aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Kleikamp <shaggy@austin.ibm.com>2005-07-13 08:57:38 -0500
committerDave Kleikamp <shaggy@austin.ibm.com>2005-07-13 08:57:38 -0500
commitf7f24758ac98a506770bc5910d33567610fa3403 (patch)
treeff7fad3d01bf9dc2e2e54b908f9fca4891e1ee72
parentJFS: Code cleanup - getting rid of never-used debug code (diff)
parentLinux 2.6.13-rc3 (diff)
downloadlinux-dev-f7f24758ac98a506770bc5910d33567610fa3403.tar.xz
linux-dev-f7f24758ac98a506770bc5910d33567610fa3403.zip
Merge with /home/shaggy/git/linus-clean/
Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
-rw-r--r--Documentation/00-INDEX2
-rw-r--r--Documentation/Changes26
-rw-r--r--Documentation/DocBook/Makefile2
-rw-r--r--Documentation/DocBook/kernel-api.tmpl2
-rw-r--r--Documentation/DocBook/libata.tmpl96
-rw-r--r--Documentation/DocBook/stylesheet.xsl1
-rw-r--r--Documentation/IPMI.txt146
-rw-r--r--Documentation/SubmittingDrivers14
-rw-r--r--Documentation/SubmittingPatches61
-rw-r--r--Documentation/acpi-hotkey.txt35
-rw-r--r--Documentation/basic_profiling.txt10
-rw-r--r--Documentation/block/ioprio.txt176
-rw-r--r--Documentation/cciss.txt1
-rw-r--r--Documentation/cdrom/sbpcd16
-rw-r--r--Documentation/cpu-freq/governors.txt14
-rw-r--r--Documentation/cpusets.txt16
-rw-r--r--Documentation/devices.txt1
-rw-r--r--Documentation/dvb/README.dibusb285
-rw-r--r--Documentation/dvb/README.dvb-usb232
-rw-r--r--Documentation/dvb/bt8xx.txt84
-rw-r--r--Documentation/feature-removal-schedule.txt24
-rw-r--r--Documentation/filesystems/ext2.txt2
-rw-r--r--Documentation/filesystems/inotify.txt138
-rw-r--r--Documentation/filesystems/xip.txt67
-rw-r--r--Documentation/hwmon/adm1021 (renamed from Documentation/i2c/chips/adm1021)0
-rw-r--r--Documentation/hwmon/adm1025 (renamed from Documentation/i2c/chips/adm1025)0
-rw-r--r--Documentation/hwmon/adm1026 (renamed from Documentation/i2c/chips/adm1026)0
-rw-r--r--Documentation/hwmon/adm1031 (renamed from Documentation/i2c/chips/adm1031)0
-rw-r--r--Documentation/hwmon/adm9240 (renamed from Documentation/i2c/chips/adm9240)0
-rw-r--r--Documentation/hwmon/asb100 (renamed from Documentation/i2c/chips/asb100)0
-rw-r--r--Documentation/hwmon/ds1621 (renamed from Documentation/i2c/chips/ds1621)0
-rw-r--r--Documentation/hwmon/fscher (renamed from Documentation/i2c/chips/fscher)0
-rw-r--r--Documentation/hwmon/gl518sm (renamed from Documentation/i2c/chips/gl518sm)0
-rw-r--r--Documentation/hwmon/it87 (renamed from Documentation/i2c/chips/it87)0
-rw-r--r--Documentation/hwmon/lm63 (renamed from Documentation/i2c/chips/lm63)0
-rw-r--r--Documentation/hwmon/lm75 (renamed from Documentation/i2c/chips/lm75)0
-rw-r--r--Documentation/hwmon/lm77 (renamed from Documentation/i2c/chips/lm77)0
-rw-r--r--Documentation/hwmon/lm78 (renamed from Documentation/i2c/chips/lm78)0
-rw-r--r--Documentation/hwmon/lm80 (renamed from Documentation/i2c/chips/lm80)0
-rw-r--r--Documentation/hwmon/lm83 (renamed from Documentation/i2c/chips/lm83)0
-rw-r--r--Documentation/hwmon/lm85 (renamed from Documentation/i2c/chips/lm85)0
-rw-r--r--Documentation/hwmon/lm87 (renamed from Documentation/i2c/chips/lm87)0
-rw-r--r--Documentation/hwmon/lm90 (renamed from Documentation/i2c/chips/lm90)0
-rw-r--r--Documentation/hwmon/lm92 (renamed from Documentation/i2c/chips/lm92)0
-rw-r--r--Documentation/hwmon/max1619 (renamed from Documentation/i2c/chips/max1619)0
-rw-r--r--Documentation/hwmon/pc87360 (renamed from Documentation/i2c/chips/pc87360)0
-rw-r--r--Documentation/hwmon/sis5595 (renamed from Documentation/i2c/chips/sis5595)0
-rw-r--r--Documentation/hwmon/smsc47b397 (renamed from Documentation/i2c/chips/smsc47b397)0
-rw-r--r--Documentation/hwmon/smsc47m1 (renamed from Documentation/i2c/chips/smsc47m1)0
-rw-r--r--Documentation/hwmon/sysfs-interface (renamed from Documentation/i2c/sysfs-interface)0
-rw-r--r--Documentation/hwmon/userspace-tools (renamed from Documentation/i2c/userspace-tools)0
-rw-r--r--Documentation/hwmon/via686a (renamed from Documentation/i2c/chips/via686a)0
-rw-r--r--Documentation/hwmon/w83627hf (renamed from Documentation/i2c/chips/w83627hf)0
-rw-r--r--Documentation/hwmon/w83781d (renamed from Documentation/i2c/chips/w83781d)0
-rw-r--r--Documentation/hwmon/w83l785ts (renamed from Documentation/i2c/chips/w83l785ts)0
-rw-r--r--Documentation/i2c/chips/max687522
-rw-r--r--Documentation/i2c/dev-interface15
-rw-r--r--Documentation/i2c/writing-clients7
-rw-r--r--Documentation/infiniband/user_verbs.txt69
-rw-r--r--Documentation/kdump/gdbmacros.txt179
-rw-r--r--Documentation/kdump/kdump.txt141
-rw-r--r--Documentation/kernel-parameters.txt33
-rw-r--r--Documentation/keys.txt319
-rw-r--r--Documentation/networking/00-INDEX4
-rw-r--r--Documentation/networking/dmfe.txt82
-rw-r--r--Documentation/networking/fib_trie.txt145
-rw-r--r--Documentation/networking/ip-sysctl.txt56
-rw-r--r--Documentation/networking/tcp.txt69
-rw-r--r--Documentation/networking/wanpipe.txt622
-rw-r--r--Documentation/pcmcia/devicetable.txt63
-rw-r--r--Documentation/pcmcia/driver-changes.txt58
-rw-r--r--Documentation/power/kernel_threads.txt3
-rw-r--r--Documentation/power/pci.txt38
-rw-r--r--Documentation/power/swsusp.txt84
-rw-r--r--Documentation/power/video.txt4
-rw-r--r--Documentation/power/video_extension.txt19
-rw-r--r--Documentation/s390/s390dbf.txt79
-rw-r--r--Documentation/serial/driver4
-rw-r--r--Documentation/sysrq.txt5
-rw-r--r--Documentation/usb/sn9c102.txt4
-rw-r--r--Documentation/usb/usbmon.txt29
-rw-r--r--Documentation/video4linux/API.html415
-rw-r--r--Documentation/video4linux/CARDLIST.bttv16
-rw-r--r--Documentation/video4linux/CARDLIST.cx8831
-rw-r--r--Documentation/video4linux/CARDLIST.saa713441
-rw-r--r--Documentation/video4linux/CARDLIST.tuner18
-rw-r--r--Documentation/video4linux/README.saa71349
-rw-r--r--Documentation/video4linux/bttv/Cards74
-rw-r--r--Documentation/video4linux/hauppauge-wintv-cx88-ir.txt54
-rw-r--r--Documentation/video4linux/lifeview.txt42
-rw-r--r--Documentation/video4linux/not-in-cx2388x-datasheet.txt41
-rw-r--r--MAINTAINERS54
-rw-r--r--Makefile12
-rw-r--r--arch/alpha/Kconfig2
-rw-r--r--arch/alpha/kernel/irq_alpha.c2
-rw-r--r--arch/alpha/kernel/traps.c2
-rw-r--r--arch/arm/Kconfig34
-rw-r--r--arch/arm/Makefile8
-rw-r--r--arch/arm/configs/enp2611_defconfig49
-rw-r--r--arch/arm/configs/ixdp2400_defconfig49
-rw-r--r--arch/arm/configs/ixdp2401_defconfig49
-rw-r--r--arch/arm/configs/ixdp2800_defconfig49
-rw-r--r--arch/arm/configs/ixdp2801_defconfig49
-rw-r--r--arch/arm/configs/omap_h2_1610_defconfig117
-rw-r--r--arch/arm/configs/omnimeter_defconfig803
-rw-r--r--arch/arm/configs/s3c2410_defconfig27
-rw-r--r--arch/arm/kernel/armksyms.c9
-rw-r--r--arch/arm/kernel/head.S20
-rw-r--r--arch/arm/kernel/irq.c14
-rw-r--r--arch/arm/kernel/process.c5
-rw-r--r--arch/arm/kernel/setup.c7
-rw-r--r--arch/arm/kernel/signal.c2
-rw-r--r--arch/arm/kernel/smp.c123
-rw-r--r--arch/arm/kernel/time.c107
-rw-r--r--arch/arm/kernel/traps.c12
-rw-r--r--arch/arm/lib/Makefile2
-rw-r--r--arch/arm/lib/longlong.h183
-rw-r--r--arch/arm/lib/udivdi3.c222
-rw-r--r--arch/arm/mach-aaec2000/Makefile.boot1
-rw-r--r--arch/arm/mach-aaec2000/aaed2000.c10
-rw-r--r--arch/arm/mach-aaec2000/core.c4
-rw-r--r--arch/arm/mach-clps711x/Kconfig2
-rw-r--r--arch/arm/mach-clps711x/autcpu12.c12
-rw-r--r--arch/arm/mach-clps711x/cdb89712.c12
-rw-r--r--arch/arm/mach-clps711x/ceiva.c12
-rw-r--r--arch/arm/mach-clps711x/clep7312.c14
-rw-r--r--arch/arm/mach-clps711x/edb7211-arch.c14
-rw-r--r--arch/arm/mach-clps711x/fortunet.c14
-rw-r--r--arch/arm/mach-clps711x/p720t.c14
-rw-r--r--arch/arm/mach-clps711x/time.c4
-rw-r--r--arch/arm/mach-clps7500/core.c18
-rw-r--r--arch/arm/mach-ebsa110/core.c22
-rw-r--r--arch/arm/mach-epxa10db/arch.c10
-rw-r--r--arch/arm/mach-epxa10db/time.c4
-rw-r--r--arch/arm/mach-footbridge/cats-hw.c16
-rw-r--r--arch/arm/mach-footbridge/co285.c12
-rw-r--r--arch/arm/mach-footbridge/dc21285-timer.c2
-rw-r--r--arch/arm/mach-footbridge/ebsa285.c15
-rw-r--r--arch/arm/mach-footbridge/isa-timer.c2
-rw-r--r--arch/arm/mach-footbridge/netwinder-hw.c21
-rw-r--r--arch/arm/mach-footbridge/personal.c12
-rw-r--r--arch/arm/mach-h720x/cpu-h7201.c4
-rw-r--r--arch/arm/mach-h720x/cpu-h7202.c4
-rw-r--r--arch/arm/mach-h720x/h7201-eval.c14
-rw-r--r--arch/arm/mach-h720x/h7202-eval.c16
-rw-r--r--arch/arm/mach-imx/mx1ads.c14
-rw-r--r--arch/arm/mach-imx/time.c4
-rw-r--r--arch/arm/mach-integrator/core.c45
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c14
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c14
-rw-r--r--arch/arm/mach-iop3xx/iop321-setup.c28
-rw-r--r--arch/arm/mach-iop3xx/iop321-time.c2
-rw-r--r--arch/arm/mach-iop3xx/iop331-setup.c30
-rw-r--r--arch/arm/mach-iop3xx/iop331-time.c2
-rw-r--r--arch/arm/mach-ixp2000/Kconfig8
-rw-r--r--arch/arm/mach-ixp2000/core.c149
-rw-r--r--arch/arm/mach-ixp2000/enp2611.c32
-rw-r--r--arch/arm/mach-ixp2000/ixdp2400.c14
-rw-r--r--arch/arm/mach-ixp2000/ixdp2800.c20
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x00.c4
-rw-r--r--arch/arm/mach-ixp2000/ixdp2x01.c29
-rw-r--r--arch/arm/mach-ixp2000/pci.c13
-rw-r--r--arch/arm/mach-ixp4xx/common-pci.c4
-rw-r--r--arch/arm/mach-ixp4xx/common.c12
-rw-r--r--arch/arm/mach-ixp4xx/coyote-setup.c57
-rw-r--r--arch/arm/mach-ixp4xx/gtwx5715-setup.c17
-rw-r--r--arch/arm/mach-ixp4xx/ixdp425-setup.c63
-rw-r--r--arch/arm/mach-l7200/core.c10
-rw-r--r--arch/arm/mach-lh7a40x/arch-kev7a400.c12
-rw-r--r--arch/arm/mach-lh7a40x/arch-lpd7a40x.c28
-rw-r--r--arch/arm/mach-lh7a40x/time.c4
-rw-r--r--arch/arm/mach-omap/Kconfig221
-rw-r--r--arch/arm/mach-omap/Makefile40
-rw-r--r--arch/arm/mach-omap/common.c549
-rw-r--r--arch/arm/mach-omap1/Kconfig144
-rw-r--r--arch/arm/mach-omap1/Makefile30
-rw-r--r--arch/arm/mach-omap1/Makefile.boot (renamed from arch/arm/mach-omap/Makefile.boot)1
-rw-r--r--arch/arm/mach-omap1/board-generic.c (renamed from arch/arm/mach-omap/board-generic.c)21
-rw-r--r--arch/arm/mach-omap1/board-h2.c (renamed from arch/arm/mach-omap/board-h2.c)21
-rw-r--r--arch/arm/mach-omap1/board-h3.c (renamed from arch/arm/mach-omap/board-h3.c)21
-rw-r--r--arch/arm/mach-omap1/board-innovator.c (renamed from arch/arm/mach-omap/board-innovator.c)21
-rw-r--r--arch/arm/mach-omap1/board-netstar.c (renamed from arch/arm/mach-omap/board-netstar.c)21
-rw-r--r--arch/arm/mach-omap1/board-osk.c (renamed from arch/arm/mach-omap/board-osk.c)21
-rw-r--r--arch/arm/mach-omap1/board-perseus2.c (renamed from arch/arm/mach-omap/board-perseus2.c)21
-rw-r--r--arch/arm/mach-omap1/board-voiceblue.c (renamed from arch/arm/mach-omap/board-voiceblue.c)23
-rw-r--r--arch/arm/mach-omap1/fpga.c (renamed from arch/arm/mach-omap/fpga.c)0
-rw-r--r--arch/arm/mach-omap1/id.c188
-rw-r--r--arch/arm/mach-omap1/io.c115
-rw-r--r--arch/arm/mach-omap1/irq.c (renamed from arch/arm/mach-omap/irq.c)17
-rw-r--r--arch/arm/mach-omap1/leds-h2p2-debug.c (renamed from arch/arm/mach-omap/leds-h2p2-debug.c)0
-rw-r--r--arch/arm/mach-omap1/leds-innovator.c (renamed from arch/arm/mach-omap/leds-innovator.c)0
-rw-r--r--arch/arm/mach-omap1/leds-osk.c (renamed from arch/arm/mach-omap/leds-osk.c)4
-rw-r--r--arch/arm/mach-omap1/leds.c (renamed from arch/arm/mach-omap/leds.c)0
-rw-r--r--arch/arm/mach-omap1/leds.h (renamed from arch/arm/mach-omap/leds.h)0
-rw-r--r--arch/arm/mach-omap1/serial.c200
-rw-r--r--arch/arm/mach-omap1/time.c (renamed from arch/arm/mach-omap/time.c)86
-rw-r--r--arch/arm/mach-pxa/Makefile4
-rw-r--r--arch/arm/mach-pxa/corgi.c42
-rw-r--r--arch/arm/mach-pxa/idp.c12
-rw-r--r--arch/arm/mach-pxa/lubbock.c12
-rw-r--r--arch/arm/mach-pxa/mainstone.c12
-rw-r--r--arch/arm/mach-pxa/poodle.c14
-rw-r--r--arch/arm/mach-pxa/pxa27x.c9
-rw-r--r--arch/arm/mach-pxa/standby.S32
-rw-r--r--arch/arm/mach-pxa/time.c4
-rw-r--r--arch/arm/mach-rpc/riscpc.c16
-rw-r--r--arch/arm/mach-s3c2410/Kconfig5
-rw-r--r--arch/arm/mach-s3c2410/Makefile1
-rw-r--r--arch/arm/mach-s3c2410/devs.c4
-rw-r--r--arch/arm/mach-s3c2410/irq.c7
-rw-r--r--arch/arm/mach-s3c2410/mach-bast.c95
-rw-r--r--arch/arm/mach-s3c2410/mach-h1940.c12
-rw-r--r--arch/arm/mach-s3c2410/mach-n30.c9
-rw-r--r--arch/arm/mach-s3c2410/mach-nexcoder.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-otom.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-rx3715.c14
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2410.c12
-rw-r--r--arch/arm/mach-s3c2410/mach-smdk2440.c8
-rw-r--r--arch/arm/mach-s3c2410/mach-vr1000.c93
-rw-r--r--arch/arm/mach-s3c2410/pm-simtec.c65
-rw-r--r--arch/arm/mach-s3c2410/time.c4
-rw-r--r--arch/arm/mach-sa1100/assabet.c12
-rw-r--r--arch/arm/mach-sa1100/badge4.c10
-rw-r--r--arch/arm/mach-sa1100/cerf.c10
-rw-r--r--arch/arm/mach-sa1100/collie.c8
-rw-r--r--arch/arm/mach-sa1100/cpu-sa1110.c3
-rw-r--r--arch/arm/mach-sa1100/h3600.c32
-rw-r--r--arch/arm/mach-sa1100/hackkit.c10
-rw-r--r--arch/arm/mach-sa1100/jornada720.c10
-rw-r--r--arch/arm/mach-sa1100/lart.c10
-rw-r--r--arch/arm/mach-sa1100/pleb.c8
-rw-r--r--arch/arm/mach-sa1100/shannon.c10
-rw-r--r--arch/arm/mach-sa1100/simpad.c12
-rw-r--r--arch/arm/mach-sa1100/time.c4
-rw-r--r--arch/arm/mach-shark/core.c16
-rw-r--r--arch/arm/mach-versatile/core.c65
-rw-r--r--arch/arm/mach-versatile/versatile_ab.c14
-rw-r--r--arch/arm/mach-versatile/versatile_pb.c14
-rw-r--r--arch/arm/mm/Kconfig2
-rw-r--r--arch/arm/mm/blockops.c3
-rw-r--r--arch/arm/mm/fault.c75
-rw-r--r--arch/arm/mm/init.c73
-rw-r--r--arch/arm/mm/mm-armv.c93
-rw-r--r--arch/arm/mm/proc-arm1020.S4
-rw-r--r--arch/arm/mm/proc-arm1020e.S4
-rw-r--r--arch/arm/mm/proc-v6.S8
-rw-r--r--arch/arm/nwfpe/softfloat-macros22
-rw-r--r--arch/arm/nwfpe/softfloat.c12
-rw-r--r--arch/arm/oprofile/Makefile2
-rw-r--r--arch/arm/oprofile/backtrace.c144
-rw-r--r--arch/arm/oprofile/init.c2
-rw-r--r--arch/arm/oprofile/op_arm_model.h2
-rw-r--r--arch/arm/plat-omap/Kconfig112
-rw-r--r--arch/arm/plat-omap/Makefile17
-rw-r--r--arch/arm/plat-omap/clock.c (renamed from arch/arm/mach-omap/clock.c)371
-rw-r--r--arch/arm/plat-omap/clock.h (renamed from arch/arm/mach-omap/clock.h)12
-rw-r--r--arch/arm/plat-omap/common.c135
-rw-r--r--arch/arm/plat-omap/cpu-omap.c128
-rw-r--r--arch/arm/plat-omap/dma.c (renamed from arch/arm/mach-omap/dma.c)46
-rw-r--r--arch/arm/plat-omap/gpio.c (renamed from arch/arm/mach-omap/gpio.c)2
-rw-r--r--arch/arm/plat-omap/mcbsp.c (renamed from arch/arm/mach-omap/mcbsp.c)99
-rw-r--r--arch/arm/plat-omap/mux.c (renamed from arch/arm/mach-omap/mux.c)19
-rw-r--r--arch/arm/plat-omap/ocpi.c (renamed from arch/arm/mach-omap/ocpi.c)2
-rw-r--r--arch/arm/plat-omap/pm.c (renamed from arch/arm/mach-omap/pm.c)18
-rw-r--r--arch/arm/plat-omap/sleep.S (renamed from arch/arm/mach-omap/sleep.S)2
-rw-r--r--arch/arm/plat-omap/usb.c (renamed from arch/arm/mach-omap/usb.c)13
-rw-r--r--arch/arm/tools/mach-types69
-rw-r--r--arch/arm/vfp/vfp.h15
-rw-r--r--arch/arm/vfp/vfpdouble.c2
-rw-r--r--arch/arm/vfp/vfpmodule.c2
-rw-r--r--arch/arm/vfp/vfpsingle.c14
-rw-r--r--arch/arm26/Kconfig4
-rw-r--r--arch/cris/Kconfig4
-rw-r--r--arch/frv/Kconfig2
-rw-r--r--arch/frv/defconfig627
-rw-r--r--arch/frv/kernel/setup.c2
-rw-r--r--arch/frv/kernel/signal.c4
-rw-r--r--arch/frv/mb93090-mb00/pci-irq.c2
-rw-r--r--arch/h8300/Kconfig6
-rw-r--r--arch/h8300/kernel/signal.c4
-rw-r--r--arch/i386/Kconfig69
-rw-r--r--arch/i386/boot/Makefile4
-rw-r--r--arch/i386/boot/compressed/head.S7
-rw-r--r--arch/i386/boot/compressed/misc.c8
-rw-r--r--arch/i386/boot/edd.S2
-rw-r--r--arch/i386/boot/setup.S6
-rw-r--r--arch/i386/boot/tools/build.c8
-rw-r--r--arch/i386/crypto/aes.c2
-rw-r--r--arch/i386/defconfig1
-rw-r--r--arch/i386/kernel/Makefile1
-rw-r--r--arch/i386/kernel/acpi/Makefile4
-rw-r--r--arch/i386/kernel/acpi/boot.c277
-rw-r--r--arch/i386/kernel/acpi/cstate.c103
-rw-r--r--arch/i386/kernel/acpi/sleep.c27
-rw-r--r--arch/i386/kernel/acpi/wakeup.S5
-rw-r--r--arch/i386/kernel/apic.c82
-rw-r--r--arch/i386/kernel/apm.c13
-rw-r--r--arch/i386/kernel/cpu/common.c50
-rw-r--r--arch/i386/kernel/cpu/cpufreq/gx-suspmod.c2
-rw-r--r--arch/i386/kernel/cpu/cpufreq/powernow-k7.c4
-rw-r--r--arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c2
-rw-r--r--arch/i386/kernel/cpu/intel.c14
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c4
-rw-r--r--arch/i386/kernel/cpu/mcheck/k7.c2
-rw-r--r--arch/i386/kernel/cpu/mcheck/mce.c4
-rw-r--r--arch/i386/kernel/cpu/mcheck/p4.c4
-rw-r--r--arch/i386/kernel/cpu/mcheck/p5.c2
-rw-r--r--arch/i386/kernel/cpu/mcheck/p6.c2
-rw-r--r--arch/i386/kernel/cpu/mcheck/winchip.c2
-rw-r--r--arch/i386/kernel/cpu/mtrr/generic.c23
-rw-r--r--arch/i386/kernel/cpu/mtrr/main.c76
-rw-r--r--arch/i386/kernel/cpu/mtrr/mtrr.h1
-rw-r--r--arch/i386/kernel/crash.c223
-rw-r--r--arch/i386/kernel/dmi_scan.c391
-rw-r--r--arch/i386/kernel/efi.c4
-rw-r--r--arch/i386/kernel/head.S6
-rw-r--r--arch/i386/kernel/i8259.c12
-rw-r--r--arch/i386/kernel/io_apic.c45
-rw-r--r--arch/i386/kernel/irq.c72
-rw-r--r--arch/i386/kernel/kprobes.c133
-rw-r--r--arch/i386/kernel/machine_kexec.c226
-rw-r--r--arch/i386/kernel/mpparse.c2
-rw-r--r--arch/i386/kernel/process.c68
-rw-r--r--arch/i386/kernel/reboot.c82
-rw-r--r--arch/i386/kernel/relocate_kernel.S120
-rw-r--r--arch/i386/kernel/setup.c69
-rw-r--r--arch/i386/kernel/signal.c4
-rw-r--r--arch/i386/kernel/smp.c34
-rw-r--r--arch/i386/kernel/smpboot.c359
-rw-r--r--arch/i386/kernel/syscall_table.S7
-rw-r--r--arch/i386/kernel/sysenter.c12
-rw-r--r--arch/i386/kernel/time.c7
-rw-r--r--arch/i386/kernel/time_hpet.c2
-rw-r--r--arch/i386/kernel/timers/common.c2
-rw-r--r--arch/i386/kernel/timers/timer_cyclone.c4
-rw-r--r--arch/i386/kernel/timers/timer_hpet.c4
-rw-r--r--arch/i386/kernel/timers/timer_pit.c4
-rw-r--r--arch/i386/kernel/timers/timer_tsc.c5
-rw-r--r--arch/i386/kernel/traps.c51
-rw-r--r--arch/i386/kernel/vmlinux.lds.S62
-rw-r--r--arch/i386/mach-default/setup.c27
-rw-r--r--arch/i386/mach-default/topology.c15
-rw-r--r--arch/i386/mach-visws/mpparse.c5
-rw-r--r--arch/i386/mach-voyager/voyager_basic.c2
-rw-r--r--arch/i386/mm/discontig.c2
-rw-r--r--arch/i386/mm/fault.c7
-rw-r--r--arch/i386/mm/highmem.c18
-rw-r--r--arch/i386/mm/init.c2
-rw-r--r--arch/i386/mm/ioremap.c8
-rw-r--r--arch/i386/mm/pgtable.c30
-rw-r--r--arch/i386/pci/common.c9
-rw-r--r--arch/i386/pci/i386.c11
-rw-r--r--arch/i386/pci/irq.c67
-rw-r--r--arch/i386/pci/legacy.c2
-rw-r--r--arch/i386/pci/mmconfig.c39
-rw-r--r--arch/i386/pci/numa.c2
-rw-r--r--arch/i386/pci/pci.h1
-rw-r--r--arch/i386/pci/visws.c2
-rw-r--r--arch/i386/power/cpu.c24
-rw-r--r--arch/ia64/Kconfig2
-rw-r--r--arch/ia64/configs/sn2_defconfig4
-rw-r--r--arch/ia64/configs/tiger_defconfig39
-rw-r--r--arch/ia64/configs/zx1_defconfig166
-rw-r--r--arch/ia64/hp/common/sba_iommu.c4
-rw-r--r--arch/ia64/hp/sim/simeth.c6
-rw-r--r--arch/ia64/hp/sim/simserial.c23
-rw-r--r--arch/ia64/kernel/Makefile1
-rw-r--r--arch/ia64/kernel/acpi.c88
-rw-r--r--arch/ia64/kernel/domain.c78
-rw-r--r--arch/ia64/kernel/entry.S116
-rw-r--r--arch/ia64/kernel/fsys.S147
-rw-r--r--arch/ia64/kernel/gate.S62
-rw-r--r--arch/ia64/kernel/ia64_ksyms.c3
-rw-r--r--arch/ia64/kernel/iosapic.c147
-rw-r--r--arch/ia64/kernel/irq_ia64.c15
-rw-r--r--arch/ia64/kernel/ivt.S198
-rw-r--r--arch/ia64/kernel/kprobes.c128
-rw-r--r--arch/ia64/kernel/mca.c2
-rw-r--r--arch/ia64/kernel/numa.c57
-rw-r--r--arch/ia64/kernel/perfmon.c1
-rw-r--r--arch/ia64/kernel/process.c17
-rw-r--r--arch/ia64/kernel/ptrace.c22
-rw-r--r--arch/ia64/kernel/setup.c15
-rw-r--r--arch/ia64/kernel/signal.c2
-rw-r--r--arch/ia64/kernel/smp.c3
-rw-r--r--arch/ia64/kernel/smpboot.c45
-rw-r--r--arch/ia64/kernel/topology.c7
-rw-r--r--arch/ia64/kernel/traps.c6
-rw-r--r--arch/ia64/kernel/vmlinux.lds.S7
-rw-r--r--arch/ia64/mm/discontig.c432
-rw-r--r--arch/ia64/mm/init.c3
-rw-r--r--arch/ia64/pci/pci.c38
-rw-r--r--arch/ia64/sn/include/xtalk/hubdev.h2
-rw-r--r--arch/ia64/sn/kernel/io_init.c187
-rw-r--r--arch/ia64/sn/kernel/iomv.c6
-rw-r--r--arch/ia64/sn/kernel/irq.c255
-rw-r--r--arch/ia64/sn/kernel/setup.c56
-rw-r--r--arch/ia64/sn/kernel/sn2/ptc_deadlock.S1
-rw-r--r--arch/ia64/sn/kernel/tiocx.c19
-rw-r--r--arch/ia64/sn/kernel/xpc.h12
-rw-r--r--arch/ia64/sn/kernel/xpc_channel.c12
-rw-r--r--arch/ia64/sn/kernel/xpc_main.c16
-rw-r--r--arch/ia64/sn/kernel/xpc_partition.c2
-rw-r--r--arch/ia64/sn/pci/pci_dma.c3
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_ate.c2
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_dma.c15
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_provider.c48
-rw-r--r--arch/ia64/sn/pci/pcibr/pcibr_reg.c8
-rw-r--r--arch/ia64/sn/pci/tioca_provider.c11
-rw-r--r--arch/m32r/Kconfig2
-rw-r--r--arch/m32r/kernel/setup_m32700ut.c55
-rw-r--r--arch/m32r/kernel/setup_mappi.c51
-rw-r--r--arch/m32r/kernel/setup_mappi2.c4
-rw-r--r--arch/m32r/kernel/setup_mappi3.c52
-rw-r--r--arch/m32r/kernel/setup_oaks32r.c5
-rw-r--r--arch/m32r/kernel/setup_opsput.c53
-rw-r--r--arch/m32r/kernel/signal.c4
-rw-r--r--arch/m68k/Kconfig2
-rw-r--r--arch/m68knommu/Kconfig2
-rw-r--r--arch/mips/Kconfig8
-rw-r--r--arch/mips/kernel/setup.c4
-rw-r--r--arch/mips/kernel/signal.c2
-rw-r--r--arch/mips/mm/init.c4
-rw-r--r--arch/mips/mm/pgtable.c2
-rw-r--r--arch/parisc/Kconfig2
-rw-r--r--arch/parisc/configs/712_defconfig2
-rw-r--r--arch/parisc/configs/a500_defconfig2
-rw-r--r--arch/parisc/configs/b180_defconfig2
-rw-r--r--arch/parisc/configs/c3000_defconfig2
-rw-r--r--arch/parisc/defconfig2
-rw-r--r--arch/ppc/8xx_io/enet.c52
-rw-r--r--arch/ppc/Kconfig61
-rw-r--r--arch/ppc/Kconfig.debug2
-rw-r--r--arch/ppc/Makefile3
-rw-r--r--arch/ppc/boot/openfirmware/chrpmain.c2
-rw-r--r--arch/ppc/configs/mpc86x_ads_defconfig633
-rw-r--r--arch/ppc/configs/mpc885ads_defconfig622
-rw-r--r--arch/ppc/kernel/Makefile3
-rw-r--r--arch/ppc/kernel/cputable.c25
-rw-r--r--arch/ppc/kernel/entry.S9
-rw-r--r--arch/ppc/kernel/head_booke.h64
-rw-r--r--arch/ppc/kernel/head_fsl_booke.S51
-rw-r--r--arch/ppc/kernel/machine_kexec.c124
-rw-r--r--arch/ppc/kernel/misc.S12
-rw-r--r--arch/ppc/kernel/pci.c21
-rw-r--r--arch/ppc/kernel/perfmon.c2
-rw-r--r--arch/ppc/kernel/relocate_kernel.S123
-rw-r--r--arch/ppc/kernel/signal.c3
-rw-r--r--arch/ppc/kernel/time.c13
-rw-r--r--arch/ppc/kernel/traps.c24
-rw-r--r--arch/ppc/mm/44x_mmu.c1
-rw-r--r--arch/ppc/mm/4xx_mmu.c1
-rw-r--r--arch/ppc/mm/fsl_booke_mmu.c3
-rw-r--r--arch/ppc/mm/init.c14
-rw-r--r--arch/ppc/platforms/83xx/mpc834x_sys.c28
-rw-r--r--arch/ppc/platforms/85xx/mpc8540_ads.c42
-rw-r--r--arch/ppc/platforms/85xx/mpc8560_ads.c28
-rw-r--r--arch/ppc/platforms/85xx/sbc8560.c28
-rw-r--r--arch/ppc/platforms/85xx/stx_gp3.c26
-rw-r--r--arch/ppc/platforms/chrp_pci.c1
-rw-r--r--arch/ppc/platforms/fads.h109
-rw-r--r--arch/ppc/platforms/katana.c2
-rw-r--r--arch/ppc/platforms/mpc885ads.h92
-rw-r--r--arch/ppc/platforms/pmac_cpufreq.c2
-rw-r--r--arch/ppc/platforms/pmac_pci.c1
-rw-r--r--arch/ppc/platforms/pmac_sleep.S4
-rw-r--r--arch/ppc/platforms/pmac_time.c8
-rw-r--r--arch/ppc/platforms/sandpoint.c1
-rw-r--r--arch/ppc/syslib/cpm2_common.c2
-rw-r--r--arch/ppc/syslib/indirect_pci.c1
-rw-r--r--arch/ppc/syslib/ipic.c14
-rw-r--r--arch/ppc/syslib/mv64x60.c1
-rw-r--r--arch/ppc/syslib/mv64x60_win.c1
-rw-r--r--arch/ppc/syslib/of_device.c15
-rw-r--r--arch/ppc/syslib/open_pic.c26
-rw-r--r--arch/ppc/syslib/ppc4xx_pic.c4
-rw-r--r--arch/ppc64/Kconfig40
-rw-r--r--arch/ppc64/boot/Makefile5
-rw-r--r--arch/ppc64/boot/main.c8
-rw-r--r--arch/ppc64/boot/mknote.c43
-rw-r--r--arch/ppc64/boot/piggyback.c83
-rw-r--r--arch/ppc64/boot/prom.c16
-rw-r--r--arch/ppc64/kernel/ItLpQueue.c294
-rw-r--r--arch/ppc64/kernel/LparData.c11
-rw-r--r--arch/ppc64/kernel/Makefile1
-rw-r--r--arch/ppc64/kernel/cputable.c365
-rw-r--r--arch/ppc64/kernel/head.S16
-rw-r--r--arch/ppc64/kernel/hvconsole.c51
-rw-r--r--arch/ppc64/kernel/iSeries_proc.c48
-rw-r--r--arch/ppc64/kernel/iSeries_setup.c119
-rw-r--r--arch/ppc64/kernel/idle.c283
-rw-r--r--arch/ppc64/kernel/irq.c9
-rw-r--r--arch/ppc64/kernel/kprobes.c125
-rw-r--r--arch/ppc64/kernel/lparcfg.c1
-rw-r--r--arch/ppc64/kernel/machine_kexec.c302
-rw-r--r--arch/ppc64/kernel/maple_setup.c3
-rw-r--r--arch/ppc64/kernel/mf.c6
-rw-r--r--arch/ppc64/kernel/misc.S181
-rw-r--r--arch/ppc64/kernel/mpic.c29
-rw-r--r--arch/ppc64/kernel/mpic.h3
-rw-r--r--arch/ppc64/kernel/nvram.c8
-rw-r--r--arch/ppc64/kernel/of_device.c15
-rw-r--r--arch/ppc64/kernel/pSeries_setup.c160
-rw-r--r--arch/ppc64/kernel/pSeries_smp.c5
-rw-r--r--arch/ppc64/kernel/pacaData.c212
-rw-r--r--arch/ppc64/kernel/pci.c22
-rw-r--r--arch/ppc64/kernel/pmac_setup.c5
-rw-r--r--arch/ppc64/kernel/ppc_ksyms.c1
-rw-r--r--arch/ppc64/kernel/process.c4
-rw-r--r--arch/ppc64/kernel/ptrace.c4
-rw-r--r--arch/ppc64/kernel/setup.c30
-rw-r--r--arch/ppc64/kernel/sys_ppc32.c54
-rw-r--r--arch/ppc64/kernel/sysfs.c21
-rw-r--r--arch/ppc64/kernel/time.c9
-rw-r--r--arch/ppc64/kernel/vdso32/vdso32.lds.S4
-rw-r--r--arch/ppc64/kernel/xics.c25
-rw-r--r--arch/ppc64/mm/hash_native.c47
-rw-r--r--arch/s390/Kconfig12
-rw-r--r--arch/s390/defconfig1
-rw-r--r--arch/s390/kernel/Makefile10
-rw-r--r--arch/s390/kernel/compat_wrapper.S8
-rw-r--r--arch/s390/kernel/cpcmd.c109
-rw-r--r--arch/s390/kernel/crash.c17
-rw-r--r--arch/s390/kernel/debug.c820
-rw-r--r--arch/s390/kernel/entry.S102
-rw-r--r--arch/s390/kernel/entry64.S97
-rw-r--r--arch/s390/kernel/machine_kexec.c98
-rw-r--r--arch/s390/kernel/process.c46
-rw-r--r--arch/s390/kernel/relocate_kernel.S81
-rw-r--r--arch/s390/kernel/relocate_kernel64.S82
-rw-r--r--arch/s390/kernel/setup.c19
-rw-r--r--arch/s390/kernel/smp.c23
-rw-r--r--arch/s390/kernel/syscalls.S2
-rw-r--r--arch/s390/kernel/traps.c2
-rw-r--r--arch/s390/mm/extmem.c4
-rw-r--r--arch/sh/Kconfig2
-rw-r--r--arch/sh64/Kconfig2
-rw-r--r--arch/sparc/Kconfig58
-rw-r--r--arch/sparc/kernel/systbls.S4
-rw-r--r--arch/sparc64/Kconfig43
-rw-r--r--arch/sparc64/kernel/auxio.c2
-rw-r--r--arch/sparc64/kernel/dtlb_backend.S2
-rw-r--r--arch/sparc64/kernel/entry.S179
-rw-r--r--arch/sparc64/kernel/irq.c759
-rw-r--r--arch/sparc64/kernel/kprobes.c5
-rw-r--r--arch/sparc64/kernel/pci_psycho.c3
-rw-r--r--arch/sparc64/kernel/pci_sabre.c46
-rw-r--r--arch/sparc64/kernel/pci_schizo.c78
-rw-r--r--arch/sparc64/kernel/power.c3
-rw-r--r--arch/sparc64/kernel/ptrace.c46
-rw-r--r--arch/sparc64/kernel/semaphore.c12
-rw-r--r--arch/sparc64/kernel/smp.c10
-rw-r--r--arch/sparc64/kernel/sparc64_ksyms.c3
-rw-r--r--arch/sparc64/kernel/sys32.S2
-rw-r--r--arch/sparc64/kernel/systbls.S8
-rw-r--r--arch/sparc64/kernel/time.c26
-rw-r--r--arch/sparc64/kernel/trampoline.S3
-rw-r--r--arch/sparc64/kernel/vmlinux.lds.S2
-rw-r--r--arch/sparc64/lib/U1memcpy.S103
-rw-r--r--arch/sparc64/lib/VISsave.S15
-rw-r--r--arch/sparc64/lib/atomic.S42
-rw-r--r--arch/sparc64/lib/bitops.S31
-rw-r--r--arch/sparc64/lib/debuglocks.c6
-rw-r--r--arch/sparc64/lib/dec_and_lock.S6
-rw-r--r--arch/sparc64/lib/rwsem.S15
-rw-r--r--arch/sparc64/mm/fault.c16
-rw-r--r--arch/sparc64/mm/init.c6
-rw-r--r--arch/sparc64/mm/ultra.S8
-rw-r--r--arch/sparc64/solaris/entry64.S7
-rw-r--r--arch/um/Kconfig10
-rw-r--r--arch/um/Kconfig_i38612
-rw-r--r--arch/um/Kconfig_x86_6412
-rw-r--r--arch/um/Makefile3
-rw-r--r--arch/um/Makefile-i3862
-rw-r--r--arch/um/Makefile-x86_642
-rw-r--r--arch/um/defconfig58
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/line.c56
-rw-r--r--arch/um/drivers/mconsole_kern.c36
-rw-r--r--arch/um/drivers/net_kern.c31
-rw-r--r--arch/um/drivers/ssl.c9
-rw-r--r--arch/um/drivers/stdio_console.c7
-rw-r--r--arch/um/drivers/ubd_kern.c37
-rw-r--r--arch/um/include/line.h3
-rw-r--r--arch/um/include/mconsole_kern.h3
-rw-r--r--arch/um/include/mem.h1
-rw-r--r--arch/um/include/registers.h1
-rw-r--r--arch/um/include/sysdep-i386/ptrace_user.h13
-rw-r--r--arch/um/include/sysdep-i386/stub.h65
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h14
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h58
-rw-r--r--arch/um/include/time_user.h3
-rw-r--r--arch/um/include/tlb.h30
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/main.c1
-rw-r--r--arch/um/kernel/physmem.c8
-rw-r--r--arch/um/kernel/process.c28
-rw-r--r--arch/um/kernel/process_kern.c6
-rw-r--r--arch/um/kernel/reboot.c9
-rw-r--r--arch/um/kernel/skas/Makefile9
-rw-r--r--arch/um/kernel/skas/clone.c44
-rw-r--r--arch/um/kernel/skas/exec_kern.c2
-rw-r--r--arch/um/kernel/skas/include/mm_id.h17
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h7
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h1
-rw-r--r--arch/um/kernel/skas/include/skas.h16
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/mem.c6
-rw-r--r--arch/um/kernel/skas/mem_user.c225
-rw-r--r--arch/um/kernel/skas/mmu.c141
-rw-r--r--arch/um/kernel/skas/process.c216
-rw-r--r--arch/um/kernel/skas/process_kern.c46
-rw-r--r--arch/um/kernel/skas/time.c30
-rw-r--r--arch/um/kernel/skas/tlb.c29
-rw-r--r--arch/um/kernel/syscall_kern.c19
-rw-r--r--arch/um/kernel/time.c36
-rw-r--r--arch/um/kernel/time_kern.c2
-rw-r--r--arch/um/kernel/tlb.c132
-rw-r--r--arch/um/kernel/tt/Makefile4
-rw-r--r--arch/um/kernel/tt/gdb.c4
-rw-r--r--arch/um/kernel/tt/gdb_kern.c2
-rw-r--r--arch/um/kernel/tt/include/debug.h17
-rw-r--r--arch/um/kernel/tt/include/mode-tt.h1
-rw-r--r--arch/um/kernel/tt/process_kern.c17
-rw-r--r--arch/um/kernel/tt/time.c28
-rw-r--r--arch/um/kernel/tt/tlb.c4
-rw-r--r--arch/um/kernel/uml.lds.S7
-rw-r--r--arch/um/os-Linux/sys-i386/registers.c5
-rw-r--r--arch/um/os-Linux/sys-x86_64/registers.c5
-rw-r--r--arch/um/scripts/Makefile.rules5
-rw-r--r--arch/um/sys-i386/Makefile12
-rw-r--r--arch/um/sys-i386/signal.c2
-rw-r--r--arch/um/sys-i386/stub.S8
-rw-r--r--arch/um/sys-i386/stub_segv.c30
-rw-r--r--arch/um/sys-i386/syscalls.c23
-rw-r--r--arch/um/sys-x86_64/Makefile12
-rw-r--r--arch/um/sys-x86_64/stub.S15
-rw-r--r--arch/um/sys-x86_64/stub_segv.c31
-rw-r--r--arch/um/sys-x86_64/syscalls.c23
-rw-r--r--arch/v850/Kconfig4
-rw-r--r--arch/v850/lib/checksum.c3
-rw-r--r--arch/x86_64/Kconfig68
-rw-r--r--arch/x86_64/Makefile6
-rw-r--r--arch/x86_64/boot/compressed/head.S11
-rw-r--r--arch/x86_64/boot/compressed/misc.c12
-rw-r--r--arch/x86_64/boot/install.sh2
-rw-r--r--arch/x86_64/boot/setup.S8
-rw-r--r--arch/x86_64/boot/tools/build.c5
-rw-r--r--arch/x86_64/crypto/Makefile9
-rw-r--r--arch/x86_64/crypto/aes-x86_64-asm.S186
-rw-r--r--arch/x86_64/crypto/aes.c324
-rw-r--r--arch/x86_64/ia32/ia32entry.S2
-rw-r--r--arch/x86_64/kernel/Makefile1
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S2
-rw-r--r--arch/x86_64/kernel/apic.c46
-rw-r--r--arch/x86_64/kernel/crash.c35
-rw-r--r--arch/x86_64/kernel/e820.c6
-rw-r--r--arch/x86_64/kernel/genapic_flat.c110
-rw-r--r--arch/x86_64/kernel/head.S18
-rw-r--r--arch/x86_64/kernel/i387.c2
-rw-r--r--arch/x86_64/kernel/i8259.c12
-rw-r--r--arch/x86_64/kernel/io_apic.c37
-rw-r--r--arch/x86_64/kernel/irq.c29
-rw-r--r--arch/x86_64/kernel/kprobes.c236
-rw-r--r--arch/x86_64/kernel/machine_kexec.c250
-rw-r--r--arch/x86_64/kernel/mce.c10
-rw-r--r--arch/x86_64/kernel/mce_intel.c4
-rw-r--r--arch/x86_64/kernel/nmi.c4
-rw-r--r--arch/x86_64/kernel/process.c60
-rw-r--r--arch/x86_64/kernel/reboot.c62
-rw-r--r--arch/x86_64/kernel/relocate_kernel.S143
-rw-r--r--arch/x86_64/kernel/setup.c51
-rw-r--r--arch/x86_64/kernel/setup64.c6
-rw-r--r--arch/x86_64/kernel/signal.c2
-rw-r--r--arch/x86_64/kernel/smp.c10
-rw-r--r--arch/x86_64/kernel/smpboot.c317
-rw-r--r--arch/x86_64/kernel/suspend.c19
-rw-r--r--arch/x86_64/kernel/traps.c8
-rw-r--r--arch/x86_64/kernel/vmlinux.lds.S132
-rw-r--r--arch/x86_64/mm/numa.c2
-rw-r--r--arch/x86_64/pci/mmconfig.c68
-rw-r--r--arch/xtensa/Kconfig262
-rw-r--r--arch/xtensa/Kconfig.debug7
-rw-r--r--arch/xtensa/Makefile104
-rw-r--r--arch/xtensa/boot/Makefile33
-rw-r--r--arch/xtensa/boot/boot-elf/Makefile52
-rw-r--r--arch/xtensa/boot/boot-elf/boot.ld71
-rw-r--r--arch/xtensa/boot/boot-elf/bootstrap.S37
-rw-r--r--arch/xtensa/boot/boot-redboot/Makefile35
-rw-r--r--arch/xtensa/boot/boot-redboot/boot.ld66
-rw-r--r--arch/xtensa/boot/boot-redboot/bootstrap.S246
-rw-r--r--arch/xtensa/boot/lib/Makefile17
-rw-r--r--arch/xtensa/boot/lib/zmem.c79
-rw-r--r--arch/xtensa/boot/ramdisk/Makefile23
-rw-r--r--arch/xtensa/configs/common_defconfig662
-rw-r--r--arch/xtensa/configs/iss_defconfig531
-rw-r--r--arch/xtensa/kernel/Makefile18
-rw-r--r--arch/xtensa/kernel/align.S459
-rw-r--r--arch/xtensa/kernel/asm-offsets.c93
-rw-r--r--arch/xtensa/kernel/coprocessor.S201
-rw-r--r--arch/xtensa/kernel/entry.S1996
-rw-r--r--arch/xtensa/kernel/head.S237
-rw-r--r--arch/xtensa/kernel/irq.c192
-rw-r--r--arch/xtensa/kernel/module.c78
-rw-r--r--arch/xtensa/kernel/pci-dma.c73
-rw-r--r--arch/xtensa/kernel/pci.c478
-rw-r--r--arch/xtensa/kernel/platform.c49
-rw-r--r--arch/xtensa/kernel/process.c482
-rw-r--r--arch/xtensa/kernel/ptrace.c408
-rw-r--r--arch/xtensa/kernel/semaphore.c226
-rw-r--r--arch/xtensa/kernel/setup.c520
-rw-r--r--arch/xtensa/kernel/signal.c713
-rw-r--r--arch/xtensa/kernel/syscalls.c269
-rw-r--r--arch/xtensa/kernel/syscalls.h247
-rw-r--r--arch/xtensa/kernel/time.c227
-rw-r--r--arch/xtensa/kernel/traps.c498
-rw-r--r--arch/xtensa/kernel/vectors.S464
-rw-r--r--arch/xtensa/kernel/vmlinux.lds.S341
-rw-r--r--arch/xtensa/kernel/xtensa_ksyms.c123
-rw-r--r--arch/xtensa/lib/Makefile7
-rw-r--r--arch/xtensa/lib/checksum.S410
-rw-r--r--arch/xtensa/lib/memcopy.S315
-rw-r--r--arch/xtensa/lib/memset.S160
-rw-r--r--arch/xtensa/lib/pci-auto.c352
-rw-r--r--arch/xtensa/lib/strcasecmp.c32
-rw-r--r--arch/xtensa/lib/strncpy_user.S224
-rw-r--r--arch/xtensa/lib/strnlen_user.S147
-rw-r--r--arch/xtensa/lib/usercopy.S321
-rw-r--r--arch/xtensa/mm/Makefile13
-rw-r--r--arch/xtensa/mm/fault.c241
-rw-r--r--arch/xtensa/mm/init.c551
-rw-r--r--arch/xtensa/mm/misc.S374
-rw-r--r--arch/xtensa/mm/pgtable.c76
-rw-r--r--arch/xtensa/mm/tlb.c545
-rw-r--r--arch/xtensa/platform-iss/Makefile13
-rw-r--r--arch/xtensa/platform-iss/console.c300
-rw-r--r--arch/xtensa/platform-iss/io.c32
-rw-r--r--arch/xtensa/platform-iss/network.c855
-rw-r--r--arch/xtensa/platform-iss/setup.c112
-rw-r--r--crypto/Kconfig22
-rw-r--r--crypto/api.c60
-rw-r--r--crypto/cipher.c312
-rw-r--r--crypto/des.c2005
-rw-r--r--crypto/hmac.c3
-rw-r--r--crypto/internal.h43
-rw-r--r--crypto/scatterwalk.c4
-rw-r--r--crypto/scatterwalk.h12
-rw-r--r--crypto/serpent.c1
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/Makefile1
-rw-r--r--drivers/acpi/Kconfig40
-rw-r--r--drivers/acpi/Makefile5
-rw-r--r--drivers/acpi/asus_acpi.c4
-rw-r--r--drivers/acpi/bus.c8
-rw-r--r--drivers/acpi/button.c245
-rw-r--r--drivers/acpi/container.c2
-rw-r--r--drivers/acpi/dispatcher/dsfield.c58
-rw-r--r--drivers/acpi/dispatcher/dsinit.c28
-rw-r--r--drivers/acpi/dispatcher/dsmethod.c11
-rw-r--r--drivers/acpi/dispatcher/dsmthdat.c195
-rw-r--r--drivers/acpi/dispatcher/dsobject.c79
-rw-r--r--drivers/acpi/dispatcher/dsopcode.c105
-rw-r--r--drivers/acpi/dispatcher/dsutils.c41
-rw-r--r--drivers/acpi/dispatcher/dswexec.c57
-rw-r--r--drivers/acpi/dispatcher/dswload.c118
-rw-r--r--drivers/acpi/dispatcher/dswscope.c31
-rw-r--r--drivers/acpi/dispatcher/dswstate.c458
-rw-r--r--drivers/acpi/ec.c420
-rw-r--r--drivers/acpi/events/evevent.c33
-rw-r--r--drivers/acpi/events/evgpe.c39
-rw-r--r--drivers/acpi/events/evgpeblk.c63
-rw-r--r--drivers/acpi/events/evmisc.c97
-rw-r--r--drivers/acpi/events/evregion.c35
-rw-r--r--drivers/acpi/events/evrgnini.c14
-rw-r--r--drivers/acpi/events/evsci.c12
-rw-r--r--drivers/acpi/events/evxface.c19
-rw-r--r--drivers/acpi/events/evxfevnt.c25
-rw-r--r--drivers/acpi/executer/exconfig.c31
-rw-r--r--drivers/acpi/executer/exconvrt.c44
-rw-r--r--drivers/acpi/executer/excreate.c50
-rw-r--r--drivers/acpi/executer/exdump.c105
-rw-r--r--drivers/acpi/executer/exfield.c25
-rw-r--r--drivers/acpi/executer/exfldio.c133
-rw-r--r--drivers/acpi/executer/exmisc.c7
-rw-r--r--drivers/acpi/executer/exmutex.c45
-rw-r--r--drivers/acpi/executer/exnames.c70
-rw-r--r--drivers/acpi/executer/exoparg1.c94
-rw-r--r--drivers/acpi/executer/exoparg2.c69
-rw-r--r--drivers/acpi/executer/exoparg3.c25
-rw-r--r--drivers/acpi/executer/exoparg6.c26
-rw-r--r--drivers/acpi/executer/exprep.c104
-rw-r--r--drivers/acpi/executer/exregion.c34
-rw-r--r--drivers/acpi/executer/exresnte.c24
-rw-r--r--drivers/acpi/executer/exresolv.c63
-rw-r--r--drivers/acpi/executer/exresop.c80
-rw-r--r--drivers/acpi/executer/exstore.c260
-rw-r--r--drivers/acpi/executer/exstoren.c20
-rw-r--r--drivers/acpi/executer/exstorob.c9
-rw-r--r--drivers/acpi/executer/exsystem.c48
-rw-r--r--drivers/acpi/executer/exutils.c37
-rw-r--r--drivers/acpi/glue.c360
-rw-r--r--drivers/acpi/hardware/hwacpi.c19
-rw-r--r--drivers/acpi/hardware/hwgpe.c31
-rw-r--r--drivers/acpi/hardware/hwregs.c114
-rw-r--r--drivers/acpi/hardware/hwsleep.c101
-rw-r--r--drivers/acpi/hardware/hwtimer.c4
-rw-r--r--drivers/acpi/hotkey.c1019
-rw-r--r--drivers/acpi/ibm_acpi.c8
-rw-r--r--drivers/acpi/namespace/nsaccess.c5
-rw-r--r--drivers/acpi/namespace/nsalloc.c121
-rw-r--r--drivers/acpi/namespace/nsdump.c109
-rw-r--r--drivers/acpi/namespace/nsdumpdv.c18
-rw-r--r--drivers/acpi/namespace/nseval.c70
-rw-r--r--drivers/acpi/namespace/nsinit.c28
-rw-r--r--drivers/acpi/namespace/nsload.c28
-rw-r--r--drivers/acpi/namespace/nsnames.c12
-rw-r--r--drivers/acpi/namespace/nsobject.c14
-rw-r--r--drivers/acpi/namespace/nssearch.c29
-rw-r--r--drivers/acpi/namespace/nsutils.c167
-rw-r--r--drivers/acpi/namespace/nswalk.c2
-rw-r--r--drivers/acpi/namespace/nsxfeval.c16
-rw-r--r--drivers/acpi/namespace/nsxfname.c8
-rw-r--r--drivers/acpi/namespace/nsxfobj.c4
-rw-r--r--drivers/acpi/osl.c12
-rw-r--r--drivers/acpi/parser/psargs.c55
-rw-r--r--drivers/acpi/parser/psopcode.c298
-rw-r--r--drivers/acpi/parser/psparse.c144
-rw-r--r--drivers/acpi/parser/psscope.c45
-rw-r--r--drivers/acpi/parser/pstree.c159
-rw-r--r--drivers/acpi/parser/psutils.c15
-rw-r--r--drivers/acpi/parser/pswalk.c11
-rw-r--r--drivers/acpi/parser/psxface.c21
-rw-r--r--drivers/acpi/pci_bind.c27
-rw-r--r--drivers/acpi/pci_irq.c3
-rw-r--r--drivers/acpi/pci_link.c43
-rw-r--r--drivers/acpi/pci_root.c24
-rw-r--r--drivers/acpi/processor_core.c39
-rw-r--r--drivers/acpi/processor_idle.c138
-rw-r--r--drivers/acpi/processor_perflib.c33
-rw-r--r--drivers/acpi/resources/rsaddr.c480
-rw-r--r--drivers/acpi/resources/rscalc.c144
-rw-r--r--drivers/acpi/resources/rscreate.c45
-rw-r--r--drivers/acpi/resources/rsdump.c402
-rw-r--r--drivers/acpi/resources/rsio.c197
-rw-r--r--drivers/acpi/resources/rsirq.c167
-rw-r--r--drivers/acpi/resources/rslist.c68
-rw-r--r--drivers/acpi/resources/rsmemory.c236
-rw-r--r--drivers/acpi/resources/rsmisc.c160
-rw-r--r--drivers/acpi/resources/rsutils.c53
-rw-r--r--drivers/acpi/resources/rsxface.c43
-rw-r--r--drivers/acpi/scan.c138
-rw-r--r--drivers/acpi/sleep/main.c74
-rw-r--r--drivers/acpi/sleep/poweroff.c81
-rw-r--r--drivers/acpi/sleep/proc.c9
-rw-r--r--drivers/acpi/tables/tbconvrt.c105
-rw-r--r--drivers/acpi/tables/tbget.c63
-rw-r--r--drivers/acpi/tables/tbgetall.c45
-rw-r--r--drivers/acpi/tables/tbinstal.c31
-rw-r--r--drivers/acpi/tables/tbrsdt.c19
-rw-r--r--drivers/acpi/tables/tbutils.c97
-rw-r--r--drivers/acpi/tables/tbxface.c39
-rw-r--r--drivers/acpi/tables/tbxfroot.c123
-rw-r--r--drivers/acpi/toshiba_acpi.c8
-rw-r--r--drivers/acpi/utilities/utalloc.c84
-rw-r--r--drivers/acpi/utilities/utcopy.c126
-rw-r--r--drivers/acpi/utilities/utdebug.c106
-rw-r--r--drivers/acpi/utilities/utdelete.c63
-rw-r--r--drivers/acpi/utilities/uteval.c36
-rw-r--r--drivers/acpi/utilities/utglobal.c133
-rw-r--r--drivers/acpi/utilities/utinit.c36
-rw-r--r--drivers/acpi/utilities/utmath.c2
-rw-r--r--drivers/acpi/utilities/utmisc.c187
-rw-r--r--drivers/acpi/utilities/utobject.c68
-rw-r--r--drivers/acpi/utilities/utxface.c61
-rw-r--r--drivers/acpi/video.c15
-rw-r--r--drivers/base/base.h1
-rw-r--r--drivers/base/bus.c117
-rw-r--r--drivers/base/core.c2
-rw-r--r--drivers/base/cpu.c11
-rw-r--r--drivers/base/dd.c2
-rw-r--r--drivers/base/driver.c35
-rw-r--r--drivers/base/firmware_class.c13
-rw-r--r--drivers/base/sys.c1
-rw-r--r--drivers/block/as-iosched.c5
-rw-r--r--drivers/block/cciss.c18
-rw-r--r--drivers/block/cfq-iosched.c2081
-rw-r--r--drivers/block/deadline-iosched.c3
-rw-r--r--drivers/block/elevator.c9
-rw-r--r--drivers/block/ll_rw_blk.c279
-rw-r--r--drivers/block/pktcdvd.c3
-rw-r--r--drivers/block/swim3.c10
-rw-r--r--drivers/block/sx8.c7
-rw-r--r--drivers/bluetooth/bluecard_cs.c16
-rw-r--r--drivers/bluetooth/bt3c_cs.c14
-rw-r--r--drivers/bluetooth/btuart_cs.c14
-rw-r--r--drivers/bluetooth/dtl1_cs.c15
-rw-r--r--drivers/bluetooth/hci_vhci.c2
-rw-r--r--drivers/cdrom/cm206.c113
-rw-r--r--drivers/cdrom/sonycd535.c3
-rw-r--r--drivers/char/Kconfig4
-rw-r--r--drivers/char/Makefile2
-rw-r--r--drivers/char/agp/amd64-agp.c9
-rw-r--r--drivers/char/amiserial.c4
-rw-r--r--drivers/char/applicom.c2
-rw-r--r--drivers/char/drm/Kconfig9
-rw-r--r--drivers/char/drm/Makefile10
-rw-r--r--drivers/char/drm/ati_pcigart.c2
-rw-r--r--drivers/char/drm/drm.h2
-rw-r--r--drivers/char/drm/drmP.h35
-rw-r--r--drivers/char/drm/drm_auth.c4
-rw-r--r--drivers/char/drm/drm_bufs.c37
-rw-r--r--drivers/char/drm/drm_context.c10
-rw-r--r--drivers/char/drm/drm_drv.c9
-rw-r--r--drivers/char/drm/drm_fops.c14
-rw-r--r--drivers/char/drm/drm_ioc32.c1069
-rw-r--r--drivers/char/drm/drm_irq.c2
-rw-r--r--drivers/char/drm/drm_lock.c12
-rw-r--r--drivers/char/drm/drm_memory.c13
-rw-r--r--drivers/char/drm/drm_pciids.h7
-rw-r--r--drivers/char/drm/drm_proc.c2
-rw-r--r--drivers/char/drm/drm_stub.c92
-rw-r--r--drivers/char/drm/drm_vm.c10
-rw-r--r--drivers/char/drm/i810_dma.c24
-rw-r--r--drivers/char/drm/i810_drv.h1
-rw-r--r--drivers/char/drm/i830_dma.c20
-rw-r--r--drivers/char/drm/i830_drv.c2
-rw-r--r--drivers/char/drm/i830_drv.h2
-rw-r--r--drivers/char/drm/i830_irq.c5
-rw-r--r--drivers/char/drm/i915_dma.c84
-rw-r--r--drivers/char/drm/i915_drm.h27
-rw-r--r--drivers/char/drm/i915_drv.c30
-rw-r--r--drivers/char/drm/i915_drv.h38
-rw-r--r--drivers/char/drm/i915_ioc32.c221
-rw-r--r--drivers/char/drm/i915_irq.c28
-rw-r--r--drivers/char/drm/i915_mem.c24
-rw-r--r--drivers/char/drm/mga_drv.c3
-rw-r--r--drivers/char/drm/mga_drv.h2
-rw-r--r--drivers/char/drm/mga_ioc32.c167
-rw-r--r--drivers/char/drm/r128_drv.c3
-rw-r--r--drivers/char/drm/r128_drv.h3
-rw-r--r--drivers/char/drm/r128_ioc32.c219
-rw-r--r--drivers/char/drm/r128_state.c2
-rw-r--r--drivers/char/drm/radeon_drv.c3
-rw-r--r--drivers/char/drm/radeon_drv.h3
-rw-r--r--drivers/char/drm/radeon_ioc32.c395
-rw-r--r--drivers/char/drm/radeon_irq.c27
-rw-r--r--drivers/char/drm/via_3d_reg.h1651
-rw-r--r--drivers/char/drm/via_dma.c741
-rw-r--r--drivers/char/drm/via_drm.h243
-rw-r--r--drivers/char/drm/via_drv.c126
-rw-r--r--drivers/char/drm/via_drv.h118
-rw-r--r--drivers/char/drm/via_ds.c280
-rw-r--r--drivers/char/drm/via_ds.h104
-rw-r--r--drivers/char/drm/via_irq.c339
-rw-r--r--drivers/char/drm/via_map.c110
-rw-r--r--drivers/char/drm/via_mm.c358
-rw-r--r--drivers/char/drm/via_mm.h40
-rw-r--r--drivers/char/drm/via_verifier.c1061
-rw-r--r--drivers/char/drm/via_verifier.h61
-rw-r--r--drivers/char/drm/via_video.c97
-rw-r--r--drivers/char/ds1620.c3
-rw-r--r--drivers/char/ftape/compressor/zftape-compress.c4
-rw-r--r--drivers/char/hpet.c2
-rw-r--r--drivers/char/hvc_console.c429
-rw-r--r--drivers/char/hvc_vio.c152
-rw-r--r--drivers/char/hvsi.c8
-rw-r--r--drivers/char/hw_random.c2
-rw-r--r--drivers/char/i8k.c909
-rw-r--r--drivers/char/ip2/i2cmd.c6
-rw-r--r--drivers/char/ip2/i2cmd.h12
-rw-r--r--drivers/char/ip2main.c10
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c196
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c50
-rw-r--r--drivers/char/ipmi/ipmi_poweroff.c137
-rw-r--r--drivers/char/isicom.c12
-rw-r--r--drivers/char/istallion.c3
-rw-r--r--drivers/char/mem.c53
-rw-r--r--drivers/char/misc.c11
-rw-r--r--drivers/char/moxa.c2
-rw-r--r--drivers/char/mwave/3780i.c6
-rw-r--r--drivers/char/mwave/3780i.h4
-rw-r--r--drivers/char/mwave/tp3780i.c14
-rw-r--r--drivers/char/n_tty.c33
-rw-r--r--drivers/char/nvram.c6
-rw-r--r--drivers/char/pcmcia/synclink_cs.c16
-rw-r--r--drivers/char/random.c2
-rw-r--r--drivers/char/rio/func.h1
-rw-r--r--drivers/char/rio/rio_linux.c9
-rw-r--r--drivers/char/rio/rioinit.c7
-rw-r--r--drivers/char/rio/riotty.c15
-rw-r--r--drivers/char/rocket.c226
-rw-r--r--drivers/char/rocket_int.h40
-rw-r--r--drivers/char/rtc.c16
-rw-r--r--drivers/char/sysrq.c26
-rw-r--r--drivers/char/tb0219.c19
-rw-r--r--drivers/char/tipar.c2
-rw-r--r--drivers/char/toshiba.c60
-rw-r--r--drivers/char/tpm/tpm.c360
-rw-r--r--drivers/char/tpm/tpm.h38
-rw-r--r--drivers/char/tpm/tpm_atmel.c63
-rw-r--r--drivers/char/tpm/tpm_nsc.c199
-rw-r--r--drivers/char/tty_io.c10
-rw-r--r--drivers/char/tty_ioctl.c4
-rw-r--r--drivers/char/vt_ioctl.c5
-rw-r--r--drivers/char/watchdog/i8xx_tco.c2
-rw-r--r--drivers/char/watchdog/ixp2000_wdt.c2
-rw-r--r--drivers/char/watchdog/ixp4xx_wdt.c2
-rw-r--r--drivers/cpufreq/cpufreq.c4
-rw-r--r--drivers/crypto/padlock-aes.c153
-rw-r--r--drivers/crypto/padlock.h22
-rw-r--r--drivers/firmware/efivars.c7
-rw-r--r--drivers/firmware/pcdp.c24
-rw-r--r--drivers/firmware/pcdp.h33
-rw-r--r--drivers/hwmon/Kconfig420
-rw-r--r--drivers/hwmon/Makefile44
-rw-r--r--drivers/hwmon/adm1021.c (renamed from drivers/i2c/chips/adm1021.c)0
-rw-r--r--drivers/hwmon/adm1025.c (renamed from drivers/i2c/chips/adm1025.c)0
-rw-r--r--drivers/hwmon/adm1026.c (renamed from drivers/i2c/chips/adm1026.c)0
-rw-r--r--drivers/hwmon/adm1031.c (renamed from drivers/i2c/chips/adm1031.c)0
-rw-r--r--drivers/hwmon/adm9240.c (renamed from drivers/i2c/chips/adm9240.c)0
-rw-r--r--drivers/hwmon/asb100.c (renamed from drivers/i2c/chips/asb100.c)0
-rw-r--r--drivers/hwmon/atxp1.c (renamed from drivers/i2c/chips/atxp1.c)2
-rw-r--r--drivers/hwmon/ds1621.c (renamed from drivers/i2c/chips/ds1621.c)0
-rw-r--r--drivers/hwmon/fscher.c (renamed from drivers/i2c/chips/fscher.c)0
-rw-r--r--drivers/hwmon/fscpos.c (renamed from drivers/i2c/chips/fscpos.c)0
-rw-r--r--drivers/hwmon/gl518sm.c (renamed from drivers/i2c/chips/gl518sm.c)0
-rw-r--r--drivers/hwmon/gl520sm.c (renamed from drivers/i2c/chips/gl520sm.c)0
-rw-r--r--drivers/hwmon/it87.c (renamed from drivers/i2c/chips/it87.c)0
-rw-r--r--drivers/hwmon/lm63.c (renamed from drivers/i2c/chips/lm63.c)0
-rw-r--r--drivers/hwmon/lm75.c (renamed from drivers/i2c/chips/lm75.c)0
-rw-r--r--drivers/hwmon/lm75.h (renamed from drivers/i2c/chips/lm75.h)0
-rw-r--r--drivers/hwmon/lm77.c (renamed from drivers/i2c/chips/lm77.c)0
-rw-r--r--drivers/hwmon/lm78.c (renamed from drivers/i2c/chips/lm78.c)0
-rw-r--r--drivers/hwmon/lm80.c (renamed from drivers/i2c/chips/lm80.c)0
-rw-r--r--drivers/hwmon/lm83.c (renamed from drivers/i2c/chips/lm83.c)0
-rw-r--r--drivers/hwmon/lm85.c (renamed from drivers/i2c/chips/lm85.c)0
-rw-r--r--drivers/hwmon/lm87.c (renamed from drivers/i2c/chips/lm87.c)0
-rw-r--r--drivers/hwmon/lm90.c (renamed from drivers/i2c/chips/lm90.c)0
-rw-r--r--drivers/hwmon/lm92.c (renamed from drivers/i2c/chips/lm92.c)0
-rw-r--r--drivers/hwmon/max1619.c (renamed from drivers/i2c/chips/max1619.c)0
-rw-r--r--drivers/hwmon/pc87360.c (renamed from drivers/i2c/chips/pc87360.c)0
-rw-r--r--drivers/hwmon/sis5595.c (renamed from drivers/i2c/chips/sis5595.c)0
-rw-r--r--drivers/hwmon/smsc47b397.c (renamed from drivers/i2c/chips/smsc47b397.c)0
-rw-r--r--drivers/hwmon/smsc47m1.c (renamed from drivers/i2c/chips/smsc47m1.c)0
-rw-r--r--drivers/hwmon/via686a.c (renamed from drivers/i2c/chips/via686a.c)12
-rw-r--r--drivers/hwmon/w83627ehf.c (renamed from drivers/i2c/chips/w83627ehf.c)0
-rw-r--r--drivers/hwmon/w83627hf.c (renamed from drivers/i2c/chips/w83627hf.c)0
-rw-r--r--drivers/hwmon/w83781d.c (renamed from drivers/i2c/chips/w83781d.c)0
-rw-r--r--drivers/hwmon/w83l785ts.c (renamed from drivers/i2c/chips/w83l785ts.c)0
-rw-r--r--drivers/i2c/algos/i2c-algo-ite.c8
-rw-r--r--drivers/i2c/busses/i2c-i801.c4
-rw-r--r--drivers/i2c/busses/i2c-ixp2000.c3
-rw-r--r--drivers/i2c/busses/i2c-keywest.c7
-rw-r--r--drivers/i2c/busses/i2c-mpc.c204
-rw-r--r--drivers/i2c/busses/i2c-piix4.c2
-rw-r--r--drivers/i2c/busses/i2c-sis5595.c2
-rw-r--r--drivers/i2c/chips/Kconfig413
-rw-r--r--drivers/i2c/chips/Makefile38
-rw-r--r--drivers/i2c/chips/eeprom.c3
-rw-r--r--drivers/i2c/chips/m41t00.c2
-rw-r--r--drivers/i2c/chips/max6875.c6
-rw-r--r--drivers/i2c/chips/tps65010.c59
-rw-r--r--drivers/i2c/i2c-core.c17
-rw-r--r--drivers/ide/Kconfig6
-rw-r--r--drivers/ide/Makefile1
-rw-r--r--drivers/ide/ide-cd.c4
-rw-r--r--drivers/ide/ide-disk.c4
-rw-r--r--drivers/ide/ide-dma.c1
-rw-r--r--drivers/ide/ide-iops.c3
-rw-r--r--drivers/ide/ide-lib.c13
-rw-r--r--drivers/ide/legacy/hd.c4
-rw-r--r--drivers/ide/legacy/ide-cs.c42
-rw-r--r--drivers/ide/pci/Makefile1
-rw-r--r--drivers/ide/pci/alim15x3.c10
-rw-r--r--drivers/ide/pci/amd74xx.c7
-rw-r--r--drivers/ide/pci/cs5530.c4
-rw-r--r--drivers/ide/pci/cy82c693.c8
-rw-r--r--drivers/ide/pci/generic.c73
-rw-r--r--drivers/ide/pci/hpt366.c470
-rw-r--r--drivers/ide/pci/it8172.c4
-rw-r--r--drivers/ide/pci/it821x.c812
-rw-r--r--drivers/ide/pci/ns87415.c2
-rw-r--r--drivers/ide/pci/opti621.c2
-rw-r--r--drivers/ide/pci/sc1200.c2
-rw-r--r--drivers/ide/pci/serverworks.c10
-rw-r--r--drivers/ide/pci/sl82c105.c6
-rw-r--r--drivers/ide/pci/slc90e66.c2
-rw-r--r--drivers/ide/pci/triflex.c2
-rw-r--r--drivers/ide/pci/via82cxxx.c4
-rw-r--r--drivers/ide/ppc/pmac.c20
-rw-r--r--drivers/ide/setup-pci.c2
-rw-r--r--drivers/ieee1394/Kconfig12
-rw-r--r--drivers/ieee1394/csr.c3
-rw-r--r--drivers/ieee1394/csr1212.c37
-rw-r--r--drivers/ieee1394/dma.c2
-rw-r--r--drivers/ieee1394/eth1394.c6
-rw-r--r--drivers/ieee1394/ieee1394_core.c39
-rw-r--r--drivers/ieee1394/ieee1394_core.h4
-rw-r--r--drivers/ieee1394/iso.c27
-rw-r--r--drivers/ieee1394/iso.h13
-rw-r--r--drivers/ieee1394/nodemgr.c4
-rw-r--r--drivers/ieee1394/ohci1394.c50
-rw-r--r--drivers/ieee1394/pcilynx.c4
-rw-r--r--drivers/ieee1394/raw1394.c7
-rw-r--r--drivers/ieee1394/sbp2.c135
-rw-r--r--drivers/infiniband/Kconfig10
-rw-r--r--drivers/infiniband/core/Makefile5
-rw-r--r--drivers/infiniband/core/packer.c4
-rw-r--r--drivers/infiniband/core/sa_query.c18
-rw-r--r--drivers/infiniband/core/uverbs.h132
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c1006
-rw-r--r--drivers/infiniband/core/uverbs_main.c698
-rw-r--r--drivers/infiniband/core/uverbs_mem.c221
-rw-r--r--drivers/infiniband/core/verbs.c32
-rw-r--r--drivers/infiniband/hw/mthca/mthca_av.c1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.c531
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cmd.h48
-rw-r--r--drivers/infiniband/hw/mthca/mthca_cq.c177
-rw-r--r--drivers/infiniband/hw/mthca/mthca_dev.h18
-rw-r--r--drivers/infiniband/hw/mthca/mthca_doorbell.h1
-rw-r--r--drivers/infiniband/hw/mthca/mthca_eq.c58
-rw-r--r--drivers/infiniband/hw/mthca/mthca_main.c34
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mcg.c63
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.c151
-rw-r--r--drivers/infiniband/hw/mthca/mthca_memfree.h14
-rw-r--r--drivers/infiniband/hw/mthca/mthca_mr.c367
-rw-r--r--drivers/infiniband/hw/mthca/mthca_pd.c24
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.c334
-rw-r--r--drivers/infiniband/hw/mthca/mthca_provider.h30
-rw-r--r--drivers/infiniband/hw/mthca/mthca_qp.c344
-rw-r--r--drivers/infiniband/hw/mthca/mthca_user.h81
-rw-r--r--drivers/infiniband/include/ib_user_verbs.h389
-rw-r--r--drivers/infiniband/include/ib_verbs.h124
-rw-r--r--drivers/input/evdev.c407
-rw-r--r--drivers/input/gameport/Kconfig14
-rw-r--r--drivers/input/gameport/Makefile2
-rw-r--r--drivers/input/gameport/cs461x.c322
-rw-r--r--drivers/input/gameport/gameport.c36
-rw-r--r--drivers/input/gameport/ns558.c12
-rw-r--r--drivers/input/gameport/vortex.c186
-rw-r--r--drivers/input/input.c37
-rw-r--r--drivers/input/joydev.c116
-rw-r--r--drivers/input/joystick/a3d.c2
-rw-r--r--drivers/input/joystick/adi.c4
-rw-r--r--drivers/input/joystick/amijoy.c29
-rw-r--r--drivers/input/joystick/analog.c4
-rw-r--r--drivers/input/joystick/db9.c17
-rw-r--r--drivers/input/joystick/gamecon.c29
-rw-r--r--drivers/input/joystick/gf2k.c2
-rw-r--r--drivers/input/joystick/grip_mp.c2
-rw-r--r--drivers/input/joystick/iforce/iforce-main.c1
-rw-r--r--drivers/input/joystick/iforce/iforce-usb.c1
-rw-r--r--drivers/input/joystick/spaceball.c4
-rw-r--r--drivers/input/joystick/spaceorb.c2
-rw-r--r--drivers/input/joystick/tmdc.c2
-rw-r--r--drivers/input/joystick/turbografx.c35
-rw-r--r--drivers/input/keyboard/atkbd.c6
-rw-r--r--drivers/input/keyboard/corgikbd.c6
-rw-r--r--drivers/input/keyboard/lkkbd.c8
-rw-r--r--drivers/input/keyboard/locomokbd.c28
-rw-r--r--drivers/input/keyboard/maple_keyb.c22
-rw-r--r--drivers/input/misc/uinput.c6
-rw-r--r--drivers/input/mouse/Makefile2
-rw-r--r--drivers/input/mouse/alps.c52
-rw-r--r--drivers/input/mouse/amimouse.c8
-rw-r--r--drivers/input/mouse/inport.c38
-rw-r--r--drivers/input/mouse/lifebook.c134
-rw-r--r--drivers/input/mouse/lifebook.h17
-rw-r--r--drivers/input/mouse/logibm.c17
-rw-r--r--drivers/input/mouse/maplemouse.c75
-rw-r--r--drivers/input/mouse/pc110pad.c21
-rw-r--r--drivers/input/mouse/psmouse-base.c351
-rw-r--r--drivers/input/mouse/psmouse.h4
-rw-r--r--drivers/input/mouse/rpcmouse.c2
-rw-r--r--drivers/input/mouse/vsxxxaa.c4
-rw-r--r--drivers/input/mousedev.c8
-rw-r--r--drivers/input/serio/i8042.c2
-rw-r--r--drivers/input/serio/libps2.c136
-rw-r--r--drivers/input/serio/serio.c91
-rw-r--r--drivers/input/touchscreen/elo.c2
-rw-r--r--drivers/input/touchscreen/h3600_ts_input.c180
-rw-r--r--drivers/input/touchscreen/mk712.c21
-rw-r--r--drivers/isdn/act2000/capi.c2
-rw-r--r--drivers/isdn/act2000/capi.h1
-rw-r--r--drivers/isdn/hardware/avm/avm_cs.c16
-rw-r--r--drivers/isdn/hardware/avm/b1dma.c4
-rw-r--r--drivers/isdn/hardware/avm/c4.c6
-rw-r--r--drivers/isdn/hardware/avm/t1isa.c2
-rw-r--r--drivers/isdn/hardware/eicon/dadapter.c2
-rw-r--r--drivers/isdn/hisax/Makefile2
-rw-r--r--drivers/isdn/hisax/amd7930_fn.c8
-rw-r--r--drivers/isdn/hisax/asuscom.c4
-rw-r--r--drivers/isdn/hisax/avm_pci.c18
-rw-r--r--drivers/isdn/hisax/avma1_cs.c15
-rw-r--r--drivers/isdn/hisax/bkm_a4t.c4
-rw-r--r--drivers/isdn/hisax/bkm_a8.c6
-rw-r--r--drivers/isdn/hisax/callc.c6
-rw-r--r--drivers/isdn/hisax/config.c14
-rw-r--r--drivers/isdn/hisax/diva.c4
-rw-r--r--drivers/isdn/hisax/elsa.c8
-rw-r--r--drivers/isdn/hisax/elsa_cs.c15
-rw-r--r--drivers/isdn/hisax/elsa_ser.c20
-rw-r--r--drivers/isdn/hisax/enternow.h51
-rw-r--r--drivers/isdn/hisax/enternow_pci.c91
-rw-r--r--drivers/isdn/hisax/gazel.c5
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c10
-rw-r--r--drivers/isdn/hisax/hfc_2bds0.c12
-rw-r--r--drivers/isdn/hisax/hfc_2bs0.c12
-rw-r--r--drivers/isdn/hisax/hfc_pci.c12
-rw-r--r--drivers/isdn/hisax/hfc_pci.h1
-rw-r--r--drivers/isdn/hisax/hfc_sx.c10
-rw-r--r--drivers/isdn/hisax/hfc_sx.h1
-rw-r--r--drivers/isdn/hisax/hfc_usb.c6
-rw-r--r--drivers/isdn/hisax/hfc_usb.h4
-rw-r--r--drivers/isdn/hisax/hfcscard.c2
-rw-r--r--drivers/isdn/hisax/hisax.h5
-rw-r--r--drivers/isdn/hisax/hscx.c4
-rw-r--r--drivers/isdn/hisax/icc.c6
-rw-r--r--drivers/isdn/hisax/ipacx.c86
-rw-r--r--drivers/isdn/hisax/isac.c6
-rw-r--r--drivers/isdn/hisax/isar.c46
-rw-r--r--drivers/isdn/hisax/isdnl1.c11
-rw-r--r--drivers/isdn/hisax/isdnl2.c117
-rw-r--r--drivers/isdn/hisax/isdnl3.c4
-rw-r--r--drivers/isdn/hisax/isurf.c2
-rw-r--r--drivers/isdn/hisax/ix1_micro.c4
-rw-r--r--drivers/isdn/hisax/jade.c6
-rw-r--r--drivers/isdn/hisax/jade.h1
-rw-r--r--drivers/isdn/hisax/l3_1tr6.c2
-rw-r--r--drivers/isdn/hisax/l3dss1.c2
-rw-r--r--drivers/isdn/hisax/l3ni1.c4
-rw-r--r--drivers/isdn/hisax/mic.c4
-rw-r--r--drivers/isdn/hisax/netjet.c12
-rw-r--r--drivers/isdn/hisax/niccy.c4
-rw-r--r--drivers/isdn/hisax/nj_s.c2
-rw-r--r--drivers/isdn/hisax/nj_u.c2
-rw-r--r--drivers/isdn/hisax/q931.c4
-rw-r--r--drivers/isdn/hisax/s0box.c4
-rw-r--r--drivers/isdn/hisax/saphir.c2
-rw-r--r--drivers/isdn/hisax/sedlbauer.c6
-rw-r--r--drivers/isdn/hisax/sedlbauer_cs.c20
-rw-r--r--drivers/isdn/hisax/sportster.c6
-rw-r--r--drivers/isdn/hisax/st5481.h4
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.c580
-rw-r--r--drivers/isdn/hisax/st5481_hdlc.h62
-rw-r--r--drivers/isdn/hisax/st5481_usb.c10
-rw-r--r--drivers/isdn/hisax/tei.c2
-rw-r--r--drivers/isdn/hisax/teleint.c4
-rw-r--r--drivers/isdn/hisax/teles0.c4
-rw-r--r--drivers/isdn/hisax/teles3.c4
-rw-r--r--drivers/isdn/hisax/teles_cs.c14
-rw-r--r--drivers/isdn/hisax/telespci.c4
-rw-r--r--drivers/isdn/hisax/w6692.c6
-rw-r--r--drivers/isdn/hysdn/hycapi.c20
-rw-r--r--drivers/isdn/hysdn/hysdn_boot.c4
-rw-r--r--drivers/isdn/hysdn/hysdn_defs.h12
-rw-r--r--drivers/isdn/hysdn/hysdn_init.c2
-rw-r--r--drivers/isdn/hysdn/hysdn_proclog.c4
-rw-r--r--drivers/isdn/i4l/isdn_audio.c10
-rw-r--r--drivers/isdn/i4l/isdn_audio.h1
-rw-r--r--drivers/isdn/i4l/isdn_common.c6
-rw-r--r--drivers/isdn/i4l/isdn_common.h1
-rw-r--r--drivers/isdn/i4l/isdn_concap.c15
-rw-r--r--drivers/isdn/i4l/isdn_concap.h1
-rw-r--r--drivers/isdn/i4l/isdn_net.c10
-rw-r--r--drivers/isdn/i4l/isdn_tty.c8
-rw-r--r--drivers/isdn/i4l/isdn_tty.h1
-rw-r--r--drivers/isdn/i4l/isdn_ttyfax.c6
-rw-r--r--drivers/isdn/i4l/isdn_x25iface.c36
-rw-r--r--drivers/isdn/icn/icn.c4
-rw-r--r--drivers/isdn/pcbit/callbacks.c17
-rw-r--r--drivers/isdn/pcbit/callbacks.h3
-rw-r--r--drivers/isdn/pcbit/capi.c10
-rw-r--r--drivers/isdn/pcbit/capi.h1
-rw-r--r--drivers/isdn/pcbit/drv.c16
-rw-r--r--drivers/isdn/sc/Makefile2
-rw-r--r--drivers/isdn/sc/command.c88
-rw-r--r--drivers/isdn/sc/debug.c46
-rw-r--r--drivers/isdn/sc/init.c21
-rw-r--r--drivers/isdn/sc/interrupt.c2
-rw-r--r--drivers/isdn/sc/ioctl.c5
-rw-r--r--drivers/isdn/sc/packet.c16
-rw-r--r--drivers/isdn/sc/shmem.c2
-rw-r--r--drivers/isdn/sc/timer.c18
-rw-r--r--drivers/macintosh/Kconfig42
-rw-r--r--drivers/macintosh/Makefile5
-rw-r--r--drivers/macintosh/adb.c10
-rw-r--r--drivers/macintosh/macio_asic.c78
-rw-r--r--drivers/macintosh/macio_sysfs.c50
-rw-r--r--drivers/macintosh/macserial.c3036
-rw-r--r--drivers/macintosh/macserial.h461
-rw-r--r--drivers/macintosh/mediabay.c7
-rw-r--r--drivers/macintosh/therm_adt746x.c4
-rw-r--r--drivers/macintosh/therm_pm72.c9
-rw-r--r--drivers/macintosh/therm_windtunnel.c6
-rw-r--r--drivers/macintosh/via-pmu.c78
-rw-r--r--drivers/mca/mca-legacy.c1
-rw-r--r--drivers/md/dm-mpath.c68
-rw-r--r--drivers/md/dm-raid1.c1
-rw-r--r--drivers/md/dm-snap.c6
-rw-r--r--drivers/md/dm-table.c1
-rw-r--r--drivers/md/dm.c27
-rw-r--r--drivers/md/md.c4
-rw-r--r--drivers/media/common/ir-common.c259
-rw-r--r--drivers/media/common/saa7146_core.c13
-rw-r--r--drivers/media/common/saa7146_fops.c2
-rw-r--r--drivers/media/dvb/Kconfig6
-rw-r--r--drivers/media/dvb/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/Kconfig15
-rw-r--r--drivers/media/dvb/b2c2/Makefile2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h6
-rw-r--r--drivers/media/dvb/b2c2/flexcop-dma.c165
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c26
-rw-r--r--drivers/media/dvb/b2c2/flexcop-hw-filter.c12
-rw-r--r--drivers/media/dvb/b2c2/flexcop-misc.c23
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c122
-rw-r--r--drivers/media/dvb/b2c2/flexcop-reg.h551
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c2
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c34
-rw-r--r--drivers/media/dvb/b2c2/flexcop.h1
-rw-r--r--drivers/media/dvb/b2c2/flexcop_ibi_value_be.h458
-rw-r--r--drivers/media/dvb/b2c2/flexcop_ibi_value_le.h458
-rw-r--r--drivers/media/dvb/b2c2/skystar2.c2644
-rw-r--r--drivers/media/dvb/bt8xx/dst.c233
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c349
-rw-r--r--drivers/media/dvb/bt8xx/dst_common.h3
-rw-r--r--drivers/media/dvb/cinergyT2/cinergyT2.c4
-rw-r--r--drivers/media/dvb/dibusb/Kconfig62
-rw-r--r--drivers/media/dvb/dibusb/Makefile11
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-core.c558
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-dvb.c185
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c582
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-firmware.c87
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-remote.c316
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb-usb.c303
-rw-r--r--drivers/media/dvb/dibusb/dvb-dibusb.h327
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c19
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c51
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h22
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig119
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile33
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c182
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c295
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.h30
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c272
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c350
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c116
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h122
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c261
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.h65
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u-fe.c (renamed from drivers/media/dvb/dibusb/dvb-fe-dtt200u.c)163
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c233
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.h56
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-common.h46
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-dvb.c210
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-firmware.c100
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c118
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h89
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c215
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c181
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-urb.c325
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h329
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c236
-rw-r--r--drivers/media/dvb/dvb-usb/umt-010.c162
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045-fe.c196
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c288
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.h78
-rw-r--r--drivers/media/dvb/frontends/Kconfig21
-rw-r--r--drivers/media/dvb/frontends/Makefile3
-rw-r--r--drivers/media/dvb/frontends/bcm3510.c853
-rw-r--r--drivers/media/dvb/frontends/bcm3510.h40
-rw-r--r--drivers/media/dvb/frontends/bcm3510_priv.h460
-rw-r--r--drivers/media/dvb/frontends/cx22702.c29
-rw-r--r--drivers/media/dvb/frontends/cx22702.h5
-rw-r--r--drivers/media/dvb/frontends/dib3000-common.c2
-rw-r--r--drivers/media/dvb/frontends/dib3000.h5
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c20
-rw-r--r--drivers/media/dvb/frontends/dib3000mb_priv.h2
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c29
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c175
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h15
-rw-r--r--drivers/media/dvb/frontends/l64781.c9
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.c609
-rw-r--r--drivers/media/dvb/frontends/lgdt3302.h49
-rw-r--r--drivers/media/dvb/frontends/lgdt3302_priv.h72
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c800
-rw-r--r--drivers/media/dvb/frontends/s5h1420.h41
-rw-r--r--drivers/media/dvb/frontends/stv0297.c8
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c235
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h31
-rw-r--r--drivers/media/dvb/frontends/tda80xx.c1
-rw-r--r--drivers/media/dvb/pluto2/Kconfig16
-rw-r--r--drivers/media/dvb/pluto2/Makefile3
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c809
-rw-r--r--drivers/media/dvb/ttpci/Kconfig9
-rw-r--r--drivers/media/dvb/ttpci/av7110.c251
-rw-r--r--drivers/media/dvb/ttpci/av7110.h7
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c220
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.h4
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c395
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.h12
-rw-r--r--drivers/media/dvb/ttpci/av7110_ipack.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c12
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c21
-rw-r--r--drivers/media/dvb/ttpci/budget.c99
-rw-r--r--drivers/media/dvb/ttusb-budget/Kconfig1
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c52
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusb_dec.c11
-rw-r--r--drivers/media/dvb/ttusb-dec/ttusbdecfe.c14
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile3
-rw-r--r--drivers/media/video/bt832.c58
-rw-r--r--drivers/media/video/bt832.h36
-rw-r--r--drivers/media/video/bttv-cards.c208
-rw-r--r--drivers/media/video/bttv-driver.c90
-rw-r--r--drivers/media/video/bttv-i2c.c26
-rw-r--r--drivers/media/video/bttv-risc.c9
-rw-r--r--drivers/media/video/bttv.h3
-rw-r--r--drivers/media/video/bttvp.h13
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c489
-rw-r--r--drivers/media/video/cx88/cx88-cards.c279
-rw-r--r--drivers/media/video/cx88/cx88-core.c85
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c93
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c30
-rw-r--r--drivers/media/video/cx88/cx88-input.c385
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c75
-rw-r--r--drivers/media/video/cx88/cx88-reg.h12
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c177
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c6
-rw-r--r--drivers/media/video/cx88/cx88-video.c369
-rw-r--r--drivers/media/video/cx88/cx88.h40
-rw-r--r--drivers/media/video/ir-kbd-gpio.c34
-rw-r--r--drivers/media/video/ir-kbd-i2c.c51
-rw-r--r--drivers/media/video/msp3400.c32
-rw-r--r--drivers/media/video/msp3400.h4
-rw-r--r--drivers/media/video/mt20xx.c22
-rw-r--r--drivers/media/video/mxb.c7
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c24
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c2081
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c80
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c423
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c45
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c158
-rw-r--r--drivers/media/video/saa7134/saa7134-oss.c33
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c134
-rw-r--r--drivers/media/video/saa7134/saa7134-vbi.c26
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c144
-rw-r--r--drivers/media/video/saa7134/saa7134.h36
-rw-r--r--drivers/media/video/tda7432.c13
-rw-r--r--drivers/media/video/tda8290.c23
-rw-r--r--drivers/media/video/tda9875.c13
-rw-r--r--drivers/media/video/tda9887.c52
-rw-r--r--drivers/media/video/tea5767.c338
-rw-r--r--drivers/media/video/tuner-3036.c2
-rw-r--r--drivers/media/video/tuner-core.c636
-rw-r--r--drivers/media/video/tuner-simple.c106
-rw-r--r--drivers/media/video/tvaudio.c28
-rw-r--r--drivers/media/video/tveeprom.c11
-rw-r--r--drivers/media/video/tvmixer.c4
-rw-r--r--drivers/media/video/v4l1-compat.c10
-rw-r--r--drivers/media/video/video-buf-dvb.c3
-rw-r--r--drivers/message/fusion/mptbase.c14
-rw-r--r--drivers/message/fusion/mptfc.c4
-rw-r--r--drivers/message/fusion/mptscsih.c10
-rw-r--r--drivers/message/fusion/mptscsih.h4
-rw-r--r--drivers/message/fusion/mptspi.c4
-rw-r--r--drivers/message/i2o/Kconfig46
-rw-r--r--drivers/message/i2o/Makefile3
-rw-r--r--drivers/message/i2o/bus-osm.c164
-rw-r--r--drivers/message/i2o/config-osm.c581
-rw-r--r--drivers/message/i2o/core.h58
-rw-r--r--drivers/message/i2o/debug.c3
-rw-r--r--drivers/message/i2o/device.c40
-rw-r--r--drivers/message/i2o/driver.c130
-rw-r--r--drivers/message/i2o/exec-osm.c131
-rw-r--r--drivers/message/i2o/i2o_block.c453
-rw-r--r--drivers/message/i2o/i2o_block.h34
-rw-r--r--drivers/message/i2o/i2o_config.c124
-rw-r--r--drivers/message/i2o/i2o_proc.c6
-rw-r--r--drivers/message/i2o/i2o_scsi.c505
-rw-r--r--drivers/message/i2o/iop.c566
-rw-r--r--drivers/message/i2o/pci.c246
-rw-r--r--drivers/misc/Kconfig5
-rw-r--r--drivers/mmc/mmci.c9
-rw-r--r--drivers/mmc/wbsd.c80
-rw-r--r--drivers/mmc/wbsd.h9
-rw-r--r--drivers/mtd/afs.c16
-rw-r--r--drivers/mtd/chips/Kconfig29
-rw-r--r--drivers/mtd/chips/amd_flash.c14
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0001.c580
-rw-r--r--drivers/mtd/chips/cfi_cmdset_0002.c497
-rw-r--r--drivers/mtd/chips/fwh_lock.h6
-rw-r--r--drivers/mtd/chips/gen_probe.c4
-rw-r--r--drivers/mtd/chips/jedec_probe.c28
-rw-r--r--drivers/mtd/cmdlinepart.c8
-rw-r--r--drivers/mtd/devices/block2mtd.c20
-rw-r--r--drivers/mtd/devices/ms02-nv.c8
-rw-r--r--drivers/mtd/devices/mtdram.c265
-rw-r--r--drivers/mtd/devices/phram.c34
-rw-r--r--drivers/mtd/devices/slram.c23
-rw-r--r--drivers/mtd/ftl.c5
-rw-r--r--drivers/mtd/maps/Kconfig127
-rw-r--r--drivers/mtd/maps/Makefile11
-rw-r--r--drivers/mtd/maps/alchemy-flash.c192
-rw-r--r--drivers/mtd/maps/amd76xrom.c4
-rw-r--r--drivers/mtd/maps/bast-flash.c13
-rw-r--r--drivers/mtd/maps/db1550-flash.c187
-rw-r--r--drivers/mtd/maps/db1x00-flash.c226
-rw-r--r--drivers/mtd/maps/elan-104nc.c228
-rw-r--r--drivers/mtd/maps/ichxrom.c6
-rw-r--r--drivers/mtd/maps/ixp2000.c7
-rw-r--r--drivers/mtd/maps/mainstone-flash.c178
-rw-r--r--drivers/mtd/maps/map_funcs.c11
-rw-r--r--drivers/mtd/maps/omap_nor.c179
-rw-r--r--drivers/mtd/maps/pb1550-flash.c203
-rw-r--r--drivers/mtd/maps/pb1xxx-flash.c178
-rw-r--r--drivers/mtd/maps/pci.c4
-rw-r--r--drivers/mtd/maps/pcmciamtd.c36
-rw-r--r--drivers/mtd/maps/plat-ram.c278
-rw-r--r--drivers/mtd/maps/scb2_flash.c4
-rw-r--r--drivers/mtd/maps/sharpsl-flash.c33
-rw-r--r--drivers/mtd/mtdchar.c176
-rw-r--r--drivers/mtd/mtdcore.c6
-rw-r--r--drivers/mtd/mtdpart.c28
-rw-r--r--drivers/mtd/nand/Kconfig21
-rw-r--r--drivers/mtd/nand/Makefile2
-rw-r--r--drivers/mtd/nand/diskonchip.c96
-rw-r--r--drivers/mtd/nand/nand_base.c299
-rw-r--r--drivers/mtd/nand/nand_bbt.c114
-rw-r--r--drivers/mtd/nand/nand_ids.c18
-rw-r--r--drivers/mtd/nand/nandsim.c41
-rw-r--r--drivers/mtd/nand/rtc_from4.c140
-rw-r--r--drivers/mtd/nand/s3c2410.c297
-rw-r--r--[-rwxr-xr-x]drivers/mtd/nand/sharpsl.c4
-rw-r--r--drivers/mtd/nand/tx4925ndfmc.c416
-rw-r--r--drivers/mtd/nand/tx4938ndfmc.c406
-rw-r--r--drivers/net/3c503.c16
-rw-r--r--drivers/net/3c505.c6
-rw-r--r--drivers/net/3c509.c1
-rw-r--r--drivers/net/3c515.c16
-rw-r--r--drivers/net/3c523.c19
-rw-r--r--drivers/net/3c59x.c6
-rw-r--r--drivers/net/8139cp.c25
-rw-r--r--drivers/net/8139too.c2
-rw-r--r--drivers/net/82596.c14
-rw-r--r--drivers/net/Kconfig11
-rw-r--r--drivers/net/ac3200.c19
-rw-r--r--drivers/net/acenic.c5
-rwxr-xr-xdrivers/net/amd8111e.c8
-rw-r--r--drivers/net/appletalk/Kconfig27
-rw-r--r--drivers/net/arm/etherh.c16
-rw-r--r--drivers/net/at1700.c4
-rw-r--r--drivers/net/b44.c6
-rw-r--r--drivers/net/bmac.c7
-rw-r--r--drivers/net/bonding/bond_3ad.c3
-rw-r--r--drivers/net/bonding/bond_main.c390
-rw-r--r--drivers/net/bonding/bonding.h12
-rw-r--r--drivers/net/cs89x0.c59
-rw-r--r--drivers/net/cs89x0.h2
-rw-r--r--drivers/net/defxx.c88
-rw-r--r--drivers/net/dl2k.c8
-rw-r--r--drivers/net/dm9000.c4
-rw-r--r--drivers/net/e100.c37
-rw-r--r--drivers/net/e1000/e1000.h4
-rw-r--r--drivers/net/e1000/e1000_ethtool.c131
-rw-r--r--drivers/net/e1000/e1000_hw.c23
-rw-r--r--drivers/net/e1000/e1000_hw.h1
-rw-r--r--drivers/net/e1000/e1000_main.c111
-rw-r--r--drivers/net/e2100.c15
-rw-r--r--drivers/net/eepro.c21
-rw-r--r--drivers/net/eepro100.c8
-rw-r--r--drivers/net/eexpress.c12
-rw-r--r--drivers/net/epic100.c6
-rw-r--r--drivers/net/es3210.c16
-rw-r--r--drivers/net/eth16i.c20
-rw-r--r--drivers/net/ewrk3.c12
-rw-r--r--drivers/net/fealnx.c11
-rw-r--r--drivers/net/forcedeth.c53
-rw-r--r--drivers/net/gianfar.c652
-rw-r--r--drivers/net/gianfar.h363
-rw-r--r--drivers/net/gianfar_ethtool.c277
-rw-r--r--drivers/net/gianfar_phy.c2
-rw-r--r--drivers/net/hamachi.c12
-rw-r--r--drivers/net/hamradio/scc.c5
-rw-r--r--drivers/net/hp-plus.c15
-rw-r--r--drivers/net/hp.c17
-rw-r--r--drivers/net/hp100.c44
-rw-r--r--drivers/net/irda/sir_kthread.c3
-rw-r--r--drivers/net/irda/stir4200.c4
-rw-r--r--drivers/net/isa-skeleton.c20
-rw-r--r--drivers/net/ixgb/ixgb_main.c5
-rw-r--r--drivers/net/lance.c17
-rw-r--r--drivers/net/lasi_82596.c8
-rw-r--r--drivers/net/lne390.c19
-rw-r--r--drivers/net/mace.c6
-rw-r--r--drivers/net/myri_code.h1283
-rw-r--r--drivers/net/myri_sbus.c2
-rw-r--r--drivers/net/natsemi.c4
-rw-r--r--drivers/net/ne-h8300.c19
-rw-r--r--drivers/net/ne.c18
-rw-r--r--drivers/net/ne2.c19
-rw-r--r--drivers/net/ne2k-pci.c3
-rw-r--r--drivers/net/ns83820.c5
-rw-r--r--drivers/net/pcmcia/3c574_cs.c15
-rw-r--r--drivers/net/pcmcia/3c589_cs.c19
-rw-r--r--drivers/net/pcmcia/axnet_cs.c36
-rw-r--r--drivers/net/pcmcia/com20020_cs.c14
-rw-r--r--drivers/net/pcmcia/fmvj18x_cs.c37
-rw-r--r--drivers/net/pcmcia/ibmtr_cs.c18
-rw-r--r--drivers/net/pcmcia/nmclan_cs.c15
-rw-r--r--drivers/net/pcmcia/pcnet_cs.c220
-rw-r--r--drivers/net/pcmcia/smc91c92_cs.c326
-rw-r--r--drivers/net/pcmcia/xirc2ps_cs.c35
-rw-r--r--drivers/net/pcnet32.c8
-rw-r--r--drivers/net/plip.c2
-rw-r--r--drivers/net/ppp_async.c2
-rw-r--r--drivers/net/ppp_generic.c12
-rw-r--r--drivers/net/ppp_synctty.c2
-rw-r--r--drivers/net/r8169.c4
-rw-r--r--drivers/net/s2io.c15
-rw-r--r--drivers/net/sb1000.c14
-rw-r--r--drivers/net/sb1250-mac.c4
-rw-r--r--drivers/net/shaper.c42
-rw-r--r--drivers/net/sis900.c11
-rw-r--r--drivers/net/sk98lin/skge.c5
-rw-r--r--drivers/net/skfp/Makefile4
-rw-r--r--drivers/net/skfp/drvfbi.c222
-rw-r--r--drivers/net/skfp/ess.c4
-rw-r--r--drivers/net/skfp/fplustm.c70
-rw-r--r--drivers/net/skfp/h/cmtdef.h7
-rw-r--r--drivers/net/skfp/h/hwmtm.h25
-rw-r--r--drivers/net/skfp/h/osdef1st.h2
-rw-r--r--drivers/net/skfp/hwmtm.c34
-rw-r--r--drivers/net/skfp/lnkstat.c204
-rw-r--r--drivers/net/skfp/pcmplc.c7
-rw-r--r--drivers/net/skfp/pmf.c11
-rw-r--r--drivers/net/skfp/skfddi.c1
-rw-r--r--drivers/net/skfp/smt.c48
-rw-r--r--drivers/net/skfp/smtdef.c5
-rw-r--r--drivers/net/skfp/smtparse.c467
-rw-r--r--drivers/net/skge.c1714
-rw-r--r--drivers/net/skge.h587
-rw-r--r--drivers/net/slip.c21
-rw-r--r--drivers/net/smc-mca.c60
-rw-r--r--drivers/net/smc-mca.h61
-rw-r--r--drivers/net/smc-ultra.c15
-rw-r--r--drivers/net/smc91x.c45
-rw-r--r--drivers/net/smc91x.h13
-rw-r--r--drivers/net/starfire.c6
-rw-r--r--drivers/net/sundance.c6
-rw-r--r--drivers/net/sungem.c9
-rw-r--r--drivers/net/sungem_phy.c69
-rw-r--r--drivers/net/sungem_phy.h3
-rw-r--r--drivers/net/tg3.c402
-rw-r--r--drivers/net/tg3.h34
-rw-r--r--drivers/net/tlan.c3
-rw-r--r--drivers/net/tokenring/3c359.c3
-rw-r--r--drivers/net/tokenring/3c359_microcode.h2
-rw-r--r--drivers/net/tokenring/abyss.c11
-rw-r--r--drivers/net/tokenring/ibmtr.c28
-rw-r--r--drivers/net/tokenring/lanstreamer.c9
-rw-r--r--drivers/net/tokenring/madgemc.c14
-rw-r--r--drivers/net/tokenring/proteon.c11
-rw-r--r--drivers/net/tokenring/skisa.c11
-rw-r--r--drivers/net/tokenring/smctr.c2
-rw-r--r--drivers/net/tokenring/smctr_firmware.h2
-rw-r--r--drivers/net/tokenring/tms380tr.c13
-rw-r--r--drivers/net/tokenring/tmspci.c11
-rw-r--r--drivers/net/tulip/de2104x.c6
-rw-r--r--drivers/net/tulip/dmfe.c23
-rw-r--r--drivers/net/tulip/eeprom.c16
-rw-r--r--drivers/net/tulip/interrupt.c10
-rw-r--r--drivers/net/tulip/media.c3
-rw-r--r--drivers/net/tulip/tulip_core.c50
-rw-r--r--drivers/net/tulip/winbond-840.c9
-rw-r--r--drivers/net/tulip/xircom_tulip_cb.c4
-rw-r--r--drivers/net/tun.c2
-rw-r--r--drivers/net/typhoon.c10
-rw-r--r--drivers/net/via-rhine.c26
-rw-r--r--drivers/net/via-velocity.c6
-rw-r--r--drivers/net/wan/Kconfig2
-rw-r--r--drivers/net/wan/farsync.c4
-rw-r--r--drivers/net/wan/hdlc_cisco.c5
-rw-r--r--drivers/net/wan/hdlc_ppp.c3
-rw-r--r--drivers/net/wan/hdlc_raw.c3
-rw-r--r--drivers/net/wan/wanxl.c5
-rw-r--r--drivers/net/wd.c18
-rw-r--r--drivers/net/wireless/airo.c18
-rw-r--r--drivers/net/wireless/airo_cs.c17
-rw-r--r--drivers/net/wireless/airport.c8
-rw-r--r--drivers/net/wireless/arlan-main.c26
-rw-r--r--drivers/net/wireless/atmel_cs.c39
-rw-r--r--drivers/net/wireless/netwave_cs.c14
-rw-r--r--drivers/net/wireless/orinoco.c2465
-rw-r--r--drivers/net/wireless/orinoco.h30
-rw-r--r--drivers/net/wireless/orinoco_cs.c58
-rw-r--r--drivers/net/wireless/prism54/isl_38xx.c6
-rw-r--r--drivers/net/wireless/ray_cs.c14
-rw-r--r--drivers/net/wireless/wavelan_cs.c17
-rw-r--r--drivers/net/wireless/wavelan_cs.p.h1
-rw-r--r--drivers/net/wireless/wl3501_cs.c26
-rw-r--r--drivers/net/yellowfin.c8
-rw-r--r--drivers/oprofile/buffer_sync.c29
-rw-r--r--drivers/oprofile/event_buffer.h3
-rw-r--r--drivers/parisc/dino.c1
-rw-r--r--drivers/parisc/lba_pci.c2
-rw-r--r--drivers/parport/parport_cs.c16
-rw-r--r--drivers/parport/parport_pc.c2
-rw-r--r--drivers/pci/Makefile1
-rw-r--r--drivers/pci/bus.c11
-rw-r--r--drivers/pci/hotplug.c2
-rw-r--r--drivers/pci/hotplug/Kconfig5
-rw-r--r--drivers/pci/hotplug/Makefile5
-rw-r--r--drivers/pci/hotplug/acpiphp.h47
-rw-r--r--drivers/pci/hotplug/acpiphp_core.c9
-rw-r--r--drivers/pci/hotplug/acpiphp_glue.c882
-rw-r--r--drivers/pci/hotplug/acpiphp_pci.c449
-rw-r--r--drivers/pci/hotplug/acpiphp_res.c700
-rw-r--r--drivers/pci/hotplug/cpqphp_core.c5
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c611
-rw-r--r--drivers/pci/msi.c88
-rw-r--r--drivers/pci/msi.h9
-rw-r--r--drivers/pci/pci-acpi.c110
-rw-r--r--drivers/pci/pci-driver.c198
-rw-r--r--drivers/pci/pci-sysfs.c26
-rw-r--r--drivers/pci/pci.c28
-rw-r--r--drivers/pci/pci.h4
-rw-r--r--drivers/pci/pcie/portdrv.h5
-rw-r--r--drivers/pci/pcie/portdrv_core.c14
-rw-r--r--drivers/pci/pcie/portdrv_pci.c79
-rw-r--r--drivers/pci/probe.c53
-rw-r--r--drivers/pci/proc.c14
-rw-r--r--drivers/pci/quirks.c1
-rw-r--r--drivers/pci/remove.c14
-rw-r--r--drivers/pci/search.c1
-rw-r--r--drivers/pci/setup-bus.c8
-rw-r--r--drivers/pcmcia/Kconfig50
-rw-r--r--drivers/pcmcia/Makefile3
-rw-r--r--drivers/pcmcia/au1000_generic.h1
-rw-r--r--drivers/pcmcia/au1000_pb1x00.c1
-rw-r--r--drivers/pcmcia/au1000_xxs1500.c1
-rw-r--r--drivers/pcmcia/cardbus.c1
-rw-r--r--drivers/pcmcia/cistpl.c28
-rw-r--r--drivers/pcmcia/cs.c1182
-rw-r--r--drivers/pcmcia/cs_internal.h29
-rw-r--r--drivers/pcmcia/ds.c1350
-rw-r--r--drivers/pcmcia/ds_internal.h21
-rw-r--r--drivers/pcmcia/hd64465_ss.c1
-rw-r--r--drivers/pcmcia/i82365.c18
-rw-r--r--drivers/pcmcia/m32r_cfc.c1
-rw-r--r--drivers/pcmcia/m32r_pcc.c1
-rw-r--r--drivers/pcmcia/pcmcia_compat.c82
-rw-r--r--drivers/pcmcia/pcmcia_ioctl.c759
-rw-r--r--drivers/pcmcia/pcmcia_resource.c943
-rw-r--r--drivers/pcmcia/rsrc_mgr.c11
-rw-r--r--drivers/pcmcia/rsrc_nonstatic.c170
-rw-r--r--drivers/pcmcia/sa1100_generic.c1
-rw-r--r--drivers/pcmcia/soc_common.h1
-rw-r--r--drivers/pcmcia/socket_sysfs.c167
-rw-r--r--drivers/pcmcia/tcic.c1
-rw-r--r--drivers/pcmcia/ti113x.h4
-rw-r--r--drivers/pcmcia/yenta_socket.c176
-rw-r--r--drivers/pnp/card.c3
-rw-r--r--drivers/pnp/manager.c1
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c15
-rw-r--r--drivers/pnp/pnpbios/core.c2
-rw-r--r--drivers/pnp/pnpbios/rsparser.c2
-rw-r--r--drivers/pnp/resource.c2
-rw-r--r--drivers/s390/Kconfig7
-rw-r--r--drivers/s390/block/dasd.c30
-rw-r--r--drivers/s390/block/dasd_proc.c3
-rw-r--r--drivers/s390/block/dcssblk.c48
-rw-r--r--drivers/s390/char/Makefile1
-rw-r--r--drivers/s390/char/con3215.c4
-rw-r--r--drivers/s390/char/con3270.c4
-rw-r--r--drivers/s390/char/tape_34xx.c6
-rw-r--r--drivers/s390/char/tape_core.c2
-rw-r--r--drivers/s390/char/tape_proc.c1
-rw-r--r--drivers/s390/char/vmcp.c219
-rw-r--r--drivers/s390/char/vmcp.h30
-rw-r--r--drivers/s390/char/vmlogrdr.c10
-rw-r--r--drivers/s390/cio/ccwgroup.c30
-rw-r--r--drivers/s390/cio/cio.c8
-rw-r--r--drivers/s390/cio/css.c34
-rw-r--r--drivers/s390/cio/device.c84
-rw-r--r--drivers/s390/cio/qdio.c14
-rw-r--r--drivers/s390/cio/qdio.h16
-rw-r--r--drivers/s390/net/claw.c8
-rw-r--r--drivers/s390/net/ctcdbug.c10
-rw-r--r--drivers/s390/net/ctcdbug.h10
-rw-r--r--drivers/s390/net/ctctty.c6
-rw-r--r--drivers/s390/net/iucv.h6
-rw-r--r--drivers/s390/net/lcs.c8
-rw-r--r--drivers/s390/net/netiucv.c12
-rw-r--r--drivers/s390/net/qeth.h14
-rw-r--r--drivers/s390/net/qeth_main.c16
-rw-r--r--drivers/s390/net/smsgiucv.c4
-rw-r--r--drivers/s390/s390mach.c321
-rw-r--r--drivers/s390/s390mach.h35
-rw-r--r--drivers/sbus/char/bpp.c20
-rw-r--r--drivers/scsi/3w-9xxx.c8
-rw-r--r--drivers/scsi/3w-xxxx.c8
-rw-r--r--drivers/scsi/aacraid/commctrl.c2
-rw-r--r--drivers/scsi/ahci.c22
-rw-r--r--drivers/scsi/dpt_i2o.c7
-rw-r--r--drivers/scsi/dpti.h12
-rw-r--r--drivers/scsi/hosts.c2
-rw-r--r--drivers/scsi/initio.c85
-rw-r--r--drivers/scsi/initio.h18
-rw-r--r--drivers/scsi/ipr.c10
-rw-r--r--drivers/scsi/libata-core.c6
-rw-r--r--drivers/scsi/libata-scsi.c16
-rw-r--r--drivers/scsi/mac53c94.c7
-rw-r--r--drivers/scsi/megaraid.c8
-rw-r--r--drivers/scsi/mesh.c8
-rw-r--r--drivers/scsi/pcmcia/aha152x_stub.c18
-rw-r--r--drivers/scsi/pcmcia/fdomain_stub.c17
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c30
-rw-r--r--drivers/scsi/pcmcia/qlogic_stub.c26
-rw-r--r--drivers/scsi/pcmcia/sym53c500_cs.c14
-rw-r--r--drivers/scsi/scsi.c6
-rw-r--r--drivers/scsi/scsi_debug.c2
-rw-r--r--drivers/scsi/scsi_lib.c4
-rw-r--r--drivers/scsi/scsi_priv.h4
-rw-r--r--drivers/scsi/scsi_sysfs.c4
-rw-r--r--drivers/serial/68328serial.c26
-rw-r--r--drivers/serial/68360serial.c9
-rw-r--r--drivers/serial/8250.c125
-rw-r--r--drivers/serial/8250.h3
-rw-r--r--drivers/serial/8250_accent.c47
-rw-r--r--drivers/serial/8250_boca.c61
-rw-r--r--drivers/serial/8250_fourport.c53
-rw-r--r--drivers/serial/8250_hub6.c58
-rw-r--r--drivers/serial/8250_mca.c64
-rw-r--r--drivers/serial/Kconfig77
-rw-r--r--drivers/serial/Makefile5
-rw-r--r--drivers/serial/au1x00_uart.c13
-rw-r--r--drivers/serial/cpm_uart/cpm_uart_cpm1.c32
-rw-r--r--drivers/serial/icom.h2
-rw-r--r--drivers/serial/ip22zilog.c13
-rw-r--r--drivers/serial/m32r_sio.c10
-rw-r--r--drivers/serial/mpsc.c11
-rw-r--r--drivers/serial/pmac_zilog.c13
-rw-r--r--drivers/serial/pxa.c13
-rw-r--r--drivers/serial/s3c2410.c9
-rw-r--r--drivers/serial/serial_core.c42
-rw-r--r--drivers/serial/serial_cs.c113
-rw-r--r--drivers/serial/serial_txx9.c3
-rw-r--r--drivers/serial/sunsab.c7
-rw-r--r--drivers/serial/sunsu.c3
-rw-r--r--drivers/serial/sunzilog.c21
-rw-r--r--drivers/telephony/ixj.c52
-rw-r--r--drivers/telephony/ixj_pcmcia.c14
-rw-r--r--drivers/usb/Makefile4
-rw-r--r--drivers/usb/atm/Kconfig50
-rw-r--r--drivers/usb/atm/Makefile7
-rw-r--r--drivers/usb/atm/cxacru.c878
-rw-r--r--drivers/usb/atm/speedtch.c1112
-rw-r--r--drivers/usb/atm/usb_atm.c1188
-rw-r--r--drivers/usb/atm/usb_atm.h176
-rw-r--r--drivers/usb/atm/usbatm.c1230
-rw-r--r--drivers/usb/atm/usbatm.h184
-rw-r--r--drivers/usb/atm/xusbatm.c196
-rw-r--r--drivers/usb/class/cdc-acm.c240
-rw-r--r--drivers/usb/class/cdc-acm.h25
-rw-r--r--drivers/usb/class/usblp.c3
-rw-r--r--drivers/usb/core/buffer.c2
-rw-r--r--drivers/usb/core/devio.c6
-rw-r--r--drivers/usb/core/hcd-pci.c1
-rw-r--r--drivers/usb/core/hcd.c281
-rw-r--r--drivers/usb/core/hcd.h27
-rw-r--r--drivers/usb/core/hub.c61
-rw-r--r--drivers/usb/core/hub.h11
-rw-r--r--drivers/usb/core/message.c2
-rw-r--r--drivers/usb/core/sysfs.c2
-rw-r--r--drivers/usb/core/urb.c4
-rw-r--r--drivers/usb/core/usb.c5
-rw-r--r--drivers/usb/gadget/Kconfig11
-rw-r--r--drivers/usb/gadget/dummy_hcd.c754
-rw-r--r--drivers/usb/gadget/ether.c371
-rw-r--r--drivers/usb/gadget/file_storage.c64
-rw-r--r--drivers/usb/gadget/goku_udc.c34
-rw-r--r--drivers/usb/gadget/inode.c12
-rw-r--r--drivers/usb/gadget/lh7a40x_udc.c6
-rw-r--r--drivers/usb/gadget/ndis.h14
-rw-r--r--drivers/usb/gadget/net2280.c59
-rw-r--r--drivers/usb/gadget/omap_udc.c310
-rw-r--r--drivers/usb/gadget/omap_udc.h4
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.c49
-rw-r--r--drivers/usb/gadget/pxa2xx_udc.h10
-rw-r--r--drivers/usb/gadget/rndis.c515
-rw-r--r--drivers/usb/gadget/rndis.h95
-rw-r--r--drivers/usb/gadget/serial.c36
-rw-r--r--drivers/usb/gadget/zero.c14
-rw-r--r--drivers/usb/host/Kconfig13
-rw-r--r--drivers/usb/host/Makefile1
-rw-r--r--drivers/usb/host/ehci-dbg.c59
-rw-r--r--drivers/usb/host/ehci-hcd.c60
-rw-r--r--drivers/usb/host/ehci-hub.c2
-rw-r--r--drivers/usb/host/ehci-q.c4
-rw-r--r--drivers/usb/host/ehci-sched.c36
-rw-r--r--drivers/usb/host/hc_crisv10.c10
-rw-r--r--drivers/usb/host/isp116x-hcd.c1871
-rw-r--r--drivers/usb/host/isp116x.h583
-rw-r--r--drivers/usb/host/ohci-hcd.c60
-rw-r--r--drivers/usb/host/ohci-hub.c3
-rw-r--r--drivers/usb/host/ohci-mem.c5
-rw-r--r--drivers/usb/host/ohci-omap.c57
-rw-r--r--drivers/usb/host/ohci-pci.c13
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/sl811-hcd.c20
-rw-r--r--drivers/usb/host/sl811_cs.c28
-rw-r--r--drivers/usb/host/uhci-debug.c32
-rw-r--r--drivers/usb/host/uhci-hcd.c773
-rw-r--r--drivers/usb/host/uhci-hcd.h59
-rw-r--r--drivers/usb/host/uhci-hub.c83
-rw-r--r--drivers/usb/host/uhci-q.c60
-rw-r--r--drivers/usb/input/Kconfig37
-rw-r--r--drivers/usb/input/Makefile3
-rw-r--r--drivers/usb/input/acecad.c285
-rw-r--r--drivers/usb/input/aiptek.c32
-rw-r--r--drivers/usb/input/ati_remote.c248
-rw-r--r--drivers/usb/input/hid-core.c50
-rw-r--r--drivers/usb/input/hid-debug.h16
-rw-r--r--drivers/usb/input/hid-input.c16
-rw-r--r--drivers/usb/input/hid-lgff.c18
-rw-r--r--drivers/usb/input/hid.h18
-rw-r--r--drivers/usb/input/hiddev.c56
-rw-r--r--drivers/usb/input/itmtouch.c268
-rw-r--r--drivers/usb/input/kbtab.c17
-rw-r--r--drivers/usb/input/keyspan_remote.c633
-rw-r--r--drivers/usb/input/mtouchusb.c410
-rw-r--r--drivers/usb/input/powermate.c30
-rw-r--r--drivers/usb/input/touchkitusb.c11
-rw-r--r--drivers/usb/input/usbkbd.c29
-rw-r--r--drivers/usb/input/usbmouse.c31
-rw-r--r--drivers/usb/input/wacom.c398
-rw-r--r--drivers/usb/input/xpad.c75
-rw-r--r--drivers/usb/media/Makefile2
-rw-r--r--drivers/usb/media/sn9c102.h2
-rw-r--r--drivers/usb/media/sn9c102_core.c2
-rw-r--r--drivers/usb/media/sn9c102_ov7630.c394
-rw-r--r--drivers/usb/media/sn9c102_sensor.h16
-rw-r--r--drivers/usb/media/sn9c102_tas5110c1b.c21
-rw-r--r--drivers/usb/media/sn9c102_tas5130d1b.c27
-rw-r--r--drivers/usb/media/stv680.c8
-rw-r--r--drivers/usb/media/stv680.h5
-rw-r--r--drivers/usb/misc/Kconfig10
-rw-r--r--drivers/usb/misc/Makefile1
-rw-r--r--drivers/usb/misc/idmouse.c149
-rw-r--r--drivers/usb/misc/ldusb.c794
-rw-r--r--drivers/usb/misc/usbtest.c60
-rw-r--r--drivers/usb/mon/mon_text.c48
-rw-r--r--drivers/usb/net/kaweth.c4
-rw-r--r--drivers/usb/net/pegasus.c2
-rw-r--r--drivers/usb/net/pegasus.h2
-rw-r--r--drivers/usb/net/rtl8150.c2
-rw-r--r--drivers/usb/net/usbnet.c8
-rw-r--r--drivers/usb/net/zd1201.c41
-rw-r--r--drivers/usb/net/zd1201.h1
-rw-r--r--drivers/usb/serial/cyberjack.c19
-rw-r--r--drivers/usb/serial/ftdi_sio.c756
-rw-r--r--drivers/usb/serial/generic.c24
-rw-r--r--drivers/usb/serial/ipaq.c5
-rw-r--r--drivers/usb/serial/ipw.c14
-rw-r--r--drivers/usb/serial/ir-usb.c16
-rw-r--r--drivers/usb/serial/keyspan_pda.c19
-rw-r--r--drivers/usb/serial/omninet.c17
-rw-r--r--drivers/usb/serial/safe_serial.c13
-rw-r--r--drivers/usb/serial/usb-serial.c1
-rw-r--r--drivers/usb/serial/usb-serial.h3
-rw-r--r--drivers/usb/storage/scsiglue.c54
-rw-r--r--drivers/usb/storage/scsiglue.h1
-rw-r--r--drivers/usb/storage/transport.c116
-rw-r--r--drivers/usb/storage/transport.h1
-rw-r--r--drivers/usb/storage/unusual_devs.h2
-rw-r--r--drivers/usb/storage/usb.c4
-rw-r--r--drivers/video/aty/aty128fb.c14
-rw-r--r--drivers/video/au1100fb.c18
-rw-r--r--drivers/video/chipsfb.c176
-rw-r--r--drivers/video/console/Kconfig5
-rw-r--r--drivers/video/console/fbcon.c8
-rw-r--r--drivers/video/fbsysfs.c4
-rw-r--r--drivers/video/logo/Kconfig5
-rw-r--r--drivers/video/logo/Makefile1
-rw-r--r--drivers/video/logo/logo.c5
-rw-r--r--drivers/video/logo/logo_m32r_clut224.ppm1292
-rw-r--r--drivers/video/matrox/matroxfb_misc.c5
-rw-r--r--drivers/video/platinumfb.c6
-rw-r--r--drivers/video/pxafb.c3
-rw-r--r--drivers/video/s1d13xxxfb.c10
-rw-r--r--drivers/video/savage/savagefb_driver.c2
-rw-r--r--drivers/video/vesafb.c9
-rw-r--r--drivers/w1/w1.c9
-rw-r--r--fs/Kconfig72
-rw-r--r--fs/Makefile2
-rw-r--r--fs/afs/kafsasyncd.c2
-rw-r--r--fs/afs/kafstimod.c2
-rw-r--r--fs/aio.c9
-rw-r--r--fs/attr.c33
-rw-r--r--fs/autofs4/waitq.c4
-rw-r--r--fs/bio.c2
-rw-r--r--fs/buffer.c29
-rw-r--r--fs/char_dev.c5
-rw-r--r--fs/compat.c12
-rw-r--r--fs/dcookies.c6
-rw-r--r--fs/direct-io.c2
-rw-r--r--fs/dquot.c7
-rw-r--r--fs/exec.c12
-rw-r--r--fs/ext2/Makefile1
-rw-r--r--fs/ext2/ext2.h11
-rw-r--r--fs/ext2/file.c14
-rw-r--r--fs/ext2/inode.c31
-rw-r--r--fs/ext2/namei.c12
-rw-r--r--fs/ext2/super.c51
-rw-r--r--fs/ext2/xip.c80
-rw-r--r--fs/ext2/xip.h25
-rw-r--r--fs/ext3/acl.c5
-rw-r--r--fs/ext3/balloc.c135
-rw-r--r--fs/ext3/file.c4
-rw-r--r--fs/ext3/inode.c9
-rw-r--r--fs/ext3/namei.c25
-rw-r--r--fs/ext3/super.c110
-rw-r--r--fs/ext3/xattr.c2
-rw-r--r--fs/fat/cache.c2
-rw-r--r--fs/fat/inode.c21
-rw-r--r--fs/file_table.c3
-rw-r--r--fs/freevxfs/vxfs.h1
-rw-r--r--fs/freevxfs/vxfs_bmap.c2
-rw-r--r--fs/freevxfs/vxfs_fshead.c11
-rw-r--r--fs/freevxfs/vxfs_kcompat.h49
-rw-r--r--fs/freevxfs/vxfs_lookup.c8
-rw-r--r--fs/freevxfs/vxfs_olt.c10
-rw-r--r--fs/freevxfs/vxfs_subr.c1
-rw-r--r--fs/freevxfs/vxfs_super.c7
-rw-r--r--fs/hppfs/hppfs_kern.c7
-rw-r--r--fs/inode.c47
-rw-r--r--fs/inotify.c999
-rw-r--r--fs/ioprio.c172
-rw-r--r--fs/jbd/journal.c4
-rw-r--r--fs/jffs/intrep.c114
-rw-r--r--fs/jffs/intrep.h2
-rw-r--r--fs/jffs/jffs_fm.c105
-rw-r--r--fs/jffs/jffs_fm.h3
-rw-r--r--fs/jffs2/Makefile5
-rw-r--r--fs/jffs2/README.Locking6
-rw-r--r--fs/jffs2/background.c15
-rw-r--r--fs/jffs2/build.c9
-rw-r--r--fs/jffs2/compr_zlib.c4
-rw-r--r--fs/jffs2/dir.c46
-rw-r--r--fs/jffs2/erase.c24
-rw-r--r--fs/jffs2/file.c5
-rw-r--r--fs/jffs2/fs.c24
-rw-r--r--fs/jffs2/gc.c41
-rw-r--r--fs/jffs2/nodelist.c93
-rw-r--r--fs/jffs2/nodelist.h21
-rw-r--r--fs/jffs2/nodemgmt.c31
-rw-r--r--fs/jffs2/os-linux.h60
-rw-r--r--fs/jffs2/read.c32
-rw-r--r--fs/jffs2/readinode.c96
-rw-r--r--fs/jffs2/scan.c39
-rw-r--r--fs/jffs2/super.c8
-rw-r--r--fs/jffs2/symlink.c42
-rw-r--r--fs/jffs2/wbuf.c164
-rw-r--r--fs/jffs2/write.c55
-rw-r--r--fs/jfs/jfs_logmgr.c4
-rw-r--r--fs/jfs/jfs_txnmgr.c8
-rw-r--r--fs/libfs.c1
-rw-r--r--fs/lockd/clntproc.c2
-rw-r--r--fs/lockd/svc.c4
-rw-r--r--fs/locks.c4
-rw-r--r--fs/namei.c32
-rw-r--r--fs/namespace.c132
-rw-r--r--fs/ncpfs/dir.c13
-rw-r--r--fs/ncpfs/ncplib_kernel.c40
-rw-r--r--fs/ncpfs/ncplib_kernel.h3
-rw-r--r--fs/nfs/nfs3acl.c14
-rw-r--r--fs/nfsd/Makefile2
-rw-r--r--fs/nfsd/nfs4acl.c4
-rw-r--r--fs/nfsd/nfs4callback.c13
-rw-r--r--fs/nfsd/nfs4idmap.c12
-rw-r--r--fs/nfsd/nfs4proc.c32
-rw-r--r--fs/nfsd/nfs4recover.c421
-rw-r--r--fs/nfsd/nfs4state.c1253
-rw-r--r--fs/nfsd/nfs4xdr.c22
-rw-r--r--fs/nfsd/nfsctl.c28
-rw-r--r--fs/nfsd/nfssvc.c2
-rw-r--r--fs/nfsd/vfs.c21
-rw-r--r--fs/open.c7
-rw-r--r--fs/partitions/Makefile1
-rw-r--r--fs/partitions/check.c3
-rw-r--r--fs/partitions/check.h4
-rw-r--r--fs/partitions/msdos.c4
-rw-r--r--fs/proc/Makefile1
-rw-r--r--fs/proc/proc_misc.c6
-rw-r--r--fs/proc/vmcore.c669
-rw-r--r--fs/qnx4/dir.c2
-rw-r--r--fs/qnx4/inode.c4
-rw-r--r--fs/read_write.c15
-rw-r--r--fs/reiserfs/bitmap.c1842
-rw-r--r--fs/reiserfs/dir.c488
-rw-r--r--fs/reiserfs/do_balan.c3236
-rw-r--r--fs/reiserfs/file.c2564
-rw-r--r--fs/reiserfs/fix_node.c4051
-rw-r--r--fs/reiserfs/hashes.c193
-rw-r--r--fs/reiserfs/ibalance.c1844
-rw-r--r--fs/reiserfs/inode.c4899
-rw-r--r--fs/reiserfs/ioctl.c197
-rw-r--r--fs/reiserfs/item_ops.c979
-rw-r--r--fs/reiserfs/journal.c6841
-rw-r--r--fs/reiserfs/lbalance.c2218
-rw-r--r--fs/reiserfs/namei.c2571
-rw-r--r--fs/reiserfs/objectid.c303
-rw-r--r--fs/reiserfs/prints.c1003
-rw-r--r--fs/reiserfs/procfs.c695
-rw-r--r--fs/reiserfs/resize.c207
-rw-r--r--fs/reiserfs/stree.c3369
-rw-r--r--fs/reiserfs/super.c3585
-rw-r--r--fs/reiserfs/tail_conversion.c463
-rw-r--r--fs/reiserfs/xattr.c2173
-rw-r--r--fs/reiserfs/xattr_acl.c641
-rw-r--r--fs/reiserfs/xattr_security.c54
-rw-r--r--fs/reiserfs/xattr_trusted.c70
-rw-r--r--fs/reiserfs/xattr_user.c89
-rw-r--r--fs/super.c1
-rw-r--r--fs/sysfs/file.c12
-rw-r--r--fs/udf/namei.c6
-rw-r--r--fs/xattr.c5
-rw-r--r--fs/xfs/linux-2.6/xfs_aops.c3
-rw-r--r--fs/xfs/linux-2.6/xfs_buf.c4
-rw-r--r--fs/xfs/linux-2.6/xfs_super.c2
-rw-r--r--include/acpi/acconfig.h7
-rw-r--r--include/acpi/acdebug.h146
-rw-r--r--include/acpi/acdisasm.h114
-rw-r--r--include/acpi/acdispat.h171
-rw-r--r--include/acpi/acevents.h85
-rw-r--r--include/acpi/acexcep.h5
-rw-r--r--include/acpi/acglobal.h12
-rw-r--r--include/acpi/achware.h52
-rw-r--r--include/acpi/acinterp.h243
-rw-r--r--include/acpi/aclocal.h10
-rw-r--r--include/acpi/acmacros.h10
-rw-r--r--include/acpi/acnames.h84
-rw-r--r--include/acpi/acnamesp.h163
-rw-r--r--include/acpi/acobject.h2
-rw-r--r--include/acpi/acopcode.h325
-rw-r--r--include/acpi/acparser.h134
-rw-r--r--include/acpi/acpi.h1
-rw-r--r--include/acpi/acpi_bus.h38
-rw-r--r--include/acpi/acpi_drivers.h6
-rw-r--r--include/acpi/acpiosxf.h18
-rw-r--r--include/acpi/acpixf.h13
-rw-r--r--include/acpi/acresrc.h67
-rw-r--r--include/acpi/acstruct.h1
-rw-r--r--include/acpi/actables.h70
-rw-r--r--include/acpi/actbl.h2
-rw-r--r--include/acpi/actypes.h2
-rw-r--r--include/acpi/acutils.h274
-rw-r--r--include/acpi/amlcode.h12
-rw-r--r--include/acpi/pdc_intel.h29
-rw-r--r--include/acpi/platform/acenv.h20
-rw-r--r--include/acpi/processor.h34
-rw-r--r--include/asm-alpha/pci.h21
-rw-r--r--include/asm-alpha/pgtable.h6
-rw-r--r--include/asm-alpha/serial.h47
-rw-r--r--include/asm-arm/arch-ixp2000/gpio.h31
-rw-r--r--include/asm-arm/arch-ixp2000/io.h96
-rw-r--r--include/asm-arm/arch-ixp2000/ixdp2x00.h4
-rw-r--r--include/asm-arm/arch-ixp2000/ixdp2x01.h4
-rw-r--r--include/asm-arm/arch-ixp2000/ixp2000-regs.h21
-rw-r--r--include/asm-arm/arch-ixp2000/platform.h23
-rw-r--r--include/asm-arm/arch-ixp2000/vmalloc.h2
-rw-r--r--include/asm-arm/arch-ixp4xx/debug-macro.S1
-rw-r--r--include/asm-arm/arch-ixp4xx/io.h176
-rw-r--r--include/asm-arm/arch-ixp4xx/ixp4xx-regs.h10
-rw-r--r--include/asm-arm/arch-omap/board-h2.h5
-rw-r--r--include/asm-arm/arch-omap/board-h3.h5
-rw-r--r--include/asm-arm/arch-omap/board-osk.h5
-rw-r--r--include/asm-arm/arch-omap/board.h12
-rw-r--r--include/asm-arm/arch-omap/common.h (renamed from arch/arm/mach-omap/common.h)4
-rw-r--r--include/asm-arm/arch-omap/dma.h1
-rw-r--r--include/asm-arm/arch-omap/hardware.h24
-rw-r--r--include/asm-arm/arch-omap/irqs.h3
-rw-r--r--include/asm-arm/arch-omap/mux.h28
-rw-r--r--include/asm-arm/arch-omap/omap16xx.h32
-rw-r--r--include/asm-arm/arch-omap/system.h21
-rw-r--r--include/asm-arm/arch-omap/usb.h9
-rw-r--r--include/asm-arm/arch-pxa/debug-macro.S2
-rw-r--r--include/asm-arm/arch-pxa/mtd-xip.h37
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h2
-rw-r--r--include/asm-arm/arch-s3c2410/audio.h49
-rw-r--r--include/asm-arm/arch-sa1100/mtd-xip.h26
-rw-r--r--include/asm-arm/hardware/arm_timer.h21
-rw-r--r--include/asm-arm/ide.h2
-rw-r--r--include/asm-arm/io.h4
-rw-r--r--include/asm-arm/mach/arch.h34
-rw-r--r--include/asm-arm/mach/time.h23
-rw-r--r--include/asm-arm/mtd-xip.h26
-rw-r--r--include/asm-arm/pci.h12
-rw-r--r--include/asm-arm/signal.h1
-rw-r--r--include/asm-arm/stat.h2
-rw-r--r--include/asm-arm/system.h46
-rw-r--r--include/asm-arm/tlbflush.h28
-rw-r--r--include/asm-arm26/serial.h22
-rw-r--r--include/asm-frv/pci.h10
-rw-r--r--include/asm-generic/vmlinux.lds.h2
-rw-r--r--include/asm-h8300/pci.h2
-rw-r--r--include/asm-i386/acpi.h10
-rw-r--r--include/asm-i386/apic.h15
-rw-r--r--include/asm-i386/apicdef.h9
-rw-r--r--include/asm-i386/cpu.h2
-rw-r--r--include/asm-i386/highmem.h1
-rw-r--r--include/asm-i386/i8253.h6
-rw-r--r--include/asm-i386/ide.h12
-rw-r--r--include/asm-i386/irq.h6
-rw-r--r--include/asm-i386/kdebug.h2
-rw-r--r--include/asm-i386/kexec.h33
-rw-r--r--include/asm-i386/mach-default/do_timer.h1
-rw-r--r--include/asm-i386/mach-default/mach_ipi.h27
-rw-r--r--include/asm-i386/mmzone.h24
-rw-r--r--include/asm-i386/page.h3
-rw-r--r--include/asm-i386/pci.h12
-rw-r--r--include/asm-i386/processor.h10
-rw-r--r--include/asm-i386/serial.h102
-rw-r--r--include/asm-i386/smp.h10
-rw-r--r--include/asm-i386/string.h32
-rw-r--r--include/asm-i386/tlbflush.h12
-rw-r--r--include/asm-i386/topology.h7
-rw-r--r--include/asm-i386/unistd.h7
-rw-r--r--include/asm-ia64/acpi.h9
-rw-r--r--include/asm-ia64/hw_irq.h1
-rw-r--r--include/asm-ia64/iosapic.h12
-rw-r--r--include/asm-ia64/kprobes.h14
-rw-r--r--include/asm-ia64/mmu_context.h3
-rw-r--r--include/asm-ia64/mmzone.h4
-rw-r--r--include/asm-ia64/pci.h21
-rw-r--r--include/asm-ia64/sections.h1
-rw-r--r--include/asm-ia64/sn/addrs.h17
-rw-r--r--include/asm-ia64/sn/arch.h1
-rw-r--r--include/asm-ia64/sn/intr.h6
-rw-r--r--include/asm-ia64/sn/l1.h1
-rw-r--r--include/asm-ia64/sn/pcibr_provider.h (renamed from arch/ia64/sn/include/pci/pcibr_provider.h)14
-rw-r--r--include/asm-ia64/sn/pcidev.h16
-rw-r--r--include/asm-ia64/sn/pic.h (renamed from arch/ia64/sn/include/pci/pic.h)14
-rw-r--r--include/asm-ia64/sn/shub_mmr.h346
-rw-r--r--include/asm-ia64/sn/simulator.h13
-rw-r--r--include/asm-ia64/sn/sn2/sn_hwperf.h2
-rw-r--r--include/asm-ia64/sn/sn_cpuid.h5
-rw-r--r--include/asm-ia64/sn/sn_sal.h47
-rw-r--r--include/asm-ia64/sn/tioca_provider.h1
-rw-r--r--include/asm-ia64/sn/tiocp.h (renamed from arch/ia64/sn/include/pci/tiocp.h)2
-rw-r--r--include/asm-ia64/sn/xp.h1
-rw-r--r--include/asm-ia64/system.h10
-rw-r--r--include/asm-ia64/topology.h61
-rw-r--r--include/asm-ia64/unistd.h2
-rw-r--r--include/asm-ia64/vga.h5
-rw-r--r--include/asm-m32r/s1d13806.h199
-rw-r--r--include/asm-m68k/pci.h2
-rw-r--r--include/asm-m68k/serial.h47
-rw-r--r--include/asm-mips/mmzone.h4
-rw-r--r--include/asm-mips/page.h2
-rw-r--r--include/asm-mips/pci.h12
-rw-r--r--include/asm-mips/pgtable.h2
-rw-r--r--include/asm-mips/serial.h84
-rw-r--r--include/asm-mips/system.h10
-rw-r--r--include/asm-parisc/pci.h19
-rw-r--r--include/asm-parisc/serial.h16
-rw-r--r--include/asm-ppc/fsl_ocp.h54
-rw-r--r--include/asm-ppc/kexec.h40
-rw-r--r--include/asm-ppc/machdep.h31
-rw-r--r--include/asm-ppc/macio.h5
-rw-r--r--include/asm-ppc/mmu.h2
-rw-r--r--include/asm-ppc/mmu_context.h2
-rw-r--r--include/asm-ppc/mpc8xx.h4
-rw-r--r--include/asm-ppc/ocp.h4
-rw-r--r--include/asm-ppc/of_device.h20
-rw-r--r--include/asm-ppc/open_pic.h6
-rw-r--r--include/asm-ppc/pc_serial.h86
-rw-r--r--include/asm-ppc/pci.h18
-rw-r--r--include/asm-ppc/ppc_asm.h2
-rw-r--r--include/asm-ppc/reg.h1
-rw-r--r--include/asm-ppc/reg_booke.h18
-rw-r--r--include/asm-ppc/unistd.h6
-rw-r--r--include/asm-ppc64/byteorder.h10
-rw-r--r--include/asm-ppc64/cputable.h3
-rw-r--r--include/asm-ppc64/hvconsole.h17
-rw-r--r--include/asm-ppc64/iSeries/ItLpQueue.h15
-rw-r--r--include/asm-ppc64/kdebug.h2
-rw-r--r--include/asm-ppc64/kexec.h41
-rw-r--r--include/asm-ppc64/kprobes.h5
-rw-r--r--include/asm-ppc64/machdep.h6
-rw-r--r--include/asm-ppc64/mmu.h22
-rw-r--r--include/asm-ppc64/paca.h3
-rw-r--r--include/asm-ppc64/pci.h28
-rw-r--r--include/asm-ppc64/processor.h26
-rw-r--r--include/asm-ppc64/unistd.h6
-rw-r--r--include/asm-ppc64/xics.h1
-rw-r--r--include/asm-s390/cpcmd.h18
-rw-r--r--include/asm-s390/debug.h48
-rw-r--r--include/asm-s390/kexec.h42
-rw-r--r--include/asm-s390/lowcore.h7
-rw-r--r--include/asm-s390/processor.h52
-rw-r--r--include/asm-s390/ptrace.h2
-rw-r--r--include/asm-s390/system.h38
-rw-r--r--include/asm-s390/thread_info.h2
-rw-r--r--include/asm-s390/unistd.h2
-rw-r--r--include/asm-sh/bigsur/serial.h5
-rw-r--r--include/asm-sh/ec3104/serial.h4
-rw-r--r--include/asm-sh/pci.h12
-rw-r--r--include/asm-sh/serial.h6
-rw-r--r--include/asm-sh64/pci.h12
-rw-r--r--include/asm-sh64/serial.h4
-rw-r--r--include/asm-sparc/pci.h12
-rw-r--r--include/asm-sparc/system.h4
-rw-r--r--include/asm-sparc/unistd.h4
-rw-r--r--include/asm-sparc64/auxio.h2
-rw-r--r--include/asm-sparc64/floppy.h16
-rw-r--r--include/asm-sparc64/irq.h56
-rw-r--r--include/asm-sparc64/kdebug.h2
-rw-r--r--include/asm-sparc64/param.h5
-rw-r--r--include/asm-sparc64/parport.h4
-rw-r--r--include/asm-sparc64/pbm.h3
-rw-r--r--include/asm-sparc64/pci.h21
-rw-r--r--include/asm-sparc64/rwsem.h3
-rw-r--r--include/asm-sparc64/seccomp.h21
-rw-r--r--include/asm-sparc64/signal.h15
-rw-r--r--include/asm-sparc64/spinlock.h29
-rw-r--r--include/asm-sparc64/spitfire.h1
-rw-r--r--include/asm-sparc64/system.h14
-rw-r--r--include/asm-sparc64/termios.h78
-rw-r--r--include/asm-sparc64/thread_info.h11
-rw-r--r--include/asm-sparc64/unistd.h4
-rw-r--r--include/asm-um/mmu_context.h10
-rw-r--r--include/asm-um/ptrace-i386.h4
-rw-r--r--include/asm-v850/checksum.h11
-rw-r--r--include/asm-v850/mmu.h17
-rw-r--r--include/asm-v850/pci.h10
-rw-r--r--include/asm-x86_64/acpi.h8
-rw-r--r--include/asm-x86_64/apic.h2
-rw-r--r--include/asm-x86_64/apicdef.h2
-rw-r--r--include/asm-x86_64/io_apic.h2
-rw-r--r--include/asm-x86_64/irq.h5
-rw-r--r--include/asm-x86_64/kdebug.h2
-rw-r--r--include/asm-x86_64/kexec.h33
-rw-r--r--include/asm-x86_64/page.h6
-rw-r--r--include/asm-x86_64/pci.h12
-rw-r--r--include/asm-x86_64/proto.h7
-rw-r--r--include/asm-x86_64/serial.h102
-rw-r--r--include/asm-x86_64/smp.h4
-rw-r--r--include/asm-x86_64/suspend.h2
-rw-r--r--include/asm-x86_64/tlbflush.h12
-rw-r--r--include/asm-x86_64/topology.h10
-rw-r--r--include/asm-x86_64/unistd.h8
-rw-r--r--include/asm-xtensa/a.out.h33
-rw-r--r--include/asm-xtensa/atomic.h272
-rw-r--r--include/asm-xtensa/bitops.h446
-rw-r--r--include/asm-xtensa/bootparam.h61
-rw-r--r--include/asm-xtensa/bug.h41
-rw-r--r--include/asm-xtensa/bugs.h22
-rw-r--r--include/asm-xtensa/byteorder.h82
-rw-r--r--include/asm-xtensa/cache.h32
-rw-r--r--include/asm-xtensa/cacheflush.h122
-rw-r--r--include/asm-xtensa/checksum.h264
-rw-r--r--include/asm-xtensa/coprocessor.h70
-rw-r--r--include/asm-xtensa/cpumask.h16
-rw-r--r--include/asm-xtensa/cputime.h6
-rw-r--r--include/asm-xtensa/current.h38
-rw-r--r--include/asm-xtensa/delay.h50
-rw-r--r--include/asm-xtensa/div64.h19
-rw-r--r--include/asm-xtensa/dma-mapping.h182
-rw-r--r--include/asm-xtensa/dma.h61
-rw-r--r--include/asm-xtensa/elf.h222
-rw-r--r--include/asm-xtensa/errno.h16
-rw-r--r--include/asm-xtensa/fcntl.h101
-rw-r--r--include/asm-xtensa/fixmap.h252
-rw-r--r--include/asm-xtensa/hardirq.h28
-rw-r--r--include/asm-xtensa/hdreg.h17
-rw-r--r--include/asm-xtensa/highmem.h17
-rw-r--r--include/asm-xtensa/hw_irq.h18
-rw-r--r--include/asm-xtensa/ide.h36
-rw-r--r--include/asm-xtensa/io.h197
-rw-r--r--include/asm-xtensa/ioctl.h83
-rw-r--r--include/asm-xtensa/ioctls.h112
-rw-r--r--include/asm-xtensa/ipcbuf.h37
-rw-r--r--include/asm-xtensa/irq.h37
-rw-r--r--include/asm-xtensa/kmap_types.h31
-rw-r--r--include/asm-xtensa/linkage.h16
-rw-r--r--include/asm-xtensa/local.h16
-rw-r--r--include/asm-xtensa/mman.h80
-rw-r--r--include/asm-xtensa/mmu.h17
-rw-r--r--include/asm-xtensa/mmu_context.h330
-rw-r--r--include/asm-xtensa/module.h25
-rw-r--r--include/asm-xtensa/msgbuf.h48
-rw-r--r--include/asm-xtensa/namei.h26
-rw-r--r--include/asm-xtensa/page.h133
-rw-r--r--include/asm-xtensa/page.h.n135
-rw-r--r--include/asm-xtensa/param.h34
-rw-r--r--include/asm-xtensa/pci-bridge.h88
-rw-r--r--include/asm-xtensa/pci.h89
-rw-r--r--include/asm-xtensa/percpu.h16
-rw-r--r--include/asm-xtensa/pgalloc.h116
-rw-r--r--include/asm-xtensa/pgtable.h468
-rw-r--r--include/asm-xtensa/platform-iss/hardware.h29
-rw-r--r--include/asm-xtensa/platform.h92
-rw-r--r--include/asm-xtensa/poll.h37
-rw-r--r--include/asm-xtensa/posix_types.h123
-rw-r--r--include/asm-xtensa/processor.h205
-rw-r--r--include/asm-xtensa/ptrace.h135
-rw-r--r--include/asm-xtensa/resource.h16
-rw-r--r--include/asm-xtensa/rmap.h16
-rw-r--r--include/asm-xtensa/rwsem.h175
-rw-r--r--include/asm-xtensa/scatterlist.h34
-rw-r--r--include/asm-xtensa/sections.h16
-rw-r--r--include/asm-xtensa/segment.h16
-rw-r--r--include/asm-xtensa/semaphore.h129
-rw-r--r--include/asm-xtensa/sembuf.h44
-rw-r--r--include/asm-xtensa/serial.h18
-rw-r--r--include/asm-xtensa/setup.h16
-rw-r--r--include/asm-xtensa/shmbuf.h50
-rw-r--r--include/asm-xtensa/shmparam.h23
-rw-r--r--include/asm-xtensa/sigcontext.h44
-rw-r--r--include/asm-xtensa/siginfo.h16
-rw-r--r--include/asm-xtensa/signal.h187
-rw-r--r--include/asm-xtensa/smp.h27
-rw-r--r--include/asm-xtensa/socket.h61
-rw-r--r--include/asm-xtensa/sockios.h30
-rw-r--r--include/asm-xtensa/spinlock.h16
-rw-r--r--include/asm-xtensa/stat.h105
-rw-r--r--include/asm-xtensa/statfs.h17
-rw-r--r--include/asm-xtensa/string.h124
-rw-r--r--include/asm-xtensa/system.h252
-rw-r--r--include/asm-xtensa/termbits.h194
-rw-r--r--include/asm-xtensa/termios.h122
-rw-r--r--include/asm-xtensa/thread_info.h146
-rw-r--r--include/asm-xtensa/timex.h94
-rw-r--r--include/asm-xtensa/tlb.h25
-rw-r--r--include/asm-xtensa/tlbflush.h200
-rw-r--r--include/asm-xtensa/topology.h16
-rw-r--r--include/asm-xtensa/types.h66
-rw-r--r--include/asm-xtensa/uaccess.h532
-rw-r--r--include/asm-xtensa/ucontext.h22
-rw-r--r--include/asm-xtensa/unaligned.h28
-rw-r--r--include/asm-xtensa/unistd.h439
-rw-r--r--include/asm-xtensa/user.h20
-rw-r--r--include/asm-xtensa/vga.h19
-rw-r--r--include/asm-xtensa/xor.h16
-rw-r--r--include/asm-xtensa/xtensa/cacheasm.h708
-rw-r--r--include/asm-xtensa/xtensa/cacheattrasm.h432
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/core.h1270
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/defs.h270
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/specreg.h99
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/system.h198
-rw-r--r--include/asm-xtensa/xtensa/config-linux_be/tie.h275
-rw-r--r--include/asm-xtensa/xtensa/coreasm.h526
-rw-r--r--include/asm-xtensa/xtensa/corebits.h77
-rw-r--r--include/asm-xtensa/xtensa/hal.h822
-rw-r--r--include/asm-xtensa/xtensa/simcall.h130
-rw-r--r--include/asm-xtensa/xtensa/xt2000-uart.h155
-rw-r--r--include/asm-xtensa/xtensa/xt2000.h408
-rw-r--r--include/asm-xtensa/xtensa/xtboard.h120
-rw-r--r--include/linux/a.out.h2
-rw-r--r--include/linux/acpi.h26
-rw-r--r--include/linux/atalk.h2
-rw-r--r--include/linux/audit.h2
-rw-r--r--include/linux/bio.h14
-rw-r--r--include/linux/blkdev.h32
-rw-r--r--include/linux/bootmem.h4
-rw-r--r--include/linux/buffer_head.h3
-rw-r--r--include/linux/byteorder/swabb.h17
-rw-r--r--include/linux/cache.h6
-rw-r--r--include/linux/cciss_ioctl.h1
-rw-r--r--include/linux/compat_ioctl.h19
-rw-r--r--include/linux/cpu.h1
-rw-r--r--include/linux/cpufreq.h2
-rw-r--r--include/linux/crash_dump.h18
-rw-r--r--include/linux/crypto.h34
-rw-r--r--include/linux/device.h13
-rw-r--r--include/linux/dmi.h1
-rw-r--r--include/linux/dqblk_v1.h6
-rw-r--r--include/linux/dqblk_v2.h6
-rw-r--r--include/linux/elevator.h8
-rw-r--r--include/linux/etherdevice.h5
-rw-r--r--include/linux/ext2_fs.h25
-rw-r--r--include/linux/ext3_fs.h15
-rw-r--r--include/linux/ext3_jbd.h19
-rw-r--r--include/linux/fddidevice.h2
-rw-r--r--include/linux/fs.h50
-rw-r--r--include/linux/fsnotify.h248
-rw-r--r--include/linux/gfp.h4
-rw-r--r--include/linux/hardirq.h1
-rw-r--r--include/linux/hdlc.h4
-rw-r--r--include/linux/highmem.h1
-rw-r--r--include/linux/i2c-dev.h1
-rw-r--r--include/linux/i2o-dev.h43
-rw-r--r--include/linux/i2o.h497
-rw-r--r--include/linux/if_bonding.h7
-rw-r--r--include/linux/if_shaper.h2
-rw-r--r--include/linux/igmp.h1
-rw-r--r--include/linux/in6.h2
-rw-r--r--include/linux/init.h12
-rw-r--r--include/linux/init_task.h3
-rw-r--r--include/linux/inotify.h108
-rw-r--r--include/linux/input.h4
-rw-r--r--include/linux/ioprio.h85
-rw-r--r--include/linux/ipmi.h5
-rw-r--r--include/linux/irq.h6
-rw-r--r--include/linux/jffs2_fs_sb.h9
-rw-r--r--include/linux/joystick.h33
-rw-r--r--include/linux/kernel.h18
-rw-r--r--include/linux/kexec.h135
-rw-r--r--include/linux/key-ui.h47
-rw-r--r--include/linux/key.h44
-rw-r--r--include/linux/keyctl.h11
-rw-r--r--include/linux/kmod.h13
-rw-r--r--include/linux/kprobes.h30
-rw-r--r--include/linux/libps2.h1
-rw-r--r--include/linux/list.h2
-rw-r--r--include/linux/mod_devicetable.h57
-rw-r--r--include/linux/module.h5
-rw-r--r--include/linux/mount.h8
-rw-r--r--include/linux/mtd/cfi.h85
-rw-r--r--include/linux/mtd/flashchip.h7
-rw-r--r--include/linux/mtd/inftl.h4
-rw-r--r--include/linux/mtd/map.h33
-rw-r--r--include/linux/mtd/mtd.h15
-rw-r--r--include/linux/mtd/nand.h48
-rw-r--r--include/linux/mtd/plat-ram.h35
-rw-r--r--include/linux/mtd/xip.h31
-rw-r--r--include/linux/namespace.h4
-rw-r--r--include/linux/netdevice.h11
-rw-r--r--include/linux/netlink.h2
-rw-r--r--include/linux/nfs4.h2
-rw-r--r--include/linux/nfsd/nfsd.h10
-rw-r--r--include/linux/nfsd/state.h56
-rw-r--r--include/linux/nfsd/xdr4.h1
-rw-r--r--include/linux/nfsd_idmap.h5
-rw-r--r--include/linux/nvram.h2
-rw-r--r--include/linux/pci-dynids.h18
-rw-r--r--include/linux/pci.h38
-rw-r--r--include/linux/pci_ids.h11
-rw-r--r--include/linux/pkt_cls.h2
-rw-r--r--include/linux/pkt_sched.h9
-rw-r--r--include/linux/pm.h35
-rw-r--r--include/linux/pmu.h6
-rw-r--r--include/linux/proc_fs.h7
-rw-r--r--include/linux/qnx4_fs.h18
-rw-r--r--include/linux/qnxtypes.h16
-rw-r--r--include/linux/quota.h7
-rw-r--r--include/linux/reboot.h4
-rw-r--r--include/linux/reiserfs_acl.h52
-rw-r--r--include/linux/reiserfs_fs.h1610
-rw-r--r--include/linux/reiserfs_fs_i.h59
-rw-r--r--include/linux/reiserfs_fs_sb.h614
-rw-r--r--include/linux/reiserfs_xattr.h126
-rw-r--r--include/linux/rmap.h6
-rw-r--r--include/linux/rtnetlink.h15
-rw-r--r--include/linux/sched.h129
-rw-r--r--include/linux/seccomp.h10
-rw-r--r--include/linux/serial_8250.h1
-rw-r--r--include/linux/serio.h6
-rw-r--r--include/linux/skbuff.h71
-rw-r--r--include/linux/slab.h4
-rw-r--r--include/linux/string.h2
-rw-r--r--include/linux/suspend.h2
-rw-r--r--include/linux/swap.h4
-rw-r--r--include/linux/syscalls.h8
-rw-r--r--include/linux/sysctl.h22
-rw-r--r--include/linux/tc_ematch/tc_em_meta.h2
-rw-r--r--include/linux/tc_ematch/tc_em_text.h19
-rw-r--r--include/linux/tcp.h52
-rw-r--r--include/linux/tcp_diag.h4
-rw-r--r--include/linux/textsearch.h180
-rw-r--r--include/linux/textsearch_fsm.h48
-rw-r--r--include/linux/topology.h14
-rw-r--r--include/linux/usb.h8
-rw-r--r--include/linux/usb_cdc.h13
-rw-r--r--include/linux/usb_ch9.h189
-rw-r--r--include/linux/usb_gadget.h14
-rw-r--r--include/linux/usb_isp116x.h47
-rw-r--r--include/linux/videodev2.h2
-rw-r--r--include/linux/wanrouter.h3
-rw-r--r--include/linux/writeback.h8
-rw-r--r--include/linux/xattr_acl.h50
-rw-r--r--include/media/audiochip.h5
-rw-r--r--include/media/id.h4
-rw-r--r--include/media/ir-common.h3
-rw-r--r--include/media/saa6752hs.h49
-rw-r--r--include/media/tuner.h52
-rw-r--r--include/media/tveeprom.h4
-rw-r--r--include/mtd/mtd-abi.h19
-rw-r--r--include/net/ieee80211.h856
-rw-r--r--include/net/ipv6.h1
-rw-r--r--include/net/irda/irda_device.h2
-rw-r--r--include/net/pkt_sched.h17
-rw-r--r--include/net/sch_generic.h13
-rw-r--r--include/net/sctp/constants.h18
-rw-r--r--include/net/sctp/sctp.h3
-rw-r--r--include/net/sctp/sm.h17
-rw-r--r--include/net/sctp/structs.h54
-rw-r--r--include/net/sctp/ulpevent.h16
-rw-r--r--include/net/sctp/ulpqueue.h11
-rw-r--r--include/net/slhc_vj.h21
-rw-r--r--include/net/sock.h25
-rw-r--r--include/net/tcp.h400
-rw-r--r--include/net/x25device.h3
-rw-r--r--include/pcmcia/ciscode.h2
-rw-r--r--include/pcmcia/cs.h44
-rw-r--r--include/pcmcia/cs_types.h4
-rw-r--r--include/pcmcia/device_id.h249
-rw-r--r--include/pcmcia/ds.h32
-rw-r--r--include/pcmcia/ss.h34
-rw-r--r--include/pcmcia/version.h3
-rw-r--r--include/scsi/sg_request.h26
-rw-r--r--init/Kconfig2
-rw-r--r--init/do_mounts.c1
-rw-r--r--init/do_mounts.h1
-rw-r--r--init/do_mounts_initrd.c9
-rw-r--r--init/main.c7
-rw-r--r--ipc/compat.c1
-rw-r--r--ipc/util.h2
-rw-r--r--kernel/Kconfig.preempt65
-rw-r--r--kernel/Makefile2
-rw-r--r--kernel/cpu.c14
-rw-r--r--kernel/cpuset.c89
-rw-r--r--kernel/crash_dump.c52
-rw-r--r--kernel/exit.c2
-rw-r--r--kernel/fork.c30
-rw-r--r--kernel/irq/autoprobe.c9
-rw-r--r--kernel/irq/handle.c2
-rw-r--r--kernel/irq/spurious.c115
-rw-r--r--kernel/itimer.c8
-rw-r--r--kernel/kexec.c1063
-rw-r--r--kernel/kmod.c17
-rw-r--r--kernel/kprobes.c170
-rw-r--r--kernel/ksysfs.c13
-rw-r--r--kernel/module.c97
-rw-r--r--kernel/panic.c23
-rw-r--r--kernel/power/Kconfig8
-rw-r--r--kernel/power/Makefile6
-rw-r--r--kernel/power/disk.c47
-rw-r--r--kernel/power/main.c32
-rw-r--r--kernel/power/process.c30
-rw-r--r--kernel/power/smp.c89
-rw-r--r--kernel/power/swsusp.c131
-rw-r--r--kernel/printk.c3
-rw-r--r--kernel/profile.c4
-rw-r--r--kernel/resource.c2
-rw-r--r--kernel/sched.c1072
-rw-r--r--kernel/signal.c5
-rw-r--r--kernel/sys.c25
-rw-r--r--kernel/sys_ni.c5
-rw-r--r--kernel/sysctl.c46
-rw-r--r--kernel/timer.c2
-rw-r--r--kernel/user.c4
-rw-r--r--lib/Kconfig13
-rw-r--r--lib/Makefile4
-rw-r--r--lib/bitmap.c3
-rw-r--r--lib/radix-tree.c2
-rw-r--r--lib/sha1.c2
-rw-r--r--lib/textsearch.c317
-rw-r--r--lib/ts_fsm.c338
-rw-r--r--lib/ts_kmp.c145
-rw-r--r--mm/Makefile1
-rw-r--r--mm/bootmem.c14
-rw-r--r--mm/fadvise.c4
-rw-r--r--mm/filemap.c85
-rw-r--r--mm/filemap.h94
-rw-r--r--mm/filemap_xip.c447
-rw-r--r--mm/madvise.c5
-rw-r--r--mm/memory.c4
-rw-r--r--mm/mempool.c2
-rw-r--r--mm/oom_kill.c10
-rw-r--r--mm/page-writeback.c2
-rw-r--r--mm/page_alloc.c11
-rw-r--r--mm/page_io.c2
-rw-r--r--mm/pdflush.c2
-rw-r--r--mm/rmap.c4
-rw-r--r--mm/slab.c15
-rw-r--r--mm/vmscan.c6
-rw-r--r--net/802/fddi.c4
-rw-r--r--net/8021q/Kconfig19
-rw-r--r--net/8021q/vlan.c8
-rw-r--r--net/Kconfig456
-rw-r--r--net/atm/Kconfig74
-rw-r--r--net/atm/br2684.c3
-rw-r--r--net/bluetooth/cmtp/core.c6
-rw-r--r--net/bluetooth/hidp/core.c5
-rw-r--r--net/bluetooth/rfcomm/sock.c7
-rw-r--r--net/bluetooth/rfcomm/tty.c2
-rw-r--r--net/bridge/Kconfig31
-rw-r--r--net/bridge/br_netfilter.c2
-rw-r--r--net/bridge/netfilter/ebt_log.c6
-rw-r--r--net/core/dev.c132
-rw-r--r--net/core/filter.c104
-rw-r--r--net/core/neighbour.c6
-rw-r--r--net/core/pktgen.c29
-rw-r--r--net/core/rtnetlink.c2
-rw-r--r--net/core/skbuff.c176
-rw-r--r--net/core/sock.c11
-rw-r--r--net/core/sysctl_net_core.c46
-rw-r--r--net/core/wireless.c1
-rw-r--r--net/decnet/Kconfig23
-rw-r--r--net/decnet/af_decnet.c10
-rw-r--r--net/decnet/dn_fib.c3
-rw-r--r--net/decnet/dn_nsp_out.c3
-rw-r--r--net/econet/Kconfig36
-rw-r--r--net/ethernet/eth.c9
-rw-r--r--net/ipv4/Kconfig180
-rw-r--r--net/ipv4/Makefile10
-rw-r--r--net/ipv4/af_inet.c11
-rw-r--r--net/ipv4/fib_trie.c256
-rw-r--r--net/ipv4/icmp.c3
-rw-r--r--net/ipv4/igmp.c96
-rw-r--r--net/ipv4/ip_input.c6
-rw-r--r--net/ipv4/ip_output.c19
-rw-r--r--net/ipv4/ip_sockglue.c6
-rw-r--r--net/ipv4/ipconfig.c4
-rw-r--r--net/ipv4/ipmr.c10
-rw-r--r--net/ipv4/ipvs/Kconfig4
-rw-r--r--net/ipv4/ipvs/ip_vs_conn.c31
-rw-r--r--net/ipv4/ipvs/ip_vs_ctl.c17
-rw-r--r--net/ipv4/ipvs/ip_vs_sync.c4
-rw-r--r--net/ipv4/netfilter/ip_conntrack_standalone.c7
-rw-r--r--net/ipv4/netfilter/ipt_CLUSTERIP.c7
-rw-r--r--net/ipv4/route.c137
-rw-r--r--net/ipv4/sysctl_net_ipv4.c114
-rw-r--r--net/ipv4/tcp.c85
-rw-r--r--net/ipv4/tcp_bic.c331
-rw-r--r--net/ipv4/tcp_cong.c237
-rw-r--r--net/ipv4/tcp_diag.c34
-rw-r--r--net/ipv4/tcp_highspeed.c181
-rw-r--r--net/ipv4/tcp_htcp.c289
-rw-r--r--net/ipv4/tcp_hybla.c187
-rw-r--r--net/ipv4/tcp_input.c824
-rw-r--r--net/ipv4/tcp_ipv4.c5
-rw-r--r--net/ipv4/tcp_minisocks.c4
-rw-r--r--net/ipv4/tcp_output.c569
-rw-r--r--net/ipv4/tcp_scalable.c68
-rw-r--r--net/ipv4/tcp_timer.c5
-rw-r--r--net/ipv4/tcp_vegas.c411
-rw-r--r--net/ipv4/tcp_westwood.c259
-rw-r--r--net/ipv6/Kconfig22
-rw-r--r--net/ipv6/addrconf.c19
-rw-r--r--net/ipv6/af_inet6.c4
-rw-r--r--net/ipv6/ip6_flowlabel.c1
-rw-r--r--net/ipv6/ip6_output.c1
-rw-r--r--net/ipv6/mcast.c29
-rw-r--r--net/ipv6/tcp_ipv6.c4
-rw-r--r--net/ipx/Kconfig33
-rw-r--r--net/irda/irlap.c3
-rw-r--r--net/irda/irlap_event.c14
-rw-r--r--net/irda/irlap_frame.c8
-rw-r--r--net/irda/irttp.c2
-rw-r--r--net/lapb/Kconfig22
-rw-r--r--net/llc/llc_c_ev.c2
-rw-r--r--net/netlink/af_netlink.c13
-rw-r--r--net/packet/Kconfig26
-rw-r--r--net/packet/af_packet.c6
-rw-r--r--net/rxrpc/krxiod.c2
-rw-r--r--net/rxrpc/krxsecd.c2
-rw-r--r--net/rxrpc/krxtimod.c2
-rw-r--r--net/sched/Kconfig50
-rw-r--r--net/sched/Makefile3
-rw-r--r--net/sched/act_api.c10
-rw-r--r--net/sched/cls_api.c2
-rw-r--r--net/sched/cls_rsvp.h1
-rw-r--r--net/sched/em_meta.c6
-rw-r--r--net/sched/em_text.c157
-rw-r--r--net/sched/sch_api.c65
-rw-r--r--net/sched/sch_blackhole.c54
-rw-r--r--net/sched/sch_cbq.c3
-rw-r--r--net/sched/sch_generic.c35
-rw-r--r--net/sched/sch_red.c2
-rw-r--r--net/sctp/associola.c15
-rw-r--r--net/sctp/bind_addr.c16
-rw-r--r--net/sctp/chunk.c2
-rw-r--r--net/sctp/endpointola.c19
-rw-r--r--net/sctp/input.c26
-rw-r--r--net/sctp/inqueue.c18
-rw-r--r--net/sctp/output.c22
-rw-r--r--net/sctp/outqueue.c50
-rw-r--r--net/sctp/protocol.c7
-rw-r--r--net/sctp/sm_make_chunk.c27
-rw-r--r--net/sctp/sm_sideeffect.c13
-rw-r--r--net/sctp/sm_statefuns.c16
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/sctp/ssnmap.c3
-rw-r--r--net/sctp/sysctl.c13
-rw-r--r--net/sctp/transport.c6
-rw-r--r--net/sctp/ulpevent.c19
-rw-r--r--net/sctp/ulpqueue.c9
-rw-r--r--net/sunrpc/sunrpc_syms.c1
-rw-r--r--net/sunrpc/svcsock.c6
-rw-r--r--net/sunrpc/xprt.c6
-rw-r--r--net/unix/Kconfig21
-rw-r--r--net/unix/af_unix.c4
-rw-r--r--net/wanrouter/Kconfig29
-rw-r--r--net/wanrouter/wanmain.c6
-rw-r--r--net/x25/Kconfig36
-rw-r--r--net/xfrm/Kconfig15
-rw-r--r--scripts/basic/docproc.c14
-rw-r--r--scripts/basic/fixdep.c20
-rw-r--r--scripts/basic/split-include.c2
-rw-r--r--scripts/kconfig/conf.c6
-rw-r--r--scripts/kconfig/confdata.c4
-rw-r--r--scripts/kconfig/mconf.c5
-rw-r--r--scripts/mod/file2alias.c61
-rw-r--r--security/keys/Makefile5
-rw-r--r--security/keys/compat.c7
-rw-r--r--security/keys/internal.h45
-rw-r--r--security/keys/key.c118
-rw-r--r--security/keys/keyctl.c199
-rw-r--r--security/keys/keyring.c321
-rw-r--r--security/keys/proc.c21
-rw-r--r--security/keys/process_keys.c213
-rw-r--r--security/keys/request_key.c221
-rw-r--r--security/keys/request_key_auth.c180
-rw-r--r--security/keys/user_defined.c87
-rw-r--r--security/selinux/hooks.c27
-rw-r--r--security/selinux/include/av_perm_to_string.h2
-rw-r--r--security/selinux/include/av_permissions.h2
-rw-r--r--security/selinux/selinuxfs.c9
-rw-r--r--security/selinux/ss/conditional.c9
-rw-r--r--security/selinux/ss/policydb.c15
-rw-r--r--security/selinux/ss/services.c6
-rw-r--r--sound/oss/Kconfig64
-rw-r--r--sound/oss/ad1816.c2
-rw-r--r--sound/oss/ad1848.c3
-rw-r--r--sound/oss/ad1889.c3
-rw-r--r--sound/oss/cmpci.c3
-rw-r--r--sound/oss/cs46xx.c6
-rw-r--r--sound/oss/dmasound/dmasound_awacs.c34
-rw-r--r--sound/oss/emu10k1/midi.c6
-rw-r--r--sound/oss/emu10k1/passthrough.c3
-rw-r--r--sound/oss/es1370.c91
-rw-r--r--sound/oss/es1371.c98
-rw-r--r--sound/oss/esssolo1.c29
-rw-r--r--sound/oss/mad16.c30
-rw-r--r--sound/oss/maestro.c2
-rw-r--r--sound/oss/mpu401.c3
-rw-r--r--sound/oss/nm256.h5
-rw-r--r--sound/oss/nm256_audio.c9
-rw-r--r--sound/oss/nm256_coeff.h2
-rw-r--r--sound/oss/rme96xx.c4
-rw-r--r--sound/oss/sb_common.c4
-rw-r--r--sound/oss/sonicvibes.c25
-rw-r--r--sound/oss/sscape.c8
-rw-r--r--sound/oss/trident.c37
-rw-r--r--sound/oss/v_midi.c2
-rw-r--r--sound/oss/via82cxxx_audio.c5
-rw-r--r--sound/oss/wavfront.c12
-rw-r--r--sound/pci/bt87x.c4
-rw-r--r--sound/pci/cs4281.c5
-rw-r--r--sound/pcmcia/pdaudiocf/pdaudiocf.c27
-rw-r--r--sound/pcmcia/vx/vx_entry.c12
-rw-r--r--sound/pcmcia/vx/vxpocket.c21
-rw-r--r--sound/ppc/awacs.c8
-rw-r--r--sound/ppc/daca.c6
-rw-r--r--sound/ppc/pmac.c11
-rw-r--r--sound/ppc/pmac.h2
-rw-r--r--sound/ppc/tumbler.c4
2863 files changed, 168431 insertions, 88654 deletions
diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX
index 8de8a01a2474..f28a24e0279b 100644
--- a/Documentation/00-INDEX
+++ b/Documentation/00-INDEX
@@ -138,6 +138,8 @@ java.txt
- info on the in-kernel binary support for Java(tm).
kbuild/
- directory with info about the kernel build process.
+kdumpt.txt
+ - mini HowTo on getting the crash dump code to work.
kernel-doc-nano-HOWTO.txt
- mini HowTo on generation and location of kernel documentation files.
kernel-docs.txt
diff --git a/Documentation/Changes b/Documentation/Changes
index 57542bc25edd..dfec7569d450 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -44,9 +44,9 @@ running, the suggested command should tell you.
Again, keep in mind that this list assumes you are already
functionally running a Linux 2.4 kernel. Also, not all tools are
-necessary on all systems; obviously, if you don't have any PCMCIA (PC
-Card) hardware, for example, you probably needn't concern yourself
-with pcmcia-cs.
+necessary on all systems; obviously, if you don't have any ISDN
+hardware, for example, you probably needn't concern yourself with
+isdn4k-utils.
o Gnu C 2.95.3 # gcc --version
o Gnu make 3.79.1 # make --version
@@ -57,13 +57,14 @@ o e2fsprogs 1.29 # tune2fs
o jfsutils 1.1.3 # fsck.jfs -V
o reiserfsprogs 3.6.3 # reiserfsck -V 2>&1|grep reiserfsprogs
o xfsprogs 2.6.0 # xfs_db -V
+o pcmciautils 004
o pcmcia-cs 3.1.21 # cardmgr -V
o quota-tools 3.09 # quota -V
o PPP 2.4.0 # pppd --version
o isdn4k-utils 3.1pre1 # isdnctrl 2>&1|grep version
o nfs-utils 1.0.5 # showmount --version
o procps 3.2.0 # ps --version
-o oprofile 0.5.3 # oprofiled --version
+o oprofile 0.9 # oprofiled --version
Kernel compilation
==================
@@ -186,13 +187,20 @@ architecture independent and any version from 2.0.0 onward should
work correctly with this version of the XFS kernel code (2.6.0 or
later is recommended, due to some significant improvements).
+PCMCIAutils
+-----------
+
+PCMCIAutils replaces pcmcia-cs (see below). It properly sets up
+PCMCIA sockets at system startup and loads the appropriate modules
+for 16-bit PCMCIA devices if the kernel is modularized and the hotplug
+subsystem is used.
Pcmcia-cs
---------
PCMCIA (PC Card) support is now partially implemented in the main
-kernel source. Pay attention when you recompile your kernel ;-).
-Also, be sure to upgrade to the latest pcmcia-cs release.
+kernel source. The "pcmciautils" package (see above) replaces pcmcia-cs
+for newest kernels.
Quota-tools
-----------
@@ -349,9 +357,13 @@ Xfsprogs
--------
o <ftp://oss.sgi.com/projects/xfs/download/>
+Pcmciautils
+-----------
+o <ftp://ftp.kernel.org/pub/linux/utils/kernel/pcmcia/>
+
Pcmcia-cs
---------
-o <ftp://pcmcia-cs.sourceforge.net/pub/pcmcia-cs/pcmcia-cs-3.1.21.tar.gz>
+o <http://pcmcia-cs.sourceforge.net/>
Quota-tools
----------
diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile
index 87da3478fada..fa3e29ad8a46 100644
--- a/Documentation/DocBook/Makefile
+++ b/Documentation/DocBook/Makefile
@@ -49,7 +49,7 @@ installmandocs: mandocs
KERNELDOC = scripts/kernel-doc
DOCPROC = scripts/basic/docproc
-XMLTOFLAGS = -m Documentation/DocBook/stylesheet.xsl
+XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
#XMLTOFLAGS += --skip-validation
###
diff --git a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl
index bb6a0106be11..d650ce36485f 100644
--- a/Documentation/DocBook/kernel-api.tmpl
+++ b/Documentation/DocBook/kernel-api.tmpl
@@ -266,7 +266,7 @@ X!Ekernel/module.c
<chapter id="hardware">
<title>Hardware Interfaces</title>
<sect1><title>Interrupt Handling</title>
-!Iarch/i386/kernel/irq.c
+!Ikernel/irq/manage.c
</sect1>
<sect1><title>Resources Management</title>
diff --git a/Documentation/DocBook/libata.tmpl b/Documentation/DocBook/libata.tmpl
index 6df1dfd18b65..375ae760dc1e 100644
--- a/Documentation/DocBook/libata.tmpl
+++ b/Documentation/DocBook/libata.tmpl
@@ -84,6 +84,14 @@ void (*port_disable) (struct ata_port *);
Called from ata_bus_probe() and ata_bus_reset() error paths,
as well as when unregistering from the SCSI module (rmmod, hot
unplug).
+ This function should do whatever needs to be done to take the
+ port out of use. In most cases, ata_port_disable() can be used
+ as this hook.
+ </para>
+ <para>
+ Called from ata_bus_probe() on a failed probe.
+ Called from ata_bus_reset() on a failed bus reset.
+ Called from ata_scsi_release().
</para>
</sect2>
@@ -98,6 +106,13 @@ void (*dev_config) (struct ata_port *, struct ata_device *);
found. Typically used to apply device-specific fixups prior to
issue of SET FEATURES - XFER MODE, and prior to operation.
</para>
+ <para>
+ Called by ata_device_add() after ata_dev_identify() determines
+ a device is present.
+ </para>
+ <para>
+ This entry may be specified as NULL in ata_port_operations.
+ </para>
</sect2>
@@ -135,6 +150,8 @@ void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf);
registers / DMA buffers. ->tf_read() is called to read the
hardware registers / DMA buffers, to obtain the current set of
taskfile register values.
+ Most drivers for taskfile-based hardware (PIO or MMIO) use
+ ata_tf_load() and ata_tf_read() for these hooks.
</para>
</sect2>
@@ -147,6 +164,8 @@ void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf);
<para>
causes an ATA command, previously loaded with
->tf_load(), to be initiated in hardware.
+ Most drivers for taskfile-based hardware use ata_exec_command()
+ for this hook.
</para>
</sect2>
@@ -161,6 +180,10 @@ Allow low-level driver to filter ATA PACKET commands, returning a status
indicating whether or not it is OK to use DMA for the supplied PACKET
command.
</para>
+ <para>
+ This hook may be specified as NULL, in which case libata will
+ assume that atapi dma can be supported.
+ </para>
</sect2>
@@ -175,6 +198,14 @@ u8 (*check_err)(struct ata_port *ap);
Reads the Status/AltStatus/Error ATA shadow register from
hardware. On some hardware, reading the Status register has
the side effect of clearing the interrupt condition.
+ Most drivers for taskfile-based hardware use
+ ata_check_status() for this hook.
+ </para>
+ <para>
+ Note that because this is called from ata_device_add(), at
+ least a dummy function that clears device interrupts must be
+ provided for all drivers, even if the controller doesn't
+ actually have a taskfile status register.
</para>
</sect2>
@@ -188,7 +219,13 @@ void (*dev_select)(struct ata_port *ap, unsigned int device);
Issues the low-level hardware command(s) that causes one of N
hardware devices to be considered 'selected' (active and
available for use) on the ATA bus. This generally has no
-meaning on FIS-based devices.
+ meaning on FIS-based devices.
+ </para>
+ <para>
+ Most drivers for taskfile-based hardware use
+ ata_std_dev_select() for this hook. Controllers which do not
+ support second drives on a port (such as SATA contollers) will
+ use ata_noop_dev_select().
</para>
</sect2>
@@ -204,6 +241,8 @@ void (*phy_reset) (struct ata_port *ap);
for device presence (PATA and SATA), typically a soft reset
(SRST) will be performed. Drivers typically use the helper
functions ata_bus_reset() or sata_phy_reset() for this hook.
+ Many SATA drivers use sata_phy_reset() or call it from within
+ their own phy_reset() functions.
</para>
</sect2>
@@ -227,6 +266,25 @@ PCI IDE DMA Status register.
These hooks are typically either no-ops, or simply not implemented, in
FIS-based drivers.
</para>
+ <para>
+Most legacy IDE drivers use ata_bmdma_setup() for the bmdma_setup()
+hook. ata_bmdma_setup() will write the pointer to the PRD table to
+the IDE PRD Table Address register, enable DMA in the DMA Command
+register, and call exec_command() to begin the transfer.
+ </para>
+ <para>
+Most legacy IDE drivers use ata_bmdma_start() for the bmdma_start()
+hook. ata_bmdma_start() will write the ATA_DMA_START flag to the DMA
+Command register.
+ </para>
+ <para>
+Many legacy IDE drivers use ata_bmdma_stop() for the bmdma_stop()
+hook. ata_bmdma_stop() clears the ATA_DMA_START flag in the DMA
+command register.
+ </para>
+ <para>
+Many legacy IDE drivers use ata_bmdma_status() as the bmdma_status() hook.
+ </para>
</sect2>
@@ -250,6 +308,10 @@ int (*qc_issue) (struct ata_queued_cmd *qc);
helper function ata_qc_issue_prot() for taskfile protocol-based
dispatch. More advanced drivers implement their own ->qc_issue.
</para>
+ <para>
+ ata_qc_issue_prot() calls ->tf_load(), ->bmdma_setup(), and
+ ->bmdma_start() as necessary to initiate a transfer.
+ </para>
</sect2>
@@ -279,6 +341,21 @@ void (*irq_clear) (struct ata_port *);
before the interrupt handler is registered, to be sure hardware
is quiet.
</para>
+ <para>
+ The second argument, dev_instance, should be cast to a pointer
+ to struct ata_host_set.
+ </para>
+ <para>
+ Most legacy IDE drivers use ata_interrupt() for the
+ irq_handler hook, which scans all ports in the host_set,
+ determines which queued command was active (if any), and calls
+ ata_host_intr(ap,qc).
+ </para>
+ <para>
+ Most legacy IDE drivers use ata_bmdma_irq_clear() for the
+ irq_clear() hook, which simply clears the interrupt and error
+ flags in the DMA status register.
+ </para>
</sect2>
@@ -292,6 +369,7 @@ void (*scr_write) (struct ata_port *ap, unsigned int sc_reg,
<para>
Read and write standard SATA phy registers. Currently only used
if ->phy_reset hook called the sata_phy_reset() helper function.
+ sc_reg is one of SCR_STATUS, SCR_CONTROL, SCR_ERROR, or SCR_ACTIVE.
</para>
</sect2>
@@ -307,17 +385,29 @@ void (*host_stop) (struct ata_host_set *host_set);
->port_start() is called just after the data structures for each
port are initialized. Typically this is used to alloc per-port
DMA buffers / tables / rings, enable DMA engines, and similar
- tasks.
+ tasks. Some drivers also use this entry point as a chance to
+ allocate driver-private memory for ap->private_data.
+ </para>
+ <para>
+ Many drivers use ata_port_start() as this hook or call
+ it from their own port_start() hooks. ata_port_start()
+ allocates space for a legacy IDE PRD table and returns.
</para>
<para>
->port_stop() is called after ->host_stop(). It's sole function
is to release DMA/memory resources, now that they are no longer
- actively being used.
+ actively being used. Many drivers also free driver-private
+ data from port at this time.
+ </para>
+ <para>
+ Many drivers use ata_port_stop() as this hook, which frees the
+ PRD table.
</para>
<para>
->host_stop() is called after all ->port_stop() calls
have completed. The hook must finalize hardware shutdown, release DMA
and other resources, etc.
+ This hook may be specified as NULL, in which case it is not called.
</para>
</sect2>
diff --git a/Documentation/DocBook/stylesheet.xsl b/Documentation/DocBook/stylesheet.xsl
index e14c21dda403..64be9f7ee3bb 100644
--- a/Documentation/DocBook/stylesheet.xsl
+++ b/Documentation/DocBook/stylesheet.xsl
@@ -2,4 +2,5 @@
<stylesheet xmlns="http://www.w3.org/1999/XSL/Transform" version="1.0">
<param name="chunk.quietly">1</param>
<param name="funcsynopsis.style">ansi</param>
+<param name="funcsynopsis.tabular.threshold">80</param>
</stylesheet>
diff --git a/Documentation/IPMI.txt b/Documentation/IPMI.txt
index 90d10e708ca3..84d3d4d10c17 100644
--- a/Documentation/IPMI.txt
+++ b/Documentation/IPMI.txt
@@ -25,9 +25,10 @@ subject and I can't cover it all here!
Configuration
-------------
-The LinuxIPMI driver is modular, which means you have to pick several
+The Linux IPMI driver is modular, which means you have to pick several
things to have it work right depending on your hardware. Most of
-these are available in the 'Character Devices' menu.
+these are available in the 'Character Devices' menu then the IPMI
+menu.
No matter what, you must pick 'IPMI top-level message handler' to use
IPMI. What you do beyond that depends on your needs and hardware.
@@ -35,33 +36,30 @@ IPMI. What you do beyond that depends on your needs and hardware.
The message handler does not provide any user-level interfaces.
Kernel code (like the watchdog) can still use it. If you need access
from userland, you need to select 'Device interface for IPMI' if you
-want access through a device driver. Another interface is also
-available, you may select 'IPMI sockets' in the 'Networking Support'
-main menu. This provides a socket interface to IPMI. You may select
-both of these at the same time, they will both work together.
-
-The driver interface depends on your hardware. If you have a board
-with a standard interface (These will generally be either "KCS",
-"SMIC", or "BT", consult your hardware manual), choose the 'IPMI SI
-handler' option. A driver also exists for direct I2C access to the
-IPMI management controller. Some boards support this, but it is
-unknown if it will work on every board. For this, choose 'IPMI SMBus
-handler', but be ready to try to do some figuring to see if it will
-work.
-
-There is also a KCS-only driver interface supplied, but it is
-depracated in favor of the SI interface.
+want access through a device driver.
+
+The driver interface depends on your hardware. If your system
+properly provides the SMBIOS info for IPMI, the driver will detect it
+and just work. If you have a board with a standard interface (These
+will generally be either "KCS", "SMIC", or "BT", consult your hardware
+manual), choose the 'IPMI SI handler' option. A driver also exists
+for direct I2C access to the IPMI management controller. Some boards
+support this, but it is unknown if it will work on every board. For
+this, choose 'IPMI SMBus handler', but be ready to try to do some
+figuring to see if it will work on your system if the SMBIOS/APCI
+information is wrong or not present. It is fairly safe to have both
+these enabled and let the drivers auto-detect what is present.
You should generally enable ACPI on your system, as systems with IPMI
-should have ACPI tables describing them.
+can have ACPI tables describing them.
If you have a standard interface and the board manufacturer has done
their job correctly, the IPMI controller should be automatically
-detect (via ACPI or SMBIOS tables) and should just work. Sadly, many
-boards do not have this information. The driver attempts standard
-defaults, but they may not work. If you fall into this situation, you
-need to read the section below named 'The SI Driver' on how to
-hand-configure your system.
+detected (via ACPI or SMBIOS tables) and should just work. Sadly,
+many boards do not have this information. The driver attempts
+standard defaults, but they may not work. If you fall into this
+situation, you need to read the section below named 'The SI Driver' or
+"The SMBus Driver" on how to hand-configure your system.
IPMI defines a standard watchdog timer. You can enable this with the
'IPMI Watchdog Timer' config option. If you compile the driver into
@@ -73,6 +71,18 @@ closed (by default it is disabled on close). Go into the 'Watchdog
Cards' menu, enable 'Watchdog Timer Support', and enable the option
'Disable watchdog shutdown on close'.
+IPMI systems can often be powered off using IPMI commands. Select
+'IPMI Poweroff' to do this. The driver will auto-detect if the system
+can be powered off by IPMI. It is safe to enable this even if your
+system doesn't support this option. This works on ATCA systems, the
+Radisys CPI1 card, and any IPMI system that supports standard chassis
+management commands.
+
+If you want the driver to put an event into the event log on a panic,
+enable the 'Generate a panic event to all BMCs on a panic' option. If
+you want the whole panic string put into the event log using OEM
+events, enable the 'Generate OEM events containing the panic string'
+option.
Basic Design
------------
@@ -80,7 +90,7 @@ Basic Design
The Linux IPMI driver is designed to be very modular and flexible, you
only need to take the pieces you need and you can use it in many
different ways. Because of that, it's broken into many chunks of
-code. These chunks are:
+code. These chunks (by module name) are:
ipmi_msghandler - This is the central piece of software for the IPMI
system. It handles all messages, message timing, and responses. The
@@ -93,18 +103,26 @@ ipmi_devintf - This provides a userland IOCTL interface for the IPMI
driver, each open file for this device ties in to the message handler
as an IPMI user.
-ipmi_si - A driver for various system interfaces. This supports
-KCS, SMIC, and may support BT in the future. Unless you have your own
-custom interface, you probably need to use this.
+ipmi_si - A driver for various system interfaces. This supports KCS,
+SMIC, and BT interfaces. Unless you have an SMBus interface or your
+own custom interface, you probably need to use this.
ipmi_smb - A driver for accessing BMCs on the SMBus. It uses the
I2C kernel driver's SMBus interfaces to send and receive IPMI messages
over the SMBus.
-af_ipmi - A network socket interface to IPMI. This doesn't take up
-a character device in your system.
+ipmi_watchdog - IPMI requires systems to have a very capable watchdog
+timer. This driver implements the standard Linux watchdog timer
+interface on top of the IPMI message handler.
+
+ipmi_poweroff - Some systems support the ability to be turned off via
+IPMI commands.
-Note that the KCS-only interface ahs been removed.
+These are all individually selectable via configuration options.
+
+Note that the KCS-only interface has been removed. The af_ipmi driver
+is no longer supported and has been removed because it was impossible
+to do 32 bit emulation on 64-bit kernels with it.
Much documentation for the interface is in the include files. The
IPMI include files are:
@@ -424,7 +442,7 @@ at module load time (for a module) with:
modprobe ipmi_smb.o
addr=<adapter1>,<i2caddr1>[,<adapter2>,<i2caddr2>[,...]]
dbg=<flags1>,<flags2>...
- [defaultprobe=0] [dbg_probe=1]
+ [defaultprobe=1] [dbg_probe=1]
The addresses are specified in pairs, the first is the adapter ID and the
second is the I2C address on that adapter.
@@ -532,3 +550,67 @@ Once you open the watchdog timer, you must write a 'V' character to the
device to close it, or the timer will not stop. This is a new semantic
for the driver, but makes it consistent with the rest of the watchdog
drivers in Linux.
+
+
+Panic Timeouts
+--------------
+
+The OpenIPMI driver supports the ability to put semi-custom and custom
+events in the system event log if a panic occurs. if you enable the
+'Generate a panic event to all BMCs on a panic' option, you will get
+one event on a panic in a standard IPMI event format. If you enable
+the 'Generate OEM events containing the panic string' option, you will
+also get a bunch of OEM events holding the panic string.
+
+
+The field settings of the events are:
+* Generator ID: 0x21 (kernel)
+* EvM Rev: 0x03 (this event is formatting in IPMI 1.0 format)
+* Sensor Type: 0x20 (OS critical stop sensor)
+* Sensor #: The first byte of the panic string (0 if no panic string)
+* Event Dir | Event Type: 0x6f (Assertion, sensor-specific event info)
+* Event Data 1: 0xa1 (Runtime stop in OEM bytes 2 and 3)
+* Event data 2: second byte of panic string
+* Event data 3: third byte of panic string
+See the IPMI spec for the details of the event layout. This event is
+always sent to the local management controller. It will handle routing
+the message to the right place
+
+Other OEM events have the following format:
+Record ID (bytes 0-1): Set by the SEL.
+Record type (byte 2): 0xf0 (OEM non-timestamped)
+byte 3: The slave address of the card saving the panic
+byte 4: A sequence number (starting at zero)
+The rest of the bytes (11 bytes) are the panic string. If the panic string
+is longer than 11 bytes, multiple messages will be sent with increasing
+sequence numbers.
+
+Because you cannot send OEM events using the standard interface, this
+function will attempt to find an SEL and add the events there. It
+will first query the capabilities of the local management controller.
+If it has an SEL, then they will be stored in the SEL of the local
+management controller. If not, and the local management controller is
+an event generator, the event receiver from the local management
+controller will be queried and the events sent to the SEL on that
+device. Otherwise, the events go nowhere since there is nowhere to
+send them.
+
+
+Poweroff
+--------
+
+If the poweroff capability is selected, the IPMI driver will install
+a shutdown function into the standard poweroff function pointer. This
+is in the ipmi_poweroff module. When the system requests a powerdown,
+it will send the proper IPMI commands to do this. This is supported on
+several platforms.
+
+There is a module parameter named "poweroff_control" that may either be zero
+(do a power down) or 2 (do a power cycle, power the system off, then power
+it on in a few seconds). Setting ipmi_poweroff.poweroff_control=x will do
+the same thing on the kernel command line. The parameter is also available
+via the proc filesystem in /proc/ipmi/poweroff_control. Note that if the
+system does not support power cycling, it will always to the power off.
+
+Note that if you have ACPI enabled, the system will prefer using ACPI to
+power off.
diff --git a/Documentation/SubmittingDrivers b/Documentation/SubmittingDrivers
index de3b252e717d..c3cca924e94b 100644
--- a/Documentation/SubmittingDrivers
+++ b/Documentation/SubmittingDrivers
@@ -13,13 +13,14 @@ Allocating Device Numbers
-------------------------
Major and minor numbers for block and character devices are allocated
-by the Linux assigned name and number authority (currently better
-known as H Peter Anvin). The site is http://www.lanana.org/. This
+by the Linux assigned name and number authority (currently this is
+Torben Mathiasen). The site is http://www.lanana.org/. This
also deals with allocating numbers for devices that are not going to
be submitted to the mainstream kernel.
+See Documentation/devices.txt for more information on this.
-If you don't use assigned numbers then when you device is submitted it will
-get given an assigned number even if that is different from values you may
+If you don't use assigned numbers then when your device is submitted it will
+be given an assigned number even if that is different from values you may
have shipped to customers before.
Who To Submit Drivers To
@@ -32,7 +33,8 @@ Linux 2.2:
If the code area has a general maintainer then please submit it to
the maintainer listed in MAINTAINERS in the kernel file. If the
maintainer does not respond or you cannot find the appropriate
- maintainer then please contact Alan Cox <alan@lxorguk.ukuu.org.uk>
+ maintainer then please contact the 2.2 kernel maintainer:
+ Marc-Christian Petersen <m.c.p@wolk-project.de>.
Linux 2.4:
The same rules apply as 2.2. The final contact point for Linux 2.4
@@ -48,7 +50,7 @@ What Criteria Determine Acceptance
Licensing: The code must be released to us under the
GNU General Public License. We don't insist on any kind
- of exclusively GPL licensing, and if you wish the driver
+ of exclusive GPL licensing, and if you wish the driver
to be useful to other communities such as BSD you may well
wish to release under multiple licenses.
diff --git a/Documentation/SubmittingPatches b/Documentation/SubmittingPatches
index 4d35562b1cf9..6761a7b241a5 100644
--- a/Documentation/SubmittingPatches
+++ b/Documentation/SubmittingPatches
@@ -35,7 +35,7 @@ not in any lower subdirectory.
To create a patch for a single file, it is often sufficient to do:
- SRCTREE= linux-2.4
+ SRCTREE= linux-2.6
MYFILE= drivers/net/mydriver.c
cd $SRCTREE
@@ -48,17 +48,18 @@ To create a patch for multiple files, you should unpack a "vanilla",
or unmodified kernel source tree, and generate a diff against your
own source tree. For example:
- MYSRC= /devel/linux-2.4
+ MYSRC= /devel/linux-2.6
- tar xvfz linux-2.4.0-test11.tar.gz
- mv linux linux-vanilla
- wget http://www.moses.uklinux.net/patches/dontdiff
- diff -uprN -X dontdiff linux-vanilla $MYSRC > /tmp/patch
- rm -f dontdiff
+ tar xvfz linux-2.6.12.tar.gz
+ mv linux-2.6.12 linux-2.6.12-vanilla
+ diff -uprN -X linux-2.6.12-vanilla/Documentation/dontdiff \
+ linux-2.6.12-vanilla $MYSRC > /tmp/patch
"dontdiff" is a list of files which are generated by the kernel during
the build process, and should be ignored in any diff(1)-generated
-patch. dontdiff is maintained by Tigran Aivazian <tigran@veritas.com>
+patch. The "dontdiff" file is included in the kernel tree in
+2.6.12 and later. For earlier kernel versions, you can get it
+from <http://www.xenotime.net/linux/doc/dontdiff>.
Make sure your patch does not include any extra files which do not
belong in a patch submission. Make sure to review your patch -after-
@@ -66,18 +67,20 @@ generated it with diff(1), to ensure accuracy.
If your changes produce a lot of deltas, you may want to look into
splitting them into individual patches which modify things in
-logical stages, this will facilitate easier reviewing by other
+logical stages. This will facilitate easier reviewing by other
kernel developers, very important if you want your patch accepted.
-There are a number of scripts which can aid in this;
+There are a number of scripts which can aid in this:
Quilt:
http://savannah.nongnu.org/projects/quilt
Randy Dunlap's patch scripts:
-http://developer.osdl.org/rddunlap/scripts/patching-scripts.tgz
+http://www.xenotime.net/linux/scripts/patching-scripts-002.tar.gz
Andrew Morton's patch scripts:
-http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.16
+http://www.zip.com.au/~akpm/linux/patches/patch-scripts-0.20
+
+
2) Describe your changes.
@@ -132,21 +135,6 @@ which require discussion or do not have a clear advantage should
usually be sent first to linux-kernel. Only after the patch is
discussed should the patch then be submitted to Linus.
-For small patches you may want to CC the Trivial Patch Monkey
-trivial@rustcorp.com.au set up by Rusty Russell; which collects "trivial"
-patches. Trivial patches must qualify for one of the following rules:
- Spelling fixes in documentation
- Spelling fixes which could break grep(1).
- Warning fixes (cluttering with useless warnings is bad)
- Compilation fixes (only if they are actually correct)
- Runtime fixes (only if they actually fix things)
- Removing use of deprecated functions/macros (eg. check_region).
- Contact detail and documentation fixes
- Non-portable code replaced by portable code (even in arch-specific,
- since people copy, as long as it's trivial)
- Any fix by the author/maintainer of the file. (ie. patch monkey
- in re-transmission mode)
-
5) Select your CC (e-mail carbon copy) list.
@@ -178,6 +166,8 @@ patches. Trivial patches must qualify for one of the following rules:
since people copy, as long as it's trivial)
Any fix by the author/maintainer of the file. (ie. patch monkey
in re-transmission mode)
+URL: <http://www.kernel.org/pub/linux/kernel/people/rusty/trivial/>
+
@@ -299,13 +289,24 @@ can certify the below:
then you just add a line saying
- Signed-off-by: Random J Developer <random@developer.org>
+ Signed-off-by: Random J Developer <random@developer.example.org>
Some people also put extra tags at the end. They'll just be ignored for
now, but you can do this to mark internal company procedures or just
point out some special detail about the sign-off.
+
+12) More references for submitting patches
+
+Andrew Morton, "The perfect patch" (tpp).
+ <http://www.zip.com.au/~akpm/linux/patches/stuff/tpp.txt>
+
+Jeff Garzik, "Linux kernel patch submission format."
+ <http://linux.yyz.us/patch-format.html>
+
+
+
-----------------------------------
SECTION 2 - HINTS, TIPS, AND TRICKS
-----------------------------------
@@ -374,7 +375,5 @@ and 'extern __inline__'.
4) Don't over-design.
Don't try to anticipate nebulous future cases which may or may not
-be useful: "Make it as simple as you can, and no simpler"
-
-
+be useful: "Make it as simple as you can, and no simpler."
diff --git a/Documentation/acpi-hotkey.txt b/Documentation/acpi-hotkey.txt
new file mode 100644
index 000000000000..4c115a7bb826
--- /dev/null
+++ b/Documentation/acpi-hotkey.txt
@@ -0,0 +1,35 @@
+driver/acpi/hotkey.c implement:
+1. /proc/acpi/hotkey/event_config
+(event based hotkey or event config interface):
+a. add a event based hotkey(event) :
+echo "0:bus::action:method:num:num" > event_config
+
+b. delete a event based hotkey(event):
+echo "1:::::num:num" > event_config
+
+c. modify a event based hotkey(event):
+echo "2:bus::action:method:num:num" > event_config
+
+2. /proc/acpi/hotkey/poll_config
+(polling based hotkey or event config interface):
+a.add a polling based hotkey(event) :
+echo "0:bus:method:action:method:num" > poll_config
+this adding command will create a proc file
+/proc/acpi/hotkey/method, which is used to get
+result of polling.
+
+b.delete a polling based hotkey(event):
+echo "1:::::num" > event_config
+
+c.modify a polling based hotkey(event):
+echo "2:bus:method:action:method:num" > poll_config
+
+3./proc/acpi/hotkey/action
+(interface to call aml method associated with a
+specific hotkey(event))
+echo "event_num:event_type:event_argument" >
+ /proc/acpi/hotkey/action.
+The result of the execution of this aml method is
+attached to /proc/acpi/hotkey/poll_method, which is dnyamically
+created. Please use command "cat /proc/acpi/hotkey/polling_method"
+to retrieve it.
diff --git a/Documentation/basic_profiling.txt b/Documentation/basic_profiling.txt
index 65e3dc2d4437..8764e9f70821 100644
--- a/Documentation/basic_profiling.txt
+++ b/Documentation/basic_profiling.txt
@@ -27,9 +27,13 @@ dump output readprofile -m /boot/System.map > captured_profile
Oprofile
--------
-Get the source (I use 0.8) from http://oprofile.sourceforge.net/
-and add "idle=poll" to the kernel command line
+
+Get the source (see Changes for required version) from
+http://oprofile.sourceforge.net/ and add "idle=poll" to the kernel command
+line.
+
Configure with CONFIG_PROFILING=y and CONFIG_OPROFILE=y & reboot on new kernel
+
./configure --with-kernel-support
make install
@@ -46,7 +50,7 @@ start opcontrol --start
stop opcontrol --stop
dump output opreport > output_file
-To only report on the kernel, run opreport /boot/vmlinux > output_file
+To only report on the kernel, run opreport -l /boot/vmlinux > output_file
A reset is needed to clear old statistics, which survive a reboot.
diff --git a/Documentation/block/ioprio.txt b/Documentation/block/ioprio.txt
new file mode 100644
index 000000000000..96ccf681075e
--- /dev/null
+++ b/Documentation/block/ioprio.txt
@@ -0,0 +1,176 @@
+Block io priorities
+===================
+
+
+Intro
+-----
+
+With the introduction of cfq v3 (aka cfq-ts or time sliced cfq), basic io
+priorities is supported for reads on files. This enables users to io nice
+processes or process groups, similar to what has been possible to cpu
+scheduling for ages. This document mainly details the current possibilites
+with cfq, other io schedulers do not support io priorities so far.
+
+Scheduling classes
+------------------
+
+CFQ implements three generic scheduling classes that determine how io is
+served for a process.
+
+IOPRIO_CLASS_RT: This is the realtime io class. This scheduling class is given
+higher priority than any other in the system, processes from this class are
+given first access to the disk every time. Thus it needs to be used with some
+care, one io RT process can starve the entire system. Within the RT class,
+there are 8 levels of class data that determine exactly how much time this
+process needs the disk for on each service. In the future this might change
+to be more directly mappable to performance, by passing in a wanted data
+rate instead.
+
+IOPRIO_CLASS_BE: This is the best-effort scheduling class, which is the default
+for any process that hasn't set a specific io priority. The class data
+determines how much io bandwidth the process will get, it's directly mappable
+to the cpu nice levels just more coarsely implemented. 0 is the highest
+BE prio level, 7 is the lowest. The mapping between cpu nice level and io
+nice level is determined as: io_nice = (cpu_nice + 20) / 5.
+
+IOPRIO_CLASS_IDLE: This is the idle scheduling class, processes running at this
+level only get io time when no one else needs the disk. The idle class has no
+class data, since it doesn't really apply here.
+
+Tools
+-----
+
+See below for a sample ionice tool. Usage:
+
+# ionice -c<class> -n<level> -p<pid>
+
+If pid isn't given, the current process is assumed. IO priority settings
+are inherited on fork, so you can use ionice to start the process at a given
+level:
+
+# ionice -c2 -n0 /bin/ls
+
+will run ls at the best-effort scheduling class at the highest priority.
+For a running process, you can give the pid instead:
+
+# ionice -c1 -n2 -p100
+
+will change pid 100 to run at the realtime scheduling class, at priority 2.
+
+---> snip ionice.c tool <---
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+
+extern int sys_ioprio_set(int, int, int);
+extern int sys_ioprio_get(int, int);
+
+#if defined(__i386__)
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#elif defined(__ppc__)
+#define __NR_ioprio_set 273
+#define __NR_ioprio_get 274
+#elif defined(__x86_64__)
+#define __NR_ioprio_set 251
+#define __NR_ioprio_get 252
+#elif defined(__ia64__)
+#define __NR_ioprio_set 1274
+#define __NR_ioprio_get 1275
+#else
+#error "Unsupported arch"
+#endif
+
+_syscall3(int, ioprio_set, int, which, int, who, int, ioprio);
+_syscall2(int, ioprio_get, int, which, int, who);
+
+enum {
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+#define IOPRIO_CLASS_SHIFT 13
+
+const char *to_prio[] = { "none", "realtime", "best-effort", "idle", };
+
+int main(int argc, char *argv[])
+{
+ int ioprio = 4, set = 0, ioprio_class = IOPRIO_CLASS_BE;
+ int c, pid = 0;
+
+ while ((c = getopt(argc, argv, "+n:c:p:")) != EOF) {
+ switch (c) {
+ case 'n':
+ ioprio = strtol(optarg, NULL, 10);
+ set = 1;
+ break;
+ case 'c':
+ ioprio_class = strtol(optarg, NULL, 10);
+ set = 1;
+ break;
+ case 'p':
+ pid = strtol(optarg, NULL, 10);
+ break;
+ }
+ }
+
+ switch (ioprio_class) {
+ case IOPRIO_CLASS_NONE:
+ ioprio_class = IOPRIO_CLASS_BE;
+ break;
+ case IOPRIO_CLASS_RT:
+ case IOPRIO_CLASS_BE:
+ break;
+ case IOPRIO_CLASS_IDLE:
+ ioprio = 7;
+ break;
+ default:
+ printf("bad prio class %d\n", ioprio_class);
+ return 1;
+ }
+
+ if (!set) {
+ if (!pid && argv[optind])
+ pid = strtol(argv[optind], NULL, 10);
+
+ ioprio = ioprio_get(IOPRIO_WHO_PROCESS, pid);
+
+ printf("pid=%d, %d\n", pid, ioprio);
+
+ if (ioprio == -1)
+ perror("ioprio_get");
+ else {
+ ioprio_class = ioprio >> IOPRIO_CLASS_SHIFT;
+ ioprio = ioprio & 0xff;
+ printf("%s: prio %d\n", to_prio[ioprio_class], ioprio);
+ }
+ } else {
+ if (ioprio_set(IOPRIO_WHO_PROCESS, pid, ioprio | ioprio_class << IOPRIO_CLASS_SHIFT) == -1) {
+ perror("ioprio_set");
+ return 1;
+ }
+
+ if (argv[optind])
+ execvp(argv[optind], &argv[optind]);
+ }
+
+ return 0;
+}
+
+---> snip ionice.c tool <---
+
+
+March 11 2005, Jens Axboe <axboe@suse.de>
diff --git a/Documentation/cciss.txt b/Documentation/cciss.txt
index d599beb9df8a..c8f9a73111da 100644
--- a/Documentation/cciss.txt
+++ b/Documentation/cciss.txt
@@ -17,6 +17,7 @@ This driver is known to work with the following cards:
* SA P600
* SA P800
* SA E400
+ * SA E300
If nodes are not already created in the /dev/cciss directory, run as root:
diff --git a/Documentation/cdrom/sbpcd b/Documentation/cdrom/sbpcd
index d1825dffca34..b3ba63f4ce3e 100644
--- a/Documentation/cdrom/sbpcd
+++ b/Documentation/cdrom/sbpcd
@@ -419,6 +419,7 @@ into the file "track01":
*/
#include <stdio.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
#include <linux/cdrom.h>
static struct cdrom_tochdr hdr;
@@ -429,7 +430,7 @@ static int datafile, drive;
static int i, j, limit, track, err;
static char filename[32];
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
/*
* open /dev/cdrom
@@ -516,6 +517,7 @@ entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300;
}
arg.addr.lba++;
}
+ return 0;
}
/*===================== end program ========================================*/
@@ -564,15 +566,16 @@ Appendix -- the "cdtester" utility:
#include <stdio.h>
#include <malloc.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
#include <linux/cdrom.h>
#ifdef AZT_PRIVATE_IOCTLS
#include <linux/../../drivers/cdrom/aztcd.h>
-#endif AZT_PRIVATE_IOCTLS
+#endif /* AZT_PRIVATE_IOCTLS */
#ifdef SBP_PRIVATE_IOCTLS
#include <linux/../../drivers/cdrom/sbpcd.h>
#include <linux/fs.h>
-#endif SBP_PRIVATE_IOCTLS
+#endif /* SBP_PRIVATE_IOCTLS */
struct cdrom_tochdr hdr;
struct cdrom_tochdr tocHdr;
@@ -590,7 +593,7 @@ union
struct cdrom_msf msf;
unsigned char buf[CD_FRAMESIZE_RAW];
} azt;
-#endif AZT_PRIVATE_IOCTLS
+#endif /* AZT_PRIVATE_IOCTLS */
int i, i1, i2, i3, j, k;
unsigned char sequence=0;
unsigned char command[80];
@@ -738,7 +741,7 @@ void display(int size,unsigned char *buffer)
}
}
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
{
printf("\nTesting tool for a CDROM driver's audio functions V0.1\n");
printf("(C) 1995 Eberhard Moenkeberg <emoenke@gwdg.de>\n");
@@ -1046,12 +1049,13 @@ main(int argc, char *argv[])
rc=ioctl(drive,CDROMAUDIOBUFSIZ,j);
printf("%d frames granted.\n",rc);
break;
-#endif SBP_PRIVATE_IOCTLS
+#endif /* SBP_PRIVATE_IOCTLS */
default:
printf("unknown command: \"%s\".\n",command);
break;
}
}
+ return 0;
}
/*==========================================================================*/
diff --git a/Documentation/cpu-freq/governors.txt b/Documentation/cpu-freq/governors.txt
index b85481acd0ca..933fae74c337 100644
--- a/Documentation/cpu-freq/governors.txt
+++ b/Documentation/cpu-freq/governors.txt
@@ -9,6 +9,7 @@
Dominik Brodowski <linux@brodo.de>
+ some additions and corrections by Nico Golde <nico@ngolde.de>
@@ -25,6 +26,7 @@ Contents:
2.1 Performance
2.2 Powersave
2.3 Userspace
+2.4 Ondemand
3. The Governor Interface in the CPUfreq Core
@@ -86,7 +88,7 @@ highest frequency within the borders of scaling_min_freq and
scaling_max_freq.
-2.1 Powersave
+2.2 Powersave
-------------
The CPUfreq governor "powersave" sets the CPU statically to the
@@ -94,7 +96,7 @@ lowest frequency within the borders of scaling_min_freq and
scaling_max_freq.
-2.2 Userspace
+2.3 Userspace
-------------
The CPUfreq governor "userspace" allows the user, or any userspace
@@ -103,6 +105,14 @@ by making a sysfs file "scaling_setspeed" available in the CPU-device
directory.
+2.4 Ondemand
+------------
+
+The CPUfreq govenor "ondemand" sets the CPU depending on the
+current usage. To do this the CPU must have the capability to
+switch the frequency very fast.
+
+
3. The Governor Interface in the CPUfreq Core
=============================================
diff --git a/Documentation/cpusets.txt b/Documentation/cpusets.txt
index 2f8f24eaefd9..ad944c060312 100644
--- a/Documentation/cpusets.txt
+++ b/Documentation/cpusets.txt
@@ -51,6 +51,14 @@ mems_allowed vector.
If a cpuset is cpu or mem exclusive, no other cpuset, other than a direct
ancestor or descendent, may share any of the same CPUs or Memory Nodes.
+A cpuset that is cpu exclusive has a sched domain associated with it.
+The sched domain consists of all cpus in the current cpuset that are not
+part of any exclusive child cpusets.
+This ensures that the scheduler load balacing code only balances
+against the cpus that are in the sched domain as defined above and not
+all of the cpus in the system. This removes any overhead due to
+load balancing code trying to pull tasks outside of the cpu exclusive
+cpuset only to be prevented by the tasks' cpus_allowed mask.
User level code may create and destroy cpusets by name in the cpuset
virtual file system, manage the attributes and permissions of these
@@ -84,6 +92,9 @@ This can be especially valuable on:
and a database), or
* NUMA systems running large HPC applications with demanding
performance characteristics.
+ * Also cpu_exclusive cpusets are useful for servers running orthogonal
+ workloads such as RT applications requiring low latency and HPC
+ applications that are throughput sensitive
These subsets, or "soft partitions" must be able to be dynamically
adjusted, as the job mix changes, without impacting other concurrently
@@ -125,6 +136,8 @@ Cpusets extends these two mechanisms as follows:
- A cpuset may be marked exclusive, which ensures that no other
cpuset (except direct ancestors and descendents) may contain
any overlapping CPUs or Memory Nodes.
+ Also a cpu_exclusive cpuset would be associated with a sched
+ domain.
- You can list all the tasks (by pid) attached to any cpuset.
The implementation of cpusets requires a few, simple hooks
@@ -136,6 +149,9 @@ into the rest of the kernel, none in performance critical paths:
allowed in that tasks cpuset.
- in sched.c migrate_all_tasks(), to keep migrating tasks within
the CPUs allowed by their cpuset, if possible.
+ - in sched.c, a new API partition_sched_domains for handling
+ sched domain changes associated with cpu_exclusive cpusets
+ and related changes in both sched.c and arch/ia64/kernel/domain.c
- in the mbind and set_mempolicy system calls, to mask the requested
Memory Nodes by what's allowed in that tasks cpuset.
- in page_alloc, to restrict memory to allowed nodes.
diff --git a/Documentation/devices.txt b/Documentation/devices.txt
index bb67cf25010e..0f515175c72a 100644
--- a/Documentation/devices.txt
+++ b/Documentation/devices.txt
@@ -94,6 +94,7 @@ Your cooperation is appreciated.
9 = /dev/urandom Faster, less secure random number gen.
10 = /dev/aio Asyncronous I/O notification interface
11 = /dev/kmsg Writes to this come out as printk's
+ 12 = /dev/oldmem Access to crash dump from kexec kernel
1 block RAM disk
0 = /dev/ram0 First RAM disk
1 = /dev/ram1 Second RAM disk
diff --git a/Documentation/dvb/README.dibusb b/Documentation/dvb/README.dibusb
deleted file mode 100644
index 7a9e958513f3..000000000000
--- a/Documentation/dvb/README.dibusb
+++ /dev/null
@@ -1,285 +0,0 @@
-Documentation for dib3000* frontend drivers and dibusb device driver
-====================================================================
-
-Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de),
-
-dibusb and dib3000mb/mc drivers based on GPL code, which has
-
-Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
-
-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.
-
-
-Supported devices USB1.1
-========================
-
-Produced and reselled by Twinhan:
----------------------------------
-- TwinhanDTV USB-Ter DVB-T Device (VP7041)
- http://www.twinhan.com/product_terrestrial_3.asp
-
-- TwinhanDTV Magic Box (VP7041e)
- http://www.twinhan.com/product_terrestrial_4.asp
-
-- HAMA DVB-T USB device
- http://www.hama.de/portal/articleId*110620/action*2598
-
-- CTS Portable (Chinese Television System) (2)
- http://www.2cts.tv/ctsportable/
-
-- Unknown USB DVB-T device with vendor ID Hyper-Paltek
-
-
-Produced and reselled by KWorld:
---------------------------------
-- KWorld V-Stream XPERT DTV DVB-T USB
- http://www.kworld.com.tw/en/product/DVBT-USB/DVBT-USB.html
-
-- JetWay DTV DVB-T USB
- http://www.jetway.com.tw/evisn/product/lcd-tv/DVT-USB/dtv-usb.htm
-
-- ADSTech Instant TV DVB-T USB
- http://www.adstech.com/products/PTV-333/intro/PTV-333_intro.asp?pid=PTV-333
-
-
-Others:
--------
-- Ultima Electronic/Artec T1 USB TVBOX (AN2135, AN2235, AN2235 with Panasonic Tuner)
- http://82.161.246.249/products-tvbox.html
-
-- Compro Videomate DVB-U2000 - DVB-T USB (2)
- http://www.comprousa.com/products/vmu2000.htm
-
-- Grandtec USB DVB-T
- http://www.grand.com.tw/
-
-- Avermedia AverTV DVBT USB (2)
- http://www.avermedia.com/
-
-- DiBcom USB DVB-T reference device (non-public)
-
-
-Supported devices USB2.0
-========================
-- Twinhan MagicBox II (2)
- http://www.twinhan.com/product_terrestrial_7.asp
-
-- Hanftek UMT-010 (1)
- http://www.globalsources.com/si/6008819757082/ProductDetail/Digital-TV/product_id-100046529
-
-- Typhoon/Yakumo/HAMA DVB-T mobile USB2.0 (1)
- http://www.yakumo.de/produkte/index.php?pid=1&ag=DVB-T
-
-- Artec T1 USB TVBOX (FX2) (2)
-
-- Hauppauge WinTV NOVA-T USB2
- http://www.hauppauge.com/
-
-- KWorld/ADSTech Instant DVB-T USB2.0 (DiB3000M-B)
-
-- DiBcom USB2.0 DVB-T reference device (non-public)
-
-1) It is working almost.
-2) No test reports received yet.
-
-
-0. NEWS:
- 2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
- 2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
- 2005-01-31 - distorted streaming is finally gone for USB1.1 devices
- 2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
- - first almost working version for HanfTek UMT-010
- - found out, that Yakumo/HAMA/Typhoon are predessors of the HanfTek UMT-010
- 2005-01-10 - refactoring completed, now everything is very delightful
- - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
- Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
- 2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
- 2004-12-26 - refactored the dibusb-driver, splitted into separate files
- - i2c-probing enabled
- 2004-12-06 - possibility for demod i2c-address probing
- - new usb IDs (Compro,Artec)
- 2004-11-23 - merged changes from DiB3000MC_ver2.1
- - revised the debugging
- - possibility to deliver the complete TS for USB2.0
- 2004-11-21 - first working version of the dib3000mc/p frontend driver.
- 2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
- 2004-11-07 - added remote control support. Thanks to David Matthews.
- 2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
- - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
- - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
- better settled there (added xfer_ops-struct)
- - created a common files for frontends (mc/p/mb)
- 2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
- 2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
- to Amaury Demol for reporting
- - changed usb TS transfer method (several urbs, stopping transfer
- before setting a new pid)
- 2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
- to Christian Motschke for reporting
- 2004-09-05 - released the dibusb device and dib3000mb-frontend driver
-
- (old news for vp7041.c)
- 2004-07-15 - found out, by accident, that the device has a TUA6010XS for
- PLL
- 2004-07-12 - figured out, that the driver should also work with the
- CTS Portable (Chinese Television System)
- 2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working
- properly with firmware extracted from 2.422
- - #if for 2.6.4 (dvb), compile issue
- - changed firmware handling, see vp7041.txt sec 1.1
- 2004-07-02 - some tuner modifications, v0.1, cleanups, first public
- 2004-06-28 - now using the dvb_dmx_swfilter_packets, everything
- runs fine now
- 2004-06-27 - able to watch and switching channels (pre-alpha)
- - no section filtering yet
- 2004-06-06 - first TS received, but kernel oops :/
- 2004-05-14 - firmware loader is working
- 2004-05-11 - start writing the driver
-
-1. How to use?
-NOTE: This driver was developed using Linux 2.6.6.,
-it is working with 2.6.7 and above.
-
-Linux 2.4.x support is not planned, but patches are very welcome.
-
-NOTE: I'm using Debian testing, so the following explaination (especially
-the hotplug-path) needn't match your system, but probably it will :).
-
-The driver is included in the kernel since Linux 2.6.10.
-
-1.1. Firmware
-
-The USB driver needs to download a firmware to start working.
-
-You can either use "get_dvb_firmware dibusb" to download the firmware or you
-can get it directly via
-
-for USB1.1 (AN2135)
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-5.0.0.11.fw
-
-for USB1.1 (AN2235) (a few Artec T1 devices)
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
-
-for USB2.0 (FX2) Hauppauge, DiBcom
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-6.0.0.5.fw
-
-for USB2.0 ADSTech/Kworld USB2.0
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-adstech-usb2-1.fw
-
-for USB2.0 HanfTek
-http://www.linuxtv.org/downloads/firmware/dvb-dibusb-an2235-1.fw
-
-
-1.2. Compiling
-
-Since the driver is in the linux kernel, activating the driver in
-your favorite config-environment should sufficient. I recommend
-to compile the driver as module. Hotplug does the rest.
-
-1.3. Loading the drivers
-
-Hotplug is able to load the driver, when it is needed (because you plugged
-in the device).
-
-If you want to enable debug output, you have to load the driver manually and
-from withing the dvb-kernel cvs repository.
-
-first have a look, which debug level are available:
-
-modinfo dib3000mb
-modinfo dib3000-common
-modinfo dib3000mc
-modinfo dvb-dibusb
-
-modprobe dib3000-common debug=<level>
-modprobe dib3000mb debug=<level>
-modprobe dib3000mc debug=<level>
-modprobe dvb-dibusb debug=<level>
-
-should do the trick.
-
-When the driver is loaded successfully, the firmware file was in
-the right place and the device is connected, the "Power"-LED should be
-turned on.
-
-At this point you should be able to start a dvb-capable application. For myself
-I used mplayer, dvbscan, tzap and kaxtv, they are working. Using the device
-in vdr is working now also.
-
-2. Known problems and bugs
-
-- Don't remove the USB device while running an DVB application, your system will die.
-
-2.1. Adding support for devices
-
-It is not possible to determine the range of devices based on the DiBcom
-reference designs. This is because the reference design of DiBcom can be sold
-to thirds, without telling DiBcom (so done with the Twinhan VP7041 and
-the HAMA device).
-
-When you think you have a device like this and the driver does not recognizes it,
-please send the ****load*.inf and the ****cap*.inf of the Windows driver to me.
-
-Sometimes the Vendor or Product ID is identical to the ones of Twinhan, even
-though it is not a Twinhan device (e.g. HAMA), then please send me the name
-of the device. I will add it to this list in order to make this clear to
-others.
-
-If you are familar with C you can also add the VID and PID of the device to
-the dvb-dibusb-core.c-file and create a patch and send it over to me or to
-the linux-dvb mailing list, _after_ you have tried compiling and modprobing
-it.
-
-2.2. USB1.1 Bandwidth limitation
-
-Most of the currently supported devices are USB1.1 and thus they have a
-maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
-This is not enough for receiving the complete transport stream of a
-DVB-T channel (which can be about 16 MBit/s). Normally this is not a
-problem, if you only want to watch TV (this does not apply for HDTV),
-but watching a channel while recording another channel on the same
-frequency simply does not work very well. This applies to all USB1.1
-DVB-T devices, not just dibusb)
-
-Update: For the USB1.1 and VDR some work has been done (patches and comments
-are still very welcome). Maybe the problem is solved in the meantime because I
-now use the dmx_sw_filter function instead of dmx_sw_filter_packet. I hope the
-linux-dvb software filter is able to get the best of the garbled TS.
-
-The bug, where the TS is distorted by a heavy usage of the device is gone
-definitely. All dibusb-devices I was using (Twinhan, Kworld, DiBcom) are
-working like charm now with VDR. Sometimes I even was able to record a channel
-and watch another one.
-
-2.3. Comments
-
-Patches, comments and suggestions are very very welcome.
-
-3. Acknowledgements
- Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
- providing specs, code and help, on which the dvb-dibusb, dib3000mb and
- dib3000mc are based.
-
- David Matthews for identifying a new device type (Artec T1 with AN2235)
- and for extending dibusb with remote control event handling. Thank you.
-
- Alex Woods for frequently answering question about usb and dvb
- stuff, a big thank you.
-
- Bernd Wagner for helping with huge bug reports and discussions.
-
- Gunnar Wittich and Joachim von Caron for their trust for giving me
- root-shells on their machines to implement support for new devices.
-
- Some guys on the linux-dvb mailing list for encouraging me
-
- Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
- user-level firmware loader, which saves a lot of time
- (when writing the vp7041 driver)
-
- Ulf Hermenau for helping me out with traditional chinese.
-
- André Smoktun and Christian Frömmel for supporting me with
- hardware and listening to my problems very patient
diff --git a/Documentation/dvb/README.dvb-usb b/Documentation/dvb/README.dvb-usb
new file mode 100644
index 000000000000..ac0797ea646c
--- /dev/null
+++ b/Documentation/dvb/README.dvb-usb
@@ -0,0 +1,232 @@
+Documentation for dvb-usb-framework module and its devices
+
+Idea behind the dvb-usb-framework
+=================================
+
+In March 2005 I got the new Twinhan USB2.0 DVB-T device. They provided specs and a firmware.
+
+Quite keen I wanted to put the driver (with some quirks of course) into dibusb.
+After reading some specs and doing some USB snooping, it realized, that the
+dibusb-driver would be a complete mess afterwards. So I decided to do it in a
+different way: With the help of a dvb-usb-framework.
+
+The framework provides generic functions (mostly kernel API calls), such as:
+
+- Transport Stream URB handling in conjunction with dvb-demux-feed-control
+ (bulk and isoc are supported)
+- registering the device for the DVB-API
+- registering an I2C-adapter if applicable
+- remote-control/input-device handling
+- firmware requesting and loading (currently just for the Cypress USB
+ controllers)
+- other functions/methods which can be shared by several drivers (such as
+ functions for bulk-control-commands)
+- TODO: a I2C-chunker. It creates device-specific chunks of register-accesses
+ depending on length of a register and the number of values that can be
+ multi-written and multi-read.
+
+The source code of the particular DVB USB devices does just the communication
+with the device via the bus. The connection between the DVB-API-functionality
+is done via callbacks, assigned in a static device-description (struct
+dvb_usb_device) each device-driver has to have.
+
+For an example have a look in drivers/media/dvb/dvb-usb/vp7045*.
+
+Objective is to migrate all the usb-devices (dibusb, cinergyT2, maybe the
+ttusb; flexcop-usb already benefits from the generic flexcop-device) to use
+the dvb-usb-lib.
+
+TODO: dynamic enabling and disabling of the pid-filter in regard to number of
+feeds requested.
+
+Supported devices
+========================
+
+See the LinuxTV DVB Wiki at www.linuxtv.org for a complete list of
+cards/drivers/firmwares:
+
+http://www.linuxtv.org/wiki/index.php/DVB_USB
+
+0. History & News:
+ 2005-06-30 - added support for WideView WT-220U (Thanks to Steve Chang)
+ 2005-05-30 - added basic isochronous support to the dvb-usb-framework
+ added support for Conexant Hybrid reference design and Nebula DigiTV USB
+ 2005-04-17 - all dibusb devices ported to make use of the dvb-usb-framework
+ 2005-04-02 - re-enabled and improved remote control code.
+ 2005-03-31 - ported the Yakumo/Hama/Typhoon DVB-T USB2.0 device to dvb-usb.
+ 2005-03-30 - first commit of the dvb-usb-module based on the dibusb-source. First device is a new driver for the
+ TwinhanDTV Alpha / MagicBox II USB2.0-only DVB-T device.
+
+ (change from dvb-dibusb to dvb-usb)
+ 2005-03-28 - added support for the AVerMedia AverTV DVB-T USB2.0 device (Thanks to Glen Harris and Jiun-Kuei Jung, AVerMedia)
+ 2005-03-14 - added support for the Typhoon/Yakumo/HAMA DVB-T mobile USB2.0
+ 2005-02-11 - added support for the KWorld/ADSTech Instant DVB-T USB2.0. Thanks a lot to Joachim von Caron
+ 2005-02-02 - added support for the Hauppauge Win-TV Nova-T USB2
+ 2005-01-31 - distorted streaming is gone for USB1.1 devices
+ 2005-01-13 - moved the mirrored pid_filter_table back to dvb-dibusb
+ - first almost working version for HanfTek UMT-010
+ - found out, that Yakumo/HAMA/Typhoon are predecessors of the HanfTek UMT-010
+ 2005-01-10 - refactoring completed, now everything is very delightful
+ - tuner quirks for some weird devices (Artec T1 AN2235 device has sometimes a
+ Panasonic Tuner assembled). Tunerprobing implemented. Thanks a lot to Gunnar Wittich.
+ 2004-12-29 - after several days of struggling around bug of no returning URBs fixed.
+ 2004-12-26 - refactored the dibusb-driver, splitted into separate files
+ - i2c-probing enabled
+ 2004-12-06 - possibility for demod i2c-address probing
+ - new usb IDs (Compro, Artec)
+ 2004-11-23 - merged changes from DiB3000MC_ver2.1
+ - revised the debugging
+ - possibility to deliver the complete TS for USB2.0
+ 2004-11-21 - first working version of the dib3000mc/p frontend driver.
+ 2004-11-12 - added additional remote control keys. Thanks to Uwe Hanke.
+ 2004-11-07 - added remote control support. Thanks to David Matthews.
+ 2004-11-05 - added support for a new devices (Grandtec/Avermedia/Artec)
+ - merged my changes (for dib3000mb/dibusb) to the FE_REFACTORING, because it became HEAD
+ - moved transfer control (pid filter, fifo control) from usb driver to frontend, it seems
+ better settled there (added xfer_ops-struct)
+ - created a common files for frontends (mc/p/mb)
+ 2004-09-28 - added support for a new device (Unkown, vendor ID is Hyper-Paltek)
+ 2004-09-20 - added support for a new device (Compro DVB-U2000), thanks
+ to Amaury Demol for reporting
+ - changed usb TS transfer method (several urbs, stopping transfer
+ before setting a new pid)
+ 2004-09-13 - added support for a new device (Artec T1 USB TVBOX), thanks
+ to Christian Motschke for reporting
+ 2004-09-05 - released the dibusb device and dib3000mb-frontend driver
+
+ (old news for vp7041.c)
+ 2004-07-15 - found out, by accident, that the device has a TUA6010XS for
+ PLL
+ 2004-07-12 - figured out, that the driver should also work with the
+ CTS Portable (Chinese Television System)
+ 2004-07-08 - firmware-extraction-2.422-problem solved, driver is now working
+ properly with firmware extracted from 2.422
+ - #if for 2.6.4 (dvb), compile issue
+ - changed firmware handling, see vp7041.txt sec 1.1
+ 2004-07-02 - some tuner modifications, v0.1, cleanups, first public
+ 2004-06-28 - now using the dvb_dmx_swfilter_packets, everything
+ runs fine now
+ 2004-06-27 - able to watch and switching channels (pre-alpha)
+ - no section filtering yet
+ 2004-06-06 - first TS received, but kernel oops :/
+ 2004-05-14 - firmware loader is working
+ 2004-05-11 - start writing the driver
+
+1. How to use?
+1.1. Firmware
+
+Most of the USB drivers need to download a firmware to the device before start
+working.
+
+Have a look at the Wikipage for the DVB-USB-drivers to find out, which firmware
+you need for your device:
+
+http://www.linuxtv.org/wiki/index.php/DVB_USB
+
+1.2. Compiling
+
+Since the driver is in the linux kernel, activating the driver in
+your favorite config-environment should sufficient. I recommend
+to compile the driver as module. Hotplug does the rest.
+
+If you use dvb-kernel enter the build-2.6 directory run 'make' and 'insmod.sh
+load' afterwards.
+
+1.3. Loading the drivers
+
+Hotplug is able to load the driver, when it is needed (because you plugged
+in the device).
+
+If you want to enable debug output, you have to load the driver manually and
+from withing the dvb-kernel cvs repository.
+
+first have a look, which debug level are available:
+
+modinfo dvb-usb
+modinfo dvb-usb-vp7045
+etc.
+
+modprobe dvb-usb debug=<level>
+modprobe dvb-usb-vp7045 debug=<level>
+etc.
+
+should do the trick.
+
+When the driver is loaded successfully, the firmware file was in
+the right place and the device is connected, the "Power"-LED should be
+turned on.
+
+At this point you should be able to start a dvb-capable application. I'm use
+(t|s)zap, mplayer and dvbscan to test the basics. VDR-xine provides the
+long-term test scenario.
+
+2. Known problems and bugs
+
+- Don't remove the USB device while running an DVB application, your system
+ will go crazy or die most likely.
+
+2.1. Adding support for devices
+
+TODO
+
+2.2. USB1.1 Bandwidth limitation
+
+A lot of the currently supported devices are USB1.1 and thus they have a
+maximum bandwidth of about 5-6 MBit/s when connected to a USB2.0 hub.
+This is not enough for receiving the complete transport stream of a
+DVB-T channel (which is about 16 MBit/s). Normally this is not a
+problem, if you only want to watch TV (this does not apply for HDTV),
+but watching a channel while recording another channel on the same
+frequency simply does not work very well. This applies to all USB1.1
+DVB-T devices, not just the dvb-usb-devices)
+
+The bug, where the TS is distorted by a heavy usage of the device is gone
+definitely. All dvb-usb-devices I was using (Twinhan, Kworld, DiBcom) are
+working like charm now with VDR. Sometimes I even was able to record a channel
+and watch another one.
+
+2.3. Comments
+
+Patches, comments and suggestions are very very welcome.
+
+3. Acknowledgements
+ Amaury Demol (ademol@dibcom.fr) and Francois Kanounnikoff from DiBcom for
+ providing specs, code and help, on which the dvb-dibusb, dib3000mb and
+ dib3000mc are based.
+
+ David Matthews for identifying a new device type (Artec T1 with AN2235)
+ and for extending dibusb with remote control event handling. Thank you.
+
+ Alex Woods for frequently answering question about usb and dvb
+ stuff, a big thank you.
+
+ Bernd Wagner for helping with huge bug reports and discussions.
+
+ Gunnar Wittich and Joachim von Caron for their trust for providing
+ root-shells on their machines to implement support for new devices.
+
+ Allan Third and Michael Hutchinson for their help to write the Nebula
+ digitv-driver.
+
+ Glen Harris for bringing up, that there is a new dibusb-device and Jiun-Kuei
+ Jung from AVerMedia who kindly provided a special firmware to get the device
+ up and running in Linux.
+
+ Jennifer Chen, Jeff and Jack from Twinhan for kindly supporting by
+ writing the vp7045-driver.
+
+ Steve Chang from WideView for providing information for new devices and
+ firmware files.
+
+ Michael Paxton for submitting remote control keymaps.
+
+ Some guys on the linux-dvb mailing list for encouraging me.
+
+ Peter Schildmann >peter.schildmann-nospam-at-web.de< for his
+ user-level firmware loader, which saves a lot of time
+ (when writing the vp7041 driver)
+
+ Ulf Hermenau for helping me out with traditional chinese.
+
+ André Smoktun and Christian Frömmel for supporting me with
+ hardware and listening to my problems very patiently.
diff --git a/Documentation/dvb/bt8xx.txt b/Documentation/dvb/bt8xx.txt
index d64430bf4bb6..e6b8d05bc08d 100644
--- a/Documentation/dvb/bt8xx.txt
+++ b/Documentation/dvb/bt8xx.txt
@@ -1,69 +1,55 @@
-How to get the Nebula, PCTV and Twinhan DST cards working
-=========================================================
+How to get the Nebula Electronics DigiTV, Pinnacle PCTV Sat, Twinhan DST + clones working
+=========================================================================================
-This class of cards has a bt878a as the PCI interface, and
-require the bttv driver.
+1) General information
+======================
-Please pay close attention to the warning about the bttv module
-options below for the DST card.
+This class of cards has a bt878a chip as the PCI interface.
+The different card drivers require the bttv driver to provide the means
+to access the i2c bus and the gpio pins of the bt8xx chipset.
-1) General informations
-=======================
+2) Compilation rules for Kernel >= 2.6.12
+=========================================
-These drivers require the bttv driver to provide the means to access
-the i2c bus and the gpio pins of the bt8xx chipset.
+Enable the following options:
-Because of this, you need to enable
"Device drivers" => "Multimedia devices"
- => "Video For Linux" => "BT848 Video For Linux"
-
-Furthermore you need to enable
+ => "Video For Linux" => "BT848 Video For Linux"
"Device drivers" => "Multimedia devices" => "Digital Video Broadcasting Devices"
- => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
+ => "DVB for Linux" "DVB Core Support" "Nebula/Pinnacle PCTV/TwinHan PCI Cards"
-2) Loading Modules
-==================
+3) Loading Modules, described by two approaches
+===============================================
In general you need to load the bttv driver, which will handle the gpio and
-i2c communication for us, plus the common dvb-bt8xx device driver.
-The frontends for Nebula (nxt6000), Pinnacle PCTV (cx24110) and
-TwinHan (dst) are loaded automatically by the dvb-bt8xx device driver.
+i2c communication for us, plus the common dvb-bt8xx device driver,
+which is called the backend.
+The frontends for Nebula DigiTV (nxt6000), Pinnacle PCTV Sat (cx24110),
+TwinHan DST + clones (dst and dst-ca) are loaded automatically by the backend.
+For further details about TwinHan DST + clones see /Documentation/dvb/ci.txt.
-3a) Nebula / Pinnacle PCTV
---------------------------
+3a) The manual approach
+-----------------------
- $ modprobe bttv (normally bttv is being loaded automatically by kmod)
- $ modprobe dvb-bt8xx (or just place dvb-bt8xx in /etc/modules for automatic loading)
+Loading modules:
+modprobe bttv
+modprobe dvb-bt8xx
+Unloading modules:
+modprobe -r dvb-bt8xx
+modprobe -r bttv
-3b) TwinHan and Clones
+3b) The automatic approach
--------------------------
- $ modprobe bttv i2c_hw=1 card=0x71
- $ modprobe dvb-bt8xx
- $ modprobe dst
-
-The value 0x71 will override the PCI type detection for dvb-bt8xx,
-which is necessary for TwinHan cards.
-
-If you're having an older card (blue color circuit) and card=0x71 locks
-your machine, try using 0x68, too. If that does not work, ask on the
-mailing list.
-
-The DST module takes a couple of useful parameters.
-
-verbose takes values 0 to 5. These values control the verbosity level.
-
-debug takes values 0 and 1. You can either disable or enable debugging.
-
-dst_addons takes values 0 and 0x20. A value of 0 means it is a FTA card.
-0x20 means it has a Conditional Access slot.
-
-The autodected values are determined bythe cards 'response
-string' which you can see in your logs e.g.
+If not already done by installation, place a line either in
+/etc/modules.conf or in /etc/modprobe.conf containing this text:
+alias char-major-81 bttv
-dst_get_device_id: Recognise [DSTMCI]
+Then place a line in /etc/modules containing this text:
+dvb-bt8xx
+Reboot your system and have fun!
--
-Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham
+Authors: Richard Walker, Jamie Honan, Michael Hunold, Manu Abraham, Uwe Bugla
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index 77511af45362..12dde43fe657 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -43,6 +43,14 @@ Who: Randy Dunlap <rddunlap@osdl.org>
---------------------------
+What: RAW driver (CONFIG_RAW_DRIVER)
+When: December 2005
+Why: declared obsolete since kernel 2.6.3
+ O_DIRECT can be used instead
+Who: Adrian Bunk <bunk@stusta.de>
+
+---------------------------
+
What: register_ioctl32_conversion() / unregister_ioctl32_conversion()
When: April 2005
Why: Replaced by ->compat_ioctl in file_operations and other method
@@ -111,3 +119,19 @@ Why: Match the other drivers' name for the same function, duplicate names
will be available until removal of old names.
Who: Grant Coady <gcoady@gmail.com>
+---------------------------
+
+What: PCMCIA control ioctl (needed for pcmcia-cs [cardmgr, cardctl])
+When: November 2005
+Files: drivers/pcmcia/: pcmcia_ioctl.c
+Why: With the 16-bit PCMCIA subsystem now behaving (almost) like a
+ normal hotpluggable bus, and with it using the default kernel
+ infrastructure (hotplug, driver core, sysfs) keeping the PCMCIA
+ control ioctl needed by cardmgr and cardctl from pcmcia-cs is
+ unnecessary, and makes further cleanups and integration of the
+ PCMCIA subsystem into the Linux kernel device driver model more
+ difficult. The features provided by cardmgr and cardctl are either
+ handled by the kernel itself now or are available in the new
+ pcmciautils package available at
+ http://kernel.org/pub/linux/utils/kernel/pcmcia/
+Who: Dominik Brodowski <linux@brodo.de>
diff --git a/Documentation/filesystems/ext2.txt b/Documentation/filesystems/ext2.txt
index b5cb9110cc6b..d16334ec48ba 100644
--- a/Documentation/filesystems/ext2.txt
+++ b/Documentation/filesystems/ext2.txt
@@ -58,6 +58,8 @@ noacl Don't support POSIX ACLs.
nobh Do not attach buffer_heads to file pagecache.
+xip Use execute in place (no caching) if possible
+
grpquota,noquota,quota,usrquota Quota options are silently ignored by ext2.
diff --git a/Documentation/filesystems/inotify.txt b/Documentation/filesystems/inotify.txt
new file mode 100644
index 000000000000..2c716041f578
--- /dev/null
+++ b/Documentation/filesystems/inotify.txt
@@ -0,0 +1,138 @@
+ inotify
+ a powerful yet simple file change notification system
+
+
+
+Document started 15 Mar 2005 by Robert Love <rml@novell.com>
+
+(i) User Interface
+
+Inotify is controlled by a set of three sys calls
+
+First step in using inotify is to initialise an inotify instance
+
+ int fd = inotify_init ();
+
+Change events are managed by "watches". A watch is an (object,mask) pair where
+the object is a file or directory and the mask is a bit mask of one or more
+inotify events that the application wishes to receive. See <linux/inotify.h>
+for valid events. A watch is referenced by a watch descriptor, or wd.
+
+Watches are added via a path to the file.
+
+Watches on a directory will return events on any files inside of the directory.
+
+Adding a watch is simple,
+
+ int wd = inotify_add_watch (fd, path, mask);
+
+You can add a large number of files via something like
+
+ for each file to watch {
+ int wd = inotify_add_watch (fd, file, mask);
+ }
+
+You can update an existing watch in the same manner, by passing in a new mask.
+
+An existing watch is removed via the INOTIFY_IGNORE ioctl, for example
+
+ inotify_rm_watch (fd, wd);
+
+Events are provided in the form of an inotify_event structure that is read(2)
+from a inotify instance fd. The filename is of dynamic length and follows the
+struct. It is of size len. The filename is padded with null bytes to ensure
+proper alignment. This padding is reflected in len.
+
+You can slurp multiple events by passing a large buffer, for example
+
+ size_t len = read (fd, buf, BUF_LEN);
+
+Will return as many events as are available and fit in BUF_LEN.
+
+each inotify instance fd is also select()- and poll()-able.
+
+You can find the size of the current event queue via the FIONREAD ioctl.
+
+All watches are destroyed and cleaned up on close.
+
+
+(ii) Internal Kernel Implementation
+
+Each open inotify instance is associated with an inotify_device structure.
+
+Each watch is associated with an inotify_watch structure. Watches are chained
+off of each associated device and each associated inode.
+
+See fs/inotify.c for the locking and lifetime rules.
+
+
+(iii) Rationale
+
+Q: What is the design decision behind not tying the watch to the open fd of
+ the watched object?
+
+A: Watches are associated with an open inotify device, not an open file.
+ This solves the primary problem with dnotify: keeping the file open pins
+ the file and thus, worse, pins the mount. Dnotify is therefore infeasible
+ for use on a desktop system with removable media as the media cannot be
+ unmounted.
+
+Q: What is the design decision behind using an-fd-per-device as opposed to
+ an fd-per-watch?
+
+A: An fd-per-watch quickly consumes more file descriptors than are allowed,
+ more fd's than are feasible to manage, and more fd's than are optimally
+ select()-able. Yes, root can bump the per-process fd limit and yes, users
+ can use epoll, but requiring both is a silly and extraneous requirement.
+ A watch consumes less memory than an open file, separating the number
+ spaces is thus sensible. The current design is what user-space developers
+ want: Users initialize inotify, once, and add n watches, requiring but one fd
+ and no twiddling with fd limits. Initializing an inotify instance two
+ thousand times is silly. If we can implement user-space's preferences
+ cleanly--and we can, the idr layer makes stuff like this trivial--then we
+ should.
+
+ There are other good arguments. With a single fd, there is a single
+ item to block on, which is mapped to a single queue of events. The single
+ fd returns all watch events and also any potential out-of-band data. If
+ every fd was a separate watch,
+
+ - There would be no way to get event ordering. Events on file foo and
+ file bar would pop poll() on both fd's, but there would be no way to tell
+ which happened first. A single queue trivially gives you ordering. Such
+ ordering is crucial to existing applications such as Beagle. Imagine
+ "mv a b ; mv b a" events without ordering.
+
+ - We'd have to maintain n fd's and n internal queues with state,
+ versus just one. It is a lot messier in the kernel. A single, linear
+ queue is the data structure that makes sense.
+
+ - User-space developers prefer the current API. The Beagle guys, for
+ example, love it. Trust me, I asked. It is not a surprise: Who'd want
+ to manage and block on 1000 fd's via select?
+
+ - You'd have to manage the fd's, as an example: Call close() when you
+ received a delete event.
+
+ - No way to get out of band data.
+
+ - 1024 is still too low. ;-)
+
+ When you talk about designing a file change notification system that
+ scales to 1000s of directories, juggling 1000s of fd's just does not seem
+ the right interface. It is too heavy.
+
+Q: Why the system call approach?
+
+A: The poor user-space interface is the second biggest problem with dnotify.
+ Signals are a terrible, terrible interface for file notification. Or for
+ anything, for that matter. The ideal solution, from all perspectives, is a
+ file descriptor-based one that allows basic file I/O and poll/select.
+ Obtaining the fd and managing the watches could have been done either via a
+ device file or a family of new system calls. We decided to implement a
+ family of system calls because that is the preffered approach for new kernel
+ features and it means our user interface requirements.
+
+ Additionally, it _is_ possible to more than one instance and
+ juggle more than one queue and thus more than one associated fd.
+
diff --git a/Documentation/filesystems/xip.txt b/Documentation/filesystems/xip.txt
new file mode 100644
index 000000000000..6c0cef10eb4d
--- /dev/null
+++ b/Documentation/filesystems/xip.txt
@@ -0,0 +1,67 @@
+Execute-in-place for file mappings
+----------------------------------
+
+Motivation
+----------
+File mappings are performed by mapping page cache pages to userspace. In
+addition, read&write type file operations also transfer data from/to the page
+cache.
+
+For memory backed storage devices that use the block device interface, the page
+cache pages are in fact copies of the original storage. Various approaches
+exist to work around the need for an extra copy. The ramdisk driver for example
+does read the data into the page cache, keeps a reference, and discards the
+original data behind later on.
+
+Execute-in-place solves this issue the other way around: instead of keeping
+data in the page cache, the need to have a page cache copy is eliminated
+completely. With execute-in-place, read&write type operations are performed
+directly from/to the memory backed storage device. For file mappings, the
+storage device itself is mapped directly into userspace.
+
+This implementation was initialy written for shared memory segments between
+different virtual machines on s390 hardware to allow multiple machines to
+share the same binaries and libraries.
+
+Implementation
+--------------
+Execute-in-place is implemented in three steps: block device operation,
+address space operation, and file operations.
+
+A block device operation named direct_access is used to retrieve a
+reference (pointer) to a block on-disk. The reference is supposed to be
+cpu-addressable, physical address and remain valid until the release operation
+is performed. A struct block_device reference is used to address the device,
+and a sector_t argument is used to identify the individual block. As an
+alternative, memory technology devices can be used for this.
+
+The block device operation is optional, these block devices support it as of
+today:
+- dcssblk: s390 dcss block device driver
+
+An address space operation named get_xip_page is used to retrieve reference
+to a struct page. To address the target page, a reference to an address_space,
+and a sector number is provided. A 3rd argument indicates whether the
+function should allocate blocks if needed.
+
+This address space operation is mutually exclusive with readpage&writepage that
+do page cache read/write operations.
+The following filesystems support it as of today:
+- ext2: the second extended filesystem, see Documentation/filesystems/ext2.txt
+
+A set of file operations that do utilize get_xip_page can be found in
+mm/filemap_xip.c . The following file operation implementations are provided:
+- aio_read/aio_write
+- readv/writev
+- sendfile
+
+The generic file operations do_sync_read/do_sync_write can be used to implement
+classic synchronous IO calls.
+
+Shortcomings
+------------
+This implementation is limited to storage devices that are cpu addressable at
+all times (no highmem or such). It works well on rom/ram, but enhancements are
+needed to make it work with flash in read+write mode.
+Putting the Linux kernel and/or its modules on a xip filesystem does not mean
+they are not copied.
diff --git a/Documentation/i2c/chips/adm1021 b/Documentation/hwmon/adm1021
index 03d02bfb3df1..03d02bfb3df1 100644
--- a/Documentation/i2c/chips/adm1021
+++ b/Documentation/hwmon/adm1021
diff --git a/Documentation/i2c/chips/adm1025 b/Documentation/hwmon/adm1025
index 39d2b781b5d6..39d2b781b5d6 100644
--- a/Documentation/i2c/chips/adm1025
+++ b/Documentation/hwmon/adm1025
diff --git a/Documentation/i2c/chips/adm1026 b/Documentation/hwmon/adm1026
index 473c689d7924..473c689d7924 100644
--- a/Documentation/i2c/chips/adm1026
+++ b/Documentation/hwmon/adm1026
diff --git a/Documentation/i2c/chips/adm1031 b/Documentation/hwmon/adm1031
index 130a38382b98..130a38382b98 100644
--- a/Documentation/i2c/chips/adm1031
+++ b/Documentation/hwmon/adm1031
diff --git a/Documentation/i2c/chips/adm9240 b/Documentation/hwmon/adm9240
index 35f618f32896..35f618f32896 100644
--- a/Documentation/i2c/chips/adm9240
+++ b/Documentation/hwmon/adm9240
diff --git a/Documentation/i2c/chips/asb100 b/Documentation/hwmon/asb100
index ab7365e139be..ab7365e139be 100644
--- a/Documentation/i2c/chips/asb100
+++ b/Documentation/hwmon/asb100
diff --git a/Documentation/i2c/chips/ds1621 b/Documentation/hwmon/ds1621
index 1fee6f1e6bc5..1fee6f1e6bc5 100644
--- a/Documentation/i2c/chips/ds1621
+++ b/Documentation/hwmon/ds1621
diff --git a/Documentation/i2c/chips/fscher b/Documentation/hwmon/fscher
index 64031659aff3..64031659aff3 100644
--- a/Documentation/i2c/chips/fscher
+++ b/Documentation/hwmon/fscher
diff --git a/Documentation/i2c/chips/gl518sm b/Documentation/hwmon/gl518sm
index ce0881883bca..ce0881883bca 100644
--- a/Documentation/i2c/chips/gl518sm
+++ b/Documentation/hwmon/gl518sm
diff --git a/Documentation/i2c/chips/it87 b/Documentation/hwmon/it87
index 0d0195040d88..0d0195040d88 100644
--- a/Documentation/i2c/chips/it87
+++ b/Documentation/hwmon/it87
diff --git a/Documentation/i2c/chips/lm63 b/Documentation/hwmon/lm63
index 31660bf97979..31660bf97979 100644
--- a/Documentation/i2c/chips/lm63
+++ b/Documentation/hwmon/lm63
diff --git a/Documentation/i2c/chips/lm75 b/Documentation/hwmon/lm75
index 8e6356fe05d7..8e6356fe05d7 100644
--- a/Documentation/i2c/chips/lm75
+++ b/Documentation/hwmon/lm75
diff --git a/Documentation/i2c/chips/lm77 b/Documentation/hwmon/lm77
index 57c3a46d6370..57c3a46d6370 100644
--- a/Documentation/i2c/chips/lm77
+++ b/Documentation/hwmon/lm77
diff --git a/Documentation/i2c/chips/lm78 b/Documentation/hwmon/lm78
index 357086ed7f64..357086ed7f64 100644
--- a/Documentation/i2c/chips/lm78
+++ b/Documentation/hwmon/lm78
diff --git a/Documentation/i2c/chips/lm80 b/Documentation/hwmon/lm80
index cb5b407ba3e6..cb5b407ba3e6 100644
--- a/Documentation/i2c/chips/lm80
+++ b/Documentation/hwmon/lm80
diff --git a/Documentation/i2c/chips/lm83 b/Documentation/hwmon/lm83
index 061d9ed8ff43..061d9ed8ff43 100644
--- a/Documentation/i2c/chips/lm83
+++ b/Documentation/hwmon/lm83
diff --git a/Documentation/i2c/chips/lm85 b/Documentation/hwmon/lm85
index 9549237530cf..9549237530cf 100644
--- a/Documentation/i2c/chips/lm85
+++ b/Documentation/hwmon/lm85
diff --git a/Documentation/i2c/chips/lm87 b/Documentation/hwmon/lm87
index c952c57f0e11..c952c57f0e11 100644
--- a/Documentation/i2c/chips/lm87
+++ b/Documentation/hwmon/lm87
diff --git a/Documentation/i2c/chips/lm90 b/Documentation/hwmon/lm90
index 2c4cf39471f4..2c4cf39471f4 100644
--- a/Documentation/i2c/chips/lm90
+++ b/Documentation/hwmon/lm90
diff --git a/Documentation/i2c/chips/lm92 b/Documentation/hwmon/lm92
index 7705bfaa0708..7705bfaa0708 100644
--- a/Documentation/i2c/chips/lm92
+++ b/Documentation/hwmon/lm92
diff --git a/Documentation/i2c/chips/max1619 b/Documentation/hwmon/max1619
index d6f8d9cd7d7f..d6f8d9cd7d7f 100644
--- a/Documentation/i2c/chips/max1619
+++ b/Documentation/hwmon/max1619
diff --git a/Documentation/i2c/chips/pc87360 b/Documentation/hwmon/pc87360
index 89a8fcfa78df..89a8fcfa78df 100644
--- a/Documentation/i2c/chips/pc87360
+++ b/Documentation/hwmon/pc87360
diff --git a/Documentation/i2c/chips/sis5595 b/Documentation/hwmon/sis5595
index b7ae36b8cdf5..b7ae36b8cdf5 100644
--- a/Documentation/i2c/chips/sis5595
+++ b/Documentation/hwmon/sis5595
diff --git a/Documentation/i2c/chips/smsc47b397 b/Documentation/hwmon/smsc47b397
index da9d80c96432..da9d80c96432 100644
--- a/Documentation/i2c/chips/smsc47b397
+++ b/Documentation/hwmon/smsc47b397
diff --git a/Documentation/i2c/chips/smsc47m1 b/Documentation/hwmon/smsc47m1
index 34e6478c1425..34e6478c1425 100644
--- a/Documentation/i2c/chips/smsc47m1
+++ b/Documentation/hwmon/smsc47m1
diff --git a/Documentation/i2c/sysfs-interface b/Documentation/hwmon/sysfs-interface
index 346400519d0d..346400519d0d 100644
--- a/Documentation/i2c/sysfs-interface
+++ b/Documentation/hwmon/sysfs-interface
diff --git a/Documentation/i2c/userspace-tools b/Documentation/hwmon/userspace-tools
index 2622aac65422..2622aac65422 100644
--- a/Documentation/i2c/userspace-tools
+++ b/Documentation/hwmon/userspace-tools
diff --git a/Documentation/i2c/chips/via686a b/Documentation/hwmon/via686a
index b82014cb7c53..b82014cb7c53 100644
--- a/Documentation/i2c/chips/via686a
+++ b/Documentation/hwmon/via686a
diff --git a/Documentation/i2c/chips/w83627hf b/Documentation/hwmon/w83627hf
index 78f37c2d602e..78f37c2d602e 100644
--- a/Documentation/i2c/chips/w83627hf
+++ b/Documentation/hwmon/w83627hf
diff --git a/Documentation/i2c/chips/w83781d b/Documentation/hwmon/w83781d
index e5459333ba68..e5459333ba68 100644
--- a/Documentation/i2c/chips/w83781d
+++ b/Documentation/hwmon/w83781d
diff --git a/Documentation/i2c/chips/w83l785ts b/Documentation/hwmon/w83l785ts
index 1841cedc25b2..1841cedc25b2 100644
--- a/Documentation/i2c/chips/w83l785ts
+++ b/Documentation/hwmon/w83l785ts
diff --git a/Documentation/i2c/chips/max6875 b/Documentation/i2c/chips/max6875
index b4fb49b41813..b02002898a09 100644
--- a/Documentation/i2c/chips/max6875
+++ b/Documentation/i2c/chips/max6875
@@ -2,10 +2,10 @@ Kernel driver max6875
=====================
Supported chips:
- * Maxim max6874, max6875
- Prefixes: 'max6875'
+ * Maxim MAX6874, MAX6875
+ Prefix: 'max6875'
Addresses scanned: 0x50, 0x52
- Datasheets:
+ Datasheet:
http://pdfserv.maxim-ic.com/en/ds/MAX6874-MAX6875.pdf
Author: Ben Gardner <bgardner@wabtec.com>
@@ -23,14 +23,26 @@ Module Parameters
Description
-----------
-The MAXIM max6875 is a EEPROM-programmable power-supply sequencer/supervisor.
+The Maxim MAX6875 is an EEPROM-programmable power-supply sequencer/supervisor.
It provides timed outputs that can be used as a watchdog, if properly wired.
It also provides 512 bytes of user EEPROM.
-At reset, the max6875 reads the configuration eeprom into its configuration
+At reset, the MAX6875 reads the configuration EEPROM into its configuration
registers. The chip then begins to operate according to the values in the
registers.
+The Maxim MAX6874 is a similar, mostly compatible device, with more intputs
+and outputs:
+
+ vin gpi vout
+MAX6874 6 4 8
+MAX6875 4 3 5
+
+MAX6874 chips can have four different addresses (as opposed to only two for
+the MAX6875). The additional addresses (0x54 and 0x56) are not probed by
+this driver by default, but the probe module parameter can be used if
+needed.
+
See the datasheet for details on how to program the EEPROM.
diff --git a/Documentation/i2c/dev-interface b/Documentation/i2c/dev-interface
index 09d6cda2a1fb..b849ad636583 100644
--- a/Documentation/i2c/dev-interface
+++ b/Documentation/i2c/dev-interface
@@ -14,9 +14,12 @@ C example
=========
So let's say you want to access an i2c adapter from a C program. The
-first thing to do is `#include <linux/i2c.h>" and "#include <linux/i2c-dev.h>.
-Yes, I know, you should never include kernel header files, but until glibc
-knows about i2c, there is not much choice.
+first thing to do is "#include <linux/i2c-dev.h>". Please note that
+there are two files named "i2c-dev.h" out there, one is distributed
+with the Linux kernel and is meant to be included from kernel
+driver code, the other one is distributed with lm_sensors and is
+meant to be included from user-space programs. You obviously want
+the second one here.
Now, you have to decide which adapter you want to access. You should
inspect /sys/class/i2c-dev/ to decide this. Adapter numbers are assigned
@@ -78,7 +81,7 @@ Full interface description
==========================
The following IOCTLs are defined and fully supported
-(see also i2c-dev.h and i2c.h):
+(see also i2c-dev.h):
ioctl(file,I2C_SLAVE,long addr)
Change slave address. The address is passed in the 7 lower bits of the
@@ -97,10 +100,10 @@ ioctl(file,I2C_PEC,long select)
ioctl(file,I2C_FUNCS,unsigned long *funcs)
Gets the adapter functionality and puts it in *funcs.
-ioctl(file,I2C_RDWR,struct i2c_ioctl_rdwr_data *msgset)
+ioctl(file,I2C_RDWR,struct i2c_rdwr_ioctl_data *msgset)
Do combined read/write transaction without stop in between.
- The argument is a pointer to a struct i2c_ioctl_rdwr_data {
+ The argument is a pointer to a struct i2c_rdwr_ioctl_data {
struct i2c_msg *msgs; /* ptr to array of simple messages */
int nmsgs; /* number of messages to exchange */
diff --git a/Documentation/i2c/writing-clients b/Documentation/i2c/writing-clients
index f482dae81de3..91664be91ffc 100644
--- a/Documentation/i2c/writing-clients
+++ b/Documentation/i2c/writing-clients
@@ -27,7 +27,6 @@ address.
static struct i2c_driver foo_driver = {
.owner = THIS_MODULE,
.name = "Foo version 2.3 driver",
- .id = I2C_DRIVERID_FOO, /* from i2c-id.h, optional */
.flags = I2C_DF_NOTIFY,
.attach_adapter = &foo_attach_adapter,
.detach_client = &foo_detach_client,
@@ -37,12 +36,6 @@ static struct i2c_driver foo_driver = {
The name can be chosen freely, and may be upto 40 characters long. Please
use something descriptive here.
-If used, the id should be a unique ID. The range 0xf000 to 0xffff is
-reserved for local use, and you can use one of those until you start
-distributing the driver, at which time you should contact the i2c authors
-to get your own ID(s). Note that most of the time you don't need an ID
-at all so you can just omit it.
-
Don't worry about the flags field; just put I2C_DF_NOTIFY into it. This
means that your driver will be notified when new adapters are found.
This is almost always what you want.
diff --git a/Documentation/infiniband/user_verbs.txt b/Documentation/infiniband/user_verbs.txt
new file mode 100644
index 000000000000..f847501e50b5
--- /dev/null
+++ b/Documentation/infiniband/user_verbs.txt
@@ -0,0 +1,69 @@
+USERSPACE VERBS ACCESS
+
+ The ib_uverbs module, built by enabling CONFIG_INFINIBAND_USER_VERBS,
+ enables direct userspace access to IB hardware via "verbs," as
+ described in chapter 11 of the InfiniBand Architecture Specification.
+
+ To use the verbs, the libibverbs library, available from
+ <http://openib.org/>, is required. libibverbs contains a
+ device-independent API for using the ib_uverbs interface.
+ libibverbs also requires appropriate device-dependent kernel and
+ userspace driver for your InfiniBand hardware. For example, to use
+ a Mellanox HCA, you will need the ib_mthca kernel module and the
+ libmthca userspace driver be installed.
+
+User-kernel communication
+
+ Userspace communicates with the kernel for slow path, resource
+ management operations via the /dev/infiniband/uverbsN character
+ devices. Fast path operations are typically performed by writing
+ directly to hardware registers mmap()ed into userspace, with no
+ system call or context switch into the kernel.
+
+ Commands are sent to the kernel via write()s on these device files.
+ The ABI is defined in drivers/infiniband/include/ib_user_verbs.h.
+ The structs for commands that require a response from the kernel
+ contain a 64-bit field used to pass a pointer to an output buffer.
+ Status is returned to userspace as the return value of the write()
+ system call.
+
+Resource management
+
+ Since creation and destruction of all IB resources is done by
+ commands passed through a file descriptor, the kernel can keep track
+ of which resources are attached to a given userspace context. The
+ ib_uverbs module maintains idr tables that are used to translate
+ between kernel pointers and opaque userspace handles, so that kernel
+ pointers are never exposed to userspace and userspace cannot trick
+ the kernel into following a bogus pointer.
+
+ This also allows the kernel to clean up when a process exits and
+ prevent one process from touching another process's resources.
+
+Memory pinning
+
+ Direct userspace I/O requires that memory regions that are potential
+ I/O targets be kept resident at the same physical address. The
+ ib_uverbs module manages pinning and unpinning memory regions via
+ get_user_pages() and put_page() calls. It also accounts for the
+ amount of memory pinned in the process's locked_vm, and checks that
+ unprivileged processes do not exceed their RLIMIT_MEMLOCK limit.
+
+ Pages that are pinned multiple times are counted each time they are
+ pinned, so the value of locked_vm may be an overestimate of the
+ number of pages pinned by a process.
+
+/dev files
+
+ To create the appropriate character device files automatically with
+ udev, a rule like
+
+ KERNEL="uverbs*", NAME="infiniband/%k"
+
+ can be used. This will create device nodes named
+
+ /dev/infiniband/uverbs0
+
+ and so on. Since the InfiniBand userspace verbs should be safe for
+ use by non-privileged processes, it may be useful to add an
+ appropriate MODE or GROUP to the udev rule.
diff --git a/Documentation/kdump/gdbmacros.txt b/Documentation/kdump/gdbmacros.txt
new file mode 100644
index 000000000000..bc1b9eb92ae1
--- /dev/null
+++ b/Documentation/kdump/gdbmacros.txt
@@ -0,0 +1,179 @@
+#
+# This file contains a few gdb macros (user defined commands) to extract
+# useful information from kernel crashdump (kdump) like stack traces of
+# all the processes or a particular process and trapinfo.
+#
+# These macros can be used by copying this file in .gdbinit (put in home
+# directory or current directory) or by invoking gdb command with
+# --command=<command-file-name> option
+#
+# Credits:
+# Alexander Nyberg <alexn@telia.com>
+# V Srivatsa <vatsa@in.ibm.com>
+# Maneesh Soni <maneesh@in.ibm.com>
+#
+
+define bttnobp
+ set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+ set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+ set $init_t=&init_task
+ set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+ while ($next_t != $init_t)
+ set $next_t=(struct task_struct *)$next_t
+ printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+ printf "===================\n"
+ set var $stackp = $next_t.thread.esp
+ set var $stack_top = ($stackp & ~4095) + 4096
+
+ while ($stackp < $stack_top)
+ if (*($stackp) > _stext && *($stackp) < _sinittext)
+ info symbol *($stackp)
+ end
+ set $stackp += 4
+ end
+ set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+ while ($next_th != $next_t)
+ set $next_th=(struct task_struct *)$next_th
+ printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+ printf "===================\n"
+ set var $stackp = $next_t.thread.esp
+ set var $stack_top = ($stackp & ~4095) + 4096
+
+ while ($stackp < $stack_top)
+ if (*($stackp) > _stext && *($stackp) < _sinittext)
+ info symbol *($stackp)
+ end
+ set $stackp += 4
+ end
+ set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+ end
+ set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+ end
+end
+document bttnobp
+ dump all thread stack traces on a kernel compiled with !CONFIG_FRAME_POINTER
+end
+
+define btt
+ set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+ set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+ set $init_t=&init_task
+ set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+ while ($next_t != $init_t)
+ set $next_t=(struct task_struct *)$next_t
+ printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+ printf "===================\n"
+ set var $stackp = $next_t.thread.esp
+ set var $stack_top = ($stackp & ~4095) + 4096
+ set var $stack_bot = ($stackp & ~4095)
+
+ set $stackp = *($stackp)
+ while (($stackp < $stack_top) && ($stackp > $stack_bot))
+ set var $addr = *($stackp + 4)
+ info symbol $addr
+ set $stackp = *($stackp)
+ end
+
+ set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+ while ($next_th != $next_t)
+ set $next_th=(struct task_struct *)$next_th
+ printf "\npid %d; comm %s:\n", $next_t.pid, $next_t.comm
+ printf "===================\n"
+ set var $stackp = $next_t.thread.esp
+ set var $stack_top = ($stackp & ~4095) + 4096
+ set var $stack_bot = ($stackp & ~4095)
+
+ set $stackp = *($stackp)
+ while (($stackp < $stack_top) && ($stackp > $stack_bot))
+ set var $addr = *($stackp + 4)
+ info symbol $addr
+ set $stackp = *($stackp)
+ end
+ set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+ end
+ set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+ end
+end
+document btt
+ dump all thread stack traces on a kernel compiled with CONFIG_FRAME_POINTER
+end
+
+define btpid
+ set var $pid = $arg0
+ set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+ set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+ set $init_t=&init_task
+ set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+ set var $pid_task = 0
+
+ while ($next_t != $init_t)
+ set $next_t=(struct task_struct *)$next_t
+
+ if ($next_t.pid == $pid)
+ set $pid_task = $next_t
+ end
+
+ set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+ while ($next_th != $next_t)
+ set $next_th=(struct task_struct *)$next_th
+ if ($next_th.pid == $pid)
+ set $pid_task = $next_th
+ end
+ set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+ end
+ set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+ end
+
+ printf "\npid %d; comm %s:\n", $pid_task.pid, $pid_task.comm
+ printf "===================\n"
+ set var $stackp = $pid_task.thread.esp
+ set var $stack_top = ($stackp & ~4095) + 4096
+ set var $stack_bot = ($stackp & ~4095)
+
+ set $stackp = *($stackp)
+ while (($stackp < $stack_top) && ($stackp > $stack_bot))
+ set var $addr = *($stackp + 4)
+ info symbol $addr
+ set $stackp = *($stackp)
+ end
+end
+document btpid
+ backtrace of pid
+end
+
+
+define trapinfo
+ set var $pid = $arg0
+ set $tasks_off=((size_t)&((struct task_struct *)0)->tasks)
+ set $pid_off=((size_t)&((struct task_struct *)0)->pids[1].pid_list.next)
+ set $init_t=&init_task
+ set $next_t=(((char *)($init_t->tasks).next) - $tasks_off)
+ set var $pid_task = 0
+
+ while ($next_t != $init_t)
+ set $next_t=(struct task_struct *)$next_t
+
+ if ($next_t.pid == $pid)
+ set $pid_task = $next_t
+ end
+
+ set $next_th=(((char *)$next_t->pids[1].pid_list.next) - $pid_off)
+ while ($next_th != $next_t)
+ set $next_th=(struct task_struct *)$next_th
+ if ($next_th.pid == $pid)
+ set $pid_task = $next_th
+ end
+ set $next_th=(((char *)$next_th->pids[1].pid_list.next) - $pid_off)
+ end
+ set $next_t=(char *)($next_t->tasks.next) - $tasks_off
+ end
+
+ printf "Trapno %ld, cr2 0x%lx, error_code %ld\n", $pid_task.thread.trap_no, \
+ $pid_task.thread.cr2, $pid_task.thread.error_code
+
+end
+document trapinfo
+ Run info threads and lookup pid of thread #1
+ 'trapinfo <pid>' will tell you by which trap & possibly
+ addresthe kernel paniced.
+end
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
new file mode 100644
index 000000000000..7ff213f4becd
--- /dev/null
+++ b/Documentation/kdump/kdump.txt
@@ -0,0 +1,141 @@
+Documentation for kdump - the kexec-based crash dumping solution
+================================================================
+
+DESIGN
+======
+
+Kdump uses kexec to reboot to a second kernel whenever a dump needs to be taken.
+This second kernel is booted with very little memory. The first kernel reserves
+the section of memory that the second kernel uses. This ensures that on-going
+DMA from the first kernel does not corrupt the second kernel.
+
+All the necessary information about Core image is encoded in ELF format and
+stored in reserved area of memory before crash. Physical address of start of
+ELF header is passed to new kernel through command line parameter elfcorehdr=.
+
+On i386, the first 640 KB of physical memory is needed to boot, irrespective
+of where the kernel loads. Hence, this region is backed up by kexec just before
+rebooting into the new kernel.
+
+In the second kernel, "old memory" can be accessed in two ways.
+
+- The first one is through a /dev/oldmem device interface. A capture utility
+ can read the device file and write out the memory in raw format. This is raw
+ dump of memory and analysis/capture tool should be intelligent enough to
+ determine where to look for the right information. ELF headers (elfcorehdr=)
+ can become handy here.
+
+- The second interface is through /proc/vmcore. This exports the dump as an ELF
+ format file which can be written out using any file copy command
+ (cp, scp, etc). Further, gdb can be used to perform limited debugging on
+ the dump file. This method ensures methods ensure that there is correct
+ ordering of the dump pages (corresponding to the first 640 KB that has been
+ relocated).
+
+SETUP
+=====
+
+1) Download http://www.xmission.com/~ebiederm/files/kexec/kexec-tools-1.101.tar.gz
+ and apply http://lse.sourceforge.net/kdump/patches/kexec-tools-1.101-kdump.patch
+ and after that build the source.
+
+2) Download and build the appropriate (latest) kexec/kdump (-mm) kernel
+ patchset and apply it to the vanilla kernel tree.
+
+ Two kernels need to be built in order to get this feature working.
+
+ A) First kernel:
+ a) Enable "kexec system call" feature (in Processor type and features).
+ CONFIG_KEXEC=y
+ b) This kernel's physical load address should be the default value of
+ 0x100000 (0x100000, 1 MB) (in Processor type and features).
+ CONFIG_PHYSICAL_START=0x100000
+ c) Enable "sysfs file system support" (in Pseudo filesystems).
+ CONFIG_SYSFS=y
+ d) Boot into first kernel with the command line parameter "crashkernel=Y@X".
+ Use appropriate values for X and Y. Y denotes how much memory to reserve
+ for the second kernel, and X denotes at what physical address the reserved
+ memory section starts. For example: "crashkernel=64M@16M".
+
+ B) Second kernel:
+ a) Enable "kernel crash dumps" feature (in Processor type and features).
+ CONFIG_CRASH_DUMP=y
+ b) Specify a suitable value for "Physical address where the kernel is
+ loaded" (in Processor type and features). Typically this value
+ should be same as X (See option d) above, e.g., 16 MB or 0x1000000.
+ CONFIG_PHYSICAL_START=0x1000000
+ c) Enable "/proc/vmcore support" (Optional, in Pseudo filesystems).
+ CONFIG_PROC_VMCORE=y
+ d) Disable SMP support and build a UP kernel (Until it is fixed).
+ CONFIG_SMP=n
+ e) Enable "Local APIC support on uniprocessors".
+ CONFIG_X86_UP_APIC=y
+ f) Enable "IO-APIC support on uniprocessors"
+ CONFIG_X86_UP_IOAPIC=y
+
+ Note: i) Options a) and b) depend upon "Configure standard kernel features
+ (for small systems)" (under General setup).
+ ii) Option a) also depends on CONFIG_HIGHMEM (under Processor
+ type and features).
+ iii) Both option a) and b) are under "Processor type and features".
+
+3) Boot into the first kernel. You are now ready to try out kexec-based crash
+ dumps.
+
+4) Load the second kernel to be booted using:
+
+ kexec -p <second-kernel> --crash-dump --args-linux --append="root=<root-dev>
+ init 1 irqpoll"
+
+ Note: i) <second-kernel> has to be a vmlinux image. bzImage will not work,
+ as of now.
+ ii) By default ELF headers are stored in ELF32 format (for i386). This
+ is sufficient to represent the physical memory up to 4GB. To store
+ headers in ELF64 format, specifiy "--elf64-core-headers" on the
+ kexec command line additionally.
+ iii) Specify "irqpoll" as command line parameter. This reduces driver
+ initialization failures in second kernel due to shared interrupts.
+
+5) System reboots into the second kernel when a panic occurs. A module can be
+ written to force the panic or "ALT-SysRq-c" can be used initiate a crash
+ dump for testing purposes.
+
+6) Write out the dump file using
+
+ cp /proc/vmcore <dump-file>
+
+ Dump memory can also be accessed as a /dev/oldmem device for a linear/raw
+ view. To create the device, type:
+
+ mknod /dev/oldmem c 1 12
+
+ Use "dd" with suitable options for count, bs and skip to access specific
+ portions of the dump.
+
+ Entire memory: dd if=/dev/oldmem of=oldmem.001
+
+ANALYSIS
+========
+
+Limited analysis can be done using gdb on the dump file copied out of
+/proc/vmcore. Use vmlinux built with -g and run
+
+ gdb vmlinux <dump-file>
+
+Stack trace for the task on processor 0, register display, memory display
+work fine.
+
+Note: gdb cannot analyse core files generated in ELF64 format for i386.
+
+TODO
+====
+
+1) Provide a kernel pages filtering mechanism so that core file size is not
+ insane on systems having huge memory banks.
+2) Modify "crash" tool to make it recognize this dump.
+
+CONTACT
+=======
+
+Vivek Goyal (vgoyal@in.ibm.com)
+Maneesh Soni (maneesh@in.ibm.com)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 4924d387a657..a998a8c2f95b 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -37,7 +37,7 @@ restrictions referred to are that the relevant option is valid if:
IA-32 IA-32 aka i386 architecture is enabled.
IA-64 IA-64 architecture is enabled.
IOSCHED More than one I/O scheduler is enabled.
- IP_PNP IP DCHP, BOOTP, or RARP is enabled.
+ IP_PNP IP DHCP, BOOTP, or RARP is enabled.
ISAPNP ISA PnP code is enabled.
ISDN Appropriate ISDN support is enabled.
JOY Appropriate joystick support is enabled.
@@ -358,6 +358,10 @@ running once the system is up.
cpia_pp= [HW,PPT]
Format: { parport<nr> | auto | none }
+ crashkernel=nn[KMG]@ss[KMG]
+ [KNL] Reserve a chunk of physical memory to
+ hold a kernel to switch to with kexec on panic.
+
cs4232= [HW,OSS]
Format: <io>,<irq>,<dma>,<dma2>,<mpuio>,<mpuirq>
@@ -447,6 +451,10 @@ running once the system is up.
Format: {"as"|"cfq"|"deadline"|"noop"}
See Documentation/block/as-iosched.txt
and Documentation/block/deadline-iosched.txt for details.
+ elfcorehdr= [IA-32]
+ Specifies physical address of start of kernel core image
+ elf header.
+ See Documentation/kdump.txt for details.
enforcing [SELINUX] Set initial enforcing status.
Format: {"0" | "1"}
@@ -548,6 +556,9 @@ running once the system is up.
i810= [HW,DRM]
+ i8k.ignore_dmi [HW] Continue probing hardware even if DMI data
+ indicates that the driver is running on unsupported
+ hardware.
i8k.force [HW] Activate i8k driver even if SMM BIOS signature
does not match list of supported models.
i8k.power_status
@@ -611,6 +622,17 @@ running once the system is up.
ips= [HW,SCSI] Adaptec / IBM ServeRAID controller
See header of drivers/scsi/ips.c.
+ irqfixup [HW]
+ When an interrupt is not handled search all handlers
+ for it. Intended to get systems with badly broken
+ firmware running.
+
+ irqpoll [HW]
+ When an interrupt is not handled search all handlers
+ for it. Also check all handlers each timer
+ interrupt. Intended to get systems with badly broken
+ firmware running.
+
isapnp= [ISAPNP]
Format: <RDP>, <reset>, <pci_scan>, <verbosity>
@@ -736,6 +758,9 @@ running once the system is up.
maxcpus= [SMP] Maximum number of processors that an SMP kernel
should make use of
+ max_addr=[KMG] [KNL,BOOT,ia64] All physical memory greater than or
+ equal to this physical address is ignored.
+
max_luns= [SCSI] Maximum number of LUNs to probe
Should be between 1 and 2^32-1.
@@ -1019,6 +1044,10 @@ running once the system is up.
irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned
automatically to PCI devices. You can make the kernel
exclude IRQs of your ISA cards this way.
+ pirqaddr=0xAAAAA [IA-32] Specify the physical address
+ of the PIRQ table (normally generated
+ by the BIOS) if it is outside the
+ F0000h-100000h range.
lastbus=N [IA-32] Scan all buses till bus #N. Can be useful
if the kernel is unable to find your secondary buses
and you want to tell it explicitly which ones they are.
@@ -1104,7 +1133,7 @@ running once the system is up.
See Documentation/ramdisk.txt.
psmouse.proto= [HW,MOUSE] Highest PS2 mouse protocol extension to
- probe for (bare|imps|exps).
+ probe for (bare|imps|exps|lifebook|any).
psmouse.rate= [HW,MOUSE] Set desired mouse report rate, in reports
per second.
psmouse.resetafter=
diff --git a/Documentation/keys.txt b/Documentation/keys.txt
index 36d80aeeaf28..0321ded4b9ae 100644
--- a/Documentation/keys.txt
+++ b/Documentation/keys.txt
@@ -22,6 +22,7 @@ This document has the following sections:
- New procfs files
- Userspace system call interface
- Kernel services
+ - Notes on accessing payload contents
- Defining a key type
- Request-key callback service
- Key access filesystem
@@ -45,27 +46,26 @@ Each key has a number of attributes:
- State.
- (*) Each key is issued a serial number of type key_serial_t that is unique
- for the lifetime of that key. All serial numbers are positive non-zero
- 32-bit integers.
+ (*) Each key is issued a serial number of type key_serial_t that is unique for
+ the lifetime of that key. All serial numbers are positive non-zero 32-bit
+ integers.
Userspace programs can use a key's serial numbers as a way to gain access
to it, subject to permission checking.
(*) Each key is of a defined "type". Types must be registered inside the
- kernel by a kernel service (such as a filesystem) before keys of that
- type can be added or used. Userspace programs cannot define new types
- directly.
+ kernel by a kernel service (such as a filesystem) before keys of that type
+ can be added or used. Userspace programs cannot define new types directly.
- Key types are represented in the kernel by struct key_type. This defines
- a number of operations that can be performed on a key of that type.
+ Key types are represented in the kernel by struct key_type. This defines a
+ number of operations that can be performed on a key of that type.
Should a type be removed from the system, all the keys of that type will
be invalidated.
(*) Each key has a description. This should be a printable string. The key
- type provides an operation to perform a match between the description on
- a key and a criterion string.
+ type provides an operation to perform a match between the description on a
+ key and a criterion string.
(*) Each key has an owner user ID, a group ID and a permissions mask. These
are used to control what a process may do to a key from userspace, and
@@ -74,10 +74,10 @@ Each key has a number of attributes:
(*) Each key can be set to expire at a specific time by the key type's
instantiation function. Keys can also be immortal.
- (*) Each key can have a payload. This is a quantity of data that represent
- the actual "key". In the case of a keyring, this is a list of keys to
- which the keyring links; in the case of a user-defined key, it's an
- arbitrary blob of data.
+ (*) Each key can have a payload. This is a quantity of data that represent the
+ actual "key". In the case of a keyring, this is a list of keys to which
+ the keyring links; in the case of a user-defined key, it's an arbitrary
+ blob of data.
Having a payload is not required; and the payload can, in fact, just be a
value stored in the struct key itself.
@@ -92,8 +92,8 @@ Each key has a number of attributes:
(*) Each key can be in one of a number of basic states:
- (*) Uninstantiated. The key exists, but does not have any data
- attached. Keys being requested from userspace will be in this state.
+ (*) Uninstantiated. The key exists, but does not have any data attached.
+ Keys being requested from userspace will be in this state.
(*) Instantiated. This is the normal state. The key is fully formed, and
has data attached.
@@ -140,10 +140,10 @@ The key service provides a number of features besides keys:
clone, fork, vfork or execve occurs. A new keyring is created only when
required.
- The process-specific keyring is replaced with an empty one in the child
- on clone, fork, vfork unless CLONE_THREAD is supplied, in which case it
- is shared. execve also discards the process's process keyring and creates
- a new one.
+ The process-specific keyring is replaced with an empty one in the child on
+ clone, fork, vfork unless CLONE_THREAD is supplied, in which case it is
+ shared. execve also discards the process's process keyring and creates a
+ new one.
The session-specific keyring is persistent across clone, fork, vfork and
execve, even when the latter executes a set-UID or set-GID binary. A
@@ -177,11 +177,11 @@ The key service provides a number of features besides keys:
If a system call that modifies a key or keyring in some way would put the
user over quota, the operation is refused and error EDQUOT is returned.
- (*) There's a system call interface by which userspace programs can create
- and manipulate keys and keyrings.
+ (*) There's a system call interface by which userspace programs can create and
+ manipulate keys and keyrings.
- (*) There's a kernel interface by which services can register types and
- search for keys.
+ (*) There's a kernel interface by which services can register types and search
+ for keys.
(*) There's a way for the a search done from the kernel to call back to
userspace to request a key that can't be found in a process's keyrings.
@@ -194,9 +194,9 @@ The key service provides a number of features besides keys:
KEY ACCESS PERMISSIONS
======================
-Keys have an owner user ID, a group access ID, and a permissions mask. The
-mask has up to eight bits each for user, group and other access. Only five of
-each set of eight bits are defined. These permissions granted are:
+Keys have an owner user ID, a group access ID, and a permissions mask. The mask
+has up to eight bits each for user, group and other access. Only five of each
+set of eight bits are defined. These permissions granted are:
(*) View
@@ -210,8 +210,8 @@ each set of eight bits are defined. These permissions granted are:
(*) Write
- This permits a key's payload to be instantiated or updated, or it allows
- a link to be added to or removed from a keyring.
+ This permits a key's payload to be instantiated or updated, or it allows a
+ link to be added to or removed from a keyring.
(*) Search
@@ -238,8 +238,8 @@ about the status of the key service:
(*) /proc/keys
This lists all the keys on the system, giving information about their
- type, description and permissions. The payload of the key is not
- available this way:
+ type, description and permissions. The payload of the key is not available
+ this way:
SERIAL FLAGS USAGE EXPY PERM UID GID TYPE DESCRIPTION: SUMMARY
00000001 I----- 39 perm 1f0000 0 0 keyring _uid_ses.0: 1/4
@@ -318,21 +318,21 @@ The main syscalls are:
If a key of the same type and description as that proposed already exists
in the keyring, this will try to update it with the given payload, or it
will return error EEXIST if that function is not supported by the key
- type. The process must also have permission to write to the key to be
- able to update it. The new key will have all user permissions granted and
- no group or third party permissions.
+ type. The process must also have permission to write to the key to be able
+ to update it. The new key will have all user permissions granted and no
+ group or third party permissions.
- Otherwise, this will attempt to create a new key of the specified type
- and description, and to instantiate it with the supplied payload and
- attach it to the keyring. In this case, an error will be generated if the
- process does not have permission to write to the keyring.
+ Otherwise, this will attempt to create a new key of the specified type and
+ description, and to instantiate it with the supplied payload and attach it
+ to the keyring. In this case, an error will be generated if the process
+ does not have permission to write to the keyring.
The payload is optional, and the pointer can be NULL if not required by
the type. The payload is plen in size, and plen can be zero for an empty
payload.
- A new keyring can be generated by setting type "keyring", the keyring
- name as the description (or NULL) and setting the payload to NULL.
+ A new keyring can be generated by setting type "keyring", the keyring name
+ as the description (or NULL) and setting the payload to NULL.
User defined keys can be created by specifying type "user". It is
recommended that a user defined key's description by prefixed with a type
@@ -369,9 +369,9 @@ The keyctl syscall functions are:
key_serial_t keyctl(KEYCTL_GET_KEYRING_ID, key_serial_t id,
int create);
- The special key specified by "id" is looked up (with the key being
- created if necessary) and the ID of the key or keyring thus found is
- returned if it exists.
+ The special key specified by "id" is looked up (with the key being created
+ if necessary) and the ID of the key or keyring thus found is returned if
+ it exists.
If the key does not yet exist, the key will be created if "create" is
non-zero; and the error ENOKEY will be returned if "create" is zero.
@@ -402,8 +402,8 @@ The keyctl syscall functions are:
This will try to update the specified key with the given payload, or it
will return error EOPNOTSUPP if that function is not supported by the key
- type. The process must also have permission to write to the key to be
- able to update it.
+ type. The process must also have permission to write to the key to be able
+ to update it.
The payload is of length plen, and may be absent or empty as for
add_key().
@@ -422,8 +422,8 @@ The keyctl syscall functions are:
long keyctl(KEYCTL_CHOWN, key_serial_t key, uid_t uid, gid_t gid);
- This function permits a key's owner and group ID to be changed. Either
- one of uid or gid can be set to -1 to suppress that change.
+ This function permits a key's owner and group ID to be changed. Either one
+ of uid or gid can be set to -1 to suppress that change.
Only the superuser can change a key's owner to something other than the
key's current owner. Similarly, only the superuser can change a key's
@@ -484,12 +484,12 @@ The keyctl syscall functions are:
long keyctl(KEYCTL_LINK, key_serial_t keyring, key_serial_t key);
- This function creates a link from the keyring to the key. The process
- must have write permission on the keyring and must have link permission
- on the key.
+ This function creates a link from the keyring to the key. The process must
+ have write permission on the keyring and must have link permission on the
+ key.
- Should the keyring not be a keyring, error ENOTDIR will result; and if
- the keyring is full, error ENFILE will result.
+ Should the keyring not be a keyring, error ENOTDIR will result; and if the
+ keyring is full, error ENFILE will result.
The link procedure checks the nesting of the keyrings, returning ELOOP if
it appears to deep or EDEADLK if the link would introduce a cycle.
@@ -503,8 +503,8 @@ The keyctl syscall functions are:
specified key, and removes it if found. Subsequent links to that key are
ignored. The process must have write permission on the keyring.
- If the keyring is not a keyring, error ENOTDIR will result; and if the
- key is not present, error ENOENT will be the result.
+ If the keyring is not a keyring, error ENOTDIR will result; and if the key
+ is not present, error ENOENT will be the result.
(*) Search a keyring tree for a key:
@@ -513,9 +513,9 @@ The keyctl syscall functions are:
const char *type, const char *description,
key_serial_t dest_keyring);
- This searches the keyring tree headed by the specified keyring until a
- key is found that matches the type and description criteria. Each keyring
- is checked for keys before recursion into its children occurs.
+ This searches the keyring tree headed by the specified keyring until a key
+ is found that matches the type and description criteria. Each keyring is
+ checked for keys before recursion into its children occurs.
The process must have search permission on the top level keyring, or else
error EACCES will result. Only keyrings that the process has search
@@ -549,8 +549,8 @@ The keyctl syscall functions are:
As much of the data as can be fitted into the buffer will be copied to
userspace if the buffer pointer is not NULL.
- On a successful return, the function will always return the amount of
- data available rather than the amount copied.
+ On a successful return, the function will always return the amount of data
+ available rather than the amount copied.
(*) Instantiate a partially constructed key.
@@ -568,8 +568,8 @@ The keyctl syscall functions are:
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
- that keyring, however all the constraints applying in KEYCTL_LINK apply
- in this case too.
+ that keyring, however all the constraints applying in KEYCTL_LINK apply in
+ this case too.
The payload and plen arguments describe the payload data as for add_key().
@@ -587,8 +587,39 @@ The keyctl syscall functions are:
it, and the key must be uninstantiated.
If a keyring is specified (non-zero), the key will also be linked into
- that keyring, however all the constraints applying in KEYCTL_LINK apply
- in this case too.
+ that keyring, however all the constraints applying in KEYCTL_LINK apply in
+ this case too.
+
+
+ (*) Set the default request-key destination keyring.
+
+ long keyctl(KEYCTL_SET_REQKEY_KEYRING, int reqkey_defl);
+
+ This sets the default keyring to which implicitly requested keys will be
+ attached for this thread. reqkey_defl should be one of these constants:
+
+ CONSTANT VALUE NEW DEFAULT KEYRING
+ ====================================== ====== =======================
+ KEY_REQKEY_DEFL_NO_CHANGE -1 No change
+ KEY_REQKEY_DEFL_DEFAULT 0 Default[1]
+ KEY_REQKEY_DEFL_THREAD_KEYRING 1 Thread keyring
+ KEY_REQKEY_DEFL_PROCESS_KEYRING 2 Process keyring
+ KEY_REQKEY_DEFL_SESSION_KEYRING 3 Session keyring
+ KEY_REQKEY_DEFL_USER_KEYRING 4 User keyring
+ KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5 User session keyring
+ KEY_REQKEY_DEFL_GROUP_KEYRING 6 Group keyring
+
+ The old default will be returned if successful and error EINVAL will be
+ returned if reqkey_defl is not one of the above values.
+
+ The default keyring can be overridden by the keyring indicated to the
+ request_key() system call.
+
+ Note that this setting is inherited across fork/exec.
+
+ [1] The default default is: the thread keyring if there is one, otherwise
+ the process keyring if there is one, otherwise the session keyring if
+ there is one, otherwise the user default session keyring.
===============
@@ -601,17 +632,14 @@ be broken down into two areas: keys and key types.
Dealing with keys is fairly straightforward. Firstly, the kernel service
registers its type, then it searches for a key of that type. It should retain
the key as long as it has need of it, and then it should release it. For a
-filesystem or device file, a search would probably be performed during the
-open call, and the key released upon close. How to deal with conflicting keys
-due to two different users opening the same file is left to the filesystem
-author to solve.
-
-When accessing a key's payload data, key->lock should be at least read locked,
-or else the data may be changed by an update being performed from userspace
-whilst the driver or filesystem is trying to access it. If no update method is
-supplied, then the key's payload may be accessed without holding a lock as
-there is no way to change it, provided it can be guaranteed that the key's
-type definition won't go away.
+filesystem or device file, a search would probably be performed during the open
+call, and the key released upon close. How to deal with conflicting keys due to
+two different users opening the same file is left to the filesystem author to
+solve.
+
+When accessing a key's payload contents, certain precautions must be taken to
+prevent access vs modification races. See the section "Notes on accessing
+payload contents" for more information.
(*) To search for a key, call:
@@ -629,6 +657,9 @@ type definition won't go away.
Should the function fail error ENOKEY, EKEYEXPIRED or EKEYREVOKED will be
returned.
+ If successful, the key will have been attached to the default keyring for
+ implicitly obtained request-key keys, as set by KEYCTL_SET_REQKEY_KEYRING.
+
(*) When it is no longer required, the key should be released using:
@@ -690,6 +721,54 @@ type definition won't go away.
void unregister_key_type(struct key_type *type);
+===================================
+NOTES ON ACCESSING PAYLOAD CONTENTS
+===================================
+
+The simplest payload is just a number in key->payload.value. In this case,
+there's no need to indulge in RCU or locking when accessing the payload.
+
+More complex payload contents must be allocated and a pointer to them set in
+key->payload.data. One of the following ways must be selected to access the
+data:
+
+ (1) Unmodifyable key type.
+
+ If the key type does not have a modify method, then the key's payload can
+ be accessed without any form of locking, provided that it's known to be
+ instantiated (uninstantiated keys cannot be "found").
+
+ (2) The key's semaphore.
+
+ The semaphore could be used to govern access to the payload and to control
+ the payload pointer. It must be write-locked for modifications and would
+ have to be read-locked for general access. The disadvantage of doing this
+ is that the accessor may be required to sleep.
+
+ (3) RCU.
+
+ RCU must be used when the semaphore isn't already held; if the semaphore
+ is held then the contents can't change under you unexpectedly as the
+ semaphore must still be used to serialise modifications to the key. The
+ key management code takes care of this for the key type.
+
+ However, this means using:
+
+ rcu_read_lock() ... rcu_dereference() ... rcu_read_unlock()
+
+ to read the pointer, and:
+
+ rcu_dereference() ... rcu_assign_pointer() ... call_rcu()
+
+ to set the pointer and dispose of the old contents after a grace period.
+ Note that only the key type should ever modify a key's payload.
+
+ Furthermore, an RCU controlled payload must hold a struct rcu_head for the
+ use of call_rcu() and, if the payload is of variable size, the length of
+ the payload. key->datalen cannot be relied upon to be consistent with the
+ payload just dereferenced if the key's semaphore is not held.
+
+
===================
DEFINING A KEY TYPE
===================
@@ -717,15 +796,15 @@ The structure has a number of fields, some of which are mandatory:
int key_payload_reserve(struct key *key, size_t datalen);
- With the revised data length. Error EDQUOT will be returned if this is
- not viable.
+ With the revised data length. Error EDQUOT will be returned if this is not
+ viable.
(*) int (*instantiate)(struct key *key, const void *data, size_t datalen);
This method is called to attach a payload to a key during construction.
- The payload attached need not bear any relation to the data passed to
- this function.
+ The payload attached need not bear any relation to the data passed to this
+ function.
If the amount of data attached to the key differs from the size in
keytype->def_datalen, then key_payload_reserve() should be called.
@@ -734,38 +813,47 @@ The structure has a number of fields, some of which are mandatory:
The fact that KEY_FLAG_INSTANTIATED is not set in key->flags prevents
anything else from gaining access to the key.
- This method may sleep if it wishes.
+ It is safe to sleep in this method.
(*) int (*duplicate)(struct key *key, const struct key *source);
If this type of key can be duplicated, then this method should be
- provided. It is called to copy the payload attached to the source into
- the new key. The data length on the new key will have been updated and
- the quota adjusted already.
+ provided. It is called to copy the payload attached to the source into the
+ new key. The data length on the new key will have been updated and the
+ quota adjusted already.
This method will be called with the source key's semaphore read-locked to
- prevent its payload from being changed. It is safe to sleep here.
+ prevent its payload from being changed, thus RCU constraints need not be
+ applied to the source key.
+
+ This method does not have to lock the destination key in order to attach a
+ payload. The fact that KEY_FLAG_INSTANTIATED is not set in key->flags
+ prevents anything else from gaining access to the key.
+
+ It is safe to sleep in this method.
(*) int (*update)(struct key *key, const void *data, size_t datalen);
- If this type of key can be updated, then this method should be
- provided. It is called to update a key's payload from the blob of data
- provided.
+ If this type of key can be updated, then this method should be provided.
+ It is called to update a key's payload from the blob of data provided.
key_payload_reserve() should be called if the data length might change
- before any changes are actually made. Note that if this succeeds, the
- type is committed to changing the key because it's already been altered,
- so all memory allocation must be done first.
+ before any changes are actually made. Note that if this succeeds, the type
+ is committed to changing the key because it's already been altered, so all
+ memory allocation must be done first.
+
+ The key will have its semaphore write-locked before this method is called,
+ but this only deters other writers; any changes to the key's payload must
+ be made under RCU conditions, and call_rcu() must be used to dispose of
+ the old payload.
- key_payload_reserve() should be called with the key->lock write locked,
- and the changes to the key's attached payload should be made before the
- key is locked.
+ key_payload_reserve() should be called before the changes are made, but
+ after all allocations and other potentially failing function calls are
+ made.
- The key will have its semaphore write-locked before this method is
- called. Any changes to the key should be made with the key's rwlock
- write-locked also. It is safe to sleep here.
+ It is safe to sleep in this method.
(*) int (*match)(const struct key *key, const void *desc);
@@ -782,12 +870,12 @@ The structure has a number of fields, some of which are mandatory:
(*) void (*destroy)(struct key *key);
- This method is optional. It is called to discard the payload data on a
- key when it is being destroyed.
+ This method is optional. It is called to discard the payload data on a key
+ when it is being destroyed.
- This method does not need to lock the key; it can consider the key as
- being inaccessible. Note that the key's type may have changed before this
- function is called.
+ This method does not need to lock the key to access the payload; it can
+ consider the key as being inaccessible at this time. Note that the key's
+ type may have been changed before this function is called.
It is not safe to sleep in this method; the caller may hold spinlocks.
@@ -797,26 +885,31 @@ The structure has a number of fields, some of which are mandatory:
This method is optional. It is called during /proc/keys reading to
summarise a key's description and payload in text form.
- This method will be called with the key's rwlock read-locked. This will
- prevent the key's payload and state changing; also the description should
- not change. This also means it is not safe to sleep in this method.
+ This method will be called with the RCU read lock held. rcu_dereference()
+ should be used to read the payload pointer if the payload is to be
+ accessed. key->datalen cannot be trusted to stay consistent with the
+ contents of the payload.
+
+ The description will not change, though the key's state may.
+
+ It is not safe to sleep in this method; the RCU read lock is held by the
+ caller.
(*) long (*read)(const struct key *key, char __user *buffer, size_t buflen);
This method is optional. It is called by KEYCTL_READ to translate the
- key's payload into something a blob of data for userspace to deal
- with. Ideally, the blob should be in the same format as that passed in to
- the instantiate and update methods.
+ key's payload into something a blob of data for userspace to deal with.
+ Ideally, the blob should be in the same format as that passed in to the
+ instantiate and update methods.
If successful, the blob size that could be produced should be returned
rather than the size copied.
- This method will be called with the key's semaphore read-locked. This
- will prevent the key's payload changing. It is not necessary to also
- read-lock key->lock when accessing the key's payload. It is safe to sleep
- in this method, such as might happen when the userspace buffer is
- accessed.
+ This method will be called with the key's semaphore read-locked. This will
+ prevent the key's payload changing. It is not necessary to use RCU locking
+ when accessing the key's payload. It is safe to sleep in this method, such
+ as might happen when the userspace buffer is accessed.
============================
@@ -853,8 +946,8 @@ If it returns with the key remaining in the unconstructed state, the key will
be marked as being negative, it will be added to the session keyring, and an
error will be returned to the key requestor.
-Supplementary information may be provided from whoever or whatever invoked
-this service. This will be passed as the <callout_info> parameter. If no such
+Supplementary information may be provided from whoever or whatever invoked this
+service. This will be passed as the <callout_info> parameter. If no such
information was made available, then "-" will be passed as this parameter
instead.
diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX
index 834993d26730..5b01d5cc4e95 100644
--- a/Documentation/networking/00-INDEX
+++ b/Documentation/networking/00-INDEX
@@ -114,9 +114,7 @@ tuntap.txt
vortex.txt
- info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) Ethernet cards.
wan-router.txt
- - Wan router documentation
-wanpipe.txt
- - WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router
+ - WAN router documentation
wavelan.txt
- AT&T GIS (nee NCR) WaveLAN card: An Ethernet-like radio transceiver
x25.txt
diff --git a/Documentation/networking/dmfe.txt b/Documentation/networking/dmfe.txt
index c0e8398674ef..046363552d09 100644
--- a/Documentation/networking/dmfe.txt
+++ b/Documentation/networking/dmfe.txt
@@ -1,59 +1,65 @@
- dmfe.c: Version 1.28 01/18/2000
+Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
- A Davicom DM9102(A)/DM9132/DM9801 fast ethernet driver for Linux.
- Copyright (C) 1997 Sten Wang
+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 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.
- 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 driver provides kernel support for Davicom DM9102(A)/DM9132/DM9801 ethernet cards ( CNET
+10/100 ethernet cards uses Davicom chipset too, so this driver supports CNET cards too ).If you
+didn't compile this driver as a module, it will automatically load itself on boot and print a
+line similar to :
- A. Compiler command:
+ dmfe: Davicom DM9xxx net driver, version 1.36.4 (2002-01-17)
- A-1: For normal single or multiple processor kernel
- "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall
- -Wstrict-prototypes -O6 -c dmfe.c"
+If you compiled this driver as a module, you have to load it on boot.You can load it with command :
- A-2: For single or multiple processor with kernel module version function
- "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -I/usr/src/linux/net/inet
- -Wall -Wstrict-prototypes -O6 -c dmfe.c"
+ insmod dmfe
+This way it will autodetect the device mode.This is the suggested way to load the module.Or you can pass
+a mode= setting to module while loading, like :
- B. The following steps teach you how to activate a DM9102 board:
+ insmod dmfe mode=0 # Force 10M Half Duplex
+ insmod dmfe mode=1 # Force 100M Half Duplex
+ insmod dmfe mode=4 # Force 10M Full Duplex
+ insmod dmfe mode=5 # Force 100M Full Duplex
- 1. Used the upper compiler command to compile dmfe.c
+Next you should configure your network interface with a command similar to :
- 2. Insert dmfe module into kernel
- "insmod dmfe" ;;Auto Detection Mode (Suggest)
- "insmod dmfe mode=0" ;;Force 10M Half Duplex
- "insmod dmfe mode=1" ;;Force 100M Half Duplex
- "insmod dmfe mode=4" ;;Force 10M Full Duplex
- "insmod dmfe mode=5" ;;Force 100M Full Duplex
+ ifconfig eth0 172.22.3.18
+ ^^^^^^^^^^^
+ Your IP Adress
- 3. Config a dm9102 network interface
- "ifconfig eth0 172.22.3.18"
- ^^^^^^^^^^^ Your IP address
+Then you may have to modify the default routing table with command :
- 4. Activate the IP routing table. For some distributions, it is not
- necessary. You can type "route" to check.
+ route add default eth0
- "route add default eth0"
+Now your ethernet card should be up and running.
- 5. Well done. Your DM9102 adapter is now activated.
+TODO:
- C. Object files description:
- 1. dmfe_rh61.o: For Redhat 6.1
+Implement pci_driver::suspend() and pci_driver::resume() power management methods.
+Check on 64 bit boxes.
+Check and fix on big endian boxes.
+Test and make sure PCI latency is now correct for all cases.
- If you can make sure your kernel version, you can rename
- to dmfe.o and directly use it without re-compiling.
+Authors:
- Author: Sten Wang, 886-3-5798797-8517, E-mail: sten_wang@davicom.com.tw
+Sten Wang <sten_wang@davicom.com.tw > : Original Author
+Tobias Ringstrom <tori@unhappy.mine.nu> : Current Maintainer
+
+Contributors:
+
+Marcelo Tosatti <marcelo@conectiva.com.br>
+Alan Cox <alan@redhat.com>
+Jeff Garzik <jgarzik@pobox.com>
+Vojtech Pavlik <vojtech@suse.cz>
diff --git a/Documentation/networking/fib_trie.txt b/Documentation/networking/fib_trie.txt
new file mode 100644
index 000000000000..f50d0c673c57
--- /dev/null
+++ b/Documentation/networking/fib_trie.txt
@@ -0,0 +1,145 @@
+ LC-trie implementation notes.
+
+Node types
+----------
+leaf
+ An end node with data. This has a copy of the relevant key, along
+ with 'hlist' with routing table entries sorted by prefix length.
+ See struct leaf and struct leaf_info.
+
+trie node or tnode
+ An internal node, holding an array of child (leaf or tnode) pointers,
+ indexed through a subset of the key. See Level Compression.
+
+A few concepts explained
+------------------------
+Bits (tnode)
+ The number of bits in the key segment used for indexing into the
+ child array - the "child index". See Level Compression.
+
+Pos (tnode)
+ The position (in the key) of the key segment used for indexing into
+ the child array. See Path Compression.
+
+Path Compression / skipped bits
+ Any given tnode is linked to from the child array of its parent, using
+ a segment of the key specified by the parent's "pos" and "bits"
+ In certain cases, this tnode's own "pos" will not be immediately
+ adjacent to the parent (pos+bits), but there will be some bits
+ in the key skipped over because they represent a single path with no
+ deviations. These "skipped bits" constitute Path Compression.
+ Note that the search algorithm will simply skip over these bits when
+ searching, making it necessary to save the keys in the leaves to
+ verify that they actually do match the key we are searching for.
+
+Level Compression / child arrays
+ the trie is kept level balanced moving, under certain conditions, the
+ children of a full child (see "full_children") up one level, so that
+ instead of a pure binary tree, each internal node ("tnode") may
+ contain an arbitrarily large array of links to several children.
+ Conversely, a tnode with a mostly empty child array (see empty_children)
+ may be "halved", having some of its children moved downwards one level,
+ in order to avoid ever-increasing child arrays.
+
+empty_children
+ the number of positions in the child array of a given tnode that are
+ NULL.
+
+full_children
+ the number of children of a given tnode that aren't path compressed.
+ (in other words, they aren't NULL or leaves and their "pos" is equal
+ to this tnode's "pos"+"bits").
+
+ (The word "full" here is used more in the sense of "complete" than
+ as the opposite of "empty", which might be a tad confusing.)
+
+Comments
+---------
+
+We have tried to keep the structure of the code as close to fib_hash as
+possible to allow verification and help up reviewing.
+
+fib_find_node()
+ A good start for understanding this code. This function implements a
+ straightforward trie lookup.
+
+fib_insert_node()
+ Inserts a new leaf node in the trie. This is bit more complicated than
+ fib_find_node(). Inserting a new node means we might have to run the
+ level compression algorithm on part of the trie.
+
+trie_leaf_remove()
+ Looks up a key, deletes it and runs the level compression algorithm.
+
+trie_rebalance()
+ The key function for the dynamic trie after any change in the trie
+ it is run to optimize and reorganize. Tt will walk the trie upwards
+ towards the root from a given tnode, doing a resize() at each step
+ to implement level compression.
+
+resize()
+ Analyzes a tnode and optimizes the child array size by either inflating
+ or shrinking it repeatedly until it fullfills the criteria for optimal
+ level compression. This part follows the original paper pretty closely
+ and there may be some room for experimentation here.
+
+inflate()
+ Doubles the size of the child array within a tnode. Used by resize().
+
+halve()
+ Halves the size of the child array within a tnode - the inverse of
+ inflate(). Used by resize();
+
+fn_trie_insert(), fn_trie_delete(), fn_trie_select_default()
+ The route manipulation functions. Should conform pretty closely to the
+ corresponding functions in fib_hash.
+
+fn_trie_flush()
+ This walks the full trie (using nextleaf()) and searches for empty
+ leaves which have to be removed.
+
+fn_trie_dump()
+ Dumps the routing table ordered by prefix length. This is somewhat
+ slower than the corresponding fib_hash function, as we have to walk the
+ entire trie for each prefix length. In comparison, fib_hash is organized
+ as one "zone"/hash per prefix length.
+
+Locking
+-------
+
+fib_lock is used for an RW-lock in the same way that this is done in fib_hash.
+However, the functions are somewhat separated for other possible locking
+scenarios. It might conceivably be possible to run trie_rebalance via RCU
+to avoid read_lock in the fn_trie_lookup() function.
+
+Main lookup mechanism
+---------------------
+fn_trie_lookup() is the main lookup function.
+
+The lookup is in its simplest form just like fib_find_node(). We descend the
+trie, key segment by key segment, until we find a leaf. check_leaf() does
+the fib_semantic_match in the leaf's sorted prefix hlist.
+
+If we find a match, we are done.
+
+If we don't find a match, we enter prefix matching mode. The prefix length,
+starting out at the same as the key length, is reduced one step at a time,
+and we backtrack upwards through the trie trying to find a longest matching
+prefix. The goal is always to reach a leaf and get a positive result from the
+fib_semantic_match mechanism.
+
+Inside each tnode, the search for longest matching prefix consists of searching
+through the child array, chopping off (zeroing) the least significant "1" of
+the child index until we find a match or the child index consists of nothing but
+zeros.
+
+At this point we backtrack (t->stats.backtrack++) up the trie, continuing to
+chop off part of the key in order to find the longest matching prefix.
+
+At this point we will repeatedly descend subtries to look for a match, and there
+are some optimizations available that can provide us with "shortcuts" to avoid
+descending into dead ends. Look for "HL_OPTIMIZE" sections in the code.
+
+To alleviate any doubts about the correctness of the route selection process,
+a new netlink operation has been added. Look for NETLINK_FIB_LOOKUP, which
+gives userland access to fib_lookup().
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index a2c893a7475d..ab65714d95fc 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -304,57 +304,6 @@ tcp_low_latency - BOOLEAN
changed would be a Beowulf compute cluster.
Default: 0
-tcp_westwood - BOOLEAN
- Enable TCP Westwood+ congestion control algorithm.
- TCP Westwood+ is a sender-side only modification of the TCP Reno
- protocol stack that optimizes the performance of TCP congestion
- control. It is based on end-to-end bandwidth estimation to set
- congestion window and slow start threshold after a congestion
- episode. Using this estimation, TCP Westwood+ adaptively sets a
- slow start threshold and a congestion window which takes into
- account the bandwidth used at the time congestion is experienced.
- TCP Westwood+ significantly increases fairness wrt TCP Reno in
- wired networks and throughput over wireless links.
- Default: 0
-
-tcp_vegas_cong_avoid - BOOLEAN
- Enable TCP Vegas congestion avoidance algorithm.
- TCP Vegas is a sender-side only change to TCP that anticipates
- the onset of congestion by estimating the bandwidth. TCP Vegas
- adjusts the sending rate by modifying the congestion
- window. TCP Vegas should provide less packet loss, but it is
- not as aggressive as TCP Reno.
- Default:0
-
-tcp_bic - BOOLEAN
- Enable BIC TCP congestion control algorithm.
- BIC-TCP is a sender-side only change that ensures a linear RTT
- fairness under large windows while offering both scalability and
- bounded TCP-friendliness. The protocol combines two schemes
- called additive increase and binary search increase. When the
- congestion window is large, additive increase with a large
- increment ensures linear RTT fairness as well as good
- scalability. Under small congestion windows, binary search
- increase provides TCP friendliness.
- Default: 0
-
-tcp_bic_low_window - INTEGER
- Sets the threshold window (in packets) where BIC TCP starts to
- adjust the congestion window. Below this threshold BIC TCP behaves
- the same as the default TCP Reno.
- Default: 14
-
-tcp_bic_fast_convergence - BOOLEAN
- Forces BIC TCP to more quickly respond to changes in congestion
- window. Allows two flows sharing the same connection to converge
- more rapidly.
- Default: 1
-
-tcp_default_win_scale - INTEGER
- Sets the minimum window scale TCP will negotiate for on all
- conections.
- Default: 7
-
tcp_tso_win_divisor - INTEGER
This allows control over what percentage of the congestion window
can be consumed by a single TSO frame.
@@ -368,6 +317,11 @@ tcp_frto - BOOLEAN
where packet loss is typically due to random radio interference
rather than intermediate router congestion.
+tcp_congestion_control - STRING
+ Set the congestion control algorithm to be used for new
+ connections. The algorithm "reno" is always available, but
+ additional choices may be available based on kernel configuration.
+
somaxconn - INTEGER
Limit of socket listen() backlog, known in userspace as SOMAXCONN.
Defaults to 128. See also tcp_max_syn_backlog for additional tuning
diff --git a/Documentation/networking/tcp.txt b/Documentation/networking/tcp.txt
index 71749007091e..0fa300425575 100644
--- a/Documentation/networking/tcp.txt
+++ b/Documentation/networking/tcp.txt
@@ -1,5 +1,72 @@
-How the new TCP output machine [nyi] works.
+TCP protocol
+============
+
+Last updated: 21 June 2005
+
+Contents
+========
+
+- Congestion control
+- How the new TCP output machine [nyi] works
+
+Congestion control
+==================
+
+The following variables are used in the tcp_sock for congestion control:
+snd_cwnd The size of the congestion window
+snd_ssthresh Slow start threshold. We are in slow start if
+ snd_cwnd is less than this.
+snd_cwnd_cnt A counter used to slow down the rate of increase
+ once we exceed slow start threshold.
+snd_cwnd_clamp This is the maximum size that snd_cwnd can grow to.
+snd_cwnd_stamp Timestamp for when congestion window last validated.
+snd_cwnd_used Used as a highwater mark for how much of the
+ congestion window is in use. It is used to adjust
+ snd_cwnd down when the link is limited by the
+ application rather than the network.
+
+As of 2.6.13, Linux supports pluggable congestion control algorithms.
+A congestion control mechanism can be registered through functions in
+tcp_cong.c. The functions used by the congestion control mechanism are
+registered via passing a tcp_congestion_ops struct to
+tcp_register_congestion_control. As a minimum name, ssthresh,
+cong_avoid, min_cwnd must be valid.
+Private data for a congestion control mechanism is stored in tp->ca_priv.
+tcp_ca(tp) returns a pointer to this space. This is preallocated space - it
+is important to check the size of your private data will fit this space, or
+alternatively space could be allocated elsewhere and a pointer to it could
+be stored here.
+
+There are three kinds of congestion control algorithms currently: The
+simplest ones are derived from TCP reno (highspeed, scalable) and just
+provide an alternative the congestion window calculation. More complex
+ones like BIC try to look at other events to provide better
+heuristics. There are also round trip time based algorithms like
+Vegas and Westwood+.
+
+Good TCP congestion control is a complex problem because the algorithm
+needs to maintain fairness and performance. Please review current
+research and RFC's before developing new modules.
+
+The method that is used to determine which congestion control mechanism is
+determined by the setting of the sysctl net.ipv4.tcp_congestion_control.
+The default congestion control will be the last one registered (LIFO);
+so if you built everything as modules. the default will be reno. If you
+build with the default's from Kconfig, then BIC will be builtin (not a module)
+and it will end up the default.
+
+If you really want a particular default value then you will need
+to set it with the sysctl. If you use a sysctl, the module will be autoloaded
+if needed and you will get the expected protocol. If you ask for an
+unknown congestion method, then the sysctl attempt will fail.
+
+If you remove a tcp congestion control module, then you will get the next
+available one. Since reno can not be built as a module, and can not be
+deleted, it will always be available.
+
+How the new TCP output machine [nyi] works.
+===========================================
Data is kept on a single queue. The skb->users flag tells us if the frame is
one that has been queued already. To add a frame we throw it on the end. Ack
diff --git a/Documentation/networking/wanpipe.txt b/Documentation/networking/wanpipe.txt
deleted file mode 100644
index aea20cd2a56e..000000000000
--- a/Documentation/networking/wanpipe.txt
+++ /dev/null
@@ -1,622 +0,0 @@
-------------------------------------------------------------------------------
-Linux WAN Router Utilities Package
-------------------------------------------------------------------------------
-Version 2.2.1
-Mar 28, 2001
-Author: Nenad Corbic <ncorbic@sangoma.com>
-Copyright (c) 1995-2001 Sangoma Technologies Inc.
-------------------------------------------------------------------------------
-
-INTRODUCTION
-
-Wide Area Networks (WANs) are used to interconnect Local Area Networks (LANs)
-and/or stand-alone hosts over vast distances with data transfer rates
-significantly higher than those achievable with commonly used dial-up
-connections.
-
-Usually an external device called `WAN router' sitting on your local network
-or connected to your machine's serial port provides physical connection to
-WAN. Although router's job may be as simple as taking your local network
-traffic, converting it to WAN format and piping it through the WAN link, these
-devices are notoriously expensive, with prices as much as 2 - 5 times higher
-then the price of a typical PC box.
-
-Alternatively, considering robustness and multitasking capabilities of Linux,
-an internal router can be built (most routers use some sort of stripped down
-Unix-like operating system anyway). With a number of relatively inexpensive WAN
-interface cards available on the market, a perfectly usable router can be
-built for less than half a price of an external router. Yet a Linux box
-acting as a router can still be used for other purposes, such as fire-walling,
-running FTP, WWW or DNS server, etc.
-
-This kernel module introduces the notion of a WAN Link Driver (WLD) to Linux
-operating system and provides generic hardware-independent services for such
-drivers. Why can existing Linux network device interface not be used for
-this purpose? Well, it can. However, there are a few key differences between
-a typical network interface (e.g. Ethernet) and a WAN link.
-
-Many WAN protocols, such as X.25 and frame relay, allow for multiple logical
-connections (known as `virtual circuits' in X.25 terminology) over a single
-physical link. Each such virtual circuit may (and almost always does) lead
-to a different geographical location and, therefore, different network. As a
-result, it is the virtual circuit, not the physical link, that represents a
-route and, therefore, a network interface in Linux terms.
-
-To further complicate things, virtual circuits are usually volatile in nature
-(excluding so called `permanent' virtual circuits or PVCs). With almost no
-time required to set up and tear down a virtual circuit, it is highly desirable
-to implement on-demand connections in order to minimize network charges. So
-unlike a typical network driver, the WAN driver must be able to handle multiple
-network interfaces and cope as multiple virtual circuits come into existence
-and go away dynamically.
-
-Last, but not least, WAN configuration is much more complex than that of say
-Ethernet and may well amount to several dozens of parameters. Some of them
-are "link-wide" while others are virtual circuit-specific. The same holds
-true for WAN statistics which is by far more extensive and extremely useful
-when troubleshooting WAN connections. Extending the ifconfig utility to suit
-these needs may be possible, but does not seem quite reasonable. Therefore, a
-WAN configuration utility and corresponding application programmer's interface
-is needed for this purpose.
-
-Most of these problems are taken care of by this module. Its goal is to
-provide a user with more-or-less standard look and feel for all WAN devices and
-assist a WAN device driver writer by providing common services, such as:
-
- o User-level interface via /proc file system
- o Centralized configuration
- o Device management (setup, shutdown, etc.)
- o Network interface management (dynamic creation/destruction)
- o Protocol encapsulation/decapsulation
-
-To ba able to use the Linux WAN Router you will also need a WAN Tools package
-available from
-
- ftp.sangoma.com/pub/linux/current_wanpipe/wanpipe-X.Y.Z.tgz
-
-where vX.Y.Z represent the wanpipe version number.
-
-For technical questions and/or comments please e-mail to ncorbic@sangoma.com.
-For general inquiries please contact Sangoma Technologies Inc. by
-
- Hotline: 1-800-388-2475 (USA and Canada, toll free)
- Phone: (905) 474-1990 ext: 106
- Fax: (905) 474-9223
- E-mail: dm@sangoma.com (David Mandelstam)
- WWW: http://www.sangoma.com
-
-
-INSTALLATION
-
-Please read the WanpipeForLinux.pdf manual on how to
-install the WANPIPE tools and drivers properly.
-
-
-After installing wanpipe package: /usr/local/wanrouter/doc.
-On the ftp.sangoma.com : /linux/current_wanpipe/doc
-
-
-COPYRIGHT AND LICENSING INFORMATION
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; either version 2, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc., 675 Mass
-Ave, Cambridge, MA 02139, USA.
-
-
-
-ACKNOWLEDGEMENTS
-
-This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed
-by Sangoma Technologies Inc. for Linux 2.0.x and 2.2.x. Success of the WANPIPE
-together with the next major release of Linux kernel in summer 1996 commanded
-adequate changes to the WANPIPE code to take full advantage of new Linux
-features.
-
-Instead of continuing developing proprietary interface tied to Sangoma WAN
-cards, we decided to separate all hardware-independent code into a separate
-module and defined two levels of interfaces - one for user-level applications
-and another for kernel-level WAN drivers. WANPIPE is now implemented as a
-WAN driver compliant with the WAN Link Driver interface. Also a general
-purpose WAN configuration utility and a set of shell scripts was developed to
-support WAN router at the user level.
-
-Many useful ideas concerning hardware-independent interface implementation
-were given by Mike McLagan <mike.mclagan@linux.org> and his implementation
-of the Frame Relay router and drivers for Sangoma cards (dlci/sdla).
-
-With the new implementation of the APIs being incorporated into the WANPIPE,
-a special thank goes to Alan Cox in providing insight into BSD sockets.
-
-Special thanks to all the WANPIPE users who performed field-testing, reported
-bugs and made valuable comments and suggestions that help us to improve this
-product.
-
-
-
-NEW IN THIS RELEASE
-
- o Updated the WANCFG utility
- Calls the pppconfig to configure the PPPD
- for async connections.
-
- o Added the PPPCONFIG utility
- Used to configure the PPPD dameon for the
- WANPIPE Async PPP and standard serial port.
- The wancfg calls the pppconfig to configure
- the pppd.
-
- o Fixed the PCI autodetect feature.
- The SLOT 0 was used as an autodetect option
- however, some high end PC's slot numbers start
- from 0.
-
- o This release has been tested with the new backupd
- daemon release.
-
-
-PRODUCT COMPONENTS AND RELATED FILES
-
-/etc: (or user defined)
- wanpipe1.conf default router configuration file
-
-/lib/modules/X.Y.Z/misc:
- wanrouter.o router kernel loadable module
- af_wanpipe.o wanpipe api socket module
-
-/lib/modules/X.Y.Z/net:
- sdladrv.o Sangoma SDLA support module
- wanpipe.o Sangoma WANPIPE(tm) driver module
-
-/proc/net/wanrouter
- Config reads current router configuration
- Status reads current router status
- {name} reads WAN driver statistics
-
-/usr/sbin:
- wanrouter wanrouter start-up script
- wanconfig wanrouter configuration utility
- sdladump WANPIPE adapter memory dump utility
- fpipemon Monitor for Frame Relay
- cpipemon Monitor for Cisco HDLC
- ppipemon Monitor for PPP
- xpipemon Monitor for X25
- wpkbdmon WANPIPE keyboard led monitor/debugger
-
-/usr/local/wanrouter:
- README this file
- COPYING GNU General Public License
- Setup installation script
- Filelist distribution definition file
- wanrouter.rc meta-configuration file
- (used by the Setup and wanrouter script)
-
-/usr/local/wanrouter/doc:
- wanpipeForLinux.pdf WAN Router User's Manual
-
-/usr/local/wanrouter/patches:
- wanrouter-v2213.gz patch for Linux kernels 2.2.11 up to 2.2.13.
- wanrouter-v2214.gz patch for Linux kernel 2.2.14.
- wanrouter-v2215.gz patch for Linux kernels 2.2.15 to 2.2.17.
- wanrouter-v2218.gz patch for Linux kernels 2.2.18 and up.
- wanrouter-v240.gz patch for Linux kernel 2.4.0.
- wanrouter-v242.gz patch for Linux kernel 2.4.2 and up.
- wanrouter-v2034.gz patch for Linux kernel 2.0.34
- wanrouter-v2036.gz patch for Linux kernel 2.0.36 and up.
-
-/usr/local/wanrouter/patches/kdrivers:
- Sources of the latest WANPIPE device drivers.
- These are used to UPGRADE the linux kernel to the newest
- version if the kernel source has already been pathced with
- WANPIPE drivers.
-
-/usr/local/wanrouter/samples:
- interface sample interface configuration file
- wanpipe1.cpri CHDLC primary port
- wanpipe2.csec CHDLC secondary port
- wanpipe1.fr Frame Relay protocol
- wanpipe1.ppp PPP protocol )
- wanpipe1.asy CHDLC ASYNC protocol
- wanpipe1.x25 X25 protocol
- wanpipe1.stty Sync TTY driver (Used by Kernel PPPD daemon)
- wanpipe1.atty Async TTY driver (Used by Kernel PPPD daemon)
- wanrouter.rc sample meta-configuration file
-
-/usr/local/wanrouter/util:
- * wan-tools utilities source code
-
-/usr/local/wanrouter/api/x25:
- * x25 api sample programs.
-/usr/local/wanrouter/api/chdlc:
- * chdlc api sample programs.
-/usr/local/wanrouter/api/fr:
- * fr api sample programs.
-/usr/local/wanrouter/config/wancfg:
- wancfg WANPIPE GUI configuration program.
- Creates wanpipe#.conf files.
-/usr/local/wanrouter/config/cfgft1:
- cfgft1 GUI CSU/DSU configuration program.
-
-/usr/include/linux:
- wanrouter.h router API definitions
- wanpipe.h WANPIPE API definitions
- sdladrv.h SDLA support module API definitions
- sdlasfm.h SDLA firmware module definitions
- if_wanpipe.h WANPIPE Socket definitions
- if_wanpipe_common.h WANPIPE Socket/Driver common definitions.
- sdlapci.h WANPIPE PCI definitions
-
-
-/usr/src/linux/net/wanrouter:
- * wanrouter source code
-
-/var/log:
- wanrouter wanrouter start-up log (created by the Setup script)
-
-/var/lock: (or /var/lock/subsys for RedHat)
- wanrouter wanrouter lock file (created by the Setup script)
-
-/usr/local/wanrouter/firmware:
- fr514.sfm Frame relay firmware for Sangoma S508/S514 card
- cdual514.sfm Dual Port Cisco HDLC firmware for Sangoma S508/S514 card
- ppp514.sfm PPP Firmware for Sangoma S508 and S514 cards
- x25_508.sfm X25 Firmware for Sangoma S508 card.
-
-
-REVISION HISTORY
-
-1.0.0 December 31, 1996 Initial version
-
-1.0.1 January 30, 1997 Status and statistics can be read via /proc
- filesystem entries.
-
-1.0.2 April 30, 1997 Added UDP management via monitors.
-
-1.0.3 June 3, 1997 UDP management for multiple boards using Frame
- Relay and PPP
- Enabled continuous transmission of Configure
- Request Packet for PPP (for 508 only)
- Connection Timeout for PPP changed from 900 to 0
- Flow Control Problem fixed for Frame Relay
-
-1.0.4 July 10, 1997 S508/FT1 monitoring capability in fpipemon and
- ppipemon utilities.
- Configurable TTL for UDP packets.
- Multicast and Broadcast IP source addresses are
- silently discarded.
-
-1.0.5 July 28, 1997 Configurable T391,T392,N391,N392,N393 for Frame
- Relay in router.conf.
- Configurable Memory Address through router.conf
- for Frame Relay, PPP and X.25. (commenting this
- out enables auto-detection).
- Fixed freeing up received buffers using kfree()
- for Frame Relay and X.25.
- Protect sdla_peek() by calling save_flags(),
- cli() and restore_flags().
- Changed number of Trace elements from 32 to 20
- Added DLCI specific data monitoring in FPIPEMON.
-2.0.0 Nov 07, 1997 Implemented protection of RACE conditions by
- critical flags for FRAME RELAY and PPP.
- DLCI List interrupt mode implemented.
- IPX support in FRAME RELAY and PPP.
- IPX Server Support (MARS)
- More driver specific stats included in FPIPEMON
- and PIPEMON.
-
-2.0.1 Nov 28, 1997 Bug Fixes for version 2.0.0.
- Protection of "enable_irq()" while
- "disable_irq()" has been enabled from any other
- routine (for Frame Relay, PPP and X25).
- Added additional Stats for Fpipemon and Ppipemon
- Improved Load Sharing for multiple boards
-
-2.0.2 Dec 09, 1997 Support for PAP and CHAP for ppp has been
- implemented.
-
-2.0.3 Aug 15, 1998 New release supporting Cisco HDLC, CIR for Frame
- relay, Dynamic IP assignment for PPP and Inverse
- Arp support for Frame-relay. Man Pages are
- included for better support and a new utility
- for configuring FT1 cards.
-
-2.0.4 Dec 09, 1998 Dual Port support for Cisco HDLC.
- Support for HDLC (LAPB) API.
- Supports BiSync Streaming code for S502E
- and S503 cards.
- Support for Streaming HDLC API.
- Provides a BSD socket interface for
- creating applications using BiSync
- streaming.
-
-2.0.5 Aug 04, 1999 CHDLC initializatin bug fix.
- PPP interrupt driven driver:
- Fix to the PPP line hangup problem.
- New PPP firmware
- Added comments to the startup SYSTEM ERROR messages
- Xpipemon debugging application for the X25 protocol
- New USER_MANUAL.txt
- Fixed the odd boundary 4byte writes to the board.
- BiSync Streaming code has been taken out.
- Available as a patch.
- Streaming HDLC API has been taken out.
- Available as a patch.
-
-2.0.6 Aug 17, 1999 Increased debugging in statup scripts
- Fixed insallation bugs from 2.0.5
- Kernel patch works for both 2.2.10 and 2.2.11 kernels.
- There is no functional difference between the two packages
-
-2.0.7 Aug 26, 1999 o Merged X25API code into WANPIPE.
- o Fixed a memeory leak for X25API
- o Updated the X25API code for 2.2.X kernels.
- o Improved NEM handling.
-
-2.1.0 Oct 25, 1999 o New code for S514 PCI Card
- o New CHDLC and Frame Relay drivers
- o PPP and X25 are not supported in this release
-
-2.1.1 Nov 30, 1999 o PPP support for S514 PCI Cards
-
-2.1.3 Apr 06, 2000 o Socket based x25api
- o Socket based chdlc api
- o Socket based fr api
- o Dual Port Receive only CHDLC support.
- o Asynchronous CHDLC support (Secondary Port)
- o cfgft1 GUI csu/dsu configurator
- o wancfg GUI configuration file
- configurator.
- o Architectual directory changes.
-
-beta-2.1.4 Jul 2000 o Dynamic interface configuration:
- Network interfaces reflect the state
- of protocol layer. If the protocol becomes
- disconnected, driver will bring down
- the interface. Once the protocol reconnects
- the interface will be brought up.
-
- Note: This option is turned off by default.
-
- o Dynamic wanrouter setup using 'wanconfig':
- wanconfig utility can be used to
- shutdown,restart,start or reconfigure
- a virtual circuit dynamically.
-
- Frame Relay: Each DLCI can be:
- created,stopped,restarted and reconfigured
- dynamically using wanconfig.
-
- ex: wanconfig card wanpipe1 dev wp1_fr16 up
-
- o Wanrouter startup via command line arguments:
- wanconfig also supports wanrouter startup via command line
- arguments. Thus, there is no need to create a wanpipe#.conf
- configuration file.
-
- o Socket based x25api update/bug fixes.
- Added support for LCN numbers greater than 255.
- Option to pass up modem messages.
- Provided a PCI IRQ check, so a single S514
- card is guaranteed to have a non-sharing interrupt.
-
- o Fixes to the wancfg utility.
- o New FT1 debugging support via *pipemon utilities.
- o Frame Relay ARP support Enabled.
-
-beta3-2.1.4 Jul 2000 o X25 M_BIT Problem fix.
- o Added the Multi-Port PPP
- Updated utilites for the Multi-Port PPP.
-
-2.1.4 Aut 2000
- o In X25API:
- Maximum packet an application can send
- to the driver has been extended to 4096 bytes.
-
- Fixed the x25 startup bug. Enable
- communications only after all interfaces
- come up. HIGH SVC/PVC is used to calculate
- the number of channels.
- Enable protocol only after all interfaces
- are enabled.
-
- o Added an extra state to the FT1 config, kernel module.
- o Updated the pipemon debuggers.
-
- o Blocked the Multi-Port PPP from running on kernels
- 2.2.16 or greater, due to syncppp kernel module
- change.
-
-beta1-2.1.5 Nov 15 2000
- o Fixed the MulitPort PPP Support for kernels 2.2.16 and above.
- 2.2.X kernels only
-
- o Secured the driver UDP debugging calls
- - All illegal netowrk debugging calls are reported to
- the log.
- - Defined a set of allowed commands, all other denied.
-
- o Cpipemon
- - Added set FT1 commands to the cpipemon. Thus CSU/DSU
- configuraiton can be performed using cpipemon.
- All systems that cannot run cfgft1 GUI utility should
- use cpipemon to configure the on board CSU/DSU.
-
-
- o Keyboard Led Monitor/Debugger
- - A new utilty /usr/sbin/wpkbdmon uses keyboard leds
- to convey operatinal statistic information of the
- Sangoma WANPIPE cards.
- NUM_LOCK = Line State (On=connected, Off=disconnected)
- CAPS_LOCK = Tx data (On=transmitting, Off=no tx data)
- SCROLL_LOCK = Rx data (On=receiving, Off=no rx data
-
- o Hardware probe on module load and dynamic device allocation
- - During WANPIPE module load, all Sangoma cards are probed
- and found information is printed in the /var/log/messages.
- - If no cards are found, the module load fails.
- - Appropriate number of devices are dynamically loaded
- based on the number of Sangoma cards found.
-
- Note: The kernel configuraiton option
- CONFIG_WANPIPE_CARDS has been taken out.
-
- o Fixed the Frame Relay and Chdlc network interfaces so they are
- compatible with libpcap libraries. Meaning, tcpdump, snort,
- ethereal, and all other packet sniffers and debuggers work on
- all WANPIPE netowrk interfaces.
- - Set the network interface encoding type to ARPHRD_PPP.
- This tell the sniffers that data obtained from the
- network interface is in pure IP format.
- Fix for 2.2.X kernels only.
-
- o True interface encoding option for Frame Relay and CHDLC
- - The above fix sets the network interface encoding
- type to ARPHRD_PPP, however some customers use
- the encoding interface type to determine the
- protocol running. Therefore, the TURE ENCODING
- option will set the interface type back to the
- original value.
-
- NOTE: If this option is used with Frame Relay and CHDLC
- libpcap library support will be broken.
- i.e. tcpdump will not work.
- Fix for 2.2.x Kernels only.
-
- o Ethernet Bridgind over Frame Relay
- - The Frame Relay bridging has been developed by
- Kristian Hoffmann and Mark Wells.
- - The Linux kernel bridge is used to send ethernet
- data over the frame relay links.
- For 2.2.X Kernels only.
-
- o Added extensive 2.0.X support. Most new features of
- 2.1.5 for protocols Frame Relay, PPP and CHDLC are
- supported under 2.0.X kernels.
-
-beta1-2.2.0 Dec 30 2000
- o Updated drivers for 2.4.X kernels.
- o Updated drivers for SMP support.
- o X25API is now able to share PCI interrupts.
- o Took out a general polling routine that was used
- only by X25API.
- o Added appropriate locks to the dynamic reconfiguration
- code.
- o Fixed a bug in the keyboard debug monitor.
-
-beta2-2.2.0 Jan 8 2001
- o Patches for 2.4.0 kernel
- o Patches for 2.2.18 kernel
- o Minor updates to PPP and CHLDC drivers.
- Note: No functinal difference.
-
-beta3-2.2.9 Jan 10 2001
- o I missed the 2.2.18 kernel patches in beta2-2.2.0
- release. They are included in this release.
-
-Stable Release
-2.2.0 Feb 01 2001
- o Bug fix in wancfg GUI configurator.
- The edit function didn't work properly.
-
-
-bata1-2.2.1 Feb 09 2001
- o WANPIPE TTY Driver emulation.
- Two modes of operation Sync and Async.
- Sync: Using the PPPD daemon, kernel SyncPPP layer
- and the Wanpipe sync TTY driver: a PPP protocol
- connection can be established via Sangoma adapter, over
- a T1 leased line.
-
- The 2.4.0 kernel PPP layer supports MULTILINK
- protocol, that can be used to bundle any number of Sangoma
- adapters (T1 lines) into one, under a single IP address.
- Thus, efficiently obtaining multiple T1 throughput.
-
- NOTE: The remote side must also implement MULTILINK PPP
- protocol.
-
- Async:Using the PPPD daemon, kernel AsyncPPP layer
- and the WANPIPE async TTY driver: a PPP protocol
- connection can be established via Sangoma adapter and
- a modem, over a telephone line.
-
- Thus, the WANPIPE async TTY driver simulates a serial
- TTY driver that would normally be used to interface the
- MODEM to the linux kernel.
-
- o WANPIPE PPP Backup Utility
- This utility will monitor the state of the PPP T1 line.
- In case of failure, a dial up connection will be established
- via pppd daemon, ether via a serial tty driver (serial port),
- or a WANPIPE async TTY driver (in case serial port is unavailable).
-
- Furthermore, while in dial up mode, the primary PPP T1 link
- will be monitored for signs of life.
-
- If the PPP T1 link comes back to life, the dial up connection
- will be shutdown and T1 line re-established.
-
-
- o New Setup installation script.
- Option to UPGRADE device drivers if the kernel source has
- already been patched with WANPIPE.
-
- Option to COMPILE WANPIPE modules against the currently
- running kernel, thus no need for manual kernel and module
- re-compilatin.
-
- o Updates and Bug Fixes to wancfg utility.
-
-bata2-2.2.1 Feb 20 2001
-
- o Bug fixes to the CHDLC device drivers.
- The driver had compilation problems under kernels
- 2.2.14 or lower.
-
- o Bug fixes to the Setup installation script.
- The device drivers compilation options didn't work
- properly.
-
- o Update to the wpbackupd daemon.
- Optimized the cross-over times, between the primary
- link and the backup dialup.
-
-beta3-2.2.1 Mar 02 2001
- o Patches for 2.4.2 kernel.
-
- o Bug fixes to util/ make files.
- o Bug fixes to the Setup installation script.
-
- o Took out the backupd support and made it into
- as separate package.
-
-beta4-2.2.1 Mar 12 2001
-
- o Fix to the Frame Relay Device driver.
- IPSAC sends a packet of zero length
- header to the frame relay driver. The
- driver tries to push its own 2 byte header
- into the packet, which causes the driver to
- crash.
-
- o Fix the WANPIPE re-configuration code.
- Bug was found by trying to run the cfgft1 while the
- interface was already running.
-
- o Updates to cfgft1.
- Writes a wanpipe#.cfgft1 configuration file
- once the CSU/DSU is configured. This file can
- holds the current CSU/DSU configuration.
-
-
-
->>>>>> END OF README <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
-
-
diff --git a/Documentation/pcmcia/devicetable.txt b/Documentation/pcmcia/devicetable.txt
new file mode 100644
index 000000000000..3351c0355143
--- /dev/null
+++ b/Documentation/pcmcia/devicetable.txt
@@ -0,0 +1,63 @@
+Matching of PCMCIA devices to drivers is done using one or more of the
+following criteria:
+
+- manufactor ID
+- card ID
+- product ID strings _and_ hashes of these strings
+- function ID
+- device function (actual and pseudo)
+
+You should use the helpers in include/pcmcia/device_id.h for generating the
+struct pcmcia_device_id[] entries which match devices to drivers.
+
+If you want to match product ID strings, you also need to pass the crc32
+hashes of the string to the macro, e.g. if you want to match the product ID
+string 1, you need to use
+
+PCMCIA_DEVICE_PROD_ID1("some_string", 0x(hash_of_some_string)),
+
+If the hash is incorrect, the kernel will inform you about this in "dmesg"
+upon module initialization, and tell you of the correct hash.
+
+You can determine the hash of the product ID strings by catting the file
+"modalias" in the sysfs directory of the PCMCIA device. It generates a string
+in the following form:
+pcmcia:m0149cC1ABf06pfn00fn00pa725B842DpbF1EFEE84pc0877B627pd00000000
+
+The hex value after "pa" is the hash of product ID string 1, after "pb" for
+string 2 and so on.
+
+Alternatively, you can use this small tool to determine the crc32 hash.
+simply pass the string you want to evaluate as argument to this program,
+e.g.
+$ ./crc32hash "Dual Speed"
+
+-------------------------------------------------------------------------
+/* crc32hash.c - derived from linux/lib/crc32.c, GNU GPL v2 */
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+unsigned int crc32(unsigned char const *p, unsigned int len)
+{
+ int i;
+ unsigned int crc = 0;
+ while (len--) {
+ crc ^= *p++;
+ for (i = 0; i < 8; i++)
+ crc = (crc >> 1) ^ ((crc & 1) ? 0xedb88320 : 0);
+ }
+ return crc;
+}
+
+int main(int argc, char **argv) {
+ unsigned int result;
+ if (argc != 2) {
+ printf("no string passed as argument\n");
+ return -1;
+ }
+ result = crc32(argv[1], strlen(argv[1]));
+ printf("0x%x\n", result);
+ return 0;
+}
diff --git a/Documentation/pcmcia/driver-changes.txt b/Documentation/pcmcia/driver-changes.txt
new file mode 100644
index 000000000000..59ccc63838c1
--- /dev/null
+++ b/Documentation/pcmcia/driver-changes.txt
@@ -0,0 +1,58 @@
+This file details changes in 2.6 which affect PCMCIA card driver authors:
+
+* event handler initialization in struct pcmcia_driver (as of 2.6.13)
+ The event handler is notified of all events, and must be initialized
+ as the event() callback in the driver's struct pcmcia_driver.
+
+* pcmcia/version.h should not be used (as of 2.6.13)
+ This file will be removed eventually.
+
+* in-kernel device<->driver matching (as of 2.6.13)
+ PCMCIA devices and their correct drivers can now be matched in
+ kernelspace. See 'devicetable.txt' for details.
+
+* Device model integration (as of 2.6.11)
+ A struct pcmcia_device is registered with the device model core,
+ and can be used (e.g. for SET_NETDEV_DEV) by using
+ handle_to_dev(client_handle_t * handle).
+
+* Convert internal I/O port addresses to unsigned long (as of 2.6.11)
+ ioaddr_t should be replaced by kio_addr_t in PCMCIA card drivers.
+
+* irq_mask and irq_list parameters (as of 2.6.11)
+ The irq_mask and irq_list parameters should no longer be used in
+ PCMCIA card drivers. Instead, it is the job of the PCMCIA core to
+ determine which IRQ should be used. Therefore, link->irq.IRQInfo2
+ is ignored.
+
+* client->PendingEvents is gone (as of 2.6.11)
+ client->PendingEvents is no longer available.
+
+* client->Attributes are gone (as of 2.6.11)
+ client->Attributes is unused, therefore it is removed from all
+ PCMCIA card drivers
+
+* core functions no longer available (as of 2.6.11)
+ The following functions have been removed from the kernel source
+ because they are unused by all in-kernel drivers, and no external
+ driver was reported to rely on them:
+ pcmcia_get_first_region()
+ pcmcia_get_next_region()
+ pcmcia_modify_window()
+ pcmcia_set_event_mask()
+ pcmcia_get_first_window()
+ pcmcia_get_next_window()
+
+* device list iteration upon module removal (as of 2.6.10)
+ It is no longer necessary to iterate on the driver's internal
+ client list and call the ->detach() function upon module removal.
+
+* Resource management. (as of 2.6.8)
+ Although the PCMCIA subsystem will allocate resources for cards,
+ it no longer marks these resources busy. This means that driver
+ authors are now responsible for claiming your resources as per
+ other drivers in Linux. You should use request_region() to mark
+ your IO regions in-use, and request_mem_region() to mark your
+ memory regions in-use. The name argument should be a pointer to
+ your driver name. Eg, for pcnet_cs, name should point to the
+ string "pcnet_cs".
diff --git a/Documentation/power/kernel_threads.txt b/Documentation/power/kernel_threads.txt
index 60b548105edf..fb57784986b1 100644
--- a/Documentation/power/kernel_threads.txt
+++ b/Documentation/power/kernel_threads.txt
@@ -12,8 +12,7 @@ refrigerator. Code to do this looks like this:
do {
hub_events();
wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
} while (!signal_pending(current));
from drivers/usb/core/hub.c::hub_thread()
diff --git a/Documentation/power/pci.txt b/Documentation/power/pci.txt
index 35b1a7dae342..6fc9d511fc39 100644
--- a/Documentation/power/pci.txt
+++ b/Documentation/power/pci.txt
@@ -291,6 +291,44 @@ a request to enable wake events from D3, two calls should be made to
pci_enable_wake (one for both D3hot and D3cold).
+A reference implementation
+-------------------------
+.suspend()
+{
+ /* driver specific operations */
+
+ /* Disable IRQ */
+ free_irq();
+ /* If using MSI */
+ pci_disable_msi();
+
+ pci_save_state();
+ pci_enable_wake();
+ /* Disable IO/bus master/irq router */
+ pci_disable_device();
+ pci_set_power_state(pci_choose_state());
+}
+
+.resume()
+{
+ pci_set_power_state(PCI_D0);
+ pci_restore_state();
+ /* device's irq possibly is changed, driver should take care */
+ pci_enable_device();
+ pci_set_master();
+
+ /* if using MSI, device's vector possibly is changed */
+ pci_enable_msi();
+
+ request_irq();
+ /* driver specific operations; */
+}
+
+This is a typical implementation. Drivers can slightly change the order
+of the operations in the implementation, ignore some operations or add
+more deriver specific operations in it, but drivers should do something like
+this on the whole.
+
5. Resources
~~~~~~~~~~~~
diff --git a/Documentation/power/swsusp.txt b/Documentation/power/swsusp.txt
index c7c3459fde43..7a6b78966459 100644
--- a/Documentation/power/swsusp.txt
+++ b/Documentation/power/swsusp.txt
@@ -164,11 +164,11 @@ place where the thread is safe to be frozen (no kernel semaphores
should be held at that point and it must be safe to sleep there), and
add:
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
If the thread is needed for writing the image to storage, you should
-instead set the PF_NOFREEZE process flag when creating the thread.
+instead set the PF_NOFREEZE process flag when creating the thread (and
+be very carefull).
Q: What is the difference between between "platform", "shutdown" and
@@ -233,3 +233,81 @@ A: Try running
cat `cat /proc/[0-9]*/maps | grep / | sed 's:.* /:/:' | sort -u` > /dev/null
after resume. swapoff -a; swapon -a may also be usefull.
+
+Q: What happens to devices during swsusp? They seem to be resumed
+during system suspend?
+
+A: That's correct. We need to resume them if we want to write image to
+disk. Whole sequence goes like
+
+ Suspend part
+ ~~~~~~~~~~~~
+ running system, user asks for suspend-to-disk
+
+ user processes are stopped
+
+ suspend(PMSG_FREEZE): devices are frozen so that they don't interfere
+ with state snapshot
+
+ state snapshot: copy of whole used memory is taken with interrupts disabled
+
+ resume(): devices are woken up so that we can write image to swap
+
+ write image to swap
+
+ suspend(PMSG_SUSPEND): suspend devices so that we can power off
+
+ turn the power off
+
+ Resume part
+ ~~~~~~~~~~~
+ (is actually pretty similar)
+
+ running system, user asks for suspend-to-disk
+
+ user processes are stopped (in common case there are none, but with resume-from-initrd, noone knows)
+
+ read image from disk
+
+ suspend(PMSG_FREEZE): devices are frozen so that they don't interfere
+ with image restoration
+
+ image restoration: rewrite memory with image
+
+ resume(): devices are woken up so that system can continue
+
+ thaw all user processes
+
+Q: What is this 'Encrypt suspend image' for?
+
+A: First of all: it is not a replacement for dm-crypt encrypted swap.
+It cannot protect your computer while it is suspended. Instead it does
+protect from leaking sensitive data after resume from suspend.
+
+Think of the following: you suspend while an application is running
+that keeps sensitive data in memory. The application itself prevents
+the data from being swapped out. Suspend, however, must write these
+data to swap to be able to resume later on. Without suspend encryption
+your sensitive data are then stored in plaintext on disk. This means
+that after resume your sensitive data are accessible to all
+applications having direct access to the swap device which was used
+for suspend. If you don't need swap after resume these data can remain
+on disk virtually forever. Thus it can happen that your system gets
+broken in weeks later and sensitive data which you thought were
+encrypted and protected are retrieved and stolen from the swap device.
+To prevent this situation you should use 'Encrypt suspend image'.
+
+During suspend a temporary key is created and this key is used to
+encrypt the data written to disk. When, during resume, the data was
+read back into memory the temporary key is destroyed which simply
+means that all data written to disk during suspend are then
+inaccessible so they can't be stolen later on. The only thing that
+you must then take care of is that you call 'mkswap' for the swap
+partition used for suspend as early as possible during regular
+boot. This asserts that any temporary key from an oopsed suspend or
+from a failed or aborted resume is erased from the swap device.
+
+As a rule of thumb use encrypted swap to protect your data while your
+system is shut down or suspended. Additionally use the encrypted
+suspend image to prevent sensitive data from being stolen after
+resume.
diff --git a/Documentation/power/video.txt b/Documentation/power/video.txt
index 68734355d7cf..7a4a5036d123 100644
--- a/Documentation/power/video.txt
+++ b/Documentation/power/video.txt
@@ -83,8 +83,10 @@ Compaq Armada E500 - P3-700 none (1) (S1 also works OK)
Compaq Evo N620c vga=normal, s3_bios (2)
Dell 600m, ATI R250 Lf none (1), but needs xorg-x11-6.8.1.902-1
Dell D600, ATI RV250 vga=normal and X, or try vbestate (6)
+Dell D610 vga=normal and X (possibly vbestate (6) too, but not tested)
Dell Inspiron 4000 ??? (*)
Dell Inspiron 500m ??? (*)
+Dell Inspiron 510m ???
Dell Inspiron 600m ??? (*)
Dell Inspiron 8200 ??? (*)
Dell Inspiron 8500 ??? (*)
@@ -115,6 +117,7 @@ IBM Thinkpad X40 Type 2371-7JG s3_bios,s3_mode (4)
Medion MD4220 ??? (*)
Samsung P35 vbetool needed (6)
Sharp PC-AR10 (ATI rage) none (1)
+Sony Vaio PCG-C1VRX/K s3_bios (2)
Sony Vaio PCG-F403 ??? (*)
Sony Vaio PCG-N505SN ??? (*)
Sony Vaio vgn-s260 X or boot-radeon can init it (5)
@@ -123,6 +126,7 @@ Toshiba Satellite 4030CDT s3_mode (3)
Toshiba Satellite 4080XCDT s3_mode (3)
Toshiba Satellite 4090XCDT ??? (*)
Toshiba Satellite P10-554 s3_bios,s3_mode (4)(****)
+Toshiba M30 (2) xor X with nvidia driver using internal AGP
Uniwill 244IIO ??? (*)
diff --git a/Documentation/power/video_extension.txt b/Documentation/power/video_extension.txt
index 8e33d7c82c49..b2f9b1598ac2 100644
--- a/Documentation/power/video_extension.txt
+++ b/Documentation/power/video_extension.txt
@@ -1,13 +1,16 @@
-This driver implement the ACPI Extensions For Display Adapters
-for integrated graphics devices on motherboard, as specified in
-ACPI 2.0 Specification, Appendix B, allowing to perform some basic
-control like defining the video POST device, retrieving EDID information
-or to setup a video output, etc. Note that this is an ref. implementation only.
-It may or may not work for your integrated video device.
+ACPI video extensions
+~~~~~~~~~~~~~~~~~~~~~
+
+This driver implement the ACPI Extensions For Display Adapters for
+integrated graphics devices on motherboard, as specified in ACPI 2.0
+Specification, Appendix B, allowing to perform some basic control like
+defining the video POST device, retrieving EDID information or to
+setup a video output, etc. Note that this is an ref. implementation
+only. It may or may not work for your integrated video device.
Interfaces exposed to userland through /proc/acpi/video:
-VGA/info : display the supported video bus device capability like ,Video ROM, CRT/LCD/TV.
+VGA/info : display the supported video bus device capability like Video ROM, CRT/LCD/TV.
VGA/ROM : Used to get a copy of the display devices' ROM data (up to 4k).
VGA/POST_info : Used to determine what options are implemented.
VGA/POST : Used to get/set POST device.
@@ -15,7 +18,7 @@ VGA/DOS : Used to get/set ownership of output switching:
Please refer ACPI spec B.4.1 _DOS
VGA/CRT : CRT output
VGA/LCD : LCD output
-VGA/TV : TV output
+VGA/TVO : TV output
VGA/*/brightness : Used to get/set brightness of output device
Notify event through /proc/acpi/event:
diff --git a/Documentation/s390/s390dbf.txt b/Documentation/s390/s390dbf.txt
index 2d1cd939b4df..e24fdeada970 100644
--- a/Documentation/s390/s390dbf.txt
+++ b/Documentation/s390/s390dbf.txt
@@ -12,8 +12,8 @@ where log records can be stored efficiently in memory, where each component
One purpose of this is to inspect the debug logs after a production system crash
in order to analyze the reason for the crash.
If the system still runs but only a subcomponent which uses dbf failes,
-it is possible to look at the debug logs on a live system via the Linux proc
-filesystem.
+it is possible to look at the debug logs on a live system via the Linux
+debugfs filesystem.
The debug feature may also very useful for kernel and driver development.
Design:
@@ -52,16 +52,18 @@ Each debug entry contains the following data:
- Flag, if entry is an exception or not
The debug logs can be inspected in a live system through entries in
-the proc-filesystem. Under the path /proc/s390dbf there is
+the debugfs-filesystem. Under the toplevel directory "s390dbf" there is
a directory for each registered component, which is named like the
-corresponding component.
+corresponding component. The debugfs normally should be mounted to
+/sys/kernel/debug therefore the debug feature can be accessed unter
+/sys/kernel/debug/s390dbf.
The content of the directories are files which represent different views
to the debug log. Each component can decide which views should be
used through registering them with the function debug_register_view().
Predefined views for hex/ascii, sprintf and raw binary data are provided.
It is also possible to define other views. The content of
-a view can be inspected simply by reading the corresponding proc file.
+a view can be inspected simply by reading the corresponding debugfs file.
All debug logs have an an actual debug level (range from 0 to 6).
The default level is 3. Event and Exception functions have a 'level'
@@ -69,14 +71,14 @@ parameter. Only debug entries with a level that is lower or equal
than the actual level are written to the log. This means, when
writing events, high priority log entries should have a low level
value whereas low priority entries should have a high one.
-The actual debug level can be changed with the help of the proc-filesystem
-through writing a number string "x" to the 'level' proc file which is
+The actual debug level can be changed with the help of the debugfs-filesystem
+through writing a number string "x" to the 'level' debugfs file which is
provided for every debug log. Debugging can be switched off completely
-by using "-" on the 'level' proc file.
+by using "-" on the 'level' debugfs file.
Example:
-> echo "-" > /proc/s390dbf/dasd/level
+> echo "-" > /sys/kernel/debug/s390dbf/dasd/level
It is also possible to deactivate the debug feature globally for every
debug log. You can change the behavior using 2 sysctl parameters in
@@ -99,11 +101,11 @@ Kernel Interfaces:
------------------
----------------------------------------------------------------------------
-debug_info_t *debug_register(char *name, int pages_index, int nr_areas,
+debug_info_t *debug_register(char *name, int pages, int nr_areas,
int buf_size);
-Parameter: name: Name of debug log (e.g. used for proc entry)
- pages_index: 2^pages_index pages will be allocated per area
+Parameter: name: Name of debug log (e.g. used for debugfs entry)
+ pages: number of pages, which will be allocated per area
nr_areas: number of debug areas
buf_size: size of data area in each debug entry
@@ -134,7 +136,7 @@ Return Value: none
Description: Sets new actual debug level if new_level is valid.
---------------------------------------------------------------------------
-+void debug_stop_all(void);
+void debug_stop_all(void);
Parameter: none
@@ -270,7 +272,7 @@ Parameter: id: handle for debug log
Return Value: 0 : ok
< 0: Error
-Description: registers new debug view and creates proc dir entry
+Description: registers new debug view and creates debugfs dir entry
---------------------------------------------------------------------------
int debug_unregister_view (debug_info_t * id, struct debug_view *view);
@@ -281,7 +283,7 @@ Parameter: id: handle for debug log
Return Value: 0 : ok
< 0: Error
-Description: unregisters debug view and removes proc dir entry
+Description: unregisters debug view and removes debugfs dir entry
@@ -308,7 +310,7 @@ static int init(void)
{
/* register 4 debug areas with one page each and 4 byte data field */
- debug_info = debug_register ("test", 0, 4, 4 );
+ debug_info = debug_register ("test", 1, 4, 4 );
debug_register_view(debug_info,&debug_hex_ascii_view);
debug_register_view(debug_info,&debug_raw_view);
@@ -343,7 +345,7 @@ static int init(void)
/* register 4 debug areas with one page each and data field for */
/* format string pointer + 2 varargs (= 3 * sizeof(long)) */
- debug_info = debug_register ("test", 0, 4, sizeof(long) * 3);
+ debug_info = debug_register ("test", 1, 4, sizeof(long) * 3);
debug_register_view(debug_info,&debug_sprintf_view);
debug_sprintf_event(debug_info, 2 , "first event in %s:%i\n",__FILE__,__LINE__);
@@ -362,16 +364,16 @@ module_exit(cleanup);
-ProcFS Interface
+Debugfs Interface
----------------
Views to the debug logs can be investigated through reading the corresponding
-proc-files:
+debugfs-files:
Example:
-> ls /proc/s390dbf/dasd
-flush hex_ascii level raw
-> cat /proc/s390dbf/dasd/hex_ascii | sort +1
+> ls /sys/kernel/debug/s390dbf/dasd
+flush hex_ascii level pages raw
+> cat /sys/kernel/debug/s390dbf/dasd/hex_ascii | sort +1
00 00974733272:680099 2 - 02 0006ad7e 07 ea 4a 90 | ....
00 00974733272:682210 2 - 02 0006ade6 46 52 45 45 | FREE
00 00974733272:682213 2 - 02 0006adf6 07 ea 4a 90 | ....
@@ -391,25 +393,36 @@ Changing the debug level
Example:
-> cat /proc/s390dbf/dasd/level
+> cat /sys/kernel/debug/s390dbf/dasd/level
3
-> echo "5" > /proc/s390dbf/dasd/level
-> cat /proc/s390dbf/dasd/level
+> echo "5" > /sys/kernel/debug/s390dbf/dasd/level
+> cat /sys/kernel/debug/s390dbf/dasd/level
5
Flushing debug areas
--------------------
Debug areas can be flushed with piping the number of the desired
-area (0...n) to the proc file "flush". When using "-" all debug areas
+area (0...n) to the debugfs file "flush". When using "-" all debug areas
are flushed.
Examples:
1. Flush debug area 0:
-> echo "0" > /proc/s390dbf/dasd/flush
+> echo "0" > /sys/kernel/debug/s390dbf/dasd/flush
2. Flush all debug areas:
-> echo "-" > /proc/s390dbf/dasd/flush
+> echo "-" > /sys/kernel/debug/s390dbf/dasd/flush
+
+Changing the size of debug areas
+------------------------------------
+It is possible the change the size of debug areas through piping
+the number of pages to the debugfs file "pages". The resize request will
+also flush the debug areas.
+
+Example:
+
+Define 4 pages for the debug areas of debug feature "dasd":
+> echo "4" > /sys/kernel/debug/s390dbf/dasd/pages
Stooping the debug feature
--------------------------
@@ -491,7 +504,7 @@ Defining views
--------------
Views are specified with the 'debug_view' structure. There are defined
-callback functions which are used for reading and writing the proc files:
+callback functions which are used for reading and writing the debugfs files:
struct debug_view {
char name[DEBUG_MAX_PROCF_LEN];
@@ -525,7 +538,7 @@ typedef int (debug_input_proc_t) (debug_info_t* id,
The "private_data" member can be used as pointer to view specific data.
It is not used by the debug feature itself.
-The output when reading a debug-proc file is structured like this:
+The output when reading a debugfs file is structured like this:
"prolog_proc output"
@@ -534,13 +547,13 @@ The output when reading a debug-proc file is structured like this:
"header_proc output 3" "format_proc output 3"
...
-When a view is read from the proc fs, the Debug Feature calls the
+When a view is read from the debugfs, the Debug Feature calls the
'prolog_proc' once for writing the prolog.
Then 'header_proc' and 'format_proc' are called for each
existing debug entry.
The input_proc can be used to implement functionality when it is written to
-the view (e.g. like with 'echo "0" > /proc/s390dbf/dasd/level).
+the view (e.g. like with 'echo "0" > /sys/kernel/debug/s390dbf/dasd/level).
For header_proc there can be used the default function
debug_dflt_header_fn() which is defined in in debug.h.
@@ -602,7 +615,7 @@ debug_info = debug_register ("test", 0, 4, 4 ));
debug_register_view(debug_info, &debug_test_view);
for(i = 0; i < 10; i ++) debug_int_event(debug_info, 1, i);
-> cat /proc/s390dbf/test/myview
+> cat /sys/kernel/debug/s390dbf/test/myview
00 00964419734:611402 1 - 00 88042ca This error...........
00 00964419734:611405 1 - 00 88042ca That error...........
00 00964419734:611408 1 - 00 88042ca Problem..............
diff --git a/Documentation/serial/driver b/Documentation/serial/driver
index e9c0178cd202..ac7eabbf662a 100644
--- a/Documentation/serial/driver
+++ b/Documentation/serial/driver
@@ -107,8 +107,8 @@ hardware.
indicate that the signal is permanently active. If RI is
not available, the signal should not be indicated as active.
- Locking: none.
- Interrupts: caller dependent.
+ Locking: port->lock taken.
+ Interrupts: locally disabled.
This call must not sleep
stop_tx(port,tty_stop)
diff --git a/Documentation/sysrq.txt b/Documentation/sysrq.txt
index f98c2e31c143..136d817c01ba 100644
--- a/Documentation/sysrq.txt
+++ b/Documentation/sysrq.txt
@@ -72,6 +72,8 @@ On all - write a character to /proc/sysrq-trigger. eg:
'b' - Will immediately reboot the system without syncing or unmounting
your disks.
+'c' - Will perform a kexec reboot in order to take a crashdump.
+
'o' - Will shut your system off (if configured and supported).
's' - Will attempt to sync all mounted filesystems.
@@ -122,6 +124,9 @@ useful when you want to exit a program that will not let you switch consoles.
re'B'oot is good when you're unable to shut down. But you should also 'S'ync
and 'U'mount first.
+'C'rashdump can be used to manually trigger a crashdump when the system is hung.
+The kernel needs to have been built with CONFIG_KEXEC enabled.
+
'S'ync is great when your system is locked up, it allows you to sync your
disks and will certainly lessen the chance of data loss and fscking. Note
that the sync hasn't taken place until you see the "OK" and "Done" appear
diff --git a/Documentation/usb/sn9c102.txt b/Documentation/usb/sn9c102.txt
index cf9a1187edce..3f8a119db31b 100644
--- a/Documentation/usb/sn9c102.txt
+++ b/Documentation/usb/sn9c102.txt
@@ -297,6 +297,7 @@ Vendor ID Product ID
0x0c45 0x602a
0x0c45 0x602b
0x0c45 0x602c
+0x0c45 0x602d
0x0c45 0x6030
0x0c45 0x6080
0x0c45 0x6082
@@ -333,6 +334,7 @@ Model Manufacturer
----- ------------
HV7131D Hynix Semiconductor, Inc.
MI-0343 Micron Technology, Inc.
+OV7630 OmniVision Technologies, Inc.
PAS106B PixArt Imaging, Inc.
PAS202BCB PixArt Imaging, Inc.
TAS5110C1B Taiwan Advanced Sensor Corporation
@@ -470,9 +472,11 @@ order):
- Luca Capello for the donation of a webcam;
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
donation of a webcam;
+- Jon Hollstrom for the donation of a webcam;
- Carlos Eduardo Medaglia Dyonisio, who added the support for the PAS202BCB
image sensor;
- Stefano Mozzi, who donated 45 EU;
+- Andrew Pearce for the donation of a webcam;
- Bertrik Sikken, who reverse-engineered and documented the Huffman compression
algorithm used in the SN9C10x controllers and implemented the first decoder;
- Mizuno Takafumi for the donation of a webcam;
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index 2f8431f92b77..f1896ee3bb2a 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -101,6 +101,13 @@ Here is the list of words, from left to right:
or 3 and 2 positions, correspondingly.
- URB Status. This field makes no sense for submissions, but is present
to help scripts with parsing. In error case, it contains the error code.
+ In case of a setup packet, it contains a Setup Tag. If scripts read a number
+ in this field, the proceed to read Data Length. Otherwise, they read
+ the setup packet before reading the Data Length.
+- Setup packet, if present, consists of 5 words: one of each for bmRequestType,
+ bRequest, wValue, wIndex, wLength, as specified by the USB Specification 2.0.
+ These words are safe to decode if Setup Tag was 's'. Otherwise, the setup
+ packet was present, but not captured, and the fields contain filler.
- Data Length. This is the actual length in the URB.
- Data tag. The usbmon may not always capture data, even if length is nonzero.
Only if tag is '=', the data words are present.
@@ -125,25 +132,31 @@ class ParsedLine {
String data_str = st.nextToken();
int len = data_str.length() / 2;
int i;
+ int b; // byte is signed, apparently?! XXX
for (i = 0; i < len; i++) {
- data[data_len] = Byte.parseByte(
- data_str.substring(i*2, i*2 + 2),
- 16);
+ // data[data_len] = Byte.parseByte(
+ // data_str.substring(i*2, i*2 + 2),
+ // 16);
+ b = Integer.parseInt(
+ data_str.substring(i*2, i*2 + 2),
+ 16);
+ if (b >= 128)
+ b *= -1;
+ data[data_len] = (byte) b;
data_len++;
}
}
}
}
-This format is obviously deficient. For example, the setup packet for control
-transfers is not delivered. This will change in the future.
+This format may be changed in the future.
Examples:
-An input control transfer to get a port status:
+An input control transfer to get a port status.
-d74ff9a0 2640288196 S Ci:001:00 -115 4 <
-d74ff9a0 2640288202 C Ci:001:00 0 4 = 01010100
+d5ea89a0 3575914555 S Ci:001:00 s a3 00 0000 0003 0004 4 <
+d5ea89a0 3575914560 C Ci:001:00 0 4 = 01050000
An output bulk transfer to send a SCSI command 0x5E in a 31-byte Bulk wrapper
to a storage device at address 5:
diff --git a/Documentation/video4linux/API.html b/Documentation/video4linux/API.html
index 4b3d8f640a4a..441407b12a9f 100644
--- a/Documentation/video4linux/API.html
+++ b/Documentation/video4linux/API.html
@@ -1,399 +1,16 @@
-<HTML><HEAD>
-<TITLE>Video4Linux Kernel API Reference v0.1:19990430</TITLE>
-</HEAD>
-<! Revision History: >
-<! 4/30/1999 - Fred Gleason (fredg@wava.com)>
-<! Documented extensions for the Radio Data System (RDS) extensions >
-<BODY bgcolor="#ffffff">
-<H3>Devices</H3>
-Video4Linux provides the following sets of device files. These live on the
-character device formerly known as "/dev/bttv". /dev/bttv should be a
-symlink to /dev/video0 for most people.
-<P>
-<TABLE>
-<TR><TH>Device Name</TH><TH>Minor Range</TH><TH>Function</TH>
-<TR><TD>/dev/video</TD><TD>0-63</TD><TD>Video Capture Interface</TD>
-<TR><TD>/dev/radio</TD><TD>64-127</TD><TD>AM/FM Radio Devices</TD>
-<TR><TD>/dev/vtx</TD><TD>192-223</TD><TD>Teletext Interface Chips</TD>
-<TR><TD>/dev/vbi</TD><TD>224-239</TD><TD>Raw VBI Data (Intercast/teletext)</TD>
-</TABLE>
-<P>
-Video4Linux programs open and scan the devices to find what they are looking
-for. Capability queries define what each interface supports. The
-described API is only defined for video capture cards. The relevant subset
-applies to radio cards. Teletext interfaces talk the existing VTX API.
-<P>
-<H3>Capability Query Ioctl</H3>
-The <B>VIDIOCGCAP</B> ioctl call is used to obtain the capability
-information for a video device. The <b>struct video_capability</b> object
-passed to the ioctl is completed and returned. It contains the following
-information
-<P>
-<TABLE>
-<TR><TD><b>name[32]</b><TD>Canonical name for this interface</TD>
-<TR><TD><b>type</b><TD>Type of interface</TD>
-<TR><TD><b>channels</b><TD>Number of radio/tv channels if appropriate</TD>
-<TR><TD><b>audios</b><TD>Number of audio devices if appropriate</TD>
-<TR><TD><b>maxwidth</b><TD>Maximum capture width in pixels</TD>
-<TR><TD><b>maxheight</b><TD>Maximum capture height in pixels</TD>
-<TR><TD><b>minwidth</b><TD>Minimum capture width in pixels</TD>
-<TR><TD><b>minheight</b><TD>Minimum capture height in pixels</TD>
-</TABLE>
-<P>
-The type field lists the capability flags for the device. These are
-as follows
-<P>
-<TABLE>
-<TR><TH>Name</TH><TH>Description</TH>
-<TR><TD><b>VID_TYPE_CAPTURE</b><TD>Can capture to memory</TD>
-<TR><TD><b>VID_TYPE_TUNER</b><TD>Has a tuner of some form</TD>
-<TR><TD><b>VID_TYPE_TELETEXT</b><TD>Has teletext capability</TD>
-<TR><TD><b>VID_TYPE_OVERLAY</b><TD>Can overlay its image onto the frame buffer</TD>
-<TR><TD><b>VID_TYPE_CHROMAKEY</b><TD>Overlay is Chromakeyed</TD>
-<TR><TD><b>VID_TYPE_CLIPPING</b><TD>Overlay clipping is supported</TD>
-<TR><TD><b>VID_TYPE_FRAMERAM</b><TD>Overlay overwrites frame buffer memory</TD>
-<TR><TD><b>VID_TYPE_SCALES</b><TD>The hardware supports image scaling</TD>
-<TR><TD><b>VID_TYPE_MONOCHROME</b><TD>Image capture is grey scale only</TD>
-<TR><TD><b>VID_TYPE_SUBCAPTURE</b><TD>Capture can be of only part of the image</TD>
-</TABLE>
-<P>
-The minimum and maximum sizes listed for a capture device do not imply all
-that all height/width ratios or sizes within the range are possible. A
-request to set a size will be honoured by the largest available capture
-size whose capture is no large than the requested rectangle in either
-direction. For example the quickcam has 3 fixed settings.
-<P>
-<H3>Frame Buffer</H3>
-Capture cards that drop data directly onto the frame buffer must be told the
-base address of the frame buffer, its size and organisation. This is a
-privileged ioctl and one that eventually X itself should set.
-<P>
-The <b>VIDIOCSFBUF</b> ioctl sets the frame buffer parameters for a capture
-card. If the card does not do direct writes to the frame buffer then this
-ioctl will be unsupported. The <b>VIDIOCGFBUF</b> ioctl returns the
-currently used parameters. The structure used in both cases is a
-<b>struct video_buffer</b>.
-<P>
-<TABLE>
-<TR><TD><b>void *base</b></TD><TD>Base physical address of the buffer</TD>
-<TR><TD><b>int height</b></TD><TD>Height of the frame buffer</TD>
-<TR><TD><b>int width</b></TD><TD>Width of the frame buffer</TD>
-<TR><TD><b>int depth</b></TD><TD>Depth of the frame buffer</TD>
-<TR><TD><b>int bytesperline</b></TD><TD>Number of bytes of memory between the start of two adjacent lines</TD>
-</TABLE>
-<P>
-Note that these values reflect the physical layout of the frame buffer.
-The visible area may be smaller. In fact under XFree86 this is commonly the
-case. XFree86 DGA can provide the parameters required to set up this ioctl.
-Setting the base address to NULL indicates there is no physical frame buffer
-access.
-<P>
-<H3>Capture Windows</H3>
-The capture area is described by a <b>struct video_window</b>. This defines
-a capture area and the clipping information if relevant. The
-<b>VIDIOCGWIN</b> ioctl recovers the current settings and the
-<b>VIDIOCSWIN</b> sets new values. A successful call to <b>VIDIOCSWIN</b>
-indicates that a suitable set of parameters have been chosen. They do not
-indicate that exactly what was requested was granted. The program should
-call <b>VIDIOCGWIN</b> to check if the nearest match was suitable. The
-<b>struct video_window</b> contains the following fields.
-<P>
-<TABLE>
-<TR><TD><b>x</b><TD>The X co-ordinate specified in X windows format.</TD>
-<TR><TD><b>y</b><TD>The Y co-ordinate specified in X windows format.</TD>
-<TR><TD><b>width</b><TD>The width of the image capture.</TD>
-<TR><TD><b>height</b><TD>The height of the image capture.</TD>
-<TR><TD><b>chromakey</b><TD>A host order RGB32 value for the chroma key.</TD>
-<TR><TD><b>flags</b><TD>Additional capture flags.</TD>
-<TR><TD><b>clips</b><TD>A list of clipping rectangles. <em>(Set only)</em></TD>
-<TR><TD><b>clipcount</b><TD>The number of clipping rectangles. <em>(Set only)</em></TD>
-</TABLE>
-<P>
-Clipping rectangles are passed as an array. Each clip consists of the following
-fields available to the user.
-<P>
-<TABLE>
-<TR><TD><b>x</b></TD><TD>X co-ordinate of rectangle to skip</TD>
-<TR><TD><b>y</b></TD><TD>Y co-ordinate of rectangle to skip</TD>
-<TR><TD><b>width</b></TD><TD>Width of rectangle to skip</TD>
-<TR><TD><b>height</b></TD><TD>Height of rectangle to skip</TD>
-</TABLE>
-<P>
-Merely setting the window does not enable capturing. Overlay capturing
-(i.e. PCI-PCI transfer to the frame buffer of the video card)
-is activated by passing the <b>VIDIOCCAPTURE</b> ioctl a value of 1, and
-disabled by passing it a value of 0.
-<P>
-Some capture devices can capture a subfield of the image they actually see.
-This is indicated when VIDEO_TYPE_SUBCAPTURE is defined.
-The video_capture describes the time and special subfields to capture.
-The video_capture structure contains the following fields.
-<P>
-<TABLE>
-<TR><TD><b>x</b></TD><TD>X co-ordinate of source rectangle to grab</TD>
-<TR><TD><b>y</b></TD><TD>Y co-ordinate of source rectangle to grab</TD>
-<TR><TD><b>width</b></TD><TD>Width of source rectangle to grab</TD>
-<TR><TD><b>height</b></TD><TD>Height of source rectangle to grab</TD>
-<TR><TD><b>decimation</b></TD><TD>Decimation to apply</TD>
-<TR><TD><b>flags</b></TD><TD>Flag settings for grabbing</TD>
-</TABLE>
-The available flags are
-<P>
-<TABLE>
-<TR><TH>Name</TH><TH>Description</TH>
-<TR><TD><b>VIDEO_CAPTURE_ODD</b><TD>Capture only odd frames</TD>
-<TR><TD><b>VIDEO_CAPTURE_EVEN</b><TD>Capture only even frames</TD>
-</TABLE>
-<P>
-<H3>Video Sources</H3>
-Each video4linux video or audio device captures from one or more
-source <b>channels</b>. Each channel can be queries with the
-<b>VDIOCGCHAN</b> ioctl call. Before invoking this function the caller
-must set the channel field to the channel that is being queried. On return
-the <b>struct video_channel</b> is filled in with information about the
-nature of the channel itself.
-<P>
-The <b>VIDIOCSCHAN</b> ioctl takes an integer argument and switches the
-capture to this input. It is not defined whether parameters such as colour
-settings or tuning are maintained across a channel switch. The caller should
-maintain settings as desired for each channel. (This is reasonable as
-different video inputs may have different properties).
-<P>
-The <b>struct video_channel</b> consists of the following
-<P>
-<TABLE>
-<TR><TD><b>channel</b></TD><TD>The channel number</TD>
-<TR><TD><b>name</b></TD><TD>The input name - preferably reflecting the label
-on the card input itself</TD>
-<TR><TD><b>tuners</b></TD><TD>Number of tuners for this input</TD>
-<TR><TD><b>flags</b></TD><TD>Properties the tuner has</TD>
-<TR><TD><b>type</b></TD><TD>Input type (if known)</TD>
-<TR><TD><b>norm</b><TD>The norm for this channel</TD>
-</TABLE>
-<P>
-The flags defined are
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_VC_TUNER</b><TD>Channel has tuners.</TD>
-<TR><TD><b>VIDEO_VC_AUDIO</b><TD>Channel has audio.</TD>
-<TR><TD><b>VIDEO_VC_NORM</b><TD>Channel has norm setting.</TD>
-</TABLE>
-<P>
-The types defined are
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_TYPE_TV</b><TD>The input is a TV input.</TD>
-<TR><TD><b>VIDEO_TYPE_CAMERA</b><TD>The input is a camera.</TD>
-</TABLE>
-<P>
-<H3>Image Properties</H3>
-The image properties of the picture can be queried with the <b>VIDIOCGPICT</b>
-ioctl which fills in a <b>struct video_picture</b>. The <b>VIDIOCSPICT</b>
-ioctl allows values to be changed. All values except for the palette type
-are scaled between 0-65535.
-<P>
-The <b>struct video_picture</b> consists of the following fields
-<P>
-<TABLE>
-<TR><TD><b>brightness</b><TD>Picture brightness</TD>
-<TR><TD><b>hue</b><TD>Picture hue (colour only)</TD>
-<TR><TD><b>colour</b><TD>Picture colour (colour only)</TD>
-<TR><TD><b>contrast</b><TD>Picture contrast</TD>
-<TR><TD><b>whiteness</b><TD>The whiteness (greyscale only)</TD>
-<TR><TD><b>depth</b><TD>The capture depth (may need to match the frame buffer depth)</TD>
-<TR><TD><b>palette</b><TD>Reports the palette that should be used for this image</TD>
-</TABLE>
-<P>
-The following palettes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_PALETTE_GREY</b><TD>Linear intensity grey scale (255 is brightest).</TD>
-<TR><TD><b>VIDEO_PALETTE_HI240</b><TD>The BT848 8bit colour cube.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB565</b><TD>RGB565 packed into 16 bit words.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB555</b><TD>RGV555 packed into 16 bit words, top bit undefined.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB24</b><TD>RGB888 packed into 24bit words.</TD>
-<TR><TD><b>VIDEO_PALETTE_RGB32</b><TD>RGB888 packed into the low 3 bytes of 32bit words. The top 8bits are undefined.</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV422</b><TD>Video style YUV422 - 8bits packed 4bits Y 2bits U 2bits V</TD>
-<TR><TD><b>VIDEO_PALETTE_YUYV</b><TD>Describe me</TD>
-<TR><TD><b>VIDEO_PALETTE_UYVY</b><TD>Describe me</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV420</b><TD>YUV420 capture</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV411</b><TD>YUV411 capture</TD>
-<TR><TD><b>VIDEO_PALETTE_RAW</b><TD>RAW capture (BT848)</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV422P</b><TD>YUV 4:2:2 Planar</TD>
-<TR><TD><b>VIDEO_PALETTE_YUV411P</b><TD>YUV 4:1:1 Planar</TD>
-</TABLE>
-<P>
-<H3>Tuning</H3>
-Each video input channel can have one or more tuners associated with it. Many
-devices will not have tuners. TV cards and radio cards will have one or more
-tuners attached.
-<P>
-Tuners are described by a <b>struct video_tuner</b> which can be obtained by
-the <b>VIDIOCGTUNER</b> ioctl. Fill in the tuner number in the structure
-then pass the structure to the ioctl to have the data filled in. The
-tuner can be switched using <b>VIDIOCSTUNER</b> which takes an integer argument
-giving the tuner to use. A struct tuner has the following fields
-<P>
-<TABLE>
-<TR><TD><b>tuner</b><TD>Number of the tuner</TD>
-<TR><TD><b>name</b><TD>Canonical name for this tuner (eg FM/AM/TV)</TD>
-<TR><TD><b>rangelow</b><TD>Lowest tunable frequency</TD>
-<TR><TD><b>rangehigh</b><TD>Highest tunable frequency</TD>
-<TR><TD><b>flags</b><TD>Flags describing the tuner</TD>
-<TR><TD><b>mode</b><TD>The video signal mode if relevant</TD>
-<TR><TD><b>signal</b><TD>Signal strength if known - between 0-65535</TD>
-</TABLE>
-<P>
-The following flags exist
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_TUNER_PAL</b><TD>PAL tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_NTSC</b><TD>NTSC tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_SECAM</b><TD>SECAM tuning is supported</TD>
-<TR><TD><b>VIDEO_TUNER_LOW</b><TD>Frequency is in a lower range</TD>
-<TR><TD><b>VIDEO_TUNER_NORM</b><TD>The norm for this tuner is settable</TD>
-<TR><TD><b>VIDEO_TUNER_STEREO_ON</b><TD>The tuner is seeing stereo audio</TD>
-<TR><TD><b>VIDEO_TUNER_RDS_ON</b><TD>The tuner is seeing a RDS datastream</TD>
-<TR><TD><b>VIDEO_TUNER_MBS_ON</b><TD>The tuner is seeing a MBS datastream</TD>
-</TABLE>
-<P>
-The following modes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_MODE_PAL</b><TD>The tuner is in PAL mode</TD>
-<TR><TD><b>VIDEO_MODE_NTSC</b><TD>The tuner is in NTSC mode</TD>
-<TR><TD><b>VIDEO_MODE_SECAM</b><TD>The tuner is in SECAM mode</TD>
-<TR><TD><b>VIDEO_MODE_AUTO</b><TD>The tuner auto switches, or mode does not apply</TD>
-</TABLE>
-<P>
-Tuning frequencies are an unsigned 32bit value in 1/16th MHz or if the
-<b>VIDEO_TUNER_LOW</b> flag is set they are in 1/16th KHz. The current
-frequency is obtained as an unsigned long via the <b>VIDIOCGFREQ</b> ioctl and
-set by the <b>VIDIOCSFREQ</b> ioctl.
-<P>
-<H3>Audio</H3>
-TV and Radio devices have one or more audio inputs that may be selected.
-The audio properties are queried by passing a <b>struct video_audio</b> to <b>VIDIOCGAUDIO</b> ioctl. The
-<b>VIDIOCSAUDIO</b> ioctl sets audio properties.
-<P>
-The structure contains the following fields
-<P>
-<TABLE>
-<TR><TD><b>audio</b><TD>The channel number</TD>
-<TR><TD><b>volume</b><TD>The volume level</TD>
-<TR><TD><b>bass</b><TD>The bass level</TD>
-<TR><TD><b>treble</b><TD>The treble level</TD>
-<TR><TD><b>flags</b><TD>Flags describing the audio channel</TD>
-<TR><TD><b>name</b><TD>Canonical name for the audio input</TD>
-<TR><TD><b>mode</b><TD>The mode the audio input is in</TD>
-<TR><TD><b>balance</b><TD>The left/right balance</TD>
-<TR><TD><b>step</b><TD>Actual step used by the hardware</TD>
-</TABLE>
-<P>
-The following flags are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_AUDIO_MUTE</b><TD>The audio is muted</TD>
-<TR><TD><b>VIDEO_AUDIO_MUTABLE</b><TD>Audio muting is supported</TD>
-<TR><TD><b>VIDEO_AUDIO_VOLUME</b><TD>The volume is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_BASS</b><TD>The bass is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_TREBLE</b><TD>The treble is controllable</TD>
-<TR><TD><b>VIDEO_AUDIO_BALANCE</b><TD>The balance is controllable</TD>
-</TABLE>
-<P>
-The following decoding modes are defined
-<P>
-<TABLE>
-<TR><TD><b>VIDEO_SOUND_MONO</b><TD>Mono signal</TD>
-<TR><TD><b>VIDEO_SOUND_STEREO</b><TD>Stereo signal (NICAM for TV)</TD>
-<TR><TD><b>VIDEO_SOUND_LANG1</b><TD>European TV alternate language 1</TD>
-<TR><TD><b>VIDEO_SOUND_LANG2</b><TD>European TV alternate language 2</TD>
-</TABLE>
-<P>
-<H3>Reading Images</H3>
-Each call to the <b>read</b> syscall returns the next available image
-from the device. It is up to the caller to set format and size (using
-the VIDIOCSPICT and VIDIOCSWIN ioctls) and then to pass a suitable
-size buffer and length to the function. Not all devices will support
-read operations.
-<P>
-A second way to handle image capture is via the mmap interface if supported.
-To use the mmap interface a user first sets the desired image size and depth
-properties. Next the VIDIOCGMBUF ioctl is issued. This reports the size
-of buffer to mmap and the offset within the buffer for each frame. The
-number of frames supported is device dependent and may only be one.
-<P>
-The video_mbuf structure contains the following fields
-<P>
-<TABLE>
-<TR><TD><b>size</b><TD>The number of bytes to map</TD>
-<TR><TD><b>frames</b><TD>The number of frames</TD>
-<TR><TD><b>offsets</b><TD>The offset of each frame</TD>
-</TABLE>
-<P>
-Once the mmap has been made the VIDIOCMCAPTURE ioctl starts the
-capture to a frame using the format and image size specified in the
-video_mmap (which should match or be below the initial query size).
-When the VIDIOCMCAPTURE ioctl returns the frame is <em>not</em>
-captured yet, the driver just instructed the hardware to start the
-capture. The application has to use the VIDIOCSYNC ioctl to wait
-until the capture of a frame is finished. VIDIOCSYNC takes the frame
-number you want to wait for as argument.
-<p>
-It is allowed to call VIDIOCMCAPTURE multiple times (with different
-frame numbers in video_mmap->frame of course) and thus have multiple
-outstanding capture requests. A simple way do to double-buffering
-using this feature looks like this:
-<pre>
-/* setup everything */
-VIDIOCMCAPTURE(0)
-while (whatever) {
- VIDIOCMCAPTURE(1)
- VIDIOCSYNC(0)
- /* process frame 0 while the hardware captures frame 1 */
- VIDIOCMCAPTURE(0)
- VIDIOCSYNC(1)
- /* process frame 1 while the hardware captures frame 0 */
-}
-</pre>
-Note that you are <em>not</em> limited to only two frames. The API
-allows up to 32 frames, the VIDIOCGMBUF ioctl returns the number of
-frames the driver granted. Thus it is possible to build deeper queues
-to avoid loosing frames on load peaks.
-<p>
-While capturing to memory the driver will make a "best effort" attempt
-to capture to screen as well if requested. This normally means all
-frames that "miss" memory mapped capture will go to the display.
-<P>
-A final ioctl exists to allow a device to obtain related devices if a
-driver has multiple components (for example video0 may not be associated
-with vbi0 which would cause an intercast display program to make a bad
-mistake). The VIDIOCGUNIT ioctl reports the unit numbers of the associated
-devices if any exist. The video_unit structure has the following fields.
-<P>
-<TABLE>
-<TR><TD><b>video</b><TD>Video capture device</TD>
-<TR><TD><b>vbi</b><TD>VBI capture device</TD>
-<TR><TD><b>radio</b><TD>Radio device</TD>
-<TR><TD><b>audio</b><TD>Audio mixer</TD>
-<TR><TD><b>teletext</b><TD>Teletext device</TD>
-</TABLE>
-<P>
-<H3>RDS Datastreams</H3>
-For radio devices that support it, it is possible to receive Radio Data
-System (RDS) data by means of a read() on the device. The data is packed in
-groups of three, as follows:
-<TABLE>
-<TR><TD>First Octet</TD><TD>Least Significant Byte of RDS Block</TD></TR>
-<TR><TD>Second Octet</TD><TD>Most Significant Byte of RDS Block
-<TR><TD>Third Octet</TD><TD>Bit 7:</TD><TD>Error bit. Indicates that
-an uncorrectable error occurred during reception of this block.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bit 6:</TD><TD>Corrected bit. Indicates that
-an error was corrected for this data block.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bits 5-3:</TD><TD>Received Offset. Indicates the
-offset received by the sync system.</TD></TR>
-<TR><TD>&nbsp;</TD><TD>Bits 2-0:</TD><TD>Offset Name. Indicates the
-offset applied to this data.</TD></TR>
-</TABLE>
-</BODY>
-</HTML>
+<TITLE>V4L API</TITLE>
+<H1>Video For Linux APIs</H1>
+<table border=0>
+<tr>
+<td>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L1_API.html>
+V4L original API</a>
+</td><td>
+Obsoleted by V4L2 API
+</td></tr><tr><td>
+<A HREF=http://www.linuxtv.org/downloads/video4linux/API/V4L2_API.html>
+V4L2 API</a>
+</td><td>
+Should be used for new projects
+</td></tr>
+</table>
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index e46761c39e3f..62a12a08e2ac 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -1,4 +1,4 @@
-card=0 - *** UNKNOWN/GENERIC ***
+card=0 - *** UNKNOWN/GENERIC ***
card=1 - MIRO PCTV
card=2 - Hauppauge (bt848)
card=3 - STB, Gateway P/N 6000699 (bt848)
@@ -119,3 +119,17 @@ card=117 - NGS NGSTV+
card=118 - LMLBT4
card=119 - Tekram M205 PRO
card=120 - Conceptronic CONTVFMi
+card=121 - Euresys Picolo Tetra
+card=122 - Spirit TV Tuner
+card=123 - AVerMedia AVerTV DVB-T 771
+card=124 - AverMedia AverTV DVB-T 761
+card=125 - MATRIX Vision Sigma-SQ
+card=126 - MATRIX Vision Sigma-SLC
+card=127 - APAC Viewcomp 878(AMAX)
+card=128 - DVICO FusionHDTV DVB-T Lite
+card=129 - V-Gear MyVCD
+card=130 - Super TV Tuner
+card=131 - Tibet Systems 'Progress DVR' CS16
+card=132 - Kodicom 4400R (master)
+card=133 - Kodicom 4400R (slave)
+card=134 - Adlink RTV24
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
new file mode 100644
index 000000000000..6d44958289de
--- /dev/null
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -0,0 +1,31 @@
+card=0 - UNKNOWN/GENERIC
+card=1 - Hauppauge WinTV 34xxx models
+card=2 - GDI Black Gold
+card=3 - PixelView
+card=4 - ATI TV Wonder Pro
+card=5 - Leadtek Winfast 2000XP Expert
+card=6 - AverTV Studio 303 (M126)
+card=7 - MSI TV-@nywhere Master
+card=8 - Leadtek Winfast DV2000
+card=9 - Leadtek PVR 2000
+card=10 - IODATA GV-VCP3/PCI
+card=11 - Prolink PlayTV PVR
+card=12 - ASUS PVR-416
+card=13 - MSI TV-@nywhere
+card=14 - KWorld/VStream XPert DVB-T
+card=15 - DViCO FusionHDTV DVB-T1
+card=16 - KWorld LTV883RF
+card=17 - DViCO FusionHDTV 3 Gold-Q
+card=18 - Hauppauge Nova-T DVB-T
+card=19 - Conexant DVB-T reference design
+card=20 - Provideo PV259
+card=21 - DViCO FusionHDTV DVB-T Plus
+card=22 - digitalnow DNTV Live! DVB-T
+card=23 - pcHDTV HD3000 HDTV
+card=24 - Hauppauge WinTV 28xxx (Roslyn) models
+card=25 - Digital-Logic MICROSPACE Entertainment Center (MEC)
+card=26 - IODATA GV/BCTV7E
+card=27 - PixelView PlayTV Ultra Pro (Stereo)
+card=28 - DViCO FusionHDTV 3 Gold-T
+card=29 - ADS Tech Instant TV DVB-T PCI
+card=30 - TerraTec Cinergy 1400 DVB-T
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index a6c82fa4de02..1b5a3a9ffbe2 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -1,10 +1,10 @@
- 0 -> UNKNOWN/GENERIC
+ 0 -> UNKNOWN/GENERIC
1 -> Proteus Pro [philips reference design] [1131:2001,1131:2001]
2 -> LifeView FlyVIDEO3000 [5168:0138,4e42:0138]
3 -> LifeView FlyVIDEO2000 [5168:0138]
4 -> EMPRESS [1131:6752]
5 -> SKNet Monster TV [1131:4e85]
- 6 -> Tevion MD 9717
+ 6 -> Tevion MD 9717
7 -> KNC One TV-Station RDS / Typhoon TV Tuner RDS [1131:fe01,1894:fe01]
8 -> Terratec Cinergy 400 TV [153B:1142]
9 -> Medion 5044
@@ -20,16 +20,45 @@
19 -> Compro VideoMate TV [185b:c100]
20 -> Matrox CronosPlus [102B:48d0]
21 -> 10MOONS PCI TV CAPTURE CARD [1131:2001]
- 22 -> Medion 2819/ AverMedia M156 [1461:a70b,1461:2115]
+ 22 -> AverMedia M156 / Medion 2819 [1461:a70b]
23 -> BMK MPEX Tuner
24 -> KNC One TV-Station DVR [1894:a006]
25 -> ASUS TV-FM 7133 [1043:4843]
26 -> Pinnacle PCTV Stereo (saa7134) [11bd:002b]
- 27 -> Manli MuchTV M-TV002
- 28 -> Manli MuchTV M-TV001
+ 27 -> Manli MuchTV M-TV002/Behold TV 403 FM
+ 28 -> Manli MuchTV M-TV001/Behold TV 401
29 -> Nagase Sangyo TransGear 3000TV [1461:050c]
30 -> Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) [1019:4cb4]
31 -> Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM) [1019:4cb5]
32 -> AVACS SmartTV
33 -> AVerMedia DVD EZMaker [1461:10ff]
- 34 -> LifeView FlyTV Platinum33 mini [5168:0212]
+ 34 -> Noval Prime TV 7133
+ 35 -> AverMedia AverTV Studio 305 [1461:2115]
+ 36 -> UPMOST PURPLE TV [12ab:0800]
+ 37 -> Items MuchTV Plus / IT-005
+ 38 -> Terratec Cinergy 200 TV [153B:1152]
+ 39 -> LifeView FlyTV Platinum Mini [5168:0212]
+ 40 -> Compro VideoMate TV PVR/FM [185b:c100]
+ 41 -> Compro VideoMate TV Gold+ [185b:c100]
+ 42 -> Sabrent SBT-TVFM (saa7130)
+ 43 -> :Zolid Xpert TV7134
+ 44 -> Empire PCI TV-Radio LE
+ 45 -> Avermedia AVerTV Studio 307 [1461:9715]
+ 46 -> AVerMedia Cardbus TV/Radio (E500) [1461:d6ee]
+ 47 -> Terratec Cinergy 400 mobile [153b:1162]
+ 48 -> Terratec Cinergy 600 TV MK3 [153B:1158]
+ 49 -> Compro VideoMate Gold+ Pal [185b:c200]
+ 50 -> Pinnacle PCTV 300i DVB-T + PAL [11bd:002d]
+ 51 -> ProVideo PV952 [1540:9524]
+ 52 -> AverMedia AverTV/305 [1461:2108]
+ 53 -> ASUS TV-FM 7135 [1043:4845]
+ 54 -> LifeView FlyTV Platinum FM [5168:0214,1489:0214]
+ 55 -> LifeView FlyDVB-T DUO [5168:0502,5168:0306]
+ 56 -> Avermedia AVerTV 307 [1461:a70a]
+ 57 -> Avermedia AVerTV GO 007 FM [1461:f31f]
+ 58 -> ADS Tech Instant TV (saa7135) [1421:0350,1421:0370]
+ 59 -> Kworld/Tevion V-Stream Xpert TV PVR7134
+ 60 -> Typhoon DVB-T Duo Digital/Analog Cardbus [4e42:0502]
+ 61 -> Philips TOUGH DVB-T reference design [1131:2004]
+ 62 -> Compro VideoMate TV Gold+II
+ 63 -> Kworld Xpert TV PVR7134
diff --git a/Documentation/video4linux/CARDLIST.tuner b/Documentation/video4linux/CARDLIST.tuner
index f7bafe862ba0..d1b9d21ffd89 100644
--- a/Documentation/video4linux/CARDLIST.tuner
+++ b/Documentation/video4linux/CARDLIST.tuner
@@ -44,3 +44,21 @@ tuner=42 - Philips 1236D ATSC/NTSC daul in
tuner=43 - Philips NTSC MK3 (FM1236MK3 or FM1236/F)
tuner=44 - Philips 4 in 1 (ATI TV Wonder Pro/Conexant)
tuner=45 - Microtune 4049 FM5
+tuner=46 - Panasonic VP27s/ENGE4324D
+tuner=47 - LG NTSC (TAPE series)
+tuner=48 - Tenna TNF 8831 BGFF)
+tuner=49 - Microtune 4042 FI5 ATSC/NTSC dual in
+tuner=50 - TCL 2002N
+tuner=51 - Philips PAL/SECAM_D (FM 1256 I-H3)
+tuner=52 - Thomson DDT 7610 (ATSC/NTSC)
+tuner=53 - Philips FQ1286
+tuner=54 - tda8290+75
+tuner=55 - LG PAL (TAPE series)
+tuner=56 - Philips PAL/SECAM multi (FQ1216AME MK4)
+tuner=57 - Philips FQ1236A MK4
+tuner=58 - Ymec TVision TVF-8531MF/8831MF/8731MF
+tuner=59 - Ymec TVision TVF-5533MF
+tuner=60 - Thomson DDT 7611 (ATSC/NTSC)
+tuner=61 - Tena TNF9533-D/IF/TNF9533-B/DF
+tuner=62 - Philips TEA5767HN FM Radio
+tuner=63 - Philips FMD1216ME MK3 Hybrid Tuner
diff --git a/Documentation/video4linux/README.saa7134 b/Documentation/video4linux/README.saa7134
index 1a446c65365e..1f788e498eff 100644
--- a/Documentation/video4linux/README.saa7134
+++ b/Documentation/video4linux/README.saa7134
@@ -57,6 +57,15 @@ Cards can use either of these two crystals (xtal):
- 24.576MHz -> .audio_clock=0x200000
(xtal * .audio_clock = 51539600)
+Some details about 30/34/35:
+
+ - saa7130 - low-price chip, doesn't have mute, that is why all those
+ cards should have .mute field defined in their tuner structure.
+
+ - saa7134 - usual chip
+
+ - saa7133/35 - saa7135 is probably a marketing decision, since all those
+ chips identifies itself as 33 on pci.
Credits
=======
diff --git a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
index 7f8c7eb70ab2..8f1941ede4da 100644
--- a/Documentation/video4linux/bttv/Cards
+++ b/Documentation/video4linux/bttv/Cards
@@ -20,7 +20,7 @@ All other cards only differ by additional components as tuners, sound
decoders, EEPROMs, teletext decoders ...
-Unsupported Cards:
+Unsupported Cards:
------------------
Cards with Zoran (ZR) or Philips (SAA) or ISA are not supported by
@@ -50,11 +50,11 @@ Bt848a/Bt849 single crytal operation support possible!!!
Miro/Pinnacle PCTV
------------------
-- Bt848
- some (all??) come with 2 crystals for PAL/SECAM and NTSC
+- Bt848
+ some (all??) come with 2 crystals for PAL/SECAM and NTSC
- PAL, SECAM or NTSC TV tuner (Philips or TEMIC)
- MSP34xx sound decoder on add on board
- decoder is supported but AFAIK does not yet work
+ decoder is supported but AFAIK does not yet work
(other sound MUX setting in GPIO port needed??? somebody who fixed this???)
- 1 tuner, 1 composite and 1 S-VHS input
- tuner type is autodetected
@@ -70,7 +70,7 @@ in 1997!
Hauppauge Win/TV pci
--------------------
-There are many different versions of the Hauppauge cards with different
+There are many different versions of the Hauppauge cards with different
tuners (TV+Radio ...), teletext decoders.
Note that even cards with same model numbers have (depending on the revision)
different chips on it.
@@ -80,22 +80,22 @@ different chips on it.
- PAL, SECAM, NTSC or tuner with or without Radio support
e.g.:
- PAL:
+ PAL:
TDA5737: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners
TSA5522: 1.4 GHz I2C-bus controlled synthesizer, I2C 0xc2-0xc3
-
+
NTSC:
TDA5731: VHF, hyperband and UHF mixer/oscillator for TV and VCR 3-band tuners
TSA5518: no datasheet available on Philips site
-- Philips SAA5246 or SAA5284 ( or no) Teletext decoder chip
+- Philips SAA5246 or SAA5284 ( or no) Teletext decoder chip
with buffer RAM (e.g. Winbond W24257AS-35: 32Kx8 CMOS static RAM)
SAA5246 (I2C 0x22) is supported
-- 256 bytes EEPROM: Microchip 24LC02B or Philips 8582E2Y
+- 256 bytes EEPROM: Microchip 24LC02B or Philips 8582E2Y
with configuration information
I2C address 0xa0 (24LC02B also responds to 0xa2-0xaf)
- 1 tuner, 1 composite and (depending on model) 1 S-VHS input
- 14052B: mux for selection of sound source
-- sound decoder: TDA9800, MSP34xx (stereo cards)
+- sound decoder: TDA9800, MSP34xx (stereo cards)
Askey CPH-Series
@@ -108,17 +108,17 @@ Developed by TelSignal(?), OEMed by many vendors (Typhoon, Anubis, Dynalink)
CPH05x: BT878 with FM
CPH06x: BT878 (w/o FM)
CPH07x: BT878 capture only
-
+
TV standards:
CPH0x0: NTSC-M/M
CPH0x1: PAL-B/G
CPH0x2: PAL-I/I
CPH0x3: PAL-D/K
- CPH0x4: SECAM-L/L
- CPH0x5: SECAM-B/G
- CPH0x6: SECAM-D/K
- CPH0x7: PAL-N/N
- CPH0x8: PAL-B/H
+ CPH0x4: SECAM-L/L
+ CPH0x5: SECAM-B/G
+ CPH0x6: SECAM-D/K
+ CPH0x7: PAL-N/N
+ CPH0x8: PAL-B/H
CPH0x9: PAL-M/M
CPH03x was often sold as "TV capturer".
@@ -174,7 +174,7 @@ Lifeview Flyvideo Series:
"The FlyVideo2000 and FlyVideo2000s product name have renamed to FlyVideo98."
Their Bt8x8 cards are listed as discontinued.
Flyvideo 2000S was probably sold as Flyvideo 3000 in some contries(Europe?).
- The new Flyvideo 2000/3000 are SAA7130/SAA7134 based.
+ The new Flyvideo 2000/3000 are SAA7130/SAA7134 based.
"Flyvideo II" had been the name for the 848 cards, nowadays (in Germany)
this name is re-used for LR50 Rev.W.
@@ -235,12 +235,12 @@ Prolink
Multimedia TV packages (card + software pack):
PixelView Play TV Theater - (Model: PV-M4200) = PixelView Play TV pro + Software
PixelView Play TV PAK - (Model: PV-BT878P+ REV 4E)
- PixelView Play TV/VCR - (Model: PV-M3200 REV 4C / 8D / 10A )
+ PixelView Play TV/VCR - (Model: PV-M3200 REV 4C / 8D / 10A )
PixelView Studio PAK - (Model: M2200 REV 4C / 8D / 10A )
PixelView PowerStudio PAK - (Model: PV-M3600 REV 4E)
PixelView DigitalVCR PAK - (Model: PV-M2400 REV 4C / 8D / 10A )
- PixelView PlayTV PAK II (TV/FM card + usb camera) PV-M3800
+ PixelView PlayTV PAK II (TV/FM card + usb camera) PV-M3800
PixelView PlayTV XP PV-M4700,PV-M4700(w/FM)
PixelView PlayTV DVR PV-M4600 package contents:PixelView PlayTV pro, windvr & videoMail s/w
@@ -254,7 +254,7 @@ Prolink
DTV3000 PV-DTV3000P+ DVB-S CI = Twinhan VP-1030
DTV2000 DVB-S = Twinhan VP-1020
-
+
Video Conferencing:
PixelView Meeting PAK - (Model: PV-BT878P)
PixelView Meeting PAK Lite - (Model: PV-BT878P)
@@ -308,7 +308,7 @@ KNC One
newer Cards have saa7134, but model name stayed the same?
-Provideo
+Provideo
--------
PV951 or PV-951 (also are sold as:
Boeder TV-FM Video Capture Card
@@ -353,7 +353,7 @@ AVerMedia
AVerTV
AVerTV Stereo
AVerTV Studio (w/FM)
- AVerMedia TV98 with Remote
+ AVerMedia TV98 with Remote
AVerMedia TV/FM98 Stereo
AVerMedia TVCAM98
TVCapture (Bt848)
@@ -373,7 +373,7 @@ AVerMedia
(1) Daughterboard MB68-A with TDA9820T and TDA9840T
(2) Sony NE41S soldered (stereo sound?)
(3) Daughterboard M118-A w/ pic 16c54 and 4 MHz quartz
-
+
US site has different drivers for (as of 09/2002):
EZ Capture/InterCam PCI (BT-848 chip)
EZ Capture/InterCam PCI (BT-878 chip)
@@ -437,7 +437,7 @@ Terratec
Terra TValueRadio, "LR102 Rev.C" printed on the PCB
Terra TV/Radio+ Version 1.0, "80-CP2830100-0" TTTV3 printed on the PCB,
"CPH010-E83" on the back, SAA6588T, TDA9873H
- Terra TValue Version BT878, "80-CP2830110-0 TTTV4" printed on the PCB,
+ Terra TValue Version BT878, "80-CP2830110-0 TTTV4" printed on the PCB,
"CPH011-D83" on back
Terra TValue Version 1.0 "ceb105.PCB" (really identical to Terra TV+ Version 1.0)
Terra TValue New Revision "LR102 Rec.C"
@@ -528,7 +528,7 @@ Koutech
KW-606RSF
KW-607A (capture only)
KW-608 (Zoran capture only)
-
+
IODATA (jp)
------
GV-BCTV/PCI
@@ -542,15 +542,15 @@ Canopus (jp)
-------
WinDVR = Kworld "KW-TVL878RF"
-www.sigmacom.co.kr
+www.sigmacom.co.kr
------------------
- Sigma Cyber TV II
+ Sigma Cyber TV II
www.sasem.co.kr
---------------
Litte OnAir TV
-hama
+hama
----
TV/Radio-Tuner Card, PCI (Model 44677) = CPH051
@@ -638,7 +638,7 @@ Media-Surfer (esc-kathrein.de)
Jetway (www.jetway.com.tw)
--------------------------
- JW-TV 878M
+ JW-TV 878M
JW-TV 878 = KWorld KW-TV878RF
Galaxis
@@ -715,7 +715,7 @@ Hauppauge
809 MyVideo
872 MyTV2Go FM
-
+
546 WinTV Nova-S CI
543 WinTV Nova
907 Nova-S USB
@@ -739,7 +739,7 @@ Hauppauge
832 MyTV2Go
869 MyTV2Go-FM
805 MyVideo (USB)
-
+
Matrix-Vision
-------------
@@ -764,7 +764,7 @@ Gallant (www.gallantcom.com) www.minton.com.tw
Intervision IV-550 (bt8x8)
Intervision IV-100 (zoran)
Intervision IV-1000 (bt8x8)
-
+
Asonic (www.asonic.com.cn) (website down)
-----------------------------------------
SkyEye tv 878
@@ -804,11 +804,11 @@ Kworld (www.kworld.com.tw)
JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
---------------------------------------------------------------------
- JTT-02 (JTT TV) "TV watchmate pro" (bt848)
+ JTT-02 (JTT TV) "TV watchmate pro" (bt848)
ADS www.adstech.com
-------------------
- Channel Surfer TV ( CHX-950 )
+ Channel Surfer TV ( CHX-950 )
Channel Surfer TV+FM ( CHX-960FM )
AVEC www.prochips.com
@@ -874,7 +874,7 @@ www.ids-imaging.de
------------------
Falcon Series (capture only)
In USA: http://www.theimagingsource.com/
- DFG/LC1
+ DFG/LC1
www.sknet-web.co.jp
-------------------
@@ -890,7 +890,7 @@ Cybertainment
CyberMail Xtreme
These are Flyvideo
-VCR (http://www.vcrinc.com/)
+VCR (http://www.vcrinc.com/)
---
Video Catcher 16
@@ -920,7 +920,7 @@ Sdisilk www.sdisilk.com/
SDI Silk 200 SDI Input Card
www.euresys.com
- PICOLO series
+ PICOLO series
PMC/Pace
www.pacecom.co.uk website closed
diff --git a/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
new file mode 100644
index 000000000000..93fec32a1188
--- /dev/null
+++ b/Documentation/video4linux/hauppauge-wintv-cx88-ir.txt
@@ -0,0 +1,54 @@
+The controls for the mux are GPIO [0,1] for source, and GPIO 2 for muting.
+
+GPIO0 GPIO1
+ 0 0 TV Audio
+ 1 0 FM radio
+ 0 1 Line-In
+ 1 1 Mono tuner bypass or CD passthru (tuner specific)
+
+GPIO 16(i believe) is tied to the IR port (if present).
+
+------------------------------------------------------------------------------------
+
+>From the data sheet:
+ Register 24'h20004 PCI Interrupt Status
+ bit [18] IR_SMP_INT Set when 32 input samples have been collected over
+ gpio[16] pin into GP_SAMPLE register.
+
+What's missing from the data sheet:
+
+Setup 4KHz sampling rate (roughly 2x oversampled; good enough for our RC5
+compat remote)
+set register 0x35C050 to 0xa80a80
+
+enable sampling
+set register 0x35C054 to 0x5
+
+Of course, enable the IRQ bit 18 in the interrupt mask register .(and
+provide for a handler)
+
+GP_SAMPLE register is at 0x35C058
+
+Bits are then right shifted into the GP_SAMPLE register at the specified
+rate; you get an interrupt when a full DWORD is recieved.
+You need to recover the actual RC5 bits out of the (oversampled) IR sensor
+bits. (Hint: look for the 0/1and 1/0 crossings of the RC5 bi-phase data) An
+actual raw RC5 code will span 2-3 DWORDS, depending on the actual alignment.
+
+I'm pretty sure when no IR signal is present the receiver is always in a
+marking state(1); but stray light, etc can cause intermittent noise values
+as well. Remember, this is a free running sample of the IR receiver state
+over time, so don't assume any sample starts at any particular place.
+
+http://www.atmel.com/dyn/resources/prod_documents/doc2817.pdf
+This data sheet (google search) seems to have a lovely description of the
+RC5 basics
+
+http://users.pandora.be/nenya/electronics/rc5/ and more data
+
+http://www.ee.washington.edu/circuit_archive/text/ir_decode.txt
+and even a reference to how to decode a bi-phase data stream.
+
+http://www.xs4all.nl/~sbp/knowledge/ir/rc5.htm
+still more info
+
diff --git a/Documentation/video4linux/lifeview.txt b/Documentation/video4linux/lifeview.txt
new file mode 100644
index 000000000000..b07ea79c2b7e
--- /dev/null
+++ b/Documentation/video4linux/lifeview.txt
@@ -0,0 +1,42 @@
+collecting data about the lifeview models and the config coding on
+gpio pins 0-9 ...
+==================================================================
+
+bt878:
+ LR50 rev. Q ("PARTS: 7031505116), Tuner wurde als Nr. 5 erkannt, Eingänge
+ SVideo, TV, Composite, Audio, Remote. CP9..1=100001001 (1: 0-Ohm-Widerstand
+ gegen GND unbestückt; 0: bestückt)
+
+------------------------------------------------------------------------------
+
+saa7134:
+ /* LifeView FlyTV Platinum FM (LR214WF) */
+ /* "Peter Missel <peter.missel@onlinehome.de> */
+ .name = "LifeView FlyTV Platinum FM",
+ /* GP27 MDT2005 PB4 pin 10 */
+ /* GP26 MDT2005 PB3 pin 9 */
+ /* GP25 MDT2005 PB2 pin 8 */
+ /* GP23 MDT2005 PB1 pin 7 */
+ /* GP22 MDT2005 PB0 pin 6 */
+ /* GP21 MDT2005 PB5 pin 11 */
+ /* GP20 MDT2005 PB6 pin 12 */
+ /* GP19 MDT2005 PB7 pin 13 */
+ /* nc MDT2005 PA3 pin 2 */
+ /* Remote MDT2005 PA2 pin 1 */
+ /* GP18 MDT2005 PA1 pin 18 */
+ /* nc MDT2005 PA0 pin 17 strap low */
+
+ /* GP17 Strap "GP7"=High */
+ /* GP16 Strap "GP6"=High
+ 0=Radio 1=TV
+ Drives SA630D ENCH1 and HEF4052 A1 pins
+ to do FM radio through SIF input */
+ /* GP15 nc */
+ /* GP14 nc */
+ /* GP13 nc */
+ /* GP12 Strap "GP5" = High */
+ /* GP11 Strap "GP4" = High */
+ /* GP10 Strap "GP3" = High */
+ /* GP09 Strap "GP2" = Low */
+ /* GP08 Strap "GP1" = Low */
+ /* GP07.00 nc */
diff --git a/Documentation/video4linux/not-in-cx2388x-datasheet.txt b/Documentation/video4linux/not-in-cx2388x-datasheet.txt
new file mode 100644
index 000000000000..edbfe744d21d
--- /dev/null
+++ b/Documentation/video4linux/not-in-cx2388x-datasheet.txt
@@ -0,0 +1,41 @@
+=================================================================================
+MO_OUTPUT_FORMAT (0x310164)
+
+ Previous default from DScaler: 0x1c1f0008
+ Digit 8: 31-28
+ 28: PREVREMOD = 1
+
+ Digit 7: 27-24 (0xc = 12 = b1100 )
+ 27: COMBALT = 1
+ 26: PAL_INV_PHASE
+ (DScaler apparently set this to 1, resulted in sucky picture)
+
+ Digits 6,5: 23-16
+ 25-16: COMB_RANGE = 0x1f [default] (9 bits -> max 512)
+
+ Digit 4: 15-12
+ 15: DISIFX = 0
+ 14: INVCBF = 0
+ 13: DISADAPT = 0
+ 12: NARROWADAPT = 0
+
+ Digit 3: 11-8
+ 11: FORCE2H
+ 10: FORCEREMD
+ 9: NCHROMAEN
+ 8: NREMODEN
+
+ Digit 2: 7-4
+ 7-6: YCORE
+ 5-4: CCORE
+
+ Digit 1: 3-0
+ 3: RANGE = 1
+ 2: HACTEXT
+ 1: HSFMT
+
+0x47 is the sync byte for MPEG-2 transport stream packets.
+Datasheet incorrectly states to use 47 decimal. 188 is the length.
+All DVB compliant frontends output packets with this start code.
+
+=================================================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 651af5012c98..5d014725901c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -370,6 +370,10 @@ W: http://www.thekelleys.org.uk/atmel
W: http://atmelwlandriver.sourceforge.net/
S: Maintained
+AUDIT SUBSYSTEM
+L: linux-audit@redhat.com (subscribers-only)
+S: Maintained
+
AX.25 NETWORK LAYER
P: Ralf Baechle
M: ralf@linux-mips.org
@@ -512,11 +516,11 @@ W: http://linuxppc64.org
S: Supported
BTTV VIDEO4LINUX DRIVER
-P: Gerd Knorr
-M: kraxel@bytesex.org
+P: Mauro Carvalho Chehab
+M: mchehab@brturbo.com.br
L: video4linux-list@redhat.com
-W: http://bytesex.org/bttv/
-S: Orphan
+W: http://linuxtv.org
+S: Maintained
BUSLOGIC SCSI DRIVER
P: Leonard N. Zubkoff
@@ -576,10 +580,9 @@ S: Supported
COMPUTONE INTELLIPORT MULTIPORT CARD
P: Michael H. Warfield
-M: Michael H. Warfield <mhw@wittsend.com>
+M: mhw@wittsend.com
W: http://www.wittsend.com/computone.html
-L: linux-computone@lazuli.wittsend.com
-S: Orphaned
+S: Maintained
COSA/SRP SYNC SERIAL DRIVER
P: Jan "Yenya" Kasprzak
@@ -1150,7 +1153,7 @@ S: Maintained
INFINIBAND SUBSYSTEM
P: Roland Dreier
-M: roland@topspin.com
+M: rolandd@cisco.com
P: Sean Hefty
M: mshefty@ichips.intel.com
P: Hal Rosenstock
@@ -1237,7 +1240,7 @@ S: Maintained
IRDA SUBSYSTEM
P: Jean Tourrilhes
-L: irda-users@lists.sourceforge.net
+L: irda-users@lists.sourceforge.net (subscribers-only)
W: http://irda.sourceforge.net/
S: Maintained
@@ -1330,6 +1333,16 @@ M: rml@novell.com
L: linux-kernel@vger.kernel.org
S: Maintained
+KEXEC
+P: Eric Biederman
+P: Randy Dunlap
+M: ebiederm@xmission.com
+M: rddunlap@osdl.org
+W: http://www.xmission.com/~ebiederm/files/kexec/
+L: linux-kernel@vger.kernel.org
+L: fastboot@osdl.org
+S: Maintained
+
LANMEDIA WAN CARD DRIVER
P: Andrew Stanley-Jones
M: asj@lanmedia.com
@@ -1794,8 +1807,9 @@ M: greg@kroah.com
S: Maintained
PCMCIA SUBSYSTEM
+P: Linux PCMCIA Team
L: http://lists.infradead.org/mailman/listinfo/linux-pcmcia
-S: Unmaintained
+S: Maintained
PCNET32 NETWORK DRIVER
P: Thomas Bogendörfer
@@ -2115,9 +2129,7 @@ S: Maintained
SOFTWARE SUSPEND:
P: Pavel Machek
M: pavel@suse.cz
-M: pavel@ucw.cz
-L: http://lister.fornax.hu/mailman/listinfo/swsusp
-W: http://swsusp.sf.net/
+L: linux-pm@osdl.org
S: Maintained
SONIC NETWORK DRIVER
@@ -2145,11 +2157,16 @@ W: http://tpmdd.sourceforge.net
L: tpmdd-devel@lists.sourceforge.net
S: Maintained
+TENSILICA XTENSA PORT (xtensa):
+P: Chris Zankel
+M: chris@zankel.net
+S: Maintained
+
UltraSPARC (sparc64):
P: David S. Miller
M: davem@davemloft.net
P: Eddie C. Dost
-M: ecd@skynet.be
+M: ecd@brainaid.de
P: Jakub Jelinek
M: jj@sunsite.ms.mff.cuni.cz
P: Anton Blanchard
@@ -2589,7 +2606,7 @@ M: davidm@snapgear.com
P: D. Jeff Dionne (created first uClinux port)
M: jeff@uclinux.org
W: http://www.uclinux.org/
-L: uclinux-dev@uclinux.org
+L: uclinux-dev@uclinux.org (subscribers-only)
S: Maintained
UCLINUX FOR NEC V850
@@ -2613,10 +2630,11 @@ W: http://rio500.sourceforge.net
S: Maintained
VIDEO FOR LINUX
-P: Gerd Knorr
-M: kraxel@bytesex.org
+P: Mauro Carvalho Chehab
+M: mchehab@brturbo.com.br
L: video4linux-list@redhat.com
-S: Orphan
+W: http://linuxtv.org
+S: Maintained
W1 DALLAS'S 1-WIRE BUS
P: Evgeniy Polyakov
diff --git a/Makefile b/Makefile
index fad349724e99..cf34a6b5c6eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 2
PATCHLEVEL = 6
-SUBLEVEL = 12
-EXTRAVERSION =
+SUBLEVEL = 13
+EXTRAVERSION =-rc3
NAME=Woozy Numbat
# *DOCUMENTATION*
@@ -281,7 +281,7 @@ export quiet Q KBUILD_VERBOSE
# See documentation in Documentation/kbuild/makefiles.txt
# cc-option
-# Usage: cflags-y += $(call gcc-option, -march=winchip-c6, -march=i586)
+# Usage: cflags-y += $(call cc-option, -march=winchip-c6, -march=i586)
cc-option = $(shell if $(CC) $(CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
> /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
@@ -792,6 +792,9 @@ export CPPFLAGS_vmlinux.lds += -P -C -U$(ARCH)
$(Q)$(MAKE) $(build)=$(@D) $@
%.o: %.c scripts FORCE
$(Q)$(MAKE) $(build)=$(@D) $@
+%.ko: scripts FORCE
+ $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D) $(@:.ko=.o)
+ $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost
%/: scripts prepare FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) $(build)=$(@D)
%.lst: %.c scripts FORCE
@@ -1033,6 +1036,7 @@ help:
@echo ' modules_install - Install all modules'
@echo ' dir/ - Build all files in dir and below'
@echo ' dir/file.[ois] - Build specified target only'
+ @echo ' dir/file.ko - Build module including final link'
@echo ' rpm - Build a kernel as an RPM package'
@echo ' tags/TAGS - Generate tags file for editors'
@echo ' cscope - Generate cscope index'
@@ -1149,7 +1153,7 @@ endif # KBUILD_EXTMOD
#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file.
#Adding $(srctree) adds about 20M on i386 to the size of the output file!
-ifeq ($(KBUILD_OUTPUT),)
+ifeq ($(src),$(obj))
__srctree =
else
__srctree = $(srctree)/
diff --git a/arch/alpha/Kconfig b/arch/alpha/Kconfig
index c5739d6309df..083c5df42d35 100644
--- a/arch/alpha/Kconfig
+++ b/arch/alpha/Kconfig
@@ -596,6 +596,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/alpha/kernel/irq_alpha.c b/arch/alpha/kernel/irq_alpha.c
index e6ded33c6e22..9d34ce26e5ef 100644
--- a/arch/alpha/kernel/irq_alpha.c
+++ b/arch/alpha/kernel/irq_alpha.c
@@ -55,6 +55,8 @@ do_entInt(unsigned long type, unsigned long vector,
#ifdef CONFIG_SMP
{
long cpu;
+
+ local_irq_disable();
smp_percpu_timer_interrupt(regs);
cpu = smp_processor_id();
if (cpu != boot_cpuid) {
diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c
index fd7bd17cc960..6f509a644bdd 100644
--- a/arch/alpha/kernel/traps.c
+++ b/arch/alpha/kernel/traps.c
@@ -240,7 +240,7 @@ do_entIF(unsigned long type, struct pt_regs *regs)
siginfo_t info;
int signo, code;
- if (regs->ps == 0) {
+ if ((regs->ps & ~IPL_MAX) == 0) {
if (type == 1) {
const unsigned int *data
= (const unsigned int *) regs->pc;
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 07ba77c19f6c..7bc4a583f4e1 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -157,7 +157,7 @@ config ARCH_RPC
config ARCH_SA1100
bool "SA1100-based"
select ISA
- select DISCONTIGMEM
+ select ARCH_DISCONTIGMEM_ENABLE
config ARCH_S3C2410
bool "Samsung S3C2410"
@@ -223,7 +223,9 @@ source "arch/arm/mach-pxa/Kconfig"
source "arch/arm/mach-sa1100/Kconfig"
-source "arch/arm/mach-omap/Kconfig"
+source "arch/arm/plat-omap/Kconfig"
+
+source "arch/arm/mach-omap1/Kconfig"
source "arch/arm/mach-s3c2410/Kconfig"
@@ -346,6 +348,26 @@ config PREEMPT
Say Y here if you are building a kernel for a desktop, embedded
or real-time system. Say N if you are unsure.
+config NO_IDLE_HZ
+ bool "Dynamic tick timer"
+ help
+ Select this option if you want to disable continuous timer ticks
+ and have them programmed to occur as required. This option saves
+ power as the system can remain in idle state for longer.
+
+ By default dynamic tick is disabled during the boot, and can be
+ manually enabled with:
+
+ echo 1 > /sys/devices/system/timer/timer0/dyn_tick
+
+ Alternatively, if you want dynamic tick automatically enabled
+ during boot, pass "dyntick=enable" via the kernel command string.
+
+ Please note that dynamic tick may affect the accuracy of
+ timekeeping on some platforms depending on the implementation.
+ Currently at least OMAP platform is known to have accurate
+ timekeeping with dynamic tick.
+
config ARCH_DISCONTIGMEM_ENABLE
bool
default (ARCH_LH7A40X && !LH7A40X_CONTIGMEM)
@@ -494,7 +516,7 @@ config XIP_PHYS_ADDR
endmenu
-if (ARCH_SA1100 || ARCH_INTEGRATOR)
+if (ARCH_SA1100 || ARCH_INTEGRATOR || ARCH_OMAP1)
menu "CPU Frequency scaling"
@@ -678,6 +700,8 @@ config APM
endmenu
+source "net/Kconfig"
+
menu "Device Drivers"
source "drivers/base/Kconfig"
@@ -710,7 +734,7 @@ source "drivers/ieee1394/Kconfig"
source "drivers/message/i2o/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
@@ -722,6 +746,8 @@ source "drivers/char/Kconfig"
source "drivers/i2c/Kconfig"
+source "drivers/hwmon/Kconfig"
+
#source "drivers/l3/Kconfig"
source "drivers/misc/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 8330495e2448..67f1453ade05 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -56,7 +56,7 @@ tune-$(CONFIG_CPU_XSCALE) :=$(call cc-option,-mtune=xscale,-mtune=strongarm110)
tune-$(CONFIG_CPU_V6) :=-mtune=strongarm
# Need -Uarm for gcc < 3.x
-CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu)
+CFLAGS_ABI :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
CFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) -msoft-float -Uarm
AFLAGS +=$(CFLAGS_ABI) $(arch-y) $(tune-y) -msoft-float
@@ -91,7 +91,8 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0xc0008000
machine-$(CONFIG_ARCH_IOP3XX) := iop3xx
machine-$(CONFIG_ARCH_IXP4XX) := ixp4xx
machine-$(CONFIG_ARCH_IXP2000) := ixp2000
- machine-$(CONFIG_ARCH_OMAP) := omap
+ machine-$(CONFIG_ARCH_OMAP1) := omap1
+ incdir-$(CONFIG_ARCH_OMAP) := omap
machine-$(CONFIG_ARCH_S3C2410) := s3c2410
machine-$(CONFIG_ARCH_LH7A40X) := lh7a40x
machine-$(CONFIG_ARCH_VERSATILE) := versatile
@@ -142,6 +143,9 @@ core-$(CONFIG_FPE_NWFPE) += arch/arm/nwfpe/
core-$(CONFIG_FPE_FASTFPE) += $(FASTFPE_OBJ)
core-$(CONFIG_VFP) += arch/arm/vfp/
+# If we have a common platform directory, then include it in the build.
+core-$(CONFIG_ARCH_OMAP) += arch/arm/plat-omap/
+
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
drivers-$(CONFIG_ARCH_CLPS7500) += drivers/acorn/char/
drivers-$(CONFIG_ARCH_L7200) += drivers/acorn/char/
diff --git a/arch/arm/configs/enp2611_defconfig b/arch/arm/configs/enp2611_defconfig
index 06fae4b62774..f67ca01b4982 100644
--- a/arch/arm/configs/enp2611_defconfig
+++ b/arch/arm/configs/enp2611_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:08:24 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul 7 16:41:21 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -96,6 +99,7 @@ CONFIG_ARCH_ENP2611=y
# CONFIG_ARCH_IXDP2800 is not set
# CONFIG_ARCH_IXDP2401 is not set
# CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
#
# Processor Type
@@ -106,7 +110,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -118,9 +121,11 @@ CONFIG_XSCALE_PMU=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -130,7 +135,16 @@ CONFIG_PCI_NAMES=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -269,7 +283,6 @@ CONFIG_MTD_IXP2000=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -308,6 +321,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -329,12 +343,12 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -349,6 +363,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -404,6 +420,7 @@ CONFIG_MII=y
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -440,9 +457,11 @@ CONFIG_EEPRO100=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -464,6 +483,7 @@ CONFIG_EEPRO100=y
# Wan interfaces
#
CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=y
@@ -526,7 +546,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -547,6 +566,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -613,17 +633,18 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_IXP2000 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
@@ -637,7 +658,9 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -653,6 +676,7 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -662,14 +686,19 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -723,6 +752,7 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -763,7 +793,6 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -801,12 +830,14 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/arm/configs/ixdp2400_defconfig b/arch/arm/configs/ixdp2400_defconfig
index 810a450a55d2..5c6c928215d0 100644
--- a/arch/arm/configs/ixdp2400_defconfig
+++ b/arch/arm/configs/ixdp2400_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 21:13:38 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul 7 16:49:01 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2400=y
CONFIG_ARCH_IXDP2X00=y
# CONFIG_ARCH_IXDP2401 is not set
# CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
#
# Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,16 @@ CONFIG_PCI_NAMES=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -270,7 +284,6 @@ CONFIG_MTD_IXP2000=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +322,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -330,12 +344,12 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -350,6 +364,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -405,6 +421,7 @@ CONFIG_MII=y
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -441,9 +458,11 @@ CONFIG_EEPRO100=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -465,6 +484,7 @@ CONFIG_EEPRO100=y
# Wan interfaces
#
CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=y
@@ -527,7 +547,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -548,6 +567,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -614,17 +634,18 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_IXP2000 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
@@ -638,7 +659,9 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -654,6 +677,7 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -663,14 +687,19 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -724,6 +753,7 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -764,7 +794,6 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -802,12 +831,14 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/arm/configs/ixdp2401_defconfig b/arch/arm/configs/ixdp2401_defconfig
index 72e1b940e975..6dc40f6be0ef 100644
--- a/arch/arm/configs/ixdp2401_defconfig
+++ b/arch/arm/configs/ixdp2401_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 21:53:55 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul 7 16:49:08 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
CONFIG_ARCH_IXDP2401=y
# CONFIG_ARCH_IXDP2801 is not set
CONFIG_ARCH_IXDP2X01=y
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
#
# Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,16 @@ CONFIG_PCI_NAMES=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -270,7 +284,6 @@ CONFIG_MTD_IXP2000=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +322,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -330,12 +344,12 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -350,6 +364,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -405,6 +421,7 @@ CONFIG_MII=y
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -442,9 +459,11 @@ CONFIG_EEPRO100=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -466,6 +485,7 @@ CONFIG_EEPRO100=y
# Wan interfaces
#
CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=y
@@ -528,7 +548,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -549,6 +568,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -615,17 +635,18 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_IXP2000 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
@@ -639,7 +660,9 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -655,6 +678,7 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -664,14 +688,19 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -725,6 +754,7 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -765,7 +795,6 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -803,12 +832,14 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/arm/configs/ixdp2800_defconfig b/arch/arm/configs/ixdp2800_defconfig
index 1592e45f0278..d2bb0b7153fe 100644
--- a/arch/arm/configs/ixdp2800_defconfig
+++ b/arch/arm/configs/ixdp2800_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:15:23 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul 7 16:49:20 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -97,6 +100,7 @@ CONFIG_ARCH_IXDP2800=y
CONFIG_ARCH_IXDP2X00=y
# CONFIG_ARCH_IXDP2401 is not set
# CONFIG_ARCH_IXDP2801 is not set
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
#
# Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,16 @@ CONFIG_PCI_NAMES=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -270,7 +284,6 @@ CONFIG_MTD_IXP2000=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +322,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -330,12 +344,12 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -350,6 +364,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -405,6 +421,7 @@ CONFIG_MII=y
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -441,9 +458,11 @@ CONFIG_EEPRO100=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -465,6 +484,7 @@ CONFIG_EEPRO100=y
# Wan interfaces
#
CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=y
@@ -527,7 +547,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -548,6 +567,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -614,17 +634,18 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_IXP2000 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
@@ -638,7 +659,9 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -654,6 +677,7 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -663,14 +687,19 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -724,6 +753,7 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -764,7 +794,6 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -802,12 +831,14 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/arm/configs/ixdp2801_defconfig b/arch/arm/configs/ixdp2801_defconfig
index f1afe3d09ec6..2d6f960e3395 100644
--- a/arch/arm/configs/ixdp2801_defconfig
+++ b/arch/arm/configs/ixdp2801_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 22:39:19 2005
+# Linux kernel version: 2.6.13-rc2
+# Thu Jul 7 16:49:13 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -16,6 +15,7 @@ CONFIG_GENERIC_IOMAP=y
CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_EMBEDDED=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,6 +84,7 @@ CONFIG_ARCH_IXP2000=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
#
@@ -97,6 +100,7 @@ CONFIG_ARCH_SUPPORTS_BIG_ENDIAN=y
# CONFIG_ARCH_IXDP2401 is not set
CONFIG_ARCH_IXDP2801=y
CONFIG_ARCH_IXDP2X01=y
+# CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO is not set
#
# Processor Type
@@ -107,7 +111,6 @@ CONFIG_CPU_32v5=y
CONFIG_CPU_ABRT_EV5T=y
CONFIG_CPU_CACHE_VIVT=y
CONFIG_CPU_TLB_V4WBI=y
-CONFIG_CPU_MINICACHE=y
#
# Processor Features
@@ -119,9 +122,11 @@ CONFIG_XSCALE_PMU=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
CONFIG_PCI=y
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCCARD (PCMCIA/CardBus) support
@@ -131,7 +136,16 @@ CONFIG_PCI_NAMES=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_ALIGNMENT_TRAP=y
#
@@ -270,7 +284,6 @@ CONFIG_MTD_IXP2000=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_CPQ_DA is not set
# CONFIG_BLK_CPQ_CISS_DA is not set
# CONFIG_BLK_DEV_DAC960 is not set
@@ -309,6 +322,7 @@ CONFIG_IOSCHED_CFQ=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -330,12 +344,12 @@ CONFIG_NET=y
#
CONFIG_PACKET=y
CONFIG_PACKET_MMAP=y
-# CONFIG_NETLINK_DEV is not set
CONFIG_UNIX=y
# CONFIG_NET_KEY is not set
CONFIG_INET=y
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -350,6 +364,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -405,6 +421,7 @@ CONFIG_MII=y
# CONFIG_SUNGEM is not set
# CONFIG_NET_VENDOR_3COM is not set
# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
#
# Tulip family network device support
@@ -442,9 +459,11 @@ CONFIG_EEPRO100=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -466,6 +485,7 @@ CONFIG_EEPRO100=y
# Wan interfaces
#
CONFIG_WAN=y
+# CONFIG_DSCC4 is not set
# CONFIG_LANMEDIA is not set
# CONFIG_SYNCLINK_SYNCPPP is not set
CONFIG_HDLC=y
@@ -528,7 +548,6 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
#
# CONFIG_SERIO is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -549,6 +568,7 @@ CONFIG_SERIAL_8250_NR_UARTS=2
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -615,17 +635,18 @@ CONFIG_I2C_ALGOBIT=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_IXP2000 is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
-# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_PROSAVAGE is not set
# CONFIG_I2C_SAVAGE4 is not set
# CONFIG_SCx200_ACB is not set
# CONFIG_I2C_SIS5595 is not set
# CONFIG_I2C_SIS630 is not set
# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_STUB is not set
# CONFIG_I2C_VIA is not set
# CONFIG_I2C_VIAPRO is not set
# CONFIG_I2C_VOODOO3 is not set
@@ -639,7 +660,9 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -655,6 +678,7 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -664,14 +688,19 @@ CONFIG_I2C_SENSOR=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
CONFIG_SENSORS_EEPROM=y
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -725,6 +754,7 @@ CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -765,7 +795,6 @@ CONFIG_DNOTIFY=y
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
@@ -803,12 +832,14 @@ CONFIG_JFFS2_RTIME=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
# CONFIG_NFS_V4 is not set
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
# CONFIG_RPCSEC_GSS_KRB5 is not set
# CONFIG_RPCSEC_GSS_SPKM3 is not set
diff --git a/arch/arm/configs/omap_h2_1610_defconfig b/arch/arm/configs/omap_h2_1610_defconfig
index 4e58d9341bce..24955263b096 100644
--- a/arch/arm/configs/omap_h2_1610_defconfig
+++ b/arch/arm/configs/omap_h2_1610_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 17:52:41 2005
+# Linux kernel version: 2.6.13-rc2
+# Fri Jul 8 04:49:34 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -17,6 +16,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_CLEAN_COMPILE=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -33,8 +33,9 @@ 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_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -82,10 +83,28 @@ CONFIG_ARCH_OMAP=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
#
# TI OMAP Implementations
#
+CONFIG_ARCH_OMAP_OTG=y
+CONFIG_ARCH_OMAP1=y
+# CONFIG_ARCH_OMAP2 is not set
+
+#
+# OMAP Feature Selections
+#
+# CONFIG_OMAP_RESET_CLOCKS is not set
+CONFIG_OMAP_MUX=y
+# CONFIG_OMAP_MUX_DEBUG is not set
+CONFIG_OMAP_MUX_WARNINGS=y
+# CONFIG_OMAP_MPU_TIMER is not set
+CONFIG_OMAP_32K_TIMER=y
+CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_LL_DEBUG_UART1=y
+# CONFIG_OMAP_LL_DEBUG_UART2 is not set
+# CONFIG_OMAP_LL_DEBUG_UART3 is not set
#
# OMAP Core Type
@@ -93,7 +112,6 @@ CONFIG_ARCH_OMAP=y
# CONFIG_ARCH_OMAP730 is not set
# CONFIG_ARCH_OMAP1510 is not set
CONFIG_ARCH_OMAP16XX=y
-CONFIG_ARCH_OMAP_OTG=y
#
# OMAP Board Type
@@ -101,21 +119,14 @@ CONFIG_ARCH_OMAP_OTG=y
# CONFIG_MACH_OMAP_INNOVATOR is not set
CONFIG_MACH_OMAP_H2=y
# CONFIG_MACH_OMAP_H3 is not set
-# CONFIG_MACH_OMAP_H4 is not set
# CONFIG_MACH_OMAP_OSK is not set
# CONFIG_MACH_OMAP_GENERIC is not set
#
-# OMAP Feature Selections
+# OMAP CPU Speed
#
-CONFIG_OMAP_MUX=y
-# CONFIG_OMAP_MUX_DEBUG is not set
-CONFIG_OMAP_MUX_WARNINGS=y
-CONFIG_OMAP_MPU_TIMER=y
-# CONFIG_OMAP_32K_TIMER is not set
-CONFIG_OMAP_LL_DEBUG_UART1=y
-# CONFIG_OMAP_LL_DEBUG_UART2 is not set
-# CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER is not set
+# CONFIG_OMAP_ARM_216MHZ is not set
CONFIG_OMAP_ARM_192MHZ=y
# CONFIG_OMAP_ARM_168MHZ is not set
# CONFIG_OMAP_ARM_120MHZ is not set
@@ -145,6 +156,7 @@ CONFIG_ARM_THUMB=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
#
# PCCARD (PCMCIA/CardBus) support
@@ -154,7 +166,16 @@ CONFIG_ARM_THUMB=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
CONFIG_PREEMPT=y
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
# CONFIG_LEDS is not set
CONFIG_ALIGNMENT_TRAP=y
@@ -167,6 +188,22 @@ CONFIG_CMDLINE="mem=32M console=ttyS0,115200n8 root=0801 ro init=/bin/sh"
# CONFIG_XIP_KERNEL is not set
#
+# CPU Frequency scaling
+#
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_PERFORMANCE is not set
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+
+#
# Floating point emulation
#
@@ -202,7 +239,6 @@ CONFIG_PM=y
CONFIG_STANDALONE=y
CONFIG_PREVENT_FIRMWARE_BUILD=y
# CONFIG_FW_LOADER is not set
-CONFIG_DEBUG_DRIVER=y
#
# Memory Technology Devices (MTD)
@@ -292,7 +328,6 @@ CONFIG_MTD_CFI_UTIL=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
@@ -327,6 +362,7 @@ CONFIG_SCSI_PROC_FS=y
# CONFIG_CHR_DEV_OSST is not set
# CONFIG_BLK_DEV_SR is not set
# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -356,6 +392,7 @@ CONFIG_SCSI_PROC_FS=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -375,12 +412,12 @@ CONFIG_NET=y
#
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_FIB_HASH=y
CONFIG_IP_PNP=y
CONFIG_IP_PNP_DHCP=y
CONFIG_IP_PNP_BOOTP=y
@@ -395,6 +432,8 @@ CONFIG_IP_PNP_BOOTP=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -442,6 +481,7 @@ CONFIG_NETDEVICES=y
CONFIG_NET_ETHERNET=y
CONFIG_MII=y
CONFIG_SMC91X=y
+# CONFIG_DM9000 is not set
#
# Ethernet (1000 Mbit)
@@ -518,7 +558,6 @@ CONFIG_SERIO=y
CONFIG_SERIO_SERPORT=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -567,13 +606,11 @@ CONFIG_WATCHDOG_NOWAYOUT=y
#
# Ftape, the floppy tape device driver
#
-# CONFIG_DRM is not set
# CONFIG_RAW_DRIVER is not set
#
# TPM devices
#
-# CONFIG_TCG_TPM is not set
#
# I2C support
@@ -604,7 +641,9 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
# CONFIG_SENSORS_FSCPOS is not set
@@ -620,6 +659,7 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -627,15 +667,21 @@ CONFIG_I2C_CHARDEV=y
# CONFIG_SENSORS_W83781D is not set
# CONFIG_SENSORS_W83L785TS is not set
# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
CONFIG_ISP1301_OMAP=y
+CONFIG_TPS65010=y
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -663,8 +709,10 @@ CONFIG_FB=y
# CONFIG_FB_CFB_COPYAREA is not set
# CONFIG_FB_CFB_IMAGEBLIT is not set
# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -677,11 +725,13 @@ CONFIG_FONTS=y
CONFIG_FONT_8x8=y
CONFIG_FONT_8x16=y
# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
# CONFIG_FONT_PEARL_8x8 is not set
# CONFIG_FONT_ACORN_8x8 is not set
# CONFIG_FONT_MINI_4x6 is not set
# CONFIG_FONT_SUN8x16 is not set
# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
#
# Logo configuration
@@ -729,14 +779,14 @@ CONFIG_USB_ARCH_HAS_OHCI=y
#
CONFIG_USB_GADGET=y
# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
# CONFIG_USB_GADGET_NET2280 is not set
# CONFIG_USB_GADGET_PXA2XX is not set
# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_SA1100 is not set
# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
CONFIG_USB_GADGET_OMAP=y
CONFIG_USB_OMAP=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
# CONFIG_USB_GADGET_DUALSPEED is not set
# CONFIG_USB_ZERO is not set
CONFIG_USB_ETH=y
@@ -755,6 +805,7 @@ CONFIG_USB_ETH_RNDIS=y
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
# CONFIG_EXT3_FS is not set
# CONFIG_JBD is not set
# CONFIG_REISERFS_FS is not set
@@ -791,7 +842,6 @@ CONFIG_FAT_DEFAULT_CODEPAGE=437
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLB_PAGE is not set
@@ -828,12 +878,14 @@ CONFIG_CRAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
# CONFIG_NFSD is not set
CONFIG_ROOT_NFS=y
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
@@ -903,24 +955,11 @@ CONFIG_NLS_DEFAULT="iso8859-1"
# Kernel hacking
#
# CONFIG_PRINTK_TIME is not set
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_KERNEL is not set
CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
-CONFIG_DEBUG_PREEMPT=y
-# CONFIG_DEBUG_SPINLOCK is not set
-# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
-# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-CONFIG_DEBUG_USER=y
-# CONFIG_DEBUG_WAITQ is not set
-CONFIG_DEBUG_ERRORS=y
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_USER is not set
#
# Security options
diff --git a/arch/arm/configs/omnimeter_defconfig b/arch/arm/configs/omnimeter_defconfig
deleted file mode 100644
index 78fdb4a428b1..000000000000
--- a/arch/arm/configs/omnimeter_defconfig
+++ /dev/null
@@ -1,803 +0,0 @@
-#
-# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 21:31:45 2005
-#
-CONFIG_ARM=y
-CONFIG_MMU=y
-CONFIG_UID16=y
-CONFIG_RWSEM_GENERIC_SPINLOCK=y
-CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
-
-#
-# Code maturity level options
-#
-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_HOTPLUG=y
-CONFIG_KOBJECT_UEVENT=y
-# CONFIG_IKCONFIG is not set
-# CONFIG_EMBEDDED is not set
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
-CONFIG_BASE_FULL=y
-CONFIG_FUTEX=y
-CONFIG_EPOLL=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SHMEM=y
-CONFIG_CC_ALIGN_FUNCTIONS=0
-CONFIG_CC_ALIGN_LABELS=0
-CONFIG_CC_ALIGN_LOOPS=0
-CONFIG_CC_ALIGN_JUMPS=0
-# CONFIG_TINY_SHMEM is not set
-CONFIG_BASE_SMALL=0
-
-#
-# Loadable module support
-#
-CONFIG_MODULES=y
-# CONFIG_MODULE_UNLOAD is not set
-CONFIG_OBSOLETE_MODPARM=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
-
-#
-# System Type
-#
-# CONFIG_ARCH_CLPS7500 is not set
-# CONFIG_ARCH_CLPS711X is not set
-# CONFIG_ARCH_CO285 is not set
-# CONFIG_ARCH_EBSA110 is not set
-# CONFIG_ARCH_CAMELOT is not set
-# CONFIG_ARCH_FOOTBRIDGE is not set
-# CONFIG_ARCH_INTEGRATOR is not set
-# CONFIG_ARCH_IOP3XX is not set
-# CONFIG_ARCH_IXP4XX is not set
-# CONFIG_ARCH_IXP2000 is not set
-# CONFIG_ARCH_L7200 is not set
-# CONFIG_ARCH_PXA is not set
-# CONFIG_ARCH_RPC is not set
-CONFIG_ARCH_SA1100=y
-# CONFIG_ARCH_S3C2410 is not set
-# CONFIG_ARCH_SHARK is not set
-# CONFIG_ARCH_LH7A40X is not set
-# CONFIG_ARCH_OMAP is not set
-# CONFIG_ARCH_VERSATILE is not set
-# CONFIG_ARCH_IMX is not set
-# CONFIG_ARCH_H720X is not set
-
-#
-# SA11x0 Implementations
-#
-# CONFIG_SA1100_ASSABET is not set
-# CONFIG_SA1100_CERF is not set
-# CONFIG_SA1100_COLLIE is not set
-# CONFIG_SA1100_H3100 is not set
-# CONFIG_SA1100_H3600 is not set
-# CONFIG_SA1100_H3800 is not set
-# CONFIG_SA1100_BADGE4 is not set
-# CONFIG_SA1100_JORNADA720 is not set
-# CONFIG_SA1100_HACKKIT is not set
-# CONFIG_SA1100_LART is not set
-# CONFIG_SA1100_PLEB is not set
-# CONFIG_SA1100_SHANNON is not set
-# CONFIG_SA1100_SIMPAD is not set
-# CONFIG_SA1100_SSP is not set
-
-#
-# Processor Type
-#
-CONFIG_CPU_32=y
-CONFIG_CPU_SA1100=y
-CONFIG_CPU_32v4=y
-CONFIG_CPU_ABRT_EV4=y
-CONFIG_CPU_CACHE_V4WB=y
-CONFIG_CPU_CACHE_VIVT=y
-CONFIG_CPU_TLB_V4WB=y
-CONFIG_CPU_MINICACHE=y
-
-#
-# Processor Features
-#
-
-#
-# Bus support
-#
-CONFIG_ISA=y
-
-#
-# PCCARD (PCMCIA/CardBus) support
-#
-CONFIG_PCCARD=y
-# CONFIG_PCMCIA_DEBUG is not set
-CONFIG_PCMCIA=y
-
-#
-# PC-card bridges
-#
-CONFIG_I82365=y
-# CONFIG_TCIC is not set
-CONFIG_PCMCIA_SA1100=y
-CONFIG_PCCARD_NONSTATIC=y
-
-#
-# Kernel Features
-#
-# CONFIG_PREEMPT is not set
-CONFIG_DISCONTIGMEM=y
-# CONFIG_LEDS is not set
-CONFIG_ALIGNMENT_TRAP=y
-
-#
-# Boot options
-#
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="keepinitrd mem=16M root=/dev/ram ramdisk=8192 initrd=0xd0000000,4M"
-# CONFIG_XIP_KERNEL is not set
-
-#
-# CPU Frequency scaling
-#
-# CONFIG_CPU_FREQ is not set
-
-#
-# Floating point emulation
-#
-
-#
-# At least one emulation must be selected
-#
-# CONFIG_FPE_NWFPE is not set
-# CONFIG_FPE_FASTFPE is not set
-
-#
-# Userspace binary formats
-#
-CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=y
-# CONFIG_BINFMT_MISC is not set
-# CONFIG_ARTHUR is not set
-
-#
-# Power management options
-#
-# CONFIG_PM 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
-#
-# CONFIG_PNP is not set
-
-#
-# Block devices
-#
-# CONFIG_BLK_DEV_FD is not set
-# CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
-# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_RAM is not set
-CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_INITRAMFS_SOURCE=""
-# CONFIG_CDROM_PKTCDVD is not set
-
-#
-# IO Schedulers
-#
-CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=y
-CONFIG_IOSCHED_DEADLINE=y
-CONFIG_IOSCHED_CFQ=y
-# CONFIG_ATA_OVER_ETH 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 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_IDE_TASK_IOCTL is not set
-
-#
-# IDE chipset support/bugfixes
-#
-CONFIG_IDE_GENERIC=y
-# CONFIG_IDE_ARM is not set
-# CONFIG_IDE_CHIPSETS 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
-#
-
-#
-# I2O device support
-#
-
-#
-# 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=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 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_IP_TCPDIAG=y
-# CONFIG_IP_TCPDIAG_IPV6 is not set
-
-#
-# IP: Virtual Server Configuration
-#
-# CONFIG_IP_VS is not set
-# CONFIG_IPV6 is not set
-CONFIG_NETFILTER=y
-# CONFIG_NETFILTER_DEBUG is not set
-
-#
-# IP: Netfilter Configuration
-#
-# CONFIG_IP_NF_CONNTRACK is not set
-# CONFIG_IP_NF_CONNTRACK_MARK is not set
-# CONFIG_IP_NF_QUEUE is not set
-# CONFIG_IP_NF_IPTABLES is not set
-# CONFIG_IP_NF_ARPTABLES 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
-
-#
-# 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
-
-#
-# Ethernet (10 or 100Mbit)
-#
-CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_SMC91X is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_AT1700 is not set
-# CONFIG_DEPCA is not set
-# CONFIG_HP100 is not set
-# CONFIG_NET_ISA is not set
-# CONFIG_NET_PCI is not set
-# CONFIG_NET_POCKET is not set
-
-#
-# Ethernet (1000 Mbit)
-#
-
-#
-# Ethernet (10000 Mbit)
-#
-
-#
-# Token Ring devices
-#
-# CONFIG_TR is not set
-
-#
-# Wireless LAN (non-hamradio)
-#
-CONFIG_NET_RADIO=y
-
-#
-# Obsolete Wireless cards support (pre-802.11)
-#
-# CONFIG_STRIP is not set
-# CONFIG_ARLAN is not set
-# CONFIG_WAVELAN is not set
-CONFIG_PCMCIA_WAVELAN=y
-# CONFIG_PCMCIA_NETWAVE is not set
-
-#
-# Wireless 802.11 Frequency Hopping cards support
-#
-# CONFIG_PCMCIA_RAYCS is not set
-
-#
-# Wireless 802.11b ISA/PCI cards support
-#
-# CONFIG_HERMES is not set
-# CONFIG_ATMEL is not set
-
-#
-# Wireless 802.11b Pcmcia/Cardbus cards support
-#
-CONFIG_AIRO_CS=y
-CONFIG_PCMCIA_WL3501=y
-CONFIG_NET_WIRELESS=y
-
-#
-# PCMCIA network device support
-#
-CONFIG_NET_PCMCIA=y
-CONFIG_PCMCIA_3C589=y
-# CONFIG_PCMCIA_3C574 is not set
-# CONFIG_PCMCIA_FMVJ18X is not set
-CONFIG_PCMCIA_PCNET=y
-# CONFIG_PCMCIA_NMCLAN is not set
-# CONFIG_PCMCIA_SMC91C92 is not set
-# CONFIG_PCMCIA_XIRC2PS is not set
-# CONFIG_PCMCIA_AXNET is not set
-
-#
-# Wan interfaces
-#
-# CONFIG_WAN is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_SHAPER is not set
-# CONFIG_NETCONSOLE is not set
-
-#
-# ISDN subsystem
-#
-# CONFIG_ISDN 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 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_INPORT is not set
-# CONFIG_MOUSE_LOGIBM is not set
-# CONFIG_MOUSE_PC110PAD 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
-
-#
-# Hardware I/O ports
-#
-CONFIG_SERIO=y
-CONFIG_SERIO_SERPORT=y
-CONFIG_SERIO_LIBPS2=y
-# CONFIG_SERIO_RAW is not set
-# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
-
-#
-# 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_SA1100=y
-CONFIG_SERIAL_SA1100_CONSOLE=y
-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_NVRAM is not set
-# CONFIG_RTC is not set
-# CONFIG_DTLK is not set
-# CONFIG_R3964 is not set
-
-#
-# Ftape, the floppy tape device driver
-#
-# CONFIG_DRM is not set
-
-#
-# PCMCIA character devices
-#
-# CONFIG_SYNCLINK_CS is not set
-# CONFIG_RAW_DRIVER is not set
-
-#
-# TPM devices
-#
-# CONFIG_TCG_TPM is not set
-
-#
-# I2C support
-#
-# CONFIG_I2C 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=y
-CONFIG_FB_CFB_FILLRECT=y
-CONFIG_FB_CFB_COPYAREA=y
-CONFIG_FB_CFB_IMAGEBLIT=y
-CONFIG_FB_SOFT_CURSOR=y
-# CONFIG_FB_MODE_HELPERS is not set
-# CONFIG_FB_TILEBLITTING is not set
-CONFIG_FB_SA1100=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=y
-CONFIG_FONT_8x8=y
-# CONFIG_FONT_8x16 is not set
-# CONFIG_FONT_6x11 is not set
-# CONFIG_FONT_PEARL_8x8 is not set
-# CONFIG_FONT_ACORN_8x8 is not set
-# CONFIG_FONT_MINI_4x6 is not set
-# CONFIG_FONT_SUN8x16 is not set
-# CONFIG_FONT_SUN12x22 is not set
-
-#
-# Logo configuration
-#
-# CONFIG_LOGO is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
-
-#
-# Sound
-#
-# CONFIG_SOUND is not set
-
-#
-# USB support
-#
-CONFIG_USB_ARCH_HAS_HCD=y
-# CONFIG_USB_ARCH_HAS_OHCI is not set
-# CONFIG_USB is not set
-
-#
-# USB Gadget Support
-#
-# CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
-# CONFIG_MMC 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
-
-#
-# XFS support
-#
-# CONFIG_XFS_FS is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
-CONFIG_DNOTIFY=y
-# 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_FAT_FS=y
-CONFIG_MSDOS_FS=y
-# CONFIG_VFAT_FS is not set
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-# CONFIG_NTFS_FS is not set
-
-#
-# Pseudo filesystems
-#
-CONFIG_PROC_FS=y
-CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVPTS_FS_XATTR is not set
-# 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 is not set
-# CONFIG_NFS_V4 is not set
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=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
-# 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_PRINTK_TIME is not set
-# CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_DEBUG_BUGVERBOSE=y
-CONFIG_FRAME_POINTER=y
-# CONFIG_DEBUG_USER is not set
-
-#
-# Security options
-#
-# CONFIG_KEYS is not set
-# CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
-# CONFIG_CRYPTO is not set
-
-#
-# Hardware crypto devices
-#
-
-#
-# Library routines
-#
-# CONFIG_CRC_CCITT is not set
-CONFIG_CRC32=y
-# CONFIG_LIBCRC32C is not set
diff --git a/arch/arm/configs/s3c2410_defconfig b/arch/arm/configs/s3c2410_defconfig
index 2a63fb277196..98b72ff38832 100644
--- a/arch/arm/configs/s3c2410_defconfig
+++ b/arch/arm/configs/s3c2410_defconfig
@@ -1,14 +1,13 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc1-bk2
-# Sun Mar 27 17:47:45 2005
+# Linux kernel version: 2.6.12-git4
+# Wed Jun 22 15:56:42 2005
#
CONFIG_ARM=y
CONFIG_MMU=y
CONFIG_UID16=y
CONFIG_RWSEM_GENERIC_SPINLOCK=y
CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_GENERIC_IOMAP=y
#
# Code maturity level options
@@ -17,6 +16,7 @@ CONFIG_EXPERIMENTAL=y
# CONFIG_CLEAN_COMPILE is not set
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -35,6 +35,8 @@ CONFIG_KOBJECT_UEVENT=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -81,6 +83,7 @@ CONFIG_ARCH_S3C2410=y
# CONFIG_ARCH_VERSATILE is not set
# CONFIG_ARCH_IMX is not set
# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
#
# S3C24XX Implementations
@@ -134,6 +137,7 @@ CONFIG_CPU_TLB_V4WBI=y
#
# Bus support
#
+CONFIG_ISA_DMA_API=y
#
# PCCARD (PCMCIA/CardBus) support
@@ -143,7 +147,9 @@ CONFIG_CPU_TLB_V4WBI=y
#
# Kernel Features
#
+# CONFIG_SMP is not set
# CONFIG_PREEMPT is not set
+# CONFIG_DISCONTIGMEM is not set
CONFIG_ALIGNMENT_TRAP=y
#
@@ -297,7 +303,6 @@ CONFIG_PARPORT_1284=y
#
# Block devices
#
-# CONFIG_BLK_DEV_FD is not set
# CONFIG_PARIDE is not set
# CONFIG_BLK_DEV_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
@@ -359,6 +364,7 @@ CONFIG_BLK_DEV_IDE_BAST=y
#
# Fusion MPT device support
#
+# CONFIG_FUSION is not set
#
# IEEE 1394 (FireWire) support
@@ -378,10 +384,11 @@ 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_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
# CONFIG_IP_MULTICAST is not set
# CONFIG_IP_ADVANCED_ROUTER is not set
CONFIG_IP_PNP=y
@@ -443,8 +450,9 @@ CONFIG_NETDEVICES=y
# Ethernet (10 or 100Mbit)
#
CONFIG_NET_ETHERNET=y
-# CONFIG_MII is not set
+CONFIG_MII=m
# CONFIG_SMC91X is not set
+CONFIG_DM9000=m
#
# Ethernet (1000 Mbit)
@@ -521,7 +529,6 @@ CONFIG_SERIO_SERPORT=y
CONFIG_SERIO_LIBPS2=y
# CONFIG_SERIO_RAW is not set
# CONFIG_GAMEPORT is not set
-CONFIG_SOUND_GAMEPORT=y
#
# Character devices
@@ -605,7 +612,6 @@ CONFIG_S3C2410_RTC=y
#
# TPM devices
#
-# CONFIG_TCG_TPM is not set
#
# I2C support
@@ -654,6 +660,7 @@ CONFIG_SENSORS_LM78=m
CONFIG_SENSORS_LM85=m
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
# CONFIG_SENSORS_SMSC47B397 is not set
@@ -665,6 +672,7 @@ CONFIG_SENSORS_LM85=m
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
CONFIG_SENSORS_EEPROM=m
# CONFIG_SENSORS_PCF8574 is not set
# CONFIG_SENSORS_PCF8591 is not set
@@ -696,8 +704,10 @@ CONFIG_FB=y
# CONFIG_FB_CFB_COPYAREA is not set
# CONFIG_FB_CFB_IMAGEBLIT is not set
# CONFIG_FB_SOFT_CURSOR is not set
+# CONFIG_FB_MACMODES is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -782,7 +792,6 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
#
CONFIG_PROC_FS=y
CONFIG_SYSFS=y
-# CONFIG_DEVFS_FS is not set
# CONFIG_DEVPTS_FS_XATTR is not set
# CONFIG_TMPFS is not set
# CONFIG_HUGETLBFS is not set
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 4c38bd8bc298..835d450797a1 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -30,9 +30,6 @@ extern void __lshrdi3(void);
extern void __modsi3(void);
extern void __muldi3(void);
extern void __ucmpdi2(void);
-extern void __udivdi3(void);
-extern void __umoddi3(void);
-extern void __udivmoddi4(void);
extern void __udivsi3(void);
extern void __umodsi3(void);
extern void __do_div64(void);
@@ -44,7 +41,10 @@ extern void fp_enter(void);
* This has a special calling convention; it doesn't
* modify any of the usual registers, except for LR.
*/
+#define EXPORT_CRC_ALIAS(sym) __CRC_SYMBOL(sym, "")
+
#define EXPORT_SYMBOL_ALIAS(sym,orig) \
+ EXPORT_CRC_ALIAS(sym) \
const struct kernel_symbol __ksymtab_##sym \
__attribute__((section("__ksymtab"))) = \
{ (unsigned long)&orig, #sym };
@@ -134,9 +134,6 @@ 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);
EXPORT_SYMBOL(__do_div64);
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index bd4823c74645..1155cf07c871 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -344,9 +344,9 @@ __create_page_tables:
str r6, [r0]
#endif
+#ifdef CONFIG_DEBUG_LL
bic r7, r7, #0x0c @ turn off cacheable
@ and bufferable bits
-#ifdef CONFIG_DEBUG_LL
/*
* Map in IO space for serial debugging.
* This allows debug messages to be output
@@ -372,28 +372,24 @@ __create_page_tables:
teq r1, #MACH_TYPE_NETWINDER
teqne r1, #MACH_TYPE_CATS
bne 1f
- add r0, r4, #0x3fc0 @ ff000000
- mov r3, #0x7c000000
- orr r3, r3, r7
- str r3, [r0], #4
- add r3, r3, #1 << 20
- str r3, [r0], #4
+ add r0, r4, #0xff000000 >> 18
+ orr r3, r7, #0x7c000000
+ str r3, [r0]
1:
#endif
-#endif
#ifdef CONFIG_ARCH_RPC
/*
* Map in screen at 0x02000000 & SCREEN2_BASE
* Similar reasons here - for debug. This is
* only for Acorn RiscPC architectures.
*/
- add r0, r4, #0x80 @ 02000000
- mov r3, #0x02000000
- orr r3, r3, r7
+ add r0, r4, #0x02000000 >> 18
+ orr r3, r7, #0x02000000
str r3, [r0]
- add r0, r4, #0x3600 @ d8000000
+ add r0, r4, #0xd8000000 >> 18
str r3, [r0]
#endif
+#endif
mov pc, lr
.ltorg
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index ff187f4308f0..395137a8fad2 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -4,6 +4,10 @@
* Copyright (C) 1992 Linus Torvalds
* Modifications for ARM processor Copyright (C) 1995-2000 Russell King.
*
+ * Support for Dynamic Tick Timer Copyright (C) 2004-2005 Nokia Corporation.
+ * Dynamic Tick Timer written by Tony Lindgren <tony@atomide.com> and
+ * Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>.
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
@@ -37,6 +41,7 @@
#include <asm/irq.h>
#include <asm/system.h>
#include <asm/mach/irq.h>
+#include <asm/mach/time.h>
/*
* Maximum IRQ count. Currently, this is arbitary. However, it should
@@ -329,6 +334,15 @@ __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
spin_unlock(&irq_controller_lock);
+#ifdef CONFIG_NO_IDLE_HZ
+ if (!(action->flags & SA_TIMER) && system_timer->dyn_tick != NULL) {
+ write_seqlock(&xtime_lock);
+ if (system_timer->dyn_tick->state & DYN_TICK_ENABLED)
+ system_timer->dyn_tick->handler(irq, 0, regs);
+ write_sequnlock(&xtime_lock);
+ }
+#endif
+
if (!(action->flags & SA_INTERRUPT))
local_irq_enable();
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 8f146a4b4752..bbea636ff687 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -32,6 +32,7 @@
#include <asm/leds.h>
#include <asm/processor.h>
#include <asm/uaccess.h>
+#include <asm/mach/time.h>
extern const char *processor_modes[];
extern void setup_mm_for_reboot(char mode);
@@ -85,8 +86,10 @@ EXPORT_SYMBOL(pm_power_off);
void default_idle(void)
{
local_irq_disable();
- if (!need_resched() && !hlt_counter)
+ if (!need_resched() && !hlt_counter) {
+ timer_dyn_reprogram();
arch_idle();
+ }
local_irq_enable();
}
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 8cf733daa800..c9b69771f92e 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -359,7 +359,8 @@ void cpu_init(void)
"I" (offsetof(struct stack, abt[0])),
"I" (PSR_F_BIT | PSR_I_BIT | UND_MODE),
"I" (offsetof(struct stack, und[0])),
- "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE));
+ "I" (PSR_F_BIT | PSR_I_BIT | SVC_MODE)
+ : "r14");
}
static struct machine_desc * __init setup_machine(unsigned int nr)
@@ -736,8 +737,8 @@ void __init setup_arch(char **cmdline_p)
if (mdesc->soft_reboot)
reboot_setup("s");
- if (mdesc->param_offset)
- tags = phys_to_virt(mdesc->param_offset);
+ if (mdesc->boot_params)
+ tags = phys_to_virt(mdesc->boot_params);
/*
* If we have the old style parameters, convert them to
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 07ddeed61766..5e435e42dacd 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -697,7 +697,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall)
if (!user_mode(regs))
return 0;
- if (try_to_freeze(0))
+ if (try_to_freeze())
goto no_signal;
if (current->ptrace & PT_SINGLESTEP)
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 34892758f098..a931409c8fe4 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -502,3 +502,126 @@ int __init setup_profiling_timer(unsigned int multiplier)
{
return -EINVAL;
}
+
+static int
+on_each_cpu_mask(void (*func)(void *), void *info, int retry, int wait,
+ cpumask_t mask)
+{
+ int ret = 0;
+
+ preempt_disable();
+
+ ret = smp_call_function_on_cpu(func, info, retry, wait, mask);
+ if (cpu_isset(smp_processor_id(), mask))
+ func(info);
+
+ preempt_enable();
+
+ return ret;
+}
+
+/**********************************************************************/
+
+/*
+ * TLB operations
+ */
+struct tlb_args {
+ struct vm_area_struct *ta_vma;
+ unsigned long ta_start;
+ unsigned long ta_end;
+};
+
+static inline void ipi_flush_tlb_all(void *ignored)
+{
+ local_flush_tlb_all();
+}
+
+static inline void ipi_flush_tlb_mm(void *arg)
+{
+ struct mm_struct *mm = (struct mm_struct *)arg;
+
+ local_flush_tlb_mm(mm);
+}
+
+static inline void ipi_flush_tlb_page(void *arg)
+{
+ struct tlb_args *ta = (struct tlb_args *)arg;
+
+ local_flush_tlb_page(ta->ta_vma, ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_kernel_page(void *arg)
+{
+ struct tlb_args *ta = (struct tlb_args *)arg;
+
+ local_flush_tlb_kernel_page(ta->ta_start);
+}
+
+static inline void ipi_flush_tlb_range(void *arg)
+{
+ struct tlb_args *ta = (struct tlb_args *)arg;
+
+ local_flush_tlb_range(ta->ta_vma, ta->ta_start, ta->ta_end);
+}
+
+static inline void ipi_flush_tlb_kernel_range(void *arg)
+{
+ struct tlb_args *ta = (struct tlb_args *)arg;
+
+ local_flush_tlb_kernel_range(ta->ta_start, ta->ta_end);
+}
+
+void flush_tlb_all(void)
+{
+ on_each_cpu(ipi_flush_tlb_all, NULL, 1, 1);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ cpumask_t mask = mm->cpu_vm_mask;
+
+ on_each_cpu_mask(ipi_flush_tlb_mm, mm, 1, 1, mask);
+}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+{
+ cpumask_t mask = vma->vm_mm->cpu_vm_mask;
+ struct tlb_args ta;
+
+ ta.ta_vma = vma;
+ ta.ta_start = uaddr;
+
+ on_each_cpu_mask(ipi_flush_tlb_page, &ta, 1, 1, mask);
+}
+
+void flush_tlb_kernel_page(unsigned long kaddr)
+{
+ struct tlb_args ta;
+
+ ta.ta_start = kaddr;
+
+ on_each_cpu(ipi_flush_tlb_kernel_page, &ta, 1, 1);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ cpumask_t mask = vma->vm_mm->cpu_vm_mask;
+ struct tlb_args ta;
+
+ ta.ta_vma = vma;
+ ta.ta_start = start;
+ ta.ta_end = end;
+
+ on_each_cpu_mask(ipi_flush_tlb_range, &ta, 1, 1, mask);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ struct tlb_args ta;
+
+ ta.ta_start = start;
+ ta.ta_end = end;
+
+ on_each_cpu(ipi_flush_tlb_kernel_range, &ta, 1, 1);
+}
diff --git a/arch/arm/kernel/time.c b/arch/arm/kernel/time.c
index c232f24f4a60..1b7fcd50c3e2 100644
--- a/arch/arm/kernel/time.c
+++ b/arch/arm/kernel/time.c
@@ -381,6 +381,99 @@ static struct sysdev_class timer_sysclass = {
.resume = timer_resume,
};
+#ifdef CONFIG_NO_IDLE_HZ
+static int timer_dyn_tick_enable(void)
+{
+ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+ unsigned long flags;
+ int ret = -ENODEV;
+
+ if (dyn_tick) {
+ write_seqlock_irqsave(&xtime_lock, flags);
+ ret = 0;
+ if (!(dyn_tick->state & DYN_TICK_ENABLED)) {
+ ret = dyn_tick->enable();
+
+ if (ret == 0)
+ dyn_tick->state |= DYN_TICK_ENABLED;
+ }
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ }
+
+ return ret;
+}
+
+static int timer_dyn_tick_disable(void)
+{
+ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+ unsigned long flags;
+ int ret = -ENODEV;
+
+ if (dyn_tick) {
+ write_seqlock_irqsave(&xtime_lock, flags);
+ ret = 0;
+ if (dyn_tick->state & DYN_TICK_ENABLED) {
+ ret = dyn_tick->disable();
+
+ if (ret == 0)
+ dyn_tick->state &= ~DYN_TICK_ENABLED;
+ }
+ write_sequnlock_irqrestore(&xtime_lock, flags);
+ }
+
+ return ret;
+}
+
+/*
+ * Reprogram the system timer for at least the calculated time interval.
+ * This function should be called from the idle thread with IRQs disabled,
+ * immediately before sleeping.
+ */
+void timer_dyn_reprogram(void)
+{
+ struct dyn_tick_timer *dyn_tick = system_timer->dyn_tick;
+
+ write_seqlock(&xtime_lock);
+ if (dyn_tick->state & DYN_TICK_ENABLED)
+ dyn_tick->reprogram(next_timer_interrupt() - jiffies);
+ write_sequnlock(&xtime_lock);
+}
+
+static ssize_t timer_show_dyn_tick(struct sys_device *dev, char *buf)
+{
+ return sprintf(buf, "%i\n",
+ (system_timer->dyn_tick->state & DYN_TICK_ENABLED) >> 1);
+}
+
+static ssize_t timer_set_dyn_tick(struct sys_device *dev, const char *buf,
+ size_t count)
+{
+ unsigned int enable = simple_strtoul(buf, NULL, 2);
+
+ if (enable)
+ timer_dyn_tick_enable();
+ else
+ timer_dyn_tick_disable();
+
+ return count;
+}
+static SYSDEV_ATTR(dyn_tick, 0644, timer_show_dyn_tick, timer_set_dyn_tick);
+
+/*
+ * dyntick=enable|disable
+ */
+static char dyntick_str[4] __initdata = "";
+
+static int __init dyntick_setup(char *str)
+{
+ if (str)
+ strlcpy(dyntick_str, str, sizeof(dyntick_str));
+ return 1;
+}
+
+__setup("dyntick=", dyntick_setup);
+#endif
+
static int __init timer_init_sysfs(void)
{
int ret = sysdev_class_register(&timer_sysclass);
@@ -388,6 +481,20 @@ static int __init timer_init_sysfs(void)
system_timer->dev.cls = &timer_sysclass;
ret = sysdev_register(&system_timer->dev);
}
+
+#ifdef CONFIG_NO_IDLE_HZ
+ if (ret == 0 && system_timer->dyn_tick) {
+ ret = sysdev_create_file(&system_timer->dev, &attr_dyn_tick);
+
+ /*
+ * Turn on dynamic tick after calibrate delay
+ * for correct bogomips
+ */
+ if (ret == 0 && dyntick_str[0] == 'e')
+ ret = timer_dyn_tick_enable();
+ }
+#endif
+
return ret;
}
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
index 2fb0a4cfb37a..df2cb06ce424 100644
--- a/arch/arm/kernel/traps.c
+++ b/arch/arm/kernel/traps.c
@@ -230,16 +230,8 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
do_exit(SIGSEGV);
}
-void die_if_kernel(const char *str, struct pt_regs *regs, int err)
-{
- if (user_mode(regs))
- return;
-
- die(str, regs, err);
-}
-
-static void notify_die(const char *str, struct pt_regs *regs, siginfo_t *info,
- unsigned long err, unsigned long trap)
+void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+ unsigned long err, unsigned long trap)
{
if (user_mode(regs)) {
current->thread.error_code = err;
diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile
index c0e65833ffc4..8725d63e4219 100644
--- a/arch/arm/lib/Makefile
+++ b/arch/arm/lib/Makefile
@@ -11,7 +11,7 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \
strnlen_user.o strchr.o strrchr.o testchangebit.o \
testclearbit.o testsetbit.o uaccess.o getuser.o \
putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \
- ucmpdi2.o udivdi3.o lib1funcs.o div64.o \
+ ucmpdi2.o lib1funcs.o div64.o \
io-readsb.o io-writesb.o io-readsl.o io-writesl.o
ifeq ($(CONFIG_CPU_32v3),y)
diff --git a/arch/arm/lib/longlong.h b/arch/arm/lib/longlong.h
deleted file mode 100644
index 90ae647e4d76..000000000000
--- a/arch/arm/lib/longlong.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* longlong.h -- based on code from gcc-2.95.3
-
- definitions for mixed size 32/64 bit arithmetic.
- Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc.
-
- This definition file is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 2, or (at your option) any later version.
-
- This definition file 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. */
-
-/* Borrowed from GCC 2.95.3, I Molton 29/07/01 */
-
-#ifndef SI_TYPE_SIZE
-#define SI_TYPE_SIZE 32
-#endif
-
-#define __BITS4 (SI_TYPE_SIZE / 4)
-#define __ll_B (1L << (SI_TYPE_SIZE / 2))
-#define __ll_lowpart(t) ((u32) (t) % __ll_B)
-#define __ll_highpart(t) ((u32) (t) / __ll_B)
-
-/* Define auxiliary asm macros.
-
- 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand)
- multiplies two u32 integers MULTIPLER and MULTIPLICAND,
- and generates a two-part u32 product in HIGH_PROD and
- LOW_PROD.
-
- 2) __umulsidi3(a,b) multiplies two u32 integers A and B,
- and returns a u64 product. This is just a variant of umul_ppmm.
-
- 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
- denominator) divides a two-word unsigned integer, composed by the
- integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and
- places the quotient in QUOTIENT and the remainder in REMAINDER.
- HIGH_NUMERATOR must be less than DENOMINATOR for correct operation.
- If, in addition, the most significant bit of DENOMINATOR must be 1,
- then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1.
-
- 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator,
- denominator). Like udiv_qrnnd but the numbers are signed. The
- quotient is rounded towards 0.
-
- 5) count_leading_zeros(count, x) counts the number of zero-bits from
- the msb to the first non-zero bit. This is the number of steps X
- needs to be shifted left to set the msb. Undefined for X == 0.
-
- 6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1,
- high_addend_2, low_addend_2) adds two two-word unsigned integers,
- composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and
- LOW_ADDEND_2 respectively. The result is placed in HIGH_SUM and
- LOW_SUM. Overflow (i.e. carry out) is not stored anywhere, and is
- lost.
-
- 7) sub_ddmmss(high_difference, low_difference, high_minuend,
- low_minuend, high_subtrahend, low_subtrahend) subtracts two
- two-word unsigned integers, composed by HIGH_MINUEND_1 and
- LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2
- respectively. The result is placed in HIGH_DIFFERENCE and
- LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere,
- and is lost.
-
- If any of these macros are left undefined for a particular CPU,
- C macros are used. */
-
-#if defined (__arm__)
-#define add_ssaaaa(sh, sl, ah, al, bh, bl) \
- __asm__ ("adds %1, %4, %5 \n\
- adc %0, %2, %3" \
- : "=r" ((u32) (sh)), \
- "=&r" ((u32) (sl)) \
- : "%r" ((u32) (ah)), \
- "rI" ((u32) (bh)), \
- "%r" ((u32) (al)), \
- "rI" ((u32) (bl)))
-#define sub_ddmmss(sh, sl, ah, al, bh, bl) \
- __asm__ ("subs %1, %4, %5 \n\
- sbc %0, %2, %3" \
- : "=r" ((u32) (sh)), \
- "=&r" ((u32) (sl)) \
- : "r" ((u32) (ah)), \
- "rI" ((u32) (bh)), \
- "r" ((u32) (al)), \
- "rI" ((u32) (bl)))
-#define umul_ppmm(xh, xl, a, b) \
-{register u32 __t0, __t1, __t2; \
- __asm__ ("%@ Inlined umul_ppmm \n\
- mov %2, %5, lsr #16 \n\
- mov %0, %6, lsr #16 \n\
- bic %3, %5, %2, lsl #16 \n\
- bic %4, %6, %0, lsl #16 \n\
- mul %1, %3, %4 \n\
- mul %4, %2, %4 \n\
- mul %3, %0, %3 \n\
- mul %0, %2, %0 \n\
- adds %3, %4, %3 \n\
- addcs %0, %0, #65536 \n\
- adds %1, %1, %3, lsl #16 \n\
- adc %0, %0, %3, lsr #16" \
- : "=&r" ((u32) (xh)), \
- "=r" ((u32) (xl)), \
- "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \
- : "r" ((u32) (a)), \
- "r" ((u32) (b)));}
-#define UMUL_TIME 20
-#define UDIV_TIME 100
-#endif /* __arm__ */
-
-#define __umulsidi3(u, v) \
- ({DIunion __w; \
- umul_ppmm (__w.s.high, __w.s.low, u, v); \
- __w.ll; })
-
-#define __udiv_qrnnd_c(q, r, n1, n0, d) \
- do { \
- u32 __d1, __d0, __q1, __q0; \
- u32 __r1, __r0, __m; \
- __d1 = __ll_highpart (d); \
- __d0 = __ll_lowpart (d); \
- \
- __r1 = (n1) % __d1; \
- __q1 = (n1) / __d1; \
- __m = (u32) __q1 * __d0; \
- __r1 = __r1 * __ll_B | __ll_highpart (n0); \
- if (__r1 < __m) \
- { \
- __q1--, __r1 += (d); \
- if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\
- if (__r1 < __m) \
- __q1--, __r1 += (d); \
- } \
- __r1 -= __m; \
- \
- __r0 = __r1 % __d1; \
- __q0 = __r1 / __d1; \
- __m = (u32) __q0 * __d0; \
- __r0 = __r0 * __ll_B | __ll_lowpart (n0); \
- if (__r0 < __m) \
- { \
- __q0--, __r0 += (d); \
- if (__r0 >= (d)) \
- if (__r0 < __m) \
- __q0--, __r0 += (d); \
- } \
- __r0 -= __m; \
- \
- (q) = (u32) __q1 * __ll_B | __q0; \
- (r) = __r0; \
- } while (0)
-
-#define UDIV_NEEDS_NORMALIZATION 1
-#define udiv_qrnnd __udiv_qrnnd_c
-
-#define count_leading_zeros(count, x) \
- do { \
- u32 __xr = (x); \
- u32 __a; \
- \
- if (SI_TYPE_SIZE <= 32) \
- { \
- __a = __xr < ((u32)1<<2*__BITS4) \
- ? (__xr < ((u32)1<<__BITS4) ? 0 : __BITS4) \
- : (__xr < ((u32)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \
- } \
- else \
- { \
- for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8) \
- if (((__xr >> __a) & 0xff) != 0) \
- break; \
- } \
- \
- (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \
- } while (0)
diff --git a/arch/arm/lib/udivdi3.c b/arch/arm/lib/udivdi3.c
deleted file mode 100644
index e343be4c6642..000000000000
--- a/arch/arm/lib/udivdi3.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/* More subroutines needed by GCC output code on some machines. */
-/* Compile this one with gcc. */
-/* Copyright (C) 1989, 92-98, 1999 Free Software Foundation, Inc.
-
-This file is part of GNU CC.
-
-GNU CC 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.
-
-GNU CC 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 GNU CC; see the file COPYING. If not, write to
-the Free Software Foundation, 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
-
-/* As a special exception, if you link this library with other files,
- some of which are compiled with GCC, to produce an executable,
- this library does not by itself cause the resulting executable
- to be covered by the GNU General Public License.
- This exception does not however invalidate any other reasons why
- the executable file might be covered by the GNU General Public License.
- */
-/* support functions required by the kernel. based on code from gcc-2.95.3 */
-/* I Molton 29/07/01 */
-
-#include "gcclib.h"
-#include "longlong.h"
-
-static const u8 __clz_tab[] = {
- 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
- 5, 5, 5, 5, 5, 5, 5, 5,
- 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
- 6, 6, 6, 6, 6, 6, 6, 6,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
- 7, 7, 7, 7, 7, 7, 7, 7,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 8, 8, 8,
-};
-
-u64 __udivmoddi4(u64 n, u64 d, u64 * rp)
-{
- DIunion ww;
- DIunion nn, dd;
- DIunion rr;
- u32 d0, d1, n0, n1, n2;
- u32 q0, q1;
- u32 b, bm;
-
- nn.ll = n;
- dd.ll = d;
-
- d0 = dd.s.low;
- d1 = dd.s.high;
- n0 = nn.s.low;
- n1 = nn.s.high;
-
- if (d1 == 0) {
- if (d0 > n1) {
- /* 0q = nn / 0D */
-
- count_leading_zeros(bm, d0);
-
- if (bm != 0) {
- /* Normalize, i.e. make the most significant bit of the
- denominator set. */
-
- d0 = d0 << bm;
- n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm));
- n0 = n0 << bm;
- }
-
- udiv_qrnnd(q0, n0, n1, n0, d0);
- q1 = 0;
-
- /* Remainder in n0 >> bm. */
- } else {
- /* qq = NN / 0d */
-
- if (d0 == 0)
- d0 = 1 / d0; /* Divide intentionally by zero. */
-
- count_leading_zeros(bm, d0);
-
- if (bm == 0) {
- /* From (n1 >= d0) /\ (the most significant bit of d0 is set),
- conclude (the most significant bit of n1 is set) /\ (the
- leading quotient digit q1 = 1).
-
- This special case is necessary, not an optimization.
- (Shifts counts of SI_TYPE_SIZE are undefined.) */
-
- n1 -= d0;
- q1 = 1;
- } else {
- /* Normalize. */
-
- b = SI_TYPE_SIZE - bm;
-
- d0 = d0 << bm;
- n2 = n1 >> b;
- n1 = (n1 << bm) | (n0 >> b);
- n0 = n0 << bm;
-
- udiv_qrnnd(q1, n1, n2, n1, d0);
- }
-
- /* n1 != d0... */
-
- udiv_qrnnd(q0, n0, n1, n0, d0);
-
- /* Remainder in n0 >> bm. */
- }
-
- if (rp != 0) {
- rr.s.low = n0 >> bm;
- rr.s.high = 0;
- *rp = rr.ll;
- }
- } else {
- if (d1 > n1) {
- /* 00 = nn / DD */
-
- q0 = 0;
- q1 = 0;
-
- /* Remainder in n1n0. */
- if (rp != 0) {
- rr.s.low = n0;
- rr.s.high = n1;
- *rp = rr.ll;
- }
- } else {
- /* 0q = NN / dd */
-
- count_leading_zeros(bm, d1);
- if (bm == 0) {
- /* From (n1 >= d1) /\ (the most significant bit of d1 is set),
- conclude (the most significant bit of n1 is set) /\ (the
- quotient digit q0 = 0 or 1).
-
- This special case is necessary, not an optimization. */
-
- /* The condition on the next line takes advantage of that
- n1 >= d1 (true due to program flow). */
- if (n1 > d1 || n0 >= d0) {
- q0 = 1;
- sub_ddmmss(n1, n0, n1, n0, d1, d0);
- } else
- q0 = 0;
-
- q1 = 0;
-
- if (rp != 0) {
- rr.s.low = n0;
- rr.s.high = n1;
- *rp = rr.ll;
- }
- } else {
- u32 m1, m0;
- /* Normalize. */
-
- b = SI_TYPE_SIZE - bm;
-
- d1 = (d1 << bm) | (d0 >> b);
- d0 = d0 << bm;
- n2 = n1 >> b;
- n1 = (n1 << bm) | (n0 >> b);
- n0 = n0 << bm;
-
- udiv_qrnnd(q0, n1, n2, n1, d1);
- umul_ppmm(m1, m0, q0, d0);
-
- if (m1 > n1 || (m1 == n1 && m0 > n0)) {
- q0--;
- sub_ddmmss(m1, m0, m1, m0, d1, d0);
- }
-
- q1 = 0;
-
- /* Remainder in (n1n0 - m1m0) >> bm. */
- if (rp != 0) {
- sub_ddmmss(n1, n0, n1, n0, m1, m0);
- rr.s.low = (n1 << b) | (n0 >> bm);
- rr.s.high = n1 >> bm;
- *rp = rr.ll;
- }
- }
- }
- }
-
- ww.s.low = q0;
- ww.s.high = q1;
- return ww.ll;
-}
-
-u64 __udivdi3(u64 n, u64 d)
-{
- return __udivmoddi4(n, d, (u64 *) 0);
-}
-
-u64 __umoddi3(u64 u, u64 v)
-{
- u64 w;
-
- (void)__udivmoddi4(u, v, &w);
-
- return w;
-}
diff --git a/arch/arm/mach-aaec2000/Makefile.boot b/arch/arm/mach-aaec2000/Makefile.boot
new file mode 100644
index 000000000000..8f5a8b7c53c7
--- /dev/null
+++ b/arch/arm/mach-aaec2000/Makefile.boot
@@ -0,0 +1 @@
+ zreladdr-y := 0xf0008000
diff --git a/arch/arm/mach-aaec2000/aaed2000.c b/arch/arm/mach-aaec2000/aaed2000.c
index 5417ca3f4621..c9d899886648 100644
--- a/arch/arm/mach-aaec2000/aaed2000.c
+++ b/arch/arm/mach-aaec2000/aaed2000.c
@@ -40,9 +40,11 @@ static void __init aaed2000_map_io(void)
}
MACHINE_START(AAED2000, "Agilent AAED-2000 Development Platform")
- MAINTAINER("Nicolas Bellido Y Ortega")
- BOOT_MEM(0xf0000000, PIO_BASE, VIO_BASE)
- MAPIO(aaed2000_map_io)
- INITIRQ(aaed2000_init_irq)
+ /* Maintainer: Nicolas Bellido Y Ortega */
+ .phys_ram = 0xf0000000,
+ .phys_io = PIO_BASE,
+ .io_pg_offst = ((VIO_BASE) >> 18) & 0xfffc,
+ .map_io = aaed2000_map_io,
+ .init_irq = aaed2000_init_irq,
.timer = &aaec2000_timer,
MACHINE_END
diff --git a/arch/arm/mach-aaec2000/core.c b/arch/arm/mach-aaec2000/core.c
index fc145b3768fa..aece0cd4f0a3 100644
--- a/arch/arm/mach-aaec2000/core.c
+++ b/arch/arm/mach-aaec2000/core.c
@@ -128,8 +128,8 @@ aaec2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction aaec2000_timer_irq = {
.name = "AAEC-2000 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = aaec2000_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = aaec2000_timer_interrupt,
};
static void __init aaec2000_timer_init(void)
diff --git a/arch/arm/mach-clps711x/Kconfig b/arch/arm/mach-clps711x/Kconfig
index 45c930ccd064..0793dcf54f2e 100644
--- a/arch/arm/mach-clps711x/Kconfig
+++ b/arch/arm/mach-clps711x/Kconfig
@@ -28,7 +28,7 @@ config ARCH_CLEP7312
config ARCH_EDB7211
bool "EDB7211"
select ISA
- select DISCONTIGMEM
+ select ARCH_DISCONTIGMEM_ENABLE
help
Say Y here if you intend to run this kernel on a Cirrus Logic EDB-7211
evaluation board.
diff --git a/arch/arm/mach-clps711x/autcpu12.c b/arch/arm/mach-clps711x/autcpu12.c
index c106704a2c34..dc73feb1ffb0 100644
--- a/arch/arm/mach-clps711x/autcpu12.c
+++ b/arch/arm/mach-clps711x/autcpu12.c
@@ -59,11 +59,13 @@ void __init autcpu12_map_io(void)
}
MACHINE_START(AUTCPU12, "autronix autcpu12")
- MAINTAINER("Thomas Gleixner")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0020000)
- MAPIO(autcpu12_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: Thomas Gleixner */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0020000,
+ .map_io = autcpu12_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/cdb89712.c b/arch/arm/mach-clps711x/cdb89712.c
index 7664f9cf83b8..a46c82cd2711 100644
--- a/arch/arm/mach-clps711x/cdb89712.c
+++ b/arch/arm/mach-clps711x/cdb89712.c
@@ -49,10 +49,12 @@ static void __init cdb89712_map_io(void)
}
MACHINE_START(CDB89712, "Cirrus-CDB89712")
- MAINTAINER("Ray Lehtiniemi")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(cdb89712_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: Ray Lehtiniemi */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = cdb89712_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/ceiva.c b/arch/arm/mach-clps711x/ceiva.c
index e4093be3c4cb..780d91805984 100644
--- a/arch/arm/mach-clps711x/ceiva.c
+++ b/arch/arm/mach-clps711x/ceiva.c
@@ -53,10 +53,12 @@ static void __init ceiva_map_io(void)
MACHINE_START(CEIVA, "CEIVA/Polaroid Photo MAX Digital Picture Frame")
- MAINTAINER("Rob Scott")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(ceiva_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: Rob Scott */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = ceiva_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/clep7312.c b/arch/arm/mach-clps711x/clep7312.c
index 9ca21cb481ba..c83f3fd68fcd 100644
--- a/arch/arm/mach-clps711x/clep7312.c
+++ b/arch/arm/mach-clps711x/clep7312.c
@@ -37,12 +37,14 @@ fixup_clep7312(struct machine_desc *desc, struct tag *tags,
MACHINE_START(CLEP7212, "Cirrus Logic 7212/7312")
- MAINTAINER("Nobody")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0000100)
- FIXUP(fixup_clep7312)
- MAPIO(clps711x_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: Nobody */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .fixup = fixup_clep7312,
+ .map_io = clps711x_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/edb7211-arch.c b/arch/arm/mach-clps711x/edb7211-arch.c
index c6c46324a2e3..255c98b63e15 100644
--- a/arch/arm/mach-clps711x/edb7211-arch.c
+++ b/arch/arm/mach-clps711x/edb7211-arch.c
@@ -51,11 +51,13 @@ fixup_edb7211(struct machine_desc *desc, struct tag *tags,
}
MACHINE_START(EDB7211, "CL-EDB7211 (EP7211 eval board)")
- MAINTAINER("Jon McClintock")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0020100) /* 0xc0000000 - 0xc001ffff can be video RAM */
- FIXUP(fixup_edb7211)
- MAPIO(edb7211_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: Jon McClintock */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0020100, /* 0xc0000000 - 0xc001ffff can be video RAM */
+ .fixup = fixup_edb7211,
+ .map_io = edb7211_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/fortunet.c b/arch/arm/mach-clps711x/fortunet.c
index c1c5b8e01549..f83a59761e02 100644
--- a/arch/arm/mach-clps711x/fortunet.c
+++ b/arch/arm/mach-clps711x/fortunet.c
@@ -75,11 +75,13 @@ fortunet_fixup(struct machine_desc *desc, struct tag *tags,
}
MACHINE_START(FORTUNET, "ARM-FortuNet")
- MAINTAINER("FortuNet Inc.")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf0000000)
- BOOT_PARAMS(0x00000000)
- FIXUP(fortunet_fixup)
- MAPIO(clps711x_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: FortuNet Inc. */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf0000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000000,
+ .fixup = fortunet_fixup,
+ .map_io = clps711x_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/p720t.c b/arch/arm/mach-clps711x/p720t.c
index 29269df054f5..5bdb90edf992 100644
--- a/arch/arm/mach-clps711x/p720t.c
+++ b/arch/arm/mach-clps711x/p720t.c
@@ -79,12 +79,14 @@ static void __init p720t_map_io(void)
}
MACHINE_START(P720T, "ARM-Prospector720T")
- MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
- BOOT_MEM(0xc0000000, 0x80000000, 0xff000000)
- BOOT_PARAMS(0xc0000100)
- FIXUP(fixup_p720t)
- MAPIO(p720t_map_io)
- INITIRQ(clps711x_init_irq)
+ /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xff000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .fixup = fixup_p720t,
+ .map_io = p720t_map_io,
+ .init_irq = clps711x_init_irq,
.timer = &clps711x_timer,
MACHINE_END
diff --git a/arch/arm/mach-clps711x/time.c b/arch/arm/mach-clps711x/time.c
index 383d4e0c6e35..1a23f0dcd4b8 100644
--- a/arch/arm/mach-clps711x/time.c
+++ b/arch/arm/mach-clps711x/time.c
@@ -57,8 +57,8 @@ p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction clps711x_timer_irq = {
.name = "CLPS711x Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = p720t_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = p720t_timer_interrupt,
};
static void __init clps711x_timer_init(void)
diff --git a/arch/arm/mach-clps7500/core.c b/arch/arm/mach-clps7500/core.c
index 0bc7da488612..112f1d68fb2b 100644
--- a/arch/arm/mach-clps7500/core.c
+++ b/arch/arm/mach-clps7500/core.c
@@ -298,8 +298,8 @@ clps7500_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction clps7500_timer_irq = {
.name = "CLPS7500 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = clps7500_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = clps7500_timer_interrupt,
};
/*
@@ -366,11 +366,13 @@ static void __init clps7500_init(void)
}
MACHINE_START(CLPS7500, "CL-PS7500")
- MAINTAINER("Philip Blundell")
- BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
- MAPIO(clps7500_map_io)
- INITIRQ(clps7500_init_irq)
- .init_machine = clps7500_init,
- .timer = &clps7500_timer,
+ /* Maintainer: Philip Blundell */
+ .phys_ram = 0x10000000,
+ .phys_io = 0x03000000,
+ .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
+ .map_io = clps7500_map_io,
+ .init_irq = clps7500_init_irq,
+ .init_machine = clps7500_init,
+ .timer = &clps7500_timer,
MACHINE_END
diff --git a/arch/arm/mach-ebsa110/core.c b/arch/arm/mach-ebsa110/core.c
index ef362d44949d..23c4da10101b 100644
--- a/arch/arm/mach-ebsa110/core.c
+++ b/arch/arm/mach-ebsa110/core.c
@@ -173,8 +173,8 @@ ebsa110_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction ebsa110_timer_irq = {
.name = "EBSA110 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = ebsa110_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = ebsa110_timer_interrupt,
};
/*
@@ -233,13 +233,15 @@ static int __init ebsa110_init(void)
arch_initcall(ebsa110_init);
MACHINE_START(EBSA110, "EBSA110")
- MAINTAINER("Russell King")
- BOOT_MEM(0x00000000, 0xe0000000, 0xe0000000)
- BOOT_PARAMS(0x00000400)
- DISABLE_PARPORT(0)
- DISABLE_PARPORT(2)
- SOFT_REBOOT
- MAPIO(ebsa110_map_io)
- INITIRQ(ebsa110_init_irq)
+ /* Maintainer: Russell King */
+ .phys_ram = 0x00000000,
+ .phys_io = 0xe0000000,
+ .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000400,
+ .reserve_lp0 = 1,
+ .reserve_lp2 = 1,
+ .soft_reboot = 1,
+ .map_io = ebsa110_map_io,
+ .init_irq = ebsa110_init_irq,
.timer = &ebsa110_timer,
MACHINE_END
diff --git a/arch/arm/mach-epxa10db/arch.c b/arch/arm/mach-epxa10db/arch.c
index 1b40340e8a21..7daa021676d0 100644
--- a/arch/arm/mach-epxa10db/arch.c
+++ b/arch/arm/mach-epxa10db/arch.c
@@ -63,10 +63,12 @@ extern void epxa10db_init_irq(void);
extern struct sys_timer epxa10db_timer;
MACHINE_START(CAMELOT, "Altera Epxa10db")
- MAINTAINER("Altera Corporation")
- BOOT_MEM(0x00000000, 0x7fffc000, 0xffffc000)
- MAPIO(epxa10db_map_io)
- INITIRQ(epxa10db_init_irq)
+ /* Maintainer: Altera Corporation */
+ .phys_ram = 0x00000000,
+ .phys_io = 0x7fffc000,
+ .io_pg_offst = ((0xffffc000) >> 18) & 0xfffc,
+ .map_io = epxa10db_map_io,
+ .init_irq = epxa10db_init_irq,
.timer = &epxa10db_timer,
MACHINE_END
diff --git a/arch/arm/mach-epxa10db/time.c b/arch/arm/mach-epxa10db/time.c
index 1b991f3cc3c6..4b1084dde8dd 100644
--- a/arch/arm/mach-epxa10db/time.c
+++ b/arch/arm/mach-epxa10db/time.c
@@ -56,8 +56,8 @@ epxa10db_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction epxa10db_timer_irq = {
.name = "Excalibur Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = epxa10db_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = epxa10db_timer_interrupt,
};
/*
diff --git a/arch/arm/mach-footbridge/cats-hw.c b/arch/arm/mach-footbridge/cats-hw.c
index d1ced86c379c..49b898af0032 100644
--- a/arch/arm/mach-footbridge/cats-hw.c
+++ b/arch/arm/mach-footbridge/cats-hw.c
@@ -84,12 +84,14 @@ fixup_cats(struct machine_desc *desc, struct tag *tags,
}
MACHINE_START(CATS, "Chalice-CATS")
- MAINTAINER("Philip Blundell")
- BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
- BOOT_PARAMS(0x00000100)
- SOFT_REBOOT
- FIXUP(fixup_cats)
- MAPIO(footbridge_map_io)
- INITIRQ(footbridge_init_irq)
+ /* Maintainer: Philip Blundell */
+ .phys_ram = 0x00000000,
+ .phys_io = DC21285_ARMCSR_BASE,
+ .io_pg_offst = ((0xfe000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .soft_reboot = 1,
+ .fixup = fixup_cats,
+ .map_io = footbridge_map_io,
+ .init_irq = footbridge_init_irq,
.timer = &isa_timer,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/co285.c b/arch/arm/mach-footbridge/co285.c
index e1541914fdcd..548a79081688 100644
--- a/arch/arm/mach-footbridge/co285.c
+++ b/arch/arm/mach-footbridge/co285.c
@@ -28,11 +28,13 @@ fixup_coebsa285(struct machine_desc *desc, struct tag *tags,
}
MACHINE_START(CO285, "co-EBSA285")
- MAINTAINER("Mark van Doesburg")
- BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0x7cf00000)
- FIXUP(fixup_coebsa285)
- MAPIO(footbridge_map_io)
- INITIRQ(footbridge_init_irq)
+ /* Maintainer: Mark van Doesburg */
+ .phys_ram = 0x00000000,
+ .phys_io = DC21285_ARMCSR_BASE,
+ .io_pg_offst = ((0x7cf00000) >> 18) & 0xfffc,
+ .fixup = fixup_coebsa285,
+ .map_io = footbridge_map_io,
+ .init_irq = footbridge_init_irq,
.timer = &footbridge_timer,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/dc21285-timer.c b/arch/arm/mach-footbridge/dc21285-timer.c
index da5b9b7623ca..14a62d6008fe 100644
--- a/arch/arm/mach-footbridge/dc21285-timer.c
+++ b/arch/arm/mach-footbridge/dc21285-timer.c
@@ -43,7 +43,7 @@ timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction footbridge_timer_irq = {
.name = "Timer1 timer tick",
.handler = timer1_interrupt,
- .flags = SA_INTERRUPT,
+ .flags = SA_INTERRUPT | SA_TIMER,
};
/*
diff --git a/arch/arm/mach-footbridge/ebsa285.c b/arch/arm/mach-footbridge/ebsa285.c
index d0931f5a63c8..1c37605268d5 100644
--- a/arch/arm/mach-footbridge/ebsa285.c
+++ b/arch/arm/mach-footbridge/ebsa285.c
@@ -13,12 +13,15 @@
#include "common.h"
MACHINE_START(EBSA285, "EBSA285")
- MAINTAINER("Russell King")
- BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
- BOOT_PARAMS(0x00000100)
- VIDEO(0x000a0000, 0x000bffff)
- MAPIO(footbridge_map_io)
- INITIRQ(footbridge_init_irq)
+ /* Maintainer: Russell King */
+ .phys_ram = 0x00000000,
+ .phys_io = DC21285_ARMCSR_BASE,
+ .io_pg_offst = ((0xfe000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .video_start = 0x000a0000,
+ .video_end = 0x000bffff,
+ .map_io = footbridge_map_io,
+ .init_irq = footbridge_init_irq,
.timer = &footbridge_timer,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/isa-timer.c b/arch/arm/mach-footbridge/isa-timer.c
index a4fefa0bb5a1..c1d74f7ab669 100644
--- a/arch/arm/mach-footbridge/isa-timer.c
+++ b/arch/arm/mach-footbridge/isa-timer.c
@@ -72,7 +72,7 @@ isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction isa_timer_irq = {
.name = "ISA timer tick",
.handler = isa_timer_interrupt,
- .flags = SA_INTERRUPT,
+ .flags = SA_INTERRUPT | SA_TIMER,
};
static void __init isa_timer_init(void)
diff --git a/arch/arm/mach-footbridge/netwinder-hw.c b/arch/arm/mach-footbridge/netwinder-hw.c
index 1e1dfd79f4fe..775f85fc8513 100644
--- a/arch/arm/mach-footbridge/netwinder-hw.c
+++ b/arch/arm/mach-footbridge/netwinder-hw.c
@@ -647,14 +647,17 @@ fixup_netwinder(struct machine_desc *desc, struct tag *tags,
}
MACHINE_START(NETWINDER, "Rebel-NetWinder")
- MAINTAINER("Russell King/Rebel.com")
- BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
- BOOT_PARAMS(0x00000100)
- VIDEO(0x000a0000, 0x000bffff)
- DISABLE_PARPORT(0)
- DISABLE_PARPORT(2)
- FIXUP(fixup_netwinder)
- MAPIO(footbridge_map_io)
- INITIRQ(footbridge_init_irq)
+ /* Maintainer: Russell King/Rebel.com */
+ .phys_ram = 0x00000000,
+ .phys_io = DC21285_ARMCSR_BASE,
+ .io_pg_offst = ((0xfe000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .video_start = 0x000a0000,
+ .video_end = 0x000bffff,
+ .reserve_lp0 = 1,
+ .reserve_lp2 = 1,
+ .fixup = fixup_netwinder,
+ .map_io = footbridge_map_io,
+ .init_irq = footbridge_init_irq,
.timer = &isa_timer,
MACHINE_END
diff --git a/arch/arm/mach-footbridge/personal.c b/arch/arm/mach-footbridge/personal.c
index 415086d7bbee..0146b8bb59da 100644
--- a/arch/arm/mach-footbridge/personal.c
+++ b/arch/arm/mach-footbridge/personal.c
@@ -13,11 +13,13 @@
#include "common.h"
MACHINE_START(PERSONAL_SERVER, "Compaq-PersonalServer")
- MAINTAINER("Jamey Hicks / George France")
- BOOT_MEM(0x00000000, DC21285_ARMCSR_BASE, 0xfe000000)
- BOOT_PARAMS(0x00000100)
- MAPIO(footbridge_map_io)
- INITIRQ(footbridge_init_irq)
+ /* Maintainer: Jamey Hicks / George France */
+ .phys_ram = 0x00000000,
+ .phys_io = DC21285_ARMCSR_BASE,
+ .io_pg_offst = ((0xfe000000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = footbridge_map_io,
+ .init_irq = footbridge_init_irq,
.timer = &footbridge_timer,
MACHINE_END
diff --git a/arch/arm/mach-h720x/cpu-h7201.c b/arch/arm/mach-h720x/cpu-h7201.c
index 743656881ed6..af9e4a5d5ea7 100644
--- a/arch/arm/mach-h720x/cpu-h7201.c
+++ b/arch/arm/mach-h720x/cpu-h7201.c
@@ -41,8 +41,8 @@ h7201_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction h7201_timer_irq = {
.name = "h7201 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = h7201_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = h7201_timer_interrupt,
};
/*
diff --git a/arch/arm/mach-h720x/cpu-h7202.c b/arch/arm/mach-h720x/cpu-h7202.c
index 21b8fb6122cd..593b6a2a30e1 100644
--- a/arch/arm/mach-h720x/cpu-h7202.c
+++ b/arch/arm/mach-h720x/cpu-h7202.c
@@ -171,8 +171,8 @@ static struct irqchip h7202_timerx_chip = {
static struct irqaction h7202_timer_irq = {
.name = "h7202 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = h7202_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = h7202_timer_interrupt,
};
/*
diff --git a/arch/arm/mach-h720x/h7201-eval.c b/arch/arm/mach-h720x/h7201-eval.c
index 9b24b9b0db15..fa59e9e2a5c8 100644
--- a/arch/arm/mach-h720x/h7201-eval.c
+++ b/arch/arm/mach-h720x/h7201-eval.c
@@ -30,10 +30,12 @@
#include "common.h"
MACHINE_START(H7201, "Hynix GMS30C7201")
- MAINTAINER("Robert Schwebel, Pengutronix")
- BOOT_MEM(0x40000000, 0x80000000, 0xf0000000)
- BOOT_PARAMS(0xc0001000)
- MAPIO(h720x_map_io)
- INITIRQ(h720x_init_irq)
- .timer = &h7201_timer,
+ /* Maintainer: Robert Schwebel, Pengutronix */
+ .phys_ram = 0x40000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf0000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0001000,
+ .map_io = h720x_map_io,
+ .init_irq = h720x_init_irq,
+ .timer = &h7201_timer,
MACHINE_END
diff --git a/arch/arm/mach-h720x/h7202-eval.c b/arch/arm/mach-h720x/h7202-eval.c
index 3456a00d5f5c..db9078ad008c 100644
--- a/arch/arm/mach-h720x/h7202-eval.c
+++ b/arch/arm/mach-h720x/h7202-eval.c
@@ -71,11 +71,13 @@ static void __init init_eval_h7202(void)
}
MACHINE_START(H7202, "Hynix HMS30C7202")
- MAINTAINER("Robert Schwebel, Pengutronix")
- BOOT_MEM(0x40000000, 0x80000000, 0xf0000000)
- BOOT_PARAMS(0x40000100)
- MAPIO(h720x_map_io)
- INITIRQ(h7202_init_irq)
- .timer = &h7202_timer,
- INIT_MACHINE(init_eval_h7202)
+ /* Maintainer: Robert Schwebel, Pengutronix */
+ .phys_ram = 0x40000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf0000000) >> 18) & 0xfffc,
+ .boot_params = 0x40000100,
+ .map_io = h720x_map_io,
+ .init_irq = h7202_init_irq,
+ .timer = &h7202_timer,
+ .init_machine = init_eval_h7202,
MACHINE_END
diff --git a/arch/arm/mach-imx/mx1ads.c b/arch/arm/mach-imx/mx1ads.c
index 625dd01c2578..5d25434d332c 100644
--- a/arch/arm/mach-imx/mx1ads.c
+++ b/arch/arm/mach-imx/mx1ads.c
@@ -78,11 +78,13 @@ mx1ads_map_io(void)
}
MACHINE_START(MX1ADS, "Motorola MX1ADS")
- MAINTAINER("Sascha Hauer, Pengutronix")
- BOOT_MEM(0x08000000, 0x00200000, 0xe0200000)
- BOOT_PARAMS(0x08000100)
- MAPIO(mx1ads_map_io)
- INITIRQ(imx_init_irq)
+ /* Maintainer: Sascha Hauer, Pengutronix */
+ .phys_ram = 0x08000000,
+ .phys_io = 0x00200000,
+ .io_pg_offst = ((0xe0200000) >> 18) & 0xfffc,
+ .boot_params = 0x08000100,
+ .map_io = mx1ads_map_io,
+ .init_irq = imx_init_irq,
.timer = &imx_timer,
- INIT_MACHINE(mx1ads_init)
+ .init_machine = mx1ads_init,
MACHINE_END
diff --git a/arch/arm/mach-imx/time.c b/arch/arm/mach-imx/time.c
index 11f1e56c36bc..ea805bfa5e54 100644
--- a/arch/arm/mach-imx/time.c
+++ b/arch/arm/mach-imx/time.c
@@ -72,8 +72,8 @@ imx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction imx_timer_irq = {
.name = "i.MX Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = imx_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = imx_timer_interrupt,
};
/*
diff --git a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c
index bd1e5e3c9d34..dacbf504dae2 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -20,6 +20,7 @@
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/hardware/amba.h>
+#include <asm/hardware/arm_timer.h>
#include <asm/arch/cm.h>
#include <asm/system.h>
#include <asm/leds.h>
@@ -156,16 +157,6 @@ EXPORT_SYMBOL(cm_control);
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif
-/*
- * What does it look like?
- */
-typedef struct TimerStruct {
- unsigned long TimerLoad;
- unsigned long TimerValue;
- unsigned long TimerControl;
- unsigned long TimerClear;
-} TimerStruct_t;
-
static unsigned long timer_reload;
/*
@@ -174,7 +165,6 @@ static unsigned long timer_reload;
*/
unsigned long integrator_gettimeoffset(void)
{
- volatile TimerStruct_t *timer1 = (TimerStruct_t *)TIMER1_VA_BASE;
unsigned long ticks1, ticks2, status;
/*
@@ -183,11 +173,11 @@ unsigned long integrator_gettimeoffset(void)
* an interrupt. We get around this by ensuring that the
* counter has not reloaded between our two reads.
*/
- ticks2 = timer1->TimerValue & 0xffff;
+ ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
do {
ticks1 = ticks2;
status = __raw_readl(VA_IC_BASE + IRQ_RAW_STATUS);
- ticks2 = timer1->TimerValue & 0xffff;
+ ticks2 = readl(TIMER1_VA_BASE + TIMER_VALUE) & 0xffff;
} while (ticks2 > ticks1);
/*
@@ -213,14 +203,12 @@ unsigned long integrator_gettimeoffset(void)
static irqreturn_t
integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
-
write_seqlock(&xtime_lock);
/*
* clear the interrupt
*/
- timer1->TimerClear = 1;
+ writel(1, TIMER1_VA_BASE + TIMER_INTCLR);
/*
* the clock tick routines are only processed on the
@@ -247,8 +235,8 @@ integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction integrator_timer_irq = {
.name = "Integrator Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = integrator_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = integrator_timer_interrupt,
};
/*
@@ -256,32 +244,29 @@ static struct irqaction integrator_timer_irq = {
*/
void __init integrator_time_init(unsigned long reload, unsigned int ctrl)
{
- volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
- volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
- volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
- unsigned int timer_ctrl = 0x80 | 0x40; /* periodic */
+ unsigned int timer_ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
timer_reload = reload;
timer_ctrl |= ctrl;
if (timer_reload > 0x100000) {
timer_reload >>= 8;
- timer_ctrl |= 0x08; /* /256 */
+ timer_ctrl |= TIMER_CTRL_DIV256;
} else if (timer_reload > 0x010000) {
timer_reload >>= 4;
- timer_ctrl |= 0x04; /* /16 */
+ timer_ctrl |= TIMER_CTRL_DIV16;
}
/*
* Initialise to a known state (all timers off)
*/
- timer0->TimerControl = 0;
- timer1->TimerControl = 0;
- timer2->TimerControl = 0;
+ writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER2_VA_BASE + TIMER_CTRL);
- timer1->TimerLoad = timer_reload;
- timer1->TimerValue = timer_reload;
- timer1->TimerControl = timer_ctrl;
+ writel(timer_reload, TIMER1_VA_BASE + TIMER_LOAD);
+ writel(timer_reload, TIMER1_VA_BASE + TIMER_VALUE);
+ writel(timer_ctrl, TIMER1_VA_BASE + TIMER_CTRL);
/*
* Make irqs happen for the system timer
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 91ba9fd79c87..36e2b6eb67b7 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -292,11 +292,13 @@ static struct sys_timer ap_timer = {
};
MACHINE_START(INTEGRATOR, "ARM-Integrator")
- MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
- BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
- BOOT_PARAMS(0x00000100)
- MAPIO(ap_map_io)
- INITIRQ(ap_init_irq)
+ /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+ .phys_ram = 0x00000000,
+ .phys_io = 0x16000000,
+ .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ap_map_io,
+ .init_irq = ap_init_irq,
.timer = &ap_timer,
- INIT_MACHINE(ap_init)
+ .init_machine = ap_init,
MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index e0a01eef0993..569f328c479d 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -532,11 +532,13 @@ static struct sys_timer cp_timer = {
};
MACHINE_START(CINTEGRATOR, "ARM-IntegratorCP")
- MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
- BOOT_MEM(0x00000000, 0x16000000, 0xf1600000)
- BOOT_PARAMS(0x00000100)
- MAPIO(intcp_map_io)
- INITIRQ(intcp_init_irq)
+ /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+ .phys_ram = 0x00000000,
+ .phys_io = 0x16000000,
+ .io_pg_offst = ((0xf1600000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = intcp_map_io,
+ .init_irq = intcp_init_irq,
.timer = &cp_timer,
- INIT_MACHINE(intcp_init)
+ .init_machine = intcp_init,
MACHINE_END
diff --git a/arch/arm/mach-iop3xx/iop321-setup.c b/arch/arm/mach-iop3xx/iop321-setup.c
index bf23e0fd2843..0f921ba2750c 100644
--- a/arch/arm/mach-iop3xx/iop321-setup.c
+++ b/arch/arm/mach-iop3xx/iop321-setup.c
@@ -146,23 +146,27 @@ extern void iop321_init_time(void);
#if defined(CONFIG_ARCH_IQ80321)
MACHINE_START(IQ80321, "Intel IQ80321")
- MAINTAINER("Intel Corporation")
- BOOT_MEM(PHYS_OFFSET, IQ80321_UART, IQ80321_UART)
- MAPIO(iq80321_map_io)
- INITIRQ(iop321_init_irq)
+ /* Maintainer: Intel Corporation */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IQ80321_UART,
+ .io_pg_offst = ((IQ80321_UART) >> 18) & 0xfffc,
+ .map_io = iq80321_map_io,
+ .init_irq = iop321_init_irq,
.timer = &iop321_timer,
- BOOT_PARAMS(0xa0000100)
- INIT_MACHINE(iop32x_init)
+ .boot_params = 0xa0000100,
+ .init_machine = iop32x_init,
MACHINE_END
#elif defined(CONFIG_ARCH_IQ31244)
MACHINE_START(IQ31244, "Intel IQ31244")
- MAINTAINER("Intel Corp.")
- BOOT_MEM(PHYS_OFFSET, IQ31244_UART, IQ31244_UART)
- MAPIO(iq31244_map_io)
- INITIRQ(iop321_init_irq)
+ /* Maintainer: Intel Corp. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IQ31244_UART,
+ .io_pg_offst = ((IQ31244_UART) >> 18) & 0xfffc,
+ .map_io = iq31244_map_io,
+ .init_irq = iop321_init_irq,
.timer = &iop321_timer,
- BOOT_PARAMS(0xa0000100)
- INIT_MACHINE(iop32x_init)
+ .boot_params = 0xa0000100,
+ .init_machine = iop32x_init,
MACHINE_END
#else
#error No machine descriptor defined for this IOP3XX implementation
diff --git a/arch/arm/mach-iop3xx/iop321-time.c b/arch/arm/mach-iop3xx/iop321-time.c
index 9b7dd64d1b8f..d53af1669502 100644
--- a/arch/arm/mach-iop3xx/iop321-time.c
+++ b/arch/arm/mach-iop3xx/iop321-time.c
@@ -86,7 +86,7 @@ iop321_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction iop321_timer_irq = {
.name = "IOP321 Timer Tick",
.handler = iop321_timer_interrupt,
- .flags = SA_INTERRUPT
+ .flags = SA_INTERRUPT | SA_TIMER,
};
static void __init iop321_timer_init(void)
diff --git a/arch/arm/mach-iop3xx/iop331-setup.c b/arch/arm/mach-iop3xx/iop331-setup.c
index 622e7914819a..fc74b722f72f 100644
--- a/arch/arm/mach-iop3xx/iop331-setup.c
+++ b/arch/arm/mach-iop3xx/iop331-setup.c
@@ -148,26 +148,28 @@ extern void iq80332_map_io(void);
#if defined(CONFIG_ARCH_IQ80331)
MACHINE_START(IQ80331, "Intel IQ80331")
- MAINTAINER("Intel Corp.")
- BOOT_MEM(PHYS_OFFSET, 0xfefff000, 0xfffff000) // virtual, physical
- //BOOT_MEM(PHYS_OFFSET, IOP331_UART0_VIRT, IOP331_UART0_PHYS)
- MAPIO(iq80331_map_io)
- INITIRQ(iop331_init_irq)
+ /* Maintainer: Intel Corp. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = 0xfefff000,
+ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
+ .map_io = iq80331_map_io,
+ .init_irq = iop331_init_irq,
.timer = &iop331_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(iop33x_init)
+ .boot_params = 0x0100,
+ .init_machine = iop33x_init,
MACHINE_END
#elif defined(CONFIG_MACH_IQ80332)
MACHINE_START(IQ80332, "Intel IQ80332")
- MAINTAINER("Intel Corp.")
- BOOT_MEM(PHYS_OFFSET, 0xfefff000, 0xfffff000) // virtual, physical
- //BOOT_MEM(PHYS_OFFSET, IOP331_UART0_VIRT, IOP331_UART0_PHYS)
- MAPIO(iq80332_map_io)
- INITIRQ(iop331_init_irq)
+ /* Maintainer: Intel Corp. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = 0xfefff000,
+ .io_pg_offst = ((0xfffff000) >> 18) & 0xfffc, // virtual, physical
+ .map_io = iq80332_map_io,
+ .init_irq = iop331_init_irq,
.timer = &iop331_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(iop33x_init)
+ .boot_params = 0x0100,
+ .init_machine = iop33x_init,
MACHINE_END
#else
diff --git a/arch/arm/mach-iop3xx/iop331-time.c b/arch/arm/mach-iop3xx/iop331-time.c
index e01696769263..1a6d9d661e4b 100644
--- a/arch/arm/mach-iop3xx/iop331-time.c
+++ b/arch/arm/mach-iop3xx/iop331-time.c
@@ -83,7 +83,7 @@ iop331_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction iop331_timer_irq = {
.name = "IOP331 Timer Tick",
.handler = iop331_timer_interrupt,
- .flags = SA_INTERRUPT
+ .flags = SA_INTERRUPT | SA_TIMER,
};
static void __init iop331_timer_init(void)
diff --git a/arch/arm/mach-ixp2000/Kconfig b/arch/arm/mach-ixp2000/Kconfig
index 9361e05f6fa3..ecb58d83478e 100644
--- a/arch/arm/mach-ixp2000/Kconfig
+++ b/arch/arm/mach-ixp2000/Kconfig
@@ -54,6 +54,14 @@ config ARCH_IXDP2X01
depends on ARCH_IXDP2401 || ARCH_IXDP2801
default y
+config IXP2000_SUPPORT_BROKEN_PCI_IO
+ bool "Support broken PCI I/O on older IXP2000s"
+ default y
+ help
+ Say 'N' here if you only intend to run your kernel on an
+ IXP2000 B0 or later model and do not need the PCI I/O
+ byteswap workaround. Say 'Y' otherwise.
+
endmenu
endif
diff --git a/arch/arm/mach-ixp2000/core.c b/arch/arm/mach-ixp2000/core.c
index fc0555596d6d..45b18658499f 100644
--- a/arch/arm/mach-ixp2000/core.c
+++ b/arch/arm/mach-ixp2000/core.c
@@ -23,7 +23,7 @@
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/bitops.h>
-#include <linux/serial_core.h>
+#include <linux/serial_8250.h>
#include <linux/mm.h>
#include <asm/types.h>
@@ -40,6 +40,8 @@
#include <asm/mach/time.h>
#include <asm/mach/irq.h>
+#include <asm/arch/gpio.h>
+
static DEFINE_SPINLOCK(ixp2000_slowport_lock);
static unsigned long ixp2000_slowport_irq_flags;
@@ -101,6 +103,11 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
.length = IXP2000_PCI_CSR_SIZE,
.type = MT_DEVICE
}, {
+ .virtual = IXP2000_MSF_VIRT_BASE,
+ .physical = IXP2000_MSF_PHYS_BASE,
+ .length = IXP2000_MSF_SIZE,
+ .type = MT_DEVICE
+ }, {
.virtual = IXP2000_PCI_IO_VIRT_BASE,
.physical = IXP2000_PCI_IO_PHYS_BASE,
.length = IXP2000_PCI_IO_SIZE,
@@ -118,19 +125,6 @@ static struct map_desc ixp2000_io_desc[] __initdata = {
}
};
-static struct uart_port ixp2000_serial_port = {
- .membase = (char *)(IXP2000_UART_VIRT_BASE + 3),
- .mapbase = IXP2000_UART_PHYS_BASE + 3,
- .irq = IRQ_IXP2000_UART,
- .flags = UPF_SKIP_TEST,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = 50000000,
- .line = 0,
- .type = PORT_XSCALE,
- .fifosize = 16
-};
-
void __init ixp2000_map_io(void)
{
extern unsigned int processor_id;
@@ -150,12 +144,50 @@ void __init ixp2000_map_io(void)
}
iotable_init(ixp2000_io_desc, ARRAY_SIZE(ixp2000_io_desc));
- early_serial_setup(&ixp2000_serial_port);
/* Set slowport to 8-bit mode. */
ixp2000_reg_write(IXP2000_SLOWPORT_FRM, 1);
}
+
+/*************************************************************************
+ * Serial port support for IXP2000
+ *************************************************************************/
+static struct plat_serial8250_port ixp2000_serial_port[] = {
+ {
+ .mapbase = IXP2000_UART_PHYS_BASE,
+ .membase = (char *)(IXP2000_UART_VIRT_BASE + 3),
+ .irq = IRQ_IXP2000_UART,
+ .flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = 50000000,
+ },
+ { },
+};
+
+static struct resource ixp2000_uart_resource = {
+ .start = IXP2000_UART_PHYS_BASE,
+ .end = IXP2000_UART_PHYS_BASE + 0xffff,
+ .flags = IORESOURCE_MEM,
+};
+
+static struct platform_device ixp2000_serial_device = {
+ .name = "serial8250",
+ .id = 0,
+ .dev = {
+ .platform_data = ixp2000_serial_port,
+ },
+ .num_resources = 1,
+ .resource = &ixp2000_uart_resource,
+};
+
+void __init ixp2000_uart_init(void)
+{
+ platform_device_register(&ixp2000_serial_device);
+}
+
+
/*************************************************************************
* Timer-tick functions for IXP2000
*************************************************************************/
@@ -179,7 +211,7 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* clear timer 1 */
ixp2000_reg_write(IXP2000_T1_CLR, 1);
-
+
while ((next_jiffy_time - *missing_jiffy_timer_csr) > ticks_per_jiffy) {
timer_tick(regs);
next_jiffy_time -= ticks_per_jiffy;
@@ -192,8 +224,8 @@ static int ixp2000_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction ixp2000_timer_irq = {
.name = "IXP2000 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = ixp2000_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = ixp2000_timer_interrupt,
};
void __init ixp2000_init_time(unsigned long tick_rate)
@@ -238,35 +270,40 @@ void __init ixp2000_init_time(unsigned long tick_rate)
/*************************************************************************
* GPIO helpers
*************************************************************************/
-static unsigned long GPIO_IRQ_rising_edge;
static unsigned long GPIO_IRQ_falling_edge;
+static unsigned long GPIO_IRQ_rising_edge;
static unsigned long GPIO_IRQ_level_low;
static unsigned long GPIO_IRQ_level_high;
-void gpio_line_config(int line, int style)
+static void update_gpio_int_csrs(void)
+{
+ ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
+ ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
+ ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
+ ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
+}
+
+void gpio_line_config(int line, int direction)
{
unsigned long flags;
local_irq_save(flags);
+ if (direction == GPIO_OUT) {
+ irq_desc[line + IRQ_IXP2000_GPIO0].valid = 0;
- if(style == GPIO_OUT) {
/* if it's an output, it ain't an interrupt anymore */
- ixp2000_reg_write(IXP2000_GPIO_PDSR, (1 << line));
GPIO_IRQ_falling_edge &= ~(1 << line);
GPIO_IRQ_rising_edge &= ~(1 << line);
GPIO_IRQ_level_low &= ~(1 << line);
GPIO_IRQ_level_high &= ~(1 << line);
- ixp2000_reg_write(IXP2000_GPIO_FEDR, GPIO_IRQ_falling_edge);
- ixp2000_reg_write(IXP2000_GPIO_REDR, GPIO_IRQ_rising_edge);
- ixp2000_reg_write(IXP2000_GPIO_LSHR, GPIO_IRQ_level_high);
- ixp2000_reg_write(IXP2000_GPIO_LSLR, GPIO_IRQ_level_low);
- irq_desc[line+IRQ_IXP2000_GPIO0].valid = 0;
- } else if(style == GPIO_IN) {
- ixp2000_reg_write(IXP2000_GPIO_PDCR, (1 << line));
+ update_gpio_int_csrs();
+
+ ixp2000_reg_write(IXP2000_GPIO_PDSR, 1 << line);
+ } else if (direction == GPIO_IN) {
+ ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
}
-
local_irq_restore(flags);
-}
+}
/*************************************************************************
@@ -285,9 +322,50 @@ static void ixp2000_GPIO_irq_handler(unsigned int irq, struct irqdesc *desc, str
}
}
+static int ixp2000_GPIO_irq_type(unsigned int irq, unsigned int type)
+{
+ int line = irq - IRQ_IXP2000_GPIO0;
+
+ /*
+ * First, configure this GPIO line as an input.
+ */
+ ixp2000_reg_write(IXP2000_GPIO_PDCR, 1 << line);
+
+ /*
+ * Then, set the proper trigger type.
+ */
+ if (type & IRQT_FALLING)
+ GPIO_IRQ_falling_edge |= 1 << line;
+ else
+ GPIO_IRQ_falling_edge &= ~(1 << line);
+ if (type & IRQT_RISING)
+ GPIO_IRQ_rising_edge |= 1 << line;
+ else
+ GPIO_IRQ_rising_edge &= ~(1 << line);
+ if (type & IRQT_LOW)
+ GPIO_IRQ_level_low |= 1 << line;
+ else
+ GPIO_IRQ_level_low &= ~(1 << line);
+ if (type & IRQT_HIGH)
+ GPIO_IRQ_level_high |= 1 << line;
+ else
+ GPIO_IRQ_level_high &= ~(1 << line);
+ update_gpio_int_csrs();
+
+ /*
+ * Finally, mark the corresponding IRQ as valid.
+ */
+ irq_desc[irq].valid = 1;
+
+ return 0;
+}
+
static void ixp2000_GPIO_irq_mask_ack(unsigned int irq)
{
ixp2000_reg_write(IXP2000_GPIO_INCR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+
+ ixp2000_reg_write(IXP2000_GPIO_EDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
+ ixp2000_reg_write(IXP2000_GPIO_LDSR, (1 << (irq - IRQ_IXP2000_GPIO0)));
ixp2000_reg_write(IXP2000_GPIO_INST, (1 << (irq - IRQ_IXP2000_GPIO0)));
}
@@ -302,6 +380,7 @@ static void ixp2000_GPIO_irq_unmask(unsigned int irq)
}
static struct irqchip ixp2000_GPIO_irq_chip = {
+ .type = ixp2000_GPIO_irq_type,
.ack = ixp2000_GPIO_irq_mask_ack,
.mask = ixp2000_GPIO_irq_mask,
.unmask = ixp2000_GPIO_irq_unmask
@@ -338,7 +417,7 @@ static void ixp2000_irq_mask(unsigned int irq)
static void ixp2000_irq_unmask(unsigned int irq)
{
- ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
+ ixp2000_reg_write(IXP2000_IRQ_ENABLE_SET, (1 << irq));
}
static struct irqchip ixp2000_irq_chip = {
@@ -375,16 +454,16 @@ void __init ixp2000_init_irq(void)
* our mask/unmask code much simpler.
*/
for (irq = IRQ_IXP2000_SOFT_INT; irq <= IRQ_IXP2000_THDB3; irq++) {
- if((1 << irq) & IXP2000_VALID_IRQ_MASK) {
+ if ((1 << irq) & IXP2000_VALID_IRQ_MASK) {
set_irq_chip(irq, &ixp2000_irq_chip);
set_irq_handler(irq, do_level_IRQ);
set_irq_flags(irq, IRQF_VALID);
} else set_irq_flags(irq, 0);
}
-
+
/*
* GPIO IRQs are invalid until someone sets the interrupt mode
- * by calling gpio_line_set();
+ * by calling set_irq_type().
*/
for (irq = IRQ_IXP2000_GPIO0; irq <= IRQ_IXP2000_GPIO7; irq++) {
set_irq_chip(irq, &ixp2000_GPIO_irq_chip);
diff --git a/arch/arm/mach-ixp2000/enp2611.c b/arch/arm/mach-ixp2000/enp2611.c
index 04b38bcf9aac..9aa54de44740 100644
--- a/arch/arm/mach-ixp2000/enp2611.c
+++ b/arch/arm/mach-ixp2000/enp2611.c
@@ -197,24 +197,42 @@ static struct platform_device enp2611_flash = {
.resource = &enp2611_flash_resource,
};
+static struct ixp2000_i2c_pins enp2611_i2c_gpio_pins = {
+ .sda_pin = ENP2611_GPIO_SDA,
+ .scl_pin = ENP2611_GPIO_SCL,
+};
+
+static struct platform_device enp2611_i2c_controller = {
+ .name = "IXP2000-I2C",
+ .id = 0,
+ .dev = {
+ .platform_data = &enp2611_i2c_gpio_pins
+ },
+ .num_resources = 0
+};
+
static struct platform_device *enp2611_devices[] __initdata = {
- &enp2611_flash
+ &enp2611_flash,
+ &enp2611_i2c_controller
};
static void __init enp2611_init_machine(void)
{
platform_add_devices(enp2611_devices, ARRAY_SIZE(enp2611_devices));
+ ixp2000_uart_init();
}
MACHINE_START(ENP2611, "Radisys ENP-2611 PCI network processor board")
- MAINTAINER("Lennert Buytenhek <buytenh@wantstofly.org>")
- BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
- BOOT_PARAMS(0x00000100)
- MAPIO(ixp2000_map_io)
- INITIRQ(ixp2000_init_irq)
+ /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
+ .phys_ram = 0x00000000,
+ .phys_io = IXP2000_UART_PHYS_BASE,
+ .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ixp2000_map_io,
+ .init_irq = ixp2000_init_irq,
.timer = &enp2611_timer,
- INIT_MACHINE(enp2611_init_machine)
+ .init_machine = enp2611_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ixp2000/ixdp2400.c b/arch/arm/mach-ixp2000/ixdp2400.c
index df3ff26c8cdd..fd280a93637e 100644
--- a/arch/arm/mach-ixp2000/ixdp2400.c
+++ b/arch/arm/mach-ixp2000/ixdp2400.c
@@ -168,12 +168,14 @@ void ixdp2400_init_irq(void)
}
MACHINE_START(IXDP2400, "Intel IXDP2400 Development Platform")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
- BOOT_PARAMS(0x00000100)
- MAPIO(ixdp2x00_map_io)
- INITIRQ(ixdp2400_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = 0x00000000,
+ .phys_io = IXP2000_UART_PHYS_BASE,
+ .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ixdp2x00_map_io,
+ .init_irq = ixdp2400_init_irq,
.timer = &ixdp2400_timer,
- INIT_MACHINE(ixdp2x00_init_machine)
+ .init_machine = ixdp2x00_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ixp2000/ixdp2800.c b/arch/arm/mach-ixp2000/ixdp2800.c
index aec13c7108a9..f9073aa28615 100644
--- a/arch/arm/mach-ixp2000/ixdp2800.c
+++ b/arch/arm/mach-ixp2000/ixdp2800.c
@@ -42,12 +42,6 @@
#include <asm/mach/flash.h>
#include <asm/mach/arch.h>
-
-void ixdp2400_init_irq(void)
-{
- ixdp2x00_init_irq(IXDP2800_CPLD_INT_STAT, IXDP2800_CPLD_INT_MASK, IXDP2400_NR_IRQS);
-}
-
/*************************************************************************
* IXDP2800 timer tick
*************************************************************************/
@@ -290,12 +284,14 @@ void ixdp2800_init_irq(void)
}
MACHINE_START(IXDP2800, "Intel IXDP2800 Development Platform")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(0x00000000, IXP2000_UART_PHYS_BASE, IXP2000_UART_VIRT_BASE)
- BOOT_PARAMS(0x00000100)
- MAPIO(ixdp2x00_map_io)
- INITIRQ(ixdp2800_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = 0x00000000,
+ .phys_io = IXP2000_UART_PHYS_BASE,
+ .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ixdp2x00_map_io,
+ .init_irq = ixdp2800_init_irq,
.timer = &ixdp2800_timer,
- INIT_MACHINE(ixdp2x00_init_machine)
+ .init_machine = ixdp2x00_init_machine,
MACHINE_END
diff --git a/arch/arm/mach-ixp2000/ixdp2x00.c b/arch/arm/mach-ixp2000/ixdp2x00.c
index 21c41fe15b99..a43369ad876c 100644
--- a/arch/arm/mach-ixp2000/ixdp2x00.c
+++ b/arch/arm/mach-ixp2000/ixdp2x00.c
@@ -42,6 +42,9 @@
#include <asm/mach/flash.h>
#include <asm/mach/arch.h>
+#include <asm/arch/gpio.h>
+
+
/*************************************************************************
* IXDP2x00 IRQ Initialization
*************************************************************************/
@@ -300,5 +303,6 @@ void __init ixdp2x00_init_machine(void)
gpio_line_config(IXDP2X00_GPIO_I2C_ENABLE, GPIO_OUT);
platform_add_devices(ixdp2x00_devices, ARRAY_SIZE(ixdp2x00_devices));
+ ixp2000_uart_init();
}
diff --git a/arch/arm/mach-ixp2000/ixdp2x01.c b/arch/arm/mach-ixp2000/ixdp2x01.c
index e94dace3d412..43447dad1657 100644
--- a/arch/arm/mach-ixp2000/ixdp2x01.c
+++ b/arch/arm/mach-ixp2000/ixdp2x01.c
@@ -370,30 +370,35 @@ static void __init ixdp2x01_init_machine(void)
((*IXDP2X01_CPLD_FLASH_REG & IXDP2X01_CPLD_FLASH_BANK_MASK) + 1);
platform_add_devices(ixdp2x01_devices, ARRAY_SIZE(ixdp2x01_devices));
+ ixp2000_uart_init();
}
#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)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = 0x00000000,
+ .phys_io = IXP2000_UART_PHYS_BASE,
+ .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ixdp2x01_map_io,
+ .init_irq = ixdp2x01_init_irq,
.timer = &ixdp2x01_timer,
- INIT_MACHINE(ixdp2x01_init_machine)
+ .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)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = 0x00000000,
+ .phys_io = IXP2000_UART_PHYS_BASE,
+ .io_pg_offst = ((IXP2000_UART_VIRT_BASE) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = ixdp2x01_map_io,
+ .init_irq = ixdp2x01_init_irq,
.timer = &ixdp2x01_timer,
- INIT_MACHINE(ixdp2x01_init_machine)
+ .init_machine = ixdp2x01_init_machine,
MACHINE_END
#endif
diff --git a/arch/arm/mach-ixp2000/pci.c b/arch/arm/mach-ixp2000/pci.c
index 5ff2f2718c58..0788fb2b5c10 100644
--- a/arch/arm/mach-ixp2000/pci.c
+++ b/arch/arm/mach-ixp2000/pci.c
@@ -198,6 +198,19 @@ clear_master_aborts(void)
void __init
ixp2000_pci_preinit(void)
{
+#ifndef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
+ /*
+ * Configure the PCI unit to properly byteswap I/O transactions,
+ * and verify that it worked.
+ */
+ ixp2000_reg_write(IXP2000_PCI_CONTROL,
+ (*IXP2000_PCI_CONTROL | PCI_CONTROL_IEE));
+
+ if ((*IXP2000_PCI_CONTROL & PCI_CONTROL_IEE) == 0)
+ panic("IXP2000: PCI I/O is broken on this ixp model, and "
+ "the needed workaround has not been configured in");
+#endif
+
hook_fault_code(16+6, ixp2000_pci_abort_handler, SIGBUS,
"PCI config cycle to non-existent device");
}
diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
index aa92e3708838..2b544363c078 100644
--- a/arch/arm/mach-ixp4xx/common-pci.c
+++ b/arch/arm/mach-ixp4xx/common-pci.c
@@ -453,8 +453,8 @@ int ixp4xx_setup(int nr, struct pci_sys_data *sys)
local_write_config(PCI_COMMAND, 2, PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY);
res[0].name = "PCI I/O Space";
- res[0].start = 0x00001000;
- res[0].end = 0xffff0000;
+ res[0].start = 0x00000000;
+ res[0].end = 0x0000ffff;
res[0].flags = IORESOURCE_IO;
res[1].name = "PCI Memory Space";
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index 267ba02d77dc..04490a9f8f6e 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -141,7 +141,15 @@ static struct map_desc ixp4xx_io_desc[] __initdata = {
.physical = IXP4XX_PCI_CFG_BASE_PHYS,
.length = IXP4XX_PCI_CFG_REGION_SIZE,
.type = MT_DEVICE
+ },
+#ifdef CONFIG_DEBUG_LL
+ { /* Debug UART mapping */
+ .virtual = IXP4XX_DEBUG_UART_BASE_VIRT,
+ .physical = IXP4XX_DEBUG_UART_BASE_PHYS,
+ .length = IXP4XX_DEBUG_UART_REGION_SIZE,
+ .type = MT_DEVICE
}
+#endif
};
void __init ixp4xx_map_io(void)
@@ -290,8 +298,8 @@ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs
static struct irqaction ixp4xx_timer_irq = {
.name = "IXP4xx Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = ixp4xx_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = ixp4xx_timer_interrupt,
};
static void __init ixp4xx_timer_init(void)
diff --git a/arch/arm/mach-ixp4xx/coyote-setup.c b/arch/arm/mach-ixp4xx/coyote-setup.c
index 8a05a1227e5f..4ff4393ef0ea 100644
--- a/arch/arm/mach-ixp4xx/coyote-setup.c
+++ b/arch/arm/mach-ixp4xx/coyote-setup.c
@@ -56,21 +56,24 @@ static struct resource coyote_uart_resource = {
.flags = IORESOURCE_MEM,
};
-static struct plat_serial8250_port coyote_uart_data = {
- .mapbase = IXP4XX_UART2_BASE_PHYS,
- .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
- .irq = IRQ_IXP4XX_UART2,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = IXP4XX_UART_XTAL,
+static struct plat_serial8250_port coyote_uart_data[] = {
+ {
+ .mapbase = IXP4XX_UART2_BASE_PHYS,
+ .membase = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
+ .irq = IRQ_IXP4XX_UART2,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = IXP4XX_UART_XTAL,
+ },
+ { },
};
static struct platform_device coyote_uart = {
.name = "serial8250",
.id = 0,
.dev = {
- .platform_data = &coyote_uart_data,
+ .platform_data = coyote_uart_data,
},
.num_resources = 1,
.resource = &coyote_uart_resource,
@@ -87,10 +90,10 @@ static void __init coyote_init(void)
*IXP4XX_EXP_CS1 = *IXP4XX_EXP_CS0;
if (machine_is_ixdpg425()) {
- coyote_uart_data.membase =
+ coyote_uart_data[0].membase =
(char*)(IXP4XX_UART1_BASE_VIRT + REG_OFFSET);
- coyote_uart_data.mapbase = IXP4XX_UART1_BASE_PHYS;
- coyote_uart_data.irq = IRQ_IXP4XX_UART1;
+ coyote_uart_data[0].mapbase = IXP4XX_UART1_BASE_PHYS;
+ coyote_uart_data[0].irq = IRQ_IXP4XX_UART1;
}
@@ -100,14 +103,15 @@ static void __init coyote_init(void)
#ifdef CONFIG_ARCH_ADI_COYOTE
MACHINE_START(ADI_COYOTE, "ADI Engineering Coyote")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(coyote_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = coyote_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(coyote_init)
+ .boot_params = 0x0100,
+ .init_machine = coyote_init,
MACHINE_END
#endif
@@ -117,14 +121,15 @@ MACHINE_END
*/
#ifdef CONFIG_MACH_IXDPG425
MACHINE_START(IXDPG425, "Intel IXDPG425")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(coyote_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = coyote_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(coyote_init)
+ .boot_params = 0x0100,
+ .init_machine = coyote_init,
MACHINE_END
#endif
diff --git a/arch/arm/mach-ixp4xx/gtwx5715-setup.c b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
index e77c86efd21d..8ba1cd9406e7 100644
--- a/arch/arm/mach-ixp4xx/gtwx5715-setup.c
+++ b/arch/arm/mach-ixp4xx/gtwx5715-setup.c
@@ -140,14 +140,15 @@ static void __init gtwx5715_init(void)
MACHINE_START(GTWX5715, "Gemtek GTWX5715 (Linksys WRV54G)")
- MAINTAINER("George Joseph")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_UART2_BASE_PHYS,
- IXP4XX_UART2_BASE_VIRT)
- MAPIO(gtwx5715_map_io)
- INITIRQ(ixp4xx_init_irq)
- .timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(gtwx5715_init)
+ /* Maintainer: George Joseph */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_UART2_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_UART2_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = gtwx5715_map_io,
+ .init_irq = ixp4xx_init_irq,
+ .timer = &ixp4xx_timer,
+ .boot_params = 0x0100,
+ .init_machine = gtwx5715_init,
MACHINE_END
diff --git a/arch/arm/mach-ixp4xx/ixdp425-setup.c b/arch/arm/mach-ixp4xx/ixdp425-setup.c
index 77346c1f676b..c2ba759e9946 100644
--- a/arch/arm/mach-ixp4xx/ixdp425-setup.c
+++ b/arch/arm/mach-ixp4xx/ixdp425-setup.c
@@ -95,7 +95,8 @@ static struct plat_serial8250_port ixdp425_uart_data[] = {
.iotype = UPIO_MEM,
.regshift = 2,
.uartclk = IXP4XX_UART_XTAL,
- }
+ },
+ { },
};
static struct platform_device ixdp425_uart = {
@@ -128,36 +129,39 @@ static void __init ixdp425_init(void)
}
MACHINE_START(IXDP425, "Intel IXDP425 Development Platform")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(ixdp425_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixdp425_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(ixdp425_init)
+ .boot_params = 0x0100,
+ .init_machine = ixdp425_init,
MACHINE_END
MACHINE_START(IXDP465, "Intel IXDP465 Development Platform")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(ixdp425_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixdp425_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(ixdp425_init)
+ .boot_params = 0x0100,
+ .init_machine = ixdp425_init,
MACHINE_END
MACHINE_START(IXCDP1100, "Intel IXCDP1100 Development Platform")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(ixdp425_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixdp425_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(ixdp425_init)
+ .boot_params = 0x0100,
+ .init_machine = ixdp425_init,
MACHINE_END
/*
@@ -168,14 +172,15 @@ MACHINE_END
*/
#ifdef CONFIG_ARCH_AVILA
MACHINE_START(AVILA, "Gateworks Avila Network Platform")
- MAINTAINER("Deepak Saxena <dsaxena@plexity.net>")
- BOOT_MEM(PHYS_OFFSET, IXP4XX_PERIPHERAL_BASE_PHYS,
- IXP4XX_PERIPHERAL_BASE_VIRT)
- MAPIO(ixdp425_map_io)
- INITIRQ(ixp4xx_init_irq)
+ /* Maintainer: Deepak Saxena <dsaxena@plexity.net> */
+ .phys_ram = PHYS_OFFSET,
+ .phys_io = IXP4XX_PERIPHERAL_BASE_PHYS,
+ .io_pg_offst = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xfffc,
+ .map_io = ixdp425_map_io,
+ .init_irq = ixp4xx_init_irq,
.timer = &ixp4xx_timer,
- BOOT_PARAMS(0x0100)
- INIT_MACHINE(ixdp425_init)
+ .boot_params = 0x0100,
+ .init_machine = ixdp425_init,
MACHINE_END
#endif
diff --git a/arch/arm/mach-l7200/core.c b/arch/arm/mach-l7200/core.c
index 606ca95f8217..2a7fee2a7635 100644
--- a/arch/arm/mach-l7200/core.c
+++ b/arch/arm/mach-l7200/core.c
@@ -81,9 +81,11 @@ static void __init l7200_map_io(void)
}
MACHINE_START(L7200, "LinkUp Systems L7200")
- MAINTAINER("Steve Hill / Scott McConnell")
- BOOT_MEM(0xf0000000, 0x80040000, 0xd0000000)
- MAPIO(l7200_map_io)
- INITIRQ(l7200_init_irq)
+ /* Maintainer: Steve Hill / Scott McConnell */
+ .phys_ram = 0xf0000000,
+ .phys_io = 0x80040000,
+ .io_pg_offst = ((0xd0000000) >> 18) & 0xfffc,
+ .map_io = l7200_map_io,
+ .init_irq = l7200_init_irq,
MACHINE_END
diff --git a/arch/arm/mach-lh7a40x/arch-kev7a400.c b/arch/arm/mach-lh7a40x/arch-kev7a400.c
index be5d17fe9dcb..cb3dcd3bd00a 100644
--- a/arch/arm/mach-lh7a40x/arch-kev7a400.c
+++ b/arch/arm/mach-lh7a40x/arch-kev7a400.c
@@ -102,10 +102,12 @@ void __init lh7a40x_init_board_irq (void)
}
MACHINE_START (KEV7A400, "Sharp KEV7a400")
- MAINTAINER ("Marc Singer")
- BOOT_MEM (0xc0000000, 0x80000000, io_p2v (0x80000000))
- BOOT_PARAMS (0xc0000100)
- MAPIO (kev7a400_map_io)
- INITIRQ (lh7a400_init_irq)
+ /* Maintainer: Marc Singer */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = kev7a400_map_io,
+ .init_irq = lh7a400_init_irq,
.timer = &lh7a40x_timer,
MACHINE_END
diff --git a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
index c823447a150f..6eb61a17c63b 100644
--- a/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
+++ b/arch/arm/mach-lh7a40x/arch-lpd7a40x.c
@@ -260,13 +260,15 @@ lpd7a400_map_io(void)
#ifdef CONFIG_MACH_LPD7A400
MACHINE_START (LPD7A400, "Logic Product Development LPD7A400-10")
- MAINTAINER ("Marc Singer")
- BOOT_MEM (0xc0000000, 0x80000000, io_p2v (0x80000000))
- BOOT_PARAMS (0xc0000100)
- MAPIO (lpd7a400_map_io)
- INITIRQ (lh7a400_init_irq)
+ /* Maintainer: Marc Singer */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = lpd7a400_map_io,
+ .init_irq = lh7a400_init_irq,
.timer = &lh7a40x_timer,
- INIT_MACHINE (lpd7a40x_init)
+ .init_machine = lpd7a40x_init,
MACHINE_END
#endif
@@ -274,13 +276,15 @@ MACHINE_END
#ifdef CONFIG_MACH_LPD7A404
MACHINE_START (LPD7A404, "Logic Product Development LPD7A404-10")
- MAINTAINER ("Marc Singer")
- BOOT_MEM (0xc0000000, 0x80000000, io_p2v (0x80000000))
- BOOT_PARAMS (0xc0000100)
- MAPIO (lpd7a400_map_io)
- INITIRQ (lh7a404_init_irq)
+ /* Maintainer: Marc Singer */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((io_p2v (0x80000000))>>18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = lpd7a400_map_io,
+ .init_irq = lh7a404_init_irq,
.timer = &lh7a40x_timer,
- INIT_MACHINE (lpd7a40x_init)
+ .init_machine = lpd7a40x_init,
MACHINE_END
#endif
diff --git a/arch/arm/mach-lh7a40x/time.c b/arch/arm/mach-lh7a40x/time.c
index 51e1c814b400..be377e331f25 100644
--- a/arch/arm/mach-lh7a40x/time.c
+++ b/arch/arm/mach-lh7a40x/time.c
@@ -53,8 +53,8 @@ lh7a40x_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction lh7a40x_timer_irq = {
.name = "LHA740x Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = lh7a40x_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = lh7a40x_timer_interrupt,
};
static void __init lh7a40x_timer_init(void)
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
deleted file mode 100644
index 9e42efa66b2b..000000000000
--- a/arch/arm/mach-omap/Kconfig
+++ /dev/null
@@ -1,221 +0,0 @@
-if ARCH_OMAP
-
-menu "TI OMAP Implementations"
-
-comment "OMAP Core Type"
-
-config ARCH_OMAP730
- depends on ARCH_OMAP
- bool "OMAP730 Based System"
- select ARCH_OMAP_OTG
-
-config ARCH_OMAP1510
- depends on ARCH_OMAP
- default y
- bool "OMAP1510 Based System"
-
-config ARCH_OMAP16XX
- depends on ARCH_OMAP
- bool "OMAP16XX Based System"
- select ARCH_OMAP_OTG
-
-config ARCH_OMAP_OTG
- bool
-
-comment "OMAP Board Type"
-
-config MACH_OMAP_INNOVATOR
- bool "TI Innovator"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX
- help
- TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
- have such a board.
-
-config MACH_OMAP_H2
- bool "TI H2 Support"
- depends on ARCH_OMAP16XX
- help
- TI OMAP 1610/1611B H2 board support. Say Y here if you have such
- a board.
-
-config MACH_OMAP_H3
- bool "TI H3 Support"
- depends on ARCH_OMAP16XX
- help
- TI OMAP 1710 H3 board support. Say Y here if you have such
- a board.
-
-config MACH_OMAP_H4
- bool "TI H4 Support"
- depends on ARCH_OMAP16XX
- help
- TI OMAP 1610 H4 board support. Say Y here if you have such
- a board.
-
-config MACH_OMAP_OSK
- bool "TI OSK Support"
- depends on ARCH_OMAP16XX
- help
- TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
- if you have such a board.
-
-config MACH_OMAP_PERSEUS2
- bool "TI Perseus2"
- depends on ARCH_OMAP730
- help
- Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
- a board.
-
-config MACH_VOICEBLUE
- bool "Voiceblue"
- depends on ARCH_OMAP1510
- help
- Support for Voiceblue GSM/VoIP gateway. Say Y here if you have such
- board.
-
-config MACH_NETSTAR
- bool "NetStar"
- depends on ARCH_OMAP1510
- help
- Support for NetStar PBX. Say Y here if you have such a board.
-
-config MACH_OMAP_GENERIC
- bool "Generic OMAP board"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX
- help
- Support for generic OMAP-1510, 1610 or 1710 board with
- no FPGA. Can be used as template for porting Linux to
- custom OMAP boards. Say Y here if you have a custom
- board.
-
-comment "OMAP Feature Selections"
-
-#config OMAP_BOOT_TAG
-# bool "OMAP bootloader information passing"
-# depends on ARCH_OMAP
-# default n
-# help
-# Say Y, if you have a bootloader which passes information
-# about your board and its peripheral configuration.
-
-config OMAP_MUX
- bool "OMAP multiplexing support"
- depends on ARCH_OMAP
- default y
- help
- Pin multiplexing support for OMAP boards. If your bootloader
- sets the multiplexing correctly, say N. Otherwise, or if unsure,
- say Y.
-
-config OMAP_MUX_DEBUG
- bool "Multiplexing debug output"
- depends on OMAP_MUX
- default n
- help
- Makes the multiplexing functions print out a lot of debug info.
- This is useful if you want to find out the correct values of the
- multiplexing registers.
-
-config OMAP_MUX_WARNINGS
- bool "Warn about pins the bootloader didn't set up"
- depends on OMAP_MUX
- default y
- help
- Choose Y here to warn whenever driver initialization logic needs
- to change the pin multiplexing setup. When there are no warnings
- printed, it's safe to deselect OMAP_MUX for your product.
-
-choice
- prompt "System timer"
- default OMAP_MPU_TIMER
-
-config OMAP_MPU_TIMER
- bool "Use mpu timer"
- help
- Select this option if you want to use the OMAP mpu timer. This
- timer provides more intra-tick resolution than the 32KHz timer,
- but consumes more power.
-
-config OMAP_32K_TIMER
- bool "Use 32KHz timer"
- depends on ARCH_OMAP16XX
- help
- Select this option if you want to enable the OMAP 32KHz timer.
- This timer saves power compared to the OMAP_MPU_TIMER, and has
- support for no tick during idle. The 32KHz timer provides less
- intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
- currently only available for OMAP-16xx.
-
-endchoice
-
-config OMAP_32K_TIMER_HZ
- int "Kernel internal timer frequency for 32KHz timer"
- range 32 1024
- depends on OMAP_32K_TIMER
- default "128"
- help
- Kernel internal timer frequency should be a divisor of 32768,
- such as 64 or 128.
-
-choice
- prompt "Low-level debug console UART"
- depends on ARCH_OMAP
- default OMAP_LL_DEBUG_UART1
-
-config OMAP_LL_DEBUG_UART1
- bool "UART1"
-
-config OMAP_LL_DEBUG_UART2
- bool "UART2"
-
-config OMAP_LL_DEBUG_UART3
- bool "UART3"
-
-endchoice
-
-config OMAP_ARM_195MHZ
- bool "OMAP ARM 195 MHz CPU"
- depends on ARCH_OMAP730
- help
- Enable 195MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_192MHZ
- bool "OMAP ARM 192 MHz CPU"
- depends on ARCH_OMAP16XX
- help
- Enable 192MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_182MHZ
- bool "OMAP ARM 182 MHz CPU"
- depends on ARCH_OMAP730
- help
- Enable 182MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_168MHZ
- bool "OMAP ARM 168 MHz CPU"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
- help
- Enable 168MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_120MHZ
- bool "OMAP ARM 120 MHz CPU"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
- help
- Enable 120MHz clock for OMAP CPU. If unsure, say N.
-
-config OMAP_ARM_60MHZ
- bool "OMAP ARM 60 MHz CPU"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
- default y
- help
- Enable 60MHz clock for OMAP CPU. If unsure, say Y.
-
-config OMAP_ARM_30MHZ
- bool "OMAP ARM 30 MHz CPU"
- depends on ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730
- help
- Enable 30MHz clock for OMAP CPU. If unsure, say N.
-
-endmenu
-
-endif
diff --git a/arch/arm/mach-omap/Makefile b/arch/arm/mach-omap/Makefile
deleted file mode 100644
index 4cafb11d2c02..000000000000
--- a/arch/arm/mach-omap/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-#
-# Makefile for the linux kernel.
-#
-
-# Common support
-obj-y := common.o time.o irq.o dma.o clock.o mux.o gpio.o mcbsp.o usb.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
-obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
-obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
-
-# OCPI interconnect support for 1710, 1610 and 5912
-obj-$(CONFIG_ARCH_OMAP16XX) += 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-h2p2-debug.o
-obj-$(CONFIG_LEDS) += $(led-y)
-
-# Power Management
-obj-$(CONFIG_PM) += pm.o sleep.o
-
-ifeq ($(CONFIG_ARCH_OMAP1510),y)
-# Innovator-1510 FPGA
-obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o
-endif
-
-# kgdb support
-obj-$(CONFIG_KGDB_SERIAL) += kgdb-serial.o
diff --git a/arch/arm/mach-omap/common.c b/arch/arm/mach-omap/common.c
deleted file mode 100644
index 265cde48586f..000000000000
--- a/arch/arm/mach-omap/common.c
+++ /dev/null
@@ -1,549 +0,0 @@
-/*
- * linux/arch/arm/mach-omap/common.c
- *
- * Code common to all OMAP machines.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/pm.h>
-#include <linux/console.h>
-#include <linux/serial.h>
-#include <linux/tty.h>
-#include <linux/serial_8250.h>
-#include <linux/serial_reg.h>
-
-#include <asm/hardware.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-#include <asm/mach/map.h>
-#include <asm/hardware/clock.h>
-#include <asm/io.h>
-#include <asm/mach-types.h>
-
-#include <asm/arch/board.h>
-#include <asm/arch/mux.h>
-#include <asm/arch/fpga.h>
-
-#include "clock.h"
-
-#define DEBUG 1
-
-struct omap_id {
- u16 jtag_id; /* Used to determine OMAP type */
- u8 die_rev; /* Processor revision */
- u32 omap_id; /* OMAP revision */
- u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */
-};
-
-/* Register values to detect the OMAP version */
-static struct omap_id omap_ids[] __initdata = {
- { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
- { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
- { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
- { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
- { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
- { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
- { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
- { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
- { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
- { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
- { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
- { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
- { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
- { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
- { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
- { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
- { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
- { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
-};
-
-/*
- * Get OMAP type from PROD_ID.
- * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
- * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
- * Undocumented register in TEST BLOCK is used as fallback; This seems to
- * work on 1510, 1610 & 1710. The official way hopefully will work in future
- * processors.
- */
-static u16 __init omap_get_jtag_id(void)
-{
- u32 prod_id, omap_id;
-
- prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
- omap_id = omap_readl(OMAP32_ID_1);
-
- /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
- if (((prod_id >> 20) == 0) || (prod_id == omap_id))
- prod_id = 0;
- else
- prod_id &= 0xffff;
-
- if (prod_id)
- return prod_id;
-
- /* Use OMAP32_ID_1 as fallback */
- prod_id = ((omap_id >> 12) & 0xffff);
-
- return prod_id;
-}
-
-/*
- * Get OMAP revision from DIE_REV.
- * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
- * Undocumented register in the TEST BLOCK is used as fallback.
- * REVISIT: This does not seem to work on 1510
- */
-static u8 __init omap_get_die_rev(void)
-{
- u32 die_rev;
-
- die_rev = omap_readl(OMAP_DIE_ID_1);
-
- /* Check for broken OMAP_DIE_ID on early 1710 */
- if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
- die_rev = 0;
-
- die_rev = (die_rev >> 17) & 0xf;
- if (die_rev)
- return die_rev;
-
- die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
-
- return die_rev;
-}
-
-static void __init omap_check_revision(void)
-{
- int i;
- u16 jtag_id;
- u8 die_rev;
- u32 omap_id;
- u8 cpu_type;
-
- jtag_id = omap_get_jtag_id();
- die_rev = omap_get_die_rev();
- omap_id = omap_readl(OMAP32_ID_0);
-
-#ifdef DEBUG
- printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
- printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
- omap_readl(OMAP_DIE_ID_1),
- (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
- printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
- printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
- omap_readl(OMAP_PRODUCTION_ID_1),
- omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
- printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
- printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
- printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
-#endif
-
- system_serial_high = omap_readl(OMAP_DIE_ID_0);
- system_serial_low = omap_readl(OMAP_DIE_ID_1);
-
- /* First check only the major version in a safe way */
- for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
- if (jtag_id == (omap_ids[i].jtag_id)) {
- system_rev = omap_ids[i].type;
- break;
- }
- }
-
- /* Check if we can find the die revision */
- for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
- if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
- system_rev = omap_ids[i].type;
- break;
- }
- }
-
- /* Finally check also the omap_id */
- for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
- if (jtag_id == omap_ids[i].jtag_id
- && die_rev == omap_ids[i].die_rev
- && omap_id == omap_ids[i].omap_id) {
- system_rev = omap_ids[i].type;
- break;
- }
- }
-
- /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
- cpu_type = system_rev >> 24;
-
- switch (cpu_type) {
- case 0x07:
- system_rev |= 0x07;
- break;
- case 0x15:
- system_rev |= 0x15;
- break;
- case 0x16:
- case 0x17:
- system_rev |= 0x16;
- break;
- case 0x24:
- system_rev |= 0x24;
- break;
- default:
- printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
- }
-
- printk("OMAP%04x", system_rev >> 16);
- if ((system_rev >> 8) & 0xff)
- printk("%x", (system_rev >> 8) & 0xff);
- printk(" revision %i handled as %02xxx id: %08x%08x\n",
- die_rev, system_rev & 0xff, system_serial_low,
- system_serial_high);
-}
-
-/*
- * ----------------------------------------------------------------------------
- * OMAP I/O mapping
- *
- * The machine specific code may provide the extra mapping besides the
- * default mapping provided here.
- * ----------------------------------------------------------------------------
- */
-
-static struct map_desc omap_io_desc[] __initdata = {
- { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
-};
-
-#ifdef CONFIG_ARCH_OMAP730
-static struct map_desc omap730_io_desc[] __initdata = {
- { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE },
- { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
- { OMAP730_SRAM_BASE, OMAP730_SRAM_START, OMAP730_SRAM_SIZE, MT_DEVICE }
-};
-#endif
-
-#ifdef CONFIG_ARCH_OMAP1510
-static struct map_desc omap1510_io_desc[] __initdata = {
- { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE },
- { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
- { OMAP1510_SRAM_BASE, OMAP1510_SRAM_START, OMAP1510_SRAM_SIZE, MT_DEVICE }
-};
-#endif
-
-#if defined(CONFIG_ARCH_OMAP16XX)
-static struct map_desc omap1610_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
- { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP1610_SRAM_SIZE, MT_DEVICE }
-};
-
-static struct map_desc omap5912_io_desc[] __initdata = {
- { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE },
- { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
-/*
- * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
- * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
- * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
- * can be used.
- */
- { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE }
-};
-#endif
-
-static int initialized = 0;
-
-static void __init _omap_map_io(void)
-{
- initialized = 1;
-
- /* We have to initialize the IO space mapping before we can run
- * cpu_is_omapxxx() macros. */
- iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
- omap_check_revision();
-
-#ifdef CONFIG_ARCH_OMAP730
- if (cpu_is_omap730()) {
- iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
- }
-#endif
-#ifdef CONFIG_ARCH_OMAP1510
- if (cpu_is_omap1510()) {
- iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
- }
-#endif
-#if defined(CONFIG_ARCH_OMAP16XX)
- if (cpu_is_omap1610() || cpu_is_omap1710()) {
- iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
- }
- if (cpu_is_omap5912()) {
- iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
- }
-#endif
-
- /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
- * on a Posted Write in the TIPB Bridge".
- */
- omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
- omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
-
- /* Must init clocks early to assure that timer interrupt works
- */
- clk_init();
-}
-
-/*
- * This should only get called from board specific init
- */
-void omap_map_io(void)
-{
- if (!initialized)
- _omap_map_io();
-}
-
-static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
- int offset)
-{
- offset <<= up->regshift;
- return (unsigned int)__raw_readb(up->membase + offset);
-}
-
-static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
- int value)
-{
- offset <<= p->regshift;
- __raw_writeb(value, p->membase + offset);
-}
-
-/*
- * Internal UARTs need to be initialized for the 8250 autoconfig to work
- * properly. Note that the TX watermark initialization may not be needed
- * once the 8250.c watermark handling code is merged.
- */
-static void __init omap_serial_reset(struct plat_serial8250_port *p)
-{
- omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */
- omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */
- omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */
-
- if (!cpu_is_omap1510()) {
- omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
- while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
- }
-}
-
-static struct plat_serial8250_port serial_platform_data[] = {
- {
- .membase = (char*)IO_ADDRESS(OMAP_UART1_BASE),
- .mapbase = (unsigned long)OMAP_UART1_BASE,
- .irq = INT_UART1,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
- },
- {
- .membase = (char*)IO_ADDRESS(OMAP_UART2_BASE),
- .mapbase = (unsigned long)OMAP_UART2_BASE,
- .irq = INT_UART2,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
- },
- {
- .membase = (char*)IO_ADDRESS(OMAP_UART3_BASE),
- .mapbase = (unsigned long)OMAP_UART3_BASE,
- .irq = INT_UART3,
- .flags = UPF_BOOT_AUTOCONF,
- .iotype = UPIO_MEM,
- .regshift = 2,
- .uartclk = OMAP16XX_BASE_BAUD * 16,
- },
- { },
-};
-
-static struct platform_device serial_device = {
- .name = "serial8250",
- .id = 0,
- .dev = {
- .platform_data = serial_platform_data,
- },
-};
-
-/*
- * Note that on Innovator-1510 UART2 pins conflict with USB2.
- * By default UART2 does not work on Innovator-1510 if you have
- * USB OHCI enabled. To use UART2, you must disable USB2 first.
- */
-void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
-{
- int i;
-
- if (cpu_is_omap730()) {
- serial_platform_data[0].regshift = 0;
- serial_platform_data[1].regshift = 0;
- serial_platform_data[0].irq = INT_730_UART_MODEM_1;
- serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
- }
-
- if (cpu_is_omap1510()) {
- serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
- serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
- serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
- }
-
- for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
- unsigned char reg;
-
- if (ports[i] == 0) {
- serial_platform_data[i].membase = 0;
- serial_platform_data[i].mapbase = 0;
- continue;
- }
-
- switch (i) {
- case 0:
- if (cpu_is_omap1510()) {
- omap_cfg_reg(UART1_TX);
- omap_cfg_reg(UART1_RTS);
- if (machine_is_omap_innovator()) {
- reg = fpga_read(OMAP1510_FPGA_POWER);
- reg |= OMAP1510_FPGA_PCR_COM1_EN;
- fpga_write(reg, OMAP1510_FPGA_POWER);
- udelay(10);
- }
- }
- break;
- case 1:
- if (cpu_is_omap1510()) {
- omap_cfg_reg(UART2_TX);
- omap_cfg_reg(UART2_RTS);
- if (machine_is_omap_innovator()) {
- reg = fpga_read(OMAP1510_FPGA_POWER);
- reg |= OMAP1510_FPGA_PCR_COM2_EN;
- fpga_write(reg, OMAP1510_FPGA_POWER);
- udelay(10);
- }
- }
- break;
- case 2:
- if (cpu_is_omap1510()) {
- omap_cfg_reg(UART3_TX);
- omap_cfg_reg(UART3_RX);
- }
- if (cpu_is_omap1710()) {
- clk_enable(clk_get(0, "uart3_ck"));
- }
- break;
- }
- omap_serial_reset(&serial_platform_data[i]);
- }
-}
-
-static int __init omap_init(void)
-{
- return platform_device_register(&serial_device);
-}
-arch_initcall(omap_init);
-
-#define NO_LENGTH_CHECK 0xffffffff
-
-extern int omap_bootloader_tag_len;
-extern u8 omap_bootloader_tag[];
-
-struct omap_board_config_kernel *omap_board_config;
-int omap_board_config_size = 0;
-
-static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
-{
- struct omap_board_config_kernel *kinfo = NULL;
- int i;
-
-#ifdef CONFIG_OMAP_BOOT_TAG
- struct omap_board_config_entry *info = NULL;
-
- if (omap_bootloader_tag_len > 4)
- info = (struct omap_board_config_entry *) omap_bootloader_tag;
- while (info != NULL) {
- u8 *next;
-
- if (info->tag == tag) {
- if (skip == 0)
- break;
- skip--;
- }
-
- if ((info->len & 0x03) != 0) {
- /* We bail out to avoid an alignment fault */
- printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
- info->len, info->tag);
- return NULL;
- }
- next = (u8 *) info + sizeof(*info) + info->len;
- if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
- info = NULL;
- else
- info = (struct omap_board_config_entry *) next;
- }
- if (info != NULL) {
- /* Check the length as a lame attempt to check for
- * binary inconsistancy. */
- if (len != NO_LENGTH_CHECK) {
- /* Word-align len */
- if (len & 0x03)
- len = (len + 3) & ~0x03;
- 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;
- }
- }
- if (len_out != NULL)
- *len_out = info->len;
- return info->data;
- }
-#endif
- /* 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;
- }
- }
- if (kinfo == NULL)
- return NULL;
- return kinfo->data;
-}
-
-const void *__omap_get_config(u16 tag, size_t len, int nr)
-{
- return get_config(tag, len, nr, NULL);
-}
-EXPORT_SYMBOL(__omap_get_config);
-
-const void *omap_get_var_config(u16 tag, size_t *len)
-{
- return get_config(tag, NO_LENGTH_CHECK, 0, len);
-}
-EXPORT_SYMBOL(omap_get_var_config);
-
-static int __init omap_add_serial_console(void)
-{
- const struct omap_uart_config *info;
-
- info = omap_get_config(OMAP_TAG_UART, struct omap_uart_config);
- if (info != NULL && info->console_uart) {
- static char speed[11], *opt = NULL;
-
- if (info->console_speed) {
- snprintf(speed, sizeof(speed), "%u", info->console_speed);
- opt = speed;
- }
- return add_preferred_console("ttyS", info->console_uart - 1, opt);
- }
- return 0;
-}
-console_initcall(omap_add_serial_console);
diff --git a/arch/arm/mach-omap1/Kconfig b/arch/arm/mach-omap1/Kconfig
new file mode 100644
index 000000000000..7408ac94f771
--- /dev/null
+++ b/arch/arm/mach-omap1/Kconfig
@@ -0,0 +1,144 @@
+comment "OMAP Core Type"
+ depends on ARCH_OMAP1
+
+config ARCH_OMAP730
+ depends on ARCH_OMAP1
+ bool "OMAP730 Based System"
+ select ARCH_OMAP_OTG
+
+config ARCH_OMAP1510
+ depends on ARCH_OMAP1
+ default y
+ bool "OMAP1510 Based System"
+
+config ARCH_OMAP16XX
+ depends on ARCH_OMAP1
+ bool "OMAP16xx Based System"
+ select ARCH_OMAP_OTG
+
+comment "OMAP Board Type"
+ depends on ARCH_OMAP1
+
+config MACH_OMAP_INNOVATOR
+ bool "TI Innovator"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+ help
+ TI OMAP 1510 or 1610 Innovator board support. Say Y here if you
+ have such a board.
+
+config MACH_OMAP_H2
+ bool "TI H2 Support"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ TI OMAP 1610/1611B H2 board support. Say Y here if you have such
+ a board.
+
+config MACH_OMAP_H3
+ bool "TI H3 Support"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ TI OMAP 1710 H3 board support. Say Y here if you have such
+ a board.
+
+config MACH_OMAP_OSK
+ bool "TI OSK Support"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ TI OMAP 5912 OSK (OMAP Starter Kit) board support. Say Y here
+ if you have such a board.
+
+config MACH_OMAP_PERSEUS2
+ bool "TI Perseus2"
+ depends on ARCH_OMAP1 && ARCH_OMAP730
+ help
+ Support for TI OMAP 730 Perseus2 board. Say Y here if you have such
+ a board.
+
+config MACH_VOICEBLUE
+ bool "Voiceblue"
+ depends on ARCH_OMAP1 && ARCH_OMAP1510
+ help
+ Support for Voiceblue GSM/VoIP gateway. Say Y here if you have
+ such a board.
+
+config MACH_NETSTAR
+ bool "NetStar"
+ depends on ARCH_OMAP1 && ARCH_OMAP1510
+ help
+ Support for NetStar PBX. Say Y here if you have such a board.
+
+config MACH_OMAP_GENERIC
+ bool "Generic OMAP board"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX)
+ help
+ Support for generic OMAP-1510, 1610 or 1710 board with
+ no FPGA. Can be used as template for porting Linux to
+ custom OMAP boards. Say Y here if you have a custom
+ board.
+
+comment "OMAP CPU Speed"
+ depends on ARCH_OMAP1
+
+config OMAP_CLOCKS_SET_BY_BOOTLOADER
+ bool "OMAP clocks set by bootloader"
+ depends on ARCH_OMAP1
+ help
+ Enable this option to prevent the kernel from overriding the clock
+ frequencies programmed by bootloader for MPU, DSP, MMUs, TC,
+ internal LCD controller and MPU peripherals.
+
+config OMAP_ARM_216MHZ
+ bool "OMAP ARM 216 MHz CPU (1710 only)"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ Enable 216 MHz clock for OMAP1710 CPU. If unsure, say N.
+
+config OMAP_ARM_195MHZ
+ bool "OMAP ARM 195 MHz CPU"
+ depends on ARCH_OMAP1 && ARCH_OMAP730
+ help
+ Enable 195MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_192MHZ
+ bool "OMAP ARM 192 MHz CPU"
+ depends on ARCH_OMAP1 && ARCH_OMAP16XX
+ help
+ Enable 192MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_182MHZ
+ bool "OMAP ARM 182 MHz CPU"
+ depends on ARCH_OMAP1 && ARCH_OMAP730
+ help
+ Enable 182MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_168MHZ
+ bool "OMAP ARM 168 MHz CPU"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+ help
+ Enable 168MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_150MHZ
+ bool "OMAP ARM 150 MHz CPU"
+ depends on ARCH_OMAP1 && ARCH_OMAP1510
+ help
+ Enable 150MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_120MHZ
+ bool "OMAP ARM 120 MHz CPU"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+ help
+ Enable 120MHz clock for OMAP CPU. If unsure, say N.
+
+config OMAP_ARM_60MHZ
+ bool "OMAP ARM 60 MHz CPU"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+ default y
+ help
+ Enable 60MHz clock for OMAP CPU. If unsure, say Y.
+
+config OMAP_ARM_30MHZ
+ bool "OMAP ARM 30 MHz CPU"
+ depends on ARCH_OMAP1 && (ARCH_OMAP1510 || ARCH_OMAP16XX || ARCH_OMAP730)
+ help
+ Enable 30MHz clock for OMAP CPU. If unsure, say N.
+
diff --git a/arch/arm/mach-omap1/Makefile b/arch/arm/mach-omap1/Makefile
new file mode 100644
index 000000000000..d386fd913f0c
--- /dev/null
+++ b/arch/arm/mach-omap1/Makefile
@@ -0,0 +1,30 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := io.o id.o irq.o time.o serial.o
+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
+obj-$(CONFIG_MACH_VOICEBLUE) += board-voiceblue.o
+obj-$(CONFIG_MACH_NETSTAR) += board-netstar.o
+
+ifeq ($(CONFIG_ARCH_OMAP1510),y)
+# Innovator-1510 FPGA
+obj-$(CONFIG_MACH_OMAP_INNOVATOR) += fpga.o
+endif
+
+# 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-h2p2-debug.o
+led-$(CONFIG_MACH_OMAP_OSK) += leds-osk.o
+obj-$(CONFIG_LEDS) += $(led-y)
+
diff --git a/arch/arm/mach-omap/Makefile.boot b/arch/arm/mach-omap1/Makefile.boot
index fee1a6a15b54..292d56c5a888 100644
--- a/arch/arm/mach-omap/Makefile.boot
+++ b/arch/arm/mach-omap1/Makefile.boot
@@ -1,4 +1,3 @@
zreladdr-y := 0x10008000
params_phys-y := 0x10000100
initrd_phys-y := 0x10800000
-
diff --git a/arch/arm/mach-omap/board-generic.c b/arch/arm/mach-omap1/board-generic.c
index 2102a2cd1013..122796ebe8f5 100644
--- a/arch/arm/mach-omap/board-generic.c
+++ b/arch/arm/mach-omap1/board-generic.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-generic.c
+ * linux/arch/arm/mach-omap1/board-generic.c
*
* Modified from board-innovator1510.c
*
@@ -26,8 +26,7 @@
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
#include <asm/arch/board.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
static int __initdata generic_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
@@ -84,15 +83,17 @@ static void __init omap_generic_init(void)
static void __init omap_generic_map_io(void)
{
- omap_map_io();
+ omap_map_common_io()
}
MACHINE_START(OMAP_GENERIC, "Generic OMAP1510/1610/1710")
- MAINTAINER("Tony Lindgren <tony@atomide.com>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(omap_generic_map_io)
- INITIRQ(omap_generic_init_irq)
- INIT_MACHINE(omap_generic_init)
+ /* Maintainer: Tony Lindgren <tony@atomide.com> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = omap_generic_map_io,
+ .init_irq = omap_generic_init_irq,
+ .init_machine = omap_generic_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-h2.c b/arch/arm/mach-omap1/board-h2.c
index 1f067830d1fc..f4983ee95ab4 100644
--- a/arch/arm/mach-omap/board-h2.c
+++ b/arch/arm/mach-omap1/board-h2.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-h2.c
+ * linux/arch/arm/mach-omap1/board-h2.c
*
* Board specific inits for OMAP-1610 H2
*
@@ -35,8 +35,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
extern int omap_gpio_init(void);
@@ -172,16 +171,18 @@ static void __init h2_init(void)
static void __init h2_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
omap_serial_init(h2_serial_ports);
}
MACHINE_START(OMAP_H2, "TI-H2")
- MAINTAINER("Imre Deak <imre.deak@nokia.com>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(h2_map_io)
- INITIRQ(h2_init_irq)
- INIT_MACHINE(h2_init)
+ /* Maintainer: Imre Deak <imre.deak@nokia.com> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = h2_map_io,
+ .init_irq = h2_init_irq,
+ .init_machine = h2_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-h3.c b/arch/arm/mach-omap1/board-h3.c
index 486a5a006c9a..7cd419d61b40 100644
--- a/arch/arm/mach-omap/board-h3.c
+++ b/arch/arm/mach-omap1/board-h3.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-h3.c
+ * linux/arch/arm/mach-omap1/board-h3.c
*
* This file contains OMAP1710 H3 specific code.
*
@@ -37,8 +37,7 @@
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
extern int omap_gpio_init(void);
@@ -190,16 +189,18 @@ void h3_init_irq(void)
static void __init h3_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
omap_serial_init(h3_serial_ports);
}
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)
+ /* Maintainer: Texas Instruments, Inc. */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = h3_map_io,
+ .init_irq = h3_init_irq,
+ .init_machine = h3_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-innovator.c b/arch/arm/mach-omap1/board-innovator.c
index 57cf4da88d55..91de60a91ef8 100644
--- a/arch/arm/mach-omap/board-innovator.c
+++ b/arch/arm/mach-omap1/board-innovator.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-innovator.c
+ * linux/arch/arm/mach-omap1/board-innovator.c
*
* Board specific inits for OMAP-1510 and OMAP-1610 Innovator
*
@@ -33,8 +33,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/tc.h>
#include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
static int __initdata innovator_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
@@ -252,7 +251,7 @@ static void __init innovator_init(void)
static void __init innovator_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
#ifdef CONFIG_ARCH_OMAP1510
if (cpu_is_omap1510()) {
@@ -270,11 +269,13 @@ static void __init innovator_map_io(void)
}
MACHINE_START(OMAP_INNOVATOR, "TI-Innovator")
- MAINTAINER("MontaVista Software, Inc.")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(innovator_map_io)
- INITIRQ(innovator_init_irq)
- INIT_MACHINE(innovator_init)
+ /* Maintainer: MontaVista Software, Inc. */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = innovator_map_io,
+ .init_irq = innovator_init_irq,
+ .init_machine = innovator_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-netstar.c b/arch/arm/mach-omap1/board-netstar.c
index 54acbd215c4b..6750b2014092 100644
--- a/arch/arm/mach-omap/board-netstar.c
+++ b/arch/arm/mach-omap1/board-netstar.c
@@ -26,8 +26,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
extern void __init omap_init_time(void);
extern int omap_gpio_init(void);
@@ -100,7 +99,7 @@ static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
static void __init netstar_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
omap_serial_init(omap_serial_ports);
}
@@ -141,11 +140,13 @@ static int __init netstar_late_init(void)
postcore_initcall(netstar_late_init);
MACHINE_START(NETSTAR, "NetStar OMAP5910")
- MAINTAINER("Ladislav Michl <michl@2n.cz>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(netstar_map_io)
- INITIRQ(netstar_init_irq)
- INIT_MACHINE(netstar_init)
- .timer = &omap_timer,
+ /* Maintainer: Ladislav Michl <michl@2n.cz> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = netstar_map_io,
+ .init_irq = netstar_init_irq,
+ .init_machine = netstar_init,
+ .timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-osk.c b/arch/arm/mach-omap1/board-osk.c
index a951fc82459b..6844e536c698 100644
--- a/arch/arm/mach-omap/board-osk.c
+++ b/arch/arm/mach-omap1/board-osk.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-osk.c
+ * linux/arch/arm/mach-omap1/board-osk.c
*
* Board specific init for OMAP5912 OSK
*
@@ -39,8 +39,7 @@
#include <asm/arch/usb.h>
#include <asm/arch/mux.h>
#include <asm/arch/tc.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
static struct map_desc osk5912_io_desc[] __initdata = {
{ OMAP_OSK_NOR_FLASH_BASE, OMAP_OSK_NOR_FLASH_START, OMAP_OSK_NOR_FLASH_SIZE,
@@ -153,17 +152,19 @@ static void __init osk_init(void)
static void __init osk_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
iotable_init(osk5912_io_desc, ARRAY_SIZE(osk5912_io_desc));
omap_serial_init(osk_serial_ports);
}
MACHINE_START(OMAP_OSK, "TI-OSK")
- MAINTAINER("Dirk Behme <dirk.behme@de.bosch.com>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(osk_map_io)
- INITIRQ(osk_init_irq)
- INIT_MACHINE(osk_init)
+ /* Maintainer: Dirk Behme <dirk.behme@de.bosch.com> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = osk_map_io,
+ .init_irq = osk_init_irq,
+ .init_machine = osk_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-perseus2.c b/arch/arm/mach-omap1/board-perseus2.c
index 64515aeb49cf..213317392d9b 100644
--- a/arch/arm/mach-omap/board-perseus2.c
+++ b/arch/arm/mach-omap1/board-perseus2.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-perseus2.c
+ * linux/arch/arm/mach-omap1/board-perseus2.c
*
* Modified from board-generic.c
*
@@ -27,8 +27,7 @@
#include <asm/arch/gpio.h>
#include <asm/arch/mux.h>
#include <asm/arch/fpga.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
static struct resource smc91x_resources[] = {
[0] = {
@@ -140,7 +139,7 @@ static struct map_desc omap_perseus2_io_desc[] __initdata = {
static void __init omap_perseus2_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
iotable_init(omap_perseus2_io_desc,
ARRAY_SIZE(omap_perseus2_io_desc));
@@ -179,11 +178,13 @@ static void __init omap_perseus2_map_io(void)
}
MACHINE_START(OMAP_PERSEUS2, "OMAP730 Perseus2")
- MAINTAINER("Kevin Hilman <kjh@hilman.org>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(omap_perseus2_map_io)
- INITIRQ(omap_perseus2_init_irq)
- INIT_MACHINE(omap_perseus2_init)
+ /* Maintainer: Kevin Hilman <kjh@hilman.org> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = omap_perseus2_map_io,
+ .init_irq = omap_perseus2_init_irq,
+ .init_machine = omap_perseus2_init,
.timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/board-voiceblue.c b/arch/arm/mach-omap1/board-voiceblue.c
index f1a5bffac666..e42281988990 100644
--- a/arch/arm/mach-omap/board-voiceblue.c
+++ b/arch/arm/mach-omap1/board-voiceblue.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/board-voiceblue.c
+ * linux/arch/arm/mach-omap1/board-voiceblue.c
*
* Modified from board-generic.c
*
@@ -31,8 +31,7 @@
#include <asm/arch/tc.h>
#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
-
-#include "common.h"
+#include <asm/arch/common.h>
extern void omap_init_time(void);
extern int omap_gpio_init(void);
@@ -170,7 +169,7 @@ static int __initdata omap_serial_ports[OMAP_MAX_NR_PORTS] = {1, 1, 1};
static void __init voiceblue_map_io(void)
{
- omap_map_io();
+ omap_map_common_io();
omap_serial_init(omap_serial_ports);
}
@@ -246,11 +245,13 @@ EXPORT_SYMBOL(voiceblue_wdt_disable);
EXPORT_SYMBOL(voiceblue_wdt_ping);
MACHINE_START(VOICEBLUE, "VoiceBlue OMAP5910")
- MAINTAINER("Ladislav Michl <michl@2n.cz>")
- BOOT_MEM(0x10000000, 0xfff00000, 0xfef00000)
- BOOT_PARAMS(0x10000100)
- MAPIO(voiceblue_map_io)
- INITIRQ(voiceblue_init_irq)
- INIT_MACHINE(voiceblue_init)
- .timer = &omap_timer,
+ /* Maintainer: Ladislav Michl <michl@2n.cz> */
+ .phys_ram = 0x10000000,
+ .phys_io = 0xfff00000,
+ .io_pg_offst = ((0xfef00000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .map_io = voiceblue_map_io,
+ .init_irq = voiceblue_init_irq,
+ .init_machine = voiceblue_init,
+ .timer = &omap_timer,
MACHINE_END
diff --git a/arch/arm/mach-omap/fpga.c b/arch/arm/mach-omap1/fpga.c
index 7c08f6c2e1d0..7c08f6c2e1d0 100644
--- a/arch/arm/mach-omap/fpga.c
+++ b/arch/arm/mach-omap1/fpga.c
diff --git a/arch/arm/mach-omap1/id.c b/arch/arm/mach-omap1/id.c
new file mode 100644
index 000000000000..986c3b7e09bb
--- /dev/null
+++ b/arch/arm/mach-omap1/id.c
@@ -0,0 +1,188 @@
+/*
+ * linux/arch/arm/mach-omap1/id.c
+ *
+ * OMAP1 CPU identification code
+ *
+ * Copyright (C) 2004 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct omap_id {
+ u16 jtag_id; /* Used to determine OMAP type */
+ u8 die_rev; /* Processor revision */
+ u32 omap_id; /* OMAP revision */
+ u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */
+};
+
+/* Register values to detect the OMAP version */
+static struct omap_id omap_ids[] __initdata = {
+ { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
+ { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
+ { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
+ { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
+ { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
+ { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
+ { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
+ { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+ { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
+ { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
+ { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
+ { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
+ { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
+ { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
+ { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
+ { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
+ { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
+ { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
+};
+
+/*
+ * Get OMAP type from PROD_ID.
+ * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
+ * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
+ * Undocumented register in TEST BLOCK is used as fallback; This seems to
+ * work on 1510, 1610 & 1710. The official way hopefully will work in future
+ * processors.
+ */
+static u16 __init omap_get_jtag_id(void)
+{
+ u32 prod_id, omap_id;
+
+ prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
+ omap_id = omap_readl(OMAP32_ID_1);
+
+ /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730 */
+ if (((prod_id >> 20) == 0) || (prod_id == omap_id))
+ prod_id = 0;
+ else
+ prod_id &= 0xffff;
+
+ if (prod_id)
+ return prod_id;
+
+ /* Use OMAP32_ID_1 as fallback */
+ prod_id = ((omap_id >> 12) & 0xffff);
+
+ return prod_id;
+}
+
+/*
+ * Get OMAP revision from DIE_REV.
+ * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
+ * Undocumented register in the TEST BLOCK is used as fallback.
+ * REVISIT: This does not seem to work on 1510
+ */
+static u8 __init omap_get_die_rev(void)
+{
+ u32 die_rev;
+
+ die_rev = omap_readl(OMAP_DIE_ID_1);
+
+ /* Check for broken OMAP_DIE_ID on early 1710 */
+ if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
+ die_rev = 0;
+
+ die_rev = (die_rev >> 17) & 0xf;
+ if (die_rev)
+ return die_rev;
+
+ die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
+
+ return die_rev;
+}
+
+void __init omap_check_revision(void)
+{
+ int i;
+ u16 jtag_id;
+ u8 die_rev;
+ u32 omap_id;
+ u8 cpu_type;
+
+ jtag_id = omap_get_jtag_id();
+ die_rev = omap_get_die_rev();
+ omap_id = omap_readl(OMAP32_ID_0);
+
+#ifdef DEBUG
+ printk("OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
+ printk("OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
+ omap_readl(OMAP_DIE_ID_1),
+ (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
+ printk("OMAP_PRODUCTION_ID_0: 0x%08x\n", omap_readl(OMAP_PRODUCTION_ID_0));
+ printk("OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
+ omap_readl(OMAP_PRODUCTION_ID_1),
+ omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
+ printk("OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
+ printk("OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
+ printk("JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
+#endif
+
+ system_serial_high = omap_readl(OMAP_DIE_ID_0);
+ system_serial_low = omap_readl(OMAP_DIE_ID_1);
+
+ /* First check only the major version in a safe way */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == (omap_ids[i].jtag_id)) {
+ system_rev = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Check if we can find the die revision */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
+ system_rev = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Finally check also the omap_id */
+ for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
+ if (jtag_id == omap_ids[i].jtag_id
+ && die_rev == omap_ids[i].die_rev
+ && omap_id == omap_ids[i].omap_id) {
+ system_rev = omap_ids[i].type;
+ break;
+ }
+ }
+
+ /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
+ cpu_type = system_rev >> 24;
+
+ switch (cpu_type) {
+ case 0x07:
+ system_rev |= 0x07;
+ break;
+ case 0x15:
+ system_rev |= 0x15;
+ break;
+ case 0x16:
+ case 0x17:
+ system_rev |= 0x16;
+ break;
+ case 0x24:
+ system_rev |= 0x24;
+ break;
+ default:
+ printk("Unknown OMAP cpu type: 0x%02x\n", cpu_type);
+ }
+
+ printk("OMAP%04x", system_rev >> 16);
+ if ((system_rev >> 8) & 0xff)
+ printk("%x", (system_rev >> 8) & 0xff);
+ printk(" revision %i handled as %02xxx id: %08x%08x\n",
+ die_rev, system_rev & 0xff, system_serial_low,
+ system_serial_high);
+}
+
diff --git a/arch/arm/mach-omap1/io.c b/arch/arm/mach-omap1/io.c
new file mode 100644
index 000000000000..207df0fe934d
--- /dev/null
+++ b/arch/arm/mach-omap1/io.c
@@ -0,0 +1,115 @@
+/*
+ * linux/arch/arm/mach-omap1/io.c
+ *
+ * OMAP1 I/O mapping code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include <asm/mach/map.h>
+#include <asm/io.h>
+#include <asm/arch/tc.h>
+
+extern int clk_init(void);
+extern void omap_check_revision(void);
+
+/*
+ * The machine specific code may provide the extra mapping besides the
+ * default mapping provided here.
+ */
+static struct map_desc omap_io_desc[] __initdata = {
+ { IO_VIRT, IO_PHYS, IO_SIZE, MT_DEVICE },
+};
+
+#ifdef CONFIG_ARCH_OMAP730
+static struct map_desc omap730_io_desc[] __initdata = {
+ { OMAP730_DSP_BASE, OMAP730_DSP_START, OMAP730_DSP_SIZE, MT_DEVICE },
+ { OMAP730_DSPREG_BASE, OMAP730_DSPREG_START, OMAP730_DSPREG_SIZE, MT_DEVICE },
+ { OMAP730_SRAM_BASE, OMAP730_SRAM_START, OMAP730_SRAM_SIZE, MT_DEVICE }
+};
+#endif
+
+#ifdef CONFIG_ARCH_OMAP1510
+static struct map_desc omap1510_io_desc[] __initdata = {
+ { OMAP1510_DSP_BASE, OMAP1510_DSP_START, OMAP1510_DSP_SIZE, MT_DEVICE },
+ { OMAP1510_DSPREG_BASE, OMAP1510_DSPREG_START, OMAP1510_DSPREG_SIZE, MT_DEVICE },
+ { OMAP1510_SRAM_BASE, OMAP1510_SRAM_START, OMAP1510_SRAM_SIZE, MT_DEVICE }
+};
+#endif
+
+#if defined(CONFIG_ARCH_OMAP16XX)
+static struct map_desc omap1610_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+ { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP1610_SRAM_SIZE, MT_DEVICE }
+};
+
+static struct map_desc omap5912_io_desc[] __initdata = {
+ { OMAP16XX_DSP_BASE, OMAP16XX_DSP_START, OMAP16XX_DSP_SIZE, MT_DEVICE },
+ { OMAP16XX_DSPREG_BASE, OMAP16XX_DSPREG_START, OMAP16XX_DSPREG_SIZE, MT_DEVICE },
+/*
+ * The OMAP5912 has 250kByte internal SRAM. Because the mapping is baseed on page
+ * size (4kByte), it seems that the last 2kByte (=0x800) of the 250kByte are not mapped.
+ * Add additional 2kByte (0x800) so that the last page is mapped and the last 2kByte
+ * can be used.
+ */
+ { OMAP16XX_SRAM_BASE, OMAP16XX_SRAM_START, OMAP5912_SRAM_SIZE + 0x800, MT_DEVICE }
+};
+#endif
+
+static int initialized = 0;
+
+static void __init _omap_map_io(void)
+{
+ initialized = 1;
+
+ /* We have to initialize the IO space mapping before we can run
+ * cpu_is_omapxxx() macros. */
+ iotable_init(omap_io_desc, ARRAY_SIZE(omap_io_desc));
+ omap_check_revision();
+
+#ifdef CONFIG_ARCH_OMAP730
+ if (cpu_is_omap730()) {
+ iotable_init(omap730_io_desc, ARRAY_SIZE(omap730_io_desc));
+ }
+#endif
+#ifdef CONFIG_ARCH_OMAP1510
+ if (cpu_is_omap1510()) {
+ iotable_init(omap1510_io_desc, ARRAY_SIZE(omap1510_io_desc));
+ }
+#endif
+#if defined(CONFIG_ARCH_OMAP16XX)
+ if (cpu_is_omap1610() || cpu_is_omap1710()) {
+ iotable_init(omap1610_io_desc, ARRAY_SIZE(omap1610_io_desc));
+ }
+ if (cpu_is_omap5912()) {
+ iotable_init(omap5912_io_desc, ARRAY_SIZE(omap5912_io_desc));
+ }
+#endif
+
+ /* REVISIT: Refer to OMAP5910 Errata, Advisory SYS_1: "Timeout Abort
+ * on a Posted Write in the TIPB Bridge".
+ */
+ omap_writew(0x0, MPU_PUBLIC_TIPB_CNTL);
+ omap_writew(0x0, MPU_PRIVATE_TIPB_CNTL);
+
+ /* Must init clocks early to assure that timer interrupt works
+ */
+ clk_init();
+}
+
+/*
+ * This should only get called from board specific init
+ */
+void omap_map_common_io(void)
+{
+ if (!initialized)
+ _omap_map_io();
+}
diff --git a/arch/arm/mach-omap/irq.c b/arch/arm/mach-omap1/irq.c
index f01c99266a86..a11b6d807352 100644
--- a/arch/arm/mach-omap/irq.c
+++ b/arch/arm/mach-omap1/irq.c
@@ -56,6 +56,7 @@
struct omap_irq_bank {
unsigned long base_reg;
unsigned long trigger_map;
+ unsigned long wake_enable;
};
static unsigned int irq_bank_count = 0;
@@ -105,6 +106,19 @@ static void omap_mask_ack_irq(unsigned int irq)
omap_ack_irq(irq);
}
+static int omap_wake_irq(unsigned int irq, unsigned int enable)
+{
+ int bank = IRQ_BANK(irq);
+
+ if (enable)
+ irq_banks[bank].wake_enable |= IRQ_BIT(irq);
+ else
+ irq_banks[bank].wake_enable &= ~IRQ_BIT(irq);
+
+ return 0;
+}
+
+
/*
* Allows tuning the IRQ type and priority
*
@@ -145,7 +159,7 @@ static struct omap_irq_bank omap1510_irq_banks[] = {
static struct omap_irq_bank omap1610_irq_banks[] = {
{ .base_reg = OMAP_IH1_BASE, .trigger_map = 0xb3fefe8f },
{ .base_reg = OMAP_IH2_BASE, .trigger_map = 0xfdb7c1fd },
- { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xfffff7ff },
+ { .base_reg = OMAP_IH2_BASE + 0x100, .trigger_map = 0xffffb7ff },
{ .base_reg = OMAP_IH2_BASE + 0x200, .trigger_map = 0xffffffff },
};
#endif
@@ -154,6 +168,7 @@ static struct irqchip omap_irq_chip = {
.ack = omap_mask_ack_irq,
.mask = omap_mask_irq,
.unmask = omap_unmask_irq,
+ .wake = omap_wake_irq,
};
void __init omap_init_irq(void)
diff --git a/arch/arm/mach-omap/leds-h2p2-debug.c b/arch/arm/mach-omap1/leds-h2p2-debug.c
index 6e98290cca5c..6e98290cca5c 100644
--- a/arch/arm/mach-omap/leds-h2p2-debug.c
+++ b/arch/arm/mach-omap1/leds-h2p2-debug.c
diff --git a/arch/arm/mach-omap/leds-innovator.c b/arch/arm/mach-omap1/leds-innovator.c
index 8043b7d0f66e..8043b7d0f66e 100644
--- a/arch/arm/mach-omap/leds-innovator.c
+++ b/arch/arm/mach-omap1/leds-innovator.c
diff --git a/arch/arm/mach-omap/leds-osk.c b/arch/arm/mach-omap1/leds-osk.c
index f5177f430793..4a0e8b9d4fc3 100644
--- a/arch/arm/mach-omap/leds-osk.c
+++ b/arch/arm/mach-omap1/leds-osk.c
@@ -129,14 +129,11 @@ void osk_leds_event(led_event_t evt)
#ifdef CONFIG_FB_OMAP
-#ifdef CONFIG_LEDS_TIMER
case led_timer:
hw_led_state ^= TIMER_LED;
mistral_setled();
break;
-#endif
-#ifdef CONFIG_LEDS_CPU
case led_idle_start:
hw_led_state |= IDLE_LED;
mistral_setled();
@@ -146,7 +143,6 @@ void osk_leds_event(led_event_t evt)
hw_led_state &= ~IDLE_LED;
mistral_setled();
break;
-#endif
#endif /* CONFIG_FB_OMAP */
diff --git a/arch/arm/mach-omap/leds.c b/arch/arm/mach-omap1/leds.c
index 8ab21fe98e1b..8ab21fe98e1b 100644
--- a/arch/arm/mach-omap/leds.c
+++ b/arch/arm/mach-omap1/leds.c
diff --git a/arch/arm/mach-omap/leds.h b/arch/arm/mach-omap1/leds.h
index a1e9fedc376c..a1e9fedc376c 100644
--- a/arch/arm/mach-omap/leds.h
+++ b/arch/arm/mach-omap1/leds.h
diff --git a/arch/arm/mach-omap1/serial.c b/arch/arm/mach-omap1/serial.c
new file mode 100644
index 000000000000..214e5d17c8b5
--- /dev/null
+++ b/arch/arm/mach-omap1/serial.c
@@ -0,0 +1,200 @@
+/*
+ * linux/arch/arm/mach-omap1/id.c
+ *
+ * OMAP1 CPU identification code
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+#include <asm/hardware/clock.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+static struct clk * uart1_ck = NULL;
+static struct clk * uart2_ck = NULL;
+static struct clk * uart3_ck = NULL;
+
+static inline unsigned int omap_serial_in(struct plat_serial8250_port *up,
+ int offset)
+{
+ offset <<= up->regshift;
+ return (unsigned int)__raw_readb(up->membase + offset);
+}
+
+static inline void omap_serial_outp(struct plat_serial8250_port *p, int offset,
+ int value)
+{
+ offset <<= p->regshift;
+ __raw_writeb(value, p->membase + offset);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly. Note that the TX watermark initialization may not be needed
+ * once the 8250.c watermark handling code is merged.
+ */
+static void __init omap_serial_reset(struct plat_serial8250_port *p)
+{
+ omap_serial_outp(p, UART_OMAP_MDR1, 0x07); /* disable UART */
+ omap_serial_outp(p, UART_OMAP_SCR, 0x08); /* TX watermark */
+ omap_serial_outp(p, UART_OMAP_MDR1, 0x00); /* enable UART */
+
+ if (!cpu_is_omap1510()) {
+ omap_serial_outp(p, UART_OMAP_SYSC, 0x01);
+ while (!(omap_serial_in(p, UART_OMAP_SYSC) & 0x01));
+ }
+}
+
+static struct plat_serial8250_port serial_platform_data[] = {
+ {
+ .membase = (char*)IO_ADDRESS(OMAP_UART1_BASE),
+ .mapbase = (unsigned long)OMAP_UART1_BASE,
+ .irq = INT_UART1,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ {
+ .membase = (char*)IO_ADDRESS(OMAP_UART2_BASE),
+ .mapbase = (unsigned long)OMAP_UART2_BASE,
+ .irq = INT_UART2,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ {
+ .membase = (char*)IO_ADDRESS(OMAP_UART3_BASE),
+ .mapbase = (unsigned long)OMAP_UART3_BASE,
+ .irq = INT_UART3,
+ .flags = UPF_BOOT_AUTOCONF,
+ .iotype = UPIO_MEM,
+ .regshift = 2,
+ .uartclk = OMAP16XX_BASE_BAUD * 16,
+ },
+ { },
+};
+
+static struct platform_device serial_device = {
+ .name = "serial8250",
+ .id = 0,
+ .dev = {
+ .platform_data = serial_platform_data,
+ },
+};
+
+/*
+ * Note that on Innovator-1510 UART2 pins conflict with USB2.
+ * By default UART2 does not work on Innovator-1510 if you have
+ * USB OHCI enabled. To use UART2, you must disable USB2 first.
+ */
+void __init omap_serial_init(int ports[OMAP_MAX_NR_PORTS])
+{
+ int i;
+
+ if (cpu_is_omap730()) {
+ serial_platform_data[0].regshift = 0;
+ serial_platform_data[1].regshift = 0;
+ serial_platform_data[0].irq = INT_730_UART_MODEM_1;
+ serial_platform_data[1].irq = INT_730_UART_MODEM_IRDA_2;
+ }
+
+ if (cpu_is_omap1510()) {
+ serial_platform_data[0].uartclk = OMAP1510_BASE_BAUD * 16;
+ serial_platform_data[1].uartclk = OMAP1510_BASE_BAUD * 16;
+ serial_platform_data[2].uartclk = OMAP1510_BASE_BAUD * 16;
+ }
+
+ for (i = 0; i < OMAP_MAX_NR_PORTS; i++) {
+ unsigned char reg;
+
+ if (ports[i] == 0) {
+ serial_platform_data[i].membase = NULL;
+ serial_platform_data[i].mapbase = 0;
+ continue;
+ }
+
+ switch (i) {
+ case 0:
+ uart1_ck = clk_get(NULL, "uart1_ck");
+ if (IS_ERR(uart1_ck))
+ printk("Could not get uart1_ck\n");
+ else {
+ clk_use(uart1_ck);
+ if (cpu_is_omap1510())
+ clk_set_rate(uart1_ck, 12000000);
+ }
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(UART1_TX);
+ omap_cfg_reg(UART1_RTS);
+ if (machine_is_omap_innovator()) {
+ reg = fpga_read(OMAP1510_FPGA_POWER);
+ reg |= OMAP1510_FPGA_PCR_COM1_EN;
+ fpga_write(reg, OMAP1510_FPGA_POWER);
+ udelay(10);
+ }
+ }
+ break;
+ case 1:
+ uart2_ck = clk_get(NULL, "uart2_ck");
+ if (IS_ERR(uart2_ck))
+ printk("Could not get uart2_ck\n");
+ else {
+ clk_use(uart2_ck);
+ if (cpu_is_omap1510())
+ clk_set_rate(uart2_ck, 12000000);
+ else
+ clk_set_rate(uart2_ck, 48000000);
+ }
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(UART2_TX);
+ omap_cfg_reg(UART2_RTS);
+ if (machine_is_omap_innovator()) {
+ reg = fpga_read(OMAP1510_FPGA_POWER);
+ reg |= OMAP1510_FPGA_PCR_COM2_EN;
+ fpga_write(reg, OMAP1510_FPGA_POWER);
+ udelay(10);
+ }
+ }
+ break;
+ case 2:
+ uart3_ck = clk_get(NULL, "uart3_ck");
+ if (IS_ERR(uart3_ck))
+ printk("Could not get uart3_ck\n");
+ else {
+ clk_use(uart3_ck);
+ if (cpu_is_omap1510())
+ clk_set_rate(uart3_ck, 12000000);
+ }
+ if (cpu_is_omap1510()) {
+ omap_cfg_reg(UART3_TX);
+ omap_cfg_reg(UART3_RX);
+ }
+ break;
+ }
+ omap_serial_reset(&serial_platform_data[i]);
+ }
+}
+
+static int __init omap_init(void)
+{
+ return platform_device_register(&serial_device);
+}
+arch_initcall(omap_init);
diff --git a/arch/arm/mach-omap/time.c b/arch/arm/mach-omap1/time.c
index 4205fdcb632c..d540539c9bbb 100644
--- a/arch/arm/mach-omap/time.c
+++ b/arch/arm/mach-omap1/time.c
@@ -1,10 +1,10 @@
/*
- * linux/arch/arm/mach-omap/time.c
+ * linux/arch/arm/mach-omap1/time.c
*
* OMAP Timers
*
* Copyright (C) 2004 Nokia Corporation
- * Partial timer rewrite and additional VST timer support by
+ * Partial timer rewrite and additional dynamic tick timer support by
* Tony Lindgen <tony@atomide.com> and
* Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
*
@@ -58,17 +58,9 @@ struct sys_timer omap_timer;
* MPU timer
* ---------------------------------------------------------------------------
*/
-#define OMAP_MPU_TIMER1_BASE (0xfffec500)
-#define OMAP_MPU_TIMER2_BASE (0xfffec600)
-#define OMAP_MPU_TIMER3_BASE (0xfffec700)
#define OMAP_MPU_TIMER_BASE OMAP_MPU_TIMER1_BASE
#define OMAP_MPU_TIMER_OFFSET 0x100
-#define MPU_TIMER_FREE (1 << 6)
-#define MPU_TIMER_CLOCK_ENABLE (1 << 5)
-#define MPU_TIMER_AR (1 << 1)
-#define MPU_TIMER_ST (1 << 0)
-
/* cycles to nsec conversions taken from arch/i386/kernel/timers/timer_tsc.c,
* converted to use kHz by Kevin Hilman */
/* convert from cycles(64bits) => nanoseconds (64bits)
@@ -188,8 +180,8 @@ static irqreturn_t omap_mpu_timer_interrupt(int irq, void *dev_id,
static struct irqaction omap_mpu_timer_irq = {
.name = "mpu timer",
- .flags = SA_INTERRUPT,
- .handler = omap_mpu_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = omap_mpu_timer_interrupt,
};
static unsigned long omap_mpu_timer1_overflows;
@@ -203,7 +195,7 @@ static irqreturn_t omap_mpu_timer1_interrupt(int irq, void *dev_id,
static struct irqaction omap_mpu_timer1_irq = {
.name = "mpu timer1 overflow",
.flags = SA_INTERRUPT,
- .handler = omap_mpu_timer1_interrupt
+ .handler = omap_mpu_timer1_interrupt,
};
static __init void omap_init_mpu_timer(void)
@@ -255,13 +247,19 @@ unsigned long long sched_clock(void)
#define OMAP_32K_TIMER_TCR 0x04
#define OMAP_32K_TICKS_PER_HZ (32768 / HZ)
+#if (32768 % HZ) != 0
+/* We cannot ignore modulo.
+ * Potential error can be as high as several percent.
+ */
+#define OMAP_32K_TICK_MODULO (32768 % HZ)
+static unsigned modulo_count = 0; /* Counts 1/HZ units */
+#endif
/*
* TRM says 1 / HZ = ( TVR + 1) / 32768, so TRV = (32768 / HZ) - 1
* so with HZ = 100, TVR = 327.68.
*/
#define OMAP_32K_TIMER_TICK_PERIOD ((32768 / HZ) - 1)
-#define MAX_SKIP_JIFFIES 25
#define TIMER_32K_SYNCHRONIZED 0xfffbc410
#define JIFFIES_TO_HW_TICKS(nr_jiffies, clock_rate) \
@@ -332,6 +330,19 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
now = omap_32k_sync_timer_read();
while (now - omap_32k_last_tick >= OMAP_32K_TICKS_PER_HZ) {
+#ifdef OMAP_32K_TICK_MODULO
+ /* Modulo addition may put omap_32k_last_tick ahead of now
+ * and cause unwanted repetition of the while loop.
+ */
+ if (unlikely(now - omap_32k_last_tick == ~0))
+ break;
+
+ modulo_count += OMAP_32K_TICK_MODULO;
+ if (modulo_count > HZ) {
+ ++omap_32k_last_tick;
+ modulo_count -= HZ;
+ }
+#endif
omap_32k_last_tick += OMAP_32K_TICKS_PER_HZ;
timer_tick(regs);
}
@@ -347,14 +358,55 @@ static irqreturn_t omap_32k_timer_interrupt(int irq, void *dev_id,
return IRQ_HANDLED;
}
+#ifdef CONFIG_NO_IDLE_HZ
+/*
+ * Programs the next timer interrupt needed. Called when dynamic tick is
+ * enabled, and to reprogram the ticks to skip from pm_idle. Note that
+ * we can keep the timer continuous, and don't need to set it to run in
+ * one-shot mode. This is because the timer will get reprogrammed again
+ * after next interrupt.
+ */
+void omap_32k_timer_reprogram(unsigned long next_tick)
+{
+ omap_32k_timer_start(JIFFIES_TO_HW_TICKS(next_tick, 32768) + 1);
+}
+
+static struct irqaction omap_32k_timer_irq;
+extern struct timer_update_handler timer_update;
+
+static int omap_32k_timer_enable_dyn_tick(void)
+{
+ /* No need to reprogram timer, just use the next interrupt */
+ return 0;
+}
+
+static int omap_32k_timer_disable_dyn_tick(void)
+{
+ omap_32k_timer_start(OMAP_32K_TIMER_TICK_PERIOD);
+ return 0;
+}
+
+static struct dyn_tick_timer omap_dyn_tick_timer = {
+ .enable = omap_32k_timer_enable_dyn_tick,
+ .disable = omap_32k_timer_disable_dyn_tick,
+ .reprogram = omap_32k_timer_reprogram,
+ .handler = omap_32k_timer_interrupt,
+};
+#endif /* CONFIG_NO_IDLE_HZ */
+
static struct irqaction omap_32k_timer_irq = {
.name = "32KHz timer",
- .flags = SA_INTERRUPT,
- .handler = omap_32k_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = omap_32k_timer_interrupt,
};
static __init void omap_init_32k_timer(void)
{
+
+#ifdef CONFIG_NO_IDLE_HZ
+ omap_timer.dyn_tick = &omap_dyn_tick_timer;
+#endif
+
setup_irq(INT_OS_TIMER, &omap_32k_timer_irq);
omap_timer.offset = omap_32k_timer_gettimeoffset;
omap_32k_last_tick = omap_32k_sync_timer_read();
@@ -367,7 +419,7 @@ static __init void omap_init_32k_timer(void)
* Timer initialization
* ---------------------------------------------------------------------------
*/
-void __init omap_timer_init(void)
+static void __init omap_timer_init(void)
{
#if defined(CONFIG_OMAP_MPU_TIMER)
omap_init_mpu_timer();
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index c4e6d2523585..efc2f657184e 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -24,3 +24,7 @@ obj-$(CONFIG_LEDS) += $(led-y)
# Misc features
obj-$(CONFIG_PM) += pm.o sleep.o
+
+ifeq ($(CONFIG_PXA27x),y)
+obj-$(CONFIG_PM) += standby.o
+endif
diff --git a/arch/arm/mach-pxa/corgi.c b/arch/arm/mach-pxa/corgi.c
index f691cf77d390..86b862f56e7e 100644
--- a/arch/arm/mach-pxa/corgi.c
+++ b/arch/arm/mach-pxa/corgi.c
@@ -287,34 +287,40 @@ static void __init corgi_map_io(void)
#ifdef CONFIG_MACH_CORGI
MACHINE_START(CORGI, "SHARP Corgi")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- FIXUP(fixup_corgi)
- MAPIO(corgi_map_io)
- INITIRQ(corgi_init_irq)
- .init_machine = corgi_init,
- .timer = &pxa_timer,
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_corgi,
+ .map_io = corgi_map_io,
+ .init_irq = corgi_init_irq,
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
MACHINE_END
#endif
#ifdef CONFIG_MACH_SHEPHERD
MACHINE_START(SHEPHERD, "SHARP Shepherd")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- FIXUP(fixup_corgi)
- MAPIO(corgi_map_io)
- INITIRQ(corgi_init_irq)
- .init_machine = corgi_init,
- .timer = &pxa_timer,
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_corgi,
+ .map_io = corgi_map_io,
+ .init_irq = corgi_init_irq,
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
MACHINE_END
#endif
#ifdef CONFIG_MACH_HUSKY
MACHINE_START(HUSKY, "SHARP Husky")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- FIXUP(fixup_corgi)
- MAPIO(corgi_map_io)
- INITIRQ(corgi_init_irq)
- .init_machine = corgi_init,
- .timer = &pxa_timer,
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_corgi,
+ .map_io = corgi_map_io,
+ .init_irq = corgi_init_irq,
+ .init_machine = corgi_init,
+ .timer = &pxa_timer,
MACHINE_END
#endif
diff --git a/arch/arm/mach-pxa/idp.c b/arch/arm/mach-pxa/idp.c
index c5a66bf4d3d5..386e107b53cc 100644
--- a/arch/arm/mach-pxa/idp.c
+++ b/arch/arm/mach-pxa/idp.c
@@ -181,10 +181,12 @@ static void __init idp_map_io(void)
MACHINE_START(PXA_IDP, "Vibren PXA255 IDP")
- MAINTAINER("Vibren Technologies")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- MAPIO(idp_map_io)
- INITIRQ(idp_init_irq)
+ /* Maintainer: Vibren Technologies */
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .map_io = idp_map_io,
+ .init_irq = idp_init_irq,
.timer = &pxa_timer,
- INIT_MACHINE(idp_init)
+ .init_machine = idp_init,
MACHINE_END
diff --git a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
index f2c9e0d2b24b..6309853b59be 100644
--- a/arch/arm/mach-pxa/lubbock.c
+++ b/arch/arm/mach-pxa/lubbock.c
@@ -268,10 +268,12 @@ static void __init lubbock_map_io(void)
}
MACHINE_START(LUBBOCK, "Intel DBPXA250 Development Platform (aka Lubbock)")
- MAINTAINER("MontaVista Software Inc.")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- MAPIO(lubbock_map_io)
- INITIRQ(lubbock_init_irq)
+ /* Maintainer: MontaVista Software Inc. */
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .map_io = lubbock_map_io,
+ .init_irq = lubbock_init_irq,
.timer = &pxa_timer,
- INIT_MACHINE(lubbock_init)
+ .init_machine = lubbock_init,
MACHINE_END
diff --git a/arch/arm/mach-pxa/mainstone.c b/arch/arm/mach-pxa/mainstone.c
index 9896afca751f..827b7b5a5be8 100644
--- a/arch/arm/mach-pxa/mainstone.c
+++ b/arch/arm/mach-pxa/mainstone.c
@@ -345,10 +345,12 @@ static void __init mainstone_map_io(void)
}
MACHINE_START(MAINSTONE, "Intel HCDDBBVA0 Development Platform (aka Mainstone)")
- MAINTAINER("MontaVista Software Inc.")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- MAPIO(mainstone_map_io)
- INITIRQ(mainstone_init_irq)
+ /* Maintainer: MontaVista Software Inc. */
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .map_io = mainstone_map_io,
+ .init_irq = mainstone_init_irq,
.timer = &pxa_timer,
- INIT_MACHINE(mainstone_init)
+ .init_machine = mainstone_init,
MACHINE_END
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index b6c746ea3830..0e4f6fab100a 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -180,10 +180,12 @@ static void __init poodle_map_io(void)
}
MACHINE_START(POODLE, "SHARP Poodle")
- BOOT_MEM(0xa0000000, 0x40000000, io_p2v(0x40000000))
- FIXUP(fixup_poodle)
- MAPIO(poodle_map_io)
- INITIRQ(pxa_init_irq)
- .timer = &pxa_timer,
- .init_machine = poodle_init,
+ .phys_ram = 0xa0000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = (io_p2v(0x40000000) >> 18) & 0xfffc,
+ .fixup = fixup_poodle,
+ .map_io = poodle_map_io,
+ .init_irq = pxa_init_irq,
+ .timer = &pxa_timer,
+ .init_machine = poodle_init,
MACHINE_END
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 893964fb9659..9a791b07118d 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -126,6 +126,7 @@ int pxa_cpu_pm_prepare(suspend_state_t state)
{
switch (state) {
case PM_SUSPEND_MEM:
+ case PM_SUSPEND_STANDBY:
return 0;
default:
return -EINVAL;
@@ -138,7 +139,10 @@ void pxa_cpu_pm_enter(suspend_state_t state)
extern void pxa_cpu_suspend(unsigned int);
extern void pxa_cpu_resume(void);
- CKEN = CKEN22_MEMC | CKEN9_OSTIMER;
+ if (state == PM_SUSPEND_STANDBY)
+ CKEN = CKEN22_MEMC | CKEN9_OSTIMER | CKEN16_LCD |CKEN0_PWM0;
+ else
+ CKEN = CKEN22_MEMC | CKEN9_OSTIMER;
/* ensure voltage-change sequencer not initiated, which hangs */
PCFR &= ~PCFR_FVC;
@@ -147,6 +151,9 @@ void pxa_cpu_pm_enter(suspend_state_t state)
PEDR = 0xDF12FE1B;
switch (state) {
+ case PM_SUSPEND_STANDBY:
+ pxa_cpu_standby();
+ break;
case PM_SUSPEND_MEM:
/* set resume return address */
PSPR = virt_to_phys(pxa_cpu_resume);
diff --git a/arch/arm/mach-pxa/standby.S b/arch/arm/mach-pxa/standby.S
new file mode 100644
index 000000000000..8a3f27b76784
--- /dev/null
+++ b/arch/arm/mach-pxa/standby.S
@@ -0,0 +1,32 @@
+/*
+ * PXA27x standby mode
+ *
+ * Author: David Burrage
+ *
+ * 2005 (c) MontaVista Software, Inc. This file is licensed under
+ * the terms of the GNU General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, whether express
+ * or implied.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+#include <asm/arch/pxa-regs.h>
+
+ .text
+
+ENTRY(pxa_cpu_standby)
+ ldr r0, =PSSR
+ mov r1, #(PSSR_PH | PSSR_STS)
+ mov r2, #2
+ mov r3, #UNCACHED_PHYS_0 @ Read mem context in.
+ ldr ip, [r3]
+ b 1f
+
+ .align 5
+1: mcr p14, 0, r2, c7, c0, 0 @ put the system into Standby
+ str r1, [r0] @ make sure PSSR_PH/STS are clear
+ mov pc, lr
diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
index 473fb6173f72..6e5202154f91 100644
--- a/arch/arm/mach-pxa/time.c
+++ b/arch/arm/mach-pxa/time.c
@@ -105,8 +105,8 @@ pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction pxa_timer_irq = {
.name = "PXA Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = pxa_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = pxa_timer_interrupt,
};
static void __init pxa_timer_init(void)
diff --git a/arch/arm/mach-rpc/riscpc.c b/arch/arm/mach-rpc/riscpc.c
index 437106881436..a10268618f74 100644
--- a/arch/arm/mach-rpc/riscpc.c
+++ b/arch/arm/mach-rpc/riscpc.c
@@ -163,12 +163,14 @@ arch_initcall(rpc_init);
extern struct sys_timer ioc_timer;
MACHINE_START(RISCPC, "Acorn-RiscPC")
- MAINTAINER("Russell King")
- BOOT_MEM(0x10000000, 0x03000000, 0xe0000000)
- BOOT_PARAMS(0x10000100)
- DISABLE_PARPORT(0)
- DISABLE_PARPORT(1)
- MAPIO(rpc_map_io)
- INITIRQ(rpc_init_irq)
+ /* Maintainer: Russell King */
+ .phys_ram = 0x10000000,
+ .phys_io = 0x03000000,
+ .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
+ .boot_params = 0x10000100,
+ .reserve_lp0 = 1,
+ .reserve_lp1 = 1,
+ .map_io = rpc_map_io,
+ .init_irq = rpc_init_irq,
.timer = &ioc_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/Kconfig b/arch/arm/mach-s3c2410/Kconfig
index 534df0c6c770..d4d03d0daaec 100644
--- a/arch/arm/mach-s3c2410/Kconfig
+++ b/arch/arm/mach-s3c2410/Kconfig
@@ -154,6 +154,11 @@ config S3C2410_PM_CHECK_CHUNKSIZE
the CRC data block will take more memory, but wil identify any
faults with better precision.
+config PM_SIMTEC
+ bool
+ depends on PM && (ARCH_BAST || MACH_VR1000)
+ default y
+
config S3C2410_LOWLEVEL_UART_PORT
int "S3C2410 UART to use for low-level messages"
default 0
diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 7c379aad5d62..f99b689e4392 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_S3C2410_DMA) += dma.o
# Power Management support
obj-$(CONFIG_PM) += pm.o sleep.o
+obj-$(CONFIG_PM_SIMTEC) += pm-simtec.o
# S3C2440 support
diff --git a/arch/arm/mach-s3c2410/devs.c b/arch/arm/mach-s3c2410/devs.c
index 64792f678668..4664bd11adc1 100644
--- a/arch/arm/mach-s3c2410/devs.c
+++ b/arch/arm/mach-s3c2410/devs.c
@@ -96,8 +96,8 @@ struct platform_device s3c_device_lcd = {
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
- .dma_mask = &s3c_device_lcd_dmamask,
- .coherent_dma_mask = 0xffffffffUL
+ .dma_mask = &s3c_device_lcd_dmamask,
+ .coherent_dma_mask = 0xffffffffUL
}
};
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index b668c48f4399..cf9f46d88061 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -40,8 +40,11 @@
* 04-Nov-2004 Ben Dooks
* Fix standard IRQ wake for EINT0..4 and RTC
*
- * 22-Feb-2004 Ben Dooks
+ * 22-Feb-2005 Ben Dooks
* Fixed edge-triggering on ADC IRQ
+ *
+ * 28-Jun-2005 Ben Dooks
+ * Mark IRQ_LCD valid
*/
#include <linux/init.h>
@@ -366,7 +369,6 @@ static struct irqchip s3c_irq_eint0t4 = {
#define INTMSK_UART1 (1UL << (IRQ_UART1 - IRQ_EINT0))
#define INTMSK_UART2 (1UL << (IRQ_UART2 - IRQ_EINT0))
#define INTMSK_ADCPARENT (1UL << (IRQ_ADCPARENT - IRQ_EINT0))
-#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0))
static inline void
s3c_irqsub_mask(unsigned int irqno, unsigned int parentbit,
@@ -716,7 +718,6 @@ void __init s3c24xx_init_irq(void)
case IRQ_UART0:
case IRQ_UART1:
case IRQ_UART2:
- case IRQ_LCD:
case IRQ_ADCPARENT:
set_irq_chip(irqno, &s3c_irq_level_chip);
set_irq_handler(irqno, do_level_IRQ);
diff --git a/arch/arm/mach-s3c2410/mach-bast.c b/arch/arm/mach-s3c2410/mach-bast.c
index 3bb97eb6e693..ccb6bcefa46c 100644
--- a/arch/arm/mach-s3c2410/mach-bast.c
+++ b/arch/arm/mach-s3c2410/mach-bast.c
@@ -26,6 +26,8 @@
* 03-Mar-2005 BJD Ensured that bast-cpld.h is included
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
* 14-Mar-2006 BJD Updated for __iomem changes
+ * 22-Jun-2006 BJD Added DM9000 platform information
+ * 28-Jun-2006 BJD Moved pm functionality out to common code
*/
#include <linux/kernel.h>
@@ -35,6 +37,7 @@
#include <linux/timer.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/dm9000.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
@@ -53,6 +56,7 @@
#include <asm/arch/regs-serial.h>
#include <asm/arch/regs-gpio.h>
#include <asm/arch/regs-mem.h>
+#include <asm/arch/regs-lcd.h>
#include <asm/arch/nand.h>
#include <linux/mtd/mtd.h>
@@ -64,7 +68,6 @@
#include "devs.h"
#include "cpu.h"
#include "usb-simtec.h"
-#include "pm.h"
#define COPYRIGHT ", (c) 2004-2005 Simtec Electronics"
@@ -112,7 +115,6 @@ static struct map_desc bast_iodesc[] __initdata = {
{ VA_C2(BAST_VA_ISAMEM), PA_CS2(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
{ VA_C2(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
{ VA_C2(BAST_VA_SUPERIO), PA_CS2(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
- { VA_C2(BAST_VA_DM9000), PA_CS2(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C2(BAST_VA_IDEPRI), PA_CS3(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C2(BAST_VA_IDESEC), PA_CS3(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C2(BAST_VA_IDEPRIAUX), PA_CS3(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
@@ -123,7 +125,6 @@ static struct map_desc bast_iodesc[] __initdata = {
{ VA_C3(BAST_VA_ISAMEM), PA_CS3(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
{ VA_C3(BAST_VA_ASIXNET), PA_CS3(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
{ VA_C3(BAST_VA_SUPERIO), PA_CS3(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
- { VA_C3(BAST_VA_DM9000), PA_CS3(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C3(BAST_VA_IDEPRI), PA_CS3(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C3(BAST_VA_IDESEC), PA_CS3(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C3(BAST_VA_IDEPRIAUX), PA_CS3(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
@@ -134,7 +135,6 @@ static struct map_desc bast_iodesc[] __initdata = {
{ VA_C4(BAST_VA_ISAMEM), PA_CS4(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
{ VA_C4(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
{ VA_C4(BAST_VA_SUPERIO), PA_CS4(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
- { VA_C4(BAST_VA_DM9000), PA_CS4(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C4(BAST_VA_IDEPRI), PA_CS5(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C4(BAST_VA_IDESEC), PA_CS5(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C4(BAST_VA_IDEPRIAUX), PA_CS5(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
@@ -145,7 +145,6 @@ static struct map_desc bast_iodesc[] __initdata = {
{ VA_C5(BAST_VA_ISAMEM), PA_CS5(BAST_PA_ISAMEM), SZ_16M, MT_DEVICE },
{ VA_C5(BAST_VA_ASIXNET), PA_CS5(BAST_PA_ASIXNET), SZ_1M, MT_DEVICE },
{ VA_C5(BAST_VA_SUPERIO), PA_CS5(BAST_PA_SUPERIO), SZ_1M, MT_DEVICE },
- { VA_C5(BAST_VA_DM9000), PA_CS5(BAST_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C5(BAST_VA_IDEPRI), PA_CS5(BAST_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C5(BAST_VA_IDESEC), PA_CS5(BAST_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C5(BAST_VA_IDEPRIAUX), PA_CS5(BAST_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
@@ -313,6 +312,45 @@ static struct s3c2410_platform_nand bast_nand_info = {
.select_chip = bast_nand_select,
};
+/* DM9000 */
+
+static struct resource bast_dm9k_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5 + BAST_PA_DM9000,
+ .end = S3C2410_CS5 + BAST_PA_DM9000 + 3,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = S3C2410_CS5 + BAST_PA_DM9000 + 0x40,
+ .end = S3C2410_CS5 + BAST_PA_DM9000 + 0x40 + 0x3f,
+ .flags = IORESOURCE_MEM
+ },
+ [2] = {
+ .start = IRQ_DM9000,
+ .end = IRQ_DM9000,
+ .flags = IORESOURCE_IRQ
+ }
+
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+struct dm9000_plat_data bast_dm9k_platdata = {
+ .flags = DM9000_PLATF_16BITONLY
+};
+
+static struct platform_device bast_device_dm9k = {
+ .name = "dm9000",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(bast_dm9k_resource),
+ .resource = bast_dm9k_resource,
+ .dev = {
+ .platform_data = &bast_dm9k_platdata,
+ }
+};
+
/* Standard BAST devices */
@@ -324,7 +362,8 @@ static struct platform_device *bast_devices[] __initdata = {
&s3c_device_iis,
&s3c_device_rtc,
&s3c_device_nand,
- &bast_device_nor
+ &bast_device_nor,
+ &bast_device_dm9k,
};
static struct clk *bast_clocks[] = {
@@ -366,44 +405,14 @@ void __init bast_map_io(void)
usb_simtec_init();
}
-void __init bast_init_irq(void)
-{
- s3c24xx_init_irq();
-}
-
-#ifdef CONFIG_PM
-
-/* bast_init_machine
- *
- * enable the power management functions for the EB2410ITX
-*/
-
-static __init void bast_init_machine(void)
-{
- unsigned long gstatus4;
-
- printk(KERN_INFO "BAST Power Manangement" COPYRIGHT "\n");
-
- gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
- gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
- gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
-
- __raw_writel(gstatus4, S3C2410_GSTATUS4);
-
- s3c2410_pm_init();
-}
-
-#else
-#define bast_init_machine NULL
-#endif
-
MACHINE_START(BAST, "Simtec-BAST")
- MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
- MAPIO(bast_map_io)
- INITIRQ(bast_init_irq)
- .init_machine = bast_init_machine,
+ /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = bast_map_io,
+ .init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-h1940.c b/arch/arm/mach-s3c2410/mach-h1940.c
index 2924afc068a4..ea4fb1a97a50 100644
--- a/arch/arm/mach-s3c2410/mach-h1940.c
+++ b/arch/arm/mach-s3c2410/mach-h1940.c
@@ -117,10 +117,12 @@ void __init h1940_init_irq(void)
}
MACHINE_START(H1940, "IPAQ-H1940")
- MAINTAINER("Ben Dooks <ben@fluff.org>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
- MAPIO(h1940_map_io)
- INITIRQ(h1940_init_irq)
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = h1940_map_io,
+ .init_irq = h1940_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-n30.c b/arch/arm/mach-s3c2410/mach-n30.c
index bd15998c129b..79044d9bce38 100644
--- a/arch/arm/mach-s3c2410/mach-n30.c
+++ b/arch/arm/mach-s3c2410/mach-n30.c
@@ -137,10 +137,11 @@ void __init n30_init(void)
}
MACHINE_START(N30, "Acer-N30")
- MAINTAINER("Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
-
+ /* Maintainer: Christer Weinigel <christer@weinigel.se>, Ben Dooks <ben-linux@fluff.org> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
.timer = &s3c24xx_timer,
.init_machine = n30_init,
.init_irq = n30_init_irq,
diff --git a/arch/arm/mach-s3c2410/mach-nexcoder.c b/arch/arm/mach-s3c2410/mach-nexcoder.c
index 70487bf4b71e..d24c242414ca 100644
--- a/arch/arm/mach-s3c2410/mach-nexcoder.c
+++ b/arch/arm/mach-s3c2410/mach-nexcoder.c
@@ -147,9 +147,11 @@ void __init nexcoder_map_io(void)
MACHINE_START(NEXCODER_2440, "NexVision - Nexcoder 2440")
- MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+ /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = nexcoder_map_io,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
diff --git a/arch/arm/mach-s3c2410/mach-otom.c b/arch/arm/mach-s3c2410/mach-otom.c
index 67d8ce8fb00f..d901ed492ff5 100644
--- a/arch/arm/mach-s3c2410/mach-otom.c
+++ b/arch/arm/mach-s3c2410/mach-otom.c
@@ -115,9 +115,11 @@ void __init otom11_map_io(void)
MACHINE_START(OTOM, "Nex Vision - Otom 1.1")
- MAINTAINER("Guillaume GOURAT <guillaume.gourat@nexvision.tv>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+ /* Maintainer: Guillaume GOURAT <guillaume.gourat@nexvision.tv> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
.map_io = otom11_map_io,
.init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
diff --git a/arch/arm/mach-s3c2410/mach-rx3715.c b/arch/arm/mach-s3c2410/mach-rx3715.c
index f8d3a9784e71..a73d61c1de46 100644
--- a/arch/arm/mach-s3c2410/mach-rx3715.c
+++ b/arch/arm/mach-s3c2410/mach-rx3715.c
@@ -131,11 +131,13 @@ static void __init rx3715_init_machine(void)
#endif
MACHINE_START(RX3715, "IPAQ-RX3715")
- MAINTAINER("Ben Dooks <ben@fluff.org>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
- MAPIO(rx3715_map_io)
- INITIRQ(rx3715_init_irq)
- INIT_MACHINE(rx3715_init_machine)
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = rx3715_map_io,
+ .init_irq = rx3715_init_irq,
+ .init_machine = rx3715_init_machine,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-smdk2410.c b/arch/arm/mach-s3c2410/mach-smdk2410.c
index c1a4a1420ea0..67e903a700d3 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2410.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2410.c
@@ -112,11 +112,13 @@ void __init smdk2410_init_irq(void)
MACHINE_START(SMDK2410, "SMDK2410") /* @TODO: request a new identifier and switch
* to SMDK2410 */
- MAINTAINER("Jonas Dietsche")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
- MAPIO(smdk2410_map_io)
- INITIRQ(smdk2410_init_irq)
+ /* Maintainer: Jonas Dietsche */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = smdk2410_map_io,
+ .init_irq = smdk2410_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/mach-smdk2440.c b/arch/arm/mach-s3c2410/mach-smdk2440.c
index 7857176d9bcb..357522106f68 100644
--- a/arch/arm/mach-s3c2410/mach-smdk2440.c
+++ b/arch/arm/mach-s3c2410/mach-smdk2440.c
@@ -124,9 +124,11 @@ void __init smdk2440_machine_init(void)
}
MACHINE_START(S3C2440, "SMDK2440")
- MAINTAINER("Ben Dooks <ben@fluff.org>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
+ /* Maintainer: Ben Dooks <ben@fluff.org> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
.init_irq = s3c24xx_init_irq,
.map_io = smdk2440_map_io,
diff --git a/arch/arm/mach-s3c2410/mach-vr1000.c b/arch/arm/mach-s3c2410/mach-vr1000.c
index 5512146b1ce4..924e8464c212 100644
--- a/arch/arm/mach-s3c2410/mach-vr1000.c
+++ b/arch/arm/mach-s3c2410/mach-vr1000.c
@@ -27,6 +27,7 @@
* 10-Feb-2005 BJD Added power-off capability
* 10-Mar-2005 LCVR Changed S3C2410_VA to S3C24XX_VA
* 14-Mar-2006 BJD void __iomem fixes
+ * 22-Jun-2006 BJD Added DM9000 platform information
*/
#include <linux/kernel.h>
@@ -35,6 +36,7 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/init.h>
+#include <linux/dm9000.h>
#include <linux/serial.h>
#include <linux/tty.h>
@@ -98,28 +100,24 @@ static struct map_desc vr1000_iodesc[] __initdata = {
* are only 8bit */
/* slow, byte */
- { VA_C2(VR1000_VA_DM9000), PA_CS2(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C2(VR1000_VA_IDEPRI), PA_CS3(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C2(VR1000_VA_IDESEC), PA_CS3(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C2(VR1000_VA_IDEPRIAUX), PA_CS3(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
{ VA_C2(VR1000_VA_IDESECAUX), PA_CS3(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
/* slow, word */
- { VA_C3(VR1000_VA_DM9000), PA_CS3(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C3(VR1000_VA_IDEPRI), PA_CS3(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C3(VR1000_VA_IDESEC), PA_CS3(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C3(VR1000_VA_IDEPRIAUX), PA_CS3(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
{ VA_C3(VR1000_VA_IDESECAUX), PA_CS3(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
/* fast, byte */
- { VA_C4(VR1000_VA_DM9000), PA_CS4(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C4(VR1000_VA_IDEPRI), PA_CS5(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C4(VR1000_VA_IDESEC), PA_CS5(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C4(VR1000_VA_IDEPRIAUX), PA_CS5(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
{ VA_C4(VR1000_VA_IDESECAUX), PA_CS5(VR1000_PA_IDESECAUX), SZ_1M, MT_DEVICE },
/* fast, word */
- { VA_C5(VR1000_VA_DM9000), PA_CS5(VR1000_PA_DM9000), SZ_1M, MT_DEVICE },
{ VA_C5(VR1000_VA_IDEPRI), PA_CS5(VR1000_PA_IDEPRI), SZ_1M, MT_DEVICE },
{ VA_C5(VR1000_VA_IDESEC), PA_CS5(VR1000_PA_IDESEC), SZ_1M, MT_DEVICE },
{ VA_C5(VR1000_VA_IDEPRIAUX), PA_CS5(VR1000_PA_IDEPRIAUX), SZ_1M, MT_DEVICE },
@@ -246,6 +244,74 @@ static struct platform_device vr1000_nor = {
.resource = vr1000_nor_resource,
};
+/* DM9000 ethernet devices */
+
+static struct resource vr1000_dm9k0_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5 + VR1000_PA_DM9000,
+ .end = S3C2410_CS5 + VR1000_PA_DM9000 + 3,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x40,
+ .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0x7f,
+ .flags = IORESOURCE_MEM
+ },
+ [2] = {
+ .start = IRQ_VR1000_DM9000A,
+ .end = IRQ_VR1000_DM9000A,
+ .flags = IORESOURCE_IRQ
+ }
+
+};
+
+static struct resource vr1000_dm9k1_resource[] = {
+ [0] = {
+ .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0x80,
+ .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0x83,
+ .flags = IORESOURCE_MEM
+ },
+ [1] = {
+ .start = S3C2410_CS5 + VR1000_PA_DM9000 + 0xC0,
+ .end = S3C2410_CS5 + VR1000_PA_DM9000 + 0xFF,
+ .flags = IORESOURCE_MEM
+ },
+ [2] = {
+ .start = IRQ_VR1000_DM9000N,
+ .end = IRQ_VR1000_DM9000N,
+ .flags = IORESOURCE_IRQ
+ }
+};
+
+/* for the moment we limit ourselves to 16bit IO until some
+ * better IO routines can be written and tested
+*/
+
+struct dm9000_plat_data vr1000_dm9k_platdata = {
+ .flags = DM9000_PLATF_16BITONLY,
+};
+
+static struct platform_device vr1000_dm9k0 = {
+ .name = "dm9000",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(vr1000_dm9k0_resource),
+ .resource = vr1000_dm9k0_resource,
+ .dev = {
+ .platform_data = &vr1000_dm9k_platdata,
+ }
+};
+
+static struct platform_device vr1000_dm9k1 = {
+ .name = "dm9000",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(vr1000_dm9k1_resource),
+ .resource = vr1000_dm9k1_resource,
+ .dev = {
+ .platform_data = &vr1000_dm9k_platdata,
+ }
+};
+
+/* devices for this board */
static struct platform_device *vr1000_devices[] __initdata = {
&s3c_device_usb,
@@ -253,8 +319,11 @@ static struct platform_device *vr1000_devices[] __initdata = {
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
+ &s3c_device_adc,
&serial_device,
&vr1000_nor,
+ &vr1000_dm9k0,
+ &vr1000_dm9k1
};
static struct clk *vr1000_clocks[] = {
@@ -302,16 +371,14 @@ void __init vr1000_map_io(void)
usb_simtec_init();
}
-void __init vr1000_init_irq(void)
-{
- s3c24xx_init_irq();
-}
MACHINE_START(VR1000, "Thorcom-VR1000")
- MAINTAINER("Ben Dooks <ben@simtec.co.uk>")
- BOOT_MEM(S3C2410_SDRAM_PA, S3C2410_PA_UART, (u32)S3C24XX_VA_UART)
- BOOT_PARAMS(S3C2410_SDRAM_PA + 0x100)
- MAPIO(vr1000_map_io)
- INITIRQ(vr1000_init_irq)
+ /* Maintainer: Ben Dooks <ben@simtec.co.uk> */
+ .phys_ram = S3C2410_SDRAM_PA,
+ .phys_io = S3C2410_PA_UART,
+ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
+ .boot_params = S3C2410_SDRAM_PA + 0x100,
+ .map_io = vr1000_map_io,
+ .init_irq = s3c24xx_init_irq,
.timer = &s3c24xx_timer,
MACHINE_END
diff --git a/arch/arm/mach-s3c2410/pm-simtec.c b/arch/arm/mach-s3c2410/pm-simtec.c
new file mode 100644
index 000000000000..2cb798832223
--- /dev/null
+++ b/arch/arm/mach-s3c2410/pm-simtec.c
@@ -0,0 +1,65 @@
+/* linux/arch/arm/mach-s3c2410/pm-simtec.c
+ *
+ * Copyright (c) 2004 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * http://armlinux.simtec.co.uk/
+ *
+ * Power Management helpers for Simtec S3C24XX implementations
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/device.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <asm/arch/map.h>
+#include <asm/arch/regs-serial.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-mem.h>
+
+#include <asm/mach-types.h>
+
+#include "pm.h"
+
+#define COPYRIGHT ", (c) 2005 Simtec Electronics"
+
+/* pm_simtec_init
+ *
+ * enable the power management functions
+*/
+
+static __init int pm_simtec_init(void)
+{
+ unsigned long gstatus4;
+
+ /* check which machine we are running on */
+
+ if (!machine_is_bast() && !machine_is_vr1000())
+ return 0;
+
+ printk(KERN_INFO "Simtec Board Power Manangement" COPYRIGHT "\n");
+
+ gstatus4 = (__raw_readl(S3C2410_BANKCON7) & 0x3) << 30;
+ gstatus4 |= (__raw_readl(S3C2410_BANKCON6) & 0x3) << 28;
+ gstatus4 |= (__raw_readl(S3C2410_BANKSIZE) & S3C2410_BANKSIZE_MASK);
+
+ __raw_writel(gstatus4, S3C2410_GSTATUS4);
+
+ return s3c2410_pm_init();
+}
+
+arch_initcall(pm_simtec_init);
diff --git a/arch/arm/mach-s3c2410/time.c b/arch/arm/mach-s3c2410/time.c
index 179f0e031af4..765a3a9ae032 100644
--- a/arch/arm/mach-s3c2410/time.c
+++ b/arch/arm/mach-s3c2410/time.c
@@ -137,8 +137,8 @@ s3c2410_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction s3c2410_timer_irq = {
.name = "S3C2410 Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = s3c2410_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = s3c2410_timer_interrupt,
};
/*
diff --git a/arch/arm/mach-sa1100/assabet.c b/arch/arm/mach-sa1100/assabet.c
index bedf88fafe08..4d4d303ee3a8 100644
--- a/arch/arm/mach-sa1100/assabet.c
+++ b/arch/arm/mach-sa1100/assabet.c
@@ -431,11 +431,13 @@ static void __init assabet_map_io(void)
MACHINE_START(ASSABET, "Intel-Assabet")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- FIXUP(fixup_assabet)
- MAPIO(assabet_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .fixup = fixup_assabet,
+ .map_io = assabet_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = assabet_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c
index 6a60b497ab42..b6169cb09196 100644
--- a/arch/arm/mach-sa1100/badge4.c
+++ b/arch/arm/mach-sa1100/badge4.c
@@ -285,9 +285,11 @@ static void __init badge4_map_io(void)
}
MACHINE_START(BADGE4, "Hewlett-Packard Laboratories BadgePAD 4")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(badge4_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = badge4_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/cerf.c b/arch/arm/mach-sa1100/cerf.c
index f8edde5e7cbf..0aa918e24c31 100644
--- a/arch/arm/mach-sa1100/cerf.c
+++ b/arch/arm/mach-sa1100/cerf.c
@@ -123,10 +123,12 @@ static void __init cerf_init(void)
}
MACHINE_START(CERF, "Intrinsyc CerfBoard/CerfCube")
- MAINTAINER("support@intrinsyc.com")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- MAPIO(cerf_map_io)
- INITIRQ(cerf_init_irq)
+ /* Maintainer: support@intrinsyc.com */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .map_io = cerf_map_io,
+ .init_irq = cerf_init_irq,
.timer = &sa1100_timer,
.init_machine = cerf_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
index 99287890d396..8cb69113a57c 100644
--- a/arch/arm/mach-sa1100/collie.c
+++ b/arch/arm/mach-sa1100/collie.c
@@ -184,9 +184,11 @@ static void __init collie_map_io(void)
}
MACHINE_START(COLLIE, "Sharp-Collie")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- MAPIO(collie_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .map_io = collie_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = collie_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/cpu-sa1110.c b/arch/arm/mach-sa1100/cpu-sa1110.c
index 8d2a89a2ea01..04c94ab6c18b 100644
--- a/arch/arm/mach-sa1100/cpu-sa1110.c
+++ b/arch/arm/mach-sa1100/cpu-sa1110.c
@@ -271,8 +271,7 @@ static int sa1110_target(struct cpufreq_policy *policy,
*/
sdram_set_refresh(2);
if (!irqs_disabled()) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(20 * HZ / 1000);
+ msleep(20);
} else {
mdelay(20);
}
diff --git a/arch/arm/mach-sa1100/h3600.c b/arch/arm/mach-sa1100/h3600.c
index 84c86543501a..e7aa2681ca64 100644
--- a/arch/arm/mach-sa1100/h3600.c
+++ b/arch/arm/mach-sa1100/h3600.c
@@ -380,10 +380,12 @@ static void __init h3100_map_io(void)
}
MACHINE_START(H3100, "Compaq iPAQ H3100")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(h3100_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = h3100_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = h3xxx_mach_init,
MACHINE_END
@@ -496,10 +498,12 @@ static void __init h3600_map_io(void)
}
MACHINE_START(H3600, "Compaq iPAQ H3600")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(h3600_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = h3600_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = h3xxx_mach_init,
MACHINE_END
@@ -727,7 +731,7 @@ static void h3800_IRQ_demux(unsigned int irq, struct irqdesc *desc, struct pt_re
static struct irqaction h3800_irq = {
.name = "h3800_asic",
.handler = h3800_IRQ_demux,
- .flags = SA_INTERRUPT,
+ .flags = SA_INTERRUPT | SA_TIMER,
};
u32 kpio_int_shadow = 0;
@@ -881,10 +885,12 @@ static void __init h3800_map_io(void)
}
MACHINE_START(H3800, "Compaq iPAQ H3800")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(h3800_map_io)
- INITIRQ(h3800_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = h3800_map_io,
+ .init_irq = h3800_init_irq,
.timer = &sa1100_timer,
.init_machine = h3xxx_mach_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/hackkit.c b/arch/arm/mach-sa1100/hackkit.c
index 570841779714..502d65cfe654 100644
--- a/arch/arm/mach-sa1100/hackkit.c
+++ b/arch/arm/mach-sa1100/hackkit.c
@@ -191,10 +191,12 @@ static void __init hackkit_init(void)
*/
MACHINE_START(HACKKIT, "HackKit Cpu Board")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(hackkit_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = hackkit_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = hackkit_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c
index 6be78291a878..eee3cbc5ec4f 100644
--- a/arch/arm/mach-sa1100/jornada720.c
+++ b/arch/arm/mach-sa1100/jornada720.c
@@ -97,9 +97,11 @@ static void __init jornada720_map_io(void)
}
MACHINE_START(JORNADA720, "HP Jornada 720")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(jornada720_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = jornada720_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/lart.c b/arch/arm/mach-sa1100/lart.c
index 51c08ccfb8db..870b488aeda4 100644
--- a/arch/arm/mach-sa1100/lart.c
+++ b/arch/arm/mach-sa1100/lart.c
@@ -41,9 +41,11 @@ static void __init lart_map_io(void)
}
MACHINE_START(LART, "LART")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(lart_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = lart_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/pleb.c b/arch/arm/mach-sa1100/pleb.c
index 5606bd71b024..e17b58fb9c9c 100644
--- a/arch/arm/mach-sa1100/pleb.c
+++ b/arch/arm/mach-sa1100/pleb.c
@@ -146,9 +146,11 @@ static void __init pleb_map_io(void)
}
MACHINE_START(PLEB, "PLEB")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- MAPIO(pleb_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .map_io = pleb_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = pleb_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/shannon.c b/arch/arm/mach-sa1100/shannon.c
index edddd559be02..43a00359fcdd 100644
--- a/arch/arm/mach-sa1100/shannon.c
+++ b/arch/arm/mach-sa1100/shannon.c
@@ -76,10 +76,12 @@ static void __init shannon_map_io(void)
}
MACHINE_START(SHANNON, "Shannon (AKA: Tuxscreen)")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(shannon_map_io)
- INITIRQ(sa1100_init_irq)
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = shannon_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
.init_machine = shannon_init,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
index 8d113d629867..77978586b126 100644
--- a/arch/arm/mach-sa1100/simpad.c
+++ b/arch/arm/mach-sa1100/simpad.c
@@ -215,10 +215,12 @@ arch_initcall(simpad_init);
MACHINE_START(SIMPAD, "Simpad")
- MAINTAINER("Holger Freyther")
- BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
- BOOT_PARAMS(0xc0000100)
- MAPIO(simpad_map_io)
- INITIRQ(sa1100_init_irq)
+ /* Maintainer: Holger Freyther */
+ .phys_ram = 0xc0000000,
+ .phys_io = 0x80000000,
+ .io_pg_offst = ((0xf8000000) >> 18) & 0xfffc,
+ .boot_params = 0xc0000100,
+ .map_io = simpad_map_io,
+ .init_irq = sa1100_init_irq,
.timer = &sa1100_timer,
MACHINE_END
diff --git a/arch/arm/mach-sa1100/time.c b/arch/arm/mach-sa1100/time.c
index 19b0c0fd6377..0eeb3616ffea 100644
--- a/arch/arm/mach-sa1100/time.c
+++ b/arch/arm/mach-sa1100/time.c
@@ -99,8 +99,8 @@ sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction sa1100_timer_irq = {
.name = "SA11xx Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = sa1100_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = sa1100_timer_interrupt,
};
static void __init sa1100_timer_init(void)
diff --git a/arch/arm/mach-shark/core.c b/arch/arm/mach-shark/core.c
index a9bc5d0dbd85..726445895b5c 100644
--- a/arch/arm/mach-shark/core.c
+++ b/arch/arm/mach-shark/core.c
@@ -84,8 +84,8 @@ shark_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static struct irqaction shark_timer_irq = {
.name = "Shark Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = shark_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = shark_timer_interrupt,
};
/*
@@ -105,10 +105,12 @@ static struct sys_timer shark_timer = {
};
MACHINE_START(SHARK, "Shark")
- MAINTAINER("Alexander Schulz")
- BOOT_MEM(0x08000000, 0x40000000, 0xe0000000)
- BOOT_PARAMS(0x08003000)
- MAPIO(shark_map_io)
- INITIRQ(shark_init_irq)
+ /* Maintainer: Alexander Schulz */
+ .phys_ram = 0x08000000,
+ .phys_io = 0x40000000,
+ .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
+ .boot_params = 0x08003000,
+ .map_io = shark_map_io,
+ .init_irq = shark_init_irq,
.timer = &shark_timer,
MACHINE_END
diff --git a/arch/arm/mach-versatile/core.c b/arch/arm/mach-versatile/core.c
index 6a7cbea5e098..f01c0f8a2bb3 100644
--- a/arch/arm/mach-versatile/core.c
+++ b/arch/arm/mach-versatile/core.c
@@ -33,6 +33,7 @@
#include <asm/mach-types.h>
#include <asm/hardware/amba.h>
#include <asm/hardware/amba_clcd.h>
+#include <asm/hardware/arm_timer.h>
#include <asm/hardware/icst307.h>
#include <asm/mach/arch.h>
@@ -788,38 +789,25 @@ void __init versatile_init(void)
*/
#define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
#if TIMER_INTERVAL >= 0x100000
-#define TIMER_RELOAD (TIMER_INTERVAL >> 8) /* Divide by 256 */
-#define TIMER_CTRL 0x88 /* Enable, Clock / 256 */
+#define TIMER_RELOAD (TIMER_INTERVAL >> 8)
+#define TIMER_DIVISOR (TIMER_CTRL_DIV256)
#define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
#elif TIMER_INTERVAL >= 0x10000
#define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
-#define TIMER_CTRL 0x84 /* Enable, Clock / 16 */
+#define TIMER_DIVISOR (TIMER_CTRL_DIV16)
#define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
#else
#define TIMER_RELOAD (TIMER_INTERVAL)
-#define TIMER_CTRL 0x80 /* Enable */
+#define TIMER_DIVISOR (TIMER_CTRL_DIV1)
#define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
#endif
-#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable */
-
-/*
- * What does it look like?
- */
-typedef struct TimerStruct {
- unsigned long TimerLoad;
- unsigned long TimerValue;
- unsigned long TimerControl;
- unsigned long TimerClear;
-} TimerStruct_t;
-
/*
* Returns number of ms since last clock interrupt. Note that interrupts
* will have been disabled by do_gettimeoffset()
*/
static unsigned long versatile_gettimeoffset(void)
{
- volatile TimerStruct_t *timer0 = (TimerStruct_t *)TIMER0_VA_BASE;
unsigned long ticks1, ticks2, status;
/*
@@ -828,11 +816,11 @@ static unsigned long versatile_gettimeoffset(void)
* an interrupt. We get around this by ensuring that the
* counter has not reloaded between our two reads.
*/
- ticks2 = timer0->TimerValue & 0xffff;
+ ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
do {
ticks1 = ticks2;
status = __raw_readl(VA_IC_BASE + VIC_IRQ_RAW_STATUS);
- ticks2 = timer0->TimerValue & 0xffff;
+ ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff;
} while (ticks2 > ticks1);
/*
@@ -859,12 +847,10 @@ static unsigned long versatile_gettimeoffset(void)
*/
static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
- volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
-
write_seqlock(&xtime_lock);
// ...clear the interrupt
- timer0->TimerClear = 1;
+ writel(1, TIMER0_VA_BASE + TIMER_INTCLR);
timer_tick(regs);
@@ -875,8 +861,8 @@ static irqreturn_t versatile_timer_interrupt(int irq, void *dev_id, struct pt_re
static struct irqaction versatile_timer_irq = {
.name = "Versatile Timer Tick",
- .flags = SA_INTERRUPT,
- .handler = versatile_timer_interrupt
+ .flags = SA_INTERRUPT | SA_TIMER,
+ .handler = versatile_timer_interrupt,
};
/*
@@ -884,31 +870,32 @@ static struct irqaction versatile_timer_irq = {
*/
static void __init versatile_timer_init(void)
{
- volatile TimerStruct_t *timer0 = (volatile TimerStruct_t *)TIMER0_VA_BASE;
- volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
- volatile TimerStruct_t *timer2 = (volatile TimerStruct_t *)TIMER2_VA_BASE;
- volatile TimerStruct_t *timer3 = (volatile TimerStruct_t *)TIMER3_VA_BASE;
+ u32 val;
/*
* set clock frequency:
* VERSATILE_REFCLK is 32KHz
* VERSATILE_TIMCLK is 1MHz
*/
- *(volatile unsigned int *)IO_ADDRESS(VERSATILE_SCTL_BASE) |=
- ((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
- (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) | (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel));
+ val = readl(IO_ADDRESS(VERSATILE_SCTL_BASE));
+ writel((VERSATILE_TIMCLK << VERSATILE_TIMER1_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER2_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER3_EnSel) |
+ (VERSATILE_TIMCLK << VERSATILE_TIMER4_EnSel) | val,
+ IO_ADDRESS(VERSATILE_SCTL_BASE));
/*
* Initialise to a known state (all timers off)
*/
- timer0->TimerControl = 0;
- timer1->TimerControl = 0;
- timer2->TimerControl = 0;
- timer3->TimerControl = 0;
-
- timer0->TimerLoad = TIMER_RELOAD;
- timer0->TimerValue = TIMER_RELOAD;
- timer0->TimerControl = TIMER_CTRL | 0x40 | TIMER_CTRL_IE; /* periodic + IE */
+ writel(0, TIMER0_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER1_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER2_VA_BASE + TIMER_CTRL);
+ writel(0, TIMER3_VA_BASE + TIMER_CTRL);
+
+ writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD);
+ writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE);
+ writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC |
+ TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL);
/*
* Make irqs happen for the system timer
diff --git a/arch/arm/mach-versatile/versatile_ab.c b/arch/arm/mach-versatile/versatile_ab.c
index d332084586cf..8b0b3bef24ae 100644
--- a/arch/arm/mach-versatile/versatile_ab.c
+++ b/arch/arm/mach-versatile/versatile_ab.c
@@ -35,11 +35,13 @@
#include "core.h"
MACHINE_START(VERSATILE_AB, "ARM-Versatile AB")
- MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
- BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000)
- BOOT_PARAMS(0x00000100)
- MAPIO(versatile_map_io)
- INITIRQ(versatile_init_irq)
+ /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+ .phys_ram = 0x00000000,
+ .phys_io = 0x101f1000,
+ .io_pg_offst = ((0xf11f1000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = versatile_map_io,
+ .init_irq = versatile_init_irq,
.timer = &versatile_timer,
- INIT_MACHINE(versatile_init)
+ .init_machine = versatile_init,
MACHINE_END
diff --git a/arch/arm/mach-versatile/versatile_pb.c b/arch/arm/mach-versatile/versatile_pb.c
index 2702099a68f3..7c3078c38916 100644
--- a/arch/arm/mach-versatile/versatile_pb.c
+++ b/arch/arm/mach-versatile/versatile_pb.c
@@ -99,11 +99,13 @@ static int __init versatile_pb_init(void)
arch_initcall(versatile_pb_init);
MACHINE_START(VERSATILE_PB, "ARM-Versatile PB")
- MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd")
- BOOT_MEM(0x00000000, 0x101f1000, 0xf11f1000)
- BOOT_PARAMS(0x00000100)
- MAPIO(versatile_map_io)
- INITIRQ(versatile_init_irq)
+ /* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
+ .phys_ram = 0x00000000,
+ .phys_io = 0x101f1000,
+ .io_pg_offst = ((0xf11f1000) >> 18) & 0xfffc,
+ .boot_params = 0x00000100,
+ .map_io = versatile_map_io,
+ .init_irq = versatile_init_irq,
.timer = &versatile_timer,
- INIT_MACHINE(versatile_init)
+ .init_machine = versatile_init,
MACHINE_END
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 95606b4a3ba6..afbbeb6f4658 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -101,7 +101,7 @@ config CPU_ARM922T
# ARM925T
config CPU_ARM925T
- bool "Support ARM925T processor" if ARCH_OMAP
+ bool "Support ARM925T processor" if ARCH_OMAP1
depends on ARCH_OMAP1510
default y if ARCH_OMAP1510
select CPU_32v4
diff --git a/arch/arm/mm/blockops.c b/arch/arm/mm/blockops.c
index 806c6eeb1b0c..4f5ee2d08996 100644
--- a/arch/arm/mm/blockops.c
+++ b/arch/arm/mm/blockops.c
@@ -25,13 +25,14 @@ blk_flush_kern_dcache_page(void *kaddr)
{
asm(
"add r1, r0, %0 \n\
+ sub r1, r1, %1 \n\
1: .word 0xec401f0e @ mcrr p15, 0, r0, r1, c14, 0 @ blocking \n\
mov r0, #0 \n\
mcr p15, 0, r0, c7, c5, 0 \n\
mcr p15, 0, r0, c7, c10, 4 \n\
mov pc, lr"
:
- : "I" (PAGE_SIZE));
+ : "I" (PAGE_SIZE), "I" (L1_CACHE_BYTES));
}
/*
diff --git a/arch/arm/mm/fault.c b/arch/arm/mm/fault.c
index e25b4fd8412c..65bfe84b6d67 100644
--- a/arch/arm/mm/fault.c
+++ b/arch/arm/mm/fault.c
@@ -372,49 +372,50 @@ do_bad(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
static struct fsr_info {
int (*fn)(unsigned long addr, unsigned int fsr, struct pt_regs *regs);
int sig;
+ int code;
const char *name;
} fsr_info[] = {
/*
* The following are the standard ARMv3 and ARMv4 aborts. ARMv5
* defines these to be "precise" aborts.
*/
- { do_bad, SIGSEGV, "vector exception" },
- { do_bad, SIGILL, "alignment exception" },
- { do_bad, SIGKILL, "terminal exception" },
- { do_bad, SIGILL, "alignment exception" },
- { do_bad, SIGBUS, "external abort on linefetch" },
- { do_translation_fault, SIGSEGV, "section translation fault" },
- { do_bad, SIGBUS, "external abort on linefetch" },
- { do_page_fault, SIGSEGV, "page translation fault" },
- { do_bad, SIGBUS, "external abort on non-linefetch" },
- { do_bad, SIGSEGV, "section domain fault" },
- { do_bad, SIGBUS, "external abort on non-linefetch" },
- { do_bad, SIGSEGV, "page domain fault" },
- { do_bad, SIGBUS, "external abort on translation" },
- { do_sect_fault, SIGSEGV, "section permission fault" },
- { do_bad, SIGBUS, "external abort on translation" },
- { do_page_fault, SIGSEGV, "page permission fault" },
+ { do_bad, SIGSEGV, 0, "vector exception" },
+ { do_bad, SIGILL, BUS_ADRALN, "alignment exception" },
+ { do_bad, SIGKILL, 0, "terminal exception" },
+ { do_bad, SIGILL, BUS_ADRALN, "alignment exception" },
+ { do_bad, SIGBUS, 0, "external abort on linefetch" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "section translation fault" },
+ { do_bad, SIGBUS, 0, "external abort on linefetch" },
+ { do_page_fault, SIGSEGV, SEGV_MAPERR, "page translation fault" },
+ { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "section domain fault" },
+ { do_bad, SIGBUS, 0, "external abort on non-linefetch" },
+ { do_bad, SIGSEGV, SEGV_ACCERR, "page domain fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_sect_fault, SIGSEGV, SEGV_ACCERR, "section permission fault" },
+ { do_bad, SIGBUS, 0, "external abort on translation" },
+ { do_page_fault, SIGSEGV, SEGV_ACCERR, "page permission fault" },
/*
* The following are "imprecise" aborts, which are signalled by bit
* 10 of the FSR, and may not be recoverable. These are only
* supported if the CPU abort handler supports bit 10.
*/
- { do_bad, SIGBUS, "unknown 16" },
- { do_bad, SIGBUS, "unknown 17" },
- { do_bad, SIGBUS, "unknown 18" },
- { do_bad, SIGBUS, "unknown 19" },
- { do_bad, SIGBUS, "lock abort" }, /* xscale */
- { do_bad, SIGBUS, "unknown 21" },
- { do_bad, SIGBUS, "imprecise external abort" }, /* xscale */
- { do_bad, SIGBUS, "unknown 23" },
- { do_bad, SIGBUS, "dcache parity error" }, /* xscale */
- { do_bad, SIGBUS, "unknown 25" },
- { do_bad, SIGBUS, "unknown 26" },
- { do_bad, SIGBUS, "unknown 27" },
- { do_bad, SIGBUS, "unknown 28" },
- { do_bad, SIGBUS, "unknown 29" },
- { do_bad, SIGBUS, "unknown 30" },
- { do_bad, SIGBUS, "unknown 31" }
+ { do_bad, SIGBUS, 0, "unknown 16" },
+ { do_bad, SIGBUS, 0, "unknown 17" },
+ { do_bad, SIGBUS, 0, "unknown 18" },
+ { do_bad, SIGBUS, 0, "unknown 19" },
+ { do_bad, SIGBUS, 0, "lock abort" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 21" },
+ { do_bad, SIGBUS, BUS_OBJERR, "imprecise external abort" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 23" },
+ { do_bad, SIGBUS, 0, "dcache parity error" }, /* xscale */
+ { do_bad, SIGBUS, 0, "unknown 25" },
+ { do_bad, SIGBUS, 0, "unknown 26" },
+ { do_bad, SIGBUS, 0, "unknown 27" },
+ { do_bad, SIGBUS, 0, "unknown 28" },
+ { do_bad, SIGBUS, 0, "unknown 29" },
+ { do_bad, SIGBUS, 0, "unknown 30" },
+ { do_bad, SIGBUS, 0, "unknown 31" }
};
void __init
@@ -435,15 +436,19 @@ asmlinkage void
do_DataAbort(unsigned long addr, unsigned int fsr, struct pt_regs *regs)
{
const struct fsr_info *inf = fsr_info + (fsr & 15) + ((fsr & (1 << 10)) >> 6);
+ struct siginfo info;
if (!inf->fn(addr, fsr, regs))
return;
printk(KERN_ALERT "Unhandled fault: %s (0x%03x) at 0x%08lx\n",
inf->name, fsr, addr);
- force_sig(inf->sig, current);
- show_pte(current->mm, addr);
- die_if_kernel("Oops", regs, 0);
+
+ info.si_signo = inf->sig;
+ info.si_errno = 0;
+ info.si_code = inf->code;
+ info.si_addr = (void __user *)addr;
+ notify_die("", regs, &info, fsr, 0);
}
asmlinkage void
diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index c08710b1ff02..edffa47a4b2a 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -437,7 +437,7 @@ void __init paging_init(struct meminfo *mi, struct machine_desc *mdesc)
memtable_init(mi);
if (mdesc->map_io)
mdesc->map_io();
- flush_tlb_all();
+ local_flush_tlb_all();
/*
* initialise the zones within each node
@@ -522,6 +522,69 @@ static inline void free_area(unsigned long addr, unsigned long end, char *s)
printk(KERN_INFO "Freeing %s memory: %dK\n", s, size);
}
+static inline void
+free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
+{
+ struct page *start_pg, *end_pg;
+ unsigned long pg, pgend;
+
+ /*
+ * Convert start_pfn/end_pfn to a struct page pointer.
+ */
+ start_pg = pfn_to_page(start_pfn);
+ end_pg = pfn_to_page(end_pfn);
+
+ /*
+ * Convert to physical addresses, and
+ * round start upwards and end downwards.
+ */
+ pg = PAGE_ALIGN(__pa(start_pg));
+ pgend = __pa(end_pg) & PAGE_MASK;
+
+ /*
+ * If there are free pages between these,
+ * free the section of the memmap array.
+ */
+ if (pg < pgend)
+ free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
+}
+
+/*
+ * The mem_map array can get very big. Free the unused area of the memory map.
+ */
+static void __init free_unused_memmap_node(int node, struct meminfo *mi)
+{
+ unsigned long bank_start, prev_bank_end = 0;
+ unsigned int i;
+
+ /*
+ * [FIXME] This relies on each bank being in address order. This
+ * may not be the case, especially if the user has provided the
+ * information on the command line.
+ */
+ for (i = 0; i < mi->nr_banks; i++) {
+ if (mi->bank[i].size == 0 || mi->bank[i].node != node)
+ continue;
+
+ bank_start = mi->bank[i].start >> PAGE_SHIFT;
+ if (bank_start < prev_bank_end) {
+ printk(KERN_ERR "MEM: unordered memory banks. "
+ "Not freeing memmap.\n");
+ break;
+ }
+
+ /*
+ * If we had a previous bank, and there is a space
+ * between the current bank and the previous, free it.
+ */
+ if (prev_bank_end && prev_bank_end != bank_start)
+ free_memmap(node, prev_bank_end, bank_start);
+
+ prev_bank_end = (mi->bank[i].start +
+ mi->bank[i].size) >> PAGE_SHIFT;
+ }
+}
+
/*
* mem_init() marks the free areas in the mem_map and tells us how much
* memory is free. This is done after various parts of the system have
@@ -540,16 +603,12 @@ void __init mem_init(void)
max_mapnr = virt_to_page(high_memory) - mem_map;
#endif
- /*
- * We may have non-contiguous memory.
- */
- if (meminfo.nr_banks != 1)
- create_memmap_holes(&meminfo);
-
/* this will put all unused low memory onto the freelists */
for_each_online_node(node) {
pg_data_t *pgdat = NODE_DATA(node);
+ free_unused_memmap_node(node, &meminfo);
+
if (pgdat->node_spanned_pages != 0)
totalram_pages += free_all_bootmem_node(pgdat);
}
diff --git a/arch/arm/mm/mm-armv.c b/arch/arm/mm/mm-armv.c
index 2c2b93d77d43..b19f00e99a21 100644
--- a/arch/arm/mm/mm-armv.c
+++ b/arch/arm/mm/mm-armv.c
@@ -169,7 +169,14 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
memzero(new_pgd, FIRST_KERNEL_PGD_NR * sizeof(pgd_t));
+ /*
+ * Copy over the kernel and IO PGD entries
+ */
init_pgd = pgd_offset_k(0);
+ memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
+ (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
+
+ clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
if (!vectors_high()) {
/*
@@ -198,14 +205,6 @@ pgd_t *get_pgd_slow(struct mm_struct *mm)
spin_unlock(&mm->page_table_lock);
}
- /*
- * Copy over the kernel and IO PGD entries
- */
- memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR,
- (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t));
-
- clean_dcache_area(new_pgd, PTRS_PER_PGD * sizeof(pgd_t));
-
return new_pgd;
no_pte:
@@ -400,7 +399,7 @@ static void __init build_mem_type_table(void)
ecc_mask = 0;
}
- if (cpu_arch <= CPU_ARCH_ARMv5) {
+ if (cpu_arch <= CPU_ARCH_ARMv5TEJ) {
for (i = 0; i < ARRAY_SIZE(mem_types); i++) {
if (mem_types[i].prot_l1)
mem_types[i].prot_l1 |= PMD_BIT4;
@@ -585,7 +584,7 @@ void setup_mm_for_reboot(char mode)
pmdval = (i << PGDIR_SHIFT) |
PMD_SECT_AP_WRITE | PMD_SECT_AP_READ |
PMD_TYPE_SECT;
- if (cpu_arch <= CPU_ARCH_ARMv5)
+ if (cpu_arch <= CPU_ARCH_ARMv5TEJ)
pmdval |= PMD_BIT4;
pmd = pmd_off(pgd, i << PGDIR_SHIFT);
pmd[0] = __pmd(pmdval);
@@ -683,7 +682,7 @@ void __init memtable_init(struct meminfo *mi)
}
flush_cache_all();
- flush_tlb_all();
+ local_flush_tlb_all();
top_pmd = pmd_off_k(0xffff0000);
}
@@ -698,75 +697,3 @@ void __init iotable_init(struct map_desc *io_desc, int nr)
for (i = 0; i < nr; i++)
create_mapping(io_desc + i);
}
-
-static inline void
-free_memmap(int node, unsigned long start_pfn, unsigned long end_pfn)
-{
- struct page *start_pg, *end_pg;
- unsigned long pg, pgend;
-
- /*
- * Convert start_pfn/end_pfn to a struct page pointer.
- */
- start_pg = pfn_to_page(start_pfn);
- end_pg = pfn_to_page(end_pfn);
-
- /*
- * Convert to physical addresses, and
- * round start upwards and end downwards.
- */
- pg = PAGE_ALIGN(__pa(start_pg));
- pgend = __pa(end_pg) & PAGE_MASK;
-
- /*
- * If there are free pages between these,
- * free the section of the memmap array.
- */
- if (pg < pgend)
- free_bootmem_node(NODE_DATA(node), pg, pgend - pg);
-}
-
-static inline void free_unused_memmap_node(int node, struct meminfo *mi)
-{
- unsigned long bank_start, prev_bank_end = 0;
- unsigned int i;
-
- /*
- * [FIXME] This relies on each bank being in address order. This
- * may not be the case, especially if the user has provided the
- * information on the command line.
- */
- for (i = 0; i < mi->nr_banks; i++) {
- if (mi->bank[i].size == 0 || mi->bank[i].node != node)
- continue;
-
- bank_start = mi->bank[i].start >> PAGE_SHIFT;
- if (bank_start < prev_bank_end) {
- printk(KERN_ERR "MEM: unordered memory banks. "
- "Not freeing memmap.\n");
- break;
- }
-
- /*
- * If we had a previous bank, and there is a space
- * between the current bank and the previous, free it.
- */
- if (prev_bank_end && prev_bank_end != bank_start)
- free_memmap(node, prev_bank_end, bank_start);
-
- prev_bank_end = PAGE_ALIGN(mi->bank[i].start +
- mi->bank[i].size) >> PAGE_SHIFT;
- }
-}
-
-/*
- * The mem_map array can get very big. Free
- * the unused area of the memory map.
- */
-void __init create_memmap_holes(struct meminfo *mi)
-{
- int node;
-
- for_each_online_node(node)
- free_unused_memmap_node(node, mi);
-}
diff --git a/arch/arm/mm/proc-arm1020.S b/arch/arm/mm/proc-arm1020.S
index 1f325231b9e4..5c0ae5260d1c 100644
--- a/arch/arm/mm/proc-arm1020.S
+++ b/arch/arm/mm/proc-arm1020.S
@@ -445,14 +445,14 @@ __arm1020_setup:
/*
* R
* .RVI ZFRS BLDP WCAM
- * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
+ * .011 1001 ..11 0101
*/
.type arm1020_cr1_clear, #object
.type arm1020_cr1_set, #object
arm1020_cr1_clear:
.word 0x593f
arm1020_cr1_set:
- .word 0x1935
+ .word 0x3935
__INITDATA
diff --git a/arch/arm/mm/proc-arm1020e.S b/arch/arm/mm/proc-arm1020e.S
index 142a2c2d6f0b..d69389c4d4ba 100644
--- a/arch/arm/mm/proc-arm1020e.S
+++ b/arch/arm/mm/proc-arm1020e.S
@@ -427,14 +427,14 @@ __arm1020e_setup:
/*
* R
* .RVI ZFRS BLDP WCAM
- * .0.1 1001 ..11 0101 /* FIXME: why no V bit? */
+ * .011 1001 ..11 0101
*/
.type arm1020e_cr1_clear, #object
.type arm1020e_cr1_set, #object
arm1020e_cr1_clear:
.word 0x5f3f
arm1020e_cr1_set:
- .word 0x1935
+ .word 0x3935
__INITDATA
diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S
index 0aa73d414783..352db98ee269 100644
--- a/arch/arm/mm/proc-v6.S
+++ b/arch/arm/mm/proc-v6.S
@@ -132,8 +132,8 @@ ENTRY(cpu_v6_switch_mm)
* 100x 1 0 1 r/o no acc
* 10x0 1 0 1 r/o no acc
* 1011 0 0 1 r/w no acc
- * 110x 1 1 0 r/o r/o
- * 11x0 1 1 0 r/o r/o
+ * 110x 0 1 0 r/w r/o
+ * 11x0 0 1 0 r/w r/o
* 1111 0 1 1 r/w r/w
*/
ENTRY(cpu_v6_set_pte)
@@ -150,7 +150,7 @@ ENTRY(cpu_v6_set_pte)
tst r1, #L_PTE_USER
orrne r2, r2, #AP1 | nG
tstne r2, #APX
- eorne r2, r2, #AP0
+ bicne r2, r2, #APX | AP0
tst r1, #L_PTE_YOUNG
biceq r2, r2, #APX | AP1 | AP0
@@ -200,7 +200,7 @@ __v6_setup:
mcr p15, 0, r4, c2, c0, 1 @ load TTB1
#ifdef CONFIG_VFP
mrc p15, 0, r0, c1, c0, 2
- orr r0, r0, #(3 << 20)
+ orr r0, r0, #(0xf << 20)
mcr p15, 0, r0, c1, c0, 2 @ Enable full access to VFP
#endif
mrc p15, 0, r0, c1, c0, 0 @ read control register
diff --git a/arch/arm/nwfpe/softfloat-macros b/arch/arm/nwfpe/softfloat-macros
index 5469989f2c5e..5a060f95a58f 100644
--- a/arch/arm/nwfpe/softfloat-macros
+++ b/arch/arm/nwfpe/softfloat-macros
@@ -563,8 +563,14 @@ static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
bits64 rem0, rem1, term0, term1;
bits64 z;
if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF );
- b0 = b>>32;
- z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32;
+ b0 = b>>32; /* hence b0 is 32 bits wide now */
+ if ( b0<<32 <= a0 ) {
+ z = LIT64( 0xFFFFFFFF00000000 );
+ } else {
+ z = a0;
+ do_div( z, b0 );
+ z <<= 32;
+ }
mul64To128( b, z, &term0, &term1 );
sub128( a0, a1, term0, term1, &rem0, &rem1 );
while ( ( (sbits64) rem0 ) < 0 ) {
@@ -573,7 +579,12 @@ static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b )
add128( rem0, rem1, b0, b1, &rem0, &rem1 );
}
rem0 = ( rem0<<32 ) | ( rem1>>32 );
- z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0;
+ if ( b0<<32 <= rem0 ) {
+ z |= 0xFFFFFFFF;
+ } else {
+ do_div( rem0, b0 );
+ z |= rem0;
+ }
return z;
}
@@ -601,6 +612,7 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
};
int8 index;
bits32 z;
+ bits64 A;
index = ( a>>27 ) & 15;
if ( aExp & 1 ) {
@@ -614,7 +626,9 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a )
z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 );
if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 );
}
- return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 );
+ A = ( (bits64) a )<<31;
+ do_div( A, z );
+ return ( (bits32) A ) + ( z>>1 );
}
diff --git a/arch/arm/nwfpe/softfloat.c b/arch/arm/nwfpe/softfloat.c
index 9d743ae29062..e038dd3be9b3 100644
--- a/arch/arm/nwfpe/softfloat.c
+++ b/arch/arm/nwfpe/softfloat.c
@@ -28,6 +28,8 @@ this code that are retained.
===============================================================================
*/
+#include <asm/div64.h>
+
#include "fpa11.h"
//#include "milieu.h"
//#include "softfloat.h"
@@ -1331,7 +1333,11 @@ float32 float32_div( float32 a, float32 b )
aSig >>= 1;
++zExp;
}
- zSig = ( ( (bits64) aSig )<<32 ) / bSig;
+ {
+ bits64 tmp = ( (bits64) aSig )<<32;
+ do_div( tmp, bSig );
+ zSig = tmp;
+ }
if ( ( zSig & 0x3F ) == 0 ) {
zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 );
}
@@ -1397,7 +1403,9 @@ float32 float32_rem( float32 a, float32 b )
q = ( bSig <= aSig );
if ( q ) aSig -= bSig;
if ( 0 < expDiff ) {
- q = ( ( (bits64) aSig )<<32 ) / bSig;
+ bits64 tmp = ( (bits64) aSig )<<32;
+ do_div( tmp, bSig );
+ q = tmp;
q >>= 32 - expDiff;
bSig >>= 2;
aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index ba1a6e9f2b28..8ffb523e6c77 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -6,6 +6,6 @@ DRIVER_OBJS = $(addprefix ../../../drivers/oprofile/, \
oprofilefs.o oprofile_stats.o \
timer_int.o )
-oprofile-y := $(DRIVER_OBJS) init.o
+oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
oprofile-$(CONFIG_CPU_XSCALE) += common.o op_model_xscale.o
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
new file mode 100644
index 000000000000..ec58d3e2eb8b
--- /dev/null
+++ b/arch/arm/oprofile/backtrace.c
@@ -0,0 +1,144 @@
+/*
+ * Arm specific backtracing code for oprofile
+ *
+ * Copyright 2005 Openedhand Ltd.
+ *
+ * Author: Richard Purdie <rpurdie@openedhand.com>
+ *
+ * Based on i386 oprofile backtrace code by John Levon, David Smith
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <asm/ptrace.h>
+#include <asm/uaccess.h>
+
+
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct frame_tail *)(xxx->fp)-1
+ */
+struct frame_tail {
+ struct frame_tail *fp;
+ unsigned long sp;
+ unsigned long lr;
+} __attribute__((packed));
+
+
+#ifdef CONFIG_FRAME_POINTER
+static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
+{
+ oprofile_add_trace(tail->lr);
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (tail >= tail->fp)
+ return NULL;
+
+ return tail->fp-1;
+}
+#endif
+
+static struct frame_tail* user_backtrace(struct frame_tail *tail)
+{
+ struct frame_tail buftail;
+
+ /* hardware pte might not be valid due to dirty/accessed bit emulation
+ * so we use copy_from_user and benefit from exception fixups */
+ if (copy_from_user(&buftail, tail, sizeof(struct frame_tail)))
+ return NULL;
+
+ oprofile_add_trace(buftail.lr);
+
+ /* frame pointers should strictly progress back up the stack
+ * (towards higher addresses) */
+ if (tail >= buftail.fp)
+ return NULL;
+
+ return buftail.fp-1;
+}
+
+/* Compare two addresses and see if they're on the same page */
+#define CMP_ADDR_EQUAL(x,y,offset) ((((unsigned long) x) >> PAGE_SHIFT) \
+ == ((((unsigned long) y) + offset) >> PAGE_SHIFT))
+
+/* check that the page(s) containing the frame tail are present */
+static int pages_present(struct frame_tail *tail)
+{
+ struct mm_struct * mm = current->mm;
+
+ if (!check_user_page_readable(mm, (unsigned long)tail))
+ return 0;
+
+ if (CMP_ADDR_EQUAL(tail, tail, 8))
+ return 1;
+
+ if (!check_user_page_readable(mm, ((unsigned long)tail) + 8))
+ return 0;
+
+ return 1;
+}
+
+/*
+ * | | /\ Higher addresses
+ * | |
+ * --------------- stack base (address of current_thread_info)
+ * | thread info |
+ * . .
+ * | stack |
+ * --------------- saved regs->ARM_fp value if valid (frame_tail address)
+ * . .
+ * --------------- struct pt_regs stored on stack (struct pt_regs *)
+ * | |
+ * . .
+ * | |
+ * --------------- %esp
+ * | |
+ * | | \/ Lower addresses
+ *
+ * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
+ */
+static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
+{
+ unsigned long tailaddr = (unsigned long)tail;
+ unsigned long stack = (unsigned long)regs;
+ unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
+
+ return (tailaddr > stack) && (tailaddr < stack_base);
+}
+
+void arm_backtrace(struct pt_regs const *regs, unsigned int depth)
+{
+ struct frame_tail *tail;
+ unsigned long last_address = 0;
+
+ tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+
+ if (!user_mode(regs)) {
+
+#ifdef CONFIG_FRAME_POINTER
+ while (depth-- && tail && valid_kernel_stack(tail, regs)) {
+ tail = kernel_backtrace(tail);
+ }
+#endif
+ return;
+ }
+
+ while (depth-- && tail && !((unsigned long) tail & 3)) {
+ if ((!CMP_ADDR_EQUAL(last_address, tail, 0)
+ || !CMP_ADDR_EQUAL(last_address, tail, 8))
+ && !pages_present(tail))
+ return;
+ last_address = (unsigned long) tail;
+ tail = user_backtrace(tail);
+ }
+}
+
diff --git a/arch/arm/oprofile/init.c b/arch/arm/oprofile/init.c
index cce3d3015eb7..d315a3a86c86 100644
--- a/arch/arm/oprofile/init.c
+++ b/arch/arm/oprofile/init.c
@@ -20,6 +20,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
ret = pmu_init(ops, &op_xscale_spec);
#endif
+ ops->backtrace = arm_backtrace;
+
return ret;
}
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 2d4caf4781ad..2148d07484b7 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -24,6 +24,8 @@ struct op_arm_model_spec {
extern struct op_arm_model_spec op_xscale_spec;
#endif
+extern void arm_backtrace(struct pt_regs * const regs, unsigned int depth);
+
extern int __init pmu_init(struct oprofile_operations *ops, struct op_arm_model_spec *spec);
extern void pmu_exit(void);
#endif /* OP_ARM_MODEL_H */
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
new file mode 100644
index 000000000000..345365852f8c
--- /dev/null
+++ b/arch/arm/plat-omap/Kconfig
@@ -0,0 +1,112 @@
+if ARCH_OMAP
+
+menu "TI OMAP Implementations"
+
+config ARCH_OMAP_OTG
+ bool
+
+choice
+ prompt "OMAP System Type"
+ default ARCH_OMAP1
+
+config ARCH_OMAP1
+ bool "TI OMAP1"
+
+config ARCH_OMAP2
+ bool "TI OMAP2"
+
+endchoice
+
+comment "OMAP Feature Selections"
+
+config OMAP_RESET_CLOCKS
+ bool "Reset unused clocks during boot"
+ depends on ARCH_OMAP
+ default n
+ help
+ Say Y if you want to reset unused clocks during boot.
+ This option saves power, but assumes all drivers are
+ using the clock framework. Broken drivers that do not
+ yet use clock framework may not work with this option.
+ If you are booting from another operating system, you
+ probably do not want this option enabled until your
+ device drivers work properly.
+
+config OMAP_MUX
+ bool "OMAP multiplexing support"
+ depends on ARCH_OMAP
+ default y
+ help
+ Pin multiplexing support for OMAP boards. If your bootloader
+ sets the multiplexing correctly, say N. Otherwise, or if unsure,
+ say Y.
+
+config OMAP_MUX_DEBUG
+ bool "Multiplexing debug output"
+ depends on OMAP_MUX
+ default n
+ help
+ Makes the multiplexing functions print out a lot of debug info.
+ This is useful if you want to find out the correct values of the
+ multiplexing registers.
+
+config OMAP_MUX_WARNINGS
+ bool "Warn about pins the bootloader didn't set up"
+ depends on OMAP_MUX
+ default y
+ help
+ Choose Y here to warn whenever driver initialization logic needs
+ to change the pin multiplexing setup. When there are no warnings
+ printed, it's safe to deselect OMAP_MUX for your product.
+
+choice
+ prompt "System timer"
+ default OMAP_MPU_TIMER
+
+config OMAP_MPU_TIMER
+ bool "Use mpu timer"
+ help
+ Select this option if you want to use the OMAP mpu timer. This
+ timer provides more intra-tick resolution than the 32KHz timer,
+ but consumes more power.
+
+config OMAP_32K_TIMER
+ bool "Use 32KHz timer"
+ depends on ARCH_OMAP16XX
+ help
+ Select this option if you want to enable the OMAP 32KHz timer.
+ This timer saves power compared to the OMAP_MPU_TIMER, and has
+ support for no tick during idle. The 32KHz timer provides less
+ intra-tick resolution than OMAP_MPU_TIMER. The 32KHz timer is
+ currently only available for OMAP-16xx.
+
+endchoice
+
+config OMAP_32K_TIMER_HZ
+ int "Kernel internal timer frequency for 32KHz timer"
+ range 32 1024
+ depends on OMAP_32K_TIMER
+ default "128"
+ help
+ Kernel internal timer frequency should be a divisor of 32768,
+ such as 64 or 128.
+
+choice
+ prompt "Low-level debug console UART"
+ depends on ARCH_OMAP
+ default OMAP_LL_DEBUG_UART1
+
+config OMAP_LL_DEBUG_UART1
+ bool "UART1"
+
+config OMAP_LL_DEBUG_UART2
+ bool "UART2"
+
+config OMAP_LL_DEBUG_UART3
+ bool "UART3"
+
+endchoice
+
+endmenu
+
+endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
new file mode 100644
index 000000000000..531e11af54d4
--- /dev/null
+++ b/arch/arm/plat-omap/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for the linux kernel.
+#
+
+# Common support
+obj-y := common.o dma.o clock.o mux.o gpio.o mcbsp.o usb.o
+obj-m :=
+obj-n :=
+obj- :=
+
+# OCPI interconnect support for 1710, 1610 and 5912
+obj-$(CONFIG_ARCH_OMAP16XX) += ocpi.o
+
+# Power Management
+obj-$(CONFIG_PM) += pm.o sleep.o
+
+obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
diff --git a/arch/arm/mach-omap/clock.c b/arch/arm/plat-omap/clock.c
index e91186b5341a..59d91b3262ba 100644
--- a/arch/arm/mach-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/clock.c
+ * linux/arch/arm/plat-omap/clock.c
*
* Copyright (C) 2004 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
@@ -14,6 +14,7 @@
#include <linux/errno.h>
#include <linux/err.h>
+#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/hardware/clock.h>
#include <asm/arch/board.h>
@@ -25,6 +26,8 @@ static LIST_HEAD(clocks);
static DECLARE_MUTEX(clocks_sem);
static DEFINE_SPINLOCK(clockfw_lock);
static void propagate_rate(struct clk * clk);
+/* UART clock function */
+static int set_uart_rate(struct clk * clk, unsigned long rate);
/* External clock (MCLK & BCLK) functions */
static int set_ext_clk_rate(struct clk * clk, unsigned long rate);
static long round_ext_clk_rate(struct clk * clk, unsigned long rate);
@@ -34,7 +37,7 @@ static int select_table_rate(struct clk * clk, unsigned long rate);
static long round_to_table_rate(struct clk * clk, unsigned long rate);
void clk_setdpll(__u16, __u16);
-struct mpu_rate rate_table[] = {
+static struct mpu_rate rate_table[] = {
/* MPU MHz, xtal MHz, dpll1 MHz, CKCTL, DPLL_CTL
* armdiv, dspdiv, dspmmu, tcdiv, perdiv, lcddiv
*/
@@ -48,7 +51,7 @@ struct mpu_rate rate_table[] = {
{ 192000000, 19200000, 192000000, 0x050f, 0x2510 }, /* 1/1/2/2/8/8 */
{ 192000000, 12000000, 192000000, 0x050f, 0x2810 }, /* 1/1/2/2/8/8 */
{ 96000000, 12000000, 192000000, 0x055f, 0x2810 }, /* 2/2/2/2/8/8 */
- { 48000000, 12000000, 192000000, 0x0ccf, 0x2810 }, /* 4/4/4/4/8/8 */
+ { 48000000, 12000000, 192000000, 0x0baf, 0x2810 }, /* 4/8/4/4/8/8 */
{ 24000000, 12000000, 192000000, 0x0fff, 0x2810 }, /* 8/8/8/8/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_182MHZ)
@@ -58,7 +61,7 @@ struct mpu_rate rate_table[] = {
{ 168000000, 12000000, 168000000, 0x010f, 0x2710 }, /* 1/1/1/2/8/8 */
#endif
#if defined(CONFIG_OMAP_ARM_150MHZ)
- { 150000000, 12000000, 150000000, 0x150a, 0x2cb0 }, /* 0/0/1/1/2/2 */
+ { 150000000, 12000000, 150000000, 0x010a, 0x2cb0 }, /* 1/1/1/2/4/4 */
#endif
#if defined(CONFIG_OMAP_ARM_120MHZ)
{ 120000000, 12000000, 120000000, 0x010a, 0x2510 }, /* 1/1/1/2/4/4 */
@@ -76,19 +79,11 @@ struct mpu_rate rate_table[] = {
};
-static void ckctl_recalc(struct clk * clk)
-{
- int dsor;
-
- /* Calculate divisor encoded as 2-bit exponent */
- dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
- if (unlikely(clk->rate == clk->parent->rate / dsor))
- return; /* No change, quick exit */
- clk->rate = clk->parent->rate / dsor;
-
- if (unlikely(clk->flags & RATE_PROPAGATES))
- propagate_rate(clk);
-}
+static void ckctl_recalc(struct clk * clk);
+int __clk_enable(struct clk *clk);
+void __clk_disable(struct clk *clk);
+void __clk_unuse(struct clk *clk);
+int __clk_use(struct clk *clk);
static void followparent_recalc(struct clk * clk)
@@ -102,6 +97,14 @@ static void watchdog_recalc(struct clk * clk)
clk->rate = clk->parent->rate / 14;
}
+static void uart_recalc(struct clk * clk)
+{
+ unsigned int val = omap_readl(clk->enable_reg);
+ if (val & clk->enable_bit)
+ clk->rate = 48000000;
+ else
+ clk->rate = 12000000;
+}
static struct clk ck_ref = {
.name = "ck_ref",
@@ -138,7 +141,7 @@ static struct clk arm_ck = {
static struct clk armper_ck = {
.name = "armper_ck",
.parent = &ck_dpll1,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ .flags = CLOCK_IN_OMAP730 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
RATE_CKCTL,
.enable_reg = ARM_IDLECT2,
.enable_bit = EN_PERCK,
@@ -185,7 +188,7 @@ static struct clk armwdt_ck = {
static struct clk arminth_ck16xx = {
.name = "arminth_ck",
.parent = &arm_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 16xx the frequency can be divided by 2 by programming
* ARM_CKCTL:ARM_INTHCK_SEL(14) to 1
@@ -214,6 +217,38 @@ static struct clk dspmmu_ck = {
.recalc = &ckctl_recalc,
};
+static struct clk dspper_ck = {
+ .name = "dspper_ck",
+ .parent = &ck_dpll1,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ RATE_CKCTL | DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_PERCK,
+ .rate_offset = CKCTL_PERDIV_OFFSET,
+ .recalc = &followparent_recalc,
+ //.recalc = &ckctl_recalc,
+};
+
+static struct clk dspxor_ck = {
+ .name = "dspxor_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_XORPCK,
+ .recalc = &followparent_recalc,
+};
+
+static struct clk dsptim_ck = {
+ .name = "dsptim_ck",
+ .parent = &ck_ref,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ DSP_DOMAIN_CLOCK | VIRTUAL_IO_ADDRESS,
+ .enable_reg = DSP_IDLECT2,
+ .enable_bit = EN_DSPTIMCK,
+ .recalc = &followparent_recalc,
+};
+
static struct clk tc_ck = {
.name = "tc_ck",
.parent = &ck_dpll1,
@@ -226,7 +261,7 @@ static struct clk tc_ck = {
static struct clk arminth_ck1510 = {
.name = "arminth_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
/* Note: On 1510 the frequency follows TC_CK
*
@@ -237,7 +272,7 @@ static struct clk arminth_ck1510 = {
static struct clk tipb_ck = {
.name = "tibp_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510,
+ .flags = CLOCK_IN_OMAP1510 | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -271,14 +306,15 @@ static struct clk tc2_ck = {
static struct clk dma_ck = {
.name = "dma_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
+ ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
static struct clk dma_lcdfree_ck = {
.name = "dma_lcdfree_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -303,14 +339,14 @@ static struct clk lb_ck = {
static struct clk rhea1_ck = {
.name = "rhea1_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
static struct clk rhea2_ck = {
.name = "rhea2_ck",
.parent = &tc_ck,
- .flags = CLOCK_IN_OMAP16XX,
+ .flags = CLOCK_IN_OMAP16XX | ALWAYS_ENABLED,
.recalc = &followparent_recalc,
};
@@ -325,43 +361,55 @@ static struct clk lcd_ck = {
.recalc = &ckctl_recalc,
};
-static struct clk uart1_ck = {
+static struct clk uart1_1510 = {
+ .name = "uart1_ck",
+ /* Direct from ULPD, no parent */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+ .enable_reg = MOD_CONF_CTRL_0,
+ .enable_bit = 29, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
+};
+
+static struct clk uart1_16xx = {
.name = "uart1_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 29,
- /* (Only on 1510)
- * The "enable bit" actually chooses between 48MHz and 12MHz.
- */
};
static struct clk uart2_ck = {
.name = "uart2_ck",
/* Direct from ULPD, no parent */
- .rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
- .enable_bit = 30,
- /* (for both 1510 and 16xx)
- * The "enable bit" actually chooses between 48MHz and 12MHz/32kHz.
- */
+ .enable_bit = 30, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
};
-static struct clk uart3_ck = {
+static struct clk uart3_1510 = {
+ .name = "uart3_ck",
+ /* Direct from ULPD, no parent */
+ .rate = 12000000,
+ .flags = CLOCK_IN_OMAP1510 | ENABLE_REG_32BIT | ALWAYS_ENABLED,
+ .enable_reg = MOD_CONF_CTRL_0,
+ .enable_bit = 31, /* Chooses between 12MHz and 48MHz */
+ .set_rate = &set_uart_rate,
+ .recalc = &uart_recalc,
+};
+
+static struct clk uart3_16xx = {
.name = "uart3_ck",
/* Direct from ULPD, no parent */
.rate = 48000000,
- .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX |
- RATE_FIXED | ENABLE_REG_32BIT,
+ .flags = CLOCK_IN_OMAP16XX | RATE_FIXED | ENABLE_REG_32BIT,
.enable_reg = MOD_CONF_CTRL_0,
.enable_bit = 31,
- /* (Only on 1510)
- * The "enable bit" actually chooses between 48MHz and 12MHz.
- */
};
static struct clk usb_clko = { /* 6 MHz output on W4_USB_CLKO */
@@ -480,6 +528,9 @@ static struct clk * onchip_clks[] = {
/* CK_GEN2 clocks */
&dsp_ck,
&dspmmu_ck,
+ &dspper_ck,
+ &dspxor_ck,
+ &dsptim_ck,
/* CK_GEN3 clocks */
&tc_ck,
&tipb_ck,
@@ -494,9 +545,11 @@ static struct clk * onchip_clks[] = {
&rhea2_ck,
&lcd_ck,
/* ULPD clocks */
- &uart1_ck,
+ &uart1_1510,
+ &uart1_16xx,
&uart2_ck,
- &uart3_ck,
+ &uart3_1510,
+ &uart3_16xx,
&usb_clko,
&usb_hhc_ck1510, &usb_hhc_ck16xx,
&mclk_1510, &mclk_16xx,
@@ -547,14 +600,34 @@ int __clk_enable(struct clk *clk)
return 0;
}
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_use(&api_ck);
+ }
+
if (clk->flags & ENABLE_REG_32BIT) {
- regval32 = omap_readl(clk->enable_reg);
- regval32 |= (1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval32 = omap_readl(clk->enable_reg);
+ regval32 |= (1 << clk->enable_bit);
+ omap_writel(regval32, clk->enable_reg);
+ }
} else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 |= (1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ } else {
+ regval16 = omap_readw(clk->enable_reg);
+ regval16 |= (1 << clk->enable_bit);
+ omap_writew(regval16, clk->enable_reg);
+ }
+ }
+
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_unuse(&api_ck);
}
return 0;
@@ -569,14 +642,34 @@ void __clk_disable(struct clk *clk)
if (clk->enable_reg == 0)
return;
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_use(&api_ck);
+ }
+
if (clk->flags & ENABLE_REG_32BIT) {
- regval32 = omap_readl(clk->enable_reg);
- regval32 &= ~(1 << clk->enable_bit);
- omap_writel(regval32, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval32 = __raw_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ __raw_writel(regval32, clk->enable_reg);
+ } else {
+ regval32 = omap_readl(clk->enable_reg);
+ regval32 &= ~(1 << clk->enable_bit);
+ omap_writel(regval32, clk->enable_reg);
+ }
} else {
- regval16 = omap_readw(clk->enable_reg);
- regval16 &= ~(1 << clk->enable_bit);
- omap_writew(regval16, clk->enable_reg);
+ if (clk->flags & VIRTUAL_IO_ADDRESS) {
+ regval16 = __raw_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ __raw_writew(regval16, clk->enable_reg);
+ } else {
+ regval16 = omap_readw(clk->enable_reg);
+ regval16 &= ~(1 << clk->enable_bit);
+ omap_writew(regval16, clk->enable_reg);
+ }
+ }
+
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ __clk_unuse(&api_ck);
}
}
@@ -766,6 +859,33 @@ static int calc_dsor_exp(struct clk *clk, unsigned long rate)
return dsor_exp;
}
+
+static void ckctl_recalc(struct clk * clk)
+{
+ int dsor;
+
+ /* Calculate divisor encoded as 2-bit exponent */
+ if (clk->flags & DSP_DOMAIN_CLOCK) {
+ /* The clock control bits are in DSP domain,
+ * so api_ck is needed for access.
+ * Note that DSP_CKCTL virt addr = phys addr, so
+ * we must use __raw_readw() instead of omap_readw().
+ */
+ __clk_use(&api_ck);
+ dsor = 1 << (3 & (__raw_readw(DSP_CKCTL) >> clk->rate_offset));
+ __clk_unuse(&api_ck);
+ } else {
+ dsor = 1 << (3 & (omap_readw(ARM_CKCTL) >> clk->rate_offset));
+ }
+ if (unlikely(clk->rate == clk->parent->rate / dsor))
+ return; /* No change, quick exit */
+ clk->rate = clk->parent->rate / dsor;
+
+ if (unlikely(clk->flags & RATE_PROPAGATES))
+ propagate_rate(clk);
+}
+
+
long clk_round_rate(struct clk *clk, unsigned long rate)
{
int dsor_exp;
@@ -826,6 +946,9 @@ static int select_table_rate(struct clk * clk, unsigned long rate)
if (!ptr->rate)
return -EINVAL;
+ if (!ptr->rate)
+ return -EINVAL;
+
if (unlikely(ck_dpll1.rate == 0)) {
omap_writew(ptr->dpllctl_val, DPLL_CTL);
ck_dpll1.rate = ptr->pll_rate;
@@ -921,6 +1044,23 @@ static unsigned calc_ext_dsor(unsigned long rate)
return dsor;
}
+/* Only needed on 1510 */
+static int set_uart_rate(struct clk * clk, unsigned long rate)
+{
+ unsigned int val;
+
+ val = omap_readl(clk->enable_reg);
+ if (rate == 12000000)
+ val &= ~(1 << clk->enable_bit);
+ else if (rate == 48000000)
+ val |= (1 << clk->enable_bit);
+ else
+ return -EINVAL;
+ omap_writel(val, clk->enable_reg);
+ clk->rate = rate;
+
+ return 0;
+}
static int set_ext_clk_rate(struct clk * clk, unsigned long rate)
{
@@ -985,7 +1125,18 @@ void clk_unregister(struct clk *clk)
}
EXPORT_SYMBOL(clk_unregister);
-
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+/*
+ * Resets some clocks that may be left on from bootloader,
+ * but leaves serial clocks on. See also omap_late_clk_reset().
+ */
+static inline void omap_early_clk_reset(void)
+{
+ //omap_writel(0x3 << 29, MOD_CONF_CTRL_0);
+}
+#else
+#define omap_early_clk_reset() {}
+#endif
int __init clk_init(void)
{
@@ -993,6 +1144,8 @@ int __init clk_init(void)
const struct omap_clock_config *info;
int crystal_type = 0; /* Default 12 MHz */
+ omap_early_clk_reset();
+
for (clkp = onchip_clks; clkp < onchip_clks+ARRAY_SIZE(onchip_clks); clkp++) {
if (((*clkp)->flags &CLOCK_IN_OMAP1510) && cpu_is_omap1510()) {
clk_register(*clkp);
@@ -1023,9 +1176,42 @@ int __init clk_init(void)
ck_ref.rate = 19200000;
#endif
+ printk("Clocks: ARM_SYSST: 0x%04x DPLL_CTL: 0x%04x ARM_CKCTL: 0x%04x\n",
+ omap_readw(ARM_SYSST), omap_readw(DPLL_CTL),
+ omap_readw(ARM_CKCTL));
+
/* We want to be in syncronous scalable mode */
omap_writew(0x1000, ARM_SYSST);
+#ifdef CONFIG_OMAP_CLOCKS_SET_BY_BOOTLOADER
+ /* Use values set by bootloader. Determine PLL rate and recalculate
+ * dependent clocks as if kernel had changed PLL or divisors.
+ */
+ {
+ unsigned pll_ctl_val = omap_readw(DPLL_CTL);
+
+ ck_dpll1.rate = ck_ref.rate; /* Base xtal rate */
+ if (pll_ctl_val & 0x10) {
+ /* PLL enabled, apply multiplier and divisor */
+ if (pll_ctl_val & 0xf80)
+ ck_dpll1.rate *= (pll_ctl_val & 0xf80) >> 7;
+ ck_dpll1.rate /= ((pll_ctl_val & 0x60) >> 5) + 1;
+ } else {
+ /* PLL disabled, apply bypass divisor */
+ switch (pll_ctl_val & 0xc) {
+ case 0:
+ break;
+ case 0x4:
+ ck_dpll1.rate /= 2;
+ break;
+ default:
+ ck_dpll1.rate /= 4;
+ break;
+ }
+ }
+ }
+ propagate_rate(&ck_dpll1);
+#else
/* Find the highest supported frequency and enable it */
if (select_table_rate(&virtual_ck_mpu, ~0)) {
printk(KERN_ERR "System frequencies not set. Check your config.\n");
@@ -1034,12 +1220,13 @@ int __init clk_init(void)
omap_writew(0x1005, ARM_CKCTL);
ck_dpll1.rate = 60000000;
propagate_rate(&ck_dpll1);
- printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld/%ld/%ld\n",
- ck_ref.rate, ck_dpll1.rate, arm_ck.rate);
}
-
+#endif
/* Cache rates for clocks connected to ck_ref (not dpll1) */
propagate_rate(&ck_ref);
+ printk(KERN_INFO "Clocking rate (xtal/DPLL1/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ ck_ref.rate / 1000000, (ck_ref.rate / 100000) % 10,
+ ck_dpll1.rate, arm_ck.rate);
#ifdef CONFIG_MACH_OMAP_PERSEUS2
/* Select slicer output as OMAP input clock */
@@ -1074,3 +1261,63 @@ int __init clk_init(void)
return 0;
}
+
+
+#ifdef CONFIG_OMAP_RESET_CLOCKS
+
+static int __init omap_late_clk_reset(void)
+{
+ /* Turn off all unused clocks */
+ struct clk *p;
+ __u32 regval32;
+
+ omap_writew(0, SOFT_REQ_REG);
+ omap_writew(0, SOFT_REQ_REG2);
+
+ list_for_each_entry(p, &clocks, node) {
+ if (p->usecount > 0 || (p->flags & ALWAYS_ENABLED) ||
+ p->enable_reg == 0)
+ continue;
+
+ /* Assume no DSP clocks have been activated by bootloader */
+ if (p->flags & DSP_DOMAIN_CLOCK)
+ continue;
+
+ /* Is the clock already disabled? */
+ if (p->flags & ENABLE_REG_32BIT) {
+ if (p->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readl(p->enable_reg);
+ else
+ regval32 = omap_readl(p->enable_reg);
+ } else {
+ if (p->flags & VIRTUAL_IO_ADDRESS)
+ regval32 = __raw_readw(p->enable_reg);
+ else
+ regval32 = omap_readw(p->enable_reg);
+ }
+
+ if ((regval32 & (1 << p->enable_bit)) == 0)
+ continue;
+
+ /* FIXME: This clock seems to be necessary but no-one
+ * has asked for its activation. */
+ if (p == &tc2_ck // FIX: pm.c (SRAM), CCP, Camera
+ || p == &ck_dpll1out // FIX: SoSSI, SSR
+ || p == &arm_gpio_ck // FIX: GPIO code for 1510
+ ) {
+ printk(KERN_INFO "FIXME: Clock \"%s\" seems unused\n",
+ p->name);
+ continue;
+ }
+
+ printk(KERN_INFO "Disabling unused clock \"%s\"... ", p->name);
+ __clk_disable(p);
+ printk(" done\n");
+ }
+
+ return 0;
+}
+
+late_initcall(omap_late_clk_reset);
+
+#endif
diff --git a/arch/arm/mach-omap/clock.h b/arch/arm/plat-omap/clock.h
index 08c0ddde1835..a89e1e8c2519 100644
--- a/arch/arm/mach-omap/clock.h
+++ b/arch/arm/plat-omap/clock.h
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/clock.h
+ * linux/arch/arm/plat-omap/clock.h
*
* Copyright (C) 2004 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
@@ -52,6 +52,8 @@ struct mpu_rate {
#define CLOCK_IN_OMAP16XX 64
#define CLOCK_IN_OMAP1510 128
#define CLOCK_IN_OMAP730 256
+#define DSP_DOMAIN_CLOCK 512
+#define VIRTUAL_IO_ADDRESS 1024
/* ARM_CKCTL bit shifts */
#define CKCTL_PERDIV_OFFSET 0
@@ -63,6 +65,8 @@ struct mpu_rate {
/*#define ARM_TIMXO 12*/
#define EN_DSPCK 13
/*#define ARM_INTHCK_SEL 14*/ /* Divide-by-2 for mpu inth_ck */
+/* DSP_CKCTL bit shifts */
+#define CKCTL_DSPPERDIV_OFFSET 0
/* ARM_IDLECT1 bit shifts */
/*#define IDLWDT_ARM 0*/
@@ -96,6 +100,9 @@ struct mpu_rate {
#define EN_TC1_CK 2
#define EN_TC2_CK 4
+/* DSP_IDLECT2 bit shifts (0,1,2 are same as for ARM_IDLECT2) */
+#define EN_DSPTIMCK 5
+
/* Various register defines for clock controls scattered around OMAP chip */
#define USB_MCLK_EN_BIT 4 /* In ULPD_CLKC_CTRL */
#define USB_HOST_HHC_UHOST_EN 9 /* In MOD_CONF_CTRL_0 */
@@ -103,7 +110,8 @@ struct mpu_rate {
#define COM_ULPD_PLL_CLK_REQ 1 /* In COM_CLK_DIV_CTRL_SEL */
#define SWD_CLK_DIV_CTRL_SEL 0xfffe0874
#define COM_CLK_DIV_CTRL_SEL 0xfffe0878
-
+#define SOFT_REQ_REG 0xfffe0834
+#define SOFT_REQ_REG2 0xfffe0880
int clk_register(struct clk *clk);
void clk_unregister(struct clk *clk);
diff --git a/arch/arm/plat-omap/common.c b/arch/arm/plat-omap/common.c
new file mode 100644
index 000000000000..ea967a8f6ce5
--- /dev/null
+++ b/arch/arm/plat-omap/common.c
@@ -0,0 +1,135 @@
+/*
+ * linux/arch/arm/plat-omap/common.c
+ *
+ * Code common to all OMAP machines.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/console.h>
+#include <linux/serial.h>
+#include <linux/tty.h>
+#include <linux/serial_8250.h>
+#include <linux/serial_reg.h>
+
+#include <asm/hardware.h>
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/mach/map.h>
+#include <asm/hardware/clock.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/mux.h>
+#include <asm/arch/fpga.h>
+
+#include "clock.h"
+
+#define NO_LENGTH_CHECK 0xffffffff
+
+extern int omap_bootloader_tag_len;
+extern u8 omap_bootloader_tag[];
+
+struct omap_board_config_kernel *omap_board_config;
+int omap_board_config_size = 0;
+
+static const void *get_config(u16 tag, size_t len, int skip, size_t *len_out)
+{
+ struct omap_board_config_kernel *kinfo = NULL;
+ int i;
+
+#ifdef CONFIG_OMAP_BOOT_TAG
+ struct omap_board_config_entry *info = NULL;
+
+ if (omap_bootloader_tag_len > 4)
+ info = (struct omap_board_config_entry *) omap_bootloader_tag;
+ while (info != NULL) {
+ u8 *next;
+
+ if (info->tag == tag) {
+ if (skip == 0)
+ break;
+ skip--;
+ }
+
+ if ((info->len & 0x03) != 0) {
+ /* We bail out to avoid an alignment fault */
+ printk(KERN_ERR "OMAP peripheral config: Length (%d) not word-aligned (tag %04x)\n",
+ info->len, info->tag);
+ return NULL;
+ }
+ next = (u8 *) info + sizeof(*info) + info->len;
+ if (next >= omap_bootloader_tag + omap_bootloader_tag_len)
+ info = NULL;
+ else
+ info = (struct omap_board_config_entry *) next;
+ }
+ if (info != NULL) {
+ /* Check the length as a lame attempt to check for
+ * binary inconsistancy. */
+ if (len != NO_LENGTH_CHECK) {
+ /* Word-align len */
+ if (len & 0x03)
+ len = (len + 3) & ~0x03;
+ 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;
+ }
+ }
+ if (len_out != NULL)
+ *len_out = info->len;
+ return info->data;
+ }
+#endif
+ /* 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;
+ }
+ }
+ if (kinfo == NULL)
+ return NULL;
+ return kinfo->data;
+}
+
+const void *__omap_get_config(u16 tag, size_t len, int nr)
+{
+ return get_config(tag, len, nr, NULL);
+}
+EXPORT_SYMBOL(__omap_get_config);
+
+const void *omap_get_var_config(u16 tag, size_t *len)
+{
+ return get_config(tag, NO_LENGTH_CHECK, 0, len);
+}
+EXPORT_SYMBOL(omap_get_var_config);
+
+static int __init omap_add_serial_console(void)
+{
+ const struct omap_serial_console_config *info;
+
+ info = omap_get_config(OMAP_TAG_SERIAL_CONSOLE,
+ struct omap_serial_console_config);
+ if (info != NULL && info->console_uart) {
+ static char speed[11], *opt = NULL;
+
+ if (info->console_speed) {
+ snprintf(speed, sizeof(speed), "%u", info->console_speed);
+ opt = speed;
+ }
+ return add_preferred_console("ttyS", info->console_uart - 1, opt);
+ }
+ return 0;
+}
+console_initcall(omap_add_serial_console);
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
new file mode 100644
index 000000000000..409aac2c4b9d
--- /dev/null
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -0,0 +1,128 @@
+/*
+ * linux/arch/arm/plat-omap/cpu-omap.c
+ *
+ * CPU frequency scaling for OMAP
+ *
+ * Copyright (C) 2005 Nokia Corporation
+ * Written by Tony Lindgren <tony@atomide.com>
+ *
+ * Based on cpu-sa1110.c, Copyright (C) 2001 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 <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/err.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/hardware/clock.h>
+
+/* TODO: Add support for SDRAM timing changes */
+
+int omap_verify_speed(struct cpufreq_policy *policy)
+{
+ struct clk * mpu_clk;
+
+ if (policy->cpu)
+ return -EINVAL;
+
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ mpu_clk = clk_get(NULL, "mpu");
+ if (IS_ERR(mpu_clk))
+ return PTR_ERR(mpu_clk);
+ policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
+ policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
+ cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
+ policy->cpuinfo.max_freq);
+ clk_put(mpu_clk);
+
+ return 0;
+}
+
+unsigned int omap_getspeed(unsigned int cpu)
+{
+ struct clk * mpu_clk;
+ unsigned long rate;
+
+ if (cpu)
+ return 0;
+
+ mpu_clk = clk_get(NULL, "mpu");
+ if (IS_ERR(mpu_clk))
+ return 0;
+ rate = clk_get_rate(mpu_clk) / 1000;
+ clk_put(mpu_clk);
+
+ return rate;
+}
+
+static int omap_target(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation)
+{
+ struct clk * mpu_clk;
+ struct cpufreq_freqs freqs;
+ int ret = 0;
+
+ mpu_clk = clk_get(NULL, "mpu");
+ if (IS_ERR(mpu_clk))
+ return PTR_ERR(mpu_clk);
+
+ freqs.old = omap_getspeed(0);
+ freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
+ freqs.cpu = 0;
+
+ cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+ ret = clk_set_rate(mpu_clk, target_freq * 1000);
+ cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+ clk_put(mpu_clk);
+
+ return ret;
+}
+
+static int __init omap_cpu_init(struct cpufreq_policy *policy)
+{
+ struct clk * mpu_clk;
+
+ mpu_clk = clk_get(NULL, "mpu");
+ if (IS_ERR(mpu_clk))
+ return PTR_ERR(mpu_clk);
+
+ if (policy->cpu != 0)
+ return -EINVAL;
+ policy->cur = policy->min = policy->max = omap_getspeed(0);
+ policy->governor = CPUFREQ_DEFAULT_GOVERNOR;
+ policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+ policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, 216000000) / 1000;
+ policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+ clk_put(mpu_clk);
+
+ return 0;
+}
+
+static struct cpufreq_driver omap_driver = {
+ .flags = CPUFREQ_STICKY,
+ .verify = omap_verify_speed,
+ .target = omap_target,
+ .get = omap_getspeed,
+ .init = omap_cpu_init,
+ .name = "omap",
+};
+
+static int __init omap_cpufreq_init(void)
+{
+ return cpufreq_register_driver(&omap_driver);
+}
+
+arch_initcall(omap_cpufreq_init);
diff --git a/arch/arm/mach-omap/dma.c b/arch/arm/plat-omap/dma.c
index 7a9ebe80d6f8..c0a5c2fa42bd 100644
--- a/arch/arm/mach-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/omap/dma.c
+ * linux/arch/arm/plat-omap/dma.c
*
* Copyright (C) 2003 Nokia Corporation
* Author: Juha Yrjölä <juha.yrjola@nokia.com>
@@ -794,10 +794,6 @@ static void set_b1_regs(void)
w = omap_readw(OMAP1610_DMA_LCD_CTRL);
/* Always set the source port as SDRAM for now*/
w &= ~(0x03 << 6);
- if (lcd_dma.ext_ctrl)
- w |= 1 << 8;
- else
- w &= ~(1 << 8);
if (lcd_dma.callback != NULL)
w |= 1 << 1; /* Block interrupt enable */
else
@@ -889,9 +885,15 @@ void omap_enable_lcd_dma(void)
*/
if (enable_1510_mode || !lcd_dma.ext_ctrl)
return;
+
+ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+ w |= 1 << 8;
+ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
+
w = omap_readw(OMAP1610_DMA_LCD_CCR);
w |= 1 << 7;
omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
lcd_dma.active = 1;
}
@@ -922,10 +924,19 @@ void omap_setup_lcd_dma(void)
void omap_stop_lcd_dma(void)
{
+ u16 w;
+
lcd_dma.active = 0;
- if (!enable_1510_mode && lcd_dma.ext_ctrl)
- omap_writew(omap_readw(OMAP1610_DMA_LCD_CCR) & ~(1 << 7),
- OMAP1610_DMA_LCD_CCR);
+ if (enable_1510_mode || !lcd_dma.ext_ctrl)
+ return;
+
+ w = omap_readw(OMAP1610_DMA_LCD_CCR);
+ w &= ~(1 << 7);
+ omap_writew(w, OMAP1610_DMA_LCD_CCR);
+
+ w = omap_readw(OMAP1610_DMA_LCD_CTRL);
+ w &= ~(1 << 8);
+ omap_writew(w, OMAP1610_DMA_LCD_CTRL);
}
/*
@@ -972,6 +983,25 @@ dma_addr_t omap_get_dma_dst_pos(int lch)
(OMAP_DMA_CDSA_U(lch) << 16));
}
+int omap_dma_running(void)
+{
+ int lch;
+
+ /* Check if LCD DMA is running */
+ if (cpu_is_omap16xx())
+ if (omap_readw(OMAP1610_DMA_LCD_CCR) & OMAP_DMA_CCR_EN)
+ return 1;
+
+ for (lch = 0; lch < dma_chan_count; lch++) {
+ u16 w;
+
+ w = omap_readw(OMAP_DMA_CCR(lch));
+ if (w & OMAP_DMA_CCR_EN)
+ return 1;
+ }
+ return 0;
+}
+
static int __init omap_init_dma(void)
{
int ch, r;
diff --git a/arch/arm/mach-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 9045dfd469ad..1c85b4e536c2 100644
--- a/arch/arm/mach-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/gpio.c
+ * linux/arch/arm/plat-omap/gpio.c
*
* Support functions for OMAP GPIO
*
diff --git a/arch/arm/mach-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index 7c4ad7713091..43567d5edddb 100644
--- a/arch/arm/mach-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/omap/mcbsp.c
+ * linux/arch/arm/plat-omap/mcbsp.c
*
* Copyright (C) 2004 Nokia Corporation
* Author: Samuel Ortiz <samuel.ortiz@nokia.com>
@@ -66,6 +66,7 @@ struct omap_mcbsp {
static struct omap_mcbsp mcbsp[OMAP_MAX_MCBSP_COUNT];
static struct clk *mcbsp_dsp_ck = 0;
static struct clk *mcbsp_api_ck = 0;
+static struct clk *mcbsp_dspxor_ck = 0;
static void omap_mcbsp_dump_reg(u8 id)
@@ -175,7 +176,7 @@ static int omap_mcbsp_check(unsigned int id)
return 0;
}
- if (cpu_is_omap1510() || cpu_is_omap1610() || cpu_is_omap1710()) {
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
if (id > OMAP_MAX_MCBSP_COUNT) {
printk(KERN_ERR "OMAP-McBSP: McBSP%d doesn't exist\n", id + 1);
return -1;
@@ -191,15 +192,12 @@ static int omap_mcbsp_check(unsigned int id)
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);
- clk_enable(mcbsp_dsp_ck);
- clk_enable(mcbsp_api_ck);
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ clk_use(mcbsp_dsp_ck);
+ clk_use(mcbsp_api_ck);
/* enable 12MHz clock to mcbsp 1 & 3 */
- __raw_writew(__raw_readw(DSP_IDLECT2) | (1 << EN_XORPCK),
- DSP_IDLECT2);
+ clk_use(mcbsp_dspxor_ck);
__raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1 << 1,
DSP_RSTCT2);
}
@@ -207,10 +205,13 @@ static void omap_mcbsp_dsp_request(void)
static void omap_mcbsp_dsp_free(void)
{
- /* Useless for now */
+ if (cpu_is_omap1510() || cpu_is_omap16xx()) {
+ clk_unuse(mcbsp_dspxor_ck);
+ clk_unuse(mcbsp_dsp_ck);
+ clk_unuse(mcbsp_api_ck);
+ }
}
-
int omap_mcbsp_request(unsigned int id)
{
int err;
@@ -350,6 +351,73 @@ void omap_mcbsp_stop(unsigned int id)
}
+/* polled mcbsp i/o operations */
+int omap_mcbsp_pollwrite(unsigned int id, u16 buf)
+{
+ u32 base = mcbsp[id].io_base;
+ writew(buf, base + OMAP_MCBSP_REG_DXR1);
+ /* if frame sync error - clear the error */
+ if (readw(base + OMAP_MCBSP_REG_SPCR2) & XSYNC_ERR) {
+ /* clear error */
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) & (~XSYNC_ERR),
+ base + OMAP_MCBSP_REG_SPCR2);
+ /* resend */
+ return -1;
+ } else {
+ /* wait for transmit confirmation */
+ int attemps = 0;
+ while (!(readw(base + OMAP_MCBSP_REG_SPCR2) & XRDY)) {
+ if (attemps++ > 1000) {
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) &
+ (~XRST),
+ base + OMAP_MCBSP_REG_SPCR2);
+ udelay(10);
+ writew(readw(base + OMAP_MCBSP_REG_SPCR2) |
+ (XRST),
+ base + OMAP_MCBSP_REG_SPCR2);
+ udelay(10);
+ printk(KERN_ERR
+ " Could not write to McBSP Register\n");
+ return -2;
+ }
+ }
+ }
+ return 0;
+}
+
+int omap_mcbsp_pollread(unsigned int id, u16 * buf)
+{
+ u32 base = mcbsp[id].io_base;
+ /* if frame sync error - clear the error */
+ if (readw(base + OMAP_MCBSP_REG_SPCR1) & RSYNC_ERR) {
+ /* clear error */
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) & (~RSYNC_ERR),
+ base + OMAP_MCBSP_REG_SPCR1);
+ /* resend */
+ return -1;
+ } else {
+ /* wait for recieve confirmation */
+ int attemps = 0;
+ while (!(readw(base + OMAP_MCBSP_REG_SPCR1) & RRDY)) {
+ if (attemps++ > 1000) {
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) &
+ (~RRST),
+ base + OMAP_MCBSP_REG_SPCR1);
+ udelay(10);
+ writew(readw(base + OMAP_MCBSP_REG_SPCR1) |
+ (RRST),
+ base + OMAP_MCBSP_REG_SPCR1);
+ udelay(10);
+ printk(KERN_ERR
+ " Could not read from McBSP Register\n");
+ return -2;
+ }
+ }
+ }
+ *buf = readw(base + OMAP_MCBSP_REG_DRR1);
+ return 0;
+}
+
/*
* IRQ based word transmission.
*/
@@ -625,10 +693,15 @@ static int __init omap_mcbsp_init(void)
return PTR_ERR(mcbsp_dsp_ck);
}
mcbsp_api_ck = clk_get(0, "api_ck");
- if (IS_ERR(mcbsp_dsp_ck)) {
+ if (IS_ERR(mcbsp_api_ck)) {
printk(KERN_ERR "mcbsp: could not acquire api_ck handle.\n");
return PTR_ERR(mcbsp_api_ck);
}
+ mcbsp_dspxor_ck = clk_get(0, "dspxor_ck");
+ if (IS_ERR(mcbsp_dspxor_ck)) {
+ printk(KERN_ERR "mcbsp: could not acquire dspxor_ck handle.\n");
+ return PTR_ERR(mcbsp_dspxor_ck);
+ }
#ifdef CONFIG_ARCH_OMAP730
if (cpu_is_omap730()) {
@@ -643,7 +716,7 @@ static int __init omap_mcbsp_init(void)
}
#endif
#if defined(CONFIG_ARCH_OMAP16XX)
- if (cpu_is_omap1610() || cpu_is_omap1710()) {
+ if (cpu_is_omap16xx()) {
mcbsp_info = mcbsp_1610;
mcbsp_count = ARRAY_SIZE(mcbsp_1610);
}
diff --git a/arch/arm/mach-omap/mux.c b/arch/arm/plat-omap/mux.c
index bcf3c6e5ecd0..ea7b955b9c81 100644
--- a/arch/arm/mach-omap/mux.c
+++ b/arch/arm/plat-omap/mux.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/mux.c
+ * linux/arch/arm/plat-omap/mux.c
*
* Utility to set the Omap MUX and PULL_DWN registers from a table in mux.h
*
@@ -53,19 +53,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
return -EINVAL;
}
- cfg = &reg_cfg_table[reg_cfg];
-
- /*
- * We do a pretty long section here with lock on, but pin muxing
- * should only happen on driver init for each driver, so it's not time
- * critical.
- */
- spin_lock_irqsave(&mux_spin_lock, flags);
+ cfg = (reg_cfg_set *)&reg_cfg_table[reg_cfg];
/* Check the mux register in question */
if (cfg->mux_reg) {
unsigned tmp1, tmp2;
+ spin_lock_irqsave(&mux_spin_lock, flags);
reg_orig = omap_readl(cfg->mux_reg);
/* The mux registers always seem to be 3 bits long */
@@ -80,11 +74,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
warn = 1;
omap_writel(reg, cfg->mux_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
/* Check for pull up or pull down selection on 1610 */
if (!cpu_is_omap1510()) {
if (cfg->pu_pd_reg && cfg->pull_val) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
pu_pd_orig = omap_readl(cfg->pu_pd_reg);
mask = 1 << cfg->pull_bit;
@@ -100,11 +96,13 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
pu_pd = pu_pd_orig & ~mask;
}
omap_writel(pu_pd, cfg->pu_pd_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
}
/* Check for an associated pull down register */
if (cfg->pull_reg) {
+ spin_lock_irqsave(&mux_spin_lock, flags);
pull_orig = omap_readl(cfg->pull_reg);
mask = 1 << cfg->pull_bit;
@@ -121,6 +119,7 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
}
omap_writel(pull, cfg->pull_reg);
+ spin_unlock_irqrestore(&mux_spin_lock, flags);
}
if (warn) {
@@ -149,8 +148,6 @@ omap_cfg_reg(const reg_cfg_t reg_cfg)
}
#endif
- spin_unlock_irqrestore(&mux_spin_lock, flags);
-
#ifdef CONFIG_OMAP_MUX_ERRORS
return warn ? -ETXTBSY : 0;
#else
diff --git a/arch/arm/mach-omap/ocpi.c b/arch/arm/plat-omap/ocpi.c
index c9ced134a75d..1fb16f9edfd5 100644
--- a/arch/arm/mach-omap/ocpi.c
+++ b/arch/arm/plat-omap/ocpi.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/ocpi.c
+ * linux/arch/arm/plat-omap/ocpi.c
*
* Minimal OCP bus support for omap16xx
*
diff --git a/arch/arm/mach-omap/pm.c b/arch/arm/plat-omap/pm.c
index 00fac155df2a..e6536b16c385 100644
--- a/arch/arm/mach-omap/pm.c
+++ b/arch/arm/plat-omap/pm.c
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/pm.c
+ * linux/arch/arm/plat-omap/pm.c
*
* OMAP Power Management Routines
*
@@ -41,7 +41,9 @@
#include <linux/pm.h>
#include <asm/io.h>
+#include <asm/mach/time.h>
#include <asm/mach-types.h>
+
#include <asm/arch/omap16xx.h>
#include <asm/arch/pm.h>
#include <asm/arch/mux.h>
@@ -80,13 +82,13 @@ void omap_pm_idle(void)
return;
}
mask32 = omap_readl(ARM_SYSST);
- local_fiq_enable();
- local_irq_enable();
-#if defined(CONFIG_OMAP_32K_TIMER) && defined(CONFIG_NO_IDLE_HZ)
- /* Override timer to use VST for the next cycle */
- omap_32k_timer_next_vst_interrupt();
-#endif
+ /*
+ * Since an interrupt may set up a timer, we don't want to
+ * reprogram the hardware timer with interrupts enabled.
+ * Re-enable interrupts only after returning from idle.
+ */
+ timer_dyn_reprogram();
if ((mask32 & DSP_IDLE) == 0) {
__asm__ volatile ("mcr p15, 0, r0, c7, c0, 4");
@@ -102,6 +104,8 @@ void omap_pm_idle(void)
func_ptr();
}
+ local_fiq_enable();
+ local_irq_enable();
}
/*
diff --git a/arch/arm/mach-omap/sleep.S b/arch/arm/plat-omap/sleep.S
index 4d426d105828..279490ce772b 100644
--- a/arch/arm/mach-omap/sleep.S
+++ b/arch/arm/plat-omap/sleep.S
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/sleep.S
+ * linux/arch/arm/plat-omap/sleep.S
*
* Low-level OMAP1510/1610 sleep/wakeUp support
*
diff --git a/arch/arm/mach-omap/usb.c b/arch/arm/plat-omap/usb.c
index 6e805d451d0e..25bc4a8dd763 100644
--- a/arch/arm/mach-omap/usb.c
+++ b/arch/arm/plat-omap/usb.c
@@ -1,5 +1,5 @@
/*
- * arch/arm/mach-omap/usb.c -- platform level USB initialization
+ * arch/arm/plat-omap/usb.c -- platform level USB initialization
*
* Copyright (C) 2004 Texas Instruments, Inc.
*
@@ -41,7 +41,6 @@
/* 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.
@@ -288,8 +287,8 @@ static void usb_release(struct device *dev)
static struct resource udc_resources[] = {
/* order is significant! */
{ /* registers */
- .start = IO_ADDRESS(UDC_BASE),
- .end = IO_ADDRESS(UDC_BASE + 0xff),
+ .start = UDC_BASE,
+ .end = UDC_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, { /* general IRQ */
.start = IH2_BASE + 20,
@@ -327,7 +326,7 @@ static u64 ohci_dmamask = ~(u32)0;
static struct resource ohci_resources[] = {
{
.start = OMAP_OHCI_BASE,
- .end = OMAP_OHCI_BASE + 4096,
+ .end = OMAP_OHCI_BASE + 4096 - 1,
.flags = IORESOURCE_MEM,
},
{
@@ -355,8 +354,8 @@ static struct platform_device ohci_device = {
static struct resource otg_resources[] = {
/* order is significant! */
{
- .start = IO_ADDRESS(OTG_BASE),
- .end = IO_ADDRESS(OTG_BASE + 0xff),
+ .start = OTG_BASE,
+ .end = OTG_BASE + 0xff,
.flags = IORESOURCE_MEM,
}, {
.start = IH2_BASE + 8,
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index 30c1dfbb052f..6d3a79e5fef8 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: Thu Mar 24 14:34:50 2005
+# Last update: Thu Jun 23 20:19:33 2005
#
# machine_is_xxx CONFIG_xxxx MACH_TYPE_xxx number
#
@@ -243,7 +243,7 @@ yoho ARCH_YOHO YOHO 231
jasper ARCH_JASPER JASPER 232
dsc25 ARCH_DSC25 DSC25 233
omap_innovator MACH_OMAP_INNOVATOR OMAP_INNOVATOR 234
-ramses ARCH_RAMSES RAMSES 235
+mnci ARCH_RAMSES RAMSES 235
s28x ARCH_S28X S28X 236
mport3 ARCH_MPORT3 MPORT3 237
pxa_eagle250 ARCH_PXA_EAGLE250 PXA_EAGLE250 238
@@ -323,7 +323,7 @@ nimbra29x ARCH_NIMBRA29X NIMBRA29X 311
nimbra210 ARCH_NIMBRA210 NIMBRA210 312
hhp_d95xx ARCH_HHP_D95XX HHP_D95XX 313
labarm ARCH_LABARM LABARM 314
-m825xx ARCH_M825XX M825XX 315
+comcerto ARCH_M825XX M825XX 315
m7100 SA1100_M7100 M7100 316
nipc2 ARCH_NIPC2 NIPC2 317
fu7202 ARCH_FU7202 FU7202 318
@@ -724,3 +724,66 @@ lpc22xx MACH_LPC22XX LPC22XX 715
omap_comet3 MACH_COMET3 COMET3 716
omap_comet4 MACH_COMET4 COMET4 717
csb625 MACH_CSB625 CSB625 718
+fortunet2 MACH_FORTUNET2 FORTUNET2 719
+s5h2200 MACH_S5H2200 S5H2200 720
+optorm920 MACH_OPTORM920 OPTORM920 721
+adsbitsyxb MACH_ADSBITSYXB ADSBITSYXB 722
+adssphere MACH_ADSSPHERE ADSSPHERE 723
+adsportal MACH_ADSPORTAL ADSPORTAL 724
+ln2410sbc MACH_LN2410SBC LN2410SBC 725
+cb3rufc MACH_CB3RUFC CB3RUFC 726
+mp2usb MACH_MP2USB MP2USB 727
+ntnp425c MACH_NTNP425C NTNP425C 728
+colibri MACH_COLIBRI COLIBRI 729
+pcm7220 MACH_PCM7220 PCM7220 730
+gateway7001 MACH_GATEWAY7001 GATEWAY7001 731
+pcm027 MACH_PCM027 PCM027 732
+cmpxa MACH_CMPXA CMPXA 733
+anubis MACH_ANUBIS ANUBIS 734
+ite8152 MACH_ITE8152 ITE8152 735
+lpc3xxx MACH_LPC3XXX LPC3XXX 736
+puppeteer MACH_PUPPETEER PUPPETEER 737
+vt001 MACH_MACH_VADATECH MACH_VADATECH 738
+e570 MACH_E570 E570 739
+x50 MACH_X50 X50 740
+recon MACH_RECON RECON 741
+xboardgp8 MACH_XBOARDGP8 XBOARDGP8 742
+fpic2 MACH_FPIC2 FPIC2 743
+akita MACH_AKITA AKITA 744
+a81 MACH_A81 A81 745
+svm_sc25x MACH_SVM_SC25X SVM_SC25X 746
+vt020 MACH_VADATECH020 VADATECH020 747
+tli MACH_TLI TLI 748
+edb9315lc MACH_EDB9315LC EDB9315LC 749
+passec MACH_PASSEC PASSEC 750
+ds_tiger MACH_DS_TIGER DS_TIGER 751
+e310 MACH_E310 E310 752
+e330 MACH_E330 E330 753
+rt3000 MACH_RT3000 RT3000 754
+nokia770 MACH_NOKIA770 NOKIA770 755
+pnx0106 MACH_PNX0106 PNX0106 756
+hx21xx MACH_HX21XX HX21XX 757
+faraday MACH_FARADAY FARADAY 758
+sbc9312 MACH_SBC9312 SBC9312 759
+batman MACH_BATMAN BATMAN 760
+jpd201 MACH_JPD201 JPD201 761
+mipsa MACH_MIPSA MIPSA 762
+kacom MACH_KACOM KACOM 763
+swarcocpu MACH_SWARCOCPU SWARCOCPU 764
+swarcodsl MACH_SWARCODSL SWARCODSL 765
+blueangel MACH_BLUEANGEL BLUEANGEL 766
+hairygrama MACH_HAIRYGRAMA HAIRYGRAMA 767
+banff MACH_BANFF BANFF 768
+carmeva MACH_CARMEVA CARMEVA 769
+sam255 MACH_SAM255 SAM255 770
+ppm10 MACH_PPM10 PPM10 771
+edb9315a MACH_EDB9315A EDB9315A 772
+sunset MACH_SUNSET SUNSET 773
+stargate2 MACH_STARGATE2 STARGATE2 774
+intelmote2 MACH_INTELMOTE2 INTELMOTE2 775
+trizeps4 MACH_TRIZEPS4 TRIZEPS4 776
+mainstone2 MACH_MAINSTONE2 MAINSTONE2 777
+ez_ixp42x MACH_EZ_IXP42X EZ_IXP42X 778
+tapwave_zodiac MACH_TAPWAVE_ZODIAC TAPWAVE_ZODIAC 779
+universalmeter MACH_UNIVERSALMETER UNIVERSALMETER 780
+hicoarm9 MACH_HICOARM9 HICOARM9 781
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 55a02bc994a3..4b97950984e9 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -117,7 +117,13 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
if (nh >= m)
return ~0ULL;
mh = m >> 32;
- z = (mh << 32 <= nh) ? 0xffffffff00000000ULL : (nh / mh) << 32;
+ if (mh << 32 <= nh) {
+ z = 0xffffffff00000000ULL;
+ } else {
+ z = nh;
+ do_div(z, mh);
+ z <<= 32;
+ }
mul64to128(&termh, &terml, m, z);
sub128(&remh, &reml, nh, nl, termh, terml);
ml = m << 32;
@@ -126,7 +132,12 @@ static inline u64 vfp_estimate_div128to64(u64 nh, u64 nl, u64 m)
add128(&remh, &reml, remh, reml, mh, ml);
}
remh = (remh << 32) | (reml >> 32);
- z |= (mh << 32 <= remh) ? 0xffffffff : remh / mh;
+ if (mh << 32 <= remh) {
+ z |= 0xffffffff;
+ } else {
+ do_div(remh, mh);
+ z |= remh;
+ }
return z;
}
diff --git a/arch/arm/vfp/vfpdouble.c b/arch/arm/vfp/vfpdouble.c
index fa3053e84db5..b801cd66b6ea 100644
--- a/arch/arm/vfp/vfpdouble.c
+++ b/arch/arm/vfp/vfpdouble.c
@@ -32,6 +32,8 @@
*/
#include <linux/kernel.h>
#include <linux/bitops.h>
+
+#include <asm/div64.h>
#include <asm/ptrace.h>
#include <asm/vfp.h>
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 3aeedd2afc70..22f3da4e0829 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -89,7 +89,7 @@ void vfp_raise_sigfpe(unsigned int sicode, struct pt_regs *regs)
current->thread.error_code = 0;
current->thread.trap_no = 6;
- force_sig_info(SIGFPE, &info, current);
+ send_sig_info(SIGFPE, &info, current);
}
static void vfp_panic(char *reason)
diff --git a/arch/arm/vfp/vfpsingle.c b/arch/arm/vfp/vfpsingle.c
index 6849fe35cb2e..14dd696ddeb1 100644
--- a/arch/arm/vfp/vfpsingle.c
+++ b/arch/arm/vfp/vfpsingle.c
@@ -32,6 +32,8 @@
*/
#include <linux/kernel.h>
#include <linux/bitops.h>
+
+#include <asm/div64.h>
#include <asm/ptrace.h>
#include <asm/vfp.h>
@@ -303,7 +305,11 @@ u32 vfp_estimate_sqrt_significand(u32 exponent, u32 significand)
if (z <= a)
return (s32)a >> 1;
}
- return (u32)(((u64)a << 31) / z) + (z >> 1);
+ {
+ u64 v = (u64)a << 31;
+ do_div(v, z);
+ return v + (z >> 1);
+ }
}
static u32 vfp_single_fsqrt(int sd, int unused, s32 m, u32 fpscr)
@@ -1107,7 +1113,11 @@ static u32 vfp_single_fdiv(int sd, int sn, s32 m, u32 fpscr)
vsn.significand >>= 1;
vsd.exponent++;
}
- vsd.significand = ((u64)vsn.significand << 32) / vsm.significand;
+ {
+ u64 significand = (u64)vsn.significand << 32;
+ do_div(significand, vsm.significand);
+ vsd.significand = significand;
+ }
if ((vsd.significand & 0x3f) == 0)
vsd.significand |= ((u64)vsm.significand * vsd.significand != (u64)vsn.significand << 32);
diff --git a/arch/arm26/Kconfig b/arch/arm26/Kconfig
index dc0c1936969b..1f0373267306 100644
--- a/arch/arm26/Kconfig
+++ b/arch/arm26/Kconfig
@@ -183,6 +183,8 @@ source "mm/Kconfig"
endmenu
+source "net/Kconfig"
+
source "drivers/base/Kconfig"
source "drivers/parport/Kconfig"
@@ -193,7 +195,7 @@ source "drivers/block/Kconfig"
source "drivers/md/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/ide/Kconfig"
diff --git a/arch/cris/Kconfig b/arch/cris/Kconfig
index f848e3761491..e5979d68e352 100644
--- a/arch/cris/Kconfig
+++ b/arch/cris/Kconfig
@@ -122,6 +122,8 @@ source arch/cris/arch-v10/Kconfig
endmenu
+source "net/Kconfig"
+
# bring in ETRAX built-in drivers
menu "Drivers for built-in interfaces"
source arch/cris/arch-v10/drivers/Kconfig
@@ -149,7 +151,7 @@ source "drivers/ieee1394/Kconfig"
source "drivers/message/i2o/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
diff --git a/arch/frv/Kconfig b/arch/frv/Kconfig
index c93f95146cc2..ec85c0d6c6da 100644
--- a/arch/frv/Kconfig
+++ b/arch/frv/Kconfig
@@ -346,6 +346,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/frv/defconfig b/arch/frv/defconfig
new file mode 100644
index 000000000000..b6e4ca5efb59
--- /dev/null
+++ b/arch/frv/defconfig
@@ -0,0 +1,627 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11.8
+# Fri May 13 17:16:03 2005
+#
+CONFIG_FRV=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+# CONFIG_GENERIC_HARDIRQS is not set
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# 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_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Fujitsu FR-V system setup
+#
+CONFIG_MMU=y
+CONFIG_FRV_OUTOFLINE_ATOMIC_OPS=y
+CONFIG_HIGHMEM=y
+CONFIG_HIGHPTE=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_FRV_DEFL_CACHE_WBACK is not set
+# CONFIG_FRV_DEFL_CACHE_WBEHIND is not set
+CONFIG_FRV_DEFL_CACHE_WTHRU=y
+# CONFIG_FRV_DEFL_CACHE_DISABLED is not set
+
+#
+# CPU core support
+#
+CONFIG_CPU_FR451=y
+CONFIG_CPU_FR451_COMPILE=y
+CONFIG_FRV_L1_CACHE_SHIFT=5
+CONFIG_MB93091_VDK=y
+# CONFIG_MB93093_PDK is not set
+CONFIG_MB93090_MB00=y
+# CONFIG_MB93091_NO_MB is not set
+# CONFIG_GPREL_DATA_8 is not set
+CONFIG_GPREL_DATA_4=y
+# CONFIG_GPREL_DATA_NONE is not set
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCMCIA is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+
+#
+# Executable formats
+#
+# CONFIG_BINFMT_ELF is not set
+CONFIG_BINFMT_ELF_FDPIC=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+# CONFIG_STANDALONE is not set
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+# CONFIG_FORK_CONNECTOR 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_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_COW_COMMON 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 is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH 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
+#
+# 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 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 is not set
+# 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_INET_TUNNEL is not set
+# CONFIG_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 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
+
+#
+# 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_IEEE80211 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
+
+#
+# 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 is not set
+# CONFIG_E100 is not set
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+CONFIG_NE2K_PCI=y
+# 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_TLAN is not set
+# CONFIG_VIA_RHINE 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_SKGE is not set
+# CONFIG_SK98LIN is not set
+# CONFIG_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+
+#
+# Ethernet (10000 Mbit)
+#
+# CONFIG_CHELSIO_T1 is not set
+# 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_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 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+# CONFIG_VT is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=1
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+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_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS 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
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_DRM is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM 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
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_JBD is not set
+# CONFIG_REISER4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_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 is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_FS is not set
+
+#
+# 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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=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
+# 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 is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_FRAME_POINTER is not set
+# CONFIG_EARLY_PRINTK is not set
+CONFIG_DEBUG_STACKOVERFLOW=y
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_GDBSTUB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/frv/kernel/setup.c b/arch/frv/kernel/setup.c
index ef6865f0b979..767ebb55bd83 100644
--- a/arch/frv/kernel/setup.c
+++ b/arch/frv/kernel/setup.c
@@ -790,12 +790,10 @@ void __init setup_arch(char **cmdline_p)
#ifndef CONFIG_GDBSTUB_UART0
__reg(UART0_BASE + UART_IER * 8) = 0;
early_serial_setup(&__frv_uart0);
-// register_serial(&__frv_uart0);
#endif
#ifndef CONFIG_GDBSTUB_UART1
__reg(UART1_BASE + UART_IER * 8) = 0;
early_serial_setup(&__frv_uart1);
-// register_serial(&__frv_uart1);
#endif
#if defined(CONFIG_CHR_DEV_FLASH) || defined(CONFIG_BLK_DEV_FLASH)
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index d8d8f3d4304d..36a2dffc8ebd 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -536,10 +536,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!user_mode(regs))
return 1;
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze())
goto no_signal;
- }
if (!oldset)
oldset = &current->blocked;
diff --git a/arch/frv/mb93090-mb00/pci-irq.c b/arch/frv/mb93090-mb00/pci-irq.c
index 24622d89b1ca..af981bda015c 100644
--- a/arch/frv/mb93090-mb00/pci-irq.c
+++ b/arch/frv/mb93090-mb00/pci-irq.c
@@ -60,7 +60,7 @@ void __init pcibios_fixup_irqs(void)
}
}
-void __init pcibios_penalize_isa_irq(int irq)
+void __init pcibios_penalize_isa_irq(int irq, int active)
{
}
diff --git a/arch/h8300/Kconfig b/arch/h8300/Kconfig
index 62a89e812e3e..26698a49f153 100644
--- a/arch/h8300/Kconfig
+++ b/arch/h8300/Kconfig
@@ -55,6 +55,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/base/Kconfig"
source "drivers/mtd/Kconfig"
@@ -65,7 +67,7 @@ source "drivers/ide/Kconfig"
source "arch/h8300/Kconfig.ide"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
#
# input - input/joystick depends on it. As does USB.
@@ -179,6 +181,8 @@ source "drivers/serial/Kconfig"
source "drivers/i2c/Kconfig"
+source "drivers/hwmon/Kconfig"
+
source "drivers/usb/Kconfig"
endmenu
diff --git a/arch/h8300/kernel/signal.c b/arch/h8300/kernel/signal.c
index a4799d633ef4..5aab87eae1f9 100644
--- a/arch/h8300/kernel/signal.c
+++ b/arch/h8300/kernel/signal.c
@@ -517,10 +517,8 @@ asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset)
if ((regs->ccr & 0x10))
return 1;
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze())
goto no_signal;
- }
current->thread.esp0 = (unsigned long) regs;
diff --git a/arch/i386/Kconfig b/arch/i386/Kconfig
index d4ae5f9ceae6..a801d9d48606 100644
--- a/arch/i386/Kconfig
+++ b/arch/i386/Kconfig
@@ -510,28 +510,7 @@ config SCHED_SMT
cost of slightly increased overhead in some places. If unsure say
N here.
-config PREEMPT
- bool "Preemptible Kernel"
- help
- This option reduces the latency of the kernel when reacting to
- real-time or interactive events by allowing a low priority process to
- be preempted even if it is in kernel mode executing a system call.
- This allows applications to run more reliably even when the system is
- under load.
-
- Say Y here if you are building a kernel for a desktop, embedded
- or real-time system. Say N if you are unsure.
-
-config PREEMPT_BKL
- bool "Preempt The Big Kernel Lock"
- depends on PREEMPT
- default y
- help
- This option reduces the latency of the kernel by making the
- big kernel lock preemptible.
-
- Say Y here if you are building a kernel for a desktop system.
- Say N if you are unsure.
+source "kernel/Kconfig.preempt"
config X86_UP_APIC
bool "Local APIC support on uniprocessors"
@@ -963,6 +942,41 @@ config SECCOMP
source kernel/Kconfig.hz
+config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if EMBEDDED
+ default "0x100000"
+ help
+ This gives the physical address where the kernel is loaded.
+ Primarily used in the case of kexec on panic where the
+ fail safe kernel needs to run at a different address than
+ the panic-ed kernel.
+
+ Don't change this unless you know what you are doing.
+
+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
+config CRASH_DUMP
+ bool "kernel crash dumps (EXPERIMENTAL)"
+ depends on EMBEDDED
+ depends on EXPERIMENTAL
+ depends on HIGHMEM
+ help
+ Generate crash dump after being started by kexec.
endmenu
@@ -1250,6 +1264,15 @@ config SCx200
This support is also available as a module. If compiled as a
module, it will be called scx200.
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+ depends on SMP && HOTPLUG && EXPERIMENTAL
+ ---help---
+ Say Y here to experiment with turning CPUs off and on. CPUs
+ can be controlled through /sys/devices/system/cpu.
+
+ Say N.
+
source "drivers/pcmcia/Kconfig"
source "drivers/pci/hotplug/Kconfig"
@@ -1262,6 +1285,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/i386/boot/Makefile b/arch/i386/boot/Makefile
index 43cd6220ee49..1e71382d413a 100644
--- a/arch/i386/boot/Makefile
+++ b/arch/i386/boot/Makefile
@@ -25,8 +25,8 @@ SVGA_MODE := -DSVGA_MODE=NORMAL_VGA
#RAMDISK := -DRAMDISK=512
-targets := vmlinux.bin bootsect bootsect.o setup setup.o \
- zImage bzImage
+targets := vmlinux.bin bootsect bootsect.o \
+ setup setup.o zImage bzImage
subdir- := compressed
hostprogs-y := tools/build
diff --git a/arch/i386/boot/compressed/head.S b/arch/i386/boot/compressed/head.S
index c5e80b69e7d4..b5893e4ecd37 100644
--- a/arch/i386/boot/compressed/head.S
+++ b/arch/i386/boot/compressed/head.S
@@ -25,6 +25,7 @@
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/page.h>
.globl startup_32
@@ -74,7 +75,7 @@ startup_32:
popl %esi # discard address
popl %esi # real mode pointer
xorl %ebx,%ebx
- ljmp $(__BOOT_CS), $0x100000
+ ljmp $(__BOOT_CS), $__PHYSICAL_START
/*
* We come here, if we were loaded high.
@@ -99,7 +100,7 @@ startup_32:
popl %ecx # lcount
popl %edx # high_buffer_start
popl %eax # hcount
- movl $0x100000,%edi
+ movl $__PHYSICAL_START,%edi
cli # make sure we don't get interrupted
ljmp $(__BOOT_CS), $0x1000 # and jump to the move routine
@@ -124,5 +125,5 @@ move_routine_start:
movsl
movl %ebx,%esi # Restore setup pointer
xorl %ebx,%ebx
- ljmp $(__BOOT_CS), $0x100000
+ ljmp $(__BOOT_CS), $__PHYSICAL_START
move_routine_end:
diff --git a/arch/i386/boot/compressed/misc.c b/arch/i386/boot/compressed/misc.c
index cedc55cc47de..82a807f9f5e6 100644
--- a/arch/i386/boot/compressed/misc.c
+++ b/arch/i386/boot/compressed/misc.c
@@ -13,6 +13,7 @@
#include <linux/vmalloc.h>
#include <linux/tty.h>
#include <asm/io.h>
+#include <asm/page.h>
/*
* gzip declarations
@@ -308,7 +309,7 @@ static void setup_normal_output_buffer(void)
#else
if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory");
#endif
- output_data = (char *)0x100000; /* Points to 1M */
+ output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
free_mem_end_ptr = (long)real_mode;
}
@@ -333,8 +334,8 @@ static void setup_output_buffer_if_we_run_high(struct moveparams *mv)
low_buffer_size = low_buffer_end - LOW_BUFFER_START;
high_loaded = 1;
free_mem_end_ptr = (long)high_buffer_start;
- if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
- high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+ if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
+ high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
mv->hcount = 0; /* say: we need not to move high_buffer */
}
else mv->hcount = -1;
@@ -353,7 +354,6 @@ static void close_output_buffer_if_we_run_high(struct moveparams *mv)
}
}
-
asmlinkage int decompress_kernel(struct moveparams *mv, void *rmode)
{
real_mode = rmode;
diff --git a/arch/i386/boot/edd.S b/arch/i386/boot/edd.S
index 027d6b354ffb..d8d69f2b911d 100644
--- a/arch/i386/boot/edd.S
+++ b/arch/i386/boot/edd.S
@@ -6,7 +6,7 @@
* projects 1572D, 1484D, 1386D, 1226DT
* disk signature read by Matt Domsch <Matt_Domsch@dell.com>
* and Andrew Wilks <Andrew_Wilks@dell.com> September 2003, June 2004
- * legacy CHS retreival by Patrick J. LoPresti <patl@users.sourceforge.net>
+ * legacy CHS retrieval by Patrick J. LoPresti <patl@users.sourceforge.net>
* March 2004
* Command line option parsing, Matt Domsch, November 2004
*/
diff --git a/arch/i386/boot/setup.S b/arch/i386/boot/setup.S
index caa1fde6904e..8cb420f40c58 100644
--- a/arch/i386/boot/setup.S
+++ b/arch/i386/boot/setup.S
@@ -33,7 +33,7 @@
* Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
* <stiker@northlink.com>
*
- * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * Fix to work around buggy BIOSes which don't use carry bit correctly
* and/or report extended memory in CX/DX for e801h memory size detection
* call. As a result the kernel got wrong figures. The int15/e801h docs
* from Ralf Brown interrupt list seem to indicate AX/BX should be used
@@ -357,7 +357,7 @@ bail820:
meme801:
stc # fix to work around buggy
- xorw %cx,%cx # BIOSes which dont clear/set
+ xorw %cx,%cx # BIOSes which don't clear/set
xorw %dx,%dx # carry on pass/error of
# e801h memory size call
# or merely pass cx,dx though
@@ -847,7 +847,7 @@ flush_instr:
#
# but we yet haven't reloaded the CS register, so the default size
# of the target offset still is 16 bit.
-# However, using an operand prefix (0x66), the CPU will properly
+# However, using an operand prefix (0x66), the CPU will properly
# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
# Manual, Mixing 16-bit and 32-bit code, page 16-6)
diff --git a/arch/i386/boot/tools/build.c b/arch/i386/boot/tools/build.c
index 26509b826aed..6835f6d47c31 100644
--- a/arch/i386/boot/tools/build.c
+++ b/arch/i386/boot/tools/build.c
@@ -1,6 +1,4 @@
/*
- * $Id: build.c,v 1.5 1997/05/19 12:29:58 mj Exp $
- *
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1997 Martin Mares
*/
@@ -8,7 +6,8 @@
/*
* This file builds a disk-image from three different files:
*
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - bootsect: compatibility mbr which prints an error message if
+ * someone tries to boot the kernel directly.
* - setup: 8086 machine code, sets up system parm
* - system: 80386 code for actual system
*
@@ -71,7 +70,8 @@ void usage(void)
int main(int argc, char ** argv)
{
- unsigned int i, c, sz, setup_sectors;
+ unsigned int i, sz, setup_sectors;
+ int c;
u32 sys_size;
byte major_root, minor_root;
struct stat sb;
diff --git a/arch/i386/crypto/aes.c b/arch/i386/crypto/aes.c
index 1019430fc1f1..88ee85c3b43b 100644
--- a/arch/i386/crypto/aes.c
+++ b/arch/i386/crypto/aes.c
@@ -59,7 +59,7 @@ struct aes_ctx {
};
#define WPOLY 0x011b
-#define u32_in(x) le32_to_cpu(*(const u32 *)(x))
+#define u32_in(x) le32_to_cpup((const __le32 *)(x))
#define bytes2word(b0, b1, b2, b3) \
(((u32)(b3) << 24) | ((u32)(b2) << 16) | ((u32)(b1) << 8) | (b0))
diff --git a/arch/i386/defconfig b/arch/i386/defconfig
index 28e620383799..ca07b95c06b8 100644
--- a/arch/i386/defconfig
+++ b/arch/i386/defconfig
@@ -126,7 +126,6 @@ CONFIG_HAVE_DEC_LOCK=y
#
CONFIG_PM=y
CONFIG_SOFTWARE_SUSPEND=y
-# CONFIG_PM_DISK is not set
#
# ACPI (Advanced Configuration and Power Interface) Support
diff --git a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
index 51ecd512603d..4cc83b322b36 100644
--- a/arch/i386/kernel/Makefile
+++ b/arch/i386/kernel/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_X86_MPPARSE) += mpparse.o
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o
obj-$(CONFIG_X86_REBOOTFIXUPS) += reboot_fixups.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
obj-$(CONFIG_X86_NUMAQ) += numaq.o
obj-$(CONFIG_X86_SUMMIT_NUMA) += summit.o
obj-$(CONFIG_KPROBES) += kprobes.o
diff --git a/arch/i386/kernel/acpi/Makefile b/arch/i386/kernel/acpi/Makefile
index ee75cb286cfe..5e291a20c03d 100644
--- a/arch/i386/kernel/acpi/Makefile
+++ b/arch/i386/kernel/acpi/Makefile
@@ -2,3 +2,7 @@ obj-$(CONFIG_ACPI_BOOT) := boot.o
obj-$(CONFIG_X86_IO_APIC) += earlyquirk.o
obj-$(CONFIG_ACPI_SLEEP) += sleep.o wakeup.o
+ifneq ($(CONFIG_ACPI_PROCESSOR),)
+obj-y += cstate.o
+endif
+
diff --git a/arch/i386/kernel/acpi/boot.c b/arch/i386/kernel/acpi/boot.c
index 848bb97af7ca..b7808a89d945 100644
--- a/arch/i386/kernel/acpi/boot.c
+++ b/arch/i386/kernel/acpi/boot.c
@@ -29,6 +29,7 @@
#include <linux/efi.h>
#include <linux/irq.h>
#include <linux/module.h>
+#include <linux/dmi.h>
#include <asm/pgtable.h>
#include <asm/io_apic.h>
@@ -158,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
#endif
#ifdef CONFIG_PCI_MMCONFIG
-static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
+/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
+struct acpi_table_mcfg_config *pci_mmcfg_config;
+int pci_mmcfg_config_num;
+
+int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
{
struct acpi_table_mcfg *mcfg;
+ unsigned long i;
+ int config_size;
if (!phys_addr || !size)
return -EINVAL;
@@ -171,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
return -ENODEV;
}
- if (mcfg->base_reserved) {
- printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n");
+ /* how many config structures do we have */
+ pci_mmcfg_config_num = 0;
+ i = size - sizeof(struct acpi_table_mcfg);
+ while (i >= sizeof(struct acpi_table_mcfg_config)) {
+ ++pci_mmcfg_config_num;
+ i -= sizeof(struct acpi_table_mcfg_config);
+ };
+ if (pci_mmcfg_config_num == 0) {
+ printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV;
}
- pci_mmcfg_base_addr = mcfg->base_address;
+ config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
+ pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
+ if (!pci_mmcfg_config) {
+ printk(KERN_WARNING PREFIX
+ "No memory for MCFG config tables\n");
+ return -ENOMEM;
+ }
+
+ memcpy(pci_mmcfg_config, &mcfg->config, config_size);
+ for (i = 0; i < pci_mmcfg_config_num; ++i) {
+ if (mcfg->config[i].base_reserved) {
+ printk(KERN_ERR PREFIX
+ "MMCONFIG not in low 4GB of memory\n");
+ return -ENODEV;
+ }
+ }
return 0;
}
-#else
-#define acpi_parse_mcfg NULL
-#endif /* !CONFIG_PCI_MMCONFIG */
+#endif /* CONFIG_PCI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC
static int __init
@@ -506,6 +533,22 @@ acpi_unmap_lsapic(int cpu)
EXPORT_SYMBOL(acpi_unmap_lsapic);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+int
+acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_register_ioapic);
+
+int
+acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
+{
+ /* TBD */
+ return -EINVAL;
+}
+EXPORT_SYMBOL(acpi_unregister_ioapic);
+
static unsigned long __init
acpi_scan_rsdp (
unsigned long start,
@@ -815,6 +858,219 @@ acpi_process_madt(void)
return;
}
+extern int acpi_force;
+
+#ifdef __i386__
+
+#ifdef CONFIG_ACPI_PCI
+static int __init disable_acpi_irq(struct dmi_system_id *d)
+{
+ if (!acpi_force) {
+ printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
+ d->ident);
+ acpi_noirq_set();
+ }
+ return 0;
+}
+
+static int __init disable_acpi_pci(struct dmi_system_id *d)
+{
+ if (!acpi_force) {
+ printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
+ d->ident);
+ acpi_disable_pci();
+ }
+ return 0;
+}
+#endif
+
+static int __init dmi_disable_acpi(struct dmi_system_id *d)
+{
+ if (!acpi_force) {
+ printk(KERN_NOTICE "%s detected: acpi off\n",d->ident);
+ disable_acpi();
+ } else {
+ printk(KERN_NOTICE
+ "Warning: DMI blacklist says broken, but acpi forced\n");
+ }
+ return 0;
+}
+
+/*
+ * Limit ACPI to CPU enumeration for HT
+ */
+static int __init force_acpi_ht(struct dmi_system_id *d)
+{
+ if (!acpi_force) {
+ printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident);
+ disable_acpi();
+ acpi_ht = 1;
+ } else {
+ printk(KERN_NOTICE
+ "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
+ }
+ return 0;
+}
+
+/*
+ * If your system is blacklisted here, but you find that acpi=force
+ * works for you, please contact acpi-devel@sourceforge.net
+ */
+static struct dmi_system_id __initdata acpi_dmi_table[] = {
+ /*
+ * Boxes that need ACPI disabled
+ */
+ {
+ .callback = dmi_disable_acpi,
+ .ident = "IBM Thinkpad",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+ DMI_MATCH(DMI_BOARD_NAME, "2629H1G"),
+ },
+ },
+
+ /*
+ * Boxes that need acpi=ht
+ */
+ {
+ .callback = force_acpi_ht,
+ .ident = "FSC Primergy T850",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "DELL GX240",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
+ DMI_MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "HP VISUALIZE NT Workstation",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "Compaq Workstation W8000",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Compaq"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "ASUS P4B266",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "P4B266"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "ASUS P2B-DS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "P2B-DS"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "ASUS CUR-DLS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "CUR-DLS"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "ABIT i440BX-W83977",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
+ DMI_MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "IBM Bladecenter",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+ DMI_MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "IBM eServer xSeries 360",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+ DMI_MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "IBM eserver xSeries 330",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+ DMI_MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
+ },
+ },
+ {
+ .callback = force_acpi_ht,
+ .ident = "IBM eserver xSeries 440",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "IBM"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
+ },
+ },
+
+#ifdef CONFIG_ACPI_PCI
+ /*
+ * Boxes that need ACPI PCI IRQ routing disabled
+ */
+ {
+ .callback = disable_acpi_irq,
+ .ident = "ASUS A7V",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
+ DMI_MATCH(DMI_BOARD_NAME, "<A7V>"),
+ /* newer BIOS, Revision 1011, does work */
+ DMI_MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
+ },
+ },
+
+ /*
+ * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
+ */
+ { /* _BBN 0 bug */
+ .callback = disable_acpi_pci,
+ .ident = "ASUS PR-DLS",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
+ DMI_MATCH(DMI_BOARD_NAME, "PR-DLS"),
+ DMI_MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
+ DMI_MATCH(DMI_BIOS_DATE, "03/21/2003")
+ },
+ },
+ {
+ .callback = disable_acpi_pci,
+ .ident = "Acer TravelMate 36x Laptop",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
+ },
+ },
+#endif
+ { }
+};
+
+#endif /* __i386__ */
+
/*
* acpi_boot_table_init() and acpi_boot_init()
* called from setup_arch(), always.
@@ -843,6 +1099,10 @@ acpi_boot_table_init(void)
{
int error;
+#ifdef __i386__
+ dmi_check_system(acpi_dmi_table);
+#endif
+
/*
* If acpi_disabled, bail out
* One exception: acpi=ht continues far enough to enumerate LAPICs
@@ -870,8 +1130,6 @@ acpi_boot_table_init(void)
*/
error = acpi_blacklisted();
if (error) {
- extern int acpi_force;
-
if (acpi_force) {
printk(KERN_WARNING PREFIX "acpi=force override\n");
} else {
@@ -907,7 +1165,6 @@ int __init acpi_boot_init(void)
acpi_process_madt();
acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
- acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
return 0;
}
diff --git a/arch/i386/kernel/acpi/cstate.c b/arch/i386/kernel/acpi/cstate.c
new file mode 100644
index 000000000000..4c3036ba65df
--- /dev/null
+++ b/arch/i386/kernel/acpi/cstate.c
@@ -0,0 +1,103 @@
+/*
+ * arch/i386/kernel/acpi/cstate.c
+ *
+ * Copyright (C) 2005 Intel Corporation
+ * Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * - Added _PDC for SMP C-states on Intel CPUs
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+
+#include <acpi/processor.h>
+#include <asm/acpi.h>
+
+static void acpi_processor_power_init_intel_pdc(struct acpi_processor_power
+ *pow)
+{
+ struct acpi_object_list *obj_list;
+ union acpi_object *obj;
+ u32 *buf;
+
+ /* allocate and initialize pdc. It will be used later. */
+ obj_list = kmalloc(sizeof(struct acpi_object_list), GFP_KERNEL);
+ if (!obj_list) {
+ printk(KERN_ERR "Memory allocation error\n");
+ return;
+ }
+
+ obj = kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ if (!obj) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(obj_list);
+ return;
+ }
+
+ buf = kmalloc(12, GFP_KERNEL);
+ if (!buf) {
+ printk(KERN_ERR "Memory allocation error\n");
+ kfree(obj);
+ kfree(obj_list);
+ return;
+ }
+
+ buf[0] = ACPI_PDC_REVISION_ID;
+ buf[1] = 1;
+ buf[2] = ACPI_PDC_C_CAPABILITY_SMP;
+
+ obj->type = ACPI_TYPE_BUFFER;
+ obj->buffer.length = 12;
+ obj->buffer.pointer = (u8 *) buf;
+ obj_list->count = 1;
+ obj_list->pointer = obj;
+ pow->pdc = obj_list;
+
+ return;
+}
+
+/* Initialize _PDC data based on the CPU vendor */
+void acpi_processor_power_init_pdc(struct acpi_processor_power *pow,
+ unsigned int cpu)
+{
+ struct cpuinfo_x86 *c = cpu_data + cpu;
+
+ pow->pdc = NULL;
+ if (c->x86_vendor == X86_VENDOR_INTEL)
+ acpi_processor_power_init_intel_pdc(pow);
+
+ return;
+}
+
+EXPORT_SYMBOL(acpi_processor_power_init_pdc);
+
+/*
+ * Initialize bm_flags based on the CPU cache properties
+ * On SMP it depends on cache configuration
+ * - When cache is not shared among all CPUs, we flush cache
+ * before entering C3.
+ * - When cache is shared among all CPUs, we use bm_check
+ * mechanism as in UP case
+ *
+ * This routine is called only after all the CPUs are online
+ */
+void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
+ unsigned int cpu)
+{
+ struct cpuinfo_x86 *c = cpu_data + cpu;
+
+ flags->bm_check = 0;
+ if (num_online_cpus() == 1)
+ flags->bm_check = 1;
+ else if (c->x86_vendor == X86_VENDOR_INTEL) {
+ /*
+ * Today all CPUs that support C3 share cache.
+ * TBD: This needs to look at cache shared map, once
+ * multi-core detection patch makes to the base.
+ */
+ flags->bm_check = 1;
+ }
+}
+
+EXPORT_SYMBOL(acpi_processor_power_init_bm_check);
diff --git a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
index 28bb0514bb6e..c1af93032ff3 100644
--- a/arch/i386/kernel/acpi/sleep.c
+++ b/arch/i386/kernel/acpi/sleep.c
@@ -7,6 +7,7 @@
#include <linux/acpi.h>
#include <linux/bootmem.h>
+#include <linux/dmi.h>
#include <asm/smp.h>
#include <asm/tlbflush.h>
@@ -91,3 +92,29 @@ static int __init acpi_sleep_setup(char *str)
__setup("acpi_sleep=", acpi_sleep_setup);
+
+
+static __init int reset_videomode_after_s3(struct dmi_system_id *d)
+{
+ acpi_video_flags |= 2;
+ return 0;
+}
+
+static __initdata struct dmi_system_id acpisleep_dmi_table[] = {
+ { /* Reset video mode after returning from ACPI S3 sleep */
+ .callback = reset_videomode_after_s3,
+ .ident = "Toshiba Satellite 4030cdt",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
+ },
+ },
+ { }
+};
+
+static int __init acpisleep_dmi_init(void)
+{
+ dmi_check_system(acpisleep_dmi_table);
+ return 0;
+}
+
+core_initcall(acpisleep_dmi_init);
diff --git a/arch/i386/kernel/acpi/wakeup.S b/arch/i386/kernel/acpi/wakeup.S
index 39d32484f6f5..44d886c745ec 100644
--- a/arch/i386/kernel/acpi/wakeup.S
+++ b/arch/i386/kernel/acpi/wakeup.S
@@ -74,8 +74,9 @@ wakeup_code:
movw %ax,%fs
movw $0x0e00 + 'i', %fs:(0x12)
- # need a gdt
- lgdt real_save_gdt - wakeup_code
+ # need a gdt -- use lgdtl to force 32-bit operands, in case
+ # the GDT is located past 16 megabytes.
+ lgdtl real_save_gdt - wakeup_code
movl real_save_cr0 - wakeup_code, %eax
movl %eax, %cr0
diff --git a/arch/i386/kernel/apic.c b/arch/i386/kernel/apic.c
index 8d993fa71754..bd1dbf3bd223 100644
--- a/arch/i386/kernel/apic.c
+++ b/arch/i386/kernel/apic.c
@@ -26,6 +26,7 @@
#include <linux/mc146818rtc.h>
#include <linux/kernel_stat.h>
#include <linux/sysdev.h>
+#include <linux/cpu.h>
#include <asm/atomic.h>
#include <asm/smp.h>
@@ -34,12 +35,18 @@
#include <asm/desc.h>
#include <asm/arch_hooks.h>
#include <asm/hpet.h>
+#include <asm/i8253.h>
#include <mach_apic.h>
#include "io_ports.h"
/*
+ * Knob to control our willingness to enable the local APIC.
+ */
+int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
+
+/*
* Debug level
*/
int apic_verbosity;
@@ -205,7 +212,7 @@ void __init connect_bsp_APIC(void)
enable_apic_mode();
}
-void disconnect_bsp_APIC(void)
+void disconnect_bsp_APIC(int virt_wire_setup)
{
if (pic_mode) {
/*
@@ -219,6 +226,42 @@ void disconnect_bsp_APIC(void)
outb(0x70, 0x22);
outb(0x00, 0x23);
}
+ else {
+ /* Go back to Virtual Wire compatibility mode */
+ unsigned long value;
+
+ /* For the spurious interrupt use vector F, and enable it */
+ value = apic_read(APIC_SPIV);
+ value &= ~APIC_VECTOR_MASK;
+ value |= APIC_SPIV_APIC_ENABLED;
+ value |= 0xf;
+ apic_write_around(APIC_SPIV, value);
+
+ if (!virt_wire_setup) {
+ /* For LVT0 make it edge triggered, active high, external and enabled */
+ value = apic_read(APIC_LVT0);
+ value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+ APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+ APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
+ value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+ value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+ apic_write_around(APIC_LVT0, value);
+ }
+ else {
+ /* Disable LVT0 */
+ apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+ }
+
+ /* For LVT1 make it edge triggered, active high, nmi and enabled */
+ value = apic_read(APIC_LVT1);
+ value &= ~(
+ APIC_MODE_MASK | APIC_SEND_PENDING |
+ APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+ APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+ value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+ value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+ apic_write_around(APIC_LVT1, value);
+ }
}
void disable_local_APIC(void)
@@ -363,7 +406,7 @@ void __init init_bsp_APIC(void)
apic_write_around(APIC_LVT1, value);
}
-void __init setup_local_APIC (void)
+void __devinit setup_local_APIC(void)
{
unsigned long oldvalue, value, ver, maxlvt;
@@ -634,7 +677,7 @@ static struct sys_device device_lapic = {
.cls = &lapic_sysclass,
};
-static void __init apic_pm_activate(void)
+static void __devinit apic_pm_activate(void)
{
apic_pm_state.active = 1;
}
@@ -665,26 +708,6 @@ static void apic_pm_activate(void) { }
* Original code written by Keir Fraser.
*/
-/*
- * Knob to control our willingness to enable the local APIC.
- */
-int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
-
-static int __init lapic_disable(char *str)
-{
- enable_local_apic = -1;
- clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
- return 0;
-}
-__setup("nolapic", lapic_disable);
-
-static int __init lapic_enable(char *str)
-{
- enable_local_apic = 1;
- return 0;
-}
-__setup("lapic", lapic_enable);
-
static int __init apic_set_verbosity(char *str)
{
if (strcmp("debug", str) == 0)
@@ -855,9 +878,8 @@ fake_ioapic_page:
* but we do not accept timer interrupts yet. We only allow the BP
* to calibrate.
*/
-static unsigned int __init get_8254_timer_count(void)
+static unsigned int __devinit get_8254_timer_count(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
@@ -874,7 +896,7 @@ static unsigned int __init get_8254_timer_count(void)
}
/* next tick in 8254 can be caught by catching timer wraparound */
-static void __init wait_8254_wraparound(void)
+static void __devinit wait_8254_wraparound(void)
{
unsigned int curr_count, prev_count;
@@ -894,7 +916,7 @@ static void __init wait_8254_wraparound(void)
* Default initialization for 8254 timers. If we use other timers like HPET,
* we override this later
*/
-void (*wait_timer_tick)(void) __initdata = wait_8254_wraparound;
+void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound;
/*
* This function sets up the local APIC timer, with a timeout of
@@ -930,7 +952,7 @@ static void __setup_APIC_LVTT(unsigned int clocks)
apic_write_around(APIC_TMICT, clocks/APIC_DIVISOR);
}
-static void __init setup_APIC_timer(unsigned int clocks)
+static void __devinit setup_APIC_timer(unsigned int clocks)
{
unsigned long flags;
@@ -1043,12 +1065,12 @@ void __init setup_boot_APIC_clock(void)
local_irq_enable();
}
-void __init setup_secondary_APIC_clock(void)
+void __devinit setup_secondary_APIC_clock(void)
{
setup_APIC_timer(calibration_result);
}
-void __init disable_APIC_timer(void)
+void __devinit disable_APIC_timer(void)
{
if (using_apic_timer) {
unsigned long v;
diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
index 0ff65abcd56c..064211d5f41b 100644
--- a/arch/i386/kernel/apm.c
+++ b/arch/i386/kernel/apm.c
@@ -228,10 +228,10 @@
#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/desc.h>
+#include <asm/i8253.h>
#include "io_ports.h"
-extern spinlock_t i8253_lock;
extern unsigned long get_cmos_time(void);
extern void machine_real_restart(unsigned char *, int);
@@ -346,10 +346,10 @@ extern int (*console_blank_hook)(int);
struct apm_user {
int magic;
struct apm_user * next;
- int suser: 1;
- int writer: 1;
- int reader: 1;
- int suspend_wait: 1;
+ unsigned int suser: 1;
+ unsigned int writer: 1;
+ unsigned int reader: 1;
+ unsigned int suspend_wait: 1;
int suspend_result;
int suspends_pending;
int standbys_pending;
@@ -1168,8 +1168,7 @@ static void get_time_diff(void)
static void reinit_timer(void)
{
#ifdef INIT_TIMER_AFTER_SUSPEND
- unsigned long flags;
- extern spinlock_t i8253_lock;
+ unsigned long flags;
spin_lock_irqsave(&i8253_lock, flags);
/* set the clock to 100 Hz */
diff --git a/arch/i386/kernel/cpu/common.c b/arch/i386/kernel/cpu/common.c
index b9954248d0aa..4553ffd94b1f 100644
--- a/arch/i386/kernel/cpu/common.c
+++ b/arch/i386/kernel/cpu/common.c
@@ -24,9 +24,9 @@ EXPORT_PER_CPU_SYMBOL(cpu_gdt_table);
DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]);
EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack);
-static int cachesize_override __initdata = -1;
-static int disable_x86_fxsr __initdata = 0;
-static int disable_x86_serial_nr __initdata = 1;
+static int cachesize_override __devinitdata = -1;
+static int disable_x86_fxsr __devinitdata = 0;
+static int disable_x86_serial_nr __devinitdata = 1;
struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {};
@@ -59,7 +59,7 @@ static int __init cachesize_setup(char *str)
}
__setup("cachesize=", cachesize_setup);
-int __init get_model_name(struct cpuinfo_x86 *c)
+int __devinit get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
char *p, *q;
@@ -89,7 +89,7 @@ int __init get_model_name(struct cpuinfo_x86 *c)
}
-void __init display_cacheinfo(struct cpuinfo_x86 *c)
+void __devinit display_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int n, dummy, ecx, edx, l2size;
@@ -130,7 +130,7 @@ void __init display_cacheinfo(struct cpuinfo_x86 *c)
/* in particular, if CPUID levels 0x80000002..4 are supported, this isn't used */
/* Look up CPU names by table lookup. */
-static char __init *table_lookup_model(struct cpuinfo_x86 *c)
+static char __devinit *table_lookup_model(struct cpuinfo_x86 *c)
{
struct cpu_model_info *info;
@@ -151,7 +151,7 @@ static char __init *table_lookup_model(struct cpuinfo_x86 *c)
}
-void __init get_cpu_vendor(struct cpuinfo_x86 *c, int early)
+void __devinit get_cpu_vendor(struct cpuinfo_x86 *c, int early)
{
char *v = c->x86_vendor_id;
int i;
@@ -202,7 +202,7 @@ static inline int flag_is_changeable_p(u32 flag)
/* Probe for the CPUID instruction */
-static int __init have_cpuid_p(void)
+static int __devinit have_cpuid_p(void)
{
return flag_is_changeable_p(X86_EFLAGS_ID);
}
@@ -249,7 +249,7 @@ static void __init early_cpu_detect(void)
#endif
}
-void __init generic_identify(struct cpuinfo_x86 * c)
+void __devinit generic_identify(struct cpuinfo_x86 * c)
{
u32 tfms, xlvl;
int junk;
@@ -296,7 +296,7 @@ void __init generic_identify(struct cpuinfo_x86 * c)
}
}
-static void __init squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
+static void __devinit squash_the_stupid_serial_number(struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_PN) && disable_x86_serial_nr ) {
/* Disable processor serial number */
@@ -324,7 +324,7 @@ __setup("serialnumber", x86_serial_nr_setup);
/*
* This does the hard work of actually picking apart the CPU stuff...
*/
-void __init identify_cpu(struct cpuinfo_x86 *c)
+void __devinit identify_cpu(struct cpuinfo_x86 *c)
{
int i;
@@ -432,10 +432,18 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
#ifdef CONFIG_X86_MCE
mcheck_init(c);
#endif
+ if (c == &boot_cpu_data)
+ sysenter_setup();
+ enable_sep_cpu();
+
+ if (c == &boot_cpu_data)
+ mtrr_bp_init();
+ else
+ mtrr_ap_init();
}
#ifdef CONFIG_X86_HT
-void __init detect_ht(struct cpuinfo_x86 *c)
+void __devinit detect_ht(struct cpuinfo_x86 *c)
{
u32 eax, ebx, ecx, edx;
int index_msb, tmp;
@@ -490,7 +498,7 @@ void __init detect_ht(struct cpuinfo_x86 *c)
}
#endif
-void __init print_cpu_info(struct cpuinfo_x86 *c)
+void __devinit print_cpu_info(struct cpuinfo_x86 *c)
{
char *vendor = NULL;
@@ -513,7 +521,7 @@ void __init print_cpu_info(struct cpuinfo_x86 *c)
printk("\n");
}
-cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+cpumask_t cpu_initialized __devinitdata = CPU_MASK_NONE;
/* This is hacky. :)
* We're emulating future behavior.
@@ -560,7 +568,7 @@ void __init early_cpu_init(void)
* and IDT. We reload them nevertheless, this function acts as a
* 'CPU state barrier', nothing should get across.
*/
-void __init cpu_init (void)
+void __devinit cpu_init(void)
{
int cpu = smp_processor_id();
struct tss_struct * t = &per_cpu(init_tss, cpu);
@@ -648,3 +656,15 @@ void __init cpu_init (void)
clear_used_math();
mxcsr_feature_mask_init();
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+void __devinit cpu_uninit(void)
+{
+ int cpu = raw_smp_processor_id();
+ cpu_clear(cpu, cpu_initialized);
+
+ /* lazy TLB state */
+ per_cpu(cpu_tlbstate, cpu).state = 0;
+ per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
+}
+#endif
diff --git a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
index 1a49adb1f4a6..e86ea486c311 100644
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
@@ -190,7 +190,7 @@ static __init struct pci_dev *gx_detect_chipset(void)
/* detect which companion chip is used */
while ((gx_pci = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) {
- if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) {
+ if ((pci_match_id(gx_chipset_tbl, gx_pci)) != NULL) {
return gx_pci;
}
}
diff --git a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
index 5c530064eb74..73a5dc5b26b8 100644
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
@@ -648,9 +648,7 @@ static int powernow_cpu_exit (struct cpufreq_policy *policy) {
}
#endif
- if (powernow_table)
- kfree(powernow_table);
-
+ kfree(powernow_table);
return 0;
}
diff --git a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
index 7dcbf70fc16f..327a55d4d1c6 100644
--- a/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
+++ b/arch/i386/kernel/cpu/cpufreq/speedstep-centrino.c
@@ -375,7 +375,7 @@ 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_EST_CAPABILITY_SMP | ACPI_PDC_EST_CAPABILITY_MSR;
+ arg0_buf[2] = ACPI_PDC_EST_CAPABILITY_SMP_MSR;
p.pdc = &arg_list;
diff --git a/arch/i386/kernel/cpu/intel.c b/arch/i386/kernel/cpu/intel.c
index 121aa2176e69..a2c33c1a46c5 100644
--- a/arch/i386/kernel/cpu/intel.c
+++ b/arch/i386/kernel/cpu/intel.c
@@ -25,10 +25,10 @@ extern int trap_init_f00f_bug(void);
/*
* Alignment at which movsl is preferred for bulk memory copies.
*/
-struct movsl_mask movsl_mask;
+struct movsl_mask movsl_mask __read_mostly;
#endif
-void __init early_intel_workaround(struct cpuinfo_x86 *c)
+void __devinit early_intel_workaround(struct cpuinfo_x86 *c)
{
if (c->x86_vendor != X86_VENDOR_INTEL)
return;
@@ -43,7 +43,7 @@ void __init early_intel_workaround(struct cpuinfo_x86 *c)
* This is called before we do cpu ident work
*/
-int __init ppro_with_ram_bug(void)
+int __devinit ppro_with_ram_bug(void)
{
/* Uses data from early_cpu_detect now */
if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
@@ -61,7 +61,7 @@ int __init ppro_with_ram_bug(void)
* P4 Xeon errata 037 workaround.
* Hardware prefetcher may cause stale data to be loaded into the cache.
*/
-static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
+static void __devinit Intel_errata_workarounds(struct cpuinfo_x86 *c)
{
unsigned long lo, hi;
@@ -80,7 +80,7 @@ static void __init Intel_errata_workarounds(struct cpuinfo_x86 *c)
/*
* find out the number of processor cores on the die
*/
-static int __init num_cpu_cores(struct cpuinfo_x86 *c)
+static int __devinit num_cpu_cores(struct cpuinfo_x86 *c)
{
unsigned int eax;
@@ -98,7 +98,7 @@ static int __init num_cpu_cores(struct cpuinfo_x86 *c)
return 1;
}
-static void __init init_intel(struct cpuinfo_x86 *c)
+static void __devinit init_intel(struct cpuinfo_x86 *c)
{
unsigned int l2 = 0;
char *p = NULL;
@@ -204,7 +204,7 @@ static unsigned int intel_size_cache(struct cpuinfo_x86 * c, unsigned int size)
return size;
}
-static struct cpu_dev intel_cpu_dev __initdata = {
+static struct cpu_dev intel_cpu_dev __devinitdata = {
.c_vendor = "Intel",
.c_ident = { "GenuineIntel" },
.c_models = {
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index a710dc4eb20e..1d768b263269 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -28,7 +28,7 @@ struct _cache_table
};
/* all the cache descriptor types we care about (no TLB or trace cache entries) */
-static struct _cache_table cache_table[] __initdata =
+static struct _cache_table cache_table[] __devinitdata =
{
{ 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */
{ 0x08, LVL_1_INST, 16 }, /* 4-way set assoc, 32 byte line size */
@@ -160,7 +160,7 @@ static int __init find_num_cache_leaves(void)
return retval;
}
-unsigned int __init init_intel_cacheinfo(struct cpuinfo_x86 *c)
+unsigned int __devinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
diff --git a/arch/i386/kernel/cpu/mcheck/k7.c b/arch/i386/kernel/cpu/mcheck/k7.c
index 8df52e86c4d2..c4abe7657397 100644
--- a/arch/i386/kernel/cpu/mcheck/k7.c
+++ b/arch/i386/kernel/cpu/mcheck/k7.c
@@ -69,7 +69,7 @@ static fastcall void k7_machine_check(struct pt_regs * regs, long error_code)
/* AMD K7 machine check is Intel like */
-void __init amd_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit amd_mcheck_init(struct cpuinfo_x86 *c)
{
u32 l, h;
int i;
diff --git a/arch/i386/kernel/cpu/mcheck/mce.c b/arch/i386/kernel/cpu/mcheck/mce.c
index bf6d1aefafc0..2cf25d2ba0f1 100644
--- a/arch/i386/kernel/cpu/mcheck/mce.c
+++ b/arch/i386/kernel/cpu/mcheck/mce.c
@@ -16,7 +16,7 @@
#include "mce.h"
-int mce_disabled __initdata = 0;
+int mce_disabled __devinitdata = 0;
int nr_mce_banks;
EXPORT_SYMBOL_GPL(nr_mce_banks); /* non-fatal.o */
@@ -31,7 +31,7 @@ static fastcall void unexpected_machine_check(struct pt_regs * regs, long error_
void fastcall (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
/* This has to be run for each processor */
-void __init mcheck_init(struct cpuinfo_x86 *c)
+void __devinit mcheck_init(struct cpuinfo_x86 *c)
{
if (mce_disabled==1)
return;
diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c
index 8b16ceb929b4..0abccb6fdf9e 100644
--- a/arch/i386/kernel/cpu/mcheck/p4.c
+++ b/arch/i386/kernel/cpu/mcheck/p4.c
@@ -78,7 +78,7 @@ fastcall void smp_thermal_interrupt(struct pt_regs *regs)
}
/* P4/Xeon Thermal regulation detect and init */
-static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+static void __devinit intel_init_thermal(struct cpuinfo_x86 *c)
{
u32 l, h;
unsigned int cpu = smp_processor_id();
@@ -232,7 +232,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
}
-void __init intel_p4_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p4_mcheck_init(struct cpuinfo_x86 *c)
{
u32 l, h;
int i;
diff --git a/arch/i386/kernel/cpu/mcheck/p5.c b/arch/i386/kernel/cpu/mcheck/p5.c
index c45a1b485c80..ec0614cd2925 100644
--- a/arch/i386/kernel/cpu/mcheck/p5.c
+++ b/arch/i386/kernel/cpu/mcheck/p5.c
@@ -29,7 +29,7 @@ static fastcall void pentium_machine_check(struct pt_regs * regs, long error_cod
}
/* Set up machine check reporting for processors with Intel style MCE */
-void __init intel_p5_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p5_mcheck_init(struct cpuinfo_x86 *c)
{
u32 l, h;
diff --git a/arch/i386/kernel/cpu/mcheck/p6.c b/arch/i386/kernel/cpu/mcheck/p6.c
index 46640f8c2494..f01b73f947e1 100644
--- a/arch/i386/kernel/cpu/mcheck/p6.c
+++ b/arch/i386/kernel/cpu/mcheck/p6.c
@@ -80,7 +80,7 @@ static fastcall void intel_machine_check(struct pt_regs * regs, long error_code)
}
/* Set up machine check reporting for processors with Intel style MCE */
-void __init intel_p6_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit intel_p6_mcheck_init(struct cpuinfo_x86 *c)
{
u32 l, h;
int i;
diff --git a/arch/i386/kernel/cpu/mcheck/winchip.c b/arch/i386/kernel/cpu/mcheck/winchip.c
index 753fa7acb984..7bae68fa168f 100644
--- a/arch/i386/kernel/cpu/mcheck/winchip.c
+++ b/arch/i386/kernel/cpu/mcheck/winchip.c
@@ -23,7 +23,7 @@ static fastcall void winchip_machine_check(struct pt_regs * regs, long error_cod
}
/* Set up machine check reporting on the Winchip C6 series */
-void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
+void __devinit winchip_mcheck_init(struct cpuinfo_x86 *c)
{
u32 lo, hi;
machine_check_vector = winchip_machine_check;
diff --git a/arch/i386/kernel/cpu/mtrr/generic.c b/arch/i386/kernel/cpu/mtrr/generic.c
index f468a979e9aa..169ac8e0db68 100644
--- a/arch/i386/kernel/cpu/mtrr/generic.c
+++ b/arch/i386/kernel/cpu/mtrr/generic.c
@@ -67,14 +67,6 @@ void __init get_mtrr_state(void)
mtrr_state.enabled = (lo & 0xc00) >> 10;
}
-/* Free resources associated with a struct mtrr_state */
-void __init finalize_mtrr_state(void)
-{
- if (mtrr_state.var_ranges)
- kfree(mtrr_state.var_ranges);
- mtrr_state.var_ranges = NULL;
-}
-
/* Some BIOS's are fucked and don't set all MTRRs the same! */
void __init mtrr_state_warn(void)
{
@@ -335,6 +327,9 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
*/
{
unsigned long flags;
+ struct mtrr_var_range *vr;
+
+ vr = &mtrr_state.var_ranges[reg];
local_irq_save(flags);
prepare_set();
@@ -343,11 +338,15 @@ static void generic_set_mtrr(unsigned int reg, unsigned long base,
/* The invalid bit is kept in the mask, so we simply clear the
relevant mask register to disable a range. */
mtrr_wrmsr(MTRRphysMask_MSR(reg), 0, 0);
+ memset(vr, 0, sizeof(struct mtrr_var_range));
} else {
- mtrr_wrmsr(MTRRphysBase_MSR(reg), base << PAGE_SHIFT | type,
- (base & size_and_mask) >> (32 - PAGE_SHIFT));
- mtrr_wrmsr(MTRRphysMask_MSR(reg), -size << PAGE_SHIFT | 0x800,
- (-size & size_and_mask) >> (32 - PAGE_SHIFT));
+ vr->base_lo = base << PAGE_SHIFT | type;
+ vr->base_hi = (base & size_and_mask) >> (32 - PAGE_SHIFT);
+ vr->mask_lo = -size << PAGE_SHIFT | 0x800;
+ vr->mask_hi = (-size & size_and_mask) >> (32 - PAGE_SHIFT);
+
+ mtrr_wrmsr(MTRRphysBase_MSR(reg), vr->base_lo, vr->base_hi);
+ mtrr_wrmsr(MTRRphysMask_MSR(reg), vr->mask_lo, vr->mask_hi);
}
post_set();
diff --git a/arch/i386/kernel/cpu/mtrr/main.c b/arch/i386/kernel/cpu/mtrr/main.c
index d66b09e0c820..764cac64e211 100644
--- a/arch/i386/kernel/cpu/mtrr/main.c
+++ b/arch/i386/kernel/cpu/mtrr/main.c
@@ -332,6 +332,8 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = -EINVAL;
+ /* No CPU hotplug when we change MTRR entries */
+ lock_cpu_hotplug();
/* Search for existing MTRR */
down(&main_lock);
for (i = 0; i < num_var_ranges; ++i) {
@@ -372,6 +374,7 @@ int mtrr_add_page(unsigned long base, unsigned long size,
error = i;
out:
up(&main_lock);
+ unlock_cpu_hotplug();
return error;
}
@@ -461,6 +464,8 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
return -ENXIO;
max = num_var_ranges;
+ /* No CPU hotplug when we change MTRR entries */
+ lock_cpu_hotplug();
down(&main_lock);
if (reg < 0) {
/* Search for existing MTRR */
@@ -501,6 +506,7 @@ int mtrr_del_page(int reg, unsigned long base, unsigned long size)
error = reg;
out:
up(&main_lock);
+ unlock_cpu_hotplug();
return error;
}
/**
@@ -544,21 +550,9 @@ static void __init init_ifs(void)
centaur_init_mtrr();
}
-static void __init init_other_cpus(void)
-{
- if (use_intel())
- get_mtrr_state();
-
- /* bring up the other processors */
- set_mtrr(~0U,0,0,0);
-
- if (use_intel()) {
- finalize_mtrr_state();
- mtrr_state_warn();
- }
-}
-
-
+/* The suspend/resume methods are only for CPU without MTRR. CPU using generic
+ * MTRR driver doesn't require this
+ */
struct mtrr_value {
mtrr_type ltype;
unsigned long lbase;
@@ -611,13 +605,13 @@ static struct sysdev_driver mtrr_sysdev_driver = {
/**
- * mtrr_init - initialize mtrrs on the boot CPU
+ * mtrr_bp_init - initialize mtrrs on the boot CPU
*
* This needs to be called early; before any of the other CPUs are
* initialized (i.e. before smp_init()).
*
*/
-static int __init mtrr_init(void)
+void __init mtrr_bp_init(void)
{
init_ifs();
@@ -674,12 +668,48 @@ static int __init mtrr_init(void)
if (mtrr_if) {
set_num_var_ranges();
init_table();
- init_other_cpus();
-
- return sysdev_driver_register(&cpu_sysdev_class,
- &mtrr_sysdev_driver);
+ if (use_intel())
+ get_mtrr_state();
}
- return -ENXIO;
}
-subsys_initcall(mtrr_init);
+void mtrr_ap_init(void)
+{
+ unsigned long flags;
+
+ if (!mtrr_if || !use_intel())
+ return;
+ /*
+ * Ideally we should hold main_lock here to avoid mtrr entries changed,
+ * but this routine will be called in cpu boot time, holding the lock
+ * breaks it. This routine is called in two cases: 1.very earily time
+ * of software resume, when there absolutely isn't mtrr entry changes;
+ * 2.cpu hotadd time. We let mtrr_add/del_page hold cpuhotplug lock to
+ * prevent mtrr entry changes
+ */
+ local_irq_save(flags);
+
+ mtrr_if->set_all();
+
+ local_irq_restore(flags);
+}
+
+static int __init mtrr_init_finialize(void)
+{
+ if (!mtrr_if)
+ return 0;
+ if (use_intel())
+ mtrr_state_warn();
+ else {
+ /* The CPUs haven't MTRR and seemes not support SMP. They have
+ * specific drivers, we use a tricky method to support
+ * suspend/resume for them.
+ * TBD: is there any system with such CPU which supports
+ * suspend/resume? if no, we should remove the code.
+ */
+ sysdev_driver_register(&cpu_sysdev_class,
+ &mtrr_sysdev_driver);
+ }
+ return 0;
+}
+subsys_initcall(mtrr_init_finialize);
diff --git a/arch/i386/kernel/cpu/mtrr/mtrr.h b/arch/i386/kernel/cpu/mtrr/mtrr.h
index de1351245599..99c9f2682041 100644
--- a/arch/i386/kernel/cpu/mtrr/mtrr.h
+++ b/arch/i386/kernel/cpu/mtrr/mtrr.h
@@ -91,7 +91,6 @@ extern struct mtrr_ops * mtrr_if;
extern unsigned int num_var_ranges;
-void finalize_mtrr_state(void);
void mtrr_state_warn(void);
char *mtrr_attrib_to_str(int x);
void mtrr_wrmsr(unsigned, unsigned, unsigned);
diff --git a/arch/i386/kernel/crash.c b/arch/i386/kernel/crash.c
new file mode 100644
index 000000000000..e5fab12f7926
--- /dev/null
+++ b/arch/i386/kernel/crash.c
@@ -0,0 +1,223 @@
+/*
+ * Architecture specific (i386) functions for kexec based crash dumps.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2004. All rights reserved.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <asm/nmi.h>
+#include <asm/hw_irq.h>
+#include <asm/apic.h>
+#include <mach_ipi.h>
+
+
+note_buf_t crash_notes[NR_CPUS];
+/* This keeps a track of which one is crashing cpu. */
+static int crashing_cpu;
+
+static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
+ size_t data_len)
+{
+ struct elf_note note;
+
+ note.n_namesz = strlen(name) + 1;
+ note.n_descsz = data_len;
+ note.n_type = type;
+ memcpy(buf, &note, sizeof(note));
+ buf += (sizeof(note) +3)/4;
+ memcpy(buf, name, note.n_namesz);
+ buf += (note.n_namesz + 3)/4;
+ memcpy(buf, data, note.n_descsz);
+ buf += (note.n_descsz + 3)/4;
+
+ return buf;
+}
+
+static void final_note(u32 *buf)
+{
+ struct elf_note note;
+
+ note.n_namesz = 0;
+ note.n_descsz = 0;
+ note.n_type = 0;
+ memcpy(buf, &note, sizeof(note));
+}
+
+static void crash_save_this_cpu(struct pt_regs *regs, int cpu)
+{
+ struct elf_prstatus prstatus;
+ u32 *buf;
+
+ if ((cpu < 0) || (cpu >= NR_CPUS))
+ return;
+
+ /* Using ELF notes here is opportunistic.
+ * I need a well defined structure format
+ * for the data I pass, and I need tags
+ * on the data to indicate what information I have
+ * squirrelled away. ELF notes happen to provide
+ * all of that that no need to invent something new.
+ */
+ buf = &crash_notes[cpu][0];
+ memset(&prstatus, 0, sizeof(prstatus));
+ prstatus.pr_pid = current->pid;
+ elf_core_copy_regs(&prstatus.pr_reg, regs);
+ buf = append_elf_note(buf, "CORE", NT_PRSTATUS, &prstatus,
+ sizeof(prstatus));
+ final_note(buf);
+}
+
+static void crash_get_current_regs(struct pt_regs *regs)
+{
+ __asm__ __volatile__("movl %%ebx,%0" : "=m"(regs->ebx));
+ __asm__ __volatile__("movl %%ecx,%0" : "=m"(regs->ecx));
+ __asm__ __volatile__("movl %%edx,%0" : "=m"(regs->edx));
+ __asm__ __volatile__("movl %%esi,%0" : "=m"(regs->esi));
+ __asm__ __volatile__("movl %%edi,%0" : "=m"(regs->edi));
+ __asm__ __volatile__("movl %%ebp,%0" : "=m"(regs->ebp));
+ __asm__ __volatile__("movl %%eax,%0" : "=m"(regs->eax));
+ __asm__ __volatile__("movl %%esp,%0" : "=m"(regs->esp));
+ __asm__ __volatile__("movw %%ss, %%ax;" :"=a"(regs->xss));
+ __asm__ __volatile__("movw %%cs, %%ax;" :"=a"(regs->xcs));
+ __asm__ __volatile__("movw %%ds, %%ax;" :"=a"(regs->xds));
+ __asm__ __volatile__("movw %%es, %%ax;" :"=a"(regs->xes));
+ __asm__ __volatile__("pushfl; popl %0" :"=m"(regs->eflags));
+
+ regs->eip = (unsigned long)current_text_addr();
+}
+
+/* CPU does not save ss and esp on stack if execution is already
+ * running in kernel mode at the time of NMI occurrence. This code
+ * fixes it.
+ */
+static void crash_setup_regs(struct pt_regs *newregs, struct pt_regs *oldregs)
+{
+ memcpy(newregs, oldregs, sizeof(*newregs));
+ newregs->esp = (unsigned long)&(oldregs->esp);
+ __asm__ __volatile__("xorl %eax, %eax;");
+ __asm__ __volatile__ ("movw %%ss, %%ax;" :"=a"(newregs->xss));
+}
+
+/* We may have saved_regs from where the error came from
+ * or it is NULL if via a direct panic().
+ */
+static void crash_save_self(struct pt_regs *saved_regs)
+{
+ struct pt_regs regs;
+ int cpu;
+
+ cpu = smp_processor_id();
+ if (saved_regs)
+ crash_setup_regs(&regs, saved_regs);
+ else
+ crash_get_current_regs(&regs);
+ crash_save_this_cpu(&regs, cpu);
+}
+
+#ifdef CONFIG_SMP
+static atomic_t waiting_for_crash_ipi;
+
+static int crash_nmi_callback(struct pt_regs *regs, int cpu)
+{
+ struct pt_regs fixed_regs;
+
+ /* Don't do anything if this handler is invoked on crashing cpu.
+ * Otherwise, system will completely hang. Crashing cpu can get
+ * an NMI if system was initially booted with nmi_watchdog parameter.
+ */
+ if (cpu == crashing_cpu)
+ return 1;
+ local_irq_disable();
+
+ if (!user_mode(regs)) {
+ crash_setup_regs(&fixed_regs, regs);
+ regs = &fixed_regs;
+ }
+ crash_save_this_cpu(regs, cpu);
+ disable_local_APIC();
+ atomic_dec(&waiting_for_crash_ipi);
+ /* Assume hlt works */
+ __asm__("hlt");
+ for(;;);
+
+ return 1;
+}
+
+/*
+ * By using the NMI code instead of a vector we just sneak thru the
+ * word generator coming out with just what we want. AND it does
+ * not matter if clustered_apic_mode is set or not.
+ */
+static void smp_send_nmi_allbutself(void)
+{
+ send_IPI_allbutself(APIC_DM_NMI);
+}
+
+static void nmi_shootdown_cpus(void)
+{
+ unsigned long msecs;
+
+ atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
+ /* Would it be better to replace the trap vector here? */
+ set_nmi_callback(crash_nmi_callback);
+ /* Ensure the new callback function is set before sending
+ * out the NMI
+ */
+ wmb();
+
+ smp_send_nmi_allbutself();
+
+ msecs = 1000; /* Wait at most a second for the other cpus to stop */
+ while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
+ mdelay(1);
+ msecs--;
+ }
+
+ /* Leave the nmi callback set */
+ disable_local_APIC();
+}
+#else
+static void nmi_shootdown_cpus(void)
+{
+ /* There are no cpus to shootdown */
+}
+#endif
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* This function is only called after the system
+ * has paniced or is otherwise in a critical state.
+ * The minimum amount of code to allow a kexec'd kernel
+ * to run successfully needs to happen here.
+ *
+ * In practice this means shooting down the other cpus in
+ * an SMP system.
+ */
+ /* The kernel is broken so disable interrupts */
+ local_irq_disable();
+
+ /* Make a note of crashing cpu. Will be used in NMI callback.*/
+ crashing_cpu = smp_processor_id();
+ nmi_shootdown_cpus();
+ lapic_shutdown();
+#if defined(CONFIG_X86_IO_APIC)
+ disable_IO_APIC();
+#endif
+ crash_save_self(regs);
+}
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
index 6ed7e28f306c..a3cdf894302b 100644
--- a/arch/i386/kernel/dmi_scan.c
+++ b/arch/i386/kernel/dmi_scan.c
@@ -1,22 +1,15 @@
#include <linux/types.h>
-#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/acpi.h>
-#include <asm/io.h>
-#include <linux/pm.h>
-#include <asm/system.h>
#include <linux/dmi.h>
#include <linux/bootmem.h>
-struct dmi_header
-{
- u8 type;
- u8 length;
- u16 handle;
+struct dmi_header {
+ u8 type;
+ u8 length;
+ u16 handle;
};
#undef DMI_DEBUG
@@ -29,15 +22,13 @@ struct dmi_header
static char * __init dmi_string(struct dmi_header *dm, u8 s)
{
- u8 *bp=(u8 *)dm;
- bp+=dm->length;
- if(!s)
+ u8 *bp = ((u8 *) dm) + dm->length;
+
+ if (!s)
return "";
s--;
- while(s>0 && *bp)
- {
- bp+=strlen(bp);
- bp++;
+ while (s > 0 && *bp) {
+ bp += strlen(bp) + 1;
s--;
}
return bp;
@@ -47,16 +38,14 @@ static char * __init dmi_string(struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-
-static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
+static int __init dmi_table(u32 base, int len, int num,
+ void (*decode)(struct dmi_header *))
{
- u8 *buf;
- struct dmi_header *dm;
- u8 *data;
- int i=0;
+ u8 *buf, *data;
+ int i = 0;
buf = bt_ioremap(base, len);
- if(buf==NULL)
+ if (buf == NULL)
return -1;
data = buf;
@@ -65,36 +54,34 @@ static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dm
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
*/
-
- while(i<num && data-buf+sizeof(struct dmi_header)<=len)
- {
- dm=(struct dmi_header *)data;
+ while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) {
+ struct dmi_header *dm = (struct dmi_header *)data;
/*
* We want to know the total length (formated area and strings)
* before decoding to make sure we won't run off the table in
* dmi_decode or dmi_string
*/
- data+=dm->length;
- while(data-buf<len-1 && (data[0] || data[1]))
+ data += dm->length;
+ while ((data - buf < len - 1) && (data[0] || data[1]))
data++;
- if(data-buf<len-1)
+ if (data - buf < len - 1)
decode(dm);
- data+=2;
+ data += 2;
i++;
}
bt_iounmap(buf, len);
return 0;
}
-
-inline static int __init dmi_checksum(u8 *buf)
+static int __init dmi_checksum(u8 *buf)
{
- u8 sum=0;
+ u8 sum = 0;
int a;
- for(a=0; a<15; a++)
- sum+=buf[a];
- return (sum==0);
+ for (a = 0; a < 15; a++)
+ sum += buf[a];
+
+ return sum == 0;
}
static int __init dmi_iterate(void (*decode)(struct dmi_header *))
@@ -110,28 +97,30 @@ static int __init dmi_iterate(void (*decode)(struct dmi_header *))
p = ioremap(0xF0000, 0x10000);
if (p == NULL)
return -1;
+
for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(buf, q, 15);
- if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf))
- {
- u16 num=buf[13]<<8|buf[12];
- u16 len=buf[7]<<8|buf[6];
- u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8];
+ if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
+ u16 num = (buf[13] << 8) | buf[12];
+ u16 len = (buf[7] << 8) | buf[6];
+ u32 base = (buf[11] << 24) | (buf[10] << 16) |
+ (buf[9] << 8) | buf[8];
/*
* DMI version 0.0 means that the real version is taken from
* the SMBIOS version, which we don't know at this point.
*/
- if(buf[14]!=0)
+ if (buf[14] != 0)
printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14]>>4, buf[14]&0x0F);
+ buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
+
dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
num, len));
- dmi_printk((KERN_INFO "DMI table at 0x%08X.\n",
- base));
- if(dmi_table(base,len, num, decode)==0)
+ dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+
+ if (dmi_table(base,len, num, decode) == 0)
return 0;
}
}
@@ -143,16 +132,17 @@ static char *dmi_ident[DMI_STRING_MAX];
/*
* Save a DMI string
*/
-
static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
{
char *d = (char*)dm;
char *p = dmi_string(dm, d[string]);
- if(p==NULL || *p == 0)
+
+ if (p == NULL || *p == 0)
return;
if (dmi_ident[slot])
return;
- dmi_ident[slot] = alloc_bootmem(strlen(p)+1);
+
+ dmi_ident[slot] = alloc_bootmem(strlen(p) + 1);
if(dmi_ident[slot])
strcpy(dmi_ident[slot], p);
else
@@ -160,281 +150,47 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
}
/*
- * Ugly compatibility crap.
- */
-#define dmi_blacklist dmi_system_id
-#define NO_MATCH { DMI_NONE, NULL}
-#define MATCH DMI_MATCH
-
-/*
- * Toshiba keyboard likes to repeat keys when they are not repeated.
- */
-
-static __init int broken_toshiba_keyboard(struct dmi_blacklist *d)
-{
- printk(KERN_WARNING "Toshiba with broken keyboard detected. If your keyboard sometimes generates 3 keypresses instead of one, see http://davyd.ucc.asn.au/projects/toshiba/README\n");
- return 0;
-}
-
-
-#ifdef CONFIG_ACPI_SLEEP
-static __init int reset_videomode_after_s3(struct dmi_blacklist *d)
-{
- /* See acpi_wakeup.S */
- extern long acpi_video_flags;
- acpi_video_flags |= 2;
- return 0;
-}
-#endif
-
-
-#ifdef CONFIG_ACPI_BOOT
-extern int acpi_force;
-
-static __init __attribute__((unused)) int dmi_disable_acpi(struct dmi_blacklist *d)
-{
- if (!acpi_force) {
- printk(KERN_NOTICE "%s detected: acpi off\n",d->ident);
- disable_acpi();
- } else {
- printk(KERN_NOTICE
- "Warning: DMI blacklist says broken, but acpi forced\n");
- }
- return 0;
-}
-
-/*
- * Limit ACPI to CPU enumeration for HT
- */
-static __init __attribute__((unused)) int force_acpi_ht(struct dmi_blacklist *d)
-{
- if (!acpi_force) {
- printk(KERN_NOTICE "%s detected: force use of acpi=ht\n", d->ident);
- disable_acpi();
- acpi_ht = 1;
- } else {
- printk(KERN_NOTICE
- "Warning: acpi=force overrules DMI blacklist: acpi=ht\n");
- }
- return 0;
-}
-#endif
-
-#ifdef CONFIG_ACPI_PCI
-static __init int disable_acpi_irq(struct dmi_blacklist *d)
-{
- if (!acpi_force) {
- printk(KERN_NOTICE "%s detected: force use of acpi=noirq\n",
- d->ident);
- acpi_noirq_set();
- }
- return 0;
-}
-static __init int disable_acpi_pci(struct dmi_blacklist *d)
-{
- if (!acpi_force) {
- printk(KERN_NOTICE "%s detected: force use of pci=noacpi\n",
- d->ident);
- acpi_disable_pci();
- }
- return 0;
-}
-#endif
-
-/*
- * Process the DMI blacklists
- */
-
-
-/*
- * This will be expanded over time to force things like the APM
- * interrupt mask settings according to the laptop
- */
-
-static __initdata struct dmi_blacklist dmi_blacklist[]={
-
- { broken_toshiba_keyboard, "Toshiba Satellite 4030cdt", { /* Keyboard generates spurious repeats */
- MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
- NO_MATCH, NO_MATCH, NO_MATCH
- } },
-#ifdef CONFIG_ACPI_SLEEP
- { reset_videomode_after_s3, "Toshiba Satellite 4030cdt", { /* Reset video mode after returning from ACPI S3 sleep */
- MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),
- NO_MATCH, NO_MATCH, NO_MATCH
- } },
-#endif
-
-#ifdef CONFIG_ACPI_BOOT
- /*
- * If your system is blacklisted here, but you find that acpi=force
- * works for you, please contact acpi-devel@sourceforge.net
- */
-
- /*
- * Boxes that need ACPI disabled
- */
-
- { dmi_disable_acpi, "IBM Thinkpad", {
- MATCH(DMI_BOARD_VENDOR, "IBM"),
- MATCH(DMI_BOARD_NAME, "2629H1G"),
- NO_MATCH, NO_MATCH }},
-
- /*
- * Boxes that need acpi=ht
- */
-
- { force_acpi_ht, "FSC Primergy T850", {
- MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
- MATCH(DMI_PRODUCT_NAME, "PRIMERGY T850"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "DELL GX240", {
- MATCH(DMI_BOARD_VENDOR, "Dell Computer Corporation"),
- MATCH(DMI_BOARD_NAME, "OptiPlex GX240"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "HP VISUALIZE NT Workstation", {
- MATCH(DMI_BOARD_VENDOR, "Hewlett-Packard"),
- MATCH(DMI_PRODUCT_NAME, "HP VISUALIZE NT Workstation"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "Compaq Workstation W8000", {
- MATCH(DMI_SYS_VENDOR, "Compaq"),
- MATCH(DMI_PRODUCT_NAME, "Workstation W8000"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "ASUS P4B266", {
- MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
- MATCH(DMI_BOARD_NAME, "P4B266"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "ASUS P2B-DS", {
- MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
- MATCH(DMI_BOARD_NAME, "P2B-DS"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "ASUS CUR-DLS", {
- MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
- MATCH(DMI_BOARD_NAME, "CUR-DLS"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "ABIT i440BX-W83977", {
- MATCH(DMI_BOARD_VENDOR, "ABIT <http://www.abit.com>"),
- MATCH(DMI_BOARD_NAME, "i440BX-W83977 (BP6)"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "IBM Bladecenter", {
- MATCH(DMI_BOARD_VENDOR, "IBM"),
- MATCH(DMI_BOARD_NAME, "IBM eServer BladeCenter HS20"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "IBM eServer xSeries 360", {
- MATCH(DMI_BOARD_VENDOR, "IBM"),
- MATCH(DMI_BOARD_NAME, "eServer xSeries 360"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "IBM eserver xSeries 330", {
- MATCH(DMI_BOARD_VENDOR, "IBM"),
- MATCH(DMI_BOARD_NAME, "eserver xSeries 330"),
- NO_MATCH, NO_MATCH }},
-
- { force_acpi_ht, "IBM eserver xSeries 440", {
- MATCH(DMI_BOARD_VENDOR, "IBM"),
- MATCH(DMI_PRODUCT_NAME, "eserver xSeries 440"),
- NO_MATCH, NO_MATCH }},
-
-#endif // CONFIG_ACPI_BOOT
-
-#ifdef CONFIG_ACPI_PCI
- /*
- * Boxes that need ACPI PCI IRQ routing disabled
- */
-
- { disable_acpi_irq, "ASUS A7V", {
- MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC"),
- MATCH(DMI_BOARD_NAME, "<A7V>"),
- /* newer BIOS, Revision 1011, does work */
- MATCH(DMI_BIOS_VERSION, "ASUS A7V ACPI BIOS Revision 1007"),
- NO_MATCH }},
-
- /*
- * Boxes that need ACPI PCI IRQ routing and PCI scan disabled
- */
- { disable_acpi_pci, "ASUS PR-DLS", { /* _BBN 0 bug */
- MATCH(DMI_BOARD_VENDOR, "ASUSTeK Computer INC."),
- MATCH(DMI_BOARD_NAME, "PR-DLS"),
- MATCH(DMI_BIOS_VERSION, "ASUS PR-DLS ACPI BIOS Revision 1010"),
- MATCH(DMI_BIOS_DATE, "03/21/2003") }},
-
- { disable_acpi_pci, "Acer TravelMate 36x Laptop", {
- MATCH(DMI_SYS_VENDOR, "Acer"),
- MATCH(DMI_PRODUCT_NAME, "TravelMate 360"),
- NO_MATCH, NO_MATCH
- } },
-
-#endif
-
- { NULL, }
-};
-
-/*
* Process a DMI table entry. Right now all we care about are the BIOS
* and machine entries. For 2.5 we should pull the smbus controller info
* out of here.
*/
-
static void __init dmi_decode(struct dmi_header *dm)
{
-#ifdef DMI_DEBUG
- u8 *data = (u8 *)dm;
-#endif
+ u8 *data __attribute__((__unused__)) = (u8 *)dm;
- switch(dm->type)
- {
- case 0:
- dmi_printk(("BIOS Vendor: %s\n",
- dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
- dmi_printk(("BIOS Version: %s\n",
- dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
- dmi_printk(("BIOS Release: %s\n",
- dmi_string(dm, data[8])));
- dmi_save_ident(dm, DMI_BIOS_DATE, 8);
- break;
- case 1:
- dmi_printk(("System Vendor: %s\n",
- dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
- dmi_printk(("Product Name: %s\n",
- dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
- dmi_printk(("Version: %s\n",
- dmi_string(dm, data[6])));
- dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
- dmi_printk(("Serial Number: %s\n",
- dmi_string(dm, data[7])));
- break;
- case 2:
- dmi_printk(("Board Vendor: %s\n",
- dmi_string(dm, data[4])));
- dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
- dmi_printk(("Board Name: %s\n",
- dmi_string(dm, data[5])));
- dmi_save_ident(dm, DMI_BOARD_NAME, 5);
- dmi_printk(("Board Version: %s\n",
- dmi_string(dm, data[6])));
- dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
- break;
+ switch(dm->type) {
+ case 0:
+ dmi_printk(("BIOS Vendor: %s\n", dmi_string(dm, data[4])));
+ dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
+ dmi_printk(("BIOS Version: %s\n", dmi_string(dm, data[5])));
+ dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
+ dmi_printk(("BIOS Release: %s\n", dmi_string(dm, data[8])));
+ dmi_save_ident(dm, DMI_BIOS_DATE, 8);
+ break;
+ case 1:
+ dmi_printk(("System Vendor: %s\n", dmi_string(dm, data[4])));
+ dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
+ dmi_printk(("Product Name: %s\n", dmi_string(dm, data[5])));
+ dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
+ dmi_printk(("Version: %s\n", dmi_string(dm, data[6])));
+ dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
+ dmi_printk(("Serial Number: %s\n", dmi_string(dm, data[7])));
+ dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
+ break;
+ case 2:
+ dmi_printk(("Board Vendor: %s\n", dmi_string(dm, data[4])));
+ dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
+ dmi_printk(("Board Name: %s\n", dmi_string(dm, data[5])));
+ dmi_save_ident(dm, DMI_BOARD_NAME, 5);
+ dmi_printk(("Board Version: %s\n", dmi_string(dm, data[6])));
+ dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
+ break;
}
}
void __init dmi_scan_machine(void)
{
- int err = dmi_iterate(dmi_decode);
- if(err == 0)
- dmi_check_system(dmi_blacklist);
- else
+ if (dmi_iterate(dmi_decode))
printk(KERN_INFO "DMI not present.\n");
}
@@ -470,7 +226,6 @@ fail: d++;
return count;
}
-
EXPORT_SYMBOL(dmi_check_system);
/**
@@ -480,8 +235,8 @@ EXPORT_SYMBOL(dmi_check_system);
* Returns one DMI data value, can be used to perform
* complex DMI data checks.
*/
-char * dmi_get_system_info(int field)
+char *dmi_get_system_info(int field)
{
return dmi_ident[field];
}
-
+EXPORT_SYMBOL(dmi_get_system_info);
diff --git a/arch/i386/kernel/efi.c b/arch/i386/kernel/efi.c
index f732f427b418..385883ea8c19 100644
--- a/arch/i386/kernel/efi.c
+++ b/arch/i386/kernel/efi.c
@@ -30,6 +30,7 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/efi.h>
+#include <linux/kexec.h>
#include <asm/setup.h>
#include <asm/io.h>
@@ -598,6 +599,9 @@ efi_initialize_iomem_resources(struct resource *code_resource,
if (md->type == EFI_CONVENTIONAL_MEMORY) {
request_resource(res, code_resource);
request_resource(res, data_resource);
+#ifdef CONFIG_KEXEC
+ request_resource(res, &crashk_res);
+#endif
}
}
}
diff --git a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
index e966fc8c44c4..4477bb107098 100644
--- a/arch/i386/kernel/head.S
+++ b/arch/i386/kernel/head.S
@@ -299,7 +299,6 @@ is386: movl $2,%ecx # set MP
movl %eax,%cr0
call check_x87
- incb ready
lgdt cpu_gdt_descr
lidt idt_descr
ljmp $(__KERNEL_CS),$1f
@@ -316,8 +315,9 @@ is386: movl $2,%ecx # set MP
lldt %ax
cld # gcc2 wants the direction flag cleared at all times
#ifdef CONFIG_SMP
- movb ready, %cl
- cmpb $1,%cl
+ movb ready, %cl
+ movb $1, ready
+ cmpb $0,%cl
je 1f # the first CPU calls start_kernel
# all other CPUs call initialize_secondary
call initialize_secondary
diff --git a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
index 2c4813b47e57..178f4e9bac9d 100644
--- a/arch/i386/kernel/i8259.c
+++ b/arch/i386/kernel/i8259.c
@@ -268,10 +268,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
+static int i8259A_shutdown(struct sys_device *dev)
+{
+ /* Put the i8259A into a quiescent state that
+ * the kernel initialization code can get it
+ * out of.
+ */
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xA1); /* mask all of 8259A-1 */
+ return 0;
+}
+
static struct sysdev_class i8259_sysdev_class = {
set_kset_name("i8259"),
.suspend = i8259A_suspend,
.resume = i8259A_resume,
+ .shutdown = i8259A_shutdown,
};
static struct sys_device device_i8259A = {
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
index 08540bc4ba3e..6578f40bd501 100644
--- a/arch/i386/kernel/io_apic.c
+++ b/arch/i386/kernel/io_apic.c
@@ -37,6 +37,7 @@
#include <asm/smp.h>
#include <asm/desc.h>
#include <asm/timer.h>
+#include <asm/i8259.h>
#include <mach_apic.h>
@@ -573,12 +574,14 @@ static int balanced_irq(void *unused)
for ( ; ; ) {
set_current_state(TASK_INTERRUPTIBLE);
time_remaining = schedule_timeout(time_remaining);
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
if (time_after(jiffies,
prev_balance_time+balanced_irq_interval)) {
+ preempt_disable();
do_irq_balance();
prev_balance_time = jiffies;
time_remaining = balanced_irq_interval;
+ preempt_enable();
}
}
return 0;
@@ -630,10 +633,8 @@ static int __init balanced_irq_init(void)
printk(KERN_ERR "balanced_irq_init: failed to spawn balanced_irq");
failed:
for (i = 0; i < NR_CPUS; i++) {
- if(irq_cpu_data[i].irq_delta)
- kfree(irq_cpu_data[i].irq_delta);
- if(irq_cpu_data[i].last_irq)
- kfree(irq_cpu_data[i].last_irq);
+ kfree(irq_cpu_data[i].irq_delta);
+ kfree(irq_cpu_data[i].last_irq);
}
return 0;
}
@@ -1566,7 +1567,6 @@ void print_all_local_APICs (void)
void /*__init*/ print_PIC(void)
{
- extern spinlock_t i8259A_lock;
unsigned int v;
unsigned long flags;
@@ -1634,12 +1634,43 @@ static void __init enable_IO_APIC(void)
*/
void disable_IO_APIC(void)
{
+ int pin;
/*
* Clear the IO-APIC before rebooting:
*/
clear_IO_APIC();
- disconnect_bsp_APIC();
+ /*
+ * If the i82559 is routed through an IOAPIC
+ * Put that IOAPIC in virtual wire mode
+ * so legacy interrups can be delivered.
+ */
+ pin = find_isa_irq_pin(0, mp_ExtINT);
+ if (pin != -1) {
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 0; /* Enabled */
+ entry.trigger = 0; /* Edge */
+ entry.irr = 0;
+ entry.polarity = 0; /* High */
+ entry.delivery_status = 0;
+ entry.dest_mode = 0; /* Physical */
+ entry.delivery_mode = 7; /* ExtInt */
+ entry.vector = 0;
+ entry.dest.physical.physical_dest = 0;
+
+
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+ disconnect_bsp_APIC(pin != -1);
}
/*
diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
index 73945a3c53c4..ce66dcc26d90 100644
--- a/arch/i386/kernel/irq.c
+++ b/arch/i386/kernel/irq.c
@@ -15,6 +15,9 @@
#include <linux/seq_file.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/delay.h>
DEFINE_PER_CPU(irq_cpustat_t, irq_stat) ____cacheline_maxaligned_in_smp;
EXPORT_PER_CPU_SYMBOL(irq_stat);
@@ -153,6 +156,11 @@ void irq_ctx_init(int cpu)
cpu,hardirq_ctx[cpu],softirq_ctx[cpu]);
}
+void irq_ctx_exit(int cpu)
+{
+ hardirq_ctx[cpu] = NULL;
+}
+
extern asmlinkage void __do_softirq(void);
asmlinkage void do_softirq(void)
@@ -210,9 +218,8 @@ int show_interrupts(struct seq_file *p, void *v)
if (i == 0) {
seq_printf(p, " ");
- for (j=0; j<NR_CPUS; j++)
- if (cpu_online(j))
- seq_printf(p, "CPU%d ",j);
+ for_each_cpu(j)
+ seq_printf(p, "CPU%d ",j);
seq_putc(p, '\n');
}
@@ -225,9 +232,8 @@ int show_interrupts(struct seq_file *p, void *v)
#ifndef CONFIG_SMP
seq_printf(p, "%10u ", kstat_irqs(i));
#else
- for (j = 0; j < NR_CPUS; j++)
- if (cpu_online(j))
- seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+ for_each_cpu(j)
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
#endif
seq_printf(p, " %14s", irq_desc[i].handler->typename);
seq_printf(p, " %s", action->name);
@@ -240,16 +246,14 @@ skip:
spin_unlock_irqrestore(&irq_desc[i].lock, flags);
} else if (i == NR_IRQS) {
seq_printf(p, "NMI: ");
- for (j = 0; j < NR_CPUS; j++)
- if (cpu_online(j))
- seq_printf(p, "%10u ", nmi_count(j));
+ for_each_cpu(j)
+ seq_printf(p, "%10u ", nmi_count(j));
seq_putc(p, '\n');
#ifdef CONFIG_X86_LOCAL_APIC
seq_printf(p, "LOC: ");
- for (j = 0; j < NR_CPUS; j++)
- if (cpu_online(j))
- seq_printf(p, "%10u ",
- per_cpu(irq_stat,j).apic_timer_irqs);
+ for_each_cpu(j)
+ seq_printf(p, "%10u ",
+ per_cpu(irq_stat,j).apic_timer_irqs);
seq_putc(p, '\n');
#endif
seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
@@ -259,3 +263,45 @@ skip:
}
return 0;
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+#include <mach_apic.h>
+
+void fixup_irqs(cpumask_t map)
+{
+ unsigned int irq;
+ static int warned;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ cpumask_t mask;
+ if (irq == 2)
+ continue;
+
+ cpus_and(mask, irq_affinity[irq], map);
+ if (any_online_cpu(mask) == NR_CPUS) {
+ printk("Breaking affinity for irq %i\n", irq);
+ mask = map;
+ }
+ if (irq_desc[irq].handler->set_affinity)
+ irq_desc[irq].handler->set_affinity(irq, mask);
+ else if (irq_desc[irq].action && !(warned++))
+ printk("Cannot set affinity for irq %i\n", irq);
+ }
+
+#if 0
+ barrier();
+ /* Ingo Molnar says: "after the IO-APIC masks have been redirected
+ [note the nop - the interrupt-enable boundary on x86 is two
+ instructions from sti] - to flush out pending hardirqs and
+ IPIs. After this point nothing is supposed to reach this CPU." */
+ __asm__ __volatile__("sti; nop; cli");
+ barrier();
+#else
+ /* That doesn't seem sufficient. Give it 1ms. */
+ local_irq_enable();
+ mdelay(1);
+ local_irq_disable();
+#endif
+}
+#endif
+
diff --git a/arch/i386/kernel/kprobes.c b/arch/i386/kernel/kprobes.c
index 3762f6b35ab2..a6d8c45961d3 100644
--- a/arch/i386/kernel/kprobes.c
+++ b/arch/i386/kernel/kprobes.c
@@ -127,48 +127,23 @@ static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
regs->eip = (unsigned long)&p->ainsn.insn;
}
-struct task_struct *arch_get_kprobe_task(void *ptr)
-{
- return ((struct thread_info *) (((unsigned long) ptr) &
- (~(THREAD_SIZE -1))))->task;
-}
-
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)&regs->esp;
- struct kretprobe_instance *ri;
- static void *orig_ret_addr;
+ struct kretprobe_instance *ri;
+
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
+ ri->ret_addr = (kprobe_opcode_t *) *sara;
- /*
- * Save the return address when the return probe hits
- * the first time, and use it to populate the (krprobe
- * instance)->ret_addr for subsequent return probes at
- * the same addrress since stack address would have
- * the kretprobe_trampoline by then.
- */
- if (((void*) *sara) != kretprobe_trampoline)
- orig_ret_addr = (void*) *sara;
-
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->stack_addr = sara;
- ri->ret_addr = orig_ret_addr;
- add_rp_inst(ri);
/* Replace the return addr with trampoline addr */
*sara = (unsigned long) &kretprobe_trampoline;
- } else {
- rp->nmissed++;
- }
-}
-void arch_kprobe_flush_task(struct task_struct *tk)
-{
- struct kretprobe_instance *ri;
- while ((ri = get_rp_inst_tsk(tk)) != NULL) {
- *((unsigned long *)(ri->stack_addr)) =
- (unsigned long) ri->ret_addr;
- recycle_rp_inst(ri);
- }
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
}
/*
@@ -286,36 +261,59 @@ no_kprobe:
*/
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
- struct task_struct *tsk;
- struct kretprobe_instance *ri;
- struct hlist_head *head;
- struct hlist_node *node;
- unsigned long *sara = ((unsigned long *) &regs->esp) - 1;
-
- tsk = arch_get_kprobe_task(sara);
- head = kretprobe_inst_table_head(tsk);
-
- hlist_for_each_entry(ri, node, head, hlist) {
- if (ri->stack_addr == sara && ri->rp) {
- if (ri->rp->handler)
- ri->rp->handler(ri, regs);
- }
- }
- return 0;
-}
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
+ unsigned long orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
-void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags)
-{
- struct kretprobe_instance *ri;
- /* RA already popped */
- unsigned long *sara = ((unsigned long *)&regs->esp) - 1;
+ head = kretprobe_inst_table_head(current);
- while ((ri = get_rp_inst(sara))) {
- regs->eip = (unsigned long)ri->ret_addr;
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
}
- regs->eflags &= ~TF_MASK;
+
+ BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ regs->eip = orig_ret_address;
+
+ unlock_kprobes();
+ preempt_enable_no_resched();
+
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we have handled unlocking
+ * and re-enabling preemption.
+ */
+ return 1;
}
/*
@@ -403,8 +401,7 @@ static inline int post_kprobe_handler(struct pt_regs *regs)
current_kprobe->post_handler(current_kprobe, regs, 0);
}
- if (current_kprobe->post_handler != trampoline_post_handler)
- resume_execution(current_kprobe, regs);
+ resume_execution(current_kprobe, regs);
regs->eflags |= kprobe_saved_eflags;
/*Restore back the original saved kprobes variables and continue. */
@@ -534,3 +531,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
}
return 0;
}
+
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ return register_kprobe(&trampoline_p);
+}
diff --git a/arch/i386/kernel/machine_kexec.c b/arch/i386/kernel/machine_kexec.c
new file mode 100644
index 000000000000..52ed18d8b511
--- /dev/null
+++ b/arch/i386/kernel/machine_kexec.c
@@ -0,0 +1,226 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/cpufeature.h>
+
+static inline unsigned long read_cr3(void)
+{
+ unsigned long cr3;
+ asm volatile("movl %%cr3,%0": "=r"(cr3));
+ return cr3;
+}
+
+#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
+
+#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L2_ATTR (_PAGE_PRESENT)
+
+#define LEVEL0_SIZE (1UL << 12UL)
+
+#ifndef CONFIG_X86_PAE
+#define LEVEL1_SIZE (1UL << 22UL)
+static u32 pgtable_level1[1024] PAGE_ALIGNED;
+
+static void identity_map_page(unsigned long address)
+{
+ unsigned long level1_index, level2_index;
+ u32 *pgtable_level2;
+
+ /* Find the current page table */
+ pgtable_level2 = __va(read_cr3());
+
+ /* Find the indexes of the physical address to identity map */
+ level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
+ level2_index = address / LEVEL1_SIZE;
+
+ /* Identity map the page table entry */
+ pgtable_level1[level1_index] = address | L0_ATTR;
+ pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
+
+ /* Flush the tlb so the new mapping takes effect.
+ * Global tlb entries are not flushed but that is not an issue.
+ */
+ load_cr3(pgtable_level2);
+}
+
+#else
+#define LEVEL1_SIZE (1UL << 21UL)
+#define LEVEL2_SIZE (1UL << 30UL)
+static u64 pgtable_level1[512] PAGE_ALIGNED;
+static u64 pgtable_level2[512] PAGE_ALIGNED;
+
+static void identity_map_page(unsigned long address)
+{
+ unsigned long level1_index, level2_index, level3_index;
+ u64 *pgtable_level3;
+
+ /* Find the current page table */
+ pgtable_level3 = __va(read_cr3());
+
+ /* Find the indexes of the physical address to identity map */
+ level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
+ level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE;
+ level3_index = address / LEVEL2_SIZE;
+
+ /* Identity map the page table entry */
+ pgtable_level1[level1_index] = address | L0_ATTR;
+ pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
+ set_64bit(&pgtable_level3[level3_index],
+ __pa(pgtable_level2) | L2_ATTR);
+
+ /* Flush the tlb so the new mapping takes effect.
+ * Global tlb entries are not flushed but that is not an issue.
+ */
+ load_cr3(pgtable_level3);
+}
+#endif
+
+
+static void set_idt(void *newidt, __u16 limit)
+{
+ unsigned char curidt[6];
+
+ /* ia32 supports unaliged loads & stores */
+ (*(__u16 *)(curidt)) = limit;
+ (*(__u32 *)(curidt +2)) = (unsigned long)(newidt);
+
+ __asm__ __volatile__ (
+ "lidt %0\n"
+ : "=m" (curidt)
+ );
+};
+
+
+static void set_gdt(void *newgdt, __u16 limit)
+{
+ unsigned char curgdt[6];
+
+ /* ia32 supports unaligned loads & stores */
+ (*(__u16 *)(curgdt)) = limit;
+ (*(__u32 *)(curgdt +2)) = (unsigned long)(newgdt);
+
+ __asm__ __volatile__ (
+ "lgdt %0\n"
+ : "=m" (curgdt)
+ );
+};
+
+static void load_segments(void)
+{
+#define __STR(X) #X
+#define STR(X) __STR(X)
+
+ __asm__ __volatile__ (
+ "\tljmp $"STR(__KERNEL_CS)",$1f\n"
+ "\t1:\n"
+ "\tmovl $"STR(__KERNEL_DS)",%eax\n"
+ "\tmovl %eax,%ds\n"
+ "\tmovl %eax,%es\n"
+ "\tmovl %eax,%fs\n"
+ "\tmovl %eax,%gs\n"
+ "\tmovl %eax,%ss\n"
+ );
+#undef STR
+#undef __STR
+}
+
+typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long reboot_code_buffer,
+ unsigned long start_address,
+ unsigned int has_pae) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+extern void relocate_new_kernel_end(void);
+const extern unsigned int relocate_new_kernel_size;
+
+/*
+ * A architecture hook called to validate the
+ * proposed image and prepare the control pages
+ * as needed. The pages for KEXEC_CONTROL_CODE_SIZE
+ * have been allocated, but the segments have yet
+ * been copied into the kernel.
+ *
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ *
+ * Currently nothing.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+ return 0;
+}
+
+/*
+ * Undo anything leftover by machine_kexec_prepare
+ * when an image is freed.
+ */
+void machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ unsigned long page_list;
+ unsigned long reboot_code_buffer;
+
+ relocate_new_kernel_t rnk;
+
+ /* Interrupts aren't acceptable while we reboot */
+ local_irq_disable();
+
+ /* Compute some offsets */
+ reboot_code_buffer = page_to_pfn(image->control_code_page)
+ << PAGE_SHIFT;
+ page_list = image->head;
+
+ /* Set up an identity mapping for the reboot_code_buffer */
+ identity_map_page(reboot_code_buffer);
+
+ /* copy it out */
+ memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ /* The segment registers are funny things, they are
+ * automatically loaded from a table, in memory wherever you
+ * set them to a specific selector, but this table is never
+ * accessed again you set the segment to a different selector.
+ *
+ * The more common model is are caches where the behide
+ * the scenes work is done, but is also dropped at arbitrary
+ * times.
+ *
+ * I take advantage of this here by force loading the
+ * segments, before I zap the gdt with an invalid value.
+ */
+ load_segments();
+ /* The gdt & idt are now invalid.
+ * If you want to load them you must set up your own idt & gdt.
+ */
+ set_gdt(phys_to_virt(0),0);
+ set_idt(phys_to_virt(0),0);
+
+ /* now call it */
+ rnk = (relocate_new_kernel_t) reboot_code_buffer;
+ (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
+}
diff --git a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
index 383a11600d2c..af917f609c7d 100644
--- a/arch/i386/kernel/mpparse.c
+++ b/arch/i386/kernel/mpparse.c
@@ -67,7 +67,6 @@ unsigned long mp_lapic_addr;
/* Processor that is doing the boot up */
unsigned int boot_cpu_physical_apicid = -1U;
-unsigned int boot_cpu_logical_apicid = -1U;
/* Internal processor count */
static unsigned int __initdata num_processors;
@@ -180,7 +179,6 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
Dprintk(" Bootup CPU\n");
boot_cpu_physical_apicid = m->mpc_apicid;
- boot_cpu_logical_apicid = apicid;
}
if (num_processors >= NR_CPUS) {
diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
index aea2ce1145df..ba243a4cc119 100644
--- a/arch/i386/kernel/process.c
+++ b/arch/i386/kernel/process.c
@@ -13,6 +13,7 @@
#include <stdarg.h>
+#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/fs.h>
@@ -55,6 +56,9 @@
#include <linux/irq.h>
#include <linux/err.h>
+#include <asm/tlbflush.h>
+#include <asm/cpu.h>
+
asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
static int hlt_counter;
@@ -143,14 +147,42 @@ static void poll_idle (void)
}
}
+#ifdef CONFIG_HOTPLUG_CPU
+#include <asm/nmi.h>
+/* We don't actually take CPU down, just spin without interrupts. */
+static inline void play_dead(void)
+{
+ /* This must be done before dead CPU ack */
+ cpu_exit_clear();
+ wbinvd();
+ mb();
+ /* Ack it */
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+
+ /*
+ * With physical CPU hotplug, we should halt the cpu
+ */
+ local_irq_disable();
+ while (1)
+ __asm__ __volatile__("hlt":::"memory");
+}
+#else
+static inline void play_dead(void)
+{
+ BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
* low exit latency (ie sit in a loop waiting for
* somebody to say that they'd like to reschedule)
*/
-void cpu_idle (void)
+void cpu_idle(void)
{
+ int cpu = raw_smp_processor_id();
+
/* endless idle loop with no priority at all */
while (1) {
while (!need_resched()) {
@@ -165,6 +197,9 @@ void cpu_idle (void)
if (!idle)
idle = default_idle;
+ if (cpu_is_offline(cpu))
+ play_dead();
+
__get_cpu_var(irq_stat).idle_timestamp = jiffies;
idle();
}
@@ -223,7 +258,7 @@ static void mwait_idle(void)
}
}
-void __init select_idle_routine(const struct cpuinfo_x86 *c)
+void __devinit select_idle_routine(const struct cpuinfo_x86 *c)
{
if (cpu_has(c, X86_FEATURE_MWAIT)) {
printk("monitor/mwait feature present.\n");
@@ -582,6 +617,33 @@ handle_io_bitmap(struct thread_struct *next, struct tss_struct *tss)
}
/*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+ struct task_struct *next_p)
+{
+ struct thread_info *prev, *next;
+
+ /*
+ * gcc should eliminate the ->thread_info dereference if
+ * has_secure_computing returns 0 at compile time (SECCOMP=n).
+ */
+ prev = prev_p->thread_info;
+ next = next_p->thread_info;
+
+ if (has_secure_computing(prev) || has_secure_computing(next)) {
+ /* slow path here */
+ if (has_secure_computing(prev) &&
+ !has_secure_computing(next)) {
+ write_cr4(read_cr4() & ~X86_CR4_TSD);
+ } else if (!has_secure_computing(prev) &&
+ has_secure_computing(next))
+ write_cr4(read_cr4() | X86_CR4_TSD);
+ }
+}
+
+/*
* switch_to(x,yn) should switch tasks from x to y.
*
* We fsave/fwait so that an exception goes off at the right time
@@ -660,6 +722,8 @@ struct task_struct fastcall * __switch_to(struct task_struct *prev_p, struct tas
if (unlikely(prev->io_bitmap_ptr || next->io_bitmap_ptr))
handle_io_bitmap(next, tss);
+ disable_tsc(prev_p, next_p);
+
return prev_p;
}
diff --git a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
index db912209a8d3..b3e584849961 100644
--- a/arch/i386/kernel/reboot.c
+++ b/arch/i386/kernel/reboot.c
@@ -26,7 +26,6 @@ static int reboot_mode;
static int reboot_thru_bios;
#ifdef CONFIG_SMP
-int reboot_smp = 0;
static int reboot_cpu = -1;
/* shamelessly grabbed from lib/vsprintf.c for readability */
#define is_digit(c) ((c) >= '0' && (c) <= '9')
@@ -49,7 +48,6 @@ static int __init reboot_setup(char *str)
break;
#ifdef CONFIG_SMP
case 's': /* "smp" reboot by executing reset on BSP or other CPU*/
- reboot_smp = 1;
if (is_digit(*(str+1))) {
reboot_cpu = (int) (*(str+1) - '0');
if (is_digit(*(str+2)))
@@ -88,33 +86,9 @@ static int __init set_bios_reboot(struct dmi_system_id *d)
return 0;
}
-/*
- * Some machines require the "reboot=s" commandline option, this quirk makes that automatic.
- */
-static int __init set_smp_reboot(struct dmi_system_id *d)
-{
-#ifdef CONFIG_SMP
- if (!reboot_smp) {
- reboot_smp = 1;
- printk(KERN_INFO "%s series board detected. Selecting SMP-method for reboots.\n", d->ident);
- }
-#endif
- return 0;
-}
-
-/*
- * Some machines require the "reboot=b,s" commandline option, this quirk makes that automatic.
- */
-static int __init set_smp_bios_reboot(struct dmi_system_id *d)
-{
- set_smp_reboot(d);
- set_bios_reboot(d);
- return 0;
-}
-
static struct dmi_system_id __initdata reboot_dmi_table[] = {
{ /* Handle problems with rebooting on Dell 1300's */
- .callback = set_smp_bios_reboot,
+ .callback = set_bios_reboot,
.ident = "Dell PowerEdge 1300",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer Corporation"),
@@ -301,41 +275,32 @@ void machine_real_restart(unsigned char *code, int length)
EXPORT_SYMBOL(machine_real_restart);
#endif
-void machine_restart(char * __unused)
+void machine_shutdown(void)
{
#ifdef CONFIG_SMP
- int cpuid;
-
- cpuid = GET_APIC_ID(apic_read(APIC_ID));
-
- if (reboot_smp) {
-
- /* check to see if reboot_cpu is valid
- if its not, default to the BSP */
- if ((reboot_cpu == -1) ||
- (reboot_cpu > (NR_CPUS -1)) ||
- !physid_isset(cpuid, phys_cpu_present_map))
- reboot_cpu = boot_cpu_physical_apicid;
-
- reboot_smp = 0; /* use this as a flag to only go through this once*/
- /* re-run this function on the other CPUs
- it will fall though this section since we have
- cleared reboot_smp, and do the reboot if it is the
- correct CPU, otherwise it halts. */
- if (reboot_cpu != cpuid)
- smp_call_function((void *)machine_restart , NULL, 1, 0);
+ int reboot_cpu_id;
+
+ /* The boot cpu is always logical cpu 0 */
+ reboot_cpu_id = 0;
+
+ /* See if there has been given a command line override */
+ if ((reboot_cpu_id != -1) && (reboot_cpu < NR_CPUS) &&
+ cpu_isset(reboot_cpu, cpu_online_map)) {
+ reboot_cpu_id = reboot_cpu;
}
- /* if reboot_cpu is still -1, then we want a tradional reboot,
- and if we are not running on the reboot_cpu,, halt */
- if ((reboot_cpu != -1) && (cpuid != reboot_cpu)) {
- for (;;)
- __asm__ __volatile__ ("hlt");
+ /* Make certain the cpu I'm rebooting on is online */
+ if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
+ reboot_cpu_id = smp_processor_id();
}
- /*
- * Stop all CPUs and turn off local APICs and the IO-APIC, so
- * other OSs see a clean IRQ state.
+
+ /* Make certain I only run on the appropriate processor */
+ set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
+
+ /* O.K. Now that I'm on the appropriate processor, stop
+ * all of the others, and disable their local APICs.
*/
+
smp_send_stop();
#endif /* CONFIG_SMP */
@@ -344,6 +309,11 @@ void machine_restart(char * __unused)
#ifdef CONFIG_X86_IO_APIC
disable_IO_APIC();
#endif
+}
+
+void machine_restart(char * __unused)
+{
+ machine_shutdown();
if (!reboot_thru_bios) {
if (efi_enabled) {
diff --git a/arch/i386/kernel/relocate_kernel.S b/arch/i386/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..d312616effa1
--- /dev/null
+++ b/arch/i386/kernel/relocate_kernel.S
@@ -0,0 +1,120 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/linkage.h>
+
+ /*
+ * Must be relocatable PIC code callable as a C function, that once
+ * it starts can not use the previous processes stack.
+ */
+ .globl relocate_new_kernel
+relocate_new_kernel:
+ /* read the arguments and say goodbye to the stack */
+ movl 4(%esp), %ebx /* page_list */
+ movl 8(%esp), %ebp /* reboot_code_buffer */
+ movl 12(%esp), %edx /* start address */
+ movl 16(%esp), %ecx /* cpu_has_pae */
+
+ /* zero out flags, and disable interrupts */
+ pushl $0
+ popfl
+
+ /* set a new stack at the bottom of our page... */
+ lea 4096(%ebp), %esp
+
+ /* store the parameters back on the stack */
+ pushl %edx /* store the start address */
+
+ /* Set cr0 to a known state:
+ * 31 0 == Paging disabled
+ * 18 0 == Alignment check disabled
+ * 16 0 == Write protect disabled
+ * 3 0 == No task switch
+ * 2 0 == Don't do FP software emulation.
+ * 0 1 == Proctected mode enabled
+ */
+ movl %cr0, %eax
+ andl $~((1<<31)|(1<<18)|(1<<16)|(1<<3)|(1<<2)), %eax
+ orl $(1<<0), %eax
+ movl %eax, %cr0
+
+ /* clear cr4 if applicable */
+ testl %ecx, %ecx
+ jz 1f
+ /* Set cr4 to a known state:
+ * Setting everything to zero seems safe.
+ */
+ movl %cr4, %eax
+ andl $0, %eax
+ movl %eax, %cr4
+
+ jmp 1f
+1:
+
+ /* Flush the TLB (needed?) */
+ xorl %eax, %eax
+ movl %eax, %cr3
+
+ /* Do the copies */
+ movl %ebx, %ecx
+ jmp 1f
+
+0: /* top, read another word from the indirection page */
+ movl (%ebx), %ecx
+ addl $4, %ebx
+1:
+ testl $0x1, %ecx /* is it a destination page */
+ jz 2f
+ movl %ecx, %edi
+ andl $0xfffff000, %edi
+ jmp 0b
+2:
+ testl $0x2, %ecx /* is it an indirection page */
+ jz 2f
+ movl %ecx, %ebx
+ andl $0xfffff000, %ebx
+ jmp 0b
+2:
+ testl $0x4, %ecx /* is it the done indicator */
+ jz 2f
+ jmp 3f
+2:
+ testl $0x8, %ecx /* is it the source indicator */
+ jz 0b /* Ignore it otherwise */
+ movl %ecx, %esi /* For every source page do a copy */
+ andl $0xfffff000, %esi
+
+ movl $1024, %ecx
+ rep ; movsl
+ jmp 0b
+
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * I need to execute a serializing instruction here.
+ * So I flush the TLB, it's handy, and not processor dependent.
+ */
+ xorl %eax, %eax
+ movl %eax, %cr3
+
+ /* set all of the registers to known values */
+ /* leave %esp alone */
+
+ xorl %eax, %eax
+ xorl %ebx, %ebx
+ xorl %ecx, %ecx
+ xorl %edx, %edx
+ xorl %esi, %esi
+ xorl %edi, %edi
+ xorl %ebp, %ebp
+ ret
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
diff --git a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
index 30406fd0b64c..7306353c520e 100644
--- a/arch/i386/kernel/setup.c
+++ b/arch/i386/kernel/setup.c
@@ -43,7 +43,12 @@
#include <linux/init.h>
#include <linux/edd.h>
#include <linux/nodemask.h>
+#include <linux/kexec.h>
+#include <linux/crash_dump.h>
+
#include <video/edid.h>
+
+#include <asm/apic.h>
#include <asm/e820.h>
#include <asm/mpspec.h>
#include <asm/setup.h>
@@ -55,12 +60,15 @@
#include "setup_arch_pre.h"
#include <bios_ebda.h>
+/* Forward Declaration. */
+void __init find_max_pfn(void);
+
/* This value is set up by the early boot code to point to the value
immediately after the boot time page tables. It contains a *physical*
address, and must not be in the .bss segment! */
unsigned long init_pg_tables_end __initdata = ~0UL;
-int disable_pse __initdata = 0;
+int disable_pse __devinitdata = 0;
/*
* Machine setup..
@@ -732,6 +740,15 @@ static void __init parse_cmdline_early (char ** cmdline_p)
if (to != command_line)
to--;
if (!memcmp(from+7, "exactmap", 8)) {
+#ifdef CONFIG_CRASH_DUMP
+ /* If we are doing a crash dump, we
+ * still need to know the real mem
+ * size before original memory map is
+ * reset.
+ */
+ find_max_pfn();
+ saved_max_pfn = max_pfn;
+#endif
from += 8+7;
e820.nr_map = 0;
userdef = 1;
@@ -835,6 +852,44 @@ static void __init parse_cmdline_early (char ** cmdline_p)
#endif /* CONFIG_X86_LOCAL_APIC */
#endif /* CONFIG_ACPI_BOOT */
+#ifdef CONFIG_X86_LOCAL_APIC
+ /* enable local APIC */
+ else if (!memcmp(from, "lapic", 5))
+ lapic_enable();
+
+ /* disable local APIC */
+ else if (!memcmp(from, "nolapic", 6))
+ lapic_disable();
+#endif /* CONFIG_X86_LOCAL_APIC */
+
+#ifdef CONFIG_KEXEC
+ /* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel. By reserving this memory we guarantee
+ * that linux never set's it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+ else if (!memcmp(from, "crashkernel=", 12)) {
+ unsigned long size, base;
+ size = memparse(from+12, &from);
+ if (*from == '@') {
+ base = memparse(from+1, &from);
+ /* FIXME: Do I want a sanity check
+ * to validate the memory range?
+ */
+ crashk_res.start = base;
+ crashk_res.end = base + size - 1;
+ }
+ }
+#endif
+#ifdef CONFIG_CRASH_DUMP
+ /* elfcorehdr= specifies the location of elf core header
+ * stored by the crashed kernel.
+ */
+ else if (!memcmp(from, "elfcorehdr=", 11))
+ elfcorehdr_addr = memparse(from+11, &from);
+#endif
+
/*
* highmem=size forces highmem to be exactly 'size' bytes.
* This works even on boxes that have no highmem otherwise.
@@ -1113,8 +1168,8 @@ void __init setup_bootmem_allocator(void)
* the (very unlikely) case of us accidentally initializing the
* bootmem allocator with an invalid RAM area.
*/
- reserve_bootmem(HIGH_MEMORY, (PFN_PHYS(min_low_pfn) +
- bootmap_size + PAGE_SIZE-1) - (HIGH_MEMORY));
+ reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) +
+ bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START));
/*
* reserve physical page 0 - it's a special BIOS page on many boxes,
@@ -1170,6 +1225,11 @@ void __init setup_bootmem_allocator(void)
}
}
#endif
+#ifdef CONFIG_KEXEC
+ if (crashk_res.start != crashk_res.end)
+ reserve_bootmem(crashk_res.start,
+ crashk_res.end - crashk_res.start + 1);
+#endif
}
/*
@@ -1223,6 +1283,9 @@ legacy_init_iomem_resources(struct resource *code_resource, struct resource *dat
*/
request_resource(res, code_resource);
request_resource(res, data_resource);
+#ifdef CONFIG_KEXEC
+ request_resource(res, &crashk_res);
+#endif
}
}
}
diff --git a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
index b9b8f4e20fad..89ef7adc63a4 100644
--- a/arch/i386/kernel/signal.c
+++ b/arch/i386/kernel/signal.c
@@ -608,10 +608,8 @@ int fastcall do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!user_mode(regs))
return 1;
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze())
goto no_signal;
- }
if (!oldset)
oldset = &current->blocked;
diff --git a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
index 68be7d0c7238..cec4bde67161 100644
--- a/arch/i386/kernel/smp.c
+++ b/arch/i386/kernel/smp.c
@@ -19,6 +19,7 @@
#include <linux/mc146818rtc.h>
#include <linux/cache.h>
#include <linux/interrupt.h>
+#include <linux/cpu.h>
#include <linux/module.h>
#include <asm/mtrr.h>
@@ -164,7 +165,7 @@ void send_IPI_mask_bitmask(cpumask_t cpumask, int vector)
unsigned long flags;
local_irq_save(flags);
-
+ WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
/*
* Wait for idle.
*/
@@ -346,21 +347,21 @@ out:
static void flush_tlb_others(cpumask_t cpumask, struct mm_struct *mm,
unsigned long va)
{
- cpumask_t tmp;
/*
* A couple of (to be removed) sanity checks:
*
- * - we do not send IPIs to not-yet booted CPUs.
* - current CPU must not be in mask
* - mask must exist :)
*/
BUG_ON(cpus_empty(cpumask));
-
- cpus_and(tmp, cpumask, cpu_online_map);
- BUG_ON(!cpus_equal(cpumask, tmp));
BUG_ON(cpu_isset(smp_processor_id(), cpumask));
BUG_ON(!mm);
+ /* If a CPU which we ran on has gone down, OK. */
+ cpus_and(cpumask, cpumask, cpu_online_map);
+ if (cpus_empty(cpumask))
+ return;
+
/*
* i'm not happy about this global shared spinlock in the
* MM hot path, but we'll see how contended it is.
@@ -476,6 +477,7 @@ void flush_tlb_all(void)
*/
void smp_send_reschedule(int cpu)
{
+ WARN_ON(cpu_is_offline(cpu));
send_IPI_mask(cpumask_of_cpu(cpu), RESCHEDULE_VECTOR);
}
@@ -493,6 +495,16 @@ struct call_data_struct {
int wait;
};
+void lock_ipi_call_lock(void)
+{
+ spin_lock_irq(&call_lock);
+}
+
+void unlock_ipi_call_lock(void)
+{
+ spin_unlock_irq(&call_lock);
+}
+
static struct call_data_struct * call_data;
/*
@@ -516,10 +528,15 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
*/
{
struct call_data_struct data;
- int cpus = num_online_cpus()-1;
+ int cpus;
- if (!cpus)
+ /* Holding any lock stops cpus from going down. */
+ spin_lock(&call_lock);
+ cpus = num_online_cpus() - 1;
+ if (!cpus) {
+ spin_unlock(&call_lock);
return 0;
+ }
/* Can deadlock when called with interrupts disabled */
WARN_ON(irqs_disabled());
@@ -531,7 +548,6 @@ int smp_call_function (void (*func) (void *info), void *info, int nonatomic,
if (wait)
atomic_set(&data.finished, 0);
- spin_lock(&call_lock);
call_data = &data;
mb();
diff --git a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
index c20d96d5c15c..8ac8e9fd5614 100644
--- a/arch/i386/kernel/smpboot.c
+++ b/arch/i386/kernel/smpboot.c
@@ -44,6 +44,9 @@
#include <linux/smp_lock.h>
#include <linux/irq.h>
#include <linux/bootmem.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+#include <linux/percpu.h>
#include <linux/delay.h>
#include <linux/mc146818rtc.h>
@@ -56,20 +59,30 @@
#include <smpboot_hooks.h>
/* Set if we find a B stepping CPU */
-static int __initdata smp_b_stepping;
+static int __devinitdata smp_b_stepping;
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
#ifdef CONFIG_X86_HT
EXPORT_SYMBOL(smp_num_siblings);
#endif
-int phys_proc_id[NR_CPUS]; /* Package ID of each logical CPU */
+
+/* Package ID of each logical CPU */
+int phys_proc_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(phys_proc_id);
-int cpu_core_id[NR_CPUS]; /* Core ID of each logical CPU */
+
+/* Core ID of each logical CPU */
+int cpu_core_id[NR_CPUS] __read_mostly = {[0 ... NR_CPUS-1] = BAD_APICID};
EXPORT_SYMBOL(cpu_core_id);
+cpumask_t cpu_sibling_map[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(cpu_sibling_map);
+
+cpumask_t cpu_core_map[NR_CPUS] __read_mostly;
+EXPORT_SYMBOL(cpu_core_map);
+
/* bitmap of online cpus */
-cpumask_t cpu_online_map;
+cpumask_t cpu_online_map __read_mostly;
EXPORT_SYMBOL(cpu_online_map);
cpumask_t cpu_callin_map;
@@ -77,11 +90,17 @@ cpumask_t cpu_callout_map;
EXPORT_SYMBOL(cpu_callout_map);
static cpumask_t smp_commenced_mask;
+/* TSC's upper 32 bits can't be written in eariler CPU (before prescott), there
+ * is no way to resync one AP against BP. TBD: for prescott and above, we
+ * should use IA64's algorithm
+ */
+static int __devinitdata tsc_sync_disabled;
+
/* Per CPU bogomips and other parameters */
struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
EXPORT_SYMBOL(cpu_data);
-u8 x86_cpu_to_apicid[NR_CPUS] =
+u8 x86_cpu_to_apicid[NR_CPUS] __read_mostly =
{ [0 ... NR_CPUS-1] = 0xff };
EXPORT_SYMBOL(x86_cpu_to_apicid);
@@ -96,13 +115,16 @@ static int trampoline_exec;
static void map_cpu_to_logical_apicid(void);
+/* State of each CPU. */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
/*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
* has made sure it's suitably aligned.
*/
-static unsigned long __init setup_trampoline(void)
+static unsigned long __devinit setup_trampoline(void)
{
memcpy(trampoline_base, trampoline_data, trampoline_end - trampoline_data);
return virt_to_phys(trampoline_base);
@@ -132,7 +154,7 @@ void __init smp_alloc_memory(void)
* a given CPU
*/
-static void __init smp_store_cpu_info(int id)
+static void __devinit smp_store_cpu_info(int id)
{
struct cpuinfo_x86 *c = cpu_data + id;
@@ -326,7 +348,7 @@ extern void calibrate_delay(void);
static atomic_t init_deasserted;
-static void __init smp_callin(void)
+static void __devinit smp_callin(void)
{
int cpuid, phys_id;
unsigned long timeout;
@@ -411,16 +433,48 @@ static void __init smp_callin(void)
/*
* Synchronize the TSC with the BP
*/
- if (cpu_has_tsc && cpu_khz)
+ if (cpu_has_tsc && cpu_khz && !tsc_sync_disabled)
synchronize_tsc_ap();
}
static int cpucount;
+static inline void
+set_cpu_sibling_map(int cpu)
+{
+ int i;
+
+ if (smp_num_siblings > 1) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_isset(i, cpu_callout_map))
+ continue;
+ if (cpu_core_id[cpu] == cpu_core_id[i]) {
+ cpu_set(i, cpu_sibling_map[cpu]);
+ cpu_set(cpu, cpu_sibling_map[i]);
+ }
+ }
+ } else {
+ cpu_set(cpu, cpu_sibling_map[cpu]);
+ }
+
+ if (current_cpu_data.x86_num_cores > 1) {
+ for (i = 0; i < NR_CPUS; i++) {
+ if (!cpu_isset(i, cpu_callout_map))
+ continue;
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
+ }
+ }
+ } else {
+ cpu_core_map[cpu] = cpu_sibling_map[cpu];
+ }
+}
+
/*
* Activate a secondary processor.
*/
-static void __init start_secondary(void *unused)
+static void __devinit start_secondary(void *unused)
{
/*
* Dont put anything before smp_callin(), SMP
@@ -443,7 +497,23 @@ static void __init start_secondary(void *unused)
* the local TLBs too.
*/
local_flush_tlb();
+
+ /* This must be done before setting cpu_online_map */
+ set_cpu_sibling_map(raw_smp_processor_id());
+ wmb();
+
+ /*
+ * We need to hold call_lock, so there is no inconsistency
+ * between the time smp_call_function() determines number of
+ * IPI receipients, and the time when the determination is made
+ * for which cpus receive the IPI. Holding this
+ * lock helps us to not include this cpu in a currently in progress
+ * smp_call_function().
+ */
+ lock_ipi_call_lock();
cpu_set(smp_processor_id(), cpu_online_map);
+ unlock_ipi_call_lock();
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
/* We can take interrupts now: we're officially "up". */
local_irq_enable();
@@ -458,7 +528,7 @@ static void __init start_secondary(void *unused)
* from the task structure
* This function must not return.
*/
-void __init initialize_secondary(void)
+void __devinit initialize_secondary(void)
{
/*
* We don't actually need to load the full TSS,
@@ -480,10 +550,10 @@ extern struct {
#ifdef CONFIG_NUMA
/* which logical CPUs are on which nodes */
-cpumask_t node_2_cpu_mask[MAX_NUMNODES] =
+cpumask_t node_2_cpu_mask[MAX_NUMNODES] __read_mostly =
{ [0 ... MAX_NUMNODES-1] = CPU_MASK_NONE };
/* which node each logical CPU is on */
-int cpu_2_node[NR_CPUS] = { [0 ... NR_CPUS-1] = 0 };
+int cpu_2_node[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = 0 };
EXPORT_SYMBOL(cpu_2_node);
/* set up a mapping between cpu and node. */
@@ -511,7 +581,7 @@ static inline void unmap_cpu_to_node(int cpu)
#endif /* CONFIG_NUMA */
-u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
+u8 cpu_2_logical_apicid[NR_CPUS] __read_mostly = { [0 ... NR_CPUS-1] = BAD_APICID };
static void map_cpu_to_logical_apicid(void)
{
@@ -572,7 +642,7 @@ static inline void __inquire_remote_apic(int apicid)
* INIT, INIT, STARTUP sequence will reset the chip hard for us, and this
* won't ... remember to clear down the APIC, etc later.
*/
-static int __init
+static int __devinit
wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
{
unsigned long send_status = 0, accept_status = 0;
@@ -618,7 +688,7 @@ wakeup_secondary_cpu(int logical_apicid, unsigned long start_eip)
#endif /* WAKE_SECONDARY_VIA_NMI */
#ifdef WAKE_SECONDARY_VIA_INIT
-static int __init
+static int __devinit
wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
{
unsigned long send_status = 0, accept_status = 0;
@@ -753,8 +823,43 @@ wakeup_secondary_cpu(int phys_apicid, unsigned long start_eip)
#endif /* WAKE_SECONDARY_VIA_INIT */
extern cpumask_t cpu_initialized;
+static inline int alloc_cpu_id(void)
+{
+ cpumask_t tmp_map;
+ int cpu;
+ cpus_complement(tmp_map, cpu_present_map);
+ cpu = first_cpu(tmp_map);
+ if (cpu >= NR_CPUS)
+ return -ENODEV;
+ return cpu;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static struct task_struct * __devinitdata cpu_idle_tasks[NR_CPUS];
+static inline struct task_struct * alloc_idle_task(int cpu)
+{
+ struct task_struct *idle;
+
+ if ((idle = cpu_idle_tasks[cpu]) != NULL) {
+ /* initialize thread_struct. we really want to avoid destroy
+ * idle tread
+ */
+ idle->thread.esp = (unsigned long)(((struct pt_regs *)
+ (THREAD_SIZE + (unsigned long) idle->thread_info)) - 1);
+ init_idle(idle, cpu);
+ return idle;
+ }
+ idle = fork_idle(cpu);
+
+ if (!IS_ERR(idle))
+ cpu_idle_tasks[cpu] = idle;
+ return idle;
+}
+#else
+#define alloc_idle_task(cpu) fork_idle(cpu)
+#endif
-static int __init do_boot_cpu(int apicid)
+static int __devinit do_boot_cpu(int apicid, int cpu)
/*
* NOTE - on most systems this is a PHYSICAL apic ID, but on multiquad
* (ie clustered apic addressing mode), this is a LOGICAL apic ID.
@@ -763,16 +868,17 @@ static int __init do_boot_cpu(int apicid)
{
struct task_struct *idle;
unsigned long boot_error;
- int timeout, cpu;
+ int timeout;
unsigned long start_eip;
unsigned short nmi_high = 0, nmi_low = 0;
- cpu = ++cpucount;
+ ++cpucount;
+
/*
* We can't use kernel_thread since we must avoid to
* reschedule the child.
*/
- idle = fork_idle(cpu);
+ idle = alloc_idle_task(cpu);
if (IS_ERR(idle))
panic("failed fork for CPU %d", cpu);
idle->thread.eip = (unsigned long) start_secondary;
@@ -839,13 +945,16 @@ static int __init do_boot_cpu(int apicid)
inquire_remote_apic(apicid);
}
}
- x86_cpu_to_apicid[cpu] = apicid;
+
if (boot_error) {
/* Try to put things back the way they were before ... */
unmap_cpu_to_logical_apicid(cpu);
cpu_clear(cpu, cpu_callout_map); /* was set here (do_boot_cpu()) */
cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */
cpucount--;
+ } else {
+ x86_cpu_to_apicid[cpu] = apicid;
+ cpu_set(cpu, cpu_present_map);
}
/* mark "stuck" area as not stuck */
@@ -854,6 +963,75 @@ static int __init do_boot_cpu(int apicid)
return boot_error;
}
+#ifdef CONFIG_HOTPLUG_CPU
+void cpu_exit_clear(void)
+{
+ int cpu = raw_smp_processor_id();
+
+ idle_task_exit();
+
+ cpucount --;
+ cpu_uninit();
+ irq_ctx_exit(cpu);
+
+ cpu_clear(cpu, cpu_callout_map);
+ cpu_clear(cpu, cpu_callin_map);
+ cpu_clear(cpu, cpu_present_map);
+
+ cpu_clear(cpu, smp_commenced_mask);
+ unmap_cpu_to_logical_apicid(cpu);
+}
+
+struct warm_boot_cpu_info {
+ struct completion *complete;
+ int apicid;
+ int cpu;
+};
+
+static void __devinit do_warm_boot_cpu(void *p)
+{
+ struct warm_boot_cpu_info *info = p;
+ do_boot_cpu(info->apicid, info->cpu);
+ complete(info->complete);
+}
+
+int __devinit smp_prepare_cpu(int cpu)
+{
+ DECLARE_COMPLETION(done);
+ struct warm_boot_cpu_info info;
+ struct work_struct task;
+ int apicid, ret;
+
+ lock_cpu_hotplug();
+ apicid = x86_cpu_to_apicid[cpu];
+ if (apicid == BAD_APICID) {
+ ret = -ENODEV;
+ goto exit;
+ }
+
+ info.complete = &done;
+ info.apicid = apicid;
+ info.cpu = cpu;
+ INIT_WORK(&task, do_warm_boot_cpu, &info);
+
+ tsc_sync_disabled = 1;
+
+ /* init low mem mapping */
+ memcpy(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS,
+ sizeof(swapper_pg_dir[0]) * KERNEL_PGD_PTRS);
+ flush_tlb_all();
+ schedule_work(&task);
+ wait_for_completion(&done);
+
+ tsc_sync_disabled = 0;
+ zap_low_mappings();
+ ret = 0;
+exit:
+ unlock_cpu_hotplug();
+ return ret;
+}
+#endif
+
static void smp_tune_scheduling (void)
{
unsigned long cachesize; /* kB */
@@ -895,13 +1073,6 @@ void *xquad_portio;
EXPORT_SYMBOL(xquad_portio);
#endif
-cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
-#ifdef CONFIG_X86_HT
-EXPORT_SYMBOL(cpu_sibling_map);
-#endif
-cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
-EXPORT_SYMBOL(cpu_core_map);
-
static void __init smp_boot_cpus(unsigned int max_cpus)
{
int apicid, cpu, bit, kicked;
@@ -1013,7 +1184,7 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
if (max_cpus <= cpucount+1)
continue;
- if (do_boot_cpu(apicid))
+ if (((cpu = alloc_cpu_id()) <= 0) || do_boot_cpu(apicid, cpu))
printk("CPU #%d not responding - cannot use it.\n",
apicid);
else
@@ -1065,44 +1236,8 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
cpus_clear(cpu_core_map[cpu]);
}
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- struct cpuinfo_x86 *c = cpu_data + cpu;
- int siblings = 0;
- int i;
- if (!cpu_isset(cpu, cpu_callout_map))
- continue;
-
- if (smp_num_siblings > 1) {
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_isset(i, cpu_callout_map))
- continue;
- if (cpu_core_id[cpu] == cpu_core_id[i]) {
- siblings++;
- cpu_set(i, cpu_sibling_map[cpu]);
- }
- }
- } else {
- siblings++;
- cpu_set(cpu, cpu_sibling_map[cpu]);
- }
-
- if (siblings != smp_num_siblings) {
- printk(KERN_WARNING "WARNING: %d siblings found for CPU%d, should be %d\n", siblings, cpu, smp_num_siblings);
- smp_num_siblings = siblings;
- }
-
- if (c->x86_num_cores > 1) {
- for (i = 0; i < NR_CPUS; i++) {
- if (!cpu_isset(i, cpu_callout_map))
- continue;
- if (phys_proc_id[cpu] == phys_proc_id[i]) {
- cpu_set(i, cpu_core_map[cpu]);
- }
- }
- } else {
- cpu_core_map[cpu] = cpu_sibling_map[cpu];
- }
- }
+ cpu_set(0, cpu_sibling_map[0]);
+ cpu_set(0, cpu_core_map[0]);
smpboot_setup_io_apic();
@@ -1119,6 +1254,9 @@ static void __init smp_boot_cpus(unsigned int max_cpus)
who understands all this stuff should rewrite it properly. --RR 15/Jul/02 */
void __init smp_prepare_cpus(unsigned int max_cpus)
{
+ smp_commenced_mask = cpumask_of_cpu(0);
+ cpu_callin_map = cpumask_of_cpu(0);
+ mb();
smp_boot_cpus(max_cpus);
}
@@ -1126,23 +1264,98 @@ void __devinit smp_prepare_boot_cpu(void)
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callout_map);
+ cpu_set(smp_processor_id(), cpu_present_map);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
}
-int __devinit __cpu_up(unsigned int cpu)
+#ifdef CONFIG_HOTPLUG_CPU
+static void
+remove_siblinginfo(int cpu)
{
- /* This only works at boot for x86. See "rewrite" above. */
- if (cpu_isset(cpu, smp_commenced_mask)) {
- local_irq_enable();
- return -ENOSYS;
+ int sibling;
+
+ for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
+ cpu_clear(cpu, cpu_sibling_map[sibling]);
+ for_each_cpu_mask(sibling, cpu_core_map[cpu])
+ cpu_clear(cpu, cpu_core_map[sibling]);
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ phys_proc_id[cpu] = BAD_APICID;
+ cpu_core_id[cpu] = BAD_APICID;
+}
+
+int __cpu_disable(void)
+{
+ cpumask_t map = cpu_online_map;
+ int cpu = smp_processor_id();
+
+ /*
+ * Perhaps use cpufreq to drop frequency, but that could go
+ * into generic code.
+ *
+ * We won't take down the boot processor on i386 due to some
+ * interrupts only being able to be serviced by the BSP.
+ * Especially so if we're not using an IOAPIC -zwane
+ */
+ if (cpu == 0)
+ return -EBUSY;
+
+ /* We enable the timer again on the exit path of the death loop */
+ disable_APIC_timer();
+ /* Allow any queued timer interrupts to get serviced */
+ local_irq_enable();
+ mdelay(1);
+ local_irq_disable();
+
+ remove_siblinginfo(cpu);
+
+ cpu_clear(cpu, map);
+ fixup_irqs(map);
+ /* It's now safe to remove this processor from the online map */
+ cpu_clear(cpu, cpu_online_map);
+ return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ /* We don't do anything here: idle task is faking death itself. */
+ unsigned int i;
+
+ for (i = 0; i < 10; i++) {
+ /* They ack this in play_dead by setting CPU_DEAD */
+ if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+ printk ("CPU %d is now offline\n", cpu);
+ return;
+ }
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10);
}
+ printk(KERN_ERR "CPU %u didn't die...\n", cpu);
+}
+#else /* ... !CONFIG_HOTPLUG_CPU */
+int __cpu_disable(void)
+{
+ return -ENOSYS;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ /* We said "no" in __cpu_disable */
+ BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+int __devinit __cpu_up(unsigned int cpu)
+{
/* In case one didn't come up */
if (!cpu_isset(cpu, cpu_callin_map)) {
+ printk(KERN_DEBUG "skipping cpu%d, didn't come online\n", cpu);
local_irq_enable();
return -EIO;
}
local_irq_enable();
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Unleash the CPU! */
cpu_set(cpu, smp_commenced_mask);
while (!cpu_isset(cpu, cpu_online_map))
@@ -1156,10 +1369,12 @@ void __init smp_cpus_done(unsigned int max_cpus)
setup_ioapic_dest();
#endif
zap_low_mappings();
+#ifndef CONFIG_HOTPLUG_CPU
/*
* Disable executability of the SMP trampoline:
*/
set_kernel_exec((unsigned long)trampoline_base, trampoline_exec);
+#endif
}
void __init smp_intr_init(void)
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S
index d408afaf6495..468500a7e894 100644
--- a/arch/i386/kernel/syscall_table.S
+++ b/arch/i386/kernel/syscall_table.S
@@ -283,9 +283,14 @@ ENTRY(sys_call_table)
.long sys_mq_timedreceive /* 280 */
.long sys_mq_notify
.long sys_mq_getsetattr
- .long sys_ni_syscall /* reserved for kexec */
+ .long sys_kexec_load
.long sys_waitid
.long sys_ni_syscall /* 285 */ /* available */
.long sys_add_key
.long sys_request_key
.long sys_keyctl
+ .long sys_ioprio_set
+ .long sys_ioprio_get /* 290 */
+ .long sys_inotify_init
+ .long sys_inotify_add_watch
+ .long sys_inotify_rm_watch
diff --git a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
index 960d8bd137d0..0bada1870bdf 100644
--- a/arch/i386/kernel/sysenter.c
+++ b/arch/i386/kernel/sysenter.c
@@ -21,11 +21,16 @@
extern asmlinkage void sysenter_entry(void);
-void enable_sep_cpu(void *info)
+void enable_sep_cpu(void)
{
int cpu = get_cpu();
struct tss_struct *tss = &per_cpu(init_tss, cpu);
+ if (!boot_cpu_has(X86_FEATURE_SEP)) {
+ put_cpu();
+ return;
+ }
+
tss->ss1 = __KERNEL_CS;
tss->esp1 = sizeof(struct tss_struct) + (unsigned long) tss;
wrmsr(MSR_IA32_SYSENTER_CS, __KERNEL_CS, 0);
@@ -41,7 +46,7 @@ void enable_sep_cpu(void *info)
extern const char vsyscall_int80_start, vsyscall_int80_end;
extern const char vsyscall_sysenter_start, vsyscall_sysenter_end;
-static int __init sysenter_setup(void)
+int __init sysenter_setup(void)
{
void *page = (void *)get_zeroed_page(GFP_ATOMIC);
@@ -58,8 +63,5 @@ static int __init sysenter_setup(void)
&vsyscall_sysenter_start,
&vsyscall_sysenter_end - &vsyscall_sysenter_start);
- on_each_cpu(enable_sep_cpu, NULL, 1, 1);
return 0;
}
-
-__initcall(sysenter_setup);
diff --git a/arch/i386/kernel/time.c b/arch/i386/kernel/time.c
index e68d9fdb0759..0ee9dee8af06 100644
--- a/arch/i386/kernel/time.c
+++ b/arch/i386/kernel/time.c
@@ -68,7 +68,8 @@
#include "io_ports.h"
-extern spinlock_t i8259A_lock;
+#include <asm/i8259.h>
+
int pit_latch_buggy; /* extern */
#include "do_timer.h"
@@ -85,10 +86,12 @@ extern unsigned long wall_jiffies;
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
+#include <asm/i8253.h>
+
DEFINE_SPINLOCK(i8253_lock);
EXPORT_SYMBOL(i8253_lock);
-struct timer_opts *cur_timer = &timer_none;
+struct timer_opts *cur_timer __read_mostly = &timer_none;
/*
* This is a special lock that is owned by the CPU and holds the index
diff --git a/arch/i386/kernel/time_hpet.c b/arch/i386/kernel/time_hpet.c
index 10a0cbb88e75..658c0629ba6a 100644
--- a/arch/i386/kernel/time_hpet.c
+++ b/arch/i386/kernel/time_hpet.c
@@ -50,7 +50,7 @@ static void hpet_writel(unsigned long d, unsigned long a)
* comparator value and continue. Next tick can be caught by checking
* for a change in the comparator value. Used in apic.c.
*/
-static void __init wait_hpet_tick(void)
+static void __devinit wait_hpet_tick(void)
{
unsigned int start_cmp_val, end_cmp_val;
diff --git a/arch/i386/kernel/timers/common.c b/arch/i386/kernel/timers/common.c
index 37353bd31803..8163fe0cf1f0 100644
--- a/arch/i386/kernel/timers/common.c
+++ b/arch/i386/kernel/timers/common.c
@@ -86,7 +86,7 @@ bad_ctc:
#define CALIBRATE_CNT_HPET (5 * hpet_tick)
#define CALIBRATE_TIME_HPET (5 * KERNEL_TICK_USEC)
-unsigned long __init calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
+unsigned long __devinit calibrate_tsc_hpet(unsigned long *tsc_hpet_quotient_ptr)
{
unsigned long tsc_startlow, tsc_starthigh;
unsigned long tsc_endlow, tsc_endhigh;
diff --git a/arch/i386/kernel/timers/timer_cyclone.c b/arch/i386/kernel/timers/timer_cyclone.c
index f6f1206a11bb..13892a65c941 100644
--- a/arch/i386/kernel/timers/timer_cyclone.c
+++ b/arch/i386/kernel/timers/timer_cyclone.c
@@ -17,9 +17,9 @@
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/fixmap.h>
-#include "io_ports.h"
+#include <asm/i8253.h>
-extern spinlock_t i8253_lock;
+#include "io_ports.h"
/* Number of usecs that the last interrupt was delayed */
static int delay_at_last_interrupt;
diff --git a/arch/i386/kernel/timers/timer_hpet.c b/arch/i386/kernel/timers/timer_hpet.c
index d766e0963ac1..ef8dac5dd33b 100644
--- a/arch/i386/kernel/timers/timer_hpet.c
+++ b/arch/i386/kernel/timers/timer_hpet.c
@@ -18,7 +18,7 @@
#include "mach_timer.h"
#include <asm/hpet.h>
-static unsigned long hpet_usec_quotient; /* convert hpet clks to usec */
+static unsigned long __read_mostly hpet_usec_quotient; /* convert hpet clks to usec */
static unsigned long tsc_hpet_quotient; /* convert tsc to hpet clks */
static unsigned long hpet_last; /* hpet counter value at last tick*/
static unsigned long last_tsc_low; /* lsb 32 bits of Time Stamp Counter */
@@ -180,7 +180,7 @@ static int __init init_hpet(char* override)
/************************************************************/
/* tsc timer_opts struct */
-static struct timer_opts timer_hpet = {
+static struct timer_opts timer_hpet __read_mostly = {
.name = "hpet",
.mark_offset = mark_offset_hpet,
.get_offset = get_offset_hpet,
diff --git a/arch/i386/kernel/timers/timer_pit.c b/arch/i386/kernel/timers/timer_pit.c
index 967d5453cd0e..06de036a820c 100644
--- a/arch/i386/kernel/timers/timer_pit.c
+++ b/arch/i386/kernel/timers/timer_pit.c
@@ -15,9 +15,8 @@
#include <asm/smp.h>
#include <asm/io.h>
#include <asm/arch_hooks.h>
+#include <asm/i8253.h>
-extern spinlock_t i8259A_lock;
-extern spinlock_t i8253_lock;
#include "do_timer.h"
#include "io_ports.h"
@@ -166,7 +165,6 @@ struct init_timer_opts __initdata timer_pit_init = {
void setup_pit_timer(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
spin_lock_irqsave(&i8253_lock, flags);
diff --git a/arch/i386/kernel/timers/timer_tsc.c b/arch/i386/kernel/timers/timer_tsc.c
index 54c36b182021..8f4e4d5bc560 100644
--- a/arch/i386/kernel/timers/timer_tsc.c
+++ b/arch/i386/kernel/timers/timer_tsc.c
@@ -24,6 +24,7 @@
#include "mach_timer.h"
#include <asm/hpet.h>
+#include <asm/i8253.h>
#ifdef CONFIG_HPET_TIMER
static unsigned long hpet_usec_quotient;
@@ -33,9 +34,7 @@ static struct timer_opts timer_tsc;
static inline void cpufreq_delayed_get(void);
-int tsc_disable __initdata = 0;
-
-extern spinlock_t i8253_lock;
+int tsc_disable __devinitdata = 0;
static int use_tsc;
/* Number of usecs that the last interrupt was delayed */
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
index e4d4e2162c7a..a61f33d06ea3 100644
--- a/arch/i386/kernel/traps.c
+++ b/arch/i386/kernel/traps.c
@@ -27,6 +27,7 @@
#include <linux/ptrace.h>
#include <linux/utsname.h>
#include <linux/kprobes.h>
+#include <linux/kexec.h>
#ifdef CONFIG_EISA
#include <linux/ioport.h>
@@ -234,22 +235,22 @@ void show_registers(struct pt_regs *regs)
* time of the fault..
*/
if (in_kernel) {
- u8 *eip;
+ u8 __user *eip;
printk("\nStack: ");
show_stack(NULL, (unsigned long*)esp);
printk("Code: ");
- eip = (u8 *)regs->eip - 43;
+ eip = (u8 __user *)regs->eip - 43;
for (i = 0; i < 64; i++, eip++) {
unsigned char c;
- if (eip < (u8 *)PAGE_OFFSET || __get_user(c, eip)) {
+ if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
printk(" Bad EIP value.");
break;
}
- if (eip == (u8 *)regs->eip)
+ if (eip == (u8 __user *)regs->eip)
printk("<%02x> ", c);
else
printk("%02x ", c);
@@ -273,13 +274,13 @@ static void handle_BUG(struct pt_regs *regs)
if (eip < PAGE_OFFSET)
goto no_bug;
- if (__get_user(ud2, (unsigned short *)eip))
+ if (__get_user(ud2, (unsigned short __user *)eip))
goto no_bug;
if (ud2 != 0x0b0f)
goto no_bug;
- if (__get_user(line, (unsigned short *)(eip + 2)))
+ if (__get_user(line, (unsigned short __user *)(eip + 2)))
goto bug;
- if (__get_user(file, (char **)(eip + 4)) ||
+ if (__get_user(file, (char * __user *)(eip + 4)) ||
(unsigned long)file < PAGE_OFFSET || __get_user(c, file))
file = "<bad filename>";
@@ -294,6 +295,9 @@ bug:
printk("Kernel BUG\n");
}
+/* This is gone through when something in the kernel
+ * has done something bad and is about to be terminated.
+*/
void die(const char * str, struct pt_regs * regs, long err)
{
static struct {
@@ -341,6 +345,10 @@ void die(const char * str, struct pt_regs * regs, long err)
bust_spinlocks(0);
die.lock_owner = -1;
spin_unlock_irq(&die.lock);
+
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+
if (in_interrupt())
panic("Fatal exception in interrupt");
@@ -361,6 +369,10 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
static void do_trap(int trapnr, int signr, char *str, int vm86,
struct pt_regs * regs, long error_code, siginfo_t *info)
{
+ struct task_struct *tsk = current;
+ tsk->thread.error_code = error_code;
+ tsk->thread.trap_no = trapnr;
+
if (regs->eflags & VM_MASK) {
if (vm86)
goto vm86_trap;
@@ -371,9 +383,6 @@ static void do_trap(int trapnr, int signr, char *str, int vm86,
goto kernel_trap;
trap_signal: {
- struct task_struct *tsk = current;
- tsk->thread.error_code = error_code;
- tsk->thread.trap_no = trapnr;
if (info)
force_sig_info(signr, info, tsk);
else
@@ -486,6 +495,9 @@ fastcall void do_general_protection(struct pt_regs * regs, long error_code)
}
put_cpu();
+ current->thread.error_code = error_code;
+ current->thread.trap_no = 13;
+
if (regs->eflags & VM_MASK)
goto gp_in_vm86;
@@ -570,6 +582,15 @@ void die_nmi (struct pt_regs *regs, const char *msg)
console_silent();
spin_unlock(&nmi_print_lock);
bust_spinlocks(0);
+
+ /* If we are in kernel we are probably nested up pretty bad
+ * and might aswell get out now while we still can.
+ */
+ if (!user_mode(regs)) {
+ current->thread.trap_no = 2;
+ crash_kexec(regs);
+ }
+
do_exit(SIGSEGV);
}
@@ -625,6 +646,14 @@ fastcall void do_nmi(struct pt_regs * regs, long error_code)
nmi_enter();
cpu = smp_processor_id();
+
+#ifdef CONFIG_HOTPLUG_CPU
+ if (!cpu_online(cpu)) {
+ nmi_exit();
+ return;
+ }
+#endif
+
++nmi_count(cpu);
if (!nmi_callback(regs, cpu))
@@ -872,9 +901,9 @@ fastcall void do_simd_coprocessor_error(struct pt_regs * regs,
error_code);
return;
}
- die_if_kernel("cache flush denied", regs, error_code);
current->thread.trap_no = 19;
current->thread.error_code = error_code;
+ die_if_kernel("cache flush denied", regs, error_code);
force_sig(SIGSEGV, current);
}
}
diff --git a/arch/i386/kernel/vmlinux.lds.S b/arch/i386/kernel/vmlinux.lds.S
index e0512cc8bea7..761972f8cb6c 100644
--- a/arch/i386/kernel/vmlinux.lds.S
+++ b/arch/i386/kernel/vmlinux.lds.S
@@ -2,20 +2,23 @@
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
+#define LOAD_OFFSET __PAGE_OFFSET
+
#include <asm-generic/vmlinux.lds.h>
#include <asm/thread_info.h>
#include <asm/page.h>
OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386")
OUTPUT_ARCH(i386)
-ENTRY(startup_32)
+ENTRY(phys_startup_32)
jiffies = jiffies_64;
SECTIONS
{
- . = __PAGE_OFFSET + 0x100000;
+ . = __KERNEL_START;
+ phys_startup_32 = startup_32 - LOAD_OFFSET;
/* read-only */
_text = .; /* Text and read-only data */
- .text : {
+ .text : AT(ADDR(.text) - LOAD_OFFSET) {
*(.text)
SCHED_TEXT
LOCK_TEXT
@@ -27,49 +30,58 @@ SECTIONS
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
- __ex_table : { *(__ex_table) }
+ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
RODATA
/* writeable */
- .data : { /* Data */
+ .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */
*(.data)
CONSTRUCTORS
}
. = ALIGN(4096);
__nosave_begin = .;
- .data_nosave : { *(.data.nosave) }
+ .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
. = ALIGN(4096);
__nosave_end = .;
. = ALIGN(4096);
- .data.page_aligned : { *(.data.idt) }
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+ *(.data.idt)
+ }
. = ALIGN(32);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+ *(.data.cacheline_aligned)
+ }
+ /* rarely changed data like cpu maps */
+ . = ALIGN(32);
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) }
_edata = .; /* End of data section */
. = ALIGN(THREAD_SIZE); /* init_task */
- .data.init_task : { *(.data.init_task) }
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+ *(.data.init_task)
+ }
/* will be freed after init */
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
- .init.text : {
+ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
_sinittext = .;
*(.init.text)
_einittext = .;
}
- .init.data : { *(.init.data) }
+ .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
. = ALIGN(16);
__setup_start = .;
- .init.setup : { *(.init.setup) }
+ .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : {
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
@@ -80,33 +92,41 @@ SECTIONS
}
__initcall_end = .;
__con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
+ .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+ *(.con_initcall.init)
+ }
__con_initcall_end = .;
SECURITY_INIT
. = ALIGN(4);
__alt_instructions = .;
- .altinstructions : { *(.altinstructions) }
+ .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+ *(.altinstructions)
+ }
__alt_instructions_end = .;
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+ *(.altinstr_replacement)
+ }
/* .exit.text is discard at runtime, not link time, to deal with references
from .altinstructions and .eh_frame */
- .exit.text : { *(.exit.text) }
- .exit.data : { *(.exit.data) }
+ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+ .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
. = ALIGN(4096);
__initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
+ .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(32);
__per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
+ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
/* freed after init ends here */
__bss_start = .; /* BSS */
- .bss : {
+ .bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) {
*(.bss.page_aligned)
+ }
+ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
*(.bss)
}
. = ALIGN(4);
diff --git a/arch/i386/mach-default/setup.c b/arch/i386/mach-default/setup.c
index 0aa08eaa8932..e5a1a83d09ef 100644
--- a/arch/i386/mach-default/setup.c
+++ b/arch/i386/mach-default/setup.c
@@ -10,6 +10,14 @@
#include <asm/acpi.h>
#include <asm/arch_hooks.h>
+#ifdef CONFIG_HOTPLUG_CPU
+#define DEFAULT_SEND_IPI (1)
+#else
+#define DEFAULT_SEND_IPI (0)
+#endif
+
+int no_broadcast=DEFAULT_SEND_IPI;
+
/**
* pre_intr_init_hook - initialisation prior to setting up interrupt vectors
*
@@ -104,3 +112,22 @@ void __init mca_nmi_hook(void)
printk("NMI generated from unknown source!\n");
}
#endif
+
+static __init int no_ipi_broadcast(char *str)
+{
+ get_option(&str, &no_broadcast);
+ printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
+ "IPI Broadcast");
+ return 1;
+}
+
+__setup("no_ipi_broadcast", no_ipi_broadcast);
+
+static int __init print_ipi_mode(void)
+{
+ printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
+ "Shortcut");
+ return 0;
+}
+
+late_initcall(print_ipi_mode);
diff --git a/arch/i386/mach-default/topology.c b/arch/i386/mach-default/topology.c
index 5b3e8817dae8..23395fff35d1 100644
--- a/arch/i386/mach-default/topology.c
+++ b/arch/i386/mach-default/topology.c
@@ -73,12 +73,11 @@ static int __init topology_init(void)
{
int i;
- for (i = 0; i < MAX_NUMNODES; i++) {
- if (node_online(i))
- arch_register_node(i);
- }
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_possible(i)) arch_register_cpu(i);
+ for_each_online_node(i)
+ arch_register_node(i);
+
+ for_each_cpu(i)
+ arch_register_cpu(i);
return 0;
}
@@ -88,8 +87,8 @@ static int __init topology_init(void)
{
int i;
- for (i = 0; i < NR_CPUS; i++)
- if (cpu_possible(i)) arch_register_cpu(i);
+ for_each_cpu(i)
+ arch_register_cpu(i);
return 0;
}
diff --git a/arch/i386/mach-visws/mpparse.c b/arch/i386/mach-visws/mpparse.c
index 5a22082147f4..5f3d7e6de37b 100644
--- a/arch/i386/mach-visws/mpparse.c
+++ b/arch/i386/mach-visws/mpparse.c
@@ -23,7 +23,6 @@ unsigned long mp_lapic_addr;
/* Processor that is doing the boot up */
unsigned int boot_cpu_physical_apicid = -1U;
-unsigned int boot_cpu_logical_apicid = -1U;
/* Bitmask of physically existing CPUs */
physid_mask_t phys_cpu_present_map;
@@ -52,10 +51,8 @@ static void __init MP_processor_info (struct mpc_config_processor *m)
(m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
m->mpc_apicver);
- if (m->mpc_cpuflag & CPU_BOOTPROCESSOR) {
+ if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
boot_cpu_physical_apicid = m->mpc_apicid;
- boot_cpu_logical_apicid = logical_apicid;
- }
ver = m->mpc_apicver;
if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
diff --git a/arch/i386/mach-voyager/voyager_basic.c b/arch/i386/mach-voyager/voyager_basic.c
index 602aea240e9b..3e439ce5e1b2 100644
--- a/arch/i386/mach-voyager/voyager_basic.c
+++ b/arch/i386/mach-voyager/voyager_basic.c
@@ -30,6 +30,7 @@
#include <linux/irq.h>
#include <asm/tlbflush.h>
#include <asm/arch_hooks.h>
+#include <asm/i8253.h>
/*
* Power off function, if any
@@ -182,7 +183,6 @@ voyager_timer_interrupt(struct pt_regs *regs)
* and swiftly introduce it to something sharp and
* pointy. */
__u16 val;
- extern spinlock_t i8253_lock;
spin_lock(&i8253_lock);
diff --git a/arch/i386/mm/discontig.c b/arch/i386/mm/discontig.c
index f429c871e845..b358f0702a44 100644
--- a/arch/i386/mm/discontig.c
+++ b/arch/i386/mm/discontig.c
@@ -30,6 +30,8 @@
#include <linux/initrd.h>
#include <linux/nodemask.h>
#include <linux/module.h>
+#include <linux/kexec.h>
+
#include <asm/e820.h>
#include <asm/setup.h>
#include <asm/mmzone.h>
diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
index a509237c4815..8e90339d6eaa 100644
--- a/arch/i386/mm/fault.c
+++ b/arch/i386/mm/fault.c
@@ -146,7 +146,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
if (instr > limit)
break;
- if (__get_user(opcode, (unsigned char *) instr))
+ if (__get_user(opcode, (unsigned char __user *) instr))
break;
instr_hi = opcode & 0xf0;
@@ -173,7 +173,7 @@ static int __is_prefetch(struct pt_regs *regs, unsigned long addr)
scan_more = 0;
if (instr > limit)
break;
- if (__get_user(opcode, (unsigned char *) instr))
+ if (__get_user(opcode, (unsigned char __user *) instr))
break;
prefetch = (instr_lo == 0xF) &&
(opcode == 0x0D || opcode == 0x18);
@@ -463,6 +463,9 @@ no_context:
printk(KERN_ALERT "*pte = %08lx\n", page);
}
#endif
+ tsk->thread.cr2 = address;
+ tsk->thread.trap_no = 14;
+ tsk->thread.error_code = error_code;
die("Oops", regs, error_code);
bust_spinlocks(0);
do_exit(SIGKILL);
diff --git a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
index 4b7aaf99d7ea..b6eb4dcb8777 100644
--- a/arch/i386/mm/highmem.c
+++ b/arch/i386/mm/highmem.c
@@ -75,6 +75,24 @@ void kunmap_atomic(void *kvaddr, enum km_type type)
preempt_check_resched();
}
+/* This is the same as kmap_atomic() but can map memory that doesn't
+ * have a struct page associated with it.
+ */
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type)
+{
+ enum fixed_addresses idx;
+ unsigned long vaddr;
+
+ inc_preempt_count();
+
+ idx = type + KM_TYPE_NR*smp_processor_id();
+ vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
+ set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot));
+ __flush_tlb_one(vaddr);
+
+ return (void*) vaddr;
+}
+
struct page *kmap_atomic_to_page(void *ptr)
{
unsigned long idx, vaddr = (unsigned long)ptr;
diff --git a/arch/i386/mm/init.c b/arch/i386/mm/init.c
index 3672e2ef51ae..12216b52e28b 100644
--- a/arch/i386/mm/init.c
+++ b/arch/i386/mm/init.c
@@ -352,7 +352,7 @@ static void __init pagetable_init (void)
#endif
}
-#if defined(CONFIG_PM_DISK) || defined(CONFIG_SOFTWARE_SUSPEND)
+#ifdef CONFIG_SOFTWARE_SUSPEND
/*
* Swap suspend & friends need this for resume because things like the intel-agp
* driver might have split up a kernel 4MB mapping.
diff --git a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
index d393eefc7052..f379b8d67558 100644
--- a/arch/i386/mm/ioremap.c
+++ b/arch/i386/mm/ioremap.c
@@ -228,7 +228,8 @@ EXPORT_SYMBOL(ioremap_nocache);
void iounmap(volatile void __iomem *addr)
{
struct vm_struct *p;
- if ((void __force *) addr <= high_memory)
+
+ if ((void __force *)addr <= high_memory)
return;
/*
@@ -241,9 +242,10 @@ void iounmap(volatile void __iomem *addr)
return;
write_lock(&vmlist_lock);
- p = __remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
+ p = __remove_vm_area((void *)(PAGE_MASK & (unsigned long __force)addr));
if (!p) {
- printk("iounmap: bad address %p\n", addr);
+ printk(KERN_WARNING "iounmap: bad address %p\n", addr);
+ dump_stack();
goto out_unlock;
}
diff --git a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
index 270c59f099a4..bd2f7afc7a2a 100644
--- a/arch/i386/mm/pgtable.c
+++ b/arch/i386/mm/pgtable.c
@@ -32,9 +32,9 @@ void show_mem(void)
unsigned long i;
struct page_state ps;
- printk("Mem-info:\n");
+ printk(KERN_INFO "Mem-info:\n");
show_free_areas();
- printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ printk(KERN_INFO "Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
for_each_pgdat(pgdat) {
for (i = 0; i < pgdat->node_spanned_pages; ++i) {
page = pgdat_page_nr(pgdat, i);
@@ -49,18 +49,18 @@ void show_mem(void)
shared += page_count(page) - 1;
}
}
- printk("%d pages of RAM\n", total);
- printk("%d pages of HIGHMEM\n",highmem);
- printk("%d reserved pages\n",reserved);
- printk("%d pages shared\n",shared);
- printk("%d pages swap cached\n",cached);
+ printk(KERN_INFO "%d pages of RAM\n", total);
+ printk(KERN_INFO "%d pages of HIGHMEM\n", highmem);
+ printk(KERN_INFO "%d reserved pages\n", reserved);
+ printk(KERN_INFO "%d pages shared\n", shared);
+ printk(KERN_INFO "%d pages swap cached\n", cached);
get_page_state(&ps);
- printk("%lu pages dirty\n", ps.nr_dirty);
- printk("%lu pages writeback\n", ps.nr_writeback);
- printk("%lu pages mapped\n", ps.nr_mapped);
- printk("%lu pages slab\n", ps.nr_slab);
- printk("%lu pages pagetables\n", ps.nr_page_table_pages);
+ printk(KERN_INFO "%lu pages dirty\n", ps.nr_dirty);
+ printk(KERN_INFO "%lu pages writeback\n", ps.nr_writeback);
+ printk(KERN_INFO "%lu pages mapped\n", ps.nr_mapped);
+ printk(KERN_INFO "%lu pages slab\n", ps.nr_slab);
+ printk(KERN_INFO "%lu pages pagetables\n", ps.nr_page_table_pages);
}
/*
@@ -113,16 +113,16 @@ void set_pmd_pfn(unsigned long vaddr, unsigned long pfn, pgprot_t flags)
pmd_t *pmd;
if (vaddr & (PMD_SIZE-1)) { /* vaddr is misaligned */
- printk ("set_pmd_pfn: vaddr misaligned\n");
+ printk(KERN_WARNING "set_pmd_pfn: vaddr misaligned\n");
return; /* BUG(); */
}
if (pfn & (PTRS_PER_PTE-1)) { /* pfn is misaligned */
- printk ("set_pmd_pfn: pfn misaligned\n");
+ printk(KERN_WARNING "set_pmd_pfn: pfn misaligned\n");
return; /* BUG(); */
}
pgd = swapper_pg_dir + pgd_index(vaddr);
if (pgd_none(*pgd)) {
- printk ("set_pmd_pfn: pgd_none\n");
+ printk(KERN_WARNING "set_pmd_pfn: pgd_none\n");
return; /* BUG(); */
}
pud = pud_offset(pgd, vaddr);
diff --git a/arch/i386/pci/common.c b/arch/i386/pci/common.c
index 720975e1af50..70bcd53451f6 100644
--- a/arch/i386/pci/common.c
+++ b/arch/i386/pci/common.c
@@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
int pci_routeirq;
int pcibios_last_bus = -1;
-struct pci_bus *pci_root_bus = NULL;
+unsigned long pirq_table_addr;
+struct pci_bus *pci_root_bus;
struct pci_raw_ops *raw_pci_ops;
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
@@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
- return pci_scan_bus(busnum, &pci_root_ops, NULL);
+ return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
}
extern u8 pci_cache_line_size;
@@ -164,6 +165,7 @@ static int __init pcibios_init(void)
if ((pci_probe & PCI_BIOS_SORT) && !(pci_probe & PCI_NO_SORT))
pcibios_sort();
#endif
+ pci_assign_unassigned_resources();
return 0;
}
@@ -188,6 +190,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "biosirq")) {
pci_probe |= PCI_BIOS_IRQ_SCAN;
return NULL;
+ } else if (!strncmp(str, "pirqaddr=", 9)) {
+ pirq_table_addr = simple_strtoul(str+9, NULL, 0);
+ return NULL;
}
#endif
#ifdef CONFIG_PCI_DIRECT
diff --git a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c
index c205ea7e233b..93a364c82150 100644
--- a/arch/i386/pci/i386.c
+++ b/arch/i386/pci/i386.c
@@ -106,11 +106,16 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
if ((dev = bus->self)) {
for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
r = &dev->resource[idx];
- if (!r->start)
+ if (!r->flags)
continue;
pr = pci_find_parent_resource(dev, r);
- if (!pr || request_resource(pr, r) < 0)
+ if (!r->start || !pr || request_resource(pr, r) < 0) {
printk(KERN_ERR "PCI: Cannot allocate resource region %d of bridge %s\n", idx, pci_name(dev));
+ /* Something is wrong with the region.
+ Invalidate the resource to prevent child
+ resource allocations in this range. */
+ r->flags = 0;
+ }
}
}
pcibios_allocate_bus_resources(&bus->children);
@@ -227,7 +232,7 @@ int pcibios_enable_resources(struct pci_dev *dev, int mask)
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
- for(idx=0; idx<6; idx++) {
+ for(idx = 0; idx < PCI_NUM_RESOURCES; idx++) {
/* Only set up the requested stuff */
if (!(mask & (1<<idx)))
continue;
diff --git a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c
index 83458f81e661..766b104ac1a1 100644
--- a/arch/i386/pci/irq.c
+++ b/arch/i386/pci/irq.c
@@ -58,6 +58,35 @@ struct irq_router_handler {
int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
/*
+ * Check passed address for the PCI IRQ Routing Table signature
+ * and perform checksum verification.
+ */
+
+static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
+{
+ struct irq_routing_table *rt;
+ int i;
+ u8 sum;
+
+ rt = (struct irq_routing_table *) addr;
+ if (rt->signature != PIRQ_SIGNATURE ||
+ rt->version != PIRQ_VERSION ||
+ rt->size % 16 ||
+ rt->size < sizeof(struct irq_routing_table))
+ return NULL;
+ sum = 0;
+ for (i=0; i < rt->size; i++)
+ sum += addr[i];
+ if (!sum) {
+ DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+ return rt;
+ }
+ return NULL;
+}
+
+
+
+/*
* Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
*/
@@ -65,23 +94,17 @@ static struct irq_routing_table * __init pirq_find_routing_table(void)
{
u8 *addr;
struct irq_routing_table *rt;
- int i;
- u8 sum;
+ if (pirq_table_addr) {
+ rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
+ if (rt)
+ return rt;
+ printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
+ }
for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
- rt = (struct irq_routing_table *) addr;
- if (rt->signature != PIRQ_SIGNATURE ||
- rt->version != PIRQ_VERSION ||
- rt->size % 16 ||
- rt->size < sizeof(struct irq_routing_table))
- continue;
- sum = 0;
- for(i=0; i<rt->size; i++)
- sum += addr[i];
- if (!sum) {
- DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
+ rt = pirq_check_routing_table(addr);
+ if (rt)
return rt;
- }
}
return NULL;
}
@@ -1028,24 +1051,28 @@ static int __init pcibios_irq_init(void)
subsys_initcall(pcibios_irq_init);
-static void pirq_penalize_isa_irq(int irq)
+static void pirq_penalize_isa_irq(int irq, int active)
{
/*
* If any ISAPnP device reports an IRQ in its list of possible
* IRQ's, we try to avoid assigning it to PCI devices.
*/
- if (irq < 16)
- pirq_penalty[irq] += 100;
+ if (irq < 16) {
+ if (active)
+ pirq_penalty[irq] += 1000;
+ else
+ pirq_penalty[irq] += 100;
+ }
}
-void pcibios_penalize_isa_irq(int irq)
+void pcibios_penalize_isa_irq(int irq, int active)
{
#ifdef CONFIG_ACPI_PCI
if (!acpi_noirq)
- acpi_penalize_isa_irq(irq);
+ acpi_penalize_isa_irq(irq, active);
else
#endif
- pirq_penalize_isa_irq(irq);
+ pirq_penalize_isa_irq(irq, active);
}
static int pirq_enable_irq(struct pci_dev *dev)
diff --git a/arch/i386/pci/legacy.c b/arch/i386/pci/legacy.c
index 1492e3753869..149a9588c256 100644
--- a/arch/i386/pci/legacy.c
+++ b/arch/i386/pci/legacy.c
@@ -45,6 +45,8 @@ static int __init pci_legacy_init(void)
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0);
+ if (pci_root_bus)
+ pci_bus_add_devices(pci_root_bus);
pcibios_fixup_peer_bridges();
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index 021a50aa51f4..60f0e7a1162a 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -11,11 +11,9 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/acpi.h>
#include "pci.h"
-/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
-u32 pci_mmcfg_base_addr;
-
#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
/* The base address of the last MMCONFIG device accessed */
@@ -24,10 +22,31 @@ static u32 mmcfg_last_accessed_device;
/*
* Functions for accessing PCI configuration space with MMCONFIG accesses
*/
+static u32 get_base_addr(unsigned int seg, int bus)
+{
+ int cfg_num = -1;
+ struct acpi_table_mcfg_config *cfg;
+
+ while (1) {
+ ++cfg_num;
+ if (cfg_num >= pci_mmcfg_config_num) {
+ /* something bad is going on, no cfg table is found. */
+ /* so we fall back to the old way we used to do this */
+ /* and just rely on the first entry to be correct. */
+ return pci_mmcfg_config[0].base_address;
+ }
+ cfg = &pci_mmcfg_config[cfg_num];
+ if (cfg->pci_segment_group_number != seg)
+ continue;
+ if ((cfg->start_bus_number <= bus) &&
+ (cfg->end_bus_number >= bus))
+ return cfg->base_address;
+ }
+}
-static inline void pci_exp_set_dev_base(int bus, int devfn)
+static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn)
{
- u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
+ u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12);
if (dev_base != mmcfg_last_accessed_device) {
mmcfg_last_accessed_device = dev_base;
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
@@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags);
- pci_exp_set_dev_base(bus, devfn);
+ pci_exp_set_dev_base(seg, bus, devfn);
switch (len) {
case 1:
@@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags);
- pci_exp_set_dev_base(bus, devfn);
+ pci_exp_set_dev_base(seg, bus, devfn);
switch (len) {
case 1:
@@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void)
{
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
goto out;
- if (!pci_mmcfg_base_addr)
+
+ acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+ if ((pci_mmcfg_config_num == 0) ||
+ (pci_mmcfg_config == NULL) ||
+ (pci_mmcfg_config[0].base_address == 0))
goto out;
/* Kludge for now. Don't use mmconfig on AMD systems because
diff --git a/arch/i386/pci/numa.c b/arch/i386/pci/numa.c
index 9e3695461899..adbe17a38f6f 100644
--- a/arch/i386/pci/numa.c
+++ b/arch/i386/pci/numa.c
@@ -115,6 +115,8 @@ static int __init pci_numa_init(void)
return 0;
pci_root_bus = pcibios_scan_root(0);
+ if (pci_root_bus)
+ pci_bus_add_devices(pci_root_bus);
if (num_online_nodes() > 1)
for_each_online_node(quad) {
if (quad == 0)
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index a8fc80ca69f3..a80f0f55ff51 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -27,6 +27,7 @@
#define PCI_ASSIGN_ALL_BUSSES 0x4000
extern unsigned int pci_probe;
+extern unsigned long pirq_table_addr;
/* pci-i386.c */
diff --git a/arch/i386/pci/visws.c b/arch/i386/pci/visws.c
index 6a9248784439..314c933b6b8e 100644
--- a/arch/i386/pci/visws.c
+++ b/arch/i386/pci/visws.c
@@ -21,7 +21,7 @@ static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq;
-void __init pcibios_penalize_isa_irq(int irq) {}
+void __init pcibios_penalize_isa_irq(int irq, int active) {}
unsigned int pci_bus0, pci_bus1;
diff --git a/arch/i386/power/cpu.c b/arch/i386/power/cpu.c
index 6f521cf19a13..c547c1af6fa1 100644
--- a/arch/i386/power/cpu.c
+++ b/arch/i386/power/cpu.c
@@ -22,9 +22,11 @@
#include <linux/device.h>
#include <linux/suspend.h>
#include <linux/acpi.h>
+
#include <asm/uaccess.h>
#include <asm/acpi.h>
#include <asm/tlbflush.h>
+#include <asm/processor.h>
static struct saved_context saved_context;
@@ -33,8 +35,6 @@ unsigned long saved_context_esp, saved_context_ebp;
unsigned long saved_context_esi, saved_context_edi;
unsigned long saved_context_eflags;
-extern void enable_sep_cpu(void *);
-
void __save_processor_state(struct saved_context *ctxt)
{
kernel_fpu_begin();
@@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt)
*/
asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
- asm volatile ("sldt %0" : "=m" (ctxt->ldt));
asm volatile ("str %0" : "=m" (ctxt->tr));
/*
@@ -107,7 +106,6 @@ static void fix_processor_context(void)
void __restore_processor_state(struct saved_context *ctxt)
{
-
/*
* control registers
*/
@@ -117,6 +115,13 @@ void __restore_processor_state(struct saved_context *ctxt)
asm volatile ("movl %0, %%cr0" :: "r" (ctxt->cr0));
/*
+ * now restore the descriptor tables to their proper values
+ * ltr is done i fix_processor_context().
+ */
+ asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
+ asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+
+ /*
* segment registers
*/
asm volatile ("movw %0, %%es" :: "r" (ctxt->es));
@@ -125,21 +130,14 @@ void __restore_processor_state(struct saved_context *ctxt)
asm volatile ("movw %0, %%ss" :: "r" (ctxt->ss));
/*
- * now restore the descriptor tables to their proper values
- * ltr is done i fix_processor_context().
- */
- asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
- asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
- asm volatile ("lldt %0" :: "m" (ctxt->ldt));
-
- /*
* sysenter MSRs
*/
if (boot_cpu_has(X86_FEATURE_SEP))
- enable_sep_cpu(NULL);
+ enable_sep_cpu();
fix_processor_context();
do_fpu_end();
+ mtrr_ap_init();
}
void restore_processor_state(void)
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 01b78e7f992e..2e08942339ad 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -423,6 +423,8 @@ endmenu
endif
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 487d2e36b0a6..c05613980300 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -99,7 +99,7 @@ CONFIG_ACPI_DEALLOCATE_IRQ=y
# Firmware Drivers
#
CONFIG_EFI_VARS=y
-# CONFIG_EFI_PCDP is not set
+CONFIG_EFI_PCDP=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
@@ -650,7 +650,7 @@ CONFIG_MMTIMER=y
#
# Console display driver support
#
-# CONFIG_VGA_CONSOLE is not set
+CONFIG_VGA_CONSOLE=y
CONFIG_DUMMY_CONSOLE=y
#
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index 47f45341ac62..73454eee26f1 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-20050621
-# Tue Jun 21 14:03:24 2005
+# Linux kernel version: 2.6.13-rc1-20050629
+# Wed Jun 29 15:28:12 2005
#
#
@@ -80,18 +80,29 @@ CONFIG_MCKINLEY=y
# CONFIG_IA64_PAGE_SIZE_8KB is not set
CONFIG_IA64_PAGE_SIZE_16KB=y
# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
CONFIG_IA64_L1_CACHE_SHIFT=7
# CONFIG_NUMA is not set
CONFIG_VIRTUAL_MEM_MAP=y
CONFIG_HOLES_IN_ZONE=y
CONFIG_IA64_CYCLONE=y
CONFIG_IOSAPIC=y
+# CONFIG_IA64_SGI_SN_XP is not set
CONFIG_FORCE_MAX_ZONEORDER=18
CONFIG_SMP=y
CONFIG_NR_CPUS=4
CONFIG_HOTPLUG_CPU=y
# CONFIG_SCHED_SMT is not set
# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_IA32_SUPPORT=y
CONFIG_COMPAT=y
@@ -257,6 +268,7 @@ CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -395,6 +407,7 @@ CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_MULTICAST=y
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
@@ -407,6 +420,8 @@ CONFIG_SYN_COOKIES=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -598,9 +613,7 @@ CONFIG_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
#
# Character devices
@@ -629,7 +642,6 @@ 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
#
@@ -743,6 +755,7 @@ CONFIG_USB_DEVICEFS=y
CONFIG_USB_EHCI_HCD=m
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=m
# CONFIG_USB_OHCI_BIG_ENDIAN is not set
CONFIG_USB_OHCI_LITTLE_ENDIAN=y
@@ -779,9 +792,11 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_HIDDEV is not set
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
# CONFIG_USB_EGALAX is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
@@ -838,7 +853,7 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_USB_TEST is not set
#
-# USB ATM/DSL drivers
+# USB DSL modem support
#
#
@@ -857,12 +872,17 @@ CONFIG_USB_HIDINPUT=y
# CONFIG_INFINIBAND is not set
#
+# SN Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
CONFIG_EXT2_FS_POSIX_ACL=y
CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
CONFIG_EXT3_FS_POSIX_ACL=y
@@ -922,7 +942,6 @@ CONFIG_NTFS_FS=m
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_TMPFS_XATTR=y
@@ -953,15 +972,18 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=m
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
CONFIG_NFS_DIRECTIO=y
CONFIG_NFSD=m
CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
CONFIG_NFSD_V4=y
CONFIG_NFSD_TCP=y
CONFIG_LOCKD=m
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=m
CONFIG_SUNRPC_GSS=m
CONFIG_RPCSEC_GSS_KRB5=m
@@ -1069,6 +1091,7 @@ CONFIG_LOG_BUF_SHIFT=20
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
# CONFIG_DEBUG_FS is not set
+# CONFIG_KPROBES is not set
CONFIG_IA64_GRANULE_16MB=y
# CONFIG_IA64_GRANULE_64MB is not set
# CONFIG_IA64_PRINT_HAZARDS is not set
@@ -1090,7 +1113,7 @@ 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_MD5=y
# CONFIG_CRYPTO_SHA1 is not set
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index 21d6f9bab5e9..b7755e4436d2 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.10
-# Wed Dec 29 09:05:48 2004
+# Linux kernel version: 2.6.13-rc1-20050629
+# Wed Jun 29 15:31:11 2005
#
#
@@ -12,6 +12,7 @@ CONFIG_EXPERIMENTAL=y
CONFIG_BROKEN=y
CONFIG_BROKEN_ON_SMP=y
CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
#
# General setup
@@ -24,23 +25,26 @@ 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_KOBJECT_UEVENT=y
# CONFIG_IKCONFIG is not set
+# CONFIG_CPUSETS 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_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
-# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
CONFIG_SHMEM=y
CONFIG_CC_ALIGN_FUNCTIONS=0
CONFIG_CC_ALIGN_LABELS=0
CONFIG_CC_ALIGN_LOOPS=0
CONFIG_CC_ALIGN_JUMPS=0
# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
#
# Loadable module support
@@ -59,12 +63,15 @@ CONFIG_IA64=y
CONFIG_64BIT=y
CONFIG_MMU=y
CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
CONFIG_TIME_INTERPOLATION=y
CONFIG_EFI=y
CONFIG_GENERIC_IOMAP=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
# CONFIG_IA64_GENERIC is not set
# CONFIG_IA64_DIG is not set
CONFIG_IA64_HP_ZX1=y
+# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
# CONFIG_IA64_SGI_SN2 is not set
# CONFIG_IA64_HP_SIM is not set
# CONFIG_ITANIUM is not set
@@ -73,22 +80,36 @@ CONFIG_MCKINLEY=y
# CONFIG_IA64_PAGE_SIZE_8KB is not set
CONFIG_IA64_PAGE_SIZE_16KB=y
# CONFIG_IA64_PAGE_SIZE_64KB is not set
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
CONFIG_IA64_L1_CACHE_SHIFT=7
# CONFIG_NUMA is not set
CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_HOLES_IN_ZONE=y
# CONFIG_IA64_CYCLONE is not set
CONFIG_IOSAPIC=y
+# CONFIG_IA64_SGI_SN_XP is not set
CONFIG_FORCE_MAX_ZONEORDER=18
CONFIG_SMP=y
CONFIG_NR_CPUS=16
# CONFIG_HOTPLUG_CPU is not set
+# CONFIG_SCHED_SMT is not set
# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
CONFIG_HAVE_DEC_LOCK=y
CONFIG_IA32_SUPPORT=y
CONFIG_COMPAT=y
CONFIG_IA64_MCA_RECOVERY=y
CONFIG_PERFMON=y
CONFIG_IA64_PALINFO=y
+CONFIG_ACPI_DEALLOCATE_IRQ=y
#
# Firmware Drivers
@@ -120,6 +141,7 @@ CONFIG_ACPI_BUS=y
CONFIG_ACPI_POWER=y
CONFIG_ACPI_PCI=y
CONFIG_ACPI_SYSTEM=y
+# CONFIG_ACPI_CONTAINER is not set
#
# Bus options (PCI, PCMCIA)
@@ -129,6 +151,7 @@ CONFIG_PCI_DOMAINS=y
# CONFIG_PCI_MSI is not set
CONFIG_PCI_LEGACY_PROC=y
CONFIG_PCI_NAMES=y
+# CONFIG_PCI_DEBUG is not set
#
# PCI Hotplug Support
@@ -138,7 +161,6 @@ CONFIG_HOTPLUG_PCI=y
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
#
@@ -147,10 +169,6 @@ CONFIG_HOTPLUG_PCI_ACPI=y
# CONFIG_PCCARD is not set
#
-# PC-card bridges
-#
-
-#
# Device Drivers
#
@@ -184,6 +202,7 @@ CONFIG_PREVENT_FIRMWARE_BUILD=y
# 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_COW_COMMON is not set
CONFIG_BLK_DEV_LOOP=y
# CONFIG_BLK_DEV_CRYPTOLOOP is not set
# CONFIG_BLK_DEV_NBD is not set
@@ -203,6 +222,7 @@ CONFIG_IOSCHED_NOOP=y
CONFIG_IOSCHED_AS=y
CONFIG_IOSCHED_DEADLINE=y
CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
#
# ATA/ATAPI/MFM/RLL support
@@ -246,6 +266,7 @@ CONFIG_BLK_DEV_CMD64X=y
# CONFIG_BLK_DEV_HPT366 is not set
# CONFIG_BLK_DEV_SC1200 is not set
# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT821X is not set
# CONFIG_BLK_DEV_NS87415 is not set
# CONFIG_BLK_DEV_PDC202XX_OLD is not set
# CONFIG_BLK_DEV_PDC202XX_NEW is not set
@@ -275,6 +296,7 @@ CONFIG_CHR_DEV_OSST=y
CONFIG_BLK_DEV_SR=y
CONFIG_BLK_DEV_SR_VENDOR=y
CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
#
# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
@@ -288,6 +310,7 @@ CONFIG_SCSI_LOGGING=y
#
CONFIG_SCSI_SPI_ATTRS=y
# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
#
# SCSI low-level drivers
@@ -303,13 +326,10 @@ CONFIG_SCSI_SPI_ATTRS=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
# 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_INITIO is not set
# CONFIG_SCSI_INIA100 is not set
@@ -319,8 +339,6 @@ 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
# CONFIG_SCSI_QLOGIC_FC is not set
CONFIG_SCSI_QLOGIC_1280=y
@@ -331,7 +349,7 @@ CONFIG_SCSI_QLA2XXX=y
# 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_LPFC is not set
# CONFIG_SCSI_DC395x is not set
# CONFIG_SCSI_DC390T is not set
# CONFIG_SCSI_DEBUG is not set
@@ -344,9 +362,9 @@ CONFIG_SCSI_QLA2XXX=y
#
# Fusion MPT device support
#
-CONFIG_FUSION=y
-CONFIG_FUSION_MAX_SGE=40
-# CONFIG_FUSION_CTL is not set
+# CONFIG_FUSION is not set
+# CONFIG_FUSION_SPI is not set
+# CONFIG_FUSION_FC is not set
#
# IEEE 1394 (FireWire) support
@@ -368,12 +386,12 @@ CONFIG_NET=y
#
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=y
# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
# CONFIG_IP_PNP is not set
# CONFIG_NET_IPIP is not set
# CONFIG_NET_IPGRE is not set
@@ -386,6 +404,8 @@ CONFIG_IP_MULTICAST=y
# CONFIG_INET_TUNNEL is not set
# CONFIG_IP_TCPDIAG is not set
# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
#
# IP: Virtual Server Configuration
@@ -405,8 +425,6 @@ CONFIG_NETFILTER=y
CONFIG_IP_NF_ARPTABLES=y
# CONFIG_IP_NF_ARPFILTER is not set
# CONFIG_IP_NF_ARP_MANGLE is not set
-# CONFIG_IP_NF_COMPAT_IPCHAINS is not set
-# CONFIG_IP_NF_COMPAT_IPFWADM is not set
#
# SCTP Configuration (EXPERIMENTAL)
@@ -483,7 +501,6 @@ CONFIG_NET_PCI=y
# CONFIG_DGRS 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
@@ -505,9 +522,11 @@ CONFIG_E1000=y
# CONFIG_HAMACHI is not set
# CONFIG_YELLOWFIN is not set
# CONFIG_R8169 is not set
+# CONFIG_SKGE is not set
# CONFIG_SK98LIN is not set
# CONFIG_VIA_VELOCITY is not set
CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
#
# Ethernet (10000 Mbit)
@@ -565,18 +584,6 @@ 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 is not set
-# 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 is not set
@@ -586,6 +593,16 @@ CONFIG_SERIO=y
# CONFIG_INPUT_MISC is not set
#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+# CONFIG_SERIO_I8042 is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
# Character devices
#
CONFIG_VT=y
@@ -603,7 +620,6 @@ CONFIG_SERIAL_8250_NR_UARTS=8
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
#
@@ -611,6 +627,7 @@ CONFIG_SERIAL_8250_SHARE_IRQ=y
#
CONFIG_SERIAL_CORE=y
CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
CONFIG_UNIX98_PTYS=y
CONFIG_LEGACY_PTYS=y
CONFIG_LEGACY_PTY_COUNT=256
@@ -644,6 +661,12 @@ CONFIG_DRM_RADEON=y
# CONFIG_DRM_SIS is not set
# CONFIG_RAW_DRIVER is not set
# CONFIG_HPET is not set
+# CONFIG_HANGCHECK_TIMER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
#
# I2C support
@@ -668,6 +691,7 @@ CONFIG_I2C_ALGOPCF=y
# CONFIG_I2C_AMD8111 is not set
# CONFIG_I2C_I801 is not set
# CONFIG_I2C_I810 is not set
+# CONFIG_I2C_PIIX4 is not set
# CONFIG_I2C_ISA is not set
# CONFIG_I2C_NFORCE2 is not set
# CONFIG_I2C_PARPORT_LIGHT is not set
@@ -691,10 +715,14 @@ CONFIG_I2C_ALGOPCF=y
# CONFIG_SENSORS_ADM1025 is not set
# CONFIG_SENSORS_ADM1026 is not set
# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
# CONFIG_SENSORS_DS1621 is not set
# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
# CONFIG_SENSORS_IT87 is not set
# CONFIG_SENSORS_LM63 is not set
# CONFIG_SENSORS_LM75 is not set
@@ -705,21 +733,29 @@ CONFIG_I2C_ALGOPCF=y
# CONFIG_SENSORS_LM85 is not set
# CONFIG_SENSORS_LM87 is not set
# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
# CONFIG_SENSORS_MAX1619 is not set
# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_SIS5595 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
+# CONFIG_SENSORS_W83627EHF is not set
#
# Other I2C Chip support
#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
# CONFIG_SENSORS_EEPROM is not set
# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
# CONFIG_SENSORS_PCF8591 is not set
# CONFIG_SENSORS_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
# CONFIG_I2C_DEBUG_CORE is not set
# CONFIG_I2C_DEBUG_ALGO is not set
# CONFIG_I2C_DEBUG_BUS is not set
@@ -746,6 +782,7 @@ CONFIG_VIDEO_DEV=y
#
# Video Adapters
#
+# CONFIG_TUNER_MULTI_I2C is not set
# CONFIG_VIDEO_BT848 is not set
# CONFIG_VIDEO_CPIA is not set
# CONFIG_VIDEO_SAA5246A is not set
@@ -778,6 +815,11 @@ CONFIG_VIDEO_DEV=y
# Graphics support
#
CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_TILEBLITTING is not set
# CONFIG_FB_CIRRUS is not set
@@ -785,6 +827,7 @@ CONFIG_FB_MODE_HELPERS=y
# CONFIG_FB_CYBER2000 is not set
# CONFIG_FB_ASILIANT is not set
# CONFIG_FB_IMSTT is not set
+# CONFIG_FB_NVIDIA is not set
# CONFIG_FB_RIVA is not set
# CONFIG_FB_MATROX is not set
# CONFIG_FB_RADEON_OLD is not set
@@ -801,6 +844,7 @@ CONFIG_FB_RADEON_DEBUG=y
# CONFIG_FB_VOODOO1 is not set
# CONFIG_FB_TRIDENT is not set
# CONFIG_FB_PM3 is not set
+# CONFIG_FB_S1D13XXX is not set
# CONFIG_FB_VIRTUAL is not set
#
@@ -820,6 +864,7 @@ CONFIG_LOGO=y
# CONFIG_LOGO_LINUX_MONO is not set
# CONFIG_LOGO_LINUX_VGA16 is not set
CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
#
# Sound
@@ -869,6 +914,8 @@ CONFIG_SND_AC97_CODEC=y
# CONFIG_SND_CS46XX is not set
# CONFIG_SND_CS4281 is not set
# CONFIG_SND_EMU10K1 is not set
+# CONFIG_SND_EMU10K1X is not set
+# CONFIG_SND_CA0106 is not set
# CONFIG_SND_KORG1212 is not set
# CONFIG_SND_MIXART is not set
# CONFIG_SND_NM256 is not set
@@ -876,6 +923,7 @@ CONFIG_SND_AC97_CODEC=y
# CONFIG_SND_RME96 is not set
# CONFIG_SND_RME9652 is not set
# CONFIG_SND_HDSP is not set
+# CONFIG_SND_HDSPM is not set
# CONFIG_SND_TRIDENT is not set
# CONFIG_SND_YMFPCI is not set
# CONFIG_SND_ALS4000 is not set
@@ -893,13 +941,14 @@ CONFIG_SND_FM801_TEA575X=y
# CONFIG_SND_INTEL8X0M is not set
# CONFIG_SND_SONICVIBES is not set
# CONFIG_SND_VIA82XX is not set
+# CONFIG_SND_VIA82XX_MODEM is not set
# CONFIG_SND_VX222 is not set
+# CONFIG_SND_HDA_INTEL is not set
#
# USB devices
#
# CONFIG_SND_USB_AUDIO is not set
-# CONFIG_SND_USB_USX2Y is not set
#
# Open Sound System
@@ -909,6 +958,8 @@ CONFIG_SND_FM801_TEA575X=y
#
# USB support
#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB=y
# CONFIG_USB_DEBUG is not set
@@ -920,8 +971,6 @@ CONFIG_USB_BANDWIDTH=y
# CONFIG_USB_DYNAMIC_MINORS is not set
# CONFIG_USB_SUSPEND is not set
# CONFIG_USB_OTG is not set
-CONFIG_USB_ARCH_HAS_HCD=y
-CONFIG_USB_ARCH_HAS_OHCI=y
#
# USB Host Controller Drivers
@@ -929,7 +978,10 @@ CONFIG_USB_ARCH_HAS_OHCI=y
CONFIG_USB_EHCI_HCD=y
# CONFIG_USB_EHCI_SPLIT_ISO is not set
# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_ISP116X_HCD is not set
CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
CONFIG_USB_UHCI_HCD=y
# CONFIG_USB_SL811_HCD is not set
@@ -947,12 +999,11 @@ CONFIG_USB_UHCI_HCD=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
# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_HP8200e is not set
+# CONFIG_USB_STORAGE_USBAT is not set
# CONFIG_USB_STORAGE_SDDR09 is not set
# CONFIG_USB_STORAGE_SDDR55 is not set
# CONFIG_USB_STORAGE_JUMPSHOT is not set
@@ -966,9 +1017,11 @@ CONFIG_USB_HIDINPUT=y
CONFIG_USB_HIDDEV=y
# CONFIG_USB_AIPTEK is not set
# CONFIG_USB_WACOM is not set
+# CONFIG_USB_ACECAD is not set
# CONFIG_USB_KBTAB is not set
# CONFIG_USB_POWERMATE is not set
# CONFIG_USB_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
# CONFIG_USB_EGALAX is not set
# CONFIG_USB_XPAD is not set
# CONFIG_USB_ATI_REMOTE is not set
@@ -978,7 +1031,6 @@ CONFIG_USB_HIDDEV=y
#
# CONFIG_USB_MDC800 is not set
# CONFIG_USB_MICROTEK is not set
-# CONFIG_USB_HPUSBSCSI is not set
#
# USB Multimedia devices
@@ -992,6 +1044,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_SE401 is not set
# CONFIG_USB_SN9C102 is not set
# CONFIG_USB_STV680 is not set
+# CONFIG_USB_PWC is not set
#
# USB Network Adapters
@@ -1001,6 +1054,7 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_PEGASUS is not set
# CONFIG_USB_RTL8150 is not set
# CONFIG_USB_USBNET is not set
+CONFIG_USB_MON=y
#
# USB port drivers
@@ -1016,7 +1070,6 @@ CONFIG_USB_HIDDEV=y
#
# 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
@@ -1025,9 +1078,11 @@ CONFIG_USB_HIDDEV=y
# CONFIG_USB_CYTHERM is not set
# CONFIG_USB_PHIDGETKIT is not set
# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_SISUSBVGA is not set
#
-# USB ATM/DSL drivers
+# USB DSL modem support
#
#
@@ -1041,12 +1096,22 @@ CONFIG_USB_HIDDEV=y
# CONFIG_MMC is not set
#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# SN Devices
+#
+
+#
# File systems
#
CONFIG_EXT2_FS=y
CONFIG_EXT2_FS_XATTR=y
# CONFIG_EXT2_FS_POSIX_ACL is not set
# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
CONFIG_EXT3_FS_XATTR=y
# CONFIG_EXT3_FS_POSIX_ACL is not set
@@ -1056,6 +1121,10 @@ CONFIG_JBD=y
CONFIG_FS_MBCACHE=y
# CONFIG_REISERFS_FS is not set
# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
@@ -1089,7 +1158,6 @@ CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
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_TMPFS_XATTR=y
@@ -1120,15 +1188,18 @@ CONFIG_RAMFS=y
#
CONFIG_NFS_FS=y
CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
CONFIG_NFS_V4=y
# CONFIG_NFS_DIRECTIO is not set
CONFIG_NFSD=y
CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
# CONFIG_NFSD_V4 is not set
# CONFIG_NFSD_TCP is not set
CONFIG_LOCKD=y
CONFIG_LOCKD_V4=y
CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
CONFIG_SUNRPC=y
CONFIG_SUNRPC_GSS=y
CONFIG_RPCSEC_GSS_KRB5=y
@@ -1209,6 +1280,8 @@ CONFIG_NLS_UTF8=y
# CONFIG_CRC_CCITT is not set
CONFIG_CRC32=y
# CONFIG_LIBCRC32C is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
#
# Profiling support
@@ -1218,14 +1291,18 @@ CONFIG_CRC32=y
#
# Kernel hacking
#
+# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=17
# CONFIG_SCHEDSTATS is not set
# CONFIG_DEBUG_SLAB is not set
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_FS is not set
+CONFIG_KPROBES=y
CONFIG_IA64_GRANULE_16MB=y
# CONFIG_IA64_GRANULE_64MB is not set
CONFIG_IA64_PRINT_HAZARDS=y
@@ -1252,6 +1329,7 @@ CONFIG_CRYPTO_MD5=y
# CONFIG_CRYPTO_SHA256 is not set
# CONFIG_CRYPTO_SHA512 is not set
# CONFIG_CRYPTO_WP512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
CONFIG_CRYPTO_DES=y
# CONFIG_CRYPTO_BLOWFISH is not set
# CONFIG_CRYPTO_TWOFISH is not set
diff --git a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
index b8db6e3e5e81..11957598a8b9 100644
--- a/arch/ia64/hp/common/sba_iommu.c
+++ b/arch/ia64/hp/common/sba_iommu.c
@@ -156,10 +156,13 @@
*/
#define DELAYED_RESOURCE_CNT 64
+#define PCI_DEVICE_ID_HP_SX2000_IOC 0x12ec
+
#define ZX1_IOC_ID ((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
#define ZX2_IOC_ID ((PCI_DEVICE_ID_HP_ZX2_IOC << 16) | PCI_VENDOR_ID_HP)
#define REO_IOC_ID ((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
#define SX1000_IOC_ID ((PCI_DEVICE_ID_HP_SX1000_IOC << 16) | PCI_VENDOR_ID_HP)
+#define SX2000_IOC_ID ((PCI_DEVICE_ID_HP_SX2000_IOC << 16) | PCI_VENDOR_ID_HP)
#define ZX1_IOC_OFFSET 0x1000 /* ACPI reports SBA, we want IOC */
@@ -1726,6 +1729,7 @@ static struct ioc_iommu ioc_iommu_info[] __initdata = {
{ ZX1_IOC_ID, "zx1", ioc_zx1_init },
{ ZX2_IOC_ID, "zx2", NULL },
{ SX1000_IOC_ID, "sx1000", NULL },
+ { SX2000_IOC_ID, "sx2000", NULL },
};
static struct ioc * __init
diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
index ae84a1018a89..0639ec0ed015 100644
--- a/arch/ia64/hp/sim/simeth.c
+++ b/arch/ia64/hp/sim/simeth.c
@@ -191,7 +191,7 @@ simeth_probe1(void)
unsigned char mac_addr[ETH_ALEN];
struct simeth_local *local;
struct net_device *dev;
- int fd, i, err;
+ int fd, i, err, rc;
/*
* XXX Fix me
@@ -228,7 +228,9 @@ simeth_probe1(void)
return err;
}
- dev->irq = assign_irq_vector(AUTO_ASSIGN);
+ if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
+ panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+ dev->irq = rc;
/*
* attach the interrupt in the simulator, this does enable interrupts
diff --git a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
index 786e70718ce4..7dcb8582ae0d 100644
--- a/arch/ia64/hp/sim/simserial.c
+++ b/arch/ia64/hp/sim/simserial.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/serial.h>
#include <linux/serialP.h>
+#include <linux/sysrq.h>
#include <asm/irq.h>
#include <asm/hw_irq.h>
@@ -149,12 +150,17 @@ static void receive_chars(struct tty_struct *tty, struct pt_regs *regs)
seen_esc = 2;
continue;
} else if ( seen_esc == 2 ) {
- if ( ch == 'P' ) show_state(); /* F1 key */
-#ifdef CONFIG_KDB
- if ( ch == 'S' )
- kdb(KDB_REASON_KEYBOARD, 0, (kdb_eframe_t) regs);
+ if ( ch == 'P' ) /* F1 */
+ show_state();
+#ifdef CONFIG_MAGIC_SYSRQ
+ if ( ch == 'S' ) { /* F4 */
+ do
+ ch = ia64_ssc(0, 0, 0, 0,
+ SSC_GETCHAR);
+ while (!ch);
+ handle_sysrq(ch, regs, NULL);
+ }
#endif
-
seen_esc = 0;
continue;
}
@@ -976,7 +982,7 @@ static struct tty_operations hp_ops = {
static int __init
simrs_init (void)
{
- int i;
+ int i, rc;
struct serial_state *state;
if (!ia64_platform_is("hpsim"))
@@ -1011,7 +1017,10 @@ simrs_init (void)
if (state->type == PORT_UNKNOWN) continue;
if (!state->irq) {
- state->irq = assign_irq_vector(AUTO_ASSIGN);
+ if ((rc = assign_irq_vector(AUTO_ASSIGN)) < 0)
+ panic("%s: out of interrupt vectors!\n",
+ __FUNCTION__);
+ state->irq = rc;
ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq);
}
diff --git a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
index b2e2f6509eb0..e1fb68ddec26 100644
--- a/arch/ia64/kernel/Makefile
+++ b/arch/ia64/kernel/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_IA64_PALINFO) += palinfo.o
obj-$(CONFIG_IOSAPIC) += iosapic.o
obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_SMP) += smp.o smpboot.o domain.o
+obj-$(CONFIG_NUMA) += numa.o
obj-$(CONFIG_PERFMON) += perfmon_default_smpl.o
obj-$(CONFIG_IA64_CYCLONE) += cyclone.o
obj-$(CONFIG_IA64_MCA_RECOVERY) += mca_recovery.o
diff --git a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
index 72dfd9e7de0f..9609f243e5d0 100644
--- a/arch/ia64/kernel/acpi.c
+++ b/arch/ia64/kernel/acpi.c
@@ -11,6 +11,7 @@
* Copyright (C) 2001 Jenna Hall <jenna.s.hall@intel.com>
* Copyright (C) 2001 Takayoshi Kochi <t-kochi@bq.jp.nec.com>
* Copyright (C) 2002 Erich Focht <efocht@ess.nec.de>
+ * Copyright (C) 2004 Ashok Raj <ashok.raj@intel.com>
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -67,6 +68,11 @@ EXPORT_SYMBOL(pm_power_off);
unsigned char acpi_kbd_controller_present = 1;
unsigned char acpi_legacy_devices;
+static unsigned int __initdata acpi_madt_rev;
+
+unsigned int acpi_cpei_override;
+unsigned int acpi_cpei_phys_cpuid;
+
#define MAX_SAPICS 256
u16 ia64_acpiid_to_sapicid[MAX_SAPICS] =
{ [0 ... MAX_SAPICS - 1] = -1 };
@@ -236,9 +242,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
if (BAD_MADT_ENTRY(iosapic, end))
return -EINVAL;
- iosapic_init(iosapic->address, iosapic->global_irq_base);
-
- return 0;
+ return iosapic_init(iosapic->address, iosapic->global_irq_base);
}
@@ -267,10 +271,56 @@ acpi_parse_plat_int_src (
(plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
platform_intr_list[plintsrc->type] = vector;
+ if (acpi_madt_rev > 1) {
+ acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag;
+ }
+
+ /*
+ * Save the physical id, so we can check when its being removed
+ */
+ acpi_cpei_phys_cpuid = ((plintsrc->id << 8) | (plintsrc->eid)) & 0xffff;
+
return 0;
}
+unsigned int can_cpei_retarget(void)
+{
+ extern int cpe_vector;
+
+ /*
+ * Only if CPEI is supported and the override flag
+ * is present, otherwise return that its re-targettable
+ * if we are in polling mode.
+ */
+ if (cpe_vector > 0 && !acpi_cpei_override)
+ return 0;
+ else
+ return 1;
+}
+
+unsigned int is_cpu_cpei_target(unsigned int cpu)
+{
+ unsigned int logical_id;
+
+ logical_id = cpu_logical_id(acpi_cpei_phys_cpuid);
+
+ if (logical_id == cpu)
+ return 1;
+ else
+ return 0;
+}
+
+void set_cpei_target_cpu(unsigned int cpu)
+{
+ acpi_cpei_phys_cpuid = cpu_physical_id(cpu);
+}
+
+unsigned int get_cpei_target_cpu(void)
+{
+ return acpi_cpei_phys_cpuid;
+}
+
static int __init
acpi_parse_int_src_ovr (
acpi_table_entry_header *header, const unsigned long end)
@@ -328,6 +378,8 @@ acpi_parse_madt (unsigned long phys_addr, unsigned long size)
acpi_madt = (struct acpi_table_madt *) __va(phys_addr);
+ acpi_madt_rev = acpi_madt->header.revision;
+
/* remember the value for reference after free_initmem() */
#ifdef CONFIG_ITANIUM
has_8259 = 1; /* Firmware on old Itanium systems is broken */
@@ -642,9 +694,11 @@ acpi_boot_init (void)
if (smp_boot_data.cpu_phys_id[cpu] != hard_smp_processor_id())
node_cpuid[i++].phys_id = smp_boot_data.cpu_phys_id[cpu];
}
- build_cpu_to_node_map();
# endif
#endif
+#ifdef CONFIG_ACPI_NUMA
+ build_cpu_to_node_map();
+#endif
/* Make boot-up look pretty */
printk(KERN_INFO "%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);
return 0;
@@ -772,7 +826,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
#ifdef CONFIG_ACPI_NUMA
-acpi_status __init
+acpi_status __devinit
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
{
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
@@ -825,4 +879,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
return AE_OK;
}
#endif /* CONFIG_NUMA */
+
+int
+acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
+{
+ int err;
+
+ if ((err = iosapic_init(phys_addr, gsi_base)))
+ return err;
+
+#if CONFIG_ACPI_NUMA
+ acpi_map_iosapic(handle, 0, NULL, NULL);
+#endif /* CONFIG_ACPI_NUMA */
+
+ return 0;
+}
+EXPORT_SYMBOL(acpi_register_ioapic);
+
+int
+acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
+{
+ return iosapic_remove(gsi_base);
+}
+EXPORT_SYMBOL(acpi_unregister_ioapic);
+
#endif /* CONFIG_ACPI_BOOT */
diff --git a/arch/ia64/kernel/domain.c b/arch/ia64/kernel/domain.c
index fe532c970438..d65e87b6394f 100644
--- a/arch/ia64/kernel/domain.c
+++ b/arch/ia64/kernel/domain.c
@@ -14,7 +14,7 @@
#include <linux/topology.h>
#include <linux/nodemask.h>
-#define SD_NODES_PER_DOMAIN 6
+#define SD_NODES_PER_DOMAIN 16
#ifdef CONFIG_NUMA
/**
@@ -27,7 +27,7 @@
*
* Should use nodemask_t.
*/
-static int __devinit find_next_best_node(int node, unsigned long *used_nodes)
+static int find_next_best_node(int node, unsigned long *used_nodes)
{
int i, n, val, min_val, best_node = 0;
@@ -66,7 +66,7 @@ static int __devinit find_next_best_node(int node, unsigned long *used_nodes)
* should be one that prevents unnecessary balancing, but also spreads tasks
* out optimally.
*/
-static cpumask_t __devinit sched_domain_node_span(int node)
+static cpumask_t sched_domain_node_span(int node)
{
int i;
cpumask_t span, nodemask;
@@ -96,7 +96,7 @@ static cpumask_t __devinit sched_domain_node_span(int node)
#ifdef CONFIG_SCHED_SMT
static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
static struct sched_group sched_group_cpus[NR_CPUS];
-static int __devinit cpu_to_cpu_group(int cpu)
+static int cpu_to_cpu_group(int cpu)
{
return cpu;
}
@@ -104,7 +104,7 @@ static int __devinit cpu_to_cpu_group(int cpu)
static DEFINE_PER_CPU(struct sched_domain, phys_domains);
static struct sched_group sched_group_phys[NR_CPUS];
-static int __devinit cpu_to_phys_group(int cpu)
+static int cpu_to_phys_group(int cpu)
{
#ifdef CONFIG_SCHED_SMT
return first_cpu(cpu_sibling_map[cpu]);
@@ -125,44 +125,36 @@ static struct sched_group *sched_group_nodes[MAX_NUMNODES];
static DEFINE_PER_CPU(struct sched_domain, allnodes_domains);
static struct sched_group sched_group_allnodes[MAX_NUMNODES];
-static int __devinit cpu_to_allnodes_group(int cpu)
+static int cpu_to_allnodes_group(int cpu)
{
return cpu_to_node(cpu);
}
#endif
/*
- * Set up scheduler domains and groups. Callers must hold the hotplug lock.
+ * Build sched domains for a given set of cpus and attach the sched domains
+ * to the individual cpus
*/
-void __devinit arch_init_sched_domains(void)
+void build_sched_domains(const cpumask_t *cpu_map)
{
int i;
- cpumask_t cpu_default_map;
/*
- * Setup mask for cpus without special case scheduling requirements.
- * For now this just excludes isolated cpus, but could be used to
- * exclude other special cases in the future.
+ * Set up domains for cpus specified by the cpu_map.
*/
- cpus_complement(cpu_default_map, cpu_isolated_map);
- cpus_and(cpu_default_map, cpu_default_map, cpu_online_map);
-
- /*
- * Set up domains. Isolated domains just stay on the dummy domain.
- */
- for_each_cpu_mask(i, cpu_default_map) {
+ for_each_cpu_mask(i, *cpu_map) {
int group;
struct sched_domain *sd = NULL, *p;
cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
- cpus_and(nodemask, nodemask, cpu_default_map);
+ cpus_and(nodemask, nodemask, *cpu_map);
#ifdef CONFIG_NUMA
if (num_online_cpus()
> SD_NODES_PER_DOMAIN*cpus_weight(nodemask)) {
sd = &per_cpu(allnodes_domains, i);
*sd = SD_ALLNODES_INIT;
- sd->span = cpu_default_map;
+ sd->span = *cpu_map;
group = cpu_to_allnodes_group(i);
sd->groups = &sched_group_allnodes[group];
p = sd;
@@ -173,7 +165,7 @@ void __devinit arch_init_sched_domains(void)
*sd = SD_NODE_INIT;
sd->span = sched_domain_node_span(cpu_to_node(i));
sd->parent = p;
- cpus_and(sd->span, sd->span, cpu_default_map);
+ cpus_and(sd->span, sd->span, *cpu_map);
#endif
p = sd;
@@ -190,7 +182,7 @@ void __devinit arch_init_sched_domains(void)
group = cpu_to_cpu_group(i);
*sd = SD_SIBLING_INIT;
sd->span = cpu_sibling_map[i];
- cpus_and(sd->span, sd->span, cpu_default_map);
+ cpus_and(sd->span, sd->span, *cpu_map);
sd->parent = p;
sd->groups = &sched_group_cpus[group];
#endif
@@ -198,9 +190,9 @@ void __devinit arch_init_sched_domains(void)
#ifdef CONFIG_SCHED_SMT
/* Set up CPU (sibling) groups */
- for_each_cpu_mask(i, cpu_default_map) {
+ for_each_cpu_mask(i, *cpu_map) {
cpumask_t this_sibling_map = cpu_sibling_map[i];
- cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+ cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
if (i != first_cpu(this_sibling_map))
continue;
@@ -213,7 +205,7 @@ void __devinit arch_init_sched_domains(void)
for (i = 0; i < MAX_NUMNODES; i++) {
cpumask_t nodemask = node_to_cpumask(i);
- cpus_and(nodemask, nodemask, cpu_default_map);
+ cpus_and(nodemask, nodemask, *cpu_map);
if (cpus_empty(nodemask))
continue;
@@ -222,7 +214,7 @@ void __devinit arch_init_sched_domains(void)
}
#ifdef CONFIG_NUMA
- init_sched_build_groups(sched_group_allnodes, cpu_default_map,
+ init_sched_build_groups(sched_group_allnodes, *cpu_map,
&cpu_to_allnodes_group);
for (i = 0; i < MAX_NUMNODES; i++) {
@@ -233,12 +225,12 @@ void __devinit arch_init_sched_domains(void)
cpumask_t covered = CPU_MASK_NONE;
int j;
- cpus_and(nodemask, nodemask, cpu_default_map);
+ cpus_and(nodemask, nodemask, *cpu_map);
if (cpus_empty(nodemask))
continue;
domainspan = sched_domain_node_span(i);
- cpus_and(domainspan, domainspan, cpu_default_map);
+ cpus_and(domainspan, domainspan, *cpu_map);
sg = kmalloc(sizeof(struct sched_group), GFP_KERNEL);
sched_group_nodes[i] = sg;
@@ -266,7 +258,7 @@ void __devinit arch_init_sched_domains(void)
int n = (i + j) % MAX_NUMNODES;
cpus_complement(notcovered, covered);
- cpus_and(tmp, notcovered, cpu_default_map);
+ cpus_and(tmp, notcovered, *cpu_map);
cpus_and(tmp, tmp, domainspan);
if (cpus_empty(tmp))
break;
@@ -293,7 +285,7 @@ void __devinit arch_init_sched_domains(void)
#endif
/* Calculate CPU power for physical packages and nodes */
- for_each_cpu_mask(i, cpu_default_map) {
+ for_each_cpu_mask(i, *cpu_map) {
int power;
struct sched_domain *sd;
#ifdef CONFIG_SCHED_SMT
@@ -359,13 +351,35 @@ next_sg:
cpu_attach_domain(sd, i);
}
}
+/*
+ * Set up scheduler domains and groups. Callers must hold the hotplug lock.
+ */
+void arch_init_sched_domains(const cpumask_t *cpu_map)
+{
+ cpumask_t cpu_default_map;
+
+ /*
+ * Setup mask for cpus without special case scheduling requirements.
+ * For now this just excludes isolated cpus, but could be used to
+ * exclude other special cases in the future.
+ */
+ cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
+
+ build_sched_domains(&cpu_default_map);
+}
-void __devinit arch_destroy_sched_domains(void)
+void arch_destroy_sched_domains(const cpumask_t *cpu_map)
{
#ifdef CONFIG_NUMA
int i;
for (i = 0; i < MAX_NUMNODES; i++) {
+ cpumask_t nodemask = node_to_cpumask(i);
struct sched_group *oldsg, *sg = sched_group_nodes[i];
+
+ cpus_and(nodemask, nodemask, *cpu_map);
+ if (cpus_empty(nodemask))
+ continue;
+
if (sg == NULL)
continue;
sg = sg->next;
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
index b1d5d3d5276c..bb9a506deb78 100644
--- a/arch/ia64/kernel/entry.S
+++ b/arch/ia64/kernel/entry.S
@@ -470,18 +470,6 @@ ENTRY(load_switch_stack)
br.cond.sptk.many b7
END(load_switch_stack)
-GLOBAL_ENTRY(__ia64_syscall)
- .regstk 6,0,0,0
- mov r15=in5 // put syscall number in place
- break __BREAK_SYSCALL
- movl r2=errno
- cmp.eq p6,p7=-1,r10
- ;;
-(p6) st4 [r2]=r8
-(p6) mov r8=-1
- br.ret.sptk.many rp
-END(__ia64_syscall)
-
GLOBAL_ENTRY(execve)
mov r15=__NR_execve // put syscall number in place
break __BREAK_SYSCALL
@@ -637,7 +625,7 @@ END(ia64_ret_from_syscall)
* r8-r11: restored (syscall return value(s))
* r12: restored (user-level stack pointer)
* r13: restored (user-level thread pointer)
- * r14: cleared
+ * r14: set to __kernel_syscall_via_epc
* r15: restored (syscall #)
* r16-r17: cleared
* r18: user-level b6
@@ -658,7 +646,7 @@ END(ia64_ret_from_syscall)
* pr: restored (user-level pr)
* b0: restored (user-level rp)
* b6: restored
- * b7: cleared
+ * b7: set to __kernel_syscall_via_epc
* ar.unat: restored (user-level ar.unat)
* ar.pfs: restored (user-level ar.pfs)
* ar.rsc: restored (user-level ar.rsc)
@@ -704,72 +692,79 @@ ENTRY(ia64_leave_syscall)
;;
(p6) ld4 r31=[r18] // load current_thread_info()->flags
ld8 r19=[r2],PT(B6)-PT(LOADRS) // load ar.rsc value for "loadrs"
- mov b7=r0 // clear b7
+ nop.i 0
;;
- ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage)
+ mov r16=ar.bsp // M2 get existing backing store pointer
ld8 r18=[r2],PT(R9)-PT(B6) // load b6
(p6) and r15=TIF_WORK_MASK,r31 // any work other than TIF_SYSCALL_TRACE?
;;
- mov r16=ar.bsp // M2 get existing backing store pointer
+ ld8 r23=[r3],PT(R11)-PT(AR_BSPSTORE) // load ar.bspstore (may be garbage)
(p6) cmp4.ne.unc p6,p0=r15, r0 // any special work pending?
(p6) br.cond.spnt .work_pending_syscall
;;
// start restoring the state saved on the kernel stack (struct pt_regs):
ld8 r9=[r2],PT(CR_IPSR)-PT(R9)
ld8 r11=[r3],PT(CR_IIP)-PT(R11)
- mov f6=f0 // clear f6
+(pNonSys) break 0 // bug check: we shouldn't be here if pNonSys is TRUE!
;;
invala // M0|1 invalidate ALAT
- rsm psr.i | psr.ic // M2 initiate turning off of interrupt and interruption collection
- mov f9=f0 // clear f9
+ rsm psr.i | psr.ic // M2 turn off interrupts and interruption collection
+ cmp.eq p9,p0=r0,r0 // A set p9 to indicate that we should restore cr.ifs
- ld8 r29=[r2],16 // load cr.ipsr
- ld8 r28=[r3],16 // load cr.iip
- mov f8=f0 // clear f8
+ ld8 r29=[r2],16 // M0|1 load cr.ipsr
+ ld8 r28=[r3],16 // M0|1 load cr.iip
+ mov r22=r0 // A clear r22
;;
ld8 r30=[r2],16 // M0|1 load cr.ifs
ld8 r25=[r3],16 // M0|1 load ar.unat
- cmp.eq p9,p0=r0,r0 // set p9 to indicate that we should restore cr.ifs
+(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
;;
ld8 r26=[r2],PT(B0)-PT(AR_PFS) // M0|1 load ar.pfs
-(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
- mov f10=f0 // clear f10
+(pKStk) mov r22=psr // M2 read PSR now that interrupts are disabled
+ nop 0
;;
- ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // load b0
- ld8 r27=[r3],PT(PR)-PT(AR_RSC) // load ar.rsc
- mov f11=f0 // clear f11
+ ld8 r21=[r2],PT(AR_RNAT)-PT(B0) // M0|1 load b0
+ ld8 r27=[r3],PT(PR)-PT(AR_RSC) // M0|1 load ar.rsc
+ mov f6=f0 // F clear f6
;;
- ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT) // load ar.rnat (may be garbage)
- ld8 r31=[r3],PT(R1)-PT(PR) // load predicates
-(pUStk) add r14=IA64_TASK_THREAD_ON_USTACK_OFFSET,r13
+ ld8 r24=[r2],PT(AR_FPSR)-PT(AR_RNAT) // M0|1 load ar.rnat (may be garbage)
+ ld8 r31=[r3],PT(R1)-PT(PR) // M0|1 load predicates
+ mov f7=f0 // F clear f7
;;
- ld8 r20=[r2],PT(R12)-PT(AR_FPSR) // load ar.fpsr
- ld8.fill r1=[r3],16 // load r1
-(pUStk) mov r17=1
+ ld8 r20=[r2],PT(R12)-PT(AR_FPSR) // M0|1 load ar.fpsr
+ ld8.fill r1=[r3],16 // M0|1 load r1
+(pUStk) mov r17=1 // A
;;
- srlz.d // M0 ensure interruption collection is off
- ld8.fill r13=[r3],16
- mov f7=f0 // clear f7
+(pUStk) st1 [r14]=r17 // M2|3
+ ld8.fill r13=[r3],16 // M0|1
+ mov f8=f0 // F clear f8
;;
- ld8.fill r12=[r2] // restore r12 (sp)
- mov.m ar.ssd=r0 // M2 clear ar.ssd
- mov r22=r0 // clear r22
+ ld8.fill r12=[r2] // M0|1 restore r12 (sp)
+ ld8.fill r15=[r3] // M0|1 restore r15
+ mov b6=r18 // I0 restore b6
- ld8.fill r15=[r3] // restore r15
-(pUStk) st1 [r14]=r17
- addl r3=THIS_CPU(ia64_phys_stacked_size_p8),r0
+ addl r17=THIS_CPU(ia64_phys_stacked_size_p8),r0 // A
+ mov f9=f0 // F clear f9
+(pKStk) br.cond.dpnt.many skip_rbs_switch // B
+
+ srlz.d // M0 ensure interruption collection is off (for cover)
+ shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
+ cover // B add current frame into dirty partition & set cr.ifs
;;
-(pUStk) ld4 r17=[r3] // r17 = cpu_data->phys_stacked_size_p8
- mov.m ar.csd=r0 // M2 clear ar.csd
- mov b6=r18 // I0 restore b6
+(pUStk) ld4 r17=[r17] // M0|1 r17 = cpu_data->phys_stacked_size_p8
+ mov r19=ar.bsp // M2 get new backing store pointer
+ mov f10=f0 // F clear f10
+
+ nop.m 0
+ movl r14=__kernel_syscall_via_epc // X
;;
- mov r14=r0 // clear r14
- shr.u r18=r19,16 // I0|1 get byte size of existing "dirty" partition
-(pKStk) br.cond.dpnt.many skip_rbs_switch
+ mov.m ar.csd=r0 // M2 clear ar.csd
+ mov.m ar.ccv=r0 // M2 clear ar.ccv
+ mov b7=r14 // I0 clear b7 (hint with __kernel_syscall_via_epc)
- mov.m ar.ccv=r0 // clear ar.ccv
-(pNonSys) br.cond.dpnt.many dont_preserve_current_frame
- br.cond.sptk.many rbs_switch
+ mov.m ar.ssd=r0 // M2 clear ar.ssd
+ mov f11=f0 // F clear f11
+ br.cond.sptk.many rbs_switch // B
END(ia64_leave_syscall)
#ifdef CONFIG_IA32_SUPPORT
@@ -885,7 +880,7 @@ GLOBAL_ENTRY(ia64_leave_kernel)
ldf.fill f7=[r2],PT(F11)-PT(F7)
ldf.fill f8=[r3],32
;;
- srlz.i // ensure interruption collection is off
+ srlz.d // ensure that inter. collection is off (VHPT is don't care, since text is pinned)
mov ar.ccv=r15
;;
ldf.fill f11=[r2]
@@ -945,11 +940,10 @@ GLOBAL_ENTRY(ia64_leave_kernel)
* NOTE: alloc, loadrs, and cover can't be predicated.
*/
(pNonSys) br.cond.dpnt dont_preserve_current_frame
-
-rbs_switch:
cover // add current frame into dirty partition and set cr.ifs
;;
mov r19=ar.bsp // get new backing store pointer
+rbs_switch:
sub r16=r16,r18 // krbs = old bsp - size of dirty partition
cmp.ne p9,p0=r0,r0 // clear p9 to skip restore of cr.ifs
;;
@@ -1024,14 +1018,14 @@ rse_clear_invalid:
mov loc5=0
mov loc6=0
mov loc7=0
-(pRecurse) br.call.sptk.few b0=rse_clear_invalid
+(pRecurse) br.call.dptk.few b0=rse_clear_invalid
;;
mov loc8=0
mov loc9=0
cmp.ne pReturn,p0=r0,in1 // if recursion count != 0, we need to do a br.ret
mov loc10=0
mov loc11=0
-(pReturn) br.ret.sptk.many b0
+(pReturn) br.ret.dptk.many b0
#endif /* !CONFIG_ITANIUM */
# undef pRecurse
# undef pReturn
@@ -1255,7 +1249,7 @@ ENTRY(sys_rt_sigreturn)
stf.spill [r17]=f11
adds out0=16,sp // out0 = &sigscratch
br.call.sptk.many rp=ia64_rt_sigreturn
-.ret19: .restore sp 0
+.ret19: .restore sp,0
adds sp=16,sp
;;
ld8 r9=[sp] // load new ar.unat
@@ -1577,8 +1571,8 @@ sys_call_table:
data8 sys_add_key
data8 sys_request_key
data8 sys_keyctl
- data8 sys_ni_syscall
- data8 sys_ni_syscall // 1275
+ data8 sys_ioprio_set
+ data8 sys_ioprio_get // 1275
data8 sys_set_zone_reclaim
data8 sys_ni_syscall
data8 sys_ni_syscall
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 962b6c4e32b5..7d7684a369d3 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -531,93 +531,114 @@ GLOBAL_ENTRY(fsys_bubble_down)
.altrp b6
.body
/*
- * We get here for syscalls that don't have a lightweight handler. For those, we
- * need to bubble down into the kernel and that requires setting up a minimal
- * pt_regs structure, and initializing the CPU state more or less as if an
- * interruption had occurred. To make syscall-restarts work, we setup pt_regs
- * such that cr_iip points to the second instruction in syscall_via_break.
- * Decrementing the IP hence will restart the syscall via break and not
- * decrementing IP will return us to the caller, as usual. Note that we preserve
- * the value of psr.pp rather than initializing it from dcr.pp. This makes it
- * possible to distinguish fsyscall execution from other privileged execution.
+ * We get here for syscalls that don't have a lightweight
+ * handler. For those, we need to bubble down into the kernel
+ * and that requires setting up a minimal pt_regs structure,
+ * and initializing the CPU state more or less as if an
+ * interruption had occurred. To make syscall-restarts work,
+ * we setup pt_regs such that cr_iip points to the second
+ * instruction in syscall_via_break. Decrementing the IP
+ * hence will restart the syscall via break and not
+ * decrementing IP will return us to the caller, as usual.
+ * Note that we preserve the value of psr.pp rather than
+ * initializing it from dcr.pp. This makes it possible to
+ * distinguish fsyscall execution from other privileged
+ * execution.
*
* On entry:
- * - normal fsyscall handler register usage, except that we also have:
+ * - normal fsyscall handler register usage, except
+ * that we also have:
* - r18: address of syscall entry point
* - r21: ar.fpsr
* - r26: ar.pfs
* - r27: ar.rsc
* - r29: psr
+ *
+ * We used to clear some PSR bits here but that requires slow
+ * serialization. Fortuntely, that isn't really necessary.
+ * The rationale is as follows: we used to clear bits
+ * ~PSR_PRESERVED_BITS in PSR.L. Since
+ * PSR_PRESERVED_BITS==PSR.{UP,MFL,MFH,PK,DT,PP,SP,RT,IC}, we
+ * ended up clearing PSR.{BE,AC,I,DFL,DFH,DI,DB,SI,TB}.
+ * However,
+ *
+ * PSR.BE : already is turned off in __kernel_syscall_via_epc()
+ * PSR.AC : don't care (kernel normally turns PSR.AC on)
+ * PSR.I : already turned off by the time fsys_bubble_down gets
+ * invoked
+ * PSR.DFL: always 0 (kernel never turns it on)
+ * PSR.DFH: don't care --- kernel never touches f32-f127 on its own
+ * initiative
+ * PSR.DI : always 0 (kernel never turns it on)
+ * PSR.SI : always 0 (kernel never turns it on)
+ * PSR.DB : don't care --- kernel never enables kernel-level
+ * breakpoints
+ * PSR.TB : must be 0 already; if it wasn't zero on entry to
+ * __kernel_syscall_via_epc, the branch to fsys_bubble_down
+ * will trigger a taken branch; the taken-trap-handler then
+ * converts the syscall into a break-based system-call.
*/
-# define PSR_PRESERVED_BITS (IA64_PSR_UP | IA64_PSR_MFL | IA64_PSR_MFH | IA64_PSR_PK \
- | IA64_PSR_DT | IA64_PSR_PP | IA64_PSR_SP | IA64_PSR_RT \
- | IA64_PSR_IC)
/*
- * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc. The rest we have
- * to synthesize.
+ * Reading psr.l gives us only bits 0-31, psr.it, and psr.mc.
+ * The rest we have to synthesize.
*/
-# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) | (0x1 << IA64_PSR_RI_BIT) \
+# define PSR_ONE_BITS ((3 << IA64_PSR_CPL0_BIT) \
+ | (0x1 << IA64_PSR_RI_BIT) \
| IA64_PSR_BN | IA64_PSR_I)
- invala
- movl r8=PSR_ONE_BITS
+ invala // M0|1
+ movl r14=ia64_ret_from_syscall // X
- mov r25=ar.unat // save ar.unat (5 cyc)
- movl r9=PSR_PRESERVED_BITS
+ nop.m 0
+ movl r28=__kernel_syscall_via_break // X create cr.iip
+ ;;
- mov ar.rsc=0 // set enforced lazy mode, pl 0, little-endian, loadrs=0
- movl r28=__kernel_syscall_via_break
+ mov r2=r16 // A get task addr to addl-addressable register
+ adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // A
+ mov r31=pr // I0 save pr (2 cyc)
;;
- mov r23=ar.bspstore // save ar.bspstore (12 cyc)
- mov r31=pr // save pr (2 cyc)
- mov r20=r1 // save caller's gp in r20
+ st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag
+ addl r22=IA64_RBS_OFFSET,r2 // A compute base of RBS
+ add r3=TI_FLAGS+IA64_TASK_SIZE,r2 // A
;;
- mov r2=r16 // copy current task addr to addl-addressable register
- and r9=r9,r29
- mov r19=b6 // save b6 (2 cyc)
+ ld4 r3=[r3] // M0|1 r3 = current_thread_info()->flags
+ lfetch.fault.excl.nt1 [r22] // M0|1 prefetch register backing-store
+ nop.i 0
;;
- mov psr.l=r9 // slam the door (17 cyc to srlz.i)
- or r29=r8,r29 // construct cr.ipsr value to save
- addl r22=IA64_RBS_OFFSET,r2 // compute base of RBS
+ mov ar.rsc=0 // M2 set enforced lazy mode, pl 0, LE, loadrs=0
+ nop.m 0
+ nop.i 0
;;
- // GAS reports a spurious RAW hazard on the read of ar.rnat because it thinks
- // we may be reading ar.itc after writing to psr.l. Avoid that message with
- // this directive:
- dv_serialize_data
- mov.m r24=ar.rnat // read ar.rnat (5 cyc lat)
- lfetch.fault.excl.nt1 [r22]
- adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r2
-
- // ensure previous insn group is issued before we stall for srlz.i:
+ mov r23=ar.bspstore // M2 (12 cyc) save ar.bspstore
+ mov.m r24=ar.rnat // M2 (5 cyc) read ar.rnat (dual-issues!)
+ nop.i 0
;;
- srlz.i // ensure new psr.l has been established
- /////////////////////////////////////////////////////////////////////////////
- ////////// from this point on, execution is not interruptible anymore
- /////////////////////////////////////////////////////////////////////////////
- addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // compute base of memory stack
- cmp.ne pKStk,pUStk=r0,r0 // set pKStk <- 0, pUStk <- 1
+ mov ar.bspstore=r22 // M2 (6 cyc) switch to kernel RBS
+ movl r8=PSR_ONE_BITS // X
;;
- st1 [r16]=r0 // clear current->thread.on_ustack flag
- mov ar.bspstore=r22 // switch to kernel RBS
- mov b6=r18 // copy syscall entry-point to b6 (7 cyc)
- add r3=TI_FLAGS+IA64_TASK_SIZE,r2
+ mov r25=ar.unat // M2 (5 cyc) save ar.unat
+ mov r19=b6 // I0 save b6 (2 cyc)
+ mov r20=r1 // A save caller's gp in r20
;;
- ld4 r3=[r3] // r2 = current_thread_info()->flags
- mov r18=ar.bsp // save (kernel) ar.bsp (12 cyc)
- mov ar.rsc=0x3 // set eager mode, pl 0, little-endian, loadrs=0
- br.call.sptk.many b7=ia64_syscall_setup
- ;;
- ssm psr.i
- movl r2=ia64_ret_from_syscall
+ or r29=r8,r29 // A construct cr.ipsr value to save
+ mov b6=r18 // I0 copy syscall entry-point to b6 (7 cyc)
+ addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r2 // A compute base of memory stack
+
+ mov r18=ar.bsp // M2 save (kernel) ar.bsp (12 cyc)
+ cmp.ne pKStk,pUStk=r0,r0 // A set pKStk <- 0, pUStk <- 1
+ br.call.sptk.many b7=ia64_syscall_setup // B
;;
- mov rp=r2 // set the real return addr
- and r3=_TIF_SYSCALL_TRACEAUDIT,r3
+ mov ar.rsc=0x3 // M2 set eager mode, pl 0, LE, loadrs=0
+ mov rp=r14 // I0 set the real return addr
+ and r3=_TIF_SYSCALL_TRACEAUDIT,r3 // A
;;
- cmp.eq p8,p0=r3,r0
+ ssm psr.i // M2 we're on kernel stacks now, reenable irqs
+ cmp.eq p8,p0=r3,r0 // A
+(p10) br.cond.spnt.many ia64_ret_from_syscall // B return if bad call-frame or r15 is a NaT
-(p10) br.cond.spnt.many ia64_ret_from_syscall // p10==true means out registers are more than 8
-(p8) br.call.sptk.many b6=b6 // ignore this return addr
- br.cond.sptk ia64_trace_syscall
+ nop.m 0
+(p8) br.call.sptk.many b6=b6 // B (ignore return address)
+ br.cond.spnt ia64_trace_syscall // B
END(fsys_bubble_down)
.rodata
diff --git a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
index facf75acdc85..86948ce63e43 100644
--- a/arch/ia64/kernel/gate.S
+++ b/arch/ia64/kernel/gate.S
@@ -72,38 +72,40 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
* bundle get executed. The remaining code must be safe even if
* they do not get executed.
*/
- adds r17=-1024,r15
- mov r10=0 // default to successful syscall execution
- epc
+ adds r17=-1024,r15 // A
+ mov r10=0 // A default to successful syscall execution
+ epc // B causes split-issue
}
;;
- rsm psr.be // note: on McKinley "rsm psr.be/srlz.d" is slightly faster than "rum psr.be"
- LOAD_FSYSCALL_TABLE(r14)
-
- mov r16=IA64_KR(CURRENT) // 12 cycle read latency
- tnat.nz p10,p9=r15
- mov r19=NR_syscalls-1
+ rsm psr.be | psr.i // M2 (5 cyc to srlz.d)
+ LOAD_FSYSCALL_TABLE(r14) // X
;;
- shladd r18=r17,3,r14
-
- srlz.d
- cmp.ne p8,p0=r0,r0 // p8 <- FALSE
- /* Note: if r17 is a NaT, p6 will be set to zero. */
- cmp.geu p6,p7=r19,r17 // (syscall > 0 && syscall < 1024+NR_syscalls)?
- ;;
-(p6) ld8 r18=[r18]
- mov r21=ar.fpsr
- add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry
- ;;
-(p6) mov b7=r18
-(p6) tbit.z p8,p0=r18,0
-(p8) br.dptk.many b7
-
-(p6) rsm psr.i
- mov r27=ar.rsc
- mov r26=ar.pfs
+ mov r16=IA64_KR(CURRENT) // M2 (12 cyc)
+ shladd r18=r17,3,r14 // A
+ mov r19=NR_syscalls-1 // A
+ ;;
+ lfetch [r18] // M0|1
+ mov r29=psr // M2 (12 cyc)
+ // If r17 is a NaT, p6 will be zero
+ cmp.geu p6,p7=r19,r17 // A (sysnr > 0 && sysnr < 1024+NR_syscalls)?
+ ;;
+ mov r21=ar.fpsr // M2 (12 cyc)
+ tnat.nz p10,p9=r15 // I0
+ mov.i r26=ar.pfs // I0 (would stall anyhow due to srlz.d...)
+ ;;
+ srlz.d // M0 (forces split-issue) ensure PSR.BE==0
+(p6) ld8 r18=[r18] // M0|1
+ nop.i 0
+ ;;
+ nop.m 0
+(p6) tbit.z.unc p8,p0=r18,0 // I0 (dual-issues with "mov b7=r18"!)
+ nop.i 0
;;
- mov r29=psr // read psr (12 cyc load latency)
+(p8) ssm psr.i
+(p6) mov b7=r18 // I0
+(p8) br.dptk.many b7 // B
+
+ mov r27=ar.rsc // M2 (12 cyc)
/*
* brl.cond doesn't work as intended because the linker would convert this branch
* into a branch to a PLT. Perhaps there will be a way to avoid this with some
@@ -111,6 +113,8 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
* instead.
*/
#ifdef CONFIG_ITANIUM
+(p6) add r14=-8,r14 // r14 <- addr of fsys_bubble_down entry
+ ;;
(p6) ld8 r14=[r14] // r14 <- fsys_bubble_down
;;
(p6) mov b7=r14
@@ -118,7 +122,7 @@ GLOBAL_ENTRY(__kernel_syscall_via_epc)
#else
BRL_COND_FSYS_BUBBLE_DOWN(p6)
#endif
-
+ ssm psr.i
mov r10=-1
(p10) mov r8=EINVAL
(p9) mov r8=ENOSYS
diff --git a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
index 7bbf019c9867..01572814abe4 100644
--- a/arch/ia64/kernel/ia64_ksyms.c
+++ b/arch/ia64/kernel/ia64_ksyms.c
@@ -58,9 +58,6 @@ EXPORT_SYMBOL(__strlen_user);
EXPORT_SYMBOL(__strncpy_from_user);
EXPORT_SYMBOL(__strnlen_user);
-#include <asm/unistd.h>
-EXPORT_SYMBOL(__ia64_syscall);
-
/* from arch/ia64/lib */
extern void __divsi3(void);
extern void __udivsi3(void);
diff --git a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
index 88b014381df5..7936b62f7a2e 100644
--- a/arch/ia64/kernel/iosapic.c
+++ b/arch/ia64/kernel/iosapic.c
@@ -129,14 +129,13 @@ static struct 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 */
+ int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
#ifdef CONFIG_NUMA
unsigned short node; /* numa node association via pxm */
#endif
} iosapic_lists[NR_IOSAPICS];
-static int num_iosapic;
-
-static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
+static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list);
@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
{
int i;
- for (i = 0; i < num_iosapic; i++) {
+ for (i = 0; i < NR_IOSAPICS; i++) {
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
return i;
}
@@ -490,8 +489,6 @@ static int iosapic_find_sharable_vector (unsigned long trigger, unsigned long po
}
}
}
- if (vector < 0)
- panic("%s: out of interrupt vectors!\n", __FUNCTION__);
return vector;
}
@@ -507,6 +504,8 @@ iosapic_reassign_vector (int vector)
if (!list_empty(&iosapic_intr_info[vector].rtes)) {
new_vector = assign_irq_vector(AUTO_ASSIGN);
+ if (new_vector < 0)
+ panic("%s: out of interrupt vectors!\n", __FUNCTION__);
printk(KERN_INFO "Reassigning vector %d to %d\n", vector, new_vector);
memcpy(&iosapic_intr_info[new_vector], &iosapic_intr_info[vector],
sizeof(struct iosapic_intr_info));
@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
rte->refcnt++;
list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
iosapic_intr_info[vector].count++;
+ iosapic_lists[index].rtes_inuse++;
}
else if (vector_is_shared(vector)) {
struct iosapic_intr_info *info = &iosapic_intr_info[vector];
@@ -734,9 +734,12 @@ again:
spin_unlock_irqrestore(&iosapic_lock, flags);
/* If vector is running out, we try to find a sharable vector */
- vector = assign_irq_vector_nopanic(AUTO_ASSIGN);
- if (vector < 0)
+ vector = assign_irq_vector(AUTO_ASSIGN);
+ if (vector < 0) {
vector = iosapic_find_sharable_vector(trigger, polarity);
+ if (vector < 0)
+ panic("%s: out of interrupt vectors!\n", __FUNCTION__);
+ }
spin_lock_irqsave(&irq_descp(vector)->lock, flags);
spin_lock(&iosapic_lock);
@@ -778,7 +781,7 @@ void
iosapic_unregister_intr (unsigned int gsi)
{
unsigned long flags;
- int irq, vector;
+ int irq, vector, index;
irq_desc_t *idesc;
u32 low32;
unsigned long trigger, polarity;
@@ -819,6 +822,9 @@ iosapic_unregister_intr (unsigned int gsi)
list_del(&rte->rte_list);
iosapic_intr_info[vector].count--;
iosapic_free_rte(rte);
+ index = find_iosapic(gsi);
+ iosapic_lists[index].rtes_inuse--;
+ WARN_ON(iosapic_lists[index].rtes_inuse < 0);
trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity;
@@ -881,6 +887,8 @@ iosapic_register_platform_intr (u32 int_type, unsigned int gsi,
break;
case ACPI_INTERRUPT_INIT:
vector = assign_irq_vector(AUTO_ASSIGN);
+ if (vector < 0)
+ panic("%s: out of interrupt vectors!\n", __FUNCTION__);
delivery = IOSAPIC_INIT;
break;
case ACPI_INTERRUPT_CPEI:
@@ -952,30 +960,86 @@ iosapic_system_init (int system_pcat_compat)
}
}
-void __init
+static inline int
+iosapic_alloc (void)
+{
+ int index;
+
+ for (index = 0; index < NR_IOSAPICS; index++)
+ if (!iosapic_lists[index].addr)
+ return index;
+
+ printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
+ return -1;
+}
+
+static inline void
+iosapic_free (int index)
+{
+ memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
+}
+
+static inline int
+iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
+{
+ int index;
+ unsigned int gsi_end, base, end;
+
+ /* check gsi range */
+ gsi_end = gsi_base + ((ver >> 16) & 0xff);
+ for (index = 0; index < NR_IOSAPICS; index++) {
+ if (!iosapic_lists[index].addr)
+ continue;
+
+ base = iosapic_lists[index].gsi_base;
+ end = base + iosapic_lists[index].num_rte - 1;
+
+ if (gsi_base < base && gsi_end < base)
+ continue;/* OK */
+
+ if (gsi_base > end && gsi_end > end)
+ continue; /* OK */
+
+ return -EBUSY;
+ }
+ return 0;
+}
+
+int __devinit
iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
{
- int num_rte;
+ int num_rte, err, index;
unsigned int isa_irq, ver;
char __iomem *addr;
+ unsigned long flags;
- addr = ioremap(phys_addr, 0);
- ver = iosapic_version(addr);
+ spin_lock_irqsave(&iosapic_lock, flags);
+ {
+ addr = ioremap(phys_addr, 0);
+ ver = iosapic_version(addr);
- /*
- * The MAX_REDIR register holds the highest input pin
- * number (starting from 0).
- * We add 1 so that we can use it for number of pins (= RTEs)
- */
- num_rte = ((ver >> 16) & 0xff) + 1;
+ if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
+ iounmap(addr);
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+ return err;
+ }
+
+ /*
+ * The MAX_REDIR register holds the highest input pin
+ * number (starting from 0).
+ * We add 1 so that we can use it for number of pins (= RTEs)
+ */
+ num_rte = ((ver >> 16) & 0xff) + 1;
- iosapic_lists[num_iosapic].addr = addr;
- iosapic_lists[num_iosapic].gsi_base = gsi_base;
- iosapic_lists[num_iosapic].num_rte = num_rte;
+ index = iosapic_alloc();
+ iosapic_lists[index].addr = addr;
+ iosapic_lists[index].gsi_base = gsi_base;
+ iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA
- iosapic_lists[num_iosapic].node = MAX_NUMNODES;
+ iosapic_lists[index].node = MAX_NUMNODES;
#endif
- num_iosapic++;
+ }
+ spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) {
/*
@@ -986,10 +1050,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
for (isa_irq = 0; isa_irq < 16; ++isa_irq)
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
}
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+int
+iosapic_remove (unsigned int gsi_base)
+{
+ int index, err = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&iosapic_lock, flags);
+ {
+ index = find_iosapic(gsi_base);
+ if (index < 0) {
+ printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
+ __FUNCTION__, gsi_base);
+ goto out;
+ }
+
+ if (iosapic_lists[index].rtes_inuse) {
+ err = -EBUSY;
+ printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
+ __FUNCTION__, gsi_base);
+ goto out;
+ }
+
+ iounmap(iosapic_lists[index].addr);
+ iosapic_free(index);
+ }
+ out:
+ spin_unlock_irqrestore(&iosapic_lock, flags);
+ return err;
}
+#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_NUMA
-void __init
+void __devinit
map_iosapic_to_node(unsigned int gsi_base, int node)
{
int index;
diff --git a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
index 4fe60c7a2e90..6c4d59fd0364 100644
--- a/arch/ia64/kernel/irq_ia64.c
+++ b/arch/ia64/kernel/irq_ia64.c
@@ -63,30 +63,19 @@ EXPORT_SYMBOL(isa_irq_to_vector_map);
static unsigned long ia64_vector_mask[BITS_TO_LONGS(IA64_NUM_DEVICE_VECTORS)];
int
-assign_irq_vector_nopanic (int irq)
+assign_irq_vector (int irq)
{
int pos, vector;
again:
pos = find_first_zero_bit(ia64_vector_mask, IA64_NUM_DEVICE_VECTORS);
vector = IA64_FIRST_DEVICE_VECTOR + pos;
if (vector > IA64_LAST_DEVICE_VECTOR)
- return -1;
+ return -ENOSPC;
if (test_and_set_bit(pos, ia64_vector_mask))
goto again;
return vector;
}
-int
-assign_irq_vector (int irq)
-{
- int vector = assign_irq_vector_nopanic(irq);
-
- if (vector < 0)
- panic("assign_irq_vector: out of interrupt vectors!");
-
- return vector;
-}
-
void
free_irq_vector (int vector)
{
diff --git a/arch/ia64/kernel/ivt.S b/arch/ia64/kernel/ivt.S
index 2bc085a73e30..3bb3a13c4047 100644
--- a/arch/ia64/kernel/ivt.S
+++ b/arch/ia64/kernel/ivt.S
@@ -1,7 +1,7 @@
/*
* arch/ia64/kernel/ivt.S
*
- * Copyright (C) 1998-2001, 2003 Hewlett-Packard Co
+ * Copyright (C) 1998-2001, 2003, 2005 Hewlett-Packard Co
* Stephane Eranian <eranian@hpl.hp.com>
* David Mosberger <davidm@hpl.hp.com>
* Copyright (C) 2000, 2002-2003 Intel Co
@@ -692,82 +692,118 @@ ENTRY(break_fault)
* to prevent leaking bits from kernel to user level.
*/
DBG_FAULT(11)
- mov r16=IA64_KR(CURRENT) // r16 = current task; 12 cycle read lat.
- mov r17=cr.iim
- mov r18=__IA64_BREAK_SYSCALL
- mov r21=ar.fpsr
- mov r29=cr.ipsr
- mov r19=b6
- mov r25=ar.unat
- mov r27=ar.rsc
- mov r26=ar.pfs
- mov r28=cr.iip
- mov r31=pr // prepare to save predicates
- mov r20=r1
- ;;
+ mov.m r16=IA64_KR(CURRENT) // M2 r16 <- current task (12 cyc)
+ mov r29=cr.ipsr // M2 (12 cyc)
+ mov r31=pr // I0 (2 cyc)
+
+ mov r17=cr.iim // M2 (2 cyc)
+ mov.m r27=ar.rsc // M2 (12 cyc)
+ mov r18=__IA64_BREAK_SYSCALL // A
+
+ mov.m ar.rsc=0 // M2
+ mov.m r21=ar.fpsr // M2 (12 cyc)
+ mov r19=b6 // I0 (2 cyc)
+ ;;
+ mov.m r23=ar.bspstore // M2 (12 cyc)
+ mov.m r24=ar.rnat // M2 (5 cyc)
+ mov.i r26=ar.pfs // I0 (2 cyc)
+
+ invala // M0|1
+ nop.m 0 // M
+ mov r20=r1 // A save r1
+
+ nop.m 0
+ movl r30=sys_call_table // X
+
+ mov r28=cr.iip // M2 (2 cyc)
+ cmp.eq p0,p7=r18,r17 // I0 is this a system call?
+(p7) br.cond.spnt non_syscall // B no ->
+ //
+ // From this point on, we are definitely on the syscall-path
+ // and we can use (non-banked) scratch registers.
+ //
+///////////////////////////////////////////////////////////////////////
+ mov r1=r16 // A move task-pointer to "addl"-addressable reg
+ mov r2=r16 // A setup r2 for ia64_syscall_setup
+ add r9=TI_FLAGS+IA64_TASK_SIZE,r16 // A r9 = &current_thread_info()->flags
+
adds r16=IA64_TASK_THREAD_ON_USTACK_OFFSET,r16
- cmp.eq p0,p7=r18,r17 // is this a system call? (p7 <- false, if so)
-(p7) br.cond.spnt non_syscall
+ adds r15=-1024,r15 // A subtract 1024 from syscall number
+ mov r3=NR_syscalls - 1
;;
- ld1 r17=[r16] // load current->thread.on_ustack flag
- st1 [r16]=r0 // clear current->thread.on_ustack flag
- add r1=-IA64_TASK_THREAD_ON_USTACK_OFFSET,r16 // set r1 for MINSTATE_START_SAVE_MIN_VIRT
+ ld1.bias r17=[r16] // M0|1 r17 = current->thread.on_ustack flag
+ ld4 r9=[r9] // M0|1 r9 = current_thread_info()->flags
+ extr.u r8=r29,41,2 // I0 extract ei field from cr.ipsr
+
+ shladd r30=r15,3,r30 // A r30 = sys_call_table + 8*(syscall-1024)
+ addl r22=IA64_RBS_OFFSET,r1 // A compute base of RBS
+ cmp.leu p6,p7=r15,r3 // A syscall number in range?
;;
- invala
- /* adjust return address so we skip over the break instruction: */
+ lfetch.fault.excl.nt1 [r22] // M0|1 prefetch RBS
+(p6) ld8 r30=[r30] // M0|1 load address of syscall entry point
+ tnat.nz.or p7,p0=r15 // I0 is syscall nr a NaT?
- extr.u r8=r29,41,2 // extract ei field from cr.ipsr
- ;;
- cmp.eq p6,p7=2,r8 // isr.ei==2?
- mov r2=r1 // setup r2 for ia64_syscall_setup
- ;;
-(p6) mov r8=0 // clear ei to 0
-(p6) adds r28=16,r28 // switch cr.iip to next bundle cr.ipsr.ei wrapped
-(p7) adds r8=1,r8 // increment ei to next slot
- ;;
- cmp.eq pKStk,pUStk=r0,r17 // are we in kernel mode already?
- dep r29=r8,r29,41,2 // insert new ei into cr.ipsr
+ mov.m ar.bspstore=r22 // M2 switch to kernel RBS
+ cmp.eq p8,p9=2,r8 // A isr.ei==2?
;;
- // switch from user to kernel RBS:
- MINSTATE_START_SAVE_MIN_VIRT
- br.call.sptk.many b7=ia64_syscall_setup
- ;;
- MINSTATE_END_SAVE_MIN_VIRT // switch to bank 1
- ssm psr.ic | PSR_DEFAULT_BITS
- ;;
- srlz.i // guarantee that interruption collection is on
- mov r3=NR_syscalls - 1
- ;;
-(p15) ssm psr.i // restore psr.i
- // p10==true means out registers are more than 8 or r15's Nat is true
-(p10) br.cond.spnt.many ia64_ret_from_syscall
- ;;
- movl r16=sys_call_table
+(p8) mov r8=0 // A clear ei to 0
+(p7) movl r30=sys_ni_syscall // X
- adds r15=-1024,r15 // r15 contains the syscall number---subtract 1024
- movl r2=ia64_ret_from_syscall
- ;;
- shladd r20=r15,3,r16 // r20 = sys_call_table + 8*(syscall-1024)
- cmp.leu p6,p7=r15,r3 // (syscall > 0 && syscall < 1024 + NR_syscalls) ?
- mov rp=r2 // set the real return addr
+(p8) adds r28=16,r28 // A switch cr.iip to next bundle
+(p9) adds r8=1,r8 // A increment ei to next slot
+ nop.i 0
;;
-(p6) ld8 r20=[r20] // load address of syscall entry point
-(p7) movl r20=sys_ni_syscall
- add r2=TI_FLAGS+IA64_TASK_SIZE,r13
- ;;
- ld4 r2=[r2] // r2 = current_thread_info()->flags
- ;;
- and r2=_TIF_SYSCALL_TRACEAUDIT,r2 // mask trace or audit
+ mov.m r25=ar.unat // M2 (5 cyc)
+ dep r29=r8,r29,41,2 // I0 insert new ei into cr.ipsr
+ adds r15=1024,r15 // A restore original syscall number
+ //
+ // If any of the above loads miss in L1D, we'll stall here until
+ // the data arrives.
+ //
+///////////////////////////////////////////////////////////////////////
+ st1 [r16]=r0 // M2|3 clear current->thread.on_ustack flag
+ mov b6=r30 // I0 setup syscall handler branch reg early
+ cmp.eq pKStk,pUStk=r0,r17 // A were we on kernel stacks already?
+
+ and r9=_TIF_SYSCALL_TRACEAUDIT,r9 // A mask trace or audit
+ mov r18=ar.bsp // M2 (12 cyc)
+(pKStk) br.cond.spnt .break_fixup // B we're already in kernel-mode -- fix up RBS
+ ;;
+.back_from_break_fixup:
+(pUStk) addl r1=IA64_STK_OFFSET-IA64_PT_REGS_SIZE,r1 // A compute base of memory stack
+ cmp.eq p14,p0=r9,r0 // A are syscalls being traced/audited?
+ br.call.sptk.many b7=ia64_syscall_setup // B
+1:
+ mov ar.rsc=0x3 // M2 set eager mode, pl 0, LE, loadrs=0
+ nop 0
+ bsw.1 // B (6 cyc) regs are saved, switch to bank 1
;;
- cmp.eq p8,p0=r2,r0
- mov b6=r20
+
+ ssm psr.ic | PSR_DEFAULT_BITS // M2 now it's safe to re-enable intr.-collection
+ movl r3=ia64_ret_from_syscall // X
;;
-(p8) br.call.sptk.many b6=b6 // ignore this return addr
- br.cond.sptk ia64_trace_syscall
+
+ srlz.i // M0 ensure interruption collection is on
+ mov rp=r3 // I0 set the real return addr
+(p10) br.cond.spnt.many ia64_ret_from_syscall // B return if bad call-frame or r15 is a NaT
+
+(p15) ssm psr.i // M2 restore psr.i
+(p14) br.call.sptk.many b6=b6 // B invoke syscall-handker (ignore return addr)
+ br.cond.spnt.many ia64_trace_syscall // B do syscall-tracing thingamagic
// NOT REACHED
+///////////////////////////////////////////////////////////////////////
+ // On entry, we optimistically assumed that we're coming from user-space.
+ // For the rare cases where a system-call is done from within the kernel,
+ // we fix things up at this point:
+.break_fixup:
+ add r1=-IA64_PT_REGS_SIZE,sp // A allocate space for pt_regs structure
+ mov ar.rnat=r24 // M2 restore kernel's AR.RNAT
+ ;;
+ mov ar.bspstore=r23 // M2 restore kernel's AR.BSPSTORE
+ br.cond.sptk .back_from_break_fixup
END(break_fault)
.org ia64_ivt+0x3000
@@ -842,8 +878,6 @@ END(interrupt)
* - r31: saved pr
* - b0: original contents (to be saved)
* On exit:
- * - executing on bank 1 registers
- * - psr.ic enabled, interrupts restored
* - p10: TRUE if syscall is invoked with more than 8 out
* registers or r15's Nat is true
* - r1: kernel's gp
@@ -851,8 +885,11 @@ END(interrupt)
* - r8: -EINVAL if p10 is true
* - r12: points to kernel stack
* - r13: points to current task
+ * - r14: preserved (same as on entry)
+ * - p13: preserved
* - p15: TRUE if interrupts need to be re-enabled
* - ar.fpsr: set to kernel settings
+ * - b6: preserved (same as on entry)
*/
GLOBAL_ENTRY(ia64_syscall_setup)
#if PT(B6) != 0
@@ -920,10 +957,10 @@ GLOBAL_ENTRY(ia64_syscall_setup)
(p13) mov in5=-1
;;
st8 [r16]=r21,PT(R8)-PT(AR_FPSR) // save ar.fpsr
- tnat.nz p14,p0=in6
+ tnat.nz p13,p0=in6
cmp.lt p10,p9=r11,r8 // frame size can't be more than local+8
;;
- stf8 [r16]=f1 // ensure pt_regs.r8 != 0 (see handle_syscall_error)
+ mov r8=1
(p9) tnat.nz p10,p0=r15
adds r12=-16,r1 // switch to kernel memory stack (with 16 bytes of scratch)
@@ -934,9 +971,9 @@ GLOBAL_ENTRY(ia64_syscall_setup)
mov r13=r2 // establish `current'
movl r1=__gp // establish kernel global pointer
;;
-(p14) mov in6=-1
+ st8 [r16]=r8 // ensure pt_regs.r8 != 0 (see handle_syscall_error)
+(p13) mov in6=-1
(p8) mov in7=-1
- nop.i 0
cmp.eq pSys,pNonSys=r0,r0 // set pSys=1, pNonSys=0
movl r17=FPSR_DEFAULT
@@ -1007,6 +1044,8 @@ END(dispatch_illegal_op_fault)
FAULT(17)
ENTRY(non_syscall)
+ mov ar.rsc=r27 // restore ar.rsc before SAVE_MIN_WITH_COVER
+ ;;
SAVE_MIN_WITH_COVER
// There is no particular reason for this code to be here, other than that
@@ -1204,6 +1243,25 @@ END(disabled_fp_reg)
// 0x5600 Entry 26 (size 16 bundles) Nat Consumption (11,23,37,50)
ENTRY(nat_consumption)
DBG_FAULT(26)
+
+ mov r16=cr.ipsr
+ mov r17=cr.isr
+ mov r31=pr // save PR
+ ;;
+ and r18=0xf,r17 // r18 = cr.ipsr.code{3:0}
+ tbit.z p6,p0=r17,IA64_ISR_NA_BIT
+ ;;
+ cmp.ne.or p6,p0=IA64_ISR_CODE_LFETCH,r18
+ dep r16=-1,r16,IA64_PSR_ED_BIT,1
+(p6) br.cond.spnt 1f // branch if (cr.ispr.na == 0 || cr.ipsr.code{3:0} != LFETCH)
+ ;;
+ mov cr.ipsr=r16 // set cr.ipsr.na
+ mov pr=r31,-1
+ ;;
+ rfi
+
+1: mov pr=r31,-1
+ ;;
FAULT(26)
END(nat_consumption)
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 5978823d5c63..884f5cd27d8a 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -34,6 +34,7 @@
#include <asm/pgtable.h>
#include <asm/kdebug.h>
+#include <asm/sections.h>
extern void jprobe_inst_return(void);
@@ -263,13 +264,33 @@ static inline void get_kprobe_inst(bundle_t *bundle, uint slot,
}
}
+/* Returns non-zero if the addr is in the Interrupt Vector Table */
+static inline int in_ivt_functions(unsigned long addr)
+{
+ return (addr >= (unsigned long)__start_ivt_text
+ && addr < (unsigned long)__end_ivt_text);
+}
+
static int valid_kprobe_addr(int template, int slot, unsigned long addr)
{
if ((slot > 2) || ((bundle_encoding[template][1] == L) && slot > 1)) {
- printk(KERN_WARNING "Attempting to insert unaligned kprobe at 0x%lx\n",
- addr);
+ printk(KERN_WARNING "Attempting to insert unaligned kprobe "
+ "at 0x%lx\n", addr);
return -EINVAL;
}
+
+ if (in_ivt_functions(addr)) {
+ printk(KERN_WARNING "Kprobes can't be inserted inside "
+ "IVT functions at 0x%lx\n", addr);
+ return -EINVAL;
+ }
+
+ if (slot == 1 && bundle_encoding[template][1] != L) {
+ printk(KERN_WARNING "Inserting kprobes on slot #1 "
+ "is not supported\n");
+ return -EINVAL;
+ }
+
return 0;
}
@@ -290,6 +311,94 @@ static inline void set_current_kprobe(struct kprobe *p)
current_kprobe = p;
}
+static void kretprobe_trampoline(void)
+{
+}
+
+/*
+ * At this point the target function has been tricked into
+ * returning into our trampoline. Lookup the associated instance
+ * and then:
+ * - call the handler function
+ * - cleanup by marking the instance as unused
+ * - long jump back to the original return address
+ */
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
+ unsigned long orig_ret_address = 0;
+ unsigned long trampoline_address =
+ ((struct fnptr *)kretprobe_trampoline)->ip;
+
+ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+ recycle_rp_inst(ri);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+
+ BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ regs->cr_iip = orig_ret_address;
+
+ unlock_kprobes();
+ preempt_enable_no_resched();
+
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we have handled unlocking
+ * and re-enabling preemption.
+ */
+ return 1;
+}
+
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri;
+
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
+ ri->ret_addr = (kprobe_opcode_t *)regs->b0;
+
+ /* Replace the return addr with trampoline addr */
+ regs->b0 = ((struct fnptr *)kretprobe_trampoline)->ip;
+
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
+}
+
int arch_prepare_kprobe(struct kprobe *p)
{
unsigned long addr = (unsigned long) p->addr;
@@ -492,8 +601,8 @@ static int pre_kprobes_handler(struct die_args *args)
if (p->pre_handler && p->pre_handler(p, regs))
/*
* Our pre-handler is specifically requesting that we just
- * do a return. This is handling the case where the
- * pre-handler is really our special jprobe pre-handler.
+ * do a return. This is used for both the jprobe pre-handler
+ * and the kretprobe trampoline
*/
return 1;
@@ -599,3 +708,14 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
*regs = jprobe_saved_regs;
return 1;
}
+
+static struct kprobe trampoline_p = {
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ trampoline_p.addr =
+ (kprobe_opcode_t *)((struct fnptr *)kretprobe_trampoline)->ip;
+ return register_kprobe(&trampoline_p);
+}
diff --git a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
index 736e328b5e61..4ebbf3974381 100644
--- a/arch/ia64/kernel/mca.c
+++ b/arch/ia64/kernel/mca.c
@@ -271,7 +271,7 @@ ia64_mca_log_sal_error_record(int sal_info_type)
#ifdef CONFIG_ACPI
-static int cpe_vector = -1;
+int cpe_vector = -1;
static irqreturn_t
ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
diff --git a/arch/ia64/kernel/numa.c b/arch/ia64/kernel/numa.c
new file mode 100644
index 000000000000..a68ce6678092
--- /dev/null
+++ b/arch/ia64/kernel/numa.c
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ * ia64 kernel NUMA specific stuff
+ *
+ * Copyright (C) 2002 Erich Focht <efocht@ess.nec.de>
+ * Copyright (C) 2004 Silicon Graphics, Inc.
+ * Jesse Barnes <jbarnes@sgi.com>
+ */
+#include <linux/config.h>
+#include <linux/topology.h>
+#include <linux/module.h>
+#include <asm/processor.h>
+#include <asm/smp.h>
+
+u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
+EXPORT_SYMBOL(cpu_to_node_map);
+
+cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
+
+/**
+ * build_cpu_to_node_map - setup cpu to node and node to cpumask arrays
+ *
+ * Build cpu to node mapping and initialize the per node cpu masks using
+ * info from the node_cpuid array handed to us by ACPI.
+ */
+void __init build_cpu_to_node_map(void)
+{
+ int cpu, i, node;
+
+ for(node=0; node < MAX_NUMNODES; node++)
+ cpus_clear(node_to_cpu_mask[node]);
+
+ for(cpu = 0; cpu < NR_CPUS; ++cpu) {
+ node = -1;
+ for (i = 0; i < NR_CPUS; ++i)
+ if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
+ node = node_cpuid[i].nid;
+ break;
+ }
+ cpu_to_node_map[cpu] = (node >= 0) ? node : 0;
+ if (node >= 0)
+ cpu_set(cpu, node_to_cpu_mask[node]);
+ }
+}
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 6407bff6bfd7..b8ebb8e427ef 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -37,7 +37,6 @@
#include <linux/vfs.h>
#include <linux/pagemap.h>
#include <linux/mount.h>
-#include <linux/version.h>
#include <linux/bitops.h>
#include <asm/errno.h>
diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
index ebb71f3d6d19..e484910246ad 100644
--- a/arch/ia64/kernel/process.c
+++ b/arch/ia64/kernel/process.c
@@ -27,6 +27,7 @@
#include <linux/efi.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
+#include <linux/kprobes.h>
#include <asm/cpu.h>
#include <asm/delay.h>
@@ -195,6 +196,7 @@ update_pal_halt_status(int status)
void
default_idle (void)
{
+ local_irq_enable();
while (!need_resched())
if (can_do_pal_halt)
safe_halt();
@@ -707,6 +709,13 @@ kernel_thread_helper (int (*fn)(void *), void *arg)
void
flush_thread (void)
{
+ /*
+ * Remove function-return probe instances associated with this task
+ * and put them back on the free list. Do not insert an exit probe for
+ * this function, it will be disabled by kprobe_flush_task if you do.
+ */
+ kprobe_flush_task(current);
+
/* drop floating-point and debug-register state if it exists: */
current->thread.flags &= ~(IA64_THREAD_FPH_VALID | IA64_THREAD_DBG_VALID);
ia64_drop_fpu(current);
@@ -721,6 +730,14 @@ flush_thread (void)
void
exit_thread (void)
{
+
+ /*
+ * Remove function-return probe instances associated with this task
+ * and put them back on the free list. Do not insert an exit probe for
+ * this function, it will be disabled by kprobe_flush_task if you do.
+ */
+ kprobe_flush_task(current);
+
ia64_drop_fpu(current);
#ifdef CONFIG_PERFMON
/* if needed, stop monitoring and flush state to perfmon context */
diff --git a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
index 6d57aebad485..bbb8bc7c0552 100644
--- a/arch/ia64/kernel/ptrace.c
+++ b/arch/ia64/kernel/ptrace.c
@@ -725,12 +725,32 @@ convert_to_non_syscall (struct task_struct *child, struct pt_regs *pt,
break;
}
+ /*
+ * Note: at the time of this call, the target task is blocked
+ * in notify_resume_user() and by clearling PRED_LEAVE_SYSCALL
+ * (aka, "pLvSys") we redirect execution from
+ * .work_pending_syscall_end to .work_processed_kernel.
+ */
unw_get_pr(&prev_info, &pr);
- pr &= ~(1UL << PRED_SYSCALL);
+ pr &= ~((1UL << PRED_SYSCALL) | (1UL << PRED_LEAVE_SYSCALL));
pr |= (1UL << PRED_NON_SYSCALL);
unw_set_pr(&prev_info, pr);
pt->cr_ifs = (1UL << 63) | cfm;
+ /*
+ * Clear the memory that is NOT written on syscall-entry to
+ * ensure we do not leak kernel-state to user when execution
+ * resumes.
+ */
+ pt->r2 = 0;
+ pt->r3 = 0;
+ pt->r14 = 0;
+ memset(&pt->r16, 0, 16*8); /* clear r16-r31 */
+ memset(&pt->f6, 0, 6*16); /* clear f6-f11 */
+ pt->b7 = 0;
+ pt->ar_ccv = 0;
+ pt->ar_csd = 0;
+ pt->ar_ssd = 0;
}
static int
diff --git a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
index d14692e0920a..5c7c95737bbf 100644
--- a/arch/ia64/kernel/setup.c
+++ b/arch/ia64/kernel/setup.c
@@ -40,6 +40,8 @@
#include <linux/serial_core.h>
#include <linux/efi.h>
#include <linux/initrd.h>
+#include <linux/platform.h>
+#include <linux/pm.h>
#include <asm/ia32.h>
#include <asm/machvec.h>
@@ -72,6 +74,8 @@ DEFINE_PER_CPU(unsigned long, ia64_phys_stacked_size_p8);
unsigned long ia64_cycles_per_usec;
struct ia64_boot_param *ia64_boot_param;
struct screen_info screen_info;
+unsigned long vga_console_iobase;
+unsigned long vga_console_membase;
unsigned long ia64_max_cacheline_size;
unsigned long ia64_iobase; /* virtual address for I/O accesses */
@@ -273,23 +277,25 @@ io_port_init (void)
static inline int __init
early_console_setup (char *cmdline)
{
+ int earlycons = 0;
+
#ifdef CONFIG_SERIAL_SGI_L1_CONSOLE
{
extern int sn_serial_console_early_setup(void);
if (!sn_serial_console_early_setup())
- return 0;
+ earlycons++;
}
#endif
#ifdef CONFIG_EFI_PCDP
if (!efi_setup_pcdp_console(cmdline))
- return 0;
+ earlycons++;
#endif
#ifdef CONFIG_SERIAL_8250_CONSOLE
if (!early_serial_console_init(cmdline))
- return 0;
+ earlycons++;
#endif
- return -1;
+ return (earlycons) ? 0 : -1;
}
static inline void
@@ -779,6 +785,7 @@ cpu_init (void)
/* size of physical stacked register partition plus 8 bytes: */
__get_cpu_var(ia64_phys_stacked_size_p8) = num_phys_stacked*8 + 8;
platform_cpu_init();
+ pm_idle = default_idle;
}
void
diff --git a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
index edd9f07860b2..b8a0a7d257a9 100644
--- a/arch/ia64/kernel/signal.c
+++ b/arch/ia64/kernel/signal.c
@@ -143,6 +143,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
psr->mfh = 0; /* drop signal handler's fph contents... */
+ preempt_disable();
if (psr->dfh)
ia64_drop_fpu(current);
else {
@@ -150,6 +151,7 @@ restore_sigcontext (struct sigcontext __user *sc, struct sigscratch *scr)
__ia64_load_fpu(current->thread.fph);
ia64_set_local_fpu_owner(current);
}
+ preempt_enable();
}
return err;
}
diff --git a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
index b49d4ddaab93..0166a9847095 100644
--- a/arch/ia64/kernel/smp.c
+++ b/arch/ia64/kernel/smp.c
@@ -231,13 +231,16 @@ smp_flush_tlb_all (void)
void
smp_flush_tlb_mm (struct mm_struct *mm)
{
+ preempt_disable();
/* this happens for the common case of a single-threaded fork(): */
if (likely(mm == current->active_mm && atomic_read(&mm->mm_users) == 1))
{
local_finish_flush_tlb_mm(mm);
+ preempt_enable();
return;
}
+ preempt_enable();
/*
* We could optimize this further by using mm->cpu_vm_mask to track which CPUs
* have been running in the address space. It's not clear that this is worth the
diff --git a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
index 3865f088ffa2..7d72c0d872b3 100644
--- a/arch/ia64/kernel/smpboot.c
+++ b/arch/ia64/kernel/smpboot.c
@@ -346,6 +346,7 @@ smp_callin (void)
lock_ipi_calllock();
cpu_set(cpuid, cpu_online_map);
unlock_ipi_calllock();
+ per_cpu(cpu_state, cpuid) = CPU_ONLINE;
smp_setup_percpu_timer();
@@ -524,47 +525,6 @@ smp_build_cpu_map (void)
}
}
-#ifdef CONFIG_NUMA
-
-/* on which node is each logical CPU (one cacheline even for 64 CPUs) */
-u8 cpu_to_node_map[NR_CPUS] __cacheline_aligned;
-EXPORT_SYMBOL(cpu_to_node_map);
-/* which logical CPUs are on which nodes */
-cpumask_t node_to_cpu_mask[MAX_NUMNODES] __cacheline_aligned;
-
-/*
- * Build cpu to node mapping and initialize the per node cpu masks.
- */
-void __init
-build_cpu_to_node_map (void)
-{
- int cpu, i, node;
-
- for(node=0; node<MAX_NUMNODES; node++)
- cpus_clear(node_to_cpu_mask[node]);
- for(cpu = 0; cpu < NR_CPUS; ++cpu) {
- /*
- * All Itanium NUMA platforms I know use ACPI, so maybe we
- * can drop this ifdef completely. [EF]
- */
-#ifdef CONFIG_ACPI_NUMA
- node = -1;
- for (i = 0; i < NR_CPUS; ++i)
- if (cpu_physical_id(cpu) == node_cpuid[i].phys_id) {
- node = node_cpuid[i].nid;
- break;
- }
-#else
-# error Fixme: Dunno how to build CPU-to-node map.
-#endif
- cpu_to_node_map[cpu] = (node >= 0) ? node : 0;
- if (node >= 0)
- cpu_set(cpu, node_to_cpu_mask[node]);
- }
-}
-
-#endif /* CONFIG_NUMA */
-
/*
* Cycle through the APs sending Wakeup IPIs to boot each.
*/
@@ -611,6 +571,7 @@ void __devinit smp_prepare_boot_cpu(void)
{
cpu_set(smp_processor_id(), cpu_online_map);
cpu_set(smp_processor_id(), cpu_callin_map);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
}
/*
@@ -688,6 +649,7 @@ int __cpu_disable(void)
return -EBUSY;
remove_siblinginfo(cpu);
+ cpu_clear(cpu, cpu_online_map);
fixup_irqs();
local_flush_tlb_all();
cpu_clear(cpu, cpu_callin_map);
@@ -774,6 +736,7 @@ __cpu_up (unsigned int cpu)
if (cpu_isset(cpu, cpu_callin_map))
return -EINVAL;
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Processor goes to start_secondary(), sets online flag */
ret = do_boot_cpu(sapicid, cpu);
if (ret < 0)
diff --git a/arch/ia64/kernel/topology.c b/arch/ia64/kernel/topology.c
index f1aafd4c05f9..d8030f3bd865 100644
--- a/arch/ia64/kernel/topology.c
+++ b/arch/ia64/kernel/topology.c
@@ -36,6 +36,13 @@ int arch_register_cpu(int num)
parent = &sysfs_nodes[cpu_to_node(num)];
#endif /* CONFIG_NUMA */
+ /*
+ * If CPEI cannot be re-targetted, and this is
+ * CPEI target, then dont create the control file
+ */
+ if (!can_cpei_retarget() && is_cpu_cpei_target(num))
+ sysfs_cpus[num].cpu.no_control = 1;
+
return register_cpu(&sysfs_cpus[num].cpu, num, parent);
}
diff --git a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
index e7e520d90f03..4440c8343fa4 100644
--- a/arch/ia64/kernel/traps.c
+++ b/arch/ia64/kernel/traps.c
@@ -90,14 +90,16 @@ die (const char *str, struct pt_regs *regs, long err)
.lock_owner_depth = 0
};
static int die_counter;
+ int cpu = get_cpu();
- if (die.lock_owner != smp_processor_id()) {
+ if (die.lock_owner != cpu) {
console_verbose();
spin_lock_irq(&die.lock);
- die.lock_owner = smp_processor_id();
+ die.lock_owner = cpu;
die.lock_owner_depth = 0;
bust_spinlocks(1);
}
+ put_cpu();
if (++die.lock_owner_depth < 3) {
printk("%s[%d]: %s %ld [%d]\n",
diff --git a/arch/ia64/kernel/vmlinux.lds.S b/arch/ia64/kernel/vmlinux.lds.S
index b9f0db4c1b04..a676e79e0681 100644
--- a/arch/ia64/kernel/vmlinux.lds.S
+++ b/arch/ia64/kernel/vmlinux.lds.S
@@ -8,6 +8,11 @@
#define LOAD_OFFSET (KERNEL_START - KERNEL_TR_PAGE_SIZE)
#include <asm-generic/vmlinux.lds.h>
+#define IVT_TEXT \
+ VMLINUX_SYMBOL(__start_ivt_text) = .; \
+ *(.text.ivt) \
+ VMLINUX_SYMBOL(__end_ivt_text) = .;
+
OUTPUT_FORMAT("elf64-ia64-little")
OUTPUT_ARCH(ia64)
ENTRY(phys_start)
@@ -39,7 +44,7 @@ SECTIONS
.text : AT(ADDR(.text) - LOAD_OFFSET)
{
- *(.text.ivt)
+ IVT_TEXT
*(.text)
SCHED_TEXT
LOCK_TEXT
diff --git a/arch/ia64/mm/discontig.c b/arch/ia64/mm/discontig.c
index f3fd528ead3b..b5c90e548195 100644
--- a/arch/ia64/mm/discontig.c
+++ b/arch/ia64/mm/discontig.c
@@ -44,150 +44,7 @@ struct early_node_data {
};
static struct early_node_data mem_data[MAX_NUMNODES] __initdata;
-
-/**
- * reassign_cpu_only_nodes - called from find_memory to move CPU-only nodes to a memory node
- *
- * This function will move nodes with only CPUs (no memory)
- * to a node with memory which is at the minimum numa_slit distance.
- * Any reassigments will result in the compression of the nodes
- * and renumbering the nid values where appropriate.
- * The static declarations below are to avoid large stack size which
- * makes the code not re-entrant.
- */
-static void __init reassign_cpu_only_nodes(void)
-{
- struct node_memblk_s *p;
- int i, j, k, nnode, nid, cpu, cpunid, pxm;
- u8 cslit, slit;
- static DECLARE_BITMAP(nodes_with_mem, MAX_NUMNODES) __initdata;
- static u8 numa_slit_fix[MAX_NUMNODES * MAX_NUMNODES] __initdata;
- static int node_flip[MAX_NUMNODES] __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)) {
- set_bit(p->nid, (void *) nodes_with_mem);
- nnode++;
- }
-
- /*
- * All nids with memory.
- */
- if (nnode == num_online_nodes())
- return;
-
- /*
- * Change nids and attempt to migrate CPU-only nodes
- * to the best numa_slit (closest neighbor) possible.
- * For reassigned CPU nodes a nid can't be arrived at
- * until after this loop because the target nid's new
- * identity might not have been established yet. So
- * new nid values are fabricated above num_online_nodes() and
- * mapped back later to their true value.
- */
- /* MCD - This code is a bit complicated, but may be unnecessary now.
- * We can now handle much more interesting node-numbering.
- * The old requirement that 0 <= nid <= numnodes <= MAX_NUMNODES
- * and that there be no holes in the numbering 0..numnodes
- * has become simply 0 <= nid <= MAX_NUMNODES.
- */
- nid = 0;
- for_each_online_node(i) {
- if (test_bit(i, (void *) nodes_with_mem)) {
- /*
- * Save original nid value for numa_slit
- * fixup and node_cpuid reassignments.
- */
- node_flip[nid] = i;
-
- if (i == nid) {
- nid++;
- continue;
- }
-
- for (p = &node_memblk[0]; p < &node_memblk[num_node_memblks]; p++)
- if (p->nid == i)
- p->nid = nid;
-
- cpunid = nid;
- nid++;
- } else
- cpunid = MAX_NUMNODES;
-
- for (cpu = 0; cpu < NR_CPUS; cpu++)
- if (node_cpuid[cpu].nid == i) {
- /*
- * For nodes not being reassigned just
- * fix the cpu's nid and reverse pxm map
- */
- if (cpunid < MAX_NUMNODES) {
- pxm = nid_to_pxm_map[i];
- pxm_to_nid_map[pxm] =
- node_cpuid[cpu].nid = cpunid;
- continue;
- }
-
- /*
- * For nodes being reassigned, find best node by
- * numa_slit information and then make a temporary
- * nid value based on current nid and num_online_nodes().
- */
- slit = 0xff;
- k = 2*num_online_nodes();
- for_each_online_node(j) {
- if (i == j)
- continue;
- else if (test_bit(j, (void *) nodes_with_mem)) {
- cslit = numa_slit[i * num_online_nodes() + j];
- if (cslit < slit) {
- k = num_online_nodes() + j;
- slit = cslit;
- }
- }
- }
-
- /* save old nid map so we can update the pxm */
- old_nid_map[cpu] = node_cpuid[cpu].nid;
- node_cpuid[cpu].nid = k;
- }
- }
-
- /*
- * Fixup temporary nid values for CPU-only nodes.
- */
- for (cpu = 0; cpu < NR_CPUS; cpu++)
- if (node_cpuid[cpu].nid == (2*num_online_nodes())) {
- 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 - num_online_nodes()))
- 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
- * nid array to reduced nid array.
- */
- for (i = 0; i < nnode; i++)
- for (j = 0; j < nnode; j++)
- numa_slit_fix[i * nnode + j] =
- numa_slit[node_flip[i] * num_online_nodes() + node_flip[j]];
-
- memcpy(numa_slit, numa_slit_fix, sizeof (numa_slit));
-
- nodes_clear(node_online_map);
- for (i = 0; i < nnode; i++)
- node_set_online(i);
-
- return;
-}
+static nodemask_t memory_less_mask __initdata;
/*
* To prevent cache aliasing effects, align per-node structures so that they
@@ -233,44 +90,101 @@ static int __init build_node_maps(unsigned long start, unsigned long len,
}
/**
- * early_nr_phys_cpus_node - return number of physical cpus on a given node
+ * early_nr_cpus_node - return number of cpus on a given node
* @node: node to check
*
- * Count the number of physical cpus on @node. These are cpus that actually
- * exist. We can't use nr_cpus_node() yet because
+ * Count the number of cpus on @node. We can't use nr_cpus_node() yet because
* acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
- * called yet.
+ * called yet. Note that node 0 will also count all non-existent cpus.
*/
-static int early_nr_phys_cpus_node(int node)
+static int __init early_nr_cpus_node(int node)
{
int cpu, n = 0;
for (cpu = 0; cpu < NR_CPUS; cpu++)
if (node == node_cpuid[cpu].nid)
- if ((cpu == 0) || node_cpuid[cpu].phys_id)
- n++;
+ n++;
return n;
}
+/**
+ * compute_pernodesize - compute size of pernode data
+ * @node: the node id.
+ */
+static unsigned long __init compute_pernodesize(int node)
+{
+ unsigned long pernodesize = 0, cpus;
+
+ cpus = early_nr_cpus_node(node);
+ pernodesize += PERCPU_PAGE_SIZE * cpus;
+ pernodesize += node * L1_CACHE_BYTES;
+ pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
+ pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+ pernodesize = PAGE_ALIGN(pernodesize);
+ return pernodesize;
+}
/**
- * early_nr_cpus_node - return number of cpus on a given node
- * @node: node to check
+ * per_cpu_node_setup - setup per-cpu areas on each node
+ * @cpu_data: per-cpu area on this node
+ * @node: node to setup
*
- * Count the number of cpus on @node. We can't use nr_cpus_node() yet because
- * acpi_boot_init() (which builds the node_to_cpu_mask array) hasn't been
- * called yet. Note that node 0 will also count all non-existent cpus.
+ * Copy the static per-cpu data into the region we just set aside and then
+ * setup __per_cpu_offset for each CPU on this node. Return a pointer to
+ * the end of the area.
*/
-static int early_nr_cpus_node(int node)
+static void *per_cpu_node_setup(void *cpu_data, int node)
{
- int cpu, n = 0;
+#ifdef CONFIG_SMP
+ int cpu;
- for (cpu = 0; cpu < NR_CPUS; cpu++)
- if (node == node_cpuid[cpu].nid)
- n++;
+ for (cpu = 0; cpu < NR_CPUS; cpu++) {
+ if (node == node_cpuid[cpu].nid) {
+ memcpy(__va(cpu_data), __phys_per_cpu_start,
+ __per_cpu_end - __per_cpu_start);
+ __per_cpu_offset[cpu] = (char*)__va(cpu_data) -
+ __per_cpu_start;
+ cpu_data += PERCPU_PAGE_SIZE;
+ }
+ }
+#endif
+ return cpu_data;
+}
- return n;
+/**
+ * fill_pernode - initialize pernode data.
+ * @node: the node id.
+ * @pernode: physical address of pernode data
+ * @pernodesize: size of the pernode data
+ */
+static void __init fill_pernode(int node, unsigned long pernode,
+ unsigned long pernodesize)
+{
+ void *cpu_data;
+ int cpus = early_nr_cpus_node(node);
+ struct bootmem_data *bdp = &mem_data[node].bootmem_data;
+
+ mem_data[node].pernode_addr = pernode;
+ mem_data[node].pernode_size = pernodesize;
+ memset(__va(pernode), 0, pernodesize);
+
+ cpu_data = (void *)pernode;
+ pernode += PERCPU_PAGE_SIZE * cpus;
+ pernode += node * L1_CACHE_BYTES;
+
+ mem_data[node].pgdat = __va(pernode);
+ pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+ mem_data[node].node_data = __va(pernode);
+ pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
+
+ mem_data[node].pgdat->bdata = bdp;
+ pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
+
+ cpu_data = per_cpu_node_setup(cpu_data, node);
+
+ return;
}
/**
@@ -304,9 +218,8 @@ static int early_nr_cpus_node(int node)
static int __init find_pernode_space(unsigned long start, unsigned long len,
int node)
{
- unsigned long epfn, cpu, cpus, phys_cpus;
+ unsigned long epfn;
unsigned long pernodesize = 0, pernode, pages, mapsize;
- void *cpu_data;
struct bootmem_data *bdp = &mem_data[node].bootmem_data;
epfn = (start + len) >> PAGE_SHIFT;
@@ -329,49 +242,12 @@ static int __init find_pernode_space(unsigned long start, unsigned long len,
* Calculate total size needed, incl. what's necessary
* for good alignment and alias prevention.
*/
- cpus = early_nr_cpus_node(node);
- phys_cpus = early_nr_phys_cpus_node(node);
- pernodesize += PERCPU_PAGE_SIZE * cpus;
- pernodesize += node * L1_CACHE_BYTES;
- pernodesize += L1_CACHE_ALIGN(sizeof(pg_data_t));
- pernodesize += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
- pernodesize = PAGE_ALIGN(pernodesize);
+ pernodesize = compute_pernodesize(node);
pernode = NODEDATA_ALIGN(start, node);
/* Is this range big enough for what we want to store here? */
- if (start + len > (pernode + pernodesize + mapsize)) {
- mem_data[node].pernode_addr = pernode;
- mem_data[node].pernode_size = pernodesize;
- memset(__va(pernode), 0, pernodesize);
-
- cpu_data = (void *)pernode;
- pernode += PERCPU_PAGE_SIZE * cpus;
- pernode += node * L1_CACHE_BYTES;
-
- mem_data[node].pgdat = __va(pernode);
- pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
-
- mem_data[node].node_data = __va(pernode);
- pernode += L1_CACHE_ALIGN(sizeof(struct ia64_node_data));
-
- mem_data[node].pgdat->bdata = bdp;
- pernode += L1_CACHE_ALIGN(sizeof(pg_data_t));
-
- /*
- * Copy the static per-cpu data into the region we
- * just set aside and then setup __per_cpu_offset
- * for each CPU on this node.
- */
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- if (node == node_cpuid[cpu].nid) {
- memcpy(__va(cpu_data), __phys_per_cpu_start,
- __per_cpu_end - __per_cpu_start);
- __per_cpu_offset[cpu] = (char*)__va(cpu_data) -
- __per_cpu_start;
- cpu_data += PERCPU_PAGE_SIZE;
- }
- }
- }
+ if (start + len > (pernode + pernodesize + mapsize))
+ fill_pernode(node, pernode, pernodesize);
return 0;
}
@@ -411,6 +287,9 @@ static void __init reserve_pernode_space(void)
for_each_online_node(node) {
pg_data_t *pdp = mem_data[node].pgdat;
+ if (node_isset(node, memory_less_mask))
+ continue;
+
bdp = pdp->bdata;
/* First the bootmem_map itself */
@@ -436,8 +315,8 @@ static void __init reserve_pernode_space(void)
*/
static void __init initialize_pernode_data(void)
{
- int cpu, node;
pg_data_t *pgdat_list[MAX_NUMNODES];
+ int cpu, node;
for_each_online_node(node)
pgdat_list[node] = mem_data[node].pgdat;
@@ -447,12 +326,99 @@ static void __init initialize_pernode_data(void)
memcpy(mem_data[node].node_data->pg_data_ptrs, pgdat_list,
sizeof(pgdat_list));
}
-
+#ifdef CONFIG_SMP
/* Set the node_data pointer for each per-cpu struct */
for (cpu = 0; cpu < NR_CPUS; cpu++) {
node = node_cpuid[cpu].nid;
per_cpu(cpu_info, cpu).node_data = mem_data[node].node_data;
}
+#else
+ {
+ struct cpuinfo_ia64 *cpu0_cpu_info;
+ cpu = 0;
+ node = node_cpuid[cpu].nid;
+ cpu0_cpu_info = (struct cpuinfo_ia64 *)(__phys_per_cpu_start +
+ ((char *)&per_cpu__cpu_info - __per_cpu_start));
+ cpu0_cpu_info->node_data = mem_data[node].node_data;
+ }
+#endif /* CONFIG_SMP */
+}
+
+/**
+ * memory_less_node_alloc - * attempt to allocate memory on the best NUMA slit
+ * node but fall back to any other node when __alloc_bootmem_node fails
+ * for best.
+ * @nid: node id
+ * @pernodesize: size of this node's pernode data
+ * @align: alignment to use for this node's pernode data
+ */
+static void __init *memory_less_node_alloc(int nid, unsigned long pernodesize,
+ unsigned long align)
+{
+ void *ptr = NULL;
+ u8 best = 0xff;
+ int bestnode = -1, node;
+
+ for_each_online_node(node) {
+ if (node_isset(node, memory_less_mask))
+ continue;
+ else if (node_distance(nid, node) < best) {
+ best = node_distance(nid, node);
+ bestnode = node;
+ }
+ }
+
+ ptr = __alloc_bootmem_node(mem_data[bestnode].pgdat,
+ pernodesize, align, __pa(MAX_DMA_ADDRESS));
+
+ if (!ptr)
+ panic("NO memory for memory less node\n");
+ return ptr;
+}
+
+/**
+ * pgdat_insert - insert the pgdat into global pgdat_list
+ * @pgdat: the pgdat for a node.
+ */
+static void __init pgdat_insert(pg_data_t *pgdat)
+{
+ pg_data_t *prev = NULL, *next;
+
+ for_each_pgdat(next)
+ if (pgdat->node_id < next->node_id)
+ break;
+ else
+ prev = next;
+
+ if (prev) {
+ prev->pgdat_next = pgdat;
+ pgdat->pgdat_next = next;
+ } else {
+ pgdat->pgdat_next = pgdat_list;
+ pgdat_list = pgdat;
+ }
+
+ return;
+}
+
+/**
+ * memory_less_nodes - allocate and initialize CPU only nodes pernode
+ * information.
+ */
+static void __init memory_less_nodes(void)
+{
+ unsigned long pernodesize;
+ void *pernode;
+ int node;
+
+ for_each_node_mask(node, memory_less_mask) {
+ pernodesize = compute_pernodesize(node);
+ pernode = memory_less_node_alloc(node, pernodesize,
+ (node) ? (node * PERCPU_PAGE_SIZE) : (1024*1024));
+ fill_pernode(node, __pa(pernode), pernodesize);
+ }
+
+ return;
}
/**
@@ -472,16 +438,19 @@ void __init find_memory(void)
node_set_online(0);
}
+ nodes_or(memory_less_mask, memory_less_mask, node_online_map);
min_low_pfn = -1;
max_low_pfn = 0;
- if (num_online_nodes() > 1)
- reassign_cpu_only_nodes();
-
/* These actually end up getting called by call_pernode_memory() */
efi_memmap_walk(filter_rsvd_memory, build_node_maps);
efi_memmap_walk(filter_rsvd_memory, find_pernode_space);
+ for_each_online_node(node)
+ if (mem_data[node].bootmem_data.node_low_pfn) {
+ node_clear(node, memory_less_mask);
+ mem_data[node].min_pfn = ~0UL;
+ }
/*
* Initialize the boot memory maps in reverse order since that's
* what the bootmem allocator expects
@@ -492,17 +461,14 @@ void __init find_memory(void)
if (!node_online(node))
continue;
+ else if (node_isset(node, memory_less_mask))
+ continue;
bdp = &mem_data[node].bootmem_data;
pernode = mem_data[node].pernode_addr;
pernodesize = mem_data[node].pernode_size;
map = pernode + pernodesize;
- /* Sanity check... */
- if (!pernode)
- panic("pernode space for node %d "
- "could not be allocated!", node);
-
init_bootmem_node(mem_data[node].pgdat,
map>>PAGE_SHIFT,
bdp->node_boot_start>>PAGE_SHIFT,
@@ -512,6 +478,7 @@ void __init find_memory(void)
efi_memmap_walk(filter_rsvd_memory, free_node_bootmem);
reserve_pernode_space();
+ memory_less_nodes();
initialize_pernode_data();
max_pfn = max_low_pfn;
@@ -519,6 +486,7 @@ void __init find_memory(void)
find_initrd();
}
+#ifdef CONFIG_SMP
/**
* per_cpu_init - setup per-cpu variables
*
@@ -529,15 +497,15 @@ void *per_cpu_init(void)
{
int cpu;
- if (smp_processor_id() == 0) {
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- per_cpu(local_per_cpu_offset, cpu) =
- __per_cpu_offset[cpu];
- }
- }
+ if (smp_processor_id() != 0)
+ return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
+
+ for (cpu = 0; cpu < NR_CPUS; cpu++)
+ per_cpu(local_per_cpu_offset, cpu) = __per_cpu_offset[cpu];
return __per_cpu_start + __per_cpu_offset[smp_processor_id()];
}
+#endif /* CONFIG_SMP */
/**
* show_mem - give short summary of memory stats
@@ -680,12 +648,13 @@ void __init paging_init(void)
max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
- /* so min() will work in count_node_pages */
- for_each_online_node(node)
- mem_data[node].min_pfn = ~0UL;
-
efi_memmap_walk(filter_rsvd_memory, count_node_pages);
+ vmalloc_end -= PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+ vmem_map = (struct page *) vmalloc_end;
+ efi_memmap_walk(create_mem_map_page_table, NULL);
+ printk("Virtual mem_map starts at 0x%p\n", vmem_map);
+
for_each_online_node(node) {
memset(zones_size, 0, sizeof(zones_size));
memset(zholes_size, 0, sizeof(zholes_size));
@@ -719,15 +688,6 @@ void __init paging_init(void)
mem_data[node].num_dma_physpages);
}
- if (node == 0) {
- vmalloc_end -=
- PAGE_ALIGN(max_low_pfn * sizeof(struct page));
- vmem_map = (struct page *) vmalloc_end;
-
- efi_memmap_walk(create_mem_map_page_table, NULL);
- printk("Virtual mem_map starts at 0x%p\n", vmem_map);
- }
-
pfn_offset = mem_data[node].min_pfn;
NODE_DATA(node)->node_mem_map = vmem_map + pfn_offset;
@@ -735,5 +695,11 @@ void __init paging_init(void)
pfn_offset, zholes_size);
}
+ /*
+ * Make memory less nodes become a member of the known nodes.
+ */
+ for_each_node_mask(node, memory_less_mask)
+ pgdat_insert(mem_data[node].pgdat);
+
zero_page_memmap_ptr = virt_to_page(ia64_imva(empty_zero_page));
}
diff --git a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
index 4eb2f52b87a1..65f9958db9f0 100644
--- a/arch/ia64/mm/init.c
+++ b/arch/ia64/mm/init.c
@@ -597,7 +597,8 @@ mem_init (void)
kclist_add(&kcore_kernel, _stext, _end - _stext);
for_each_pgdat(pgdat)
- totalram_pages += free_all_bootmem_node(pgdat);
+ if (pgdat->bdata->node_bootmem_map)
+ totalram_pages += free_all_bootmem_node(pgdat);
reserved_pages = 0;
efi_memmap_walk(count_reserved_pages, &reserved_pages);
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index e3fc4edea113..720a861f88be 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
&info);
- pbus = pci_scan_bus(bus, &pci_root_ops, controller);
+ pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
if (pbus)
pcibios_setup_root_windows(pbus, controller);
@@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev,
res->end = region->end + offset;
}
+static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
+{
+ unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+ struct resource *devr = &dev->resource[idx];
+
+ if (!dev->bus)
+ return 0;
+ for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
+ struct resource *busr = dev->bus->resource[i];
+
+ if (!busr || ((busr->flags ^ devr->flags) & type_mask))
+ continue;
+ if ((devr->start) && (devr->start >= busr->start) &&
+ (devr->end <= busr->end))
+ return 1;
+ }
+ return 0;
+}
+
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
{
struct pci_bus_region region;
@@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
region.start = dev->resource[i].start;
region.end = dev->resource[i].end;
pcibios_bus_to_resource(dev, &dev->resource[i], &region);
- pci_claim_resource(dev, i);
+ if ((is_valid_resource(dev, i)))
+ pci_claim_resource(dev, i);
}
}
@@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b)
{
struct pci_dev *dev;
+ if (b->self) {
+ pci_read_bridge_bases(b);
+ pcibios_fixup_device_resources(b->self);
+ }
list_for_each_entry(dev, &b->devices, bus_list)
pcibios_fixup_device_resources(dev);
@@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
u16 cmd, old_cmd;
int idx;
struct resource *r;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
if (!dev)
return -EINVAL;
pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd;
- for (idx=0; idx<6; idx++) {
+ for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
/* Only set up the desired resources. */
if (!(mask & (1 << idx)))
continue;
r = &dev->resource[idx];
+ if (!(r->flags & type_mask))
+ continue;
+ if ((idx == PCI_ROM_RESOURCE) &&
+ (!(r->flags & IORESOURCE_ROM_ENABLE)))
+ continue;
if (!r->start && r->end) {
printk(KERN_ERR
"PCI: Device %s not available because of resource collisions\n",
@@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY;
}
- if (dev->resource[PCI_ROM_RESOURCE].start)
- cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd);
diff --git a/arch/ia64/sn/include/xtalk/hubdev.h b/arch/ia64/sn/include/xtalk/hubdev.h
index 868e7ecae84b..580a1c0403a7 100644
--- a/arch/ia64/sn/include/xtalk/hubdev.h
+++ b/arch/ia64/sn/include/xtalk/hubdev.h
@@ -8,6 +8,8 @@
#ifndef _ASM_IA64_SN_XTALK_HUBDEV_H
#define _ASM_IA64_SN_XTALK_HUBDEV_H
+#include "xtalk/xwidgetdev.h"
+
#define HUB_WIDGET_ID_MAX 0xf
#define DEV_PER_WIDGET (2*2*8)
#define IIO_ITTE_WIDGET_BITS 4 /* size of widget field */
diff --git a/arch/ia64/sn/kernel/io_init.c b/arch/ia64/sn/kernel/io_init.c
index 9e07f5463f21..a67f39e448cb 100644
--- a/arch/ia64/sn/kernel/io_init.c
+++ b/arch/ia64/sn/kernel/io_init.c
@@ -9,21 +9,28 @@
#include <linux/bootmem.h>
#include <linux/nodemask.h>
#include <asm/sn/types.h>
-#include <asm/sn/sn_sal.h>
#include <asm/sn/addrs.h>
-#include <asm/sn/pcibus_provider_defs.h>
-#include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
-#include "xtalk/xwidgetdev.h"
#include <asm/sn/geo.h>
-#include "xtalk/hubdev.h"
#include <asm/sn/io.h>
+#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
#include <asm/sn/simulator.h>
+#include <asm/sn/sn_sal.h>
#include <asm/sn/tioca_provider.h>
+#include "xtalk/hubdev.h"
+#include "xtalk/xwidgetdev.h"
-char master_baseio_wid;
nasid_t master_nasid = INVALID_NASID; /* Partition Master */
+static struct list_head sn_sysdata_list;
+
+/* sysdata list struct */
+struct sysdata_el {
+ struct list_head entry;
+ void *sysdata;
+};
+
struct slab_info {
struct hubdev_info hubdev;
};
@@ -138,23 +145,6 @@ sal_get_pcidev_info(u64 segment, u64 bus_number, u64 devfn, u64 pci_dev,
}
/*
- * sn_alloc_pci_sysdata() - This routine allocates a pci controller
- * which is expected as the pci_dev and pci_bus sysdata by the Linux
- * PCI infrastructure.
- */
-static inline struct pci_controller *sn_alloc_pci_sysdata(void)
-{
- struct pci_controller *pci_sysdata;
-
- pci_sysdata = kmalloc(sizeof(*pci_sysdata), GFP_KERNEL);
- if (!pci_sysdata)
- BUG();
-
- memset(pci_sysdata, 0, sizeof(*pci_sysdata));
- return pci_sysdata;
-}
-
-/*
* sn_fixup_ionodes() - This routine initializes the HUB data strcuture for
* each node in the system.
*/
@@ -221,22 +211,34 @@ static void sn_fixup_ionodes(void)
}
+void sn_pci_unfixup_slot(struct pci_dev *dev)
+{
+ struct pci_dev *host_pci_dev = SN_PCIDEV_INFO(dev)->host_pci_dev;
+
+ sn_irq_unfixup(dev);
+ pci_dev_put(host_pci_dev);
+ pci_dev_put(dev);
+}
+
/*
* sn_pci_fixup_slot() - This routine sets up a slot's resources
* consistent with the Linux PCI abstraction layer. Resources acquired
* from our PCI provider include PIO maps to BAR space and interrupt
* objects.
*/
-static void sn_pci_fixup_slot(struct pci_dev *dev)
+void sn_pci_fixup_slot(struct pci_dev *dev)
{
int idx;
int segment = 0;
- uint64_t size;
- struct sn_irq_info *sn_irq_info;
- struct pci_dev *host_pci_dev;
int status = 0;
struct pcibus_bussoft *bs;
+ struct pci_bus *host_pci_bus;
+ struct pci_dev *host_pci_dev;
+ struct sn_irq_info *sn_irq_info;
+ unsigned long size;
+ unsigned int bus_no, devfn;
+ pci_dev_get(dev); /* for the sysdata pointer */
dev->sysdata = kmalloc(sizeof(struct pcidev_info), GFP_KERNEL);
if (SN_PCIDEV_INFO(dev) <= 0)
BUG(); /* Cannot afford to run out of memory */
@@ -253,7 +255,7 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
(u64) __pa(SN_PCIDEV_INFO(dev)),
(u64) __pa(sn_irq_info));
if (status)
- BUG(); /* Cannot get platform pci device information information */
+ BUG(); /* Cannot get platform pci device information */
/* Copy over PIO Mapped Addresses */
for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
@@ -275,15 +277,21 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
dev->resource[idx].parent = &iomem_resource;
}
- /* set up host bus linkages */
- bs = SN_PCIBUS_BUSSOFT(dev->bus);
- host_pci_dev =
- pci_find_slot(SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32,
- SN_PCIDEV_INFO(dev)->
- pdi_slot_host_handle & 0xffffffff);
+ /*
+ * Using the PROMs values for the PCI host bus, get the Linux
+ * PCI host_pci_dev struct and set up host bus linkages
+ */
+
+ bus_no = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle >> 32;
+ devfn = SN_PCIDEV_INFO(dev)->pdi_slot_host_handle & 0xffffffff;
+ host_pci_bus = pci_find_bus(pci_domain_nr(dev->bus), bus_no);
+ host_pci_dev = pci_get_slot(host_pci_bus, devfn);
+
+ SN_PCIDEV_INFO(dev)->host_pci_dev = host_pci_dev;
SN_PCIDEV_INFO(dev)->pdi_host_pcidev_info =
- SN_PCIDEV_INFO(host_pci_dev);
+ SN_PCIDEV_INFO(host_pci_dev);
SN_PCIDEV_INFO(dev)->pdi_linux_pcidev = dev;
+ bs = SN_PCIBUS_BUSSOFT(dev->bus);
SN_PCIDEV_INFO(dev)->pdi_pcibus_info = bs;
if (bs && bs->bs_asic_type < PCIIO_ASIC_MAX_TYPES) {
@@ -297,6 +305,9 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = sn_irq_info;
dev->irq = SN_PCIDEV_INFO(dev)->pdi_sn_irq_info->irq_irq;
sn_irq_fixup(dev, sn_irq_info);
+ } else {
+ SN_PCIDEV_INFO(dev)->pdi_sn_irq_info = NULL;
+ kfree(sn_irq_info);
}
}
@@ -304,55 +315,57 @@ static void sn_pci_fixup_slot(struct pci_dev *dev)
* sn_pci_controller_fixup() - This routine sets up a bus's resources
* consistent with the Linux PCI abstraction layer.
*/
-static void sn_pci_controller_fixup(int segment, int busnum)
+void sn_pci_controller_fixup(int segment, int busnum, struct pci_bus *bus)
{
int status = 0;
int nasid, cnode;
- struct pci_bus *bus;
struct pci_controller *controller;
struct pcibus_bussoft *prom_bussoft_ptr;
struct hubdev_info *hubdev_info;
void *provider_soft;
struct sn_pcibus_provider *provider;
- status =
- sal_get_pcibus_info((u64) segment, (u64) busnum,
- (u64) ia64_tpa(&prom_bussoft_ptr));
- if (status > 0) {
- return; /* bus # does not exist */
- }
-
+ status = sal_get_pcibus_info((u64) segment, (u64) busnum,
+ (u64) ia64_tpa(&prom_bussoft_ptr));
+ if (status > 0)
+ return; /*bus # does not exist */
prom_bussoft_ptr = __va(prom_bussoft_ptr);
- controller = sn_alloc_pci_sysdata();
- /* controller non-zero is BUG'd in sn_alloc_pci_sysdata */
- bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+ controller = kcalloc(1,sizeof(struct pci_controller), GFP_KERNEL);
+ if (!controller)
+ BUG();
+
if (bus == NULL) {
- return; /* error, or bus already scanned */
+ bus = pci_scan_bus(busnum, &pci_root_ops, controller);
+ if (bus == NULL)
+ return; /* error, or bus already scanned */
+ bus->sysdata = NULL;
}
+ if (bus->sysdata)
+ goto error_return; /* sysdata already alloc'd */
+
/*
* Per-provider fixup. Copies the contents from prom to local
* area and links SN_PCIBUS_BUSSOFT().
*/
- if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES) {
+ if (prom_bussoft_ptr->bs_asic_type >= PCIIO_ASIC_MAX_TYPES)
return; /* unsupported asic type */
- }
+
+ if (prom_bussoft_ptr->bs_asic_type == PCIIO_ASIC_TYPE_PPB)
+ goto error_return; /* no further fixup necessary */
provider = sn_pci_provider[prom_bussoft_ptr->bs_asic_type];
- if (provider == NULL) {
+ if (provider == NULL)
return; /* no provider registerd for this asic */
- }
provider_soft = NULL;
- if (provider->bus_fixup) {
+ if (provider->bus_fixup)
provider_soft = (*provider->bus_fixup) (prom_bussoft_ptr);
- }
- if (provider_soft == NULL) {
+ if (provider_soft == NULL)
return; /* fixup failed or not applicable */
- }
/*
* Generic bus fixup goes here. Don't reference prom_bussoft_ptr
@@ -361,12 +374,47 @@ static void sn_pci_controller_fixup(int segment, int busnum)
bus->sysdata = controller;
PCI_CONTROLLER(bus)->platform_data = provider_soft;
-
nasid = NASID_GET(SN_PCIBUS_BUSSOFT(bus)->bs_base);
cnode = nasid_to_cnodeid(nasid);
hubdev_info = (struct hubdev_info *)(NODEPDA(cnode)->pdinfo);
SN_PCIBUS_BUSSOFT(bus)->bs_xwidget_info =
&(hubdev_info->hdi_xwidget_info[SN_PCIBUS_BUSSOFT(bus)->bs_xid]);
+
+ return;
+
+error_return:
+
+ kfree(controller);
+ return;
+}
+
+void sn_bus_store_sysdata(struct pci_dev *dev)
+{
+ struct sysdata_el *element;
+
+ element = kcalloc(1, sizeof(struct sysdata_el), GFP_KERNEL);
+ if (!element) {
+ dev_dbg(dev, "%s: out of memory!\n", __FUNCTION__);
+ return;
+ }
+ element->sysdata = dev->sysdata;
+ list_add(&element->entry, &sn_sysdata_list);
+}
+
+void sn_bus_free_sysdata(void)
+{
+ struct sysdata_el *element;
+ struct list_head *list;
+
+sn_sysdata_free_start:
+ list_for_each(list, &sn_sysdata_list) {
+ element = list_entry(list, struct sysdata_el, entry);
+ list_del(&element->entry);
+ kfree(element->sysdata);
+ kfree(element);
+ goto sn_sysdata_free_start;
+ }
+ return;
}
/*
@@ -384,7 +432,7 @@ static int __init sn_pci_init(void)
extern void register_sn_procfs(void);
#endif
- if (!ia64_platform_is("sn2") || IS_RUNNING_ON_SIMULATOR())
+ if (!ia64_platform_is("sn2") || IS_RUNNING_ON_FAKE_PROM())
return 0;
/*
@@ -403,20 +451,17 @@ static int __init sn_pci_init(void)
*/
ia64_max_iommu_merge_mask = ~PAGE_MASK;
sn_fixup_ionodes();
- sn_irq = kmalloc(sizeof(struct sn_irq_info *) * NR_IRQS, GFP_KERNEL);
- if (sn_irq <= 0)
- BUG(); /* Canno afford to run out of memory. */
- memset(sn_irq, 0, sizeof(struct sn_irq_info *) * NR_IRQS);
-
+ sn_irq_lh_init();
+ INIT_LIST_HEAD(&sn_sysdata_list);
sn_init_cpei_timer();
#ifdef CONFIG_PROC_FS
register_sn_procfs();
#endif
- for (i = 0; i < PCI_BUSES_TO_SCAN; i++) {
- sn_pci_controller_fixup(0, i);
- }
+ /* busses are not known yet ... */
+ for (i = 0; i < PCI_BUSES_TO_SCAN; i++)
+ sn_pci_controller_fixup(0, i, NULL);
/*
* Generic Linux PCI Layer has created the pci_bus and pci_dev
@@ -425,9 +470,8 @@ static int __init sn_pci_init(void)
*/
while ((pci_dev =
- pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) {
+ pci_get_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL)
sn_pci_fixup_slot(pci_dev);
- }
sn_ioif_inited = 1; /* sn I/O infrastructure now initialized */
@@ -469,3 +513,8 @@ cnodeid_get_geoid(cnodeid_t cnode)
}
subsys_initcall(sn_pci_init);
+EXPORT_SYMBOL(sn_pci_fixup_slot);
+EXPORT_SYMBOL(sn_pci_unfixup_slot);
+EXPORT_SYMBOL(sn_pci_controller_fixup);
+EXPORT_SYMBOL(sn_bus_store_sysdata);
+EXPORT_SYMBOL(sn_bus_free_sysdata);
diff --git a/arch/ia64/sn/kernel/iomv.c b/arch/ia64/sn/kernel/iomv.c
index fec6d8b8237b..7ce3cdad627b 100644
--- a/arch/ia64/sn/kernel/iomv.c
+++ b/arch/ia64/sn/kernel/iomv.c
@@ -9,12 +9,16 @@
#include <linux/module.h>
#include <asm/io.h>
#include <asm/delay.h>
+#include <asm/vga.h>
#include <asm/sn/nodepda.h>
#include <asm/sn/simulator.h>
#include <asm/sn/pda.h>
#include <asm/sn/sn_cpuid.h>
#include <asm/sn/shub_mmr.h>
+#define IS_LEGACY_VGA_IOPORT(p) \
+ (((p) >= 0x3b0 && (p) <= 0x3bb) || ((p) >= 0x3c0 && (p) <= 0x3df))
+
/**
* sn_io_addr - convert an in/out port to an i/o address
* @port: port to convert
@@ -26,6 +30,8 @@
void *sn_io_addr(unsigned long port)
{
if (!IS_RUNNING_ON_SIMULATOR()) {
+ if (IS_LEGACY_VGA_IOPORT(port))
+ port += vga_console_iobase;
/* On sn2, legacy I/O ports don't point at anything */
if (port < (64 * 1024))
return NULL;
diff --git a/arch/ia64/sn/kernel/irq.c b/arch/ia64/sn/kernel/irq.c
index 0f4e8138658f..84d276a14ecb 100644
--- a/arch/ia64/sn/kernel/irq.c
+++ b/arch/ia64/sn/kernel/irq.c
@@ -9,13 +9,13 @@
*/
#include <linux/irq.h>
-#include <asm/sn/intr.h>
+#include <linux/spinlock.h>
#include <asm/sn/addrs.h>
#include <asm/sn/arch.h>
-#include "xtalk/xwidgetdev.h"
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
#include <asm/sn/shub_mmr.h>
#include <asm/sn/sn_sal.h>
@@ -25,7 +25,8 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info);
extern int sn_force_interrupt_flag;
extern int sn_ioif_inited;
-struct sn_irq_info **sn_irq;
+static struct list_head **sn_irq_lh;
+static spinlock_t sn_irq_info_lock = SPIN_LOCK_UNLOCKED; /* non-IRQ lock */
static inline uint64_t sn_intr_alloc(nasid_t local_nasid, int local_widget,
u64 sn_irq_info,
@@ -101,7 +102,7 @@ static void sn_end_irq(unsigned int irq)
nasid = get_nasid();
event_occurred = HUB_L((uint64_t *) GLOBAL_MMR_ADDR
(nasid, SH_EVENT_OCCURRED));
- /* If the UART bit is set here, we may have received an
+ /* If the UART bit is set here, we may have received an
* interrupt from the UART that the driver missed. To
* make sure, we IPI ourselves to force us to look again.
*/
@@ -115,82 +116,84 @@ static void sn_end_irq(unsigned int irq)
force_interrupt(irq);
}
+static void sn_irq_info_free(struct rcu_head *head);
+
static void sn_set_affinity_irq(unsigned int irq, cpumask_t mask)
{
- struct sn_irq_info *sn_irq_info = sn_irq[irq];
- struct sn_irq_info *tmp_sn_irq_info;
+ struct sn_irq_info *sn_irq_info, *sn_irq_info_safe;
int cpuid, cpuphys;
- nasid_t t_nasid; /* nasid to target */
- int t_slice; /* slice to target */
-
- /* allocate a temp sn_irq_info struct to get new target info */
- tmp_sn_irq_info = kmalloc(sizeof(*tmp_sn_irq_info), GFP_KERNEL);
- if (!tmp_sn_irq_info)
- return;
cpuid = first_cpu(mask);
cpuphys = cpu_physical_id(cpuid);
- t_nasid = cpuid_to_nasid(cpuid);
- t_slice = cpuid_to_slice(cpuid);
- while (sn_irq_info) {
- int status;
- int local_widget;
- uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
- nasid_t local_nasid = NASID_GET(bridge);
+ list_for_each_entry_safe(sn_irq_info, sn_irq_info_safe,
+ sn_irq_lh[irq], list) {
+ uint64_t bridge;
+ int local_widget, status;
+ nasid_t local_nasid;
+ struct sn_irq_info *new_irq_info;
+
+ new_irq_info = kmalloc(sizeof(struct sn_irq_info), GFP_ATOMIC);
+ if (new_irq_info == NULL)
+ break;
+ memcpy(new_irq_info, sn_irq_info, sizeof(struct sn_irq_info));
+
+ bridge = (uint64_t) new_irq_info->irq_bridge;
+ if (!bridge) {
+ kfree(new_irq_info);
+ break; /* irq is not a device interrupt */
+ }
- if (!bridge)
- break; /* irq is not a device interrupt */
+ local_nasid = NASID_GET(bridge);
if (local_nasid & 1)
local_widget = TIO_SWIN_WIDGETNUM(bridge);
else
local_widget = SWIN_WIDGETNUM(bridge);
- /* Free the old PROM sn_irq_info structure */
- sn_intr_free(local_nasid, local_widget, sn_irq_info);
+ /* Free the old PROM new_irq_info structure */
+ sn_intr_free(local_nasid, local_widget, new_irq_info);
+ /* Update kernels new_irq_info with new target info */
+ unregister_intr_pda(new_irq_info);
- /* allocate a new PROM sn_irq_info struct */
+ /* allocate a new PROM new_irq_info struct */
status = sn_intr_alloc(local_nasid, local_widget,
- __pa(tmp_sn_irq_info), irq, t_nasid,
- t_slice);
-
- if (status == 0) {
- /* Update kernels sn_irq_info with new target info */
- unregister_intr_pda(sn_irq_info);
- sn_irq_info->irq_cpuid = cpuid;
- sn_irq_info->irq_nasid = t_nasid;
- sn_irq_info->irq_slice = t_slice;
- sn_irq_info->irq_xtalkaddr =
- tmp_sn_irq_info->irq_xtalkaddr;
- sn_irq_info->irq_cookie = tmp_sn_irq_info->irq_cookie;
- register_intr_pda(sn_irq_info);
-
- if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type)) {
- pcibr_change_devices_irq(sn_irq_info);
- }
+ __pa(new_irq_info), irq,
+ cpuid_to_nasid(cpuid),
+ cpuid_to_slice(cpuid));
+
+ /* SAL call failed */
+ if (status) {
+ kfree(new_irq_info);
+ break;
+ }
+
+ new_irq_info->irq_cpuid = cpuid;
+ register_intr_pda(new_irq_info);
+
+ if (IS_PCI_BRIDGE_ASIC(new_irq_info->irq_bridge_type))
+ pcibr_change_devices_irq(new_irq_info);
- sn_irq_info = sn_irq_info->irq_next;
+ spin_lock(&sn_irq_info_lock);
+ list_replace_rcu(&sn_irq_info->list, &new_irq_info->list);
+ spin_unlock(&sn_irq_info_lock);
+ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
#ifdef CONFIG_SMP
- set_irq_affinity_info((irq & 0xff), cpuphys, 0);
+ set_irq_affinity_info((irq & 0xff), cpuphys, 0);
#endif
- } else {
- break; /* snp_affinity failed the intr_alloc */
- }
}
- kfree(tmp_sn_irq_info);
}
struct hw_interrupt_type irq_type_sn = {
- "SN hub",
- sn_startup_irq,
- sn_shutdown_irq,
- sn_enable_irq,
- sn_disable_irq,
- sn_ack_irq,
- sn_end_irq,
- sn_set_affinity_irq
+ .typename = "SN hub",
+ .startup = sn_startup_irq,
+ .shutdown = sn_shutdown_irq,
+ .enable = sn_enable_irq,
+ .disable = sn_disable_irq,
+ .ack = sn_ack_irq,
+ .end = sn_end_irq,
+ .set_affinity = sn_set_affinity_irq
};
unsigned int sn_local_vector_to_irq(u8 vector)
@@ -231,19 +234,18 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info)
struct sn_irq_info *tmp_irq_info;
int i, foundmatch;
+ rcu_read_lock();
if (pdacpu(cpu)->sn_last_irq == irq) {
foundmatch = 0;
- for (i = pdacpu(cpu)->sn_last_irq - 1; i; i--) {
- tmp_irq_info = sn_irq[i];
- while (tmp_irq_info) {
+ for (i = pdacpu(cpu)->sn_last_irq - 1;
+ i && !foundmatch; i--) {
+ list_for_each_entry_rcu(tmp_irq_info,
+ sn_irq_lh[i],
+ list) {
if (tmp_irq_info->irq_cpuid == cpu) {
- foundmatch++;
+ foundmatch = 1;
break;
}
- tmp_irq_info = tmp_irq_info->irq_next;
- }
- if (foundmatch) {
- break;
}
}
pdacpu(cpu)->sn_last_irq = i;
@@ -251,60 +253,27 @@ static void unregister_intr_pda(struct sn_irq_info *sn_irq_info)
if (pdacpu(cpu)->sn_first_irq == irq) {
foundmatch = 0;
- for (i = pdacpu(cpu)->sn_first_irq + 1; i < NR_IRQS; i++) {
- tmp_irq_info = sn_irq[i];
- while (tmp_irq_info) {
+ for (i = pdacpu(cpu)->sn_first_irq + 1;
+ i < NR_IRQS && !foundmatch; i++) {
+ list_for_each_entry_rcu(tmp_irq_info,
+ sn_irq_lh[i],
+ list) {
if (tmp_irq_info->irq_cpuid == cpu) {
- foundmatch++;
+ foundmatch = 1;
break;
}
- tmp_irq_info = tmp_irq_info->irq_next;
- }
- if (foundmatch) {
- break;
}
}
pdacpu(cpu)->sn_first_irq = ((i == NR_IRQS) ? 0 : i);
}
+ rcu_read_unlock();
}
-struct sn_irq_info *sn_irq_alloc(nasid_t local_nasid, int local_widget, int irq,
- nasid_t nasid, int slice)
+static void sn_irq_info_free(struct rcu_head *head)
{
struct sn_irq_info *sn_irq_info;
- int status;
-
- sn_irq_info = kmalloc(sizeof(*sn_irq_info), GFP_KERNEL);
- if (sn_irq_info == NULL)
- return NULL;
-
- memset(sn_irq_info, 0x0, sizeof(*sn_irq_info));
-
- status =
- sn_intr_alloc(local_nasid, local_widget, __pa(sn_irq_info), irq,
- nasid, slice);
-
- if (status) {
- kfree(sn_irq_info);
- return NULL;
- } else {
- return sn_irq_info;
- }
-}
-
-void sn_irq_free(struct sn_irq_info *sn_irq_info)
-{
- uint64_t bridge = (uint64_t) sn_irq_info->irq_bridge;
- nasid_t local_nasid = NASID_GET(bridge);
- int local_widget;
-
- if (local_nasid & 1) /* tio check */
- local_widget = TIO_SWIN_WIDGETNUM(bridge);
- else
- local_widget = SWIN_WIDGETNUM(bridge);
-
- sn_intr_free(local_nasid, local_widget, sn_irq_info);
+ sn_irq_info = container_of(head, struct sn_irq_info, rcu);
kfree(sn_irq_info);
}
@@ -314,30 +283,54 @@ void sn_irq_fixup(struct pci_dev *pci_dev, struct sn_irq_info *sn_irq_info)
int slice = sn_irq_info->irq_slice;
int cpu = nasid_slice_to_cpuid(nasid, slice);
+ pci_dev_get(pci_dev);
sn_irq_info->irq_cpuid = cpu;
sn_irq_info->irq_pciioinfo = SN_PCIDEV_INFO(pci_dev);
/* link it into the sn_irq[irq] list */
- sn_irq_info->irq_next = sn_irq[sn_irq_info->irq_irq];
- sn_irq[sn_irq_info->irq_irq] = sn_irq_info;
+ spin_lock(&sn_irq_info_lock);
+ list_add_rcu(&sn_irq_info->list, sn_irq_lh[sn_irq_info->irq_irq]);
+ spin_unlock(&sn_irq_info_lock);
(void)register_intr_pda(sn_irq_info);
}
+void sn_irq_unfixup(struct pci_dev *pci_dev)
+{
+ struct sn_irq_info *sn_irq_info;
+
+ /* Only cleanup IRQ stuff if this device has a host bus context */
+ if (!SN_PCIDEV_BUSSOFT(pci_dev))
+ return;
+
+ sn_irq_info = SN_PCIDEV_INFO(pci_dev)->pdi_sn_irq_info;
+ if (!sn_irq_info || !sn_irq_info->irq_irq) {
+ kfree(sn_irq_info);
+ return;
+ }
+
+ unregister_intr_pda(sn_irq_info);
+ spin_lock(&sn_irq_info_lock);
+ list_del_rcu(&sn_irq_info->list);
+ spin_unlock(&sn_irq_info_lock);
+ call_rcu(&sn_irq_info->rcu, sn_irq_info_free);
+ pci_dev_put(pci_dev);
+}
+
static void force_interrupt(int irq)
{
struct sn_irq_info *sn_irq_info;
if (!sn_ioif_inited)
return;
- sn_irq_info = sn_irq[irq];
- while (sn_irq_info) {
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[irq], list) {
if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL)) {
+ (sn_irq_info->irq_bridge != NULL))
pcibr_force_interrupt(sn_irq_info);
- }
- sn_irq_info = sn_irq_info->irq_next;
}
+ rcu_read_unlock();
}
/*
@@ -402,19 +395,41 @@ static void sn_check_intr(int irq, struct sn_irq_info *sn_irq_info)
void sn_lb_int_war_check(void)
{
+ struct sn_irq_info *sn_irq_info;
int i;
if (!sn_ioif_inited || pda->sn_first_irq == 0)
return;
+
+ rcu_read_lock();
for (i = pda->sn_first_irq; i <= pda->sn_last_irq; i++) {
- struct sn_irq_info *sn_irq_info = sn_irq[i];
- while (sn_irq_info) {
- /* Only call for PCI bridges that are fully initialized. */
+ list_for_each_entry_rcu(sn_irq_info, sn_irq_lh[i], list) {
+ /*
+ * Only call for PCI bridges that are fully
+ * initialized.
+ */
if (IS_PCI_BRIDGE_ASIC(sn_irq_info->irq_bridge_type) &&
- (sn_irq_info->irq_bridge != NULL)) {
+ (sn_irq_info->irq_bridge != NULL))
sn_check_intr(i, sn_irq_info);
- }
- sn_irq_info = sn_irq_info->irq_next;
}
}
+ rcu_read_unlock();
+}
+
+void sn_irq_lh_init(void)
+{
+ int i;
+
+ sn_irq_lh = kmalloc(sizeof(struct list_head *) * NR_IRQS, GFP_KERNEL);
+ if (!sn_irq_lh)
+ panic("SN PCI INIT: Failed to allocate memory for PCI init\n");
+
+ for (i = 0; i < NR_IRQS; i++) {
+ sn_irq_lh[i] = kmalloc(sizeof(struct list_head), GFP_KERNEL);
+ if (!sn_irq_lh[i])
+ panic("SN PCI INIT: Failed IRQ memory allocation\n");
+
+ INIT_LIST_HEAD(sn_irq_lh[i]);
+ }
+
}
diff --git a/arch/ia64/sn/kernel/setup.c b/arch/ia64/sn/kernel/setup.c
index 44bfc7f318cb..7c7fe441d623 100644
--- a/arch/ia64/sn/kernel/setup.c
+++ b/arch/ia64/sn/kernel/setup.c
@@ -36,6 +36,7 @@
#include <asm/machvec.h>
#include <asm/system.h>
#include <asm/processor.h>
+#include <asm/vga.h>
#include <asm/sn/arch.h>
#include <asm/sn/addrs.h>
#include <asm/sn/pda.h>
@@ -95,6 +96,7 @@ u8 sn_coherency_id;
EXPORT_SYMBOL(sn_coherency_id);
u8 sn_region_size;
EXPORT_SYMBOL(sn_region_size);
+int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
short physical_node_map[MAX_PHYSNODE_ID];
@@ -268,19 +270,22 @@ void __init sn_setup(char **cmdline_p)
{
long status, ticks_per_sec, drift;
int pxm;
- int major = sn_sal_rev_major(), minor = sn_sal_rev_minor();
+ u32 version = sn_sal_rev();
extern void sn_cpu_init(void);
ia64_sn_plat_set_error_handling_features();
+#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
/*
- * If the generic code has enabled vga console support - lets
- * get rid of it again. This is a kludge for the fact that ACPI
- * currtently has no way of informing us if legacy VGA is available
- * or not.
+ * If there was a primary vga adapter identified through the
+ * EFI PCDP table, make it the preferred console. Otherwise
+ * zero out conswitchp.
*/
-#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
- if (conswitchp == &vga_con) {
+
+ if (vga_console_membase) {
+ /* usable vga ... make tty0 the preferred default console */
+ add_preferred_console("tty", 0, NULL);
+ } else {
printk(KERN_DEBUG "SGI: Disabling VGA console\n");
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
@@ -303,22 +308,21 @@ void __init sn_setup(char **cmdline_p)
* support here so we don't have to listen to failed keyboard probe
* messages.
*/
- if ((major < 2 || (major == 2 && minor <= 9)) &&
- acpi_kbd_controller_present) {
+ if (version <= 0x0209 && acpi_kbd_controller_present) {
printk(KERN_INFO "Disabling legacy keyboard support as prom "
"is too old and doesn't provide FADT\n");
acpi_kbd_controller_present = 0;
}
- printk("SGI SAL version %x.%02x\n", major, minor);
+ printk("SGI SAL version %x.%02x\n", version >> 8, version & 0x00FF);
/*
* Confirm the SAL we're running on is recent enough...
*/
- if ((major < SN_SAL_MIN_MAJOR) || (major == SN_SAL_MIN_MAJOR &&
- minor < SN_SAL_MIN_MINOR)) {
+ if (version < SN_SAL_MIN_VERSION) {
printk(KERN_ERR "This kernel needs SGI SAL version >= "
- "%x.%02x\n", SN_SAL_MIN_MAJOR, SN_SAL_MIN_MINOR);
+ "%x.%02x\n", SN_SAL_MIN_VERSION >> 8,
+ SN_SAL_MIN_VERSION & 0x00FF);
panic("PROM version too old\n");
}
@@ -350,7 +354,7 @@ void __init sn_setup(char **cmdline_p)
ia64_mark_idle = &snidle;
- /*
+ /*
* For the bootcpu, we do this here. All other cpus will make the
* call as part of cpu_init in slave cpu initialization.
*/
@@ -397,7 +401,7 @@ static void __init sn_init_pdas(char **cmdline_p)
nodepdaindr[cnode] =
alloc_bootmem_node(NODE_DATA(cnode), sizeof(nodepda_t));
memset(nodepdaindr[cnode], 0, sizeof(nodepda_t));
- memset(nodepdaindr[cnode]->phys_cpuid, -1,
+ memset(nodepdaindr[cnode]->phys_cpuid, -1,
sizeof(nodepdaindr[cnode]->phys_cpuid));
}
@@ -427,7 +431,7 @@ static void __init sn_init_pdas(char **cmdline_p)
}
/*
- * Initialize the per node hubdev. This includes IO Nodes and
+ * Initialize the per node hubdev. This includes IO Nodes and
* headless/memless nodes.
*/
for (cnode = 0; cnode < numionodes; cnode++) {
@@ -455,6 +459,14 @@ void __init sn_cpu_init(void)
int i;
static int wars_have_been_checked;
+ if (smp_processor_id() == 0 && IS_MEDUSA()) {
+ if (ia64_sn_is_fake_prom())
+ sn_prom_type = 2;
+ else
+ sn_prom_type = 1;
+ printk("Running on medusa with %s PROM\n", (sn_prom_type == 1) ? "real" : "fake");
+ }
+
memset(pda, 0, sizeof(pda));
if (ia64_sn_get_sn_info(0, &sn_hub_info->shub2, &sn_hub_info->nasid_bitmask, &sn_hub_info->nasid_shift,
&sn_system_size, &sn_sharing_domain_size, &sn_partition_id,
@@ -520,7 +532,7 @@ void __init sn_cpu_init(void)
*/
{
u64 pio1[] = {SH1_PIO_WRITE_STATUS_0, 0, SH1_PIO_WRITE_STATUS_1, 0};
- u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
+ u64 pio2[] = {SH2_PIO_WRITE_STATUS_0, SH2_PIO_WRITE_STATUS_1,
SH2_PIO_WRITE_STATUS_2, SH2_PIO_WRITE_STATUS_3};
u64 *pio;
pio = is_shub1() ? pio1 : pio2;
@@ -552,6 +564,10 @@ static void __init scan_for_ionodes(void)
int nasid = 0;
lboard_t *brd;
+ /* fakeprom does not support klgraph */
+ if (IS_RUNNING_ON_FAKE_PROM())
+ return;
+
/* Setup ionodes with memory */
for (nasid = 0; nasid < MAX_PHYSNODE_ID; nasid += 2) {
char *klgraph_header;
@@ -563,8 +579,6 @@ static void __init scan_for_ionodes(void)
cnodeid = -1;
klgraph_header = __va(ia64_sn_get_klconfig_addr(nasid));
if (!klgraph_header) {
- if (IS_RUNNING_ON_SIMULATOR())
- continue;
BUG(); /* All nodes must have klconfig tables! */
}
cnodeid = nasid_to_cnodeid(nasid);
@@ -630,8 +644,8 @@ int
nasid_slice_to_cpuid(int nasid, int slice)
{
long cpu;
-
- for (cpu=0; cpu < NR_CPUS; cpu++)
+
+ for (cpu=0; cpu < NR_CPUS; cpu++)
if (cpuid_to_nasid(cpu) == nasid &&
cpuid_to_slice(cpu) == slice)
return cpu;
diff --git a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
index 7947312801ec..96cb71d15682 100644
--- a/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
+++ b/arch/ia64/sn/kernel/sn2/ptc_deadlock.S
@@ -6,6 +6,7 @@
* Copyright (C) 2000-2004 Silicon Graphics, Inc. All rights reserved.
*/
+#include <asm/types.h>
#include <asm/sn/shub_mmr.h>
#define DEADLOCKBIT SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT
diff --git a/arch/ia64/sn/kernel/tiocx.c b/arch/ia64/sn/kernel/tiocx.c
index a087b274847e..254fe15c064b 100644
--- a/arch/ia64/sn/kernel/tiocx.c
+++ b/arch/ia64/sn/kernel/tiocx.c
@@ -8,12 +8,12 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/delay.h>
+#include <asm/system.h>
#include <asm/uaccess.h>
#include <asm/sn/sn_sal.h>
#include <asm/sn/addrs.h>
@@ -204,8 +204,8 @@ cx_device_register(nasid_t nasid, int part_num, int mfg_num,
cx_dev->dev.parent = NULL;
cx_dev->dev.bus = &tiocx_bus_type;
cx_dev->dev.release = tiocx_bus_release;
- snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d.0x%x",
- cx_dev->cx_id.nasid, cx_dev->cx_id.part_num);
+ snprintf(cx_dev->dev.bus_id, BUS_ID_SIZE, "%d",
+ cx_dev->cx_id.nasid);
device_register(&cx_dev->dev);
get_device(&cx_dev->dev);
@@ -236,7 +236,6 @@ int cx_device_unregister(struct cx_dev *cx_dev)
*/
static int cx_device_reload(struct cx_dev *cx_dev)
{
- device_remove_file(&cx_dev->dev, &dev_attr_cxdev_control);
cx_device_unregister(cx_dev);
return cx_device_register(cx_dev->cx_id.nasid, cx_dev->cx_id.part_num,
cx_dev->cx_id.mfg_num, cx_dev->hubdev);
@@ -383,6 +382,7 @@ static int is_fpga_brick(int nasid)
switch (tiocx_btchar_get(nasid)) {
case L1_BRICKTYPE_SA:
case L1_BRICKTYPE_ATHENA:
+ case L1_BRICKTYPE_DAYTONA:
return 1;
}
return 0;
@@ -409,7 +409,7 @@ static int tiocx_reload(struct cx_dev *cx_dev)
uint64_t cx_id;
cx_id =
- *(volatile int32_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
+ *(volatile uint64_t *)(TIO_SWIN_BASE(nasid, TIOCX_CORELET) +
WIDGET_ID);
part_num = XWIDGET_PART_NUM(cx_id);
mfg_num = XWIDGET_MFG_NUM(cx_id);
@@ -458,6 +458,10 @@ static ssize_t store_cxdev_control(struct device *dev, struct device_attribute *
switch (n) {
case 1:
+ tio_corelet_reset(cx_dev->cx_id.nasid, TIOCX_CORELET);
+ tiocx_reload(cx_dev);
+ break;
+ case 2:
tiocx_reload(cx_dev);
break;
case 3:
@@ -477,6 +481,9 @@ static int __init tiocx_init(void)
cnodeid_t cnodeid;
int found_tiocx_device = 0;
+ if (!ia64_platform_is("sn2"))
+ return -ENODEV;
+
bus_register(&tiocx_bus_type);
for (cnodeid = 0; cnodeid < MAX_COMPACT_NODES; cnodeid++) {
@@ -537,7 +544,7 @@ static void __exit tiocx_exit(void)
bus_unregister(&tiocx_bus_type);
}
-module_init(tiocx_init);
+subsys_initcall(tiocx_init);
module_exit(tiocx_exit);
/************************************************************************
diff --git a/arch/ia64/sn/kernel/xpc.h b/arch/ia64/sn/kernel/xpc.h
index 1a0aed8490d1..d0ee635daf2e 100644
--- a/arch/ia64/sn/kernel/xpc.h
+++ b/arch/ia64/sn/kernel/xpc.h
@@ -87,7 +87,7 @@ struct xpc_rsvd_page {
u8 partid; /* partition ID from SAL */
u8 version;
u8 pad[6]; /* pad to u64 align */
- u64 vars_pa;
+ volatile u64 vars_pa;
u64 part_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
u64 mach_nasids[XP_NASID_MASK_WORDS] ____cacheline_aligned;
};
@@ -138,7 +138,7 @@ struct xpc_vars {
* occupies half a cacheline.
*/
struct xpc_vars_part {
- u64 magic;
+ volatile u64 magic;
u64 openclose_args_pa; /* physical address of open and close args */
u64 GPs_pa; /* physical address of Get/Put values */
@@ -185,8 +185,8 @@ struct xpc_vars_part {
* Define a Get/Put value pair (pointers) used with a message queue.
*/
struct xpc_gp {
- s64 get; /* Get value */
- s64 put; /* Put value */
+ volatile s64 get; /* Get value */
+ volatile s64 put; /* Put value */
};
#define XPC_GP_SIZE \
@@ -231,7 +231,7 @@ struct xpc_openclose_args {
*/
struct xpc_notify {
struct semaphore sema; /* notify semaphore */
- u8 type; /* type of notification */
+ volatile u8 type; /* type of notification */
/* the following two fields are only used if type == XPC_N_CALL */
xpc_notify_func func; /* user's notify function */
@@ -439,7 +439,7 @@ struct xpc_partition {
/* XPC infrastructure referencing and teardown control */
- u8 setup_state; /* infrastructure setup state */
+ volatile u8 setup_state; /* infrastructure setup state */
wait_queue_head_t teardown_wq; /* kthread waiting to teardown infra */
atomic_t references; /* #of references to infrastructure */
diff --git a/arch/ia64/sn/kernel/xpc_channel.c b/arch/ia64/sn/kernel/xpc_channel.c
index 0bf6fbcc46d2..6d02dac8056f 100644
--- a/arch/ia64/sn/kernel/xpc_channel.c
+++ b/arch/ia64/sn/kernel/xpc_channel.c
@@ -209,7 +209,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
* With the setting of the partition setup_state to XPC_P_SETUP, we're
* declaring that this partition is ready to go.
*/
- (volatile u8) part->setup_state = XPC_P_SETUP;
+ part->setup_state = XPC_P_SETUP;
/*
@@ -227,7 +227,7 @@ xpc_setup_infrastructure(struct xpc_partition *part)
xpc_vars_part[partid].IPI_phys_cpuid =
cpu_physical_id(smp_processor_id());
xpc_vars_part[partid].nchannels = part->nchannels;
- (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
+ xpc_vars_part[partid].magic = XPC_VP_MAGIC1;
return xpcSuccess;
}
@@ -355,7 +355,7 @@ xpc_pull_remote_vars_part(struct xpc_partition *part)
/* let the other side know that we've pulled their variables */
- (volatile u64) xpc_vars_part[partid].magic = XPC_VP_MAGIC2;
+ xpc_vars_part[partid].magic = XPC_VP_MAGIC2;
}
if (pulled_entry->magic == XPC_VP_MAGIC1) {
@@ -1183,7 +1183,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
*/
xpc_clear_local_msgqueue_flags(ch);
- (volatile s64) ch->w_remote_GP.get = ch->remote_GP.get;
+ ch->w_remote_GP.get = ch->remote_GP.get;
dev_dbg(xpc_chan, "w_remote_GP.get changed to %ld, partid=%d, "
"channel=%d\n", ch->w_remote_GP.get, ch->partid,
@@ -1211,7 +1211,7 @@ xpc_process_msg_IPI(struct xpc_partition *part, int ch_number)
*/
xpc_clear_remote_msgqueue_flags(ch);
- (volatile s64) ch->w_remote_GP.put = ch->remote_GP.put;
+ ch->w_remote_GP.put = ch->remote_GP.put;
dev_dbg(xpc_chan, "w_remote_GP.put changed to %ld, partid=%d, "
"channel=%d\n", ch->w_remote_GP.put, ch->partid,
@@ -1875,7 +1875,7 @@ xpc_send_msg(struct xpc_channel *ch, struct xpc_msg *msg, u8 notify_type,
notify = &ch->notify_queue[msg_number % ch->local_nentries];
notify->func = func;
notify->key = key;
- (volatile u8) notify->type = notify_type;
+ notify->type = notify_type;
// >>> is a mb() needed here?
diff --git a/arch/ia64/sn/kernel/xpc_main.c b/arch/ia64/sn/kernel/xpc_main.c
index 177ddb748ebe..d580adcad927 100644
--- a/arch/ia64/sn/kernel/xpc_main.c
+++ b/arch/ia64/sn/kernel/xpc_main.c
@@ -53,6 +53,7 @@
#include <linux/cache.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <asm/sn/intr.h>
#include <asm/sn/sn_sal.h>
#include <asm/uaccess.h>
@@ -308,8 +309,7 @@ xpc_make_first_contact(struct xpc_partition *part)
"partition %d\n", XPC_PARTID(part));
/* wait a 1/4 of a second or so */
- set_current_state(TASK_INTERRUPTIBLE);
- (void) schedule_timeout(0.25 * HZ);
+ msleep_interruptible(250);
if (part->act_state == XPC_P_DEACTIVATING) {
return part->reason;
@@ -841,9 +841,7 @@ xpc_do_exit(void)
down(&xpc_discovery_exited);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(0.3 * HZ);
- set_current_state(TASK_RUNNING);
+ msleep_interruptible(300);
/* wait for all partitions to become inactive */
@@ -860,12 +858,8 @@ xpc_do_exit(void)
}
}
- if (active_part_count) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(0.3 * HZ);
- set_current_state(TASK_RUNNING);
- }
-
+ if (active_part_count)
+ msleep_interruptible(300);
} while (active_part_count > 0);
diff --git a/arch/ia64/sn/kernel/xpc_partition.c b/arch/ia64/sn/kernel/xpc_partition.c
index cd7ed73f0e7a..578265ea9e67 100644
--- a/arch/ia64/sn/kernel/xpc_partition.c
+++ b/arch/ia64/sn/kernel/xpc_partition.c
@@ -253,7 +253,7 @@ xpc_rsvd_page_init(void)
* This signifies to the remote partition that our reserved
* page is initialized.
*/
- (volatile u64) rp->vars_pa = __pa(xpc_vars);
+ rp->vars_pa = __pa(xpc_vars);
return rp;
}
diff --git a/arch/ia64/sn/pci/pci_dma.c b/arch/ia64/sn/pci/pci_dma.c
index 5da9bdbde7cb..a2f7a88aefbb 100644
--- a/arch/ia64/sn/pci/pci_dma.c
+++ b/arch/ia64/sn/pci/pci_dma.c
@@ -11,9 +11,10 @@
#include <linux/module.h>
#include <asm/dma.h>
-#include <asm/sn/sn_sal.h>
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
+#include <asm/sn/sn_sal.h>
#define SG_ENT_VIRT_ADDRESS(sg) (page_address((sg)->page) + (sg)->offset)
#define SG_ENT_PHYS_ADDRESS(SG) virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_ate.c b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
index 0e47bce85f2d..d1647b863e61 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_ate.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_ate.c
@@ -8,9 +8,9 @@
#include <linux/types.h>
#include <asm/sn/sn_sal.h>
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
int pcibr_invalidate_ate = 0; /* by default don't invalidate ATE on free */
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_dma.c b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
index 64af2b2c1787..b058dc2a0b9d 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_dma.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_dma.c
@@ -8,18 +8,17 @@
#include <linux/types.h>
#include <linux/pci.h>
-#include <asm/sn/sn_sal.h>
+#include <asm/sn/addrs.h>
#include <asm/sn/geo.h>
-#include "xtalk/xwidgetdev.h"
-#include "xtalk/hubdev.h"
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
-#include "pci/tiocp.h"
-#include "pci/pic.h"
-#include "pci/pcibr_provider.h"
-#include "pci/tiocp.h"
+#include <asm/sn/pic.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/tiocp.h>
#include "tio.h"
-#include <asm/sn/addrs.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
extern int sn_ioif_inited;
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_provider.c b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
index 3893999d23d8..9813da56d311 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_provider.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_provider.c
@@ -6,18 +6,51 @@
* Copyright (C) 2001-2004 Silicon Graphics, Inc. All rights reserved.
*/
-#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/types.h>
#include <linux/pci.h>
-#include <asm/sn/sn_sal.h>
-#include "xtalk/xwidgetdev.h"
+#include <asm/sn/addrs.h>
#include <asm/sn/geo.h>
-#include "xtalk/hubdev.h"
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
-#include "pci/pcibr_provider.h"
-#include <asm/sn/addrs.h>
+#include <asm/sn/sn_sal.h>
+#include "xtalk/xwidgetdev.h"
+#include "xtalk/hubdev.h"
+
+int
+sal_pcibr_slot_enable(struct pcibus_info *soft, int device, void *resp)
+{
+ struct ia64_sal_retval ret_stuff;
+ uint64_t busnum;
+
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+ busnum = soft->pbi_buscommon.bs_persist_busnum;
+ SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_ENABLE, (u64) busnum,
+ (u64) device, (u64) resp, 0, 0, 0, 0);
+
+ return (int)ret_stuff.v0;
+}
+
+int
+sal_pcibr_slot_disable(struct pcibus_info *soft, int device, int action,
+ void *resp)
+{
+ struct ia64_sal_retval ret_stuff;
+ uint64_t busnum;
+
+ ret_stuff.status = 0;
+ ret_stuff.v0 = 0;
+
+ busnum = soft->pbi_buscommon.bs_persist_busnum;
+ SAL_CALL_NOLOCK(ret_stuff, (u64) SN_SAL_IOIF_SLOT_DISABLE,
+ (u64) busnum, (u64) device, (u64) action,
+ (u64) resp, 0, 0, 0);
+
+ return (int)ret_stuff.v0;
+}
static int sal_pcibr_error_interrupt(struct pcibus_info *soft)
{
@@ -188,3 +221,6 @@ pcibr_init_provider(void)
return 0;
}
+
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_enable);
+EXPORT_SYMBOL_GPL(sal_pcibr_slot_disable);
diff --git a/arch/ia64/sn/pci/pcibr/pcibr_reg.c b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
index 865c11c3b50a..21426d02fbe6 100644
--- a/arch/ia64/sn/pci/pcibr/pcibr_reg.c
+++ b/arch/ia64/sn/pci/pcibr/pcibr_reg.c
@@ -6,13 +6,13 @@
* Copyright (C) 2004 Silicon Graphics, Inc. All rights reserved.
*/
-#include <linux/types.h>
#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <asm/sn/pcibr_provider.h>
#include <asm/sn/pcibus_provider_defs.h>
#include <asm/sn/pcidev.h>
-#include "pci/tiocp.h"
-#include "pci/pic.h"
-#include "pci/pcibr_provider.h"
+#include <asm/sn/pic.h>
+#include <asm/sn/tiocp.h>
union br_ptr {
struct tiocp tio;
diff --git a/arch/ia64/sn/pci/tioca_provider.c b/arch/ia64/sn/pci/tioca_provider.c
index 8dae9eb45456..51cc4e63092c 100644
--- a/arch/ia64/sn/pci/tioca_provider.c
+++ b/arch/ia64/sn/pci/tioca_provider.c
@@ -336,7 +336,7 @@ tioca_dma_d48(struct pci_dev *pdev, uint64_t paddr)
if (!ct_addr)
return 0;
- bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffff);
+ bus_addr = (dma_addr_t) (ct_addr & 0xffffffffffffUL);
node_upper = ct_addr >> 48;
if (node_upper > 64) {
@@ -464,7 +464,7 @@ map_return:
* For mappings created using the direct modes (64 or 48) there are no
* resources to release.
*/
-void
+static void
tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
{
int i, entry;
@@ -514,7 +514,7 @@ tioca_dma_unmap(struct pci_dev *pdev, dma_addr_t bus_addr, int dir)
* The mapping mode used is based on the devices dma_mask. As a last resort
* use the GART mapped mode.
*/
-uint64_t
+static uint64_t
tioca_dma_map(struct pci_dev *pdev, uint64_t paddr, size_t byte_count)
{
uint64_t mapaddr;
@@ -580,7 +580,7 @@ tioca_error_intr_handler(int irq, void *arg, struct pt_regs *pt)
* On successful setup, returns the kernel version of tioca_common back to
* the caller.
*/
-void *
+static void *
tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft)
{
struct tioca_common *tioca_common;
@@ -589,8 +589,7 @@ tioca_bus_fixup(struct pcibus_bussoft *prom_bussoft)
/* sanity check prom rev */
- if (sn_sal_rev_major() < 4 ||
- (sn_sal_rev_major() == 4 && sn_sal_rev_minor() < 6)) {
+ if (sn_sal_rev() < 0x0406) {
printk
(KERN_ERR "%s: SGI prom rev 4.06 or greater required "
"for tioca support\n", __FUNCTION__);
diff --git a/arch/m32r/Kconfig b/arch/m32r/Kconfig
index 42ca8a39798d..7772951df313 100644
--- a/arch/m32r/Kconfig
+++ b/arch/m32r/Kconfig
@@ -359,6 +359,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/m32r/kernel/setup_m32700ut.c b/arch/m32r/kernel/setup_m32700ut.c
index b014e2c1e524..a146b24a556b 100644
--- a/arch/m32r/kernel/setup_m32700ut.c
+++ b/arch/m32r/kernel/setup_m32700ut.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas M32700UT Board
*
- * Copyright (c) 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Takeo Takahashi
+ * Copyright (c) 2002-2005 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
@@ -435,7 +435,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_m32700ut_irq(M32R_IRQ_INT2);
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
/*
* INT3# is used for AR
*/
@@ -445,9 +445,11 @@ void __init init_IRQ(void)
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_VIDEO_M32R_AR */
+#endif /* CONFIG_VIDEO_M32R_AR */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -469,10 +471,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10600000UL,
+ .end = 0x1073FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10400000UL,
+ .end = 0x104001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_mappi.c b/arch/m32r/kernel/setup_mappi.c
index aaf8e569b930..4e709809efc5 100644
--- a/arch/m32r/kernel/setup_mappi.c
+++ b/arch/m32r/kernel/setup_mappi.c
@@ -3,14 +3,15 @@
*
* Setup routines for Renesas MAPPI Board
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto
*/
#include <linux/config.h>
#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/device.h>
#include <asm/system.h>
#include <asm/m32r.h>
@@ -158,3 +159,49 @@ void __init init_IRQ(void)
disable_mappi_irq(M32R_IRQ_INT2);
#endif /* CONFIG_M32RPCC */
}
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10200000UL,
+ .end = 0x1033FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10000000UL,
+ .end = 0x100001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+
+static int __init platform_init(void)
+{
+ platform_device_register(&s1d13xxxfb_device);
+ return 0;
+}
+arch_initcall(platform_init);
+#endif
diff --git a/arch/m32r/kernel/setup_mappi2.c b/arch/m32r/kernel/setup_mappi2.c
index 38d5e9a41427..a1d801598aa4 100644
--- a/arch/m32r/kernel/setup_mappi2.c
+++ b/arch/m32r/kernel/setup_mappi2.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas MAPPI-II(M3A-ZA36) Board
*
- * Copyright (c) 2001, 2002 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
diff --git a/arch/m32r/kernel/setup_mappi3.c b/arch/m32r/kernel/setup_mappi3.c
index 3d60a85aaec5..a76412e883e8 100644
--- a/arch/m32r/kernel/setup_mappi3.c
+++ b/arch/m32r/kernel/setup_mappi3.c
@@ -3,8 +3,8 @@
*
* Setup routines for Renesas MAPPI-III(M3A-2170) Board
*
- * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2001-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
@@ -178,6 +178,8 @@ void __init init_IRQ(void)
#endif /* CONFIG_M32R_CFC */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -200,9 +202,55 @@ static struct platform_device smc91x_device = {
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x1d600000UL,
+ .end = 0x1d73FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x1d400000UL,
+ .end = 0x1d4001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
+
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/setup_oaks32r.c b/arch/m32r/kernel/setup_oaks32r.c
index d656640badc9..45add5b76f19 100644
--- a/arch/m32r/kernel/setup_oaks32r.c
+++ b/arch/m32r/kernel/setup_oaks32r.c
@@ -3,8 +3,8 @@
*
* Setup routines for OAKS32R Board
*
- * Copyright (c) 2002-2004 Hiroyuki Kondo, Hirokazu Takata,
- * Hitoshi Yamamoto, Mamoru Sakugawa
+ * Copyright (c) 2002-2005 Hiroyuki Kondo, Hirokazu Takata,
+ * Hitoshi Yamamoto, Mamoru Sakugawa
*/
#include <linux/config.h>
@@ -139,5 +139,4 @@ void __init init_IRQ(void)
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
index 86f4cf2a86c3..f0301f58bcce 100644
--- a/arch/m32r/kernel/setup_opsput.c
+++ b/arch/m32r/kernel/setup_opsput.c
@@ -3,7 +3,7 @@
*
* Setup routines for Renesas OPSPUT Board
*
- * Copyright (c) 2002-2004
+ * Copyright (c) 2002-2005
* Hiroyuki Kondo, Hirokazu Takata,
* Hitoshi Yamamoto, Takeo Takahashi, Mamoru Sakugawa
*
@@ -439,7 +439,7 @@ void __init init_IRQ(void)
icu_data[M32R_IRQ_INT2].icucr = M32R_ICUCR_IEN|M32R_ICUCR_ISMOD01;
enable_opsput_irq(M32R_IRQ_INT2);
-//#if defined(CONFIG_VIDEO_M32R_AR)
+#if defined(CONFIG_VIDEO_M32R_AR)
/*
* INT3# is used for AR
*/
@@ -449,9 +449,11 @@ void __init init_IRQ(void)
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_VIDEO_M32R_AR */
+#endif /* CONFIG_VIDEO_M32R_AR */
}
+#if defined(CONFIG_SMC91X)
+
#define LAN_IOSTART 0x300
#define LAN_IOEND 0x320
static struct resource smc91x_resources[] = {
@@ -473,10 +475,55 @@ static struct platform_device smc91x_device = {
.num_resources = ARRAY_SIZE(smc91x_resources),
.resource = smc91x_resources,
};
+#endif
+
+#if defined(CONFIG_FB_S1D13XXX)
+
+#include <video/s1d13xxxfb.h>
+#include <asm/s1d13806.h>
+
+static struct s1d13xxxfb_pdata s1d13xxxfb_data = {
+ .initregs = s1d13xxxfb_initregs,
+ .initregssize = ARRAY_SIZE(s1d13xxxfb_initregs),
+ .platform_init_video = NULL,
+#ifdef CONFIG_PM
+ .platform_suspend_video = NULL,
+ .platform_resume_video = NULL,
+#endif
+};
+
+static struct resource s1d13xxxfb_resources[] = {
+ [0] = {
+ .start = 0x10600000UL,
+ .end = 0x1073FFFFUL,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = 0x10400000UL,
+ .end = 0x104001FFUL,
+ .flags = IORESOURCE_MEM,
+ }
+};
+
+static struct platform_device s1d13xxxfb_device = {
+ .name = S1D_DEVICENAME,
+ .id = 0,
+ .dev = {
+ .platform_data = &s1d13xxxfb_data,
+ },
+ .num_resources = ARRAY_SIZE(s1d13xxxfb_resources),
+ .resource = s1d13xxxfb_resources,
+};
+#endif
static int __init platform_init(void)
{
+#if defined(CONFIG_SMC91X)
platform_device_register(&smc91x_device);
+#endif
+#if defined(CONFIG_FB_S1D13XXX)
+ platform_device_register(&s1d13xxxfb_device);
+#endif
return 0;
}
arch_initcall(platform_init);
diff --git a/arch/m32r/kernel/signal.c b/arch/m32r/kernel/signal.c
index 50311eb07a24..5aef7e406ef5 100644
--- a/arch/m32r/kernel/signal.c
+++ b/arch/m32r/kernel/signal.c
@@ -371,10 +371,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!user_mode(regs))
return 1;
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze())
goto no_signal;
- }
if (!oldset)
oldset = &current->blocked;
diff --git a/arch/m68k/Kconfig b/arch/m68k/Kconfig
index 691a2469ff36..178c4a3fbb72 100644
--- a/arch/m68k/Kconfig
+++ b/arch/m68k/Kconfig
@@ -450,6 +450,8 @@ source "drivers/zorro/Kconfig"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
menu "Character devices"
diff --git a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig
index dbfcdc8e6087..117f183f0b43 100644
--- a/arch/m68knommu/Kconfig
+++ b/arch/m68knommu/Kconfig
@@ -575,6 +575,8 @@ config PM
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 94f5a8eb2c22..b578239146b5 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -1416,6 +1416,12 @@ config HIGHMEM
bool "High Memory Support"
depends on MIPS32 && (CPU_R3000 || CPU_SB1 || CPU_R7000 || CPU_RM9000 || CPU_R10000) && !(MACH_DECSTATION || MOMENCO_JAGUAR_ATX)
+config ARCH_FLATMEM_ENABLE
+ def_bool y
+ depends on !NUMA
+
+source "mm/Kconfig"
+
config SMP
bool "Multi-Processing support"
depends on CPU_RM9000 || (SIBYTE_SB1250 && !SIBYTE_STANDALONE) || SGI_IP27
@@ -1634,6 +1640,8 @@ config PM
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c
index 6018ca25aceb..3a240e3e004c 100644
--- a/arch/mips/kernel/setup.c
+++ b/arch/mips/kernel/setup.c
@@ -33,6 +33,7 @@
#include <linux/root_dev.h>
#include <linux/highmem.h>
#include <linux/console.h>
+#include <linux/mmzone.h>
#include <asm/addrspace.h>
#include <asm/bootinfo.h>
@@ -356,6 +357,8 @@ static inline void bootmem_init(void)
}
#endif
+ memory_present(0, first_usable_pfn, max_low_pfn);
+
/* Initialize the boot-time allocator with low memory only. */
bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn);
@@ -557,6 +560,7 @@ void __init setup_arch(char **cmdline_p)
parse_cmdline_early();
bootmem_init();
+ sparse_init();
paging_init();
resource_init();
}
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 508026ae5842..65ee15396ffd 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -457,7 +457,7 @@ static int do_signal(sigset_t *oldset, struct pt_regs *regs)
if (!user_mode(regs))
return 1;
- if (try_to_freeze(0))
+ if (try_to_freeze())
goto no_signal;
if (!oldset)
diff --git a/arch/mips/mm/init.c b/arch/mips/mm/init.c
index 73843c528778..9c9a271c8a3a 100644
--- a/arch/mips/mm/init.c
+++ b/arch/mips/mm/init.c
@@ -128,7 +128,7 @@ static void __init fixrange_init(unsigned long start, unsigned long end,
#endif /* CONFIG_MIPS64 */
#endif /* CONFIG_HIGHMEM */
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
extern void pagetable_init(void);
void __init paging_init(void)
@@ -253,7 +253,7 @@ void __init mem_init(void)
initsize >> 10,
(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)));
}
-#endif /* !CONFIG_DISCONTIGMEM */
+#endif /* !CONFIG_NEED_MULTIPLE_NODES */
#ifdef CONFIG_BLK_DEV_INITRD
void free_initrd_mem(unsigned long start, unsigned long end)
diff --git a/arch/mips/mm/pgtable.c b/arch/mips/mm/pgtable.c
index 3b88fdeef329..3fe94202da8c 100644
--- a/arch/mips/mm/pgtable.c
+++ b/arch/mips/mm/pgtable.c
@@ -5,7 +5,7 @@
void show_mem(void)
{
-#ifndef CONFIG_DISCONTIGMEM /* XXX(hch): later.. */
+#ifndef CONFIG_NEED_MULTIPLE_NODES /* XXX(hch): later.. */
int pfn, total = 0, reserved = 0;
int shared = 0, cached = 0;
int highmem = 0;
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig
index ce327c799b44..1c2d87435233 100644
--- a/arch/parisc/Kconfig
+++ b/arch/parisc/Kconfig
@@ -190,6 +190,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/parisc/configs/712_defconfig b/arch/parisc/configs/712_defconfig
index 872085dea8a8..6efaa9293eef 100644
--- a/arch/parisc/configs/712_defconfig
+++ b/arch/parisc/configs/712_defconfig
@@ -506,7 +506,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_NR_UARTS=17
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
diff --git a/arch/parisc/configs/a500_defconfig b/arch/parisc/configs/a500_defconfig
index d28ebfa1070d..30fc03ed0cfb 100644
--- a/arch/parisc/configs/a500_defconfig
+++ b/arch/parisc/configs/a500_defconfig
@@ -662,7 +662,7 @@ CONFIG_HW_CONSOLE=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_CS=m
-CONFIG_SERIAL_8250_NR_UARTS=8
+CONFIG_SERIAL_8250_NR_UARTS=17
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
diff --git a/arch/parisc/configs/b180_defconfig b/arch/parisc/configs/b180_defconfig
index 1700d7aec686..46c9511f3229 100644
--- a/arch/parisc/configs/b180_defconfig
+++ b/arch/parisc/configs/b180_defconfig
@@ -514,7 +514,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
diff --git a/arch/parisc/configs/c3000_defconfig b/arch/parisc/configs/c3000_defconfig
index b27980161c31..67aca6ccc9b0 100644
--- a/arch/parisc/configs/c3000_defconfig
+++ b/arch/parisc/configs/c3000_defconfig
@@ -661,7 +661,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
diff --git a/arch/parisc/defconfig b/arch/parisc/defconfig
index ebd6301aa599..fdae21c503d7 100644
--- a/arch/parisc/defconfig
+++ b/arch/parisc/defconfig
@@ -517,7 +517,7 @@ CONFIG_HW_CONSOLE=y
#
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_NR_UARTS=13
CONFIG_SERIAL_8250_EXTENDED=y
CONFIG_SERIAL_8250_MANY_PORTS=y
CONFIG_SERIAL_8250_SHARE_IRQ=y
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 4ea7158e5062..ece6a9fbe09b 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -714,16 +714,24 @@ static int __init scc_enet_init(void)
immap->im_ioport.iop_pcdat &= ~PC_ENET_LBK; /* Disable Loopback */
#endif /* PC_ENET_LBK */
- /* Configure port C pins to enable CLSN and RENA.
+#ifdef PE_ENET_TCLK
+ /* Configure port E for TCLK and RCLK.
*/
- immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
- immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
- immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
-
+ cp->cp_pepar |= (PE_ENET_TCLK | PE_ENET_RCLK);
+ cp->cp_pedir &= ~(PE_ENET_TCLK | PE_ENET_RCLK);
+ cp->cp_peso &= ~(PE_ENET_TCLK | PE_ENET_RCLK);
+#else
/* Configure port A for TCLK and RCLK.
*/
immap->im_ioport.iop_papar |= (PA_ENET_TCLK | PA_ENET_RCLK);
immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
+#endif
+
+ /* Configure port C pins to enable CLSN and RENA.
+ */
+ immap->im_ioport.iop_pcpar &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immap->im_ioport.iop_pcdir &= ~(PC_ENET_CLSN | PC_ENET_RENA);
+ immap->im_ioport.iop_pcso |= (PC_ENET_CLSN | PC_ENET_RENA);
/* Configure Serial Interface clock routing.
* First, clear all SCC bits to zero, then set the ones we want.
@@ -896,14 +904,18 @@ static int __init scc_enet_init(void)
/* It is now OK to enable the Ethernet transmitter.
* Unfortunately, there are board implementation differences here.
*/
-#if (!defined (PB_ENET_TENA) && defined (PC_ENET_TENA))
+#if (!defined (PB_ENET_TENA) && defined (PC_ENET_TENA) && !defined (PE_ENET_TENA))
immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
-#elif ( defined (PB_ENET_TENA) && !defined (PC_ENET_TENA))
+#elif ( defined (PB_ENET_TENA) && !defined (PC_ENET_TENA) && !defined (PE_ENET_TENA))
cp->cp_pbpar |= PB_ENET_TENA;
cp->cp_pbdir |= PB_ENET_TENA;
+#elif ( !defined (PB_ENET_TENA) && !defined (PC_ENET_TENA) && defined (PE_ENET_TENA))
+ cp->cp_pepar |= PE_ENET_TENA;
+ cp->cp_pedir &= ~PE_ENET_TENA;
+ cp->cp_peso |= PE_ENET_TENA;
#else
-#error Configuration Error: define exactly ONE of PB_ENET_TENA, PC_ENET_TENA
+#error Configuration Error: define exactly ONE of PB_ENET_TENA, PC_ENET_TENA, PE_ENET_TENA
#endif
#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
@@ -936,6 +948,29 @@ static int __init scc_enet_init(void)
*((volatile uint *)BCSR1) &= ~BCSR1_ETHEN;
#endif
+#ifdef CONFIG_MPC885ADS
+
+ /* Deassert PHY reset and enable the PHY.
+ */
+ {
+ volatile uint __iomem *bcsr = ioremap(BCSR_ADDR, BCSR_SIZE);
+ uint tmp;
+
+ tmp = in_be32(bcsr + 1 /* BCSR1 */);
+ tmp |= BCSR1_ETHEN;
+ out_be32(bcsr + 1, tmp);
+ tmp = in_be32(bcsr + 4 /* BCSR4 */);
+ tmp |= BCSR4_ETH10_RST;
+ out_be32(bcsr + 4, tmp);
+ iounmap(bcsr);
+ }
+
+ /* On MPC885ADS SCC ethernet PHY defaults to the full duplex mode
+ * upon reset. SCC is set to half duplex by default. So this
+ * inconsistency should be better fixed by the software.
+ */
+#endif
+
dev->base_addr = (unsigned long)ep;
#if 0
dev->name = "CPM_ENET";
@@ -969,3 +1004,4 @@ static int __init scc_enet_init(void)
}
module_init(scc_enet_init);
+
diff --git a/arch/ppc/Kconfig b/arch/ppc/Kconfig
index 848f43970a4b..b833cbcd77f0 100644
--- a/arch/ppc/Kconfig
+++ b/arch/ppc/Kconfig
@@ -88,6 +88,9 @@ config 8xx
depends on BROKEN
bool "8xx"
+config E200
+ bool "e200"
+
config E500
bool "e500"
@@ -98,12 +101,12 @@ config PPC_FPU
config BOOKE
bool
- depends on E500
+ depends on E200 || E500
default y
config FSL_BOOKE
bool
- depends on E500
+ depends on E200 || E500
default y
config PTE_64BIT
@@ -141,16 +144,16 @@ config ALTIVEC
config SPE
bool "SPE Support"
- depends on E500
+ depends on E200 || E500
---help---
This option enables kernel support for the Signal Processing
Extensions (SPE) to the PowerPC processor. The kernel currently
supports saving and restoring SPE registers, and turning on the
'spe enable' bit so user processes can execute SPE instructions.
- This option is only usefully if you have a processor that supports
+ This option is only useful if you have a processor that supports
SPE (e500, otherwise known as 85xx series), but does not have any
- affect on a non-spe cpu (it does, however add code to the kernel).
+ effect on a non-spe cpu (it does, however add code to the kernel).
If in doubt, say Y here.
@@ -200,7 +203,7 @@ config TAU_AVERAGE
config MATH_EMULATION
bool "Math emulation"
- depends on 4xx || 8xx || E500
+ depends on 4xx || 8xx || E200 || E500
---help---
Some PowerPC chips designed for embedded applications do not have
a floating-point unit and therefore do not implement the
@@ -214,6 +217,26 @@ config MATH_EMULATION
here. Saying Y here will not hurt performance (on any machine) but
will increase the size of the kernel.
+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
+ In the GameCube implementation, kexec allows you to load and
+ run DOL files, including kernel and homebrew DOLs.
+
source "drivers/cpufreq/Kconfig"
config CPU_FREQ_PMAC
@@ -254,13 +277,16 @@ config PPC_STD_MMU
config NOT_COHERENT_CACHE
bool
- depends on 4xx || 8xx
+ depends on 4xx || 8xx || E200
default y
endmenu
menu "Platform options"
+config FADS
+ bool
+
choice
prompt "8xx Machine Type"
depends on 8xx
@@ -376,8 +402,25 @@ config BSEIP
26MB DRAM, 4MB flash, Ethernet, a 16K-gate FPGA, USB, an LCD/video
controller, and two RS232 ports.
-config FADS
+config MPC8XXFADS
bool "FADS"
+ select FADS
+
+config MPC86XADS
+ bool "MPC86XADS"
+ help
+ MPC86x Application Development System by Freescale Semiconductor.
+ The MPC86xADS is meant to serve as a platform for s/w and h/w
+ development around the MPC86X processor families.
+ select FADS
+
+config MPC885ADS
+ bool "MPC885ADS"
+ help
+ Freescale Semiconductor MPC885 Application Development System (ADS).
+ Also known as DUET.
+ The MPC885ADS is meant to serve as a platform for s/w and h/w
+ development around the MPC885 processor family.
config TQM823L
bool "TQM823L"
@@ -1312,6 +1355,8 @@ config PIN_TLB
depends on ADVANCED_OPTIONS && 8xx
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/ppc/Kconfig.debug b/arch/ppc/Kconfig.debug
index d2e1eea8e8e4..e16c7710d4be 100644
--- a/arch/ppc/Kconfig.debug
+++ b/arch/ppc/Kconfig.debug
@@ -66,7 +66,7 @@ config SERIAL_TEXT_DEBUG
config PPC_OCP
bool
- depends on IBM_OCP || FSL_OCP || XILINX_OCP
+ depends on IBM_OCP || XILINX_OCP
default y
endmenu
diff --git a/arch/ppc/Makefile b/arch/ppc/Makefile
index 0432a25b4735..f9b0d778dd82 100644
--- a/arch/ppc/Makefile
+++ b/arch/ppc/Makefile
@@ -29,7 +29,7 @@ CPP = $(CC) -E $(CFLAGS)
CHECKFLAGS += -D__powerpc__
-ifndef CONFIG_E500
+ifndef CONFIG_FSL_BOOKE
CFLAGS += -mstring
endif
@@ -38,6 +38,7 @@ cpu-as-$(CONFIG_4xx) += -Wa,-m405
cpu-as-$(CONFIG_6xx) += -Wa,-maltivec
cpu-as-$(CONFIG_POWER4) += -Wa,-maltivec
cpu-as-$(CONFIG_E500) += -Wa,-me500
+cpu-as-$(CONFIG_E200) += -Wa,-me200
AFLAGS += $(cpu-as-y)
CFLAGS += $(cpu-as-y)
diff --git a/arch/ppc/boot/openfirmware/chrpmain.c b/arch/ppc/boot/openfirmware/chrpmain.c
index 6fb4f738728c..effe4a0624b0 100644
--- a/arch/ppc/boot/openfirmware/chrpmain.c
+++ b/arch/ppc/boot/openfirmware/chrpmain.c
@@ -39,7 +39,7 @@ char *avail_high;
#define SCRATCH_SIZE (128 << 10)
-static char scratch[SCRATCH_SIZE]; /* 1MB of scratch space for gunzip */
+static char scratch[SCRATCH_SIZE]; /* 128k of scratch space for gunzip */
typedef void (*kernel_start_t)(int, int, void *, unsigned int, unsigned int);
diff --git a/arch/ppc/configs/mpc86x_ads_defconfig b/arch/ppc/configs/mpc86x_ads_defconfig
new file mode 100644
index 000000000000..f63c6f59d68a
--- /dev/null
+++ b/arch/ppc/configs/mpc86x_ads_defconfig
@@ -0,0 +1,633 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc4
+# Tue Jun 14 13:36:35 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+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_HOTPLUG is not set
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+# CONFIG_SHMEM is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+# CONFIG_KMOD is not set
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+CONFIG_8xx=y
+# CONFIG_E500 is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_PM is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+CONFIG_FADS=y
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_MPC8XXFADS is not set
+CONFIG_MPC86XADS=y
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_SPD823TS is not set
+# CONFIG_IVMS8 is not set
+# CONFIG_IVML24 is not set
+# CONFIG_SM850 is not set
+# CONFIG_HERMES_PRO is not set
+# CONFIG_IP860 is not set
+# CONFIG_LWMON is not set
+# CONFIG_PCU_E is not set
+# CONFIG_CCM is not set
+# CONFIG_LANTEC is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# 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 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_COW_COMMON 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 is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH 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
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP 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_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 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
+
+#
+# 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
+
+#
+# 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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+# CONFIG_MII is not set
+# CONFIG_OAKNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP 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 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+CONFIG_SOUND_GAMEPORT=y
+
+#
+# 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_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+# CONFIG_SERIAL_CPM_SMC2 is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM 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
+
+#
+# TPM devices
+#
+
+#
+# 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
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY 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 is not set
+# CONFIG_TMPFS is not set
+# 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_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=y
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=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_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+CONFIG_SCC1_ENET=y
+# CONFIG_SCC2_ENET is not set
+# CONFIG_SCC3_ENET is not set
+# CONFIG_FEC_ENET is not set
+# CONFIG_ENET_BIG_BUFFERS is not set
+
+#
+# Generic MPC8xx Options
+#
+# CONFIG_8xx_COPYBACK is not set
+# CONFIG_8xx_CPU6 is not set
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# 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_WP512 is not set
+# CONFIG_CRYPTO_TGR192 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_ANUBIS 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
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/configs/mpc885ads_defconfig b/arch/ppc/configs/mpc885ads_defconfig
new file mode 100644
index 000000000000..016f94d9325f
--- /dev/null
+++ b/arch/ppc/configs/mpc885ads_defconfig
@@ -0,0 +1,622 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.12-rc6
+# Thu Jun 9 21:17:29 2005
+#
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_PPC=y
+CONFIG_PPC32=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+# CONFIG_CLEAN_COMPILE is not set
+CONFIG_BROKEN=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_SWAP is not set
+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_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+# CONFIG_KALLSYMS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+# CONFIG_EPOLL is not set
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor
+#
+# CONFIG_6xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_POWER3 is not set
+# CONFIG_POWER4 is not set
+CONFIG_8xx=y
+# CONFIG_E500 is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_CPU_FREQ is not set
+CONFIG_EMBEDDEDBOOT=y
+# CONFIG_PM is not set
+CONFIG_NOT_COHERENT_CACHE=y
+
+#
+# Platform options
+#
+# CONFIG_RPXLITE is not set
+# CONFIG_RPXCLASSIC is not set
+# CONFIG_BSEIP is not set
+# CONFIG_FADS is not set
+CONFIG_MPC885ADS=y
+# CONFIG_TQM823L is not set
+# CONFIG_TQM850L is not set
+# CONFIG_TQM855L is not set
+# CONFIG_TQM860L is not set
+# CONFIG_FPS850L is not set
+# CONFIG_SPD823TS is not set
+# CONFIG_IVMS8 is not set
+# CONFIG_IVML24 is not set
+# CONFIG_SM850 is not set
+# CONFIG_HERMES_PRO is not set
+# CONFIG_IP860 is not set
+# CONFIG_LWMON is not set
+# CONFIG_PCU_E is not set
+# CONFIG_CCM is not set
+# CONFIG_LANTEC is not set
+# CONFIG_MBX is not set
+# CONFIG_WINCEPT is not set
+# CONFIG_SMP is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_QSPAN is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_HIGHMEM_START=0xfe000000
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_CONSISTENT_START=0xff100000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_BOOT_LOAD=0x00400000
+
+#
+# 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_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_LBD is not set
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH 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
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+
+#
+# Macintosh device drivers
+#
+
+#
+# Networking support
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP 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=y
+# 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_INET_TUNNEL is not set
+CONFIG_IP_TCPDIAG=y
+# CONFIG_IP_TCPDIAG_IPV6 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
+
+#
+# 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
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_OAKNET is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# 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=y
+CONFIG_PPP_SYNC_TTY=y
+CONFIG_PPP_DEFLATE=y
+# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPPOE is not set
+# CONFIG_SLIP 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 is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT 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_CPM=y
+CONFIG_SERIAL_CPM_CONSOLE=y
+# CONFIG_SERIAL_CPM_SCC1 is not set
+# CONFIG_SERIAL_CPM_SCC2 is not set
+# CONFIG_SERIAL_CPM_SCC3 is not set
+# CONFIG_SERIAL_CPM_SCC4 is not set
+CONFIG_SERIAL_CPM_SMC1=y
+CONFIG_SERIAL_CPM_SMC2=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_LEGACY_PTYS is not set
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM 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
+
+#
+# TPM devices
+#
+
+#
+# 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
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY 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
+
+#
+# XFS support
+#
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_QUOTA is not set
+# CONFIG_DNOTIFY 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 is not set
+CONFIG_SYSFS=y
+# CONFIG_DEVFS_FS is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# CONFIG_TMPFS is not set
+# 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_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 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
+# CONFIG_NFSD is not set
+CONFIG_ROOT_NFS=y
+CONFIG_LOCKD=y
+CONFIG_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
+# 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 is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# MPC8xx CPM Options
+#
+CONFIG_SCC_ENET=y
+# CONFIG_SCC1_ENET is not set
+# CONFIG_SCC2_ENET is not set
+CONFIG_SCC3_ENET=y
+# CONFIG_FEC_ENET is not set
+# CONFIG_ENET_BIG_BUFFERS is not set
+
+#
+# Generic MPC8xx Options
+#
+CONFIG_8xx_COPYBACK=y
+CONFIG_8xx_CPU6=y
+CONFIG_NO_UCODE_PATCH=y
+# CONFIG_USB_SOF_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_UCODE_PATCH is not set
+# CONFIG_I2C_SPI_SMC1_UCODE_PATCH is not set
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_LOG_BUF_SHIFT=14
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
diff --git a/arch/ppc/kernel/Makefile b/arch/ppc/kernel/Makefile
index b284451802c9..b1457a8a9c0f 100644
--- a/arch/ppc/kernel/Makefile
+++ b/arch/ppc/kernel/Makefile
@@ -26,7 +26,10 @@ obj-$(CONFIG_KGDB) += ppc-stub.o
obj-$(CONFIG_SMP) += smp.o smp-tbsync.o
obj-$(CONFIG_TAU) += temp.o
obj-$(CONFIG_ALTIVEC) += vecemu.o vector.o
+ifndef CONFIG_E200
obj-$(CONFIG_FSL_BOOKE) += perfmon_fsl_booke.o
+endif
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
ifndef CONFIG_MATH_EMULATION
obj-$(CONFIG_8xx) += softemu8xx.o
diff --git a/arch/ppc/kernel/cputable.c b/arch/ppc/kernel/cputable.c
index 01c226008dbf..50936cda0af9 100644
--- a/arch/ppc/kernel/cputable.c
+++ b/arch/ppc/kernel/cputable.c
@@ -903,7 +903,30 @@ struct cpu_spec cpu_specs[] = {
.dcache_bsize = 32,
},
#endif /* CONFIG_44x */
-#ifdef CONFIG_E500
+#ifdef CONFIG_FSL_BOOKE
+ { /* e200z5 */
+ .pvr_mask = 0xfff00000,
+ .pvr_value = 0x81000000,
+ .cpu_name = "e200z5",
+ /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+ .cpu_features = CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_HAS_EFP_SINGLE |
+ PPC_FEATURE_UNIFIED_CACHE,
+ .dcache_bsize = 32,
+ },
+ { /* e200z6 */
+ .pvr_mask = 0xfff00000,
+ .pvr_value = 0x81100000,
+ .cpu_name = "e200z6",
+ /* xxx - galak: add CPU_FTR_MAYBE_CAN_DOZE */
+ .cpu_features = CPU_FTR_USE_TB,
+ .cpu_user_features = PPC_FEATURE_32 |
+ PPC_FEATURE_HAS_MMU | PPC_FEATURE_SPE_COMP |
+ PPC_FEATURE_HAS_EFP_SINGLE |
+ PPC_FEATURE_UNIFIED_CACHE,
+ .dcache_bsize = 32,
+ },
{ /* e500 */
.pvr_mask = 0xffff0000,
.pvr_value = 0x80200000,
diff --git a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S
index 8377b6ca26da..d4df68629cc6 100644
--- a/arch/ppc/kernel/entry.S
+++ b/arch/ppc/kernel/entry.S
@@ -60,6 +60,11 @@ mcheck_transfer_to_handler:
TRANSFER_TO_HANDLER_EXC_LEVEL(MCHECK)
b transfer_to_handler_full
+ .globl debug_transfer_to_handler
+debug_transfer_to_handler:
+ TRANSFER_TO_HANDLER_EXC_LEVEL(DEBUG)
+ b transfer_to_handler_full
+
.globl crit_transfer_to_handler
crit_transfer_to_handler:
TRANSFER_TO_HANDLER_EXC_LEVEL(CRIT)
@@ -835,6 +840,10 @@ ret_from_crit_exc:
RET_FROM_EXC_LEVEL(SPRN_CSRR0, SPRN_CSRR1, RFCI)
#ifdef CONFIG_BOOKE
+ .globl ret_from_debug_exc
+ret_from_debug_exc:
+ RET_FROM_EXC_LEVEL(SPRN_DSRR0, SPRN_DSRR1, RFDI)
+
.globl ret_from_mcheck_exc
ret_from_mcheck_exc:
RET_FROM_EXC_LEVEL(SPRN_MCSRR0, SPRN_MCSRR1, RFMCI)
diff --git a/arch/ppc/kernel/head_booke.h b/arch/ppc/kernel/head_booke.h
index 9c50f9d2657c..9342acf12e72 100644
--- a/arch/ppc/kernel/head_booke.h
+++ b/arch/ppc/kernel/head_booke.h
@@ -49,6 +49,7 @@
*
* On 40x critical is the only additional level
* On 44x/e500 we have critical and machine check
+ * On e200 we have critical and debug (machine check occurs via critical)
*
* Additionally we reserve a SPRG for each priority level so we can free up a
* GPR to use as the base for indirect access to the exception stacks. This
@@ -60,12 +61,16 @@
/* CRIT_SPRG only used in critical exception handling */
#define CRIT_SPRG SPRN_SPRG2
-/* MCHECK_SPRG only used in critical exception handling */
+/* MCHECK_SPRG only used in machine check exception handling */
#define MCHECK_SPRG SPRN_SPRG6W
#define MCHECK_STACK_TOP (exception_stack_top - 4096)
#define CRIT_STACK_TOP (exception_stack_top)
+/* only on e200 for now */
+#define DEBUG_STACK_TOP (exception_stack_top - 4096)
+#define DEBUG_SPRG SPRN_SPRG6W
+
#ifdef CONFIG_SMP
#define BOOKE_LOAD_EXC_LEVEL_STACK(level) \
mfspr r8,SPRN_PIR; \
@@ -124,6 +129,8 @@
#define CRITICAL_EXCEPTION_PROLOG \
EXC_LEVEL_EXCEPTION_PROLOG(CRIT, SPRN_CSRR0, SPRN_CSRR1)
+#define DEBUG_EXCEPTION_PROLOG \
+ EXC_LEVEL_EXCEPTION_PROLOG(DEBUG, SPRN_DSRR0, SPRN_DSRR1)
#define MCHECK_EXCEPTION_PROLOG \
EXC_LEVEL_EXCEPTION_PROLOG(MCHECK, SPRN_MCSRR0, SPRN_MCSRR1)
@@ -205,6 +212,60 @@ label:
* save (and later restore) the MSR via SPRN_CSRR1, which will still have
* the MSR_DE bit set.
*/
+#ifdef CONFIG_E200
+#define DEBUG_EXCEPTION \
+ START_EXCEPTION(Debug); \
+ DEBUG_EXCEPTION_PROLOG; \
+ \
+ /* \
+ * If there is a single step or branch-taken exception in an \
+ * exception entry sequence, it was probably meant to apply to \
+ * the code where the exception occurred (since exception entry \
+ * doesn't turn off DE automatically). We simulate the effect \
+ * of turning off DE on entry to an exception handler by turning \
+ * off DE in the CSRR1 value and clearing the debug status. \
+ */ \
+ mfspr r10,SPRN_DBSR; /* check single-step/branch taken */ \
+ andis. r10,r10,DBSR_IC@h; \
+ beq+ 2f; \
+ \
+ lis r10,KERNELBASE@h; /* check if exception in vectors */ \
+ ori r10,r10,KERNELBASE@l; \
+ cmplw r12,r10; \
+ blt+ 2f; /* addr below exception vectors */ \
+ \
+ lis r10,Debug@h; \
+ ori r10,r10,Debug@l; \
+ cmplw r12,r10; \
+ bgt+ 2f; /* addr above exception vectors */ \
+ \
+ /* here it looks like we got an inappropriate debug exception. */ \
+1: rlwinm r9,r9,0,~MSR_DE; /* clear DE in the CDRR1 value */ \
+ lis r10,DBSR_IC@h; /* clear the IC event */ \
+ mtspr SPRN_DBSR,r10; \
+ /* restore state and get out */ \
+ lwz r10,_CCR(r11); \
+ lwz r0,GPR0(r11); \
+ lwz r1,GPR1(r11); \
+ mtcrf 0x80,r10; \
+ mtspr SPRN_DSRR0,r12; \
+ mtspr SPRN_DSRR1,r9; \
+ lwz r9,GPR9(r11); \
+ lwz r12,GPR12(r11); \
+ mtspr DEBUG_SPRG,r8; \
+ BOOKE_LOAD_EXC_LEVEL_STACK(DEBUG); /* r8 points to the debug stack */ \
+ lwz r10,GPR10-INT_FRAME_SIZE(r8); \
+ lwz r11,GPR11-INT_FRAME_SIZE(r8); \
+ mfspr r8,DEBUG_SPRG; \
+ \
+ RFDI; \
+ b .; \
+ \
+ /* continue normal handling for a critical exception... */ \
+2: mfspr r4,SPRN_DBSR; \
+ addi r3,r1,STACK_FRAME_OVERHEAD; \
+ EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, debug_transfer_to_handler, ret_from_debug_exc)
+#else
#define DEBUG_EXCEPTION \
START_EXCEPTION(Debug); \
CRITICAL_EXCEPTION_PROLOG; \
@@ -257,6 +318,7 @@ label:
2: mfspr r4,SPRN_DBSR; \
addi r3,r1,STACK_FRAME_OVERHEAD; \
EXC_XFER_TEMPLATE(DebugException, 0x2002, (MSR_KERNEL & ~(MSR_ME|MSR_DE|MSR_CE)), NOCOPY, crit_transfer_to_handler, ret_from_crit_exc)
+#endif
#define INSTRUCTION_STORAGE_EXCEPTION \
START_EXCEPTION(InstructionStorage) \
diff --git a/arch/ppc/kernel/head_fsl_booke.S b/arch/ppc/kernel/head_fsl_booke.S
index ce36e88ba627..eb804b7a3cb2 100644
--- a/arch/ppc/kernel/head_fsl_booke.S
+++ b/arch/ppc/kernel/head_fsl_booke.S
@@ -102,6 +102,7 @@ invstr: mflr r6 /* Make it accessible */
or r7,r7,r4
mtspr SPRN_MAS6,r7
tlbsx 0,r6 /* search MSR[IS], SPID=PID0 */
+#ifndef CONFIG_E200
mfspr r7,SPRN_MAS1
andis. r7,r7,MAS1_VALID@h
bne match_TLB
@@ -118,6 +119,7 @@ invstr: mflr r6 /* Make it accessible */
or r7,r7,r4
mtspr SPRN_MAS6,r7
tlbsx 0,r6 /* Fall through, we had to match */
+#endif
match_TLB:
mfspr r7,SPRN_MAS0
rlwinm r3,r7,16,20,31 /* Extract MAS0(Entry) */
@@ -196,8 +198,10 @@ skpinv: addi r6,r6,1 /* Increment */
/* 4. Clear out PIDs & Search info */
li r6,0
mtspr SPRN_PID0,r6
+#ifndef CONFIG_E200
mtspr SPRN_PID1,r6
mtspr SPRN_PID2,r6
+#endif
mtspr SPRN_MAS6,r6
/* 5. Invalidate mapping we started in */
@@ -277,7 +281,9 @@ skpinv: addi r6,r6,1 /* Increment */
SET_IVOR(32, SPEUnavailable);
SET_IVOR(33, SPEFloatingPointData);
SET_IVOR(34, SPEFloatingPointRound);
+#ifndef CONFIG_E200
SET_IVOR(35, PerformanceMonitor);
+#endif
/* Establish the interrupt vector base */
lis r4,interrupt_base@h /* IVPR only uses the high 16-bits */
@@ -285,6 +291,9 @@ skpinv: addi r6,r6,1 /* Increment */
/* Setup the defaults for TLB entries */
li r2,(MAS4_TSIZED(BOOKE_PAGESZ_4K))@l
+#ifdef CONFIG_E200
+ oris r2,r2,MAS4_TLBSELD(1)@h
+#endif
mtspr SPRN_MAS4, r2
#if 0
@@ -293,6 +302,12 @@ skpinv: addi r6,r6,1 /* Increment */
oris r2,r2,HID0_DOZE@h
mtspr SPRN_HID0, r2
#endif
+#ifdef CONFIG_E200
+ /* enable dedicated debug exception handling resources (Debug APU) */
+ mfspr r2,SPRN_HID0
+ ori r2,r2,HID0_DAPUEN@l
+ mtspr SPRN_HID0,r2
+#endif
#if !defined(CONFIG_BDI_SWITCH)
/*
@@ -414,7 +429,12 @@ interrupt_base:
CRITICAL_EXCEPTION(0x0100, CriticalInput, UnknownException)
/* Machine Check Interrupt */
+#ifdef CONFIG_E200
+ /* no RFMCI, MCSRRs on E200 */
+ CRITICAL_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#else
MCHECK_EXCEPTION(0x0200, MachineCheck, MachineCheckException)
+#endif
/* Data Storage Interrupt */
START_EXCEPTION(DataStorage)
@@ -520,8 +540,13 @@ interrupt_base:
#ifdef CONFIG_PPC_FPU
FP_UNAVAILABLE_EXCEPTION
#else
+#ifdef CONFIG_E200
+ /* E200 treats 'normal' floating point instructions as FP Unavail exception */
+ EXCEPTION(0x0800, FloatingPointUnavailable, ProgramCheckException, EXC_XFER_EE)
+#else
EXCEPTION(0x0800, FloatingPointUnavailable, UnknownException, EXC_XFER_EE)
#endif
+#endif
/* System Call Interrupt */
START_EXCEPTION(SystemCall)
@@ -691,6 +716,7 @@ interrupt_base:
/*
* Local functions
*/
+
/*
* Data TLB exceptions will bail out to this point
* if they can't resolve the lightweight TLB fault.
@@ -761,6 +787,31 @@ END_FTR_SECTION_IFSET(CPU_FTR_BIG_PHYS)
2: rlwimi r11, r12, 0, 20, 31 /* Extract RPN from PTE and merge with perms */
mtspr SPRN_MAS3, r11
#endif
+#ifdef CONFIG_E200
+ /* Round robin TLB1 entries assignment */
+ mfspr r12, SPRN_MAS0
+
+ /* Extract TLB1CFG(NENTRY) */
+ mfspr r11, SPRN_TLB1CFG
+ andi. r11, r11, 0xfff
+
+ /* Extract MAS0(NV) */
+ andi. r13, r12, 0xfff
+ addi r13, r13, 1
+ cmpw 0, r13, r11
+ addi r12, r12, 1
+
+ /* check if we need to wrap */
+ blt 7f
+
+ /* wrap back to first free tlbcam entry */
+ lis r13, tlbcam_index@ha
+ lwz r13, tlbcam_index@l(r13)
+ rlwimi r12, r13, 0, 20, 31
+7:
+ mtspr SPRN_MAS0,r12
+#endif /* CONFIG_E200 */
+
tlbwe
/* Done...restore registers and get out of here. */
diff --git a/arch/ppc/kernel/machine_kexec.c b/arch/ppc/kernel/machine_kexec.c
new file mode 100644
index 000000000000..a72787747df7
--- /dev/null
+++ b/arch/ppc/kernel/machine_kexec.c
@@ -0,0 +1,124 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/reboot.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/hw_irq.h>
+#include <asm/cacheflush.h>
+#include <asm/machdep.h>
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(
+ unsigned long indirection_page,
+ unsigned long reboot_code_buffer,
+ unsigned long start_address) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned int relocate_new_kernel_size;
+
+/*
+ * Provide a dummy crash_notes definition while crash dump arrives to ppc.
+ * This prevents breakage of crash_notes attribute in kernel/ksysfs.c.
+ */
+void *crash_notes = NULL;
+
+void machine_shutdown(void)
+{
+ if (ppc_md.machine_shutdown)
+ ppc_md.machine_shutdown();
+}
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ if (ppc_md.machine_crash_shutdown)
+ ppc_md.machine_crash_shutdown();
+}
+
+/*
+ * Do what every setup is needed on image and the
+ * reboot code buffer to allow us to avoid allocations
+ * later.
+ */
+int machine_kexec_prepare(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_prepare)
+ return ppc_md.machine_kexec_prepare(image);
+ /*
+ * Fail if platform doesn't provide its own machine_kexec_prepare
+ * implementation.
+ */
+ return -ENOSYS;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ if (ppc_md.machine_kexec_cleanup)
+ ppc_md.machine_kexec_cleanup(image);
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ if (ppc_md.machine_kexec)
+ ppc_md.machine_kexec(image);
+ else {
+ /*
+ * Fall back to normal restart if platform doesn't provide
+ * its own kexec function, and user insist to kexec...
+ */
+ machine_restart(NULL);
+ }
+ for(;;);
+}
+
+/*
+ * This is a generic machine_kexec function suitable at least for
+ * non-OpenFirmware embedded platforms.
+ * It merely copies the image relocation code to the control page and
+ * jumps to it.
+ * A platform specific function may just call this one.
+ */
+void machine_kexec_simple(struct kimage *image)
+{
+ unsigned long page_list;
+ unsigned long reboot_code_buffer, reboot_code_buffer_phys;
+ relocate_new_kernel_t rnk;
+
+ /* Interrupts aren't acceptable while we reboot */
+ local_irq_disable();
+
+ page_list = image->head;
+
+ /* we need both effective and real address here */
+ reboot_code_buffer =
+ (unsigned long)page_address(image->control_code_page);
+ reboot_code_buffer_phys = virt_to_phys((void *)reboot_code_buffer);
+
+ /* copy our kernel relocation code to the control code page */
+ memcpy((void *)reboot_code_buffer, relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ flush_icache_range(reboot_code_buffer,
+ reboot_code_buffer + KEXEC_CONTROL_CODE_SIZE);
+ printk(KERN_INFO "Bye!\n");
+
+ /* now call it */
+ rnk = (relocate_new_kernel_t) reboot_code_buffer;
+ (*rnk)(page_list, reboot_code_buffer_phys, image->start);
+}
+
diff --git a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S
index 7329ef177a18..191a8def3bdb 100644
--- a/arch/ppc/kernel/misc.S
+++ b/arch/ppc/kernel/misc.S
@@ -593,6 +593,14 @@ _GLOBAL(flush_instruction_cache)
iccci 0,r3
#endif
#elif CONFIG_FSL_BOOKE
+BEGIN_FTR_SECTION
+ mfspr r3,SPRN_L1CSR0
+ ori r3,r3,L1CSR0_CFI|L1CSR0_CLFC
+ /* msync; isync recommended here */
+ mtspr SPRN_L1CSR0,r3
+ isync
+ blr
+END_FTR_SECTION_IFCLR(CPU_FTR_SPLIT_ID_CACHE)
mfspr r3,SPRN_L1CSR1
ori r3,r3,L1CSR1_ICFI|L1CSR1_ICLFR
mtspr SPRN_L1CSR1,r3
@@ -1436,8 +1444,10 @@ _GLOBAL(sys_call_table)
.long sys_mq_timedreceive /* 265 */
.long sys_mq_notify
.long sys_mq_getsetattr
- .long sys_ni_syscall /* 268 reserved for sys_kexec_load */
+ .long sys_kexec_load
.long sys_add_key
.long sys_request_key /* 270 */
.long sys_keyctl
.long sys_waitid
+ .long sys_ioprio_set
+ .long sys_ioprio_get
diff --git a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c
index 6d7b92d72458..70cfb6ffd877 100644
--- a/arch/ppc/kernel/pci.c
+++ b/arch/ppc/kernel/pci.c
@@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
*offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM;
} else {
- io_offset = (unsigned long)hose->io_base_virt;
+ io_offset = hose->io_base_virt - ___IO_BASE;
*offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* found it! construct the final physical address */
if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - _IO_BASE;
+ *offset += hose->io_base_phys - io_offset;
return rp;
}
@@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
return result;
}
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ u64 *start, u64 *end)
+{
+ struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
+ unsigned long offset = 0;
+
+ if (hose == NULL)
+ return;
+
+ if (rsrc->flags & IORESOURCE_IO)
+ offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
+
+ *start = rsrc->start + offset;
+ *end = rsrc->end + offset;
+}
+
void __init
pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
int flags, char *name)
diff --git a/arch/ppc/kernel/perfmon.c b/arch/ppc/kernel/perfmon.c
index 918f6b252e45..fa1dad96b830 100644
--- a/arch/ppc/kernel/perfmon.c
+++ b/arch/ppc/kernel/perfmon.c
@@ -36,7 +36,7 @@
/* A lock to regulate grabbing the interrupt */
DEFINE_SPINLOCK(perfmon_lock);
-#ifdef CONFIG_FSL_BOOKE
+#if defined (CONFIG_FSL_BOOKE) && !defined (CONFIG_E200)
static void dummy_perf(struct pt_regs *regs)
{
unsigned int pmgc0 = mfpmr(PMRN_PMGC0);
diff --git a/arch/ppc/kernel/relocate_kernel.S b/arch/ppc/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..9b2ad48e988c
--- /dev/null
+++ b/arch/ppc/kernel/relocate_kernel.S
@@ -0,0 +1,123 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2003 Eric Biederman <ebiederm@xmission.com>
+ *
+ * GameCube/ppc32 port Copyright (C) 2004 Albert Herranz
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <asm/reg.h>
+#include <asm/ppc_asm.h>
+#include <asm/processor.h>
+
+#include <asm/kexec.h>
+
+#define PAGE_SIZE 4096 /* must be same value as in <asm/page.h> */
+
+ /*
+ * Must be relocatable PIC code callable as a C function.
+ */
+ .globl relocate_new_kernel
+relocate_new_kernel:
+ /* r3 = page_list */
+ /* r4 = reboot_code_buffer */
+ /* r5 = start_address */
+
+ li r0, 0
+
+ /*
+ * Set Machine Status Register to a known status,
+ * switch the MMU off and jump to 1: in a single step.
+ */
+
+ mr r8, r0
+ ori r8, r8, MSR_RI|MSR_ME
+ mtspr SPRN_SRR1, r8
+ addi r8, r4, 1f - relocate_new_kernel
+ mtspr SPRN_SRR0, r8
+ sync
+ rfi
+
+1:
+ /* from this point address translation is turned off */
+ /* and interrupts are disabled */
+
+ /* set a new stack at the bottom of our page... */
+ /* (not really needed now) */
+ addi r1, r4, KEXEC_CONTROL_CODE_SIZE - 8 /* for LR Save+Back Chain */
+ stw r0, 0(r1)
+
+ /* Do the copies */
+ li r6, 0 /* checksum */
+ mr r0, r3
+ b 1f
+
+0: /* top, read another word for the indirection page */
+ lwzu r0, 4(r3)
+
+1:
+ /* is it a destination page? (r8) */
+ rlwinm. r7, r0, 0, 31, 31 /* IND_DESTINATION (1<<0) */
+ beq 2f
+
+ rlwinm r8, r0, 0, 0, 19 /* clear kexec flags, page align */
+ b 0b
+
+2: /* is it an indirection page? (r3) */
+ rlwinm. r7, r0, 0, 30, 30 /* IND_INDIRECTION (1<<1) */
+ beq 2f
+
+ rlwinm r3, r0, 0, 0, 19 /* clear kexec flags, page align */
+ subi r3, r3, 4
+ b 0b
+
+2: /* are we done? */
+ rlwinm. r7, r0, 0, 29, 29 /* IND_DONE (1<<2) */
+ beq 2f
+ b 3f
+
+2: /* is it a source page? (r9) */
+ rlwinm. r7, r0, 0, 28, 28 /* IND_SOURCE (1<<3) */
+ beq 0b
+
+ rlwinm r9, r0, 0, 0, 19 /* clear kexec flags, page align */
+
+ li r7, PAGE_SIZE / 4
+ mtctr r7
+ subi r9, r9, 4
+ subi r8, r8, 4
+9:
+ lwzu r0, 4(r9) /* do the copy */
+ xor r6, r6, r0
+ stwu r0, 4(r8)
+ dcbst 0, r8
+ sync
+ icbi 0, r8
+ bdnz 9b
+
+ addi r9, r9, 4
+ addi r8, r8, 4
+ b 0b
+
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * execute a serializing instruction here.
+ */
+ isync
+ sync
+
+ /* jump to the entry point, usually the setup routine */
+ mtlr r5
+ blrl
+
+1: b 1b
+
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .long relocate_new_kernel_end - relocate_new_kernel
+
diff --git a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c
index 7c8437da09d5..8aaeb6f4e750 100644
--- a/arch/ppc/kernel/signal.c
+++ b/arch/ppc/kernel/signal.c
@@ -705,8 +705,7 @@ int do_signal(sigset_t *oldset, struct pt_regs *regs)
unsigned long frame, newsp;
int signr, ret;
- if (current->flags & PF_FREEZE) {
- refrigerator(PF_FREEZE);
+ if (try_to_freeze()) {
signr = 0;
if (!signal_pending(current))
goto no_signal;
diff --git a/arch/ppc/kernel/time.c b/arch/ppc/kernel/time.c
index 735866559199..bf4ddca5e853 100644
--- a/arch/ppc/kernel/time.c
+++ b/arch/ppc/kernel/time.c
@@ -89,6 +89,9 @@ unsigned long tb_to_ns_scale;
extern unsigned long wall_jiffies;
+/* used for timezone offset */
+static long timezone_offset;
+
DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL(rtc_lock);
@@ -170,7 +173,7 @@ void timer_interrupt(struct pt_regs * regs)
xtime.tv_sec - last_rtc_update >= 659 &&
abs((xtime.tv_nsec / 1000) - (1000000-1000000/HZ)) < 500000/HZ &&
jiffies - wall_jiffies == 1) {
- if (ppc_md.set_rtc_time(xtime.tv_sec+1 + time_offset) == 0)
+ if (ppc_md.set_rtc_time(xtime.tv_sec+1 + timezone_offset) == 0)
last_rtc_update = xtime.tv_sec+1;
else
/* Try again one minute later */
@@ -286,7 +289,7 @@ void __init time_init(void)
unsigned old_stamp, stamp, elapsed;
if (ppc_md.time_init != NULL)
- time_offset = ppc_md.time_init();
+ timezone_offset = ppc_md.time_init();
if (__USE_RTC()) {
/* 601 processor: dec counts down by 128 every 128ns */
@@ -331,10 +334,10 @@ void __init time_init(void)
set_dec(tb_ticks_per_jiffy);
/* If platform provided a timezone (pmac), we correct the time */
- if (time_offset) {
- sys_tz.tz_minuteswest = -time_offset / 60;
+ if (timezone_offset) {
+ sys_tz.tz_minuteswest = -timezone_offset / 60;
sys_tz.tz_dsttime = 0;
- xtime.tv_sec -= time_offset;
+ xtime.tv_sec -= timezone_offset;
}
set_normalized_timespec(&wall_to_monotonic,
-xtime.tv_sec, -xtime.tv_nsec);
diff --git a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c
index 2ca8ecfeefd9..9e6ae5696650 100644
--- a/arch/ppc/kernel/traps.c
+++ b/arch/ppc/kernel/traps.c
@@ -173,13 +173,13 @@ static inline int check_io_access(struct pt_regs *regs)
/* On 4xx, the reason for the machine check or program exception
is in the ESR. */
#define get_reason(regs) ((regs)->dsisr)
-#ifndef CONFIG_E500
+#ifndef CONFIG_FSL_BOOKE
#define get_mc_reason(regs) ((regs)->dsisr)
#else
#define get_mc_reason(regs) (mfspr(SPRN_MCSR))
#endif
#define REASON_FP ESR_FP
-#define REASON_ILLEGAL ESR_PIL
+#define REASON_ILLEGAL (ESR_PIL | ESR_PUO)
#define REASON_PRIVILEGED ESR_PPR
#define REASON_TRAP ESR_PTR
@@ -302,7 +302,25 @@ void MachineCheckException(struct pt_regs *regs)
printk("Bus - Instruction Parity Error\n");
if (reason & MCSR_BUS_RPERR)
printk("Bus - Read Parity Error\n");
-#else /* !CONFIG_4xx && !CONFIG_E500 */
+#elif defined (CONFIG_E200)
+ printk("Machine check in kernel mode.\n");
+ printk("Caused by (from MCSR=%lx): ", reason);
+
+ if (reason & MCSR_MCP)
+ printk("Machine Check Signal\n");
+ if (reason & MCSR_CP_PERR)
+ printk("Cache Push Parity Error\n");
+ if (reason & MCSR_CPERR)
+ printk("Cache Parity Error\n");
+ if (reason & MCSR_EXCP_ERR)
+ printk("ISI, ITLB, or Bus Error on first instruction fetch for an exception handler\n");
+ if (reason & MCSR_BUS_IRERR)
+ printk("Bus - Read Bus Error on instruction fetch\n");
+ if (reason & MCSR_BUS_DRERR)
+ printk("Bus - Read Bus Error on data load\n");
+ if (reason & MCSR_BUS_WRERR)
+ printk("Bus - Write Bus Error on buffered store or cache line push\n");
+#else /* !CONFIG_4xx && !CONFIG_E500 && !CONFIG_E200 */
printk("Machine check in kernel mode.\n");
printk("Caused by (from SRR1=%lx): ", reason);
switch (reason & 0x601F0000) {
diff --git a/arch/ppc/mm/44x_mmu.c b/arch/ppc/mm/44x_mmu.c
index 72f7c0d1c0ed..3d79ce281b67 100644
--- a/arch/ppc/mm/44x_mmu.c
+++ b/arch/ppc/mm/44x_mmu.c
@@ -39,7 +39,6 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <asm/pgalloc.h>
diff --git a/arch/ppc/mm/4xx_mmu.c b/arch/ppc/mm/4xx_mmu.c
index a7f616140381..b7bcbc232f39 100644
--- a/arch/ppc/mm/4xx_mmu.c
+++ b/arch/ppc/mm/4xx_mmu.c
@@ -36,7 +36,6 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <asm/pgalloc.h>
diff --git a/arch/ppc/mm/fsl_booke_mmu.c b/arch/ppc/mm/fsl_booke_mmu.c
index e07990efa046..af9ca0eb6d55 100644
--- a/arch/ppc/mm/fsl_booke_mmu.c
+++ b/arch/ppc/mm/fsl_booke_mmu.c
@@ -41,7 +41,6 @@
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <asm/pgalloc.h>
@@ -126,7 +125,7 @@ void settlbcam(int index, unsigned long virt, phys_addr_t phys,
flags |= _PAGE_COHERENT;
#endif
- TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index);
+ TLBCAM[index].MAS0 = MAS0_TLBSEL(1) | MAS0_ESEL(index) | MAS0_NV(index+1);
TLBCAM[index].MAS1 = MAS1_VALID | MAS1_IPROT | MAS1_TSIZE(tsize) | MAS1_TID(pid);
TLBCAM[index].MAS2 = virt & PAGE_MASK;
diff --git a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c
index 334ef4150d92..6164a2b34733 100644
--- a/arch/ppc/mm/init.c
+++ b/arch/ppc/mm/init.c
@@ -606,9 +606,19 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
struct page *page = pfn_to_page(pfn);
if (!PageReserved(page)
&& !test_bit(PG_arch_1, &page->flags)) {
- if (vma->vm_mm == current->active_mm)
+ if (vma->vm_mm == current->active_mm) {
+#ifdef CONFIG_8xx
+ /* On 8xx, cache control instructions (particularly
+ * "dcbst" from flush_dcache_icache) fault as write
+ * operation if there is an unpopulated TLB entry
+ * for the address in question. To workaround that,
+ * we invalidate the TLB here, thus avoiding dcbst
+ * misbehaviour.
+ */
+ _tlbie(address);
+#endif
__flush_dcache_icache((void *) address);
- else
+ } else
flush_dcache_icache_page(page);
set_bit(PG_arch_1, &page->flags);
}
diff --git a/arch/ppc/platforms/83xx/mpc834x_sys.c b/arch/ppc/platforms/83xx/mpc834x_sys.c
index 37ece1542799..ddd04d4c1ea9 100644
--- a/arch/ppc/platforms/83xx/mpc834x_sys.c
+++ b/arch/ppc/platforms/83xx/mpc834x_sys.c
@@ -94,20 +94,24 @@ mpc834x_sys_setup_arch(void)
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC1);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC83xx_IRQ_EXT1;
- pdata->phyid = 0;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC83xx_IRQ_EXT1;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC83xx_TSEC2);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC83xx_IRQ_EXT2;
- pdata->phyid = 1;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC83xx_IRQ_EXT2;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
diff --git a/arch/ppc/platforms/85xx/mpc8540_ads.c b/arch/ppc/platforms/85xx/mpc8540_ads.c
index a2ed611cd936..f761fdf160db 100644
--- a/arch/ppc/platforms/85xx/mpc8540_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8540_ads.c
@@ -92,28 +92,34 @@ mpc8540ads_setup_arch(void)
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 0;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 1;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_FEC);
- pdata->board_flags = 0;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 3;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+ if (pdata) {
+ pdata->board_flags = 0;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 3;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet2addr, 6);
+ }
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
diff --git a/arch/ppc/platforms/85xx/mpc8560_ads.c b/arch/ppc/platforms/85xx/mpc8560_ads.c
index d87dfd5ce0a2..e18380258b68 100644
--- a/arch/ppc/platforms/85xx/mpc8560_ads.c
+++ b/arch/ppc/platforms/85xx/mpc8560_ads.c
@@ -90,20 +90,24 @@ mpc8560ads_setup_arch(void)
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 0;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 0;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 1;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 1;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
diff --git a/arch/ppc/platforms/85xx/sbc8560.c b/arch/ppc/platforms/85xx/sbc8560.c
index 3dbdd73618eb..165df94d4aa6 100644
--- a/arch/ppc/platforms/85xx/sbc8560.c
+++ b/arch/ppc/platforms/85xx/sbc8560.c
@@ -129,20 +129,24 @@ sbc8560_setup_arch(void)
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT6;
- pdata->phyid = 25;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT6;
+ pdata->phyid = 25;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
- pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
- pdata->interruptPHY = MPC85xx_IRQ_EXT7;
- pdata->phyid = 26;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR;
+ pdata->interruptPHY = MPC85xx_IRQ_EXT7;
+ pdata->phyid = 26;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
diff --git a/arch/ppc/platforms/85xx/stx_gp3.c b/arch/ppc/platforms/85xx/stx_gp3.c
index 9455bb6b45e9..bb41265cfc85 100644
--- a/arch/ppc/platforms/85xx/stx_gp3.c
+++ b/arch/ppc/platforms/85xx/stx_gp3.c
@@ -122,19 +122,23 @@ gp3_setup_arch(void)
/* setup the board related information for the enet controllers */
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC1);
-/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 2;
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ if (pdata) {
+ /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 2;
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enetaddr, 6);
+ }
pdata = (struct gianfar_platform_data *) ppc_sys_get_pdata(MPC85xx_TSEC2);
-/* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
- pdata->interruptPHY = MPC85xx_IRQ_EXT5;
- pdata->phyid = 4;
- /* fixup phy address */
- pdata->phy_reg_addr += binfo->bi_immr_base;
- memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ if (pdata) {
+ /* pdata->board_flags = FSL_GIANFAR_BRD_HAS_PHY_INTR; */
+ pdata->interruptPHY = MPC85xx_IRQ_EXT5;
+ pdata->phyid = 4;
+ /* fixup phy address */
+ pdata->phy_reg_addr += binfo->bi_immr_base;
+ memcpy(pdata->mac_addr, binfo->bi_enet1addr, 6);
+ }
#ifdef CONFIG_BLK_DEV_INITRD
if (initrd_start)
diff --git a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c
index 7d0ee308f662..7d3fbb5c5db2 100644
--- a/arch/ppc/platforms/chrp_pci.c
+++ b/arch/ppc/platforms/chrp_pci.c
@@ -9,7 +9,6 @@
#include <linux/string.h>
#include <linux/init.h>
#include <linux/ide.h>
-#include <linux/bootmem.h>
#include <asm/io.h>
#include <asm/pgtable.h>
diff --git a/arch/ppc/platforms/fads.h b/arch/ppc/platforms/fads.h
index 632b8178ce66..b60c56450b67 100644
--- a/arch/ppc/platforms/fads.h
+++ b/arch/ppc/platforms/fads.h
@@ -3,7 +3,18 @@
* the Motorola 860T FADS board. Copied from the MBX stuff.
*
* Copyright (c) 1998 Dan Malek (dmalek@jlc.net)
+ *
+ * Added MPC86XADS support.
+ * The MPC86xADS manual says the board "is compatible with the MPC8xxFADS
+ * for SW point of view". This is 99% correct.
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ * 2005 (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_FADS_H__
#define __ASM_FADS_H__
@@ -12,18 +23,45 @@
#include <asm/ppcboot.h>
+#if defined(CONFIG_MPC86XADS)
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR ((uint)0xff080000)
+
+/* MPC86XADS has one more CPLD and an additional BCSR.
+ */
+#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
+#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define BCSR5_T1_RST 0x10
+#define BCSR5_ATM155_RST 0x08
+#define BCSR5_ATM25_RST 0x04
+#define BCSR5_MII1_EN 0x02
+#define BCSR5_MII1_RST 0x01
+
+/* There is no PHY link change interrupt */
+#define PHY_INTERRUPT (-1)
+
+#else /* FADS */
+
/* Memory map is configured by the PROM startup.
* I tried to follow the FADS manual, although the startup PROM
* dictates this and we simply have to move some of the physical
* addresses for Linux.
*/
#define BCSR_ADDR ((uint)0xff010000)
+
+/* PHY link change interrupt */
+#define PHY_INTERRUPT SIU_IRQ2
+
+#endif /* CONFIG_MPC86XADS */
+
#define BCSR_SIZE ((uint)(64 * 1024))
-#define BCSR0 ((uint)0xff010000)
-#define BCSR1 ((uint)0xff010004)
-#define BCSR2 ((uint)0xff010008)
-#define BCSR3 ((uint)0xff01000c)
-#define BCSR4 ((uint)0xff010010)
+#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
+#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
+#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
+#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
#define IMAP_ADDR ((uint)0xff000000)
#define IMAP_SIZE ((uint)(64 * 1024))
@@ -34,8 +72,17 @@
/* Bits of interest in the BCSRs.
*/
#define BCSR1_ETHEN ((uint)0x20000000)
+#define BCSR1_IRDAEN ((uint)0x10000000)
#define BCSR1_RS232EN_1 ((uint)0x01000000)
+#define BCSR1_PCCEN ((uint)0x00800000)
+#define BCSR1_PCCVCC0 ((uint)0x00400000)
+#define BCSR1_PCCVPP0 ((uint)0x00200000)
+#define BCSR1_PCCVPP1 ((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
#define BCSR1_RS232EN_2 ((uint)0x00040000)
+#define BCSR1_PCCVCC1 ((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
#define BCSR4_ETHLOOP ((uint)0x80000000) /* EEST Loopback */
#define BCSR4_EEFDX ((uint)0x40000000) /* EEST FDX enable */
#define BCSR4_FETH_EN ((uint)0x08000000) /* PHY enable */
@@ -44,14 +91,64 @@
#define BCSR4_FETHFDE ((uint)0x02000000) /* PHY FDX advertise */
#define BCSR4_FETHRST ((uint)0x00200000) /* PHY Reset */
+/* IO_BASE definition for pcmcia.
+ */
+#define _IO_BASE 0x80000000
+#define _IO_BASE_SIZE 0x1000
+
+#ifdef CONFIG_IDE
+#define MAX_HWIFS 1
+#endif
+
/* Interrupt level assignments.
*/
#define FEC_INTERRUPT SIU_LEVEL1 /* FEC interrupt */
-#define PHY_INTERRUPT SIU_IRQ2 /* PHY link change interrupt */
/* We don't use the 8259.
*/
#define NR_8259_INTS 0
+/* CPM Ethernet through SCC1 or SCC2 */
+
+#ifdef CONFIG_SCC1_ENET /* Probably 860 variant */
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ * TCLK - CLK1, RCLK - CLK2.
+ */
+#define PA_ENET_RXD ((ushort)0x0001)
+#define PA_ENET_TXD ((ushort)0x0002)
+#define PA_ENET_TCLK ((ushort)0x0100)
+#define PA_ENET_RCLK ((ushort)0x0200)
+#define PB_ENET_TENA ((uint)0x00001000)
+#define PC_ENET_CLSN ((ushort)0x0010)
+#define PC_ENET_RENA ((ushort)0x0020)
+
+/* Control bits in the SICR to route TCLK (CLK1) and RCLK (CLK2) to
+ * SCC1. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x000000ff)
+#define SICR_ENET_CLKRT ((uint)0x0000002c)
+#endif /* CONFIG_SCC1_ENET */
+
+#ifdef CONFIG_SCC2_ENET /* Probably 823/850 variant */
+/* Bits in parallel I/O port registers that have to be set/cleared
+ * to configure the pins for SCC1 use.
+ * TCLK - CLK1, RCLK - CLK2.
+ */
+#define PA_ENET_RXD ((ushort)0x0004)
+#define PA_ENET_TXD ((ushort)0x0008)
+#define PA_ENET_TCLK ((ushort)0x0400)
+#define PA_ENET_RCLK ((ushort)0x0200)
+#define PB_ENET_TENA ((uint)0x00002000)
+#define PC_ENET_CLSN ((ushort)0x0040)
+#define PC_ENET_RENA ((ushort)0x0080)
+
+/* Control bits in the SICR to route TCLK and RCLK to
+ * SCC2. Also, make sure GR1 (bit 24) and SC1 (bit 25) are zero.
+ */
+#define SICR_ENET_MASK ((uint)0x0000ff00)
+#define SICR_ENET_CLKRT ((uint)0x00002e00)
+#endif /* CONFIG_SCC2_ENET */
+
#endif /* __ASM_FADS_H__ */
#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/katana.c b/arch/ppc/platforms/katana.c
index eda922ac3167..169dbf6534b9 100644
--- a/arch/ppc/platforms/katana.c
+++ b/arch/ppc/platforms/katana.c
@@ -27,12 +27,12 @@
#include <linux/root_dev.h>
#include <linux/delay.h>
#include <linux/seq_file.h>
-#include <linux/bootmem.h>
#include <linux/mtd/physmap.h>
#include <linux/mv643xx.h>
#ifdef CONFIG_BOOTIMG
#include <linux/bootimg.h>
#endif
+#include <asm/io.h>
#include <asm/page.h>
#include <asm/time.h>
#include <asm/smp.h>
diff --git a/arch/ppc/platforms/mpc885ads.h b/arch/ppc/platforms/mpc885ads.h
new file mode 100644
index 000000000000..eb386635b0fd
--- /dev/null
+++ b/arch/ppc/platforms/mpc885ads.h
@@ -0,0 +1,92 @@
+/*
+ * A collection of structures, addresses, and values associated with
+ * the Freescale MPC885ADS board.
+ * Copied from the FADS stuff.
+ *
+ * Author: MontaVista Software, Inc.
+ * source@mvista.com
+ *
+ * 2005 (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_MPC885ADS_H__
+#define __ASM_MPC885ADS_H__
+
+#include <linux/config.h>
+
+#include <asm/ppcboot.h>
+
+/* U-Boot maps BCSR to 0xff080000 */
+#define BCSR_ADDR ((uint)0xff080000)
+#define BCSR_SIZE ((uint)32)
+#define BCSR0 ((uint)(BCSR_ADDR + 0x00))
+#define BCSR1 ((uint)(BCSR_ADDR + 0x04))
+#define BCSR2 ((uint)(BCSR_ADDR + 0x08))
+#define BCSR3 ((uint)(BCSR_ADDR + 0x0c))
+#define BCSR4 ((uint)(BCSR_ADDR + 0x10))
+
+#define CFG_PHYDEV_ADDR ((uint)0xff0a0000)
+#define BCSR5 ((uint)(CFG_PHYDEV_ADDR + 0x300))
+
+#define IMAP_ADDR ((uint)0xff000000)
+#define IMAP_SIZE ((uint)(64 * 1024))
+
+#define PCMCIA_MEM_ADDR ((uint)0xff020000)
+#define PCMCIA_MEM_SIZE ((uint)(64 * 1024))
+
+/* Bits of interest in the BCSRs.
+ */
+#define BCSR1_ETHEN ((uint)0x20000000)
+#define BCSR1_IRDAEN ((uint)0x10000000)
+#define BCSR1_RS232EN_1 ((uint)0x01000000)
+#define BCSR1_PCCEN ((uint)0x00800000)
+#define BCSR1_PCCVCC0 ((uint)0x00400000)
+#define BCSR1_PCCVPP0 ((uint)0x00200000)
+#define BCSR1_PCCVPP1 ((uint)0x00100000)
+#define BCSR1_PCCVPP_MASK (BCSR1_PCCVPP0 | BCSR1_PCCVPP1)
+#define BCSR1_RS232EN_2 ((uint)0x00040000)
+#define BCSR1_PCCVCC1 ((uint)0x00010000)
+#define BCSR1_PCCVCC_MASK (BCSR1_PCCVCC0 | BCSR1_PCCVCC1)
+
+#define BCSR4_ETH10_RST ((uint)0x80000000) /* 10Base-T PHY reset*/
+#define BCSR4_USB_LO_SPD ((uint)0x04000000)
+#define BCSR4_USB_VCC ((uint)0x02000000)
+#define BCSR4_USB_FULL_SPD ((uint)0x00040000)
+#define BCSR4_USB_EN ((uint)0x00020000)
+
+#define BCSR5_MII2_EN 0x40
+#define BCSR5_MII2_RST 0x20
+#define BCSR5_T1_RST 0x10
+#define BCSR5_ATM155_RST 0x08
+#define BCSR5_ATM25_RST 0x04
+#define BCSR5_MII1_EN 0x02
+#define BCSR5_MII1_RST 0x01
+
+/* Interrupt level assignments */
+#define PHY_INTERRUPT SIU_IRQ7 /* PHY link change interrupt */
+#define SIU_INT_FEC1 SIU_LEVEL1 /* FEC1 interrupt */
+#define SIU_INT_FEC2 SIU_LEVEL3 /* FEC2 interrupt */
+#define FEC_INTERRUPT SIU_INT_FEC1 /* FEC interrupt */
+
+/* We don't use the 8259 */
+#define NR_8259_INTS 0
+
+/* CPM Ethernet through SCC3 */
+#define PA_ENET_RXD ((ushort)0x0040)
+#define PA_ENET_TXD ((ushort)0x0080)
+#define PE_ENET_TCLK ((uint)0x00004000)
+#define PE_ENET_RCLK ((uint)0x00008000)
+#define PE_ENET_TENA ((uint)0x00000010)
+#define PC_ENET_CLSN ((ushort)0x0400)
+#define PC_ENET_RENA ((ushort)0x0800)
+
+/* Control bits in the SICR to route TCLK (CLK5) and RCLK (CLK6) to
+ * SCC3. Also, make sure GR3 (bit 8) and SC3 (bit 9) are zero */
+#define SICR_ENET_MASK ((uint)0x00ff0000)
+#define SICR_ENET_CLKRT ((uint)0x002c0000)
+
+#endif /* __ASM_MPC885ADS_H__ */
+#endif /* __KERNEL__ */
diff --git a/arch/ppc/platforms/pmac_cpufreq.c b/arch/ppc/platforms/pmac_cpufreq.c
index 5fdd4f607a40..c0605244edda 100644
--- a/arch/ppc/platforms/pmac_cpufreq.c
+++ b/arch/ppc/platforms/pmac_cpufreq.c
@@ -452,7 +452,7 @@ static u32 __pmac read_gpio(struct device_node *np)
return offset;
}
-static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, u32 state)
+static int __pmac pmac_cpufreq_suspend(struct cpufreq_policy *policy, pm_message_t pmsg)
{
/* Ok, this could be made a bit smarter, but let's be robust for now. We
* always force a speed change to high speed before sleep, to make sure
diff --git a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c
index f6ff51924061..719fb49fe2bc 100644
--- a/arch/ppc/platforms/pmac_pci.c
+++ b/arch/ppc/platforms/pmac_pci.c
@@ -17,7 +17,6 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
#include <asm/sections.h>
#include <asm/io.h>
diff --git a/arch/ppc/platforms/pmac_sleep.S b/arch/ppc/platforms/pmac_sleep.S
index f459ade1bd63..016a74649155 100644
--- a/arch/ppc/platforms/pmac_sleep.S
+++ b/arch/ppc/platforms/pmac_sleep.S
@@ -46,7 +46,7 @@
.section .text
.align 5
-#if defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ_PMAC)
+#if defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ_PMAC)
/* This gets called by via-pmu.c late during the sleep process.
* The PMU was already send the sleep command and will shut us down
@@ -382,7 +382,7 @@ turn_on_mmu:
isync
rfi
-#endif /* defined(CONFIG_PMAC_PBOOK) || defined(CONFIG_CPU_FREQ) */
+#endif /* defined(CONFIG_PM) || defined(CONFIG_CPU_FREQ) */
.section .data
.balign L1_CACHE_LINE_SIZE
diff --git a/arch/ppc/platforms/pmac_time.c b/arch/ppc/platforms/pmac_time.c
index de60ccc7db9f..778ce4fec368 100644
--- a/arch/ppc/platforms/pmac_time.c
+++ b/arch/ppc/platforms/pmac_time.c
@@ -206,7 +206,7 @@ via_calibrate_decr(void)
return 1;
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* Reset the time after a sleep.
*/
@@ -238,7 +238,7 @@ time_sleep_notify(struct pmu_sleep_notifier *self, int when)
static struct pmu_sleep_notifier time_sleep_notifier __pmacdata = {
time_sleep_notify, SLEEP_LEVEL_MISC,
};
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
/*
* Query the OF and get the decr frequency.
@@ -251,9 +251,9 @@ pmac_calibrate_decr(void)
struct device_node *cpu;
unsigned int freq, *fp;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
pmu_register_sleep_notifier(&time_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
/* We assume MacRISC2 machines have correct device-tree
* calibration. That's better since the VIA itself seems
diff --git a/arch/ppc/platforms/sandpoint.c b/arch/ppc/platforms/sandpoint.c
index 70e58f43f2b8..8b149c2fc54f 100644
--- a/arch/ppc/platforms/sandpoint.c
+++ b/arch/ppc/platforms/sandpoint.c
@@ -324,6 +324,7 @@ sandpoint_setup_arch(void)
pdata[1].irq = 0;
pdata[1].mapbase = 0;
}
+ }
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/syslib/cpm2_common.c b/arch/ppc/syslib/cpm2_common.c
index ea5e77080e8d..4c19a4ac7163 100644
--- a/arch/ppc/syslib/cpm2_common.c
+++ b/arch/ppc/syslib/cpm2_common.c
@@ -21,8 +21,8 @@
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
-#include <linux/bootmem.h>
#include <linux/module.h>
+#include <asm/io.h>
#include <asm/irq.h>
#include <asm/mpc8260.h>
#include <asm/page.h>
diff --git a/arch/ppc/syslib/indirect_pci.c b/arch/ppc/syslib/indirect_pci.c
index a5a752609e2c..e71488469704 100644
--- a/arch/ppc/syslib/indirect_pci.c
+++ b/arch/ppc/syslib/indirect_pci.c
@@ -14,7 +14,6 @@
#include <linux/delay.h>
#include <linux/string.h>
#include <linux/init.h>
-#include <linux/bootmem.h>
#include <asm/io.h>
#include <asm/prom.h>
diff --git a/arch/ppc/syslib/ipic.c b/arch/ppc/syslib/ipic.c
index 580ed658e872..8f01e0f1d847 100644
--- a/arch/ppc/syslib/ipic.c
+++ b/arch/ppc/syslib/ipic.c
@@ -79,7 +79,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 7,
},
[17] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_A,
.force = IPIC_SEFCR,
@@ -87,7 +87,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 5,
},
[18] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_A,
.force = IPIC_SEFCR,
@@ -95,7 +95,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 6,
},
[19] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_A,
.force = IPIC_SEFCR,
@@ -103,7 +103,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 7,
},
[20] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_B,
.force = IPIC_SEFCR,
@@ -111,7 +111,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 4,
},
[21] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_B,
.force = IPIC_SEFCR,
@@ -119,7 +119,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 5,
},
[22] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_B,
.force = IPIC_SEFCR,
@@ -127,7 +127,7 @@ static struct ipic_info ipic_info[] = {
.prio_mask = 6,
},
[23] = {
- .pend = IPIC_SIPNR_H,
+ .pend = IPIC_SEPNR,
.mask = IPIC_SEMSR,
.prio = IPIC_SMPRR_B,
.force = IPIC_SEFCR,
diff --git a/arch/ppc/syslib/mv64x60.c b/arch/ppc/syslib/mv64x60.c
index 7b241e7876bd..cc77177fa1c6 100644
--- a/arch/ppc/syslib/mv64x60.c
+++ b/arch/ppc/syslib/mv64x60.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/bootmem.h>
#include <linux/spinlock.h>
#include <linux/mv643xx.h>
diff --git a/arch/ppc/syslib/mv64x60_win.c b/arch/ppc/syslib/mv64x60_win.c
index b6f0f5dcf6ee..5b827e2bbe22 100644
--- a/arch/ppc/syslib/mv64x60_win.c
+++ b/arch/ppc/syslib/mv64x60_win.c
@@ -17,7 +17,6 @@
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/string.h>
-#include <linux/bootmem.h>
#include <linux/mv643xx.h>
#include <asm/byteorder.h>
diff --git a/arch/ppc/syslib/of_device.c b/arch/ppc/syslib/of_device.c
index 49c0e34e2d6b..1eb4f726ca9f 100644
--- a/arch/ppc/syslib/of_device.c
+++ b/arch/ppc/syslib/of_device.c
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <asm/errno.h>
#include <asm/of_device.h>
@@ -15,20 +16,20 @@
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
-const struct of_match * of_match_device(const struct of_match *matches,
+const struct of_device_id * of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
- while (matches->name || matches->type || matches->compatible) {
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
- if (matches->name && matches->name != OF_ANY_MATCH)
+ if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
- if (matches->type && matches->type != OF_ANY_MATCH)
+ if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
- if (matches->compatible && matches->compatible != OF_ANY_MATCH)
+ if (matches->compatible[0])
match &= device_is_compatible(dev->node,
matches->compatible);
if (match)
@@ -42,7 +43,7 @@ static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_match * matches = of_drv->match_table;
+ const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
@@ -75,7 +76,7 @@ static int of_device_probe(struct device *dev)
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
- const struct of_match *match;
+ const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
diff --git a/arch/ppc/syslib/open_pic.c b/arch/ppc/syslib/open_pic.c
index b45d8268bf93..ad39b86ca92c 100644
--- a/arch/ppc/syslib/open_pic.c
+++ b/arch/ppc/syslib/open_pic.c
@@ -370,8 +370,9 @@ void __init openpic_init(int offset)
/* Initialize IPI interrupts */
if ( ppc_md.progress ) ppc_md.progress("openpic: ipi",0x3bb);
for (i = 0; i < OPENPIC_NUM_IPI; i++) {
- /* Disabled, Priority 10..13 */
- openpic_initipi(i, 10+i, OPENPIC_VEC_IPI+i+offset);
+ /* Disabled, increased priorities 10..13 */
+ openpic_initipi(i, OPENPIC_PRIORITY_IPI_BASE+i,
+ OPENPIC_VEC_IPI+i+offset);
/* IPIs are per-CPU */
irq_desc[OPENPIC_VEC_IPI+i+offset].status |= IRQ_PER_CPU;
irq_desc[OPENPIC_VEC_IPI+i+offset].handler = &open_pic_ipi;
@@ -399,8 +400,9 @@ void __init openpic_init(int offset)
if (sense & IRQ_SENSE_MASK)
irq_desc[i+offset].status = IRQ_LEVEL;
- /* Enabled, Priority 8 */
- openpic_initirq(i, 8, i+offset, (sense & IRQ_POLARITY_MASK),
+ /* Enabled, Default priority */
+ openpic_initirq(i, OPENPIC_PRIORITY_DEFAULT, i+offset,
+ (sense & IRQ_POLARITY_MASK),
(sense & IRQ_SENSE_MASK));
/* Processor 0 */
openpic_mapirq(i, CPU_MASK_CPU0, CPU_MASK_NONE);
@@ -656,6 +658,18 @@ static void __init openpic_maptimer(u_int timer, cpumask_t cpumask)
}
/*
+ * Change the priority of an interrupt
+ */
+void __init
+openpic_set_irq_priority(u_int irq, u_int pri)
+{
+ check_arg_irq(irq);
+ openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
+ OPENPIC_PRIORITY_MASK,
+ pri << OPENPIC_PRIORITY_SHIFT);
+}
+
+/*
* Initalize the interrupt source which will generate an NMI.
* This raises the interrupt's priority from 8 to 9.
*
@@ -665,9 +679,7 @@ void __init
openpic_init_nmi_irq(u_int irq)
{
check_arg_irq(irq);
- openpic_safe_writefield(&ISR[irq - open_pic_irq_offset]->Vector_Priority,
- OPENPIC_PRIORITY_MASK,
- 9 << OPENPIC_PRIORITY_SHIFT);
+ openpic_set_irq_priority(irq, OPENPIC_PRIORITY_NMI);
}
/*
diff --git a/arch/ppc/syslib/ppc4xx_pic.c b/arch/ppc/syslib/ppc4xx_pic.c
index 05686fa73545..40086212b9c3 100644
--- a/arch/ppc/syslib/ppc4xx_pic.c
+++ b/arch/ppc/syslib/ppc4xx_pic.c
@@ -110,6 +110,10 @@ static int ppc4xx_pic_get_irq(struct pt_regs *regs)
static void __init ppc4xx_pic_impl_init(void)
{
+#if defined(CONFIG_440GX)
+ /* Disable 440GP compatibility mode if it was enabled in firmware */
+ SDR_WRITE(DCRN_SDR_MFR, SDR_READ(DCRN_SDR_MFR) & ~DCRN_SDR_MFR_PCM);
+#endif
/* Configure Base UIC */
mtdcr(DCRN_UIC_CR(UICB), 0);
mtdcr(DCRN_UIC_TR(UICB), 0);
diff --git a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig
index cb27068bfcd4..fdd8afba7152 100644
--- a/arch/ppc64/Kconfig
+++ b/arch/ppc64/Kconfig
@@ -142,6 +142,23 @@ config PPC_SPLPAR
processors, that is, which share physical processors between
two or more partitions.
+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on PPC_MULTIPLATFORM && EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
config IBMVIO
depends on PPC_PSERIES || PPC_ISERIES
bool
@@ -270,26 +287,7 @@ config SCHED_SMT
when dealing with POWER5 cpus at a cost of slightly increased
overhead in some places. If unsure say N here.
-config PREEMPT
- bool "Preemptible Kernel"
- help
- This option reduces the latency of the kernel when reacting to
- real-time or interactive events by allowing a low priority process to
- be preempted even if it is in kernel mode executing a system call.
-
- Say Y here if you are building a kernel for a desktop, embedded
- or real-time system. Say N if you are unsure.
-
-config PREEMPT_BKL
- bool "Preempt The Big Kernel Lock"
- depends on PREEMPT
- default y
- help
- This option reduces the latency of the kernel by making the
- big kernel lock preemptible.
-
- Say Y here if you are building a kernel for a desktop system.
- Say N if you are unsure.
+source "kernel/Kconfig.preempt"
config EEH
bool "PCI Extended Error Handling (EEH)" if EMBEDDED
@@ -431,6 +429,8 @@ config CMDLINE
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile
index d3e1d6af9203..683b2d43c15f 100644
--- a/arch/ppc64/boot/Makefile
+++ b/arch/ppc64/boot/Makefile
@@ -52,7 +52,7 @@ 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)))
-hostprogs-y := piggy addnote addRamDisk
+hostprogs-y := addnote addRamDisk
targets += zImage zImage.initrd imagesize.c \
$(patsubst $(obj)/%,%, $(call obj-sec, $(required) $(initrd))) \
$(patsubst $(obj)/%,%, $(call src-sec, $(required) $(initrd))) \
@@ -78,9 +78,6 @@ addsection = $(CROSS32OBJCOPY) $(1) \
quiet_cmd_addnote = ADDNOTE $@
cmd_addnote = $(CROSS32LD) $(BOOTLFLAGS) -o $@ $(obj-boot) && $(obj)/addnote $@
-quiet_cmd_piggy = PIGGY $@
- cmd_piggy = $(obj)/piggyback $(@:.o=) < $< | $(CROSS32AS) -o $@
-
$(call gz-sec, $(required)): $(obj)/kernel-%.gz: % FORCE
$(call if_changed,gzip)
diff --git a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c
index da12ea2ca464..199d9804f61c 100644
--- a/arch/ppc64/boot/main.c
+++ b/arch/ppc64/boot/main.c
@@ -17,7 +17,6 @@
extern void *finddevice(const char *);
extern int getprop(void *, const char *, void *, int);
-extern void printk(char *fmt, ...);
extern void printf(const char *fmt, ...);
extern int sprintf(char *buf, const char *fmt, ...);
void gunzip(void *, int, unsigned char *, int *);
@@ -147,10 +146,10 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
}
a1 = initrd.addr;
a2 = initrd.size;
- printf("initial ramdisk moving 0x%lx <- 0x%lx (%lx bytes)\n\r",
+ printf("initial ramdisk moving 0x%lx <- 0x%lx (0x%lx bytes)\n\r",
initrd.addr, (unsigned long)_initrd_start, initrd.size);
memmove((void *)initrd.addr, (void *)_initrd_start, initrd.size);
- printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
+ printf("initrd head: 0x%lx\n\r", *((unsigned long *)initrd.addr));
}
/* Eventually gunzip the kernel */
@@ -201,9 +200,6 @@ void start(unsigned long a1, unsigned long a2, void *promptr)
flush_cache((void *)vmlinux.addr, vmlinux.size);
- if (a1)
- printf("initrd head: 0x%lx\n\r", *((u32 *)initrd.addr));
-
kernel_entry = (kernel_entry_t)vmlinux.addr;
#ifdef DEBUG
printf( "kernel:\n\r"
diff --git a/arch/ppc64/boot/mknote.c b/arch/ppc64/boot/mknote.c
deleted file mode 100644
index 120cc1d89739..000000000000
--- a/arch/ppc64/boot/mknote.c
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) Cort Dougan 1999.
- *
- * 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.
- *
- * Generate a note section as per the CHRP specification.
- *
- */
-
-#include <stdio.h>
-
-#define PL(x) printf("%c%c%c%c", ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, (x)&0xff );
-
-int main(void)
-{
-/* header */
- /* namesz */
- PL(strlen("PowerPC")+1);
- /* descrsz */
- PL(6*4);
- /* type */
- PL(0x1275);
- /* name */
- printf("PowerPC"); printf("%c", 0);
-
-/* descriptor */
- /* real-mode */
- PL(0xffffffff);
- /* real-base */
- PL(0x00c00000);
- /* real-size */
- PL(0xffffffff);
- /* virt-base */
- PL(0xffffffff);
- /* virt-size */
- PL(0xffffffff);
- /* load-base */
- PL(0x4000);
- return 0;
-}
diff --git a/arch/ppc64/boot/piggyback.c b/arch/ppc64/boot/piggyback.c
deleted file mode 100644
index 235c7a87269c..000000000000
--- a/arch/ppc64/boot/piggyback.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2001 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.
- */
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-
-extern long ce_exec_config[];
-
-int main(int argc, char *argv[])
-{
- int i, cnt, pos, len;
- unsigned int cksum, val;
- unsigned char *lp;
- unsigned char buf[8192];
- char *varname;
- if (argc != 2)
- {
- fprintf(stderr, "usage: %s name <in-file >out-file\n",
- argv[0]);
- exit(1);
- }
-
- varname = strrchr(argv[1], '/');
- if (varname)
- varname++;
- else
- varname = argv[1];
-
- fprintf(stdout, "#\n");
- fprintf(stdout, "# Miscellaneous data structures:\n");
- fprintf(stdout, "# WARNING - this file is automatically generated!\n");
- fprintf(stdout, "#\n");
- fprintf(stdout, "\n");
- fprintf(stdout, "\t.data\n");
- fprintf(stdout, "\t.globl %s_data\n", varname);
- fprintf(stdout, "%s_data:\n", varname);
- pos = 0;
- cksum = 0;
- while ((len = read(0, buf, sizeof(buf))) > 0)
- {
- cnt = 0;
- lp = (unsigned char *)buf;
- len = (len + 3) & ~3; /* Round up to longwords */
- for (i = 0; i < len; i += 4)
- {
- if (cnt == 0)
- {
- fprintf(stdout, "\t.long\t");
- }
- fprintf(stdout, "0x%02X%02X%02X%02X", lp[0], lp[1], lp[2], lp[3]);
- val = *(unsigned long *)lp;
- cksum ^= val;
- lp += 4;
- if (++cnt == 4)
- {
- cnt = 0;
- fprintf(stdout, " # %x \n", pos+i-12);
- fflush(stdout);
- } else
- {
- fprintf(stdout, ",");
- }
- }
- if (cnt)
- {
- fprintf(stdout, "0\n");
- }
- pos += len;
- }
- fprintf(stdout, "\t.globl %s_len\n", varname);
- fprintf(stdout, "%s_len:\t.long\t0x%x\n", varname, pos);
- fflush(stdout);
- fclose(stdout);
- fprintf(stderr, "cksum = %x\n", cksum);
- exit(0);
-}
-
diff --git a/arch/ppc64/boot/prom.c b/arch/ppc64/boot/prom.c
index d5218b15824e..5e48b80ff5a0 100644
--- a/arch/ppc64/boot/prom.c
+++ b/arch/ppc64/boot/prom.c
@@ -40,7 +40,7 @@ void *finddevice(const char *name);
int getprop(void *phandle, const char *name, void *buf, int buflen);
void chrpboot(int a1, int a2, void *prom); /* in main.c */
-void printk(char *fmt, ...);
+int printf(char *fmt, ...);
/* there is no convenient header to get this from... -- paulus */
extern unsigned long strlen(const char *);
@@ -220,7 +220,7 @@ readchar(void)
case 1:
return ch;
case -1:
- printk("read(stdin) returned -1\r\n");
+ printf("read(stdin) returned -1\r\n");
return -1;
}
}
@@ -627,18 +627,6 @@ int sprintf(char * buf, const char *fmt, ...)
static char sprint_buf[1024];
-void
-printk(char *fmt, ...)
-{
- va_list args;
- int n;
-
- va_start(args, fmt);
- n = vsprintf(sprint_buf, fmt, args);
- va_end(args);
- write(stdout, sprint_buf, n);
-}
-
int
printf(char *fmt, ...)
{
diff --git a/arch/ppc64/kernel/ItLpQueue.c b/arch/ppc64/kernel/ItLpQueue.c
index cdea00d7707f..4231861288a3 100644
--- a/arch/ppc64/kernel/ItLpQueue.c
+++ b/arch/ppc64/kernel/ItLpQueue.c
@@ -1,7 +1,7 @@
/*
* ItLpQueue.c
* Copyright (C) 2001 Mike Corrigan 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
@@ -11,156 +11,252 @@
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/sched.h>
+#include <linux/bootmem.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
#include <asm/system.h>
#include <asm/paca.h>
#include <asm/iSeries/ItLpQueue.h>
#include <asm/iSeries/HvLpEvent.h>
#include <asm/iSeries/HvCallEvent.h>
-static __inline__ int set_inUse( struct ItLpQueue * lpQueue )
-{
- int t;
- u32 * inUseP = &(lpQueue->xInUseWord);
-
- __asm__ __volatile__("\n\
-1: lwarx %0,0,%2 \n\
- cmpwi 0,%0,0 \n\
- li %0,0 \n\
- bne- 2f \n\
- addi %0,%0,1 \n\
- stwcx. %0,0,%2 \n\
- bne- 1b \n\
-2: eieio"
- : "=&r" (t), "=m" (lpQueue->xInUseWord)
- : "r" (inUseP), "m" (lpQueue->xInUseWord)
- : "cc");
-
- return t;
-}
+/*
+ * The LpQueue is used to pass event data from the hypervisor to
+ * the partition. This is where I/O interrupt events are communicated.
+ *
+ * It is written to by the hypervisor so cannot end up in the BSS.
+ */
+struct hvlpevent_queue hvlpevent_queue __attribute__((__section__(".data")));
-static __inline__ void clear_inUse( struct ItLpQueue * lpQueue )
-{
- lpQueue->xInUseWord = 0;
-}
+DEFINE_PER_CPU(unsigned long[HvLpEvent_Type_NumTypes], hvlpevent_counts);
+
+static char *event_types[HvLpEvent_Type_NumTypes] = {
+ "Hypervisor",
+ "Machine Facilities",
+ "Session Manager",
+ "SPD I/O",
+ "Virtual Bus",
+ "PCI I/O",
+ "RIO I/O",
+ "Virtual Lan",
+ "Virtual I/O"
+};
/* Array of LpEvent handler functions */
extern LpEventHandler lpEventHandler[HvLpEvent_Type_NumTypes];
-unsigned long ItLpQueueInProcess = 0;
-struct HvLpEvent * ItLpQueue_getNextLpEvent( struct ItLpQueue * lpQueue )
+static struct HvLpEvent * get_next_hvlpevent(void)
{
- struct HvLpEvent * nextLpEvent =
- (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
- if ( nextLpEvent->xFlags.xValid ) {
+ struct HvLpEvent * event;
+ event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+
+ if (event->xFlags.xValid) {
/* rmb() needed only for weakly consistent machines (regatta) */
rmb();
/* Set pointer to next potential event */
- lpQueue->xSlicCurEventPtr += ((nextLpEvent->xSizeMinus1 +
- LpEventAlign ) /
- LpEventAlign ) *
- LpEventAlign;
+ hvlpevent_queue.xSlicCurEventPtr += ((event->xSizeMinus1 +
+ LpEventAlign) / LpEventAlign) * LpEventAlign;
+
/* Wrap to beginning if no room at end */
- if (lpQueue->xSlicCurEventPtr > lpQueue->xSlicLastValidEventPtr)
- lpQueue->xSlicCurEventPtr = lpQueue->xSlicEventStackPtr;
+ if (hvlpevent_queue.xSlicCurEventPtr >
+ hvlpevent_queue.xSlicLastValidEventPtr) {
+ hvlpevent_queue.xSlicCurEventPtr =
+ hvlpevent_queue.xSlicEventStackPtr;
+ }
+ } else {
+ event = NULL;
}
- else
- nextLpEvent = NULL;
- return nextLpEvent;
+ return event;
}
-int ItLpQueue_isLpIntPending( struct ItLpQueue * lpQueue )
+static unsigned long spread_lpevents = NR_CPUS;
+
+int hvlpevent_is_pending(void)
{
- int retval = 0;
- struct HvLpEvent * nextLpEvent;
- if ( lpQueue ) {
- nextLpEvent = (struct HvLpEvent *)lpQueue->xSlicCurEventPtr;
- retval = nextLpEvent->xFlags.xValid | lpQueue->xPlicOverflowIntPending;
- }
- return retval;
+ struct HvLpEvent *next_event;
+
+ if (smp_processor_id() >= spread_lpevents)
+ return 0;
+
+ next_event = (struct HvLpEvent *)hvlpevent_queue.xSlicCurEventPtr;
+
+ return next_event->xFlags.xValid |
+ hvlpevent_queue.xPlicOverflowIntPending;
}
-void ItLpQueue_clearValid( struct HvLpEvent * event )
+static void hvlpevent_clear_valid(struct HvLpEvent * event)
{
- /* Clear the valid bit of the event
- * Also clear bits within this event that might
- * look like valid bits (on 64-byte boundaries)
- */
- unsigned extra = (( event->xSizeMinus1 + LpEventAlign ) /
- LpEventAlign ) - 1;
- switch ( extra ) {
- case 3:
- ((struct HvLpEvent*)((char*)event+3*LpEventAlign))->xFlags.xValid=0;
- case 2:
- ((struct HvLpEvent*)((char*)event+2*LpEventAlign))->xFlags.xValid=0;
- case 1:
- ((struct HvLpEvent*)((char*)event+1*LpEventAlign))->xFlags.xValid=0;
- case 0:
- ;
+ /* Tell the Hypervisor that we're done with this event.
+ * Also clear bits within this event that might look like valid bits.
+ * ie. on 64-byte boundaries.
+ */
+ struct HvLpEvent *tmp;
+ unsigned extra = ((event->xSizeMinus1 + LpEventAlign) /
+ LpEventAlign) - 1;
+
+ switch (extra) {
+ case 3:
+ tmp = (struct HvLpEvent*)((char*)event + 3 * LpEventAlign);
+ tmp->xFlags.xValid = 0;
+ case 2:
+ tmp = (struct HvLpEvent*)((char*)event + 2 * LpEventAlign);
+ tmp->xFlags.xValid = 0;
+ case 1:
+ tmp = (struct HvLpEvent*)((char*)event + 1 * LpEventAlign);
+ tmp->xFlags.xValid = 0;
}
+
mb();
+
event->xFlags.xValid = 0;
}
-unsigned ItLpQueue_process( struct ItLpQueue * lpQueue, struct pt_regs *regs )
+void process_hvlpevents(struct pt_regs *regs)
{
- unsigned numIntsProcessed = 0;
- struct HvLpEvent * nextLpEvent;
+ struct HvLpEvent * event;
/* If we have recursed, just return */
- if ( !set_inUse( lpQueue ) )
- return 0;
-
- if (ItLpQueueInProcess == 0)
- ItLpQueueInProcess = 1;
- else
- BUG();
+ if (!spin_trylock(&hvlpevent_queue.lock))
+ return;
for (;;) {
- nextLpEvent = ItLpQueue_getNextLpEvent( lpQueue );
- if ( nextLpEvent ) {
- /* Count events to return to caller
- * and count processed events in lpQueue
- */
- ++numIntsProcessed;
- lpQueue->xLpIntCount++;
- /* Call appropriate handler here, passing
+ event = get_next_hvlpevent();
+ if (event) {
+ /* Call appropriate handler here, passing
* a pointer to the LpEvent. The handler
* must make a copy of the LpEvent if it
* needs it in a bottom half. (perhaps for
* an ACK)
- *
- * Handlers are responsible for ACK processing
+ *
+ * Handlers are responsible for ACK processing
*
* The Hypervisor guarantees that LpEvents will
* only be delivered with types that we have
* registered for, so no type check is necessary
* here!
- */
- if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes )
- lpQueue->xLpIntCountByType[nextLpEvent->xType]++;
- if ( nextLpEvent->xType < HvLpEvent_Type_NumTypes &&
- lpEventHandler[nextLpEvent->xType] )
- lpEventHandler[nextLpEvent->xType](nextLpEvent, regs);
+ */
+ if (event->xType < HvLpEvent_Type_NumTypes)
+ __get_cpu_var(hvlpevent_counts)[event->xType]++;
+ if (event->xType < HvLpEvent_Type_NumTypes &&
+ lpEventHandler[event->xType])
+ lpEventHandler[event->xType](event, regs);
else
- printk(KERN_INFO "Unexpected Lp Event type=%d\n", nextLpEvent->xType );
-
- ItLpQueue_clearValid( nextLpEvent );
- } else if ( lpQueue->xPlicOverflowIntPending )
+ printk(KERN_INFO "Unexpected Lp Event type=%d\n", event->xType );
+
+ hvlpevent_clear_valid(event);
+ } else if (hvlpevent_queue.xPlicOverflowIntPending)
/*
* No more valid events. If overflow events are
* pending process them
*/
- HvCallEvent_getOverflowLpEvents( lpQueue->xIndex);
+ HvCallEvent_getOverflowLpEvents(hvlpevent_queue.xIndex);
else
break;
}
- ItLpQueueInProcess = 0;
- mb();
- clear_inUse( lpQueue );
+ spin_unlock(&hvlpevent_queue.lock);
+}
+
+static int set_spread_lpevents(char *str)
+{
+ unsigned long val = simple_strtoul(str, NULL, 0);
+
+ /*
+ * The parameter is the number of processors to share in processing
+ * lp events.
+ */
+ if (( val > 0) && (val <= NR_CPUS)) {
+ spread_lpevents = val;
+ printk("lpevent processing spread over %ld processors\n", val);
+ } else {
+ printk("invalid spread_lpevents %ld\n", val);
+ }
- get_paca()->lpevent_count += numIntsProcessed;
+ return 1;
+}
+__setup("spread_lpevents=", set_spread_lpevents);
+
+void setup_hvlpevent_queue(void)
+{
+ void *eventStack;
+
+ /*
+ * Allocate a page for the Event Stack. The Hypervisor needs the
+ * absolute real address, so we subtract out the KERNELBASE and add
+ * in the absolute real address of the kernel load area.
+ */
+ eventStack = alloc_bootmem_pages(LpEventStackSize);
+ memset(eventStack, 0, LpEventStackSize);
+
+ /* Invoke the hypervisor to initialize the event stack */
+ HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
+
+ hvlpevent_queue.xSlicEventStackPtr = (char *)eventStack;
+ hvlpevent_queue.xSlicCurEventPtr = (char *)eventStack;
+ hvlpevent_queue.xSlicLastValidEventPtr = (char *)eventStack +
+ (LpEventStackSize - LpEventMaxSize);
+ hvlpevent_queue.xIndex = 0;
+}
+
+static int proc_lpevents_show(struct seq_file *m, void *v)
+{
+ int cpu, i;
+ unsigned long sum;
+ static unsigned long cpu_totals[NR_CPUS];
+
+ /* FIXME: do we care that there's no locking here? */
+ sum = 0;
+ for_each_online_cpu(cpu) {
+ cpu_totals[cpu] = 0;
+ for (i = 0; i < HvLpEvent_Type_NumTypes; i++) {
+ cpu_totals[cpu] += per_cpu(hvlpevent_counts, cpu)[i];
+ }
+ sum += cpu_totals[cpu];
+ }
+
+ seq_printf(m, "LpEventQueue 0\n");
+ seq_printf(m, " events processed:\t%lu\n", sum);
+
+ for (i = 0; i < HvLpEvent_Type_NumTypes; ++i) {
+ sum = 0;
+ for_each_online_cpu(cpu) {
+ sum += per_cpu(hvlpevent_counts, cpu)[i];
+ }
+
+ seq_printf(m, " %-20s %10lu\n", event_types[i], sum);
+ }
+
+ seq_printf(m, "\n events processed by processor:\n");
+
+ for_each_online_cpu(cpu) {
+ seq_printf(m, " CPU%02d %10lu\n", cpu, cpu_totals[cpu]);
+ }
+
+ return 0;
+}
+
+static int proc_lpevents_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_lpevents_show, NULL);
+}
- return numIntsProcessed;
+static struct file_operations proc_lpevents_operations = {
+ .open = proc_lpevents_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init proc_lpevents_init(void)
+{
+ struct proc_dir_entry *e;
+
+ e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
+ if (e)
+ e->proc_fops = &proc_lpevents_operations;
+
+ return 0;
}
+__initcall(proc_lpevents_init);
+
diff --git a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
index badc5a443614..6ffcf67dd507 100644
--- a/arch/ppc64/kernel/LparData.c
+++ b/arch/ppc64/kernel/LparData.c
@@ -28,13 +28,6 @@
#include <asm/iSeries/IoHriProcessorVpd.h>
#include <asm/iSeries/ItSpCommArea.h>
-/* The LpQueue is used to pass event data from the hypervisor to
- * the partition. This is where I/O interrupt events are communicated.
- */
-
-/* May be filled in by the hypervisor so cannot end up in the BSS */
-struct ItLpQueue xItLpQueue __attribute__((__section__(".data")));
-
/* The HvReleaseData is the root of the information shared between
* the hypervisor and Linux.
@@ -200,7 +193,7 @@ struct ItVpdAreas itVpdAreas = {
0,0,0, /* 13 - 15 */
sizeof(struct IoHriProcessorVpd),/* 16 length of Proc Vpd */
0,0,0,0,0,0, /* 17 - 22 */
- sizeof(struct ItLpQueue),/* 23 length of Lp Queue */
+ sizeof(struct hvlpevent_queue), /* 23 length of Lp Queue */
0,0 /* 24 - 25 */
},
.xSlicVpdAdrs = { /* VPD addresses */
@@ -218,7 +211,7 @@ struct ItVpdAreas itVpdAreas = {
0,0,0, /* 13 - 15 */
&xIoHriProcessorVpd, /* 16 Proc Vpd */
0,0,0,0,0,0, /* 17 - 22 */
- &xItLpQueue, /* 23 Lp Queue */
+ &hvlpevent_queue, /* 23 Lp Queue */
0,0
}
};
diff --git a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
index dffbfb7ac8d5..d9b2660ef221 100644
--- a/arch/ppc64/kernel/Makefile
+++ b/arch/ppc64/kernel/Makefile
@@ -36,6 +36,7 @@ obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
obj-$(CONFIG_PPC_BPA) += bpa_setup.o bpa_iommu.o bpa_nvram.o \
bpa_iic.o spider-pic.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o
obj-$(CONFIG_EEH) += eeh.o
obj-$(CONFIG_PROC_FS) += proc_ppc64.o
obj-$(CONFIG_RTAS_FLASH) += rtas_flash.o
diff --git a/arch/ppc64/kernel/cputable.c b/arch/ppc64/kernel/cputable.c
index 1d162c7c59df..8d4c46f6f0b6 100644
--- a/arch/ppc64/kernel/cputable.c
+++ b/arch/ppc64/kernel/cputable.c
@@ -49,160 +49,219 @@ extern void __setup_cpu_be(unsigned long offset, struct cpu_spec* spec);
#endif
struct cpu_spec cpu_specs[] = {
- { /* Power3 */
- 0xffff0000, 0x00400000, "POWER3 (630)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Power3+ */
- 0xffff0000, 0x00410000, "POWER3 (630+)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Northstar */
- 0xffff0000, 0x00330000, "RS64-II (northstar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Pulsar */
- 0xffff0000, 0x00340000, "RS64-III (pulsar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* I-star */
- 0xffff0000, 0x00360000, "RS64-III (icestar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* S-star */
- 0xffff0000, 0x00370000, "RS64-IV (sstar)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_IABR | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power3,
- COMMON_PPC64_FW
- },
- { /* Power4 */
- 0xffff0000, 0x00350000, "POWER4 (gp)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* Power4+ */
- 0xffff0000, 0x00380000, "POWER4+ (gq)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* PPC970 */
- 0xffff0000, 0x00390000, "PPC970",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_ppc970,
- COMMON_PPC64_FW
- },
- { /* PPC970FX */
- 0xffff0000, 0x003c0000, "PPC970FX",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_ppc970,
- COMMON_PPC64_FW
- },
- { /* Power5 */
- 0xffff0000, 0x003a0000, "POWER5 (gr)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
- CPU_FTR_MMCRA_SIHV,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* Power5 */
- 0xffff0000, 0x003b0000, "POWER5 (gs)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
- CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
- CPU_FTR_MMCRA_SIHV,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- },
- { /* BE DD1.x */
- 0xffff0000, 0x00700000, "Broadband Engine",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
- CPU_FTR_SMT,
- COMMON_USER_PPC64 | PPC_FEATURE_HAS_ALTIVEC_COMP,
- 128, 128,
- __setup_cpu_be,
- COMMON_PPC64_FW
- },
- { /* default match */
- 0x00000000, 0x00000000, "POWER4 (compatible)",
- CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
- CPU_FTR_PPCAS_ARCH_V2,
- COMMON_USER_PPC64,
- 128, 128,
- __setup_cpu_power4,
- COMMON_PPC64_FW
- }
+ { /* Power3 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00400000,
+ .cpu_name = "POWER3 (630)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power3+ */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00410000,
+ .cpu_name = "POWER3 (630+)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Northstar */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00330000,
+ .cpu_name = "RS64-II (northstar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Pulsar */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00340000,
+ .cpu_name = "RS64-III (pulsar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* I-star */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00360000,
+ .cpu_name = "RS64-III (icestar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* S-star */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00370000,
+ .cpu_name = "RS64-IV (sstar)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE | CPU_FTR_IABR |
+ CPU_FTR_PMC8 | CPU_FTR_MMCRA | CPU_FTR_CTRL,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power3,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power4 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00350000,
+ .cpu_name = "POWER4 (gp)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power4+ */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00380000,
+ .cpu_name = "POWER4+ (gq)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* PPC970 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00390000,
+ .cpu_name = "PPC970",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_ppc970,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* PPC970FX */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003c0000,
+ .cpu_name = "PPC970FX",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_CAN_NAP | CPU_FTR_PMC8 | CPU_FTR_MMCRA,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_ppc970,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power5 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003a0000,
+ .cpu_name = "POWER5 (gr)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+ CPU_FTR_MMCRA_SIHV,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* Power5 */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x003b0000,
+ .cpu_name = "POWER5 (gs)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_MMCRA | CPU_FTR_SMT |
+ CPU_FTR_COHERENT_ICACHE | CPU_FTR_LOCKLESS_TLBIE |
+ CPU_FTR_MMCRA_SIHV,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* BE DD1.x */
+ .pvr_mask = 0xffff0000,
+ .pvr_value = 0x00700000,
+ .cpu_name = "Broadband Engine",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_ALTIVEC_COMP |
+ CPU_FTR_SMT,
+ .cpu_user_features = COMMON_USER_PPC64 |
+ PPC_FEATURE_HAS_ALTIVEC_COMP,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_be,
+ .firmware_features = COMMON_PPC64_FW,
+ },
+ { /* default match */
+ .pvr_mask = 0x00000000,
+ .pvr_value = 0x00000000,
+ .cpu_name = "POWER4 (compatible)",
+ .cpu_features = CPU_FTR_SPLIT_ID_CACHE |
+ CPU_FTR_USE_TB | CPU_FTR_HPTE_TABLE |
+ CPU_FTR_PPCAS_ARCH_V2,
+ .cpu_user_features = COMMON_USER_PPC64,
+ .icache_bsize = 128,
+ .dcache_bsize = 128,
+ .cpu_setup = __setup_cpu_power4,
+ .firmware_features = COMMON_PPC64_FW,
+ }
};
firmware_feature_t firmware_features_table[FIRMWARE_MAX_FEATURES] = {
- {FW_FEATURE_PFT, "hcall-pft"},
- {FW_FEATURE_TCE, "hcall-tce"},
- {FW_FEATURE_SPRG0, "hcall-sprg0"},
- {FW_FEATURE_DABR, "hcall-dabr"},
- {FW_FEATURE_COPY, "hcall-copy"},
- {FW_FEATURE_ASR, "hcall-asr"},
- {FW_FEATURE_DEBUG, "hcall-debug"},
- {FW_FEATURE_PERF, "hcall-perf"},
- {FW_FEATURE_DUMP, "hcall-dump"},
- {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
- {FW_FEATURE_MIGRATE, "hcall-migrate"},
- {FW_FEATURE_PERFMON, "hcall-perfmon"},
- {FW_FEATURE_CRQ, "hcall-crq"},
- {FW_FEATURE_VIO, "hcall-vio"},
- {FW_FEATURE_RDMA, "hcall-rdma"},
- {FW_FEATURE_LLAN, "hcall-lLAN"},
- {FW_FEATURE_BULK, "hcall-bulk"},
- {FW_FEATURE_XDABR, "hcall-xdabr"},
- {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
- {FW_FEATURE_SPLPAR, "hcall-splpar"},
+ {FW_FEATURE_PFT, "hcall-pft"},
+ {FW_FEATURE_TCE, "hcall-tce"},
+ {FW_FEATURE_SPRG0, "hcall-sprg0"},
+ {FW_FEATURE_DABR, "hcall-dabr"},
+ {FW_FEATURE_COPY, "hcall-copy"},
+ {FW_FEATURE_ASR, "hcall-asr"},
+ {FW_FEATURE_DEBUG, "hcall-debug"},
+ {FW_FEATURE_PERF, "hcall-perf"},
+ {FW_FEATURE_DUMP, "hcall-dump"},
+ {FW_FEATURE_INTERRUPT, "hcall-interrupt"},
+ {FW_FEATURE_MIGRATE, "hcall-migrate"},
+ {FW_FEATURE_PERFMON, "hcall-perfmon"},
+ {FW_FEATURE_CRQ, "hcall-crq"},
+ {FW_FEATURE_VIO, "hcall-vio"},
+ {FW_FEATURE_RDMA, "hcall-rdma"},
+ {FW_FEATURE_LLAN, "hcall-lLAN"},
+ {FW_FEATURE_BULK, "hcall-bulk"},
+ {FW_FEATURE_XDABR, "hcall-xdabr"},
+ {FW_FEATURE_MULTITCE, "hcall-multi-tce"},
+ {FW_FEATURE_SPLPAR, "hcall-splpar"},
};
diff --git a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
index 02c8f4e3e4bc..93ebcac0d5a2 100644
--- a/arch/ppc64/kernel/head.S
+++ b/arch/ppc64/kernel/head.S
@@ -308,6 +308,7 @@ exception_marker:
label##_pSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, label##_common)
#define STD_EXCEPTION_ISERIES(n, label, area) \
@@ -315,6 +316,7 @@ label##_pSeries: \
label##_iSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(area); \
EXCEPTION_PROLOG_ISERIES_2; \
b label##_common
@@ -324,6 +326,7 @@ label##_iSeries: \
label##_iSeries: \
HMT_MEDIUM; \
mtspr SPRG1,r13; /* save r13 */ \
+ RUNLATCH_ON(r13); \
EXCEPTION_PROLOG_ISERIES_1(PACA_EXGEN); \
lbz r10,PACAPROCENABLED(r13); \
cmpwi 0,r10,0; \
@@ -393,6 +396,7 @@ __start_interrupts:
_machine_check_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
. = 0x300
@@ -419,6 +423,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_SLB)
data_access_slb_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13
+ RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13)
@@ -439,6 +444,7 @@ data_access_slb_pSeries:
instruction_access_slb_pSeries:
HMT_MEDIUM
mtspr SPRG1,r13
+ RUNLATCH_ON(r13)
mfspr r13,SPRG3 /* get paca address into r13 */
std r9,PACA_EXSLB+EX_R9(r13) /* save r9 - r12 */
std r10,PACA_EXSLB+EX_R10(r13)
@@ -464,6 +470,7 @@ instruction_access_slb_pSeries:
.globl system_call_pSeries
system_call_pSeries:
HMT_MEDIUM
+ RUNLATCH_ON(r9)
mr r9,r13
mfmsr r10
mfspr r13,SPRG3
@@ -707,11 +714,13 @@ fwnmi_data_area:
system_reset_fwnmi:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXGEN, system_reset_common)
.globl machine_check_fwnmi
machine_check_fwnmi:
HMT_MEDIUM
mtspr SPRG1,r13 /* save r13 */
+ RUNLATCH_ON(r13)
EXCEPTION_PROLOG_PSERIES(PACA_EXMC, machine_check_common)
/*
@@ -848,6 +857,7 @@ unrecov_fer:
.align 7
.globl data_access_common
data_access_common:
+ RUNLATCH_ON(r10) /* It wont fit in the 0x300 handler */
mfspr r10,DAR
std r10,PACA_EXGEN+EX_DAR(r13)
mfspr r10,DSISR
@@ -1194,7 +1204,7 @@ _GLOBAL(pSeries_secondary_smp_init)
bl .__restore_cpu_setup
/* Set up a paca value for this processor. Since we have the
- * physical cpu id in r3, we need to search the pacas to find
+ * physical cpu id in r24, we need to search the pacas to find
* which logical id maps to our physical one.
*/
LOADADDR(r13, paca) /* Get base vaddr of paca array */
@@ -1207,8 +1217,8 @@ _GLOBAL(pSeries_secondary_smp_init)
cmpwi r5,NR_CPUS
blt 1b
-99: HMT_LOW /* Couldn't find our CPU id */
- b 99b
+ mr r3,r24 /* not found, copy phys to r3 */
+ b .kexec_wait /* next kernel might do better */
2: mtspr SPRG3,r13 /* Save vaddr of paca in SPRG3 */
/* From now on, r24 is expected to be logica cpuid */
diff --git a/arch/ppc64/kernel/hvconsole.c b/arch/ppc64/kernel/hvconsole.c
index c72fb8ffe974..138e128a3886 100644
--- a/arch/ppc64/kernel/hvconsole.c
+++ b/arch/ppc64/kernel/hvconsole.c
@@ -27,7 +27,6 @@
#include <linux/module.h>
#include <asm/hvcall.h>
#include <asm/hvconsole.h>
-#include <asm/prom.h>
/**
* hvc_get_chars - retrieve characters from firmware for denoted vterm adatper
@@ -42,29 +41,14 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count)
unsigned long 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
- * after every \r. -- paulus
- */
- if (got > 0) {
- int i;
- for (i = 1; i < got; ++i) {
- if (buf[i] == 0 && buf[i-1] == '\r') {
- --got;
- if (i < got)
- memmove(&buf[i], &buf[i+1],
- got - i);
- }
- }
- }
+ (unsigned long *)buf, (unsigned long *)buf+1) == H_Success)
return got;
- }
return 0;
}
EXPORT_SYMBOL(hvc_get_chars);
+
/**
* hvc_put_chars: send characters to firmware for denoted vterm adapter
* @vtermno: The vtermno or unit_address of the adapter from which the data
@@ -88,34 +72,3 @@ int hvc_put_chars(uint32_t vtermno, const char *buf, int count)
}
EXPORT_SYMBOL(hvc_put_chars);
-
-/*
- * 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;
-
- 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;
-
- 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/iSeries_proc.c b/arch/ppc64/kernel/iSeries_proc.c
index 356bd9931fcc..0fe3116eba29 100644
--- a/arch/ppc64/kernel/iSeries_proc.c
+++ b/arch/ppc64/kernel/iSeries_proc.c
@@ -40,50 +40,6 @@ static int __init iseries_proc_create(void)
}
core_initcall(iseries_proc_create);
-static char *event_types[9] = {
- "Hypervisor\t\t",
- "Machine Facilities\t",
- "Session Manager\t",
- "SPD I/O\t\t",
- "Virtual Bus\t\t",
- "PCI I/O\t\t",
- "RIO I/O\t\t",
- "Virtual Lan\t\t",
- "Virtual I/O\t\t"
-};
-
-static int proc_lpevents_show(struct seq_file *m, void *v)
-{
- unsigned int i;
-
- seq_printf(m, "LpEventQueue 0\n");
- seq_printf(m, " events processed:\t%lu\n",
- (unsigned long)xItLpQueue.xLpIntCount);
-
- for (i = 0; i < 9; ++i)
- seq_printf(m, " %s %10lu\n", event_types[i],
- (unsigned long)xItLpQueue.xLpIntCountByType[i]);
-
- seq_printf(m, "\n events processed by processor:\n");
-
- for_each_online_cpu(i)
- seq_printf(m, " CPU%02d %10u\n", i, paca[i].lpevent_count);
-
- return 0;
-}
-
-static int proc_lpevents_open(struct inode *inode, struct file *file)
-{
- return single_open(file, proc_lpevents_show, NULL);
-}
-
-static struct file_operations proc_lpevents_operations = {
- .open = proc_lpevents_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static unsigned long startTitan = 0;
static unsigned long startTb = 0;
@@ -148,10 +104,6 @@ static int __init iseries_proc_init(void)
{
struct proc_dir_entry *e;
- e = create_proc_entry("iSeries/lpevents", S_IFREG|S_IRUGO, NULL);
- if (e)
- e->proc_fops = &proc_lpevents_operations;
-
e = create_proc_entry("iSeries/titanTod", S_IFREG|S_IRUGO, NULL);
if (e)
e->proc_fops = &proc_titantod_operations;
diff --git a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
index 86966ce76b58..077c82fc9f3a 100644
--- a/arch/ppc64/kernel/iSeries_setup.c
+++ b/arch/ppc64/kernel/iSeries_setup.c
@@ -24,7 +24,6 @@
#include <linux/smp.h>
#include <linux/param.h>
#include <linux/string.h>
-#include <linux/bootmem.h>
#include <linux/initrd.h>
#include <linux/seq_file.h>
#include <linux/kdev_t.h>
@@ -676,7 +675,6 @@ static void __init iSeries_bolt_kernel(unsigned long saddr, unsigned long eaddr)
*/
static void __init iSeries_setup_arch(void)
{
- void *eventStack;
unsigned procIx = get_paca()->lppaca.dyn_hv_phys_proc_index;
/* Add an eye catcher and the systemcfg layout version number */
@@ -685,24 +683,7 @@ static void __init iSeries_setup_arch(void)
systemcfg->version.minor = SYSTEMCFG_MINOR;
/* Setup the Lp Event Queue */
-
- /* Allocate a page for the Event Stack
- * The hypervisor wants the absolute real address, so
- * we subtract out the KERNELBASE and add in the
- * absolute real address of the kernel load area
- */
- eventStack = alloc_bootmem_pages(LpEventStackSize);
- memset(eventStack, 0, LpEventStackSize);
-
- /* Invoke the hypervisor to initialize the event stack */
- HvCallEvent_setLpEventStack(0, eventStack, LpEventStackSize);
-
- /* Initialize fields in our Lp Event Queue */
- xItLpQueue.xSlicEventStackPtr = (char *)eventStack;
- xItLpQueue.xSlicCurEventPtr = (char *)eventStack;
- xItLpQueue.xSlicLastValidEventPtr = (char *)eventStack +
- (LpEventStackSize - LpEventMaxSize);
- xItLpQueue.xIndex = 0;
+ setup_hvlpevent_queue();
/* Compute processor frequency */
procFreqHz = ((1UL << 34) * 1000000) /
@@ -853,27 +834,91 @@ static int __init iSeries_src_init(void)
late_initcall(iSeries_src_init);
-static int set_spread_lpevents(char *str)
+static inline void process_iSeries_events(void)
{
- unsigned long i;
- unsigned long val = simple_strtoul(str, NULL, 0);
+ asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
+}
+
+static void yield_shared_processor(void)
+{
+ unsigned long tb;
+
+ HvCall_setEnabledInterrupts(HvCall_MaskIPI |
+ HvCall_MaskLpEvent |
+ HvCall_MaskLpProd |
+ HvCall_MaskTimeout);
+
+ tb = get_tb();
+ /* Compute future tb value when yield should expire */
+ HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
/*
- * The parameter is the number of processors to share in processing
- * lp events.
+ * The decrementer stops during the yield. Force a fake decrementer
+ * here and let the timer_interrupt code sort out the actual time.
*/
- if (( val > 0) && (val <= NR_CPUS)) {
- for (i = 1; i < val; ++i)
- paca[i].lpqueue_ptr = paca[0].lpqueue_ptr;
+ get_paca()->lppaca.int_dword.fields.decr_int = 1;
+ process_iSeries_events();
+}
- printk("lpevent processing spread over %ld processors\n", val);
- } else {
- printk("invalid spread_lpevents %ld\n", val);
+static int iseries_shared_idle(void)
+{
+ while (1) {
+ while (!need_resched() && !hvlpevent_is_pending()) {
+ local_irq_disable();
+ ppc64_runlatch_off();
+
+ /* Recheck with irqs off */
+ if (!need_resched() && !hvlpevent_is_pending())
+ yield_shared_processor();
+
+ HMT_medium();
+ local_irq_enable();
+ }
+
+ ppc64_runlatch_on();
+
+ if (hvlpevent_is_pending())
+ process_iSeries_events();
+
+ schedule();
+ }
+
+ return 0;
+}
+
+static int iseries_dedicated_idle(void)
+{
+ long oldval;
+
+ while (1) {
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+
+ if (!oldval) {
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ while (!need_resched()) {
+ ppc64_runlatch_off();
+ HMT_low();
+
+ if (hvlpevent_is_pending()) {
+ HMT_medium();
+ ppc64_runlatch_on();
+ process_iSeries_events();
+ }
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ } else {
+ set_need_resched();
+ }
+
+ ppc64_runlatch_on();
+ schedule();
}
- return 1;
+ return 0;
}
-__setup("spread_lpevents=", set_spread_lpevents);
#ifndef CONFIG_PCI
void __init iSeries_init_IRQ(void) { }
@@ -900,5 +945,13 @@ void __init iSeries_early_setup(void)
ppc_md.get_rtc_time = iSeries_get_rtc_time;
ppc_md.calibrate_decr = iSeries_calibrate_decr;
ppc_md.progress = iSeries_progress;
+
+ if (get_paca()->lppaca.shared_proc) {
+ ppc_md.idle_loop = iseries_shared_idle;
+ printk(KERN_INFO "Using shared processor idle loop\n");
+ } else {
+ ppc_md.idle_loop = iseries_dedicated_idle;
+ printk(KERN_INFO "Using dedicated idle loop\n");
+ }
}
diff --git a/arch/ppc64/kernel/idle.c b/arch/ppc64/kernel/idle.c
index bdf13b4dc1c8..954395d42636 100644
--- a/arch/ppc64/kernel/idle.c
+++ b/arch/ppc64/kernel/idle.c
@@ -20,109 +20,18 @@
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/cpu.h>
-#include <linux/module.h>
#include <linux/sysctl.h>
-#include <linux/smp.h>
#include <asm/system.h>
#include <asm/processor.h>
-#include <asm/mmu.h>
#include <asm/cputable.h>
#include <asm/time.h>
-#include <asm/iSeries/HvCall.h>
-#include <asm/iSeries/ItLpQueue.h>
-#include <asm/plpar_wrappers.h>
#include <asm/systemcfg.h>
+#include <asm/machdep.h>
extern void power4_idle(void);
-static int (*idle_loop)(void);
-
-#ifdef CONFIG_PPC_ISERIES
-static unsigned long maxYieldTime = 0;
-static unsigned long minYieldTime = 0xffffffffffffffffUL;
-
-static inline void process_iSeries_events(void)
-{
- asm volatile ("li 0,0x5555; sc" : : : "r0", "r3");
-}
-
-static void yield_shared_processor(void)
-{
- unsigned long tb;
- unsigned long yieldTime;
-
- HvCall_setEnabledInterrupts(HvCall_MaskIPI |
- HvCall_MaskLpEvent |
- HvCall_MaskLpProd |
- HvCall_MaskTimeout);
-
- tb = get_tb();
- /* Compute future tb value when yield should expire */
- HvCall_yieldProcessor(HvCall_YieldTimed, tb+tb_ticks_per_jiffy);
-
- yieldTime = get_tb() - tb;
- if (yieldTime > maxYieldTime)
- maxYieldTime = yieldTime;
-
- if (yieldTime < minYieldTime)
- minYieldTime = yieldTime;
-
- /*
- * The decrementer stops during the yield. Force a fake decrementer
- * here and let the timer_interrupt code sort out the actual time.
- */
- get_paca()->lppaca.int_dword.fields.decr_int = 1;
- process_iSeries_events();
-}
-
-static int iSeries_idle(void)
-{
- struct paca_struct *lpaca;
- long oldval;
-
- /* ensure iSeries run light will be out when idle */
- ppc64_runlatch_off();
-
- lpaca = get_paca();
-
- while (1) {
- if (lpaca->lppaca.shared_proc) {
- if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr))
- process_iSeries_events();
- if (!need_resched())
- yield_shared_processor();
- } else {
- oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
-
- if (!oldval) {
- set_thread_flag(TIF_POLLING_NRFLAG);
-
- while (!need_resched()) {
- HMT_medium();
- if (ItLpQueue_isLpIntPending(lpaca->lpqueue_ptr))
- process_iSeries_events();
- HMT_low();
- }
-
- HMT_medium();
- clear_thread_flag(TIF_POLLING_NRFLAG);
- } else {
- set_need_resched();
- }
- }
-
- ppc64_runlatch_on();
- schedule();
- ppc64_runlatch_off();
- }
-
- return 0;
-}
-
-#else
-
-static int default_idle(void)
+int default_idle(void)
{
long oldval;
unsigned int cpu = smp_processor_id();
@@ -134,7 +43,8 @@ static int default_idle(void)
set_thread_flag(TIF_POLLING_NRFLAG);
while (!need_resched() && !cpu_is_offline(cpu)) {
- barrier();
+ ppc64_runlatch_off();
+
/*
* Go into low thread priority and possibly
* low power mode.
@@ -149,6 +59,7 @@ static int default_idle(void)
set_need_resched();
}
+ ppc64_runlatch_on();
schedule();
if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
cpu_die();
@@ -157,127 +68,19 @@ static int default_idle(void)
return 0;
}
-#ifdef CONFIG_PPC_PSERIES
-
-DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
-
-int dedicated_idle(void)
+int native_idle(void)
{
- long oldval;
- 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[cpu ^ 1];
-
while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- lpaca->lppaca.idle = 1;
-
- oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
- if (!oldval) {
- set_thread_flag(TIF_POLLING_NRFLAG);
- start_snooze = __get_tb() +
- *smt_snooze_delay * tb_ticks_per_usec;
- 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)
- continue;
-
- HMT_medium();
-
- if (!(ppaca->lppaca.idle)) {
- local_irq_disable();
-
- /*
- * We are about to sleep the thread
- * and so wont be polling any
- * more.
- */
- clear_thread_flag(TIF_POLLING_NRFLAG);
-
- /*
- * 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,
- * an interrupt is presented, or a prod
- * occurs. Returning from the cede
- * enables external interrupts.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
- } else {
- /*
- * 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();
- }
-
- HMT_medium();
- lpaca->lppaca.idle = 0;
- schedule();
- if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
- cpu_die();
- }
- return 0;
-}
-
-static int shared_idle(void)
-{
- struct paca_struct *lpaca = get_paca();
- unsigned int cpu = smp_processor_id();
-
- while (1) {
- /*
- * Indicate to the HV that we are idle. Now would be
- * a good time to find other work to dispatch.
- */
- lpaca->lppaca.idle = 1;
+ ppc64_runlatch_off();
- while (!need_resched() && !cpu_is_offline(cpu)) {
- local_irq_disable();
+ if (!need_resched())
+ power4_idle();
- /*
- * 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
- * are enabled.
- *
- * Check need_resched() again with interrupts disabled
- * to avoid a race.
- */
- if (!need_resched())
- cede_processor();
- else
- local_irq_enable();
+ if (need_resched()) {
+ ppc64_runlatch_on();
+ schedule();
}
- HMT_medium();
- lpaca->lppaca.idle = 0;
- schedule();
if (cpu_is_offline(smp_processor_id()) &&
system_state == SYSTEM_RUNNING)
cpu_die();
@@ -286,29 +89,10 @@ static int shared_idle(void)
return 0;
}
-#endif /* CONFIG_PPC_PSERIES */
-
-static int native_idle(void)
-{
- while(1) {
- /* check CPU type here */
- if (!need_resched())
- power4_idle();
- if (need_resched())
- schedule();
-
- if (cpu_is_offline(raw_smp_processor_id()) &&
- system_state == SYSTEM_RUNNING)
- cpu_die();
- }
- return 0;
-}
-
-#endif /* CONFIG_PPC_ISERIES */
-
void cpu_idle(void)
{
- idle_loop();
+ BUG_ON(NULL == ppc_md.idle_loop);
+ ppc_md.idle_loop();
}
int powersave_nap;
@@ -342,42 +126,3 @@ register_powersave_nap_sysctl(void)
}
__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.shared_proc) {
- printk(KERN_INFO "Using shared processor idle loop\n");
- idle_loop = shared_idle;
- } else {
- printk(KERN_INFO "Using dedicated idle loop\n");
- idle_loop = dedicated_idle;
- }
- } else {
- printk(KERN_INFO "Using default idle loop\n");
- idle_loop = default_idle;
- }
- }
-#endif /* CONFIG_PPC_PSERIES */
-#ifndef CONFIG_PPC_ISERIES
- if (systemcfg->platform == PLATFORM_POWERMAC ||
- systemcfg->platform == PLATFORM_MAPLE) {
- printk(KERN_INFO "Using native/NAP idle loop\n");
- idle_loop = native_idle;
- }
-#endif /* CONFIG_PPC_ISERIES */
-
- return 1;
-}
diff --git a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
index 3defc8c33adf..f41afe545045 100644
--- a/arch/ppc64/kernel/irq.c
+++ b/arch/ppc64/kernel/irq.c
@@ -66,7 +66,6 @@ EXPORT_SYMBOL(irq_desc);
int distribute_irqs = 1;
int __irq_offset_value;
int ppc_spurious_interrupts;
-unsigned long lpevent_count;
u64 ppc64_interrupt_controller;
int show_interrupts(struct seq_file *p, void *v)
@@ -245,7 +244,7 @@ void ppc_irq_dispatch_handler(struct pt_regs *regs, int irq)
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ note_interrupt(irq, desc, action_ret, regs);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
@@ -269,7 +268,6 @@ out:
void do_IRQ(struct pt_regs *regs)
{
struct paca_struct *lpaca;
- struct ItLpQueue *lpq;
irq_enter();
@@ -295,9 +293,8 @@ void do_IRQ(struct pt_regs *regs)
iSeries_smp_message_recv(regs);
}
#endif /* CONFIG_SMP */
- lpq = lpaca->lpqueue_ptr;
- if (lpq && ItLpQueue_isLpIntPending(lpq))
- lpevent_count += ItLpQueue_process(lpq, regs);
+ if (hvlpevent_is_pending())
+ process_hvlpevents(regs);
irq_exit();
diff --git a/arch/ppc64/kernel/kprobes.c b/arch/ppc64/kernel/kprobes.c
index 782ce3efa2c1..a3d519518fb8 100644
--- a/arch/ppc64/kernel/kprobes.c
+++ b/arch/ppc64/kernel/kprobes.c
@@ -36,6 +36,8 @@
#include <asm/kdebug.h>
#include <asm/sstep.h>
+static DECLARE_MUTEX(kprobe_mutex);
+
static struct kprobe *current_kprobe;
static unsigned long kprobe_status, kprobe_saved_msr;
static struct kprobe *kprobe_prev;
@@ -54,6 +56,15 @@ int arch_prepare_kprobe(struct kprobe *p)
printk("Cannot register a kprobe on rfid or mtmsrd\n");
ret = -EINVAL;
}
+
+ /* insn must be on a special executable page on ppc64 */
+ if (!ret) {
+ up(&kprobe_mutex);
+ p->ainsn.insn = get_insn_slot();
+ down(&kprobe_mutex);
+ if (!p->ainsn.insn)
+ ret = -ENOMEM;
+ }
return ret;
}
@@ -79,16 +90,22 @@ void arch_disarm_kprobe(struct kprobe *p)
void arch_remove_kprobe(struct kprobe *p)
{
+ up(&kprobe_mutex);
+ free_insn_slot(p->ainsn.insn);
+ down(&kprobe_mutex);
}
static inline void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
{
+ kprobe_opcode_t insn = *p->ainsn.insn;
+
regs->msr |= MSR_SE;
- /*single step inline if it a breakpoint instruction*/
- if (p->opcode == BREAKPOINT_INSTRUCTION)
+
+ /* single step inline if it is a trap variant */
+ if (IS_TW(insn) || IS_TD(insn) || IS_TWI(insn) || IS_TDI(insn))
regs->nip = (unsigned long)p->addr;
else
- regs->nip = (unsigned long)&p->ainsn.insn;
+ regs->nip = (unsigned long)p->ainsn.insn;
}
static inline void save_previous_kprobe(void)
@@ -105,6 +122,23 @@ static inline void restore_previous_kprobe(void)
kprobe_saved_msr = kprobe_saved_msr_prev;
}
+void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri;
+
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
+ ri->ret_addr = (kprobe_opcode_t *)regs->link;
+
+ /* Replace the return addr with trampoline addr */
+ regs->link = (unsigned long)kretprobe_trampoline;
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
+}
+
static inline int kprobe_handler(struct pt_regs *regs)
{
struct kprobe *p;
@@ -195,6 +229,78 @@ no_kprobe:
}
/*
+ * Function return probe trampoline:
+ * - init_kprobes() establishes a probepoint here
+ * - When the probed function returns, this probe
+ * causes the handlers to fire
+ */
+void kretprobe_trampoline_holder(void)
+{
+ asm volatile(".global kretprobe_trampoline\n"
+ "kretprobe_trampoline:\n"
+ "nop\n");
+}
+
+/*
+ * Called when the probe at kretprobe trampoline is hit
+ */
+int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
+ unsigned long orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
+
+ head = kretprobe_inst_table_head(current);
+
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
+ recycle_rp_inst(ri);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
+ }
+
+ BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ regs->nip = orig_ret_address;
+
+ unlock_kprobes();
+
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we have handled unlocking
+ * and re-enabling preemption.
+ */
+ return 1;
+}
+
+/*
* 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
@@ -205,9 +311,10 @@ no_kprobe:
static void resume_execution(struct kprobe *p, struct pt_regs *regs)
{
int ret;
+ unsigned int insn = *p->ainsn.insn;
regs->nip = (unsigned long)p->addr;
- ret = emulate_step(regs, p->ainsn.insn[0]);
+ ret = emulate_step(regs, insn);
if (ret == 0)
regs->nip = (unsigned long)p->addr + 4;
}
@@ -331,3 +438,13 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
memcpy(regs, &jprobe_saved_regs, sizeof(struct pt_regs));
return 1;
}
+
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
+};
+
+int __init arch_init_kprobes(void)
+{
+ return register_kprobe(&trampoline_p);
+}
diff --git a/arch/ppc64/kernel/lparcfg.c b/arch/ppc64/kernel/lparcfg.c
index 387923fcf9b0..02e96627fa66 100644
--- a/arch/ppc64/kernel/lparcfg.c
+++ b/arch/ppc64/kernel/lparcfg.c
@@ -34,6 +34,7 @@
#include <asm/system.h>
#include <asm/time.h>
#include <asm/iSeries/ItExtVpdPanel.h>
+#include <asm/prom.h>
#define MODULE_VERS "1.6"
#define MODULE_NAME "lparcfg"
diff --git a/arch/ppc64/kernel/machine_kexec.c b/arch/ppc64/kernel/machine_kexec.c
new file mode 100644
index 000000000000..fdb2fc649d72
--- /dev/null
+++ b/arch/ppc64/kernel/machine_kexec.c
@@ -0,0 +1,302 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ *
+ * Copyright (C) 2004-2005, IBM Corp.
+ *
+ * Created by: Milton D Miller II
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+
+#include <linux/cpumask.h>
+#include <linux/kexec.h>
+#include <linux/smp.h>
+#include <linux/thread_info.h>
+#include <linux/errno.h>
+
+#include <asm/page.h>
+#include <asm/current.h>
+#include <asm/machdep.h>
+#include <asm/cacheflush.h>
+#include <asm/paca.h>
+#include <asm/mmu.h>
+#include <asm/sections.h> /* _end */
+#include <asm/prom.h>
+
+#define HASH_GROUP_SIZE 0x80 /* size of each hash group, asm/mmu.h */
+
+/* Have this around till we move it into crash specific file */
+note_buf_t crash_notes[NR_CPUS];
+
+/* Dummy for now. Not sure if we need to have a crash shutdown in here
+ * and if what it will achieve. Letting it be now to compile the code
+ * in generic kexec environment
+ */
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* do nothing right now */
+ /* smp_relase_cpus() if we want smp on panic kernel */
+ /* cpu_irq_down to isolate us until we are ready */
+}
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ int i;
+ unsigned long begin, end; /* limits of segment */
+ unsigned long low, high; /* limits of blocked memory range */
+ struct device_node *node;
+ unsigned long *basep;
+ unsigned int *sizep;
+
+ if (!ppc_md.hpte_clear_all)
+ return -ENOENT;
+
+ /*
+ * Since we use the kernel fault handlers and paging code to
+ * handle the virtual mode, we must make sure no destination
+ * overlaps kernel static data or bss.
+ */
+ for (i = 0; i < image->nr_segments; i++)
+ if (image->segment[i].mem < __pa(_end))
+ return -ETXTBSY;
+
+ /*
+ * For non-LPAR, we absolutely can not overwrite the mmu hash
+ * table, since we are still using the bolted entries in it to
+ * do the copy. Check that here.
+ *
+ * It is safe if the end is below the start of the blocked
+ * region (end <= low), or if the beginning is after the
+ * end of the blocked region (begin >= high). Use the
+ * boolean identity !(a || b) === (!a && !b).
+ */
+ if (htab_address) {
+ low = __pa(htab_address);
+ high = low + (htab_hash_mask + 1) * HASH_GROUP_SIZE;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ begin = image->segment[i].mem;
+ end = begin + image->segment[i].memsz;
+
+ if ((begin < high) && (end > low))
+ return -ETXTBSY;
+ }
+ }
+
+ /* We also should not overwrite the tce tables */
+ for (node = of_find_node_by_type(NULL, "pci"); node != NULL;
+ node = of_find_node_by_type(node, "pci")) {
+ basep = (unsigned long *)get_property(node, "linux,tce-base",
+ NULL);
+ sizep = (unsigned int *)get_property(node, "linux,tce-size",
+ NULL);
+ if (basep == NULL || sizep == NULL)
+ continue;
+
+ low = *basep;
+ high = low + (*sizep);
+
+ for (i = 0; i < image->nr_segments; i++) {
+ begin = image->segment[i].mem;
+ end = begin + image->segment[i].memsz;
+
+ if ((begin < high) && (end > low))
+ return -ETXTBSY;
+ }
+ }
+
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ /* we do nothing in prepare that needs to be undone */
+}
+
+#define IND_FLAGS (IND_DESTINATION | IND_INDIRECTION | IND_DONE | IND_SOURCE)
+
+static void copy_segments(unsigned long ind)
+{
+ unsigned long entry;
+ unsigned long *ptr;
+ void *dest;
+ void *addr;
+
+ /*
+ * We rely on kexec_load to create a lists that properly
+ * initializes these pointers before they are used.
+ * We will still crash if the list is wrong, but at least
+ * the compiler will be quiet.
+ */
+ ptr = NULL;
+ dest = NULL;
+
+ for (entry = ind; !(entry & IND_DONE); entry = *ptr++) {
+ addr = __va(entry & PAGE_MASK);
+
+ switch (entry & IND_FLAGS) {
+ case IND_DESTINATION:
+ dest = addr;
+ break;
+ case IND_INDIRECTION:
+ ptr = addr;
+ break;
+ case IND_SOURCE:
+ copy_page(dest, addr);
+ dest += PAGE_SIZE;
+ }
+ }
+}
+
+void kexec_copy_flush(struct kimage *image)
+{
+ long i, nr_segments = image->nr_segments;
+ struct kexec_segment ranges[KEXEC_SEGMENT_MAX];
+
+ /* save the ranges on the stack to efficiently flush the icache */
+ memcpy(ranges, image->segment, sizeof(ranges));
+
+ /*
+ * After this call we may not use anything allocated in dynamic
+ * memory, including *image.
+ *
+ * Only globals and the stack are allowed.
+ */
+ copy_segments(image->head);
+
+ /*
+ * we need to clear the icache for all dest pages sometime,
+ * including ones that were in place on the original copy
+ */
+ for (i = 0; i < nr_segments; i++)
+ flush_icache_range(ranges[i].mem + KERNELBASE,
+ ranges[i].mem + KERNELBASE +
+ ranges[i].memsz);
+}
+
+#ifdef CONFIG_SMP
+
+/* FIXME: we should schedule this function to be called on all cpus based
+ * on calling the interrupts, but we would like to call it off irq level
+ * so that the interrupt controller is clean.
+ */
+void kexec_smp_down(void *arg)
+{
+ if (ppc_md.cpu_irq_down)
+ ppc_md.cpu_irq_down();
+
+ local_irq_disable();
+ kexec_smp_wait();
+ /* NOTREACHED */
+}
+
+static void kexec_prepare_cpus(void)
+{
+ int my_cpu, i, notified=-1;
+
+ smp_call_function(kexec_smp_down, NULL, 0, /* wait */0);
+ my_cpu = get_cpu();
+
+ /* check the others cpus are now down (via paca hw cpu id == -1) */
+ for (i=0; i < NR_CPUS; i++) {
+ if (i == my_cpu)
+ continue;
+
+ while (paca[i].hw_cpu_id != -1) {
+ if (!cpu_possible(i)) {
+ printk("kexec: cpu %d hw_cpu_id %d is not"
+ " possible, ignoring\n",
+ i, paca[i].hw_cpu_id);
+ break;
+ }
+ if (!cpu_online(i)) {
+ /* Fixme: this can be spinning in
+ * pSeries_secondary_wait with a paca
+ * waiting for it to go online.
+ */
+ printk("kexec: cpu %d hw_cpu_id %d is not"
+ " online, ignoring\n",
+ i, paca[i].hw_cpu_id);
+ break;
+ }
+ if (i != notified) {
+ printk( "kexec: waiting for cpu %d (physical"
+ " %d) to go down\n",
+ i, paca[i].hw_cpu_id);
+ notified = i;
+ }
+ }
+ }
+
+ /* after we tell the others to go down */
+ if (ppc_md.cpu_irq_down)
+ ppc_md.cpu_irq_down();
+
+ put_cpu();
+
+ local_irq_disable();
+}
+
+#else /* ! SMP */
+
+static void kexec_prepare_cpus(void)
+{
+ /*
+ * move the secondarys to us so that we can copy
+ * the new kernel 0-0x100 safely
+ *
+ * do this if kexec in setup.c ?
+ */
+ smp_relase_cpus();
+ if (ppc_md.cpu_irq_down)
+ ppc_md.cpu_irq_down();
+ local_irq_disable();
+}
+
+#endif /* SMP */
+
+/*
+ * kexec thread structure and stack.
+ *
+ * We need to make sure that this is 16384-byte aligned due to the
+ * way process stacks are handled. It also must be statically allocated
+ * or allocated as part of the kimage, because everything else may be
+ * overwritten when we copy the kexec image. We piggyback on the
+ * "init_task" linker section here to statically allocate a stack.
+ *
+ * We could use a smaller stack if we don't care about anything using
+ * current, but that audit has not been performed.
+ */
+union thread_union kexec_stack
+ __attribute__((__section__(".data.init_task"))) = { };
+
+/* Our assembly helper, in kexec_stub.S */
+extern NORET_TYPE void kexec_sequence(void *newstack, unsigned long start,
+ void *image, void *control,
+ void (*clear_all)(void)) ATTRIB_NORET;
+
+/* too late to fail here */
+void machine_kexec(struct kimage *image)
+{
+
+ /* prepare control code if any */
+
+ /* shutdown other cpus into our wait loop and quiesce interrupts */
+ kexec_prepare_cpus();
+
+ /* switch to a staticly allocated stack. Based on irq stack code.
+ * XXX: the task struct will likely be invalid once we do the copy!
+ */
+ kexec_stack.thread_info.task = current_thread_info()->task;
+ kexec_stack.thread_info.flags = 0;
+
+ /* Some things are best done in assembly. Finding globals with
+ * a toc is easier in C, so pass in what we can.
+ */
+ kexec_sequence(&kexec_stack, image->start, image,
+ page_address(image->control_code_page),
+ ppc_md.hpte_clear_all);
+ /* NOTREACHED */
+}
diff --git a/arch/ppc64/kernel/maple_setup.c b/arch/ppc64/kernel/maple_setup.c
index da8900b51f40..bb55b5a56910 100644
--- a/arch/ppc64/kernel/maple_setup.c
+++ b/arch/ppc64/kernel/maple_setup.c
@@ -177,6 +177,8 @@ void __init maple_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
+
+ printk(KERN_INFO "Using native/NAP idle loop\n");
}
/*
@@ -297,4 +299,5 @@ struct machdep_calls __initdata maple_md = {
.get_rtc_time = maple_get_rtc_time,
.calibrate_decr = generic_calibrate_decr,
.progress = maple_progress,
+ .idle_loop = native_idle,
};
diff --git a/arch/ppc64/kernel/mf.c b/arch/ppc64/kernel/mf.c
index d98bebf7042f..ef4a338ebd01 100644
--- a/arch/ppc64/kernel/mf.c
+++ b/arch/ppc64/kernel/mf.c
@@ -801,10 +801,8 @@ int mf_get_boot_rtc(struct rtc_time *tm)
return rc;
/* We need to poll here as we are not yet taking interrupts */
while (rtc_data.busy) {
- extern unsigned long lpevent_count;
- struct ItLpQueue *lpq = get_paca()->lpqueue_ptr;
- if (lpq && ItLpQueue_isLpIntPending(lpq))
- lpevent_count += ItLpQueue_process(lpq, NULL);
+ if (hvlpevent_is_pending())
+ process_hvlpevents(NULL);
}
return rtc_set_tm(rtc_data.rc, rtc_data.ce_msg.ce_msg, tm);
}
diff --git a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
index e3c73b3425dc..59f4f9973818 100644
--- a/arch/ppc64/kernel/misc.S
+++ b/arch/ppc64/kernel/misc.S
@@ -680,6 +680,177 @@ _GLOBAL(kernel_thread)
ld r30,-16(r1)
blr
+/* kexec_wait(phys_cpu)
+ *
+ * wait for the flag to change, indicating this kernel is going away but
+ * the slave code for the next one is at addresses 0 to 100.
+ *
+ * This is used by all slaves.
+ *
+ * Physical (hardware) cpu id should be in r3.
+ */
+_GLOBAL(kexec_wait)
+ bl 1f
+1: mflr r5
+ addi r5,r5,kexec_flag-1b
+
+99: HMT_LOW
+#ifdef CONFIG_KEXEC /* use no memory without kexec */
+ lwz r4,0(r5)
+ cmpwi 0,r4,0
+ bnea 0x60
+#endif
+ b 99b
+
+/* this can be in text because we won't change it until we are
+ * running in real anyways
+ */
+kexec_flag:
+ .long 0
+
+
+#ifdef CONFIG_KEXEC
+
+/* kexec_smp_wait(void)
+ *
+ * call with interrupts off
+ * note: this is a terminal routine, it does not save lr
+ *
+ * get phys id from paca
+ * set paca id to -1 to say we got here
+ * switch to real mode
+ * join other cpus in kexec_wait(phys_id)
+ */
+_GLOBAL(kexec_smp_wait)
+ lhz r3,PACAHWCPUID(r13)
+ li r4,-1
+ sth r4,PACAHWCPUID(r13) /* let others know we left */
+ bl real_mode
+ b .kexec_wait
+
+/*
+ * switch to real mode (turn mmu off)
+ * we use the early kernel trick that the hardware ignores bits
+ * 0 and 1 (big endian) of the effective address in real mode
+ *
+ * don't overwrite r3 here, it is live for kexec_wait above.
+ */
+real_mode: /* assume normal blr return */
+1: li r9,MSR_RI
+ li r10,MSR_DR|MSR_IR
+ mflr r11 /* return address to SRR0 */
+ mfmsr r12
+ andc r9,r12,r9
+ andc r10,r12,r10
+
+ mtmsrd r9,1
+ mtspr SPRN_SRR1,r10
+ mtspr SPRN_SRR0,r11
+ rfid
+
+
+/*
+ * kexec_sequence(newstack, start, image, control, clear_all())
+ *
+ * does the grungy work with stack switching and real mode switches
+ * also does simple calls to other code
+ */
+
+_GLOBAL(kexec_sequence)
+ mflr r0
+ std r0,16(r1)
+
+ /* switch stacks to newstack -- &kexec_stack.stack */
+ stdu r1,THREAD_SIZE-112(r3)
+ mr r1,r3
+
+ li r0,0
+ std r0,16(r1)
+
+ /* save regs for local vars on new stack.
+ * yes, we won't go back, but ...
+ */
+ std r31,-8(r1)
+ std r30,-16(r1)
+ std r29,-24(r1)
+ std r28,-32(r1)
+ std r27,-40(r1)
+ std r26,-48(r1)
+ std r25,-56(r1)
+
+ stdu r1,-112-64(r1)
+
+ /* save args into preserved regs */
+ mr r31,r3 /* newstack (both) */
+ mr r30,r4 /* start (real) */
+ mr r29,r5 /* image (virt) */
+ mr r28,r6 /* control, unused */
+ mr r27,r7 /* clear_all() fn desc */
+ mr r26,r8 /* spare */
+ lhz r25,PACAHWCPUID(r13) /* get our phys cpu from paca */
+
+ /* disable interrupts, we are overwriting kernel data next */
+ mfmsr r3
+ rlwinm r3,r3,0,17,15
+ mtmsrd r3,1
+
+ /* copy dest pages, flush whole dest image */
+ mr r3,r29
+ bl .kexec_copy_flush /* (image) */
+
+ /* turn off mmu */
+ bl real_mode
+
+ /* clear out hardware hash page table and tlb */
+ ld r5,0(r27) /* deref function descriptor */
+ mtctr r5
+ bctrl /* ppc_md.hash_clear_all(void); */
+
+/*
+ * kexec image calling is:
+ * the first 0x100 bytes of the entry point are copied to 0
+ *
+ * all slaves branch to slave = 0x60 (absolute)
+ * slave(phys_cpu_id);
+ *
+ * master goes to start = entry point
+ * start(phys_cpu_id, start, 0);
+ *
+ *
+ * a wrapper is needed to call existing kernels, here is an approximate
+ * description of one method:
+ *
+ * v2: (2.6.10)
+ * start will be near the boot_block (maybe 0x100 bytes before it?)
+ * it will have a 0x60, which will b to boot_block, where it will wait
+ * and 0 will store phys into struct boot-block and load r3 from there,
+ * copy kernel 0-0x100 and tell slaves to back down to 0x60 again
+ *
+ * v1: (2.6.9)
+ * boot block will have all cpus scanning device tree to see if they
+ * are the boot cpu ?????
+ * other device tree differences (prop sizes, va vs pa, etc)...
+ */
+
+ /* copy 0x100 bytes starting at start to 0 */
+ li r3,0
+ mr r4,r30
+ li r5,0x100
+ li r6,0
+ bl .copy_and_flush /* (dest, src, copy limit, start offset) */
+1: /* assume normal blr return */
+
+ /* release other cpus to the new kernel secondary start at 0x60 */
+ mflr r5
+ li r6,1
+ stw r6,kexec_flag-1b(5)
+ mr r3,r25 # my phys cpu
+ mr r4,r30 # start, aka phys mem offset
+ mtlr 4
+ li r5,0
+ blr /* image->start(physid, image->start, 0); */
+#endif /* CONFIG_KEXEC */
+
/* Why isn't this a) automatic, b) written in 'C'? */
.balign 8
_GLOBAL(sys_call_table32)
@@ -951,11 +1122,13 @@ _GLOBAL(sys_call_table32)
.llong .compat_sys_mq_timedreceive /* 265 */
.llong .compat_sys_mq_notify
.llong .compat_sys_mq_getsetattr
- .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */
+ .llong .compat_sys_kexec_load
.llong .sys32_add_key
- .llong .sys32_request_key
+ .llong .sys32_request_key /* 270 */
.llong .compat_sys_keyctl
.llong .compat_sys_waitid
+ .llong .sys32_ioprio_set
+ .llong .sys32_ioprio_get
.balign 8
_GLOBAL(sys_call_table)
@@ -1227,8 +1400,10 @@ _GLOBAL(sys_call_table)
.llong .sys_mq_timedreceive /* 265 */
.llong .sys_mq_notify
.llong .sys_mq_getsetattr
- .llong .sys_ni_syscall /* 268 reserved for sys_kexec_load */
+ .llong .sys_kexec_load
.llong .sys_add_key
.llong .sys_request_key /* 270 */
.llong .sys_keyctl
.llong .sys_waitid
+ .llong .sys_ioprio_set
+ .llong .sys_ioprio_get
diff --git a/arch/ppc64/kernel/mpic.c b/arch/ppc64/kernel/mpic.c
index 593ea5b82afa..e8fbab1df37f 100644
--- a/arch/ppc64/kernel/mpic.c
+++ b/arch/ppc64/kernel/mpic.c
@@ -792,6 +792,35 @@ void mpic_setup_this_cpu(void)
#endif /* CONFIG_SMP */
}
+/*
+ * XXX: someone who knows mpic should check this.
+ * do we need to eoi the ipi here (see xics comments)?
+ * or can we reset the mpic in the new kernel?
+ */
+void mpic_teardown_this_cpu(void)
+{
+ struct mpic *mpic = mpic_primary;
+ unsigned long flags;
+ u32 msk = 1 << hard_smp_processor_id();
+ unsigned int i;
+
+ BUG_ON(mpic == NULL);
+
+ DBG("%s: teardown_this_cpu(%d)\n", mpic->name, hard_smp_processor_id());
+ spin_lock_irqsave(&mpic_lock, flags);
+
+ /* let the mpic know we don't want intrs. */
+ for (i = 0; i < mpic->num_sources ; i++)
+ mpic_irq_write(i, MPIC_IRQ_DESTINATION,
+ mpic_irq_read(i, MPIC_IRQ_DESTINATION) & ~msk);
+
+ /* Set current processor priority to max */
+ mpic_cpu_write(MPIC_CPU_CURRENT_TASK_PRI, 0xf);
+
+ spin_unlock_irqrestore(&mpic_lock, flags);
+}
+
+
void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask)
{
struct mpic *mpic = mpic_primary;
diff --git a/arch/ppc64/kernel/mpic.h b/arch/ppc64/kernel/mpic.h
index 63e177143eac..99fbbc9a084c 100644
--- a/arch/ppc64/kernel/mpic.h
+++ b/arch/ppc64/kernel/mpic.h
@@ -255,6 +255,9 @@ extern unsigned int mpic_irq_get_priority(unsigned int irq);
/* Setup a non-boot CPU */
extern void mpic_setup_this_cpu(void);
+/* Clean up for kexec (or cpu offline or ...) */
+extern void mpic_teardown_this_cpu(void);
+
/* Request IPIs on primary mpic */
extern void mpic_request_ipis(void);
diff --git a/arch/ppc64/kernel/nvram.c b/arch/ppc64/kernel/nvram.c
index 4e71781a4414..4fb1a9f5060d 100644
--- a/arch/ppc64/kernel/nvram.c
+++ b/arch/ppc64/kernel/nvram.c
@@ -338,9 +338,8 @@ static int nvram_remove_os_partition(void)
*/
static int nvram_create_os_partition(void)
{
- struct list_head * p;
- struct nvram_partition *part = NULL;
- struct nvram_partition *new_part = NULL;
+ struct nvram_partition *part;
+ struct nvram_partition *new_part;
struct nvram_partition *free_part = NULL;
int seq_init[2] = { 0, 0 };
loff_t tmp_index;
@@ -349,8 +348,7 @@ static int nvram_create_os_partition(void)
/* Find a free partition that will give us the maximum needed size
If can't find one that will give us the minimum size needed */
- list_for_each(p, &nvram_part->partition) {
- part = list_entry(p, struct nvram_partition, partition);
+ list_for_each_entry(part, &nvram_part->partition, partition) {
if (part->header.signature != NVRAM_SIG_FREE)
continue;
diff --git a/arch/ppc64/kernel/of_device.c b/arch/ppc64/kernel/of_device.c
index 66bd5ab7c25a..b80e81984ba8 100644
--- a/arch/ppc64/kernel/of_device.c
+++ b/arch/ppc64/kernel/of_device.c
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mod_devicetable.h>
#include <asm/errno.h>
#include <asm/of_device.h>
@@ -15,20 +16,20 @@
* Used by a driver to check whether an of_device present in the
* system is in its list of supported devices.
*/
-const struct of_match * of_match_device(const struct of_match *matches,
+const struct of_device_id *of_match_device(const struct of_device_id *matches,
const struct of_device *dev)
{
if (!dev->node)
return NULL;
- while (matches->name || matches->type || matches->compatible) {
+ while (matches->name[0] || matches->type[0] || matches->compatible[0]) {
int match = 1;
- if (matches->name && matches->name != OF_ANY_MATCH)
+ if (matches->name[0])
match &= dev->node->name
&& !strcmp(matches->name, dev->node->name);
- if (matches->type && matches->type != OF_ANY_MATCH)
+ if (matches->type[0])
match &= dev->node->type
&& !strcmp(matches->type, dev->node->type);
- if (matches->compatible && matches->compatible != OF_ANY_MATCH)
+ if (matches->compatible[0])
match &= device_is_compatible(dev->node,
matches->compatible);
if (match)
@@ -42,7 +43,7 @@ static int of_platform_bus_match(struct device *dev, struct device_driver *drv)
{
struct of_device * of_dev = to_of_device(dev);
struct of_platform_driver * of_drv = to_of_platform_driver(drv);
- const struct of_match * matches = of_drv->match_table;
+ const struct of_device_id * matches = of_drv->match_table;
if (!matches)
return 0;
@@ -75,7 +76,7 @@ static int of_device_probe(struct device *dev)
int error = -ENODEV;
struct of_platform_driver *drv;
struct of_device *of_dev;
- const struct of_match *match;
+ const struct of_device_id *match;
drv = to_of_platform_driver(dev->driver);
of_dev = to_of_device(dev);
diff --git a/arch/ppc64/kernel/pSeries_setup.c b/arch/ppc64/kernel/pSeries_setup.c
index f2b41243342c..5bec956e44a0 100644
--- a/arch/ppc64/kernel/pSeries_setup.c
+++ b/arch/ppc64/kernel/pSeries_setup.c
@@ -19,6 +19,7 @@
#undef DEBUG
#include <linux/config.h>
+#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -82,6 +83,9 @@ int fwnmi_active; /* TRUE if an FWNMI handler is present */
extern void pSeries_system_reset_exception(struct pt_regs *regs);
extern int pSeries_machine_check_exception(struct pt_regs *regs);
+static int pseries_shared_idle(void);
+static int pseries_dedicated_idle(void);
+
static volatile void __iomem * chrp_int_ack_special;
struct mpic *pSeries_mpic;
@@ -187,14 +191,16 @@ static void __init pSeries_setup_arch(void)
{
/* Fixup ppc_md depending on the type of interrupt controller */
if (ppc64_interrupt_controller == IC_OPEN_PIC) {
- ppc_md.init_IRQ = pSeries_init_mpic;
+ ppc_md.init_IRQ = pSeries_init_mpic;
ppc_md.get_irq = mpic_get_irq;
+ ppc_md.cpu_irq_down = mpic_teardown_this_cpu;
/* Allocate the mpic now, so that find_and_init_phbs() can
* fill the ISUs */
pSeries_setup_mpic();
} else {
ppc_md.init_IRQ = xics_init_IRQ;
ppc_md.get_irq = xics_get_irq;
+ ppc_md.cpu_irq_down = xics_teardown_cpu;
}
#ifdef CONFIG_SMP
@@ -227,6 +233,20 @@ static void __init pSeries_setup_arch(void)
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
vpa_init(boot_cpuid);
+
+ /* Choose an idle loop */
+ if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR) {
+ if (get_paca()->lppaca.shared_proc) {
+ printk(KERN_INFO "Using shared processor idle loop\n");
+ ppc_md.idle_loop = pseries_shared_idle;
+ } else {
+ printk(KERN_INFO "Using dedicated idle loop\n");
+ ppc_md.idle_loop = pseries_dedicated_idle;
+ }
+ } else {
+ printk(KERN_INFO "Using default idle loop\n");
+ ppc_md.idle_loop = default_idle;
+ }
}
static int __init pSeries_init_panel(void)
@@ -416,6 +436,144 @@ static int __init pSeries_probe(int platform)
return 1;
}
+DECLARE_PER_CPU(unsigned long, smt_snooze_delay);
+
+static inline void dedicated_idle_sleep(unsigned int cpu)
+{
+ struct paca_struct *ppaca = &paca[cpu ^ 1];
+
+ /* Only sleep if the other thread is not idle */
+ if (!(ppaca->lppaca.idle)) {
+ local_irq_disable();
+
+ /*
+ * We are about to sleep the thread and so wont be polling any
+ * more.
+ */
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+
+ /*
+ * 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, an interrupt is presented, or
+ * a prod occurs. Returning from the cede enables external
+ * interrupts.
+ */
+ if (!need_resched())
+ cede_processor();
+ else
+ local_irq_enable();
+ } else {
+ /*
+ * Give the HV an opportunity at the processor, since we are
+ * not doing any work.
+ */
+ poll_pending();
+ }
+}
+
+static int pseries_dedicated_idle(void)
+{
+ long oldval;
+ struct paca_struct *lpaca = get_paca();
+ unsigned int cpu = smp_processor_id();
+ unsigned long start_snooze;
+ unsigned long *smt_snooze_delay = &__get_cpu_var(smt_snooze_delay);
+
+ while (1) {
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ lpaca->lppaca.idle = 1;
+
+ oldval = test_and_clear_thread_flag(TIF_NEED_RESCHED);
+ if (!oldval) {
+ set_thread_flag(TIF_POLLING_NRFLAG);
+
+ start_snooze = __get_tb() +
+ *smt_snooze_delay * tb_ticks_per_usec;
+
+ while (!need_resched() && !cpu_is_offline(cpu)) {
+ ppc64_runlatch_off();
+
+ /*
+ * 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_medium();
+ dedicated_idle_sleep(cpu);
+ }
+
+ }
+
+ HMT_medium();
+ clear_thread_flag(TIF_POLLING_NRFLAG);
+ } else {
+ set_need_resched();
+ }
+
+ lpaca->lppaca.idle = 0;
+ ppc64_runlatch_on();
+
+ schedule();
+
+ if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+ cpu_die();
+ }
+}
+
+static int pseries_shared_idle(void)
+{
+ struct paca_struct *lpaca = get_paca();
+ unsigned int cpu = smp_processor_id();
+
+ while (1) {
+ /*
+ * Indicate to the HV that we are idle. Now would be
+ * a good time to find other work to dispatch.
+ */
+ lpaca->lppaca.idle = 1;
+
+ while (!need_resched() && !cpu_is_offline(cpu)) {
+ local_irq_disable();
+ ppc64_runlatch_off();
+
+ /*
+ * 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
+ * are enabled.
+ *
+ * Check need_resched() again with interrupts disabled
+ * to avoid a race.
+ */
+ if (!need_resched())
+ cede_processor();
+ else
+ local_irq_enable();
+
+ HMT_medium();
+ }
+
+ lpaca->lppaca.idle = 0;
+ ppc64_runlatch_on();
+
+ schedule();
+
+ if (cpu_is_offline(cpu) && system_state == SYSTEM_RUNNING)
+ cpu_die();
+ }
+
+ return 0;
+}
+
struct machdep_calls __initdata pSeries_md = {
.probe = pSeries_probe,
.setup_arch = pSeries_setup_arch,
diff --git a/arch/ppc64/kernel/pSeries_smp.c b/arch/ppc64/kernel/pSeries_smp.c
index 30154140f7e2..62c55a123560 100644
--- a/arch/ppc64/kernel/pSeries_smp.c
+++ b/arch/ppc64/kernel/pSeries_smp.c
@@ -93,10 +93,13 @@ static int query_cpu_stopped(unsigned int pcpu)
int pSeries_cpu_disable(void)
{
+ int cpu = smp_processor_id();
+
+ cpu_clear(cpu, cpu_online_map);
systemcfg->processorCount--;
/*fix boot_cpuid here*/
- if (smp_processor_id() == boot_cpuid)
+ if (cpu == boot_cpuid)
boot_cpuid = any_online_cpu(cpu_online_map);
/* FIXME: abstract this to not be platform specific later on */
diff --git a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
index a3e0975c26c1..6316188737b6 100644
--- a/arch/ppc64/kernel/pacaData.c
+++ b/arch/ppc64/kernel/pacaData.c
@@ -42,21 +42,7 @@ extern unsigned long __toc_start;
* processors. The processor VPD array needs one entry per physical
* processor (not thread).
*/
-#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) \
-{ \
+#define PACA_INIT_COMMON(number, start, asrr, asrv) \
.lock_token = 0x8000, \
.paca_index = (number), /* Paca Index */ \
.default_decr = 0x00ff0000, /* Initial Decr */ \
@@ -74,147 +60,79 @@ extern unsigned long __toc_start;
.end_of_quantum = 0xfffffffffffffffful, \
.slb_count = 64, \
}, \
- EXTRA_INITS((number), (lpq)) \
-}
-struct paca_struct paca[] = {
#ifdef CONFIG_PPC_ISERIES
- PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
+#define PACA_INIT_ISERIES(number) \
+ .lppaca_ptr = &paca[number].lppaca, \
+ .reg_save_ptr = &paca[number].reg_save, \
+ .reg_save = { \
+ .xDesc = 0xd397d9e2, /* "LpRS" */ \
+ .xSize = sizeof(struct ItLpRegSave) \
+ }
+
+#define PACA_INIT(number) \
+{ \
+ PACA_INIT_COMMON(number, 0, 0, 0) \
+ PACA_INIT_ISERIES(number) \
+}
+
+#define BOOTCPU_PACA_INIT(number) \
+{ \
+ PACA_INIT_COMMON(number, 1, 0, STAB0_VIRT_ADDR) \
+ PACA_INIT_ISERIES(number) \
+}
+
#else
- PACAINITDATA( 0, 1, NULL, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
+#define PACA_INIT(number) \
+{ \
+ PACA_INIT_COMMON(number, 0, 0, 0) \
+}
+
+#define BOOTCPU_PACA_INIT(number) \
+{ \
+ PACA_INIT_COMMON(number, 1, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR) \
+}
#endif
+
+struct paca_struct paca[] = {
+ BOOTCPU_PACA_INIT(0),
#if NR_CPUS > 1
- PACAINITDATA( 1, 0, NULL, 0, 0),
- PACAINITDATA( 2, 0, NULL, 0, 0),
- PACAINITDATA( 3, 0, NULL, 0, 0),
+ PACA_INIT( 1), PACA_INIT( 2), PACA_INIT( 3),
#if NR_CPUS > 4
- PACAINITDATA( 4, 0, NULL, 0, 0),
- PACAINITDATA( 5, 0, NULL, 0, 0),
- PACAINITDATA( 6, 0, NULL, 0, 0),
- PACAINITDATA( 7, 0, NULL, 0, 0),
+ PACA_INIT( 4), PACA_INIT( 5), PACA_INIT( 6), PACA_INIT( 7),
#if NR_CPUS > 8
- PACAINITDATA( 8, 0, NULL, 0, 0),
- PACAINITDATA( 9, 0, NULL, 0, 0),
- PACAINITDATA(10, 0, NULL, 0, 0),
- PACAINITDATA(11, 0, NULL, 0, 0),
- PACAINITDATA(12, 0, NULL, 0, 0),
- PACAINITDATA(13, 0, NULL, 0, 0),
- PACAINITDATA(14, 0, NULL, 0, 0),
- PACAINITDATA(15, 0, NULL, 0, 0),
- PACAINITDATA(16, 0, NULL, 0, 0),
- PACAINITDATA(17, 0, NULL, 0, 0),
- PACAINITDATA(18, 0, NULL, 0, 0),
- PACAINITDATA(19, 0, NULL, 0, 0),
- PACAINITDATA(20, 0, NULL, 0, 0),
- PACAINITDATA(21, 0, NULL, 0, 0),
- PACAINITDATA(22, 0, NULL, 0, 0),
- PACAINITDATA(23, 0, NULL, 0, 0),
- PACAINITDATA(24, 0, NULL, 0, 0),
- PACAINITDATA(25, 0, NULL, 0, 0),
- PACAINITDATA(26, 0, NULL, 0, 0),
- PACAINITDATA(27, 0, NULL, 0, 0),
- PACAINITDATA(28, 0, NULL, 0, 0),
- PACAINITDATA(29, 0, NULL, 0, 0),
- PACAINITDATA(30, 0, NULL, 0, 0),
- PACAINITDATA(31, 0, NULL, 0, 0),
+ PACA_INIT( 8), PACA_INIT( 9), PACA_INIT( 10), PACA_INIT( 11),
+ PACA_INIT( 12), PACA_INIT( 13), PACA_INIT( 14), PACA_INIT( 15),
+ PACA_INIT( 16), PACA_INIT( 17), PACA_INIT( 18), PACA_INIT( 19),
+ PACA_INIT( 20), PACA_INIT( 21), PACA_INIT( 22), PACA_INIT( 23),
+ PACA_INIT( 24), PACA_INIT( 25), PACA_INIT( 26), PACA_INIT( 27),
+ PACA_INIT( 28), PACA_INIT( 29), PACA_INIT( 30), PACA_INIT( 31),
#if NR_CPUS > 32
- PACAINITDATA(32, 0, NULL, 0, 0),
- PACAINITDATA(33, 0, NULL, 0, 0),
- PACAINITDATA(34, 0, NULL, 0, 0),
- PACAINITDATA(35, 0, NULL, 0, 0),
- PACAINITDATA(36, 0, NULL, 0, 0),
- PACAINITDATA(37, 0, NULL, 0, 0),
- PACAINITDATA(38, 0, NULL, 0, 0),
- PACAINITDATA(39, 0, NULL, 0, 0),
- PACAINITDATA(40, 0, NULL, 0, 0),
- PACAINITDATA(41, 0, NULL, 0, 0),
- PACAINITDATA(42, 0, NULL, 0, 0),
- PACAINITDATA(43, 0, NULL, 0, 0),
- PACAINITDATA(44, 0, NULL, 0, 0),
- PACAINITDATA(45, 0, NULL, 0, 0),
- PACAINITDATA(46, 0, NULL, 0, 0),
- PACAINITDATA(47, 0, NULL, 0, 0),
- PACAINITDATA(48, 0, NULL, 0, 0),
- PACAINITDATA(49, 0, NULL, 0, 0),
- PACAINITDATA(50, 0, NULL, 0, 0),
- PACAINITDATA(51, 0, NULL, 0, 0),
- PACAINITDATA(52, 0, NULL, 0, 0),
- PACAINITDATA(53, 0, NULL, 0, 0),
- PACAINITDATA(54, 0, NULL, 0, 0),
- PACAINITDATA(55, 0, NULL, 0, 0),
- PACAINITDATA(56, 0, NULL, 0, 0),
- PACAINITDATA(57, 0, NULL, 0, 0),
- PACAINITDATA(58, 0, NULL, 0, 0),
- PACAINITDATA(59, 0, NULL, 0, 0),
- PACAINITDATA(60, 0, NULL, 0, 0),
- PACAINITDATA(61, 0, NULL, 0, 0),
- PACAINITDATA(62, 0, NULL, 0, 0),
- PACAINITDATA(63, 0, NULL, 0, 0),
+ PACA_INIT( 32), PACA_INIT( 33), PACA_INIT( 34), PACA_INIT( 35),
+ PACA_INIT( 36), PACA_INIT( 37), PACA_INIT( 38), PACA_INIT( 39),
+ PACA_INIT( 40), PACA_INIT( 41), PACA_INIT( 42), PACA_INIT( 43),
+ PACA_INIT( 44), PACA_INIT( 45), PACA_INIT( 46), PACA_INIT( 47),
+ PACA_INIT( 48), PACA_INIT( 49), PACA_INIT( 50), PACA_INIT( 51),
+ PACA_INIT( 52), PACA_INIT( 53), PACA_INIT( 54), PACA_INIT( 55),
+ PACA_INIT( 56), PACA_INIT( 57), PACA_INIT( 58), PACA_INIT( 59),
+ PACA_INIT( 60), PACA_INIT( 61), PACA_INIT( 62), PACA_INIT( 63),
#if NR_CPUS > 64
- PACAINITDATA(64, 0, NULL, 0, 0),
- PACAINITDATA(65, 0, NULL, 0, 0),
- PACAINITDATA(66, 0, NULL, 0, 0),
- PACAINITDATA(67, 0, NULL, 0, 0),
- PACAINITDATA(68, 0, NULL, 0, 0),
- PACAINITDATA(69, 0, NULL, 0, 0),
- PACAINITDATA(70, 0, NULL, 0, 0),
- PACAINITDATA(71, 0, NULL, 0, 0),
- PACAINITDATA(72, 0, NULL, 0, 0),
- PACAINITDATA(73, 0, NULL, 0, 0),
- PACAINITDATA(74, 0, NULL, 0, 0),
- PACAINITDATA(75, 0, NULL, 0, 0),
- PACAINITDATA(76, 0, NULL, 0, 0),
- PACAINITDATA(77, 0, NULL, 0, 0),
- PACAINITDATA(78, 0, NULL, 0, 0),
- PACAINITDATA(79, 0, NULL, 0, 0),
- PACAINITDATA(80, 0, NULL, 0, 0),
- PACAINITDATA(81, 0, NULL, 0, 0),
- PACAINITDATA(82, 0, NULL, 0, 0),
- PACAINITDATA(83, 0, NULL, 0, 0),
- PACAINITDATA(84, 0, NULL, 0, 0),
- PACAINITDATA(85, 0, NULL, 0, 0),
- PACAINITDATA(86, 0, NULL, 0, 0),
- PACAINITDATA(87, 0, NULL, 0, 0),
- PACAINITDATA(88, 0, NULL, 0, 0),
- PACAINITDATA(89, 0, NULL, 0, 0),
- PACAINITDATA(90, 0, NULL, 0, 0),
- PACAINITDATA(91, 0, NULL, 0, 0),
- PACAINITDATA(92, 0, NULL, 0, 0),
- PACAINITDATA(93, 0, NULL, 0, 0),
- PACAINITDATA(94, 0, NULL, 0, 0),
- PACAINITDATA(95, 0, NULL, 0, 0),
- PACAINITDATA(96, 0, NULL, 0, 0),
- PACAINITDATA(97, 0, NULL, 0, 0),
- PACAINITDATA(98, 0, NULL, 0, 0),
- PACAINITDATA(99, 0, NULL, 0, 0),
- PACAINITDATA(100, 0, NULL, 0, 0),
- PACAINITDATA(101, 0, NULL, 0, 0),
- PACAINITDATA(102, 0, NULL, 0, 0),
- PACAINITDATA(103, 0, NULL, 0, 0),
- PACAINITDATA(104, 0, NULL, 0, 0),
- PACAINITDATA(105, 0, NULL, 0, 0),
- PACAINITDATA(106, 0, NULL, 0, 0),
- PACAINITDATA(107, 0, NULL, 0, 0),
- PACAINITDATA(108, 0, NULL, 0, 0),
- PACAINITDATA(109, 0, NULL, 0, 0),
- PACAINITDATA(110, 0, NULL, 0, 0),
- PACAINITDATA(111, 0, NULL, 0, 0),
- PACAINITDATA(112, 0, NULL, 0, 0),
- PACAINITDATA(113, 0, NULL, 0, 0),
- PACAINITDATA(114, 0, NULL, 0, 0),
- PACAINITDATA(115, 0, NULL, 0, 0),
- PACAINITDATA(116, 0, NULL, 0, 0),
- PACAINITDATA(117, 0, NULL, 0, 0),
- PACAINITDATA(118, 0, NULL, 0, 0),
- PACAINITDATA(119, 0, NULL, 0, 0),
- PACAINITDATA(120, 0, NULL, 0, 0),
- PACAINITDATA(121, 0, NULL, 0, 0),
- PACAINITDATA(122, 0, NULL, 0, 0),
- PACAINITDATA(123, 0, NULL, 0, 0),
- PACAINITDATA(124, 0, NULL, 0, 0),
- PACAINITDATA(125, 0, NULL, 0, 0),
- PACAINITDATA(126, 0, NULL, 0, 0),
- PACAINITDATA(127, 0, NULL, 0, 0),
+ PACA_INIT( 64), PACA_INIT( 65), PACA_INIT( 66), PACA_INIT( 67),
+ PACA_INIT( 68), PACA_INIT( 69), PACA_INIT( 70), PACA_INIT( 71),
+ PACA_INIT( 72), PACA_INIT( 73), PACA_INIT( 74), PACA_INIT( 75),
+ PACA_INIT( 76), PACA_INIT( 77), PACA_INIT( 78), PACA_INIT( 79),
+ PACA_INIT( 80), PACA_INIT( 81), PACA_INIT( 82), PACA_INIT( 83),
+ PACA_INIT( 84), PACA_INIT( 85), PACA_INIT( 86), PACA_INIT( 87),
+ PACA_INIT( 88), PACA_INIT( 89), PACA_INIT( 90), PACA_INIT( 91),
+ PACA_INIT( 92), PACA_INIT( 93), PACA_INIT( 94), PACA_INIT( 95),
+ PACA_INIT( 96), PACA_INIT( 97), PACA_INIT( 98), PACA_INIT( 99),
+ PACA_INIT(100), PACA_INIT(101), PACA_INIT(102), PACA_INIT(103),
+ PACA_INIT(104), PACA_INIT(105), PACA_INIT(106), PACA_INIT(107),
+ PACA_INIT(108), PACA_INIT(109), PACA_INIT(110), PACA_INIT(111),
+ PACA_INIT(112), PACA_INIT(113), PACA_INIT(114), PACA_INIT(115),
+ PACA_INIT(116), PACA_INIT(117), PACA_INIT(118), PACA_INIT(119),
+ PACA_INIT(120), PACA_INIT(121), PACA_INIT(122), PACA_INIT(123),
+ PACA_INIT(124), PACA_INIT(125), PACA_INIT(126), PACA_INIT(127),
#endif
#endif
#endif
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index 580676f87d23..ae6f579d3fa0 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
*offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM;
} else {
- io_offset = (unsigned long)hose->io_base_virt;
+ io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
*offset += io_offset;
res_bit = IORESOURCE_IO;
}
@@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* found it! construct the final physical address */
if (mmap_state == pci_mmap_io)
- *offset += hose->io_base_phys - io_offset;
+ *offset += hose->io_base_phys - io_offset;
return rp;
}
@@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
}
EXPORT_SYMBOL(pci_read_irq_line);
+void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ u64 *start, u64 *end)
+{
+ struct pci_controller *hose = pci_bus_to_host(dev->bus);
+ unsigned long offset = 0;
+
+ if (hose == NULL)
+ return;
+
+ if (rsrc->flags & IORESOURCE_IO)
+ offset = pci_io_base - (unsigned long)hose->io_base_virt +
+ hose->io_base_phys;
+
+ *start = rsrc->start + offset;
+ *end = rsrc->end + offset;
+}
+
#endif /* CONFIG_PPC_MULTIPLATFORM */
diff --git a/arch/ppc64/kernel/pmac_setup.c b/arch/ppc64/kernel/pmac_setup.c
index 6cf03d387b91..3013cdb5f933 100644
--- a/arch/ppc64/kernel/pmac_setup.c
+++ b/arch/ppc64/kernel/pmac_setup.c
@@ -186,6 +186,8 @@ void __init pmac_setup_arch(void)
#ifdef CONFIG_DUMMY_CONSOLE
conswitchp = &dummy_con;
#endif
+
+ printk(KERN_INFO "Using native/NAP idle loop\n");
}
#ifdef CONFIG_SCSI
@@ -507,5 +509,6 @@ struct machdep_calls __initdata pmac_md = {
.calibrate_decr = pmac_calibrate_decr,
.feature_call = pmac_do_feature_call,
.progress = pmac_progress,
- .check_legacy_ioport = pmac_check_legacy_ioport
+ .check_legacy_ioport = pmac_check_legacy_ioport,
+ .idle_loop = native_idle,
};
diff --git a/arch/ppc64/kernel/ppc_ksyms.c b/arch/ppc64/kernel/ppc_ksyms.c
index b230a63fe4c8..705742f4eec6 100644
--- a/arch/ppc64/kernel/ppc_ksyms.c
+++ b/arch/ppc64/kernel/ppc_ksyms.c
@@ -75,6 +75,7 @@ EXPORT_SYMBOL(giveup_fpu);
EXPORT_SYMBOL(giveup_altivec);
#endif
EXPORT_SYMBOL(__flush_icache_range);
+EXPORT_SYMBOL(flush_dcache_range);
#ifdef CONFIG_SMP
#ifdef CONFIG_PPC_ISERIES
diff --git a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
index aba89554d89d..f7cae05e40fb 100644
--- a/arch/ppc64/kernel/process.c
+++ b/arch/ppc64/kernel/process.c
@@ -36,6 +36,7 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
#include <linux/utsname.h>
+#include <linux/kprobes.h>
#include <asm/pgtable.h>
#include <asm/uaccess.h>
@@ -307,6 +308,8 @@ void show_regs(struct pt_regs * regs)
void exit_thread(void)
{
+ kprobe_flush_task(current);
+
#ifndef CONFIG_SMP
if (last_task_used_math == current)
last_task_used_math = NULL;
@@ -321,6 +324,7 @@ void flush_thread(void)
{
struct thread_info *t = current_thread_info();
+ kprobe_flush_task(current);
if (t->flags & _TIF_ABI_PENDING)
t->flags ^= (_TIF_ABI_PENDING | _TIF_32BIT);
diff --git a/arch/ppc64/kernel/ptrace.c b/arch/ppc64/kernel/ptrace.c
index 9f8c6087ae56..2993f108d96d 100644
--- a/arch/ppc64/kernel/ptrace.c
+++ b/arch/ppc64/kernel/ptrace.c
@@ -305,6 +305,8 @@ static void do_syscall_trace(void)
void do_syscall_trace_enter(struct pt_regs *regs)
{
+ secure_computing(regs->gpr[0]);
+
if (test_thread_flag(TIF_SYSCALL_TRACE)
&& (current->ptrace & PT_PTRACED))
do_syscall_trace();
@@ -320,8 +322,6 @@ void do_syscall_trace_enter(struct pt_regs *regs)
void do_syscall_trace_leave(struct pt_regs *regs)
{
- secure_computing(regs->gpr[0]);
-
if (unlikely(current->audit_context))
audit_syscall_exit(current,
(regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
diff --git a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
index 0a47a5ef428d..d1b33f0b26cb 100644
--- a/arch/ppc64/kernel/setup.c
+++ b/arch/ppc64/kernel/setup.c
@@ -96,7 +96,6 @@ extern void udbg_init_maple_realmode(void);
extern unsigned long klimit;
extern void mm_init_ppc64(void);
-extern int idle_setup(void);
extern void stab_initialize(unsigned long stab);
extern void htab_initialize(void);
extern void early_init_devtree(void *flat_dt);
@@ -677,11 +676,16 @@ void __init setup_system(void)
DBG(" <- setup_system()\n");
}
-
-void machine_restart(char *cmd)
+/* also used by kexec */
+void machine_shutdown(void)
{
if (ppc_md.nvram_sync)
ppc_md.nvram_sync();
+}
+
+void machine_restart(char *cmd)
+{
+ machine_shutdown();
ppc_md.restart(cmd);
#ifdef CONFIG_SMP
smp_send_stop();
@@ -690,13 +694,11 @@ void machine_restart(char *cmd)
local_irq_disable();
while (1) ;
}
-
EXPORT_SYMBOL(machine_restart);
-
+
void machine_power_off(void)
{
- if (ppc_md.nvram_sync)
- ppc_md.nvram_sync();
+ machine_shutdown();
ppc_md.power_off();
#ifdef CONFIG_SMP
smp_send_stop();
@@ -705,13 +707,11 @@ void machine_power_off(void)
local_irq_disable();
while (1) ;
}
-
EXPORT_SYMBOL(machine_power_off);
-
+
void machine_halt(void)
{
- if (ppc_md.nvram_sync)
- ppc_md.nvram_sync();
+ machine_shutdown();
ppc_md.halt();
#ifdef CONFIG_SMP
smp_send_stop();
@@ -720,7 +720,6 @@ void machine_halt(void)
local_irq_disable();
while (1) ;
}
-
EXPORT_SYMBOL(machine_halt);
static int ppc64_panic_event(struct notifier_block *this,
@@ -1081,8 +1080,11 @@ void __init setup_arch(char **cmdline_p)
ppc_md.setup_arch();
- /* Select the correct idle loop for the platform. */
- idle_setup();
+ /* Use the default idle loop if the platform hasn't provided one. */
+ if (NULL == ppc_md.idle_loop) {
+ ppc_md.idle_loop = default_idle;
+ printk(KERN_INFO "Using default idle loop\n");
+ }
paging_init();
ppc64_boot_msg(0x15, "Setup Done");
diff --git a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
index 118436e8085a..206619080e66 100644
--- a/arch/ppc64/kernel/sys_ppc32.c
+++ b/arch/ppc64/kernel/sys_ppc32.c
@@ -30,47 +30,26 @@
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
-#include <linux/slab.h>
-#include <linux/uio.h>
-#include <linux/aio.h>
-#include <linux/nfs_fs.h>
-#include <linux/module.h>
-#include <linux/sunrpc/svc.h>
-#include <linux/nfsd/nfsd.h>
-#include <linux/nfsd/cache.h>
-#include <linux/nfsd/xdr.h>
-#include <linux/nfsd/syscall.h>
#include <linux/poll.h>
#include <linux/personality.h>
#include <linux/stat.h>
-#include <linux/filter.h>
-#include <linux/highmem.h>
-#include <linux/highuid.h>
#include <linux/mman.h>
-#include <linux/ipv6.h>
#include <linux/in.h>
-#include <linux/icmpv6.h>
#include <linux/syscalls.h>
#include <linux/unistd.h>
#include <linux/sysctl.h>
#include <linux/binfmts.h>
-#include <linux/dnotify.h>
#include <linux/security.h>
#include <linux/compat.h>
#include <linux/ptrace.h>
-#include <linux/aio_abi.h>
#include <linux/elf.h>
-#include <net/scm.h>
-#include <net/sock.h>
-
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/ipc.h>
#include <asm/uaccess.h>
#include <asm/unistd.h>
#include <asm/semaphore.h>
-#include <asm/ppcdebug.h>
#include <asm/time.h>
#include <asm/mmu_context.h>
#include <asm/systemcfg.h>
@@ -350,8 +329,6 @@ asmlinkage long sys32_adjtimex(struct timex32 __user *utp)
return ret;
}
-
-/* These are here just in case some old sparc32 binary calls it. */
asmlinkage long sys32_pause(void)
{
current->state = TASK_INTERRUPTIBLE;
@@ -360,8 +337,6 @@ asmlinkage long sys32_pause(void)
return -ERESTARTNOHAND;
}
-
-
static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i)
{
long usec;
@@ -847,16 +822,6 @@ asmlinkage long sys32_getpgid(u32 pid)
}
-/* Note: it is necessary to treat which and who as unsigned ints,
- * with the corresponding cast to a signed int to insure that the
- * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
- * and the register representation of a signed int (msr in 64-bit mode) is performed.
- */
-asmlinkage long sys32_getpriority(u32 which, u32 who)
-{
- return sys_getpriority((int)which, (int)who);
-}
-
/* Note: it is necessary to treat pid as an unsigned int,
* with the corresponding cast to a signed int to insure that the
@@ -1048,6 +1013,11 @@ asmlinkage long sys32_setpgid(u32 pid, u32 pgid)
return sys_setpgid((int)pid, (int)pgid);
}
+long sys32_getpriority(u32 which, u32 who)
+{
+ /* sign extend which and who */
+ return sys_getpriority((int)which, (int)who);
+}
long sys32_setpriority(u32 which, u32 who, u32 niceval)
{
@@ -1055,6 +1025,18 @@ long sys32_setpriority(u32 which, u32 who, u32 niceval)
return sys_setpriority((int)which, (int)who, (int)niceval);
}
+long sys32_ioprio_get(u32 which, u32 who)
+{
+ /* sign extend which and who */
+ return sys_ioprio_get((int)which, (int)who);
+}
+
+long sys32_ioprio_set(u32 which, u32 who, u32 ioprio)
+{
+ /* sign extend which, who and ioprio */
+ return sys_ioprio_set((int)which, (int)who, (int)ioprio);
+}
+
/* Note: it is necessary to treat newmask as an unsigned int,
* with the corresponding cast to a signed int to insure that the
* proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
@@ -1273,8 +1255,6 @@ long ppc32_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low,
(u64)len_high << 32 | len_low, advice);
}
-extern asmlinkage long sys_timer_create(clockid_t, sigevent_t __user *, timer_t __user *);
-
long ppc32_timer_create(clockid_t clock,
struct compat_sigevent __user *ev32,
timer_t __user *timer_id)
diff --git a/arch/ppc64/kernel/sysfs.c b/arch/ppc64/kernel/sysfs.c
index c8fa6569b2fd..02b8ac4e0168 100644
--- a/arch/ppc64/kernel/sysfs.c
+++ b/arch/ppc64/kernel/sysfs.c
@@ -112,7 +112,6 @@ void ppc64_enable_pmcs(void)
unsigned long hid0;
#ifdef CONFIG_PPC_PSERIES
unsigned long set, reset;
- int ret;
#endif /* CONFIG_PPC_PSERIES */
/* Only need to enable them once */
@@ -145,11 +144,7 @@ void ppc64_enable_pmcs(void)
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);
+ plpar_hcall_norets(H_PERFMON, set, reset);
break;
#endif /* CONFIG_PPC_PSERIES */
@@ -161,13 +156,6 @@ void ppc64_enable_pmcs(void)
/* instruct hypervisor to maintain PMCs */
if (cur_cpu_spec->firmware_features & FW_FEATURE_SPLPAR)
get_paca()->lppaca.pmcregs_in_use = 1;
-
- /*
- * On SMT machines we have to set the run latch in the ctrl register
- * in order to make PMC6 spin.
- */
- if (cpu_has_feature(CPU_FTR_SMT))
- ppc64_runlatch_on();
#endif /* CONFIG_PPC_PSERIES */
}
@@ -400,7 +388,12 @@ static int __init topology_init(void)
struct cpu *c = &per_cpu(cpu_devices, cpu);
#ifdef CONFIG_NUMA
- parent = &node_devices[cpu_to_node(cpu)];
+ /* The node to which a cpu belongs can't be known
+ * until the cpu is made present.
+ */
+ parent = NULL;
+ if (cpu_present(cpu))
+ parent = &node_devices[cpu_to_node(cpu)];
#endif
/*
* For now, we just see if the system supports making
diff --git a/arch/ppc64/kernel/time.c b/arch/ppc64/kernel/time.c
index 2348a75e050d..909462e1adea 100644
--- a/arch/ppc64/kernel/time.c
+++ b/arch/ppc64/kernel/time.c
@@ -91,6 +91,7 @@ unsigned long tb_to_xs;
unsigned tb_to_us;
unsigned long processor_freq;
DEFINE_SPINLOCK(rtc_lock);
+EXPORT_SYMBOL_GPL(rtc_lock);
unsigned long tb_to_ns_scale;
unsigned long tb_to_ns_shift;
@@ -98,7 +99,6 @@ unsigned long tb_to_ns_shift;
struct gettimeofday_struct do_gtod;
extern unsigned long wall_jiffies;
-extern unsigned long lpevent_count;
extern int smp_tb_synchronized;
extern struct timezone sys_tz;
@@ -366,11 +366,8 @@ int timer_interrupt(struct pt_regs * regs)
set_dec(next_dec);
#ifdef CONFIG_PPC_ISERIES
- {
- struct ItLpQueue *lpq = lpaca->lpqueue_ptr;
- if (lpq && ItLpQueue_isLpIntPending(lpq))
- lpevent_count += ItLpQueue_process(lpq, regs);
- }
+ if (hvlpevent_is_pending())
+ process_hvlpevents(regs);
#endif
/* collect purr register values often, for accurate calculations */
diff --git a/arch/ppc64/kernel/vdso32/vdso32.lds.S b/arch/ppc64/kernel/vdso32/vdso32.lds.S
index 11290c902ba3..6f87a916a394 100644
--- a/arch/ppc64/kernel/vdso32/vdso32.lds.S
+++ b/arch/ppc64/kernel/vdso32/vdso32.lds.S
@@ -40,9 +40,9 @@ SECTIONS
.gcc_except_table : { *(.gcc_except_table) }
.fixup : { *(.fixup) }
- .got ALIGN(4) : { *(.got.plt) *(.got) }
-
.dynamic : { *(.dynamic) } :text :dynamic
+ .got : { *(.got) }
+ .plt : { *(.plt) }
_end = .;
__end = .;
diff --git a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
index 879f39b90a33..677c4450984a 100644
--- a/arch/ppc64/kernel/xics.c
+++ b/arch/ppc64/kernel/xics.c
@@ -647,6 +647,31 @@ static void xics_set_affinity(unsigned int virq, cpumask_t cpumask)
}
}
+void xics_teardown_cpu(void)
+{
+ int cpu = smp_processor_id();
+ int status;
+
+ ops->cppr_info(cpu, 0x00);
+ iosync();
+
+ /*
+ * we need to EOI the IPI if we got here from kexec down IPI
+ *
+ * xics doesn't care if we duplicate an EOI as long as we
+ * don't EOI and raise priority.
+ *
+ * probably need to check all the other interrupts too
+ * should we be flagging idle loop instead?
+ * or creating some task to be scheduled?
+ */
+ ops->xirr_info_set(cpu, XICS_IPI);
+
+ status = rtas_set_indicator(GLOBAL_INTERRUPT_QUEUE,
+ (1UL << interrupt_server_size) - 1 - default_distrib_server, 0);
+ WARN_ON(status != 0);
+}
+
#ifdef CONFIG_HOTPLUG_CPU
/* Interrupts are disabled. */
diff --git a/arch/ppc64/mm/hash_native.c b/arch/ppc64/mm/hash_native.c
index 52b6b9305341..4fec05817d66 100644
--- a/arch/ppc64/mm/hash_native.c
+++ b/arch/ppc64/mm/hash_native.c
@@ -304,6 +304,50 @@ static void native_hpte_invalidate(unsigned long slot, unsigned long va,
local_irq_restore(flags);
}
+/*
+ * clear all mappings on kexec. All cpus are in real mode (or they will
+ * be when they isi), and we are the only one left. We rely on our kernel
+ * mapping being 0xC0's and the hardware ignoring those two real bits.
+ *
+ * TODO: add batching support when enabled. remember, no dynamic memory here,
+ * athough there is the control page available...
+ */
+static void native_hpte_clear(void)
+{
+ unsigned long slot, slots, flags;
+ HPTE *hptep = htab_address;
+ Hpte_dword0 dw0;
+ unsigned long pteg_count;
+
+ pteg_count = htab_hash_mask + 1;
+
+ local_irq_save(flags);
+
+ /* we take the tlbie lock and hold it. Some hardware will
+ * deadlock if we try to tlbie from two processors at once.
+ */
+ spin_lock(&native_tlbie_lock);
+
+ slots = pteg_count * HPTES_PER_GROUP;
+
+ for (slot = 0; slot < slots; slot++, hptep++) {
+ /*
+ * we could lock the pte here, but we are the only cpu
+ * running, right? and for crash dump, we probably
+ * don't want to wait for a maybe bad cpu.
+ */
+ dw0 = hptep->dw0.dw0;
+
+ if (dw0.v) {
+ hptep->dw0.dword0 = 0;
+ tlbie(slot2va(dw0.avpn, dw0.l, dw0.h, slot), dw0.l);
+ }
+ }
+
+ spin_unlock(&native_tlbie_lock);
+ local_irq_restore(flags);
+}
+
static void native_flush_hash_range(unsigned long context,
unsigned long number, int local)
{
@@ -415,7 +459,8 @@ void hpte_init_native(void)
ppc_md.hpte_updatepp = native_hpte_updatepp;
ppc_md.hpte_updateboltedpp = native_hpte_updateboltedpp;
ppc_md.hpte_insert = native_hpte_insert;
- ppc_md.hpte_remove = native_hpte_remove;
+ ppc_md.hpte_remove = native_hpte_remove;
+ ppc_md.hpte_clear_all = native_hpte_clear;
if (tlb_batching_enabled())
ppc_md.flush_hash_range = native_flush_hash_range;
htab_finish_init();
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 32696c1d9280..477ac2758bd5 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -455,8 +455,18 @@ config NO_IDLE_HZ_INIT
The HZ timer is switched off in idle by default. That means the
HZ timer is already disabled at boot time.
+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but is independent of hardware/microcode support.
+
endmenu
+source "net/Kconfig"
+
config PCMCIA
bool
default n
@@ -467,7 +477,7 @@ source "drivers/scsi/Kconfig"
source "drivers/s390/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "fs/Kconfig"
diff --git a/arch/s390/defconfig b/arch/s390/defconfig
index 07fd0414a4bf..89850b2c27ea 100644
--- a/arch/s390/defconfig
+++ b/arch/s390/defconfig
@@ -245,6 +245,7 @@ CONFIG_S390_TAPE_BLOCK=y
#
CONFIG_S390_TAPE_34XX=m
# CONFIG_VMLOGRDR is not set
+# CONFIG_VMCP is not set
# CONFIG_MONREADER is not set
# CONFIG_DCSS_SHM is not set
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index b41e0e199a7c..ab1e49d2e518 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -25,6 +25,16 @@ obj-$(CONFIG_ARCH_S390X) += entry64.o reipl64.o
obj-$(CONFIG_VIRT_TIMER) += vtime.o
+# Kexec part
+S390_KEXEC_OBJS := machine_kexec.o crash.o
+ifeq ($(CONFIG_ARCH_S390X),y)
+S390_KEXEC_OBJS += relocate_kernel64.o
+else
+S390_KEXEC_OBJS += relocate_kernel.o
+endif
+obj-$(CONFIG_KEXEC) += $(S390_KEXEC_OBJS)
+
+
#
# This is just to get the dependencies...
#
diff --git a/arch/s390/kernel/compat_wrapper.S b/arch/s390/kernel/compat_wrapper.S
index 7a607b1d0380..bf529739c8ab 100644
--- a/arch/s390/kernel/compat_wrapper.S
+++ b/arch/s390/kernel/compat_wrapper.S
@@ -1441,3 +1441,11 @@ compat_sys_waitid_wrapper:
lgfr %r5,%r5 # int
llgtr %r6,%r6 # struct rusage_emu31 *
jg compat_sys_waitid
+
+ .globl compat_sys_kexec_load_wrapper
+compat_sys_kexec_load_wrapper:
+ llgfr %r2,%r2 # unsigned long
+ llgfr %r3,%r3 # unsigned long
+ llgtr %r4,%r4 # struct kexec_segment *
+ llgfr %r5,%r5 # unsigned long
+ jg compat_sys_kexec_load
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c
index 44df8dc07c59..20062145e84e 100644
--- a/arch/s390/kernel/cpcmd.c
+++ b/arch/s390/kernel/cpcmd.c
@@ -2,7 +2,7 @@
* arch/s390/kernel/cpcmd.c
*
* S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
+ * Copyright (C) 1999,2005 IBM Deutschland Entwicklung GmbH, IBM Corporation
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Christian Borntraeger (cborntra@de.ibm.com),
*/
@@ -18,93 +18,114 @@
#include <asm/system.h>
static DEFINE_SPINLOCK(cpcmd_lock);
-static char cpcmd_buf[240];
+static char cpcmd_buf[241];
/*
* the caller of __cpcmd has to ensure that the response buffer is below 2 GB
*/
-void __cpcmd(char *cmd, char *response, int rlen)
+int __cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{
const int mask = 0x40000000L;
unsigned long flags;
+ int return_code;
+ int return_len;
int cmdlen;
spin_lock_irqsave(&cpcmd_lock, flags);
cmdlen = strlen(cmd);
BUG_ON(cmdlen > 240);
- strcpy(cpcmd_buf, cmd);
+ memcpy(cpcmd_buf, cmd, cmdlen);
ASCEBC(cpcmd_buf, cmdlen);
if (response != NULL && rlen > 0) {
memset(response, 0, rlen);
#ifndef CONFIG_ARCH_S390X
- asm volatile ("LRA 2,0(%0)\n\t"
- "LR 4,%1\n\t"
- "O 4,%4\n\t"
- "LRA 3,0(%2)\n\t"
- "LR 5,%3\n\t"
- ".long 0x83240008 # Diagnose X'08'\n\t"
- : /* no output */
- : "a" (cpcmd_buf), "d" (cmdlen),
- "a" (response), "d" (rlen), "m" (mask)
- : "cc", "2", "3", "4", "5" );
+ asm volatile ( "lra 2,0(%2)\n"
+ "lr 4,%3\n"
+ "o 4,%6\n"
+ "lra 3,0(%4)\n"
+ "lr 5,%5\n"
+ "diag 2,4,0x8\n"
+ "brc 8, .Litfits\n"
+ "ar 5, %5\n"
+ ".Litfits: \n"
+ "lr %0,4\n"
+ "lr %1,5\n"
+ : "=d" (return_code), "=d" (return_len)
+ : "a" (cpcmd_buf), "d" (cmdlen),
+ "a" (response), "d" (rlen), "m" (mask)
+ : "cc", "2", "3", "4", "5" );
#else /* CONFIG_ARCH_S390X */
- asm volatile (" lrag 2,0(%0)\n"
- " lgr 4,%1\n"
- " o 4,%4\n"
- " lrag 3,0(%2)\n"
- " lgr 5,%3\n"
- " sam31\n"
- " .long 0x83240008 # Diagnose X'08'\n"
- " sam64"
- : /* no output */
- : "a" (cpcmd_buf), "d" (cmdlen),
- "a" (response), "d" (rlen), "m" (mask)
- : "cc", "2", "3", "4", "5" );
+ asm volatile ( "lrag 2,0(%2)\n"
+ "lgr 4,%3\n"
+ "o 4,%6\n"
+ "lrag 3,0(%4)\n"
+ "lgr 5,%5\n"
+ "sam31\n"
+ "diag 2,4,0x8\n"
+ "sam64\n"
+ "brc 8, .Litfits\n"
+ "agr 5, %5\n"
+ ".Litfits: \n"
+ "lgr %0,4\n"
+ "lgr %1,5\n"
+ : "=d" (return_code), "=d" (return_len)
+ : "a" (cpcmd_buf), "d" (cmdlen),
+ "a" (response), "d" (rlen), "m" (mask)
+ : "cc", "2", "3", "4", "5" );
#endif /* CONFIG_ARCH_S390X */
EBCASC(response, rlen);
} else {
+ return_len = 0;
#ifndef CONFIG_ARCH_S390X
- asm volatile ("LRA 2,0(%0)\n\t"
- "LR 3,%1\n\t"
- ".long 0x83230008 # Diagnose X'08'\n\t"
- : /* no output */
- : "a" (cpcmd_buf), "d" (cmdlen)
- : "2", "3" );
+ asm volatile ( "lra 2,0(%1)\n"
+ "lr 3,%2\n"
+ "diag 2,3,0x8\n"
+ "lr %0,3\n"
+ : "=d" (return_code)
+ : "a" (cpcmd_buf), "d" (cmdlen)
+ : "2", "3" );
#else /* CONFIG_ARCH_S390X */
- asm volatile (" lrag 2,0(%0)\n"
- " lgr 3,%1\n"
- " sam31\n"
- " .long 0x83230008 # Diagnose X'08'\n"
- " sam64"
- : /* no output */
- : "a" (cpcmd_buf), "d" (cmdlen)
- : "2", "3" );
+ asm volatile ( "lrag 2,0(%1)\n"
+ "lgr 3,%2\n"
+ "sam31\n"
+ "diag 2,3,0x8\n"
+ "sam64\n"
+ "lgr %0,3\n"
+ : "=d" (return_code)
+ : "a" (cpcmd_buf), "d" (cmdlen)
+ : "2", "3" );
#endif /* CONFIG_ARCH_S390X */
}
spin_unlock_irqrestore(&cpcmd_lock, flags);
+ if (response_code != NULL)
+ *response_code = return_code;
+ return return_len;
}
EXPORT_SYMBOL(__cpcmd);
#ifdef CONFIG_ARCH_S390X
-void cpcmd(char *cmd, char *response, int rlen)
+int cpcmd(const char *cmd, char *response, int rlen, int *response_code)
{
char *lowbuf;
+ int len;
+
if ((rlen == 0) || (response == NULL)
|| !((unsigned long)response >> 31))
- __cpcmd(cmd, response, rlen);
+ len = __cpcmd(cmd, response, rlen, response_code);
else {
lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA);
if (!lowbuf) {
printk(KERN_WARNING
"cpcmd: could not allocate response buffer\n");
- return;
+ return -ENOMEM;
}
- __cpcmd(cmd, lowbuf, rlen);
+ len = __cpcmd(cmd, lowbuf, rlen, response_code);
memcpy(response, lowbuf, rlen);
kfree(lowbuf);
}
+ return len;
}
EXPORT_SYMBOL(cpcmd);
diff --git a/arch/s390/kernel/crash.c b/arch/s390/kernel/crash.c
new file mode 100644
index 000000000000..7bd169c58b0c
--- /dev/null
+++ b/arch/s390/kernel/crash.c
@@ -0,0 +1,17 @@
+/*
+ * arch/s390/kernel/crash.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
+ *
+ */
+
+#include <linux/threads.h>
+#include <linux/kexec.h>
+
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+}
diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
index 91f8ce5543d3..960ba6029c3a 100644
--- a/arch/s390/kernel/debug.c
+++ b/arch/s390/kernel/debug.c
@@ -19,22 +19,27 @@
#include <linux/sysctl.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
-
#include <linux/module.h>
#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
#include <asm/debug.h>
#define DEBUG_PROLOG_ENTRY -1
+#define ALL_AREAS 0 /* copy all debug areas */
+#define NO_AREAS 1 /* copy no debug areas */
+
/* typedefs */
typedef struct file_private_info {
loff_t offset; /* offset of last read in file */
int act_area; /* number of last formated area */
+ int act_page; /* act page in given area */
int act_entry; /* last formated entry (offset */
/* relative to beginning of last */
- /* formated area) */
+ /* formated page) */
size_t act_entry_offset; /* up to this offset we copied */
/* in last read the last formated */
/* entry to userland */
@@ -51,8 +56,8 @@ typedef struct
* This assumes that all args are converted into longs
* on L/390 this is the case for all types of parameter
* except of floats, and long long (32 bit)
- *
- */
+ *
+ */
long args[0];
} debug_sprintf_entry_t;
@@ -63,32 +68,38 @@ extern void tod_to_timeval(uint64_t todval, struct timeval *xtime);
static int debug_init(void);
static ssize_t debug_output(struct file *file, char __user *user_buf,
- size_t user_len, loff_t * offset);
+ size_t user_len, loff_t * offset);
static ssize_t debug_input(struct file *file, const char __user *user_buf,
- size_t user_len, loff_t * offset);
+ size_t user_len, loff_t * offset);
static int debug_open(struct inode *inode, struct file *file);
static int debug_close(struct inode *inode, struct file *file);
-static debug_info_t* debug_info_create(char *name, int page_order, int nr_areas, int buf_size);
+static debug_info_t* debug_info_create(char *name, int pages_per_area,
+ int nr_areas, int buf_size);
static void debug_info_get(debug_info_t *);
static void debug_info_put(debug_info_t *);
static int debug_prolog_level_fn(debug_info_t * id,
- struct debug_view *view, char *out_buf);
+ struct debug_view *view, char *out_buf);
static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
- struct file *file, const char __user *user_buf,
- size_t user_buf_size, loff_t * offset);
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
+static int debug_prolog_pages_fn(debug_info_t * id,
+ struct debug_view *view, char *out_buf);
+static int debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
- struct file *file, const char __user *user_buf,
- size_t user_buf_size, loff_t * offset);
+ struct file *file, const char __user *user_buf,
+ size_t user_buf_size, loff_t * offset);
static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
- char *out_buf, const char *in_buf);
+ char *out_buf, const char *in_buf);
static int debug_raw_format_fn(debug_info_t * id,
- struct debug_view *view, char *out_buf,
- const char *in_buf);
+ struct debug_view *view, char *out_buf,
+ const char *in_buf);
static int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
- int area, debug_entry_t * entry, char *out_buf);
+ int area, debug_entry_t * entry, char *out_buf);
static int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
- char *out_buf, debug_sprintf_entry_t *curr_event);
+ char *out_buf, debug_sprintf_entry_t *curr_event);
/* globals */
@@ -119,6 +130,15 @@ struct debug_view debug_level_view = {
NULL
};
+struct debug_view debug_pages_view = {
+ "pages",
+ &debug_prolog_pages_fn,
+ NULL,
+ NULL,
+ &debug_input_pages_fn,
+ NULL
+};
+
struct debug_view debug_flush_view = {
"flush",
NULL,
@@ -149,98 +169,161 @@ DECLARE_MUTEX(debug_lock);
static int initialized;
static struct file_operations debug_file_ops = {
- .owner = THIS_MODULE,
+ .owner = THIS_MODULE,
.read = debug_output,
- .write = debug_input,
+ .write = debug_input,
.open = debug_open,
.release = debug_close,
};
-static struct proc_dir_entry *debug_proc_root_entry;
+static struct dentry *debug_debugfs_root_entry;
/* functions */
/*
+ * debug_areas_alloc
+ * - Debug areas are implemented as a threedimensonal array:
+ * areas[areanumber][pagenumber][pageoffset]
+ */
+
+static debug_entry_t***
+debug_areas_alloc(int pages_per_area, int nr_areas)
+{
+ debug_entry_t*** areas;
+ int i,j;
+
+ areas = (debug_entry_t ***) kmalloc(nr_areas *
+ sizeof(debug_entry_t**),
+ GFP_KERNEL);
+ if (!areas)
+ goto fail_malloc_areas;
+ for (i = 0; i < nr_areas; i++) {
+ areas[i] = (debug_entry_t**) kmalloc(pages_per_area *
+ sizeof(debug_entry_t*),GFP_KERNEL);
+ if (!areas[i]) {
+ goto fail_malloc_areas2;
+ }
+ for(j = 0; j < pages_per_area; j++) {
+ areas[i][j] = (debug_entry_t*)kmalloc(PAGE_SIZE,
+ GFP_KERNEL);
+ if(!areas[i][j]) {
+ for(j--; j >=0 ; j--) {
+ kfree(areas[i][j]);
+ }
+ kfree(areas[i]);
+ goto fail_malloc_areas2;
+ } else {
+ memset(areas[i][j],0,PAGE_SIZE);
+ }
+ }
+ }
+ return areas;
+
+fail_malloc_areas2:
+ for(i--; i >= 0; i--){
+ for(j=0; j < pages_per_area;j++){
+ kfree(areas[i][j]);
+ }
+ kfree(areas[i]);
+ }
+ kfree(areas);
+fail_malloc_areas:
+ return NULL;
+
+}
+
+
+/*
* debug_info_alloc
* - alloc new debug-info
*/
-static debug_info_t* debug_info_alloc(char *name, int page_order,
- int nr_areas, int buf_size)
+static debug_info_t*
+debug_info_alloc(char *name, int pages_per_area, int nr_areas, int buf_size,
+ int level, int mode)
{
debug_info_t* rc;
- int i;
/* alloc everything */
- rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_ATOMIC);
+ rc = (debug_info_t*) kmalloc(sizeof(debug_info_t), GFP_KERNEL);
if(!rc)
goto fail_malloc_rc;
- rc->active_entry = (int*)kmalloc(nr_areas * sizeof(int), GFP_ATOMIC);
- if(!rc->active_entry)
- goto fail_malloc_active_entry;
- memset(rc->active_entry, 0, nr_areas * sizeof(int));
- rc->areas = (debug_entry_t **) kmalloc(nr_areas *
- sizeof(debug_entry_t *),
- GFP_ATOMIC);
- if (!rc->areas)
- goto fail_malloc_areas;
- for (i = 0; i < nr_areas; i++) {
- rc->areas[i] = (debug_entry_t *) __get_free_pages(GFP_ATOMIC,
- page_order);
- if (!rc->areas[i]) {
- for (i--; i >= 0; i--) {
- free_pages((unsigned long) rc->areas[i],
- page_order);
- }
- goto fail_malloc_areas2;
- } else {
- memset(rc->areas[i], 0, PAGE_SIZE << page_order);
- }
+ rc->active_entries = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL);
+ if(!rc->active_entries)
+ goto fail_malloc_active_entries;
+ memset(rc->active_entries, 0, nr_areas * sizeof(int));
+ rc->active_pages = (int*)kmalloc(nr_areas * sizeof(int), GFP_KERNEL);
+ if(!rc->active_pages)
+ goto fail_malloc_active_pages;
+ memset(rc->active_pages, 0, nr_areas * sizeof(int));
+ if((mode == ALL_AREAS) && (pages_per_area != 0)){
+ rc->areas = debug_areas_alloc(pages_per_area, nr_areas);
+ if(!rc->areas)
+ goto fail_malloc_areas;
+ } else {
+ rc->areas = NULL;
}
/* initialize members */
spin_lock_init(&rc->lock);
- rc->page_order = page_order;
- rc->nr_areas = nr_areas;
- rc->active_area = 0;
- rc->level = DEBUG_DEFAULT_LEVEL;
- rc->buf_size = buf_size;
- rc->entry_size = sizeof(debug_entry_t) + buf_size;
- strlcpy(rc->name, name, sizeof(rc->name));
+ rc->pages_per_area = pages_per_area;
+ rc->nr_areas = nr_areas;
+ rc->active_area = 0;
+ rc->level = level;
+ rc->buf_size = buf_size;
+ rc->entry_size = sizeof(debug_entry_t) + buf_size;
+ strlcpy(rc->name, name, sizeof(rc->name)-1);
memset(rc->views, 0, DEBUG_MAX_VIEWS * sizeof(struct debug_view *));
-#ifdef CONFIG_PROC_FS
- memset(rc->proc_entries, 0 ,DEBUG_MAX_VIEWS *
- sizeof(struct proc_dir_entry*));
-#endif /* CONFIG_PROC_FS */
+ memset(rc->debugfs_entries, 0 ,DEBUG_MAX_VIEWS *
+ sizeof(struct dentry*));
atomic_set(&(rc->ref_count), 0);
return rc;
-fail_malloc_areas2:
- kfree(rc->areas);
fail_malloc_areas:
- kfree(rc->active_entry);
-fail_malloc_active_entry:
+ kfree(rc->active_pages);
+fail_malloc_active_pages:
+ kfree(rc->active_entries);
+fail_malloc_active_entries:
kfree(rc);
fail_malloc_rc:
return NULL;
}
/*
- * debug_info_free
- * - free memory debug-info
+ * debug_areas_free
+ * - free all debug areas
*/
-static void debug_info_free(debug_info_t* db_info){
- int i;
+static void
+debug_areas_free(debug_info_t* db_info)
+{
+ int i,j;
+
+ if(!db_info->areas)
+ return;
for (i = 0; i < db_info->nr_areas; i++) {
- free_pages((unsigned long) db_info->areas[i],
- db_info->page_order);
+ for(j = 0; j < db_info->pages_per_area; j++) {
+ kfree(db_info->areas[i][j]);
+ }
+ kfree(db_info->areas[i]);
}
kfree(db_info->areas);
- kfree(db_info->active_entry);
+ db_info->areas = NULL;
+}
+
+/*
+ * debug_info_free
+ * - free memory debug-info
+ */
+
+static void
+debug_info_free(debug_info_t* db_info){
+ debug_areas_free(db_info);
+ kfree(db_info->active_entries);
+ kfree(db_info->active_pages);
kfree(db_info);
}
@@ -249,21 +332,22 @@ static void debug_info_free(debug_info_t* db_info){
* - create new debug-info
*/
-static debug_info_t* debug_info_create(char *name, int page_order,
- int nr_areas, int buf_size)
+static debug_info_t*
+debug_info_create(char *name, int pages_per_area, int nr_areas, int buf_size)
{
debug_info_t* rc;
- rc = debug_info_alloc(name, page_order, nr_areas, buf_size);
+ rc = debug_info_alloc(name, pages_per_area, nr_areas, buf_size,
+ DEBUG_DEFAULT_LEVEL, ALL_AREAS);
if(!rc)
goto out;
-
- /* create proc rood directory */
- rc->proc_root_entry = proc_mkdir(rc->name, debug_proc_root_entry);
+ /* create root directory */
+ rc->debugfs_root_entry = debugfs_create_dir(rc->name,
+ debug_debugfs_root_entry);
/* append new element to linked list */
- if (debug_area_first == NULL) {
+ if (!debug_area_first) {
/* first element in list */
debug_area_first = rc;
rc->prev = NULL;
@@ -285,17 +369,21 @@ out:
* - copy debug-info
*/
-static debug_info_t* debug_info_copy(debug_info_t* in)
+static debug_info_t*
+debug_info_copy(debug_info_t* in, int mode)
{
- int i;
+ int i,j;
debug_info_t* rc;
- rc = debug_info_alloc(in->name, in->page_order,
- in->nr_areas, in->buf_size);
- if(!rc)
+
+ rc = debug_info_alloc(in->name, in->pages_per_area, in->nr_areas,
+ in->buf_size, in->level, mode);
+ if(!rc || (mode == NO_AREAS))
goto out;
for(i = 0; i < in->nr_areas; i++){
- memcpy(rc->areas[i],in->areas[i], PAGE_SIZE << in->page_order);
+ for(j = 0; j < in->pages_per_area; j++) {
+ memcpy(rc->areas[i][j], in->areas[i][j],PAGE_SIZE);
+ }
}
out:
return rc;
@@ -306,7 +394,8 @@ out:
* - increments reference count for debug-info
*/
-static void debug_info_get(debug_info_t * db_info)
+static void
+debug_info_get(debug_info_t * db_info)
{
if (db_info)
atomic_inc(&db_info->ref_count);
@@ -317,29 +406,20 @@ static void debug_info_get(debug_info_t * db_info)
* - decreases reference count for debug-info and frees it if necessary
*/
-static void debug_info_put(debug_info_t *db_info)
+static void
+debug_info_put(debug_info_t *db_info)
{
int i;
if (!db_info)
return;
if (atomic_dec_and_test(&db_info->ref_count)) {
-#ifdef DEBUG
- printk(KERN_INFO "debug: freeing debug area %p (%s)\n",
- db_info, db_info->name);
-#endif
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
- if (db_info->views[i] == NULL)
+ if (!db_info->views[i])
continue;
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(db_info->proc_entries[i]->name,
- db_info->proc_root_entry);
-#endif
+ debugfs_remove(db_info->debugfs_entries[i]);
}
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(db_info->proc_root_entry->name,
- debug_proc_root_entry);
-#endif
+ debugfs_remove(db_info->debugfs_root_entry);
if(db_info == debug_area_first)
debug_area_first = db_info->next;
if(db_info == debug_area_last)
@@ -355,9 +435,9 @@ static void debug_info_put(debug_info_t *db_info)
* - format one debug entry and return size of formated data
*/
-static int debug_format_entry(file_private_info_t *p_info)
+static int
+debug_format_entry(file_private_info_t *p_info)
{
- debug_info_t *id_org = p_info->debug_info_org;
debug_info_t *id_snap = p_info->debug_info_snap;
struct debug_view *view = p_info->view;
debug_entry_t *act_entry;
@@ -365,22 +445,23 @@ static int debug_format_entry(file_private_info_t *p_info)
if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
/* print prolog */
if (view->prolog_proc)
- len += view->prolog_proc(id_org, view,p_info->temp_buf);
+ len += view->prolog_proc(id_snap,view,p_info->temp_buf);
goto out;
}
-
- act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area] +
- p_info->act_entry);
+ if (!id_snap->areas) /* this is true, if we have a prolog only view */
+ goto out; /* or if 'pages_per_area' is 0 */
+ act_entry = (debug_entry_t *) ((char*)id_snap->areas[p_info->act_area]
+ [p_info->act_page] + p_info->act_entry);
if (act_entry->id.stck == 0LL)
goto out; /* empty entry */
if (view->header_proc)
- len += view->header_proc(id_org, view, p_info->act_area,
+ len += view->header_proc(id_snap, view, p_info->act_area,
act_entry, p_info->temp_buf + len);
if (view->format_proc)
- len += view->format_proc(id_org, view, p_info->temp_buf + len,
+ len += view->format_proc(id_snap, view, p_info->temp_buf + len,
DEBUG_DATA(act_entry));
- out:
+out:
return len;
}
@@ -389,20 +470,30 @@ static int debug_format_entry(file_private_info_t *p_info)
* - goto next entry in p_info
*/
-extern inline int debug_next_entry(file_private_info_t *p_info)
+extern inline int
+debug_next_entry(file_private_info_t *p_info)
{
- debug_info_t *id = p_info->debug_info_snap;
+ debug_info_t *id;
+
+ id = p_info->debug_info_snap;
if(p_info->act_entry == DEBUG_PROLOG_ENTRY){
p_info->act_entry = 0;
+ p_info->act_page = 0;
goto out;
}
- if ((p_info->act_entry += id->entry_size)
- > ((PAGE_SIZE << (id->page_order))
- - id->entry_size)){
-
- /* next area */
+ if(!id->areas)
+ return 1;
+ p_info->act_entry += id->entry_size;
+ /* switch to next page, if we reached the end of the page */
+ if (p_info->act_entry > (PAGE_SIZE - id->entry_size)){
+ /* next page */
p_info->act_entry = 0;
- p_info->act_area++;
+ p_info->act_page += 1;
+ if((p_info->act_page % id->pages_per_area) == 0) {
+ /* next area */
+ p_info->act_area++;
+ p_info->act_page=0;
+ }
if(p_info->act_area >= id->nr_areas)
return 1;
}
@@ -416,13 +507,14 @@ out:
* - copies formated debug entries to the user buffer
*/
-static ssize_t debug_output(struct file *file, /* file descriptor */
- char __user *user_buf, /* user buffer */
- size_t len, /* length of buffer */
- loff_t *offset) /* offset in the file */
+static ssize_t
+debug_output(struct file *file, /* file descriptor */
+ char __user *user_buf, /* user buffer */
+ size_t len, /* length of buffer */
+ loff_t *offset) /* offset in the file */
{
size_t count = 0;
- size_t entry_offset, size = 0;
+ size_t entry_offset;
file_private_info_t *p_info;
p_info = ((file_private_info_t *) file->private_data);
@@ -430,27 +522,33 @@ static ssize_t debug_output(struct file *file, /* file descriptor */
return -EPIPE;
if(p_info->act_area >= p_info->debug_info_snap->nr_areas)
return 0;
-
entry_offset = p_info->act_entry_offset;
-
while(count < len){
- size = debug_format_entry(p_info);
- size = min((len - count), (size - entry_offset));
-
- if(size){
- if (copy_to_user(user_buf + count,
- p_info->temp_buf + entry_offset, size))
- return -EFAULT;
+ int formatted_line_size;
+ int formatted_line_residue;
+ int user_buf_residue;
+ size_t copy_size;
+
+ formatted_line_size = debug_format_entry(p_info);
+ formatted_line_residue = formatted_line_size - entry_offset;
+ user_buf_residue = len-count;
+ copy_size = min(user_buf_residue, formatted_line_residue);
+ if(copy_size){
+ if (copy_to_user(user_buf + count, p_info->temp_buf
+ + entry_offset, copy_size))
+ return -EFAULT;
+ count += copy_size;
+ entry_offset += copy_size;
}
- count += size;
- entry_offset = 0;
- if(count != len)
- if(debug_next_entry(p_info))
+ if(copy_size == formatted_line_residue){
+ entry_offset = 0;
+ if(debug_next_entry(p_info))
goto out;
+ }
}
out:
p_info->offset = *offset + count;
- p_info->act_entry_offset = size;
+ p_info->act_entry_offset = entry_offset;
*offset = p_info->offset;
return count;
}
@@ -461,9 +559,9 @@ out:
* - calls input function of view
*/
-static ssize_t debug_input(struct file *file,
- const char __user *user_buf, size_t length,
- loff_t *offset)
+static ssize_t
+debug_input(struct file *file, const char __user *user_buf, size_t length,
+ loff_t *offset)
{
int rc = 0;
file_private_info_t *p_info;
@@ -487,26 +585,23 @@ static ssize_t debug_input(struct file *file,
* handle
*/
-static int debug_open(struct inode *inode, struct file *file)
+static int
+debug_open(struct inode *inode, struct file *file)
{
int i = 0, rc = 0;
file_private_info_t *p_info;
debug_info_t *debug_info, *debug_info_snapshot;
-#ifdef DEBUG
- printk("debug_open\n");
-#endif
down(&debug_lock);
/* find debug log and view */
-
debug_info = debug_area_first;
while(debug_info != NULL){
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
- if (debug_info->views[i] == NULL)
+ if (!debug_info->views[i])
continue;
- else if (debug_info->proc_entries[i] ==
- PDE(file->f_dentry->d_inode)) {
+ else if (debug_info->debugfs_entries[i] ==
+ file->f_dentry) {
goto found; /* found view ! */
}
}
@@ -516,41 +611,42 @@ static int debug_open(struct inode *inode, struct file *file)
rc = -EINVAL;
goto out;
- found:
+found:
- /* make snapshot of current debug areas to get it consistent */
+ /* Make snapshot of current debug areas to get it consistent. */
+ /* To copy all the areas is only needed, if we have a view which */
+ /* formats the debug areas. */
- debug_info_snapshot = debug_info_copy(debug_info);
+ if(!debug_info->views[i]->format_proc &&
+ !debug_info->views[i]->header_proc){
+ debug_info_snapshot = debug_info_copy(debug_info, NO_AREAS);
+ } else {
+ debug_info_snapshot = debug_info_copy(debug_info, ALL_AREAS);
+ }
if(!debug_info_snapshot){
-#ifdef DEBUG
- printk(KERN_ERR "debug_open: debug_info_copy failed (out of mem)\n");
-#endif
rc = -ENOMEM;
goto out;
}
-
- if ((file->private_data =
- kmalloc(sizeof(file_private_info_t), GFP_ATOMIC)) == 0) {
-#ifdef DEBUG
- printk(KERN_ERR "debug_open: kmalloc failed\n");
-#endif
- debug_info_free(debug_info_snapshot);
+ p_info = (file_private_info_t *) kmalloc(sizeof(file_private_info_t),
+ GFP_KERNEL);
+ if(!p_info){
+ if(debug_info_snapshot)
+ debug_info_free(debug_info_snapshot);
rc = -ENOMEM;
goto out;
}
- p_info = (file_private_info_t *) file->private_data;
p_info->offset = 0;
p_info->debug_info_snap = debug_info_snapshot;
p_info->debug_info_org = debug_info;
p_info->view = debug_info->views[i];
p_info->act_area = 0;
+ p_info->act_page = 0;
p_info->act_entry = DEBUG_PROLOG_ENTRY;
p_info->act_entry_offset = 0;
-
+ file->private_data = p_info;
debug_info_get(debug_info);
-
- out:
+out:
up(&debug_lock);
return rc;
}
@@ -561,14 +657,13 @@ static int debug_open(struct inode *inode, struct file *file)
* - deletes private_data area of the file handle
*/
-static int debug_close(struct inode *inode, struct file *file)
+static int
+debug_close(struct inode *inode, struct file *file)
{
file_private_info_t *p_info;
-#ifdef DEBUG
- printk("debug_close\n");
-#endif
p_info = (file_private_info_t *) file->private_data;
- debug_info_free(p_info->debug_info_snap);
+ if(p_info->debug_info_snap)
+ debug_info_free(p_info->debug_info_snap);
debug_info_put(p_info->debug_info_org);
kfree(file->private_data);
return 0; /* success */
@@ -580,8 +675,8 @@ static int debug_close(struct inode *inode, struct file *file)
* - returns handle for debug area
*/
-debug_info_t *debug_register
- (char *name, int page_order, int nr_areas, int buf_size)
+debug_info_t*
+debug_register (char *name, int pages_per_area, int nr_areas, int buf_size)
{
debug_info_t *rc = NULL;
@@ -591,18 +686,14 @@ debug_info_t *debug_register
/* create new debug_info */
- rc = debug_info_create(name, page_order, nr_areas, buf_size);
+ rc = debug_info_create(name, pages_per_area, nr_areas, buf_size);
if(!rc)
goto out;
debug_register_view(rc, &debug_level_view);
debug_register_view(rc, &debug_flush_view);
-#ifdef DEBUG
- printk(KERN_INFO
- "debug: reserved %d areas of %d pages for debugging %s\n",
- nr_areas, 1 << page_order, rc->name);
-#endif
- out:
- if (rc == NULL){
+ debug_register_view(rc, &debug_pages_view);
+out:
+ if (!rc){
printk(KERN_ERR "debug: debug_register failed for %s\n",name);
}
up(&debug_lock);
@@ -614,27 +705,65 @@ debug_info_t *debug_register
* - give back debug area
*/
-void debug_unregister(debug_info_t * id)
+void
+debug_unregister(debug_info_t * id)
{
if (!id)
goto out;
down(&debug_lock);
-#ifdef DEBUG
- printk(KERN_INFO "debug: unregistering %s\n", id->name);
-#endif
debug_info_put(id);
up(&debug_lock);
- out:
+out:
return;
}
/*
+ * debug_set_size:
+ * - set area size (number of pages) and number of areas
+ */
+static int
+debug_set_size(debug_info_t* id, int nr_areas, int pages_per_area)
+{
+ unsigned long flags;
+ debug_entry_t *** new_areas;
+ int rc=0;
+
+ if(!id || (nr_areas <= 0) || (pages_per_area < 0))
+ return -EINVAL;
+ if(pages_per_area > 0){
+ new_areas = debug_areas_alloc(pages_per_area, nr_areas);
+ if(!new_areas) {
+ printk(KERN_WARNING "debug: could not allocate memory "\
+ "for pagenumber: %i\n",pages_per_area);
+ rc = -ENOMEM;
+ goto out;
+ }
+ } else {
+ new_areas = NULL;
+ }
+ spin_lock_irqsave(&id->lock,flags);
+ debug_areas_free(id);
+ id->areas = new_areas;
+ id->nr_areas = nr_areas;
+ id->pages_per_area = pages_per_area;
+ id->active_area = 0;
+ memset(id->active_entries,0,sizeof(int)*id->nr_areas);
+ memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
+ spin_unlock_irqrestore(&id->lock,flags);
+ printk(KERN_INFO "debug: %s: set new size (%i pages)\n"\
+ ,id->name, pages_per_area);
+out:
+ return rc;
+}
+
+/*
* debug_set_level:
* - set actual debug level
*/
-void debug_set_level(debug_info_t* id, int new_level)
+void
+debug_set_level(debug_info_t* id, int new_level)
{
unsigned long flags;
if(!id)
@@ -649,10 +778,6 @@ void debug_set_level(debug_info_t* id, int new_level)
id->name, new_level, 0, DEBUG_MAX_LEVEL);
} else {
id->level = new_level;
-#ifdef DEBUG
- printk(KERN_INFO
- "debug: %s: new level %i\n",id->name,id->level);
-#endif
}
spin_unlock_irqrestore(&id->lock,flags);
}
@@ -663,11 +788,16 @@ void debug_set_level(debug_info_t* id, int new_level)
* - set active entry to next in the ring buffer
*/
-extern inline void proceed_active_entry(debug_info_t * id)
+extern inline void
+proceed_active_entry(debug_info_t * id)
{
- if ((id->active_entry[id->active_area] += id->entry_size)
- > ((PAGE_SIZE << (id->page_order)) - id->entry_size))
- id->active_entry[id->active_area] = 0;
+ if ((id->active_entries[id->active_area] += id->entry_size)
+ > (PAGE_SIZE - id->entry_size)){
+ id->active_entries[id->active_area] = 0;
+ id->active_pages[id->active_area] =
+ (id->active_pages[id->active_area] + 1) %
+ id->pages_per_area;
+ }
}
/*
@@ -675,7 +805,8 @@ extern inline void proceed_active_entry(debug_info_t * id)
* - set active area to next in the ring buffer
*/
-extern inline void proceed_active_area(debug_info_t * id)
+extern inline void
+proceed_active_area(debug_info_t * id)
{
id->active_area++;
id->active_area = id->active_area % id->nr_areas;
@@ -685,10 +816,12 @@ extern inline void proceed_active_area(debug_info_t * id)
* get_active_entry:
*/
-extern inline debug_entry_t *get_active_entry(debug_info_t * id)
+extern inline debug_entry_t*
+get_active_entry(debug_info_t * id)
{
- return (debug_entry_t *) ((char *) id->areas[id->active_area] +
- id->active_entry[id->active_area]);
+ return (debug_entry_t *) (((char *) id->areas[id->active_area]
+ [id->active_pages[id->active_area]]) +
+ id->active_entries[id->active_area]);
}
/*
@@ -696,8 +829,9 @@ extern inline debug_entry_t *get_active_entry(debug_info_t * id)
* - set timestamp, caller address, cpu number etc.
*/
-extern inline void debug_finish_entry(debug_info_t * id, debug_entry_t* active,
- int level, int exception)
+extern inline void
+debug_finish_entry(debug_info_t * id, debug_entry_t* active, int level,
+ int exception)
{
STCK(active->id.stck);
active->id.fields.cpuid = smp_processor_id();
@@ -721,7 +855,8 @@ static int debug_active=1;
* always allow read, allow write only if debug_stoppable is set or
* if debug_active is already off
*/
-static int s390dbf_procactive(ctl_table *table, int write, struct file *filp,
+static int
+s390dbf_procactive(ctl_table *table, int write, struct file *filp,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
if (!write || debug_stoppable || !debug_active)
@@ -766,7 +901,8 @@ static struct ctl_table s390dbf_dir_table[] = {
struct ctl_table_header *s390dbf_sysctl_header;
-void debug_stop_all(void)
+void
+debug_stop_all(void)
{
if (debug_stoppable)
debug_active = 0;
@@ -778,13 +914,13 @@ void debug_stop_all(void)
* - write debug entry with given size
*/
-debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
- int len)
+debug_entry_t*
+debug_event_common(debug_info_t * id, int level, const void *buf, int len)
{
unsigned long flags;
debug_entry_t *active;
- if (!debug_active)
+ if (!debug_active || !id->areas)
return NULL;
spin_lock_irqsave(&id->lock, flags);
active = get_active_entry(id);
@@ -801,13 +937,13 @@ debug_entry_t *debug_event_common(debug_info_t * id, int level, const void *buf,
* - write debug entry with given size and switch to next debug area
*/
-debug_entry_t *debug_exception_common(debug_info_t * id, int level,
- const void *buf, int len)
+debug_entry_t
+*debug_exception_common(debug_info_t * id, int level, const void *buf, int len)
{
unsigned long flags;
debug_entry_t *active;
- if (!debug_active)
+ if (!debug_active || !id->areas)
return NULL;
spin_lock_irqsave(&id->lock, flags);
active = get_active_entry(id);
@@ -823,7 +959,8 @@ debug_entry_t *debug_exception_common(debug_info_t * id, int level,
* counts arguments in format string for sprintf view
*/
-extern inline int debug_count_numargs(char *string)
+extern inline int
+debug_count_numargs(char *string)
{
int numargs=0;
@@ -838,8 +975,8 @@ extern inline int debug_count_numargs(char *string)
* debug_sprintf_event:
*/
-debug_entry_t *debug_sprintf_event(debug_info_t* id,
- int level,char *string,...)
+debug_entry_t*
+debug_sprintf_event(debug_info_t* id, int level,char *string,...)
{
va_list ap;
int numargs,idx;
@@ -849,7 +986,7 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id,
if((!id) || (level > id->level))
return NULL;
- if (!debug_active)
+ if (!debug_active || !id->areas)
return NULL;
numargs=debug_count_numargs(string);
@@ -871,8 +1008,8 @@ debug_entry_t *debug_sprintf_event(debug_info_t* id,
* debug_sprintf_exception:
*/
-debug_entry_t *debug_sprintf_exception(debug_info_t* id,
- int level,char *string,...)
+debug_entry_t*
+debug_sprintf_exception(debug_info_t* id, int level,char *string,...)
{
va_list ap;
int numargs,idx;
@@ -882,7 +1019,7 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
if((!id) || (level > id->level))
return NULL;
- if (!debug_active)
+ if (!debug_active || !id->areas)
return NULL;
numargs=debug_count_numargs(string);
@@ -906,15 +1043,14 @@ debug_entry_t *debug_sprintf_exception(debug_info_t* id,
* - is called exactly once to initialize the debug feature
*/
-static int __init debug_init(void)
+static int
+__init debug_init(void)
{
int rc = 0;
s390dbf_sysctl_header = register_sysctl_table(s390dbf_dir_table, 1);
down(&debug_lock);
-#ifdef CONFIG_PROC_FS
- debug_proc_root_entry = proc_mkdir(DEBUG_DIR_ROOT, NULL);
-#endif /* CONFIG_PROC_FS */
+ debug_debugfs_root_entry = debugfs_create_dir(DEBUG_DIR_ROOT,NULL);
printk(KERN_INFO "debug: Initialization complete\n");
initialized = 1;
up(&debug_lock);
@@ -926,13 +1062,14 @@ static int __init debug_init(void)
* debug_register_view:
*/
-int debug_register_view(debug_info_t * id, struct debug_view *view)
+int
+debug_register_view(debug_info_t * id, struct debug_view *view)
{
int rc = 0;
int i;
unsigned long flags;
mode_t mode = S_IFREG;
- struct proc_dir_entry *pde;
+ struct dentry *pde;
if (!id)
goto out;
@@ -940,16 +1077,17 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
mode |= S_IRUSR;
if (view->input_proc)
mode |= S_IWUSR;
- pde = create_proc_entry(view->name, mode, id->proc_root_entry);
+ pde = debugfs_create_file(view->name, mode, id->debugfs_root_entry,
+ NULL, &debug_file_ops);
if (!pde){
- printk(KERN_WARNING "debug: create_proc_entry() failed! Cannot register view %s/%s\n", id->name,view->name);
+ printk(KERN_WARNING "debug: debugfs_create_file() failed!"\
+ " Cannot register view %s/%s\n", id->name,view->name);
rc = -1;
goto out;
}
-
spin_lock_irqsave(&id->lock, flags);
for (i = 0; i < DEBUG_MAX_VIEWS; i++) {
- if (id->views[i] == NULL)
+ if (!id->views[i])
break;
}
if (i == DEBUG_MAX_VIEWS) {
@@ -957,16 +1095,14 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
id->name,view->name);
printk(KERN_WARNING
"debug: maximum number of views reached (%i)!\n", i);
- remove_proc_entry(pde->name, id->proc_root_entry);
+ debugfs_remove(pde);
rc = -1;
- }
- else {
+ } else {
id->views[i] = view;
- pde->proc_fops = &debug_file_ops;
- id->proc_entries[i] = pde;
+ id->debugfs_entries[i] = pde;
}
spin_unlock_irqrestore(&id->lock, flags);
- out:
+out:
return rc;
}
@@ -974,7 +1110,8 @@ int debug_register_view(debug_info_t * id, struct debug_view *view)
* debug_unregister_view:
*/
-int debug_unregister_view(debug_info_t * id, struct debug_view *view)
+int
+debug_unregister_view(debug_info_t * id, struct debug_view *view)
{
int rc = 0;
int i;
@@ -990,15 +1127,46 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view)
if (i == DEBUG_MAX_VIEWS)
rc = -1;
else {
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(id->proc_entries[i]->name,
- id->proc_root_entry);
-#endif
+ debugfs_remove(id->debugfs_entries[i]);
id->views[i] = NULL;
rc = 0;
}
spin_unlock_irqrestore(&id->lock, flags);
- out:
+out:
+ return rc;
+}
+
+static inline char *
+debug_get_user_string(const char __user *user_buf, size_t user_len)
+{
+ char* buffer;
+
+ buffer = kmalloc(user_len + 1, GFP_KERNEL);
+ if (!buffer)
+ return ERR_PTR(-ENOMEM);
+ if (copy_from_user(buffer, user_buf, user_len) != 0) {
+ kfree(buffer);
+ return ERR_PTR(-EFAULT);
+ }
+ /* got the string, now strip linefeed. */
+ if (buffer[user_len - 1] == '\n')
+ buffer[user_len - 1] = 0;
+ else
+ buffer[user_len] = 0;
+ return buffer;
+}
+
+static inline int
+debug_get_uint(char *buf)
+{
+ int rc;
+
+ for(; isspace(*buf); buf++);
+ rc = simple_strtoul(buf, &buf, 10);
+ if(*buf){
+ printk("debug: no integer specified!\n");
+ rc = -EINVAL;
+ }
return rc;
}
@@ -1011,13 +1179,69 @@ int debug_unregister_view(debug_info_t * id, struct debug_view *view)
* prints out actual debug level
*/
-static int debug_prolog_level_fn(debug_info_t * id,
+static int
+debug_prolog_pages_fn(debug_info_t * id,
struct debug_view *view, char *out_buf)
{
+ return sprintf(out_buf, "%i\n", id->pages_per_area);
+}
+
+/*
+ * reads new size (number of pages per debug area)
+ */
+
+static int
+debug_input_pages_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ char *str;
+ int rc,new_pages;
+
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
+ goto out;
+ }
+ str = debug_get_user_string(user_buf,user_len);
+ if(IS_ERR(str)){
+ rc = PTR_ERR(str);
+ goto out;
+ }
+ new_pages = debug_get_uint(str);
+ if(new_pages < 0){
+ rc = -EINVAL;
+ goto free_str;
+ }
+ rc = debug_set_size(id,id->nr_areas, new_pages);
+ if(rc != 0){
+ rc = -EINVAL;
+ goto free_str;
+ }
+ rc = user_len;
+free_str:
+ kfree(str);
+out:
+ *offset += user_len;
+ return rc; /* number of input characters */
+}
+
+/*
+ * prints out actual debug level
+ */
+
+static int
+debug_prolog_level_fn(debug_info_t * id, struct debug_view *view, char *out_buf)
+{
int rc = 0;
- if(id->level == -1) rc = sprintf(out_buf,"-\n");
- else rc = sprintf(out_buf, "%i\n", id->level);
+ if(id->level == DEBUG_OFF_LEVEL) {
+ rc = sprintf(out_buf,"-\n");
+ }
+ else {
+ rc = sprintf(out_buf, "%i\n", id->level);
+ }
return rc;
}
@@ -1025,30 +1249,43 @@ static int debug_prolog_level_fn(debug_info_t * id,
* reads new debug level
*/
-static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
- struct file *file, const char __user *user_buf,
- size_t in_buf_size, loff_t * offset)
+static int
+debug_input_level_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
{
- char input_buf[1];
- int rc = in_buf_size;
+ char *str;
+ int rc,new_level;
- if (*offset != 0)
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
goto out;
- if (copy_from_user(input_buf, user_buf, 1)){
- rc = -EFAULT;
+ }
+ str = debug_get_user_string(user_buf,user_len);
+ if(IS_ERR(str)){
+ rc = PTR_ERR(str);
goto out;
}
- if (isdigit(input_buf[0])) {
- int new_level = ((int) input_buf[0] - (int) '0');
- debug_set_level(id, new_level);
- } else if(input_buf[0] == '-') {
+ if(str[0] == '-'){
debug_set_level(id, DEBUG_OFF_LEVEL);
+ rc = user_len;
+ goto free_str;
} else {
- printk(KERN_INFO "debug: level `%c` is not valid\n",
- input_buf[0]);
+ new_level = debug_get_uint(str);
}
- out:
- *offset += in_buf_size;
+ if(new_level < 0) {
+ printk(KERN_INFO "debug: level `%s` is not valid\n", str);
+ rc = -EINVAL;
+ } else {
+ debug_set_level(id, new_level);
+ rc = user_len;
+ }
+free_str:
+ kfree(str);
+out:
+ *offset += user_len;
return rc; /* number of input characters */
}
@@ -1057,29 +1294,36 @@ static int debug_input_level_fn(debug_info_t * id, struct debug_view *view,
* flushes debug areas
*/
-void debug_flush(debug_info_t* id, int area)
+void
+debug_flush(debug_info_t* id, int area)
{
unsigned long flags;
- int i;
+ int i,j;
- if(!id)
+ if(!id || !id->areas)
return;
spin_lock_irqsave(&id->lock,flags);
if(area == DEBUG_FLUSH_ALL){
id->active_area = 0;
- memset(id->active_entry, 0, id->nr_areas * sizeof(int));
- for (i = 0; i < id->nr_areas; i++)
- memset(id->areas[i], 0, PAGE_SIZE << id->page_order);
+ memset(id->active_entries, 0, id->nr_areas * sizeof(int));
+ for (i = 0; i < id->nr_areas; i++) {
+ id->active_pages[i] = 0;
+ for(j = 0; j < id->pages_per_area; j++) {
+ memset(id->areas[i][j], 0, PAGE_SIZE);
+ }
+ }
printk(KERN_INFO "debug: %s: all areas flushed\n",id->name);
} else if(area >= 0 && area < id->nr_areas) {
- id->active_entry[area] = 0;
- memset(id->areas[area], 0, PAGE_SIZE << id->page_order);
- printk(KERN_INFO
- "debug: %s: area %i has been flushed\n",
+ id->active_entries[area] = 0;
+ id->active_pages[area] = 0;
+ for(i = 0; i < id->pages_per_area; i++) {
+ memset(id->areas[area][i],0,PAGE_SIZE);
+ }
+ printk(KERN_INFO "debug: %s: area %i has been flushed\n",
id->name, area);
} else {
printk(KERN_INFO
- "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
+ "debug: %s: area %i cannot be flushed (range: %i - %i)\n",
id->name, area, 0, id->nr_areas-1);
}
spin_unlock_irqrestore(&id->lock,flags);
@@ -1089,15 +1333,20 @@ void debug_flush(debug_info_t* id, int area)
* view function: flushes debug areas
*/
-static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
- struct file *file, const char __user *user_buf,
- size_t in_buf_size, loff_t * offset)
+static int
+debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
+ struct file *file, const char __user *user_buf,
+ size_t user_len, loff_t * offset)
{
char input_buf[1];
- int rc = in_buf_size;
-
- if (*offset != 0)
+ int rc = user_len;
+
+ if (user_len > 0x10000)
+ user_len = 0x10000;
+ if (*offset != 0){
+ rc = -EPIPE;
goto out;
+ }
if (copy_from_user(input_buf, user_buf, 1)){
rc = -EFAULT;
goto out;
@@ -1114,8 +1363,8 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
printk(KERN_INFO "debug: area `%c` is not valid\n", input_buf[0]);
- out:
- *offset += in_buf_size;
+out:
+ *offset += user_len;
return rc; /* number of input characters */
}
@@ -1123,8 +1372,9 @@ static int debug_input_flush_fn(debug_info_t * id, struct debug_view *view,
* prints debug header in raw format
*/
-int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
- int area, debug_entry_t * entry, char *out_buf)
+static int
+debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
+ int area, debug_entry_t * entry, char *out_buf)
{
int rc;
@@ -1137,7 +1387,8 @@ int debug_raw_header_fn(debug_info_t * id, struct debug_view *view,
* prints debug data in raw format
*/
-static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
+static int
+debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
char *out_buf, const char *in_buf)
{
int rc;
@@ -1151,8 +1402,9 @@ static int debug_raw_format_fn(debug_info_t * id, struct debug_view *view,
* prints debug data in hex/ascii format
*/
-static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
- char *out_buf, const char *in_buf)
+static int
+debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, const char *in_buf)
{
int i, rc = 0;
@@ -1176,7 +1428,8 @@ static int debug_hex_ascii_format_fn(debug_info_t * id, struct debug_view *view,
* prints header for debug entry
*/
-int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
+int
+debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
int area, debug_entry_t * entry, char *out_buf)
{
struct timeval time_val;
@@ -1210,8 +1463,9 @@ int debug_dflt_header_fn(debug_info_t * id, struct debug_view *view,
#define DEBUG_SPRINTF_MAX_ARGS 10
-int debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
- char *out_buf, debug_sprintf_entry_t *curr_event)
+static int
+debug_sprintf_format_fn(debug_info_t * id, struct debug_view *view,
+ char *out_buf, debug_sprintf_entry_t *curr_event)
{
int num_longs, num_used_args = 0,i, rc = 0;
int index[DEBUG_SPRINTF_MAX_ARGS];
@@ -1251,14 +1505,10 @@ out:
/*
* clean up module
*/
-void __exit debug_exit(void)
+void
+__exit debug_exit(void)
{
-#ifdef DEBUG
- printk("debug_cleanup_module: \n");
-#endif
-#ifdef CONFIG_PROC_FS
- remove_proc_entry(debug_proc_root_entry->name, NULL);
-#endif /* CONFIG_PROC_FS */
+ debugfs_remove(debug_debugfs_root_entry);
unregister_sysctl_table(s390dbf_sysctl_header);
return;
}
@@ -1266,7 +1516,7 @@ void __exit debug_exit(void)
/*
* module definitions
*/
-core_initcall(debug_init);
+postcore_initcall(debug_init);
module_exit(debug_exit);
MODULE_LICENSE("GPL");
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index c0e09b33febe..5b262b5d869f 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -7,6 +7,7 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/sys.h>
@@ -49,9 +50,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
_TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
@@ -121,7 +122,11 @@ STACK_SIZE = 1 << STACK_SHIFT
bz BASED(stack_overflow)
3:
#endif
-2: s %r15,BASED(.Lc_spsize) # make room for registers & psw
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
@@ -161,6 +166,13 @@ __switch_to_base:
be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
+ l %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+ bz __switch_to_no_mcck-__switch_to_base(%r1)
+ ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ l %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
@@ -185,6 +197,7 @@ system_call:
sysc_saveall:
SAVE_ALL_BASE __LC_SAVE_AREA
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
lh %r7,0x8a # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
@@ -234,6 +247,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(sysc_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(sysc_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -253,6 +268,14 @@ sysc_reschedule:
br %r1 # call scheduler
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # TIF bit will be cleared by handler
+
+#
# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
@@ -430,6 +453,7 @@ pgm_check_handler:
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
bnz BASED(pgm_per) # got per exception -> special case
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime)
@@ -468,6 +492,7 @@ pgm_per:
#
pgm_per_std:
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime2)
@@ -493,6 +518,7 @@ pgm_no_vtime2:
#
pgm_svcper:
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime3)
@@ -521,6 +547,7 @@ io_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+16
SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(io_no_vtime)
@@ -578,9 +605,11 @@ io_work:
lr %r15,%r1
#
# One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
#
io_work_loop:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(io_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(io_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -588,6 +617,14 @@ io_work_loop:
b BASED(io_leave)
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ l %r14,BASED(io_work_loop)
+ br %r1 # TIF bit will be cleared by handler
+
+#
# _TIF_NEED_RESCHED is set, call schedule
#
io_reschedule:
@@ -621,6 +658,7 @@ ext_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+16
SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(ext_no_vtime)
@@ -642,19 +680,62 @@ ext_no_vtime:
.globl mcck_int_handler
mcck_int_handler:
- STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer
+ lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+32
- SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ bo BASED(mcck_int_main) # yes -> rest of mcck code invalid
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ bo BASED(0f)
+ spt __LC_LAST_UPDATE_TIMER # revalidate cpu timer
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ bno BASED(mcck_no_vtime) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
bz BASED(mcck_no_vtime)
UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
#endif
+0:
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ bno BASED(mcck_int_main) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ bnz BASED(mcck_int_main) # from user -> load async stack
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end)
+ bhe BASED(mcck_int_main)
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start)
+ bl BASED(mcck_int_main)
+ l %r14,BASED(.Lcleanup_critical)
+ basr %r14,%r14
+mcck_int_main:
+ l %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slr %r14,%r15
+ sra %r14,PAGE_SHIFT
+ be BASED(0f)
+ l %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Ls390_mcck)
- basr %r14,%r1 # call machine check handler
+ basr %r14,%r1 # call machine check handler
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ bno BASED(mcck_return)
+ l %r1,__LC_KERNEL_STACK # switch to kernel stack
+ s %r1,BASED(.Lc_spsize)
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bno BASED(mcck_return)
+ l %r1,BASED(.Ls390_handle_mcck)
+ basr %r14,%r1 # call machine check handler
mcck_return:
RESTORE_ALL 0
@@ -742,7 +823,7 @@ cleanup_critical:
clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop)
bl BASED(0f)
clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
- bl BASED(cleanup_sysc_leave)
+ bl BASED(cleanup_sysc_return)
0:
br %r14
@@ -760,6 +841,7 @@ cleanup_system_call:
mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
0: st %r13,__LC_SAVE_AREA+20
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
st %r15,__LC_SAVE_AREA+28
lh %r7,0x8a
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn:
* Symbol constants
*/
.Ls390_mcck: .long s390_do_machine_check
+.Ls390_handle_mcck:
+ .long s390_handle_mcck
.Ldo_IRQ: .long do_IRQ
.Ldo_extint: .long do_extint
.Ldo_signal: .long do_signal
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 51527ab8c8f9..57ca75d0ad7f 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -7,6 +7,7 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
_TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13)
@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
jz stack_overflow
3:
#endif
-2: aghi %r15,-SP_SIZE # make room for registers & psw
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ aghi %r15,-SP_SIZE # make room for registers & psw
mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
@@ -152,6 +157,13 @@ __switch_to:
je __switch_to_noper # we got away without bashing TLB's
lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
+ lg %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+ jz __switch_to_no_mcck
+ ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ lg %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
@@ -176,6 +188,7 @@ system_call:
sysc_saveall:
SAVE_ALL_BASE __LC_SAVE_AREA
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
@@ -232,6 +245,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo sysc_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo sysc_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -250,6 +265,13 @@ sysc_reschedule:
jg schedule # return point is sysc_return
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ larl %r14,sysc_work_loop
+ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+#
# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
@@ -474,6 +496,7 @@ pgm_check_handler:
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
jnz pgm_per # got per exception -> special case
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime
@@ -512,6 +535,7 @@ pgm_per:
#
pgm_per_std:
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime2
@@ -537,6 +561,7 @@ pgm_no_vtime2:
#
pgm_svcper:
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime3
@@ -564,6 +589,7 @@ io_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+32
SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz io_no_vtime
@@ -621,9 +647,11 @@ io_work:
lgr %r15,%r1
#
# One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
#
io_work_loop:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo io_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo io_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -631,6 +659,13 @@ io_work_loop:
j io_leave
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ larl %r14,io_work_loop
+ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+#
# _TIF_NEED_RESCHED is set, call schedule
#
io_reschedule:
@@ -661,6 +696,7 @@ ext_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+32
SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz ext_no_vtime
@@ -680,18 +716,60 @@ ext_no_vtime:
*/
.globl mcck_int_handler
mcck_int_handler:
- STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ la %r1,4095 # revalidate r1
+ spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+64
- SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ jo mcck_int_main # yes -> rest of mcck code invalid
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ jo 0f
+ spt __LC_LAST_UPDATE_TIMER
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ jno mcck_no_vtime # no -> no timer update
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
jz mcck_no_vtime
UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
#endif
- brasl %r14,s390_do_machine_check
+0:
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ jno mcck_int_main # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ jnz mcck_int_main # from user -> load kernel stack
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end)
+ jhe mcck_int_main
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+ jl mcck_int_main
+ brasl %r14,cleanup_critical
+mcck_int_main:
+ lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slgr %r14,%r15
+ srag %r14,%r14,PAGE_SHIFT
+ jz 0f
+ lg %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,s390_do_machine_check
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno mcck_return
+ lg %r1,__LC_KERNEL_STACK # switch to kernel stack
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jno mcck_return
+ brasl %r14,s390_handle_mcck
mcck_return:
RESTORE_ALL 0
@@ -775,7 +853,7 @@ cleanup_critical:
clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop)
jl 0f
clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
- jl cleanup_sysc_leave
+ jl cleanup_sysc_return
0:
br %r14
@@ -793,6 +871,7 @@ cleanup_system_call:
mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
0: stg %r13,__LC_SAVE_AREA+40
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
stg %r15,__LC_SAVE_AREA+56
llgh %r7,__LC_SVC_INT_CODE
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c
new file mode 100644
index 000000000000..2721c3a32b84
--- /dev/null
+++ b/arch/s390/kernel/machine_kexec.c
@@ -0,0 +1,98 @@
+/*
+ * arch/s390/kernel/machine_kexec.c
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * s390_machine_kexec.c - handle the transition of Linux booting another kernel
+ * on the S390 architecture.
+ */
+
+#include <asm/cio.h>
+#include <asm/setup.h>
+#include <linux/device.h>
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/system.h>
+
+static void kexec_halt_all_cpus(void *);
+
+typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long);
+
+const extern unsigned char relocate_kernel[];
+const extern unsigned long long relocate_kernel_len;
+
+int
+machine_kexec_prepare(struct kimage *image)
+{
+ unsigned long reboot_code_buffer;
+
+ /* We don't support anything but the default image type for now. */
+ if (image->type != KEXEC_TYPE_DEFAULT)
+ return -EINVAL;
+
+ /* Get the destination where the assembler code should be copied to.*/
+ reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT;
+
+ /* Then copy it */
+ memcpy((void *) reboot_code_buffer, relocate_kernel,
+ relocate_kernel_len);
+ return 0;
+}
+
+void
+machine_kexec_cleanup(struct kimage *image)
+{
+}
+
+void
+machine_shutdown(void)
+{
+ printk(KERN_INFO "kexec: machine_shutdown called\n");
+}
+
+NORET_TYPE void
+machine_kexec(struct kimage *image)
+{
+ clear_all_subchannels();
+
+ /* Disable lowcore protection */
+ ctl_clear_bit(0,28);
+
+ on_each_cpu(kexec_halt_all_cpus, image, 0, 0);
+ for (;;);
+}
+
+static void
+kexec_halt_all_cpus(void *kernel_image)
+{
+ static atomic_t cpuid = ATOMIC_INIT(-1);
+ int cpu;
+ struct kimage *image;
+ relocate_kernel_t data_mover;
+
+ if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid))
+ signal_processor(smp_processor_id(), sigp_stop);
+
+ /* Wait for all other cpus to enter stopped state */
+ for_each_online_cpu(cpu) {
+ if (cpu == smp_processor_id())
+ continue;
+ while (!smp_cpu_not_running(cpu))
+ cpu_relax();
+ }
+
+ image = (struct kimage *) kernel_image;
+ data_mover = (relocate_kernel_t)
+ (page_to_pfn(image->control_code_page) << PAGE_SHIFT);
+
+ /* Call the moving routine */
+ (*data_mover) (&image->head, image->start);
+}
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 7aea25d6e300..9f3dff6c0b72 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code)
(void *)(long) smp_processor_id());
}
+extern void s390_handle_mcck(void);
/*
* The idle loop on a S390...
*/
void default_idle(void)
{
- psw_t wait_psw;
- unsigned long reg;
int cpu, rc;
local_irq_disable();
@@ -125,38 +124,17 @@ void default_idle(void)
cpu_die();
#endif
- /*
- * Wait for external, I/O or machine check interrupt and
- * switch off machine check bit after the wait has ended.
- */
- wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
- PSW_MASK_IO | PSW_MASK_EXT;
-#ifndef CONFIG_ARCH_S390X
- asm volatile (
- " basr %0,0\n"
- "0: la %0,1f-0b(%0)\n"
- " st %0,4(%1)\n"
- " oi 4(%1),0x80\n"
- " lpsw 0(%1)\n"
- "1: la %0,2f-1b(%0)\n"
- " st %0,4(%1)\n"
- " oi 4(%1),0x80\n"
- " ni 1(%1),0xf9\n"
- " lpsw 0(%1)\n"
- "2:"
- : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#else /* CONFIG_ARCH_S390X */
- asm volatile (
- " larl %0,0f\n"
- " stg %0,8(%1)\n"
- " lpswe 0(%1)\n"
- "0: larl %0,1f\n"
- " stg %0,8(%1)\n"
- " ni 1(%1),0xf9\n"
- " lpswe 0(%1)\n"
- "1:"
- : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#endif /* CONFIG_ARCH_S390X */
+ local_mcck_disable();
+ if (test_thread_flag(TIF_MCCK_PENDING)) {
+ local_mcck_enable();
+ local_irq_enable();
+ s390_handle_mcck();
+ return;
+ }
+
+ /* Wait for external, I/O or machine check interrupt. */
+ __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+ PSW_MASK_IO | PSW_MASK_EXT);
}
void cpu_idle(void)
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..d5e4a62fbb79
--- /dev/null
+++ b/arch/s390/kernel/relocate_kernel.S
@@ -0,0 +1,81 @@
+/*
+ * arch/s390/kernel/relocate_kernel.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ * %r10 is a page mask
+ */
+
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+ basr %r13,0 #base address
+ .base:
+ spx zero64-.base(%r13) #absolute addressing mode
+ stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
+ lhi %r10,-1 #preparing the mask
+ sll %r10,12 #shift it such that it becomes 0xf000
+ .top:
+ lhi %r7,4096 #load PAGE_SIZE in r7
+ lhi %r9,4096 #load PAGE_SIZE in r9
+ l %r5,0(%r2) #read another word for indirection page
+ ahi %r2,4 #increment pointer
+ tml %r5,0x1 #is it a destination page?
+ je .indir_check #NO, goto "indir_check"
+ lr %r6,%r5 #r6 = r5
+ nr %r6,%r10 #mask it out and...
+ j .top #...next iteration
+ .indir_check:
+ tml %r5,0x2 #is it a indirection page?
+ je .done_test #NO, goto "done_test"
+ nr %r5,%r10 #YES, mask out,
+ lr %r2,%r5 #move it into the right register,
+ j .top #and read next...
+ .done_test:
+ tml %r5,0x4 #is it the done indicator?
+ je .source_test #NO! Well, then it should be the source indicator...
+ j .done #ok, lets finish it here...
+ .source_test:
+ tml %r5,0x8 #it should be a source indicator...
+ je .top #NO, ignore it...
+ lr %r8,%r5 #r8 = r5
+ nr %r8,%r10 #masking
+ 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ jo 0b
+ j .top
+ .done:
+ sr %r0,%r0 #clear register r0
+ la %r4,load_psw-.base(%r13) #load psw-address into the register
+ o %r3,4(%r4) #or load address into psw
+ st %r3,4(%r4)
+ mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
+ sr %r1,%r1 #clear %r1
+ sr %r2,%r2 #clear %r2
+ sigp %r1,%r2,0x12 #set cpuid to zero
+ lpsw 0 #hopefully start new kernel...
+
+ .align 8
+ zero64:
+ .quad 0
+ load_psw:
+ .long 0x00080000,0x80000000
+ sys_msk:
+ .quad 0
+ relocate_kernel_end:
+ .globl relocate_kernel_len
+ relocate_kernel_len:
+ .quad relocate_kernel_end - relocate_kernel
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S
new file mode 100644
index 000000000000..96290cc4eb3c
--- /dev/null
+++ b/arch/s390/kernel/relocate_kernel64.S
@@ -0,0 +1,82 @@
+/*
+ * arch/s390/kernel/relocate_kernel64.S
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+/*
+ * moves the new kernel to its destination...
+ * %r2 = pointer to first kimage_entry_t
+ * %r3 = start address - where to jump to after the job is done...
+ *
+ * %r5 will be used as temp. storage
+ * %r6 holds the destination address
+ * %r7 = PAGE_SIZE
+ * %r8 holds the source address
+ * %r9 = PAGE_SIZE
+ *
+ * 0xf000 is a page_mask
+ */
+
+ .text
+ .globl relocate_kernel
+ relocate_kernel:
+ basr %r13,0 #base address
+ .base:
+ spx zero64-.base(%r13) #absolute addressing mode
+ stnsm sys_msk-.base(%r13),0xf8 #disable DAT and IRQ (external)
+ .top:
+ lghi %r7,4096 #load PAGE_SIZE in r7
+ lghi %r9,4096 #load PAGE_SIZE in r9
+ lg %r5,0(%r2) #read another word for indirection page
+ aghi %r2,8 #increment pointer
+ tml %r5,0x1 #is it a destination page?
+ je .indir_check #NO, goto "indir_check"
+ lgr %r6,%r5 #r6 = r5
+ nill %r6,0xf000 #mask it out and...
+ j .top #...next iteration
+ .indir_check:
+ tml %r5,0x2 #is it a indirection page?
+ je .done_test #NO, goto "done_test"
+ nill %r5,0xf000 #YES, mask out,
+ lgr %r2,%r5 #move it into the right register,
+ j .top #and read next...
+ .done_test:
+ tml %r5,0x4 #is it the done indicator?
+ je .source_test #NO! Well, then it should be the source indicator...
+ j .done #ok, lets finish it here...
+ .source_test:
+ tml %r5,0x8 #it should be a source indicator...
+ je .top #NO, ignore it...
+ lgr %r8,%r5 #r8 = r5
+ nill %r8,0xf000 #masking
+ 0: mvcle %r6,%r8,0x0 #copy PAGE_SIZE bytes from r8 to r6 - pad with 0
+ jo 0b
+ j .top
+ .done:
+ sgr %r0,%r0 #clear register r0
+ la %r4,load_psw-.base(%r13) #load psw-address into the register
+ o %r3,4(%r4) #or load address into psw
+ st %r3,4(%r4)
+ mvc 0(8,%r0),0(%r4) #copy psw to absolute address 0
+ sam31 #31 bit mode
+ sr %r1,%r1 #erase register r1
+ sr %r2,%r2 #erase register r2
+ sigp %r1,%r2,0x12 #set cpuid to zero
+ lpsw 0 #hopefully start new kernel...
+
+ .align 8
+ zero64:
+ .quad 0
+ load_psw:
+ .long 0x00080000,0x80000000
+ sys_msk:
+ .quad 0
+ relocate_kernel_end:
+ .globl relocate_kernel_len
+ relocate_kernel_len:
+ .quad relocate_kernel_end - relocate_kernel
+
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index df83215beac3..b6d740ac0e6e 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -198,11 +198,11 @@ static void __init conmode_default(void)
char *ptr;
if (MACHINE_IS_VM) {
- __cpcmd("QUERY CONSOLE", query_buffer, 1024);
+ __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL);
console_devno = simple_strtoul(query_buffer + 5, NULL, 16);
ptr = strstr(query_buffer, "SUBCHANNEL =");
console_irq = simple_strtoul(ptr + 13, NULL, 16);
- __cpcmd("QUERY TERM", query_buffer, 1024);
+ __cpcmd("QUERY TERM", query_buffer, 1024, NULL);
ptr = strstr(query_buffer, "CONMODE");
/*
* Set the conmode to 3215 so that the device recognition
@@ -211,7 +211,7 @@ static void __init conmode_default(void)
* 3215 and the 3270 driver will try to access the console
* device (3215 as console and 3270 as normal tty).
*/
- __cpcmd("TERM CONMODE 3215", NULL, 0);
+ __cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
if (ptr == NULL) {
#if defined(CONFIG_SCLP_CONSOLE)
SET_CONSOLE_SCLP;
@@ -414,7 +414,8 @@ setup_lowcore(void)
lc->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
- lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+ lc->mcck_new_psw.mask =
+ PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
lc->mcck_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
lc->io_new_psw.mask = PSW_KERNEL_BITS;
@@ -424,12 +425,18 @@ setup_lowcore(void)
lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
lc->async_stack = (unsigned long)
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
-#ifdef CONFIG_CHECK_STACK
lc->panic_stack = (unsigned long)
__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
-#endif
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
lc->thread_info = (unsigned long) &init_thread_union;
+#ifndef CONFIG_ARCH_S390X
+ if (MACHINE_HAS_IEEE) {
+ lc->extended_save_area_addr = (__u32)
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+ /* enable extended save area */
+ ctl_set_bit(14, 29);
+ }
+#endif
#ifdef CONFIG_ARCH_S390X
if (MACHINE_HAS_DIAG44)
lc->diag44_opcode = 0x83000044;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index fdfcf0488b49..642572a8e334 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -284,7 +284,7 @@ static void do_machine_restart(void * __unused)
* locks are always held disabled).
*/
if (MACHINE_IS_VM)
- cpcmd ("IPL", NULL, 0);
+ cpcmd ("IPL", NULL, 0, NULL);
else
reipl (0x10000 | S390_lowcore.ipl_device);
}
@@ -313,7 +313,7 @@ static void do_machine_halt(void * __unused)
if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0)
- cpcmd(vmhalt_cmd, NULL, 0);
+ cpcmd(vmhalt_cmd, NULL, 0, NULL);
signal_processor(smp_processor_id(),
sigp_stop_and_store_status);
}
@@ -332,7 +332,7 @@ static void do_machine_power_off(void * __unused)
if (atomic_compare_and_swap(-1, smp_processor_id(), &cpuid) == 0) {
smp_send_stop();
if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0)
- cpcmd(vmpoff_cmd, NULL, 0);
+ cpcmd(vmpoff_cmd, NULL, 0, NULL);
signal_processor(smp_processor_id(),
sigp_stop_and_store_status);
}
@@ -679,12 +679,14 @@ __cpu_disable(void)
{
unsigned long flags;
ec_creg_mask_parms cr_parms;
+ int cpu = smp_processor_id();
spin_lock_irqsave(&smp_reserve_lock, flags);
- if (smp_cpu_reserved[smp_processor_id()] != 0) {
+ if (smp_cpu_reserved[cpu] != 0) {
spin_unlock_irqrestore(&smp_reserve_lock, flags);
return -EBUSY;
}
+ cpu_clear(cpu, cpu_online_map);
#ifdef CONFIG_PFAULT
/* Disable pfault pseudo page faults on this cpu. */
@@ -771,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*(lowcore_ptr[i]) = S390_lowcore;
lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
-#ifdef CONFIG_CHECK_STACK
stack = __get_free_pages(GFP_KERNEL,0);
if (stack == 0ULL)
panic("smp_boot_cpus failed to allocate memory\n");
lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
+#ifndef __s390x__
+ if (MACHINE_HAS_IEEE) {
+ lowcore_ptr[i]->extended_save_area_addr =
+ (__u32) __get_free_pages(GFP_KERNEL,0);
+ if (lowcore_ptr[i]->extended_save_area_addr == 0)
+ panic("smp_boot_cpus failed to "
+ "allocate memory\n");
+ }
#endif
}
+#ifndef __s390x__
+ if (MACHINE_HAS_IEEE)
+ ctl_set_bit(14, 29); /* enable extended save area */
+#endif
set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
for_each_cpu(cpu)
diff --git a/arch/s390/kernel/syscalls.S b/arch/s390/kernel/syscalls.S
index 515938628f82..a8668afb5f87 100644
--- a/arch/s390/kernel/syscalls.S
+++ b/arch/s390/kernel/syscalls.S
@@ -285,7 +285,7 @@ SYSCALL(sys_mq_timedsend,sys_mq_timedsend,compat_sys_mq_timedsend_wrapper)
SYSCALL(sys_mq_timedreceive,sys_mq_timedreceive,compat_sys_mq_timedreceive_wrapper)
SYSCALL(sys_mq_notify,sys_mq_notify,compat_sys_mq_notify_wrapper) /* 275 */
SYSCALL(sys_mq_getsetattr,sys_mq_getsetattr,compat_sys_mq_getsetattr_wrapper)
-NI_SYSCALL /* reserved for kexec */
+SYSCALL(sys_kexec_load,sys_kexec_load,compat_sys_kexec_load_wrapper)
SYSCALL(sys_add_key,sys_add_key,compat_sys_add_key_wrapper)
SYSCALL(sys_request_key,sys_request_key,compat_sys_request_key_wrapper)
SYSCALL(sys_keyctl,sys_keyctl,compat_sys_keyctl) /* 280 */
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
index ca34b6f34b38..bc7b7be7acbe 100644
--- a/arch/s390/kernel/traps.c
+++ b/arch/s390/kernel/traps.c
@@ -735,7 +735,7 @@ void __init trap_init(void)
&ext_int_pfault);
#endif
#ifndef CONFIG_ARCH_S390X
- cpcmd("SET PAGEX ON", NULL, 0);
+ cpcmd("SET PAGEX ON", NULL, 0, NULL);
#endif
}
}
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c
index 648deed17e25..c5348108ca3c 100644
--- a/arch/s390/mm/extmem.c
+++ b/arch/s390/mm/extmem.c
@@ -576,8 +576,8 @@ segment_save(char *name)
segtype_string[seg->range[i].start & 0xff]);
}
sprintf(cmd2, "SAVESEG %s", name);
- cpcmd(cmd1, NULL, 0);
- cpcmd(cmd2, NULL, 0);
+ cpcmd(cmd1, NULL, 0, NULL);
+ cpcmd(cmd2, NULL, 0, NULL);
spin_unlock(&dcss_lock);
}
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index a7c8bfc11604..adc8109f8b77 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -784,6 +784,8 @@ config EMBEDDED_RAMDISK_IMAGE
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/sh64/Kconfig b/arch/sh64/Kconfig
index 708e59736a4d..4c3e5334adb3 100644
--- a/arch/sh64/Kconfig
+++ b/arch/sh64/Kconfig
@@ -268,6 +268,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
source "drivers/Kconfig"
source "fs/Kconfig"
diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 262e13d086fe..aca028aa29bf 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
@@ -268,68 +268,14 @@ source "mm/Kconfig"
endmenu
-source "drivers/Kconfig"
-
-config PRINTER
- tristate "Parallel printer support"
- depends on PARPORT
- ---help---
- If you intend to attach a printer to the parallel port of your Linux
- box (as opposed to using a serial printer; if the connector at the
- printer has 9 or 25 holes ["female"], then it's serial), say Y.
- Also read the Printing-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
-
- It is possible to share one parallel port among several devices
- (e.g. printer and ZIP drive) and it is safe to compile the
- corresponding drivers into the kernel. If you want to compile this
- driver as a module however, choose M here and read
- <file:Documentation/parport.txt>. The module will be called lp.
-
- If you have several parallel ports, you can specify which ports to
- use with the "lp" kernel command line option. (Try "man bootparam"
- or see the documentation of your boot loader (silo) about how to pass
- options to the kernel at boot time.) The syntax of the "lp" command
- line option can be found in <file:drivers/char/lp.c>.
-
- If you have more than 8 printers, you need to increase the LP_NO
- macro in lp.c and the PARPORT_MAX macro in parport.h.
-
-source "mm/Kconfig"
-
-endmenu
-
-source "drivers/base/Kconfig"
-
-source "drivers/video/Kconfig"
-
-source "drivers/mtd/Kconfig"
+source "net/Kconfig"
-source "drivers/serial/Kconfig"
+source "drivers/Kconfig"
if !SUN4
source "drivers/sbus/char/Kconfig"
endif
-source "drivers/block/Kconfig"
-
-# Don't frighten a common SBus user
-if PCI
-
-source "drivers/ide/Kconfig"
-
-endif
-
-source "drivers/isdn/Kconfig"
-
-source "drivers/scsi/Kconfig"
-
-source "drivers/fc4/Kconfig"
-
-source "drivers/md/Kconfig"
-
-source "net/Kconfig"
-
# This one must be before the filesystem configs. -DaveM
menu "Unix98 PTY support"
diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S
index 928ffeb0fabb..025f4516e651 100644
--- a/arch/sparc/kernel/systbls.S
+++ b/arch/sparc/kernel/systbls.S
@@ -57,11 +57,11 @@ sys_call_table:
/*180*/ .long sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_sigpending, sys_ni_syscall
/*185*/ .long sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sys_newuname
/*190*/ .long sys_init_module, sys_personality, sparc_remap_file_pages, sys_epoll_create, sys_epoll_ctl
-/*195*/ .long sys_epoll_wait, sys_nis_syscall, sys_getppid, sparc_sigaction, sys_sgetmask
+/*195*/ .long sys_epoll_wait, sys_ioprio_set, sys_getppid, sparc_sigaction, sys_sgetmask
/*200*/ .long sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, old_readdir
/*205*/ .long sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
/*210*/ .long sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
-/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*215*/ .long sys_ipc, sys_sigreturn, sys_clone, sys_ioprio_get, sys_adjtimex
/*220*/ .long sys_sigprocmask, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
/*225*/ .long sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid16, sys_setfsgid16
/*230*/ .long sys_select, sys_time, sys_nis_syscall, sys_stime, sys_statfs64
diff --git a/arch/sparc64/Kconfig b/arch/sparc64/Kconfig
index e2b050eb3b96..9afd28e2c4d5 100644
--- a/arch/sparc64/Kconfig
+++ b/arch/sparc64/Kconfig
@@ -43,6 +43,25 @@ config SPARC64_PAGE_SIZE_4MB
endchoice
+config SECCOMP
+ bool "Enable seccomp to safely compute untrusted bytecode"
+ depends on PROC_FS
+ default y
+ help
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via /proc/<pid>/seccomp, it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
+ If unsure, say Y. Only embedded should say N here.
+
+source kernel/Kconfig.hz
+
source "init/Kconfig"
config SYSVIPC_COMPAT
@@ -444,6 +463,24 @@ config PRINTER
If you have more than 8 printers, you need to increase the LP_NO
macro in lp.c and the PARPORT_MAX macro in parport.h.
+config PPDEV
+ tristate "Support for user-space parallel port device drivers"
+ depends on PARPORT
+ ---help---
+ Saying Y to this adds support for /dev/parport device nodes. This
+ is needed for programs that want portable access to the parallel
+ port, for instance deviceid (which displays Plug-and-Play device
+ IDs).
+
+ This is the parallel port equivalent of SCSI generic support (sg).
+ It is safe to say N to this -- it is not needed for normal printing
+ or parallel port CD-ROM/disk support.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ppdev.
+
+ If unsure, say N.
+
config ENVCTRL
tristate "SUNW, envctrl support"
depends on PCI
@@ -488,6 +525,8 @@ source "mm/Kconfig"
endmenu
+source "net/Kconfig"
+
source "drivers/base/Kconfig"
source "drivers/video/Kconfig"
@@ -514,7 +553,7 @@ endif
source "drivers/ieee1394/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
@@ -610,6 +649,8 @@ source "drivers/input/Kconfig"
source "drivers/i2c/Kconfig"
+source "drivers/hwmon/Kconfig"
+
source "fs/Kconfig"
source "drivers/media/Kconfig"
diff --git a/arch/sparc64/kernel/auxio.c b/arch/sparc64/kernel/auxio.c
index a0716ccc2f4a..8852c20c8d99 100644
--- a/arch/sparc64/kernel/auxio.c
+++ b/arch/sparc64/kernel/auxio.c
@@ -16,7 +16,7 @@
#include <asm/ebus.h>
#include <asm/auxio.h>
-/* This cannot be static, as it is referenced in entry.S */
+/* This cannot be static, as it is referenced in irq.c */
void __iomem *auxio_register = NULL;
enum auxio_type {
diff --git a/arch/sparc64/kernel/dtlb_backend.S b/arch/sparc64/kernel/dtlb_backend.S
index b73a3c858770..538522848ad4 100644
--- a/arch/sparc64/kernel/dtlb_backend.S
+++ b/arch/sparc64/kernel/dtlb_backend.S
@@ -16,7 +16,7 @@
#elif PAGE_SHIFT == 19
#define SZ_BITS _PAGE_SZ512K
#elif PAGE_SHIFT == 22
-#define SZ_BITS _PAGE_SZ4M
+#define SZ_BITS _PAGE_SZ4MB
#endif
#define VALID_SZ_BITS (_PAGE_VALID | SZ_BITS)
diff --git a/arch/sparc64/kernel/entry.S b/arch/sparc64/kernel/entry.S
index a47f2d0b1a29..d781f10adc52 100644
--- a/arch/sparc64/kernel/entry.S
+++ b/arch/sparc64/kernel/entry.S
@@ -22,8 +22,6 @@
#include <asm/estate.h>
#include <asm/auxio.h>
-/* #define SYSCALL_TRACING 1 */
-
#define curptr g6
#define NR_SYSCALLS 284 /* Each OS is different... */
@@ -271,8 +269,9 @@ cplus_fptrap_insn_1:
fmuld %f0, %f2, %f26
faddd %f0, %f2, %f28
fmuld %f0, %f2, %f30
+ membar #Sync
b,pt %xcc, fpdis_exit
- membar #Sync
+ nop
2: andcc %g5, FPRS_DU, %g0
bne,pt %icc, 3f
fzero %f32
@@ -301,8 +300,9 @@ cplus_fptrap_insn_2:
fmuld %f32, %f34, %f58
faddd %f32, %f34, %f60
fmuld %f32, %f34, %f62
+ membar #Sync
ba,pt %xcc, fpdis_exit
- membar #Sync
+ nop
3: mov SECONDARY_CONTEXT, %g3
add %g6, TI_FPREGS, %g1
ldxa [%g3] ASI_DMMU, %g5
@@ -551,13 +551,11 @@ do_ivec:
sllx %g3, 5, %g3
or %g2, %lo(ivector_table), %g2
add %g2, %g3, %g3
- ldx [%g3 + 0x08], %g2 /* irq_info */
ldub [%g3 + 0x04], %g4 /* pil */
- brz,pn %g2, do_ivec_spurious
- mov 1, %g2
-
+ mov 1, %g2
sllx %g2, %g4, %g2
sllx %g4, 2, %g4
+
lduw [%g6 + %g4], %g5 /* g5 = irq_work(cpu, pil) */
stw %g5, [%g3 + 0x00] /* bucket->irq_chain = g5 */
stw %g3, [%g6 + %g4] /* irq_work(cpu, pil) = bucket */
@@ -565,9 +563,9 @@ do_ivec:
retry
do_ivec_xcall:
mov 0x50, %g1
-
ldxa [%g1 + %g0] ASI_INTR_R, %g1
srl %g3, 0, %g3
+
mov 0x60, %g7
ldxa [%g7 + %g0] ASI_INTR_R, %g7
stxa %g0, [%g0] ASI_INTR_RECEIVE
@@ -579,19 +577,6 @@ do_ivec_xcall:
1: jmpl %g3, %g0
nop
-do_ivec_spurious:
- stw %g3, [%g6 + 0x00] /* irq_work(cpu, 0) = bucket */
- rdpr %pstate, %g5
-
- wrpr %g5, PSTATE_IG | PSTATE_AG, %pstate
- sethi %hi(109f), %g7
- ba,pt %xcc, etrap
-109: or %g7, %lo(109b), %g7
- call catch_disabled_ivec
- add %sp, PTREGS_OFF, %o0
- ba,pt %xcc, rtrap
- clr %l6
-
.globl save_alternate_globals
save_alternate_globals: /* %o0 = save_area */
rdpr %pstate, %o5
@@ -699,116 +684,6 @@ utrap_ill:
ba,pt %xcc, rtrap
clr %l6
-#ifdef CONFIG_BLK_DEV_FD
- .globl floppy_hardint
-floppy_hardint:
- wr %g0, (1 << 11), %clear_softint
- sethi %hi(doing_pdma), %g1
- ld [%g1 + %lo(doing_pdma)], %g2
- brz,pn %g2, floppy_dosoftint
- sethi %hi(fdc_status), %g3
- ldx [%g3 + %lo(fdc_status)], %g3
- sethi %hi(pdma_vaddr), %g5
- ldx [%g5 + %lo(pdma_vaddr)], %g4
- sethi %hi(pdma_size), %g5
- ldx [%g5 + %lo(pdma_size)], %g5
-
-next_byte:
- lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7
- andcc %g7, 0x80, %g0
- be,pn %icc, floppy_fifo_emptied
- andcc %g7, 0x20, %g0
- be,pn %icc, floppy_overrun
- andcc %g7, 0x40, %g0
- be,pn %icc, floppy_write
- sub %g5, 1, %g5
-
- inc %g3
- lduba [%g3] ASI_PHYS_BYPASS_EC_E, %g7
- dec %g3
- orcc %g0, %g5, %g0
- stb %g7, [%g4]
- bne,pn %xcc, next_byte
- add %g4, 1, %g4
-
- b,pt %xcc, floppy_tdone
- nop
-
-floppy_write:
- ldub [%g4], %g7
- orcc %g0, %g5, %g0
- inc %g3
- stba %g7, [%g3] ASI_PHYS_BYPASS_EC_E
- dec %g3
- bne,pn %xcc, next_byte
- add %g4, 1, %g4
-
-floppy_tdone:
- sethi %hi(pdma_vaddr), %g1
- stx %g4, [%g1 + %lo(pdma_vaddr)]
- sethi %hi(pdma_size), %g1
- stx %g5, [%g1 + %lo(pdma_size)]
- sethi %hi(auxio_register), %g1
- ldx [%g1 + %lo(auxio_register)], %g7
- lduba [%g7] ASI_PHYS_BYPASS_EC_E, %g5
- or %g5, AUXIO_AUX1_FTCNT, %g5
-/* andn %g5, AUXIO_AUX1_MASK, %g5 */
- stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E
- andn %g5, AUXIO_AUX1_FTCNT, %g5
-/* andn %g5, AUXIO_AUX1_MASK, %g5 */
-
- nop; nop; nop; nop; nop; nop;
- nop; nop; nop; nop; nop; nop;
-
- stba %g5, [%g7] ASI_PHYS_BYPASS_EC_E
- sethi %hi(doing_pdma), %g1
- b,pt %xcc, floppy_dosoftint
- st %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_fifo_emptied:
- sethi %hi(pdma_vaddr), %g1
- stx %g4, [%g1 + %lo(pdma_vaddr)]
- sethi %hi(pdma_size), %g1
- stx %g5, [%g1 + %lo(pdma_size)]
- sethi %hi(irq_action), %g1
- or %g1, %lo(irq_action), %g1
- ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq]
- ldx [%g3 + 0x08], %g4 ! action->flags>>48==ino
- sethi %hi(ivector_table), %g3
- srlx %g4, 48, %g4
- or %g3, %lo(ivector_table), %g3
- sllx %g4, 5, %g4
- ldx [%g3 + %g4], %g4 ! &ivector_table[ino]
- ldx [%g4 + 0x10], %g4 ! bucket->iclr
- stwa %g0, [%g4] ASI_PHYS_BYPASS_EC_E ! ICLR_IDLE
- membar #Sync ! probably not needed...
- retry
-
-floppy_overrun:
- sethi %hi(pdma_vaddr), %g1
- stx %g4, [%g1 + %lo(pdma_vaddr)]
- sethi %hi(pdma_size), %g1
- stx %g5, [%g1 + %lo(pdma_size)]
- sethi %hi(doing_pdma), %g1
- st %g0, [%g1 + %lo(doing_pdma)]
-
-floppy_dosoftint:
- rdpr %pil, %g2
- wrpr %g0, 15, %pil
- sethi %hi(109f), %g7
- b,pt %xcc, etrap_irq
-109: or %g7, %lo(109b), %g7
-
- mov 11, %o0
- mov 0, %o1
- call sparc_floppy_irq
- add %sp, PTREGS_OFF, %o2
-
- b,pt %xcc, rtrap_irq
- nop
-
-#endif /* CONFIG_BLK_DEV_FD */
-
/* XXX Here is stuff we still need to write... -DaveM XXX */
.globl netbsd_syscall
netbsd_syscall:
@@ -1677,11 +1552,12 @@ sys_ptrace: add %sp, PTREGS_OFF, %o0
nop
.align 32
1: ldx [%curptr + TI_FLAGS], %l5
- andcc %l5, _TIF_SYSCALL_TRACE, %g0
+ andcc %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
be,pt %icc, rtrap
clr %l6
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- nop
+ mov 1, %o1
ba,pt %xcc, rtrap
clr %l6
@@ -1765,18 +1641,20 @@ linux_sparc_ni_syscall:
or %l7, %lo(sys_ni_syscall), %l7
linux_syscall_trace32:
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- nop
+ clr %o1
srl %i0, 0, %o0
- mov %i4, %o4
+ srl %i4, 0, %o4
srl %i1, 0, %o1
srl %i2, 0, %o2
b,pt %xcc, 2f
srl %i3, 0, %o3
linux_syscall_trace:
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- nop
+ clr %o1
mov %i0, %o0
mov %i1, %o1
mov %i2, %o2
@@ -1794,11 +1672,6 @@ linux_sparc_syscall32:
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
srl %i0, 0, %o0 ! IEU0
sll %g1, 2, %l4 ! IEU0 Group
-#ifdef SYSCALL_TRACING
- call syscall_trace_entry
- add %sp, PTREGS_OFF, %o0
- srl %i0, 0, %o0
-#endif
srl %i4, 0, %o4 ! IEU1
lduw [%l7 + %l4], %l7 ! Load
srl %i1, 0, %o1 ! IEU0 Group
@@ -1806,7 +1679,7 @@ linux_sparc_syscall32:
srl %i5, 0, %o5 ! IEU1
srl %i2, 0, %o2 ! IEU0 Group
- andcc %l0, _TIF_SYSCALL_TRACE, %g0 ! IEU0 Group
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
bne,pn %icc, linux_syscall_trace32 ! CTI
mov %i0, %l5 ! IEU1
call %l7 ! CTI Group brk forced
@@ -1822,11 +1695,6 @@ linux_sparc_syscall:
bgeu,pn %xcc, linux_sparc_ni_syscall ! CTI
mov %i0, %o0 ! IEU0
sll %g1, 2, %l4 ! IEU0 Group
-#ifdef SYSCALL_TRACING
- call syscall_trace_entry
- add %sp, PTREGS_OFF, %o0
- mov %i0, %o0
-#endif
mov %i1, %o1 ! IEU1
lduw [%l7 + %l4], %l7 ! Load
4: mov %i2, %o2 ! IEU0 Group
@@ -1834,7 +1702,7 @@ linux_sparc_syscall:
mov %i3, %o3 ! IEU1
mov %i4, %o4 ! IEU0 Group
- andcc %l0, _TIF_SYSCALL_TRACE, %g0 ! IEU1 Group+1 bubble
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %g0
bne,pn %icc, linux_syscall_trace ! CTI Group
mov %i0, %l5 ! IEU0
2: call %l7 ! CTI Group brk forced
@@ -1843,12 +1711,6 @@ linux_sparc_syscall:
3: stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
ret_sys_call:
-#ifdef SYSCALL_TRACING
- mov %o0, %o1
- call syscall_trace_exit
- add %sp, PTREGS_OFF, %o0
- mov %o1, %o0
-#endif
ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %g3
ldx [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
sra %o0, 0, %o0
@@ -1868,7 +1730,7 @@ ret_sys_call:
1:
cmp %o0, -ERESTART_RESTARTBLOCK
bgeu,pn %xcc, 1f
- andcc %l0, _TIF_SYSCALL_TRACE, %l6
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
80:
/* System call success, clear Carry condition code. */
andn %g3, %g2, %g3
@@ -1883,7 +1745,7 @@ ret_sys_call:
/* System call failure, set Carry condition code.
* Also, get abs(errno) to return to the process.
*/
- andcc %l0, _TIF_SYSCALL_TRACE, %l6
+ andcc %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT), %l6
sub %g0, %o0, %o0
or %g3, %g2, %g3
stx %o0, [%sp + PTREGS_OFF + PT_V9_I0]
@@ -1896,8 +1758,9 @@ ret_sys_call:
b,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
linux_syscall_trace2:
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- nop
+ mov 1, %o1
stx %l1, [%sp + PTREGS_OFF + PT_V9_TPC]
ba,pt %xcc, rtrap
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC]
diff --git a/arch/sparc64/kernel/irq.c b/arch/sparc64/kernel/irq.c
index 4dcb8af94090..daa2fb93052c 100644
--- a/arch/sparc64/kernel/irq.c
+++ b/arch/sparc64/kernel/irq.c
@@ -37,6 +37,7 @@
#include <asm/uaccess.h>
#include <asm/cache.h>
#include <asm/cpudata.h>
+#include <asm/auxio.h>
#ifdef CONFIG_SMP
static void distribute_irqs(void);
@@ -70,31 +71,7 @@ struct irq_work_struct {
struct irq_work_struct __irq_work[NR_CPUS];
#define irq_work(__cpu, __pil) &(__irq_work[(__cpu)].irq_worklists[(__pil)])
-#ifdef CONFIG_PCI
-/* This is a table of physical addresses used to deal with IBF_DMA_SYNC.
- * It is used for PCI only to synchronize DMA transfers with IRQ delivery
- * for devices behind busses other than APB on Sabre systems.
- *
- * Currently these physical addresses are just config space accesses
- * to the command register for that device.
- */
-unsigned long pci_dma_wsync;
-unsigned long dma_sync_reg_table[256];
-unsigned char dma_sync_reg_table_entry = 0;
-#endif
-
-/* This is based upon code in the 32-bit Sparc kernel written mostly by
- * David Redman (djhr@tadpole.co.uk).
- */
-#define MAX_STATIC_ALLOC 4
-static struct irqaction static_irqaction[MAX_STATIC_ALLOC];
-static int static_irq_count;
-
-/* This is exported so that fast IRQ handlers can get at it... -DaveM */
-struct irqaction *irq_action[NR_IRQS+1] = {
- NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL
-};
+static struct irqaction *irq_action[NR_IRQS+1];
/* This only synchronizes entities which modify IRQ handler
* state and some selected user-level spots that want to
@@ -240,17 +217,22 @@ void disable_irq(unsigned int irq)
* the CPU %tick register and not by some normal vectored interrupt
* source. To handle this special case, we use this dummy INO bucket.
*/
+static struct irq_desc pil0_dummy_desc;
static struct ino_bucket pil0_dummy_bucket = {
- 0, /* irq_chain */
- 0, /* pil */
- 0, /* pending */
- 0, /* flags */
- 0, /* __unused */
- NULL, /* irq_info */
- 0UL, /* iclr */
- 0UL, /* imap */
+ .irq_info = &pil0_dummy_desc,
};
+static void build_irq_error(const char *msg, unsigned int ino, int pil, int inofixup,
+ unsigned long iclr, unsigned long imap,
+ struct ino_bucket *bucket)
+{
+ prom_printf("IRQ: INO %04x (%d:%016lx:%016lx) --> "
+ "(%d:%d:%016lx:%016lx), halting...\n",
+ ino, bucket->pil, bucket->iclr, bucket->imap,
+ pil, inofixup, iclr, imap);
+ prom_halt();
+}
+
unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap)
{
struct ino_bucket *bucket;
@@ -279,28 +261,35 @@ unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long
prom_halt();
}
- /* Ok, looks good, set it up. Don't touch the irq_chain or
- * the pending flag.
- */
bucket = &ivector_table[ino];
- if ((bucket->flags & IBF_ACTIVE) ||
- (bucket->irq_info != NULL)) {
- /* This is a gross fatal error if it happens here. */
- prom_printf("IRQ: Trying to reinit INO bucket, fatal error.\n");
- prom_printf("IRQ: Request INO %04x (%d:%d:%016lx:%016lx)\n",
- ino, pil, inofixup, iclr, imap);
- prom_printf("IRQ: Existing (%d:%016lx:%016lx)\n",
- bucket->pil, bucket->iclr, bucket->imap);
- prom_printf("IRQ: Cannot continue, halting...\n");
+ if (bucket->flags & IBF_ACTIVE)
+ build_irq_error("IRQ: Trying to build active INO bucket.\n",
+ ino, pil, inofixup, iclr, imap, bucket);
+
+ if (bucket->irq_info) {
+ if (bucket->imap != imap || bucket->iclr != iclr)
+ build_irq_error("IRQ: Trying to reinit INO bucket.\n",
+ ino, pil, inofixup, iclr, imap, bucket);
+
+ goto out;
+ }
+
+ bucket->irq_info = kmalloc(sizeof(struct irq_desc), GFP_ATOMIC);
+ if (!bucket->irq_info) {
+ prom_printf("IRQ: Error, kmalloc(irq_desc) failed.\n");
prom_halt();
}
+ memset(bucket->irq_info, 0, sizeof(struct irq_desc));
+
+ /* Ok, looks good, set it up. Don't touch the irq_chain or
+ * the pending flag.
+ */
bucket->imap = imap;
bucket->iclr = iclr;
bucket->pil = pil;
bucket->flags = 0;
- bucket->irq_info = NULL;
-
+out:
return __irq(bucket);
}
@@ -318,26 +307,65 @@ static void atomic_bucket_insert(struct ino_bucket *bucket)
__asm__ __volatile__("wrpr %0, 0x0, %%pstate" : : "r" (pstate));
}
+static int check_irq_sharing(int pil, unsigned long irqflags)
+{
+ struct irqaction *action, *tmp;
+
+ action = *(irq_action + pil);
+ if (action) {
+ if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ)) {
+ for (tmp = action; tmp->next; tmp = tmp->next)
+ ;
+ } else {
+ return -EBUSY;
+ }
+ }
+ return 0;
+}
+
+static void append_irq_action(int pil, struct irqaction *action)
+{
+ struct irqaction **pp = irq_action + pil;
+
+ while (*pp)
+ pp = &((*pp)->next);
+ *pp = action;
+}
+
+static struct irqaction *get_action_slot(struct ino_bucket *bucket)
+{
+ struct irq_desc *desc = bucket->irq_info;
+ int max_irq, i;
+
+ max_irq = 1;
+ if (bucket->flags & IBF_PCI)
+ max_irq = MAX_IRQ_DESC_ACTION;
+ for (i = 0; i < max_irq; i++) {
+ struct irqaction *p = &desc->action[i];
+ u32 mask = (1 << i);
+
+ if (desc->action_active_mask & mask)
+ continue;
+
+ desc->action_active_mask |= mask;
+ return p;
+ }
+ return NULL;
+}
+
int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags, const char *name, void *dev_id)
{
- struct irqaction *action, *tmp = NULL;
+ struct irqaction *action;
struct ino_bucket *bucket = __bucket(irq);
unsigned long flags;
int pending = 0;
- if ((bucket != &pil0_dummy_bucket) &&
- (bucket < &ivector_table[0] ||
- bucket >= &ivector_table[NUM_IVECS])) {
- unsigned int *caller;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- printk(KERN_CRIT "request_irq: Old style IRQ registry attempt "
- "from %p, irq %08x.\n", caller, irq);
+ if (unlikely(!handler))
return -EINVAL;
- }
- if (!handler)
- return -EINVAL;
+
+ if (unlikely(!bucket->irq_info))
+ return -ENODEV;
if ((bucket != &pil0_dummy_bucket) && (irqflags & SA_SAMPLE_RANDOM)) {
/*
@@ -355,93 +383,20 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_
spin_lock_irqsave(&irq_action_lock, flags);
- action = *(bucket->pil + irq_action);
- if (action) {
- if ((action->flags & SA_SHIRQ) && (irqflags & SA_SHIRQ))
- for (tmp = action; tmp->next; tmp = tmp->next)
- ;
- else {
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -EBUSY;
- }
- action = NULL; /* Or else! */
+ if (check_irq_sharing(bucket->pil, irqflags)) {
+ spin_unlock_irqrestore(&irq_action_lock, flags);
+ return -EBUSY;
}
- /* If this is flagged as statically allocated then we use our
- * private struct which is never freed.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
- "using kmalloc\n", irq, name);
- }
- if (action == NULL)
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
- GFP_ATOMIC);
-
+ action = get_action_slot(bucket);
if (!action) {
spin_unlock_irqrestore(&irq_action_lock, flags);
return -ENOMEM;
}
- if (bucket == &pil0_dummy_bucket) {
- bucket->irq_info = action;
- bucket->flags |= IBF_ACTIVE;
- } else {
- if ((bucket->flags & IBF_ACTIVE) != 0) {
- void *orig = bucket->irq_info;
- void **vector = NULL;
-
- if ((bucket->flags & IBF_PCI) == 0) {
- printk("IRQ: Trying to share non-PCI bucket.\n");
- goto free_and_ebusy;
- }
- if ((bucket->flags & IBF_MULTI) == 0) {
- vector = kmalloc(sizeof(void *) * 4, GFP_ATOMIC);
- if (vector == NULL)
- goto free_and_enomem;
-
- /* We might have slept. */
- if ((bucket->flags & IBF_MULTI) != 0) {
- int ent;
-
- kfree(vector);
- vector = (void **)bucket->irq_info;
- for(ent = 0; ent < 4; ent++) {
- if (vector[ent] == NULL) {
- vector[ent] = action;
- break;
- }
- }
- if (ent == 4)
- goto free_and_ebusy;
- } else {
- vector[0] = orig;
- vector[1] = action;
- vector[2] = NULL;
- vector[3] = NULL;
- bucket->irq_info = vector;
- bucket->flags |= IBF_MULTI;
- }
- } else {
- int ent;
-
- vector = (void **)orig;
- for (ent = 0; ent < 4; ent++) {
- if (vector[ent] == NULL) {
- vector[ent] = action;
- break;
- }
- }
- if (ent == 4)
- goto free_and_ebusy;
- }
- } else {
- bucket->irq_info = action;
- bucket->flags |= IBF_ACTIVE;
- }
+ bucket->flags |= IBF_ACTIVE;
+ pending = 0;
+ if (bucket != &pil0_dummy_bucket) {
pending = bucket->pending;
if (pending)
bucket->pending = 0;
@@ -455,10 +410,7 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_
put_ino_in_irqaction(action, irq);
put_smpaff_in_irqaction(action, CPU_MASK_NONE);
- if (tmp)
- tmp->next = action;
- else
- *(bucket->pil + irq_action) = action;
+ append_irq_action(bucket->pil, action);
enable_irq(irq);
@@ -467,147 +419,103 @@ int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_
atomic_bucket_insert(bucket);
set_softint(1 << bucket->pil);
}
+
spin_unlock_irqrestore(&irq_action_lock, flags);
- if ((bucket != &pil0_dummy_bucket) && (!(irqflags & SA_STATIC_ALLOC)))
+
+ if (bucket != &pil0_dummy_bucket)
register_irq_proc(__irq_ino(irq));
#ifdef CONFIG_SMP
distribute_irqs();
#endif
return 0;
-
-free_and_ebusy:
- kfree(action);
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -EBUSY;
-
-free_and_enomem:
- kfree(action);
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -ENOMEM;
}
EXPORT_SYMBOL(request_irq);
-void free_irq(unsigned int irq, void *dev_id)
+static struct irqaction *unlink_irq_action(unsigned int irq, void *dev_id)
{
- struct irqaction *action;
- struct irqaction *tmp = NULL;
- unsigned long flags;
- struct ino_bucket *bucket = __bucket(irq), *bp;
-
- if ((bucket != &pil0_dummy_bucket) &&
- (bucket < &ivector_table[0] ||
- bucket >= &ivector_table[NUM_IVECS])) {
- unsigned int *caller;
+ struct ino_bucket *bucket = __bucket(irq);
+ struct irqaction *action, **pp;
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- printk(KERN_CRIT "free_irq: Old style IRQ removal attempt "
- "from %p, irq %08x.\n", caller, irq);
- return;
- }
-
- spin_lock_irqsave(&irq_action_lock, flags);
+ pp = irq_action + bucket->pil;
+ action = *pp;
+ if (unlikely(!action))
+ return NULL;
- action = *(bucket->pil + irq_action);
- if (!action->handler) {
+ if (unlikely(!action->handler)) {
printk("Freeing free IRQ %d\n", bucket->pil);
- return;
- }
- if (dev_id) {
- for ( ; action; action = action->next) {
- if (action->dev_id == dev_id)
- break;
- tmp = action;
- }
- if (!action) {
- printk("Trying to free free shared IRQ %d\n", bucket->pil);
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return;
- }
- } else if (action->flags & SA_SHIRQ) {
- printk("Trying to free shared IRQ %d with NULL device ID\n", bucket->pil);
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return;
+ return NULL;
}
- if (action->flags & SA_STATIC_ALLOC) {
- printk("Attempt to free statically allocated IRQ %d (%s)\n",
- bucket->pil, action->name);
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return;
+ while (action && action->dev_id != dev_id) {
+ pp = &action->next;
+ action = *pp;
}
- if (action && tmp)
- tmp->next = action->next;
- else
- *(bucket->pil + irq_action) = action->next;
+ if (likely(action))
+ *pp = action->next;
+
+ return action;
+}
+
+void free_irq(unsigned int irq, void *dev_id)
+{
+ struct irqaction *action;
+ struct ino_bucket *bucket;
+ unsigned long flags;
+
+ spin_lock_irqsave(&irq_action_lock, flags);
+
+ action = unlink_irq_action(irq, dev_id);
spin_unlock_irqrestore(&irq_action_lock, flags);
+ if (unlikely(!action))
+ return;
+
synchronize_irq(irq);
spin_lock_irqsave(&irq_action_lock, flags);
+ bucket = __bucket(irq);
if (bucket != &pil0_dummy_bucket) {
+ struct irq_desc *desc = bucket->irq_info;
unsigned long imap = bucket->imap;
- void **vector, *orig;
- int ent;
-
- orig = bucket->irq_info;
- vector = (void **)orig;
-
- if ((bucket->flags & IBF_MULTI) != 0) {
- int other = 0;
- void *orphan = NULL;
- for (ent = 0; ent < 4; ent++) {
- if (vector[ent] == action)
- vector[ent] = NULL;
- else if (vector[ent] != NULL) {
- orphan = vector[ent];
- other++;
- }
- }
+ int ent, i;
- /* Only free when no other shared irq
- * uses this bucket.
- */
- if (other) {
- if (other == 1) {
- /* Convert back to non-shared bucket. */
- bucket->irq_info = orphan;
- bucket->flags &= ~(IBF_MULTI);
- kfree(vector);
- }
- goto out;
+ for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
+ struct irqaction *p = &desc->action[i];
+
+ if (p == action) {
+ desc->action_active_mask &= ~(1 << i);
+ break;
}
- } else {
- bucket->irq_info = NULL;
}
- /* This unique interrupt source is now inactive. */
- bucket->flags &= ~IBF_ACTIVE;
+ if (!desc->action_active_mask) {
+ /* This unique interrupt source is now inactive. */
+ bucket->flags &= ~IBF_ACTIVE;
- /* See if any other buckets share this bucket's IMAP
- * and are still active.
- */
- for (ent = 0; ent < NUM_IVECS; ent++) {
- bp = &ivector_table[ent];
- if (bp != bucket &&
- bp->imap == imap &&
- (bp->flags & IBF_ACTIVE) != 0)
- break;
- }
+ /* See if any other buckets share this bucket's IMAP
+ * and are still active.
+ */
+ for (ent = 0; ent < NUM_IVECS; ent++) {
+ struct ino_bucket *bp = &ivector_table[ent];
+ if (bp != bucket &&
+ bp->imap == imap &&
+ (bp->flags & IBF_ACTIVE) != 0)
+ break;
+ }
- /* Only disable when no other sub-irq levels of
- * the same IMAP are active.
- */
- if (ent == NUM_IVECS)
- disable_irq(irq);
+ /* Only disable when no other sub-irq levels of
+ * the same IMAP are active.
+ */
+ if (ent == NUM_IVECS)
+ disable_irq(irq);
+ }
}
-out:
- kfree(action);
spin_unlock_irqrestore(&irq_action_lock, flags);
}
@@ -646,99 +554,55 @@ void synchronize_irq(unsigned int irq)
}
#endif /* CONFIG_SMP */
-void catch_disabled_ivec(struct pt_regs *regs)
-{
- int cpu = smp_processor_id();
- struct ino_bucket *bucket = __bucket(*irq_work(cpu, 0));
-
- /* We can actually see this on Ultra/PCI PCI cards, which are bridges
- * to other devices. Here a single IMAP enabled potentially multiple
- * unique interrupt sources (which each do have a unique ICLR register.
- *
- * So what we do is just register that the IVEC arrived, when registered
- * for real the request_irq() code will check the bit and signal
- * a local CPU interrupt for it.
- */
-#if 0
- printk("IVEC: Spurious interrupt vector (%x) received at (%016lx)\n",
- bucket - &ivector_table[0], regs->tpc);
-#endif
- *irq_work(cpu, 0) = 0;
- bucket->pending = 1;
-}
-
-/* Tune this... */
-#define FORWARD_VOLUME 12
-
-#ifdef CONFIG_SMP
-
-static inline void redirect_intr(int cpu, struct ino_bucket *bp)
+static void process_bucket(int irq, struct ino_bucket *bp, struct pt_regs *regs)
{
- /* Ok, here is what is going on:
- * 1) Retargeting IRQs on Starfire is very
- * expensive so just forget about it on them.
- * 2) Moving around very high priority interrupts
- * is a losing game.
- * 3) If the current cpu is idle, interrupts are
- * useful work, so keep them here. But do not
- * pass to our neighbour if he is not very idle.
- * 4) If sysadmin explicitly asks for directed intrs,
- * Just Do It.
- */
- struct irqaction *ap = bp->irq_info;
- cpumask_t cpu_mask;
- unsigned int buddy, ticks;
+ struct irq_desc *desc = bp->irq_info;
+ unsigned char flags = bp->flags;
+ u32 action_mask, i;
+ int random;
- cpu_mask = get_smpaff_in_irqaction(ap);
- cpus_and(cpu_mask, cpu_mask, cpu_online_map);
- if (cpus_empty(cpu_mask))
- cpu_mask = cpu_online_map;
+ bp->flags |= IBF_INPROGRESS;
- if (this_is_starfire != 0 ||
- bp->pil >= 10 || current->pid == 0)
+ if (unlikely(!(flags & IBF_ACTIVE))) {
+ bp->pending = 1;
goto out;
-
- /* 'cpu' is the MID (ie. UPAID), calculate the MID
- * of our buddy.
- */
- buddy = cpu + 1;
- if (buddy >= NR_CPUS)
- buddy = 0;
-
- ticks = 0;
- while (!cpu_isset(buddy, cpu_mask)) {
- if (++buddy >= NR_CPUS)
- buddy = 0;
- if (++ticks > NR_CPUS) {
- put_smpaff_in_irqaction(ap, CPU_MASK_NONE);
- goto out;
- }
}
- if (buddy == cpu)
- goto out;
+ if (desc->pre_handler)
+ desc->pre_handler(bp,
+ desc->pre_handler_arg1,
+ desc->pre_handler_arg2);
- /* Voo-doo programming. */
- if (cpu_data(buddy).idle_volume < FORWARD_VOLUME)
- goto out;
+ action_mask = desc->action_active_mask;
+ random = 0;
+ for (i = 0; i < MAX_IRQ_DESC_ACTION; i++) {
+ struct irqaction *p = &desc->action[i];
+ u32 mask = (1 << i);
- /* This just so happens to be correct on Cheetah
- * at the moment.
- */
- buddy <<= 26;
+ if (!(action_mask & mask))
+ continue;
- /* Push it to our buddy. */
- upa_writel(buddy | IMAP_VALID, bp->imap);
+ action_mask &= ~mask;
+ if (p->handler(__irq(bp), p->dev_id, regs) == IRQ_HANDLED)
+ random |= p->flags;
+
+ if (!action_mask)
+ break;
+ }
+ if (bp->pil != 0) {
+ upa_writel(ICLR_IDLE, bp->iclr);
+ /* Test and add entropy */
+ if (random & SA_SAMPLE_RANDOM)
+ add_interrupt_randomness(irq);
+ }
out:
- return;
+ bp->flags &= ~IBF_INPROGRESS;
}
-#endif
-
void handler_irq(int irq, struct pt_regs *regs)
{
- struct ino_bucket *bp, *nbp;
+ struct ino_bucket *bp;
int cpu = smp_processor_id();
#ifndef CONFIG_SMP
@@ -756,8 +620,6 @@ void handler_irq(int irq, struct pt_regs *regs)
clear_softint(clr_mask);
}
#else
- int should_forward = 0;
-
clear_softint(1 << irq);
#endif
@@ -772,199 +634,76 @@ void handler_irq(int irq, struct pt_regs *regs)
#else
bp = __bucket(xchg32(irq_work(cpu, irq), 0));
#endif
- for ( ; bp != NULL; bp = nbp) {
- unsigned char flags = bp->flags;
- unsigned char random = 0;
+ while (bp) {
+ struct ino_bucket *nbp = __bucket(bp->irq_chain);
- nbp = __bucket(bp->irq_chain);
bp->irq_chain = 0;
-
- bp->flags |= IBF_INPROGRESS;
-
- if ((flags & IBF_ACTIVE) != 0) {
-#ifdef CONFIG_PCI
- if ((flags & IBF_DMA_SYNC) != 0) {
- upa_readl(dma_sync_reg_table[bp->synctab_ent]);
- upa_readq(pci_dma_wsync);
- }
-#endif
- if ((flags & IBF_MULTI) == 0) {
- struct irqaction *ap = bp->irq_info;
- 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) {
- int ret;
-
- ret = ap->handler(__irq(bp),
- ap->dev_id,
- regs);
- if (ret == IRQ_HANDLED)
- random |= ap->flags;
- }
- }
- }
- /* Only the dummy bucket lacks IMAP/ICLR. */
- if (bp->pil != 0) {
-#ifdef CONFIG_SMP
- if (should_forward) {
- redirect_intr(cpu, bp);
- should_forward = 0;
- }
-#endif
- upa_writel(ICLR_IDLE, bp->iclr);
-
- /* Test and add entropy */
- if (random & SA_SAMPLE_RANDOM)
- add_interrupt_randomness(irq);
- }
- } else
- bp->pending = 1;
-
- bp->flags &= ~IBF_INPROGRESS;
+ process_bucket(irq, bp, regs);
+ bp = nbp;
}
irq_exit();
}
#ifdef CONFIG_BLK_DEV_FD
-extern void floppy_interrupt(int irq, void *dev_cookie, struct pt_regs *regs);
-
-void sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
-{
- struct irqaction *action = *(irq + irq_action);
- struct ino_bucket *bucket;
- int cpu = smp_processor_id();
-
- irq_enter();
- kstat_this_cpu.irqs[irq]++;
-
- *(irq_work(cpu, irq)) = 0;
- bucket = get_ino_in_irqaction(action) + ivector_table;
-
- bucket->flags |= IBF_INPROGRESS;
-
- floppy_interrupt(irq, dev_cookie, regs);
- upa_writel(ICLR_IDLE, bucket->iclr);
+extern irqreturn_t floppy_interrupt(int, void *, struct pt_regs *);;
- bucket->flags &= ~IBF_INPROGRESS;
+/* XXX No easy way to include asm/floppy.h XXX */
+extern unsigned char *pdma_vaddr;
+extern unsigned long pdma_size;
+extern volatile int doing_pdma;
+extern unsigned long fdc_status;
- irq_exit();
-}
-#endif
-
-/* The following assumes that the branch lies before the place we
- * are branching to. This is the case for a trap vector...
- * You have been warned.
- */
-#define SPARC_BRANCH(dest_addr, inst_addr) \
- (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff))
-
-#define SPARC_NOP (0x01000000)
-
-static void install_fast_irq(unsigned int cpu_irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *))
+irqreturn_t sparc_floppy_irq(int irq, void *dev_cookie, struct pt_regs *regs)
{
- extern unsigned long sparc64_ttable_tl0;
- unsigned long ttent = (unsigned long) &sparc64_ttable_tl0;
- unsigned int *insns;
-
- ttent += 0x820;
- ttent += (cpu_irq - 1) << 5;
- insns = (unsigned int *) ttent;
- insns[0] = SPARC_BRANCH(((unsigned long) handler),
- ((unsigned long)&insns[0]));
- insns[1] = SPARC_NOP;
- __asm__ __volatile__("membar #StoreStore; flush %0" : : "r" (ttent));
-}
-
-int request_fast_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags, const char *name, void *dev_id)
-{
- struct irqaction *action;
- struct ino_bucket *bucket = __bucket(irq);
- unsigned long flags;
-
- /* No pil0 dummy buckets allowed here. */
- if (bucket < &ivector_table[0] ||
- bucket >= &ivector_table[NUM_IVECS]) {
- unsigned int *caller;
-
- __asm__ __volatile__("mov %%i7, %0" : "=r" (caller));
- printk(KERN_CRIT "request_fast_irq: Old style IRQ registry attempt "
- "from %p, irq %08x.\n", caller, irq);
- return -EINVAL;
- }
-
- if (!handler)
- return -EINVAL;
+ if (likely(doing_pdma)) {
+ void __iomem *stat = (void __iomem *) fdc_status;
+ unsigned char *vaddr = pdma_vaddr;
+ unsigned long size = pdma_size;
+ u8 val;
+
+ while (size) {
+ val = readb(stat);
+ if (unlikely(!(val & 0x80))) {
+ pdma_vaddr = vaddr;
+ pdma_size = size;
+ return IRQ_HANDLED;
+ }
+ if (unlikely(!(val & 0x20))) {
+ pdma_vaddr = vaddr;
+ pdma_size = size;
+ doing_pdma = 0;
+ goto main_interrupt;
+ }
+ if (val & 0x40) {
+ /* read */
+ *vaddr++ = readb(stat + 1);
+ } else {
+ unsigned char data = *vaddr++;
- if ((bucket->pil == 0) || (bucket->pil == 14)) {
- printk("request_fast_irq: Trying to register shared IRQ 0 or 14.\n");
- return -EBUSY;
- }
+ /* write */
+ writeb(data, stat + 1);
+ }
+ size--;
+ }
- spin_lock_irqsave(&irq_action_lock, flags);
+ pdma_vaddr = vaddr;
+ pdma_size = size;
- action = *(bucket->pil + irq_action);
- if (action) {
- if (action->flags & SA_SHIRQ)
- panic("Trying to register fast irq when already shared.\n");
- if (irqflags & SA_SHIRQ)
- panic("Trying to register fast irq as shared.\n");
- printk("request_fast_irq: Trying to register yet already owned.\n");
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -EBUSY;
- }
+ /* Send Terminal Count pulse to floppy controller. */
+ val = readb(auxio_register);
+ val |= AUXIO_AUX1_FTCNT;
+ writeb(val, auxio_register);
+ val &= AUXIO_AUX1_FTCNT;
+ writeb(val, auxio_register);
- /*
- * We do not check for SA_SAMPLE_RANDOM in this path. Neither do we
- * support smp intr affinity in this path.
- */
- if (irqflags & SA_STATIC_ALLOC) {
- if (static_irq_count < MAX_STATIC_ALLOC)
- action = &static_irqaction[static_irq_count++];
- else
- printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed "
- "using kmalloc\n", bucket->pil, name);
- }
- if (action == NULL)
- action = (struct irqaction *)kmalloc(sizeof(struct irqaction),
- GFP_ATOMIC);
- if (!action) {
- spin_unlock_irqrestore(&irq_action_lock, flags);
- return -ENOMEM;
+ doing_pdma = 0;
}
- install_fast_irq(bucket->pil, handler);
-
- bucket->irq_info = action;
- bucket->flags |= IBF_ACTIVE;
-
- action->handler = handler;
- action->flags = irqflags;
- action->dev_id = NULL;
- action->name = name;
- action->next = NULL;
- put_ino_in_irqaction(action, irq);
- put_smpaff_in_irqaction(action, CPU_MASK_NONE);
-
- *(bucket->pil + irq_action) = action;
- enable_irq(irq);
- spin_unlock_irqrestore(&irq_action_lock, flags);
-
-#ifdef CONFIG_SMP
- distribute_irqs();
-#endif
- return 0;
+main_interrupt:
+ return floppy_interrupt(irq, dev_cookie, regs);
}
+EXPORT_SYMBOL(sparc_floppy_irq);
+#endif
/* We really don't need these at all on the Sparc. We only have
* stubs here because they are exported to modules.
@@ -1030,7 +769,10 @@ static void distribute_irqs(void)
*/
for (level = 1; level < NR_IRQS; level++) {
struct irqaction *p = irq_action[level];
- if (level == 12) continue;
+
+ if (level == 12)
+ continue;
+
while(p) {
cpu = retarget_one_irq(p, cpu);
p = p->next;
@@ -1175,7 +917,8 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off,
int count, int *eof, void *data)
{
struct ino_bucket *bp = ivector_table + (long)data;
- struct irqaction *ap = bp->irq_info;
+ struct irq_desc *desc = bp->irq_info;
+ struct irqaction *ap = desc->action;
cpumask_t mask;
int len;
@@ -1193,11 +936,13 @@ static int irq_affinity_read_proc (char *page, char **start, off_t off,
static inline void set_intr_affinity(int irq, cpumask_t hw_aff)
{
struct ino_bucket *bp = ivector_table + irq;
+ struct irq_desc *desc = bp->irq_info;
+ struct irqaction *ap = desc->action;
/* Users specify affinity in terms of hw cpu ids.
* As soon as we do this, handler_irq() might see and take action.
*/
- put_smpaff_in_irqaction((struct irqaction *)bp->irq_info, hw_aff);
+ put_smpaff_in_irqaction(ap, hw_aff);
/* Migration is simply done by the next cpu to service this
* interrupt.
diff --git a/arch/sparc64/kernel/kprobes.c b/arch/sparc64/kernel/kprobes.c
index bdac631cf011..bbf11f85dab1 100644
--- a/arch/sparc64/kernel/kprobes.c
+++ b/arch/sparc64/kernel/kprobes.c
@@ -433,3 +433,8 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
+/* architecture specific initialization */
+int arch_init_kprobes(void)
+{
+ return 0;
+}
diff --git a/arch/sparc64/kernel/pci_psycho.c b/arch/sparc64/kernel/pci_psycho.c
index 534320ef0db2..91ab466d6c66 100644
--- a/arch/sparc64/kernel/pci_psycho.c
+++ b/arch/sparc64/kernel/pci_psycho.c
@@ -1303,8 +1303,7 @@ static void psycho_controller_hwinit(struct pci_controller_info *p)
{
u64 tmp;
- /* PROM sets the IRQ retry value too low, increase it. */
- psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 0xff);
+ psycho_write(p->pbm_A.controller_regs + PSYCHO_IRQ_RETRY, 5);
/* Enable arbiter for all PCI slots. */
tmp = psycho_read(p->pbm_A.controller_regs + PSYCHO_PCIA_CTRL);
diff --git a/arch/sparc64/kernel/pci_sabre.c b/arch/sparc64/kernel/pci_sabre.c
index 53d333b4a4e8..52bf3431a422 100644
--- a/arch/sparc64/kernel/pci_sabre.c
+++ b/arch/sparc64/kernel/pci_sabre.c
@@ -595,6 +595,23 @@ static int __init sabre_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
return ret;
}
+/* When a device lives behind a bridge deeper in the PCI bus topology
+ * than APB, a special sequence must run to make sure all pending DMA
+ * transfers at the time of IRQ delivery are visible in the coherency
+ * domain by the cpu. This sequence is to perform a read on the far
+ * side of the non-APB bridge, then perform a read of Sabre's DMA
+ * write-sync register.
+ */
+static void sabre_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
+{
+ struct pci_dev *pdev = _arg1;
+ unsigned long sync_reg = (unsigned long) _arg2;
+ u16 _unused;
+
+ pci_read_config_word(pdev, PCI_VENDOR_ID, &_unused);
+ sabre_read(sync_reg);
+}
+
static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int ino)
@@ -639,24 +656,14 @@ static unsigned int __init sabre_irq_build(struct pci_pbm_info *pbm,
if (pdev) {
struct pcidev_cookie *pcp = pdev->sysdata;
- /* When a device lives behind a bridge deeper in the
- * PCI bus topology than APB, a special sequence must
- * run to make sure all pending DMA transfers at the
- * time of IRQ delivery are visible in the coherency
- * domain by the cpu. This sequence is to perform
- * a read on the far side of the non-APB bridge, then
- * perform a read of Sabre's DMA write-sync register.
- *
- * Currently, the PCI_CONFIG register for the device
- * is used for this read from the far side of the bridge.
- */
if (pdev->bus->number != pcp->pbm->pci_first_busno) {
- bucket->flags |= IBF_DMA_SYNC;
- bucket->synctab_ent = dma_sync_reg_table_entry++;
- dma_sync_reg_table[bucket->synctab_ent] =
- (unsigned long) sabre_pci_config_mkaddr(
- pcp->pbm,
- pdev->bus->number, pdev->devfn, PCI_COMMAND);
+ struct pci_controller_info *p = pcp->pbm->parent;
+ struct irq_desc *d = bucket->irq_info;
+
+ d->pre_handler = sabre_wsync_handler;
+ d->pre_handler_arg1 = pdev;
+ d->pre_handler_arg2 = (void *)
+ p->pbm_A.controller_regs + SABRE_WRSYNC;
}
}
return __irq(bucket);
@@ -1626,10 +1633,9 @@ void __init sabre_init(int pnode, char *model_name)
*/
p->pbm_A.controller_regs = pr_regs[0].phys_addr;
p->pbm_B.controller_regs = pr_regs[0].phys_addr;
- pci_dma_wsync = p->pbm_A.controller_regs + SABRE_WRSYNC;
- printk("PCI: Found SABRE, main regs at %016lx, wsync at %016lx\n",
- p->pbm_A.controller_regs, pci_dma_wsync);
+ printk("PCI: Found SABRE, main regs at %016lx\n",
+ p->pbm_A.controller_regs);
/* Clear interrupts */
diff --git a/arch/sparc64/kernel/pci_schizo.c b/arch/sparc64/kernel/pci_schizo.c
index 5753175b94e6..6a182bb66281 100644
--- a/arch/sparc64/kernel/pci_schizo.c
+++ b/arch/sparc64/kernel/pci_schizo.c
@@ -15,6 +15,7 @@
#include <asm/iommu.h>
#include <asm/irq.h>
#include <asm/upa.h>
+#include <asm/pstate.h>
#include "pci_impl.h"
#include "iommu_common.h"
@@ -326,6 +327,44 @@ static int __init schizo_ino_to_pil(struct pci_dev *pdev, unsigned int ino)
return ret;
}
+static void tomatillo_wsync_handler(struct ino_bucket *bucket, void *_arg1, void *_arg2)
+{
+ unsigned long sync_reg = (unsigned long) _arg2;
+ u64 mask = 1 << (__irq_ino(__irq(bucket)) & IMAP_INO);
+ u64 val;
+ int limit;
+
+ schizo_write(sync_reg, mask);
+
+ limit = 100000;
+ val = 0;
+ while (--limit) {
+ val = schizo_read(sync_reg);
+ if (!(val & mask))
+ break;
+ }
+ if (limit <= 0) {
+ printk("tomatillo_wsync_handler: DMA won't sync [%lx:%lx]\n",
+ val, mask);
+ }
+
+ if (_arg1) {
+ static unsigned char cacheline[64]
+ __attribute__ ((aligned (64)));
+
+ __asm__ __volatile__("rd %%fprs, %0\n\t"
+ "or %0, %4, %1\n\t"
+ "wr %1, 0x0, %%fprs\n\t"
+ "stda %%f0, [%5] %6\n\t"
+ "wr %0, 0x0, %%fprs\n\t"
+ "membar #Sync"
+ : "=&r" (mask), "=&r" (val)
+ : "0" (mask), "1" (val),
+ "i" (FPRS_FEF), "r" (&cacheline[0]),
+ "i" (ASI_BLK_COMMIT_P));
+ }
+}
+
static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
struct pci_dev *pdev,
unsigned int ino)
@@ -369,6 +408,15 @@ static unsigned int schizo_irq_build(struct pci_pbm_info *pbm,
bucket = __bucket(build_irq(pil, ign_fixup, iclr, imap));
bucket->flags |= IBF_PCI;
+ if (pdev && pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO) {
+ struct irq_desc *p = bucket->irq_info;
+
+ p->pre_handler = tomatillo_wsync_handler;
+ p->pre_handler_arg1 = ((pbm->chip_version <= 4) ?
+ (void *) 1 : (void *) 0);
+ p->pre_handler_arg2 = (void *) pbm->sync_reg;
+ }
+
return __irq(bucket);
}
@@ -885,6 +933,7 @@ static irqreturn_t schizo_ce_intr(int irq, void *dev_id, struct pt_regs *regs)
#define SCHIZO_PCI_CTRL (0x2000UL)
#define SCHIZO_PCICTRL_BUS_UNUS (1UL << 63UL) /* Safari */
+#define SCHIZO_PCICTRL_DTO_INT (1UL << 61UL) /* Tomatillo */
#define SCHIZO_PCICTRL_ARB_PRIO (0x1ff << 52UL) /* Tomatillo */
#define SCHIZO_PCICTRL_ESLCK (1UL << 51UL) /* Safari */
#define SCHIZO_PCICTRL_ERRSLOT (7UL << 48UL) /* Safari */
@@ -1887,37 +1936,27 @@ static void __init schizo_pbm_hw_init(struct pci_pbm_info *pbm)
{
u64 tmp;
- /* Set IRQ retry to infinity. */
- schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY,
- SCHIZO_IRQ_RETRY_INF);
+ schizo_write(pbm->pbm_regs + SCHIZO_PCI_IRQ_RETRY, 5);
- /* Enable arbiter for all PCI slots. Also, disable PCI interval
- * timer so that DTO (Discard TimeOuts) are not reported because
- * some Schizo revisions report them erroneously.
- */
tmp = schizo_read(pbm->pbm_regs + SCHIZO_PCI_CTRL);
- if (pbm->chip_type == PBM_CHIP_TYPE_SCHIZO_PLUS &&
- pbm->chip_version == 0x5 &&
- pbm->chip_revision == 0x1)
- tmp |= 0x0f;
- else
- tmp |= 0xff;
- tmp &= ~SCHIZO_PCICTRL_PTO;
+ /* Enable arbiter for all PCI slots. */
+ tmp |= 0xff;
+
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
pbm->chip_version >= 0x2)
tmp |= 0x3UL << SCHIZO_PCICTRL_PTO_SHIFT;
- else
- tmp |= 0x1UL << SCHIZO_PCICTRL_PTO_SHIFT;
if (!prom_getbool(pbm->prom_node, "no-bus-parking"))
tmp |= SCHIZO_PCICTRL_PARK;
+ else
+ tmp &= ~SCHIZO_PCICTRL_PARK;
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO &&
pbm->chip_version <= 0x1)
- tmp |= (1UL << 61);
+ tmp |= SCHIZO_PCICTRL_DTO_INT;
else
- tmp &= ~(1UL << 61);
+ tmp &= ~SCHIZO_PCICTRL_DTO_INT;
if (pbm->chip_type == PBM_CHIP_TYPE_TOMATILLO)
tmp |= (SCHIZO_PCICTRL_MRM_PREF |
@@ -2015,6 +2054,9 @@ static void __init schizo_pbm_init(struct pci_controller_info *p,
pbm->pbm_regs = pr_regs[0].phys_addr;
pbm->controller_regs = pr_regs[1].phys_addr - 0x10000UL;
+ if (chip_type == PBM_CHIP_TYPE_TOMATILLO)
+ pbm->sync_reg = pr_regs[3].phys_addr + 0x1a18UL;
+
sprintf(pbm->name,
(chip_type == PBM_CHIP_TYPE_TOMATILLO ?
"TOMATILLO%d PBM%c" :
diff --git a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
index 52f14e399b1c..533104c7907d 100644
--- a/arch/sparc64/kernel/power.c
+++ b/arch/sparc64/kernel/power.c
@@ -4,6 +4,8 @@
* Copyright (C) 1999 David S. Miller (davem@redhat.com)
*/
+#define __KERNEL_SYSCALLS__
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -17,7 +19,6 @@
#include <asm/ebus.h>
#include <asm/auxio.h>
-#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
/*
diff --git a/arch/sparc64/kernel/ptrace.c b/arch/sparc64/kernel/ptrace.c
index 80a76e2ad732..23ad839d113f 100644
--- a/arch/sparc64/kernel/ptrace.c
+++ b/arch/sparc64/kernel/ptrace.c
@@ -19,6 +19,8 @@
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/security.h>
+#include <linux/seccomp.h>
+#include <linux/audit.h>
#include <linux/signal.h>
#include <asm/asi.h>
@@ -628,15 +630,27 @@ out:
unlock_kernel();
}
-asmlinkage void syscall_trace(void)
+asmlinkage void syscall_trace(struct pt_regs *regs, int syscall_exit_p)
{
-#ifdef DEBUG_PTRACE
- printk("%s [%d]: syscall_trace\n", current->comm, current->pid);
-#endif
- if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
+ /* do the secure computing check first */
+ secure_computing(regs->u_regs[UREG_G1]);
+
+ if (unlikely(current->audit_context) && syscall_exit_p) {
+ unsigned long tstate = regs->tstate;
+ int result = AUDITSC_SUCCESS;
+
+ if (unlikely(tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
+ result = AUDITSC_FAILURE;
+
+ audit_syscall_exit(current, result, regs->u_regs[UREG_I0]);
+ }
+
if (!(current->ptrace & PT_PTRACED))
- return;
+ goto out;
+
+ if (!test_thread_flag(TIF_SYSCALL_TRACE))
+ goto out;
+
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
@@ -645,12 +659,20 @@ asmlinkage void syscall_trace(void)
* for normal use. strace only continues with a signal if the
* stopping signal is not SIGTRAP. -brl
*/
-#ifdef DEBUG_PTRACE
- printk("%s [%d]: syscall_trace exit= %x\n", current->comm,
- current->pid, current->exit_code);
-#endif
if (current->exit_code) {
- send_sig (current->exit_code, current, 1);
+ send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
+
+out:
+ if (unlikely(current->audit_context) && !syscall_exit_p)
+ audit_syscall_entry(current,
+ (test_thread_flag(TIF_32BIT) ?
+ AUDIT_ARCH_SPARC :
+ AUDIT_ARCH_SPARC64),
+ regs->u_regs[UREG_G1],
+ regs->u_regs[UREG_I0],
+ regs->u_regs[UREG_I1],
+ regs->u_regs[UREG_I2],
+ regs->u_regs[UREG_I3]);
}
diff --git a/arch/sparc64/kernel/semaphore.c b/arch/sparc64/kernel/semaphore.c
index 63496c43fe17..a809e63f03ef 100644
--- a/arch/sparc64/kernel/semaphore.c
+++ b/arch/sparc64/kernel/semaphore.c
@@ -32,8 +32,9 @@ static __inline__ int __sem_update_count(struct semaphore *sem, int incr)
" add %1, %4, %1\n"
" cas [%3], %0, %1\n"
" cmp %0, %1\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
: "=&r" (old_count), "=&r" (tmp), "=m" (sem->count)
: "r" (&sem->count), "r" (incr), "m" (sem->count)
: "cc");
@@ -71,8 +72,9 @@ void up(struct semaphore *sem)
" cmp %%g1, %%g7\n"
" bne,pn %%icc, 1b\n"
" addcc %%g7, 1, %%g0\n"
+" membar #StoreLoad | #StoreStore\n"
" ble,pn %%icc, 3f\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
"2:\n"
" .subsection 2\n"
"3: mov %0, %%g1\n"
@@ -128,8 +130,9 @@ void __sched down(struct semaphore *sem)
" cmp %%g1, %%g7\n"
" bne,pn %%icc, 1b\n"
" cmp %%g7, 1\n"
+" membar #StoreLoad | #StoreStore\n"
" bl,pn %%icc, 3f\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
"2:\n"
" .subsection 2\n"
"3: mov %0, %%g1\n"
@@ -233,8 +236,9 @@ int __sched down_interruptible(struct semaphore *sem)
" cmp %%g1, %%g7\n"
" bne,pn %%icc, 1b\n"
" cmp %%g7, 1\n"
+" membar #StoreLoad | #StoreStore\n"
" bl,pn %%icc, 3f\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
"2:\n"
" .subsection 2\n"
"3: mov %2, %%g1\n"
diff --git a/arch/sparc64/kernel/smp.c b/arch/sparc64/kernel/smp.c
index e5b9c7a27789..7e8e2919e186 100644
--- a/arch/sparc64/kernel/smp.c
+++ b/arch/sparc64/kernel/smp.c
@@ -45,8 +45,8 @@ extern void calibrate_delay(void);
/* Please don't make this stuff initdata!!! --DaveM */
static unsigned char boot_cpu_id;
-cpumask_t cpu_online_map = CPU_MASK_NONE;
-cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+cpumask_t cpu_online_map __read_mostly = CPU_MASK_NONE;
+cpumask_t phys_cpu_present_map __read_mostly = CPU_MASK_NONE;
static cpumask_t smp_commenced_mask;
static cpumask_t cpu_callout_map;
@@ -155,7 +155,7 @@ void cpu_panic(void)
panic("SMP bolixed\n");
}
-static unsigned long current_tick_offset;
+static unsigned long current_tick_offset __read_mostly;
/* This tick register synchronization scheme is taken entirely from
* the ia64 port, see arch/ia64/kernel/smpboot.c for details and credit.
@@ -1193,8 +1193,8 @@ void smp_send_stop(void)
{
}
-unsigned long __per_cpu_base;
-unsigned long __per_cpu_shift;
+unsigned long __per_cpu_base __read_mostly;
+unsigned long __per_cpu_shift __read_mostly;
EXPORT_SYMBOL(__per_cpu_base);
EXPORT_SYMBOL(__per_cpu_shift);
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
index e78cc53594fa..9202d925a9ce 100644
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -79,7 +79,7 @@ extern void linux_sparc_syscall(void);
extern void rtrap(void);
extern void show_regs(struct pt_regs *);
extern void solaris_syscall(void);
-extern void syscall_trace(void);
+extern void syscall_trace(struct pt_regs *, int);
extern u32 sunos_sys_table[], sys_call_table32[];
extern void tl0_solaris(void);
extern void sys_sigsuspend(void);
@@ -227,7 +227,6 @@ EXPORT_SYMBOL(__flush_dcache_range);
EXPORT_SYMBOL(mostek_lock);
EXPORT_SYMBOL(mstk48t02_regs);
-EXPORT_SYMBOL(request_fast_irq);
#ifdef CONFIG_SUN_AUXIO
EXPORT_SYMBOL(auxio_set_led);
EXPORT_SYMBOL(auxio_set_lte);
diff --git a/arch/sparc64/kernel/sys32.S b/arch/sparc64/kernel/sys32.S
index 5a95e98c5317..5f9e4fae612e 100644
--- a/arch/sparc64/kernel/sys32.S
+++ b/arch/sparc64/kernel/sys32.S
@@ -135,6 +135,8 @@ SIGN2(sys32_shutdown, sys_shutdown, %o0, %o1)
SIGN3(sys32_socketpair, sys_socketpair, %o0, %o1, %o2)
SIGN1(sys32_getpeername, sys_getpeername, %o0)
SIGN1(sys32_getsockname, sys_getsockname, %o0)
+SIGN2(sys32_ioprio_get, sys_ioprio_get, %o0, %o1)
+SIGN3(sys32_ioprio_set, sys_ioprio_set, %o0, %o1, %o2)
.globl sys32_mmap2
sys32_mmap2:
diff --git a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S
index a5e36a4c8924..bceb91a8a2bd 100644
--- a/arch/sparc64/kernel/systbls.S
+++ b/arch/sparc64/kernel/systbls.S
@@ -59,11 +59,11 @@ sys_call_table32:
/*180*/ .word sys32_flistxattr, sys_removexattr, sys_lremovexattr, compat_sys_sigpending, sys_ni_syscall
.word sys32_setpgid, sys32_fremovexattr, sys32_tkill, sys32_exit_group, sparc64_newuname
/*190*/ .word sys32_init_module, sparc64_personality, sys_remap_file_pages, sys32_epoll_create, sys32_epoll_ctl
- .word sys32_epoll_wait, sys_nis_syscall, sys_getppid, sys32_sigaction, sys_sgetmask
+ .word sys32_epoll_wait, sys32_ioprio_set, sys_getppid, sys32_sigaction, sys_sgetmask
/*200*/ .word sys32_ssetmask, sys_sigsuspend, compat_sys_newlstat, sys_uselib, compat_sys_old_readdir
.word sys32_readahead, sys32_socketcall, sys32_syslog, sys32_lookup_dcookie, sys32_fadvise64
/*210*/ .word sys32_fadvise64_64, sys32_tgkill, sys32_waitpid, sys_swapoff, sys32_sysinfo
- .word sys32_ipc, sys32_sigreturn, sys_clone, sys_nis_syscall, sys32_adjtimex
+ .word sys32_ipc, sys32_sigreturn, sys_clone, sys32_ioprio_get, sys32_adjtimex
/*220*/ .word sys32_sigprocmask, sys_ni_syscall, sys32_delete_module, sys_ni_syscall, sys32_getpgid
.word sys32_bdflush, sys32_sysfs, sys_nis_syscall, sys32_setfsuid16, sys32_setfsgid16
/*230*/ .word sys32_select, compat_sys_time, sys_nis_syscall, compat_sys_stime, compat_sys_statfs64
@@ -125,11 +125,11 @@ sys_call_table:
/*180*/ .word sys_flistxattr, sys_removexattr, sys_lremovexattr, sys_nis_syscall, sys_ni_syscall
.word sys_setpgid, sys_fremovexattr, sys_tkill, sys_exit_group, sparc64_newuname
/*190*/ .word sys_init_module, sparc64_personality, sys_remap_file_pages, sys_epoll_create, sys_epoll_ctl
- .word sys_epoll_wait, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
+ .word sys_epoll_wait, sys_ioprio_set, sys_getppid, sys_nis_syscall, sys_sgetmask
/*200*/ .word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
.word sys_readahead, sys_socketcall, sys_syslog, sys_lookup_dcookie, sys_fadvise64
/*210*/ .word sys_fadvise64_64, sys_tgkill, sys_waitpid, sys_swapoff, sys_sysinfo
- .word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
+ .word sys_ipc, sys_nis_syscall, sys_clone, sys_ioprio_get, sys_adjtimex
/*220*/ .word sys_nis_syscall, sys_ni_syscall, sys_delete_module, sys_ni_syscall, sys_getpgid
.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
/*230*/ .word sys_select, sys_nis_syscall, sys_nis_syscall, sys_stime, sys_statfs64
diff --git a/arch/sparc64/kernel/time.c b/arch/sparc64/kernel/time.c
index 71b4e3807694..362b9c26871b 100644
--- a/arch/sparc64/kernel/time.c
+++ b/arch/sparc64/kernel/time.c
@@ -73,7 +73,7 @@ static __initdata struct sparc64_tick_ops dummy_tick_ops = {
.get_tick = dummy_get_tick,
};
-struct sparc64_tick_ops *tick_ops = &dummy_tick_ops;
+struct sparc64_tick_ops *tick_ops __read_mostly = &dummy_tick_ops;
#define TICK_PRIV_BIT (1UL << 63)
@@ -195,7 +195,7 @@ static unsigned long tick_add_tick(unsigned long adj, unsigned long offset)
return new_tick;
}
-static struct sparc64_tick_ops tick_operations = {
+static struct sparc64_tick_ops tick_operations __read_mostly = {
.init_tick = tick_init_tick,
.get_tick = tick_get_tick,
.get_compare = tick_get_compare,
@@ -276,7 +276,7 @@ static unsigned long stick_add_compare(unsigned long adj)
return new_compare;
}
-static struct sparc64_tick_ops stick_operations = {
+static struct sparc64_tick_ops stick_operations __read_mostly = {
.init_tick = stick_init_tick,
.get_tick = stick_get_tick,
.get_compare = stick_get_compare,
@@ -422,7 +422,7 @@ static unsigned long hbtick_add_compare(unsigned long adj)
return val;
}
-static struct sparc64_tick_ops hbtick_operations = {
+static struct sparc64_tick_ops hbtick_operations __read_mostly = {
.init_tick = hbtick_init_tick,
.get_tick = hbtick_get_tick,
.get_compare = hbtick_get_compare,
@@ -437,10 +437,9 @@ static struct sparc64_tick_ops hbtick_operations = {
* NOTE: On SUN5 systems the ticker interrupt comes in using 2
* interrupts, one at level14 and one with softint bit 0.
*/
-unsigned long timer_tick_offset;
-unsigned long timer_tick_compare;
+unsigned long timer_tick_offset __read_mostly;
-static unsigned long timer_ticks_per_nsec_quotient;
+static unsigned long timer_ticks_per_nsec_quotient __read_mostly;
#define TICK_SIZE (tick_nsec / 1000)
@@ -464,7 +463,7 @@ static inline void timer_check_rtc(void)
static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
{
- unsigned long ticks, pstate;
+ unsigned long ticks, compare, pstate;
write_seqlock(&xtime_lock);
@@ -483,14 +482,14 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
: "=r" (pstate)
: "i" (PSTATE_IE));
- timer_tick_compare = tick_ops->add_compare(timer_tick_offset);
+ compare = tick_ops->add_compare(timer_tick_offset);
ticks = tick_ops->get_tick();
/* Restore PSTATE_IE. */
__asm__ __volatile__("wrpr %0, 0x0, %%pstate"
: /* no outputs */
: "r" (pstate));
- } while (time_after_eq(ticks, timer_tick_compare));
+ } while (time_after_eq(ticks, compare));
timer_check_rtc();
@@ -506,11 +505,6 @@ void timer_tick_interrupt(struct pt_regs *regs)
do_timer(regs);
- /*
- * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.
- */
- timer_tick_compare = tick_ops->get_compare() + timer_tick_offset;
-
timer_check_rtc();
write_sequnlock(&xtime_lock);
@@ -973,7 +967,7 @@ static void sparc64_start_timers(irqreturn_t (*cfunc)(int, void *, struct pt_reg
int err;
/* Register IRQ handler. */
- err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, SA_STATIC_ALLOC,
+ err = request_irq(build_irq(0, 0, 0UL, 0UL), cfunc, 0,
"timer", NULL);
if (err) {
diff --git a/arch/sparc64/kernel/trampoline.S b/arch/sparc64/kernel/trampoline.S
index 2c8f9344b4ee..3a145fc39cf2 100644
--- a/arch/sparc64/kernel/trampoline.S
+++ b/arch/sparc64/kernel/trampoline.S
@@ -98,8 +98,9 @@ startup_continue:
sethi %hi(prom_entry_lock), %g2
1: ldstub [%g2 + %lo(prom_entry_lock)], %g1
+ membar #StoreLoad | #StoreStore
brnz,pn %g1, 1b
- membar #StoreLoad | #StoreStore
+ nop
sethi %hi(p1275buf), %g2
or %g2, %lo(p1275buf), %g2
diff --git a/arch/sparc64/kernel/vmlinux.lds.S b/arch/sparc64/kernel/vmlinux.lds.S
index 382fd6798bb9..950423da8a6a 100644
--- a/arch/sparc64/kernel/vmlinux.lds.S
+++ b/arch/sparc64/kernel/vmlinux.lds.S
@@ -32,6 +32,8 @@ SECTIONS
.data1 : { *(.data1) }
. = ALIGN(64);
.data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ . = ALIGN(64);
+ .data.read_mostly : { *(.data.read_mostly) }
_edata = .;
PROVIDE (edata = .);
.fixup : { *(.fixup) }
diff --git a/arch/sparc64/lib/U1memcpy.S b/arch/sparc64/lib/U1memcpy.S
index da9b520c7189..bafd2fc07acb 100644
--- a/arch/sparc64/lib/U1memcpy.S
+++ b/arch/sparc64/lib/U1memcpy.S
@@ -87,14 +87,17 @@
#define LOOP_CHUNK3(src, dest, len, branch_dest) \
MAIN_LOOP_CHUNK(src, dest, f32, f48, len, branch_dest)
+#define DO_SYNC membar #Sync;
#define STORE_SYNC(dest, fsrc) \
EX_ST(STORE_BLK(%fsrc, %dest)); \
- add %dest, 0x40, %dest;
+ add %dest, 0x40, %dest; \
+ DO_SYNC
#define STORE_JUMP(dest, fsrc, target) \
EX_ST(STORE_BLK(%fsrc, %dest)); \
add %dest, 0x40, %dest; \
- ba,pt %xcc, target;
+ ba,pt %xcc, target; \
+ nop;
#define FINISH_VISCHUNK(dest, f0, f1, left) \
subcc %left, 8, %left;\
@@ -239,17 +242,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
- STORE_JUMP(o0, f48, 40f) membar #Sync
+ STORE_JUMP(o0, f48, 40f)
2: FREG_FROB(f32,f34,f36,f38,f40,f42,f44,f46,f0)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
- STORE_JUMP(o0, f48, 48f) membar #Sync
+ STORE_JUMP(o0, f48, 48f)
3: FREG_FROB(f0, f2, f4, f6, f8, f10,f12,f14,f16)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f16,f18,f20,f22,f24,f26,f28,f30,f32)
- STORE_JUMP(o0, f48, 56f) membar #Sync
+ STORE_JUMP(o0, f48, 56f)
1: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -260,17 +263,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
- STORE_JUMP(o0, f48, 41f) membar #Sync
+ STORE_JUMP(o0, f48, 41f)
2: FREG_FROB(f34,f36,f38,f40,f42,f44,f46,f0, f2)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
- STORE_JUMP(o0, f48, 49f) membar #Sync
+ STORE_JUMP(o0, f48, 49f)
3: FREG_FROB(f2, f4, f6, f8, f10,f12,f14,f16,f18)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f18,f20,f22,f24,f26,f28,f30,f32,f34)
- STORE_JUMP(o0, f48, 57f) membar #Sync
+ STORE_JUMP(o0, f48, 57f)
1: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -281,17 +284,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
- STORE_JUMP(o0, f48, 42f) membar #Sync
+ STORE_JUMP(o0, f48, 42f)
2: FREG_FROB(f36,f38,f40,f42,f44,f46,f0, f2, f4)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
- STORE_JUMP(o0, f48, 50f) membar #Sync
+ STORE_JUMP(o0, f48, 50f)
3: FREG_FROB(f4, f6, f8, f10,f12,f14,f16,f18,f20)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f20,f22,f24,f26,f28,f30,f32,f34,f36)
- STORE_JUMP(o0, f48, 58f) membar #Sync
+ STORE_JUMP(o0, f48, 58f)
1: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -302,17 +305,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
- STORE_JUMP(o0, f48, 43f) membar #Sync
+ STORE_JUMP(o0, f48, 43f)
2: FREG_FROB(f38,f40,f42,f44,f46,f0, f2, f4, f6)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
- STORE_JUMP(o0, f48, 51f) membar #Sync
+ STORE_JUMP(o0, f48, 51f)
3: FREG_FROB(f6, f8, f10,f12,f14,f16,f18,f20,f22)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f22,f24,f26,f28,f30,f32,f34,f36,f38)
- STORE_JUMP(o0, f48, 59f) membar #Sync
+ STORE_JUMP(o0, f48, 59f)
1: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -323,17 +326,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
- STORE_JUMP(o0, f48, 44f) membar #Sync
+ STORE_JUMP(o0, f48, 44f)
2: FREG_FROB(f40,f42,f44,f46,f0, f2, f4, f6, f8)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
- STORE_JUMP(o0, f48, 52f) membar #Sync
+ STORE_JUMP(o0, f48, 52f)
3: FREG_FROB(f8, f10,f12,f14,f16,f18,f20,f22,f24)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f24,f26,f28,f30,f32,f34,f36,f38,f40)
- STORE_JUMP(o0, f48, 60f) membar #Sync
+ STORE_JUMP(o0, f48, 60f)
1: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -344,17 +347,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
- STORE_JUMP(o0, f48, 45f) membar #Sync
+ STORE_JUMP(o0, f48, 45f)
2: FREG_FROB(f42,f44,f46,f0, f2, f4, f6, f8, f10)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
- STORE_JUMP(o0, f48, 53f) membar #Sync
+ STORE_JUMP(o0, f48, 53f)
3: FREG_FROB(f10,f12,f14,f16,f18,f20,f22,f24,f26)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f26,f28,f30,f32,f34,f36,f38,f40,f42)
- STORE_JUMP(o0, f48, 61f) membar #Sync
+ STORE_JUMP(o0, f48, 61f)
1: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -365,17 +368,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
- STORE_JUMP(o0, f48, 46f) membar #Sync
+ STORE_JUMP(o0, f48, 46f)
2: FREG_FROB(f44,f46,f0, f2, f4, f6, f8, f10,f12)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
- STORE_JUMP(o0, f48, 54f) membar #Sync
+ STORE_JUMP(o0, f48, 54f)
3: FREG_FROB(f12,f14,f16,f18,f20,f22,f24,f26,f28)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f28,f30,f32,f34,f36,f38,f40,f42,f44)
- STORE_JUMP(o0, f48, 62f) membar #Sync
+ STORE_JUMP(o0, f48, 62f)
1: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
LOOP_CHUNK1(o1, o0, GLOBAL_SPARE, 1f)
@@ -386,17 +389,17 @@ FUNC_NAME: /* %o0=dst, %o1=src, %o2=len */
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
+ STORE_SYNC(o0, f48)
FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
- STORE_JUMP(o0, f48, 47f) membar #Sync
+ STORE_JUMP(o0, f48, 47f)
2: FREG_FROB(f46,f0, f2, f4, f6, f8, f10,f12,f14)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
- STORE_JUMP(o0, f48, 55f) membar #Sync
+ STORE_JUMP(o0, f48, 55f)
3: FREG_FROB(f14,f16,f18,f20,f22,f24,f26,f28,f30)
- STORE_SYNC(o0, f48) membar #Sync
+ STORE_SYNC(o0, f48)
FREG_FROB(f30,f32,f34,f36,f38,f40,f42,f44,f46)
- STORE_JUMP(o0, f48, 63f) membar #Sync
+ STORE_JUMP(o0, f48, 63f)
40: FINISH_VISCHUNK(o0, f0, f2, g3)
41: FINISH_VISCHUNK(o0, f2, f4, g3)
diff --git a/arch/sparc64/lib/VISsave.S b/arch/sparc64/lib/VISsave.S
index 65e328d600a8..4e18989bd602 100644
--- a/arch/sparc64/lib/VISsave.S
+++ b/arch/sparc64/lib/VISsave.S
@@ -72,7 +72,11 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3
stda %f48, [%g3 + %g1] ASI_BLK_P
5: membar #Sync
- jmpl %g7 + %g0, %g0
+ ba,pt %xcc, 80f
+ nop
+
+ .align 32
+80: jmpl %g7 + %g0, %g0
nop
6: ldub [%g3 + TI_FPSAVED], %o5
@@ -87,8 +91,11 @@ vis1: ldub [%g6 + TI_FPSAVED], %g3
stda %f32, [%g2 + %g1] ASI_BLK_P
stda %f48, [%g3 + %g1] ASI_BLK_P
membar #Sync
- jmpl %g7 + %g0, %g0
+ ba,pt %xcc, 80f
+ nop
+ .align 32
+80: jmpl %g7 + %g0, %g0
nop
.align 32
@@ -126,6 +133,10 @@ VISenterhalf:
stda %f0, [%g2 + %g1] ASI_BLK_P
stda %f16, [%g3 + %g1] ASI_BLK_P
membar #Sync
+ ba,pt %xcc, 4f
+ nop
+
+ .align 32
4: and %o5, FPRS_DU, %o5
jmpl %g7 + %g0, %g0
wr %o5, FPRS_FEF, %fprs
diff --git a/arch/sparc64/lib/atomic.S b/arch/sparc64/lib/atomic.S
index e528b8d1a3e6..faf87c31598b 100644
--- a/arch/sparc64/lib/atomic.S
+++ b/arch/sparc64/lib/atomic.S
@@ -7,18 +7,6 @@
#include <linux/config.h>
#include <asm/asi.h>
- /* On SMP we need to use memory barriers to ensure
- * correct memory operation ordering, nop these out
- * for uniprocessor.
- */
-#ifdef CONFIG_SMP
-#define ATOMIC_PRE_BARRIER membar #StoreLoad | #LoadLoad
-#define ATOMIC_POST_BARRIER membar #StoreLoad | #StoreStore
-#else
-#define ATOMIC_PRE_BARRIER nop
-#define ATOMIC_POST_BARRIER nop
-#endif
-
.text
/* Two versions of the atomic routines, one that
@@ -52,6 +40,24 @@ atomic_sub: /* %o0 = decrement, %o1 = atomic_ptr */
nop
.size atomic_sub, .-atomic_sub
+ /* On SMP we need to use memory barriers to ensure
+ * correct memory operation ordering, nop these out
+ * for uniprocessor.
+ */
+#ifdef CONFIG_SMP
+
+#define ATOMIC_PRE_BARRIER membar #StoreLoad | #LoadLoad;
+#define ATOMIC_POST_BARRIER \
+ ba,pt %xcc, 80b; \
+ membar #StoreLoad | #StoreStore
+
+80: retl
+ nop
+#else
+#define ATOMIC_PRE_BARRIER
+#define ATOMIC_POST_BARRIER
+#endif
+
.globl atomic_add_ret
.type atomic_add_ret,#function
atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
@@ -62,9 +68,10 @@ atomic_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
cmp %g1, %g7
bne,pn %icc, 1b
add %g7, %o0, %g7
+ sra %g7, 0, %o0
ATOMIC_POST_BARRIER
retl
- sra %g7, 0, %o0
+ nop
.size atomic_add_ret, .-atomic_add_ret
.globl atomic_sub_ret
@@ -77,9 +84,10 @@ atomic_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
cmp %g1, %g7
bne,pn %icc, 1b
sub %g7, %o0, %g7
+ sra %g7, 0, %o0
ATOMIC_POST_BARRIER
retl
- sra %g7, 0, %o0
+ nop
.size atomic_sub_ret, .-atomic_sub_ret
.globl atomic64_add
@@ -118,9 +126,10 @@ atomic64_add_ret: /* %o0 = increment, %o1 = atomic_ptr */
cmp %g1, %g7
bne,pn %xcc, 1b
add %g7, %o0, %g7
+ mov %g7, %o0
ATOMIC_POST_BARRIER
retl
- mov %g7, %o0
+ nop
.size atomic64_add_ret, .-atomic64_add_ret
.globl atomic64_sub_ret
@@ -133,7 +142,8 @@ atomic64_sub_ret: /* %o0 = decrement, %o1 = atomic_ptr */
cmp %g1, %g7
bne,pn %xcc, 1b
sub %g7, %o0, %g7
+ mov %g7, %o0
ATOMIC_POST_BARRIER
retl
- mov %g7, %o0
+ nop
.size atomic64_sub_ret, .-atomic64_sub_ret
diff --git a/arch/sparc64/lib/bitops.S b/arch/sparc64/lib/bitops.S
index 886dcd2b376a..31afbfe6c1e8 100644
--- a/arch/sparc64/lib/bitops.S
+++ b/arch/sparc64/lib/bitops.S
@@ -7,20 +7,26 @@
#include <linux/config.h>
#include <asm/asi.h>
+ .text
+
/* On SMP we need to use memory barriers to ensure
* correct memory operation ordering, nop these out
* for uniprocessor.
*/
+
#ifdef CONFIG_SMP
#define BITOP_PRE_BARRIER membar #StoreLoad | #LoadLoad
-#define BITOP_POST_BARRIER membar #StoreLoad | #StoreStore
+#define BITOP_POST_BARRIER \
+ ba,pt %xcc, 80b; \
+ membar #StoreLoad | #StoreStore
+
+80: retl
+ nop
#else
-#define BITOP_PRE_BARRIER nop
-#define BITOP_POST_BARRIER nop
+#define BITOP_PRE_BARRIER
+#define BITOP_POST_BARRIER
#endif
- .text
-
.globl test_and_set_bit
.type test_and_set_bit,#function
test_and_set_bit: /* %o0=nr, %o1=addr */
@@ -37,10 +43,11 @@ test_and_set_bit: /* %o0=nr, %o1=addr */
cmp %g7, %g1
bne,pn %xcc, 1b
and %g7, %o2, %g2
- BITOP_POST_BARRIER
clr %o0
+ movrne %g2, 1, %o0
+ BITOP_POST_BARRIER
retl
- movrne %g2, 1, %o0
+ nop
.size test_and_set_bit, .-test_and_set_bit
.globl test_and_clear_bit
@@ -59,10 +66,11 @@ test_and_clear_bit: /* %o0=nr, %o1=addr */
cmp %g7, %g1
bne,pn %xcc, 1b
and %g7, %o2, %g2
- BITOP_POST_BARRIER
clr %o0
+ movrne %g2, 1, %o0
+ BITOP_POST_BARRIER
retl
- movrne %g2, 1, %o0
+ nop
.size test_and_clear_bit, .-test_and_clear_bit
.globl test_and_change_bit
@@ -81,10 +89,11 @@ test_and_change_bit: /* %o0=nr, %o1=addr */
cmp %g7, %g1
bne,pn %xcc, 1b
and %g7, %o2, %g2
- BITOP_POST_BARRIER
clr %o0
+ movrne %g2, 1, %o0
+ BITOP_POST_BARRIER
retl
- movrne %g2, 1, %o0
+ nop
.size test_and_change_bit, .-test_and_change_bit
.globl set_bit
diff --git a/arch/sparc64/lib/debuglocks.c b/arch/sparc64/lib/debuglocks.c
index c421e0c65325..f03344cf784e 100644
--- a/arch/sparc64/lib/debuglocks.c
+++ b/arch/sparc64/lib/debuglocks.c
@@ -252,8 +252,9 @@ wlock_again:
" andn %%g1, %%g3, %%g7\n"
" casx [%0], %%g1, %%g7\n"
" cmp %%g1, %%g7\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%xcc, 1b\n"
-" membar #StoreLoad | #StoreStore"
+" nop"
: /* no outputs */
: "r" (&(rw->lock))
: "g3", "g1", "g7", "cc", "memory");
@@ -351,8 +352,9 @@ int _do_write_trylock (rwlock_t *rw, char *str)
" andn %%g1, %%g3, %%g7\n"
" casx [%0], %%g1, %%g7\n"
" cmp %%g1, %%g7\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%xcc, 1b\n"
-" membar #StoreLoad | #StoreStore"
+" nop"
: /* no outputs */
: "r" (&(rw->lock))
: "g3", "g1", "g7", "cc", "memory");
diff --git a/arch/sparc64/lib/dec_and_lock.S b/arch/sparc64/lib/dec_and_lock.S
index 7e6fdaebedba..8ee288dd0afc 100644
--- a/arch/sparc64/lib/dec_and_lock.S
+++ b/arch/sparc64/lib/dec_and_lock.S
@@ -48,8 +48,9 @@ start_to_zero:
#endif
to_zero:
ldstub [%o1], %g3
+ membar #StoreLoad | #StoreStore
brnz,pn %g3, spin_on_lock
- membar #StoreLoad | #StoreStore
+ nop
loop2: cas [%o0], %g2, %g7 /* ASSERT(g7 == 0) */
cmp %g2, %g7
@@ -71,8 +72,9 @@ loop2: cas [%o0], %g2, %g7 /* ASSERT(g7 == 0) */
nop
spin_on_lock:
ldub [%o1], %g3
+ membar #LoadLoad
brnz,pt %g3, spin_on_lock
- membar #LoadLoad
+ nop
ba,pt %xcc, to_zero
nop
nop
diff --git a/arch/sparc64/lib/rwsem.S b/arch/sparc64/lib/rwsem.S
index 174ff7b9164c..75f0e6b951d6 100644
--- a/arch/sparc64/lib/rwsem.S
+++ b/arch/sparc64/lib/rwsem.S
@@ -17,8 +17,9 @@ __down_read:
bne,pn %icc, 1b
add %g7, 1, %g7
cmp %g7, 0
+ membar #StoreLoad | #StoreStore
bl,pn %icc, 3f
- membar #StoreLoad | #StoreStore
+ nop
2:
retl
nop
@@ -57,8 +58,9 @@ __down_write:
cmp %g3, %g7
bne,pn %icc, 1b
cmp %g7, 0
+ membar #StoreLoad | #StoreStore
bne,pn %icc, 3f
- membar #StoreLoad | #StoreStore
+ nop
2: retl
nop
3:
@@ -97,8 +99,9 @@ __up_read:
cmp %g1, %g7
bne,pn %icc, 1b
cmp %g7, 0
+ membar #StoreLoad | #StoreStore
bl,pn %icc, 3f
- membar #StoreLoad | #StoreStore
+ nop
2: retl
nop
3: sethi %hi(RWSEM_ACTIVE_MASK), %g1
@@ -126,8 +129,9 @@ __up_write:
bne,pn %icc, 1b
sub %g7, %g1, %g7
cmp %g7, 0
+ membar #StoreLoad | #StoreStore
bl,pn %icc, 3f
- membar #StoreLoad | #StoreStore
+ nop
2:
retl
nop
@@ -151,8 +155,9 @@ __downgrade_write:
bne,pn %icc, 1b
sub %g7, %g1, %g7
cmp %g7, 0
+ membar #StoreLoad | #StoreStore
bl,pn %icc, 3f
- membar #StoreLoad | #StoreStore
+ nop
2:
retl
nop
diff --git a/arch/sparc64/mm/fault.c b/arch/sparc64/mm/fault.c
index 3ffee7b51aed..52e9375288a9 100644
--- a/arch/sparc64/mm/fault.c
+++ b/arch/sparc64/mm/fault.c
@@ -34,22 +34,6 @@
extern struct sparc_phys_banks sp_banks[SPARC_PHYS_BANKS];
/*
- * To debug kernel during syscall entry.
- */
-void syscall_trace_entry(struct pt_regs *regs)
-{
- printk("scall entry: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
-}
-
-/*
- * To debug kernel during syscall exit.
- */
-void syscall_trace_exit(struct pt_regs *regs)
-{
- printk("scall exit: %s[%d]/cpu%d: %d\n", current->comm, current->pid, smp_processor_id(), (int) regs->u_regs[UREG_G1]);
-}
-
-/*
* To debug kernel to catch accesses to certain virtual/physical addresses.
* Mode = 0 selects physical watchpoints, mode = 1 selects virtual watchpoints.
* flags = VM_READ watches memread accesses, flags = VM_WRITE watches memwrite accesses.
diff --git a/arch/sparc64/mm/init.c b/arch/sparc64/mm/init.c
index 9c5222075da9..8fc413cb6acd 100644
--- a/arch/sparc64/mm/init.c
+++ b/arch/sparc64/mm/init.c
@@ -136,8 +136,9 @@ static __inline__ void set_dcache_dirty(struct page *page, int this_cpu)
"or %%g1, %0, %%g1\n\t"
"casx [%2], %%g7, %%g1\n\t"
"cmp %%g7, %%g1\n\t"
+ "membar #StoreLoad | #StoreStore\n\t"
"bne,pn %%xcc, 1b\n\t"
- " membar #StoreLoad | #StoreStore"
+ " nop"
: /* no outputs */
: "r" (mask), "r" (non_cpu_bits), "r" (&page->flags)
: "g1", "g7");
@@ -157,8 +158,9 @@ static __inline__ void clear_dcache_dirty_cpu(struct page *page, unsigned long c
" andn %%g7, %1, %%g1\n\t"
"casx [%2], %%g7, %%g1\n\t"
"cmp %%g7, %%g1\n\t"
+ "membar #StoreLoad | #StoreStore\n\t"
"bne,pn %%xcc, 1b\n\t"
- " membar #StoreLoad | #StoreStore\n"
+ " nop\n"
"2:"
: /* no outputs */
: "r" (cpu), "r" (mask), "r" (&page->flags),
diff --git a/arch/sparc64/mm/ultra.S b/arch/sparc64/mm/ultra.S
index 7a0934321010..363770893797 100644
--- a/arch/sparc64/mm/ultra.S
+++ b/arch/sparc64/mm/ultra.S
@@ -72,6 +72,7 @@ __flush_tlb_pending:
flush %g6
retl
wrpr %g7, 0x0, %pstate
+ nop
.align 32
.globl __flush_tlb_kernel_range
@@ -249,7 +250,7 @@ __cheetah_flush_tlb_mm: /* 15 insns */
retl
wrpr %g7, 0x0, %pstate
-__cheetah_flush_tlb_pending: /* 22 insns */
+__cheetah_flush_tlb_pending: /* 23 insns */
/* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
rdpr %pstate, %g7
sllx %o1, 3, %o1
@@ -266,8 +267,9 @@ __cheetah_flush_tlb_pending: /* 22 insns */
andn %o3, 1, %o3
stxa %g0, [%o3] ASI_IMMU_DEMAP
2: stxa %g0, [%o3] ASI_DMMU_DEMAP
+ membar #Sync
brnz,pt %o1, 1b
- membar #Sync
+ nop
stxa %g2, [%o4] ASI_DMMU
flush %g6
wrpr %g0, 0, %tl
@@ -316,7 +318,7 @@ cheetah_patch_cachetlbops:
sethi %hi(__cheetah_flush_tlb_pending), %o1
or %o1, %lo(__cheetah_flush_tlb_pending), %o1
call cheetah_patch_one
- mov 22, %o2
+ mov 23, %o2
#ifdef DCACHE_ALIASING_POSSIBLE
sethi %hi(__flush_dcache_page), %o0
diff --git a/arch/sparc64/solaris/entry64.S b/arch/sparc64/solaris/entry64.S
index 0cc9dad75c5e..4b6ae583c0a3 100644
--- a/arch/sparc64/solaris/entry64.S
+++ b/arch/sparc64/solaris/entry64.S
@@ -24,8 +24,9 @@
.text
solaris_syscall_trace:
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- nop
+ mov 0, %o1
srl %i0, 0, %o0
mov %i4, %o4
srl %i1, 0, %o1
@@ -159,8 +160,10 @@ ret_from_solaris:
stx %l2, [%sp + PTREGS_OFF + PT_V9_TNPC] !npc = npc+4
solaris_syscall_trace2:
+ add %sp, PTREGS_OFF, %o0
call syscall_trace
- add %l1, 0x4, %l2 /* npc = npc+4 */
+ mov 1, %o1
+ add %l1, 0x4, %l2 /* npc = npc+4 */
andcc %l1, 1, %g0
bne,pn %icc, 2b
nop
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index 9469e77303e6..f945444df49c 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -128,7 +128,6 @@ config HOSTFS
config HPPFS
tristate "HoneyPot ProcFS (EXPERIMENTAL)"
- depends on BROKEN
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
@@ -141,8 +140,9 @@ config HPPFS
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
- If you are actively using it, please ask for it to be fixed. In this
- moment, it does not work on 2.6 (it works somehow on 2.4).
+ If you are actively using it, please report any problems, since it's
+ getting fixed. In this moment, it is experimental on 2.6 (it works on
+ 2.4).
config MCONSOLE
bool "Management console"
@@ -275,6 +275,8 @@ endmenu
source "init/Kconfig"
+source "net/Kconfig"
+
source "drivers/base/Kconfig"
source "arch/um/Kconfig_char"
@@ -287,7 +289,7 @@ config NETDEVICES
source "arch/um/Kconfig_net"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "fs/Kconfig"
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
index e41f3748d30f..27c18a8d9d17 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES
memory. All the memory that can't be mapped directly will be treated
as high memory.
+config STUB_CODE
+ hex
+ default 0xbfffe000
+
+config STUB_DATA
+ hex
+ default 0xbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default y
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
index f162f50f0b17..735a047c890c 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES
bool
default y
+config STUB_CODE
+ hex
+ default 0x7fbfffe000
+
+config STUB_DATA
+ hex
+ default 0x7fbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default n
diff --git a/arch/um/Makefile b/arch/um/Makefile
index 3f073902351f..4a375bbac109 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -140,7 +140,8 @@ endef
#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
+ $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h \
+ $(ARCH_DIR)/include/user_constants.h
MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 29e182d5a83a..301059062a3e 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y)
endif
endif
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
ARCH_USER_CFLAGS :=
ifneq ($(CONFIG_GPROF),y)
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 32144562c279..d80bd0052e6b 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -4,7 +4,7 @@
SUBARCH_LIBS := arch/um/sys-x86_64/
START := 0x60000000
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
ARCH_USER_CFLAGS := -D__x86_64__
ELF_ARCH := i386:x86-64
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 4067c3aa5b60..80d30d19d750 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
-# Sun Apr 24 19:46:10 2005
+# Linux kernel version: 2.6.12-rc6-mm1
+# Tue Jun 14 18:22:21 2005
#
CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y
@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
#
# UML-specific options
#
-CONFIG_MODE_TT=y
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y
CONFIG_UML_X86=y
# CONFIG_64BIT is not set
CONFIG_TOP_ADDR=0xc0000000
# CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0xbfffe000
+CONFIG_STUB_DATA=0xbffff000
+CONFIG_STUB_START=0xbfffe000
CONFIG_ARCH_HAS_SC_SIGNALS=y
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
-CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_HOSTFS=y
+# CONFIG_HOSTFS is not set
CONFIG_MCONSOLE=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HOST_2G_2G is not set
-# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set
@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -81,6 +92,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m
CONFIG_SOUND=m
CONFIG_HOSTAUDIO=m
CONFIG_UML_RANDOM=y
+# CONFIG_MMAPPER is not set
#
# Block devices
@@ -176,6 +189,17 @@ CONFIG_INET=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y
# 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_IEEE80211 is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -227,6 +255,7 @@ CONFIG_PPP=m
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=m
# CONFIG_SLIP_COMPRESSED is not set
@@ -240,10 +269,12 @@ CONFIG_SLIP=m
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISER4_FS is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
@@ -265,6 +297,12 @@ CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
+#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
@@ -291,6 +329,8 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
#
# Miscellaneous filesystems
@@ -319,6 +359,7 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -404,14 +445,15 @@ CONFIG_CRC32=m
# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
# CONFIG_GCOV is not set
# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index cf15b4a8b517..c1b03f7c1daa 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -157,9 +157,9 @@ static void daemon_remove(void *data)
os_close_file(pri->fd);
os_close_file(pri->control);
- if(pri->data_addr != NULL) kfree(pri->data_addr);
- if(pri->ctl_addr != NULL) kfree(pri->ctl_addr);
- if(pri->local_addr != NULL) kfree(pri->local_addr);
+ kfree(pri->data_addr);
+ kfree(pri->ctl_addr);
+ kfree(pri->local_addr);
}
int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 0f59736db329..e0fdffa2d542 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -602,11 +602,26 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
return n;
}
-int line_remove(struct line *lines, unsigned int num, char *str)
+int line_id(char **str, int *start_out, int *end_out)
+{
+ char *end;
+ int n;
+
+ n = simple_strtoul(*str, &end, 0);
+ if((*end != '\0') || (end == *str))
+ return -1;
+
+ *str = end;
+ *start_out = n;
+ *end_out = n;
+ return n;
+}
+
+int line_remove(struct line *lines, unsigned int num, int n)
{
char config[sizeof("conxxxx=none\0")];
- sprintf(config, "%s=none", str);
+ sprintf(config, "%d=none", n);
return !line_setup(lines, num, config, 0);
}
@@ -648,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set,
return driver;
}
+static spinlock_t winch_handler_lock;
+LIST_HEAD(winch_handlers);
+
void lines_init(struct line *lines, int nlines)
{
struct line *line;
int i;
+ spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
@@ -709,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
return IRQ_HANDLED;
}
-DECLARE_MUTEX(winch_handler_sem);
-LIST_HEAD(winch_handlers);
-
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
{
struct winch *winch;
- down(&winch_handler_sem);
winch = kmalloc(sizeof(*winch), GFP_KERNEL);
if (winch == NULL) {
printk("register_winch_irq - kmalloc failed\n");
- goto out;
+ return;
}
+
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
.tty = tty });
+
+ spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
+ spin_unlock(&winch_handler_lock);
+
if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM,
"winch", winch) < 0)
printk("register_winch_irq - failed to register IRQ\n");
- out:
- up(&winch_handler_sem);
}
static void unregister_winch(struct tty_struct *tty)
@@ -741,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
struct list_head *ele;
struct winch *winch, *found = NULL;
- down(&winch_handler_sem);
+ spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
@@ -749,20 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
break;
}
}
-
if(found == NULL)
- goto out;
+ goto err;
+
+ list_del(&winch->list);
+ spin_unlock(&winch_handler_lock);
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
free_irq(WINCH_IRQ, winch);
- list_del(&winch->list);
kfree(winch);
- out:
- up(&winch_handler_sem);
+
+ return;
+err:
+ spin_unlock(&winch_handler_lock);
}
+/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
+ * order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void)
{
struct list_head *ele;
@@ -771,6 +794,9 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->fd != -1){
+ /* Why is this different from the above free_irq(),
+ * which deactivates SIGIO? This searches the FD
+ * somewhere else and removes it from the list... */
deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd);
}
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index d7c7adcc0a67..404de41a4f67 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -419,8 +419,9 @@ void mconsole_config(struct mc_request *req)
void mconsole_remove(struct mc_request *req)
{
struct mc_device *dev;
- char *ptr = req->request.data;
- int err;
+ char *ptr = req->request.data, *err_msg = "";
+ char error[256];
+ int err, start, end, n;
ptr += strlen("remove");
while(isspace(*ptr)) ptr++;
@@ -429,8 +430,35 @@ void mconsole_remove(struct mc_request *req)
mconsole_reply(req, "Bad remove option", 1, 0);
return;
}
- err = (*dev->remove)(&ptr[strlen(dev->name)]);
- mconsole_reply(req, "", err, 0);
+
+ ptr = &ptr[strlen(dev->name)];
+
+ err = 1;
+ n = (*dev->id)(&ptr, &start, &end);
+ if(n < 0){
+ err_msg = "Couldn't parse device number";
+ goto out;
+ }
+ else if((n < start) || (n > end)){
+ sprintf(error, "Invalid device number - must be between "
+ "%d and %d", start, end);
+ err_msg = error;
+ goto out;
+ }
+
+ err = (*dev->remove)(n);
+ switch(err){
+ case -ENODEV:
+ err_msg = "Device doesn't exist";
+ break;
+ case -EBUSY:
+ err_msg = "Device is currently open";
+ break;
+ default:
+ break;
+ }
+ out:
+ mconsole_reply(req, err_msg, err, 0);
}
#ifdef CONFIG_MAGIC_SYSRQ
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 5388a7428691..1495007bf6c0 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -612,25 +612,35 @@ static int net_config(char *str)
return(err);
}
-static int net_remove(char *str)
+static int net_id(char **str, int *start_out, int *end_out)
+{
+ char *end;
+ int n;
+
+ n = simple_strtoul(*str, &end, 0);
+ if((*end != '\0') || (end == *str))
+ return -1;
+
+ *start_out = n;
+ *end_out = n;
+ *str = end;
+ return n;
+}
+
+static int net_remove(int n)
{
struct uml_net *device;
struct net_device *dev;
struct uml_net_private *lp;
- char *end;
- int n;
-
- n = simple_strtoul(str, &end, 0);
- if((*end != '\0') || (end == str))
- return(-1);
device = find_device(n);
if(device == NULL)
- return(0);
+ return -ENODEV;
dev = device->dev;
lp = dev->priv;
- if(lp->fd > 0) return(-1);
+ if(lp->fd > 0)
+ return -EBUSY;
if(lp->remove != NULL) (*lp->remove)(&lp->user);
unregister_netdev(dev);
platform_device_unregister(&device->pdev);
@@ -638,13 +648,14 @@ static int net_remove(char *str)
list_del(&device->list);
kfree(device);
free_netdev(dev);
- return(0);
+ return 0;
}
static struct mc_device net_mc = {
.name = "eth",
.config = net_config,
.get_config = NULL,
+ .id = net_id,
.remove = net_remove,
};
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index b32a77010fbe..62e04ecfada8 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -49,7 +49,7 @@ static struct chan_opts opts = {
static int ssl_config(char *str);
static int ssl_get_config(char *dev, char *str, int size, char **error_out);
-static int ssl_remove(char *str);
+static int ssl_remove(int n);
static struct line_driver driver = {
.name = "UML serial line",
@@ -69,6 +69,7 @@ static struct line_driver driver = {
.name = "ssl",
.config = ssl_config,
.get_config = ssl_get_config,
+ .id = line_id,
.remove = ssl_remove,
},
};
@@ -94,10 +95,10 @@ static int ssl_get_config(char *dev, char *str, int size, char **error_out)
str, size, error_out));
}
-static int ssl_remove(char *str)
+static int ssl_remove(int n)
{
- return(line_remove(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+ return line_remove(serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]), n);
}
int ssl_open(struct tty_struct *tty, struct file *filp)
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index afbe1e71ed83..005aa6333b6e 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -55,7 +55,7 @@ static struct chan_opts opts = {
static int con_config(char *str);
static int con_get_config(char *dev, char *str, int size, char **error_out);
-static int con_remove(char *str);
+static int con_remove(int n);
static struct line_driver driver = {
.name = "UML console",
@@ -75,6 +75,7 @@ static struct line_driver driver = {
.name = "con",
.config = con_config,
.get_config = con_get_config,
+ .id = line_id,
.remove = con_remove,
},
};
@@ -99,9 +100,9 @@ static int con_get_config(char *dev, char *str, int size, char **error_out)
size, error_out));
}
-static int con_remove(char *str)
+static int con_remove(int n)
{
- return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
+ return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n);
}
static int con_open(struct tty_struct *tty, struct file *filp)
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 2a7f6892c55c..344b24d09a7c 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -754,24 +754,34 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out)
return(len);
}
-static int ubd_remove(char *str)
+static int ubd_id(char **str, int *start_out, int *end_out)
+{
+ int n;
+
+ n = parse_unit(str);
+ *start_out = 0;
+ *end_out = MAX_DEV - 1;
+ return n;
+}
+
+static int ubd_remove(int n)
{
struct ubd *dev;
- int n, err = -ENODEV;
+ int err = -ENODEV;
- n = parse_unit(&str);
+ spin_lock(&ubd_lock);
- if((n < 0) || (n >= MAX_DEV))
- return(err);
+ if(ubd_gendisk[n] == NULL)
+ goto out;
dev = &ubd_dev[n];
- if(dev->count > 0)
- return(-EBUSY); /* you cannot remove a open disk */
- err = 0;
- spin_lock(&ubd_lock);
+ if(dev->file == NULL)
+ goto out;
- if(ubd_gendisk[n] == NULL)
+ /* you cannot remove a open disk */
+ err = -EBUSY;
+ if(dev->count > 0)
goto out;
del_gendisk(ubd_gendisk[n]);
@@ -787,15 +797,16 @@ static int ubd_remove(char *str)
platform_device_unregister(&dev->pdev);
*dev = ((struct ubd) DEFAULT_UBD);
err = 0;
- out:
- spin_unlock(&ubd_lock);
- return(err);
+out:
+ spin_unlock(&ubd_lock);
+ return err;
}
static struct mc_device ubd_mc = {
.name = "ubd",
.config = ubd_config,
.get_config = ubd_get_config,
+ .id = ubd_id,
.remove = ubd_remove,
};
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 4c5e92c04ccb..5323d22a6ca7 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -101,7 +101,8 @@ extern void lines_init(struct line *lines, int nlines);
extern void close_lines(struct line *lines, int nlines);
extern int line_config(struct line *lines, unsigned int sizeof_lines, char *str);
-extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_id(char **str, int *start_out, int *end_out);
+extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n);
extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str,
int size, char **error_out);
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
index 61c274fcee5d..d86ee14260ce 100644
--- a/arch/um/include/mconsole_kern.h
+++ b/arch/um/include/mconsole_kern.h
@@ -20,7 +20,8 @@ struct mc_device {
char *name;
int (*config)(char *);
int (*get_config)(char *, char *, int, char **);
- int (*remove)(char *);
+ int (*id)(char **, int *, int *);
+ int (*remove)(int);
};
#define CONFIG_CHUNK(str, size, current, chunk, end) \
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index 10c46c38949a..99d3ad4a03e5 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -13,6 +13,7 @@ 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);
+extern unsigned long to_phys(void *virt);
#endif
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 8744abb5224f..0a35e6d0baa0 100644
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern void save_registers(int pid, union uml_pt_regs *regs);
extern void restore_registers(int pid, union uml_pt_regs *regs);
extern void init_registers(int pid);
+extern void get_safe_registers(unsigned long * regs);
#endif
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index eca8066e7a43..899aa4b2a78d 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -20,11 +20,24 @@
#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
+#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
+#define REGS_SYSCALL_NR EAX /* This is used before a system call */
+#define REGS_SYSCALL_ARG1 EBX
+#define REGS_SYSCALL_ARG2 ECX
+#define REGS_SYSCALL_ARG3 EDX
+#define REGS_SYSCALL_ARG4 ESI
+#define REGS_SYSCALL_ARG5 EDI
+#define REGS_SYSCALL_ARG6 EBP
+
+#define REGS_IP_INDEX EIP
+#define REGS_SP_INDEX UESP
+
#define PT_IP_OFFSET PT_OFFSET(EIP)
#define PT_IP(regs) ((regs)[EIP])
+#define PT_SP_OFFSET PT_OFFSET(UESP)
#define PT_SP(regs) ((regs)[UESP])
#ifndef FRAME_SIZE
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
new file mode 100644
index 000000000000..d3699fe1c613
--- /dev/null
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET EAX
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("int $0x80;" : : : "%eax");
+ __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ long ret;
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
+ __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
+ "int $0x80; popl %%ebp ; "
+ "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
+ return(ret);
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 31729973fb14..128faf027364 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -55,6 +55,20 @@
#define PTRACE_OLDSETOPTIONS 21
#endif
+/* These are before the system call, so the the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+#define REGS_SYSCALL_NR PT_INDEX(RAX)
+#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
+#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
+#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
+#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
+#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
+#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
+
+#define REGS_IP_INDEX PT_INDEX(RIP)
+#define REGS_SP_INDEX PT_INDEX(RSP)
+
#endif
/*
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
new file mode 100644
index 000000000000..f599058d8263
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <sysdep/ptrace_user.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET PT_INDEX(RAX)
+#define STUB_MMAP_NR __NR_mmap
+#define MMAP_OFFSET(o) (o)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
+ __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
+ __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
+ __asm__("syscall;" : : : "%rax", "%r11", "%rcx");
+ __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
+ __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
+ return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index 6793a2fcd0ae..17d7ef2141f4 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -8,11 +8,12 @@
extern void timer(void);
extern void switch_timers(int to_real);
-extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
extern void enable_timer(void);
+extern void prepare_timer(void * ptr);
extern void disable_timer(void);
extern unsigned long time_lock(void);
extern void time_unlock(unsigned long);
+extern void user_time_init(void);
#endif
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index da1097285b8c..c6f9628f39bf 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -37,31 +37,25 @@ struct host_vm_op {
extern void mprotect_kernel_vm(int w);
extern void force_flush_all(void);
extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *,
+ struct host_vm_op *, int));
extern int flush_tlb_kernel_range_common(unsigned long start,
unsigned long end);
extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_munmap(unsigned long addr, unsigned long len,
struct host_vm_op *ops, int index, int last_filled,
- int data, void (*do_ops)(int, struct host_vm_op *, int));
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
#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/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b0838a68c..3942a5f245de 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@ SECTIONS
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
} =0x90909090
.fini : {
KEEP (*(.fini))
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
index e59f58152678..1e1a87f1c510 100644
--- a/arch/um/kernel/main.c
+++ b/arch/um/kernel/main.c
@@ -69,7 +69,6 @@ static __init void do_uml_initcalls(void)
static void last_ditch_exit(int sig)
{
- kmalloc_ok = 0;
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d51fa0f..a24e3b7f4bf0 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+extern int __syscall_stub_start, __binary_start;
+
void setup_physmem(unsigned long start, unsigned long reserve_end,
unsigned long len, unsigned long highmem)
{
@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
exit(1);
}
+ /* Special kludge - This page will be mapped in to userspace processes
+ * from physmem_fd, so it needs to be written out there.
+ */
+ os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
+ os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+
bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size,
len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e96c71..c45a60e9c92d 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
#include "uml-config.h"
#include "choose-mode.h"
#include "mode.h"
+#include "tempfile.h"
#ifdef UML_CONFIG_MODE_SKAS
#include "skas.h"
#include "skas_ptrace.h"
@@ -358,11 +359,16 @@ void forward_pending_sigio(int target)
kill(target, SIGIO);
}
+int ptrace_faultinfo = 0;
+int proc_mm = 1;
+
+extern void *__syscall_stub_start, __syscall_stub_end;
+
#ifdef UML_CONFIG_MODE_SKAS
-static inline int check_skas3_ptrace_support(void)
+static inline void check_skas3_ptrace_support(void)
{
struct ptrace_faultinfo fi;
- int pid, n, ret = 1;
+ int pid, n;
printf("Checking for the skas3 patch in the host...");
pid = start_ptraced_child();
@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void)
else {
perror("not found");
}
- ret = 0;
- } else {
+ }
+ else {
+ ptrace_faultinfo = 1;
printf("found\n");
}
init_registers(pid);
stop_ptraced_child(pid, 1, 1);
-
- return(ret);
}
int can_do_skas(void)
{
- int ret = 1;
-
printf("Checking for /proc/mm...");
if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
+ proc_mm = 0;
printf("not found\n");
- ret = 0;
goto out;
- } else {
+ }
+ else {
printf("found\n");
}
- ret = check_skas3_ptrace_support();
out:
- return ret;
+ check_skas3_ptrace_support();
+ return 1;
}
#else
int can_do_skas(void)
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 157584ae4792..d4036ed680bc 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -96,8 +96,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
current->thread.request.u.thread.proc = fn;
current->thread.request.u.thread.arg = arg;
- pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
- NULL);
+ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
+ &current->thread.regs, 0, NULL, NULL);
if(pid < 0)
panic("do_fork failed in kernel_thread, errno = %d", pid);
return(pid);
@@ -169,7 +169,7 @@ int current_pid(void)
void default_idle(void)
{
- uml_idle_timer();
+ CHOOSE_MODE(uml_idle_timer(), (void) 0);
atomic_inc(&init_mm.mm_count);
current->mm = &init_mm;
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 207f89d74908..fcec51da1d37 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -38,14 +38,14 @@ static void kill_off_processes(void)
void uml_cleanup(void)
{
- kill_off_processes();
+ kmalloc_ok = 0;
do_uml_exitcalls();
+ kill_off_processes();
}
void machine_restart(char * __unused)
{
- do_uml_exitcalls();
- kill_off_processes();
+ uml_cleanup();
CHOOSE_MODE(reboot_tt(), reboot_skas());
}
@@ -53,8 +53,7 @@ EXPORT_SYMBOL(machine_restart);
void machine_power_off(void)
{
- do_uml_exitcalls();
- kill_off_processes();
+ uml_cleanup();
CHOOSE_MODE(halt_tt(), halt_skas());
}
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index d37d1bfcd6f7..d296d55ade4b 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,11 +3,14 @@
# Licensed under the GPL
#
-obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
- syscall_kern.o syscall_user.o time.o tlb.o trap_user.o uaccess.o \
+obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
+ syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
subdir- := util
-USER_OBJS := process.o time.o
+USER_OBJS := process.o clone.o
include arch/um/scripts/Makefile.rules
+
+# clone.o is in the stub, so it can't be built with profiling
+$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
new file mode 100644
index 000000000000..4dc55f10cd18
--- /dev/null
+++ b/arch/um/kernel/skas/clone.c
@@ -0,0 +1,44 @@
+#include <sched.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "ptrace_user.h"
+#include "skas.h"
+#include "stub-data.h"
+#include "uml-config.h"
+#include "sysdep/stub.h"
+
+/* This is in a separate file because it needs to be compiled with any
+ * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
+ */
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_clone_handler(void)
+{
+ long err;
+ struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
+
+ err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+ UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
+ sizeof(void *));
+ if(err != 0)
+ goto out;
+
+ err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ (long) &from->timer, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
+ from->fd, from->offset);
+ out:
+ /* save current result. Parent: pid; child: retcode of mmap */
+ from->err = err;
+ trap_myself();
+}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5dba789..77ed7bbab219 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
void flush_thread_skas(void)
{
force_flush_all();
- switch_mm_skas(current->mm->context.skas.mm_fd);
+ switch_mm_skas(&current->mm->context.skas.id);
}
void start_thread_skas(struct pt_regs *regs, unsigned long eip,
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
new file mode 100644
index 000000000000..48dd0989ddaa
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MM_ID_H
+#define __MM_ID_H
+
+struct mm_id {
+ union {
+ int mm_fd;
+ int pid;
+ } u;
+ unsigned long stack;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7213f3..278b72f1d9ad 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
+#include "mm_id.h"
+
struct mmu_context_skas {
- int mm_fd;
+ struct mm_id id;
+ unsigned long last_page_table;
};
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
#endif
/*
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
index c1e33bd788db..bcd26a6a3888 100644
--- a/arch/um/kernel/skas/include/mode-skas.h
+++ b/arch/um/kernel/skas/include/mode-skas.h
@@ -13,7 +13,6 @@ extern unsigned long exec_fp_regs[];
extern unsigned long exec_fpx_regs[];
extern int have_fpx_regs;
-extern void user_time_init_skas(void);
extern void sig_handler_common_skas(int sig, void *sc_ptr);
extern void halt_skas(void);
extern void reboot_skas(void);
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51dba3471..d983ea842547 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
#ifndef __SKAS_H
#define __SKAS_H
+#include "mm_id.h"
#include "sysdep/ptrace.h"
extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo;
extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,18 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
extern void remove_sigstack(void);
extern void new_thread_handler(int sig);
extern void handle_syscall(union uml_pt_regs *regs);
-extern void map(int fd, unsigned long virt, unsigned long len, int r, int w,
- int x, int phys_fd, unsigned long long offset);
-extern int unmap(int fd, void *addr, unsigned long len);
-extern int protect(int fd, unsigned long addr, unsigned long len,
- int r, int w, int x);
+extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+ unsigned long len, int r, int w, int x);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
extern int new_mm(int from);
-extern void start_userspace(int cpu);
+extern int start_userspace(unsigned long stub_stack);
+extern int copy_context_skas0(unsigned long stack, int pid);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
extern long execute_syscall_skas(void *r);
+extern unsigned long current_stub_stack(void);
#endif
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h
new file mode 100644
index 000000000000..f6ed92c3727d
--- /dev/null
+++ b/arch/um/kernel/skas/include/stub-data.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STUB_DATA_H
+#define __STUB_DATA_H
+
+#include <sys/time.h>
+
+struct stub_data {
+ long offset;
+ int fd;
+ struct itimerval timer;
+ long err;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f43456..147466d7ff4f 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
#include "linux/config.h"
#include "linux/mm.h"
+#include "asm/pgtable.h"
#include "mem_user.h"
+#include "skas.h"
unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out)
@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
*task_size_out = CONFIG_HOST_TASK_SIZE;
#else
*host_size_out = top;
- *task_size_out = top;
+ if (proc_mm && ptrace_faultinfo)
+ *task_size_out = top;
+ else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
#endif
return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
}
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1e88d1..b0980ff3bd95 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
* Licensed under the GPL
*/
+#include <signal.h>
#include <errno.h>
#include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
#include "mem_user.h"
#include "mem.h"
+#include "mm_id.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
-
-void map(int fd, unsigned long virt, unsigned long len, int r, int w,
- int x, int phys_fd, unsigned long long offset)
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+#include "skas.h"
+
+extern unsigned long syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+ unsigned long *args)
{
- struct proc_mm_op map;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- map = ((struct proc_mm_op) { .op = MM_MMAP,
- .u =
- { .mmap =
- { .addr = virt,
- .len = len,
- .prot = prot,
- .flags = MAP_SHARED |
- MAP_FIXED,
- .fd = phys_fd,
- .offset = offset
- } } } );
- n = os_write_file(fd, &map, sizeof(map));
- if(n != sizeof(map))
- printk("map : /proc/mm map failed, err = %d\n", -n);
+ int n, pid = mm_idp->u.pid;
+ unsigned long regs[MAX_REG_NR];
+
+ get_safe_registers(regs);
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ ((unsigned long) &syscall_stub -
+ (unsigned long) &__syscall_stub_start);
+ /* XXX Don't have a define for starting a syscall */
+ regs[REGS_SYSCALL_NR] = syscall;
+ regs[REGS_SYSCALL_ARG1] = args[0];
+ regs[REGS_SYSCALL_ARG2] = args[1];
+ regs[REGS_SYSCALL_ARG3] = args[2];
+ regs[REGS_SYSCALL_ARG4] = args[3];
+ regs[REGS_SYSCALL_ARG5] = args[4];
+ regs[REGS_SYSCALL_ARG6] = args[5];
+ n = ptrace_setregs(pid, regs);
+ if(n < 0){
+ printk("run_syscall_stub : PTRACE_SETREGS failed, "
+ "errno = %d\n", n);
+ return(n);
+ }
+
+ wait_stub_done(pid, 0, "run_syscall_stub");
+
+ return(*((unsigned long *) mm_idp->stack));
}
-int unmap(int fd, void *addr, unsigned long len)
+int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset)
{
- struct proc_mm_op unmap;
- int n;
-
- unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
- .u =
- { .munmap =
- { .addr = (unsigned long) addr,
- .len = len } } } );
- n = os_write_file(fd, &unmap, sizeof(unmap));
- if(n != sizeof(unmap)) {
- if(n < 0)
- return(n);
- else if(n > 0)
- return(-EIO);
- }
-
- return(0);
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ struct proc_mm_op map;
+ int fd = mm_idp->u.mm_fd;
+ map = ((struct proc_mm_op) { .op = MM_MMAP,
+ .u =
+ { .mmap =
+ { .addr = virt,
+ .len = len,
+ .prot = prot,
+ .flags = MAP_SHARED |
+ MAP_FIXED,
+ .fd = phys_fd,
+ .offset= offset
+ } } } );
+ n = os_write_file(fd, &map, sizeof(map));
+ if(n != sizeof(map))
+ printk("map : /proc/mm map failed, err = %d\n", -n);
+ }
+ else {
+ long res;
+ unsigned long args[] = { virt, len, prot,
+ MAP_SHARED | MAP_FIXED, phys_fd,
+ MMAP_OFFSET(offset) };
+
+ res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
+ if((void *) res == MAP_FAILED)
+ printk("mmap stub failed, errno = %d\n", res);
+ }
+
+ return 0;
}
-int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
- int x, int must_succeed)
+int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
{
- struct proc_mm_op protect;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
- .u =
- { .mprotect =
- { .addr = (unsigned long) addr,
- .len = len,
- .prot = prot } } } );
-
- n = os_write_file(fd, &protect, sizeof(protect));
- if(n != sizeof(protect)) {
- if(n == 0) return(0);
-
- if(must_succeed)
- panic("protect failed, err = %d", -n);
-
- return(-EIO);
- }
+ int n;
+
+ if(proc_mm){
+ struct proc_mm_op unmap;
+ int fd = mm_idp->u.mm_fd;
+ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
+ .u =
+ { .munmap =
+ { .addr =
+ (unsigned long) addr,
+ .len = len } } } );
+ n = os_write_file(fd, &unmap, sizeof(unmap));
+ if(n != sizeof(unmap)) {
+ if(n < 0)
+ return(n);
+ else if(n > 0)
+ return(-EIO);
+ }
+ }
+ else {
+ int res;
+ unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+ 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_munmap, args);
+ if(res < 0)
+ printk("munmap stub failed, errno = %d\n", res);
+ }
+
+ return(0);
+}
- return(0);
+int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
+ int r, int w, int x)
+{
+ struct proc_mm_op protect;
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ int fd = mm_idp->u.mm_fd;
+ protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
+ .u =
+ { .mprotect =
+ { .addr =
+ (unsigned long) addr,
+ .len = len,
+ .prot = prot } } } );
+
+ n = os_write_file(fd, &protect, sizeof(protect));
+ if(n != sizeof(protect))
+ panic("protect failed, err = %d", -n);
+ }
+ else {
+ int res;
+ unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_mprotect, args);
+ if(res < 0)
+ panic("mprotect stub failed, errno = %d\n", res);
+ }
+
+ return(0);
}
void before_mem_skas(unsigned long unused)
{
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d028a9..d232daa42c31 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,143 @@
* Licensed under the GPL
*/
+#include "linux/config.h"
#include "linux/sched.h"
#include "linux/list.h"
#include "linux/spinlock.h"
#include "linux/slab.h"
+#include "linux/errno.h"
+#include "linux/mm.h"
#include "asm/current.h"
#include "asm/segment.h"
#include "asm/mmu.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
#include "os.h"
#include "skas.h"
+extern int __syscall_stub_start;
+
+static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
+ unsigned long kernel)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ spin_lock(&mm->page_table_lock);
+ pgd = pgd_offset(mm, proc);
+ pud = pud_alloc(mm, pgd, proc);
+ if (!pud)
+ goto out;
+
+ pmd = pmd_alloc(mm, pud, proc);
+ if (!pmd)
+ goto out_pmd;
+
+ pte = pte_alloc_map(mm, pmd, proc);
+ if (!pte)
+ goto out_pte;
+
+ /* There's an interaction between the skas0 stub pages, stack
+ * randomization, and the BUG at the end of exit_mmap. exit_mmap
+ * checks that the number of page tables freed is the same as had
+ * been allocated. If the stack is on the last page table page,
+ * then the stack pte page will be freed, and if not, it won't. To
+ * avoid having to know where the stack is, or if the process mapped
+ * something at the top of its address space for some other reason,
+ * we set TASK_SIZE to end at the start of the last page table.
+ * This keeps exit_mmap off the last page, but introduces a leak
+ * of that page. So, we hang onto it here and free it in
+ * destroy_context_skas.
+ */
+
+ mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+
+ *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+ *pte = pte_mkexec(*pte);
+ *pte = pte_wrprotect(*pte);
+ spin_unlock(&mm->page_table_lock);
+ return(0);
+
+ out_pmd:
+ pud_free(pud);
+ out_pte:
+ pmd_free(pmd);
+ out:
+ spin_unlock(&mm->page_table_lock);
+ return(-ENOMEM);
+}
+
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{
- int from;
+ struct mm_struct *cur_mm = current->mm;
+ struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
+ struct mm_id *mm_id = &mm->context.skas.id;
+ unsigned long stack;
+ int from, ret;
- if((current->mm != NULL) && (current->mm != &init_mm))
- from = current->mm->context.skas.mm_fd;
- else from = -1;
+ if(proc_mm){
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ from = cur_mm->context.skas.id.u.mm_fd;
+ else from = -1;
- mm->context.skas.mm_fd = new_mm(from);
- 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);
+ ret = new_mm(from);
+ if(ret < 0){
+ printk("init_new_context_skas - new_mm failed, "
+ "errno = %d\n", ret);
+ return ret;
+ }
+ mm_id->u.mm_fd = ret;
}
+ else {
+ /* This zeros the entry that pgd_alloc didn't, needed since
+ * we are about to reinitialize it, and want mm.nr_ptes to
+ * be accurate.
+ */
+ mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
- return(0);
+ ret = init_stub_pte(mm, CONFIG_STUB_CODE,
+ (unsigned long) &__syscall_stub_start);
+ if(ret)
+ goto out;
+
+ ret = -ENOMEM;
+ stack = get_zeroed_page(GFP_KERNEL);
+ if(stack == 0)
+ goto out;
+ mm_id->stack = stack;
+
+ ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
+ if(ret)
+ goto out_free;
+
+ mm->nr_ptes--;
+
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ mm_id->u.pid = copy_context_skas0(stack,
+ cur_mm_id->u.pid);
+ else mm_id->u.pid = start_userspace(stack);
+ }
+
+ return 0;
+
+ out_free:
+ free_page(mm_id->stack);
+ out:
+ return ret;
}
void destroy_context_skas(struct mm_struct *mm)
{
- os_close_file(mm->context.skas.mm_fd);
-}
+ struct mmu_context_skas *mmu = &mm->context.skas;
-/*
- * 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:
- */
+ if(proc_mm)
+ os_close_file(mmu->id.u.mm_fd);
+ else {
+ os_kill_ptraced_process(mmu->id.u.pid, 1);
+ free_page(mmu->id.stack);
+ free_page(mmu->last_page_table);
+ }
+}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b525fc..ba671dab8878 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.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
*/
@@ -13,7 +13,9 @@
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/user.h>
+#include <sys/time.h>
#include <asm/unistd.h>
+#include <asm/types.h>
#include "user.h"
#include "ptrace_user.h"
#include "time_user.h"
@@ -21,13 +23,18 @@
#include "user_util.h"
#include "kern_util.h"
#include "skas.h"
+#include "stub-data.h"
+#include "mm_id.h"
#include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
#include "os.h"
#include "proc_mm.h"
#include "skas_ptrace.h"
#include "chan_user.h"
#include "signal_user.h"
#include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
#include "process.h"
int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data)
return(1);
}
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
+void wait_stub_done(int pid, int sig, char * fname)
{
- int err;
-
- err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
- if(err)
- panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
- "errno = %d\n", errno);
+ int n, status, err;
+
+ do {
+ if ( sig != -1 ) {
+ err = ptrace(PTRACE_CONT, pid, 0, sig);
+ if(err)
+ panic("%s : continue failed, errno = %d\n",
+ fname, errno);
+ }
+ sig = 0;
+
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ } while((n >= 0) && WIFSTOPPED(status) &&
+ (WSTOPSIG(status) == SIGVTALRM));
+
+ if((n < 0) || !WIFSTOPPED(status) ||
+ (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
+ panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+ "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+ fname, pid, n, errno, status);
+ }
+}
- /* Special handling for i386, which has different structs */
- if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
- memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
- sizeof(struct faultinfo) -
- sizeof(struct ptrace_faultinfo));
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
+{
+ int err;
+
+ if(ptrace_faultinfo){
+ err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+ if(err)
+ panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+ "errno = %d\n", errno);
+
+ /* Special handling for i386, which has different structs */
+ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+ memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+ sizeof(struct faultinfo) -
+ sizeof(struct ptrace_faultinfo));
+ }
+ else {
+ wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+ /* faultinfo is prepared by the stub-segv-handler at start of
+ * the stub stack page. We just have to copy it.
+ */
+ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+ }
}
static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
handle_syscall(regs);
}
-static int userspace_tramp(void *arg)
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
{
- init_new_thread_signals(0);
- enable_timer();
+ void *addr;
+
ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+ init_new_thread_signals(1);
+ enable_timer();
+
+ if(!proc_mm){
+ /* This has a pte, but it can't be mapped in with the usual
+ * tlb_flush mechanism because this is part of that mechanism
+ */
+ int fd;
+ __u64 offset;
+
+ fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+ addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+ PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping mmap stub failed, errno = %d\n",
+ errno);
+ exit(1);
+ }
+
+ if(stack != NULL){
+ fd = phys_mapping(to_phys(stack), &offset);
+ addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping segfault stack failed, "
+ "errno = %d\n", errno);
+ exit(1);
+ }
+ }
+ }
+ if(!ptrace_faultinfo && (stack != NULL)){
+ unsigned long v = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_segv_handler -
+ (unsigned long) &__syscall_stub_start;
+
+ set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+ set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+ SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+ SIGUSR1, -1);
+ }
+
os_stop_process(os_getpid());
return(0);
}
@@ -105,11 +192,11 @@ static int userspace_tramp(void *arg)
#define NR_CPUS 1
int userspace_pid[NR_CPUS];
-void start_userspace(int cpu)
+int start_userspace(unsigned long stub_stack)
{
void *stack;
unsigned long sp;
- int pid, status, n;
+ int pid, status, n, flags;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +204,9 @@ void start_userspace(int cpu)
panic("start_userspace : mmap failed, errno = %d", errno);
sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
- pid = clone(userspace_tramp, (void *) sp,
- CLONE_FILES | CLONE_VM | SIGCHLD, NULL);
+ flags = CLONE_FILES | SIGCHLD;
+ if(proc_mm) flags |= CLONE_VM;
+ pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
if(pid < 0)
panic("start_userspace : clone failed, errno = %d", errno);
@@ -140,7 +228,7 @@ void start_userspace(int cpu)
if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno);
- userspace_pid[cpu] = pid;
+ return(pid);
}
void userspace(union uml_pt_regs *regs)
@@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs)
if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){
case SIGSEGV:
- handle_segv(pid, regs);
+ if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+ user_signal(SIGSEGV, regs, pid);
+ else handle_segv(pid, regs);
break;
case SIGTRAP + 0x80:
handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs)
printk("userspace - child stopped with signal "
"%d\n", WSTOPSIG(status));
}
+ pid = userspace_pid[0];
interrupt_end();
/* Avoid -ERESTARTSYS handling in host */
@@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs)
#define INIT_JMP_HALT 3
#define INIT_JMP_REBOOT 4
+
+int copy_context_skas0(unsigned long new_stack, int pid)
+{
+ int err;
+ unsigned long regs[MAX_REG_NR];
+ unsigned long current_stack = current_stub_stack();
+ struct stub_data *data = (struct stub_data *) current_stack;
+ struct stub_data *child_data = (struct stub_data *) new_stack;
+ __u64 new_offset;
+ int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+
+ /* prepare offset and fd of child's stack as argument for parent's
+ * and child's mmap2 calls
+ */
+ *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
+ .fd = new_fd,
+ .timer = ((struct itimerval)
+ { { 0, 1000000 / hz() },
+ { 0, 1000000 / hz() }})});
+ get_safe_registers(regs);
+
+ /* Set parent's instruction pointer to start of clone-stub */
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_clone_handler -
+ (unsigned long) &__syscall_stub_start;
+ regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+ sizeof(void *);
+ err = ptrace_setregs(pid, regs);
+ if(err < 0)
+ panic("copy_context_skas0 : PTRACE_SETREGS failed, "
+ "pid = %d, errno = %d\n", pid, errno);
+
+ /* set a well known return code for detection of child write failure */
+ child_data->err = 12345678;
+
+ /* Wait, until parent has finished its work: read child's pid from
+ * parent's stack, and check, if bad result.
+ */
+ wait_stub_done(pid, 0, "copy_context_skas0");
+
+ pid = data->err;
+ if(pid < 0)
+ panic("copy_context_skas0 - stub-parent reports error %d\n",
+ pid);
+
+ /* Wait, until child has finished too: read child's result from
+ * child's stack and check it.
+ */
+ wait_stub_done(pid, -1, "copy_context_skas0");
+ if (child_data->err != UML_CONFIG_STUB_DATA)
+ panic("copy_context_skas0 - stub-child reports error %d\n",
+ child_data->err);
+
+ if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
+ "errno = %d\n", errno);
+
+ return pid;
+}
+
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
@@ -334,21 +486,19 @@ void reboot_skas(void)
siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
}
-void switch_mm_skas(int mm_fd)
+void switch_mm_skas(struct mm_id *mm_idp)
{
int err;
#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);
-}
-
-void kill_off_processes_skas(void)
-{
-#warning need to loop over userspace_pids in kill_off_processes_skas
- os_kill_ptraced_process(userspace_pid[0], 1);
+ if(proc_mm){
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+ mm_idp->u.mm_fd);
+ if(err)
+ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+ "errno = %d\n", errno);
+ }
+ else userspace_pid[0] = mm_idp->u.pid;
}
/*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index fc71ef295782..cbabab104ac3 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -111,8 +111,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
void (*handler)(int);
if(current->thread.forking){
- memcpy(&p->thread.regs.regs.skas,
- &current->thread.regs.regs.skas,
+ memcpy(&p->thread.regs.regs.skas, &regs->regs.skas,
sizeof(p->thread.regs.regs.skas));
REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0);
if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp;
@@ -176,12 +175,14 @@ static int start_kernel_proc(void *unused)
return(0);
}
+extern int userspace_pid[];
+
int start_uml_skas(void)
{
- start_userspace(0);
+ if(proc_mm)
+ userspace_pid[0] = start_userspace(0);
init_new_thread_signals(1);
- uml_idle_timer();
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
@@ -202,13 +203,30 @@ int thread_pid_skas(struct task_struct *task)
return(userspace_pid[0]);
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+void kill_off_processes_skas(void)
+{
+ if(proc_mm)
+#warning need to loop over userspace_pids in kill_off_processes_skas
+ os_kill_ptraced_process(userspace_pid[0], 1);
+ else {
+ struct task_struct *p;
+ int pid, me;
+
+ me = os_getpid();
+ for_each_process(p){
+ if(p->mm == NULL)
+ continue;
+
+ pid = p->mm->context.skas.id.u.pid;
+ os_kill_ptraced_process(pid, 1);
+ }
+ }
+}
+
+unsigned long current_stub_stack(void)
+{
+ if(current->mm == NULL)
+ return(0);
+
+ return(current->mm->context.skas.id.stack);
+}
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
deleted file mode 100644
index 98091494b897..000000000000
--- a/arch/um/kernel/skas/time.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <sys/signal.h>
-#include <sys/time.h>
-#include "time_user.h"
-#include "process.h"
-#include "user.h"
-
-void user_time_init_skas(void)
-{
- if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
- panic("Couldn't set SIGALRM handler");
- if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
- panic("Couldn't set SIGVTALRM handler");
- set_interval(ITIMER_VIRTUAL);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index b8c5e71763d1..6230999c672c 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
#include "linux/stddef.h"
#include "linux/sched.h"
+#include "linux/config.h"
#include "linux/mm.h"
#include "asm/page.h"
#include "asm/pgtable.h"
@@ -17,7 +18,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int fd, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
op = &ops[i];
switch(op->type){
case MMAP:
- map(fd, op->u.mmap.addr, op->u.mmap.len,
+ map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
op->u.mmap.fd, op->u.mmap.offset);
break;
case MUNMAP:
- unmap(fd, (void *) op->u.munmap.addr,
+ unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
op->u.munmap.len);
break;
case MPROTECT:
- protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
- op->u.mprotect.r, op->u.mprotect.w,
- op->u.mprotect.x);
+ protect(&mmu->skas.id, op->u.mprotect.addr,
+ op->u.mprotect.len, op->u.mprotect.r,
+ op->u.mprotect.w, op->u.mprotect.x);
break;
default:
printk("Unknown op type %d in do_ops\n", op->type);
@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
}
}
+extern int proc_mm;
+
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force)
{
- int fd = mm->context.skas.mm_fd;
+ if(!proc_mm && (end_addr > CONFIG_STUB_START))
+ end_addr = CONFIG_STUB_START;
- fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
void __flush_tlb_one_skas(unsigned long addr)
@@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
void flush_tlb_mm_skas(struct mm_struct *mm)
{
+ unsigned long end;
+
/* Don't bother flushing if this address space is about to be
* destroyed.
*/
if(atomic_read(&mm->mm_users) == 0)
return;
- fix_range(mm, 0, host_task_size, 0);
- flush_tlb_kernel_range_common(start_vm, end_vm);
+ end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(mm, 0, end, 0);
}
void force_flush_all_skas(void)
{
- fix_range(current->mm, 0, host_task_size, 1);
+ unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(current->mm, 0, end, 1);
}
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
index b7a55251e897..8e1a3501ff46 100644
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -31,7 +31,8 @@ long sys_fork(void)
long ret;
current->thread.forking = 1;
- ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+ ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+ &current->thread.regs, 0, NULL, NULL);
current->thread.forking = 0;
return(ret);
}
@@ -41,8 +42,9 @@ long sys_vfork(void)
long ret;
current->thread.forking = 1;
- ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL,
- NULL);
+ ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+ UPT_SP(&current->thread.regs.regs),
+ &current->thread.regs, 0, NULL, NULL);
current->thread.forking = 0;
return(ret);
}
@@ -162,14 +164,3 @@ int next_syscall_index(int limit)
spin_unlock(&syscall_lock);
return(ret);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index c40c86a3f918..c40b611e3d93 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -33,7 +33,7 @@ void timer(void)
timeradd(&xtime, &local_offset, &xtime);
}
-void set_interval(int timer_type)
+static void set_interval(int timer_type)
{
int usec = 1000000/hz();
struct itimerval interval = ((struct itimerval) { { 0, usec },
@@ -45,12 +45,14 @@ void set_interval(int timer_type)
void enable_timer(void)
{
+ set_interval(ITIMER_VIRTUAL);
+}
+
+void prepare_timer(void * ptr)
+{
int usec = 1000000/hz();
- struct itimerval enable = ((struct itimerval) { { 0, usec },
- { 0, usec }});
- if(setitimer(ITIMER_VIRTUAL, &enable, NULL))
- printk("enable_timer - setitimer failed, errno = %d\n",
- errno);
+ *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
+ { 0, usec }});
}
void disable_timer(void)
@@ -155,13 +157,15 @@ void idle_sleep(int secs)
nanosleep(&ts, NULL);
}
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+/* XXX This partly duplicates init_irq_signals */
+
+void user_time_init(void)
+{
+ set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGALRM, SIGUSR2, -1);
+ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGVTALRM, SIGUSR2, -1);
+ set_interval(ITIMER_VIRTUAL);
+}
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 6516fc52afe0..a8b4ef601f59 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -162,7 +162,7 @@ int __init timer_init(void)
{
int err;
- CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
+ user_time_init();
err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
if(err != 0)
printk(KERN_ERR "timer_init : request_irq failed - "
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477edfdf5..83ec8d4747fd 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int))
{
pgd_t *npgd;
pud_t *npud;
pmd_t *npmd;
pte_t *npte;
+ union mm_context *mmu = &mm->context;
unsigned long addr, end;
int r, w, x;
struct host_vm_op ops[16];
@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pgd_newpage(*npgd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pgd_mkuptodate(*npgd);
}
@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pud_newpage(*npud)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pud_mkuptodate(*npud);
}
@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pmd_newpage(*npmd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pmd_mkuptodate(*npmd);
}
@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
op_index = add_mmap(addr,
pte_val(*npte) & PAGE_MASK,
PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
else op_index = add_munmap(addr, PAGE_SIZE, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
}
else if(pte_newprot(*npte))
op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
*npte = pte_mkuptodate(*npte);
addr += PAGE_SIZE;
}
- (*do_ops)(data, ops, op_index);
+ (*do_ops)(mmu, ops, op_index);
}
int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
return(updated);
}
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
-void flush_tlb_all(void)
-{
- flush_tlb_mm(current->mm);
-}
-
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
- flush_tlb_kernel_range_common, start, end);
-}
-
-void flush_tlb_kernel_vm(void)
-{
- CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
- flush_tlb_kernel_range_common(start_vm, end_vm));
-}
-
-void __flush_tlb_one(unsigned long addr)
-{
- CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
-}
-
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
- end);
-}
-
-void flush_tlb_mm(struct mm_struct *mm)
-{
- CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
-}
-
-void force_flush_all(void)
-{
- CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
-}
-
pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
{
return(pgd_offset(mm, address));
@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
}
int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int r, int w, int x, struct host_vm_op *ops, int index,
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
__u64 offset;
struct host_vm_op *last;
@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
- int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int index, int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
- struct host_vm_op *ops, int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ struct host_vm_op *ops, int index, int last_filled,
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
.x = x } } });
return(index);
}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+ address &= PAGE_MASK;
+ flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+ flush_tlb_mm(current->mm);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+ flush_tlb_kernel_range_common, start, end);
+}
+
+void flush_tlb_kernel_vm(void)
+{
+ CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+ flush_tlb_kernel_range_common(start_vm, end_vm));
+}
+
+void __flush_tlb_one(unsigned long addr)
+{
+ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
+ end);
+}
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
+}
+
+void force_flush_all(void)
+{
+ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
+}
+
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
index 3fd2554e60b6..6939e5af8472 100644
--- a/arch/um/kernel/tt/Makefile
+++ b/arch/um/kernel/tt/Makefile
@@ -4,11 +4,11 @@
#
obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \
- syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \
+ syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
uaccess.o uaccess_user.o
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
-USER_OBJS := gdb.o time.o tracer.o
+USER_OBJS := gdb.o tracer.o
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
index 19a0ad7b35b3..37e22d71a0d9 100644
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -153,10 +153,10 @@ void remove_gdb_cb(void *unused)
exit_debugger_cb(NULL);
}
-int gdb_remove(char *unused)
+int gdb_remove(int unused)
{
initial_thread_cb(remove_gdb_cb, NULL);
- return(0);
+ return 0;
}
void signal_usr1(int sig)
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
index 93fb121f86af..26506388a6aa 100644
--- a/arch/um/kernel/tt/gdb_kern.c
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -10,7 +10,7 @@
#ifdef CONFIG_MCONSOLE
extern int gdb_config(char *str);
-extern int gdb_remove(char *unused);
+extern int gdb_remove(int n);
static struct mc_device gdb_mc = {
.name = "gdb",
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
index 8eff674107ca..738435461e13 100644
--- a/arch/um/kernel/tt/include/debug.h
+++ b/arch/um/kernel/tt/include/debug.h
@@ -4,8 +4,8 @@
* Licensed under the GPL
*/
-#ifndef __DEBUG_H
-#define __DEBUG_H
+#ifndef __UML_TT_DEBUG_H
+#define __UML_TT_DEBUG_H
extern int debugger_proxy(int status, pid_t pid);
extern void child_proxy(pid_t pid, int status);
@@ -13,17 +13,6 @@ extern void init_proxy (pid_t pid, int waiting, int status);
extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd);
extern void fake_child_exit(void);
extern int gdb_config(char *str);
-extern int gdb_remove(char *unused);
+extern int gdb_remove(int unused);
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
index efe462019069..e171e15fead5 100644
--- a/arch/um/kernel/tt/include/mode-tt.h
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -13,7 +13,6 @@ enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB };
extern int tracing_pid;
extern int tracer(int (*init_proc)(void *), void *sp);
-extern void user_time_init_tt(void);
extern void sig_handler_common_tt(int sig, void *sc);
extern void syscall_handler_tt(int sig, union uml_pt_regs *regs);
extern void reboot_tt(void);
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 776310fd5b8b..a189a2b92935 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -266,10 +266,10 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
}
if(current->thread.forking){
- sc_to_sc(UPT_SC(&p->thread.regs.regs),
- UPT_SC(&current->thread.regs.regs));
+ sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(&regs->regs));
SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0);
- if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
+ if(sp != 0)
+ SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
}
p->thread.mode.tt.extern_pid = new_pid;
@@ -459,14 +459,3 @@ int is_valid_pid(int pid)
read_unlock(&tasklist_lock);
return(0);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
deleted file mode 100644
index 8565b71b07cd..000000000000
--- a/arch/um/kernel/tt/time.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
- * Licensed under the GPL
- */
-
-#include <signal.h>
-#include <sys/time.h>
-#include <time_user.h>
-#include "process.h"
-#include "user.h"
-
-void user_time_init_tt(void)
-{
- if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR)
- panic("Couldn't set SIGVTALRM handler");
- set_interval(ITIMER_VIRTUAL);
-}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216ad86f1..2eefb43bc9c2 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int unused, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
panic("fix_range fixing wrong address space, current = 0x%p",
current);
- fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 61dfd4fef752..163476a8cb1b 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -30,6 +30,7 @@ SECTIONS
_einittext = .;
}
. = ALIGN(4096);
+
.text :
{
*(.text)
@@ -39,6 +40,12 @@ SECTIONS
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
}
#include "asm/common.lds.S"
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index 9a0ad094d926..3125d320722c 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -121,6 +121,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* 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/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
index 6286c974bbeb..44438d15c3d6 100644
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -69,6 +69,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* 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/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 7459d09c233e..17f305b6bade 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -16,6 +16,11 @@ define unprofile
endef
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+ $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
quiet_cmd_make_link = SYMLINK $@
cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 095bcdb0b9cc..77c3c4d29f55 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
- ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
- sys_call_table.o
+ ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+ syscalls.o sysrq.o sys_call_table.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
@@ -16,6 +16,14 @@ semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 03913ca5d256..4efc69a039d7 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -312,7 +312,7 @@ long sys_sigreturn(struct pt_regs regs)
unsigned long __user *extramask = frame->extramask;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
- if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
+ if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
copy_from_user(&set.sig[1], extramask, sig_size))
goto segfault;
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 000000000000..2f2c70a8f043
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,8 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ int $0x80
+ mov %eax, UML_CONFIG_STUB_DATA
+ int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 000000000000..b251442ad0b1
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ sc);
+
+ __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+ __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+ "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Pop the frame pointer and return address since we need to leave
+ * the stack in its original form when we do the sigreturn here, by
+ * hand.
+ */
+ __asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
+ "int $0x80" : : "g" (__NR_sigreturn));
+}
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
index 335e2d89504d..83e9be820a86 100644
--- a/arch/um/sys-i386/syscalls.c
+++ b/arch/um/sys-i386/syscalls.c
@@ -69,15 +69,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
{
long ret;
- /* XXX: normal arch do here this pass, and also pass the regs to
- * do_fork, instead of NULL. Currently the arch-independent code
- * ignores these values, while the UML code (actually it's
- * copy_thread) does the right thing. But this should change,
- probably. */
- /*if (!newsp)
- newsp = UPT_SP(current->thread.regs);*/
+ if (!newsp)
+ newsp = UPT_SP(&current->thread.regs.regs);
current->thread.forking = 1;
- ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+ ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+ child_tid);
current->thread.forking = 0;
return(ret);
}
@@ -197,14 +193,3 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
return ret;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 2bc6f6849010..7488206ce6f4 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,8 @@
#XXX: why into lib-y?
lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
- ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
- syscalls.o sysrq.o thunk.o syscall_table.o
+ ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+ stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
obj-y := ksyms.o
obj-$(CONFIG_MODULES) += module.o um_module.o
@@ -28,6 +28,14 @@ semaphore.c-dir = kernel
thunk.S-dir = lib
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
new file mode 100644
index 000000000000..31c14925716b
--- /dev/null
+++ b/arch/um/sys-x86_64/stub.S
@@ -0,0 +1,15 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ syscall
+ /* We don't have 64-bit constants, so this constructs the address
+ * we need.
+ */
+ movq $(UML_CONFIG_STUB_DATA >> 32), %rbx
+ salq $32, %rbx
+ movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
+ or %rcx, %rbx
+ movq %rax, (%rbx)
+ int3
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
new file mode 100644
index 000000000000..161d1fe9c034
--- /dev/null
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <linux/compiler.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct ucontext *uc;
+
+ __asm__("movq %%rdx, %0" : "=g" (uc) :);
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ &uc->uc_mcontext);
+
+ __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
+ __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
+ "syscall": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Two popqs to restore the stack to the state just before entering
+ * the handler, one pops the return address, the other pops the frame
+ * pointer.
+ */
+ __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
+ (__NR_rt_sigreturn));
+}
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index 6f44f40204ed..3259a4db4534 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -174,26 +174,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
{
long ret;
- /* XXX: normal arch do here this pass, and also pass the regs to
- * do_fork, instead of NULL. Currently the arch-independent code
- * ignores these values, while the UML code (actually it's
- * copy_thread) does the right thing. But this should change,
- probably. */
- /*if (!newsp)
- newsp = UPT_SP(current->thread.regs);*/
+ if (!newsp)
+ newsp = UPT_SP(&current->thread.regs.regs);
current->thread.forking = 1;
- ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+ ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+ child_tid);
current->thread.forking = 0;
return(ret);
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/v850/Kconfig b/arch/v850/Kconfig
index 27febd6ffa80..89c053b6c2c4 100644
--- a/arch/v850/Kconfig
+++ b/arch/v850/Kconfig
@@ -250,6 +250,8 @@ source "fs/Kconfig.binfmt"
endmenu
+source "net/Kconfig"
+
#############################################################################
source "drivers/base/Kconfig"
@@ -283,7 +285,7 @@ source "drivers/ieee1394/Kconfig"
source "drivers/message/i2o/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
diff --git a/arch/v850/lib/checksum.c b/arch/v850/lib/checksum.c
index d308b724c023..fa5872633075 100644
--- a/arch/v850/lib/checksum.c
+++ b/arch/v850/lib/checksum.c
@@ -138,7 +138,8 @@ unsigned int csum_partial_copy(const unsigned char *src, unsigned char *dst,
* 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 unsigned char *src, unsigned char *dst,
+unsigned int csum_partial_copy_from_user (const unsigned char *src,
+ unsigned char *dst,
int len, unsigned int sum,
int *err_ptr)
{
diff --git a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig
index db259757dc8a..4b8326177c52 100644
--- a/arch/x86_64/Kconfig
+++ b/arch/x86_64/Kconfig
@@ -207,33 +207,6 @@ config SMP
If you don't know what to do here, say N.
-config PREEMPT
- bool "Preemptible Kernel"
- ---help---
- This option reduces the latency of the kernel when reacting to
- real-time or interactive events by allowing a low priority process to
- be preempted even if it is in kernel mode executing a system call.
- This allows applications to run more reliably even when the system is
- under load. On contrary it may also break your drivers and add
- priority inheritance problems to your system. Don't select it if
- you rely on a stable system or have slightly obscure hardware.
- It's also not very well tested on x86-64 currently.
- You have been warned.
-
- Say Y here if you are feeling brave and building a kernel for a
- desktop, embedded or real-time system. Say N if you are unsure.
-
-config PREEMPT_BKL
- bool "Preempt The Big Kernel Lock"
- depends on PREEMPT
- default y
- help
- This option reduces the latency of the kernel by making the
- big kernel lock preemptible.
-
- Say Y here if you are building a kernel for a desktop system.
- Say N if you are unsure.
-
config SCHED_SMT
bool "SMT (Hyperthreading) scheduler support"
depends on SMP
@@ -244,6 +217,8 @@ config SCHED_SMT
cost of slightly increased overhead in some places. If unsure say
N here.
+source "kernel/Kconfig.preempt"
+
config K8_NUMA
bool "K8 NUMA support"
select NUMA
@@ -313,6 +288,15 @@ config NR_CPUS
This is purely to save memory - each supported CPU requires
memory in the static kernel configuration.
+config HOTPLUG_CPU
+ bool "Support for hot-pluggable CPUs (EXPERIMENTAL)"
+ depends on SMP && HOTPLUG && EXPERIMENTAL
+ help
+ Say Y here to experiment with turning CPUs off and on. CPUs
+ can be controlled through /sys/devices/system/cpu/cpu#.
+ Say N if you want to disable CPU hotplug.
+
+
config HPET_TIMER
bool
default y
@@ -385,6 +369,34 @@ config X86_MCE_INTEL
Additional support for intel specific MCE features such as
the thermal monitor.
+config PHYSICAL_START
+ hex "Physical address where the kernel is loaded" if EMBEDDED
+ default "0x100000"
+ help
+ This gives the physical address where the kernel is loaded.
+ Primarily used in the case of kexec on panic where the
+ fail safe kernel needs to run at a different address than
+ the panic-ed kernel.
+
+ Don't change this unless you know what you are doing.
+
+config KEXEC
+ bool "kexec system call (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ help
+ kexec is a system call that implements the ability to shutdown your
+ current kernel, and to start another kernel. It is like a reboot
+ but it is indepedent of the system firmware. And like a reboot
+ you can start any kernel with it, not just Linux.
+
+ The name comes from the similiarity to the exec system call.
+
+ It is an ongoing process to be certain the hardware in a machine
+ is properly shutdown, so do not be surprised if this code does not
+ initially work for you. It may help to enable device hotplugging
+ support. As of this writing the exact hardware interface is
+ strongly in flux, so no good recommendation can be made.
+
config SECCOMP
bool "Enable seccomp to safely compute untrusted bytecode"
depends on PROC_FS
@@ -503,6 +515,8 @@ config UID16
endmenu
+source "net/Kconfig"
+
source drivers/Kconfig
source "drivers/firmware/Kconfig"
diff --git a/arch/x86_64/Makefile b/arch/x86_64/Makefile
index 6f90c246c418..428915697675 100644
--- a/arch/x86_64/Makefile
+++ b/arch/x86_64/Makefile
@@ -35,7 +35,7 @@ export IA32_CC IA32_LD IA32_AS IA32_OBJCOPY IA32_CPP
LDFLAGS := -m elf_x86_64
OBJCOPYFLAGS := -O binary -R .note -R .comment -S
-LDFLAGS_vmlinux := -e stext
+LDFLAGS_vmlinux :=
CHECKFLAGS += -D__x86_64__ -m64
@@ -65,7 +65,9 @@ CFLAGS += $(call cc-option,-mno-sse -mno-mmx -mno-sse2 -mno-3dnow,)
head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kernel/init_task.o
libs-y += arch/x86_64/lib/
-core-y += arch/x86_64/kernel/ arch/x86_64/mm/
+core-y += arch/x86_64/kernel/ \
+ arch/x86_64/mm/ \
+ arch/x86_64/crypto/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
diff --git a/arch/x86_64/boot/compressed/head.S b/arch/x86_64/boot/compressed/head.S
index 27264dbd575c..6f55565e4d42 100644
--- a/arch/x86_64/boot/compressed/head.S
+++ b/arch/x86_64/boot/compressed/head.S
@@ -2,8 +2,6 @@
* linux/boot/head.S
*
* Copyright (C) 1991, 1992, 1993 Linus Torvalds
- *
- * $Id: head.S,v 1.3 2001/04/20 00:59:28 ak Exp $
*/
/*
@@ -21,13 +19,14 @@
*/
/*
- * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
+ * High loaded stuff by Hans Lermen & Werner Almesberger, Feb. 1996
*/
.code32
.text
#include <linux/linkage.h>
#include <asm/segment.h>
+#include <asm/page.h>
.code32
.globl startup_32
@@ -77,7 +76,7 @@ startup_32:
jnz 3f
addl $8,%esp
xorl %ebx,%ebx
- ljmp $(__KERNEL_CS), $0x100000
+ ljmp $(__KERNEL_CS), $__PHYSICAL_START
/*
* We come here, if we were loaded high.
@@ -103,7 +102,7 @@ startup_32:
popl %ecx # lcount
popl %edx # high_buffer_start
popl %eax # hcount
- movl $0x100000,%edi
+ movl $__PHYSICAL_START,%edi
cli # make sure we don't get interrupted
ljmp $(__KERNEL_CS), $0x1000 # and jump to the move routine
@@ -128,7 +127,7 @@ move_routine_start:
movsl
movl %ebx,%esi # Restore setup pointer
xorl %ebx,%ebx
- ljmp $(__KERNEL_CS), $0x100000
+ ljmp $(__KERNEL_CS), $__PHYSICAL_START
move_routine_end:
diff --git a/arch/x86_64/boot/compressed/misc.c b/arch/x86_64/boot/compressed/misc.c
index c8b9216f9e63..b38d5b8b5fb8 100644
--- a/arch/x86_64/boot/compressed/misc.c
+++ b/arch/x86_64/boot/compressed/misc.c
@@ -11,6 +11,7 @@
#include "miscsetup.h"
#include <asm/io.h>
+#include <asm/page.h>
/*
* gzip declarations
@@ -92,8 +93,11 @@ static unsigned long output_ptr = 0;
static void *malloc(int size);
static void free(void *where);
+void* memset(void* s, int c, unsigned n);
+void* memcpy(void* dest, const void* src, unsigned n);
+
static void putstr(const char *);
-
+
extern int end;
static long free_mem_ptr = (long)&end;
static long free_mem_end_ptr;
@@ -284,7 +288,7 @@ void setup_normal_output_buffer(void)
#else
if ((ALT_MEM_K > EXT_MEM_K ? ALT_MEM_K : EXT_MEM_K) < 1024) error("Less than 2MB of memory");
#endif
- output_data = (char *)0x100000; /* Points to 1M */
+ output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */
free_mem_end_ptr = (long)real_mode;
}
@@ -307,8 +311,8 @@ void setup_output_buffer_if_we_run_high(struct moveparams *mv)
low_buffer_size = low_buffer_end - LOW_BUFFER_START;
high_loaded = 1;
free_mem_end_ptr = (long)high_buffer_start;
- if ( (0x100000 + low_buffer_size) > ((ulg)high_buffer_start)) {
- high_buffer_start = (uch *)(0x100000 + low_buffer_size);
+ if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) {
+ high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size);
mv->hcount = 0; /* say: we need not to move high_buffer */
}
else mv->hcount = -1;
diff --git a/arch/x86_64/boot/install.sh b/arch/x86_64/boot/install.sh
index f17b40dfc0f4..198af15a7758 100644
--- a/arch/x86_64/boot/install.sh
+++ b/arch/x86_64/boot/install.sh
@@ -1,6 +1,6 @@
#!/bin/sh
#
-# arch/i386/boot/install.sh
+# arch/x86_64/boot/install.sh
#
# This file is subject to the terms and conditions of the GNU General Public
# License. See the file "COPYING" in the main directory of this archive
diff --git a/arch/x86_64/boot/setup.S b/arch/x86_64/boot/setup.S
index 75d4d2ad93b3..ff58b2832b75 100644
--- a/arch/x86_64/boot/setup.S
+++ b/arch/x86_64/boot/setup.S
@@ -33,7 +33,7 @@
* Transcribed from Intel (as86) -> AT&T (gas) by Chris Noe, May 1999.
* <stiker@northlink.com>
*
- * Fix to work around buggy BIOSes which dont use carry bit correctly
+ * Fix to work around buggy BIOSes which don't use carry bit correctly
* and/or report extended memory in CX/DX for e801h memory size detection
* call. As a result the kernel got wrong figures. The int15/e801h docs
* from Ralf Brown interrupt list seem to indicate AX/BX should be used
@@ -383,7 +383,7 @@ sse_ok:
# a whole bunch of different types, and allows memory holes and
# everything. We scan through this memory map and build a list
# of the first 32 memory areas, which we return at [E820MAP].
-# This is documented at http://www.teleport.com/~acpi/acpihtml/topic245.htm
+# This is documented at http://www.acpi.info/, in the ACPI 2.0 specification.
#define SMAP 0x534d4150
@@ -436,7 +436,7 @@ bail820:
meme801:
stc # fix to work around buggy
- xorw %cx,%cx # BIOSes which dont clear/set
+ xorw %cx,%cx # BIOSes which don't clear/set
xorw %dx,%dx # carry on pass/error of
# e801h memory size call
# or merely pass cx,dx though
@@ -733,7 +733,7 @@ flush_instr:
#
# but we yet haven't reloaded the CS register, so the default size
# of the target offset still is 16 bit.
-# However, using an operant prefix (0x66), the CPU will properly
+# However, using an operand prefix (0x66), the CPU will properly
# take our 48 bit far pointer. (INTeL 80386 Programmer's Reference
# Manual, Mixing 16-bit and 32-bit code, page 16-6)
diff --git a/arch/x86_64/boot/tools/build.c b/arch/x86_64/boot/tools/build.c
index c2fa66313170..18b5bac1c428 100644
--- a/arch/x86_64/boot/tools/build.c
+++ b/arch/x86_64/boot/tools/build.c
@@ -1,6 +1,4 @@
/*
- * $Id: build.c,v 1.3 2001/06/26 15:14:50 pavel Exp $
- *
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright (C) 1997 Martin Mares
*/
@@ -8,7 +6,8 @@
/*
* This file builds a disk-image from three different files:
*
- * - bootsect: exactly 512 bytes of 8086 machine code, loads the rest
+ * - bootsect: compatibility mbr which prints an error message if
+ * someone tries to boot the kernel directly.
* - setup: 8086 machine code, sets up system parm
* - system: 80386 code for actual system
*
diff --git a/arch/x86_64/crypto/Makefile b/arch/x86_64/crypto/Makefile
new file mode 100644
index 000000000000..426d20f4b72e
--- /dev/null
+++ b/arch/x86_64/crypto/Makefile
@@ -0,0 +1,9 @@
+#
+# x86_64/crypto/Makefile
+#
+# Arch-specific CryptoAPI modules.
+#
+
+obj-$(CONFIG_CRYPTO_AES_X86_64) += aes-x86_64.o
+
+aes-x86_64-y := aes-x86_64-asm.o aes.o
diff --git a/arch/x86_64/crypto/aes-x86_64-asm.S b/arch/x86_64/crypto/aes-x86_64-asm.S
new file mode 100644
index 000000000000..483cbb23ab8d
--- /dev/null
+++ b/arch/x86_64/crypto/aes-x86_64-asm.S
@@ -0,0 +1,186 @@
+/* AES (Rijndael) implementation (FIPS PUB 197) for x86_64
+ *
+ * Copyright (C) 2005 Andreas Steinmetz, <ast@domdv.de>
+ *
+ * License:
+ * This code can be distributed under the terms of the GNU General Public
+ * License (GPL) Version 2 provided that the above header down to and
+ * including this sentence is retained in full.
+ */
+
+.extern aes_ft_tab
+.extern aes_it_tab
+.extern aes_fl_tab
+.extern aes_il_tab
+
+.text
+
+#define R1 %rax
+#define R1E %eax
+#define R1X %ax
+#define R1H %ah
+#define R1L %al
+#define R2 %rbx
+#define R2E %ebx
+#define R2X %bx
+#define R2H %bh
+#define R2L %bl
+#define R3 %rcx
+#define R3E %ecx
+#define R3X %cx
+#define R3H %ch
+#define R3L %cl
+#define R4 %rdx
+#define R4E %edx
+#define R4X %dx
+#define R4H %dh
+#define R4L %dl
+#define R5 %rsi
+#define R5E %esi
+#define R6 %rdi
+#define R6E %edi
+#define R7 %rbp
+#define R7E %ebp
+#define R8 %r8
+#define R9 %r9
+#define R10 %r10
+#define R11 %r11
+
+#define prologue(FUNC,BASE,B128,B192,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11) \
+ .global FUNC; \
+ .type FUNC,@function; \
+ .align 8; \
+FUNC: movq r1,r2; \
+ movq r3,r4; \
+ leaq BASE+52(r8),r9; \
+ movq r10,r11; \
+ movl (r7),r5 ## E; \
+ movl 4(r7),r1 ## E; \
+ movl 8(r7),r6 ## E; \
+ movl 12(r7),r7 ## E; \
+ movl (r8),r10 ## E; \
+ xorl -48(r9),r5 ## E; \
+ xorl -44(r9),r1 ## E; \
+ xorl -40(r9),r6 ## E; \
+ xorl -36(r9),r7 ## E; \
+ cmpl $24,r10 ## E; \
+ jb B128; \
+ leaq 32(r9),r9; \
+ je B192; \
+ leaq 32(r9),r9;
+
+#define epilogue(r1,r2,r3,r4,r5,r6,r7,r8,r9) \
+ movq r1,r2; \
+ movq r3,r4; \
+ movl r5 ## E,(r9); \
+ movl r6 ## E,4(r9); \
+ movl r7 ## E,8(r9); \
+ movl r8 ## E,12(r9); \
+ ret;
+
+#define round(TAB,OFFSET,r1,r2,r3,r4,r5,r6,r7,r8,ra,rb,rc,rd) \
+ movzbl r2 ## H,r5 ## E; \
+ movzbl r2 ## L,r6 ## E; \
+ movl TAB+1024(,r5,4),r5 ## E;\
+ movw r4 ## X,r2 ## X; \
+ movl TAB(,r6,4),r6 ## E; \
+ roll $16,r2 ## E; \
+ shrl $16,r4 ## E; \
+ movzbl r4 ## H,r7 ## E; \
+ movzbl r4 ## L,r4 ## E; \
+ xorl OFFSET(r8),ra ## E; \
+ xorl OFFSET+4(r8),rb ## E; \
+ xorl TAB+3072(,r7,4),r5 ## E;\
+ xorl TAB+2048(,r4,4),r6 ## E;\
+ movzbl r1 ## L,r7 ## E; \
+ movzbl r1 ## H,r4 ## E; \
+ movl TAB+1024(,r4,4),r4 ## E;\
+ movw r3 ## X,r1 ## X; \
+ roll $16,r1 ## E; \
+ shrl $16,r3 ## E; \
+ xorl TAB(,r7,4),r5 ## E; \
+ movzbl r3 ## H,r7 ## E; \
+ movzbl r3 ## L,r3 ## E; \
+ xorl TAB+3072(,r7,4),r4 ## E;\
+ xorl TAB+2048(,r3,4),r5 ## E;\
+ movzbl r1 ## H,r7 ## E; \
+ movzbl r1 ## L,r3 ## E; \
+ shrl $16,r1 ## E; \
+ xorl TAB+3072(,r7,4),r6 ## E;\
+ movl TAB+2048(,r3,4),r3 ## E;\
+ movzbl r1 ## H,r7 ## E; \
+ movzbl r1 ## L,r1 ## E; \
+ xorl TAB+1024(,r7,4),r6 ## E;\
+ xorl TAB(,r1,4),r3 ## E; \
+ movzbl r2 ## H,r1 ## E; \
+ movzbl r2 ## L,r7 ## E; \
+ shrl $16,r2 ## E; \
+ xorl TAB+3072(,r1,4),r3 ## E;\
+ xorl TAB+2048(,r7,4),r4 ## E;\
+ movzbl r2 ## H,r1 ## E; \
+ movzbl r2 ## L,r2 ## E; \
+ xorl OFFSET+8(r8),rc ## E; \
+ xorl OFFSET+12(r8),rd ## E; \
+ xorl TAB+1024(,r1,4),r3 ## E;\
+ xorl TAB(,r2,4),r4 ## E;
+
+#define move_regs(r1,r2,r3,r4) \
+ movl r3 ## E,r1 ## E; \
+ movl r4 ## E,r2 ## E;
+
+#define entry(FUNC,BASE,B128,B192) \
+ prologue(FUNC,BASE,B128,B192,R2,R8,R7,R9,R1,R3,R4,R6,R10,R5,R11)
+
+#define return epilogue(R8,R2,R9,R7,R5,R6,R3,R4,R11)
+
+#define encrypt_round(TAB,OFFSET) \
+ round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4) \
+ move_regs(R1,R2,R5,R6)
+
+#define encrypt_final(TAB,OFFSET) \
+ round(TAB,OFFSET,R1,R2,R3,R4,R5,R6,R7,R10,R5,R6,R3,R4)
+
+#define decrypt_round(TAB,OFFSET) \
+ round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4) \
+ move_regs(R1,R2,R5,R6)
+
+#define decrypt_final(TAB,OFFSET) \
+ round(TAB,OFFSET,R2,R1,R4,R3,R6,R5,R7,R10,R5,R6,R3,R4)
+
+/* void aes_encrypt(void *ctx, u8 *out, const u8 *in) */
+
+ entry(aes_encrypt,0,enc128,enc192)
+ encrypt_round(aes_ft_tab,-96)
+ encrypt_round(aes_ft_tab,-80)
+enc192: encrypt_round(aes_ft_tab,-64)
+ encrypt_round(aes_ft_tab,-48)
+enc128: encrypt_round(aes_ft_tab,-32)
+ encrypt_round(aes_ft_tab,-16)
+ encrypt_round(aes_ft_tab, 0)
+ encrypt_round(aes_ft_tab, 16)
+ encrypt_round(aes_ft_tab, 32)
+ encrypt_round(aes_ft_tab, 48)
+ encrypt_round(aes_ft_tab, 64)
+ encrypt_round(aes_ft_tab, 80)
+ encrypt_round(aes_ft_tab, 96)
+ encrypt_final(aes_fl_tab,112)
+ return
+
+/* void aes_decrypt(void *ctx, u8 *out, const u8 *in) */
+
+ entry(aes_decrypt,240,dec128,dec192)
+ decrypt_round(aes_it_tab,-96)
+ decrypt_round(aes_it_tab,-80)
+dec192: decrypt_round(aes_it_tab,-64)
+ decrypt_round(aes_it_tab,-48)
+dec128: decrypt_round(aes_it_tab,-32)
+ decrypt_round(aes_it_tab,-16)
+ decrypt_round(aes_it_tab, 0)
+ decrypt_round(aes_it_tab, 16)
+ decrypt_round(aes_it_tab, 32)
+ decrypt_round(aes_it_tab, 48)
+ decrypt_round(aes_it_tab, 64)
+ decrypt_round(aes_it_tab, 80)
+ decrypt_round(aes_it_tab, 96)
+ decrypt_final(aes_il_tab,112)
+ return
diff --git a/arch/x86_64/crypto/aes.c b/arch/x86_64/crypto/aes.c
new file mode 100644
index 000000000000..2b5c4010ce38
--- /dev/null
+++ b/arch/x86_64/crypto/aes.c
@@ -0,0 +1,324 @@
+/*
+ * Cryptographic API.
+ *
+ * AES Cipher Algorithm.
+ *
+ * Based on Brian Gladman's code.
+ *
+ * Linux developers:
+ * Alexander Kjeldaas <astor@fast.no>
+ * Herbert Valerio Riedel <hvr@hvrlab.org>
+ * Kyle McMartin <kyle@debian.org>
+ * Adam J. Richter <adam@yggdrasil.com> (conversion to 2.5 API).
+ * Andreas Steinmetz <ast@domdv.de> (adapted to x86_64 assembler)
+ *
+ * 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.
+ *
+ * ---------------------------------------------------------------------------
+ * Copyright (c) 2002, Dr Brian Gladman <brg@gladman.me.uk>, Worcester, UK.
+ * All rights reserved.
+ *
+ * LICENSE TERMS
+ *
+ * The free distribution and use of this software in both source and binary
+ * form is allowed (with or without changes) provided that:
+ *
+ * 1. distributions of this source code include the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ *
+ * 2. distributions in binary form include the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other associated materials;
+ *
+ * 3. the copyright holder's name is not used to endorse products
+ * built using this software without specific written permission.
+ *
+ * ALTERNATIVELY, provided that this notice is retained in full, this product
+ * may be distributed under the terms of the GNU General Public License (GPL),
+ * in which case the provisions of the GPL apply INSTEAD OF those given above.
+ *
+ * DISCLAIMER
+ *
+ * This software is provided 'as is' with no explicit or implied warranties
+ * in respect of its properties, including, but not limited to, correctness
+ * and/or fitness for purpose.
+ * ---------------------------------------------------------------------------
+ */
+
+/* Some changes from the Gladman version:
+ s/RIJNDAEL(e_key)/E_KEY/g
+ s/RIJNDAEL(d_key)/D_KEY/g
+*/
+
+#include <asm/byteorder.h>
+#include <linux/bitops.h>
+#include <linux/crypto.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+
+#define AES_MIN_KEY_SIZE 16
+#define AES_MAX_KEY_SIZE 32
+
+#define AES_BLOCK_SIZE 16
+
+/*
+ * #define byte(x, nr) ((unsigned char)((x) >> (nr*8)))
+ */
+static inline u8 byte(const u32 x, const unsigned n)
+{
+ return x >> (n << 3);
+}
+
+#define u32_in(x) le32_to_cpu(*(const __le32 *)(x))
+
+struct aes_ctx
+{
+ u32 key_length;
+ u32 E[60];
+ u32 D[60];
+};
+
+#define E_KEY ctx->E
+#define D_KEY ctx->D
+
+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];
+u32 aes_ft_tab[4][256];
+u32 aes_it_tab[4][256];
+
+u32 aes_fl_tab[4][256];
+u32 aes_il_tab[4][256];
+
+static inline u8 f_mult(u8 a, u8 b)
+{
+ u8 aa = log_tab[a], cc = aa + log_tab[b];
+
+ return pow_tab[cc + (cc < aa ? 1 : 0)];
+}
+
+#define ff_mult(a, b) (a && b ? f_mult(a, b) : 0)
+
+#define ls_box(x) \
+ (aes_fl_tab[0][byte(x, 0)] ^ \
+ aes_fl_tab[1][byte(x, 1)] ^ \
+ aes_fl_tab[2][byte(x, 2)] ^ \
+ aes_fl_tab[3][byte(x, 3)])
+
+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 primitive
+ root is 0x03, used here to generate the tables */
+
+ for (i = 0, p = 1; i < 256; ++i) {
+ pow_tab[i] = (u8)p;
+ log_tab[p] = (u8)i;
+
+ p ^= (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+ }
+
+ log_tab[1] = 0;
+
+ for (i = 0, p = 1; i < 10; ++i) {
+ rco_tab[i] = p;
+
+ p = (p << 1) ^ (p & 0x80 ? 0x01b : 0);
+ }
+
+ for (i = 0; i < 256; ++i) {
+ p = (i ? pow_tab[255 - log_tab[i]] : 0);
+ q = ((p >> 7) | (p << 1)) ^ ((p >> 6) | (p << 2));
+ p ^= 0x63 ^ q ^ ((q >> 6) | (q << 2));
+ sbx_tab[i] = p;
+ isb_tab[p] = (u8)i;
+ }
+
+ for (i = 0; i < 256; ++i) {
+ p = sbx_tab[i];
+
+ t = p;
+ aes_fl_tab[0][i] = t;
+ aes_fl_tab[1][i] = rol32(t, 8);
+ aes_fl_tab[2][i] = rol32(t, 16);
+ aes_fl_tab[3][i] = rol32(t, 24);
+
+ t = ((u32)ff_mult(2, p)) |
+ ((u32)p << 8) |
+ ((u32)p << 16) | ((u32)ff_mult(3, p) << 24);
+
+ aes_ft_tab[0][i] = t;
+ aes_ft_tab[1][i] = rol32(t, 8);
+ aes_ft_tab[2][i] = rol32(t, 16);
+ aes_ft_tab[3][i] = rol32(t, 24);
+
+ p = isb_tab[i];
+
+ t = p;
+ aes_il_tab[0][i] = t;
+ aes_il_tab[1][i] = rol32(t, 8);
+ aes_il_tab[2][i] = rol32(t, 16);
+ aes_il_tab[3][i] = rol32(t, 24);
+
+ t = ((u32)ff_mult(14, p)) |
+ ((u32)ff_mult(9, p) << 8) |
+ ((u32)ff_mult(13, p) << 16) |
+ ((u32)ff_mult(11, p) << 24);
+
+ aes_it_tab[0][i] = t;
+ aes_it_tab[1][i] = rol32(t, 8);
+ aes_it_tab[2][i] = rol32(t, 16);
+ aes_it_tab[3][i] = rol32(t, 24);
+ }
+}
+
+#define star_x(x) (((x) & 0x7f7f7f7f) << 1) ^ ((((x) & 0x80808080) >> 7) * 0x1b)
+
+#define imix_col(y, x) \
+ u = star_x(x); \
+ v = star_x(u); \
+ w = star_x(v); \
+ t = w ^ (x); \
+ (y) = u ^ v ^ w; \
+ (y) ^= ror32(u ^ t, 8) ^ \
+ ror32(v ^ t, 16) ^ \
+ ror32(t, 24)
+
+/* initialise the key schedule from the user supplied key */
+
+#define loop4(i) \
+{ \
+ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \
+ t ^= E_KEY[4 * i]; E_KEY[4 * i + 4] = t; \
+ t ^= E_KEY[4 * i + 1]; E_KEY[4 * i + 5] = t; \
+ t ^= E_KEY[4 * i + 2]; E_KEY[4 * i + 6] = t; \
+ t ^= E_KEY[4 * i + 3]; E_KEY[4 * i + 7] = t; \
+}
+
+#define loop6(i) \
+{ \
+ t = ror32(t, 8); t = ls_box(t) ^ rco_tab[i]; \
+ t ^= E_KEY[6 * i]; E_KEY[6 * i + 6] = t; \
+ t ^= E_KEY[6 * i + 1]; E_KEY[6 * i + 7] = t; \
+ t ^= E_KEY[6 * i + 2]; E_KEY[6 * i + 8] = t; \
+ t ^= E_KEY[6 * i + 3]; E_KEY[6 * i + 9] = t; \
+ t ^= E_KEY[6 * i + 4]; E_KEY[6 * i + 10] = t; \
+ t ^= E_KEY[6 * i + 5]; E_KEY[6 * i + 11] = t; \
+}
+
+#define loop8(i) \
+{ \
+ t = ror32(t, 8); ; t = ls_box(t) ^ rco_tab[i]; \
+ t ^= E_KEY[8 * i]; E_KEY[8 * i + 8] = t; \
+ t ^= E_KEY[8 * i + 1]; E_KEY[8 * i + 9] = t; \
+ t ^= E_KEY[8 * i + 2]; E_KEY[8 * i + 10] = t; \
+ t ^= E_KEY[8 * i + 3]; E_KEY[8 * i + 11] = t; \
+ t = E_KEY[8 * i + 4] ^ ls_box(t); \
+ E_KEY[8 * i + 12] = t; \
+ t ^= E_KEY[8 * i + 5]; E_KEY[8 * i + 13] = t; \
+ t ^= E_KEY[8 * i + 6]; E_KEY[8 * i + 14] = t; \
+ t ^= E_KEY[8 * i + 7]; E_KEY[8 * i + 15] = t; \
+}
+
+static int aes_set_key(void *ctx_arg, const u8 *in_key, unsigned int key_len,
+ u32 *flags)
+{
+ struct aes_ctx *ctx = ctx_arg;
+ u32 i, j, t, u, v, w;
+
+ if (key_len != 16 && key_len != 24 && key_len != 32) {
+ *flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+ }
+
+ ctx->key_length = key_len;
+
+ D_KEY[key_len + 24] = E_KEY[0] = u32_in(in_key);
+ D_KEY[key_len + 25] = E_KEY[1] = u32_in(in_key + 4);
+ D_KEY[key_len + 26] = E_KEY[2] = u32_in(in_key + 8);
+ D_KEY[key_len + 27] = E_KEY[3] = u32_in(in_key + 12);
+
+ switch (key_len) {
+ case 16:
+ t = E_KEY[3];
+ for (i = 0; i < 10; ++i)
+ loop4(i);
+ break;
+
+ case 24:
+ E_KEY[4] = u32_in(in_key + 16);
+ t = E_KEY[5] = u32_in(in_key + 20);
+ for (i = 0; i < 8; ++i)
+ loop6 (i);
+ break;
+
+ case 32:
+ E_KEY[4] = u32_in(in_key + 16);
+ E_KEY[5] = u32_in(in_key + 20);
+ E_KEY[6] = u32_in(in_key + 24);
+ t = E_KEY[7] = u32_in(in_key + 28);
+ for (i = 0; i < 7; ++i)
+ loop8(i);
+ break;
+ }
+
+ D_KEY[0] = E_KEY[key_len + 24];
+ D_KEY[1] = E_KEY[key_len + 25];
+ D_KEY[2] = E_KEY[key_len + 26];
+ D_KEY[3] = E_KEY[key_len + 27];
+
+ for (i = 4; i < key_len + 24; ++i) {
+ j = key_len + 24 - (i & ~3) + (i & 3);
+ imix_col(D_KEY[j], E_KEY[i]);
+ }
+
+ return 0;
+}
+
+extern void aes_encrypt(void *ctx_arg, u8 *out, const u8 *in);
+extern void aes_decrypt(void *ctx_arg, u8 *out, const u8 *in);
+
+static struct crypto_alg aes_alg = {
+ .cra_name = "aes",
+ .cra_flags = CRYPTO_ALG_TYPE_CIPHER,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_module = THIS_MODULE,
+ .cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
+ .cra_u = {
+ .cipher = {
+ .cia_min_keysize = AES_MIN_KEY_SIZE,
+ .cia_max_keysize = AES_MAX_KEY_SIZE,
+ .cia_setkey = aes_set_key,
+ .cia_encrypt = aes_encrypt,
+ .cia_decrypt = aes_decrypt
+ }
+ }
+};
+
+static int __init aes_init(void)
+{
+ gen_tabs();
+ return crypto_register_alg(&aes_alg);
+}
+
+static void __exit aes_fini(void)
+{
+ crypto_unregister_alg(&aes_alg);
+}
+
+module_init(aes_init);
+module_exit(aes_fini);
+
+MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
+MODULE_LICENSE("GPL");
diff --git a/arch/x86_64/ia32/ia32entry.S b/arch/x86_64/ia32/ia32entry.S
index f3ca0db85b5b..cc935427d532 100644
--- a/arch/x86_64/ia32/ia32entry.S
+++ b/arch/x86_64/ia32/ia32entry.S
@@ -589,7 +589,7 @@ ia32_sys_call_table:
.quad compat_sys_mq_timedreceive /* 280 */
.quad compat_sys_mq_notify
.quad compat_sys_mq_getsetattr
- .quad quiet_ni_syscall /* reserved for kexec */
+ .quad compat_sys_kexec_load /* reserved for kexec */
.quad compat_sys_waitid
.quad quiet_ni_syscall /* sys_altroot */
.quad sys_add_key
diff --git a/arch/x86_64/kernel/Makefile b/arch/x86_64/kernel/Makefile
index 5ca4a4598fda..48f9e2c19cd6 100644
--- a/arch/x86_64/kernel/Makefile
+++ b/arch/x86_64/kernel/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_SMP) += smp.o smpboot.o trampoline.o
obj-$(CONFIG_X86_LOCAL_APIC) += apic.o nmi.o
obj-$(CONFIG_X86_IO_APIC) += io_apic.o mpparse.o \
genapic.o genapic_cluster.o genapic_flat.o
+obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o crash.o
obj-$(CONFIG_PM) += suspend.o
obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend_asm.o
obj-$(CONFIG_CPU_FREQ) += cpufreq/
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index a4c630034cd4..185faa911db5 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -67,7 +67,7 @@ wakeup_code:
shll $4, %eax
addl $(gdta - wakeup_code), %eax
movl %eax, gdt_48a +2 - wakeup_code
- lgdt %ds:gdt_48a - wakeup_code # load gdt with whatever is
+ lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is
# appropriate
movl $1, %eax # protected mode (PE) bit
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c
index f8e6cc4fecd4..375d369570ca 100644
--- a/arch/x86_64/kernel/apic.c
+++ b/arch/x86_64/kernel/apic.c
@@ -133,7 +133,7 @@ void __init connect_bsp_APIC(void)
}
}
-void disconnect_bsp_APIC(void)
+void disconnect_bsp_APIC(int virt_wire_setup)
{
if (pic_mode) {
/*
@@ -146,6 +146,42 @@ void disconnect_bsp_APIC(void)
outb(0x70, 0x22);
outb(0x00, 0x23);
}
+ else {
+ /* Go back to Virtual Wire compatibility mode */
+ unsigned long value;
+
+ /* For the spurious interrupt use vector F, and enable it */
+ value = apic_read(APIC_SPIV);
+ value &= ~APIC_VECTOR_MASK;
+ value |= APIC_SPIV_APIC_ENABLED;
+ value |= 0xf;
+ apic_write_around(APIC_SPIV, value);
+
+ if (!virt_wire_setup) {
+ /* For LVT0 make it edge triggered, active high, external and enabled */
+ value = apic_read(APIC_LVT0);
+ value &= ~(APIC_MODE_MASK | APIC_SEND_PENDING |
+ APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+ APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED );
+ value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+ value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_EXTINT);
+ apic_write_around(APIC_LVT0, value);
+ }
+ else {
+ /* Disable LVT0 */
+ apic_write_around(APIC_LVT0, APIC_LVT_MASKED);
+ }
+
+ /* For LVT1 make it edge triggered, active high, nmi and enabled */
+ value = apic_read(APIC_LVT1);
+ value &= ~(
+ APIC_MODE_MASK | APIC_SEND_PENDING |
+ APIC_INPUT_POLARITY | APIC_LVT_REMOTE_IRR |
+ APIC_LVT_LEVEL_TRIGGER | APIC_LVT_MASKED);
+ value |= APIC_LVT_REMOTE_IRR | APIC_SEND_PENDING;
+ value = SET_APIC_DELIVERY_MODE(value, APIC_MODE_NMI);
+ apic_write_around(APIC_LVT1, value);
+ }
}
void disable_local_APIC(void)
@@ -285,7 +321,7 @@ void __init init_bsp_APIC(void)
apic_write_around(APIC_LVT1, value);
}
-void __init setup_local_APIC (void)
+void __cpuinit setup_local_APIC (void)
{
unsigned int value, ver, maxlvt;
@@ -534,7 +570,7 @@ static struct sys_device device_lapic = {
.cls = &lapic_sysclass,
};
-static void __init apic_pm_activate(void)
+static void __cpuinit apic_pm_activate(void)
{
apic_pm_state.active = 1;
}
@@ -774,14 +810,14 @@ void __init setup_boot_APIC_clock (void)
local_irq_enable();
}
-void __init setup_secondary_APIC_clock(void)
+void __cpuinit setup_secondary_APIC_clock(void)
{
local_irq_disable(); /* FIXME: Do we need this? --RR */
setup_APIC_timer(calibration_result);
local_irq_enable();
}
-void __init disable_APIC_timer(void)
+void __cpuinit disable_APIC_timer(void)
{
if (using_apic_timer) {
unsigned long v;
diff --git a/arch/x86_64/kernel/crash.c b/arch/x86_64/kernel/crash.c
new file mode 100644
index 000000000000..d7fa4248501c
--- /dev/null
+++ b/arch/x86_64/kernel/crash.c
@@ -0,0 +1,35 @@
+/*
+ * Architecture specific (x86_64) functions for kexec based crash dumps.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ *
+ * Copyright (C) IBM Corporation, 2004. All rights reserved.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/irq.h>
+#include <linux/reboot.h>
+#include <linux/kexec.h>
+
+#include <asm/processor.h>
+#include <asm/hardirq.h>
+#include <asm/nmi.h>
+#include <asm/hw_irq.h>
+
+note_buf_t crash_notes[NR_CPUS];
+
+void machine_crash_shutdown(struct pt_regs *regs)
+{
+ /* This function is only called after the system
+ * has paniced or is otherwise in a critical state.
+ * The minimum amount of code to allow a kexec'd kernel
+ * to run successfully needs to happen here.
+ *
+ * In practice this means shooting down the other cpus in
+ * an SMP system.
+ */
+}
diff --git a/arch/x86_64/kernel/e820.c b/arch/x86_64/kernel/e820.c
index 7c154dfff64a..6ded3a50dfe6 100644
--- a/arch/x86_64/kernel/e820.c
+++ b/arch/x86_64/kernel/e820.c
@@ -16,6 +16,7 @@
#include <linux/bootmem.h>
#include <linux/ioport.h>
#include <linux/string.h>
+#include <linux/kexec.h>
#include <asm/page.h>
#include <asm/e820.h>
#include <asm/proto.h>
@@ -191,8 +192,6 @@ void __init e820_reserve_resources(void)
int i;
for (i = 0; i < e820.nr_map; i++) {
struct resource *res;
- if (e820.map[i].addr + e820.map[i].size > 0x100000000ULL)
- continue;
res = alloc_bootmem_low(sizeof(struct resource));
switch (e820.map[i].type) {
case E820_RAM: res->name = "System RAM"; break;
@@ -212,6 +211,9 @@ void __init e820_reserve_resources(void)
*/
request_resource(res, &code_resource);
request_resource(res, &data_resource);
+#ifdef CONFIG_KEXEC
+ request_resource(res, &crashk_res);
+#endif
}
}
}
diff --git a/arch/x86_64/kernel/genapic_flat.c b/arch/x86_64/kernel/genapic_flat.c
index b4cbbad04226..282846965080 100644
--- a/arch/x86_64/kernel/genapic_flat.c
+++ b/arch/x86_64/kernel/genapic_flat.c
@@ -7,6 +7,8 @@
* Hacked for x86-64 by James Cleverdon from i386 architecture code by
* Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
* James Cleverdon.
+ * Ashok Raj <ashok.raj@intel.com>
+ * Removed IPI broadcast shortcut to support CPU hotplug
*/
#include <linux/config.h>
#include <linux/threads.h>
@@ -18,6 +20,46 @@
#include <asm/smp.h>
#include <asm/ipi.h>
+/*
+ * The following permit choosing broadcast IPI shortcut v.s sending IPI only
+ * to online cpus via the send_IPI_mask varient.
+ * The mask version is my preferred option, since it eliminates a lot of
+ * other extra code that would need to be written to cleanup intrs sent
+ * to a CPU while offline.
+ *
+ * Sending broadcast introduces lots of trouble in CPU hotplug situations.
+ * These IPI's are delivered to cpu's irrespective of their offline status
+ * and could pickup stale intr data when these CPUS are turned online.
+ *
+ * Not using broadcast is a cleaner approach IMO, but Andi Kleen disagrees with
+ * the idea of not using broadcast IPI's anymore. Hence the run time check
+ * is introduced, on his request so we can choose an alternate mechanism.
+ *
+ * Initial wacky performance tests that collect cycle counts show
+ * no increase in using mask v.s broadcast version. In fact they seem
+ * identical in terms of cycle counts.
+ *
+ * if we need to use broadcast, we need to do the following.
+ *
+ * cli;
+ * hold call_lock;
+ * clear any pending IPI, just ack and clear all pending intr
+ * set cpu_online_map;
+ * release call_lock;
+ * sti;
+ *
+ * The complicated dummy irq processing shown above is not required if
+ * we didnt sent IPI's to wrong CPU's in the first place.
+ *
+ * - Ashok Raj <ashok.raj@intel.com>
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+#define DEFAULT_SEND_IPI (1)
+#else
+#define DEFAULT_SEND_IPI (0)
+#endif
+
+static int no_broadcast=DEFAULT_SEND_IPI;
static cpumask_t flat_target_cpus(void)
{
@@ -45,22 +87,6 @@ static void flat_init_apic_ldr(void)
apic_write_around(APIC_LDR, val);
}
-static void flat_send_IPI_allbutself(int vector)
-{
- /*
- * if there are no other CPUs in the system then
- * we get an APIC send error if we try to broadcast.
- * thus we have to avoid sending IPIs in this case.
- */
- if (num_online_cpus() > 1)
- __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
-}
-
-static void flat_send_IPI_all(int vector)
-{
- __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
-}
-
static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
{
unsigned long mask = cpus_addr(cpumask)[0];
@@ -93,6 +119,39 @@ static void flat_send_IPI_mask(cpumask_t cpumask, int vector)
local_irq_restore(flags);
}
+static inline void __local_flat_send_IPI_allbutself(int vector)
+{
+ if (no_broadcast) {
+ cpumask_t mask = cpu_online_map;
+ int this_cpu = get_cpu();
+
+ cpu_clear(this_cpu, mask);
+ flat_send_IPI_mask(mask, vector);
+ put_cpu();
+ }
+ else
+ __send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
+}
+
+static inline void __local_flat_send_IPI_all(int vector)
+{
+ if (no_broadcast)
+ flat_send_IPI_mask(cpu_online_map, vector);
+ else
+ __send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
+}
+
+static void flat_send_IPI_allbutself(int vector)
+{
+ if (((num_online_cpus()) - 1) >= 1)
+ __local_flat_send_IPI_allbutself(vector);
+}
+
+static void flat_send_IPI_all(int vector)
+{
+ __local_flat_send_IPI_all(vector);
+}
+
static int flat_apic_id_registered(void)
{
return physid_isset(GET_APIC_ID(apic_read(APIC_ID)), phys_cpu_present_map);
@@ -111,6 +170,16 @@ static unsigned int phys_pkg_id(int index_msb)
return ((ebx >> 24) & 0xFF) >> index_msb;
}
+static __init int no_ipi_broadcast(char *str)
+{
+ get_option(&str, &no_broadcast);
+ printk ("Using %s mode\n", no_broadcast ? "No IPI Broadcast" :
+ "IPI Broadcast");
+ return 1;
+}
+
+__setup("no_ipi_broadcast", no_ipi_broadcast);
+
struct genapic apic_flat = {
.name = "flat",
.int_delivery_mode = dest_LowestPrio,
@@ -125,3 +194,12 @@ struct genapic apic_flat = {
.cpu_mask_to_apicid = flat_cpu_mask_to_apicid,
.phys_pkg_id = phys_pkg_id,
};
+
+static int __init print_ipi_mode(void)
+{
+ printk ("Using IPI %s mode\n", no_broadcast ? "No-Shortcut" :
+ "Shortcut");
+ return 0;
+}
+
+late_initcall(print_ipi_mode);
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 9bd2e7a4b81e..8d765aa77a26 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -248,23 +248,23 @@ ENTRY(_stext)
*/
.org 0x1000
ENTRY(init_level4_pgt)
- .quad 0x0000000000102007 /* -> level3_ident_pgt */
+ .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */
.fill 255,8,0
- .quad 0x000000000010a007
+ .quad 0x000000000000a007 + __PHYSICAL_START
.fill 254,8,0
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad 0x0000000000103007 /* -> level3_kernel_pgt */
+ .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */
.org 0x2000
ENTRY(level3_ident_pgt)
- .quad 0x0000000000104007
+ .quad 0x0000000000004007 + __PHYSICAL_START
.fill 511,8,0
.org 0x3000
ENTRY(level3_kernel_pgt)
.fill 510,8,0
/* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */
- .quad 0x0000000000105007 /* -> level2_kernel_pgt */
+ .quad 0x0000000000005007 + __PHYSICAL_START /* -> level2_kernel_pgt */
.fill 1,8,0
.org 0x4000
@@ -337,17 +337,17 @@ ENTRY(empty_bad_pmd_table)
.org 0xa000
ENTRY(level3_physmem_pgt)
- .quad 0x0000000000105007 /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
+ .quad 0x0000000000005007 + __PHYSICAL_START /* -> level2_kernel_pgt (so that __va works even before pagetable_init) */
.org 0xb000
#ifdef CONFIG_ACPI_SLEEP
ENTRY(wakeup_level4_pgt)
- .quad 0x0000000000102007 /* -> level3_ident_pgt */
+ .quad 0x0000000000002007 + __PHYSICAL_START /* -> level3_ident_pgt */
.fill 255,8,0
- .quad 0x000000000010a007
+ .quad 0x000000000000a007 + __PHYSICAL_START
.fill 254,8,0
/* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
- .quad 0x0000000000103007 /* -> level3_kernel_pgt */
+ .quad 0x0000000000003007 + __PHYSICAL_START /* -> level3_kernel_pgt */
#endif
.data
diff --git a/arch/x86_64/kernel/i387.c b/arch/x86_64/kernel/i387.c
index ba139cac57ce..d9b22b633e39 100644
--- a/arch/x86_64/kernel/i387.c
+++ b/arch/x86_64/kernel/i387.c
@@ -42,7 +42,7 @@ void mxcsr_feature_mask_init(void)
* Called at bootup to set up the initial FPU state that is later cloned
* into all processes.
*/
-void __init fpu_init(void)
+void __cpuinit fpu_init(void)
{
unsigned long oldcr0 = read_cr0();
extern void __bad_fxsave_alignment(void);
diff --git a/arch/x86_64/kernel/i8259.c b/arch/x86_64/kernel/i8259.c
index 19eafa0aa95c..a89169095129 100644
--- a/arch/x86_64/kernel/i8259.c
+++ b/arch/x86_64/kernel/i8259.c
@@ -414,10 +414,22 @@ static int i8259A_suspend(struct sys_device *dev, pm_message_t state)
return 0;
}
+static int i8259A_shutdown(struct sys_device *dev)
+{
+ /* Put the i8259A into a quiescent state that
+ * the kernel initialization code can get it
+ * out of.
+ */
+ outb(0xff, 0x21); /* mask all of 8259A-1 */
+ outb(0xff, 0xA1); /* mask all of 8259A-1 */
+ return 0;
+}
+
static struct sysdev_class i8259_sysdev_class = {
set_kset_name("i8259"),
.suspend = i8259A_suspend,
.resume = i8259A_resume,
+ .shutdown = i8259A_shutdown,
};
static struct sys_device device_i8259A = {
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index afd87e64d0a8..d206d7e49cf5 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -330,7 +330,7 @@ static int find_irq_entry(int apic, int pin, int type)
/*
* Find the pin to which IRQ[irq] (ISA) is connected
*/
-static int __init find_isa_irq_pin(int irq, int type)
+static int find_isa_irq_pin(int irq, int type)
{
int i;
@@ -1064,7 +1064,6 @@ void print_all_local_APICs (void)
void __apicdebuginit print_PIC(void)
{
- extern spinlock_t i8259A_lock;
unsigned int v;
unsigned long flags;
@@ -1132,12 +1131,44 @@ static void __init enable_IO_APIC(void)
*/
void disable_IO_APIC(void)
{
+ int pin;
/*
* Clear the IO-APIC before rebooting:
*/
clear_IO_APIC();
- disconnect_bsp_APIC();
+ /*
+ * If the i82559 is routed through an IOAPIC
+ * Put that IOAPIC in virtual wire mode
+ * so legacy interrups can be delivered.
+ */
+ pin = find_isa_irq_pin(0, mp_ExtINT);
+ if (pin != -1) {
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
+
+ memset(&entry, 0, sizeof(entry));
+ entry.mask = 0; /* Enabled */
+ entry.trigger = 0; /* Edge */
+ entry.irr = 0;
+ entry.polarity = 0; /* High */
+ entry.delivery_status = 0;
+ entry.dest_mode = 0; /* Physical */
+ entry.delivery_mode = 7; /* ExtInt */
+ entry.vector = 0;
+ entry.dest.physical.physical_dest = 0;
+
+
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+ }
+
+ disconnect_bsp_APIC(pin != -1);
}
/*
diff --git a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
index 62b112e4deb4..cc3fb85f5145 100644
--- a/arch/x86_64/kernel/irq.c
+++ b/arch/x86_64/kernel/irq.c
@@ -14,6 +14,7 @@
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/module.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/io_apic.h>
@@ -106,3 +107,31 @@ asmlinkage unsigned int do_IRQ(struct pt_regs *regs)
return 1;
}
+#ifdef CONFIG_HOTPLUG_CPU
+void fixup_irqs(cpumask_t map)
+{
+ unsigned int irq;
+ static int warned;
+
+ for (irq = 0; irq < NR_IRQS; irq++) {
+ cpumask_t mask;
+ if (irq == 2)
+ continue;
+
+ cpus_and(mask, irq_affinity[irq], map);
+ if (any_online_cpu(mask) == NR_CPUS) {
+ printk("Breaking affinity for irq %i\n", irq);
+ mask = map;
+ }
+ if (irq_desc[irq].handler->set_affinity)
+ irq_desc[irq].handler->set_affinity(irq, mask);
+ else if (irq_desc[irq].action && !(warned++))
+ printk("Cannot set affinity for irq %i\n", irq);
+ }
+
+ /* That doesn't seem sufficient. Give it 1ms. */
+ local_irq_enable();
+ mdelay(1);
+ local_irq_disable();
+}
+#endif
diff --git a/arch/x86_64/kernel/kprobes.c b/arch/x86_64/kernel/kprobes.c
index 4e680f87a75f..5c6dc7051482 100644
--- a/arch/x86_64/kernel/kprobes.c
+++ b/arch/x86_64/kernel/kprobes.c
@@ -38,7 +38,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/preempt.h>
-#include <linux/moduleloader.h>
+
#include <asm/cacheflush.h>
#include <asm/pgtable.h>
#include <asm/kdebug.h>
@@ -51,8 +51,6 @@ static struct kprobe *kprobe_prev;
static unsigned long kprobe_status_prev, kprobe_old_rflags_prev, kprobe_saved_rflags_prev;
static struct pt_regs jprobe_saved_regs;
static long *jprobe_saved_rsp;
-static kprobe_opcode_t *get_insn_slot(void);
-static void free_insn_slot(kprobe_opcode_t *slot);
void jprobe_return_end(void);
/* copy of the kernel stack at the probe fire time */
@@ -274,48 +272,23 @@ static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs)
regs->rip = (unsigned long)p->ainsn.insn;
}
-struct task_struct *arch_get_kprobe_task(void *ptr)
-{
- return ((struct thread_info *) (((unsigned long) ptr) &
- (~(THREAD_SIZE -1))))->task;
-}
-
void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs)
{
unsigned long *sara = (unsigned long *)regs->rsp;
- struct kretprobe_instance *ri;
- static void *orig_ret_addr;
+ struct kretprobe_instance *ri;
+
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->task = current;
+ ri->ret_addr = (kprobe_opcode_t *) *sara;
- /*
- * Save the return address when the return probe hits
- * the first time, and use it to populate the (krprobe
- * instance)->ret_addr for subsequent return probes at
- * the same addrress since stack address would have
- * the kretprobe_trampoline by then.
- */
- if (((void*) *sara) != kretprobe_trampoline)
- orig_ret_addr = (void*) *sara;
-
- if ((ri = get_free_rp_inst(rp)) != NULL) {
- ri->rp = rp;
- ri->stack_addr = sara;
- ri->ret_addr = orig_ret_addr;
- add_rp_inst(ri);
/* Replace the return addr with trampoline addr */
*sara = (unsigned long) &kretprobe_trampoline;
- } else {
- rp->nmissed++;
- }
-}
-void arch_kprobe_flush_task(struct task_struct *tk)
-{
- struct kretprobe_instance *ri;
- while ((ri = get_rp_inst_tsk(tk)) != NULL) {
- *((unsigned long *)(ri->stack_addr)) =
- (unsigned long) ri->ret_addr;
- recycle_rp_inst(ri);
- }
+ add_rp_inst(ri);
+ } else {
+ rp->nmissed++;
+ }
}
/*
@@ -428,36 +401,59 @@ no_kprobe:
*/
int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs)
{
- struct task_struct *tsk;
- struct kretprobe_instance *ri;
- struct hlist_head *head;
- struct hlist_node *node;
- unsigned long *sara = (unsigned long *)regs->rsp - 1;
-
- tsk = arch_get_kprobe_task(sara);
- head = kretprobe_inst_table_head(tsk);
-
- hlist_for_each_entry(ri, node, head, hlist) {
- if (ri->stack_addr == sara && ri->rp) {
- if (ri->rp->handler)
- ri->rp->handler(ri, regs);
- }
- }
- return 0;
-}
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
+ unsigned long orig_ret_address = 0;
+ unsigned long trampoline_address =(unsigned long)&kretprobe_trampoline;
-void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags)
-{
- struct kretprobe_instance *ri;
- /* RA already popped */
- unsigned long *sara = ((unsigned long *)regs->rsp) - 1;
+ head = kretprobe_inst_table_head(current);
- while ((ri = get_rp_inst(sara))) {
- regs->rip = (unsigned long)ri->ret_addr;
+ /*
+ * It is possible to have multiple instances associated with a given
+ * task either because an multiple functions in the call path
+ * have a return probe installed on them, and/or more then one return
+ * return probe was registered for a target function.
+ *
+ * We can handle this because:
+ * - instances are always inserted at the head of the list
+ * - when multiple return probes are registered for the same
+ * function, the first instance's ret_addr will point to the
+ * real return address, and all the rest will point to
+ * kretprobe_trampoline
+ */
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task != current)
+ /* another task is sharing our hash bucket */
+ continue;
+
+ if (ri->rp && ri->rp->handler)
+ ri->rp->handler(ri, regs);
+
+ orig_ret_address = (unsigned long)ri->ret_addr;
recycle_rp_inst(ri);
+
+ if (orig_ret_address != trampoline_address)
+ /*
+ * This is the real return address. Any other
+ * instances associated with this task are for
+ * other calls deeper on the call stack
+ */
+ break;
}
- regs->eflags &= ~TF_MASK;
+
+ BUG_ON(!orig_ret_address || (orig_ret_address == trampoline_address));
+ regs->rip = orig_ret_address;
+
+ unlock_kprobes();
+ preempt_enable_no_resched();
+
+ /*
+ * By returning a non-zero value, we are telling
+ * kprobe_handler() that we have handled unlocking
+ * and re-enabling preemption.
+ */
+ return 1;
}
/*
@@ -550,8 +546,7 @@ int post_kprobe_handler(struct pt_regs *regs)
current_kprobe->post_handler(current_kprobe, regs, 0);
}
- if (current_kprobe->post_handler != trampoline_post_handler)
- resume_execution(current_kprobe, regs);
+ resume_execution(current_kprobe, regs);
regs->eflags |= kprobe_saved_rflags;
/* Restore the original saved kprobes variables and continue. */
@@ -682,111 +677,12 @@ int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
-/*
- * kprobe->ainsn.insn points to the copy of the instruction to be single-stepped.
- * By default on x86_64, pages we get from kmalloc or vmalloc are not
- * executable. Single-stepping an instruction on such a page yields an
- * oops. So instead of storing the instruction copies in their respective
- * kprobe objects, we allocate a page, map it executable, and store all the
- * instruction copies there. (We can allocate additional pages if somebody
- * inserts a huge number of probes.) Each page can hold up to INSNS_PER_PAGE
- * instruction slots, each of which is MAX_INSN_SIZE*sizeof(kprobe_opcode_t)
- * bytes.
- */
-#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE*sizeof(kprobe_opcode_t)))
-struct kprobe_insn_page {
- struct hlist_node hlist;
- kprobe_opcode_t *insns; /* page of instruction slots */
- char slot_used[INSNS_PER_PAGE];
- int nused;
+static struct kprobe trampoline_p = {
+ .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
+ .pre_handler = trampoline_probe_handler
};
-static struct hlist_head kprobe_insn_pages;
-
-/**
- * get_insn_slot() - Find a slot on an executable page for an instruction.
- * We allocate an executable page if there's no room on existing ones.
- */
-static kprobe_opcode_t *get_insn_slot(void)
-{
- struct kprobe_insn_page *kip;
- struct hlist_node *pos;
-
- hlist_for_each(pos, &kprobe_insn_pages) {
- kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
- if (kip->nused < INSNS_PER_PAGE) {
- int i;
- for (i = 0; i < INSNS_PER_PAGE; i++) {
- if (!kip->slot_used[i]) {
- kip->slot_used[i] = 1;
- kip->nused++;
- return kip->insns + (i*MAX_INSN_SIZE);
- }
- }
- /* Surprise! No unused slots. Fix kip->nused. */
- kip->nused = INSNS_PER_PAGE;
- }
- }
-
- /* All out of space. Need to allocate a new page. Use slot 0.*/
- kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
- if (!kip) {
- return NULL;
- }
-
- /*
- * For the %rip-relative displacement fixups to be doable, we
- * need our instruction copy to be within +/- 2GB of any data it
- * might access via %rip. That is, within 2GB of where the
- * kernel image and loaded module images reside. So we allocate
- * a page in the module loading area.
- */
- kip->insns = module_alloc(PAGE_SIZE);
- if (!kip->insns) {
- kfree(kip);
- return NULL;
- }
- INIT_HLIST_NODE(&kip->hlist);
- hlist_add_head(&kip->hlist, &kprobe_insn_pages);
- memset(kip->slot_used, 0, INSNS_PER_PAGE);
- kip->slot_used[0] = 1;
- kip->nused = 1;
- return kip->insns;
-}
-
-/**
- * free_insn_slot() - Free instruction slot obtained from get_insn_slot().
- */
-static void free_insn_slot(kprobe_opcode_t *slot)
+int __init arch_init_kprobes(void)
{
- struct kprobe_insn_page *kip;
- struct hlist_node *pos;
-
- hlist_for_each(pos, &kprobe_insn_pages) {
- kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
- if (kip->insns <= slot
- && slot < kip->insns+(INSNS_PER_PAGE*MAX_INSN_SIZE)) {
- int i = (slot - kip->insns) / MAX_INSN_SIZE;
- kip->slot_used[i] = 0;
- kip->nused--;
- if (kip->nused == 0) {
- /*
- * Page is no longer in use. Free it unless
- * it's the last one. We keep the last one
- * so as not to have to set it up again the
- * next time somebody inserts a probe.
- */
- hlist_del(&kip->hlist);
- if (hlist_empty(&kprobe_insn_pages)) {
- INIT_HLIST_NODE(&kip->hlist);
- hlist_add_head(&kip->hlist,
- &kprobe_insn_pages);
- } else {
- module_free(NULL, kip->insns);
- kfree(kip);
- }
- }
- return;
- }
- }
+ return register_kprobe(&trampoline_p);
}
diff --git a/arch/x86_64/kernel/machine_kexec.c b/arch/x86_64/kernel/machine_kexec.c
new file mode 100644
index 000000000000..60d1eff41567
--- /dev/null
+++ b/arch/x86_64/kernel/machine_kexec.c
@@ -0,0 +1,250 @@
+/*
+ * machine_kexec.c - handle transition of Linux booting another kernel
+ * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/kexec.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/reboot.h>
+#include <asm/pda.h>
+#include <asm/pgtable.h>
+#include <asm/pgalloc.h>
+#include <asm/tlbflush.h>
+#include <asm/mmu_context.h>
+#include <asm/io.h>
+#include <asm/apic.h>
+#include <asm/cpufeature.h>
+#include <asm/hw_irq.h>
+
+#define LEVEL0_SIZE (1UL << 12UL)
+#define LEVEL1_SIZE (1UL << 21UL)
+#define LEVEL2_SIZE (1UL << 30UL)
+#define LEVEL3_SIZE (1UL << 39UL)
+#define LEVEL4_SIZE (1UL << 48UL)
+
+#define L0_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L1_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_PSE)
+#define L2_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define L3_ATTR (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
+
+static void init_level2_page(u64 *level2p, unsigned long addr)
+{
+ unsigned long end_addr;
+
+ addr &= PAGE_MASK;
+ end_addr = addr + LEVEL2_SIZE;
+ while (addr < end_addr) {
+ *(level2p++) = addr | L1_ATTR;
+ addr += LEVEL1_SIZE;
+ }
+}
+
+static int init_level3_page(struct kimage *image, u64 *level3p,
+ unsigned long addr, unsigned long last_addr)
+{
+ unsigned long end_addr;
+ int result;
+
+ result = 0;
+ addr &= PAGE_MASK;
+ end_addr = addr + LEVEL3_SIZE;
+ while ((addr < last_addr) && (addr < end_addr)) {
+ struct page *page;
+ u64 *level2p;
+
+ page = kimage_alloc_control_pages(image, 0);
+ if (!page) {
+ result = -ENOMEM;
+ goto out;
+ }
+ level2p = (u64 *)page_address(page);
+ init_level2_page(level2p, addr);
+ *(level3p++) = __pa(level2p) | L2_ATTR;
+ addr += LEVEL2_SIZE;
+ }
+ /* clear the unused entries */
+ while (addr < end_addr) {
+ *(level3p++) = 0;
+ addr += LEVEL2_SIZE;
+ }
+out:
+ return result;
+}
+
+
+static int init_level4_page(struct kimage *image, u64 *level4p,
+ unsigned long addr, unsigned long last_addr)
+{
+ unsigned long end_addr;
+ int result;
+
+ result = 0;
+ addr &= PAGE_MASK;
+ end_addr = addr + LEVEL4_SIZE;
+ while ((addr < last_addr) && (addr < end_addr)) {
+ struct page *page;
+ u64 *level3p;
+
+ page = kimage_alloc_control_pages(image, 0);
+ if (!page) {
+ result = -ENOMEM;
+ goto out;
+ }
+ level3p = (u64 *)page_address(page);
+ result = init_level3_page(image, level3p, addr, last_addr);
+ if (result) {
+ goto out;
+ }
+ *(level4p++) = __pa(level3p) | L3_ATTR;
+ addr += LEVEL3_SIZE;
+ }
+ /* clear the unused entries */
+ while (addr < end_addr) {
+ *(level4p++) = 0;
+ addr += LEVEL3_SIZE;
+ }
+out:
+ return result;
+}
+
+
+static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
+{
+ u64 *level4p;
+ level4p = (u64 *)__va(start_pgtable);
+ return init_level4_page(image, level4p, 0, end_pfn << PAGE_SHIFT);
+}
+
+static void set_idt(void *newidt, u16 limit)
+{
+ unsigned char curidt[10];
+
+ /* x86-64 supports unaliged loads & stores */
+ (*(u16 *)(curidt)) = limit;
+ (*(u64 *)(curidt +2)) = (unsigned long)(newidt);
+
+ __asm__ __volatile__ (
+ "lidt %0\n"
+ : "=m" (curidt)
+ );
+};
+
+
+static void set_gdt(void *newgdt, u16 limit)
+{
+ unsigned char curgdt[10];
+
+ /* x86-64 supports unaligned loads & stores */
+ (*(u16 *)(curgdt)) = limit;
+ (*(u64 *)(curgdt +2)) = (unsigned long)(newgdt);
+
+ __asm__ __volatile__ (
+ "lgdt %0\n"
+ : "=m" (curgdt)
+ );
+};
+
+static void load_segments(void)
+{
+ __asm__ __volatile__ (
+ "\tmovl $"STR(__KERNEL_DS)",%eax\n"
+ "\tmovl %eax,%ds\n"
+ "\tmovl %eax,%es\n"
+ "\tmovl %eax,%ss\n"
+ "\tmovl %eax,%fs\n"
+ "\tmovl %eax,%gs\n"
+ );
+#undef STR
+#undef __STR
+}
+
+typedef NORET_TYPE void (*relocate_new_kernel_t)(unsigned long indirection_page,
+ unsigned long control_code_buffer,
+ unsigned long start_address,
+ unsigned long pgtable) ATTRIB_NORET;
+
+const extern unsigned char relocate_new_kernel[];
+const extern unsigned long relocate_new_kernel_size;
+
+int machine_kexec_prepare(struct kimage *image)
+{
+ unsigned long start_pgtable, control_code_buffer;
+ int result;
+
+ /* Calculate the offsets */
+ start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+ control_code_buffer = start_pgtable + 4096UL;
+
+ /* Setup the identity mapped 64bit page table */
+ result = init_pgtable(image, start_pgtable);
+ if (result)
+ return result;
+
+ /* Place the code in the reboot code buffer */
+ memcpy(__va(control_code_buffer), relocate_new_kernel,
+ relocate_new_kernel_size);
+
+ return 0;
+}
+
+void machine_kexec_cleanup(struct kimage *image)
+{
+ return;
+}
+
+/*
+ * Do not allocate memory (or fail in any way) in machine_kexec().
+ * We are past the point of no return, committed to rebooting now.
+ */
+NORET_TYPE void machine_kexec(struct kimage *image)
+{
+ unsigned long page_list;
+ unsigned long control_code_buffer;
+ unsigned long start_pgtable;
+ relocate_new_kernel_t rnk;
+
+ /* Interrupts aren't acceptable while we reboot */
+ local_irq_disable();
+
+ /* Calculate the offsets */
+ page_list = image->head;
+ start_pgtable = page_to_pfn(image->control_code_page) << PAGE_SHIFT;
+ control_code_buffer = start_pgtable + 4096UL;
+
+ /* Set the low half of the page table to my identity mapped
+ * page table for kexec. Leave the high half pointing at the
+ * kernel pages. Don't bother to flush the global pages
+ * as that will happen when I fully switch to my identity mapped
+ * page table anyway.
+ */
+ memcpy(__va(read_cr3()), __va(start_pgtable), PAGE_SIZE/2);
+ __flush_tlb();
+
+
+ /* The segment registers are funny things, they are
+ * automatically loaded from a table, in memory wherever you
+ * set them to a specific selector, but this table is never
+ * accessed again unless you set the segment to a different selector.
+ *
+ * The more common model are caches where the behide
+ * the scenes work is done, but is also dropped at arbitrary
+ * times.
+ *
+ * I take advantage of this here by force loading the
+ * segments, before I zap the gdt with an invalid value.
+ */
+ load_segments();
+ /* The gdt & idt are now invalid.
+ * If you want to load them you must set up your own idt & gdt.
+ */
+ set_gdt(phys_to_virt(0),0);
+ set_idt(phys_to_virt(0),0);
+ /* now call it */
+ rnk = (relocate_new_kernel_t) control_code_buffer;
+ (*rnk)(page_list, control_code_buffer, image->start, start_pgtable);
+}
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c
index 3a89d735a4f6..21e70625a495 100644
--- a/arch/x86_64/kernel/mce.c
+++ b/arch/x86_64/kernel/mce.c
@@ -327,7 +327,7 @@ static void mce_init(void *dummy)
}
/* Add per CPU specific workarounds here */
-static void __init mce_cpu_quirks(struct cpuinfo_x86 *c)
+static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
{
/* This should be disabled by the BIOS, but isn't always */
if (c->x86_vendor == X86_VENDOR_AMD && c->x86 == 15) {
@@ -337,7 +337,7 @@ static void __init mce_cpu_quirks(struct cpuinfo_x86 *c)
}
}
-static void __init mce_cpu_features(struct cpuinfo_x86 *c)
+static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
{
switch (c->x86_vendor) {
case X86_VENDOR_INTEL:
@@ -352,7 +352,7 @@ static void __init mce_cpu_features(struct cpuinfo_x86 *c)
* Called for each booted CPU to set up machine checks.
* Must be called with preempt off.
*/
-void __init mcheck_init(struct cpuinfo_x86 *c)
+void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
{
static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
@@ -411,7 +411,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
memset(mcelog.entry, 0, next * sizeof(struct mce));
mcelog.next = 0;
- synchronize_kernel();
+ synchronize_sched();
/* Collect entries that were still getting written before the synchronize. */
@@ -542,7 +542,7 @@ ACCESSOR(bank4ctl,bank[4],mce_restart())
ACCESSOR(tolerant,tolerant,)
ACCESSOR(check_interval,check_interval,mce_restart())
-static __init int mce_init_device(void)
+static __cpuinit int mce_init_device(void)
{
int err;
if (!mce_available(&boot_cpu_data))
diff --git a/arch/x86_64/kernel/mce_intel.c b/arch/x86_64/kernel/mce_intel.c
index 4db9a640069f..0be0a7959814 100644
--- a/arch/x86_64/kernel/mce_intel.c
+++ b/arch/x86_64/kernel/mce_intel.c
@@ -42,7 +42,7 @@ done:
irq_exit();
}
-static void __init intel_init_thermal(struct cpuinfo_x86 *c)
+static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
{
u32 l, h;
int tm2 = 0;
@@ -93,7 +93,7 @@ static void __init intel_init_thermal(struct cpuinfo_x86 *c)
return;
}
-void __init mce_intel_feature_init(struct cpuinfo_x86 *c)
+void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
{
intel_init_thermal(c);
}
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 31c0f2e6ac91..4e44d6e6b7e5 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -98,7 +98,7 @@ static unsigned int nmi_p4_cccr_val;
(P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \
P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
-static __init inline int nmi_known_cpu(void)
+static __cpuinit inline int nmi_known_cpu(void)
{
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_AMD:
@@ -110,7 +110,7 @@ static __init inline int nmi_known_cpu(void)
}
/* Run after command line and cpu_init init, but before all other checks */
-void __init nmi_watchdog_default(void)
+void __cpuinit nmi_watchdog_default(void)
{
if (nmi_watchdog != NMI_DEFAULT)
return;
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index e59d1f9d6163..7577f9d7a75d 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -8,7 +8,8 @@
*
* X86-64 port
* Andi Kleen.
- *
+ *
+ * CPU hotplug support - ashok.raj@intel.com
* $Id: process.c,v 1.38 2002/01/15 10:08:03 ak Exp $
*/
@@ -18,6 +19,7 @@
#include <stdarg.h>
+#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -154,6 +156,29 @@ void cpu_idle_wait(void)
}
EXPORT_SYMBOL_GPL(cpu_idle_wait);
+#ifdef CONFIG_HOTPLUG_CPU
+DECLARE_PER_CPU(int, cpu_state);
+
+#include <asm/nmi.h>
+/* We don't actually take CPU down, just spin without interrupts. */
+static inline void play_dead(void)
+{
+ idle_task_exit();
+ wbinvd();
+ mb();
+ /* Ack it */
+ __get_cpu_var(cpu_state) = CPU_DEAD;
+
+ while (1)
+ safe_halt();
+}
+#else
+static inline void play_dead(void)
+{
+ BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
/*
* The idle thread. There's no useful work to be
* done, so just try to conserve power and have a
@@ -174,6 +199,8 @@ void cpu_idle (void)
idle = pm_idle;
if (!idle)
idle = default_idle;
+ if (cpu_is_offline(smp_processor_id()))
+ play_dead();
idle();
}
@@ -204,7 +231,7 @@ static void mwait_idle(void)
}
}
-void __init select_idle_routine(const struct cpuinfo_x86 *c)
+void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
{
static int printed;
if (cpu_has(c, X86_FEATURE_MWAIT)) {
@@ -455,6 +482,33 @@ out:
}
/*
+ * This function selects if the context switch from prev to next
+ * has to tweak the TSC disable bit in the cr4.
+ */
+static inline void disable_tsc(struct task_struct *prev_p,
+ struct task_struct *next_p)
+{
+ struct thread_info *prev, *next;
+
+ /*
+ * gcc should eliminate the ->thread_info dereference if
+ * has_secure_computing returns 0 at compile time (SECCOMP=n).
+ */
+ prev = prev_p->thread_info;
+ next = next_p->thread_info;
+
+ if (has_secure_computing(prev) || has_secure_computing(next)) {
+ /* slow path here */
+ if (has_secure_computing(prev) &&
+ !has_secure_computing(next)) {
+ write_cr4(read_cr4() & ~X86_CR4_TSD);
+ } else if (!has_secure_computing(prev) &&
+ has_secure_computing(next))
+ write_cr4(read_cr4() | X86_CR4_TSD);
+ }
+}
+
+/*
* This special macro can be used to load a debugging register
*/
#define loaddebug(thread,r) set_debug(thread->debugreg ## r, r)
@@ -572,6 +626,8 @@ struct task_struct *__switch_to(struct task_struct *prev_p, struct task_struct *
}
}
+ disable_tsc(prev_p, next_p);
+
return prev_p;
}
diff --git a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
index be4b36f762cf..57e71dbdfd69 100644
--- a/arch/x86_64/kernel/reboot.c
+++ b/arch/x86_64/kernel/reboot.c
@@ -66,41 +66,47 @@ static int __init reboot_setup(char *str)
__setup("reboot=", reboot_setup);
-#ifdef CONFIG_SMP
-static void smp_halt(void)
+static inline void kb_wait(void)
{
- int cpuid = safe_smp_processor_id();
- static int first_entry = 1;
+ int i;
- if (reboot_force)
- return;
+ for (i=0; i<0x10000; i++)
+ if ((inb_p(0x64) & 0x02) == 0)
+ break;
+}
- if (first_entry) {
- first_entry = 0;
- smp_call_function((void *)machine_restart, NULL, 1, 0);
- }
-
- smp_stop_cpu();
+void machine_shutdown(void)
+{
+ /* Stop the cpus and apics */
+#ifdef CONFIG_SMP
+ int reboot_cpu_id;
- /* AP calling this. Just halt */
- if (cpuid != boot_cpu_id) {
- for (;;)
- asm("hlt");
+ /* The boot cpu is always logical cpu 0 */
+ reboot_cpu_id = 0;
+
+ /* Make certain the cpu I'm about to reboot on is online */
+ if (!cpu_isset(reboot_cpu_id, cpu_online_map)) {
+ reboot_cpu_id = smp_processor_id();
}
- /* Wait for all other CPUs to have run smp_stop_cpu */
- while (!cpus_empty(cpu_online_map))
- rep_nop();
-}
+ /* Make certain I only run on the appropriate processor */
+ set_cpus_allowed(current, cpumask_of_cpu(reboot_cpu_id));
+
+ /* O.K Now that I'm on the appropriate processor,
+ * stop all of the others.
+ */
+ smp_send_stop();
#endif
-static inline void kb_wait(void)
-{
- int i;
+ local_irq_disable();
- for (i=0; i<0x10000; i++)
- if ((inb_p(0x64) & 0x02) == 0)
- break;
+#ifndef CONFIG_SMP
+ disable_local_APIC();
+#endif
+
+ disable_IO_APIC();
+
+ local_irq_enable();
}
void machine_restart(char * __unused)
@@ -109,9 +115,7 @@ void machine_restart(char * __unused)
printk("machine restart\n");
-#ifdef CONFIG_SMP
- smp_halt();
-#endif
+ machine_shutdown();
if (!reboot_force) {
local_irq_disable();
diff --git a/arch/x86_64/kernel/relocate_kernel.S b/arch/x86_64/kernel/relocate_kernel.S
new file mode 100644
index 000000000000..d24fa9b72a2b
--- /dev/null
+++ b/arch/x86_64/kernel/relocate_kernel.S
@@ -0,0 +1,143 @@
+/*
+ * relocate_kernel.S - put the kernel image in place to boot
+ * Copyright (C) 2002-2005 Eric Biederman <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/linkage.h>
+
+ /*
+ * Must be relocatable PIC code callable as a C function, that once
+ * it starts can not use the previous processes stack.
+ */
+ .globl relocate_new_kernel
+ .code64
+relocate_new_kernel:
+ /* %rdi page_list
+ * %rsi reboot_code_buffer
+ * %rdx start address
+ * %rcx page_table
+ * %r8 arg5
+ * %r9 arg6
+ */
+
+ /* zero out flags, and disable interrupts */
+ pushq $0
+ popfq
+
+ /* set a new stack at the bottom of our page... */
+ lea 4096(%rsi), %rsp
+
+ /* store the parameters back on the stack */
+ pushq %rdx /* store the start address */
+
+ /* Set cr0 to a known state:
+ * 31 1 == Paging enabled
+ * 18 0 == Alignment check disabled
+ * 16 0 == Write protect disabled
+ * 3 0 == No task switch
+ * 2 0 == Don't do FP software emulation.
+ * 0 1 == Proctected mode enabled
+ */
+ movq %cr0, %rax
+ andq $~((1<<18)|(1<<16)|(1<<3)|(1<<2)), %rax
+ orl $((1<<31)|(1<<0)), %eax
+ movq %rax, %cr0
+
+ /* Set cr4 to a known state:
+ * 10 0 == xmm exceptions disabled
+ * 9 0 == xmm registers instructions disabled
+ * 8 0 == performance monitoring counter disabled
+ * 7 0 == page global disabled
+ * 6 0 == machine check exceptions disabled
+ * 5 1 == physical address extension enabled
+ * 4 0 == page size extensions disabled
+ * 3 0 == Debug extensions disabled
+ * 2 0 == Time stamp disable (disabled)
+ * 1 0 == Protected mode virtual interrupts disabled
+ * 0 0 == VME disabled
+ */
+
+ movq $((1<<5)), %rax
+ movq %rax, %cr4
+
+ jmp 1f
+1:
+
+ /* Switch to the identity mapped page tables,
+ * and flush the TLB.
+ */
+ movq %rcx, %cr3
+
+ /* Do the copies */
+ movq %rdi, %rcx /* Put the page_list in %rcx */
+ xorq %rdi, %rdi
+ xorq %rsi, %rsi
+ jmp 1f
+
+0: /* top, read another word for the indirection page */
+
+ movq (%rbx), %rcx
+ addq $8, %rbx
+1:
+ testq $0x1, %rcx /* is it a destination page? */
+ jz 2f
+ movq %rcx, %rdi
+ andq $0xfffffffffffff000, %rdi
+ jmp 0b
+2:
+ testq $0x2, %rcx /* is it an indirection page? */
+ jz 2f
+ movq %rcx, %rbx
+ andq $0xfffffffffffff000, %rbx
+ jmp 0b
+2:
+ testq $0x4, %rcx /* is it the done indicator? */
+ jz 2f
+ jmp 3f
+2:
+ testq $0x8, %rcx /* is it the source indicator? */
+ jz 0b /* Ignore it otherwise */
+ movq %rcx, %rsi /* For ever source page do a copy */
+ andq $0xfffffffffffff000, %rsi
+
+ movq $512, %rcx
+ rep ; movsq
+ jmp 0b
+3:
+
+ /* To be certain of avoiding problems with self-modifying code
+ * I need to execute a serializing instruction here.
+ * So I flush the TLB by reloading %cr3 here, it's handy,
+ * and not processor dependent.
+ */
+ movq %cr3, %rax
+ movq %rax, %cr3
+
+ /* set all of the registers to known values */
+ /* leave %rsp alone */
+
+ xorq %rax, %rax
+ xorq %rbx, %rbx
+ xorq %rcx, %rcx
+ xorq %rdx, %rdx
+ xorq %rsi, %rsi
+ xorq %rdi, %rdi
+ xorq %rbp, %rbp
+ xorq %r8, %r8
+ xorq %r9, %r9
+ xorq %r10, %r9
+ xorq %r11, %r11
+ xorq %r12, %r12
+ xorq %r13, %r13
+ xorq %r14, %r14
+ xorq %r15, %r15
+
+ ret
+relocate_new_kernel_end:
+
+ .globl relocate_new_kernel_size
+relocate_new_kernel_size:
+ .quad relocate_new_kernel_end - relocate_new_kernel
diff --git a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c
index 000015dd5a8b..5fd03225058a 100644
--- a/arch/x86_64/kernel/setup.c
+++ b/arch/x86_64/kernel/setup.c
@@ -41,6 +41,7 @@
#include <linux/kallsyms.h>
#include <linux/edd.h>
#include <linux/mmzone.h>
+#include <linux/kexec.h>
#include <asm/mtrr.h>
#include <asm/uaccess.h>
@@ -367,6 +368,27 @@ static __init void parse_cmdline_early (char ** cmdline_p)
if (!memcmp(from, "noexec=", 7))
nonx_setup(from + 7);
+#ifdef CONFIG_KEXEC
+ /* crashkernel=size@addr specifies the location to reserve for
+ * a crash kernel. By reserving this memory we guarantee
+ * that linux never set's it up as a DMA target.
+ * Useful for holding code to do something appropriate
+ * after a kernel panic.
+ */
+ else if (!memcmp(from, "crashkernel=", 12)) {
+ unsigned long size, base;
+ size = memparse(from+12, &from);
+ if (*from == '@') {
+ base = memparse(from+1, &from);
+ /* FIXME: Do I want a sanity check
+ * to validate the memory range?
+ */
+ crashk_res.start = base;
+ crashk_res.end = base + size - 1;
+ }
+ }
+#endif
+
next_char:
c = *(from++);
if (!c)
@@ -625,6 +647,13 @@ void __init setup_arch(char **cmdline_p)
#endif
sparse_init();
+
+#ifdef CONFIG_KEXEC
+ if (crashk_res.start != crashk_res.end) {
+ reserve_bootmem(crashk_res.start,
+ crashk_res.end - crashk_res.start + 1);
+ }
+#endif
paging_init();
check_ioapic();
@@ -676,7 +705,7 @@ void __init setup_arch(char **cmdline_p)
#endif
}
-static int __init get_model_name(struct cpuinfo_x86 *c)
+static int __cpuinit get_model_name(struct cpuinfo_x86 *c)
{
unsigned int *v;
@@ -692,7 +721,7 @@ static int __init get_model_name(struct cpuinfo_x86 *c)
}
-static void __init display_cacheinfo(struct cpuinfo_x86 *c)
+static void __cpuinit display_cacheinfo(struct cpuinfo_x86 *c)
{
unsigned int n, dummy, eax, ebx, ecx, edx;
@@ -803,7 +832,7 @@ static int __init init_amd(struct cpuinfo_x86 *c)
return r;
}
-static void __init detect_ht(struct cpuinfo_x86 *c)
+static void __cpuinit detect_ht(struct cpuinfo_x86 *c)
{
#ifdef CONFIG_SMP
u32 eax, ebx, ecx, edx;
@@ -864,7 +893,7 @@ static void __init detect_ht(struct cpuinfo_x86 *c)
/*
* find out the number of processor cores on the die
*/
-static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c)
+static int __cpuinit intel_num_cpu_cores(struct cpuinfo_x86 *c)
{
unsigned int eax;
@@ -882,7 +911,7 @@ static int __init intel_num_cpu_cores(struct cpuinfo_x86 *c)
return 1;
}
-static void __init init_intel(struct cpuinfo_x86 *c)
+static void __cpuinit init_intel(struct cpuinfo_x86 *c)
{
/* Cache sizes */
unsigned n;
@@ -902,7 +931,7 @@ static void __init init_intel(struct cpuinfo_x86 *c)
c->x86_num_cores = intel_num_cpu_cores(c);
}
-void __init get_cpu_vendor(struct cpuinfo_x86 *c)
+void __cpuinit get_cpu_vendor(struct cpuinfo_x86 *c)
{
char *v = c->x86_vendor_id;
@@ -923,7 +952,7 @@ struct cpu_model_info {
/* Do some early cpuid on the boot CPU to get some parameter that are
needed before check_bugs. Everything advanced is in identify_cpu
below. */
-void __init early_identify_cpu(struct cpuinfo_x86 *c)
+void __cpuinit early_identify_cpu(struct cpuinfo_x86 *c)
{
u32 tfms;
@@ -977,7 +1006,7 @@ void __init early_identify_cpu(struct cpuinfo_x86 *c)
/*
* This does the hard work of actually picking apart the CPU stuff...
*/
-void __init identify_cpu(struct cpuinfo_x86 *c)
+void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
{
int i;
u32 xlvl;
@@ -1047,6 +1076,10 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
#ifdef CONFIG_X86_MCE
mcheck_init(c);
#endif
+ if (c == &boot_cpu_data)
+ mtrr_bp_init();
+ else
+ mtrr_ap_init();
#ifdef CONFIG_NUMA
if (c != &boot_cpu_data)
numa_add_cpu(c - cpu_data);
@@ -1054,7 +1087,7 @@ void __init identify_cpu(struct cpuinfo_x86 *c)
}
-void __init print_cpu_info(struct cpuinfo_x86 *c)
+void __cpuinit print_cpu_info(struct cpuinfo_x86 *c)
{
if (c->x86_model_id[0])
printk("%s", c->x86_model_id);
diff --git a/arch/x86_64/kernel/setup64.c b/arch/x86_64/kernel/setup64.c
index 678b7ac33b8b..f2b9c6bc999a 100644
--- a/arch/x86_64/kernel/setup64.c
+++ b/arch/x86_64/kernel/setup64.c
@@ -29,7 +29,7 @@
char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
-cpumask_t cpu_initialized __initdata = CPU_MASK_NONE;
+cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
struct x8664_pda cpu_pda[NR_CPUS] __cacheline_aligned;
@@ -171,7 +171,7 @@ void syscall_init(void)
wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000);
}
-void __init check_efer(void)
+void __cpuinit check_efer(void)
{
unsigned long efer;
@@ -188,7 +188,7 @@ void __init check_efer(void)
* 'CPU state barrier', nothing should get across.
* A lot of state is already set up in PDA init.
*/
-void __init cpu_init (void)
+void __cpuinit cpu_init (void)
{
#ifdef CONFIG_SMP
int cpu = stack_smp_processor_id();
diff --git a/arch/x86_64/kernel/signal.c b/arch/x86_64/kernel/signal.c
index 98b7ba95d581..98590a989f3d 100644
--- a/arch/x86_64/kernel/signal.c
+++ b/arch/x86_64/kernel/signal.c
@@ -425,7 +425,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
if (!user_mode(regs))
return 1;
- if (try_to_freeze(0))
+ if (try_to_freeze())
goto no_signal;
if (!oldset)
diff --git a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c
index 1e379ed17b1d..ccae392886af 100644
--- a/arch/x86_64/kernel/smp.c
+++ b/arch/x86_64/kernel/smp.c
@@ -283,6 +283,16 @@ struct call_data_struct {
static struct call_data_struct * call_data;
+void lock_ipi_call_lock(void)
+{
+ spin_lock_irq(&call_lock);
+}
+
+void unlock_ipi_call_lock(void)
+{
+ spin_unlock_irq(&call_lock);
+}
+
/*
* this function sends a 'generic call function' IPI to all other CPUs
* in the system.
diff --git a/arch/x86_64/kernel/smpboot.c b/arch/x86_64/kernel/smpboot.c
index f1ec0f345941..b969ee128728 100644
--- a/arch/x86_64/kernel/smpboot.c
+++ b/arch/x86_64/kernel/smpboot.c
@@ -34,6 +34,7 @@
* Andi Kleen : Converted to new state machine.
* Various cleanups.
* Probably mostly hotplug CPU ready now.
+ * Ashok Raj : CPU hotplug support
*/
@@ -58,11 +59,6 @@
#include <asm/proto.h>
#include <asm/nmi.h>
-/* Change for real CPU hotplug. Note other files need to be fixed
- first too. */
-#define __cpuinit __init
-#define __cpuinitdata __initdata
-
/* Number of siblings per CPU package */
int smp_num_siblings = 1;
/* Package ID of each logical CPU */
@@ -103,6 +99,37 @@ EXPORT_SYMBOL(cpu_core_map);
extern unsigned char trampoline_data[];
extern unsigned char trampoline_end[];
+/* State of each CPU */
+DEFINE_PER_CPU(int, cpu_state) = { 0 };
+
+/*
+ * Store all idle threads, this can be reused instead of creating
+ * a new thread. Also avoids complicated thread destroy functionality
+ * for idle threads.
+ */
+struct task_struct *idle_thread_array[NR_CPUS] __cpuinitdata ;
+
+#define get_idle_for_cpu(x) (idle_thread_array[(x)])
+#define set_idle_for_cpu(x,p) (idle_thread_array[(x)] = (p))
+
+/*
+ * cpu_possible_map should be static, it cannot change as cpu's
+ * are onlined, or offlined. The reason is per-cpu data-structures
+ * are allocated by some modules at init time, and dont expect to
+ * do this dynamically on cpu arrival/departure.
+ * cpu_present_map on the other hand can change dynamically.
+ * In case when cpu_hotplug is not compiled, then we resort to current
+ * behaviour, which is cpu_possible == cpu_present.
+ * If cpu-hotplug is supported, then we need to preallocate for all
+ * those NR_CPUS, hence cpu_possible_map represents entire NR_CPUS range.
+ * - Ashok Raj
+ */
+#ifdef CONFIG_HOTPLUG_CPU
+#define fixup_cpu_possible_map(x) cpu_set((x), cpu_possible_map)
+#else
+#define fixup_cpu_possible_map(x)
+#endif
+
/*
* Currently trivial. Write the real->protected mode
* bootstrap into the page concerned. The caller
@@ -418,6 +445,33 @@ void __cpuinit smp_callin(void)
cpu_set(cpuid, cpu_callin_map);
}
+static inline void set_cpu_sibling_map(int cpu)
+{
+ int i;
+
+ if (smp_num_siblings > 1) {
+ for_each_cpu(i) {
+ if (cpu_core_id[cpu] == cpu_core_id[i]) {
+ cpu_set(i, cpu_sibling_map[cpu]);
+ cpu_set(cpu, cpu_sibling_map[i]);
+ }
+ }
+ } else {
+ cpu_set(cpu, cpu_sibling_map[cpu]);
+ }
+
+ if (current_cpu_data.x86_num_cores > 1) {
+ for_each_cpu(i) {
+ if (phys_proc_id[cpu] == phys_proc_id[i]) {
+ cpu_set(i, cpu_core_map[cpu]);
+ cpu_set(cpu, cpu_core_map[i]);
+ }
+ }
+ } else {
+ cpu_core_map[cpu] = cpu_sibling_map[cpu];
+ }
+}
+
/*
* Setup code on secondary processor (after comming out of the trampoline)
*/
@@ -448,9 +502,28 @@ void __cpuinit start_secondary(void)
enable_APIC_timer();
/*
+ * The sibling maps must be set before turing the online map on for
+ * this cpu
+ */
+ set_cpu_sibling_map(smp_processor_id());
+
+ /*
+ * We need to hold call_lock, so there is no inconsistency
+ * between the time smp_call_function() determines number of
+ * IPI receipients, and the time when the determination is made
+ * for which cpus receive the IPI in genapic_flat.c. Holding this
+ * lock helps us to not include this cpu in a currently in progress
+ * smp_call_function().
+ */
+ lock_ipi_call_lock();
+
+ /*
* Allow the master to continue.
*/
cpu_set(smp_processor_id(), cpu_online_map);
+ per_cpu(cpu_state, smp_processor_id()) = CPU_ONLINE;
+ unlock_ipi_call_lock();
+
mb();
/* Wait for TSC sync to not schedule things before.
@@ -628,33 +701,77 @@ static int __cpuinit wakeup_secondary_via_INIT(int phys_apicid, unsigned int sta
return (send_status | accept_status);
}
+struct create_idle {
+ struct task_struct *idle;
+ struct completion done;
+ int cpu;
+};
+
+void do_fork_idle(void *_c_idle)
+{
+ struct create_idle *c_idle = _c_idle;
+
+ c_idle->idle = fork_idle(c_idle->cpu);
+ complete(&c_idle->done);
+}
+
/*
* Boot one CPU.
*/
static int __cpuinit do_boot_cpu(int cpu, int apicid)
{
- struct task_struct *idle;
unsigned long boot_error;
int timeout;
unsigned long start_rip;
+ struct create_idle c_idle = {
+ .cpu = cpu,
+ .done = COMPLETION_INITIALIZER(c_idle.done),
+ };
+ DECLARE_WORK(work, do_fork_idle, &c_idle);
+
+ c_idle.idle = get_idle_for_cpu(cpu);
+
+ if (c_idle.idle) {
+ c_idle.idle->thread.rsp = (unsigned long) (((struct pt_regs *)
+ (THREAD_SIZE + (unsigned long) c_idle.idle->thread_info)) - 1);
+ init_idle(c_idle.idle, cpu);
+ goto do_rest;
+ }
+
/*
- * We can't use kernel_thread since we must avoid to
- * reschedule the child.
+ * During cold boot process, keventd thread is not spun up yet.
+ * When we do cpu hot-add, we create idle threads on the fly, we should
+ * not acquire any attributes from the calling context. Hence the clean
+ * way to create kernel_threads() is to do that from keventd().
+ * We do the current_is_keventd() due to the fact that ACPI notifier
+ * was also queuing to keventd() and when the caller is already running
+ * in context of keventd(), we would end up with locking up the keventd
+ * thread.
*/
- idle = fork_idle(cpu);
- if (IS_ERR(idle)) {
+ if (!keventd_up() || current_is_keventd())
+ work.func(work.data);
+ else {
+ schedule_work(&work);
+ wait_for_completion(&c_idle.done);
+ }
+
+ if (IS_ERR(c_idle.idle)) {
printk("failed fork for CPU %d\n", cpu);
- return PTR_ERR(idle);
+ return PTR_ERR(c_idle.idle);
}
- cpu_pda[cpu].pcurrent = idle;
+ set_idle_for_cpu(cpu, c_idle.idle);
+
+do_rest:
+
+ cpu_pda[cpu].pcurrent = c_idle.idle;
start_rip = setup_trampoline();
- init_rsp = idle->thread.rsp;
+ init_rsp = c_idle.idle->thread.rsp;
per_cpu(init_tss,cpu).rsp0 = init_rsp;
initial_code = start_secondary;
- clear_ti_thread_flag(idle->thread_info, TIF_FORK);
+ clear_ti_thread_flag(c_idle.idle->thread_info, TIF_FORK);
printk(KERN_INFO "Booting processor %d/%d rip %lx rsp %lx\n", cpu, apicid,
start_rip, init_rsp);
@@ -746,51 +863,6 @@ cycles_t cacheflush_time;
unsigned long cache_decay_ticks;
/*
- * Construct cpu_sibling_map[], so that we can tell the sibling CPU
- * on SMT systems efficiently.
- */
-static __cpuinit void detect_siblings(void)
-{
- int cpu;
-
- for (cpu = 0; cpu < NR_CPUS; cpu++) {
- cpus_clear(cpu_sibling_map[cpu]);
- cpus_clear(cpu_core_map[cpu]);
- }
-
- for_each_online_cpu (cpu) {
- struct cpuinfo_x86 *c = cpu_data + cpu;
- int siblings = 0;
- int i;
- if (smp_num_siblings > 1) {
- for_each_online_cpu (i) {
- if (cpu_core_id[cpu] == cpu_core_id[i]) {
- siblings++;
- cpu_set(i, cpu_sibling_map[cpu]);
- }
- }
- } else {
- siblings++;
- cpu_set(cpu, cpu_sibling_map[cpu]);
- }
-
- if (siblings != smp_num_siblings) {
- printk(KERN_WARNING
- "WARNING: %d siblings found for CPU%d, should be %d\n",
- siblings, cpu, smp_num_siblings);
- smp_num_siblings = siblings;
- }
- if (c->x86_num_cores > 1) {
- for_each_online_cpu(i) {
- if (phys_proc_id[cpu] == phys_proc_id[i])
- cpu_set(i, cpu_core_map[cpu]);
- }
- } else
- cpu_core_map[cpu] = cpu_sibling_map[cpu];
- }
-}
-
-/*
* Cleanup possible dangling ends...
*/
static __cpuinit void smp_cleanup_boot(void)
@@ -823,7 +895,7 @@ static __cpuinit void smp_cleanup_boot(void)
*
* RED-PEN audit/test this more. I bet there is more state messed up here.
*/
-static __cpuinit void disable_smp(void)
+static __init void disable_smp(void)
{
cpu_present_map = cpumask_of_cpu(0);
cpu_possible_map = cpumask_of_cpu(0);
@@ -838,7 +910,7 @@ static __cpuinit void disable_smp(void)
/*
* Handle user cpus=... parameter.
*/
-static __cpuinit void enforce_max_cpus(unsigned max_cpus)
+static __init void enforce_max_cpus(unsigned max_cpus)
{
int i, k;
k = 0;
@@ -855,7 +927,7 @@ static __cpuinit void enforce_max_cpus(unsigned max_cpus)
/*
* Various sanity checks.
*/
-static int __cpuinit smp_sanity_check(unsigned max_cpus)
+static int __init smp_sanity_check(unsigned max_cpus)
{
if (!physid_isset(hard_smp_processor_id(), phys_cpu_present_map)) {
printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
@@ -913,7 +985,7 @@ static int __cpuinit smp_sanity_check(unsigned max_cpus)
* Prepare for SMP bootup. The MP table or ACPI has been read
* earlier. Just do some sanity checking here and enable APIC mode.
*/
-void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
+void __init smp_prepare_cpus(unsigned int max_cpus)
{
int i;
@@ -930,10 +1002,9 @@ void __cpuinit smp_prepare_cpus(unsigned int max_cpus)
int apicid = cpu_present_to_apicid(i);
if (physid_isset(apicid, phys_cpu_present_map)) {
cpu_set(i, cpu_present_map);
- /* possible map would be different if we supported real
- CPU hotplug. */
cpu_set(i, cpu_possible_map);
}
+ fixup_cpu_possible_map(i);
}
if (smp_sanity_check(max_cpus) < 0) {
@@ -978,13 +1049,13 @@ void __init smp_prepare_boot_cpu(void)
int me = smp_processor_id();
cpu_set(me, cpu_online_map);
cpu_set(me, cpu_callout_map);
+ cpu_set(0, cpu_sibling_map[0]);
+ cpu_set(0, cpu_core_map[0]);
+ per_cpu(cpu_state, me) = CPU_ONLINE;
}
/*
* Entry point to boot a CPU.
- *
- * This is all __cpuinit, not __devinit for now because we don't support
- * CPU hotplug (yet).
*/
int __cpuinit __cpu_up(unsigned int cpu)
{
@@ -1001,6 +1072,15 @@ int __cpuinit __cpu_up(unsigned int cpu)
return -EINVAL;
}
+ /*
+ * Already booted CPU?
+ */
+ if (cpu_isset(cpu, cpu_callin_map)) {
+ Dprintk("do_boot_cpu %d Already started\n", cpu);
+ return -ENOSYS;
+ }
+
+ per_cpu(cpu_state, cpu) = CPU_UP_PREPARE;
/* Boot it! */
err = do_boot_cpu(cpu, apicid);
if (err < 0) {
@@ -1013,23 +1093,118 @@ int __cpuinit __cpu_up(unsigned int cpu)
while (!cpu_isset(cpu, cpu_online_map))
cpu_relax();
- return 0;
+ err = 0;
+
+ return err;
}
/*
* Finish the SMP boot.
*/
-void __cpuinit smp_cpus_done(unsigned int max_cpus)
+void __init smp_cpus_done(unsigned int max_cpus)
{
+#ifndef CONFIG_HOTPLUG_CPU
zap_low_mappings();
+#endif
smp_cleanup_boot();
#ifdef CONFIG_X86_IO_APIC
setup_ioapic_dest();
#endif
- detect_siblings();
time_init_gtod();
check_nmi_watchdog();
}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void remove_siblinginfo(int cpu)
+{
+ int sibling;
+
+ for_each_cpu_mask(sibling, cpu_sibling_map[cpu])
+ cpu_clear(cpu, cpu_sibling_map[sibling]);
+ for_each_cpu_mask(sibling, cpu_core_map[cpu])
+ cpu_clear(cpu, cpu_core_map[sibling]);
+ cpus_clear(cpu_sibling_map[cpu]);
+ cpus_clear(cpu_core_map[cpu]);
+ phys_proc_id[cpu] = BAD_APICID;
+ cpu_core_id[cpu] = BAD_APICID;
+}
+
+void remove_cpu_from_maps(void)
+{
+ int cpu = smp_processor_id();
+
+ cpu_clear(cpu, cpu_callout_map);
+ cpu_clear(cpu, cpu_callin_map);
+ clear_bit(cpu, &cpu_initialized); /* was set by cpu_init() */
+}
+
+int __cpu_disable(void)
+{
+ int cpu = smp_processor_id();
+
+ /*
+ * Perhaps use cpufreq to drop frequency, but that could go
+ * into generic code.
+ *
+ * We won't take down the boot processor on i386 due to some
+ * interrupts only being able to be serviced by the BSP.
+ * Especially so if we're not using an IOAPIC -zwane
+ */
+ if (cpu == 0)
+ return -EBUSY;
+
+ disable_APIC_timer();
+
+ /*
+ * HACK:
+ * Allow any queued timer interrupts to get serviced
+ * This is only a temporary solution until we cleanup
+ * fixup_irqs as we do for IA64.
+ */
+ local_irq_enable();
+ mdelay(1);
+
+ local_irq_disable();
+ remove_siblinginfo(cpu);
+
+ /* It's now safe to remove this processor from the online map */
+ cpu_clear(cpu, cpu_online_map);
+ remove_cpu_from_maps();
+ fixup_irqs(cpu_online_map);
+ return 0;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ /* We don't do anything here: idle task is faking death itself. */
+ unsigned int i;
+
+ for (i = 0; i < 10; i++) {
+ /* They ack this in play_dead by setting CPU_DEAD */
+ if (per_cpu(cpu_state, cpu) == CPU_DEAD) {
+ printk ("CPU %d is now offline\n", cpu);
+ return;
+ }
+ current->state = TASK_UNINTERRUPTIBLE;
+ schedule_timeout(HZ/10);
+ }
+ printk(KERN_ERR "CPU %u didn't die...\n", cpu);
+}
+
+#else /* ... !CONFIG_HOTPLUG_CPU */
+
+int __cpu_disable(void)
+{
+ return -ENOSYS;
+}
+
+void __cpu_die(unsigned int cpu)
+{
+ /* We said "no" in __cpu_disable */
+ BUG();
+}
+#endif /* CONFIG_HOTPLUG_CPU */
diff --git a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c
index ebaa1e37d657..0612640d91b1 100644
--- a/arch/x86_64/kernel/suspend.c
+++ b/arch/x86_64/kernel/suspend.c
@@ -44,7 +44,6 @@ void __save_processor_state(struct saved_context *ctxt)
*/
asm volatile ("sgdt %0" : "=m" (ctxt->gdt_limit));
asm volatile ("sidt %0" : "=m" (ctxt->idt_limit));
- asm volatile ("sldt %0" : "=m" (ctxt->ldt));
asm volatile ("str %0" : "=m" (ctxt->tr));
/* XMM0..XMM15 should be handled by kernel_fpu_begin(). */
@@ -69,6 +68,7 @@ void __save_processor_state(struct saved_context *ctxt)
asm volatile ("movq %%cr2, %0" : "=r" (ctxt->cr2));
asm volatile ("movq %%cr3, %0" : "=r" (ctxt->cr3));
asm volatile ("movq %%cr4, %0" : "=r" (ctxt->cr4));
+ asm volatile ("movq %%cr8, %0" : "=r" (ctxt->cr8));
}
void save_processor_state(void)
@@ -90,12 +90,20 @@ void __restore_processor_state(struct saved_context *ctxt)
/*
* control registers
*/
+ asm volatile ("movq %0, %%cr8" :: "r" (ctxt->cr8));
asm volatile ("movq %0, %%cr4" :: "r" (ctxt->cr4));
asm volatile ("movq %0, %%cr3" :: "r" (ctxt->cr3));
asm volatile ("movq %0, %%cr2" :: "r" (ctxt->cr2));
asm volatile ("movq %0, %%cr0" :: "r" (ctxt->cr0));
/*
+ * now restore the descriptor tables to their proper values
+ * ltr is done i fix_processor_context().
+ */
+ asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
+ asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
+
+ /*
* segment registers
*/
asm volatile ("movw %0, %%ds" :: "r" (ctxt->ds));
@@ -108,17 +116,10 @@ void __restore_processor_state(struct saved_context *ctxt)
wrmsrl(MSR_GS_BASE, ctxt->gs_base);
wrmsrl(MSR_KERNEL_GS_BASE, ctxt->gs_kernel_base);
- /*
- * now restore the descriptor tables to their proper values
- * ltr is done i fix_processor_context().
- */
- asm volatile ("lgdt %0" :: "m" (ctxt->gdt_limit));
- asm volatile ("lidt %0" :: "m" (ctxt->idt_limit));
- asm volatile ("lldt %0" :: "m" (ctxt->ldt));
-
fix_processor_context();
do_fpu_end();
+ mtrr_ap_init();
}
void restore_processor_state(void)
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 121646fc43f6..102736630002 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -586,11 +586,17 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
asmlinkage void default_do_nmi(struct pt_regs *regs)
{
unsigned char reason = 0;
+ int cpu;
+
+ cpu = smp_processor_id();
/* Only the BSP gets external NMIs from the system. */
- if (!smp_processor_id())
+ if (!cpu)
reason = get_nmi_reason();
+ if (!cpu_online(cpu))
+ return;
+
if (!(reason & 0xc0)) {
if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
== NOTIFY_STOP)
diff --git a/arch/x86_64/kernel/vmlinux.lds.S b/arch/x86_64/kernel/vmlinux.lds.S
index 59ebd5beda87..2a94f9b60b2d 100644
--- a/arch/x86_64/kernel/vmlinux.lds.S
+++ b/arch/x86_64/kernel/vmlinux.lds.S
@@ -2,7 +2,10 @@
* Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>;
*/
+#define LOAD_OFFSET __START_KERNEL_map
+
#include <asm-generic/vmlinux.lds.h>
+#include <asm/page.h>
#include <linux/config.h>
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
@@ -11,28 +14,30 @@ ENTRY(phys_startup_64)
jiffies_64 = jiffies;
SECTIONS
{
- . = 0xffffffff80100000;
+ . = __START_KERNEL;
phys_startup_64 = startup_64 - LOAD_OFFSET;
_text = .; /* Text and read-only data */
- .text : {
+ .text : AT(ADDR(.text) - LOAD_OFFSET) {
*(.text)
SCHED_TEXT
LOCK_TEXT
*(.fixup)
*(.gnu.warning)
} = 0x9090
- .text.lock : { *(.text.lock) } /* out-of-line lock text */
+ /* out-of-line lock text */
+ .text.lock : AT(ADDR(.text.lock) - LOAD_OFFSET) { *(.text.lock) }
_etext = .; /* End of text section */
. = ALIGN(16); /* Exception table */
__start___ex_table = .;
- __ex_table : { *(__ex_table) }
+ __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) }
__stop___ex_table = .;
RODATA
- .data : { /* Data */
+ /* Data */
+ .data : AT(ADDR(.data) - LOAD_OFFSET) {
*(.data)
CONSTRUCTORS
}
@@ -40,62 +45,99 @@ SECTIONS
_edata = .; /* End of data section */
__bss_start = .; /* BSS */
- .bss : {
+ .bss : AT(ADDR(.bss) - LOAD_OFFSET) {
*(.bss.page_aligned)
*(.bss)
}
__bss_end = .;
+ . = ALIGN(PAGE_SIZE);
+ . = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
+ .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
+ *(.data.cacheline_aligned)
+ }
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
- .data.cacheline_aligned : { *(.data.cacheline_aligned) }
+ .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) {
+ *(.data.read_mostly)
+ }
+
+#define VSYSCALL_ADDR (-10*1024*1024)
+#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095))
+
+#define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR)
+#define VLOAD(x) (ADDR(x) - VLOAD_OFFSET)
-#define AFTER(x) BINALIGN(LOADADDR(x) + SIZEOF(x), 16)
-#define BINALIGN(x,y) (((x) + (y) - 1) & ~((y) - 1))
-#define CACHE_ALIGN(x) BINALIGN(x, CONFIG_X86_L1_CACHE_BYTES)
+#define VVIRT_OFFSET (VSYSCALL_ADDR - VSYSCALL_VIRT_ADDR)
+#define VVIRT(x) (ADDR(x) - VVIRT_OFFSET)
+
+ . = VSYSCALL_ADDR;
+ .vsyscall_0 : AT(VSYSCALL_PHYS_ADDR) { *(.vsyscall_0) }
+ __vsyscall_0 = VSYSCALL_VIRT_ADDR;
- .vsyscall_0 -10*1024*1024: AT ((LOADADDR(.data.cacheline_aligned) + SIZEOF(.data.cacheline_aligned) + 4095) & ~(4095)) { *(.vsyscall_0) }
- __vsyscall_0 = LOADADDR(.vsyscall_0);
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
- .xtime_lock : AT CACHE_ALIGN(AFTER(.vsyscall_0)) { *(.xtime_lock) }
- xtime_lock = LOADADDR(.xtime_lock);
- .vxtime : AT AFTER(.xtime_lock) { *(.vxtime) }
- vxtime = LOADADDR(.vxtime);
- .wall_jiffies : AT AFTER(.vxtime) { *(.wall_jiffies) }
- wall_jiffies = LOADADDR(.wall_jiffies);
- .sys_tz : AT AFTER(.wall_jiffies) { *(.sys_tz) }
- sys_tz = LOADADDR(.sys_tz);
- .sysctl_vsyscall : AT AFTER(.sys_tz) { *(.sysctl_vsyscall) }
- sysctl_vsyscall = LOADADDR(.sysctl_vsyscall);
- .xtime : AT AFTER(.sysctl_vsyscall) { *(.xtime) }
- xtime = LOADADDR(.xtime);
+ .xtime_lock : AT(VLOAD(.xtime_lock)) { *(.xtime_lock) }
+ xtime_lock = VVIRT(.xtime_lock);
+
+ .vxtime : AT(VLOAD(.vxtime)) { *(.vxtime) }
+ vxtime = VVIRT(.vxtime);
+
+ .wall_jiffies : AT(VLOAD(.wall_jiffies)) { *(.wall_jiffies) }
+ wall_jiffies = VVIRT(.wall_jiffies);
+
+ .sys_tz : AT(VLOAD(.sys_tz)) { *(.sys_tz) }
+ sys_tz = VVIRT(.sys_tz);
+
+ .sysctl_vsyscall : AT(VLOAD(.sysctl_vsyscall)) { *(.sysctl_vsyscall) }
+ sysctl_vsyscall = VVIRT(.sysctl_vsyscall);
+
+ .xtime : AT(VLOAD(.xtime)) { *(.xtime) }
+ xtime = VVIRT(.xtime);
+
. = ALIGN(CONFIG_X86_L1_CACHE_BYTES);
- .jiffies : AT CACHE_ALIGN(AFTER(.xtime)) { *(.jiffies) }
- jiffies = LOADADDR(.jiffies);
- .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT (LOADADDR(.vsyscall_0) + 1024) { *(.vsyscall_1) }
- . = LOADADDR(.vsyscall_0) + 4096;
+ .jiffies : AT(VLOAD(.jiffies)) { *(.jiffies) }
+ jiffies = VVIRT(.jiffies);
+
+ .vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1)) { *(.vsyscall_1) }
+ .vsyscall_2 ADDR(.vsyscall_0) + 2048: AT(VLOAD(.vsyscall_2)) { *(.vsyscall_2) }
+ .vsyscall_3 ADDR(.vsyscall_0) + 3072: AT(VLOAD(.vsyscall_3)) { *(.vsyscall_3) }
+
+ . = VSYSCALL_VIRT_ADDR + 4096;
+
+#undef VSYSCALL_ADDR
+#undef VSYSCALL_PHYS_ADDR
+#undef VSYSCALL_VIRT_ADDR
+#undef VLOAD_OFFSET
+#undef VLOAD
+#undef VVIRT_OFFSET
+#undef VVIRT
. = ALIGN(8192); /* init_task */
- .data.init_task : { *(.data.init_task) }
+ .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) {
+ *(.data.init_task)
+ }
. = ALIGN(4096);
- .data.page_aligned : { *(.data.page_aligned) }
+ .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) {
+ *(.data.page_aligned)
+ }
. = ALIGN(4096); /* Init code and data */
__init_begin = .;
- .init.text : {
+ .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) {
_sinittext = .;
*(.init.text)
_einittext = .;
}
__initdata_begin = .;
- .init.data : { *(.init.data) }
+ .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) }
__initdata_end = .;
. = ALIGN(16);
__setup_start = .;
- .init.setup : { *(.init.setup) }
+ .init.setup : AT(ADDR(.init.setup) - LOAD_OFFSET) { *(.init.setup) }
__setup_end = .;
__initcall_start = .;
- .initcall.init : {
+ .initcall.init : AT(ADDR(.initcall.init) - LOAD_OFFSET) {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
@@ -106,32 +148,38 @@ SECTIONS
}
__initcall_end = .;
__con_initcall_start = .;
- .con_initcall.init : { *(.con_initcall.init) }
+ .con_initcall.init : AT(ADDR(.con_initcall.init) - LOAD_OFFSET) {
+ *(.con_initcall.init)
+ }
__con_initcall_end = .;
SECURITY_INIT
. = ALIGN(8);
__alt_instructions = .;
- .altinstructions : { *(.altinstructions) }
+ .altinstructions : AT(ADDR(.altinstructions) - LOAD_OFFSET) {
+ *(.altinstructions)
+ }
__alt_instructions_end = .;
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) {
+ *(.altinstr_replacement)
+ }
/* .exit.text is discard at runtime, not link time, to deal with references
from .altinstructions and .eh_frame */
- .exit.text : { *(.exit.text) }
- .exit.data : { *(.exit.data) }
+ .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
+ .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }
. = ALIGN(4096);
__initramfs_start = .;
- .init.ramfs : { *(.init.ramfs) }
+ .init.ramfs : AT(ADDR(.init.ramfs) - LOAD_OFFSET) { *(.init.ramfs) }
__initramfs_end = .;
. = ALIGN(32);
__per_cpu_start = .;
- .data.percpu : { *(.data.percpu) }
+ .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) }
__per_cpu_end = .;
. = ALIGN(4096);
__init_end = .;
. = ALIGN(4096);
__nosave_begin = .;
- .data_nosave : { *(.data.nosave) }
+ .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) }
. = ALIGN(4096);
__nosave_end = .;
diff --git a/arch/x86_64/mm/numa.c b/arch/x86_64/mm/numa.c
index 84cde796ecb1..ac61c186eb02 100644
--- a/arch/x86_64/mm/numa.c
+++ b/arch/x86_64/mm/numa.c
@@ -251,7 +251,7 @@ void __init numa_initmem_init(unsigned long start_pfn, unsigned long end_pfn)
setup_node_bootmem(0, start_pfn << PAGE_SHIFT, end_pfn << PAGE_SHIFT);
}
-__init void numa_add_cpu(int cpu)
+__cpuinit void numa_add_cpu(int cpu)
{
/* BP is initialized elsewhere */
if (cpu)
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index b693c232fd07..657e88aa0902 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -7,25 +7,50 @@
#include <linux/pci.h>
#include <linux/init.h>
+#include <linux/acpi.h>
#include "pci.h"
#define MMCONFIG_APER_SIZE (256*1024*1024)
-/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
-u32 pci_mmcfg_base_addr;
-
/* Static virtual mapping of the MMCONFIG aperture */
-char *pci_mmcfg_virt;
+struct mmcfg_virt {
+ struct acpi_table_mcfg_config *cfg;
+ char *virt;
+};
+static struct mmcfg_virt *pci_mmcfg_virt;
-static inline char *pci_dev_base(unsigned int bus, unsigned int devfn)
+static char *get_virt(unsigned int seg, int bus)
{
- return pci_mmcfg_virt + ((bus << 20) | (devfn << 12));
+ int cfg_num = -1;
+ struct acpi_table_mcfg_config *cfg;
+
+ while (1) {
+ ++cfg_num;
+ if (cfg_num >= pci_mmcfg_config_num) {
+ /* something bad is going on, no cfg table is found. */
+ /* so we fall back to the old way we used to do this */
+ /* and just rely on the first entry to be correct. */
+ return pci_mmcfg_virt[0].virt;
+ }
+ cfg = pci_mmcfg_virt[cfg_num].cfg;
+ if (cfg->pci_segment_group_number != seg)
+ continue;
+ if ((cfg->start_bus_number <= bus) &&
+ (cfg->end_bus_number >= bus))
+ return pci_mmcfg_virt[cfg_num].virt;
+ }
+}
+
+static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
+{
+
+ return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
}
static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value)
{
- char *addr = pci_dev_base(bus, devfn);
+ char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
@@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value)
{
- char *addr = pci_dev_base(bus,devfn);
+ char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
@@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = {
static int __init pci_mmcfg_init(void)
{
+ int i;
+
if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return 0;
- if (!pci_mmcfg_base_addr)
+
+ acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
+ if ((pci_mmcfg_config_num == 0) ||
+ (pci_mmcfg_config == NULL) ||
+ (pci_mmcfg_config[0].base_address == 0))
return 0;
/* Kludge for now. Don't use mmconfig on AMD systems because
@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void)
return 0;
/* RED-PEN i386 doesn't do _nocache right now */
- pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE);
- if (!pci_mmcfg_virt) {
- printk("PCI: Cannot map mmconfig aperture\n");
+ pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
+ if (pci_mmcfg_virt == NULL) {
+ printk("PCI: Can not allocate memory for mmconfig structures\n");
return 0;
- }
+ }
+ for (i = 0; i < pci_mmcfg_config_num; ++i) {
+ pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
+ pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
+ if (!pci_mmcfg_virt[i].virt) {
+ printk("PCI: Cannot map mmconfig aperture for segment %d\n",
+ pci_mmcfg_config[i].pci_segment_group_number);
+ return 0;
+ }
+ printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
+ }
- printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr);
raw_pci_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
diff --git a/arch/xtensa/Kconfig b/arch/xtensa/Kconfig
new file mode 100644
index 000000000000..2b6257bec4c3
--- /dev/null
+++ b/arch/xtensa/Kconfig
@@ -0,0 +1,262 @@
+# For a description of the syntax of this configuration file,
+# see Documentation/kbuild/config-language.txt.
+
+mainmenu "Linux/Xtensa Kernel Configuration"
+
+config FRAME_POINTER
+ bool
+ default n
+
+config XTENSA
+ bool
+ default y
+ help
+ Xtensa processors are 32-bit RISC machines designed by Tensilica
+ primarily for embedded systems. These processors are both
+ configurable and extensible. The Linux port to the Xtensa
+ architecture supports all processor configurations and extensions,
+ with reasonable minimum requirements. The Xtensa Linux project has
+ a home page at <http://xtensa.sourceforge.net/>.
+
+config UID16
+ bool
+ default n
+
+config RWSEM_XCHGADD_ALGORITHM
+ bool
+ default y
+
+config HAVE_DEC_LOCK
+ bool
+ default y
+
+config GENERIC_HARDIRQS
+ bool
+ default y
+
+source "init/Kconfig"
+
+menu "Processor type and features"
+
+choice
+ prompt "Xtensa Processor Configuration"
+ default XTENSA_CPU_LINUX_BE
+
+config XTENSA_CPU_LINUX_BE
+ bool "linux_be"
+ ---help---
+ The linux_be processor configuration is the baseline Xtensa
+ configurations included in this kernel and also used by
+ binutils, gcc, and gdb. It contains no TIE, no coprocessors,
+ and the following configuration options:
+
+ Code Density Option 2 Misc Special Registers
+ NSA/NSAU Instructions 128-bit Data Bus Width
+ Processor ID 8K, 2-way I and D Caches
+ Zero-Overhead Loops 2 Inst Address Break Registers
+ Big Endian 2 Data Address Break Registers
+ 64 General-Purpose Registers JTAG Interface and Trace Port
+ 17 Interrupts MMU w/ TLBs and Autorefill
+ 3 Interrupt Levels 8 Autorefill Ways (I/D TLBs)
+ 3 Timers Unaligned Exceptions
+endchoice
+
+config MMU
+ bool
+ default y
+
+config XTENSA_UNALIGNED_USER
+ bool "Unaligned memory access in use space"
+ ---help---
+ The Xtensa architecture currently does not handle unaligned
+ memory accesses in hardware but through an exception handler.
+ Per default, unaligned memory accesses are disabled in user space.
+
+ Say Y here to enable unaligned memory access in user space.
+
+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.
+ Unfortunately the kernel code has some race conditions if both
+ CONFIG_SMP and CONFIG_PREEMPT are enabled, so this option is
+ currently disabled if you are building an SMP kernel.
+
+ Say Y here if you are building a kernel for a desktop, embedded
+ or real-time system. Say N if you are unsure.
+
+config MATH_EMULATION
+ bool "Math emulation"
+ help
+ Can we use information of configuration file?
+
+config HIGHMEM
+ bool "High memory support"
+
+endmenu
+
+menu "Platform options"
+
+choice
+ prompt "Xtensa System Type"
+ default XTENSA_PLATFORM_ISS
+
+config XTENSA_PLATFORM_ISS
+ bool "ISS"
+ help
+ ISS is an acronym for Tensilica's Instruction Set Simulator.
+
+config XTENSA_PLATFORM_XT2000
+ bool "XT2000"
+ help
+ XT2000 is the name of Tensilica's feature-rich emulation platform.
+ This hardware is capable of running a full Linux distribution.
+
+endchoice
+
+
+config XTENSA_CALIBRATE_CCOUNT
+ bool "Auto calibration of the CPU clock rate"
+ ---help---
+ On some platforms (XT2000, for example), the CPU clock rate can
+ vary. The frequency can be determined, however, by measuring
+ against a well known, fixed frequency, such as an UART oscillator.
+
+config XTENSA_CPU_CLOCK
+ int "CPU clock rate [MHz]"
+ depends on !XTENSA_CALIBRATE_CCOUNT
+ default "16"
+
+config GENERIC_CALIBRATE_DELAY
+ bool "Auto calibration of the BogoMIPS value"
+ ---help---
+ The BogoMIPS value can easily be derived from the CPU frequency.
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+
+config CMDLINE
+ string "Initial kernel command string"
+ depends on CMDLINE_BOOL
+ default "console=ttyS0,38400 root=/dev/ram"
+ help
+ On some architectures (EBSA110 and CATS), there is currently no way
+ for the boot loader to pass arguments to the kernel. For these
+ architectures, you should supply some command-line options at build
+ time by entering them here. As a minimum, you should specify the
+ memory size and the root device (e.g., mem=64M root=/dev/nfs).
+
+config SERIAL_CONSOLE
+ bool
+ depends on XTENSA_PLATFORM_ISS
+ default y
+
+config XTENSA_ISS_NETWORK
+ bool
+ depends on XTENSA_PLATFORM_ISS
+ default y
+
+source "mm/Kconfig"
+
+endmenu
+
+menu "Bus options"
+
+config PCI
+ bool "PCI support" if !XTENSA_PLATFORM_ISS
+ depends on !XTENSA_PLATFORM_ISS
+ default y
+ 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
+ <http://www.linuxdoc.org/docs.html#howto>, contains valuable
+ information about which PCI hardware does work under Linux and which
+ doesn't
+
+source "drivers/pci/Kconfig"
+
+config HOTPLUG
+
+ bool "Support for hot-pluggable devices"
+ ---help---
+ Say Y here if you want to plug devices into your computer while
+ the system is running, and be able to use them quickly. In many
+ cases, the devices can likewise be unplugged at any time too.
+
+ One well known example of this is PCMCIA- or PC-cards, credit-card
+ size devices such as network cards, modems or hard drives which are
+ plugged into slots found on all modern laptop computers. Another
+ example, used on modern desktops as well as laptops, is USB.
+
+ Enable HOTPLUG and KMOD, and build a modular kernel. Get agent
+ software (at <http://linux-hotplug.sourceforge.net/>) and install it.
+ Then your kernel will automatically call out to a user mode "policy
+ agent" (/sbin/hotplug) to load modules and set up software needed
+ to use devices as you hotplug them.
+
+source "drivers/pcmcia/Kconfig"
+
+source "drivers/pci/hotplug/Kconfig"
+
+endmenu
+
+menu "Exectuable file formats"
+
+# only elf supported
+config KCORE_ELF
+ bool
+ depends on PROC_FS
+ default y
+ help
+ If you enabled support for /proc file system then the file
+ /proc/kcore will contain the kernel core image in ELF format. This
+ can be used in gdb:
+
+ $ cd /usr/src/linux ; gdb vmlinux /proc/kcore
+
+ This is especially useful if you have compiled the kernel with the
+ "-g" option to preserve debugging information. It is mainly used
+ for examining kernel data structures on the live kernel.
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+menu "Xtensa initrd options"
+ depends on BLK_DEV_INITRD
+
+ config EMBEDDED_RAMDISK
+ bool "Embed root filesystem ramdisk into the kernel"
+
+config EMBEDDED_RAMDISK_IMAGE
+ string "Filename of gziped ramdisk image"
+ depends on EMBEDDED_RAMDISK
+ default "ramdisk.gz"
+ help
+ This is the filename of the ramdisk image to be built into the
+ kernel. Relative pathnames are relative to arch/xtensa/boot/ramdisk/.
+ The ramdisk image is not part of the kernel distribution; you must
+ provide one yourself.
+endmenu
+
+source "arch/xtensa/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
+
+
diff --git a/arch/xtensa/Kconfig.debug b/arch/xtensa/Kconfig.debug
new file mode 100644
index 000000000000..11c585295dd7
--- /dev/null
+++ b/arch/xtensa/Kconfig.debug
@@ -0,0 +1,7 @@
+menu "Kernel hacking"
+
+source "lib/Kconfig.debug"
+
+endmenu
+
+
diff --git a/arch/xtensa/Makefile b/arch/xtensa/Makefile
new file mode 100644
index 000000000000..27847e4ffcbf
--- /dev/null
+++ b/arch/xtensa/Makefile
@@ -0,0 +1,104 @@
+#
+# 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 - 2005 Tensilica Inc.
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" and "archdep" for cleaning up and making dependencies for
+# this architecture
+
+# Core configuration.
+# (Use CPU=<xtensa_config> to use another default compiler.)
+
+cpu-$(CONFIG_XTENSA_CPU_LINUX_BE) := linux_be
+cpu-$(CONFIG_XTENSA_CPU_LINUX_CUSTOM) := linux_custom
+
+CPU = $(cpu-y)
+export CPU
+
+# Platform configuration
+
+platform-$(CONFIG_XTENSA_PLATFORM_XT2000) := xt2000
+platform-$(CONFIG_XTENSA_PLATFORM_ISS) := iss
+
+PLATFORM = $(platform-y)
+export PLATFORM
+
+CPPFLAGS += $(if $(KBUILD_SRC),-I$(srctree)/include/asm-xtensa/)
+CPPFLAGS += -Iinclude/asm
+CFLAGS += -pipe -mlongcalls
+
+KBUILD_DEFCONFIG := iss_defconfig
+
+# ramdisk/initrd support
+# You need a compressed ramdisk image, named ramdisk.gz in
+# arch/xtensa/boot/ramdisk
+
+core-$(CONFIG_EMBEDDED_RAMDISK) += arch/xtensa/boot/ramdisk/
+
+# Test for cross compiling
+
+ifneq ($(CPU),)
+ COMPILE_ARCH = $(shell uname -m)
+
+ ifneq ($(COMPILE_ARCH), xtensa)
+ ifndef CROSS_COMPILE
+ CROSS_COMPILE = xtensa_$(CPU)-
+ endif
+ endif
+endif
+
+#
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+head-y := arch/xtensa/kernel/head.o
+core-y += arch/xtensa/kernel/ arch/xtensa/mm/
+ifneq ($(PLATFORM),)
+core-y += arch/xtensa/platform-$(PLATFORM)/
+endif
+libs-y += arch/xtensa/lib/ $(LIBGCC)
+
+boot := arch/xtensa/boot
+
+archinc := include/asm-xtensa
+
+arch/xtensa/kernel/asm-offsets.s: \
+ arch/xtensa/kernel/asm-offsets.c $(archinc)/.platform
+
+include/asm-xtensa/offsets.h: arch/xtensa/kernel/asm-offsets.s
+ $(call filechk,gen-asm-offsets)
+
+prepare: $(archinc)/.platform $(archinc)/offsets.h
+
+# Update machine cpu and platform symlinks if something which affects
+# them changed.
+
+$(archinc)/.platform: $(wildcard include/config/arch/*.h) include/config/MARKER
+ @echo ' SYMLINK $(archinc)/xtensa/config -> $(archinc)/xtensa/config-$(CPU)'
+ $(Q)mkdir -p $(archinc)
+ $(Q)mkdir -p $(archinc)/xtensa
+ $(Q)ln -fsn $(srctree)/$(archinc)/xtensa/config-$(CPU) $(archinc)/xtensa/config
+ @echo ' SYMLINK $(archinc)/platform -> $(archinc)/platform-$(PLATFORM)'
+ $(Q)ln -fsn $(srctree)/$(archinc)/platform-$(PLATFORM) $(archinc)/platform
+ @touch $@
+
+
+all: zImage
+
+bzImage : zImage
+
+zImage zImage.initrd: vmlinux
+ $(Q)$(MAKE) $(build)=$(boot) $@
+
+CLEAN_FILES += arch/xtensa/vmlinux.lds $(archinc)/offset.h \
+ $(archinc)/platform $(archinc)/xtensa/config \
+ $(archinc)/.platform
+
+define archhelp
+ @echo '* zImage - Compressed kernel image (arch/xtensa/boot/images/zImage.*)'
+endef
+
diff --git a/arch/xtensa/boot/Makefile b/arch/xtensa/boot/Makefile
new file mode 100644
index 000000000000..820b31d10ae4
--- /dev/null
+++ b/arch/xtensa/boot/Makefile
@@ -0,0 +1,33 @@
+#
+# arch/xtensa/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.
+#
+#
+
+
+CFLAGS += -fno-builtin -Iarch/$(ARCH)/boot/include
+HOSTFLAGS += -Iarch/$(ARCH)/boot/include
+
+BIG_ENDIAN := $(shell echo -e __XTENSA_EB__ | $(CC) -E - | grep -v "\#")
+
+export CFLAGS
+export AFLAGS
+export BIG_ENDIAN
+
+subdir-y := lib
+
+# Subdirs for the boot loader(s)
+
+bootdir-$(CONFIG_XTENSA_PLATFORM_ISS) += boot-elf
+bootdir-$(CONFIG_XTENSA_PLATFORM_XT2000) += boot-redboot boot-elf
+
+
+zImage zImage.initrd Image Image.initrd: $(bootdir-y)
+
+$(bootdir-y): $(addprefix $(obj)/,$(subdir-y)) \
+ $(addprefix $(obj)/,$(host-progs))
+ $(Q)$(MAKE) $(build)=$(obj)/$@ $(MAKECMDGOALS)
+
diff --git a/arch/xtensa/boot/boot-elf/Makefile b/arch/xtensa/boot/boot-elf/Makefile
new file mode 100644
index 000000000000..734db7f76583
--- /dev/null
+++ b/arch/xtensa/boot/boot-elf/Makefile
@@ -0,0 +1,52 @@
+#
+# 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.
+#
+
+GZIP = gzip
+GZIP_FLAGS = -v9fc
+
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS := -O elf32-xtensa-le
+endif
+
+export OBJCOPY_ARGS
+
+boot-y := bootstrap.o
+
+OBJS := $(addprefix $(obj)/,$(boot-y))
+
+Image: vmlinux $(OBJS)
+ $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+ vmlinux vmlinux.tmp
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section image=vmlinux.tmp \
+ --set-section-flags image=contents,alloc,load,load,data \
+ $(OBJS) $@.tmp
+ $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+ -T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \
+ -o arch/$(ARCH)/boot/$@.elf $@.tmp
+ rm -f $@.tmp vmlinux.tmp
+
+Image.initrd: vmlinux $(OBJS)
+ $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+ --add-section .initrd=arch/$(ARCH)/boot/ramdisk \
+ --set-section-flags .initrd=contents,alloc,load,load,data \
+ vmlinux vmlinux.tmp
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section image=vmlinux.tmp \
+ --set-section-flags image=contents,alloc,load,load,data \
+ $(OBJS) $@.tmp
+ $(LD) $(LDFLAGS) $(LDFLAGS_vmlinux) \
+ -T $(srctree)/arch/$(ARCH)/boot/boot-elf/boot.ld \
+ -o arch/$(ARCH)/boot/$@.elf $@.tmp
+ rm -f $@.tmp vmlinux.tmp
+
+
+zImage: Image
+
+zImage.initrd: Image.initrd
+
diff --git a/arch/xtensa/boot/boot-elf/boot.ld b/arch/xtensa/boot/boot-elf/boot.ld
new file mode 100644
index 000000000000..4ab06a0a7a6b
--- /dev/null
+++ b/arch/xtensa/boot/boot-elf/boot.ld
@@ -0,0 +1,71 @@
+OUTPUT_ARCH(xtensa)
+
+SECTIONS
+{
+ .start 0xD0000000 : { *(.start) }
+
+ .text 0xD0000000:
+ {
+ __reloc_start = . ;
+ _text_start = . ;
+ *(.literal .text.literal .text)
+ _text_end = . ;
+ }
+
+ .rodata ALIGN(0x04):
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
+
+ .data ALIGN(0x04):
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt)
+ *(.got)
+ *(.dynamic)
+ }
+
+ __reloc_end = . ;
+
+ .initrd ALIGN(0x10) :
+ {
+ boot_initrd_start = . ;
+ *(.initrd)
+ boot_initrd_end = .;
+ }
+
+ . = ALIGN(0x10);
+ __image_load = . ;
+ .image 0xd0001000:
+ {
+ _image_start = .;
+ *(image)
+ . = (. + 3) & ~ 3;
+ _image_end = . ;
+ }
+
+
+ .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3):
+ {
+ __bss_start = .;
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ __bss_end = .;
+ }
+ _end = .;
+ _param_start = .;
+
+ .ResetVector.text 0xfe000020 :
+ {
+ *(.ResetVector.text)
+ }
+
+
+ PROVIDE (end = .);
+}
diff --git a/arch/xtensa/boot/boot-elf/bootstrap.S b/arch/xtensa/boot/boot-elf/bootstrap.S
new file mode 100644
index 000000000000..7cba94abdab8
--- /dev/null
+++ b/arch/xtensa/boot/boot-elf/bootstrap.S
@@ -0,0 +1,37 @@
+
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/core.h>
+
+#include <linux/config.h>
+#include <asm/bootparam.h>
+
+
+/* ResetVector
+ */
+ .section .ResetVector.text, "ax"
+ .global _ResetVector
+_ResetVector:
+ _j reset
+ .align 4
+RomInitAddr:
+ .word 0xd0001000
+RomBootParam:
+ .word _bootparam
+reset:
+ l32r a0, RomInitAddr
+ l32r a2, RomBootParam
+ movi a3, 0
+ movi a4, 0
+ jx a0
+
+ .align 4
+ .section .bootstrap.data, "aw"
+
+ .globl _bootparam
+_bootparam:
+ .short BP_TAG_FIRST
+ .short 4
+ .long BP_VERSION
+ .short BP_TAG_LAST
+ .short 0
+ .long 0
diff --git a/arch/xtensa/boot/boot-redboot/Makefile b/arch/xtensa/boot/boot-redboot/Makefile
new file mode 100644
index 000000000000..f53262c2e1f3
--- /dev/null
+++ b/arch/xtensa/boot/boot-redboot/Makefile
@@ -0,0 +1,35 @@
+#
+# 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.
+#
+
+GZIP = gzip
+GZIP_FLAGS = -v9fc
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS := -O elf32-xtensa-le
+endif
+
+LD_ARGS = -T $(srctree)/$(obj)/boot.ld
+
+boot-y := bootstrap.o
+
+OBJS := $(addprefix $(obj)/,$(boot-y))
+LIBS := arch/xtensa/boot/lib/lib.a arch/xtensa/lib/lib.a
+
+LIBGCC := $(shell $(CC) $(CFLAGS) -print-libgcc-file-name)
+
+zImage: vmlinux $(OBJS) $(LIBS)
+ $(OBJCOPY) --strip-all -R .comment -R .xt.insn -O binary \
+ vmlinux vmlinux.tmp
+ gzip -vf9 vmlinux.tmp
+ $(OBJCOPY) $(OBJCOPY_ARGS) -R .comment \
+ --add-section image=vmlinux.tmp.gz \
+ --set-section-flags image=contents,alloc,load,load,data \
+ $(OBJS) $@.tmp
+ $(LD) $(LD_ARGS) -o $@.elf $@.tmp $(LIBS) -L/xtensa-elf/lib $(LIBGCC)
+ $(OBJCOPY) -S -O binary $@.elf arch/$(ARCH)/boot/$@.redboot
+ rm -f $@.tmp $@.elf vmlinux.tmp.gz
+
diff --git a/arch/xtensa/boot/boot-redboot/boot.ld b/arch/xtensa/boot/boot-redboot/boot.ld
new file mode 100644
index 000000000000..65b726410e8a
--- /dev/null
+++ b/arch/xtensa/boot/boot-redboot/boot.ld
@@ -0,0 +1,66 @@
+OUTPUT_ARCH(xtensa)
+
+SECTIONS
+{
+ .start 0xD0200000 : { *(.start) }
+
+ .text :
+ {
+ __reloc_start = . ;
+ _text_start = . ;
+ *(.literal .text.literal .text)
+ _text_end = . ;
+ }
+
+ .rodata ALIGN(0x04):
+ {
+ *(.rodata)
+ *(.rodata1)
+ }
+
+ .data ALIGN(0x04):
+ {
+ *(.data)
+ *(.data1)
+ *(.sdata)
+ *(.sdata2)
+ *(.got.plt)
+ *(.got)
+ *(.dynamic)
+ }
+
+ __reloc_end = . ;
+
+ .initrd ALIGN(0x10) :
+ {
+ boot_initrd_start = . ;
+ *(.initrd)
+ boot_initrd_end = .;
+ }
+
+ . = ALIGN(0x10);
+ __image_load = . ;
+ .image 0xd0001000: AT(__image_load)
+ {
+ _image_start = .;
+ *(image)
+ . = (. + 3) & ~ 3;
+ _image_end = . ;
+ }
+
+
+ .bss ((LOADADDR(.image) + SIZEOF(.image) + 3) & ~ 3):
+ {
+ __bss_start = .;
+ *(.sbss)
+ *(.scommon)
+ *(.dynbss)
+ *(.bss)
+ __bss_end = .;
+ }
+ _end = .;
+ _param_start = .;
+
+
+ PROVIDE (end = .);
+}
diff --git a/arch/xtensa/boot/boot-redboot/bootstrap.S b/arch/xtensa/boot/boot-redboot/bootstrap.S
new file mode 100644
index 000000000000..ee636b0da81c
--- /dev/null
+++ b/arch/xtensa/boot/boot-redboot/bootstrap.S
@@ -0,0 +1,246 @@
+
+#define _ASMLANGUAGE
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/core.h>
+#include <xtensa/cacheasm.h>
+
+ /*
+ * RB-Data: RedBoot data/bss
+ * P: Boot-Parameters
+ * L: Kernel-Loader
+ *
+ * The Linux-Kernel image including the loader must be loaded
+ * to a position so that the kernel and the boot parameters
+ * can fit in the space before the load address.
+ * ______________________________________________________
+ * |_RB-Data_|_P_|__________|_L_|___Linux-Kernel___|______|
+ * ^
+ * ^ Load address
+ * ______________________________________________________
+ * |___Linux-Kernel___|_P_|_L_|___________________________|
+ *
+ * The loader copies the parameter to the position that will
+ * be the end of the kernel and itself to the end of the
+ * parameter list.
+ */
+
+/* Make sure we have enough space for the 'uncompressor' */
+
+#define STACK_SIZE 32768
+#define HEAP_SIZE (131072*4)
+
+ # a2: Parameter list
+ # a3: Size of parameter list
+
+ .section .start, "ax"
+
+ .globl __start
+ /* this must be the first byte of the loader! */
+__start:
+ entry sp, 32 # we do not intend to return
+ _call0 _start
+__start_a0:
+ .align 4
+
+ .section .text, "ax"
+ .begin literal_prefix .text
+
+ /* put literals in here! */
+
+ .globl _start
+_start:
+
+ /* 'reset' window registers */
+
+ movi a4, 1
+ wsr a4, PS
+ rsync
+
+ rsr a5, WINDOWBASE
+ ssl a5
+ sll a4, a4
+ wsr a4, WINDOWSTART
+ rsync
+
+ movi a4, 0x00040000
+ wsr a4, PS
+ rsync
+
+ /* copy the loader to its address
+ * Note: The loader itself is a very small piece, so we assume we
+ * don't partially overlap. We also assume (even more important)
+ * that the kernel image is out of the way. Usually, when the
+ * load address of this image is not at an arbitrary address,
+ * but aligned to some 10K's we shouldn't overlap.
+ */
+
+ /* Note: The assembler cannot relax "addi a0, a0, ..." to an
+ l32r, so we load to a4 first. */
+
+ addi a4, a0, __start - __start_a0
+ mov a0, a4
+ movi a4, __start
+ movi a5, __reloc_end
+
+ # a0: address where this code has been loaded
+ # a4: compiled address of __start
+ # a5: compiled end address
+
+ mov.n a7, a0
+ mov.n a8, a4
+
+1:
+ l32i a10, a7, 0
+ l32i a11, a7, 4
+ s32i a10, a8, 0
+ s32i a11, a8, 4
+ l32i a10, a7, 8
+ l32i a11, a7, 12
+ s32i a10, a8, 8
+ s32i a11, a8, 12
+ addi a8, a8, 16
+ addi a7, a7, 16
+ blt a8, a5, 1b
+
+
+ /* We have to flush and invalidate the caches here before we jump. */
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+ dcache_writeback_all a5, a6
+#endif
+ icache_invalidate_all a5, a6
+
+ movi a11, _reloc
+ jx a11
+
+ .globl _reloc
+_reloc:
+
+ /* RedBoot is now at the end of the memory, so we don't have
+ * to copy the parameter list. Keep the code around; in case
+ * we need it again. */
+#if 0
+ # a0: load address
+ # a2: start address of parameter list
+ # a3: length of parameter list
+ # a4: __start
+
+ /* copy the parameter list out of the way */
+
+ movi a6, _param_start
+ add a3, a2, a3
+2:
+ l32i a8, a2, 0
+ s32i a8, a6, 0
+ addi a2, a2, 4
+ addi a6, a6, 4
+ blt a2, a3, 2b
+#endif
+
+ /* clear BSS section */
+ movi a6, __bss_start
+ movi a7, __bss_end
+ movi.n a5, 0
+3:
+ s32i a5, a6, 0
+ addi a6, a6, 4
+ blt a6, a7, 3b
+
+ movi a5, -16
+ movi a1, _stack + STACK_SIZE
+ and a1, a1, a5
+
+ /* Uncompress the kernel */
+
+ # a0: load address
+ # a2: boot parameter
+ # a4: __start
+
+ movi a3, __image_load
+ sub a4, a3, a4
+ add a8, a0, a4
+
+ # a1 Stack
+ # a8(a4) Load address of the image
+
+ movi a6, _image_start
+ movi a10, _image_end
+ movi a7, 0x1000000
+ sub a11, a10, a6
+ movi a9, complen
+ s32i a11, a9, 0
+
+ movi a0, 0
+
+ # a6 destination
+ # a7 maximum size of destination
+ # a8 source
+ # a9 ptr to length
+
+ .extern gunzip
+ movi a4, gunzip
+ beqz a4, 1f
+
+ callx4 a4
+
+ j 2f
+
+
+ # a6 destination start
+ # a7 maximum size of destination
+ # a8 source start
+ # a9 ptr to length
+ # a10 destination end
+
+1:
+ l32i a9, a8, 0
+ l32i a11, a8, 4
+ s32i a9, a6, 0
+ s32i a11, a6, 4
+ l32i a9, a8, 8
+ l32i a11, a8, 12
+ s32i a9, a6, 8
+ s32i a11, a6, 12
+ addi a6, a6, 16
+ addi a8, a8, 16
+ blt a6, a10, 1b
+
+
+ /* jump to the kernel */
+2:
+#if XCHAL_DCACHE_IS_WRITEBACK
+ dcache_writeback_all a5, a6
+#endif
+ icache_invalidate_all a5, a6
+
+ movi a5, __start
+ movi a3, boot_initrd_start
+ movi a4, boot_initrd_end
+ sub a3, a3, a5
+ sub a4, a4, a5
+ add a3, a0, a3
+ add a4, a0, a4
+
+ # a2 Boot parameter list
+ # a3 initrd_start (virtual load address)
+ # a4 initrd_end (virtual load address)
+
+ movi a0, _image_start
+ jx a0
+
+ .align 16
+ .data
+ .globl avail_ram
+avail_ram:
+ .long _heap
+ .globl end_avail
+end_avail:
+ .long _heap + HEAP_SIZE
+
+ .comm _stack, STACK_SIZE
+ .comm _heap, HEAP_SIZE
+
+ .globl end_avail
+ .comm complen, 4
+
+ .end literal_prefix
diff --git a/arch/xtensa/boot/lib/Makefile b/arch/xtensa/boot/lib/Makefile
new file mode 100644
index 000000000000..9e73bb8aeb7a
--- /dev/null
+++ b/arch/xtensa/boot/lib/Makefile
@@ -0,0 +1,17 @@
+#
+# Makefile for some libs needed by zImage.
+#
+
+zlib := infblock.c infcodes.c inffast.c inflate.c inftrees.c infutil.c
+
+lib-y += $(zlib:.c=.o) zmem.o
+
+EXTRA_CFLAGS += -Ilib/zlib_inflate
+
+quiet_cmd_copy_zlib = COPY $@
+ cmd_copy_zlib = cat $< > $@
+
+$(addprefix $(obj)/,$(zlib)): $(obj)/%: $(srctree)/lib/zlib_inflate/%
+ $(call cmd,copy_zlib)
+
+clean-files := $(zlib)
diff --git a/arch/xtensa/boot/lib/zmem.c b/arch/xtensa/boot/lib/zmem.c
new file mode 100644
index 000000000000..d9862aa8ca25
--- /dev/null
+++ b/arch/xtensa/boot/lib/zmem.c
@@ -0,0 +1,79 @@
+#include <linux/zlib.h>
+
+/* bits taken from ppc */
+
+extern void *avail_ram, *end_avail;
+
+void exit (void)
+{
+ for (;;);
+}
+
+void *zalloc(unsigned size)
+{
+ void *p = avail_ram;
+
+ size = (size + 7) & -8;
+ avail_ram += size;
+ if (avail_ram > end_avail) {
+ //puts("oops... out of memory\n");
+ //pause();
+ exit ();
+ }
+ return p;
+}
+
+#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) {
+ //puts("bad gzipped data\n");
+ 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) {
+ //puts("gunzip: ran out of data in header\n");
+ exit();
+ }
+
+ s.workspace = zalloc(zlib_inflate_workspacesize());
+ r = zlib_inflateInit2(&s, -MAX_WBITS);
+ if (r != Z_OK) {
+ //puts("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 = 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;
+ zlib_inflateEnd(&s);
+}
+
diff --git a/arch/xtensa/boot/ramdisk/Makefile b/arch/xtensa/boot/ramdisk/Makefile
new file mode 100644
index 000000000000..b12f76352438
--- /dev/null
+++ b/arch/xtensa/boot/ramdisk/Makefile
@@ -0,0 +1,23 @@
+#
+# Makefile for a ramdisk image
+#
+
+BIG_ENDIAN := $(shell echo -e "\#ifdef __XTENSA_EL__\nint little;\n\#else\nint big;\n\#endif" | $(CC) -E -|grep -c big)
+
+ifeq ($(BIG_ENDIAN),1)
+OBJCOPY_ARGS := -O elf32-xtensa-be
+else
+OBJCOPY_ARGS := -O elf32-xtensa-le
+endif
+
+obj-y = ramdisk.o
+
+RAMDISK_IMAGE = arch/$(ARCH)/boot/ramdisk/$(CONFIG_EMBEDDED_RAMDISK_IMAGE)
+
+arch/$(ARCH)/boot/ramdisk/ramdisk.o:
+ $(Q)echo -e "dummy:" | $(AS) -o $@;
+ $(Q)$(OBJCOPY) $(OBJCOPY_ARGS) \
+ --add-section .initrd=$(RAMDISK_IMAGE) \
+ --set-section-flags .initrd=contents,alloc,load,load,data \
+ arch/$(ARCH)/boot/ramdisk/ramdisk.o $@
+
diff --git a/arch/xtensa/configs/common_defconfig b/arch/xtensa/configs/common_defconfig
new file mode 100644
index 000000000000..1d230ee081b4
--- /dev/null
+++ b/arch/xtensa/configs/common_defconfig
@@ -0,0 +1,662 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc2
+# Tue Mar 1 16:36:53 2005
+#
+# CONFIG_FRAME_POINTER is not set
+CONFIG_XTENSA=y
+# CONFIG_UID16 is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_GENERIC_HARDIRQS=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_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+# CONFIG_MODULE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+CONFIG_MODVERSIONS=y
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Processor type and features
+#
+CONFIG_XTENSA_ARCH_LINUX_BE=y
+# CONFIG_XTENSA_ARCH_LINUX_LE is not set
+# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
+# CONFIG_XTENSA_ARCH_S5 is not set
+# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_MMU=y
+# CONFIG_XTENSA_UNALIGNED_USER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_HIGHMEM is not set
+
+#
+# Platform options
+#
+# CONFIG_XTENSA_PLATFORM_ISS is not set
+CONFIG_XTENSA_PLATFORM_XT2000=y
+CONFIG_XTENSA_CALIBRATE_CCOUNT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,38400 ip=bootp root=nfs nfsroot=/opt/montavista/pro/devkit/xtensa/linux_be/target"
+
+#
+# Bus options
+#
+CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
+# CONFIG_PCI_NAMES is not set
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+# CONFIG_HOTPLUG_PCI is not set
+
+#
+# Exectuable file formats
+#
+CONFIG_KCORE_ELF=y
+CONFIG_BINFMT_ELF=y
+CONFIG_BINFMT_MISC=y
+
+#
+# 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_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_COW_COMMON 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 is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH 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
+#
+# CONFIG_IEEE1394 is not set
+
+#
+# I2O device support
+#
+# CONFIG_I2O is not set
+
+#
+# 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=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE 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_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 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
+
+#
+# QoS and/or fair queueing
+#
+CONFIG_NET_SCHED=y
+CONFIG_NET_SCH_CLK_JIFFIES=y
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU is not set
+CONFIG_NET_SCH_CBQ=m
+CONFIG_NET_SCH_HTB=m
+# CONFIG_NET_SCH_HFSC is not set
+CONFIG_NET_SCH_PRIO=m
+CONFIG_NET_SCH_RED=m
+CONFIG_NET_SCH_SFQ=m
+CONFIG_NET_SCH_TEQL=m
+CONFIG_NET_SCH_TBF=m
+CONFIG_NET_SCH_GRED=m
+CONFIG_NET_SCH_DSMARK=m
+# CONFIG_NET_SCH_NETEM is not set
+CONFIG_NET_SCH_INGRESS=m
+CONFIG_NET_QOS=y
+CONFIG_NET_ESTIMATOR=y
+CONFIG_NET_CLS=y
+CONFIG_NET_CLS_TCINDEX=m
+CONFIG_NET_CLS_ROUTE4=m
+CONFIG_NET_CLS_ROUTE=y
+CONFIG_NET_CLS_FW=m
+CONFIG_NET_CLS_U32=m
+# CONFIG_CLS_U32_PERF is not set
+# CONFIG_NET_CLS_IND is not set
+CONFIG_NET_CLS_RSVP=m
+CONFIG_NET_CLS_RSVP6=m
+# CONFIG_NET_CLS_ACT is not set
+CONFIG_NET_CLS_POLICE=y
+
+#
+# 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 is not set
+CONFIG_XT2000_SONIC=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 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=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+CONFIG_STRIP=m
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+CONFIG_HERMES=m
+# CONFIG_PLX_HERMES is not set
+# CONFIG_TMD_HERMES is not set
+# CONFIG_PCI_HERMES is not set
+# CONFIG_ATMEL is not set
+
+#
+# Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support
+#
+# CONFIG_PRISM54 is not set
+CONFIG_NET_WIRELESS=y
+
+#
+# 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_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 is not set
+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
+# CONFIG_SERIO_PCIPS2 is not set
+# CONFIG_SERIO_RAW 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=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED 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_RTC is not set
+# CONFIG_GEN_RTC is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# 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
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB is not set
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS 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_DNOTIFY=y
+# 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 is not set
+CONFIG_SYSFS=y
+CONFIG_DEVFS_FS=y
+# CONFIG_DEVFS_MOUNT is not set
+# CONFIG_DEVFS_DEBUG is not set
+# CONFIG_DEVPTS_FS_XATTR is not set
+# 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_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_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SLAB is not set
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/xtensa/configs/iss_defconfig b/arch/xtensa/configs/iss_defconfig
new file mode 100644
index 000000000000..802621dd4867
--- /dev/null
+++ b/arch/xtensa/configs/iss_defconfig
@@ -0,0 +1,531 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.11-rc2
+# Fri Feb 25 19:21:24 2005
+#
+CONFIG_FRAME_POINTER=y
+CONFIG_XTENSA=y
+# CONFIG_UID16 is not set
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HAVE_DEC_LOCK=y
+CONFIG_GENERIC_HARDIRQS=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_HOTPLUG is not set
+# CONFIG_KOBJECT_UEVENT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SHMEM=y
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+# CONFIG_TINY_SHMEM is not set
+
+#
+# Loadable module support
+#
+# CONFIG_MODULES is not set
+
+#
+# Processor type and features
+#
+CONFIG_XTENSA_ARCH_LINUX_BE=y
+# CONFIG_XTENSA_ARCH_LINUX_LE is not set
+# CONFIG_XTENSA_ARCH_LINUX_TEST is not set
+# CONFIG_XTENSA_ARCH_S5 is not set
+# CONFIG_XTENSA_CUSTOM is not set
+CONFIG_MMU=y
+# CONFIG_XTENSA_UNALIGNED_USER is not set
+# CONFIG_PREEMPT is not set
+# CONFIG_MATH_EMULATION is not set
+# CONFIG_HIGHMEM is not set
+
+#
+# Platform options
+#
+CONFIG_XTENSA_PLATFORM_ISS=y
+# CONFIG_XTENSA_PLATFORM_XT2000 is not set
+# CONFIG_XTENSA_PLATFORM_ARUBA is not set
+# CONFIG_XTENSA_CALIBRATE_CCOUNT is not set
+CONFIG_XTENSA_CPU_CLOCK=10
+# CONFIG_GENERIC_CALIBRATE_DELAY is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,38400 eth0=tuntap,,tap0 ip=192.168.168.5:192.168.168.1 root=nfs nfsroot=192.168.168.1:/opt/montavista/pro/devkit/xtensa/linux_be/target"
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_XTENSA_ISS_NETWORK=y
+
+#
+# Bus options
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# PC-card bridges
+#
+
+#
+# PCI Hotplug Support
+#
+
+#
+# Exectuable file formats
+#
+CONFIG_KCORE_ELF=y
+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
+# 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_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_RAM is not set
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_ATA_OVER_ETH 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=y
+CONFIG_IP_PNP_RARP=y
+# 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_IP_TCPDIAG is not set
+# CONFIG_IP_TCPDIAG_IPV6 is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETFILTER is not set
+
+#
+# SCTP Configuration (EXPERIMENTAL)
+#
+# CONFIG_IP_SCTP is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+# CONFIG_SCTP_HMAC_MD5 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
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_SCH_CLK_JIFFIES is not set
+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
+# CONFIG_NET_SCH_CLK_CPU 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 is not set
+# CONFIG_SERIO_I8042 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_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+CONFIG_SOFT_WATCHDOG=y
+# 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_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
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# USB support
+#
+# CONFIG_USB_ARCH_HAS_HCD is not set
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information
+#
+
+#
+# USB Gadget Support
+#
+# CONFIG_USB_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+# CONFIG_MMC is not set
+
+#
+# InfiniBand support
+#
+# CONFIG_INFINIBAND is not set
+
+#
+# File systems
+#
+# CONFIG_EXT2_FS 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_DNOTIFY 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 is not set
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_XATTR 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=y
+# 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_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_AFS_FS is not set
+
+#
+# Partition Types
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+# CONFIG_NLS is not set
+
+#
+# Kernel hacking
+#
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_KGDB is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC32 is not set
+# CONFIG_LIBCRC32C is not set
diff --git a/arch/xtensa/kernel/Makefile b/arch/xtensa/kernel/Makefile
new file mode 100644
index 000000000000..d573017a5dde
--- /dev/null
+++ b/arch/xtensa/kernel/Makefile
@@ -0,0 +1,18 @@
+#
+# Makefile for the Linux/Xtensa kernel.
+#
+
+extra-y := head.o vmlinux.lds
+
+
+obj-y := align.o entry.o irq.o coprocessor.o process.o ptrace.o semaphore.o \
+ setup.o signal.o syscalls.o time.o traps.o vectors.o platform.o \
+ pci-dma.o
+
+## windowspill.o
+
+obj-$(CONFIG_KGDB) += xtensa-stub.o
+obj-$(CONFIG_PCI) += pci.o
+obj-$(CONFIG_MODULES) += xtensa_ksyms.o module.o
+
+
diff --git a/arch/xtensa/kernel/align.S b/arch/xtensa/kernel/align.S
new file mode 100644
index 000000000000..74b1e90ef08c
--- /dev/null
+++ b/arch/xtensa/kernel/align.S
@@ -0,0 +1,459 @@
+/*
+ * arch/xtensa/kernel/align.S
+ *
+ * Handle unalignment exceptions in kernel space.
+ *
+ * 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 - 2005 Tensilica, Inc.
+ *
+ * Rewritten by Chris Zankel <chris@zankel.net>
+ *
+ * Based on work from Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * and Marc Gauthier <marc@tensilica.com, marc@alimni.uwaterloo.ca>
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+
+/* First-level exception handler for unaligned exceptions.
+ *
+ * Note: This handler works only for kernel exceptions. Unaligned user
+ * access should get a seg fault.
+ */
+
+/* Big and little endian 16-bit values are located in
+ * different halves of a register. HWORD_START helps to
+ * abstract the notion of extracting a 16-bit value from a
+ * register.
+ * We also have to define new shifting instructions because
+ * lsb and msb are on 'opposite' ends in a register for
+ * different endian machines.
+ *
+ * Assume a memory region in ascending address:
+ * 0 1 2 3|4 5 6 7
+ *
+ * When loading one word into a register, the content of that register is:
+ * LE 3 2 1 0, 7 6 5 4
+ * BE 0 1 2 3, 4 5 6 7
+ *
+ * Masking the bits of the higher/lower address means:
+ * LE X X 0 0, 0 0 X X
+ * BE 0 0 X X, X X 0 0
+ *
+ * Shifting to higher/lower addresses, means:
+ * LE shift left / shift right
+ * BE shift right / shift left
+ *
+ * Extracting 16 bits from a 32 bit reg. value to higher/lower address means:
+ * LE mask 0 0 X X / shift left
+ * BE shift left / mask 0 0 X X
+ */
+
+#define UNALIGNED_USER_EXCEPTION
+
+#if XCHAL_HAVE_BE
+
+#define HWORD_START 16
+#define INSN_OP0 28
+#define INSN_T 24
+#define INSN_OP1 16
+
+.macro __src_b r, w0, w1; src \r, \w0, \w1; .endm
+.macro __ssa8 r; ssa8b \r; .endm
+.macro __ssa8r r; ssa8l \r; .endm
+.macro __sh r, s; srl \r, \s; .endm
+.macro __sl r, s; sll \r, \s; .endm
+.macro __exth r, s; extui \r, \s, 0, 16; .endm
+.macro __extl r, s; slli \r, \s, 16; .endm
+
+#else
+
+#define HWORD_START 0
+#define INSN_OP0 0
+#define INSN_T 4
+#define INSN_OP1 12
+
+.macro __src_b r, w0, w1; src \r, \w1, \w0; .endm
+.macro __ssa8 r; ssa8l \r; .endm
+.macro __ssa8r r; ssa8b \r; .endm
+.macro __sh r, s; sll \r, \s; .endm
+.macro __sl r, s; srl \r, \s; .endm
+.macro __exth r, s; slli \r, \s, 16; .endm
+.macro __extl r, s; extui \r, \s, 0, 16; .endm
+
+#endif
+
+/*
+ * xxxx xxxx = imm8 field
+ * yyyy = imm4 field
+ * ssss = s field
+ * tttt = t field
+ *
+ * 16 0
+ * -------------------
+ * L32I.N yyyy ssss tttt 1000
+ * S32I.N yyyy ssss tttt 1001
+ *
+ * 23 0
+ * -----------------------------
+ * res 0000 0010
+ * L16UI xxxx xxxx 0001 ssss tttt 0010
+ * L32I xxxx xxxx 0010 ssss tttt 0010
+ * XXX 0011 ssss tttt 0010
+ * XXX 0100 ssss tttt 0010
+ * S16I xxxx xxxx 0101 ssss tttt 0010
+ * S32I xxxx xxxx 0110 ssss tttt 0010
+ * XXX 0111 ssss tttt 0010
+ * XXX 1000 ssss tttt 0010
+ * L16SI xxxx xxxx 1001 ssss tttt 0010
+ * XXX 1010 0010
+ * **L32AI xxxx xxxx 1011 ssss tttt 0010 unsupported
+ * XXX 1100 0010
+ * XXX 1101 0010
+ * XXX 1110 0010
+ * **S32RI xxxx xxxx 1111 ssss tttt 0010 unsupported
+ * -----------------------------
+ * ^ ^ ^
+ * sub-opcode (NIBBLE_R) -+ | |
+ * t field (NIBBLE_T) -----------+ |
+ * major opcode (NIBBLE_OP0) --------------+
+ */
+
+#define OP0_L32I_N 0x8 /* load immediate narrow */
+#define OP0_S32I_N 0x9 /* store immediate narrow */
+#define OP1_SI_MASK 0x4 /* OP1 bit set for stores */
+#define OP1_SI_BIT 2 /* OP1 bit number for stores */
+
+#define OP1_L32I 0x2
+#define OP1_L16UI 0x1
+#define OP1_L16SI 0x9
+#define OP1_L32AI 0xb
+
+#define OP1_S32I 0x6
+#define OP1_S16I 0x5
+#define OP1_S32RI 0xf
+
+/*
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+
+ENTRY(fast_unaligned)
+
+ /* Note: We don't expect the address to be aligned on a word
+ * boundary. After all, the processor generated that exception
+ * and it would be a hardware fault.
+ */
+
+ /* Save some working register */
+
+ s32i a4, a2, PT_AREG4
+ s32i a5, a2, PT_AREG5
+ s32i a6, a2, PT_AREG6
+ s32i a7, a2, PT_AREG7
+ s32i a8, a2, PT_AREG8
+
+ rsr a0, DEPC
+ xsr a3, EXCSAVE_1
+ s32i a0, a2, PT_AREG2
+ s32i a3, a2, PT_AREG3
+
+ /* Keep value of SAR in a0 */
+
+ rsr a0, SAR
+ rsr a8, EXCVADDR # load unaligned memory address
+
+ /* Now, identify one of the following load/store instructions.
+ *
+ * The only possible danger of a double exception on the
+ * following l32i instructions is kernel code in vmalloc
+ * memory. The processor was just executing at the EPC_1
+ * address, and indeed, already fetched the instruction. That
+ * guarantees a TLB mapping, which hasn't been replaced by
+ * this unaligned exception handler that uses only static TLB
+ * mappings. However, high-level interrupt handlers might
+ * modify TLB entries, so for the generic case, we register a
+ * TABLE_FIXUP handler here, too.
+ */
+
+ /* a3...a6 saved on stack, a2 = SP */
+
+ /* Extract the instruction that caused the unaligned access. */
+
+ rsr a7, EPC_1 # load exception address
+ movi a3, ~3
+ and a3, a3, a7 # mask lower bits
+
+ l32i a4, a3, 0 # load 2 words
+ l32i a5, a3, 4
+
+ __ssa8 a7
+ __src_b a4, a4, a5 # a4 has the instruction
+
+ /* Analyze the instruction (load or store?). */
+
+ extui a5, a4, INSN_OP0, 4 # get insn.op0 nibble
+
+#if XCHAL_HAVE_NARROW
+ _beqi a5, OP0_L32I_N, .Lload # L32I.N, jump
+ addi a6, a5, -OP0_S32I_N
+ _beqz a6, .Lstore # S32I.N, do a store
+#endif
+ /* 'store indicator bit' not set, jump */
+ _bbci.l a4, OP1_SI_BIT + INSN_OP1, .Lload
+
+ /* Store: Jump to table entry to get the value in the source register.*/
+
+.Lstore:movi a5, .Lstore_table # table
+ extui a6, a4, INSN_T, 4 # get source register
+ addx8 a5, a6, a5
+ jx a5 # jump into table
+
+ /* Invalid instruction, CRITICAL! */
+.Linvalid_instruction_load:
+ j .Linvalid_instruction
+
+ /* Load: Load memory address. */
+
+.Lload: movi a3, ~3
+ and a3, a3, a8 # align memory address
+
+ __ssa8 a8
+#ifdef UNALIGNED_USER_EXCEPTION
+ addi a3, a3, 8
+ l32e a5, a3, -8
+ l32e a6, a3, -4
+#else
+ l32i a5, a3, 0
+ l32i a6, a3, 4
+#endif
+ __src_b a3, a5, a6 # a3 has the data word
+
+#if XCHAL_HAVE_NARROW
+ addi a7, a7, 2 # increment PC (assume 16-bit insn)
+
+ extui a5, a4, INSN_OP0, 4
+ _beqi a5, OP0_L32I_N, 1f # l32i.n: jump
+
+ addi a7, a7, 1
+#else
+ addi a7, a7, 3
+#endif
+
+ extui a5, a4, INSN_OP1, 4
+ _beqi a5, OP1_L32I, 1f # l32i: jump
+
+ extui a3, a3, 0, 16 # extract lower 16 bits
+ _beqi a5, OP1_L16UI, 1f
+ addi a5, a5, -OP1_L16SI
+ _bnez a5, .Linvalid_instruction_load
+
+ /* sign extend value */
+
+ slli a3, a3, 16
+ srai a3, a3, 16
+
+ /* Set target register. */
+
+1:
+
+#if XCHAL_HAVE_LOOP
+ rsr a3, LEND # check if we reached LEND
+ bne a7, a3, 1f
+ rsr a3, LCOUNT # and LCOUNT != 0
+ beqz a3, 1f
+ addi a3, a3, -1 # decrement LCOUNT and set
+ rsr a7, LBEG # set PC to LBEGIN
+ wsr a3, LCOUNT
+#endif
+
+1: wsr a7, EPC_1 # skip load instruction
+ extui a4, a4, INSN_T, 4 # extract target register
+ movi a5, .Lload_table
+ addx8 a4, a4, a5
+ jx a4 # jump to entry for target register
+
+ .align 8
+.Lload_table:
+ s32i a3, a2, PT_AREG0; _j .Lexit; .align 8
+ mov a1, a3; _j .Lexit; .align 8 # fishy??
+ s32i a3, a2, PT_AREG2; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG3; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG4; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG5; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG6; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG7; _j .Lexit; .align 8
+ s32i a3, a2, PT_AREG8; _j .Lexit; .align 8
+ mov a9, a3 ; _j .Lexit; .align 8
+ mov a10, a3 ; _j .Lexit; .align 8
+ mov a11, a3 ; _j .Lexit; .align 8
+ mov a12, a3 ; _j .Lexit; .align 8
+ mov a13, a3 ; _j .Lexit; .align 8
+ mov a14, a3 ; _j .Lexit; .align 8
+ mov a15, a3 ; _j .Lexit; .align 8
+
+.Lstore_table:
+ l32i a3, a2, PT_AREG0; _j 1f; .align 8
+ mov a3, a1; _j 1f; .align 8 # fishy??
+ l32i a3, a2, PT_AREG2; _j 1f; .align 8
+ l32i a3, a2, PT_AREG3; _j 1f; .align 8
+ l32i a3, a2, PT_AREG4; _j 1f; .align 8
+ l32i a3, a2, PT_AREG5; _j 1f; .align 8
+ l32i a3, a2, PT_AREG6; _j 1f; .align 8
+ l32i a3, a2, PT_AREG7; _j 1f; .align 8
+ l32i a3, a2, PT_AREG8; _j 1f; .align 8
+ mov a3, a9 ; _j 1f; .align 8
+ mov a3, a10 ; _j 1f; .align 8
+ mov a3, a11 ; _j 1f; .align 8
+ mov a3, a12 ; _j 1f; .align 8
+ mov a3, a13 ; _j 1f; .align 8
+ mov a3, a14 ; _j 1f; .align 8
+ mov a3, a15 ; _j 1f; .align 8
+
+1: # a7: instruction pointer, a4: instruction, a3: value
+
+ movi a6, 0 # mask: ffffffff:00000000
+
+#if XCHAL_HAVE_NARROW
+ addi a7, a7, 2 # incr. PC,assume 16-bit instruction
+
+ extui a5, a4, INSN_OP0, 4 # extract OP0
+ addi a5, a5, -OP0_S32I_N
+ _beqz a5, 1f # s32i.n: jump
+
+ addi a7, a7, 1 # increment PC, 32-bit instruction
+#else
+ addi a7, a7, 3 # increment PC, 32-bit instruction
+#endif
+
+ extui a5, a4, INSN_OP1, 4 # extract OP1
+ _beqi a5, OP1_S32I, 1f # jump if 32 bit store
+ _bnei a5, OP1_S16I, .Linvalid_instruction_store
+
+ movi a5, -1
+ __extl a3, a3 # get 16-bit value
+ __exth a6, a5 # get 16-bit mask ffffffff:ffff0000
+
+ /* Get memory address */
+
+1:
+#if XCHAL_HAVE_LOOP
+ rsr a3, LEND # check if we reached LEND
+ bne a7, a3, 1f
+ rsr a3, LCOUNT # and LCOUNT != 0
+ beqz a3, 1f
+ addi a3, a3, -1 # decrement LCOUNT and set
+ rsr a7, LBEG # set PC to LBEGIN
+ wsr a3, LCOUNT
+#endif
+
+1: wsr a7, EPC_1 # skip store instruction
+ movi a4, ~3
+ and a4, a4, a8 # align memory address
+
+ /* Insert value into memory */
+
+ movi a5, -1 # mask: ffffffff:XXXX0000
+#ifdef UNALIGNED_USER_EXCEPTION
+ addi a4, a4, 8
+#endif
+
+ __ssa8r a8
+ __src_b a7, a5, a6 # lo-mask F..F0..0 (BE) 0..0F..F (LE)
+ __src_b a6, a6, a5 # hi-mask 0..0F..F (BE) F..F0..0 (LE)
+#ifdef UNALIGNED_USER_EXCEPTION
+ l32e a5, a4, -8
+#else
+ l32i a5, a4, 0 # load lower address word
+#endif
+ and a5, a5, a7 # mask
+ __sh a7, a3 # shift value
+ or a5, a5, a7 # or with original value
+#ifdef UNALIGNED_USER_EXCEPTION
+ s32e a5, a4, -8
+ l32e a7, a4, -4
+#else
+ s32i a5, a4, 0 # store
+ l32i a7, a4, 4 # same for upper address word
+#endif
+ __sl a5, a3
+ and a6, a7, a6
+ or a6, a6, a5
+#ifdef UNALIGNED_USER_EXCEPTION
+ s32e a6, a4, -4
+#else
+ s32i a6, a4, 4
+#endif
+
+ /* Done. restore stack and return */
+
+.Lexit:
+ movi a4, 0
+ rsr a3, EXCSAVE_1
+ s32i a4, a3, EXC_TABLE_FIXUP
+
+ /* Restore working register */
+
+ l32i a7, a2, PT_AREG7
+ l32i a6, a2, PT_AREG6
+ l32i a5, a2, PT_AREG5
+ l32i a4, a2, PT_AREG4
+ l32i a3, a2, PT_AREG3
+
+ /* restore SAR and return */
+
+ wsr a0, SAR
+ l32i a0, a2, PT_AREG0
+ l32i a2, a2, PT_AREG2
+ rfe
+
+ /* We cannot handle this exception. */
+
+ .extern _kernel_exception
+.Linvalid_instruction_store:
+.Linvalid_instruction:
+
+ /* Restore a4...a8 and SAR, set SP, and jump to default exception. */
+
+ l32i a8, a2, PT_AREG8
+ l32i a7, a2, PT_AREG7
+ l32i a6, a2, PT_AREG6
+ l32i a5, a2, PT_AREG5
+ l32i a4, a2, PT_AREG4
+ wsr a0, SAR
+ mov a1, a2
+
+ rsr a0, PS
+ bbsi.l a2, PS_UM_SHIFT, 1f # jump if user mode
+
+ movi a0, _kernel_exception
+ jx a0
+
+1: movi a0, _user_exception
+ jx a0
+
+
+#endif /* XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION */
+
diff --git a/arch/xtensa/kernel/asm-offsets.c b/arch/xtensa/kernel/asm-offsets.c
new file mode 100644
index 000000000000..7cd1d7f8f608
--- /dev/null
+++ b/arch/xtensa/kernel/asm-offsets.c
@@ -0,0 +1,93 @@
+/*
+ * arch/xtensa/kernel/asm-offsets.c
+ *
+ * Generates definitions from c-type structures used by assembly sources.
+ *
+ * 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <asm/processor.h>
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/thread_info.h>
+#include <linux/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+#define DEFINE(sym, val) asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+#define BLANK() asm volatile("\n->" : : )
+
+int main(void)
+{
+ /* struct pt_regs */
+ DEFINE(PT_PC, offsetof (struct pt_regs, pc));
+ DEFINE(PT_PS, offsetof (struct pt_regs, ps));
+ DEFINE(PT_DEPC, offsetof (struct pt_regs, depc));
+ DEFINE(PT_EXCCAUSE, offsetof (struct pt_regs, exccause));
+ DEFINE(PT_EXCVADDR, offsetof (struct pt_regs, excvaddr));
+ DEFINE(PT_DEBUGCAUSE, offsetof (struct pt_regs, debugcause));
+ DEFINE(PT_WMASK, offsetof (struct pt_regs, wmask));
+ DEFINE(PT_LBEG, offsetof (struct pt_regs, lbeg));
+ DEFINE(PT_LEND, offsetof (struct pt_regs, lend));
+ DEFINE(PT_LCOUNT, offsetof (struct pt_regs, lcount));
+ DEFINE(PT_SAR, offsetof (struct pt_regs, sar));
+ DEFINE(PT_SYSCALL, offsetof (struct pt_regs, syscall));
+ DEFINE(PT_AREG, offsetof (struct pt_regs, areg[0]));
+ DEFINE(PT_AREG0, offsetof (struct pt_regs, areg[0]));
+ DEFINE(PT_AREG1, offsetof (struct pt_regs, areg[1]));
+ DEFINE(PT_AREG2, offsetof (struct pt_regs, areg[2]));
+ DEFINE(PT_AREG3, offsetof (struct pt_regs, areg[3]));
+ DEFINE(PT_AREG4, offsetof (struct pt_regs, areg[4]));
+ DEFINE(PT_AREG5, offsetof (struct pt_regs, areg[5]));
+ DEFINE(PT_AREG6, offsetof (struct pt_regs, areg[6]));
+ DEFINE(PT_AREG7, offsetof (struct pt_regs, areg[7]));
+ DEFINE(PT_AREG8, offsetof (struct pt_regs, areg[8]));
+ DEFINE(PT_AREG9, offsetof (struct pt_regs, areg[9]));
+ DEFINE(PT_AREG10, offsetof (struct pt_regs, areg[10]));
+ DEFINE(PT_AREG11, offsetof (struct pt_regs, areg[11]));
+ DEFINE(PT_AREG12, offsetof (struct pt_regs, areg[12]));
+ DEFINE(PT_AREG13, offsetof (struct pt_regs, areg[13]));
+ DEFINE(PT_AREG14, offsetof (struct pt_regs, areg[14]));
+ DEFINE(PT_AREG15, offsetof (struct pt_regs, areg[15]));
+ DEFINE(PT_WINDOWBASE, offsetof (struct pt_regs, windowbase));
+ DEFINE(PT_WINDOWSTART, offsetof(struct pt_regs, windowstart));
+ DEFINE(PT_SIZE, sizeof(struct pt_regs));
+ DEFINE(PT_AREG_END, offsetof (struct pt_regs, areg[XCHAL_NUM_AREGS]));
+ DEFINE(PT_USER_SIZE, offsetof(struct pt_regs, areg[XCHAL_NUM_AREGS]));
+ BLANK();
+
+ /* struct task_struct */
+ DEFINE(TASK_PTRACE, offsetof (struct task_struct, ptrace));
+ DEFINE(TASK_MM, offsetof (struct task_struct, mm));
+ DEFINE(TASK_ACTIVE_MM, offsetof (struct task_struct, active_mm));
+ DEFINE(TASK_PID, offsetof (struct task_struct, pid));
+ DEFINE(TASK_THREAD, offsetof (struct task_struct, thread));
+ DEFINE(TASK_THREAD_INFO, offsetof (struct task_struct, thread_info));
+ DEFINE(TASK_STRUCT_SIZE, sizeof (struct task_struct));
+ BLANK();
+
+ /* struct thread_info (offset from start_struct) */
+ DEFINE(THREAD_RA, offsetof (struct task_struct, thread.ra));
+ DEFINE(THREAD_SP, offsetof (struct task_struct, thread.sp));
+ DEFINE(THREAD_CP_SAVE, offsetof (struct task_struct, thread.cp_save));
+ DEFINE(THREAD_CURRENT_DS, offsetof (struct task_struct, thread.current_ds));
+ BLANK();
+
+ /* struct mm_struct */
+ DEFINE(MM_USERS, offsetof(struct mm_struct, mm_users));
+ DEFINE(MM_PGD, offsetof (struct mm_struct, pgd));
+ DEFINE(MM_CONTEXT, offsetof (struct mm_struct, context));
+ BLANK();
+ DEFINE(PT_SINGLESTEP_BIT, PT_SINGLESTEP_BIT);
+ return 0;
+}
+
+
diff --git a/arch/xtensa/kernel/coprocessor.S b/arch/xtensa/kernel/coprocessor.S
new file mode 100644
index 000000000000..356192a4d39d
--- /dev/null
+++ b/arch/xtensa/kernel/coprocessor.S
@@ -0,0 +1,201 @@
+/*
+ * arch/xtensa/kernel/coprocessor.S
+ *
+ * Xtensa processor configuration-specific table of coprocessor and
+ * other custom register layout information.
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ *
+ * Marc Gauthier <marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+/*
+ * This module contains a table that describes the layout of the various
+ * custom registers and states associated with each coprocessor, as well
+ * as those not associated with any coprocessor ("extra state").
+ * This table is included with core dumps and is available via the ptrace
+ * interface, allowing the layout of such register/state information to
+ * be modified in the kernel without affecting the debugger. Each
+ * register or state is identified using a 32-bit "libdb target number"
+ * assigned when the Xtensa processor is generated.
+ */
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <asm/processor.h>
+
+#if XCHAL_HAVE_CP
+
+#define CP_LAST ((XCHAL_CP_MAX - 1) * COPROCESSOR_INFO_SIZE)
+
+ENTRY(release_coprocessors)
+
+ entry a1, 16
+ # a2: task
+ movi a3, 1 << XCHAL_CP_MAX # a3: coprocessor-bit
+ movi a4, coprocessor_info+CP_LAST # a4: owner-table
+ # a5: tmp
+ movi a6, 0 # a6: 0
+ rsil a7, LOCKLEVEL # a7: PS
+
+1: /* Check if task is coprocessor owner of coprocessor[i]. */
+
+ l32i a5, a4, COPROCESSOR_INFO_OWNER
+ srli a3, a3, 1
+ beqz a3, 1f
+ addi a4, a4, -8
+ beq a2, a5, 1b
+
+ /* Found an entry: Clear entry CPENABLE bit to disable CP. */
+
+ rsr a5, CPENABLE
+ s32i a6, a4, COPROCESSOR_INFO_OWNER
+ xor a5, a3, a5
+ wsr a5, CPENABLE
+
+ bnez a3, 1b
+
+1: wsr a7, PS
+ rsync
+ retw
+
+
+ENTRY(disable_coprocessor)
+ entry sp, 16
+ rsil a7, LOCKLEVEL
+ rsr a3, CPENABLE
+ movi a4, 1
+ ssl a2
+ sll a4, a4
+ and a4, a3, a4
+ xor a3, a3, a4
+ wsr a3, CPENABLE
+ wsr a7, PS
+ rsync
+ retw
+
+ENTRY(enable_coprocessor)
+ entry sp, 16
+ rsil a7, LOCKLEVEL
+ rsr a3, CPENABLE
+ movi a4, 1
+ ssl a2
+ sll a4, a4
+ or a3, a3, a4
+ wsr a3, CPENABLE
+ wsr a7, PS
+ rsync
+ retw
+
+#endif
+
+ENTRY(save_coprocessor_extra)
+ entry sp, 16
+ xchal_extra_store_funcbody
+ retw
+
+ENTRY(restore_coprocessor_extra)
+ entry sp, 16
+ xchal_extra_load_funcbody
+ retw
+
+ENTRY(save_coprocessor_registers)
+ entry sp, 16
+ xchal_cpi_store_funcbody
+ retw
+
+ENTRY(restore_coprocessor_registers)
+ entry sp, 16
+ xchal_cpi_load_funcbody
+ retw
+
+
+/*
+ * The Xtensa compile-time HAL (core.h) XCHAL_*_SA_CONTENTS_LIBDB macros
+ * describe the contents of coprocessor & extra save areas in terms of
+ * undefined CONTENTS_LIBDB_{SREG,UREG,REGF} macros. We define these
+ * latter macros here; they expand into a table of the format we want.
+ * The general format is:
+ *
+ * CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum,
+ * bitmask, rsv2, rsv3)
+ * CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum,
+ * bitmask, rsv2, rsv3)
+ * CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index,
+ * numentries, contentsize, regname_base,
+ * regfile_name, rsv2, rsv3)
+ *
+ * For this table, we only care about the <libdbnum>, <offset> and <size>
+ * fields.
+ */
+
+/* Map all XCHAL CONTENTS macros to the reg_entry asm macro defined below: */
+
+#define CONTENTS_LIBDB_SREG(libdbnum,offset,size,align,rsv1,name,sregnum, \
+ bitmask, rsv2, rsv3) \
+ reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_UREG(libdbnum,offset,size,align,rsv1,name,uregnum, \
+ bitmask, rsv2, rsv3) \
+ reg_entry libdbnum, offset, size ;
+#define CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, \
+ numentries, contentsize, regname_base, \
+ regfile_name, rsv2, rsv3) \
+ reg_entry libdbnum, offset, size ;
+
+/* A single table entry: */
+ .macro reg_entry libdbnum, offset, size
+ .ifne (__last_offset-(__last_group_offset+\offset))
+ /* padding entry */
+ .word (0xFC000000+__last_offset-(__last_group_offset+\offset))
+ .endif
+ .word \libdbnum /* actual entry */
+ .set __last_offset, __last_group_offset+\offset+\size
+ .endm /* reg_entry */
+
+
+/* Table entry that marks the beginning of a group (coprocessor or "extra"): */
+ .macro reg_group cpnum, num_entries, align
+ .set __last_group_offset, (__last_offset + \align- 1) & -\align
+ .ifne \num_entries
+ .word 0xFD000000+(\cpnum<<16)+\num_entries
+ .endif
+ .endm /* reg_group */
+
+/*
+ * Register info tables.
+ */
+
+ .section .rodata, "a"
+ .globl _xtensa_reginfo_tables
+ .globl _xtensa_reginfo_table_size
+ .align 4
+_xtensa_reginfo_table_size:
+ .word _xtensa_reginfo_table_end - _xtensa_reginfo_tables
+
+_xtensa_reginfo_tables:
+ .set __last_offset, 0
+ reg_group 0xFF, XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM, XCHAL_EXTRA_SA_ALIGN
+ XCHAL_EXTRA_SA_CONTENTS_LIBDB
+ reg_group 0, XCHAL_CP0_SA_CONTENTS_LIBDB_NUM, XCHAL_CP0_SA_ALIGN
+ XCHAL_CP0_SA_CONTENTS_LIBDB
+ reg_group 1, XCHAL_CP1_SA_CONTENTS_LIBDB_NUM, XCHAL_CP1_SA_ALIGN
+ XCHAL_CP1_SA_CONTENTS_LIBDB
+ reg_group 2, XCHAL_CP2_SA_CONTENTS_LIBDB_NUM, XCHAL_CP2_SA_ALIGN
+ XCHAL_CP2_SA_CONTENTS_LIBDB
+ reg_group 3, XCHAL_CP3_SA_CONTENTS_LIBDB_NUM, XCHAL_CP3_SA_ALIGN
+ XCHAL_CP3_SA_CONTENTS_LIBDB
+ reg_group 4, XCHAL_CP4_SA_CONTENTS_LIBDB_NUM, XCHAL_CP4_SA_ALIGN
+ XCHAL_CP4_SA_CONTENTS_LIBDB
+ reg_group 5, XCHAL_CP5_SA_CONTENTS_LIBDB_NUM, XCHAL_CP5_SA_ALIGN
+ XCHAL_CP5_SA_CONTENTS_LIBDB
+ reg_group 6, XCHAL_CP6_SA_CONTENTS_LIBDB_NUM, XCHAL_CP6_SA_ALIGN
+ XCHAL_CP6_SA_CONTENTS_LIBDB
+ reg_group 7, XCHAL_CP7_SA_CONTENTS_LIBDB_NUM, XCHAL_CP7_SA_ALIGN
+ XCHAL_CP7_SA_CONTENTS_LIBDB
+ .word 0xFC000000 /* invalid register number,marks end of table*/
+_xtensa_reginfo_table_end:
+
diff --git a/arch/xtensa/kernel/entry.S b/arch/xtensa/kernel/entry.S
new file mode 100644
index 000000000000..c64a01f71de6
--- /dev/null
+++ b/arch/xtensa/kernel/entry.S
@@ -0,0 +1,1996 @@
+/*
+ * arch/xtensa/kernel/entry.S
+ *
+ * Low-level exception handling
+ *
+ * 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-2005 by Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+#include <asm/thread_info.h>
+#include <asm/uaccess.h>
+#include <asm/unistd.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/signal.h>
+#include <xtensa/coreasm.h>
+
+/* Unimplemented features. */
+
+#undef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+#undef KERNEL_STACK_OVERFLOW_CHECK
+#undef PREEMPTIBLE_KERNEL
+#undef ALLOCA_EXCEPTION_IN_IRAM
+
+/* Not well tested.
+ *
+ * - fast_coprocessor
+ */
+
+/*
+ * Macro to find first bit set in WINDOWBASE from the left + 1
+ *
+ * 100....0 -> 1
+ * 010....0 -> 2
+ * 000....1 -> WSBITS
+ */
+
+ .macro ffs_ws bit mask
+
+#if XCHAL_HAVE_NSA
+ nsau \bit, \mask # 32-WSBITS ... 31 (32 iff 0)
+ addi \bit, \bit, WSBITS - 32 + 1 # uppest bit set -> return 1
+#else
+ movi \bit, WSBITS
+#if WSBITS > 16
+ _bltui \mask, 0x10000, 99f
+ addi \bit, \bit, -16
+ extui \mask, \mask, 16, 16
+#endif
+#if WSBITS > 8
+99: _bltui \mask, 0x100, 99f
+ addi \bit, \bit, -8
+ srli \mask, \mask, 8
+#endif
+99: _bltui \mask, 0x10, 99f
+ addi \bit, \bit, -4
+ srli \mask, \mask, 4
+99: _bltui \mask, 0x4, 99f
+ addi \bit, \bit, -2
+ srli \mask, \mask, 2
+99: _bltui \mask, 0x2, 99f
+ addi \bit, \bit, -1
+99:
+
+#endif
+ .endm
+
+/* ----------------- DEFAULT FIRST LEVEL EXCEPTION HANDLERS ----------------- */
+
+/*
+ * First-level exception handler for user exceptions.
+ * Save some special registers, extra states and all registers in the AR
+ * register file that were in use in the user task, and jump to the common
+ * exception code.
+ * We save SAR (used to calculate WMASK), and WB and WS (we don't have to
+ * save them for kernel exceptions).
+ *
+ * Entry condition for user_exception:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original value in depc
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _user_exception:
+ *
+ * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ * excsave has been restored, and
+ * stack pointer (a1) has been set.
+ *
+ * Note: _user_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(user_exception)
+
+ /* Save a2, a3, and depc, restore excsave_1 and set SP. */
+
+ xsr a3, EXCSAVE_1
+ rsr a0, DEPC
+ s32i a1, a2, PT_AREG1
+ s32i a0, a2, PT_AREG2
+ s32i a3, a2, PT_AREG3
+ mov a1, a2
+
+ .globl _user_exception
+_user_exception:
+
+ /* Save SAR and turn off single stepping */
+
+ movi a2, 0
+ rsr a3, SAR
+ wsr a2, ICOUNTLEVEL
+ s32i a3, a1, PT_SAR
+
+ /* Rotate ws so that the current windowbase is at bit0. */
+ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+ rsr a2, WINDOWBASE
+ rsr a3, WINDOWSTART
+ ssr a2
+ s32i a2, a1, PT_WINDOWBASE
+ s32i a3, a1, PT_WINDOWSTART
+ slli a2, a3, 32-WSBITS
+ src a2, a3, a2
+ srli a2, a2, 32-WSBITS
+ s32i a2, a1, PT_WMASK # needed for restoring registers
+
+ /* Save only live registers. */
+
+ _bbsi.l a2, 1, 1f
+ s32i a4, a1, PT_AREG4
+ s32i a5, a1, PT_AREG5
+ s32i a6, a1, PT_AREG6
+ s32i a7, a1, PT_AREG7
+ _bbsi.l a2, 2, 1f
+ s32i a8, a1, PT_AREG8
+ s32i a9, a1, PT_AREG9
+ s32i a10, a1, PT_AREG10
+ s32i a11, a1, PT_AREG11
+ _bbsi.l a2, 3, 1f
+ s32i a12, a1, PT_AREG12
+ s32i a13, a1, PT_AREG13
+ s32i a14, a1, PT_AREG14
+ s32i a15, a1, PT_AREG15
+ _bnei a2, 1, 1f # only one valid frame?
+
+ /* Only one valid frame, skip saving regs. */
+
+ j 2f
+
+ /* Save the remaining registers.
+ * We have to save all registers up to the first '1' from
+ * the right, except the current frame (bit 0).
+ * Assume a2 is: 001001000110001
+ * All regiser frames starting from the top fiel to the marked '1'
+ * must be saved.
+ */
+
+1: addi a3, a2, -1 # eliminate '1' in bit 0: yyyyxxww0
+ neg a3, a3 # yyyyxxww0 -> YYYYXXWW1+1
+ and a3, a3, a2 # max. only one bit is set
+
+ /* Find number of frames to save */
+
+ ffs_ws a0, a3 # number of frames to the '1' from left
+
+ /* Store information into WMASK:
+ * bits 0..3: xxx1 masked lower 4 bits of the rotated windowstart,
+ * bits 4...: number of valid 4-register frames
+ */
+
+ slli a3, a0, 4 # number of frames to save in bits 8..4
+ extui a2, a2, 0, 4 # mask for the first 16 registers
+ or a2, a3, a2
+ s32i a2, a1, PT_WMASK # needed when we restore the reg-file
+
+ /* Save 4 registers at a time */
+
+1: rotw -1
+ s32i a0, a5, PT_AREG_END - 16
+ s32i a1, a5, PT_AREG_END - 12
+ s32i a2, a5, PT_AREG_END - 8
+ s32i a3, a5, PT_AREG_END - 4
+ addi a0, a4, -1
+ addi a1, a5, -16
+ _bnez a0, 1b
+
+ /* WINDOWBASE still in SAR! */
+
+ rsr a2, SAR # original WINDOWBASE
+ movi a3, 1
+ ssl a2
+ sll a3, a3
+ wsr a3, WINDOWSTART # set corresponding WINDOWSTART bit
+ wsr a2, WINDOWBASE # and WINDOWSTART
+ rsync
+
+ /* We are back to the original stack pointer (a1) */
+
+2:
+#if XCHAL_EXTRA_SA_SIZE
+
+ /* For user exceptions, save the extra state into the user's TCB.
+ * Note: We must assume that xchal_extra_store_funcbody destroys a2..a15
+ */
+
+ GET_CURRENT(a2,a1)
+ addi a2, a2, THREAD_CP_SAVE
+ xchal_extra_store_funcbody
+#endif
+
+ /* Now, jump to the common exception handler. */
+
+ j common_exception
+
+
+/*
+ * First-level exit handler for kernel exceptions
+ * Save special registers and the live window frame.
+ * Note: Even though we changes the stack pointer, we don't have to do a
+ * MOVSP here, as we do that when we return from the exception.
+ * (See comment in the kernel exception exit code)
+ *
+ * Entry condition for kernel_exception:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Entry condition for _kernel_exception:
+ *
+ * a0-a3 and depc have been saved to PT_AREG0...PT_AREG3 and PT_DEPC
+ * excsave has been restored, and
+ * stack pointer (a1) has been set.
+ *
+ * Note: _kernel_exception might be at an odd adress. Don't use call0..call12
+ */
+
+ENTRY(kernel_exception)
+
+ /* Save a0, a2, a3, DEPC and set SP. */
+
+ xsr a3, EXCSAVE_1 # restore a3, excsave_1
+ rsr a0, DEPC # get a2
+ s32i a1, a2, PT_AREG1
+ s32i a0, a2, PT_AREG2
+ s32i a3, a2, PT_AREG3
+ mov a1, a2
+
+ .globl _kernel_exception
+_kernel_exception:
+
+ /* Save SAR and turn off single stepping */
+
+ movi a2, 0
+ rsr a3, SAR
+ wsr a2, ICOUNTLEVEL
+ s32i a3, a1, PT_SAR
+
+ /* Rotate ws so that the current windowbase is at bit0. */
+ /* Assume ws = xxwww1yyyy. Rotate ws right, so that a2 = yyyyxxwww1 */
+
+ rsr a2, WINDOWBASE # don't need to save these, we only
+ rsr a3, WINDOWSTART # need shifted windowstart: windowmask
+ ssr a2
+ slli a2, a3, 32-WSBITS
+ src a2, a3, a2
+ srli a2, a2, 32-WSBITS
+ s32i a2, a1, PT_WMASK # needed for kernel_exception_exit
+
+ /* Save only the live window-frame */
+
+ _bbsi.l a2, 1, 1f
+ s32i a4, a1, PT_AREG4
+ s32i a5, a1, PT_AREG5
+ s32i a6, a1, PT_AREG6
+ s32i a7, a1, PT_AREG7
+ _bbsi.l a2, 2, 1f
+ s32i a8, a1, PT_AREG8
+ s32i a9, a1, PT_AREG9
+ s32i a10, a1, PT_AREG10
+ s32i a11, a1, PT_AREG11
+ _bbsi.l a2, 3, 1f
+ s32i a12, a1, PT_AREG12
+ s32i a13, a1, PT_AREG13
+ s32i a14, a1, PT_AREG14
+ s32i a15, a1, PT_AREG15
+
+1:
+
+#ifdef KERNEL_STACK_OVERFLOW_CHECK
+
+ /* Stack overflow check, for debugging */
+ extui a2, a1, TASK_SIZE_BITS,XX
+ movi a3, SIZE??
+ _bge a2, a3, out_of_stack_panic
+
+#endif
+
+/*
+ * This is the common exception handler.
+ * We get here from the user exception handler or simply by falling through
+ * from the kernel exception handler.
+ * Save the remaining special registers, switch to kernel mode, and jump
+ * to the second-level exception handler.
+ *
+ */
+
+common_exception:
+
+ /* Save EXCVADDR, DEBUGCAUSE, and PC, and clear LCOUNT */
+
+ rsr a2, DEBUGCAUSE
+ rsr a3, EPC_1
+ s32i a2, a1, PT_DEBUGCAUSE
+ s32i a3, a1, PT_PC
+
+ rsr a3, EXCVADDR
+ movi a2, 0
+ s32i a3, a1, PT_EXCVADDR
+ xsr a2, LCOUNT
+ s32i a2, a1, PT_LCOUNT
+
+ /* It is now save to restore the EXC_TABLE_FIXUP variable. */
+
+ rsr a0, EXCCAUSE
+ movi a3, 0
+ rsr a2, EXCSAVE_1
+ s32i a0, a1, PT_EXCCAUSE
+ s32i a3, a2, EXC_TABLE_FIXUP
+
+ /* All unrecoverable states are saved on stack, now, and a1 is valid,
+ * so we can allow exceptions and interrupts (*) again.
+ * Set PS(EXCM = 0, UM = 0, RING = 0, OWB = 0, WOE = 1, INTLEVEL = X)
+ *
+ * (*) We only allow interrupts if PS.INTLEVEL was not set to 1 before
+ * (interrupts disabled) and if this exception is not an interrupt.
+ */
+
+ rsr a3, PS
+ addi a0, a0, -4
+ movi a2, 1
+ extui a3, a3, 0, 1 # a3 = PS.INTLEVEL[0]
+ moveqz a3, a2, a0 # a3 = 1 iff interrupt exception
+ movi a2, PS_WOE_MASK
+ or a3, a3, a2
+ rsr a0, EXCCAUSE
+ xsr a3, PS
+
+ s32i a3, a1, PT_PS # save ps
+
+ /* Save LBEG, LEND */
+
+ rsr a2, LBEG
+ rsr a3, LEND
+ s32i a2, a1, PT_LBEG
+ s32i a3, a1, PT_LEND
+
+ /* Go to second-level dispatcher. Set up parameters to pass to the
+ * exception handler and call the exception handler.
+ */
+
+ movi a4, exc_table
+ mov a6, a1 # pass stack frame
+ mov a7, a0 # pass EXCCAUSE
+ addx4 a4, a0, a4
+ l32i a4, a4, EXC_TABLE_DEFAULT # load handler
+
+ /* Call the second-level handler */
+
+ callx4 a4
+
+ /* Jump here for exception exit */
+
+common_exception_return:
+
+ /* Jump if we are returning from kernel exceptions. */
+
+1: l32i a3, a1, PT_PS
+ _bbsi.l a3, PS_UM_SHIFT, 2f
+ j kernel_exception_exit
+
+ /* Specific to a user exception exit:
+ * We need to check some flags for signal handling and rescheduling,
+ * and have to restore WB and WS, extra states, and all registers
+ * in the register file that were in use in the user task.
+ */
+
+2: wsr a3, PS /* disable interrupts */
+
+ /* Check for signals (keep interrupts disabled while we read TI_FLAGS)
+ * Note: PS.INTLEVEL = 0, PS.EXCM = 1
+ */
+
+ GET_THREAD_INFO(a2,a1)
+ l32i a4, a2, TI_FLAGS
+
+ /* Enable interrupts again.
+ * Note: When we get here, we certainly have handled any interrupts.
+ * (Hint: There is only one user exception frame on stack)
+ */
+
+ movi a3, PS_WOE_MASK
+
+ _bbsi.l a4, TIF_NEED_RESCHED, 3f
+ _bbci.l a4, TIF_SIGPENDING, 4f
+
+#ifndef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+ l32i a4, a1, PT_DEPC
+ bgeui a4, VALID_DOUBLE_EXCEPTION_ADDRESS, 4f
+#endif
+
+ /* Reenable interrupts and call do_signal() */
+
+ wsr a3, PS
+ movi a4, do_signal # int do_signal(struct pt_regs*, sigset_t*)
+ mov a6, a1
+ movi a7, 0
+ callx4 a4
+ j 1b
+
+3: /* Reenable interrupts and reschedule */
+
+ wsr a3, PS
+ movi a4, schedule # void schedule (void)
+ callx4 a4
+ j 1b
+
+ /* Restore the state of the task and return from the exception. */
+
+
+ /* If we are returning from a user exception, and the process
+ * to run next has PT_SINGLESTEP set, we want to setup
+ * ICOUNT and ICOUNTLEVEL to step one instruction.
+ * PT_SINGLESTEP is set by sys_ptrace (ptrace.c)
+ */
+
+4: /* a2 holds GET_CURRENT(a2,a1) */
+
+ l32i a3, a2, TI_TASK
+ l32i a3, a3, TASK_PTRACE
+ bbci.l a3, PT_SINGLESTEP_BIT, 1f # jump if single-step flag is not set
+
+ movi a3, -2 # PT_SINGLESTEP flag is set,
+ movi a4, 1 # icountlevel of 1 means it won't
+ wsr a3, ICOUNT # start counting until after rfe
+ wsr a4, ICOUNTLEVEL # so setup icount & icountlevel.
+ isync
+
+1:
+
+#if XCHAL_EXTRA_SA_SIZE
+
+ /* For user exceptions, restore the extra state from the user's TCB. */
+
+ /* Note: a2 still contains GET_CURRENT(a2,a1) */
+ addi a2, a2, THREAD_CP_SAVE
+ xchal_extra_load_funcbody
+
+ /* We must assume that xchal_extra_store_funcbody destroys
+ * registers a2..a15. FIXME, this list can eventually be
+ * reduced once real register requirements of the macro are
+ * finalized. */
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+
+ /* Switch to the user thread WINDOWBASE. Save SP temporarily in DEPC */
+
+ l32i a2, a1, PT_WINDOWBASE
+ l32i a3, a1, PT_WINDOWSTART
+ wsr a1, DEPC # use DEPC as temp storage
+ wsr a3, WINDOWSTART # restore WINDOWSTART
+ ssr a2 # preserve user's WB in the SAR
+ wsr a2, WINDOWBASE # switch to user's saved WB
+ rsync
+ rsr a1, DEPC # restore stack pointer
+ l32i a2, a1, PT_WMASK # register frames saved (in bits 4...9)
+ rotw -1 # we restore a4..a7
+ _bltui a6, 16, 1f # only have to restore current window?
+
+ /* The working registers are a0 and a3. We are restoring to
+ * a4..a7. Be careful not to destroy what we have just restored.
+ * Note: wmask has the format YYYYM:
+ * Y: number of registers saved in groups of 4
+ * M: 4 bit mask of first 16 registers
+ */
+
+ mov a2, a6
+ mov a3, a5
+
+2: rotw -1 # a0..a3 become a4..a7
+ addi a3, a7, -4*4 # next iteration
+ addi a2, a6, -16 # decrementing Y in WMASK
+ l32i a4, a3, PT_AREG_END + 0
+ l32i a5, a3, PT_AREG_END + 4
+ l32i a6, a3, PT_AREG_END + 8
+ l32i a7, a3, PT_AREG_END + 12
+ _bgeui a2, 16, 2b
+
+ /* Clear unrestored registers (don't leak anything to user-land */
+
+1: rsr a0, WINDOWBASE
+ rsr a3, SAR
+ sub a3, a0, a3
+ beqz a3, 2f
+ extui a3, a3, 0, WBBITS
+
+1: rotw -1
+ addi a3, a7, -1
+ movi a4, 0
+ movi a5, 0
+ movi a6, 0
+ movi a7, 0
+ bgei a3, 1, 1b
+
+ /* We are back were we were when we started.
+ * Note: a2 still contains WMASK (if we've returned to the original
+ * frame where we had loaded a2), or at least the lower 4 bits
+ * (if we have restored WSBITS-1 frames).
+ */
+
+2: j common_exception_exit
+
+ /* This is the kernel exception exit.
+ * We avoided to do a MOVSP when we entered the exception, but we
+ * have to do it here.
+ */
+
+kernel_exception_exit:
+
+ /* Disable interrupts (a3 holds PT_PS) */
+
+ wsr a3, PS
+
+#ifdef PREEMPTIBLE_KERNEL
+
+#ifdef CONFIG_PREEMPT
+
+ /*
+ * Note: We've just returned from a call4, so we have
+ * at least 4 addt'l regs.
+ */
+
+ /* Check current_thread_info->preempt_count */
+
+ GET_THREAD_INFO(a2)
+ l32i a3, a2, TI_PREEMPT
+ bnez a3, 1f
+
+ l32i a2, a2, TI_FLAGS
+
+1:
+
+#endif
+
+#endif
+
+ /* Check if we have to do a movsp.
+ *
+ * We only have to do a movsp if the previous window-frame has
+ * been spilled to the *temporary* exception stack instead of the
+ * task's stack. This is the case if the corresponding bit in
+ * WINDOWSTART for the previous window-frame was set before
+ * (not spilled) but is zero now (spilled).
+ * If this bit is zero, all other bits except the one for the
+ * current window frame are also zero. So, we can use a simple test:
+ * 'and' WINDOWSTART and WINDOWSTART-1:
+ *
+ * (XXXXXX1[0]* - 1) AND XXXXXX1[0]* = XXXXXX0[0]*
+ *
+ * The result is zero only if one bit was set.
+ *
+ * (Note: We might have gone through several task switches before
+ * we come back to the current task, so WINDOWBASE might be
+ * different from the time the exception occurred.)
+ */
+
+ /* Test WINDOWSTART before and after the exception.
+ * We actually have WMASK, so we only have to test if it is 1 or not.
+ */
+
+ l32i a2, a1, PT_WMASK
+ _beqi a2, 1, common_exception_exit # Spilled before exception,jump
+
+ /* Test WINDOWSTART now. If spilled, do the movsp */
+
+ rsr a3, WINDOWSTART
+ addi a0, a3, -1
+ and a3, a3, a0
+ _bnez a3, common_exception_exit
+
+ /* Do a movsp (we returned from a call4, so we have at least a0..a7) */
+
+ addi a0, a1, -16
+ l32i a3, a0, 0
+ l32i a4, a0, 4
+ s32i a3, a1, PT_SIZE+0
+ s32i a4, a1, PT_SIZE+4
+ l32i a3, a0, 8
+ l32i a4, a0, 12
+ s32i a3, a1, PT_SIZE+8
+ s32i a4, a1, PT_SIZE+12
+
+ /* Common exception exit.
+ * We restore the special register and the current window frame, and
+ * return from the exception.
+ *
+ * Note: We expect a2 to hold PT_WMASK
+ */
+
+common_exception_exit:
+
+ _bbsi.l a2, 1, 1f
+ l32i a4, a1, PT_AREG4
+ l32i a5, a1, PT_AREG5
+ l32i a6, a1, PT_AREG6
+ l32i a7, a1, PT_AREG7
+ _bbsi.l a2, 2, 1f
+ l32i a8, a1, PT_AREG8
+ l32i a9, a1, PT_AREG9
+ l32i a10, a1, PT_AREG10
+ l32i a11, a1, PT_AREG11
+ _bbsi.l a2, 3, 1f
+ l32i a12, a1, PT_AREG12
+ l32i a13, a1, PT_AREG13
+ l32i a14, a1, PT_AREG14
+ l32i a15, a1, PT_AREG15
+
+ /* Restore PC, SAR */
+
+1: l32i a2, a1, PT_PC
+ l32i a3, a1, PT_SAR
+ wsr a2, EPC_1
+ wsr a3, SAR
+
+ /* Restore LBEG, LEND, LCOUNT */
+
+ l32i a2, a1, PT_LBEG
+ l32i a3, a1, PT_LEND
+ wsr a2, LBEG
+ l32i a2, a1, PT_LCOUNT
+ wsr a3, LEND
+ wsr a2, LCOUNT
+
+ /* Check if it was double exception. */
+
+ l32i a0, a1, PT_DEPC
+ l32i a3, a1, PT_AREG3
+ l32i a2, a1, PT_AREG2
+ _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+ /* Restore a0...a3 and return */
+
+ l32i a0, a1, PT_AREG0
+ l32i a1, a1, PT_AREG1
+ rfe
+
+1: wsr a0, DEPC
+ l32i a0, a1, PT_AREG0
+ l32i a1, a1, PT_AREG1
+ rfde
+
+/*
+ * Debug exception handler.
+ *
+ * Currently, we don't support KGDB, so only user application can be debugged.
+ *
+ * When we get here, a0 is trashed and saved to excsave[debuglevel]
+ */
+
+ENTRY(debug_exception)
+
+ rsr a0, EPS + XCHAL_DEBUGLEVEL
+ bbsi.l a0, PS_EXCM_SHIFT, 1f # exception mode
+
+ /* Set EPC_1 and EXCCAUSE */
+
+ wsr a2, DEPC # save a2 temporarily
+ rsr a2, EPC + XCHAL_DEBUGLEVEL
+ wsr a2, EPC_1
+
+ movi a2, EXCCAUSE_MAPPED_DEBUG
+ wsr a2, EXCCAUSE
+
+ /* Restore PS to the value before the debug exc but with PS.EXCM set.*/
+
+ movi a2, 1 << PS_EXCM_SHIFT
+ or a2, a0, a2
+ movi a0, debug_exception # restore a3, debug jump vector
+ wsr a2, PS
+ xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL
+
+ /* Switch to kernel/user stack, restore jump vector, and save a0 */
+
+ bbsi.l a2, PS_UM_SHIFT, 2f # jump if user mode
+
+ addi a2, a1, -16-PT_SIZE # assume kernel stack
+ s32i a0, a2, PT_AREG0
+ movi a0, 0
+ s32i a1, a2, PT_AREG1
+ s32i a0, a2, PT_DEPC # mark it as a regular exception
+ xsr a0, DEPC
+ s32i a3, a2, PT_AREG3
+ s32i a0, a2, PT_AREG2
+ mov a1, a2
+ j _kernel_exception
+
+2: rsr a2, EXCSAVE_1
+ l32i a2, a2, EXC_TABLE_KSTK # load kernel stack pointer
+ s32i a0, a2, PT_AREG0
+ movi a0, 0
+ s32i a1, a2, PT_AREG1
+ s32i a0, a2, PT_DEPC
+ xsr a0, DEPC
+ s32i a3, a2, PT_AREG3
+ s32i a0, a2, PT_AREG2
+ mov a1, a2
+ j _user_exception
+
+ /* Debug exception while in exception mode. */
+1: j 1b // FIXME!!
+
+
+/*
+ * We get here in case of an unrecoverable exception.
+ * The only thing we can do is to be nice and print a panic message.
+ * We only produce a single stack frame for panic, so ???
+ *
+ *
+ * Entry conditions:
+ *
+ * - a0 contains the caller address; original value saved in excsave1.
+ * - the original a0 contains a valid return address (backtrace) or 0.
+ * - a2 contains a valid stackpointer
+ *
+ * Notes:
+ *
+ * - If the stack pointer could be invalid, the caller has to setup a
+ * dummy stack pointer (e.g. the stack of the init_task)
+ *
+ * - If the return address could be invalid, the caller has to set it
+ * to 0, so the backtrace would stop.
+ *
+ */
+ .align 4
+unrecoverable_text:
+ .ascii "Unrecoverable error in exception handler\0"
+
+ENTRY(unrecoverable_exception)
+
+ movi a0, 1
+ movi a1, 0
+
+ wsr a0, WINDOWSTART
+ wsr a1, WINDOWBASE
+ rsync
+
+ movi a1, PS_WOE_MASK | 1
+ wsr a1, PS
+ rsync
+
+ movi a1, init_task
+ movi a0, 0
+ addi a1, a1, PT_REGS_OFFSET
+
+ movi a4, panic
+ movi a6, unrecoverable_text
+
+ callx4 a4
+
+1: j 1b
+
+
+/* -------------------------- FAST EXCEPTION HANDLERS ----------------------- */
+
+/*
+ * Fast-handler for alloca exceptions
+ *
+ * The ALLOCA handler is entered when user code executes the MOVSP
+ * instruction and the caller's frame is not in the register file.
+ * In this case, the caller frame's a0..a3 are on the stack just
+ * below sp (a1), and this handler moves them.
+ *
+ * For "MOVSP <ar>,<as>" without destination register a1, this routine
+ * simply moves the value from <as> to <ar> without moving the save area.
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+#if XCHAL_HAVE_BE
+#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 4, 4
+#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 0, 4
+#else
+#define _EXTUI_MOVSP_SRC(ar) extui ar, ar, 0, 4
+#define _EXTUI_MOVSP_DST(ar) extui ar, ar, 4, 4
+#endif
+
+ENTRY(fast_alloca)
+
+ /* We shouldn't be in a double exception. */
+
+ l32i a0, a2, PT_DEPC
+ _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, .Lunhandled_double
+
+ rsr a0, DEPC # get a2
+ s32i a4, a2, PT_AREG4 # save a4 and
+ s32i a0, a2, PT_AREG2 # a2 to stack
+
+ /* Exit critical section. */
+
+ movi a0, 0
+ s32i a0, a3, EXC_TABLE_FIXUP
+
+ /* Restore a3, excsave_1 */
+
+ xsr a3, EXCSAVE_1 # make sure excsave_1 is valid for dbl.
+ rsr a4, EPC_1 # get exception address
+ s32i a3, a2, PT_AREG3 # save a3 to stack
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error iram not supported
+#else
+ /* Note: l8ui not allowed in IRAM/IROM!! */
+ l8ui a0, a4, 1 # read as(src) from MOVSP instruction
+#endif
+ movi a3, .Lmovsp_src
+ _EXTUI_MOVSP_SRC(a0) # extract source register number
+ addx8 a3, a0, a3
+ jx a3
+
+.Lunhandled_double:
+ wsr a0, EXCSAVE_1
+ movi a0, unrecoverable_exception
+ callx0 a0
+
+ .align 8
+.Lmovsp_src:
+ l32i a3, a2, PT_AREG0; _j 1f; .align 8
+ mov a3, a1; _j 1f; .align 8
+ l32i a3, a2, PT_AREG2; _j 1f; .align 8
+ l32i a3, a2, PT_AREG3; _j 1f; .align 8
+ l32i a3, a2, PT_AREG4; _j 1f; .align 8
+ mov a3, a5; _j 1f; .align 8
+ mov a3, a6; _j 1f; .align 8
+ mov a3, a7; _j 1f; .align 8
+ mov a3, a8; _j 1f; .align 8
+ mov a3, a9; _j 1f; .align 8
+ mov a3, a10; _j 1f; .align 8
+ mov a3, a11; _j 1f; .align 8
+ mov a3, a12; _j 1f; .align 8
+ mov a3, a13; _j 1f; .align 8
+ mov a3, a14; _j 1f; .align 8
+ mov a3, a15; _j 1f; .align 8
+
+1:
+
+#ifdef ALLOCA_EXCEPTION_IN_IRAM
+#error iram not supported
+#else
+ l8ui a0, a4, 0 # read ar(dst) from MOVSP instruction
+#endif
+ addi a4, a4, 3 # step over movsp
+ _EXTUI_MOVSP_DST(a0) # extract destination register
+ wsr a4, EPC_1 # save new epc_1
+
+ _bnei a0, 1, 1f # no 'movsp a1, ax': jump
+
+ /* Move the save area. This implies the use of the L32E
+ * and S32E instructions, because this move must be done with
+ * the user's PS.RING privilege levels, not with ring 0
+ * (kernel's) privileges currently active with PS.EXCM
+ * set. Note that we have stil registered a fixup routine with the
+ * double exception vector in case a double exception occurs.
+ */
+
+ /* a0,a4:avail a1:old user stack a2:exc. stack a3:new user stack. */
+
+ l32e a0, a1, -16
+ l32e a4, a1, -12
+ s32e a0, a3, -16
+ s32e a4, a3, -12
+ l32e a0, a1, -8
+ l32e a4, a1, -4
+ s32e a0, a3, -8
+ s32e a4, a3, -4
+
+ /* Restore stack-pointer and all the other saved registers. */
+
+ mov a1, a3
+
+ l32i a4, a2, PT_AREG4
+ l32i a3, a2, PT_AREG3
+ l32i a0, a2, PT_AREG0
+ l32i a2, a2, PT_AREG2
+ rfe
+
+ /* MOVSP <at>,<as> was invoked with <at> != a1.
+ * Because the stack pointer is not being modified,
+ * we should be able to just modify the pointer
+ * without moving any save area.
+ * The processor only traps these occurrences if the
+ * caller window isn't live, so unfortunately we can't
+ * use this as an alternate trap mechanism.
+ * So we just do the move. This requires that we
+ * resolve the destination register, not just the source,
+ * so there's some extra work.
+ * (PERHAPS NOT REALLY NEEDED, BUT CLEANER...)
+ */
+
+ /* a0 dst-reg, a1 user-stack, a2 stack, a3 value of src reg. */
+
+1: movi a4, .Lmovsp_dst
+ addx8 a4, a0, a4
+ jx a4
+
+ .align 8
+.Lmovsp_dst:
+ s32i a3, a2, PT_AREG0; _j 1f; .align 8
+ mov a1, a3; _j 1f; .align 8
+ s32i a3, a2, PT_AREG2; _j 1f; .align 8
+ s32i a3, a2, PT_AREG3; _j 1f; .align 8
+ s32i a3, a2, PT_AREG4; _j 1f; .align 8
+ mov a5, a3; _j 1f; .align 8
+ mov a6, a3; _j 1f; .align 8
+ mov a7, a3; _j 1f; .align 8
+ mov a8, a3; _j 1f; .align 8
+ mov a9, a3; _j 1f; .align 8
+ mov a10, a3; _j 1f; .align 8
+ mov a11, a3; _j 1f; .align 8
+ mov a12, a3; _j 1f; .align 8
+ mov a13, a3; _j 1f; .align 8
+ mov a14, a3; _j 1f; .align 8
+ mov a15, a3; _j 1f; .align 8
+
+1: l32i a4, a2, PT_AREG4
+ l32i a3, a2, PT_AREG3
+ l32i a0, a2, PT_AREG0
+ l32i a2, a2, PT_AREG2
+ rfe
+
+
+/*
+ * fast system calls.
+ *
+ * WARNING: The kernel doesn't save the entire user context before
+ * handling a fast system call. These functions are small and short,
+ * usually offering some functionality not available to user tasks.
+ *
+ * BE CAREFUL TO PRESERVE THE USER'S CONTEXT.
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ */
+
+ENTRY(fast_syscall_kernel)
+
+ /* Skip syscall. */
+
+ rsr a0, EPC_1
+ addi a0, a0, 3
+ wsr a0, EPC_1
+
+ l32i a0, a2, PT_DEPC
+ bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+ rsr a0, DEPC # get syscall-nr
+ _beqz a0, fast_syscall_spill_registers
+
+ addi a0, a0, -__NR_sysxtensa
+ _beqz a0, fast_syscall_sysxtensa
+
+ j kernel_exception
+
+
+ENTRY(fast_syscall_user)
+
+ /* Skip syscall. */
+
+ rsr a0, EPC_1
+ addi a0, a0, 3
+ wsr a0, EPC_1
+
+ l32i a0, a2, PT_DEPC
+ bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_syscall_unrecoverable
+
+ rsr a0, DEPC # get syscall-nr
+ _beqz a0, fast_syscall_spill_registers
+
+ addi a0, a0, -__NR_sysxtensa
+ _beqz a0, fast_syscall_sysxtensa
+
+ j user_exception
+
+ENTRY(fast_syscall_unrecoverable)
+
+ /* Restore all states. */
+
+ l32i a0, a2, PT_AREG0 # restore a0
+ xsr a2, DEPC # restore a2, depc
+ rsr a3, EXCSAVE_1
+
+ wsr a0, EXCSAVE_1
+ movi a0, unrecoverable_exception
+ callx0 a0
+
+
+
+/*
+ * sysxtensa syscall handler
+ *
+ * int sysxtensa (XTENSA_ATOMIC_SET, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_EXG_ADD, ptr, val, unused);
+ * int sysxtensa (XTENSA_ATOMIC_CMP_SWP, ptr, oldval, newval);
+ * a2 a6 a3 a4 a5
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note: we don't have to save a2; a2 holds the return value
+ *
+ * We use the two macros TRY and CATCH:
+ *
+ * TRY adds an entry to the __ex_table fixup table for the immediately
+ * following instruction.
+ *
+ * CATCH catches any exception that occurred at one of the preceeding TRY
+ * statements and continues from there
+ *
+ * Usage TRY l32i a0, a1, 0
+ * <other code>
+ * done: rfe
+ * CATCH <set return code>
+ * j done
+ */
+
+#define TRY \
+ .section __ex_table, "a"; \
+ .word 66f, 67f; \
+ .text; \
+66:
+
+#define CATCH \
+67:
+
+ENTRY(fast_syscall_sysxtensa)
+
+ _beqz a6, 1f
+ _blti a6, SYSXTENSA_COUNT, 2f
+
+1: j user_exception
+
+2: xsr a3, EXCSAVE_1 # restore a3, excsave1
+ s32i a7, a2, PT_AREG7
+
+ movi a7, 4 # sizeof(unsigned int)
+ verify_area a3, a7, a0, a2, .Leac
+
+ _beqi a6, SYSXTENSA_ATOMIC_SET, .Lset
+ _beqi a6, SYSXTENSA_ATOMIC_EXG_ADD, .Lexg
+ _beqi a6, SYSXTENSA_ATOMIC_ADD, .Ladd
+
+ /* Fall through for SYSXTENSA_ATOMIC_CMP_SWP */
+
+.Lswp: /* Atomic compare and swap */
+
+TRY l32i a7, a3, 0 # read old value
+ bne a7, a4, 1f # same as old value? jump
+ s32i a5, a3, 0 # different, modify value
+ movi a7, 1 # and return 1
+ j .Lret
+
+1: movi a7, 0 # same values: return 0
+ j .Lret
+
+.Ladd: /* Atomic add */
+.Lexg: /* Atomic (exchange) add */
+
+TRY l32i a7, a3, 0
+ add a4, a4, a7
+ s32i a4, a3, 0
+ j .Lret
+
+.Lset: /* Atomic set */
+
+TRY l32i a7, a3, 0 # read old value as return value
+ s32i a4, a3, 0 # write new value
+
+.Lret: mov a0, a2
+ mov a2, a7
+ l32i a7, a0, PT_AREG7
+ l32i a3, a0, PT_AREG3
+ l32i a0, a0, PT_AREG0
+ rfe
+
+CATCH
+.Leac: movi a7, -EFAULT
+ j .Lret
+
+
+
+/* fast_syscall_spill_registers.
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * Note: We assume the stack pointer is EXC_TABLE_KSTK in the fixup handler.
+ * Note: We don't need to save a2 in depc (return value)
+ */
+
+ENTRY(fast_syscall_spill_registers)
+
+ /* Register a FIXUP handler (pass current wb as a parameter) */
+
+ movi a0, fast_syscall_spill_registers_fixup
+ s32i a0, a3, EXC_TABLE_FIXUP
+ rsr a0, WINDOWBASE
+ s32i a0, a3, EXC_TABLE_PARAM
+
+ /* Save a3 and SAR on stack. */
+
+ rsr a0, SAR
+ xsr a3, EXCSAVE_1 # restore a3 and excsave_1
+ s32i a0, a2, PT_AREG4 # store SAR to PT_AREG4
+ s32i a3, a2, PT_AREG3
+
+ /* The spill routine might clobber a7, a11, and a15. */
+
+ s32i a7, a2, PT_AREG5
+ s32i a11, a2, PT_AREG6
+ s32i a15, a2, PT_AREG7
+
+ call0 _spill_registers # destroys a3, DEPC, and SAR
+
+ /* Advance PC, restore registers and SAR, and return from exception. */
+
+ l32i a3, a2, PT_AREG4
+ l32i a0, a2, PT_AREG0
+ wsr a3, SAR
+ l32i a3, a2, PT_AREG3
+
+ /* Restore clobbered registers. */
+
+ l32i a7, a2, PT_AREG5
+ l32i a11, a2, PT_AREG6
+ l32i a15, a2, PT_AREG7
+
+ movi a2, 0
+ rfe
+
+/* Fixup handler.
+ *
+ * We get here if the spill routine causes an exception, e.g. tlb miss.
+ * We basically restore WINDOWBASE and WINDOWSTART to the condition when
+ * we entered the spill routine and jump to the user exception handler.
+ *
+ * a0: value of depc, original value in depc
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_SAVE
+ * a3: exctable, original value in excsave1
+ */
+
+fast_syscall_spill_registers_fixup:
+
+ rsr a2, WINDOWBASE # get current windowbase (a2 is saved)
+ xsr a0, DEPC # restore depc and a0
+ ssl a2 # set shift (32 - WB)
+
+ /* We need to make sure the current registers (a0-a3) are preserved.
+ * To do this, we simply set the bit for the current window frame
+ * in WS, so that the exception handlers save them to the task stack.
+ */
+
+ rsr a3, EXCSAVE_1 # get spill-mask
+ slli a2, a3, 1 # shift left by one
+
+ slli a3, a2, 32-WSBITS
+ src a2, a2, a3 # a1 = xxwww1yyxxxwww1yy......
+ wsr a2, WINDOWSTART # set corrected windowstart
+
+ movi a3, exc_table
+ l32i a2, a3, EXC_TABLE_DOUBLE_SAVE # restore a2
+ l32i a3, a3, EXC_TABLE_PARAM # original WB (in user task)
+
+ /* Return to the original (user task) WINDOWBASE.
+ * We leave the following frame behind:
+ * a0, a1, a2 same
+ * a3: trashed (saved in excsave_1)
+ * depc: depc (we have to return to that address)
+ * excsave_1: a3
+ */
+
+ wsr a3, WINDOWBASE
+ rsync
+
+ /* We are now in the original frame when we entered _spill_registers:
+ * a0: return address
+ * a1: used, stack pointer
+ * a2: kernel stack pointer
+ * a3: available, saved in EXCSAVE_1
+ * depc: exception address
+ * excsave: a3
+ * Note: This frame might be the same as above.
+ */
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+ /* Restore registers we precautiously saved.
+ * We have the value of the 'right' a3
+ */
+
+ l32i a7, a2, PT_AREG5
+ l32i a11, a2, PT_AREG6
+ l32i a15, a2, PT_AREG7
+#endif
+
+ /* Setup stack pointer. */
+
+ addi a2, a2, -PT_USER_SIZE
+ s32i a0, a2, PT_AREG0
+
+ /* Make sure we return to this fixup handler. */
+
+ movi a3, fast_syscall_spill_registers_fixup_return
+ s32i a3, a2, PT_DEPC # setup depc
+
+ /* Jump to the exception handler. */
+
+ movi a3, exc_table
+ rsr a0, EXCCAUSE
+ addx4 a0, a0, a3 # find entry in table
+ l32i a0, a0, EXC_TABLE_FAST_USER # load handler
+ jx a0
+
+fast_syscall_spill_registers_fixup_return:
+
+ /* When we return here, all registers have been restored (a2: DEPC) */
+
+ wsr a2, DEPC # exception address
+
+ /* Restore fixup handler. */
+
+ xsr a3, EXCSAVE_1
+ movi a2, fast_syscall_spill_registers_fixup
+ s32i a2, a3, EXC_TABLE_FIXUP
+ rsr a2, WINDOWBASE
+ s32i a2, a3, EXC_TABLE_PARAM
+ l32i a2, a3, EXC_TABLE_KSTK
+
+#ifdef SIGNAL_HANDLING_IN_DOUBLE_EXCEPTION
+ /* Save registers again that might be clobbered. */
+
+ s32i a7, a2, PT_AREG5
+ s32i a11, a2, PT_AREG6
+ s32i a15, a2, PT_AREG7
+#endif
+
+ /* Load WB at the time the exception occurred. */
+
+ rsr a3, SAR # WB is still in SAR
+ neg a3, a3
+ wsr a3, WINDOWBASE
+ rsync
+
+ /* Restore a3 and return. */
+
+ movi a3, exc_table
+ xsr a3, EXCSAVE_1
+
+ rfde
+
+
+/*
+ * spill all registers.
+ *
+ * This is not a real function. The following conditions must be met:
+ *
+ * - must be called with call0.
+ * - uses DEPC, a3 and SAR.
+ * - the last 'valid' register of each frame are clobbered.
+ * - the caller must have registered a fixup handler
+ * (or be inside a critical section)
+ * - PS_EXCM must be set (PS_WOE cleared?)
+ */
+
+ENTRY(_spill_registers)
+
+ /*
+ * Rotate ws so that the current windowbase is at bit 0.
+ * Assume ws = xxxwww1yy (www1 current window frame).
+ * Rotate ws right so that a2 = yyxxxwww1.
+ */
+
+ wsr a2, DEPC # preserve a2
+ rsr a2, WINDOWBASE
+ rsr a3, WINDOWSTART
+ ssr a2 # holds WB
+ slli a2, a3, WSBITS
+ or a3, a3, a2 # a2 = xxxwww1yyxxxwww1yy
+ srl a3, a3
+
+ /* We are done if there are no more than the current register frame. */
+
+ extui a3, a3, 1, WSBITS-2 # a3 = 0yyxxxwww
+ movi a2, (1 << (WSBITS-1))
+ _beqz a3, .Lnospill # only one active frame? jump
+
+ /* We want 1 at the top, so that we return to the current windowbase */
+
+ or a3, a3, a2 # 1yyxxxwww
+
+ /* Skip empty frames - get 'oldest' WINDOWSTART-bit. */
+
+ wsr a3, WINDOWSTART # save shifted windowstart
+ neg a2, a3
+ and a3, a2, a3 # first bit set from right: 000010000
+
+ ffs_ws a2, a3 # a2: shifts to skip empty frames
+ movi a3, WSBITS
+ sub a2, a3, a2 # WSBITS-a2:number of 0-bits from right
+ ssr a2 # save in SAR for later.
+
+ rsr a3, WINDOWBASE
+ add a3, a3, a2
+ rsr a2, DEPC # restore a2
+ wsr a3, WINDOWBASE
+ rsync
+
+ rsr a3, WINDOWSTART
+ srl a3, a3 # shift windowstart
+
+ /* WB is now just one frame below the oldest frame in the register
+ window. WS is shifted so the oldest frame is in bit 0, thus, WB
+ and WS differ by one 4-register frame. */
+
+ /* Save frames. Depending what call was used (call4, call8, call12),
+ * we have to save 4,8. or 12 registers.
+ */
+
+ _bbsi.l a3, 1, .Lc4
+ _bbsi.l a3, 2, .Lc8
+
+ /* Special case: we have a call12-frame starting at a4. */
+
+ _bbci.l a3, 3, .Lc12 # bit 3 shouldn't be zero! (Jump to Lc12 first)
+
+ s32e a4, a1, -16 # a1 is valid with an empty spill area
+ l32e a4, a5, -12
+ s32e a8, a4, -48
+ mov a8, a4
+ l32e a4, a1, -16
+ j .Lc12c
+
+.Lloop: _bbsi.l a3, 1, .Lc4
+ _bbci.l a3, 2, .Lc12
+
+.Lc8: s32e a4, a13, -16
+ l32e a4, a5, -12
+ s32e a8, a4, -32
+ s32e a5, a13, -12
+ s32e a6, a13, -8
+ s32e a7, a13, -4
+ s32e a9, a4, -28
+ s32e a10, a4, -24
+ s32e a11, a4, -20
+
+ srli a11, a3, 2 # shift windowbase by 2
+ rotw 2
+ _bnei a3, 1, .Lloop
+
+.Lexit: /* Done. Do the final rotation, set WS, and return. */
+
+ rotw 1
+ rsr a3, WINDOWBASE
+ ssl a3
+ movi a3, 1
+ sll a3, a3
+ wsr a3, WINDOWSTART
+
+.Lnospill:
+ jx a0
+
+.Lc4: s32e a4, a9, -16
+ s32e a5, a9, -12
+ s32e a6, a9, -8
+ s32e a7, a9, -4
+
+ srli a7, a3, 1
+ rotw 1
+ _bnei a3, 1, .Lloop
+ j .Lexit
+
+.Lc12: _bbci.l a3, 3, .Linvalid_mask # bit 2 shouldn't be zero!
+
+ /* 12-register frame (call12) */
+
+ l32e a2, a5, -12
+ s32e a8, a2, -48
+ mov a8, a2
+
+.Lc12c: s32e a9, a8, -44
+ s32e a10, a8, -40
+ s32e a11, a8, -36
+ s32e a12, a8, -32
+ s32e a13, a8, -28
+ s32e a14, a8, -24
+ s32e a15, a8, -20
+ srli a15, a3, 3
+
+ /* The stack pointer for a4..a7 is out of reach, so we rotate the
+ * window, grab the stackpointer, and rotate back.
+ * Alternatively, we could also use the following approach, but that
+ * makes the fixup routine much more complicated:
+ * rotw 1
+ * s32e a0, a13, -16
+ * ...
+ * rotw 2
+ */
+
+ rotw 1
+ mov a5, a13
+ rotw -1
+
+ s32e a4, a9, -16
+ s32e a5, a9, -12
+ s32e a6, a9, -8
+ s32e a7, a9, -4
+
+ rotw 3
+
+ _beqi a3, 1, .Lexit
+ j .Lloop
+
+.Linvalid_mask:
+
+ /* We get here because of an unrecoverable error in the window
+ * registers. If we are in user space, we kill the application,
+ * however, this condition is unrecoverable in kernel space.
+ */
+
+ rsr a0, PS
+ _bbci.l a0, PS_UM_SHIFT, 1f
+
+ /* User space: Setup a dummy frame and kill application.
+ * Note: We assume EXC_TABLE_KSTK contains a valid stack pointer.
+ */
+
+ movi a0, 1
+ movi a1, 0
+
+ wsr a0, WINDOWSTART
+ wsr a1, WINDOWBASE
+ rsync
+
+ movi a0, 0
+
+ movi a3, exc_table
+ l32i a1, a3, EXC_TABLE_KSTK
+ wsr a3, EXCSAVE_1
+
+ movi a4, PS_WOE_MASK | 1
+ wsr a4, PS
+ rsync
+
+ movi a6, SIGSEGV
+ movi a4, do_exit
+ callx4 a4
+
+1: /* Kernel space: PANIC! */
+
+ wsr a0, EXCSAVE_1
+ movi a0, unrecoverable_exception
+ callx0 a0 # should not return
+1: j 1b
+
+/*
+ * We should never get here. Bail out!
+ */
+
+ENTRY(fast_second_level_miss_double_kernel)
+
+1: movi a0, unrecoverable_exception
+ callx0 a0 # should not return
+1: j 1b
+
+/* First-level entry handler for user, kernel, and double 2nd-level
+ * TLB miss exceptions. Note that for now, user and kernel miss
+ * exceptions share the same entry point and are handled identically.
+ *
+ * An old, less-efficient C version of this function used to exist.
+ * We include it below, interleaved as comments, for reference.
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_second_level_miss)
+
+ /* Save a1. Note: we don't expect a double exception. */
+
+ s32i a1, a2, PT_AREG1
+
+ /* We need to map the page of PTEs for the user task. Find
+ * the pointer to that page. Also, it's possible for tsk->mm
+ * to be NULL while tsk->active_mm is nonzero if we faulted on
+ * a vmalloc address. In that rare case, we must use
+ * active_mm instead to avoid a fault in this handler. See
+ *
+ * http://mail.nl.linux.org/linux-mm/2002-08/msg00258.html
+ * (or search Internet on "mm vs. active_mm")
+ *
+ * if (!mm)
+ * mm = tsk->active_mm;
+ * pgd = pgd_offset (mm, regs->excvaddr);
+ * pmd = pmd_offset (pgd, regs->excvaddr);
+ * pmdval = *pmd;
+ */
+
+ GET_CURRENT(a1,a2)
+ l32i a0, a1, TASK_MM # tsk->mm
+ beqz a0, 9f
+
+8: rsr a1, EXCVADDR # fault address
+ _PGD_OFFSET(a0, a1, a1)
+ l32i a0, a0, 0 # read pmdval
+ //beqi a0, _PAGE_USER, 2f
+ beqz a0, 2f
+
+ /* Read ptevaddr and convert to top of page-table page.
+ *
+ * vpnval = read_ptevaddr_register() & PAGE_MASK;
+ * vpnval += DTLB_WAY_PGTABLE;
+ * pteval = mk_pte (virt_to_page(pmd_val(pmdval)), PAGE_KERNEL);
+ * write_dtlb_entry (pteval, vpnval);
+ *
+ * The messy computation for 'pteval' above really simplifies
+ * into the following:
+ *
+ * pteval = ((pmdval - PAGE_OFFSET) & PAGE_MASK) | PAGE_KERNEL
+ */
+
+ movi a1, -PAGE_OFFSET
+ add a0, a0, a1 # pmdval - PAGE_OFFSET
+ extui a1, a0, 0, PAGE_SHIFT # ... & PAGE_MASK
+ xor a0, a0, a1
+
+
+ movi a1, PAGE_DIRECTORY
+ or a0, a0, a1 # ... | PAGE_DIRECTORY
+
+ rsr a1, PTEVADDR
+ srli a1, a1, PAGE_SHIFT
+ slli a1, a1, PAGE_SHIFT # ptevaddr & PAGE_MASK
+ addi a1, a1, DTLB_WAY_PGTABLE # ... + way_number
+
+ wdtlb a0, a1
+ dsync
+
+ /* Exit critical section. */
+
+ movi a0, 0
+ s32i a0, a3, EXC_TABLE_FIXUP
+
+ /* Restore the working registers, and return. */
+
+ l32i a0, a2, PT_AREG0
+ l32i a1, a2, PT_AREG1
+ l32i a2, a2, PT_DEPC
+ xsr a3, EXCSAVE_1
+
+ bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+ /* Restore excsave1 and return. */
+
+ rsr a2, DEPC
+ rfe
+
+ /* Return from double exception. */
+
+1: xsr a2, DEPC
+ esync
+ rfde
+
+9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
+ j 8b
+
+2: /* Invalid PGD, default exception handling */
+
+ rsr a1, DEPC
+ xsr a3, EXCSAVE_1
+ s32i a1, a2, PT_AREG2
+ s32i a3, a2, PT_AREG3
+ mov a1, a2
+
+ rsr a2, PS
+ bbsi.l a2, PS_UM_SHIFT, 1f
+ j _kernel_exception
+1: j _user_exception
+
+
+/*
+ * StoreProhibitedException
+ *
+ * Update the pte and invalidate the itlb mapping for this pte.
+ *
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_store_prohibited)
+
+ /* Save a1 and a4. */
+
+ s32i a1, a2, PT_AREG1
+ s32i a4, a2, PT_AREG4
+
+ GET_CURRENT(a1,a2)
+ l32i a0, a1, TASK_MM # tsk->mm
+ beqz a0, 9f
+
+8: rsr a1, EXCVADDR # fault address
+ _PGD_OFFSET(a0, a1, a4)
+ l32i a0, a0, 0
+ //beqi a0, _PAGE_USER, 2f # FIXME use _PAGE_INVALID
+ beqz a0, 2f
+
+ _PTE_OFFSET(a0, a1, a4)
+ l32i a4, a0, 0 # read pteval
+ movi a1, _PAGE_VALID | _PAGE_RW
+ bnall a4, a1, 2f
+
+ movi a1, _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_WRENABLE
+ or a4, a4, a1
+ rsr a1, EXCVADDR
+ s32i a4, a0, 0
+
+ /* We need to flush the cache if we have page coloring. */
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+ dhwb a0, 0
+#endif
+ pdtlb a0, a1
+ beqz a0, 1f
+ idtlb a0 // FIXME do we need this?
+ wdtlb a4, a0
+1:
+
+ /* Exit critical section. */
+
+ movi a0, 0
+ s32i a0, a3, EXC_TABLE_FIXUP
+
+ /* Restore the working registers, and return. */
+
+ l32i a4, a2, PT_AREG4
+ l32i a1, a2, PT_AREG1
+ l32i a0, a2, PT_AREG0
+ l32i a2, a2, PT_DEPC
+
+ /* Restore excsave1 and a3. */
+
+ xsr a3, EXCSAVE_1
+ bgeui a2, VALID_DOUBLE_EXCEPTION_ADDRESS, 1f
+
+ rsr a2, DEPC
+ rfe
+
+ /* Double exception. Restore FIXUP handler and return. */
+
+1: xsr a2, DEPC
+ esync
+ rfde
+
+9: l32i a0, a1, TASK_ACTIVE_MM # unlikely case mm == 0
+ j 8b
+
+2: /* If there was a problem, handle fault in C */
+
+ rsr a4, DEPC # still holds a2
+ xsr a3, EXCSAVE_1
+ s32i a4, a2, PT_AREG2
+ s32i a3, a2, PT_AREG3
+ l32i a4, a2, PT_AREG4
+ mov a1, a2
+
+ rsr a2, PS
+ bbsi.l a2, PS_UM_SHIFT, 1f
+ j _kernel_exception
+1: j _user_exception
+
+
+#if XCHAL_EXTRA_SA_SIZE
+
+#warning fast_coprocessor untested
+
+/*
+ * Entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original in DEPC
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ */
+
+ENTRY(fast_coprocessor_double)
+ wsr a0, EXCSAVE_1
+ movi a0, unrecoverable_exception
+ callx0 a0
+
+ENTRY(fast_coprocessor)
+
+ /* Fatal if we are in a double exception. */
+
+ l32i a0, a2, PT_DEPC
+ _bgeui a0, VALID_DOUBLE_EXCEPTION_ADDRESS, fast_coprocessor_double
+
+ /* Save some registers a1, a3, a4, SAR */
+
+ xsr a3, EXCSAVE_1
+ s32i a3, a2, PT_AREG3
+ rsr a3, SAR
+ s32i a4, a2, PT_AREG4
+ s32i a1, a2, PT_AREG1
+ s32i a5, a1, PT_AREG5
+ s32i a3, a2, PT_SAR
+ mov a1, a2
+
+ /* Currently, the HAL macros only guarantee saving a0 and a1.
+ * These can and will be refined in the future, but for now,
+ * just save the remaining registers of a2...a15.
+ */
+ s32i a6, a1, PT_AREG6
+ s32i a7, a1, PT_AREG7
+ s32i a8, a1, PT_AREG8
+ s32i a9, a1, PT_AREG9
+ s32i a10, a1, PT_AREG10
+ s32i a11, a1, PT_AREG11
+ s32i a12, a1, PT_AREG12
+ s32i a13, a1, PT_AREG13
+ s32i a14, a1, PT_AREG14
+ s32i a15, a1, PT_AREG15
+
+ /* Find coprocessor number. Subtract first CP EXCCAUSE from EXCCAUSE */
+
+ rsr a0, EXCCAUSE
+ addi a3, a0, -XCHAL_EXCCAUSE_COPROCESSOR0_DISABLED
+
+ /* Set corresponding CPENABLE bit */
+
+ movi a4, 1
+ ssl a3 # SAR: 32 - coprocessor_number
+ rsr a5, CPENABLE
+ sll a4, a4
+ or a4, a5, a4
+ wsr a4, CPENABLE
+ rsync
+ movi a5, coprocessor_info # list of owner and offset into cp_save
+ addx8 a0, a4, a5 # entry for CP
+
+ bne a4, a5, .Lload # bit wasn't set before, cp not in use
+
+ /* Now compare the current task with the owner of the coprocessor.
+ * If they are the same, there is no reason to save or restore any
+ * coprocessor state. Having already enabled the coprocessor,
+ * branch ahead to return.
+ */
+ GET_CURRENT(a5,a1)
+ l32i a4, a0, COPROCESSOR_INFO_OWNER # a4: current owner for this CP
+ beq a4, a5, .Ldone
+
+ /* Find location to dump current coprocessor state:
+ * task_struct->task_cp_save_offset + coprocessor_offset[coprocessor]
+ *
+ * Note: a0 pointer to the entry in the coprocessor owner table,
+ * a3 coprocessor number,
+ * a4 current owner of coprocessor.
+ */
+ l32i a5, a0, COPROCESSOR_INFO_OFFSET
+ addi a2, a4, THREAD_CP_SAVE
+ add a2, a2, a5
+
+ /* Store current coprocessor states. (a5 still has CP number) */
+
+ xchal_cpi_store_funcbody
+
+ /* The macro might have destroyed a3 (coprocessor number), but
+ * SAR still has 32 - coprocessor_number!
+ */
+ movi a3, 32
+ rsr a4, SAR
+ sub a3, a3, a4
+
+.Lload: /* A new task now owns the corpocessors. Save its TCB pointer into
+ * the coprocessor owner table.
+ *
+ * Note: a0 pointer to the entry in the coprocessor owner table,
+ * a3 coprocessor number.
+ */
+ GET_CURRENT(a4,a1)
+ s32i a4, a0, 0
+
+ /* Find location from where to restore the current coprocessor state.*/
+
+ l32i a5, a0, COPROCESSOR_INFO_OFFSET
+ addi a2, a4, THREAD_CP_SAVE
+ add a2, a2, a4
+
+ xchal_cpi_load_funcbody
+
+ /* We must assume that the xchal_cpi_store_funcbody macro destroyed
+ * registers a2..a15.
+ */
+
+.Ldone: l32i a15, a1, PT_AREG15
+ l32i a14, a1, PT_AREG14
+ l32i a13, a1, PT_AREG13
+ l32i a12, a1, PT_AREG12
+ l32i a11, a1, PT_AREG11
+ l32i a10, a1, PT_AREG10
+ l32i a9, a1, PT_AREG9
+ l32i a8, a1, PT_AREG8
+ l32i a7, a1, PT_AREG7
+ l32i a6, a1, PT_AREG6
+ l32i a5, a1, PT_AREG5
+ l32i a4, a1, PT_AREG4
+ l32i a3, a1, PT_AREG3
+ l32i a2, a1, PT_AREG2
+ l32i a0, a1, PT_AREG0
+ l32i a1, a1, PT_AREG1
+
+ rfe
+
+#endif /* XCHAL_EXTRA_SA_SIZE */
+
+/*
+ * Task switch.
+ *
+ * struct task* _switch_to (struct task* prev, struct task* next)
+ * a2 a2 a3
+ */
+
+ENTRY(_switch_to)
+
+ entry a1, 16
+
+ mov a4, a3 # preserve a3
+
+ s32i a0, a2, THREAD_RA # save return address
+ s32i a1, a2, THREAD_SP # save stack pointer
+
+ /* Disable ints while we manipulate the stack pointer; spill regs. */
+
+ movi a5, PS_EXCM_MASK | LOCKLEVEL
+ xsr a5, PS
+ rsr a3, EXCSAVE_1
+ rsync
+ s32i a3, a3, EXC_TABLE_FIXUP /* enter critical section */
+
+ call0 _spill_registers
+
+ /* Set kernel stack (and leave critical section)
+ * Note: It's save to set it here. The stack will not be overwritten
+ * because the kernel stack will only be loaded again after
+ * we return from kernel space.
+ */
+
+ l32i a0, a4, TASK_THREAD_INFO
+ rsr a3, EXCSAVE_1 # exc_table
+ movi a1, 0
+ addi a0, a0, PT_REGS_OFFSET
+ s32i a1, a3, EXC_TABLE_FIXUP
+ s32i a0, a3, EXC_TABLE_KSTK
+
+ /* restore context of the task that 'next' addresses */
+
+ l32i a0, a4, THREAD_RA /* restore return address */
+ l32i a1, a4, THREAD_SP /* restore stack pointer */
+
+ wsr a5, PS
+ rsync
+
+ retw
+
+
+ENTRY(ret_from_fork)
+
+ /* void schedule_tail (struct task_struct *prev)
+ * Note: prev is still in a6 (return value from fake call4 frame)
+ */
+ movi a4, schedule_tail
+ callx4 a4
+
+ movi a4, do_syscall_trace
+ callx4 a4
+
+ j common_exception_return
+
+
+
+/*
+ * Table of syscalls
+ */
+
+.data
+.align 4
+.global sys_call_table
+sys_call_table:
+
+#define SYSCALL(call, narg) .word call
+#include "syscalls.h"
+
+/*
+ * Number of arguments of each syscall
+ */
+
+.global sys_narg_table
+sys_narg_table:
+
+#undef SYSCALL
+#define SYSCALL(call, narg) .byte narg
+#include "syscalls.h"
+
diff --git a/arch/xtensa/kernel/head.S b/arch/xtensa/kernel/head.S
new file mode 100644
index 000000000000..6e9b5225b8f6
--- /dev/null
+++ b/arch/xtensa/kernel/head.S
@@ -0,0 +1,237 @@
+/*
+ * arch/xtensa/kernel/head.S
+ *
+ * Xtensa Processor startup code.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ */
+
+#include <xtensa/cacheasm.h>
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/*
+ * This module contains the entry code for kernel images. It performs the
+ * minimal setup needed to call the generic C routines.
+ *
+ * Prerequisites:
+ *
+ * - The kernel image has been loaded to the actual address where it was
+ * compiled to.
+ * - a2 contains either 0 or a pointer to a list of boot parameters.
+ * (see setup.c for more details)
+ *
+ */
+
+ .macro iterate from, to , cmd
+ .ifeq ((\to - \from) & ~0xfff)
+ \cmd \from
+ iterate "(\from+1)", \to, \cmd
+ .endif
+ .endm
+
+/*
+ * _start
+ *
+ * The bootloader passes a pointer to a list of boot parameters in a2.
+ */
+
+ /* The first bytes of the kernel image must be an instruction, so we
+ * manually allocate and define the literal constant we need for a jx
+ * instruction.
+ */
+
+ .section .head.text, "ax"
+ .globl _start
+_start: _j 2f
+ .align 4
+1: .word _startup
+2: l32r a0, 1b
+ jx a0
+
+ .text
+ .align 4
+_startup:
+
+ /* Disable interrupts and exceptions. */
+
+ movi a0, XCHAL_PS_EXCM_MASK
+ wsr a0, PS
+
+ /* Preserve the pointer to the boot parameter list in EXCSAVE_1 */
+
+ wsr a2, EXCSAVE_1
+
+ /* Start with a fresh windowbase and windowstart. */
+
+ movi a1, 1
+ movi a0, 0
+ wsr a1, WINDOWSTART
+ wsr a0, WINDOWBASE
+ rsync
+
+ /* Set a0 to 0 for the remaining initialization. */
+
+ movi a0, 0
+
+ /* Clear debugging registers. */
+
+#if XCHAL_HAVE_DEBUG
+ wsr a0, IBREAKENABLE
+ wsr a0, ICOUNT
+ movi a1, 15
+ wsr a0, ICOUNTLEVEL
+
+ .macro reset_dbreak num
+ wsr a0, DBREAKC + \num
+ .endm
+
+ iterate 0, XCHAL_NUM_IBREAK-1, reset_dbreak
+#endif
+
+ /* Clear CCOUNT (not really necessary, but nice) */
+
+ wsr a0, CCOUNT # not really necessary, but nice
+
+ /* Disable zero-loops. */
+
+#if XCHAL_HAVE_LOOPS
+ wsr a0, LCOUNT
+#endif
+
+ /* Disable all timers. */
+
+ .macro reset_timer num
+ wsr a0, CCOMPARE_0 + \num
+ .endm
+ iterate 0, XCHAL_NUM_TIMERS-1, reset_timer
+
+ /* Interrupt initialization. */
+
+ movi a2, XCHAL_INTTYPE_MASK_SOFTWARE | XCHAL_INTTYPE_MASK_EXTERN_EDGE
+ wsr a0, INTENABLE
+ wsr a2, INTCLEAR
+
+ /* Disable coprocessors. */
+
+#if XCHAL_CP_NUM > 0
+ wsr a0, CPENABLE
+#endif
+
+ /* Set PS.INTLEVEL=1, PS.WOE=0, kernel stack, PS.EXCM=0
+ *
+ * Note: PS.EXCM must be cleared before using any loop
+ * instructions; otherwise, they are silently disabled, and
+ * at most one iteration of the loop is executed.
+ */
+
+ movi a1, 1
+ wsr a1, PS
+ rsync
+
+ /* Initialize the caches.
+ * Does not include flushing writeback d-cache.
+ * a6, a7 are just working registers (clobbered).
+ */
+
+ icache_reset a2, a3
+ dcache_reset a2, a3
+
+ /* Unpack data sections
+ *
+ * The linker script used to build the Linux kernel image
+ * creates a table located at __boot_reloc_table_start
+ * that contans the information what data needs to be unpacked.
+ *
+ * Uses a2-a7.
+ */
+
+ movi a2, __boot_reloc_table_start
+ movi a3, __boot_reloc_table_end
+
+1: beq a2, a3, 3f # no more entries?
+ l32i a4, a2, 0 # start destination (in RAM)
+ l32i a5, a2, 4 # end desination (in RAM)
+ l32i a6, a2, 8 # start source (in ROM)
+ addi a2, a2, 12 # next entry
+ beq a4, a5, 1b # skip, empty entry
+ beq a4, a6, 1b # skip, source and dest. are the same
+
+2: l32i a7, a6, 0 # load word
+ addi a6, a6, 4
+ s32i a7, a4, 0 # store word
+ addi a4, a4, 4
+ bltu a4, a5, 2b
+ j 1b
+
+3:
+ /* All code and initialized data segments have been copied.
+ * Now clear the BSS segment.
+ */
+
+ movi a2, _bss_start # start of BSS
+ movi a3, _bss_end # end of BSS
+
+1: addi a2, a2, 4
+ s32i a0, a2, 0
+ blt a2, a3, 1b
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+
+ /* After unpacking, flush the writeback cache to memory so the
+ * instructions/data are available.
+ */
+
+ dcache_writeback_all a2, a3
+#endif
+
+ /* Setup stack and enable window exceptions (keep irqs disabled) */
+
+ movi a1, init_thread_union
+ addi a1, a1, KERNEL_STACK_SIZE
+
+ movi a2, 0x00040001 # WOE=1, INTLEVEL=1, UM=0
+ wsr a2, PS # (enable reg-windows; progmode stack)
+ rsync
+
+ /* Set up EXCSAVE[DEBUGLEVEL] to point to the Debug Exception Handler.*/
+
+ movi a2, debug_exception
+ wsr a2, EXCSAVE + XCHAL_DEBUGLEVEL
+
+ /* Set up EXCSAVE[1] to point to the exc_table. */
+
+ movi a6, exc_table
+ xsr a6, EXCSAVE_1
+
+ /* init_arch kick-starts the linux kernel */
+
+ movi a4, init_arch
+ callx4 a4
+
+ movi a4, start_kernel
+ callx4 a4
+
+should_never_return:
+ j should_never_return
+
+ /* Define some common data structures here. We define them
+ * here in this assembly file due to their unusual alignment
+ * requirements.
+ */
+
+ .comm swapper_pg_dir,PAGE_SIZE,PAGE_SIZE
+ .comm empty_bad_page_table,PAGE_SIZE,PAGE_SIZE
+ .comm empty_bad_page,PAGE_SIZE,PAGE_SIZE
+ .comm empty_zero_page,PAGE_SIZE,PAGE_SIZE
+
diff --git a/arch/xtensa/kernel/irq.c b/arch/xtensa/kernel/irq.c
new file mode 100644
index 000000000000..4cbf6d91571f
--- /dev/null
+++ b/arch/xtensa/kernel/irq.c
@@ -0,0 +1,192 @@
+/*
+ * linux/arch/xtensa/kernel/irq.c
+ *
+ * Xtensa built-in interrupt controller and some generic functions copied
+ * from i386.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica, Inc.
+ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar
+ *
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/kernel_stat.h>
+
+#include <asm/uaccess.h>
+#include <asm/platform.h>
+
+static void enable_xtensa_irq(unsigned int irq);
+static void disable_xtensa_irq(unsigned int irq);
+static void mask_and_ack_xtensa(unsigned int irq);
+static void end_xtensa_irq(unsigned int irq);
+
+static unsigned int cached_irq_mask;
+
+atomic_t irq_err_count;
+
+/*
+ * 'what should we do if we get a hw irq event on an illegal vector'.
+ * each architecture has to answer this themselves.
+ */
+void ack_bad_irq(unsigned int irq)
+{
+ printk("unexpected IRQ trap at vector %02x\n", irq);
+}
+
+/*
+ * do_IRQ handles all normal device IRQ's (the special
+ * SMP cross-CPU interrupts have their own specific
+ * handlers).
+ */
+
+unsigned int do_IRQ(int irq, struct pt_regs *regs)
+{
+ irq_enter();
+
+#ifdef CONFIG_DEBUG_STACKOVERFLOW
+ /* Debugging check for stack overflow: is there less than 1KB free? */
+ {
+ unsigned long sp;
+
+ __asm__ __volatile__ ("mov %0, a1\n" : "=a" (sp));
+ sp &= THREAD_SIZE - 1;
+
+ if (unlikely(sp < (sizeof(thread_info) + 1024)))
+ printk("Stack overflow in do_IRQ: %ld\n",
+ sp - sizeof(struct thread_info));
+ }
+#endif
+
+ __do_IRQ(irq, regs);
+
+ irq_exit();
+
+ return 1;
+}
+
+/*
+ * 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; j<NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "CPU%d ",j);
+ seq_putc(p, '\n');
+ }
+
+ if (i < NR_IRQS) {
+ spin_lock_irqsave(&irq_desc[i].lock, flags);
+ action = irq_desc[i].action;
+ if (!action)
+ goto skip;
+ seq_printf(p, "%3d: ",i);
+#ifndef CONFIG_SMP
+ seq_printf(p, "%10u ", kstat_irqs(i));
+#else
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
+#endif
+ seq_printf(p, " %14s", irq_desc[i].handler->typename);
+ 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, "NMI: ");
+ for (j = 0; j < NR_CPUS; j++)
+ if (cpu_online(j))
+ seq_printf(p, "%10u ", nmi_count(j));
+ seq_putc(p, '\n');
+ seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
+ }
+ return 0;
+}
+/* shutdown is same as "disable" */
+#define shutdown_xtensa_irq disable_xtensa_irq
+
+static unsigned int startup_xtensa_irq(unsigned int irq)
+{
+ enable_xtensa_irq(irq);
+ return 0; /* never anything pending */
+}
+
+static struct hw_interrupt_type xtensa_irq_type = {
+ "Xtensa-IRQ",
+ startup_xtensa_irq,
+ shutdown_xtensa_irq,
+ enable_xtensa_irq,
+ disable_xtensa_irq,
+ mask_and_ack_xtensa,
+ end_xtensa_irq
+};
+
+static inline void mask_irq(unsigned int irq)
+{
+ cached_irq_mask &= ~(1 << irq);
+ set_sr (cached_irq_mask, INTENABLE);
+}
+
+static inline void unmask_irq(unsigned int irq)
+{
+ cached_irq_mask |= 1 << irq;
+ set_sr (cached_irq_mask, INTENABLE);
+}
+
+static void disable_xtensa_irq(unsigned int irq)
+{
+ unsigned long flags;
+ local_save_flags(flags);
+ mask_irq(irq);
+ local_irq_restore(flags);
+}
+
+static void enable_xtensa_irq(unsigned int irq)
+{
+ unsigned long flags;
+ local_save_flags(flags);
+ unmask_irq(irq);
+ local_irq_restore(flags);
+}
+
+static void mask_and_ack_xtensa(unsigned int irq)
+{
+ disable_xtensa_irq(irq);
+}
+
+static void end_xtensa_irq(unsigned int irq)
+{
+ enable_xtensa_irq(irq);
+}
+
+
+void __init init_IRQ(void)
+{
+ int i;
+
+ for (i=0; i < XTENSA_NR_IRQS; i++)
+ irq_desc[i].handler = &xtensa_irq_type;
+
+ cached_irq_mask = 0;
+
+ platform_init_irq();
+}
diff --git a/arch/xtensa/kernel/module.c b/arch/xtensa/kernel/module.c
new file mode 100644
index 000000000000..d1683cfa19a2
--- /dev/null
+++ b/arch/xtensa/kernel/module.c
@@ -0,0 +1,78 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Module 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) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/cache.h>
+
+LIST_HEAD(module_buf_list);
+
+void *module_alloc(unsigned long size)
+{
+ panic("module_alloc not implemented");
+}
+
+void module_free(struct module *mod, void *module_region)
+{
+ panic("module_free not implemented");
+}
+
+int module_frob_arch_sections(Elf32_Ehdr *hdr,
+ Elf32_Shdr *sechdrs,
+ char *secstrings,
+ struct module *me)
+{
+ panic("module_frob_arch_sections not implemented");
+}
+
+int apply_relocate(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *module)
+{
+ panic ("apply_relocate not implemented");
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs,
+ const char *strtab,
+ unsigned int symindex,
+ unsigned int relsec,
+ struct module *module)
+{
+ panic("apply_relocate_add not implemented");
+}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ panic ("module_finalize not implemented");
+}
+
+void module_arch_cleanup(struct module *mod)
+{
+ panic("module_arch_cleanup not implemented");
+}
+
+struct bug_entry *module_find_bug(unsigned long bugaddr)
+{
+ panic("module_find_bug not implemented");
+}
diff --git a/arch/xtensa/kernel/pci-dma.c b/arch/xtensa/kernel/pci-dma.c
new file mode 100644
index 000000000000..84fde258cf85
--- /dev/null
+++ b/arch/xtensa/kernel/pci-dma.c
@@ -0,0 +1,73 @@
+/*
+ * arch/xtensa/pci-dma.c
+ *
+ * DMA coherent memory allocation.
+ *
+ * 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.
+ *
+ * Copyright (C) 2002 - 2005 Tensilica Inc.
+ *
+ * Based on version for i386.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Note: We assume that the full memory space is always mapped to 'kseg'
+ * Otherwise we have to use page attributes (not implemented).
+ */
+
+void *
+dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp)
+{
+ void *ret;
+
+ /* ignore region speicifiers */
+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+ if (dev == NULL || (*dev->dma_mask < 0xffffffff))
+ gfp |= GFP_DMA;
+ ret = (void *)__get_free_pages(gfp, get_order(size));
+
+ if (ret != NULL) {
+ memset(ret, 0, size);
+ *handle = virt_to_bus(ret);
+ }
+ return (void*) BYPASS_ADDR((unsigned long)ret);
+}
+
+void dma_free_coherent(struct device *hwdev, size_t size,
+ void *vaddr, dma_addr_t dma_handle)
+{
+ free_pages(CACHED_ADDR((unsigned long)vaddr), get_order(size));
+}
+
+
+void consistent_sync(void *vaddr, size_t size, int direction)
+{
+ switch (direction) {
+ case PCI_DMA_NONE:
+ BUG();
+ case PCI_DMA_FROMDEVICE: /* invalidate only */
+ __invalidate_dcache_range((unsigned long)vaddr,
+ (unsigned long)size);
+ break;
+
+ case PCI_DMA_TODEVICE: /* writeback only */
+ case PCI_DMA_BIDIRECTIONAL: /* writeback and invalidate */
+ __flush_invalidate_dcache_range((unsigned long)vaddr,
+ (unsigned long)size);
+ break;
+ }
+}
diff --git a/arch/xtensa/kernel/pci.c b/arch/xtensa/kernel/pci.c
new file mode 100644
index 000000000000..09887c96e9a1
--- /dev/null
+++ b/arch/xtensa/kernel/pci.c
@@ -0,0 +1,478 @@
+/*
+ * arch/xtensa/pcibios.c
+ *
+ * PCI bios-type initialisation for PCI machines
+ *
+ * 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.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ *
+ * Based largely on work from Cort (ppc/kernel/pci.c)
+ * IO functions copied from sparc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/bootmem.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/platform.h>
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+/* PCI Controller */
+
+
+/*
+ * pcibios_alloc_controller
+ * pcibios_enable_device
+ * pcibios_fixups
+ * pcibios_align_resource
+ * pcibios_fixup_bus
+ * pcibios_setup
+ * pci_bus_add_device
+ * pci_mmap_page_range
+ */
+
+struct pci_controller* pci_ctrl_head;
+struct pci_controller** pci_ctrl_tail = &pci_ctrl_head;
+
+static int pci_bus_count;
+
+/*
+ * We need to avoid collisions with `mirrored' VGA ports
+ * and other strange ISA hardware, so we always want the
+ * addresses to be allocated in the 0x000-0x0ff region
+ * modulo 0x400.
+ *
+ * Why? Because some silly external IO cards only decode
+ * the low 10 bits of the IO address. The 0x00-0xff region
+ * is reserved for motherboard devices that decode all 16
+ * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
+ * 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,
+ unsigned long align)
+{
+ struct pci_dev *dev = data;
+
+ if (res->flags & IORESOURCE_IO) {
+ unsigned long start = res->start;
+
+ if (size > 0x100) {
+ printk(KERN_ERR "PCI: I/O Region %s/%d too large"
+ " (%ld bytes)\n", pci_name(dev),
+ dev->resource - res, size);
+ }
+
+ if (start & 0x300) {
+ start = (start + 0x3ff) & ~0x3ff;
+ res->start = start;
+ }
+ }
+}
+
+int
+pcibios_enable_resources(struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for(idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk (KERN_ERR "PCI: Device %s not available because "
+ "of resource collisions\n", pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (dev->resource[PCI_ROM_RESOURCE].start)
+ cmd |= PCI_COMMAND_MEMORY;
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ pci_name(dev), old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+ return 0;
+}
+
+struct pci_controller * __init pcibios_alloc_controller(void)
+{
+ struct pci_controller *pci_ctrl;
+
+ pci_ctrl = (struct pci_controller *)alloc_bootmem(sizeof(*pci_ctrl));
+ memset(pci_ctrl, 0, sizeof(struct pci_controller));
+
+ *pci_ctrl_tail = pci_ctrl;
+ pci_ctrl_tail = &pci_ctrl->next;
+
+ return pci_ctrl;
+}
+
+static int __init pcibios_init(void)
+{
+ struct pci_controller *pci_ctrl;
+ struct pci_bus *bus;
+ int next_busno = 0, i;
+
+ printk("PCI: Probing PCI hardware\n");
+
+ /* Scan all of the recorded PCI controllers. */
+ for (pci_ctrl = pci_ctrl_head; pci_ctrl; pci_ctrl = pci_ctrl->next) {
+ pci_ctrl->last_busno = 0xff;
+ bus = pci_scan_bus(pci_ctrl->first_busno, pci_ctrl->ops,
+ pci_ctrl);
+ if (pci_ctrl->io_resource.flags) {
+ unsigned long offs;
+
+ offs = (unsigned long)pci_ctrl->io_space.base;
+ pci_ctrl->io_resource.start += offs;
+ pci_ctrl->io_resource.end += offs;
+ bus->resource[0] = &pci_ctrl->io_resource;
+ }
+ for (i = 0; i < 3; ++i)
+ if (pci_ctrl->mem_resources[i].flags)
+ bus->resource[i+1] =&pci_ctrl->mem_resources[i];
+ pci_ctrl->bus = bus;
+ pci_ctrl->last_busno = bus->subordinate;
+ if (next_busno <= pci_ctrl->last_busno)
+ next_busno = pci_ctrl->last_busno+1;
+ }
+ pci_bus_count = next_busno;
+
+ return platform_pcibios_fixup();
+}
+
+subsys_initcall(pcibios_init);
+
+void __init pcibios_fixup_bus(struct pci_bus *bus)
+{
+ struct pci_controller *pci_ctrl = bus->sysdata;
+ struct resource *res;
+ unsigned long io_offset;
+ int i;
+
+ io_offset = (unsigned long)pci_ctrl->io_space.base;
+ if (bus->parent == NULL) {
+ /* this is a host bridge - fill in its resources */
+ pci_ctrl->bus = bus;
+
+ bus->resource[0] = res = &pci_ctrl->io_resource;
+ if (!res->flags) {
+ if (io_offset)
+ printk (KERN_ERR "I/O resource not set for host"
+ " bridge %d\n", pci_ctrl->index);
+ res->start = 0;
+ res->end = IO_SPACE_LIMIT;
+ res->flags = IORESOURCE_IO;
+ }
+ res->start += io_offset;
+ res->end += io_offset;
+
+ for (i = 0; i < 3; i++) {
+ res = &pci_ctrl->mem_resources[i];
+ if (!res->flags) {
+ if (i > 0)
+ continue;
+ printk(KERN_ERR "Memory resource not set for "
+ "host bridge %d\n", pci_ctrl->index);
+ res->start = 0;
+ res->end = ~0U;
+ res->flags = IORESOURCE_MEM;
+ }
+ bus->resource[i+1] = res;
+ }
+ } else {
+ /* This is a subordinate bridge */
+ pci_read_bridge_bases(bus);
+
+ for (i = 0; i < 4; i++) {
+ if ((res = bus->resource[i]) == NULL || !res->flags)
+ continue;
+ if (io_offset && (res->flags & IORESOURCE_IO)) {
+ res->start += io_offset;
+ res->end += io_offset;
+ }
+ }
+ }
+}
+
+char __init *pcibios_setup(char *str)
+{
+ return str;
+}
+
+/* the next one is stolen from the alpha port... */
+
+void __init
+pcibios_update_irq(struct pci_dev *dev, int irq)
+{
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+int pcibios_enable_device(struct pci_dev *dev, int mask)
+{
+ u16 cmd, old_cmd;
+ int idx;
+ struct resource *r;
+
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ old_cmd = cmd;
+ for (idx=0; idx<6; idx++) {
+ r = &dev->resource[idx];
+ if (!r->start && r->end) {
+ printk(KERN_ERR "PCI: Device %s not available because "
+ "of resource collisions\n", pci_name(dev));
+ return -EINVAL;
+ }
+ if (r->flags & IORESOURCE_IO)
+ cmd |= PCI_COMMAND_IO;
+ if (r->flags & IORESOURCE_MEM)
+ cmd |= PCI_COMMAND_MEMORY;
+ }
+ if (cmd != old_cmd) {
+ printk("PCI: Enabling device %s (%04x -> %04x)\n",
+ pci_name(dev), old_cmd, cmd);
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Return the index of the PCI controller for device pdev.
+ */
+
+int
+pci_controller_num(struct pci_dev *dev)
+{
+ struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+ return pci_ctrl->index;
+}
+
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * Platform support for /proc/bus/pci/X/Y mmap()s,
+ * modelled on the sparc64 implementation by Dave Miller.
+ * -- paulus.
+ */
+
+/*
+ * Adjust vm_pgoff of VMA such that it is the physical page offset
+ * corresponding to the 32-bit pci bus offset for DEV requested by the user.
+ *
+ * Basically, the user finds the base address for his device which he wishes
+ * to mmap. They read the 32-bit value from the config space base register,
+ * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
+ * offset parameter of mmap on /proc/bus/pci/XXX for that device.
+ *
+ * Returns negative error code on failure, zero on success.
+ */
+static __inline__ int
+__pci_mmap_make_offset(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state)
+{
+ struct pci_controller *pci_ctrl = (struct pci_controller*) dev->sysdata;
+ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
+ unsigned long io_offset = 0;
+ int i, res_bit;
+
+ if (pci_ctrl == 0)
+ return -EINVAL; /* should never happen */
+
+ /* If memory, add on the PCI bridge address offset */
+ if (mmap_state == pci_mmap_mem) {
+ res_bit = IORESOURCE_MEM;
+ } else {
+ io_offset = (unsigned long)pci_ctrl->io_space.base;
+ offset += io_offset;
+ res_bit = IORESOURCE_IO;
+ }
+
+ /*
+ * Check that the offset requested corresponds to one of the
+ * resources of the device.
+ */
+ for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
+ struct resource *rp = &dev->resource[i];
+ int flags = rp->flags;
+
+ /* treat ROM as memory (should be already) */
+ if (i == PCI_ROM_RESOURCE)
+ flags |= IORESOURCE_MEM;
+
+ /* Active and same type? */
+ if ((flags & res_bit) == 0)
+ continue;
+
+ /* In the range of this resource? */
+ if (offset < (rp->start & PAGE_MASK) || offset > rp->end)
+ continue;
+
+ /* found it! construct the final physical address */
+ if (mmap_state == pci_mmap_io)
+ offset += pci_ctrl->io_space.start - io_offset;
+ vma->vm_pgoff = offset >> PAGE_SHIFT;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Set vm_flags of VMA, as appropriate for this architecture, for a pci device
+ * mapping.
+ */
+static __inline__ void
+__pci_mmap_set_flags(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state)
+{
+ vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO;
+}
+
+/*
+ * Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
+ * device mapping.
+ */
+static __inline__ void
+__pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine)
+{
+ int prot = pgprot_val(vma->vm_page_prot);
+
+ /* Set to write-through */
+ prot &= ~_PAGE_NO_CACHE;
+#if 0
+ if (!write_combine)
+ prot |= _PAGE_WRITETHRU;
+#endif
+ vma->vm_page_prot = __pgprot(prot);
+}
+
+/*
+ * Perform the actual remap of the pages for a PCI device mapping, as
+ * appropriate for this architecture. The region in the process to map
+ * is described by vm_start and vm_end members of VMA, the base physical
+ * address is found in vm_pgoff.
+ * The pci device structure is provided so that architectures may make mapping
+ * decisions on a per-device or per-bus basis.
+ *
+ * Returns a negative error code on failure, zero on success.
+ */
+int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state,
+ int write_combine)
+{
+ int ret;
+
+ ret = __pci_mmap_make_offset(dev, vma, mmap_state);
+ if (ret < 0)
+ return ret;
+
+ __pci_mmap_set_flags(dev, vma, mmap_state);
+ __pci_mmap_set_pgprot(dev, vma, mmap_state, write_combine);
+
+ ret = io_remap_page_range(vma, vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT,
+ vma->vm_end - vma->vm_start, vma->vm_page_prot);
+
+ return ret;
+}
+
+/*
+ * This probably belongs here rather than ioport.c because
+ * we do not want this crud linked into SBus kernels.
+ * Also, think for a moment about likes of floppy.c that
+ * include architecture specific parts. They may want to redefine ins/outs.
+ *
+ * We do not use horroble macroses here because we want to
+ * advance pointer by sizeof(size).
+ */
+void outsb(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 1;
+ writeb(*(const char *)src, addr);
+ src += 1;
+ addr += 1;
+ }
+}
+
+void outsw(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 2;
+ writew(*(const short *)src, addr);
+ src += 2;
+ addr += 2;
+ }
+}
+
+void outsl(unsigned long addr, const void *src, unsigned long count) {
+ while (count) {
+ count -= 4;
+ writel(*(const long *)src, addr);
+ src += 4;
+ addr += 4;
+ }
+}
+
+void insb(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 1;
+ *(unsigned char *)dst = readb(addr);
+ dst += 1;
+ addr += 1;
+ }
+}
+
+void insw(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 2;
+ *(unsigned short *)dst = readw(addr);
+ dst += 2;
+ addr += 2;
+ }
+}
+
+void insl(unsigned long addr, void *dst, unsigned long count) {
+ while (count) {
+ count -= 4;
+ /*
+ * XXX I am sure we are in for an unaligned trap here.
+ */
+ *(unsigned long *)dst = readl(addr);
+ dst += 4;
+ addr += 4;
+ }
+}
+
+
+
diff --git a/arch/xtensa/kernel/platform.c b/arch/xtensa/kernel/platform.c
new file mode 100644
index 000000000000..cf1362784443
--- /dev/null
+++ b/arch/xtensa/kernel/platform.c
@@ -0,0 +1,49 @@
+/*
+ * arch/xtensa/kernel/platform.c
+ *
+ * Default platform functions.
+ *
+ * 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/platform.h>
+#include <asm/timex.h>
+
+#define _F(r,f,a,b) \
+ r __platform_##f a b; \
+ r platform_##f a __attribute__((weak, alias("__platform_"#f)))
+
+/*
+ * Default functions that are used if no platform specific function is defined.
+ * (Please, refer to include/asm-xtensa/platform.h for more information)
+ */
+
+_F(void, setup, (char** cmd), { });
+_F(void, init_irq, (void), { });
+_F(void, restart, (void), { while(1); });
+_F(void, halt, (void), { while(1); });
+_F(void, power_off, (void), { while(1); });
+_F(void, idle, (void), { __asm__ __volatile__ ("waiti 0" ::: "memory"); });
+_F(void, heartbeat, (void), { });
+_F(int, pcibios_fixup, (void), { return 0; });
+_F(int, get_rtc_time, (time_t* t), { return 0; });
+_F(int, set_rtc_time, (time_t t), { return 0; });
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+_F(void, calibrate_ccount, (void),
+{
+ printk ("ERROR: Cannot calibrate cpu frequency! Assuming 100MHz.\n");
+ ccount_per_jiffy = 100 * (1000000UL/HZ);
+});
+#endif
+
diff --git a/arch/xtensa/kernel/process.c b/arch/xtensa/kernel/process.c
new file mode 100644
index 000000000000..4099703b14be
--- /dev/null
+++ b/arch/xtensa/kernel/process.c
@@ -0,0 +1,482 @@
+// TODO verify coprocessor handling
+/*
+ * arch/xtensa/kernel/process.c
+ *
+ * Xtensa Processor version.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/stddef.h>
+#include <linux/unistd.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/elf.h>
+#include <linux/init.h>
+#include <linux/prctl.h>
+#include <linux/init_task.h>
+#include <linux/module.h>
+#include <linux/mqueue.h>
+
+#include <asm/pgtable.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/platform.h>
+#include <asm/mmu.h>
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/offsets.h>
+#include <asm/coprocessor.h>
+
+extern void ret_from_fork(void);
+
+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);
+
+union thread_union init_thread_union
+ __attribute__((__section__(".data.init_task"))) =
+{ INIT_THREAD_INFO(init_task) };
+
+struct task_struct init_task = INIT_TASK(init_task);
+EXPORT_SYMBOL(init_task);
+
+struct task_struct *current_set[NR_CPUS] = {&init_task, };
+
+
+#if XCHAL_CP_NUM > 0
+
+/*
+ * Coprocessor ownership.
+ */
+
+coprocessor_info_t coprocessor_info[] = {
+ { 0, XTENSA_CPE_CP0_OFFSET },
+ { 0, XTENSA_CPE_CP1_OFFSET },
+ { 0, XTENSA_CPE_CP2_OFFSET },
+ { 0, XTENSA_CPE_CP3_OFFSET },
+ { 0, XTENSA_CPE_CP4_OFFSET },
+ { 0, XTENSA_CPE_CP5_OFFSET },
+ { 0, XTENSA_CPE_CP6_OFFSET },
+ { 0, XTENSA_CPE_CP7_OFFSET },
+};
+
+#endif
+
+/*
+ * Powermanagement idle function, if any is provided by the platform.
+ */
+
+void cpu_idle(void)
+{
+ local_irq_enable();
+
+ /* endless idle loop with no priority at all */
+ while (1) {
+ while (!need_resched())
+ platform_idle();
+ preempt_enable();
+ schedule();
+ }
+}
+
+/*
+ * Free current thread data structures etc..
+ */
+
+void exit_thread(void)
+{
+ release_coprocessors(current); /* Empty macro if no CPs are defined */
+}
+
+void flush_thread(void)
+{
+ release_coprocessors(current); /* Empty macro if no CPs are defined */
+}
+
+/*
+ * Copy thread.
+ *
+ * The stack layout for the new thread looks like this:
+ *
+ * +------------------------+ <- sp in childregs (= tos)
+ * | childregs |
+ * +------------------------+ <- thread.sp = sp in dummy-frame
+ * | dummy-frame | (saved in dummy-frame spill-area)
+ * +------------------------+
+ *
+ * We create a dummy frame to return to ret_from_fork:
+ * a0 points to ret_from_fork (simulating a call4)
+ * sp points to itself (thread.sp)
+ * a2, a3 are unused.
+ *
+ * Note: This is a pristine frame, so we don't need any spill region on top of
+ * childregs.
+ */
+
+int copy_thread(int nr, unsigned long clone_flags, unsigned long usp,
+ unsigned long unused,
+ struct task_struct * p, struct pt_regs * regs)
+{
+ struct pt_regs *childregs;
+ unsigned long tos;
+ int user_mode = user_mode(regs);
+
+ /* Set up new TSS. */
+ tos = (unsigned long)p->thread_info + THREAD_SIZE;
+ if (user_mode)
+ childregs = (struct pt_regs*)(tos - PT_USER_SIZE);
+ else
+ childregs = (struct pt_regs*)tos - 1;
+
+ *childregs = *regs;
+
+ /* Create a call4 dummy-frame: a0 = 0, a1 = childregs. */
+ *((int*)childregs - 3) = (unsigned long)childregs;
+ *((int*)childregs - 4) = 0;
+
+ childregs->areg[1] = tos;
+ childregs->areg[2] = 0;
+ p->set_child_tid = p->clear_child_tid = NULL;
+ p->thread.ra = MAKE_RA_FOR_CALL((unsigned long)ret_from_fork, 0x1);
+ p->thread.sp = (unsigned long)childregs;
+ if (user_mode(regs)) {
+
+ int len = childregs->wmask & ~0xf;
+ childregs->areg[1] = usp;
+ memcpy(&childregs->areg[XCHAL_NUM_AREGS - len/4],
+ &regs->areg[XCHAL_NUM_AREGS - len/4], len);
+
+ if (clone_flags & CLONE_SETTLS)
+ childregs->areg[2] = childregs->areg[6];
+
+ } else {
+ /* In kernel space, we start a new thread with a new stack. */
+ childregs->wmask = 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Create a kernel thread
+ */
+
+int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
+{
+ long retval;
+ __asm__ __volatile__
+ ("mov a5, %4\n\t" /* preserve fn in a5 */
+ "mov a6, %3\n\t" /* preserve and setup arg in a6 */
+ "movi a2, %1\n\t" /* load __NR_clone for syscall*/
+ "mov a3, sp\n\t" /* sp check and sys_clone */
+ "mov a4, %5\n\t" /* load flags for syscall */
+ "syscall\n\t"
+ "beq a3, sp, 1f\n\t" /* branch if parent */
+ "callx4 a5\n\t" /* call fn */
+ "movi a2, %2\n\t" /* load __NR_exit for syscall */
+ "mov a3, a6\n\t" /* load fn return value */
+ "syscall\n"
+ "1:\n\t"
+ "mov %0, a2\n\t" /* parent returns zero */
+ :"=r" (retval)
+ :"i" (__NR_clone), "i" (__NR_exit),
+ "r" (arg), "r" (fn),
+ "r" (flags | CLONE_VM)
+ : "a2", "a3", "a4", "a5", "a6" );
+ return retval;
+}
+
+
+/*
+ * These bracket the sleeping functions..
+ */
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long sp, pc;
+ unsigned long stack_page = (unsigned long) p->thread_info;
+ int count = 0;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ sp = p->thread.sp;
+ pc = MAKE_PC_FROM_RA(p->thread.ra, p->thread.sp);
+
+ do {
+ if (sp < stack_page + sizeof(struct task_struct) ||
+ sp >= (stack_page + THREAD_SIZE) ||
+ pc == 0)
+ return 0;
+ if (!in_sched_functions(pc))
+ return pc;
+
+ /* Stack layout: sp-4: ra, sp-3: sp' */
+
+ pc = MAKE_PC_FROM_RA(*(unsigned long*)sp - 4, sp);
+ sp = *(unsigned long *)sp - 3;
+ } while (count++ < 16);
+ return 0;
+}
+
+/*
+ * do_copy_regs() gathers information from 'struct pt_regs' and
+ * 'current->thread.areg[]' to fill in the xtensa_gregset_t
+ * structure.
+ *
+ * xtensa_gregset_t and 'struct pt_regs' are vastly different formats
+ * of processor registers. Besides different ordering,
+ * xtensa_gregset_t contains non-live register information that
+ * 'struct pt_regs' does not. Exception handling (primarily) uses
+ * 'struct pt_regs'. Core files and ptrace use xtensa_gregset_t.
+ *
+ */
+
+void do_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+ struct task_struct *tsk)
+{
+ int i, n, wb_offset;
+
+ elfregs->xchal_config_id0 = XCHAL_HW_CONFIGID0;
+ elfregs->xchal_config_id1 = XCHAL_HW_CONFIGID1;
+
+ __asm__ __volatile__ ("rsr %0, 176\n" : "=a" (i));
+ elfregs->cpux = i;
+ __asm__ __volatile__ ("rsr %0, 208\n" : "=a" (i));
+ elfregs->cpuy = i;
+
+ /* Note: PS.EXCM is not set while user task is running; its
+ * being set in regs->ps is for exception handling convenience.
+ */
+
+ elfregs->pc = regs->pc;
+ elfregs->ps = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+ elfregs->exccause = regs->exccause;
+ elfregs->excvaddr = regs->excvaddr;
+ elfregs->windowbase = regs->windowbase;
+ elfregs->windowstart = regs->windowstart;
+ elfregs->lbeg = regs->lbeg;
+ elfregs->lend = regs->lend;
+ elfregs->lcount = regs->lcount;
+ elfregs->sar = regs->sar;
+ elfregs->syscall = regs->syscall;
+
+ /* Copy register file.
+ * The layout looks like this:
+ *
+ * | a0 ... a15 | Z ... Z | arX ... arY |
+ * current window unused saved frames
+ */
+
+ memset (elfregs->ar, 0, sizeof(elfregs->ar));
+
+ wb_offset = regs->windowbase * 4;
+ n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+ for (i = 0; i < n; i++)
+ elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+
+ n = (regs->wmask >> 4) * 4;
+
+ for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+ elfregs->ar[(wb_offset + i) % XCHAL_NUM_AREGS] = regs->areg[i];
+}
+
+void xtensa_elf_core_copy_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs)
+{
+ do_copy_regs ((xtensa_gregset_t *)elfregs, regs, current);
+}
+
+
+/* The inverse of do_copy_regs(). No error or sanity checking. */
+
+void do_restore_regs (xtensa_gregset_t *elfregs, struct pt_regs *regs,
+ struct task_struct *tsk)
+{
+ int i, n, wb_offset;
+
+ /* Note: PS.EXCM is not set while user task is running; it
+ * needs to be set in regs->ps is for exception handling convenience.
+ */
+
+ regs->pc = elfregs->pc;
+ regs->ps = (elfregs->ps | XCHAL_PS_EXCM_MASK);
+ regs->exccause = elfregs->exccause;
+ regs->excvaddr = elfregs->excvaddr;
+ regs->windowbase = elfregs->windowbase;
+ regs->windowstart = elfregs->windowstart;
+ regs->lbeg = elfregs->lbeg;
+ regs->lend = elfregs->lend;
+ regs->lcount = elfregs->lcount;
+ regs->sar = elfregs->sar;
+ regs->syscall = elfregs->syscall;
+
+ /* Clear everything. */
+
+ memset (regs->areg, 0, sizeof(regs->areg));
+
+ /* Copy regs from live window frame. */
+
+ wb_offset = regs->windowbase * 4;
+ n = (regs->wmask&1)? 4 : (regs->wmask&2)? 8 : (regs->wmask&4)? 12 : 16;
+
+ for (i = 0; i < n; i++)
+ regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+
+ n = (regs->wmask >> 4) * 4;
+
+ for (i = XCHAL_NUM_AREGS - n; n > 0; i++, n--)
+ regs->areg[(wb_offset+i) % XCHAL_NUM_AREGS] = elfregs->ar[i];
+}
+
+/*
+ * do_save_fpregs() gathers information from 'struct pt_regs' and
+ * 'current->thread' to fill in the elf_fpregset_t structure.
+ *
+ * Core files and ptrace use elf_fpregset_t.
+ */
+
+void do_save_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+ struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+ extern unsigned char _xtensa_reginfo_tables[];
+ extern unsigned _xtensa_reginfo_table_size;
+ int i;
+ unsigned long flags;
+
+ /* Before dumping coprocessor state from memory,
+ * ensure any live coprocessor contents for this
+ * task are first saved to memory:
+ */
+ local_irq_save(flags);
+
+ for (i = 0; i < XCHAL_CP_MAX; i++) {
+ if (tsk == coprocessor_info[i].owner) {
+ enable_coprocessor(i);
+ save_coprocessor_registers(
+ tsk->thread.cp_save+coprocessor_info[i].offset,i);
+ disable_coprocessor(i);
+ }
+ }
+
+ local_irq_restore(flags);
+
+ /* Now dump coprocessor & extra state: */
+ memcpy((unsigned char*)fpregs,
+ _xtensa_reginfo_tables, _xtensa_reginfo_table_size);
+ memcpy((unsigned char*)fpregs + _xtensa_reginfo_table_size,
+ tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+#endif
+}
+
+/*
+ * The inverse of do_save_fpregs().
+ * Copies coprocessor and extra state from fpregs into regs and tsk->thread.
+ * Returns 0 on success, non-zero if layout doesn't match.
+ */
+
+int do_restore_fpregs (elf_fpregset_t *fpregs, struct pt_regs *regs,
+ struct task_struct *tsk)
+{
+#if XCHAL_HAVE_CP
+
+ extern unsigned char _xtensa_reginfo_tables[];
+ extern unsigned _xtensa_reginfo_table_size;
+ int i;
+ unsigned long flags;
+
+ /* Make sure save area layouts match.
+ * FIXME: in the future we could allow restoring from
+ * a different layout of the same registers, by comparing
+ * fpregs' table with _xtensa_reginfo_tables and matching
+ * entries and copying registers one at a time.
+ * Not too sure yet whether that's very useful.
+ */
+
+ if( memcmp((unsigned char*)fpregs,
+ _xtensa_reginfo_tables, _xtensa_reginfo_table_size) ) {
+ return -1;
+ }
+
+ /* Before restoring coprocessor state from memory,
+ * ensure any live coprocessor contents for this
+ * task are first invalidated.
+ */
+
+ local_irq_save(flags);
+
+ for (i = 0; i < XCHAL_CP_MAX; i++) {
+ if (tsk == coprocessor_info[i].owner) {
+ enable_coprocessor(i);
+ save_coprocessor_registers(
+ tsk->thread.cp_save+coprocessor_info[i].offset,i);
+ coprocessor_info[i].owner = 0;
+ disable_coprocessor(i);
+ }
+ }
+
+ local_irq_restore(flags);
+
+ /* Now restore coprocessor & extra state: */
+
+ memcpy(tsk->thread.cp_save,
+ (unsigned char*)fpregs + _xtensa_reginfo_table_size,
+ XTENSA_CP_EXTRA_SIZE);
+#endif
+ return 0;
+}
+/*
+ * Fill in the CP structure for a core dump for a particular task.
+ */
+
+int
+dump_task_fpu(struct pt_regs *regs, struct task_struct *task, elf_fpregset_t *r)
+{
+/* see asm/coprocessor.h for this magic number 16 */
+#if TOTAL_CPEXTRA_SIZE > 16
+ do_save_fpregs (r, regs, task);
+
+ /* For now, bit 16 means some extra state may be present: */
+// FIXME!! need to track to return more accurate mask
+ return 0x10000 | XCHAL_CP_MASK;
+#else
+ return 0; /* no coprocessors active on this processor */
+#endif
+}
+
+/*
+ * Fill in the CP structure for a core dump.
+ * This includes any FPU coprocessor.
+ * Here, we dump all coprocessors, and other ("extra") custom state.
+ *
+ * This function is called by elf_core_dump() in fs/binfmt_elf.c
+ * (in which case 'regs' comes from calls to do_coredump, see signals.c).
+ */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+{
+ return dump_task_fpu(regs, current, r);
+}
diff --git a/arch/xtensa/kernel/ptrace.c b/arch/xtensa/kernel/ptrace.c
new file mode 100644
index 000000000000..2659efdd4e99
--- /dev/null
+++ b/arch/xtensa/kernel/ptrace.c
@@ -0,0 +1,408 @@
+// TODO some minor issues
+/*
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Scott Foehner<sfoehner@yahoo.com>,
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/security.h>
+#include <linux/signal.h>
+
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/ptrace.h>
+#include <asm/elf.h>
+
+#define TEST_KERNEL // verify kernel operations FIXME: remove
+
+
+/*
+ * 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.. */
+}
+
+int sys_ptrace(long request, long pid, long addr, long data)
+{
+ struct task_struct *child;
+ int ret = -EPERM;
+
+ lock_kernel();
+
+#if 0
+ if ((int)request != 1)
+ printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n",
+ (int) request, (int) pid, (unsigned long) addr,
+ (unsigned long) data);
+#endif
+
+ if (request == PTRACE_TRACEME) {
+
+ /* Are we already being traced? */
+
+ if (current->ptrace & PT_PTRACED)
+ goto out;
+
+ if ((ret = security_ptrace(current->parent, current)))
+ 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);
+ goto out_tsk;
+ }
+
+ if ((ret = ptrace_check_attach(child, request == PTRACE_KILL)) < 0)
+ goto out_tsk;
+
+ switch (request) {
+ case PTRACE_PEEKTEXT: /* read word at location addr. */
+ case PTRACE_PEEKDATA:
+ {
+ unsigned long tmp;
+ int copied;
+
+ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0);
+ ret = -EIO;
+ if (copied != sizeof(tmp))
+ break;
+ ret = put_user(tmp,(unsigned long *) data);
+
+ goto out;
+ }
+
+ /* Read the word at location addr in the USER area. */
+
+ case PTRACE_PEEKUSR:
+ {
+ struct pt_regs *regs;
+ unsigned long tmp;
+
+ regs = xtensa_pt_regs(child);
+ tmp = 0; /* Default return value. */
+
+ switch(addr) {
+
+ case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+ {
+ int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+ ar &= (XCHAL_NUM_AREGS - 1);
+ if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+ tmp = regs->areg[ar];
+ else
+ ret = -EIO;
+ break;
+ }
+ case REG_A_BASE ... REG_A_BASE + 15:
+ tmp = regs->areg[addr - REG_A_BASE];
+ break;
+ case REG_PC:
+ tmp = regs->pc;
+ break;
+ case REG_PS:
+ /* Note: PS.EXCM is not set while user task is running;
+ * its being set in regs is for exception handling
+ * convenience. */
+ tmp = (regs->ps & ~XCHAL_PS_EXCM_MASK);
+ break;
+ case REG_WB:
+ tmp = regs->windowbase;
+ break;
+ case REG_WS:
+ tmp = regs->windowstart;
+ break;
+ case REG_LBEG:
+ tmp = regs->lbeg;
+ break;
+ case REG_LEND:
+ tmp = regs->lend;
+ break;
+ case REG_LCOUNT:
+ tmp = regs->lcount;
+ break;
+ case REG_SAR:
+ tmp = regs->sar;
+ break;
+ case REG_DEPC:
+ tmp = regs->depc;
+ break;
+ case REG_EXCCAUSE:
+ tmp = regs->exccause;
+ break;
+ case REG_EXCVADDR:
+ tmp = regs->excvaddr;
+ break;
+ case SYSCALL_NR:
+ tmp = regs->syscall;
+ break;
+ default:
+ tmp = 0;
+ ret = -EIO;
+ goto out;
+ }
+ ret = put_user(tmp, (unsigned long *) data);
+ goto out;
+ }
+
+ case PTRACE_POKETEXT: /* write the word at location addr. */
+ case PTRACE_POKEDATA:
+ if (access_process_vm(child, addr, &data, sizeof(data), 1)
+ == sizeof(data))
+ break;
+ ret = -EIO;
+ goto out;
+
+ case PTRACE_POKEUSR:
+ {
+ struct pt_regs *regs;
+ regs = xtensa_pt_regs(child);
+
+ switch (addr) {
+ case REG_AR_BASE ... REG_AR_BASE + XCHAL_NUM_AREGS - 1:
+ {
+ int ar = addr - REG_AR_BASE - regs->windowbase * 4;
+ if (ar < 16 && ar + (regs->wmask >> 4) * 4 >= 0)
+ regs->areg[ar & (XCHAL_NUM_AREGS - 1)] = data;
+ else
+ ret = -EIO;
+ break;
+ }
+ case REG_A_BASE ... REG_A_BASE + 15:
+ regs->areg[addr - REG_A_BASE] = data;
+ break;
+ case REG_PC:
+ regs->pc = data;
+ break;
+ case SYSCALL_NR:
+ regs->syscall = data;
+ break;
+#ifdef TEST_KERNEL
+ case REG_WB:
+ regs->windowbase = data;
+ break;
+ case REG_WS:
+ regs->windowstart = data;
+ break;
+#endif
+
+ default:
+ /* The rest are not allowed. */
+ ret = -EIO;
+ break;
+ }
+ break;
+ }
+
+ /* continue and stop at next (return from) syscall */
+ case PTRACE_SYSCALL:
+ case PTRACE_CONT: /* restart after signal. */
+ {
+ ret = -EIO;
+ if (!valid_signal(data))
+ 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;
+ /* Make sure the single step bit is not set. */
+ child->ptrace &= ~PT_SINGLESTEP;
+ 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;
+ if (child->state == EXIT_ZOMBIE) /* already dead */
+ break;
+ child->exit_code = SIGKILL;
+ child->ptrace &= ~PT_SINGLESTEP;
+ wake_up_process(child);
+ break;
+
+ case PTRACE_SINGLESTEP:
+ ret = -EIO;
+ if (!valid_signal(data))
+ break;
+ clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
+ child->ptrace |= PT_SINGLESTEP;
+ child->exit_code = data;
+ wake_up_process(child);
+ ret = 0;
+ break;
+
+ case PTRACE_GETREGS:
+ {
+ /* 'data' points to user memory in which to write.
+ * Mainly due to the non-live register values, we
+ * reformat the register values into something more
+ * standard. For convenience, we use the handy
+ * elf_gregset_t format. */
+
+ xtensa_gregset_t format;
+ struct pt_regs *regs = xtensa_pt_regs(child);
+
+ do_copy_regs (&format, regs, child);
+
+ /* Now, copy to user space nice and easy... */
+ ret = 0;
+ if (copy_to_user((void *)data, &format, sizeof(elf_gregset_t)))
+ ret = -EFAULT;
+ break;
+ }
+
+ case PTRACE_SETREGS:
+ {
+ /* 'data' points to user memory that contains the new
+ * values in the elf_gregset_t format. */
+
+ xtensa_gregset_t format;
+ struct pt_regs *regs = xtensa_pt_regs(child);
+
+ if (copy_from_user(&format,(void *)data,sizeof(elf_gregset_t))){
+ ret = -EFAULT;
+ break;
+ }
+
+ /* FIXME: Perhaps we want some sanity checks on
+ * these user-space values? See ARM version. Are
+ * debuggers a security concern? */
+
+ do_restore_regs (&format, regs, child);
+
+ ret = 0;
+ break;
+ }
+
+ case PTRACE_GETFPREGS:
+ {
+ /* 'data' points to user memory in which to write.
+ * For convenience, we use the handy
+ * elf_fpregset_t format. */
+
+ elf_fpregset_t fpregs;
+ struct pt_regs *regs = xtensa_pt_regs(child);
+
+ do_save_fpregs (&fpregs, regs, child);
+
+ /* Now, copy to user space nice and easy... */
+ ret = 0;
+ if (copy_to_user((void *)data, &fpregs, sizeof(elf_fpregset_t)))
+ ret = -EFAULT;
+
+ break;
+ }
+
+ case PTRACE_SETFPREGS:
+ {
+ /* 'data' points to user memory that contains the new
+ * values in the elf_fpregset_t format.
+ */
+ elf_fpregset_t fpregs;
+ struct pt_regs *regs = xtensa_pt_regs(child);
+
+ ret = 0;
+ if (copy_from_user(&fpregs, (void *)data, sizeof(elf_fpregset_t))) {
+ ret = -EFAULT;
+ break;
+ }
+
+ if (do_restore_fpregs (&fpregs, regs, child))
+ ret = -EIO;
+ break;
+ }
+
+ case PTRACE_GETFPREGSIZE:
+ /* 'data' points to 'unsigned long' set to the size
+ * of elf_fpregset_t
+ */
+ ret = put_user(sizeof(elf_fpregset_t), (unsigned long *) data);
+ break;
+
+ case PTRACE_DETACH: /* detach a process that was attached. */
+ ret = ptrace_detach(child, data);
+ break;
+
+ default:
+ ret = ptrace_request(child, request, addr, data);
+ goto out;
+ }
+out_tsk:
+ put_task_struct(child);
+out:
+ unlock_kernel();
+ return ret;
+}
+
+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/xtensa/kernel/semaphore.c b/arch/xtensa/kernel/semaphore.c
new file mode 100644
index 000000000000..d40f4b1b75ac
--- /dev/null
+++ b/arch/xtensa/kernel/semaphore.c
@@ -0,0 +1,226 @@
+/*
+ * arch/xtensa/kernel/semaphore.c
+ *
+ * Generic semaphore code. Buyer beware. Do your own specific changes
+ * in <asm/semaphore-helper.h>
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/init.h>
+#include <asm/semaphore.h>
+#include <asm/errno.h>
+
+/*
+ * These two _must_ execute atomically wrt each other.
+ */
+
+static __inline__ void wake_one_more(struct semaphore * sem)
+{
+ atomic_inc((atomic_t *)&sem->sleepers);
+}
+
+static __inline__ int waking_non_zero(struct semaphore *sem)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers > 0) {
+ sem->sleepers--;
+ ret = 1;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_interruptible:
+ * 1 got the lock
+ * 0 go to sleep
+ * -EINTR interrupted
+ *
+ * We must undo the sem->count down_interruptible() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_interruptible(struct semaphore *sem,
+ struct task_struct *tsk)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers > 0) {
+ sem->sleepers--;
+ ret = 1;
+ } else if (signal_pending(tsk)) {
+ atomic_inc(&sem->count);
+ ret = -EINTR;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+/*
+ * waking_non_zero_trylock:
+ * 1 failed to lock
+ * 0 got the lock
+ *
+ * We must undo the sem->count down_trylock() increment while we are
+ * protected by the spinlock in order to make atomic this atomic_inc() with the
+ * atomic_read() in wake_one_more(), otherwise we can race. -arca
+ */
+
+static __inline__ int waking_non_zero_trylock(struct semaphore *sem)
+{
+ unsigned long flags;
+ int ret = 1;
+
+ spin_lock_irqsave(&semaphore_wake_lock, flags);
+ if (sem->sleepers <= 0)
+ atomic_inc(&sem->count);
+ else {
+ sem->sleepers--;
+ ret = 0;
+ }
+ spin_unlock_irqrestore(&semaphore_wake_lock, flags);
+ return ret;
+}
+
+spinlock_t semaphore_wake_lock;
+
+/*
+ * Semaphores are implemented using a two-way counter:
+ * The "count" variable is decremented for each process
+ * that tries to sleep, while the "waking" variable is
+ * incremented when the "up()" code goes to wake up waiting
+ * processes.
+ *
+ * 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.
+ *
+ * waking_non_zero() (from asm/semaphore.h) must execute
+ * atomically.
+ *
+ * When __up() is called, the count was negative before
+ * incrementing it, and we need to wake up somebody.
+ *
+ * This routine adds one to the count of processes that need to
+ * wake up and exit. ALL waiting processes actually wake up but
+ * only the one that gets to the "waking" field first will gate
+ * through and acquire the semaphore. The others will go back
+ * to sleep.
+ *
+ * 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 <asm/semaphore.h>
+ * where we want to avoid any extra jumps and calls.
+ */
+
+void __up(struct semaphore *sem)
+{
+ wake_one_more(sem);
+ wake_up(&sem->wait);
+}
+
+/*
+ * Perform the "down" function. Return zero for semaphore acquired,
+ * return negative for signalled out of the function.
+ *
+ * If called from __down, the return is ignored and the wait loop is
+ * not interruptible. This means that a task waiting on a semaphore
+ * using "down()" cannot be killed until someone does an "up()" on
+ * the semaphore.
+ *
+ * If called from __down_interruptible, the return value gets checked
+ * upon return. If the return value is negative then the task continues
+ * with the negative value in the return register (it can be tested by
+ * the caller).
+ *
+ * Either form may be used in conjunction with "up()".
+ *
+ */
+
+#define DOWN_VAR \
+ struct task_struct *tsk = current; \
+ wait_queue_t wait; \
+ init_waitqueue_entry(&wait, tsk);
+
+#define DOWN_HEAD(task_state) \
+ \
+ \
+ tsk->state = (task_state); \
+ add_wait_queue(&sem->wait, &wait); \
+ \
+ /* \
+ * Ok, we're set up. sem->count is known to be less than zero \
+ * so we must wait. \
+ * \
+ * We can let go the lock for purposes of waiting. \
+ * We re-acquire it after awaking so as to protect \
+ * all semaphore operations. \
+ * \
+ * If "up()" is called before we call waking_non_zero() then \
+ * we will catch it right away. If it is called later then \
+ * we will have to go through a wakeup cycle to catch it. \
+ * \
+ * Multiple waiters contend for the semaphore lock to see \
+ * who gets to gate through and who has to wait some more. \
+ */ \
+ for (;;) {
+
+#define DOWN_TAIL(task_state) \
+ tsk->state = (task_state); \
+ } \
+ tsk->state = TASK_RUNNING; \
+ remove_wait_queue(&sem->wait, &wait);
+
+void __sched __down(struct semaphore * sem)
+{
+ DOWN_VAR
+ DOWN_HEAD(TASK_UNINTERRUPTIBLE)
+ if (waking_non_zero(sem))
+ break;
+ schedule();
+ DOWN_TAIL(TASK_UNINTERRUPTIBLE)
+}
+
+int __sched __down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+ DOWN_VAR
+ DOWN_HEAD(TASK_INTERRUPTIBLE)
+
+ ret = waking_non_zero_interruptible(sem, tsk);
+ if (ret)
+ {
+ if (ret == 1)
+ /* ret != 0 only if we get interrupted -arca */
+ ret = 0;
+ break;
+ }
+ schedule();
+ DOWN_TAIL(TASK_INTERRUPTIBLE)
+ return ret;
+}
+
+int __down_trylock(struct semaphore * sem)
+{
+ return waking_non_zero_trylock(sem);
+}
diff --git a/arch/xtensa/kernel/setup.c b/arch/xtensa/kernel/setup.c
new file mode 100644
index 000000000000..1f5bf5d624e4
--- /dev/null
+++ b/arch/xtensa/kernel/setup.c
@@ -0,0 +1,520 @@
+/*
+ * arch/xtensa/setup.c
+ *
+ * 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 Linus Torvalds
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Kevin Chea
+ * Marc Gauthier<marc@tensilica.com> <marc@alumni.uwaterloo.ca>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/tty.h>
+#include <linux/bootmem.h>
+#include <linux/kernel.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+# include <linux/console.h>
+#endif
+
+#ifdef CONFIG_RTC
+# include <linux/timex.h>
+#endif
+
+#ifdef CONFIG_PROC_FS
+# include <linux/seq_file.h>
+#endif
+
+#include <asm/system.h>
+#include <asm/bootparam.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+#include <asm/platform.h>
+#include <asm/page.h>
+#include <asm/setup.h>
+
+#include <xtensa/config/system.h>
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+struct screen_info screen_info = { 0, 24, 0, 0, 0, 80, 0, 0, 0, 24, 1, 16};
+#endif
+
+#ifdef CONFIG_BLK_DEV_FD
+extern struct fd_ops no_fd_ops;
+struct fd_ops *fd_ops;
+#endif
+
+#if defined(CONFIG_BLK_DEV_IDE) || defined(CONFIG_BLK_DEV_IDE_MODULE)
+extern struct ide_ops no_ide_ops;
+struct ide_ops *ide_ops;
+#endif
+
+extern struct rtc_ops no_rtc_ops;
+struct rtc_ops *rtc_ops;
+
+#ifdef CONFIG_PC_KEYB
+extern struct kbd_ops no_kbd_ops;
+struct kbd_ops *kbd_ops;
+#endif
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern void *initrd_start;
+extern void *initrd_end;
+extern void *__initrd_start;
+extern void *__initrd_end;
+int initrd_is_mapped = 0;
+extern int initrd_below_start_ok;
+#endif
+
+unsigned char aux_device_present;
+extern unsigned long loops_per_jiffy;
+
+/* Command line specified as configuration option. */
+
+static char command_line[COMMAND_LINE_SIZE];
+
+#ifdef CONFIG_CMDLINE_BOOL
+static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE;
+#endif
+
+sysmem_info_t __initdata sysmem;
+
+#ifdef CONFIG_BLK_DEV_INITRD
+int initrd_is_mapped;
+#endif
+
+extern void init_mmu(void);
+
+/*
+ * Boot parameter parsing.
+ *
+ * The Xtensa port uses a list of variable-sized tags to pass data to
+ * the kernel. The first tag must be a BP_TAG_FIRST tag for the list
+ * to be recognised. The list is terminated with a zero-sized
+ * BP_TAG_LAST tag.
+ */
+
+typedef struct tagtable {
+ u32 tag;
+ int (*parse)(const bp_tag_t*);
+} tagtable_t;
+
+#define __tagtable(tag, fn) static tagtable_t __tagtable_##fn \
+ __attribute__((unused, __section__(".taglist"))) = { tag, fn }
+
+/* parse current tag */
+
+static int __init parse_tag_mem(const bp_tag_t *tag)
+{
+ meminfo_t *mi = (meminfo_t*)(tag->data);
+
+ if (mi->type != MEMORY_TYPE_CONVENTIONAL)
+ return -1;
+
+ if (sysmem.nr_banks >= SYSMEM_BANKS_MAX) {
+ printk(KERN_WARNING
+ "Ignoring memory bank 0x%08lx size %ldKB\n",
+ (unsigned long)mi->start,
+ (unsigned long)mi->end - (unsigned long)mi->start);
+ return -EINVAL;
+ }
+ sysmem.bank[sysmem.nr_banks].type = mi->type;
+ sysmem.bank[sysmem.nr_banks].start = PAGE_ALIGN(mi->start);
+ sysmem.bank[sysmem.nr_banks].end = mi->end & PAGE_SIZE;
+ sysmem.nr_banks++;
+
+ return 0;
+}
+
+__tagtable(BP_TAG_MEMORY, parse_tag_mem);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+
+static int __init parse_tag_initrd(const bp_tag_t* tag)
+{
+ meminfo_t* mi;
+ mi = (meminfo_t*)(tag->data);
+ initrd_start = (void*)(mi->start);
+ initrd_end = (void*)(mi->end);
+
+ return 0;
+}
+
+__tagtable(BP_TAG_INITRD, parse_tag_initrd);
+
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+static int __init parse_tag_cmdline(const bp_tag_t* tag)
+{
+ strncpy(command_line, (char*)(tag->data), COMMAND_LINE_SIZE);
+ command_line[COMMAND_LINE_SIZE - 1] = '\0';
+ return 0;
+}
+
+__tagtable(BP_TAG_COMMAND_LINE, parse_tag_cmdline);
+
+static int __init parse_bootparam(const bp_tag_t* tag)
+{
+ extern tagtable_t __tagtable_begin, __tagtable_end;
+ tagtable_t *t;
+
+ /* Boot parameters must start with a BP_TAG_FIRST tag. */
+
+ if (tag->id != BP_TAG_FIRST) {
+ printk(KERN_WARNING "Invalid boot parameters!\n");
+ return 0;
+ }
+
+ tag = (bp_tag_t*)((unsigned long)tag + sizeof(bp_tag_t) + tag->size);
+
+ /* Parse all tags. */
+
+ while (tag != NULL && tag->id != BP_TAG_LAST) {
+ for (t = &__tagtable_begin; t < &__tagtable_end; t++) {
+ if (tag->id == t->tag) {
+ t->parse(tag);
+ break;
+ }
+ }
+ if (t == &__tagtable_end)
+ printk(KERN_WARNING "Ignoring tag "
+ "0x%08x\n", tag->id);
+ tag = (bp_tag_t*)((unsigned long)(tag + 1) + tag->size);
+ }
+
+ return 0;
+}
+
+/*
+ * Initialize architecture. (Early stage)
+ */
+
+void __init init_arch(bp_tag_t *bp_start)
+{
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ initrd_start = &__initrd_start;
+ initrd_end = &__initrd_end;
+#endif
+
+ sysmem.nr_banks = 0;
+
+#ifdef CONFIG_CMDLINE_BOOL
+ strcpy(command_line, default_command_line);
+#endif
+
+ /* Parse boot parameters */
+
+ if (bp_start)
+ parse_bootparam(bp_start);
+
+ if (sysmem.nr_banks == 0) {
+ sysmem.nr_banks = 1;
+ sysmem.bank[0].start = PLATFORM_DEFAULT_MEM_START;
+ sysmem.bank[0].end = PLATFORM_DEFAULT_MEM_START
+ + PLATFORM_DEFAULT_MEM_SIZE;
+ }
+
+ /* Early hook for platforms */
+
+ platform_init(bp_start);
+
+ /* Initialize MMU. */
+
+ init_mmu();
+}
+
+/*
+ * Initialize system. Setup memory and reserve regions.
+ */
+
+extern char _end;
+extern char _stext;
+extern char _WindowVectors_text_start;
+extern char _WindowVectors_text_end;
+extern char _DebugInterruptVector_literal_start;
+extern char _DebugInterruptVector_text_end;
+extern char _KernelExceptionVector_literal_start;
+extern char _KernelExceptionVector_text_end;
+extern char _UserExceptionVector_literal_start;
+extern char _UserExceptionVector_text_end;
+extern char _DoubleExceptionVector_literal_start;
+extern char _DoubleExceptionVector_text_end;
+
+void __init setup_arch(char **cmdline_p)
+{
+ extern int mem_reserve(unsigned long, unsigned long, int);
+ extern void bootmem_init(void);
+
+ memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
+ saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
+ *cmdline_p = command_line;
+
+ /* Reserve some memory regions */
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start < initrd_end) {
+ initrd_is_mapped = mem_reserve(__pa(initrd_start),
+ __pa(initrd_end), 0);
+ initrd_below_start_ok = 1;
+ } else {
+ initrd_start = 0;
+ }
+#endif
+
+ mem_reserve(__pa(&_stext),__pa(&_end), 1);
+
+ mem_reserve(__pa(&_WindowVectors_text_start),
+ __pa(&_WindowVectors_text_end), 0);
+
+ mem_reserve(__pa(&_DebugInterruptVector_literal_start),
+ __pa(&_DebugInterruptVector_text_end), 0);
+
+ mem_reserve(__pa(&_KernelExceptionVector_literal_start),
+ __pa(&_KernelExceptionVector_text_end), 0);
+
+ mem_reserve(__pa(&_UserExceptionVector_literal_start),
+ __pa(&_UserExceptionVector_text_end), 0);
+
+ mem_reserve(__pa(&_DoubleExceptionVector_literal_start),
+ __pa(&_DoubleExceptionVector_text_end), 0);
+
+ bootmem_init();
+
+ platform_setup(cmdline_p);
+
+
+ paging_init();
+
+#ifdef CONFIG_VT
+# if defined(CONFIG_VGA_CONSOLE)
+ conswitchp = &vga_con;
+# elif defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+# endif
+#endif
+
+#if CONFIG_PCI
+ platform_pcibios_init();
+#endif
+}
+
+void machine_restart(char * cmd)
+{
+ platform_restart();
+}
+
+void machine_halt(void)
+{
+ platform_halt();
+ while (1);
+}
+
+void machine_power_off(void)
+{
+ platform_power_off();
+ while (1);
+}
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Display some core information through /proc/cpuinfo.
+ */
+
+static int
+c_show(struct seq_file *f, void *slot)
+{
+ /* high-level stuff */
+ seq_printf(f,"processor\t: 0\n"
+ "vendor_id\t: Tensilica\n"
+ "model\t\t: Xtensa " XCHAL_HW_RELEASE_NAME "\n"
+ "core ID\t\t: " XCHAL_CORE_ID "\n"
+ "build ID\t: 0x%x\n"
+ "byte order\t: %s\n"
+ "cpu MHz\t\t: %lu.%02lu\n"
+ "bogomips\t: %lu.%02lu\n",
+ XCHAL_BUILD_UNIQUE_ID,
+ XCHAL_HAVE_BE ? "big" : "little",
+ CCOUNT_PER_JIFFY/(1000000/HZ),
+ (CCOUNT_PER_JIFFY/(10000/HZ)) % 100,
+ loops_per_jiffy/(500000/HZ),
+ (loops_per_jiffy/(5000/HZ)) % 100);
+
+ seq_printf(f,"flags\t\t: "
+#if XCHAL_HAVE_NMI
+ "nmi "
+#endif
+#if XCHAL_HAVE_DEBUG
+ "debug "
+# if XCHAL_HAVE_OCD
+ "ocd "
+# endif
+#endif
+#if XCHAL_HAVE_DENSITY
+ "density "
+#endif
+#if XCHAL_HAVE_BOOLEANS
+ "boolean "
+#endif
+#if XCHAL_HAVE_LOOPS
+ "loop "
+#endif
+#if XCHAL_HAVE_NSA
+ "nsa "
+#endif
+#if XCHAL_HAVE_MINMAX
+ "minmax "
+#endif
+#if XCHAL_HAVE_SEXT
+ "sext "
+#endif
+#if XCHAL_HAVE_CLAMPS
+ "clamps "
+#endif
+#if XCHAL_HAVE_MAC16
+ "mac16 "
+#endif
+#if XCHAL_HAVE_MUL16
+ "mul16 "
+#endif
+#if XCHAL_HAVE_MUL32
+ "mul32 "
+#endif
+#if XCHAL_HAVE_MUL32_HIGH
+ "mul32h "
+#endif
+#if XCHAL_HAVE_FP
+ "fpu "
+#endif
+ "\n");
+
+ /* Registers. */
+ seq_printf(f,"physical aregs\t: %d\n"
+ "misc regs\t: %d\n"
+ "ibreak\t\t: %d\n"
+ "dbreak\t\t: %d\n",
+ XCHAL_NUM_AREGS,
+ XCHAL_NUM_MISC_REGS,
+ XCHAL_NUM_IBREAK,
+ XCHAL_NUM_DBREAK);
+
+
+ /* Interrupt. */
+ seq_printf(f,"num ints\t: %d\n"
+ "ext ints\t: %d\n"
+ "int levels\t: %d\n"
+ "timers\t\t: %d\n"
+ "debug level\t: %d\n",
+ XCHAL_NUM_INTERRUPTS,
+ XCHAL_NUM_EXTINTERRUPTS,
+ XCHAL_NUM_INTLEVELS,
+ XCHAL_NUM_TIMERS,
+ XCHAL_DEBUGLEVEL);
+
+ /* Coprocessors */
+#if XCHAL_HAVE_CP
+ seq_printf(f, "coprocessors\t: %d\n", XCHAL_CP_NUM);
+#else
+ seq_printf(f, "coprocessors\t: none\n");
+#endif
+
+ /* {I,D}{RAM,ROM} and XLMI */
+ seq_printf(f,"inst ROMs\t: %d\n"
+ "inst RAMs\t: %d\n"
+ "data ROMs\t: %d\n"
+ "data RAMs\t: %d\n"
+ "XLMI ports\t: %d\n",
+ XCHAL_NUM_IROM,
+ XCHAL_NUM_IRAM,
+ XCHAL_NUM_DROM,
+ XCHAL_NUM_DRAM,
+ XCHAL_NUM_XLMI);
+
+ /* Cache */
+ seq_printf(f,"icache line size: %d\n"
+ "icache ways\t: %d\n"
+ "icache size\t: %d\n"
+ "icache flags\t: "
+#if XCHAL_ICACHE_LINE_LOCKABLE
+ "lock"
+#endif
+ "\n"
+ "dcache line size: %d\n"
+ "dcache ways\t: %d\n"
+ "dcache size\t: %d\n"
+ "dcache flags\t: "
+#if XCHAL_DCACHE_IS_WRITEBACK
+ "writeback"
+#endif
+#if XCHAL_DCACHE_LINE_LOCKABLE
+ "lock"
+#endif
+ "\n",
+ XCHAL_ICACHE_LINESIZE,
+ XCHAL_ICACHE_WAYS,
+ XCHAL_ICACHE_SIZE,
+ XCHAL_DCACHE_LINESIZE,
+ XCHAL_DCACHE_WAYS,
+ XCHAL_DCACHE_SIZE);
+
+ /* MMU */
+ seq_printf(f,"ASID bits\t: %d\n"
+ "ASID invalid\t: %d\n"
+ "ASID kernel\t: %d\n"
+ "rings\t\t: %d\n"
+ "itlb ways\t: %d\n"
+ "itlb AR ways\t: %d\n"
+ "dtlb ways\t: %d\n"
+ "dtlb AR ways\t: %d\n",
+ XCHAL_MMU_ASID_BITS,
+ XCHAL_MMU_ASID_INVALID,
+ XCHAL_MMU_ASID_KERNEL,
+ XCHAL_MMU_RINGS,
+ XCHAL_ITLB_WAYS,
+ XCHAL_ITLB_ARF_WAYS,
+ XCHAL_DTLB_WAYS,
+ XCHAL_DTLB_ARF_WAYS);
+
+ return 0;
+}
+
+/*
+ * We show only CPU #0 info.
+ */
+static void *
+c_start(struct seq_file *f, loff_t *pos)
+{
+ return (void *) ((*pos == 0) ? (void *)1 : NULL);
+}
+
+static void *
+c_next(struct seq_file *f, void *v, loff_t *pos)
+{
+ return NULL;
+}
+
+static void
+c_stop(struct seq_file *f, void *v)
+{
+}
+
+struct seq_operations cpuinfo_op =
+{
+ start: c_start,
+ next: c_next,
+ stop: c_stop,
+ show: c_show
+};
+
+#endif /* CONFIG_PROC_FS */
+
diff --git a/arch/xtensa/kernel/signal.c b/arch/xtensa/kernel/signal.c
new file mode 100644
index 000000000000..df6e1e17b096
--- /dev/null
+++ b/arch/xtensa/kernel/signal.c
@@ -0,0 +1,713 @@
+// TODO coprocessor stuff
+/*
+ * linux/arch/xtensa/kernel/signal.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ * 1997-11-28 Modified for POSIX.1b signals by Richard Henderson
+ *
+ * Joe Taylor <joe@tensilica.com>
+ * Chris Zankel <chris@zankel.net>
+ *
+ *
+ *
+ */
+
+#include <xtensa/config/core.h>
+#include <xtensa/hal.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/wait.h>
+#include <linux/ptrace.h>
+#include <linux/unistd.h>
+#include <linux/stddef.h>
+#include <linux/personality.h>
+#include <asm/ucontext.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+#define DEBUG_SIG 0
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options,
+ struct rusage * ru);
+asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+
+extern struct task_struct *coproc_owners[];
+
+
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+
+int sys_sigsuspend(struct pt_regs *regs)
+{
+ old_sigset_t mask = (old_sigset_t) regs->areg[3];
+ sigset_t saveset;
+
+ mask &= _BLOCKABLE;
+ spin_lock_irq(&current->sighand->siglock);
+ saveset = current->blocked;
+ siginitset(&current->blocked, mask);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ regs->areg[2] = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage int
+sys_rt_sigsuspend(struct pt_regs *regs)
+{
+ sigset_t *unewset = (sigset_t *) regs->areg[4];
+ size_t sigsetsize = (size_t) regs->areg[3];
+ 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(&current->sighand->siglock);
+ saveset = current->blocked;
+ current->blocked = newset;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ regs->areg[2] = -EINTR;
+ while (1) {
+ current->state = TASK_INTERRUPTIBLE;
+ schedule();
+ if (do_signal(regs, &saveset))
+ return -EINTR;
+ }
+}
+
+asmlinkage 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;
+}
+
+asmlinkage int
+sys_sigaltstack(struct pt_regs *regs)
+{
+ const stack_t *uss = (stack_t *) regs->areg[4];
+ stack_t *uoss = (stack_t *) regs->areg[3];
+
+ if (regs->depc > 64)
+ panic ("Double exception sys_sigreturn\n");
+
+
+ return do_sigaltstack(uss, uoss, regs->areg[1]);
+}
+
+
+/*
+ * Do a signal return; undo the signal stack.
+ */
+
+struct sigframe
+{
+ struct sigcontext sc;
+ struct _cpstate cpstate;
+ unsigned long extramask[_NSIG_WORDS-1];
+ unsigned char retcode[6];
+ unsigned int reserved[4]; /* Reserved area for chaining */
+ unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+struct rt_sigframe
+{
+ struct siginfo info;
+ struct ucontext uc;
+ struct _cpstate cpstate;
+ unsigned char retcode[6];
+ unsigned int reserved[4]; /* Reserved area for chaining */
+ unsigned int window[4]; /* Window of 4 registers for initial context */
+};
+
+extern void release_all_cp (struct task_struct *);
+
+
+// FIXME restore_cpextra
+static inline int
+restore_cpextra (struct _cpstate *buf)
+{
+#if 0
+ /* The signal handler may have used coprocessors in which
+ * case they are still enabled. We disable them to force a
+ * reloading of the original task's CP state by the lazy
+ * context-switching mechanisms of CP exception handling.
+ * Also, we essentially discard any coprocessor state that the
+ * signal handler created. */
+
+ struct task_struct *tsk = current;
+ release_all_cp(tsk);
+ return __copy_from_user(tsk->thread.cpextra, buf, TOTAL_CPEXTRA_SIZE);
+#endif
+ return 0;
+}
+
+/* Note: We don't copy double exception 'tregs', we have to finish double exc. first before we return to signal handler! This dbl.exc.handler might cause another double exception, but I think we are fine as the situation is the same as if we had returned to the signal handerl and got an interrupt immediately...
+ */
+
+
+static int
+restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+{
+ struct thread_struct *thread;
+ unsigned int err = 0;
+ unsigned long ps;
+ struct _cpstate *buf;
+
+#define COPY(x) err |= __get_user(regs->x, &sc->sc_##x)
+ COPY(pc);
+ COPY(depc);
+ COPY(wmask);
+ COPY(lbeg);
+ COPY(lend);
+ COPY(lcount);
+ COPY(sar);
+ COPY(windowbase);
+ COPY(windowstart);
+#undef COPY
+
+ /* For PS, restore only PS.CALLINC.
+ * Assume that all other bits are either the same as for the signal
+ * handler, or the user mode value doesn't matter (e.g. PS.OWB).
+ */
+ err |= __get_user(ps, &sc->sc_ps);
+ regs->ps = (regs->ps & ~XCHAL_PS_CALLINC_MASK)
+ | (ps & XCHAL_PS_CALLINC_MASK);
+
+ /* Additional corruption checks */
+
+ if ((regs->windowbase >= (XCHAL_NUM_AREGS/4))
+ || ((regs->windowstart & ~((1<<(XCHAL_NUM_AREGS/4)) - 1)) != 0) )
+ err = 1;
+ if ((regs->lcount > 0)
+ && ((regs->lbeg > TASK_SIZE) || (regs->lend > TASK_SIZE)) )
+ err = 1;
+
+ /* Restore extended register state.
+ * See struct thread_struct in processor.h.
+ */
+ thread = &current->thread;
+
+ err |= __copy_from_user (regs->areg, sc->sc_areg, XCHAL_NUM_AREGS*4);
+ err |= __get_user(buf, &sc->sc_cpstate);
+ if (buf) {
+ if (verify_area(VERIFY_READ, buf, sizeof(*buf)))
+ goto badframe;
+ err |= restore_cpextra(buf);
+ }
+
+ regs->syscall = -1; /* disable syscall checks */
+ return err;
+
+badframe:
+ return 1;
+}
+
+static inline void
+flush_my_cpstate(struct task_struct *tsk)
+{
+ unsigned long flags;
+ local_irq_save(flags);
+
+#if 0 // FIXME
+ for (i = 0; i < XCHAL_CP_NUM; i++) {
+ if (tsk == coproc_owners[i]) {
+ xthal_validate_cp(i);
+ xthal_save_cpregs(tsk->thread.cpregs_ptr[i], i);
+
+ /* Invalidate and "disown" the cp to allow
+ * callers the chance to reset cp state in the
+ * task_struct. */
+
+ xthal_invalidate_cp(i);
+ coproc_owners[i] = 0;
+ }
+ }
+#endif
+ local_irq_restore(flags);
+}
+
+/* Return codes:
+ 0: nothing saved
+ 1: stuff to save, successful
+ -1: stuff to save, error happened
+*/
+static int
+save_cpextra (struct _cpstate *buf)
+{
+#if (XCHAL_EXTRA_SA_SIZE == 0) && (XCHAL_CP_NUM == 0)
+ return 0;
+#else
+
+ /* FIXME: If a task has never used a coprocessor, there is
+ * no need to save and restore anything. Tracking this
+ * information would allow us to optimize this section.
+ * Perhaps we can use current->used_math or (current->flags &
+ * PF_USEDFPU) or define a new field in the thread
+ * structure. */
+
+ /* We flush any live, task-owned cp state to the task_struct,
+ * then copy it all to the sigframe. Then we clear all
+ * cp/extra state in the task_struct, effectively
+ * clearing/resetting all cp/extra state for the signal
+ * handler (cp-exception handling will load these new values
+ * into the cp/extra registers.) This step is important for
+ * things like a floating-point cp, where the OS must reset
+ * the FCR to the default rounding mode. */
+
+ int err = 0;
+ struct task_struct *tsk = current;
+
+ flush_my_cpstate(tsk);
+ /* Note that we just copy everything: 'extra' and 'cp' state together.*/
+ err |= __copy_to_user(buf, tsk->thread.cp_save, XTENSA_CP_EXTRA_SIZE);
+ memset(tsk->thread.cp_save, 0, XTENSA_CP_EXTRA_SIZE);
+
+#if (XTENSA_CP_EXTRA_SIZE == 0)
+#error Sanity check on memset above, cpextra_size should not be zero.
+#endif
+
+ return err ? -1 : 1;
+#endif
+}
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct _cpstate *cpstate,
+ struct pt_regs *regs, unsigned long mask)
+{
+ struct thread_struct *thread;
+ int err = 0;
+
+//printk("setup_sigcontext\n");
+#define COPY(x) err |= __put_user(regs->x, &sc->sc_##x)
+ COPY(pc);
+ COPY(ps);
+ COPY(depc);
+ COPY(wmask);
+ COPY(lbeg);
+ COPY(lend);
+ COPY(lcount);
+ COPY(sar);
+ COPY(windowbase);
+ COPY(windowstart);
+#undef COPY
+
+ /* Save extended register state.
+ * See struct thread_struct in processor.h.
+ */
+ thread = &current->thread;
+ err |= __copy_to_user (sc->sc_areg, regs->areg, XCHAL_NUM_AREGS * 4);
+ err |= save_cpextra(cpstate);
+ err |= __put_user(err ? NULL : cpstate, &sc->sc_cpstate);
+ /* non-iBCS2 extensions.. */
+ err |= __put_user(mask, &sc->oldmask);
+
+ return err;
+}
+
+asmlinkage int sys_sigreturn(struct pt_regs *regs)
+{
+ struct sigframe *frame = (struct sigframe *)regs->areg[1];
+ sigset_t set;
+ if (regs->depc > 64)
+ panic ("Double exception sys_sigreturn\n");
+
+ 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(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->sc))
+ goto badframe;
+ return regs->areg[2];
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+asmlinkage int sys_rt_sigreturn(struct pt_regs *regs)
+{
+ struct rt_sigframe *frame = (struct rt_sigframe *)regs->areg[1];
+ sigset_t set;
+ stack_t st;
+ int ret;
+ if (regs->depc > 64)
+ {
+ printk("!!!!!!! DEPC !!!!!!!\n");
+ return 0;
+ }
+
+ 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(&current->sighand->siglock);
+ current->blocked = set;
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+
+ if (restore_sigcontext(regs, &frame->uc.uc_mcontext))
+ goto badframe;
+ ret = regs->areg[2];
+
+ 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->areg[1]);
+
+ return ret;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+/*
+ * Set up a signal frame.
+ */
+
+/*
+ * Determine which stack to use..
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
+{
+ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp))
+ sp = current->sas_ss_sp + current->sas_ss_size;
+
+ return (void *)((sp - frame_size) & -16ul);
+}
+
+#define USE_SIGRETURN 0
+#define USE_RT_SIGRETURN 1
+
+static int
+gen_return_code(unsigned char *codemem, unsigned int use_rt_sigreturn)
+{
+ unsigned int retcall;
+ int err = 0;
+
+#if 0
+ /* Ignoring SA_RESTORER for now; it's supposed to be obsolete,
+ * and the xtensa glibc doesn't use it.
+ */
+ if (ka->sa.sa_flags & SA_RESTORER) {
+ regs->pr = (unsigned long) ka->sa.sa_restorer;
+ } else
+#endif /* 0 */
+ {
+
+#if (__NR_sigreturn > 255) || (__NR_rt_sigreturn > 255)
+
+/* The 12-bit immediate is really split up within the 24-bit MOVI
+ * instruction. As long as the above system call numbers fit within
+ * 8-bits, the following code works fine. See the Xtensa ISA for
+ * details.
+ */
+
+#error Generating the MOVI instruction below breaks!
+#endif
+
+ retcall = use_rt_sigreturn ? __NR_rt_sigreturn : __NR_sigreturn;
+
+#ifdef __XTENSA_EB__ /* Big Endian version */
+ /* Generate instruction: MOVI a2, retcall */
+ err |= __put_user(0x22, &codemem[0]);
+ err |= __put_user(0x0a, &codemem[1]);
+ err |= __put_user(retcall, &codemem[2]);
+ /* Generate instruction: SYSCALL */
+ err |= __put_user(0x00, &codemem[3]);
+ err |= __put_user(0x05, &codemem[4]);
+ err |= __put_user(0x00, &codemem[5]);
+
+#elif defined __XTENSA_EL__ /* Little Endian version */
+ /* Generate instruction: MOVI a2, retcall */
+ err |= __put_user(0x22, &codemem[0]);
+ err |= __put_user(0xa0, &codemem[1]);
+ err |= __put_user(retcall, &codemem[2]);
+ /* Generate instruction: SYSCALL */
+ err |= __put_user(0x00, &codemem[3]);
+ err |= __put_user(0x50, &codemem[4]);
+ err |= __put_user(0x00, &codemem[5]);
+#else
+#error Must use compiler for Xtensa processors.
+#endif
+ }
+
+ /* Flush generated code out of the data cache */
+
+ if (err == 0)
+ __flush_invalidate_cache_range((unsigned long)codemem, 6UL);
+
+ return err;
+}
+
+static void
+set_thread_state(struct pt_regs *regs, void *stack, unsigned char *retaddr,
+ void *handler, unsigned long arg1, void *arg2, void *arg3)
+{
+ /* Set up registers for signal handler */
+ start_thread(regs, (unsigned long) handler, (unsigned long) stack);
+
+ /* Set up a stack frame for a call4
+ * Note: PS.CALLINC is set to one by start_thread
+ */
+ regs->areg[4] = (((unsigned long) retaddr) & 0x3fffffff) | 0x40000000;
+ regs->areg[6] = arg1;
+ regs->areg[7] = (unsigned long) arg2;
+ regs->areg[8] = (unsigned long) arg3;
+}
+
+static void setup_frame(int sig, struct k_sigaction *ka,
+ sigset_t *set, struct pt_regs *regs)
+{
+ struct sigframe *frame;
+ int err = 0;
+ int signal;
+
+ frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+ if (regs->depc > 64)
+ {
+ printk("!!!!!!! DEPC !!!!!!!\n");
+ return;
+ }
+
+
+ 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 |= setup_sigcontext(&frame->sc, &frame->cpstate, regs, set->sig[0]);
+
+ if (_NSIG_WORDS > 1) {
+ err |= __copy_to_user(frame->extramask, &set->sig[1],
+ sizeof(frame->extramask));
+ }
+
+ /* Create sys_sigreturn syscall in stack frame */
+ err |= gen_return_code(frame->retcode, USE_SIGRETURN);
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Create signal handler execution context.
+ * Return context not modified until this point.
+ */
+ set_thread_state(regs, frame, frame->retcode,
+ ka->sa.sa_handler, signal, &frame->sc, NULL);
+
+ /* Set access mode to USER_DS. Nomenclature is outdated, but
+ * functionality is used in uaccess.h
+ */
+ set_fs(USER_DS);
+
+
+#if DEBUG_SIG
+ printk("SIG deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+ current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, 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 *frame;
+ int err = 0;
+ int signal;
+
+ frame = get_sigframe(ka, regs->areg[1], sizeof(*frame));
+ if (regs->depc > 64)
+ panic ("Double exception sys_sigreturn\n");
+
+ 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 |= copy_siginfo_to_user(&frame->info, info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __put_user((void *)current->sas_ss_sp,
+ &frame->uc.uc_stack.ss_sp);
+ err |= __put_user(sas_ss_flags(regs->areg[1]),
+ &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, &frame->cpstate,
+ regs, set->sig[0]);
+ err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ /* Create sys_rt_sigreturn syscall in stack frame */
+ err |= gen_return_code(frame->retcode, USE_RT_SIGRETURN);
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Create signal handler execution context.
+ * Return context not modified until this point.
+ */
+ set_thread_state(regs, frame, frame->retcode,
+ ka->sa.sa_handler, signal, &frame->info, &frame->uc);
+
+ /* Set access mode to USER_DS. Nomenclature is outdated, but
+ * functionality is used in uaccess.h
+ */
+ set_fs(USER_DS);
+
+#if DEBUG_SIG
+ printk("SIG rt deliver (%s:%d): signal=%d sp=%p pc=%08x\n",
+ current->comm, current->pid, signal, frame, regs->pc);
+#endif
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV, current);
+}
+
+
+
+/*
+ * 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.
+ *
+ * Note that we go through the signals twice: once to check the signals that
+ * the kernel can handle, and then we build all the user-level signal handling
+ * stack-frames in one go after that.
+ */
+int do_signal(struct pt_regs *regs, sigset_t *oldset)
+{
+ siginfo_t info;
+ int signr;
+ struct k_sigaction ka;
+
+ if (!oldset)
+ oldset = &current->blocked;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+ /* Are we from a system call? */
+ if (regs->syscall >= 0) {
+ /* If so, check system call restarting.. */
+ switch (regs->areg[2]) {
+ case ERESTARTNOHAND:
+ case ERESTART_RESTARTBLOCK:
+ regs->areg[2] = -EINTR;
+ break;
+
+ case ERESTARTSYS:
+ if (!(ka.sa.sa_flags & SA_RESTART)) {
+ regs->areg[2] = -EINTR;
+ break;
+ }
+ /* fallthrough */
+ case ERESTARTNOINTR:
+ regs->areg[2] = regs->syscall;
+ regs->pc -= 3;
+ }
+ }
+
+ if (signr == 0)
+ return 0; /* no signals delivered */
+
+ /* Whee! Actually deliver the signal. */
+
+ /* Set up the stack frame */
+ if (ka.sa.sa_flags & SA_SIGINFO)
+ setup_rt_frame(signr, &ka, &info, oldset, regs);
+ else
+ setup_frame(signr, &ka, oldset, regs);
+
+ if (ka.sa.sa_flags & SA_ONESHOT)
+ ka.sa.sa_handler = SIG_DFL;
+
+ if (!(ka.sa.sa_flags & SA_NODEFER)) {
+ spin_lock_irq(&current->sighand->siglock);
+ sigorsets(&current->blocked, &current->blocked, &ka.sa.sa_mask);
+ sigaddset(&current->blocked, signr);
+ recalc_sigpending();
+ spin_unlock_irq(&current->sighand->siglock);
+ }
+ return 1;
+}
diff --git a/arch/xtensa/kernel/syscalls.c b/arch/xtensa/kernel/syscalls.c
new file mode 100644
index 000000000000..f20c6494c518
--- /dev/null
+++ b/arch/xtensa/kernel/syscalls.c
@@ -0,0 +1,269 @@
+/*
+ * arch/xtensa/kernel/syscall.c
+ *
+ * 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 - 2005 Tensilica Inc.
+ * Copyright (C) 2000 Silicon Graphics, Inc.
+ * Copyright (C) 1995 - 2000 by Ralf Baechle
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Chris Zankel <chris@zankel.net>
+ * Kevin Chea
+ *
+ */
+
+#define DEBUG 0
+
+#include <linux/config.h>
+#include <linux/linkage.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/mman.h>
+#include <linux/sched.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/unistd.h>
+#include <linux/stringify.h>
+#include <linux/syscalls.h>
+#include <linux/sem.h>
+#include <linux/msg.h>
+#include <linux/shm.h>
+#include <linux/errno.h>
+#include <asm/ptrace.h>
+#include <asm/signal.h>
+#include <asm/uaccess.h>
+#include <asm/hardirq.h>
+#include <asm/mman.h>
+#include <asm/shmparam.h>
+#include <asm/page.h>
+
+extern void do_syscall_trace(void);
+typedef int (*syscall_t)(void *a0,...);
+extern syscall_t sys_call_table[];
+extern unsigned char sys_narg_table[];
+
+/*
+ * sys_pipe() is the normal C calling standard for creating a pipe. It's not
+ * the way unix traditional does this, though.
+ */
+
+int sys_pipe(int __user *userfds)
+{
+ int fd[2];
+ int error;
+
+ error = do_pipe(fd);
+ if (!error) {
+ if (copy_to_user(userfds, fd, 2 * sizeof(int)))
+ error = -EFAULT;
+ }
+ return error;
+}
+
+/*
+ * Common code for old and new mmaps.
+ */
+long sys_mmap(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(&current->mm->mmap_sem);
+ error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ up_write(&current->mm->mmap_sem);
+
+ if (file)
+ fput(file);
+out:
+ return error;
+}
+
+int sys_clone(struct pt_regs *regs)
+{
+ unsigned long clone_flags;
+ unsigned long newsp;
+ int __user *parent_tidptr, *child_tidptr;
+ clone_flags = regs->areg[4];
+ newsp = regs->areg[3];
+ parent_tidptr = (int __user *)regs->areg[5];
+ child_tidptr = (int __user *)regs->areg[6];
+ if (!newsp)
+ newsp = regs->areg[1];
+ return do_fork(clone_flags,newsp,regs,0,parent_tidptr,child_tidptr);
+}
+
+/*
+ * sys_execve() executes a new program.
+ */
+
+int sys_execve(struct pt_regs *regs)
+{
+ int error;
+ char * filename;
+
+ filename = getname((char *) (long)regs->areg[5]);
+ error = PTR_ERR(filename);
+ if (IS_ERR(filename))
+ goto out;
+ error = do_execve(filename, (char **) (long)regs->areg[3],
+ (char **) (long)regs->areg[4], regs);
+ putname(filename);
+
+out:
+ return error;
+}
+
+int sys_uname(struct old_utsname * name)
+{
+ if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
+ return 0;
+ return -EFAULT;
+}
+
+/*
+ * Build the string table for the builtin "poor man's strace".
+ */
+
+#if DEBUG
+#define SYSCALL(fun, narg) #fun,
+static char *sfnames[] = {
+#include "syscalls.h"
+};
+#undef SYS
+#endif
+
+void system_call (struct pt_regs *regs)
+{
+ syscall_t syscall;
+ unsigned long parm0, parm1, parm2, parm3, parm4, parm5;
+ int nargs, res;
+ unsigned int syscallnr;
+ int ps;
+
+#if DEBUG
+ int i;
+ unsigned long parms[6];
+ char *sysname;
+#endif
+
+ regs->syscall = regs->areg[2];
+
+ do_syscall_trace();
+
+ /* Have to load after syscall_trace because strace
+ * sometimes changes regs->syscall.
+ */
+ syscallnr = regs->syscall;
+
+ parm0 = parm1 = parm2 = parm3 = parm4 = parm5 = 0;
+
+ /* Restore interrupt level to syscall invoker's.
+ * If this were in assembly, we wouldn't disable
+ * interrupts in the first place:
+ */
+ local_save_flags (ps);
+ local_irq_restore((ps & ~XCHAL_PS_INTLEVEL_MASK) |
+ (regs->ps & XCHAL_PS_INTLEVEL_MASK) );
+
+ if (syscallnr > __NR_Linux_syscalls) {
+ regs->areg[2] = -ENOSYS;
+ return;
+ }
+
+ syscall = sys_call_table[syscallnr];
+ nargs = sys_narg_table[syscallnr];
+
+ if (syscall == NULL) {
+ regs->areg[2] = -ENOSYS;
+ return;
+ }
+
+ /* There shouldn't be more than six arguments in the table! */
+
+ if (nargs > 6)
+ panic("Internal error - too many syscall arguments (%d)!\n",
+ nargs);
+
+ /* Linux takes system-call arguments in registers. The ABI
+ * and Xtensa software conventions require the system-call
+ * number in a2. If an argument exists in a2, we move it to
+ * the next available register. Note that for improved
+ * efficiency, we do NOT shift all parameters down one
+ * register to maintain the original order.
+ *
+ * At best case (zero arguments), we just write the syscall
+ * number to a2. At worst case (1 to 6 arguments), we move
+ * the argument in a2 to the next available register, then
+ * write the syscall number to a2.
+ *
+ * For clarity, the following truth table enumerates all
+ * possibilities.
+ *
+ * arguments syscall number arg0, arg1, arg2, arg3, arg4, arg5
+ * --------- -------------- ----------------------------------
+ * 0 a2
+ * 1 a2 a3
+ * 2 a2 a4, a3
+ * 3 a2 a5, a3, a4
+ * 4 a2 a6, a3, a4, a5
+ * 5 a2 a7, a3, a4, a5, a6
+ * 6 a2 a8, a3, a4, a5, a6, a7
+ */
+ if (nargs) {
+ parm0 = regs->areg[nargs+2];
+ parm1 = regs->areg[3];
+ parm2 = regs->areg[4];
+ parm3 = regs->areg[5];
+ parm4 = regs->areg[6];
+ parm5 = regs->areg[7];
+ } else /* nargs == 0 */
+ parm0 = (unsigned long) regs;
+
+#if DEBUG
+ parms[0] = parm0;
+ parms[1] = parm1;
+ parms[2] = parm2;
+ parms[3] = parm3;
+ parms[4] = parm4;
+ parms[5] = parm5;
+
+ sysname = sfnames[syscallnr];
+ if (strncmp(sysname, "sys_", 4) == 0)
+ sysname = sysname + 4;
+
+ printk("\017SYSCALL:I:%x:%d:%s %s(", regs->pc, current->pid,
+ current->comm, sysname);
+ for (i = 0; i < nargs; i++)
+ printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+ printk(")\n");
+#endif
+
+ res = syscall((void *)parm0, parm1, parm2, parm3, parm4, parm5);
+
+#if DEBUG
+ printk("\017SYSCALL:O:%d:%s %s(",current->pid, current->comm, sysname);
+ for (i = 0; i < nargs; i++)
+ printk((i>0) ? ", %#lx" : "%#lx", parms[i]);
+ if (res < 4096)
+ printk(") = %d\n", res);
+ else
+ printk(") = %#x\n", res);
+#endif /* DEBUG */
+
+ regs->areg[2] = res;
+ do_syscall_trace();
+}
diff --git a/arch/xtensa/kernel/syscalls.h b/arch/xtensa/kernel/syscalls.h
new file mode 100644
index 000000000000..216c10a31501
--- /dev/null
+++ b/arch/xtensa/kernel/syscalls.h
@@ -0,0 +1,247 @@
+/*
+ * arch/xtensa/kernel/syscalls.h
+ *
+ * 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, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Changes by Joe Taylor <joe@tensilica.com>
+ */
+
+/*
+ * This file is being included twice - once to build a list of all
+ * syscalls and once to build a table of how many arguments each syscall
+ * accepts. Syscalls that receive a pointer to the saved registers are
+ * marked as having zero arguments.
+ *
+ * The binary compatibility calls are in a separate list.
+ *
+ * Entry '0' used to be system_call. It's removed to disable indirect
+ * system calls for now so user tasks can't recurse. See mips'
+ * sys_syscall for a comparable example.
+ */
+
+SYSCALL(0, 0) /* 00 */
+SYSCALL(sys_exit, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_read, 3)
+SYSCALL(sys_write, 3)
+SYSCALL(sys_open, 3) /* 05 */
+SYSCALL(sys_close, 1)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_creat, 2)
+SYSCALL(sys_link, 2)
+SYSCALL(sys_unlink, 1) /* 10 */
+SYSCALL(sys_execve, 0)
+SYSCALL(sys_chdir, 1)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_mknod, 3)
+SYSCALL(sys_chmod, 2) /* 15 */
+SYSCALL(sys_lchown, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_newstat, 2)
+SYSCALL(sys_lseek, 3)
+SYSCALL(sys_getpid, 0) /* 20 */
+SYSCALL(sys_mount, 5)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_setuid, 1)
+SYSCALL(sys_getuid, 0)
+SYSCALL(sys_ni_syscall, 1) /* 25 */
+SYSCALL(sys_ptrace, 4)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_newfstat, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_utime, 2) /* 30 */
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_access, 2)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_ni_syscall, 0) /* 35 */
+SYSCALL(sys_sync, 0)
+SYSCALL(sys_kill, 2)
+SYSCALL(sys_rename, 2)
+SYSCALL(sys_mkdir, 2)
+SYSCALL(sys_rmdir, 1) /* 40 */
+SYSCALL(sys_dup, 1)
+SYSCALL(sys_pipe, 1)
+SYSCALL(sys_times, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_brk, 1) /* 45 */
+SYSCALL(sys_setgid, 1)
+SYSCALL(sys_getgid, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_geteuid, 0)
+SYSCALL(sys_getegid, 0) /* 50 */
+SYSCALL(sys_acct, 1)
+SYSCALL(sys_umount, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ioctl, 3)
+SYSCALL(sys_fcntl, 3) /* 55 */
+SYSCALL(sys_ni_syscall, 2)
+SYSCALL(sys_setpgid, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_umask, 1) /* 60 */
+SYSCALL(sys_chroot, 1)
+SYSCALL(sys_ustat, 2)
+SYSCALL(sys_dup2, 2)
+SYSCALL(sys_getppid, 0)
+SYSCALL(sys_ni_syscall, 0) /* 65 */
+SYSCALL(sys_setsid, 0)
+SYSCALL(sys_sigaction, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_setreuid, 2) /* 70 */
+SYSCALL(sys_setregid, 2)
+SYSCALL(sys_sigsuspend, 0)
+SYSCALL(sys_ni_syscall, 1)
+SYSCALL(sys_sethostname, 2)
+SYSCALL(sys_setrlimit, 2) /* 75 */
+SYSCALL(sys_getrlimit, 2)
+SYSCALL(sys_getrusage, 2)
+SYSCALL(sys_gettimeofday, 2)
+SYSCALL(sys_settimeofday, 2)
+SYSCALL(sys_getgroups, 2) /* 80 */
+SYSCALL(sys_setgroups, 2)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_symlink, 2)
+SYSCALL(sys_newlstat, 2)
+SYSCALL(sys_readlink, 3) /* 85 */
+SYSCALL(sys_uselib, 1)
+SYSCALL(sys_swapon, 2)
+SYSCALL(sys_reboot, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 6) /* 90 */
+SYSCALL(sys_munmap, 2)
+SYSCALL(sys_truncate, 2)
+SYSCALL(sys_ftruncate, 2)
+SYSCALL(sys_fchmod, 2)
+SYSCALL(sys_fchown, 3) /* 95 */
+SYSCALL(sys_getpriority, 2)
+SYSCALL(sys_setpriority, 3)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_statfs, 2)
+SYSCALL(sys_fstatfs, 2) /* 100 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 2)
+SYSCALL(sys_syslog, 3)
+SYSCALL(sys_setitimer, 3)
+SYSCALL(sys_getitimer, 2) /* 105 */
+SYSCALL(sys_newstat, 2)
+SYSCALL(sys_newlstat, 2)
+SYSCALL(sys_newfstat, 2)
+SYSCALL(sys_uname, 1)
+SYSCALL(sys_ni_syscall, 0) /* 110 */
+SYSCALL(sys_vhangup, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_wait4, 4)
+SYSCALL(sys_swapoff, 1) /* 115 */
+SYSCALL(sys_sysinfo, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_fsync, 1)
+SYSCALL(sys_sigreturn, 0)
+SYSCALL(sys_clone, 0) /* 120 */
+SYSCALL(sys_setdomainname, 2)
+SYSCALL(sys_newuname, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_adjtimex, 1)
+SYSCALL(sys_mprotect, 3) /* 125 */
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 2)
+SYSCALL(sys_init_module, 2)
+SYSCALL(sys_delete_module, 1)
+SYSCALL(sys_ni_syscall, 1) /* 130 */
+SYSCALL(sys_quotactl, 0)
+SYSCALL(sys_getpgid, 1)
+SYSCALL(sys_fchdir, 1)
+SYSCALL(sys_bdflush, 2)
+SYSCALL(sys_sysfs, 3) /* 135 */
+SYSCALL(sys_personality, 1)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_setfsuid, 1)
+SYSCALL(sys_setfsgid, 1)
+SYSCALL(sys_llseek, 5) /* 140 */
+SYSCALL(sys_getdents, 3)
+SYSCALL(sys_select, 5)
+SYSCALL(sys_flock, 2)
+SYSCALL(sys_msync, 3)
+SYSCALL(sys_readv, 3) /* 145 */
+SYSCALL(sys_writev, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 3)
+SYSCALL(sys_ni_syscall, 4) /* handled in fast syscall handler. */
+SYSCALL(sys_ni_syscall, 0) /* 150 */
+SYSCALL(sys_getsid, 1)
+SYSCALL(sys_fdatasync, 1)
+SYSCALL(sys_sysctl, 1)
+SYSCALL(sys_mlock, 2)
+SYSCALL(sys_munlock, 2) /* 155 */
+SYSCALL(sys_mlockall, 1)
+SYSCALL(sys_munlockall, 0)
+SYSCALL(sys_sched_setparam,2)
+SYSCALL(sys_sched_getparam,2)
+SYSCALL(sys_sched_setscheduler,3) /* 160 */
+SYSCALL(sys_sched_getscheduler,1)
+SYSCALL(sys_sched_yield,0)
+SYSCALL(sys_sched_get_priority_max,1)
+SYSCALL(sys_sched_get_priority_min,1)
+SYSCALL(sys_sched_rr_get_interval,2) /* 165 */
+SYSCALL(sys_nanosleep,2)
+SYSCALL(sys_mremap,4)
+SYSCALL(sys_accept, 3)
+SYSCALL(sys_bind, 3)
+SYSCALL(sys_connect, 3) /* 170 */
+SYSCALL(sys_getpeername, 3)
+SYSCALL(sys_getsockname, 3)
+SYSCALL(sys_getsockopt, 5)
+SYSCALL(sys_listen, 2)
+SYSCALL(sys_recv, 4) /* 175 */
+SYSCALL(sys_recvfrom, 6)
+SYSCALL(sys_recvmsg, 3)
+SYSCALL(sys_send, 4)
+SYSCALL(sys_sendmsg, 3)
+SYSCALL(sys_sendto, 6) /* 180 */
+SYSCALL(sys_setsockopt, 5)
+SYSCALL(sys_shutdown, 2)
+SYSCALL(sys_socket, 3)
+SYSCALL(sys_socketpair, 4)
+SYSCALL(sys_setresuid, 3) /* 185 */
+SYSCALL(sys_getresuid, 3)
+SYSCALL(sys_ni_syscall, 5)
+SYSCALL(sys_poll, 3)
+SYSCALL(sys_nfsservctl, 3)
+SYSCALL(sys_setresgid, 3) /* 190 */
+SYSCALL(sys_getresgid, 3)
+SYSCALL(sys_prctl, 5)
+SYSCALL(sys_rt_sigreturn, 0)
+SYSCALL(sys_rt_sigaction, 4)
+SYSCALL(sys_rt_sigprocmask, 4) /* 195 */
+SYSCALL(sys_rt_sigpending, 2)
+SYSCALL(sys_rt_sigtimedwait, 4)
+SYSCALL(sys_rt_sigqueueinfo, 3)
+SYSCALL(sys_rt_sigsuspend, 0)
+SYSCALL(sys_pread64, 5) /* 200 */
+SYSCALL(sys_pwrite64, 5)
+SYSCALL(sys_chown, 3)
+SYSCALL(sys_getcwd, 2)
+SYSCALL(sys_capget, 2)
+SYSCALL(sys_capset, 2) /* 205 */
+SYSCALL(sys_sigaltstack, 0)
+SYSCALL(sys_sendfile, 4)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_ni_syscall, 0)
+SYSCALL(sys_mmap, 6) /* 210 */
+SYSCALL(sys_truncate64, 2)
+SYSCALL(sys_ftruncate64, 2)
+SYSCALL(sys_stat64, 2)
+SYSCALL(sys_lstat64, 2)
+SYSCALL(sys_fstat64, 2) /* 215 */
+SYSCALL(sys_pivot_root, 2)
+SYSCALL(sys_mincore, 3)
+SYSCALL(sys_madvise, 3)
+SYSCALL(sys_getdents64, 3)
+SYSCALL(sys_ni_syscall, 0) /* 220 */
diff --git a/arch/xtensa/kernel/time.c b/arch/xtensa/kernel/time.c
new file mode 100644
index 000000000000..e07287db5a40
--- /dev/null
+++ b/arch/xtensa/kernel/time.c
@@ -0,0 +1,227 @@
+/*
+ * arch/xtensa/kernel/time.c
+ *
+ * Timer and clock 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) 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/timex.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/profile.h>
+#include <linux/delay.h>
+
+#include <asm/timex.h>
+#include <asm/platform.h>
+
+
+extern volatile unsigned long wall_jiffies;
+
+u64 jiffies_64 = INITIAL_JIFFIES;
+EXPORT_SYMBOL(jiffies_64);
+
+spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;
+EXPORT_SYMBOL(rtc_lock);
+
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+unsigned long ccount_per_jiffy; /* per 1/HZ */
+unsigned long ccount_nsec; /* nsec per ccount increment */
+#endif
+
+unsigned int last_ccount_stamp;
+static long last_rtc_update = 0;
+
+/*
+ * Scheduler clock - returns current tim in nanosec units.
+ */
+
+unsigned long long sched_clock(void)
+{
+ return (unsigned long long)jiffies * (1000000000 / HZ);
+}
+
+static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct irqaction timer_irqaction = {
+ .handler = timer_interrupt,
+ .flags = SA_INTERRUPT,
+ .name = "timer",
+};
+
+void __init time_init(void)
+{
+ time_t sec_o, sec_n = 0;
+
+ /* The platform must provide a function to calibrate the processor
+ * speed for the CALIBRATE.
+ */
+
+#if CONFIG_XTENSA_CALIBRATE_CCOUNT
+ printk("Calibrating CPU frequency ");
+ platform_calibrate_ccount();
+ printk("%d.%02d MHz\n", (int)ccount_per_jiffy/(1000000/HZ),
+ (int)(ccount_per_jiffy/(10000/HZ))%100);
+#endif
+
+ /* Set time from RTC (if provided) */
+
+ if (platform_get_rtc_time(&sec_o) == 0)
+ while (platform_get_rtc_time(&sec_n))
+ if (sec_o != sec_n)
+ break;
+
+ xtime.tv_nsec = 0;
+ last_rtc_update = xtime.tv_sec = sec_n;
+ last_ccount_stamp = get_ccount();
+
+ set_normalized_timespec(&wall_to_monotonic,
+ -xtime.tv_sec, -xtime.tv_nsec);
+
+ /* Initialize the linux timer interrupt. */
+
+ setup_irq(LINUX_TIMER_INT, &timer_irqaction);
+ set_linux_timer(get_ccount() + CCOUNT_PER_JIFFY);
+}
+
+
+int do_settimeofday(struct timespec *tv)
+{
+ time_t wtm_sec, sec = tv->tv_sec;
+ long wtm_nsec, nsec = tv->tv_nsec;
+ unsigned long ccount;
+
+ 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!
+ */
+ ccount = get_ccount();
+ nsec -= (ccount - last_ccount_stamp) * CCOUNT_NSEC;
+ nsec -= (jiffies - wall_jiffies) * CCOUNT_PER_JIFFY * CCOUNT_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);
+ return 0;
+}
+
+EXPORT_SYMBOL(do_settimeofday);
+
+
+void do_gettimeofday(struct timeval *tv)
+{
+ unsigned long flags;
+ unsigned long sec, usec, delta, lost, seq;
+
+ do {
+ seq = read_seqbegin_irqsave(&xtime_lock, flags);
+
+ delta = get_ccount() - last_ccount_stamp;
+ sec = xtime.tv_sec;
+ usec = (xtime.tv_nsec / NSEC_PER_USEC);
+
+ lost = jiffies - wall_jiffies;
+
+ } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
+
+ usec += lost * (1000000UL/HZ) + (delta * CCOUNT_NSEC) / NSEC_PER_USEC;
+ for (; usec >= 1000000; sec++, usec -= 1000000)
+ ;
+
+ tv->tv_sec = sec;
+ tv->tv_usec = usec;
+}
+
+EXPORT_SYMBOL(do_gettimeofday);
+
+/*
+ * The timer interrupt is called HZ times per second.
+ */
+
+irqreturn_t timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+
+ unsigned long next;
+
+ next = get_linux_timer();
+
+again:
+ while ((signed long)(get_ccount() - next) > 0) {
+
+ profile_tick(CPU_PROFILING, regs);
+#ifndef CONFIG_SMP
+ update_process_times(user_mode(regs));
+#endif
+
+ write_seqlock(&xtime_lock);
+
+ last_ccount_stamp = next;
+ next += CCOUNT_PER_JIFFY;
+ do_timer (regs); /* Linux handler in kernel/timer.c */
+
+ if ((time_status & STA_UNSYNC) == 0 &&
+ xtime.tv_sec - last_rtc_update >= 659 &&
+ abs((xtime.tv_nsec/1000)-(1000000-1000000/HZ))<5000000/HZ &&
+ jiffies - wall_jiffies == 1) {
+
+ if (platform_set_rtc_time(xtime.tv_sec+1) == 0)
+ last_rtc_update = xtime.tv_sec+1;
+ else
+ /* Do it again in 60 s */
+ last_rtc_update += 60;
+ }
+ write_sequnlock(&xtime_lock);
+ }
+
+ /* NOTE: writing CCOMPAREn clears the interrupt. */
+
+ set_linux_timer (next);
+
+ /* Make sure we didn't miss any tick... */
+
+ if ((signed long)(get_ccount() - next) > 0)
+ goto again;
+
+ /* Allow platform to do something usefull (Wdog). */
+
+ platform_heartbeat();
+
+ return IRQ_HANDLED;
+}
+
+#ifndef CONFIG_GENERIC_CALIBRATE_DELAY
+void __devinit calibrate_delay(void)
+{
+ loops_per_jiffy = CCOUNT_PER_JIFFY;
+ printk("Calibrating delay loop (skipped)... "
+ "%lu.%02lu BogoMIPS preset\n",
+ loops_per_jiffy/(1000000/HZ),
+ (loops_per_jiffy/(10000/HZ)) % 100);
+}
+#endif
+
diff --git a/arch/xtensa/kernel/traps.c b/arch/xtensa/kernel/traps.c
new file mode 100644
index 000000000000..225d64d73f04
--- /dev/null
+++ b/arch/xtensa/kernel/traps.c
@@ -0,0 +1,498 @@
+/*
+ * arch/xtensa/kernel/traps.c
+ *
+ * Exception handling.
+ *
+ * Derived from code with the following copyrights:
+ * Copyright (C) 1994 - 1999 by Ralf Baechle
+ * Modified for R3000 by Paul M. Antoine, 1995, 1996
+ * Complete output from die() by Ulf Carlsson, 1998
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * Essentially rewritten for the Xtensa architecture port.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier<marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Kevin Chea
+ *
+ * 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 <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/stringify.h>
+#include <linux/kallsyms.h>
+#include <linux/delay.h>
+
+#include <asm/ptrace.h>
+#include <asm/timex.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+
+#ifdef CONFIG_KGDB
+extern int gdb_enter;
+extern int return_from_debug_flag;
+#endif
+
+/*
+ * Machine specific interrupt handlers
+ */
+
+extern void kernel_exception(void);
+extern void user_exception(void);
+
+extern void fast_syscall_kernel(void);
+extern void fast_syscall_user(void);
+extern void fast_alloca(void);
+extern void fast_unaligned(void);
+extern void fast_second_level_miss(void);
+extern void fast_store_prohibited(void);
+extern void fast_coprocessor(void);
+
+extern void do_illegal_instruction (struct pt_regs*);
+extern void do_interrupt (struct pt_regs*);
+extern void do_unaligned_user (struct pt_regs*);
+extern void do_multihit (struct pt_regs*, unsigned long);
+extern void do_page_fault (struct pt_regs*, unsigned long);
+extern void do_debug (struct pt_regs*);
+extern void system_call (struct pt_regs*);
+
+/*
+ * The vector table must be preceded by a save area (which
+ * implies it must be in RAM, unless one places RAM immediately
+ * before a ROM and puts the vector at the start of the ROM (!))
+ */
+
+#define KRNL 0x01
+#define USER 0x02
+
+#define COPROCESSOR(x) \
+{ XCHAL_EXCCAUSE_COPROCESSOR ## x ## _DISABLED, USER, fast_coprocessor }
+
+typedef struct {
+ int cause;
+ int fast;
+ void* handler;
+} dispatch_init_table_t;
+
+dispatch_init_table_t __init dispatch_init_table[] = {
+
+{ XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION, 0, do_illegal_instruction},
+{ XCHAL_EXCCAUSE_SYSTEM_CALL, KRNL, fast_syscall_kernel },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL, USER, fast_syscall_user },
+{ XCHAL_EXCCAUSE_SYSTEM_CALL, 0, system_call },
+/* XCHAL_EXCCAUSE_INSTRUCTION_FETCH unhandled */
+/* XCHAL_EXCCAUSE_LOAD_STORE_ERROR unhandled*/
+{ XCHAL_EXCCAUSE_LEVEL1_INTERRUPT, 0, do_interrupt },
+{ XCHAL_EXCCAUSE_ALLOCA, USER|KRNL, fast_alloca },
+/* XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO unhandled */
+/* XCHAL_EXCCAUSE_PRIVILEGED unhandled */
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifdef CONFIG_UNALIGNED_USER
+{ XCHAL_EXCCAUSE_UNALIGNED, USER, fast_unaligned },
+#else
+{ XCHAL_EXCCAUSE_UNALIGNED, 0, do_unaligned_user },
+#endif
+{ XCHAL_EXCCAUSE_UNALIGNED, KRNL, fast_unaligned },
+#endif
+{ XCHAL_EXCCAUSE_ITLB_MISS, 0, do_page_fault },
+{ XCHAL_EXCCAUSE_ITLB_MISS, USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_ITLB_MULTIHIT, 0, do_multihit },
+{ XCHAL_EXCCAUSE_ITLB_PRIVILEGE, 0, do_page_fault },
+/* XCHAL_EXCCAUSE_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE, 0, do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MISS, USER|KRNL, fast_second_level_miss},
+{ XCHAL_EXCCAUSE_DTLB_MISS, 0, do_page_fault },
+{ XCHAL_EXCCAUSE_DTLB_MULTIHIT, 0, do_multihit },
+{ XCHAL_EXCCAUSE_DTLB_PRIVILEGE, 0, do_page_fault },
+/* XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION unhandled */
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE, USER|KRNL, fast_store_prohibited },
+{ XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE, 0, do_page_fault },
+{ XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE, 0, do_page_fault },
+/* XCCHAL_EXCCAUSE_FLOATING_POINT unhandled */
+#if (XCHAL_CP_MASK & 1)
+COPROCESSOR(0),
+#endif
+#if (XCHAL_CP_MASK & 2)
+COPROCESSOR(1),
+#endif
+#if (XCHAL_CP_MASK & 4)
+COPROCESSOR(2),
+#endif
+#if (XCHAL_CP_MASK & 8)
+COPROCESSOR(3),
+#endif
+#if (XCHAL_CP_MASK & 16)
+COPROCESSOR(4),
+#endif
+#if (XCHAL_CP_MASK & 32)
+COPROCESSOR(5),
+#endif
+#if (XCHAL_CP_MASK & 64)
+COPROCESSOR(6),
+#endif
+#if (XCHAL_CP_MASK & 128)
+COPROCESSOR(7),
+#endif
+{ EXCCAUSE_MAPPED_DEBUG, 0, do_debug },
+{ -1, -1, 0 }
+
+};
+
+/* The exception table <exc_table> serves two functions:
+ * 1. it contains three dispatch tables (fast_user, fast_kernel, default-c)
+ * 2. it is a temporary memory buffer for the exception handlers.
+ */
+
+unsigned long exc_table[EXC_TABLE_SIZE/4];
+
+void die(const char*, struct pt_regs*, long);
+
+static inline void
+__die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+ if (!user_mode(regs))
+ die(str, regs, err);
+}
+
+/*
+ * Unhandled Exceptions. Kill user task or panic if in kernel space.
+ */
+
+void do_unhandled(struct pt_regs *regs, unsigned long exccause)
+{
+ __die_if_kernel("Caught unhandled exception - should not happen",
+ regs, SIGKILL);
+
+ /* If in user mode, send SIGILL signal to current process */
+ printk("Caught unhandled exception in '%s' "
+ "(pid = %d, pc = %#010lx) - should not happen\n"
+ "\tEXCCAUSE is %ld\n",
+ current->comm, current->pid, regs->pc, exccause);
+ force_sig(SIGILL, current);
+}
+
+/*
+ * Multi-hit exception. This if fatal!
+ */
+
+void do_multihit(struct pt_regs *regs, unsigned long exccause)
+{
+ die("Caught multihit exception", regs, SIGKILL);
+}
+
+/*
+ * Level-1 interrupt.
+ * We currently have no priority encoding.
+ */
+
+unsigned long ignored_level1_interrupts;
+extern void do_IRQ(int, struct pt_regs *);
+
+void do_interrupt (struct pt_regs *regs)
+{
+ unsigned long intread = get_sr (INTREAD);
+ unsigned long intenable = get_sr (INTENABLE);
+ int i, mask;
+
+ /* Handle all interrupts (no priorities).
+ * (Clear the interrupt before processing, in case it's
+ * edge-triggered or software-generated)
+ */
+
+ for (i=0, mask = 1; i < XCHAL_NUM_INTERRUPTS; i++, mask <<= 1) {
+ if (mask & (intread & intenable)) {
+ set_sr (mask, INTCLEAR);
+ do_IRQ (i,regs);
+ }
+ }
+}
+
+/*
+ * Illegal instruction. Fatal if in kernel space.
+ */
+
+void
+do_illegal_instruction(struct pt_regs *regs)
+{
+ __die_if_kernel("Illegal instruction in kernel", regs, SIGKILL);
+
+ /* If in user mode, send SIGILL signal to current process. */
+
+ printk("Illegal Instruction in '%s' (pid = %d, pc = %#010lx)\n",
+ current->comm, current->pid, regs->pc);
+ force_sig(SIGILL, current);
+}
+
+
+/*
+ * Handle unaligned memory accesses from user space. Kill task.
+ *
+ * If CONFIG_UNALIGNED_USER is not set, we don't allow unaligned memory
+ * accesses causes from user space.
+ */
+
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || XCHAL_UNALIGNED_STORE_EXCEPTION
+#ifndef CONFIG_UNALIGNED_USER
+void
+do_unaligned_user (struct pt_regs *regs)
+{
+ siginfo_t info;
+
+ __die_if_kernel("Unhandled unaligned exception in kernel",
+ regs, SIGKILL);
+
+ current->thread.bad_vaddr = regs->excvaddr;
+ current->thread.error_code = -3;
+ printk("Unaligned memory access to %08lx in '%s' "
+ "(pid = %d, pc = %#010lx)\n",
+ regs->excvaddr, current->comm, current->pid, regs->pc);
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (void *) regs->excvaddr;
+ force_sig_info(SIGSEGV, &info, current);
+
+}
+#endif
+#endif
+
+void
+do_debug(struct pt_regs *regs)
+{
+#ifdef CONFIG_KGDB
+ /* If remote debugging is configured AND enabled, we give control to
+ * kgdb. Otherwise, we fall through, perhaps giving control to the
+ * native debugger.
+ */
+
+ if (gdb_enter) {
+ extern void gdb_handle_exception(struct pt_regs *);
+ gdb_handle_exception(regs);
+ return_from_debug_flag = 1;
+ return;
+ }
+#endif
+
+ __die_if_kernel("Breakpoint in kernel", regs, SIGKILL);
+
+ /* If in user mode, send SIGTRAP signal to current process */
+
+ force_sig(SIGTRAP, current);
+}
+
+
+/*
+ * Initialize dispatch tables.
+ *
+ * The exception vectors are stored compressed the __init section in the
+ * dispatch_init_table. This function initializes the following three tables
+ * from that compressed table:
+ * - fast user first dispatch table for user exceptions
+ * - fast kernel first dispatch table for kernel exceptions
+ * - default C-handler C-handler called by the default fast handler.
+ *
+ * See vectors.S for more details.
+ */
+
+#define set_handler(idx,handler) (exc_table[idx] = (unsigned long) (handler))
+
+void trap_init(void)
+{
+ int i;
+
+ /* Setup default vectors. */
+
+ for(i = 0; i < 64; i++) {
+ set_handler(EXC_TABLE_FAST_USER/4 + i, user_exception);
+ set_handler(EXC_TABLE_FAST_KERNEL/4 + i, kernel_exception);
+ set_handler(EXC_TABLE_DEFAULT/4 + i, do_unhandled);
+ }
+
+ /* Setup specific handlers. */
+
+ for(i = 0; dispatch_init_table[i].cause >= 0; i++) {
+
+ int fast = dispatch_init_table[i].fast;
+ int cause = dispatch_init_table[i].cause;
+ void *handler = dispatch_init_table[i].handler;
+
+ if (fast == 0)
+ set_handler (EXC_TABLE_DEFAULT/4 + cause, handler);
+ if (fast && fast & USER)
+ set_handler (EXC_TABLE_FAST_USER/4 + cause, handler);
+ if (fast && fast & KRNL)
+ set_handler (EXC_TABLE_FAST_KERNEL/4 + cause, handler);
+ }
+
+ /* Initialize EXCSAVE_1 to hold the address of the exception table. */
+
+ i = (unsigned long)exc_table;
+ __asm__ __volatile__("wsr %0, "__stringify(EXCSAVE_1)"\n" : : "a" (i));
+}
+
+/*
+ * This function dumps the current valid window frame and other base registers.
+ */
+
+void show_regs(struct pt_regs * regs)
+{
+ int i, wmask;
+
+ wmask = regs->wmask & ~1;
+
+ for (i = 0; i < 32; i++) {
+ if (wmask & (1 << (i / 4)))
+ break;
+ if ((i % 8) == 0)
+ printk ("\n" KERN_INFO "a%02d: ", i);
+ printk("%08lx ", regs->areg[i]);
+ }
+ printk("\n");
+
+ printk("pc: %08lx, ps: %08lx, depc: %08lx, excvaddr: %08lx\n",
+ regs->pc, regs->ps, regs->depc, regs->excvaddr);
+ printk("lbeg: %08lx, lend: %08lx lcount: %08lx, sar: %08lx\n",
+ regs->lbeg, regs->lend, regs->lcount, regs->sar);
+ if (user_mode(regs))
+ printk("wb: %08lx, ws: %08lx, wmask: %08lx, syscall: %ld\n",
+ regs->windowbase, regs->windowstart, regs->wmask,
+ regs->syscall);
+}
+
+void show_trace(struct task_struct *task, unsigned long *sp)
+{
+ unsigned long a0, a1, pc;
+ unsigned long sp_start, sp_end;
+
+ a1 = (unsigned long)sp;
+
+ if (a1 == 0)
+ __asm__ __volatile__ ("mov %0, a1\n" : "=a"(a1));
+
+
+ sp_start = a1 & ~(THREAD_SIZE-1);
+ sp_end = sp_start + THREAD_SIZE;
+
+ printk("Call Trace:");
+#ifdef CONFIG_KALLSYMS
+ printk("\n");
+#endif
+ spill_registers();
+
+ while (a1 > sp_start && a1 < sp_end) {
+ sp = (unsigned long*)a1;
+
+ a0 = *(sp - 4);
+ a1 = *(sp - 3);
+
+ if (a1 <= (unsigned long) sp)
+ break;
+
+ pc = MAKE_PC_FROM_RA(a0, a1);
+
+ if (kernel_text_address(pc)) {
+ printk(" [<%08lx>] ", pc);
+ print_symbol("%s\n", pc);
+ }
+ }
+ printk("\n");
+}
+
+/*
+ * This routine abuses get_user()/put_user() to reference pointers
+ * with at least a bit of error checking ...
+ */
+
+static int kstack_depth_to_print = 24;
+
+void show_stack(struct task_struct *task, unsigned long *sp)
+{
+ int i = 0;
+ unsigned long *stack;
+
+ if (sp == 0)
+ __asm__ __volatile__ ("mov %0, a1\n" : "=a"(sp));
+
+ stack = sp;
+
+ printk("\nStack: ");
+
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (kstack_end(sp))
+ break;
+ if (i && ((i % 8) == 0))
+ printk("\n ");
+ printk("%08lx ", *sp++);
+ }
+ printk("\n");
+ show_trace(task, stack);
+}
+
+void dump_stack(void)
+{
+ show_stack(current, NULL);
+}
+
+EXPORT_SYMBOL(dump_stack);
+
+
+void show_code(unsigned int *pc)
+{
+ long i;
+
+ printk("\nCode:");
+
+ for(i = -3 ; i < 6 ; i++) {
+ unsigned long insn;
+ if (__get_user(insn, pc + i)) {
+ printk(" (Bad address in pc)\n");
+ break;
+ }
+ printk("%c%08lx%c",(i?' ':'<'),insn,(i?' ':'>'));
+ }
+}
+
+spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+
+void die(const char * str, struct pt_regs * regs, long err)
+{
+ static int die_counter;
+ int nl = 0;
+
+ console_verbose();
+ spin_lock_irq(&die_lock);
+
+ printk("%s: sig: %ld [#%d]\n", str, err, ++die_counter);
+#ifdef CONFIG_PREEMPT
+ printk("PREEMPT ");
+ nl = 1;
+#endif
+ if (nl)
+ printk("\n");
+ show_regs(regs);
+ if (!user_mode(regs))
+ show_stack(NULL, (unsigned long*)regs->areg[1]);
+
+ spin_unlock_irq(&die_lock);
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops) {
+ printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+ ssleep(5);
+ panic("Fatal exception");
+ }
+ do_exit(err);
+}
+
+
diff --git a/arch/xtensa/kernel/vectors.S b/arch/xtensa/kernel/vectors.S
new file mode 100644
index 000000000000..81808f0c6742
--- /dev/null
+++ b/arch/xtensa/kernel/vectors.S
@@ -0,0 +1,464 @@
+/*
+ * arch/xtensa/kernel/vectors.S
+ *
+ * This file contains all exception vectors (user, kernel, and double),
+ * as well as the window vectors (overflow and underflow), and the debug
+ * vector. These are the primary vectors executed by the processor if an
+ * exception occurs.
+ *
+ * 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) 2005 Tensilica, Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ *
+ */
+
+/*
+ * We use a two-level table approach. The user and kernel exception vectors
+ * use a first-level dispatch table to dispatch the exception to a registered
+ * fast handler or the default handler, if no fast handler was registered.
+ * The default handler sets up a C-stack and dispatches the exception to a
+ * registerd C handler in the second-level dispatch table.
+ *
+ * Fast handler entry condition:
+ *
+ * a0: trashed, original value saved on stack (PT_AREG0)
+ * a1: a1
+ * a2: new stack pointer, original value in depc
+ * a3: dispatch table
+ * depc: a2, original value saved on stack (PT_DEPC)
+ * excsave_1: a3
+ *
+ * The value for PT_DEPC saved to stack also functions as a boolean to
+ * indicate that the exception is either a double or a regular exception:
+ *
+ * PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception
+ * < VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
+ *
+ * Note: Neither the kernel nor the user exception handler generate literals.
+ *
+ */
+
+#include <linux/linkage.h>
+#include <asm/ptrace.h>
+#include <asm/ptrace.h>
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/pgtable.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+
+
+/*
+ * User exception vector. (Exceptions with PS.UM == 1, PS.EXCM == 0)
+ *
+ * We get here when an exception occurred while we were in userland.
+ * We switch to the kernel stack and jump to the first level handler
+ * associated to the exception cause.
+ *
+ * Note: the saved kernel stack pointer (EXC_TABLE_KSTK) is already
+ * decremented by PT_USER_SIZE.
+ */
+
+ .section .UserExceptionVector.text, "ax"
+
+ENTRY(_UserExceptionVector)
+
+ xsr a3, EXCSAVE_1 # save a3 and get dispatch table
+ wsr a2, DEPC # save a2
+ l32i a2, a3, EXC_TABLE_KSTK # load kernel stack to a2
+ s32i a0, a2, PT_AREG0 # save a0 to ESF
+ rsr a0, EXCCAUSE # retrieve exception cause
+ s32i a0, a2, PT_DEPC # mark it as a regular exception
+ addx4 a0, a0, a3 # find entry in table
+ l32i a0, a0, EXC_TABLE_FAST_USER # load handler
+ jx a0
+
+/*
+ * Kernel exception vector. (Exceptions with PS.UM == 0, PS.EXCM == 0)
+ *
+ * We get this exception when we were already in kernel space.
+ * We decrement the current stack pointer (kernel) by PT_SIZE and
+ * jump to the first-level handler associated with the exception cause.
+ *
+ * Note: we need to preserve space for the spill region.
+ */
+
+ .section .KernelExceptionVector.text, "ax"
+
+ENTRY(_KernelExceptionVector)
+
+ xsr a3, EXCSAVE_1 # save a3, and get dispatch table
+ wsr a2, DEPC # save a2
+ addi a2, a1, -16-PT_SIZE # adjust stack pointer
+ s32i a0, a2, PT_AREG0 # save a0 to ESF
+ rsr a0, EXCCAUSE # retrieve exception cause
+ s32i a0, a2, PT_DEPC # mark it as a regular exception
+ addx4 a0, a0, a3 # find entry in table
+ l32i a0, a0, EXC_TABLE_FAST_KERNEL # load handler address
+ jx a0
+
+
+/*
+ * Double exception vector (Exceptions with PS.EXCM == 1)
+ * We get this exception when another exception occurs while were are
+ * already in an exception, such as window overflow/underflow exception,
+ * or 'expected' exceptions, for example memory exception when we were trying
+ * to read data from an invalid address in user space.
+ *
+ * Note that this vector is never invoked for level-1 interrupts, because such
+ * interrupts are disabled (masked) when PS.EXCM is set.
+ *
+ * We decode the exception and take the appropriate action. However, the
+ * double exception vector is much more careful, because a lot more error
+ * cases go through the double exception vector than through the user and
+ * kernel exception vectors.
+ *
+ * Occasionally, the kernel expects a double exception to occur. This usually
+ * happens when accessing user-space memory with the user's permissions
+ * (l32e/s32e instructions). The kernel state, though, is not always suitable
+ * for immediate transfer of control to handle_double, where "normal" exception
+ * processing occurs. Also in kernel mode, TLB misses can occur if accessing
+ * vmalloc memory, possibly requiring repair in a double exception handler.
+ *
+ * The variable at TABLE_FIXUP offset from the pointer in EXCSAVE_1 doubles as
+ * a boolean variable and a pointer to a fixup routine. If the variable
+ * EXC_TABLE_FIXUP is non-zero, this handler jumps to that address. A value of
+ * zero indicates to use the default kernel/user exception handler.
+ * There is only one exception, when the value is identical to the exc_table
+ * label, the kernel is in trouble. This mechanism is used to protect critical
+ * sections, mainly when the handler writes to the stack to assert the stack
+ * pointer is valid. Once the fixup/default handler leaves that area, the
+ * EXC_TABLE_FIXUP variable is reset to the fixup handler or zero.
+ *
+ * Procedures wishing to use this mechanism should set EXC_TABLE_FIXUP to the
+ * nonzero address of a fixup routine before it could cause a double exception
+ * and reset it before it returns.
+ *
+ * Some other things to take care of when a fast exception handler doesn't
+ * specify a particular fixup handler but wants to use the default handlers:
+ *
+ * - The original stack pointer (in a1) must not be modified. The fast
+ * exception handler should only use a2 as the stack pointer.
+ *
+ * - If the fast handler manipulates the stack pointer (in a2), it has to
+ * register a valid fixup handler and cannot use the default handlers.
+ *
+ * - The handler can use any other generic register from a3 to a15, but it
+ * must save the content of these registers to stack (PT_AREG3...PT_AREGx)
+ *
+ * - These registers must be saved before a double exception can occur.
+ *
+ * - If we ever implement handling signals while in double exceptions, the
+ * number of registers a fast handler has saved (excluding a0 and a1) must
+ * be written to PT_AREG1. (1 if only a3 is used, 2 for a3 and a4, etc. )
+ *
+ * The fixup handlers are special handlers:
+ *
+ * - Fixup entry conditions differ from regular exceptions:
+ *
+ * a0: DEPC
+ * a1: a1
+ * a2: trashed, original value in EXC_TABLE_DOUBLE_A2
+ * a3: exctable
+ * depc: a0
+ * excsave_1: a3
+ *
+ * - When the kernel enters the fixup handler, it still assumes it is in a
+ * critical section, so EXC_TABLE_FIXUP variable is set to exc_table.
+ * The fixup handler, therefore, has to re-register itself as the fixup
+ * handler before it returns from the double exception.
+ *
+ * - Fixup handler can share the same exception frame with the fast handler.
+ * The kernel stack pointer is not changed when entering the fixup handler.
+ *
+ * - Fixup handlers can jump to the default kernel and user exception
+ * handlers. Before it jumps, though, it has to setup a exception frame
+ * on stack. Because the default handler resets the register fixup handler
+ * the fixup handler must make sure that the default handler returns to
+ * it instead of the exception address, so it can re-register itself as
+ * the fixup handler.
+ *
+ * In case of a critical condition where the kernel cannot recover, we jump
+ * to unrecoverable_exception with the following entry conditions.
+ * All registers a0...a15 are unchanged from the last exception, except:
+ *
+ * a0: last address before we jumped to the unrecoverable_exception.
+ * excsave_1: a0
+ *
+ *
+ * See the handle_alloca_user and spill_registers routines for example clients.
+ *
+ * FIXME: Note: we currently don't allow signal handling coming from a double
+ * exception, so the item markt with (*) is not required.
+ */
+
+ .section .DoubleExceptionVector.text, "ax"
+ .begin literal_prefix .DoubleExceptionVector
+
+ENTRY(_DoubleExceptionVector)
+
+ /* Deliberately destroy excsave (don't assume it's value was valid). */
+
+ wsr a3, EXCSAVE_1 # save a3
+
+ /* Check for kernel double exception (usually fatal). */
+
+ rsr a3, PS
+ _bbci.l a3, PS_UM_SHIFT, .Lksp
+
+ /* Check if we are currently handling a window exception. */
+ /* Note: We don't need to indicate that we enter a critical section. */
+
+ xsr a0, DEPC # get DEPC, save a0
+
+ movi a3, XCHAL_WINDOW_VECTORS_VADDR
+ _bltu a0, a3, .Lfixup
+ addi a3, a3, XSHAL_WINDOW_VECTORS_SIZE
+ _bgeu a0, a3, .Lfixup
+
+ /* Window overflow/underflow exception. Get stack pointer. */
+
+ mov a3, a2
+ movi a2, exc_table
+ l32i a2, a2, EXC_TABLE_KSTK
+
+ /* Check for overflow/underflow exception, jump if overflow. */
+
+ _bbci.l a0, 6, .Lovfl
+
+ /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
+
+ /* Restart window underflow exception.
+ * We return to the instruction in user space that caused the window
+ * underflow exception. Therefore, we change window base to the value
+ * before we entered the window underflow exception and prepare the
+ * registers to return as if we were coming from a regular exception
+ * by changing depc (in a0).
+ * Note: We can trash the current window frame (a0...a3) and depc!
+ */
+
+ wsr a2, DEPC # save stack pointer temporarily
+ rsr a0, PS
+ extui a0, a0, XCHAL_PS_OWB_SHIFT, XCHAL_PS_OWB_BITS
+ wsr a0, WINDOWBASE
+ rsync
+
+ /* We are now in the previous window frame. Save registers again. */
+
+ xsr a2, DEPC # save a2 and get stack pointer
+ s32i a0, a2, PT_AREG0
+
+ wsr a3, EXCSAVE_1 # save a3
+ movi a3, exc_table
+
+ rsr a0, EXCCAUSE
+ s32i a0, a2, PT_DEPC # mark it as a regular exception
+ addx4 a0, a0, a3
+ l32i a0, a0, EXC_TABLE_FAST_USER
+ jx a0
+
+.Lfixup:/* Check for a fixup handler or if we were in a critical section. */
+
+ /* a0: depc, a1: a1, a2: a2, a3: trashed, depc: a0, excsave1: a3 */
+
+ movi a3, exc_table
+ s32i a2, a3, EXC_TABLE_DOUBLE_SAVE # temporary variable
+
+ /* Enter critical section. */
+
+ l32i a2, a3, EXC_TABLE_FIXUP
+ s32i a3, a3, EXC_TABLE_FIXUP
+ beq a2, a3, .Lunrecoverable_fixup # critical!
+ beqz a2, .Ldflt # no handler was registered
+
+ /* a0: depc, a1: a1, a2: trash, a3: exctable, depc: a0, excsave: a3 */
+
+ jx a2
+
+.Ldflt: /* Get stack pointer. */
+
+ l32i a3, a3, EXC_TABLE_DOUBLE_SAVE
+ addi a2, a3, -PT_USER_SIZE
+
+.Lovfl: /* Jump to default handlers. */
+
+ /* a0: depc, a1: a1, a2: kstk, a3: a2, depc: a0, excsave: a3 */
+
+ xsr a3, DEPC
+ s32i a0, a2, PT_DEPC
+ s32i a3, a2, PT_AREG0
+
+ /* a0: avail, a1: a1, a2: kstk, a3: avail, depc: a2, excsave: a3 */
+
+ movi a3, exc_table
+ rsr a0, EXCCAUSE
+ addx4 a0, a0, a3
+ l32i a0, a0, EXC_TABLE_FAST_USER
+ jx a0
+
+ /*
+ * We only allow the ITLB miss exception if we are in kernel space.
+ * All other exceptions are unexpected and thus unrecoverable!
+ */
+
+ .extern fast_second_level_miss_double_kernel
+
+.Lksp: /* a0: a0, a1: a1, a2: a2, a3: trashed, depc: depc, excsave: a3 */
+
+ rsr a3, EXCCAUSE
+ beqi a3, XCHAL_EXCCAUSE_ITLB_MISS, 1f
+ addi a3, a3, -XCHAL_EXCCAUSE_DTLB_MISS
+ bnez a3, .Lunrecoverable
+1: movi a3, fast_second_level_miss_double_kernel
+ jx a3
+
+ /* Critical! We can't handle this situation. PANIC! */
+
+ .extern unrecoverable_exception
+
+.Lunrecoverable_fixup:
+ l32i a2, a3, EXC_TABLE_DOUBLE_SAVE
+ xsr a0, DEPC
+
+.Lunrecoverable:
+ rsr a3, EXCSAVE_1
+ wsr a0, EXCSAVE_1
+ movi a0, unrecoverable_exception
+ callx0 a0
+
+ .end literal_prefix
+
+
+/*
+ * Debug interrupt vector
+ *
+ * There is not much space here, so simply jump to another handler.
+ * EXCSAVE[DEBUGLEVEL] has been set to that handler.
+ */
+
+ .section .DebugInterruptVector.text, "ax"
+
+ENTRY(_DebugInterruptVector)
+ xsr a0, EXCSAVE + XCHAL_DEBUGLEVEL
+ jx a0
+
+
+
+/* Window overflow and underflow handlers.
+ * The handlers must be 64 bytes apart, first starting with the underflow
+ * handlers underflow-4 to underflow-12, then the overflow handlers
+ * overflow-4 to overflow-12.
+ *
+ * Note: We rerun the underflow handlers if we hit an exception, so
+ * we try to access any page that would cause a page fault early.
+ */
+
+ .section .WindowVectors.text, "ax"
+
+
+/* 4-Register Window Overflow Vector (Handler) */
+
+ .align 64
+.global _WindowOverflow4
+_WindowOverflow4:
+ s32e a0, a5, -16
+ s32e a1, a5, -12
+ s32e a2, a5, -8
+ s32e a3, a5, -4
+ rfwo
+
+
+/* 4-Register Window Underflow Vector (Handler) */
+
+ .align 64
+.global _WindowUnderflow4
+_WindowUnderflow4:
+ l32e a0, a5, -16
+ l32e a1, a5, -12
+ l32e a2, a5, -8
+ l32e a3, a5, -4
+ rfwu
+
+
+/* 8-Register Window Overflow Vector (Handler) */
+
+ .align 64
+.global _WindowOverflow8
+_WindowOverflow8:
+ s32e a0, a9, -16
+ l32e a0, a1, -12
+ s32e a2, a9, -8
+ s32e a1, a9, -12
+ s32e a3, a9, -4
+ s32e a4, a0, -32
+ s32e a5, a0, -28
+ s32e a6, a0, -24
+ s32e a7, a0, -20
+ rfwo
+
+/* 8-Register Window Underflow Vector (Handler) */
+
+ .align 64
+.global _WindowUnderflow8
+_WindowUnderflow8:
+ l32e a1, a9, -12
+ l32e a0, a9, -16
+ l32e a7, a1, -12
+ l32e a2, a9, -8
+ l32e a4, a7, -32
+ l32e a3, a9, -4
+ l32e a5, a7, -28
+ l32e a6, a7, -24
+ l32e a7, a7, -20
+ rfwu
+
+
+/* 12-Register Window Overflow Vector (Handler) */
+
+ .align 64
+.global _WindowOverflow12
+_WindowOverflow12:
+ s32e a0, a13, -16
+ l32e a0, a1, -12
+ s32e a1, a13, -12
+ s32e a2, a13, -8
+ s32e a3, a13, -4
+ s32e a4, a0, -48
+ s32e a5, a0, -44
+ s32e a6, a0, -40
+ s32e a7, a0, -36
+ s32e a8, a0, -32
+ s32e a9, a0, -28
+ s32e a10, a0, -24
+ s32e a11, a0, -20
+ rfwo
+
+/* 12-Register Window Underflow Vector (Handler) */
+
+ .align 64
+.global _WindowUnderflow12
+_WindowUnderflow12:
+ l32e a1, a13, -12
+ l32e a0, a13, -16
+ l32e a11, a1, -12
+ l32e a2, a13, -8
+ l32e a4, a11, -48
+ l32e a8, a11, -32
+ l32e a3, a13, -4
+ l32e a5, a11, -44
+ l32e a6, a11, -40
+ l32e a7, a11, -36
+ l32e a9, a11, -28
+ l32e a10, a11, -24
+ l32e a11, a11, -20
+ rfwu
+
+ .text
+
+
diff --git a/arch/xtensa/kernel/vmlinux.lds.S b/arch/xtensa/kernel/vmlinux.lds.S
new file mode 100644
index 000000000000..5ed71dfc8110
--- /dev/null
+++ b/arch/xtensa/kernel/vmlinux.lds.S
@@ -0,0 +1,341 @@
+/*
+ * arch/xtensa/kernel/vmlinux.lds.S
+ *
+ * Xtensa linker script
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier <marc@tensilica.com, marc@alumni.uwaterloo.ca>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <asm-generic/vmlinux.lds.h>
+
+#include <linux/config.h>
+#define _NOCLANGUAGE
+#include <xtensa/config/core.h>
+#include <xtensa/config/system.h>
+OUTPUT_ARCH(xtensa)
+ENTRY(_start)
+
+#if XCHAL_MEMORY_ORDER == XTHAL_BIGENDIAN
+jiffies = jiffies_64 + 4;
+#else
+jiffies = jiffies_64;
+#endif
+
+#define KERNELOFFSET 0x1000
+
+/* Note: In the following macros, it would be nice to specify only the
+ vector name and section kind and construct "sym" and "section" using
+ CPP concatenation, but that does not work reliably. Concatenating a
+ string with "." produces an invalid token. CPP will not print a
+ warning because it thinks this is an assembly file, but it leaves
+ them as multiple tokens and there may or may not be whitespace
+ between them. */
+
+/* Macro for a relocation entry */
+
+#define RELOCATE_ENTRY(sym, section) \
+ LONG(sym ## _start); \
+ LONG(sym ## _end); \
+ LONG(LOADADDR(section))
+
+/* Macro to define a section for a vector.
+ *
+ * Use of the MIN function catches the types of errors illustrated in
+ * the following example:
+ *
+ * Assume the section .DoubleExceptionVector.literal is completely
+ * full. Then a programmer adds code to .DoubleExceptionVector.text
+ * that produces another literal. The final literal position will
+ * overlay onto the first word of the adjacent code section
+ * .DoubleExceptionVector.text. (In practice, the literals will
+ * overwrite the code, and the first few instructions will be
+ * garbage.)
+ */
+
+#define SECTION_VECTOR(sym, section, addr, max_prevsec_size, prevsec) \
+ section addr : AT((MIN(LOADADDR(prevsec) + max_prevsec_size, \
+ LOADADDR(prevsec) + SIZEOF(prevsec)) + 3) & ~ 3) \
+ { \
+ . = ALIGN(4); \
+ sym ## _start = ABSOLUTE(.); \
+ *(section) \
+ sym ## _end = ABSOLUTE(.); \
+ }
+
+/*
+ * Mapping of input sections to output sections when linking.
+ */
+
+SECTIONS
+{
+ . = XCHAL_KSEG_CACHED_VADDR + KERNELOFFSET;
+ /* .text section */
+
+ _text = .;
+ _stext = .;
+ _ftext = .;
+
+ .text :
+ {
+ /* The .head.text section must be the first section! */
+ *(.head.text)
+ *(.literal .text)
+ *(.srom.text)
+ VMLINUX_SYMBOL(__sched_text_start) = .;
+ *(.sched.literal .sched.text)
+ VMLINUX_SYMBOL(__sched_text_end) = .;
+ VMLINUX_SYMBOL(__lock_text_start) = .;
+ *(.spinlock.literal .spinlock.text)
+ VMLINUX_SYMBOL(__lock_text_end) = .;
+
+ }
+ _etext = .;
+
+ . = ALIGN(16);
+
+ RODATA
+
+ /* Relocation table */
+
+ . = ALIGN(16);
+ __boot_reloc_table_start = ABSOLUTE(.);
+
+ __relocate : {
+
+ RELOCATE_ENTRY(_WindowVectors_text,
+ .WindowVectors.text);
+#if 0
+ RELOCATE_ENTRY(_KernelExceptionVector_literal,
+ .KernelExceptionVector.literal);
+#endif
+ RELOCATE_ENTRY(_KernelExceptionVector_text,
+ .KernelExceptionVector.text);
+#if 0
+ RELOCATE_ENTRY(_UserExceptionVector_literal,
+ .UserExceptionVector.literal);
+#endif
+ RELOCATE_ENTRY(_UserExceptionVector_text,
+ .UserExceptionVector.text);
+ RELOCATE_ENTRY(_DoubleExceptionVector_literal,
+ .DoubleExceptionVector.literal);
+ RELOCATE_ENTRY(_DoubleExceptionVector_text,
+ .DoubleExceptionVector.text);
+ }
+ __boot_reloc_table_end = ABSOLUTE(.) ;
+
+ .fixup : { *(.fixup) }
+
+ . = ALIGN(16);
+
+ __ex_table : {
+ __start___ex_table = .;
+ *(__ex_table)
+ __stop___ex_table = .;
+ }
+
+ /* Data section */
+
+ . = ALIGN(XCHAL_ICACHE_LINESIZE);
+ _fdata = .;
+ .data :
+ {
+ *(.data) CONSTRUCTORS
+ . = ALIGN(XCHAL_ICACHE_LINESIZE);
+ *(.data.cacheline_aligned)
+ }
+
+ _edata = .;
+
+ /* The initial task */
+ . = ALIGN(8192);
+ .data.init_task : { *(.data.init_task) }
+
+ /* Initialization code and data: */
+
+ . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+ __init_begin = .;
+ .init.text : {
+ _sinittext = .;
+ *(.init.literal) *(.init.text)
+ _einittext = .;
+ }
+
+ .init.data :
+ {
+ *(.init.data)
+ . = ALIGN(0x4);
+ __tagtable_begin = .;
+ *(.taglist)
+ __tagtable_end = .;
+ }
+
+ . = ALIGN(XCHAL_ICACHE_LINESIZE);
+
+ __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);
+
+ __start___ftr_fixup = .;
+ __ftr_fixup : { *(__ftr_fixup) }
+ __stop___ftr_fixup = .;
+
+ . = ALIGN(32);
+ __per_cpu_start = .;
+ .data.percpu : { *(.data.percpu) }
+ __per_cpu_end = .;
+
+ . = ALIGN(4096);
+ __initramfs_start =.;
+ .init.ramfs : { *(.init.ramfs) }
+ __initramfs_end = .;
+
+ /* We need this dummy segment here */
+
+ . = ALIGN(4);
+ .dummy : { LONG(0) }
+
+ /* The vectors are relocated to the real position at startup time */
+
+ SECTION_VECTOR (_WindowVectors_text,
+ .WindowVectors.text,
+ XCHAL_WINDOW_VECTORS_VADDR, 4,
+ .dummy)
+ SECTION_VECTOR (_DebugInterruptVector_literal,
+ .DebugInterruptVector.literal,
+ XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL) - 4,
+ SIZEOF(.WindowVectors.text),
+ .WindowVectors.text)
+ SECTION_VECTOR (_DebugInterruptVector_text,
+ .DebugInterruptVector.text,
+ XCHAL_INTLEVEL_VECTOR_VADDR(XCHAL_DEBUGLEVEL),
+ 4,
+ .DebugInterruptVector.literal)
+ SECTION_VECTOR (_KernelExceptionVector_literal,
+ .KernelExceptionVector.literal,
+ XCHAL_KERNELEXC_VECTOR_VADDR - 4,
+ SIZEOF(.DebugInterruptVector.text),
+ .DebugInterruptVector.text)
+ SECTION_VECTOR (_KernelExceptionVector_text,
+ .KernelExceptionVector.text,
+ XCHAL_KERNELEXC_VECTOR_VADDR,
+ 4,
+ .KernelExceptionVector.literal)
+ SECTION_VECTOR (_UserExceptionVector_literal,
+ .UserExceptionVector.literal,
+ XCHAL_USEREXC_VECTOR_VADDR - 4,
+ SIZEOF(.KernelExceptionVector.text),
+ .KernelExceptionVector.text)
+ SECTION_VECTOR (_UserExceptionVector_text,
+ .UserExceptionVector.text,
+ XCHAL_USEREXC_VECTOR_VADDR,
+ 4,
+ .UserExceptionVector.literal)
+ SECTION_VECTOR (_DoubleExceptionVector_literal,
+ .DoubleExceptionVector.literal,
+ XCHAL_DOUBLEEXC_VECTOR_VADDR - 16,
+ SIZEOF(.UserExceptionVector.text),
+ .UserExceptionVector.text)
+ SECTION_VECTOR (_DoubleExceptionVector_text,
+ .DoubleExceptionVector.text,
+ XCHAL_DOUBLEEXC_VECTOR_VADDR,
+ 32,
+ .DoubleExceptionVector.literal)
+
+ . = (LOADADDR( .DoubleExceptionVector.text ) + SIZEOF( .DoubleExceptionVector.text ) + 3) & ~ 3;
+ . = ALIGN(1<<XCHAL_MMU_MIN_PTE_PAGE_SIZE);
+
+ __init_end = .;
+
+ . = ALIGN(8192);
+
+ /* BSS section */
+ _bss_start = .;
+ .sbss : { *(.sbss) *(.scommon) }
+ .bss : { *(COMMON) *(.bss) }
+ _bss_end = .;
+ _end = .;
+
+ /* only used by the boot loader */
+
+ . = ALIGN(0x10);
+ .bootstrap : { *(.bootstrap.literal .bootstrap.text .bootstrap.data) }
+
+ . = ALIGN(0x1000);
+ __initrd_start = .;
+ .initrd : { *(.initrd) }
+ __initrd_end = .;
+
+ .ResetVector.text XCHAL_RESET_VECTOR_VADDR :
+ {
+ *(.ResetVector.text)
+ }
+
+
+ /* Sections to be discarded */
+ /DISCARD/ :
+ {
+ *(.text.exit)
+ *(.text.exit.literal)
+ *(.data.exit)
+ *(.exitcall.exit)
+ }
+
+
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ .debug_info 0 : { *(.debug_info) }
+ .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) }
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+
+ .xt.insn 0 :
+ {
+ *(.xt.insn)
+ *(.gnu.linkonce.x*)
+ }
+
+ .xt.lit 0 :
+ {
+ *(.xt.lit)
+ *(.gnu.linkonce.p*)
+ }
+}
diff --git a/arch/xtensa/kernel/xtensa_ksyms.c b/arch/xtensa/kernel/xtensa_ksyms.c
new file mode 100644
index 000000000000..efae56a51475
--- /dev/null
+++ b/arch/xtensa/kernel/xtensa_ksyms.c
@@ -0,0 +1,123 @@
+/*
+ * arch/xtensa/kernel/xtensa_ksyms.c
+ *
+ * Export Xtensa-specific functions for loadable modules.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Joe Taylor <joe@tensilica.com>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <asm/irq.h>
+#include <linux/in6.h>
+#include <linux/pci.h>
+#include <linux/ide.h>
+
+#include <asm/uaccess.h>
+#include <asm/checksum.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/semaphore.h>
+#ifdef CONFIG_BLK_DEV_FD
+#include <asm/floppy.h>
+#endif
+#ifdef CONFIG_NET
+#include <net/checksum.h>
+#endif /* CONFIG_NET */
+
+
+/*
+ * String functions
+ */
+EXPORT_SYMBOL(memcmp);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memmove);
+EXPORT_SYMBOL(memchr);
+EXPORT_SYMBOL(strcat);
+EXPORT_SYMBOL(strchr);
+EXPORT_SYMBOL(strlen);
+EXPORT_SYMBOL(strpbrk);
+EXPORT_SYMBOL(strncat);
+EXPORT_SYMBOL(strnlen);
+EXPORT_SYMBOL(strrchr);
+EXPORT_SYMBOL(strstr);
+
+EXPORT_SYMBOL(enable_irq);
+EXPORT_SYMBOL(disable_irq);
+EXPORT_SYMBOL(kernel_thread);
+
+/*
+ * gcc internal math functions
+ */
+extern long long __ashrdi3(long long, int);
+extern long long __ashldi3(long long, int);
+extern long long __lshrdi3(long long, int);
+extern int __divsi3(int, int);
+extern int __modsi3(int, int);
+extern long long __muldi3(long long, long long);
+extern int __mulsi3(int, int);
+extern unsigned int __udivsi3(unsigned int, unsigned int);
+extern unsigned int __umodsi3(unsigned int, unsigned int);
+extern unsigned long long __umoddi3(unsigned long long, unsigned long long);
+extern unsigned long long __udivdi3(unsigned long long, unsigned long long);
+
+EXPORT_SYMBOL(__ashldi3);
+EXPORT_SYMBOL(__ashrdi3);
+EXPORT_SYMBOL(__lshrdi3);
+EXPORT_SYMBOL(__divsi3);
+EXPORT_SYMBOL(__modsi3);
+EXPORT_SYMBOL(__muldi3);
+EXPORT_SYMBOL(__mulsi3);
+EXPORT_SYMBOL(__udivsi3);
+EXPORT_SYMBOL(__umodsi3);
+EXPORT_SYMBOL(__udivdi3);
+EXPORT_SYMBOL(__umoddi3);
+
+/*
+ * Semaphore operations
+ */
+EXPORT_SYMBOL(__down);
+EXPORT_SYMBOL(__down_interruptible);
+EXPORT_SYMBOL(__down_trylock);
+EXPORT_SYMBOL(__up);
+
+#ifdef CONFIG_NET
+/*
+ * Networking support
+ */
+EXPORT_SYMBOL(csum_partial_copy_generic);
+#endif /* CONFIG_NET */
+
+/*
+ * Architecture-specific symbols
+ */
+EXPORT_SYMBOL(__xtensa_copy_user);
+
+/*
+ * Kernel hacking ...
+ */
+
+#if defined(CONFIG_VGA_CONSOLE) || defined(CONFIG_DUMMY_CONSOLE)
+// FIXME EXPORT_SYMBOL(screen_info);
+#endif
+
+EXPORT_SYMBOL(get_wchan);
+
+EXPORT_SYMBOL(outsb);
+EXPORT_SYMBOL(outsw);
+EXPORT_SYMBOL(outsl);
+EXPORT_SYMBOL(insb);
+EXPORT_SYMBOL(insw);
+EXPORT_SYMBOL(insl);
diff --git a/arch/xtensa/lib/Makefile b/arch/xtensa/lib/Makefile
new file mode 100644
index 000000000000..ed935b58e8a4
--- /dev/null
+++ b/arch/xtensa/lib/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for Xtensa-specific library files.
+#
+
+lib-y += memcopy.o memset.o checksum.o strcasecmp.o \
+ usercopy.o strncpy_user.o strnlen_user.o
+lib-$(CONFIG_PCI) += pci-auto.o
diff --git a/arch/xtensa/lib/checksum.S b/arch/xtensa/lib/checksum.S
new file mode 100644
index 000000000000..e2d64dfd530c
--- /dev/null
+++ b/arch/xtensa/lib/checksum.S
@@ -0,0 +1,410 @@
+/*
+ * 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
+ *
+ * Xtensa version: Copyright (C) 2001 Tensilica, Inc. by Kevin Chea
+ * Optimized by Joe Taylor
+ *
+ * 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 <asm/errno.h>
+#include <linux/linkage.h>
+#define _ASMLANGUAGE
+#include <xtensa/config/core.h>
+
+/*
+ * computes a partial checksum, e.g. for TCP/UDP fragments
+ */
+
+/*
+ * unsigned int csum_partial(const unsigned char *buf, int len,
+ * unsigned int sum);
+ * a2 = buf
+ * a3 = len
+ * a4 = sum
+ *
+ * This function assumes 2- or 4-byte alignment. Other alignments will fail!
+ */
+
+/* ONES_ADD converts twos-complement math to ones-complement. */
+#define ONES_ADD(sum, val) \
+ add sum, sum, val ; \
+ bgeu sum, val, 99f ; \
+ addi sum, sum, 1 ; \
+99: ;
+
+.text
+ENTRY(csum_partial)
+ /*
+ * Experiments with Ethernet and SLIP connections show that buf
+ * is aligned on either a 2-byte or 4-byte boundary.
+ */
+ entry sp, 32
+ extui a5, a2, 0, 2
+ bnez a5, 8f /* branch if 2-byte aligned */
+ /* Fall-through on common case, 4-byte alignment */
+1:
+ srli a5, a3, 5 /* 32-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a5, 2f
+#else
+ beqz a5, 2f
+ slli a5, a5, 5
+ add a5, a5, a2 /* a5 = end of last 32-byte chunk */
+.Loop1:
+#endif
+ l32i a6, a2, 0
+ l32i a7, a2, 4
+ ONES_ADD(a4, a6)
+ ONES_ADD(a4, a7)
+ l32i a6, a2, 8
+ l32i a7, a2, 12
+ ONES_ADD(a4, a6)
+ ONES_ADD(a4, a7)
+ l32i a6, a2, 16
+ l32i a7, a2, 20
+ ONES_ADD(a4, a6)
+ ONES_ADD(a4, a7)
+ l32i a6, a2, 24
+ l32i a7, a2, 28
+ ONES_ADD(a4, a6)
+ ONES_ADD(a4, a7)
+ addi a2, a2, 4*8
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a5, .Loop1
+#endif
+2:
+ extui a5, a3, 2, 3 /* remaining 4-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a5, 3f
+#else
+ beqz a5, 3f
+ slli a5, a5, 2
+ add a5, a5, a2 /* a5 = end of last 4-byte chunk */
+.Loop2:
+#endif
+ l32i a6, a2, 0
+ ONES_ADD(a4, a6)
+ addi a2, a2, 4
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a5, .Loop2
+#endif
+3:
+ _bbci.l a3, 1, 5f /* remaining 2-byte chunk */
+ l16ui a6, a2, 0
+ ONES_ADD(a4, a6)
+ addi a2, a2, 2
+5:
+ _bbci.l a3, 0, 7f /* remaining 1-byte chunk */
+6: l8ui a6, a2, 0
+#ifdef __XTENSA_EB__
+ slli a6, a6, 8 /* load byte into bits 8..15 */
+#endif
+ ONES_ADD(a4, a6)
+7:
+ mov a2, a4
+ retw
+
+ /* uncommon case, buf is 2-byte aligned */
+8:
+ beqz a3, 7b /* branch if len == 0 */
+ beqi a3, 1, 6b /* branch if len == 1 */
+
+ extui a5, a2, 0, 1
+ bnez a5, 8f /* branch if 1-byte aligned */
+
+ l16ui a6, a2, 0 /* common case, len >= 2 */
+ ONES_ADD(a4, a6)
+ addi a2, a2, 2 /* adjust buf */
+ addi a3, a3, -2 /* adjust len */
+ j 1b /* now buf is 4-byte aligned */
+
+ /* case: odd-byte aligned, len > 1
+ * This case is dog slow, so don't give us an odd address.
+ * (I don't think this ever happens, but just in case.)
+ */
+8:
+ srli a5, a3, 2 /* 4-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a5, 2f
+#else
+ beqz a5, 2f
+ slli a5, a5, 2
+ add a5, a5, a2 /* a5 = end of last 4-byte chunk */
+.Loop3:
+#endif
+ l8ui a6, a2, 0 /* bits 24..31 */
+ l16ui a7, a2, 1 /* bits 8..23 */
+ l8ui a8, a2, 3 /* bits 0.. 8 */
+#ifdef __XTENSA_EB__
+ slli a6, a6, 24
+#else
+ slli a8, a8, 24
+#endif
+ slli a7, a7, 8
+ or a7, a7, a6
+ or a7, a7, a8
+ ONES_ADD(a4, a7)
+ addi a2, a2, 4
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a5, .Loop3
+#endif
+2:
+ _bbci.l a3, 1, 3f /* remaining 2-byte chunk, still odd addr */
+ l8ui a6, a2, 0
+ l8ui a7, a2, 1
+#ifdef __XTENSA_EB__
+ slli a6, a6, 8
+#else
+ slli a7, a7, 8
+#endif
+ or a7, a7, a6
+ ONES_ADD(a4, a7)
+ addi a2, a2, 2
+3:
+ j 5b /* branch to handle the remaining byte */
+
+
+
+/*
+ * 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 each access type.
+ */
+
+#define SRC(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6001f ; \
+ .previous
+
+#define DST(y...) \
+ 9999: y; \
+ .section __ex_table, "a"; \
+ .long 9999b, 6002f ; \
+ .previous
+
+/*
+unsigned int csum_partial_copy_generic (const char *src, char *dst, int len,
+ int sum, int *src_err_ptr, int *dst_err_ptr)
+ a2 = src
+ a3 = dst
+ a4 = len
+ a5 = sum
+ a6 = src_err_ptr
+ a7 = dst_err_ptr
+ a8 = temp
+ a9 = temp
+ a10 = temp
+ a11 = original len for exception handling
+ a12 = original dst for exception handling
+
+ This function is optimized for 4-byte aligned addresses. Other
+ alignments work, but not nearly as efficiently.
+ */
+
+ENTRY(csum_partial_copy_generic)
+ entry sp, 32
+ mov a12, a3
+ mov a11, a4
+ or a10, a2, a3
+
+ /* We optimize the following alignment tests for the 4-byte
+ aligned case. Two bbsi.l instructions might seem more optimal
+ (commented out below). However, both labels 5: and 3: are out
+ of the imm8 range, so the assembler relaxes them into
+ equivalent bbci.l, j combinations, which is actually
+ slower. */
+
+ extui a9, a10, 0, 2
+ beqz a9, 1f /* branch if both are 4-byte aligned */
+ bbsi.l a10, 0, 5f /* branch if one address is odd */
+ j 3f /* one address is 2-byte aligned */
+
+/* _bbsi.l a10, 0, 5f */ /* branch if odd address */
+/* _bbsi.l a10, 1, 3f */ /* branch if 2-byte-aligned address */
+
+1:
+ /* src and dst are both 4-byte aligned */
+ srli a10, a4, 5 /* 32-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a10, 2f
+#else
+ beqz a10, 2f
+ slli a10, a10, 5
+ add a10, a10, a2 /* a10 = end of last 32-byte src chunk */
+.Loop5:
+#endif
+SRC( l32i a9, a2, 0 )
+SRC( l32i a8, a2, 4 )
+DST( s32i a9, a3, 0 )
+DST( s32i a8, a3, 4 )
+ ONES_ADD(a5, a9)
+ ONES_ADD(a5, a8)
+SRC( l32i a9, a2, 8 )
+SRC( l32i a8, a2, 12 )
+DST( s32i a9, a3, 8 )
+DST( s32i a8, a3, 12 )
+ ONES_ADD(a5, a9)
+ ONES_ADD(a5, a8)
+SRC( l32i a9, a2, 16 )
+SRC( l32i a8, a2, 20 )
+DST( s32i a9, a3, 16 )
+DST( s32i a8, a3, 20 )
+ ONES_ADD(a5, a9)
+ ONES_ADD(a5, a8)
+SRC( l32i a9, a2, 24 )
+SRC( l32i a8, a2, 28 )
+DST( s32i a9, a3, 24 )
+DST( s32i a8, a3, 28 )
+ ONES_ADD(a5, a9)
+ ONES_ADD(a5, a8)
+ addi a2, a2, 32
+ addi a3, a3, 32
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a10, .Loop5
+#endif
+2:
+ extui a10, a4, 2, 3 /* remaining 4-byte chunks */
+ extui a4, a4, 0, 2 /* reset len for general-case, 2-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a10, 3f
+#else
+ beqz a10, 3f
+ slli a10, a10, 2
+ add a10, a10, a2 /* a10 = end of last 4-byte src chunk */
+.Loop6:
+#endif
+SRC( l32i a9, a2, 0 )
+DST( s32i a9, a3, 0 )
+ ONES_ADD(a5, a9)
+ addi a2, a2, 4
+ addi a3, a3, 4
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a10, .Loop6
+#endif
+3:
+ /*
+ Control comes to here in two cases: (1) It may fall through
+ to here from the 4-byte alignment case to process, at most,
+ one 2-byte chunk. (2) It branches to here from above if
+ either src or dst is 2-byte aligned, and we process all bytes
+ here, except for perhaps a trailing odd byte. It's
+ inefficient, so align your addresses to 4-byte boundaries.
+
+ a2 = src
+ a3 = dst
+ a4 = len
+ a5 = sum
+ */
+ srli a10, a4, 1 /* 2-byte chunks */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a10, 4f
+#else
+ beqz a10, 4f
+ slli a10, a10, 1
+ add a10, a10, a2 /* a10 = end of last 2-byte src chunk */
+.Loop7:
+#endif
+SRC( l16ui a9, a2, 0 )
+DST( s16i a9, a3, 0 )
+ ONES_ADD(a5, a9)
+ addi a2, a2, 2
+ addi a3, a3, 2
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a10, .Loop7
+#endif
+4:
+ /* This section processes a possible trailing odd byte. */
+ _bbci.l a4, 0, 8f /* 1-byte chunk */
+SRC( l8ui a9, a2, 0 )
+DST( s8i a9, a3, 0 )
+#ifdef __XTENSA_EB__
+ slli a9, a9, 8 /* shift byte to bits 8..15 */
+#endif
+ ONES_ADD(a5, a9)
+8:
+ mov a2, a5
+ retw
+
+5:
+ /* Control branch to here when either src or dst is odd. We
+ process all bytes using 8-bit accesses. Grossly inefficient,
+ so don't feed us an odd address. */
+
+ srli a10, a4, 1 /* handle in pairs for 16-bit csum */
+#if XCHAL_HAVE_LOOPS
+ loopgtz a10, 6f
+#else
+ beqz a10, 6f
+ slli a10, a10, 1
+ add a10, a10, a2 /* a10 = end of last odd-aligned, 2-byte src chunk */
+.Loop8:
+#endif
+SRC( l8ui a9, a2, 0 )
+SRC( l8ui a8, a2, 1 )
+DST( s8i a9, a3, 0 )
+DST( s8i a8, a3, 1 )
+#ifdef __XTENSA_EB__
+ slli a9, a9, 8 /* combine into a single 16-bit value */
+#else /* for checksum computation */
+ slli a8, a8, 8
+#endif
+ or a9, a9, a8
+ ONES_ADD(a5, a9)
+ addi a2, a2, 2
+ addi a3, a3, 2
+#if !XCHAL_HAVE_LOOPS
+ blt a2, a10, .Loop8
+#endif
+6:
+ j 4b /* process the possible trailing odd byte */
+
+
+# Exception handler:
+.section .fixup, "ax"
+/*
+ a6 = src_err_ptr
+ a7 = dst_err_ptr
+ a11 = original len for exception handling
+ a12 = original dst for exception handling
+*/
+
+6001:
+ _movi a2, -EFAULT
+ s32i a2, a6, 0 /* src_err_ptr */
+
+ # clear the complete destination - computing the rest
+ # is too much work
+ movi a2, 0
+#if XCHAL_HAVE_LOOPS
+ loopgtz a11, 2f
+#else
+ beqz a11, 2f
+ add a11, a11, a12 /* a11 = ending address */
+.Leloop:
+#endif
+ s8i a2, a12, 0
+ addi a12, a12, 1
+#if !XCHAL_HAVE_LOOPS
+ blt a12, a11, .Leloop
+#endif
+2:
+ retw
+
+6002:
+ movi a2, -EFAULT
+ s32i a2, a7, 0 /* dst_err_ptr */
+ movi a2, 0
+ retw
+
+.previous
+
diff --git a/arch/xtensa/lib/memcopy.S b/arch/xtensa/lib/memcopy.S
new file mode 100644
index 000000000000..e8f6d7eb7222
--- /dev/null
+++ b/arch/xtensa/lib/memcopy.S
@@ -0,0 +1,315 @@
+/*
+ * arch/xtensa/lib/hal/memcopy.S -- Core HAL library functions
+ * xthal_memcpy and xthal_bcopy
+ *
+ * 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) 2002 - 2005 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+ .macro src_b r, w0, w1
+#ifdef __XTENSA_EB__
+ src \r, \w0, \w1
+#else
+ src \r, \w1, \w0
+#endif
+ .endm
+
+ .macro ssa8 r
+#ifdef __XTENSA_EB__
+ ssa8b \r
+#else
+ ssa8l \r
+#endif
+ .endm
+
+
+/*
+ * void *memcpy(void *dst, const void *src, size_t len);
+ * void *memmove(void *dst, const void *src, size_t len);
+ * void *bcopy(const void *src, void *dst, size_t len);
+ *
+ * This function is intended to do the same thing as the standard
+ * library function memcpy() (or bcopy()) for most cases.
+ * However, where the source and/or destination references
+ * an instruction RAM or ROM or a data RAM or ROM, that
+ * source and/or destination will always be accessed with
+ * 32-bit load and store instructions (as required for these
+ * types of devices).
+ *
+ * !!!!!!! XTFIXME:
+ * !!!!!!! Handling of IRAM/IROM has not yet
+ * !!!!!!! been implemented.
+ *
+ * The bcopy version is provided here to avoid the overhead
+ * of an extra call, for callers that require this convention.
+ *
+ * The (general case) algorithm is as follows:
+ * If destination is unaligned, align it by conditionally
+ * copying 1 and 2 bytes.
+ * If source is aligned,
+ * do 16 bytes with a loop, and then finish up with
+ * 8, 4, 2, and 1 byte copies conditional on the length;
+ * else (if source is unaligned),
+ * do the same, but use SRC to align the source data.
+ * This code tries to use fall-through branches for the common
+ * case of aligned source and destination and multiple
+ * of 4 (or 8) length.
+ *
+ * Register use:
+ * a0/ return address
+ * a1/ stack pointer
+ * a2/ return value
+ * a3/ src
+ * a4/ length
+ * a5/ dst
+ * a6/ tmp
+ * a7/ tmp
+ * a8/ tmp
+ * a9/ tmp
+ * a10/ tmp
+ * a11/ tmp
+ */
+
+ .text
+ .align 4
+ .global bcopy
+ .type bcopy,@function
+bcopy:
+ entry sp, 16 # minimal stack frame
+ # a2=src, a3=dst, a4=len
+ mov a5, a3 # copy dst so that a2 is return value
+ mov a3, a2
+ mov a2, a5
+ j .Lcommon # go to common code for memcpy+bcopy
+
+
+/*
+ * Byte by byte copy
+ */
+ .align 4
+ .byte 0 # 1 mod 4 alignment for LOOPNEZ
+ # (0 mod 4 alignment for LBEG)
+.Lbytecopy:
+#if XCHAL_HAVE_LOOPS
+ loopnez a4, .Lbytecopydone
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a4, .Lbytecopydone
+ add a7, a3, a4 # a7 = end address for source
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+ l8ui a6, a3, 0
+ addi a3, a3, 1
+ s8i a6, a5, 0
+ addi a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a7, .Lnextbyte
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytecopydone:
+ retw
+
+/*
+ * Destination is unaligned
+ */
+
+ .align 4
+.Ldst1mod2: # dst is only byte aligned
+ _bltui a4, 7, .Lbytecopy # do short copies byte by byte
+
+ # copy 1 byte
+ l8ui a6, a3, 0
+ addi a3, a3, 1
+ addi a4, a4, -1
+ s8i a6, a5, 0
+ addi a5, a5, 1
+ _bbci.l a5, 1, .Ldstaligned # if dst is now aligned, then
+ # return to main algorithm
+.Ldst2mod4: # dst 16-bit aligned
+ # copy 2 bytes
+ _bltui a4, 6, .Lbytecopy # do short copies byte by byte
+ l8ui a6, a3, 0
+ l8ui a7, a3, 1
+ addi a3, a3, 2
+ addi a4, a4, -2
+ s8i a6, a5, 0
+ s8i a7, a5, 1
+ addi a5, a5, 2
+ j .Ldstaligned # dst is now aligned, return to main algorithm
+
+ .align 4
+ .global memcpy
+ .type memcpy,@function
+memcpy:
+ .global memmove
+ .type memmove,@function
+memmove:
+
+ entry sp, 16 # minimal stack frame
+ # a2/ dst, a3/ src, a4/ len
+ mov a5, a2 # copy dst so that a2 is return value
+.Lcommon:
+ _bbsi.l a2, 0, .Ldst1mod2 # if dst is 1 mod 2
+ _bbsi.l a2, 1, .Ldst2mod4 # if dst is 2 mod 4
+.Ldstaligned: # return here from .Ldst?mod? once dst is aligned
+ srli a7, a4, 4 # number of loop iterations with 16B
+ # per iteration
+ movi a8, 3 # if source is not aligned,
+ _bany a3, a8, .Lsrcunaligned # then use shifting copy
+ /*
+ * Destination and source are word-aligned, use word copy.
+ */
+ # copy 16 bytes per iteration for word-aligned dst and word-aligned src
+#if XCHAL_HAVE_LOOPS
+ loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a7, .Loop1done
+ slli a8, a7, 4
+ add a8, a8, a3 # a8 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+ l32i a6, a3, 0
+ l32i a7, a3, 4
+ s32i a6, a5, 0
+ l32i a6, a3, 8
+ s32i a7, a5, 4
+ l32i a7, a3, 12
+ s32i a6, a5, 8
+ addi a3, a3, 16
+ s32i a7, a5, 12
+ addi a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a8, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+ bbci.l a4, 3, .L2
+ # copy 8 bytes
+ l32i a6, a3, 0
+ l32i a7, a3, 4
+ addi a3, a3, 8
+ s32i a6, a5, 0
+ s32i a7, a5, 4
+ addi a5, a5, 8
+.L2:
+ bbsi.l a4, 2, .L3
+ bbsi.l a4, 1, .L4
+ bbsi.l a4, 0, .L5
+ retw
+.L3:
+ # copy 4 bytes
+ l32i a6, a3, 0
+ addi a3, a3, 4
+ s32i a6, a5, 0
+ addi a5, a5, 4
+ bbsi.l a4, 1, .L4
+ bbsi.l a4, 0, .L5
+ retw
+.L4:
+ # copy 2 bytes
+ l16ui a6, a3, 0
+ addi a3, a3, 2
+ s16i a6, a5, 0
+ addi a5, a5, 2
+ bbsi.l a4, 0, .L5
+ retw
+.L5:
+ # copy 1 byte
+ l8ui a6, a3, 0
+ s8i a6, a5, 0
+ retw
+
+/*
+ * Destination is aligned, Source is unaligned
+ */
+
+ .align 4
+.Lsrcunaligned:
+ _beqz a4, .Ldone # avoid loading anything for zero-length copies
+ # copy 16 bytes per iteration for word-aligned dst and unaligned src
+ ssa8 a3 # set shift amount from byte offset
+#define SIM_CHECKS_ALIGNMENT 1 /* set to 1 when running on ISS (simulator) with the
+ lint or ferret client, or 0 to save a few cycles */
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
+ and a11, a3, a8 # save unalignment offset for below
+ sub a3, a3, a11 # align a3
+#endif
+ l32i a6, a3, 0 # load first word
+#if XCHAL_HAVE_LOOPS
+ loopnez a7, .Loop2done
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a7, .Loop2done
+ slli a10, a7, 4
+ add a10, a10, a3 # a10 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2:
+ l32i a7, a3, 4
+ l32i a8, a3, 8
+ src_b a6, a6, a7
+ s32i a6, a5, 0
+ l32i a9, a3, 12
+ src_b a7, a7, a8
+ s32i a7, a5, 4
+ l32i a6, a3, 16
+ src_b a8, a8, a9
+ s32i a8, a5, 8
+ addi a3, a3, 16
+ src_b a9, a9, a6
+ s32i a9, a5, 12
+ addi a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a10, .Loop2
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2done:
+ bbci.l a4, 3, .L12
+ # copy 8 bytes
+ l32i a7, a3, 4
+ l32i a8, a3, 8
+ src_b a6, a6, a7
+ s32i a6, a5, 0
+ addi a3, a3, 8
+ src_b a7, a7, a8
+ s32i a7, a5, 4
+ addi a5, a5, 8
+ mov a6, a8
+.L12:
+ bbci.l a4, 2, .L13
+ # copy 4 bytes
+ l32i a7, a3, 4
+ addi a3, a3, 4
+ src_b a6, a6, a7
+ s32i a6, a5, 0
+ addi a5, a5, 4
+ mov a6, a7
+.L13:
+#if XCHAL_UNALIGNED_LOAD_EXCEPTION || SIM_CHECKS_ALIGNMENT
+ add a3, a3, a11 # readjust a3 with correct misalignment
+#endif
+ bbsi.l a4, 1, .L14
+ bbsi.l a4, 0, .L15
+.Ldone: retw
+.L14:
+ # copy 2 bytes
+ l8ui a6, a3, 0
+ l8ui a7, a3, 1
+ addi a3, a3, 2
+ s8i a6, a5, 0
+ s8i a7, a5, 1
+ addi a5, a5, 2
+ bbsi.l a4, 0, .L15
+ retw
+.L15:
+ # copy 1 byte
+ l8ui a6, a3, 0
+ s8i a6, a5, 0
+ retw
+
+/*
+ * Local Variables:
+ * mode:fundamental
+ * comment-start: "# "
+ * comment-start-skip: "# *"
+ * End:
+ */
diff --git a/arch/xtensa/lib/memset.S b/arch/xtensa/lib/memset.S
new file mode 100644
index 000000000000..4de25134bc62
--- /dev/null
+++ b/arch/xtensa/lib/memset.S
@@ -0,0 +1,160 @@
+/*
+ * arch/xtensa/lib/memset.S
+ *
+ * ANSI C standard library function memset
+ * (Well, almost. .fixup code might return zero.)
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+/*
+ * void *memset(void *dst, int c, size_t length)
+ *
+ * The algorithm is as follows:
+ * Create a word with c in all byte positions
+ * If the destination is aligned,
+ * do 16B chucks with a loop, and then finish up with
+ * 8B, 4B, 2B, and 1B stores conditional on the length.
+ * If destination is unaligned, align it by conditionally
+ * setting 1B and 2B and then go to aligned case.
+ * This code tries to use fall-through branches for the common
+ * case of an aligned destination (except for the branches to
+ * the alignment labels).
+ */
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler) \
+9: insn reg1, reg2, offset; \
+ .section __ex_table, "a"; \
+ .word 9b, handler; \
+ .previous
+
+
+.text
+.align 4
+.global memset
+.type memset,@function
+memset:
+ entry sp, 16 # minimal stack frame
+ # a2/ dst, a3/ c, a4/ length
+ extui a3, a3, 0, 8 # mask to just 8 bits
+ slli a7, a3, 8 # duplicate character in all bytes of word
+ or a3, a3, a7 # ...
+ slli a7, a3, 16 # ...
+ or a3, a3, a7 # ...
+ mov a5, a2 # copy dst so that a2 is return value
+ movi a6, 3 # for alignment tests
+ bany a2, a6, .Ldstunaligned # if dst is unaligned
+.L0: # return here from .Ldstunaligned when dst is aligned
+ srli a7, a4, 4 # number of loop iterations with 16B
+ # per iteration
+ bnez a4, .Laligned
+ retw
+
+/*
+ * Destination is word-aligned.
+ */
+ # set 16 bytes per iteration for word-aligned dst
+ .align 4 # 1 mod 4 alignment for LOOPNEZ
+ .byte 0 # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+ loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a7, .Loop1done
+ slli a6, a7, 4
+ add a6, a6, a5 # a6 = end of last 16B chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+ EX(s32i, a3, a5, 0, memset_fixup)
+ EX(s32i, a3, a5, 4, memset_fixup)
+ EX(s32i, a3, a5, 8, memset_fixup)
+ EX(s32i, a3, a5, 12, memset_fixup)
+ addi a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+ blt a5, a6, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+ bbci.l a4, 3, .L2
+ # set 8 bytes
+ EX(s32i, a3, a5, 0, memset_fixup)
+ EX(s32i, a3, a5, 4, memset_fixup)
+ addi a5, a5, 8
+.L2:
+ bbci.l a4, 2, .L3
+ # set 4 bytes
+ EX(s32i, a3, a5, 0, memset_fixup)
+ addi a5, a5, 4
+.L3:
+ bbci.l a4, 1, .L4
+ # set 2 bytes
+ EX(s16i, a3, a5, 0, memset_fixup)
+ addi a5, a5, 2
+.L4:
+ bbci.l a4, 0, .L5
+ # set 1 byte
+ EX(s8i, a3, a5, 0, memset_fixup)
+.L5:
+.Lret1:
+ retw
+
+/*
+ * Destination is unaligned
+ */
+
+.Ldstunaligned:
+ bltui a4, 8, .Lbyteset # do short copies byte by byte
+ bbci.l a5, 0, .L20 # branch if dst alignment half-aligned
+ # dst is only byte aligned
+ # set 1 byte
+ EX(s8i, a3, a5, 0, memset_fixup)
+ addi a5, a5, 1
+ addi a4, a4, -1
+ # now retest if dst aligned
+ bbci.l a5, 1, .L0 # if now aligned, return to main algorithm
+.L20:
+ # dst half-aligned
+ # set 2 bytes
+ EX(s16i, a3, a5, 0, memset_fixup)
+ addi a5, a5, 2
+ addi a4, a4, -2
+ j .L0 # dst is now aligned, return to main algorithm
+
+/*
+ * Byte by byte set
+ */
+ .align 4
+ .byte 0 # 1 mod 4 alignment for LOOPNEZ
+ # (0 mod 4 alignment for LBEG)
+.Lbyteset:
+#if XCHAL_HAVE_LOOPS
+ loopnez a4, .Lbytesetdone
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a4, .Lbytesetdone
+ add a6, a5, a4 # a6 = ending address
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbyteloop:
+ EX(s8i, a3, a5, 0, memset_fixup)
+ addi a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+ blt a5, a6, .Lbyteloop
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytesetdone:
+ retw
+
+
+ .section .fixup, "ax"
+ .align 4
+
+/* We return zero if a failure occurred. */
+
+memset_fixup:
+ movi a2, 0
+ retw
diff --git a/arch/xtensa/lib/pci-auto.c b/arch/xtensa/lib/pci-auto.c
new file mode 100644
index 000000000000..90c790f6123b
--- /dev/null
+++ b/arch/xtensa/lib/pci-auto.c
@@ -0,0 +1,352 @@
+/*
+ * arch/xtensa/kernel/pci-auto.c
+ *
+ * PCI autoconfiguration library
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <zankel@tensilica.com, cez@zankel.net>
+ *
+ * Based on work from Matt Porter <mporter@mvista.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+
+#include <asm/pci-bridge.h>
+
+
+/*
+ *
+ * Setting up a PCI
+ *
+ * pci_ctrl->first_busno = <first bus number (0)>
+ * pci_ctrl->last_busno = <last bus number (0xff)>
+ * pci_ctrl->ops = <PCI config operations>
+ * pci_ctrl->map_irq = <function to return the interrupt number for a device>
+ *
+ * pci_ctrl->io_space.start = <IO space start address (PCI view)>
+ * pci_ctrl->io_space.end = <IO space end address (PCI view)>
+ * pci_ctrl->io_space.base = <IO space offset: address 0 from CPU space>
+ * pci_ctrl->mem_space.start = <MEM space start address (PCI view)>
+ * pci_ctrl->mem_space.end = <MEM space end address (PCI view)>
+ * pci_ctrl->mem_space.base = <MEM space offset: address 0 from CPU space>
+ *
+ * pcibios_init_resource(&pci_ctrl->io_resource, <IO space start>,
+ * <IO space end>, IORESOURCE_IO, "PCI host bridge");
+ * pcibios_init_resource(&pci_ctrl->mem_resources[0], <MEM space start>,
+ * <MEM space end>, IORESOURCE_MEM, "PCI host bridge");
+ *
+ * pci_ctrl->last_busno = pciauto_bus_scan(pci_ctrl,pci_ctrl->first_busno);
+ *
+ * int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
+ *
+ */
+
+
+/* define DEBUG to print some debugging messages. */
+
+#undef DEBUG
+
+#ifdef DEBUG
+# define DBG(x...) printk(x)
+#else
+# define DBG(x...)
+#endif
+
+static int pciauto_upper_iospc;
+static int pciauto_upper_memspc;
+
+static struct pci_dev pciauto_dev;
+static struct pci_bus pciauto_bus;
+
+/*
+ * Helper functions
+ */
+
+/* Initialize the bars of a PCI device. */
+
+static void __init
+pciauto_setup_bars(struct pci_dev *dev, int bar_limit)
+{
+ int bar_size;
+ int bar, bar_nr;
+ int *upper_limit;
+ int found_mem64 = 0;
+
+ for (bar = PCI_BASE_ADDRESS_0, bar_nr = 0;
+ bar <= bar_limit;
+ bar+=4, bar_nr++)
+ {
+ /* Tickle the BAR and get the size */
+ pci_write_config_dword(dev, bar, 0xffffffff);
+ pci_read_config_dword(dev, bar, &bar_size);
+
+ /* If BAR is not implemented go to the next BAR */
+ if (!bar_size)
+ continue;
+
+ /* Check the BAR type and set our address mask */
+ if (bar_size & PCI_BASE_ADDRESS_SPACE_IO)
+ {
+ bar_size &= PCI_BASE_ADDRESS_IO_MASK;
+ upper_limit = &pciauto_upper_iospc;
+ DBG("PCI Autoconfig: BAR %d, I/O, ", bar_nr);
+ }
+ else
+ {
+ if ((bar_size & PCI_BASE_ADDRESS_MEM_TYPE_MASK) ==
+ PCI_BASE_ADDRESS_MEM_TYPE_64)
+ found_mem64 = 1;
+
+ bar_size &= PCI_BASE_ADDRESS_MEM_MASK;
+ upper_limit = &pciauto_upper_memspc;
+ DBG("PCI Autoconfig: BAR %d, Mem, ", bar_nr);
+ }
+
+ /* Allocate a base address (bar_size is negative!) */
+ *upper_limit = (*upper_limit + bar_size) & bar_size;
+
+ /* Write it out and update our limit */
+ pci_write_config_dword(dev, bar, *upper_limit);
+
+ /*
+ * If we are a 64-bit decoder then increment to the
+ * upper 32 bits of the bar and force it to locate
+ * in the lower 4GB of memory.
+ */
+
+ if (found_mem64)
+ pci_write_config_dword(dev, (bar+=4), 0x00000000);
+
+ DBG("size=0x%x, address=0x%x\n", ~bar_size + 1, *upper_limit);
+ }
+}
+
+/* Initialize the interrupt number. */
+
+static void __init
+pciauto_setup_irq(struct pci_controller* pci_ctrl,struct pci_dev *dev,int devfn)
+{
+ u8 pin;
+ int irq = 0;
+
+ pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+
+ /* Fix illegal pin numbers. */
+
+ if (pin == 0 || pin > 4)
+ pin = 1;
+
+ if (pci_ctrl->map_irq)
+ irq = pci_ctrl->map_irq(dev, PCI_SLOT(devfn), pin);
+
+ if (irq == -1)
+ irq = 0;
+
+ DBG("PCI Autoconfig: Interrupt %d, pin %d\n", irq, pin);
+
+ pci_write_config_byte(dev, PCI_INTERRUPT_LINE, irq);
+}
+
+
+static void __init
+pciauto_prescan_setup_bridge(struct pci_dev *dev, int current_bus,
+ int sub_bus, int *iosave, int *memsave)
+{
+ /* Configure bus number registers */
+ pci_write_config_byte(dev, PCI_PRIMARY_BUS, current_bus);
+ pci_write_config_byte(dev, PCI_SECONDARY_BUS, sub_bus + 1);
+ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, 0xff);
+
+ /* Round memory allocator to 1MB boundary */
+ pciauto_upper_memspc &= ~(0x100000 - 1);
+ *memsave = pciauto_upper_memspc;
+
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_upper_iospc &= ~(0x1000 - 1);
+ *iosave = pciauto_upper_iospc;
+
+ /* Set up memory and I/O filter limits, assume 32-bit I/O space */
+ pci_write_config_word(dev, PCI_MEMORY_LIMIT,
+ ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+ pci_write_config_byte(dev, PCI_IO_LIMIT,
+ ((pciauto_upper_iospc - 1) & 0x0000f000) >> 8);
+ pci_write_config_word(dev, PCI_IO_LIMIT_UPPER16,
+ ((pciauto_upper_iospc - 1) & 0xffff0000) >> 16);
+}
+
+static void __init
+pciauto_postscan_setup_bridge(struct pci_dev *dev, int current_bus, int sub_bus,
+ int *iosave, int *memsave)
+{
+ int cmdstat;
+
+ /* Configure bus number registers */
+ pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, sub_bus);
+
+ /*
+ * Round memory allocator to 1MB boundary.
+ * If no space used, allocate minimum.
+ */
+ pciauto_upper_memspc &= ~(0x100000 - 1);
+ if (*memsave == pciauto_upper_memspc)
+ pciauto_upper_memspc -= 0x00100000;
+
+ pci_write_config_word(dev, PCI_MEMORY_BASE, pciauto_upper_memspc >> 16);
+
+ /* Allocate 1MB for pre-fretch */
+ pci_write_config_word(dev, PCI_PREF_MEMORY_LIMIT,
+ ((pciauto_upper_memspc - 1) & 0xfff00000) >> 16);
+
+ pciauto_upper_memspc -= 0x100000;
+
+ pci_write_config_word(dev, PCI_PREF_MEMORY_BASE,
+ pciauto_upper_memspc >> 16);
+
+ /* Round I/O allocator to 4KB boundary */
+ pciauto_upper_iospc &= ~(0x1000 - 1);
+ if (*iosave == pciauto_upper_iospc)
+ pciauto_upper_iospc -= 0x1000;
+
+ pci_write_config_byte(dev, PCI_IO_BASE,
+ (pciauto_upper_iospc & 0x0000f000) >> 8);
+ pci_write_config_word(dev, PCI_IO_BASE_UPPER16,
+ pciauto_upper_iospc >> 16);
+
+ /* Enable memory and I/O accesses, enable bus master */
+ pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
+ pci_write_config_dword(dev, PCI_COMMAND,
+ cmdstat |
+ PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER);
+}
+
+/*
+ * Scan the current PCI bus.
+ */
+
+
+int __init pciauto_bus_scan(struct pci_controller *pci_ctrl, int current_bus)
+{
+ int sub_bus, pci_devfn, pci_class, cmdstat, found_multi=0;
+ unsigned short vid;
+ unsigned char header_type;
+ struct pci_dev *dev = &pciauto_dev;
+
+ pciauto_dev.bus = &pciauto_bus;
+ pciauto_dev.sysdata = pci_ctrl;
+ pciauto_bus.ops = pci_ctrl->ops;
+
+ /*
+ * Fetch our I/O and memory space upper boundaries used
+ * to allocated base addresses on this pci_controller.
+ */
+
+ if (current_bus == pci_ctrl->first_busno)
+ {
+ pciauto_upper_iospc = pci_ctrl->io_resource.end + 1;
+ pciauto_upper_memspc = pci_ctrl->mem_resources[0].end + 1;
+ }
+
+ sub_bus = current_bus;
+
+ for (pci_devfn = 0; pci_devfn < 0xff; pci_devfn++)
+ {
+ /* Skip our host bridge */
+ if ((current_bus == pci_ctrl->first_busno) && (pci_devfn == 0))
+ continue;
+
+ if (PCI_FUNC(pci_devfn) && !found_multi)
+ continue;
+
+ pciauto_bus.number = current_bus;
+ pciauto_dev.devfn = pci_devfn;
+
+ /* If config space read fails from this device, move on */
+ if (pci_read_config_byte(dev, PCI_HEADER_TYPE, &header_type))
+ continue;
+
+ if (!PCI_FUNC(pci_devfn))
+ found_multi = header_type & 0x80;
+ pci_read_config_word(dev, PCI_VENDOR_ID, &vid);
+
+ if (vid == 0xffff || vid == 0x0000) {
+ found_multi = 0;
+ continue;
+ }
+
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &pci_class);
+
+ if ((pci_class >> 16) == PCI_CLASS_BRIDGE_PCI) {
+
+ int iosave, memsave;
+
+ DBG("PCI Autoconfig: Found P2P bridge, device %d\n",
+ PCI_SLOT(pci_devfn));
+
+ /* Allocate PCI I/O and/or memory space */
+ pciauto_setup_bars(dev, PCI_BASE_ADDRESS_1);
+
+ pciauto_prescan_setup_bridge(dev, current_bus, sub_bus,
+ &iosave, &memsave);
+ sub_bus = pciauto_bus_scan(pci_ctrl, sub_bus+1);
+ pciauto_postscan_setup_bridge(dev, current_bus, sub_bus,
+ &iosave, &memsave);
+ pciauto_bus.number = current_bus;
+
+ continue;
+
+ }
+
+
+#if 0
+ /* Skip legacy mode IDE controller */
+
+ if ((pci_class >> 16) == PCI_CLASS_STORAGE_IDE) {
+
+ unsigned char prg_iface;
+ pci_read_config_byte(dev, PCI_CLASS_PROG, &prg_iface);
+
+ if (!(prg_iface & PCIAUTO_IDE_MODE_MASK)) {
+ DBG("PCI Autoconfig: Skipping legacy mode "
+ "IDE controller\n");
+ continue;
+ }
+ }
+#endif
+
+ /*
+ * Found a peripheral, enable some standard
+ * settings
+ */
+
+ pci_read_config_dword(dev, PCI_COMMAND, &cmdstat);
+ pci_write_config_dword(dev, PCI_COMMAND,
+ cmdstat |
+ PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY |
+ PCI_COMMAND_MASTER);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+
+ /* Allocate PCI I/O and/or memory space */
+ DBG("PCI Autoconfig: Found Bus %d, Device %d, Function %d\n",
+ current_bus, PCI_SLOT(pci_devfn), PCI_FUNC(pci_devfn) );
+
+ pciauto_setup_bars(dev, PCI_BASE_ADDRESS_5);
+ pciauto_setup_irq(pci_ctrl, dev, pci_devfn);
+ }
+ return sub_bus;
+}
+
+
+
+
+
diff --git a/arch/xtensa/lib/strcasecmp.c b/arch/xtensa/lib/strcasecmp.c
new file mode 100644
index 000000000000..165b2d6effa5
--- /dev/null
+++ b/arch/xtensa/lib/strcasecmp.c
@@ -0,0 +1,32 @@
+/*
+ * linux/arch/xtensa/lib/strcasecmp.c
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+#include <linux/string.h>
+
+
+/* We handle nothing here except the C locale. Since this is used in
+ only one place, on strings known to contain only 7 bit ASCII, this
+ is ok. */
+
+int strcasecmp(const char *a, const char *b)
+{
+ int ca, cb;
+
+ do {
+ ca = *a++ & 0xff;
+ cb = *b++ & 0xff;
+ if (ca >= 'A' && ca <= 'Z')
+ ca += 'a' - 'A';
+ if (cb >= 'A' && cb <= 'Z')
+ cb += 'a' - 'A';
+ } while (ca == cb && ca != '\0');
+
+ return ca - cb;
+}
diff --git a/arch/xtensa/lib/strncpy_user.S b/arch/xtensa/lib/strncpy_user.S
new file mode 100644
index 000000000000..71d55df43893
--- /dev/null
+++ b/arch/xtensa/lib/strncpy_user.S
@@ -0,0 +1,224 @@
+/*
+ * arch/xtensa/lib/strncpy_user.S
+ *
+ * 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.
+ *
+ * Returns: -EFAULT if exception before terminator, N if the entire
+ * buffer filled, else strlen.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+#include <linux/errno.h>
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler) \
+9: insn reg1, reg2, offset; \
+ .section __ex_table, "a"; \
+ .word 9b, handler; \
+ .previous
+
+/*
+ * char *__strncpy_user(char *dst, const char *src, size_t len)
+ */
+.text
+.begin literal
+.align 4
+.Lmask0:
+ .byte 0xff, 0x00, 0x00, 0x00
+.Lmask1:
+ .byte 0x00, 0xff, 0x00, 0x00
+.Lmask2:
+ .byte 0x00, 0x00, 0xff, 0x00
+.Lmask3:
+ .byte 0x00, 0x00, 0x00, 0xff
+.end literal
+
+# Register use
+# a0/ return address
+# a1/ stack pointer
+# a2/ return value
+# a3/ src
+# a4/ len
+# a5/ mask0
+# a6/ mask1
+# a7/ mask2
+# a8/ mask3
+# a9/ tmp
+# a10/ tmp
+# a11/ dst
+# a12/ tmp
+
+.align 4
+.global __strncpy_user
+.type __strncpy_user,@function
+__strncpy_user:
+ entry sp, 16 # minimal stack frame
+ # a2/ dst, a3/ src, a4/ len
+ mov a11, a2 # leave dst in return value register
+ beqz a4, .Lret # if len is zero
+ l32r a5, .Lmask0 # mask for byte 0
+ l32r a6, .Lmask1 # mask for byte 1
+ l32r a7, .Lmask2 # mask for byte 2
+ l32r a8, .Lmask3 # mask for byte 3
+ bbsi.l a3, 0, .Lsrc1mod2 # if only 8-bit aligned
+ bbsi.l a3, 1, .Lsrc2mod4 # if only 16-bit aligned
+.Lsrcaligned: # return here when src is word-aligned
+ srli a12, a4, 2 # number of loop iterations with 4B per loop
+ movi a9, 3
+ bnone a11, a9, .Laligned
+ j .Ldstunaligned
+
+.Lsrc1mod2: # src address is odd
+ EX(l8ui, a9, a3, 0, fixup_l) # get byte 0
+ addi a3, a3, 1 # advance src pointer
+ EX(s8i, a9, a11, 0, fixup_s) # store byte 0
+ beqz a9, .Lret # if byte 0 is zero
+ addi a11, a11, 1 # advance dst pointer
+ addi a4, a4, -1 # decrement len
+ beqz a4, .Lret # if len is zero
+ bbci.l a3, 1, .Lsrcaligned # if src is now word-aligned
+
+.Lsrc2mod4: # src address is 2 mod 4
+ EX(l8ui, a9, a3, 0, fixup_l) # get byte 0
+ /* 1-cycle interlock */
+ EX(s8i, a9, a11, 0, fixup_s) # store byte 0
+ beqz a9, .Lret # if byte 0 is zero
+ addi a11, a11, 1 # advance dst pointer
+ addi a4, a4, -1 # decrement len
+ beqz a4, .Lret # if len is zero
+ EX(l8ui, a9, a3, 1, fixup_l) # get byte 0
+ addi a3, a3, 2 # advance src pointer
+ EX(s8i, a9, a11, 0, fixup_s) # store byte 0
+ beqz a9, .Lret # if byte 0 is zero
+ addi a11, a11, 1 # advance dst pointer
+ addi a4, a4, -1 # decrement len
+ bnez a4, .Lsrcaligned # if len is nonzero
+.Lret:
+ sub a2, a11, a2 # compute strlen
+ retw
+
+/*
+ * dst is word-aligned, src is word-aligned
+ */
+ .align 4 # 1 mod 4 alignment for LOOPNEZ
+ .byte 0 # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+ loopnez a12, .Loop1done
+#else
+ beqz a12, .Loop1done
+ slli a12, a12, 2
+ add a12, a12, a11 # a12 = end of last 4B chunck
+#endif
+.Loop1:
+ EX(l32i, a9, a3, 0, fixup_l) # get word from src
+ addi a3, a3, 4 # advance src pointer
+ bnone a9, a5, .Lz0 # if byte 0 is zero
+ bnone a9, a6, .Lz1 # if byte 1 is zero
+ bnone a9, a7, .Lz2 # if byte 2 is zero
+ EX(s32i, a9, a11, 0, fixup_s) # store word to dst
+ bnone a9, a8, .Lz3 # if byte 3 is zero
+ addi a11, a11, 4 # advance dst pointer
+#if !XCHAL_HAVE_LOOPS
+ blt a11, a12, .Loop1
+#endif
+
+.Loop1done:
+ bbci.l a4, 1, .L100
+ # copy 2 bytes
+ EX(l16ui, a9, a3, 0, fixup_l)
+ addi a3, a3, 2 # advance src pointer
+#ifdef __XTENSA_EB__
+ bnone a9, a7, .Lz0 # if byte 2 is zero
+ bnone a9, a8, .Lz1 # if byte 3 is zero
+#else
+ bnone a9, a5, .Lz0 # if byte 0 is zero
+ bnone a9, a6, .Lz1 # if byte 1 is zero
+#endif
+ EX(s16i, a9, a11, 0, fixup_s)
+ addi a11, a11, 2 # advance dst pointer
+.L100:
+ bbci.l a4, 0, .Lret
+ EX(l8ui, a9, a3, 0, fixup_l)
+ /* slot */
+ EX(s8i, a9, a11, 0, fixup_s)
+ beqz a9, .Lret # if byte is zero
+ addi a11, a11, 1-3 # advance dst ptr 1, but also cancel
+ # the effect of adding 3 in .Lz3 code
+ /* fall thru to .Lz3 and "retw" */
+
+.Lz3: # byte 3 is zero
+ addi a11, a11, 3 # advance dst pointer
+ sub a2, a11, a2 # compute strlen
+ retw
+.Lz0: # byte 0 is zero
+#ifdef __XTENSA_EB__
+ movi a9, 0
+#endif /* __XTENSA_EB__ */
+ EX(s8i, a9, a11, 0, fixup_s)
+ sub a2, a11, a2 # compute strlen
+ retw
+.Lz1: # byte 1 is zero
+#ifdef __XTENSA_EB__
+ extui a9, a9, 16, 16
+#endif /* __XTENSA_EB__ */
+ EX(s16i, a9, a11, 0, fixup_s)
+ addi a11, a11, 1 # advance dst pointer
+ sub a2, a11, a2 # compute strlen
+ retw
+.Lz2: # byte 2 is zero
+#ifdef __XTENSA_EB__
+ extui a9, a9, 16, 16
+#endif /* __XTENSA_EB__ */
+ EX(s16i, a9, a11, 0, fixup_s)
+ movi a9, 0
+ EX(s8i, a9, a11, 2, fixup_s)
+ addi a11, a11, 2 # advance dst pointer
+ sub a2, a11, a2 # compute strlen
+ retw
+
+ .align 4 # 1 mod 4 alignment for LOOPNEZ
+ .byte 0 # (0 mod 4 alignment for LBEG)
+.Ldstunaligned:
+/*
+ * for now just use byte copy loop
+ */
+#if XCHAL_HAVE_LOOPS
+ loopnez a4, .Lunalignedend
+#else
+ beqz a4, .Lunalignedend
+ add a12, a11, a4 # a12 = ending address
+#endif /* XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+ EX(l8ui, a9, a3, 0, fixup_l)
+ addi a3, a3, 1
+ EX(s8i, a9, a11, 0, fixup_s)
+ beqz a9, .Lunalignedend
+ addi a11, a11, 1
+#if !XCHAL_HAVE_LOOPS
+ blt a11, a12, .Lnextbyte
+#endif
+
+.Lunalignedend:
+ sub a2, a11, a2 # compute strlen
+ retw
+
+
+ .section .fixup, "ax"
+ .align 4
+
+ /* For now, just return -EFAULT. Future implementations might
+ * like to clear remaining kernel space, like the fixup
+ * implementation in memset(). Thus, we differentiate between
+ * load/store fixups. */
+
+fixup_s:
+fixup_l:
+ movi a2, -EFAULT
+ retw
+
diff --git a/arch/xtensa/lib/strnlen_user.S b/arch/xtensa/lib/strnlen_user.S
new file mode 100644
index 000000000000..cdff4d670f3b
--- /dev/null
+++ b/arch/xtensa/lib/strnlen_user.S
@@ -0,0 +1,147 @@
+/*
+ * arch/xtensa/lib/strnlen_user.S
+ *
+ * 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.
+ *
+ * Returns strnlen, including trailing zero terminator.
+ * Zero indicates error.
+ *
+ * Copyright (C) 2002 Tensilica Inc.
+ */
+
+#include <xtensa/coreasm.h>
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler) \
+9: insn reg1, reg2, offset; \
+ .section __ex_table, "a"; \
+ .word 9b, handler; \
+ .previous
+
+/*
+ * size_t __strnlen_user(const char *s, size_t len)
+ */
+.text
+.begin literal
+.align 4
+.Lmask0:
+ .byte 0xff, 0x00, 0x00, 0x00
+.Lmask1:
+ .byte 0x00, 0xff, 0x00, 0x00
+.Lmask2:
+ .byte 0x00, 0x00, 0xff, 0x00
+.Lmask3:
+ .byte 0x00, 0x00, 0x00, 0xff
+.end literal
+
+# Register use:
+# a2/ src
+# a3/ len
+# a4/ tmp
+# a5/ mask0
+# a6/ mask1
+# a7/ mask2
+# a8/ mask3
+# a9/ tmp
+# a10/ tmp
+
+.align 4
+.global __strnlen_user
+.type __strnlen_user,@function
+__strnlen_user:
+ entry sp, 16 # minimal stack frame
+ # a2/ s, a3/ len
+ addi a4, a2, -4 # because we overincrement at the end;
+ # we compensate with load offsets of 4
+ l32r a5, .Lmask0 # mask for byte 0
+ l32r a6, .Lmask1 # mask for byte 1
+ l32r a7, .Lmask2 # mask for byte 2
+ l32r a8, .Lmask3 # mask for byte 3
+ bbsi.l a2, 0, .L1mod2 # if only 8-bit aligned
+ bbsi.l a2, 1, .L2mod4 # if only 16-bit aligned
+
+/*
+ * String is word-aligned.
+ */
+.Laligned:
+ srli a10, a3, 2 # number of loop iterations with 4B per loop
+#if XCHAL_HAVE_LOOPS
+ loopnez a10, .Ldone
+#else
+ beqz a10, .Ldone
+ slli a10, a10, 2
+ add a10, a10, a4 # a10 = end of last 4B chunk
+#endif /* XCHAL_HAVE_LOOPS */
+.Loop:
+ EX(l32i, a9, a4, 4, lenfixup) # get next word of string
+ addi a4, a4, 4 # advance string pointer
+ bnone a9, a5, .Lz0 # if byte 0 is zero
+ bnone a9, a6, .Lz1 # if byte 1 is zero
+ bnone a9, a7, .Lz2 # if byte 2 is zero
+ bnone a9, a8, .Lz3 # if byte 3 is zero
+#if !XCHAL_HAVE_LOOPS
+ blt a4, a10, .Loop
+#endif
+
+.Ldone:
+ EX(l32i, a9, a4, 4, lenfixup) # load 4 bytes for remaining checks
+
+ bbci.l a3, 1, .L100
+ # check two more bytes (bytes 0, 1 of word)
+ addi a4, a4, 2 # advance string pointer
+ bnone a9, a5, .Lz0 # if byte 0 is zero
+ bnone a9, a6, .Lz1 # if byte 1 is zero
+.L100:
+ bbci.l a3, 0, .L101
+ # check one more byte (byte 2 of word)
+ # Actually, we don't need to check. Zero or nonzero, we'll add one.
+ # Do not add an extra one for the NULL terminator since we have
+ # exhausted the original len parameter.
+ addi a4, a4, 1 # advance string pointer
+.L101:
+ sub a2, a4, a2 # compute length
+ retw
+
+# NOTE that in several places below, we point to the byte just after
+# the zero byte in order to include the NULL terminator in the count.
+
+.Lz3: # byte 3 is zero
+ addi a4, a4, 3 # point to zero byte
+.Lz0: # byte 0 is zero
+ addi a4, a4, 1 # point just beyond zero byte
+ sub a2, a4, a2 # subtract to get length
+ retw
+.Lz1: # byte 1 is zero
+ addi a4, a4, 1+1 # point just beyond zero byte
+ sub a2, a4, a2 # subtract to get length
+ retw
+.Lz2: # byte 2 is zero
+ addi a4, a4, 2+1 # point just beyond zero byte
+ sub a2, a4, a2 # subtract to get length
+ retw
+
+.L1mod2: # address is odd
+ EX(l8ui, a9, a4, 4, lenfixup) # get byte 0
+ addi a4, a4, 1 # advance string pointer
+ beqz a9, .Lz3 # if byte 0 is zero
+ bbci.l a4, 1, .Laligned # if string pointer is now word-aligned
+
+.L2mod4: # address is 2 mod 4
+ addi a4, a4, 2 # advance ptr for aligned access
+ EX(l32i, a9, a4, 0, lenfixup) # get word with first two bytes of string
+ bnone a9, a7, .Lz2 # if byte 2 (of word, not string) is zero
+ bany a9, a8, .Laligned # if byte 3 (of word, not string) is nonzero
+ # byte 3 is zero
+ addi a4, a4, 3+1 # point just beyond zero byte
+ sub a2, a4, a2 # subtract to get length
+ retw
+
+ .section .fixup, "ax"
+ .align 4
+lenfixup:
+ movi a2, 0
+ retw
+
diff --git a/arch/xtensa/lib/usercopy.S b/arch/xtensa/lib/usercopy.S
new file mode 100644
index 000000000000..265db2693cbd
--- /dev/null
+++ b/arch/xtensa/lib/usercopy.S
@@ -0,0 +1,321 @@
+/*
+ * arch/xtensa/lib/usercopy.S
+ *
+ * Copy to/from user space (derived from arch/xtensa/lib/hal/memcopy.S)
+ *
+ * DO NOT COMBINE this function with <arch/xtensa/lib/hal/memcopy.S>.
+ * It needs to remain separate and distinct. The hal files are part
+ * of the the Xtensa link-time HAL, and those files may differ per
+ * processor configuration. Patching the kernel for another
+ * processor configuration includes replacing the hal files, and we
+ * could loose the special functionality for accessing user-space
+ * memory during such a patch. We sacrifice a little code space here
+ * in favor to simplify code maintenance.
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+/*
+ * size_t __xtensa_copy_user (void *dst, const void *src, size_t len);
+ *
+ * The returned value is the number of bytes not copied. Implies zero
+ * is success.
+ *
+ * The general case algorithm is as follows:
+ * If the destination and source are both aligned,
+ * do 16B chunks with a loop, and then finish up with
+ * 8B, 4B, 2B, and 1B copies conditional on the length.
+ * If destination is aligned and source unaligned,
+ * do the same, but use SRC to align the source data.
+ * If destination is unaligned, align it by conditionally
+ * copying 1B and 2B and then retest.
+ * This code tries to use fall-through braches for the common
+ * case of aligned destinations (except for the branches to
+ * the alignment label).
+ *
+ * Register use:
+ * a0/ return address
+ * a1/ stack pointer
+ * a2/ return value
+ * a3/ src
+ * a4/ length
+ * a5/ dst
+ * a6/ tmp
+ * a7/ tmp
+ * a8/ tmp
+ * a9/ tmp
+ * a10/ tmp
+ * a11/ original length
+ */
+
+#include <xtensa/coreasm.h>
+
+#ifdef __XTENSA_EB__
+#define ALIGN(R, W0, W1) src R, W0, W1
+#define SSA8(R) ssa8b R
+#else
+#define ALIGN(R, W0, W1) src R, W1, W0
+#define SSA8(R) ssa8l R
+#endif
+
+/* Load or store instructions that may cause exceptions use the EX macro. */
+
+#define EX(insn,reg1,reg2,offset,handler) \
+9: insn reg1, reg2, offset; \
+ .section __ex_table, "a"; \
+ .word 9b, handler; \
+ .previous
+
+
+ .text
+ .align 4
+ .global __xtensa_copy_user
+ .type __xtensa_copy_user,@function
+__xtensa_copy_user:
+ entry sp, 16 # minimal stack frame
+ # a2/ dst, a3/ src, a4/ len
+ mov a5, a2 # copy dst so that a2 is return value
+ mov a11, a4 # preserve original len for error case
+.Lcommon:
+ bbsi.l a2, 0, .Ldst1mod2 # if dst is 1 mod 2
+ bbsi.l a2, 1, .Ldst2mod4 # if dst is 2 mod 4
+.Ldstaligned: # return here from .Ldstunaligned when dst is aligned
+ srli a7, a4, 4 # number of loop iterations with 16B
+ # per iteration
+ movi a8, 3 # if source is also aligned,
+ bnone a3, a8, .Laligned # then use word copy
+ SSA8( a3) # set shift amount from byte offset
+ bnez a4, .Lsrcunaligned
+ movi a2, 0 # return success for len==0
+ retw
+
+/*
+ * Destination is unaligned
+ */
+
+.Ldst1mod2: # dst is only byte aligned
+ bltui a4, 7, .Lbytecopy # do short copies byte by byte
+
+ # copy 1 byte
+ EX(l8ui, a6, a3, 0, l_fixup)
+ addi a3, a3, 1
+ EX(s8i, a6, a5, 0, s_fixup)
+ addi a5, a5, 1
+ addi a4, a4, -1
+ bbci.l a5, 1, .Ldstaligned # if dst is now aligned, then
+ # return to main algorithm
+.Ldst2mod4: # dst 16-bit aligned
+ # copy 2 bytes
+ bltui a4, 6, .Lbytecopy # do short copies byte by byte
+ EX(l8ui, a6, a3, 0, l_fixup)
+ EX(l8ui, a7, a3, 1, l_fixup)
+ addi a3, a3, 2
+ EX(s8i, a6, a5, 0, s_fixup)
+ EX(s8i, a7, a5, 1, s_fixup)
+ addi a5, a5, 2
+ addi a4, a4, -2
+ j .Ldstaligned # dst is now aligned, return to main algorithm
+
+/*
+ * Byte by byte copy
+ */
+ .align 4
+ .byte 0 # 1 mod 4 alignment for LOOPNEZ
+ # (0 mod 4 alignment for LBEG)
+.Lbytecopy:
+#if XCHAL_HAVE_LOOPS
+ loopnez a4, .Lbytecopydone
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a4, .Lbytecopydone
+ add a7, a3, a4 # a7 = end address for source
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lnextbyte:
+ EX(l8ui, a6, a3, 0, l_fixup)
+ addi a3, a3, 1
+ EX(s8i, a6, a5, 0, s_fixup)
+ addi a5, a5, 1
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a7, .Lnextbyte
+#endif /* !XCHAL_HAVE_LOOPS */
+.Lbytecopydone:
+ movi a2, 0 # return success for len bytes copied
+ retw
+
+/*
+ * Destination and source are word-aligned.
+ */
+ # copy 16 bytes per iteration for word-aligned dst and word-aligned src
+ .align 4 # 1 mod 4 alignment for LOOPNEZ
+ .byte 0 # (0 mod 4 alignment for LBEG)
+.Laligned:
+#if XCHAL_HAVE_LOOPS
+ loopnez a7, .Loop1done
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a7, .Loop1done
+ slli a8, a7, 4
+ add a8, a8, a3 # a8 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1:
+ EX(l32i, a6, a3, 0, l_fixup)
+ EX(l32i, a7, a3, 4, l_fixup)
+ EX(s32i, a6, a5, 0, s_fixup)
+ EX(l32i, a6, a3, 8, l_fixup)
+ EX(s32i, a7, a5, 4, s_fixup)
+ EX(l32i, a7, a3, 12, l_fixup)
+ EX(s32i, a6, a5, 8, s_fixup)
+ addi a3, a3, 16
+ EX(s32i, a7, a5, 12, s_fixup)
+ addi a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a8, .Loop1
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop1done:
+ bbci.l a4, 3, .L2
+ # copy 8 bytes
+ EX(l32i, a6, a3, 0, l_fixup)
+ EX(l32i, a7, a3, 4, l_fixup)
+ addi a3, a3, 8
+ EX(s32i, a6, a5, 0, s_fixup)
+ EX(s32i, a7, a5, 4, s_fixup)
+ addi a5, a5, 8
+.L2:
+ bbci.l a4, 2, .L3
+ # copy 4 bytes
+ EX(l32i, a6, a3, 0, l_fixup)
+ addi a3, a3, 4
+ EX(s32i, a6, a5, 0, s_fixup)
+ addi a5, a5, 4
+.L3:
+ bbci.l a4, 1, .L4
+ # copy 2 bytes
+ EX(l16ui, a6, a3, 0, l_fixup)
+ addi a3, a3, 2
+ EX(s16i, a6, a5, 0, s_fixup)
+ addi a5, a5, 2
+.L4:
+ bbci.l a4, 0, .L5
+ # copy 1 byte
+ EX(l8ui, a6, a3, 0, l_fixup)
+ EX(s8i, a6, a5, 0, s_fixup)
+.L5:
+ movi a2, 0 # return success for len bytes copied
+ retw
+
+/*
+ * Destination is aligned, Source is unaligned
+ */
+
+ .align 4
+ .byte 0 # 1 mod 4 alignement for LOOPNEZ
+ # (0 mod 4 alignment for LBEG)
+.Lsrcunaligned:
+ # copy 16 bytes per iteration for word-aligned dst and unaligned src
+ and a10, a3, a8 # save unalignment offset for below
+ sub a3, a3, a10 # align a3 (to avoid sim warnings only; not needed for hardware)
+ EX(l32i, a6, a3, 0, l_fixup) # load first word
+#if XCHAL_HAVE_LOOPS
+ loopnez a7, .Loop2done
+#else /* !XCHAL_HAVE_LOOPS */
+ beqz a7, .Loop2done
+ slli a10, a7, 4
+ add a10, a10, a3 # a10 = end of last 16B source chunk
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2:
+ EX(l32i, a7, a3, 4, l_fixup)
+ EX(l32i, a8, a3, 8, l_fixup)
+ ALIGN( a6, a6, a7)
+ EX(s32i, a6, a5, 0, s_fixup)
+ EX(l32i, a9, a3, 12, l_fixup)
+ ALIGN( a7, a7, a8)
+ EX(s32i, a7, a5, 4, s_fixup)
+ EX(l32i, a6, a3, 16, l_fixup)
+ ALIGN( a8, a8, a9)
+ EX(s32i, a8, a5, 8, s_fixup)
+ addi a3, a3, 16
+ ALIGN( a9, a9, a6)
+ EX(s32i, a9, a5, 12, s_fixup)
+ addi a5, a5, 16
+#if !XCHAL_HAVE_LOOPS
+ blt a3, a10, .Loop2
+#endif /* !XCHAL_HAVE_LOOPS */
+.Loop2done:
+ bbci.l a4, 3, .L12
+ # copy 8 bytes
+ EX(l32i, a7, a3, 4, l_fixup)
+ EX(l32i, a8, a3, 8, l_fixup)
+ ALIGN( a6, a6, a7)
+ EX(s32i, a6, a5, 0, s_fixup)
+ addi a3, a3, 8
+ ALIGN( a7, a7, a8)
+ EX(s32i, a7, a5, 4, s_fixup)
+ addi a5, a5, 8
+ mov a6, a8
+.L12:
+ bbci.l a4, 2, .L13
+ # copy 4 bytes
+ EX(l32i, a7, a3, 4, l_fixup)
+ addi a3, a3, 4
+ ALIGN( a6, a6, a7)
+ EX(s32i, a6, a5, 0, s_fixup)
+ addi a5, a5, 4
+ mov a6, a7
+.L13:
+ add a3, a3, a10 # readjust a3 with correct misalignment
+ bbci.l a4, 1, .L14
+ # copy 2 bytes
+ EX(l8ui, a6, a3, 0, l_fixup)
+ EX(l8ui, a7, a3, 1, l_fixup)
+ addi a3, a3, 2
+ EX(s8i, a6, a5, 0, s_fixup)
+ EX(s8i, a7, a5, 1, s_fixup)
+ addi a5, a5, 2
+.L14:
+ bbci.l a4, 0, .L15
+ # copy 1 byte
+ EX(l8ui, a6, a3, 0, l_fixup)
+ EX(s8i, a6, a5, 0, s_fixup)
+.L15:
+ movi a2, 0 # return success for len bytes copied
+ retw
+
+
+ .section .fixup, "ax"
+ .align 4
+
+/* a2 = original dst; a5 = current dst; a11= original len
+ * bytes_copied = a5 - a2
+ * retval = bytes_not_copied = original len - bytes_copied
+ * retval = a11 - (a5 - a2)
+ *
+ * Clearing the remaining pieces of kernel memory plugs security
+ * holes. This functionality is the equivalent of the *_zeroing
+ * functions that some architectures provide.
+ */
+
+.Lmemset:
+ .word memset
+
+s_fixup:
+ sub a2, a5, a2 /* a2 <-- bytes copied */
+ sub a2, a11, a2 /* a2 <-- bytes not copied */
+ retw
+
+l_fixup:
+ sub a2, a5, a2 /* a2 <-- bytes copied */
+ sub a2, a11, a2 /* a2 <-- bytes not copied == return value */
+
+ /* void *memset(void *s, int c, size_t n); */
+ mov a6, a5 /* s */
+ movi a7, 0 /* c */
+ mov a8, a2 /* n */
+ l32r a4, .Lmemset
+ callx4 a4
+ /* Ignore memset return value in a6. */
+ /* a2 still contains bytes not copied. */
+ retw
+
diff --git a/arch/xtensa/mm/Makefile b/arch/xtensa/mm/Makefile
new file mode 100644
index 000000000000..a5aed5932d7b
--- /dev/null
+++ b/arch/xtensa/mm/Makefile
@@ -0,0 +1,13 @@
+#
+# Makefile for the Linux/Xtensa-specific parts of the memory manager.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+obj-y := init.o fault.o tlb.o misc.o
+obj-m :=
+obj-n :=
+obj- :=
diff --git a/arch/xtensa/mm/fault.c b/arch/xtensa/mm/fault.c
new file mode 100644
index 000000000000..a945a33e85a1
--- /dev/null
+++ b/arch/xtensa/mm/fault.c
@@ -0,0 +1,241 @@
+// TODO VM_EXEC flag work-around, cache aliasing
+/*
+ * arch/xtensa/mm/fault.c
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ */
+
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+#include <asm/hardirq.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/pgalloc.h>
+
+unsigned long asid_cache = ASID_FIRST_VERSION;
+void bad_page_fault(struct pt_regs*, unsigned long, int);
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ *
+ * Note: does not handle Miss and MultiHit.
+ */
+
+void do_page_fault(struct pt_regs *regs)
+{
+ struct vm_area_struct * vma;
+ struct mm_struct *mm = current->mm;
+ unsigned int exccause = regs->exccause;
+ unsigned int address = regs->excvaddr;
+ siginfo_t info;
+
+ int is_write, is_exec;
+
+ info.si_code = SEGV_MAPERR;
+
+ /* We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ */
+ if (address >= TASK_SIZE && !user_mode(regs))
+ goto vmalloc_fault;
+
+ /* If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_atomic() || !mm) {
+ bad_page_fault(regs, address, SIGSEGV);
+ return;
+ }
+
+ is_write = (exccause == XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE) ? 1 : 0;
+ is_exec = (exccause == XCHAL_EXCCAUSE_ITLB_PRIVILEGE ||
+ exccause == XCHAL_EXCCAUSE_ITLB_MISS ||
+ exccause == XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE) ? 1 : 0;
+
+#if 0
+ printk("[%s:%d:%08x:%d:%08x:%s%s]\n", current->comm, current->pid,
+ address, exccause, regs->pc, is_write? "w":"", is_exec? "x":"");
+#endif
+
+ 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 (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;
+
+ if (is_write) {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ } else if (is_exec) {
+ if (!(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+ } else /* Allow read even from write-only pages. */
+ if (!(vma->vm_flags & (VM_READ | VM_WRITE)))
+ goto bad_area;
+
+ /* If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+survive:
+ switch (handle_mm_fault(mm, vma, address, is_write)) {
+ case VM_FAULT_MINOR:
+ current->min_flt++;
+ break;
+ case VM_FAULT_MAJOR:
+ current->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);
+ if (user_mode(regs)) {
+ current->thread.bad_vaddr = address;
+ current->thread.error_code = is_write;
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code has been set above */
+ info.si_addr = (void *) address;
+ force_sig_info(SIGSEGV, &info, current);
+ return;
+ }
+ bad_page_fault(regs, address, SIGSEGV);
+ return;
+
+
+ /* 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 (current->pid == 1) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ printk("VM: killing process %s\n", current->comm);
+ if (user_mode(regs))
+ do_exit(SIGKILL);
+ bad_page_fault(regs, address, SIGKILL);
+ return;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+
+ /* Send a sigbus, regardless of whether we were in kernel
+ * or user mode.
+ */
+ current->thread.bad_vaddr = address;
+ info.si_code = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *) address;
+ force_sig_info(SIGBUS, &info, current);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ bad_page_fault(regs, address, SIGBUS);
+
+vmalloc_fault:
+ {
+ /* Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ */
+ struct mm_struct *act_mm = current->active_mm;
+ int index = pgd_index(address);
+ pgd_t *pgd, *pgd_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ if (act_mm == NULL)
+ goto bad_page_fault;
+
+ pgd = act_mm->pgd + index;
+ pgd_k = init_mm.pgd + index;
+
+ if (!pgd_present(*pgd_k))
+ goto bad_page_fault;
+
+ pgd_val(*pgd) = pgd_val(*pgd_k);
+
+ pmd = pmd_offset(pgd, address);
+ pmd_k = pmd_offset(pgd_k, address);
+ if (!pmd_present(*pmd) || !pmd_present(*pmd_k))
+ goto bad_page_fault;
+
+ pmd_val(*pmd) = pmd_val(*pmd_k);
+ pte_k = pte_offset_kernel(pmd_k, address);
+
+ if (!pte_present(*pte_k))
+ goto bad_page_fault;
+ return;
+ }
+bad_page_fault:
+ bad_page_fault(regs, address, SIGKILL);
+ return;
+}
+
+
+void
+bad_page_fault(struct pt_regs *regs, unsigned long address, int sig)
+{
+ extern void die(const char*, struct pt_regs*, long);
+ const struct exception_table_entry *entry;
+
+ /* Are we prepared to handle this kernel fault? */
+ if ((entry = search_exception_tables(regs->pc)) != NULL) {
+#if 1
+ printk(KERN_DEBUG "%s: Exception at pc=%#010lx (%lx)\n",
+ current->comm, regs->pc, entry->fixup);
+#endif
+ current->thread.bad_uaddr = address;
+ regs->pc = entry->fixup;
+ return;
+ }
+
+ /* Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
+ "address %08lx\n pc = %08lx, ra = %08lx\n",
+ address, regs->pc, regs->areg[0]);
+ die("Oops", regs, sig);
+ do_exit(sig);
+}
+
diff --git a/arch/xtensa/mm/init.c b/arch/xtensa/mm/init.c
new file mode 100644
index 000000000000..56aace84aaeb
--- /dev/null
+++ b/arch/xtensa/mm/init.c
@@ -0,0 +1,551 @@
+/*
+ * arch/xtensa/mm/init.c
+ *
+ * Derived from MIPS, PPC.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
+ * Marc Gauthier
+ * Kevin Chea
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/bootmem.h>
+#include <linux/swap.h>
+
+#include <asm/pgtable.h>
+#include <asm/bootparam.h>
+#include <asm/mmu_context.h>
+#include <asm/tlb.h>
+#include <asm/tlbflush.h>
+#include <asm/page.h>
+#include <asm/pgalloc.h>
+#include <asm/pgtable.h>
+
+
+#define DEBUG 0
+
+DEFINE_PER_CPU(struct mmu_gather, mmu_gathers);
+//static DEFINE_SPINLOCK(tlb_lock);
+
+/*
+ * This flag is used to indicate that the page was mapped and modified in
+ * kernel space, so the cache is probably dirty at that address.
+ * If cache aliasing is enabled and the page color mismatches, update_mmu_cache
+ * synchronizes the caches if this bit is set.
+ */
+
+#define PG_cache_clean PG_arch_1
+
+/* References to section boundaries */
+
+extern char _ftext, _etext, _fdata, _edata, _rodata_end;
+extern char __init_begin, __init_end;
+
+/*
+ * mem_reserve(start, end, must_exist)
+ *
+ * Reserve some memory from the memory pool.
+ *
+ * Parameters:
+ * start Start of region,
+ * end End of region,
+ * must_exist Must exist in memory pool.
+ *
+ * Returns:
+ * 0 (memory area couldn't be mapped)
+ * -1 (success)
+ */
+
+int __init mem_reserve(unsigned long start, unsigned long end, int must_exist)
+{
+ int i;
+
+ if (start == end)
+ return 0;
+
+ start = start & PAGE_MASK;
+ end = PAGE_ALIGN(end);
+
+ for (i = 0; i < sysmem.nr_banks; i++)
+ if (start < sysmem.bank[i].end
+ && end >= sysmem.bank[i].start)
+ break;
+
+ if (i == sysmem.nr_banks) {
+ if (must_exist)
+ printk (KERN_WARNING "mem_reserve: [0x%0lx, 0x%0lx) "
+ "not in any region!\n", start, end);
+ return 0;
+ }
+
+ if (start > sysmem.bank[i].start) {
+ if (end < sysmem.bank[i].end) {
+ /* split entry */
+ if (sysmem.nr_banks >= SYSMEM_BANKS_MAX)
+ panic("meminfo overflow\n");
+ sysmem.bank[sysmem.nr_banks].start = end;
+ sysmem.bank[sysmem.nr_banks].end = sysmem.bank[i].end;
+ sysmem.nr_banks++;
+ }
+ sysmem.bank[i].end = start;
+ } else {
+ if (end < sysmem.bank[i].end)
+ sysmem.bank[i].start = end;
+ else {
+ /* remove entry */
+ sysmem.nr_banks--;
+ sysmem.bank[i].start = sysmem.bank[sysmem.nr_banks].start;
+ sysmem.bank[i].end = sysmem.bank[sysmem.nr_banks].end;
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * Initialize the bootmem system and give it all the memory we have available.
+ */
+
+void __init bootmem_init(void)
+{
+ unsigned long pfn;
+ unsigned long bootmap_start, bootmap_size;
+ int i;
+
+ max_low_pfn = max_pfn = 0;
+ min_low_pfn = ~0;
+
+ for (i=0; i < sysmem.nr_banks; i++) {
+ pfn = PAGE_ALIGN(sysmem.bank[i].start) >> PAGE_SHIFT;
+ if (pfn < min_low_pfn)
+ min_low_pfn = pfn;
+ pfn = PAGE_ALIGN(sysmem.bank[i].end - 1) >> PAGE_SHIFT;
+ if (pfn > max_pfn)
+ max_pfn = pfn;
+ }
+
+ if (min_low_pfn > max_pfn)
+ panic("No memory found!\n");
+
+ max_low_pfn = max_pfn < MAX_LOW_MEMORY >> PAGE_SHIFT ?
+ max_pfn : MAX_LOW_MEMORY >> PAGE_SHIFT;
+
+ /* Find an area to use for the bootmem bitmap. */
+
+ bootmap_size = bootmem_bootmap_pages(max_low_pfn) << PAGE_SHIFT;
+ bootmap_start = ~0;
+
+ for (i=0; i<sysmem.nr_banks; i++)
+ if (sysmem.bank[i].end - sysmem.bank[i].start >= bootmap_size) {
+ bootmap_start = sysmem.bank[i].start;
+ break;
+ }
+
+ if (bootmap_start == ~0UL)
+ panic("Cannot find %ld bytes for bootmap\n", bootmap_size);
+
+ /* Reserve the bootmem bitmap area */
+
+ mem_reserve(bootmap_start, bootmap_start + bootmap_size, 1);
+ bootmap_size = init_bootmem_node(NODE_DATA(0), min_low_pfn,
+ bootmap_start >> PAGE_SHIFT,
+ max_low_pfn);
+
+ /* Add all remaining memory pieces into the bootmem map */
+
+ for (i=0; i<sysmem.nr_banks; i++)
+ free_bootmem(sysmem.bank[i].start,
+ sysmem.bank[i].end - sysmem.bank[i].start);
+
+}
+
+
+void __init paging_init(void)
+{
+ unsigned long zones_size[MAX_NR_ZONES];
+ int i;
+
+ /* All pages are DMA-able, so we put them all in the DMA zone. */
+
+ zones_size[ZONE_DMA] = max_low_pfn;
+ for (i = 1; i < MAX_NR_ZONES; i++)
+ zones_size[i] = 0;
+
+#ifdef CONFIG_HIGHMEM
+ zones_size[ZONE_HIGHMEM] = max_pfn - max_low_pfn;
+#endif
+
+ /* Initialize the kernel's page tables. */
+
+ memset(swapper_pg_dir, 0, PAGE_SIZE);
+
+ free_area_init(zones_size);
+}
+
+/*
+ * Flush the mmu and reset associated register to default values.
+ */
+
+void __init init_mmu (void)
+{
+ /* Writing zeros to the <t>TLBCFG special registers ensure
+ * that valid values exist in the register. For existing
+ * PGSZID<w> fields, zero selects the first element of the
+ * page-size array. For nonexistant PGSZID<w> fields, zero is
+ * the best value to write. Also, when changing PGSZID<w>
+ * fields, the corresponding TLB must be flushed.
+ */
+ set_itlbcfg_register (0);
+ set_dtlbcfg_register (0);
+ flush_tlb_all ();
+
+ /* Set rasid register to a known value. */
+
+ set_rasid_register (ASID_ALL_RESERVED);
+
+ /* Set PTEVADDR special register to the start of the page
+ * table, which is in kernel mappable space (ie. not
+ * statically mapped). This register's value is undefined on
+ * reset.
+ */
+ set_ptevaddr_register (PGTABLE_START);
+}
+
+/*
+ * Initialize memory pages.
+ */
+
+void __init mem_init(void)
+{
+ unsigned long codesize, reservedpages, datasize, initsize;
+ unsigned long highmemsize, tmp, ram;
+
+ max_mapnr = num_physpages = max_low_pfn;
+ high_memory = (void *) __va(max_mapnr << PAGE_SHIFT);
+ highmemsize = 0;
+
+#if CONFIG_HIGHMEM
+#error HIGHGMEM not implemented in init.c
+#endif
+
+ totalram_pages += free_all_bootmem();
+
+ reservedpages = ram = 0;
+ for (tmp = 0; tmp < max_low_pfn; tmp++) {
+ ram++;
+ if (PageReserved(mem_map+tmp))
+ reservedpages++;
+ }
+
+ codesize = (unsigned long) &_etext - (unsigned long) &_ftext;
+ datasize = (unsigned long) &_edata - (unsigned long) &_fdata;
+ initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin;
+
+ printk("Memory: %luk/%luk available (%ldk kernel code, %ldk reserved, "
+ "%ldk data, %ldk init %ldk highmem)\n",
+ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10),
+ ram << (PAGE_SHIFT-10),
+ codesize >> 10,
+ reservedpages << (PAGE_SHIFT-10),
+ datasize >> 10,
+ initsize >> 10,
+ highmemsize >> 10);
+}
+
+void
+free_reserved_mem(void *start, void *end)
+{
+ for (; start < end; start += PAGE_SIZE) {
+ ClearPageReserved(virt_to_page(start));
+ set_page_count(virt_to_page(start), 1);
+ free_page((unsigned long)start);
+ totalram_pages++;
+ }
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+extern int initrd_is_mapped;
+
+void free_initrd_mem(unsigned long start, unsigned long end)
+{
+ if (initrd_is_mapped) {
+ free_reserved_mem((void*)start, (void*)end);
+ printk ("Freeing initrd memory: %ldk freed\n",(end-start)>>10);
+ }
+}
+#endif
+
+void free_initmem(void)
+{
+ free_reserved_mem(&__init_begin, &__init_end);
+ printk("Freeing unused kernel memory: %dk freed\n",
+ (&__init_end - &__init_begin) >> 10);
+}
+
+void show_mem(void)
+{
+ int i, free = 0, total = 0, reserved = 0;
+ int shared = 0, cached = 0;
+
+ printk("Mem-info:\n");
+ show_free_areas();
+ printk("Free swap: %6ldkB\n", nr_swap_pages<<(PAGE_SHIFT-10));
+ i = max_mapnr;
+ while (i-- > 0) {
+ total++;
+ if (PageReserved(mem_map+i))
+ reserved++;
+ else if (PageSwapCache(mem_map+i))
+ cached++;
+ else if (!page_count(mem_map + i))
+ free++;
+ else
+ shared += page_count(mem_map + i) - 1;
+ }
+ printk("%d pages of RAM\n", total);
+ printk("%d reserved pages\n", reserved);
+ printk("%d pages shared\n", shared);
+ printk("%d pages swap cached\n",cached);
+ printk("%d free pages\n", free);
+}
+
+/* ------------------------------------------------------------------------- */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+
+/*
+ * With cache aliasing, the page color of the page in kernel space and user
+ * space might mismatch. We temporarily map the page to a different virtual
+ * address with the same color and clear the page there.
+ */
+
+void clear_user_page(void *kaddr, unsigned long vaddr, struct page* page)
+{
+
+ /* There shouldn't be any entries for this page. */
+
+ __flush_invalidate_dcache_page_phys(__pa(page_address(page)));
+
+ if (!PAGE_COLOR_EQ(vaddr, kaddr)) {
+ unsigned long v, p;
+
+ /* Temporarily map page to DTLB_WAY_DCACHE_ALIAS0. */
+
+ spin_lock(&tlb_lock);
+
+ p = (unsigned long)pte_val((mk_pte(page,PAGE_KERNEL)));
+ kaddr = (void*)PAGE_COLOR_MAP0(vaddr);
+ v = (unsigned long)kaddr | DTLB_WAY_DCACHE_ALIAS0;
+ __asm__ __volatile__("wdtlb %0,%1; dsync" : :"a" (p), "a" (v));
+
+ clear_page(kaddr);
+
+ spin_unlock(&tlb_lock);
+ } else {
+ clear_page(kaddr);
+ }
+
+ /* We need to make sure that i$ and d$ are coherent. */
+
+ clear_bit(PG_cache_clean, &page->flags);
+}
+
+/*
+ * With cache aliasing, we have to make sure that the page color of the page
+ * in kernel space matches that of the virtual user address before we read
+ * the page. If the page color differ, we create a temporary DTLB entry with
+ * the corrent page color and use this 'temporary' address as the source.
+ * We then use the same approach as in clear_user_page and copy the data
+ * to the kernel space and clear the PG_cache_clean bit to synchronize caches
+ * later.
+ *
+ * Note:
+ * Instead of using another 'way' for the temporary DTLB entry, we could
+ * probably use the same entry that points to the kernel address (after
+ * saving the original value and restoring it when we are done).
+ */
+
+void copy_user_page(void* to, void* from, unsigned long vaddr,
+ struct page* to_page)
+{
+ /* There shouldn't be any entries for the new page. */
+
+ __flush_invalidate_dcache_page_phys(__pa(page_address(to_page)));
+
+ spin_lock(&tlb_lock);
+
+ if (!PAGE_COLOR_EQ(vaddr, from)) {
+ unsigned long v, p, t;
+
+ __asm__ __volatile__ ("pdtlb %1,%2; rdtlb1 %0,%1"
+ : "=a"(p), "=a"(t) : "a"(from));
+ from = (void*)PAGE_COLOR_MAP0(vaddr);
+ v = (unsigned long)from | DTLB_WAY_DCACHE_ALIAS0;
+ __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
+ }
+
+ if (!PAGE_COLOR_EQ(vaddr, to)) {
+ unsigned long v, p;
+
+ p = (unsigned long)pte_val((mk_pte(to_page,PAGE_KERNEL)));
+ to = (void*)PAGE_COLOR_MAP1(vaddr);
+ v = (unsigned long)to | DTLB_WAY_DCACHE_ALIAS1;
+ __asm__ __volatile__ ("wdtlb %0,%1; dsync" ::"a" (p), "a" (v));
+ }
+ copy_page(to, from);
+
+ spin_unlock(&tlb_lock);
+
+ /* We need to make sure that i$ and d$ are coherent. */
+
+ clear_bit(PG_cache_clean, &to_page->flags);
+}
+
+
+
+/*
+ * Any time the kernel writes to a user page cache page, or it is about to
+ * read from a page cache page this routine is called.
+ *
+ * Note:
+ * The kernel currently only provides one architecture bit in the page
+ * flags that we use for I$/D$ coherency. Maybe, in future, we can
+ * use a sepearte bit for deferred dcache aliasing:
+ * If the page is not mapped yet, we only need to set a flag,
+ * if mapped, we need to invalidate the page.
+ */
+// FIXME: we probably need this for WB caches not only for Page Coloring..
+
+void flush_dcache_page(struct page *page)
+{
+ unsigned long addr = __pa(page_address(page));
+ struct address_space *mapping = page_mapping(page);
+
+ __flush_invalidate_dcache_page_phys(addr);
+
+ if (!test_bit(PG_cache_clean, &page->flags))
+ return;
+
+ /* If this page hasn't been mapped, yet, handle I$/D$ coherency later.*/
+#if 0
+ if (mapping && !mapping_mapped(mapping))
+ clear_bit(PG_cache_clean, &page->flags);
+ else
+#endif
+ __invalidate_icache_page_phys(addr);
+}
+
+void flush_cache_range(struct vm_area_struct* vma, unsigned long s,
+ unsigned long e)
+{
+ __flush_invalidate_cache_all();
+}
+
+void flush_cache_page(struct vm_area_struct* vma, unsigned long address,
+ unsigned long pfn)
+{
+ struct page *page = pfn_to_page(pfn);
+
+ /* Remove any entry for the old mapping. */
+
+ if (current->active_mm == vma->vm_mm) {
+ unsigned long addr = __pa(page_address(page));
+ __flush_invalidate_dcache_page_phys(addr);
+ if ((vma->vm_flags & VM_EXEC) != 0)
+ __invalidate_icache_page_phys(addr);
+ } else {
+ BUG();
+ }
+}
+
+#endif /* (DCACHE_WAY_SIZE > PAGE_SIZE) */
+
+
+pte_t* pte_alloc_one_kernel (struct mm_struct* mm, unsigned long addr)
+{
+ pte_t* pte = (pte_t*)__get_free_pages(GFP_KERNEL|__GFP_REPEAT, 0);
+ if (likely(pte)) {
+ pte_t* ptep = (pte_t*)(pte_val(*pte) + PAGE_OFFSET);
+ int i;
+ for (i = 0; i < 1024; i++, ptep++)
+ pte_clear(mm, addr, ptep);
+ }
+ return pte;
+}
+
+struct page* pte_alloc_one(struct mm_struct *mm, unsigned long addr)
+{
+ struct page *page;
+
+ page = alloc_pages(GFP_KERNEL | __GFP_REPEAT, 0);
+
+ if (likely(page)) {
+ pte_t* ptep = kmap_atomic(page, KM_USER0);
+ int i;
+
+ for (i = 0; i < 1024; i++, ptep++)
+ pte_clear(mm, addr, ptep);
+
+ kunmap_atomic(ptep, KM_USER0);
+ }
+ return page;
+}
+
+
+/*
+ * Handle D$/I$ coherency.
+ *
+ * Note:
+ * We only have one architecture bit for the page flags, so we cannot handle
+ * cache aliasing, yet.
+ */
+
+void
+update_mmu_cache(struct vm_area_struct * vma, unsigned long addr, pte_t pte)
+{
+ unsigned long pfn = pte_pfn(pte);
+ struct page *page;
+ unsigned long vaddr = addr & PAGE_MASK;
+
+ if (!pfn_valid(pfn))
+ return;
+
+ page = pfn_to_page(pfn);
+
+ invalidate_itlb_mapping(addr);
+ invalidate_dtlb_mapping(addr);
+
+ /* We have a new mapping. Use it. */
+
+ write_dtlb_entry(pte, dtlb_probe(addr));
+
+ /* If the processor can execute from this page, synchronize D$/I$. */
+
+ if ((vma->vm_flags & VM_EXEC) != 0) {
+
+ write_itlb_entry(pte, itlb_probe(addr));
+
+ /* Synchronize caches, if not clean. */
+
+ if (!test_and_set_bit(PG_cache_clean, &page->flags)) {
+ __flush_dcache_page(vaddr);
+ __invalidate_icache_page(vaddr);
+ }
+ }
+}
+
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S
new file mode 100644
index 000000000000..327c0f17187c
--- /dev/null
+++ b/arch/xtensa/mm/misc.S
@@ -0,0 +1,374 @@
+/*
+ * arch/xtensa/mm/misc.S
+ *
+ * Miscellaneous assembly functions.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+/* Note: we might want to implement some of the loops as zero-overhead-loops,
+ * where applicable and if supported by the processor.
+ */
+
+#include <linux/linkage.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include <xtensa/cacheasm.h>
+#include <xtensa/cacheattrasm.h>
+
+/* clear_page (page) */
+
+ENTRY(clear_page)
+ entry a1, 16
+ addi a4, a2, PAGE_SIZE
+ movi a3, 0
+
+1: s32i a3, a2, 0
+ s32i a3, a2, 4
+ s32i a3, a2, 8
+ s32i a3, a2, 12
+ s32i a3, a2, 16
+ s32i a3, a2, 20
+ s32i a3, a2, 24
+ s32i a3, a2, 28
+ addi a2, a2, 32
+ blt a2, a4, 1b
+
+ retw
+
+/*
+ * copy_page (void *to, void *from)
+ * a2 a3
+ */
+
+ENTRY(copy_page)
+ entry a1, 16
+ addi a4, a2, PAGE_SIZE
+
+1: l32i a5, a3, 0
+ l32i a6, a3, 4
+ l32i a7, a3, 8
+ s32i a5, a2, 0
+ s32i a6, a2, 4
+ s32i a7, a2, 8
+ l32i a5, a3, 12
+ l32i a6, a3, 16
+ l32i a7, a3, 20
+ s32i a5, a2, 12
+ s32i a6, a2, 16
+ s32i a7, a2, 20
+ l32i a5, a3, 24
+ l32i a6, a3, 28
+ s32i a5, a2, 24
+ s32i a6, a2, 28
+ addi a2, a2, 32
+ addi a3, a3, 32
+ blt a2, a4, 1b
+
+ retw
+
+
+/*
+ * void __flush_invalidate_cache_all(void)
+ */
+
+ENTRY(__flush_invalidate_cache_all)
+ entry sp, 16
+ dcache_writeback_inv_all a2, a3
+ icache_invalidate_all a2, a3
+ retw
+
+/*
+ * void __invalidate_icache_all(void)
+ */
+
+ENTRY(__invalidate_icache_all)
+ entry sp, 16
+ icache_invalidate_all a2, a3
+ retw
+
+/*
+ * void __flush_invalidate_dcache_all(void)
+ */
+
+ENTRY(__flush_invalidate_dcache_all)
+ entry sp, 16
+ dcache_writeback_inv_all a2, a3
+ retw
+
+
+/*
+ * void __flush_invalidate_cache_range(ulong start, ulong size)
+ */
+
+ENTRY(__flush_invalidate_cache_range)
+ entry sp, 16
+ mov a4, a2
+ mov a5, a3
+ dcache_writeback_inv_region a4, a5, a6
+ icache_invalidate_region a2, a3, a4
+ retw
+
+/*
+ * void __invalidate_icache_page(ulong start)
+ */
+
+ENTRY(__invalidate_icache_page)
+ entry sp, 16
+ movi a3, PAGE_SIZE
+ icache_invalidate_region a2, a3, a4
+ retw
+
+/*
+ * void __invalidate_dcache_page(ulong start)
+ */
+
+ENTRY(__invalidate_dcache_page)
+ entry sp, 16
+ movi a3, PAGE_SIZE
+ dcache_invalidate_region a2, a3, a4
+ retw
+
+/*
+ * void __invalidate_icache_range(ulong start, ulong size)
+ */
+
+ENTRY(__invalidate_icache_range)
+ entry sp, 16
+ icache_invalidate_region a2, a3, a4
+ retw
+
+/*
+ * void __invalidate_dcache_range(ulong start, ulong size)
+ */
+
+ENTRY(__invalidate_dcache_range)
+ entry sp, 16
+ dcache_invalidate_region a2, a3, a4
+ retw
+
+/*
+ * void __flush_dcache_page(ulong start)
+ */
+
+ENTRY(__flush_dcache_page)
+ entry sp, 16
+ movi a3, PAGE_SIZE
+ dcache_writeback_region a2, a3, a4
+ retw
+
+/*
+ * void __flush_invalidate_dcache_page(ulong start)
+ */
+
+ENTRY(__flush_invalidate_dcache_page)
+ entry sp, 16
+ movi a3, PAGE_SIZE
+ dcache_writeback_inv_region a2, a3, a4
+ retw
+
+/*
+ * void __flush_invalidate_dcache_range(ulong start, ulong size)
+ */
+
+ENTRY(__flush_invalidate_dcache_range)
+ entry sp, 16
+ dcache_writeback_inv_region a2, a3, a4
+ retw
+
+/*
+ * void __invalidate_dcache_all(void)
+ */
+
+ENTRY(__invalidate_dcache_all)
+ entry sp, 16
+ dcache_invalidate_all a2, a3
+ retw
+
+/*
+ * void __flush_invalidate_dcache_page_phys(ulong start)
+ */
+
+ENTRY(__flush_invalidate_dcache_page_phys)
+ entry sp, 16
+
+ movi a3, XCHAL_DCACHE_SIZE
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
+
+ ldct a6, a3
+ dsync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a3, 2, 1b
+ retw
+
+2: diwbi a3, 0
+ bgeui a3, 2, 1b
+ retw
+
+ENTRY(check_dcache_low0)
+ entry sp, 16
+
+ movi a3, XCHAL_DCACHE_SIZE / 4
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
+
+ ldct a6, a3
+ dsync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a3, 2, 1b
+ retw
+
+2: j 2b
+
+ENTRY(check_dcache_high0)
+ entry sp, 16
+
+ movi a5, XCHAL_DCACHE_SIZE / 4
+ movi a3, XCHAL_DCACHE_SIZE / 2
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
+ addi a5, a5, -XCHAL_DCACHE_LINESIZE
+
+ ldct a6, a3
+ dsync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a5, 2, 1b
+ retw
+
+2: j 2b
+
+ENTRY(check_dcache_low1)
+ entry sp, 16
+
+ movi a5, XCHAL_DCACHE_SIZE / 4
+ movi a3, XCHAL_DCACHE_SIZE * 3 / 4
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
+ addi a5, a5, -XCHAL_DCACHE_LINESIZE
+
+ ldct a6, a3
+ dsync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a5, 2, 1b
+ retw
+
+2: j 2b
+
+ENTRY(check_dcache_high1)
+ entry sp, 16
+
+ movi a5, XCHAL_DCACHE_SIZE / 4
+ movi a3, XCHAL_DCACHE_SIZE
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_DCACHE_LINESIZE
+ addi a5, a5, -XCHAL_DCACHE_LINESIZE
+
+ ldct a6, a3
+ dsync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a5, 2, 1b
+ retw
+
+2: j 2b
+
+
+/*
+ * void __invalidate_icache_page_phys(ulong start)
+ */
+
+ENTRY(__invalidate_icache_page_phys)
+ entry sp, 16
+
+ movi a3, XCHAL_ICACHE_SIZE
+ movi a4, PAGE_MASK | 1
+ addi a2, a2, 1
+
+1: addi a3, a3, -XCHAL_ICACHE_LINESIZE
+
+ lict a6, a3
+ isync
+ and a6, a6, a4
+ beq a6, a2, 2f
+ bgeui a3, 2, 1b
+ retw
+
+2: iii a3, 0
+ bgeui a3, 2, 1b
+ retw
+
+
+#if 0
+
+ movi a3, XCHAL_DCACHE_WAYS - 1
+ movi a4, PAGE_SIZE
+
+1: mov a5, a2
+ add a6, a2, a4
+
+2: diwbi a5, 0
+ diwbi a5, XCHAL_DCACHE_LINESIZE
+ diwbi a5, XCHAL_DCACHE_LINESIZE * 2
+ diwbi a5, XCHAL_DCACHE_LINESIZE * 3
+
+ addi a5, a5, XCHAL_DCACHE_LINESIZE * 4
+ blt a5, a6, 2b
+
+ addi a3, a3, -1
+ addi a2, a2, XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS
+ bgez a3, 1b
+
+ retw
+
+ENTRY(__invalidate_icache_page_index)
+ entry sp, 16
+
+ movi a3, XCHAL_ICACHE_WAYS - 1
+ movi a4, PAGE_SIZE
+
+1: mov a5, a2
+ add a6, a2, a4
+
+2: iii a5, 0
+ iii a5, XCHAL_ICACHE_LINESIZE
+ iii a5, XCHAL_ICACHE_LINESIZE * 2
+ iii a5, XCHAL_ICACHE_LINESIZE * 3
+
+ addi a5, a5, XCHAL_ICACHE_LINESIZE * 4
+ blt a5, a6, 2b
+
+ addi a3, a3, -1
+ addi a2, a2, XCHAL_ICACHE_SIZE / XCHAL_ICACHE_WAYS
+ bgez a3, 2b
+
+ retw
+
+#endif
+
+
+
+
+
+
diff --git a/arch/xtensa/mm/pgtable.c b/arch/xtensa/mm/pgtable.c
new file mode 100644
index 000000000000..e5e119c820e4
--- /dev/null
+++ b/arch/xtensa/mm/pgtable.c
@@ -0,0 +1,76 @@
+/*
+ * arch/xtensa/mm/fault.c
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Chris Zankel <chris@zankel.net>
+ */
+
+#if (DCACHE_SIZE > PAGE_SIZE)
+
+pte_t* pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+{
+ pte_t *pte, p;
+ int color = ADDR_COLOR(address);
+ int i;
+
+ p = (pte_t*) __get_free_pages(GFP_KERNEL|__GFP_REPEAT, COLOR_ORDER);
+
+ if (likely(p)) {
+ struct page *page;
+
+ for (i = 0; i < COLOR_SIZE; i++, p++) {
+ page = virt_to_page(pte);
+
+ set_page_count(page, 1);
+ ClearPageCompound(page);
+
+ if (ADDR_COLOR(p) == color)
+ pte = p;
+ else
+ free_page(p);
+ }
+ clear_page(pte);
+ }
+ return pte;
+}
+
+#ifdef PROFILING
+
+int mask;
+int hit;
+int flush;
+
+#endif
+
+struct page* pte_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+ struct page *page, p;
+ int color = ADDR_COLOR(address);
+
+ p = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
+
+ if (likely(p)) {
+ for (i = 0; i < PAGE_ORDER; i++) {
+ set_page_count(p, 1);
+ ClearPageCompound(p);
+
+ if (PADDR_COLOR(page_address(pg)) == color)
+ page = p;
+ else
+ free_page(p);
+ }
+ clear_highpage(page);
+ }
+
+ return page;
+}
+
+#endif
+
+
+
diff --git a/arch/xtensa/mm/tlb.c b/arch/xtensa/mm/tlb.c
new file mode 100644
index 000000000000..d3bd3bfc3b3b
--- /dev/null
+++ b/arch/xtensa/mm/tlb.c
@@ -0,0 +1,545 @@
+/*
+ * arch/xtensa/mm/mmu.c
+ *
+ * Logic that manipulates the Xtensa MMU. Derived from MIPS.
+ *
+ * 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 - 2003 Tensilica Inc.
+ *
+ * Joe Taylor
+ * Chris Zankel <chris@zankel.net>
+ * Marc Gauthier
+ */
+
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/mmu_context.h>
+#include <asm/tlbflush.h>
+#include <asm/system.h>
+#include <asm/cacheflush.h>
+
+
+static inline void __flush_itlb_all (void)
+{
+ int way, index;
+
+ for (way = 0; way < XCHAL_ITLB_ARF_WAYS; way++) {
+ for (index = 0; index < ITLB_ENTRIES_PER_ARF_WAY; index++) {
+ int entry = way + (index << PAGE_SHIFT);
+ invalidate_itlb_entry_no_isync (entry);
+ }
+ }
+ asm volatile ("isync\n");
+}
+
+static inline void __flush_dtlb_all (void)
+{
+ int way, index;
+
+ for (way = 0; way < XCHAL_DTLB_ARF_WAYS; way++) {
+ for (index = 0; index < DTLB_ENTRIES_PER_ARF_WAY; index++) {
+ int entry = way + (index << PAGE_SHIFT);
+ invalidate_dtlb_entry_no_isync (entry);
+ }
+ }
+ asm volatile ("isync\n");
+}
+
+
+void flush_tlb_all (void)
+{
+ __flush_itlb_all();
+ __flush_dtlb_all();
+}
+
+/* If mm is current, we simply assign the current task a new ASID, thus,
+ * invalidating all previous tlb entries. If mm is someone else's user mapping,
+ * wie invalidate the context, thus, when that user mapping is swapped in,
+ * a new context will be assigned to it.
+ */
+
+void flush_tlb_mm(struct mm_struct *mm)
+{
+#if 0
+ printk("[tlbmm<%lx>]\n", (unsigned long)mm->context);
+#endif
+
+ if (mm == current->active_mm) {
+ int flags;
+ local_save_flags(flags);
+ get_new_mmu_context(mm, asid_cache);
+ set_rasid_register(ASID_INSERT(mm->context));
+ local_irq_restore(flags);
+ }
+ else
+ mm->context = 0;
+}
+
+void flush_tlb_range (struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ struct mm_struct *mm = vma->vm_mm;
+ unsigned long flags;
+
+ if (mm->context == NO_CONTEXT)
+ return;
+
+#if 0
+ printk("[tlbrange<%02lx,%08lx,%08lx>]\n",
+ (unsigned long)mm->context, start, end);
+#endif
+ local_save_flags(flags);
+
+ if (end-start + (PAGE_SIZE-1) <= SMALLEST_NTLB_ENTRIES << PAGE_SHIFT) {
+ int oldpid = get_rasid_register();
+ set_rasid_register (ASID_INSERT(mm->context));
+ start &= PAGE_MASK;
+ if (vma->vm_flags & VM_EXEC)
+ while(start < end) {
+ invalidate_itlb_mapping(start);
+ invalidate_dtlb_mapping(start);
+ start += PAGE_SIZE;
+ }
+ else
+ while(start < end) {
+ invalidate_dtlb_mapping(start);
+ start += PAGE_SIZE;
+ }
+
+ set_rasid_register(oldpid);
+ } else {
+ get_new_mmu_context(mm, asid_cache);
+ if (mm == current->active_mm)
+ set_rasid_register(ASID_INSERT(mm->context));
+ }
+ local_irq_restore(flags);
+}
+
+void flush_tlb_page (struct vm_area_struct *vma, unsigned long page)
+{
+ struct mm_struct* mm = vma->vm_mm;
+ unsigned long flags;
+ int oldpid;
+#if 0
+ printk("[tlbpage<%02lx,%08lx>]\n",
+ (unsigned long)mm->context, page);
+#endif
+
+ if(mm->context == NO_CONTEXT)
+ return;
+
+ local_save_flags(flags);
+
+ oldpid = get_rasid_register();
+
+ if (vma->vm_flags & VM_EXEC)
+ invalidate_itlb_mapping(page);
+ invalidate_dtlb_mapping(page);
+
+ set_rasid_register(oldpid);
+
+ local_irq_restore(flags);
+
+#if 0
+ flush_tlb_all();
+ return;
+#endif
+}
+
+
+#ifdef DEBUG_TLB
+
+#define USE_ITLB 0
+#define USE_DTLB 1
+
+struct way_config_t {
+ int indicies;
+ int indicies_log2;
+ int pgsz_log2;
+ int arf;
+};
+
+static struct way_config_t itlb[XCHAL_ITLB_WAYS] =
+{
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ARF)
+ },
+ { XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES_LOG2),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, PAGESZ_LOG2_MIN),
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ARF)
+ }
+};
+
+static struct way_config_t dtlb[XCHAL_DTLB_WAYS] =
+{
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ARF)
+ },
+ { XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES_LOG2),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, PAGESZ_LOG2_MIN),
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ARF)
+ }
+};
+
+/* Total number of entries: */
+#define ITLB_TOTAL_ENTRIES \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY0_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY1_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY2_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY3_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY4_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY5_SET, ENTRIES) + \
+ XCHAL_ITLB_SET(XCHAL_ITLB_WAY6_SET, ENTRIES)
+#define DTLB_TOTAL_ENTRIES \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY0_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY1_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY2_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY3_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY4_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY5_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY6_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY7_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY8_SET, ENTRIES) + \
+ XCHAL_DTLB_SET(XCHAL_DTLB_WAY9_SET, ENTRIES)
+
+
+typedef struct {
+ unsigned va;
+ unsigned pa;
+ unsigned char asid;
+ unsigned char ca;
+ unsigned char way;
+ unsigned char index;
+ unsigned char pgsz_log2; /* 0 .. 32 */
+ unsigned char type; /* 0=ITLB 1=DTLB */
+} tlb_dump_entry_t;
+
+/* Return -1 if a precedes b, +1 if a follows b, 0 if same: */
+int cmp_tlb_dump_info( tlb_dump_entry_t *a, tlb_dump_entry_t *b )
+{
+ if (a->asid < b->asid) return -1;
+ if (a->asid > b->asid) return 1;
+ if (a->va < b->va) return -1;
+ if (a->va > b->va) return 1;
+ if (a->pa < b->pa) return -1;
+ if (a->pa > b->pa) return 1;
+ if (a->ca < b->ca) return -1;
+ if (a->ca > b->ca) return 1;
+ if (a->way < b->way) return -1;
+ if (a->way > b->way) return 1;
+ if (a->index < b->index) return -1;
+ if (a->index > b->index) return 1;
+ return 0;
+}
+
+void sort_tlb_dump_info( tlb_dump_entry_t *t, int n )
+{
+ int i, j;
+ /* Simple O(n*n) sort: */
+ for (i = 0; i < n-1; i++)
+ for (j = i+1; j < n; j++)
+ if (cmp_tlb_dump_info(t+i, t+j) > 0) {
+ tlb_dump_entry_t tmp = t[i];
+ t[i] = t[j];
+ t[j] = tmp;
+ }
+}
+
+
+static tlb_dump_entry_t itlb_dump_info[ITLB_TOTAL_ENTRIES];
+static tlb_dump_entry_t dtlb_dump_info[DTLB_TOTAL_ENTRIES];
+
+
+static inline char *way_type (int type)
+{
+ return type ? "autorefill" : "non-autorefill";
+}
+
+void print_entry (struct way_config_t *way_info,
+ unsigned int way,
+ unsigned int index,
+ unsigned int virtual,
+ unsigned int translation)
+{
+ char valid_chr;
+ unsigned int va, pa, asid, ca;
+
+ va = virtual &
+ ~((1 << (way_info->pgsz_log2 + way_info->indicies_log2)) - 1);
+ asid = virtual & ((1 << XCHAL_MMU_ASID_BITS) - 1);
+ pa = translation & ~((1 << way_info->pgsz_log2) - 1);
+ ca = translation & ((1 << XCHAL_MMU_CA_BITS) - 1);
+ valid_chr = asid ? 'V' : 'I';
+
+ /* Compute and incorporate the effect of the index bits on the
+ * va. It's more useful for kernel debugging, since we always
+ * want to know the effective va anyway. */
+
+ va += index << way_info->pgsz_log2;
+
+ printk ("\t[%d,%d] (%c) vpn 0x%.8x ppn 0x%.8x asid 0x%.2x am 0x%x\n",
+ way, index, valid_chr, va, pa, asid, ca);
+}
+
+void print_itlb_entry (struct way_config_t *way_info, int way, int index)
+{
+ print_entry (way_info, way, index,
+ read_itlb_virtual (way + (index << way_info->pgsz_log2)),
+ read_itlb_translation (way + (index << way_info->pgsz_log2)));
+}
+
+void print_dtlb_entry (struct way_config_t *way_info, int way, int index)
+{
+ print_entry (way_info, way, index,
+ read_dtlb_virtual (way + (index << way_info->pgsz_log2)),
+ read_dtlb_translation (way + (index << way_info->pgsz_log2)));
+}
+
+void dump_itlb (void)
+{
+ int way, index;
+
+ printk ("\nITLB: ways = %d\n", XCHAL_ITLB_WAYS);
+
+ for (way = 0; way < XCHAL_ITLB_WAYS; way++) {
+ printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
+ way, itlb[way].indicies,
+ itlb[way].pgsz_log2, way_type(itlb[way].arf));
+ for (index = 0; index < itlb[way].indicies; index++) {
+ print_itlb_entry(&itlb[way], way, index);
+ }
+ }
+}
+
+void dump_dtlb (void)
+{
+ int way, index;
+
+ printk ("\nDTLB: ways = %d\n", XCHAL_DTLB_WAYS);
+
+ for (way = 0; way < XCHAL_DTLB_WAYS; way++) {
+ printk ("\nWay: %d, Entries: %d, MinPageSize: %d, Type: %s\n",
+ way, dtlb[way].indicies,
+ dtlb[way].pgsz_log2, way_type(dtlb[way].arf));
+ for (index = 0; index < dtlb[way].indicies; index++) {
+ print_dtlb_entry(&dtlb[way], way, index);
+ }
+ }
+}
+
+void dump_tlb (tlb_dump_entry_t *tinfo, struct way_config_t *config,
+ int entries, int ways, int type, int show_invalid)
+{
+ tlb_dump_entry_t *e = tinfo;
+ int way, i;
+
+ /* Gather all info: */
+ for (way = 0; way < ways; way++) {
+ struct way_config_t *cfg = config + way;
+ for (i = 0; i < cfg->indicies; i++) {
+ unsigned wayindex = way + (i << cfg->pgsz_log2);
+ unsigned vv = (type ? read_dtlb_virtual (wayindex)
+ : read_itlb_virtual (wayindex));
+ unsigned pp = (type ? read_dtlb_translation (wayindex)
+ : read_itlb_translation (wayindex));
+
+ /* Compute and incorporate the effect of the index bits on the
+ * va. It's more useful for kernel debugging, since we always
+ * want to know the effective va anyway. */
+
+ e->va = (vv & ~((1 << (cfg->pgsz_log2 + cfg->indicies_log2)) - 1));
+ e->va += (i << cfg->pgsz_log2);
+ e->pa = (pp & ~((1 << cfg->pgsz_log2) - 1));
+ e->asid = (vv & ((1 << XCHAL_MMU_ASID_BITS) - 1));
+ e->ca = (pp & ((1 << XCHAL_MMU_CA_BITS) - 1));
+ e->way = way;
+ e->index = i;
+ e->pgsz_log2 = cfg->pgsz_log2;
+ e->type = type;
+ e++;
+ }
+ }
+#if 1
+ /* Sort by ASID and VADDR: */
+ sort_tlb_dump_info (tinfo, entries);
+#endif
+
+ /* Display all sorted info: */
+ printk ("\n%cTLB dump:\n", (type ? 'D' : 'I'));
+ for (e = tinfo, i = 0; i < entries; i++, e++) {
+#if 0
+ if (e->asid == 0 && !show_invalid)
+ continue;
+#endif
+ printk ("%c way=%d i=%d ASID=%02X V=%08X -> P=%08X CA=%X (%d %cB)\n",
+ (e->type ? 'D' : 'I'), e->way, e->index,
+ e->asid, e->va, e->pa, e->ca,
+ (1 << (e->pgsz_log2 % 10)),
+ " kMG"[e->pgsz_log2 / 10]
+ );
+ }
+}
+
+void dump_tlbs2 (int showinv)
+{
+ dump_tlb (itlb_dump_info, itlb, ITLB_TOTAL_ENTRIES, XCHAL_ITLB_WAYS, 0, showinv);
+ dump_tlb (dtlb_dump_info, dtlb, DTLB_TOTAL_ENTRIES, XCHAL_DTLB_WAYS, 1, showinv);
+}
+
+void dump_all_tlbs (void)
+{
+ dump_tlbs2 (1);
+}
+
+void dump_valid_tlbs (void)
+{
+ dump_tlbs2 (0);
+}
+
+
+void dump_tlbs (void)
+{
+ dump_itlb();
+ dump_dtlb();
+}
+
+void dump_cache_tag(int dcache, int idx)
+{
+ int w, i, s, e;
+ unsigned long tag, index;
+ unsigned long num_lines, num_ways, cache_size, line_size;
+
+ num_ways = dcache ? XCHAL_DCACHE_WAYS : XCHAL_ICACHE_WAYS;
+ cache_size = dcache ? XCHAL_DCACHE_SIZE : XCHAL_ICACHE_SIZE;
+ line_size = dcache ? XCHAL_DCACHE_LINESIZE : XCHAL_ICACHE_LINESIZE;
+
+ num_lines = cache_size / num_ways;
+
+ s = 0; e = num_lines;
+
+ if (idx >= 0)
+ e = (s = idx * line_size) + 1;
+
+ for (i = s; i < e; i+= line_size) {
+ printk("\nline %#08x:", i);
+ for (w = 0; w < num_ways; w++) {
+ index = w * num_lines + i;
+ if (dcache)
+ __asm__ __volatile__("ldct %0, %1\n\t"
+ : "=a"(tag) : "a"(index));
+ else
+ __asm__ __volatile__("lict %0, %1\n\t"
+ : "=a"(tag) : "a"(index));
+
+ printk(" %#010lx", tag);
+ }
+ }
+ printk ("\n");
+}
+
+void dump_icache(int index)
+{
+ unsigned long data, addr;
+ int w, i;
+
+ const unsigned long num_ways = XCHAL_ICACHE_WAYS;
+ const unsigned long cache_size = XCHAL_ICACHE_SIZE;
+ const unsigned long line_size = XCHAL_ICACHE_LINESIZE;
+ const unsigned long num_lines = cache_size / num_ways / line_size;
+
+ for (w = 0; w < num_ways; w++) {
+ printk ("\nWay %d", w);
+
+ for (i = 0; i < line_size; i+= 4) {
+ addr = w * num_lines + index * line_size + i;
+ __asm__ __volatile__("licw %0, %1\n\t"
+ : "=a"(data) : "a"(addr));
+ printk(" %#010lx", data);
+ }
+ }
+ printk ("\n");
+}
+
+void dump_cache_tags(void)
+{
+ printk("Instruction cache\n");
+ dump_cache_tag(0, -1);
+ printk("Data cache\n");
+ dump_cache_tag(1, -1);
+}
+
+#endif
diff --git a/arch/xtensa/platform-iss/Makefile b/arch/xtensa/platform-iss/Makefile
new file mode 100644
index 000000000000..5b394e9620e5
--- /dev/null
+++ b/arch/xtensa/platform-iss/Makefile
@@ -0,0 +1,13 @@
+# $Id: Makefile,v 1.1.1.1 2002/08/28 16:10:14 aroll Exp $
+#
+# Makefile for the Xtensa Instruction Set Simulator (ISS)
+# "prom monitor" library routines under Linux.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are in the main makefile...
+
+obj-y = io.o console.o setup.o network.o
+
diff --git a/arch/xtensa/platform-iss/console.c b/arch/xtensa/platform-iss/console.c
new file mode 100644
index 000000000000..4fbddf92a921
--- /dev/null
+++ b/arch/xtensa/platform-iss/console.c
@@ -0,0 +1,300 @@
+/*
+ * arch/xtensa/platform-iss/console.c
+ *
+ * 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-2005 Tensilica Inc.
+ * Authors Christian Zankel, Joe Taylor
+ */
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/major.h>
+#include <linux/param.h>
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/console.h>
+
+#include <asm/uaccess.h>
+#include <asm/irq.h>
+
+#include <xtensa/simcall.h>
+
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+#ifdef SERIAL_INLINE
+#define _INLINE_ inline
+#endif
+
+#define SERIAL_MAX_NUM_LINES 1
+#define SERIAL_TIMER_VALUE (20 * HZ)
+
+static struct tty_driver *serial_driver;
+static struct timer_list serial_timer;
+
+static DEFINE_SPINLOCK(timer_lock);
+
+int errno;
+
+static int __simc (int a, int b, int c, int d, int e, int f)
+{
+ int ret;
+ __asm__ __volatile__ ("simcall\n"
+ "mov %0, a2\n"
+ "mov %1, a3\n" : "=a" (ret), "=a" (errno)
+ : : "a2", "a3");
+ return ret;
+}
+
+static char *serial_version = "0.1";
+static char *serial_name = "ISS serial driver";
+
+/*
+ * This routine is called whenever a serial port is opened. It
+ * enables interrupts for a serial port, linking in its async structure into
+ * the IRQ chain. It also performs the serial-specific
+ * initialization for the tty structure.
+ */
+
+static void rs_poll(unsigned long);
+
+static int rs_open(struct tty_struct *tty, struct file * filp)
+{
+ int line = tty->index;
+
+ if ((line < 0) || (line >= SERIAL_MAX_NUM_LINES))
+ return -ENODEV;
+
+ spin_lock(&timer_lock);
+
+ if (tty->count == 1) {
+ init_timer(&serial_timer);
+ serial_timer.data = (unsigned long) tty;
+ serial_timer.function = rs_poll;
+ mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+ }
+ spin_unlock(&timer_lock);
+
+ return 0;
+}
+
+
+/*
+ * ------------------------------------------------------------
+ * iss_serial_close()
+ *
+ * This routine is called when the serial port gets closed. First, we
+ * wait for the last remaining data to be sent. Then, we unlink its
+ * async structure from the interrupt chain if necessary, and we free
+ * that IRQ if nothing is left in the chain.
+ * ------------------------------------------------------------
+ */
+static void rs_close(struct tty_struct *tty, struct file * filp)
+{
+ spin_lock(&timer_lock);
+ if (tty->count == 1)
+ del_timer_sync(&serial_timer);
+ spin_unlock(&timer_lock);
+}
+
+
+static int rs_write(struct tty_struct * tty,
+ const unsigned char *buf, int count)
+{
+ /* see drivers/char/serialX.c to reference original version */
+
+ __simc (SYS_write, 1, (unsigned long)buf, count, 0, 0);
+ return count;
+}
+
+static void rs_poll(unsigned long priv)
+{
+ struct tty_struct* tty = (struct tty_struct*) priv;
+
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+ int i = 0;
+ unsigned char c;
+
+ spin_lock(&timer_lock);
+
+ while (__simc(SYS_select_one, 0, XTISS_SELECT_ONE_READ, (int)&tv,0,0)){
+ __simc (SYS_read, 0, (unsigned long)&c, 1, 0, 0);
+ tty->flip.count++;
+ *tty->flip.char_buf_ptr++ = c;
+ *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
+ i++;
+ }
+
+ if (i)
+ tty_flip_buffer_push(tty);
+
+
+ mod_timer(&serial_timer, jiffies + SERIAL_TIMER_VALUE);
+ spin_unlock(&timer_lock);
+}
+
+
+static void rs_put_char(struct tty_struct *tty, unsigned char ch)
+{
+ char buf[2];
+
+ if (!tty)
+ return;
+
+ buf[0] = ch;
+ buf[1] = '\0'; /* Is this NULL necessary? */
+ __simc (SYS_write, 1, (unsigned long) buf, 1, 0, 0);
+}
+
+static void rs_flush_chars(struct tty_struct *tty)
+{
+}
+
+static int rs_write_room(struct tty_struct *tty)
+{
+ /* Let's say iss can always accept 2K characters.. */
+ return 2 * 1024;
+}
+
+static int rs_chars_in_buffer(struct tty_struct *tty)
+{
+ /* the iss doesn't buffer characters */
+ return 0;
+}
+
+static void rs_hangup(struct tty_struct *tty)
+{
+ /* Stub, once again.. */
+}
+
+static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
+{
+ /* Stub, once again.. */
+}
+
+static int rs_read_proc(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ int len = 0;
+ off_t begin = 0;
+
+ len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
+ *eof = 1;
+
+ if (off >= len + begin)
+ return 0;
+
+ *start = page + (off - begin);
+ return ((count < begin + len - off) ? count : begin + len - off);
+}
+
+
+static struct tty_operations serial_ops = {
+ .open = rs_open,
+ .close = rs_close,
+ .write = rs_write,
+ .put_char = rs_put_char,
+ .flush_chars = rs_flush_chars,
+ .write_room = rs_write_room,
+ .chars_in_buffer = rs_chars_in_buffer,
+ .hangup = rs_hangup,
+ .wait_until_sent = rs_wait_until_sent,
+ .read_proc = rs_read_proc
+};
+
+int __init rs_init(void)
+{
+ serial_driver = alloc_tty_driver(1);
+
+ printk ("%s %s\n", serial_name, serial_version);
+
+ /* Initialize the tty_driver structure */
+
+ serial_driver->owner = THIS_MODULE;
+ serial_driver->driver_name = "iss_serial";
+ serial_driver->name = "ttyS";
+ serial_driver->major = TTY_MAJOR;
+ serial_driver->minor_start = 64;
+ serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
+ serial_driver->subtype = SERIAL_TYPE_NORMAL;
+ serial_driver->init_termios = tty_std_termios;
+ serial_driver->init_termios.c_cflag =
+ B9600 | CS8 | CREAD | HUPCL | CLOCAL;
+ serial_driver->flags = TTY_DRIVER_REAL_RAW;
+
+ tty_set_operations(serial_driver, &serial_ops);
+
+ if (tty_register_driver(serial_driver))
+ panic("Couldn't register serial driver\n");
+ return 0;
+}
+
+
+static __exit void rs_exit(void)
+{
+ int error;
+
+ if ((error = tty_unregister_driver(serial_driver)))
+ printk("ISS_SERIAL: failed to unregister serial driver (%d)\n",
+ error);
+ put_tty_driver(serial_driver);
+}
+
+
+/* We use `late_initcall' instead of just `__initcall' as a workaround for
+ * the fact that (1) simcons_tty_init can't be called before tty_init,
+ * (2) tty_init is called via `module_init', (3) if statically linked,
+ * module_init == device_init, and (4) there's no ordering of init lists.
+ * We can do this easily because simcons is always statically linked, but
+ * other tty drivers that depend on tty_init and which must use
+ * `module_init' to declare their init routines are likely to be broken.
+ */
+
+late_initcall(rs_init);
+
+
+#ifdef CONFIG_SERIAL_CONSOLE
+
+static void iss_console_write(struct console *co, const char *s, unsigned count)
+{
+ int len = strlen(s);
+
+ if (s != 0 && *s != 0)
+ __simc (SYS_write, 1, (unsigned long)s,
+ count < len ? count : len,0,0);
+}
+
+static struct tty_driver* iss_console_device(struct console *c, int *index)
+{
+ *index = c->index;
+ return serial_driver;
+}
+
+
+static struct console sercons = {
+ .name = "ttyS",
+ .write = iss_console_write,
+ .device = iss_console_device,
+ .flags = CON_PRINTBUFFER,
+ .index = -1
+};
+
+static int __init iss_console_init(void)
+{
+ register_console(&sercons);
+ return 0;
+}
+
+console_initcall(iss_console_init);
+
+#endif /* CONFIG_SERIAL_CONSOLE */
+
diff --git a/arch/xtensa/platform-iss/io.c b/arch/xtensa/platform-iss/io.c
new file mode 100644
index 000000000000..5b161a5cb65f
--- /dev/null
+++ b/arch/xtensa/platform-iss/io.c
@@ -0,0 +1,32 @@
+/* This file isn't really needed right now. */
+
+#if 0
+
+#include <asm/io.h>
+#include <xtensa/simcall.h>
+
+extern int __simc ();
+
+
+char iss_serial_getc()
+{
+ char c;
+ __simc( SYS_read, 0, &c, 1 );
+ return c;
+}
+
+void iss_serial_putc( char c )
+{
+ __simc( SYS_write, 1, &c, 1 );
+}
+
+void iss_serial_puts( char *s )
+{
+ if( s != 0 && *s != 0 )
+ __simc( SYS_write, 1, s, strlen(s) );
+}
+
+/*#error Need I/O ports to specific hardware!*/
+
+#endif
+
diff --git a/arch/xtensa/platform-iss/network.c b/arch/xtensa/platform-iss/network.c
new file mode 100644
index 000000000000..498d7dced1f4
--- /dev/null
+++ b/arch/xtensa/platform-iss/network.c
@@ -0,0 +1,855 @@
+/*
+ *
+ * arch/xtensa/platform-iss/network.c
+ *
+ * Platform specific initialization.
+ *
+ * Authors: Chris Zankel <chris@zankel.net>
+ * Based on work form the UML team.
+ *
+ * Copyright 2005 Tensilica Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/if_ether.h>
+#include <linux/inetdevice.h>
+#include <linux/init.h>
+#include <linux/if_tun.h>
+#include <linux/etherdevice.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/bootmem.h>
+#include <linux/ethtool.h>
+#include <linux/rtnetlink.h>
+#include <linux/timer.h>
+
+#include <xtensa/simcall.h>
+
+#define DRIVER_NAME "iss-netdev"
+#define ETH_MAX_PACKET 1500
+#define ETH_HEADER_OTHER 14
+#define ISS_NET_TIMER_VALUE (2 * HZ)
+
+
+static DEFINE_SPINLOCK(opened_lock);
+static LIST_HEAD(opened);
+
+static DEFINE_SPINLOCK(devices_lock);
+static LIST_HEAD(devices);
+
+/* ------------------------------------------------------------------------- */
+
+/* We currently only support the TUNTAP transport protocol. */
+
+#define TRANSPORT_TUNTAP_NAME "tuntap"
+#define TRANSPORT_TUNTAP_MTU ETH_MAX_PACKET
+
+struct tuntap_info {
+ char dev_name[IFNAMSIZ];
+ int fixed_config;
+ unsigned char gw[ETH_ALEN];
+ int fd;
+};
+
+/* ------------------------------------------------------------------------- */
+
+
+/* This structure contains out private information for the driver. */
+
+struct iss_net_private {
+
+ struct list_head device_list;
+ struct list_head opened_list;
+
+ spinlock_t lock;
+ struct net_device *dev;
+ struct platform_device pdev;
+ struct timer_list tl;
+ struct net_device_stats stats;
+
+ struct timer_list timer;
+ unsigned int timer_val;
+
+ int index;
+ int mtu;
+
+ unsigned char mac[ETH_ALEN];
+ int have_mac;
+
+ struct {
+ union {
+ struct tuntap_info tuntap;
+ } info;
+
+ int (*open)(struct iss_net_private *lp);
+ void (*close)(struct iss_net_private *lp);
+ int (*read)(struct iss_net_private *lp, struct sk_buff **skb);
+ int (*write)(struct iss_net_private *lp, struct sk_buff **skb);
+ unsigned short (*protocol)(struct sk_buff *skb);
+ int (*poll)(struct iss_net_private *lp);
+ } tp;
+
+};
+
+/* ======================= ISS SIMCALL INTERFACE =========================== */
+
+/* Note: __simc must _not_ be declared inline! */
+
+static int errno;
+
+static int __simc (int a, int b, int c, int d, int e, int f)
+{
+ int ret;
+ __asm__ __volatile__ ("simcall\n"
+ "mov %0, a2\n"
+ "mov %1, a3\n" : "=a" (ret), "=a" (errno)
+ : : "a2", "a3");
+ return ret;
+}
+
+static int inline simc_open(char *file, int flags, int mode)
+{
+ return __simc(SYS_open, (int) file, flags, mode, 0, 0);
+}
+
+static int inline simc_close(int fd)
+{
+ return __simc(SYS_close, fd, 0, 0, 0, 0);
+}
+
+static int inline simc_ioctl(int fd, int request, void *arg)
+{
+ return __simc(SYS_ioctl, fd, request, (int) arg, 0, 0);
+}
+
+static int inline simc_read(int fd, void *buf, size_t count)
+{
+ return __simc(SYS_read, fd, (int) buf, count, 0, 0);
+}
+
+static int inline simc_write(int fd, void *buf, size_t count)
+{
+ return __simc(SYS_write, fd, (int) buf, count, 0, 0);
+}
+
+static int inline simc_poll(int fd)
+{
+ struct timeval tv = { .tv_sec = 0, .tv_usec = 0 };
+
+ return __simc(SYS_select_one, fd, XTISS_SELECT_ONE_READ, (int)&tv,0,0);
+}
+
+/* ================================ HELPERS ================================ */
+
+
+static char *split_if_spec(char *str, ...)
+{
+ char **arg, *end;
+ va_list ap;
+
+ va_start(ap, str);
+ while ((arg = va_arg(ap, char**)) != NULL) {
+ if (*str == '\0')
+ return NULL;
+ end = strchr(str, ',');
+ if (end != str)
+ *arg = str;
+ if (end == NULL)
+ return NULL;
+ *end ++ = '\0';
+ str = end;
+ }
+ va_end(ap);
+ return str;
+}
+
+
+#if 0
+/* Adjust SKB. */
+
+struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra)
+{
+ if ((skb != NULL) && (skb_tailroom(skb) < extra)) {
+ struct sk_buff *skb2;
+
+ skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC);
+ dev_kfree_skb(skb);
+ skb = skb2;
+ }
+ if (skb != NULL)
+ skb_put(skb, extra);
+
+ return skb;
+}
+#endif
+
+/* Return the IP address as a string for a given device. */
+
+static void dev_ip_addr(void *d, char *buf, char *bin_buf)
+{
+ struct net_device *dev = d;
+ struct in_device *ip = dev->ip_ptr;
+ struct in_ifaddr *in;
+ u32 addr;
+
+ if ((ip == NULL) || ((in = ip->ifa_list) == NULL)) {
+ printk(KERN_WARNING "Device not assigned an IP address!\n");
+ return;
+ }
+
+ addr = in->ifa_address;
+ sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff,
+ (addr >> 16) & 0xff, addr >> 24);
+
+ if (bin_buf) {
+ bin_buf[0] = addr & 0xff;
+ bin_buf[1] = (addr >> 8) & 0xff;
+ bin_buf[2] = (addr >> 16) & 0xff;
+ bin_buf[3] = addr >> 24;
+ }
+}
+
+/* Set Ethernet address of the specified device. */
+
+static void inline set_ether_mac(void *d, unsigned char *addr)
+{
+ struct net_device *dev = d;
+ memcpy(dev->dev_addr, addr, ETH_ALEN);
+}
+
+
+/* ======================= TUNTAP TRANSPORT INTERFACE ====================== */
+
+static int tuntap_open(struct iss_net_private *lp)
+{
+ struct ifreq ifr;
+ char *dev_name = lp->tp.info.tuntap.dev_name;
+ int err = -EINVAL;
+ int fd;
+
+ /* We currently only support a fixed configuration. */
+
+ if (!lp->tp.info.tuntap.fixed_config)
+ return -EINVAL;
+
+ if ((fd = simc_open("/dev/net/tun", 02, 0)) < 0) { /* O_RDWR */
+ printk("Failed to open /dev/net/tun, returned %d "
+ "(errno = %d)\n", fd, errno);
+ return fd;
+ }
+
+ memset(&ifr, 0, sizeof ifr);
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strlcpy(ifr.ifr_name, dev_name, sizeof ifr.ifr_name - 1);
+
+ if ((err = simc_ioctl(fd, TUNSETIFF, (void*) &ifr)) < 0) {
+ printk("Failed to set interface, returned %d "
+ "(errno = %d)\n", err, errno);
+ simc_close(fd);
+ return err;
+ }
+
+ lp->tp.info.tuntap.fd = fd;
+ return err;
+}
+
+static void tuntap_close(struct iss_net_private *lp)
+{
+#if 0
+ if (lp->tp.info.tuntap.fixed_config)
+ iter_addresses(lp->tp.info.tuntap.dev, close_addr, lp->host.dev_name);
+#endif
+ simc_close(lp->tp.info.tuntap.fd);
+ lp->tp.info.tuntap.fd = -1;
+}
+
+static int tuntap_read (struct iss_net_private *lp, struct sk_buff **skb)
+{
+#if 0
+ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER);
+ if (*skb == NULL)
+ return -ENOMEM;
+#endif
+
+ return simc_read(lp->tp.info.tuntap.fd,
+ (*skb)->data, (*skb)->dev->mtu + ETH_HEADER_OTHER);
+}
+
+static int tuntap_write (struct iss_net_private *lp, struct sk_buff **skb)
+{
+ return simc_write(lp->tp.info.tuntap.fd, (*skb)->data, (*skb)->len);
+}
+
+unsigned short tuntap_protocol(struct sk_buff *skb)
+{
+ return eth_type_trans(skb, skb->dev);
+}
+
+static int tuntap_poll(struct iss_net_private *lp)
+{
+ return simc_poll(lp->tp.info.tuntap.fd);
+}
+
+/*
+ * Currently only a device name is supported.
+ * ethX=tuntap[,[mac address][,[device name]]]
+ */
+
+static int tuntap_probe(struct iss_net_private *lp, int index, char *init)
+{
+ const int len = strlen(TRANSPORT_TUNTAP_NAME);
+ char *dev_name = NULL, *mac_str = NULL, *rem = NULL;
+
+ /* Transport should be 'tuntap': ethX=tuntap,mac,dev_name */
+
+ if (strncmp(init, TRANSPORT_TUNTAP_NAME, len))
+ return 0;
+
+ if (*(init += strlen(TRANSPORT_TUNTAP_NAME)) == ',') {
+ if ((rem=split_if_spec(init+1, &mac_str, &dev_name)) != NULL) {
+ printk("Extra garbage on specification : '%s'\n", rem);
+ return 0;
+ }
+ } else if (*init != '\0') {
+ printk("Invalid argument: %s. Skipping device!\n", init);
+ return 0;
+ }
+
+ if (dev_name) {
+ strncpy(lp->tp.info.tuntap.dev_name, dev_name,
+ sizeof lp->tp.info.tuntap.dev_name);
+ lp->tp.info.tuntap.fixed_config = 1;
+ } else
+ strcpy(lp->tp.info.tuntap.dev_name, TRANSPORT_TUNTAP_NAME);
+
+
+#if 0
+ if (setup_etheraddr(mac_str, lp->mac))
+ lp->have_mac = 1;
+#endif
+ lp->mtu = TRANSPORT_TUNTAP_MTU;
+
+ //lp->info.tuntap.gate_addr = gate_addr;
+
+ lp->tp.info.tuntap.fd = -1;
+
+ lp->tp.open = tuntap_open;
+ lp->tp.close = tuntap_close;
+ lp->tp.read = tuntap_read;
+ lp->tp.write = tuntap_write;
+ lp->tp.protocol = tuntap_protocol;
+ lp->tp.poll = tuntap_poll;
+
+ printk("TUN/TAP backend - ");
+#if 0
+ if (lp->host.gate_addr != NULL)
+ printk("IP = %s", lp->host.gate_addr);
+#endif
+ printk("\n");
+
+ return 1;
+}
+
+/* ================================ ISS NET ================================ */
+
+static int iss_net_rx(struct net_device *dev)
+{
+ struct iss_net_private *lp = dev->priv;
+ int pkt_len;
+ struct sk_buff *skb;
+
+ /* Check if there is any new data. */
+
+ if (lp->tp.poll(lp) == 0)
+ return 0;
+
+ /* Try to allocate memory, if it fails, try again next round. */
+
+ if ((skb = dev_alloc_skb(dev->mtu + 2 + ETH_HEADER_OTHER)) == NULL) {
+ lp->stats.rx_dropped++;
+ return 0;
+ }
+
+ skb_reserve(skb, 2);
+
+ /* Setup skb */
+
+ skb->dev = dev;
+ skb->mac.raw = skb->data;
+ pkt_len = lp->tp.read(lp, &skb);
+ skb_put(skb, pkt_len);
+
+ if (pkt_len > 0) {
+ skb_trim(skb, pkt_len);
+ skb->protocol = lp->tp.protocol(skb);
+ // netif_rx(skb);
+ netif_rx_ni(skb);
+
+ lp->stats.rx_bytes += skb->len;
+ lp->stats.rx_packets++;
+ return pkt_len;
+ }
+ kfree_skb(skb);
+ return pkt_len;
+}
+
+static int iss_net_poll(void)
+{
+ struct list_head *ele;
+ int err, ret = 0;
+
+ spin_lock(&opened_lock);
+
+ list_for_each(ele, &opened) {
+ struct iss_net_private *lp;
+
+ lp = list_entry(ele, struct iss_net_private, opened_list);
+
+ if (!netif_running(lp->dev))
+ break;
+
+ spin_lock(&lp->lock);
+
+ while ((err = iss_net_rx(lp->dev)) > 0)
+ ret++;
+
+ spin_unlock(&lp->lock);
+
+ if (err < 0) {
+ printk(KERN_ERR "Device '%s' read returned %d, "
+ "shutting it down\n", lp->dev->name, err);
+ dev_close(lp->dev);
+ } else {
+ // FIXME reactivate_fd(lp->fd, ISS_ETH_IRQ);
+ }
+ }
+
+ spin_unlock(&opened_lock);
+ return ret;
+}
+
+
+static void iss_net_timer(unsigned long priv)
+{
+ struct iss_net_private* lp = (struct iss_net_private*) priv;
+
+ spin_lock(&lp->lock);
+
+ iss_net_poll();
+
+ mod_timer(&lp->timer, jiffies + lp->timer_val);
+
+ spin_unlock(&lp->lock);
+}
+
+
+static int iss_net_open(struct net_device *dev)
+{
+ struct iss_net_private *lp = dev->priv;
+ char addr[sizeof "255.255.255.255\0"];
+ int err;
+
+ spin_lock(&lp->lock);
+
+ if ((err = lp->tp.open(lp)) < 0)
+ goto out;
+
+ if (!lp->have_mac) {
+ dev_ip_addr(dev, addr, &lp->mac[2]);
+ set_ether_mac(dev, lp->mac);
+ }
+
+ netif_start_queue(dev);
+
+ /* clear buffer - it can happen that the host side of the interface
+ * is full when we gethere. In this case, new data is never queued,
+ * SIGIOs never arrive, and the net never works.
+ */
+ while ((err = iss_net_rx(dev)) > 0)
+ ;
+
+ spin_lock(&opened_lock);
+ list_add(&lp->opened_list, &opened);
+ spin_unlock(&opened_lock);
+
+ init_timer(&lp->timer);
+ lp->timer_val = ISS_NET_TIMER_VALUE;
+ lp->timer.data = (unsigned long) lp;
+ lp->timer.function = iss_net_timer;
+ mod_timer(&lp->timer, jiffies + lp->timer_val);
+
+out:
+ spin_unlock(&lp->lock);
+ return err;
+}
+
+static int iss_net_close(struct net_device *dev)
+{
+ struct iss_net_private *lp = dev->priv;
+printk("iss_net_close!\n");
+ netif_stop_queue(dev);
+ spin_lock(&lp->lock);
+
+ spin_lock(&opened_lock);
+ list_del(&opened);
+ spin_unlock(&opened_lock);
+
+ del_timer_sync(&lp->timer);
+
+ lp->tp.close(lp);
+
+ spin_unlock(&lp->lock);
+ return 0;
+}
+
+static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct iss_net_private *lp = dev->priv;
+ unsigned long flags;
+ int len;
+
+ netif_stop_queue(dev);
+ spin_lock_irqsave(&lp->lock, flags);
+
+ len = lp->tp.write(lp, &skb);
+
+ if (len == skb->len) {
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += skb->len;
+ dev->trans_start = jiffies;
+ netif_start_queue(dev);
+
+ /* this is normally done in the interrupt when tx finishes */
+ netif_wake_queue(dev);
+
+ } else if (len == 0) {
+ netif_start_queue(dev);
+ lp->stats.tx_dropped++;
+
+ } else {
+ netif_start_queue(dev);
+ printk(KERN_ERR "iss_net_start_xmit: failed(%d)\n", len);
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ dev_kfree_skb(skb);
+ return 0;
+}
+
+
+static struct net_device_stats *iss_net_get_stats(struct net_device *dev)
+{
+ struct iss_net_private *lp = dev->priv;
+ return &lp->stats;
+}
+
+static void iss_net_set_multicast_list(struct net_device *dev)
+{
+#if 0
+ if (dev->flags & IFF_PROMISC)
+ return;
+ else if (dev->mc_count)
+ dev->flags |= IFF_ALLMULTI;
+ else
+ dev->flags &= ~IFF_ALLMULTI;
+#endif
+}
+
+static void iss_net_tx_timeout(struct net_device *dev)
+{
+#if 0
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+#endif
+}
+
+static int iss_net_set_mac(struct net_device *dev, void *addr)
+{
+#if 0
+ struct iss_net_private *lp = dev->priv;
+ struct sockaddr *hwaddr = addr;
+
+ spin_lock(&lp->lock);
+ memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN);
+ spin_unlock(&lp->lock);
+#endif
+
+ return 0;
+}
+
+static int iss_net_change_mtu(struct net_device *dev, int new_mtu)
+{
+#if 0
+ struct iss_net_private *lp = dev->priv;
+ int err = 0;
+
+ spin_lock(&lp->lock);
+
+ // FIXME not needed new_mtu = transport_set_mtu(new_mtu, &lp->user);
+
+ if (new_mtu < 0)
+ err = new_mtu;
+ else
+ dev->mtu = new_mtu;
+
+ spin_unlock(&lp->lock);
+ return err;
+#endif
+ return -EINVAL;
+}
+
+static int iss_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+#if 0
+ static const struct ethtool_drvinfo info = {
+ .cmd = ETHTOOL_GDRVINFO,
+ .driver = DRIVER_NAME,
+ .version = "42",
+ };
+ void *useraddr;
+ u32 ethcmd;
+
+ switch (cmd) {
+ case SIOCETHTOOL:
+ useraddr = ifr->ifr_data;
+ if (copy_from_user(&ethcmd, 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;
+ }
+#endif
+ return -EINVAL;
+}
+
+void iss_net_user_timer_expire(unsigned long _conn)
+{
+}
+
+
+static struct device_driver iss_net_driver = {
+ .name = DRIVER_NAME,
+ .bus = &platform_bus_type,
+};
+
+static int driver_registered;
+
+static int iss_net_configure(int index, char *init)
+{
+ struct net_device *dev;
+ struct iss_net_private *lp;
+ int err;
+
+ if ((dev = alloc_etherdev(sizeof *lp)) == NULL) {
+ printk(KERN_ERR "eth_configure: failed to allocate device\n");
+ return 1;
+ }
+
+ /* Initialize private element. */
+
+ lp = dev->priv;
+ *lp = ((struct iss_net_private) {
+ .device_list = LIST_HEAD_INIT(lp->device_list),
+ .opened_list = LIST_HEAD_INIT(lp->opened_list),
+ .lock = SPIN_LOCK_UNLOCKED,
+ .dev = dev,
+ .index = index,
+ //.fd = -1,
+ .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 },
+ .have_mac = 0,
+ });
+
+ /*
+ * Try all transport protocols.
+ * Note: more protocols can be added by adding '&& !X_init(lp, eth)'.
+ */
+
+ if (!tuntap_probe(lp, index, init)) {
+ printk("Invalid arguments. Skipping device!\n");
+ goto errout;
+ }
+
+ printk(KERN_INFO "Netdevice %d ", index);
+ if (lp->have_mac)
+ printk("(%02x:%02x:%02x:%02x:%02x:%02x) ",
+ lp->mac[0], lp->mac[1],
+ lp->mac[2], lp->mac[3],
+ lp->mac[4], lp->mac[5]);
+ printk(": ");
+
+ /* sysfs register */
+
+ if (!driver_registered) {
+ driver_register(&iss_net_driver);
+ driver_registered = 1;
+ }
+
+ spin_lock(&devices_lock);
+ list_add(&lp->device_list, &devices);
+ spin_unlock(&devices_lock);
+
+ lp->pdev.id = index;
+ lp->pdev.name = DRIVER_NAME;
+ platform_device_register(&lp->pdev);
+ SET_NETDEV_DEV(dev,&lp->pdev.dev);
+
+ /*
+ * If this name ends up conflicting with an existing registered
+ * netdevice, that is OK, register_netdev{,ice}() will notice this
+ * and fail.
+ */
+ snprintf(dev->name, sizeof dev->name, "eth%d", index);
+
+ dev->mtu = lp->mtu;
+ dev->open = iss_net_open;
+ dev->hard_start_xmit = iss_net_start_xmit;
+ dev->stop = iss_net_close;
+ dev->get_stats = iss_net_get_stats;
+ dev->set_multicast_list = iss_net_set_multicast_list;
+ dev->tx_timeout = iss_net_tx_timeout;
+ dev->set_mac_address = iss_net_set_mac;
+ dev->change_mtu = iss_net_change_mtu;
+ dev->do_ioctl = iss_net_ioctl;
+ dev->watchdog_timeo = (HZ >> 1);
+ dev->irq = -1;
+
+ rtnl_lock();
+ err = register_netdevice(dev);
+ rtnl_unlock();
+
+ if (err) {
+ printk("Error registering net device!\n");
+ /* XXX: should we call ->remove() here? */
+ free_netdev(dev);
+ return 1;
+ }
+
+ init_timer(&lp->tl);
+ lp->tl.function = iss_net_user_timer_expire;
+
+#if 0
+ if (lp->have_mac)
+ set_ether_mac(dev, lp->mac);
+#endif
+ return 0;
+
+errout:
+ // FIXME: unregister; free, etc..
+ return -EIO;
+
+}
+
+/* ------------------------------------------------------------------------- */
+
+/* Filled in during early boot */
+
+struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line);
+
+struct iss_net_init {
+ struct list_head list;
+ char *init; /* init string */
+ int index;
+};
+
+/*
+ * Parse the command line and look for 'ethX=...' fields, and register all
+ * those fields. They will be later initialized in iss_net_init.
+ */
+
+#define ERR KERN_ERR "iss_net_setup: "
+
+static int iss_net_setup(char *str)
+{
+ struct iss_net_private *device = NULL;
+ struct iss_net_init *new;
+ struct list_head *ele;
+ char *end;
+ int n;
+
+ n = simple_strtoul(str, &end, 0);
+ if (end == str) {
+ printk(ERR "Failed to parse '%s'\n", str);
+ return 1;
+ }
+ if (n < 0) {
+ printk(ERR "Device %d is negative\n", n);
+ return 1;
+ }
+ if (*(str = end) != '=') {
+ printk(ERR "Expected '=' after device number\n");
+ return 1;
+ }
+
+ spin_lock(&devices_lock);
+
+ list_for_each(ele, &devices) {
+ device = list_entry(ele, struct iss_net_private, device_list);
+ if (device->index == n)
+ break;
+ }
+
+ spin_unlock(&devices_lock);
+
+ if (device && device->index == n) {
+ printk(ERR "Device %d already configured\n", n);
+ return 1;
+ }
+
+ if ((new = alloc_bootmem(sizeof new)) == NULL) {
+ printk("Alloc_bootmem failed\n");
+ return 1;
+ }
+
+ INIT_LIST_HEAD(&new->list);
+ new->index = n;
+ new->init = str + 1;
+
+ list_add_tail(&new->list, &eth_cmd_line);
+ return 1;
+}
+
+#undef ERR
+
+__setup("eth", iss_net_setup);
+
+/*
+ * Initialize all ISS Ethernet devices previously registered in iss_net_setup.
+ */
+
+static int iss_net_init(void)
+{
+ struct list_head *ele, *next;
+
+ /* Walk through all Ethernet devices specified in the command line. */
+
+ list_for_each_safe(ele, next, &eth_cmd_line) {
+ struct iss_net_init *eth;
+ eth = list_entry(ele, struct iss_net_init, list);
+ iss_net_configure(eth->index, eth->init);
+ }
+
+ return 1;
+}
+
+module_init(iss_net_init);
+
diff --git a/arch/xtensa/platform-iss/setup.c b/arch/xtensa/platform-iss/setup.c
new file mode 100644
index 000000000000..2e6dcbf0cc04
--- /dev/null
+++ b/arch/xtensa/platform-iss/setup.c
@@ -0,0 +1,112 @@
+/*
+ *
+ * arch/xtensa/platform-iss/setup.c
+ *
+ * Platform specific initialization.
+ *
+ * Authors: Chris Zankel <chris@zankel.net>
+ * Joe Taylor <joe@tensilica.com>
+ *
+ * Copyright 2001 - 2005 Tensilica Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <linux/config.h>
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/stringify.h>
+#include <linux/notifier.h>
+
+#include <asm/platform.h>
+#include <asm/bootparam.h>
+
+
+void __init platform_init(bp_tag_t* bootparam)
+{
+
+}
+
+void platform_halt(void)
+{
+ printk (" ** Called platform_halt(), looping forever! **\n");
+ while (1);
+}
+
+void platform_power_off(void)
+{
+ printk (" ** Called platform_power_off(), looping forever! **\n");
+ while (1);
+}
+void platform_restart(void)
+{
+ /* Flush and reset the mmu, simulate a processor reset, and
+ * jump to the reset vector. */
+
+ __asm__ __volatile__("movi a2, 15\n\t"
+ "wsr a2, " __stringify(ICOUNTLEVEL) "\n\t"
+ "movi a2, 0\n\t"
+ "wsr a2, " __stringify(ICOUNT) "\n\t"
+ "wsr a2, " __stringify(IBREAKENABLE) "\n\t"
+ "wsr a2, " __stringify(LCOUNT) "\n\t"
+ "movi a2, 0x1f\n\t"
+ "wsr a2, " __stringify(PS) "\n\t"
+ "isync\n\t"
+ "jx %0\n\t"
+ :
+ : "a" (XCHAL_RESET_VECTOR_VADDR)
+ : "a2");
+
+ /* control never gets here */
+}
+
+extern void iss_net_poll(void);
+
+const char twirl[]="|/-\\|/-\\";
+
+void platform_heartbeat(void)
+{
+#if 0
+ static int i = 0, j = 0;
+
+ if (--i < 0) {
+ i = 99;
+ printk("\r%c\r", twirl[j++]);
+ if (j == 8)
+ j = 0;
+ }
+#endif
+}
+
+
+
+static int
+iss_panic_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ __asm__ __volatile__("movi a2, -1; simcall\n");
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block iss_panic_block = {
+ iss_panic_event,
+ NULL,
+ 0
+};
+
+void __init platform_setup(char **p_cmdline)
+{
+ notifier_chain_register(&panic_notifier_list, &iss_panic_block);
+}
diff --git a/crypto/Kconfig b/crypto/Kconfig
index 90d6089d60ed..256c0b1fed10 100644
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -146,7 +146,7 @@ config CRYPTO_SERPENT
config CRYPTO_AES
tristate "AES cipher algorithms"
- depends on CRYPTO && !((X86 || UML_X86) && !64BIT)
+ depends on CRYPTO && !(X86 || UML_X86)
help
AES cipher algorithms (FIPS-197). AES uses the Rijndael
algorithm.
@@ -184,6 +184,26 @@ config CRYPTO_AES_586
See <http://csrc.nist.gov/encryption/aes/> for more information.
+config CRYPTO_AES_X86_64
+ tristate "AES cipher algorithms (x86_64)"
+ depends on CRYPTO && ((X86 || UML_X86) && 64BIT)
+ help
+ AES cipher algorithms (FIPS-197). AES uses the Rijndael
+ algorithm.
+
+ Rijndael appears to be consistently a very good performer in
+ both hardware and software across a wide range of computing
+ environments regardless of its use in feedback or non-feedback
+ modes. Its key setup time is excellent, and its key agility is
+ good. Rijndael's very low memory requirements make it very well
+ suited for restricted-space environments, in which it also
+ demonstrates excellent performance. Rijndael's operations are
+ among the easiest to defend against power and timing attacks.
+
+ The AES specifies three key sizes: 128, 192 and 256 bits
+
+ See <http://csrc.nist.gov/encryption/aes/> for more information.
+
config CRYPTO_CAST5
tristate "CAST5 (CAST-128) cipher algorithm"
depends on CRYPTO
diff --git a/crypto/api.c b/crypto/api.c
index 394169a8577d..b4728811ce3b 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -13,9 +13,12 @@
* any later version.
*
*/
+
+#include <linux/compiler.h>
#include <linux/init.h>
#include <linux/crypto.h>
#include <linux/errno.h>
+#include <linux/kmod.h>
#include <linux/rwsem.h>
#include <linux/slab.h>
#include "internal.h"
@@ -33,7 +36,7 @@ static inline void crypto_alg_put(struct crypto_alg *alg)
module_put(alg->cra_module);
}
-struct crypto_alg *crypto_alg_lookup(const char *name)
+static struct crypto_alg *crypto_alg_lookup(const char *name)
{
struct crypto_alg *q, *alg = NULL;
@@ -54,6 +57,13 @@ struct crypto_alg *crypto_alg_lookup(const char *name)
return alg;
}
+/* A far more intelligent version of this is planned. For now, just
+ * try an exact match on the name of the algorithm. */
+static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
+{
+ return try_then_request_module(crypto_alg_lookup(name), name);
+}
+
static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
{
tfm->crt_flags = 0;
@@ -117,20 +127,46 @@ static void crypto_exit_ops(struct crypto_tfm *tfm)
}
}
+static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags)
+{
+ unsigned int len;
+
+ switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
+ default:
+ BUG();
+
+ case CRYPTO_ALG_TYPE_CIPHER:
+ len = crypto_cipher_ctxsize(alg, flags);
+ break;
+
+ case CRYPTO_ALG_TYPE_DIGEST:
+ len = crypto_digest_ctxsize(alg, flags);
+ break;
+
+ case CRYPTO_ALG_TYPE_COMPRESS:
+ len = crypto_compress_ctxsize(alg, flags);
+ break;
+ }
+
+ return len + alg->cra_alignmask;
+}
+
struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags)
{
struct crypto_tfm *tfm = NULL;
struct crypto_alg *alg;
+ unsigned int tfm_size;
alg = crypto_alg_mod_lookup(name);
if (alg == NULL)
goto out;
-
- tfm = kmalloc(sizeof(*tfm) + alg->cra_ctxsize, GFP_KERNEL);
+
+ tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags);
+ tfm = kmalloc(tfm_size, GFP_KERNEL);
if (tfm == NULL)
goto out_put;
- memset(tfm, 0, sizeof(*tfm) + alg->cra_ctxsize);
+ memset(tfm, 0, tfm_size);
tfm->__crt_alg = alg;
@@ -155,8 +191,14 @@ out:
void crypto_free_tfm(struct crypto_tfm *tfm)
{
- struct crypto_alg *alg = tfm->__crt_alg;
- int size = sizeof(*tfm) + alg->cra_ctxsize;
+ struct crypto_alg *alg;
+ int size;
+
+ if (unlikely(!tfm))
+ return;
+
+ alg = tfm->__crt_alg;
+ size = sizeof(*tfm) + alg->cra_ctxsize;
crypto_exit_ops(tfm);
crypto_alg_put(alg);
@@ -168,6 +210,12 @@ int crypto_register_alg(struct crypto_alg *alg)
{
int ret = 0;
struct crypto_alg *q;
+
+ if (alg->cra_alignmask & (alg->cra_alignmask + 1))
+ return -EINVAL;
+
+ if (alg->cra_alignmask > PAGE_SIZE)
+ return -EINVAL;
down_write(&crypto_alg_sem);
diff --git a/crypto/cipher.c b/crypto/cipher.c
index f434ce7c2d0b..1c92c6bb138b 100644
--- a/crypto/cipher.c
+++ b/crypto/cipher.c
@@ -4,6 +4,7 @@
* Cipher operations.
*
* Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 Herbert Xu <herbert@gondor.apana.org.au>
*
* 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
@@ -22,10 +23,6 @@
#include "internal.h"
#include "scatterwalk.h"
-typedef void (cryptfn_t)(void *, u8 *, const u8 *);
-typedef void (procfn_t)(struct crypto_tfm *, u8 *,
- u8*, cryptfn_t, void *);
-
static inline void xor_64(u8 *a, const u8 *b)
{
((u32 *)a)[0] ^= ((u32 *)b)[0];
@@ -39,63 +36,70 @@ static inline void xor_128(u8 *a, const u8 *b)
((u32 *)a)[2] ^= ((u32 *)b)[2];
((u32 *)a)[3] ^= ((u32 *)b)[3];
}
-
-static inline void *prepare_src(struct scatter_walk *walk, int bsize,
- void *tmp, int in_place)
+
+static unsigned int crypt_slow(const struct cipher_desc *desc,
+ struct scatter_walk *in,
+ struct scatter_walk *out, unsigned int bsize)
{
- void *src = walk->data;
- int n = bsize;
+ unsigned int alignmask = crypto_tfm_alg_alignmask(desc->tfm);
+ u8 buffer[bsize * 2 + alignmask];
+ u8 *src = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ u8 *dst = src + bsize;
+ unsigned int n;
- if (unlikely(scatterwalk_across_pages(walk, bsize))) {
- src = tmp;
- n = scatterwalk_copychunks(src, walk, bsize, 0);
- }
- scatterwalk_advance(walk, n);
- return src;
+ n = scatterwalk_copychunks(src, in, bsize, 0);
+ scatterwalk_advance(in, n);
+
+ desc->prfn(desc, dst, src, bsize);
+
+ n = scatterwalk_copychunks(dst, out, bsize, 1);
+ scatterwalk_advance(out, n);
+
+ return bsize;
}
-static inline void *prepare_dst(struct scatter_walk *walk, int bsize,
- void *tmp, int in_place)
+static inline unsigned int crypt_fast(const struct cipher_desc *desc,
+ struct scatter_walk *in,
+ struct scatter_walk *out,
+ unsigned int nbytes, u8 *tmp)
{
- void *dst = walk->data;
+ u8 *src, *dst;
- if (unlikely(scatterwalk_across_pages(walk, bsize)) || in_place)
+ src = in->data;
+ dst = scatterwalk_samebuf(in, out) ? src : out->data;
+
+ if (tmp) {
+ memcpy(tmp, in->data, nbytes);
+ src = tmp;
dst = tmp;
- return dst;
-}
+ }
-static inline void complete_src(struct scatter_walk *walk, int bsize,
- void *src, int in_place)
-{
-}
+ nbytes = desc->prfn(desc, dst, src, nbytes);
-static inline void complete_dst(struct scatter_walk *walk, int bsize,
- void *dst, int in_place)
-{
- int n = bsize;
+ if (tmp)
+ memcpy(out->data, tmp, nbytes);
+
+ scatterwalk_advance(in, nbytes);
+ scatterwalk_advance(out, nbytes);
- if (unlikely(scatterwalk_across_pages(walk, bsize)))
- n = scatterwalk_copychunks(dst, walk, bsize, 1);
- else if (in_place)
- memcpy(walk->data, dst, bsize);
- scatterwalk_advance(walk, n);
+ return nbytes;
}
/*
* Generic encrypt/decrypt wrapper for ciphers, handles operations across
* multiple page boundaries by using temporary blocks. In user context,
- * the kernel is given a chance to schedule us once per block.
+ * the kernel is given a chance to schedule us once per page.
*/
-static int crypt(struct crypto_tfm *tfm,
+static int crypt(const struct cipher_desc *desc,
struct scatterlist *dst,
struct scatterlist *src,
- unsigned int nbytes, cryptfn_t crfn,
- procfn_t prfn, void *info)
+ unsigned int nbytes)
{
struct scatter_walk walk_in, walk_out;
+ struct crypto_tfm *tfm = desc->tfm;
const unsigned int bsize = crypto_tfm_alg_blocksize(tfm);
- u8 tmp_src[bsize];
- u8 tmp_dst[bsize];
+ unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
+ unsigned long buffer = 0;
if (!nbytes)
return 0;
@@ -109,64 +113,144 @@ static int crypt(struct crypto_tfm *tfm,
scatterwalk_start(&walk_out, dst);
for(;;) {
- u8 *src_p, *dst_p;
- int in_place;
+ unsigned int n = nbytes;
+ u8 *tmp = NULL;
+
+ if (!scatterwalk_aligned(&walk_in, alignmask) ||
+ !scatterwalk_aligned(&walk_out, alignmask)) {
+ if (!buffer) {
+ buffer = __get_free_page(GFP_ATOMIC);
+ if (!buffer)
+ n = 0;
+ }
+ tmp = (u8 *)buffer;
+ }
scatterwalk_map(&walk_in, 0);
scatterwalk_map(&walk_out, 1);
- in_place = scatterwalk_samebuf(&walk_in, &walk_out);
-
- do {
- src_p = prepare_src(&walk_in, bsize, tmp_src,
- in_place);
- dst_p = prepare_dst(&walk_out, bsize, tmp_dst,
- in_place);
-
- prfn(tfm, dst_p, src_p, crfn, info);
+ n = scatterwalk_clamp(&walk_in, n);
+ n = scatterwalk_clamp(&walk_out, n);
- complete_src(&walk_in, bsize, src_p, in_place);
- complete_dst(&walk_out, bsize, dst_p, in_place);
+ if (likely(n >= bsize))
+ n = crypt_fast(desc, &walk_in, &walk_out, n, tmp);
+ else
+ n = crypt_slow(desc, &walk_in, &walk_out, bsize);
- nbytes -= bsize;
- } while (nbytes &&
- !scatterwalk_across_pages(&walk_in, bsize) &&
- !scatterwalk_across_pages(&walk_out, bsize));
+ nbytes -= n;
scatterwalk_done(&walk_in, 0, nbytes);
scatterwalk_done(&walk_out, 1, nbytes);
if (!nbytes)
- return 0;
+ break;
crypto_yield(tfm);
}
+
+ if (buffer)
+ free_page(buffer);
+
+ return 0;
}
-static void cbc_process_encrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
- cryptfn_t fn, void *info)
+static int crypt_iv_unaligned(struct cipher_desc *desc,
+ struct scatterlist *dst,
+ struct scatterlist *src,
+ unsigned int nbytes)
{
- u8 *iv = info;
+ struct crypto_tfm *tfm = desc->tfm;
+ unsigned int alignmask = crypto_tfm_alg_alignmask(tfm);
+ u8 *iv = desc->info;
- tfm->crt_u.cipher.cit_xor_block(iv, src);
- fn(crypto_tfm_ctx(tfm), dst, iv);
- memcpy(iv, dst, crypto_tfm_alg_blocksize(tfm));
+ if (unlikely(((unsigned long)iv & alignmask))) {
+ unsigned int ivsize = tfm->crt_cipher.cit_ivsize;
+ u8 buffer[ivsize + alignmask];
+ u8 *tmp = (u8 *)ALIGN((unsigned long)buffer, alignmask + 1);
+ int err;
+
+ desc->info = memcpy(tmp, iv, ivsize);
+ err = crypt(desc, dst, src, nbytes);
+ memcpy(iv, tmp, ivsize);
+
+ return err;
+ }
+
+ return crypt(desc, dst, src, nbytes);
}
-static void cbc_process_decrypt(struct crypto_tfm *tfm, u8 *dst, u8 *src,
- cryptfn_t fn, void *info)
+static unsigned int cbc_process_encrypt(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes)
{
- u8 *iv = info;
+ struct crypto_tfm *tfm = desc->tfm;
+ void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
+ int bsize = crypto_tfm_alg_blocksize(tfm);
+
+ void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+ u8 *iv = desc->info;
+ unsigned int done = 0;
+
+ do {
+ xor(iv, src);
+ fn(crypto_tfm_ctx(tfm), dst, iv);
+ memcpy(iv, dst, bsize);
- fn(crypto_tfm_ctx(tfm), dst, src);
- tfm->crt_u.cipher.cit_xor_block(dst, iv);
- memcpy(iv, src, crypto_tfm_alg_blocksize(tfm));
+ src += bsize;
+ dst += bsize;
+ } while ((done += bsize) < nbytes);
+
+ return done;
}
-static void ecb_process(struct crypto_tfm *tfm, u8 *dst, u8 *src,
- cryptfn_t fn, void *info)
+static unsigned int cbc_process_decrypt(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes)
{
- fn(crypto_tfm_ctx(tfm), dst, src);
+ struct crypto_tfm *tfm = desc->tfm;
+ void (*xor)(u8 *, const u8 *) = tfm->crt_u.cipher.cit_xor_block;
+ int bsize = crypto_tfm_alg_blocksize(tfm);
+
+ u8 stack[src == dst ? bsize : 0];
+ u8 *buf = stack;
+ u8 **dst_p = src == dst ? &buf : &dst;
+
+ void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+ u8 *iv = desc->info;
+ unsigned int done = 0;
+
+ do {
+ u8 *tmp_dst = *dst_p;
+
+ fn(crypto_tfm_ctx(tfm), tmp_dst, src);
+ xor(tmp_dst, iv);
+ memcpy(iv, src, bsize);
+ if (tmp_dst != dst)
+ memcpy(dst, tmp_dst, bsize);
+
+ src += bsize;
+ dst += bsize;
+ } while ((done += bsize) < nbytes);
+
+ return done;
+}
+
+static unsigned int ecb_process(const struct cipher_desc *desc, u8 *dst,
+ const u8 *src, unsigned int nbytes)
+{
+ struct crypto_tfm *tfm = desc->tfm;
+ int bsize = crypto_tfm_alg_blocksize(tfm);
+ void (*fn)(void *, u8 *, const u8 *) = desc->crfn;
+ unsigned int done = 0;
+
+ do {
+ fn(crypto_tfm_ctx(tfm), dst, src);
+
+ src += bsize;
+ dst += bsize;
+ } while ((done += bsize) < nbytes);
+
+ return done;
}
static int setkey(struct crypto_tfm *tfm, const u8 *key, unsigned int keylen)
@@ -185,9 +269,14 @@ static int ecb_encrypt(struct crypto_tfm *tfm,
struct scatterlist *dst,
struct scatterlist *src, unsigned int nbytes)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- ecb_process, NULL);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+ desc.prfn = cipher->cia_encrypt_ecb ?: ecb_process;
+
+ return crypt(&desc, dst, src, nbytes);
}
static int ecb_decrypt(struct crypto_tfm *tfm,
@@ -195,9 +284,14 @@ static int ecb_decrypt(struct crypto_tfm *tfm,
struct scatterlist *src,
unsigned int nbytes)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- ecb_process, NULL);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+ desc.prfn = cipher->cia_decrypt_ecb ?: ecb_process;
+
+ return crypt(&desc, dst, src, nbytes);
}
static int cbc_encrypt(struct crypto_tfm *tfm,
@@ -205,9 +299,15 @@ static int cbc_encrypt(struct crypto_tfm *tfm,
struct scatterlist *src,
unsigned int nbytes)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- cbc_process_encrypt, tfm->crt_cipher.cit_iv);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+ desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
+ desc.info = tfm->crt_cipher.cit_iv;
+
+ return crypt(&desc, dst, src, nbytes);
}
static int cbc_encrypt_iv(struct crypto_tfm *tfm,
@@ -215,9 +315,15 @@ static int cbc_encrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_encrypt,
- cbc_process_encrypt, iv);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_encrypt;
+ desc.prfn = cipher->cia_encrypt_cbc ?: cbc_process_encrypt;
+ desc.info = iv;
+
+ return crypt_iv_unaligned(&desc, dst, src, nbytes);
}
static int cbc_decrypt(struct crypto_tfm *tfm,
@@ -225,9 +331,15 @@ static int cbc_decrypt(struct crypto_tfm *tfm,
struct scatterlist *src,
unsigned int nbytes)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- cbc_process_decrypt, tfm->crt_cipher.cit_iv);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+ desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
+ desc.info = tfm->crt_cipher.cit_iv;
+
+ return crypt(&desc, dst, src, nbytes);
}
static int cbc_decrypt_iv(struct crypto_tfm *tfm,
@@ -235,9 +347,15 @@ static int cbc_decrypt_iv(struct crypto_tfm *tfm,
struct scatterlist *src,
unsigned int nbytes, u8 *iv)
{
- return crypt(tfm, dst, src, nbytes,
- tfm->__crt_alg->cra_cipher.cia_decrypt,
- cbc_process_decrypt, iv);
+ struct cipher_desc desc;
+ struct cipher_alg *cipher = &tfm->__crt_alg->cra_cipher;
+
+ desc.tfm = tfm;
+ desc.crfn = cipher->cia_decrypt;
+ desc.prfn = cipher->cia_decrypt_cbc ?: cbc_process_decrypt;
+ desc.info = iv;
+
+ return crypt_iv_unaligned(&desc, dst, src, nbytes);
}
static int nocrypt(struct crypto_tfm *tfm,
@@ -306,6 +424,8 @@ int crypto_init_cipher_ops(struct crypto_tfm *tfm)
}
if (ops->cit_mode == CRYPTO_TFM_MODE_CBC) {
+ unsigned int align;
+ unsigned long addr;
switch (crypto_tfm_alg_blocksize(tfm)) {
case 8:
@@ -325,9 +445,11 @@ int crypto_init_cipher_ops(struct crypto_tfm *tfm)
}
ops->cit_ivsize = crypto_tfm_alg_blocksize(tfm);
- ops->cit_iv = kmalloc(ops->cit_ivsize, GFP_KERNEL);
- if (ops->cit_iv == NULL)
- ret = -ENOMEM;
+ align = crypto_tfm_alg_alignmask(tfm) + 1;
+ addr = (unsigned long)crypto_tfm_ctx(tfm);
+ addr = ALIGN(addr, align);
+ addr += ALIGN(tfm->__crt_alg->cra_ctxsize, align);
+ ops->cit_iv = (void *)addr;
}
out:
@@ -336,6 +458,4 @@ out:
void crypto_exit_cipher_ops(struct crypto_tfm *tfm)
{
- if (tfm->crt_cipher.cit_iv)
- kfree(tfm->crt_cipher.cit_iv);
}
diff --git a/crypto/des.c b/crypto/des.c
index 1c7e6de9356c..a3c863dddded 100644
--- a/crypto/des.c
+++ b/crypto/des.c
@@ -1,18 +1,9 @@
-/*
+/*
* Cryptographic API.
*
* DES & Triple DES EDE Cipher Algorithms.
*
- * Originally released as descore by Dana L. How <how@isl.stanford.edu>.
- * Modified by Raimar Falke <rf13@inf.tu-dresden.de> for the Linux-Kernel.
- * Derived from Cryptoapi and Nettle implementations, adapted for in-place
- * scatterlist interface. Changed LGPL to GPL per section 3 of the LGPL.
- *
- * Copyright (c) 1992 Dana L. How.
- * Copyright (c) Raimar Falke <rf13@inf.tu-dresden.de>
- * Copyright (c) Gisle Sælensminde <gisle@ii.uib.no>
- * Copyright (C) 2001 Niels Möller.
- * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
+ * Copyright (c) 2005 Dag Arne Osvik <da@osvik.no>
*
* 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
@@ -20,11 +11,11 @@
* (at your option) any later version.
*
*/
+
+#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/module.h>
-#include <linux/mm.h>
#include <linux/errno.h>
-#include <asm/scatterlist.h>
#include <linux/crypto.h>
#define DES_KEY_SIZE 8
@@ -35,1157 +26,826 @@
#define DES3_EDE_EXPKEY_WORDS (3 * DES_EXPKEY_WORDS)
#define DES3_EDE_BLOCK_SIZE DES_BLOCK_SIZE
-#define ROR(d,c,o) ((d) = (d) >> (c) | (d) << (o))
+#define ROL(x, r) ((x) = rol32((x), (r)))
+#define ROR(x, r) ((x) = ror32((x), (r)))
struct des_ctx {
- u8 iv[DES_BLOCK_SIZE];
u32 expkey[DES_EXPKEY_WORDS];
};
struct des3_ede_ctx {
- u8 iv[DES_BLOCK_SIZE];
u32 expkey[DES3_EDE_EXPKEY_WORDS];
};
-static const u32 des_keymap[] = {
- 0x02080008, 0x02082000, 0x00002008, 0x00000000,
- 0x02002000, 0x00080008, 0x02080000, 0x02082008,
- 0x00000008, 0x02000000, 0x00082000, 0x00002008,
- 0x00082008, 0x02002008, 0x02000008, 0x02080000,
- 0x00002000, 0x00082008, 0x00080008, 0x02002000,
- 0x02082008, 0x02000008, 0x00000000, 0x00082000,
- 0x02000000, 0x00080000, 0x02002008, 0x02080008,
- 0x00080000, 0x00002000, 0x02082000, 0x00000008,
- 0x00080000, 0x00002000, 0x02000008, 0x02082008,
- 0x00002008, 0x02000000, 0x00000000, 0x00082000,
- 0x02080008, 0x02002008, 0x02002000, 0x00080008,
- 0x02082000, 0x00000008, 0x00080008, 0x02002000,
- 0x02082008, 0x00080000, 0x02080000, 0x02000008,
- 0x00082000, 0x00002008, 0x02002008, 0x02080000,
- 0x00000008, 0x02082000, 0x00082008, 0x00000000,
- 0x02000000, 0x02080008, 0x00002000, 0x00082008,
-
- 0x08000004, 0x00020004, 0x00000000, 0x08020200,
- 0x00020004, 0x00000200, 0x08000204, 0x00020000,
- 0x00000204, 0x08020204, 0x00020200, 0x08000000,
- 0x08000200, 0x08000004, 0x08020000, 0x00020204,
- 0x00020000, 0x08000204, 0x08020004, 0x00000000,
- 0x00000200, 0x00000004, 0x08020200, 0x08020004,
- 0x08020204, 0x08020000, 0x08000000, 0x00000204,
- 0x00000004, 0x00020200, 0x00020204, 0x08000200,
- 0x00000204, 0x08000000, 0x08000200, 0x00020204,
- 0x08020200, 0x00020004, 0x00000000, 0x08000200,
- 0x08000000, 0x00000200, 0x08020004, 0x00020000,
- 0x00020004, 0x08020204, 0x00020200, 0x00000004,
- 0x08020204, 0x00020200, 0x00020000, 0x08000204,
- 0x08000004, 0x08020000, 0x00020204, 0x00000000,
- 0x00000200, 0x08000004, 0x08000204, 0x08020200,
- 0x08020000, 0x00000204, 0x00000004, 0x08020004,
-
- 0x80040100, 0x01000100, 0x80000000, 0x81040100,
- 0x00000000, 0x01040000, 0x81000100, 0x80040000,
- 0x01040100, 0x81000000, 0x01000000, 0x80000100,
- 0x81000000, 0x80040100, 0x00040000, 0x01000000,
- 0x81040000, 0x00040100, 0x00000100, 0x80000000,
- 0x00040100, 0x81000100, 0x01040000, 0x00000100,
- 0x80000100, 0x00000000, 0x80040000, 0x01040100,
- 0x01000100, 0x81040000, 0x81040100, 0x00040000,
- 0x81040000, 0x80000100, 0x00040000, 0x81000000,
- 0x00040100, 0x01000100, 0x80000000, 0x01040000,
- 0x81000100, 0x00000000, 0x00000100, 0x80040000,
- 0x00000000, 0x81040000, 0x01040100, 0x00000100,
- 0x01000000, 0x81040100, 0x80040100, 0x00040000,
- 0x81040100, 0x80000000, 0x01000100, 0x80040100,
- 0x80040000, 0x00040100, 0x01040000, 0x81000100,
- 0x80000100, 0x01000000, 0x81000000, 0x01040100,
-
- 0x04010801, 0x00000000, 0x00010800, 0x04010000,
- 0x04000001, 0x00000801, 0x04000800, 0x00010800,
- 0x00000800, 0x04010001, 0x00000001, 0x04000800,
- 0x00010001, 0x04010800, 0x04010000, 0x00000001,
- 0x00010000, 0x04000801, 0x04010001, 0x00000800,
- 0x00010801, 0x04000000, 0x00000000, 0x00010001,
- 0x04000801, 0x00010801, 0x04010800, 0x04000001,
- 0x04000000, 0x00010000, 0x00000801, 0x04010801,
- 0x00010001, 0x04010800, 0x04000800, 0x00010801,
- 0x04010801, 0x00010001, 0x04000001, 0x00000000,
- 0x04000000, 0x00000801, 0x00010000, 0x04010001,
- 0x00000800, 0x04000000, 0x00010801, 0x04000801,
- 0x04010800, 0x00000800, 0x00000000, 0x04000001,
- 0x00000001, 0x04010801, 0x00010800, 0x04010000,
- 0x04010001, 0x00010000, 0x00000801, 0x04000800,
- 0x04000801, 0x00000001, 0x04010000, 0x00010800,
-
- 0x00000400, 0x00000020, 0x00100020, 0x40100000,
- 0x40100420, 0x40000400, 0x00000420, 0x00000000,
- 0x00100000, 0x40100020, 0x40000020, 0x00100400,
- 0x40000000, 0x00100420, 0x00100400, 0x40000020,
- 0x40100020, 0x00000400, 0x40000400, 0x40100420,
- 0x00000000, 0x00100020, 0x40100000, 0x00000420,
- 0x40100400, 0x40000420, 0x00100420, 0x40000000,
- 0x40000420, 0x40100400, 0x00000020, 0x00100000,
- 0x40000420, 0x00100400, 0x40100400, 0x40000020,
- 0x00000400, 0x00000020, 0x00100000, 0x40100400,
- 0x40100020, 0x40000420, 0x00000420, 0x00000000,
- 0x00000020, 0x40100000, 0x40000000, 0x00100020,
- 0x00000000, 0x40100020, 0x00100020, 0x00000420,
- 0x40000020, 0x00000400, 0x40100420, 0x00100000,
- 0x00100420, 0x40000000, 0x40000400, 0x40100420,
- 0x40100000, 0x00100420, 0x00100400, 0x40000400,
-
- 0x00800000, 0x00001000, 0x00000040, 0x00801042,
- 0x00801002, 0x00800040, 0x00001042, 0x00801000,
- 0x00001000, 0x00000002, 0x00800002, 0x00001040,
- 0x00800042, 0x00801002, 0x00801040, 0x00000000,
- 0x00001040, 0x00800000, 0x00001002, 0x00000042,
- 0x00800040, 0x00001042, 0x00000000, 0x00800002,
- 0x00000002, 0x00800042, 0x00801042, 0x00001002,
- 0x00801000, 0x00000040, 0x00000042, 0x00801040,
- 0x00801040, 0x00800042, 0x00001002, 0x00801000,
- 0x00001000, 0x00000002, 0x00800002, 0x00800040,
- 0x00800000, 0x00001040, 0x00801042, 0x00000000,
- 0x00001042, 0x00800000, 0x00000040, 0x00001002,
- 0x00800042, 0x00000040, 0x00000000, 0x00801042,
- 0x00801002, 0x00801040, 0x00000042, 0x00001000,
- 0x00001040, 0x00801002, 0x00800040, 0x00000042,
- 0x00000002, 0x00001042, 0x00801000, 0x00800002,
-
- 0x10400000, 0x00404010, 0x00000010, 0x10400010,
- 0x10004000, 0x00400000, 0x10400010, 0x00004010,
- 0x00400010, 0x00004000, 0x00404000, 0x10000000,
- 0x10404010, 0x10000010, 0x10000000, 0x10404000,
- 0x00000000, 0x10004000, 0x00404010, 0x00000010,
- 0x10000010, 0x10404010, 0x00004000, 0x10400000,
- 0x10404000, 0x00400010, 0x10004010, 0x00404000,
- 0x00004010, 0x00000000, 0x00400000, 0x10004010,
- 0x00404010, 0x00000010, 0x10000000, 0x00004000,
- 0x10000010, 0x10004000, 0x00404000, 0x10400010,
- 0x00000000, 0x00404010, 0x00004010, 0x10404000,
- 0x10004000, 0x00400000, 0x10404010, 0x10000000,
- 0x10004010, 0x10400000, 0x00400000, 0x10404010,
- 0x00004000, 0x00400010, 0x10400010, 0x00004010,
- 0x00400010, 0x00000000, 0x10404000, 0x10000010,
- 0x10400000, 0x10004010, 0x00000010, 0x00404000,
-
- 0x00208080, 0x00008000, 0x20200000, 0x20208080,
- 0x00200000, 0x20008080, 0x20008000, 0x20200000,
- 0x20008080, 0x00208080, 0x00208000, 0x20000080,
- 0x20200080, 0x00200000, 0x00000000, 0x20008000,
- 0x00008000, 0x20000000, 0x00200080, 0x00008080,
- 0x20208080, 0x00208000, 0x20000080, 0x00200080,
- 0x20000000, 0x00000080, 0x00008080, 0x20208000,
- 0x00000080, 0x20200080, 0x20208000, 0x00000000,
- 0x00000000, 0x20208080, 0x00200080, 0x20008000,
- 0x00208080, 0x00008000, 0x20000080, 0x00200080,
- 0x20208000, 0x00000080, 0x00008080, 0x20200000,
- 0x20008080, 0x20000000, 0x20200000, 0x00208000,
- 0x20208080, 0x00008080, 0x00208000, 0x20200080,
- 0x00200000, 0x20000080, 0x20008000, 0x00000000,
- 0x00008000, 0x00200000, 0x20200080, 0x00208080,
- 0x20000000, 0x20208000, 0x00000080, 0x20008080,
+/* Lookup tables for key expansion */
+
+static const u8 pc1[256] = {
+ 0x00, 0x00, 0x40, 0x04, 0x10, 0x10, 0x50, 0x14,
+ 0x04, 0x40, 0x44, 0x44, 0x14, 0x50, 0x54, 0x54,
+ 0x02, 0x02, 0x42, 0x06, 0x12, 0x12, 0x52, 0x16,
+ 0x06, 0x42, 0x46, 0x46, 0x16, 0x52, 0x56, 0x56,
+ 0x80, 0x08, 0xc0, 0x0c, 0x90, 0x18, 0xd0, 0x1c,
+ 0x84, 0x48, 0xc4, 0x4c, 0x94, 0x58, 0xd4, 0x5c,
+ 0x82, 0x0a, 0xc2, 0x0e, 0x92, 0x1a, 0xd2, 0x1e,
+ 0x86, 0x4a, 0xc6, 0x4e, 0x96, 0x5a, 0xd6, 0x5e,
+ 0x20, 0x20, 0x60, 0x24, 0x30, 0x30, 0x70, 0x34,
+ 0x24, 0x60, 0x64, 0x64, 0x34, 0x70, 0x74, 0x74,
+ 0x22, 0x22, 0x62, 0x26, 0x32, 0x32, 0x72, 0x36,
+ 0x26, 0x62, 0x66, 0x66, 0x36, 0x72, 0x76, 0x76,
+ 0xa0, 0x28, 0xe0, 0x2c, 0xb0, 0x38, 0xf0, 0x3c,
+ 0xa4, 0x68, 0xe4, 0x6c, 0xb4, 0x78, 0xf4, 0x7c,
+ 0xa2, 0x2a, 0xe2, 0x2e, 0xb2, 0x3a, 0xf2, 0x3e,
+ 0xa6, 0x6a, 0xe6, 0x6e, 0xb6, 0x7a, 0xf6, 0x7e,
+ 0x08, 0x80, 0x48, 0x84, 0x18, 0x90, 0x58, 0x94,
+ 0x0c, 0xc0, 0x4c, 0xc4, 0x1c, 0xd0, 0x5c, 0xd4,
+ 0x0a, 0x82, 0x4a, 0x86, 0x1a, 0x92, 0x5a, 0x96,
+ 0x0e, 0xc2, 0x4e, 0xc6, 0x1e, 0xd2, 0x5e, 0xd6,
+ 0x88, 0x88, 0xc8, 0x8c, 0x98, 0x98, 0xd8, 0x9c,
+ 0x8c, 0xc8, 0xcc, 0xcc, 0x9c, 0xd8, 0xdc, 0xdc,
+ 0x8a, 0x8a, 0xca, 0x8e, 0x9a, 0x9a, 0xda, 0x9e,
+ 0x8e, 0xca, 0xce, 0xce, 0x9e, 0xda, 0xde, 0xde,
+ 0x28, 0xa0, 0x68, 0xa4, 0x38, 0xb0, 0x78, 0xb4,
+ 0x2c, 0xe0, 0x6c, 0xe4, 0x3c, 0xf0, 0x7c, 0xf4,
+ 0x2a, 0xa2, 0x6a, 0xa6, 0x3a, 0xb2, 0x7a, 0xb6,
+ 0x2e, 0xe2, 0x6e, 0xe6, 0x3e, 0xf2, 0x7e, 0xf6,
+ 0xa8, 0xa8, 0xe8, 0xac, 0xb8, 0xb8, 0xf8, 0xbc,
+ 0xac, 0xe8, 0xec, 0xec, 0xbc, 0xf8, 0xfc, 0xfc,
+ 0xaa, 0xaa, 0xea, 0xae, 0xba, 0xba, 0xfa, 0xbe,
+ 0xae, 0xea, 0xee, 0xee, 0xbe, 0xfa, 0xfe, 0xfe
};
-static const u8 rotors[] = {
- 34, 13, 5, 46, 47, 18, 32, 41, 11, 53, 33, 20,
- 14, 36, 30, 24, 49, 2, 15, 37, 42, 50, 0, 21,
- 38, 48, 6, 26, 39, 4, 52, 25, 12, 27, 31, 40,
- 1, 17, 28, 29, 23, 51, 35, 7, 3, 22, 9, 43,
-
- 41, 20, 12, 53, 54, 25, 39, 48, 18, 31, 40, 27,
- 21, 43, 37, 0, 1, 9, 22, 44, 49, 2, 7, 28,
- 45, 55, 13, 33, 46, 11, 6, 32, 19, 34, 38, 47,
- 8, 24, 35, 36, 30, 3, 42, 14, 10, 29, 16, 50,
-
- 55, 34, 26, 38, 11, 39, 53, 5, 32, 45, 54, 41,
- 35, 2, 51, 14, 15, 23, 36, 3, 8, 16, 21, 42,
- 6, 12, 27, 47, 31, 25, 20, 46, 33, 48, 52, 4,
- 22, 7, 49, 50, 44, 17, 1, 28, 24, 43, 30, 9,
-
- 12, 48, 40, 52, 25, 53, 38, 19, 46, 6, 11, 55,
- 49, 16, 10, 28, 29, 37, 50, 17, 22, 30, 35, 1,
- 20, 26, 41, 4, 45, 39, 34, 31, 47, 5, 13, 18,
- 36, 21, 8, 9, 3, 0, 15, 42, 7, 2, 44, 23,
-
- 26, 5, 54, 13, 39, 38, 52, 33, 31, 20, 25, 12,
- 8, 30, 24, 42, 43, 51, 9, 0, 36, 44, 49, 15,
- 34, 40, 55, 18, 6, 53, 48, 45, 4, 19, 27, 32,
- 50, 35, 22, 23, 17, 14, 29, 1, 21, 16, 3, 37,
-
- 40, 19, 11, 27, 53, 52, 13, 47, 45, 34, 39, 26,
- 22, 44, 7, 1, 2, 10, 23, 14, 50, 3, 8, 29,
- 48, 54, 12, 32, 20, 38, 5, 6, 18, 33, 41, 46,
- 9, 49, 36, 37, 0, 28, 43, 15, 35, 30, 17, 51,
-
- 54, 33, 25, 41, 38, 13, 27, 4, 6, 48, 53, 40,
- 36, 3, 21, 15, 16, 24, 37, 28, 9, 17, 22, 43,
- 5, 11, 26, 46, 34, 52, 19, 20, 32, 47, 55, 31,
- 23, 8, 50, 51, 14, 42, 2, 29, 49, 44, 0, 10,
-
- 11, 47, 39, 55, 52, 27, 41, 18, 20, 5, 38, 54,
- 50, 17, 35, 29, 30, 7, 51, 42, 23, 0, 36, 2,
- 19, 25, 40, 31, 48, 13, 33, 34, 46, 4, 12, 45,
- 37, 22, 9, 10, 28, 1, 16, 43, 8, 3, 14, 24,
-
- 18, 54, 46, 5, 6, 34, 48, 25, 27, 12, 45, 4,
- 2, 24, 42, 36, 37, 14, 3, 49, 30, 7, 43, 9,
- 26, 32, 47, 38, 55, 20, 40, 41, 53, 11, 19, 52,
- 44, 29, 16, 17, 35, 8, 23, 50, 15, 10, 21, 0,
-
- 32, 11, 31, 19, 20, 48, 5, 39, 41, 26, 6, 18,
- 16, 7, 1, 50, 51, 28, 17, 8, 44, 21, 2, 23,
- 40, 46, 4, 52, 12, 34, 54, 55, 38, 25, 33, 13,
- 3, 43, 30, 0, 49, 22, 37, 9, 29, 24, 35, 14,
-
- 46, 25, 45, 33, 34, 5, 19, 53, 55, 40, 20, 32,
- 30, 21, 15, 9, 10, 42, 0, 22, 3, 35, 16, 37,
- 54, 31, 18, 13, 26, 48, 11, 12, 52, 39, 47, 27,
- 17, 2, 44, 14, 8, 36, 51, 23, 43, 7, 49, 28,
-
- 31, 39, 6, 47, 48, 19, 33, 38, 12, 54, 34, 46,
- 44, 35, 29, 23, 24, 1, 14, 36, 17, 49, 30, 51,
- 11, 45, 32, 27, 40, 5, 25, 26, 13, 53, 4, 41,
- 0, 16, 3, 28, 22, 50, 10, 37, 2, 21, 8, 42,
-
- 45, 53, 20, 4, 5, 33, 47, 52, 26, 11, 48, 31,
- 3, 49, 43, 37, 7, 15, 28, 50, 0, 8, 44, 10,
- 25, 6, 46, 41, 54, 19, 39, 40, 27, 38, 18, 55,
- 14, 30, 17, 42, 36, 9, 24, 51, 16, 35, 22, 1,
-
- 6, 38, 34, 18, 19, 47, 4, 13, 40, 25, 5, 45,
- 17, 8, 2, 51, 21, 29, 42, 9, 14, 22, 3, 24,
- 39, 20, 31, 55, 11, 33, 53, 54, 41, 52, 32, 12,
- 28, 44, 0, 1, 50, 23, 7, 10, 30, 49, 36, 15,
-
- 20, 52, 48, 32, 33, 4, 18, 27, 54, 39, 19, 6,
- 0, 22, 16, 10, 35, 43, 1, 23, 28, 36, 17, 7,
- 53, 34, 45, 12, 25, 47, 38, 11, 55, 13, 46, 26,
- 42, 3, 14, 15, 9, 37, 21, 24, 44, 8, 50, 29,
-
- 27, 6, 55, 39, 40, 11, 25, 34, 4, 46, 26, 13,
- 7, 29, 23, 17, 42, 50, 8, 30, 35, 43, 24, 14,
- 31, 41, 52, 19, 32, 54, 45, 18, 5, 20, 53, 33,
- 49, 10, 21, 22, 16, 44, 28, 0, 51, 15, 2, 36,
+static const u8 rs[256] = {
+ 0x00, 0x00, 0x80, 0x80, 0x02, 0x02, 0x82, 0x82,
+ 0x04, 0x04, 0x84, 0x84, 0x06, 0x06, 0x86, 0x86,
+ 0x08, 0x08, 0x88, 0x88, 0x0a, 0x0a, 0x8a, 0x8a,
+ 0x0c, 0x0c, 0x8c, 0x8c, 0x0e, 0x0e, 0x8e, 0x8e,
+ 0x10, 0x10, 0x90, 0x90, 0x12, 0x12, 0x92, 0x92,
+ 0x14, 0x14, 0x94, 0x94, 0x16, 0x16, 0x96, 0x96,
+ 0x18, 0x18, 0x98, 0x98, 0x1a, 0x1a, 0x9a, 0x9a,
+ 0x1c, 0x1c, 0x9c, 0x9c, 0x1e, 0x1e, 0x9e, 0x9e,
+ 0x20, 0x20, 0xa0, 0xa0, 0x22, 0x22, 0xa2, 0xa2,
+ 0x24, 0x24, 0xa4, 0xa4, 0x26, 0x26, 0xa6, 0xa6,
+ 0x28, 0x28, 0xa8, 0xa8, 0x2a, 0x2a, 0xaa, 0xaa,
+ 0x2c, 0x2c, 0xac, 0xac, 0x2e, 0x2e, 0xae, 0xae,
+ 0x30, 0x30, 0xb0, 0xb0, 0x32, 0x32, 0xb2, 0xb2,
+ 0x34, 0x34, 0xb4, 0xb4, 0x36, 0x36, 0xb6, 0xb6,
+ 0x38, 0x38, 0xb8, 0xb8, 0x3a, 0x3a, 0xba, 0xba,
+ 0x3c, 0x3c, 0xbc, 0xbc, 0x3e, 0x3e, 0xbe, 0xbe,
+ 0x40, 0x40, 0xc0, 0xc0, 0x42, 0x42, 0xc2, 0xc2,
+ 0x44, 0x44, 0xc4, 0xc4, 0x46, 0x46, 0xc6, 0xc6,
+ 0x48, 0x48, 0xc8, 0xc8, 0x4a, 0x4a, 0xca, 0xca,
+ 0x4c, 0x4c, 0xcc, 0xcc, 0x4e, 0x4e, 0xce, 0xce,
+ 0x50, 0x50, 0xd0, 0xd0, 0x52, 0x52, 0xd2, 0xd2,
+ 0x54, 0x54, 0xd4, 0xd4, 0x56, 0x56, 0xd6, 0xd6,
+ 0x58, 0x58, 0xd8, 0xd8, 0x5a, 0x5a, 0xda, 0xda,
+ 0x5c, 0x5c, 0xdc, 0xdc, 0x5e, 0x5e, 0xde, 0xde,
+ 0x60, 0x60, 0xe0, 0xe0, 0x62, 0x62, 0xe2, 0xe2,
+ 0x64, 0x64, 0xe4, 0xe4, 0x66, 0x66, 0xe6, 0xe6,
+ 0x68, 0x68, 0xe8, 0xe8, 0x6a, 0x6a, 0xea, 0xea,
+ 0x6c, 0x6c, 0xec, 0xec, 0x6e, 0x6e, 0xee, 0xee,
+ 0x70, 0x70, 0xf0, 0xf0, 0x72, 0x72, 0xf2, 0xf2,
+ 0x74, 0x74, 0xf4, 0xf4, 0x76, 0x76, 0xf6, 0xf6,
+ 0x78, 0x78, 0xf8, 0xf8, 0x7a, 0x7a, 0xfa, 0xfa,
+ 0x7c, 0x7c, 0xfc, 0xfc, 0x7e, 0x7e, 0xfe, 0xfe
};
-static const u8 parity[] = {
- 8,1,0,8,0,8,8,0,0,8,8,0,8,0,2,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,3,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 8,0,0,8,0,8,8,0,0,8,8,0,8,0,0,8,0,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,
- 4,8,8,0,8,0,0,8,8,0,0,8,0,8,8,0,8,5,0,8,0,8,8,0,0,8,8,0,8,0,6,8,
+static const u32 pc2[1024] = {
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00040000, 0x00000000, 0x04000000, 0x00100000,
+ 0x00400000, 0x00000008, 0x00000800, 0x40000000,
+ 0x00440000, 0x00000008, 0x04000800, 0x40100000,
+ 0x00000400, 0x00000020, 0x08000000, 0x00000100,
+ 0x00040400, 0x00000020, 0x0c000000, 0x00100100,
+ 0x00400400, 0x00000028, 0x08000800, 0x40000100,
+ 0x00440400, 0x00000028, 0x0c000800, 0x40100100,
+ 0x80000000, 0x00000010, 0x00000000, 0x00800000,
+ 0x80040000, 0x00000010, 0x04000000, 0x00900000,
+ 0x80400000, 0x00000018, 0x00000800, 0x40800000,
+ 0x80440000, 0x00000018, 0x04000800, 0x40900000,
+ 0x80000400, 0x00000030, 0x08000000, 0x00800100,
+ 0x80040400, 0x00000030, 0x0c000000, 0x00900100,
+ 0x80400400, 0x00000038, 0x08000800, 0x40800100,
+ 0x80440400, 0x00000038, 0x0c000800, 0x40900100,
+ 0x10000000, 0x00000000, 0x00200000, 0x00001000,
+ 0x10040000, 0x00000000, 0x04200000, 0x00101000,
+ 0x10400000, 0x00000008, 0x00200800, 0x40001000,
+ 0x10440000, 0x00000008, 0x04200800, 0x40101000,
+ 0x10000400, 0x00000020, 0x08200000, 0x00001100,
+ 0x10040400, 0x00000020, 0x0c200000, 0x00101100,
+ 0x10400400, 0x00000028, 0x08200800, 0x40001100,
+ 0x10440400, 0x00000028, 0x0c200800, 0x40101100,
+ 0x90000000, 0x00000010, 0x00200000, 0x00801000,
+ 0x90040000, 0x00000010, 0x04200000, 0x00901000,
+ 0x90400000, 0x00000018, 0x00200800, 0x40801000,
+ 0x90440000, 0x00000018, 0x04200800, 0x40901000,
+ 0x90000400, 0x00000030, 0x08200000, 0x00801100,
+ 0x90040400, 0x00000030, 0x0c200000, 0x00901100,
+ 0x90400400, 0x00000038, 0x08200800, 0x40801100,
+ 0x90440400, 0x00000038, 0x0c200800, 0x40901100,
+ 0x00000200, 0x00080000, 0x00000000, 0x00000004,
+ 0x00040200, 0x00080000, 0x04000000, 0x00100004,
+ 0x00400200, 0x00080008, 0x00000800, 0x40000004,
+ 0x00440200, 0x00080008, 0x04000800, 0x40100004,
+ 0x00000600, 0x00080020, 0x08000000, 0x00000104,
+ 0x00040600, 0x00080020, 0x0c000000, 0x00100104,
+ 0x00400600, 0x00080028, 0x08000800, 0x40000104,
+ 0x00440600, 0x00080028, 0x0c000800, 0x40100104,
+ 0x80000200, 0x00080010, 0x00000000, 0x00800004,
+ 0x80040200, 0x00080010, 0x04000000, 0x00900004,
+ 0x80400200, 0x00080018, 0x00000800, 0x40800004,
+ 0x80440200, 0x00080018, 0x04000800, 0x40900004,
+ 0x80000600, 0x00080030, 0x08000000, 0x00800104,
+ 0x80040600, 0x00080030, 0x0c000000, 0x00900104,
+ 0x80400600, 0x00080038, 0x08000800, 0x40800104,
+ 0x80440600, 0x00080038, 0x0c000800, 0x40900104,
+ 0x10000200, 0x00080000, 0x00200000, 0x00001004,
+ 0x10040200, 0x00080000, 0x04200000, 0x00101004,
+ 0x10400200, 0x00080008, 0x00200800, 0x40001004,
+ 0x10440200, 0x00080008, 0x04200800, 0x40101004,
+ 0x10000600, 0x00080020, 0x08200000, 0x00001104,
+ 0x10040600, 0x00080020, 0x0c200000, 0x00101104,
+ 0x10400600, 0x00080028, 0x08200800, 0x40001104,
+ 0x10440600, 0x00080028, 0x0c200800, 0x40101104,
+ 0x90000200, 0x00080010, 0x00200000, 0x00801004,
+ 0x90040200, 0x00080010, 0x04200000, 0x00901004,
+ 0x90400200, 0x00080018, 0x00200800, 0x40801004,
+ 0x90440200, 0x00080018, 0x04200800, 0x40901004,
+ 0x90000600, 0x00080030, 0x08200000, 0x00801104,
+ 0x90040600, 0x00080030, 0x0c200000, 0x00901104,
+ 0x90400600, 0x00080038, 0x08200800, 0x40801104,
+ 0x90440600, 0x00080038, 0x0c200800, 0x40901104,
+ 0x00000002, 0x00002000, 0x20000000, 0x00000001,
+ 0x00040002, 0x00002000, 0x24000000, 0x00100001,
+ 0x00400002, 0x00002008, 0x20000800, 0x40000001,
+ 0x00440002, 0x00002008, 0x24000800, 0x40100001,
+ 0x00000402, 0x00002020, 0x28000000, 0x00000101,
+ 0x00040402, 0x00002020, 0x2c000000, 0x00100101,
+ 0x00400402, 0x00002028, 0x28000800, 0x40000101,
+ 0x00440402, 0x00002028, 0x2c000800, 0x40100101,
+ 0x80000002, 0x00002010, 0x20000000, 0x00800001,
+ 0x80040002, 0x00002010, 0x24000000, 0x00900001,
+ 0x80400002, 0x00002018, 0x20000800, 0x40800001,
+ 0x80440002, 0x00002018, 0x24000800, 0x40900001,
+ 0x80000402, 0x00002030, 0x28000000, 0x00800101,
+ 0x80040402, 0x00002030, 0x2c000000, 0x00900101,
+ 0x80400402, 0x00002038, 0x28000800, 0x40800101,
+ 0x80440402, 0x00002038, 0x2c000800, 0x40900101,
+ 0x10000002, 0x00002000, 0x20200000, 0x00001001,
+ 0x10040002, 0x00002000, 0x24200000, 0x00101001,
+ 0x10400002, 0x00002008, 0x20200800, 0x40001001,
+ 0x10440002, 0x00002008, 0x24200800, 0x40101001,
+ 0x10000402, 0x00002020, 0x28200000, 0x00001101,
+ 0x10040402, 0x00002020, 0x2c200000, 0x00101101,
+ 0x10400402, 0x00002028, 0x28200800, 0x40001101,
+ 0x10440402, 0x00002028, 0x2c200800, 0x40101101,
+ 0x90000002, 0x00002010, 0x20200000, 0x00801001,
+ 0x90040002, 0x00002010, 0x24200000, 0x00901001,
+ 0x90400002, 0x00002018, 0x20200800, 0x40801001,
+ 0x90440002, 0x00002018, 0x24200800, 0x40901001,
+ 0x90000402, 0x00002030, 0x28200000, 0x00801101,
+ 0x90040402, 0x00002030, 0x2c200000, 0x00901101,
+ 0x90400402, 0x00002038, 0x28200800, 0x40801101,
+ 0x90440402, 0x00002038, 0x2c200800, 0x40901101,
+ 0x00000202, 0x00082000, 0x20000000, 0x00000005,
+ 0x00040202, 0x00082000, 0x24000000, 0x00100005,
+ 0x00400202, 0x00082008, 0x20000800, 0x40000005,
+ 0x00440202, 0x00082008, 0x24000800, 0x40100005,
+ 0x00000602, 0x00082020, 0x28000000, 0x00000105,
+ 0x00040602, 0x00082020, 0x2c000000, 0x00100105,
+ 0x00400602, 0x00082028, 0x28000800, 0x40000105,
+ 0x00440602, 0x00082028, 0x2c000800, 0x40100105,
+ 0x80000202, 0x00082010, 0x20000000, 0x00800005,
+ 0x80040202, 0x00082010, 0x24000000, 0x00900005,
+ 0x80400202, 0x00082018, 0x20000800, 0x40800005,
+ 0x80440202, 0x00082018, 0x24000800, 0x40900005,
+ 0x80000602, 0x00082030, 0x28000000, 0x00800105,
+ 0x80040602, 0x00082030, 0x2c000000, 0x00900105,
+ 0x80400602, 0x00082038, 0x28000800, 0x40800105,
+ 0x80440602, 0x00082038, 0x2c000800, 0x40900105,
+ 0x10000202, 0x00082000, 0x20200000, 0x00001005,
+ 0x10040202, 0x00082000, 0x24200000, 0x00101005,
+ 0x10400202, 0x00082008, 0x20200800, 0x40001005,
+ 0x10440202, 0x00082008, 0x24200800, 0x40101005,
+ 0x10000602, 0x00082020, 0x28200000, 0x00001105,
+ 0x10040602, 0x00082020, 0x2c200000, 0x00101105,
+ 0x10400602, 0x00082028, 0x28200800, 0x40001105,
+ 0x10440602, 0x00082028, 0x2c200800, 0x40101105,
+ 0x90000202, 0x00082010, 0x20200000, 0x00801005,
+ 0x90040202, 0x00082010, 0x24200000, 0x00901005,
+ 0x90400202, 0x00082018, 0x20200800, 0x40801005,
+ 0x90440202, 0x00082018, 0x24200800, 0x40901005,
+ 0x90000602, 0x00082030, 0x28200000, 0x00801105,
+ 0x90040602, 0x00082030, 0x2c200000, 0x00901105,
+ 0x90400602, 0x00082038, 0x28200800, 0x40801105,
+ 0x90440602, 0x00082038, 0x2c200800, 0x40901105,
+
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000008, 0x00080000, 0x10000000,
+ 0x02000000, 0x00000000, 0x00000080, 0x00001000,
+ 0x02000000, 0x00000008, 0x00080080, 0x10001000,
+ 0x00004000, 0x00000000, 0x00000040, 0x00040000,
+ 0x00004000, 0x00000008, 0x00080040, 0x10040000,
+ 0x02004000, 0x00000000, 0x000000c0, 0x00041000,
+ 0x02004000, 0x00000008, 0x000800c0, 0x10041000,
+ 0x00020000, 0x00008000, 0x08000000, 0x00200000,
+ 0x00020000, 0x00008008, 0x08080000, 0x10200000,
+ 0x02020000, 0x00008000, 0x08000080, 0x00201000,
+ 0x02020000, 0x00008008, 0x08080080, 0x10201000,
+ 0x00024000, 0x00008000, 0x08000040, 0x00240000,
+ 0x00024000, 0x00008008, 0x08080040, 0x10240000,
+ 0x02024000, 0x00008000, 0x080000c0, 0x00241000,
+ 0x02024000, 0x00008008, 0x080800c0, 0x10241000,
+ 0x00000000, 0x01000000, 0x00002000, 0x00000020,
+ 0x00000000, 0x01000008, 0x00082000, 0x10000020,
+ 0x02000000, 0x01000000, 0x00002080, 0x00001020,
+ 0x02000000, 0x01000008, 0x00082080, 0x10001020,
+ 0x00004000, 0x01000000, 0x00002040, 0x00040020,
+ 0x00004000, 0x01000008, 0x00082040, 0x10040020,
+ 0x02004000, 0x01000000, 0x000020c0, 0x00041020,
+ 0x02004000, 0x01000008, 0x000820c0, 0x10041020,
+ 0x00020000, 0x01008000, 0x08002000, 0x00200020,
+ 0x00020000, 0x01008008, 0x08082000, 0x10200020,
+ 0x02020000, 0x01008000, 0x08002080, 0x00201020,
+ 0x02020000, 0x01008008, 0x08082080, 0x10201020,
+ 0x00024000, 0x01008000, 0x08002040, 0x00240020,
+ 0x00024000, 0x01008008, 0x08082040, 0x10240020,
+ 0x02024000, 0x01008000, 0x080020c0, 0x00241020,
+ 0x02024000, 0x01008008, 0x080820c0, 0x10241020,
+ 0x00000400, 0x04000000, 0x00100000, 0x00000004,
+ 0x00000400, 0x04000008, 0x00180000, 0x10000004,
+ 0x02000400, 0x04000000, 0x00100080, 0x00001004,
+ 0x02000400, 0x04000008, 0x00180080, 0x10001004,
+ 0x00004400, 0x04000000, 0x00100040, 0x00040004,
+ 0x00004400, 0x04000008, 0x00180040, 0x10040004,
+ 0x02004400, 0x04000000, 0x001000c0, 0x00041004,
+ 0x02004400, 0x04000008, 0x001800c0, 0x10041004,
+ 0x00020400, 0x04008000, 0x08100000, 0x00200004,
+ 0x00020400, 0x04008008, 0x08180000, 0x10200004,
+ 0x02020400, 0x04008000, 0x08100080, 0x00201004,
+ 0x02020400, 0x04008008, 0x08180080, 0x10201004,
+ 0x00024400, 0x04008000, 0x08100040, 0x00240004,
+ 0x00024400, 0x04008008, 0x08180040, 0x10240004,
+ 0x02024400, 0x04008000, 0x081000c0, 0x00241004,
+ 0x02024400, 0x04008008, 0x081800c0, 0x10241004,
+ 0x00000400, 0x05000000, 0x00102000, 0x00000024,
+ 0x00000400, 0x05000008, 0x00182000, 0x10000024,
+ 0x02000400, 0x05000000, 0x00102080, 0x00001024,
+ 0x02000400, 0x05000008, 0x00182080, 0x10001024,
+ 0x00004400, 0x05000000, 0x00102040, 0x00040024,
+ 0x00004400, 0x05000008, 0x00182040, 0x10040024,
+ 0x02004400, 0x05000000, 0x001020c0, 0x00041024,
+ 0x02004400, 0x05000008, 0x001820c0, 0x10041024,
+ 0x00020400, 0x05008000, 0x08102000, 0x00200024,
+ 0x00020400, 0x05008008, 0x08182000, 0x10200024,
+ 0x02020400, 0x05008000, 0x08102080, 0x00201024,
+ 0x02020400, 0x05008008, 0x08182080, 0x10201024,
+ 0x00024400, 0x05008000, 0x08102040, 0x00240024,
+ 0x00024400, 0x05008008, 0x08182040, 0x10240024,
+ 0x02024400, 0x05008000, 0x081020c0, 0x00241024,
+ 0x02024400, 0x05008008, 0x081820c0, 0x10241024,
+ 0x00000800, 0x00010000, 0x20000000, 0x00000010,
+ 0x00000800, 0x00010008, 0x20080000, 0x10000010,
+ 0x02000800, 0x00010000, 0x20000080, 0x00001010,
+ 0x02000800, 0x00010008, 0x20080080, 0x10001010,
+ 0x00004800, 0x00010000, 0x20000040, 0x00040010,
+ 0x00004800, 0x00010008, 0x20080040, 0x10040010,
+ 0x02004800, 0x00010000, 0x200000c0, 0x00041010,
+ 0x02004800, 0x00010008, 0x200800c0, 0x10041010,
+ 0x00020800, 0x00018000, 0x28000000, 0x00200010,
+ 0x00020800, 0x00018008, 0x28080000, 0x10200010,
+ 0x02020800, 0x00018000, 0x28000080, 0x00201010,
+ 0x02020800, 0x00018008, 0x28080080, 0x10201010,
+ 0x00024800, 0x00018000, 0x28000040, 0x00240010,
+ 0x00024800, 0x00018008, 0x28080040, 0x10240010,
+ 0x02024800, 0x00018000, 0x280000c0, 0x00241010,
+ 0x02024800, 0x00018008, 0x280800c0, 0x10241010,
+ 0x00000800, 0x01010000, 0x20002000, 0x00000030,
+ 0x00000800, 0x01010008, 0x20082000, 0x10000030,
+ 0x02000800, 0x01010000, 0x20002080, 0x00001030,
+ 0x02000800, 0x01010008, 0x20082080, 0x10001030,
+ 0x00004800, 0x01010000, 0x20002040, 0x00040030,
+ 0x00004800, 0x01010008, 0x20082040, 0x10040030,
+ 0x02004800, 0x01010000, 0x200020c0, 0x00041030,
+ 0x02004800, 0x01010008, 0x200820c0, 0x10041030,
+ 0x00020800, 0x01018000, 0x28002000, 0x00200030,
+ 0x00020800, 0x01018008, 0x28082000, 0x10200030,
+ 0x02020800, 0x01018000, 0x28002080, 0x00201030,
+ 0x02020800, 0x01018008, 0x28082080, 0x10201030,
+ 0x00024800, 0x01018000, 0x28002040, 0x00240030,
+ 0x00024800, 0x01018008, 0x28082040, 0x10240030,
+ 0x02024800, 0x01018000, 0x280020c0, 0x00241030,
+ 0x02024800, 0x01018008, 0x280820c0, 0x10241030,
+ 0x00000c00, 0x04010000, 0x20100000, 0x00000014,
+ 0x00000c00, 0x04010008, 0x20180000, 0x10000014,
+ 0x02000c00, 0x04010000, 0x20100080, 0x00001014,
+ 0x02000c00, 0x04010008, 0x20180080, 0x10001014,
+ 0x00004c00, 0x04010000, 0x20100040, 0x00040014,
+ 0x00004c00, 0x04010008, 0x20180040, 0x10040014,
+ 0x02004c00, 0x04010000, 0x201000c0, 0x00041014,
+ 0x02004c00, 0x04010008, 0x201800c0, 0x10041014,
+ 0x00020c00, 0x04018000, 0x28100000, 0x00200014,
+ 0x00020c00, 0x04018008, 0x28180000, 0x10200014,
+ 0x02020c00, 0x04018000, 0x28100080, 0x00201014,
+ 0x02020c00, 0x04018008, 0x28180080, 0x10201014,
+ 0x00024c00, 0x04018000, 0x28100040, 0x00240014,
+ 0x00024c00, 0x04018008, 0x28180040, 0x10240014,
+ 0x02024c00, 0x04018000, 0x281000c0, 0x00241014,
+ 0x02024c00, 0x04018008, 0x281800c0, 0x10241014,
+ 0x00000c00, 0x05010000, 0x20102000, 0x00000034,
+ 0x00000c00, 0x05010008, 0x20182000, 0x10000034,
+ 0x02000c00, 0x05010000, 0x20102080, 0x00001034,
+ 0x02000c00, 0x05010008, 0x20182080, 0x10001034,
+ 0x00004c00, 0x05010000, 0x20102040, 0x00040034,
+ 0x00004c00, 0x05010008, 0x20182040, 0x10040034,
+ 0x02004c00, 0x05010000, 0x201020c0, 0x00041034,
+ 0x02004c00, 0x05010008, 0x201820c0, 0x10041034,
+ 0x00020c00, 0x05018000, 0x28102000, 0x00200034,
+ 0x00020c00, 0x05018008, 0x28182000, 0x10200034,
+ 0x02020c00, 0x05018000, 0x28102080, 0x00201034,
+ 0x02020c00, 0x05018008, 0x28182080, 0x10201034,
+ 0x00024c00, 0x05018000, 0x28102040, 0x00240034,
+ 0x00024c00, 0x05018008, 0x28182040, 0x10240034,
+ 0x02024c00, 0x05018000, 0x281020c0, 0x00241034,
+ 0x02024c00, 0x05018008, 0x281820c0, 0x10241034
};
+/* S-box lookup tables */
+
+static const u32 S1[64] = {
+ 0x01010400, 0x00000000, 0x00010000, 0x01010404,
+ 0x01010004, 0x00010404, 0x00000004, 0x00010000,
+ 0x00000400, 0x01010400, 0x01010404, 0x00000400,
+ 0x01000404, 0x01010004, 0x01000000, 0x00000004,
+ 0x00000404, 0x01000400, 0x01000400, 0x00010400,
+ 0x00010400, 0x01010000, 0x01010000, 0x01000404,
+ 0x00010004, 0x01000004, 0x01000004, 0x00010004,
+ 0x00000000, 0x00000404, 0x00010404, 0x01000000,
+ 0x00010000, 0x01010404, 0x00000004, 0x01010000,
+ 0x01010400, 0x01000000, 0x01000000, 0x00000400,
+ 0x01010004, 0x00010000, 0x00010400, 0x01000004,
+ 0x00000400, 0x00000004, 0x01000404, 0x00010404,
+ 0x01010404, 0x00010004, 0x01010000, 0x01000404,
+ 0x01000004, 0x00000404, 0x00010404, 0x01010400,
+ 0x00000404, 0x01000400, 0x01000400, 0x00000000,
+ 0x00010004, 0x00010400, 0x00000000, 0x01010004
+};
-static void des_small_fips_encrypt(u32 *expkey, u8 *dst, const u8 *src)
-{
- u32 x, y, z;
-
- x = src[7];
- x <<= 8;
- x |= src[6];
- x <<= 8;
- x |= src[5];
- x <<= 8;
- x |= src[4];
- y = src[3];
- y <<= 8;
- y |= src[2];
- y <<= 8;
- y |= src[1];
- y <<= 8;
- y |= src[0];
- z = ((x >> 004) ^ y) & 0x0F0F0F0FL;
- x ^= z << 004;
- y ^= z;
- z = ((y >> 020) ^ x) & 0x0000FFFFL;
- y ^= z << 020;
- x ^= z;
- z = ((x >> 002) ^ y) & 0x33333333L;
- x ^= z << 002;
- y ^= z;
- z = ((y >> 010) ^ x) & 0x00FF00FFL;
- y ^= z << 010;
- x ^= z;
- x = x >> 1 | x << 31;
- z = (x ^ y) & 0x55555555L;
- y ^= z;
- x ^= z;
- y = y >> 1 | y << 31;
- z = expkey[0];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[1];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[2];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[3];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[4];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[5];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[6];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[7];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[8];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[9];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[10];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[11];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[12];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[13];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[14];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[15];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[16];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[17];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[18];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[19];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[20];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[21];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[22];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[23];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[24];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[25];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[26];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[27];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[28];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[29];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[30];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[31];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- x = x << 1 | x >> 31;
- z = (x ^ y) & 0x55555555L;
- y ^= z;
- x ^= z;
- y = y << 1 | y >> 31;
- z = ((x >> 010) ^ y) & 0x00FF00FFL;
- x ^= z << 010;
- y ^= z;
- z = ((y >> 002) ^ x) & 0x33333333L;
- y ^= z << 002;
- x ^= z;
- z = ((x >> 020) ^ y) & 0x0000FFFFL;
- x ^= z << 020;
- y ^= z;
- z = ((y >> 004) ^ x) & 0x0F0F0F0FL;
- y ^= z << 004;
- x ^= z;
- dst[0] = x;
- x >>= 8;
- dst[1] = x;
- x >>= 8;
- dst[2] = x;
- x >>= 8;
- dst[3] = x;
- dst[4] = y;
- y >>= 8;
- dst[5] = y;
- y >>= 8;
- dst[6] = y;
- y >>= 8;
- dst[7] = y;
-}
+static const u32 S2[64] = {
+ 0x80108020, 0x80008000, 0x00008000, 0x00108020,
+ 0x00100000, 0x00000020, 0x80100020, 0x80008020,
+ 0x80000020, 0x80108020, 0x80108000, 0x80000000,
+ 0x80008000, 0x00100000, 0x00000020, 0x80100020,
+ 0x00108000, 0x00100020, 0x80008020, 0x00000000,
+ 0x80000000, 0x00008000, 0x00108020, 0x80100000,
+ 0x00100020, 0x80000020, 0x00000000, 0x00108000,
+ 0x00008020, 0x80108000, 0x80100000, 0x00008020,
+ 0x00000000, 0x00108020, 0x80100020, 0x00100000,
+ 0x80008020, 0x80100000, 0x80108000, 0x00008000,
+ 0x80100000, 0x80008000, 0x00000020, 0x80108020,
+ 0x00108020, 0x00000020, 0x00008000, 0x80000000,
+ 0x00008020, 0x80108000, 0x00100000, 0x80000020,
+ 0x00100020, 0x80008020, 0x80000020, 0x00100020,
+ 0x00108000, 0x00000000, 0x80008000, 0x00008020,
+ 0x80000000, 0x80100020, 0x80108020, 0x00108000
+};
-static void des_small_fips_decrypt(u32 *expkey, u8 *dst, const u8 *src)
-{
- u32 x, y, z;
-
- x = src[7];
- x <<= 8;
- x |= src[6];
- x <<= 8;
- x |= src[5];
- x <<= 8;
- x |= src[4];
- y = src[3];
- y <<= 8;
- y |= src[2];
- y <<= 8;
- y |= src[1];
- y <<= 8;
- y |= src[0];
- z = ((x >> 004) ^ y) & 0x0F0F0F0FL;
- x ^= z << 004;
- y ^= z;
- z = ((y >> 020) ^ x) & 0x0000FFFFL;
- y ^= z << 020;
- x ^= z;
- z = ((x >> 002) ^ y) & 0x33333333L;
- x ^= z << 002;
- y ^= z;
- z = ((y >> 010) ^ x) & 0x00FF00FFL;
- y ^= z << 010;
- x ^= z;
- x = x >> 1 | x << 31;
- z = (x ^ y) & 0x55555555L;
- y ^= z;
- x ^= z;
- y = y >> 1 | y << 31;
- z = expkey[31];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[30];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[29];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[28];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[27];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[26];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[25];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[24];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[23];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[22];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[21];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[20];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[19];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[18];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[17];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[16];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[15];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[14];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[13];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[12];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[11];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[10];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[9];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[8];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[7];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[6];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[5];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[4];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[3];
- z ^= y;
- z = z << 4 | z >> 28;
- x ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[2];
- z ^= y;
- x ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- x ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- z = expkey[1];
- z ^= x;
- z = z << 4 | z >> 28;
- y ^= * (u32 *) ((u8 *) (des_keymap + 448) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 384) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 320) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 256) + (0xFC & z));
- z = expkey[0];
- z ^= x;
- y ^= * (u32 *) ((u8 *) (des_keymap + 192) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 128) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) (des_keymap + 64) + (0xFC & z));
- z >>= 8;
- y ^= * (u32 *) ((u8 *) des_keymap + (0xFC & z));
- x = x << 1 | x >> 31;
- z = (x ^ y) & 0x55555555L;
- y ^= z;
- x ^= z;
- y = y << 1 | y >> 31;
- z = ((x >> 010) ^ y) & 0x00FF00FFL;
- x ^= z << 010;
- y ^= z;
- z = ((y >> 002) ^ x) & 0x33333333L;
- y ^= z << 002;
- x ^= z;
- z = ((x >> 020) ^ y) & 0x0000FFFFL;
- x ^= z << 020;
- y ^= z;
- z = ((y >> 004) ^ x) & 0x0F0F0F0FL;
- y ^= z << 004;
- x ^= z;
- dst[0] = x;
- x >>= 8;
- dst[1] = x;
- x >>= 8;
- dst[2] = x;
- x >>= 8;
- dst[3] = x;
- dst[4] = y;
- y >>= 8;
- dst[5] = y;
- y >>= 8;
- dst[6] = y;
- y >>= 8;
- dst[7] = y;
-}
+static const u32 S3[64] = {
+ 0x00000208, 0x08020200, 0x00000000, 0x08020008,
+ 0x08000200, 0x00000000, 0x00020208, 0x08000200,
+ 0x00020008, 0x08000008, 0x08000008, 0x00020000,
+ 0x08020208, 0x00020008, 0x08020000, 0x00000208,
+ 0x08000000, 0x00000008, 0x08020200, 0x00000200,
+ 0x00020200, 0x08020000, 0x08020008, 0x00020208,
+ 0x08000208, 0x00020200, 0x00020000, 0x08000208,
+ 0x00000008, 0x08020208, 0x00000200, 0x08000000,
+ 0x08020200, 0x08000000, 0x00020008, 0x00000208,
+ 0x00020000, 0x08020200, 0x08000200, 0x00000000,
+ 0x00000200, 0x00020008, 0x08020208, 0x08000200,
+ 0x08000008, 0x00000200, 0x00000000, 0x08020008,
+ 0x08000208, 0x00020000, 0x08000000, 0x08020208,
+ 0x00000008, 0x00020208, 0x00020200, 0x08000008,
+ 0x08020000, 0x08000208, 0x00000208, 0x08020000,
+ 0x00020208, 0x00000008, 0x08020008, 0x00020200
+};
+
+static const u32 S4[64] = {
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802080, 0x00800081, 0x00800001, 0x00002001,
+ 0x00000000, 0x00802000, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00800080, 0x00800001,
+ 0x00000001, 0x00002000, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002001, 0x00002080,
+ 0x00800081, 0x00000001, 0x00002080, 0x00800080,
+ 0x00002000, 0x00802080, 0x00802081, 0x00000081,
+ 0x00800080, 0x00800001, 0x00802000, 0x00802081,
+ 0x00000081, 0x00000000, 0x00000000, 0x00802000,
+ 0x00002080, 0x00800080, 0x00800081, 0x00000001,
+ 0x00802001, 0x00002081, 0x00002081, 0x00000080,
+ 0x00802081, 0x00000081, 0x00000001, 0x00002000,
+ 0x00800001, 0x00002001, 0x00802080, 0x00800081,
+ 0x00002001, 0x00002080, 0x00800000, 0x00802001,
+ 0x00000080, 0x00800000, 0x00002000, 0x00802080
+};
+
+static const u32 S5[64] = {
+ 0x00000100, 0x02080100, 0x02080000, 0x42000100,
+ 0x00080000, 0x00000100, 0x40000000, 0x02080000,
+ 0x40080100, 0x00080000, 0x02000100, 0x40080100,
+ 0x42000100, 0x42080000, 0x00080100, 0x40000000,
+ 0x02000000, 0x40080000, 0x40080000, 0x00000000,
+ 0x40000100, 0x42080100, 0x42080100, 0x02000100,
+ 0x42080000, 0x40000100, 0x00000000, 0x42000000,
+ 0x02080100, 0x02000000, 0x42000000, 0x00080100,
+ 0x00080000, 0x42000100, 0x00000100, 0x02000000,
+ 0x40000000, 0x02080000, 0x42000100, 0x40080100,
+ 0x02000100, 0x40000000, 0x42080000, 0x02080100,
+ 0x40080100, 0x00000100, 0x02000000, 0x42080000,
+ 0x42080100, 0x00080100, 0x42000000, 0x42080100,
+ 0x02080000, 0x00000000, 0x40080000, 0x42000000,
+ 0x00080100, 0x02000100, 0x40000100, 0x00080000,
+ 0x00000000, 0x40080000, 0x02080100, 0x40000100
+};
+
+static const u32 S6[64] = {
+ 0x20000010, 0x20400000, 0x00004000, 0x20404010,
+ 0x20400000, 0x00000010, 0x20404010, 0x00400000,
+ 0x20004000, 0x00404010, 0x00400000, 0x20000010,
+ 0x00400010, 0x20004000, 0x20000000, 0x00004010,
+ 0x00000000, 0x00400010, 0x20004010, 0x00004000,
+ 0x00404000, 0x20004010, 0x00000010, 0x20400010,
+ 0x20400010, 0x00000000, 0x00404010, 0x20404000,
+ 0x00004010, 0x00404000, 0x20404000, 0x20000000,
+ 0x20004000, 0x00000010, 0x20400010, 0x00404000,
+ 0x20404010, 0x00400000, 0x00004010, 0x20000010,
+ 0x00400000, 0x20004000, 0x20000000, 0x00004010,
+ 0x20000010, 0x20404010, 0x00404000, 0x20400000,
+ 0x00404010, 0x20404000, 0x00000000, 0x20400010,
+ 0x00000010, 0x00004000, 0x20400000, 0x00404010,
+ 0x00004000, 0x00400010, 0x20004010, 0x00000000,
+ 0x20404000, 0x20000000, 0x00400010, 0x20004010
+};
+
+static const u32 S7[64] = {
+ 0x00200000, 0x04200002, 0x04000802, 0x00000000,
+ 0x00000800, 0x04000802, 0x00200802, 0x04200800,
+ 0x04200802, 0x00200000, 0x00000000, 0x04000002,
+ 0x00000002, 0x04000000, 0x04200002, 0x00000802,
+ 0x04000800, 0x00200802, 0x00200002, 0x04000800,
+ 0x04000002, 0x04200000, 0x04200800, 0x00200002,
+ 0x04200000, 0x00000800, 0x00000802, 0x04200802,
+ 0x00200800, 0x00000002, 0x04000000, 0x00200800,
+ 0x04000000, 0x00200800, 0x00200000, 0x04000802,
+ 0x04000802, 0x04200002, 0x04200002, 0x00000002,
+ 0x00200002, 0x04000000, 0x04000800, 0x00200000,
+ 0x04200800, 0x00000802, 0x00200802, 0x04200800,
+ 0x00000802, 0x04000002, 0x04200802, 0x04200000,
+ 0x00200800, 0x00000000, 0x00000002, 0x04200802,
+ 0x00000000, 0x00200802, 0x04200000, 0x00000800,
+ 0x04000002, 0x04000800, 0x00000800, 0x00200002
+};
+
+static const u32 S8[64] = {
+ 0x10001040, 0x00001000, 0x00040000, 0x10041040,
+ 0x10000000, 0x10001040, 0x00000040, 0x10000000,
+ 0x00040040, 0x10040000, 0x10041040, 0x00041000,
+ 0x10041000, 0x00041040, 0x00001000, 0x00000040,
+ 0x10040000, 0x10000040, 0x10001000, 0x00001040,
+ 0x00041000, 0x00040040, 0x10040040, 0x10041000,
+ 0x00001040, 0x00000000, 0x00000000, 0x10040040,
+ 0x10000040, 0x10001000, 0x00041040, 0x00040000,
+ 0x00041040, 0x00040000, 0x10041000, 0x00001000,
+ 0x00000040, 0x10040040, 0x00001000, 0x00041040,
+ 0x10001000, 0x00000040, 0x10000040, 0x10040000,
+ 0x10040040, 0x10000000, 0x00040000, 0x10001040,
+ 0x00000000, 0x10041040, 0x00040040, 0x10000040,
+ 0x10040000, 0x10001000, 0x10001040, 0x00000000,
+ 0x10041040, 0x00041000, 0x00041000, 0x00001040,
+ 0x00001040, 0x00040040, 0x10000000, 0x10041000
+};
+
+/* Encryption components: IP, FP, and round function */
+
+#define IP(L, R, T) \
+ ROL(R, 4); \
+ T = L; \
+ L ^= R; \
+ L &= 0xf0f0f0f0; \
+ R ^= L; \
+ L ^= T; \
+ ROL(R, 12); \
+ T = L; \
+ L ^= R; \
+ L &= 0xffff0000; \
+ R ^= L; \
+ L ^= T; \
+ ROR(R, 14); \
+ T = L; \
+ L ^= R; \
+ L &= 0xcccccccc; \
+ R ^= L; \
+ L ^= T; \
+ ROL(R, 6); \
+ T = L; \
+ L ^= R; \
+ L &= 0xff00ff00; \
+ R ^= L; \
+ L ^= T; \
+ ROR(R, 7); \
+ T = L; \
+ L ^= R; \
+ L &= 0xaaaaaaaa; \
+ R ^= L; \
+ L ^= T; \
+ ROL(L, 1);
+
+#define FP(L, R, T) \
+ ROR(L, 1); \
+ T = L; \
+ L ^= R; \
+ L &= 0xaaaaaaaa; \
+ R ^= L; \
+ L ^= T; \
+ ROL(R, 7); \
+ T = L; \
+ L ^= R; \
+ L &= 0xff00ff00; \
+ R ^= L; \
+ L ^= T; \
+ ROR(R, 6); \
+ T = L; \
+ L ^= R; \
+ L &= 0xcccccccc; \
+ R ^= L; \
+ L ^= T; \
+ ROL(R, 14); \
+ T = L; \
+ L ^= R; \
+ L &= 0xffff0000; \
+ R ^= L; \
+ L ^= T; \
+ ROR(R, 12); \
+ T = L; \
+ L ^= R; \
+ L &= 0xf0f0f0f0; \
+ R ^= L; \
+ L ^= T; \
+ ROR(R, 4);
+
+#define ROUND(L, R, A, B, K, d) \
+ B = K[0]; A = K[1]; K += d; \
+ B ^= R; A ^= R; \
+ B &= 0x3f3f3f3f; ROR(A, 4); \
+ L ^= S8[0xff & B]; A &= 0x3f3f3f3f; \
+ L ^= S6[0xff & (B >> 8)]; B >>= 16; \
+ L ^= S7[0xff & A]; \
+ L ^= S5[0xff & (A >> 8)]; A >>= 16; \
+ L ^= S4[0xff & B]; \
+ L ^= S2[0xff & (B >> 8)]; \
+ L ^= S3[0xff & A]; \
+ L ^= S1[0xff & (A >> 8)];
+
+/*
+ * PC2 lookup tables are organized as 2 consecutive sets of 4 interleaved
+ * tables of 128 elements. One set is for C_i and the other for D_i, while
+ * the 4 interleaved tables correspond to four 7-bit subsets of C_i or D_i.
+ *
+ * After PC1 each of the variables a,b,c,d contains a 7 bit subset of C_i
+ * or D_i in bits 7-1 (bit 0 being the least significant).
+ */
+
+#define T1(x) pt[2 * (x) + 0]
+#define T2(x) pt[2 * (x) + 1]
+#define T3(x) pt[2 * (x) + 2]
+#define T4(x) pt[2 * (x) + 3]
+
+#define PC2(a, b, c, d) (T4(d) | T3(c) | T2(b) | T1(a))
/*
+ * Encryption key expansion
+ *
* RFC2451: Weak key checks SHOULD be performed.
+ *
+ * FIPS 74:
+ *
+ * Keys having duals are keys which produce all zeros, all ones, or
+ * alternating zero-one patterns in the C and D registers after Permuted
+ * Choice 1 has operated on the key.
+ *
*/
-static int setkey(u32 *expkey, const u8 *key, unsigned int keylen, u32 *flags)
+static unsigned long ekey(u32 *pe, const u8 *k)
{
- const u8 *k;
- u8 *b0, *b1;
- u32 n, w;
- u8 bits0[56], bits1[56];
-
- n = parity[key[0]]; n <<= 4;
- n |= parity[key[1]]; n <<= 4;
- n |= parity[key[2]]; n <<= 4;
- n |= parity[key[3]]; n <<= 4;
- n |= parity[key[4]]; n <<= 4;
- n |= parity[key[5]]; n <<= 4;
- n |= parity[key[6]]; n <<= 4;
- n |= parity[key[7]];
- w = 0x88888888L;
-
- if ((*flags & CRYPTO_TFM_REQ_WEAK_KEY)
- && !((n - (w >> 3)) & w)) { /* 1 in 10^10 keys passes this test */
- if (n < 0x41415151) {
- if (n < 0x31312121) {
- if (n < 0x14141515) {
- /* 01 01 01 01 01 01 01 01 */
- if (n == 0x11111111) goto weak;
- /* 01 1F 01 1F 01 0E 01 0E */
- if (n == 0x13131212) goto weak;
- } else {
- /* 01 E0 01 E0 01 F1 01 F1 */
- if (n == 0x14141515) goto weak;
- /* 01 FE 01 FE 01 FE 01 FE */
- if (n == 0x16161616) goto weak;
- }
- } else {
- if (n < 0x34342525) {
- /* 1F 01 1F 01 0E 01 0E 01 */
- if (n == 0x31312121) goto weak;
- /* 1F 1F 1F 1F 0E 0E 0E 0E (?) */
- if (n == 0x33332222) goto weak;
- } else {
- /* 1F E0 1F E0 0E F1 0E F1 */
- if (n == 0x34342525) goto weak;
- /* 1F FE 1F FE 0E FE 0E FE */
- if (n == 0x36362626) goto weak;
- }
- }
- } else {
- if (n < 0x61616161) {
- if (n < 0x44445555) {
- /* E0 01 E0 01 F1 01 F1 01 */
- if (n == 0x41415151) goto weak;
- /* E0 1F E0 1F F1 0E F1 0E */
- if (n == 0x43435252) goto weak;
- } else {
- /* E0 E0 E0 E0 F1 F1 F1 F1 (?) */
- if (n == 0x44445555) goto weak;
- /* E0 FE E0 FE F1 FE F1 FE */
- if (n == 0x46465656) goto weak;
- }
- } else {
- if (n < 0x64646565) {
- /* FE 01 FE 01 FE 01 FE 01 */
- if (n == 0x61616161) goto weak;
- /* FE 1F FE 1F FE 0E FE 0E */
- if (n == 0x63636262) goto weak;
- } else {
- /* FE E0 FE E0 FE F1 FE F1 */
- if (n == 0x64646565) goto weak;
- /* FE FE FE FE FE FE FE FE */
- if (n == 0x66666666) goto weak;
- }
- }
- }
-
- goto not_weak;
-weak:
- *flags |= CRYPTO_TFM_RES_WEAK_KEY;
- return -EINVAL;
+ /* K&R: long is at least 32 bits */
+ unsigned long a, b, c, d, w;
+ const u32 *pt = pc2;
+
+ d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
+ c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
+ b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
+ a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
+
+ pe[15 * 2 + 0] = PC2(a, b, c, d); d = rs[d];
+ pe[14 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[13 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[12 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[11 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[10 * 2 + 0] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 9 * 2 + 0] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 8 * 2 + 0] = PC2(d, a, b, c); c = rs[c];
+ pe[ 7 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 6 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 5 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 4 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 3 * 2 + 0] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 2 * 2 + 0] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 1 * 2 + 0] = PC2(c, d, a, b); b = rs[b];
+ pe[ 0 * 2 + 0] = PC2(b, c, d, a);
+
+ /* Check if first half is weak */
+ w = (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
+
+ /* Skip to next table set */
+ pt += 512;
+
+ d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
+ c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
+ b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
+ a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
+
+ /* Check if second half is weak */
+ w |= (a ^ c) | (b ^ d) | (rs[a] ^ c) | (b ^ rs[d]);
+
+ pe[15 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
+ pe[14 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[13 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[12 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[11 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[10 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 9 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 8 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
+ pe[ 7 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 6 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 5 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 4 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 3 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 2 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[ 1 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
+ pe[ 0 * 2 + 1] = PC2(b, c, d, a);
+
+ /* Fixup: 2413 5768 -> 1357 2468 */
+ for (d = 0; d < 16; ++d) {
+ a = pe[2 * d];
+ b = pe[2 * d + 1];
+ c = a ^ b;
+ c &= 0xffff0000;
+ a ^= c;
+ b ^= c;
+ ROL(b, 18);
+ pe[2 * d] = a;
+ pe[2 * d + 1] = b;
}
-not_weak:
-
- /* explode the bits */
- n = 56;
- b0 = bits0;
- b1 = bits1;
-
- do {
- w = (256 | *key++) << 2;
- do {
- --n;
- b1[n] = 8 & w;
- w >>= 1;
- b0[n] = 4 & w;
- } while ( w >= 16 );
- } while ( n );
-
- /* put the bits in the correct places */
- n = 16;
- k = rotors;
-
- do {
- w = (b1[k[ 0 ]] | b0[k[ 1 ]]) << 4;
- w |= (b1[k[ 2 ]] | b0[k[ 3 ]]) << 2;
- w |= b1[k[ 4 ]] | b0[k[ 5 ]];
- w <<= 8;
- w |= (b1[k[ 6 ]] | b0[k[ 7 ]]) << 4;
- w |= (b1[k[ 8 ]] | b0[k[ 9 ]]) << 2;
- w |= b1[k[10 ]] | b0[k[11 ]];
- w <<= 8;
- w |= (b1[k[12 ]] | b0[k[13 ]]) << 4;
- w |= (b1[k[14 ]] | b0[k[15 ]]) << 2;
- w |= b1[k[16 ]] | b0[k[17 ]];
- w <<= 8;
- w |= (b1[k[18 ]] | b0[k[19 ]]) << 4;
- w |= (b1[k[20 ]] | b0[k[21 ]]) << 2;
- w |= b1[k[22 ]] | b0[k[23 ]];
- expkey[0] = w;
-
- w = (b1[k[ 0+24]] | b0[k[ 1+24]]) << 4;
- w |= (b1[k[ 2+24]] | b0[k[ 3+24]]) << 2;
- w |= b1[k[ 4+24]] | b0[k[ 5+24]];
- w <<= 8;
- w |= (b1[k[ 6+24]] | b0[k[ 7+24]]) << 4;
- w |= (b1[k[ 8+24]] | b0[k[ 9+24]]) << 2;
- w |= b1[k[10+24]] | b0[k[11+24]];
- w <<= 8;
- w |= (b1[k[12+24]] | b0[k[13+24]]) << 4;
- w |= (b1[k[14+24]] | b0[k[15+24]]) << 2;
- w |= b1[k[16+24]] | b0[k[17+24]];
- w <<= 8;
- w |= (b1[k[18+24]] | b0[k[19+24]]) << 4;
- w |= (b1[k[20+24]] | b0[k[21+24]]) << 2;
- w |= b1[k[22+24]] | b0[k[23+24]];
-
- ROR(w, 4, 28); /* could be eliminated */
- expkey[1] = w;
-
- k += 48;
- expkey += 2;
- } while (--n);
+ /* Zero if weak key */
+ return w;
+}
- return 0;
+/*
+ * Decryption key expansion
+ *
+ * No weak key checking is performed, as this is only used by triple DES
+ *
+ */
+static void dkey(u32 *pe, const u8 *k)
+{
+ /* K&R: long is at least 32 bits */
+ unsigned long a, b, c, d;
+ const u32 *pt = pc2;
+
+ d = k[4]; d &= 0x0e; d <<= 4; d |= k[0] & 0x1e; d = pc1[d];
+ c = k[5]; c &= 0x0e; c <<= 4; c |= k[1] & 0x1e; c = pc1[c];
+ b = k[6]; b &= 0x0e; b <<= 4; b |= k[2] & 0x1e; b = pc1[b];
+ a = k[7]; a &= 0x0e; a <<= 4; a |= k[3] & 0x1e; a = pc1[a];
+
+ pe[ 0 * 2] = PC2(a, b, c, d); d = rs[d];
+ pe[ 1 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 2 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 3 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 4 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 5 * 2] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 6 * 2] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 7 * 2] = PC2(d, a, b, c); c = rs[c];
+ pe[ 8 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 9 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[10 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[11 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[12 * 2] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[13 * 2] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[14 * 2] = PC2(c, d, a, b); b = rs[b];
+ pe[15 * 2] = PC2(b, c, d, a);
+
+ /* Skip to next table set */
+ pt += 512;
+
+ d = k[0]; d &= 0xe0; d >>= 4; d |= k[4] & 0xf0; d = pc1[d + 1];
+ c = k[1]; c &= 0xe0; c >>= 4; c |= k[5] & 0xf0; c = pc1[c + 1];
+ b = k[2]; b &= 0xe0; b >>= 4; b |= k[6] & 0xf0; b = pc1[b + 1];
+ a = k[3]; a &= 0xe0; a >>= 4; a |= k[7] & 0xf0; a = pc1[a + 1];
+
+ pe[ 0 * 2 + 1] = PC2(a, b, c, d); d = rs[d];
+ pe[ 1 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 2 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 3 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 4 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 5 * 2 + 1] = PC2(d, a, b, c); c = rs[c]; b = rs[b];
+ pe[ 6 * 2 + 1] = PC2(b, c, d, a); a = rs[a]; d = rs[d];
+ pe[ 7 * 2 + 1] = PC2(d, a, b, c); c = rs[c];
+ pe[ 8 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[ 9 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[10 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[11 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[12 * 2 + 1] = PC2(c, d, a, b); b = rs[b]; a = rs[a];
+ pe[13 * 2 + 1] = PC2(a, b, c, d); d = rs[d]; c = rs[c];
+ pe[14 * 2 + 1] = PC2(c, d, a, b); b = rs[b];
+ pe[15 * 2 + 1] = PC2(b, c, d, a);
+
+ /* Fixup: 2413 5768 -> 1357 2468 */
+ for (d = 0; d < 16; ++d) {
+ a = pe[2 * d];
+ b = pe[2 * d + 1];
+ c = a ^ b;
+ c &= 0xffff0000;
+ a ^= c;
+ b ^= c;
+ ROL(b, 18);
+ pe[2 * d] = a;
+ pe[2 * d + 1] = b;
+ }
}
static int des_setkey(void *ctx, const u8 *key, unsigned int keylen, u32 *flags)
{
- return setkey(((struct des_ctx *)ctx)->expkey, key, keylen, flags);
+ struct des_ctx *dctx = ctx;
+ u32 tmp[DES_EXPKEY_WORDS];
+ int ret;
+
+ /* Expand to tmp */
+ ret = ekey(tmp, key);
+
+ if (unlikely(ret == 0) && (*flags & CRYPTO_TFM_REQ_WEAK_KEY)) {
+ *flags |= CRYPTO_TFM_RES_WEAK_KEY;
+ return -EINVAL;
+ }
+
+ /* Copy to output */
+ memcpy(dctx->expkey, tmp, sizeof(dctx->expkey));
+
+ return 0;
}
static void des_encrypt(void *ctx, u8 *dst, const u8 *src)
{
- des_small_fips_encrypt(((struct des_ctx *)ctx)->expkey, dst, src);
+ const u32 *K = ((struct des_ctx *)ctx)->expkey;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 L, R, A, B;
+ int i;
+
+ L = le32_to_cpu(s[0]);
+ R = le32_to_cpu(s[1]);
+
+ IP(L, R, A);
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, 2);
+ ROUND(R, L, A, B, K, 2);
+ }
+ FP(R, L, A);
+
+ d[0] = cpu_to_le32(R);
+ d[1] = cpu_to_le32(L);
}
static void des_decrypt(void *ctx, u8 *dst, const u8 *src)
{
- des_small_fips_decrypt(((struct des_ctx *)ctx)->expkey, dst, src);
+ const u32 *K = ((struct des_ctx *)ctx)->expkey + DES_EXPKEY_WORDS - 2;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 L, R, A, B;
+ int i;
+
+ L = le32_to_cpu(s[0]);
+ R = le32_to_cpu(s[1]);
+
+ IP(L, R, A);
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, -2);
+ ROUND(R, L, A, B, K, -2);
+ }
+ FP(R, L, A);
+
+ d[0] = cpu_to_le32(R);
+ d[1] = cpu_to_le32(L);
}
-/*
+/*
* RFC2451:
*
* For DES-EDE3, there is no known need to reject weak or
@@ -1199,44 +859,86 @@ static void des_decrypt(void *ctx, u8 *dst, const u8 *src)
*
*/
static int des3_ede_setkey(void *ctx, const u8 *key,
- unsigned int keylen, u32 *flags)
+ unsigned int keylen, u32 *flags)
{
- unsigned int i, off;
+ const u32 *K = (const u32 *)key;
struct des3_ede_ctx *dctx = ctx;
+ u32 *expkey = dctx->expkey;
- if (!(memcmp(key, &key[DES_KEY_SIZE], DES_KEY_SIZE) &&
- memcmp(&key[DES_KEY_SIZE], &key[DES_KEY_SIZE * 2],
- DES_KEY_SIZE))) {
-
+ if (unlikely(!((K[0] ^ K[2]) | (K[1] ^ K[3])) ||
+ !((K[2] ^ K[4]) | (K[3] ^ K[5]))))
+ {
*flags |= CRYPTO_TFM_RES_BAD_KEY_SCHED;
return -EINVAL;
}
-
- for (i = 0, off = 0; i < 3; i++, off += DES_EXPKEY_WORDS,
- key += DES_KEY_SIZE) {
- int ret = setkey(&dctx->expkey[off], key, DES_KEY_SIZE, flags);
- if (ret < 0)
- return ret;
- }
+
+ ekey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+ dkey(expkey, key); expkey += DES_EXPKEY_WORDS; key += DES_KEY_SIZE;
+ ekey(expkey, key);
+
return 0;
}
static void des3_ede_encrypt(void *ctx, u8 *dst, const u8 *src)
{
struct des3_ede_ctx *dctx = ctx;
-
- des_small_fips_encrypt(dctx->expkey, dst, src);
- des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst);
- des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, dst);
+ const u32 *K = dctx->expkey;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 L, R, A, B;
+ int i;
+
+ L = le32_to_cpu(s[0]);
+ R = le32_to_cpu(s[1]);
+
+ IP(L, R, A);
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, 2);
+ ROUND(R, L, A, B, K, 2);
+ }
+ for (i = 0; i < 8; i++) {
+ ROUND(R, L, A, B, K, 2);
+ ROUND(L, R, A, B, K, 2);
+ }
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, 2);
+ ROUND(R, L, A, B, K, 2);
+ }
+ FP(R, L, A);
+
+ d[0] = cpu_to_le32(R);
+ d[1] = cpu_to_le32(L);
}
static void des3_ede_decrypt(void *ctx, u8 *dst, const u8 *src)
{
struct des3_ede_ctx *dctx = ctx;
+ const u32 *K = dctx->expkey + DES3_EDE_EXPKEY_WORDS - 2;
+ const __le32 *s = (const __le32 *)src;
+ __le32 *d = (__le32 *)dst;
+ u32 L, R, A, B;
+ int i;
+
+ L = le32_to_cpu(s[0]);
+ R = le32_to_cpu(s[1]);
+
+ IP(L, R, A);
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, -2);
+ ROUND(R, L, A, B, K, -2);
+ }
+ for (i = 0; i < 8; i++) {
+ ROUND(R, L, A, B, K, -2);
+ ROUND(L, R, A, B, K, -2);
+ }
+ for (i = 0; i < 8; i++) {
+ ROUND(L, R, A, B, K, -2);
+ ROUND(R, L, A, B, K, -2);
+ }
+ FP(R, L, A);
- des_small_fips_decrypt(&dctx->expkey[DES_EXPKEY_WORDS * 2], dst, src);
- des_small_fips_encrypt(&dctx->expkey[DES_EXPKEY_WORDS], dst, dst);
- des_small_fips_decrypt(dctx->expkey, dst, dst);
+ d[0] = cpu_to_le32(R);
+ d[1] = cpu_to_le32(L);
}
static struct crypto_alg des_alg = {
@@ -1249,7 +951,7 @@ static struct crypto_alg des_alg = {
.cra_u = { .cipher = {
.cia_min_keysize = DES_KEY_SIZE,
.cia_max_keysize = DES_KEY_SIZE,
- .cia_setkey = des_setkey,
+ .cia_setkey = des_setkey,
.cia_encrypt = des_encrypt,
.cia_decrypt = des_decrypt } }
};
@@ -1264,9 +966,9 @@ static struct crypto_alg des3_ede_alg = {
.cra_u = { .cipher = {
.cia_min_keysize = DES3_EDE_KEY_SIZE,
.cia_max_keysize = DES3_EDE_KEY_SIZE,
- .cia_setkey = des3_ede_setkey,
- .cia_encrypt = des3_ede_encrypt,
- .cia_decrypt = des3_ede_decrypt } }
+ .cia_setkey = des3_ede_setkey,
+ .cia_encrypt = des3_ede_encrypt,
+ .cia_decrypt = des3_ede_decrypt } }
};
MODULE_ALIAS("des3_ede");
@@ -1274,7 +976,7 @@ MODULE_ALIAS("des3_ede");
static int __init init(void)
{
int ret = 0;
-
+
ret = crypto_register_alg(&des_alg);
if (ret < 0)
goto out;
@@ -1282,7 +984,7 @@ static int __init init(void)
ret = crypto_register_alg(&des3_ede_alg);
if (ret < 0)
crypto_unregister_alg(&des_alg);
-out:
+out:
return ret;
}
@@ -1297,3 +999,4 @@ module_exit(fini);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("DES & Triple DES EDE Cipher Algorithms");
+MODULE_AUTHOR("Dag Arne Osvik <da@osvik.no>");
diff --git a/crypto/hmac.c b/crypto/hmac.c
index 847df9263e16..da0456b37109 100644
--- a/crypto/hmac.c
+++ b/crypto/hmac.c
@@ -49,8 +49,7 @@ int crypto_alloc_hmac_block(struct crypto_tfm *tfm)
void crypto_free_hmac_block(struct crypto_tfm *tfm)
{
- if (tfm->crt_digest.dit_hmac_block)
- kfree(tfm->crt_digest.dit_hmac_block);
+ kfree(tfm->crt_digest.dit_hmac_block);
}
void crypto_hmac_init(struct crypto_tfm *tfm, u8 *key, unsigned int *keylen)
diff --git a/crypto/internal.h b/crypto/internal.h
index 964b9a60ca24..68612874b5fd 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -16,7 +16,7 @@
#include <linux/highmem.h>
#include <linux/interrupt.h>
#include <linux/init.h>
-#include <linux/kmod.h>
+#include <linux/kernel.h>
#include <asm/kmap_types.h>
extern enum km_type crypto_km_types[];
@@ -42,20 +42,6 @@ static inline void crypto_yield(struct crypto_tfm *tfm)
cond_resched();
}
-static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
-{
- return (void *)&tfm[1];
-}
-
-struct crypto_alg *crypto_alg_lookup(const char *name);
-
-/* A far more intelligent version of this is planned. For now, just
- * try an exact match on the name of the algorithm. */
-static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name)
-{
- return try_then_request_module(crypto_alg_lookup(name), name);
-}
-
#ifdef CONFIG_CRYPTO_HMAC
int crypto_alloc_hmac_block(struct crypto_tfm *tfm);
void crypto_free_hmac_block(struct crypto_tfm *tfm);
@@ -76,6 +62,33 @@ static inline void crypto_init_proc(void)
{ }
#endif
+static inline unsigned int crypto_digest_ctxsize(struct crypto_alg *alg,
+ int flags)
+{
+ return alg->cra_ctxsize;
+}
+
+static inline unsigned int crypto_cipher_ctxsize(struct crypto_alg *alg,
+ int flags)
+{
+ unsigned int len = alg->cra_ctxsize;
+
+ switch (flags & CRYPTO_TFM_MODE_MASK) {
+ case CRYPTO_TFM_MODE_CBC:
+ len = ALIGN(len, alg->cra_alignmask + 1);
+ len += alg->cra_blocksize;
+ break;
+ }
+
+ return len;
+}
+
+static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg,
+ int flags)
+{
+ return alg->cra_ctxsize;
+}
+
int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
diff --git a/crypto/scatterwalk.c b/crypto/scatterwalk.c
index 50c9461e8cc6..47ac90e615f4 100644
--- a/crypto/scatterwalk.c
+++ b/crypto/scatterwalk.c
@@ -100,7 +100,7 @@ void scatterwalk_done(struct scatter_walk *walk, int out, int more)
int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
size_t nbytes, int out)
{
- do {
+ while (nbytes > walk->len_this_page) {
memcpy_dir(buf, walk->data, walk->len_this_page, out);
buf += walk->len_this_page;
nbytes -= walk->len_this_page;
@@ -108,7 +108,7 @@ int scatterwalk_copychunks(void *buf, struct scatter_walk *walk,
scatterwalk_unmap(walk, out);
scatterwalk_pagedone(walk, out, 1);
scatterwalk_map(walk, out);
- } while (nbytes > walk->len_this_page);
+ }
memcpy_dir(buf, walk->data, nbytes, out);
return nbytes;
diff --git a/crypto/scatterwalk.h b/crypto/scatterwalk.h
index 02aa56c649b4..e79925c474a3 100644
--- a/crypto/scatterwalk.h
+++ b/crypto/scatterwalk.h
@@ -40,10 +40,10 @@ static inline int scatterwalk_samebuf(struct scatter_walk *walk_in,
walk_in->offset == walk_out->offset;
}
-static inline int scatterwalk_across_pages(struct scatter_walk *walk,
- unsigned int nbytes)
+static inline unsigned int scatterwalk_clamp(struct scatter_walk *walk,
+ unsigned int nbytes)
{
- return nbytes > walk->len_this_page;
+ return nbytes > walk->len_this_page ? walk->len_this_page : nbytes;
}
static inline void scatterwalk_advance(struct scatter_walk *walk,
@@ -55,6 +55,12 @@ static inline void scatterwalk_advance(struct scatter_walk *walk,
walk->len_this_segment -= nbytes;
}
+static inline unsigned int scatterwalk_aligned(struct scatter_walk *walk,
+ unsigned int alignmask)
+{
+ return !(walk->offset & alignmask);
+}
+
void scatterwalk_start(struct scatter_walk *walk, struct scatterlist *sg);
int scatterwalk_copychunks(void *buf, struct scatter_walk *walk, size_t nbytes, int out);
void scatterwalk_map(struct scatter_walk *walk, int out);
diff --git a/crypto/serpent.c b/crypto/serpent.c
index 7d152e89016f..3cf2c5067eea 100644
--- a/crypto/serpent.c
+++ b/crypto/serpent.c
@@ -210,7 +210,6 @@
x4 ^= x2;
struct serpent_ctx {
- u8 iv[SERPENT_BLOCK_SIZE];
u32 expkey[SERPENT_EXPKEY_WORDS];
};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index aed4a9b97c14..cecab0acc3fe 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -28,7 +28,7 @@ source "drivers/message/i2o/Kconfig"
source "drivers/macintosh/Kconfig"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
@@ -44,6 +44,8 @@ source "drivers/i2c/Kconfig"
source "drivers/w1/Kconfig"
+source "drivers/hwmon/Kconfig"
+
source "drivers/misc/Kconfig"
source "drivers/media/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index 3167be54fedd..126a851d5653 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -52,6 +52,7 @@ obj-$(CONFIG_INPUT) += input/
obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_W1) += w1/
+obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 670fdb5142d1..986410e7b483 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -3,6 +3,7 @@
#
menu "ACPI (Advanced Configuration and Power Interface) Support"
+ depends on PM
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
@@ -48,14 +49,13 @@ config ACPI_BOOT
config ACPI_INTERPRETER
bool
- depends on !IA64_SGI_SN
default y
if ACPI_INTERPRETER
config ACPI_SLEEP
bool "Sleep States (EXPERIMENTAL)"
- depends on X86
+ depends on X86 && (!SMP || SUSPEND_SMP)
depends on EXPERIMENTAL && PM
default y
---help---
@@ -79,6 +79,14 @@ config ACPI_SLEEP_PROC_FS
depends on ACPI_SLEEP && PROC_FS
default y
+config ACPI_SLEEP_PROC_SLEEP
+ bool "/proc/acpi/sleep (deprecated)"
+ depends on ACPI_SLEEP_PROC_FS
+ default n
+ ---help---
+ Create /proc/acpi/sleep
+ Deprecated by /sys/power/state
+
config ACPI_AC
tristate "AC Adapter"
depends on X86
@@ -99,7 +107,6 @@ config ACPI_BATTERY
config ACPI_BUTTON
tristate "Button"
- depends on !IA64_SGI_SN
default m
help
This driver registers for events based on buttons, such as the
@@ -111,7 +118,6 @@ config ACPI_BUTTON
config ACPI_VIDEO
tristate "Video"
depends on EXPERIMENTAL
- depends on !IA64_SGI_SN
default m
help
This driver implement the ACPI Extensions For Display Adapters
@@ -122,9 +128,17 @@ config ACPI_VIDEO
Note that this is an ref. implementation only. It may or may not work
for your integrated video device.
+config ACPI_HOTKEY
+ tristate "Generic Hotkey"
+ depends on ACPI_INTERPRETER
+ depends on EXPERIMENTAL
+ depends on !IA64_SGI_SN
+ default m
+ help
+ ACPI generic hotkey
+
config ACPI_FAN
tristate "Fan"
- depends on !IA64_SGI_SN
default m
help
This driver adds support for ACPI fan devices, allowing user-mode
@@ -132,7 +146,6 @@ config ACPI_FAN
config ACPI_PROCESSOR
tristate "Processor"
- depends on !IA64_SGI_SN
default m
help
This driver installs ACPI as the idle handler for Linux, and uses
@@ -142,7 +155,6 @@ config ACPI_PROCESSOR
config ACPI_HOTPLUG_CPU
bool "Processor Hotplug (EXPERIMENTAL)"
depends on ACPI_PROCESSOR && HOTPLUG_CPU && EXPERIMENTAL
- depends on !IA64_SGI_SN
select ACPI_CONTAINER
default n
---help---
@@ -262,7 +274,6 @@ config ACPI_BLACKLIST_YEAR
config ACPI_DEBUG
bool "Debug Statements"
- depends on !IA64_SGI_SN
default n
help
The ACPI driver can optionally report errors with a great deal
@@ -271,7 +282,6 @@ config ACPI_DEBUG
config ACPI_BUS
bool
- depends on !IA64_SGI_SN
default y
config ACPI_EC
@@ -285,17 +295,14 @@ config ACPI_EC
config ACPI_POWER
bool
- depends on !IA64_SGI_SN
default y
config ACPI_PCI
bool
- depends on !IA64_SGI_SN
default PCI
config ACPI_SYSTEM
bool
- depends on !IA64_SGI_SN
default y
help
This driver will enable your system to shut down using ACPI, and
@@ -327,8 +334,13 @@ config ACPI_CONTAINER
depends on EXPERIMENTAL
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
---help---
- This is the ACPI generic container driver which supports
- ACPI0004, PNP0A05 and PNP0A06 devices
+ This allows _physical_ insertion and removal of CPUs and memory.
+ This can be useful, for example, on NUMA machines that support
+ ACPI based physical hotplug of nodes, or non-NUMA machines that
+ support physical cpu/memory hot-plug.
+
+ If one selects "m", this driver can be loaded with
+ "modprobe acpi_container".
config ACPI_HOTPLUG_MEMORY
tristate "Memory Hotplug"
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 65c92e20566d..ad67e8f61e6c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -36,13 +36,14 @@ processor-objs += processor_perflib.o
endif
obj-$(CONFIG_ACPI_BUS) += sleep/
-obj-$(CONFIG_ACPI_BUS) += bus.o
+obj-$(CONFIG_ACPI_BUS) += bus.o glue.o
obj-$(CONFIG_ACPI_AC) += ac.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_BUTTON) += button.o
obj-$(CONFIG_ACPI_EC) += ec.o
obj-$(CONFIG_ACPI_FAN) += fan.o
-obj-$(CONFIG_ACPI_VIDEO) += video.o
+obj-$(CONFIG_ACPI_VIDEO) += video.o
+obj-$(CONFIG_ACPI_HOTKEY) += hotkey.o
obj-$(CONFIG_ACPI_PCI) += pci_root.o pci_link.o pci_irq.o pci_bind.o
obj-$(CONFIG_ACPI_POWER) += power.o
obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
index a75cb565caeb..a560b1e2da77 100644
--- a/drivers/acpi/asus_acpi.c
+++ b/drivers/acpi/asus_acpi.c
@@ -1204,6 +1204,10 @@ static int __init asus_acpi_init(void)
if (acpi_disabled)
return -ENODEV;
+ if (!acpi_specific_hotkey_enabled){
+ printk(KERN_ERR "Using generic hotkey driver\n");
+ 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");
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 4edff1738579..d77c2307883c 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -212,6 +212,12 @@ acpi_bus_set_power (
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Device is not power manageable\n"));
return_VALUE(-ENODEV);
}
+ /*
+ * Get device's current power state if it's unknown
+ * This means device power state isn't initialized or previous setting failed
+ */
+ if (device->power.state == ACPI_STATE_UNKNOWN)
+ acpi_bus_get_power(device->handle, &device->power.state);
if (state == device->power.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device is already at D%d\n", state));
return_VALUE(0);
@@ -231,7 +237,7 @@ acpi_bus_set_power (
* On transitions to a high-powered state we first apply power (via
* power resources) then evalute _PSx. Conversly for transitions to
* a lower-powered state.
- */
+ */
if (state < device->power.state) {
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index ec4430e3053f..0f45d45f05a0 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -26,9 +26,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -36,9 +33,6 @@
#define ACPI_BUTTON_COMPONENT 0x00080000
#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
#define ACPI_BUTTON_CLASS "button"
-#define ACPI_BUTTON_FILE_INFO "info"
-#define ACPI_BUTTON_FILE_STATE "state"
-#define ACPI_BUTTON_TYPE_UNKNOWN 0x00
#define ACPI_BUTTON_NOTIFY_STATUS 0x80
#define ACPI_BUTTON_SUBCLASS_POWER "power"
@@ -70,8 +64,6 @@ MODULE_LICENSE("GPL");
static int acpi_button_add (struct acpi_device *device);
static int acpi_button_remove (struct acpi_device *device, int type);
-static int acpi_button_info_open_fs(struct inode *inode, struct file *file);
-static int acpi_button_state_open_fs(struct inode *inode, struct file *file);
static struct acpi_driver acpi_button_driver = {
.name = ACPI_BUTTON_DRIVER_NAME,
@@ -90,187 +82,6 @@ struct acpi_button {
unsigned long pushed;
};
-static struct file_operations acpi_button_info_fops = {
- .open = acpi_button_info_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static struct file_operations acpi_button_state_fops = {
- .open = acpi_button_state_open_fs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-/* --------------------------------------------------------------------------
- FS Interface (/proc)
- -------------------------------------------------------------------------- */
-
-static struct proc_dir_entry *acpi_button_dir;
-
-static int acpi_button_info_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_button *button = (struct acpi_button *) seq->private;
-
- ACPI_FUNCTION_TRACE("acpi_button_info_seq_show");
-
- if (!button || !button->device)
- return_VALUE(0);
-
- seq_printf(seq, "type: %s\n",
- acpi_device_name(button->device));
-
- return_VALUE(0);
-}
-
-static int acpi_button_info_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_button_info_seq_show, PDE(inode)->data);
-}
-
-static int acpi_button_state_seq_show(struct seq_file *seq, void *offset)
-{
- struct acpi_button *button = (struct acpi_button *) seq->private;
- acpi_status status;
- unsigned long state;
-
- ACPI_FUNCTION_TRACE("acpi_button_state_seq_show");
-
- if (!button || !button->device)
- return_VALUE(0);
-
- status = acpi_evaluate_integer(button->handle,"_LID",NULL,&state);
- if (ACPI_FAILURE(status)) {
- seq_printf(seq, "state: unsupported\n");
- }
- else{
- seq_printf(seq, "state: %s\n", (state ? "open" : "closed"));
- }
-
- return_VALUE(0);
-}
-
-static int acpi_button_state_open_fs(struct inode *inode, struct file *file)
-{
- return single_open(file, acpi_button_state_seq_show, PDE(inode)->data);
-}
-
-static int
-acpi_button_add_fs (
- struct acpi_device *device)
-{
- struct proc_dir_entry *entry = NULL;
- struct acpi_button *button = NULL;
-
- ACPI_FUNCTION_TRACE("acpi_button_add_fs");
-
- if (!device || !acpi_driver_data(device))
- return_VALUE(-EINVAL);
-
- button = acpi_driver_data(device);
-
- switch (button->type) {
- case ACPI_BUTTON_TYPE_POWER:
- case ACPI_BUTTON_TYPE_POWERF:
- entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
- acpi_button_dir);
- break;
- case ACPI_BUTTON_TYPE_SLEEP:
- case ACPI_BUTTON_TYPE_SLEEPF:
- entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
- acpi_button_dir);
- break;
- case ACPI_BUTTON_TYPE_LID:
- entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
- acpi_button_dir);
- break;
- }
-
- if (!entry)
- return_VALUE(-ENODEV);
- entry->owner = THIS_MODULE;
-
- acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
- if (!acpi_device_dir(device))
- return_VALUE(-ENODEV);
- acpi_device_dir(device)->owner = THIS_MODULE;
-
- /* 'info' [R] */
- entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BUTTON_FILE_INFO));
- else {
- entry->proc_fops = &acpi_button_info_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
-
- /* show lid state [R] */
- if (button->type == ACPI_BUTTON_TYPE_LID) {
- entry = create_proc_entry(ACPI_BUTTON_FILE_STATE,
- S_IRUGO, acpi_device_dir(device));
- if (!entry)
- ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
- "Unable to create '%s' fs entry\n",
- ACPI_BUTTON_FILE_INFO));
- else {
- entry->proc_fops = &acpi_button_state_fops;
- entry->data = acpi_driver_data(device);
- entry->owner = THIS_MODULE;
- }
- }
-
- return_VALUE(0);
-}
-
-
-static int
-acpi_button_remove_fs (
- struct acpi_device *device)
-{
- struct acpi_button *button = NULL;
-
- ACPI_FUNCTION_TRACE("acpi_button_remove_fs");
-
- button = acpi_driver_data(device);
- if (acpi_device_dir(device)) {
- if (button->type == ACPI_BUTTON_TYPE_LID)
- remove_proc_entry(ACPI_BUTTON_FILE_STATE,
- acpi_device_dir(device));
- remove_proc_entry(ACPI_BUTTON_FILE_INFO,
- acpi_device_dir(device));
-
- remove_proc_entry(acpi_device_bid(device),
- acpi_device_dir(device)->parent);
-
-
- switch (button->type) {
- case ACPI_BUTTON_TYPE_POWER:
- case ACPI_BUTTON_TYPE_POWERF:
- remove_proc_entry(ACPI_BUTTON_SUBCLASS_POWER,
- acpi_button_dir);
- break;
- case ACPI_BUTTON_TYPE_SLEEP:
- case ACPI_BUTTON_TYPE_SLEEPF:
- remove_proc_entry(ACPI_BUTTON_SUBCLASS_SLEEP,
- acpi_button_dir);
- break;
- case ACPI_BUTTON_TYPE_LID:
- remove_proc_entry(ACPI_BUTTON_SUBCLASS_LID,
- acpi_button_dir);
- break;
- }
- acpi_device_dir(device) = NULL;
- }
-
- return_VALUE(0);
-}
-
-
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
@@ -310,8 +121,7 @@ acpi_button_notify_fixed (
ACPI_FUNCTION_TRACE("acpi_button_notify_fixed");
- if (!button)
- return_ACPI_STATUS(AE_BAD_PARAMETER);
+ BUG_ON(!button);
acpi_button_notify(button->handle, ACPI_BUTTON_NOTIFY_STATUS, button);
@@ -327,10 +137,6 @@ acpi_button_add (
acpi_status status = AE_OK;
struct acpi_button *button = NULL;
- static struct acpi_device *power_button;
- static struct acpi_device *sleep_button;
- static struct acpi_device *lid_button;
-
ACPI_FUNCTION_TRACE("acpi_button_add");
if (!device)
@@ -391,42 +197,6 @@ acpi_button_add (
goto end;
}
- /*
- * Ensure only one button of each type is used.
- */
- switch (button->type) {
- case ACPI_BUTTON_TYPE_POWER:
- case ACPI_BUTTON_TYPE_POWERF:
- if (!power_button)
- power_button = device;
- else {
- kfree(button);
- return_VALUE(-ENODEV);
- }
- break;
- case ACPI_BUTTON_TYPE_SLEEP:
- case ACPI_BUTTON_TYPE_SLEEPF:
- if (!sleep_button)
- sleep_button = device;
- else {
- kfree(button);
- return_VALUE(-ENODEV);
- }
- break;
- case ACPI_BUTTON_TYPE_LID:
- if (!lid_button)
- lid_button = device;
- else {
- kfree(button);
- return_VALUE(-ENODEV);
- }
- break;
- }
-
- result = acpi_button_add_fs(device);
- if (result)
- goto end;
-
switch (button->type) {
case ACPI_BUTTON_TYPE_POWERF:
status = acpi_install_fixed_event_handler (
@@ -470,7 +240,6 @@ acpi_button_add (
end:
if (result) {
- acpi_button_remove_fs(device);
kfree(button);
}
@@ -511,8 +280,6 @@ acpi_button_remove (struct acpi_device *device, int type)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error removing notify handler\n"));
- acpi_button_remove_fs(device);
-
kfree(button);
return_VALUE(0);
@@ -526,21 +293,14 @@ acpi_button_init (void)
ACPI_FUNCTION_TRACE("acpi_button_init");
- acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
- if (!acpi_button_dir)
- return_VALUE(-ENODEV);
- acpi_button_dir->owner = THIS_MODULE;
-
result = acpi_bus_register_driver(&acpi_button_driver);
if (result < 0) {
- remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
-
static void __exit
acpi_button_exit (void)
{
@@ -548,11 +308,8 @@ acpi_button_exit (void)
acpi_bus_unregister_driver(&acpi_button_driver);
- remove_proc_entry(ACPI_BUTTON_CLASS, acpi_root_dir);
-
return_VOID;
}
-
module_init(acpi_button_init);
module_exit(acpi_button_exit);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index 5a0adbf8bc04..97013ddfa202 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle)
return_VALUE(-ENODEV);
}
- result = acpi_bus_scan(*device);
+ result = acpi_bus_start(*device);
return_VALUE(result);
}
diff --git a/drivers/acpi/dispatcher/dsfield.c b/drivers/acpi/dispatcher/dsfield.c
index 2779211be756..84193983d6ba 100644
--- a/drivers/acpi/dispatcher/dsfield.c
+++ b/drivers/acpi/dispatcher/dsfield.c
@@ -53,13 +53,20 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsfield")
+/* Local prototypes */
+
+static acpi_status
+acpi_ds_get_field_names (
+ struct acpi_create_field_info *info,
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *arg);
+
/*******************************************************************************
*
* FUNCTION: acpi_ds_create_buffer_field
*
- * PARAMETERS: Opcode - The opcode to be executed
- * Operands - List of operands for the opcode
+ * PARAMETERS: Op - Current parse op (create_xXField)
* walk_state - Current state
*
* RETURN: Status
@@ -70,7 +77,7 @@
* create_word_field_op,
* create_dword_field_op,
* create_qword_field_op,
- * create_field_op (all of which define fields in buffers)
+ * create_field_op (all of which define a field in a buffer)
*
******************************************************************************/
@@ -119,7 +126,8 @@ acpi_ds_create_buffer_field (
flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE;
}
else {
- flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND;
+ flags = ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND;
}
/*
@@ -134,16 +142,16 @@ acpi_ds_create_buffer_field (
}
}
- /* We could put the returned object (Node) on the object stack for later, but
- * for now, we will put it in the "op" object that the parser uses, so we
- * can get it again at the end of this scope
+ /* We could put the returned object (Node) on the object stack for later,
+ * but for now, we will put it in the "op" object that the parser uses,
+ * so we can get it again at the end of this scope
*/
op->common.node = node;
/*
- * If there is no object attached to the node, this node was just created and
- * we need to create the field object. Otherwise, this was a lookup of an
- * existing node and we don't want to create the field object again.
+ * If there is no object attached to the node, this node was just created
+ * and we need to create the field object. Otherwise, this was a lookup
+ * of an existing node and we don't want to create the field object again.
*/
obj_desc = acpi_ns_get_attached_object (node);
if (obj_desc) {
@@ -205,7 +213,7 @@ cleanup:
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_get_field_names (
struct acpi_create_field_info *info,
struct acpi_walk_state *walk_state,
@@ -238,7 +246,8 @@ acpi_ds_get_field_names (
+ (acpi_integer) arg->common.value.size;
if (position > ACPI_UINT32_MAX) {
- ACPI_REPORT_ERROR (("Bit offset within field too large (> 0xFFFFFFFF)\n"));
+ ACPI_REPORT_ERROR ((
+ "Bit offset within field too large (> 0xFFFFFFFF)\n"));
return_ACPI_STATUS (AE_SUPPORT);
}
@@ -250,12 +259,15 @@ acpi_ds_get_field_names (
/*
* Get a new access_type and access_attribute -- to be used for all
- * field units that follow, until field end or another access_as keyword.
+ * field units that follow, until field end or another access_as
+ * keyword.
*
- * In field_flags, preserve the flag bits other than the ACCESS_TYPE bits
+ * In field_flags, preserve the flag bits other than the
+ * ACCESS_TYPE bits
*/
- info->field_flags = (u8) ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
- ((u8) ((u32) arg->common.value.integer >> 8)));
+ info->field_flags = (u8)
+ ((info->field_flags & ~(AML_FIELD_ACCESS_TYPE_MASK)) |
+ ((u8) ((u32) arg->common.value.integer >> 8)));
info->attribute = (u8) (arg->common.value.integer);
break;
@@ -267,7 +279,8 @@ acpi_ds_get_field_names (
status = acpi_ns_lookup (walk_state->scope_info,
(char *) &arg->named.name,
- info->field_type, ACPI_IMODE_EXECUTE, ACPI_NS_DONT_OPEN_SCOPE,
+ info->field_type, ACPI_IMODE_EXECUTE,
+ ACPI_NS_DONT_OPEN_SCOPE,
walk_state, &info->field_node);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
@@ -295,8 +308,9 @@ acpi_ds_get_field_names (
+ (acpi_integer) arg->common.value.size;
if (position > ACPI_UINT32_MAX) {
- ACPI_REPORT_ERROR (("Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n",
- (char *) &info->field_node->name));
+ ACPI_REPORT_ERROR ((
+ "Field [%4.4s] bit offset too large (> 0xFFFFFFFF)\n",
+ (char *) &info->field_node->name));
return_ACPI_STATUS (AE_SUPPORT);
}
@@ -306,7 +320,8 @@ acpi_ds_get_field_names (
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid opcode in field list: %X\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid opcode in field list: %X\n",
arg->common.aml_opcode));
return_ACPI_STATUS (AE_AML_BAD_OPCODE);
}
@@ -435,7 +450,8 @@ acpi_ds_init_field_objects (
status = acpi_ns_lookup (walk_state->scope_info,
(char *) &arg->named.name,
type, ACPI_IMODE_LOAD_PASS1,
- ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE | ACPI_NS_ERROR_IF_FOUND,
+ ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE |
+ ACPI_NS_ERROR_IF_FOUND,
walk_state, &node);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_NSERROR ((char *) &arg->named.name, status);
diff --git a/drivers/acpi/dispatcher/dsinit.c b/drivers/acpi/dispatcher/dsinit.c
index b4d264dbbf67..d7790db50178 100644
--- a/drivers/acpi/dispatcher/dsinit.c
+++ b/drivers/acpi/dispatcher/dsinit.c
@@ -49,12 +49,21 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsinit")
+/* Local prototypes */
+
+static acpi_status
+acpi_ds_init_one_object (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
/*******************************************************************************
*
* FUNCTION: acpi_ds_init_one_object
*
- * PARAMETERS: obj_handle - Node
+ * PARAMETERS: obj_handle - Node for the object
* Level - Current nesting level
* Context - Points to a init info struct
* return_value - Not used
@@ -70,7 +79,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_init_one_object (
acpi_handle obj_handle,
u32 level,
@@ -105,7 +114,8 @@ acpi_ds_init_one_object (
status = acpi_ds_initialize_region (obj_handle);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Region %p [%4.4s] - Init failure, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Region %p [%4.4s] - Init failure, %s\n",
obj_handle, acpi_ut_get_node_name (obj_handle),
acpi_format_exception (status)));
}
@@ -118,8 +128,10 @@ acpi_ds_init_one_object (
info->method_count++;
- /* Print a dot for each method unless we are going to print the entire pathname */
-
+ /*
+ * Print a dot for each method unless we are going to print
+ * the entire pathname
+ */
if (!(acpi_dbg_level & ACPI_LV_INIT_NAMES)) {
ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INIT, "."));
}
@@ -140,7 +152,8 @@ acpi_ds_init_one_object (
*/
status = acpi_ds_parse_method (obj_handle);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Method %p [%4.4s] - parse failure, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Method %p [%4.4s] - parse failure, %s\n",
obj_handle, acpi_ut_get_node_name (obj_handle),
acpi_format_exception (status)));
@@ -154,7 +167,8 @@ acpi_ds_init_one_object (
* for every execution since there isn't much overhead
*/
acpi_ns_delete_namespace_subtree (obj_handle);
- acpi_ns_delete_namespace_by_owner (((struct acpi_namespace_node *) obj_handle)->object->method.owning_id);
+ acpi_ns_delete_namespace_by_owner (
+ ((struct acpi_namespace_node *) obj_handle)->object->method.owning_id);
break;
diff --git a/drivers/acpi/dispatcher/dsmethod.c b/drivers/acpi/dispatcher/dsmethod.c
index 9f0456cb9bb5..9fc3f4c033eb 100644
--- a/drivers/acpi/dispatcher/dsmethod.c
+++ b/drivers/acpi/dispatcher/dsmethod.c
@@ -153,12 +153,11 @@ acpi_ds_parse_method (
/*
* Parse the method, first pass
*
- * The first pass load is where newly declared named objects are
- * added into the namespace. Actual evaluation of
- * the named objects (what would be called a "second
- * pass") happens during the actual execution of the
- * method so that operands to the named objects can
- * take on dynamic run-time values.
+ * The first pass load is where newly declared named objects are added into
+ * the namespace. Actual evaluation of the named objects (what would be
+ * called a "second pass") happens during the actual execution of the
+ * method so that operands to the named objects can take on dynamic
+ * run-time values.
*/
status = acpi_ps_parse_aml (walk_state);
if (ACPI_FAILURE (status)) {
diff --git a/drivers/acpi/dispatcher/dsmthdat.c b/drivers/acpi/dispatcher/dsmthdat.c
index f31d095f9833..f7998306f756 100644
--- a/drivers/acpi/dispatcher/dsmthdat.c
+++ b/drivers/acpi/dispatcher/dsmthdat.c
@@ -52,6 +52,29 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsmthdat")
+/* Local prototypes */
+
+static void
+acpi_ds_method_data_delete_value (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state);
+
+static acpi_status
+acpi_ds_method_data_set_value (
+ u16 opcode,
+ u32 index,
+ union acpi_operand_object *object,
+ struct acpi_walk_state *walk_state);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_object_type
+acpi_ds_method_data_get_type (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state);
+#endif
+
/*******************************************************************************
*
@@ -62,8 +85,8 @@
* RETURN: Status
*
* DESCRIPTION: Initialize the data structures that hold the method's arguments
- * and locals. The data struct is an array of NTEs for each.
- * This allows ref_of and de_ref_of to work properly for these
+ * and locals. The data struct is an array of namespace nodes for
+ * each - this allows ref_of and de_ref_of to work properly for these
* special data types.
*
* NOTES: walk_state fields are initialized to zero by the
@@ -92,7 +115,8 @@ acpi_ds_method_data_init (
walk_state->arguments[i].name.integer |= (i << 24);
walk_state->arguments[i].descriptor = ACPI_DESC_TYPE_NAMED;
walk_state->arguments[i].type = ACPI_TYPE_ANY;
- walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_ARG;
+ walk_state->arguments[i].flags = ANOBJ_END_OF_PEER_LIST |
+ ANOBJ_METHOD_ARG;
}
/* Init the method locals */
@@ -104,7 +128,8 @@ acpi_ds_method_data_init (
walk_state->local_variables[i].name.integer |= (i << 24);
walk_state->local_variables[i].descriptor = ACPI_DESC_TYPE_NAMED;
walk_state->local_variables[i].type = ACPI_TYPE_ANY;
- walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST | ANOBJ_METHOD_LOCAL;
+ walk_state->local_variables[i].flags = ANOBJ_END_OF_PEER_LIST |
+ ANOBJ_METHOD_LOCAL;
}
return_VOID;
@@ -198,15 +223,18 @@ acpi_ds_method_data_init_args (
return_ACPI_STATUS (AE_OK);
}
- /* Copy passed parameters into the new method stack frame */
+ /* Copy passed parameters into the new method stack frame */
- while ((index < ACPI_METHOD_NUM_ARGS) && (index < max_param_count) && params[index]) {
+ while ((index < ACPI_METHOD_NUM_ARGS) &&
+ (index < max_param_count) &&
+ params[index]) {
/*
* A valid parameter.
* Store the argument in the method/walk descriptor.
* Do not copy the arg in order to implement call by reference
*/
- status = acpi_ds_method_data_set_value (AML_ARG_OP, index, params[index], walk_state);
+ status = acpi_ds_method_data_set_value (AML_ARG_OP, index,
+ params[index], walk_state);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -224,11 +252,13 @@ acpi_ds_method_data_init_args (
* FUNCTION: acpi_ds_method_data_get_node
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument whose type
- * to get
+ * Index - Which Local or Arg whose type to get
* walk_state - Current walk state object
+ * Node - Where the node is returned.
*
- * RETURN: Get the Node associated with a local or arg.
+ * RETURN: Status and node
+ *
+ * DESCRIPTION: Get the Node associated with a local or arg.
*
******************************************************************************/
@@ -249,7 +279,8 @@ acpi_ds_method_data_get_node (
case AML_LOCAL_OP:
if (index > ACPI_METHOD_MAX_LOCAL) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Local index %d is invalid (max %d)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Local index %d is invalid (max %d)\n",
index, ACPI_METHOD_MAX_LOCAL));
return_ACPI_STATUS (AE_AML_INVALID_INDEX);
}
@@ -262,7 +293,8 @@ acpi_ds_method_data_get_node (
case AML_ARG_OP:
if (index > ACPI_METHOD_MAX_ARG) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Arg index %d is invalid (max %d)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Arg index %d is invalid (max %d)\n",
index, ACPI_METHOD_MAX_ARG));
return_ACPI_STATUS (AE_AML_INVALID_INDEX);
}
@@ -286,7 +318,7 @@ acpi_ds_method_data_get_node (
* FUNCTION: acpi_ds_method_data_set_value
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument to get
+ * Index - Which Local or Arg to get
* Object - Object to be inserted into the stack entry
* walk_state - Current walk state object
*
@@ -297,7 +329,7 @@ acpi_ds_method_data_get_node (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_method_data_set_value (
u16 opcode,
u32 index,
@@ -340,68 +372,16 @@ acpi_ds_method_data_set_value (
/*******************************************************************************
*
- * FUNCTION: acpi_ds_method_data_get_type
- *
- * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument whose type
- * to get
- * walk_state - Current walk state object
- *
- * RETURN: Data type of current value of the selected Arg or Local
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-acpi_object_type
-acpi_ds_method_data_get_type (
- u16 opcode,
- u32 index,
- struct acpi_walk_state *walk_state)
-{
- acpi_status status;
- struct acpi_namespace_node *node;
- union acpi_operand_object *object;
-
-
- ACPI_FUNCTION_TRACE ("ds_method_data_get_type");
-
-
- /* Get the namespace node for the arg/local */
-
- status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
- if (ACPI_FAILURE (status)) {
- return_VALUE ((ACPI_TYPE_NOT_FOUND));
- }
-
- /* Get the object */
-
- object = acpi_ns_get_attached_object (node);
- if (!object) {
- /* Uninitialized local/arg, return TYPE_ANY */
-
- return_VALUE (ACPI_TYPE_ANY);
- }
-
- /* Get the object type */
-
- return_VALUE (ACPI_GET_OBJECT_TYPE (object));
-}
-#endif /* ACPI_FUTURE_USAGE */
-
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ds_method_data_get_value
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
* Index - which local_var or argument to get
* walk_state - Current walk state object
- * *dest_desc - Ptr to Descriptor into which selected Arg
- * or Local value should be copied
+ * dest_desc - Where Arg or Local value is returned
*
* RETURN: Status
*
- * DESCRIPTION: Retrieve value of selected Arg or Local from the method frame
- * at the current top of the method stack.
+ * DESCRIPTION: Retrieve value of selected Arg or Local for this method
* Used only in acpi_ex_resolve_to_value().
*
******************************************************************************/
@@ -467,14 +447,16 @@ acpi_ds_method_data_get_value (
else switch (opcode) {
case AML_ARG_OP:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Arg[%d] at node %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Uninitialized Arg[%d] at node %p\n",
index, node));
return_ACPI_STATUS (AE_AML_UNINITIALIZED_ARG);
case AML_LOCAL_OP:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Uninitialized Local[%d] at node %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Uninitialized Local[%d] at node %p\n",
index, node));
return_ACPI_STATUS (AE_AML_UNINITIALIZED_LOCAL);
@@ -506,12 +488,12 @@ acpi_ds_method_data_get_value (
*
* RETURN: None
*
- * DESCRIPTION: Delete the entry at Opcode:Index on the method stack. Inserts
+ * DESCRIPTION: Delete the entry at Opcode:Index. Inserts
* a null into the stack slot after the object is deleted.
*
******************************************************************************/
-void
+static void
acpi_ds_method_data_delete_value (
u16 opcode,
u32 index,
@@ -562,7 +544,7 @@ acpi_ds_method_data_delete_value (
* FUNCTION: acpi_ds_store_object_to_local
*
* PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
- * Index - which local_var or argument to set
+ * Index - Which Local or Arg to set
* obj_desc - Value to be stored
* walk_state - Current walk state
*
@@ -651,19 +633,20 @@ acpi_ds_store_object_to_local (
*/
if (opcode == AML_ARG_OP) {
/*
- * Make sure that the object is the correct type. This may be overkill, but
- * it is here because references were NS nodes in the past. Now they are
- * operand objects of type Reference.
+ * Make sure that the object is the correct type. This may be
+ * overkill, butit is here because references were NS nodes in
+ * the past. Now they are operand objects of type Reference.
*/
if (ACPI_GET_DESCRIPTOR_TYPE (current_obj_desc) != ACPI_DESC_TYPE_OPERAND) {
- ACPI_REPORT_ERROR (("Invalid descriptor type while storing to method arg: [%s]\n",
- acpi_ut_get_descriptor_name (current_obj_desc)));
+ ACPI_REPORT_ERROR ((
+ "Invalid descriptor type while storing to method arg: [%s]\n",
+ acpi_ut_get_descriptor_name (current_obj_desc)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
/*
- * If we have a valid reference object that came from ref_of(), do the
- * indirect store
+ * If we have a valid reference object that came from ref_of(),
+ * do the indirect store
*/
if ((current_obj_desc->common.type == ACPI_TYPE_LOCAL_REFERENCE) &&
(current_obj_desc->reference.opcode == AML_REF_OF_OP)) {
@@ -713,3 +696,55 @@ acpi_ds_store_object_to_local (
}
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_method_data_get_type
+ *
+ * PARAMETERS: Opcode - Either AML_LOCAL_OP or AML_ARG_OP
+ * Index - Which Local or Arg whose type to get
+ * walk_state - Current walk state object
+ *
+ * RETURN: Data type of current value of the selected Arg or Local
+ *
+ * DESCRIPTION: Get the type of the object stored in the Local or Arg
+ *
+ ******************************************************************************/
+
+acpi_object_type
+acpi_ds_method_data_get_type (
+ u16 opcode,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ acpi_status status;
+ struct acpi_namespace_node *node;
+ union acpi_operand_object *object;
+
+
+ ACPI_FUNCTION_TRACE ("ds_method_data_get_type");
+
+
+ /* Get the namespace node for the arg/local */
+
+ status = acpi_ds_method_data_get_node (opcode, index, walk_state, &node);
+ if (ACPI_FAILURE (status)) {
+ return_VALUE ((ACPI_TYPE_NOT_FOUND));
+ }
+
+ /* Get the object */
+
+ object = acpi_ns_get_attached_object (node);
+ if (!object) {
+ /* Uninitialized local/arg, return TYPE_ANY */
+
+ return_VALUE (ACPI_TYPE_ANY);
+ }
+
+ /* Get the object type */
+
+ return_VALUE (ACPI_GET_OBJECT_TYPE (object));
+}
+#endif
+
+
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c
index eb8af4785bcb..bfbae4e4c667 100644
--- a/drivers/acpi/dispatcher/dsobject.c
+++ b/drivers/acpi/dispatcher/dsobject.c
@@ -52,9 +52,15 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsobject")
+static acpi_status
+acpi_ds_build_internal_object (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ union acpi_operand_object **obj_desc_ptr);
+
#ifndef ACPI_NO_METHOD_EXECUTION
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_build_internal_object
*
@@ -67,9 +73,9 @@
* DESCRIPTION: Translate a parser Op object to the equivalent namespace object
* Simple objects are any objects other than a package object!
*
- ****************************************************************************/
+ ******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_build_internal_object (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
@@ -90,9 +96,11 @@ acpi_ds_build_internal_object (
* Otherwise, go ahead and look it up now
*/
if (!op->common.node) {
- status = acpi_ns_lookup (walk_state->scope_info, op->common.value.string,
+ status = acpi_ns_lookup (walk_state->scope_info,
+ op->common.value.string,
ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL,
(struct acpi_namespace_node **) &(op->common.node));
if (ACPI_FAILURE (status)) {
@@ -104,12 +112,14 @@ acpi_ds_build_internal_object (
/* Create and init the internal ACPI object */
- obj_desc = acpi_ut_create_internal_object ((acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type);
+ obj_desc = acpi_ut_create_internal_object (
+ (acpi_ps_get_opcode_info (op->common.aml_opcode))->object_type);
if (!obj_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
- status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode, &obj_desc);
+ status = acpi_ds_init_object_from_op (walk_state, op, op->common.aml_opcode,
+ &obj_desc);
if (ACPI_FAILURE (status)) {
acpi_ut_remove_reference (obj_desc);
return_ACPI_STATUS (status);
@@ -120,7 +130,7 @@ acpi_ds_build_internal_object (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_build_internal_buffer_obj
*
@@ -134,7 +144,7 @@ acpi_ds_build_internal_object (
* DESCRIPTION: Translate a parser Op package object to the equivalent
* namespace object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_build_internal_buffer_obj (
@@ -229,7 +239,7 @@ acpi_ds_build_internal_buffer_obj (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_build_internal_package_obj
*
@@ -243,7 +253,7 @@ acpi_ds_build_internal_buffer_obj (
* DESCRIPTION: Translate a parser Op package object to the equivalent
* namespace object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_build_internal_package_obj (
@@ -331,11 +341,12 @@ acpi_ds_build_internal_package_obj (
if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
/* Object (package or buffer) is already built */
- obj_desc->package.elements[i] = ACPI_CAST_PTR (union acpi_operand_object, arg->common.node);
+ obj_desc->package.elements[i] =
+ ACPI_CAST_PTR (union acpi_operand_object, arg->common.node);
}
else {
status = acpi_ds_build_internal_object (walk_state, arg,
- &obj_desc->package.elements[i]);
+ &obj_desc->package.elements[i]);
}
i++;
@@ -348,7 +359,7 @@ acpi_ds_build_internal_package_obj (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_create_node
*
@@ -360,7 +371,7 @@ acpi_ds_build_internal_package_obj (
*
* DESCRIPTION: Create the object to be associated with a namespace node
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_create_node (
@@ -392,7 +403,8 @@ acpi_ds_create_node (
/* Build an internal object for the argument(s) */
- status = acpi_ds_build_internal_object (walk_state, op->common.value.arg, &obj_desc);
+ status = acpi_ds_build_internal_object (walk_state, op->common.value.arg,
+ &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -414,7 +426,7 @@ acpi_ds_create_node (
#endif /* ACPI_NO_METHOD_EXECUTION */
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_init_object_from_op
*
@@ -429,7 +441,7 @@ acpi_ds_create_node (
* associated arguments. The namespace object is a more compact
* representation of the Op and its arguments.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_init_object_from_op (
@@ -462,7 +474,8 @@ acpi_ds_init_object_from_op (
/*
* Defer evaluation of Buffer term_arg operand
*/
- obj_desc->buffer.node = (struct acpi_namespace_node *) walk_state->operands[0];
+ obj_desc->buffer.node = (struct acpi_namespace_node *)
+ walk_state->operands[0];
obj_desc->buffer.aml_start = op->named.data;
obj_desc->buffer.aml_length = op->named.length;
break;
@@ -473,7 +486,8 @@ acpi_ds_init_object_from_op (
/*
* Defer evaluation of Package term_arg operand
*/
- obj_desc->package.node = (struct acpi_namespace_node *) walk_state->operands[0];
+ obj_desc->package.node = (struct acpi_namespace_node *)
+ walk_state->operands[0];
obj_desc->package.aml_start = op->named.data;
obj_desc->package.aml_length = op->named.length;
break;
@@ -486,9 +500,10 @@ acpi_ds_init_object_from_op (
/*
* Resolve AML Constants here - AND ONLY HERE!
* All constants are integers.
- * We mark the integer with a flag that indicates that it started life
- * as a constant -- so that stores to constants will perform as expected (noop).
- * (zero_op is used as a placeholder for optional target operands.)
+ * We mark the integer with a flag that indicates that it started
+ * life as a constant -- so that stores to constants will perform
+ * as expected (noop). zero_op is used as a placeholder for optional
+ * target operands.
*/
obj_desc->common.flags = AOPOBJ_AML_CONSTANT;
@@ -521,7 +536,8 @@ acpi_ds_init_object_from_op (
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown constant opcode %X\n", opcode));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown constant opcode %X\n", opcode));
status = AE_AML_OPERAND_TYPE;
break;
}
@@ -535,7 +551,8 @@ acpi_ds_init_object_from_op (
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n", op_info->type));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Integer type %X\n",
+ op_info->type));
status = AE_AML_OPERAND_TYPE;
break;
}
@@ -570,8 +587,10 @@ acpi_ds_init_object_from_op (
obj_desc->reference.offset = opcode - AML_LOCAL_OP;
#ifndef ACPI_NO_METHOD_EXECUTION
- status = acpi_ds_method_data_get_node (AML_LOCAL_OP, obj_desc->reference.offset,
- walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object);
+ status = acpi_ds_method_data_get_node (AML_LOCAL_OP,
+ obj_desc->reference.offset,
+ walk_state,
+ (struct acpi_namespace_node **) &obj_desc->reference.object);
#endif
break;
@@ -584,8 +603,10 @@ acpi_ds_init_object_from_op (
obj_desc->reference.offset = opcode - AML_ARG_OP;
#ifndef ACPI_NO_METHOD_EXECUTION
- status = acpi_ds_method_data_get_node (AML_ARG_OP, obj_desc->reference.offset,
- walk_state, (struct acpi_namespace_node **) &obj_desc->reference.object);
+ status = acpi_ds_method_data_get_node (AML_ARG_OP,
+ obj_desc->reference.offset,
+ walk_state,
+ (struct acpi_namespace_node **) &obj_desc->reference.object);
#endif
break;
diff --git a/drivers/acpi/dispatcher/dsopcode.c b/drivers/acpi/dispatcher/dsopcode.c
index 5c987a0e7b75..ba13bca28bee 100644
--- a/drivers/acpi/dispatcher/dsopcode.c
+++ b/drivers/acpi/dispatcher/dsopcode.c
@@ -54,12 +54,31 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dsopcode")
+/* Local prototypes */
-/*****************************************************************************
+static acpi_status
+acpi_ds_execute_arguments (
+ struct acpi_namespace_node *node,
+ struct acpi_namespace_node *scope_node,
+ u32 aml_length,
+ u8 *aml_start);
+
+static acpi_status
+acpi_ds_init_buffer_field (
+ u16 aml_opcode,
+ union acpi_operand_object *obj_desc,
+ union acpi_operand_object *buffer_desc,
+ union acpi_operand_object *offset_desc,
+ union acpi_operand_object *length_desc,
+ union acpi_operand_object *result_desc);
+
+
+/*******************************************************************************
*
* FUNCTION: acpi_ds_execute_arguments
*
- * PARAMETERS: Node - Parent NS node
+ * PARAMETERS: Node - Object NS node
+ * scope_node - Parent NS node
* aml_length - Length of executable AML
* aml_start - Pointer to the AML
*
@@ -67,9 +86,9 @@
*
* DESCRIPTION: Late (deferred) execution of region or field arguments
*
- ****************************************************************************/
+ ******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_execute_arguments (
struct acpi_namespace_node *node,
struct acpi_namespace_node *scope_node,
@@ -162,7 +181,7 @@ acpi_ds_execute_arguments (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_get_buffer_field_arguments
*
@@ -173,7 +192,7 @@ acpi_ds_execute_arguments (
* DESCRIPTION: Get buffer_field Buffer and Index. This implements the late
* evaluation of these field attributes.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_get_buffer_field_arguments (
@@ -208,7 +227,7 @@ acpi_ds_get_buffer_field_arguments (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_get_buffer_arguments
*
@@ -219,7 +238,7 @@ acpi_ds_get_buffer_field_arguments (
* DESCRIPTION: Get Buffer length and initializer byte list. This implements
* the late evaluation of these attributes.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_get_buffer_arguments (
@@ -255,7 +274,7 @@ acpi_ds_get_buffer_arguments (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_get_package_arguments
*
@@ -266,7 +285,7 @@ acpi_ds_get_buffer_arguments (
* DESCRIPTION: Get Package length and initializer byte list. This implements
* the late evaluation of these attributes.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_get_package_arguments (
@@ -353,17 +372,17 @@ acpi_ds_get_region_arguments (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_initialize_region
*
- * PARAMETERS: Op - A valid region Op object
+ * PARAMETERS: obj_handle - Region namespace node
*
* RETURN: Status
*
* DESCRIPTION: Front end to ev_initialize_region
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_initialize_region (
@@ -382,7 +401,7 @@ acpi_ds_initialize_region (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_init_buffer_field
*
@@ -390,16 +409,16 @@ acpi_ds_initialize_region (
* obj_desc - buffer_field object
* buffer_desc - Host Buffer
* offset_desc - Offset into buffer
- * Length - Length of field (CREATE_FIELD_OP only)
- * Result - Where to store the result
+ * length_desc - Length of field (CREATE_FIELD_OP only)
+ * result_desc - Where to store the result
*
* RETURN: Status
*
* DESCRIPTION: Perform actual initialization of a buffer field
*
- ****************************************************************************/
+ ******************************************************************************/
-acpi_status
+static acpi_status
acpi_ds_init_buffer_field (
u16 aml_opcode,
union acpi_operand_object *obj_desc,
@@ -435,8 +454,10 @@ acpi_ds_init_buffer_field (
* after resolution in acpi_ex_resolve_operands().
*/
if (ACPI_GET_DESCRIPTOR_TYPE (result_desc) != ACPI_DESC_TYPE_NAMED) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "(%s) destination not a NS Node [%s]\n",
- acpi_ps_get_opcode_name (aml_opcode), acpi_ut_get_descriptor_name (result_desc)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "(%s) destination not a NS Node [%s]\n",
+ acpi_ps_get_opcode_name (aml_opcode),
+ acpi_ut_get_descriptor_name (result_desc)));
status = AE_AML_OPERAND_TYPE;
goto cleanup;
@@ -452,9 +473,18 @@ acpi_ds_init_buffer_field (
/* Offset is in bits, count is in bits */
+ field_flags = AML_FIELD_ACCESS_BYTE;
bit_offset = offset;
bit_count = (u32) length_desc->integer.value;
- field_flags = AML_FIELD_ACCESS_BYTE;
+
+ /* Must have a valid (>0) bit count */
+
+ if (bit_count == 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Attempt to create_field of length 0\n"));
+ status = AE_AML_OPERAND_VALUE;
+ goto cleanup;
+ }
break;
case AML_CREATE_BIT_FIELD_OP:
@@ -527,7 +557,8 @@ acpi_ds_init_buffer_field (
/*
* Initialize areas of the field object that are common to all fields
- * For field_flags, use LOCK_RULE = 0 (NO_LOCK), UPDATE_RULE = 0 (UPDATE_PRESERVE)
+ * For field_flags, use LOCK_RULE = 0 (NO_LOCK),
+ * UPDATE_RULE = 0 (UPDATE_PRESERVE)
*/
status = acpi_ex_prep_common_field_object (obj_desc, field_flags, 0,
bit_offset, bit_count);
@@ -539,8 +570,8 @@ acpi_ds_init_buffer_field (
/* Reference count for buffer_desc inherits obj_desc count */
- buffer_desc->common.reference_count = (u16) (buffer_desc->common.reference_count +
- obj_desc->common.reference_count);
+ buffer_desc->common.reference_count = (u16)
+ (buffer_desc->common.reference_count + obj_desc->common.reference_count);
cleanup:
@@ -569,7 +600,7 @@ cleanup:
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_eval_buffer_field_operands
*
@@ -581,7 +612,7 @@ cleanup:
* DESCRIPTION: Get buffer_field Buffer and Index
* Called from acpi_ds_exec_end_op during buffer_field parse tree walk
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_eval_buffer_field_operands (
@@ -656,7 +687,7 @@ acpi_ds_eval_buffer_field_operands (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_eval_region_operands
*
@@ -668,7 +699,7 @@ acpi_ds_eval_buffer_field_operands (
* DESCRIPTION: Get region address and length
* Called from acpi_ds_exec_end_op during op_region parse tree walk
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_eval_region_operands (
@@ -686,7 +717,8 @@ acpi_ds_eval_region_operands (
/*
- * This is where we evaluate the address and length fields of the op_region declaration
+ * This is where we evaluate the address and length fields of the
+ * op_region declaration
*/
node = op->common.node;
@@ -707,7 +739,8 @@ acpi_ds_eval_region_operands (
/* Resolve the length and address operands to numbers */
- status = acpi_ex_resolve_operands (op->common.aml_opcode, ACPI_WALK_OPERANDS, walk_state);
+ status = acpi_ex_resolve_operands (op->common.aml_opcode,
+ ACPI_WALK_OPERANDS, walk_state);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -736,7 +769,8 @@ acpi_ds_eval_region_operands (
*/
operand_desc = walk_state->operands[walk_state->num_operands - 2];
- obj_desc->region.address = (acpi_physical_address) operand_desc->integer.value;
+ obj_desc->region.address = (acpi_physical_address)
+ operand_desc->integer.value;
acpi_ut_remove_reference (operand_desc);
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "rgn_obj %p Addr %8.8X%8.8X Len %X\n",
@@ -752,7 +786,7 @@ acpi_ds_eval_region_operands (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ds_eval_data_object_operands
*
@@ -765,7 +799,7 @@ acpi_ds_eval_region_operands (
* DESCRIPTION: Get the operands and complete the following data object types:
* Buffer, Package.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ds_eval_data_object_operands (
@@ -830,7 +864,7 @@ acpi_ds_eval_data_object_operands (
if (ACPI_SUCCESS (status)) {
/*
- * Return the object in the walk_state, unless the parent is a package --
+ * Return the object in the walk_state, unless the parent is a package -
* in this case, the return object will be stored in the parse tree
* for the package.
*/
@@ -988,7 +1022,8 @@ acpi_ds_exec_end_control_op (
status = AE_CTRL_PENDING;
}
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[WHILE_OP] termination! Op=%p\n", op));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "[WHILE_OP] termination! Op=%p\n",op));
/* Pop this control state and free it */
diff --git a/drivers/acpi/dispatcher/dsutils.c b/drivers/acpi/dispatcher/dsutils.c
index 462c5d83e747..9613349ac31d 100644
--- a/drivers/acpi/dispatcher/dsutils.c
+++ b/drivers/acpi/dispatcher/dsutils.c
@@ -100,7 +100,6 @@ acpi_ds_clear_implicit_return (
#ifndef ACPI_NO_METHOD_EXECUTION
-
/*******************************************************************************
*
* FUNCTION: acpi_ds_do_implicit_return
@@ -205,7 +204,7 @@ acpi_ds_is_result_used (
* NOTE: this is optional because the ASL language does not actually
* support this behavior.
*/
- acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE);
+ (void) acpi_ds_do_implicit_return (walk_state->result_obj, walk_state, TRUE);
/*
* Now determine if the parent will use the result
@@ -219,8 +218,9 @@ acpi_ds_is_result_used (
(op->common.parent->common.aml_opcode == AML_SCOPE_OP)) {
/* No parent, the return value cannot possibly be used */
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "At Method level, result of [%s] not used\n",
- acpi_ps_get_opcode_name (op->common.aml_opcode)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "At Method level, result of [%s] not used\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode)));
return_VALUE (FALSE);
}
@@ -228,7 +228,8 @@ acpi_ds_is_result_used (
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));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown parent opcode. Op=%p\n", op));
return_VALUE (FALSE);
}
@@ -309,17 +310,19 @@ acpi_ds_is_result_used (
result_used:
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] used by Parent [%s] Op=%p\n",
- acpi_ps_get_opcode_name (op->common.aml_opcode),
- acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Result of [%s] used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
return_VALUE (TRUE);
result_not_used:
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Result of [%s] not used by Parent [%s] Op=%p\n",
- acpi_ps_get_opcode_name (op->common.aml_opcode),
- acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Result of [%s] not used by Parent [%s] Op=%p\n",
+ acpi_ps_get_opcode_name (op->common.aml_opcode),
+ acpi_ps_get_opcode_name (op->common.parent->common.aml_opcode), op));
return_VALUE (FALSE);
}
@@ -522,7 +525,8 @@ acpi_ds_create_operand (
if ((walk_state->deferred_node) &&
(walk_state->deferred_node->type == ACPI_TYPE_BUFFER_FIELD) &&
(arg_index != 0)) {
- obj_desc = ACPI_CAST_PTR (union acpi_operand_object, walk_state->deferred_node);
+ obj_desc = ACPI_CAST_PTR (
+ union acpi_operand_object, walk_state->deferred_node);
status = AE_OK;
}
else /* All other opcodes */ {
@@ -565,7 +569,8 @@ acpi_ds_create_operand (
* indicate this to the interpreter, set the
* object to the root
*/
- obj_desc = ACPI_CAST_PTR (union acpi_operand_object, acpi_gbl_root_node);
+ obj_desc = ACPI_CAST_PTR (
+ union acpi_operand_object, acpi_gbl_root_node);
status = AE_OK;
}
else {
@@ -612,7 +617,8 @@ acpi_ds_create_operand (
*/
opcode = AML_ZERO_OP; /* Has no arguments! */
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Null namepath: Arg=%p\n", arg));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Null namepath: Arg=%p\n", arg));
}
else {
opcode = arg->common.aml_opcode;
@@ -642,7 +648,8 @@ acpi_ds_create_operand (
* Only error is underflow, and this indicates
* a missing or null operand!
*/
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Missing or null operand, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Missing or null operand, %s\n",
acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
@@ -657,8 +664,8 @@ acpi_ds_create_operand (
/* Initialize the new object */
- status = acpi_ds_init_object_from_op (walk_state, arg,
- opcode, &obj_desc);
+ status = acpi_ds_init_object_from_op (
+ walk_state, arg, opcode, &obj_desc);
if (ACPI_FAILURE (status)) {
acpi_ut_delete_object_desc (obj_desc);
return_ACPI_STATUS (status);
diff --git a/drivers/acpi/dispatcher/dswexec.c b/drivers/acpi/dispatcher/dswexec.c
index 2071a0d2bbbb..10f71318e23b 100644
--- a/drivers/acpi/dispatcher/dswexec.c
+++ b/drivers/acpi/dispatcher/dswexec.c
@@ -73,11 +73,13 @@ static ACPI_EXECUTE_OP acpi_gbl_op_type_dispatch [] = {
acpi_ex_opcode_3A_1T_1R,
acpi_ex_opcode_6A_0T_1R};
+
/*****************************************************************************
*
* FUNCTION: acpi_ds_get_predicate_value
*
* PARAMETERS: walk_state - Current state of the parse tree walk
+ * result_obj - if non-zero, pop result from result stack
*
* RETURN: Status
*
@@ -124,7 +126,8 @@ acpi_ds_get_predicate_value (
}
if (!obj_desc) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No predicate obj_desc=%p State=%p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No predicate obj_desc=%p State=%p\n",
obj_desc, walk_state));
return_ACPI_STATUS (AE_AML_NO_OPERAND);
@@ -197,7 +200,7 @@ cleanup:
* FUNCTION: acpi_ds_exec_begin_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * out_op - Return op if a new one is created
+ * out_op - Where to return op if a new one is created
*
* RETURN: Status
*
@@ -233,7 +236,8 @@ acpi_ds_exec_begin_op (
walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
if (acpi_ns_opens_scope (walk_state->op_info->object_type)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "(%s) Popping scope for Op %p\n",
acpi_ut_get_type_name (walk_state->op_info->object_type), op));
status = acpi_ds_scope_stack_pop (walk_state);
@@ -297,11 +301,10 @@ acpi_ds_exec_begin_op (
if (walk_state->walk_type == ACPI_WALK_METHOD) {
/*
- * Found a named object declaration during method
- * execution; we must enter this object into the
- * namespace. The created object is temporary and
- * will be deleted upon completion of the execution
- * of this method.
+ * Found a named object declaration during method execution;
+ * we must enter this object into the namespace. The created
+ * object is temporary and will be deleted upon completion of
+ * the execution of this method.
*/
status = acpi_ds_load2_begin_op (walk_state, NULL);
}
@@ -338,8 +341,6 @@ acpi_ds_exec_begin_op (
* FUNCTION: acpi_ds_exec_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * Op - Op that has been just been completed in the
- * walk; Arguments have now been evaluated.
*
* RETURN: Status
*
@@ -389,7 +390,7 @@ acpi_ds_exec_end_op (
/* Decode the Opcode Class */
switch (op_class) {
- case AML_CLASS_ARGUMENT: /* constants, literals, etc. -- do nothing */
+ case AML_CLASS_ARGUMENT: /* constants, literals, etc. - do nothing */
break;
@@ -417,12 +418,12 @@ acpi_ds_exec_end_op (
/* Resolve all operands */
status = acpi_ex_resolve_operands (walk_state->opcode,
- &(walk_state->operands [walk_state->num_operands -1]),
- walk_state);
+ &(walk_state->operands [walk_state->num_operands -1]),
+ walk_state);
if (ACPI_SUCCESS (status)) {
ACPI_DUMP_OPERANDS (ACPI_WALK_OPERANDS, ACPI_IMODE_EXECUTE,
- acpi_ps_get_opcode_name (walk_state->opcode),
- walk_state->num_operands, "after ex_resolve_operands");
+ acpi_ps_get_opcode_name (walk_state->opcode),
+ walk_state->num_operands, "after ex_resolve_operands");
}
}
@@ -506,7 +507,8 @@ acpi_ds_exec_end_op (
if ((op->asl.parent) &&
((op->asl.parent->asl.aml_opcode == AML_PACKAGE_OP) ||
(op->asl.parent->asl.aml_opcode == AML_VAR_PACKAGE_OP))) {
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Method Reference in a Package, Op=%p\n", op));
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "Method Reference in a Package, Op=%p\n", op));
op->common.node = (struct acpi_namespace_node *) op->asl.value.arg->asl.node->object;
acpi_ut_add_reference (op->asl.value.arg->asl.node->object);
return_ACPI_STATUS (AE_OK);
@@ -583,13 +585,15 @@ acpi_ds_exec_end_op (
case AML_NAME_OP:
/*
- * Put the Node on the object stack (Contains the ACPI Name of
- * this object)
+ * Put the Node on the object stack (Contains the ACPI Name
+ * of this object)
*/
walk_state->operands[0] = (void *) op->common.parent->common.node;
walk_state->num_operands = 1;
- status = acpi_ds_create_node (walk_state, op->common.parent->common.node, op->common.parent);
+ status = acpi_ds_create_node (walk_state,
+ op->common.parent->common.node,
+ op->common.parent);
if (ACPI_FAILURE (status)) {
break;
}
@@ -600,7 +604,7 @@ acpi_ds_exec_end_op (
case AML_INT_EVAL_SUBTREE_OP:
status = acpi_ds_eval_data_object_operands (walk_state, op,
- acpi_ns_get_attached_object (op->common.parent->common.node));
+ acpi_ns_get_attached_object (op->common.parent->common.node));
break;
default:
@@ -609,7 +613,7 @@ acpi_ds_exec_end_op (
break;
}
- /* Done with this result state (Now that operand stack is built) */
+ /* Done with result state (Now that operand stack is built) */
status = acpi_ds_result_stack_pop (walk_state);
if (ACPI_FAILURE (status)) {
@@ -620,8 +624,7 @@ acpi_ds_exec_end_op (
* If a result object was returned from above, push it on the
* current result stack
*/
- if (ACPI_SUCCESS (status) &&
- walk_state->result_obj) {
+ if (walk_state->result_obj) {
status = acpi_ds_result_push (walk_state->result_obj, walk_state);
}
break;
@@ -654,7 +657,8 @@ acpi_ds_exec_end_op (
case AML_TYPE_UNDEFINED:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Undefined opcode type Op=%p\n", op));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Undefined opcode type Op=%p\n", op));
return_ACPI_STATUS (AE_NOT_IMPLEMENTED);
@@ -709,13 +713,14 @@ cleanup:
status = acpi_gbl_exception_handler (status,
walk_state->method_node->name.integer, walk_state->opcode,
walk_state->aml_offset, NULL);
- acpi_ex_enter_interpreter ();
+ (void) acpi_ex_enter_interpreter ();
}
if (walk_state->result_obj) {
/* Break to debugger to display result */
- ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj, walk_state));
+ ACPI_DEBUGGER_EXEC (acpi_db_display_result_object (walk_state->result_obj,
+ walk_state));
/*
* Delete the result op if and only if:
diff --git a/drivers/acpi/dispatcher/dswload.c b/drivers/acpi/dispatcher/dswload.c
index 06d758679588..1ac197ccfc80 100644
--- a/drivers/acpi/dispatcher/dswload.c
+++ b/drivers/acpi/dispatcher/dswload.c
@@ -79,20 +79,23 @@ acpi_ds_init_callbacks (
switch (pass_number) {
case 1:
- walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load1_begin_op;
walk_state->ascending_callback = acpi_ds_load1_end_op;
break;
case 2:
- walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 | ACPI_PARSE_DELETE_TREE;
+ walk_state->parse_flags = ACPI_PARSE_LOAD_PASS1 |
+ ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_load2_begin_op;
walk_state->ascending_callback = acpi_ds_load2_end_op;
break;
case 3:
#ifndef ACPI_NO_METHOD_EXECUTION
- walk_state->parse_flags |= ACPI_PARSE_EXECUTE | ACPI_PARSE_DELETE_TREE;
+ walk_state->parse_flags |= ACPI_PARSE_EXECUTE |
+ ACPI_PARSE_DELETE_TREE;
walk_state->descending_callback = acpi_ds_exec_begin_op;
walk_state->ascending_callback = acpi_ds_exec_end_op;
#endif
@@ -111,8 +114,7 @@ acpi_ds_init_callbacks (
* FUNCTION: acpi_ds_load1_begin_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * Op - Op that has been just been reached in the
- * walk; Arguments have not been evaluated yet.
+ * out_op - Where to return op if a new one is created
*
* RETURN: Status
*
@@ -146,7 +148,8 @@ acpi_ds_load1_begin_op (
#if 0
if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
(walk_state->op_info->class == AML_CLASS_CONTROL)) {
- acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n", walk_state->op_info->name);
+ acpi_os_printf ("\n\n***EXECUTABLE OPCODE %s***\n\n",
+ walk_state->op_info->name);
*out_op = op;
return (AE_CTRL_SKIP);
}
@@ -191,7 +194,8 @@ acpi_ds_load1_begin_op (
*/
acpi_dm_add_to_external_list (path);
status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
- ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ ACPI_IMODE_LOAD_PASS1, ACPI_NS_SEARCH_PARENT,
+ walk_state, &(node));
}
#endif
if (ACPI_FAILURE (status)) {
@@ -224,10 +228,12 @@ acpi_ds_load1_begin_op (
* Name (DEB, 0)
* Scope (DEB) { ... }
*
- * Note: silently change the type here. On the second pass, we will report a warning
+ * Note: silently change the type here. On the second pass, we will report
+ * a warning
*/
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
path, acpi_ut_get_type_name (node->type)));
node->type = ACPI_TYPE_ANY;
@@ -238,7 +244,8 @@ acpi_ds_load1_begin_op (
/* All other types are an error */
- ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n",
+ ACPI_REPORT_ERROR ((
+ "Invalid type (%s) for target of Scope operator [%4.4s] (Cannot override)\n",
acpi_ut_get_type_name (node->type), path));
return (AE_AML_OPERAND_TYPE);
@@ -249,7 +256,8 @@ acpi_ds_load1_begin_op (
default:
/*
- * For all other named opcodes, we will enter the name into the namespace.
+ * For all other named opcodes, we will enter the name into
+ * the namespace.
*
* Setup the search flags.
* Since we are entering a name into the namespace, we do not want to
@@ -279,14 +287,16 @@ acpi_ds_load1_begin_op (
acpi_ut_get_type_name (object_type)));
}
else {
- ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "[%s] Both Find or Create allowed\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
+ "[%s] Both Find or Create allowed\n",
acpi_ut_get_type_name (object_type)));
}
/*
* Enter the named type into the internal namespace. We enter the name
- * as we go downward in the parse tree. Any necessary subobjects that involve
- * arguments to the opcode must be created as we go back up the parse tree later.
+ * as we go downward in the parse tree. Any necessary subobjects that
+ * involve arguments to the opcode must be created as we go back up the
+ * parse tree later.
*/
status = acpi_ns_lookup (walk_state->scope_info, path, object_type,
ACPI_IMODE_LOAD_PASS1, flags, walk_state, &(node));
@@ -335,8 +345,6 @@ acpi_ds_load1_begin_op (
* FUNCTION: acpi_ds_load1_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * Op - Op that has been just been completed in the
- * walk; Arguments have now been evaluated.
*
* RETURN: Status
*
@@ -383,7 +391,9 @@ acpi_ds_load1_end_op (
if (op->common.aml_opcode == AML_REGION_OP) {
status = acpi_ex_create_region (op->named.data, op->named.length,
- (acpi_adr_space_type) ((op->common.value.arg)->common.value.integer), walk_state);
+ (acpi_adr_space_type)
+ ((op->common.value.arg)->common.value.integer),
+ walk_state);
if (ACPI_FAILURE (status)) {
return (status);
}
@@ -394,7 +404,8 @@ acpi_ds_load1_end_op (
/* For Name opcode, get the object type from the argument */
if (op->common.value.arg) {
- object_type = (acpi_ps_get_opcode_info ((op->common.value.arg)->common.aml_opcode))->object_type;
+ object_type = (acpi_ps_get_opcode_info (
+ (op->common.value.arg)->common.aml_opcode))->object_type;
op->common.node->type = (u8) object_type;
}
}
@@ -448,8 +459,7 @@ acpi_ds_load1_end_op (
* FUNCTION: acpi_ds_load2_begin_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * Op - Op that has been just been reached in the
- * walk; Arguments have not been evaluated yet.
+ * out_op - Wher to return op if a new one is created
*
* RETURN: Status
*
@@ -478,14 +488,20 @@ acpi_ds_load2_begin_op (
if (op) {
/* We only care about Namespace opcodes here */
- if ((!(walk_state->op_info->flags & AML_NSOPCODE) && (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
+ if ((!(walk_state->op_info->flags & AML_NSOPCODE) &&
+ (walk_state->opcode != AML_INT_NAMEPATH_OP)) ||
(!(walk_state->op_info->flags & AML_NAMED))) {
+ if ((walk_state->op_info->class == AML_CLASS_EXECUTE) ||
+ (walk_state->op_info->class == AML_CLASS_CONTROL)) {
+ ACPI_REPORT_WARNING ((
+ "Encountered executable code at module level, [%s]\n",
+ acpi_ps_get_opcode_name (walk_state->opcode)));
+ }
return_ACPI_STATUS (AE_OK);
}
- /*
- * Get the name we are going to enter or lookup in the namespace
- */
+ /* Get the name we are going to enter or lookup in the namespace */
+
if (walk_state->opcode == AML_INT_NAMEPATH_OP) {
/* For Namepath op, get the path string */
@@ -528,21 +544,25 @@ acpi_ds_load2_begin_op (
case AML_INT_NAMEPATH_OP:
/*
- * The name_path is an object reference to an existing object. Don't enter the
- * name into the namespace, but look it up for use later
+ * The name_path is an object reference to an existing object.
+ * Don't enter the name into the namespace, but look it up
+ * for use later.
*/
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
- ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
+ walk_state, &(node));
break;
case AML_SCOPE_OP:
/*
- * The Path is an object reference to an existing object. Don't enter the
- * name into the namespace, but look it up for use later
+ * The Path is an object reference to an existing object.
+ * Don't enter the name into the namespace, but look it up
+ * for use later.
*/
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
- ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT, walk_state, &(node));
+ ACPI_IMODE_EXECUTE, ACPI_NS_SEARCH_PARENT,
+ walk_state, &(node));
if (ACPI_FAILURE (status)) {
#ifdef _ACPI_ASL_COMPILER
if (status == AE_NOT_FOUND) {
@@ -582,7 +602,8 @@ acpi_ds_load2_begin_op (
* Scope (DEB) { ... }
*/
- ACPI_REPORT_WARNING (("Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
+ ACPI_REPORT_WARNING ((
+ "Type override - [%4.4s] had invalid type (%s) for Scope operator, changed to (Scope)\n",
buffer_ptr, acpi_ut_get_type_name (node->type)));
node->type = ACPI_TYPE_ANY;
@@ -593,7 +614,8 @@ acpi_ds_load2_begin_op (
/* All other types are an error */
- ACPI_REPORT_ERROR (("Invalid type (%s) for target of Scope operator [%4.4s]\n",
+ ACPI_REPORT_ERROR ((
+ "Invalid type (%s) for target of Scope operator [%4.4s]\n",
acpi_ut_get_type_name (node->type), buffer_ptr));
return (AE_AML_OPERAND_TYPE);
@@ -621,8 +643,9 @@ acpi_ds_load2_begin_op (
/*
* Enter the named type into the internal namespace. We enter the name
- * as we go downward in the parse tree. Any necessary subobjects that involve
- * arguments to the opcode must be created as we go back up the parse tree later.
+ * as we go downward in the parse tree. Any necessary subobjects that
+ * involve arguments to the opcode must be created as we go back up the
+ * parse tree later.
*
* Note: Name may already exist if we are executing a deferred opcode.
*/
@@ -635,7 +658,8 @@ acpi_ds_load2_begin_op (
}
status = acpi_ns_lookup (walk_state->scope_info, buffer_ptr, object_type,
- ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH, walk_state, &(node));
+ ACPI_IMODE_EXECUTE, ACPI_NS_NO_UPSEARCH,
+ walk_state, &(node));
break;
}
@@ -678,8 +702,6 @@ acpi_ds_load2_begin_op (
* FUNCTION: acpi_ds_load2_end_op
*
* PARAMETERS: walk_state - Current state of the parse tree walk
- * Op - Op that has been just been completed in the
- * walk; Arguments have now been evaluated.
*
* RETURN: Status
*
@@ -738,7 +760,8 @@ acpi_ds_load2_end_op (
/* Pop the scope stack */
- if (acpi_ns_opens_scope (object_type) && (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
+ if (acpi_ns_opens_scope (object_type) &&
+ (op->common.aml_opcode != AML_INT_METHODCALL_OP)) {
ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "(%s) Popping scope for Op %p\n",
acpi_ut_get_type_name (object_type), op));
@@ -803,7 +826,7 @@ acpi_ds_load2_end_op (
case AML_INDEX_FIELD_OP:
status = acpi_ds_create_index_field (op, (acpi_handle) arg->common.node,
- walk_state);
+ walk_state);
break;
case AML_BANK_FIELD_OP:
@@ -884,14 +907,16 @@ acpi_ds_load2_end_op (
#ifndef ACPI_NO_METHOD_EXECUTION
case AML_REGION_OP:
/*
- * The op_region is not fully parsed at this time. Only valid argument is the space_id.
- * (We must save the address of the AML of the address and length operands)
+ * The op_region is not fully parsed at this time. Only valid
+ * argument is the space_id. (We must save the address of the
+ * AML of the address and length operands)
*/
/*
* If we have a valid region, initialize it
* Namespace is NOT locked at this point.
*/
- status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node), FALSE);
+ status = acpi_ev_initialize_region (acpi_ns_get_attached_object (node),
+ FALSE);
if (ACPI_FAILURE (status)) {
/*
* If AE_NOT_EXIST is returned, it is not fatal
@@ -942,15 +967,16 @@ acpi_ds_load2_end_op (
if (ACPI_SUCCESS (status)) {
/*
* Make sure that what we found is indeed a method
- * We didn't search for a method on purpose, to see if the name would resolve
+ * We didn't search for a method on purpose, to see if the name
+ * would resolve
*/
if (new_node->type != ACPI_TYPE_METHOD) {
status = AE_AML_OPERAND_TYPE;
}
- /* We could put the returned object (Node) on the object stack for later, but
- * for now, we will put it in the "op" object that the parser uses, so we
- * can get it again at the end of this scope
+ /* We could put the returned object (Node) on the object stack for
+ * later, but for now, we will put it in the "op" object that the
+ * parser uses, so we can get it again at the end of this scope
*/
op->common.node = new_node;
}
diff --git a/drivers/acpi/dispatcher/dswscope.c b/drivers/acpi/dispatcher/dswscope.c
index 65f456151e25..21f4548ff323 100644
--- a/drivers/acpi/dispatcher/dswscope.c
+++ b/drivers/acpi/dispatcher/dswscope.c
@@ -50,14 +50,13 @@
ACPI_MODULE_NAME ("dswscope")
-#define STACK_POP(head) head
-
-
/****************************************************************************
*
* FUNCTION: acpi_ds_scope_stack_clear
*
- * PARAMETERS: None
+ * PARAMETERS: walk_state - Current state
+ *
+ * RETURN: None
*
* DESCRIPTION: Pop (and free) everything on the scope stack except the
* root scope object (which remains at the stack top.)
@@ -80,7 +79,8 @@ acpi_ds_scope_stack_clear (
walk_state->scope_info = scope_info->scope.next;
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
- "Popped object type (%s)\n", acpi_ut_get_type_name (scope_info->common.value)));
+ "Popped object type (%s)\n",
+ acpi_ut_get_type_name (scope_info->common.value)));
acpi_ut_delete_generic_state (scope_info);
}
}
@@ -90,8 +90,11 @@ acpi_ds_scope_stack_clear (
*
* FUNCTION: acpi_ds_scope_stack_push
*
- * PARAMETERS: *Node, - Name to be made current
- * Type, - Type of frame being pushed
+ * PARAMETERS: Node - Name to be made current
+ * Type - Type of frame being pushed
+ * walk_state - Current state
+ *
+ * RETURN: Status
*
* DESCRIPTION: Push the current scope on the scope stack, and make the
* passed Node current.
@@ -121,7 +124,8 @@ acpi_ds_scope_stack_push (
/* Make sure object type is valid */
if (!acpi_ut_valid_object_type (type)) {
- ACPI_REPORT_WARNING (("ds_scope_stack_push: Invalid object type: 0x%X\n", type));
+ ACPI_REPORT_WARNING ((
+ "ds_scope_stack_push: Invalid object type: 0x%X\n", type));
}
/* Allocate a new scope object */
@@ -170,16 +174,11 @@ acpi_ds_scope_stack_push (
*
* FUNCTION: acpi_ds_scope_stack_pop
*
- * PARAMETERS: Type - The type of frame to be found
+ * PARAMETERS: walk_state - Current state
*
- * DESCRIPTION: Pop the scope stack until a frame of the requested type
- * is found.
+ * RETURN: Status
*
- * RETURN: Count of frames popped. If no frame of the requested type
- * was found, the count is returned as a negative number and
- * the scope stack is emptied (which sets the current scope
- * to the root). If the scope stack was empty at entry, the
- * function is a no-op and returns 0.
+ * DESCRIPTION: Pop the scope stack once.
*
***************************************************************************/
diff --git a/drivers/acpi/dispatcher/dswstate.c b/drivers/acpi/dispatcher/dswstate.c
index e555b3fbd5e5..9cd3db652b31 100644
--- a/drivers/acpi/dispatcher/dswstate.c
+++ b/drivers/acpi/dispatcher/dswstate.c
@@ -50,67 +50,31 @@
#define _COMPONENT ACPI_DISPATCHER
ACPI_MODULE_NAME ("dswstate")
+/* Local prototypes */
-#ifdef ACPI_FUTURE_USAGE
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_result_insert
- *
- * PARAMETERS: Object - Object to push
- * Index - Where to insert the object
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Insert an object onto this walk's result stack
- *
- ******************************************************************************/
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
acpi_status
acpi_ds_result_insert (
void *object,
u32 index,
- struct acpi_walk_state *walk_state)
-{
- union acpi_generic_state *state;
-
+ struct acpi_walk_state *walk_state);
- ACPI_FUNCTION_NAME ("ds_result_insert");
-
-
- state = walk_state->results;
- if (!state) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n",
- walk_state));
- return (AE_NOT_EXIST);
- }
-
- if (index >= ACPI_OBJ_NUM_OPERANDS) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Index out of range: %X Obj=%p State=%p Num=%X\n",
- index, object, walk_state, state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- if (!object) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Null Object! Index=%X Obj=%p State=%p Num=%X\n",
- index, object, walk_state, state->results.num_results));
- return (AE_BAD_PARAMETER);
- }
-
- state->results.obj_desc [index] = object;
- state->results.num_results++;
+acpi_status
+acpi_ds_obj_stack_delete_all (
+ struct acpi_walk_state *walk_state);
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
- "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
- object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL",
- walk_state, state->results.num_results, walk_state->current_result));
+acpi_status
+acpi_ds_obj_stack_pop_object (
+ union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state);
- return (AE_OK);
-}
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ struct acpi_walk_state *walk_state);
+#endif
+#ifdef ACPI_FUTURE_USAGE
/*******************************************************************************
*
@@ -178,7 +142,6 @@ acpi_ds_result_remove (
#endif /* ACPI_FUTURE_USAGE */
-
/*******************************************************************************
*
* FUNCTION: acpi_ds_result_pop
@@ -227,15 +190,18 @@ acpi_ds_result_pop (
*object = state->results.obj_desc [index -1];
state->results.obj_desc [index -1] = NULL;
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] Index=%X State=%p Num=%X\n",
- *object, (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Obj=%p [%s] Index=%X State=%p Num=%X\n",
+ *object,
+ (*object) ? acpi_ut_get_object_type_name (*object) : "NULL",
(u32) index -1, walk_state, state->results.num_results));
return (AE_OK);
}
}
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No result objects! State=%p\n", walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
@@ -274,7 +240,8 @@ acpi_ds_result_pop_from_bottom (
}
if (!state->results.num_results) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n", walk_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result objects! State=%p\n",
+ walk_state));
return (AE_AML_NO_RETURN_VALUE);
}
@@ -293,7 +260,8 @@ acpi_ds_result_pop_from_bottom (
/* Check for a valid result object */
if (!*object) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null operand! State=%p #Ops=%X, Index=%X\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null operand! State=%p #Ops=%X, Index=%X\n",
walk_state, state->results.num_results, (u32) index));
return (AE_AML_NO_RETURN_VALUE);
}
@@ -344,7 +312,8 @@ acpi_ds_result_push (
}
if (!object) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Null Object! Obj=%p State=%p Num=%X\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null Object! Obj=%p State=%p Num=%X\n",
object, walk_state, state->results.num_results));
return (AE_BAD_PARAMETER);
}
@@ -439,43 +408,6 @@ acpi_ds_result_stack_pop (
/*******************************************************************************
*
- * FUNCTION: acpi_ds_obj_stack_delete_all
- *
- * PARAMETERS: walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
- * Should be used with great care, if at all!
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ds_obj_stack_delete_all (
- struct acpi_walk_state *walk_state)
-{
- u32 i;
-
-
- ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state);
-
-
- /* The stack size is configurable, but fixed */
-
- for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
- if (walk_state->operands[i]) {
- acpi_ut_remove_reference (walk_state->operands[i]);
- walk_state->operands[i] = NULL;
- }
- }
-
- return_ACPI_STATUS (AE_OK);
-}
-#endif /* ACPI_FUTURE_USAGE */
-
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ds_obj_stack_push
*
* PARAMETERS: Object - Object to push
@@ -517,67 +449,6 @@ acpi_ds_obj_stack_push (
}
-#if 0
-/*******************************************************************************
- *
- * FUNCTION: acpi_ds_obj_stack_pop_object
- *
- * PARAMETERS: pop_count - Number of objects/entries to pop
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
- * deleted by this routine.
- *
- ******************************************************************************/
-
-acpi_status
-acpi_ds_obj_stack_pop_object (
- union acpi_operand_object **object,
- struct acpi_walk_state *walk_state)
-{
- ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object");
-
-
- /* Check for stack underflow */
-
- if (walk_state->num_operands == 0) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Missing operand/stack empty! State=%p #Ops=%X\n",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Pop the stack */
-
- walk_state->num_operands--;
-
- /* Check for a valid operand */
-
- if (!walk_state->operands [walk_state->num_operands]) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Null operand! State=%p #Ops=%X\n",
- walk_state, walk_state->num_operands));
- *object = NULL;
- return (AE_AML_NO_OPERAND);
- }
-
- /* Get operand and set stack entry to null */
-
- *object = walk_state->operands [walk_state->num_operands];
- walk_state->operands [walk_state->num_operands] = NULL;
-
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
- *object, acpi_ut_get_object_type_name (*object),
- walk_state, walk_state->num_operands));
-
- return (AE_OK);
-}
-#endif
-
-
/*******************************************************************************
*
* FUNCTION: acpi_ds_obj_stack_pop
@@ -680,48 +551,6 @@ acpi_ds_obj_stack_pop_and_delete (
/*******************************************************************************
*
- * FUNCTION: acpi_ds_obj_stack_get_value
- *
- * PARAMETERS: Index - Stack index whose value is desired. Based
- * on the top of the stack (index=0 == top)
- * walk_state - Current Walk state
- *
- * RETURN: Status
- *
- * DESCRIPTION: Retrieve an object from this walk's object stack. Index must
- * be within the range of the current stack pointer.
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-void *
-acpi_ds_obj_stack_get_value (
- u32 index,
- struct acpi_walk_state *walk_state)
-{
-
- ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state);
-
-
- /* Can't do it if the stack is empty */
-
- if (walk_state->num_operands == 0) {
- return_PTR (NULL);
- }
-
- /* or if the index is past the top of the stack */
-
- if (index > (walk_state->num_operands - (u32) 1)) {
- return_PTR (NULL);
- }
-
- return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) -
- index]);
-}
-#endif /* ACPI_FUTURE_USAGE */
-
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ds_get_current_walk_state
*
* PARAMETERS: Thread - Get current active state for this Thread
@@ -757,11 +586,11 @@ acpi_ds_get_current_walk_state (
* FUNCTION: acpi_ds_push_walk_state
*
* PARAMETERS: walk_state - State to push
- * walk_list - The list that owns the walk stack
+ * Thread - Thread state object
*
* RETURN: None
*
- * DESCRIPTION: Place the walk_state at the head of the state list.
+ * DESCRIPTION: Place the Thread state at the head of the state list.
*
******************************************************************************/
@@ -784,9 +613,9 @@ acpi_ds_push_walk_state (
*
* FUNCTION: acpi_ds_pop_walk_state
*
- * PARAMETERS: walk_list - The list that owns the walk stack
+ * PARAMETERS: Thread - Current thread state
*
- * RETURN: A walk_state object popped from the stack
+ * RETURN: A walk_state object popped from the thread's stack
*
* DESCRIPTION: Remove and return the walkstate object that is at the head of
* the walk stack for the given walk list. NULL indicates that
@@ -814,7 +643,7 @@ acpi_ds_pop_walk_state (
/*
* Don't clear the NEXT field, this serves as an indicator
* that there is a parent WALK STATE
- * NO: walk_state->Next = NULL;
+ * Do Not: walk_state->Next = NULL;
*/
}
@@ -826,7 +655,9 @@ acpi_ds_pop_walk_state (
*
* FUNCTION: acpi_ds_create_walk_state
*
- * PARAMETERS: Origin - Starting point for this walk
+ * PARAMETERS: owner_id - ID for object creation
+ * Origin - Starting point for this walk
+ * mth_desc - Method object
* Thread - Current thread state
*
* RETURN: Pointer to the new walk state.
@@ -896,8 +727,7 @@ acpi_ds_create_walk_state (
* method_node - Control method NS node, if any
* aml_start - Start of AML
* aml_length - Length of AML
- * Params - Method args, if any
- * return_obj_desc - Where to store a return object, if any
+ * Info - Method info block (params, etc.)
* pass_number - 1, 2, or 3
*
* RETURN: Status
@@ -931,7 +761,7 @@ 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->next_op = NULL;
if (info) {
if (info->parameter_type == ACPI_PARAM_GPE) {
@@ -939,8 +769,8 @@ acpi_ds_init_aml_walk (
info->parameters);
}
else {
- walk_state->params = info->parameters;
- walk_state->caller_return_desc = &info->return_object;
+ walk_state->params = info->parameters;
+ walk_state->caller_return_desc = &info->return_object;
}
}
@@ -964,7 +794,8 @@ acpi_ds_init_aml_walk (
/* Init the method arguments */
- status = acpi_ds_method_data_init_args (walk_state->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);
}
@@ -1031,12 +862,14 @@ acpi_ds_delete_walk_state (
}
if (walk_state->data_type != ACPI_DESC_TYPE_WALK) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n", walk_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p is not a valid walk state\n",
+ walk_state));
return;
}
if (walk_state->parser_state.scope) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n", walk_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "%p walk still has a scope list\n",
+ walk_state));
}
/* Always must free any linked control states */
@@ -1078,7 +911,7 @@ acpi_ds_delete_walk_state (
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Purge the global state object cache. Used during subsystem
* termination.
@@ -1098,3 +931,200 @@ acpi_ds_delete_walk_state_cache (
#endif
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_result_insert
+ *
+ * PARAMETERS: Object - Object to push
+ * Index - Where to insert the object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Insert an object onto this walk's result stack
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_result_insert (
+ void *object,
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+ union acpi_generic_state *state;
+
+
+ ACPI_FUNCTION_NAME ("ds_result_insert");
+
+
+ state = walk_state->results;
+ if (!state) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No result object pushed! State=%p\n",
+ walk_state));
+ return (AE_NOT_EXIST);
+ }
+
+ if (index >= ACPI_OBJ_NUM_OPERANDS) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index out of range: %X Obj=%p State=%p Num=%X\n",
+ index, object, walk_state, state->results.num_results));
+ return (AE_BAD_PARAMETER);
+ }
+
+ if (!object) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null Object! Index=%X Obj=%p State=%p Num=%X\n",
+ index, object, walk_state, state->results.num_results));
+ return (AE_BAD_PARAMETER);
+ }
+
+ state->results.obj_desc [index] = object;
+ state->results.num_results++;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Obj=%p [%s] State=%p Num=%X Cur=%X\n",
+ object, object ? acpi_ut_get_object_type_name ((union acpi_operand_object *) object) : "NULL",
+ walk_state, state->results.num_results, walk_state->current_result));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_delete_all
+ *
+ * PARAMETERS: walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear the object stack by deleting all objects that are on it.
+ * Should be used with great care, if at all!
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_delete_all (
+ struct acpi_walk_state *walk_state)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_delete_all", walk_state);
+
+
+ /* The stack size is configurable, but fixed */
+
+ for (i = 0; i < ACPI_OBJ_NUM_OPERANDS; i++) {
+ if (walk_state->operands[i]) {
+ acpi_ut_remove_reference (walk_state->operands[i]);
+ walk_state->operands[i] = NULL;
+ }
+ }
+
+ return_ACPI_STATUS (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_pop_object
+ *
+ * PARAMETERS: Object - Where to return the popped object
+ * walk_state - Current Walk state
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT
+ * deleted by this routine.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_ds_obj_stack_pop_object (
+ union acpi_operand_object **object,
+ struct acpi_walk_state *walk_state)
+{
+ ACPI_FUNCTION_NAME ("ds_obj_stack_pop_object");
+
+
+ /* Check for stack underflow */
+
+ if (walk_state->num_operands == 0) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Missing operand/stack empty! State=%p #Ops=%X\n",
+ walk_state, walk_state->num_operands));
+ *object = NULL;
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Pop the stack */
+
+ walk_state->num_operands--;
+
+ /* Check for a valid operand */
+
+ if (!walk_state->operands [walk_state->num_operands]) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Null operand! State=%p #Ops=%X\n",
+ walk_state, walk_state->num_operands));
+ *object = NULL;
+ return (AE_AML_NO_OPERAND);
+ }
+
+ /* Get operand and set stack entry to null */
+
+ *object = walk_state->operands [walk_state->num_operands];
+ walk_state->operands [walk_state->num_operands] = NULL;
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n",
+ *object, acpi_ut_get_object_type_name (*object),
+ walk_state, walk_state->num_operands));
+
+ return (AE_OK);
+}
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ds_obj_stack_get_value
+ *
+ * PARAMETERS: Index - Stack index whose value is desired. Based
+ * on the top of the stack (index=0 == top)
+ * walk_state - Current Walk state
+ *
+ * RETURN: Pointer to the requested operand
+ *
+ * DESCRIPTION: Retrieve an object from this walk's operand stack. Index must
+ * be within the range of the current stack pointer.
+ *
+ ******************************************************************************/
+
+void *
+acpi_ds_obj_stack_get_value (
+ u32 index,
+ struct acpi_walk_state *walk_state)
+{
+
+ ACPI_FUNCTION_TRACE_PTR ("ds_obj_stack_get_value", walk_state);
+
+
+ /* Can't do it if the stack is empty */
+
+ if (walk_state->num_operands == 0) {
+ return_PTR (NULL);
+ }
+
+ /* or if the index is past the top of the stack */
+
+ if (index > (walk_state->num_operands - (u32) 1)) {
+ return_PTR (NULL);
+ }
+
+ return_PTR (walk_state->operands[(acpi_native_uint)(walk_state->num_operands - 1) -
+ index]);
+}
+#endif
+
+
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index fdf143b405be..8e665f2e3138 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/interrupt.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
@@ -49,17 +50,19 @@ ACPI_MODULE_NAME ("acpi_ec")
#define ACPI_EC_FLAG_OBF 0x01 /* Output buffer full */
#define ACPI_EC_FLAG_IBF 0x02 /* Input buffer full */
+#define ACPI_EC_FLAG_BURST 0x10 /* burst mode */
#define ACPI_EC_FLAG_SCI 0x20 /* EC-SCI occurred */
#define ACPI_EC_EVENT_OBF 0x01 /* Output buffer full */
#define ACPI_EC_EVENT_IBE 0x02 /* Input buffer empty */
-#define ACPI_EC_UDELAY 100 /* Poll @ 100us increments */
-#define ACPI_EC_UDELAY_COUNT 1000 /* Wait 10ms max. during EC ops */
+#define ACPI_EC_DELAY 50 /* Wait 50ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_COMMAND_READ 0x80
#define ACPI_EC_COMMAND_WRITE 0x81
+#define ACPI_EC_BURST_ENABLE 0x82
+#define ACPI_EC_BURST_DISABLE 0x83
#define ACPI_EC_COMMAND_QUERY 0x84
static int acpi_ec_add (struct acpi_device *device);
@@ -87,7 +90,11 @@ struct acpi_ec {
struct acpi_generic_address command_addr;
struct acpi_generic_address data_addr;
unsigned long global_lock;
- spinlock_t lock;
+ unsigned int expect_event;
+ atomic_t leaving_burst; /* 0 : No, 1 : Yes, 2: abort*/
+ atomic_t pending_gpe;
+ struct semaphore sem;
+ wait_queue_head_t wait;
};
/* If we find an EC via the ECDT, we need to keep a ptr to its context */
@@ -100,42 +107,122 @@ static struct acpi_device *first_ec;
Transaction Management
-------------------------------------------------------------------------- */
-static int
-acpi_ec_wait (
- struct acpi_ec *ec,
- u8 event)
+static inline u32 acpi_ec_read_status(struct acpi_ec *ec)
{
- u32 acpi_ec_status = 0;
- u32 i = ACPI_EC_UDELAY_COUNT;
+ u32 status = 0;
- if (!ec)
- return -EINVAL;
+ acpi_hw_low_level_read(8, &status, &ec->status_addr);
+ return status;
+}
+
+static int acpi_ec_wait(struct acpi_ec *ec, unsigned int event)
+{
+ int result = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_wait");
- /* Poll the EC status register waiting for the event to occur. */
+ ec->expect_event = event;
+ smp_mb();
+
+ result = wait_event_interruptible_timeout(ec->wait,
+ !ec->expect_event,
+ msecs_to_jiffies(ACPI_EC_DELAY));
+
+ ec->expect_event = 0;
+ smp_mb();
+
+ if (result < 0){
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR," result = %d ", result));
+ return_VALUE(result);
+ }
+
+ /*
+ * Verify that the event in question has actually happened by
+ * querying EC status. Do the check even if operation timed-out
+ * to make sure that we did not miss interrupt.
+ */
switch (event) {
case ACPI_EC_EVENT_OBF:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (acpi_ec_status & ACPI_EC_FLAG_OBF)
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_OBF)
+ return_VALUE(0);
break;
+
case ACPI_EC_EVENT_IBE:
- do {
- acpi_hw_low_level_read(8, &acpi_ec_status, &ec->status_addr);
- if (!(acpi_ec_status & ACPI_EC_FLAG_IBF))
- return 0;
- udelay(ACPI_EC_UDELAY);
- } while (--i>0);
+ if (~acpi_ec_read_status(ec) & ACPI_EC_FLAG_IBF)
+ return_VALUE(0);
break;
- default:
- return -EINVAL;
}
- return -ETIME;
+ return_VALUE(-ETIME);
+}
+
+
+
+static int
+acpi_ec_enter_burst_mode (
+ struct acpi_ec *ec)
+{
+ u32 tmp = 0;
+ int status = 0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_enter_burst_mode");
+
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL &&
+ !(status & ACPI_EC_FLAG_BURST)){
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"entering burst mode \n"));
+ acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (status){
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR," status = %d\n", status));
+ return_VALUE(-EINVAL);
+ }
+ acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ if(tmp != 0x90 ) {/* Burst ACK byte*/
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"Ack failed \n"));
+ return_VALUE(-EINVAL);
+ }
+ } else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in burst mode \n"));
+ atomic_set(&ec->leaving_burst , 0);
+ return_VALUE(0);
}
+static int
+acpi_ec_leave_burst_mode (
+ struct acpi_ec *ec)
+{
+ int status =0;
+
+ ACPI_FUNCTION_TRACE("acpi_ec_leave_burst_mode");
+
+ atomic_set(&ec->leaving_burst , 1);
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL &&
+ (status & ACPI_EC_FLAG_BURST)){
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n"));
+ acpi_hw_low_level_write(8, ACPI_EC_BURST_DISABLE, &ec->command_addr);
+ status = acpi_ec_wait(ec, ACPI_EC_FLAG_IBF);
+ if (status){
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->wait fail\n"));
+ return_VALUE(-EINVAL);
+ }
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL &&
+ (status & ACPI_EC_FLAG_BURST)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,"------->status fail\n"));
+ return_VALUE(-EINVAL);
+ }
+ }else
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"already be in Non-burst mode \n"));
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"leaving burst mode\n"));
+
+ return_VALUE(0);
+}
static int
acpi_ec_read (
@@ -143,16 +230,15 @@ acpi_ec_read (
u8 address,
u32 *data)
{
- acpi_status status = AE_OK;
- int result = 0;
- unsigned long flags = 0;
- u32 glk = 0;
+ int status = 0;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_read");
if (!ec || !data)
return_VALUE(-EINVAL);
+retry:
*data = 0;
if (ec->global_lock) {
@@ -160,32 +246,50 @@ acpi_ec_read (
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
}
-
- spin_lock_irqsave(&ec->lock, flags);
+
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
+
+ if(acpi_ec_enter_burst_mode(ec))
+ goto end;
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_READ, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ if (status) {
goto end;
+ }
acpi_hw_low_level_write(8, address, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
+ status= acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (status){
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end;
-
+ }
acpi_hw_low_level_read(8, data, &ec->data_addr);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Read [%02x] from address [%02x]\n",
*data, address));
-
+
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ acpi_ec_leave_burst_mode(ec);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ if(atomic_read(&ec->leaving_burst) == 2){
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
+ while(atomic_read(&ec->pending_gpe)){
+ msleep(1);
+ }
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ goto retry;
+ }
+
+ return_VALUE(status);
}
@@ -195,49 +299,80 @@ acpi_ec_write (
u8 address,
u8 data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int status = 0;
+ u32 glk;
+ u32 tmp;
ACPI_FUNCTION_TRACE("acpi_ec_write");
if (!ec)
return_VALUE(-EINVAL);
-
+retry:
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status))
return_VALUE(-ENODEV);
}
- spin_lock_irqsave(&ec->lock, flags);
+ WARN_ON(in_interrupt());
+ down(&ec->sem);
+
+ if(acpi_ec_enter_burst_mode(ec))
+ goto end;
+
+ status = acpi_ec_read_status(ec);
+ if (status != -EINVAL &&
+ !(status & ACPI_EC_FLAG_BURST)){
+ acpi_hw_low_level_write(8, ACPI_EC_BURST_ENABLE, &ec->command_addr);
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (status)
+ goto end;
+ acpi_hw_low_level_read(8, &tmp, &ec->data_addr);
+ if(tmp != 0x90 ) /* Burst ACK byte*/
+ goto end;
+ }
+ /*Now we are in burst mode*/
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_WRITE, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ if (status){
goto end;
+ }
acpi_hw_low_level_write(8, address, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ if (status){
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end;
+ }
acpi_hw_low_level_write(8, data, &ec->data_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
- if (result)
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_IBE);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ if (status)
goto end;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Wrote [%02x] to address [%02x]\n",
data, address));
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ acpi_ec_leave_burst_mode(ec);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ if(atomic_read(&ec->leaving_burst) == 2){
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
+ while(atomic_read(&ec->pending_gpe)){
+ msleep(1);
+ }
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ goto retry;
+ }
+
+ return_VALUE(status);
}
/*
@@ -289,16 +424,13 @@ acpi_ec_query (
struct acpi_ec *ec,
u32 *data)
{
- int result = 0;
- acpi_status status = AE_OK;
- unsigned long flags = 0;
- u32 glk = 0;
+ int status = 0;
+ u32 glk;
ACPI_FUNCTION_TRACE("acpi_ec_query");
if (!ec || !data)
return_VALUE(-EINVAL);
-
*data = 0;
if (ec->global_lock) {
@@ -307,29 +439,39 @@ acpi_ec_query (
return_VALUE(-ENODEV);
}
+ down(&ec->sem);
+ if(acpi_ec_enter_burst_mode(ec))
+ goto end;
/*
* Query the EC to find out which _Qxx method we need to evaluate.
* Note that successful completion of the query causes the ACPI_EC_SCI
* bit to be cleared (and thus clearing the interrupt source).
*/
- spin_lock_irqsave(&ec->lock, flags);
-
acpi_hw_low_level_write(8, ACPI_EC_COMMAND_QUERY, &ec->command_addr);
- result = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
- if (result)
+ status = acpi_ec_wait(ec, ACPI_EC_EVENT_OBF);
+ if (status){
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
goto end;
-
+ }
+
acpi_hw_low_level_read(8, data, &ec->data_addr);
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
if (!*data)
- result = -ENODATA;
+ status = -ENODATA;
end:
- spin_unlock_irqrestore(&ec->lock, flags);
+ acpi_ec_leave_burst_mode(ec);
+ up(&ec->sem);
if (ec->global_lock)
acpi_release_global_lock(glk);
- return_VALUE(result);
+ if(atomic_read(&ec->leaving_burst) == 2){
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,"aborted, retry ...\n"));
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+ status = -ENODATA;
+ }
+ return_VALUE(status);
}
@@ -347,42 +489,29 @@ acpi_ec_gpe_query (
void *ec_cxt)
{
struct acpi_ec *ec = (struct acpi_ec *) ec_cxt;
- u32 value = 0;
- unsigned long flags = 0;
+ u32 value;
+ int result = -ENODATA;
static char object_name[5] = {'_','Q','0','0','\0'};
const char hex[] = {'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
ACPI_FUNCTION_TRACE("acpi_ec_gpe_query");
- if (!ec_cxt)
- goto end;
-
- spin_lock_irqsave(&ec->lock, flags);
- acpi_hw_low_level_read(8, &value, &ec->command_addr);
- spin_unlock_irqrestore(&ec->lock, flags);
+ if (acpi_ec_read_status(ec) & ACPI_EC_FLAG_SCI)
+ result = acpi_ec_query(ec, &value);
- /* TBD: Implement asynch events!
- * NOTE: All we care about are EC-SCI's. Other EC events are
- * handled via polling (yuck!). This is because some systems
- * treat EC-SCIs as level (versus EDGE!) triggered, preventing
- * a purely interrupt-driven approach (grumble, grumble).
- */
- if (!(value & ACPI_EC_FLAG_SCI))
+ if (result)
goto end;
- if (acpi_ec_query(ec, &value))
- goto end;
-
object_name[2] = hex[((value >> 4) & 0x0F)];
object_name[3] = hex[(value & 0x0F)];
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Evaluating %s\n", object_name));
acpi_evaluate_object(ec->handle, object_name, NULL, NULL);
-
-end:
- acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
+end:
+ atomic_dec(&ec->pending_gpe);
+ return;
}
static u32
@@ -390,6 +519,7 @@ acpi_ec_gpe_handler (
void *data)
{
acpi_status status = AE_OK;
+ u32 value;
struct acpi_ec *ec = (struct acpi_ec *) data;
if (!ec)
@@ -397,13 +527,41 @@ acpi_ec_gpe_handler (
acpi_disable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
- status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
- acpi_ec_gpe_query, ec);
+ value = acpi_ec_read_status(ec);
- if (status == AE_OK)
- return ACPI_INTERRUPT_HANDLED;
- else
- return ACPI_INTERRUPT_NOT_HANDLED;
+ if((value & ACPI_EC_FLAG_IBF) &&
+ !(value & ACPI_EC_FLAG_BURST) &&
+ (atomic_read(&ec->leaving_burst) == 0)) {
+ /*
+ * the embedded controller disables
+ * burst mode for any reason other
+ * than the burst disable command
+ * to process critical event.
+ */
+ atomic_set(&ec->leaving_burst , 2); /* block current pending transaction
+ and retry */
+ wake_up(&ec->wait);
+ }else {
+ if ((ec->expect_event == ACPI_EC_EVENT_OBF &&
+ (value & ACPI_EC_FLAG_OBF)) ||
+ (ec->expect_event == ACPI_EC_EVENT_IBE &&
+ !(value & ACPI_EC_FLAG_IBF))) {
+ ec->expect_event = 0;
+ wake_up(&ec->wait);
+ return ACPI_INTERRUPT_HANDLED;
+ }
+ }
+
+ if (value & ACPI_EC_FLAG_SCI){
+ atomic_add(1, &ec->pending_gpe) ;
+ status = acpi_os_queue_for_execution(OSD_PRIORITY_GPE,
+ acpi_ec_gpe_query, ec);
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
+ }
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_ISR);
+ return status == AE_OK ?
+ ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
}
/* --------------------------------------------------------------------------
@@ -421,10 +579,8 @@ acpi_ec_space_setup (
* The EC object is in the handler context and is needed
* when calling the acpi_ec_space_handler.
*/
- if(function == ACPI_REGION_DEACTIVATE)
- *return_context = NULL;
- else
- *return_context = handler_context;
+ *return_context = (function != ACPI_REGION_DEACTIVATE) ?
+ handler_context : NULL;
return AE_OK;
}
@@ -441,7 +597,7 @@ acpi_ec_space_handler (
{
int result = 0;
struct acpi_ec *ec = NULL;
- u32 temp = 0;
+ u64 temp = *value;
acpi_integer f_v = 0;
int i = 0;
@@ -450,10 +606,9 @@ acpi_ec_space_handler (
if ((address > 0xFF) || !value || !handler_context)
return_VALUE(AE_BAD_PARAMETER);
- if(bit_width != 8) {
+ if (bit_width != 8 && acpi_strict) {
printk(KERN_WARNING PREFIX "acpi_ec_space_handler: bit_width should be 8\n");
- if (acpi_strict)
- return_VALUE(AE_BAD_PARAMETER);
+ return_VALUE(AE_BAD_PARAMETER);
}
ec = (struct acpi_ec *) handler_context;
@@ -461,11 +616,11 @@ acpi_ec_space_handler (
next_byte:
switch (function) {
case ACPI_READ:
- result = acpi_ec_read(ec, (u8) address, &temp);
- *value = (acpi_integer) temp;
+ temp = 0;
+ result = acpi_ec_read(ec, (u8) address, (u32 *)&temp);
break;
case ACPI_WRITE:
- result = acpi_ec_write(ec, (u8) address, (u8) *value);
+ result = acpi_ec_write(ec, (u8) address, (u8) temp);
break;
default:
result = -EINVAL;
@@ -474,19 +629,18 @@ next_byte:
}
bit_width -= 8;
- if(bit_width){
-
- if(function == ACPI_READ)
- f_v |= (acpi_integer) (*value) << 8*i;
- if(function == ACPI_WRITE)
- (*value) >>=8;
+ if (bit_width) {
+ if (function == ACPI_READ)
+ f_v |= temp << 8 * i;
+ if (function == ACPI_WRITE)
+ temp >>= 8;
i++;
+ address++;
goto next_byte;
}
-
- if(function == ACPI_READ){
- f_v |= (acpi_integer) (*value) << 8*i;
+ if (function == ACPI_READ) {
+ f_v |= temp << 8 * i;
*value = f_v;
}
@@ -505,8 +659,6 @@ out:
default:
return_VALUE(AE_OK);
}
-
-
}
@@ -533,6 +685,7 @@ acpi_ec_read_info (struct seq_file *seq, void *offset)
(u32) ec->status_addr.address, (u32) ec->data_addr.address);
seq_printf(seq, "use global lock: %s\n",
ec->global_lock?"yes":"no");
+ acpi_enable_gpe(NULL, ec->gpe_bit, ACPI_NOT_ISR);
end:
return_VALUE(0);
@@ -555,7 +708,7 @@ static int
acpi_ec_add_fs (
struct acpi_device *device)
{
- struct proc_dir_entry *entry = NULL;
+ struct proc_dir_entry *entry;
ACPI_FUNCTION_TRACE("acpi_ec_add_fs");
@@ -606,9 +759,9 @@ static int
acpi_ec_add (
struct acpi_device *device)
{
- int result = 0;
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ int result;
+ acpi_status status;
+ struct acpi_ec *ec;
unsigned long uid;
ACPI_FUNCTION_TRACE("acpi_ec_add");
@@ -623,7 +776,10 @@ acpi_ec_add (
ec->handle = device->handle;
ec->uid = -1;
- spin_lock_init(&ec->lock);
+ atomic_set(&ec->pending_gpe, 0);
+ atomic_set(&ec->leaving_burst , 1);
+ init_MUTEX(&ec->sem);
+ init_waitqueue_head(&ec->wait);
strcpy(acpi_device_name(device), ACPI_EC_DEVICE_NAME);
strcpy(acpi_device_class(device), ACPI_EC_CLASS);
acpi_driver_data(device) = ec;
@@ -637,7 +793,7 @@ acpi_ec_add (
if (ec_ecdt && ec_ecdt->uid == uid) {
acpi_remove_address_space_handler(ACPI_ROOT_OBJECT,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler);
-
+
acpi_remove_gpe_handler(NULL, ec_ecdt->gpe_bit, &acpi_ec_gpe_handler);
kfree(ec_ecdt);
@@ -677,7 +833,7 @@ acpi_ec_remove (
struct acpi_device *device,
int type)
{
- struct acpi_ec *ec = NULL;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_remove");
@@ -732,8 +888,8 @@ static int
acpi_ec_start (
struct acpi_device *device)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_start");
@@ -789,8 +945,8 @@ acpi_ec_stop (
struct acpi_device *device,
int type)
{
- acpi_status status = AE_OK;
- struct acpi_ec *ec = NULL;
+ acpi_status status;
+ struct acpi_ec *ec;
ACPI_FUNCTION_TRACE("acpi_ec_stop");
@@ -832,7 +988,6 @@ acpi_fake_ecdt_callback (
status = acpi_evaluate_integer(handle, "_GPE", NULL, &ec_ecdt->gpe_bit);
if (ACPI_FAILURE(status))
return status;
- spin_lock_init(&ec_ecdt->lock);
ec_ecdt->global_lock = TRUE;
ec_ecdt->handle = handle;
@@ -890,7 +1045,7 @@ acpi_ec_get_real_ecdt(void)
acpi_status status;
struct acpi_table_ecdt *ecdt_ptr;
- status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
+ status = acpi_get_firmware_table("ECDT", 1, ACPI_LOGICAL_ADDRESSING,
(struct acpi_table_header **) &ecdt_ptr);
if (ACPI_FAILURE(status))
return -ENODEV;
@@ -905,11 +1060,12 @@ acpi_ec_get_real_ecdt(void)
return -ENOMEM;
memset(ec_ecdt, 0, sizeof(struct acpi_ec));
+ init_MUTEX(&ec_ecdt->sem);
+ init_waitqueue_head(&ec_ecdt->wait);
ec_ecdt->command_addr = ecdt_ptr->ec_control;
ec_ecdt->status_addr = ecdt_ptr->ec_control;
ec_ecdt->data_addr = ecdt_ptr->ec_data;
ec_ecdt->gpe_bit = ecdt_ptr->gpe_bit;
- spin_lock_init(&ec_ecdt->lock);
/* use the GL just to be safe */
ec_ecdt->global_lock = TRUE;
ec_ecdt->uid = ecdt_ptr->uid;
@@ -978,7 +1134,7 @@ error:
static int __init acpi_ec_init (void)
{
- int result = 0;
+ int result;
ACPI_FUNCTION_TRACE("acpi_ec_init");
diff --git a/drivers/acpi/events/evevent.c b/drivers/acpi/events/evevent.c
index 2a213604ae51..dd3a72a869f4 100644
--- a/drivers/acpi/events/evevent.c
+++ b/drivers/acpi/events/evevent.c
@@ -47,6 +47,16 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME ("evevent")
+/* Local prototypes */
+
+static acpi_status
+acpi_ev_fixed_event_initialize (
+ void);
+
+static u32
+acpi_ev_fixed_event_dispatch (
+ u32 event);
+
/*******************************************************************************
*
@@ -56,7 +66,7 @@
*
* RETURN: Status
*
- * DESCRIPTION: Initialize global data structures for events.
+ * DESCRIPTION: Initialize global data structures for ACPI events (Fixed, GPE)
*
******************************************************************************/
@@ -78,9 +88,9 @@ acpi_ev_initialize_events (
}
/*
- * Initialize the Fixed and General Purpose Events. This is
- * done prior to enabling SCIs to prevent interrupts from
- * occurring before handers are installed.
+ * Initialize the Fixed and General Purpose Events. This is done prior to
+ * enabling SCIs to prevent interrupts from occurring before the handlers are
+ * installed.
*/
status = acpi_ev_fixed_event_initialize ();
if (ACPI_FAILURE (status)) {
@@ -161,7 +171,7 @@ acpi_ev_install_xrupt_handlers (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ev_fixed_event_initialize (
void)
{
@@ -180,7 +190,8 @@ acpi_ev_fixed_event_initialize (
/* Enable the fixed event */
if (acpi_gbl_fixed_event_info[i].enable_register_id != 0xFF) {
- status = acpi_set_register (acpi_gbl_fixed_event_info[i].enable_register_id,
+ status = acpi_set_register (
+ acpi_gbl_fixed_event_info[i].enable_register_id,
0, ACPI_MTX_LOCK);
if (ACPI_FAILURE (status)) {
return (status);
@@ -200,7 +211,7 @@ acpi_ev_fixed_event_initialize (
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
*
- * DESCRIPTION: Checks the PM status register for fixed events
+ * DESCRIPTION: Checks the PM status register for active fixed events
*
******************************************************************************/
@@ -221,8 +232,10 @@ acpi_ev_fixed_event_detect (
* Read the fixed feature status and enable registers, as all the cases
* depend on their values. Ignore errors here.
*/
- (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS, &fixed_status);
- (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE, &fixed_enable);
+ (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
+ &fixed_status);
+ (void) acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_ENABLE,
+ &fixed_enable);
ACPI_DEBUG_PRINT ((ACPI_DB_INTERRUPTS,
"Fixed Event Block: Enable %08X Status %08X\n",
@@ -259,7 +272,7 @@ acpi_ev_fixed_event_detect (
*
******************************************************************************/
-u32
+static u32
acpi_ev_fixed_event_dispatch (
u32 event)
{
diff --git a/drivers/acpi/events/evgpe.c b/drivers/acpi/events/evgpe.c
index 118d72ac7c76..081120b109ba 100644
--- a/drivers/acpi/events/evgpe.c
+++ b/drivers/acpi/events/evgpe.c
@@ -48,6 +48,12 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME ("evgpe")
+/* Local prototypes */
+
+static void ACPI_SYSTEM_XFACE
+acpi_ev_asynch_execute_gpe_method (
+ void *context);
+
/*******************************************************************************
*
@@ -335,8 +341,10 @@ acpi_ev_get_gpe_event_info (
gpe_block = acpi_gbl_gpe_fadt_blocks[i];
if (gpe_block) {
if ((gpe_number >= gpe_block->block_base_number) &&
- (gpe_number < gpe_block->block_base_number + (gpe_block->register_count * 8))) {
- return (&gpe_block->event_info[gpe_number - gpe_block->block_base_number]);
+ (gpe_number < gpe_block->block_base_number +
+ (gpe_block->register_count * 8))) {
+ return (&gpe_block->event_info[gpe_number -
+ gpe_block->block_base_number]);
}
}
}
@@ -437,7 +445,7 @@ acpi_ev_gpe_detect (
"Read GPE Register at GPE%X: Status=%02X, Enable=%02X\n",
gpe_register_info->base_gpe_number, status_reg, enable_reg));
- /* First check if there is anything active at all in this register */
+ /* Check if there is anything active at all in this register */
enabled_status_byte = (u8) (status_reg & enable_reg);
if (!enabled_status_byte) {
@@ -457,8 +465,8 @@ acpi_ev_gpe_detect (
* or method.
*/
int_status |= acpi_ev_gpe_dispatch (
- &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j],
- (u32) j + gpe_register_info->base_gpe_number);
+ &gpe_block->event_info[(i * ACPI_GPE_REGISTER_WIDTH) + j],
+ (u32) j + gpe_register_info->base_gpe_number);
}
}
}
@@ -523,7 +531,8 @@ acpi_ev_asynch_execute_gpe_method (
* Take a snapshot of the GPE info for this level - we copy the
* info to prevent a race condition with remove_handler/remove_block.
*/
- ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info, sizeof (struct acpi_gpe_event_info));
+ ACPI_MEMCPY (&local_gpe_event_info, gpe_event_info,
+ sizeof (struct acpi_gpe_event_info));
status = acpi_ut_release_mutex (ACPI_MTX_EVENTS);
if (ACPI_FAILURE (status)) {
@@ -534,7 +543,8 @@ acpi_ev_asynch_execute_gpe_method (
* 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) {
+ if ((local_gpe_event_info.flags & ACPI_GPE_DISPATCH_MASK) ==
+ ACPI_GPE_DISPATCH_METHOD) {
/*
* Invoke the GPE Method (_Lxx, _Exx) i.e., evaluate the _Lxx/_Exx
* control method that corresponds to this GPE
@@ -553,7 +563,8 @@ acpi_ev_asynch_execute_gpe_method (
}
}
- if ((local_gpe_event_info.flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
+ 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.
@@ -575,7 +586,7 @@ acpi_ev_asynch_execute_gpe_method (
*
* FUNCTION: acpi_ev_gpe_dispatch
*
- * PARAMETERS: gpe_event_info - info for this GPE
+ * PARAMETERS: gpe_event_info - Info for this GPE
* gpe_number - Number relative to the parent GPE block
*
* RETURN: INTERRUPT_HANDLED or INTERRUPT_NOT_HANDLED
@@ -602,10 +613,12 @@ acpi_ev_gpe_dispatch (
* If edge-triggered, clear the GPE status bit now. Note that
* level-triggered events are cleared after the GPE is serviced.
*/
- if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_EDGE_TRIGGERED) {
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+ ACPI_GPE_EDGE_TRIGGERED) {
status = acpi_hw_clear_gpe (gpe_event_info);
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
+ ACPI_REPORT_ERROR ((
+ "acpi_ev_gpe_dispatch: %s, Unable to clear GPE[%2X]\n",
acpi_format_exception (status), gpe_number));
return_VALUE (ACPI_INTERRUPT_NOT_HANDLED);
}
@@ -639,7 +652,8 @@ acpi_ev_gpe_dispatch (
/* It is now safe to clear level-triggered events. */
- if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) == ACPI_GPE_LEVEL_TRIGGERED) {
+ if ((gpe_event_info->flags & ACPI_GPE_XRUPT_TYPE_MASK) ==
+ ACPI_GPE_LEVEL_TRIGGERED) {
status = acpi_hw_clear_gpe (gpe_event_info);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
@@ -704,7 +718,6 @@ acpi_ev_gpe_dispatch (
#ifdef ACPI_GPE_NOTIFY_CHECK
-
/*******************************************************************************
* TBD: NOT USED, PROTOTYPE ONLY AND WILL PROBABLY BE REMOVED
*
diff --git a/drivers/acpi/events/evgpeblk.c b/drivers/acpi/events/evgpeblk.c
index 00d981f53c6a..84186a7d17b2 100644
--- a/drivers/acpi/events/evgpeblk.c
+++ b/drivers/acpi/events/evgpeblk.c
@@ -48,6 +48,39 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME ("evgpeblk")
+/* Local prototypes */
+
+static acpi_status
+acpi_ev_save_method_info (
+ acpi_handle obj_handle,
+ u32 level,
+ void *obj_desc,
+ void **return_value);
+
+static acpi_status
+acpi_ev_match_prw_and_gpe (
+ acpi_handle obj_handle,
+ u32 level,
+ void *info,
+ void **return_value);
+
+static struct acpi_gpe_xrupt_info *
+acpi_ev_get_gpe_xrupt_block (
+ u32 interrupt_level);
+
+static acpi_status
+acpi_ev_delete_gpe_xrupt (
+ struct acpi_gpe_xrupt_info *gpe_xrupt);
+
+static acpi_status
+acpi_ev_install_gpe_block (
+ struct acpi_gpe_block_info *gpe_block,
+ u32 interrupt_level);
+
+static acpi_status
+acpi_ev_create_gpe_info_blocks (
+ struct acpi_gpe_block_info *gpe_block);
+
/*******************************************************************************
*
@@ -155,7 +188,7 @@ unlock_and_exit:
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ev_delete_gpe_handlers
*
@@ -190,7 +223,8 @@ acpi_ev_delete_gpe_handlers (
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) {
+ 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;
@@ -471,7 +505,7 @@ acpi_ev_get_gpe_xrupt_block (
ACPI_FUNCTION_TRACE ("ev_get_gpe_xrupt_block");
- /* No need for spin lock since we are not changing any list elements here */
+ /* No need for lock since we are not changing any list elements here */
next_gpe_xrupt = acpi_gbl_gpe_xrupt_list_head;
while (next_gpe_xrupt) {
@@ -619,7 +653,7 @@ acpi_ev_install_gpe_block (
goto unlock_and_exit;
}
- /* Install the new block at the end of the list for this interrupt with lock */
+ /* Install the new block at the end of the list with lock */
acpi_os_acquire_lock (acpi_gbl_gpe_lock, ACPI_NOT_ISR);
if (gpe_xrupt_block->gpe_block_list_head) {
@@ -756,10 +790,12 @@ acpi_ev_create_gpe_info_blocks (
* per register. Initialization to zeros is sufficient.
*/
gpe_event_info = ACPI_MEM_CALLOCATE (
- ((acpi_size) gpe_block->register_count * ACPI_GPE_REGISTER_WIDTH) *
+ ((acpi_size) gpe_block->register_count *
+ ACPI_GPE_REGISTER_WIDTH) *
sizeof (struct acpi_gpe_event_info));
if (!gpe_event_info) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not allocate the gpe_event_info table\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not allocate the gpe_event_info table\n"));
status = AE_NO_MEMORY;
goto error_exit;
}
@@ -899,7 +935,8 @@ acpi_ev_create_gpe_block (
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));
+ ACPI_MEMCPY (&gpe_block->block_address, gpe_block_address,
+ sizeof (struct acpi_generic_address));
/* Create the register_info and event_info sub-structures */
@@ -1061,8 +1098,9 @@ acpi_ev_gpe_initialize (
/* Install GPE Block 0 */
- status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe0_blk,
- register_count0, 0, acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device,
+ &acpi_gbl_FADT->xgpe0_blk, register_count0, 0,
+ acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[0]);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR ((
@@ -1094,8 +1132,9 @@ acpi_ev_gpe_initialize (
else {
/* Install GPE Block 1 */
- status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device, &acpi_gbl_FADT->xgpe1_blk,
- register_count1, acpi_gbl_FADT->gpe1_base,
+ status = acpi_ev_create_gpe_block (acpi_gbl_fadt_gpe_device,
+ &acpi_gbl_FADT->xgpe1_blk, register_count1,
+ acpi_gbl_FADT->gpe1_base,
acpi_gbl_FADT->sci_int, &acpi_gbl_gpe_fadt_blocks[1]);
if (ACPI_FAILURE (status)) {
@@ -1109,7 +1148,7 @@ acpi_ev_gpe_initialize (
* space. However, GPE0 always starts at GPE number zero.
*/
gpe_number_max = acpi_gbl_FADT->gpe1_base +
- ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
+ ((register_count1 * ACPI_GPE_REGISTER_WIDTH) - 1);
}
}
diff --git a/drivers/acpi/events/evmisc.c b/drivers/acpi/events/evmisc.c
index 2548efa7a45f..659e90956112 100644
--- a/drivers/acpi/events/evmisc.c
+++ b/drivers/acpi/events/evmisc.c
@@ -50,6 +50,35 @@
ACPI_MODULE_NAME ("evmisc")
+#ifdef ACPI_DEBUG_OUTPUT
+static const char *acpi_notify_value_names[] =
+{
+ "Bus Check",
+ "Device Check",
+ "Device Wake",
+ "Eject request",
+ "Device Check Light",
+ "Frequency Mismatch",
+ "Bus Mode Mismatch",
+ "Power Fault"
+};
+#endif
+
+/* Local prototypes */
+
+static void ACPI_SYSTEM_XFACE
+acpi_ev_notify_dispatch (
+ void *context);
+
+static void ACPI_SYSTEM_XFACE
+acpi_ev_global_lock_thread (
+ void *context);
+
+static u32
+acpi_ev_global_lock_handler (
+ void *context);
+
+
/*******************************************************************************
*
* FUNCTION: acpi_ev_is_notify_object
@@ -98,20 +127,6 @@ acpi_ev_is_notify_object (
*
******************************************************************************/
-#ifdef ACPI_DEBUG_OUTPUT
-static const char *acpi_notify_value_names[] =
-{
- "Bus Check",
- "Device Check",
- "Device Wake",
- "Eject request",
- "Device Check Light",
- "Frequency Mismatch",
- "Bus Mode Mismatch",
- "Power Fault"
-};
-#endif
-
acpi_status
acpi_ev_queue_notify_request (
struct acpi_namespace_node *node,
@@ -128,9 +143,10 @@ acpi_ev_queue_notify_request (
/*
* For value 3 (Ejection Request), some device method may need to be run.
- * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need to be run.
+ * For value 2 (Device Wake) if _PRW exists, the _PS0 method may need
+ * to be run.
* For value 0x80 (Status Change) on the power button or sleep button,
- * initiate soft-off or sleep operation?
+ * initiate soft-off or sleep operation?
*/
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"Dispatching Notify(%X) on node %p\n", notify_value, node));
@@ -140,8 +156,9 @@ 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",
- notify_value));
+ 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 */
@@ -210,7 +227,7 @@ acpi_ev_queue_notify_request (
*
* FUNCTION: acpi_ev_notify_dispatch
*
- * PARAMETERS: Context - To be passsed to the notify handler
+ * PARAMETERS: Context - To be passed to the notify handler
*
* RETURN: None.
*
@@ -219,7 +236,7 @@ acpi_ev_queue_notify_request (
*
******************************************************************************/
-void ACPI_SYSTEM_XFACE
+static void ACPI_SYSTEM_XFACE
acpi_ev_notify_dispatch (
void *context)
{
@@ -234,7 +251,8 @@ acpi_ev_notify_dispatch (
/*
* We will invoke a global notify handler if installed.
- * This is done _before_ we invoke the per-device handler attached to the device.
+ * This is done _before_ we invoke the per-device handler attached
+ * to the device.
*/
if (notify_info->notify.value <= ACPI_MAX_SYS_NOTIFY) {
/* Global system notification handler */
@@ -256,15 +274,17 @@ acpi_ev_notify_dispatch (
/* Invoke the system handler first, if present */
if (global_handler) {
- global_handler (notify_info->notify.node, notify_info->notify.value, global_context);
+ global_handler (notify_info->notify.node, notify_info->notify.value,
+ global_context);
}
/* Now invoke the per-device handler, if present */
handler_obj = notify_info->notify.handler_obj;
if (handler_obj) {
- handler_obj->notify.handler (notify_info->notify.node, notify_info->notify.value,
- handler_obj->notify.context);
+ handler_obj->notify.handler (notify_info->notify.node,
+ notify_info->notify.value,
+ handler_obj->notify.context);
}
/* All done with the info object */
@@ -370,7 +390,8 @@ acpi_ev_global_lock_handler (
******************************************************************************/
acpi_status
-acpi_ev_init_global_lock_handler (void)
+acpi_ev_init_global_lock_handler (
+ void)
{
acpi_status status;
@@ -380,7 +401,7 @@ acpi_ev_init_global_lock_handler (void)
acpi_gbl_global_lock_present = TRUE;
status = acpi_install_fixed_event_handler (ACPI_EVENT_GLOBAL,
- acpi_ev_global_lock_handler, NULL);
+ acpi_ev_global_lock_handler, NULL);
/*
* If the global lock does not exist on this platform, the attempt
@@ -433,8 +454,10 @@ acpi_ev_acquire_global_lock (
acpi_gbl_global_lock_thread_count++;
- /* If we (OS side vs. BIOS side) have the hardware lock already, we are done */
-
+ /*
+ * If we (OS side vs. BIOS side) have the hardware lock already,
+ * we are done
+ */
if (acpi_gbl_global_lock_acquired) {
return_ACPI_STATUS (AE_OK);
}
@@ -480,7 +503,8 @@ acpi_ev_acquire_global_lock (
******************************************************************************/
acpi_status
-acpi_ev_release_global_lock (void)
+acpi_ev_release_global_lock (
+ void)
{
u8 pending = FALSE;
acpi_status status = AE_OK;
@@ -490,7 +514,8 @@ acpi_ev_release_global_lock (void)
if (!acpi_gbl_global_lock_thread_count) {
- ACPI_REPORT_WARNING(("Cannot release HW Global Lock, it has not been acquired\n"));
+ ACPI_REPORT_WARNING((
+ "Cannot release HW Global Lock, it has not been acquired\n"));
return_ACPI_STATUS (AE_NOT_ACQUIRED);
}
@@ -515,7 +540,8 @@ acpi_ev_release_global_lock (void)
* register
*/
if (pending) {
- status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE, 1, ACPI_MTX_LOCK);
+ status = acpi_set_register (ACPI_BITREG_GLOBAL_LOCK_RELEASE,
+ 1, ACPI_MTX_LOCK);
}
return_ACPI_STATUS (status);
@@ -535,7 +561,8 @@ acpi_ev_release_global_lock (void)
******************************************************************************/
void
-acpi_ev_terminate (void)
+acpi_ev_terminate (
+ void)
{
acpi_native_uint i;
acpi_status status;
@@ -555,7 +582,8 @@ acpi_ev_terminate (void)
for (i = 0; i < ACPI_NUM_FIXED_EVENTS; i++) {
status = acpi_disable_event ((u32) i, 0);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not disable fixed event %d\n", (u32) i));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not disable fixed event %d\n", (u32) i));
}
}
@@ -567,7 +595,8 @@ acpi_ev_terminate (void)
status = acpi_ev_remove_sci_handler ();
if (ACPI_FAILURE(status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not remove SCI handler\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not remove SCI handler\n"));
}
}
diff --git a/drivers/acpi/events/evregion.c b/drivers/acpi/events/evregion.c
index 772342708a7a..a1d7276c5742 100644
--- a/drivers/acpi/events/evregion.c
+++ b/drivers/acpi/events/evregion.c
@@ -58,6 +58,22 @@ static u8 acpi_gbl_default_address_spaces[ACPI_NUM_DEFAULT_SPA
ACPI_ADR_SPACE_PCI_CONFIG,
ACPI_ADR_SPACE_DATA_TABLE};
+/* Local prototypes */
+
+static acpi_status
+acpi_ev_reg_run (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
+static acpi_status
+acpi_ev_install_handler (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
/*******************************************************************************
*
@@ -179,8 +195,8 @@ acpi_ev_initialize_op_regions (
*
* FUNCTION: acpi_ev_execute_reg_method
*
- * PARAMETERS: region_obj - Object structure
- * Function - Passed to _REG: On (1) or Off (0)
+ * PARAMETERS: region_obj - Region object
+ * Function - Passed to _REG: On (1) or Off (0)
*
* RETURN: Status
*
@@ -323,14 +339,16 @@ acpi_ev_address_space_dispatch (
if (!region_setup) {
/* No initialization routine, exit with error */
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No init routine for region(%p) [%s]\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "No init routine for region(%p) [%s]\n",
region_obj, acpi_ut_get_region_name (region_obj->region.space_id)));
return_ACPI_STATUS (AE_NOT_EXIST);
}
/*
- * We must exit the interpreter because the region setup will potentially
- * execute control methods (e.g., _REG method for this region)
+ * We must exit the interpreter because the region
+ * setup will potentially execute control methods
+ * (e.g., _REG method for this region)
*/
acpi_ex_exit_interpreter ();
@@ -621,7 +639,7 @@ acpi_ev_attach_region (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ev_install_handler (
acpi_handle obj_handle,
u32 level,
@@ -848,7 +866,8 @@ acpi_ev_install_space_handler (
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.
+ * handler twice. This can easily happen
+ * with PCI_Config space.
*/
status = AE_SAME_HANDLER;
goto unlock_and_exit;
@@ -1011,7 +1030,7 @@ acpi_ev_execute_reg_methods (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ev_reg_run (
acpi_handle obj_handle,
u32 level,
diff --git a/drivers/acpi/events/evrgnini.c b/drivers/acpi/events/evrgnini.c
index 4983a3378be5..95bc09c73a6a 100644
--- a/drivers/acpi/events/evrgnini.c
+++ b/drivers/acpi/events/evrgnini.c
@@ -61,7 +61,7 @@
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling, a nop for now
+ * DESCRIPTION: Setup a system_memory operation region
*
******************************************************************************/
@@ -115,7 +115,7 @@ acpi_ev_system_memory_region_setup (
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling
+ * DESCRIPTION: Setup a IO operation region
*
******************************************************************************/
@@ -144,14 +144,14 @@ acpi_ev_io_space_region_setup (
*
* FUNCTION: acpi_ev_pci_config_region_setup
*
- * PARAMETERS: Handle - 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
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling
+ * DESCRIPTION: Setup a PCI_Config operation region
*
* MUTEX: Assumes namespace is not locked
*
@@ -324,7 +324,7 @@ acpi_ev_pci_config_region_setup (
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling
+ * DESCRIPTION: Setup a pci_bAR operation region
*
* MUTEX: Assumes namespace is not locked
*
@@ -355,7 +355,7 @@ acpi_ev_pci_bar_region_setup (
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling
+ * DESCRIPTION: Setup a CMOS operation region
*
* MUTEX: Assumes namespace is not locked
*
@@ -386,7 +386,7 @@ acpi_ev_cmos_region_setup (
*
* RETURN: Status
*
- * DESCRIPTION: Do any prep work for region handling
+ * DESCRIPTION: Default region initialization
*
******************************************************************************/
diff --git a/drivers/acpi/events/evsci.c b/drivers/acpi/events/evsci.c
index 46b31995c827..f3123c26ae98 100644
--- a/drivers/acpi/events/evsci.c
+++ b/drivers/acpi/events/evsci.c
@@ -49,6 +49,12 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME ("evsci")
+/* Local prototypes */
+
+static u32 ACPI_SYSTEM_XFACE
+acpi_ev_sci_xrupt_handler (
+ void *context);
+
/*******************************************************************************
*
@@ -146,7 +152,8 @@ acpi_ev_gpe_xrupt_handler (
******************************************************************************/
u32
-acpi_ev_install_sci_handler (void)
+acpi_ev_install_sci_handler (
+ void)
{
u32 status = AE_OK;
@@ -180,7 +187,8 @@ acpi_ev_install_sci_handler (void)
******************************************************************************/
acpi_status
-acpi_ev_remove_sci_handler (void)
+acpi_ev_remove_sci_handler (
+ void)
{
acpi_status status;
diff --git a/drivers/acpi/events/evxface.c b/drivers/acpi/events/evxface.c
index 0bfec10a5f1e..4092d47f6758 100644
--- a/drivers/acpi/events/evxface.c
+++ b/drivers/acpi/events/evxface.c
@@ -64,6 +64,7 @@
* DESCRIPTION: Saves the pointer to the handler function
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_install_exception_handler (
@@ -457,7 +458,8 @@ acpi_remove_notify_handler (
/* Root Object */
if (device == ACPI_ROOT_OBJECT) {
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Removing notify handler for ROOT object.\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Removing notify handler for ROOT object.\n"));
if (((handler_type & ACPI_SYSTEM_NOTIFY) &&
!acpi_gbl_system_notify.handler) ||
@@ -564,8 +566,9 @@ EXPORT_SYMBOL(acpi_remove_notify_handler);
*
* FUNCTION: acpi_install_gpe_handler
*
- * PARAMETERS: gpe_number - The GPE number within the GPE block
- * gpe_block - GPE block (NULL == FADT GPEs)
+ * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
+ * defined GPEs)
+ * gpe_number - The GPE number within the GPE block
* Type - Whether this GPE should be treated as an
* edge- or level-triggered interrupt.
* Address - Address of the handler
@@ -662,8 +665,9 @@ EXPORT_SYMBOL(acpi_install_gpe_handler);
*
* FUNCTION: acpi_remove_gpe_handler
*
- * PARAMETERS: gpe_number - The event to remove a handler
- * gpe_block - GPE block (NULL == FADT GPEs)
+ * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
+ * defined GPEs)
+ * gpe_number - The event to remove a handler
* Address - Address of the handler
*
* RETURN: Status
@@ -766,7 +770,8 @@ EXPORT_SYMBOL(acpi_remove_gpe_handler);
* FUNCTION: acpi_acquire_global_lock
*
* PARAMETERS: Timeout - How long the caller is willing to wait
- * out_handle - A handle to the lock if acquired
+ * Handle - Where the handle to the lock is returned
+ * (if acquired)
*
* RETURN: Status
*
@@ -812,7 +817,7 @@ EXPORT_SYMBOL(acpi_acquire_global_lock);
*
* RETURN: Status
*
- * DESCRIPTION: Release the ACPI Global Lock
+ * DESCRIPTION: Release the ACPI Global Lock. The handle must be valid.
*
******************************************************************************/
diff --git a/drivers/acpi/events/evxfevnt.c b/drivers/acpi/events/evxfevnt.c
index fa8d5f25be62..f337dc2cc569 100644
--- a/drivers/acpi/events/evxfevnt.c
+++ b/drivers/acpi/events/evxfevnt.c
@@ -64,7 +64,8 @@
******************************************************************************/
acpi_status
-acpi_enable (void)
+acpi_enable (
+ void)
{
acpi_status status = AE_OK;
@@ -91,7 +92,8 @@ acpi_enable (void)
return_ACPI_STATUS (status);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Transition to ACPI mode successful\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "Transition to ACPI mode successful\n"));
}
return_ACPI_STATUS (status);
@@ -106,12 +108,13 @@ acpi_enable (void)
*
* RETURN: Status
*
- * DESCRIPTION: Transfers the system into LEGACY mode.
+ * DESCRIPTION: Transfers the system into LEGACY (non-ACPI) mode.
*
******************************************************************************/
acpi_status
-acpi_disable (void)
+acpi_disable (
+ void)
{
acpi_status status = AE_OK;
@@ -125,7 +128,8 @@ acpi_disable (void)
}
if (acpi_hw_get_mode() == ACPI_SYS_MODE_LEGACY) {
- ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "System is already in legacy (non-ACPI) mode\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "System is already in legacy (non-ACPI) mode\n"));
}
else {
/* Transition to LEGACY mode */
@@ -133,7 +137,8 @@ acpi_disable (void)
status = acpi_hw_set_mode (ACPI_SYS_MODE_LEGACY);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not exit ACPI mode to legacy mode"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not exit ACPI mode to legacy mode"));
return_ACPI_STATUS (status);
}
@@ -214,7 +219,7 @@ EXPORT_SYMBOL(acpi_enable_event);
*
* RETURN: Status
*
- * DESCRIPTION: Enable an ACPI event (general purpose)
+ * DESCRIPTION: Set the type of an individual GPE
*
******************************************************************************/
@@ -519,13 +524,12 @@ unlock_and_exit:
#ifdef ACPI_FUTURE_USAGE
-
/*******************************************************************************
*
* FUNCTION: acpi_get_event_status
*
* PARAMETERS: Event - The fixed event
- * Event Status - Where the current status of the event will
+ * event_status - Where the current status of the event will
* be returned
*
* RETURN: Status
@@ -571,7 +575,7 @@ acpi_get_event_status (
* PARAMETERS: gpe_device - Parent GPE Device
* gpe_number - GPE level within the GPE block
* Flags - Called from an ISR or not
- * Event Status - Where the current status of the event will
+ * event_status - Where the current status of the event will
* be returned
*
* RETURN: Status
@@ -775,4 +779,5 @@ unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return_ACPI_STATUS (status);
}
+
EXPORT_SYMBOL(acpi_remove_gpe_block);
diff --git a/drivers/acpi/executer/exconfig.c b/drivers/acpi/executer/exconfig.c
index ac3c061967f2..734b2f24af48 100644
--- a/drivers/acpi/executer/exconfig.c
+++ b/drivers/acpi/executer/exconfig.c
@@ -54,6 +54,14 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exconfig")
+/* Local prototypes */
+
+static acpi_status
+acpi_ex_add_table (
+ struct acpi_table_header *table,
+ struct acpi_namespace_node *parent_node,
+ union acpi_operand_object **ddb_handle);
+
/*******************************************************************************
*
@@ -70,7 +78,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_add_table (
struct acpi_table_header *table,
struct acpi_namespace_node *parent_node,
@@ -95,10 +103,10 @@ acpi_ex_add_table (
ACPI_MEMSET (&table_info, 0, sizeof (struct acpi_table_desc));
- table_info.type = ACPI_TABLE_SSDT;
- table_info.pointer = table;
- table_info.length = (acpi_size) table->length;
- table_info.allocation = ACPI_MEM_ALLOCATED;
+ table_info.type = ACPI_TABLE_SSDT;
+ table_info.pointer = table;
+ table_info.length = (acpi_size) table->length;
+ table_info.allocation = ACPI_MEM_ALLOCATED;
status = acpi_tb_install_table (&table_info);
if (ACPI_FAILURE (status)) {
@@ -226,11 +234,10 @@ acpi_ex_load_table_op (
start_node = parent_node;
}
- /*
- * Find the node referenced by the parameter_path_string
- */
+ /* Find the node referenced by the parameter_path_string */
+
status = acpi_ns_get_node_by_path (operand[4]->string.pointer, start_node,
- ACPI_NS_SEARCH_PARENT, &parameter_node);
+ ACPI_NS_SEARCH_PARENT, &parameter_node);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -248,7 +255,8 @@ acpi_ex_load_table_op (
if (parameter_node) {
/* Store the parameter data into the optional parameter object */
- status = acpi_ex_store (operand[5], ACPI_CAST_PTR (union acpi_operand_object, parameter_node),
+ status = acpi_ex_store (operand[5],
+ ACPI_CAST_PTR (union acpi_operand_object, parameter_node),
walk_state);
if (ACPI_FAILURE (status)) {
(void) acpi_ex_unload_table (ddb_handle);
@@ -371,7 +379,8 @@ acpi_ex_load_op (
goto cleanup;
}
- table_ptr = ACPI_CAST_PTR (struct acpi_table_header, buffer_desc->buffer.pointer);
+ table_ptr = ACPI_CAST_PTR (struct acpi_table_header,
+ buffer_desc->buffer.pointer);
/* Sanity check the table length */
diff --git a/drivers/acpi/executer/exconvrt.c b/drivers/acpi/executer/exconvrt.c
index df7ba1219bf6..97856c48bd74 100644
--- a/drivers/acpi/executer/exconvrt.c
+++ b/drivers/acpi/executer/exconvrt.c
@@ -50,6 +50,15 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exconvrt")
+/* Local prototypes */
+
+static u32
+acpi_ex_convert_to_ascii (
+ acpi_integer integer,
+ u16 base,
+ u8 *string,
+ u8 max_length);
+
/*******************************************************************************
*
@@ -115,9 +124,8 @@ acpi_ex_convert_to_integer (
*/
result = 0;
- /*
- * String conversion is different than Buffer conversion
- */
+ /* String conversion is different than Buffer conversion */
+
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_STRING:
@@ -168,9 +176,8 @@ acpi_ex_convert_to_integer (
break;
}
- /*
- * Create a new integer
- */
+ /* Create a new integer */
+
return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
if (!return_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
@@ -251,7 +258,8 @@ acpi_ex_convert_to_buffer (
* ASL/AML code that depends on the null being transferred to the new
* buffer.
*/
- return_desc = acpi_ut_create_buffer_object ((acpi_size) obj_desc->string.length + 1);
+ return_desc = acpi_ut_create_buffer_object (
+ (acpi_size) obj_desc->string.length + 1);
if (!return_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
@@ -291,7 +299,7 @@ acpi_ex_convert_to_buffer (
*
******************************************************************************/
-u32
+static u32
acpi_ex_convert_to_ascii (
acpi_integer integer,
u16 base,
@@ -357,8 +365,9 @@ acpi_ex_convert_to_ascii (
case 16:
- hex_length = ACPI_MUL_2 (data_width); /* 2 ascii hex chars per data byte */
+ /* hex_length: 2 ascii hex chars per data byte */
+ hex_length = ACPI_MUL_2 (data_width);
for (i = 0, j = (hex_length-1); i < hex_length; i++, j--) {
/* Get one hex digit, most significant digits first */
@@ -475,7 +484,7 @@ acpi_ex_convert_to_string (
/* Setup string length, base, and separator */
switch (type) {
- case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string operator */
+ case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by to_decimal_string */
/*
* From ACPI: "If Data is a buffer, it is converted to a string of
* decimal values separated by commas."
@@ -509,7 +518,7 @@ acpi_ex_convert_to_string (
string_length = (obj_desc->buffer.length * 3);
break;
- case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string operator */
+ case ACPI_EXPLICIT_CONVERT_HEX: /* Used by to_hex_string */
/*
* From ACPI: "If Data is a buffer, it is converted to a string of
* hexadecimal values separated by commas."
@@ -530,9 +539,8 @@ acpi_ex_convert_to_string (
return_ACPI_STATUS (AE_AML_STRING_LIMIT);
}
- /*
- * Create a new string object and string buffer
- */
+ /* Create a new string object and string buffer */
+
return_desc = acpi_ut_create_string_object ((acpi_size) string_length);
if (!return_desc) {
return_ACPI_STATUS (AE_NO_MEMORY);
@@ -551,8 +559,10 @@ acpi_ex_convert_to_string (
*new_buf++ = separator; /* each separated by a comma or space */
}
- /* Null terminate the string (overwrites final comma/space from above) */
-
+ /*
+ * Null terminate the string
+ * (overwrites final comma/space from above)
+ */
new_buf--;
*new_buf = 0;
break;
@@ -645,7 +655,6 @@ acpi_ex_convert_to_target_type (
case ACPI_TYPE_STRING:
-
/*
* The operand must be a String. We can convert an
* Integer or Buffer if necessary
@@ -656,7 +665,6 @@ acpi_ex_convert_to_target_type (
case ACPI_TYPE_BUFFER:
-
/*
* The operand must be a Buffer. We can convert an
* Integer or String if necessary
diff --git a/drivers/acpi/executer/excreate.c b/drivers/acpi/executer/excreate.c
index d94c260dac6d..812cdcb2e370 100644
--- a/drivers/acpi/executer/excreate.c
+++ b/drivers/acpi/executer/excreate.c
@@ -55,7 +55,7 @@
#ifndef ACPI_NO_METHOD_EXECUTION
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_alias
*
@@ -65,7 +65,7 @@
*
* DESCRIPTION: Create a new named alias
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_alias (
@@ -140,8 +140,7 @@ acpi_ex_create_alias (
* target node or the alias Node
*/
status = acpi_ns_attach_object (alias_node,
- acpi_ns_get_attached_object (target_node),
- target_node->type);
+ acpi_ns_get_attached_object (target_node), target_node->type);
break;
}
@@ -151,7 +150,7 @@ acpi_ex_create_alias (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_event
*
@@ -161,7 +160,7 @@ acpi_ex_create_alias (
*
* DESCRIPTION: Create a new event object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_event (
@@ -185,7 +184,7 @@ acpi_ex_create_event (
* that the event is created in an unsignalled state
*/
status = acpi_os_create_semaphore (ACPI_NO_UNIT_LIMIT, 0,
- &obj_desc->event.semaphore);
+ &obj_desc->event.semaphore);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
@@ -193,7 +192,7 @@ acpi_ex_create_event (
/* Attach object to the Node */
status = acpi_ns_attach_object ((struct acpi_namespace_node *) walk_state->operands[0],
- obj_desc, ACPI_TYPE_EVENT);
+ obj_desc, ACPI_TYPE_EVENT);
cleanup:
/*
@@ -205,7 +204,7 @@ cleanup:
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_mutex
*
@@ -217,7 +216,7 @@ cleanup:
*
* Mutex (Name[0], sync_level[1])
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_mutex (
@@ -267,20 +266,20 @@ cleanup:
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_region
*
* PARAMETERS: aml_start - Pointer to the region declaration AML
* aml_length - Max length of the declaration AML
- * Operands - List of operands for the opcode
+ * region_space - space_iD for the region
* walk_state - Current state
*
* RETURN: Status
*
* DESCRIPTION: Create a new operation region object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_region (
@@ -321,7 +320,7 @@ acpi_ex_create_region (
}
ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "Region Type - %s (%X)\n",
- acpi_ut_get_region_name (region_space), region_space));
+ acpi_ut_get_region_name (region_space), region_space));
/* Create the region descriptor */
@@ -360,7 +359,7 @@ cleanup:
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_table_region
*
@@ -370,7 +369,7 @@ cleanup:
*
* DESCRIPTION: Create a new data_table_region object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_table_region (
@@ -455,7 +454,7 @@ cleanup:
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_processor
*
@@ -467,7 +466,7 @@ cleanup:
*
* Processor (Name[0], cpu_iD[1], pblock_addr[2], pblock_length[3])
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_processor (
@@ -488,9 +487,8 @@ acpi_ex_create_processor (
return_ACPI_STATUS (AE_NO_MEMORY);
}
- /*
- * Initialize the processor object from the operands
- */
+ /* Initialize the processor object from the operands */
+
obj_desc->processor.proc_id = (u8) operand[1]->integer.value;
obj_desc->processor.address = (acpi_io_address) operand[2]->integer.value;
obj_desc->processor.length = (u8) operand[3]->integer.value;
@@ -507,7 +505,7 @@ acpi_ex_create_processor (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_power_resource
*
@@ -519,7 +517,7 @@ acpi_ex_create_processor (
*
* power_resource (Name[0], system_level[1], resource_order[2])
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_power_resource (
@@ -555,10 +553,10 @@ acpi_ex_create_power_resource (
acpi_ut_remove_reference (obj_desc);
return_ACPI_STATUS (status);
}
-
#endif
-/*****************************************************************************
+
+/*******************************************************************************
*
* FUNCTION: acpi_ex_create_method
*
@@ -570,7 +568,7 @@ acpi_ex_create_power_resource (
*
* DESCRIPTION: Create a new method object
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
acpi_ex_create_method (
diff --git a/drivers/acpi/executer/exdump.c b/drivers/acpi/executer/exdump.c
index e2f7c32f28de..408500648114 100644
--- a/drivers/acpi/executer/exdump.c
+++ b/drivers/acpi/executer/exdump.c
@@ -51,23 +51,48 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exdump")
+/* Local prototypes */
+
+#ifdef ACPI_FUTURE_USAGE
+static void
+acpi_ex_out_string (
+ char *title,
+ char *value);
+
+static void
+acpi_ex_out_pointer (
+ char *title,
+ void *value);
+
+static void
+acpi_ex_out_integer (
+ char *title,
+ u32 value);
+
+static void
+acpi_ex_out_address (
+ char *title,
+ acpi_physical_address value);
+#endif /* ACPI_FUTURE_USAGE */
+
/*
* The following routines are used for debug output only
*/
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_operand
*
- * PARAMETERS: *obj_desc - Pointer to entry to be dumped
+ * PARAMETERS: *obj_desc - Pointer to entry to be dumped
+ * Depth - Current nesting depth
*
* RETURN: None
*
* DESCRIPTION: Dump an operand object
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ex_dump_operand (
@@ -86,9 +111,8 @@ acpi_ex_dump_operand (
}
if (!obj_desc) {
- /*
- * This could be a null element of a package
- */
+ /* This could be a null element of a package */
+
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Null Object Descriptor\n"));
return;
}
@@ -117,6 +141,8 @@ acpi_ex_dump_operand (
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "%p ", obj_desc));
}
+ /* Decode object type */
+
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
@@ -274,7 +300,9 @@ acpi_ex_dump_operand (
case ACPI_TYPE_STRING:
acpi_os_printf ("String length %X @ %p ",
- obj_desc->string.length, obj_desc->string.pointer);
+ obj_desc->string.length,
+ obj_desc->string.pointer);
+
acpi_ut_print_string (obj_desc->string.pointer, ACPI_UINT8_MAX);
acpi_os_printf ("\n");
break;
@@ -290,10 +318,13 @@ acpi_ex_dump_operand (
acpi_os_printf (
"region_field: Bits=%X acc_width=%X Lock=%X Update=%X at byte=%X bit=%X of below:\n",
- obj_desc->field.bit_length, obj_desc->field.access_byte_width,
+ obj_desc->field.bit_length,
+ obj_desc->field.access_byte_width,
obj_desc->field.field_flags & AML_FIELD_LOCK_RULE_MASK,
obj_desc->field.field_flags & AML_FIELD_UPDATE_RULE_MASK,
- obj_desc->field.base_byte_offset, obj_desc->field.start_field_bit_offset);
+ obj_desc->field.base_byte_offset,
+ obj_desc->field.start_field_bit_offset);
+
acpi_ex_dump_operand (obj_desc->field.region_obj, depth+1);
break;
@@ -308,13 +339,15 @@ acpi_ex_dump_operand (
acpi_os_printf (
"buffer_field: %X bits at byte %X bit %X of \n",
- obj_desc->buffer_field.bit_length, obj_desc->buffer_field.base_byte_offset,
+ obj_desc->buffer_field.bit_length,
+ obj_desc->buffer_field.base_byte_offset,
obj_desc->buffer_field.start_field_bit_offset);
if (!obj_desc->buffer_field.buffer_obj) {
ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*NULL* \n"));
}
- else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) != ACPI_TYPE_BUFFER) {
+ else if (ACPI_GET_OBJECT_TYPE (obj_desc->buffer_field.buffer_obj) !=
+ ACPI_TYPE_BUFFER) {
acpi_os_printf ("*not a Buffer* \n");
}
else {
@@ -331,10 +364,10 @@ acpi_ex_dump_operand (
case ACPI_TYPE_METHOD:
- acpi_os_printf (
- "Method(%X) @ %p:%X\n",
+ acpi_os_printf ("Method(%X) @ %p:%X\n",
obj_desc->method.param_count,
- obj_desc->method.aml_start, obj_desc->method.aml_length);
+ obj_desc->method.aml_start,
+ obj_desc->method.aml_length);
break;
@@ -379,7 +412,7 @@ acpi_ex_dump_operand (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_operands
*
@@ -393,7 +426,7 @@ acpi_ex_dump_operand (
*
* DESCRIPTION: Dump the object stack
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ex_dump_operands (
@@ -441,10 +474,9 @@ acpi_ex_dump_operands (
#ifdef ACPI_FUTURE_USAGE
-
-/*****************************************************************************
+/*******************************************************************************
*
- * FUNCTION: acpi_ex_out*
+ * FUNCTION: acpi_ex_out* functions
*
* PARAMETERS: Title - Descriptive text
* Value - Value to be displayed
@@ -453,9 +485,9 @@ acpi_ex_dump_operands (
* reduce the number of format strings required and keeps them
* all in one place for easy modification.
*
- ****************************************************************************/
+ ******************************************************************************/
-void
+static void
acpi_ex_out_string (
char *title,
char *value)
@@ -463,7 +495,7 @@ acpi_ex_out_string (
acpi_os_printf ("%20s : %s\n", title, value);
}
-void
+static void
acpi_ex_out_pointer (
char *title,
void *value)
@@ -471,7 +503,7 @@ acpi_ex_out_pointer (
acpi_os_printf ("%20s : %p\n", title, value);
}
-void
+static void
acpi_ex_out_integer (
char *title,
u32 value)
@@ -479,7 +511,7 @@ acpi_ex_out_integer (
acpi_os_printf ("%20s : %X\n", title, value);
}
-void
+static void
acpi_ex_out_address (
char *title,
acpi_physical_address value)
@@ -493,16 +525,16 @@ acpi_ex_out_address (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_node
*
* PARAMETERS: *Node - Descriptor to dump
- * Flags - Force display
+ * Flags - Force display if TRUE
*
* DESCRIPTION: Dumps the members of the given.Node
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ex_dump_node (
@@ -531,16 +563,16 @@ acpi_ex_dump_node (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ex_dump_object_descriptor
*
* PARAMETERS: *Object - Descriptor to dump
- * Flags - Force display
+ * Flags - Force display if TRUE
*
* DESCRIPTION: Dumps the members of the object descriptor given.
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ex_dump_object_descriptor (
@@ -553,6 +585,10 @@ acpi_ex_dump_object_descriptor (
ACPI_FUNCTION_TRACE ("ex_dump_object_descriptor");
+ if (!obj_desc) {
+ return_VOID;
+ }
+
if (!flags) {
if (!((ACPI_LV_OBJECTS & acpi_dbg_level) && (_COMPONENT & acpi_dbg_layer))) {
return_VOID;
@@ -747,11 +783,17 @@ acpi_ex_dump_object_descriptor (
case ACPI_TYPE_LOCAL_REFERENCE:
acpi_ex_out_integer ("target_type", obj_desc->reference.target_type);
- acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (obj_desc->reference.opcode))->name);
+ acpi_ex_out_string ("Opcode", (acpi_ps_get_opcode_info (
+ obj_desc->reference.opcode))->name);
acpi_ex_out_integer ("Offset", obj_desc->reference.offset);
acpi_ex_out_pointer ("obj_desc", obj_desc->reference.object);
acpi_ex_out_pointer ("Node", obj_desc->reference.node);
acpi_ex_out_pointer ("Where", obj_desc->reference.where);
+
+ if (obj_desc->reference.object) {
+ acpi_os_printf ("\nReferenced Object:\n");
+ acpi_ex_dump_object_descriptor (obj_desc->reference.object, flags);
+ }
break;
@@ -788,6 +830,5 @@ acpi_ex_dump_object_descriptor (
}
#endif /* ACPI_FUTURE_USAGE */
-
#endif
diff --git a/drivers/acpi/executer/exfield.c b/drivers/acpi/executer/exfield.c
index be7f2124fa02..22c8fa480f60 100644
--- a/drivers/acpi/executer/exfield.c
+++ b/drivers/acpi/executer/exfield.c
@@ -120,8 +120,8 @@ acpi_ex_read_data_from_field (
* Note: Smbus protocol value is passed in upper 16-bits of Function
*/
status = acpi_ex_access_region (obj_desc, 0,
- ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer),
- ACPI_READ | (obj_desc->field.attribute << 16));
+ ACPI_CAST_PTR (acpi_integer, buffer_desc->buffer.pointer),
+ ACPI_READ | (obj_desc->field.attribute << 16));
acpi_ex_release_global_lock (locked);
goto exit;
}
@@ -196,6 +196,7 @@ exit:
*
* PARAMETERS: source_desc - Contains data to write
* obj_desc - The named field
+ * result_desc - Where the return value is returned, if any
*
* RETURN: Status
*
@@ -250,12 +251,15 @@ acpi_ex_write_data_to_field (
if (ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) {
ACPI_REPORT_ERROR (("SMBus write requires Buffer, found type %s\n",
acpi_ut_get_object_type_name (source_desc)));
+
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
if (source_desc->buffer.length < ACPI_SMBUS_BUFFER_SIZE) {
- ACPI_REPORT_ERROR (("SMBus write requires Buffer of length %X, found length %X\n",
+ ACPI_REPORT_ERROR ((
+ "SMBus write requires Buffer of length %X, found length %X\n",
ACPI_SMBUS_BUFFER_SIZE, source_desc->buffer.length));
+
return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
}
@@ -265,14 +269,16 @@ acpi_ex_write_data_to_field (
}
buffer = buffer_desc->buffer.pointer;
- ACPI_MEMCPY (buffer, source_desc->buffer.pointer, ACPI_SMBUS_BUFFER_SIZE);
+ ACPI_MEMCPY (buffer, source_desc->buffer.pointer,
+ ACPI_SMBUS_BUFFER_SIZE);
/* Lock entire transaction if requested */
locked = acpi_ex_acquire_global_lock (obj_desc->common_field.field_flags);
/*
- * Perform the write (returns status and perhaps data in the same buffer)
+ * Perform the write (returns status and perhaps data in the
+ * same buffer)
* Note: SMBus protocol type is passed in upper 16-bits of Function.
*/
status = acpi_ex_access_region (obj_desc, 0,
@@ -284,9 +290,8 @@ acpi_ex_write_data_to_field (
return_ACPI_STATUS (status);
}
- /*
- * Get a pointer to the data to be written
- */
+ /* Get a pointer to the data to be written */
+
switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
case ACPI_TYPE_INTEGER:
buffer = &source_desc->integer.value;
@@ -314,7 +319,8 @@ acpi_ex_write_data_to_field (
* the ACPI specification.
*/
new_buffer = NULL;
- required_length = ACPI_ROUND_BITS_UP_TO_BYTES (obj_desc->common_field.bit_length);
+ required_length = ACPI_ROUND_BITS_UP_TO_BYTES (
+ obj_desc->common_field.bit_length);
if (length < required_length) {
/* We need to create a new buffer */
@@ -338,6 +344,7 @@ acpi_ex_write_data_to_field (
"field_write [FROM]: Obj %p (%s:%X), Buf %p, byte_len %X\n",
source_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (source_desc)),
ACPI_GET_OBJECT_TYPE (source_desc), buffer, length));
+
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"field_write [TO]: Obj %p (%s:%X), bit_len %X, bit_off %X, byte_off %X\n",
obj_desc, acpi_ut_get_type_name (ACPI_GET_OBJECT_TYPE (obj_desc)),
diff --git a/drivers/acpi/executer/exfldio.c b/drivers/acpi/executer/exfldio.c
index 9d0f9d2e9061..3c2f89e00f78 100644
--- a/drivers/acpi/executer/exfldio.c
+++ b/drivers/acpi/executer/exfldio.c
@@ -52,12 +52,31 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exfldio")
+/* Local prototypes */
+
+static acpi_status
+acpi_ex_field_datum_io (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset,
+ acpi_integer *value,
+ u32 read_write);
+
+static u8
+acpi_ex_register_overflow (
+ union acpi_operand_object *obj_desc,
+ acpi_integer value);
+
+static acpi_status
+acpi_ex_setup_region (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset);
+
/*******************************************************************************
*
* FUNCTION: acpi_ex_setup_region
*
- * PARAMETERS: *obj_desc - Field to be read or written
+ * PARAMETERS: obj_desc - Field to be read or written
* field_datum_byte_offset - Byte offset of this datum within the
* parent field
*
@@ -69,7 +88,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_setup_region (
union acpi_operand_object *obj_desc,
u32 field_datum_byte_offset)
@@ -127,9 +146,9 @@ acpi_ex_setup_region (
* length of one field datum (access width) must fit within the region.
* (Region length is specified in bytes)
*/
- if (rgn_desc->region.length < (obj_desc->common_field.base_byte_offset
- + field_datum_byte_offset
- + obj_desc->common_field.access_byte_width)) {
+ 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
@@ -155,7 +174,8 @@ acpi_ex_setup_region (
"Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n",
acpi_ut_get_node_name (obj_desc->common_field.node),
obj_desc->common_field.access_byte_width,
- acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length));
+ acpi_ut_get_node_name (rgn_desc->region.node),
+ rgn_desc->region.length));
}
/*
@@ -167,7 +187,8 @@ acpi_ex_setup_region (
acpi_ut_get_node_name (obj_desc->common_field.node),
obj_desc->common_field.base_byte_offset,
field_datum_byte_offset, obj_desc->common_field.access_byte_width,
- acpi_ut_get_node_name (rgn_desc->region.node), rgn_desc->region.length));
+ acpi_ut_get_node_name (rgn_desc->region.node),
+ rgn_desc->region.length));
return_ACPI_STATUS (AE_AML_REGION_LIMIT);
}
@@ -180,10 +201,10 @@ acpi_ex_setup_region (
*
* FUNCTION: acpi_ex_access_region
*
- * PARAMETERS: *obj_desc - Field to be read
+ * PARAMETERS: obj_desc - Field to be read
* field_datum_byte_offset - Byte offset of this datum within the
* parent field
- * *Value - Where to store value (must at least
+ * Value - Where to store value (must at least
* the size of acpi_integer)
* Function - Read or Write flag plus other region-
* dependent flags
@@ -226,9 +247,9 @@ acpi_ex_access_region (
* 3) The current offset into the field
*/
rgn_desc = obj_desc->common_field.region_obj;
- address = rgn_desc->region.address
- + obj_desc->common_field.base_byte_offset
- + field_datum_byte_offset;
+ address = rgn_desc->region.address +
+ obj_desc->common_field.base_byte_offset +
+ field_datum_byte_offset;
if ((function & ACPI_IO_MASK) == ACPI_READ) {
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
@@ -249,7 +270,8 @@ acpi_ex_access_region (
/* Invoke the appropriate address_space/op_region handler */
status = acpi_ev_address_space_dispatch (rgn_desc, function,
- address, ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value);
+ address,
+ ACPI_MUL_8 (obj_desc->common_field.access_byte_width), value);
if (ACPI_FAILURE (status)) {
if (status == AE_NOT_IMPLEMENTED) {
@@ -274,7 +296,7 @@ acpi_ex_access_region (
*
* FUNCTION: acpi_ex_register_overflow
*
- * PARAMETERS: *obj_desc - Register(Field) to be written
+ * PARAMETERS: obj_desc - Register(Field) to be written
* Value - Value to be stored
*
* RETURN: TRUE if value overflows the field, FALSE otherwise
@@ -287,7 +309,7 @@ acpi_ex_access_region (
*
******************************************************************************/
-u8
+static u8
acpi_ex_register_overflow (
union acpi_operand_object *obj_desc,
acpi_integer value)
@@ -319,10 +341,10 @@ acpi_ex_register_overflow (
*
* FUNCTION: acpi_ex_field_datum_io
*
- * PARAMETERS: *obj_desc - Field to be read
+ * PARAMETERS: obj_desc - Field to be read
* field_datum_byte_offset - Byte offset of this datum within the
* parent field
- * *Value - Where to store value (must be 64 bits)
+ * Value - Where to store value (must be 64 bits)
* read_write - Read or Write flag
*
* RETURN: Status
@@ -333,7 +355,7 @@ acpi_ex_register_overflow (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_field_datum_io (
union acpi_operand_object *obj_desc,
u32 field_datum_byte_offset,
@@ -350,7 +372,9 @@ acpi_ex_field_datum_io (
if (read_write == ACPI_READ) {
if (!value) {
local_value = 0;
- value = &local_value; /* To support reads without saving return value */
+
+ /* To support reads without saving return value */
+ value = &local_value;
}
/* Clear the entire return buffer first, [Very Important!] */
@@ -363,8 +387,10 @@ acpi_ex_field_datum_io (
*
* buffer_field - Read/write from/to a Buffer
* region_field - Read/write from/to a Operation Region.
- * bank_field - Write to a Bank Register, then read/write from/to an op_region
- * index_field - Write to an Index Register, then read/write from/to a Data Register
+ * bank_field - Write to a Bank Register, then read/write from/to an
+ * operation_region
+ * index_field - Write to an Index Register, then read/write from/to a
+ * Data Register
*/
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_BUFFER_FIELD:
@@ -384,19 +410,20 @@ acpi_ex_field_datum_io (
* Copy the data from the source buffer.
* Length is the field width in bytes.
*/
- ACPI_MEMCPY (value, (obj_desc->buffer_field.buffer_obj)->buffer.pointer
- + obj_desc->buffer_field.base_byte_offset
- + field_datum_byte_offset,
- obj_desc->common_field.access_byte_width);
+ ACPI_MEMCPY (value,
+ (obj_desc->buffer_field.buffer_obj)->buffer.pointer +
+ obj_desc->buffer_field.base_byte_offset +
+ field_datum_byte_offset,
+ obj_desc->common_field.access_byte_width);
}
else {
/*
* Copy the data to the target buffer.
* Length is the field width in bytes.
*/
- ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer
- + obj_desc->buffer_field.base_byte_offset
- + field_datum_byte_offset,
+ ACPI_MEMCPY ((obj_desc->buffer_field.buffer_obj)->buffer.pointer +
+ obj_desc->buffer_field.base_byte_offset +
+ field_datum_byte_offset,
value, obj_desc->common_field.access_byte_width);
}
@@ -406,8 +433,10 @@ acpi_ex_field_datum_io (
case ACPI_TYPE_LOCAL_BANK_FIELD:
- /* Ensure that the bank_value is not beyond the capacity of the register */
-
+ /*
+ * Ensure that the bank_value is not beyond the capacity of
+ * the register
+ */
if (acpi_ex_register_overflow (obj_desc->bank_field.bank_obj,
(acpi_integer) obj_desc->bank_field.value)) {
return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
@@ -445,8 +474,10 @@ acpi_ex_field_datum_io (
case ACPI_TYPE_LOCAL_INDEX_FIELD:
- /* Ensure that the index_value is not beyond the capacity of the register */
-
+ /*
+ * Ensure that the index_value is not beyond the capacity of
+ * the register
+ */
if (acpi_ex_register_overflow (obj_desc->index_field.index_obj,
(acpi_integer) obj_desc->index_field.value)) {
return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
@@ -496,14 +527,16 @@ acpi_ex_field_datum_io (
if (ACPI_SUCCESS (status)) {
if (read_write == ACPI_READ) {
- ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n",
- ACPI_FORMAT_UINT64 (*value),
- obj_desc->common_field.access_byte_width));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Value Read %8.8X%8.8X, Width %d\n",
+ ACPI_FORMAT_UINT64 (*value),
+ obj_desc->common_field.access_byte_width));
}
else {
- ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n",
- ACPI_FORMAT_UINT64 (*value),
- obj_desc->common_field.access_byte_width));
+ ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
+ "Value Written %8.8X%8.8X, Width %d\n",
+ ACPI_FORMAT_UINT64 (*value),
+ obj_desc->common_field.access_byte_width));
}
}
@@ -515,8 +548,10 @@ acpi_ex_field_datum_io (
*
* FUNCTION: acpi_ex_write_with_update_rule
*
- * PARAMETERS: *obj_desc - Field to be set
- * Value - Value to store
+ * PARAMETERS: obj_desc - Field to be written
+ * Mask - bitmask within field datum
+ * field_value - Value to write
+ * field_datum_byte_offset - Offset of datum within field
*
* RETURN: Status
*
@@ -689,7 +724,8 @@ acpi_ex_extract_from_field (
/* Merge with previous datum if necessary */
merged_datum |= raw_datum <<
- (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
+ (obj_desc->common_field.access_bit_width -
+ obj_desc->common_field.start_field_bit_offset);
if (i == datum_count) {
break;
@@ -707,7 +743,8 @@ acpi_ex_extract_from_field (
/* Mask off any extra bits in the last datum */
- buffer_tail_bits = obj_desc->common_field.bit_length % obj_desc->common_field.access_bit_width;
+ buffer_tail_bits = obj_desc->common_field.bit_length %
+ obj_desc->common_field.access_bit_width;
if (buffer_tail_bits) {
merged_datum &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
}
@@ -791,7 +828,8 @@ acpi_ex_insert_into_field (
/* Write merged datum to the target field */
merged_datum &= mask;
- status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
+ status = acpi_ex_write_with_update_rule (obj_desc, mask,
+ merged_datum, field_offset);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -800,7 +838,8 @@ acpi_ex_insert_into_field (
field_offset += obj_desc->common_field.access_byte_width;
merged_datum = raw_datum >>
- (obj_desc->common_field.access_bit_width - obj_desc->common_field.start_field_bit_offset);
+ (obj_desc->common_field.access_bit_width -
+ obj_desc->common_field.start_field_bit_offset);
mask = ACPI_INTEGER_MAX;
if (i == datum_count) {
@@ -819,7 +858,8 @@ acpi_ex_insert_into_field (
/* Mask off any extra bits in the last datum */
buffer_tail_bits = (obj_desc->common_field.bit_length +
- obj_desc->common_field.start_field_bit_offset) % obj_desc->common_field.access_bit_width;
+ obj_desc->common_field.start_field_bit_offset) %
+ obj_desc->common_field.access_bit_width;
if (buffer_tail_bits) {
mask &= ACPI_MASK_BITS_ABOVE (buffer_tail_bits);
}
@@ -827,7 +867,8 @@ acpi_ex_insert_into_field (
/* Write the last datum to the field */
merged_datum &= mask;
- status = acpi_ex_write_with_update_rule (obj_desc, mask, merged_datum, field_offset);
+ status = acpi_ex_write_with_update_rule (obj_desc,
+ mask, merged_datum, field_offset);
return_ACPI_STATUS (status);
}
diff --git a/drivers/acpi/executer/exmisc.c b/drivers/acpi/executer/exmisc.c
index b542dcd58c07..022f281345b8 100644
--- a/drivers/acpi/executer/exmisc.c
+++ b/drivers/acpi/executer/exmisc.c
@@ -139,8 +139,9 @@ acpi_ex_get_object_reference (
reference_obj->reference.object = referenced_obj;
*return_desc = reference_obj;
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Object %p Type [%s], returning Reference %p\n",
- obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Object %p Type [%s], returning Reference %p\n",
+ obj_desc, acpi_ut_get_object_type_name (obj_desc), *return_desc));
return_ACPI_STATUS (AE_OK);
}
@@ -456,7 +457,7 @@ acpi_ex_do_math_op (
return (integer0 * integer1);
- case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result) */
+ case AML_SHIFT_LEFT_OP: /* shift_left (Operand, shift_count, Result)*/
return (integer0 << integer1);
diff --git a/drivers/acpi/executer/exmutex.c b/drivers/acpi/executer/exmutex.c
index 68c4bb1970a5..c3cb714d2cba 100644
--- a/drivers/acpi/executer/exmutex.c
+++ b/drivers/acpi/executer/exmutex.c
@@ -49,6 +49,13 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exmutex")
+/* Local prototypes */
+
+static void
+acpi_ex_link_mutex (
+ union acpi_operand_object *obj_desc,
+ struct acpi_thread_state *thread);
+
/*******************************************************************************
*
@@ -56,7 +63,7 @@
*
* PARAMETERS: obj_desc - The mutex to be unlinked
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Remove a mutex from the "acquired_mutex" list
*
@@ -92,16 +99,16 @@ 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
+ * Thread - Current executing thread object
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Add a mutex to the "acquired_mutex" list for this walk
*
******************************************************************************/
-void
+static void
acpi_ex_link_mutex (
union acpi_operand_object *obj_desc,
struct acpi_thread_state *thread)
@@ -132,8 +139,9 @@ 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 - Timeout integer
+ * obj_desc - Mutex object
+ * walk_state - Current method execution state
*
* RETURN: Status
*
@@ -161,7 +169,7 @@ acpi_ex_acquire_mutex (
if (!walk_state->thread) {
ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n",
- acpi_ut_get_node_name (obj_desc->mutex.node)));
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
@@ -170,8 +178,9 @@ acpi_ex_acquire_mutex (
* mutex. This mechanism provides some deadlock prevention
*/
if (walk_state->thread->current_sync_level > obj_desc->mutex.sync_level) {
- ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], incorrect sync_level\n",
- acpi_ut_get_node_name (obj_desc->mutex.node)));
+ ACPI_REPORT_ERROR ((
+ "Cannot acquire Mutex [%4.4s], incorrect sync_level\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
}
@@ -180,8 +189,10 @@ acpi_ex_acquire_mutex (
if (obj_desc->mutex.owner_thread) {
/* Special case for Global Lock, allow all threads */
- if ((obj_desc->mutex.owner_thread->thread_id == walk_state->thread->thread_id) ||
- (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore)) {
+ if ((obj_desc->mutex.owner_thread->thread_id ==
+ walk_state->thread->thread_id) ||
+ (obj_desc->mutex.semaphore ==
+ acpi_gbl_global_lock_semaphore)) {
/*
* The mutex is already owned by this thread,
* just increment the acquisition depth
@@ -221,6 +232,7 @@ acpi_ex_acquire_mutex (
* FUNCTION: acpi_ex_release_mutex
*
* PARAMETERS: obj_desc - The object descriptor for this op
+ * walk_state - Current method execution state
*
* RETURN: Status
*
@@ -278,8 +290,9 @@ acpi_ex_release_mutex (
* equal to the current sync level
*/
if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) {
- ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], incorrect sync_level\n",
- acpi_ut_get_node_name (obj_desc->mutex.node)));
+ ACPI_REPORT_ERROR ((
+ "Cannot release Mutex [%4.4s], incorrect sync_level\n",
+ acpi_ut_get_node_name (obj_desc->mutex.node)));
return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
}
@@ -313,11 +326,11 @@ acpi_ex_release_mutex (
*
* FUNCTION: acpi_ex_release_all_mutexes
*
- * PARAMETERS: mutex_list - Head of the mutex list
+ * PARAMETERS: Thread - Current executing thread object
*
* RETURN: Status
*
- * DESCRIPTION: Release all mutexes in the list
+ * DESCRIPTION: Release all mutexes held by this thread
*
******************************************************************************/
diff --git a/drivers/acpi/executer/exnames.c b/drivers/acpi/executer/exnames.c
index 7911c533c265..639f0bd3f6d8 100644
--- a/drivers/acpi/executer/exnames.c
+++ b/drivers/acpi/executer/exnames.c
@@ -50,13 +50,17 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exnames")
+/* Local prototypes */
-/* AML Package Length encodings */
+static char *
+acpi_ex_allocate_name_string (
+ u32 prefix_count,
+ u32 num_name_segs);
-#define ACPI_AML_PACKAGE_TYPE1 0x40
-#define ACPI_AML_PACKAGE_TYPE2 0x4000
-#define ACPI_AML_PACKAGE_TYPE3 0x400000
-#define ACPI_AML_PACKAGE_TYPE4 0x40000000
+static acpi_status
+acpi_ex_name_segment (
+ u8 **in_aml_address,
+ char *name_string);
/*******************************************************************************
@@ -64,7 +68,7 @@
* FUNCTION: acpi_ex_allocate_name_string
*
* PARAMETERS: prefix_count - Count of parent levels. Special cases:
- * (-1) = root, 0 = none
+ * (-1)==root, 0==none
* num_name_segs - count of 4-character name segments
*
* RETURN: A pointer to the allocated string segment. This segment must
@@ -75,7 +79,7 @@
*
******************************************************************************/
-char *
+static char *
acpi_ex_allocate_name_string (
u32 prefix_count,
u32 num_name_segs)
@@ -88,7 +92,7 @@ acpi_ex_allocate_name_string (
/*
- * Allow room for all \ and ^ prefixes, all segments, and a multi_name_prefix.
+ * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix.
* Also, one byte for the null terminator.
* This may actually be somewhat longer than needed.
*/
@@ -107,7 +111,8 @@ acpi_ex_allocate_name_string (
*/
name_string = ACPI_MEM_ALLOCATE (size_needed);
if (!name_string) {
- ACPI_REPORT_ERROR (("ex_allocate_name_string: Could not allocate size %d\n", size_needed));
+ ACPI_REPORT_ERROR ((
+ "ex_allocate_name_string: Could not allocate size %d\n", size_needed));
return_PTR (NULL);
}
@@ -152,15 +157,17 @@ acpi_ex_allocate_name_string (
*
* FUNCTION: acpi_ex_name_segment
*
- * PARAMETERS: interpreter_mode - Current running mode (load1/Load2/Exec)
+ * PARAMETERS: in_aml_address - Pointer to the name in the AML code
+ * name_string - Where to return the name. The name is appended
+ * to any existing string to form a namepath
*
* RETURN: Status
*
- * DESCRIPTION: Execute a name segment (4 bytes)
+ * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_name_segment (
u8 **in_aml_address,
char *name_string)
@@ -223,10 +230,13 @@ acpi_ex_name_segment (
status = AE_CTRL_PENDING;
}
else {
- /* Segment started with one or more valid characters, but fewer than 4 */
-
+ /*
+ * Segment started with one or more valid characters, but fewer than
+ * the required 4
+ */
status = AE_AML_BAD_NAME;
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad character %02x in name, at %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Bad character %02x in name, at %p\n",
*aml_address, aml_address));
}
@@ -239,11 +249,16 @@ acpi_ex_name_segment (
*
* FUNCTION: acpi_ex_get_name_string
*
- * PARAMETERS: data_type - Data type to be associated with this name
+ * PARAMETERS: data_type - Object type to be associated with this
+ * name
+ * in_aml_address - Pointer to the namestring in the AML code
+ * out_name_string - Where the namestring is returned
+ * out_name_length - Length of the returned string
*
- * RETURN: Status
+ * RETURN: Status, namestring and length
*
- * DESCRIPTION: Get a name, including any prefixes.
+ * DESCRIPTION: Extract a full namepath from the AML byte stream,
+ * including any prefixes.
*
******************************************************************************/
@@ -286,7 +301,8 @@ acpi_ex_get_name_string (
switch (*aml_address) {
case AML_ROOT_PREFIX:
- ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n", aml_address));
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "root_prefix(\\) at %p\n",
+ aml_address));
/*
* Remember that we have a root_prefix --
@@ -303,7 +319,8 @@ acpi_ex_get_name_string (
/* Increment past possibly multiple parent prefixes */
do {
- ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n", aml_address));
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "parent_prefix (^) at %p\n",
+ aml_address));
aml_address++;
prefix_count++;
@@ -321,13 +338,13 @@ acpi_ex_get_name_string (
break;
}
-
/* Examine first character of name for name segment prefix operator */
switch (*aml_address) {
case AML_DUAL_NAME_PREFIX:
- ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n", aml_address));
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "dual_name_prefix at %p\n",
+ aml_address));
aml_address++;
name_string = acpi_ex_allocate_name_string (prefix_count, 2);
@@ -349,7 +366,8 @@ acpi_ex_get_name_string (
case AML_MULTI_NAME_PREFIX_OP:
- ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n", aml_address));
+ ACPI_DEBUG_PRINT ((ACPI_DB_LOAD, "multi_name_prefix at %p\n",
+ aml_address));
/* Fetch count of segments remaining in name path */
@@ -368,7 +386,8 @@ acpi_ex_get_name_string (
has_prefix = TRUE;
while (num_segments &&
- (status = acpi_ex_name_segment (&aml_address, name_string)) == AE_OK) {
+ (status = acpi_ex_name_segment (&aml_address, name_string)) ==
+ AE_OK) {
num_segments--;
}
@@ -380,7 +399,8 @@ acpi_ex_get_name_string (
/* null_name valid as of 8-12-98 ASL/AML Grammar Update */
if (prefix_count == ACPI_UINT32_MAX) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "name_seg is \"\\\" followed by NULL\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "name_seg is \"\\\" followed by NULL\n"));
}
/* Consume the NULL byte */
diff --git a/drivers/acpi/executer/exoparg1.c b/drivers/acpi/executer/exoparg1.c
index 8482aefaf38b..dbdf8262ba00 100644
--- a/drivers/acpi/executer/exoparg1.c
+++ b/drivers/acpi/executer/exoparg1.c
@@ -97,7 +97,8 @@ acpi_ex_opcode_0A_0T_1R (
union acpi_operand_object *return_desc = NULL;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_0A_0T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
/* Examine the AML opcode */
@@ -161,7 +162,8 @@ acpi_ex_opcode_1A_0T_0R (
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_0R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
/* Examine the AML opcode */
@@ -236,7 +238,8 @@ acpi_ex_opcode_1A_1T_0R (
union acpi_operand_object **operand = &walk_state->operands[0];
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_0R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
/* Examine the AML opcode */
@@ -289,7 +292,8 @@ acpi_ex_opcode_1A_1T_1R (
acpi_integer digit;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_1T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
/* Examine the AML opcode */
@@ -409,8 +413,10 @@ acpi_ex_opcode_1A_1T_1R (
for (i = 0; (i < acpi_gbl_integer_nybble_width) && (digit > 0); i++) {
(void) acpi_ut_short_divide (digit, 10, &digit, &temp32);
- /* Insert the BCD digit that resides in the remainder from above */
-
+ /*
+ * Insert the BCD digit that resides in the
+ * remainder from above
+ */
return_desc->integer.value |= (((acpi_integer) temp32) <<
ACPI_MUL_4 (i));
}
@@ -445,7 +451,8 @@ acpi_ex_opcode_1A_1T_1R (
/* Get the object reference, store it, and remove our reference */
- status = acpi_ex_get_object_reference (operand[0], &return_desc2, walk_state);
+ status = acpi_ex_get_object_reference (operand[0],
+ &return_desc2, walk_state);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
@@ -482,10 +489,10 @@ acpi_ex_opcode_1A_1T_1R (
if (!walk_state->result_obj) {
/*
- * Normally, we would remove a reference on the Operand[0] parameter;
- * But since it is being used as the internal return object
- * (meaning we would normally increment it), the two cancel out,
- * and we simply don't do anything.
+ * Normally, we would remove a reference on the Operand[0]
+ * parameter; But since it is being used as the internal return
+ * object (meaning we would normally increment it), the two
+ * cancel out, and we simply don't do anything.
*/
walk_state->result_obj = operand[0];
walk_state->operands[0] = NULL; /* Prevent deletion */
@@ -549,9 +556,8 @@ acpi_ex_opcode_1A_1T_1R (
case AML_SHIFT_LEFT_BIT_OP: /* shift_left_bit (Source, bit_num) */
case AML_SHIFT_RIGHT_BIT_OP: /* shift_right_bit (Source, bit_num) */
- /*
- * These are two obsolete opcodes
- */
+ /* These are two obsolete opcodes */
+
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"%s is obsolete and not implemented\n",
acpi_ps_get_opcode_name (walk_state->opcode)));
@@ -568,9 +574,8 @@ acpi_ex_opcode_1A_1T_1R (
}
if (ACPI_SUCCESS (status)) {
- /*
- * Store the return value computed above into the target object
- */
+ /* Store the return value computed above into the target object */
+
status = acpi_ex_store (return_desc, operand[1], walk_state);
}
@@ -615,7 +620,8 @@ acpi_ex_opcode_1A_0T_1R (
acpi_integer value;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_1A_0T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
/* Examine the AML opcode */
@@ -706,9 +712,9 @@ acpi_ex_opcode_1A_0T_1R (
/*
* Note: The operand is not resolved at this point because we want to
- * get the associated object, not its value. For example, we don't want
- * to resolve a field_unit to its value, we want the actual field_unit
- * object.
+ * get the associated object, not its value. For example, we don't
+ * want to resolve a field_unit to its value, we want the actual
+ * field_unit object.
*/
/* Get the type of the base object */
@@ -738,7 +744,8 @@ acpi_ex_opcode_1A_0T_1R (
/* Get the base object */
- status = acpi_ex_resolve_multiple (walk_state, operand[0], &type, &temp_desc);
+ status = acpi_ex_resolve_multiple (walk_state,
+ operand[0], &type, &temp_desc);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
@@ -818,8 +825,10 @@ acpi_ex_opcode_1A_0T_1R (
/* Set Operand[0] to the value of the local/arg */
- status = acpi_ds_method_data_get_value (operand[0]->reference.opcode,
- operand[0]->reference.offset, walk_state, &temp_desc);
+ status = acpi_ds_method_data_get_value (
+ operand[0]->reference.opcode,
+ operand[0]->reference.offset,
+ walk_state, &temp_desc);
if (ACPI_FAILURE (status)) {
goto cleanup;
}
@@ -852,21 +861,26 @@ acpi_ex_opcode_1A_0T_1R (
case ACPI_TYPE_STRING:
/*
- * This is a deref_of (String). The string is a reference to a named ACPI object.
+ * This is a deref_of (String). The string is a reference
+ * to a named ACPI object.
*
* 1) Find the owning Node
- * 2) Dereference the node to an actual object. Could be a Field, so we nee
- * to resolve the node to a value.
+ * 2) Dereference the node to an actual object. Could be a
+ * Field, so we need to resolve the node to a value.
*/
status = acpi_ns_get_node_by_path (operand[0]->string.pointer,
- walk_state->scope_info->scope.node, ACPI_NS_SEARCH_PARENT,
- ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc));
+ walk_state->scope_info->scope.node,
+ ACPI_NS_SEARCH_PARENT,
+ ACPI_CAST_INDIRECT_PTR (
+ struct acpi_namespace_node, &return_desc));
if (ACPI_FAILURE (status)) {
goto cleanup;
}
status = acpi_ex_resolve_node_to_value (
- ACPI_CAST_INDIRECT_PTR (struct acpi_namespace_node, &return_desc), walk_state);
+ ACPI_CAST_INDIRECT_PTR (
+ struct acpi_namespace_node, &return_desc),
+ walk_state);
goto cleanup;
@@ -883,14 +897,16 @@ acpi_ex_opcode_1A_0T_1R (
/*
* This is a deref_of (object_reference)
* Get the actual object from the Node (This is the dereference).
- * -- This case may only happen when a local_x or arg_x is dereferenced above.
+ * This case may only happen when a local_x or arg_x is
+ * dereferenced above.
*/
- return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) operand[0]);
+ return_desc = acpi_ns_get_attached_object (
+ (struct acpi_namespace_node *) operand[0]);
}
else {
/*
- * This must be a reference object produced by either the Index() or
- * ref_of() operator
+ * This must be a reference object produced by either the
+ * Index() or ref_of() operator
*/
switch (operand[0]->reference.opcode) {
case AML_INDEX_OP:
@@ -931,8 +947,8 @@ acpi_ex_opcode_1A_0T_1R (
case ACPI_TYPE_PACKAGE:
/*
- * Return the referenced element of the package. We must add
- * another reference to the referenced object, however.
+ * Return the referenced element of the package. We must
+ * add another reference to the referenced object, however.
*/
return_desc = *(operand[0]->reference.where);
if (!return_desc) {
@@ -967,9 +983,11 @@ acpi_ex_opcode_1A_0T_1R (
return_desc = operand[0]->reference.object;
- if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) == ACPI_DESC_TYPE_NAMED) {
+ if (ACPI_GET_DESCRIPTOR_TYPE (return_desc) ==
+ ACPI_DESC_TYPE_NAMED) {
- return_desc = acpi_ns_get_attached_object ((struct acpi_namespace_node *) return_desc);
+ return_desc = acpi_ns_get_attached_object (
+ (struct acpi_namespace_node *) return_desc);
}
/* Add another reference to the object! */
diff --git a/drivers/acpi/executer/exoparg2.c b/drivers/acpi/executer/exoparg2.c
index 8be4d80ceed5..7429032c2b6c 100644
--- a/drivers/acpi/executer/exoparg2.c
+++ b/drivers/acpi/executer/exoparg2.c
@@ -118,7 +118,7 @@ acpi_ex_opcode_2A_0T_0R (
value = (u32) operand[1]->integer.value;
- /* Notifies allowed on this object? */
+ /* Are notifies allowed on this object? */
if (!acpi_ev_is_notify_object (node)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
@@ -203,11 +203,12 @@ acpi_ex_opcode_2A_2T_1R (
acpi_ps_get_opcode_name (walk_state->opcode));
- /*
- * Execute the opcode
- */
+ /* Execute the opcode */
+
switch (walk_state->opcode) {
- case AML_DIVIDE_OP: /* Divide (Dividend, Divisor, remainder_result quotient_result) */
+ case AML_DIVIDE_OP:
+
+ /* Divide (Dividend, Divisor, remainder_result quotient_result) */
return_desc1 = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
if (!return_desc1) {
@@ -241,7 +242,6 @@ acpi_ex_opcode_2A_2T_1R (
goto cleanup;
}
-
/* Store the results to the target reference operands */
status = acpi_ex_store (return_desc2, operand[2], walk_state);
@@ -295,7 +295,7 @@ acpi_ex_opcode_2A_1T_1R (
{
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *return_desc = NULL;
- u32 index;
+ acpi_integer index;
acpi_status status = AE_OK;
acpi_size length;
@@ -304,9 +304,8 @@ acpi_ex_opcode_2A_1T_1R (
acpi_ps_get_opcode_name (walk_state->opcode));
- /*
- * Execute the opcode
- */
+ /* Execute the opcode */
+
if (walk_state->op_info->flags & AML_MATH) {
/* All simple math opcodes (add, etc.) */
@@ -322,9 +321,8 @@ acpi_ex_opcode_2A_1T_1R (
goto store_result_to_target;
}
-
switch (walk_state->opcode) {
- case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */
+ case AML_MOD_OP: /* Mod (Dividend, Divisor, remainder_result (ACPI 2.0) */
return_desc = acpi_ut_create_internal_object (ACPI_TYPE_INTEGER);
if (!return_desc) {
@@ -341,18 +339,19 @@ acpi_ex_opcode_2A_1T_1R (
break;
- case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */
+ case AML_CONCAT_OP: /* Concatenate (Data1, Data2, Result) */
status = acpi_ex_do_concatenate (operand[0], operand[1],
&return_desc, walk_state);
break;
- case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */
+ case AML_TO_STRING_OP: /* to_string (Buffer, Length, Result) (ACPI 2.0) */
/*
* Input object is guaranteed to be a buffer at this point (it may have
- * been converted.) Copy the raw buffer data to a new object of type String.
+ * been converted.) Copy the raw buffer data to a new object of
+ * type String.
*/
/*
@@ -383,14 +382,16 @@ acpi_ex_opcode_2A_1T_1R (
goto cleanup;
}
- /* Copy the raw buffer data with no transform. NULL terminated already. */
+ /* Copy the raw buffer data with no transform. NULL terminated already*/
ACPI_MEMCPY (return_desc->string.pointer,
operand[0]->buffer.pointer, length);
break;
- case AML_CONCAT_RES_OP: /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */
+ case AML_CONCAT_RES_OP:
+
+ /* concatenate_res_template (Buffer, Buffer, Result) (ACPI 2.0) */
status = acpi_ex_concat_template (operand[0], operand[1],
&return_desc, walk_state);
@@ -407,33 +408,33 @@ acpi_ex_opcode_2A_1T_1R (
goto cleanup;
}
- index = (u32) operand[1]->integer.value;
+ index = operand[1]->integer.value;
+
+ /* At this point, the Source operand is a Package, Buffer, or String */
- /*
- * At this point, the Source operand is a Package, Buffer, or String
- */
if (ACPI_GET_OBJECT_TYPE (operand[0]) == ACPI_TYPE_PACKAGE) {
/* Object to be indexed is a Package */
if (index >= operand[0]->package.count) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Index value (%X) beyond package end (%X)\n",
- index, operand[0]->package.count));
+ "Index value (%X%8.8X) beyond package end (%X)\n",
+ ACPI_FORMAT_UINT64 (index), operand[0]->package.count));
status = AE_AML_PACKAGE_LIMIT;
goto cleanup;
}
return_desc->reference.target_type = ACPI_TYPE_PACKAGE;
return_desc->reference.object = operand[0];
- return_desc->reference.where = &operand[0]->package.elements [index];
+ return_desc->reference.where = &operand[0]->package.elements [
+ index];
}
else {
/* Object to be indexed is a Buffer/String */
if (index >= operand[0]->buffer.length) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Index value (%X) beyond end of buffer (%X)\n",
- index, operand[0]->buffer.length));
+ "Index value (%X%8.8X) beyond end of buffer (%X)\n",
+ ACPI_FORMAT_UINT64 (index), operand[0]->buffer.length));
status = AE_AML_BUFFER_LIMIT;
goto cleanup;
}
@@ -451,7 +452,7 @@ acpi_ex_opcode_2A_1T_1R (
/* Complete the Index reference object */
return_desc->reference.opcode = AML_INDEX_OP;
- return_desc->reference.offset = index;
+ return_desc->reference.offset = (u32) index;
/* Store the reference to the Target */
@@ -536,22 +537,24 @@ acpi_ex_opcode_2A_0T_1R (
goto cleanup;
}
- /*
- * Execute the Opcode
- */
- if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) /* logical_op (Operand0, Operand1) */ {
+ /* Execute the Opcode */
+
+ if (walk_state->op_info->flags & AML_LOGICAL_NUMERIC) {
+ /* logical_op (Operand0, Operand1) */
+
status = acpi_ex_do_logical_numeric_op (walk_state->opcode,
operand[0]->integer.value, operand[1]->integer.value,
&logical_result);
goto store_logical_result;
}
- else if (walk_state->op_info->flags & AML_LOGICAL) /* logical_op (Operand0, Operand1) */ {
+ else if (walk_state->op_info->flags & AML_LOGICAL) {
+ /* logical_op (Operand0, Operand1) */
+
status = acpi_ex_do_logical_op (walk_state->opcode, operand[0],
operand[1], &logical_result);
goto store_logical_result;
}
-
switch (walk_state->opcode) {
case AML_ACQUIRE_OP: /* Acquire (mutex_object, Timeout) */
diff --git a/drivers/acpi/executer/exoparg3.c b/drivers/acpi/executer/exoparg3.c
index 29d0b167745d..23b068adbf58 100644
--- a/drivers/acpi/executer/exoparg3.c
+++ b/drivers/acpi/executer/exoparg3.c
@@ -97,11 +97,12 @@ acpi_ex_opcode_3A_0T_0R (
acpi_status status = AE_OK;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_0T_0R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
switch (walk_state->opcode) {
- case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
+ case AML_FATAL_OP: /* Fatal (fatal_type fatal_code fatal_arg) */
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"fatal_op: Type %X Code %X Arg %X <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n",
@@ -116,9 +117,8 @@ acpi_ex_opcode_3A_0T_0R (
fatal->argument = (u32) operand[2]->integer.value;
}
- /*
- * Always signal the OS!
- */
+ /* Always signal the OS! */
+
status = acpi_os_signal (ACPI_SIGNAL_FATAL, fatal);
/* Might return while OS is shutting down, just continue */
@@ -162,21 +162,23 @@ acpi_ex_opcode_3A_1T_1R (
union acpi_operand_object *return_desc = NULL;
char *buffer;
acpi_status status = AE_OK;
- acpi_native_uint index;
+ acpi_integer index;
acpi_size length;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_3A_1T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
switch (walk_state->opcode) {
- case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */
+ case AML_MID_OP: /* Mid (Source[0], Index[1], Length[2], Result[3]) */
/*
* Create the return object. The Source operand is guaranteed to be
* either a String or a Buffer, so just use its type.
*/
- return_desc = acpi_ut_create_internal_object (ACPI_GET_OBJECT_TYPE (operand[0]));
+ return_desc = acpi_ut_create_internal_object (
+ ACPI_GET_OBJECT_TYPE (operand[0]));
if (!return_desc) {
status = AE_NO_MEMORY;
goto cleanup;
@@ -184,7 +186,7 @@ acpi_ex_opcode_3A_1T_1R (
/* Get the Integer values from the objects */
- index = (acpi_native_uint) operand[1]->integer.value;
+ index = operand[1]->integer.value;
length = (acpi_size) operand[2]->integer.value;
/*
@@ -197,7 +199,8 @@ acpi_ex_opcode_3A_1T_1R (
if ((index + length) >
operand[0]->string.length) {
- length = (acpi_size) operand[0]->string.length - index;
+ length = (acpi_size) operand[0]->string.length -
+ (acpi_size) index;
}
/* Allocate a new buffer for the String/Buffer */
diff --git a/drivers/acpi/executer/exoparg6.c b/drivers/acpi/executer/exoparg6.c
index d32624331626..17f81d42ee41 100644
--- a/drivers/acpi/executer/exoparg6.c
+++ b/drivers/acpi/executer/exoparg6.c
@@ -75,6 +75,14 @@
* fully resolved operands.
!*/
+/* Local prototypes */
+
+static u8
+acpi_ex_do_match (
+ u32 match_op,
+ union acpi_operand_object *package_obj,
+ union acpi_operand_object *match_obj);
+
/*******************************************************************************
*
@@ -92,7 +100,7 @@
*
******************************************************************************/
-u8
+static u8
acpi_ex_do_match (
u32 match_op,
union acpi_operand_object *package_obj,
@@ -216,11 +224,12 @@ acpi_ex_opcode_6A_0T_1R (
union acpi_operand_object **operand = &walk_state->operands[0];
union acpi_operand_object *return_desc = NULL;
acpi_status status = AE_OK;
- u32 index;
+ acpi_integer index;
union acpi_operand_object *this_element;
- ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R", acpi_ps_get_opcode_name (walk_state->opcode));
+ ACPI_FUNCTION_TRACE_STR ("ex_opcode_6A_0T_1R",
+ acpi_ps_get_opcode_name (walk_state->opcode));
switch (walk_state->opcode) {
@@ -241,9 +250,11 @@ acpi_ex_opcode_6A_0T_1R (
/* Get the package start_index, validate against the package length */
- index = (u32) operand[5]->integer.value;
- if (index >= (u32) operand[0]->package.count) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Index beyond package end\n"));
+ index = operand[5]->integer.value;
+ if (index >= operand[0]->package.count) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Index (%X%8.8X) beyond package end (%X)\n",
+ ACPI_FORMAT_UINT64 (index), operand[0]->package.count));
status = AE_AML_PACKAGE_LIMIT;
goto cleanup;
}
@@ -314,13 +325,12 @@ acpi_ex_opcode_6A_0T_1R (
default:
- ACPI_REPORT_ERROR (("acpi_ex_opcode_3A_0T_0R: Unknown opcode %X\n",
+ ACPI_REPORT_ERROR (("acpi_ex_opcode_6A_0T_1R: Unknown opcode %X\n",
walk_state->opcode));
status = AE_AML_BAD_OPCODE;
goto cleanup;
}
-
walk_state->result_obj = return_desc;
diff --git a/drivers/acpi/executer/exprep.c b/drivers/acpi/executer/exprep.c
index 264ef3bba31b..c9e3c68b5549 100644
--- a/drivers/acpi/executer/exprep.c
+++ b/drivers/acpi/executer/exprep.c
@@ -52,8 +52,23 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exprep")
+/* Local prototypes */
+
+static u32
+acpi_ex_decode_field_access (
+ union acpi_operand_object *obj_desc,
+ u8 field_flags,
+ u32 *return_byte_alignment);
+
#ifdef ACPI_UNDER_DEVELOPMENT
+
+static u32
+acpi_ex_generate_access (
+ u32 field_bit_offset,
+ u32 field_bit_length,
+ u32 region_length);
+
/*******************************************************************************
*
* FUNCTION: acpi_ex_generate_access
@@ -99,12 +114,14 @@ acpi_ex_generate_access (
/* Round Field start offset and length to "minimal" byte boundaries */
field_byte_offset = ACPI_DIV_8 (ACPI_ROUND_DOWN (field_bit_offset, 8));
- field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length + field_bit_offset, 8));
+ field_byte_end_offset = ACPI_DIV_8 (ACPI_ROUND_UP (field_bit_length +
+ field_bit_offset, 8));
field_byte_length = field_byte_end_offset - field_byte_offset;
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Bit length %d, Bit offset %d\n",
field_bit_length, field_bit_offset));
+
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Byte Length %d, Byte Offset %d, End Offset %d\n",
field_byte_length, field_byte_offset, field_byte_end_offset));
@@ -117,20 +134,26 @@ acpi_ex_generate_access (
*/
for (access_byte_width = 1; access_byte_width <= 8; access_byte_width <<= 1) {
/*
- * 1) Round end offset up to next access boundary and make sure that this
- * does not go beyond the end of the parent region.
- * 2) When the Access width is greater than the field_byte_length, we are done.
- * (This does not optimize for the perfectly aligned case yet).
+ * 1) Round end offset up to next access boundary and make sure that
+ * this does not go beyond the end of the parent region.
+ * 2) When the Access width is greater than the field_byte_length, we
+ * are done. (This does not optimize for the perfectly aligned
+ * case yet).
*/
if (ACPI_ROUND_UP (field_byte_end_offset, access_byte_width) <= region_length) {
- field_start_offset = ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) /
- access_byte_width;
- field_end_offset = ACPI_ROUND_UP ((field_byte_length + field_byte_offset),
- access_byte_width) / access_byte_width;
- accesses = field_end_offset - field_start_offset;
+ field_start_offset =
+ ACPI_ROUND_DOWN (field_byte_offset, access_byte_width) /
+ access_byte_width;
+
+ field_end_offset =
+ ACPI_ROUND_UP ((field_byte_length + field_byte_offset),
+ access_byte_width) / access_byte_width;
+
+ accesses = field_end_offset - field_start_offset;
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"access_width %d end is within region\n", access_byte_width));
+
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Field Start %d, Field End %d -- requires %d accesses\n",
field_start_offset, field_end_offset, accesses));
@@ -139,8 +162,8 @@ acpi_ex_generate_access (
if (accesses <= 1) {
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
- "Entire field can be accessed with one operation of size %d\n",
- access_byte_width));
+ "Entire field can be accessed with one operation of size %d\n",
+ access_byte_width));
return_VALUE (access_byte_width);
}
@@ -155,15 +178,20 @@ acpi_ex_generate_access (
}
else {
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
- "access_width %d end is NOT within region\n", access_byte_width));
+ "access_width %d end is NOT within region\n", access_byte_width));
if (access_byte_width == 1) {
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Field goes beyond end-of-region!\n"));
- return_VALUE (0); /* Field does not fit in the region at all */
- }
- /* This width goes beyond the end-of-region, back off to previous access */
+ /* Field does not fit in the region at all */
+ return_VALUE (0);
+ }
+
+ /*
+ * This width goes beyond the end-of-region, back off to
+ * previous access
+ */
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Backing off to previous optimal access width of %d\n",
minimum_access_width));
@@ -171,8 +199,10 @@ acpi_ex_generate_access (
}
}
- /* Could not read/write field with one operation, just use max access width */
-
+ /*
+ * Could not read/write field with one operation,
+ * just use max access width
+ */
ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
"Cannot access field in one operation, using width 8\n"));
return_VALUE (8);
@@ -184,8 +214,9 @@ acpi_ex_generate_access (
*
* FUNCTION: acpi_ex_decode_field_access
*
- * PARAMETERS: Access - Encoded field access bits
- * Length - Field length.
+ * PARAMETERS: obj_desc - Field object
+ * field_flags - Encoded fieldflags (contains access bits)
+ * return_byte_alignment - Where the byte alignment is returned
*
* RETURN: Field granularity (8, 16, 32 or 64) and
* byte_alignment (1, 2, 3, or 4)
@@ -214,9 +245,10 @@ acpi_ex_decode_field_access (
case AML_FIELD_ACCESS_ANY:
#ifdef ACPI_UNDER_DEVELOPMENT
- byte_alignment = acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset,
- obj_desc->common_field.bit_length,
- 0xFFFFFFFF /* Temp until we pass region_length as param */);
+ byte_alignment =
+ acpi_ex_generate_access (obj_desc->common_field.start_field_bit_offset,
+ obj_desc->common_field.bit_length,
+ 0xFFFFFFFF /* Temp until we pass region_length as parameter */);
bit_length = byte_alignment * 8;
#endif
@@ -276,6 +308,7 @@ acpi_ex_decode_field_access (
* field_flags - Access, lock_rule, and update_rule.
* The format of a field_flag is described
* in the ACPI specification
+ * field_attribute - Special attributes (not used)
* field_bit_position - Field start position
* field_bit_length - Field length in number of bits
*
@@ -337,7 +370,7 @@ acpi_ex_prep_common_field_object (
/* Setup width (access granularity) fields */
obj_desc->common_field.access_byte_width = (u8)
- ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */
+ ACPI_DIV_8 (access_bit_width); /* 1, 2, 4, 8 */
obj_desc->common_field.access_bit_width = (u8) access_bit_width;
@@ -380,11 +413,7 @@ acpi_ex_prep_common_field_object (
*
* FUNCTION: acpi_ex_prep_field_value
*
- * PARAMETERS: Node - Owning Node
- * region_node - Region in which field is being defined
- * field_flags - Access, lock_rule, and update_rule.
- * field_bit_position - Field start position
- * field_bit_length - Field length in number of bits
+ * PARAMETERS: Info - Contains all field creation info
*
* RETURN: Status
*
@@ -445,7 +474,7 @@ acpi_ex_prep_field_value (
switch (info->field_type) {
case ACPI_TYPE_LOCAL_REGION_FIELD:
- obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node);
+ obj_desc->field.region_obj = acpi_ns_get_attached_object (info->region_node);
/* An additional reference for the container */
@@ -461,8 +490,10 @@ acpi_ex_prep_field_value (
case ACPI_TYPE_LOCAL_BANK_FIELD:
obj_desc->bank_field.value = info->bank_value;
- obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (info->region_node);
- obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (info->register_node);
+ obj_desc->bank_field.region_obj = acpi_ns_get_attached_object (
+ info->region_node);
+ obj_desc->bank_field.bank_obj = acpi_ns_get_attached_object (
+ info->register_node);
/* An additional reference for the attached objects */
@@ -481,10 +512,13 @@ acpi_ex_prep_field_value (
case ACPI_TYPE_LOCAL_INDEX_FIELD:
- obj_desc->index_field.index_obj = acpi_ns_get_attached_object (info->register_node);
- obj_desc->index_field.data_obj = acpi_ns_get_attached_object (info->data_register_node);
+ obj_desc->index_field.index_obj = acpi_ns_get_attached_object (
+ info->register_node);
+ obj_desc->index_field.data_obj = acpi_ns_get_attached_object (
+ info->data_register_node);
obj_desc->index_field.value = (u32)
- (info->field_bit_position / ACPI_MUL_8 (obj_desc->field.access_byte_width));
+ (info->field_bit_position / ACPI_MUL_8 (
+ obj_desc->field.access_byte_width));
if (!obj_desc->index_field.data_obj || !obj_desc->index_field.index_obj) {
ACPI_REPORT_ERROR (("Null Index Object during field prep\n"));
diff --git a/drivers/acpi/executer/exregion.c b/drivers/acpi/executer/exregion.c
index 7cfd0684c70b..723aaef4bb4a 100644
--- a/drivers/acpi/executer/exregion.c
+++ b/drivers/acpi/executer/exregion.c
@@ -115,7 +115,6 @@ acpi_ex_system_memory_space_handler (
return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
}
-
#ifndef ACPI_MISALIGNED_TRANSFERS
/*
* Hardware does not support non-aligned data transfers, we must verify
@@ -134,7 +133,8 @@ acpi_ex_system_memory_space_handler (
*/
if ((address < mem_info->mapped_physical_address) ||
(((acpi_integer) address + length) >
- ((acpi_integer) mem_info->mapped_physical_address + mem_info->mapped_length))) {
+ ((acpi_integer)
+ mem_info->mapped_physical_address + mem_info->mapped_length))) {
/*
* The request cannot be resolved by the current memory mapping;
* Delete the existing mapping and create a new one.
@@ -150,7 +150,9 @@ acpi_ex_system_memory_space_handler (
* Don't attempt to map memory beyond the end of the region, and
* constrain the maximum mapping size to something reasonable.
*/
- window_size = (acpi_size) ((mem_info->address + mem_info->length) - address);
+ window_size = (acpi_size)
+ ((mem_info->address + mem_info->length) - address);
+
if (window_size > ACPI_SYSMEM_REGION_WINDOW_SIZE) {
window_size = ACPI_SYSMEM_REGION_WINDOW_SIZE;
}
@@ -160,8 +162,9 @@ acpi_ex_system_memory_space_handler (
status = acpi_os_map_memory (address, window_size,
(void **) &mem_info->mapped_logical_address);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not map memory at %8.8X%8.8X, size %X\n",
- ACPI_FORMAT_UINT64 (address), (u32) window_size));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not map memory at %8.8X%8.8X, size %X\n",
+ ACPI_FORMAT_UINT64 (address), (u32) window_size));
mem_info->mapped_length = 0;
return_ACPI_STATUS (status);
}
@@ -177,10 +180,12 @@ acpi_ex_system_memory_space_handler (
* access
*/
logical_addr_ptr = mem_info->mapped_logical_address +
- ((acpi_integer) address - (acpi_integer) mem_info->mapped_physical_address);
+ ((acpi_integer) address -
+ (acpi_integer) mem_info->mapped_physical_address);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
- "system_memory %d (%d width) Address=%8.8X%8.8X\n", function, bit_width,
+ "system_memory %d (%d width) Address=%8.8X%8.8X\n",
+ function, bit_width,
ACPI_FORMAT_UINT64 (address)));
/*
@@ -298,13 +303,15 @@ acpi_ex_system_io_space_handler (
switch (function) {
case ACPI_READ:
- status = acpi_os_read_port ((acpi_io_address) address, &value32, bit_width);
+ status = acpi_os_read_port ((acpi_io_address) address,
+ &value32, bit_width);
*value = value32;
break;
case ACPI_WRITE:
- status = acpi_os_write_port ((acpi_io_address) address, (u32) *value, bit_width);
+ status = acpi_os_write_port ((acpi_io_address) address,
+ (u32) *value, bit_width);
break;
default:
@@ -375,12 +382,14 @@ acpi_ex_pci_config_space_handler (
case ACPI_READ:
*value = 0;
- status = acpi_os_read_pci_configuration (pci_id, pci_register, value, bit_width);
+ status = acpi_os_read_pci_configuration (pci_id, pci_register,
+ value, bit_width);
break;
case ACPI_WRITE:
- status = acpi_os_write_pci_configuration (pci_id, pci_register, *value, bit_width);
+ status = acpi_os_write_pci_configuration (pci_id, pci_register,
+ *value, bit_width);
break;
default:
@@ -505,8 +514,7 @@ acpi_ex_data_table_space_handler (
logical_addr_ptr = ACPI_PHYSADDR_TO_PTR (address);
-
- /* Perform the memory read or write */
+ /* Perform the memory read or write */
switch (function) {
case ACPI_READ:
diff --git a/drivers/acpi/executer/exresnte.c b/drivers/acpi/executer/exresnte.c
index 7936329a0e35..21d5c74fa309 100644
--- a/drivers/acpi/executer/exresnte.c
+++ b/drivers/acpi/executer/exresnte.c
@@ -210,15 +210,15 @@ acpi_ex_resolve_node_to_value (
case ACPI_TYPE_LOCAL_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_FIELD:
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "field_read Node=%p source_desc=%p Type=%X\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "field_read Node=%p source_desc=%p Type=%X\n",
node, source_desc, entry_type));
status = acpi_ex_read_data_from_field (walk_state, source_desc, &obj_desc);
break;
- /*
- * For these objects, just return the object attached to the Node
- */
+ /* For these objects, just return the object attached to the Node */
+
case ACPI_TYPE_MUTEX:
case ACPI_TYPE_METHOD:
case ACPI_TYPE_POWER:
@@ -233,12 +233,12 @@ acpi_ex_resolve_node_to_value (
acpi_ut_add_reference (obj_desc);
break;
-
/* TYPE_ANY is untyped, and thus there is no object associated with it */
case ACPI_TYPE_ANY:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Untyped entry %p, no attached object!\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Untyped entry %p, no attached object!\n",
node));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE); /* Cannot be AE_TYPE */
@@ -259,7 +259,8 @@ acpi_ex_resolve_node_to_value (
default:
/* No named references are allowed here */
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unsupported Reference opcode %X (%s)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unsupported Reference opcode %X (%s)\n",
source_desc->reference.opcode,
acpi_ps_get_opcode_name (source_desc->reference.opcode)));
@@ -268,11 +269,12 @@ acpi_ex_resolve_node_to_value (
break;
- /* Default case is for unknown types */
-
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Node %p - Unknown object type %X\n",
+ /* Default case is for unknown types */
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Node %p - Unknown object type %X\n",
node, entry_type));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
@@ -280,7 +282,7 @@ acpi_ex_resolve_node_to_value (
} /* switch (entry_type) */
- /* Put the object descriptor on the stack */
+ /* Return the object descriptor */
*object_ptr = (void *) obj_desc;
return_ACPI_STATUS (status);
diff --git a/drivers/acpi/executer/exresolv.c b/drivers/acpi/executer/exresolv.c
index 7be604911156..3de45672379a 100644
--- a/drivers/acpi/executer/exresolv.c
+++ b/drivers/acpi/executer/exresolv.c
@@ -54,6 +54,13 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exresolv")
+/* Local prototypes */
+
+static acpi_status
+acpi_ex_resolve_object_to_value (
+ union acpi_operand_object **stack_ptr,
+ struct acpi_walk_state *walk_state);
+
/*******************************************************************************
*
@@ -96,6 +103,11 @@ acpi_ex_resolve_to_value (
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
+
+ if (!*stack_ptr) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Internal - null pointer\n"));
+ return_ACPI_STATUS (AE_AML_NO_OPERAND);
+ }
}
/*
@@ -120,18 +132,17 @@ acpi_ex_resolve_to_value (
*
* FUNCTION: acpi_ex_resolve_object_to_value
*
- * PARAMETERS: stack_ptr - Pointer to a stack location that contains a
- * ptr to an internal object.
+ * PARAMETERS: stack_ptr - Pointer to an internal object
* walk_state - Current method state
*
* RETURN: Status
*
- * DESCRIPTION: Retrieve the value from an internal object. The Reference type
+ * DESCRIPTION: Retrieve the value from an internal object. The Reference type
* uses the associated AML opcode to determine the value.
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_resolve_object_to_value (
union acpi_operand_object **stack_ptr,
struct acpi_walk_state *walk_state)
@@ -159,7 +170,7 @@ acpi_ex_resolve_object_to_value (
case AML_NAME_OP:
/*
- * Convert indirect name ptr to a direct name ptr.
+ * Convert name reference to a namespace node
* Then, acpi_ex_resolve_node_to_value can be used to get the value
*/
temp_node = stack_desc->reference.object;
@@ -168,7 +179,7 @@ acpi_ex_resolve_object_to_value (
acpi_ut_remove_reference (stack_desc);
- /* Put direct name pointer onto stack and exit */
+ /* Return the namespace node */
(*stack_ptr) = temp_node;
break;
@@ -255,10 +266,19 @@ acpi_ex_resolve_object_to_value (
break;
+ case AML_INT_NAMEPATH_OP: /* Reference to a named object */
+
+ /* Get the object pointed to by the namespace node */
+
+ *stack_ptr = (stack_desc->reference.node)->object;
+ acpi_ut_add_reference (*stack_ptr);
+ acpi_ut_remove_reference (stack_desc);
+ break;
default:
- ACPI_REPORT_ERROR (("During resolve, Unknown Reference opcode %X (%s) in %p\n",
+ ACPI_REPORT_ERROR ((
+ "During resolve, Unknown Reference opcode %X (%s) in %p\n",
opcode, acpi_ps_get_opcode_name (opcode), stack_desc));
status = AE_AML_INTERNAL;
break;
@@ -278,9 +298,8 @@ acpi_ex_resolve_object_to_value (
break;
- /*
- * These cases may never happen here, but just in case..
- */
+ /* These cases may never happen here, but just in case.. */
+
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
@@ -333,9 +352,8 @@ acpi_ex_resolve_multiple (
ACPI_FUNCTION_TRACE ("acpi_ex_resolve_multiple");
- /*
- * Operand can be either a namespace node or an operand descriptor
- */
+ /* Operand can be either a namespace node or an operand descriptor */
+
switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
case ACPI_DESC_TYPE_OPERAND:
type = obj_desc->common.type;
@@ -357,10 +375,8 @@ acpi_ex_resolve_multiple (
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
+ /* If type is anything other than a reference, we are done */
- /*
- * If type is anything other than a reference, we are done
- */
if (type != ACPI_TYPE_LOCAL_REFERENCE) {
goto exit;
}
@@ -382,8 +398,9 @@ acpi_ex_resolve_multiple (
/* All "References" point to a NS node */
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
- ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
- node, acpi_ut_get_descriptor_name (node)));
+ ACPI_REPORT_ERROR ((
+ "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
+ node, acpi_ut_get_descriptor_name (node)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
@@ -440,8 +457,9 @@ acpi_ex_resolve_multiple (
/* All "References" point to a NS node */
if (ACPI_GET_DESCRIPTOR_TYPE (node) != ACPI_DESC_TYPE_NAMED) {
- ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
- node, acpi_ut_get_descriptor_name (node)));
+ ACPI_REPORT_ERROR ((
+ "acpi_ex_resolve_multiple: Not a NS node %p [%s]\n",
+ node, acpi_ut_get_descriptor_name (node)));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
@@ -468,7 +486,7 @@ acpi_ex_resolve_multiple (
if (return_desc) {
status = acpi_ds_method_data_get_value (obj_desc->reference.opcode,
- obj_desc->reference.offset, walk_state, &obj_desc);
+ obj_desc->reference.offset, walk_state, &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -500,7 +518,8 @@ acpi_ex_resolve_multiple (
default:
- ACPI_REPORT_ERROR (("acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
+ ACPI_REPORT_ERROR ((
+ "acpi_ex_resolve_multiple: Unknown Reference subtype %X\n",
obj_desc->reference.opcode));
return_ACPI_STATUS (AE_AML_INTERNAL);
}
diff --git a/drivers/acpi/executer/exresop.c b/drivers/acpi/executer/exresop.c
index c92890220c32..d8b470eefe7a 100644
--- a/drivers/acpi/executer/exresop.c
+++ b/drivers/acpi/executer/exresop.c
@@ -52,6 +52,14 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exresop")
+/* Local prototypes */
+
+static acpi_status
+acpi_ex_check_object_type (
+ acpi_object_type type_needed,
+ acpi_object_type this_type,
+ void *object);
+
/*******************************************************************************
*
@@ -67,7 +75,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_check_object_type (
acpi_object_type type_needed,
acpi_object_type this_type,
@@ -142,6 +150,7 @@ acpi_ex_resolve_operands (
const struct acpi_opcode_info *op_info;
u32 this_arg_type;
acpi_object_type type_needed;
+ u16 target_op = 0;
ACPI_FUNCTION_TRACE_U32 ("ex_resolve_operands", opcode);
@@ -160,7 +169,8 @@ acpi_ex_resolve_operands (
return_ACPI_STATUS (AE_AML_INTERNAL);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Opcode %X [%s] required_operand_types=%8.8X \n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Opcode %X [%s] required_operand_types=%8.8X \n",
opcode, op_info->name, arg_types));
/*
@@ -187,7 +197,7 @@ acpi_ex_resolve_operands (
switch (ACPI_GET_DESCRIPTOR_TYPE (obj_desc)) {
case ACPI_DESC_TYPE_NAMED:
- /* Node */
+ /* Namespace Node */
object_type = ((struct acpi_namespace_node *) obj_desc)->type;
break;
@@ -202,16 +212,16 @@ acpi_ex_resolve_operands (
/* Check for bad acpi_object_type */
if (!acpi_ut_valid_object_type (object_type)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Bad operand object type [%X]\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Bad operand object type [%X]\n",
object_type));
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
if (object_type == (u8) ACPI_TYPE_LOCAL_REFERENCE) {
- /*
- * Decode the Reference
- */
+ /* Decode the Reference */
+
op_info = acpi_ps_get_opcode_info (opcode);
if (op_info->class == AML_CLASS_UNKNOWN) {
return_ACPI_STATUS (AE_AML_BAD_OPCODE);
@@ -219,12 +229,17 @@ acpi_ex_resolve_operands (
switch (obj_desc->reference.opcode) {
case AML_DEBUG_OP:
+ target_op = AML_DEBUG_OP;
+
+ /*lint -fallthrough */
+
case AML_NAME_OP:
case AML_INDEX_OP:
case AML_REF_OF_OP:
case AML_ARG_OP:
case AML_LOCAL_OP:
- case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
+ case AML_LOAD_OP: /* ddb_handle from LOAD_OP or LOAD_TABLE_OP */
+ case AML_INT_NAMEPATH_OP: /* Reference to a named object */
ACPI_DEBUG_ONLY_MEMBERS (ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
"Operand is a Reference, ref_opcode [%s]\n",
@@ -254,10 +269,8 @@ acpi_ex_resolve_operands (
return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
}
+ /* Get one argument type, point to the next */
- /*
- * Get one argument type, point to the next
- */
this_arg_type = GET_CURRENT_ARG_TYPE (arg_types);
INCREMENT_ARG_LIST (arg_types);
@@ -271,26 +284,31 @@ acpi_ex_resolve_operands (
if ((ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_OPERAND) &&
(ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_STRING)) {
/*
- * String found - the string references a named object and must be
- * resolved to a node
+ * String found - the string references a named object and
+ * must be resolved to a node
*/
goto next_operand;
}
- /* Else not a string - fall through to the normal Reference case below */
+ /*
+ * Else not a string - fall through to the normal Reference
+ * case below
+ */
/*lint -fallthrough */
case ARGI_REFERENCE: /* References: */
case ARGI_INTEGER_REF:
case ARGI_OBJECT_REF:
case ARGI_DEVICE_REF:
- case ARGI_TARGETREF: /* Allows implicit conversion rules before store */
- case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
- case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */
-
- /* Need an operand of type ACPI_TYPE_LOCAL_REFERENCE */
+ case ARGI_TARGETREF: /* Allows implicit conversion rules before store */
+ case ARGI_FIXED_TARGET: /* No implicit conversion before store to target */
+ case ARGI_SIMPLE_TARGET: /* Name, Local, or Arg - no implicit conversion */
- if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) /* Node (name) ptr OK as-is */ {
+ /*
+ * Need an operand of type ACPI_TYPE_LOCAL_REFERENCE
+ * A Namespace Node is OK as-is
+ */
+ if (ACPI_GET_DESCRIPTOR_TYPE (obj_desc) == ACPI_DESC_TYPE_NAMED) {
goto next_operand;
}
@@ -300,11 +318,9 @@ acpi_ex_resolve_operands (
return_ACPI_STATUS (status);
}
- if (AML_NAME_OP == obj_desc->reference.opcode) {
- /*
- * Convert an indirect name ptr to direct name ptr and put
- * it on the stack
- */
+ if (obj_desc->reference.opcode == AML_NAME_OP) {
+ /* Convert a named reference to the actual named object */
+
temp_node = obj_desc->reference.object;
acpi_ut_remove_reference (obj_desc);
(*stack_ptr) = temp_node;
@@ -332,7 +348,6 @@ acpi_ex_resolve_operands (
break;
}
-
/*
* Resolve this object to a value
*/
@@ -392,7 +407,7 @@ acpi_ex_resolve_operands (
/*
* The more complex cases allow multiple resolved object types
*/
- case ARGI_INTEGER: /* Number */
+ case ARGI_INTEGER:
/*
* Need an operand of type ACPI_TYPE_INTEGER,
@@ -563,7 +578,7 @@ acpi_ex_resolve_operands (
case ARGI_REGION_OR_FIELD:
- /* Need an operand of type ACPI_TYPE_REGION or a FIELD in a region */
+ /* Need an operand of type REGION or a FIELD in a region */
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_REGION:
@@ -614,6 +629,12 @@ acpi_ex_resolve_operands (
break;
}
+ if (target_op == AML_DEBUG_OP) {
+ /* Allow store of any object to the Debug object */
+
+ break;
+ }
+
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Needed Integer/Buffer/String/Package/Ref/Ddb], found [%s] %p\n",
acpi_ut_get_object_type_name (obj_desc), obj_desc));
@@ -652,8 +673,7 @@ next_operand:
if (GET_CURRENT_ARG_TYPE (arg_types)) {
stack_ptr--;
}
-
- } /* while (*Types) */
+ }
return_ACPI_STATUS (status);
}
diff --git a/drivers/acpi/executer/exstore.c b/drivers/acpi/executer/exstore.c
index e0fc6aba1253..2725db0901b8 100644
--- a/drivers/acpi/executer/exstore.c
+++ b/drivers/acpi/executer/exstore.c
@@ -48,11 +48,171 @@
#include <acpi/acinterp.h>
#include <acpi/amlcode.h>
#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exstore")
+/* Local prototypes */
+
+static void
+acpi_ex_do_debug_object (
+ union acpi_operand_object *source_desc,
+ u32 level,
+ u32 index);
+
+static acpi_status
+acpi_ex_store_object_to_index (
+ union acpi_operand_object *val_desc,
+ union acpi_operand_object *dest_desc,
+ struct acpi_walk_state *walk_state);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ex_do_debug_object
+ *
+ * PARAMETERS: source_desc - Value to be stored
+ * Level - Indentation level (used for packages)
+ * Index - Current package element, zero if not pkg
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Handles stores to the Debug Object.
+ *
+ ******************************************************************************/
+
+static void
+acpi_ex_do_debug_object (
+ union acpi_operand_object *source_desc,
+ u32 level,
+ u32 index)
+{
+ u32 i;
+
+
+ ACPI_FUNCTION_TRACE_PTR ("ex_do_debug_object", source_desc);
+
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %*s",
+ level, " "));
+
+ /* Display index for package output only */
+
+ if (index > 0) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT,
+ "(%.2u) ", index -1));
+ }
+
+ if (!source_desc) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "<Null Object>\n"));
+ return_VOID;
+ }
+
+ if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_OPERAND) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: ",
+ acpi_ut_get_object_type_name (source_desc)));
+
+ if (!acpi_ut_valid_internal_object (source_desc)) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT,
+ "%p, Invalid Internal Object!\n", source_desc));
+ return_VOID;
+ }
+ }
+ else if (ACPI_GET_DESCRIPTOR_TYPE (source_desc) == ACPI_DESC_TYPE_NAMED) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%s: %p\n",
+ acpi_ut_get_type_name (((struct acpi_namespace_node *) source_desc)->type),
+ source_desc));
+ return_VOID;
+ }
+ else {
+ return_VOID;
+ }
+
+ switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
+ case ACPI_TYPE_INTEGER:
+
+ /* Output correct integer width */
+
+ if (acpi_gbl_integer_byte_width == 4) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n",
+ (u32) source_desc->integer.value));
+ }
+ else {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
+ ACPI_FORMAT_UINT64 (source_desc->integer.value)));
+ }
+ break;
+
+ case ACPI_TYPE_BUFFER:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]",
+ (u32) source_desc->buffer.length));
+ ACPI_DUMP_BUFFER (source_desc->buffer.pointer,
+ (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32);
+ break;
+
+ case ACPI_TYPE_STRING:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n",
+ source_desc->string.length, source_desc->string.pointer));
+ break;
+
+ case ACPI_TYPE_PACKAGE:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X Elements]\n",
+ source_desc->package.count));
+
+ /* Output the entire contents of the package */
+
+ for (i = 0; i < source_desc->package.count; i++) {
+ acpi_ex_do_debug_object (source_desc->package.elements[i],
+ level+4, i+1);
+ }
+ break;
+
+ case ACPI_TYPE_LOCAL_REFERENCE:
+
+ if (source_desc->reference.opcode == AML_INDEX_OP) {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s, 0x%X]\n",
+ acpi_ps_get_opcode_name (source_desc->reference.opcode),
+ source_desc->reference.offset));
+ }
+ else {
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[%s]\n",
+ acpi_ps_get_opcode_name (source_desc->reference.opcode)));
+ }
+
+
+ if (source_desc->reference.object) {
+ if (ACPI_GET_DESCRIPTOR_TYPE (source_desc->reference.object) ==
+ ACPI_DESC_TYPE_NAMED) {
+ acpi_ex_do_debug_object (((struct acpi_namespace_node *)
+ source_desc->reference.object)->object,
+ level+4, 0);
+ }
+ else {
+ acpi_ex_do_debug_object (source_desc->reference.object, level+4, 0);
+ }
+ }
+ else if (source_desc->reference.node) {
+ acpi_ex_do_debug_object ((source_desc->reference.node)->object,
+ level+4, 0);
+ }
+ break;
+
+ default:
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p %s\n",
+ source_desc, acpi_ut_get_object_type_name (source_desc)));
+ break;
+ }
+
+ ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
+ return_VOID;
+}
+
/*******************************************************************************
*
@@ -154,8 +314,9 @@ 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, ACPI_IMPLICIT_CONVERSION);
+ status = acpi_ex_store_object_to_node (source_desc,
+ ref_desc->reference.object,
+ walk_state, ACPI_IMPLICIT_CONVERSION);
break;
@@ -173,7 +334,7 @@ acpi_ex_store (
/* Store to a method local/arg */
status = acpi_ds_store_object_to_local (ref_desc->reference.opcode,
- ref_desc->reference.offset, source_desc, walk_state);
+ ref_desc->reference.offset, source_desc, walk_state);
break;
@@ -187,60 +348,7 @@ acpi_ex_store (
"**** Write to Debug Object: Object %p %s ****:\n\n",
source_desc, acpi_ut_get_object_type_name (source_desc)));
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[ACPI Debug] %s: ",
- acpi_ut_get_object_type_name (source_desc)));
-
- if (!acpi_ut_valid_internal_object (source_desc)) {
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT,
- "%p, Invalid Internal Object!\n", source_desc));
- break;
- }
-
- switch (ACPI_GET_OBJECT_TYPE (source_desc)) {
- case ACPI_TYPE_INTEGER:
-
- if (acpi_gbl_integer_byte_width == 4) {
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X\n",
- (u32) source_desc->integer.value));
- }
- else {
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "0x%8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (source_desc->integer.value)));
- }
- break;
-
-
- case ACPI_TYPE_BUFFER:
-
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X]",
- (u32) source_desc->buffer.length));
- ACPI_DUMP_BUFFER (source_desc->buffer.pointer,
- (source_desc->buffer.length < 32) ? source_desc->buffer.length : 32);
- break;
-
-
- case ACPI_TYPE_STRING:
-
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] \"%s\"\n",
- source_desc->string.length, source_desc->string.pointer));
- break;
-
-
- case ACPI_TYPE_PACKAGE:
-
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "[0x%.2X] Elements Ptr - %p\n",
- source_desc->package.count, source_desc->package.elements));
- break;
-
-
- default:
-
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_DEBUG_OBJECT, "%p\n",
- source_desc));
- break;
- }
-
- ACPI_DEBUG_PRINT_RAW ((ACPI_DB_EXEC, "\n"));
+ acpi_ex_do_debug_object (source_desc, 0, 0);
break;
@@ -272,7 +380,7 @@ acpi_ex_store (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ex_store_object_to_index (
union acpi_operand_object *source_desc,
union acpi_operand_object *index_desc,
@@ -313,16 +421,22 @@ acpi_ex_store_object_to_index (
if (obj_desc) {
/* Decrement reference count by the ref count of the parent package */
- for (i = 0; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) {
+ for (i = 0;
+ i < ((union acpi_operand_object *)
+ index_desc->reference.object)->common.reference_count;
+ i++) {
acpi_ut_remove_reference (obj_desc);
}
}
*(index_desc->reference.where) = new_desc;
- /* Increment reference count by the ref count of the parent package -1 */
+ /* Increment ref count by the ref count of the parent package-1 */
- for (i = 1; i < ((union acpi_operand_object *) index_desc->reference.object)->common.reference_count; i++) {
+ for (i = 1;
+ i < ((union acpi_operand_object *)
+ index_desc->reference.object)->common.reference_count;
+ i++) {
acpi_ut_add_reference (new_desc);
}
@@ -440,9 +554,8 @@ acpi_ex_store_object_to_node (
ACPI_FUNCTION_TRACE_PTR ("ex_store_object_to_node", source_desc);
- /*
- * Get current type of the node, and object attached to Node
- */
+ /* Get current type of the node, and object attached to Node */
+
target_type = acpi_ns_get_type (node);
target_desc = acpi_ns_get_attached_object (node);
@@ -467,19 +580,18 @@ acpi_ex_store_object_to_node (
target_type = ACPI_TYPE_ANY;
}
- /*
- * Do the actual store operation
- */
+ /* Do the actual store operation */
+
switch (target_type) {
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
case ACPI_TYPE_LOCAL_BANK_FIELD:
case ACPI_TYPE_LOCAL_INDEX_FIELD:
- /*
- * For fields, copy the source data to the target field.
- */
- status = acpi_ex_write_data_to_field (source_desc, target_desc, &walk_state->result_obj);
+ /* For fields, copy the source data to the target field. */
+
+ status = acpi_ex_write_data_to_field (source_desc, target_desc,
+ &walk_state->result_obj);
break;
@@ -493,7 +605,8 @@ acpi_ex_store_object_to_node (
*
* Copy and/or convert the source object to a new target object
*/
- status = acpi_ex_store_object_to_object (source_desc, target_desc, &new_desc, walk_state);
+ status = acpi_ex_store_object_to_object (source_desc, target_desc,
+ &new_desc, walk_state);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -526,7 +639,8 @@ acpi_ex_store_object_to_node (
/* No conversions for all other types. Just attach the source object */
- status = acpi_ns_attach_object (node, source_desc, ACPI_GET_OBJECT_TYPE (source_desc));
+ status = acpi_ns_attach_object (node, source_desc,
+ ACPI_GET_OBJECT_TYPE (source_desc));
break;
}
diff --git a/drivers/acpi/executer/exstoren.c b/drivers/acpi/executer/exstoren.c
index d3677feb07fd..120f30ed0bd4 100644
--- a/drivers/acpi/executer/exstoren.c
+++ b/drivers/acpi/executer/exstoren.c
@@ -81,9 +81,8 @@ acpi_ex_resolve_object (
ACPI_FUNCTION_TRACE ("ex_resolve_object");
- /*
- * Ensure we have a Target that can be stored to
- */
+ /* Ensure we have a Target that can be stored to */
+
switch (target_type) {
case ACPI_TYPE_BUFFER_FIELD:
case ACPI_TYPE_LOCAL_REGION_FIELD:
@@ -118,16 +117,14 @@ acpi_ex_resolve_object (
break;
}
- /*
- * Must have a Integer, Buffer, or String
- */
+ /* Must have a Integer, Buffer, or String */
+
if ((ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_INTEGER) &&
(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_BUFFER) &&
(ACPI_GET_OBJECT_TYPE (source_desc) != ACPI_TYPE_STRING) &&
!((ACPI_GET_OBJECT_TYPE (source_desc) == ACPI_TYPE_LOCAL_REFERENCE) && (source_desc->reference.opcode == AML_LOAD_OP))) {
- /*
- * Conversion successful but still not a valid type
- */
+ /* Conversion successful but still not a valid type */
+
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Cannot assign type %s to %s (must be type Int/Str/Buf)\n",
acpi_ut_get_object_type_name (source_desc),
@@ -140,9 +137,8 @@ acpi_ex_resolve_object (
case ACPI_TYPE_LOCAL_ALIAS:
case ACPI_TYPE_LOCAL_METHOD_ALIAS:
- /*
- * Aliases are resolved by acpi_ex_prep_operands
- */
+ /* Aliases are resolved by acpi_ex_prep_operands */
+
ACPI_REPORT_ERROR (("Store into Alias - should never happen\n"));
status = AE_AML_INTERNAL;
break;
diff --git a/drivers/acpi/executer/exstorob.c b/drivers/acpi/executer/exstorob.c
index 05e1ecae8d92..12d1527669c8 100644
--- a/drivers/acpi/executer/exstorob.c
+++ b/drivers/acpi/executer/exstorob.c
@@ -128,7 +128,8 @@ acpi_ex_store_buffer_to_buffer (
else {
/* Truncate the source, copy only what will fit */
- ACPI_MEMCPY (target_desc->buffer.pointer, buffer, target_desc->buffer.length);
+ ACPI_MEMCPY (target_desc->buffer.pointer, buffer,
+ target_desc->buffer.length);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
"Truncating source buffer from %X to %X\n",
@@ -183,7 +184,8 @@ acpi_ex_store_string_to_string (
* String will fit in existing non-static buffer.
* Clear old string and copy in the new one
*/
- ACPI_MEMSET (target_desc->string.pointer, 0, (acpi_size) target_desc->string.length + 1);
+ ACPI_MEMSET (target_desc->string.pointer, 0,
+ (acpi_size) target_desc->string.length + 1);
ACPI_MEMCPY (target_desc->string.pointer, buffer, length);
}
else {
@@ -198,7 +200,8 @@ acpi_ex_store_string_to_string (
ACPI_MEM_FREE (target_desc->string.pointer);
}
- target_desc->string.pointer = ACPI_MEM_CALLOCATE ((acpi_size) length + 1);
+ target_desc->string.pointer = ACPI_MEM_CALLOCATE (
+ (acpi_size) length + 1);
if (!target_desc->string.pointer) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
diff --git a/drivers/acpi/executer/exsystem.c b/drivers/acpi/executer/exsystem.c
index f92efc512890..cafa702108dc 100644
--- a/drivers/acpi/executer/exsystem.c
+++ b/drivers/acpi/executer/exsystem.c
@@ -55,8 +55,8 @@
*
* FUNCTION: acpi_ex_system_wait_semaphore
*
- * PARAMETERS: Semaphore - OSD semaphore to wait on
- * Timeout - Max time to wait
+ * PARAMETERS: Semaphore - Semaphore to wait on
+ * Timeout - Max time to wait
*
* RETURN: Status
*
@@ -90,7 +90,8 @@ acpi_ex_system_wait_semaphore (
status = acpi_os_wait_semaphore (semaphore, 1, timeout);
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "*** Thread awake after blocking, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "*** Thread awake after blocking, %s\n",
acpi_format_exception (status)));
/* Reacquire the interpreter */
@@ -111,8 +112,8 @@ acpi_ex_system_wait_semaphore (
*
* FUNCTION: acpi_ex_system_do_stall
*
- * PARAMETERS: how_long - The amount of time to stall,
- * in microseconds
+ * PARAMETERS: how_long - The amount of time to stall,
+ * in microseconds
*
* RETURN: Status
*
@@ -141,7 +142,8 @@ acpi_ex_system_do_stall (
* (ACPI specifies 100 usec as max, but this gives some slack in
* order to support existing BIOSs)
*/
- ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n", how_long));
+ ACPI_REPORT_ERROR (("Stall: Time parameter is too large (%d)\n",
+ how_long));
status = AE_AML_OPERAND_VALUE;
}
else {
@@ -156,8 +158,8 @@ acpi_ex_system_do_stall (
*
* FUNCTION: acpi_ex_system_do_suspend
*
- * PARAMETERS: how_long - The amount of time to suspend,
- * in milliseconds
+ * PARAMETERS: how_long - The amount of time to suspend,
+ * in milliseconds
*
* RETURN: None
*
@@ -192,8 +194,8 @@ acpi_ex_system_do_suspend (
*
* FUNCTION: acpi_ex_system_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
*
@@ -218,16 +220,15 @@ acpi_ex_system_acquire_mutex (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
- /*
- * Support for the _GL_ Mutex object -- go get the global lock
- */
+ /* Support for the _GL_ Mutex object -- go get the global lock */
+
if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
status = acpi_ev_acquire_global_lock ((u16) time_desc->integer.value);
return_ACPI_STATUS (status);
}
status = acpi_ex_system_wait_semaphore (obj_desc->mutex.semaphore,
- (u16) time_desc->integer.value);
+ (u16) time_desc->integer.value);
return_ACPI_STATUS (status);
}
@@ -236,7 +237,7 @@ acpi_ex_system_acquire_mutex (
*
* FUNCTION: acpi_ex_system_release_mutex
*
- * PARAMETERS: *obj_desc - The object descriptor for this op
+ * PARAMETERS: obj_desc - The object descriptor for this op
*
* RETURN: Status
*
@@ -261,9 +262,8 @@ acpi_ex_system_release_mutex (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
- /*
- * Support for the _GL_ Mutex object -- release the global lock
- */
+ /* Support for the _GL_ Mutex object -- release the global lock */
+
if (obj_desc->mutex.semaphore == acpi_gbl_global_lock_semaphore) {
status = acpi_ev_release_global_lock ();
return_ACPI_STATUS (status);
@@ -278,9 +278,9 @@ acpi_ex_system_release_mutex (
*
* FUNCTION: acpi_ex_system_signal_event
*
- * PARAMETERS: *obj_desc - The object descriptor for this op
+ * PARAMETERS: obj_desc - The object descriptor for this op
*
- * RETURN: AE_OK
+ * RETURN: Status
*
* DESCRIPTION: Provides an access point to perform synchronization operations
* within the AML.
@@ -309,8 +309,8 @@ acpi_ex_system_signal_event (
*
* FUNCTION: acpi_ex_system_wait_event
*
- * 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
*
@@ -333,7 +333,7 @@ acpi_ex_system_wait_event (
if (obj_desc) {
status = acpi_ex_system_wait_semaphore (obj_desc->event.semaphore,
- (u16) time_desc->integer.value);
+ (u16) time_desc->integer.value);
}
return_ACPI_STATUS (status);
@@ -344,7 +344,7 @@ acpi_ex_system_wait_event (
*
* FUNCTION: acpi_ex_system_reset_event
*
- * PARAMETERS: *obj_desc - The object descriptor for this op
+ * PARAMETERS: obj_desc - The object descriptor for this op
*
* RETURN: Status
*
diff --git a/drivers/acpi/executer/exutils.c b/drivers/acpi/executer/exutils.c
index 40c6abb8b49a..5c7ec0c04177 100644
--- a/drivers/acpi/executer/exutils.c
+++ b/drivers/acpi/executer/exutils.c
@@ -67,22 +67,31 @@
#define _COMPONENT ACPI_EXECUTER
ACPI_MODULE_NAME ("exutils")
+/* Local prototypes */
-#ifndef ACPI_NO_METHOD_EXECUTION
+static u32
+acpi_ex_digits_needed (
+ acpi_integer value,
+ u32 base);
+
+#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
*
* FUNCTION: acpi_ex_enter_interpreter
*
* PARAMETERS: None
*
+ * RETURN: Status
+ *
* DESCRIPTION: Enter the interpreter execution region. Failure to enter
* the interpreter region is a fatal system error
*
******************************************************************************/
acpi_status
-acpi_ex_enter_interpreter (void)
+acpi_ex_enter_interpreter (
+ void)
{
acpi_status status;
@@ -104,6 +113,8 @@ acpi_ex_enter_interpreter (void)
*
* PARAMETERS: None
*
+ * RETURN: None
+ *
* DESCRIPTION: Exit the interpreter execution region
*
* Cases where the interpreter is unlocked:
@@ -119,7 +130,8 @@ acpi_ex_enter_interpreter (void)
******************************************************************************/
void
-acpi_ex_exit_interpreter (void)
+acpi_ex_exit_interpreter (
+ void)
{
acpi_status status;
@@ -212,7 +224,8 @@ acpi_ex_acquire_global_lock (
locked = TRUE;
}
else {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not acquire Global Lock, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Could not acquire Global Lock, %s\n",
acpi_format_exception (status)));
}
}
@@ -228,7 +241,7 @@ acpi_ex_acquire_global_lock (
* PARAMETERS: locked_by_me - Return value from corresponding call to
* acquire_global_lock.
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Release the global lock if it is locked.
*
@@ -269,11 +282,14 @@ acpi_ex_release_global_lock (
* PARAMETERS: Value - Value to be represented
* Base - Base of representation
*
- * RETURN: the number of digits needed to represent Value in Base
+ * RETURN: The number of digits.
+ *
+ * DESCRIPTION: Calculate the number of digits needed to represent the Value
+ * in the given Base (Radix)
*
******************************************************************************/
-u32
+static u32
acpi_ex_digits_needed (
acpi_integer value,
u32 base)
@@ -312,6 +328,8 @@ acpi_ex_digits_needed (
* PARAMETERS: numeric_id - EISA ID to be converted
* out_string - Where to put the converted string (8 bytes)
*
+ * RETURN: None
+ *
* DESCRIPTION: Convert a numeric EISA ID to string representation
*
******************************************************************************/
@@ -349,7 +367,10 @@ acpi_ex_eisa_id_to_string (
* PARAMETERS: Value - Value to be converted
* out_string - Where to put the converted string (8 bytes)
*
- * RETURN: Convert a number to string representation
+ * RETURN: None, string
+ *
+ * DESCRIPTOIN: Convert a number to string representation. Assumes string
+ * buffer is large enough to hold the string.
*
******************************************************************************/
diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c
new file mode 100644
index 000000000000..770cfc8b17e0
--- /dev/null
+++ b/drivers/acpi/glue.c
@@ -0,0 +1,360 @@
+/*
+ * Link physical devices with ACPI devices support
+ *
+ * Copyright (c) 2005 David Shaohua Li <shaohua.li@intel.com>
+ * Copyright (c) 2005 Intel Corp.
+ *
+ * This file is released under the GPLv2.
+ */
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/device.h>
+#include <linux/rwsem.h>
+#include <linux/acpi.h>
+
+#define ACPI_GLUE_DEBUG 0
+#if ACPI_GLUE_DEBUG
+#define DBG(x...) printk(PREFIX x)
+#else
+#define DBG(x...)
+#endif
+static LIST_HEAD(bus_type_list);
+static DECLARE_RWSEM(bus_type_sem);
+
+int register_acpi_bus_type(struct acpi_bus_type *type)
+{
+ if (acpi_disabled)
+ return -ENODEV;
+ if (type && type->bus && type->find_device) {
+ down_write(&bus_type_sem);
+ list_add_tail(&type->list, &bus_type_list);
+ up_write(&bus_type_sem);
+ printk(KERN_INFO PREFIX "bus type %s registered\n", type->bus->name);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(register_acpi_bus_type);
+
+int unregister_acpi_bus_type(struct acpi_bus_type *type)
+{
+ if (acpi_disabled)
+ return 0;
+ if (type) {
+ down_write(&bus_type_sem);
+ list_del_init(&type->list);
+ up_write(&bus_type_sem);
+ printk(KERN_INFO PREFIX "ACPI bus type %s unregistered\n", type->bus->name);
+ return 0;
+ }
+ return -ENODEV;
+}
+
+EXPORT_SYMBOL(unregister_acpi_bus_type);
+
+static struct acpi_bus_type *acpi_get_bus_type(struct bus_type *type)
+{
+ struct acpi_bus_type *tmp, *ret = NULL;
+
+ down_read(&bus_type_sem);
+ list_for_each_entry(tmp, &bus_type_list, list) {
+ if (tmp->bus == type) {
+ ret = tmp;
+ break;
+ }
+ }
+ up_read(&bus_type_sem);
+ return ret;
+}
+
+static int acpi_find_bridge_device(struct device *dev, acpi_handle * handle)
+{
+ struct acpi_bus_type *tmp;
+ int ret = -ENODEV;
+
+ down_read(&bus_type_sem);
+ list_for_each_entry(tmp, &bus_type_list, list) {
+ if (tmp->find_bridge && !tmp->find_bridge(dev, handle)) {
+ ret = 0;
+ break;
+ }
+ }
+ up_read(&bus_type_sem);
+ return ret;
+}
+
+/* Get PCI root bridge's handle from its segment and bus number */
+struct acpi_find_pci_root {
+ unsigned int seg;
+ unsigned int bus;
+ acpi_handle handle;
+};
+
+static acpi_status
+do_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
+{
+ int *busnr = (int *)data;
+ struct acpi_resource_address64 address;
+
+ if (resource->id != ACPI_RSTYPE_ADDRESS16 &&
+ resource->id != ACPI_RSTYPE_ADDRESS32 &&
+ resource->id != ACPI_RSTYPE_ADDRESS64)
+ return AE_OK;
+
+ acpi_resource_to_address64(resource, &address);
+ if ((address.address_length > 0) &&
+ (address.resource_type == ACPI_BUS_NUMBER_RANGE))
+ *busnr = address.min_address_range;
+
+ return AE_OK;
+}
+
+static int get_root_bridge_busnr(acpi_handle handle)
+{
+ acpi_status status;
+ int bus, bbn;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__BBN, NULL,
+ (unsigned long *)&bbn);
+ if (status == AE_NOT_FOUND) {
+ /* Assume bus = 0 */
+ printk(KERN_INFO PREFIX
+ "Assume root bridge [%s] bus is 0\n",
+ (char *)buffer.pointer);
+ status = AE_OK;
+ bbn = 0;
+ }
+ if (ACPI_FAILURE(status)) {
+ bbn = -ENODEV;
+ goto exit;
+ }
+ if (bbn > 0)
+ goto exit;
+
+ /* _BBN in some systems return 0 for all root bridges */
+ bus = -1;
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ do_root_bridge_busnr_callback, &bus);
+ /* If _CRS failed, we just use _BBN */
+ if (ACPI_FAILURE(status) || (bus == -1))
+ goto exit;
+ /* We select _CRS */
+ if (bbn != bus) {
+ printk(KERN_INFO PREFIX
+ "_BBN and _CRS returns different value for %s. Select _CRS\n",
+ (char *)buffer.pointer);
+ bbn = bus;
+ }
+ exit:
+ acpi_os_free(buffer.pointer);
+ return bbn;
+}
+
+static acpi_status
+find_pci_rootbridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ struct acpi_find_pci_root *find = (struct acpi_find_pci_root *)context;
+ unsigned long seg, bus;
+ acpi_status status;
+ int tmp;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
+
+ status = acpi_evaluate_integer(handle, METHOD_NAME__SEG, NULL, &seg);
+ if (status == AE_NOT_FOUND) {
+ /* Assume seg = 0 */
+ printk(KERN_INFO PREFIX
+ "Assume root bridge [%s] segment is 0\n",
+ (char *)buffer.pointer);
+ status = AE_OK;
+ seg = 0;
+ }
+ if (ACPI_FAILURE(status)) {
+ status = AE_CTRL_DEPTH;
+ goto exit;
+ }
+
+ tmp = get_root_bridge_busnr(handle);
+ if (tmp < 0) {
+ printk(KERN_ERR PREFIX
+ "Find root bridge failed for %s\n",
+ (char *)buffer.pointer);
+ status = AE_CTRL_DEPTH;
+ goto exit;
+ }
+ bus = tmp;
+
+ if (seg == find->seg && bus == find->bus)
+ find->handle = handle;
+ status = AE_OK;
+ exit:
+ acpi_os_free(buffer.pointer);
+ return status;
+}
+
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int seg, unsigned int bus)
+{
+ struct acpi_find_pci_root find = { seg, bus, NULL };
+
+ acpi_get_devices(PCI_ROOT_HID_STRING, find_pci_rootbridge, &find, NULL);
+ return find.handle;
+}
+
+/* Get device's handler per its address under its parent */
+struct acpi_find_child {
+ acpi_handle handle;
+ acpi_integer address;
+};
+
+static acpi_status
+do_acpi_find_child(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ struct acpi_device_info *info;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_find_child *find = (struct acpi_find_child *)context;
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ info = buffer.pointer;
+ if (info->address == find->address)
+ find->handle = handle;
+ acpi_os_free(buffer.pointer);
+ }
+ return AE_OK;
+}
+
+acpi_handle acpi_get_child(acpi_handle parent, acpi_integer address)
+{
+ struct acpi_find_child find = { NULL, address };
+
+ if (!parent)
+ return NULL;
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, parent,
+ 1, do_acpi_find_child, &find, NULL);
+ return find.handle;
+}
+
+EXPORT_SYMBOL(acpi_get_child);
+
+/* Link ACPI devices with physical devices */
+static void acpi_glue_data_handler(acpi_handle handle,
+ u32 function, void *context)
+{
+ /* we provide an empty handler */
+}
+
+/* Note: a success call will increase reference count by one */
+struct device *acpi_get_physical_device(acpi_handle handle)
+{
+ acpi_status status;
+ struct device *dev;
+
+ status = acpi_get_data(handle, acpi_glue_data_handler, (void **)&dev);
+ if (ACPI_SUCCESS(status))
+ return get_device(dev);
+ return NULL;
+}
+
+EXPORT_SYMBOL(acpi_get_physical_device);
+
+static int acpi_bind_one(struct device *dev, acpi_handle handle)
+{
+ acpi_status status;
+
+ if (dev->firmware_data) {
+ printk(KERN_WARNING PREFIX
+ "Drivers changed 'firmware_data' for %s\n", dev->bus_id);
+ return -EINVAL;
+ }
+ get_device(dev);
+ status = acpi_attach_data(handle, acpi_glue_data_handler, dev);
+ if (ACPI_FAILURE(status)) {
+ put_device(dev);
+ return -EINVAL;
+ }
+ dev->firmware_data = handle;
+
+ return 0;
+}
+
+static int acpi_unbind_one(struct device *dev)
+{
+ if (!dev->firmware_data)
+ return 0;
+ if (dev == acpi_get_physical_device(dev->firmware_data)) {
+ /* acpi_get_physical_device increase refcnt by one */
+ put_device(dev);
+ acpi_detach_data(dev->firmware_data, acpi_glue_data_handler);
+ dev->firmware_data = NULL;
+ /* acpi_bind_one increase refcnt by one */
+ put_device(dev);
+ } else {
+ printk(KERN_ERR PREFIX
+ "Oops, 'firmware_data' corrupt for %s\n", dev->bus_id);
+ }
+ return 0;
+}
+
+static int acpi_platform_notify(struct device *dev)
+{
+ struct acpi_bus_type *type;
+ acpi_handle handle;
+ int ret = -EINVAL;
+
+ if (!dev->bus || !dev->parent) {
+ /* bridge devices genernally haven't bus or parent */
+ ret = acpi_find_bridge_device(dev, &handle);
+ goto end;
+ }
+ type = acpi_get_bus_type(dev->bus);
+ if (!type) {
+ DBG("No ACPI bus support for %s\n", dev->bus_id);
+ ret = -EINVAL;
+ goto end;
+ }
+ if ((ret = type->find_device(dev, &handle)) != 0)
+ DBG("Can't get handler for %s\n", dev->bus_id);
+ end:
+ if (!ret)
+ acpi_bind_one(dev, handle);
+
+#if ACPI_GLUE_DEBUG
+ if (!ret) {
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+
+ acpi_get_name(dev->firmware_data, ACPI_FULL_PATHNAME, &buffer);
+ DBG("Device %s -> %s\n", dev->bus_id, (char *)buffer.pointer);
+ acpi_os_free(buffer.pointer);
+ } else
+ DBG("Device %s -> No ACPI support\n", dev->bus_id);
+#endif
+
+ return ret;
+}
+
+static int acpi_platform_notify_remove(struct device *dev)
+{
+ acpi_unbind_one(dev);
+ return 0;
+}
+
+static int __init init_acpi_device_notify(void)
+{
+ if (acpi_disabled)
+ return 0;
+ if (platform_notify || platform_notify_remove) {
+ printk(KERN_ERR PREFIX "Can't use platform_notify\n");
+ return 0;
+ }
+ platform_notify = acpi_platform_notify;
+ platform_notify_remove = acpi_platform_notify_remove;
+ return 0;
+}
+
+arch_initcall(init_acpi_device_notify);
diff --git a/drivers/acpi/hardware/hwacpi.c b/drivers/acpi/hardware/hwacpi.c
index 529e922bdc85..b51001e74eea 100644
--- a/drivers/acpi/hardware/hwacpi.c
+++ b/drivers/acpi/hardware/hwacpi.c
@@ -58,7 +58,8 @@
*
* RETURN: Status
*
- * DESCRIPTION: Initialize and validate various ACPI registers
+ * DESCRIPTION: Initialize and validate the various ACPI registers defined in
+ * the FADT.
*
******************************************************************************/
@@ -75,7 +76,7 @@ acpi_hw_initialize (
/* We must have the ACPI tables by the time we get here */
if (!acpi_gbl_FADT) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "A FADT is not loaded\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "No FADT is present\n"));
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
@@ -131,7 +132,8 @@ acpi_hw_set_mode (
* transitions are not supported.
*/
if (!acpi_gbl_FADT->acpi_enable && !acpi_gbl_FADT->acpi_disable) {
- ACPI_REPORT_ERROR (("No ACPI mode transition supported in this system (enable/disable both zero)\n"));
+ ACPI_REPORT_ERROR ((
+ "No ACPI mode transition supported in this system (enable/disable both zero)\n"));
return_ACPI_STATUS (AE_OK);
}
@@ -162,7 +164,8 @@ acpi_hw_set_mode (
}
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("Could not write mode change, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Could not write mode change, %s\n",
+ acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
@@ -173,7 +176,8 @@ acpi_hw_set_mode (
retry = 3000;
while (retry) {
if (acpi_hw_get_mode() == mode) {
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n", mode));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Mode %X successfully enabled\n",
+ mode));
return_ACPI_STATUS (AE_OK);
}
acpi_os_stall(1000);
@@ -185,7 +189,7 @@ acpi_hw_set_mode (
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_hw_get_mode
*
@@ -199,7 +203,8 @@ acpi_hw_set_mode (
******************************************************************************/
u32
-acpi_hw_get_mode (void)
+acpi_hw_get_mode (
+ void)
{
acpi_status status;
u32 value;
diff --git a/drivers/acpi/hardware/hwgpe.c b/drivers/acpi/hardware/hwgpe.c
index 9ac1d639bf51..8daeabb2fc7a 100644
--- a/drivers/acpi/hardware/hwgpe.c
+++ b/drivers/acpi/hardware/hwgpe.c
@@ -48,6 +48,13 @@
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME ("hwgpe")
+/* Local prototypes */
+
+static acpi_status
+acpi_hw_enable_wakeup_gpe_block (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block);
+
/******************************************************************************
*
@@ -135,6 +142,7 @@ acpi_hw_clear_gpe (
* DESCRIPTION: Return the status of a single GPE.
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_hw_get_gpe_status (
@@ -206,7 +214,7 @@ unlock_and_exit:
*
* RETURN: Status
*
- * DESCRIPTION: Disable all GPEs within a GPE block
+ * DESCRIPTION: Disable all GPEs within a single GPE block
*
******************************************************************************/
@@ -244,7 +252,7 @@ acpi_hw_disable_gpe_block (
*
* RETURN: Status
*
- * DESCRIPTION: Clear status bits for all GPEs within a GPE block
+ * DESCRIPTION: Clear status bits for all GPEs within a single GPE block
*
******************************************************************************/
@@ -282,8 +290,8 @@ acpi_hw_clear_gpe_block (
*
* RETURN: Status
*
- * DESCRIPTION: Enable all "runtime" GPEs within a GPE block. (Includes
- * combination wake/run GPEs.)
+ * DESCRIPTION: Enable all "runtime" GPEs within a single GPE block. Includes
+ * combination wake/run GPEs.
*
******************************************************************************/
@@ -327,12 +335,12 @@ acpi_hw_enable_runtime_gpe_block (
*
* RETURN: Status
*
- * DESCRIPTION: Enable all "wake" GPEs within a GPE block. (Includes
- * combination wake/run GPEs.)
+ * DESCRIPTION: Enable all "wake" GPEs within a single GPE block. Includes
+ * combination wake/run GPEs.
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_hw_enable_wakeup_gpe_block (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block)
@@ -350,7 +358,8 @@ acpi_hw_enable_wakeup_gpe_block (
/* Enable all "wake" GPEs in this register */
- status = acpi_hw_low_level_write (8, gpe_block->register_info[i].enable_for_wake,
+ 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);
@@ -369,7 +378,7 @@ acpi_hw_enable_wakeup_gpe_block (
*
* RETURN: Status
*
- * DESCRIPTION: Disable and clear all GPEs
+ * DESCRIPTION: Disable and clear all GPEs in all GPE blocks
*
******************************************************************************/
@@ -397,7 +406,7 @@ acpi_hw_disable_all_gpes (
*
* RETURN: Status
*
- * DESCRIPTION: Enable all GPEs of the given type
+ * DESCRIPTION: Enable all "runtime" GPEs, in all GPE blocks
*
******************************************************************************/
@@ -424,7 +433,7 @@ acpi_hw_enable_all_runtime_gpes (
*
* RETURN: Status
*
- * DESCRIPTION: Enable all GPEs of the given type
+ * DESCRIPTION: Enable all "wakeup" GPEs, in all GPE blocks
*
******************************************************************************/
diff --git a/drivers/acpi/hardware/hwregs.c b/drivers/acpi/hardware/hwregs.c
index 91af0c2ddcf7..6d9e4eb84836 100644
--- a/drivers/acpi/hardware/hwregs.c
+++ b/drivers/acpi/hardware/hwregs.c
@@ -87,8 +87,9 @@ acpi_hw_clear_acpi_status (
}
}
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_STATUS,
- ACPI_BITMASK_ALL_FIXED_STATUS);
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_STATUS,
+ ACPI_BITMASK_ALL_FIXED_STATUS);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
@@ -138,28 +139,30 @@ acpi_get_sleep_type_data (
{
acpi_status status = AE_OK;
struct acpi_parameter_info info;
+ char *sleep_state_name;
ACPI_FUNCTION_TRACE ("acpi_get_sleep_type_data");
- /*
- * Validate parameters
- */
+ /* Validate parameters */
+
if ((sleep_state > ACPI_S_STATES_MAX) ||
!sleep_type_a || !sleep_type_b) {
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
- /*
- * Evaluate the namespace object containing the values for this state
- */
+ /* 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],
- &info);
+ info.return_object = NULL;
+ sleep_state_name = (char *) acpi_gbl_sleep_state_names[sleep_state];
+
+ status = acpi_ns_evaluate_by_name (sleep_state_name, &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]));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "%s while evaluating sleep_state [%s]\n",
+ acpi_format_exception (status), sleep_state_name));
return_ACPI_STATUS (status);
}
@@ -167,45 +170,57 @@ acpi_get_sleep_type_data (
/* Must have a return object */
if (!info.return_object) {
- ACPI_REPORT_ERROR (("Missing Sleep State object\n"));
+ ACPI_REPORT_ERROR (("No Sleep State object returned from [%s]\n",
+ sleep_state_name));
status = AE_NOT_EXIST;
}
/* It must be of type Package */
else if (ACPI_GET_OBJECT_TYPE (info.return_object) != ACPI_TYPE_PACKAGE) {
- ACPI_REPORT_ERROR (("Sleep State object not a Package\n"));
+ ACPI_REPORT_ERROR (("Sleep State return object is not a Package\n"));
status = AE_AML_OPERAND_TYPE;
}
- /* The package must have at least two elements */
-
+ /*
+ * The package must have at least two elements. NOTE (March 2005): This
+ * goes against the current ACPI spec which defines this object as a
+ * package with one encoded DWORD element. However, existing practice
+ * by BIOS vendors seems to be to have 2 or more elements, at least
+ * one per sleep type (A/B).
+ */
else if (info.return_object->package.count < 2) {
- ACPI_REPORT_ERROR (("Sleep State package does not have at least two elements\n"));
+ ACPI_REPORT_ERROR ((
+ "Sleep State return 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 (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",
+ 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 return package elements are not both Integers (%s, %s)\n",
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) (info.return_object->package.elements[0])->integer.value;
- *sleep_type_b = (u8) (info.return_object->package.elements[1])->integer.value;
+ /* Valid _Sx_ package size, type, and 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], info.return_object,
+ "%s While evaluating sleep_state [%s], bad Sleep object %p type %s\n",
+ acpi_format_exception (status),
+ sleep_state_name, info.return_object,
acpi_ut_get_object_type_name (info.return_object)));
}
@@ -221,9 +236,9 @@ EXPORT_SYMBOL(acpi_get_sleep_type_data);
*
* PARAMETERS: register_id - Index of ACPI Register to access
*
- * RETURN: The bit mask to be used when accessing the register
+ * RETURN: The bitmask to be used when accessing the register
*
- * DESCRIPTION: Map register_id into a register bit mask.
+ * DESCRIPTION: Map register_id into a register bitmask.
*
******************************************************************************/
@@ -359,7 +374,7 @@ acpi_set_register (
/* Always do a register read first so we can insert the new bits */
status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
- bit_reg_info->parent_register, &register_value);
+ bit_reg_info->parent_register, &register_value);
if (ACPI_FAILURE (status)) {
goto unlock_and_exit;
}
@@ -396,7 +411,7 @@ acpi_set_register (
bit_reg_info->access_bit_mask, value);
status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_ENABLE, (u16) register_value);
+ ACPI_REGISTER_PM1_ENABLE, (u16) register_value);
break;
@@ -413,7 +428,7 @@ acpi_set_register (
bit_reg_info->access_bit_mask, value);
status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM1_CONTROL, (u16) register_value);
+ ACPI_REGISTER_PM1_CONTROL, (u16) register_value);
break;
@@ -427,17 +442,19 @@ acpi_set_register (
ACPI_DEBUG_PRINT ((ACPI_DB_IO, "PM2 control: Read %X from %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64 (
+ acpi_gbl_FADT->xpm2_cnt_blk.address)));
ACPI_REGISTER_INSERT_VALUE (register_value, bit_reg_info->bit_position,
bit_reg_info->access_bit_mask, value);
ACPI_DEBUG_PRINT ((ACPI_DB_IO, "About to write %4.4X to %8.8X%8.8X\n",
register_value,
- ACPI_FORMAT_UINT64 (acpi_gbl_FADT->xpm2_cnt_blk.address)));
+ ACPI_FORMAT_UINT64 (
+ acpi_gbl_FADT->xpm2_cnt_blk.address)));
status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
- ACPI_REGISTER_PM2_CONTROL, (u8) (register_value));
+ ACPI_REGISTER_PM2_CONTROL, (u8) (register_value));
break;
@@ -454,7 +471,9 @@ unlock_and_exit:
/* Normalize the value that was read */
- ACPI_DEBUG_EXEC (register_value = ((register_value & bit_reg_info->access_bit_mask) >> bit_reg_info->bit_position));
+ ACPI_DEBUG_EXEC (register_value =
+ ((register_value & bit_reg_info->access_bit_mask) >>
+ bit_reg_info->bit_position));
ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Set bits: %8.8X actual %8.8X register %X\n",
value, register_value, bit_reg_info->parent_register));
@@ -469,7 +488,7 @@ EXPORT_SYMBOL(acpi_set_register);
*
* PARAMETERS: use_lock - Mutex hw access
* register_id - register_iD + Offset
- * return_value - Value that was read from the register
+ * return_value - Where the register value is returned
*
* RETURN: Status and the value read.
*
@@ -557,7 +576,8 @@ acpi_hw_register_read (
break;
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n", register_id));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown Register ID: %X\n",
+ register_id));
status = AE_BAD_PARAMETER;
break;
}
@@ -763,10 +783,11 @@ acpi_hw_low_level_read (
return (AE_BAD_PARAMETER);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
- *value, width,
- ACPI_FORMAT_UINT64 (address),
- acpi_ut_get_region_name (reg->address_space_id)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO,
+ "Read: %8.8X width %2d from %8.8X%8.8X (%s)\n",
+ *value, width,
+ ACPI_FORMAT_UINT64 (address),
+ acpi_ut_get_region_name (reg->address_space_id)));
return (status);
}
@@ -841,10 +862,11 @@ acpi_hw_low_level_write (
return (AE_BAD_PARAMETER);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_IO, "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
- value, width,
- ACPI_FORMAT_UINT64 (address),
- acpi_ut_get_region_name (reg->address_space_id)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_IO,
+ "Wrote: %8.8X width %2d to %8.8X%8.8X (%s)\n",
+ value, width,
+ ACPI_FORMAT_UINT64 (address),
+ acpi_ut_get_region_name (reg->address_space_id)));
return (status);
}
diff --git a/drivers/acpi/hardware/hwsleep.c b/drivers/acpi/hardware/hwsleep.c
index 77b3e9a8550b..415d342aeab5 100644
--- a/drivers/acpi/hardware/hwsleep.c
+++ b/drivers/acpi/hardware/hwsleep.c
@@ -43,27 +43,13 @@
*/
#include <linux/module.h>
-
#include <acpi/acpi.h>
#define _COMPONENT ACPI_HARDWARE
ACPI_MODULE_NAME ("hwsleep")
-#define METHOD_NAME__BFS "\\_BFS"
-#define METHOD_NAME__GTS "\\_GTS"
-#define METHOD_NAME__PTS "\\_PTS"
-#define METHOD_NAME__SST "\\_SI._SST"
-#define METHOD_NAME__WAK "\\_WAK"
-
-#define ACPI_SST_INDICATOR_OFF 0
-#define ACPI_SST_WORKING 1
-#define ACPI_SST_WAKING 2
-#define ACPI_SST_SLEEPING 3
-#define ACPI_SST_SLEEP_CONTEXT 4
-
-
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_set_firmware_waking_vector
*
@@ -72,7 +58,7 @@
*
* RETURN: Status
*
- * DESCRIPTION: access function for d_firmware_waking_vector field in FACS
+ * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
*
******************************************************************************/
@@ -99,19 +85,20 @@ acpi_set_firmware_waking_vector (
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_get_firmware_waking_vector
*
- * PARAMETERS: *physical_address - Output buffer where contents of
+ * PARAMETERS: *physical_address - Where the contents of
* the firmware_waking_vector field of
- * the FACS will be stored.
+ * the FACS will be returned.
*
- * RETURN: Status
+ * RETURN: Status, vector
*
- * DESCRIPTION: Access function for firmware_waking_vector field in FACS
+ * DESCRIPTION: Access function for the firmware_waking_vector field in FACS
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_get_firmware_waking_vector (
@@ -141,7 +128,7 @@ acpi_get_firmware_waking_vector (
#endif
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_prep
*
@@ -215,7 +202,7 @@ acpi_enter_sleep_state_prep (
break;
default:
- arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is indicator off */
+ arg.integer.value = ACPI_SST_INDICATOR_OFF; /* Default is off */
break;
}
@@ -223,14 +210,15 @@ acpi_enter_sleep_state_prep (
status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
- ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n",
+ acpi_format_exception (status)));
}
return_ACPI_STATUS (AE_OK);
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state
*
@@ -299,15 +287,18 @@ acpi_enter_sleep_state (
/* Get current value of PM1A control */
- status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
+ status = acpi_hw_register_read (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL, &PM1Acontrol);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "Entering sleep state [S%d]\n", sleep_state));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INIT,
+ "Entering sleep state [S%d]\n", sleep_state));
/* Clear SLP_EN and SLP_TYP fields */
- PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask | sleep_enable_reg_info->access_bit_mask);
+ PM1Acontrol &= ~(sleep_type_reg_info->access_bit_mask |
+ sleep_enable_reg_info->access_bit_mask);
PM1Bcontrol = PM1Acontrol;
/* Insert SLP_TYP bits */
@@ -322,12 +313,14 @@ acpi_enter_sleep_state (
/* Write #1: fill in SLP_TYP data */
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -341,22 +334,25 @@ acpi_enter_sleep_state (
ACPI_FLUSH_CPU_CACHE ();
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1A_CONTROL, PM1Acontrol);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1B_CONTROL, PM1Bcontrol);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
if (sleep_state > ACPI_STATE_S3) {
/*
- * We wanted to sleep > S3, but it didn't happen (by virtue of the fact that
- * we are still executing!)
+ * We wanted to sleep > S3, but it didn't happen (by virtue of the
+ * fact that we are still executing!)
*
- * Wait ten seconds, then try again. This is to get S4/S5 to work on all machines.
+ * Wait ten seconds, then try again. This is to get S4/S5 to work on
+ * all machines.
*
* We wait so long to allow chipsets that poll this reg very slowly to
* still read the right value. Ideally, this block would go
@@ -364,7 +360,8 @@ acpi_enter_sleep_state (
*/
acpi_os_stall (10000000);
- status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK, ACPI_REGISTER_PM1_CONTROL,
+ status = acpi_hw_register_write (ACPI_MTX_DO_NOT_LOCK,
+ ACPI_REGISTER_PM1_CONTROL,
sleep_enable_reg_info->access_bit_mask);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
@@ -374,7 +371,8 @@ acpi_enter_sleep_state (
/* Wait until we enter sleep state */
do {
- status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value,
+ ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -388,7 +386,7 @@ acpi_enter_sleep_state (
EXPORT_SYMBOL(acpi_enter_sleep_state);
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_enter_sleep_state_s4bios
*
@@ -439,11 +437,13 @@ acpi_enter_sleep_state_s4bios (
ACPI_FLUSH_CPU_CACHE ();
- status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd, (u32) acpi_gbl_FADT->S4bios_req, 8);
+ status = acpi_os_write_port (acpi_gbl_FADT->smi_cmd,
+ (u32) acpi_gbl_FADT->S4bios_req, 8);
do {
acpi_os_stall(1000);
- status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value, ACPI_MTX_DO_NOT_LOCK);
+ status = acpi_get_register (ACPI_BITREG_WAKE_STATUS, &in_value,
+ ACPI_MTX_DO_NOT_LOCK);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -454,7 +454,7 @@ acpi_enter_sleep_state_s4bios (
EXPORT_SYMBOL(acpi_enter_sleep_state_s4bios);
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_leave_sleep_state
*
@@ -534,18 +534,21 @@ acpi_leave_sleep_state (
arg.integer.value = ACPI_SST_WAKING;
status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
- ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n",
+ acpi_format_exception (status)));
}
arg.integer.value = sleep_state;
status = acpi_evaluate_object (NULL, METHOD_NAME__BFS, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
- ACPI_REPORT_ERROR (("Method _BFS failed, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Method _BFS failed, %s\n",
+ acpi_format_exception (status)));
}
status = acpi_evaluate_object (NULL, METHOD_NAME__WAK, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
- ACPI_REPORT_ERROR (("Method _WAK failed, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Method _WAK failed, %s\n",
+ acpi_format_exception (status)));
}
/* TBD: _WAK "sometimes" returns stuff - do we want to look at it? */
@@ -567,15 +570,19 @@ acpi_leave_sleep_state (
/* Enable power button */
- (void) 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);
- (void) 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);
arg.integer.value = ACPI_SST_WORKING;
status = acpi_evaluate_object (NULL, METHOD_NAME__SST, &arg_list, NULL);
if (ACPI_FAILURE (status) && status != AE_NOT_FOUND) {
- ACPI_REPORT_ERROR (("Method _SST failed, %s\n", acpi_format_exception (status)));
+ ACPI_REPORT_ERROR (("Method _SST failed, %s\n",
+ acpi_format_exception (status)));
}
return_ACPI_STATUS (status);
diff --git a/drivers/acpi/hardware/hwtimer.c b/drivers/acpi/hardware/hwtimer.c
index 1906167d7294..49d7b395322e 100644
--- a/drivers/acpi/hardware/hwtimer.c
+++ b/drivers/acpi/hardware/hwtimer.c
@@ -43,7 +43,6 @@
*/
#include <linux/module.h>
-
#include <acpi/acpi.h>
#define _COMPONENT ACPI_HARDWARE
@@ -90,7 +89,7 @@ acpi_get_timer_resolution (
*
* PARAMETERS: Ticks - Where the timer value is returned
*
- * RETURN: Status and current ticks
+ * RETURN: Status and current timer value (ticks)
*
* DESCRIPTION: Obtains current value of ACPI PM Timer (in ticks).
*
@@ -199,5 +198,6 @@ acpi_get_timer_duration (
*time_elapsed = (u32) quotient;
return_ACPI_STATUS (status);
}
+
EXPORT_SYMBOL(acpi_get_timer_duration);
diff --git a/drivers/acpi/hotkey.c b/drivers/acpi/hotkey.c
new file mode 100644
index 000000000000..babdf762eadb
--- /dev/null
+++ b/drivers/acpi/hotkey.c
@@ -0,0 +1,1019 @@
+/*
+ * hotkey.c - ACPI Hotkey Driver ($Revision:$)
+ *
+ * Copyright (C) 2004 Luming Yu <luming.yu@intel.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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/kmod.h>
+#include <linux/seq_file.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define HOTKEY_ACPI_VERSION "0.1"
+
+#define HOTKEY_PROC "hotkey"
+#define HOTKEY_EV_CONFIG "event_config"
+#define HOTKEY_PL_CONFIG "poll_config"
+#define HOTKEY_ACTION "action"
+#define HOTKEY_INFO "info"
+
+#define ACPI_HOTK_NAME "Generic Hotkey Driver"
+#define ACPI_HOTK_CLASS "Hotkey"
+#define ACPI_HOTK_DEVICE_NAME "Hotkey"
+#define ACPI_HOTK_HID "Unknown?"
+#define ACPI_HOTKEY_COMPONENT 0x20000000
+
+#define ACPI_HOTKEY_EVENT 0x1
+#define ACPI_HOTKEY_POLLING 0x2
+#define ACPI_UNDEFINED_EVENT 0xf
+
+#define MAX_CONFIG_RECORD_LEN 80
+#define MAX_NAME_PATH_LEN 80
+#define MAX_CALL_PARM 80
+
+#define IS_EVENT(e) 0xff /* ((e) & 0x40000000) */
+#define IS_POLL(e) 0xff /* (~((e) & 0x40000000)) */
+
+#define _COMPONENT ACPI_HOTKEY_COMPONENT
+ACPI_MODULE_NAME("acpi_hotkey")
+
+ MODULE_AUTHOR("luming.yu@intel.com");
+MODULE_DESCRIPTION(ACPI_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+/* standardized internal hotkey number/event */
+enum {
+ /* Video Extension event */
+ HK_EVENT_CYCLE_OUTPUT_DEVICE = 0x80,
+ HK_EVENT_OUTPUT_DEVICE_STATUS_CHANGE,
+ HK_EVENT_CYCLE_DISPLAY_OUTPUT,
+ HK_EVENT_NEXT_DISPLAY_OUTPUT,
+ HK_EVENT_PREVIOUS_DISPLAY_OUTPUT,
+ HK_EVENT_CYCLE_BRIGHTNESS,
+ HK_EVENT_INCREASE_BRIGHTNESS,
+ HK_EVENT_DECREASE_BRIGHTNESS,
+ HK_EVENT_ZERO_BRIGHTNESS,
+ HK_EVENT_DISPLAY_DEVICE_OFF,
+
+ /* Snd Card event */
+ HK_EVENT_VOLUME_MUTE,
+ HK_EVENT_VOLUME_INCLREASE,
+ HK_EVENT_VOLUME_DECREASE,
+
+ /* running state control */
+ HK_EVENT_ENTERRING_S3,
+ HK_EVENT_ENTERRING_S4,
+ HK_EVENT_ENTERRING_S5,
+};
+
+/* procdir we use */
+static struct proc_dir_entry *hotkey_proc_dir;
+static struct proc_dir_entry *hotkey_config;
+static struct proc_dir_entry *hotkey_poll_config;
+static struct proc_dir_entry *hotkey_action;
+static struct proc_dir_entry *hotkey_info;
+
+/* linkage for all type of hotkey */
+struct acpi_hotkey_link {
+ struct list_head entries;
+ int hotkey_type; /* event or polling based hotkey */
+ int hotkey_standard_num; /* standardized hotkey(event) number */
+};
+
+/* event based hotkey */
+struct acpi_event_hotkey {
+ struct acpi_hotkey_link hotkey_link;
+ int flag;
+ acpi_handle bus_handle; /* bus to install notify handler */
+ int external_hotkey_num; /* external hotkey/event number */
+ acpi_handle action_handle; /* acpi handle attached aml action method */
+ char *action_method; /* action method */
+};
+
+/*
+ * There are two ways to poll status
+ * 1. directy call read_xxx method, without any arguments passed in
+ * 2. call write_xxx method, with arguments passed in, you need
+ * the result is saved in acpi_polling_hotkey.poll_result.
+ * anthoer read command through polling interface.
+ *
+ */
+
+/* polling based hotkey */
+struct acpi_polling_hotkey {
+ struct acpi_hotkey_link hotkey_link;
+ int flag;
+ acpi_handle poll_handle; /* acpi handle attached polling method */
+ char *poll_method; /* poll method */
+ acpi_handle action_handle; /* acpi handle attached action method */
+ char *action_method; /* action method */
+ void *poll_result; /* polling_result */
+ struct proc_dir_entry *proc;
+};
+
+/* hotkey object union */
+union acpi_hotkey {
+ struct list_head entries;
+ struct acpi_hotkey_link link;
+ struct acpi_event_hotkey event_hotkey;
+ struct acpi_polling_hotkey poll_hotkey;
+};
+
+/* hotkey object list */
+struct acpi_hotkey_list {
+ struct list_head *entries;
+ int count;
+};
+
+static int auto_hotkey_add(struct acpi_device *device);
+static int auto_hotkey_remove(struct acpi_device *device, int type);
+
+static struct acpi_driver hotkey_driver = {
+ .name = ACPI_HOTK_NAME,
+ .class = ACPI_HOTK_CLASS,
+ .ids = ACPI_HOTK_HID,
+ .ops = {
+ .add = auto_hotkey_add,
+ .remove = auto_hotkey_remove,
+ },
+};
+
+static int hotkey_open_config(struct inode *inode, struct file *file);
+static ssize_t hotkey_write_config(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data);
+static ssize_t hotkey_write_poll_config(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data);
+static int hotkey_info_open_fs(struct inode *inode, struct file *file);
+static int hotkey_action_open_fs(struct inode *inode, struct file *file);
+static ssize_t hotkey_execute_aml_method(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data);
+static int hotkey_config_seq_show(struct seq_file *seq, void *offset);
+static int hotkey_polling_open_fs(struct inode *inode, struct file *file);
+
+/* event based config */
+static struct file_operations hotkey_config_fops = {
+ .open = hotkey_open_config,
+ .read = seq_read,
+ .write = hotkey_write_config,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* polling based config */
+static struct file_operations hotkey_poll_config_fops = {
+ .open = hotkey_open_config,
+ .read = seq_read,
+ .write = hotkey_write_poll_config,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* hotkey driver info */
+static struct file_operations hotkey_info_fops = {
+ .open = hotkey_info_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* action */
+static struct file_operations hotkey_action_fops = {
+ .open = hotkey_action_open_fs,
+ .read = seq_read,
+ .write = hotkey_execute_aml_method,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* polling results */
+static struct file_operations hotkey_polling_fops = {
+ .open = hotkey_polling_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+struct acpi_hotkey_list global_hotkey_list; /* link all ev or pl hotkey */
+struct list_head hotkey_entries; /* head of the list of hotkey_list */
+
+static int hotkey_info_seq_show(struct seq_file *seq, void *offset)
+{
+ ACPI_FUNCTION_TRACE("hotkey_info_seq_show");
+
+ seq_printf(seq, "Hotkey generic driver ver: %s", HOTKEY_ACPI_VERSION);
+
+ return_VALUE(0);
+}
+
+static int hotkey_info_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
+}
+
+static char *format_result(union acpi_object *object)
+{
+ char *buf = (char *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+
+ memset(buf, 0, sizeof(union acpi_object));
+
+ /* Now, just support integer type */
+ if (object->type == ACPI_TYPE_INTEGER)
+ sprintf(buf, "%d", (u32) object->integer.value);
+
+ return buf;
+}
+
+static int hotkey_polling_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_polling_hotkey *poll_hotkey =
+ (struct acpi_polling_hotkey *)seq->private;
+
+ ACPI_FUNCTION_TRACE("hotkey_polling_seq_show");
+
+ if (poll_hotkey->poll_result)
+ seq_printf(seq, "%s", format_result(poll_hotkey->poll_result));
+
+ return_VALUE(0);
+}
+
+static int hotkey_polling_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, hotkey_polling_seq_show, PDE(inode)->data);
+}
+
+static int hotkey_action_open_fs(struct inode *inode, struct file *file)
+{
+ return single_open(file, hotkey_info_seq_show, PDE(inode)->data);
+}
+
+/* Mapping external hotkey number to standardized hotkey event num */
+static int hotkey_get_internal_event(int event, struct acpi_hotkey_list *list)
+{
+ struct list_head *entries, *next;
+ int val = 0;
+
+ ACPI_FUNCTION_TRACE("hotkey_get_internal_event");
+
+ list_for_each_safe(entries, next, list->entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
+ && key->event_hotkey.external_hotkey_num == event)
+ val = key->link.hotkey_standard_num;
+ else
+ val = -1;
+ }
+
+ return_VALUE(val);
+}
+
+static void
+acpi_hotkey_notify_handler(acpi_handle handle, u32 event, void *data)
+{
+ struct acpi_device *device = NULL;
+ u32 internal_event;
+
+ ACPI_FUNCTION_TRACE("acpi_hotkey_notify_handler");
+
+ if (acpi_bus_get_device(handle, &device))
+ return_VOID;
+
+ internal_event = hotkey_get_internal_event(event, &global_hotkey_list);
+ acpi_bus_generate_event(device, event, 0);
+
+ return_VOID;
+}
+
+/* Need to invent automatically hotkey add method */
+static int auto_hotkey_add(struct acpi_device *device)
+{
+ /* Implement me */
+ return 0;
+}
+
+/* Need to invent automatically hotkey remove method */
+static int auto_hotkey_remove(struct acpi_device *device, int type)
+{
+ /* Implement me */
+ return 0;
+}
+
+/* Create a proc file for each polling method */
+static int create_polling_proc(union acpi_hotkey *device)
+{
+ struct proc_dir_entry *proc;
+ mode_t mode;
+
+ ACPI_FUNCTION_TRACE("create_polling_proc");
+ mode = S_IFREG | S_IRUGO | S_IWUGO;
+
+ proc = create_proc_entry(device->poll_hotkey.action_method,
+ mode, hotkey_proc_dir);
+
+ if (!proc) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ device->poll_hotkey.poll_method));
+ return_VALUE(-ENODEV);
+ } else {
+ proc->proc_fops = &hotkey_polling_fops;
+ proc->owner = THIS_MODULE;
+ proc->data = device;
+ proc->uid = 0;
+ proc->gid = 0;
+ device->poll_hotkey.proc = proc;
+ }
+ return_VALUE(0);
+}
+
+static int is_valid_acpi_path(const char *pathname)
+{
+ acpi_handle handle;
+ acpi_status status;
+ ACPI_FUNCTION_TRACE("is_valid_acpi_path");
+
+ status = acpi_get_handle(NULL, (char *)pathname, &handle);
+ return_VALUE(!ACPI_FAILURE(status));
+}
+
+static int is_valid_hotkey(union acpi_hotkey *device)
+{
+ ACPI_FUNCTION_TRACE("is_valid_hotkey");
+ /* Implement valid check */
+ return_VALUE(1);
+}
+
+static int hotkey_add(union acpi_hotkey *device)
+{
+ int status = 0;
+ struct acpi_device *dev = NULL;
+
+ ACPI_FUNCTION_TRACE("hotkey_add");
+
+ if (device->link.hotkey_type == ACPI_HOTKEY_EVENT) {
+ status =
+ acpi_bus_get_device(device->event_hotkey.bus_handle, &dev);
+ if (status)
+ return_VALUE(status);
+
+ status = acpi_install_notify_handler(dev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_hotkey_notify_handler,
+ device);
+ } else /* Add polling hotkey */
+ create_polling_proc(device);
+
+ global_hotkey_list.count++;
+
+ list_add_tail(&device->link.entries, global_hotkey_list.entries);
+
+ return_VALUE(status);
+}
+
+static int hotkey_remove(union acpi_hotkey *device)
+{
+ struct list_head *entries, *next;
+
+ ACPI_FUNCTION_TRACE("hotkey_remove");
+
+ list_for_each_safe(entries, next, global_hotkey_list.entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_standard_num ==
+ device->link.hotkey_standard_num) {
+ list_del(&key->link.entries);
+ remove_proc_entry(key->poll_hotkey.action_method,
+ hotkey_proc_dir);
+ global_hotkey_list.count--;
+ break;
+ }
+ }
+ return_VALUE(0);
+}
+
+static void hotkey_update(union acpi_hotkey *key)
+{
+ struct list_head *entries, *next;
+
+ ACPI_FUNCTION_TRACE("hotkey_update");
+
+ list_for_each_safe(entries, next, global_hotkey_list.entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_standard_num ==
+ key->link.hotkey_standard_num) {
+ key->event_hotkey.bus_handle =
+ key->event_hotkey.bus_handle;
+ key->event_hotkey.external_hotkey_num =
+ key->event_hotkey.external_hotkey_num;
+ key->event_hotkey.action_handle =
+ key->event_hotkey.action_handle;
+ key->event_hotkey.action_method =
+ key->event_hotkey.action_method;
+ break;
+ }
+ }
+
+ return_VOID;
+}
+
+static void free_hotkey_device(union acpi_hotkey *key)
+{
+ struct acpi_device *dev;
+ int status;
+
+ ACPI_FUNCTION_TRACE("free_hotkey_device");
+
+ if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
+ status =
+ acpi_bus_get_device(key->event_hotkey.bus_handle, &dev);
+ if (dev->handle)
+ acpi_remove_notify_handler(dev->handle,
+ ACPI_SYSTEM_NOTIFY,
+ acpi_hotkey_notify_handler);
+ } else
+ remove_proc_entry(key->poll_hotkey.action_method,
+ hotkey_proc_dir);
+ kfree(key);
+ return_VOID;
+}
+
+static int
+init_hotkey_device(union acpi_hotkey *key, char *bus_str, char *action_str,
+ char *method, int std_num, int external_num)
+{
+ ACPI_FUNCTION_TRACE("init_hotkey_device");
+
+ key->link.hotkey_type = ACPI_HOTKEY_EVENT;
+ key->link.hotkey_standard_num = std_num;
+ key->event_hotkey.flag = 0;
+ if (is_valid_acpi_path(bus_str))
+ acpi_get_handle((acpi_handle) 0,
+ bus_str, &(key->event_hotkey.bus_handle));
+ else
+ return_VALUE(-ENODEV);
+ key->event_hotkey.external_hotkey_num = external_num;
+ if (is_valid_acpi_path(action_str))
+ acpi_get_handle((acpi_handle) 0,
+ action_str, &(key->event_hotkey.action_handle));
+ key->event_hotkey.action_method = kmalloc(sizeof(method), GFP_KERNEL);
+ strcpy(key->event_hotkey.action_method, method);
+
+ return_VALUE(!is_valid_hotkey(key));
+}
+
+static int
+init_poll_hotkey_device(union acpi_hotkey *key,
+ char *poll_str,
+ char *poll_method,
+ char *action_str, char *action_method, int std_num)
+{
+ ACPI_FUNCTION_TRACE("init_poll_hotkey_device");
+
+ key->link.hotkey_type = ACPI_HOTKEY_POLLING;
+ key->link.hotkey_standard_num = std_num;
+ key->poll_hotkey.flag = 0;
+ if (is_valid_acpi_path(poll_str))
+ acpi_get_handle((acpi_handle) 0,
+ poll_str, &(key->poll_hotkey.poll_handle));
+ else
+ return_VALUE(-ENODEV);
+ key->poll_hotkey.poll_method = poll_method;
+ if (is_valid_acpi_path(action_str))
+ acpi_get_handle((acpi_handle) 0,
+ action_str, &(key->poll_hotkey.action_handle));
+ key->poll_hotkey.action_method =
+ kmalloc(sizeof(action_method), GFP_KERNEL);
+ strcpy(key->poll_hotkey.action_method, action_method);
+ key->poll_hotkey.poll_result =
+ (union acpi_object *)kmalloc(sizeof(union acpi_object), GFP_KERNEL);
+ return_VALUE(is_valid_hotkey(key));
+}
+
+static int check_hotkey_valid(union acpi_hotkey *key,
+ struct acpi_hotkey_list *list)
+{
+ ACPI_FUNCTION_TRACE("check_hotkey_valid");
+ return_VALUE(0);
+}
+
+static int hotkey_open_config(struct inode *inode, struct file *file)
+{
+ ACPI_FUNCTION_TRACE("hotkey_open_config");
+ return_VALUE(single_open
+ (file, hotkey_config_seq_show, PDE(inode)->data));
+}
+
+static int hotkey_config_seq_show(struct seq_file *seq, void *offset)
+{
+ struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
+ struct list_head *entries, *next;
+ char bus_name[ACPI_PATHNAME_MAX] = { 0 };
+ char action_name[ACPI_PATHNAME_MAX] = { 0 };
+ struct acpi_buffer bus = { ACPI_PATHNAME_MAX, bus_name };
+ struct acpi_buffer act = { ACPI_PATHNAME_MAX, action_name };
+
+ ACPI_FUNCTION_TRACE(("hotkey_config_seq_show"));
+
+ if (!hotkey_list)
+ goto end;
+
+ list_for_each_safe(entries, next, hotkey_list->entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_type == ACPI_HOTKEY_EVENT) {
+ acpi_get_name(key->event_hotkey.bus_handle,
+ ACPI_NAME_TYPE_MAX, &bus);
+ acpi_get_name(key->event_hotkey.action_handle,
+ ACPI_NAME_TYPE_MAX, &act);
+ seq_printf(seq, "%s:%s:%s:%d:%d", bus_name,
+ action_name,
+ key->event_hotkey.action_method,
+ key->link.hotkey_standard_num,
+ key->event_hotkey.external_hotkey_num);
+ } /* ACPI_HOTKEY_POLLING */
+ else {
+ acpi_get_name(key->poll_hotkey.poll_handle,
+ ACPI_NAME_TYPE_MAX, &bus);
+ acpi_get_name(key->poll_hotkey.action_handle,
+ ACPI_NAME_TYPE_MAX, &act);
+ seq_printf(seq, "%s:%s:%s:%s:%d", bus_name,
+ key->poll_hotkey.poll_method,
+ action_name,
+ key->poll_hotkey.action_method,
+ key->link.hotkey_standard_num);
+ }
+ }
+ seq_puts(seq, "\n");
+ end:
+ return_VALUE(0);
+}
+
+static int
+get_parms(char *config_record,
+ int *cmd,
+ char *bus_handle,
+ char *bus_method,
+ char *action_handle,
+ char *method, int *internal_event_num, int *external_event_num)
+{
+ char *tmp, *tmp1;
+ ACPI_FUNCTION_TRACE(("get_parms"));
+
+ sscanf(config_record, "%d", cmd);
+
+ tmp = strchr(config_record, ':');
+ tmp++;
+ tmp1 = strchr(tmp, ':');
+ strncpy(bus_handle, tmp, tmp1 - tmp);
+ bus_handle[tmp1 - tmp] = 0;
+
+ tmp = tmp1;
+ tmp++;
+ tmp1 = strchr(tmp, ':');
+ strncpy(bus_method, tmp, tmp1 - tmp);
+ bus_method[tmp1 - tmp] = 0;
+
+ tmp = tmp1;
+ tmp++;
+ tmp1 = strchr(tmp, ':');
+ strncpy(action_handle, tmp, tmp1 - tmp);
+ action_handle[tmp1 - tmp] = 0;
+
+ tmp = tmp1;
+ tmp++;
+ tmp1 = strchr(tmp, ':');
+ strncpy(method, tmp, tmp1 - tmp);
+ method[tmp1 - tmp] = 0;
+
+ sscanf(tmp1 + 1, "%d:%d", internal_event_num, external_event_num);
+ return_VALUE(6);
+}
+
+/* count is length for one input record */
+static ssize_t hotkey_write_config(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data)
+{
+ struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
+ char config_record[MAX_CONFIG_RECORD_LEN];
+ char bus_handle[MAX_NAME_PATH_LEN];
+ char bus_method[MAX_NAME_PATH_LEN];
+ char action_handle[MAX_NAME_PATH_LEN];
+ char method[20];
+ int cmd, internal_event_num, external_event_num;
+ int ret = 0;
+ union acpi_hotkey *key = NULL;
+
+ ACPI_FUNCTION_TRACE(("hotkey_write_config"));
+
+ if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (copy_from_user(config_record, buffer, count)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
+ return_VALUE(-EINVAL);
+ }
+ config_record[count] = '\0';
+
+ ret = get_parms(config_record,
+ &cmd,
+ bus_handle,
+ bus_method,
+ action_handle,
+ method, &internal_event_num, &external_event_num);
+ if (ret != 6) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Invalid data format ret=%d\n", ret));
+ return_VALUE(-EINVAL);
+ }
+
+ key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
+ ret = init_hotkey_device(key, bus_handle, action_handle, method,
+ internal_event_num, external_event_num);
+
+ if (ret || check_hotkey_valid(key, hotkey_list)) {
+ kfree(key);
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
+ return_VALUE(-EINVAL);
+ }
+ switch (cmd) {
+ case 0:
+ hotkey_add(key);
+ break;
+ case 1:
+ hotkey_remove(key);
+ free_hotkey_device(key);
+ break;
+ case 2:
+ hotkey_update(key);
+ break;
+ default:
+ break;
+ }
+ return_VALUE(count);
+}
+
+/* count is length for one input record */
+static ssize_t hotkey_write_poll_config(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ struct acpi_hotkey_list *hotkey_list =
+ (struct acpi_hotkey_list *)m->private;
+
+ char config_record[MAX_CONFIG_RECORD_LEN];
+ char polling_handle[MAX_NAME_PATH_LEN];
+ char action_handle[MAX_NAME_PATH_LEN];
+ char poll_method[20], action_method[20];
+ int ret, internal_event_num, cmd, external_event_num;
+ union acpi_hotkey *key = NULL;
+
+ ACPI_FUNCTION_TRACE("hotkey_write_poll_config");
+
+ if (!hotkey_list || count > MAX_CONFIG_RECORD_LEN) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid arguments\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (copy_from_user(config_record, buffer, count)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data \n"));
+ return_VALUE(-EINVAL);
+ }
+ config_record[count] = '\0';
+
+ ret = get_parms(config_record,
+ &cmd,
+ polling_handle,
+ poll_method,
+ action_handle,
+ action_method,
+ &internal_event_num, &external_event_num);
+
+ if (ret != 6) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
+ return_VALUE(-EINVAL);
+ }
+
+ key = kmalloc(sizeof(union acpi_hotkey), GFP_KERNEL);
+ ret = init_poll_hotkey_device(key, polling_handle, poll_method,
+ action_handle, action_method,
+ internal_event_num);
+ if (ret || check_hotkey_valid(key, hotkey_list)) {
+ kfree(key);
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid hotkey \n"));
+ return_VALUE(-EINVAL);
+ }
+ switch (cmd) {
+ case 0:
+ hotkey_add(key);
+ break;
+ case 1:
+ hotkey_remove(key);
+ break;
+ case 2:
+ hotkey_update(key);
+ break;
+ default:
+ break;
+ }
+ return_VALUE(count);
+}
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+ struct acpi_buffer *output)
+{
+ struct acpi_object_list params; /* list of input parameters (an int here) */
+ union acpi_object in_obj; /* the only param we use */
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("write_acpi_int");
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = val;
+
+ status = acpi_evaluate_object(handle, (char *)method, &params, output);
+
+ return_VALUE(status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+ struct acpi_buffer output;
+ union acpi_object out_obj;
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE("read_acpi_int");
+ output.length = sizeof(out_obj);
+ output.pointer = &out_obj;
+
+ status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
+ *val = out_obj.integer.value;
+ return_VALUE((status == AE_OK)
+ && (out_obj.type == ACPI_TYPE_INTEGER));
+}
+
+static acpi_handle
+get_handle_from_hotkeylist(struct acpi_hotkey_list *hotkey_list, int event_num)
+{
+ struct list_head *entries, *next;
+
+ list_for_each_safe(entries, next, hotkey_list->entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_type == ACPI_HOTKEY_EVENT
+ && key->link.hotkey_standard_num == event_num) {
+ return (key->event_hotkey.action_handle);
+ }
+ }
+ return (NULL);
+}
+
+static
+char *get_method_from_hotkeylist(struct acpi_hotkey_list *hotkey_list,
+ int event_num)
+{
+ struct list_head *entries, *next;
+
+ list_for_each_safe(entries, next, hotkey_list->entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+
+ if (key->link.hotkey_type == ACPI_HOTKEY_EVENT &&
+ key->link.hotkey_standard_num == event_num)
+ return (key->event_hotkey.action_method);
+ }
+ return (NULL);
+}
+
+static struct acpi_polling_hotkey *get_hotkey_by_event(struct
+ acpi_hotkey_list
+ *hotkey_list, int event)
+{
+ struct list_head *entries, *next;
+
+ list_for_each_safe(entries, next, hotkey_list->entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+ if (key->link.hotkey_type == ACPI_HOTKEY_POLLING
+ && key->link.hotkey_standard_num == event) {
+ return (&key->poll_hotkey);
+ }
+ }
+ return (NULL);
+}
+
+/*
+ * user call AML method interface:
+ * Call convention:
+ * echo "event_num: arg type : value"
+ * example: echo "1:1:30" > /proc/acpi/action
+ * Just support 1 integer arg passing to AML method
+ */
+
+static ssize_t hotkey_execute_aml_method(struct file *file,
+ const char __user * buffer,
+ size_t count, loff_t * data)
+{
+ struct acpi_hotkey_list *hotkey_list = &global_hotkey_list;
+ char arg[MAX_CALL_PARM];
+ int event, type, value;
+
+ char *method;
+ acpi_handle handle;
+
+ ACPI_FUNCTION_TRACE("hotkey_execte_aml_method");
+
+ if (!hotkey_list || count > MAX_CALL_PARM) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 1"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (copy_from_user(arg, buffer, count)) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 2"));
+ return_VALUE(-EINVAL);
+ }
+
+ arg[count] = '\0';
+
+ if (sscanf(arg, "%d:%d:%d", &event, &type, &value) != 3) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument 3"));
+ return_VALUE(-EINVAL);
+ }
+
+ if (type == ACPI_TYPE_INTEGER) {
+ handle = get_handle_from_hotkeylist(hotkey_list, event);
+ method = (char *)get_method_from_hotkeylist(hotkey_list, event);
+ if (IS_EVENT(event))
+ write_acpi_int(handle, method, value, NULL);
+ else if (IS_POLL(event)) {
+ struct acpi_polling_hotkey *key;
+ key = (struct acpi_polling_hotkey *)
+ get_hotkey_by_event(hotkey_list, event);
+ read_acpi_int(handle, method, key->poll_result);
+ }
+ } else {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Not supported"));
+ return_VALUE(-EINVAL);
+ }
+
+ return_VALUE(count);
+}
+
+static int __init hotkey_init(void)
+{
+ int result;
+ mode_t mode = S_IFREG | S_IRUGO | S_IWUGO;
+
+ ACPI_FUNCTION_TRACE("hotkey_init");
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (acpi_specific_hotkey_enabled) {
+ printk("Using specific hotkey driver\n");
+ return -ENODEV;
+ }
+
+ hotkey_proc_dir = proc_mkdir(HOTKEY_PROC, acpi_root_dir);
+ if (!hotkey_proc_dir) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ HOTKEY_PROC));
+ return (-ENODEV);
+ }
+ hotkey_proc_dir->owner = THIS_MODULE;
+
+ hotkey_config =
+ create_proc_entry(HOTKEY_EV_CONFIG, mode, hotkey_proc_dir);
+ if (!hotkey_config) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ HOTKEY_EV_CONFIG));
+ return (-ENODEV);
+ } else {
+ hotkey_config->proc_fops = &hotkey_config_fops;
+ hotkey_config->data = &global_hotkey_list;
+ hotkey_config->owner = THIS_MODULE;
+ hotkey_config->uid = 0;
+ hotkey_config->gid = 0;
+ }
+
+ hotkey_poll_config =
+ create_proc_entry(HOTKEY_PL_CONFIG, mode, hotkey_proc_dir);
+ if (!hotkey_poll_config) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ HOTKEY_EV_CONFIG));
+ return (-ENODEV);
+ } else {
+ hotkey_poll_config->proc_fops = &hotkey_poll_config_fops;
+ hotkey_poll_config->data = &global_hotkey_list;
+ hotkey_poll_config->owner = THIS_MODULE;
+ hotkey_poll_config->uid = 0;
+ hotkey_poll_config->gid = 0;
+ }
+
+ hotkey_action = create_proc_entry(HOTKEY_ACTION, mode, hotkey_proc_dir);
+ if (!hotkey_action) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ HOTKEY_ACTION));
+ return (-ENODEV);
+ } else {
+ hotkey_action->proc_fops = &hotkey_action_fops;
+ hotkey_action->owner = THIS_MODULE;
+ hotkey_action->uid = 0;
+ hotkey_action->gid = 0;
+ }
+
+ hotkey_info = create_proc_entry(HOTKEY_INFO, mode, hotkey_proc_dir);
+ if (!hotkey_info) {
+ ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+ "Hotkey: Unable to create %s entry\n",
+ HOTKEY_INFO));
+ return (-ENODEV);
+ } else {
+ hotkey_info->proc_fops = &hotkey_info_fops;
+ hotkey_info->owner = THIS_MODULE;
+ hotkey_info->uid = 0;
+ hotkey_info->gid = 0;
+ }
+
+ result = acpi_bus_register_driver(&hotkey_driver);
+ if (result < 0) {
+ remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
+ return (-ENODEV);
+ }
+ global_hotkey_list.count = 0;
+ global_hotkey_list.entries = &hotkey_entries;
+
+ INIT_LIST_HEAD(&hotkey_entries);
+
+ return (0);
+}
+
+static void __exit hotkey_exit(void)
+{
+ struct list_head *entries, *next;
+
+ ACPI_FUNCTION_TRACE("hotkey_remove");
+
+ list_for_each_safe(entries, next, global_hotkey_list.entries) {
+ union acpi_hotkey *key =
+ container_of(entries, union acpi_hotkey, entries);
+
+ acpi_os_wait_events_complete(NULL);
+ list_del(&key->link.entries);
+ global_hotkey_list.count--;
+ free_hotkey_device(key);
+ }
+ acpi_bus_unregister_driver(&hotkey_driver);
+ remove_proc_entry(HOTKEY_EV_CONFIG, hotkey_proc_dir);
+ remove_proc_entry(HOTKEY_PL_CONFIG, hotkey_proc_dir);
+ remove_proc_entry(HOTKEY_ACTION, hotkey_proc_dir);
+ remove_proc_entry(HOTKEY_INFO, hotkey_proc_dir);
+ remove_proc_entry(HOTKEY_PROC, acpi_root_dir);
+ return;
+}
+
+module_init(hotkey_init);
+module_exit(hotkey_exit);
diff --git a/drivers/acpi/ibm_acpi.c b/drivers/acpi/ibm_acpi.c
index 0fb731a470dc..ad85e10001f4 100644
--- a/drivers/acpi/ibm_acpi.c
+++ b/drivers/acpi/ibm_acpi.c
@@ -1025,7 +1025,7 @@ static int setup_notify(struct ibm_struct *ibm)
return 0;
}
-static int device_add(struct acpi_device *device)
+static int ibmacpi_device_add(struct acpi_device *device)
{
return 0;
}
@@ -1043,7 +1043,7 @@ static int register_driver(struct ibm_struct *ibm)
memset(ibm->driver, 0, sizeof(struct acpi_driver));
sprintf(ibm->driver->name, "%s/%s", IBM_NAME, ibm->name);
ibm->driver->ids = ibm->hid;
- ibm->driver->ops.add = &device_add;
+ ibm->driver->ops.add = &ibmacpi_device_add;
ret = acpi_bus_register_driver(ibm->driver);
if (ret < 0) {
@@ -1185,6 +1185,10 @@ static int __init acpi_ibm_init(void)
if (acpi_disabled)
return -ENODEV;
+ if (!acpi_specific_hotkey_enabled){
+ printk(IBM_ERR "Using generic hotkey driver\n");
+ return -ENODEV;
+ }
/* these handles are required */
if (IBM_HANDLE_INIT(ec, 1) < 0 ||
IBM_HANDLE_INIT(hkey, 1) < 0 ||
diff --git a/drivers/acpi/namespace/nsaccess.c b/drivers/acpi/namespace/nsaccess.c
index 1c0c12336c57..ece7a9dedd5c 100644
--- a/drivers/acpi/namespace/nsaccess.c
+++ b/drivers/acpi/namespace/nsaccess.c
@@ -67,7 +67,8 @@
******************************************************************************/
acpi_status
-acpi_ns_root_initialize (void)
+acpi_ns_root_initialize (
+ void)
{
acpi_status status;
const struct acpi_predefined_names *init_val = NULL;
@@ -265,7 +266,7 @@ unlock_and_exit:
*
* FUNCTION: acpi_ns_lookup
*
- * PARAMETERS: prefix_node - Search scope if name is not fully qualified
+ * PARAMETERS: scope_info - Current scope info block
* Pathname - Search pathname, in internal format
* (as represented in the AML stream)
* Type - Type associated with name
diff --git a/drivers/acpi/namespace/nsalloc.c b/drivers/acpi/namespace/nsalloc.c
index bfd922c5c7d1..5653a19d7172 100644
--- a/drivers/acpi/namespace/nsalloc.c
+++ b/drivers/acpi/namespace/nsalloc.c
@@ -49,14 +49,20 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsalloc")
+/* Local prototypes */
+
+static void
+acpi_ns_remove_reference (
+ struct acpi_namespace_node *node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_create_node
*
- * PARAMETERS: acpi_name - Name of the new node
+ * PARAMETERS: Name - Name of the new node (4 char ACPI name)
*
- * RETURN: None
+ * RETURN: New namespace node (Null on failure)
*
* DESCRIPTION: Create a namespace node
*
@@ -145,7 +151,6 @@ acpi_ns_delete_node (
}
}
-
ACPI_MEM_TRACKING (acpi_gbl_memory_lists[ACPI_MEM_LIST_NSNODE].total_freed++);
/*
@@ -157,57 +162,6 @@ acpi_ns_delete_node (
}
-#ifdef ACPI_ALPHABETIC_NAMESPACE
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_compare_names
- *
- * PARAMETERS: Name1 - First name to compare
- * Name2 - Second name to compare
- *
- * RETURN: value from strncmp
- *
- * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an
- * underscore are forced to be alphabetically first.
- *
- ******************************************************************************/
-
-int
-acpi_ns_compare_names (
- char *name1,
- char *name2)
-{
- char reversed_name1[ACPI_NAME_SIZE];
- char reversed_name2[ACPI_NAME_SIZE];
- u32 i;
- u32 j;
-
-
- /*
- * Replace all instances of "underscore" with a value that is smaller so
- * that all names that are prefixed with underscore(s) are alphabetically
- * first.
- *
- * Reverse the name bytewise so we can just do a 32-bit compare instead
- * of a strncmp.
- */
- for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) {
- reversed_name1[j] = name1[i];
- if (name1[i] == '_') {
- reversed_name1[j] = '*';
- }
-
- reversed_name2[j] = name2[i];
- if (name2[i] == '_') {
- reversed_name2[j] = '*';
- }
- }
-
- return (*(int *) reversed_name1 - *(int *) reversed_name2);
-}
-#endif
-
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_install_node
@@ -271,7 +225,8 @@ acpi_ns_install_node (
* alphabetic placement.
*/
previous_child_node = NULL;
- while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node), acpi_ut_get_node_name (node)) < 0) {
+ while (acpi_ns_compare_names (acpi_ut_get_node_name (child_node),
+ acpi_ut_get_node_name (node)) < 0) {
if (child_node->flags & ANOBJ_END_OF_PEER_LIST) {
/* Last peer; Clear end-of-list flag */
@@ -429,7 +384,8 @@ acpi_ns_delete_children (
/* There should be only one reference remaining on this node */
if (child_node->reference_count != 1) {
- ACPI_REPORT_WARNING (("Existing references (%d) on node being deleted (%p)\n",
+ ACPI_REPORT_WARNING ((
+ "Existing references (%d) on node being deleted (%p)\n",
child_node->reference_count, child_node));
}
@@ -548,7 +504,7 @@ acpi_ns_delete_namespace_subtree (
*
******************************************************************************/
-void
+static void
acpi_ns_remove_reference (
struct acpi_namespace_node *node)
{
@@ -683,3 +639,54 @@ acpi_ns_delete_namespace_by_owner (
}
+#ifdef ACPI_ALPHABETIC_NAMESPACE
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_compare_names
+ *
+ * PARAMETERS: Name1 - First name to compare
+ * Name2 - Second name to compare
+ *
+ * RETURN: value from strncmp
+ *
+ * DESCRIPTION: Compare two ACPI names. Names that are prefixed with an
+ * underscore are forced to be alphabetically first.
+ *
+ ******************************************************************************/
+
+int
+acpi_ns_compare_names (
+ char *name1,
+ char *name2)
+{
+ char reversed_name1[ACPI_NAME_SIZE];
+ char reversed_name2[ACPI_NAME_SIZE];
+ u32 i;
+ u32 j;
+
+
+ /*
+ * Replace all instances of "underscore" with a value that is smaller so
+ * that all names that are prefixed with underscore(s) are alphabetically
+ * first.
+ *
+ * Reverse the name bytewise so we can just do a 32-bit compare instead
+ * of a strncmp.
+ */
+ for (i = 0, j= (ACPI_NAME_SIZE - 1); i < ACPI_NAME_SIZE; i++, j--) {
+ reversed_name1[j] = name1[i];
+ if (name1[i] == '_') {
+ reversed_name1[j] = '*';
+ }
+
+ reversed_name2[j] = name2[i];
+ if (name2[i] == '_') {
+ reversed_name2[j] = '*';
+ }
+ }
+
+ return (*(int *) reversed_name1 - *(int *) reversed_name2);
+}
+#endif
+
+
diff --git a/drivers/acpi/namespace/nsdump.c b/drivers/acpi/namespace/nsdump.c
index 1f6af3eb6c91..6c2aef0e0dd4 100644
--- a/drivers/acpi/namespace/nsdump.c
+++ b/drivers/acpi/namespace/nsdump.c
@@ -50,16 +50,32 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsdump")
+/* Local prototypes */
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+void
+acpi_ns_dump_root_devices (
+ void);
+static acpi_status
+acpi_ns_dump_one_device (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+#endif
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*******************************************************************************
*
* FUNCTION: acpi_ns_print_pathname
*
- * PARAMETERS: num_segment - Number of ACPI name segments
+ * PARAMETERS: num_segments - Number of ACPI name segments
* Pathname - The compressed (internal) path
*
+ * RETURN: None
+ *
* DESCRIPTION: Print an object's full namespace pathname
*
******************************************************************************/
@@ -103,6 +119,8 @@ acpi_ns_print_pathname (
* Level - Desired debug level
* Component - Caller's component ID
*
+ * RETURN: None
+ *
* DESCRIPTION: Print an object's full namespace pathname
* Manages allocation/freeing of a pathname buffer
*
@@ -137,9 +155,12 @@ acpi_ns_dump_pathname (
*
* FUNCTION: acpi_ns_dump_one_object
*
- * PARAMETERS: Handle - Node to be dumped
+ * PARAMETERS: obj_handle - Node to be dumped
* Level - Nesting level of the handle
* Context - Passed into walk_namespace
+ * return_value - Not used
+ *
+ * RETURN: Status
*
* DESCRIPTION: Dump a single Node
* This procedure is a user_function called by acpi_ns_walk_namespace.
@@ -394,8 +415,7 @@ acpi_ns_dump_one_object (
return (AE_OK);
}
- acpi_os_printf ("(R%d)",
- obj_desc->common.reference_count);
+ acpi_os_printf ("(R%d)", obj_desc->common.reference_count);
switch (type) {
case ACPI_TYPE_METHOD:
@@ -551,18 +571,20 @@ cleanup:
#ifdef ACPI_FUTURE_USAGE
-
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_objects
*
* PARAMETERS: Type - Object type to be dumped
+ * display_type - 0 or ACPI_DISPLAY_SUMMARY
* max_depth - Maximum depth of dump. Use ACPI_UINT32_MAX
* for an effectively unlimited depth.
* owner_id - Dump only objects owned by this ID. Use
* ACPI_UINT32_MAX to match all owners.
* start_handle - Where in namespace to start/end search
*
+ * RETURN: None
+ *
* DESCRIPTION: Dump typed objects within the loaded namespace.
* Uses acpi_ns_walk_namespace in conjunction with acpi_ns_dump_one_object.
*
@@ -590,10 +612,44 @@ acpi_ns_dump_objects (
ACPI_NS_WALK_NO_UNLOCK, acpi_ns_dump_one_object,
(void *) &info, NULL);
}
+#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
*
+ * FUNCTION: acpi_ns_dump_entry
+ *
+ * PARAMETERS: Handle - Node to be dumped
+ * debug_level - Output level
+ *
+ * RETURN: None
+ *
+ * DESCRIPTION: Dump a single Node
+ *
+ ******************************************************************************/
+
+void
+acpi_ns_dump_entry (
+ acpi_handle handle,
+ u32 debug_level)
+{
+ struct acpi_walk_info info;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ info.debug_level = debug_level;
+ info.owner_id = ACPI_UINT32_MAX;
+ info.display_type = ACPI_DISPLAY_SUMMARY;
+
+ (void) acpi_ns_dump_one_object (handle, 1, &info, NULL);
+}
+
+
+#ifdef _ACPI_ASL_COMPILER
+/*******************************************************************************
+ *
* FUNCTION: acpi_ns_dump_tables
*
* PARAMETERS: search_base - Root of subtree to be dumped, or
@@ -601,6 +657,8 @@ acpi_ns_dump_objects (
* max_depth - Maximum depth of dump. Use INT_MAX
* for an effectively unlimited depth.
*
+ * RETURN: None
+ *
* DESCRIPTION: Dump the name space, or a portion of it.
*
******************************************************************************/
@@ -626,7 +684,7 @@ acpi_ns_dump_tables (
}
if (ACPI_NS_ALL == search_base) {
- /* entire namespace */
+ /* Entire namespace */
search_handle = acpi_gbl_root_node;
ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "\\\n"));
@@ -636,38 +694,5 @@ acpi_ns_dump_tables (
ACPI_UINT32_MAX, search_handle);
return_VOID;
}
-
-#endif /* ACPI_FUTURE_USAGE */
-
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ns_dump_entry
- *
- * PARAMETERS: Handle - Node to be dumped
- * debug_level - Output level
- *
- * DESCRIPTION: Dump a single Node
- *
- ******************************************************************************/
-
-void
-acpi_ns_dump_entry (
- acpi_handle handle,
- u32 debug_level)
-{
- struct acpi_walk_info info;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- info.debug_level = debug_level;
- info.owner_id = ACPI_UINT32_MAX;
- info.display_type = ACPI_DISPLAY_SUMMARY;
-
- (void) acpi_ns_dump_one_object (handle, 1, &info, NULL);
-}
-
-#endif
-
+#endif /* _ACPI_ASL_COMPILER */
+#endif /* defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER) */
diff --git a/drivers/acpi/namespace/nsdumpdv.c b/drivers/acpi/namespace/nsdumpdv.c
index d30a59e6b07d..27c4f7cd2a43 100644
--- a/drivers/acpi/namespace/nsdumpdv.c
+++ b/drivers/acpi/namespace/nsdumpdv.c
@@ -43,15 +43,18 @@
#include <acpi/acpi.h>
-#include <acpi/acnamesp.h>
+/* TBD: This entire module is apparently obsolete and should be removed */
+
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsdumpdv")
-
+#ifdef ACPI_OBSOLETE_FUNCTIONS
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+#include <acpi/acnamesp.h>
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_dump_one_device
@@ -59,13 +62,16 @@
* PARAMETERS: Handle - Node to be dumped
* Level - Nesting level of the handle
* Context - Passed into walk_namespace
+ * return_value - Not used
+ *
+ * RETURN: Status
*
* DESCRIPTION: Dump a single Node that represents a device
* This procedure is a user_function called by acpi_ns_walk_namespace.
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_dump_one_device (
acpi_handle obj_handle,
u32 level,
@@ -108,12 +114,15 @@ acpi_ns_dump_one_device (
*
* PARAMETERS: None
*
+ * RETURN: None
+ *
* DESCRIPTION: Dump all objects of type "device"
*
******************************************************************************/
void
-acpi_ns_dump_root_devices (void)
+acpi_ns_dump_root_devices (
+ void)
{
acpi_handle sys_bus_handle;
acpi_status status;
@@ -142,5 +151,6 @@ acpi_ns_dump_root_devices (void)
}
#endif
+#endif
diff --git a/drivers/acpi/namespace/nseval.c b/drivers/acpi/namespace/nseval.c
index 0d008d53657e..1ae89a1c8826 100644
--- a/drivers/acpi/namespace/nseval.c
+++ b/drivers/acpi/namespace/nseval.c
@@ -52,19 +52,33 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nseval")
+/* Local prototypes */
+
+static acpi_status
+acpi_ns_execute_control_method (
+ struct acpi_parameter_info *info);
+
+static acpi_status
+acpi_ns_get_object_value (
+ struct acpi_parameter_info *info);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_evaluate_relative
*
- * PARAMETERS: Pathname - Name of method to execute, If NULL, the
- * handle is the object to execute
- * Info - Method info block
+ * PARAMETERS: Pathname - Name of method to execute, If NULL, the
+ * handle is the object to execute
+ * Info - Method info block, 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,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
*
* RETURN: Status
*
- * DESCRIPTION: Find and execute the requested method using the handle as a
- * scope
+ * DESCRIPTION: Evaluate the object or find and execute the requested method
*
* MUTEX: Locks Namespace
*
@@ -157,8 +171,8 @@ cleanup1:
*
* FUNCTION: acpi_ns_evaluate_by_name
*
- * PARAMETERS: Pathname - Fully qualified pathname to the object
- * Info - Contains:
+ * PARAMETERS: Pathname - Fully qualified pathname to the object
+ * Info - Method info block, 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,
@@ -167,8 +181,8 @@ cleanup1:
*
* RETURN: Status
*
- * DESCRIPTION: Find and execute the requested method passing the given
- * parameters
+ * DESCRIPTION: Evaluate the object or rind and execute the requested method
+ * passing the given parameters
*
* MUTEX: Locks Namespace
*
@@ -241,17 +255,21 @@ cleanup:
*
* FUNCTION: acpi_ns_evaluate_by_handle
*
- * PARAMETERS: Handle - Method Node to execute
- * Params - List of parameters to pass to the method,
- * terminated by NULL. Params itself may be
+ * PARAMETERS: Info - Method info block, contains:
+ * Node - Method/Object Node to execute
+ * Parameters - 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.
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * parameter_type - Type of Parameter list
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
*
* RETURN: Status
*
- * DESCRIPTION: Execute the requested method passing the given parameters
+ * DESCRIPTION: Evaluate object or execute the requested method passing the
+ * given parameters
*
* MUTEX: Locks Namespace
*
@@ -345,7 +363,16 @@ acpi_ns_evaluate_by_handle (
*
* FUNCTION: acpi_ns_execute_control_method
*
- * PARAMETERS: Info - Method info block (w/params)
+ * PARAMETERS: Info - Method info block, contains:
+ * Node - Method Node to execute
+ * Parameters - List of parameters to pass to the method,
+ * terminated by NULL. Params itself may be
+ * NULL if no parameters are being passed.
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * parameter_type - Type of Parameter list
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
*
* RETURN: Status
*
@@ -355,7 +382,7 @@ acpi_ns_evaluate_by_handle (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_execute_control_method (
struct acpi_parameter_info *info)
{
@@ -414,7 +441,10 @@ acpi_ns_execute_control_method (
*
* FUNCTION: acpi_ns_get_object_value
*
- * PARAMETERS: Info - Method info block (w/params)
+ * PARAMETERS: Info - Method info block, contains:
+ * Node - Object's NS node
+ * return_object - Where to put object value (if
+ * any). If NULL, no value is returned.
*
* RETURN: Status
*
@@ -424,7 +454,7 @@ acpi_ns_execute_control_method (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_get_object_value (
struct acpi_parameter_info *info)
{
diff --git a/drivers/acpi/namespace/nsinit.c b/drivers/acpi/namespace/nsinit.c
index 4a46b380605b..362802ae29a2 100644
--- a/drivers/acpi/namespace/nsinit.c
+++ b/drivers/acpi/namespace/nsinit.c
@@ -50,6 +50,22 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsinit")
+/* Local prototypes */
+
+static acpi_status
+acpi_ns_init_one_object (
+ acpi_handle obj_handle,
+ u32 level,
+ void *context,
+ void **return_value);
+
+static acpi_status
+acpi_ns_init_one_device (
+ acpi_handle obj_handle,
+ u32 nesting_level,
+ void *context,
+ void **return_value);
+
/*******************************************************************************
*
@@ -191,7 +207,7 @@ acpi_ns_initialize_devices (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_init_one_object (
acpi_handle obj_handle,
u32 level,
@@ -331,7 +347,7 @@ acpi_ns_init_one_object (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_init_one_device (
acpi_handle obj_handle,
u32 nesting_level,
@@ -374,7 +390,8 @@ 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, pinfo.node, "_STA"));
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD,
+ pinfo.node, METHOD_NAME__STA));
status = acpi_ut_execute_STA (pinfo.node, &flags);
if (ACPI_FAILURE (status)) {
@@ -399,8 +416,9 @@ acpi_ns_init_one_device (
/*
* The device is present. Run _INI.
*/
- ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD, pinfo.node, "_INI"));
- status = acpi_ns_evaluate_relative ("_INI", &pinfo);
+ ACPI_DEBUG_EXEC (acpi_ut_display_init_pathname (ACPI_TYPE_METHOD,
+ pinfo.node, METHOD_NAME__INI));
+ status = acpi_ns_evaluate_relative (METHOD_NAME__INI, &pinfo);
if (ACPI_FAILURE (status)) {
/* No _INI (AE_NOT_FOUND) means device requires no initialization */
diff --git a/drivers/acpi/namespace/nsload.c b/drivers/acpi/namespace/nsload.c
index 1d7aedf68a77..34e497016601 100644
--- a/drivers/acpi/namespace/nsload.c
+++ b/drivers/acpi/namespace/nsload.c
@@ -50,9 +50,24 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsload")
+/* Local prototypes */
-#ifndef ACPI_NO_METHOD_EXECUTION
+static acpi_status
+acpi_ns_load_table_by_type (
+ acpi_table_type table_type);
+
+#ifdef ACPI_FUTURE_IMPLEMENTATION
+acpi_status
+acpi_ns_unload_namespace (
+ acpi_handle handle);
+
+static acpi_status
+acpi_ns_delete_subtree (
+ acpi_handle start_handle);
+#endif
+
+#ifndef ACPI_NO_METHOD_EXECUTION
/*******************************************************************************
*
* FUNCTION: acpi_ns_load_table
@@ -159,7 +174,7 @@ acpi_ns_load_table (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_load_table_by_type (
acpi_table_type table_type)
{
@@ -321,8 +336,7 @@ acpi_ns_load_namespace (
}
-#ifdef ACPI_FUTURE_USAGE
-
+#ifdef ACPI_FUTURE_IMPLEMENTATION
/*******************************************************************************
*
* FUNCTION: acpi_ns_delete_subtree
@@ -339,7 +353,7 @@ acpi_ns_load_namespace (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ns_delete_subtree (
acpi_handle start_handle)
{
@@ -453,8 +467,6 @@ acpi_ns_unload_namespace (
return_ACPI_STATUS (status);
}
-
-#endif /* ACPI_FUTURE_USAGE */
-
+#endif
#endif
diff --git a/drivers/acpi/namespace/nsnames.c b/drivers/acpi/namespace/nsnames.c
index b6f8f910eff0..d8ce7e39795f 100644
--- a/drivers/acpi/namespace/nsnames.c
+++ b/drivers/acpi/namespace/nsnames.c
@@ -50,6 +50,14 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsnames")
+/* Local prototypes */
+
+static void
+acpi_ns_build_external_path (
+ struct acpi_namespace_node *node,
+ acpi_size size,
+ char *name_buffer);
+
/*******************************************************************************
*
@@ -66,7 +74,7 @@
*
******************************************************************************/
-void
+static void
acpi_ns_build_external_path (
struct acpi_namespace_node *node,
acpi_size size,
@@ -126,7 +134,7 @@ acpi_ns_build_external_path (
*
* FUNCTION: acpi_ns_get_external_pathname
*
- * PARAMETERS: Node - NS node whose pathname is needed
+ * PARAMETERS: Node - Namespace node whose pathname is needed
*
* RETURN: Pointer to storage containing the fully qualified name of
* the node, In external format (name segments separated by path
diff --git a/drivers/acpi/namespace/nsobject.c b/drivers/acpi/namespace/nsobject.c
index 4e41e66db61f..27258c1ca4f1 100644
--- a/drivers/acpi/namespace/nsobject.c
+++ b/drivers/acpi/namespace/nsobject.c
@@ -60,6 +60,8 @@
* Type - Type of object, or ACPI_TYPE_ANY if not
* known
*
+ * RETURN: Status
+ *
* DESCRIPTION: Record the given object as the value associated with the
* name whose acpi_handle is passed. If Object is NULL
* and Type is ACPI_TYPE_ANY, set the name as having no value.
@@ -97,7 +99,8 @@ acpi_ns_attach_object (
if (!object && (ACPI_TYPE_ANY != type)) {
/* Null object */
- ACPI_REPORT_ERROR (("ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n"));
+ ACPI_REPORT_ERROR ((
+ "ns_attach_object: Null object, but type not ACPI_TYPE_ANY\n"));
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
@@ -112,7 +115,8 @@ acpi_ns_attach_object (
/* Check if this object is already attached */
if (node->object == object) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Obj %p already installed in name_obj %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Obj %p already installed in name_obj %p\n",
object, node));
return_ACPI_STATUS (AE_OK);
@@ -192,7 +196,7 @@ acpi_ns_attach_object (
*
* FUNCTION: acpi_ns_detach_object
*
- * PARAMETERS: Node - An node whose object will be detached
+ * PARAMETERS: Node - A Namespace node whose object will be detached
*
* RETURN: None.
*
@@ -248,7 +252,7 @@ acpi_ns_detach_object (
*
* FUNCTION: acpi_ns_get_attached_object
*
- * PARAMETERS: Node - Parent Node to be examined
+ * PARAMETERS: Node - Namespace node
*
* RETURN: Current value of the object field from the Node whose
* handle is passed
@@ -284,7 +288,7 @@ acpi_ns_get_attached_object (
*
* FUNCTION: acpi_ns_get_secondary_object
*
- * PARAMETERS: Node - Parent Node to be examined
+ * PARAMETERS: Node - Namespace node
*
* RETURN: Current value of the object field from the Node whose
* handle is passed.
diff --git a/drivers/acpi/namespace/nssearch.c b/drivers/acpi/namespace/nssearch.c
index 0e6dea23603b..af8aaa9cc4f3 100644
--- a/drivers/acpi/namespace/nssearch.c
+++ b/drivers/acpi/namespace/nssearch.c
@@ -49,15 +49,24 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nssearch")
+/* Local prototypes */
+
+static acpi_status
+acpi_ns_search_parent_tree (
+ u32 target_name,
+ struct acpi_namespace_node *node,
+ acpi_object_type type,
+ struct acpi_namespace_node **return_node);
+
/*******************************************************************************
*
* FUNCTION: acpi_ns_search_node
*
- * PARAMETERS: *target_name - Ascii ACPI name to search for
- * *Node - Starting node where search will begin
- * Type - Object type to match
- * **return_node - Where the matched Named obj is returned
+ * PARAMETERS: target_name - Ascii ACPI name to search for
+ * Node - Starting node where search will begin
+ * Type - Object type to match
+ * return_node - Where the matched Named obj is returned
*
* RETURN: Status
*
@@ -163,10 +172,10 @@ acpi_ns_search_node (
*
* FUNCTION: acpi_ns_search_parent_tree
*
- * PARAMETERS: *target_name - Ascii ACPI name to search for
- * *Node - Starting node where search will begin
- * Type - Object type to match
- * **return_node - Where the matched Node is returned
+ * PARAMETERS: target_name - Ascii ACPI name to search for
+ * Node - Starting node where search will begin
+ * Type - Object type to match
+ * return_node - Where the matched Node is returned
*
* RETURN: Status
*
@@ -257,12 +266,12 @@ acpi_ns_search_parent_tree (
*
* PARAMETERS: target_name - Ascii ACPI name to search for (4 chars)
* walk_state - Current state of the walk
- * *Node - Starting node where search will begin
+ * Node - Starting node where search will begin
* interpreter_mode - Add names only in ACPI_MODE_LOAD_PASS_x.
* Otherwise,search only.
* Type - Object type to match
* Flags - Flags describing the search restrictions
- * **return_node - Where the Node is returned
+ * return_node - Where the Node is returned
*
* RETURN: Status
*
diff --git a/drivers/acpi/namespace/nsutils.c b/drivers/acpi/namespace/nsutils.c
index 75da76cc0b19..c53b82e94ce3 100644
--- a/drivers/acpi/namespace/nsutils.c
+++ b/drivers/acpi/namespace/nsutils.c
@@ -51,6 +51,18 @@
#define _COMPONENT ACPI_NAMESPACE
ACPI_MODULE_NAME ("nsutils")
+/* Local prototypes */
+
+static u8
+acpi_ns_valid_path_separator (
+ char sep);
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+acpi_name
+acpi_ns_find_parent_name (
+ struct acpi_namespace_node *node_to_search);
+#endif
+
/*******************************************************************************
*
@@ -59,7 +71,8 @@
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
* component_id - Caller's component ID (for error output)
- * Message - Error message to use on failure
+ * internal_name - Name or path of the namespace node
+ * lookup_status - Exception code from NS lookup
*
* RETURN: None
*
@@ -121,6 +134,9 @@ acpi_ns_report_error (
* line_number - Caller's line number (for error output)
* component_id - Caller's component ID (for error output)
* Message - Error message to use on failure
+ * prefix_node - Prefix relative to the path
+ * Path - Path to the node
+ * method_status - Execution status
*
* RETURN: None
*
@@ -161,8 +177,8 @@ acpi_ns_report_method_error (
*
* FUNCTION: acpi_ns_print_node_pathname
*
- * PARAMETERS: Node - Object
- * Msg - Prefix message
+ * PARAMETERS: Node - Object
+ * Message - Prefix message
*
* DESCRIPTION: Print an object's full namespace pathname
* Manages allocation/freeing of a pathname buffer
@@ -172,7 +188,7 @@ acpi_ns_report_method_error (
void
acpi_ns_print_node_pathname (
struct acpi_namespace_node *node,
- char *msg)
+ char *message)
{
struct acpi_buffer buffer;
acpi_status status;
@@ -189,8 +205,8 @@ acpi_ns_print_node_pathname (
status = acpi_ns_handle_to_pathname (node, &buffer);
if (ACPI_SUCCESS (status)) {
- if (msg) {
- acpi_os_printf ("%s ", msg);
+ if (message) {
+ acpi_os_printf ("%s ", message);
}
acpi_os_printf ("[%s] (Node %p)", (char *) buffer.pointer, node);
@@ -224,7 +240,7 @@ acpi_ns_valid_root_prefix (
*
* FUNCTION: acpi_ns_valid_path_separator
*
- * PARAMETERS: Sep - Character to be checked
+ * PARAMETERS: Sep - Character to be checked
*
* RETURN: TRUE if a valid path separator
*
@@ -232,7 +248,7 @@ acpi_ns_valid_root_prefix (
*
******************************************************************************/
-u8
+static u8
acpi_ns_valid_path_separator (
char sep)
{
@@ -245,10 +261,12 @@ acpi_ns_valid_path_separator (
*
* FUNCTION: acpi_ns_get_type
*
- * PARAMETERS: Handle - Parent Node to be examined
+ * PARAMETERS: Node - Parent Node to be examined
*
* RETURN: Type field from Node whose handle is passed
*
+ * DESCRIPTION: Return the type of a Namespace node
+ *
******************************************************************************/
acpi_object_type
@@ -271,11 +289,13 @@ acpi_ns_get_type (
*
* FUNCTION: acpi_ns_local
*
- * PARAMETERS: Type - A namespace object type
+ * PARAMETERS: Type - A namespace object type
*
* RETURN: LOCAL if names must be found locally in objects of the
* passed type, 0 if enclosing scopes should be searched
*
+ * DESCRIPTION: Returns scope rule for the given object type.
+ *
******************************************************************************/
u32
@@ -303,7 +323,7 @@ acpi_ns_local (
* PARAMETERS: Info - Info struct initialized with the
* external name pointer.
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Calculate the length of the internal (AML) namestring
* corresponding to the external (ASL) namestring.
@@ -551,14 +571,16 @@ acpi_ns_internalize_name (
*
* FUNCTION: acpi_ns_externalize_name
*
- * PARAMETERS: *internal_name - Internal representation of name
- * **converted_name - Where to return the resulting
- * external representation of name
+ * PARAMETERS: internal_name_length - Lenth of the internal name below
+ * internal_name - Internal representation of name
+ * converted_name_length - Where the length is returned
+ * converted_name - Where the resulting external name
+ * is returned
*
* RETURN: Status
*
* DESCRIPTION: Convert internal name (e.g. 5c 2f 02 5f 50 52 5f 43 50 55 30)
- * to its external form (e.g. "\_PR_.CPU0")
+ * to its external (printable) form (e.g. "\_PR_.CPU0")
*
******************************************************************************/
@@ -717,8 +739,9 @@ acpi_ns_externalize_name (
*
* DESCRIPTION: Convert a namespace handle to a real Node
*
- * Note: Real integer handles allow for more verification
- * and keep all pointers within this subsystem.
+ * Note: Real integer handles would allow for more verification
+ * and keep all pointers within this subsystem - however this introduces
+ * more (and perhaps unnecessary) overhead.
*
******************************************************************************/
@@ -775,7 +798,7 @@ acpi_ns_convert_entry_to_handle (
return ((acpi_handle) node);
-/* ---------------------------------------------------
+/* Example future implementation ---------------------
if (!Node)
{
@@ -801,12 +824,13 @@ acpi_ns_convert_entry_to_handle (
*
* RETURN: none
*
- * DESCRIPTION: free memory allocated for table storage.
+ * DESCRIPTION: free memory allocated for namespace and ACPI table storage.
*
******************************************************************************/
void
-acpi_ns_terminate (void)
+acpi_ns_terminate (
+ void)
{
union acpi_operand_object *obj_desc;
@@ -940,7 +964,6 @@ acpi_ns_get_node_by_path (
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
cleanup:
- /* Cleanup */
if (internal_path) {
ACPI_MEM_FREE (internal_path);
}
@@ -950,55 +973,6 @@ cleanup:
/*******************************************************************************
*
- * FUNCTION: acpi_ns_find_parent_name
- *
- * PARAMETERS: *child_node - Named Obj whose name is to be found
- *
- * RETURN: The ACPI name
- *
- * DESCRIPTION: Search for the given obj in its parent scope and return the
- * name segment, or "????" if the parent name can't be found
- * (which "should not happen").
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-acpi_name
-acpi_ns_find_parent_name (
- struct acpi_namespace_node *child_node)
-{
- struct acpi_namespace_node *parent_node;
-
-
- ACPI_FUNCTION_TRACE ("ns_find_parent_name");
-
-
- if (child_node) {
- /* Valid entry. Get the parent Node */
-
- parent_node = acpi_ns_get_parent_node (child_node);
- if (parent_node) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
- "Parent of %p [%4.4s] is %p [%4.4s]\n",
- child_node, acpi_ut_get_node_name (child_node),
- parent_node, acpi_ut_get_node_name (parent_node)));
-
- if (parent_node->name.integer) {
- return_VALUE ((acpi_name) parent_node->name.integer);
- }
- }
-
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
- "Unable to find parent of %p (%4.4s)\n",
- child_node, acpi_ut_get_node_name (child_node)));
- }
-
- return_VALUE (ACPI_UNKNOWN_NAME);
-}
-#endif
-
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ns_get_parent_node
*
* PARAMETERS: Node - Current table entry
@@ -1009,7 +983,6 @@ acpi_ns_find_parent_name (
*
******************************************************************************/
-
struct acpi_namespace_node *
acpi_ns_get_parent_node (
struct acpi_namespace_node *node)
@@ -1030,7 +1003,6 @@ acpi_ns_get_parent_node (
node = node->peer;
}
-
return (node->peer);
}
@@ -1049,7 +1021,6 @@ acpi_ns_get_parent_node (
*
******************************************************************************/
-
struct acpi_namespace_node *
acpi_ns_get_next_valid_node (
struct acpi_namespace_node *node)
@@ -1067,3 +1038,53 @@ acpi_ns_get_next_valid_node (
}
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ns_find_parent_name
+ *
+ * PARAMETERS: *child_node - Named Obj whose name is to be found
+ *
+ * RETURN: The ACPI name
+ *
+ * DESCRIPTION: Search for the given obj in its parent scope and return the
+ * name segment, or "????" if the parent name can't be found
+ * (which "should not happen").
+ *
+ ******************************************************************************/
+
+acpi_name
+acpi_ns_find_parent_name (
+ struct acpi_namespace_node *child_node)
+{
+ struct acpi_namespace_node *parent_node;
+
+
+ ACPI_FUNCTION_TRACE ("ns_find_parent_name");
+
+
+ if (child_node) {
+ /* Valid entry. Get the parent Node */
+
+ parent_node = acpi_ns_get_parent_node (child_node);
+ if (parent_node) {
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Parent of %p [%4.4s] is %p [%4.4s]\n",
+ child_node, acpi_ut_get_node_name (child_node),
+ parent_node, acpi_ut_get_node_name (parent_node)));
+
+ if (parent_node->name.integer) {
+ return_VALUE ((acpi_name) parent_node->name.integer);
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "Unable to find parent of %p (%4.4s)\n",
+ child_node, acpi_ut_get_node_name (child_node)));
+ }
+
+ return_VALUE (ACPI_UNKNOWN_NAME);
+}
+#endif
+
+
diff --git a/drivers/acpi/namespace/nswalk.c b/drivers/acpi/namespace/nswalk.c
index 4de2444df300..f9a7277dca6e 100644
--- a/drivers/acpi/namespace/nswalk.c
+++ b/drivers/acpi/namespace/nswalk.c
@@ -56,7 +56,7 @@
*
* PARAMETERS: Type - Type of node to be searched for
* parent_node - Parent node whose children we are
- * getting
+ * getting
* child_node - Previous child that was found.
* The NEXT child will be returned
*
diff --git a/drivers/acpi/namespace/nsxfeval.c b/drivers/acpi/namespace/nsxfeval.c
index 1dc995586cbe..12ea202257fa 100644
--- a/drivers/acpi/namespace/nsxfeval.c
+++ b/drivers/acpi/namespace/nsxfeval.c
@@ -58,11 +58,11 @@
* FUNCTION: acpi_evaluate_object_typed
*
* PARAMETERS: Handle - Object handle (optional)
- * *Pathname - Object pathname (optional)
- * **external_params - List of parameters to pass to method,
+ * Pathname - Object pathname (optional)
+ * external_params - List of parameters to pass to method,
* terminated by NULL. May be NULL
* if no parameters are being passed.
- * *return_buffer - Where to put method's return value (if
+ * return_buffer - Where to put method's return value (if
* any). If NULL, no value is returned.
* return_type - Expected type of return object
*
@@ -73,6 +73,7 @@
* be valid (non-null)
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_evaluate_object_typed (
@@ -307,7 +308,8 @@ acpi_evaluate_object (
if (ACPI_SUCCESS (status)) {
/* Validate/Allocate/Clear caller buffer */
- status = acpi_ut_initialize_buffer (return_buffer, buffer_space_needed);
+ status = acpi_ut_initialize_buffer (return_buffer,
+ buffer_space_needed);
if (ACPI_FAILURE (status)) {
/*
* Caller's buffer is too small or a new one can't be allocated
@@ -423,7 +425,8 @@ acpi_walk_namespace (
return_ACPI_STATUS (status);
}
- status = acpi_ns_walk_namespace (type, start_object, max_depth, ACPI_NS_WALK_UNLOCK,
+ status = acpi_ns_walk_namespace (type, start_object, max_depth,
+ ACPI_NS_WALK_UNLOCK,
user_function, context, return_value);
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
@@ -525,7 +528,8 @@ acpi_ns_get_device_callback (
}
}
- status = info->user_function (obj_handle, nesting_level, info->context, return_value);
+ status = info->user_function (obj_handle, nesting_level, info->context,
+ return_value);
return (status);
}
diff --git a/drivers/acpi/namespace/nsxfname.c b/drivers/acpi/namespace/nsxfname.c
index f2405efd1b9a..8d097914c49a 100644
--- a/drivers/acpi/namespace/nsxfname.c
+++ b/drivers/acpi/namespace/nsxfname.c
@@ -57,9 +57,9 @@
* FUNCTION: acpi_get_handle
*
* PARAMETERS: Parent - Object to search under (search scope).
- * path_name - Pointer to an asciiz string containing the
- * name
- * ret_handle - Where the return handle is placed
+ * Pathname - Pointer to an asciiz string containing the
+ * name
+ * ret_handle - Where the return handle is returned
*
* RETURN: Status
*
@@ -220,7 +220,7 @@ EXPORT_SYMBOL(acpi_get_name);
* FUNCTION: acpi_get_object_info
*
* PARAMETERS: Handle - Object Handle
- * Info - Where the info is returned
+ * Buffer - Where the info is returned
*
* RETURN: Status
*
diff --git a/drivers/acpi/namespace/nsxfobj.c b/drivers/acpi/namespace/nsxfobj.c
index 19acf32674b9..363e1f6cfb18 100644
--- a/drivers/acpi/namespace/nsxfobj.c
+++ b/drivers/acpi/namespace/nsxfobj.c
@@ -56,7 +56,7 @@
* FUNCTION: acpi_get_type
*
* PARAMETERS: Handle - Handle of object whose type is desired
- * *ret_type - Where the type will be placed
+ * ret_type - Where the type will be placed
*
* RETURN: Status
*
@@ -258,5 +258,5 @@ unlock_and_exit:
(void) acpi_ut_release_mutex (ACPI_MTX_NAMESPACE);
return (status);
}
-EXPORT_SYMBOL(acpi_get_next_object);
+EXPORT_SYMBOL(acpi_get_next_object);
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 5a9128de6226..bdd9f37f8101 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -71,6 +71,9 @@ EXPORT_SYMBOL(acpi_in_debugger);
extern char line_buf[80];
#endif /*ENABLE_DEBUGGER*/
+int acpi_specific_hotkey_enabled;
+EXPORT_SYMBOL(acpi_specific_hotkey_enabled);
+
static unsigned int acpi_irq_irq;
static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
@@ -1152,6 +1155,15 @@ acpi_wake_gpes_always_on_setup(char *str)
__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);
+int __init
+acpi_hotkey_setup(char *str)
+{
+ acpi_specific_hotkey_enabled = TRUE;
+ return 1;
+}
+
+__setup("acpi_specific_hotkey", acpi_hotkey_setup);
+
/*
* max_cstate is defined in the base kernel so modules can
* change it w/o depending on the state of the processor module.
diff --git a/drivers/acpi/parser/psargs.c b/drivers/acpi/parser/psargs.c
index b5d98895f6a8..b7ac68cc9e1c 100644
--- a/drivers/acpi/parser/psargs.c
+++ b/drivers/acpi/parser/psargs.c
@@ -50,6 +50,16 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME ("psargs")
+/* Local prototypes */
+
+static u32
+acpi_ps_get_next_package_length (
+ struct acpi_parse_state *parser_state);
+
+static union acpi_parse_object *
+acpi_ps_get_next_field (
+ struct acpi_parse_state *parser_state);
+
/*******************************************************************************
*
@@ -64,7 +74,7 @@
*
******************************************************************************/
-u32
+static u32
acpi_ps_get_next_package_length (
struct acpi_parse_state *parser_state)
{
@@ -78,7 +88,6 @@ acpi_ps_get_next_package_length (
encoded_length = (u32) ACPI_GET8 (parser_state->aml);
parser_state->aml++;
-
switch (encoded_length >> 6) /* bits 6-7 contain encoding scheme */ {
case 0: /* 1-byte encoding (bits 0-5) */
@@ -287,13 +296,14 @@ acpi_ps_get_next_namepath (
* parent tree, but don't open a new scope -- we just want to lookup the
* object (MUST BE mode EXECUTE to perform upsearch)
*/
- status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
- ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &node);
+ status = acpi_ns_lookup (&scope_info, path, ACPI_TYPE_ANY,
+ ACPI_IMODE_EXECUTE,
+ ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE,
+ NULL, &node);
if (ACPI_SUCCESS (status) && method_call) {
if (node->type == ACPI_TYPE_METHOD) {
- /*
- * This name is actually a control method invocation
- */
+ /* This name is actually a control method invocation */
+
method_desc = acpi_ns_get_attached_object (node);
ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
"Control Method - %p Desc %p Path=%p\n",
@@ -360,7 +370,7 @@ acpi_ps_get_next_namepath (
/*
* We got a NOT_FOUND during table load or we encountered
* a cond_ref_of(x) where the target does not exist.
- * -- either case is ok
+ * Either case is ok
*/
status = AE_OK;
}
@@ -486,12 +496,13 @@ acpi_ps_get_next_simple_arg (
*
******************************************************************************/
-union acpi_parse_object *
+static union acpi_parse_object *
acpi_ps_get_next_field (
struct acpi_parse_state *parser_state)
{
- u32 aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
- parser_state->aml_start);
+ u32 aml_offset = (u32)
+ ACPI_PTR_DIFF (parser_state->aml,
+ parser_state->aml_start);
union acpi_parse_object *field;
u16 opcode;
u32 name;
@@ -500,7 +511,7 @@ acpi_ps_get_next_field (
ACPI_FUNCTION_TRACE ("ps_get_next_field");
- /* determine field type */
+ /* Determine field type */
switch (ACPI_GET8 (parser_state->aml)) {
default:
@@ -521,7 +532,6 @@ acpi_ps_get_next_field (
break;
}
-
/* Allocate a new field op */
field = acpi_ps_alloc_op (opcode);
@@ -582,10 +592,10 @@ acpi_ps_get_next_field (
*
* FUNCTION: acpi_ps_get_next_arg
*
- * PARAMETERS: parser_state - Current parser state object
+ * PARAMETERS: walk_state - Current state
+ * parser_state - Current parser state object
* arg_type - The argument type (AML_*_ARG)
- * arg_count - If the argument points to a control method
- * the method's argument is returned here.
+ * return_arg - Where the next arg is returned
*
* RETURN: Status, and an op object containing the next argument.
*
@@ -619,7 +629,7 @@ acpi_ps_get_next_arg (
case ARGP_NAME:
case ARGP_NAMESTRING:
- /* constants, strings, and namestrings are all the same size */
+ /* Constants, strings, and namestrings are all the same size */
arg = acpi_ps_alloc_op (AML_BYTE_OP);
if (!arg) {
@@ -654,7 +664,6 @@ acpi_ps_get_next_arg (
else {
arg = field;
}
-
prev = field;
}
@@ -677,8 +686,8 @@ acpi_ps_get_next_arg (
/* Fill in bytelist data */
- arg->common.value.size = (u32) ACPI_PTR_DIFF (parser_state->pkg_end,
- parser_state->aml);
+ arg->common.value.size = (u32)
+ ACPI_PTR_DIFF (parser_state->pkg_end, parser_state->aml);
arg->named.data = parser_state->aml;
/* Skip to End of byte data */
@@ -706,7 +715,7 @@ acpi_ps_get_next_arg (
status = acpi_ps_get_next_namepath (walk_state, parser_state, arg, 0);
}
else {
- /* single complex argument, nothing returned */
+ /* Single complex argument, nothing returned */
walk_state->arg_count = 1;
}
@@ -716,7 +725,7 @@ acpi_ps_get_next_arg (
case ARGP_DATAOBJ:
case ARGP_TERMARG:
- /* single complex argument, nothing returned */
+ /* Single complex argument, nothing returned */
walk_state->arg_count = 1;
break;
@@ -727,7 +736,7 @@ acpi_ps_get_next_arg (
case ARGP_OBJLIST:
if (parser_state->aml < parser_state->pkg_end) {
- /* non-empty list of variable arguments, nothing returned */
+ /* Non-empty list of variable arguments, nothing returned */
walk_state->arg_count = ACPI_VAR_ARGS;
}
diff --git a/drivers/acpi/parser/psopcode.c b/drivers/acpi/parser/psopcode.c
index 03e33fedc11a..5744673568c0 100644
--- a/drivers/acpi/parser/psopcode.c
+++ b/drivers/acpi/parser/psopcode.c
@@ -44,6 +44,7 @@
#include <acpi/acpi.h>
#include <acpi/acparser.h>
+#include <acpi/acopcode.h>
#include <acpi/amlcode.h>
@@ -51,23 +52,6 @@
ACPI_MODULE_NAME ("psopcode")
-#define _UNK 0x6B
-/*
- * Reserved ASCII characters. Do not use any of these for
- * internal opcodes, since they are used to differentiate
- * name strings from AML opcodes
- */
-#define _ASC 0x6C
-#define _NAM 0x6C
-#define _PFX 0x6D
-#define _UNKNOWN_OPCODE 0x02 /* An example unknown opcode */
-
-#define MAX_EXTENDED_OPCODE 0x88
-#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1)
-#define MAX_INTERNAL_OPCODE
-#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1)
-
-
/*******************************************************************************
*
* NAME: acpi_gbl_aml_op_info
@@ -79,274 +63,9 @@
*
******************************************************************************/
-
-/*
- * All AML opcodes and the parse-time arguments for each. Used by the AML parser Each list is compressed
- * into a 32-bit number and stored in the master opcode table at the end of this file.
- */
-
-
-#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA)
-#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME)
-#define ARGP_ARG0 ARG_NONE
-#define ARGP_ARG1 ARG_NONE
-#define ARGP_ARG2 ARG_NONE
-#define ARGP_ARG3 ARG_NONE
-#define ARGP_ARG4 ARG_NONE
-#define ARGP_ARG5 ARG_NONE
-#define ARGP_ARG6 ARG_NONE
-#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST)
-#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_BREAK_OP ARG_NONE
-#define ARGP_BREAK_POINT_OP ARG_NONE
-#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST)
-#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA)
-#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
-#define ARGP_CONTINUE_OP ARG_NONE
-#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME)
-#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
-#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_DEBUG_OP ARG_NONE
-#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
-#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
-#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
-#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
-#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
-#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
-#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
-#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
-#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
-#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST)
-#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG)
-#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME)
-#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_LOCAL0 ARG_NONE
-#define ARGP_LOCAL1 ARG_NONE
-#define ARGP_LOCAL2 ARG_NONE
-#define ARGP_LOCAL3 ARG_NONE
-#define ARGP_LOCAL4 ARG_NONE
-#define ARGP_LOCAL5 ARG_NONE
-#define ARGP_LOCAL6 ARG_NONE
-#define ARGP_LOCAL7 ARG_NONE
-#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST)
-#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA)
-#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ)
-#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_NOOP_OP ARG_NONE
-#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
-#define ARGP_ONE_OP ARG_NONE
-#define ARGP_ONES_OP ARG_NONE
-#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
-#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
-#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
-#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA)
-#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
-#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG)
-#define ARGP_REVISION_OP ARG_NONE
-#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST)
-#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG)
-#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG)
-#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING)
-#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME)
-#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST)
-#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
-#define ARGP_TIMER_OP ARG_NONE
-#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
-#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME)
-#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST)
-#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
-#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
-#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA)
-#define ARGP_ZERO_OP ARG_NONE
-
-
-/*
- * All AML opcodes and the runtime arguments for each. Used by the AML interpreter Each list is compressed
- * into a 32-bit number and stored in the master opcode table at the end of this file.
- *
- * (Used by prep_operands procedure and the ASL Compiler)
- */
-
-
-#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE
-#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER)
-#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE
-#define ARGI_ARG0 ARG_NONE
-#define ARGI_ARG1 ARG_NONE
-#define ARGI_ARG2 ARG_NONE
-#define ARGI_ARG3 ARG_NONE
-#define ARGI_ARG4 ARG_NONE
-#define ARGI_ARG5 ARG_NONE
-#define ARGI_ARG6 ARG_NONE
-#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE
-#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_BREAK_OP ARG_NONE
-#define ARGI_BREAK_POINT_OP ARG_NONE
-#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER)
-#define ARGI_BYTE_OP ARGI_INVALID_OPCODE
-#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE
-#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF)
-#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF)
-#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF)
-#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE
-#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET)
-#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
-#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
-#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
-#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_DEBUG_OP ARG_NONE
-#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
-#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
-#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
-#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
-#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
-#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
-#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
-#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER)
-#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
-#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_IF_OP ARGI_INVALID_OPCODE
-#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
-#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_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_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
-#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
-#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE)
-#define ARGI_LOCAL0 ARG_NONE
-#define ARGI_LOCAL1 ARG_NONE
-#define ARGI_LOCAL2 ARG_NONE
-#define ARGI_LOCAL3 ARG_NONE
-#define ARGI_LOCAL4 ARG_NONE
-#define ARGI_LOCAL5 ARG_NONE
-#define ARGI_LOCAL6 ARG_NONE
-#define ARGI_LOCAL7 ARG_NONE
-#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
-#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER)
-#define ARGI_METHOD_OP ARGI_INVALID_OPCODE
-#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
-#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE
-#define ARGI_NAME_OP ARGI_INVALID_OPCODE
-#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE
-#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE
-#define ARGI_NOOP_OP ARG_NONE
-#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER)
-#define ARGI_ONE_OP ARG_NONE
-#define ARGI_ONES_OP ARG_NONE
-#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
-#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE
-#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE
-#define ARGI_QWORD_OP ARGI_INVALID_OPCODE
-#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF)
-#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
-#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX)
-#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE
-#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT)
-#define ARGI_RETURN_OP ARGI_INVALID_OPCODE
-#define ARGI_REVISION_OP ARG_NONE
-#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE
-#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT)
-#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT)
-#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER)
-#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER)
-#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE
-#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
-#define ARGI_STRING_OP ARGI_INVALID_OPCODE
-#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
-#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
-#define ARGI_TIMER_OP ARG_NONE
-#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
-#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
-#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET)
-#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE)
-#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
-#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
-#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER)
-#define ARGI_WHILE_OP ARGI_INVALID_OPCODE
-#define ARGI_WORD_OP ARGI_INVALID_OPCODE
-#define ARGI_ZERO_OP ARG_NONE
-
-
/*
* Summary of opcode types/flags
- */
-
-/******************************************************************************
+ *
Opcodes that have associated namespace objects (AML_NSOBJECT flag)
@@ -460,14 +179,13 @@
AML_CREATE_DWORD_FIELD_OP
AML_CREATE_QWORD_FIELD_OP
-******************************************************************************/
+ ******************************************************************************/
/*
- * Master Opcode information table. A summary of everything we know about each opcode, all in one place.
+ * Master Opcode information table. A summary of everything we know about each
+ * opcode, all in one place.
*/
-
-
const struct acpi_opcode_info acpi_gbl_aml_op_info[AML_NUM_OPCODES] =
{
/*! [Begin] no source code translation */
@@ -693,8 +411,7 @@ static const u8 acpi_gbl_long_op_index[NUM_EXTENDED_OPCODE] =
*
* PARAMETERS: Opcode - The AML opcode
*
- * RETURN: A pointer to the info about the opcode. NULL if the opcode was
- * not found in the table.
+ * RETURN: A pointer to the info about the opcode.
*
* DESCRIPTION: Find AML opcode description based on the opcode.
* NOTE: This procedure must ALWAYS return a valid pointer!
@@ -731,7 +448,8 @@ acpi_ps_get_opcode_info (
default:
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown AML opcode [%4.4X]\n", opcode));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown AML opcode [%4.4X]\n", opcode));
break;
}
diff --git a/drivers/acpi/parser/psparse.c b/drivers/acpi/parser/psparse.c
index e79edb53cb3b..bbfdc1a58c27 100644
--- a/drivers/acpi/parser/psparse.c
+++ b/drivers/acpi/parser/psparse.c
@@ -64,6 +64,23 @@
static u32 acpi_gbl_depth = 0;
+/* Local prototypes */
+
+static void
+acpi_ps_complete_this_op (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
+
+static acpi_status
+acpi_ps_next_parse_state (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op,
+ acpi_status callback_status);
+
+static acpi_status
+acpi_ps_parse_loop (
+ struct acpi_walk_state *walk_state);
+
/*******************************************************************************
*
@@ -100,7 +117,7 @@ acpi_ps_get_opcode_size (
*
* PARAMETERS: parser_state - A parser state object
*
- * RETURN: Status
+ * RETURN: Next AML opcode
*
* DESCRIPTION: Get next AML opcode (without incrementing AML pointer)
*
@@ -117,7 +134,6 @@ acpi_ps_peek_opcode (
aml = parser_state->aml;
opcode = (u16) ACPI_GET8 (aml);
-
if (opcode == AML_EXTOP) {
/* Extended opcode */
@@ -142,7 +158,7 @@ acpi_ps_peek_opcode (
*
******************************************************************************/
-void
+static void
acpi_ps_complete_this_op (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op)
@@ -272,7 +288,6 @@ acpi_ps_complete_this_op (
next = NULL;
}
}
-
prev = next;
}
}
@@ -280,7 +295,7 @@ acpi_ps_complete_this_op (
cleanup:
- /* Now we can actually delete the subtree rooted at op */
+ /* Now we can actually delete the subtree rooted at Op */
acpi_ps_delete_parse_tree (op);
return_VOID;
@@ -291,7 +306,9 @@ cleanup:
*
* FUNCTION: acpi_ps_next_parse_state
*
- * PARAMETERS: parser_state - Current parser state object
+ * PARAMETERS: walk_state - Current state
+ * Op - Current parse op
+ * callback_status - Status from previous operation
*
* RETURN: Status
*
@@ -300,7 +317,7 @@ cleanup:
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ps_next_parse_state (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
@@ -382,9 +399,8 @@ acpi_ps_next_parse_state (
case AE_CTRL_TRANSFER:
- /*
- * A method call (invocation) -- transfer control
- */
+ /* A method call (invocation) -- transfer control */
+
status = AE_CTRL_TRANSFER;
walk_state->prev_op = op;
walk_state->method_call_op = op;
@@ -397,6 +413,7 @@ acpi_ps_next_parse_state (
default:
+
status = callback_status;
if ((callback_status & AE_CODE_MASK) == AE_CODE_CONTROL) {
status = AE_OK;
@@ -412,7 +429,7 @@ acpi_ps_next_parse_state (
*
* FUNCTION: acpi_ps_parse_loop
*
- * PARAMETERS: parser_state - Current parser state object
+ * PARAMETERS: walk_state - Current state
*
* RETURN: Status
*
@@ -421,7 +438,7 @@ acpi_ps_next_parse_state (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ps_parse_loop (
struct acpi_walk_state *walk_state)
{
@@ -443,6 +460,7 @@ acpi_ps_parse_loop (
walk_state->arg_types = 0;
#if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
+
if (walk_state->walk_type & ACPI_WALK_METHOD_RESTART) {
/* We are restarting a preempted control method */
@@ -471,7 +489,8 @@ acpi_ps_parse_loop (
acpi_format_exception (status)));
}
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "get_predicate Failed, %s\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "get_predicate Failed, %s\n",
acpi_format_exception (status)));
return_ACPI_STATUS (status);
}
@@ -492,16 +511,15 @@ acpi_ps_parse_loop (
}
#endif
- /*
- * Iterative parsing loop, while there is more aml to process:
- */
+ /* Iterative parsing loop, while there is more AML to process: */
+
while ((parser_state->aml < parser_state->aml_end) || (op)) {
aml_op_start = parser_state->aml;
if (!op) {
/* Get the next opcode from the AML stream */
walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
- parser_state->aml_start);
+ parser_state->aml_start);
walk_state->opcode = acpi_ps_peek_opcode (parser_state);
/*
@@ -578,8 +596,10 @@ acpi_ps_parse_loop (
INCREMENT_ARG_LIST (walk_state->arg_types);
}
- /* Make sure that we found a NAME and didn't run out of arguments */
-
+ /*
+ * Make sure that we found a NAME and didn't run out of
+ * arguments
+ */
if (!GET_CURRENT_ARG_TYPE (walk_state->arg_types)) {
status = AE_AML_NO_OPERAND;
goto close_this_op;
@@ -597,12 +617,13 @@ acpi_ps_parse_loop (
status = walk_state->descending_callback (walk_state, &op);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "During name lookup/catalog, %s\n",
- acpi_format_exception (status)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "During name lookup/catalog, %s\n",
+ acpi_format_exception (status)));
goto close_this_op;
}
- if (op == NULL) {
+ if (!op) {
continue;
}
@@ -659,7 +680,7 @@ acpi_ps_parse_loop (
if ((walk_state->descending_callback != NULL)) {
/*
- * Find the object. This will either insert the object into
+ * Find the object. This will either insert the object into
* the namespace or simply look it up
*/
walk_state->op = op;
@@ -688,11 +709,15 @@ acpi_ps_parse_loop (
}
- /* Start arg_count at zero because we don't know if there are any args yet */
-
+ /*
+ * Start arg_count at zero because we don't know if there are
+ * any args yet
+ */
walk_state->arg_count = 0;
- if (walk_state->arg_types) /* Are there any arguments that must be processed? */ {
+ /* Are there any arguments that must be processed? */
+
+ if (walk_state->arg_types) {
/* Get arguments */
switch (op->common.aml_opcode) {
@@ -720,14 +745,18 @@ acpi_ps_parse_loop (
default:
- /* Op is not a constant or string, append each argument to the Op */
-
+ /*
+ * Op is not a constant or string, append each argument
+ * to the Op
+ */
while (GET_CURRENT_ARG_TYPE (walk_state->arg_types) &&
!walk_state->arg_count) {
- walk_state->aml_offset = (u32) ACPI_PTR_DIFF (parser_state->aml,
- parser_state->aml_start);
+ walk_state->aml_offset = (u32)
+ ACPI_PTR_DIFF (parser_state->aml, parser_state->aml_start);
+
status = acpi_ps_get_next_arg (walk_state, parser_state,
- GET_CURRENT_ARG_TYPE (walk_state->arg_types), &arg);
+ GET_CURRENT_ARG_TYPE (walk_state->arg_types),
+ &arg);
if (ACPI_FAILURE (status)) {
goto close_this_op;
}
@@ -752,7 +781,8 @@ acpi_ps_parse_loop (
* Save the length and address of the body
*/
op->named.data = parser_state->aml;
- op->named.length = (u32) (parser_state->pkg_end - parser_state->aml);
+ op->named.length = (u32) (parser_state->pkg_end -
+ parser_state->aml);
/* Skip body of method */
@@ -773,7 +803,8 @@ acpi_ps_parse_loop (
* to parse them correctly.
*/
op->named.data = aml_op_start;
- op->named.length = (u32) (parser_state->pkg_end - aml_op_start);
+ op->named.length = (u32) (parser_state->pkg_end -
+ aml_op_start);
/* Skip body */
@@ -785,7 +816,8 @@ acpi_ps_parse_loop (
case AML_WHILE_OP:
if (walk_state->control_state) {
- walk_state->control_state->control.package_end = parser_state->pkg_end;
+ walk_state->control_state->control.package_end =
+ parser_state->pkg_end;
}
break;
@@ -801,8 +833,10 @@ acpi_ps_parse_loop (
/* Check for arguments that need to be processed */
if (walk_state->arg_count) {
- /* There are arguments (complex ones), push Op and prepare for argument */
-
+ /*
+ * There are arguments (complex ones), push Op and
+ * prepare for argument
+ */
status = acpi_ps_push_scope (parser_state, op,
walk_state->arg_types, walk_state->arg_count);
if (ACPI_FAILURE (status)) {
@@ -812,8 +846,10 @@ acpi_ps_parse_loop (
continue;
}
- /* All arguments have been processed -- Op is complete, prepare for next */
-
+ /*
+ * All arguments have been processed -- Op is complete,
+ * prepare for next
+ */
walk_state->op_info = acpi_ps_get_opcode_info (op->common.aml_opcode);
if (walk_state->op_info->flags & AML_NAMED) {
if (acpi_gbl_depth) {
@@ -880,9 +916,8 @@ close_this_op:
case AE_CTRL_TRANSFER:
- /*
- * We are about to transfer to a called method.
- */
+ /* We are about to transfer to a called method. */
+
walk_state->prev_op = op;
walk_state->prev_arg_types = walk_state->arg_types;
return_ACPI_STATUS (status);
@@ -1051,10 +1086,7 @@ close_this_op:
*
* FUNCTION: acpi_ps_parse_aml
*
- * PARAMETERS: start_scope - The starting point of the parse. Becomes the
- * root of the parsed op tree.
- * Aml - Pointer to the raw AML code to parse
- * aml_size - Length of the AML to parse
+ * PARAMETERS: walk_state - Current state
*
*
* RETURN: Status
@@ -1076,8 +1108,10 @@ acpi_ps_parse_aml (
ACPI_FUNCTION_TRACE ("ps_parse_aml");
- ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Entered with walk_state=%p Aml=%p size=%X\n",
- walk_state, walk_state->parser_state.aml, walk_state->parser_state.aml_size));
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Entered with walk_state=%p Aml=%p size=%X\n",
+ walk_state, walk_state->parser_state.aml,
+ walk_state->parser_state.aml_size));
/* Create and initialize a new thread state */
@@ -1142,9 +1176,10 @@ acpi_ps_parse_aml (
if ((status == AE_ALREADY_EXISTS) &&
(!walk_state->method_desc->method.semaphore)) {
/*
- * This method is marked not_serialized, but it tried to create a named
- * object, causing the second thread entrance to fail. We will workaround
- * this by marking the method permanently as Serialized.
+ * This method is marked not_serialized, but it tried to create
+ * a named object, causing the second thread entrance to fail.
+ * We will workaround this by marking the method permanently
+ * as Serialized.
*/
walk_state->method_desc->method.method_flags |= AML_METHOD_SERIALIZED;
walk_state->method_desc->method.concurrency = 1;
@@ -1187,7 +1222,8 @@ acpi_ps_parse_aml (
previous_walk_state = walk_state;
- ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "return_value=%p, implicit_value=%p State=%p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "return_value=%p, implicit_value=%p State=%p\n",
walk_state->return_desc, walk_state->implicit_return_obj, walk_state));
/* Check if we have restarted a preempted walk */
@@ -1231,12 +1267,14 @@ acpi_ps_parse_aml (
*/
else if (previous_walk_state->caller_return_desc) {
if (previous_walk_state->implicit_return_obj) {
- *(previous_walk_state->caller_return_desc) = previous_walk_state->implicit_return_obj;
+ *(previous_walk_state->caller_return_desc) =
+ previous_walk_state->implicit_return_obj;
}
else {
/* NULL if no return value */
- *(previous_walk_state->caller_return_desc) = previous_walk_state->return_desc;
+ *(previous_walk_state->caller_return_desc) =
+ previous_walk_state->return_desc;
}
}
else {
diff --git a/drivers/acpi/parser/psscope.c b/drivers/acpi/parser/psscope.c
index dcbed49608b0..8dcd1b1e7131 100644
--- a/drivers/acpi/parser/psscope.c
+++ b/drivers/acpi/parser/psscope.c
@@ -65,6 +65,7 @@ union acpi_parse_object *
acpi_ps_get_parent_scope (
struct acpi_parse_state *parser_state)
{
+
return (parser_state->scope->parse_scope.op);
}
@@ -87,8 +88,10 @@ u8
acpi_ps_has_completed_scope (
struct acpi_parse_state *parser_state)
{
- return ((u8) ((parser_state->aml >= parser_state->scope->parse_scope.arg_end ||
- !parser_state->scope->parse_scope.arg_count)));
+
+ return ((u8)
+ ((parser_state->aml >= parser_state->scope->parse_scope.arg_end ||
+ !parser_state->scope->parse_scope.arg_count)));
}
@@ -167,23 +170,23 @@ acpi_ps_push_scope (
return_ACPI_STATUS (AE_NO_MEMORY);
}
- scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE;
- scope->parse_scope.op = op;
- scope->parse_scope.arg_list = remaining_args;
- scope->parse_scope.arg_count = arg_count;
- scope->parse_scope.pkg_end = parser_state->pkg_end;
+ scope->common.data_type = ACPI_DESC_TYPE_STATE_PSCOPE;
+ scope->parse_scope.op = op;
+ scope->parse_scope.arg_list = remaining_args;
+ scope->parse_scope.arg_count = arg_count;
+ scope->parse_scope.pkg_end = parser_state->pkg_end;
/* Push onto scope stack */
acpi_ut_push_generic_state (&parser_state->scope, scope);
if (arg_count == ACPI_VAR_ARGS) {
- /* multiple arguments */
+ /* Multiple arguments */
scope->parse_scope.arg_end = parser_state->pkg_end;
}
else {
- /* single argument */
+ /* Single argument */
scope->parse_scope.arg_end = ACPI_TO_POINTER (ACPI_MAX_PTR);
}
@@ -221,18 +224,17 @@ acpi_ps_pop_scope (
ACPI_FUNCTION_TRACE ("ps_pop_scope");
- /*
- * Only pop the scope if there is in fact a next scope
- */
+ /* Only pop the scope if there is in fact a next scope */
+
if (scope->common.next) {
scope = acpi_ut_pop_generic_state (&parser_state->scope);
/* return to parsing previous op */
- *op = scope->parse_scope.op;
- *arg_list = scope->parse_scope.arg_list;
- *arg_count = scope->parse_scope.arg_count;
- parser_state->pkg_end = scope->parse_scope.pkg_end;
+ *op = scope->parse_scope.op;
+ *arg_list = scope->parse_scope.arg_list;
+ *arg_count = scope->parse_scope.arg_count;
+ parser_state->pkg_end = scope->parse_scope.pkg_end;
/* All done with this scope state structure */
@@ -241,12 +243,13 @@ acpi_ps_pop_scope (
else {
/* empty parse stack, prepare to fetch next opcode */
- *op = NULL;
- *arg_list = 0;
- *arg_count = 0;
+ *op = NULL;
+ *arg_list = 0;
+ *arg_count = 0;
}
- ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped Op %p Args %X\n", *op, *arg_count));
+ ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
+ "Popped Op %p Args %X\n", *op, *arg_count));
return_VOID;
}
@@ -257,7 +260,7 @@ acpi_ps_pop_scope (
*
* PARAMETERS: parser_state - Current parser state object
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Destroy available list, remaining stack levels, and return
* root scope
diff --git a/drivers/acpi/parser/pstree.c b/drivers/acpi/parser/pstree.c
index 2140bd1ac10b..d5aafe73fca0 100644
--- a/drivers/acpi/parser/pstree.c
+++ b/drivers/acpi/parser/pstree.c
@@ -49,6 +49,14 @@
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME ("pstree")
+/* Local prototypes */
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+union acpi_parse_object *
+acpi_ps_get_child (
+ union acpi_parse_object *op);
+#endif
+
/*******************************************************************************
*
@@ -57,7 +65,7 @@
* PARAMETERS: Op - Get an argument for this op
* Argn - Nth argument to get
*
- * RETURN: The argument (as an Op object). NULL if argument does not exist
+ * RETURN: The argument (as an Op object). NULL if argument does not exist
*
* DESCRIPTION: Get the specified op's argument.
*
@@ -152,7 +160,6 @@ acpi_ps_append_arg (
return;
}
-
/* Append the argument to the linked argument list */
if (op->common.value.arg) {
@@ -164,14 +171,12 @@ acpi_ps_append_arg (
}
prev_arg->common.next = arg;
}
-
else {
/* No argument list, this will be the first argument */
op->common.value.arg = arg;
}
-
/* Set the parent in this arg and any args linked after it */
while (arg) {
@@ -182,73 +187,6 @@ acpi_ps_append_arg (
#ifdef ACPI_FUTURE_USAGE
-
-/*******************************************************************************
- *
- * FUNCTION: acpi_ps_get_child
- *
- * PARAMETERS: Op - Get the child of this Op
- *
- * RETURN: Child Op, Null if none is found.
- *
- * DESCRIPTION: Get op's children or NULL if none
- *
- ******************************************************************************/
-union acpi_parse_object *
-acpi_ps_get_child (
- union acpi_parse_object *op)
-{
- union acpi_parse_object *child = NULL;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- switch (op->common.aml_opcode) {
- case AML_SCOPE_OP:
- case AML_ELSE_OP:
- case AML_DEVICE_OP:
- case AML_THERMAL_ZONE_OP:
- case AML_INT_METHODCALL_OP:
-
- child = acpi_ps_get_arg (op, 0);
- break;
-
-
- case AML_BUFFER_OP:
- case AML_PACKAGE_OP:
- case AML_METHOD_OP:
- case AML_IF_OP:
- case AML_WHILE_OP:
- case AML_FIELD_OP:
-
- child = acpi_ps_get_arg (op, 1);
- break;
-
-
- case AML_POWER_RES_OP:
- case AML_INDEX_FIELD_OP:
-
- child = acpi_ps_get_arg (op, 2);
- break;
-
-
- case AML_PROCESSOR_OP:
- case AML_BANK_FIELD_OP:
-
- child = acpi_ps_get_arg (op, 3);
- break;
-
-
- default:
- /* All others have no children */
- break;
- }
-
- return (child);
-}
-
-
/*******************************************************************************
*
* FUNCTION: acpi_ps_get_depth_next
@@ -280,21 +218,21 @@ acpi_ps_get_depth_next (
return (NULL);
}
- /* look for an argument or child */
+ /* Look for an argument or child */
next = acpi_ps_get_arg (op, 0);
if (next) {
return (next);
}
- /* look for a sibling */
+ /* Look for a sibling */
next = op->common.next;
if (next) {
return (next);
}
- /* look for a sibling of parent */
+ /* Look for a sibling of parent */
parent = op->common.parent;
@@ -305,13 +243,13 @@ acpi_ps_get_depth_next (
}
if (arg == origin) {
- /* reached parent of origin, end search */
+ /* Reached parent of origin, end search */
return (NULL);
}
if (parent->common.next) {
- /* found sibling of parent */
+ /* Found sibling of parent */
return (parent->common.next);
}
@@ -323,5 +261,74 @@ acpi_ps_get_depth_next (
return (next);
}
+
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ps_get_child
+ *
+ * PARAMETERS: Op - Get the child of this Op
+ *
+ * RETURN: Child Op, Null if none is found.
+ *
+ * DESCRIPTION: Get op's children or NULL if none
+ *
+ ******************************************************************************/
+
+union acpi_parse_object *
+acpi_ps_get_child (
+ union acpi_parse_object *op)
+{
+ union acpi_parse_object *child = NULL;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ switch (op->common.aml_opcode) {
+ case AML_SCOPE_OP:
+ case AML_ELSE_OP:
+ case AML_DEVICE_OP:
+ case AML_THERMAL_ZONE_OP:
+ case AML_INT_METHODCALL_OP:
+
+ child = acpi_ps_get_arg (op, 0);
+ break;
+
+
+ case AML_BUFFER_OP:
+ case AML_PACKAGE_OP:
+ case AML_METHOD_OP:
+ case AML_IF_OP:
+ case AML_WHILE_OP:
+ case AML_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 1);
+ break;
+
+
+ case AML_POWER_RES_OP:
+ case AML_INDEX_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 2);
+ break;
+
+
+ case AML_PROCESSOR_OP:
+ case AML_BANK_FIELD_OP:
+
+ child = acpi_ps_get_arg (op, 3);
+ break;
+
+
+ default:
+ /* All others have no children */
+ break;
+ }
+
+ return (child);
+}
+#endif
+
#endif /* ACPI_FUTURE_USAGE */
diff --git a/drivers/acpi/parser/psutils.c b/drivers/acpi/parser/psutils.c
index b3597cb19f88..a10f88715d43 100644
--- a/drivers/acpi/parser/psutils.c
+++ b/drivers/acpi/parser/psutils.c
@@ -45,7 +45,6 @@
#include <acpi/acpi.h>
#include <acpi/acparser.h>
#include <acpi/amlcode.h>
-#include <acpi/acnamesp.h>
#define _COMPONENT ACPI_PARSER
ACPI_MODULE_NAME ("psutils")
@@ -57,7 +56,7 @@
*
* PARAMETERS: None
*
- * RETURN: scope_op
+ * RETURN: A new Scope object, null on failure
*
* DESCRIPTION: Create a Scope and associated namepath op with the root name
*
@@ -75,7 +74,6 @@ acpi_ps_create_scope_op (
return (NULL);
}
-
scope_op->named.name = ACPI_ROOT_NAME;
return (scope_op);
}
@@ -88,10 +86,9 @@ acpi_ps_create_scope_op (
* PARAMETERS: Op - A newly allocated Op object
* Opcode - Opcode to store in the Op
*
- * RETURN: Status
+ * RETURN: None
*
- * DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
- * opcode
+ * DESCRIPTION: Initialize a parse (Op) object
*
******************************************************************************/
@@ -107,7 +104,8 @@ acpi_ps_init_op (
op->common.aml_opcode = opcode;
ACPI_DISASM_ONLY_MEMBERS (ACPI_STRNCPY (op->common.aml_op_name,
- (acpi_ps_get_opcode_info (opcode))->name, sizeof (op->common.aml_op_name)));
+ (acpi_ps_get_opcode_info (opcode))->name,
+ sizeof (op->common.aml_op_name)));
}
@@ -117,7 +115,7 @@ acpi_ps_init_op (
*
* PARAMETERS: Opcode - Opcode that will be stored in the new Op
*
- * RETURN: Pointer to the new Op.
+ * RETURN: Pointer to the new Op, null on failure
*
* DESCRIPTION: Allocate an acpi_op, choose op type (and thus size) based on
* opcode. A cache of opcodes is available for the pure
@@ -275,7 +273,6 @@ acpi_ps_get_name (
union acpi_parse_object *op)
{
-
/* The "generic" object has no name associated with it */
if (op->common.flags & ACPI_PARSEOP_GENERIC) {
diff --git a/drivers/acpi/parser/pswalk.c b/drivers/acpi/parser/pswalk.c
index 110d2ce917b6..9d20cb2ceb51 100644
--- a/drivers/acpi/parser/pswalk.c
+++ b/drivers/acpi/parser/pswalk.c
@@ -90,17 +90,15 @@ acpi_ps_delete_parse_tree (
}
}
- /*
- * No more children, this Op is complete.
- */
+ /* No more children, this Op is complete. */
+
next = op->common.next;
parent = op->common.parent;
acpi_ps_free_op (op);
- /*
- * If we are back to the starting point, the walk is complete.
- */
+ /* If we are back to the starting point, the walk is complete. */
+
if (op == subtree_root) {
return_VOID;
}
@@ -111,5 +109,6 @@ acpi_ps_delete_parse_tree (
op = parent;
}
}
+
return_VOID;
}
diff --git a/drivers/acpi/parser/psxface.c b/drivers/acpi/parser/psxface.c
index b318ad24726d..dba893648e84 100644
--- a/drivers/acpi/parser/psxface.c
+++ b/drivers/acpi/parser/psxface.c
@@ -57,13 +57,16 @@
*
* FUNCTION: acpi_psx_execute
*
- * PARAMETERS: Info->Node - A method object containing both the AML
- * address and length.
- * **Params - List of parameters to pass to method,
+ * PARAMETERS: Info - Method info block, contains:
+ * Node - Method Node to execute
+ * Parameters - List of parameters to pass to the method,
* terminated by NULL. Params itself may be
* NULL if no parameters are being passed.
- * **return_obj_desc - Return object from execution of the
- * method.
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
+ * parameter_type - Type of Parameter list
+ * return_object - Where to put method's return value (if
+ * any). If NULL, no value is returned.
*
* RETURN: Status
*
@@ -196,9 +199,8 @@ acpi_psx_execute (
goto cleanup3;
}
- /*
- * The walk of the parse tree is where we actually execute the method
- */
+ /* The walk of the parse tree is where we actually execute the method */
+
status = acpi_ps_parse_aml (walk_state);
goto cleanup2; /* Walk state already deleted */
@@ -217,7 +219,8 @@ cleanup1:
for (i = 0; info->parameters[i]; i++) {
/* Ignore errors, just do them all */
- (void) acpi_ut_update_object_reference (info->parameters[i], REF_DECREMENT);
+ (void) acpi_ut_update_object_reference (
+ info->parameters[i], REF_DECREMENT);
}
}
diff --git a/drivers/acpi/pci_bind.c b/drivers/acpi/pci_bind.c
index 5d19b39e9e2b..5148f3c10b5c 100644
--- a/drivers/acpi/pci_bind.c
+++ b/drivers/acpi/pci_bind.c
@@ -61,15 +61,14 @@ acpi_pci_data_handler (
/**
- * acpi_os_get_pci_id
+ * acpi_get_pci_id
* ------------------
* This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
* to resolve PCI information for ACPI-PCI devices defined in the namespace.
* This typically occurs when resolving PCI operation region information.
*/
-#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_os_get_pci_id (
+acpi_get_pci_id (
acpi_handle handle,
struct acpi_pci_id *id)
{
@@ -78,7 +77,7 @@ acpi_os_get_pci_id (
struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL;
- ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
+ ACPI_FUNCTION_TRACE("acpi_get_pci_id");
if (!id)
return_ACPI_STATUS(AE_BAD_PARAMETER);
@@ -92,7 +91,7 @@ acpi_os_get_pci_id (
}
status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
- if (ACPI_FAILURE(status) || !data || !data->dev) {
+ if (ACPI_FAILURE(status) || !data) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI-PCI context for device %s\n",
acpi_device_bid(device)));
@@ -115,7 +114,7 @@ acpi_os_get_pci_id (
return_ACPI_STATUS(AE_OK);
}
-#endif /* ACPI_FUTURE_USAGE */
+EXPORT_SYMBOL(acpi_get_pci_id);
int
@@ -129,6 +128,8 @@ acpi_pci_bind (
char *pathname = NULL;
struct acpi_buffer buffer = {0, NULL};
acpi_handle handle = NULL;
+ struct pci_dev *dev;
+ struct pci_bus *bus;
ACPI_FUNCTION_TRACE("acpi_pci_bind");
@@ -193,8 +194,20 @@ acpi_pci_bind (
* Locate matching device in PCI namespace. If it doesn't exist
* this typically means that the device isn't currently inserted
* (e.g. docking station, port replicator, etc.).
+ * We cannot simply search the global pci device list, since
+ * PCI devices are added to the global pci list when the root
+ * bridge start ops are run, which may not have happened yet.
*/
- data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function));
+ bus = pci_find_bus(data->id.segment, data->id.bus);
+ if (bus) {
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (dev->devfn == PCI_DEVFN(data->id.device,
+ data->id.function)) {
+ data->dev = dev;
+ break;
+ }
+ }
+ }
if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 8093f2e00321..d1f42b972821 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -433,8 +433,9 @@ acpi_pci_irq_enable (
printk(KERN_WARNING PREFIX "PCI Interrupt %s[%c]: no GSI",
pci_name(dev), ('A' + pin));
/* Interrupt Line values above 0xF are forbidden */
- if (dev->irq >= 0 && (dev->irq <= 0xF)) {
+ if (dev->irq > 0 && (dev->irq <= 0xF)) {
printk(" - using IRQ %d\n", dev->irq);
+ acpi_register_gsi(dev->irq, ACPI_LEVEL_SENSITIVE, ACPI_ACTIVE_LOW);
return_VALUE(0);
}
else {
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index 520b28ad0740..6ad0e77df9b3 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -72,10 +72,12 @@ struct acpi_pci_link_irq {
u8 active; /* Current IRQ */
u8 edge_level; /* All IRQs */
u8 active_high_low; /* All IRQs */
- u8 initialized;
u8 resource_type;
u8 possible_count;
u8 possible[ACPI_PCI_LINK_MAX_POSSIBLE];
+ u8 initialized:1;
+ u8 suspend_resume:1;
+ u8 reserved:6;
};
struct acpi_pci_link {
@@ -530,6 +532,10 @@ static int acpi_pci_link_allocate(
ACPI_FUNCTION_TRACE("acpi_pci_link_allocate");
+ if (link->irq.suspend_resume) {
+ acpi_pci_link_set(link, link->irq.active);
+ link->irq.suspend_resume = 0;
+ }
if (link->irq.initialized)
return_VALUE(0);
@@ -713,38 +719,24 @@ end:
return_VALUE(result);
}
-
-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)
+irqrouter_suspend(
+ struct sys_device *dev,
+ u32 state)
{
struct list_head *node = NULL;
struct acpi_pci_link *link = NULL;
- ACPI_FUNCTION_TRACE("irqrouter_resume");
+ ACPI_FUNCTION_TRACE("irqrouter_suspend");
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);
+ if (link->irq.active && link->irq.initialized)
+ link->irq.suspend_resume = 1;
}
return_VALUE(0);
}
@@ -812,9 +804,12 @@ static int __init acpi_irq_penalty_update(char *str, int used)
* There is no ISA_POSSIBLE weight, so we simply use
* the (small) PCI_USING penalty.
*/
-void acpi_penalize_isa_irq(int irq)
+void acpi_penalize_isa_irq(int irq, int active)
{
- acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
+ if (active)
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_ISA_USED;
+ else
+ acpi_irq_penalty[irq] += PIRQ_PENALTY_PCI_USING;
}
/*
@@ -856,7 +851,7 @@ __setup("acpi_irq_balance", acpi_irq_balance_set);
static struct sysdev_class irqrouter_sysdev_class = {
set_kset_name("irqrouter"),
- .resume = irqrouter_resume,
+ .suspend = irqrouter_suspend,
};
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 7e6b8e3b2ed4..5d2f77fcd50c 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root")
static int acpi_pci_root_add (struct acpi_device *device);
static int acpi_pci_root_remove (struct acpi_device *device, int type);
+static int acpi_pci_root_start (struct acpi_device *device);
static struct acpi_driver acpi_pci_root_driver = {
.name = ACPI_PCI_ROOT_DRIVER_NAME,
@@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = {
.ops = {
.add = acpi_pci_root_add,
.remove = acpi_pci_root_remove,
+ .start = acpi_pci_root_start,
},
};
@@ -169,6 +171,7 @@ acpi_pci_root_add (
if (!root)
return_VALUE(-ENOMEM);
memset(root, 0, sizeof(struct acpi_pci_root));
+ INIT_LIST_HEAD(&root->node);
root->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
@@ -298,12 +301,31 @@ acpi_pci_root_add (
root->id.bus);
end:
- if (result)
+ if (result) {
+ if (!list_empty(&root->node))
+ list_del(&root->node);
kfree(root);
+ }
return_VALUE(result);
}
+static int
+acpi_pci_root_start (
+ struct acpi_device *device)
+{
+ struct acpi_pci_root *root;
+
+ ACPI_FUNCTION_TRACE("acpi_pci_root_start");
+
+ list_for_each_entry(root, &acpi_pci_roots, node) {
+ if (root->handle == device->handle) {
+ pci_bus_add_devices(root->bus);
+ return_VALUE(0);
+ }
+ }
+ return_VALUE(-ENODEV);
+}
static int
acpi_pci_root_remove (
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index f4778747e889..d56a439ac614 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -256,6 +256,43 @@ acpi_processor_errata (
/* --------------------------------------------------------------------------
+ Common ACPI processor fucntions
+ -------------------------------------------------------------------------- */
+
+/*
+ * _PDC is required for a BIOS-OS handshake for most of the newer
+ * ACPI processor features.
+ */
+
+int acpi_processor_set_pdc(struct acpi_processor *pr,
+ struct acpi_object_list *pdc_in)
+{
+ acpi_status status = AE_OK;
+ u32 arg0_buf[3];
+ union acpi_object arg0 = {ACPI_TYPE_BUFFER};
+ struct acpi_object_list no_object = {1, &arg0};
+ struct acpi_object_list *pdc;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
+
+ arg0.buffer.length = 12;
+ arg0.buffer.pointer = (u8 *) arg0_buf;
+ arg0_buf[0] = ACPI_PDC_REVISION_ID;
+ arg0_buf[1] = 0;
+ arg0_buf[2] = 0;
+
+ pdc = (pdc_in) ? pdc_in : &no_object;
+
+ status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL);
+
+ if ((ACPI_FAILURE(status)) && (pdc_in))
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n"));
+
+ return_VALUE(status);
+}
+
+
+/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
@@ -723,7 +760,7 @@ int acpi_processor_device_add(
return_VALUE(-ENODEV);
}
- acpi_bus_scan(*device);
+ acpi_bus_start(*device);
pr = acpi_driver_data(*device);
if (!pr)
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index c9d671cf7857..893b074e3d1a 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -6,6 +6,8 @@
* Copyright (C) 2004 Dominik Brodowski <linux@brodo.de>
* Copyright (C) 2004 Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com>
* - Added processor hotplug support
+ * Copyright (C) 2005 Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
+ * - Added support for C3 on SMP
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
@@ -142,7 +144,7 @@ acpi_processor_power_activate (
switch (old->type) {
case ACPI_STATE_C3:
/* Disable bus master reload */
- if (new->type != ACPI_STATE_C3)
+ if (new->type != ACPI_STATE_C3 && pr->flags.bm_check)
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 0, ACPI_MTX_DO_NOT_LOCK);
break;
}
@@ -152,7 +154,7 @@ acpi_processor_power_activate (
switch (new->type) {
case ACPI_STATE_C3:
/* Enable bus master reload */
- if (old->type != ACPI_STATE_C3)
+ if (old->type != ACPI_STATE_C3 && pr->flags.bm_check)
acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD, 1, ACPI_MTX_DO_NOT_LOCK);
break;
}
@@ -163,6 +165,9 @@ acpi_processor_power_activate (
}
+static atomic_t c3_cpu_count;
+
+
static void acpi_processor_idle (void)
{
struct acpi_processor *pr = NULL;
@@ -297,8 +302,22 @@ static void acpi_processor_idle (void)
break;
case ACPI_STATE_C3:
- /* Disable bus master arbitration */
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
+
+ if (pr->flags.bm_check) {
+ if (atomic_inc_return(&c3_cpu_count) ==
+ num_online_cpus()) {
+ /*
+ * All CPUs are trying to go to C3
+ * Disable bus master arbitration
+ */
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1,
+ ACPI_MTX_DO_NOT_LOCK);
+ }
+ } else {
+ /* SMP with no shared cache... Invalidate cache */
+ ACPI_FLUSH_CPU_CACHE();
+ }
+
/* Get start time (ticks) */
t1 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Invoke C3 */
@@ -307,8 +326,12 @@ static void acpi_processor_idle (void)
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
/* Get end time (ticks) */
t2 = inl(acpi_fadt.xpm_tmr_blk.address);
- /* Enable bus master arbitration */
- acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK);
+ if (pr->flags.bm_check) {
+ /* Enable bus master arbitration */
+ atomic_dec(&c3_cpu_count);
+ acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0, ACPI_MTX_DO_NOT_LOCK);
+ }
+
/* Re-enable interrupts */
local_irq_enable();
/* Compute time (ticks) that we were actually asleep */
@@ -519,6 +542,29 @@ static int acpi_processor_get_power_info_fadt (struct acpi_processor *pr)
}
+static int acpi_processor_get_power_info_default_c1 (struct acpi_processor *pr)
+{
+ int i;
+
+ ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_default_c1");
+
+ for (i = 0; i < ACPI_PROCESSOR_MAX_POWER; i++)
+ memset(pr->power.states, 0, sizeof(struct acpi_processor_cx));
+
+ /* if info is obtained from pblk/fadt, type equals state */
+ pr->power.states[ACPI_STATE_C1].type = ACPI_STATE_C1;
+ pr->power.states[ACPI_STATE_C2].type = ACPI_STATE_C2;
+ pr->power.states[ACPI_STATE_C3].type = ACPI_STATE_C3;
+
+ /* the C0 state only exists as a filler in our array,
+ * and all processors need to support C1 */
+ pr->power.states[ACPI_STATE_C0].valid = 1;
+ pr->power.states[ACPI_STATE_C1].valid = 1;
+
+ return_VALUE(0);
+}
+
+
static int acpi_processor_get_power_info_cst (struct acpi_processor *pr)
{
acpi_status status = 0;
@@ -529,9 +575,6 @@ static int acpi_processor_get_power_info_cst (struct acpi_processor *pr)
ACPI_FUNCTION_TRACE("acpi_processor_get_power_info_cst");
- if (errata.smp)
- return_VALUE(-ENODEV);
-
if (nocst)
return_VALUE(-ENODEV);
@@ -664,13 +707,6 @@ static void acpi_processor_power_verify_c2(struct acpi_processor_cx *cx)
return_VOID;
}
- /* We're (currently) only supporting C2 on UP */
- else if (errata.smp) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C2 not supported in SMP mode\n"));
- return_VOID;
- }
-
/*
* Otherwise we've met all of our C2 requirements.
* Normalize the C2 latency to expidite policy
@@ -686,6 +722,8 @@ static void acpi_processor_power_verify_c3(
struct acpi_processor *pr,
struct acpi_processor_cx *cx)
{
+ static int bm_check_flag;
+
ACPI_FUNCTION_TRACE("acpi_processor_get_power_verify_c3");
if (!cx->address)
@@ -702,20 +740,6 @@ static void acpi_processor_power_verify_c3(
return_VOID;
}
- /* bus mastering control is necessary */
- else if (!pr->flags.bm_control) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 support requires bus mastering control\n"));
- return_VOID;
- }
-
- /* We're (currently) only supporting C2 on UP */
- else if (errata.smp) {
- ACPI_DEBUG_PRINT((ACPI_DB_INFO,
- "C3 not supported in SMP mode\n"));
- return_VOID;
- }
-
/*
* PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
* DMA transfers are used by any ISA device to avoid livelock.
@@ -729,6 +753,39 @@ static void acpi_processor_power_verify_c3(
return_VOID;
}
+ /* All the logic here assumes flags.bm_check is same across all CPUs */
+ if (!bm_check_flag) {
+ /* Determine whether bm_check is needed based on CPU */
+ acpi_processor_power_init_bm_check(&(pr->flags), pr->id);
+ bm_check_flag = pr->flags.bm_check;
+ } else {
+ pr->flags.bm_check = bm_check_flag;
+ }
+
+ if (pr->flags.bm_check) {
+ printk("Disabling BM access before entering C3\n");
+ /* bus mastering control is necessary */
+ if (!pr->flags.bm_control) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "C3 support requires bus mastering control\n"));
+ return_VOID;
+ }
+ } else {
+ printk("Invalidating cache before entering C3\n");
+ /*
+ * WBINVD should be set in fadt, for C3 state to be
+ * supported on when bm_check is not required.
+ */
+ if (acpi_fadt.wb_invd != 1) {
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+ "Cache invalidation should work properly"
+ " for C3 to be enabled on SMP systems\n"));
+ return_VOID;
+ }
+ acpi_set_register(ACPI_BITREG_BUS_MASTER_RLD,
+ 0, ACPI_MTX_DO_NOT_LOCK);
+ }
+
/*
* Otherwise we've met all of our C3 requirements.
* Normalize the C3 latency to expidite policy. Enable
@@ -737,7 +794,6 @@ static void acpi_processor_power_verify_c3(
*/
cx->valid = 1;
cx->latency_ticks = US_TO_PM_TIMER_TICKS(cx->latency);
- pr->flags.bm_check = 1;
return_VOID;
}
@@ -787,10 +843,7 @@ static int acpi_processor_get_power_info (
if ((result) || (acpi_processor_power_verify(pr) < 2)) {
result = acpi_processor_get_power_info_fadt(pr);
if (result)
- return_VALUE(result);
-
- if (acpi_processor_power_verify(pr) < 2)
- return_VALUE(-ENODEV);
+ result = acpi_processor_get_power_info_default_c1(pr);
}
/*
@@ -810,11 +863,10 @@ static int acpi_processor_get_power_info (
* CPU as being "idle manageable"
*/
for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
- if (pr->power.states[i].valid)
+ if (pr->power.states[i].valid) {
pr->power.count = i;
- if ((pr->power.states[i].valid) &&
- (pr->power.states[i].type >= ACPI_STATE_C2))
pr->flags.power = 1;
+ }
}
return_VALUE(0);
@@ -829,7 +881,7 @@ int acpi_processor_cst_has_changed (struct acpi_processor *pr)
if (!pr)
return_VALUE(-EINVAL);
- if (errata.smp || nocst) {
+ if ( nocst) {
return_VALUE(-ENODEV);
}
@@ -929,7 +981,6 @@ static struct file_operations acpi_processor_power_fops = {
.release = single_release,
};
-
int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *device)
{
acpi_status status = 0;
@@ -946,7 +997,10 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev
first_run++;
}
- if (!errata.smp && (pr->id == 0) && acpi_fadt.cst_cnt && !nocst) {
+ if (!pr)
+ return_VALUE(-EINVAL);
+
+ if (acpi_fadt.cst_cnt && !nocst) {
status = acpi_os_write_port(acpi_fadt.smi_cmd, acpi_fadt.cst_cnt, 8);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
@@ -954,6 +1008,8 @@ int acpi_processor_power_init(struct acpi_processor *pr, struct acpi_device *dev
}
}
+ acpi_processor_power_init_pdc(&(pr->power), pr->id);
+ acpi_processor_set_pdc(pr, pr->power.pdc);
acpi_processor_get_power_info(pr);
/*
diff --git a/drivers/acpi/processor_perflib.c b/drivers/acpi/processor_perflib.c
index a9a1a8fe3199..1f0d6256302f 100644
--- a/drivers/acpi/processor_perflib.c
+++ b/drivers/acpi/processor_perflib.c
@@ -165,37 +165,6 @@ void acpi_processor_ppc_exit(void) {
acpi_processor_ppc_status &= ~PPC_REGISTERED;
}
-/*
- * when registering a cpufreq driver with this ACPI processor driver, the
- * _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;
- u32 arg0_buf[3];
- union acpi_object arg0 = {ACPI_TYPE_BUFFER};
- struct acpi_object_list no_object = {1, &arg0};
- struct acpi_object_list *pdc;
-
- ACPI_FUNCTION_TRACE("acpi_processor_set_pdc");
-
- arg0.buffer.length = 12;
- arg0.buffer.pointer = (u8 *) arg0_buf;
- arg0_buf[0] = ACPI_PDC_REVISION_ID;
- arg0_buf[1] = 0;
- arg0_buf[2] = 0;
-
- pdc = (pr->performance->pdc) ? pr->performance->pdc : &no_object;
-
- status = acpi_evaluate_object(pr->handle, "_PDC", pdc, NULL);
-
- if ((ACPI_FAILURE(status)) && (pr->performance->pdc))
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PDC, using legacy perf. control...\n"));
-
- return_VALUE(status);
-}
-
static int
acpi_processor_get_performance_control (
@@ -357,7 +326,7 @@ acpi_processor_get_performance_info (
if (!pr || !pr->performance || !pr->handle)
return_VALUE(-EINVAL);
- acpi_processor_set_pdc(pr);
+ acpi_processor_set_pdc(pr, pr->performance->pdc);
status = acpi_get_handle(pr->handle, "_PCT", &handle);
if (ACPI_FAILURE(status)) {
diff --git a/drivers/acpi/resources/rsaddr.c b/drivers/acpi/resources/rsaddr.c
index 4788c079735d..55d264771c48 100644
--- a/drivers/acpi/resources/rsaddr.c
+++ b/drivers/acpi/resources/rsaddr.c
@@ -77,21 +77,21 @@ acpi_rs_address16_resource (
u8 **output_buffer,
acpi_size *structure_size)
{
- u8 *buffer = byte_stream_buffer;
- struct acpi_resource *output_struct = (void *) *output_buffer;
- u8 *temp_ptr;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16);
u32 index;
u16 temp16;
u8 temp8;
+ u8 *temp_ptr;
+ u8 *buffer = byte_stream_buffer;
+ struct acpi_resource *output_struct = (void *) *output_buffer;
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_address16);
ACPI_FUNCTION_TRACE ("rs_address16_resource");
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -104,9 +104,8 @@ acpi_rs_address16_resource (
*bytes_consumed = temp16 + 3;
output_struct->id = ACPI_RSTYPE_ADDRESS16;
- /*
- * Get the Resource Type (Byte3)
- */
+ /* Get the Resource Type (Byte3) */
+
buffer += 2;
temp8 = *buffer;
@@ -118,9 +117,8 @@ acpi_rs_address16_resource (
output_struct->data.address16.resource_type = temp8;
- /*
- * Get the General Flags (Byte4)
- */
+ /* Get the General Flags (Byte4) */
+
buffer += 1;
temp8 = *buffer;
@@ -140,9 +138,8 @@ acpi_rs_address16_resource (
output_struct->data.address16.max_address_fixed = (temp8 >> 3) & 0x01;
- /*
- * Get the Type Specific Flags (Byte5)
- */
+ /* Get the Type Specific Flags (Byte5) */
+
buffer += 1;
temp8 = *buffer;
@@ -165,39 +162,34 @@ acpi_rs_address16_resource (
}
}
- /*
- * Get Granularity (Bytes 6-7)
- */
+ /* Get Granularity (Bytes 6-7) */
+
buffer += 1;
ACPI_MOVE_16_TO_32 (&output_struct->data.address16.granularity, buffer);
- /*
- * Get min_address_range (Bytes 8-9)
- */
+ /* Get min_address_range (Bytes 8-9) */
+
buffer += 2;
ACPI_MOVE_16_TO_32 (&output_struct->data.address16.min_address_range, buffer);
- /*
- * Get max_address_range (Bytes 10-11)
- */
+ /* Get max_address_range (Bytes 10-11) */
+
buffer += 2;
ACPI_MOVE_16_TO_32 (&output_struct->data.address16.max_address_range, buffer);
- /*
- * Get address_translation_offset (Bytes 12-13)
- */
+ /* Get address_translation_offset (Bytes 12-13) */
+
buffer += 2;
- ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset, buffer);
+ ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_translation_offset,
+ buffer);
+
+ /* Get address_length (Bytes 14-15) */
- /*
- * Get address_length (Bytes 14-15)
- */
buffer += 2;
ACPI_MOVE_16_TO_32 (&output_struct->data.address16.address_length, buffer);
- /*
- * Resource Source Index (if present)
- */
+ /* Resource Source Index (if present) */
+
buffer += 2;
/*
@@ -225,7 +217,8 @@ acpi_rs_address16_resource (
output_struct->data.address16.resource_source.string_ptr =
(char *)((u8 * )output_struct + struct_size);
- temp_ptr = (u8 *) output_struct->data.address16.resource_source.string_ptr;
+ temp_ptr = (u8 *)
+ output_struct->data.address16.resource_source.string_ptr;
/* Copy the string into the buffer */
@@ -239,9 +232,8 @@ acpi_rs_address16_resource (
index += 1;
}
- /*
- * Add the terminating null
- */
+ /* Add the terminating null */
+
*temp_ptr = 0x00;
output_struct->data.address16.resource_source.string_length = index + 1;
@@ -260,14 +252,12 @@ acpi_rs_address16_resource (
output_struct->data.address16.resource_source.string_ptr = NULL;
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -305,28 +295,24 @@ acpi_rs_address16_stream (
ACPI_FUNCTION_TRACE ("rs_address16_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x88;
buffer += 1;
- /*
- * Save a pointer to the Length field - to be filled in later
- */
+ /* Save a pointer to the Length field - to be filled in later */
+
length_field = buffer;
buffer += 2;
- /*
- * Set the Resource Type (Memory, Io, bus_number)
- */
+ /* Set the Resource Type (Memory, Io, bus_number) */
+
temp8 = (u8) (linked_list->data.address16.resource_type & 0x03);
*buffer = temp8;
buffer += 1;
- /*
- * Set the general flags
- */
+ /* Set the general flags */
+
temp8 = (u8) (linked_list->data.address16.producer_consumer & 0x01);
temp8 |= (linked_list->data.address16.decode & 0x01) << 1;
@@ -336,9 +322,8 @@ acpi_rs_address16_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the type specific flags
- */
+ /* Set the type specific flags */
+
temp8 = 0;
if (ACPI_MEMORY_RANGE == linked_list->data.address16.resource_type) {
@@ -362,39 +347,34 @@ acpi_rs_address16_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the address space granularity
- */
+ /* Set the address space granularity */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.granularity);
buffer += 2;
- /*
- * Set the address range minimum
- */
+ /* Set the address range minimum */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.min_address_range);
buffer += 2;
- /*
- * Set the address range maximum
- */
+ /* Set the address range maximum */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.max_address_range);
buffer += 2;
- /*
- * Set the address translation offset
- */
- ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_translation_offset);
+ /* Set the address translation offset */
+
+ ACPI_MOVE_32_TO_16 (buffer,
+ &linked_list->data.address16.address_translation_offset);
buffer += 2;
- /*
- * Set the address length
- */
+ /* Set the address length */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.address16.address_length);
buffer += 2;
- /*
- * Resource Source Index and Resource Source are optional
- */
+ /* Resource Source Index and Resource Source are optional */
+
if (0 != linked_list->data.address16.resource_source.string_length) {
temp8 = (u8) linked_list->data.address16.resource_source.index;
@@ -403,9 +383,8 @@ acpi_rs_address16_stream (
temp_pointer = (char *) buffer;
- /*
- * Copy the string
- */
+ /* Copy the string */
+
ACPI_STRCPY (temp_pointer,
linked_list->data.address16.resource_source.string_ptr);
@@ -413,12 +392,12 @@ acpi_rs_address16_stream (
* Buffer needs to be set to the length of the sting + one for the
* terminating null
*/
- buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address16.resource_source.string_ptr) + 1);
+ buffer += (acpi_size)(ACPI_STRLEN (
+ linked_list->data.address16.resource_source.string_ptr) + 1);
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
actual_bytes = ACPI_PTR_DIFF (buffer, *output_buffer);
*bytes_consumed = actual_bytes;
@@ -475,9 +454,8 @@ acpi_rs_address32_resource (
buffer = byte_stream_buffer;
struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32);
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -490,9 +468,8 @@ acpi_rs_address32_resource (
*bytes_consumed = temp16 + 3;
output_struct->id = ACPI_RSTYPE_ADDRESS32;
- /*
- * Get the Resource Type (Byte3)
- */
+ /* Get the Resource Type (Byte3) */
+
buffer += 2;
temp8 = *buffer;
@@ -504,35 +481,29 @@ acpi_rs_address32_resource (
output_struct->data.address32.resource_type = temp8;
- /*
- * Get the General Flags (Byte4)
- */
+ /* Get the General Flags (Byte4) */
+
buffer += 1;
temp8 = *buffer;
- /*
- * Producer / Consumer
- */
+ /* Producer / Consumer */
+
output_struct->data.address32.producer_consumer = temp8 & 0x01;
- /*
- * Decode
- */
+ /* Decode */
+
output_struct->data.address32.decode = (temp8 >> 1) & 0x01;
- /*
- * Min Address Fixed
- */
+ /* Min Address Fixed */
+
output_struct->data.address32.min_address_fixed = (temp8 >> 2) & 0x01;
- /*
- * Max Address Fixed
- */
+ /* Max Address Fixed */
+
output_struct->data.address32.max_address_fixed = (temp8 >> 3) & 0x01;
- /*
- * Get the Type Specific Flags (Byte5)
- */
+ /* Get the Type Specific Flags (Byte5) */
+
buffer += 1;
temp8 = *buffer;
@@ -556,39 +527,34 @@ acpi_rs_address32_resource (
}
}
- /*
- * Get Granularity (Bytes 6-9)
- */
+ /* Get Granularity (Bytes 6-9) */
+
buffer += 1;
ACPI_MOVE_32_TO_32 (&output_struct->data.address32.granularity, buffer);
- /*
- * Get min_address_range (Bytes 10-13)
- */
+ /* Get min_address_range (Bytes 10-13) */
+
buffer += 4;
ACPI_MOVE_32_TO_32 (&output_struct->data.address32.min_address_range, buffer);
- /*
- * Get max_address_range (Bytes 14-17)
- */
+ /* Get max_address_range (Bytes 14-17) */
+
buffer += 4;
ACPI_MOVE_32_TO_32 (&output_struct->data.address32.max_address_range, buffer);
- /*
- * Get address_translation_offset (Bytes 18-21)
- */
+ /* Get address_translation_offset (Bytes 18-21) */
+
buffer += 4;
- ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset, buffer);
+ ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_translation_offset,
+ buffer);
+
+ /* Get address_length (Bytes 22-25) */
- /*
- * Get address_length (Bytes 22-25)
- */
buffer += 4;
ACPI_MOVE_32_TO_32 (&output_struct->data.address32.address_length, buffer);
- /*
- * Resource Source Index (if present)
- */
+ /* Resource Source Index (if present) */
+
buffer += 4;
/*
@@ -615,7 +581,8 @@ acpi_rs_address32_resource (
output_struct->data.address32.resource_source.string_ptr =
(char *)((u8 *)output_struct + struct_size);
- temp_ptr = (u8 *) output_struct->data.address32.resource_source.string_ptr;
+ temp_ptr = (u8 *)
+ output_struct->data.address32.resource_source.string_ptr;
/* Copy the string into the buffer */
@@ -628,9 +595,8 @@ acpi_rs_address32_resource (
index += 1;
}
- /*
- * Add the terminating null
- */
+ /* Add the terminating null */
+
*temp_ptr = 0x00;
output_struct->data.address32.resource_source.string_length = index + 1;
@@ -648,14 +614,12 @@ acpi_rs_address32_resource (
output_struct->data.address32.resource_source.string_ptr = NULL;
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -694,29 +658,25 @@ acpi_rs_address32_stream (
buffer = *output_buffer;
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x87;
buffer += 1;
- /*
- * Set a pointer to the Length field - to be filled in later
- */
+ /* Set a pointer to the Length field - to be filled in later */
+
length_field = ACPI_CAST_PTR (u16, buffer);
buffer += 2;
- /*
- * Set the Resource Type (Memory, Io, bus_number)
- */
+ /* Set the Resource Type (Memory, Io, bus_number) */
+
temp8 = (u8) (linked_list->data.address32.resource_type & 0x03);
*buffer = temp8;
buffer += 1;
- /*
- * Set the general flags
- */
+ /* Set the general flags */
+
temp8 = (u8) (linked_list->data.address32.producer_consumer & 0x01);
temp8 |= (linked_list->data.address32.decode & 0x01) << 1;
temp8 |= (linked_list->data.address32.min_address_fixed & 0x01) << 2;
@@ -725,9 +685,8 @@ acpi_rs_address32_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the type specific flags
- */
+ /* Set the type specific flags */
+
temp8 = 0;
if (ACPI_MEMORY_RANGE == linked_list->data.address32.resource_type) {
@@ -751,39 +710,34 @@ acpi_rs_address32_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the address space granularity
- */
+ /* Set the address space granularity */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.granularity);
buffer += 4;
- /*
- * Set the address range minimum
- */
+ /* Set the address range minimum */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.min_address_range);
buffer += 4;
- /*
- * Set the address range maximum
- */
+ /* Set the address range maximum */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.max_address_range);
buffer += 4;
- /*
- * Set the address translation offset
- */
- ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_translation_offset);
+ /* Set the address translation offset */
+
+ ACPI_MOVE_32_TO_32 (buffer,
+ &linked_list->data.address32.address_translation_offset);
buffer += 4;
- /*
- * Set the address length
- */
+ /* Set the address length */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.address32.address_length);
buffer += 4;
- /*
- * Resource Source Index and Resource Source are optional
- */
+ /* Resource Source Index and Resource Source are optional */
+
if (0 != linked_list->data.address32.resource_source.string_length) {
temp8 = (u8) linked_list->data.address32.resource_source.index;
@@ -792,9 +746,8 @@ acpi_rs_address32_stream (
temp_pointer = (char *) buffer;
- /*
- * Copy the string
- */
+ /* Copy the string */
+
ACPI_STRCPY (temp_pointer,
linked_list->data.address32.resource_source.string_ptr);
@@ -802,12 +755,12 @@ acpi_rs_address32_stream (
* Buffer needs to be set to the length of the sting + one for the
* terminating null
*/
- buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address32.resource_source.string_ptr) + 1);
+ buffer += (acpi_size)(ACPI_STRLEN (
+ linked_list->data.address32.resource_source.string_ptr) + 1);
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
/*
@@ -864,9 +817,8 @@ acpi_rs_address64_resource (
struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64);
resource_type = *buffer;
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -879,9 +831,8 @@ acpi_rs_address64_resource (
*bytes_consumed = temp16 + 3;
output_struct->id = ACPI_RSTYPE_ADDRESS64;
- /*
- * Get the Resource Type (Byte3)
- */
+ /* Get the Resource Type (Byte3) */
+
buffer += 2;
temp8 = *buffer;
@@ -893,35 +844,29 @@ acpi_rs_address64_resource (
output_struct->data.address64.resource_type = temp8;
- /*
- * Get the General Flags (Byte4)
- */
+ /* Get the General Flags (Byte4) */
+
buffer += 1;
temp8 = *buffer;
- /*
- * Producer / Consumer
- */
+ /* Producer / Consumer */
+
output_struct->data.address64.producer_consumer = temp8 & 0x01;
- /*
- * Decode
- */
+ /* Decode */
+
output_struct->data.address64.decode = (temp8 >> 1) & 0x01;
- /*
- * Min Address Fixed
- */
+ /* Min Address Fixed */
+
output_struct->data.address64.min_address_fixed = (temp8 >> 2) & 0x01;
- /*
- * Max Address Fixed
- */
+ /* Max Address Fixed */
+
output_struct->data.address64.max_address_fixed = (temp8 >> 3) & 0x01;
- /*
- * Get the Type Specific Flags (Byte5)
- */
+ /* Get the Type Specific Flags (Byte5) */
+
buffer += 1;
temp8 = *buffer;
@@ -951,33 +896,29 @@ acpi_rs_address64_resource (
buffer += 2;
}
- /*
- * Get Granularity (Bytes 6-13) or (Bytes 8-15)
- */
+ /* Get Granularity (Bytes 6-13) or (Bytes 8-15) */
+
buffer += 1;
ACPI_MOVE_64_TO_64 (&output_struct->data.address64.granularity, buffer);
- /*
- * Get min_address_range (Bytes 14-21) or (Bytes 16-23)
- */
+ /* Get min_address_range (Bytes 14-21) or (Bytes 16-23) */
+
buffer += 8;
ACPI_MOVE_64_TO_64 (&output_struct->data.address64.min_address_range, buffer);
- /*
- * Get max_address_range (Bytes 22-29) or (Bytes 24-31)
- */
+ /* Get max_address_range (Bytes 22-29) or (Bytes 24-31) */
+
buffer += 8;
ACPI_MOVE_64_TO_64 (&output_struct->data.address64.max_address_range, buffer);
- /*
- * Get address_translation_offset (Bytes 30-37) or (Bytes 32-39)
- */
+ /* Get address_translation_offset (Bytes 30-37) or (Bytes 32-39) */
+
buffer += 8;
- ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset, buffer);
+ ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_translation_offset,
+ buffer);
+
+ /* Get address_length (Bytes 38-45) or (Bytes 40-47) */
- /*
- * Get address_length (Bytes 38-45) or (Bytes 40-47)
- */
buffer += 8;
ACPI_MOVE_64_TO_64 (&output_struct->data.address64.address_length, buffer);
@@ -989,14 +930,15 @@ acpi_rs_address64_resource (
/* Get type_specific_attribute (Bytes 48-55) */
buffer += 8;
- ACPI_MOVE_64_TO_64 (&output_struct->data.address64.type_specific_attributes, buffer);
+ ACPI_MOVE_64_TO_64 (
+ &output_struct->data.address64.type_specific_attributes,
+ buffer);
}
else {
output_struct->data.address64.type_specific_attributes = 0;
- /*
- * Resource Source Index (if present)
- */
+ /* Resource Source Index (if present) */
+
buffer += 8;
/*
@@ -1025,7 +967,8 @@ acpi_rs_address64_resource (
output_struct->data.address64.resource_source.string_ptr =
(char *)((u8 *)output_struct + struct_size);
- temp_ptr = (u8 *) output_struct->data.address64.resource_source.string_ptr;
+ temp_ptr = (u8 *)
+ output_struct->data.address64.resource_source.string_ptr;
/* Copy the string into the buffer */
@@ -1042,7 +985,8 @@ acpi_rs_address64_resource (
* Add the terminating null
*/
*temp_ptr = 0x00;
- output_struct->data.address64.resource_source.string_length = index + 1;
+ output_struct->data.address64.resource_source.string_length =
+ index + 1;
/*
* In order for the struct_size to fall on a 32-bit boundary,
@@ -1054,14 +998,12 @@ acpi_rs_address64_resource (
}
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -1100,29 +1042,25 @@ acpi_rs_address64_stream (
buffer = *output_buffer;
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x8A;
buffer += 1;
- /*
- * Set a pointer to the Length field - to be filled in later
- */
+ /* Set a pointer to the Length field - to be filled in later */
+
length_field = ACPI_CAST_PTR (u16, buffer);
buffer += 2;
- /*
- * Set the Resource Type (Memory, Io, bus_number)
- */
+ /* Set the Resource Type (Memory, Io, bus_number) */
+
temp8 = (u8) (linked_list->data.address64.resource_type & 0x03);
*buffer = temp8;
buffer += 1;
- /*
- * Set the general flags
- */
+ /* Set the general flags */
+
temp8 = (u8) (linked_list->data.address64.producer_consumer & 0x01);
temp8 |= (linked_list->data.address64.decode & 0x01) << 1;
temp8 |= (linked_list->data.address64.min_address_fixed & 0x01) << 2;
@@ -1131,9 +1069,8 @@ acpi_rs_address64_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the type specific flags
- */
+ /* Set the type specific flags */
+
temp8 = 0;
if (ACPI_MEMORY_RANGE == linked_list->data.address64.resource_type) {
@@ -1157,39 +1094,34 @@ acpi_rs_address64_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the address space granularity
- */
+ /* Set the address space granularity */
+
ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.granularity);
buffer += 8;
- /*
- * Set the address range minimum
- */
+ /* Set the address range minimum */
+
ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.min_address_range);
buffer += 8;
- /*
- * Set the address range maximum
- */
+ /* Set the address range maximum */
+
ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.max_address_range);
buffer += 8;
- /*
- * Set the address translation offset
- */
- ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_translation_offset);
+ /* Set the address translation offset */
+
+ ACPI_MOVE_64_TO_64 (buffer,
+ &linked_list->data.address64.address_translation_offset);
buffer += 8;
- /*
- * Set the address length
- */
+ /* Set the address length */
+
ACPI_MOVE_64_TO_64 (buffer, &linked_list->data.address64.address_length);
buffer += 8;
- /*
- * Resource Source Index and Resource Source are optional
- */
+ /* Resource Source Index and Resource Source are optional */
+
if (0 != linked_list->data.address64.resource_source.string_length) {
temp8 = (u8) linked_list->data.address64.resource_source.index;
@@ -1198,21 +1130,21 @@ acpi_rs_address64_stream (
temp_pointer = (char *) buffer;
- /*
- * Copy the string
- */
- ACPI_STRCPY (temp_pointer, linked_list->data.address64.resource_source.string_ptr);
+ /* Copy the string */
+
+ ACPI_STRCPY (temp_pointer,
+ linked_list->data.address64.resource_source.string_ptr);
/*
* Buffer needs to be set to the length of the sting + one for the
* terminating null
*/
- buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.address64.resource_source.string_ptr) + 1);
+ buffer += (acpi_size)(ACPI_STRLEN (
+ linked_list->data.address64.resource_source.string_ptr) + 1);
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
/*
diff --git a/drivers/acpi/resources/rscalc.c b/drivers/acpi/resources/rscalc.c
index 8a5f0a52371d..98176f2fcb5d 100644
--- a/drivers/acpi/resources/rscalc.c
+++ b/drivers/acpi/resources/rscalc.c
@@ -81,9 +81,8 @@ acpi_rs_get_byte_stream_length (
while (!done) {
- /*
- * Init the variable that will hold the size to add to the total.
- */
+ /* Init the variable that will hold the size to add to the total. */
+
segment_size = 0;
switch (linked_list->id) {
@@ -196,7 +195,8 @@ acpi_rs_get_byte_stream_length (
segment_size = 16;
if (linked_list->data.address16.resource_source.string_ptr) {
- segment_size += linked_list->data.address16.resource_source.string_length;
+ segment_size +=
+ linked_list->data.address16.resource_source.string_length;
segment_size++;
}
break;
@@ -212,7 +212,8 @@ acpi_rs_get_byte_stream_length (
segment_size = 26;
if (linked_list->data.address32.resource_source.string_ptr) {
- segment_size += linked_list->data.address32.resource_source.string_length;
+ segment_size +=
+ linked_list->data.address32.resource_source.string_length;
segment_size++;
}
break;
@@ -227,7 +228,8 @@ acpi_rs_get_byte_stream_length (
segment_size = 46;
if (linked_list->data.address64.resource_source.string_ptr) {
- segment_size += linked_list->data.address64.resource_source.string_length;
+ segment_size +=
+ linked_list->data.address64.resource_source.string_length;
segment_size++;
}
break;
@@ -241,38 +243,36 @@ acpi_rs_get_byte_stream_length (
* Index + the length of the null terminated string
* Resource Source + 1 for the null.
*/
- segment_size = 9 +
- (((acpi_size) linked_list->data.extended_irq.number_of_interrupts - 1) * 4);
+ segment_size = 9 + (((acpi_size)
+ linked_list->data.extended_irq.number_of_interrupts - 1) * 4);
if (linked_list->data.extended_irq.resource_source.string_ptr) {
- segment_size += linked_list->data.extended_irq.resource_source.string_length;
+ segment_size +=
+ linked_list->data.extended_irq.resource_source.string_length;
segment_size++;
}
break;
default:
- /*
- * If we get here, everything is out of sync, exit with error
- */
+
+ /* If we get here, everything is out of sync, exit with error */
+
return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
} /* switch (linked_list->Id) */
- /*
- * Update the total
- */
+ /* Update the total */
+
byte_stream_size_needed += segment_size;
- /*
- * Point to the next object
- */
+ /* Point to the next object */
+
linked_list = ACPI_PTR_ADD (struct acpi_resource,
linked_list, linked_list->length);
}
- /*
- * This is the data the caller needs
- */
+ /* This is the data the caller needs */
+
*size_needed = byte_stream_size_needed;
return_ACPI_STATUS (AE_OK);
}
@@ -320,9 +320,8 @@ acpi_rs_get_list_length (
while (bytes_parsed < byte_stream_buffer_length) {
- /*
- * The next byte in the stream is the resource type
- */
+ /* The next byte in the stream is the resource type */
+
resource_type = acpi_rs_get_resource_type (*byte_stream_buffer);
switch (resource_type) {
@@ -346,9 +345,8 @@ acpi_rs_get_list_length (
ACPI_MOVE_16_TO_16 (&temp16, buffer);
bytes_consumed = temp16 + 3;
- /*
- * Ensure a 32-bit boundary for the structure
- */
+ /* Ensure a 32-bit boundary for the structure */
+
temp16 = (u16) ACPI_ROUND_UP_to_32_bITS (temp16);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
@@ -416,9 +414,8 @@ acpi_rs_get_list_length (
temp8 = 0;
}
- /*
- * Ensure a 64-bit boundary for the structure
- */
+ /* Ensure a 64-bit boundary for the structure */
+
temp8 = (u8) ACPI_ROUND_UP_to_64_bITS (temp8);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address64) +
@@ -452,9 +449,8 @@ acpi_rs_get_list_length (
temp8 = 0;
}
- /*
- * Ensure a 32-bit boundary for the structure
- */
+ /* Ensure a 32-bit boundary for the structure */
+
temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address32) +
@@ -488,9 +484,8 @@ acpi_rs_get_list_length (
temp8 = 0;
}
- /*
- * Ensure a 32-bit boundary for the structure
- */
+ /* Ensure a 32-bit boundary for the structure */
+
temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_address16) +
@@ -537,9 +532,8 @@ acpi_rs_get_list_length (
temp8 = 0;
}
- /*
- * Ensure a 32-bit boundary for the structure
- */
+ /* Ensure a 32-bit boundary for the structure */
+
temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq) +
@@ -567,9 +561,8 @@ acpi_rs_get_list_length (
++buffer;
- /*
- * Look at the number of bits set
- */
+ /* Look at the number of bits set */
+
ACPI_MOVE_16_TO_16 (&temp16, buffer);
for (index = 0; index < 16; index++) {
@@ -596,9 +589,8 @@ acpi_rs_get_list_length (
++buffer;
- /*
- * Look at the number of bits set
- */
+ /* Look at the number of bits set */
+
temp8 = *buffer;
for(index = 0; index < 8; index++) {
@@ -670,9 +662,8 @@ acpi_rs_get_list_length (
temp8 = (u8) (temp8 & 0x7);
bytes_consumed = temp8 + 1;
- /*
- * Ensure a 32-bit boundary for the structure
- */
+ /* Ensure a 32-bit boundary for the structure */
+
temp8 = (u8) ACPI_ROUND_UP_to_32_bITS (temp8);
structure_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor) +
(temp8 * sizeof (u8));
@@ -697,21 +688,18 @@ acpi_rs_get_list_length (
return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
}
- /*
- * Update the return value and counter
- */
+ /* Update the return value and counter */
+
buffer_size += (u32) ACPI_ALIGN_RESOURCE_SIZE (structure_size);
bytes_parsed += bytes_consumed;
- /*
- * Set the byte stream to point to the next resource
- */
+ /* Set the byte stream to point to the next resource */
+
byte_stream_buffer += bytes_consumed;
}
- /*
- * This is the data the caller needs
- */
+ /* This is the data the caller needs */
+
*size_needed = buffer_size;
return_ACPI_STATUS (AE_OK);
}
@@ -767,9 +755,8 @@ acpi_rs_get_pci_routing_table_length (
top_object_list = package_object->package.elements;
for (index = 0; index < number_of_elements; index++) {
- /*
- * Dereference the sub-package
- */
+ /* Dereference the sub-package */
+
package_element = *top_object_list;
/*
@@ -778,37 +765,40 @@ acpi_rs_get_pci_routing_table_length (
*/
sub_object_list = package_element->package.elements;
- /*
- * Scan the irq_table_elements for the Source Name String
- */
+ /* Scan the irq_table_elements for the Source Name String */
+
name_found = FALSE;
for (table_index = 0; table_index < 4 && !name_found; table_index++) {
- if ((ACPI_TYPE_STRING == ACPI_GET_OBJECT_TYPE (*sub_object_list)) ||
- ((ACPI_TYPE_LOCAL_REFERENCE == ACPI_GET_OBJECT_TYPE (*sub_object_list)) &&
- ((*sub_object_list)->reference.opcode == AML_INT_NAMEPATH_OP))) {
+ if ((ACPI_TYPE_STRING ==
+ ACPI_GET_OBJECT_TYPE (*sub_object_list)) ||
+
+ ((ACPI_TYPE_LOCAL_REFERENCE ==
+ ACPI_GET_OBJECT_TYPE (*sub_object_list)) &&
+
+ ((*sub_object_list)->reference.opcode ==
+ AML_INT_NAMEPATH_OP))) {
name_found = TRUE;
}
else {
- /*
- * Look at the next element
- */
+ /* Look at the next element */
+
sub_object_list++;
}
}
temp_size_needed += (sizeof (struct acpi_pci_routing_table) - 4);
- /*
- * Was a String type found?
- */
+ /* Was a String type found? */
+
if (name_found) {
if (ACPI_GET_OBJECT_TYPE (*sub_object_list) == ACPI_TYPE_STRING) {
/*
* The length String.Length field does not include the
* terminating NULL, add 1
*/
- temp_size_needed += ((acpi_size) (*sub_object_list)->string.length + 1);
+ temp_size_needed += ((acpi_size)
+ (*sub_object_list)->string.length + 1);
}
else {
temp_size_needed += acpi_ns_get_pathname_length (
@@ -827,14 +817,14 @@ acpi_rs_get_pci_routing_table_length (
temp_size_needed = ACPI_ROUND_UP_to_64_bITS (temp_size_needed);
- /*
- * Point to the next union acpi_operand_object
- */
+ /* Point to the next union acpi_operand_object */
+
top_object_list++;
}
/*
- * Adding an extra element to the end of the list, essentially a NULL terminator
+ * Adding an extra element to the end of the list, essentially a
+ * NULL terminator
*/
*buffer_size_needed = temp_size_needed + sizeof (struct acpi_pci_routing_table);
return_ACPI_STATUS (AE_OK);
diff --git a/drivers/acpi/resources/rscreate.c b/drivers/acpi/resources/rscreate.c
index a3a0cbfda68d..8e0eae0d50bb 100644
--- a/drivers/acpi/resources/rscreate.c
+++ b/drivers/acpi/resources/rscreate.c
@@ -87,9 +87,8 @@ acpi_rs_create_resource_list (
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "byte_stream_buffer = %p\n",
byte_stream_buffer));
- /*
- * Params already validated, so we don't re-validate here
- */
+ /* Params already validated, so we don't re-validate here */
+
byte_stream_buffer_length = byte_stream_buffer->buffer.length;
byte_stream_start = byte_stream_buffer->buffer.pointer;
@@ -171,9 +170,8 @@ acpi_rs_create_pci_routing_table (
/* Params already validated, so we don't re-validate here */
- /*
- * Get the required buffer length
- */
+ /* Get the required buffer length */
+
status = acpi_rs_get_pci_routing_table_length (package_object,
&buffer_size_needed);
if (ACPI_FAILURE (status)) {
@@ -217,9 +215,8 @@ acpi_rs_create_pci_routing_table (
*/
user_prt->length = (sizeof (struct acpi_pci_routing_table) - 4);
- /*
- * Each element of the top-level package must also be a package
- */
+ /* Each element of the top-level package must also be a package */
+
if (ACPI_GET_OBJECT_TYPE (*top_object_list) != ACPI_TYPE_PACKAGE) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"(PRT[%X]) Need sub-package, found %s\n",
@@ -243,9 +240,8 @@ acpi_rs_create_pci_routing_table (
*/
sub_object_list = (*top_object_list)->package.elements;
- /*
- * 1) First subobject: Dereference the PRT.Address
- */
+ /* 1) First subobject: Dereference the PRT.Address */
+
obj_desc = sub_object_list[0];
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
user_prt->address = obj_desc->integer.value;
@@ -257,9 +253,8 @@ acpi_rs_create_pci_routing_table (
return_ACPI_STATUS (AE_BAD_DATA);
}
- /*
- * 2) Second subobject: Dereference the PRT.Pin
- */
+ /* 2) Second subobject: Dereference the PRT.Pin */
+
obj_desc = sub_object_list[1];
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
user_prt->pin = (u32) obj_desc->integer.value;
@@ -271,9 +266,8 @@ acpi_rs_create_pci_routing_table (
return_ACPI_STATUS (AE_BAD_DATA);
}
- /*
- * 3) Third subobject: Dereference the PRT.source_name
- */
+ /* 3) Third subobject: Dereference the PRT.source_name */
+
obj_desc = sub_object_list[2];
switch (ACPI_GET_OBJECT_TYPE (obj_desc)) {
case ACPI_TYPE_LOCAL_REFERENCE:
@@ -296,7 +290,9 @@ acpi_rs_create_pci_routing_table (
status = acpi_ns_handle_to_pathname ((acpi_handle) node, &path_buffer);
- user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1; /* include null terminator */
+ /* +1 to include null terminator */
+
+ user_prt->length += (u32) ACPI_STRLEN (user_prt->source) + 1;
break;
@@ -304,8 +300,10 @@ acpi_rs_create_pci_routing_table (
ACPI_STRCPY (user_prt->source, obj_desc->string.pointer);
- /* Add to the Length field the length of the string (add 1 for terminator) */
-
+ /*
+ * Add to the Length field the length of the string
+ * (add 1 for terminator)
+ */
user_prt->length += obj_desc->string.length + 1;
break;
@@ -333,9 +331,8 @@ acpi_rs_create_pci_routing_table (
user_prt->length = (u32) ACPI_ROUND_UP_to_64_bITS (user_prt->length);
- /*
- * 4) Fourth subobject: Dereference the PRT.source_index
- */
+ /* 4) Fourth subobject: Dereference the PRT.source_index */
+
obj_desc = sub_object_list[3];
if (ACPI_GET_OBJECT_TYPE (obj_desc) == ACPI_TYPE_INTEGER) {
user_prt->source_index = (u32) obj_desc->integer.value;
diff --git a/drivers/acpi/resources/rsdump.c b/drivers/acpi/resources/rsdump.c
index eef1b1f2c685..1935dab2ab51 100644
--- a/drivers/acpi/resources/rsdump.c
+++ b/drivers/acpi/resources/rsdump.c
@@ -48,9 +48,62 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME ("rsdump")
+/* Local prototypes */
-#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
+static void
+acpi_rs_dump_irq (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_address16 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_address32 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_address64 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_dma (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_io (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_extended_irq (
+ union acpi_resource_data *data);
+static void
+acpi_rs_dump_fixed_io (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_fixed_memory32 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_memory24 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_memory32 (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_start_depend_fns (
+ union acpi_resource_data *data);
+
+static void
+acpi_rs_dump_vendor_specific (
+ union acpi_resource_data *data);
+
+
+#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
/*******************************************************************************
*
* FUNCTION: acpi_rs_dump_irq
@@ -63,7 +116,7 @@
*
******************************************************************************/
-void
+static void
acpi_rs_dump_irq (
union acpi_resource_data *data)
{
@@ -77,13 +130,13 @@ acpi_rs_dump_irq (
acpi_os_printf ("IRQ Resource\n");
acpi_os_printf (" %s Triggered\n",
- ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge");
+ ACPI_LEVEL_SENSITIVE == irq_data->edge_level ? "Level" : "Edge");
acpi_os_printf (" Active %s\n",
- ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High");
+ ACPI_ACTIVE_LOW == irq_data->active_high_low ? "Low" : "High");
acpi_os_printf (" %s\n",
- ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive");
+ ACPI_SHARED == irq_data->shared_exclusive ? "Shared" : "Exclusive");
acpi_os_printf (" %X Interrupts ( ", irq_data->number_of_interrupts);
@@ -108,7 +161,7 @@ acpi_rs_dump_irq (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_dma (
union acpi_resource_data *data)
{
@@ -144,7 +197,7 @@ acpi_rs_dump_dma (
}
acpi_os_printf (" %sBus Master\n",
- ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a ");
+ ACPI_BUS_MASTER == dma_data->bus_master ? "" : "Not a ");
switch (dma_data->transfer) {
@@ -165,7 +218,8 @@ acpi_rs_dump_dma (
break;
}
- acpi_os_printf (" Number of Channels: %X ( ", dma_data->number_of_channels);
+ acpi_os_printf (" Number of Channels: %X ( ",
+ dma_data->number_of_channels);
for (index = 0; index < dma_data->number_of_channels; index++) {
acpi_os_printf ("%X ", dma_data->channels[index]);
@@ -188,7 +242,7 @@ acpi_rs_dump_dma (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_start_depend_fns (
union acpi_resource_data *data)
{
@@ -232,8 +286,7 @@ acpi_rs_dump_start_depend_fns (
break;
default:
- acpi_os_printf (" Invalid performance "
- "robustness preference\n");
+ acpi_os_printf (" Invalid performance robustness preference\n");
break;
}
@@ -253,7 +306,7 @@ acpi_rs_dump_start_depend_fns (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_io (
union acpi_resource_data *data)
{
@@ -266,19 +319,15 @@ acpi_rs_dump_io (
acpi_os_printf ("Io Resource\n");
acpi_os_printf (" %d bit decode\n",
- ACPI_DECODE_16 == io_data->io_decode ? 16 : 10);
+ ACPI_DECODE_16 == io_data->io_decode ? 16 : 10);
- acpi_os_printf (" Range minimum base: %08X\n",
- io_data->min_base_address);
+ acpi_os_printf (" Range minimum base: %08X\n", io_data->min_base_address);
- acpi_os_printf (" Range maximum base: %08X\n",
- io_data->max_base_address);
+ acpi_os_printf (" Range maximum base: %08X\n", io_data->max_base_address);
- acpi_os_printf (" Alignment: %08X\n",
- io_data->alignment);
+ acpi_os_printf (" Alignment: %08X\n", io_data->alignment);
- acpi_os_printf (" Range Length: %08X\n",
- io_data->range_length);
+ acpi_os_printf (" Range Length: %08X\n", io_data->range_length);
return;
}
@@ -296,7 +345,7 @@ acpi_rs_dump_io (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_fixed_io (
union acpi_resource_data *data)
{
@@ -307,11 +356,9 @@ acpi_rs_dump_fixed_io (
acpi_os_printf ("Fixed Io Resource\n");
- acpi_os_printf (" Range base address: %08X",
- fixed_io_data->base_address);
+ acpi_os_printf (" Range base address: %08X", fixed_io_data->base_address);
- acpi_os_printf (" Range length: %08X",
- fixed_io_data->range_length);
+ acpi_os_printf (" Range length: %08X", fixed_io_data->range_length);
return;
}
@@ -329,7 +376,7 @@ acpi_rs_dump_fixed_io (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_vendor_specific (
union acpi_resource_data *data)
{
@@ -346,7 +393,7 @@ acpi_rs_dump_vendor_specific (
for (index = 0; index < vendor_data->length; index++) {
acpi_os_printf (" Byte %X: %08X\n",
- index, vendor_data->reserved[index]);
+ index, vendor_data->reserved[index]);
}
return;
@@ -365,7 +412,7 @@ acpi_rs_dump_vendor_specific (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_memory24 (
union acpi_resource_data *data)
{
@@ -378,21 +425,19 @@ acpi_rs_dump_memory24 (
acpi_os_printf ("24-Bit Memory Range Resource\n");
acpi_os_printf (" Read%s\n",
- ACPI_READ_WRITE_MEMORY ==
- memory24_data->read_write_attribute ?
- "/Write" : " only");
+ ACPI_READ_WRITE_MEMORY ==
+ memory24_data->read_write_attribute ?
+ "/Write" : " only");
acpi_os_printf (" Range minimum base: %08X\n",
- memory24_data->min_base_address);
+ memory24_data->min_base_address);
acpi_os_printf (" Range maximum base: %08X\n",
- memory24_data->max_base_address);
+ memory24_data->max_base_address);
- acpi_os_printf (" Alignment: %08X\n",
- memory24_data->alignment);
+ acpi_os_printf (" Alignment: %08X\n", memory24_data->alignment);
- acpi_os_printf (" Range length: %08X\n",
- memory24_data->range_length);
+ acpi_os_printf (" Range length: %08X\n", memory24_data->range_length);
return;
}
@@ -410,7 +455,7 @@ acpi_rs_dump_memory24 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_memory32 (
union acpi_resource_data *data)
{
@@ -423,21 +468,19 @@ acpi_rs_dump_memory32 (
acpi_os_printf ("32-Bit Memory Range Resource\n");
acpi_os_printf (" Read%s\n",
- ACPI_READ_WRITE_MEMORY ==
- memory32_data->read_write_attribute ?
- "/Write" : " only");
+ ACPI_READ_WRITE_MEMORY ==
+ memory32_data->read_write_attribute ?
+ "/Write" : " only");
acpi_os_printf (" Range minimum base: %08X\n",
- memory32_data->min_base_address);
+ memory32_data->min_base_address);
acpi_os_printf (" Range maximum base: %08X\n",
- memory32_data->max_base_address);
+ memory32_data->max_base_address);
- acpi_os_printf (" Alignment: %08X\n",
- memory32_data->alignment);
+ acpi_os_printf (" Alignment: %08X\n", memory32_data->alignment);
- acpi_os_printf (" Range length: %08X\n",
- memory32_data->range_length);
+ acpi_os_printf (" Range length: %08X\n", memory32_data->range_length);
return;
}
@@ -455,11 +498,12 @@ acpi_rs_dump_memory32 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_fixed_memory32 (
union acpi_resource_data *data)
{
- struct acpi_resource_fixed_mem32 *fixed_memory32_data = (struct acpi_resource_fixed_mem32 *) data;
+ struct acpi_resource_fixed_mem32 *fixed_memory32_data =
+ (struct acpi_resource_fixed_mem32 *) data;
ACPI_FUNCTION_ENTRY ();
@@ -468,15 +512,14 @@ acpi_rs_dump_fixed_memory32 (
acpi_os_printf ("32-Bit Fixed Location Memory Range Resource\n");
acpi_os_printf (" Read%s\n",
- ACPI_READ_WRITE_MEMORY ==
- fixed_memory32_data->read_write_attribute ?
- "/Write" : " Only");
+ ACPI_READ_WRITE_MEMORY ==
+ fixed_memory32_data->read_write_attribute ? "/Write" : " Only");
acpi_os_printf (" Range base address: %08X\n",
- fixed_memory32_data->range_base_address);
+ fixed_memory32_data->range_base_address);
acpi_os_printf (" Range length: %08X\n",
- fixed_memory32_data->range_length);
+ fixed_memory32_data->range_length);
return;
}
@@ -494,7 +537,7 @@ acpi_rs_dump_fixed_memory32 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_address16 (
union acpi_resource_data *data)
{
@@ -514,35 +557,30 @@ acpi_rs_dump_address16 (
switch (address16_data->attribute.memory.cache_attribute) {
case ACPI_NON_CACHEABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Noncacheable memory\n");
+ acpi_os_printf (" Type Specific: Noncacheable memory\n");
break;
case ACPI_CACHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Cacheable memory\n");
+ acpi_os_printf (" Type Specific: Cacheable memory\n");
break;
case ACPI_WRITE_COMBINING_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Write-combining memory\n");
+ acpi_os_printf (" Type Specific: Write-combining memory\n");
break;
case ACPI_PREFETCHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Prefetchable memory\n");
+ acpi_os_printf (" Type Specific: Prefetchable memory\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid cache attribute\n");
+ acpi_os_printf (" Type Specific: Invalid cache attribute\n");
break;
}
acpi_os_printf (" Type Specific: Read%s\n",
ACPI_READ_WRITE_MEMORY ==
- address16_data->attribute.memory.read_write_attribute ?
- "/Write" : " Only");
+ address16_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
break;
case ACPI_IO_RANGE:
@@ -551,30 +589,26 @@ acpi_rs_dump_address16 (
switch (address16_data->attribute.io.range_attribute) {
case ACPI_NON_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "Non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n");
break;
case ACPI_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA Io Addresses\n");
break;
case ACPI_ENTIRE_RANGE:
- acpi_os_printf (" Type Specific: "
- "ISA and non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid range attribute\n");
+ acpi_os_printf (" Type Specific: Invalid range attribute\n");
break;
}
acpi_os_printf (" Type Specific: %s Translation\n",
ACPI_SPARSE_TRANSLATION ==
- address16_data->attribute.io.translation_attribute ?
- "Sparse" : "Dense");
+ address16_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
break;
case ACPI_BUS_NUMBER_RANGE:
@@ -589,41 +623,42 @@ acpi_rs_dump_address16 (
}
acpi_os_printf (" Resource %s\n",
- ACPI_CONSUMER == address16_data->producer_consumer ?
+ ACPI_CONSUMER == address16_data->producer_consumer ?
"Consumer" : "Producer");
acpi_os_printf (" %s decode\n",
- ACPI_SUB_DECODE == address16_data->decode ?
- "Subtractive" : "Positive");
+ ACPI_SUB_DECODE == address16_data->decode ?
+ "Subtractive" : "Positive");
acpi_os_printf (" Min address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ?
- "" : "not");
+ ACPI_ADDRESS_FIXED == address16_data->min_address_fixed ?
+ "" : "not");
acpi_os_printf (" Max address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ?
- "" : "not");
+ ACPI_ADDRESS_FIXED == address16_data->max_address_fixed ?
+ "" : "not");
acpi_os_printf (" Granularity: %08X\n",
- address16_data->granularity);
+ address16_data->granularity);
acpi_os_printf (" Address range min: %08X\n",
- address16_data->min_address_range);
+ address16_data->min_address_range);
acpi_os_printf (" Address range max: %08X\n",
- address16_data->max_address_range);
+ address16_data->max_address_range);
acpi_os_printf (" Address translation offset: %08X\n",
- address16_data->address_translation_offset);
+ address16_data->address_translation_offset);
acpi_os_printf (" Address Length: %08X\n",
- address16_data->address_length);
+ address16_data->address_length);
if (0xFF != address16_data->resource_source.index) {
acpi_os_printf (" Resource Source Index: %X\n",
- address16_data->resource_source.index);
+ address16_data->resource_source.index);
+
acpi_os_printf (" Resource Source: %s\n",
- address16_data->resource_source.string_ptr);
+ address16_data->resource_source.string_ptr);
}
return;
@@ -642,7 +677,7 @@ acpi_rs_dump_address16 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_address32 (
union acpi_resource_data *data)
{
@@ -661,35 +696,30 @@ acpi_rs_dump_address32 (
switch (address32_data->attribute.memory.cache_attribute) {
case ACPI_NON_CACHEABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Noncacheable memory\n");
+ acpi_os_printf (" Type Specific: Noncacheable memory\n");
break;
case ACPI_CACHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Cacheable memory\n");
+ acpi_os_printf (" Type Specific: Cacheable memory\n");
break;
case ACPI_WRITE_COMBINING_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Write-combining memory\n");
+ acpi_os_printf (" Type Specific: Write-combining memory\n");
break;
case ACPI_PREFETCHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Prefetchable memory\n");
+ acpi_os_printf (" Type Specific: Prefetchable memory\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid cache attribute\n");
+ acpi_os_printf (" Type Specific: Invalid cache attribute\n");
break;
}
acpi_os_printf (" Type Specific: Read%s\n",
ACPI_READ_WRITE_MEMORY ==
- address32_data->attribute.memory.read_write_attribute ?
- "/Write" : " Only");
+ address32_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
break;
case ACPI_IO_RANGE:
@@ -698,30 +728,26 @@ acpi_rs_dump_address32 (
switch (address32_data->attribute.io.range_attribute) {
case ACPI_NON_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "Non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n");
break;
case ACPI_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA Io Addresses\n");
break;
case ACPI_ENTIRE_RANGE:
- acpi_os_printf (" Type Specific: "
- "ISA and non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid Range attribute");
+ acpi_os_printf (" Type Specific: Invalid Range attribute");
break;
}
acpi_os_printf (" Type Specific: %s Translation\n",
ACPI_SPARSE_TRANSLATION ==
- address32_data->attribute.io.translation_attribute ?
- "Sparse" : "Dense");
+ address32_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
break;
case ACPI_BUS_NUMBER_RANGE:
@@ -731,46 +757,48 @@ acpi_rs_dump_address32 (
default:
- acpi_os_printf (" Resource Type: 0x%2.2X\n", address32_data->resource_type);
+ acpi_os_printf (" Resource Type: 0x%2.2X\n",
+ address32_data->resource_type);
break;
}
acpi_os_printf (" Resource %s\n",
- ACPI_CONSUMER == address32_data->producer_consumer ?
- "Consumer" : "Producer");
+ ACPI_CONSUMER == address32_data->producer_consumer ?
+ "Consumer" : "Producer");
acpi_os_printf (" %s decode\n",
- ACPI_SUB_DECODE == address32_data->decode ?
- "Subtractive" : "Positive");
+ ACPI_SUB_DECODE == address32_data->decode ?
+ "Subtractive" : "Positive");
acpi_os_printf (" Min address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ?
- "" : "not ");
+ ACPI_ADDRESS_FIXED == address32_data->min_address_fixed ?
+ "" : "not ");
acpi_os_printf (" Max address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ?
- "" : "not ");
+ ACPI_ADDRESS_FIXED == address32_data->max_address_fixed ?
+ "" : "not ");
acpi_os_printf (" Granularity: %08X\n",
- address32_data->granularity);
+ address32_data->granularity);
acpi_os_printf (" Address range min: %08X\n",
- address32_data->min_address_range);
+ address32_data->min_address_range);
acpi_os_printf (" Address range max: %08X\n",
- address32_data->max_address_range);
+ address32_data->max_address_range);
acpi_os_printf (" Address translation offset: %08X\n",
- address32_data->address_translation_offset);
+ address32_data->address_translation_offset);
acpi_os_printf (" Address Length: %08X\n",
- address32_data->address_length);
+ address32_data->address_length);
if(0xFF != address32_data->resource_source.index) {
acpi_os_printf (" Resource Source Index: %X\n",
- address32_data->resource_source.index);
+ address32_data->resource_source.index);
+
acpi_os_printf (" Resource Source: %s\n",
- address32_data->resource_source.string_ptr);
+ address32_data->resource_source.string_ptr);
}
return;
@@ -789,7 +817,7 @@ acpi_rs_dump_address32 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_address64 (
union acpi_resource_data *data)
{
@@ -808,35 +836,30 @@ acpi_rs_dump_address64 (
switch (address64_data->attribute.memory.cache_attribute) {
case ACPI_NON_CACHEABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Noncacheable memory\n");
+ acpi_os_printf (" Type Specific: Noncacheable memory\n");
break;
case ACPI_CACHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Cacheable memory\n");
+ acpi_os_printf (" Type Specific: Cacheable memory\n");
break;
case ACPI_WRITE_COMBINING_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Write-combining memory\n");
+ acpi_os_printf (" Type Specific: Write-combining memory\n");
break;
case ACPI_PREFETCHABLE_MEMORY:
- acpi_os_printf (" Type Specific: "
- "Prefetchable memory\n");
+ acpi_os_printf (" Type Specific: Prefetchable memory\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid cache attribute\n");
+ acpi_os_printf (" Type Specific: Invalid cache attribute\n");
break;
}
acpi_os_printf (" Type Specific: Read%s\n",
ACPI_READ_WRITE_MEMORY ==
- address64_data->attribute.memory.read_write_attribute ?
- "/Write" : " Only");
+ address64_data->attribute.memory.read_write_attribute ?
+ "/Write" : " Only");
break;
case ACPI_IO_RANGE:
@@ -845,30 +868,26 @@ acpi_rs_dump_address64 (
switch (address64_data->attribute.io.range_attribute) {
case ACPI_NON_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "Non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: Non-ISA Io Addresses\n");
break;
case ACPI_ISA_ONLY_RANGES:
- acpi_os_printf (" Type Specific: "
- "ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA Io Addresses\n");
break;
case ACPI_ENTIRE_RANGE:
- acpi_os_printf (" Type Specific: "
- "ISA and non-ISA Io Addresses\n");
+ acpi_os_printf (" Type Specific: ISA and non-ISA Io Addresses\n");
break;
default:
- acpi_os_printf (" Type Specific: "
- "Invalid Range attribute");
+ acpi_os_printf (" Type Specific: Invalid Range attribute");
break;
}
acpi_os_printf (" Type Specific: %s Translation\n",
ACPI_SPARSE_TRANSLATION ==
- address64_data->attribute.io.translation_attribute ?
- "Sparse" : "Dense");
+ address64_data->attribute.io.translation_attribute ?
+ "Sparse" : "Dense");
break;
case ACPI_BUS_NUMBER_RANGE:
@@ -878,49 +897,51 @@ acpi_rs_dump_address64 (
default:
- acpi_os_printf (" Resource Type: 0x%2.2X\n", address64_data->resource_type);
+ acpi_os_printf (" Resource Type: 0x%2.2X\n",
+ address64_data->resource_type);
break;
}
acpi_os_printf (" Resource %s\n",
- ACPI_CONSUMER == address64_data->producer_consumer ?
- "Consumer" : "Producer");
+ ACPI_CONSUMER == address64_data->producer_consumer ?
+ "Consumer" : "Producer");
acpi_os_printf (" %s decode\n",
- ACPI_SUB_DECODE == address64_data->decode ?
- "Subtractive" : "Positive");
+ ACPI_SUB_DECODE == address64_data->decode ?
+ "Subtractive" : "Positive");
acpi_os_printf (" Min address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ?
- "" : "not ");
+ ACPI_ADDRESS_FIXED == address64_data->min_address_fixed ?
+ "" : "not ");
acpi_os_printf (" Max address is %s fixed\n",
- ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ?
- "" : "not ");
+ ACPI_ADDRESS_FIXED == address64_data->max_address_fixed ?
+ "" : "not ");
acpi_os_printf (" Granularity: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->granularity));
+ ACPI_FORMAT_UINT64 (address64_data->granularity));
acpi_os_printf (" Address range min: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->min_address_range));
+ ACPI_FORMAT_UINT64 (address64_data->min_address_range));
acpi_os_printf (" Address range max: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->max_address_range));
+ ACPI_FORMAT_UINT64 (address64_data->max_address_range));
acpi_os_printf (" Address translation offset: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->address_translation_offset));
+ ACPI_FORMAT_UINT64 (address64_data->address_translation_offset));
acpi_os_printf (" Address Length: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->address_length));
+ ACPI_FORMAT_UINT64 (address64_data->address_length));
acpi_os_printf (" Type Specific Attributes: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes));
+ ACPI_FORMAT_UINT64 (address64_data->type_specific_attributes));
if (0xFF != address64_data->resource_source.index) {
acpi_os_printf (" Resource Source Index: %X\n",
- address64_data->resource_source.index);
+ address64_data->resource_source.index);
+
acpi_os_printf (" Resource Source: %s\n",
- address64_data->resource_source.string_ptr);
+ address64_data->resource_source.string_ptr);
}
return;
@@ -939,7 +960,7 @@ acpi_rs_dump_address64 (
*
******************************************************************************/
-void
+static void
acpi_rs_dump_extended_irq (
union acpi_resource_data *data)
{
@@ -953,23 +974,22 @@ acpi_rs_dump_extended_irq (
acpi_os_printf ("Extended IRQ Resource\n");
acpi_os_printf (" Resource %s\n",
- ACPI_CONSUMER == ext_irq_data->producer_consumer ?
- "Consumer" : "Producer");
+ ACPI_CONSUMER == ext_irq_data->producer_consumer ?
+ "Consumer" : "Producer");
acpi_os_printf (" %s\n",
- ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ?
- "Level" : "Edge");
+ ACPI_LEVEL_SENSITIVE == ext_irq_data->edge_level ?
+ "Level" : "Edge");
acpi_os_printf (" Active %s\n",
- ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ?
- "low" : "high");
+ ACPI_ACTIVE_LOW == ext_irq_data->active_high_low ?
+ "low" : "high");
acpi_os_printf (" %s\n",
- ACPI_SHARED == ext_irq_data->shared_exclusive ?
- "Shared" : "Exclusive");
+ ACPI_SHARED == ext_irq_data->shared_exclusive ?
+ "Shared" : "Exclusive");
- acpi_os_printf (" Interrupts : %X ( ",
- ext_irq_data->number_of_interrupts);
+ acpi_os_printf (" Interrupts : %X ( ", ext_irq_data->number_of_interrupts);
for (index = 0; index < ext_irq_data->number_of_interrupts; index++) {
acpi_os_printf ("%X ", ext_irq_data->interrupts[index]);
@@ -979,9 +999,10 @@ acpi_rs_dump_extended_irq (
if(0xFF != ext_irq_data->resource_source.index) {
acpi_os_printf (" Resource Source Index: %X",
- ext_irq_data->resource_source.index);
+ ext_irq_data->resource_source.index);
+
acpi_os_printf (" Resource Source: %s",
- ext_irq_data->resource_source.string_ptr);
+ ext_irq_data->resource_source.string_ptr);
}
return;
@@ -992,7 +1013,7 @@ acpi_rs_dump_extended_irq (
*
* FUNCTION: acpi_rs_dump_resource_list
*
- * PARAMETERS: Data - pointer to the resource structure to dump.
+ * PARAMETERS: Resource - pointer to the resource structure to dump.
*
* RETURN: None
*
@@ -1096,7 +1117,7 @@ acpi_rs_dump_resource_list (
*
* FUNCTION: acpi_rs_dump_irq_list
*
- * PARAMETERS: Data - pointer to the routing table to dump.
+ * PARAMETERS: route_table - pointer to the routing table to dump.
*
* RETURN: None
*
@@ -1124,20 +1145,17 @@ acpi_rs_dump_irq_list (
acpi_os_printf ("PCI IRQ Routing Table structure %X.\n", count++);
acpi_os_printf (" Address: %8.8X%8.8X\n",
- ACPI_FORMAT_UINT64 (prt_element->address));
+ ACPI_FORMAT_UINT64 (prt_element->address));
acpi_os_printf (" Pin: %X\n", prt_element->pin);
acpi_os_printf (" Source: %s\n", prt_element->source);
- acpi_os_printf (" source_index: %X\n",
- prt_element->source_index);
+ acpi_os_printf (" source_index: %X\n", prt_element->source_index);
buffer += prt_element->length;
-
prt_element = ACPI_CAST_PTR (struct acpi_pci_routing_table, buffer);
-
- if(0 == prt_element->length) {
+ if (0 == prt_element->length) {
done = TRUE;
}
}
diff --git a/drivers/acpi/resources/rsio.c b/drivers/acpi/resources/rsio.c
index 972c746d37e4..23a4d149fac8 100644
--- a/drivers/acpi/resources/rsio.c
+++ b/drivers/acpi/resources/rsio.c
@@ -81,67 +81,60 @@ acpi_rs_io_resource (
struct acpi_resource *output_struct = (void *) *output_buffer;
u16 temp16 = 0;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_io);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_io);
ACPI_FUNCTION_TRACE ("rs_io_resource");
- /*
- * The number of bytes consumed are Constant
- */
+ /* The number of bytes consumed are Constant */
+
*bytes_consumed = 8;
output_struct->id = ACPI_RSTYPE_IO;
- /*
- * Check Decode
- */
+ /* Check Decode */
+
buffer += 1;
temp8 = *buffer;
output_struct->data.io.io_decode = temp8 & 0x01;
- /*
- * Check min_base Address
- */
+ /* Check min_base Address */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
output_struct->data.io.min_base_address = temp16;
- /*
- * Check max_base Address
- */
+ /* Check max_base Address */
+
buffer += 2;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
output_struct->data.io.max_base_address = temp16;
- /*
- * Check Base alignment
- */
+ /* Check Base alignment */
+
buffer += 2;
temp8 = *buffer;
output_struct->data.io.alignment = temp8;
- /*
- * Check range_length
- */
+ /* Check range_length */
+
buffer += 1;
temp8 = *buffer;
output_struct->data.io.range_length = temp8;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -179,43 +172,39 @@ acpi_rs_fixed_io_resource (
struct acpi_resource *output_struct = (void *) *output_buffer;
u16 temp16 = 0;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_io);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_fixed_io);
ACPI_FUNCTION_TRACE ("rs_fixed_io_resource");
- /*
- * The number of bytes consumed are Constant
- */
+ /* The number of bytes consumed are Constant */
+
*bytes_consumed = 4;
output_struct->id = ACPI_RSTYPE_FIXED_IO;
- /*
- * Check Range Base Address
- */
+ /* Check Range Base Address */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
output_struct->data.fixed_io.base_address = temp16;
- /*
- * Check range_length
- */
+ /* Check range_length */
+
buffer += 2;
temp8 = *buffer;
output_struct->data.fixed_io.range_length = temp8;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -251,55 +240,48 @@ acpi_rs_io_stream (
ACPI_FUNCTION_TRACE ("rs_io_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x47;
buffer += 1;
- /*
- * Io Information Byte
- */
+ /* Io Information Byte */
+
temp8 = (u8) (linked_list->data.io.io_decode & 0x01);
*buffer = temp8;
buffer += 1;
- /*
- * Set the Range minimum base address
- */
+ /* Set the Range minimum base address */
+
temp16 = (u16) linked_list->data.io.min_base_address;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the Range maximum base address
- */
+ /* Set the Range maximum base address */
+
temp16 = (u16) linked_list->data.io.max_base_address;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the base alignment
- */
+ /* Set the base alignment */
+
temp8 = (u8) linked_list->data.io.alignment;
*buffer = temp8;
buffer += 1;
- /*
- * Set the range length
- */
+ /* Set the range length */
+
temp8 = (u8) linked_list->data.io.range_length;
*buffer = temp8;
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -335,32 +317,28 @@ acpi_rs_fixed_io_stream (
ACPI_FUNCTION_TRACE ("rs_fixed_io_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x4B;
buffer += 1;
- /*
- * Set the Range base address
- */
+ /* Set the Range base address */
+
temp16 = (u16) linked_list->data.fixed_io.base_address;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the range length
- */
+ /* Set the range length */
+
temp8 = (u8) linked_list->data.fixed_io.range_length;
*buffer = temp8;
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -399,21 +377,20 @@ acpi_rs_dma_resource (
u8 temp8 = 0;
u8 index;
u8 i;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_dma);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_dma);
ACPI_FUNCTION_TRACE ("rs_dma_resource");
- /*
- * The number of bytes consumed are Constant
- */
+ /* The number of bytes consumed are Constant */
+
*bytes_consumed = 3;
output_struct->id = ACPI_RSTYPE_DMA;
- /*
- * Point to the 8-bits of Byte 1
- */
+ /* Point to the 8-bits of Byte 1 */
+
buffer += 1;
temp8 = *buffer;
@@ -430,46 +407,40 @@ acpi_rs_dma_resource (
output_struct->data.dma.number_of_channels = i;
if (i > 0) {
- /*
- * Calculate the structure size based upon the number of interrupts
- */
+ /* Calculate the structure size based upon the number of interrupts */
+
struct_size += ((acpi_size) i - 1) * 4;
}
- /*
- * Point to Byte 2
- */
+ /* Point to Byte 2 */
+
buffer += 1;
temp8 = *buffer;
- /*
- * Check for transfer preference (Bits[1:0])
- */
+ /* Check for transfer preference (Bits[1:0]) */
+
output_struct->data.dma.transfer = temp8 & 0x03;
if (0x03 == output_struct->data.dma.transfer) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid DMA.Transfer preference (3)\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid DMA.Transfer preference (3)\n"));
return_ACPI_STATUS (AE_BAD_DATA);
}
- /*
- * Get bus master preference (Bit[2])
- */
+ /* Get bus master preference (Bit[2]) */
+
output_struct->data.dma.bus_master = (temp8 >> 2) & 0x01;
- /*
- * Get channel speed support (Bits[6:5])
- */
+ /* Get channel speed support (Bits[6:5]) */
+
output_struct->data.dma.type = (temp8 >> 5) & 0x03;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -506,16 +477,14 @@ acpi_rs_dma_stream (
ACPI_FUNCTION_TRACE ("rs_dma_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x2A;
buffer += 1;
temp8 = 0;
- /*
- * Loop through all of the Channels and set the mask bits
- */
+ /* Loop through all of the Channels and set the mask bits */
+
for (index = 0;
index < linked_list->data.dma.number_of_channels;
index++) {
@@ -526,9 +495,8 @@ acpi_rs_dma_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Set the DMA Info
- */
+ /* Set the DMA Info */
+
temp8 = (u8) ((linked_list->data.dma.type & 0x03) << 5);
temp8 |= ((linked_list->data.dma.bus_master & 0x01) << 2);
temp8 |= (linked_list->data.dma.transfer & 0x03);
@@ -536,9 +504,8 @@ acpi_rs_dma_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
diff --git a/drivers/acpi/resources/rsirq.c b/drivers/acpi/resources/rsirq.c
index fd07a8702fbe..8a2b630be45b 100644
--- a/drivers/acpi/resources/rsirq.c
+++ b/drivers/acpi/resources/rsirq.c
@@ -83,7 +83,8 @@ acpi_rs_irq_resource (
u8 temp8 = 0;
u8 index;
u8 i;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_irq);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_irq);
ACPI_FUNCTION_TRACE ("rs_irq_resource");
@@ -91,15 +92,14 @@ acpi_rs_irq_resource (
/*
* The number of bytes consumed are contained in the descriptor
- * (Bits:0-1)
+ * (Bits:0-1)
*/
temp8 = *buffer;
*bytes_consumed = (temp8 & 0x03) + 1;
output_struct->id = ACPI_RSTYPE_IRQ;
- /*
- * Point to the 16-bits of Bytes 1 and 2
- */
+ /* Point to the 16-bits of Bytes 1 and 2 */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -118,22 +118,19 @@ acpi_rs_irq_resource (
output_struct->data.irq.number_of_interrupts = i;
if (i > 0) {
- /*
- * Calculate the structure size based upon the number of interrupts
- */
+ /* Calculate the structure size based upon the number of interrupts */
+
struct_size += ((acpi_size) i - 1) * 4;
}
- /*
- * Point to Byte 3 if it is used
- */
+ /* Point to Byte 3 if it is used */
+
if (4 == *bytes_consumed) {
buffer += 2;
temp8 = *buffer;
- /*
- * Check for HE, LL interrupts
- */
+ /* Check for HE, LL interrupts */
+
switch (temp8 & 0x09) {
case 0x01: /* HE */
output_struct->data.irq.edge_level = ACPI_EDGE_SENSITIVE;
@@ -152,13 +149,13 @@ acpi_rs_irq_resource (
* so 0x00 and 0x09 are illegal.
*/
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Invalid interrupt polarity/trigger in resource list, %X\n", temp8));
+ "Invalid interrupt polarity/trigger in resource list, %X\n",
+ temp8));
return_ACPI_STATUS (AE_BAD_DATA);
}
- /*
- * Check for sharable
- */
+ /* Check for sharable */
+
output_struct->data.irq.shared_exclusive = (temp8 >> 3) & 0x01;
}
else {
@@ -171,14 +168,12 @@ acpi_rs_irq_resource (
output_struct->data.irq.shared_exclusive = ACPI_EXCLUSIVE;
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -234,9 +229,8 @@ acpi_rs_irq_stream (
buffer += 1;
temp16 = 0;
- /*
- * Loop through all of the interrupts and set the mask bits
- */
+ /* Loop through all of the interrupts and set the mask bits */
+
for(index = 0;
index < linked_list->data.irq.number_of_interrupts;
index++) {
@@ -247,9 +241,8 @@ acpi_rs_irq_stream (
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the IRQ Info byte if needed.
- */
+ /* Set the IRQ Info byte if needed. */
+
if (IRqinfo_byte_needed) {
temp8 = 0;
temp8 = (u8) ((linked_list->data.irq.shared_exclusive &
@@ -267,9 +260,8 @@ acpi_rs_irq_stream (
buffer += 1;
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -309,15 +301,15 @@ acpi_rs_extended_irq_resource (
u8 temp8 = 0;
u8 *temp_ptr;
u8 index;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_ext_irq);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_ext_irq);
ACPI_FUNCTION_TRACE ("rs_extended_irq_resource");
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -330,9 +322,8 @@ acpi_rs_extended_irq_resource (
*bytes_consumed = temp16 + 3;
output_struct->id = ACPI_RSTYPE_EXT_IRQ;
- /*
- * Point to the Byte3
- */
+ /* Point to the Byte3 */
+
buffer += 2;
temp8 = *buffer;
@@ -347,21 +338,18 @@ acpi_rs_extended_irq_resource (
* - Edge/Level are defined opposite in the table vs the headers
*/
output_struct->data.extended_irq.edge_level =
- (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
+ (temp8 & 0x2) ? ACPI_EDGE_SENSITIVE : ACPI_LEVEL_SENSITIVE;
+
+ /* Check Interrupt Polarity */
- /*
- * Check Interrupt Polarity
- */
output_struct->data.extended_irq.active_high_low = (temp8 >> 2) & 0x1;
- /*
- * Check for sharable
- */
+ /* Check for sharable */
+
output_struct->data.extended_irq.shared_exclusive = (temp8 >> 3) & 0x01;
- /*
- * Point to Byte4 (IRQ Table length)
- */
+ /* Point to Byte4 (IRQ Table length) */
+
buffer += 1;
temp8 = *buffer;
@@ -379,14 +367,12 @@ acpi_rs_extended_irq_resource (
*/
struct_size += (temp8 - 1) * 4;
- /*
- * Point to Byte5 (First IRQ Number)
- */
+ /* Point to Byte5 (First IRQ Number) */
+
buffer += 1;
- /*
- * Cycle through every IRQ in the table
- */
+ /* Cycle through every IRQ in the table */
+
for (index = 0; index < temp8; index++) {
ACPI_MOVE_32_TO_32 (
&output_struct->data.extended_irq.interrupts[index], buffer);
@@ -407,7 +393,8 @@ acpi_rs_extended_irq_resource (
* we add 1 to the length.
*/
if (*bytes_consumed >
- ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) + (5 + 1)) {
+ ((acpi_size) output_struct->data.extended_irq.number_of_interrupts * 4) +
+ (5 + 1)) {
/* Dereference the Index */
temp8 = *buffer;
@@ -417,13 +404,13 @@ acpi_rs_extended_irq_resource (
buffer += 1;
- /*
- * Point the String pointer to the end of this structure.
- */
+ /* Point the String pointer to the end of this structure. */
+
output_struct->data.extended_irq.resource_source.string_ptr =
(char *)((char *) output_struct + struct_size);
- temp_ptr = (u8 *) output_struct->data.extended_irq.resource_source.string_ptr;
+ temp_ptr = (u8 *)
+ output_struct->data.extended_irq.resource_source.string_ptr;
/* Copy the string into the buffer */
@@ -436,9 +423,8 @@ acpi_rs_extended_irq_resource (
index += 1;
}
- /*
- * Add the terminating null
- */
+ /* Add the terminating null */
+
*temp_ptr = 0x00;
output_struct->data.extended_irq.resource_source.string_length = index + 1;
@@ -456,14 +442,12 @@ acpi_rs_extended_irq_resource (
output_struct->data.extended_irq.resource_source.string_ptr = NULL;
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -501,21 +485,18 @@ acpi_rs_extended_irq_stream (
ACPI_FUNCTION_TRACE ("rs_extended_irq_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x89;
buffer += 1;
- /*
- * Set a pointer to the Length field - to be filled in later
- */
+ /* Set a pointer to the Length field - to be filled in later */
+
length_field = ACPI_CAST_PTR (u16, buffer);
buffer += 2;
- /*
- * Set the Interrupt vector flags
- */
+ /* Set the Interrupt vector flags */
+
temp8 = (u8)(linked_list->data.extended_irq.producer_consumer & 0x01);
temp8 |= ((linked_list->data.extended_irq.shared_exclusive & 0x01) << 3);
@@ -532,17 +513,15 @@ acpi_rs_extended_irq_stream (
temp8 |= 0x2;
}
- /*
- * Set the Interrupt Polarity
- */
+ /* Set the Interrupt Polarity */
+
temp8 |= ((linked_list->data.extended_irq.active_high_low & 0x1) << 2);
*buffer = temp8;
buffer += 1;
- /*
- * Set the Interrupt table length
- */
+ /* Set the Interrupt table length */
+
temp8 = (u8) linked_list->data.extended_irq.number_of_interrupts;
*buffer = temp8;
@@ -555,18 +534,16 @@ acpi_rs_extended_irq_stream (
buffer += 4;
}
- /*
- * Resource Source Index and Resource Source are optional
- */
+ /* Resource Source Index and Resource Source are optional */
+
if (0 != linked_list->data.extended_irq.resource_source.string_length) {
*buffer = (u8) linked_list->data.extended_irq.resource_source.index;
buffer += 1;
temp_pointer = (char *) buffer;
- /*
- * Copy the string
- */
+ /* Copy the string */
+
ACPI_STRCPY (temp_pointer,
linked_list->data.extended_irq.resource_source.string_ptr);
@@ -574,12 +551,12 @@ acpi_rs_extended_irq_stream (
* Buffer needs to be set to the length of the sting + one for the
* terminating null
*/
- buffer += (acpi_size)(ACPI_STRLEN (linked_list->data.extended_irq.resource_source.string_ptr) + 1);
+ buffer += (acpi_size) (ACPI_STRLEN (
+ linked_list->data.extended_irq.resource_source.string_ptr) + 1);
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
/*
diff --git a/drivers/acpi/resources/rslist.c b/drivers/acpi/resources/rslist.c
index e49c1e030f99..db7bcb4e60e3 100644
--- a/drivers/acpi/resources/rslist.c
+++ b/drivers/acpi/resources/rslist.c
@@ -55,7 +55,7 @@
*
* PARAMETERS: resource_start_byte - Byte 0 of a resource descriptor
*
- * RETURN: The Resource Type (Name) with no extraneous bits
+ * RETURN: The Resource Type with no extraneous bits
*
* DESCRIPTION: Extract the Resource Type/Name from the first byte of
* a resource descriptor.
@@ -70,28 +70,25 @@ acpi_rs_get_resource_type (
ACPI_FUNCTION_ENTRY ();
- /*
- * Determine if this is a small or large resource
- */
+ /* Determine if this is a small or large resource */
+
switch (resource_start_byte & ACPI_RDESC_TYPE_MASK) {
case ACPI_RDESC_TYPE_SMALL:
- /*
- * Small Resource Type -- Only bits 6:3 are valid
- */
+ /* Small Resource Type -- Only bits 6:3 are valid */
+
return ((u8) (resource_start_byte & ACPI_RDESC_SMALL_MASK));
case ACPI_RDESC_TYPE_LARGE:
- /*
- * Large Resource Type -- All bits are valid
- */
+ /* Large Resource Type -- All bits are valid */
+
return (resource_start_byte);
default:
- /* No other types of resource descriptor */
+ /* Invalid type */
break;
}
@@ -135,9 +132,8 @@ acpi_rs_byte_stream_to_list (
while (bytes_parsed < byte_stream_buffer_length &&
!end_tag_processed) {
- /*
- * The next byte in the stream is the resource type
- */
+ /* The next byte in the stream is the resource type */
+
resource_type = acpi_rs_get_resource_type (*byte_stream_buffer);
switch (resource_type) {
@@ -299,28 +295,23 @@ acpi_rs_byte_stream_to_list (
return_ACPI_STATUS (status);
}
- /*
- * Update the return value and counter
- */
+ /* Update the return value and counter */
+
bytes_parsed += bytes_consumed;
- /*
- * Set the byte stream to point to the next resource
- */
+ /* Set the byte stream to point to the next resource */
+
byte_stream_buffer += bytes_consumed;
- /*
- * Set the Buffer to the next structure
- */
+ /* Set the Buffer to the next structure */
+
resource = ACPI_CAST_PTR (struct acpi_resource, buffer);
resource->length = (u32) ACPI_ALIGN_RESOURCE_SIZE (resource->length);
buffer += ACPI_ALIGN_RESOURCE_SIZE (structure_size);
+ }
- } /* end while */
+ /* Check the reason for exiting the while loop */
- /*
- * Check the reason for exiting the while loop
- */
if (!end_tag_processed) {
return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
}
@@ -424,9 +415,8 @@ acpi_rs_list_to_byte_stream (
*/
status = acpi_rs_end_tag_stream (linked_list, &buffer, &bytes_consumed);
- /*
- * An End Tag indicates the end of the Resource Template
- */
+ /* An End Tag indicates the end of the Resource Template */
+
done = TRUE;
break;
@@ -488,27 +478,25 @@ acpi_rs_list_to_byte_stream (
default:
/*
* If we get here, everything is out of sync,
- * so exit with an error
+ * so exit with an error
*/
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid descriptor type (%X) in resource list\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Invalid descriptor type (%X) in resource list\n",
linked_list->id));
status = AE_BAD_DATA;
break;
-
- } /* switch (linked_list->Id) */
+ }
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
- /*
- * Set the Buffer to point to the open byte
- */
+ /* Set the Buffer to point to the open byte */
+
buffer += bytes_consumed;
- /*
- * Point to the next object
- */
+ /* Point to the next object */
+
linked_list = ACPI_PTR_ADD (struct acpi_resource,
linked_list, linked_list->length);
}
diff --git a/drivers/acpi/resources/rsmemory.c b/drivers/acpi/resources/rsmemory.c
index 7c935aecf075..91d0207f01ac 100644
--- a/drivers/acpi/resources/rsmemory.c
+++ b/drivers/acpi/resources/rsmemory.c
@@ -81,15 +81,15 @@ acpi_rs_memory24_resource (
struct acpi_resource *output_struct = (void *) *output_buffer;
u16 temp16 = 0;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem24);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_mem24);
ACPI_FUNCTION_TRACE ("rs_memory24_resource");
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -97,48 +97,41 @@ acpi_rs_memory24_resource (
*bytes_consumed = (acpi_size) temp16 + 3;
output_struct->id = ACPI_RSTYPE_MEM24;
- /*
- * Check Byte 3 the Read/Write bit
- */
+ /* Check Byte 3 the Read/Write bit */
+
temp8 = *buffer;
buffer += 1;
output_struct->data.memory24.read_write_attribute = temp8 & 0x01;
- /*
- * Get min_base_address (Bytes 4-5)
- */
+ /* Get min_base_address (Bytes 4-5) */
+
ACPI_MOVE_16_TO_16 (&temp16, buffer);
buffer += 2;
output_struct->data.memory24.min_base_address = temp16;
- /*
- * Get max_base_address (Bytes 6-7)
- */
+ /* Get max_base_address (Bytes 6-7) */
+
ACPI_MOVE_16_TO_16 (&temp16, buffer);
buffer += 2;
output_struct->data.memory24.max_base_address = temp16;
- /*
- * Get Alignment (Bytes 8-9)
- */
+ /* Get Alignment (Bytes 8-9) */
+
ACPI_MOVE_16_TO_16 (&temp16, buffer);
buffer += 2;
output_struct->data.memory24.alignment = temp16;
- /*
- * Get range_length (Bytes 10-11)
- */
+ /* Get range_length (Bytes 10-11) */
+
ACPI_MOVE_16_TO_16 (&temp16, buffer);
output_struct->data.memory24.range_length = temp16;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -174,53 +167,45 @@ acpi_rs_memory24_stream (
ACPI_FUNCTION_TRACE ("rs_memory24_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x81;
buffer += 1;
- /*
- * The length field is static
- */
+ /* The length field is static */
+
temp16 = 0x09;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the Information Byte
- */
+ /* Set the Information Byte */
+
temp8 = (u8) (linked_list->data.memory24.read_write_attribute & 0x01);
*buffer = temp8;
buffer += 1;
- /*
- * Set the Range minimum base address
- */
+ /* Set the Range minimum base address */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.min_base_address);
buffer += 2;
- /*
- * Set the Range maximum base address
- */
+ /* Set the Range maximum base address */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.max_base_address);
buffer += 2;
- /*
- * Set the base alignment
- */
+ /* Set the base alignment */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.alignment);
buffer += 2;
- /*
- * Set the range length
- */
+ /* Set the range length */
+
ACPI_MOVE_32_TO_16 (buffer, &linked_list->data.memory24.range_length);
buffer += 2;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -258,15 +243,15 @@ acpi_rs_memory32_range_resource (
struct acpi_resource *output_struct = (void *) *output_buffer;
u16 temp16 = 0;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_mem32);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_mem32);
ACPI_FUNCTION_TRACE ("rs_memory32_range_resource");
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -285,45 +270,38 @@ acpi_rs_memory32_range_resource (
* 4 * sizeof(RESOURCE_DATA) instead of 4 * sizeof(u8)
*/
- /*
- * Check Byte 3 the Read/Write bit
- */
+ /* Check Byte 3 the Read/Write bit */
+
temp8 = *buffer;
buffer += 1;
output_struct->data.memory32.read_write_attribute = temp8 & 0x01;
- /*
- * Get min_base_address (Bytes 4-7)
- */
+ /* Get min_base_address (Bytes 4-7) */
+
ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.min_base_address, buffer);
buffer += 4;
- /*
- * Get max_base_address (Bytes 8-11)
- */
+ /* Get max_base_address (Bytes 8-11) */
+
ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.max_base_address, buffer);
buffer += 4;
- /*
- * Get Alignment (Bytes 12-15)
- */
+ /* Get Alignment (Bytes 12-15) */
+
ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.alignment, buffer);
buffer += 4;
- /*
- * Get range_length (Bytes 16-19)
- */
+ /* Get range_length (Bytes 16-19) */
+
ACPI_MOVE_32_TO_32 (&output_struct->data.memory32.range_length, buffer);
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -361,15 +339,15 @@ acpi_rs_fixed_memory32_resource (
struct acpi_resource *output_struct = (void *) *output_buffer;
u16 temp16 = 0;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_fixed_mem32);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_fixed_mem32);
ACPI_FUNCTION_TRACE ("rs_fixed_memory32_resource");
- /*
- * Point past the Descriptor to get the number of bytes consumed
- */
+ /* Point past the Descriptor to get the number of bytes consumed */
+
buffer += 1;
ACPI_MOVE_16_TO_16 (&temp16, buffer);
@@ -378,32 +356,28 @@ acpi_rs_fixed_memory32_resource (
output_struct->id = ACPI_RSTYPE_FIXED_MEM32;
- /*
- * Check Byte 3 the Read/Write bit
- */
+ /* Check Byte 3 the Read/Write bit */
+
temp8 = *buffer;
buffer += 1;
output_struct->data.fixed_memory32.read_write_attribute = temp8 & 0x01;
- /*
- * Get range_base_address (Bytes 4-7)
- */
- ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address, buffer);
+ /* Get range_base_address (Bytes 4-7) */
+
+ ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_base_address,
+ buffer);
buffer += 4;
- /*
- * Get range_length (Bytes 8-11)
- */
+ /* Get range_length (Bytes 8-11) */
+
ACPI_MOVE_32_TO_32 (&output_struct->data.fixed_memory32.range_length, buffer);
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -439,54 +413,46 @@ acpi_rs_memory32_range_stream (
ACPI_FUNCTION_TRACE ("rs_memory32_range_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x85;
buffer += 1;
- /*
- * The length field is static
- */
+ /* The length field is static */
+
temp16 = 0x11;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the Information Byte
- */
+ /* Set the Information Byte */
+
temp8 = (u8) (linked_list->data.memory32.read_write_attribute & 0x01);
*buffer = temp8;
buffer += 1;
- /*
- * Set the Range minimum base address
- */
+ /* Set the Range minimum base address */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.min_base_address);
buffer += 4;
- /*
- * Set the Range maximum base address
- */
+ /* Set the Range maximum base address */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.max_base_address);
buffer += 4;
- /*
- * Set the base alignment
- */
+ /* Set the base alignment */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.alignment);
buffer += 4;
- /*
- * Set the range length
- */
+ /* Set the range length */
+
ACPI_MOVE_32_TO_32 (buffer, &linked_list->data.memory32.range_length);
buffer += 4;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -522,44 +488,38 @@ acpi_rs_fixed_memory32_stream (
ACPI_FUNCTION_TRACE ("rs_fixed_memory32_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x86;
buffer += 1;
- /*
- * The length field is static
- */
+ /* The length field is static */
+
temp16 = 0x09;
ACPI_MOVE_16_TO_16 (buffer, &temp16);
buffer += 2;
- /*
- * Set the Information Byte
- */
+ /* Set the Information Byte */
+
temp8 = (u8) (linked_list->data.fixed_memory32.read_write_attribute & 0x01);
*buffer = temp8;
buffer += 1;
- /*
- * Set the Range base address
- */
+ /* Set the Range base address */
+
ACPI_MOVE_32_TO_32 (buffer,
- &linked_list->data.fixed_memory32.range_base_address);
+ &linked_list->data.fixed_memory32.range_base_address);
buffer += 4;
- /*
- * Set the range length
- */
+ /* Set the range length */
+
ACPI_MOVE_32_TO_32 (buffer,
- &linked_list->data.fixed_memory32.range_length);
+ &linked_list->data.fixed_memory32.range_length);
buffer += 4;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
diff --git a/drivers/acpi/resources/rsmisc.c b/drivers/acpi/resources/rsmisc.c
index d16be44b5df7..a1f1741f0d83 100644
--- a/drivers/acpi/resources/rsmisc.c
+++ b/drivers/acpi/resources/rsmisc.c
@@ -84,24 +84,20 @@ acpi_rs_end_tag_resource (
ACPI_FUNCTION_TRACE ("rs_end_tag_resource");
- /*
- * The number of bytes consumed is static
- */
+ /* The number of bytes consumed is static */
+
*bytes_consumed = 2;
- /*
- * Fill out the structure
- */
+ /* Fill out the structure */
+
output_struct->id = ACPI_RSTYPE_END_TAG;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = 0;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -136,9 +132,8 @@ acpi_rs_end_tag_stream (
ACPI_FUNCTION_TRACE ("rs_end_tag_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x79;
buffer += 1;
@@ -151,9 +146,8 @@ acpi_rs_end_tag_stream (
*buffer = temp8;
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -192,21 +186,20 @@ acpi_rs_vendor_resource (
u16 temp16 = 0;
u8 temp8 = 0;
u8 index;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_vendor);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_vendor);
ACPI_FUNCTION_TRACE ("rs_vendor_resource");
- /*
- * Dereference the Descriptor to find if this is a large or small item.
- */
+ /* Dereference the Descriptor to find if this is a large or small item. */
+
temp8 = *buffer;
if (temp8 & 0x80) {
- /*
- * Large Item, point to the length field
- */
+ /* Large Item, point to the length field */
+
buffer += 1;
/* Dereference */
@@ -222,9 +215,8 @@ acpi_rs_vendor_resource (
buffer += 2;
}
else {
- /*
- * Small Item, dereference the size
- */
+ /* Small Item, dereference the size */
+
temp16 = (u8)(*buffer & 0x07);
/* Calculate bytes consumed */
@@ -251,14 +243,12 @@ acpi_rs_vendor_resource (
*/
struct_size += ACPI_ROUND_UP_to_32_bITS (temp16);
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -295,13 +285,11 @@ acpi_rs_vendor_stream (
ACPI_FUNCTION_TRACE ("rs_vendor_stream");
- /*
- * Dereference the length to find if this is a large or small item.
- */
+ /* Dereference the length to find if this is a large or small item. */
+
if(linked_list->data.vendor_specific.length > 7) {
- /*
- * Large Item, Set the descriptor field and length bytes
- */
+ /* Large Item, Set the descriptor field and length bytes */
+
*buffer = 0x84;
buffer += 1;
@@ -311,9 +299,8 @@ acpi_rs_vendor_stream (
buffer += 2;
}
else {
- /*
- * Small Item, Set the descriptor field
- */
+ /* Small Item, Set the descriptor field */
+
temp8 = 0x70;
temp8 |= (u8) linked_list->data.vendor_specific.length;
@@ -321,9 +308,8 @@ acpi_rs_vendor_stream (
buffer += 1;
}
- /*
- * Loop through all of the Vendor Specific fields
- */
+ /* Loop through all of the Vendor Specific fields */
+
for (index = 0; index < linked_list->data.vendor_specific.length; index++) {
temp8 = linked_list->data.vendor_specific.reserved[index];
@@ -331,9 +317,8 @@ acpi_rs_vendor_stream (
buffer += 1;
}
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -370,40 +355,37 @@ acpi_rs_start_depend_fns_resource (
u8 *buffer = byte_stream_buffer;
struct acpi_resource *output_struct = (void *) *output_buffer;
u8 temp8 = 0;
- acpi_size struct_size = ACPI_SIZEOF_RESOURCE (struct acpi_resource_start_dpf);
+ acpi_size struct_size = ACPI_SIZEOF_RESOURCE (
+ struct acpi_resource_start_dpf);
ACPI_FUNCTION_TRACE ("rs_start_depend_fns_resource");
- /*
- * The number of bytes consumed are contained in the descriptor (Bits:0-1)
- */
+ /* The number of bytes consumed are found in the descriptor (Bits:0-1) */
+
temp8 = *buffer;
*bytes_consumed = (temp8 & 0x01) + 1;
output_struct->id = ACPI_RSTYPE_START_DPF;
- /*
- * Point to Byte 1 if it is used
- */
+ /* Point to Byte 1 if it is used */
+
if (2 == *bytes_consumed) {
buffer += 1;
temp8 = *buffer;
- /*
- * Check Compatibility priority
- */
+ /* Check Compatibility priority */
+
output_struct->data.start_dpf.compatibility_priority = temp8 & 0x03;
if (3 == output_struct->data.start_dpf.compatibility_priority) {
return_ACPI_STATUS (AE_AML_BAD_RESOURCE_VALUE);
}
- /*
- * Check Performance/Robustness preference
- */
+ /* Check Performance/Robustness preference */
+
output_struct->data.start_dpf.performance_robustness = (temp8 >> 2) & 0x03;
if (3 == output_struct->data.start_dpf.performance_robustness) {
@@ -412,20 +394,18 @@ acpi_rs_start_depend_fns_resource (
}
else {
output_struct->data.start_dpf.compatibility_priority =
- ACPI_ACCEPTABLE_CONFIGURATION;
+ ACPI_ACCEPTABLE_CONFIGURATION;
output_struct->data.start_dpf.performance_robustness =
- ACPI_ACCEPTABLE_CONFIGURATION;
+ ACPI_ACCEPTABLE_CONFIGURATION;
}
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -466,24 +446,20 @@ acpi_rs_end_depend_fns_resource (
ACPI_FUNCTION_TRACE ("rs_end_depend_fns_resource");
- /*
- * The number of bytes consumed is static
- */
+ /* The number of bytes consumed is static */
+
*bytes_consumed = 1;
- /*
- * Fill out the structure
- */
+ /* Fill out the structure */
+
output_struct->id = ACPI_RSTYPE_END_DPF;
- /*
- * Set the Length parameter
- */
+ /* Set the Length parameter */
+
output_struct->length = (u32) struct_size;
- /*
- * Return the final size of the structure
- */
+ /* Return the final size of the structure */
+
*structure_size = struct_size;
return_ACPI_STATUS (AE_OK);
}
@@ -533,9 +509,8 @@ acpi_rs_start_depend_fns_stream (
*buffer = 0x31;
buffer += 1;
- /*
- * Set the Priority Byte Definition
- */
+ /* Set the Priority Byte Definition */
+
temp8 = 0;
temp8 = (u8) ((linked_list->data.start_dpf.performance_robustness &
0x03) << 2);
@@ -546,9 +521,8 @@ acpi_rs_start_depend_fns_stream (
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
@@ -582,15 +556,13 @@ acpi_rs_end_depend_fns_stream (
ACPI_FUNCTION_TRACE ("rs_end_depend_fns_stream");
- /*
- * The descriptor field is static
- */
+ /* The descriptor field is static */
+
*buffer = 0x38;
buffer += 1;
- /*
- * Return the number of bytes consumed in this operation
- */
+ /* Return the number of bytes consumed in this operation */
+
*bytes_consumed = ACPI_PTR_DIFF (buffer, *output_buffer);
return_ACPI_STATUS (AE_OK);
}
diff --git a/drivers/acpi/resources/rsutils.c b/drivers/acpi/resources/rsutils.c
index ee9ce13c053d..700cf7d65d76 100644
--- a/drivers/acpi/resources/rsutils.c
+++ b/drivers/acpi/resources/rsutils.c
@@ -83,10 +83,10 @@ acpi_rs_get_prt_method_data (
/* Parameters guaranteed valid by caller */
- /*
- * Execute the method, no parameters
- */
- status = acpi_ut_evaluate_object (handle, "_PRT", ACPI_BTYPE_PACKAGE, &obj_desc);
+ /* Execute the method, no parameters */
+
+ status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRT,
+ ACPI_BTYPE_PACKAGE, &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -136,10 +136,10 @@ acpi_rs_get_crs_method_data (
/* Parameters guaranteed valid by caller */
- /*
- * Execute the method, no parameters
- */
- status = acpi_ut_evaluate_object (handle, "_CRS", ACPI_BTYPE_BUFFER, &obj_desc);
+ /* Execute the method, no parameters */
+
+ status = acpi_ut_evaluate_object (handle, METHOD_NAME__CRS,
+ ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -175,6 +175,7 @@ acpi_rs_get_crs_method_data (
* and the contents of the callers buffer is undefined.
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_rs_get_prs_method_data (
@@ -190,10 +191,10 @@ acpi_rs_get_prs_method_data (
/* Parameters guaranteed valid by caller */
- /*
- * Execute the method, no parameters
- */
- status = acpi_ut_evaluate_object (handle, "_PRS", ACPI_BTYPE_BUFFER, &obj_desc);
+ /* Execute the method, no parameters */
+
+ status = acpi_ut_evaluate_object (handle, METHOD_NAME__PRS,
+ ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -218,6 +219,7 @@ acpi_rs_get_prs_method_data (
* FUNCTION: acpi_rs_get_method_data
*
* PARAMETERS: Handle - a handle to the containing object
+ * Path - Path to method, relative to Handle
* ret_buffer - a pointer to a buffer structure for the
* results
*
@@ -246,9 +248,8 @@ acpi_rs_get_method_data (
/* Parameters guaranteed valid by caller */
- /*
- * Execute the method, no parameters
- */
+ /* Execute the method, no parameters */
+
status = acpi_ut_evaluate_object (handle, path, ACPI_BTYPE_BUFFER, &obj_desc);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
@@ -314,18 +315,16 @@ acpi_rs_set_srs_method_data (
return_ACPI_STATUS (status);
}
- /*
- * Init the param object
- */
+ /* Init the param object */
+
params[0] = acpi_ut_create_internal_object (ACPI_TYPE_BUFFER);
if (!params[0]) {
acpi_os_free (buffer.pointer);
return_ACPI_STATUS (AE_NO_MEMORY);
}
- /*
- * Set up the parameter object
- */
+ /* Set up the parameter object */
+
params[0]->buffer.length = (u32) buffer.length;
params[0]->buffer.pointer = buffer.pointer;
params[0]->common.flags = AOPOBJ_DATA_VALID;
@@ -335,10 +334,9 @@ acpi_rs_set_srs_method_data (
info.parameters = params;
info.parameter_type = ACPI_PARAM_ARGS;
- /*
- * Execute the method, no return value
- */
- status = acpi_ns_evaluate_relative ("_SRS", &info);
+ /* Execute the method, no return value */
+
+ status = acpi_ns_evaluate_relative (METHOD_NAME__SRS, &info);
if (ACPI_SUCCESS (status)) {
/* Delete any return object (especially if implicit_return is enabled) */
@@ -347,9 +345,8 @@ acpi_rs_set_srs_method_data (
}
}
- /*
- * Clean up and return the status from acpi_ns_evaluate_relative
- */
+ /* Clean up and return the status from acpi_ns_evaluate_relative */
+
acpi_ut_remove_reference (params[0]);
return_ACPI_STATUS (status);
}
diff --git a/drivers/acpi/resources/rsxface.c b/drivers/acpi/resources/rsxface.c
index a9cdcbeb3432..83c944b8b097 100644
--- a/drivers/acpi/resources/rsxface.c
+++ b/drivers/acpi/resources/rsxface.c
@@ -49,6 +49,23 @@
#define _COMPONENT ACPI_RESOURCES
ACPI_MODULE_NAME ("rsxface")
+/* Local macros for 16,32-bit to 64-bit conversion */
+
+#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field)
+#define ACPI_COPY_ADDRESS(out, in) \
+ ACPI_COPY_FIELD(out, in, resource_type); \
+ ACPI_COPY_FIELD(out, in, producer_consumer); \
+ ACPI_COPY_FIELD(out, in, decode); \
+ ACPI_COPY_FIELD(out, in, min_address_fixed); \
+ ACPI_COPY_FIELD(out, in, max_address_fixed); \
+ ACPI_COPY_FIELD(out, in, attribute); \
+ ACPI_COPY_FIELD(out, in, granularity); \
+ ACPI_COPY_FIELD(out, in, min_address_range); \
+ ACPI_COPY_FIELD(out, in, max_address_range); \
+ ACPI_COPY_FIELD(out, in, address_translation_offset); \
+ ACPI_COPY_FIELD(out, in, address_length); \
+ ACPI_COPY_FIELD(out, in, resource_source);
+
/*******************************************************************************
*
@@ -180,6 +197,7 @@ EXPORT_SYMBOL(acpi_get_current_resources);
* and the value of ret_buffer is undefined.
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_get_possible_resources (
@@ -346,9 +364,8 @@ acpi_set_current_resources (
ACPI_FUNCTION_TRACE ("acpi_set_current_resources");
- /*
- * Must have a valid handle and buffer
- */
+ /* Must have a valid handle and buffer */
+
if ((!device_handle) ||
(!in_buffer) ||
(!in_buffer->pointer) ||
@@ -362,21 +379,6 @@ acpi_set_current_resources (
EXPORT_SYMBOL(acpi_set_current_resources);
-#define ACPI_COPY_FIELD(out, in, field) ((out)->field = (in)->field)
-#define ACPI_COPY_ADDRESS(out, in) \
- ACPI_COPY_FIELD(out, in, resource_type); \
- ACPI_COPY_FIELD(out, in, producer_consumer); \
- ACPI_COPY_FIELD(out, in, decode); \
- ACPI_COPY_FIELD(out, in, min_address_fixed); \
- ACPI_COPY_FIELD(out, in, max_address_fixed); \
- ACPI_COPY_FIELD(out, in, attribute); \
- ACPI_COPY_FIELD(out, in, granularity); \
- ACPI_COPY_FIELD(out, in, min_address_range); \
- ACPI_COPY_FIELD(out, in, max_address_range); \
- ACPI_COPY_FIELD(out, in, address_translation_offset); \
- ACPI_COPY_FIELD(out, in, address_length); \
- ACPI_COPY_FIELD(out, in, resource_source);
-
/******************************************************************************
*
* FUNCTION: acpi_resource_to_address64
@@ -408,14 +410,14 @@ acpi_resource_to_address64 (
case ACPI_RSTYPE_ADDRESS16:
address16 = (struct acpi_resource_address16 *) &resource->data;
- ACPI_COPY_ADDRESS(out, address16);
+ ACPI_COPY_ADDRESS (out, address16);
break;
case ACPI_RSTYPE_ADDRESS32:
address32 = (struct acpi_resource_address32 *) &resource->data;
- ACPI_COPY_ADDRESS(out, address32);
+ ACPI_COPY_ADDRESS (out, address32);
break;
@@ -434,4 +436,3 @@ acpi_resource_to_address64 (
return (AE_OK);
}
EXPORT_SYMBOL(acpi_resource_to_address64);
-
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index e85885593280..cbcda30c172d 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -553,20 +553,29 @@ acpi_bus_driver_init (
* upon possible configuration and currently allocated resources.
*/
+ ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
+ return_VALUE(0);
+}
+
+int
+acpi_start_single_object (
+ struct acpi_device *device)
+{
+ int result = 0;
+ struct acpi_driver *driver;
+
+ ACPI_FUNCTION_TRACE("acpi_start_single_object");
+
+ if (!(driver = device->driver))
+ return_VALUE(0);
+
if (driver->ops.start) {
result = driver->ops.start(device);
if (result && driver->ops.remove)
driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
- return_VALUE(result);
- }
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
-
- if (driver->ops.scan) {
- driver->ops.scan(device);
}
- return_VALUE(0);
+ return_VALUE(result);
}
static int acpi_driver_attach(struct acpi_driver * drv)
@@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv)
if (!acpi_bus_match(dev, drv)) {
if (!acpi_bus_driver_init(dev, drv)) {
+ acpi_start_single_object(dev);
atomic_inc(&drv->references);
count++;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
@@ -1009,8 +1019,8 @@ acpi_bus_remove (
}
-int
-acpi_bus_add (
+static int
+acpi_add_single_object (
struct acpi_device **child,
struct acpi_device *parent,
acpi_handle handle,
@@ -1019,7 +1029,7 @@ acpi_bus_add (
int result = 0;
struct acpi_device *device = NULL;
- ACPI_FUNCTION_TRACE("acpi_bus_add");
+ ACPI_FUNCTION_TRACE("acpi_add_single_object");
if (!child)
return_VALUE(-EINVAL);
@@ -1051,13 +1061,15 @@ acpi_bus_add (
/*
* Status
* ------
- * See if the device is present. We always assume that non-Device()
- * objects (e.g. thermal zones, power resources, processors, etc.) are
- * present, functioning, etc. (at least when parent object is present).
- * Note that _STA has a different meaning for some objects (e.g.
- * power resources) so we need to be careful how we use it.
+ * See if the device is present. We always assume that non-Device
+ * and non-Processor objects (e.g. thermal zones, power resources,
+ * etc.) are present, functioning, etc. (at least when parent object
+ * is present). Note that _STA has a different meaning for some
+ * objects (e.g. power resources) so we need to be careful how we use
+ * it.
*/
switch (type) {
+ case ACPI_BUS_TYPE_PROCESSOR:
case ACPI_BUS_TYPE_DEVICE:
result = acpi_bus_get_status(device);
if (ACPI_FAILURE(result) || !device->status.present) {
@@ -1140,7 +1152,7 @@ acpi_bus_add (
*
* TBD: Assumes LDM provides driver hot-plug capability.
*/
- acpi_bus_find_driver(device);
+ result = acpi_bus_find_driver(device);
end:
if (!result)
@@ -1153,10 +1165,10 @@ end:
return_VALUE(result);
}
-EXPORT_SYMBOL(acpi_bus_add);
-int acpi_bus_scan (struct acpi_device *start)
+static int acpi_bus_scan (struct acpi_device *start,
+ struct acpi_bus_ops *ops)
{
acpi_status status = AE_OK;
struct acpi_device *parent = NULL;
@@ -1229,9 +1241,20 @@ int acpi_bus_scan (struct acpi_device *start)
continue;
}
- status = acpi_bus_add(&child, parent, chandle, type);
- if (ACPI_FAILURE(status))
- continue;
+ if (ops->acpi_op_add)
+ status = acpi_add_single_object(&child, parent,
+ chandle, type);
+ else
+ status = acpi_bus_get_device(chandle, &child);
+
+ if (ACPI_FAILURE(status))
+ continue;
+
+ if (ops->acpi_op_start) {
+ status = acpi_start_single_object(child);
+ if (ACPI_FAILURE(status))
+ continue;
+ }
/*
* If the device is present, enabled, and functioning then
@@ -1257,8 +1280,50 @@ int acpi_bus_scan (struct acpi_device *start)
return_VALUE(0);
}
-EXPORT_SYMBOL(acpi_bus_scan);
+int
+acpi_bus_add (
+ struct acpi_device **child,
+ struct acpi_device *parent,
+ acpi_handle handle,
+ int type)
+{
+ int result;
+ struct acpi_bus_ops ops;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_add");
+
+ result = acpi_add_single_object(child, parent, handle, type);
+ if (!result) {
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ result = acpi_bus_scan(*child, &ops);
+ }
+ return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_add);
+
+int
+acpi_bus_start (
+ struct acpi_device *device)
+{
+ int result;
+ struct acpi_bus_ops ops;
+
+ ACPI_FUNCTION_TRACE("acpi_bus_start");
+
+ if (!device)
+ return_VALUE(-EINVAL);
+
+ result = acpi_start_single_object(device);
+ if (!result) {
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_start = 1;
+ result = acpi_bus_scan(device, &ops);
+ }
+ return_VALUE(result);
+}
+EXPORT_SYMBOL(acpi_bus_start);
static int
acpi_bus_trim(struct acpi_device *start,
@@ -1331,13 +1396,19 @@ acpi_bus_scan_fixed (
/*
* Enumerate all fixed-feature devices.
*/
- if (acpi_fadt.pwr_button == 0)
- result = acpi_bus_add(&device, acpi_root,
+ if (acpi_fadt.pwr_button == 0) {
+ result = acpi_add_single_object(&device, acpi_root,
NULL, ACPI_BUS_TYPE_POWER_BUTTON);
+ if (!result)
+ result = acpi_start_single_object(device);
+ }
- if (acpi_fadt.sleep_button == 0)
- result = acpi_bus_add(&device, acpi_root,
+ if (acpi_fadt.sleep_button == 0) {
+ result = acpi_add_single_object(&device, acpi_root,
NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
+ if (!result)
+ result = acpi_start_single_object(device);
+ }
return_VALUE(result);
}
@@ -1346,6 +1417,7 @@ acpi_bus_scan_fixed (
static int __init acpi_scan_init(void)
{
int result;
+ struct acpi_bus_ops ops;
ACPI_FUNCTION_TRACE("acpi_scan_init");
@@ -1357,17 +1429,23 @@ static int __init acpi_scan_init(void)
/*
* Create the root device in the bus's device tree
*/
- result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT,
+ result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
ACPI_BUS_TYPE_SYSTEM);
if (result)
goto Done;
+ result = acpi_start_single_object(acpi_root);
+
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
- if (!result)
- result = acpi_bus_scan(acpi_root);
+ if (!result) {
+ memset(&ops, 0, sizeof(ops));
+ ops.acpi_op_add = 1;
+ ops.acpi_op_start = 1;
+ result = acpi_bus_scan(acpi_root, &ops);
+ }
if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
diff --git a/drivers/acpi/sleep/main.c b/drivers/acpi/sleep/main.c
index 0a5d2a94131e..7249ba2b7a27 100644
--- a/drivers/acpi/sleep/main.c
+++ b/drivers/acpi/sleep/main.c
@@ -1,6 +1,7 @@
/*
* sleep.c - ACPI sleep support.
*
+ * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
* Copyright (c) 2004 David Shaohua Li <shaohua.li@intel.com>
* Copyright (c) 2000-2003 Patrick Mochel
* Copyright (c) 2003 Open Source Development Lab
@@ -14,7 +15,6 @@
#include <linux/dmi.h>
#include <linux/device.h>
#include <linux/suspend.h>
-#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
#include "sleep.h"
@@ -27,10 +27,11 @@ extern void do_suspend_lowlevel_s4bios(void);
extern void do_suspend_lowlevel(void);
static u32 acpi_suspend_states[] = {
- [PM_SUSPEND_ON] = ACPI_STATE_S0,
- [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
- [PM_SUSPEND_MEM] = ACPI_STATE_S3,
- [PM_SUSPEND_DISK] = ACPI_STATE_S4,
+ [PM_SUSPEND_ON] = ACPI_STATE_S0,
+ [PM_SUSPEND_STANDBY] = ACPI_STATE_S1,
+ [PM_SUSPEND_MEM] = ACPI_STATE_S3,
+ [PM_SUSPEND_DISK] = ACPI_STATE_S4,
+ [PM_SUSPEND_MAX] = ACPI_STATE_S5
};
static int init_8259A_after_S1;
@@ -44,30 +45,20 @@ static int init_8259A_after_S1;
* wakeup code to the waking vector.
*/
+extern int acpi_sleep_prepare(u32 acpi_state);
+extern void acpi_power_off(void);
+
static int acpi_pm_prepare(suspend_state_t pm_state)
{
u32 acpi_state = acpi_suspend_states[pm_state];
- if (!sleep_states[acpi_state])
+ if (!sleep_states[acpi_state]) {
+ printk("acpi_pm_prepare does not support %d \n", pm_state);
return -EPERM;
-
- /* 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 (pm_state == PM_SUSPEND_MEM || pm_state == PM_SUSPEND_DISK) {
- if (!acpi_wakeup_address)
- return -EFAULT;
- acpi_set_firmware_waking_vector(
- (acpi_physical_address) virt_to_phys(
- (void *)acpi_wakeup_address));
}
- ACPI_FLUSH_CPU_CACHE();
- acpi_enable_wakeup_device_prep(acpi_state);
- acpi_enter_sleep_state_prep(acpi_state);
- return 0;
+ return acpi_sleep_prepare(acpi_state);
}
-
/**
* acpi_pm_enter - Actually enter a sleep state.
* @pm_state: State we're entering.
@@ -92,11 +83,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
return error;
}
-
local_irq_save(flags);
acpi_enable_wakeup_device(acpi_state);
- switch (pm_state)
- {
+ switch (pm_state) {
case PM_SUSPEND_STANDBY:
barrier();
status = acpi_enter_sleep_state(acpi_state);
@@ -112,6 +101,10 @@ static int acpi_pm_enter(suspend_state_t pm_state)
else
do_suspend_lowlevel_s4bios();
break;
+ case PM_SUSPEND_MAX:
+ acpi_power_off();
+ break;
+
default:
return -EINVAL;
}
@@ -126,11 +119,9 @@ static int acpi_pm_enter(suspend_state_t pm_state)
if (pm_state > PM_SUSPEND_STANDBY)
acpi_restore_state_mem();
-
return ACPI_SUCCESS(status) ? 0 : -EFAULT;
}
-
/**
* acpi_pm_finish - Finish up suspend sequence.
* @pm_state: State we're coming out of.
@@ -156,27 +147,26 @@ static int acpi_pm_finish(suspend_state_t pm_state)
return 0;
}
-
int acpi_suspend(u32 acpi_state)
{
suspend_state_t states[] = {
- [1] = PM_SUSPEND_STANDBY,
- [3] = PM_SUSPEND_MEM,
- [4] = PM_SUSPEND_DISK,
+ [1] = PM_SUSPEND_STANDBY,
+ [3] = PM_SUSPEND_MEM,
+ [4] = PM_SUSPEND_DISK,
+ [5] = PM_SUSPEND_MAX
};
- if (acpi_state <= 4 && states[acpi_state])
+ if (acpi_state < 6 && states[acpi_state])
return pm_suspend(states[acpi_state]);
return -EINVAL;
}
static struct pm_ops acpi_pm_ops = {
- .prepare = acpi_pm_prepare,
- .enter = acpi_pm_enter,
- .finish = acpi_pm_finish,
+ .prepare = acpi_pm_prepare,
+ .enter = acpi_pm_enter,
+ .finish = acpi_pm_finish,
};
-
/*
* Toshiba fails to preserve interrupts over S1, reinitialization
* of 8259 is needed after S1 resume.
@@ -190,16 +180,16 @@ static int __init init_ints_after_s1(struct dmi_system_id *d)
static struct dmi_system_id __initdata acpisleep_dmi_table[] = {
{
- .callback = init_ints_after_s1,
- .ident = "Toshiba Satellite 4030cdt",
- .matches = { DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), },
- },
- { },
+ .callback = init_ints_after_s1,
+ .ident = "Toshiba Satellite 4030cdt",
+ .matches = {DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"),},
+ },
+ {},
};
static int __init acpi_sleep_init(void)
{
- int i = 0;
+ int i = 0;
dmi_check_system(acpisleep_dmi_table);
@@ -207,7 +197,7 @@ static int __init acpi_sleep_init(void)
return 0;
printk(KERN_INFO PREFIX "(supports");
- for (i=0; i < ACPI_S_STATE_COUNT; i++) {
+ for (i = 0; i < ACPI_S_STATE_COUNT; i++) {
acpi_status status;
u8 type_a, type_b;
status = acpi_get_sleep_type_data(i, &type_a, &type_b);
diff --git a/drivers/acpi/sleep/poweroff.c b/drivers/acpi/sleep/poweroff.c
index da237754ded9..1fc86e6b5ab9 100644
--- a/drivers/acpi/sleep/poweroff.c
+++ b/drivers/acpi/sleep/poweroff.c
@@ -3,35 +3,100 @@
*
* AKA S5, but it is independent of whether or not the kernel supports
* any other sleep support in the system.
+ *
+ * Copyright (c) 2005 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
+ *
+ * This file is released under the GPLv2.
*/
#include <linux/pm.h>
#include <linux/init.h>
#include <acpi/acpi_bus.h>
#include <linux/sched.h>
+#include <linux/sysdev.h>
+#include <asm/io.h>
#include "sleep.h"
-static void
-acpi_power_off (void)
+int acpi_sleep_prepare(u32 acpi_state)
+{
+ /* Flag to do not allow second time invocation for S5 state */
+ static int shutdown_prepared = 0;
+#ifdef CONFIG_ACPI_SLEEP
+ /* 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 (acpi_state == ACPI_STATE_S3 || acpi_state == ACPI_STATE_S4) {
+ if (!acpi_wakeup_address) {
+ return -EFAULT;
+ }
+ acpi_set_firmware_waking_vector((acpi_physical_address)
+ virt_to_phys((void *)
+ acpi_wakeup_address));
+
+ }
+ ACPI_FLUSH_CPU_CACHE();
+ acpi_enable_wakeup_device_prep(acpi_state);
+#endif
+ if (acpi_state == ACPI_STATE_S5) {
+ /* Check if we were already called */
+ if (shutdown_prepared)
+ return 0;
+ acpi_wakeup_gpe_poweroff_prepare();
+ shutdown_prepared = 1;
+ }
+ acpi_enter_sleep_state_prep(acpi_state);
+ return 0;
+}
+
+void acpi_power_off(void)
{
- printk("%s called\n",__FUNCTION__);
+ printk("%s called\n", __FUNCTION__);
+ acpi_sleep_prepare(ACPI_STATE_S5);
+ local_irq_disable();
/* Some SMP machines only can poweroff in boot CPU */
set_cpus_allowed(current, cpumask_of_cpu(0));
- acpi_wakeup_gpe_poweroff_prepare();
- acpi_enter_sleep_state_prep(ACPI_STATE_S5);
- ACPI_DISABLE_IRQS();
acpi_enter_sleep_state(ACPI_STATE_S5);
}
+#ifdef CONFIG_PM
+
+static int acpi_shutdown(struct sys_device *x)
+{
+ return acpi_sleep_prepare(ACPI_STATE_S5);
+}
+
+static struct sysdev_class acpi_sysclass = {
+ set_kset_name("acpi"),
+ .shutdown = acpi_shutdown
+};
+
+static struct sys_device device_acpi = {
+ .id = 0,
+ .cls = &acpi_sysclass,
+};
+
+#endif
+
static int acpi_poweroff_init(void)
{
if (!acpi_disabled) {
u8 type_a, type_b;
acpi_status status;
- status = acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
- if (ACPI_SUCCESS(status))
+ status =
+ acpi_get_sleep_type_data(ACPI_STATE_S5, &type_a, &type_b);
+ if (ACPI_SUCCESS(status)) {
pm_power_off = acpi_power_off;
+#ifdef CONFIG_PM
+ {
+ int error;
+ error = sysdev_class_register(&acpi_sysclass);
+ if (!error)
+ error = sysdev_register(&device_acpi);
+ return error;
+ }
+#endif
+ }
}
return 0;
}
diff --git a/drivers/acpi/sleep/proc.c b/drivers/acpi/sleep/proc.c
index fd7c5a0649af..1be99f0996d6 100644
--- a/drivers/acpi/sleep/proc.c
+++ b/drivers/acpi/sleep/proc.c
@@ -13,13 +13,17 @@
#include "sleep.h"
+#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
#define ACPI_SYSTEM_FILE_SLEEP "sleep"
+#endif
+
#define ACPI_SYSTEM_FILE_ALARM "alarm"
#define ACPI_SYSTEM_FILE_WAKEUP_DEVICE "wakeup"
#define _COMPONENT ACPI_SYSTEM_COMPONENT
ACPI_MODULE_NAME ("sleep")
+#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
static int acpi_system_sleep_seq_show(struct seq_file *seq, void *offset)
{
@@ -78,6 +82,7 @@ acpi_system_write_sleep (
Done:
return error ? error : count;
}
+#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
{
@@ -452,6 +457,7 @@ static struct file_operations acpi_system_wakeup_device_fops = {
.release = single_release,
};
+#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
static struct file_operations acpi_system_sleep_fops = {
.open = acpi_system_sleep_open_fs,
.read = seq_read,
@@ -459,6 +465,7 @@ static struct file_operations acpi_system_sleep_fops = {
.llseek = seq_lseek,
.release = single_release,
};
+#endif /* CONFIG_ACPI_SLEEP_PROC_SLEEP */
static struct file_operations acpi_system_alarm_fops = {
.open = acpi_system_alarm_open_fs,
@@ -484,11 +491,13 @@ static int acpi_sleep_proc_init(void)
if (acpi_disabled)
return 0;
+#ifdef CONFIG_ACPI_SLEEP_PROC_SLEEP
/* 'sleep' [R/W]*/
entry = create_proc_entry(ACPI_SYSTEM_FILE_SLEEP,
S_IFREG|S_IRUGO|S_IWUSR, acpi_root_dir);
if (entry)
entry->proc_fops = &acpi_system_sleep_fops;
+#endif
/* 'alarm' [R/W] */
entry = create_proc_entry(ACPI_SYSTEM_FILE_ALARM,
diff --git a/drivers/acpi/tables/tbconvrt.c b/drivers/acpi/tables/tbconvrt.c
index 334327c1f66f..92e0c31539be 100644
--- a/drivers/acpi/tables/tbconvrt.c
+++ b/drivers/acpi/tables/tbconvrt.c
@@ -50,6 +50,24 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbconvrt")
+/* Local prototypes */
+
+static void
+acpi_tb_init_generic_address (
+ struct acpi_generic_address *new_gas_struct,
+ u8 register_bit_width,
+ acpi_physical_address address);
+
+static void
+acpi_tb_convert_fadt1 (
+ struct fadt_descriptor_rev2 *local_fadt,
+ struct fadt_descriptor_rev1 *original_fadt);
+
+static void
+acpi_tb_convert_fadt2 (
+ struct fadt_descriptor_rev2 *local_fadt,
+ struct fadt_descriptor_rev2 *original_fadt);
+
u8 acpi_fadt_is_v1;
EXPORT_SYMBOL(acpi_fadt_is_v1);
@@ -142,11 +160,13 @@ acpi_tb_convert_to_xsdt (
for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
if (acpi_gbl_RSDP->revision < 2) {
ACPI_STORE_ADDRESS (new_table->table_offset_entry[i],
- (ACPI_CAST_PTR (struct rsdt_descriptor_rev1, table_info->pointer))->table_offset_entry[i]);
+ (ACPI_CAST_PTR (struct rsdt_descriptor_rev1,
+ table_info->pointer))->table_offset_entry[i]);
}
else {
new_table->table_offset_entry[i] =
- (ACPI_CAST_PTR (XSDT_DESCRIPTOR, table_info->pointer))->table_offset_entry[i];
+ (ACPI_CAST_PTR (XSDT_DESCRIPTOR,
+ table_info->pointer))->table_offset_entry[i];
}
}
@@ -164,7 +184,7 @@ acpi_tb_convert_to_xsdt (
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_tb_init_generic_address
*
@@ -201,7 +221,7 @@ acpi_tb_init_generic_address (
* PARAMETERS: local_fadt - Pointer to new FADT
* original_fadt - Pointer to old FADT
*
- * RETURN: Populates local_fadt
+ * RETURN: None, populates local_fadt
*
* DESCRIPTION: Convert an ACPI 1.0 FADT to common internal format
*
@@ -213,7 +233,6 @@ acpi_tb_convert_fadt1 (
struct fadt_descriptor_rev1 *original_fadt)
{
-
/* ACPI 1.0 FACS */
/* The BIOS stored FADT should agree with Revision 1.0 */
acpi_fadt_is_v1 = 1;
@@ -232,7 +251,8 @@ acpi_tb_convert_fadt1 (
ACPI_STORE_ADDRESS (local_fadt->Xdsdt, local_fadt->V1_dsdt);
/*
- * System Interrupt Model isn't used in ACPI 2.0 (local_fadt->Reserved1 = 0;)
+ * System Interrupt Model isn't used in ACPI 2.0
+ * (local_fadt->Reserved1 = 0;)
*/
/*
@@ -269,7 +289,8 @@ acpi_tb_convert_fadt1 (
* that immediately follows.
*/
ACPI_MEMCPY (&local_fadt->reset_register,
- &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus, original_fadt))->reset_register,
+ &(ACPI_CAST_PTR (struct fadt_descriptor_rev2_minus,
+ original_fadt))->reset_register,
sizeof (struct acpi_generic_address) + 1);
}
else {
@@ -304,7 +325,8 @@ acpi_tb_convert_fadt1 (
acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable,
(u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
- (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address +
+ (acpi_physical_address)
+ (local_fadt->xpm1a_evt_blk.address +
ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
/* PM1B is optional; leave null if not present */
@@ -312,7 +334,8 @@ acpi_tb_convert_fadt1 (
if (local_fadt->xpm1b_evt_blk.address) {
acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable,
(u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
- (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address +
+ (acpi_physical_address)
+ (local_fadt->xpm1b_evt_blk.address +
ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
}
}
@@ -325,7 +348,7 @@ acpi_tb_convert_fadt1 (
* PARAMETERS: local_fadt - Pointer to new FADT
* original_fadt - Pointer to old FADT
*
- * RETURN: Populates local_fadt
+ * RETURN: None, populates local_fadt
*
* DESCRIPTION: Convert an ACPI 2.0 FADT to common internal format.
* Handles optional "X" fields.
@@ -348,7 +371,8 @@ acpi_tb_convert_fadt2 (
* is zero.
*/
if (!(local_fadt->xfirmware_ctrl)) {
- ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl, local_fadt->V1_firmware_ctrl);
+ ACPI_STORE_ADDRESS (local_fadt->xfirmware_ctrl,
+ local_fadt->V1_firmware_ctrl);
}
if (!(local_fadt->Xdsdt)) {
@@ -357,32 +381,38 @@ acpi_tb_convert_fadt2 (
if (!(local_fadt->xpm1a_evt_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm1a_evt_blk,
- local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1a_evt_blk);
+ local_fadt->pm1_evt_len,
+ (acpi_physical_address) local_fadt->V1_pm1a_evt_blk);
}
if (!(local_fadt->xpm1b_evt_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm1b_evt_blk,
- local_fadt->pm1_evt_len, (acpi_physical_address) local_fadt->V1_pm1b_evt_blk);
+ local_fadt->pm1_evt_len,
+ (acpi_physical_address) local_fadt->V1_pm1b_evt_blk);
}
if (!(local_fadt->xpm1a_cnt_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm1a_cnt_blk,
- local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk);
+ local_fadt->pm1_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm1a_cnt_blk);
}
if (!(local_fadt->xpm1b_cnt_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm1b_cnt_blk,
- local_fadt->pm1_cnt_len, (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk);
+ local_fadt->pm1_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm1b_cnt_blk);
}
if (!(local_fadt->xpm2_cnt_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm2_cnt_blk,
- local_fadt->pm2_cnt_len, (acpi_physical_address) local_fadt->V1_pm2_cnt_blk);
+ local_fadt->pm2_cnt_len,
+ (acpi_physical_address) local_fadt->V1_pm2_cnt_blk);
}
if (!(local_fadt->xpm_tmr_blk.address)) {
acpi_tb_init_generic_address (&local_fadt->xpm_tmr_blk,
- local_fadt->pm_tm_len, (acpi_physical_address) local_fadt->V1_pm_tmr_blk);
+ local_fadt->pm_tm_len,
+ (acpi_physical_address) local_fadt->V1_pm_tmr_blk);
}
if (!(local_fadt->xgpe0_blk.address)) {
@@ -399,18 +429,24 @@ acpi_tb_convert_fadt2 (
acpi_tb_init_generic_address (&acpi_gbl_xpm1a_enable,
(u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
- (acpi_physical_address) (local_fadt->xpm1a_evt_blk.address +
+ (acpi_physical_address)
+ (local_fadt->xpm1a_evt_blk.address +
ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
- acpi_gbl_xpm1a_enable.address_space_id = local_fadt->xpm1a_evt_blk.address_space_id;
+
+ acpi_gbl_xpm1a_enable.address_space_id =
+ local_fadt->xpm1a_evt_blk.address_space_id;
/* PM1B is optional; leave null if not present */
if (local_fadt->xpm1b_evt_blk.address) {
acpi_tb_init_generic_address (&acpi_gbl_xpm1b_enable,
(u8) ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len),
- (acpi_physical_address) (local_fadt->xpm1b_evt_blk.address +
+ (acpi_physical_address)
+ (local_fadt->xpm1b_evt_blk.address +
ACPI_DIV_2 (acpi_gbl_FADT->pm1_evt_len)));
- acpi_gbl_xpm1b_enable.address_space_id = local_fadt->xpm1b_evt_blk.address_space_id;
+
+ acpi_gbl_xpm1b_enable.address_space_id =
+ local_fadt->xpm1b_evt_blk.address_space_id;
}
}
@@ -432,7 +468,8 @@ acpi_tb_convert_fadt2 (
******************************************************************************/
acpi_status
-acpi_tb_convert_table_fadt (void)
+acpi_tb_convert_table_fadt (
+ void)
{
struct fadt_descriptor_rev2 *local_fadt;
struct acpi_table_desc *table_desc;
@@ -446,7 +483,8 @@ acpi_tb_convert_table_fadt (void)
* at least as long as the version 1.0 FADT
*/
if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev1)) {
- ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n", acpi_gbl_FADT->length));
+ ACPI_REPORT_ERROR (("FADT is invalid, too short: 0x%X\n",
+ acpi_gbl_FADT->length));
return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
}
@@ -461,8 +499,9 @@ acpi_tb_convert_table_fadt (void)
if (acpi_gbl_FADT->length < sizeof (struct fadt_descriptor_rev2)) {
/* Length is too short to be a V2.0 table */
- ACPI_REPORT_WARNING (("Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n",
- acpi_gbl_FADT->length, acpi_gbl_FADT->revision));
+ ACPI_REPORT_WARNING ((
+ "Inconsistent FADT length (0x%X) and revision (0x%X), using FADT V1.0 portion of table\n",
+ acpi_gbl_FADT->length, acpi_gbl_FADT->revision));
acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT);
}
@@ -478,9 +517,8 @@ acpi_tb_convert_table_fadt (void)
acpi_tb_convert_fadt1 (local_fadt, (void *) acpi_gbl_FADT);
}
- /*
- * Global FADT pointer will point to the new common V2.0 FADT
- */
+ /* Global FADT pointer will point to the new common V2.0 FADT */
+
acpi_gbl_FADT = local_fadt;
acpi_gbl_FADT->length = sizeof (FADT_DESCRIPTOR);
@@ -508,7 +546,7 @@ acpi_tb_convert_table_fadt (void)
/*******************************************************************************
*
- * FUNCTION: acpi_tb_convert_table_facs
+ * FUNCTION: acpi_tb_build_common_facs
*
* PARAMETERS: table_info - Info for currently installed FACS
*
@@ -530,12 +568,14 @@ acpi_tb_build_common_facs (
/* Absolute minimum length is 24, but the ACPI spec says 64 */
if (acpi_gbl_FACS->length < 24) {
- ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n", acpi_gbl_FACS->length));
+ ACPI_REPORT_ERROR (("Invalid FACS table length: 0x%X\n",
+ acpi_gbl_FACS->length));
return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
}
if (acpi_gbl_FACS->length < 64) {
- ACPI_REPORT_WARNING (("FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n",
+ ACPI_REPORT_WARNING ((
+ "FACS is shorter than the ACPI specification allows: 0x%X, using anyway\n",
acpi_gbl_FACS->length));
}
@@ -548,7 +588,8 @@ acpi_tb_build_common_facs (
(!(acpi_gbl_FACS->xfirmware_waking_vector))) {
/* ACPI 1.0 FACS or short table or optional X_ field is zero */
- acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64, &(acpi_gbl_FACS->firmware_waking_vector));
+ acpi_gbl_common_fACS.firmware_waking_vector = ACPI_CAST_PTR (u64,
+ &(acpi_gbl_FACS->firmware_waking_vector));
acpi_gbl_common_fACS.vector_width = 32;
}
else {
diff --git a/drivers/acpi/tables/tbget.c b/drivers/acpi/tables/tbget.c
index 896f3ddda62e..4ab2aadc6133 100644
--- a/drivers/acpi/tables/tbget.c
+++ b/drivers/acpi/tables/tbget.c
@@ -49,6 +49,19 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbget")
+/* Local prototypes */
+
+static acpi_status
+acpi_tb_get_this_table (
+ struct acpi_pointer *address,
+ struct acpi_table_header *header,
+ struct acpi_table_desc *table_info);
+
+static acpi_status
+acpi_tb_table_override (
+ struct acpi_table_header *header,
+ struct acpi_table_desc *table_info);
+
/*******************************************************************************
*
@@ -76,9 +89,8 @@ acpi_tb_get_table (
ACPI_FUNCTION_TRACE ("tb_get_table");
- /*
- * Get the header in order to get signature and table size
- */
+ /* Get the header in order to get signature and table size */
+
status = acpi_tb_get_table_header (address, &header);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
@@ -127,8 +139,8 @@ acpi_tb_get_table_header (
/*
- * Flags contains the current processor mode (Virtual or Physical addressing)
- * The pointer_type is either Logical or Physical
+ * Flags contains the current processor mode (Virtual or Physical
+ * addressing) The pointer_type is either Logical or Physical
*/
switch (address->pointer_type) {
case ACPI_PHYSMODE_PHYSPTR:
@@ -136,7 +148,8 @@ acpi_tb_get_table_header (
/* Pointer matches processor mode, copy the header */
- ACPI_MEMCPY (return_header, address->pointer.logical, sizeof (struct acpi_table_header));
+ ACPI_MEMCPY (return_header, address->pointer.logical,
+ sizeof (struct acpi_table_header));
break;
@@ -144,10 +157,11 @@ acpi_tb_get_table_header (
/* Create a logical address for the physical pointer*/
- status = acpi_os_map_memory (address->pointer.physical, sizeof (struct acpi_table_header),
- (void *) &header);
+ status = acpi_os_map_memory (address->pointer.physical,
+ sizeof (struct acpi_table_header), (void *) &header);
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("Could not map memory at %8.8X%8.8X for length %X\n",
+ ACPI_REPORT_ERROR ((
+ "Could not map memory at %8.8X%8.8X for length %X\n",
ACPI_FORMAT_UINT64 (address->pointer.physical),
sizeof (struct acpi_table_header)));
return_ACPI_STATUS (status);
@@ -210,9 +224,8 @@ acpi_tb_get_table_body (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
- /*
- * Attempt table override.
- */
+ /* Attempt table override. */
+
status = acpi_tb_table_override (header, table_info);
if (ACPI_SUCCESS (status)) {
/* Table was overridden by the host OS */
@@ -241,7 +254,7 @@ acpi_tb_get_table_body (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_table_override (
struct acpi_table_header *header,
struct acpi_table_desc *table_info)
@@ -315,7 +328,7 @@ acpi_tb_table_override (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_get_this_table (
struct acpi_pointer *address,
struct acpi_table_header *header,
@@ -330,8 +343,8 @@ acpi_tb_get_this_table (
/*
- * Flags contains the current processor mode (Virtual or Physical addressing)
- * The pointer_type is either Logical or Physical
+ * Flags contains the current processor mode (Virtual or Physical
+ * addressing) The pointer_type is either Logical or Physical
*/
switch (address->pointer_type) {
case ACPI_PHYSMODE_PHYSPTR:
@@ -341,7 +354,8 @@ acpi_tb_get_this_table (
full_table = ACPI_MEM_ALLOCATE (header->length);
if (!full_table) {
- ACPI_REPORT_ERROR (("Could not allocate table memory for [%4.4s] length %X\n",
+ ACPI_REPORT_ERROR ((
+ "Could not allocate table memory for [%4.4s] length %X\n",
header->signature, header->length));
return_ACPI_STATUS (AE_NO_MEMORY);
}
@@ -362,12 +376,14 @@ acpi_tb_get_this_table (
* Just map the table's physical memory
* into our address space.
*/
- status = acpi_os_map_memory (address->pointer.physical, (acpi_size) header->length,
- (void *) &full_table);
+ status = acpi_os_map_memory (address->pointer.physical,
+ (acpi_size) header->length, (void *) &full_table);
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n",
+ ACPI_REPORT_ERROR ((
+ "Could not map memory for table [%4.4s] at %8.8X%8.8X for length %X\n",
header->signature,
- ACPI_FORMAT_UINT64 (address->pointer.physical), header->length));
+ ACPI_FORMAT_UINT64 (address->pointer.physical),
+ header->length));
return (status);
}
@@ -465,9 +481,8 @@ acpi_tb_get_table_ptr (
return_ACPI_STATUS (AE_OK);
}
- /*
- * Check for instance out of range
- */
+ /* Check for instance out of range */
+
if (instance > acpi_gbl_table_lists[table_type].count) {
return_ACPI_STATUS (AE_NOT_EXIST);
}
diff --git a/drivers/acpi/tables/tbgetall.c b/drivers/acpi/tables/tbgetall.c
index adc4270988bc..eea5b8cb5ebb 100644
--- a/drivers/acpi/tables/tbgetall.c
+++ b/drivers/acpi/tables/tbgetall.c
@@ -49,6 +49,19 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbgetall")
+/* Local prototypes */
+
+static acpi_status
+acpi_tb_get_primary_table (
+ struct acpi_pointer *address,
+ struct acpi_table_desc *table_info);
+
+static acpi_status
+acpi_tb_get_secondary_table (
+ struct acpi_pointer *address,
+ acpi_string signature,
+ struct acpi_table_desc *table_info);
+
/*******************************************************************************
*
@@ -63,7 +76,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_get_primary_table (
struct acpi_pointer *address,
struct acpi_table_desc *table_info)
@@ -81,9 +94,8 @@ acpi_tb_get_primary_table (
return_ACPI_STATUS (AE_OK);
}
- /*
- * Get the header in order to get signature and table size
- */
+ /* Get the header in order to get signature and table size */
+
status = acpi_tb_get_table_header (address, &header);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
@@ -130,7 +142,7 @@ acpi_tb_get_primary_table (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_get_secondary_table (
struct acpi_pointer *address,
acpi_string signature,
@@ -153,7 +165,8 @@ acpi_tb_get_secondary_table (
/* Signature must match request */
if (ACPI_STRNCMP (header.signature, signature, ACPI_NAME_SIZE)) {
- ACPI_REPORT_ERROR (("Incorrect table signature - wanted [%s] found [%4.4s]\n",
+ ACPI_REPORT_ERROR ((
+ "Incorrect table signature - wanted [%s] found [%4.4s]\n",
signature, header.signature));
return_ACPI_STATUS (AE_BAD_SIGNATURE);
}
@@ -230,7 +243,8 @@ acpi_tb_get_required_tables (
for (i = 0; i < acpi_gbl_rsdt_table_count; i++) {
/* Get the table address from the common internal XSDT */
- address.pointer.value = acpi_gbl_XSDT->table_offset_entry[i];
+ address.pointer.value =
+ acpi_gbl_XSDT->table_offset_entry[i];
/*
* Get the tables needed by this subsystem (FADT and any SSDTs).
@@ -252,18 +266,18 @@ acpi_tb_get_required_tables (
}
/*
- * Convert the FADT to a common format. This allows earlier revisions of the
- * table to coexist with newer versions, using common access code.
+ * Convert the FADT to a common format. This allows earlier revisions of
+ * the table to coexist with newer versions, using common access code.
*/
status = acpi_tb_convert_table_fadt ();
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("Could not convert FADT to internal common format\n"));
+ ACPI_REPORT_ERROR ((
+ "Could not convert FADT to internal common format\n"));
return_ACPI_STATUS (status);
}
- /*
- * Get the FACS (Pointed to by the FADT)
- */
+ /* Get the FACS (Pointed to by the FADT) */
+
address.pointer.value = acpi_gbl_FADT->xfirmware_ctrl;
status = acpi_tb_get_secondary_table (&address, FACS_SIG, &table_info);
@@ -282,9 +296,8 @@ acpi_tb_get_required_tables (
return_ACPI_STATUS (status);
}
- /*
- * Get/install the DSDT (Pointed to by the FADT)
- */
+ /* Get/install the DSDT (Pointed to by the FADT) */
+
address.pointer.value = acpi_gbl_FADT->Xdsdt;
status = acpi_tb_get_secondary_table (&address, DSDT_SIG, &table_info);
diff --git a/drivers/acpi/tables/tbinstal.c b/drivers/acpi/tables/tbinstal.c
index 85d5bb01022c..629b64c8193d 100644
--- a/drivers/acpi/tables/tbinstal.c
+++ b/drivers/acpi/tables/tbinstal.c
@@ -49,6 +49,14 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbinstal")
+/* Local prototypes */
+
+static acpi_status
+acpi_tb_match_signature (
+ char *signature,
+ struct acpi_table_desc *table_info,
+ u8 search_type);
+
/*******************************************************************************
*
@@ -56,6 +64,7 @@
*
* PARAMETERS: Signature - Table signature to match
* table_info - Return data
+ * search_type - Table type to match (primary/secondary)
*
* RETURN: Status
*
@@ -64,7 +73,7 @@
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_match_signature (
char *signature,
struct acpi_table_desc *table_info,
@@ -76,9 +85,8 @@ acpi_tb_match_signature (
ACPI_FUNCTION_TRACE ("tb_match_signature");
- /*
- * Search for a signature match among the known table types
- */
+ /* Search for a signature match among the known table types */
+
for (i = 0; i < NUM_ACPI_TABLE_TYPES; i++) {
if (!(acpi_gbl_table_data[i].flags & search_type)) {
continue;
@@ -161,6 +169,7 @@ acpi_tb_install_table (
* FUNCTION: acpi_tb_recognize_table
*
* PARAMETERS: table_info - Return value from acpi_tb_get_table_body
+ * search_type - Table type to match (primary/secondary)
*
* RETURN: Status
*
@@ -203,7 +212,8 @@ acpi_tb_recognize_table (
* This can be any one of many valid ACPI tables, it just isn't one of
* the tables that is consumed by the core subsystem
*/
- status = acpi_tb_match_signature (table_header->signature, table_info, search_type);
+ status = acpi_tb_match_signature (table_header->signature,
+ table_info, search_type);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -253,9 +263,8 @@ acpi_tb_init_table_descriptor (
return_ACPI_STATUS (AE_NO_MEMORY);
}
- /*
- * Install the table into the global data structure
- */
+ /* Install the table into the global data structure */
+
list_head = &acpi_gbl_table_lists[table_type];
/*
@@ -316,7 +325,8 @@ acpi_tb_init_table_descriptor (
table_desc->aml_start = (u8 *) (table_desc->pointer + 1),
table_desc->aml_length = (u32) (table_desc->length -
(u32) sizeof (struct acpi_table_header));
- table_desc->table_id = acpi_ut_allocate_owner_id (ACPI_OWNER_TYPE_TABLE);
+ table_desc->table_id = acpi_ut_allocate_owner_id (
+ ACPI_OWNER_TYPE_TABLE);
table_desc->loaded_into_namespace = FALSE;
/*
@@ -349,7 +359,8 @@ acpi_tb_init_table_descriptor (
******************************************************************************/
void
-acpi_tb_delete_all_tables (void)
+acpi_tb_delete_all_tables (
+ void)
{
acpi_table_type type;
diff --git a/drivers/acpi/tables/tbrsdt.c b/drivers/acpi/tables/tbrsdt.c
index 9c6913238d52..b7ffe39c3626 100644
--- a/drivers/acpi/tables/tbrsdt.c
+++ b/drivers/acpi/tables/tbrsdt.c
@@ -84,8 +84,9 @@ acpi_tb_verify_rsdp (
/*
* Obtain access to the RSDP structure
*/
- status = acpi_os_map_memory (address->pointer.physical, sizeof (struct rsdp_descriptor),
- (void *) &rsdp);
+ status = acpi_os_map_memory (address->pointer.physical,
+ sizeof (struct rsdp_descriptor),
+ (void *) &rsdp);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -154,9 +155,9 @@ cleanup:
*
* FUNCTION: acpi_tb_get_rsdt_address
*
- * PARAMETERS: None
+ * PARAMETERS: out_address - Where the address is returned
*
- * RETURN: RSDT physical address
+ * RETURN: None, Address
*
* DESCRIPTION: Extract the address of the RSDT or XSDT, depending on the
* version of the RSDP
@@ -181,7 +182,8 @@ acpi_tb_get_rsdt_address (
out_address->pointer.value = acpi_gbl_RSDP->rsdt_physical_address;
}
else {
- out_address->pointer.value = acpi_gbl_RSDP->xsdt_physical_address;
+ out_address->pointer.value =
+ acpi_gbl_RSDP->xsdt_physical_address;
}
}
@@ -224,7 +226,8 @@ acpi_tb_validate_rsdt (
if (no_match) {
/* Invalid RSDT or XSDT signature */
- ACPI_REPORT_ERROR (("Invalid signature where RSDP indicates RSDT/XSDT should be located\n"));
+ ACPI_REPORT_ERROR ((
+ "Invalid signature where RSDP indicates RSDT/XSDT should be located\n"));
ACPI_DUMP_BUFFER (acpi_gbl_RSDP, 20);
@@ -282,6 +285,7 @@ acpi_tb_get_table_rsdt (
if (ACPI_FAILURE (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Could not get the RSDT/XSDT, %s\n",
acpi_format_exception (status)));
+
return_ACPI_STATUS (status);
}
@@ -299,7 +303,8 @@ acpi_tb_get_table_rsdt (
/* Get the number of tables defined in the RSDT or XSDT */
- acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP, table_info.pointer);
+ acpi_gbl_rsdt_table_count = acpi_tb_get_table_count (acpi_gbl_RSDP,
+ table_info.pointer);
/* Convert and/or copy to an XSDT structure */
diff --git a/drivers/acpi/tables/tbutils.c b/drivers/acpi/tables/tbutils.c
index fede5804c783..e69d01d443d2 100644
--- a/drivers/acpi/tables/tbutils.c
+++ b/drivers/acpi/tables/tbutils.c
@@ -49,48 +49,14 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbutils")
+/* Local prototypes */
-/*******************************************************************************
- *
- * FUNCTION: acpi_tb_handle_to_object
- *
- * PARAMETERS: table_id - Id for which the function is searching
- * table_desc - Pointer to return the matching table
- * descriptor.
- *
- * RETURN: Search the tables to find one with a matching table_id and
- * return a pointer to that table descriptor.
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_OBSOLETE_FUNCTIONS
acpi_status
acpi_tb_handle_to_object (
u16 table_id,
- struct acpi_table_desc **return_table_desc)
-{
- u32 i;
- struct acpi_table_desc *table_desc;
-
-
- ACPI_FUNCTION_NAME ("tb_handle_to_object");
-
-
- for (i = 0; i < ACPI_TABLE_MAX; i++) {
- table_desc = acpi_gbl_table_lists[i].next;
- while (table_desc) {
- if (table_desc->table_id == table_id) {
- *return_table_desc = table_desc;
- return (AE_OK);
- }
-
- table_desc = table_desc->next;
- }
- }
-
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id));
- return (AE_BAD_PARAMETER);
-}
-#endif /* ACPI_FUTURE_USAGE */
+ struct acpi_table_desc **table_desc);
+#endif
/*******************************************************************************
@@ -128,6 +94,7 @@ acpi_tb_validate_table_header (
if (!acpi_os_readable (table_header, sizeof (struct acpi_table_header))) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"Cannot read table header at %p\n", table_header));
+
return (AE_BAD_ADDRESS);
}
@@ -141,6 +108,7 @@ acpi_tb_validate_table_header (
ACPI_REPORT_WARNING (("Invalid table signature found: [%4.4s]\n",
(char *) &signature));
+
ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header));
return (AE_BAD_SIGNATURE);
}
@@ -154,6 +122,7 @@ acpi_tb_validate_table_header (
ACPI_REPORT_WARNING (("Invalid table header length (0x%X) found\n",
(u32) table_header->length));
+
ACPI_DUMP_BUFFER (table_header, sizeof (struct acpi_table_header));
return (AE_BAD_HEADER);
}
@@ -193,8 +162,10 @@ acpi_tb_verify_table_checksum (
/* Return the appropriate exception */
if (checksum) {
- ACPI_REPORT_WARNING (("Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n",
- table_header->signature, (u32) table_header->checksum, (u32) checksum));
+ ACPI_REPORT_WARNING ((
+ "Invalid checksum in table [%4.4s] (%02X, sum %02X is not zero)\n",
+ table_header->signature, (u32) table_header->checksum,
+ (u32) checksum));
status = AE_BAD_CHECKSUM;
}
@@ -209,7 +180,7 @@ acpi_tb_verify_table_checksum (
* PARAMETERS: Buffer - Buffer to checksum
* Length - Size of the buffer
*
- * RETURNS 8 bit checksum of buffer
+ * RETURN: 8 bit checksum of buffer
*
* DESCRIPTION: Computes an 8 bit checksum of the buffer(length) and returns it.
*
@@ -238,3 +209,47 @@ acpi_tb_checksum (
}
+#ifdef ACPI_OBSOLETE_FUNCTIONS
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_tb_handle_to_object
+ *
+ * PARAMETERS: table_id - Id for which the function is searching
+ * table_desc - Pointer to return the matching table
+ * descriptor.
+ *
+ * RETURN: Search the tables to find one with a matching table_id and
+ * return a pointer to that table descriptor.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_tb_handle_to_object (
+ u16 table_id,
+ struct acpi_table_desc **return_table_desc)
+{
+ u32 i;
+ struct acpi_table_desc *table_desc;
+
+
+ ACPI_FUNCTION_NAME ("tb_handle_to_object");
+
+
+ for (i = 0; i < ACPI_TABLE_MAX; i++) {
+ table_desc = acpi_gbl_table_lists[i].next;
+ while (table_desc) {
+ if (table_desc->table_id == table_id) {
+ *return_table_desc = table_desc;
+ return (AE_OK);
+ }
+
+ table_desc = table_desc->next;
+ }
+ }
+
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "table_id=%X does not exist\n", table_id));
+ return (AE_BAD_PARAMETER);
+}
+#endif
+
+
diff --git a/drivers/acpi/tables/tbxface.c b/drivers/acpi/tables/tbxface.c
index 7715043461c4..0c0b9085dbeb 100644
--- a/drivers/acpi/tables/tbxface.c
+++ b/drivers/acpi/tables/tbxface.c
@@ -67,7 +67,8 @@
******************************************************************************/
acpi_status
-acpi_load_tables (void)
+acpi_load_tables (
+ void)
{
struct acpi_pointer rsdp_address;
acpi_status status;
@@ -82,7 +83,7 @@ acpi_load_tables (void)
&rsdp_address);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("acpi_load_tables: Could not get RSDP, %s\n",
- acpi_format_exception (status)));
+ acpi_format_exception (status)));
goto error_exit;
}
@@ -93,7 +94,7 @@ acpi_load_tables (void)
status = acpi_tb_verify_rsdp (&rsdp_address);
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("acpi_load_tables: RSDP Failed validation: %s\n",
- acpi_format_exception (status)));
+ acpi_format_exception (status)));
goto error_exit;
}
@@ -102,7 +103,7 @@ acpi_load_tables (void)
status = acpi_tb_get_table_rsdt ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("acpi_load_tables: Could not load RSDT: %s\n",
- acpi_format_exception (status)));
+ acpi_format_exception (status)));
goto error_exit;
}
@@ -110,20 +111,20 @@ acpi_load_tables (void)
status = acpi_tb_get_required_tables ();
if (ACPI_FAILURE (status)) {
- ACPI_REPORT_ERROR (("acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n",
- acpi_format_exception (status)));
+ ACPI_REPORT_ERROR ((
+ "acpi_load_tables: Error getting required tables (DSDT/FADT/FACS): %s\n",
+ acpi_format_exception (status)));
goto error_exit;
}
ACPI_DEBUG_PRINT ((ACPI_DB_INIT, "ACPI Tables successfully acquired\n"));
-
/* Load the namespace from the tables */
status = acpi_ns_load_namespace ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("acpi_load_tables: Could not load namespace: %s\n",
- acpi_format_exception (status)));
+ acpi_format_exception (status)));
goto error_exit;
}
@@ -139,7 +140,6 @@ error_exit:
#ifdef ACPI_FUTURE_USAGE
-
/*******************************************************************************
*
* FUNCTION: acpi_load_table
@@ -250,7 +250,6 @@ acpi_unload_table (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
-
/* Find all tables of the requested type */
table_desc = acpi_gbl_table_lists[table_type].next;
@@ -321,7 +320,6 @@ acpi_get_table_header (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
-
/* Get a pointer to the entire table */
status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
@@ -329,23 +327,20 @@ acpi_get_table_header (
return_ACPI_STATUS (status);
}
- /*
- * The function will return a NULL pointer if the table is not loaded
- */
+ /* The function will return a NULL pointer if the table is not loaded */
+
if (tbl_ptr == NULL) {
return_ACPI_STATUS (AE_NOT_EXIST);
}
- /*
- * Copy the header to the caller's buffer
- */
+ /* Copy the header to the caller's buffer */
+
ACPI_MEMCPY ((void *) out_table_header, (void *) tbl_ptr,
- sizeof (struct acpi_table_header));
+ sizeof (struct acpi_table_header));
return_ACPI_STATUS (status);
}
-
#endif /* ACPI_FUTURE_USAGE */
/*******************************************************************************
@@ -404,7 +399,6 @@ acpi_get_table (
return_ACPI_STATUS (AE_BAD_PARAMETER);
}
-
/* Get a pointer to the entire table */
status = acpi_tb_get_table_ptr (table_type, instance, &tbl_ptr);
@@ -423,9 +417,8 @@ acpi_get_table (
/* Get the table length */
if (table_type == ACPI_TABLE_RSDP) {
- /*
- * RSD PTR is the only "table" without a header
- */
+ /* RSD PTR is the only "table" without a header */
+
table_length = sizeof (struct rsdp_descriptor);
}
else {
diff --git a/drivers/acpi/tables/tbxfroot.c b/drivers/acpi/tables/tbxfroot.c
index 6e8072ebbac6..dc3c3f6a9f62 100644
--- a/drivers/acpi/tables/tbxfroot.c
+++ b/drivers/acpi/tables/tbxfroot.c
@@ -50,6 +50,18 @@
#define _COMPONENT ACPI_TABLES
ACPI_MODULE_NAME ("tbxfroot")
+/* Local prototypes */
+
+static acpi_status
+acpi_tb_find_rsdp (
+ struct acpi_table_desc *table_info,
+ u32 flags);
+
+static u8 *
+acpi_tb_scan_memory_for_rsdp (
+ u8 *start_address,
+ u32 length);
+
/*******************************************************************************
*
@@ -57,7 +69,8 @@
*
* PARAMETERS: Signature - String with ACPI table signature
* oem_id - String with the table OEM ID
- * oem_table_id - String with the OEM Table ID.
+ * oem_table_id - String with the OEM Table ID
+ * table_ptr - Where the table pointer is returned
*
* RETURN: Status
*
@@ -99,14 +112,13 @@ acpi_tb_find_table (
if (!acpi_gbl_DSDT) {
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
-
table = acpi_gbl_DSDT;
}
else {
/* Find the table */
status = acpi_get_firmware_table (signature, 1,
- ACPI_LOGICAL_ADDRESSING, &table);
+ ACPI_LOGICAL_ADDRESSING, &table);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -114,14 +126,19 @@ acpi_tb_find_table (
/* Check oem_id and oem_table_id */
- if ((oem_id[0] && ACPI_STRNCMP (
- oem_id, table->oem_id, sizeof (table->oem_id))) ||
+ if ((oem_id[0] && ACPI_STRNCMP (
+ oem_id, table->oem_id,
+ sizeof (table->oem_id))) ||
+
(oem_table_id[0] && ACPI_STRNCMP (
- oem_table_id, table->oem_table_id, sizeof (table->oem_table_id)))) {
+ oem_table_id, table->oem_table_id,
+ sizeof (table->oem_table_id)))) {
return_ACPI_STATUS (AE_AML_NAME_NOT_FOUND);
}
- ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n", table->signature));
+ ACPI_DEBUG_PRINT ((ACPI_DB_TABLES, "Found table [%4.4s]\n",
+ table->signature));
+
*table_ptr = table;
return_ACPI_STATUS (AE_OK);
}
@@ -191,8 +208,8 @@ acpi_get_firmware_table (
/* Map and validate the RSDP */
if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
- status = acpi_os_map_memory (address.pointer.physical, sizeof (struct rsdp_descriptor),
- (void *) &acpi_gbl_RSDP);
+ status = acpi_os_map_memory (address.pointer.physical,
+ sizeof (struct rsdp_descriptor), (void *) &acpi_gbl_RSDP);
if (ACPI_FAILURE (status)) {
return_ACPI_STATUS (status);
}
@@ -203,7 +220,8 @@ acpi_get_firmware_table (
/* The signature and checksum must both be correct */
- if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ if (ACPI_STRNCMP ((char *) acpi_gbl_RSDP, RSDP_SIG,
+ sizeof (RSDP_SIG)-1) != 0) {
/* Nope, BAD Signature */
return_ACPI_STATUS (AE_BAD_SIGNATURE);
@@ -313,7 +331,8 @@ 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) {
@@ -335,8 +354,8 @@ EXPORT_SYMBOL(acpi_get_firmware_table);
*
* FUNCTION: acpi_find_root_pointer
*
- * PARAMETERS: **rsdp_address - Where to place the RSDP address
- * Flags - Logical/Physical addressing
+ * PARAMETERS: Flags - Logical/Physical addressing
+ * rsdp_address - Where to place the RSDP address
*
* RETURN: Status, Physical address of the RSDP
*
@@ -363,6 +382,7 @@ acpi_find_root_pointer (
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
"RSDP structure not found, %s Flags=%X\n",
acpi_format_exception (status), flags));
+
return_ACPI_STATUS (AE_NO_ACPI_TABLES);
}
@@ -385,7 +405,7 @@ acpi_find_root_pointer (
*
******************************************************************************/
-u8 *
+static u8 *
acpi_tb_scan_memory_for_rsdp (
u8 *start_address,
u32 length)
@@ -406,7 +426,8 @@ acpi_tb_scan_memory_for_rsdp (
mem_rover += ACPI_RSDP_SCAN_STEP) {
/* The signature and checksum must both be correct */
- if (ACPI_STRNCMP ((char *) mem_rover, RSDP_SIG, sizeof (RSDP_SIG)-1) != 0) {
+ if (ACPI_STRNCMP ((char *) mem_rover,
+ RSDP_SIG, sizeof (RSDP_SIG) - 1) != 0) {
/* No signature match, keep looking */
continue;
@@ -450,7 +471,7 @@ acpi_tb_scan_memory_for_rsdp (
*
* FUNCTION: acpi_tb_find_rsdp
*
- * PARAMETERS: *table_info - Where the table info is returned
+ * PARAMETERS: table_info - Where the table info is returned
* Flags - Current memory mode (logical vs.
* physical addressing)
*
@@ -468,7 +489,7 @@ acpi_tb_scan_memory_for_rsdp (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_tb_find_rsdp (
struct acpi_table_desc *table_info,
u32 flags)
@@ -483,43 +504,49 @@ acpi_tb_find_rsdp (
/*
- * Scan supports either 1) Logical addressing or 2) Physical addressing
+ * Scan supports either logical addressing or physical addressing
*/
if ((flags & ACPI_MEMORY_MODE) == ACPI_LOGICAL_ADDRESSING) {
- /*
- * 1a) Get the location of the EBDA
- */
- status = acpi_os_map_memory ((acpi_physical_address) ACPI_EBDA_PTR_LOCATION,
- ACPI_EBDA_PTR_LENGTH,
- (void *) &table_ptr);
+ /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
+
+ 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 %8.8X for length %X\n",
ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
+
return_ACPI_STATUS (status);
}
ACPI_MOVE_16_TO_32 (&physical_address, table_ptr);
- physical_address <<= 4; /* Convert segment to physical address */
+
+ /* Convert segment part to physical address */
+
+ physical_address <<= 4;
acpi_os_unmap_memory (table_ptr, ACPI_EBDA_PTR_LENGTH);
/* EBDA present? */
if (physical_address > 0x400) {
/*
- * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length)
+ * 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);
+ 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);
}
- mem_rover = acpi_tb_scan_memory_for_rsdp (table_ptr, ACPI_EBDA_WINDOW_SIZE);
+ 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) {
@@ -527,7 +554,8 @@ acpi_tb_find_rsdp (
physical_address += ACPI_PTR_DIFF (mem_rover, table_ptr);
- table_info->physical_address = (acpi_physical_address) physical_address;
+ table_info->physical_address =
+ (acpi_physical_address) physical_address;
return_ACPI_STATUS (AE_OK);
}
}
@@ -535,13 +563,15 @@ acpi_tb_find_rsdp (
/*
* 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
*/
- status = acpi_os_map_memory ((acpi_physical_address) ACPI_HI_RSDP_WINDOW_BASE,
- ACPI_HI_RSDP_WINDOW_SIZE,
- (void *) &table_ptr);
+ 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 %8.8X for length %X\n",
ACPI_HI_RSDP_WINDOW_BASE, ACPI_HI_RSDP_WINDOW_SIZE));
+
return_ACPI_STATUS (status);
}
@@ -551,9 +581,11 @@ acpi_tb_find_rsdp (
if (mem_rover) {
/* Found it, return the physical address */
- physical_address = ACPI_HI_RSDP_WINDOW_BASE + 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 = (acpi_physical_address) physical_address;
+ table_info->physical_address =
+ (acpi_physical_address) physical_address;
return_ACPI_STATUS (AE_OK);
}
}
@@ -562,9 +594,8 @@ acpi_tb_find_rsdp (
* Physical addressing
*/
else {
- /*
- * 1a) Get the location of the EBDA
- */
+ /* 1a) Get the location of the EBDA */
+
ACPI_MOVE_16_TO_32 (&physical_address, ACPI_EBDA_PTR_LOCATION);
physical_address <<= 4; /* Convert segment to physical address */
@@ -572,9 +603,11 @@ acpi_tb_find_rsdp (
if (physical_address > 0x400) {
/*
- * 1b) Search EBDA paragraphs (EBDa is required to be a minimum of 1_k length)
+ * 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),
+ 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 */
@@ -584,10 +617,10 @@ acpi_tb_find_rsdp (
}
}
- /*
- * 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),
+ /* 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);
if (mem_rover) {
/* Found it, return the physical address */
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
index c84997c9f964..73b1d8aeae9d 100644
--- a/drivers/acpi/toshiba_acpi.c
+++ b/drivers/acpi/toshiba_acpi.c
@@ -263,6 +263,9 @@ dispatch_write(struct file* file, const char __user * buffer,
* destination so that sscanf can be used on it safely.
*/
tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+ if(!tmp_buffer)
+ return -ENOMEM;
+
if (copy_from_user(tmp_buffer, buffer, count)) {
result = -EFAULT;
}
@@ -529,6 +532,11 @@ toshiba_acpi_init(void)
if (acpi_disabled)
return -ENODEV;
+
+ if (!acpi_specific_hotkey_enabled){
+ printk(MY_INFO "Using generic hotkey driver\n");
+ return -ENODEV;
+ }
/* simple device detection: look for HCI method */
if (is_valid_acpi_path(METHOD_HCI_1))
method_hci = METHOD_HCI_1;
diff --git a/drivers/acpi/utilities/utalloc.c b/drivers/acpi/utilities/utalloc.c
index 3313439c4bc7..c4e7f989a2bd 100644
--- a/drivers/acpi/utilities/utalloc.c
+++ b/drivers/acpi/utilities/utalloc.c
@@ -47,8 +47,35 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utalloc")
+/* Local prototypes */
-/******************************************************************************
+#ifdef ACPI_DBG_TRACK_ALLOCATIONS
+static struct acpi_debug_mem_block *
+acpi_ut_find_allocation (
+ u32 list_id,
+ void *allocation);
+
+static acpi_status
+acpi_ut_track_allocation (
+ u32 list_id,
+ struct acpi_debug_mem_block *address,
+ acpi_size size,
+ u8 alloc_type,
+ u32 component,
+ char *module,
+ u32 line);
+
+static acpi_status
+acpi_ut_remove_allocation (
+ u32 list_id,
+ struct acpi_debug_mem_block *address,
+ u32 component,
+ char *module,
+ u32 line);
+#endif /* ACPI_DBG_TRACK_ALLOCATIONS */
+
+
+/*******************************************************************************
*
* FUNCTION: acpi_ut_release_to_cache
*
@@ -98,7 +125,8 @@ acpi_ut_release_to_cache (
/* Put the object at the head of the cache list */
- * (ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head;
+ * (ACPI_CAST_INDIRECT_PTR (char,
+ &(((char *) object)[cache_info->link_offset]))) = cache_info->list_head;
cache_info->list_head = object;
cache_info->cache_depth++;
@@ -115,7 +143,7 @@ acpi_ut_release_to_cache (
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_acquire_from_cache
*
@@ -156,7 +184,8 @@ acpi_ut_acquire_from_cache (
/* There is an object available, use it */
object = cache_info->list_head;
- cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) object)[cache_info->link_offset])));
+ cache_info->list_head = *(ACPI_CAST_INDIRECT_PTR (char,
+ &(((char *) object)[cache_info->link_offset])));
ACPI_MEM_TRACKING (cache_info->cache_hits++);
cache_info->cache_depth--;
@@ -201,7 +230,7 @@ acpi_ut_acquire_from_cache (
#ifdef ACPI_ENABLE_OBJECT_CACHE
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_delete_generic_cache
*
@@ -228,7 +257,8 @@ acpi_ut_delete_generic_cache (
while (cache_info->list_head) {
/* Delete one cached state object */
- next = *(ACPI_CAST_INDIRECT_PTR (char, &(((char *) cache_info->list_head)[cache_info->link_offset])));
+ next = *(ACPI_CAST_INDIRECT_PTR (char,
+ &(((char *) cache_info->list_head)[cache_info->link_offset])));
ACPI_MEM_FREE (cache_info->list_head);
cache_info->list_head = next;
@@ -497,8 +527,8 @@ acpi_ut_allocate_and_track (
acpi_status status;
- allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header), component,
- module, line);
+ allocation = acpi_ut_allocate (size + sizeof (struct acpi_debug_mem_header),
+ component, module, line);
if (!allocation) {
return (NULL);
}
@@ -543,8 +573,8 @@ acpi_ut_callocate_and_track (
acpi_status status;
- allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header), component,
- module, line);
+ allocation = acpi_ut_callocate (size + sizeof (struct acpi_debug_mem_header),
+ component, module, line);
if (!allocation) {
/* Report allocation error */
@@ -637,7 +667,7 @@ acpi_ut_free_and_track (
*
******************************************************************************/
-struct acpi_debug_mem_block *
+static struct acpi_debug_mem_block *
acpi_ut_find_allocation (
u32 list_id,
void *allocation)
@@ -686,7 +716,7 @@ acpi_ut_find_allocation (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_track_allocation (
u32 list_id,
struct acpi_debug_mem_block *allocation,
@@ -721,10 +751,12 @@ acpi_ut_track_allocation (
element = acpi_ut_find_allocation (list_id, allocation);
if (element) {
- ACPI_REPORT_ERROR (("ut_track_allocation: Allocation already present in list! (%p)\n",
+ ACPI_REPORT_ERROR ((
+ "ut_track_allocation: Allocation already present in list! (%p)\n",
allocation));
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n", element, allocation));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Element %p Address %p\n",
+ element, allocation));
goto unlock_and_exit;
}
@@ -773,7 +805,7 @@ unlock_and_exit:
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_remove_allocation (
u32 list_id,
struct acpi_debug_mem_block *allocation,
@@ -797,7 +829,7 @@ acpi_ut_remove_allocation (
/* No allocations! */
_ACPI_REPORT_ERROR (module, line, component,
- ("ut_remove_allocation: Empty allocation list, nothing to free!\n"));
+ ("ut_remove_allocation: Empty allocation list, nothing to free!\n"));
return_ACPI_STATUS (AE_OK);
}
@@ -824,7 +856,8 @@ acpi_ut_remove_allocation (
ACPI_MEMSET (&allocation->user_space, 0xEA, allocation->size);
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n", allocation->size));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Freeing size 0%X\n",
+ allocation->size));
status = acpi_ut_release_mutex (ACPI_MTX_MEMORY);
return_ACPI_STATUS (status);
@@ -842,6 +875,7 @@ acpi_ut_remove_allocation (
* DESCRIPTION: Print some info about the outstanding allocations.
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
void
acpi_ut_dump_allocation_info (
@@ -884,7 +918,8 @@ acpi_ut_dump_allocation_info (
ACPI_DEBUG_PRINT (TRACE_ALLOCATIONS | TRACE_TABLES,
("%30s: %4d (%3d Kb)\n", "Max Nodes",
acpi_gbl_max_concurrent_node_count,
- ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count * sizeof (struct acpi_namespace_node)))));
+ ROUND_UP_TO_1K ((acpi_gbl_max_concurrent_node_count *
+ sizeof (struct acpi_namespace_node)))));
*/
return_VOID;
}
@@ -933,26 +968,26 @@ acpi_ut_dump_allocations (
descriptor = ACPI_CAST_PTR (union acpi_descriptor, &element->user_space);
if (descriptor->descriptor_id != ACPI_DESC_TYPE_CACHED) {
acpi_os_printf ("%p Len %04X %9.9s-%d [%s] ",
- descriptor, element->size, element->module,
- element->line, acpi_ut_get_descriptor_name (descriptor));
+ descriptor, element->size, element->module,
+ element->line, acpi_ut_get_descriptor_name (descriptor));
/* Most of the elements will be Operand objects. */
switch (ACPI_GET_DESCRIPTOR_TYPE (descriptor)) {
case ACPI_DESC_TYPE_OPERAND:
acpi_os_printf ("%12.12s R%hd",
- acpi_ut_get_type_name (descriptor->object.common.type),
- descriptor->object.common.reference_count);
+ acpi_ut_get_type_name (descriptor->object.common.type),
+ descriptor->object.common.reference_count);
break;
case ACPI_DESC_TYPE_PARSER:
acpi_os_printf ("aml_opcode %04hX",
- descriptor->op.asl.aml_opcode);
+ descriptor->op.asl.aml_opcode);
break;
case ACPI_DESC_TYPE_NAMED:
acpi_os_printf ("%4.4s",
- acpi_ut_get_node_name (&descriptor->node));
+ acpi_ut_get_node_name (&descriptor->node));
break;
default:
@@ -983,6 +1018,5 @@ acpi_ut_dump_allocations (
return_VOID;
}
-
#endif /* #ifdef ACPI_DBG_TRACK_ALLOCATIONS */
diff --git a/drivers/acpi/utilities/utcopy.c b/drivers/acpi/utilities/utcopy.c
index 0fcd98bde0d1..11e884957162 100644
--- a/drivers/acpi/utilities/utcopy.c
+++ b/drivers/acpi/utilities/utcopy.c
@@ -49,21 +49,69 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utcopy")
+/* Local prototypes */
+
+static acpi_status
+acpi_ut_copy_isimple_to_esimple (
+ union acpi_operand_object *internal_object,
+ union acpi_object *external_object,
+ u8 *data_space,
+ acpi_size *buffer_space_used);
+
+static acpi_status
+acpi_ut_copy_ielement_to_ielement (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context);
+
+static acpi_status
+acpi_ut_copy_ipackage_to_epackage (
+ union acpi_operand_object *internal_object,
+ u8 *buffer,
+ acpi_size *space_used);
+
+static acpi_status
+acpi_ut_copy_esimple_to_isimple(
+ union acpi_object *user_obj,
+ union acpi_operand_object **return_obj);
+
+static acpi_status
+acpi_ut_copy_simple_object (
+ union acpi_operand_object *source_desc,
+ union acpi_operand_object *dest_desc);
+
+static acpi_status
+acpi_ut_copy_ielement_to_eelement (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context);
+
+static acpi_status
+acpi_ut_copy_ipackage_to_ipackage (
+ union acpi_operand_object *source_obj,
+ union acpi_operand_object *dest_obj,
+ struct acpi_walk_state *walk_state);
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_copy_isimple_to_esimple
*
- * PARAMETERS: *internal_object - Pointer to the object we are examining
- * *Buffer - Where the object is returned
- * *space_used - Where the data length is returned
+ * PARAMETERS: internal_object - Source object to be copied
+ * external_object - Where to return the copied object
+ * data_space - Where object data is returned (such as
+ * buffer and string data)
+ * buffer_space_used - Length of data_space that was used
*
* RETURN: Status
*
- * DESCRIPTION: This function is called to place a simple object in a user
- * buffer.
+ * DESCRIPTION: This function is called to copy a simple internal object to
+ * an external object.
*
- * The buffer is assumed to have sufficient space for the object.
+ * The data_space buffer is assumed to have sufficient space for
+ * the object.
*
******************************************************************************/
@@ -107,10 +155,12 @@ acpi_ut_copy_isimple_to_esimple (
external_object->string.pointer = (char *) data_space;
external_object->string.length = internal_object->string.length;
- *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD ((acpi_size) internal_object->string.length + 1);
+ *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (
+ (acpi_size) internal_object->string.length + 1);
- ACPI_MEMCPY ((void *) data_space, (void *) internal_object->string.pointer,
- (acpi_size) internal_object->string.length + 1);
+ ACPI_MEMCPY ((void *) data_space,
+ (void *) internal_object->string.pointer,
+ (acpi_size) internal_object->string.length + 1);
break;
@@ -118,10 +168,12 @@ acpi_ut_copy_isimple_to_esimple (
external_object->buffer.pointer = data_space;
external_object->buffer.length = internal_object->buffer.length;
- *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (internal_object->string.length);
+ *buffer_space_used = ACPI_ROUND_UP_TO_NATIVE_WORD (
+ internal_object->string.length);
- ACPI_MEMCPY ((void *) data_space, (void *) internal_object->buffer.pointer,
- internal_object->buffer.length);
+ ACPI_MEMCPY ((void *) data_space,
+ (void *) internal_object->buffer.pointer,
+ internal_object->buffer.length);
break;
@@ -194,7 +246,7 @@ acpi_ut_copy_isimple_to_esimple (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_copy_ielement_to_eelement (
u8 object_type,
union acpi_operand_object *source_object,
@@ -213,7 +265,7 @@ acpi_ut_copy_ielement_to_eelement (
this_index = state->pkg.index;
target_object = (union acpi_object *)
- &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index];
+ &((union acpi_object *)(state->pkg.dest_object))->package.elements[this_index];
switch (object_type) {
case ACPI_COPY_TYPE_SIMPLE:
@@ -236,7 +288,8 @@ acpi_ut_copy_ielement_to_eelement (
*/
target_object->type = ACPI_TYPE_PACKAGE;
target_object->package.count = source_object->package.count;
- target_object->package.elements = ACPI_CAST_PTR (union acpi_object, info->free_space);
+ target_object->package.elements =
+ ACPI_CAST_PTR (union acpi_object, info->free_space);
/*
* Pass the new package object back to the package walk routine
@@ -248,7 +301,8 @@ acpi_ut_copy_ielement_to_eelement (
* update the buffer length counter
*/
object_space = ACPI_ROUND_UP_TO_NATIVE_WORD (
- (acpi_size) target_object->package.count * sizeof (union acpi_object));
+ (acpi_size) target_object->package.count *
+ sizeof (union acpi_object));
break;
@@ -266,9 +320,9 @@ acpi_ut_copy_ielement_to_eelement (
*
* FUNCTION: acpi_ut_copy_ipackage_to_epackage
*
- * PARAMETERS: *internal_object - Pointer to the object we are returning
- * *Buffer - Where the object is returned
- * *space_used - Where the object length is returned
+ * PARAMETERS: internal_object - Pointer to the object we are returning
+ * Buffer - Where the object is returned
+ * space_used - Where the object length is returned
*
* RETURN: Status
*
@@ -304,13 +358,15 @@ acpi_ut_copy_ipackage_to_epackage (
* Free space begins right after the first package
*/
info.length = ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
- info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object));
+ info.free_space = buffer + ACPI_ROUND_UP_TO_NATIVE_WORD (
+ sizeof (union acpi_object));
info.object_space = 0;
info.num_packages = 1;
external_object->type = ACPI_GET_OBJECT_TYPE (internal_object);
external_object->package.count = internal_object->package.count;
- external_object->package.elements = ACPI_CAST_PTR (union acpi_object, info.free_space);
+ external_object->package.elements = ACPI_CAST_PTR (union acpi_object,
+ info.free_space);
/*
* Leave room for an array of ACPI_OBJECTS in the buffer
@@ -333,8 +389,8 @@ acpi_ut_copy_ipackage_to_epackage (
*
* FUNCTION: acpi_ut_copy_iobject_to_eobject
*
- * PARAMETERS: *internal_object - The internal object to be converted
- * *buffer_ptr - Where the object is returned
+ * PARAMETERS: internal_object - The internal object to be converted
+ * buffer_ptr - Where the object is returned
*
* RETURN: Status
*
@@ -367,10 +423,10 @@ acpi_ut_copy_iobject_to_eobject (
* Build a simple object (no nested objects)
*/
status = acpi_ut_copy_isimple_to_esimple (internal_object,
- (union acpi_object *) ret_buffer->pointer,
- ((u8 *) ret_buffer->pointer +
- ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))),
- &ret_buffer->length);
+ (union acpi_object *) ret_buffer->pointer,
+ ((u8 *) ret_buffer->pointer +
+ ACPI_ROUND_UP_TO_NATIVE_WORD (sizeof (union acpi_object))),
+ &ret_buffer->length);
/*
* build simple does not include the object size in the length
* so we add it in here
@@ -386,8 +442,8 @@ acpi_ut_copy_iobject_to_eobject (
*
* FUNCTION: acpi_ut_copy_esimple_to_isimple
*
- * PARAMETERS: *external_object - The external object to be converted
- * *internal_object - Where the internal object is returned
+ * PARAMETERS: external_object - The external object to be converted
+ * ret_internal_object - Where the internal object is returned
*
* RETURN: Status
*
@@ -398,7 +454,7 @@ acpi_ut_copy_iobject_to_eobject (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_copy_esimple_to_isimple (
union acpi_object *external_object,
union acpi_operand_object **ret_internal_object)
@@ -417,7 +473,8 @@ acpi_ut_copy_esimple_to_isimple (
case ACPI_TYPE_BUFFER:
case ACPI_TYPE_INTEGER:
- internal_object = acpi_ut_create_internal_object ((u8) external_object->type);
+ internal_object = acpi_ut_create_internal_object (
+ (u8) external_object->type);
if (!internal_object) {
return_ACPI_STATUS (AE_NO_MEMORY);
}
@@ -486,7 +543,6 @@ error_exit:
#ifdef ACPI_FUTURE_IMPLEMENTATION
-
/* Code to convert packages that are parameters to control methods */
/*******************************************************************************
@@ -614,7 +670,7 @@ acpi_ut_copy_eobject_to_iobject (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_copy_simple_object (
union acpi_operand_object *source_desc,
union acpi_operand_object *dest_desc)
@@ -724,7 +780,7 @@ acpi_ut_copy_simple_object (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_copy_ielement_to_ielement (
u8 object_type,
union acpi_operand_object *source_object,
@@ -837,7 +893,7 @@ error_exit:
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_copy_ipackage_to_ipackage (
union acpi_operand_object *source_obj,
union acpi_operand_object *dest_obj,
diff --git a/drivers/acpi/utilities/utdebug.c b/drivers/acpi/utilities/utdebug.c
index 985c5d045b78..794c7df3f2ad 100644
--- a/drivers/acpi/utilities/utdebug.c
+++ b/drivers/acpi/utilities/utdebug.c
@@ -56,7 +56,7 @@ static char *acpi_gbl_fn_entry_str = "----Entry";
static char *acpi_gbl_fn_exit_str = "----Exit-";
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_init_stack_ptr_trace
*
@@ -64,9 +64,9 @@ static char *acpi_gbl_fn_exit_str = "----Exit-";
*
* RETURN: None
*
- * DESCRIPTION: Save the current stack pointer
+ * DESCRIPTION: Save the current CPU stack pointer at subsystem startup
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_init_stack_ptr_trace (
@@ -79,7 +79,7 @@ acpi_ut_init_stack_ptr_trace (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_track_stack_ptr
*
@@ -87,9 +87,9 @@ acpi_ut_init_stack_ptr_trace (
*
* RETURN: None
*
- * DESCRIPTION: Save the current stack pointer
+ * DESCRIPTION: Save the current CPU stack pointer
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_track_stack_ptr (
@@ -110,16 +110,16 @@ acpi_ut_track_stack_ptr (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_debug_print
*
- * PARAMETERS: debug_level - Requested debug print level
- * proc_name - Caller's procedure name
- * module_name - Caller's module name (for error output)
+ * PARAMETERS: requested_debug_level - Requested debug print level
* line_number - Caller's line number (for error output)
- * component_id - Caller's component ID (for error output)
- *
+ * dbg_info - Contains:
+ * proc_name - Caller's procedure name
+ * module_name - Caller's module name
+ * component_id - Caller's component ID
* Format - Printf format field
* ... - Optional printf arguments
*
@@ -128,7 +128,7 @@ acpi_ut_track_stack_ptr (
* DESCRIPTION: Print error message with prefix consisting of the module name,
* line number, and component ID.
*
- ****************************************************************************/
+ ******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print (
@@ -157,7 +157,8 @@ acpi_ut_debug_print (
if (thread_id != acpi_gbl_prev_thread_id) {
if (ACPI_LV_THREADS & acpi_dbg_level) {
- acpi_os_printf ("\n**** Context Switch from TID %X to TID %X ****\n\n",
+ acpi_os_printf (
+ "\n**** Context Switch from TID %X to TID %X ****\n\n",
acpi_gbl_prev_thread_id, thread_id);
}
@@ -174,15 +175,16 @@ acpi_ut_debug_print (
acpi_os_printf ("[%04lX] ", thread_id);
}
- acpi_os_printf ("[%02ld] %-22.22s: ", acpi_gbl_nesting_level, dbg_info->proc_name);
+ acpi_os_printf ("[%02ld] %-22.22s: ",
+ acpi_gbl_nesting_level, dbg_info->proc_name);
va_start (args, format);
acpi_os_vprintf (format, args);
}
-EXPORT_SYMBOL(acpi_ut_debug_print);
+EXPORT_SYMBOL(acpi_ut_debug_print);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_debug_print_raw
*
@@ -200,7 +202,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print);
* DESCRIPTION: Print message with no headers. Has same interface as
* debug_print so that the same macros can be used.
*
- ****************************************************************************/
+ ******************************************************************************/
void ACPI_INTERNAL_VAR_XFACE
acpi_ut_debug_print_raw (
@@ -224,7 +226,7 @@ acpi_ut_debug_print_raw (
EXPORT_SYMBOL(acpi_ut_debug_print_raw);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_trace
*
@@ -239,7 +241,7 @@ EXPORT_SYMBOL(acpi_ut_debug_print_raw);
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_trace (
@@ -256,7 +258,7 @@ acpi_ut_trace (
EXPORT_SYMBOL(acpi_ut_trace);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_trace_ptr
*
@@ -272,7 +274,7 @@ EXPORT_SYMBOL(acpi_ut_trace);
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_trace_ptr (
@@ -288,7 +290,7 @@ acpi_ut_trace_ptr (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_trace_str
*
@@ -304,7 +306,7 @@ acpi_ut_trace_ptr (
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_trace_str (
@@ -321,7 +323,7 @@ acpi_ut_trace_str (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_trace_u32
*
@@ -337,7 +339,7 @@ acpi_ut_trace_str (
* DESCRIPTION: Function entry trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_trace_u32 (
@@ -354,7 +356,7 @@ acpi_ut_trace_u32 (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_exit
*
@@ -369,7 +371,7 @@ acpi_ut_trace_u32 (
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_exit (
@@ -385,7 +387,7 @@ acpi_ut_exit (
EXPORT_SYMBOL(acpi_ut_exit);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_status_exit
*
@@ -401,7 +403,7 @@ EXPORT_SYMBOL(acpi_ut_exit);
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level. Prints exit status also.
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_status_exit (
@@ -426,7 +428,7 @@ acpi_ut_status_exit (
EXPORT_SYMBOL(acpi_ut_status_exit);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_value_exit
*
@@ -442,7 +444,7 @@ EXPORT_SYMBOL(acpi_ut_status_exit);
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level. Prints exit value also.
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_value_exit (
@@ -460,7 +462,7 @@ acpi_ut_value_exit (
EXPORT_SYMBOL(acpi_ut_value_exit);
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_ptr_exit
*
@@ -469,14 +471,14 @@ EXPORT_SYMBOL(acpi_ut_value_exit);
* proc_name - Caller's procedure name
* module_name - Caller's module name
* component_id - Caller's component ID
- * Value - Value to be printed with exit msg
+ * Ptr - Pointer to display
*
* RETURN: None
*
* DESCRIPTION: Function exit trace. Prints only if TRACE_FUNCTIONS bit is
* set in debug_level. Prints exit value also.
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_ptr_exit (
@@ -494,7 +496,7 @@ acpi_ut_ptr_exit (
#endif
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_dump_buffer
*
@@ -507,7 +509,7 @@ acpi_ut_ptr_exit (
*
* DESCRIPTION: Generic dump buffer in both hex and ascii.
*
- ****************************************************************************/
+ ******************************************************************************/
void
acpi_ut_dump_buffer (
@@ -533,34 +535,28 @@ acpi_ut_dump_buffer (
display = DB_BYTE_DISPLAY;
}
- acpi_os_printf ("\nOffset Value\n");
+ /* Nasty little dump buffer routine! */
- /*
- * Nasty little dump buffer routine!
- */
while (i < count) {
/* Print current offset */
- acpi_os_printf ("%05X ", (u32) i);
+ acpi_os_printf ("%6.4X: ", (u32) i);
/* Print 16 hex chars */
for (j = 0; j < 16;) {
if (i + j >= count) {
- acpi_os_printf ("\n");
- return;
- }
+ /* Dump fill spaces */
- /* Make sure that the s8 doesn't get sign-extended! */
+ acpi_os_printf ("%*s", ((display * 2) + 1), " ");
+ j += display;
+ continue;
+ }
switch (display) {
- /* Default is BYTE display */
+ default: /* Default is BYTE display */
- default:
-
- acpi_os_printf ("%02X ",
- *((u8 *) &buffer[i + j]));
- j += 1;
+ acpi_os_printf ("%02X ", buffer[i + j]);
break;
@@ -568,7 +564,6 @@ acpi_ut_dump_buffer (
ACPI_MOVE_16_TO_32 (&temp32, &buffer[i + j]);
acpi_os_printf ("%04X ", temp32);
- j += 2;
break;
@@ -576,7 +571,6 @@ acpi_ut_dump_buffer (
ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j]);
acpi_os_printf ("%08X ", temp32);
- j += 4;
break;
@@ -587,15 +581,17 @@ acpi_ut_dump_buffer (
ACPI_MOVE_32_TO_32 (&temp32, &buffer[i + j + 4]);
acpi_os_printf ("%08X ", temp32);
- j += 8;
break;
}
+
+ j += display;
}
/*
* Print the ASCII equivalent characters
* But watch out for the bad unprintable ones...
*/
+ acpi_os_printf (" ");
for (j = 0; j < 16; j++) {
if (i + j >= count) {
acpi_os_printf ("\n");
diff --git a/drivers/acpi/utilities/utdelete.c b/drivers/acpi/utilities/utdelete.c
index 9a52ad52a23a..bc5403022681 100644
--- a/drivers/acpi/utilities/utdelete.c
+++ b/drivers/acpi/utilities/utdelete.c
@@ -51,12 +51,23 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utdelete")
+/* Local prototypes */
+
+static void
+acpi_ut_delete_internal_obj (
+ union acpi_operand_object *object);
+
+static void
+acpi_ut_update_ref_count (
+ union acpi_operand_object *object,
+ u32 action);
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_delete_internal_obj
*
- * PARAMETERS: *Object - Pointer to the list to be deleted
+ * PARAMETERS: Object - Object to be deleted
*
* RETURN: None
*
@@ -65,7 +76,7 @@
*
******************************************************************************/
-void
+static void
acpi_ut_delete_internal_obj (
union acpi_operand_object *object)
{
@@ -152,7 +163,8 @@ acpi_ut_delete_internal_obj (
case ACPI_TYPE_MUTEX:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Mutex %p, Semaphore %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "***** Mutex %p, Semaphore %p\n",
object, object->mutex.semaphore));
acpi_ex_unlink_mutex (object);
@@ -162,7 +174,8 @@ acpi_ut_delete_internal_obj (
case ACPI_TYPE_EVENT:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Event %p, Semaphore %p\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "***** Event %p, Semaphore %p\n",
object, object->event.semaphore));
(void) acpi_os_delete_semaphore (object->event.semaphore);
@@ -172,7 +185,8 @@ acpi_ut_delete_internal_obj (
case ACPI_TYPE_METHOD:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Method %p\n", object));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "***** Method %p\n", object));
/* Delete the method semaphore if it exists */
@@ -185,7 +199,8 @@ acpi_ut_delete_internal_obj (
case ACPI_TYPE_REGION:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Region %p\n", object));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "***** Region %p\n", object));
second_desc = acpi_ns_get_secondary_object (object);
if (second_desc) {
@@ -212,7 +227,8 @@ acpi_ut_delete_internal_obj (
case ACPI_TYPE_BUFFER_FIELD:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "***** Buffer Field %p\n", object));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "***** Buffer Field %p\n", object));
second_desc = acpi_ns_get_secondary_object (object);
if (second_desc) {
@@ -247,7 +263,7 @@ acpi_ut_delete_internal_obj (
*
* FUNCTION: acpi_ut_delete_internal_object_list
*
- * PARAMETERS: *obj_list - Pointer to the list to be deleted
+ * PARAMETERS: obj_list - Pointer to the list to be deleted
*
* RETURN: None
*
@@ -283,7 +299,7 @@ acpi_ut_delete_internal_object_list (
*
* FUNCTION: acpi_ut_update_ref_count
*
- * PARAMETERS: *Object - Object whose ref count is to be updated
+ * PARAMETERS: Object - Object whose ref count is to be updated
* Action - What to do
*
* RETURN: New ref count
@@ -312,7 +328,8 @@ acpi_ut_update_ref_count (
new_count = count;
/*
- * Perform the reference count action (increment, decrement, or force delete)
+ * Perform the reference count action
+ * (increment, decrement, or force delete)
*/
switch (action) {
@@ -321,7 +338,8 @@ acpi_ut_update_ref_count (
new_count++;
object->common.reference_count = new_count;
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Incremented]\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Refs=%X, [Incremented]\n",
object, new_count));
break;
@@ -329,7 +347,8 @@ acpi_ut_update_ref_count (
case REF_DECREMENT:
if (count < 1) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Refs=%X, can't decrement! (Set to 0)\n",
object, new_count));
new_count = 0;
@@ -337,12 +356,14 @@ acpi_ut_update_ref_count (
else {
new_count--;
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, [Decremented]\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Refs=%X, [Decremented]\n",
object, new_count));
}
if (ACPI_GET_OBJECT_TYPE (object) == ACPI_TYPE_METHOD) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Method Obj %p Refs=%X, [Decremented]\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Method Obj %p Refs=%X, [Decremented]\n",
object, new_count));
}
@@ -356,7 +377,8 @@ acpi_ut_update_ref_count (
case REF_FORCE_DELETE:
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Obj %p Refs=%X, Force delete! (Set to 0)\n",
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Obj %p Refs=%X, Force delete! (Set to 0)\n",
object, count));
new_count = 0;
@@ -390,7 +412,7 @@ acpi_ut_update_ref_count (
*
* FUNCTION: acpi_ut_update_object_reference
*
- * PARAMETERS: *Object - Increment ref count for this object
+ * PARAMETERS: Object - Increment ref count for this object
* and all sub-objects
* Action - Either REF_INCREMENT or REF_DECREMENT or
* REF_FORCE_DELETE
@@ -431,7 +453,8 @@ acpi_ut_update_object_reference (
/* Make sure that this isn't a namespace handle */
if (ACPI_GET_DESCRIPTOR_TYPE (object) == ACPI_DESC_TYPE_NAMED) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS, "Object %p is NS handle\n", object));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ALLOCATIONS,
+ "Object %p is NS handle\n", object));
return_ACPI_STATUS (AE_OK);
}
@@ -614,8 +637,8 @@ error_exit:
*
* FUNCTION: acpi_ut_add_reference
*
- * PARAMETERS: *Object - Object whose reference count is to be
- * incremented
+ * PARAMETERS: Object - Object whose reference count is to be
+ * incremented
*
* RETURN: None
*
@@ -652,7 +675,7 @@ acpi_ut_add_reference (
*
* FUNCTION: acpi_ut_remove_reference
*
- * PARAMETERS: *Object - Object whose ref count will be decremented
+ * PARAMETERS: Object - Object whose ref count will be decremented
*
* RETURN: None
*
diff --git a/drivers/acpi/utilities/uteval.c b/drivers/acpi/utilities/uteval.c
index ead27d2c4d18..00046dd5d925 100644
--- a/drivers/acpi/utilities/uteval.c
+++ b/drivers/acpi/utilities/uteval.c
@@ -50,6 +50,19 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("uteval")
+/* Local prototypes */
+
+static void
+acpi_ut_copy_id_string (
+ char *destination,
+ char *source,
+ acpi_size max_length);
+
+static acpi_status
+acpi_ut_translate_one_cid (
+ union acpi_operand_object *obj_desc,
+ struct acpi_compatible_id *one_cid);
+
/*******************************************************************************
*
@@ -237,9 +250,9 @@ acpi_ut_evaluate_object (
*
* FUNCTION: acpi_ut_evaluate_numeric_object
*
- * PARAMETERS: *object_name - Object name to be evaluated
+ * PARAMETERS: object_name - Object name to be evaluated
* device_node - Node for the device
- * *Address - Where the value is returned
+ * Address - Where the value is returned
*
* RETURN: Status
*
@@ -303,7 +316,6 @@ acpi_ut_copy_id_string (
acpi_size max_length)
{
-
/*
* Workaround for ID strings that have a leading asterisk. This construct
* is not allowed by the ACPI specification (ID strings must be
@@ -325,7 +337,7 @@ acpi_ut_copy_id_string (
* FUNCTION: acpi_ut_execute_HID
*
* PARAMETERS: device_node - Node for the device
- * *Hid - Where the HID is returned
+ * Hid - Where the HID is returned
*
* RETURN: Status
*
@@ -429,7 +441,7 @@ acpi_ut_translate_one_cid (
* FUNCTION: acpi_ut_execute_CID
*
* PARAMETERS: device_node - Node for the device
- * *Cid - Where the CID is returned
+ * return_cid_list - Where the CID list is returned
*
* RETURN: Status
*
@@ -488,10 +500,10 @@ acpi_ut_execute_CID (
cid_list->size = size;
/*
- * A _CID can return either a single compatible ID or a package of compatible
- * IDs. Each compatible ID can be one of the following:
- * -- Number (32 bit compressed EISA ID) or
- * -- String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss").
+ * A _CID can return either a single compatible ID or a package of
+ * compatible IDs. Each compatible ID can be one of the following:
+ * 1) Integer (32 bit compressed EISA ID) or
+ * 2) String (PCI ID format, e.g. "PCI\VEN_vvvv&DEV_dddd&SUBSYS_ssssssss")
*/
/* The _CID object can be either a single CID or a package (list) of CIDs */
@@ -534,7 +546,7 @@ acpi_ut_execute_CID (
* FUNCTION: acpi_ut_execute_UID
*
* PARAMETERS: device_node - Node for the device
- * *Uid - Where the UID is returned
+ * Uid - Where the UID is returned
*
* RETURN: Status
*
@@ -587,7 +599,7 @@ acpi_ut_execute_UID (
* FUNCTION: acpi_ut_execute_STA
*
* PARAMETERS: device_node - Node for the device
- * *Flags - Where the status flags are returned
+ * Flags - Where the status flags are returned
*
* RETURN: Status
*
@@ -641,7 +653,7 @@ acpi_ut_execute_STA (
* FUNCTION: acpi_ut_execute_Sxds
*
* PARAMETERS: device_node - Node for the device
- * *Flags - Where the status flags are returned
+ * Flags - Where the status flags are returned
*
* RETURN: Status
*
diff --git a/drivers/acpi/utilities/utglobal.c b/drivers/acpi/utilities/utglobal.c
index 25b0f8ae1bc6..4146019b543f 100644
--- a/drivers/acpi/utilities/utglobal.c
+++ b/drivers/acpi/utilities/utglobal.c
@@ -44,7 +44,6 @@
#define DEFINE_ACPI_GLOBALS
#include <linux/module.h>
-
#include <acpi/acpi.h>
#include <acpi/acnamesp.h>
@@ -52,13 +51,14 @@
ACPI_MODULE_NAME ("utglobal")
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_format_exception
*
* PARAMETERS: Status - The acpi_status code to be formatted
*
- * RETURN: A string containing the exception text
+ * RETURN: A string containing the exception text. A valid pointer is
+ * always returned.
*
* DESCRIPTION: This function translates an ACPI exception into an ASCII string.
*
@@ -68,8 +68,8 @@ const char *
acpi_format_exception (
acpi_status status)
{
- const char *exception = "UNKNOWN_STATUS_CODE";
acpi_status sub_status;
+ const char *exception = NULL;
ACPI_FUNCTION_NAME ("format_exception");
@@ -82,57 +82,55 @@ acpi_format_exception (
if (sub_status <= AE_CODE_ENV_MAX) {
exception = acpi_gbl_exception_names_env [sub_status];
- break;
}
- goto unknown;
+ break;
case AE_CODE_PROGRAMMER:
if (sub_status <= AE_CODE_PGM_MAX) {
exception = acpi_gbl_exception_names_pgm [sub_status -1];
- break;
}
- goto unknown;
+ break;
case AE_CODE_ACPI_TABLES:
if (sub_status <= AE_CODE_TBL_MAX) {
exception = acpi_gbl_exception_names_tbl [sub_status -1];
- break;
}
- goto unknown;
+ break;
case AE_CODE_AML:
if (sub_status <= AE_CODE_AML_MAX) {
exception = acpi_gbl_exception_names_aml [sub_status -1];
- break;
}
- goto unknown;
+ break;
case AE_CODE_CONTROL:
if (sub_status <= AE_CODE_CTRL_MAX) {
exception = acpi_gbl_exception_names_ctrl [sub_status -1];
- break;
}
- goto unknown;
+ break;
default:
- goto unknown;
+ break;
}
+ if (!exception) {
+ /* Exception code was not recognized */
- return ((const char *) exception);
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Unknown exception code: 0x%8.8X\n", status));
-unknown:
+ return ((const char *) "UNKNOWN_STATUS_CODE");
+ }
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Unknown exception code: 0x%8.8X\n", status));
return ((const char *) exception);
}
-/******************************************************************************
+/*******************************************************************************
*
* Static global variable initialization.
*
@@ -212,13 +210,12 @@ const char *acpi_gbl_valid_osi_strings[ACPI_NUM_OSI_STR
};
-/******************************************************************************
+/*******************************************************************************
*
* Namespace globals
*
******************************************************************************/
-
/*
* Predefined ACPI Names (Built-in to the Interpreter)
*
@@ -241,9 +238,11 @@ const struct acpi_predefined_names acpi_gbl_pre_defined_names[] =
#if !defined (ACPI_NO_METHOD_EXECUTION) || defined (ACPI_CONSTANT_EVAL_ONLY)
{"_OSI", ACPI_TYPE_METHOD, (char *) 1},
#endif
- {NULL, ACPI_TYPE_ANY, NULL} /* Table terminator */
-};
+ /* Table terminator */
+
+ {NULL, ACPI_TYPE_ANY, NULL}
+};
/*
* Properties of the ACPI Object Types, both internal and external.
@@ -288,22 +287,25 @@ const u8 acpi_gbl_ns_properties[] =
/* Hex to ASCII conversion table */
static const char acpi_gbl_hex_to_ascii[] =
- {'0','1','2','3','4','5','6','7',
- '8','9','A','B','C','D','E','F'};
+{
+ '0','1','2','3','4','5','6','7',
+ '8','9','A','B','C','D','E','F'
+};
+
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_hex_to_ascii_char
*
* PARAMETERS: Integer - Contains the hex digit
* Position - bit position of the digit within the
- * integer
+ * integer (multiple of 4)
*
- * RETURN: Ascii character
+ * RETURN: The converted Ascii character
*
- * DESCRIPTION: Convert a hex digit to an ascii character
+ * DESCRIPTION: Convert a hex digit to an Ascii character
*
- ****************************************************************************/
+ ******************************************************************************/
char
acpi_ut_hex_to_ascii_char (
@@ -315,7 +317,7 @@ acpi_ut_hex_to_ascii_char (
}
-/******************************************************************************
+/*******************************************************************************
*
* Table name globals
*
@@ -324,7 +326,7 @@ acpi_ut_hex_to_ascii_char (
* that are not used by the subsystem are simply ignored.
*
* Do NOT add any table to this list that is not consumed directly by this
- * subsystem.
+ * subsystem (No MADT, ECDT, SBST, etc.)
*
******************************************************************************/
@@ -391,7 +393,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE
/* ACPI_EVENT_RTC */ {ACPI_BITREG_RT_CLOCK_STATUS, ACPI_BITREG_RT_CLOCK_ENABLE, ACPI_BITMASK_RT_CLOCK_STATUS, ACPI_BITMASK_RT_CLOCK_ENABLE},
};
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_region_name
*
@@ -401,7 +403,7 @@ struct acpi_fixed_event_info acpi_gbl_fixed_event_info[ACPI_NUM_FIXED_EVE
*
* DESCRIPTION: Translate a Space ID into a name string (Debug only)
*
- ****************************************************************************/
+ ******************************************************************************/
/* Region type decoding */
@@ -429,7 +431,6 @@ acpi_ut_get_region_name (
{
return ("user_defined_region");
}
-
else if (space_id >= ACPI_NUM_PREDEFINED_REGIONS)
{
return ("invalid_space_id");
@@ -439,7 +440,7 @@ acpi_ut_get_region_name (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_event_name
*
@@ -449,7 +450,7 @@ acpi_ut_get_region_name (
*
* DESCRIPTION: Translate a Event ID into a name string (Debug only)
*
- ****************************************************************************/
+ ******************************************************************************/
/* Event type decoding */
@@ -477,7 +478,7 @@ acpi_ut_get_event_name (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_type_name
*
@@ -487,20 +488,21 @@ acpi_ut_get_event_name (
*
* DESCRIPTION: Translate a Type ID into a name string (Debug only)
*
- ****************************************************************************/
+ ******************************************************************************/
/*
* Elements of acpi_gbl_ns_type_names below must match
* one-to-one with values of acpi_object_type
*
- * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching; when
- * stored in a table it really means that we have thus far seen no evidence to
- * indicate what type is actually going to be stored for this entry.
+ * The type ACPI_TYPE_ANY (Untyped) is used as a "don't care" when searching;
+ * when stored in a table it really means that we have thus far seen no
+ * evidence to indicate what type is actually going to be stored for this entry.
*/
static const char acpi_gbl_bad_type[] = "UNDEFINED";
-#define TYPE_NAME_LENGTH 12 /* Maximum length of each string */
-static const char *acpi_gbl_ns_type_names[] = /* printable names of ACPI types */
+/* Printable names of the ACPI object types */
+
+static const char *acpi_gbl_ns_type_names[] =
{
/* 00 */ "Untyped",
/* 01 */ "Integer",
@@ -564,7 +566,7 @@ acpi_ut_get_object_type_name (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_node_name
*
@@ -574,7 +576,7 @@ acpi_ut_get_object_type_name (
*
* DESCRIPTION: Validate the node and return the node's ACPI name.
*
- ****************************************************************************/
+ ******************************************************************************/
char *
acpi_ut_get_node_name (
@@ -618,7 +620,7 @@ acpi_ut_get_node_name (
}
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_descriptor_name
*
@@ -628,9 +630,11 @@ acpi_ut_get_node_name (
*
* DESCRIPTION: Validate object and return the descriptor type
*
- ****************************************************************************/
+ ******************************************************************************/
+
+/* Printable names of object descriptor types */
-static const char *acpi_gbl_desc_type_names[] = /* printable names of descriptor types */
+static const char *acpi_gbl_desc_type_names[] =
{
/* 00 */ "Invalid",
/* 01 */ "Cached",
@@ -676,17 +680,18 @@ acpi_ut_get_descriptor_name (
* Strings and procedures used for debug only
*/
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_get_mutex_name
*
- * PARAMETERS: None.
+ * PARAMETERS: mutex_id - The predefined ID for this mutex.
*
- * RETURN: Status
+ * RETURN: String containing the name of the mutex. Always returns a valid
+ * pointer.
*
* DESCRIPTION: Translate a mutex ID into a name string (Debug only)
*
- ****************************************************************************/
+ ******************************************************************************/
char *
acpi_ut_get_mutex_name (
@@ -700,21 +705,20 @@ acpi_ut_get_mutex_name (
return (acpi_gbl_mutex_names[mutex_id]);
}
-
#endif
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_valid_object_type
*
* PARAMETERS: Type - Object type to be validated
*
- * RETURN: TRUE if valid object type
+ * RETURN: TRUE if valid object type, FALSE otherwise
*
* DESCRIPTION: Validate an object type
*
- ****************************************************************************/
+ ******************************************************************************/
u8
acpi_ut_valid_object_type (
@@ -732,7 +736,7 @@ acpi_ut_valid_object_type (
}
-/****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_allocate_owner_id
*
@@ -740,7 +744,10 @@ acpi_ut_valid_object_type (
*
* DESCRIPTION: Allocate a table or method owner id
*
- ***************************************************************************/
+ * NOTE: this algorithm has a wraparound problem at 64_k method invocations, and
+ * should be revisited (TBD)
+ *
+ ******************************************************************************/
acpi_owner_id
acpi_ut_allocate_owner_id (
@@ -796,16 +803,18 @@ acpi_ut_allocate_owner_id (
}
-/****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_ut_init_globals
*
- * PARAMETERS: none
+ * PARAMETERS: None
+ *
+ * RETURN: None
*
* DESCRIPTION: Init library globals. All globals that require specific
* initialization should be initialized here!
*
- ***************************************************************************/
+ ******************************************************************************/
void
acpi_ut_init_globals (
diff --git a/drivers/acpi/utilities/utinit.c b/drivers/acpi/utilities/utinit.c
index bdbadaf48d29..7f3713889ff0 100644
--- a/drivers/acpi/utilities/utinit.c
+++ b/drivers/acpi/utilities/utinit.c
@@ -49,19 +49,29 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utinit")
+/* Local prototypes */
+
+static void
+acpi_ut_fadt_register_error (
+ char *register_name,
+ u32 value,
+ acpi_size offset);
+
+static void acpi_ut_terminate (
+ void);
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_fadt_register_error
*
- * PARAMETERS: *register_name - Pointer to string identifying register
+ * PARAMETERS: register_name - Pointer to string identifying register
* Value - Actual register contents value
- * acpi_test_spec_section - TDS section containing assertion
- * acpi_assertion - Assertion number being tested
+ * Offset - Byte offset in the FADT
*
* RETURN: AE_BAD_VALUE
*
- * DESCRIPTION: Display failure message and link failure to TDS assertion
+ * DESCRIPTION: Display failure message
*
******************************************************************************/
@@ -166,12 +176,13 @@ acpi_ut_validate_fadt (
*
* RETURN: none
*
- * DESCRIPTION: free global memory
+ * DESCRIPTION: Free global memory
*
******************************************************************************/
-void
-acpi_ut_terminate (void)
+static void
+acpi_ut_terminate (
+ void)
{
struct acpi_gpe_block_info *gpe_block;
struct acpi_gpe_block_info *next_gpe_block;
@@ -183,8 +194,6 @@ acpi_ut_terminate (void)
/* Free global tables, etc. */
-
-
/* Free global GPE blocks and related info structures */
gpe_xrupt_info = acpi_gbl_gpe_xrupt_list_head;
@@ -221,7 +230,8 @@ acpi_ut_terminate (void)
******************************************************************************/
void
-acpi_ut_subsystem_shutdown (void)
+acpi_ut_subsystem_shutdown (
+ void)
{
ACPI_FUNCTION_TRACE ("ut_subsystem_shutdown");
@@ -229,14 +239,16 @@ acpi_ut_subsystem_shutdown (void)
/* Just exit if subsystem is already shutdown */
if (acpi_gbl_shutdown) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "ACPI Subsystem is already terminated\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "ACPI Subsystem is already terminated\n"));
return_VOID;
}
/* Subsystem appears active, go ahead and shut it down */
acpi_gbl_shutdown = TRUE;
- ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Shutting down ACPI Subsystem...\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
+ "Shutting down ACPI Subsystem...\n"));
/* Close the acpi_event Handling */
diff --git a/drivers/acpi/utilities/utmath.c b/drivers/acpi/utilities/utmath.c
index 2525c1a93547..0d527c91543c 100644
--- a/drivers/acpi/utilities/utmath.c
+++ b/drivers/acpi/utilities/utmath.c
@@ -259,6 +259,8 @@ acpi_ut_divide (
*
* FUNCTION: acpi_ut_short_divide, acpi_ut_divide
*
+ * PARAMETERS: See function headers above
+ *
* DESCRIPTION: Native versions of the ut_divide functions. Use these if either
* 1) The target is a 64-bit platform and therefore 64-bit
* integer math is supported directly by the machine.
diff --git a/drivers/acpi/utilities/utmisc.c b/drivers/acpi/utilities/utmisc.c
index f6598547389b..f6de4ed3d527 100644
--- a/drivers/acpi/utilities/utmisc.c
+++ b/drivers/acpi/utilities/utmisc.c
@@ -49,12 +49,57 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utmisc")
+/* Local prototypes */
+
+static acpi_status
+acpi_ut_create_mutex (
+ acpi_mutex_handle mutex_id);
+
+static acpi_status
+acpi_ut_delete_mutex (
+ acpi_mutex_handle mutex_id);
+
+
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_ut_strupr (strupr)
+ *
+ * PARAMETERS: src_string - The source string to convert
+ *
+ * RETURN: Converted src_string (same as input pointer)
+ *
+ * DESCRIPTION: Convert string to uppercase
+ *
+ * NOTE: This is not a POSIX function, so it appears here, not in utclib.c
+ *
+ ******************************************************************************/
+
+char *
+acpi_ut_strupr (
+ char *src_string)
+{
+ char *string;
+
+
+ ACPI_FUNCTION_ENTRY ();
+
+
+ /* Walk entire string, uppercasing the letters */
+
+ for (string = src_string; *string; string++) {
+ *string = (char) ACPI_TOUPPER (*string);
+ }
+
+ return (src_string);
+}
+
/*******************************************************************************
*
* FUNCTION: acpi_ut_print_string
*
* PARAMETERS: String - Null terminated ASCII string
+ * max_length - Maximum output length
*
* RETURN: None
*
@@ -148,6 +193,8 @@ acpi_ut_print_string (
*
* PARAMETERS: Value - Value to be converted
*
+ * RETURN: u32 integer with bytes swapped
+ *
* DESCRIPTION: Convert a 32-bit value to big-endian (swap the bytes)
*
******************************************************************************/
@@ -160,7 +207,6 @@ acpi_ut_dword_byte_swap (
u32 value;
u8 bytes[4];
} out;
-
union {
u32 value;
u8 bytes[4];
@@ -219,7 +265,8 @@ acpi_ut_set_integer_width (
*
* FUNCTION: acpi_ut_display_init_pathname
*
- * PARAMETERS: obj_handle - Handle whose pathname will be displayed
+ * PARAMETERS: Type - Object type of the node
+ * obj_handle - Handle whose pathname will be displayed
* Path - Additional path string to be appended.
* (NULL if no extra path)
*
@@ -270,7 +317,8 @@ acpi_ut_display_init_pathname (
/* Print the object type and pathname */
- acpi_os_printf ("%-12s %s", acpi_ut_get_type_name (type), (char *) buffer.pointer);
+ acpi_os_printf ("%-12s %s",
+ acpi_ut_get_type_name (type), (char *) buffer.pointer);
/* Extra path is used to append names like _STA, _INI, etc. */
@@ -288,9 +336,9 @@ acpi_ut_display_init_pathname (
*
* FUNCTION: acpi_ut_valid_acpi_name
*
- * PARAMETERS: Character - The character to be examined
+ * PARAMETERS: Name - The name to be examined
*
- * RETURN: 1 if Character may appear in a name, else 0
+ * RETURN: TRUE if the name is valid, FALSE otherwise
*
* DESCRIPTION: Check for a valid ACPI name. Each character must be one of:
* 1) Upper case alpha
@@ -495,40 +543,6 @@ error_exit:
/*******************************************************************************
*
- * FUNCTION: acpi_ut_strupr
- *
- * PARAMETERS: src_string - The source string to convert to
- *
- * RETURN: src_string
- *
- * DESCRIPTION: Convert string to uppercase
- *
- ******************************************************************************/
-#ifdef ACPI_FUTURE_USAGE
-char *
-acpi_ut_strupr (
- char *src_string)
-{
- char *string;
-
-
- ACPI_FUNCTION_ENTRY ();
-
-
- /* Walk entire string, uppercasing the letters */
-
- for (string = src_string; *string; ) {
- *string = (char) ACPI_TOUPPER (*string);
- string++;
- }
-
- return (src_string);
-}
-#endif /* ACPI_FUTURE_USAGE */
-
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ut_mutex_initialize
*
* PARAMETERS: None.
@@ -611,7 +625,7 @@ acpi_ut_mutex_terminate (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_create_mutex (
acpi_mutex_handle mutex_id)
{
@@ -648,7 +662,7 @@ acpi_ut_create_mutex (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_delete_mutex (
acpi_mutex_handle mutex_id)
{
@@ -715,16 +729,16 @@ acpi_ut_acquire_mutex (
if (acpi_gbl_mutex_info[i].owner_id == this_thread_id) {
if (i == mutex_id) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Mutex [%s] already acquired by this thread [%X]\n",
- acpi_ut_get_mutex_name (mutex_id), this_thread_id));
+ "Mutex [%s] already acquired by this thread [%X]\n",
+ acpi_ut_get_mutex_name (mutex_id), this_thread_id));
return (AE_ALREADY_ACQUIRED);
}
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Invalid acquire order: Thread %X owns [%s], wants [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name (i),
- acpi_ut_get_mutex_name (mutex_id)));
+ "Invalid acquire order: Thread %X owns [%s], wants [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (i),
+ acpi_ut_get_mutex_name (mutex_id)));
return (AE_ACQUIRE_DEADLOCK);
}
@@ -733,22 +747,23 @@ acpi_ut_acquire_mutex (
#endif
ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX,
- "Thread %X attempting to acquire Mutex [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+ "Thread %X attempting to acquire Mutex [%s]\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
status = acpi_os_wait_semaphore (acpi_gbl_mutex_info[mutex_id].mutex,
1, ACPI_WAIT_FOREVER);
if (ACPI_SUCCESS (status)) {
ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X acquired Mutex [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
acpi_gbl_mutex_info[mutex_id].use_count++;
acpi_gbl_mutex_info[mutex_id].owner_id = this_thread_id;
}
else {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not acquire Mutex [%s] %s\n",
- this_thread_id, acpi_ut_get_mutex_name (mutex_id),
- acpi_format_exception (status)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Thread %X could not acquire Mutex [%s] %s\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id),
+ acpi_format_exception (status)));
}
return (status);
@@ -793,8 +808,8 @@ acpi_ut_release_mutex (
*/
if (acpi_gbl_mutex_info[mutex_id].owner_id == ACPI_MUTEX_NOT_ACQUIRED) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Mutex [%s] is not acquired, cannot release\n",
- acpi_ut_get_mutex_name (mutex_id)));
+ "Mutex [%s] is not acquired, cannot release\n",
+ acpi_ut_get_mutex_name (mutex_id)));
return (AE_NOT_ACQUIRED);
}
@@ -812,8 +827,8 @@ acpi_ut_release_mutex (
}
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
- "Invalid release order: owns [%s], releasing [%s]\n",
- acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id)));
+ "Invalid release order: owns [%s], releasing [%s]\n",
+ acpi_ut_get_mutex_name (i), acpi_ut_get_mutex_name (mutex_id)));
return (AE_RELEASE_DEADLOCK);
}
@@ -826,13 +841,14 @@ acpi_ut_release_mutex (
status = acpi_os_signal_semaphore (acpi_gbl_mutex_info[mutex_id].mutex, 1);
if (ACPI_FAILURE (status)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Thread %X could not release Mutex [%s] %s\n",
- this_thread_id, acpi_ut_get_mutex_name (mutex_id),
- acpi_format_exception (status)));
+ ACPI_DEBUG_PRINT ((ACPI_DB_ERROR,
+ "Thread %X could not release Mutex [%s] %s\n",
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id),
+ acpi_format_exception (status)));
}
else {
ACPI_DEBUG_PRINT ((ACPI_DB_MUTEX, "Thread %X released Mutex [%s]\n",
- this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
+ this_thread_id, acpi_ut_get_mutex_name (mutex_id)));
}
return (status);
@@ -843,11 +859,11 @@ acpi_ut_release_mutex (
*
* FUNCTION: acpi_ut_create_update_state_and_push
*
- * PARAMETERS: *Object - Object to be added to the new state
+ * PARAMETERS: Object - Object to be added to the new state
* Action - Increment/Decrement
* state_list - List the state will be added to
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Create a new state and push it
*
@@ -885,15 +901,16 @@ acpi_ut_create_update_state_and_push (
*
* FUNCTION: acpi_ut_create_pkg_state_and_push
*
- * PARAMETERS: *Object - Object to be added to the new state
+ * PARAMETERS: Object - Object to be added to the new state
* Action - Increment/Decrement
* state_list - List the state will be added to
*
- * RETURN: None
+ * RETURN: Status
*
* DESCRIPTION: Create a new state and push it
*
******************************************************************************/
+
#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_ut_create_pkg_state_and_push (
@@ -925,7 +942,7 @@ acpi_ut_create_pkg_state_and_push (
* PARAMETERS: list_head - Head of the state stack
* State - State object to push
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Push a state object onto a state stack
*
@@ -954,7 +971,7 @@ acpi_ut_push_generic_state (
*
* PARAMETERS: list_head - Head of the state stack
*
- * RETURN: Status
+ * RETURN: The popped state object
*
* DESCRIPTION: Pop a state object from a state stack
*
@@ -989,7 +1006,7 @@ acpi_ut_pop_generic_state (
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: The new state object. NULL on failure.
*
* DESCRIPTION: Create a generic state object. Attempt to obtain one from
* the global state cache; If none available, create a new one.
@@ -997,7 +1014,8 @@ acpi_ut_pop_generic_state (
******************************************************************************/
union acpi_generic_state *
-acpi_ut_create_generic_state (void)
+acpi_ut_create_generic_state (
+ void)
{
union acpi_generic_state *state;
@@ -1023,7 +1041,7 @@ acpi_ut_create_generic_state (void)
*
* PARAMETERS: None
*
- * RETURN: Thread State
+ * RETURN: New Thread State. NULL on failure
*
* DESCRIPTION: Create a "Thread State" - a flavor of the generic state used
* to track per-thread info during method execution
@@ -1060,11 +1078,10 @@ acpi_ut_create_thread_state (
*
* FUNCTION: acpi_ut_create_update_state
*
- * PARAMETERS: Object - Initial Object to be installed in the
- * state
- * Action - Update action to be performed
+ * PARAMETERS: Object - Initial Object to be installed in the state
+ * Action - Update action to be performed
*
- * RETURN: Status
+ * RETURN: New state object, null on failure
*
* DESCRIPTION: Create an "Update State" - a flavor of the generic state used
* to update reference counts and delete complex objects such
@@ -1104,11 +1121,10 @@ acpi_ut_create_update_state (
*
* FUNCTION: acpi_ut_create_pkg_state
*
- * PARAMETERS: Object - Initial Object to be installed in the
- * state
- * Action - Update action to be performed
+ * PARAMETERS: Object - Initial Object to be installed in the state
+ * Action - Update action to be performed
*
- * RETURN: Status
+ * RETURN: New state object, null on failure
*
* DESCRIPTION: Create a "Package State"
*
@@ -1151,7 +1167,7 @@ acpi_ut_create_pkg_state (
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: New state object, null on failure
*
* DESCRIPTION: Create a "Control State" - a flavor of the generic state used
* to support nested IF/WHILE constructs in the AML.
@@ -1190,7 +1206,7 @@ acpi_ut_create_control_state (
*
* PARAMETERS: State - The state object to be deleted
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Put a state object back into the global state cache. The object
* is not actually freed at this time.
@@ -1216,7 +1232,7 @@ acpi_ut_delete_generic_state (
*
* PARAMETERS: None
*
- * RETURN: Status
+ * RETURN: None
*
* DESCRIPTION: Purge the global state object cache. Used during subsystem
* termination.
@@ -1240,7 +1256,10 @@ acpi_ut_delete_generic_state_cache (
*
* FUNCTION: acpi_ut_walk_package_tree
*
- * PARAMETERS: obj_desc - The Package object on which to resolve refs
+ * PARAMETERS: source_object - The package to walk
+ * target_object - Target object (if package is being copied)
+ * walk_callback - Called once for each package element
+ * Context - Passed to the callback function
*
* RETURN: Status
*
@@ -1359,7 +1378,7 @@ acpi_ut_walk_package_tree (
* PARAMETERS: Buffer - Buffer to be scanned
* Length - number of bytes to examine
*
- * RETURN: checksum
+ * RETURN: The generated checksum
*
* DESCRIPTION: Generate a checksum on a raw buffer
*
@@ -1442,7 +1461,6 @@ acpi_ut_get_resource_end_tag (
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
* component_id - Caller's component ID (for error output)
- * Message - Error message to use on failure
*
* RETURN: None
*
@@ -1457,7 +1475,6 @@ acpi_ut_report_error (
u32 component_id)
{
-
acpi_os_printf ("%8s-%04d: *** Error: ", module_name, line_number);
}
@@ -1469,7 +1486,6 @@ acpi_ut_report_error (
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
* component_id - Caller's component ID (for error output)
- * Message - Error message to use on failure
*
* RETURN: None
*
@@ -1495,7 +1511,6 @@ acpi_ut_report_warning (
* PARAMETERS: module_name - Caller's module name (for error output)
* line_number - Caller's line number (for error output)
* component_id - Caller's component ID (for error output)
- * Message - Error message to use on failure
*
* RETURN: None
*
diff --git a/drivers/acpi/utilities/utobject.c b/drivers/acpi/utilities/utobject.c
index 9ee40a484e07..cd3899b9cc5a 100644
--- a/drivers/acpi/utilities/utobject.c
+++ b/drivers/acpi/utilities/utobject.c
@@ -50,6 +50,25 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME ("utobject")
+/* Local prototypes */
+
+static acpi_status
+acpi_ut_get_simple_object_size (
+ union acpi_operand_object *obj,
+ acpi_size *obj_length);
+
+static acpi_status
+acpi_ut_get_package_object_size (
+ union acpi_operand_object *obj,
+ acpi_size *obj_length);
+
+static acpi_status
+acpi_ut_get_element_length (
+ u8 object_type,
+ union acpi_operand_object *source_object,
+ union acpi_generic_state *state,
+ void *context);
+
/*******************************************************************************
*
@@ -60,7 +79,7 @@
* component_id - Component type of caller
* Type - ACPI Type of the new object
*
- * RETURN: Object - The new object. Null on failure
+ * RETURN: A new internal object, null on failure
*
* DESCRIPTION: Create and initialize a new internal object.
*
@@ -83,7 +102,8 @@ acpi_ut_create_internal_object_dbg (
union acpi_operand_object *second_object;
- ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg", acpi_ut_get_type_name (type));
+ ACPI_FUNCTION_TRACE_STR ("ut_create_internal_object_dbg",
+ acpi_ut_get_type_name (type));
/* Allocate the raw object descriptor */
@@ -99,7 +119,8 @@ acpi_ut_create_internal_object_dbg (
/* These types require a secondary object */
- second_object = acpi_ut_allocate_object_desc_dbg (module_name, line_number, component_id);
+ second_object = acpi_ut_allocate_object_desc_dbg (module_name,
+ line_number, component_id);
if (!second_object) {
acpi_ut_delete_object_desc (object);
return_PTR (NULL);
@@ -138,7 +159,7 @@ acpi_ut_create_internal_object_dbg (
*
* PARAMETERS: buffer_size - Size of buffer to be created
*
- * RETURN: Pointer to a new Buffer object
+ * RETURN: Pointer to a new Buffer object, null on failure
*
* DESCRIPTION: Create a fully initialized buffer object
*
@@ -192,9 +213,9 @@ acpi_ut_create_buffer_object (
*
* FUNCTION: acpi_ut_create_string_object
*
- * PARAMETERS: string_size - Size of string to be created. Does not
- * include NULL terminator, this is added
- * automatically.
+ * PARAMETERS: string_size - Size of string to be created. Does not
+ * include NULL terminator, this is added
+ * automatically.
*
* RETURN: Pointer to a new String object
*
@@ -249,7 +270,9 @@ acpi_ut_create_string_object (
*
* PARAMETERS: Object - Object to be validated
*
- * RETURN: Validate a pointer to be an union acpi_operand_object
+ * RETURN: TRUE if object is valid, FALSE otherwise
+ *
+ * DESCRIPTION: Validate a pointer to be an union acpi_operand_object
*
******************************************************************************/
@@ -399,8 +422,8 @@ acpi_ut_delete_object_cache (
*
* FUNCTION: acpi_ut_get_simple_object_size
*
- * PARAMETERS: *internal_object - Pointer to the object we are examining
- * *obj_length - Where the length is returned
+ * PARAMETERS: internal_object - An ACPI operand object
+ * obj_length - Where the length is returned
*
* RETURN: Status
*
@@ -412,7 +435,7 @@ acpi_ut_delete_object_cache (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_get_simple_object_size (
union acpi_operand_object *internal_object,
acpi_size *obj_length)
@@ -424,8 +447,10 @@ acpi_ut_get_simple_object_size (
ACPI_FUNCTION_TRACE_PTR ("ut_get_simple_object_size", internal_object);
- /* Handle a null object (Could be a uninitialized package element -- which is legal) */
-
+ /*
+ * Handle a null object (Could be a uninitialized package
+ * element -- which is legal)
+ */
if (!internal_object) {
*obj_length = 0;
return_ACPI_STATUS (AE_OK);
@@ -480,7 +505,8 @@ acpi_ut_get_simple_object_size (
* Get the actual length of the full pathname to this object.
* The reference will be converted to the pathname to the object
*/
- length += ACPI_ROUND_UP_TO_NATIVE_WORD (acpi_ns_get_pathname_length (internal_object->reference.node));
+ length += ACPI_ROUND_UP_TO_NATIVE_WORD (
+ acpi_ns_get_pathname_length (internal_object->reference.node));
break;
default:
@@ -530,7 +556,7 @@ acpi_ut_get_simple_object_size (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_get_element_length (
u8 object_type,
union acpi_operand_object *source_object,
@@ -582,8 +608,8 @@ acpi_ut_get_element_length (
*
* FUNCTION: acpi_ut_get_package_object_size
*
- * PARAMETERS: *internal_object - Pointer to the object we are examining
- * *obj_length - Where the length is returned
+ * PARAMETERS: internal_object - An ACPI internal object
+ * obj_length - Where the length is returned
*
* RETURN: Status
*
@@ -595,7 +621,7 @@ acpi_ut_get_element_length (
*
******************************************************************************/
-acpi_status
+static acpi_status
acpi_ut_get_package_object_size (
union acpi_operand_object *internal_object,
acpi_size *obj_length)
@@ -636,8 +662,8 @@ acpi_ut_get_package_object_size (
*
* FUNCTION: acpi_ut_get_object_size
*
- * PARAMETERS: *internal_object - Pointer to the object we are examining
- * *obj_length - Where the length will be returned
+ * PARAMETERS: internal_object - An ACPI internal object
+ * obj_length - Where the length will be returned
*
* RETURN: Status
*
@@ -647,7 +673,7 @@ acpi_ut_get_package_object_size (
******************************************************************************/
acpi_status
-acpi_ut_get_object_size(
+acpi_ut_get_object_size (
union acpi_operand_object *internal_object,
acpi_size *obj_length)
{
diff --git a/drivers/acpi/utilities/utxface.c b/drivers/acpi/utilities/utxface.c
index 97a91f3f06f0..e8803d810656 100644
--- a/drivers/acpi/utilities/utxface.c
+++ b/drivers/acpi/utilities/utxface.c
@@ -73,6 +73,7 @@ acpi_initialize_subsystem (
{
acpi_status status;
+
ACPI_FUNCTION_TRACE ("acpi_initialize_subsystem");
@@ -105,7 +106,6 @@ acpi_initialize_subsystem (
* Initialize the namespace manager and
* the root of the namespace tree
*/
-
status = acpi_ns_root_initialize ();
if (ACPI_FAILURE (status)) {
ACPI_REPORT_ERROR (("Namespace initialization failure, %s\n",
@@ -113,7 +113,6 @@ acpi_initialize_subsystem (
return_ACPI_STATUS (status);
}
-
/* If configured, initialize the AML debugger */
ACPI_DEBUGGER_EXEC (status = acpi_db_initialize ());
@@ -150,7 +149,8 @@ acpi_enable_subsystem (
* The values from the FADT are validated here.
*/
if (!(flags & ACPI_NO_HARDWARE_INIT)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI hardware\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Initializing ACPI hardware\n"));
status = acpi_hw_initialize ();
if (ACPI_FAILURE (status)) {
@@ -178,7 +178,8 @@ acpi_enable_subsystem (
* 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"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Installing default address space handlers\n"));
status = acpi_ev_install_region_handlers ();
if (ACPI_FAILURE (status)) {
@@ -189,12 +190,14 @@ acpi_enable_subsystem (
/*
* 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
- * support, so the hardware MUST be initialized before execution!
+ * NOTE: We must have the hardware AND events initialized before we can
+ * execute ANY control methods SAFELY. Any control method can require
+ * ACPI hardware support, so the hardware MUST be initialized before
+ * execution!
*/
if (!(flags & ACPI_NO_EVENT_INIT)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI events\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Initializing ACPI events\n"));
status = acpi_ev_initialize_events ();
if (ACPI_FAILURE (status)) {
@@ -205,7 +208,8 @@ acpi_enable_subsystem (
/* Install the SCI handler and Global Lock handler */
if (!(flags & ACPI_NO_HANDLER_INIT)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Installing SCI/GL handlers\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Installing SCI/GL handlers\n"));
status = acpi_ev_install_xrupt_handlers ();
if (ACPI_FAILURE (status)) {
@@ -247,7 +251,8 @@ acpi_initialize_objects (
* 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] Executing _REG op_region methods\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Executing _REG op_region methods\n"));
status = acpi_ev_initialize_op_regions ();
if (ACPI_FAILURE (status)) {
@@ -261,7 +266,8 @@ acpi_initialize_objects (
* objects: operation_regions, buffer_fields, Buffers, and Packages.
*/
if (!(flags & ACPI_NO_OBJECT_INIT)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Completing Initialization of 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)) {
@@ -274,7 +280,8 @@ acpi_initialize_objects (
* This runs the _STA and _INI methods.
*/
if (!(flags & ACPI_NO_DEVICE_INIT)) {
- ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "[Init] Initializing ACPI Devices\n"));
+ ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
+ "[Init] Initializing ACPI Devices\n"));
status = acpi_ns_initialize_devices ();
if (ACPI_FAILURE (status)) {
@@ -307,7 +314,8 @@ acpi_initialize_objects (
******************************************************************************/
acpi_status
-acpi_terminate (void)
+acpi_terminate (
+ void)
{
acpi_status status;
@@ -344,8 +352,7 @@ acpi_terminate (void)
#ifdef ACPI_FUTURE_USAGE
-
-/*****************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_subsystem_status
*
@@ -354,14 +361,16 @@ acpi_terminate (void)
* RETURN: Status of the ACPI subsystem
*
* DESCRIPTION: Other drivers that use the ACPI subsystem should call this
- * before making any other calls, to ensure the subsystem initial-
- * ized successfully.
+ * before making any other calls, to ensure the subsystem
+ * initialized successfully.
*
- ****************************************************************************/
+ ******************************************************************************/
acpi_status
-acpi_subsystem_status (void)
+acpi_subsystem_status (
+ void)
{
+
if (acpi_gbl_startup_flags & ACPI_INITIALIZED_OK) {
return (AE_OK);
}
@@ -371,13 +380,12 @@ acpi_subsystem_status (void)
}
-/******************************************************************************
+/*******************************************************************************
*
* FUNCTION: acpi_get_system_info
*
- * PARAMETERS: out_buffer - a pointer to a buffer to receive the
- * resources for the device
- * buffer_length - the number of bytes available in the buffer
+ * PARAMETERS: out_buffer - A buffer to receive the resources for the
+ * device
*
* RETURN: Status - the status of the call
*
@@ -395,8 +403,8 @@ acpi_get_system_info (
struct acpi_buffer *out_buffer)
{
struct acpi_system_info *info_ptr;
- u32 i;
acpi_status status;
+ u32 i;
ACPI_FUNCTION_TRACE ("acpi_get_system_info");
@@ -466,6 +474,7 @@ EXPORT_SYMBOL(acpi_get_system_info);
* FUNCTION: acpi_install_initialization_handler
*
* PARAMETERS: Handler - Callback procedure
+ * Function - Not (currently) used, see below
*
* RETURN: Status
*
@@ -495,7 +504,6 @@ acpi_install_initialization_handler (
#endif /* ACPI_FUTURE_USAGE */
-
/*****************************************************************************
*
* FUNCTION: acpi_purge_cached_objects
@@ -509,7 +517,8 @@ acpi_install_initialization_handler (
****************************************************************************/
acpi_status
-acpi_purge_cached_objects (void)
+acpi_purge_cached_objects (
+ void)
{
ACPI_FUNCTION_TRACE ("acpi_purge_cached_objects");
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 71fa1011715f..2cf264fd52e0 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -564,12 +564,13 @@ acpi_video_device_find_cap (struct acpi_video_device *device)
int count = 0;
union acpi_object *o;
- br = kmalloc(sizeof &br, GFP_KERNEL);
+ br = kmalloc(sizeof(*br), GFP_KERNEL);
if (!br) {
printk(KERN_ERR "can't allocate memory\n");
} else {
- memset(br, 0, sizeof &br);
- br->levels = kmalloc(obj->package.count * sizeof &br->levels, GFP_KERNEL);
+ memset(br, 0, sizeof(*br));
+ br->levels = kmalloc(obj->package.count *
+ sizeof *(br->levels), GFP_KERNEL);
if (!br->levels)
goto out;
@@ -584,8 +585,7 @@ acpi_video_device_find_cap (struct acpi_video_device *device)
}
out:
if (count < 2) {
- if (br->levels)
- kfree(br->levels);
+ kfree(br->levels);
kfree(br);
} else {
br->count = count;
@@ -595,8 +595,7 @@ out:
}
}
- if (obj)
- kfree(obj);
+ kfree(obj);
return_VOID;
}
@@ -1585,7 +1584,7 @@ acpi_video_switch_output(
ACPI_FUNCTION_TRACE("acpi_video_switch_output");
list_for_each_safe(node, next, &video->video_device_list) {
- struct acpi_video_device * dev = container_of(node, struct acpi_video_device, entry);
+ dev = container_of(node, struct acpi_video_device, entry);
status = acpi_video_device_get_state(dev, &state);
if (state & 0x2){
dev_next = container_of(node->next, struct acpi_video_device, entry);
diff --git a/drivers/base/base.h b/drivers/base/base.h
index 645f62692920..783752b68a9a 100644
--- a/drivers/base/base.h
+++ b/drivers/base/base.h
@@ -5,6 +5,7 @@ extern int bus_add_driver(struct device_driver *);
extern void bus_remove_driver(struct device_driver *);
extern void driver_detach(struct device_driver * drv);
+extern int driver_probe_device(struct device_driver *, struct device *);
static inline struct class_device *to_class_dev(struct kobject *obj)
{
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index c3fac7fd555e..96fe2f956754 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -133,6 +133,58 @@ static struct kobj_type ktype_bus = {
decl_subsys(bus, &ktype_bus, NULL);
+/* Manually detach a device from it's associated driver. */
+static int driver_helper(struct device *dev, void *data)
+{
+ const char *name = data;
+
+ if (strcmp(name, dev->bus_id) == 0)
+ return 1;
+ return 0;
+}
+
+static ssize_t driver_unbind(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ struct bus_type *bus = get_bus(drv->bus);
+ struct device *dev;
+ int err = -ENODEV;
+
+ dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+ if ((dev) &&
+ (dev->driver == drv)) {
+ device_release_driver(dev);
+ err = count;
+ }
+ return err;
+}
+static DRIVER_ATTR(unbind, S_IWUSR, NULL, driver_unbind);
+
+/*
+ * Manually attach a device to a driver.
+ * Note: the driver must want to bind to the device,
+ * it is not possible to override the driver's id table.
+ */
+static ssize_t driver_bind(struct device_driver *drv,
+ const char *buf, size_t count)
+{
+ struct bus_type *bus = get_bus(drv->bus);
+ struct device *dev;
+ int err = -ENODEV;
+
+ dev = bus_find_device(bus, NULL, (void *)buf, driver_helper);
+ if ((dev) &&
+ (dev->driver == NULL)) {
+ down(&dev->sem);
+ err = driver_probe_device(drv, dev);
+ up(&dev->sem);
+ put_device(dev);
+ }
+ return err;
+}
+static DRIVER_ATTR(bind, S_IWUSR, NULL, driver_bind);
+
+
static struct device * next_device(struct klist_iter * i)
{
struct klist_node * n = klist_next(i);
@@ -177,6 +229,39 @@ int bus_for_each_dev(struct bus_type * bus, struct device * start,
return error;
}
+/**
+ * bus_find_device - device iterator for locating a particular device.
+ * @bus: bus type
+ * @start: Device to begin with
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * This is similar to the bus_for_each_dev() function above, but it
+ * returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does. If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ */
+struct device * bus_find_device(struct bus_type *bus,
+ struct device *start, void *data,
+ int (*match)(struct device *, void *))
+{
+ struct klist_iter i;
+ struct device *dev;
+
+ if (!bus)
+ return NULL;
+
+ klist_iter_init_node(&bus->klist_devices, &i,
+ (start ? &start->knode_bus : NULL));
+ while ((dev = next_device(&i)))
+ if (match(dev, data) && get_device(dev))
+ break;
+ klist_iter_exit(&i);
+ return dev;
+}
static struct device_driver * next_driver(struct klist_iter * i)
@@ -363,6 +448,8 @@ int bus_add_driver(struct device_driver * drv)
module_add_driver(drv->owner, drv);
driver_add_attrs(bus, drv);
+ driver_create_file(drv, &driver_attr_unbind);
+ driver_create_file(drv, &driver_attr_bind);
}
return error;
}
@@ -380,6 +467,8 @@ int bus_add_driver(struct device_driver * drv)
void bus_remove_driver(struct device_driver * drv)
{
if (drv->bus) {
+ driver_remove_file(drv, &driver_attr_bind);
+ driver_remove_file(drv, &driver_attr_unbind);
driver_remove_attrs(drv->bus, drv);
klist_remove(&drv->knode_bus);
pr_debug("bus %s: remove driver %s\n", drv->bus->name, drv->name);
@@ -394,31 +483,22 @@ void bus_remove_driver(struct device_driver * drv)
/* Helper for bus_rescan_devices's iter */
static int bus_rescan_devices_helper(struct device *dev, void *data)
{
- int *count = data;
-
- if (!dev->driver && (device_attach(dev) > 0))
- (*count)++;
-
+ if (!dev->driver)
+ device_attach(dev);
return 0;
}
-
/**
- * bus_rescan_devices - rescan devices on the bus for possible drivers
- * @bus: the bus to scan.
+ * bus_rescan_devices - rescan devices on the bus for possible drivers
+ * @bus: the bus to scan.
*
- * This function will look for devices on the bus with no driver
- * attached and rescan it against existing drivers to see if it
- * matches any. Calls device_attach(). Returns the number of devices
- * that were sucessfully bound to a driver.
+ * This function will look for devices on the bus with no driver
+ * attached and rescan it against existing drivers to see if it matches
+ * any by calling device_attach() for the unbound devices.
*/
-int bus_rescan_devices(struct bus_type * bus)
+void bus_rescan_devices(struct bus_type * bus)
{
- int count = 0;
-
- bus_for_each_dev(bus, NULL, &count, bus_rescan_devices_helper);
-
- return count;
+ bus_for_each_dev(bus, NULL, NULL, bus_rescan_devices_helper);
}
@@ -557,6 +637,7 @@ int __init buses_init(void)
EXPORT_SYMBOL_GPL(bus_for_each_dev);
+EXPORT_SYMBOL_GPL(bus_find_device);
EXPORT_SYMBOL_GPL(bus_for_each_drv);
EXPORT_SYMBOL_GPL(bus_add_device);
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 86d79755fbfb..efe03a024a5b 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -333,7 +333,7 @@ void device_del(struct device * dev)
struct device * parent = dev->parent;
if (parent)
- klist_remove(&dev->knode_parent);
+ klist_del(&dev->knode_parent);
/* Notify the platform of the removal, in case they
* need to do anything...
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 6ef3069b5710..b79badd0f158 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -16,6 +16,11 @@ struct sysdev_class cpu_sysdev_class = {
EXPORT_SYMBOL(cpu_sysdev_class);
#ifdef CONFIG_HOTPLUG_CPU
+int __attribute__((weak)) smp_prepare_cpu (int cpu)
+{
+ return 0;
+}
+
static ssize_t show_online(struct sys_device *dev, char *buf)
{
struct cpu *cpu = container_of(dev, struct cpu, sysdev);
@@ -36,7 +41,11 @@ static ssize_t store_online(struct sys_device *dev, const char *buf,
kobject_hotplug(&dev->kobj, KOBJ_OFFLINE);
break;
case '1':
- ret = cpu_up(cpu->sysdev.id);
+ ret = smp_prepare_cpu(cpu->sysdev.id);
+ if (!ret)
+ ret = cpu_up(cpu->sysdev.id);
+ if (!ret)
+ kobject_hotplug(&dev->kobj, KOBJ_ONLINE);
break;
default:
ret = -EINVAL;
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index 6db3a789c54f..16323f9cbff0 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -65,7 +65,7 @@ void device_bind_driver(struct device * dev)
*
* This function must be called with @dev->sem held.
*/
-static int driver_probe_device(struct device_driver * drv, struct device * dev)
+int driver_probe_device(struct device_driver * drv, struct device * dev)
{
int ret = 0;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 1b645886e9eb..291c5954a3af 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -56,6 +56,41 @@ EXPORT_SYMBOL_GPL(driver_for_each_device);
/**
+ * driver_find_device - device iterator for locating a particular device.
+ * @driver: The device's driver
+ * @start: Device to begin with
+ * @data: Data to pass to match function
+ * @match: Callback function to check device
+ *
+ * This is similar to the driver_for_each_device() function above, but
+ * it returns a reference to a device that is 'found' for later use, as
+ * determined by the @match callback.
+ *
+ * The callback should return 0 if the device doesn't match and non-zero
+ * if it does. If the callback returns non-zero, this function will
+ * return to the caller and not iterate over any more devices.
+ */
+struct device * driver_find_device(struct device_driver *drv,
+ struct device * start, void * data,
+ int (*match)(struct device *, void *))
+{
+ struct klist_iter i;
+ struct device *dev;
+
+ if (!drv)
+ return NULL;
+
+ klist_iter_init_node(&drv->klist_devices, &i,
+ (start ? &start->knode_driver : NULL));
+ while ((dev = next_device(&i)))
+ if (match(dev, data) && get_device(dev))
+ break;
+ klist_iter_exit(&i);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(driver_find_device);
+
+/**
* driver_create_file - create sysfs file for driver.
* @drv: driver.
* @attr: driver attribute descriptor.
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 97fe13f7f07c..652281402c92 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -74,6 +74,8 @@ static ssize_t
firmware_timeout_store(struct class *class, const char *buf, size_t count)
{
loading_timeout = simple_strtol(buf, NULL, 10);
+ if (loading_timeout < 0)
+ loading_timeout = 0;
return count;
}
@@ -138,6 +140,10 @@ firmware_loading_store(struct class_device *class_dev,
switch (loading) {
case 1:
down(&fw_lock);
+ if (!fw_priv->fw) {
+ up(&fw_lock);
+ break;
+ }
vfree(fw_priv->fw->data);
fw_priv->fw->data = NULL;
fw_priv->fw->size = 0;
@@ -178,7 +184,7 @@ firmware_data_read(struct kobject *kobj,
down(&fw_lock);
fw = fw_priv->fw;
- if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
ret_count = -ENODEV;
goto out;
}
@@ -238,9 +244,10 @@ firmware_data_write(struct kobject *kobj,
if (!capable(CAP_SYS_RAWIO))
return -EPERM;
+
down(&fw_lock);
fw = fw_priv->fw;
- if (test_bit(FW_STATUS_DONE, &fw_priv->status)) {
+ if (!fw || test_bit(FW_STATUS_DONE, &fw_priv->status)) {
retval = -ENODEV;
goto out;
}
@@ -418,7 +425,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
fw_priv = class_get_devdata(class_dev);
- if (loading_timeout) {
+ if (loading_timeout > 0) {
fw_priv->timeout.expires = jiffies + loading_timeout * HZ;
add_timer(&fw_priv->timeout);
}
diff --git a/drivers/base/sys.c b/drivers/base/sys.c
index f37a13de804a..214b96435409 100644
--- a/drivers/base/sys.c
+++ b/drivers/base/sys.c
@@ -22,7 +22,6 @@
#include <linux/string.h>
#include <linux/pm.h>
-
extern struct subsystem devices_subsys;
#define to_sysdev(k) container_of(k, struct sys_device, kobj)
diff --git a/drivers/block/as-iosched.c b/drivers/block/as-iosched.c
index 3410b4d294b9..91aeb678135d 100644
--- a/drivers/block/as-iosched.c
+++ b/drivers/block/as-iosched.c
@@ -1806,7 +1806,8 @@ static void as_put_request(request_queue_t *q, struct request *rq)
rq->elevator_private = NULL;
}
-static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int as_set_request(request_queue_t *q, struct request *rq,
+ struct bio *bio, int gfp_mask)
{
struct as_data *ad = q->elevator->elevator_data;
struct as_rq *arq = mempool_alloc(ad->arq_pool, gfp_mask);
@@ -1827,7 +1828,7 @@ static int as_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
return 1;
}
-static int as_may_queue(request_queue_t *q, int rw)
+static int as_may_queue(request_queue_t *q, int rw, struct bio *bio)
{
int ret = ELV_MQUEUE_MAY;
struct as_data *ad = q->elevator->elevator_data;
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index abde27027c06..3e9fb6e4a52a 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -1,6 +1,6 @@
/*
* Disk Array driver for HP SA 5xxx and 6xxx Controllers
- * Copyright 2000, 2002 Hewlett-Packard Development Company, L.P.
+ * Copyright 2000, 2005 Hewlett-Packard Development Company, L.P.
*
* 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
@@ -54,7 +54,7 @@
MODULE_AUTHOR("Hewlett-Packard Company");
MODULE_DESCRIPTION("Driver for HP Controller SA5xxx SA6xxx version 2.6.6");
MODULE_SUPPORTED_DEVICE("HP SA5i SA5i+ SA532 SA5300 SA5312 SA641 SA642 SA6400"
- " SA6i P600 P800 E400");
+ " SA6i P600 P800 E400 E300");
MODULE_LICENSE("GPL");
#include "cciss_cmd.h"
@@ -85,8 +85,10 @@ static const struct pci_device_id cciss_pci_device_id[] = {
0x103C, 0x3225, 0, 0, 0},
{ PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
0x103c, 0x3223, 0, 0, 0},
- { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSB,
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
0x103c, 0x3231, 0, 0, 0},
+ { PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSC,
+ 0x103c, 0x3233, 0, 0, 0},
{0,}
};
MODULE_DEVICE_TABLE(pci, cciss_pci_device_id);
@@ -110,6 +112,7 @@ static struct board_type products[] = {
{ 0x3225103C, "Smart Array P600", &SA5_access},
{ 0x3223103C, "Smart Array P800", &SA5_access},
{ 0x3231103C, "Smart Array E400", &SA5_access},
+ { 0x3233103C, "Smart Array E300", &SA5_access},
};
/* How long to wait (in millesconds) for board to go into simple mode */
@@ -635,6 +638,7 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
cciss_pci_info_struct pciinfo;
if (!arg) return -EINVAL;
+ pciinfo.domain = pci_domain_nr(host->pdev->bus);
pciinfo.bus = host->pdev->bus->number;
pciinfo.dev_fn = host->pdev->devfn;
pciinfo.board_id = host->board_id;
@@ -782,18 +786,10 @@ static int cciss_ioctl(struct inode *inode, struct file *filep,
case CCISS_GETLUNINFO: {
LogvolInfo_struct luninfo;
- int i;
luninfo.LunID = drv->LunID;
luninfo.num_opens = drv->usage_count;
luninfo.num_parts = 0;
- /* count partitions 1 to 15 with sizes > 0 */
- for (i = 0; i < MAX_PART - 1; i++) {
- if (!disk->part[i])
- continue;
- if (disk->part[i]->nr_sects != 0)
- luninfo.num_parts++;
- }
if (copy_to_user(argp, &luninfo,
sizeof(LogvolInfo_struct)))
return -EFAULT;
diff --git a/drivers/block/cfq-iosched.c b/drivers/block/cfq-iosched.c
index 3ac47dde64da..de5746e38af9 100644
--- a/drivers/block/cfq-iosched.c
+++ b/drivers/block/cfq-iosched.c
@@ -21,22 +21,34 @@
#include <linux/hash.h>
#include <linux/rbtree.h>
#include <linux/mempool.h>
-
-static unsigned long max_elapsed_crq;
-static unsigned long max_elapsed_dispatch;
+#include <linux/ioprio.h>
+#include <linux/writeback.h>
/*
* tunables
*/
static int cfq_quantum = 4; /* max queue in one round of service */
static int cfq_queued = 8; /* minimum rq allocate limit per-queue*/
-static int cfq_service = HZ; /* period over which service is avg */
-static int cfq_fifo_expire_r = HZ / 2; /* fifo timeout for sync requests */
-static int cfq_fifo_expire_w = 5 * HZ; /* fifo timeout for async requests */
-static int cfq_fifo_rate = HZ / 8; /* fifo expiry rate */
+static int cfq_fifo_expire[2] = { HZ / 4, HZ / 8 };
static int cfq_back_max = 16 * 1024; /* maximum backwards seek, in KiB */
static int cfq_back_penalty = 2; /* penalty of a backwards seek */
+static int cfq_slice_sync = HZ / 10;
+static int cfq_slice_async = HZ / 25;
+static int cfq_slice_async_rq = 2;
+static int cfq_slice_idle = HZ / 100;
+
+#define CFQ_IDLE_GRACE (HZ / 10)
+#define CFQ_SLICE_SCALE (5)
+
+#define CFQ_KEY_ASYNC (0)
+#define CFQ_KEY_ANY (0xffff)
+
+/*
+ * disable queueing at the driver/hardware level
+ */
+static int cfq_max_depth = 1;
+
/*
* for the hash of cfqq inside the cfqd
*/
@@ -55,6 +67,7 @@ static int cfq_back_penalty = 2; /* penalty of a backwards seek */
#define list_entry_hash(ptr) hlist_entry((ptr), struct cfq_rq, hash)
#define list_entry_cfqq(ptr) list_entry((ptr), struct cfq_queue, cfq_list)
+#define list_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
#define RQ_DATA(rq) (rq)->elevator_private
@@ -75,78 +88,110 @@ static int cfq_back_penalty = 2; /* penalty of a backwards seek */
#define rb_entry_crq(node) rb_entry((node), struct cfq_rq, rb_node)
#define rq_rb_key(rq) (rq)->sector
-/*
- * threshold for switching off non-tag accounting
- */
-#define CFQ_MAX_TAG (4)
-
-/*
- * sort key types and names
- */
-enum {
- CFQ_KEY_PGID,
- CFQ_KEY_TGID,
- CFQ_KEY_UID,
- CFQ_KEY_GID,
- CFQ_KEY_LAST,
-};
-
-static char *cfq_key_types[] = { "pgid", "tgid", "uid", "gid", NULL };
-
static kmem_cache_t *crq_pool;
static kmem_cache_t *cfq_pool;
static kmem_cache_t *cfq_ioc_pool;
+#define CFQ_PRIO_LISTS IOPRIO_BE_NR
+#define cfq_class_idle(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_IDLE)
+#define cfq_class_be(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_BE)
+#define cfq_class_rt(cfqq) ((cfqq)->ioprio_class == IOPRIO_CLASS_RT)
+
+#define ASYNC (0)
+#define SYNC (1)
+
+#define cfq_cfqq_dispatched(cfqq) \
+ ((cfqq)->on_dispatch[ASYNC] + (cfqq)->on_dispatch[SYNC])
+
+#define cfq_cfqq_class_sync(cfqq) ((cfqq)->key != CFQ_KEY_ASYNC)
+
+#define cfq_cfqq_sync(cfqq) \
+ (cfq_cfqq_class_sync(cfqq) || (cfqq)->on_dispatch[SYNC])
+
+/*
+ * Per block device queue structure
+ */
struct cfq_data {
- struct list_head rr_list;
+ atomic_t ref;
+ request_queue_t *queue;
+
+ /*
+ * rr list of queues with requests and the count of them
+ */
+ struct list_head rr_list[CFQ_PRIO_LISTS];
+ struct list_head busy_rr;
+ struct list_head cur_rr;
+ struct list_head idle_rr;
+ unsigned int busy_queues;
+
+ /*
+ * non-ordered list of empty cfqq's
+ */
struct list_head empty_list;
+ /*
+ * cfqq lookup hash
+ */
struct hlist_head *cfq_hash;
- struct hlist_head *crq_hash;
- /* queues on rr_list (ie they have pending requests */
- unsigned int busy_queues;
+ /*
+ * global crq hash for all queues
+ */
+ struct hlist_head *crq_hash;
unsigned int max_queued;
- atomic_t ref;
+ mempool_t *crq_pool;
- int key_type;
+ int rq_in_driver;
- mempool_t *crq_pool;
+ /*
+ * schedule slice state info
+ */
+ /*
+ * idle window management
+ */
+ struct timer_list idle_slice_timer;
+ struct work_struct unplug_work;
- request_queue_t *queue;
+ struct cfq_queue *active_queue;
+ struct cfq_io_context *active_cic;
+ int cur_prio, cur_end_prio;
+ unsigned int dispatch_slice;
+
+ struct timer_list idle_class_timer;
sector_t last_sector;
+ unsigned long last_end_request;
- int rq_in_driver;
+ unsigned int rq_starved;
/*
* tunables, see top of file
*/
unsigned int cfq_quantum;
unsigned int cfq_queued;
- unsigned int cfq_fifo_expire_r;
- unsigned int cfq_fifo_expire_w;
- unsigned int cfq_fifo_batch_expire;
+ unsigned int cfq_fifo_expire[2];
unsigned int cfq_back_penalty;
unsigned int cfq_back_max;
- unsigned int find_best_crq;
-
- unsigned int cfq_tagged;
+ unsigned int cfq_slice[2];
+ unsigned int cfq_slice_async_rq;
+ unsigned int cfq_slice_idle;
+ unsigned int cfq_max_depth;
};
+/*
+ * Per process-grouping structure
+ */
struct cfq_queue {
/* reference count */
atomic_t ref;
/* parent cfq_data */
struct cfq_data *cfqd;
- /* hash of mergeable requests */
+ /* cfqq lookup hash */
struct hlist_node cfq_hash;
/* hash key */
- unsigned long key;
- /* whether queue is on rr (or empty) list */
- int on_rr;
+ unsigned int key;
/* on either rr or empty list of cfqd */
struct list_head cfq_list;
/* sorted list of pending requests */
@@ -158,21 +203,22 @@ struct cfq_queue {
/* currently allocated requests */
int allocated[2];
/* fifo list of requests in sort_list */
- struct list_head fifo[2];
- /* last time fifo expired */
- unsigned long last_fifo_expire;
+ struct list_head fifo;
- int key_type;
+ unsigned long slice_start;
+ unsigned long slice_end;
+ unsigned long slice_left;
+ unsigned long service_last;
- unsigned long service_start;
- unsigned long service_used;
+ /* number of requests that are on the dispatch list */
+ int on_dispatch[2];
- unsigned int max_rate;
+ /* io prio of this group */
+ unsigned short ioprio, org_ioprio;
+ unsigned short ioprio_class, org_ioprio_class;
- /* number of requests that have been handed to the driver */
- int in_flight;
- /* number of currently allocated requests */
- int alloc_limit[2];
+ /* various state flags, see below */
+ unsigned int flags;
};
struct cfq_rq {
@@ -184,42 +230,78 @@ struct cfq_rq {
struct cfq_queue *cfq_queue;
struct cfq_io_context *io_context;
- unsigned long service_start;
- unsigned long queue_start;
+ unsigned int crq_flags;
+};
+
+enum cfqq_state_flags {
+ CFQ_CFQQ_FLAG_on_rr = 0,
+ CFQ_CFQQ_FLAG_wait_request,
+ CFQ_CFQQ_FLAG_must_alloc,
+ CFQ_CFQQ_FLAG_must_alloc_slice,
+ CFQ_CFQQ_FLAG_must_dispatch,
+ CFQ_CFQQ_FLAG_fifo_expire,
+ CFQ_CFQQ_FLAG_idle_window,
+ CFQ_CFQQ_FLAG_prio_changed,
+ CFQ_CFQQ_FLAG_expired,
+};
- unsigned int in_flight : 1;
- unsigned int accounted : 1;
- unsigned int is_sync : 1;
- unsigned int is_write : 1;
+#define CFQ_CFQQ_FNS(name) \
+static inline void cfq_mark_cfqq_##name(struct cfq_queue *cfqq) \
+{ \
+ cfqq->flags |= (1 << CFQ_CFQQ_FLAG_##name); \
+} \
+static inline void cfq_clear_cfqq_##name(struct cfq_queue *cfqq) \
+{ \
+ cfqq->flags &= ~(1 << CFQ_CFQQ_FLAG_##name); \
+} \
+static inline int cfq_cfqq_##name(const struct cfq_queue *cfqq) \
+{ \
+ return (cfqq->flags & (1 << CFQ_CFQQ_FLAG_##name)) != 0; \
+}
+
+CFQ_CFQQ_FNS(on_rr);
+CFQ_CFQQ_FNS(wait_request);
+CFQ_CFQQ_FNS(must_alloc);
+CFQ_CFQQ_FNS(must_alloc_slice);
+CFQ_CFQQ_FNS(must_dispatch);
+CFQ_CFQQ_FNS(fifo_expire);
+CFQ_CFQQ_FNS(idle_window);
+CFQ_CFQQ_FNS(prio_changed);
+CFQ_CFQQ_FNS(expired);
+#undef CFQ_CFQQ_FNS
+
+enum cfq_rq_state_flags {
+ CFQ_CRQ_FLAG_in_flight = 0,
+ CFQ_CRQ_FLAG_in_driver,
+ CFQ_CRQ_FLAG_is_sync,
+ CFQ_CRQ_FLAG_requeued,
};
-static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned long);
+#define CFQ_CRQ_FNS(name) \
+static inline void cfq_mark_crq_##name(struct cfq_rq *crq) \
+{ \
+ crq->crq_flags |= (1 << CFQ_CRQ_FLAG_##name); \
+} \
+static inline void cfq_clear_crq_##name(struct cfq_rq *crq) \
+{ \
+ crq->crq_flags &= ~(1 << CFQ_CRQ_FLAG_##name); \
+} \
+static inline int cfq_crq_##name(const struct cfq_rq *crq) \
+{ \
+ return (crq->crq_flags & (1 << CFQ_CRQ_FLAG_##name)) != 0; \
+}
+
+CFQ_CRQ_FNS(in_flight);
+CFQ_CRQ_FNS(in_driver);
+CFQ_CRQ_FNS(is_sync);
+CFQ_CRQ_FNS(requeued);
+#undef CFQ_CRQ_FNS
+
+static struct cfq_queue *cfq_find_cfq_hash(struct cfq_data *, unsigned int, unsigned short);
static void cfq_dispatch_sort(request_queue_t *, struct cfq_rq *);
-static void cfq_update_next_crq(struct cfq_rq *);
static void cfq_put_cfqd(struct cfq_data *cfqd);
-/*
- * what the fairness is based on (ie how processes are grouped and
- * differentiated)
- */
-static inline unsigned long
-cfq_hash_key(struct cfq_data *cfqd, struct task_struct *tsk)
-{
- /*
- * optimize this so that ->key_type is the offset into the struct
- */
- switch (cfqd->key_type) {
- case CFQ_KEY_PGID:
- return process_group(tsk);
- default:
- case CFQ_KEY_TGID:
- return tsk->tgid;
- case CFQ_KEY_UID:
- return tsk->uid;
- case CFQ_KEY_GID:
- return tsk->gid;
- }
-}
+#define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE)
/*
* lots of deadline iosched dupes, can be abstracted later...
@@ -235,16 +317,12 @@ static void cfq_remove_merge_hints(request_queue_t *q, struct cfq_rq *crq)
if (q->last_merge == crq->request)
q->last_merge = NULL;
-
- cfq_update_next_crq(crq);
}
static inline void cfq_add_crq_hash(struct cfq_data *cfqd, struct cfq_rq *crq)
{
const int hash_idx = CFQ_MHASH_FN(rq_hash_key(crq->request));
- BUG_ON(!hlist_unhashed(&crq->hash));
-
hlist_add_head(&crq->hash, &cfqd->crq_hash[hash_idx]);
}
@@ -257,8 +335,6 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
struct cfq_rq *crq = list_entry_hash(entry);
struct request *__rq = crq->request;
- BUG_ON(hlist_unhashed(&crq->hash));
-
if (!rq_mergeable(__rq)) {
cfq_del_crq_hash(crq);
continue;
@@ -271,6 +347,28 @@ static struct request *cfq_find_rq_hash(struct cfq_data *cfqd, sector_t offset)
return NULL;
}
+static inline int cfq_pending_requests(struct cfq_data *cfqd)
+{
+ return !list_empty(&cfqd->queue->queue_head) || cfqd->busy_queues;
+}
+
+/*
+ * scheduler run of queue, if there are requests pending and no one in the
+ * driver that will restart queueing
+ */
+static inline void cfq_schedule_dispatch(struct cfq_data *cfqd)
+{
+ if (!cfqd->rq_in_driver && cfq_pending_requests(cfqd))
+ kblockd_schedule_work(&cfqd->unplug_work);
+}
+
+static int cfq_queue_empty(request_queue_t *q)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+
+ return !cfq_pending_requests(cfqd);
+}
+
/*
* Lifted from AS - choose which of crq1 and crq2 that is best served now.
* We choose the request that is closest to the head right now. Distance
@@ -287,36 +385,16 @@ cfq_choose_req(struct cfq_data *cfqd, struct cfq_rq *crq1, struct cfq_rq *crq2)
return crq2;
if (crq2 == NULL)
return crq1;
+ if (cfq_crq_requeued(crq1))
+ return crq1;
+ if (cfq_crq_requeued(crq2))
+ return crq2;
s1 = crq1->request->sector;
s2 = crq2->request->sector;
last = cfqd->last_sector;
-#if 0
- if (!list_empty(&cfqd->queue->queue_head)) {
- struct list_head *entry = &cfqd->queue->queue_head;
- unsigned long distance = ~0UL;
- struct request *rq;
-
- while ((entry = entry->prev) != &cfqd->queue->queue_head) {
- rq = list_entry_rq(entry);
-
- if (blk_barrier_rq(rq))
- break;
-
- if (distance < abs(s1 - rq->sector + rq->nr_sectors)) {
- distance = abs(s1 - rq->sector +rq->nr_sectors);
- last = rq->sector + rq->nr_sectors;
- }
- if (distance < abs(s2 - rq->sector + rq->nr_sectors)) {
- distance = abs(s2 - rq->sector +rq->nr_sectors);
- last = rq->sector + rq->nr_sectors;
- }
- }
- }
-#endif
-
/*
* by definition, 1KiB is 2 sectors
*/
@@ -377,11 +455,14 @@ cfq_find_next_crq(struct cfq_data *cfqd, struct cfq_queue *cfqq,
struct cfq_rq *crq_next = NULL, *crq_prev = NULL;
struct rb_node *rbnext, *rbprev;
- if (!ON_RB(&last->rb_node))
- return NULL;
-
- if ((rbnext = rb_next(&last->rb_node)) == NULL)
+ rbnext = NULL;
+ if (ON_RB(&last->rb_node))
+ rbnext = rb_next(&last->rb_node);
+ if (!rbnext) {
rbnext = rb_first(&cfqq->sort_list);
+ if (rbnext == &last->rb_node)
+ rbnext = NULL;
+ }
rbprev = rb_prev(&last->rb_node);
@@ -401,67 +482,53 @@ static void cfq_update_next_crq(struct cfq_rq *crq)
cfqq->next_crq = cfq_find_next_crq(cfqq->cfqd, cfqq, crq);
}
-static int cfq_check_sort_rr_list(struct cfq_queue *cfqq)
+static void cfq_resort_rr_list(struct cfq_queue *cfqq, int preempted)
{
- struct list_head *head = &cfqq->cfqd->rr_list;
- struct list_head *next, *prev;
-
- /*
- * list might still be ordered
- */
- next = cfqq->cfq_list.next;
- if (next != head) {
- struct cfq_queue *cnext = list_entry_cfqq(next);
+ struct cfq_data *cfqd = cfqq->cfqd;
+ struct list_head *list, *entry;
- if (cfqq->service_used > cnext->service_used)
- return 1;
- }
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
- prev = cfqq->cfq_list.prev;
- if (prev != head) {
- struct cfq_queue *cprev = list_entry_cfqq(prev);
+ list_del(&cfqq->cfq_list);
- if (cfqq->service_used < cprev->service_used)
- return 1;
+ if (cfq_class_rt(cfqq))
+ list = &cfqd->cur_rr;
+ else if (cfq_class_idle(cfqq))
+ list = &cfqd->idle_rr;
+ else {
+ /*
+ * if cfqq has requests in flight, don't allow it to be
+ * found in cfq_set_active_queue before it has finished them.
+ * this is done to increase fairness between a process that
+ * has lots of io pending vs one that only generates one
+ * sporadically or synchronously
+ */
+ if (cfq_cfqq_dispatched(cfqq))
+ list = &cfqd->busy_rr;
+ else
+ list = &cfqd->rr_list[cfqq->ioprio];
}
- return 0;
-}
-
-static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
-{
- struct list_head *entry = &cfqq->cfqd->rr_list;
-
- if (!cfqq->on_rr)
- return;
- if (!new_queue && !cfq_check_sort_rr_list(cfqq))
+ /*
+ * if queue was preempted, just add to front to be fair. busy_rr
+ * isn't sorted.
+ */
+ if (preempted || list == &cfqd->busy_rr) {
+ list_add(&cfqq->cfq_list, list);
return;
-
- list_del(&cfqq->cfq_list);
+ }
/*
- * sort by our mean service_used, sub-sort by in-flight requests
+ * sort by when queue was last serviced
*/
- while ((entry = entry->prev) != &cfqq->cfqd->rr_list) {
+ entry = list;
+ while ((entry = entry->prev) != list) {
struct cfq_queue *__cfqq = list_entry_cfqq(entry);
- if (cfqq->service_used > __cfqq->service_used)
+ if (!__cfqq->service_last)
+ break;
+ if (time_before(__cfqq->service_last, cfqq->service_last))
break;
- else if (cfqq->service_used == __cfqq->service_used) {
- struct list_head *prv;
-
- while ((prv = entry->prev) != &cfqq->cfqd->rr_list) {
- __cfqq = list_entry_cfqq(prv);
-
- WARN_ON(__cfqq->service_used > cfqq->service_used);
- if (cfqq->service_used != __cfqq->service_used)
- break;
- if (cfqq->in_flight > __cfqq->in_flight)
- break;
-
- entry = prv;
- }
- }
}
list_add(&cfqq->cfq_list, entry);
@@ -469,28 +536,24 @@ static void cfq_sort_rr_list(struct cfq_queue *cfqq, int new_queue)
/*
* add to busy list of queues for service, trying to be fair in ordering
- * the pending list according to requests serviced
+ * the pending list according to last request service
*/
static inline void
-cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+cfq_add_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq, int requeue)
{
- /*
- * it's currently on the empty list
- */
- cfqq->on_rr = 1;
+ BUG_ON(cfq_cfqq_on_rr(cfqq));
+ cfq_mark_cfqq_on_rr(cfqq);
cfqd->busy_queues++;
- if (time_after(jiffies, cfqq->service_start + cfq_service))
- cfqq->service_used >>= 3;
-
- cfq_sort_rr_list(cfqq, 1);
+ cfq_resort_rr_list(cfqq, requeue);
}
static inline void
cfq_del_cfqq_rr(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
+ BUG_ON(!cfq_cfqq_on_rr(cfqq));
+ cfq_clear_cfqq_on_rr(cfqq);
list_move(&cfqq->cfq_list, &cfqd->empty_list);
- cfqq->on_rr = 0;
BUG_ON(!cfqd->busy_queues);
cfqd->busy_queues--;
@@ -505,16 +568,17 @@ static inline void cfq_del_crq_rb(struct cfq_rq *crq)
if (ON_RB(&crq->rb_node)) {
struct cfq_data *cfqd = cfqq->cfqd;
+ const int sync = cfq_crq_is_sync(crq);
- BUG_ON(!cfqq->queued[crq->is_sync]);
+ BUG_ON(!cfqq->queued[sync]);
+ cfqq->queued[sync]--;
cfq_update_next_crq(crq);
- cfqq->queued[crq->is_sync]--;
rb_erase(&crq->rb_node, &cfqq->sort_list);
RB_CLEAR_COLOR(&crq->rb_node);
- if (RB_EMPTY(&cfqq->sort_list) && cfqq->on_rr)
+ if (cfq_cfqq_on_rr(cfqq) && RB_EMPTY(&cfqq->sort_list))
cfq_del_cfqq_rr(cfqd, cfqq);
}
}
@@ -550,7 +614,7 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
struct cfq_rq *__alias;
crq->rb_key = rq_rb_key(rq);
- cfqq->queued[crq->is_sync]++;
+ cfqq->queued[cfq_crq_is_sync(crq)]++;
/*
* looks a little odd, but the first insert might return an alias.
@@ -561,8 +625,8 @@ static void cfq_add_crq_rb(struct cfq_rq *crq)
rb_insert_color(&crq->rb_node, &cfqq->sort_list);
- if (!cfqq->on_rr)
- cfq_add_cfqq_rr(cfqd, cfqq);
+ if (!cfq_cfqq_on_rr(cfqq))
+ cfq_add_cfqq_rr(cfqd, cfqq, cfq_crq_requeued(crq));
/*
* check if this request is a better next-serve candidate
@@ -575,17 +639,16 @@ cfq_reposition_crq_rb(struct cfq_queue *cfqq, struct cfq_rq *crq)
{
if (ON_RB(&crq->rb_node)) {
rb_erase(&crq->rb_node, &cfqq->sort_list);
- cfqq->queued[crq->is_sync]--;
+ cfqq->queued[cfq_crq_is_sync(crq)]--;
}
cfq_add_crq_rb(crq);
}
-static struct request *
-cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector)
+
{
- const unsigned long key = cfq_hash_key(cfqd, current);
- struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, key);
+ struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY);
struct rb_node *n;
if (!cfqq)
@@ -609,20 +672,25 @@ out:
static void cfq_deactivate_request(request_queue_t *q, struct request *rq)
{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
struct cfq_rq *crq = RQ_DATA(rq);
if (crq) {
struct cfq_queue *cfqq = crq->cfq_queue;
- if (cfqq->cfqd->cfq_tagged) {
- cfqq->service_used--;
- cfq_sort_rr_list(cfqq, 0);
+ if (cfq_crq_in_driver(crq)) {
+ cfq_clear_crq_in_driver(crq);
+ WARN_ON(!cfqd->rq_in_driver);
+ cfqd->rq_in_driver--;
}
+ if (cfq_crq_in_flight(crq)) {
+ const int sync = cfq_crq_is_sync(crq);
- if (crq->accounted) {
- crq->accounted = 0;
- cfqq->cfqd->rq_in_driver--;
+ cfq_clear_crq_in_flight(crq);
+ WARN_ON(!cfqq->on_dispatch[sync]);
+ cfqq->on_dispatch[sync]--;
}
+ cfq_mark_crq_requeued(crq);
}
}
@@ -640,11 +708,10 @@ static void cfq_remove_request(request_queue_t *q, struct request *rq)
struct cfq_rq *crq = RQ_DATA(rq);
if (crq) {
- cfq_remove_merge_hints(q, crq);
list_del_init(&rq->queuelist);
+ cfq_del_crq_rb(crq);
+ cfq_remove_merge_hints(q, crq);
- if (crq->cfq_queue)
- cfq_del_crq_rb(crq);
}
}
@@ -662,21 +729,15 @@ cfq_merge(request_queue_t *q, struct request **req, struct bio *bio)
}
__rq = cfq_find_rq_hash(cfqd, bio->bi_sector);
- if (__rq) {
- BUG_ON(__rq->sector + __rq->nr_sectors != bio->bi_sector);
-
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_BACK_MERGE;
- goto out;
- }
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ ret = ELEVATOR_BACK_MERGE;
+ goto out;
}
__rq = cfq_find_rq_rb(cfqd, bio->bi_sector + bio_sectors(bio));
- if (__rq) {
- if (elv_rq_merge_ok(__rq, bio)) {
- ret = ELEVATOR_FRONT_MERGE;
- goto out;
- }
+ if (__rq && elv_rq_merge_ok(__rq, bio)) {
+ ret = ELEVATOR_FRONT_MERGE;
+ goto out;
}
return ELEVATOR_NO_MERGE;
@@ -709,20 +770,220 @@ static void
cfq_merged_requests(request_queue_t *q, struct request *rq,
struct request *next)
{
- struct cfq_rq *crq = RQ_DATA(rq);
- struct cfq_rq *cnext = RQ_DATA(next);
-
cfq_merged_request(q, rq);
- if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist)) {
- if (time_before(cnext->queue_start, crq->queue_start)) {
- list_move(&rq->queuelist, &next->queuelist);
- crq->queue_start = cnext->queue_start;
+ /*
+ * reposition in fifo if next is older than rq
+ */
+ if (!list_empty(&rq->queuelist) && !list_empty(&next->queuelist) &&
+ time_before(next->start_time, rq->start_time))
+ list_move(&rq->queuelist, &next->queuelist);
+
+ cfq_remove_request(q, next);
+}
+
+static inline void
+__cfq_set_active_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ if (cfqq) {
+ /*
+ * stop potential idle class queues waiting service
+ */
+ del_timer(&cfqd->idle_class_timer);
+
+ cfqq->slice_start = jiffies;
+ cfqq->slice_end = 0;
+ cfqq->slice_left = 0;
+ cfq_clear_cfqq_must_alloc_slice(cfqq);
+ cfq_clear_cfqq_fifo_expire(cfqq);
+ cfq_clear_cfqq_expired(cfqq);
+ }
+
+ cfqd->active_queue = cfqq;
+}
+
+/*
+ * 0
+ * 0,1
+ * 0,1,2
+ * 0,1,2,3
+ * 0,1,2,3,4
+ * 0,1,2,3,4,5
+ * 0,1,2,3,4,5,6
+ * 0,1,2,3,4,5,6,7
+ */
+static int cfq_get_next_prio_level(struct cfq_data *cfqd)
+{
+ int prio, wrap;
+
+ prio = -1;
+ wrap = 0;
+ do {
+ int p;
+
+ for (p = cfqd->cur_prio; p <= cfqd->cur_end_prio; p++) {
+ if (!list_empty(&cfqd->rr_list[p])) {
+ prio = p;
+ break;
+ }
+ }
+
+ if (prio != -1)
+ break;
+ cfqd->cur_prio = 0;
+ if (++cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+ cfqd->cur_end_prio = 0;
+ if (wrap)
+ break;
+ wrap = 1;
}
+ } while (1);
+
+ if (unlikely(prio == -1))
+ return -1;
+
+ BUG_ON(prio >= CFQ_PRIO_LISTS);
+
+ list_splice_init(&cfqd->rr_list[prio], &cfqd->cur_rr);
+
+ cfqd->cur_prio = prio + 1;
+ if (cfqd->cur_prio > cfqd->cur_end_prio) {
+ cfqd->cur_end_prio = cfqd->cur_prio;
+ cfqd->cur_prio = 0;
+ }
+ if (cfqd->cur_end_prio == CFQ_PRIO_LISTS) {
+ cfqd->cur_prio = 0;
+ cfqd->cur_end_prio = 0;
}
- cfq_update_next_crq(cnext);
- cfq_remove_request(q, next);
+ return prio;
+}
+
+static struct cfq_queue *cfq_set_active_queue(struct cfq_data *cfqd)
+{
+ struct cfq_queue *cfqq;
+
+ /*
+ * if current queue is expired but not done with its requests yet,
+ * wait for that to happen
+ */
+ if ((cfqq = cfqd->active_queue) != NULL) {
+ if (cfq_cfqq_expired(cfqq) && cfq_cfqq_dispatched(cfqq))
+ return NULL;
+ }
+
+ /*
+ * if current list is non-empty, grab first entry. if it is empty,
+ * get next prio level and grab first entry then if any are spliced
+ */
+ if (!list_empty(&cfqd->cur_rr) || cfq_get_next_prio_level(cfqd) != -1)
+ cfqq = list_entry_cfqq(cfqd->cur_rr.next);
+
+ /*
+ * if we have idle queues and no rt or be queues had pending
+ * requests, either allow immediate service if the grace period
+ * has passed or arm the idle grace timer
+ */
+ if (!cfqq && !list_empty(&cfqd->idle_rr)) {
+ unsigned long end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+
+ if (time_after_eq(jiffies, end))
+ cfqq = list_entry_cfqq(cfqd->idle_rr.next);
+ else
+ mod_timer(&cfqd->idle_class_timer, end);
+ }
+
+ __cfq_set_active_queue(cfqd, cfqq);
+ return cfqq;
+}
+
+/*
+ * current cfqq expired its slice (or was too idle), select new one
+ */
+static void
+__cfq_slice_expired(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ int preempted)
+{
+ unsigned long now = jiffies;
+
+ if (cfq_cfqq_wait_request(cfqq))
+ del_timer(&cfqd->idle_slice_timer);
+
+ if (!preempted && !cfq_cfqq_dispatched(cfqq))
+ cfqq->service_last = now;
+
+ cfq_clear_cfqq_must_dispatch(cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
+
+ /*
+ * store what was left of this slice, if the queue idled out
+ * or was preempted
+ */
+ if (time_after(now, cfqq->slice_end))
+ cfqq->slice_left = now - cfqq->slice_end;
+ else
+ cfqq->slice_left = 0;
+
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, preempted);
+
+ if (cfqq == cfqd->active_queue)
+ cfqd->active_queue = NULL;
+
+ if (cfqd->active_cic) {
+ put_io_context(cfqd->active_cic->ioc);
+ cfqd->active_cic = NULL;
+ }
+
+ cfqd->dispatch_slice = 0;
+}
+
+static inline void cfq_slice_expired(struct cfq_data *cfqd, int preempted)
+{
+ struct cfq_queue *cfqq = cfqd->active_queue;
+
+ if (cfqq) {
+ /*
+ * use deferred expiry, if there are requests in progress as
+ * not to disturb the slice of the next queue
+ */
+ if (cfq_cfqq_dispatched(cfqq))
+ cfq_mark_cfqq_expired(cfqq);
+ else
+ __cfq_slice_expired(cfqd, cfqq, preempted);
+ }
+}
+
+static int cfq_arm_slice_timer(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+
+{
+ WARN_ON(!RB_EMPTY(&cfqq->sort_list));
+ WARN_ON(cfqq != cfqd->active_queue);
+
+ /*
+ * idle is disabled, either manually or by past process history
+ */
+ if (!cfqd->cfq_slice_idle)
+ return 0;
+ if (!cfq_cfqq_idle_window(cfqq))
+ return 0;
+ /*
+ * task has exited, don't wait
+ */
+ if (cfqd->active_cic && !cfqd->active_cic->ioc->task)
+ return 0;
+
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ cfq_mark_cfqq_wait_request(cfqq);
+
+ if (!timer_pending(&cfqd->idle_slice_timer)) {
+ unsigned long slice_left = min(cfqq->slice_end - 1, (unsigned long) cfqd->cfq_slice_idle);
+
+ cfqd->idle_slice_timer.expires = jiffies + slice_left;
+ add_timer(&cfqd->idle_slice_timer);
+ }
+
+ return 1;
}
/*
@@ -738,31 +999,40 @@ static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
struct request *__rq;
sector_t last;
- cfq_del_crq_rb(crq);
- cfq_remove_merge_hints(q, crq);
list_del(&crq->request->queuelist);
last = cfqd->last_sector;
- while ((entry = entry->prev) != head) {
- __rq = list_entry_rq(entry);
+ list_for_each_entry_reverse(__rq, head, queuelist) {
+ struct cfq_rq *__crq = RQ_DATA(__rq);
- if (blk_barrier_rq(crq->request))
+ if (blk_barrier_rq(__rq))
break;
- if (!blk_fs_request(crq->request))
+ if (!blk_fs_request(__rq))
+ break;
+ if (cfq_crq_requeued(__crq))
break;
- if (crq->request->sector > __rq->sector)
+ if (__rq->sector <= crq->request->sector)
break;
if (__rq->sector > last && crq->request->sector < last) {
- last = crq->request->sector;
+ last = crq->request->sector + crq->request->nr_sectors;
break;
}
+ entry = &__rq->queuelist;
}
cfqd->last_sector = last;
- crq->in_flight = 1;
- cfqq->in_flight++;
- list_add(&crq->request->queuelist, entry);
+
+ cfqq->next_crq = cfq_find_next_crq(cfqd, cfqq, crq);
+
+ cfq_del_crq_rb(crq);
+ cfq_remove_merge_hints(q, crq);
+
+ cfq_mark_crq_in_flight(crq);
+ cfq_clear_crq_requeued(crq);
+
+ cfqq->on_dispatch[cfq_crq_is_sync(crq)]++;
+ list_add_tail(&crq->request->queuelist, entry);
}
/*
@@ -771,173 +1041,225 @@ static void cfq_dispatch_sort(request_queue_t *q, struct cfq_rq *crq)
static inline struct cfq_rq *cfq_check_fifo(struct cfq_queue *cfqq)
{
struct cfq_data *cfqd = cfqq->cfqd;
- const int reads = !list_empty(&cfqq->fifo[0]);
- const int writes = !list_empty(&cfqq->fifo[1]);
- unsigned long now = jiffies;
+ struct request *rq;
struct cfq_rq *crq;
- if (time_before(now, cfqq->last_fifo_expire + cfqd->cfq_fifo_batch_expire))
+ if (cfq_cfqq_fifo_expire(cfqq))
return NULL;
- crq = RQ_DATA(list_entry(cfqq->fifo[0].next, struct request, queuelist));
- if (reads && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_r)) {
- cfqq->last_fifo_expire = now;
- return crq;
- }
+ if (!list_empty(&cfqq->fifo)) {
+ int fifo = cfq_cfqq_class_sync(cfqq);
- crq = RQ_DATA(list_entry(cfqq->fifo[1].next, struct request, queuelist));
- if (writes && time_after(now, crq->queue_start + cfqd->cfq_fifo_expire_w)) {
- cfqq->last_fifo_expire = now;
- return crq;
+ crq = RQ_DATA(list_entry_fifo(cfqq->fifo.next));
+ rq = crq->request;
+ if (time_after(jiffies, rq->start_time + cfqd->cfq_fifo_expire[fifo])) {
+ cfq_mark_cfqq_fifo_expire(cfqq);
+ return crq;
+ }
}
return NULL;
}
/*
- * dispatch a single request from given queue
+ * Scale schedule slice based on io priority. Use the sync time slice only
+ * if a queue is marked sync and has sync io queued. A sync queue with async
+ * io only, should not get full sync slice length.
*/
+static inline int
+cfq_prio_to_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ const int base_slice = cfqd->cfq_slice[cfq_cfqq_sync(cfqq)];
+
+ WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+ return base_slice + (base_slice/CFQ_SLICE_SCALE * (4 - cfqq->ioprio));
+}
+
static inline void
-cfq_dispatch_request(request_queue_t *q, struct cfq_data *cfqd,
- struct cfq_queue *cfqq)
+cfq_set_prio_slice(struct cfq_data *cfqd, struct cfq_queue *cfqq)
{
- struct cfq_rq *crq;
+ cfqq->slice_end = cfq_prio_to_slice(cfqd, cfqq) + jiffies;
+}
+
+static inline int
+cfq_prio_to_maxrq(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ const int base_rq = cfqd->cfq_slice_async_rq;
+
+ WARN_ON(cfqq->ioprio >= IOPRIO_BE_NR);
+
+ return 2 * (base_rq + base_rq * (CFQ_PRIO_LISTS - 1 - cfqq->ioprio));
+}
+
+/*
+ * get next queue for service
+ */
+static struct cfq_queue *cfq_select_queue(struct cfq_data *cfqd, int force)
+{
+ unsigned long now = jiffies;
+ struct cfq_queue *cfqq;
+
+ cfqq = cfqd->active_queue;
+ if (!cfqq)
+ goto new_queue;
+
+ if (cfq_cfqq_expired(cfqq))
+ goto new_queue;
/*
- * follow expired path, else get first next available
+ * slice has expired
*/
- if ((crq = cfq_check_fifo(cfqq)) == NULL) {
- if (cfqd->find_best_crq)
- crq = cfqq->next_crq;
- else
- crq = rb_entry_crq(rb_first(&cfqq->sort_list));
- }
-
- cfqd->last_sector = crq->request->sector + crq->request->nr_sectors;
+ if (!cfq_cfqq_must_dispatch(cfqq) && time_after(now, cfqq->slice_end))
+ goto expire;
/*
- * finally, insert request into driver list
+ * if queue has requests, dispatch one. if not, check if
+ * enough slice is left to wait for one
*/
- cfq_dispatch_sort(q, crq);
+ if (!RB_EMPTY(&cfqq->sort_list))
+ goto keep_queue;
+ else if (!force && cfq_cfqq_class_sync(cfqq) &&
+ time_before(now, cfqq->slice_end)) {
+ if (cfq_arm_slice_timer(cfqd, cfqq))
+ return NULL;
+ }
+
+expire:
+ cfq_slice_expired(cfqd, 0);
+new_queue:
+ cfqq = cfq_set_active_queue(cfqd);
+keep_queue:
+ return cfqq;
}
-static int cfq_dispatch_requests(request_queue_t *q, int max_dispatch)
+static int
+__cfq_dispatch_requests(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ int max_dispatch)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
- struct list_head *entry, *tmp;
- int queued, busy_queues, first_round;
+ int dispatched = 0;
- if (list_empty(&cfqd->rr_list))
- return 0;
+ BUG_ON(RB_EMPTY(&cfqq->sort_list));
- queued = 0;
- first_round = 1;
-restart:
- busy_queues = 0;
- list_for_each_safe(entry, tmp, &cfqd->rr_list) {
- cfqq = list_entry_cfqq(entry);
+ do {
+ struct cfq_rq *crq;
- BUG_ON(RB_EMPTY(&cfqq->sort_list));
+ /*
+ * follow expired path, else get first next available
+ */
+ if ((crq = cfq_check_fifo(cfqq)) == NULL)
+ crq = cfqq->next_crq;
/*
- * first round of queueing, only select from queues that
- * don't already have io in-flight
+ * finally, insert request into driver dispatch list
*/
- if (first_round && cfqq->in_flight)
- continue;
+ cfq_dispatch_sort(cfqd->queue, crq);
- cfq_dispatch_request(q, cfqd, cfqq);
+ cfqd->dispatch_slice++;
+ dispatched++;
- if (!RB_EMPTY(&cfqq->sort_list))
- busy_queues++;
+ if (!cfqd->active_cic) {
+ atomic_inc(&crq->io_context->ioc->refcount);
+ cfqd->active_cic = crq->io_context;
+ }
- queued++;
- }
+ if (RB_EMPTY(&cfqq->sort_list))
+ break;
+
+ } while (dispatched < max_dispatch);
+
+ /*
+ * if slice end isn't set yet, set it. if at least one request was
+ * sync, use the sync time slice value
+ */
+ if (!cfqq->slice_end)
+ cfq_set_prio_slice(cfqd, cfqq);
+
+ /*
+ * expire an async queue immediately if it has used up its slice. idle
+ * queue always expire after 1 dispatch round.
+ */
+ if ((!cfq_cfqq_sync(cfqq) &&
+ cfqd->dispatch_slice >= cfq_prio_to_maxrq(cfqd, cfqq)) ||
+ cfq_class_idle(cfqq))
+ cfq_slice_expired(cfqd, 0);
+
+ return dispatched;
+}
+
+static int
+cfq_dispatch_requests(request_queue_t *q, int max_dispatch, int force)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct cfq_queue *cfqq;
+
+ if (!cfqd->busy_queues)
+ return 0;
+
+ cfqq = cfq_select_queue(cfqd, force);
+ if (cfqq) {
+ cfq_clear_cfqq_must_dispatch(cfqq);
+ cfq_clear_cfqq_wait_request(cfqq);
+ del_timer(&cfqd->idle_slice_timer);
- if ((queued < max_dispatch) && (busy_queues || first_round)) {
- first_round = 0;
- goto restart;
+ if (cfq_class_idle(cfqq))
+ max_dispatch = 1;
+
+ return __cfq_dispatch_requests(cfqd, cfqq, max_dispatch);
}
- return queued;
+ return 0;
}
static inline void cfq_account_dispatch(struct cfq_rq *crq)
{
struct cfq_queue *cfqq = crq->cfq_queue;
struct cfq_data *cfqd = cfqq->cfqd;
- unsigned long now, elapsed;
- if (!blk_fs_request(crq->request))
+ if (unlikely(!blk_fs_request(crq->request)))
return;
/*
* accounted bit is necessary since some drivers will call
* elv_next_request() many times for the same request (eg ide)
*/
- if (crq->accounted)
+ if (cfq_crq_in_driver(crq))
return;
- now = jiffies;
- if (cfqq->service_start == ~0UL)
- cfqq->service_start = now;
-
- /*
- * on drives with tagged command queueing, command turn-around time
- * doesn't necessarily reflect the time spent processing this very
- * command inside the drive. so do the accounting differently there,
- * by just sorting on the number of requests
- */
- if (cfqd->cfq_tagged) {
- if (time_after(now, cfqq->service_start + cfq_service)) {
- cfqq->service_start = now;
- cfqq->service_used /= 10;
- }
-
- cfqq->service_used++;
- cfq_sort_rr_list(cfqq, 0);
- }
-
- elapsed = now - crq->queue_start;
- if (elapsed > max_elapsed_dispatch)
- max_elapsed_dispatch = elapsed;
-
- crq->accounted = 1;
- crq->service_start = now;
-
- if (++cfqd->rq_in_driver >= CFQ_MAX_TAG && !cfqd->cfq_tagged) {
- cfqq->cfqd->cfq_tagged = 1;
- printk("cfq: depth %d reached, tagging now on\n", CFQ_MAX_TAG);
- }
+ cfq_mark_crq_in_driver(crq);
+ cfqd->rq_in_driver++;
}
static inline void
cfq_account_completion(struct cfq_queue *cfqq, struct cfq_rq *crq)
{
struct cfq_data *cfqd = cfqq->cfqd;
+ unsigned long now;
- if (!crq->accounted)
+ if (!cfq_crq_in_driver(crq))
return;
+ now = jiffies;
+
WARN_ON(!cfqd->rq_in_driver);
cfqd->rq_in_driver--;
- if (!cfqd->cfq_tagged) {
- unsigned long now = jiffies;
- unsigned long duration = now - crq->service_start;
+ if (!cfq_class_idle(cfqq))
+ cfqd->last_end_request = now;
- if (time_after(now, cfqq->service_start + cfq_service)) {
- cfqq->service_start = now;
- cfqq->service_used >>= 3;
+ if (!cfq_cfqq_dispatched(cfqq)) {
+ if (cfq_cfqq_on_rr(cfqq)) {
+ cfqq->service_last = now;
+ cfq_resort_rr_list(cfqq, 0);
+ }
+ if (cfq_cfqq_expired(cfqq)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
}
-
- cfqq->service_used += duration;
- cfq_sort_rr_list(cfqq, 0);
-
- if (duration > max_elapsed_crq)
- max_elapsed_crq = duration;
}
+
+ if (cfq_crq_is_sync(crq))
+ crq->io_context->last_end_request = now;
}
static struct request *cfq_next_request(request_queue_t *q)
@@ -950,7 +1272,18 @@ static struct request *cfq_next_request(request_queue_t *q)
dispatch:
rq = list_entry_rq(q->queue_head.next);
- if ((crq = RQ_DATA(rq)) != NULL) {
+ crq = RQ_DATA(rq);
+ if (crq) {
+ struct cfq_queue *cfqq = crq->cfq_queue;
+
+ /*
+ * if idle window is disabled, allow queue buildup
+ */
+ if (!cfq_crq_in_driver(crq) &&
+ !cfq_cfqq_idle_window(cfqq) &&
+ cfqd->rq_in_driver >= cfqd->cfq_max_depth)
+ return NULL;
+
cfq_remove_merge_hints(q, crq);
cfq_account_dispatch(crq);
}
@@ -958,7 +1291,7 @@ dispatch:
return rq;
}
- if (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+ if (cfq_dispatch_requests(q, cfqd->cfq_quantum, 0))
goto dispatch;
return NULL;
@@ -972,13 +1305,21 @@ dispatch:
*/
static void cfq_put_queue(struct cfq_queue *cfqq)
{
- BUG_ON(!atomic_read(&cfqq->ref));
+ struct cfq_data *cfqd = cfqq->cfqd;
+
+ BUG_ON(atomic_read(&cfqq->ref) <= 0);
if (!atomic_dec_and_test(&cfqq->ref))
return;
BUG_ON(rb_first(&cfqq->sort_list));
- BUG_ON(cfqq->on_rr);
+ BUG_ON(cfqq->allocated[READ] + cfqq->allocated[WRITE]);
+ BUG_ON(cfq_cfqq_on_rr(cfqq));
+
+ if (unlikely(cfqd->active_queue == cfqq)) {
+ __cfq_slice_expired(cfqd, cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
cfq_put_cfqd(cfqq->cfqd);
@@ -991,15 +1332,17 @@ static void cfq_put_queue(struct cfq_queue *cfqq)
}
static inline struct cfq_queue *
-__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
+__cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned int prio,
+ const int hashval)
{
struct hlist_head *hash_list = &cfqd->cfq_hash[hashval];
struct hlist_node *entry, *next;
hlist_for_each_safe(entry, next, hash_list) {
struct cfq_queue *__cfqq = list_entry_qhash(entry);
+ const unsigned short __p = IOPRIO_PRIO_VALUE(__cfqq->ioprio_class, __cfqq->ioprio);
- if (__cfqq->key == key)
+ if (__cfqq->key == key && (__p == prio || prio == CFQ_KEY_ANY))
return __cfqq;
}
@@ -1007,94 +1350,220 @@ __cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key, const int hashval)
}
static struct cfq_queue *
-cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned long key)
+cfq_find_cfq_hash(struct cfq_data *cfqd, unsigned int key, unsigned short prio)
{
- return __cfq_find_cfq_hash(cfqd, key, hash_long(key, CFQ_QHASH_SHIFT));
+ return __cfq_find_cfq_hash(cfqd, key, prio, hash_long(key, CFQ_QHASH_SHIFT));
}
-static inline void
-cfq_rehash_cfqq(struct cfq_data *cfqd, struct cfq_queue **cfqq,
- struct cfq_io_context *cic)
+static void cfq_free_io_context(struct cfq_io_context *cic)
{
- unsigned long hashkey = cfq_hash_key(cfqd, current);
- unsigned long hashval = hash_long(hashkey, CFQ_QHASH_SHIFT);
- struct cfq_queue *__cfqq;
- unsigned long flags;
-
- spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+ struct cfq_io_context *__cic;
+ struct list_head *entry, *next;
- hlist_del(&(*cfqq)->cfq_hash);
-
- __cfqq = __cfq_find_cfq_hash(cfqd, hashkey, hashval);
- if (!__cfqq || __cfqq == *cfqq) {
- __cfqq = *cfqq;
- hlist_add_head(&__cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
- __cfqq->key_type = cfqd->key_type;
- } else {
- atomic_inc(&__cfqq->ref);
- cic->cfqq = __cfqq;
- cfq_put_queue(*cfqq);
- *cfqq = __cfqq;
+ list_for_each_safe(entry, next, &cic->list) {
+ __cic = list_entry(entry, struct cfq_io_context, list);
+ kmem_cache_free(cfq_ioc_pool, __cic);
}
- cic->cfqq = __cfqq;
- spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+ kmem_cache_free(cfq_ioc_pool, cic);
}
-static void cfq_free_io_context(struct cfq_io_context *cic)
+/*
+ * Called with interrupts disabled
+ */
+static void cfq_exit_single_io_context(struct cfq_io_context *cic)
{
- kmem_cache_free(cfq_ioc_pool, cic);
+ struct cfq_data *cfqd = cic->cfqq->cfqd;
+ request_queue_t *q = cfqd->queue;
+
+ WARN_ON(!irqs_disabled());
+
+ spin_lock(q->queue_lock);
+
+ if (unlikely(cic->cfqq == cfqd->active_queue)) {
+ __cfq_slice_expired(cfqd, cic->cfqq, 0);
+ cfq_schedule_dispatch(cfqd);
+ }
+
+ cfq_put_queue(cic->cfqq);
+ cic->cfqq = NULL;
+ spin_unlock(q->queue_lock);
}
/*
- * locking hierarchy is: io_context lock -> queue locks
+ * Another task may update the task cic list, if it is doing a queue lookup
+ * on its behalf. cfq_cic_lock excludes such concurrent updates
*/
static void cfq_exit_io_context(struct cfq_io_context *cic)
{
- struct cfq_queue *cfqq = cic->cfqq;
- struct list_head *entry = &cic->list;
- request_queue_t *q;
+ struct cfq_io_context *__cic;
+ struct list_head *entry;
unsigned long flags;
+ local_irq_save(flags);
+
/*
* put the reference this task is holding to the various queues
*/
- spin_lock_irqsave(&cic->ioc->lock, flags);
- while ((entry = cic->list.next) != &cic->list) {
- struct cfq_io_context *__cic;
-
+ list_for_each(entry, &cic->list) {
__cic = list_entry(entry, struct cfq_io_context, list);
- list_del(entry);
-
- q = __cic->cfqq->cfqd->queue;
- spin_lock(q->queue_lock);
- cfq_put_queue(__cic->cfqq);
- spin_unlock(q->queue_lock);
+ cfq_exit_single_io_context(__cic);
}
- q = cfqq->cfqd->queue;
- spin_lock(q->queue_lock);
- cfq_put_queue(cfqq);
- spin_unlock(q->queue_lock);
-
- cic->cfqq = NULL;
- spin_unlock_irqrestore(&cic->ioc->lock, flags);
+ cfq_exit_single_io_context(cic);
+ local_irq_restore(flags);
}
-static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
+static struct cfq_io_context *
+cfq_alloc_io_context(struct cfq_data *cfqd, int gfp_mask)
{
- struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_flags);
+ struct cfq_io_context *cic = kmem_cache_alloc(cfq_ioc_pool, gfp_mask);
if (cic) {
- cic->dtor = cfq_free_io_context;
- cic->exit = cfq_exit_io_context;
INIT_LIST_HEAD(&cic->list);
cic->cfqq = NULL;
+ cic->key = NULL;
+ cic->last_end_request = jiffies;
+ cic->ttime_total = 0;
+ cic->ttime_samples = 0;
+ cic->ttime_mean = 0;
+ cic->dtor = cfq_free_io_context;
+ cic->exit = cfq_exit_io_context;
}
return cic;
}
+static void cfq_init_prio_data(struct cfq_queue *cfqq)
+{
+ struct task_struct *tsk = current;
+ int ioprio_class;
+
+ if (!cfq_cfqq_prio_changed(cfqq))
+ return;
+
+ ioprio_class = IOPRIO_PRIO_CLASS(tsk->ioprio);
+ switch (ioprio_class) {
+ default:
+ printk(KERN_ERR "cfq: bad prio %x\n", ioprio_class);
+ case IOPRIO_CLASS_NONE:
+ /*
+ * no prio set, place us in the middle of the BE classes
+ */
+ cfqq->ioprio = task_nice_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ break;
+ case IOPRIO_CLASS_RT:
+ cfqq->ioprio = task_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_RT;
+ break;
+ case IOPRIO_CLASS_BE:
+ cfqq->ioprio = task_ioprio(tsk);
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ break;
+ case IOPRIO_CLASS_IDLE:
+ cfqq->ioprio_class = IOPRIO_CLASS_IDLE;
+ cfqq->ioprio = 7;
+ cfq_clear_cfqq_idle_window(cfqq);
+ break;
+ }
+
+ /*
+ * keep track of original prio settings in case we have to temporarily
+ * elevate the priority of this queue
+ */
+ cfqq->org_ioprio = cfqq->ioprio;
+ cfqq->org_ioprio_class = cfqq->ioprio_class;
+
+ if (cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, 0);
+
+ cfq_clear_cfqq_prio_changed(cfqq);
+}
+
+static inline void changed_ioprio(struct cfq_queue *cfqq)
+{
+ if (cfqq) {
+ struct cfq_data *cfqd = cfqq->cfqd;
+
+ spin_lock(cfqd->queue->queue_lock);
+ cfq_mark_cfqq_prio_changed(cfqq);
+ cfq_init_prio_data(cfqq);
+ spin_unlock(cfqd->queue->queue_lock);
+ }
+}
+
+/*
+ * callback from sys_ioprio_set, irqs are disabled
+ */
+static int cfq_ioc_set_ioprio(struct io_context *ioc, unsigned int ioprio)
+{
+ struct cfq_io_context *cic = ioc->cic;
+
+ changed_ioprio(cic->cfqq);
+
+ list_for_each_entry(cic, &cic->list, list)
+ changed_ioprio(cic->cfqq);
+
+ return 0;
+}
+
+static struct cfq_queue *
+cfq_get_queue(struct cfq_data *cfqd, unsigned int key, unsigned short ioprio,
+ int gfp_mask)
+{
+ const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
+ struct cfq_queue *cfqq, *new_cfqq = NULL;
+
+retry:
+ cfqq = __cfq_find_cfq_hash(cfqd, key, ioprio, hashval);
+
+ if (!cfqq) {
+ if (new_cfqq) {
+ cfqq = new_cfqq;
+ new_cfqq = NULL;
+ } else if (gfp_mask & __GFP_WAIT) {
+ spin_unlock_irq(cfqd->queue->queue_lock);
+ new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ spin_lock_irq(cfqd->queue->queue_lock);
+ goto retry;
+ } else {
+ cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
+ if (!cfqq)
+ goto out;
+ }
+
+ memset(cfqq, 0, sizeof(*cfqq));
+
+ INIT_HLIST_NODE(&cfqq->cfq_hash);
+ INIT_LIST_HEAD(&cfqq->cfq_list);
+ RB_CLEAR_ROOT(&cfqq->sort_list);
+ INIT_LIST_HEAD(&cfqq->fifo);
+
+ cfqq->key = key;
+ hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
+ atomic_set(&cfqq->ref, 0);
+ cfqq->cfqd = cfqd;
+ atomic_inc(&cfqd->ref);
+ cfqq->service_last = 0;
+ /*
+ * set ->slice_left to allow preemption for a new process
+ */
+ cfqq->slice_left = 2 * cfqd->cfq_slice_idle;
+ cfq_mark_cfqq_idle_window(cfqq);
+ cfq_mark_cfqq_prio_changed(cfqq);
+ cfq_init_prio_data(cfqq);
+ }
+
+ if (new_cfqq)
+ kmem_cache_free(cfq_pool, new_cfqq);
+
+ atomic_inc(&cfqq->ref);
+out:
+ WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
+ return cfqq;
+}
+
/*
* Setup general io context and cfq io context. There can be several cfq
* io contexts per general io context, if this process is doing io to more
@@ -1102,39 +1571,39 @@ static struct cfq_io_context *cfq_alloc_io_context(int gfp_flags)
* cfqq, so we don't need to worry about it disappearing
*/
static struct cfq_io_context *
-cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
+cfq_get_io_context(struct cfq_data *cfqd, pid_t pid, int gfp_mask)
{
- struct cfq_data *cfqd = (*cfqq)->cfqd;
- struct cfq_queue *__cfqq = *cfqq;
+ struct io_context *ioc = NULL;
struct cfq_io_context *cic;
- struct io_context *ioc;
- might_sleep_if(gfp_flags & __GFP_WAIT);
+ might_sleep_if(gfp_mask & __GFP_WAIT);
- ioc = get_io_context(gfp_flags);
+ ioc = get_io_context(gfp_mask);
if (!ioc)
return NULL;
if ((cic = ioc->cic) == NULL) {
- cic = cfq_alloc_io_context(gfp_flags);
+ cic = cfq_alloc_io_context(cfqd, gfp_mask);
if (cic == NULL)
goto err;
+ /*
+ * manually increment generic io_context usage count, it
+ * cannot go away since we are already holding one ref to it
+ */
ioc->cic = cic;
+ ioc->set_ioprio = cfq_ioc_set_ioprio;
cic->ioc = ioc;
- cic->cfqq = __cfqq;
- atomic_inc(&__cfqq->ref);
+ cic->key = cfqd;
+ atomic_inc(&cfqd->ref);
} else {
struct cfq_io_context *__cic;
- unsigned long flags;
/*
- * since the first cic on the list is actually the head
- * itself, need to check this here or we'll duplicate an
- * cic per ioc for no reason
+ * the first cic on the list is actually the head itself
*/
- if (cic->cfqq == __cfqq)
+ if (cic->key == cfqd)
goto out;
/*
@@ -1142,152 +1611,250 @@ cfq_get_io_context(struct cfq_queue **cfqq, int gfp_flags)
* should be ok here, the list will usually not be more than
* 1 or a few entries long
*/
- spin_lock_irqsave(&ioc->lock, flags);
list_for_each_entry(__cic, &cic->list, list) {
/*
* this process is already holding a reference to
* this queue, so no need to get one more
*/
- if (__cic->cfqq == __cfqq) {
+ if (__cic->key == cfqd) {
cic = __cic;
- spin_unlock_irqrestore(&ioc->lock, flags);
goto out;
}
}
- spin_unlock_irqrestore(&ioc->lock, flags);
/*
* nope, process doesn't have a cic assoicated with this
* cfqq yet. get a new one and add to list
*/
- __cic = cfq_alloc_io_context(gfp_flags);
+ __cic = cfq_alloc_io_context(cfqd, gfp_mask);
if (__cic == NULL)
goto err;
__cic->ioc = ioc;
- __cic->cfqq = __cfqq;
- atomic_inc(&__cfqq->ref);
- spin_lock_irqsave(&ioc->lock, flags);
+ __cic->key = cfqd;
+ atomic_inc(&cfqd->ref);
list_add(&__cic->list, &cic->list);
- spin_unlock_irqrestore(&ioc->lock, flags);
-
cic = __cic;
- *cfqq = __cfqq;
}
out:
- /*
- * if key_type has been changed on the fly, we lazily rehash
- * each queue at lookup time
- */
- if ((*cfqq)->key_type != cfqd->key_type)
- cfq_rehash_cfqq(cfqd, cfqq, cic);
-
return cic;
err:
put_io_context(ioc);
return NULL;
}
-static struct cfq_queue *
-__cfq_get_queue(struct cfq_data *cfqd, unsigned long key, int gfp_mask)
+static void
+cfq_update_io_thinktime(struct cfq_data *cfqd, struct cfq_io_context *cic)
{
- const int hashval = hash_long(key, CFQ_QHASH_SHIFT);
- struct cfq_queue *cfqq, *new_cfqq = NULL;
-
-retry:
- cfqq = __cfq_find_cfq_hash(cfqd, key, hashval);
+ unsigned long elapsed, ttime;
- if (!cfqq) {
- if (new_cfqq) {
- cfqq = new_cfqq;
- new_cfqq = NULL;
- } else {
- spin_unlock_irq(cfqd->queue->queue_lock);
- new_cfqq = kmem_cache_alloc(cfq_pool, gfp_mask);
- spin_lock_irq(cfqd->queue->queue_lock);
+ /*
+ * if this context already has stuff queued, thinktime is from
+ * last queue not last end
+ */
+#if 0
+ if (time_after(cic->last_end_request, cic->last_queue))
+ elapsed = jiffies - cic->last_end_request;
+ else
+ elapsed = jiffies - cic->last_queue;
+#else
+ elapsed = jiffies - cic->last_end_request;
+#endif
- if (!new_cfqq && !(gfp_mask & __GFP_WAIT))
- goto out;
+ ttime = min(elapsed, 2UL * cfqd->cfq_slice_idle);
- goto retry;
- }
+ cic->ttime_samples = (7*cic->ttime_samples + 256) / 8;
+ cic->ttime_total = (7*cic->ttime_total + 256*ttime) / 8;
+ cic->ttime_mean = (cic->ttime_total + 128) / cic->ttime_samples;
+}
- memset(cfqq, 0, sizeof(*cfqq));
+#define sample_valid(samples) ((samples) > 80)
- INIT_HLIST_NODE(&cfqq->cfq_hash);
- INIT_LIST_HEAD(&cfqq->cfq_list);
- RB_CLEAR_ROOT(&cfqq->sort_list);
- INIT_LIST_HEAD(&cfqq->fifo[0]);
- INIT_LIST_HEAD(&cfqq->fifo[1]);
+/*
+ * Disable idle window if the process thinks too long or seeks so much that
+ * it doesn't matter
+ */
+static void
+cfq_update_idle_window(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct cfq_io_context *cic)
+{
+ int enable_idle = cfq_cfqq_idle_window(cfqq);
- cfqq->key = key;
- hlist_add_head(&cfqq->cfq_hash, &cfqd->cfq_hash[hashval]);
- atomic_set(&cfqq->ref, 0);
- cfqq->cfqd = cfqd;
- atomic_inc(&cfqd->ref);
- cfqq->key_type = cfqd->key_type;
- cfqq->service_start = ~0UL;
+ if (!cic->ioc->task || !cfqd->cfq_slice_idle)
+ enable_idle = 0;
+ else if (sample_valid(cic->ttime_samples)) {
+ if (cic->ttime_mean > cfqd->cfq_slice_idle)
+ enable_idle = 0;
+ else
+ enable_idle = 1;
}
- if (new_cfqq)
- kmem_cache_free(cfq_pool, new_cfqq);
+ if (enable_idle)
+ cfq_mark_cfqq_idle_window(cfqq);
+ else
+ cfq_clear_cfqq_idle_window(cfqq);
+}
- atomic_inc(&cfqq->ref);
-out:
- WARN_ON((gfp_mask & __GFP_WAIT) && !cfqq);
- return cfqq;
+
+/*
+ * Check if new_cfqq should preempt the currently active queue. Return 0 for
+ * no or if we aren't sure, a 1 will cause a preempt.
+ */
+static int
+cfq_should_preempt(struct cfq_data *cfqd, struct cfq_queue *new_cfqq,
+ struct cfq_rq *crq)
+{
+ struct cfq_queue *cfqq = cfqd->active_queue;
+
+ if (cfq_class_idle(new_cfqq))
+ return 0;
+
+ if (!cfqq)
+ return 1;
+
+ if (cfq_class_idle(cfqq))
+ return 1;
+ if (!cfq_cfqq_wait_request(new_cfqq))
+ return 0;
+ /*
+ * if it doesn't have slice left, forget it
+ */
+ if (new_cfqq->slice_left < cfqd->cfq_slice_idle)
+ return 0;
+ if (cfq_crq_is_sync(crq) && !cfq_cfqq_sync(cfqq))
+ return 1;
+
+ return 0;
+}
+
+/*
+ * cfqq preempts the active queue. if we allowed preempt with no slice left,
+ * let it have half of its nominal slice.
+ */
+static void cfq_preempt_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ struct cfq_queue *__cfqq, *next;
+
+ list_for_each_entry_safe(__cfqq, next, &cfqd->cur_rr, cfq_list)
+ cfq_resort_rr_list(__cfqq, 1);
+
+ if (!cfqq->slice_left)
+ cfqq->slice_left = cfq_prio_to_slice(cfqd, cfqq) / 2;
+
+ cfqq->slice_end = cfqq->slice_left + jiffies;
+ __cfq_slice_expired(cfqd, cfqq, 1);
+ __cfq_set_active_queue(cfqd, cfqq);
}
-static void cfq_enqueue(struct cfq_data *cfqd, struct cfq_rq *crq)
+/*
+ * should really be a ll_rw_blk.c helper
+ */
+static void cfq_start_queueing(struct cfq_data *cfqd, struct cfq_queue *cfqq)
+{
+ request_queue_t *q = cfqd->queue;
+
+ if (!blk_queue_plugged(q))
+ q->request_fn(q);
+ else
+ __generic_unplug_device(q);
+}
+
+/*
+ * Called when a new fs request (crq) is added (to cfqq). Check if there's
+ * something we should do about it
+ */
+static void
+cfq_crq_enqueued(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct cfq_rq *crq)
{
- crq->is_sync = 0;
- if (rq_data_dir(crq->request) == READ || current->flags & PF_SYNCWRITE)
- crq->is_sync = 1;
+ const int sync = cfq_crq_is_sync(crq);
+
+ cfqq->next_crq = cfq_choose_req(cfqd, cfqq->next_crq, crq);
+
+ if (sync) {
+ struct cfq_io_context *cic = crq->io_context;
+
+ cfq_update_io_thinktime(cfqd, cic);
+ cfq_update_idle_window(cfqd, cfqq, cic);
+
+ cic->last_queue = jiffies;
+ }
+
+ if (cfqq == cfqd->active_queue) {
+ /*
+ * if we are waiting for a request for this queue, let it rip
+ * immediately and flag that we must not expire this queue
+ * just now
+ */
+ if (cfq_cfqq_wait_request(cfqq)) {
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ del_timer(&cfqd->idle_slice_timer);
+ cfq_start_queueing(cfqd, cfqq);
+ }
+ } else if (cfq_should_preempt(cfqd, cfqq, crq)) {
+ /*
+ * not the active queue - expire current slice if it is
+ * idle and has expired it's mean thinktime or this new queue
+ * has some old slice time left and is of higher priority
+ */
+ cfq_preempt_queue(cfqd, cfqq);
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ cfq_start_queueing(cfqd, cfqq);
+ }
+}
+
+static void cfq_enqueue(struct cfq_data *cfqd, struct request *rq)
+{
+ struct cfq_rq *crq = RQ_DATA(rq);
+ struct cfq_queue *cfqq = crq->cfq_queue;
+
+ cfq_init_prio_data(cfqq);
cfq_add_crq_rb(crq);
- crq->queue_start = jiffies;
- list_add_tail(&crq->request->queuelist, &crq->cfq_queue->fifo[crq->is_sync]);
+ list_add_tail(&rq->queuelist, &cfqq->fifo);
+
+ if (rq_mergeable(rq)) {
+ cfq_add_crq_hash(cfqd, crq);
+
+ if (!cfqd->queue->last_merge)
+ cfqd->queue->last_merge = rq;
+ }
+
+ cfq_crq_enqueued(cfqd, cfqq, crq);
}
static void
cfq_insert_request(request_queue_t *q, struct request *rq, int where)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_rq *crq = RQ_DATA(rq);
switch (where) {
case ELEVATOR_INSERT_BACK:
- while (cfq_dispatch_requests(q, cfqd->cfq_quantum))
+ while (cfq_dispatch_requests(q, INT_MAX, 1))
;
list_add_tail(&rq->queuelist, &q->queue_head);
+ /*
+ * If we were idling with pending requests on
+ * inactive cfqqs, force dispatching will
+ * remove the idle timer and the queue won't
+ * be kicked by __make_request() afterward.
+ * Kick it here.
+ */
+ cfq_schedule_dispatch(cfqd);
break;
case ELEVATOR_INSERT_FRONT:
list_add(&rq->queuelist, &q->queue_head);
break;
case ELEVATOR_INSERT_SORT:
BUG_ON(!blk_fs_request(rq));
- cfq_enqueue(cfqd, crq);
+ cfq_enqueue(cfqd, rq);
break;
default:
printk("%s: bad insert point %d\n", __FUNCTION__,where);
return;
}
-
- if (rq_mergeable(rq)) {
- cfq_add_crq_hash(cfqd, crq);
-
- if (!q->last_merge)
- q->last_merge = rq;
- }
-}
-
-static int cfq_queue_empty(request_queue_t *q)
-{
- struct cfq_data *cfqd = q->elevator->elevator_data;
-
- return list_empty(&q->queue_head) && list_empty(&cfqd->rr_list);
}
static void cfq_completed_request(request_queue_t *q, struct request *rq)
@@ -1300,9 +1867,11 @@ static void cfq_completed_request(request_queue_t *q, struct request *rq)
cfqq = crq->cfq_queue;
- if (crq->in_flight) {
- WARN_ON(!cfqq->in_flight);
- cfqq->in_flight--;
+ if (cfq_crq_in_flight(crq)) {
+ const int sync = cfq_crq_is_sync(crq);
+
+ WARN_ON(!cfqq->on_dispatch[sync]);
+ cfqq->on_dispatch[sync]--;
}
cfq_account_completion(cfqq, crq);
@@ -1332,51 +1901,136 @@ cfq_latter_request(request_queue_t *q, struct request *rq)
return NULL;
}
-static int cfq_may_queue(request_queue_t *q, int rw)
+/*
+ * we temporarily boost lower priority queues if they are holding fs exclusive
+ * resources. they are boosted to normal prio (CLASS_BE/4)
+ */
+static void cfq_prio_boost(struct cfq_queue *cfqq)
{
- struct cfq_data *cfqd = q->elevator->elevator_data;
- struct cfq_queue *cfqq;
- int ret = ELV_MQUEUE_MAY;
+ const int ioprio_class = cfqq->ioprio_class;
+ const int ioprio = cfqq->ioprio;
- if (current->flags & PF_MEMALLOC)
- return ELV_MQUEUE_MAY;
+ if (has_fs_excl()) {
+ /*
+ * boost idle prio on transactions that would lock out other
+ * users of the filesystem
+ */
+ if (cfq_class_idle(cfqq))
+ cfqq->ioprio_class = IOPRIO_CLASS_BE;
+ if (cfqq->ioprio > IOPRIO_NORM)
+ cfqq->ioprio = IOPRIO_NORM;
+ } else {
+ /*
+ * check if we need to unboost the queue
+ */
+ if (cfqq->ioprio_class != cfqq->org_ioprio_class)
+ cfqq->ioprio_class = cfqq->org_ioprio_class;
+ if (cfqq->ioprio != cfqq->org_ioprio)
+ cfqq->ioprio = cfqq->org_ioprio;
+ }
- cfqq = cfq_find_cfq_hash(cfqd, cfq_hash_key(cfqd, current));
- if (cfqq) {
- int limit = cfqd->max_queued;
+ /*
+ * refile between round-robin lists if we moved the priority class
+ */
+ if ((ioprio_class != cfqq->ioprio_class || ioprio != cfqq->ioprio) &&
+ cfq_cfqq_on_rr(cfqq))
+ cfq_resort_rr_list(cfqq, 0);
+}
- if (cfqq->allocated[rw] < cfqd->cfq_queued)
- return ELV_MQUEUE_MUST;
+static inline pid_t cfq_queue_pid(struct task_struct *task, int rw)
+{
+ if (rw == READ || process_sync(task))
+ return task->pid;
- if (cfqd->busy_queues)
- limit = q->nr_requests / cfqd->busy_queues;
+ return CFQ_KEY_ASYNC;
+}
- if (limit < cfqd->cfq_queued)
- limit = cfqd->cfq_queued;
- else if (limit > cfqd->max_queued)
- limit = cfqd->max_queued;
+static inline int
+__cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq,
+ struct task_struct *task, int rw)
+{
+#if 1
+ if ((cfq_cfqq_wait_request(cfqq) || cfq_cfqq_must_alloc(cfqq)) &&
+ !cfq_cfqq_must_alloc_slice(cfqq)) {
+ cfq_mark_cfqq_must_alloc_slice(cfqq);
+ return ELV_MQUEUE_MUST;
+ }
- if (cfqq->allocated[rw] >= limit) {
- if (limit > cfqq->alloc_limit[rw])
- cfqq->alloc_limit[rw] = limit;
+ return ELV_MQUEUE_MAY;
+#else
+ if (!cfqq || task->flags & PF_MEMALLOC)
+ return ELV_MQUEUE_MAY;
+ if (!cfqq->allocated[rw] || cfq_cfqq_must_alloc(cfqq)) {
+ if (cfq_cfqq_wait_request(cfqq))
+ return ELV_MQUEUE_MUST;
- ret = ELV_MQUEUE_NO;
+ /*
+ * only allow 1 ELV_MQUEUE_MUST per slice, otherwise we
+ * can quickly flood the queue with writes from a single task
+ */
+ if (rw == READ || !cfq_cfqq_must_alloc_slice(cfqq)) {
+ cfq_mark_cfqq_must_alloc_slice(cfqq);
+ return ELV_MQUEUE_MUST;
}
+
+ return ELV_MQUEUE_MAY;
}
+ if (cfq_class_idle(cfqq))
+ return ELV_MQUEUE_NO;
+ if (cfqq->allocated[rw] >= cfqd->max_queued) {
+ struct io_context *ioc = get_io_context(GFP_ATOMIC);
+ int ret = ELV_MQUEUE_NO;
- return ret;
+ if (ioc && ioc->nr_batch_requests)
+ ret = ELV_MQUEUE_MAY;
+
+ put_io_context(ioc);
+ return ret;
+ }
+
+ return ELV_MQUEUE_MAY;
+#endif
+}
+
+static int cfq_may_queue(request_queue_t *q, int rw, struct bio *bio)
+{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
+ struct cfq_queue *cfqq;
+
+ /*
+ * don't force setup of a queue from here, as a call to may_queue
+ * does not necessarily imply that a request actually will be queued.
+ * so just lookup a possibly existing queue, or return 'may queue'
+ * if that fails
+ */
+ cfqq = cfq_find_cfq_hash(cfqd, cfq_queue_pid(tsk, rw), tsk->ioprio);
+ if (cfqq) {
+ cfq_init_prio_data(cfqq);
+ cfq_prio_boost(cfqq);
+
+ return __cfq_may_queue(cfqd, cfqq, tsk, rw);
+ }
+
+ return ELV_MQUEUE_MAY;
}
static void cfq_check_waiters(request_queue_t *q, struct cfq_queue *cfqq)
{
+ struct cfq_data *cfqd = q->elevator->elevator_data;
struct request_list *rl = &q->rq;
- const int write = waitqueue_active(&rl->wait[WRITE]);
- const int read = waitqueue_active(&rl->wait[READ]);
- if (read && cfqq->allocated[READ] < cfqq->alloc_limit[READ])
- wake_up(&rl->wait[READ]);
- if (write && cfqq->allocated[WRITE] < cfqq->alloc_limit[WRITE])
- wake_up(&rl->wait[WRITE]);
+ if (cfqq->allocated[READ] <= cfqd->max_queued || cfqd->rq_starved) {
+ smp_mb();
+ if (waitqueue_active(&rl->wait[READ]))
+ wake_up(&rl->wait[READ]);
+ }
+
+ if (cfqq->allocated[WRITE] <= cfqd->max_queued || cfqd->rq_starved) {
+ smp_mb();
+ if (waitqueue_active(&rl->wait[WRITE]))
+ wake_up(&rl->wait[WRITE]);
+ }
}
/*
@@ -1389,69 +2043,61 @@ static void cfq_put_request(request_queue_t *q, struct request *rq)
if (crq) {
struct cfq_queue *cfqq = crq->cfq_queue;
+ const int rw = rq_data_dir(rq);
- BUG_ON(q->last_merge == rq);
- BUG_ON(!hlist_unhashed(&crq->hash));
+ BUG_ON(!cfqq->allocated[rw]);
+ cfqq->allocated[rw]--;
- if (crq->io_context)
- put_io_context(crq->io_context->ioc);
-
- BUG_ON(!cfqq->allocated[crq->is_write]);
- cfqq->allocated[crq->is_write]--;
+ put_io_context(crq->io_context->ioc);
mempool_free(crq, cfqd->crq_pool);
rq->elevator_private = NULL;
- smp_mb();
cfq_check_waiters(q, cfqq);
cfq_put_queue(cfqq);
}
}
/*
- * Allocate cfq data structures associated with this request. A queue and
+ * Allocate cfq data structures associated with this request.
*/
-static int cfq_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+static int
+cfq_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
struct cfq_data *cfqd = q->elevator->elevator_data;
+ struct task_struct *tsk = current;
struct cfq_io_context *cic;
const int rw = rq_data_dir(rq);
- struct cfq_queue *cfqq, *saved_cfqq;
+ pid_t key = cfq_queue_pid(tsk, rw);
+ struct cfq_queue *cfqq;
struct cfq_rq *crq;
unsigned long flags;
might_sleep_if(gfp_mask & __GFP_WAIT);
+ cic = cfq_get_io_context(cfqd, key, gfp_mask);
+
spin_lock_irqsave(q->queue_lock, flags);
- cfqq = __cfq_get_queue(cfqd, cfq_hash_key(cfqd, current), gfp_mask);
- if (!cfqq)
- goto out_lock;
+ if (!cic)
+ goto queue_fail;
+
+ if (!cic->cfqq) {
+ cfqq = cfq_get_queue(cfqd, key, tsk->ioprio, gfp_mask);
+ if (!cfqq)
+ goto queue_fail;
-repeat:
- if (cfqq->allocated[rw] >= cfqd->max_queued)
- goto out_lock;
+ cic->cfqq = cfqq;
+ } else
+ cfqq = cic->cfqq;
cfqq->allocated[rw]++;
+ cfq_clear_cfqq_must_alloc(cfqq);
+ cfqd->rq_starved = 0;
+ atomic_inc(&cfqq->ref);
spin_unlock_irqrestore(q->queue_lock, flags);
- /*
- * if hashing type has changed, the cfq_queue might change here.
- */
- saved_cfqq = cfqq;
- cic = cfq_get_io_context(&cfqq, gfp_mask);
- if (!cic)
- goto err;
-
- /*
- * repeat allocation checks on queue change
- */
- if (unlikely(saved_cfqq != cfqq)) {
- spin_lock_irqsave(q->queue_lock, flags);
- saved_cfqq->allocated[rw]--;
- goto repeat;
- }
-
crq = mempool_alloc(cfqd->crq_pool, gfp_mask);
if (crq) {
RB_CLEAR(&crq->rb_node);
@@ -1460,24 +2106,141 @@ repeat:
INIT_HLIST_NODE(&crq->hash);
crq->cfq_queue = cfqq;
crq->io_context = cic;
- crq->service_start = crq->queue_start = 0;
- crq->in_flight = crq->accounted = crq->is_sync = 0;
- crq->is_write = rw;
+ cfq_clear_crq_in_flight(crq);
+ cfq_clear_crq_in_driver(crq);
+ cfq_clear_crq_requeued(crq);
+
+ if (rw == READ || process_sync(tsk))
+ cfq_mark_crq_is_sync(crq);
+ else
+ cfq_clear_crq_is_sync(crq);
+
rq->elevator_private = crq;
- cfqq->alloc_limit[rw] = 0;
return 0;
}
- put_io_context(cic->ioc);
-err:
spin_lock_irqsave(q->queue_lock, flags);
cfqq->allocated[rw]--;
+ if (!(cfqq->allocated[0] + cfqq->allocated[1]))
+ cfq_mark_cfqq_must_alloc(cfqq);
cfq_put_queue(cfqq);
-out_lock:
+queue_fail:
+ if (cic)
+ put_io_context(cic->ioc);
+ /*
+ * mark us rq allocation starved. we need to kickstart the process
+ * ourselves if there are no pending requests that can do it for us.
+ * that would be an extremely rare OOM situation
+ */
+ cfqd->rq_starved = 1;
+ cfq_schedule_dispatch(cfqd);
spin_unlock_irqrestore(q->queue_lock, flags);
return 1;
}
+static void cfq_kick_queue(void *data)
+{
+ request_queue_t *q = data;
+ struct cfq_data *cfqd = q->elevator->elevator_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+
+ if (cfqd->rq_starved) {
+ struct request_list *rl = &q->rq;
+
+ /*
+ * we aren't guaranteed to get a request after this, but we
+ * have to be opportunistic
+ */
+ smp_mb();
+ if (waitqueue_active(&rl->wait[READ]))
+ wake_up(&rl->wait[READ]);
+ if (waitqueue_active(&rl->wait[WRITE]))
+ wake_up(&rl->wait[WRITE]);
+ }
+
+ blk_remove_plug(q);
+ q->request_fn(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+}
+
+/*
+ * Timer running if the active_queue is currently idling inside its time slice
+ */
+static void cfq_idle_slice_timer(unsigned long data)
+{
+ struct cfq_data *cfqd = (struct cfq_data *) data;
+ struct cfq_queue *cfqq;
+ unsigned long flags;
+
+ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+ if ((cfqq = cfqd->active_queue) != NULL) {
+ unsigned long now = jiffies;
+
+ /*
+ * expired
+ */
+ if (time_after(now, cfqq->slice_end))
+ goto expire;
+
+ /*
+ * only expire and reinvoke request handler, if there are
+ * other queues with pending requests
+ */
+ if (!cfq_pending_requests(cfqd)) {
+ cfqd->idle_slice_timer.expires = min(now + cfqd->cfq_slice_idle, cfqq->slice_end);
+ add_timer(&cfqd->idle_slice_timer);
+ goto out_cont;
+ }
+
+ /*
+ * not expired and it has a request pending, let it dispatch
+ */
+ if (!RB_EMPTY(&cfqq->sort_list)) {
+ cfq_mark_cfqq_must_dispatch(cfqq);
+ goto out_kick;
+ }
+ }
+expire:
+ cfq_slice_expired(cfqd, 0);
+out_kick:
+ cfq_schedule_dispatch(cfqd);
+out_cont:
+ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+/*
+ * Timer running if an idle class queue is waiting for service
+ */
+static void cfq_idle_class_timer(unsigned long data)
+{
+ struct cfq_data *cfqd = (struct cfq_data *) data;
+ unsigned long flags, end;
+
+ spin_lock_irqsave(cfqd->queue->queue_lock, flags);
+
+ /*
+ * race with a non-idle queue, reset timer
+ */
+ end = cfqd->last_end_request + CFQ_IDLE_GRACE;
+ if (!time_after_eq(jiffies, end)) {
+ cfqd->idle_class_timer.expires = end;
+ add_timer(&cfqd->idle_class_timer);
+ } else
+ cfq_schedule_dispatch(cfqd);
+
+ spin_unlock_irqrestore(cfqd->queue->queue_lock, flags);
+}
+
+static void cfq_shutdown_timer_wq(struct cfq_data *cfqd)
+{
+ del_timer_sync(&cfqd->idle_slice_timer);
+ del_timer_sync(&cfqd->idle_class_timer);
+ blk_sync_queue(cfqd->queue);
+}
+
static void cfq_put_cfqd(struct cfq_data *cfqd)
{
request_queue_t *q = cfqd->queue;
@@ -1487,6 +2250,9 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
blk_put_queue(q);
+ cfq_shutdown_timer_wq(cfqd);
+ q->elevator->elevator_data = NULL;
+
mempool_destroy(cfqd->crq_pool);
kfree(cfqd->crq_hash);
kfree(cfqd->cfq_hash);
@@ -1495,7 +2261,10 @@ static void cfq_put_cfqd(struct cfq_data *cfqd)
static void cfq_exit_queue(elevator_t *e)
{
- cfq_put_cfqd(e->elevator_data);
+ struct cfq_data *cfqd = e->elevator_data;
+
+ cfq_shutdown_timer_wq(cfqd);
+ cfq_put_cfqd(cfqd);
}
static int cfq_init_queue(request_queue_t *q, elevator_t *e)
@@ -1508,7 +2277,13 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
return -ENOMEM;
memset(cfqd, 0, sizeof(*cfqd));
- INIT_LIST_HEAD(&cfqd->rr_list);
+
+ for (i = 0; i < CFQ_PRIO_LISTS; i++)
+ INIT_LIST_HEAD(&cfqd->rr_list[i]);
+
+ INIT_LIST_HEAD(&cfqd->busy_rr);
+ INIT_LIST_HEAD(&cfqd->cur_rr);
+ INIT_LIST_HEAD(&cfqd->idle_rr);
INIT_LIST_HEAD(&cfqd->empty_list);
cfqd->crq_hash = kmalloc(sizeof(struct hlist_head) * CFQ_MHASH_ENTRIES, GFP_KERNEL);
@@ -1533,24 +2308,32 @@ static int cfq_init_queue(request_queue_t *q, elevator_t *e)
cfqd->queue = q;
atomic_inc(&q->refcnt);
- /*
- * just set it to some high value, we want anyone to be able to queue
- * some requests. fairness is handled differently
- */
- q->nr_requests = 1024;
- cfqd->max_queued = q->nr_requests / 16;
+ cfqd->max_queued = q->nr_requests / 4;
q->nr_batching = cfq_queued;
- cfqd->key_type = CFQ_KEY_TGID;
- cfqd->find_best_crq = 1;
+
+ init_timer(&cfqd->idle_slice_timer);
+ cfqd->idle_slice_timer.function = cfq_idle_slice_timer;
+ cfqd->idle_slice_timer.data = (unsigned long) cfqd;
+
+ init_timer(&cfqd->idle_class_timer);
+ cfqd->idle_class_timer.function = cfq_idle_class_timer;
+ cfqd->idle_class_timer.data = (unsigned long) cfqd;
+
+ INIT_WORK(&cfqd->unplug_work, cfq_kick_queue, q);
+
atomic_set(&cfqd->ref, 1);
cfqd->cfq_queued = cfq_queued;
cfqd->cfq_quantum = cfq_quantum;
- cfqd->cfq_fifo_expire_r = cfq_fifo_expire_r;
- cfqd->cfq_fifo_expire_w = cfq_fifo_expire_w;
- cfqd->cfq_fifo_batch_expire = cfq_fifo_rate;
+ cfqd->cfq_fifo_expire[0] = cfq_fifo_expire[0];
+ cfqd->cfq_fifo_expire[1] = cfq_fifo_expire[1];
cfqd->cfq_back_max = cfq_back_max;
cfqd->cfq_back_penalty = cfq_back_penalty;
+ cfqd->cfq_slice[0] = cfq_slice_async;
+ cfqd->cfq_slice[1] = cfq_slice_sync;
+ cfqd->cfq_slice_async_rq = cfq_slice_async_rq;
+ cfqd->cfq_slice_idle = cfq_slice_idle;
+ cfqd->cfq_max_depth = cfq_max_depth;
return 0;
out_crqpool:
@@ -1595,7 +2378,6 @@ fail:
return -ENOMEM;
}
-
/*
* sysfs parts below -->
*/
@@ -1620,45 +2402,6 @@ cfq_var_store(unsigned int *var, const char *page, size_t count)
return count;
}
-static ssize_t
-cfq_clear_elapsed(struct cfq_data *cfqd, const char *page, size_t count)
-{
- max_elapsed_dispatch = max_elapsed_crq = 0;
- return count;
-}
-
-static ssize_t
-cfq_set_key_type(struct cfq_data *cfqd, const char *page, size_t count)
-{
- spin_lock_irq(cfqd->queue->queue_lock);
- if (!strncmp(page, "pgid", 4))
- cfqd->key_type = CFQ_KEY_PGID;
- else if (!strncmp(page, "tgid", 4))
- cfqd->key_type = CFQ_KEY_TGID;
- else if (!strncmp(page, "uid", 3))
- cfqd->key_type = CFQ_KEY_UID;
- else if (!strncmp(page, "gid", 3))
- cfqd->key_type = CFQ_KEY_GID;
- spin_unlock_irq(cfqd->queue->queue_lock);
- return count;
-}
-
-static ssize_t
-cfq_read_key_type(struct cfq_data *cfqd, char *page)
-{
- ssize_t len = 0;
- int i;
-
- for (i = CFQ_KEY_PGID; i < CFQ_KEY_LAST; i++) {
- if (cfqd->key_type == i)
- len += sprintf(page+len, "[%s] ", cfq_key_types[i]);
- else
- len += sprintf(page+len, "%s ", cfq_key_types[i]);
- }
- len += sprintf(page+len, "\n");
- return len;
-}
-
#define SHOW_FUNCTION(__FUNC, __VAR, __CONV) \
static ssize_t __FUNC(struct cfq_data *cfqd, char *page) \
{ \
@@ -1669,12 +2412,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, char *page) \
}
SHOW_FUNCTION(cfq_quantum_show, cfqd->cfq_quantum, 0);
SHOW_FUNCTION(cfq_queued_show, cfqd->cfq_queued, 0);
-SHOW_FUNCTION(cfq_fifo_expire_r_show, cfqd->cfq_fifo_expire_r, 1);
-SHOW_FUNCTION(cfq_fifo_expire_w_show, cfqd->cfq_fifo_expire_w, 1);
-SHOW_FUNCTION(cfq_fifo_batch_expire_show, cfqd->cfq_fifo_batch_expire, 1);
-SHOW_FUNCTION(cfq_find_best_show, cfqd->find_best_crq, 0);
+SHOW_FUNCTION(cfq_fifo_expire_sync_show, cfqd->cfq_fifo_expire[1], 1);
+SHOW_FUNCTION(cfq_fifo_expire_async_show, cfqd->cfq_fifo_expire[0], 1);
SHOW_FUNCTION(cfq_back_max_show, cfqd->cfq_back_max, 0);
SHOW_FUNCTION(cfq_back_penalty_show, cfqd->cfq_back_penalty, 0);
+SHOW_FUNCTION(cfq_slice_idle_show, cfqd->cfq_slice_idle, 1);
+SHOW_FUNCTION(cfq_slice_sync_show, cfqd->cfq_slice[1], 1);
+SHOW_FUNCTION(cfq_slice_async_show, cfqd->cfq_slice[0], 1);
+SHOW_FUNCTION(cfq_slice_async_rq_show, cfqd->cfq_slice_async_rq, 0);
+SHOW_FUNCTION(cfq_max_depth_show, cfqd->cfq_max_depth, 0);
#undef SHOW_FUNCTION
#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \
@@ -1694,12 +2440,15 @@ static ssize_t __FUNC(struct cfq_data *cfqd, const char *page, size_t count) \
}
STORE_FUNCTION(cfq_quantum_store, &cfqd->cfq_quantum, 1, UINT_MAX, 0);
STORE_FUNCTION(cfq_queued_store, &cfqd->cfq_queued, 1, UINT_MAX, 0);
-STORE_FUNCTION(cfq_fifo_expire_r_store, &cfqd->cfq_fifo_expire_r, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_expire_w_store, &cfqd->cfq_fifo_expire_w, 1, UINT_MAX, 1);
-STORE_FUNCTION(cfq_fifo_batch_expire_store, &cfqd->cfq_fifo_batch_expire, 0, UINT_MAX, 1);
-STORE_FUNCTION(cfq_find_best_store, &cfqd->find_best_crq, 0, 1, 0);
+STORE_FUNCTION(cfq_fifo_expire_sync_store, &cfqd->cfq_fifo_expire[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_fifo_expire_async_store, &cfqd->cfq_fifo_expire[0], 1, UINT_MAX, 1);
STORE_FUNCTION(cfq_back_max_store, &cfqd->cfq_back_max, 0, UINT_MAX, 0);
STORE_FUNCTION(cfq_back_penalty_store, &cfqd->cfq_back_penalty, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_slice_idle_store, &cfqd->cfq_slice_idle, 0, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_sync_store, &cfqd->cfq_slice[1], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_store, &cfqd->cfq_slice[0], 1, UINT_MAX, 1);
+STORE_FUNCTION(cfq_slice_async_rq_store, &cfqd->cfq_slice_async_rq, 1, UINT_MAX, 0);
+STORE_FUNCTION(cfq_max_depth_store, &cfqd->cfq_max_depth, 1, UINT_MAX, 0);
#undef STORE_FUNCTION
static struct cfq_fs_entry cfq_quantum_entry = {
@@ -1712,25 +2461,15 @@ static struct cfq_fs_entry cfq_queued_entry = {
.show = cfq_queued_show,
.store = cfq_queued_store,
};
-static struct cfq_fs_entry cfq_fifo_expire_r_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_sync_entry = {
.attr = {.name = "fifo_expire_sync", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_expire_r_show,
- .store = cfq_fifo_expire_r_store,
+ .show = cfq_fifo_expire_sync_show,
+ .store = cfq_fifo_expire_sync_store,
};
-static struct cfq_fs_entry cfq_fifo_expire_w_entry = {
+static struct cfq_fs_entry cfq_fifo_expire_async_entry = {
.attr = {.name = "fifo_expire_async", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_expire_w_show,
- .store = cfq_fifo_expire_w_store,
-};
-static struct cfq_fs_entry cfq_fifo_batch_expire_entry = {
- .attr = {.name = "fifo_batch_expire", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_fifo_batch_expire_show,
- .store = cfq_fifo_batch_expire_store,
-};
-static struct cfq_fs_entry cfq_find_best_entry = {
- .attr = {.name = "find_best_crq", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_find_best_show,
- .store = cfq_find_best_store,
+ .show = cfq_fifo_expire_async_show,
+ .store = cfq_fifo_expire_async_store,
};
static struct cfq_fs_entry cfq_back_max_entry = {
.attr = {.name = "back_seek_max", .mode = S_IRUGO | S_IWUSR },
@@ -1742,27 +2481,44 @@ static struct cfq_fs_entry cfq_back_penalty_entry = {
.show = cfq_back_penalty_show,
.store = cfq_back_penalty_store,
};
-static struct cfq_fs_entry cfq_clear_elapsed_entry = {
- .attr = {.name = "clear_elapsed", .mode = S_IWUSR },
- .store = cfq_clear_elapsed,
+static struct cfq_fs_entry cfq_slice_sync_entry = {
+ .attr = {.name = "slice_sync", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_sync_show,
+ .store = cfq_slice_sync_store,
+};
+static struct cfq_fs_entry cfq_slice_async_entry = {
+ .attr = {.name = "slice_async", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_async_show,
+ .store = cfq_slice_async_store,
};
-static struct cfq_fs_entry cfq_key_type_entry = {
- .attr = {.name = "key_type", .mode = S_IRUGO | S_IWUSR },
- .show = cfq_read_key_type,
- .store = cfq_set_key_type,
+static struct cfq_fs_entry cfq_slice_async_rq_entry = {
+ .attr = {.name = "slice_async_rq", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_async_rq_show,
+ .store = cfq_slice_async_rq_store,
+};
+static struct cfq_fs_entry cfq_slice_idle_entry = {
+ .attr = {.name = "slice_idle", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_slice_idle_show,
+ .store = cfq_slice_idle_store,
+};
+static struct cfq_fs_entry cfq_max_depth_entry = {
+ .attr = {.name = "max_depth", .mode = S_IRUGO | S_IWUSR },
+ .show = cfq_max_depth_show,
+ .store = cfq_max_depth_store,
};
static struct attribute *default_attrs[] = {
&cfq_quantum_entry.attr,
&cfq_queued_entry.attr,
- &cfq_fifo_expire_r_entry.attr,
- &cfq_fifo_expire_w_entry.attr,
- &cfq_fifo_batch_expire_entry.attr,
- &cfq_key_type_entry.attr,
- &cfq_find_best_entry.attr,
+ &cfq_fifo_expire_sync_entry.attr,
+ &cfq_fifo_expire_async_entry.attr,
&cfq_back_max_entry.attr,
&cfq_back_penalty_entry.attr,
- &cfq_clear_elapsed_entry.attr,
+ &cfq_slice_sync_entry.attr,
+ &cfq_slice_async_entry.attr,
+ &cfq_slice_async_rq_entry.attr,
+ &cfq_slice_idle_entry.attr,
+ &cfq_max_depth_entry.attr,
NULL,
};
@@ -1832,21 +2588,46 @@ static int __init cfq_init(void)
{
int ret;
+ /*
+ * could be 0 on HZ < 1000 setups
+ */
+ if (!cfq_slice_async)
+ cfq_slice_async = 1;
+ if (!cfq_slice_idle)
+ cfq_slice_idle = 1;
+
if (cfq_slab_setup())
return -ENOMEM;
ret = elv_register(&iosched_cfq);
- if (!ret) {
- __module_get(THIS_MODULE);
- return 0;
- }
+ if (ret)
+ cfq_slab_kill();
- cfq_slab_kill();
return ret;
}
static void __exit cfq_exit(void)
{
+ struct task_struct *g, *p;
+ unsigned long flags;
+
+ read_lock_irqsave(&tasklist_lock, flags);
+
+ /*
+ * iterate each process in the system, removing our io_context
+ */
+ do_each_thread(g, p) {
+ struct io_context *ioc = p->io_context;
+
+ if (ioc && ioc->cic) {
+ ioc->cic->exit(ioc->cic);
+ cfq_free_io_context(ioc->cic);
+ ioc->cic = NULL;
+ }
+ } while_each_thread(g, p);
+
+ read_unlock_irqrestore(&tasklist_lock, flags);
+
cfq_slab_kill();
elv_unregister(&iosched_cfq);
}
diff --git a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
index 4bc2fea73273..ff5201e02153 100644
--- a/drivers/block/deadline-iosched.c
+++ b/drivers/block/deadline-iosched.c
@@ -760,7 +760,8 @@ static void deadline_put_request(request_queue_t *q, struct request *rq)
}
static int
-deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+deadline_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
struct deadline_data *dd = q->elevator->elevator_data;
struct deadline_rq *drq;
diff --git a/drivers/block/elevator.c b/drivers/block/elevator.c
index f831f08f839c..98f0126a2deb 100644
--- a/drivers/block/elevator.c
+++ b/drivers/block/elevator.c
@@ -486,12 +486,13 @@ struct request *elv_former_request(request_queue_t *q, struct request *rq)
return NULL;
}
-int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+int elv_set_request(request_queue_t *q, struct request *rq, struct bio *bio,
+ int gfp_mask)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_set_req_fn)
- return e->ops->elevator_set_req_fn(q, rq, gfp_mask);
+ return e->ops->elevator_set_req_fn(q, rq, bio, gfp_mask);
rq->elevator_private = NULL;
return 0;
@@ -505,12 +506,12 @@ void elv_put_request(request_queue_t *q, struct request *rq)
e->ops->elevator_put_req_fn(q, rq);
}
-int elv_may_queue(request_queue_t *q, int rw)
+int elv_may_queue(request_queue_t *q, int rw, struct bio *bio)
{
elevator_t *e = q->elevator;
if (e->ops->elevator_may_queue_fn)
- return e->ops->elevator_may_queue_fn(q, rw);
+ return e->ops->elevator_may_queue_fn(q, rw, bio);
return ELV_MQUEUE_MAY;
}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index fd94ea27d594..692a5fced76e 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -37,6 +37,7 @@
static void blk_unplug_work(void *data);
static void blk_unplug_timeout(unsigned long data);
+static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io);
/*
* For the allocated request tables
@@ -275,6 +276,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq)
rq->errors = 0;
rq->rq_status = RQ_ACTIVE;
rq->bio = rq->biotail = NULL;
+ rq->ioprio = 0;
rq->buffer = NULL;
rq->ref_count = 1;
rq->q = q;
@@ -1137,7 +1139,7 @@ new_hw_segment:
}
-int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
+static int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
struct bio *nxt)
{
if (!(q->queue_flags & (1 << QUEUE_FLAG_CLUSTER)))
@@ -1158,9 +1160,7 @@ int blk_phys_contig_segment(request_queue_t *q, struct bio *bio,
return 0;
}
-EXPORT_SYMBOL(blk_phys_contig_segment);
-
-int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
+static int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
struct bio *nxt)
{
if (unlikely(!bio_flagged(bio, BIO_SEG_VALID)))
@@ -1176,8 +1176,6 @@ int blk_hw_contig_segment(request_queue_t *q, struct bio *bio,
return 1;
}
-EXPORT_SYMBOL(blk_hw_contig_segment);
-
/*
* map a request to scatterlist, return number of sg entries setup. Caller
* must make sure sg can hold rq->nr_phys_segments entries
@@ -1347,8 +1345,8 @@ static int ll_front_merge_fn(request_queue_t *q, struct request *req,
static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
struct request *next)
{
- int total_phys_segments = req->nr_phys_segments +next->nr_phys_segments;
- int total_hw_segments = req->nr_hw_segments + next->nr_hw_segments;
+ int total_phys_segments;
+ int total_hw_segments;
/*
* First check if the either of the requests are re-queued
@@ -1358,7 +1356,7 @@ static int ll_merge_requests_fn(request_queue_t *q, struct request *req,
return 0;
/*
- * Will it become to large?
+ * Will it become too large?
*/
if ((req->nr_sectors + next->nr_sectors) > q->max_sectors)
return 0;
@@ -1445,11 +1443,7 @@ void __generic_unplug_device(request_queue_t *q)
if (!blk_remove_plug(q))
return;
- /*
- * was plugged, fire request_fn if queue has stuff to do
- */
- if (elv_next_request(q))
- q->request_fn(q);
+ q->request_fn(q);
}
EXPORT_SYMBOL(__generic_unplug_device);
@@ -1779,8 +1773,8 @@ static inline void blk_free_request(request_queue_t *q, struct request *rq)
mempool_free(rq, q->rq.rq_pool);
}
-static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
- int gfp_mask)
+static inline struct request *
+blk_alloc_request(request_queue_t *q, int rw, struct bio *bio, int gfp_mask)
{
struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
@@ -1793,7 +1787,7 @@ static inline struct request *blk_alloc_request(request_queue_t *q, int rw,
*/
rq->flags = rw;
- if (!elv_set_request(q, rq, gfp_mask))
+ if (!elv_set_request(q, rq, bio, gfp_mask))
return rq;
mempool_free(rq, q->rq.rq_pool);
@@ -1825,7 +1819,7 @@ static inline int ioc_batching(request_queue_t *q, struct io_context *ioc)
* is the behaviour we want though - once it gets a wakeup it should be given
* a nice run.
*/
-void ioc_set_batching(request_queue_t *q, struct io_context *ioc)
+static void ioc_set_batching(request_queue_t *q, struct io_context *ioc)
{
if (!ioc || ioc_batching(q, ioc))
return;
@@ -1873,18 +1867,20 @@ static void freed_request(request_queue_t *q, int rw)
#define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist)
/*
- * Get a free request, queue_lock must not be held
+ * Get a free request, queue_lock must be held.
+ * Returns NULL on failure, with queue_lock held.
+ * Returns !NULL on success, with queue_lock *not held*.
*/
-static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
+static struct request *get_request(request_queue_t *q, int rw, struct bio *bio,
+ int gfp_mask)
{
struct request *rq = NULL;
struct request_list *rl = &q->rq;
- struct io_context *ioc = get_io_context(gfp_mask);
+ struct io_context *ioc = current_io_context(GFP_ATOMIC);
if (unlikely(test_bit(QUEUE_FLAG_DRAIN, &q->queue_flags)))
goto out;
- spin_lock_irq(q->queue_lock);
if (rl->count[rw]+1 >= q->nr_requests) {
/*
* The queue will fill after this allocation, so set it as
@@ -1898,7 +1894,7 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
}
}
- switch (elv_may_queue(q, rw)) {
+ switch (elv_may_queue(q, rw, bio)) {
case ELV_MQUEUE_NO:
goto rq_starved;
case ELV_MQUEUE_MAY:
@@ -1912,18 +1908,25 @@ static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
* The queue is full and the allocating process is not a
* "batcher", and not exempted by the IO scheduler
*/
- spin_unlock_irq(q->queue_lock);
goto out;
}
get_rq:
+ /*
+ * Only allow batching queuers to allocate up to 50% over the defined
+ * limit of requests, otherwise we could have thousands of requests
+ * allocated with any setting of ->nr_requests
+ */
+ if (rl->count[rw] >= (3 * q->nr_requests / 2))
+ goto out;
+
rl->count[rw]++;
rl->starved[rw] = 0;
if (rl->count[rw] >= queue_congestion_on_threshold(q))
set_queue_congested(q, rw);
spin_unlock_irq(q->queue_lock);
- rq = blk_alloc_request(q, rw, gfp_mask);
+ rq = blk_alloc_request(q, rw, bio, gfp_mask);
if (!rq) {
/*
* Allocation failed presumably due to memory. Undo anything
@@ -1946,7 +1949,6 @@ rq_starved:
if (unlikely(rl->count[rw] == 0))
rl->starved[rw] = 1;
- spin_unlock_irq(q->queue_lock);
goto out;
}
@@ -1956,31 +1958,35 @@ rq_starved:
rq_init(q, rq);
rq->rl = rl;
out:
- put_io_context(ioc);
return rq;
}
/*
* No available requests for this queue, unplug the device and wait for some
* requests to become available.
+ *
+ * Called with q->queue_lock held, and returns with it unlocked.
*/
-static struct request *get_request_wait(request_queue_t *q, int rw)
+static struct request *get_request_wait(request_queue_t *q, int rw,
+ struct bio *bio)
{
- DEFINE_WAIT(wait);
struct request *rq;
- do {
+ rq = get_request(q, rw, bio, GFP_NOIO);
+ while (!rq) {
+ DEFINE_WAIT(wait);
struct request_list *rl = &q->rq;
prepare_to_wait_exclusive(&rl->wait[rw], &wait,
TASK_UNINTERRUPTIBLE);
- rq = get_request(q, rw, GFP_NOIO);
+ rq = get_request(q, rw, bio, GFP_NOIO);
if (!rq) {
struct io_context *ioc;
- generic_unplug_device(q);
+ __generic_unplug_device(q);
+ spin_unlock_irq(q->queue_lock);
io_schedule();
/*
@@ -1989,12 +1995,13 @@ static struct request *get_request_wait(request_queue_t *q, int rw)
* up to a big batch of them for a small period time.
* See ioc_batching, ioc_set_batching
*/
- ioc = get_io_context(GFP_NOIO);
+ ioc = current_io_context(GFP_NOIO);
ioc_set_batching(q, ioc);
- put_io_context(ioc);
+
+ spin_lock_irq(q->queue_lock);
}
finish_wait(&rl->wait[rw], &wait);
- } while (!rq);
+ }
return rq;
}
@@ -2005,14 +2012,18 @@ struct request *blk_get_request(request_queue_t *q, int rw, int gfp_mask)
BUG_ON(rw != READ && rw != WRITE);
- if (gfp_mask & __GFP_WAIT)
- rq = get_request_wait(q, rw);
- else
- rq = get_request(q, rw, gfp_mask);
+ spin_lock_irq(q->queue_lock);
+ if (gfp_mask & __GFP_WAIT) {
+ rq = get_request_wait(q, rw, NULL);
+ } else {
+ rq = get_request(q, rw, NULL, gfp_mask);
+ if (!rq)
+ spin_unlock_irq(q->queue_lock);
+ }
+ /* q->queue_lock is unlocked at this point */
return rq;
}
-
EXPORT_SYMBOL(blk_get_request);
/**
@@ -2254,45 +2265,7 @@ int blkdev_issue_flush(struct block_device *bdev, sector_t *error_sector)
EXPORT_SYMBOL(blkdev_issue_flush);
-/**
- * blkdev_scsi_issue_flush_fn - issue flush for SCSI devices
- * @q: device queue
- * @disk: gendisk
- * @error_sector: error offset
- *
- * Description:
- * Devices understanding the SCSI command set, can use this function as
- * a helper for issuing a cache flush. Note: driver is required to store
- * the error offset (in case of error flushing) in ->sector of struct
- * request.
- */
-int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
- sector_t *error_sector)
-{
- struct request *rq = blk_get_request(q, WRITE, __GFP_WAIT);
- int ret;
-
- rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
- rq->sector = 0;
- memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->cmd[0] = 0x35;
- rq->cmd_len = 12;
- rq->data = NULL;
- rq->data_len = 0;
- rq->timeout = 60 * HZ;
-
- ret = blk_execute_rq(q, disk, rq);
-
- if (ret && error_sector)
- *error_sector = rq->sector;
-
- blk_put_request(rq);
- return ret;
-}
-
-EXPORT_SYMBOL(blkdev_scsi_issue_flush_fn);
-
-void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
+static void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
{
int rw = rq_data_dir(rq);
@@ -2374,7 +2347,6 @@ static void __blk_put_request(request_queue_t *q, struct request *req)
return;
req->rq_status = RQ_INACTIVE;
- req->q = NULL;
req->rl = NULL;
/*
@@ -2503,6 +2475,8 @@ static int attempt_merge(request_queue_t *q, struct request *req,
req->rq_disk->in_flight--;
}
+ req->ioprio = ioprio_best(req->ioprio, next->ioprio);
+
__blk_put_request(q, next);
return 1;
}
@@ -2551,25 +2525,17 @@ void blk_attempt_remerge(request_queue_t *q, struct request *rq)
EXPORT_SYMBOL(blk_attempt_remerge);
-/*
- * Non-locking blk_attempt_remerge variant.
- */
-void __blk_attempt_remerge(request_queue_t *q, struct request *rq)
-{
- attempt_back_merge(q, rq);
-}
-
-EXPORT_SYMBOL(__blk_attempt_remerge);
-
static int __make_request(request_queue_t *q, struct bio *bio)
{
- struct request *req, *freereq = NULL;
+ struct request *req;
int el_ret, rw, nr_sectors, cur_nr_sectors, barrier, err, sync;
+ unsigned short prio;
sector_t sector;
sector = bio->bi_sector;
nr_sectors = bio_sectors(bio);
cur_nr_sectors = bio_cur_sectors(bio);
+ prio = bio_prio(bio);
rw = bio_data_dir(bio);
sync = bio_sync(bio);
@@ -2589,14 +2555,9 @@ static int __make_request(request_queue_t *q, struct bio *bio)
goto end_io;
}
-again:
spin_lock_irq(q->queue_lock);
- if (elv_queue_empty(q)) {
- blk_plug_device(q);
- goto get_rq;
- }
- if (barrier)
+ if (unlikely(barrier) || elv_queue_empty(q))
goto get_rq;
el_ret = elv_merge(q, &req, bio);
@@ -2610,6 +2571,7 @@ again:
req->biotail->bi_next = bio;
req->biotail = bio;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+ req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_back_merge(q, req))
elv_merged_request(q, req);
@@ -2634,45 +2596,30 @@ again:
req->hard_cur_sectors = cur_nr_sectors;
req->sector = req->hard_sector = sector;
req->nr_sectors = req->hard_nr_sectors += nr_sectors;
+ req->ioprio = ioprio_best(req->ioprio, prio);
drive_stat_acct(req, nr_sectors, 0);
if (!attempt_front_merge(q, req))
elv_merged_request(q, req);
goto out;
- /*
- * elevator says don't/can't merge. get new request
- */
- case ELEVATOR_NO_MERGE:
- break;
-
+ /* ELV_NO_MERGE: elevator says don't/can't merge. */
default:
- printk("elevator returned crap (%d)\n", el_ret);
- BUG();
+ ;
}
+get_rq:
/*
- * Grab a free request from the freelist - if that is empty, check
- * if we are doing read ahead and abort instead of blocking for
- * a free slot.
+ * Grab a free request. This is might sleep but can not fail.
+ * Returns with the queue unlocked.
+ */
+ req = get_request_wait(q, rw, bio);
+
+ /*
+ * After dropping the lock and possibly sleeping here, our request
+ * may now be mergeable after it had proven unmergeable (above).
+ * We don't worry about that case for efficiency. It won't happen
+ * often, and the elevators are able to handle it.
*/
-get_rq:
- if (freereq) {
- req = freereq;
- freereq = NULL;
- } else {
- spin_unlock_irq(q->queue_lock);
- if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
- /*
- * READA bit set
- */
- err = -EWOULDBLOCK;
- if (bio_rw_ahead(bio))
- goto end_io;
-
- freereq = get_request_wait(q, rw);
- }
- goto again;
- }
req->flags |= REQ_CMD;
@@ -2697,13 +2644,15 @@ get_rq:
req->buffer = bio_data(bio); /* see ->buffer comment above */
req->waiting = NULL;
req->bio = req->biotail = bio;
+ req->ioprio = prio;
req->rq_disk = bio->bi_bdev->bd_disk;
req->start_time = jiffies;
+ spin_lock_irq(q->queue_lock);
+ if (elv_queue_empty(q))
+ blk_plug_device(q);
add_request(q, req);
out:
- if (freereq)
- __blk_put_request(q, freereq);
if (sync)
__generic_unplug_device(q);
@@ -2725,7 +2674,7 @@ static inline void blk_partition_remap(struct bio *bio)
if (bdev != bdev->bd_contains) {
struct hd_struct *p = bdev->bd_part;
- switch (bio->bi_rw) {
+ switch (bio_data_dir(bio)) {
case READ:
p->read_sectors += bio_sectors(bio);
p->reads++;
@@ -2744,6 +2693,7 @@ void blk_finish_queue_drain(request_queue_t *q)
{
struct request_list *rl = &q->rq;
struct request *rq;
+ int requeued = 0;
spin_lock_irq(q->queue_lock);
clear_bit(QUEUE_FLAG_DRAIN, &q->queue_flags);
@@ -2752,9 +2702,13 @@ void blk_finish_queue_drain(request_queue_t *q)
rq = list_entry_rq(q->drain_list.next);
list_del_init(&rq->queuelist);
- __elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1);
+ elv_requeue_request(q, rq);
+ requeued++;
}
+ if (requeued)
+ q->request_fn(q);
+
spin_unlock_irq(q->queue_lock);
wake_up(&rl->wait[0]);
@@ -2951,7 +2905,7 @@ void submit_bio(int rw, struct bio *bio)
BIO_BUG_ON(!bio->bi_size);
BIO_BUG_ON(!bio->bi_io_vec);
- bio->bi_rw = rw;
+ bio->bi_rw |= rw;
if (rw & WRITE)
mod_page_state(pgpgout, count);
else
@@ -2971,7 +2925,7 @@ void submit_bio(int rw, struct bio *bio)
EXPORT_SYMBOL(submit_bio);
-void blk_recalc_rq_segments(struct request *rq)
+static void blk_recalc_rq_segments(struct request *rq)
{
struct bio *bio, *prevbio = NULL;
int nr_phys_segs, nr_hw_segs;
@@ -3013,7 +2967,7 @@ void blk_recalc_rq_segments(struct request *rq)
rq->nr_hw_segments = nr_hw_segs;
}
-void blk_recalc_rq_sectors(struct request *rq, int nsect)
+static void blk_recalc_rq_sectors(struct request *rq, int nsect)
{
if (blk_fs_request(rq)) {
rq->hard_sector += nsect;
@@ -3308,8 +3262,11 @@ void exit_io_context(void)
struct io_context *ioc;
local_irq_save(flags);
+ task_lock(current);
ioc = current->io_context;
current->io_context = NULL;
+ ioc->task = NULL;
+ task_unlock(current);
local_irq_restore(flags);
if (ioc->aic && ioc->aic->exit)
@@ -3322,53 +3279,49 @@ void exit_io_context(void)
/*
* If the current task has no IO context then create one and initialise it.
- * If it does have a context, take a ref on it.
+ * Otherwise, return its existing IO context.
*
- * This is always called in the context of the task which submitted the I/O.
- * But weird things happen, so we disable local interrupts to ensure exclusive
- * access to *current.
+ * This returned IO context doesn't have a specifically elevated refcount,
+ * but since the current task itself holds a reference, the context can be
+ * used in general code, so long as it stays within `current` context.
*/
-struct io_context *get_io_context(int gfp_flags)
+struct io_context *current_io_context(int gfp_flags)
{
struct task_struct *tsk = current;
- unsigned long flags;
struct io_context *ret;
- local_irq_save(flags);
ret = tsk->io_context;
- if (ret)
- goto out;
-
- local_irq_restore(flags);
+ if (likely(ret))
+ return ret;
ret = kmem_cache_alloc(iocontext_cachep, gfp_flags);
if (ret) {
atomic_set(&ret->refcount, 1);
- ret->pid = tsk->pid;
+ ret->task = current;
+ ret->set_ioprio = NULL;
ret->last_waited = jiffies; /* doesn't matter... */
ret->nr_batch_requests = 0; /* because this is 0 */
ret->aic = NULL;
ret->cic = NULL;
- spin_lock_init(&ret->lock);
-
- local_irq_save(flags);
+ tsk->io_context = ret;
+ }
- /*
- * very unlikely, someone raced with us in setting up the task
- * io context. free new context and just grab a reference.
- */
- if (!tsk->io_context)
- tsk->io_context = ret;
- else {
- kmem_cache_free(iocontext_cachep, ret);
- ret = tsk->io_context;
- }
+ return ret;
+}
+EXPORT_SYMBOL(current_io_context);
-out:
+/*
+ * If the current task has no IO context then create one and initialise it.
+ * If it does have a context, take a ref on it.
+ *
+ * This is always called in the context of the task which submitted the I/O.
+ */
+struct io_context *get_io_context(int gfp_flags)
+{
+ struct io_context *ret;
+ ret = current_io_context(gfp_flags);
+ if (likely(ret))
atomic_inc(&ret->refcount);
- local_irq_restore(flags);
- }
-
return ret;
}
EXPORT_SYMBOL(get_io_context);
@@ -3601,7 +3554,7 @@ static struct sysfs_ops queue_sysfs_ops = {
.store = queue_attr_store,
};
-struct kobj_type queue_ktype = {
+static struct kobj_type queue_ktype = {
.sysfs_ops = &queue_sysfs_ops,
.default_attrs = default_attrs,
};
diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c
index 7f3d78de265c..7b838342f0a3 100644
--- a/drivers/block/pktcdvd.c
+++ b/drivers/block/pktcdvd.c
@@ -1251,8 +1251,7 @@ static int kcdrwd(void *foobar)
VPRINTK("kcdrwd: wake up\n");
/* make swsusp happy with our thread */
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
list_for_each_entry(pkt, &pd->cdrw.pkt_active_list, list) {
if (!pkt->sleep_time)
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index 5b09cf154ac7..e5f7494c00ee 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -253,7 +253,7 @@ static int floppy_revalidate(struct gendisk *disk);
static int swim3_add_device(struct device_node *swims);
int swim3_init(void);
-#ifndef CONFIG_PMAC_PBOOK
+#ifndef CONFIG_PMAC_MEDIABAY
#define check_media_bay(which, what) 1
#endif
@@ -297,9 +297,11 @@ static void do_fd_request(request_queue_t * q)
int i;
for(i=0;i<floppy_count;i++)
{
+#ifdef CONFIG_PMAC_MEDIABAY
if (floppy_states[i].media_bay &&
check_media_bay(floppy_states[i].media_bay, MB_FD))
continue;
+#endif /* CONFIG_PMAC_MEDIABAY */
start_request(&floppy_states[i]);
}
sti();
@@ -856,8 +858,10 @@ static int floppy_ioctl(struct inode *inode, struct file *filp,
if ((cmd & 0x80) && !capable(CAP_SYS_ADMIN))
return -EPERM;
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
switch (cmd) {
case FDEJECT:
@@ -881,8 +885,10 @@ static int floppy_open(struct inode *inode, struct file *filp)
int n, err = 0;
if (fs->ref_count == 0) {
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
out_8(&sw->setup, S_IBM_DRIVE | S_FCLK_DIV2);
out_8(&sw->control_bic, 0xff);
out_8(&sw->mode, 0x95);
@@ -967,8 +973,10 @@ static int floppy_revalidate(struct gendisk *disk)
struct swim3 __iomem *sw;
int ret, n;
+#ifdef CONFIG_PMAC_MEDIABAY
if (fs->media_bay && check_media_bay(fs->media_bay, MB_FD))
return -ENXIO;
+#endif
sw = fs->swim3;
grab_drive(fs, revalidating, 0);
diff --git a/drivers/block/sx8.c b/drivers/block/sx8.c
index 5ed3a6379452..9db0a9e3e59c 100644
--- a/drivers/block/sx8.c
+++ b/drivers/block/sx8.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/time.h>
#include <linux/hdreg.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -1582,9 +1583,9 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out;
#if IF_64BIT_DMA_IS_POSSIBLE /* grrrr... */
- rc = pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
if (!rc) {
- rc = pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
if (rc) {
printk(KERN_ERR DRV_NAME "(%s): consistent DMA mask failure\n",
pci_name(pdev));
@@ -1593,7 +1594,7 @@ static int carm_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
pci_dac = 1;
} else {
#endif
- rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR DRV_NAME "(%s): DMA mask failure\n",
pci_name(pdev));
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index e481cc411b5d..bd2ec7e284cc 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -40,7 +40,6 @@
#include <linux/skbuff.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -895,11 +894,6 @@ static dev_link_t *bluecard_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &bluecard_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -1089,13 +1083,23 @@ static int bluecard_event(event_t event, int priority, event_callback_args_t *ar
return 0;
}
+static struct pcmcia_device_id bluecard_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("BlueCard", "LSE041", 0xbaf16fbf, 0x657cc15e),
+ PCMCIA_DEVICE_PROD_ID12("BTCFCARD", "LSE139", 0xe3987764, 0x2524b59c),
+ PCMCIA_DEVICE_PROD_ID12("WSS", "LSE039", 0x0a0736ec, 0x24e6dfab),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bluecard_ids);
+
static struct pcmcia_driver bluecard_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "bluecard_cs",
},
.attach = bluecard_attach,
+ .event = bluecard_event,
.detach = bluecard_detach,
+ .id_table = bluecard_ids,
};
static int __init init_bluecard_cs(void)
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index f71e5c76963d..adf1750ea58d 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -47,7 +47,6 @@
#include <linux/device.h>
#include <linux/firmware.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -696,11 +695,6 @@ static dev_link_t *bt3c_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &bt3c_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -935,13 +929,21 @@ static int bt3c_event(event_t event, int priority, event_callback_args_t *args)
return 0;
}
+static struct pcmcia_device_id bt3c_ids[] = {
+ PCMCIA_DEVICE_PROD_ID13("3COM", "Bluetooth PC Card", 0xefce0a31, 0xd4ce9b02),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, bt3c_ids);
+
static struct pcmcia_driver bt3c_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "bt3c_cs",
},
.attach = bt3c_attach,
+ .event = bt3c_event,
.detach = bt3c_detach,
+ .id_table = bt3c_ids,
};
static int __init init_bt3c_cs(void)
diff --git a/drivers/bluetooth/btuart_cs.c b/drivers/bluetooth/btuart_cs.c
index ad8d972444a5..e4c59fdc0e12 100644
--- a/drivers/bluetooth/btuart_cs.c
+++ b/drivers/bluetooth/btuart_cs.c
@@ -43,7 +43,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -615,11 +614,6 @@ static dev_link_t *btuart_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &btuart_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -855,13 +849,21 @@ static int btuart_event(event_t event, int priority, event_callback_args_t *args
return 0;
}
+static struct pcmcia_device_id btuart_ids[] = {
+ /* don't use this driver. Use serial_cs + hci_uart instead */
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, btuart_ids);
+
static struct pcmcia_driver btuart_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "btuart_cs",
},
.attach = btuart_attach,
+ .event = btuart_event,
.detach = btuart_detach,
+ .id_table = btuart_ids,
};
static int __init init_btuart_cs(void)
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index fe954e5d9a1d..e39868c3da48 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -43,7 +43,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -594,11 +593,6 @@ static dev_link_t *dtl1_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &dtl1_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -807,13 +801,22 @@ static int dtl1_event(event_t event, int priority, event_callback_args_t *args)
return 0;
}
+static struct pcmcia_device_id dtl1_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("Nokia Mobile Phones", "DTL-1", 0xe1bfdd64, 0xe168480d),
+ PCMCIA_DEVICE_PROD_ID12("Socket", "CF", 0xb38bcc2e, 0x44ebf863),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, dtl1_ids);
+
static struct pcmcia_driver dtl1_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "dtl1_cs",
},
.attach = dtl1_attach,
+ .event = dtl1_event,
.detach = dtl1_detach,
+ .id_table = dtl1_ids,
};
static int __init init_dtl1_cs(void)
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index 3256192dcde8..f9b956fb2b8b 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -120,7 +120,7 @@ static unsigned int hci_vhci_chr_poll(struct file *file, poll_table * wait)
poll_wait(file, &hci_vhci->read_wait, wait);
- if (skb_queue_len(&hci_vhci->readq))
+ if (!skb_queue_empty(&hci_vhci->readq))
return POLLIN | POLLRDNORM;
return POLLOUT | POLLWRNORM;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index da80b14335a5..01f035173328 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -307,7 +307,7 @@ static DEFINE_SPINLOCK(cm206_lock);
/* First, we define some polling functions. These are actually
only being used in the initialization. */
-void send_command_polled(int command)
+static void send_command_polled(int command)
{
int loop = POLLOOP;
while (!(inw(r_line_status) & ls_transmitter_buffer_empty)
@@ -318,7 +318,7 @@ void send_command_polled(int command)
outw(command, r_uart_transmit);
}
-uch receive_echo_polled(void)
+static uch receive_echo_polled(void)
{
int loop = POLLOOP;
while (!(inw(r_line_status) & ls_receive_buffer_full) && loop > 0) {
@@ -328,13 +328,13 @@ uch receive_echo_polled(void)
return ((uch) inw(r_uart_receive));
}
-uch send_receive_polled(int command)
+static uch send_receive_polled(int command)
{
send_command_polled(command);
return receive_echo_polled();
}
-inline void clear_ur(void)
+static inline void clear_ur(void)
{
if (cd->ur_r != cd->ur_w) {
debug(("Deleting bytes from fifo:"));
@@ -439,7 +439,7 @@ static irqreturn_t cm206_interrupt(int sig, void *dev_id, struct pt_regs *regs)
}
/* we have put the address of the wait queue in who */
-void cm206_timeout(unsigned long who)
+static void cm206_timeout(unsigned long who)
{
cd->timed_out = 1;
debug(("Timing out\n"));
@@ -448,7 +448,7 @@ void cm206_timeout(unsigned long who)
/* This function returns 1 if a timeout occurred, 0 if an interrupt
happened */
-int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
+static int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
{
cd->timed_out = 0;
init_timer(&cd->timer);
@@ -465,13 +465,7 @@ int sleep_or_timeout(wait_queue_head_t * wait, int timeout)
return 0;
}
-void cm206_delay(int nr_jiffies)
-{
- DECLARE_WAIT_QUEUE_HEAD(wait);
- sleep_or_timeout(&wait, nr_jiffies);
-}
-
-void send_command(int command)
+static void send_command(int command)
{
debug(("Sending 0x%x\n", command));
if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) {
@@ -490,7 +484,7 @@ void send_command(int command)
outw(command, r_uart_transmit);
}
-uch receive_byte(int timeout)
+static uch receive_byte(int timeout)
{
uch ret;
cli();
@@ -521,23 +515,23 @@ uch receive_byte(int timeout)
return ret;
}
-inline uch receive_echo(void)
+static inline uch receive_echo(void)
{
return receive_byte(UART_TIMEOUT);
}
-inline uch send_receive(int command)
+static inline uch send_receive(int command)
{
send_command(command);
return receive_echo();
}
-inline uch wait_dsb(void)
+static inline uch wait_dsb(void)
{
return receive_byte(DSB_TIMEOUT);
}
-int type_0_command(int command, int expect_dsb)
+static int type_0_command(int command, int expect_dsb)
{
int e;
clear_ur();
@@ -552,7 +546,7 @@ int type_0_command(int command, int expect_dsb)
return 0;
}
-int type_1_command(int command, int bytes, uch * status)
+static int type_1_command(int command, int bytes, uch * status)
{ /* returns info */
int i;
if (type_0_command(command, 0))
@@ -564,7 +558,7 @@ int type_1_command(int command, int bytes, uch * status)
/* This function resets the adapter card. We'd better not do this too
* often, because it tends to generate `lost interrupts.' */
-void reset_cm260(void)
+static void reset_cm260(void)
{
outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control);
udelay(10); /* 3.3 mu sec minimum */
@@ -572,7 +566,7 @@ void reset_cm260(void)
}
/* fsm: frame-sec-min from linear address; one of many */
-void fsm(int lba, uch * fsm)
+static void fsm(int lba, uch * fsm)
{
fsm[0] = lba % 75;
lba /= 75;
@@ -581,17 +575,17 @@ void fsm(int lba, uch * fsm)
fsm[2] = lba / 60;
}
-inline int fsm2lba(uch * fsm)
+static inline int fsm2lba(uch * fsm)
{
return fsm[0] + 75 * (fsm[1] - 2 + 60 * fsm[2]);
}
-inline int f_s_m2lba(uch f, uch s, uch m)
+static inline int f_s_m2lba(uch f, uch s, uch m)
{
return f + 75 * (s - 2 + 60 * m);
}
-int start_read(int start)
+static int start_read(int start)
{
uch read_sector[4] = { c_read_data, };
int i, e;
@@ -613,7 +607,7 @@ int start_read(int start)
return 0;
}
-int stop_read(void)
+static int stop_read(void)
{
int e;
type_0_command(c_stop, 0);
@@ -630,7 +624,7 @@ int stop_read(void)
routine takes care of this. Set a flag `background' in the cd
struct to indicate the process. */
-int read_background(int start, int reading)
+static int read_background(int start, int reading)
{
if (cd->background)
return -1; /* can't do twice */
@@ -658,7 +652,7 @@ void transport_data(int port, ush * dest, int count)
#define MAX_TRIES 100
-int read_sector(int start)
+static int read_sector(int start)
{
int tries = 0;
if (cd->background) {
@@ -753,7 +747,7 @@ static DECLARE_TASKLET(cm206_tasklet, cm206_tasklet_func, 0);
/* This command clears the dsb_possible_media_change flag, so we must
* retain it.
*/
-void get_drive_status(void)
+static void get_drive_status(void)
{
uch status[2];
type_1_command(c_drive_status, 2, status); /* this might be done faster */
@@ -764,7 +758,7 @@ void get_drive_status(void)
dsb_drive_not_ready | dsb_tray_not_closed));
}
-void get_disc_status(void)
+static void get_disc_status(void)
{
if (type_1_command(c_disc_status, 7, cd->disc_status)) {
debug(("get_disc_status: error\n"));
@@ -801,7 +795,7 @@ static void cm206_release(struct cdrom_device_info *cdi)
/* Empty buffer empties $sectors$ sectors of the adapter card buffer,
* and then reads a sector in kernel memory. */
-void empty_buffer(int sectors)
+static void empty_buffer(int sectors)
{
while (sectors >= 0) {
transport_data(r_fifo_output_buffer,
@@ -819,7 +813,7 @@ void empty_buffer(int sectors)
/* try_adapter. This function determines if the requested sector is
in adapter memory, or will appear there soon. Returns 0 upon
success */
-int try_adapter(int sector)
+static int try_adapter(int sector)
{
if (cd->adapter_first <= sector && sector < cd->adapter_last) {
/* sector is in adapter memory */
@@ -910,7 +904,7 @@ static void do_cm206_request(request_queue_t * q)
*/
/* seek seeks to address lba. It does wait to arrive there. */
-void seek(int lba)
+static void seek(int lba)
{
int i;
uch seek_command[4] = { c_seek, };
@@ -926,7 +920,7 @@ uch bcdbin(unsigned char bcd)
return (bcd >> 4) * 10 + (bcd & 0xf);
}
-inline uch normalize_track(uch track)
+static inline uch normalize_track(uch track)
{
if (track < 1)
return 1;
@@ -939,7 +933,7 @@ inline uch normalize_track(uch track)
* tracks seen in the process. Input $track$ must be between 1 and
* #-of-tracks+1. Note that the start of the disc must be in toc[1].fsm.
*/
-int get_toc_lba(uch track)
+static int get_toc_lba(uch track)
{
int max = 74 * 60 * 75 - 150, min = fsm2lba(cd->toc[1].fsm);
int i, lba, l, old_lba = 0;
@@ -991,7 +985,7 @@ int get_toc_lba(uch track)
return lba;
}
-void update_toc_entry(uch track)
+static void update_toc_entry(uch track)
{
track = normalize_track(track);
if (!cd->toc[track].track)
@@ -999,7 +993,7 @@ void update_toc_entry(uch track)
}
/* return 0 upon success */
-int read_toc_header(struct cdrom_tochdr *hp)
+static int read_toc_header(struct cdrom_tochdr *hp)
{
if (!FIRST_TRACK)
get_disc_status();
@@ -1016,7 +1010,7 @@ int read_toc_header(struct cdrom_tochdr *hp)
return -1;
}
-void play_from_to_msf(struct cdrom_msf *msfp)
+static void play_from_to_msf(struct cdrom_msf *msfp)
{
uch play_command[] = { c_play,
msfp->cdmsf_frame0, msfp->cdmsf_sec0, msfp->cdmsf_min0,
@@ -1032,7 +1026,7 @@ void play_from_to_msf(struct cdrom_msf *msfp)
cd->dsb = wait_dsb();
}
-void play_from_to_track(int from, int to)
+static void play_from_to_track(int from, int to)
{
uch play_command[8] = { c_play, };
int i;
@@ -1059,7 +1053,7 @@ void play_from_to_track(int from, int to)
cd->dsb = wait_dsb();
}
-int get_current_q(struct cdrom_subchnl *qp)
+static int get_current_q(struct cdrom_subchnl *qp)
{
int i;
uch *q = cd->q;
@@ -1093,14 +1087,14 @@ int get_current_q(struct cdrom_subchnl *qp)
return 0;
}
-void invalidate_toc(void)
+static void invalidate_toc(void)
{
memset(cd->toc, 0, sizeof(cd->toc));
memset(cd->disc_status, 0, sizeof(cd->disc_status));
}
/* cdrom.c guarantees that cdte_format == CDROM_MSF */
-void get_toc_entry(struct cdrom_tocentry *ep)
+static void get_toc_entry(struct cdrom_tocentry *ep)
{
uch track = normalize_track(ep->cdte_track);
update_toc_entry(track);
@@ -1117,8 +1111,8 @@ void get_toc_entry(struct cdrom_tocentry *ep)
* upon success. Memory checking has been done by cdrom_ioctl(), the
* calling function, as well as LBA/MSF sanitization.
*/
-int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
- void *arg)
+static int cm206_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
+ void *arg)
{
switch (cmd) {
case CDROMREADTOCHDR:
@@ -1189,7 +1183,7 @@ static int cm206_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
}
}
-int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
+static int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
{
if (cd != NULL) {
int r;
@@ -1204,16 +1198,9 @@ int cm206_media_changed(struct cdrom_device_info *cdi, int disc_nr)
/* The new generic cdrom support. Routines should be concise, most of
the logic should be in cdrom.c */
-/* returns number of times device is in use */
-int cm206_open_files(struct cdrom_device_info *cdi)
-{
- if (cd)
- return cd->openfiles;
- return -1;
-}
/* controls tray movement */
-int cm206_tray_move(struct cdrom_device_info *cdi, int position)
+static int cm206_tray_move(struct cdrom_device_info *cdi, int position)
{
if (position) { /* 1: eject */
type_0_command(c_open_tray, 1);
@@ -1224,7 +1211,7 @@ int cm206_tray_move(struct cdrom_device_info *cdi, int position)
}
/* gives current state of the drive */
-int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
+static int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
{
get_drive_status();
if (cd->dsb & dsb_tray_not_closed)
@@ -1237,7 +1224,7 @@ int cm206_drive_status(struct cdrom_device_info *cdi, int slot_nr)
}
/* locks or unlocks door lock==1: lock; return 0 upon success */
-int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
+static int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
{
uch command = (lock) ? c_lock_tray : c_unlock_tray;
type_0_command(command, 1); /* wait and get dsb */
@@ -1248,8 +1235,8 @@ int cm206_lock_door(struct cdrom_device_info *cdi, int lock)
/* Although a session start should be in LBA format, we return it in
MSF format because it is slightly easier, and the new generic ioctl
will take care of the necessary conversion. */
-int cm206_get_last_session(struct cdrom_device_info *cdi,
- struct cdrom_multisession *mssp)
+static int cm206_get_last_session(struct cdrom_device_info *cdi,
+ struct cdrom_multisession *mssp)
{
if (!FIRST_TRACK)
get_disc_status();
@@ -1268,7 +1255,7 @@ int cm206_get_last_session(struct cdrom_device_info *cdi,
return 0;
}
-int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+static int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
{
uch upc[10];
char *ret = mcn->medium_catalog_number;
@@ -1287,7 +1274,7 @@ int cm206_get_upc(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
return 0;
}
-int cm206_reset(struct cdrom_device_info *cdi)
+static int cm206_reset(struct cdrom_device_info *cdi)
{
stop_read();
reset_cm260();
@@ -1300,7 +1287,7 @@ int cm206_reset(struct cdrom_device_info *cdi)
return 0;
}
-int cm206_select_speed(struct cdrom_device_info *cdi, int speed)
+static int cm206_select_speed(struct cdrom_device_info *cdi, int speed)
{
int r;
switch (speed) {
@@ -1392,7 +1379,7 @@ static struct gendisk *cm206_gendisk;
request_region, 15 bits of one port and 6 of another make things
likely enough to accept the region on the first hit...
*/
-int __init probe_base_port(int base)
+static int __init probe_base_port(int base)
{
int b = 0x300, e = 0x370; /* this is the range of start addresses */
volatile int fool, i;
@@ -1416,7 +1403,7 @@ int __init probe_base_port(int base)
#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)
/* Probe for irq# nr. If nr==0, probe for all possible irq's. */
-int __init probe_irq(int nr)
+static int __init probe_irq(int nr)
{
int irqs, irq;
outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */
@@ -1558,7 +1545,7 @@ static void __init parse_options(void)
}
}
-int __cm206_init(void)
+static int __cm206_init(void)
{
parse_options();
#if !defined(AUTO_PROBE_MODULE)
@@ -1567,7 +1554,7 @@ int __cm206_init(void)
return cm206_init();
}
-void __exit cm206_exit(void)
+static void __exit cm206_exit(void)
{
del_gendisk(cm206_gendisk);
put_disk(cm206_gendisk);
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index f4be7bfd6675..9f22e8f1f6c0 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1605,8 +1605,7 @@ out7:
put_disk(cdu_disk);
out6:
for (i = 0; i < sony_buffer_sectors; i++)
- if (sony_buffer[i])
- kfree(sony_buffer[i]);
+ kfree(sony_buffer[i]);
out5:
kfree(sony_buffer);
out4:
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 7ccf871d3c9d..43d0cb19ef6a 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -940,8 +940,8 @@ config RAW_DRIVER
Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O.
See the raw(8) manpage for more details.
- The raw driver is deprecated and may be removed from 2.7
- kernels. Applications should simply open the device (eg /dev/hda1)
+ The raw driver is deprecated and will be removed soon.
+ Applications should simply open the device (eg /dev/hda1)
with the O_DIRECT flag.
config HPET
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 1aff819f3832..08f69287ea36 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -40,7 +40,7 @@ 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 hvsi.o
+obj-$(CONFIG_HVC_CONSOLE) += hvc_console.o hvc_vio.o hvsi.o
obj-$(CONFIG_RAW_DRIVER) += raw.o
obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
obj-$(CONFIG_MMTIMER) += mmtimer.o
diff --git a/drivers/char/agp/amd64-agp.c b/drivers/char/agp/amd64-agp.c
index 1407945a5892..59f589d733f9 100644
--- a/drivers/char/agp/amd64-agp.c
+++ b/drivers/char/agp/amd64-agp.c
@@ -686,6 +686,15 @@ static struct pci_device_id agp_amd64_pci_table[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
},
+ /* SIS 760 */
+ {
+ .class = (PCI_CLASS_BRIDGE_HOST << 8),
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_SI,
+ .device = PCI_DEVICE_ID_SI_760,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ },
{ }
};
diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c
index 777bc499bbbd..2a36561eec68 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1973,10 +1973,6 @@ static _INLINE_ void show_serial_version(void)
}
-int register_serial(struct serial_struct *req);
-void unregister_serial(int line);
-
-
static struct tty_operations serial_ops = {
.open = rs_open,
.close = rs_close,
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 6bf2e27dc23a..11f9ee581124 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -599,7 +599,7 @@ static ssize_t ac_read (struct file *filp, char __user *buf, size_t count, loff_
#ifdef DEBUG
if (loopcount++ > 2) {
- printk("Looping in ac_read. loopcount %d\n", loopcount);
+ printk(KERN_DEBUG "Looping in ac_read. loopcount %d\n", loopcount);
}
#endif
}
diff --git a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
index d9a029934678..123417e43040 100644
--- a/drivers/char/drm/Kconfig
+++ b/drivers/char/drm/Kconfig
@@ -6,7 +6,7 @@
#
config DRM
tristate "Direct Rendering Manager (XFree86 4.1.0 and higher DRI support)"
- depends on AGP || AGP=n
+ depends on (AGP || AGP=n) && PCI
help
Kernel-level support for the Direct Rendering Infrastructure (DRI)
introduced in XFree86 4.0. If you say Y here, you need to select
@@ -96,3 +96,10 @@ config DRM_SIS
chipset. If M is selected the module will be called sis. AGP
support is required for this driver to work.
+config DRM_VIA
+ tristate "Via unichrome video cards"
+ depends on DRM
+ help
+ Choose this option if you have a Via unichrome or compatible video
+ chipset. If M is selected the module will be called via.
+
diff --git a/drivers/char/drm/Makefile b/drivers/char/drm/Makefile
index 23ab26321e9a..ddd941045b1f 100644
--- a/drivers/char/drm/Makefile
+++ b/drivers/char/drm/Makefile
@@ -18,6 +18,15 @@ 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
+via-objs := via_irq.o via_drv.o via_ds.o via_map.o via_mm.o via_dma.o via_verifier.o via_video.o
+
+ifeq ($(CONFIG_COMPAT),y)
+drm-objs += drm_ioc32.o
+radeon-objs += radeon_ioc32.o
+mga-objs += mga_ioc32.o
+r128-objs += r128_ioc32.o
+i915-objs += i915_ioc32.o
+endif
obj-$(CONFIG_DRM) += drm.o
obj-$(CONFIG_DRM_GAMMA) += gamma.o
@@ -30,4 +39,5 @@ obj-$(CONFIG_DRM_I830) += i830.o
obj-$(CONFIG_DRM_I915) += i915.o
obj-$(CONFIG_DRM_FFB) += ffb.o
obj-$(CONFIG_DRM_SIS) += sis.o
+obj-$(CONFIG_DRM_VIA) +=via.o
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index fdca1876ecd5..0aec5ef481b8 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -52,7 +52,7 @@
# define ATI_MAX_PCIGART_PAGES 8192 /**< 32 MB aperture, 4K pages */
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
-unsigned long drm_ati_alloc_pcigart_table( void )
+static unsigned long drm_ati_alloc_pcigart_table( void )
{
unsigned long address;
struct page *page;
diff --git a/drivers/char/drm/drm.h b/drivers/char/drm/drm.h
index 587305282ea8..e8371dd87fbc 100644
--- a/drivers/char/drm/drm.h
+++ b/drivers/char/drm/drm.h
@@ -38,7 +38,9 @@
#define _DRM_H_
#if defined(__linux__)
+#if defined(__KERNEL__)
#include <linux/config.h>
+#endif
#include <asm/ioctl.h> /* For _IO* macros */
#define DRM_IOCTL_NR(n) _IOC_NR(n)
#define DRM_IOC_VOID _IOC_NONE
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index 21f4c54e1a8d..5df09cc8c6db 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -316,6 +316,9 @@ do { \
typedef int drm_ioctl_t( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
+typedef int drm_ioctl_compat_t(struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
typedef struct drm_ioctl_desc {
drm_ioctl_t *func;
int auth_needed;
@@ -771,37 +774,28 @@ extern int drm_cpu_valid( void );
/* Driver support (drm_drv.h) */
extern int drm_init(struct drm_driver *driver);
extern void drm_exit(struct drm_driver *driver);
-extern int drm_version(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg);
extern int drm_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
+extern long drm_compat_ioctl(struct file *filp,
+ unsigned int cmd, unsigned long arg);
extern int drm_takedown(drm_device_t * dev);
/* Device support (drm_fops.h) */
extern int drm_open(struct inode *inode, struct file *filp);
extern int drm_stub_open(struct inode *inode, struct file *filp);
-extern int drm_open_helper(struct inode *inode, struct file *filp,
- drm_device_t *dev);
extern int drm_flush(struct file *filp);
extern int drm_fasync(int fd, struct file *filp, int on);
extern int drm_release(struct inode *inode, struct file *filp);
/* Mapping support (drm_vm.h) */
-extern void drm_vm_open(struct vm_area_struct *vma);
-extern void drm_vm_close(struct vm_area_struct *vma);
-extern void drm_vm_shm_close(struct vm_area_struct *vma);
-extern int drm_mmap_dma(struct file *filp,
- struct vm_area_struct *vma);
extern int drm_mmap(struct file *filp, struct vm_area_struct *vma);
extern unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait);
-extern ssize_t drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off);
/* Memory management support (drm_memory.h) */
#include "drm_memory.h"
extern void drm_mem_init(void);
extern int drm_mem_info(char *buf, char **start, off_t offset,
int request, int *eof, void *data);
-extern void *drm_calloc(size_t nmemb, size_t size, int area);
extern void *drm_realloc(void *oldpt, size_t oldsize, size_t size,
int area);
extern unsigned long drm_alloc_pages(int order, int area);
@@ -849,9 +843,6 @@ extern int drm_newctx( struct inode *inode, struct file *filp,
extern int drm_rmctx( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
-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);
-
extern int drm_ctxbitmap_init( drm_device_t *dev );
extern void drm_ctxbitmap_cleanup( drm_device_t *dev );
extern void drm_ctxbitmap_free( drm_device_t *dev, int ctx_handle );
@@ -869,9 +860,6 @@ extern int drm_rmdraw(struct inode *inode, struct file *filp,
/* Authentication IOCTL support (drm_auth.h) */
-extern int drm_add_magic(drm_device_t *dev, drm_file_t *priv,
- drm_magic_t magic);
-extern int drm_remove_magic(drm_device_t *dev, drm_magic_t magic);
extern int drm_getmagic(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_authmagic(struct inode *inode, struct file *filp,
@@ -888,13 +876,9 @@ extern int drm_unlock(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg);
extern int drm_lock_take(__volatile__ unsigned int *lock,
unsigned int context);
-extern int drm_lock_transfer(drm_device_t *dev,
- __volatile__ unsigned int *lock,
- unsigned int context);
extern int drm_lock_free(drm_device_t *dev,
__volatile__ unsigned int *lock,
unsigned int context);
-extern int drm_notifier(void *priv);
/* Buffer management support (drm_bufs.h) */
extern int drm_order( unsigned long size );
@@ -922,7 +906,6 @@ extern void drm_core_reclaim_buffers(drm_device_t *dev, struct file *filp);
/* IRQ support (drm_irq.h) */
extern int drm_control( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
-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 );
@@ -962,7 +945,6 @@ extern int drm_agp_unbind_memory(DRM_AGP_MEM *handle);
extern int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
struct drm_driver *driver);
extern int drm_put_dev(drm_device_t * dev);
-extern int drm_get_head(drm_device_t * dev, drm_head_t *head);
extern int drm_put_head(drm_head_t * head);
extern unsigned int drm_debug;
extern unsigned int drm_cards_limit;
@@ -1059,9 +1041,16 @@ static __inline__ void drm_free(void *pt, size_t size, int area)
{
kfree(pt);
}
+
+/** Wrapper around kcalloc() */
+static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area)
+{
+ return kcalloc(nmemb, size, GFP_KERNEL);
+}
#else
extern void *drm_alloc(size_t size, int area);
extern void drm_free(void *pt, size_t size, int area);
+extern void *drm_calloc(size_t nmemb, size_t size, int area);
#endif
/*@}*/
diff --git a/drivers/char/drm/drm_auth.c b/drivers/char/drm/drm_auth.c
index b428761c4e91..dd140bca8f71 100644
--- a/drivers/char/drm/drm_auth.c
+++ b/drivers/char/drm/drm_auth.c
@@ -87,7 +87,7 @@ static drm_file_t *drm_find_file(drm_device_t *dev, drm_magic_t magic)
* associated the magic number hash key in drm_device::magiclist, while holding
* the drm_device::struct_sem lock.
*/
-int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
+static int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
{
int hash;
drm_magic_entry_t *entry;
@@ -124,7 +124,7 @@ int drm_add_magic(drm_device_t *dev, drm_file_t *priv, drm_magic_t magic)
* Searches and unlinks the entry in drm_device::magiclist with the magic
* number hash key, while holding the drm_device::struct_sem lock.
*/
-int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
+static int drm_remove_magic(drm_device_t *dev, drm_magic_t magic)
{
drm_magic_entry_t *prev = NULL;
drm_magic_entry_t *pt;
diff --git a/drivers/char/drm/drm_bufs.c b/drivers/char/drm/drm_bufs.c
index 4113bcba67fe..4c6191d231b8 100644
--- a/drivers/char/drm/drm_bufs.c
+++ b/drivers/char/drm/drm_bufs.c
@@ -60,6 +60,15 @@ int drm_order( unsigned long size )
}
EXPORT_SYMBOL(drm_order);
+#ifdef CONFIG_COMPAT
+/*
+ * Used to allocate 32-bit handles for _DRM_SHM regions
+ * The 0x10000000 value is chosen to be out of the way of
+ * FB/register and GART physical addresses.
+ */
+static unsigned int map32_handle = 0x10000000;
+#endif
+
/**
* Ioctl to specify a range of memory that is available for mapping by a non-root process.
*
@@ -187,16 +196,18 @@ int drm_addmap( struct inode *inode, struct file *filp,
down(&dev->struct_sem);
list_add(&list->head, &dev->maplist->head);
+#ifdef CONFIG_COMPAT
+ /* Assign a 32-bit handle for _DRM_SHM mappings */
+ /* We do it here so that dev->struct_sem protects the increment */
+ if (map->type == _DRM_SHM)
+ map->offset = map32_handle += PAGE_SIZE;
+#endif
up(&dev->struct_sem);
if ( copy_to_user( argp, map, sizeof(*map) ) )
return -EFAULT;
- if ( map->type != _DRM_SHM ) {
- if ( copy_to_user( &argp->handle,
- &map->offset,
- sizeof(map->offset) ) )
- return -EFAULT;
- }
+ if (copy_to_user(&argp->handle, &map->offset, sizeof(map->offset)))
+ return -EFAULT;
return 0;
}
@@ -240,7 +251,7 @@ int drm_rmmap(struct inode *inode, struct file *filp,
r_list = list_entry(list, drm_map_list_t, head);
if(r_list->map &&
- r_list->map->handle == request.handle &&
+ r_list->map->offset == (unsigned long) request.handle &&
r_list->map->flags & _DRM_REMOVABLE) break;
}
@@ -345,8 +356,8 @@ static void drm_cleanup_buf_error(drm_device_t *dev, drm_buf_entry_t *entry)
* reallocates the buffer list of the same size order to accommodate the new
* buffers.
*/
-int drm_addbufs_agp( struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg )
+static int drm_addbufs_agp( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
@@ -510,8 +521,8 @@ int drm_addbufs_agp( struct inode *inode, struct file *filp,
}
#endif /* __OS_HAS_AGP */
-int drm_addbufs_pci( struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg )
+static int drm_addbufs_pci( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
@@ -740,8 +751,8 @@ int drm_addbufs_pci( struct inode *inode, struct file *filp,
}
-int drm_addbufs_sg( struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg )
+static int drm_addbufs_sg( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
diff --git a/drivers/char/drm/drm_context.c b/drivers/char/drm/drm_context.c
index f15c86c57875..a7cfabd1ca2e 100644
--- a/drivers/char/drm/drm_context.c
+++ b/drivers/char/drm/drm_context.c
@@ -84,7 +84,7 @@ failed:
* drm_device::context_sareas to accommodate the new entry while holding the
* drm_device::struct_sem lock.
*/
-int drm_ctxbitmap_next( drm_device_t *dev )
+static int drm_ctxbitmap_next( drm_device_t *dev )
{
int bit;
@@ -225,7 +225,7 @@ int drm_getsareactx(struct inode *inode, struct file *filp,
map = dev->context_sareas[request.ctx_id];
up(&dev->struct_sem);
- request.handle = map->handle;
+ request.handle = (void *) map->offset;
if (copy_to_user(argp, &request, sizeof(request)))
return -EFAULT;
return 0;
@@ -261,8 +261,8 @@ int drm_setsareactx(struct inode *inode, struct file *filp,
down(&dev->struct_sem);
list_for_each(list, &dev->maplist->head) {
r_list = list_entry(list, drm_map_list_t, head);
- if(r_list->map &&
- r_list->map->handle == request.handle)
+ if (r_list->map
+ && r_list->map->offset == (unsigned long) request.handle)
goto found;
}
bad:
@@ -326,7 +326,7 @@ int drm_context_switch( drm_device_t *dev, int old, int new )
* hardware lock is held, clears the drm_device::context_flag and wakes up
* drm_device::context_wait.
*/
-int drm_context_switch_complete( drm_device_t *dev, int new )
+static int drm_context_switch_complete( drm_device_t *dev, int new )
{
dev->last_context = new; /* PRE/POST: This is the _only_ writer. */
dev->last_switch = jiffies;
diff --git a/drivers/char/drm/drm_drv.c b/drivers/char/drm/drm_drv.c
index 1e37ed0c6b8d..3333c250c4d9 100644
--- a/drivers/char/drm/drm_drv.c
+++ b/drivers/char/drm/drm_drv.c
@@ -51,8 +51,11 @@
#include "drmP.h"
#include "drm_core.h"
+static int drm_version(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
/** Ioctl table */
-drm_ioctl_desc_t drm_ioctls[] = {
+static 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 },
@@ -447,8 +450,8 @@ module_exit( drm_core_exit );
*
* Fills in the version information in \p arg.
*/
-int drm_version( struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg )
+static int drm_version( struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg )
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 906794247aeb..10e64fde8d78 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -37,6 +37,8 @@
#include "drmP.h"
#include <linux/poll.h>
+static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev);
+
static int drm_setup( drm_device_t *dev )
{
int i;
@@ -251,7 +253,7 @@ int drm_release( struct inode *inode, struct file *filp )
}
}
- if (drm_core_check_feature(dev, DRIVER_HAVE_DMA))
+ if (drm_core_check_feature(dev, DRIVER_HAVE_DMA) && !dev->driver->release)
{
dev->driver->reclaim_buffers(dev, filp);
}
@@ -259,7 +261,7 @@ int drm_release( struct inode *inode, struct file *filp )
drm_fasync( -1, filp, 0 );
down( &dev->ctxlist_sem );
- if ( !list_empty( &dev->ctxlist->head ) ) {
+ if ( dev->ctxlist && (!list_empty(&dev->ctxlist->head))) {
drm_ctx_list_t *pos, *n;
list_for_each_entry_safe( pos, n, &dev->ctxlist->head, head ) {
@@ -341,7 +343,7 @@ EXPORT_SYMBOL(drm_release);
* Creates and initializes a drm_file structure for the file private data in \p
* filp and add it into the double linked list in \p dev.
*/
-int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
+static int drm_open_helper(struct inode *inode, struct file *filp, drm_device_t *dev)
{
int minor = iminor(inode);
drm_file_t *priv;
@@ -443,9 +445,3 @@ unsigned int drm_poll(struct file *filp, struct poll_table_struct *wait)
}
EXPORT_SYMBOL(drm_poll);
-
-/** No-op. */
-ssize_t drm_read(struct file *filp, char __user *buf, size_t count, loff_t *off)
-{
- return 0;
-}
diff --git a/drivers/char/drm/drm_ioc32.c b/drivers/char/drm/drm_ioc32.c
new file mode 100644
index 000000000000..8087a9636399
--- /dev/null
+++ b/drivers/char/drm/drm_ioc32.c
@@ -0,0 +1,1069 @@
+/**
+ * \file drm_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 2005.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm_core.h"
+
+#define DRM_IOCTL_VERSION32 DRM_IOWR(0x00, drm_version32_t)
+#define DRM_IOCTL_GET_UNIQUE32 DRM_IOWR(0x01, drm_unique32_t)
+#define DRM_IOCTL_GET_MAP32 DRM_IOWR(0x04, drm_map32_t)
+#define DRM_IOCTL_GET_CLIENT32 DRM_IOWR(0x05, drm_client32_t)
+#define DRM_IOCTL_GET_STATS32 DRM_IOR( 0x06, drm_stats32_t)
+
+#define DRM_IOCTL_SET_UNIQUE32 DRM_IOW( 0x10, drm_unique32_t)
+#define DRM_IOCTL_ADD_MAP32 DRM_IOWR(0x15, drm_map32_t)
+#define DRM_IOCTL_ADD_BUFS32 DRM_IOWR(0x16, drm_buf_desc32_t)
+#define DRM_IOCTL_MARK_BUFS32 DRM_IOW( 0x17, drm_buf_desc32_t)
+#define DRM_IOCTL_INFO_BUFS32 DRM_IOWR(0x18, drm_buf_info32_t)
+#define DRM_IOCTL_MAP_BUFS32 DRM_IOWR(0x19, drm_buf_map32_t)
+#define DRM_IOCTL_FREE_BUFS32 DRM_IOW( 0x1a, drm_buf_free32_t)
+
+#define DRM_IOCTL_RM_MAP32 DRM_IOW( 0x1b, drm_map32_t)
+
+#define DRM_IOCTL_SET_SAREA_CTX32 DRM_IOW( 0x1c, drm_ctx_priv_map32_t)
+#define DRM_IOCTL_GET_SAREA_CTX32 DRM_IOWR(0x1d, drm_ctx_priv_map32_t)
+
+#define DRM_IOCTL_RES_CTX32 DRM_IOWR(0x26, drm_ctx_res32_t)
+#define DRM_IOCTL_DMA32 DRM_IOWR(0x29, drm_dma32_t)
+
+#define DRM_IOCTL_AGP_ENABLE32 DRM_IOW( 0x32, drm_agp_mode32_t)
+#define DRM_IOCTL_AGP_INFO32 DRM_IOR( 0x33, drm_agp_info32_t)
+#define DRM_IOCTL_AGP_ALLOC32 DRM_IOWR(0x34, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_FREE32 DRM_IOW( 0x35, drm_agp_buffer32_t)
+#define DRM_IOCTL_AGP_BIND32 DRM_IOW( 0x36, drm_agp_binding32_t)
+#define DRM_IOCTL_AGP_UNBIND32 DRM_IOW( 0x37, drm_agp_binding32_t)
+
+#define DRM_IOCTL_SG_ALLOC32 DRM_IOW( 0x38, drm_scatter_gather32_t)
+#define DRM_IOCTL_SG_FREE32 DRM_IOW( 0x39, drm_scatter_gather32_t)
+
+#define DRM_IOCTL_WAIT_VBLANK32 DRM_IOWR(0x3a, drm_wait_vblank32_t)
+
+typedef struct drm_version_32 {
+ int version_major; /**< Major version */
+ int version_minor; /**< Minor version */
+ int version_patchlevel;/**< Patch level */
+ u32 name_len; /**< Length of name buffer */
+ u32 name; /**< Name of driver */
+ u32 date_len; /**< Length of date buffer */
+ u32 date; /**< User-space buffer to hold date */
+ u32 desc_len; /**< Length of desc buffer */
+ u32 desc; /**< User-space buffer to hold desc */
+} drm_version32_t;
+
+static int compat_drm_version(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_version32_t v32;
+ drm_version_t __user *version;
+ int err;
+
+ if (copy_from_user(&v32, (void __user *) arg, sizeof(v32)))
+ return -EFAULT;
+
+ version = compat_alloc_user_space(sizeof(*version));
+ if (!access_ok(VERIFY_WRITE, version, sizeof(*version)))
+ return -EFAULT;
+ if (__put_user(v32.name_len, &version->name_len)
+ || __put_user((void __user *)(unsigned long)v32.name,
+ &version->name)
+ || __put_user(v32.date_len, &version->date_len)
+ || __put_user((void __user *)(unsigned long)v32.date,
+ &version->date)
+ || __put_user(v32.desc_len, &version->desc_len)
+ || __put_user((void __user *)(unsigned long)v32.desc,
+ &version->desc))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_VERSION, (unsigned long) version);
+ if (err)
+ return err;
+
+ if (__get_user(v32.version_major, &version->version_major)
+ || __get_user(v32.version_minor, &version->version_minor)
+ || __get_user(v32.version_patchlevel, &version->version_patchlevel)
+ || __get_user(v32.name_len, &version->name_len)
+ || __get_user(v32.date_len, &version->date_len)
+ || __get_user(v32.desc_len, &version->desc_len))
+ return -EFAULT;
+
+ if (copy_to_user((void __user *) arg, &v32, sizeof(v32)))
+ return -EFAULT;
+ return 0;
+}
+
+typedef struct drm_unique32 {
+ u32 unique_len; /**< Length of unique */
+ u32 unique; /**< Unique name for driver instantiation */
+} drm_unique32_t;
+
+static int compat_drm_getunique(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_unique32_t uq32;
+ drm_unique_t __user *u;
+ int err;
+
+ if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
+ return -EFAULT;
+
+ u = compat_alloc_user_space(sizeof(*u));
+ if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+ return -EFAULT;
+ if (__put_user(uq32.unique_len, &u->unique_len)
+ || __put_user((void __user *)(unsigned long) uq32.unique,
+ &u->unique))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_GET_UNIQUE, (unsigned long) u);
+ if (err)
+ return err;
+
+ if (__get_user(uq32.unique_len, &u->unique_len))
+ return -EFAULT;
+ if (copy_to_user((void __user *) arg, &uq32, sizeof(uq32)))
+ return -EFAULT;
+ return 0;
+}
+
+static int compat_drm_setunique(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_unique32_t uq32;
+ drm_unique_t __user *u;
+
+ if (copy_from_user(&uq32, (void __user *) arg, sizeof(uq32)))
+ return -EFAULT;
+
+ u = compat_alloc_user_space(sizeof(*u));
+ if (!access_ok(VERIFY_WRITE, u, sizeof(*u)))
+ return -EFAULT;
+ if (__put_user(uq32.unique_len, &u->unique_len)
+ || __put_user((void __user *)(unsigned long) uq32.unique,
+ &u->unique))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_SET_UNIQUE, (unsigned long) u);
+}
+
+typedef struct drm_map32 {
+ u32 offset; /**< Requested physical address (0 for SAREA)*/
+ u32 size; /**< Requested physical size (bytes) */
+ drm_map_type_t type; /**< Type of memory to map */
+ drm_map_flags_t flags; /**< Flags */
+ u32 handle; /**< User-space: "Handle" to pass to mmap() */
+ int mtrr; /**< MTRR slot used */
+} drm_map32_t;
+
+static int compat_drm_getmap(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_map32_t __user *argp = (void __user *)arg;
+ drm_map32_t m32;
+ drm_map_t __user *map;
+ int idx, err;
+ void *handle;
+
+ if (get_user(idx, &argp->offset))
+ return -EFAULT;
+
+ map = compat_alloc_user_space(sizeof(*map));
+ if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+ return -EFAULT;
+ if (__put_user(idx, &map->offset))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_GET_MAP, (unsigned long) map);
+ if (err)
+ return err;
+
+ if (__get_user(m32.offset, &map->offset)
+ || __get_user(m32.size, &map->size)
+ || __get_user(m32.type, &map->type)
+ || __get_user(m32.flags, &map->flags)
+ || __get_user(handle, &map->handle)
+ || __get_user(m32.mtrr, &map->mtrr))
+ return -EFAULT;
+
+ m32.handle = (unsigned long) handle;
+ if (copy_to_user(argp, &m32, sizeof(m32)))
+ return -EFAULT;
+ return 0;
+
+}
+
+static int compat_drm_addmap(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_map32_t __user *argp = (void __user *)arg;
+ drm_map32_t m32;
+ drm_map_t __user *map;
+ int err;
+ void *handle;
+
+ if (copy_from_user(&m32, argp, sizeof(m32)))
+ return -EFAULT;
+
+ map = compat_alloc_user_space(sizeof(*map));
+ if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+ return -EFAULT;
+ if (__put_user(m32.offset, &map->offset)
+ || __put_user(m32.size, &map->size)
+ || __put_user(m32.type, &map->type)
+ || __put_user(m32.flags, &map->flags))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_ADD_MAP, (unsigned long) map);
+ if (err)
+ return err;
+
+ if (__get_user(m32.offset, &map->offset)
+ || __get_user(m32.mtrr, &map->mtrr)
+ || __get_user(handle, &map->handle))
+ return -EFAULT;
+
+ m32.handle = (unsigned long) handle;
+ if (m32.handle != (unsigned long) handle && printk_ratelimit())
+ printk(KERN_ERR "compat_drm_addmap truncated handle"
+ " %p for type %d offset %x\n",
+ handle, m32.type, m32.offset);
+
+ if (copy_to_user(argp, &m32, sizeof(m32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int compat_drm_rmmap(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_map32_t __user *argp = (void __user *)arg;
+ drm_map_t __user *map;
+ u32 handle;
+
+ if (get_user(handle, &argp->handle))
+ return -EFAULT;
+
+ map = compat_alloc_user_space(sizeof(*map));
+ if (!access_ok(VERIFY_WRITE, map, sizeof(*map)))
+ return -EFAULT;
+ if (__put_user((void *)(unsigned long) handle, &map->handle))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RM_MAP, (unsigned long) map);
+}
+
+typedef struct drm_client32 {
+ int idx; /**< Which client desired? */
+ int auth; /**< Is client authenticated? */
+ u32 pid; /**< Process ID */
+ u32 uid; /**< User ID */
+ u32 magic; /**< Magic */
+ u32 iocs; /**< Ioctl count */
+} drm_client32_t;
+
+static int compat_drm_getclient(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_client32_t c32;
+ drm_client32_t __user *argp = (void __user *)arg;
+ drm_client_t __user *client;
+ int idx, err;
+
+ if (get_user(idx, &argp->idx))
+ return -EFAULT;
+
+ client = compat_alloc_user_space(sizeof(*client));
+ if (!access_ok(VERIFY_WRITE, client, sizeof(*client)))
+ return -EFAULT;
+ if (__put_user(idx, &client->idx))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_GET_CLIENT, (unsigned long) client);
+ if (err)
+ return err;
+
+ if (__get_user(c32.auth, &client->auth)
+ || __get_user(c32.pid, &client->pid)
+ || __get_user(c32.uid, &client->uid)
+ || __get_user(c32.magic, &client->magic)
+ || __get_user(c32.iocs, &client->iocs))
+ return -EFAULT;
+
+ if (copy_to_user(argp, &c32, sizeof(c32)))
+ return -EFAULT;
+ return 0;
+}
+
+typedef struct drm_stats32 {
+ u32 count;
+ struct {
+ u32 value;
+ drm_stat_type_t type;
+ } data[15];
+} drm_stats32_t;
+
+static int compat_drm_getstats(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_stats32_t s32;
+ drm_stats32_t __user *argp = (void __user *)arg;
+ drm_stats_t __user *stats;
+ int i, err;
+
+ stats = compat_alloc_user_space(sizeof(*stats));
+ if (!access_ok(VERIFY_WRITE, stats, sizeof(*stats)))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_GET_STATS, (unsigned long) stats);
+ if (err)
+ return err;
+
+ if (__get_user(s32.count, &stats->count))
+ return -EFAULT;
+ for (i = 0; i < 15; ++i)
+ if (__get_user(s32.data[i].value, &stats->data[i].value)
+ || __get_user(s32.data[i].type, &stats->data[i].type))
+ return -EFAULT;
+
+ if (copy_to_user(argp, &s32, sizeof(s32)))
+ return -EFAULT;
+ return 0;
+}
+
+typedef struct drm_buf_desc32 {
+ int count; /**< Number of buffers of this size */
+ int size; /**< Size in bytes */
+ int low_mark; /**< Low water mark */
+ int high_mark; /**< High water mark */
+ int flags;
+ u32 agp_start; /**< Start address in the AGP aperture */
+} drm_buf_desc32_t;
+
+static int compat_drm_addbufs(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_buf_desc32_t __user *argp = (void __user *)arg;
+ drm_buf_desc_t __user *buf;
+ int err;
+ unsigned long agp_start;
+
+ buf = compat_alloc_user_space(sizeof(*buf));
+ if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf))
+ || !access_ok(VERIFY_WRITE, argp, sizeof(*argp)))
+ return -EFAULT;
+
+ if (__copy_in_user(buf, argp, offsetof(drm_buf_desc32_t, agp_start))
+ || __get_user(agp_start, &argp->agp_start)
+ || __put_user(agp_start, &buf->agp_start))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_ADD_BUFS, (unsigned long) buf);
+ if (err)
+ return err;
+
+ if (__copy_in_user(argp, buf, offsetof(drm_buf_desc32_t, agp_start))
+ || __get_user(agp_start, &buf->agp_start)
+ || __put_user(agp_start, &argp->agp_start))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int compat_drm_markbufs(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_buf_desc32_t b32;
+ drm_buf_desc32_t __user *argp = (void __user *)arg;
+ drm_buf_desc_t __user *buf;
+
+ if (copy_from_user(&b32, argp, sizeof(b32)))
+ return -EFAULT;
+
+ buf = compat_alloc_user_space(sizeof(*buf));
+ if (!access_ok(VERIFY_WRITE, buf, sizeof(*buf)))
+ return -EFAULT;
+
+ if (__put_user(b32.size, &buf->size)
+ || __put_user(b32.low_mark, &buf->low_mark)
+ || __put_user(b32.high_mark, &buf->high_mark))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_MARK_BUFS, (unsigned long) buf);
+}
+
+typedef struct drm_buf_info32 {
+ int count; /**< Entries in list */
+ u32 list;
+} drm_buf_info32_t;
+
+static int compat_drm_infobufs(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_buf_info32_t req32;
+ drm_buf_info32_t __user *argp = (void __user *)arg;
+ drm_buf_desc32_t __user *to;
+ drm_buf_info_t __user *request;
+ drm_buf_desc_t __user *list;
+ size_t nbytes;
+ int i, err;
+ int count, actual;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ count = req32.count;
+ to = (drm_buf_desc32_t __user *)(unsigned long) req32.list;
+ if (count < 0)
+ count = 0;
+ if (count > 0
+ && !access_ok(VERIFY_WRITE, to, count * sizeof(drm_buf_desc32_t)))
+ return -EFAULT;
+
+ nbytes = sizeof(*request) + count * sizeof(drm_buf_desc_t);
+ request = compat_alloc_user_space(nbytes);
+ if (!access_ok(VERIFY_WRITE, request, nbytes))
+ return -EFAULT;
+ list = (drm_buf_desc_t *) (request + 1);
+
+ if (__put_user(count, &request->count)
+ || __put_user(list, &request->list))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_INFO_BUFS, (unsigned long) request);
+ if (err)
+ return err;
+
+ if (__get_user(actual, &request->count))
+ return -EFAULT;
+ if (count >= actual)
+ for (i = 0; i < actual; ++i)
+ if (__copy_in_user(&to[i], &list[i],
+ offsetof(drm_buf_desc_t, flags)))
+ return -EFAULT;
+
+ if (__put_user(actual, &argp->count))
+ return -EFAULT;
+
+ return 0;
+}
+
+typedef struct drm_buf_pub32 {
+ int idx; /**< Index into the master buffer list */
+ int total; /**< Buffer size */
+ int used; /**< Amount of buffer in use (for DMA) */
+ u32 address; /**< Address of buffer */
+} drm_buf_pub32_t;
+
+typedef struct drm_buf_map32 {
+ int count; /**< Length of the buffer list */
+ u32 virtual; /**< Mmap'd area in user-virtual */
+ u32 list; /**< Buffer information */
+} drm_buf_map32_t;
+
+static int compat_drm_mapbufs(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_buf_map32_t __user *argp = (void __user *)arg;
+ drm_buf_map32_t req32;
+ drm_buf_pub32_t __user *list32;
+ drm_buf_map_t __user *request;
+ drm_buf_pub_t __user *list;
+ int i, err;
+ int count, actual;
+ size_t nbytes;
+ void __user *addr;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+ count = req32.count;
+ list32 = (void __user *)(unsigned long)req32.list;
+
+ if (count < 0)
+ return -EINVAL;
+ nbytes = sizeof(*request) + count * sizeof(drm_buf_pub_t);
+ request = compat_alloc_user_space(nbytes);
+ if (!access_ok(VERIFY_WRITE, request, nbytes))
+ return -EFAULT;
+ list = (drm_buf_pub_t *) (request + 1);
+
+ if (__put_user(count, &request->count)
+ || __put_user(list, &request->list))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_MAP_BUFS, (unsigned long) request);
+ if (err)
+ return err;
+
+ if (__get_user(actual, &request->count))
+ return -EFAULT;
+ if (count >= actual)
+ for (i = 0; i < actual; ++i)
+ if (__copy_in_user(&list32[i], &list[i],
+ offsetof(drm_buf_pub_t, address))
+ || __get_user(addr, &list[i].address)
+ || __put_user((unsigned long) addr,
+ &list32[i].address))
+ return -EFAULT;
+
+ if (__put_user(actual, &argp->count)
+ || __get_user(addr, &request->virtual)
+ || __put_user((unsigned long) addr, &argp->virtual))
+ return -EFAULT;
+
+ return 0;
+}
+
+typedef struct drm_buf_free32 {
+ int count;
+ u32 list;
+} drm_buf_free32_t;
+
+static int compat_drm_freebufs(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_buf_free32_t req32;
+ drm_buf_free_t __user *request;
+ drm_buf_free32_t __user *argp = (void __user *)arg;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+ return -EFAULT;
+ if (__put_user(req32.count, &request->count)
+ || __put_user((int __user *)(unsigned long) req32.list,
+ &request->list))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_FREE_BUFS, (unsigned long) request);
+}
+
+typedef struct drm_ctx_priv_map32 {
+ unsigned int ctx_id; /**< Context requesting private mapping */
+ u32 handle; /**< Handle of map */
+} drm_ctx_priv_map32_t;
+
+static int compat_drm_setsareactx(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_priv_map32_t req32;
+ drm_ctx_priv_map_t __user *request;
+ drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+ return -EFAULT;
+ if (__put_user(req32.ctx_id, &request->ctx_id)
+ || __put_user((void *)(unsigned long) req32.handle,
+ &request->handle))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_SET_SAREA_CTX, (unsigned long) request);
+}
+
+static int compat_drm_getsareactx(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_priv_map_t __user *request;
+ drm_ctx_priv_map32_t __user *argp = (void __user *)arg;
+ int err;
+ unsigned int ctx_id;
+ void *handle;
+
+ if (!access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+ || __get_user(ctx_id, &argp->ctx_id))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request)))
+ return -EFAULT;
+ if (__put_user(ctx_id, &request->ctx_id))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_GET_SAREA_CTX, (unsigned long) request);
+ if (err)
+ return err;
+
+ if (__get_user(handle, &request->handle)
+ || __put_user((unsigned long) handle, &argp->handle))
+ return -EFAULT;
+
+ return 0;
+}
+
+typedef struct drm_ctx_res32 {
+ int count;
+ u32 contexts;
+} drm_ctx_res32_t;
+
+static int compat_drm_resctx(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_ctx_res32_t __user *argp = (void __user *)arg;
+ drm_ctx_res32_t res32;
+ drm_ctx_res_t __user *res;
+ int err;
+
+ if (copy_from_user(&res32, argp, sizeof(res32)))
+ return -EFAULT;
+
+ res = compat_alloc_user_space(sizeof(*res));
+ if (!access_ok(VERIFY_WRITE, res, sizeof(*res)))
+ return -EFAULT;
+ if (__put_user(res32.count, &res->count)
+ || __put_user((drm_ctx_t __user *)(unsigned long) res32.contexts,
+ &res->contexts))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RES_CTX, (unsigned long) res);
+ if (err)
+ return err;
+
+ if (__get_user(res32.count, &res->count)
+ || __put_user(res32.count, &argp->count))
+ return -EFAULT;
+
+ return 0;
+}
+
+typedef struct drm_dma32 {
+ int context; /**< Context handle */
+ int send_count; /**< Number of buffers to send */
+ u32 send_indices; /**< List of handles to buffers */
+ u32 send_sizes; /**< Lengths of data to send */
+ drm_dma_flags_t flags; /**< Flags */
+ int request_count; /**< Number of buffers requested */
+ int request_size; /**< Desired size for buffers */
+ u32 request_indices; /**< Buffer information */
+ u32 request_sizes;
+ int granted_count; /**< Number of buffers granted */
+} drm_dma32_t;
+
+static int compat_drm_dma(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_dma32_t d32;
+ drm_dma32_t __user *argp = (void __user *) arg;
+ drm_dma_t __user *d;
+ int err;
+
+ if (copy_from_user(&d32, argp, sizeof(d32)))
+ return -EFAULT;
+
+ d = compat_alloc_user_space(sizeof(*d));
+ if (!access_ok(VERIFY_WRITE, d, sizeof(*d)))
+ return -EFAULT;
+
+ if (__put_user(d32.context, &d->context)
+ || __put_user(d32.send_count, &d->send_count)
+ || __put_user((int __user *)(unsigned long) d32.send_indices,
+ &d->send_indices)
+ || __put_user((int __user *)(unsigned long) d32.send_sizes,
+ &d->send_sizes)
+ || __put_user(d32.flags, &d->flags)
+ || __put_user(d32.request_count, &d->request_count)
+ || __put_user((int __user *)(unsigned long) d32.request_indices,
+ &d->request_indices)
+ || __put_user((int __user *)(unsigned long) d32.request_sizes,
+ &d->request_sizes))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_DMA, (unsigned long) d);
+ if (err)
+ return err;
+
+ if (__get_user(d32.request_size, &d->request_size)
+ || __get_user(d32.granted_count, &d->granted_count)
+ || __put_user(d32.request_size, &argp->request_size)
+ || __put_user(d32.granted_count, &argp->granted_count))
+ return -EFAULT;
+
+ return 0;
+}
+
+#if __OS_HAS_AGP
+typedef struct drm_agp_mode32 {
+ u32 mode; /**< AGP mode */
+} drm_agp_mode32_t;
+
+static int compat_drm_agp_enable(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_mode32_t __user *argp = (void __user *)arg;
+ drm_agp_mode32_t m32;
+ drm_agp_mode_t __user *mode;
+
+ if (get_user(m32.mode, &argp->mode))
+ return -EFAULT;
+
+ mode = compat_alloc_user_space(sizeof(*mode));
+ if (put_user(m32.mode, &mode->mode))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_ENABLE, (unsigned long) mode);
+}
+
+typedef struct drm_agp_info32 {
+ int agp_version_major;
+ int agp_version_minor;
+ u32 mode;
+ u32 aperture_base; /* physical address */
+ u32 aperture_size; /* bytes */
+ u32 memory_allowed; /* bytes */
+ u32 memory_used;
+
+ /* PCI information */
+ unsigned short id_vendor;
+ unsigned short id_device;
+} drm_agp_info32_t;
+
+static int compat_drm_agp_info(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_info32_t __user *argp = (void __user *)arg;
+ drm_agp_info32_t i32;
+ drm_agp_info_t __user *info;
+ int err;
+
+ info = compat_alloc_user_space(sizeof(*info));
+ if (!access_ok(VERIFY_WRITE, info, sizeof(*info)))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_INFO, (unsigned long) info);
+ if (err)
+ return err;
+
+ if (__get_user(i32.agp_version_major, &info->agp_version_major)
+ || __get_user(i32.agp_version_minor, &info->agp_version_minor)
+ || __get_user(i32.mode, &info->mode)
+ || __get_user(i32.aperture_base, &info->aperture_base)
+ || __get_user(i32.aperture_size, &info->aperture_size)
+ || __get_user(i32.memory_allowed, &info->memory_allowed)
+ || __get_user(i32.memory_used, &info->memory_used)
+ || __get_user(i32.id_vendor, &info->id_vendor)
+ || __get_user(i32.id_device, &info->id_device))
+ return -EFAULT;
+
+ if (copy_to_user(argp, &i32, sizeof(i32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+typedef struct drm_agp_buffer32 {
+ u32 size; /**< In bytes -- will round to page boundary */
+ u32 handle; /**< Used for binding / unbinding */
+ u32 type; /**< Type of memory to allocate */
+ u32 physical; /**< Physical used by i810 */
+} drm_agp_buffer32_t;
+
+static int compat_drm_agp_alloc(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_buffer32_t __user *argp = (void __user *)arg;
+ drm_agp_buffer32_t req32;
+ drm_agp_buffer_t __user *request;
+ int err;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.size, &request->size)
+ || __put_user(req32.type, &request->type))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_ALLOC, (unsigned long) request);
+ if (err)
+ return err;
+
+ if (__get_user(req32.handle, &request->handle)
+ || __get_user(req32.physical, &request->physical)
+ || copy_to_user(argp, &req32, sizeof(req32))) {
+ drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_FREE, (unsigned long) request);
+ return -EFAULT;
+ }
+
+ return 0;
+}
+
+static int compat_drm_agp_free(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_buffer32_t __user *argp = (void __user *)arg;
+ drm_agp_buffer_t __user *request;
+ u32 handle;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || get_user(handle, &argp->handle)
+ || __put_user(handle, &request->handle))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_FREE, (unsigned long) request);
+}
+
+typedef struct drm_agp_binding32 {
+ u32 handle; /**< From drm_agp_buffer */
+ u32 offset; /**< In bytes -- will round to page boundary */
+} drm_agp_binding32_t;
+
+static int compat_drm_agp_bind(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_binding32_t __user *argp = (void __user *)arg;
+ drm_agp_binding32_t req32;
+ drm_agp_binding_t __user *request;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.handle, &request->handle)
+ || __put_user(req32.offset, &request->offset))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_BIND, (unsigned long) request);
+}
+
+static int compat_drm_agp_unbind(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_agp_binding32_t __user *argp = (void __user *)arg;
+ drm_agp_binding_t __user *request;
+ u32 handle;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || get_user(handle, &argp->handle)
+ || __put_user(handle, &request->handle))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_AGP_UNBIND, (unsigned long) request);
+}
+#endif /* __OS_HAS_AGP */
+
+typedef struct drm_scatter_gather32 {
+ u32 size; /**< In bytes -- will round to page boundary */
+ u32 handle; /**< Used for mapping / unmapping */
+} drm_scatter_gather32_t;
+
+static int compat_drm_sg_alloc(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_scatter_gather32_t __user *argp = (void __user *)arg;
+ drm_scatter_gather_t __user *request;
+ int err;
+ unsigned long x;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+ || __get_user(x, &argp->size)
+ || __put_user(x, &request->size))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_SG_ALLOC, (unsigned long) request);
+ if (err)
+ return err;
+
+ /* XXX not sure about the handle conversion here... */
+ if (__get_user(x, &request->handle)
+ || __put_user(x >> PAGE_SHIFT, &argp->handle))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int compat_drm_sg_free(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_scatter_gather32_t __user *argp = (void __user *)arg;
+ drm_scatter_gather_t __user *request;
+ unsigned long x;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || !access_ok(VERIFY_WRITE, argp, sizeof(*argp))
+ || __get_user(x, &argp->handle)
+ || __put_user(x << PAGE_SHIFT, &request->handle))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_SG_FREE, (unsigned long) request);
+}
+
+struct drm_wait_vblank_request32 {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ u32 signal;
+};
+
+struct drm_wait_vblank_reply32 {
+ drm_vblank_seq_type_t type;
+ unsigned int sequence;
+ s32 tval_sec;
+ s32 tval_usec;
+};
+
+typedef union drm_wait_vblank32 {
+ struct drm_wait_vblank_request32 request;
+ struct drm_wait_vblank_reply32 reply;
+} drm_wait_vblank32_t;
+
+static int compat_drm_wait_vblank(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_wait_vblank32_t __user *argp = (void __user *)arg;
+ drm_wait_vblank32_t req32;
+ drm_wait_vblank_t __user *request;
+ int err;
+
+ if (copy_from_user(&req32, argp, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.request.type, &request->request.type)
+ || __put_user(req32.request.sequence, &request->request.sequence)
+ || __put_user(req32.request.signal, &request->request.signal))
+ return -EFAULT;
+
+ err = drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_WAIT_VBLANK, (unsigned long) request);
+ if (err)
+ return err;
+
+ if (__get_user(req32.reply.type, &request->reply.type)
+ || __get_user(req32.reply.sequence, &request->reply.sequence)
+ || __get_user(req32.reply.tval_sec, &request->reply.tval_sec)
+ || __get_user(req32.reply.tval_usec, &request->reply.tval_usec))
+ return -EFAULT;
+
+ if (copy_to_user(argp, &req32, sizeof(req32)))
+ return -EFAULT;
+
+ return 0;
+}
+
+drm_ioctl_compat_t *drm_compat_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_IOCTL_VERSION32)] = compat_drm_version,
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_UNIQUE32)] = compat_drm_getunique,
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_MAP32)] = compat_drm_getmap,
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_CLIENT32)] = compat_drm_getclient,
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_STATS32)] = compat_drm_getstats,
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_UNIQUE32)] = compat_drm_setunique,
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_MAP32)] = compat_drm_addmap,
+ [DRM_IOCTL_NR(DRM_IOCTL_ADD_BUFS32)] = compat_drm_addbufs,
+ [DRM_IOCTL_NR(DRM_IOCTL_MARK_BUFS32)] = compat_drm_markbufs,
+ [DRM_IOCTL_NR(DRM_IOCTL_INFO_BUFS32)] = compat_drm_infobufs,
+ [DRM_IOCTL_NR(DRM_IOCTL_MAP_BUFS32)] = compat_drm_mapbufs,
+ [DRM_IOCTL_NR(DRM_IOCTL_FREE_BUFS32)] = compat_drm_freebufs,
+ [DRM_IOCTL_NR(DRM_IOCTL_RM_MAP32)] = compat_drm_rmmap,
+ [DRM_IOCTL_NR(DRM_IOCTL_SET_SAREA_CTX32)] = compat_drm_setsareactx,
+ [DRM_IOCTL_NR(DRM_IOCTL_GET_SAREA_CTX32)] = compat_drm_getsareactx,
+ [DRM_IOCTL_NR(DRM_IOCTL_RES_CTX32)] = compat_drm_resctx,
+ [DRM_IOCTL_NR(DRM_IOCTL_DMA32)] = compat_drm_dma,
+#if __OS_HAS_AGP
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_ENABLE32)] = compat_drm_agp_enable,
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_INFO32)] = compat_drm_agp_info,
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_ALLOC32)] = compat_drm_agp_alloc,
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_FREE32)] = compat_drm_agp_free,
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_BIND32)] = compat_drm_agp_bind,
+ [DRM_IOCTL_NR(DRM_IOCTL_AGP_UNBIND32)] = compat_drm_agp_unbind,
+#endif
+ [DRM_IOCTL_NR(DRM_IOCTL_SG_ALLOC32)] = compat_drm_sg_alloc,
+ [DRM_IOCTL_NR(DRM_IOCTL_SG_FREE32)] = compat_drm_sg_free,
+ [DRM_IOCTL_NR(DRM_IOCTL_WAIT_VBLANK32)] = compat_drm_wait_vblank,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/drm.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long drm_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ drm_ioctl_compat_t *fn;
+ int ret;
+
+ if (nr >= DRM_ARRAY_SIZE(drm_compat_ioctls))
+ return -ENOTTY;
+
+ fn = drm_compat_ioctls[nr];
+
+ lock_kernel(); /* XXX for now */
+ if (fn != NULL)
+ ret = (*fn)(filp, cmd, arg);
+ else
+ ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
+EXPORT_SYMBOL(drm_compat_ioctl);
diff --git a/drivers/char/drm/drm_irq.c b/drivers/char/drm/drm_irq.c
index 2e236ebcf27b..cdd4aecd25e2 100644
--- a/drivers/char/drm/drm_irq.c
+++ b/drivers/char/drm/drm_irq.c
@@ -89,7 +89,7 @@ int drm_irq_by_busid(struct inode *inode, struct file *filp,
* \c drm_driver_irq_preinstall() and \c drm_driver_irq_postinstall() functions
* before and after the installation.
*/
-int drm_irq_install( drm_device_t *dev )
+static int drm_irq_install( drm_device_t *dev )
{
int ret;
unsigned long sh_flags=0;
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index d0d6fc661625..4702d863bcc6 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -35,6 +35,11 @@
#include "drmP.h"
+static int drm_lock_transfer(drm_device_t *dev,
+ __volatile__ unsigned int *lock,
+ unsigned int context);
+static int drm_notifier(void *priv);
+
/**
* Lock ioctl.
*
@@ -225,8 +230,9 @@ int drm_lock_take(__volatile__ unsigned int *lock, unsigned int context)
* Resets the lock file pointer.
* Marks the lock as held by the given context, via the \p cmpxchg instruction.
*/
-int drm_lock_transfer(drm_device_t *dev,
- __volatile__ unsigned int *lock, unsigned int context)
+static int drm_lock_transfer(drm_device_t *dev,
+ __volatile__ unsigned int *lock,
+ unsigned int context)
{
unsigned int old, new, prev;
@@ -282,7 +288,7 @@ int drm_lock_free(drm_device_t *dev,
* \return one if the signal should be delivered normally, or zero if the
* signal should be blocked.
*/
-int drm_notifier(void *priv)
+static int drm_notifier(void *priv)
{
drm_sigdata_t *s = (drm_sigdata_t *)priv;
unsigned int old, new, prev;
diff --git a/drivers/char/drm/drm_memory.c b/drivers/char/drm/drm_memory.c
index 7f53f756c052..ace3d42f4407 100644
--- a/drivers/char/drm/drm_memory.c
+++ b/drivers/char/drm/drm_memory.c
@@ -65,19 +65,6 @@ int drm_mem_info(char *buf, char **start, off_t offset,
return 0;
}
-/** Wrapper around kmalloc() */
-void *drm_calloc(size_t nmemb, size_t size, int area)
-{
- void *addr;
-
- addr = kmalloc(size * nmemb, GFP_KERNEL);
- if (addr != NULL)
- memset((void *)addr, 0, size * nmemb);
-
- return addr;
-}
-EXPORT_SYMBOL(drm_calloc);
-
/** Wrapper around kmalloc() and kfree() */
void *drm_realloc(void *oldpt, size_t oldsize, size_t size, int area)
{
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 11c6950158b3..70ca4fa55c9d 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -223,3 +223,10 @@
{0x8086, 0x2772, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
{0, 0, 0}
+#define viadrv_PCI_IDS \
+ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x3122, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7205, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0x1106, 0x7204, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \
+ {0, 0, 0}
+
diff --git a/drivers/char/drm/drm_proc.c b/drivers/char/drm/drm_proc.c
index 6e06e8c6a516..4774087d2e9e 100644
--- a/drivers/char/drm/drm_proc.c
+++ b/drivers/char/drm/drm_proc.c
@@ -57,7 +57,7 @@ static int drm_vma_info(char *buf, char **start, off_t offset,
/**
* Proc file list.
*/
-struct drm_proc_list {
+static struct drm_proc_list {
const char *name; /**< file name */
int (*f)(char *, char **, off_t, int, int *, void *); /**< proc callback*/
} drm_proc_list[] = {
diff --git a/drivers/char/drm/drm_stub.c b/drivers/char/drm/drm_stub.c
index 8ccbdef7bb3e..48829a1a086a 100644
--- a/drivers/char/drm/drm_stub.c
+++ b/drivers/char/drm/drm_stub.c
@@ -157,52 +157,6 @@ int drm_stub_open(struct inode *inode, struct file *filp)
return err;
}
-
-/**
- * Register.
- *
- * \param pdev - PCI device structure
- * \param ent entry from the PCI ID table with device type flags
- * \return zero on success or a negative number on failure.
- *
- * Attempt to gets inter module "drm" information. If we are first
- * then register the character device and inter module information.
- * Try and register, if we fail to register, backout previous work.
- */
-int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
- struct drm_driver *driver)
-{
- drm_device_t *dev;
- int ret;
-
- DRM_DEBUG("\n");
-
- dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
- if (!dev)
- return -ENOMEM;
-
- pci_enable_device(pdev);
-
- if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
- printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
- goto err_g1;
- }
- if ((ret = drm_get_head(dev, &dev->primary)))
- goto err_g1;
-
- /* postinit is a required function to display the signon banner */
- /* drivers add secondary heads here if needed */
- if ((ret = dev->driver->postinit(dev, ent->driver_data)))
- goto err_g1;
-
- return 0;
-
-err_g1:
- drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
- return ret;
-}
-EXPORT_SYMBOL(drm_get_dev);
-
/**
* Get a secondary minor number.
*
@@ -214,7 +168,7 @@ EXPORT_SYMBOL(drm_get_dev);
* create the proc init entry via proc_init(). This routines assigns
* minor numbers to secondary heads of multi-headed cards
*/
-int drm_get_head(drm_device_t *dev, drm_head_t *head)
+static int drm_get_head(drm_device_t *dev, drm_head_t *head)
{
drm_head_t **heads = drm_heads;
int ret;
@@ -262,6 +216,50 @@ err_g1:
return ret;
}
+/**
+ * Register.
+ *
+ * \param pdev - PCI device structure
+ * \param ent entry from the PCI ID table with device type flags
+ * \return zero on success or a negative number on failure.
+ *
+ * Attempt to gets inter module "drm" information. If we are first
+ * then register the character device and inter module information.
+ * Try and register, if we fail to register, backout previous work.
+ */
+int drm_get_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
+ struct drm_driver *driver)
+{
+ drm_device_t *dev;
+ int ret;
+
+ DRM_DEBUG("\n");
+
+ dev = drm_calloc(1, sizeof(*dev), DRM_MEM_STUB);
+ if (!dev)
+ return -ENOMEM;
+
+ pci_enable_device(pdev);
+
+ if ((ret = drm_fill_in_dev(dev, pdev, ent, driver))) {
+ printk(KERN_ERR "DRM: Fill_in_dev failed.\n");
+ goto err_g1;
+ }
+ if ((ret = drm_get_head(dev, &dev->primary)))
+ goto err_g1;
+
+ /* postinit is a required function to display the signon banner */
+ /* drivers add secondary heads here if needed */
+ if ((ret = dev->driver->postinit(dev, ent->driver_data)))
+ goto err_g1;
+
+ return 0;
+
+err_g1:
+ drm_free(dev, sizeof(*dev), DRM_MEM_STUB);
+ return ret;
+}
+EXPORT_SYMBOL(drm_get_dev);
/**
* Put a device minor number.
diff --git a/drivers/char/drm/drm_vm.c b/drivers/char/drm/drm_vm.c
index fc72f30f312b..621220f3f372 100644
--- a/drivers/char/drm/drm_vm.c
+++ b/drivers/char/drm/drm_vm.c
@@ -38,6 +38,8 @@
#include <linux/efi.h>
#endif
+static void drm_vm_open(struct vm_area_struct *vma);
+static void drm_vm_close(struct vm_area_struct *vma);
/**
* \c nopage method for AGP virtual memory.
@@ -163,7 +165,7 @@ static __inline__ struct page *drm_do_vm_shm_nopage(struct vm_area_struct *vma,
* Deletes map information if we are the last
* person to close a mapping and it's not in the global maplist.
*/
-void drm_vm_shm_close(struct vm_area_struct *vma)
+static void drm_vm_shm_close(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -399,7 +401,7 @@ static struct vm_operations_struct drm_vm_sg_ops = {
* Create a new drm_vma_entry structure as the \p vma private data entry and
* add it to drm_device::vmalist.
*/
-void drm_vm_open(struct vm_area_struct *vma)
+static void drm_vm_open(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -428,7 +430,7 @@ void drm_vm_open(struct vm_area_struct *vma)
* Search the \p vma private data entry in drm_device::vmalist, unlink it, and
* free it.
*/
-void drm_vm_close(struct vm_area_struct *vma)
+static void drm_vm_close(struct vm_area_struct *vma)
{
drm_file_t *priv = vma->vm_file->private_data;
drm_device_t *dev = priv->head->dev;
@@ -463,7 +465,7 @@ void drm_vm_close(struct vm_area_struct *vma)
* Sets the virtual memory area operations structure to vm_dma_ops, the file
* pointer, and calls vm_open().
*/
-int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
+static int drm_mmap_dma(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev;
diff --git a/drivers/char/drm/i810_dma.c b/drivers/char/drm/i810_dma.c
index 24857cc6c23b..18e0b7622893 100644
--- a/drivers/char/drm/i810_dma.c
+++ b/drivers/char/drm/i810_dma.c
@@ -90,16 +90,7 @@ static int i810_freelist_put(drm_device_t *dev, drm_buf_t *buf)
return 0;
}
-static struct file_operations i810_buffer_fops = {
- .open = drm_open,
- .flush = drm_flush,
- .release = drm_release,
- .ioctl = drm_ioctl,
- .mmap = i810_mmap_buffers,
- .fasync = drm_fasync,
-};
-
-int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+static int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev;
@@ -126,6 +117,15 @@ int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
return 0;
}
+static struct file_operations i810_buffer_fops = {
+ .open = drm_open,
+ .flush = drm_flush,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = i810_mmap_buffers,
+ .fasync = drm_fasync,
+};
+
static int i810_map_buffer(drm_buf_t *buf, struct file *filp)
{
drm_file_t *priv = filp->private_data;
@@ -1003,8 +1003,8 @@ void i810_reclaim_buffers(drm_device_t *dev, struct file *filp)
}
}
-int i810_flush_ioctl(struct inode *inode, struct file *filp,
- unsigned int cmd, unsigned long arg)
+static int i810_flush_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev = priv->head->dev;
diff --git a/drivers/char/drm/i810_drv.h b/drivers/char/drm/i810_drv.h
index fa23ca454e57..1b40538d1725 100644
--- a/drivers/char/drm/i810_drv.h
+++ b/drivers/char/drm/i810_drv.h
@@ -115,7 +115,6 @@ typedef struct drm_i810_private {
/* i810_dma.c */
extern void i810_reclaim_buffers(drm_device_t *dev, struct file *filp);
-extern int i810_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
extern int i810_driver_dma_quiescent(drm_device_t *dev);
extern void i810_driver_release(drm_device_t *dev, struct file *filp);
diff --git a/drivers/char/drm/i830_dma.c b/drivers/char/drm/i830_dma.c
index 98adccf8e434..dc7733035864 100644
--- a/drivers/char/drm/i830_dma.c
+++ b/drivers/char/drm/i830_dma.c
@@ -92,16 +92,7 @@ static int i830_freelist_put(drm_device_t *dev, drm_buf_t *buf)
return 0;
}
-static struct file_operations i830_buffer_fops = {
- .open = drm_open,
- .flush = drm_flush,
- .release = drm_release,
- .ioctl = drm_ioctl,
- .mmap = i830_mmap_buffers,
- .fasync = drm_fasync,
-};
-
-int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
+static int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
{
drm_file_t *priv = filp->private_data;
drm_device_t *dev;
@@ -128,6 +119,15 @@ int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma)
return 0;
}
+static struct file_operations i830_buffer_fops = {
+ .open = drm_open,
+ .flush = drm_flush,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = i830_mmap_buffers,
+ .fasync = drm_fasync,
+};
+
static int i830_map_buffer(drm_buf_t *buf, struct file *filp)
{
drm_file_t *priv = filp->private_data;
diff --git a/drivers/char/drm/i830_drv.c b/drivers/char/drm/i830_drv.c
index aa80ad6a5ee0..bc36be76b8b2 100644
--- a/drivers/char/drm/i830_drv.c
+++ b/drivers/char/drm/i830_drv.c
@@ -40,7 +40,7 @@
#include "drm_pciids.h"
-int postinit( struct drm_device *dev, unsigned long flags )
+static int postinit( struct drm_device *dev, unsigned long flags )
{
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
diff --git a/drivers/char/drm/i830_drv.h b/drivers/char/drm/i830_drv.h
index d4b2d093d6ab..df7746131dea 100644
--- a/drivers/char/drm/i830_drv.h
+++ b/drivers/char/drm/i830_drv.h
@@ -123,8 +123,6 @@ typedef struct drm_i830_private {
/* i830_dma.c */
extern void i830_reclaim_buffers(drm_device_t *dev, struct file *filp);
-extern int i830_mmap_buffers(struct file *filp, struct vm_area_struct *vma);
-
/* i830_irq.c */
extern int i830_irq_emit( struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg );
diff --git a/drivers/char/drm/i830_irq.c b/drivers/char/drm/i830_irq.c
index 6d7729ffe2dc..a5923e5d0a77 100644
--- a/drivers/char/drm/i830_irq.c
+++ b/drivers/char/drm/i830_irq.c
@@ -54,8 +54,7 @@ irqreturn_t i830_driver_irq_handler( DRM_IRQ_ARGS )
return IRQ_HANDLED;
}
-
-int i830_emit_irq(drm_device_t *dev)
+static int i830_emit_irq(drm_device_t *dev)
{
drm_i830_private_t *dev_priv = dev->dev_private;
RING_LOCALS;
@@ -73,7 +72,7 @@ int i830_emit_irq(drm_device_t *dev)
}
-int i830_wait_irq(drm_device_t *dev, int irq_nr)
+static int i830_wait_irq(drm_device_t *dev, int irq_nr)
{
drm_i830_private_t *dev_priv =
(drm_i830_private_t *)dev->dev_private;
diff --git a/drivers/char/drm/i915_dma.c b/drivers/char/drm/i915_dma.c
index 7300a09dbd5c..acf9e52a9507 100644
--- a/drivers/char/drm/i915_dma.c
+++ b/drivers/char/drm/i915_dma.c
@@ -1,10 +1,30 @@
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
*/
/**************************************************************************
- *
+ *
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
**************************************************************************/
#include "drmP.h"
@@ -12,23 +32,6 @@
#include "i915_drm.h"
#include "i915_drv.h"
-drm_ioctl_desc_t i915_ioctls[] = {
- [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1},
- [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1},
- [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0},
- [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1},
- [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0}
-};
-
-int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
-
/* 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
@@ -75,7 +78,7 @@ void i915_kernel_lost_context(drm_device_t * dev)
dev_priv->sarea_priv->perf_boxes |= I915_BOX_RING_EMPTY;
}
-int i915_dma_cleanup(drm_device_t * dev)
+static 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
@@ -227,7 +230,7 @@ static int i915_resume(drm_device_t * dev)
return 0;
}
-int i915_dma_init(DRM_IOCTL_ARGS)
+static int i915_dma_init(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv;
@@ -538,7 +541,7 @@ static int i915_quiescent(drm_device_t * dev)
return i915_wait_ring(dev, dev_priv->ring.Size - 8, __FUNCTION__);
}
-int i915_flush_ioctl(DRM_IOCTL_ARGS)
+static int i915_flush_ioctl(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
@@ -547,7 +550,7 @@ int i915_flush_ioctl(DRM_IOCTL_ARGS)
return i915_quiescent(dev);
}
-int i915_batchbuffer(DRM_IOCTL_ARGS)
+static int i915_batchbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -581,7 +584,7 @@ int i915_batchbuffer(DRM_IOCTL_ARGS)
return ret;
}
-int i915_cmdbuffer(DRM_IOCTL_ARGS)
+static int i915_cmdbuffer(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
@@ -617,18 +620,7 @@ int i915_cmdbuffer(DRM_IOCTL_ARGS)
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)
+static int i915_flip_bufs(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
@@ -639,7 +631,7 @@ int i915_flip_bufs(DRM_IOCTL_ARGS)
return i915_dispatch_flip(dev);
}
-int i915_getparam(DRM_IOCTL_ARGS)
+static int i915_getparam(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -674,7 +666,7 @@ int i915_getparam(DRM_IOCTL_ARGS)
return 0;
}
-int i915_setparam(DRM_IOCTL_ARGS)
+static int i915_setparam(DRM_IOCTL_ARGS)
{
DRM_DEVICE;
drm_i915_private_t *dev_priv = dev->dev_private;
@@ -723,3 +715,19 @@ void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp)
}
}
+drm_ioctl_desc_t i915_ioctls[] = {
+ [DRM_IOCTL_NR(DRM_I915_INIT)] = {i915_dma_init, 1, 1},
+ [DRM_IOCTL_NR(DRM_I915_FLUSH)] = {i915_flush_ioctl, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_FLIP)] = {i915_flip_bufs, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_BATCHBUFFER)] = {i915_batchbuffer, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_IRQ_EMIT)] = {i915_irq_emit, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_IRQ_WAIT)] = {i915_irq_wait, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_GETPARAM)] = {i915_getparam, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_SETPARAM)] = {i915_setparam, 1, 1},
+ [DRM_IOCTL_NR(DRM_I915_ALLOC)] = {i915_mem_alloc, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_FREE)] = {i915_mem_free, 1, 0},
+ [DRM_IOCTL_NR(DRM_I915_INIT_HEAP)] = {i915_mem_init_heap, 1, 1},
+ [DRM_IOCTL_NR(DRM_I915_CMDBUFFER)] = {i915_cmdbuffer, 1, 0}
+};
+
+int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/char/drm/i915_drm.h b/drivers/char/drm/i915_drm.h
index 7e55edf45c4f..23e027d29080 100644
--- a/drivers/char/drm/i915_drm.h
+++ b/drivers/char/drm/i915_drm.h
@@ -1,3 +1,30 @@
+/**************************************************************************
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ **************************************************************************/
+
#ifndef _I915_DRM_H_
#define _I915_DRM_H_
diff --git a/drivers/char/drm/i915_drv.c b/drivers/char/drm/i915_drv.c
index 002b7082e21b..1f59d3fc79bc 100644
--- a/drivers/char/drm/i915_drv.c
+++ b/drivers/char/drm/i915_drv.c
@@ -1,11 +1,30 @@
/* i915_drv.c -- i830,i845,i855,i865,i915 driver -*- linux-c -*-
*/
-
/**************************************************************************
- *
+ *
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
**************************************************************************/
#include "drmP.h"
@@ -15,7 +34,7 @@
#include "drm_pciids.h"
-int postinit( struct drm_device *dev, unsigned long flags )
+static int postinit( struct drm_device *dev, unsigned long flags )
{
dev->counters += 4;
dev->types[6] = _DRM_STAT_IRQ;
@@ -78,6 +97,9 @@ static struct drm_driver driver = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = i915_compat_ioctl,
+#endif
},
.pci_driver = {
.name = DRIVER_NAME,
diff --git a/drivers/char/drm/i915_drv.h b/drivers/char/drm/i915_drv.h
index f6ca92a565db..9c37d2367dd5 100644
--- a/drivers/char/drm/i915_drv.h
+++ b/drivers/char/drm/i915_drv.h
@@ -1,10 +1,30 @@
/* i915_drv.h -- Private header for the I915 driver -*- linux-c -*-
*/
/**************************************************************************
- *
+ *
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
**************************************************************************/
#ifndef _I915_DRV_H_
@@ -79,14 +99,6 @@ typedef struct drm_i915_private {
} 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);
extern void i915_driver_pretakedown(drm_device_t *dev);
extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp);
@@ -94,8 +106,6 @@ extern void i915_driver_prerelease(drm_device_t *dev, DRMFILE filp);
/* 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);
@@ -110,6 +120,10 @@ extern void i915_mem_takedown(struct mem_block **heap);
extern void i915_mem_release(drm_device_t * dev,
DRMFILE filp, struct mem_block *heap);
+extern long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
+
#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)
diff --git a/drivers/char/drm/i915_ioc32.c b/drivers/char/drm/i915_ioc32.c
new file mode 100644
index 000000000000..fe009e1b3a3f
--- /dev/null
+++ b/drivers/char/drm/i915_ioc32.c
@@ -0,0 +1,221 @@
+/**
+ * \file i915_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the i915 DRM.
+ *
+ * \author Alan Hourihane <alanh@fairlite.demon.co.uk>
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Alan Hourihane 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "i915_drm.h"
+
+typedef struct _drm_i915_batchbuffer32 {
+ 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? */
+ u32 cliprects; /* pointer to userspace cliprects */
+} drm_i915_batchbuffer32_t;
+
+static int compat_i915_batchbuffer(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_i915_batchbuffer32_t batchbuffer32;
+ drm_i915_batchbuffer_t __user *batchbuffer;
+
+ if (copy_from_user(&batchbuffer32, (void __user *)arg, sizeof(batchbuffer32)))
+ return -EFAULT;
+
+ batchbuffer = compat_alloc_user_space(sizeof(*batchbuffer));
+ if (!access_ok(VERIFY_WRITE, batchbuffer, sizeof(*batchbuffer))
+ || __put_user(batchbuffer32.start, &batchbuffer->start)
+ || __put_user(batchbuffer32.used, &batchbuffer->used)
+ || __put_user(batchbuffer32.DR1, &batchbuffer->DR1)
+ || __put_user(batchbuffer32.DR4, &batchbuffer->DR4)
+ || __put_user(batchbuffer32.num_cliprects, &batchbuffer->num_cliprects)
+ || __put_user((int __user *)(unsigned long)batchbuffer32.cliprects,
+ &batchbuffer->cliprects))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_I915_BATCHBUFFER, (unsigned long) batchbuffer);
+}
+
+typedef struct _drm_i915_cmdbuffer32 {
+ u32 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? */
+ u32 cliprects; /* pointer to userspace cliprects */
+} drm_i915_cmdbuffer32_t;
+
+static int compat_i915_cmdbuffer(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_i915_cmdbuffer32_t cmdbuffer32;
+ drm_i915_cmdbuffer_t __user *cmdbuffer;
+
+ if (copy_from_user(&cmdbuffer32, (void __user *)arg, sizeof(cmdbuffer32)))
+ return -EFAULT;
+
+ cmdbuffer = compat_alloc_user_space(sizeof(*cmdbuffer));
+ if (!access_ok(VERIFY_WRITE, cmdbuffer, sizeof(*cmdbuffer))
+ || __put_user((int __user *)(unsigned long)cmdbuffer32.buf,
+ &cmdbuffer->buf)
+ || __put_user(cmdbuffer32.sz, &cmdbuffer->sz)
+ || __put_user(cmdbuffer32.DR1, &cmdbuffer->DR1)
+ || __put_user(cmdbuffer32.DR4, &cmdbuffer->DR4)
+ || __put_user(cmdbuffer32.num_cliprects, &cmdbuffer->num_cliprects)
+ || __put_user((int __user *)(unsigned long)cmdbuffer32.cliprects,
+ &cmdbuffer->cliprects))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_I915_CMDBUFFER, (unsigned long) cmdbuffer);
+}
+
+typedef struct drm_i915_irq_emit32 {
+ u32 irq_seq;
+} drm_i915_irq_emit32_t;
+
+static int compat_i915_irq_emit(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_i915_irq_emit32_t req32;
+ drm_i915_irq_emit_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user((int __user *)(unsigned long)req32.irq_seq,
+ &request->irq_seq))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_I915_IRQ_EMIT, (unsigned long) request);
+}
+typedef struct drm_i915_getparam32 {
+ int param;
+ u32 value;
+} drm_i915_getparam32_t;
+
+static int compat_i915_getparam(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_i915_getparam32_t req32;
+ drm_i915_getparam_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.param, &request->param)
+ || __put_user((void __user *)(unsigned long)req32.value,
+ &request->value))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_I915_GETPARAM, (unsigned long) request);
+}
+
+typedef struct drm_i915_mem_alloc32 {
+ int region;
+ int alignment;
+ int size;
+ u32 region_offset; /* offset from start of fb or agp */
+} drm_i915_mem_alloc32_t;
+
+static int compat_i915_alloc(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_i915_mem_alloc32_t req32;
+ drm_i915_mem_alloc_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.region, &request->region)
+ || __put_user(req32.alignment, &request->alignment)
+ || __put_user(req32.size, &request->size)
+ || __put_user((void __user *)(unsigned long)req32.region_offset,
+ &request->region_offset))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_I915_ALLOC, (unsigned long) request);
+}
+
+
+drm_ioctl_compat_t *i915_compat_ioctls[] = {
+ [DRM_I915_BATCHBUFFER] = compat_i915_batchbuffer,
+ [DRM_I915_CMDBUFFER] = compat_i915_cmdbuffer,
+ [DRM_I915_GETPARAM] = compat_i915_getparam,
+ [DRM_I915_IRQ_EMIT] = compat_i915_irq_emit,
+ [DRM_I915_ALLOC] = compat_i915_alloc
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long i915_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ drm_ioctl_compat_t *fn = NULL;
+ int ret;
+
+ if (nr < DRM_COMMAND_BASE)
+ return drm_compat_ioctl(filp, cmd, arg);
+
+ if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(i915_compat_ioctls))
+ fn = i915_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+ lock_kernel(); /* XXX for now */
+ if (fn != NULL)
+ ret = (*fn)(filp, cmd, arg);
+ else
+ ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
diff --git a/drivers/char/drm/i915_irq.c b/drivers/char/drm/i915_irq.c
index b0239262a84a..4fa448ee846b 100644
--- a/drivers/char/drm/i915_irq.c
+++ b/drivers/char/drm/i915_irq.c
@@ -1,10 +1,30 @@
/* i915_dma.c -- DMA support for the I915 -*- linux-c -*-
*/
/**************************************************************************
- *
+ *
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
**************************************************************************/
#include "drmP.h"
@@ -36,7 +56,7 @@ irqreturn_t i915_driver_irq_handler(DRM_IRQ_ARGS)
return IRQ_HANDLED;
}
-int i915_emit_irq(drm_device_t * dev)
+static int i915_emit_irq(drm_device_t * dev)
{
drm_i915_private_t *dev_priv = dev->dev_private;
u32 ret;
@@ -56,7 +76,7 @@ int i915_emit_irq(drm_device_t * dev)
return ret;
}
-int i915_wait_irq(drm_device_t * dev, int irq_nr)
+static 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;
diff --git a/drivers/char/drm/i915_mem.c b/drivers/char/drm/i915_mem.c
index d54a3005946b..9b1698f521be 100644
--- a/drivers/char/drm/i915_mem.c
+++ b/drivers/char/drm/i915_mem.c
@@ -1,10 +1,30 @@
/* i915_mem.c -- Simple agp/fb memory manager for i915 -*- linux-c -*-
*/
/**************************************************************************
- *
+ *
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
- *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+ * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
**************************************************************************/
#include "drmP.h"
diff --git a/drivers/char/drm/mga_drv.c b/drivers/char/drm/mga_drv.c
index 22dab3e9d92a..844cca9cb29d 100644
--- a/drivers/char/drm/mga_drv.c
+++ b/drivers/char/drm/mga_drv.c
@@ -101,6 +101,9 @@ static struct drm_driver driver = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = mga_compat_ioctl,
+#endif
},
.pci_driver = {
.name = DRIVER_NAME,
diff --git a/drivers/char/drm/mga_drv.h b/drivers/char/drm/mga_drv.h
index 1d84a1eb34db..9412e2816eb7 100644
--- a/drivers/char/drm/mga_drv.h
+++ b/drivers/char/drm/mga_drv.h
@@ -137,6 +137,8 @@ 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 );
+extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
#define mga_flush_write_combine() DRM_WRITEMEMORYBARRIER()
diff --git a/drivers/char/drm/mga_ioc32.c b/drivers/char/drm/mga_ioc32.c
new file mode 100644
index 000000000000..bc745cfa2095
--- /dev/null
+++ b/drivers/char/drm/mga_ioc32.c
@@ -0,0 +1,167 @@
+/**
+ * \file mga_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the MGA DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "mga_drm.h"
+
+typedef struct drm32_mga_init {
+ int func;
+ u32 sarea_priv_offset;
+ int chipset;
+ int sgram;
+ unsigned int maccess;
+ unsigned int fb_cpp;
+ unsigned int front_offset, front_pitch;
+ unsigned int back_offset, back_pitch;
+ unsigned int depth_cpp;
+ unsigned int depth_offset, depth_pitch;
+ unsigned int texture_offset[MGA_NR_TEX_HEAPS];
+ unsigned int texture_size[MGA_NR_TEX_HEAPS];
+ u32 fb_offset;
+ u32 mmio_offset;
+ u32 status_offset;
+ u32 warp_offset;
+ u32 primary_offset;
+ u32 buffers_offset;
+} drm_mga_init32_t;
+
+static int compat_mga_init(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_mga_init32_t init32;
+ drm_mga_init_t __user *init;
+ int err = 0, i;
+
+ if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+ return -EFAULT;
+
+ init = compat_alloc_user_space(sizeof(*init));
+ if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+ || __put_user(init32.func, &init->func)
+ || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+ || __put_user(init32.chipset, &init->chipset)
+ || __put_user(init32.sgram, &init->sgram)
+ || __put_user(init32.maccess, &init->maccess)
+ || __put_user(init32.fb_cpp, &init->fb_cpp)
+ || __put_user(init32.front_offset, &init->front_offset)
+ || __put_user(init32.front_pitch, &init->front_pitch)
+ || __put_user(init32.back_offset, &init->back_offset)
+ || __put_user(init32.back_pitch, &init->back_pitch)
+ || __put_user(init32.depth_cpp, &init->depth_cpp)
+ || __put_user(init32.depth_offset, &init->depth_offset)
+ || __put_user(init32.depth_pitch, &init->depth_pitch)
+ || __put_user(init32.fb_offset, &init->fb_offset)
+ || __put_user(init32.mmio_offset, &init->mmio_offset)
+ || __put_user(init32.status_offset, &init->status_offset)
+ || __put_user(init32.warp_offset, &init->warp_offset)
+ || __put_user(init32.primary_offset, &init->primary_offset)
+ || __put_user(init32.buffers_offset, &init->buffers_offset))
+ return -EFAULT;
+
+ for (i=0; i<MGA_NR_TEX_HEAPS; i++)
+ {
+ err |= __put_user(init32.texture_offset[i], &init->texture_offset[i]);
+ err |= __put_user(init32.texture_size[i], &init->texture_size[i]);
+ }
+ if (err)
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_MGA_INIT, (unsigned long) init);
+}
+
+
+typedef struct drm_mga_getparam32 {
+ int param;
+ u32 value;
+} drm_mga_getparam32_t;
+
+
+static int compat_mga_getparam(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_mga_getparam32_t getparam32;
+ drm_mga_getparam_t __user *getparam;
+
+ if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+ return -EFAULT;
+
+ getparam = compat_alloc_user_space(sizeof(*getparam));
+ if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+ || __put_user(getparam32.param, &getparam->param)
+ || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_MGA_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *mga_compat_ioctls[] = {
+ [DRM_MGA_INIT] = compat_mga_init,
+ [DRM_MGA_GETPARAM] = compat_mga_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long mga_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ drm_ioctl_compat_t *fn = NULL;
+ int ret;
+
+ if (nr < DRM_COMMAND_BASE)
+ return drm_compat_ioctl(filp, cmd, arg);
+
+ if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(mga_compat_ioctls))
+ fn = mga_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+ lock_kernel(); /* XXX for now */
+ if (fn != NULL)
+ ret = (*fn)(filp, cmd, arg);
+ else
+ ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
diff --git a/drivers/char/drm/r128_drv.c b/drivers/char/drm/r128_drv.c
index ced63810237b..bc446da1b210 100644
--- a/drivers/char/drm/r128_drv.c
+++ b/drivers/char/drm/r128_drv.c
@@ -96,6 +96,9 @@ static struct drm_driver driver = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = r128_compat_ioctl,
+#endif
},
.pci_driver = {
.name = DRIVER_NAME,
diff --git a/drivers/char/drm/r128_drv.h b/drivers/char/drm/r128_drv.h
index cf1aa5df459e..0fb687c9505e 100644
--- a/drivers/char/drm/r128_drv.h
+++ b/drivers/char/drm/r128_drv.h
@@ -156,6 +156,9 @@ extern void r128_driver_irq_uninstall( drm_device_t *dev );
extern void r128_driver_pretakedown(drm_device_t *dev);
extern void r128_driver_prerelease(drm_device_t *dev, DRMFILE filp);
+extern long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
/* Register definitions, register access macros and drmAddMap constants
* for Rage 128 kernel driver.
*/
diff --git a/drivers/char/drm/r128_ioc32.c b/drivers/char/drm/r128_ioc32.c
new file mode 100644
index 000000000000..60598ef9475a
--- /dev/null
+++ b/drivers/char/drm/r128_ioc32.c
@@ -0,0 +1,219 @@
+/**
+ * \file r128_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the R128 DRM.
+ *
+ * \author Dave Airlie <airlied@linux.ie> with code from patches by Egbert Eich
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * Copyright (C) Egbert Eich 2003,2004
+ * Copyright (C) Dave Airlie 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "r128_drm.h"
+
+typedef struct drm_r128_init32 {
+ int func;
+ unsigned int sarea_priv_offset;
+ int is_pci;
+ int cce_mode;
+ int cce_secure;
+ int ring_size;
+ int usec_timeout;
+
+ unsigned int fb_bpp;
+ unsigned int front_offset, front_pitch;
+ unsigned int back_offset, back_pitch;
+ unsigned int depth_bpp;
+ unsigned int depth_offset, depth_pitch;
+ unsigned int span_offset;
+
+ unsigned int fb_offset;
+ unsigned int mmio_offset;
+ unsigned int ring_offset;
+ unsigned int ring_rptr_offset;
+ unsigned int buffers_offset;
+ unsigned int agp_textures_offset;
+} drm_r128_init32_t;
+
+static int compat_r128_init(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_r128_init32_t init32;
+ drm_r128_init_t __user *init;
+
+ if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+ return -EFAULT;
+
+ init = compat_alloc_user_space(sizeof(*init));
+ if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+ || __put_user(init32.func, &init->func)
+ || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+ || __put_user(init32.is_pci, &init->is_pci)
+ || __put_user(init32.cce_mode, &init->cce_mode)
+ || __put_user(init32.cce_secure, &init->cce_secure)
+ || __put_user(init32.ring_size, &init->ring_size)
+ || __put_user(init32.usec_timeout, &init->usec_timeout)
+ || __put_user(init32.fb_bpp, &init->fb_bpp)
+ || __put_user(init32.front_offset, &init->front_offset)
+ || __put_user(init32.front_pitch, &init->front_pitch)
+ || __put_user(init32.back_offset, &init->back_offset)
+ || __put_user(init32.back_pitch, &init->back_pitch)
+ || __put_user(init32.depth_bpp, &init->depth_bpp)
+ || __put_user(init32.depth_offset, &init->depth_offset)
+ || __put_user(init32.depth_pitch, &init->depth_pitch)
+ || __put_user(init32.span_offset, &init->span_offset)
+ || __put_user(init32.fb_offset, &init->fb_offset)
+ || __put_user(init32.mmio_offset, &init->mmio_offset)
+ || __put_user(init32.ring_offset, &init->ring_offset)
+ || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
+ || __put_user(init32.buffers_offset, &init->buffers_offset)
+ || __put_user(init32.agp_textures_offset, &init->agp_textures_offset))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_R128_INIT, (unsigned long)init);
+}
+
+
+typedef struct drm_r128_depth32 {
+ int func;
+ int n;
+ u32 x;
+ u32 y;
+ u32 buffer;
+ u32 mask;
+} drm_r128_depth32_t;
+
+static int compat_r128_depth(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_r128_depth32_t depth32;
+ drm_r128_depth_t __user *depth;
+
+ if (copy_from_user(&depth32, (void __user *)arg, sizeof(depth32)))
+ return -EFAULT;
+
+ depth = compat_alloc_user_space(sizeof(*depth));
+ if (!access_ok(VERIFY_WRITE, depth, sizeof(*depth))
+ || __put_user(depth32.func, &depth->func)
+ || __put_user(depth32.n, &depth->n)
+ || __put_user((int __user *)(unsigned long)depth32.x, &depth->x)
+ || __put_user((int __user *)(unsigned long)depth32.y, &depth->y)
+ || __put_user((unsigned int __user *)(unsigned long)depth32.buffer, &depth->buffer)
+ || __put_user((unsigned char __user *)(unsigned long)depth32.mask, &depth->mask))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_R128_DEPTH, (unsigned long)depth);
+
+}
+
+typedef struct drm_r128_stipple32 {
+ u32 mask;
+} drm_r128_stipple32_t;
+
+static int compat_r128_stipple(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_r128_stipple32_t stipple32;
+ drm_r128_stipple_t __user *stipple;
+
+ if (copy_from_user(&stipple32, (void __user *)arg, sizeof(stipple32)))
+ return -EFAULT;
+
+ stipple = compat_alloc_user_space(sizeof(*stipple));
+ if (!access_ok(VERIFY_WRITE, stipple, sizeof(*stipple))
+ || __put_user((unsigned int __user *)(unsigned long)stipple32.mask, &stipple->mask))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_R128_STIPPLE, (unsigned long)stipple);
+}
+
+typedef struct drm_r128_getparam32 {
+ int param;
+ u32 value;
+} drm_r128_getparam32_t;
+
+static int compat_r128_getparam(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_r128_getparam32_t getparam32;
+ drm_r128_getparam_t __user *getparam;
+
+ if (copy_from_user(&getparam32, (void __user *)arg, sizeof(getparam32)))
+ return -EFAULT;
+
+ getparam = compat_alloc_user_space(sizeof(*getparam));
+ if (!access_ok(VERIFY_WRITE, getparam, sizeof(*getparam))
+ || __put_user(getparam32.param, &getparam->param)
+ || __put_user((void __user *)(unsigned long)getparam32.value, &getparam->value))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_R128_GETPARAM, (unsigned long)getparam);
+}
+
+drm_ioctl_compat_t *r128_compat_ioctls[] = {
+ [DRM_R128_INIT] = compat_r128_init,
+ [DRM_R128_DEPTH] = compat_r128_depth,
+ [DRM_R128_STIPPLE] = compat_r128_stipple,
+ [DRM_R128_GETPARAM] = compat_r128_getparam,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long r128_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ drm_ioctl_compat_t *fn = NULL;
+ int ret;
+
+ if (nr < DRM_COMMAND_BASE)
+ return drm_compat_ioctl(filp, cmd, arg);
+
+ if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(r128_compat_ioctls))
+ fn = r128_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+ lock_kernel(); /* XXX for now */
+ if (fn != NULL)
+ ret = (*fn)(filp, cmd, arg);
+ else
+ ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
diff --git a/drivers/char/drm/r128_state.c b/drivers/char/drm/r128_state.c
index 53af69162829..426a71c049d9 100644
--- a/drivers/char/drm/r128_state.c
+++ b/drivers/char/drm/r128_state.c
@@ -1307,7 +1307,7 @@ static int r128_do_init_pageflip( drm_device_t *dev )
return 0;
}
-int r128_do_cleanup_pageflip( drm_device_t *dev )
+static int r128_do_cleanup_pageflip( drm_device_t *dev )
{
drm_r128_private_t *dev_priv = dev->dev_private;
DRM_DEBUG( "\n" );
diff --git a/drivers/char/drm/radeon_drv.c b/drivers/char/drm/radeon_drv.c
index 7b983d96e53b..18e4e5b0952f 100644
--- a/drivers/char/drm/radeon_drv.c
+++ b/drivers/char/drm/radeon_drv.c
@@ -101,6 +101,9 @@ static struct drm_driver driver = {
.mmap = drm_mmap,
.poll = drm_poll,
.fasync = drm_fasync,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = radeon_compat_ioctl,
+#endif
},
.pci_driver = {
.name = DRIVER_NAME,
diff --git a/drivers/char/drm/radeon_drv.h b/drivers/char/drm/radeon_drv.h
index 5837098afae8..771aa80a5e8c 100644
--- a/drivers/char/drm/radeon_drv.h
+++ b/drivers/char/drm/radeon_drv.h
@@ -317,6 +317,9 @@ extern int radeon_preinit( struct drm_device *dev, unsigned long flags );
extern int radeon_postinit( struct drm_device *dev, unsigned long flags );
extern int radeon_postcleanup( struct drm_device *dev );
+extern long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg);
+
/* Flags for stats.boxes
*/
#define RADEON_BOX_DMA_IDLE 0x1
diff --git a/drivers/char/drm/radeon_ioc32.c b/drivers/char/drm/radeon_ioc32.c
new file mode 100644
index 000000000000..bfe612215fb3
--- /dev/null
+++ b/drivers/char/drm/radeon_ioc32.c
@@ -0,0 +1,395 @@
+/**
+ * \file radeon_ioc32.c
+ *
+ * 32-bit ioctl compatibility routines for the Radeon DRM.
+ *
+ * \author Paul Mackerras <paulus@samba.org>
+ *
+ * Copyright (C) Paul Mackerras 2005
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ */
+#include <linux/compat.h>
+#include <linux/ioctl32.h>
+
+#include "drmP.h"
+#include "drm.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+typedef struct drm_radeon_init32 {
+ int func;
+ u32 sarea_priv_offset;
+ int is_pci;
+ int cp_mode;
+ int gart_size;
+ int ring_size;
+ int usec_timeout;
+
+ unsigned int fb_bpp;
+ unsigned int front_offset, front_pitch;
+ unsigned int back_offset, back_pitch;
+ unsigned int depth_bpp;
+ unsigned int depth_offset, depth_pitch;
+
+ u32 fb_offset;
+ u32 mmio_offset;
+ u32 ring_offset;
+ u32 ring_rptr_offset;
+ u32 buffers_offset;
+ u32 gart_textures_offset;
+} drm_radeon_init32_t;
+
+static int compat_radeon_cp_init(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_init32_t init32;
+ drm_radeon_init_t __user *init;
+
+ if (copy_from_user(&init32, (void __user *)arg, sizeof(init32)))
+ return -EFAULT;
+
+ init = compat_alloc_user_space(sizeof(*init));
+ if (!access_ok(VERIFY_WRITE, init, sizeof(*init))
+ || __put_user(init32.func, &init->func)
+ || __put_user(init32.sarea_priv_offset, &init->sarea_priv_offset)
+ || __put_user(init32.is_pci, &init->is_pci)
+ || __put_user(init32.cp_mode, &init->cp_mode)
+ || __put_user(init32.gart_size, &init->gart_size)
+ || __put_user(init32.ring_size, &init->ring_size)
+ || __put_user(init32.usec_timeout, &init->usec_timeout)
+ || __put_user(init32.fb_bpp, &init->fb_bpp)
+ || __put_user(init32.front_offset, &init->front_offset)
+ || __put_user(init32.front_pitch, &init->front_pitch)
+ || __put_user(init32.back_offset, &init->back_offset)
+ || __put_user(init32.back_pitch, &init->back_pitch)
+ || __put_user(init32.depth_bpp, &init->depth_bpp)
+ || __put_user(init32.depth_offset, &init->depth_offset)
+ || __put_user(init32.depth_pitch, &init->depth_pitch)
+ || __put_user(init32.fb_offset, &init->fb_offset)
+ || __put_user(init32.mmio_offset, &init->mmio_offset)
+ || __put_user(init32.ring_offset, &init->ring_offset)
+ || __put_user(init32.ring_rptr_offset, &init->ring_rptr_offset)
+ || __put_user(init32.buffers_offset, &init->buffers_offset)
+ || __put_user(init32.gart_textures_offset,
+ &init->gart_textures_offset))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_CP_INIT, (unsigned long) init);
+}
+
+typedef struct drm_radeon_clear32 {
+ unsigned int flags;
+ unsigned int clear_color;
+ unsigned int clear_depth;
+ unsigned int color_mask;
+ unsigned int depth_mask; /* misnamed field: should be stencil */
+ u32 depth_boxes;
+} drm_radeon_clear32_t;
+
+static int compat_radeon_cp_clear(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_clear32_t clr32;
+ drm_radeon_clear_t __user *clr;
+
+ if (copy_from_user(&clr32, (void __user *)arg, sizeof(clr32)))
+ return -EFAULT;
+
+ clr = compat_alloc_user_space(sizeof(*clr));
+ if (!access_ok(VERIFY_WRITE, clr, sizeof(*clr))
+ || __put_user(clr32.flags, &clr->flags)
+ || __put_user(clr32.clear_color, &clr->clear_color)
+ || __put_user(clr32.clear_depth, &clr->clear_depth)
+ || __put_user(clr32.color_mask, &clr->color_mask)
+ || __put_user(clr32.depth_mask, &clr->depth_mask)
+ || __put_user((void __user *)(unsigned long)clr32.depth_boxes,
+ &clr->depth_boxes))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_CLEAR, (unsigned long) clr);
+}
+
+typedef struct drm_radeon_stipple32 {
+ u32 mask;
+} drm_radeon_stipple32_t;
+
+static int compat_radeon_cp_stipple(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_stipple32_t __user *argp = (void __user *) arg;
+ drm_radeon_stipple_t __user *request;
+ u32 mask;
+
+ if (get_user(mask, &argp->mask))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user((unsigned int __user *)(unsigned long) mask,
+ &request->mask))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_STIPPLE, (unsigned long) request);
+}
+
+typedef struct drm_radeon_tex_image32 {
+ unsigned int x, y; /* Blit coordinates */
+ unsigned int width, height;
+ u32 data;
+} drm_radeon_tex_image32_t;
+
+typedef struct drm_radeon_texture32 {
+ unsigned int offset;
+ int pitch;
+ int format;
+ int width; /* Texture image coordinates */
+ int height;
+ u32 image;
+} drm_radeon_texture32_t;
+
+static int compat_radeon_cp_texture(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_texture32_t req32;
+ drm_radeon_texture_t __user *request;
+ drm_radeon_tex_image32_t img32;
+ drm_radeon_tex_image_t __user *image;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+ if (req32.image == 0)
+ return -EINVAL;
+ if (copy_from_user(&img32, (void __user *)(unsigned long)req32.image,
+ sizeof(img32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request) + sizeof(*image));
+ if (!access_ok(VERIFY_WRITE, request,
+ sizeof(*request) + sizeof(*image)))
+ return -EFAULT;
+ image = (drm_radeon_tex_image_t __user *) (request + 1);
+
+ if (__put_user(req32.offset, &request->offset)
+ || __put_user(req32.pitch, &request->pitch)
+ || __put_user(req32.format, &request->format)
+ || __put_user(req32.width, &request->width)
+ || __put_user(req32.height, &request->height)
+ || __put_user(image, &request->image)
+ || __put_user(img32.x, &image->x)
+ || __put_user(img32.y, &image->y)
+ || __put_user(img32.width, &image->width)
+ || __put_user(img32.height, &image->height)
+ || __put_user((const void __user *)(unsigned long)img32.data,
+ &image->data))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_TEXTURE, (unsigned long) request);
+}
+
+typedef struct drm_radeon_vertex2_32 {
+ int idx; /* Index of vertex buffer */
+ int discard; /* Client finished with buffer? */
+ int nr_states;
+ u32 state;
+ int nr_prims;
+ u32 prim;
+} drm_radeon_vertex2_32_t;
+
+static int compat_radeon_cp_vertex2(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_vertex2_32_t req32;
+ drm_radeon_vertex2_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.idx, &request->idx)
+ || __put_user(req32.discard, &request->discard)
+ || __put_user(req32.nr_states, &request->nr_states)
+ || __put_user((void __user *)(unsigned long)req32.state,
+ &request->state)
+ || __put_user(req32.nr_prims, &request->nr_prims)
+ || __put_user((void __user *)(unsigned long)req32.prim,
+ &request->prim))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_VERTEX2, (unsigned long) request);
+}
+
+typedef struct drm_radeon_cmd_buffer32 {
+ int bufsz;
+ u32 buf;
+ int nbox;
+ u32 boxes;
+} drm_radeon_cmd_buffer32_t;
+
+static int compat_radeon_cp_cmdbuf(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_cmd_buffer32_t req32;
+ drm_radeon_cmd_buffer_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.bufsz, &request->bufsz)
+ || __put_user((void __user *)(unsigned long)req32.buf,
+ &request->buf)
+ || __put_user(req32.nbox, &request->nbox)
+ || __put_user((void __user *)(unsigned long)req32.boxes,
+ &request->boxes))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_CMDBUF, (unsigned long) request);
+}
+
+typedef struct drm_radeon_getparam32 {
+ int param;
+ u32 value;
+} drm_radeon_getparam32_t;
+
+static int compat_radeon_cp_getparam(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_getparam32_t req32;
+ drm_radeon_getparam_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.param, &request->param)
+ || __put_user((void __user *)(unsigned long)req32.value,
+ &request->value))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_GETPARAM, (unsigned long) request);
+}
+
+typedef struct drm_radeon_mem_alloc32 {
+ int region;
+ int alignment;
+ int size;
+ u32 region_offset; /* offset from start of fb or GART */
+} drm_radeon_mem_alloc32_t;
+
+static int compat_radeon_mem_alloc(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_mem_alloc32_t req32;
+ drm_radeon_mem_alloc_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user(req32.region, &request->region)
+ || __put_user(req32.alignment, &request->alignment)
+ || __put_user(req32.size, &request->size)
+ || __put_user((int __user *)(unsigned long)req32.region_offset,
+ &request->region_offset))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_ALLOC, (unsigned long) request);
+}
+
+typedef struct drm_radeon_irq_emit32 {
+ u32 irq_seq;
+} drm_radeon_irq_emit32_t;
+
+static int compat_radeon_irq_emit(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ drm_radeon_irq_emit32_t req32;
+ drm_radeon_irq_emit_t __user *request;
+
+ if (copy_from_user(&req32, (void __user *) arg, sizeof(req32)))
+ return -EFAULT;
+
+ request = compat_alloc_user_space(sizeof(*request));
+ if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
+ || __put_user((int __user *)(unsigned long)req32.irq_seq,
+ &request->irq_seq))
+ return -EFAULT;
+
+ return drm_ioctl(file->f_dentry->d_inode, file,
+ DRM_IOCTL_RADEON_IRQ_EMIT, (unsigned long) request);
+}
+
+drm_ioctl_compat_t *radeon_compat_ioctls[] = {
+ [DRM_RADEON_CP_INIT] = compat_radeon_cp_init,
+ [DRM_RADEON_CLEAR] = compat_radeon_cp_clear,
+ [DRM_RADEON_STIPPLE] = compat_radeon_cp_stipple,
+ [DRM_RADEON_TEXTURE] = compat_radeon_cp_texture,
+ [DRM_RADEON_VERTEX2] = compat_radeon_cp_vertex2,
+ [DRM_RADEON_CMDBUF] = compat_radeon_cp_cmdbuf,
+ [DRM_RADEON_GETPARAM] = compat_radeon_cp_getparam,
+ [DRM_RADEON_ALLOC] = compat_radeon_mem_alloc,
+ [DRM_RADEON_IRQ_EMIT] = compat_radeon_irq_emit,
+};
+
+/**
+ * Called whenever a 32-bit process running under a 64-bit kernel
+ * performs an ioctl on /dev/dri/card<n>.
+ *
+ * \param filp file pointer.
+ * \param cmd command.
+ * \param arg user argument.
+ * \return zero on success or negative number on failure.
+ */
+long radeon_compat_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ unsigned int nr = DRM_IOCTL_NR(cmd);
+ drm_ioctl_compat_t *fn = NULL;
+ int ret;
+
+ if (nr < DRM_COMMAND_BASE)
+ return drm_compat_ioctl(filp, cmd, arg);
+
+ if (nr < DRM_COMMAND_BASE + DRM_ARRAY_SIZE(radeon_compat_ioctls))
+ fn = radeon_compat_ioctls[nr - DRM_COMMAND_BASE];
+
+ lock_kernel(); /* XXX for now */
+ if (fn != NULL)
+ ret = (*fn)(filp, cmd, arg);
+ else
+ ret = drm_ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
+ unlock_kernel();
+
+ return ret;
+}
diff --git a/drivers/char/drm/radeon_irq.c b/drivers/char/drm/radeon_irq.c
index cd25f28e26a3..40474a65f56d 100644
--- a/drivers/char/drm/radeon_irq.c
+++ b/drivers/char/drm/radeon_irq.c
@@ -35,6 +35,14 @@
#include "radeon_drm.h"
#include "radeon_drv.h"
+static __inline__ u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 mask)
+{
+ u32 irqs = RADEON_READ(RADEON_GEN_INT_STATUS) & mask;
+ if (irqs)
+ RADEON_WRITE(RADEON_GEN_INT_STATUS, irqs);
+ return irqs;
+}
+
/* Interrupts - Used for device synchronization and flushing in the
* following circumstances:
*
@@ -63,8 +71,8 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS )
/* Only consider the bits we're interested in - others could be used
* outside the DRM
*/
- stat = RADEON_READ(RADEON_GEN_INT_STATUS)
- & (RADEON_SW_INT_TEST | RADEON_CRTC_VBLANK_STAT);
+ stat = radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+ RADEON_CRTC_VBLANK_STAT));
if (!stat)
return IRQ_NONE;
@@ -80,19 +88,9 @@ irqreturn_t radeon_driver_irq_handler( DRM_IRQ_ARGS )
drm_vbl_send_signals( dev );
}
- /* Acknowledge interrupts we handle */
- RADEON_WRITE(RADEON_GEN_INT_STATUS, stat);
return IRQ_HANDLED;
}
-static __inline__ void radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv)
-{
- u32 tmp = RADEON_READ( RADEON_GEN_INT_STATUS )
- & (RADEON_SW_INT_TEST_ACK | RADEON_CRTC_VBLANK_STAT);
- if (tmp)
- RADEON_WRITE( RADEON_GEN_INT_STATUS, tmp );
-}
-
static int radeon_emit_irq(drm_device_t *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
@@ -141,7 +139,7 @@ int radeon_driver_vblank_wait(drm_device_t *dev, unsigned int *sequence)
return DRM_ERR(EINVAL);
}
- radeon_acknowledge_irqs( dev_priv );
+ radeon_acknowledge_irqs(dev_priv, RADEON_CRTC_VBLANK_STAT);
dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
@@ -219,7 +217,8 @@ void radeon_driver_irq_preinstall( drm_device_t *dev ) {
RADEON_WRITE( RADEON_GEN_INT_CNTL, 0 );
/* Clear bits if they're already high */
- radeon_acknowledge_irqs( dev_priv );
+ radeon_acknowledge_irqs(dev_priv, (RADEON_SW_INT_TEST_ACK |
+ RADEON_CRTC_VBLANK_STAT));
}
void radeon_driver_irq_postinstall( drm_device_t *dev ) {
diff --git a/drivers/char/drm/via_3d_reg.h b/drivers/char/drm/via_3d_reg.h
new file mode 100644
index 000000000000..cf61bb514db1
--- /dev/null
+++ b/drivers/char/drm/via_3d_reg.h
@@ -0,0 +1,1651 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ */
+
+#ifndef VIA_3D_REG_H
+#define VIA_3D_REG_H
+#define HC_REG_BASE 0x0400
+
+#define HC_REG_TRANS_SPACE 0x0040
+
+#define HC_ParaN_MASK 0xffffffff
+#define HC_Para_MASK 0x00ffffff
+#define HC_SubA_MASK 0xff000000
+#define HC_SubA_SHIFT 24
+/* Transmission Setting
+ */
+#define HC_REG_TRANS_SET 0x003c
+#define HC_ParaSubType_MASK 0xff000000
+#define HC_ParaType_MASK 0x00ff0000
+#define HC_ParaOS_MASK 0x0000ff00
+#define HC_ParaAdr_MASK 0x000000ff
+#define HC_ParaSubType_SHIFT 24
+#define HC_ParaType_SHIFT 16
+#define HC_ParaOS_SHIFT 8
+#define HC_ParaAdr_SHIFT 0
+
+#define HC_ParaType_CmdVdata 0x0000
+#define HC_ParaType_NotTex 0x0001
+#define HC_ParaType_Tex 0x0002
+#define HC_ParaType_Palette 0x0003
+#define HC_ParaType_PreCR 0x0010
+#define HC_ParaType_Auto 0x00fe
+
+/* Transmission Space
+ */
+#define HC_REG_Hpara0 0x0040
+#define HC_REG_HpataAF 0x02fc
+
+/* Read
+ */
+#define HC_REG_HREngSt 0x0000
+#define HC_REG_HRFIFOempty 0x0004
+#define HC_REG_HRFIFOfull 0x0008
+#define HC_REG_HRErr 0x000c
+#define HC_REG_FIFOstatus 0x0010
+/* HC_REG_HREngSt 0x0000
+ */
+#define HC_HDASZC_MASK 0x00010000
+#define HC_HSGEMI_MASK 0x0000f000
+#define HC_HLGEMISt_MASK 0x00000f00
+#define HC_HCRSt_MASK 0x00000080
+#define HC_HSE0St_MASK 0x00000040
+#define HC_HSE1St_MASK 0x00000020
+#define HC_HPESt_MASK 0x00000010
+#define HC_HXESt_MASK 0x00000008
+#define HC_HBESt_MASK 0x00000004
+#define HC_HE2St_MASK 0x00000002
+#define HC_HE3St_MASK 0x00000001
+/* HC_REG_HRFIFOempty 0x0004
+ */
+#define HC_HRZDempty_MASK 0x00000010
+#define HC_HRTXAempty_MASK 0x00000008
+#define HC_HRTXDempty_MASK 0x00000004
+#define HC_HWZDempty_MASK 0x00000002
+#define HC_HWCDempty_MASK 0x00000001
+/* HC_REG_HRFIFOfull 0x0008
+ */
+#define HC_HRZDfull_MASK 0x00000010
+#define HC_HRTXAfull_MASK 0x00000008
+#define HC_HRTXDfull_MASK 0x00000004
+#define HC_HWZDfull_MASK 0x00000002
+#define HC_HWCDfull_MASK 0x00000001
+/* HC_REG_HRErr 0x000c
+ */
+#define HC_HAGPCMErr_MASK 0x80000000
+#define HC_HAGPCMErrC_MASK 0x70000000
+/* HC_REG_FIFOstatus 0x0010
+ */
+#define HC_HRFIFOATall_MASK 0x80000000
+#define HC_HRFIFOATbusy_MASK 0x40000000
+#define HC_HRATFGMDo_MASK 0x00000100
+#define HC_HRATFGMDi_MASK 0x00000080
+#define HC_HRATFRZD_MASK 0x00000040
+#define HC_HRATFRTXA_MASK 0x00000020
+#define HC_HRATFRTXD_MASK 0x00000010
+#define HC_HRATFWZD_MASK 0x00000008
+#define HC_HRATFWCD_MASK 0x00000004
+#define HC_HRATTXTAG_MASK 0x00000002
+#define HC_HRATTXCH_MASK 0x00000001
+
+/* AGP Command Setting
+ */
+#define HC_SubA_HAGPBstL 0x0060
+#define HC_SubA_HAGPBendL 0x0061
+#define HC_SubA_HAGPCMNT 0x0062
+#define HC_SubA_HAGPBpL 0x0063
+#define HC_SubA_HAGPBpH 0x0064
+/* HC_SubA_HAGPCMNT 0x0062
+ */
+#define HC_HAGPCMNT_MASK 0x00800000
+#define HC_HCmdErrClr_MASK 0x00400000
+#define HC_HAGPBendH_MASK 0x0000ff00
+#define HC_HAGPBstH_MASK 0x000000ff
+#define HC_HAGPBendH_SHIFT 8
+#define HC_HAGPBstH_SHIFT 0
+/* HC_SubA_HAGPBpL 0x0063
+ */
+#define HC_HAGPBpL_MASK 0x00fffffc
+#define HC_HAGPBpID_MASK 0x00000003
+#define HC_HAGPBpID_PAUSE 0x00000000
+#define HC_HAGPBpID_JUMP 0x00000001
+#define HC_HAGPBpID_STOP 0x00000002
+/* HC_SubA_HAGPBpH 0x0064
+ */
+#define HC_HAGPBpH_MASK 0x00ffffff
+
+/* Miscellaneous Settings
+ */
+#define HC_SubA_HClipTB 0x0070
+#define HC_SubA_HClipLR 0x0071
+#define HC_SubA_HFPClipTL 0x0072
+#define HC_SubA_HFPClipBL 0x0073
+#define HC_SubA_HFPClipLL 0x0074
+#define HC_SubA_HFPClipRL 0x0075
+#define HC_SubA_HFPClipTBH 0x0076
+#define HC_SubA_HFPClipLRH 0x0077
+#define HC_SubA_HLP 0x0078
+#define HC_SubA_HLPRF 0x0079
+#define HC_SubA_HSolidCL 0x007a
+#define HC_SubA_HPixGC 0x007b
+#define HC_SubA_HSPXYOS 0x007c
+#define HC_SubA_HVertexCNT 0x007d
+
+#define HC_HClipT_MASK 0x00fff000
+#define HC_HClipT_SHIFT 12
+#define HC_HClipB_MASK 0x00000fff
+#define HC_HClipB_SHIFT 0
+#define HC_HClipL_MASK 0x00fff000
+#define HC_HClipL_SHIFT 12
+#define HC_HClipR_MASK 0x00000fff
+#define HC_HClipR_SHIFT 0
+#define HC_HFPClipBH_MASK 0x0000ff00
+#define HC_HFPClipBH_SHIFT 8
+#define HC_HFPClipTH_MASK 0x000000ff
+#define HC_HFPClipTH_SHIFT 0
+#define HC_HFPClipRH_MASK 0x0000ff00
+#define HC_HFPClipRH_SHIFT 8
+#define HC_HFPClipLH_MASK 0x000000ff
+#define HC_HFPClipLH_SHIFT 0
+#define HC_HSolidCH_MASK 0x000000ff
+#define HC_HPixGC_MASK 0x00800000
+#define HC_HSPXOS_MASK 0x00fff000
+#define HC_HSPXOS_SHIFT 12
+#define HC_HSPYOS_MASK 0x00000fff
+
+/* Command
+ * Command A
+ */
+#define HC_HCmdHeader_MASK 0xfe000000 /*0xffe00000 */
+#define HC_HE3Fire_MASK 0x00100000
+#define HC_HPMType_MASK 0x000f0000
+#define HC_HEFlag_MASK 0x0000e000
+#define HC_HShading_MASK 0x00001c00
+#define HC_HPMValidN_MASK 0x00000200
+#define HC_HPLEND_MASK 0x00000100
+#define HC_HVCycle_MASK 0x000000ff
+#define HC_HVCycle_Style_MASK 0x000000c0
+#define HC_HVCycle_ChgA_MASK 0x00000030
+#define HC_HVCycle_ChgB_MASK 0x0000000c
+#define HC_HVCycle_ChgC_MASK 0x00000003
+#define HC_HPMType_Point 0x00000000
+#define HC_HPMType_Line 0x00010000
+#define HC_HPMType_Tri 0x00020000
+#define HC_HPMType_TriWF 0x00040000
+#define HC_HEFlag_NoAA 0x00000000
+#define HC_HEFlag_ab 0x00008000
+#define HC_HEFlag_bc 0x00004000
+#define HC_HEFlag_ca 0x00002000
+#define HC_HShading_Solid 0x00000000
+#define HC_HShading_FlatA 0x00000400
+#define HC_HShading_FlatB 0x00000800
+#define HC_HShading_FlatC 0x00000c00
+#define HC_HShading_Gouraud 0x00001000
+#define HC_HVCycle_Full 0x00000000
+#define HC_HVCycle_AFP 0x00000040
+#define HC_HVCycle_One 0x000000c0
+#define HC_HVCycle_NewA 0x00000000
+#define HC_HVCycle_AA 0x00000010
+#define HC_HVCycle_AB 0x00000020
+#define HC_HVCycle_AC 0x00000030
+#define HC_HVCycle_NewB 0x00000000
+#define HC_HVCycle_BA 0x00000004
+#define HC_HVCycle_BB 0x00000008
+#define HC_HVCycle_BC 0x0000000c
+#define HC_HVCycle_NewC 0x00000000
+#define HC_HVCycle_CA 0x00000001
+#define HC_HVCycle_CB 0x00000002
+#define HC_HVCycle_CC 0x00000003
+
+/* Command B
+ */
+#define HC_HLPrst_MASK 0x00010000
+#define HC_HLLastP_MASK 0x00008000
+#define HC_HVPMSK_MASK 0x00007f80
+#define HC_HBFace_MASK 0x00000040
+#define HC_H2nd1VT_MASK 0x0000003f
+#define HC_HVPMSK_X 0x00004000
+#define HC_HVPMSK_Y 0x00002000
+#define HC_HVPMSK_Z 0x00001000
+#define HC_HVPMSK_W 0x00000800
+#define HC_HVPMSK_Cd 0x00000400
+#define HC_HVPMSK_Cs 0x00000200
+#define HC_HVPMSK_S 0x00000100
+#define HC_HVPMSK_T 0x00000080
+
+/* Enable Setting
+ */
+#define HC_SubA_HEnable 0x0000
+#define HC_HenTXEnvMap_MASK 0x00200000
+#define HC_HenVertexCNT_MASK 0x00100000
+#define HC_HenCPUDAZ_MASK 0x00080000
+#define HC_HenDASZWC_MASK 0x00040000
+#define HC_HenFBCull_MASK 0x00020000
+#define HC_HenCW_MASK 0x00010000
+#define HC_HenAA_MASK 0x00008000
+#define HC_HenST_MASK 0x00004000
+#define HC_HenZT_MASK 0x00002000
+#define HC_HenZW_MASK 0x00001000
+#define HC_HenAT_MASK 0x00000800
+#define HC_HenAW_MASK 0x00000400
+#define HC_HenSP_MASK 0x00000200
+#define HC_HenLP_MASK 0x00000100
+#define HC_HenTXCH_MASK 0x00000080
+#define HC_HenTXMP_MASK 0x00000040
+#define HC_HenTXPP_MASK 0x00000020
+#define HC_HenTXTR_MASK 0x00000010
+#define HC_HenCS_MASK 0x00000008
+#define HC_HenFOG_MASK 0x00000004
+#define HC_HenABL_MASK 0x00000002
+#define HC_HenDT_MASK 0x00000001
+
+/* Z Setting
+ */
+#define HC_SubA_HZWBBasL 0x0010
+#define HC_SubA_HZWBBasH 0x0011
+#define HC_SubA_HZWBType 0x0012
+#define HC_SubA_HZBiasL 0x0013
+#define HC_SubA_HZWBend 0x0014
+#define HC_SubA_HZWTMD 0x0015
+#define HC_SubA_HZWCDL 0x0016
+#define HC_SubA_HZWCTAGnum 0x0017
+#define HC_SubA_HZCYNum 0x0018
+#define HC_SubA_HZWCFire 0x0019
+/* HC_SubA_HZWBType
+ */
+#define HC_HZWBType_MASK 0x00800000
+#define HC_HZBiasedWB_MASK 0x00400000
+#define HC_HZONEasFF_MASK 0x00200000
+#define HC_HZOONEasFF_MASK 0x00100000
+#define HC_HZWBFM_MASK 0x00030000
+#define HC_HZWBLoc_MASK 0x0000c000
+#define HC_HZWBPit_MASK 0x00003fff
+#define HC_HZWBFM_16 0x00000000
+#define HC_HZWBFM_32 0x00020000
+#define HC_HZWBFM_24 0x00030000
+#define HC_HZWBLoc_Local 0x00000000
+#define HC_HZWBLoc_SyS 0x00004000
+/* HC_SubA_HZWBend
+ */
+#define HC_HZWBend_MASK 0x00ffe000
+#define HC_HZBiasH_MASK 0x000000ff
+#define HC_HZWBend_SHIFT 10
+/* HC_SubA_HZWTMD
+ */
+#define HC_HZWTMD_MASK 0x00070000
+#define HC_HEBEBias_MASK 0x00007f00
+#define HC_HZNF_MASK 0x000000ff
+#define HC_HZWTMD_NeverPass 0x00000000
+#define HC_HZWTMD_LT 0x00010000
+#define HC_HZWTMD_EQ 0x00020000
+#define HC_HZWTMD_LE 0x00030000
+#define HC_HZWTMD_GT 0x00040000
+#define HC_HZWTMD_NE 0x00050000
+#define HC_HZWTMD_GE 0x00060000
+#define HC_HZWTMD_AllPass 0x00070000
+#define HC_HEBEBias_SHIFT 8
+/* HC_SubA_HZWCDL 0x0016
+ */
+#define HC_HZWCDL_MASK 0x00ffffff
+/* HC_SubA_HZWCTAGnum 0x0017
+ */
+#define HC_HZWCTAGnum_MASK 0x00ff0000
+#define HC_HZWCTAGnum_SHIFT 16
+#define HC_HZWCDH_MASK 0x000000ff
+#define HC_HZWCDH_SHIFT 0
+/* HC_SubA_HZCYNum 0x0018
+ */
+#define HC_HZCYNum_MASK 0x00030000
+#define HC_HZCYNum_SHIFT 16
+#define HC_HZWCQWnum_MASK 0x00003fff
+#define HC_HZWCQWnum_SHIFT 0
+/* HC_SubA_HZWCFire 0x0019
+ */
+#define HC_ZWCFire_MASK 0x00010000
+#define HC_HZWCQWnumLast_MASK 0x00003fff
+#define HC_HZWCQWnumLast_SHIFT 0
+
+/* Stencil Setting
+ */
+#define HC_SubA_HSTREF 0x0023
+#define HC_SubA_HSTMD 0x0024
+/* HC_SubA_HSBFM
+ */
+#define HC_HSBFM_MASK 0x00030000
+#define HC_HSBLoc_MASK 0x0000c000
+#define HC_HSBPit_MASK 0x00003fff
+/* HC_SubA_HSTREF
+ */
+#define HC_HSTREF_MASK 0x00ff0000
+#define HC_HSTOPMSK_MASK 0x0000ff00
+#define HC_HSTBMSK_MASK 0x000000ff
+#define HC_HSTREF_SHIFT 16
+#define HC_HSTOPMSK_SHIFT 8
+/* HC_SubA_HSTMD
+ */
+#define HC_HSTMD_MASK 0x00070000
+#define HC_HSTOPSF_MASK 0x000001c0
+#define HC_HSTOPSPZF_MASK 0x00000038
+#define HC_HSTOPSPZP_MASK 0x00000007
+#define HC_HSTMD_NeverPass 0x00000000
+#define HC_HSTMD_LT 0x00010000
+#define HC_HSTMD_EQ 0x00020000
+#define HC_HSTMD_LE 0x00030000
+#define HC_HSTMD_GT 0x00040000
+#define HC_HSTMD_NE 0x00050000
+#define HC_HSTMD_GE 0x00060000
+#define HC_HSTMD_AllPass 0x00070000
+#define HC_HSTOPSF_KEEP 0x00000000
+#define HC_HSTOPSF_ZERO 0x00000040
+#define HC_HSTOPSF_REPLACE 0x00000080
+#define HC_HSTOPSF_INCRSAT 0x000000c0
+#define HC_HSTOPSF_DECRSAT 0x00000100
+#define HC_HSTOPSF_INVERT 0x00000140
+#define HC_HSTOPSF_INCR 0x00000180
+#define HC_HSTOPSF_DECR 0x000001c0
+#define HC_HSTOPSPZF_KEEP 0x00000000
+#define HC_HSTOPSPZF_ZERO 0x00000008
+#define HC_HSTOPSPZF_REPLACE 0x00000010
+#define HC_HSTOPSPZF_INCRSAT 0x00000018
+#define HC_HSTOPSPZF_DECRSAT 0x00000020
+#define HC_HSTOPSPZF_INVERT 0x00000028
+#define HC_HSTOPSPZF_INCR 0x00000030
+#define HC_HSTOPSPZF_DECR 0x00000038
+#define HC_HSTOPSPZP_KEEP 0x00000000
+#define HC_HSTOPSPZP_ZERO 0x00000001
+#define HC_HSTOPSPZP_REPLACE 0x00000002
+#define HC_HSTOPSPZP_INCRSAT 0x00000003
+#define HC_HSTOPSPZP_DECRSAT 0x00000004
+#define HC_HSTOPSPZP_INVERT 0x00000005
+#define HC_HSTOPSPZP_INCR 0x00000006
+#define HC_HSTOPSPZP_DECR 0x00000007
+
+/* Alpha Setting
+ */
+#define HC_SubA_HABBasL 0x0030
+#define HC_SubA_HABBasH 0x0031
+#define HC_SubA_HABFM 0x0032
+#define HC_SubA_HATMD 0x0033
+#define HC_SubA_HABLCsat 0x0034
+#define HC_SubA_HABLCop 0x0035
+#define HC_SubA_HABLAsat 0x0036
+#define HC_SubA_HABLAop 0x0037
+#define HC_SubA_HABLRCa 0x0038
+#define HC_SubA_HABLRFCa 0x0039
+#define HC_SubA_HABLRCbias 0x003a
+#define HC_SubA_HABLRCb 0x003b
+#define HC_SubA_HABLRFCb 0x003c
+#define HC_SubA_HABLRAa 0x003d
+#define HC_SubA_HABLRAb 0x003e
+/* HC_SubA_HABFM
+ */
+#define HC_HABFM_MASK 0x00030000
+#define HC_HABLoc_MASK 0x0000c000
+#define HC_HABPit_MASK 0x000007ff
+/* HC_SubA_HATMD
+ */
+#define HC_HATMD_MASK 0x00000700
+#define HC_HATREF_MASK 0x000000ff
+#define HC_HATMD_NeverPass 0x00000000
+#define HC_HATMD_LT 0x00000100
+#define HC_HATMD_EQ 0x00000200
+#define HC_HATMD_LE 0x00000300
+#define HC_HATMD_GT 0x00000400
+#define HC_HATMD_NE 0x00000500
+#define HC_HATMD_GE 0x00000600
+#define HC_HATMD_AllPass 0x00000700
+/* HC_SubA_HABLCsat
+ */
+#define HC_HABLCsat_MASK 0x00010000
+#define HC_HABLCa_MASK 0x0000fc00
+#define HC_HABLCa_C_MASK 0x0000c000
+#define HC_HABLCa_OPC_MASK 0x00003c00
+#define HC_HABLFCa_MASK 0x000003f0
+#define HC_HABLFCa_C_MASK 0x00000300
+#define HC_HABLFCa_OPC_MASK 0x000000f0
+#define HC_HABLCbias_MASK 0x0000000f
+#define HC_HABLCbias_C_MASK 0x00000008
+#define HC_HABLCbias_OPC_MASK 0x00000007
+/*-- Define the input color.
+ */
+#define HC_XC_Csrc 0x00000000
+#define HC_XC_Cdst 0x00000001
+#define HC_XC_Asrc 0x00000002
+#define HC_XC_Adst 0x00000003
+#define HC_XC_Fog 0x00000004
+#define HC_XC_HABLRC 0x00000005
+#define HC_XC_minSrcDst 0x00000006
+#define HC_XC_maxSrcDst 0x00000007
+#define HC_XC_mimAsrcInvAdst 0x00000008
+#define HC_XC_OPC 0x00000000
+#define HC_XC_InvOPC 0x00000010
+#define HC_XC_OPCp5 0x00000020
+/*-- Define the input Alpha
+ */
+#define HC_XA_OPA 0x00000000
+#define HC_XA_InvOPA 0x00000010
+#define HC_XA_OPAp5 0x00000020
+#define HC_XA_0 0x00000000
+#define HC_XA_Asrc 0x00000001
+#define HC_XA_Adst 0x00000002
+#define HC_XA_Fog 0x00000003
+#define HC_XA_minAsrcFog 0x00000004
+#define HC_XA_minAsrcAdst 0x00000005
+#define HC_XA_maxAsrcFog 0x00000006
+#define HC_XA_maxAsrcAdst 0x00000007
+#define HC_XA_HABLRA 0x00000008
+#define HC_XA_minAsrcInvAdst 0x00000008
+#define HC_XA_HABLFRA 0x00000009
+/*--
+ */
+#define HC_HABLCa_OPC (HC_XC_OPC << 10)
+#define HC_HABLCa_InvOPC (HC_XC_InvOPC << 10)
+#define HC_HABLCa_OPCp5 (HC_XC_OPCp5 << 10)
+#define HC_HABLCa_Csrc (HC_XC_Csrc << 10)
+#define HC_HABLCa_Cdst (HC_XC_Cdst << 10)
+#define HC_HABLCa_Asrc (HC_XC_Asrc << 10)
+#define HC_HABLCa_Adst (HC_XC_Adst << 10)
+#define HC_HABLCa_Fog (HC_XC_Fog << 10)
+#define HC_HABLCa_HABLRCa (HC_XC_HABLRC << 10)
+#define HC_HABLCa_minSrcDst (HC_XC_minSrcDst << 10)
+#define HC_HABLCa_maxSrcDst (HC_XC_maxSrcDst << 10)
+#define HC_HABLFCa_OPC (HC_XC_OPC << 4)
+#define HC_HABLFCa_InvOPC (HC_XC_InvOPC << 4)
+#define HC_HABLFCa_OPCp5 (HC_XC_OPCp5 << 4)
+#define HC_HABLFCa_Csrc (HC_XC_Csrc << 4)
+#define HC_HABLFCa_Cdst (HC_XC_Cdst << 4)
+#define HC_HABLFCa_Asrc (HC_XC_Asrc << 4)
+#define HC_HABLFCa_Adst (HC_XC_Adst << 4)
+#define HC_HABLFCa_Fog (HC_XC_Fog << 4)
+#define HC_HABLFCa_HABLRCa (HC_XC_HABLRC << 4)
+#define HC_HABLFCa_minSrcDst (HC_XC_minSrcDst << 4)
+#define HC_HABLFCa_maxSrcDst (HC_XC_maxSrcDst << 4)
+#define HC_HABLFCa_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 4)
+#define HC_HABLCbias_HABLRCbias 0x00000000
+#define HC_HABLCbias_Asrc 0x00000001
+#define HC_HABLCbias_Adst 0x00000002
+#define HC_HABLCbias_Fog 0x00000003
+#define HC_HABLCbias_Cin 0x00000004
+/* HC_SubA_HABLCop 0x0035
+ */
+#define HC_HABLdot_MASK 0x00010000
+#define HC_HABLCop_MASK 0x00004000
+#define HC_HABLCb_MASK 0x00003f00
+#define HC_HABLCb_C_MASK 0x00003000
+#define HC_HABLCb_OPC_MASK 0x00000f00
+#define HC_HABLFCb_MASK 0x000000fc
+#define HC_HABLFCb_C_MASK 0x000000c0
+#define HC_HABLFCb_OPC_MASK 0x0000003c
+#define HC_HABLCshift_MASK 0x00000003
+#define HC_HABLCb_OPC (HC_XC_OPC << 8)
+#define HC_HABLCb_InvOPC (HC_XC_InvOPC << 8)
+#define HC_HABLCb_OPCp5 (HC_XC_OPCp5 << 8)
+#define HC_HABLCb_Csrc (HC_XC_Csrc << 8)
+#define HC_HABLCb_Cdst (HC_XC_Cdst << 8)
+#define HC_HABLCb_Asrc (HC_XC_Asrc << 8)
+#define HC_HABLCb_Adst (HC_XC_Adst << 8)
+#define HC_HABLCb_Fog (HC_XC_Fog << 8)
+#define HC_HABLCb_HABLRCa (HC_XC_HABLRC << 8)
+#define HC_HABLCb_minSrcDst (HC_XC_minSrcDst << 8)
+#define HC_HABLCb_maxSrcDst (HC_XC_maxSrcDst << 8)
+#define HC_HABLFCb_OPC (HC_XC_OPC << 2)
+#define HC_HABLFCb_InvOPC (HC_XC_InvOPC << 2)
+#define HC_HABLFCb_OPCp5 (HC_XC_OPCp5 << 2)
+#define HC_HABLFCb_Csrc (HC_XC_Csrc << 2)
+#define HC_HABLFCb_Cdst (HC_XC_Cdst << 2)
+#define HC_HABLFCb_Asrc (HC_XC_Asrc << 2)
+#define HC_HABLFCb_Adst (HC_XC_Adst << 2)
+#define HC_HABLFCb_Fog (HC_XC_Fog << 2)
+#define HC_HABLFCb_HABLRCb (HC_XC_HABLRC << 2)
+#define HC_HABLFCb_minSrcDst (HC_XC_minSrcDst << 2)
+#define HC_HABLFCb_maxSrcDst (HC_XC_maxSrcDst << 2)
+#define HC_HABLFCb_mimAsrcInvAdst (HC_XC_mimAsrcInvAdst << 2)
+/* HC_SubA_HABLAsat 0x0036
+ */
+#define HC_HABLAsat_MASK 0x00010000
+#define HC_HABLAa_MASK 0x0000fc00
+#define HC_HABLAa_A_MASK 0x0000c000
+#define HC_HABLAa_OPA_MASK 0x00003c00
+#define HC_HABLFAa_MASK 0x000003f0
+#define HC_HABLFAa_A_MASK 0x00000300
+#define HC_HABLFAa_OPA_MASK 0x000000f0
+#define HC_HABLAbias_MASK 0x0000000f
+#define HC_HABLAbias_A_MASK 0x00000008
+#define HC_HABLAbias_OPA_MASK 0x00000007
+#define HC_HABLAa_OPA (HC_XA_OPA << 10)
+#define HC_HABLAa_InvOPA (HC_XA_InvOPA << 10)
+#define HC_HABLAa_OPAp5 (HC_XA_OPAp5 << 10)
+#define HC_HABLAa_0 (HC_XA_0 << 10)
+#define HC_HABLAa_Asrc (HC_XA_Asrc << 10)
+#define HC_HABLAa_Adst (HC_XA_Adst << 10)
+#define HC_HABLAa_Fog (HC_XA_Fog << 10)
+#define HC_HABLAa_minAsrcFog (HC_XA_minAsrcFog << 10)
+#define HC_HABLAa_minAsrcAdst (HC_XA_minAsrcAdst << 10)
+#define HC_HABLAa_maxAsrcFog (HC_XA_maxAsrcFog << 10)
+#define HC_HABLAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 10)
+#define HC_HABLAa_HABLRA (HC_XA_HABLRA << 10)
+#define HC_HABLFAa_OPA (HC_XA_OPA << 4)
+#define HC_HABLFAa_InvOPA (HC_XA_InvOPA << 4)
+#define HC_HABLFAa_OPAp5 (HC_XA_OPAp5 << 4)
+#define HC_HABLFAa_0 (HC_XA_0 << 4)
+#define HC_HABLFAa_Asrc (HC_XA_Asrc << 4)
+#define HC_HABLFAa_Adst (HC_XA_Adst << 4)
+#define HC_HABLFAa_Fog (HC_XA_Fog << 4)
+#define HC_HABLFAa_minAsrcFog (HC_XA_minAsrcFog << 4)
+#define HC_HABLFAa_minAsrcAdst (HC_XA_minAsrcAdst << 4)
+#define HC_HABLFAa_maxAsrcFog (HC_XA_maxAsrcFog << 4)
+#define HC_HABLFAa_maxAsrcAdst (HC_XA_maxAsrcAdst << 4)
+#define HC_HABLFAa_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 4)
+#define HC_HABLFAa_HABLFRA (HC_XA_HABLFRA << 4)
+#define HC_HABLAbias_HABLRAbias 0x00000000
+#define HC_HABLAbias_Asrc 0x00000001
+#define HC_HABLAbias_Adst 0x00000002
+#define HC_HABLAbias_Fog 0x00000003
+#define HC_HABLAbias_Aaa 0x00000004
+/* HC_SubA_HABLAop 0x0037
+ */
+#define HC_HABLAop_MASK 0x00004000
+#define HC_HABLAb_MASK 0x00003f00
+#define HC_HABLAb_OPA_MASK 0x00000f00
+#define HC_HABLFAb_MASK 0x000000fc
+#define HC_HABLFAb_OPA_MASK 0x0000003c
+#define HC_HABLAshift_MASK 0x00000003
+#define HC_HABLAb_OPA (HC_XA_OPA << 8)
+#define HC_HABLAb_InvOPA (HC_XA_InvOPA << 8)
+#define HC_HABLAb_OPAp5 (HC_XA_OPAp5 << 8)
+#define HC_HABLAb_0 (HC_XA_0 << 8)
+#define HC_HABLAb_Asrc (HC_XA_Asrc << 8)
+#define HC_HABLAb_Adst (HC_XA_Adst << 8)
+#define HC_HABLAb_Fog (HC_XA_Fog << 8)
+#define HC_HABLAb_minAsrcFog (HC_XA_minAsrcFog << 8)
+#define HC_HABLAb_minAsrcAdst (HC_XA_minAsrcAdst << 8)
+#define HC_HABLAb_maxAsrcFog (HC_XA_maxAsrcFog << 8)
+#define HC_HABLAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 8)
+#define HC_HABLAb_HABLRA (HC_XA_HABLRA << 8)
+#define HC_HABLFAb_OPA (HC_XA_OPA << 2)
+#define HC_HABLFAb_InvOPA (HC_XA_InvOPA << 2)
+#define HC_HABLFAb_OPAp5 (HC_XA_OPAp5 << 2)
+#define HC_HABLFAb_0 (HC_XA_0 << 2)
+#define HC_HABLFAb_Asrc (HC_XA_Asrc << 2)
+#define HC_HABLFAb_Adst (HC_XA_Adst << 2)
+#define HC_HABLFAb_Fog (HC_XA_Fog << 2)
+#define HC_HABLFAb_minAsrcFog (HC_XA_minAsrcFog << 2)
+#define HC_HABLFAb_minAsrcAdst (HC_XA_minAsrcAdst << 2)
+#define HC_HABLFAb_maxAsrcFog (HC_XA_maxAsrcFog << 2)
+#define HC_HABLFAb_maxAsrcAdst (HC_XA_maxAsrcAdst << 2)
+#define HC_HABLFAb_minAsrcInvAdst (HC_XA_minAsrcInvAdst << 2)
+#define HC_HABLFAb_HABLFRA (HC_XA_HABLFRA << 2)
+/* HC_SubA_HABLRAa 0x003d
+ */
+#define HC_HABLRAa_MASK 0x00ff0000
+#define HC_HABLRFAa_MASK 0x0000ff00
+#define HC_HABLRAbias_MASK 0x000000ff
+#define HC_HABLRAa_SHIFT 16
+#define HC_HABLRFAa_SHIFT 8
+/* HC_SubA_HABLRAb 0x003e
+ */
+#define HC_HABLRAb_MASK 0x0000ff00
+#define HC_HABLRFAb_MASK 0x000000ff
+#define HC_HABLRAb_SHIFT 8
+
+/* Destination Setting
+ */
+#define HC_SubA_HDBBasL 0x0040
+#define HC_SubA_HDBBasH 0x0041
+#define HC_SubA_HDBFM 0x0042
+#define HC_SubA_HFBBMSKL 0x0043
+#define HC_SubA_HROP 0x0044
+/* HC_SubA_HDBFM 0x0042
+ */
+#define HC_HDBFM_MASK 0x001f0000
+#define HC_HDBLoc_MASK 0x0000c000
+#define HC_HDBPit_MASK 0x00003fff
+#define HC_HDBFM_RGB555 0x00000000
+#define HC_HDBFM_RGB565 0x00010000
+#define HC_HDBFM_ARGB4444 0x00020000
+#define HC_HDBFM_ARGB1555 0x00030000
+#define HC_HDBFM_BGR555 0x00040000
+#define HC_HDBFM_BGR565 0x00050000
+#define HC_HDBFM_ABGR4444 0x00060000
+#define HC_HDBFM_ABGR1555 0x00070000
+#define HC_HDBFM_ARGB0888 0x00080000
+#define HC_HDBFM_ARGB8888 0x00090000
+#define HC_HDBFM_ABGR0888 0x000a0000
+#define HC_HDBFM_ABGR8888 0x000b0000
+#define HC_HDBLoc_Local 0x00000000
+#define HC_HDBLoc_Sys 0x00004000
+/* HC_SubA_HROP 0x0044
+ */
+#define HC_HROP_MASK 0x00000f00
+#define HC_HFBBMSKH_MASK 0x000000ff
+#define HC_HROP_BLACK 0x00000000
+#define HC_HROP_DPon 0x00000100
+#define HC_HROP_DPna 0x00000200
+#define HC_HROP_Pn 0x00000300
+#define HC_HROP_PDna 0x00000400
+#define HC_HROP_Dn 0x00000500
+#define HC_HROP_DPx 0x00000600
+#define HC_HROP_DPan 0x00000700
+#define HC_HROP_DPa 0x00000800
+#define HC_HROP_DPxn 0x00000900
+#define HC_HROP_D 0x00000a00
+#define HC_HROP_DPno 0x00000b00
+#define HC_HROP_P 0x00000c00
+#define HC_HROP_PDno 0x00000d00
+#define HC_HROP_DPo 0x00000e00
+#define HC_HROP_WHITE 0x00000f00
+
+/* Fog Setting
+ */
+#define HC_SubA_HFogLF 0x0050
+#define HC_SubA_HFogCL 0x0051
+#define HC_SubA_HFogCH 0x0052
+#define HC_SubA_HFogStL 0x0053
+#define HC_SubA_HFogStH 0x0054
+#define HC_SubA_HFogOOdMF 0x0055
+#define HC_SubA_HFogOOdEF 0x0056
+#define HC_SubA_HFogEndL 0x0057
+#define HC_SubA_HFogDenst 0x0058
+/* HC_SubA_FogLF 0x0050
+ */
+#define HC_FogLF_MASK 0x00000010
+#define HC_FogEq_MASK 0x00000008
+#define HC_FogMD_MASK 0x00000007
+#define HC_FogMD_LocalFog 0x00000000
+#define HC_FogMD_LinearFog 0x00000002
+#define HC_FogMD_ExponentialFog 0x00000004
+#define HC_FogMD_Exponential2Fog 0x00000005
+/* #define HC_FogMD_FogTable 0x00000003 */
+
+/* HC_SubA_HFogDenst 0x0058
+ */
+#define HC_FogDenst_MASK 0x001fff00
+#define HC_FogEndL_MASK 0x000000ff
+
+/* Texture subtype definitions
+ */
+#define HC_SubType_Tex0 0x00000000
+#define HC_SubType_Tex1 0x00000001
+#define HC_SubType_TexGeneral 0x000000fe
+
+/* Attribute of texture n
+ */
+#define HC_SubA_HTXnL0BasL 0x0000
+#define HC_SubA_HTXnL1BasL 0x0001
+#define HC_SubA_HTXnL2BasL 0x0002
+#define HC_SubA_HTXnL3BasL 0x0003
+#define HC_SubA_HTXnL4BasL 0x0004
+#define HC_SubA_HTXnL5BasL 0x0005
+#define HC_SubA_HTXnL6BasL 0x0006
+#define HC_SubA_HTXnL7BasL 0x0007
+#define HC_SubA_HTXnL8BasL 0x0008
+#define HC_SubA_HTXnL9BasL 0x0009
+#define HC_SubA_HTXnLaBasL 0x000a
+#define HC_SubA_HTXnLbBasL 0x000b
+#define HC_SubA_HTXnLcBasL 0x000c
+#define HC_SubA_HTXnLdBasL 0x000d
+#define HC_SubA_HTXnLeBasL 0x000e
+#define HC_SubA_HTXnLfBasL 0x000f
+#define HC_SubA_HTXnL10BasL 0x0010
+#define HC_SubA_HTXnL11BasL 0x0011
+#define HC_SubA_HTXnL012BasH 0x0020
+#define HC_SubA_HTXnL345BasH 0x0021
+#define HC_SubA_HTXnL678BasH 0x0022
+#define HC_SubA_HTXnL9abBasH 0x0023
+#define HC_SubA_HTXnLcdeBasH 0x0024
+#define HC_SubA_HTXnLf1011BasH 0x0025
+#define HC_SubA_HTXnL0Pit 0x002b
+#define HC_SubA_HTXnL1Pit 0x002c
+#define HC_SubA_HTXnL2Pit 0x002d
+#define HC_SubA_HTXnL3Pit 0x002e
+#define HC_SubA_HTXnL4Pit 0x002f
+#define HC_SubA_HTXnL5Pit 0x0030
+#define HC_SubA_HTXnL6Pit 0x0031
+#define HC_SubA_HTXnL7Pit 0x0032
+#define HC_SubA_HTXnL8Pit 0x0033
+#define HC_SubA_HTXnL9Pit 0x0034
+#define HC_SubA_HTXnLaPit 0x0035
+#define HC_SubA_HTXnLbPit 0x0036
+#define HC_SubA_HTXnLcPit 0x0037
+#define HC_SubA_HTXnLdPit 0x0038
+#define HC_SubA_HTXnLePit 0x0039
+#define HC_SubA_HTXnLfPit 0x003a
+#define HC_SubA_HTXnL10Pit 0x003b
+#define HC_SubA_HTXnL11Pit 0x003c
+#define HC_SubA_HTXnL0_5WE 0x004b
+#define HC_SubA_HTXnL6_bWE 0x004c
+#define HC_SubA_HTXnLc_11WE 0x004d
+#define HC_SubA_HTXnL0_5HE 0x0051
+#define HC_SubA_HTXnL6_bHE 0x0052
+#define HC_SubA_HTXnLc_11HE 0x0053
+#define HC_SubA_HTXnL0OS 0x0077
+#define HC_SubA_HTXnTB 0x0078
+#define HC_SubA_HTXnMPMD 0x0079
+#define HC_SubA_HTXnCLODu 0x007a
+#define HC_SubA_HTXnFM 0x007b
+#define HC_SubA_HTXnTRCH 0x007c
+#define HC_SubA_HTXnTRCL 0x007d
+#define HC_SubA_HTXnTBC 0x007e
+#define HC_SubA_HTXnTRAH 0x007f
+#define HC_SubA_HTXnTBLCsat 0x0080
+#define HC_SubA_HTXnTBLCop 0x0081
+#define HC_SubA_HTXnTBLMPfog 0x0082
+#define HC_SubA_HTXnTBLAsat 0x0083
+#define HC_SubA_HTXnTBLRCa 0x0085
+#define HC_SubA_HTXnTBLRCb 0x0086
+#define HC_SubA_HTXnTBLRCc 0x0087
+#define HC_SubA_HTXnTBLRCbias 0x0088
+#define HC_SubA_HTXnTBLRAa 0x0089
+#define HC_SubA_HTXnTBLRFog 0x008a
+#define HC_SubA_HTXnBumpM00 0x0090
+#define HC_SubA_HTXnBumpM01 0x0091
+#define HC_SubA_HTXnBumpM10 0x0092
+#define HC_SubA_HTXnBumpM11 0x0093
+#define HC_SubA_HTXnLScale 0x0094
+#define HC_SubA_HTXSMD 0x0000
+/* HC_SubA_HTXnL012BasH 0x0020
+ */
+#define HC_HTXnL0BasH_MASK 0x000000ff
+#define HC_HTXnL1BasH_MASK 0x0000ff00
+#define HC_HTXnL2BasH_MASK 0x00ff0000
+#define HC_HTXnL1BasH_SHIFT 8
+#define HC_HTXnL2BasH_SHIFT 16
+/* HC_SubA_HTXnL345BasH 0x0021
+ */
+#define HC_HTXnL3BasH_MASK 0x000000ff
+#define HC_HTXnL4BasH_MASK 0x0000ff00
+#define HC_HTXnL5BasH_MASK 0x00ff0000
+#define HC_HTXnL4BasH_SHIFT 8
+#define HC_HTXnL5BasH_SHIFT 16
+/* HC_SubA_HTXnL678BasH 0x0022
+ */
+#define HC_HTXnL6BasH_MASK 0x000000ff
+#define HC_HTXnL7BasH_MASK 0x0000ff00
+#define HC_HTXnL8BasH_MASK 0x00ff0000
+#define HC_HTXnL7BasH_SHIFT 8
+#define HC_HTXnL8BasH_SHIFT 16
+/* HC_SubA_HTXnL9abBasH 0x0023
+ */
+#define HC_HTXnL9BasH_MASK 0x000000ff
+#define HC_HTXnLaBasH_MASK 0x0000ff00
+#define HC_HTXnLbBasH_MASK 0x00ff0000
+#define HC_HTXnLaBasH_SHIFT 8
+#define HC_HTXnLbBasH_SHIFT 16
+/* HC_SubA_HTXnLcdeBasH 0x0024
+ */
+#define HC_HTXnLcBasH_MASK 0x000000ff
+#define HC_HTXnLdBasH_MASK 0x0000ff00
+#define HC_HTXnLeBasH_MASK 0x00ff0000
+#define HC_HTXnLdBasH_SHIFT 8
+#define HC_HTXnLeBasH_SHIFT 16
+/* HC_SubA_HTXnLcdeBasH 0x0025
+ */
+#define HC_HTXnLfBasH_MASK 0x000000ff
+#define HC_HTXnL10BasH_MASK 0x0000ff00
+#define HC_HTXnL11BasH_MASK 0x00ff0000
+#define HC_HTXnL10BasH_SHIFT 8
+#define HC_HTXnL11BasH_SHIFT 16
+/* HC_SubA_HTXnL0Pit 0x002b
+ */
+#define HC_HTXnLnPit_MASK 0x00003fff
+#define HC_HTXnEnPit_MASK 0x00080000
+#define HC_HTXnLnPitE_MASK 0x00f00000
+#define HC_HTXnLnPitE_SHIFT 20
+/* HC_SubA_HTXnL0_5WE 0x004b
+ */
+#define HC_HTXnL0WE_MASK 0x0000000f
+#define HC_HTXnL1WE_MASK 0x000000f0
+#define HC_HTXnL2WE_MASK 0x00000f00
+#define HC_HTXnL3WE_MASK 0x0000f000
+#define HC_HTXnL4WE_MASK 0x000f0000
+#define HC_HTXnL5WE_MASK 0x00f00000
+#define HC_HTXnL1WE_SHIFT 4
+#define HC_HTXnL2WE_SHIFT 8
+#define HC_HTXnL3WE_SHIFT 12
+#define HC_HTXnL4WE_SHIFT 16
+#define HC_HTXnL5WE_SHIFT 20
+/* HC_SubA_HTXnL6_bWE 0x004c
+ */
+#define HC_HTXnL6WE_MASK 0x0000000f
+#define HC_HTXnL7WE_MASK 0x000000f0
+#define HC_HTXnL8WE_MASK 0x00000f00
+#define HC_HTXnL9WE_MASK 0x0000f000
+#define HC_HTXnLaWE_MASK 0x000f0000
+#define HC_HTXnLbWE_MASK 0x00f00000
+#define HC_HTXnL7WE_SHIFT 4
+#define HC_HTXnL8WE_SHIFT 8
+#define HC_HTXnL9WE_SHIFT 12
+#define HC_HTXnLaWE_SHIFT 16
+#define HC_HTXnLbWE_SHIFT 20
+/* HC_SubA_HTXnLc_11WE 0x004d
+ */
+#define HC_HTXnLcWE_MASK 0x0000000f
+#define HC_HTXnLdWE_MASK 0x000000f0
+#define HC_HTXnLeWE_MASK 0x00000f00
+#define HC_HTXnLfWE_MASK 0x0000f000
+#define HC_HTXnL10WE_MASK 0x000f0000
+#define HC_HTXnL11WE_MASK 0x00f00000
+#define HC_HTXnLdWE_SHIFT 4
+#define HC_HTXnLeWE_SHIFT 8
+#define HC_HTXnLfWE_SHIFT 12
+#define HC_HTXnL10WE_SHIFT 16
+#define HC_HTXnL11WE_SHIFT 20
+/* HC_SubA_HTXnL0_5HE 0x0051
+ */
+#define HC_HTXnL0HE_MASK 0x0000000f
+#define HC_HTXnL1HE_MASK 0x000000f0
+#define HC_HTXnL2HE_MASK 0x00000f00
+#define HC_HTXnL3HE_MASK 0x0000f000
+#define HC_HTXnL4HE_MASK 0x000f0000
+#define HC_HTXnL5HE_MASK 0x00f00000
+#define HC_HTXnL1HE_SHIFT 4
+#define HC_HTXnL2HE_SHIFT 8
+#define HC_HTXnL3HE_SHIFT 12
+#define HC_HTXnL4HE_SHIFT 16
+#define HC_HTXnL5HE_SHIFT 20
+/* HC_SubA_HTXnL6_bHE 0x0052
+ */
+#define HC_HTXnL6HE_MASK 0x0000000f
+#define HC_HTXnL7HE_MASK 0x000000f0
+#define HC_HTXnL8HE_MASK 0x00000f00
+#define HC_HTXnL9HE_MASK 0x0000f000
+#define HC_HTXnLaHE_MASK 0x000f0000
+#define HC_HTXnLbHE_MASK 0x00f00000
+#define HC_HTXnL7HE_SHIFT 4
+#define HC_HTXnL8HE_SHIFT 8
+#define HC_HTXnL9HE_SHIFT 12
+#define HC_HTXnLaHE_SHIFT 16
+#define HC_HTXnLbHE_SHIFT 20
+/* HC_SubA_HTXnLc_11HE 0x0053
+ */
+#define HC_HTXnLcHE_MASK 0x0000000f
+#define HC_HTXnLdHE_MASK 0x000000f0
+#define HC_HTXnLeHE_MASK 0x00000f00
+#define HC_HTXnLfHE_MASK 0x0000f000
+#define HC_HTXnL10HE_MASK 0x000f0000
+#define HC_HTXnL11HE_MASK 0x00f00000
+#define HC_HTXnLdHE_SHIFT 4
+#define HC_HTXnLeHE_SHIFT 8
+#define HC_HTXnLfHE_SHIFT 12
+#define HC_HTXnL10HE_SHIFT 16
+#define HC_HTXnL11HE_SHIFT 20
+/* HC_SubA_HTXnL0OS 0x0077
+ */
+#define HC_HTXnL0OS_MASK 0x003ff000
+#define HC_HTXnLVmax_MASK 0x00000fc0
+#define HC_HTXnLVmin_MASK 0x0000003f
+#define HC_HTXnL0OS_SHIFT 12
+#define HC_HTXnLVmax_SHIFT 6
+/* HC_SubA_HTXnTB 0x0078
+ */
+#define HC_HTXnTB_MASK 0x00f00000
+#define HC_HTXnFLSe_MASK 0x0000e000
+#define HC_HTXnFLSs_MASK 0x00001c00
+#define HC_HTXnFLTe_MASK 0x00000380
+#define HC_HTXnFLTs_MASK 0x00000070
+#define HC_HTXnFLDs_MASK 0x0000000f
+#define HC_HTXnTB_NoTB 0x00000000
+#define HC_HTXnTB_TBC_S 0x00100000
+#define HC_HTXnTB_TBC_T 0x00200000
+#define HC_HTXnTB_TB_S 0x00400000
+#define HC_HTXnTB_TB_T 0x00800000
+#define HC_HTXnFLSe_Nearest 0x00000000
+#define HC_HTXnFLSe_Linear 0x00002000
+#define HC_HTXnFLSe_NonLinear 0x00004000
+#define HC_HTXnFLSe_Sharp 0x00008000
+#define HC_HTXnFLSe_Flat_Gaussian_Cubic 0x0000c000
+#define HC_HTXnFLSs_Nearest 0x00000000
+#define HC_HTXnFLSs_Linear 0x00000400
+#define HC_HTXnFLSs_NonLinear 0x00000800
+#define HC_HTXnFLSs_Flat_Gaussian_Cubic 0x00001800
+#define HC_HTXnFLTe_Nearest 0x00000000
+#define HC_HTXnFLTe_Linear 0x00000080
+#define HC_HTXnFLTe_NonLinear 0x00000100
+#define HC_HTXnFLTe_Sharp 0x00000180
+#define HC_HTXnFLTe_Flat_Gaussian_Cubic 0x00000300
+#define HC_HTXnFLTs_Nearest 0x00000000
+#define HC_HTXnFLTs_Linear 0x00000010
+#define HC_HTXnFLTs_NonLinear 0x00000020
+#define HC_HTXnFLTs_Flat_Gaussian_Cubic 0x00000060
+#define HC_HTXnFLDs_Tex0 0x00000000
+#define HC_HTXnFLDs_Nearest 0x00000001
+#define HC_HTXnFLDs_Linear 0x00000002
+#define HC_HTXnFLDs_NonLinear 0x00000003
+#define HC_HTXnFLDs_Dither 0x00000004
+#define HC_HTXnFLDs_ConstLOD 0x00000005
+#define HC_HTXnFLDs_Ani 0x00000006
+#define HC_HTXnFLDs_AniDither 0x00000007
+/* HC_SubA_HTXnMPMD 0x0079
+ */
+#define HC_HTXnMPMD_SMASK 0x00070000
+#define HC_HTXnMPMD_TMASK 0x00380000
+#define HC_HTXnLODDTf_MASK 0x00000007
+#define HC_HTXnXY2ST_MASK 0x00000008
+#define HC_HTXnMPMD_Tsingle 0x00000000
+#define HC_HTXnMPMD_Tclamp 0x00080000
+#define HC_HTXnMPMD_Trepeat 0x00100000
+#define HC_HTXnMPMD_Tmirror 0x00180000
+#define HC_HTXnMPMD_Twrap 0x00200000
+#define HC_HTXnMPMD_Ssingle 0x00000000
+#define HC_HTXnMPMD_Sclamp 0x00010000
+#define HC_HTXnMPMD_Srepeat 0x00020000
+#define HC_HTXnMPMD_Smirror 0x00030000
+#define HC_HTXnMPMD_Swrap 0x00040000
+/* HC_SubA_HTXnCLODu 0x007a
+ */
+#define HC_HTXnCLODu_MASK 0x000ffc00
+#define HC_HTXnCLODd_MASK 0x000003ff
+#define HC_HTXnCLODu_SHIFT 10
+/* HC_SubA_HTXnFM 0x007b
+ */
+#define HC_HTXnFM_MASK 0x00ff0000
+#define HC_HTXnLoc_MASK 0x00000003
+#define HC_HTXnFM_INDEX 0x00000000
+#define HC_HTXnFM_Intensity 0x00080000
+#define HC_HTXnFM_Lum 0x00100000
+#define HC_HTXnFM_Alpha 0x00180000
+#define HC_HTXnFM_DX 0x00280000
+#define HC_HTXnFM_ARGB16 0x00880000
+#define HC_HTXnFM_ARGB32 0x00980000
+#define HC_HTXnFM_ABGR16 0x00a80000
+#define HC_HTXnFM_ABGR32 0x00b80000
+#define HC_HTXnFM_RGBA16 0x00c80000
+#define HC_HTXnFM_RGBA32 0x00d80000
+#define HC_HTXnFM_BGRA16 0x00e80000
+#define HC_HTXnFM_BGRA32 0x00f80000
+#define HC_HTXnFM_BUMPMAP 0x00380000
+#define HC_HTXnFM_Index1 (HC_HTXnFM_INDEX | 0x00000000)
+#define HC_HTXnFM_Index2 (HC_HTXnFM_INDEX | 0x00010000)
+#define HC_HTXnFM_Index4 (HC_HTXnFM_INDEX | 0x00020000)
+#define HC_HTXnFM_Index8 (HC_HTXnFM_INDEX | 0x00030000)
+#define HC_HTXnFM_T1 (HC_HTXnFM_Intensity | 0x00000000)
+#define HC_HTXnFM_T2 (HC_HTXnFM_Intensity | 0x00010000)
+#define HC_HTXnFM_T4 (HC_HTXnFM_Intensity | 0x00020000)
+#define HC_HTXnFM_T8 (HC_HTXnFM_Intensity | 0x00030000)
+#define HC_HTXnFM_L1 (HC_HTXnFM_Lum | 0x00000000)
+#define HC_HTXnFM_L2 (HC_HTXnFM_Lum | 0x00010000)
+#define HC_HTXnFM_L4 (HC_HTXnFM_Lum | 0x00020000)
+#define HC_HTXnFM_L8 (HC_HTXnFM_Lum | 0x00030000)
+#define HC_HTXnFM_AL44 (HC_HTXnFM_Lum | 0x00040000)
+#define HC_HTXnFM_AL88 (HC_HTXnFM_Lum | 0x00050000)
+#define HC_HTXnFM_A1 (HC_HTXnFM_Alpha | 0x00000000)
+#define HC_HTXnFM_A2 (HC_HTXnFM_Alpha | 0x00010000)
+#define HC_HTXnFM_A4 (HC_HTXnFM_Alpha | 0x00020000)
+#define HC_HTXnFM_A8 (HC_HTXnFM_Alpha | 0x00030000)
+#define HC_HTXnFM_DX1 (HC_HTXnFM_DX | 0x00010000)
+#define HC_HTXnFM_DX23 (HC_HTXnFM_DX | 0x00020000)
+#define HC_HTXnFM_DX45 (HC_HTXnFM_DX | 0x00030000)
+#define HC_HTXnFM_RGB555 (HC_HTXnFM_ARGB16 | 0x00000000)
+#define HC_HTXnFM_RGB565 (HC_HTXnFM_ARGB16 | 0x00010000)
+#define HC_HTXnFM_ARGB1555 (HC_HTXnFM_ARGB16 | 0x00020000)
+#define HC_HTXnFM_ARGB4444 (HC_HTXnFM_ARGB16 | 0x00030000)
+#define HC_HTXnFM_ARGB0888 (HC_HTXnFM_ARGB32 | 0x00000000)
+#define HC_HTXnFM_ARGB8888 (HC_HTXnFM_ARGB32 | 0x00010000)
+#define HC_HTXnFM_BGR555 (HC_HTXnFM_ABGR16 | 0x00000000)
+#define HC_HTXnFM_BGR565 (HC_HTXnFM_ABGR16 | 0x00010000)
+#define HC_HTXnFM_ABGR1555 (HC_HTXnFM_ABGR16 | 0x00020000)
+#define HC_HTXnFM_ABGR4444 (HC_HTXnFM_ABGR16 | 0x00030000)
+#define HC_HTXnFM_ABGR0888 (HC_HTXnFM_ABGR32 | 0x00000000)
+#define HC_HTXnFM_ABGR8888 (HC_HTXnFM_ABGR32 | 0x00010000)
+#define HC_HTXnFM_RGBA5550 (HC_HTXnFM_RGBA16 | 0x00000000)
+#define HC_HTXnFM_RGBA5551 (HC_HTXnFM_RGBA16 | 0x00020000)
+#define HC_HTXnFM_RGBA4444 (HC_HTXnFM_RGBA16 | 0x00030000)
+#define HC_HTXnFM_RGBA8880 (HC_HTXnFM_RGBA32 | 0x00000000)
+#define HC_HTXnFM_RGBA8888 (HC_HTXnFM_RGBA32 | 0x00010000)
+#define HC_HTXnFM_BGRA5550 (HC_HTXnFM_BGRA16 | 0x00000000)
+#define HC_HTXnFM_BGRA5551 (HC_HTXnFM_BGRA16 | 0x00020000)
+#define HC_HTXnFM_BGRA4444 (HC_HTXnFM_BGRA16 | 0x00030000)
+#define HC_HTXnFM_BGRA8880 (HC_HTXnFM_BGRA32 | 0x00000000)
+#define HC_HTXnFM_BGRA8888 (HC_HTXnFM_BGRA32 | 0x00010000)
+#define HC_HTXnFM_VU88 (HC_HTXnFM_BUMPMAP | 0x00000000)
+#define HC_HTXnFM_LVU655 (HC_HTXnFM_BUMPMAP | 0x00010000)
+#define HC_HTXnFM_LVU888 (HC_HTXnFM_BUMPMAP | 0x00020000)
+#define HC_HTXnLoc_Local 0x00000000
+#define HC_HTXnLoc_Sys 0x00000002
+#define HC_HTXnLoc_AGP 0x00000003
+/* HC_SubA_HTXnTRAH 0x007f
+ */
+#define HC_HTXnTRAH_MASK 0x00ff0000
+#define HC_HTXnTRAL_MASK 0x0000ff00
+#define HC_HTXnTBA_MASK 0x000000ff
+#define HC_HTXnTRAH_SHIFT 16
+#define HC_HTXnTRAL_SHIFT 8
+/* HC_SubA_HTXnTBLCsat 0x0080
+ *-- Define the input texture.
+ */
+#define HC_XTC_TOPC 0x00000000
+#define HC_XTC_InvTOPC 0x00000010
+#define HC_XTC_TOPCp5 0x00000020
+#define HC_XTC_Cbias 0x00000000
+#define HC_XTC_InvCbias 0x00000010
+#define HC_XTC_0 0x00000000
+#define HC_XTC_Dif 0x00000001
+#define HC_XTC_Spec 0x00000002
+#define HC_XTC_Tex 0x00000003
+#define HC_XTC_Cur 0x00000004
+#define HC_XTC_Adif 0x00000005
+#define HC_XTC_Fog 0x00000006
+#define HC_XTC_Atex 0x00000007
+#define HC_XTC_Acur 0x00000008
+#define HC_XTC_HTXnTBLRC 0x00000009
+#define HC_XTC_Ctexnext 0x0000000a
+/*--
+ */
+#define HC_HTXnTBLCsat_MASK 0x00800000
+#define HC_HTXnTBLCa_MASK 0x000fc000
+#define HC_HTXnTBLCb_MASK 0x00001f80
+#define HC_HTXnTBLCc_MASK 0x0000003f
+#define HC_HTXnTBLCa_TOPC (HC_XTC_TOPC << 14)
+#define HC_HTXnTBLCa_InvTOPC (HC_XTC_InvTOPC << 14)
+#define HC_HTXnTBLCa_TOPCp5 (HC_XTC_TOPCp5 << 14)
+#define HC_HTXnTBLCa_0 (HC_XTC_0 << 14)
+#define HC_HTXnTBLCa_Dif (HC_XTC_Dif << 14)
+#define HC_HTXnTBLCa_Spec (HC_XTC_Spec << 14)
+#define HC_HTXnTBLCa_Tex (HC_XTC_Tex << 14)
+#define HC_HTXnTBLCa_Cur (HC_XTC_Cur << 14)
+#define HC_HTXnTBLCa_Adif (HC_XTC_Adif << 14)
+#define HC_HTXnTBLCa_Fog (HC_XTC_Fog << 14)
+#define HC_HTXnTBLCa_Atex (HC_XTC_Atex << 14)
+#define HC_HTXnTBLCa_Acur (HC_XTC_Acur << 14)
+#define HC_HTXnTBLCa_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14)
+#define HC_HTXnTBLCa_Ctexnext (HC_XTC_Ctexnext << 14)
+#define HC_HTXnTBLCb_TOPC (HC_XTC_TOPC << 7)
+#define HC_HTXnTBLCb_InvTOPC (HC_XTC_InvTOPC << 7)
+#define HC_HTXnTBLCb_TOPCp5 (HC_XTC_TOPCp5 << 7)
+#define HC_HTXnTBLCb_0 (HC_XTC_0 << 7)
+#define HC_HTXnTBLCb_Dif (HC_XTC_Dif << 7)
+#define HC_HTXnTBLCb_Spec (HC_XTC_Spec << 7)
+#define HC_HTXnTBLCb_Tex (HC_XTC_Tex << 7)
+#define HC_HTXnTBLCb_Cur (HC_XTC_Cur << 7)
+#define HC_HTXnTBLCb_Adif (HC_XTC_Adif << 7)
+#define HC_HTXnTBLCb_Fog (HC_XTC_Fog << 7)
+#define HC_HTXnTBLCb_Atex (HC_XTC_Atex << 7)
+#define HC_HTXnTBLCb_Acur (HC_XTC_Acur << 7)
+#define HC_HTXnTBLCb_HTXnTBLRC (HC_XTC_HTXnTBLRC << 7)
+#define HC_HTXnTBLCb_Ctexnext (HC_XTC_Ctexnext << 7)
+#define HC_HTXnTBLCc_TOPC (HC_XTC_TOPC << 0)
+#define HC_HTXnTBLCc_InvTOPC (HC_XTC_InvTOPC << 0)
+#define HC_HTXnTBLCc_TOPCp5 (HC_XTC_TOPCp5 << 0)
+#define HC_HTXnTBLCc_0 (HC_XTC_0 << 0)
+#define HC_HTXnTBLCc_Dif (HC_XTC_Dif << 0)
+#define HC_HTXnTBLCc_Spec (HC_XTC_Spec << 0)
+#define HC_HTXnTBLCc_Tex (HC_XTC_Tex << 0)
+#define HC_HTXnTBLCc_Cur (HC_XTC_Cur << 0)
+#define HC_HTXnTBLCc_Adif (HC_XTC_Adif << 0)
+#define HC_HTXnTBLCc_Fog (HC_XTC_Fog << 0)
+#define HC_HTXnTBLCc_Atex (HC_XTC_Atex << 0)
+#define HC_HTXnTBLCc_Acur (HC_XTC_Acur << 0)
+#define HC_HTXnTBLCc_HTXnTBLRC (HC_XTC_HTXnTBLRC << 0)
+#define HC_HTXnTBLCc_Ctexnext (HC_XTC_Ctexnext << 0)
+/* HC_SubA_HTXnTBLCop 0x0081
+ */
+#define HC_HTXnTBLdot_MASK 0x00c00000
+#define HC_HTXnTBLCop_MASK 0x00380000
+#define HC_HTXnTBLCbias_MASK 0x0007c000
+#define HC_HTXnTBLCshift_MASK 0x00001800
+#define HC_HTXnTBLAop_MASK 0x00000380
+#define HC_HTXnTBLAbias_MASK 0x00000078
+#define HC_HTXnTBLAshift_MASK 0x00000003
+#define HC_HTXnTBLCop_Add 0x00000000
+#define HC_HTXnTBLCop_Sub 0x00080000
+#define HC_HTXnTBLCop_Min 0x00100000
+#define HC_HTXnTBLCop_Max 0x00180000
+#define HC_HTXnTBLCop_Mask 0x00200000
+#define HC_HTXnTBLCbias_Cbias (HC_XTC_Cbias << 14)
+#define HC_HTXnTBLCbias_InvCbias (HC_XTC_InvCbias << 14)
+#define HC_HTXnTBLCbias_0 (HC_XTC_0 << 14)
+#define HC_HTXnTBLCbias_Dif (HC_XTC_Dif << 14)
+#define HC_HTXnTBLCbias_Spec (HC_XTC_Spec << 14)
+#define HC_HTXnTBLCbias_Tex (HC_XTC_Tex << 14)
+#define HC_HTXnTBLCbias_Cur (HC_XTC_Cur << 14)
+#define HC_HTXnTBLCbias_Adif (HC_XTC_Adif << 14)
+#define HC_HTXnTBLCbias_Fog (HC_XTC_Fog << 14)
+#define HC_HTXnTBLCbias_Atex (HC_XTC_Atex << 14)
+#define HC_HTXnTBLCbias_Acur (HC_XTC_Acur << 14)
+#define HC_HTXnTBLCbias_HTXnTBLRC (HC_XTC_HTXnTBLRC << 14)
+#define HC_HTXnTBLCshift_1 0x00000000
+#define HC_HTXnTBLCshift_2 0x00000800
+#define HC_HTXnTBLCshift_No 0x00001000
+#define HC_HTXnTBLCshift_DotP 0x00001800
+/*=* John Sheng [2003.7.18] texture combine *=*/
+#define HC_HTXnTBLDOT3 0x00080000
+#define HC_HTXnTBLDOT4 0x000C0000
+
+#define HC_HTXnTBLAop_Add 0x00000000
+#define HC_HTXnTBLAop_Sub 0x00000080
+#define HC_HTXnTBLAop_Min 0x00000100
+#define HC_HTXnTBLAop_Max 0x00000180
+#define HC_HTXnTBLAop_Mask 0x00000200
+#define HC_HTXnTBLAbias_Inv 0x00000040
+#define HC_HTXnTBLAbias_Adif 0x00000000
+#define HC_HTXnTBLAbias_Fog 0x00000008
+#define HC_HTXnTBLAbias_Acur 0x00000010
+#define HC_HTXnTBLAbias_HTXnTBLRAbias 0x00000018
+#define HC_HTXnTBLAbias_Atex 0x00000020
+#define HC_HTXnTBLAshift_1 0x00000000
+#define HC_HTXnTBLAshift_2 0x00000001
+#define HC_HTXnTBLAshift_No 0x00000002
+/* #define HC_HTXnTBLAshift_DotP 0x00000003 */
+/* HC_SubA_HTXnTBLMPFog 0x0082
+ */
+#define HC_HTXnTBLMPfog_MASK 0x00e00000
+#define HC_HTXnTBLMPfog_0 0x00000000
+#define HC_HTXnTBLMPfog_Adif 0x00200000
+#define HC_HTXnTBLMPfog_Fog 0x00400000
+#define HC_HTXnTBLMPfog_Atex 0x00600000
+#define HC_HTXnTBLMPfog_Acur 0x00800000
+#define HC_HTXnTBLMPfog_GHTXnTBLRFog 0x00a00000
+/* HC_SubA_HTXnTBLAsat 0x0083
+ *-- Define the texture alpha input.
+ */
+#define HC_XTA_TOPA 0x00000000
+#define HC_XTA_InvTOPA 0x00000008
+#define HC_XTA_TOPAp5 0x00000010
+#define HC_XTA_Adif 0x00000000
+#define HC_XTA_Fog 0x00000001
+#define HC_XTA_Acur 0x00000002
+#define HC_XTA_HTXnTBLRA 0x00000003
+#define HC_XTA_Atex 0x00000004
+#define HC_XTA_Atexnext 0x00000005
+/*--
+ */
+#define HC_HTXnTBLAsat_MASK 0x00800000
+#define HC_HTXnTBLAMB_MASK 0x00700000
+#define HC_HTXnTBLAa_MASK 0x0007c000
+#define HC_HTXnTBLAb_MASK 0x00000f80
+#define HC_HTXnTBLAc_MASK 0x0000001f
+#define HC_HTXnTBLAMB_SHIFT 20
+#define HC_HTXnTBLAa_TOPA (HC_XTA_TOPA << 14)
+#define HC_HTXnTBLAa_InvTOPA (HC_XTA_InvTOPA << 14)
+#define HC_HTXnTBLAa_TOPAp5 (HC_XTA_TOPAp5 << 14)
+#define HC_HTXnTBLAa_Adif (HC_XTA_Adif << 14)
+#define HC_HTXnTBLAa_Fog (HC_XTA_Fog << 14)
+#define HC_HTXnTBLAa_Acur (HC_XTA_Acur << 14)
+#define HC_HTXnTBLAa_HTXnTBLRA (HC_XTA_HTXnTBLRA << 14)
+#define HC_HTXnTBLAa_Atex (HC_XTA_Atex << 14)
+#define HC_HTXnTBLAa_Atexnext (HC_XTA_Atexnext << 14)
+#define HC_HTXnTBLAb_TOPA (HC_XTA_TOPA << 7)
+#define HC_HTXnTBLAb_InvTOPA (HC_XTA_InvTOPA << 7)
+#define HC_HTXnTBLAb_TOPAp5 (HC_XTA_TOPAp5 << 7)
+#define HC_HTXnTBLAb_Adif (HC_XTA_Adif << 7)
+#define HC_HTXnTBLAb_Fog (HC_XTA_Fog << 7)
+#define HC_HTXnTBLAb_Acur (HC_XTA_Acur << 7)
+#define HC_HTXnTBLAb_HTXnTBLRA (HC_XTA_HTXnTBLRA << 7)
+#define HC_HTXnTBLAb_Atex (HC_XTA_Atex << 7)
+#define HC_HTXnTBLAb_Atexnext (HC_XTA_Atexnext << 7)
+#define HC_HTXnTBLAc_TOPA (HC_XTA_TOPA << 0)
+#define HC_HTXnTBLAc_InvTOPA (HC_XTA_InvTOPA << 0)
+#define HC_HTXnTBLAc_TOPAp5 (HC_XTA_TOPAp5 << 0)
+#define HC_HTXnTBLAc_Adif (HC_XTA_Adif << 0)
+#define HC_HTXnTBLAc_Fog (HC_XTA_Fog << 0)
+#define HC_HTXnTBLAc_Acur (HC_XTA_Acur << 0)
+#define HC_HTXnTBLAc_HTXnTBLRA (HC_XTA_HTXnTBLRA << 0)
+#define HC_HTXnTBLAc_Atex (HC_XTA_Atex << 0)
+#define HC_HTXnTBLAc_Atexnext (HC_XTA_Atexnext << 0)
+/* HC_SubA_HTXnTBLRAa 0x0089
+ */
+#define HC_HTXnTBLRAa_MASK 0x00ff0000
+#define HC_HTXnTBLRAb_MASK 0x0000ff00
+#define HC_HTXnTBLRAc_MASK 0x000000ff
+#define HC_HTXnTBLRAa_SHIFT 16
+#define HC_HTXnTBLRAb_SHIFT 8
+#define HC_HTXnTBLRAc_SHIFT 0
+/* HC_SubA_HTXnTBLRFog 0x008a
+ */
+#define HC_HTXnTBLRFog_MASK 0x0000ff00
+#define HC_HTXnTBLRAbias_MASK 0x000000ff
+#define HC_HTXnTBLRFog_SHIFT 8
+#define HC_HTXnTBLRAbias_SHIFT 0
+/* HC_SubA_HTXnLScale 0x0094
+ */
+#define HC_HTXnLScale_MASK 0x0007fc00
+#define HC_HTXnLOff_MASK 0x000001ff
+#define HC_HTXnLScale_SHIFT 10
+/* HC_SubA_HTXSMD 0x0000
+ */
+#define HC_HTXSMD_MASK 0x00000080
+#define HC_HTXTMD_MASK 0x00000040
+#define HC_HTXNum_MASK 0x00000038
+#define HC_HTXTRMD_MASK 0x00000006
+#define HC_HTXCHCLR_MASK 0x00000001
+#define HC_HTXNum_SHIFT 3
+
+/* Texture Palette n
+ */
+#define HC_SubType_TexPalette0 0x00000000
+#define HC_SubType_TexPalette1 0x00000001
+#define HC_SubType_FogTable 0x00000010
+#define HC_SubType_Stipple 0x00000014
+/* HC_SubA_TexPalette0 0x0000
+ */
+#define HC_HTPnA_MASK 0xff000000
+#define HC_HTPnR_MASK 0x00ff0000
+#define HC_HTPnG_MASK 0x0000ff00
+#define HC_HTPnB_MASK 0x000000ff
+/* HC_SubA_FogTable 0x0010
+ */
+#define HC_HFPn3_MASK 0xff000000
+#define HC_HFPn2_MASK 0x00ff0000
+#define HC_HFPn1_MASK 0x0000ff00
+#define HC_HFPn_MASK 0x000000ff
+#define HC_HFPn3_SHIFT 24
+#define HC_HFPn2_SHIFT 16
+#define HC_HFPn1_SHIFT 8
+
+/* Auto Testing & Security
+ */
+#define HC_SubA_HenFIFOAT 0x0000
+#define HC_SubA_HFBDrawFirst 0x0004
+#define HC_SubA_HFBBasL 0x0005
+#define HC_SubA_HFBDst 0x0006
+/* HC_SubA_HenFIFOAT 0x0000
+ */
+#define HC_HenFIFOAT_MASK 0x00000020
+#define HC_HenGEMILock_MASK 0x00000010
+#define HC_HenFBASwap_MASK 0x00000008
+#define HC_HenOT_MASK 0x00000004
+#define HC_HenCMDQ_MASK 0x00000002
+#define HC_HenTXCTSU_MASK 0x00000001
+/* HC_SubA_HFBDrawFirst 0x0004
+ */
+#define HC_HFBDrawFirst_MASK 0x00000800
+#define HC_HFBQueue_MASK 0x00000400
+#define HC_HFBLock_MASK 0x00000200
+#define HC_HEOF_MASK 0x00000100
+#define HC_HFBBasH_MASK 0x000000ff
+
+/* GEMI Setting
+ */
+#define HC_SubA_HTArbRCM 0x0008
+#define HC_SubA_HTArbRZ 0x000a
+#define HC_SubA_HTArbWZ 0x000b
+#define HC_SubA_HTArbRTX 0x000c
+#define HC_SubA_HTArbRCW 0x000d
+#define HC_SubA_HTArbE2 0x000e
+#define HC_SubA_HArbRQCM 0x0010
+#define HC_SubA_HArbWQCM 0x0011
+#define HC_SubA_HGEMITout 0x0020
+#define HC_SubA_HFthRTXD 0x0040
+#define HC_SubA_HFthRTXA 0x0044
+#define HC_SubA_HCMDQstL 0x0050
+#define HC_SubA_HCMDQendL 0x0051
+#define HC_SubA_HCMDQLen 0x0052
+/* HC_SubA_HTArbRCM 0x0008
+ */
+#define HC_HTArbRCM_MASK 0x0000ffff
+/* HC_SubA_HTArbRZ 0x000a
+ */
+#define HC_HTArbRZ_MASK 0x0000ffff
+/* HC_SubA_HTArbWZ 0x000b
+ */
+#define HC_HTArbWZ_MASK 0x0000ffff
+/* HC_SubA_HTArbRTX 0x000c
+ */
+#define HC_HTArbRTX_MASK 0x0000ffff
+/* HC_SubA_HTArbRCW 0x000d
+ */
+#define HC_HTArbRCW_MASK 0x0000ffff
+/* HC_SubA_HTArbE2 0x000e
+ */
+#define HC_HTArbE2_MASK 0x0000ffff
+/* HC_SubA_HArbRQCM 0x0010
+ */
+#define HC_HTArbRQCM_MASK 0x0000ffff
+/* HC_SubA_HArbWQCM 0x0011
+ */
+#define HC_HArbWQCM_MASK 0x0000ffff
+/* HC_SubA_HGEMITout 0x0020
+ */
+#define HC_HGEMITout_MASK 0x000f0000
+#define HC_HNPArbZC_MASK 0x0000ffff
+#define HC_HGEMITout_SHIFT 16
+/* HC_SubA_HFthRTXD 0x0040
+ */
+#define HC_HFthRTXD_MASK 0x00ff0000
+#define HC_HFthRZD_MASK 0x0000ff00
+#define HC_HFthWZD_MASK 0x000000ff
+#define HC_HFthRTXD_SHIFT 16
+#define HC_HFthRZD_SHIFT 8
+/* HC_SubA_HFthRTXA 0x0044
+ */
+#define HC_HFthRTXA_MASK 0x000000ff
+
+/******************************************************************************
+** Define the Halcyon Internal register access constants. For simulator only.
+******************************************************************************/
+#define HC_SIMA_HAGPBstL 0x0000
+#define HC_SIMA_HAGPBendL 0x0001
+#define HC_SIMA_HAGPCMNT 0x0002
+#define HC_SIMA_HAGPBpL 0x0003
+#define HC_SIMA_HAGPBpH 0x0004
+#define HC_SIMA_HClipTB 0x0005
+#define HC_SIMA_HClipLR 0x0006
+#define HC_SIMA_HFPClipTL 0x0007
+#define HC_SIMA_HFPClipBL 0x0008
+#define HC_SIMA_HFPClipLL 0x0009
+#define HC_SIMA_HFPClipRL 0x000a
+#define HC_SIMA_HFPClipTBH 0x000b
+#define HC_SIMA_HFPClipLRH 0x000c
+#define HC_SIMA_HLP 0x000d
+#define HC_SIMA_HLPRF 0x000e
+#define HC_SIMA_HSolidCL 0x000f
+#define HC_SIMA_HPixGC 0x0010
+#define HC_SIMA_HSPXYOS 0x0011
+#define HC_SIMA_HCmdA 0x0012
+#define HC_SIMA_HCmdB 0x0013
+#define HC_SIMA_HEnable 0x0014
+#define HC_SIMA_HZWBBasL 0x0015
+#define HC_SIMA_HZWBBasH 0x0016
+#define HC_SIMA_HZWBType 0x0017
+#define HC_SIMA_HZBiasL 0x0018
+#define HC_SIMA_HZWBend 0x0019
+#define HC_SIMA_HZWTMD 0x001a
+#define HC_SIMA_HZWCDL 0x001b
+#define HC_SIMA_HZWCTAGnum 0x001c
+#define HC_SIMA_HZCYNum 0x001d
+#define HC_SIMA_HZWCFire 0x001e
+/* #define HC_SIMA_HSBBasL 0x001d */
+/* #define HC_SIMA_HSBBasH 0x001e */
+/* #define HC_SIMA_HSBFM 0x001f */
+#define HC_SIMA_HSTREF 0x0020
+#define HC_SIMA_HSTMD 0x0021
+#define HC_SIMA_HABBasL 0x0022
+#define HC_SIMA_HABBasH 0x0023
+#define HC_SIMA_HABFM 0x0024
+#define HC_SIMA_HATMD 0x0025
+#define HC_SIMA_HABLCsat 0x0026
+#define HC_SIMA_HABLCop 0x0027
+#define HC_SIMA_HABLAsat 0x0028
+#define HC_SIMA_HABLAop 0x0029
+#define HC_SIMA_HABLRCa 0x002a
+#define HC_SIMA_HABLRFCa 0x002b
+#define HC_SIMA_HABLRCbias 0x002c
+#define HC_SIMA_HABLRCb 0x002d
+#define HC_SIMA_HABLRFCb 0x002e
+#define HC_SIMA_HABLRAa 0x002f
+#define HC_SIMA_HABLRAb 0x0030
+#define HC_SIMA_HDBBasL 0x0031
+#define HC_SIMA_HDBBasH 0x0032
+#define HC_SIMA_HDBFM 0x0033
+#define HC_SIMA_HFBBMSKL 0x0034
+#define HC_SIMA_HROP 0x0035
+#define HC_SIMA_HFogLF 0x0036
+#define HC_SIMA_HFogCL 0x0037
+#define HC_SIMA_HFogCH 0x0038
+#define HC_SIMA_HFogStL 0x0039
+#define HC_SIMA_HFogStH 0x003a
+#define HC_SIMA_HFogOOdMF 0x003b
+#define HC_SIMA_HFogOOdEF 0x003c
+#define HC_SIMA_HFogEndL 0x003d
+#define HC_SIMA_HFogDenst 0x003e
+/*---- start of texture 0 setting ----
+ */
+#define HC_SIMA_HTX0L0BasL 0x0040
+#define HC_SIMA_HTX0L1BasL 0x0041
+#define HC_SIMA_HTX0L2BasL 0x0042
+#define HC_SIMA_HTX0L3BasL 0x0043
+#define HC_SIMA_HTX0L4BasL 0x0044
+#define HC_SIMA_HTX0L5BasL 0x0045
+#define HC_SIMA_HTX0L6BasL 0x0046
+#define HC_SIMA_HTX0L7BasL 0x0047
+#define HC_SIMA_HTX0L8BasL 0x0048
+#define HC_SIMA_HTX0L9BasL 0x0049
+#define HC_SIMA_HTX0LaBasL 0x004a
+#define HC_SIMA_HTX0LbBasL 0x004b
+#define HC_SIMA_HTX0LcBasL 0x004c
+#define HC_SIMA_HTX0LdBasL 0x004d
+#define HC_SIMA_HTX0LeBasL 0x004e
+#define HC_SIMA_HTX0LfBasL 0x004f
+#define HC_SIMA_HTX0L10BasL 0x0050
+#define HC_SIMA_HTX0L11BasL 0x0051
+#define HC_SIMA_HTX0L012BasH 0x0052
+#define HC_SIMA_HTX0L345BasH 0x0053
+#define HC_SIMA_HTX0L678BasH 0x0054
+#define HC_SIMA_HTX0L9abBasH 0x0055
+#define HC_SIMA_HTX0LcdeBasH 0x0056
+#define HC_SIMA_HTX0Lf1011BasH 0x0057
+#define HC_SIMA_HTX0L0Pit 0x0058
+#define HC_SIMA_HTX0L1Pit 0x0059
+#define HC_SIMA_HTX0L2Pit 0x005a
+#define HC_SIMA_HTX0L3Pit 0x005b
+#define HC_SIMA_HTX0L4Pit 0x005c
+#define HC_SIMA_HTX0L5Pit 0x005d
+#define HC_SIMA_HTX0L6Pit 0x005e
+#define HC_SIMA_HTX0L7Pit 0x005f
+#define HC_SIMA_HTX0L8Pit 0x0060
+#define HC_SIMA_HTX0L9Pit 0x0061
+#define HC_SIMA_HTX0LaPit 0x0062
+#define HC_SIMA_HTX0LbPit 0x0063
+#define HC_SIMA_HTX0LcPit 0x0064
+#define HC_SIMA_HTX0LdPit 0x0065
+#define HC_SIMA_HTX0LePit 0x0066
+#define HC_SIMA_HTX0LfPit 0x0067
+#define HC_SIMA_HTX0L10Pit 0x0068
+#define HC_SIMA_HTX0L11Pit 0x0069
+#define HC_SIMA_HTX0L0_5WE 0x006a
+#define HC_SIMA_HTX0L6_bWE 0x006b
+#define HC_SIMA_HTX0Lc_11WE 0x006c
+#define HC_SIMA_HTX0L0_5HE 0x006d
+#define HC_SIMA_HTX0L6_bHE 0x006e
+#define HC_SIMA_HTX0Lc_11HE 0x006f
+#define HC_SIMA_HTX0L0OS 0x0070
+#define HC_SIMA_HTX0TB 0x0071
+#define HC_SIMA_HTX0MPMD 0x0072
+#define HC_SIMA_HTX0CLODu 0x0073
+#define HC_SIMA_HTX0FM 0x0074
+#define HC_SIMA_HTX0TRCH 0x0075
+#define HC_SIMA_HTX0TRCL 0x0076
+#define HC_SIMA_HTX0TBC 0x0077
+#define HC_SIMA_HTX0TRAH 0x0078
+#define HC_SIMA_HTX0TBLCsat 0x0079
+#define HC_SIMA_HTX0TBLCop 0x007a
+#define HC_SIMA_HTX0TBLMPfog 0x007b
+#define HC_SIMA_HTX0TBLAsat 0x007c
+#define HC_SIMA_HTX0TBLRCa 0x007d
+#define HC_SIMA_HTX0TBLRCb 0x007e
+#define HC_SIMA_HTX0TBLRCc 0x007f
+#define HC_SIMA_HTX0TBLRCbias 0x0080
+#define HC_SIMA_HTX0TBLRAa 0x0081
+#define HC_SIMA_HTX0TBLRFog 0x0082
+#define HC_SIMA_HTX0BumpM00 0x0083
+#define HC_SIMA_HTX0BumpM01 0x0084
+#define HC_SIMA_HTX0BumpM10 0x0085
+#define HC_SIMA_HTX0BumpM11 0x0086
+#define HC_SIMA_HTX0LScale 0x0087
+/*---- end of texture 0 setting ---- 0x008f
+ */
+#define HC_SIMA_TX0TX1_OFF 0x0050
+/*---- start of texture 1 setting ----
+ */
+#define HC_SIMA_HTX1L0BasL (HC_SIMA_HTX0L0BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L1BasL (HC_SIMA_HTX0L1BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L2BasL (HC_SIMA_HTX0L2BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L3BasL (HC_SIMA_HTX0L3BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L4BasL (HC_SIMA_HTX0L4BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L5BasL (HC_SIMA_HTX0L5BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6BasL (HC_SIMA_HTX0L6BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L7BasL (HC_SIMA_HTX0L7BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L8BasL (HC_SIMA_HTX0L8BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9BasL (HC_SIMA_HTX0L9BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LaBasL (HC_SIMA_HTX0LaBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LbBasL (HC_SIMA_HTX0LbBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcBasL (HC_SIMA_HTX0LcBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LdBasL (HC_SIMA_HTX0LdBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LeBasL (HC_SIMA_HTX0LeBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LfBasL (HC_SIMA_HTX0LfBasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L10BasL (HC_SIMA_HTX0L10BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L11BasL (HC_SIMA_HTX0L11BasL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L012BasH (HC_SIMA_HTX0L012BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L345BasH (HC_SIMA_HTX0L345BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L678BasH (HC_SIMA_HTX0L678BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9abBasH (HC_SIMA_HTX0L9abBasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcdeBasH (HC_SIMA_HTX0LcdeBasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lf1011BasH (HC_SIMA_HTX0Lf1011BasH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0Pit (HC_SIMA_HTX0L0Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L1Pit (HC_SIMA_HTX0L1Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L2Pit (HC_SIMA_HTX0L2Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L3Pit (HC_SIMA_HTX0L3Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L4Pit (HC_SIMA_HTX0L4Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L5Pit (HC_SIMA_HTX0L5Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6Pit (HC_SIMA_HTX0L6Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L7Pit (HC_SIMA_HTX0L7Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L8Pit (HC_SIMA_HTX0L8Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L9Pit (HC_SIMA_HTX0L9Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LaPit (HC_SIMA_HTX0LaPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LbPit (HC_SIMA_HTX0LbPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LcPit (HC_SIMA_HTX0LcPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LdPit (HC_SIMA_HTX0LdPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LePit (HC_SIMA_HTX0LePit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LfPit (HC_SIMA_HTX0LfPit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L10Pit (HC_SIMA_HTX0L10Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L11Pit (HC_SIMA_HTX0L11Pit + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0_5WE (HC_SIMA_HTX0L0_5WE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6_bWE (HC_SIMA_HTX0L6_bWE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lc_11WE (HC_SIMA_HTX0Lc_11WE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0_5HE (HC_SIMA_HTX0L0_5HE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L6_bHE (HC_SIMA_HTX0L6_bHE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1Lc_11HE (HC_SIMA_HTX0Lc_11HE + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1L0OS (HC_SIMA_HTX0L0OS + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TB (HC_SIMA_HTX0TB + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1MPMD (HC_SIMA_HTX0MPMD + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1CLODu (HC_SIMA_HTX0CLODu + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1FM (HC_SIMA_HTX0FM + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRCH (HC_SIMA_HTX0TRCH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRCL (HC_SIMA_HTX0TRCL + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBC (HC_SIMA_HTX0TBC + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TRAH (HC_SIMA_HTX0TRAH + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LTC (HC_SIMA_HTX0LTC + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LTA (HC_SIMA_HTX0LTA + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLCsat (HC_SIMA_HTX0TBLCsat + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLCop (HC_SIMA_HTX0TBLCop + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLMPfog (HC_SIMA_HTX0TBLMPfog + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLAsat (HC_SIMA_HTX0TBLAsat + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCa (HC_SIMA_HTX0TBLRCa + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCb (HC_SIMA_HTX0TBLRCb + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCc (HC_SIMA_HTX0TBLRCc + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRCbias (HC_SIMA_HTX0TBLRCbias + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRAa (HC_SIMA_HTX0TBLRAa + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1TBLRFog (HC_SIMA_HTX0TBLRFog + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM00 (HC_SIMA_HTX0BumpM00 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM01 (HC_SIMA_HTX0BumpM01 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM10 (HC_SIMA_HTX0BumpM10 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1BumpM11 (HC_SIMA_HTX0BumpM11 + HC_SIMA_TX0TX1_OFF)
+#define HC_SIMA_HTX1LScale (HC_SIMA_HTX0LScale + HC_SIMA_TX0TX1_OFF)
+/*---- end of texture 1 setting ---- 0xaf
+ */
+#define HC_SIMA_HTXSMD 0x00b0
+#define HC_SIMA_HenFIFOAT 0x00b1
+#define HC_SIMA_HFBDrawFirst 0x00b2
+#define HC_SIMA_HFBBasL 0x00b3
+#define HC_SIMA_HTArbRCM 0x00b4
+#define HC_SIMA_HTArbRZ 0x00b5
+#define HC_SIMA_HTArbWZ 0x00b6
+#define HC_SIMA_HTArbRTX 0x00b7
+#define HC_SIMA_HTArbRCW 0x00b8
+#define HC_SIMA_HTArbE2 0x00b9
+#define HC_SIMA_HGEMITout 0x00ba
+#define HC_SIMA_HFthRTXD 0x00bb
+#define HC_SIMA_HFthRTXA 0x00bc
+/* Define the texture palette 0
+ */
+#define HC_SIMA_HTP0 0x0100
+#define HC_SIMA_HTP1 0x0200
+#define HC_SIMA_FOGTABLE 0x0300
+#define HC_SIMA_STIPPLE 0x0400
+#define HC_SIMA_HE3Fire 0x0440
+#define HC_SIMA_TRANS_SET 0x0441
+#define HC_SIMA_HREngSt 0x0442
+#define HC_SIMA_HRFIFOempty 0x0443
+#define HC_SIMA_HRFIFOfull 0x0444
+#define HC_SIMA_HRErr 0x0445
+#define HC_SIMA_FIFOstatus 0x0446
+
+/******************************************************************************
+** Define the AGP command header.
+******************************************************************************/
+#define HC_ACMD_MASK 0xfe000000
+#define HC_ACMD_SUB_MASK 0x0c000000
+#define HC_ACMD_HCmdA 0xee000000
+#define HC_ACMD_HCmdB 0xec000000
+#define HC_ACMD_HCmdC 0xea000000
+#define HC_ACMD_H1 0xf0000000
+#define HC_ACMD_H2 0xf2000000
+#define HC_ACMD_H3 0xf4000000
+#define HC_ACMD_H4 0xf6000000
+
+#define HC_ACMD_H1IO_MASK 0x000001ff
+#define HC_ACMD_H2IO1_MASK 0x001ff000
+#define HC_ACMD_H2IO2_MASK 0x000001ff
+#define HC_ACMD_H2IO1_SHIFT 12
+#define HC_ACMD_H2IO2_SHIFT 0
+#define HC_ACMD_H3IO_MASK 0x000001ff
+#define HC_ACMD_H3COUNT_MASK 0x01fff000
+#define HC_ACMD_H3COUNT_SHIFT 12
+#define HC_ACMD_H4ID_MASK 0x000001ff
+#define HC_ACMD_H4COUNT_MASK 0x01fffe00
+#define HC_ACMD_H4COUNT_SHIFT 9
+
+/********************************************************************************
+** Define Header
+********************************************************************************/
+#define HC_HEADER2 0xF210F110
+
+/********************************************************************************
+** Define Dummy Value
+********************************************************************************/
+#define HC_DUMMY 0xCCCCCCCC
+/********************************************************************************
+** Define for DMA use
+********************************************************************************/
+#define HALCYON_HEADER2 0XF210F110
+#define HALCYON_FIRECMD 0XEE100000
+#define HALCYON_FIREMASK 0XFFF00000
+#define HALCYON_CMDB 0XEC000000
+#define HALCYON_CMDBMASK 0XFFFE0000
+#define HALCYON_SUB_ADDR0 0X00000000
+#define HALCYON_HEADER1MASK 0XFFFFFC00
+#define HALCYON_HEADER1 0XF0000000
+#define HC_SubA_HAGPBstL 0x0060
+#define HC_SubA_HAGPBendL 0x0061
+#define HC_SubA_HAGPCMNT 0x0062
+#define HC_SubA_HAGPBpL 0x0063
+#define HC_SubA_HAGPBpH 0x0064
+#define HC_HAGPCMNT_MASK 0x00800000
+#define HC_HCmdErrClr_MASK 0x00400000
+#define HC_HAGPBendH_MASK 0x0000ff00
+#define HC_HAGPBstH_MASK 0x000000ff
+#define HC_HAGPBendH_SHIFT 8
+#define HC_HAGPBstH_SHIFT 0
+#define HC_HAGPBpL_MASK 0x00fffffc
+#define HC_HAGPBpID_MASK 0x00000003
+#define HC_HAGPBpID_PAUSE 0x00000000
+#define HC_HAGPBpID_JUMP 0x00000001
+#define HC_HAGPBpID_STOP 0x00000002
+#define HC_HAGPBpH_MASK 0x00ffffff
+
+
+#define VIA_VIDEO_HEADER5 0xFE040000
+#define VIA_VIDEO_HEADER6 0xFE050000
+#define VIA_VIDEO_HEADER7 0xFE060000
+#define VIA_VIDEOMASK 0xFFFF0000
+#endif
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
new file mode 100644
index 000000000000..82f839451622
--- /dev/null
+++ b/drivers/char/drm/via_dma.c
@@ -0,0 +1,741 @@
+/* via_dma.c -- DMA support for the VIA Unichrome/Pro
+ *
+ * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
+ * All Rights Reserved.
+ *
+ * Copyright 2004 The Unichrome project.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS 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.
+ *
+ * Authors:
+ * Tungsten Graphics,
+ * Erdi Chen,
+ * Thomas Hellstrom.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_drv.h"
+#include "via_3d_reg.h"
+
+#define CMDBUF_ALIGNMENT_SIZE (0x100)
+#define CMDBUF_ALIGNMENT_MASK (0x0ff)
+
+/* defines for VIA 3D registers */
+#define VIA_REG_STATUS 0x400
+#define VIA_REG_TRANSET 0x43C
+#define VIA_REG_TRANSPACE 0x440
+
+/* VIA_REG_STATUS(0x400): Engine Status */
+#define VIA_CMD_RGTR_BUSY 0x00000080 /* Command Regulator is busy */
+#define VIA_2D_ENG_BUSY 0x00000001 /* 2D Engine is busy */
+#define VIA_3D_ENG_BUSY 0x00000002 /* 3D Engine is busy */
+#define VIA_VR_QUEUE_BUSY 0x00020000 /* Virtual Queue is busy */
+
+#define SetReg2DAGP(nReg, nData) { \
+ *((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1; \
+ *((uint32_t *)(vb) + 1) = (nData); \
+ vb = ((uint32_t *)vb) + 2; \
+ dev_priv->dma_low +=8; \
+}
+
+#define via_flush_write_combine() DRM_MEMORYBARRIER()
+
+#define VIA_OUT_RING_QW(w1,w2) \
+ *vb++ = (w1); \
+ *vb++ = (w2); \
+ dev_priv->dma_low += 8;
+
+static void via_cmdbuf_start(drm_via_private_t * dev_priv);
+static void via_cmdbuf_pause(drm_via_private_t * dev_priv);
+static void via_cmdbuf_reset(drm_via_private_t * dev_priv);
+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv);
+static int via_wait_idle(drm_via_private_t * dev_priv);
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);
+
+
+/*
+ * Free space in command buffer.
+ */
+
+static uint32_t
+via_cmdbuf_space(drm_via_private_t *dev_priv)
+{
+ uint32_t agp_base = dev_priv->dma_offset +
+ (uint32_t) dev_priv->agpAddr;
+ uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
+
+ return ((hw_addr <= dev_priv->dma_low) ?
+ (dev_priv->dma_high + hw_addr - dev_priv->dma_low) :
+ (hw_addr - dev_priv->dma_low));
+}
+
+/*
+ * How much does the command regulator lag behind?
+ */
+
+static uint32_t
+via_cmdbuf_lag(drm_via_private_t *dev_priv)
+{
+ uint32_t agp_base = dev_priv->dma_offset +
+ (uint32_t) dev_priv->agpAddr;
+ uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
+
+ return ((hw_addr <= dev_priv->dma_low) ?
+ (dev_priv->dma_low - hw_addr) :
+ (dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
+}
+
+/*
+ * Check that the given size fits in the buffer, otherwise wait.
+ */
+
+static inline int
+via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
+{
+ uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+ uint32_t cur_addr, hw_addr, next_addr;
+ volatile uint32_t *hw_addr_ptr;
+ uint32_t count;
+ hw_addr_ptr = dev_priv->hw_addr_ptr;
+ cur_addr = dev_priv->dma_low;
+ next_addr = cur_addr + size + 512*1024;
+ count = 1000000;
+ do {
+ hw_addr = *hw_addr_ptr - agp_base;
+ if (count-- == 0) {
+ DRM_ERROR("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
+ hw_addr, cur_addr, next_addr);
+ return -1;
+ }
+ } while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
+ return 0;
+}
+
+
+/*
+ * Checks whether buffer head has reach the end. Rewind the ring buffer
+ * when necessary.
+ *
+ * Returns virtual pointer to ring buffer.
+ */
+
+static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
+ unsigned int size)
+{
+ if ((dev_priv->dma_low + size + 4*CMDBUF_ALIGNMENT_SIZE) > dev_priv->dma_high) {
+ via_cmdbuf_rewind(dev_priv);
+ }
+ if (via_cmdbuf_wait(dev_priv, size) != 0) {
+ return NULL;
+ }
+
+ return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
+}
+
+int via_dma_cleanup(drm_device_t * dev)
+{
+ if (dev->dev_private) {
+ drm_via_private_t *dev_priv =
+ (drm_via_private_t *) dev->dev_private;
+
+ if (dev_priv->ring.virtual_start) {
+ via_cmdbuf_reset(dev_priv);
+
+ drm_core_ioremapfree(&dev_priv->ring.map, dev);
+ dev_priv->ring.virtual_start = NULL;
+ }
+
+ }
+
+ return 0;
+}
+
+static int via_initialize(drm_device_t * dev,
+ drm_via_private_t * dev_priv,
+ drm_via_dma_init_t * init)
+{
+ if (!dev_priv || !dev_priv->mmio) {
+ DRM_ERROR("via_dma_init called before via_map_init\n");
+ return DRM_ERR(EFAULT);
+ }
+
+ if (dev_priv->ring.virtual_start != NULL) {
+ DRM_ERROR("%s called again without calling cleanup\n",
+ __FUNCTION__);
+ return DRM_ERR(EFAULT);
+ }
+
+ if (!dev->agp || !dev->agp->base) {
+ DRM_ERROR("%s called with no agp memory available\n",
+ __FUNCTION__);
+ return DRM_ERR(EFAULT);
+ }
+
+ dev_priv->ring.map.offset = dev->agp->base + init->offset;
+ dev_priv->ring.map.size = init->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) {
+ via_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->dma_ptr = dev_priv->ring.virtual_start;
+ dev_priv->dma_low = 0;
+ dev_priv->dma_high = init->size;
+ dev_priv->dma_wrap = init->size;
+ dev_priv->dma_offset = init->offset;
+ dev_priv->last_pause_ptr = NULL;
+ dev_priv->hw_addr_ptr = dev_priv->mmio->handle + init->reg_pause_addr;
+
+ via_cmdbuf_start(dev_priv);
+
+ return 0;
+}
+
+int via_dma_init(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_dma_init_t init;
+ int retcode = 0;
+
+ DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t *) data,
+ sizeof(init));
+
+ switch (init.func) {
+ case VIA_INIT_DMA:
+ if (!capable(CAP_SYS_ADMIN))
+ retcode = DRM_ERR(EPERM);
+ else
+ retcode = via_initialize(dev, dev_priv, &init);
+ break;
+ case VIA_CLEANUP_DMA:
+ if (!capable(CAP_SYS_ADMIN))
+ retcode = DRM_ERR(EPERM);
+ else
+ retcode = via_dma_cleanup(dev);
+ break;
+ case VIA_DMA_INITIALIZED:
+ retcode = (dev_priv->ring.virtual_start != NULL) ?
+ 0: DRM_ERR( EFAULT );
+ break;
+ default:
+ retcode = DRM_ERR(EINVAL);
+ break;
+ }
+
+ return retcode;
+}
+
+
+
+static int via_dispatch_cmdbuffer(drm_device_t * dev, drm_via_cmdbuffer_t * cmd)
+{
+ drm_via_private_t *dev_priv;
+ uint32_t *vb;
+ int ret;
+
+ dev_priv = (drm_via_private_t *) dev->dev_private;
+
+ if (dev_priv->ring.virtual_start == NULL) {
+ DRM_ERROR("%s called without initializing AGP ring buffer.\n",
+ __FUNCTION__);
+ return DRM_ERR(EFAULT);
+ }
+
+ if (cmd->size > VIA_PCI_BUF_SIZE) {
+ return DRM_ERR(ENOMEM);
+ }
+
+
+ if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+ return DRM_ERR(EFAULT);
+
+ /*
+ * Running this function on AGP memory is dead slow. Therefore
+ * we run it on a temporary cacheable system memory buffer and
+ * copy it to AGP memory when ready.
+ */
+
+
+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 1))) {
+ return ret;
+ }
+
+
+ vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
+ if (vb == NULL) {
+ return DRM_ERR(EAGAIN);
+ }
+
+ memcpy(vb, dev_priv->pci_buf, cmd->size);
+
+ dev_priv->dma_low += cmd->size;
+
+ /*
+ * Small submissions somehow stalls the CPU. (AGP cache effects?)
+ * pad to greater size.
+ */
+
+ if (cmd->size < 0x100)
+ via_pad_cache(dev_priv,(0x100 - cmd->size) >> 3);
+ via_cmdbuf_pause(dev_priv);
+
+ return 0;
+}
+
+int via_driver_dma_quiescent(drm_device_t * dev)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+
+ if (!via_wait_idle(dev_priv)) {
+ return DRM_ERR(EBUSY);
+ }
+ return 0;
+}
+
+int via_flush_ioctl(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+
+ LOCK_TEST_WITH_RETURN( dev, filp );
+
+ return via_driver_dma_quiescent(dev);
+}
+
+int via_cmdbuffer(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_cmdbuffer_t cmdbuf;
+ int ret;
+
+ LOCK_TEST_WITH_RETURN( dev, filp );
+
+ DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,
+ sizeof(cmdbuf));
+
+ DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+
+ ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
+extern int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size);
+static int via_dispatch_pci_cmdbuffer(drm_device_t * dev,
+ drm_via_cmdbuffer_t * cmd)
+{
+ drm_via_private_t *dev_priv = dev->dev_private;
+ int ret;
+
+ if (cmd->size > VIA_PCI_BUF_SIZE) {
+ return DRM_ERR(ENOMEM);
+ }
+ if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+ return DRM_ERR(EFAULT);
+
+ if ((ret = via_verify_command_stream((uint32_t *)dev_priv->pci_buf, cmd->size, dev, 0))) {
+ return ret;
+ }
+
+ ret = via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf, cmd->size);
+ return ret;
+}
+
+int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_cmdbuffer_t cmdbuf;
+ int ret;
+
+ LOCK_TEST_WITH_RETURN( dev, filp );
+
+ DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t *) data,
+ sizeof(cmdbuf));
+
+ DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
+ cmdbuf.size);
+
+ ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+ if (ret) {
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,
+ uint32_t * vb, int qw_count)
+{
+ for (; qw_count > 0; --qw_count) {
+ VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
+ }
+ return vb;
+}
+
+
+/*
+ * This function is used internally by ring buffer mangement code.
+ *
+ * Returns virtual pointer to ring buffer.
+ */
+static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv)
+{
+ return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
+}
+
+/*
+ * Hooks a segment of data into the tail of the ring-buffer by
+ * modifying the pause address stored in the buffer itself. If
+ * the regulator has already paused, restart it.
+ */
+static int via_hook_segment(drm_via_private_t *dev_priv,
+ uint32_t pause_addr_hi, uint32_t pause_addr_lo,
+ int no_pci_fire)
+{
+ int paused, count;
+ volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
+
+ via_flush_write_combine();
+ while(! *(via_get_dma(dev_priv)-1));
+ *dev_priv->last_pause_ptr = pause_addr_lo;
+ via_flush_write_combine();
+
+ /*
+ * The below statement is inserted to really force the flush.
+ * Not sure it is needed.
+ */
+
+ while(! *dev_priv->last_pause_ptr);
+ dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
+ while(! *dev_priv->last_pause_ptr);
+
+
+ paused = 0;
+ count = 20;
+
+ while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
+ if ((count <= 8) && (count >= 0)) {
+ uint32_t rgtr, ptr;
+ rgtr = *(dev_priv->hw_addr_ptr);
+ ptr = ((char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4 -
+ CMDBUF_ALIGNMENT_SIZE;
+ if (rgtr <= ptr) {
+ DRM_ERROR("Command regulator\npaused at count %d, address %x, "
+ "while current pause address is %x.\n"
+ "Please mail this message to "
+ "<unichrome-devel@lists.sourceforge.net>\n",
+ count, rgtr, ptr);
+ }
+ }
+
+ if (paused && !no_pci_fire) {
+ uint32_t rgtr,ptr;
+ uint32_t ptr_low;
+
+ count = 1000000;
+ while ((VIA_READ(VIA_REG_STATUS) & VIA_CMD_RGTR_BUSY) && count--);
+
+ rgtr = *(dev_priv->hw_addr_ptr);
+ ptr = ((char *)paused_at - dev_priv->dma_ptr) +
+ dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
+
+ ptr_low = (ptr > 3*CMDBUF_ALIGNMENT_SIZE) ?
+ ptr - 3*CMDBUF_ALIGNMENT_SIZE : 0;
+ if (rgtr <= ptr && rgtr >= ptr_low) {
+ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+ }
+ }
+ return paused;
+}
+
+
+
+static int via_wait_idle(drm_via_private_t * dev_priv)
+{
+ int count = 10000000;
+ while (count-- && (VIA_READ(VIA_REG_STATUS) &
+ (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
+ VIA_3D_ENG_BUSY))) ;
+ return count;
+}
+
+static uint32_t *via_align_cmd(drm_via_private_t * dev_priv, uint32_t cmd_type,
+ uint32_t addr, uint32_t *cmd_addr_hi,
+ uint32_t *cmd_addr_lo,
+ int skip_wait)
+{
+ uint32_t agp_base;
+ uint32_t cmd_addr, addr_lo, addr_hi;
+ uint32_t *vb;
+ uint32_t qw_pad_count;
+
+ if (!skip_wait)
+ via_cmdbuf_wait(dev_priv, 2*CMDBUF_ALIGNMENT_SIZE);
+
+ vb = via_get_dma(dev_priv);
+ VIA_OUT_RING_QW( HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
+ (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+ qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
+ ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
+
+
+ cmd_addr = (addr) ? addr :
+ agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
+ addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |
+ (cmd_addr & HC_HAGPBpL_MASK));
+ addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
+
+ vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
+ VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi,
+ *cmd_addr_lo = addr_lo);
+ return vb;
+}
+
+
+
+
+static void via_cmdbuf_start(drm_via_private_t * dev_priv)
+{
+ uint32_t pause_addr_lo, pause_addr_hi;
+ uint32_t start_addr, start_addr_lo;
+ uint32_t end_addr, end_addr_lo;
+ uint32_t command;
+ uint32_t agp_base;
+
+
+ dev_priv->dma_low = 0;
+
+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+ start_addr = agp_base;
+ end_addr = agp_base + dev_priv->dma_high;
+
+ start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
+ end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
+ command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
+ ((end_addr & 0xff000000) >> 16));
+
+ dev_priv->last_pause_ptr =
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
+ &pause_addr_hi, & pause_addr_lo, 1) - 1;
+
+ via_flush_write_combine();
+ while(! *dev_priv->last_pause_ptr);
+
+ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
+ VIA_WRITE(VIA_REG_TRANSPACE, command);
+ VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo);
+ VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo);
+
+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
+ VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
+
+ VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
+}
+
+static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)
+{
+ uint32_t *vb;
+
+ via_cmdbuf_wait(dev_priv, qwords + 2);
+ vb = via_get_dma(dev_priv);
+ VIA_OUT_RING_QW( HC_HEADER2, HC_ParaType_NotTex << 16);
+ via_align_buffer(dev_priv,vb,qwords);
+}
+
+static inline void via_dummy_bitblt(drm_via_private_t * dev_priv)
+{
+ uint32_t *vb = via_get_dma(dev_priv);
+ SetReg2DAGP(0x0C, (0 | (0 << 16)));
+ SetReg2DAGP(0x10, 0 | (0 << 16));
+ SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
+}
+
+
+static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
+{
+ uint32_t agp_base;
+ uint32_t pause_addr_lo, pause_addr_hi;
+ uint32_t jump_addr_lo, jump_addr_hi;
+ volatile uint32_t *last_pause_ptr;
+ uint32_t dma_low_save1, dma_low_save2;
+
+ agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+ via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
+ &jump_addr_lo, 0);
+
+ dev_priv->dma_wrap = dev_priv->dma_low;
+
+
+ /*
+ * Wrap command buffer to the beginning.
+ */
+
+ dev_priv->dma_low = 0;
+ if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) {
+ DRM_ERROR("via_cmdbuf_jump failed\n");
+ }
+
+ via_dummy_bitblt(dev_priv);
+ via_dummy_bitblt(dev_priv);
+
+ last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0) -1;
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0);
+
+ *last_pause_ptr = pause_addr_lo;
+ dma_low_save1 = dev_priv->dma_low;
+
+ /*
+ * Now, set a trap that will pause the regulator if it tries to rerun the old
+ * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
+ * and reissues the jump command over PCI, while the regulator has already taken the jump
+ * and actually paused at the current buffer end).
+ * There appears to be no other way to detect this condition, since the hw_addr_pointer
+ * does not seem to get updated immediately when a jump occurs.
+ */
+
+ last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0) -1;
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0);
+ *last_pause_ptr = pause_addr_lo;
+
+ dma_low_save2 = dev_priv->dma_low;
+ dev_priv->dma_low = dma_low_save1;
+ via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
+ dev_priv->dma_low = dma_low_save2;
+ via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
+}
+
+
+static void via_cmdbuf_rewind(drm_via_private_t * dev_priv)
+{
+ via_cmdbuf_jump(dev_priv);
+}
+
+static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
+{
+ uint32_t pause_addr_lo, pause_addr_hi;
+
+ via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
+ via_hook_segment( dev_priv, pause_addr_hi, pause_addr_lo, 0);
+}
+
+
+static void via_cmdbuf_pause(drm_via_private_t * dev_priv)
+{
+ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
+}
+
+static void via_cmdbuf_reset(drm_via_private_t * dev_priv)
+{
+ via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
+ via_wait_idle(dev_priv);
+}
+
+/*
+ * User interface to the space and lag functions.
+ */
+
+int
+via_cmdbuf_size(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_cmdbuf_size_t d_siz;
+ int ret = 0;
+ uint32_t tmp_size, count;
+ drm_via_private_t *dev_priv;
+
+ DRM_DEBUG("via cmdbuf_size\n");
+ LOCK_TEST_WITH_RETURN( dev, filp );
+
+ dev_priv = (drm_via_private_t *) dev->dev_private;
+
+ if (dev_priv->ring.virtual_start == NULL) {
+ DRM_ERROR("%s called without initializing AGP ring buffer.\n",
+ __FUNCTION__);
+ return DRM_ERR(EFAULT);
+ }
+
+ DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t *) data,
+ sizeof(d_siz));
+
+
+ count = 1000000;
+ tmp_size = d_siz.size;
+ switch(d_siz.func) {
+ case VIA_CMDBUF_SPACE:
+ while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size) && count--) {
+ if (!d_siz.wait) {
+ break;
+ }
+ }
+ if (!count) {
+ DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
+ ret = DRM_ERR(EAGAIN);
+ }
+ break;
+ case VIA_CMDBUF_LAG:
+ while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size) && count--) {
+ if (!d_siz.wait) {
+ break;
+ }
+ }
+ if (!count) {
+ DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
+ ret = DRM_ERR(EAGAIN);
+ }
+ break;
+ default:
+ ret = DRM_ERR(EFAULT);
+ }
+ d_siz.size = tmp_size;
+
+ DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t *) data, d_siz,
+ sizeof(d_siz));
+ return ret;
+}
diff --git a/drivers/char/drm/via_drm.h b/drivers/char/drm/via_drm.h
new file mode 100644
index 000000000000..4588c9bd1816
--- /dev/null
+++ b/drivers/char/drm/via_drm.h
@@ -0,0 +1,243 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ */
+#ifndef _VIA_DRM_H_
+#define _VIA_DRM_H_
+
+/* WARNING: These defines must be the same as what the Xserver uses.
+ * if you change them, you must change the defines in the Xserver.
+ */
+
+#ifndef _VIA_DEFINES_
+#define _VIA_DEFINES_
+
+#ifndef __KERNEL__
+#include "via_drmclient.h"
+#endif
+
+#define VIA_NR_SAREA_CLIPRECTS 8
+#define VIA_NR_XVMC_PORTS 10
+#define VIA_NR_XVMC_LOCKS 5
+#define VIA_MAX_CACHELINE_SIZE 64
+#define XVMCLOCKPTR(saPriv,lockNo) \
+ ((volatile drm_hw_lock_t *)(((((unsigned long) (saPriv)->XvMCLockArea) + \
+ (VIA_MAX_CACHELINE_SIZE - 1)) & \
+ ~(VIA_MAX_CACHELINE_SIZE - 1)) + \
+ VIA_MAX_CACHELINE_SIZE*(lockNo)))
+
+/* Each region is a minimum of 64k, and there are at most 64 of them.
+ */
+#define VIA_NR_TEX_REGIONS 64
+#define VIA_LOG_MIN_TEX_REGION_SIZE 16
+#endif
+
+#define VIA_UPLOAD_TEX0IMAGE 0x1 /* handled clientside */
+#define VIA_UPLOAD_TEX1IMAGE 0x2 /* handled clientside */
+#define VIA_UPLOAD_CTX 0x4
+#define VIA_UPLOAD_BUFFERS 0x8
+#define VIA_UPLOAD_TEX0 0x10
+#define VIA_UPLOAD_TEX1 0x20
+#define VIA_UPLOAD_CLIPRECTS 0x40
+#define VIA_UPLOAD_ALL 0xff
+
+/* VIA specific ioctls */
+#define DRM_VIA_ALLOCMEM 0x00
+#define DRM_VIA_FREEMEM 0x01
+#define DRM_VIA_AGP_INIT 0x02
+#define DRM_VIA_FB_INIT 0x03
+#define DRM_VIA_MAP_INIT 0x04
+#define DRM_VIA_DEC_FUTEX 0x05
+#define NOT_USED
+#define DRM_VIA_DMA_INIT 0x07
+#define DRM_VIA_CMDBUFFER 0x08
+#define DRM_VIA_FLUSH 0x09
+#define DRM_VIA_PCICMD 0x0a
+#define DRM_VIA_CMDBUF_SIZE 0x0b
+#define NOT_USED
+#define DRM_VIA_WAIT_IRQ 0x0d
+
+#define DRM_IOCTL_VIA_ALLOCMEM DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_ALLOCMEM, drm_via_mem_t)
+#define DRM_IOCTL_VIA_FREEMEM DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_FREEMEM, drm_via_mem_t)
+#define DRM_IOCTL_VIA_AGP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_AGP_INIT, drm_via_agp_t)
+#define DRM_IOCTL_VIA_FB_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_FB_INIT, drm_via_fb_t)
+#define DRM_IOCTL_VIA_MAP_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_MAP_INIT, drm_via_init_t)
+#define DRM_IOCTL_VIA_DEC_FUTEX DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_DEC_FUTEX, drm_via_futex_t)
+#define DRM_IOCTL_VIA_DMA_INIT DRM_IOWR(DRM_COMMAND_BASE + DRM_VIA_DMA_INIT, drm_via_dma_init_t)
+#define DRM_IOCTL_VIA_CMDBUFFER DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_CMDBUFFER, drm_via_cmdbuffer_t)
+#define DRM_IOCTL_VIA_FLUSH DRM_IO( DRM_COMMAND_BASE + DRM_VIA_FLUSH)
+#define DRM_IOCTL_VIA_PCICMD DRM_IOW( DRM_COMMAND_BASE + DRM_VIA_PCICMD, drm_via_cmdbuffer_t)
+#define DRM_IOCTL_VIA_CMDBUF_SIZE DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_CMDBUF_SIZE, \
+ drm_via_cmdbuf_size_t)
+#define DRM_IOCTL_VIA_WAIT_IRQ DRM_IOWR( DRM_COMMAND_BASE + DRM_VIA_WAIT_IRQ, drm_via_irqwait_t)
+
+/* Indices into buf.Setup where various bits of state are mirrored per
+ * context and per buffer. These can be fired at the card as a unit,
+ * or in a piecewise fashion as required.
+ */
+
+#define VIA_TEX_SETUP_SIZE 8
+
+/* Flags for clear ioctl
+ */
+#define VIA_FRONT 0x1
+#define VIA_BACK 0x2
+#define VIA_DEPTH 0x4
+#define VIA_STENCIL 0x8
+#define VIDEO 0
+#define AGP 1
+typedef struct {
+ uint32_t offset;
+ uint32_t size;
+} drm_via_agp_t;
+
+typedef struct {
+ uint32_t offset;
+ uint32_t size;
+} drm_via_fb_t;
+
+typedef struct {
+ uint32_t context;
+ uint32_t type;
+ uint32_t size;
+ unsigned long index;
+ unsigned long offset;
+} drm_via_mem_t;
+
+typedef struct _drm_via_init {
+ enum {
+ VIA_INIT_MAP = 0x01,
+ VIA_CLEANUP_MAP = 0x02
+ } func;
+
+ unsigned long sarea_priv_offset;
+ unsigned long fb_offset;
+ unsigned long mmio_offset;
+ unsigned long agpAddr;
+} drm_via_init_t;
+
+typedef struct _drm_via_futex {
+ enum {
+ VIA_FUTEX_WAIT = 0x00,
+ VIA_FUTEX_WAKE = 0X01
+ } func;
+ uint32_t ms;
+ uint32_t lock;
+ uint32_t val;
+} drm_via_futex_t;
+
+typedef struct _drm_via_dma_init {
+ enum {
+ VIA_INIT_DMA = 0x01,
+ VIA_CLEANUP_DMA = 0x02,
+ VIA_DMA_INITIALIZED = 0x03
+ } func;
+
+ unsigned long offset;
+ unsigned long size;
+ unsigned long reg_pause_addr;
+} drm_via_dma_init_t;
+
+typedef struct _drm_via_cmdbuffer {
+ char *buf;
+ unsigned long size;
+} drm_via_cmdbuffer_t;
+
+/* Warning: If you change the SAREA structure you must change the Xserver
+ * structure as well */
+
+typedef struct _drm_via_tex_region {
+ unsigned char next, prev; /* indices to form a circular LRU */
+ unsigned char inUse; /* owned by a client, or free? */
+ int age; /* tracked by clients to update local LRU's */
+} drm_via_tex_region_t;
+
+typedef struct _drm_via_sarea {
+ unsigned int dirty;
+ unsigned int nbox;
+ drm_clip_rect_t boxes[VIA_NR_SAREA_CLIPRECTS];
+ drm_via_tex_region_t texList[VIA_NR_TEX_REGIONS + 1];
+ int texAge; /* last time texture was uploaded */
+ int ctxOwner; /* last context to upload state */
+ int vertexPrim;
+
+ /*
+ * Below is for XvMC.
+ * We want the lock integers alone on, and aligned to, a cache line.
+ * Therefore this somewhat strange construct.
+ */
+
+ char XvMCLockArea[VIA_MAX_CACHELINE_SIZE * (VIA_NR_XVMC_LOCKS + 1)];
+
+ unsigned int XvMCDisplaying[VIA_NR_XVMC_PORTS];
+ unsigned int XvMCSubPicOn[VIA_NR_XVMC_PORTS];
+ unsigned int XvMCCtxNoGrabbed; /* Last context to hold decoder */
+
+} drm_via_sarea_t;
+
+typedef struct _drm_via_cmdbuf_size {
+ enum {
+ VIA_CMDBUF_SPACE = 0x01,
+ VIA_CMDBUF_LAG = 0x02
+ } func;
+ int wait;
+ uint32_t size;
+} drm_via_cmdbuf_size_t;
+
+typedef enum {
+ VIA_IRQ_ABSOLUTE = 0x0,
+ VIA_IRQ_RELATIVE = 0x1,
+ VIA_IRQ_SIGNAL = 0x10000000,
+ VIA_IRQ_FORCE_SEQUENCE = 0x20000000
+} via_irq_seq_type_t;
+
+#define VIA_IRQ_FLAGS_MASK 0xF0000000
+
+struct drm_via_wait_irq_request{
+ unsigned irq;
+ via_irq_seq_type_t type;
+ uint32_t sequence;
+ uint32_t signal;
+};
+
+typedef union drm_via_irqwait {
+ struct drm_via_wait_irq_request request;
+ struct drm_wait_vblank_reply reply;
+} drm_via_irqwait_t;
+
+#ifdef __KERNEL__
+
+int via_fb_init(DRM_IOCTL_ARGS);
+int via_mem_alloc(DRM_IOCTL_ARGS);
+int via_mem_free(DRM_IOCTL_ARGS);
+int via_agp_init(DRM_IOCTL_ARGS);
+int via_map_init(DRM_IOCTL_ARGS);
+int via_decoder_futex(DRM_IOCTL_ARGS);
+int via_dma_init(DRM_IOCTL_ARGS);
+int via_cmdbuffer(DRM_IOCTL_ARGS);
+int via_flush_ioctl(DRM_IOCTL_ARGS);
+int via_pci_cmdbuffer(DRM_IOCTL_ARGS);
+int via_cmdbuf_size(DRM_IOCTL_ARGS);
+int via_wait_irq(DRM_IOCTL_ARGS);
+
+#endif
+#endif /* _VIA_DRM_H_ */
diff --git a/drivers/char/drm/via_drv.c b/drivers/char/drm/via_drv.c
new file mode 100644
index 000000000000..275eefc79221
--- /dev/null
+++ b/drivers/char/drm/via_drv.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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 <linux/config.h>
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+#include "drm_pciids.h"
+
+static int postinit(struct drm_device *dev, unsigned long flags)
+{
+ DRM_INFO("Initialized %s %d.%d.%d %s on minor %d: %s\n",
+ DRIVER_NAME,
+ DRIVER_MAJOR,
+ DRIVER_MINOR,
+ DRIVER_PATCHLEVEL,
+ DRIVER_DATE, dev->primary.minor, pci_pretty_name(dev->pdev)
+ );
+ return 0;
+}
+
+static int version(drm_version_t * version)
+{
+ int len;
+
+ version->version_major = DRIVER_MAJOR;
+ version->version_minor = DRIVER_MINOR;
+ version->version_patchlevel = DRIVER_PATCHLEVEL;
+ DRM_COPY(version->name, DRIVER_NAME);
+ DRM_COPY(version->date, DRIVER_DATE);
+ DRM_COPY(version->desc, DRIVER_DESC);
+ return 0;
+}
+
+static struct pci_device_id pciidlist[] = {
+ viadrv_PCI_IDS
+};
+
+static drm_ioctl_desc_t ioctls[] = {
+ [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, 1, 0},
+ [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, 1, 0}
+};
+
+static struct drm_driver driver = {
+ .driver_features =
+ DRIVER_USE_AGP | DRIVER_USE_MTRR | DRIVER_HAVE_IRQ |
+ DRIVER_IRQ_SHARED | DRIVER_IRQ_VBL,
+ .context_ctor = via_init_context,
+ .context_dtor = via_final_context,
+ .vblank_wait = via_driver_vblank_wait,
+ .irq_preinstall = via_driver_irq_preinstall,
+ .irq_postinstall = via_driver_irq_postinstall,
+ .irq_uninstall = via_driver_irq_uninstall,
+ .irq_handler = via_driver_irq_handler,
+ .dma_quiescent = via_driver_dma_quiescent,
+ .reclaim_buffers = drm_core_reclaim_buffers,
+ .get_map_ofs = drm_core_get_map_ofs,
+ .get_reg_ofs = drm_core_get_reg_ofs,
+ .postinit = postinit,
+ .version = version,
+ .ioctls = ioctls,
+ .num_ioctls = DRM_ARRAY_SIZE(ioctls),
+ .fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .ioctl = drm_ioctl,
+ .mmap = drm_mmap,
+ .poll = drm_poll,
+ .fasync = drm_fasync,
+ },
+ .pci_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pciidlist,
+ }
+};
+
+static int __init via_init(void)
+{
+ via_init_command_verifier();
+ return drm_init(&driver);
+}
+
+static void __exit via_exit(void)
+{
+ drm_exit(&driver);
+}
+
+module_init(via_init);
+module_exit(via_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/char/drm/via_drv.h b/drivers/char/drm/via_drv.h
new file mode 100644
index 000000000000..4eaa8b7c4c96
--- /dev/null
+++ b/drivers/char/drm/via_drv.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ */
+#ifndef _VIA_DRV_H_
+#define _VIA_DRV_H_
+
+#define DRIVER_AUTHOR "VIA"
+
+#define DRIVER_NAME "via"
+#define DRIVER_DESC "VIA Unichrome / Pro"
+#define DRIVER_DATE "20050523"
+
+#define DRIVER_MAJOR 2
+#define DRIVER_MINOR 6
+#define DRIVER_PATCHLEVEL 3
+
+#include "via_verifier.h"
+
+#define VIA_PCI_BUF_SIZE 60000
+#define VIA_FIRE_BUF_SIZE 1024
+#define VIA_NUM_IRQS 2
+
+
+
+typedef struct drm_via_ring_buffer {
+ drm_map_t map;
+ char *virtual_start;
+} drm_via_ring_buffer_t;
+
+typedef uint32_t maskarray_t[5];
+
+typedef struct drm_via_irq {
+ atomic_t irq_received;
+ uint32_t pending_mask;
+ uint32_t enable_mask;
+ wait_queue_head_t irq_queue;
+} drm_via_irq_t;
+
+typedef struct drm_via_private {
+ drm_via_sarea_t *sarea_priv;
+ drm_map_t *sarea;
+ drm_map_t *fb;
+ drm_map_t *mmio;
+ unsigned long agpAddr;
+ wait_queue_head_t decoder_queue[VIA_NR_XVMC_LOCKS];
+ char *dma_ptr;
+ unsigned int dma_low;
+ unsigned int dma_high;
+ unsigned int dma_offset;
+ uint32_t dma_wrap;
+ volatile uint32_t *last_pause_ptr;
+ volatile uint32_t *hw_addr_ptr;
+ drm_via_ring_buffer_t ring;
+ struct timeval last_vblank;
+ int last_vblank_valid;
+ unsigned usec_per_vblank;
+ drm_via_state_t hc_state;
+ char pci_buf[VIA_PCI_BUF_SIZE];
+ const uint32_t *fire_offsets[VIA_FIRE_BUF_SIZE];
+ uint32_t num_fire_offsets;
+ int pro_group_a;
+ drm_via_irq_t via_irqs[VIA_NUM_IRQS];
+ unsigned num_irqs;
+ maskarray_t *irq_masks;
+ uint32_t irq_enable_mask;
+ uint32_t irq_pending_mask;
+} drm_via_private_t;
+
+/* VIA MMIO register access */
+#define VIA_BASE ((dev_priv->mmio))
+
+#define VIA_READ(reg) DRM_READ32(VIA_BASE, reg)
+#define VIA_WRITE(reg,val) DRM_WRITE32(VIA_BASE, reg, val)
+#define VIA_READ8(reg) DRM_READ8(VIA_BASE, reg)
+#define VIA_WRITE8(reg,val) DRM_WRITE8(VIA_BASE, reg, val)
+
+extern int via_init_context(drm_device_t * dev, int context);
+extern int via_final_context(drm_device_t * dev, int context);
+
+extern int via_do_cleanup_map(drm_device_t * dev);
+extern int via_map_init(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+extern int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence);
+
+extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
+extern void via_driver_irq_preinstall(drm_device_t * dev);
+extern void via_driver_irq_postinstall(drm_device_t * dev);
+extern void via_driver_irq_uninstall(drm_device_t * dev);
+
+extern int via_dma_cleanup(drm_device_t * dev);
+extern void via_init_command_verifier(void);
+extern int via_driver_dma_quiescent(drm_device_t * dev);
+extern void via_init_futex(drm_via_private_t *dev_priv);
+extern void via_cleanup_futex(drm_via_private_t *dev_priv);
+extern void via_release_futex(drm_via_private_t *dev_priv, int context);
+
+
+#endif
diff --git a/drivers/char/drm/via_ds.c b/drivers/char/drm/via_ds.c
new file mode 100644
index 000000000000..daf3df75a20e
--- /dev/null
+++ b/drivers/char/drm/via_ds.c
@@ -0,0 +1,280 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ *
+ * 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 <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include "via_ds.h"
+extern unsigned int VIA_DEBUG;
+
+set_t *via_setInit(void)
+{
+ int i;
+ set_t *set;
+ set = (set_t *) drm_alloc(sizeof(set_t), DRM_MEM_DRIVER);
+ for (i = 0; i < SET_SIZE; i++) {
+ set->list[i].free_next = i + 1;
+ set->list[i].alloc_next = -1;
+ }
+ set->list[SET_SIZE - 1].free_next = -1;
+ set->free = 0;
+ set->alloc = -1;
+ set->trace = -1;
+ return set;
+}
+
+int via_setAdd(set_t * set, ITEM_TYPE item)
+{
+ int free = set->free;
+ if (free != -1) {
+ set->list[free].val = item;
+ set->free = set->list[free].free_next;
+ } else {
+ return 0;
+ }
+ set->list[free].alloc_next = set->alloc;
+ set->alloc = free;
+ set->list[free].free_next = -1;
+ return 1;
+}
+
+int via_setDel(set_t * set, ITEM_TYPE item)
+{
+ int alloc = set->alloc;
+ int prev = -1;
+
+ while (alloc != -1) {
+ if (set->list[alloc].val == item) {
+ if (prev != -1)
+ set->list[prev].alloc_next =
+ set->list[alloc].alloc_next;
+ else
+ set->alloc = set->list[alloc].alloc_next;
+ break;
+ }
+ prev = alloc;
+ alloc = set->list[alloc].alloc_next;
+ }
+
+ if (alloc == -1)
+ return 0;
+
+ set->list[alloc].free_next = set->free;
+ set->free = alloc;
+ set->list[alloc].alloc_next = -1;
+
+ return 1;
+}
+
+/* setFirst -> setAdd -> setNext is wrong */
+
+int via_setFirst(set_t * set, ITEM_TYPE * item)
+{
+ if (set->alloc == -1)
+ return 0;
+
+ *item = set->list[set->alloc].val;
+ set->trace = set->list[set->alloc].alloc_next;
+
+ return 1;
+}
+
+int via_setNext(set_t * set, ITEM_TYPE * item)
+{
+ if (set->trace == -1)
+ return 0;
+
+ *item = set->list[set->trace].val;
+ set->trace = set->list[set->trace].alloc_next;
+
+ return 1;
+}
+
+int via_setDestroy(set_t * set)
+{
+ drm_free(set, sizeof(set_t), DRM_MEM_DRIVER);
+
+ return 1;
+}
+
+#define ISFREE(bptr) ((bptr)->free)
+
+#define fprintf(fmt, arg...) do{}while(0)
+
+memHeap_t *via_mmInit(int ofs, int size)
+{
+ PMemBlock blocks;
+
+ if (size <= 0)
+ return 0;
+
+ blocks = (TMemBlock *) drm_calloc(1, sizeof(TMemBlock), DRM_MEM_DRIVER);
+
+ if (blocks) {
+ blocks->ofs = ofs;
+ blocks->size = size;
+ blocks->free = 1;
+ return (memHeap_t *) blocks;
+ } else
+ return 0;
+}
+
+static TMemBlock *SliceBlock(TMemBlock * p,
+ int startofs, int size,
+ int reserved, int alignment)
+{
+ TMemBlock *newblock;
+
+ /* break left */
+ if (startofs > p->ofs) {
+ newblock =
+ (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
+ DRM_MEM_DRIVER);
+ newblock->ofs = startofs;
+ newblock->size = p->size - (startofs - p->ofs);
+ newblock->free = 1;
+ newblock->next = p->next;
+ p->size -= newblock->size;
+ p->next = newblock;
+ p = newblock;
+ }
+
+ /* break right */
+ if (size < p->size) {
+ newblock =
+ (TMemBlock *) drm_calloc(1, sizeof(TMemBlock),
+ DRM_MEM_DRIVER);
+ newblock->ofs = startofs + size;
+ newblock->size = p->size - size;
+ newblock->free = 1;
+ newblock->next = p->next;
+ p->size = size;
+ p->next = newblock;
+ }
+
+ /* p = middle block */
+ p->align = alignment;
+ p->free = 0;
+ p->reserved = reserved;
+ return p;
+}
+
+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
+ int startSearch)
+{
+ int mask, startofs, endofs;
+ TMemBlock *p;
+
+ if (!heap || align2 < 0 || size <= 0)
+ return NULL;
+
+ mask = (1 << align2) - 1;
+ startofs = 0;
+ p = (TMemBlock *) heap;
+
+ while (p) {
+ if (ISFREE(p)) {
+ startofs = (p->ofs + mask) & ~mask;
+
+ if (startofs < startSearch)
+ startofs = startSearch;
+
+ endofs = startofs + size;
+
+ if (endofs <= (p->ofs + p->size))
+ break;
+ }
+
+ p = p->next;
+ }
+
+ if (!p)
+ return NULL;
+
+ p = SliceBlock(p, startofs, size, 0, mask + 1);
+ p->heap = heap;
+
+ return p;
+}
+
+static __inline__ int Join2Blocks(TMemBlock * p)
+{
+ if (p->free && p->next && p->next->free) {
+ TMemBlock *q = p->next;
+ p->size += q->size;
+ p->next = q->next;
+ drm_free(q, sizeof(TMemBlock), DRM_MEM_DRIVER);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int via_mmFreeMem(PMemBlock b)
+{
+ TMemBlock *p, *prev;
+
+ if (!b)
+ return 0;
+
+ if (!b->heap) {
+ fprintf(stderr, "no heap\n");
+
+ return -1;
+ }
+
+ p = b->heap;
+ prev = NULL;
+
+ while (p && p != b) {
+ prev = p;
+ p = p->next;
+ }
+
+ if (!p || p->free || p->reserved) {
+ if (!p)
+ fprintf(stderr, "block not found in heap\n");
+ else if (p->free)
+ fprintf(stderr, "block already free\n");
+ else
+ fprintf(stderr, "block is reserved\n");
+
+ return -1;
+ }
+
+ p->free = 1;
+ Join2Blocks(p);
+
+ if (prev)
+ Join2Blocks(prev);
+
+ return 0;
+}
diff --git a/drivers/char/drm/via_ds.h b/drivers/char/drm/via_ds.h
new file mode 100644
index 000000000000..be9c7f9f1aee
--- /dev/null
+++ b/drivers/char/drm/via_ds.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ * Copyright 2000 Silicon Integrated Systems Corp, Inc., HsinChu, Taiwan.
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ */
+#ifndef _via_ds_h_
+#define _via_ds_h_
+
+#include "drmP.h"
+
+/* Set Data Structure */
+#define SET_SIZE 5000
+typedef unsigned long ITEM_TYPE;
+
+typedef struct {
+ ITEM_TYPE val;
+ int alloc_next, free_next;
+} list_item_t;
+
+typedef struct {
+ int alloc;
+ int free;
+ int trace;
+ list_item_t list[SET_SIZE];
+} set_t;
+
+set_t *via_setInit(void);
+int via_setAdd(set_t * set, ITEM_TYPE item);
+int via_setDel(set_t * set, ITEM_TYPE item);
+int via_setFirst(set_t * set, ITEM_TYPE * item);
+int via_setNext(set_t * set, ITEM_TYPE * item);
+int via_setDestroy(set_t * set);
+
+#endif
+
+#ifndef MM_INC
+#define MM_INC
+
+struct mem_block_t {
+ struct mem_block_t *next;
+ struct mem_block_t *heap;
+ int ofs, size;
+ int align;
+ int free:1;
+ int reserved:1;
+};
+typedef struct mem_block_t TMemBlock;
+typedef struct mem_block_t *PMemBlock;
+
+/* a heap is just the first block in a chain */
+typedef struct mem_block_t memHeap_t;
+
+static __inline__ int mmBlockSize(PMemBlock b)
+{
+ return b->size;
+}
+
+static __inline__ int mmOffset(PMemBlock b)
+{
+ return b->ofs;
+}
+
+static __inline__ void mmMarkReserved(PMemBlock b)
+{
+ b->reserved = 1;
+}
+
+/*
+ * input: total size in bytes
+ * return: a heap pointer if OK, NULL if error
+ */
+memHeap_t *via_mmInit(int ofs, int size);
+
+PMemBlock via_mmAllocMem(memHeap_t * heap, int size, int align2,
+ int startSearch);
+
+/*
+ * Free block starts at offset
+ * input: pointer to a block
+ * return: 0 if OK, -1 if error
+ */
+int via_mmFreeMem(PMemBlock b);
+
+#endif
diff --git a/drivers/char/drm/via_irq.c b/drivers/char/drm/via_irq.c
new file mode 100644
index 000000000000..e8027f3a93b0
--- /dev/null
+++ b/drivers/char/drm/via_irq.c
@@ -0,0 +1,339 @@
+/* via_irq.c
+ *
+ * Copyright 2004 BEAM Ltd.
+ * Copyright 2002 Tungsten Graphics, Inc.
+ * Copyright 2005 Thomas Hellstrom.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BEAM LTD, TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ * Terry Barnaby <terry1@beam.ltd.uk>
+ * Keith Whitwell <keith@tungstengraphics.com>
+ * Thomas Hellstrom <unichrome@shipmail.org>
+ *
+ * This code provides standard DRM access to the Via Unichrome / Pro Vertical blank
+ * interrupt, as well as an infrastructure to handle other interrupts of the chip.
+ * The refresh rate is also calculated for video playback sync purposes.
+ */
+
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+#define VIA_REG_INTERRUPT 0x200
+
+/* VIA_REG_INTERRUPT */
+#define VIA_IRQ_GLOBAL (1 << 31)
+#define VIA_IRQ_VBLANK_ENABLE (1 << 19)
+#define VIA_IRQ_VBLANK_PENDING (1 << 3)
+#define VIA_IRQ_HQV0_ENABLE (1 << 11)
+#define VIA_IRQ_HQV1_ENABLE (1 << 25)
+#define VIA_IRQ_HQV0_PENDING (1 << 9)
+#define VIA_IRQ_HQV1_PENDING (1 << 10)
+
+/*
+ * Device-specific IRQs go here. This type might need to be extended with
+ * the register if there are multiple IRQ control registers.
+ * Currently we activate the HQV interrupts of Unichrome Pro group A.
+ */
+
+static maskarray_t via_pro_group_a_irqs[] = {
+ {VIA_IRQ_HQV0_ENABLE, VIA_IRQ_HQV0_PENDING, 0x000003D0, 0x00008010, 0x00000000 },
+ {VIA_IRQ_HQV1_ENABLE, VIA_IRQ_HQV1_PENDING, 0x000013D0, 0x00008010, 0x00000000 }};
+static int via_num_pro_group_a = sizeof(via_pro_group_a_irqs)/sizeof(maskarray_t);
+
+static maskarray_t via_unichrome_irqs[] = {};
+static int via_num_unichrome = sizeof(via_unichrome_irqs)/sizeof(maskarray_t);
+
+
+static unsigned time_diff(struct timeval *now,struct timeval *then)
+{
+ return (now->tv_usec >= then->tv_usec) ?
+ now->tv_usec - then->tv_usec :
+ 1000000 - (then->tv_usec - now->tv_usec);
+}
+
+irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
+{
+ drm_device_t *dev = (drm_device_t *) arg;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ u32 status;
+ int handled = 0;
+ struct timeval cur_vblank;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
+
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ if (status & VIA_IRQ_VBLANK_PENDING) {
+ atomic_inc(&dev->vbl_received);
+ if (!(atomic_read(&dev->vbl_received) & 0x0F)) {
+ do_gettimeofday(&cur_vblank);
+ if (dev_priv->last_vblank_valid) {
+ dev_priv->usec_per_vblank =
+ time_diff( &cur_vblank,&dev_priv->last_vblank) >> 4;
+ }
+ dev_priv->last_vblank = cur_vblank;
+ dev_priv->last_vblank_valid = 1;
+ }
+ if (!(atomic_read(&dev->vbl_received) & 0xFF)) {
+ DRM_DEBUG("US per vblank is: %u\n",
+ dev_priv->usec_per_vblank);
+ }
+ DRM_WAKEUP(&dev->vbl_queue);
+ drm_vbl_send_signals(dev);
+ handled = 1;
+ }
+
+
+ for (i=0; i<dev_priv->num_irqs; ++i) {
+ if (status & cur_irq->pending_mask) {
+ atomic_inc( &cur_irq->irq_received );
+ DRM_WAKEUP( &cur_irq->irq_queue );
+ handled = 1;
+ }
+ cur_irq++;
+ }
+
+ /* Acknowlege interrupts */
+ VIA_WRITE(VIA_REG_INTERRUPT, status);
+
+
+ if (handled)
+ return IRQ_HANDLED;
+ else
+ return IRQ_NONE;
+}
+
+static __inline__ void viadrv_acknowledge_irqs(drm_via_private_t * dev_priv)
+{
+ u32 status;
+
+ if (dev_priv) {
+ /* Acknowlege interrupts */
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status |
+ dev_priv->irq_pending_mask);
+ }
+}
+
+int via_driver_vblank_wait(drm_device_t * dev, unsigned int *sequence)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned int cur_vblank;
+ int ret = 0;
+
+ DRM_DEBUG("viadrv_vblank_wait\n");
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return -EINVAL;
+ }
+
+ viadrv_acknowledge_irqs(dev_priv);
+
+ /* Assume that the user has missed the current sequence number
+ * by about a day rather than she wants to wait for years
+ * using vertical blanks...
+ */
+
+ DRM_WAIT_ON(ret, dev->vbl_queue, 3 * DRM_HZ,
+ (((cur_vblank = atomic_read(&dev->vbl_received)) -
+ *sequence) <= (1 << 23)));
+
+ *sequence = cur_vblank;
+ return ret;
+}
+
+static int
+via_driver_irq_wait(drm_device_t * dev, unsigned int irq, int force_sequence,
+ unsigned int *sequence)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ unsigned int cur_irq_sequence;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int ret = 0;
+ maskarray_t *masks = dev_priv->irq_masks;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ if (!dev_priv) {
+ DRM_ERROR("%s called with no initialization\n", __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irq >= dev_priv->num_irqs ) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__, irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irq;
+
+ if (masks[irq][2] && !force_sequence) {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ ((VIA_READ(masks[irq][2]) & masks[irq][3]) == masks[irq][4]));
+ cur_irq_sequence = atomic_read(&cur_irq->irq_received);
+ } else {
+ DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+ (((cur_irq_sequence = atomic_read(&cur_irq->irq_received)) -
+ *sequence) <= (1 << 23)));
+ }
+ *sequence = cur_irq_sequence;
+ return ret;
+}
+
+
+/*
+ * drm_dma.h hooks
+ */
+
+void via_driver_irq_preinstall(drm_device_t * dev)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ u32 status;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int i;
+
+ DRM_DEBUG("driver_irq_preinstall: dev_priv: %p\n", dev_priv);
+ if (dev_priv) {
+
+ dev_priv->irq_enable_mask = VIA_IRQ_VBLANK_ENABLE;
+ dev_priv->irq_pending_mask = VIA_IRQ_VBLANK_PENDING;
+
+ dev_priv->irq_masks = (dev_priv->pro_group_a) ?
+ via_pro_group_a_irqs : via_unichrome_irqs;
+ dev_priv->num_irqs = (dev_priv->pro_group_a) ?
+ via_num_pro_group_a : via_num_unichrome;
+
+ for(i=0; i < dev_priv->num_irqs; ++i) {
+ atomic_set(&cur_irq->irq_received, 0);
+ cur_irq->enable_mask = dev_priv->irq_masks[i][0];
+ cur_irq->pending_mask = dev_priv->irq_masks[i][1];
+ DRM_INIT_WAITQUEUE( &cur_irq->irq_queue );
+ dev_priv->irq_enable_mask |= cur_irq->enable_mask;
+ dev_priv->irq_pending_mask |= cur_irq->pending_mask;
+ cur_irq++;
+
+ DRM_DEBUG("Initializing IRQ %d\n", i);
+ }
+
+ dev_priv->last_vblank_valid = 0;
+
+ // Clear VSync interrupt regs
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(dev_priv->irq_enable_mask));
+
+ /* Clear bits if they're already high */
+ viadrv_acknowledge_irqs(dev_priv);
+ }
+}
+
+void via_driver_irq_postinstall(drm_device_t * dev)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ u32 status;
+
+ DRM_DEBUG("via_driver_irq_postinstall\n");
+ if (dev_priv) {
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status | VIA_IRQ_GLOBAL
+ | dev_priv->irq_enable_mask);
+
+ /* Some magic, oh for some data sheets ! */
+
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) | 0x30);
+
+ }
+}
+
+void via_driver_irq_uninstall(drm_device_t * dev)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ u32 status;
+
+ DRM_DEBUG("driver_irq_uninstall)\n");
+ if (dev_priv) {
+
+ /* Some more magic, oh for some data sheets ! */
+
+ VIA_WRITE8(0x83d4, 0x11);
+ VIA_WRITE8(0x83d5, VIA_READ8(0x83d5) & ~0x30);
+
+ status = VIA_READ(VIA_REG_INTERRUPT);
+ VIA_WRITE(VIA_REG_INTERRUPT, status &
+ ~(VIA_IRQ_VBLANK_ENABLE | dev_priv->irq_enable_mask));
+ }
+}
+
+int via_wait_irq(DRM_IOCTL_ARGS)
+{
+ drm_file_t *priv = filp->private_data;
+ drm_device_t *dev = priv->head->dev;
+ drm_via_irqwait_t __user *argp = (void __user *)data;
+ drm_via_irqwait_t irqwait;
+ struct timeval now;
+ int ret = 0;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_irq_t *cur_irq = dev_priv->via_irqs;
+ int force_sequence;
+
+ if (!dev->irq)
+ return DRM_ERR(EINVAL);
+
+ DRM_COPY_FROM_USER_IOCTL(irqwait, argp, sizeof(irqwait));
+ if (irqwait.request.irq >= dev_priv->num_irqs) {
+ DRM_ERROR("%s Trying to wait on unknown irq %d\n", __FUNCTION__,
+ irqwait.request.irq);
+ return DRM_ERR(EINVAL);
+ }
+
+ cur_irq += irqwait.request.irq;
+
+ switch (irqwait.request.type & ~VIA_IRQ_FLAGS_MASK) {
+ case VIA_IRQ_RELATIVE:
+ irqwait.request.sequence += atomic_read(&cur_irq->irq_received);
+ irqwait.request.type &= ~_DRM_VBLANK_RELATIVE;
+ case VIA_IRQ_ABSOLUTE:
+ break;
+ default:
+ return DRM_ERR(EINVAL);
+ }
+
+ if (irqwait.request.type & VIA_IRQ_SIGNAL) {
+ DRM_ERROR("%s Signals on Via IRQs not implemented yet.\n",
+ __FUNCTION__);
+ return DRM_ERR(EINVAL);
+ }
+
+ force_sequence = (irqwait.request.type & VIA_IRQ_FORCE_SEQUENCE);
+
+ ret = via_driver_irq_wait(dev, irqwait.request.irq, force_sequence,
+ &irqwait.request.sequence);
+ do_gettimeofday(&now);
+ irqwait.reply.tval_sec = now.tv_sec;
+ irqwait.reply.tval_usec = now.tv_usec;
+
+ DRM_COPY_TO_USER_IOCTL(argp, irqwait, sizeof(irqwait));
+
+ return ret;
+}
diff --git a/drivers/char/drm/via_map.c b/drivers/char/drm/via_map.c
new file mode 100644
index 000000000000..0be829b6ec65
--- /dev/null
+++ b/drivers/char/drm/via_map.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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 "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+static int via_do_init_map(drm_device_t * dev, drm_via_init_t * init)
+{
+ drm_via_private_t *dev_priv;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ dev_priv = drm_alloc(sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+ if (dev_priv == NULL)
+ return -ENOMEM;
+
+ memset(dev_priv, 0, sizeof(drm_via_private_t));
+
+ DRM_GETSAREA();
+ if (!dev_priv->sarea) {
+ DRM_ERROR("could not find sarea!\n");
+ dev->dev_private = (void *)dev_priv;
+ via_do_cleanup_map(dev);
+ return -EINVAL;
+ }
+
+ dev_priv->fb = drm_core_findmap(dev, init->fb_offset);
+ if (!dev_priv->fb) {
+ DRM_ERROR("could not find framebuffer!\n");
+ dev->dev_private = (void *)dev_priv;
+ via_do_cleanup_map(dev);
+ return -EINVAL;
+ }
+ 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;
+ via_do_cleanup_map(dev);
+ return -EINVAL;
+ }
+
+ dev_priv->sarea_priv =
+ (drm_via_sarea_t *) ((u8 *) dev_priv->sarea->handle +
+ init->sarea_priv_offset);
+
+ dev_priv->agpAddr = init->agpAddr;
+
+ via_init_futex( dev_priv );
+ dev_priv->pro_group_a = (dev->pdev->device == 0x3118);
+
+ dev->dev_private = (void *)dev_priv;
+ return 0;
+}
+
+int via_do_cleanup_map(drm_device_t * dev)
+{
+ if (dev->dev_private) {
+
+ drm_via_private_t *dev_priv = dev->dev_private;
+
+ via_dma_cleanup(dev);
+
+ drm_free(dev_priv, sizeof(drm_via_private_t), DRM_MEM_DRIVER);
+ dev->dev_private = NULL;
+ }
+
+ return 0;
+}
+
+int via_map_init(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_init_t init;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ DRM_COPY_FROM_USER_IOCTL(init, (drm_via_init_t *) data, sizeof(init));
+
+ switch (init.func) {
+ case VIA_INIT_MAP:
+ return via_do_init_map(dev, &init);
+ case VIA_CLEANUP_MAP:
+ return via_do_cleanup_map(dev);
+ }
+
+ return -EINVAL;
+}
+
+
diff --git a/drivers/char/drm/via_mm.c b/drivers/char/drm/via_mm.c
new file mode 100644
index 000000000000..c22712f44d42
--- /dev/null
+++ b/drivers/char/drm/via_mm.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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 "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+#include "via_ds.h"
+#include "via_mm.h"
+
+#define MAX_CONTEXT 100
+
+typedef struct {
+ int used;
+ int context;
+ set_t *sets[2]; /* 0 for frame buffer, 1 for AGP , 2 for System */
+} via_context_t;
+
+static via_context_t global_ppriv[MAX_CONTEXT];
+
+static int via_agp_alloc(drm_via_mem_t * mem);
+static int via_agp_free(drm_via_mem_t * mem);
+static int via_fb_alloc(drm_via_mem_t * mem);
+static int via_fb_free(drm_via_mem_t * mem);
+
+static int add_alloc_set(int context, int type, unsigned int val)
+{
+ int i, retval = 0;
+
+ for (i = 0; i < MAX_CONTEXT; i++) {
+ if (global_ppriv[i].used && global_ppriv[i].context == context) {
+ retval = via_setAdd(global_ppriv[i].sets[type], val);
+ break;
+ }
+ }
+
+ return retval;
+}
+
+static int del_alloc_set(int context, int type, unsigned int val)
+{
+ int i, retval = 0;
+
+ for (i = 0; i < MAX_CONTEXT; i++)
+ if (global_ppriv[i].used && global_ppriv[i].context == context) {
+ retval = via_setDel(global_ppriv[i].sets[type], val);
+ break;
+ }
+
+ return retval;
+}
+
+/* agp memory management */
+static memHeap_t *AgpHeap = NULL;
+
+int via_agp_init(DRM_IOCTL_ARGS)
+{
+ drm_via_agp_t agp;
+
+ DRM_COPY_FROM_USER_IOCTL(agp, (drm_via_agp_t *) data, sizeof(agp));
+
+ AgpHeap = via_mmInit(agp.offset, agp.size);
+
+ DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)agp.offset, (unsigned long)agp.size);
+
+ return 0;
+}
+
+/* fb memory management */
+static memHeap_t *FBHeap = NULL;
+
+int via_fb_init(DRM_IOCTL_ARGS)
+{
+ drm_via_fb_t fb;
+
+ DRM_COPY_FROM_USER_IOCTL(fb, (drm_via_fb_t *) data, sizeof(fb));
+
+ FBHeap = via_mmInit(fb.offset, fb.size);
+
+ DRM_DEBUG("offset = %lu, size = %lu", (unsigned long)fb.offset, (unsigned long)fb.size);
+
+ return 0;
+}
+
+int via_init_context(struct drm_device *dev, int context)
+{
+ int i;
+
+ for (i = 0; i < MAX_CONTEXT; i++)
+ if (global_ppriv[i].used &&
+ (global_ppriv[i].context == context))
+ break;
+
+ if (i >= MAX_CONTEXT) {
+ for (i = 0; i < MAX_CONTEXT; i++) {
+ if (!global_ppriv[i].used) {
+ global_ppriv[i].context = context;
+ global_ppriv[i].used = 1;
+ global_ppriv[i].sets[0] = via_setInit();
+ global_ppriv[i].sets[1] = via_setInit();
+ DRM_DEBUG("init allocation set, socket=%d,"
+ " context = %d\n", i, context);
+ break;
+ }
+ }
+
+ if ((i >= MAX_CONTEXT) || (global_ppriv[i].sets[0] == NULL) ||
+ (global_ppriv[i].sets[1] == NULL)) {
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int via_final_context(struct drm_device *dev, int context)
+{
+ int i;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+
+ for (i = 0; i < MAX_CONTEXT; i++)
+ if (global_ppriv[i].used &&
+ (global_ppriv[i].context == context))
+ break;
+
+ if (i < MAX_CONTEXT) {
+ set_t *set;
+ ITEM_TYPE item;
+ int retval;
+
+ DRM_DEBUG("find socket %d, context = %d\n", i, context);
+
+ /* Video Memory */
+ set = global_ppriv[i].sets[0];
+ retval = via_setFirst(set, &item);
+ while (retval) {
+ DRM_DEBUG("free video memory 0x%lx\n", item);
+ via_mmFreeMem((PMemBlock) item);
+ retval = via_setNext(set, &item);
+ }
+ via_setDestroy(set);
+
+ /* AGP Memory */
+ set = global_ppriv[i].sets[1];
+ retval = via_setFirst(set, &item);
+ while (retval) {
+ DRM_DEBUG("free agp memory 0x%lx\n", item);
+ via_mmFreeMem((PMemBlock) item);
+ retval = via_setNext(set, &item);
+ }
+ via_setDestroy(set);
+ global_ppriv[i].used = 0;
+ }
+ via_release_futex(dev_priv, context);
+
+
+#if defined(__linux__)
+ /* Linux specific until context tracking code gets ported to BSD */
+ /* Last context, perform cleanup */
+ if (dev->ctx_count == 1 && dev->dev_private) {
+ DRM_DEBUG("Last Context\n");
+ if (dev->irq)
+ drm_irq_uninstall(dev);
+
+ via_cleanup_futex(dev_priv);
+ via_do_cleanup_map(dev);
+ }
+#endif
+
+ return 1;
+}
+
+int via_mem_alloc(DRM_IOCTL_ARGS)
+{
+ drm_via_mem_t mem;
+
+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));
+
+ switch (mem.type) {
+ case VIDEO:
+ if (via_fb_alloc(&mem) < 0)
+ return -EFAULT;
+ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,
+ sizeof(mem));
+ return 0;
+ case AGP:
+ if (via_agp_alloc(&mem) < 0)
+ return -EFAULT;
+ DRM_COPY_TO_USER_IOCTL((drm_via_mem_t *) data, mem,
+ sizeof(mem));
+ return 0;
+ }
+
+ return -EFAULT;
+}
+
+static int via_fb_alloc(drm_via_mem_t * mem)
+{
+ drm_via_mm_t fb;
+ PMemBlock block;
+ int retval = 0;
+
+ if (!FBHeap)
+ return -1;
+
+ fb.size = mem->size;
+ fb.context = mem->context;
+
+ block = via_mmAllocMem(FBHeap, fb.size, 5, 0);
+ if (block) {
+ fb.offset = block->ofs;
+ fb.free = (unsigned long)block;
+ if (!add_alloc_set(fb.context, VIDEO, fb.free)) {
+ DRM_DEBUG("adding to allocation set fails\n");
+ via_mmFreeMem((PMemBlock) fb.free);
+ retval = -1;
+ }
+ } else {
+ fb.offset = 0;
+ fb.size = 0;
+ fb.free = 0;
+ retval = -1;
+ }
+
+ mem->offset = fb.offset;
+ mem->index = fb.free;
+
+ DRM_DEBUG("alloc fb, size = %d, offset = %d\n", fb.size,
+ (int)fb.offset);
+
+ return retval;
+}
+
+static int via_agp_alloc(drm_via_mem_t * mem)
+{
+ drm_via_mm_t agp;
+ PMemBlock block;
+ int retval = 0;
+
+ if (!AgpHeap)
+ return -1;
+
+ agp.size = mem->size;
+ agp.context = mem->context;
+
+ block = via_mmAllocMem(AgpHeap, agp.size, 5, 0);
+ if (block) {
+ agp.offset = block->ofs;
+ agp.free = (unsigned long)block;
+ if (!add_alloc_set(agp.context, AGP, agp.free)) {
+ DRM_DEBUG("adding to allocation set fails\n");
+ via_mmFreeMem((PMemBlock) agp.free);
+ retval = -1;
+ }
+ } else {
+ agp.offset = 0;
+ agp.size = 0;
+ agp.free = 0;
+ }
+
+ mem->offset = agp.offset;
+ mem->index = agp.free;
+
+ DRM_DEBUG("alloc agp, size = %d, offset = %d\n", agp.size,
+ (unsigned int)agp.offset);
+ return retval;
+}
+
+int via_mem_free(DRM_IOCTL_ARGS)
+{
+ drm_via_mem_t mem;
+
+ DRM_COPY_FROM_USER_IOCTL(mem, (drm_via_mem_t *) data, sizeof(mem));
+
+ switch (mem.type) {
+
+ case VIDEO:
+ if (via_fb_free(&mem) == 0)
+ return 0;
+ break;
+ case AGP:
+ if (via_agp_free(&mem) == 0)
+ return 0;
+ break;
+ }
+
+ return -EFAULT;
+}
+
+static int via_fb_free(drm_via_mem_t * mem)
+{
+ drm_via_mm_t fb;
+ int retval = 0;
+
+ if (!FBHeap) {
+ return -1;
+ }
+
+ fb.free = mem->index;
+ fb.context = mem->context;
+
+ if (!fb.free) {
+ return -1;
+
+ }
+
+ via_mmFreeMem((PMemBlock) fb.free);
+
+ if (!del_alloc_set(fb.context, VIDEO, fb.free)) {
+ retval = -1;
+ }
+
+ DRM_DEBUG("free fb, free = %ld\n", fb.free);
+
+ return retval;
+}
+
+static int via_agp_free(drm_via_mem_t * mem)
+{
+ drm_via_mm_t agp;
+
+ int retval = 0;
+
+ agp.free = mem->index;
+ agp.context = mem->context;
+
+ if (!agp.free)
+ return -1;
+
+ via_mmFreeMem((PMemBlock) agp.free);
+
+ if (!del_alloc_set(agp.context, AGP, agp.free)) {
+ retval = -1;
+ }
+
+ DRM_DEBUG("free agp, free = %ld\n", agp.free);
+
+ return retval;
+}
diff --git a/drivers/char/drm/via_mm.h b/drivers/char/drm/via_mm.h
new file mode 100644
index 000000000000..d57efda57c76
--- /dev/null
+++ b/drivers/char/drm/via_mm.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 1998-2003 VIA Technologies, Inc. All Rights Reserved.
+ * Copyright 2001-2003 S3 Graphics, Inc. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * 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.
+ */
+#ifndef _via_drm_mm_h_
+#define _via_drm_mm_h_
+
+typedef struct {
+ unsigned int context;
+ unsigned int size;
+ unsigned long offset;
+ unsigned long free;
+} drm_via_mm_t;
+
+typedef struct {
+ unsigned int size;
+ unsigned long handle;
+ void *virtual;
+} drm_via_dma_t;
+
+#endif
diff --git a/drivers/char/drm/via_verifier.c b/drivers/char/drm/via_verifier.c
new file mode 100644
index 000000000000..07923b0c7a97
--- /dev/null
+++ b/drivers/char/drm/via_verifier.c
@@ -0,0 +1,1061 @@
+/*
+ * Copyright 2004 The Unichrome Project. All Rights Reserved.
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) 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.
+ *
+ * Author: Thomas Hellstrom 2004, 2005.
+ * This code was written using docs obtained under NDA from VIA Inc.
+ *
+ * Don't run this code directly on an AGP buffer. Due to cache problems it will
+ * be very slow.
+ */
+
+
+#include "via_3d_reg.h"
+#include "drmP.h"
+#include "drm.h"
+#include "via_drm.h"
+#include "via_verifier.h"
+#include "via_drv.h"
+
+typedef enum{
+ state_command,
+ state_header2,
+ state_header1,
+ state_vheader5,
+ state_vheader6,
+ state_error
+} verifier_state_t;
+
+
+typedef enum{
+ no_check = 0,
+ check_for_header2,
+ check_for_header1,
+ check_for_header2_err,
+ check_for_header1_err,
+ check_for_fire,
+ check_z_buffer_addr0,
+ check_z_buffer_addr1,
+ check_z_buffer_addr_mode,
+ check_destination_addr0,
+ check_destination_addr1,
+ check_destination_addr_mode,
+ check_for_dummy,
+ check_for_dd,
+ check_texture_addr0,
+ check_texture_addr1,
+ check_texture_addr2,
+ check_texture_addr3,
+ check_texture_addr4,
+ check_texture_addr5,
+ check_texture_addr6,
+ check_texture_addr7,
+ check_texture_addr8,
+ check_texture_addr_mode,
+ check_for_vertex_count,
+ check_number_texunits,
+ forbidden_command
+}hazard_t;
+
+/*
+ * Associates each hazard above with a possible multi-command
+ * sequence. For example an address that is split over multiple
+ * commands and that needs to be checked at the first command
+ * that does not include any part of the address.
+ */
+
+static drm_via_sequence_t seqs[] = {
+ no_sequence,
+ no_sequence,
+ no_sequence,
+ no_sequence,
+ no_sequence,
+ no_sequence,
+ z_address,
+ z_address,
+ z_address,
+ dest_address,
+ dest_address,
+ dest_address,
+ no_sequence,
+ no_sequence,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ tex_address,
+ no_sequence
+};
+
+typedef struct{
+ unsigned int code;
+ hazard_t hz;
+} hz_init_t;
+
+
+
+static hz_init_t init_table1[] = {
+ {0xf2, check_for_header2_err},
+ {0xf0, check_for_header1_err},
+ {0xee, check_for_fire},
+ {0xcc, check_for_dummy},
+ {0xdd, check_for_dd},
+ {0x00, no_check},
+ {0x10, check_z_buffer_addr0},
+ {0x11, check_z_buffer_addr1},
+ {0x12, check_z_buffer_addr_mode},
+ {0x13, no_check},
+ {0x14, no_check},
+ {0x15, no_check},
+ {0x23, no_check},
+ {0x24, no_check},
+ {0x33, no_check},
+ {0x34, no_check},
+ {0x35, no_check},
+ {0x36, no_check},
+ {0x37, no_check},
+ {0x38, no_check},
+ {0x39, no_check},
+ {0x3A, no_check},
+ {0x3B, no_check},
+ {0x3C, no_check},
+ {0x3D, no_check},
+ {0x3E, no_check},
+ {0x40, check_destination_addr0},
+ {0x41, check_destination_addr1},
+ {0x42, check_destination_addr_mode},
+ {0x43, no_check},
+ {0x44, no_check},
+ {0x50, no_check},
+ {0x51, no_check},
+ {0x52, no_check},
+ {0x53, no_check},
+ {0x54, no_check},
+ {0x55, no_check},
+ {0x56, no_check},
+ {0x57, no_check},
+ {0x58, no_check},
+ {0x70, no_check},
+ {0x71, no_check},
+ {0x78, no_check},
+ {0x79, no_check},
+ {0x7A, no_check},
+ {0x7B, no_check},
+ {0x7C, no_check},
+ {0x7D, check_for_vertex_count}
+};
+
+
+
+static hz_init_t init_table2[] = {
+ {0xf2, check_for_header2_err},
+ {0xf0, check_for_header1_err},
+ {0xee, check_for_fire},
+ {0xcc, check_for_dummy},
+ {0x00, check_texture_addr0},
+ {0x01, check_texture_addr0},
+ {0x02, check_texture_addr0},
+ {0x03, check_texture_addr0},
+ {0x04, check_texture_addr0},
+ {0x05, check_texture_addr0},
+ {0x06, check_texture_addr0},
+ {0x07, check_texture_addr0},
+ {0x08, check_texture_addr0},
+ {0x09, check_texture_addr0},
+ {0x20, check_texture_addr1},
+ {0x21, check_texture_addr1},
+ {0x22, check_texture_addr1},
+ {0x23, check_texture_addr4},
+ {0x2B, check_texture_addr3},
+ {0x2C, check_texture_addr3},
+ {0x2D, check_texture_addr3},
+ {0x2E, check_texture_addr3},
+ {0x2F, check_texture_addr3},
+ {0x30, check_texture_addr3},
+ {0x31, check_texture_addr3},
+ {0x32, check_texture_addr3},
+ {0x33, check_texture_addr3},
+ {0x34, check_texture_addr3},
+ {0x4B, check_texture_addr5},
+ {0x4C, check_texture_addr6},
+ {0x51, check_texture_addr7},
+ {0x52, check_texture_addr8},
+ {0x77, check_texture_addr2},
+ {0x78, no_check},
+ {0x79, no_check},
+ {0x7A, no_check},
+ {0x7B, check_texture_addr_mode},
+ {0x7C, no_check},
+ {0x7D, no_check},
+ {0x7E, no_check},
+ {0x7F, no_check},
+ {0x80, no_check},
+ {0x81, no_check},
+ {0x82, no_check},
+ {0x83, no_check},
+ {0x85, no_check},
+ {0x86, no_check},
+ {0x87, no_check},
+ {0x88, no_check},
+ {0x89, no_check},
+ {0x8A, no_check},
+ {0x90, no_check},
+ {0x91, no_check},
+ {0x92, no_check},
+ {0x93, no_check}
+};
+
+static hz_init_t init_table3[] = {
+ {0xf2, check_for_header2_err},
+ {0xf0, check_for_header1_err},
+ {0xcc, check_for_dummy},
+ {0x00, check_number_texunits}
+};
+
+
+static hazard_t table1[256];
+static hazard_t table2[256];
+static hazard_t table3[256];
+
+
+
+static __inline__ int
+eat_words(const uint32_t **buf, const uint32_t *buf_end, unsigned num_words)
+{
+ if ((*buf - buf_end) >= num_words) {
+ *buf += num_words;
+ return 0;
+ }
+ DRM_ERROR("Illegal termination of DMA command buffer\n");
+ return 1;
+}
+
+
+/*
+ * Partially stolen from drm_memory.h
+ */
+
+static __inline__ drm_map_t *
+via_drm_lookup_agp_map (drm_via_state_t *seq, unsigned long offset, unsigned long size,
+ drm_device_t *dev)
+{
+ struct list_head *list;
+ drm_map_list_t *r_list;
+ drm_map_t *map = seq->map_cache;
+
+ if (map && map->offset <= offset && (offset + size) <= (map->offset + map->size)) {
+ return map;
+ }
+
+ list_for_each(list, &dev->maplist->head) {
+ r_list = (drm_map_list_t *) list;
+ map = r_list->map;
+ if (!map)
+ continue;
+ if (map->offset <= offset && (offset + size) <= (map->offset + map->size) &&
+ !(map->flags & _DRM_RESTRICTED) && (map->type == _DRM_AGP)) {
+ seq->map_cache = map;
+ return map;
+ }
+ }
+ return NULL;
+}
+
+
+/*
+ * Require that all AGP texture levels reside in the same AGP map which should
+ * be mappable by the client. This is not a big restriction.
+ * FIXME: To actually enforce this security policy strictly, drm_rmmap
+ * would have to wait for dma quiescent before removing an AGP map.
+ * The via_drm_lookup_agp_map call in reality seems to take
+ * very little CPU time.
+ */
+
+
+static __inline__ int
+finish_current_sequence(drm_via_state_t *cur_seq)
+{
+ switch(cur_seq->unfinished) {
+ case z_address:
+ DRM_DEBUG("Z Buffer start address is 0x%x\n", cur_seq->z_addr);
+ break;
+ case dest_address:
+ DRM_DEBUG("Destination start address is 0x%x\n", cur_seq->d_addr);
+ break;
+ case tex_address:
+ if (cur_seq->agp_texture) {
+ unsigned start = cur_seq->tex_level_lo[cur_seq->texture];
+ unsigned end = cur_seq->tex_level_hi[cur_seq->texture];
+ unsigned long lo=~0, hi=0, tmp;
+ uint32_t *addr, *pitch, *height, tex;
+ unsigned i;
+
+ if (end > 9) end = 9;
+ if (start > 9) start = 9;
+
+ addr =&(cur_seq->t_addr[tex = cur_seq->texture][start]);
+ pitch = &(cur_seq->pitch[tex][start]);
+ height = &(cur_seq->height[tex][start]);
+
+ for (i=start; i<= end; ++i) {
+ tmp = *addr++;
+ if (tmp < lo) lo = tmp;
+ tmp += (*height++ << *pitch++);
+ if (tmp > hi) hi = tmp;
+ }
+
+ if (! via_drm_lookup_agp_map (cur_seq, lo, hi - lo, cur_seq->dev)) {
+ DRM_ERROR("AGP texture is not in allowed map\n");
+ return 2;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ cur_seq->unfinished = no_sequence;
+ return 0;
+}
+
+static __inline__ int
+investigate_hazard( uint32_t cmd, hazard_t hz, drm_via_state_t *cur_seq)
+{
+ register uint32_t tmp, *tmp_addr;
+
+ if (cur_seq->unfinished && (cur_seq->unfinished != seqs[hz])) {
+ int ret;
+ if ((ret = finish_current_sequence(cur_seq))) return ret;
+ }
+
+ switch(hz) {
+ case check_for_header2:
+ if (cmd == HALCYON_HEADER2) return 1;
+ return 0;
+ case check_for_header1:
+ if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;
+ return 0;
+ case check_for_header2_err:
+ if (cmd == HALCYON_HEADER2) return 1;
+ DRM_ERROR("Illegal DMA HALCYON_HEADER2 command\n");
+ break;
+ case check_for_header1_err:
+ if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1) return 1;
+ DRM_ERROR("Illegal DMA HALCYON_HEADER1 command\n");
+ break;
+ case check_for_fire:
+ if ((cmd & HALCYON_FIREMASK) == HALCYON_FIRECMD) return 1;
+ DRM_ERROR("Illegal DMA HALCYON_FIRECMD command\n");
+ break;
+ case check_for_dummy:
+ if (HC_DUMMY == cmd) return 0;
+ DRM_ERROR("Illegal DMA HC_DUMMY command\n");
+ break;
+ case check_for_dd:
+ if (0xdddddddd == cmd) return 0;
+ DRM_ERROR("Illegal DMA 0xdddddddd command\n");
+ break;
+ case check_z_buffer_addr0:
+ cur_seq->unfinished = z_address;
+ cur_seq->z_addr = (cur_seq->z_addr & 0xFF000000) |
+ (cmd & 0x00FFFFFF);
+ return 0;
+ case check_z_buffer_addr1:
+ cur_seq->unfinished = z_address;
+ cur_seq->z_addr = (cur_seq->z_addr & 0x00FFFFFF) |
+ ((cmd & 0xFF) << 24);
+ return 0;
+ case check_z_buffer_addr_mode:
+ cur_seq->unfinished = z_address;
+ if ((cmd & 0x0000C000) == 0) return 0;
+ DRM_ERROR("Attempt to place Z buffer in system memory\n");
+ return 2;
+ case check_destination_addr0:
+ cur_seq->unfinished = dest_address;
+ cur_seq->d_addr = (cur_seq->d_addr & 0xFF000000) |
+ (cmd & 0x00FFFFFF);
+ return 0;
+ case check_destination_addr1:
+ cur_seq->unfinished = dest_address;
+ cur_seq->d_addr = (cur_seq->d_addr & 0x00FFFFFF) |
+ ((cmd & 0xFF) << 24);
+ return 0;
+ case check_destination_addr_mode:
+ cur_seq->unfinished = dest_address;
+ if ((cmd & 0x0000C000) == 0) return 0;
+ DRM_ERROR("Attempt to place 3D drawing buffer in system memory\n");
+ return 2;
+ case check_texture_addr0:
+ cur_seq->unfinished = tex_address;
+ tmp = (cmd >> 24);
+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
+ *tmp_addr = (*tmp_addr & 0xFF000000) | (cmd & 0x00FFFFFF);
+ return 0;
+ case check_texture_addr1:
+ cur_seq->unfinished = tex_address;
+ tmp = ((cmd >> 24) - 0x20);
+ tmp += tmp << 1;
+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][tmp];
+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
+ tmp_addr++;
+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF00) << 16);
+ tmp_addr++;
+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF0000) << 8);
+ return 0;
+ case check_texture_addr2:
+ cur_seq->unfinished = tex_address;
+ cur_seq->tex_level_lo[tmp = cur_seq->texture] = cmd & 0x3F;
+ cur_seq->tex_level_hi[tmp] = (cmd & 0xFC0) >> 6;
+ return 0;
+ case check_texture_addr3:
+ cur_seq->unfinished = tex_address;
+ tmp = ((cmd >> 24) - 0x2B);
+ cur_seq->pitch[cur_seq->texture][tmp] = (cmd & 0x00F00000) >> 20;
+ if (!tmp && (cmd & 0x000FFFFF)) {
+ DRM_ERROR("Unimplemented texture level 0 pitch mode.\n");
+ return 2;
+ }
+ return 0;
+ case check_texture_addr4:
+ cur_seq->unfinished = tex_address;
+ tmp_addr = &cur_seq->t_addr[cur_seq->texture][9];
+ *tmp_addr = (*tmp_addr & 0x00FFFFFF) | ((cmd & 0xFF) << 24);
+ return 0;
+ case check_texture_addr5:
+ case check_texture_addr6:
+ cur_seq->unfinished = tex_address;
+ /*
+ * Texture width. We don't care since we have the pitch.
+ */
+ return 0;
+ case check_texture_addr7:
+ cur_seq->unfinished = tex_address;
+ tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
+ tmp_addr[5] = 1 << ((cmd & 0x00F00000) >> 20);
+ tmp_addr[4] = 1 << ((cmd & 0x000F0000) >> 16);
+ tmp_addr[3] = 1 << ((cmd & 0x0000F000) >> 12);
+ tmp_addr[2] = 1 << ((cmd & 0x00000F00) >> 8);
+ tmp_addr[1] = 1 << ((cmd & 0x000000F0) >> 4);
+ tmp_addr[0] = 1 << (cmd & 0x0000000F);
+ return 0;
+ case check_texture_addr8:
+ cur_seq->unfinished = tex_address;
+ tmp_addr = &(cur_seq->height[cur_seq->texture][0]);
+ tmp_addr[9] = 1 << ((cmd & 0x0000F000) >> 12);
+ tmp_addr[8] = 1 << ((cmd & 0x00000F00) >> 8);
+ tmp_addr[7] = 1 << ((cmd & 0x000000F0) >> 4);
+ tmp_addr[6] = 1 << (cmd & 0x0000000F);
+ return 0;
+ case check_texture_addr_mode:
+ cur_seq->unfinished = tex_address;
+ if ( 2 == (tmp = cmd & 0x00000003)) {
+ DRM_ERROR("Attempt to fetch texture from system memory.\n");
+ return 2;
+ }
+ cur_seq->agp_texture = (tmp == 3);
+ cur_seq->tex_palette_size[cur_seq->texture] =
+ (cmd >> 16) & 0x000000007;
+ return 0;
+ case check_for_vertex_count:
+ cur_seq->vertex_count = cmd & 0x0000FFFF;
+ return 0;
+ case check_number_texunits:
+ cur_seq->multitex = (cmd >> 3) & 1;
+ return 0;
+ default:
+ DRM_ERROR("Illegal DMA data: 0x%x\n", cmd);
+ return 2;
+ }
+ return 2;
+}
+
+
+static __inline__ int
+via_check_prim_list(uint32_t const **buffer, const uint32_t *buf_end,
+ drm_via_state_t *cur_seq)
+{
+ drm_via_private_t *dev_priv = (drm_via_private_t *) cur_seq->dev->dev_private;
+ uint32_t a_fire, bcmd , dw_count;
+ int ret = 0;
+ int have_fire;
+ const uint32_t *buf = *buffer;
+
+ while(buf < buf_end) {
+ have_fire = 0;
+ if ((buf_end - buf) < 2) {
+ DRM_ERROR("Unexpected termination of primitive list.\n");
+ ret = 1;
+ break;
+ }
+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdB) break;
+ bcmd = *buf++;
+ if ((*buf & HC_ACMD_MASK) != HC_ACMD_HCmdA) {
+ DRM_ERROR("Expected Vertex List A command, got 0x%x\n",
+ *buf);
+ ret = 1;
+ break;
+ }
+ a_fire = *buf++ | HC_HPLEND_MASK | HC_HPMValidN_MASK | HC_HE3Fire_MASK;
+
+ /*
+ * How many dwords per vertex ?
+ */
+
+ if (cur_seq->agp && ((bcmd & (0xF << 11)) == 0)) {
+ DRM_ERROR("Illegal B command vertex data for AGP.\n");
+ ret = 1;
+ break;
+ }
+
+ dw_count = 0;
+ if (bcmd & (1 << 7)) dw_count += (cur_seq->multitex) ? 2:1;
+ if (bcmd & (1 << 8)) dw_count += (cur_seq->multitex) ? 2:1;
+ if (bcmd & (1 << 9)) dw_count++;
+ if (bcmd & (1 << 10)) dw_count++;
+ if (bcmd & (1 << 11)) dw_count++;
+ if (bcmd & (1 << 12)) dw_count++;
+ if (bcmd & (1 << 13)) dw_count++;
+ if (bcmd & (1 << 14)) dw_count++;
+
+ while(buf < buf_end) {
+ if (*buf == a_fire) {
+ if (dev_priv->num_fire_offsets >= VIA_FIRE_BUF_SIZE) {
+ DRM_ERROR("Fire offset buffer full.\n");
+ ret = 1;
+ break;
+ }
+ dev_priv->fire_offsets[dev_priv->num_fire_offsets++] = buf;
+ have_fire = 1;
+ buf++;
+ if (buf < buf_end && *buf == a_fire)
+ buf++;
+ break;
+ }
+ if ((*buf == HALCYON_HEADER2) ||
+ ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD)) {
+ DRM_ERROR("Missing Vertex Fire command, "
+ "Stray Vertex Fire command or verifier "
+ "lost sync.\n");
+ ret = 1;
+ break;
+ }
+ if ((ret = eat_words(&buf, buf_end, dw_count)))
+ break;
+ }
+ if (buf >= buf_end && !have_fire) {
+ DRM_ERROR("Missing Vertex Fire command or verifier "
+ "lost sync.\n");
+ ret = 1;
+ break;
+ }
+ if (cur_seq->agp && ((buf - cur_seq->buf_start) & 0x01)) {
+ DRM_ERROR("AGP Primitive list end misaligned.\n");
+ ret = 1;
+ break;
+ }
+ }
+ *buffer = buf;
+ return ret;
+}
+
+
+
+
+
+static __inline__ verifier_state_t
+via_check_header2( uint32_t const **buffer, const uint32_t *buf_end,
+ drm_via_state_t *hc_state)
+{
+ uint32_t cmd;
+ int hz_mode;
+ hazard_t hz;
+ const uint32_t *buf = *buffer;
+ const hazard_t *hz_table;
+
+
+ if ((buf_end - buf) < 2) {
+ DRM_ERROR("Illegal termination of DMA HALCYON_HEADER2 sequence.\n");
+ return state_error;
+ }
+ buf++;
+ cmd = (*buf++ & 0xFFFF0000) >> 16;
+
+ switch(cmd) {
+ case HC_ParaType_CmdVdata:
+ if (via_check_prim_list(&buf, buf_end, hc_state ))
+ return state_error;
+ *buffer = buf;
+ return state_command;
+ case HC_ParaType_NotTex:
+ hz_table = table1;
+ break;
+ case HC_ParaType_Tex:
+ hc_state->texture = 0;
+ hz_table = table2;
+ break;
+ case (HC_ParaType_Tex | (HC_SubType_Tex1 << 8)):
+ hc_state->texture = 1;
+ hz_table = table2;
+ break;
+ case (HC_ParaType_Tex | (HC_SubType_TexGeneral << 8)):
+ hz_table = table3;
+ break;
+ case HC_ParaType_Auto:
+ if (eat_words(&buf, buf_end, 2))
+ return state_error;
+ *buffer = buf;
+ return state_command;
+ case (HC_ParaType_Palette | (HC_SubType_Stipple << 8)):
+ if (eat_words(&buf, buf_end, 32))
+ return state_error;
+ *buffer = buf;
+ return state_command;
+ case (HC_ParaType_Palette | (HC_SubType_TexPalette0 << 8)):
+ case (HC_ParaType_Palette | (HC_SubType_TexPalette1 << 8)):
+ DRM_ERROR("Texture palettes are rejected because of "
+ "lack of info how to determine their size.\n");
+ return state_error;
+ case (HC_ParaType_Palette | (HC_SubType_FogTable << 8)):
+ DRM_ERROR("Fog factor palettes are rejected because of "
+ "lack of info how to determine their size.\n");
+ return state_error;
+ default:
+
+ /*
+ * There are some unimplemented HC_ParaTypes here, that
+ * need to be implemented if the Mesa driver is extended.
+ */
+
+ DRM_ERROR("Invalid or unimplemented HALCYON_HEADER2 "
+ "DMA subcommand: 0x%x. Previous dword: 0x%x\n",
+ cmd, *(buf -2));
+ *buffer = buf;
+ return state_error;
+ }
+
+ while(buf < buf_end) {
+ cmd = *buf++;
+ if ((hz = hz_table[cmd >> 24])) {
+ if ((hz_mode = investigate_hazard(cmd, hz, hc_state))) {
+ if (hz_mode == 1) {
+ buf--;
+ break;
+ }
+ return state_error;
+ }
+ } else if (hc_state->unfinished &&
+ finish_current_sequence(hc_state)) {
+ return state_error;
+ }
+ }
+ if (hc_state->unfinished && finish_current_sequence(hc_state)) {
+ return state_error;
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+static __inline__ verifier_state_t
+via_parse_header2( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end,
+ int *fire_count)
+{
+ uint32_t cmd;
+ const uint32_t *buf = *buffer;
+ const uint32_t *next_fire;
+ int burst = 0;
+
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ buf++;
+ cmd = (*buf & 0xFFFF0000) >> 16;
+ VIA_WRITE(HC_REG_TRANS_SET + HC_REG_BASE, *buf++);
+ switch(cmd) {
+ case HC_ParaType_CmdVdata:
+ while ((buf < buf_end) &&
+ (*fire_count < dev_priv->num_fire_offsets) &&
+ (*buf & HC_ACMD_MASK) == HC_ACMD_HCmdB ) {
+ while(buf <= next_fire) {
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst += 4;
+ }
+ if ( ( buf < buf_end ) && ((*buf & HALCYON_FIREMASK) == HALCYON_FIRECMD))
+ buf++;
+
+ if (++(*fire_count) < dev_priv->num_fire_offsets)
+ next_fire = dev_priv->fire_offsets[*fire_count];
+ }
+ break;
+ default:
+ while(buf < buf_end) {
+
+ if ( *buf == HC_HEADER2 ||
+ (*buf & HALCYON_HEADER1MASK) == HALCYON_HEADER1 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5 ||
+ (*buf & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6 ) break;
+
+ VIA_WRITE(HC_REG_TRANS_SPACE + HC_REG_BASE + (burst & 63), *buf++);
+ burst +=4;
+ }
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+
+
+static __inline__ int
+verify_mmio_address( uint32_t address)
+{
+ if ((address > 0x3FF) && (address < 0xC00 )) {
+ DRM_ERROR("Invalid VIDEO DMA command. "
+ "Attempt to access 3D- or command burst area.\n");
+ return 1;
+ } else if ((address > 0xCFF) && (address < 0x1300)) {
+ DRM_ERROR("Invalid VIDEO DMA command. "
+ "Attempt to access PCI DMA area.\n");
+ return 1;
+ } else if (address > 0x13FF ) {
+ DRM_ERROR("Invalid VIDEO DMA command. "
+ "Attempt to access VGA registers.\n");
+ return 1;
+ }
+ return 0;
+}
+
+static __inline__ int
+verify_video_tail( uint32_t const **buffer, const uint32_t *buf_end, uint32_t dwords)
+{
+ const uint32_t *buf = *buffer;
+
+ if (buf_end - buf < dwords) {
+ DRM_ERROR("Illegal termination of video command.\n");
+ return 1;
+ }
+ while (dwords--) {
+ if (*buf++) {
+ DRM_ERROR("Illegal video command tail.\n");
+ return 1;
+ }
+ }
+ *buffer = buf;
+ return 0;
+}
+
+
+static __inline__ verifier_state_t
+via_check_header1( uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t cmd;
+ const uint32_t *buf = *buffer;
+ verifier_state_t ret = state_command;
+
+ while (buf < buf_end) {
+ cmd = *buf;
+ if ((cmd > ((0x3FF >> 2) | HALCYON_HEADER1)) &&
+ (cmd < ((0xC00 >> 2) | HALCYON_HEADER1))) {
+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
+ break;
+ DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ "Attempt to access 3D- or command burst area.\n");
+ ret = state_error;
+ break;
+ } else if (cmd > ((0xCFF >> 2) | HALCYON_HEADER1)) {
+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1)
+ break;
+ DRM_ERROR("Invalid HALCYON_HEADER1 command. "
+ "Attempt to access VGA registers.\n");
+ ret = state_error;
+ break;
+ } else {
+ buf += 2;
+ }
+ }
+ *buffer = buf;
+ return ret;
+}
+
+static __inline__ verifier_state_t
+via_parse_header1( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ register uint32_t cmd;
+ const uint32_t *buf = *buffer;
+
+ while (buf < buf_end) {
+ cmd = *buf;
+ if ((cmd & HALCYON_HEADER1MASK) != HALCYON_HEADER1) break;
+ VIA_WRITE( (cmd & ~HALCYON_HEADER1MASK) << 2, *++buf);
+ buf++;
+ }
+ *buffer = buf;
+ return state_command;
+}
+
+static __inline__ verifier_state_t
+via_check_vheader5( uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t data;
+ const uint32_t *buf = *buffer;
+
+ if (buf_end - buf < 4) {
+ DRM_ERROR("Illegal termination of video header5 command\n");
+ return state_error;
+ }
+
+ data = *buf++ & ~VIA_VIDEOMASK;
+ if (verify_mmio_address(data))
+ return state_error;
+
+ data = *buf++;
+ if (*buf++ != 0x00F50000) {
+ DRM_ERROR("Illegal header5 header data\n");
+ return state_error;
+ }
+ if (*buf++ != 0x00000000) {
+ DRM_ERROR("Illegal header5 header data\n");
+ return state_error;
+ }
+ if (eat_words(&buf, buf_end, data))
+ return state_error;
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
+ return state_error;
+ *buffer = buf;
+ return state_command;
+
+}
+
+static __inline__ verifier_state_t
+via_parse_vheader5( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ addr = *buf++ & ~VIA_VIDEOMASK;
+ i = count = *buf;
+ buf += 3;
+ while(i--) {
+ VIA_WRITE(addr, *buf++);
+ }
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
+static __inline__ verifier_state_t
+via_check_vheader6( uint32_t const **buffer, const uint32_t *buf_end )
+{
+ uint32_t data;
+ const uint32_t *buf = *buffer;
+ uint32_t i;
+
+
+ if (buf_end - buf < 4) {
+ DRM_ERROR("Illegal termination of video header6 command\n");
+ return state_error;
+ }
+ buf++;
+ data = *buf++;
+ if (*buf++ != 0x00F60000) {
+ DRM_ERROR("Illegal header6 header data\n");
+ return state_error;
+ }
+ if (*buf++ != 0x00000000) {
+ DRM_ERROR("Illegal header6 header data\n");
+ return state_error;
+ }
+ if ((buf_end - buf) < (data << 1)) {
+ DRM_ERROR("Illegal termination of video header6 command\n");
+ return state_error;
+ }
+ for (i=0; i<data; ++i) {
+ if (verify_mmio_address(*buf++))
+ return state_error;
+ buf++;
+ }
+ data <<= 1;
+ if ((data & 3) && verify_video_tail(&buf, buf_end, 4 - (data & 3)))
+ return state_error;
+ *buffer = buf;
+ return state_command;
+}
+
+static __inline__ verifier_state_t
+via_parse_vheader6( drm_via_private_t *dev_priv, uint32_t const **buffer, const uint32_t *buf_end )
+{
+
+ uint32_t addr, count, i;
+ const uint32_t *buf = *buffer;
+
+ i = count = *++buf;
+ buf += 3;
+ while(i--) {
+ addr = *buf++;
+ VIA_WRITE(addr, *buf++);
+ }
+ count <<= 1;
+ if (count & 3) buf += 4 - (count & 3);
+ *buffer = buf;
+ return state_command;
+}
+
+
+
+int
+via_verify_command_stream(const uint32_t * buf, unsigned int size, drm_device_t *dev,
+ int agp)
+{
+
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_state_t *hc_state = &dev_priv->hc_state;
+ drm_via_state_t saved_state = *hc_state;
+ uint32_t cmd;
+ const uint32_t *buf_end = buf + ( size >> 2 );
+ verifier_state_t state = state_command;
+ int pro_group_a = dev_priv->pro_group_a;
+
+ hc_state->dev = dev;
+ hc_state->unfinished = no_sequence;
+ hc_state->map_cache = NULL;
+ hc_state->agp = agp;
+ hc_state->buf_start = buf;
+ dev_priv->num_fire_offsets = 0;
+
+ while (buf < buf_end) {
+
+ switch (state) {
+ case state_header2:
+ state = via_check_header2( &buf, buf_end, hc_state );
+ break;
+ case state_header1:
+ state = via_check_header1( &buf, buf_end );
+ break;
+ case state_vheader5:
+ state = via_check_vheader5( &buf, buf_end );
+ break;
+ case state_vheader6:
+ state = via_check_vheader6( &buf, buf_end );
+ break;
+ case state_command:
+ if (HALCYON_HEADER2 == (cmd = *buf))
+ state = state_header2;
+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
+ state = state_header1;
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ state = state_vheader5;
+ else if (pro_group_a && (cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ state = state_vheader6;
+ else {
+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+ cmd);
+ state = state_error;
+ }
+ break;
+ case state_error:
+ default:
+ *hc_state = saved_state;
+ return DRM_ERR(EINVAL);
+ }
+ }
+ if (state == state_error) {
+ *hc_state = saved_state;
+ return DRM_ERR(EINVAL);
+ }
+ return 0;
+}
+
+int
+via_parse_command_stream(drm_device_t *dev, const uint32_t * buf, unsigned int size)
+{
+
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ uint32_t cmd;
+ const uint32_t *buf_end = buf + ( size >> 2 );
+ verifier_state_t state = state_command;
+ int fire_count = 0;
+
+ while (buf < buf_end) {
+
+ switch (state) {
+ case state_header2:
+ state = via_parse_header2( dev_priv, &buf, buf_end, &fire_count );
+ break;
+ case state_header1:
+ state = via_parse_header1( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader5:
+ state = via_parse_vheader5( dev_priv, &buf, buf_end );
+ break;
+ case state_vheader6:
+ state = via_parse_vheader6( dev_priv, &buf, buf_end );
+ break;
+ case state_command:
+ if (HALCYON_HEADER2 == (cmd = *buf))
+ state = state_header2;
+ else if ((cmd & HALCYON_HEADER1MASK) == HALCYON_HEADER1)
+ state = state_header1;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER5)
+ state = state_vheader5;
+ else if ((cmd & VIA_VIDEOMASK) == VIA_VIDEO_HEADER6)
+ state = state_vheader6;
+ else {
+ DRM_ERROR("Invalid / Unimplemented DMA HEADER command. 0x%x\n",
+ cmd);
+ state = state_error;
+ }
+ break;
+ case state_error:
+ default:
+ return DRM_ERR(EINVAL);
+ }
+ }
+ if (state == state_error) {
+ return DRM_ERR(EINVAL);
+ }
+ return 0;
+}
+
+
+
+static void
+setup_hazard_table(hz_init_t init_table[], hazard_t table[], int size)
+{
+ int i;
+
+ for(i=0; i<256; ++i) {
+ table[i] = forbidden_command;
+ }
+
+ for(i=0; i<size; ++i) {
+ table[init_table[i].code] = init_table[i].hz;
+ }
+}
+
+void
+via_init_command_verifier( void )
+{
+ setup_hazard_table(init_table1, table1, sizeof(init_table1) / sizeof(hz_init_t));
+ setup_hazard_table(init_table2, table2, sizeof(init_table2) / sizeof(hz_init_t));
+ setup_hazard_table(init_table3, table3, sizeof(init_table3) / sizeof(hz_init_t));
+}
diff --git a/drivers/char/drm/via_verifier.h b/drivers/char/drm/via_verifier.h
new file mode 100644
index 000000000000..a8e13592620f
--- /dev/null
+++ b/drivers/char/drm/via_verifier.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2004 The Unichrome Project. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE UNICHROME PROJECT, 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.
+ *
+ * Author: Thomas Hellström 2004.
+ */
+
+#ifndef _VIA_VERIFIER_H_
+#define _VIA_VERIFIER_H_
+
+typedef enum{
+ no_sequence = 0,
+ z_address,
+ dest_address,
+ tex_address
+}drm_via_sequence_t;
+
+
+
+typedef struct{
+ unsigned texture;
+ uint32_t z_addr;
+ uint32_t d_addr;
+ uint32_t t_addr[2][10];
+ uint32_t pitch[2][10];
+ uint32_t height[2][10];
+ uint32_t tex_level_lo[2];
+ uint32_t tex_level_hi[2];
+ uint32_t tex_palette_size[2];
+ drm_via_sequence_t unfinished;
+ int agp_texture;
+ int multitex;
+ drm_device_t *dev;
+ drm_map_t *map_cache;
+ uint32_t vertex_count;
+ int agp;
+ const uint32_t *buf_start;
+} drm_via_state_t;
+
+extern int via_verify_command_stream(const uint32_t * buf, unsigned int size,
+ drm_device_t *dev, int agp);
+
+#endif
diff --git a/drivers/char/drm/via_video.c b/drivers/char/drm/via_video.c
new file mode 100644
index 000000000000..37a61c67b292
--- /dev/null
+++ b/drivers/char/drm/via_video.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2005 Thomas Hellstrom. All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHOR(S), AND/OR THE COPYRIGHT HOLDER(S) 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.
+ *
+ * Author: Thomas Hellstrom 2005.
+ *
+ * Video and XvMC related functions.
+ */
+
+#include "drmP.h"
+#include "via_drm.h"
+#include "via_drv.h"
+
+void
+via_init_futex(drm_via_private_t *dev_priv)
+{
+ unsigned int i;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
+ DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
+ XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
+ }
+}
+
+void
+via_cleanup_futex(drm_via_private_t *dev_priv)
+{
+}
+
+void
+via_release_futex(drm_via_private_t *dev_priv, int context)
+{
+ unsigned int i;
+ volatile int *lock;
+
+ for (i=0; i < VIA_NR_XVMC_LOCKS; ++i) {
+ lock = (int *) XVMCLOCKPTR(dev_priv->sarea_priv, i);
+ if ( (_DRM_LOCKING_CONTEXT( *lock ) == context)) {
+ if (_DRM_LOCK_IS_HELD( *lock ) && (*lock & _DRM_LOCK_CONT)) {
+ DRM_WAKEUP( &(dev_priv->decoder_queue[i]));
+ }
+ *lock = 0;
+ }
+ }
+}
+
+int
+via_decoder_futex(DRM_IOCTL_ARGS)
+{
+ DRM_DEVICE;
+ drm_via_futex_t fx;
+ volatile int *lock;
+ drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
+ drm_via_sarea_t *sAPriv = dev_priv->sarea_priv;
+ int ret = 0;
+
+ DRM_DEBUG("%s\n", __FUNCTION__);
+
+ DRM_COPY_FROM_USER_IOCTL(fx, (drm_via_futex_t *) data, sizeof(fx));
+
+ if (fx.lock > VIA_NR_XVMC_LOCKS)
+ return -EFAULT;
+
+ lock = (int *)XVMCLOCKPTR(sAPriv, fx.lock);
+
+ switch (fx.func) {
+ case VIA_FUTEX_WAIT:
+ DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx.lock],
+ (fx.ms / 10) * (DRM_HZ / 100), *lock != fx.val);
+ return ret;
+ case VIA_FUTEX_WAKE:
+ DRM_WAKEUP(&(dev_priv->decoder_queue[fx.lock]));
+ return 0;
+ }
+ return 0;
+}
+
diff --git a/drivers/char/ds1620.c b/drivers/char/ds1620.c
index 7def6ad51798..62cda25724e3 100644
--- a/drivers/char/ds1620.c
+++ b/drivers/char/ds1620.c
@@ -163,8 +163,7 @@ static void ds1620_out(int cmd, int bits, int value)
netwinder_ds1620_reset();
netwinder_unlock(&flags);
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(2);
+ msleep(20);
}
static unsigned int ds1620_in(int cmd, int bits)
diff --git a/drivers/char/ftape/compressor/zftape-compress.c b/drivers/char/ftape/compressor/zftape-compress.c
index 220a227e6061..65ffc0be3df9 100644
--- a/drivers/char/ftape/compressor/zftape-compress.c
+++ b/drivers/char/ftape/compressor/zftape-compress.c
@@ -1176,8 +1176,8 @@ KERN_INFO "Compressor for zftape (lzrw3 algorithm)\n");
}
#else /* !MODULE */
/* print a short no-nonsense boot message */
- printk("zftape compressor v1.00a 970514\n");
- printk("For use with " FTAPE_VERSION "\n");
+ printk(KERN_INFO "zftape compressor v1.00a 970514\n");
+ printk(KERN_INFO "For use with " FTAPE_VERSION "\n");
#endif /* MODULE */
TRACE(ft_t_info, "zft_compressor_init @ 0x%p", zft_compressor_init);
TRACE(ft_t_info, "installing compressor for zftape ...");
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index 5ec732e6ca92..762fa430fb5b 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -834,7 +834,7 @@ int hpet_alloc(struct hpet_data *hdp)
printk("\n");
ns = hpetp->hp_period; /* femptoseconds, 10^-15 */
- do_div(ns, 1000000); /* convert to nanoseconds, 10^-9 */
+ ns /= 1000000; /* convert to nanoseconds, 10^-9 */
printk(KERN_INFO "hpet%d: %ldns tick, %d %d-bit timers\n",
hpetp->hp_which, ns, hpetp->hp_ntimer,
cap & HPET_COUNTER_SIZE_MASK ? 64 : 32);
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
index 88cd858f74d0..cddb789902db 100644
--- a/drivers/char/hvc_console.c
+++ b/drivers/char/hvc_console.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <linux/config.h>
#include <linux/console.h>
#include <linux/cpumask.h>
#include <linux/init.h>
@@ -40,7 +41,6 @@
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/hvconsole.h>
-#include <asm/vio.h>
#define HVC_MAJOR 229
#define HVC_MINOR 0
@@ -61,16 +61,21 @@
*/
#define HVC_ALLOC_TTY_ADAPTERS 8
-static struct tty_driver *hvc_driver;
-#ifdef CONFIG_MAGIC_SYSRQ
-static int sysrq_pressed;
-#endif
-
#define N_OUTBUF 16
#define N_INBUF 16
#define __ALIGNED__ __attribute__((__aligned__(8)))
+static struct tty_driver *hvc_driver;
+static struct task_struct *hvc_task;
+
+/* Picks up late kicks after list walk but before schedule() */
+static int hvc_kicked;
+
+#ifdef CONFIG_MAGIC_SYSRQ
+static int sysrq_pressed;
+#endif
+
struct hvc_struct {
spinlock_t lock;
int index;
@@ -80,11 +85,11 @@ struct hvc_struct {
char outbuf[N_OUTBUF] __ALIGNED__;
int n_outbuf;
uint32_t vtermno;
+ struct hv_ops *ops;
int irq_requested;
int irq;
struct list_head next;
struct kobject kobj; /* ref count & hvc_struct lifetime */
- struct vio_dev *vdev;
};
/* dynamic list of hvc_struct instances */
@@ -97,26 +102,185 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs);
static DEFINE_SPINLOCK(hvc_structs_lock);
/*
+ * This value is used to assign a tty->index value to a hvc_struct based
+ * upon order of exposure via hvc_probe(), when we can not match it to
+ * a console canidate registered with hvc_instantiate().
+ */
+static int last_hvc = -1;
+
+/*
+ * 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;
+}
+
+
+/*
* 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];
+static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
+static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
+ {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
-/* Used for accounting purposes */
-static int num_vterms = 0;
+/*
+ * Console APIs, NOT TTY. These APIs are available immediately when
+ * hvc_console_setup() finds adapters.
+ */
-static struct task_struct *hvc_task;
+void hvc_console_print(struct console *co, const char *b, unsigned count)
+{
+ char c[16] __ALIGNED__;
+ unsigned i = 0, n = 0;
+ int r, donecr = 0, index = co->index;
+
+ /* Console access attempt outside of acceptable console range. */
+ if (index >= MAX_NR_HVC_CONSOLES)
+ return;
+
+ /* This console adapter was removed so it is not useable. */
+ if (vtermnos[index] < 0)
+ return;
+
+ while (count > 0 || i > 0) {
+ if (count > 0 && i < sizeof(c)) {
+ if (b[n] == '\n' && !donecr) {
+ c[i++] = '\r';
+ donecr = 1;
+ } else {
+ c[i++] = b[n++];
+ donecr = 0;
+ --count;
+ }
+ } else {
+ r = cons_ops[index]->put_chars(vtermnos[index], c, i);
+ if (r < 0) {
+ /* throw away chars on error */
+ i = 0;
+ } else if (r > 0) {
+ i -= r;
+ if (i > 0)
+ memmove(c, c+r, i);
+ }
+ }
+ }
+}
+
+static struct tty_driver *hvc_console_device(struct console *c, int *index)
+{
+ if (vtermnos[c->index] == -1)
+ return NULL;
+
+ *index = c->index;
+ return hvc_driver;
+}
+
+static int __init hvc_console_setup(struct console *co, char *options)
+{
+ if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
+ return -ENODEV;
+
+ if (vtermnos[co->index] == -1)
+ return -ENODEV;
+
+ return 0;
+}
+
+struct console hvc_con_driver = {
+ .name = "hvc",
+ .write = hvc_console_print,
+ .device = hvc_console_device,
+ .setup = hvc_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
/*
- * This value is used to associate a tty->index value to a hvc_struct based
- * upon order of exposure via hvc_probe().
+ * Early console initialization. Preceeds driver initialization.
+ *
+ * (1) we are first, and the user specified another driver
+ * -- index will remain -1
+ * (2) we are first and the user specified no driver
+ * -- index will be set to 0, then we will fail setup.
+ * (3) we are first and the user specified our driver
+ * -- index will be set to user specified driver, and we will fail
+ * (4) we are after driver, and this initcall will register us
+ * -- if the user didn't specify a driver then the console will match
+ *
+ * Note that for cases 2 and 3, we will match later when the io driver
+ * calls hvc_instantiate() and call register again.
*/
-static int hvc_count = -1;
+static int __init hvc_console_init(void)
+{
+ register_console(&hvc_con_driver);
+ return 0;
+}
+console_initcall(hvc_console_init);
-/* Picks up late kicks after list walk but before schedule() */
-static int hvc_kicked;
+/*
+ * 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 they
+ * appear after early console init.
+ */
+int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
+{
+ struct hvc_struct *hp;
+
+ if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
+ return -1;
+
+ if (vtermnos[index] != -1)
+ return -1;
+
+ /* make sure no no tty has been registerd in this index */
+ hp = hvc_get_by_index(index);
+ if (hp) {
+ kobject_put(&hp->kobj);
+ return -1;
+ }
+
+ vtermnos[index] = vtermno;
+ cons_ops[index] = ops;
+
+ /* reserve all indices upto and including this index */
+ if (last_hvc < index)
+ last_hvc = index;
+
+ /* if this index is what the user requested, then register
+ * now (setup won't fail at this point). It's ok to just
+ * call register again if previously .setup failed.
+ */
+ if (index == hvc_con_driver.index)
+ register_console(&hvc_con_driver);
+
+ return 0;
+}
+EXPORT_SYMBOL(hvc_instantiate);
/* Wake the sleeping khvcd */
static void hvc_kick(void)
@@ -125,13 +289,17 @@ static void hvc_kick(void)
wake_up_process(hvc_task);
}
+static int hvc_poll(struct hvc_struct *hp);
+
/*
* 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();
+ /* if hvc_poll request a repoll, then kick the hvcd thread */
+ if (hvc_poll(dev_instance))
+ hvc_kick();
return IRQ_HANDLED;
}
@@ -141,34 +309,6 @@ static void hvc_unthrottle(struct tty_struct *tty)
}
/*
- * 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.
*/
@@ -329,7 +469,7 @@ static void hvc_push(struct hvc_struct *hp)
{
int n;
- n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
+ n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
if (n <= 0) {
if (n == 0)
return;
@@ -467,7 +607,7 @@ static int hvc_poll(struct hvc_struct *hp)
break;
}
- n = hvc_get_chars(hp->vtermno, buf, count);
+ n = hp->ops->get_chars(hp->vtermno, buf, count);
if (n <= 0) {
/* Hangup the tty when disconnected from host */
if (n == -EPIPE) {
@@ -479,14 +619,17 @@ static int hvc_poll(struct hvc_struct *hp)
}
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;
+ if (hp->index == hvc_con_driver.index) {
+ /* Handle the SysRq Hack */
+ /* XXX should support a sequence */
+ if (buf[i] == '\x0f') { /* ^O */
+ 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);
@@ -497,8 +640,8 @@ static int hvc_poll(struct hvc_struct *hp)
/*
* 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.
+ * 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) {
@@ -542,7 +685,6 @@ int khvcd(void *unused)
if (cpus_empty(cpus_in_xmon)) {
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);
@@ -577,14 +719,6 @@ static struct tty_operations hvc_ops = {
.chars_in_buffer = hvc_chars_in_buffer,
};
-char hvc_driver_name[] = "hvc_console";
-
-static struct vio_device_id hvc_driver_table[] __devinitdata= {
- {"serial", "hvterm1"},
- { NULL, }
-};
-MODULE_DEVICE_TABLE(vio, hvc_driver_table);
-
/* callback when the kboject ref count reaches zero. */
static void destroy_hvc_struct(struct kobject *kobj)
{
@@ -606,41 +740,51 @@ 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 __devinit *hvc_alloc(uint32_t vtermno, int irq,
+ struct hv_ops *ops)
{
struct hvc_struct *hp;
-
- /* probed with invalid parameters. */
- if (!dev || !id)
- return -EPERM;
+ int i;
hp = kmalloc(sizeof(*hp), GFP_KERNEL);
if (!hp)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
memset(hp, 0x00, sizeof(*hp));
- hp->vtermno = dev->unit_address;
- hp->vdev = dev;
- hp->vdev->dev.driver_data = hp;
- hp->irq = dev->irq;
+
+ hp->vtermno = vtermno;
+ hp->irq = irq;
+ hp->ops = ops;
kobject_init(&hp->kobj);
hp->kobj.ktype = &hvc_kobj_type;
spin_lock_init(&hp->lock);
spin_lock(&hvc_structs_lock);
- hp->index = ++hvc_count;
+
+ /*
+ * find index to use:
+ * see if this vterm id matches one registered for console.
+ */
+ for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
+ if (vtermnos[i] == hp->vtermno)
+ break;
+
+ /* no matching slot, just use a counter */
+ if (i >= MAX_NR_HVC_CONSOLES)
+ i = ++last_hvc;
+
+ hp->index = i;
+
list_add_tail(&(hp->next), &hvc_structs);
spin_unlock(&hvc_structs_lock);
- return 0;
+ return hp;
}
+EXPORT_SYMBOL(hvc_alloc);
-static int __devexit hvc_remove(struct vio_dev *dev)
+int __devexit hvc_remove(struct hvc_struct *hp)
{
- struct hvc_struct *hp = dev->dev.driver_data;
unsigned long flags;
struct kobject *kobjp;
struct tty_struct *tty;
@@ -673,23 +817,14 @@ static int __devexit hvc_remove(struct vio_dev *dev)
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,
-};
+EXPORT_SYMBOL(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. */
+ /* We need more than hvc_count 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;
@@ -716,116 +851,20 @@ int __init hvc_init(void)
return -EIO;
}
- /* Register as a vio device to receive callbacks */
- rc = vio_register_driver(&hvc_vio_driver);
-
- return rc;
+ return 0;
}
+module_init(hvc_init);
-/* This isn't particularily necessary due to this being a console driver but it
- * is nice to be thorough */
+/* 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);
+ unregister_console(&hvc_con_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 = 0, n = 0;
- int r, donecr = 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) {
- c[i++] = '\r';
- donecr = 1;
- } else {
- c[i++] = b[n++];
- donecr = 0;
- --count;
- }
- } else {
- r = hvc_put_chars(vtermnos[co->index], c, i);
- if (r < 0) {
- /* throw away chars on error */
- i = 0;
- } else if (r > 0) {
- i -= r;
- if (i > 0)
- memmove(c, c+r, i);
- }
- }
- }
-}
-
-static struct tty_driver *hvc_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return hvc_driver;
-}
-
-static int __init hvc_console_setup(struct console *co, char *options)
-{
- return 0;
-}
-
-struct console hvc_con_driver = {
- .name = "hvc",
- .write = hvc_console_print,
- .device = hvc_console_device,
- .setup = hvc_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/* Early console initialization. Preceeds driver initialization. */
-static int __init hvc_console_init(void)
-{
- int i;
-
- for (i=0; i<MAX_NR_HVC_CONSOLES; i++)
- vtermnos[i] = -1;
- num_vterms = hvc_find_vtys();
- register_console(&hvc_con_driver);
- return 0;
-}
-console_initcall(hvc_console_init);
-
-module_init(hvc_init);
module_exit(hvc_exit);
diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c
new file mode 100644
index 000000000000..60bb9152b832
--- /dev/null
+++ b/drivers/char/hvc_vio.c
@@ -0,0 +1,152 @@
+/*
+ * vio driver interface to hvc_console.c
+ *
+ * This code was moved here to allow the remaing code to be reused as a
+ * generic polling mode with semi-reliable transport driver core to the
+ * console and tty subsystems.
+ *
+ *
+ * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM
+ * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM
+ * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp.
+ * Copyright (C) 2004 IBM Corporation
+ *
+ * Additional Author(s):
+ * Ryan S. Arnold <rsa@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
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <asm/hvconsole.h>
+#include <asm/vio.h>
+#include <asm/prom.h>
+
+char hvc_driver_name[] = "hvc_console";
+
+static struct vio_device_id hvc_driver_table[] __devinitdata = {
+ {"serial", "hvterm1"},
+ { NULL, }
+};
+MODULE_DEVICE_TABLE(vio, hvc_driver_table);
+
+static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
+{
+ unsigned long got;
+ int i;
+
+ got = hvc_get_chars(vtermno, buf, count);
+
+ /*
+ * Work around a HV bug where it gives us a null
+ * after every \r. -- paulus
+ */
+ for (i = 1; i < got; ++i) {
+ if (buf[i] == 0 && buf[i-1] == '\r') {
+ --got;
+ if (i < got)
+ memmove(&buf[i], &buf[i+1],
+ got - i);
+ }
+ }
+ return got;
+}
+
+static struct hv_ops hvc_get_put_ops = {
+ .get_chars = filtered_get_chars,
+ .put_chars = hvc_put_chars,
+};
+
+static int __devinit hvc_vio_probe(struct vio_dev *vdev,
+ const struct vio_device_id *id)
+{
+ struct hvc_struct *hp;
+
+ /* probed with invalid parameters. */
+ if (!vdev || !id)
+ return -EPERM;
+
+ hp = hvc_alloc(vdev->unit_address, vdev->irq, &hvc_get_put_ops);
+ if (IS_ERR(hp))
+ return PTR_ERR(hp);
+ dev_set_drvdata(&vdev->dev, hp);
+
+ return 0;
+}
+
+static int __devexit hvc_vio_remove(struct vio_dev *vdev)
+{
+ struct hvc_struct *hp = dev_get_drvdata(&vdev->dev);
+
+ return hvc_remove(hp);
+}
+
+static struct vio_driver hvc_vio_driver = {
+ .name = hvc_driver_name,
+ .id_table = hvc_driver_table,
+ .probe = hvc_vio_probe,
+ .remove = hvc_vio_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ }
+};
+
+static int hvc_vio_init(void)
+{
+ int rc;
+
+ /* Register as a vio device to receive callbacks */
+ rc = vio_register_driver(&hvc_vio_driver);
+
+ return rc;
+}
+module_init(hvc_vio_init); /* after drivers/char/hvc_console.c */
+
+static void hvc_vio_exit(void)
+{
+ vio_unregister_driver(&hvc_vio_driver);
+}
+module_exit(hvc_vio_exit);
+
+/* the device tree order defines our numbering */
+static int hvc_find_vtys(void)
+{
+ struct device_node *vty;
+ int num_found = 0;
+
+ 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;
+
+ vtermno = (uint32_t *)get_property(vty, "reg", NULL);
+ if (!vtermno)
+ continue;
+
+ if (device_is_compatible(vty, "hvterm1")) {
+ hvc_instantiate(*vtermno, num_found, &hvc_get_put_ops);
+ ++num_found;
+ }
+ }
+
+ return num_found;
+}
+console_initcall(hvc_find_vtys);
diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c
index f1f1192ba2b5..a22aa940e01e 100644
--- a/drivers/char/hvsi.c
+++ b/drivers/char/hvsi.c
@@ -291,15 +291,13 @@ static void dump_packet(uint8_t *packet)
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;
+ got = hvc_get_chars(hp->vtermno, buf, count);
+
+ return got;
}
static void hvsi_recv_control(struct hvsi_struct *hp, uint8_t *packet,
diff --git a/drivers/char/hw_random.c b/drivers/char/hw_random.c
index 7e6ac14c2450..3480535a09c5 100644
--- a/drivers/char/hw_random.c
+++ b/drivers/char/hw_random.c
@@ -579,7 +579,7 @@ static int __init rng_init (void)
/* Probe for Intel, AMD RNGs */
for_each_pci_dev(pdev) {
- ent = pci_match_device (rng_pci_tbl, pdev);
+ ent = pci_match_id(rng_pci_tbl, pdev);
if (ent) {
rng_ops = &rng_vendor_ops[ent->driver_data];
goto match;
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index a81197640283..6c4b3f986d0c 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -20,13 +20,14 @@
#include <linux/types.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
-#include <linux/apm_bios.h>
+#include <linux/seq_file.h>
+#include <linux/dmi.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/i8k.h>
-#define I8K_VERSION "1.13 14/05/2002"
+#define I8K_VERSION "1.14 21/02/2005"
#define I8K_SMM_FN_STATUS 0x0025
#define I8K_SMM_POWER_STATUS 0x0069
@@ -34,7 +35,8 @@
#define I8K_SMM_GET_FAN 0x00a3
#define I8K_SMM_GET_SPEED 0x02a3
#define I8K_SMM_GET_TEMP 0x10a3
-#define I8K_SMM_GET_DELL_SIG 0xffa3
+#define I8K_SMM_GET_DELL_SIG1 0xfea3
+#define I8K_SMM_GET_DELL_SIG2 0xffa3
#define I8K_SMM_BIOS_VERSION 0x00a6
#define I8K_FAN_MULT 30
@@ -52,18 +54,7 @@
#define I8K_TEMPERATURE_BUG 1
-#define DELL_SIGNATURE "Dell Computer"
-
-static char *supported_models[] = {
- "Inspiron",
- "Latitude",
- NULL
-};
-
-static char system_vendor[48] = "?";
-static char product_name [48] = "?";
-static char bios_version [4] = "?";
-static char serial_number[16] = "?";
+static char bios_version[4];
MODULE_AUTHOR("Massimo Dal Zotto (dz@debian.org)");
MODULE_DESCRIPTION("Driver for accessing SMM BIOS on Dell laptops");
@@ -73,6 +64,10 @@ static int force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force, "Force loading without checking for supported models");
+static int ignore_dmi;
+module_param(ignore_dmi, bool, 0);
+MODULE_PARM_DESC(ignore_dmi, "Continue probing hardware even if DMI data does not match");
+
static int restricted;
module_param(restricted, bool, 0);
MODULE_PARM_DESC(restricted, "Allow fan control if SYS_ADMIN capability set");
@@ -81,69 +76,69 @@ static int power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
-static ssize_t i8k_read(struct file *, char __user *, size_t, loff_t *);
+static int i8k_open_fs(struct inode *inode, struct file *file);
static int i8k_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
static struct file_operations i8k_fops = {
- .read = i8k_read,
- .ioctl = i8k_ioctl,
+ .open = i8k_open_fs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .ioctl = i8k_ioctl,
+};
+
+struct smm_regs {
+ unsigned int eax;
+ unsigned int ebx __attribute__ ((packed));
+ unsigned int ecx __attribute__ ((packed));
+ unsigned int edx __attribute__ ((packed));
+ unsigned int esi __attribute__ ((packed));
+ unsigned int edi __attribute__ ((packed));
};
-typedef struct {
- unsigned int eax;
- unsigned int ebx __attribute__ ((packed));
- unsigned int ecx __attribute__ ((packed));
- unsigned int edx __attribute__ ((packed));
- unsigned int esi __attribute__ ((packed));
- unsigned int edi __attribute__ ((packed));
-} SMMRegisters;
-
-typedef struct {
- u8 type;
- u8 length;
- u16 handle;
-} DMIHeader;
+static inline char *i8k_get_dmi_data(int field)
+{
+ return dmi_get_system_info(field) ? : "N/A";
+}
/*
* Call the System Management Mode BIOS. Code provided by Jonathan Buzzard.
*/
-static int i8k_smm(SMMRegisters *regs)
+static int i8k_smm(struct smm_regs *regs)
{
- int rc;
- int eax = regs->eax;
-
- asm("pushl %%eax\n\t" \
- "movl 0(%%eax),%%edx\n\t" \
- "push %%edx\n\t" \
- "movl 4(%%eax),%%ebx\n\t" \
- "movl 8(%%eax),%%ecx\n\t" \
- "movl 12(%%eax),%%edx\n\t" \
- "movl 16(%%eax),%%esi\n\t" \
- "movl 20(%%eax),%%edi\n\t" \
- "popl %%eax\n\t" \
- "out %%al,$0xb2\n\t" \
- "out %%al,$0x84\n\t" \
- "xchgl %%eax,(%%esp)\n\t"
- "movl %%ebx,4(%%eax)\n\t" \
- "movl %%ecx,8(%%eax)\n\t" \
- "movl %%edx,12(%%eax)\n\t" \
- "movl %%esi,16(%%eax)\n\t" \
- "movl %%edi,20(%%eax)\n\t" \
- "popl %%edx\n\t" \
- "movl %%edx,0(%%eax)\n\t" \
- "lahf\n\t" \
- "shrl $8,%%eax\n\t" \
- "andl $1,%%eax\n" \
- : "=a" (rc)
- : "a" (regs)
- : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
-
- if ((rc != 0) || ((regs->eax & 0xffff) == 0xffff) || (regs->eax == eax)) {
- return -EINVAL;
- }
-
- return 0;
+ int rc;
+ int eax = regs->eax;
+
+ asm("pushl %%eax\n\t"
+ "movl 0(%%eax),%%edx\n\t"
+ "push %%edx\n\t"
+ "movl 4(%%eax),%%ebx\n\t"
+ "movl 8(%%eax),%%ecx\n\t"
+ "movl 12(%%eax),%%edx\n\t"
+ "movl 16(%%eax),%%esi\n\t"
+ "movl 20(%%eax),%%edi\n\t"
+ "popl %%eax\n\t"
+ "out %%al,$0xb2\n\t"
+ "out %%al,$0x84\n\t"
+ "xchgl %%eax,(%%esp)\n\t"
+ "movl %%ebx,4(%%eax)\n\t"
+ "movl %%ecx,8(%%eax)\n\t"
+ "movl %%edx,12(%%eax)\n\t"
+ "movl %%esi,16(%%eax)\n\t"
+ "movl %%edi,20(%%eax)\n\t"
+ "popl %%edx\n\t"
+ "movl %%edx,0(%%eax)\n\t"
+ "lahf\n\t"
+ "shrl $8,%%eax\n\t"
+ "andl $1,%%eax\n":"=a"(rc)
+ : "a"(regs)
+ : "%ebx", "%ecx", "%edx", "%esi", "%edi", "memory");
+
+ if (rc != 0 || (regs->eax & 0xffff) == 0xffff || regs->eax == eax)
+ return -EINVAL;
+
+ return 0;
}
/*
@@ -152,24 +147,9 @@ static int i8k_smm(SMMRegisters *regs)
*/
static int i8k_get_bios_version(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_BIOS_VERSION;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return regs.eax;
-}
+ struct smm_regs regs = { .eax = I8K_SMM_BIOS_VERSION, };
-/*
- * Read the machine id.
- */
-static int i8k_get_serial_number(unsigned char *buff)
-{
- strlcpy(buff, serial_number, sizeof(serial_number));
- return 0;
+ return i8k_smm(&regs) ? : regs.eax;
}
/*
@@ -177,24 +157,22 @@ static int i8k_get_serial_number(unsigned char *buff)
*/
static int i8k_get_fn_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_FN_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
- case I8K_FN_UP:
- return I8K_VOL_UP;
- case I8K_FN_DOWN:
- return I8K_VOL_DOWN;
- case I8K_FN_MUTE:
- return I8K_VOL_MUTE;
- default:
- return 0;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_FN_STATUS, };
+ int rc;
+
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
+
+ switch ((regs.eax >> I8K_FN_SHIFT) & I8K_FN_MASK) {
+ case I8K_FN_UP:
+ return I8K_VOL_UP;
+ case I8K_FN_DOWN:
+ return I8K_VOL_DOWN;
+ case I8K_FN_MUTE:
+ return I8K_VOL_MUTE;
+ default:
+ return 0;
+ }
}
/*
@@ -202,20 +180,13 @@ static int i8k_get_fn_status(void)
*/
static int i8k_get_power_status(void)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_POWER_STATUS;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- switch (regs.eax & 0xff) {
- case I8K_POWER_AC:
- return I8K_AC;
- default:
- return I8K_BATTERY;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_POWER_STATUS, };
+ int rc;
+
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
+
+ return (regs.eax & 0xff) == I8K_POWER_AC ? I8K_AC : I8K_BATTERY;
}
/*
@@ -223,16 +194,10 @@ static int i8k_get_power_status(void)
*/
static int i8k_get_fan_status(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- regs.eax = I8K_SMM_GET_FAN;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN, };
- return (regs.eax & 0xff);
+ regs.ebx = fan & 0xff;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
}
/*
@@ -240,16 +205,10 @@ static int i8k_get_fan_status(int fan)
*/
static int i8k_get_fan_speed(int fan)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_SPEED, };
- regs.eax = I8K_SMM_GET_SPEED;
- regs.ebx = fan & 0xff;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
-
- return (regs.eax & 0xffff) * I8K_FAN_MULT;
+ regs.ebx = fan & 0xff;
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * I8K_FAN_MULT;
}
/*
@@ -257,532 +216,318 @@ static int i8k_get_fan_speed(int fan)
*/
static int i8k_set_fan(int fan, int speed)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
-
- speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+ struct smm_regs regs = { .eax = I8K_SMM_SET_FAN, };
- regs.eax = I8K_SMM_SET_FAN;
- regs.ebx = (fan & 0xff) | (speed << 8);
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ speed = (speed < 0) ? 0 : ((speed > I8K_FAN_MAX) ? I8K_FAN_MAX : speed);
+ regs.ebx = (fan & 0xff) | (speed << 8);
- return (i8k_get_fan_status(fan));
+ return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
}
/*
* Read the cpu temperature.
*/
-static int i8k_get_cpu_temp(void)
+static int i8k_get_temp(int sensor)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
- int temp;
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
+ int rc;
+ int temp;
#ifdef I8K_TEMPERATURE_BUG
- static int prev = 0;
+ static int prev;
#endif
+ regs.ebx = sensor & 0xff;
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
- regs.eax = I8K_SMM_GET_TEMP;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
- temp = regs.eax & 0xff;
+ temp = regs.eax & 0xff;
#ifdef I8K_TEMPERATURE_BUG
- /*
- * Sometimes the temperature sensor returns 0x99, which is out of range.
- * In this case we return (once) the previous cached value. For example:
- # 1003655137 00000058 00005a4b
- # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
- # 1003655139 00000054 00005c52
- */
- if (temp > I8K_MAX_TEMP) {
- temp = prev;
- prev = I8K_MAX_TEMP;
- } else {
- prev = temp;
- }
+ /*
+ * Sometimes the temperature sensor returns 0x99, which is out of range.
+ * In this case we return (once) the previous cached value. For example:
+ # 1003655137 00000058 00005a4b
+ # 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
+ # 1003655139 00000054 00005c52
+ */
+ if (temp > I8K_MAX_TEMP) {
+ temp = prev;
+ prev = I8K_MAX_TEMP;
+ } else {
+ prev = temp;
+ }
#endif
- return temp;
+ return temp;
}
-static int i8k_get_dell_signature(void)
+static int i8k_get_dell_signature(int req_fn)
{
- SMMRegisters regs = { 0, 0, 0, 0, 0, 0 };
- int rc;
+ struct smm_regs regs = { .eax = req_fn, };
+ int rc;
- regs.eax = I8K_SMM_GET_DELL_SIG;
- if ((rc=i8k_smm(&regs)) < 0) {
- return rc;
- }
+ if ((rc = i8k_smm(&regs)) < 0)
+ return rc;
- if ((regs.eax == 1145651527) && (regs.edx == 1145392204)) {
- return 0;
- } else {
- return -1;
- }
+ return regs.eax == 1145651527 && regs.edx == 1145392204 ? 0 : -1;
}
static int i8k_ioctl(struct inode *ip, struct file *fp, unsigned int cmd,
unsigned long arg)
{
- int val;
- int speed;
- unsigned char buff[16];
- int __user *argp = (int __user *)arg;
-
- if (!argp)
- return -EINVAL;
-
- switch (cmd) {
- case I8K_BIOS_VERSION:
- val = i8k_get_bios_version();
- break;
-
- case I8K_MACHINE_ID:
- memset(buff, 0, 16);
- val = i8k_get_serial_number(buff);
- break;
-
- case I8K_FN_STATUS:
- val = i8k_get_fn_status();
- break;
-
- case I8K_POWER_STATUS:
- val = i8k_get_power_status();
- break;
-
- case I8K_GET_TEMP:
- val = i8k_get_cpu_temp();
- break;
-
- case I8K_GET_SPEED:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_speed(val);
- break;
-
- case I8K_GET_FAN:
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_get_fan_status(val);
- break;
+ int val = 0;
+ int speed;
+ unsigned char buff[16];
+ int __user *argp = (int __user *)arg;
- case I8K_SET_FAN:
- if (restricted && !capable(CAP_SYS_ADMIN)) {
- return -EPERM;
- }
- if (copy_from_user(&val, argp, sizeof(int))) {
- return -EFAULT;
- }
- if (copy_from_user(&speed, argp+1, sizeof(int))) {
- return -EFAULT;
- }
- val = i8k_set_fan(val, speed);
- break;
+ if (!argp)
+ return -EINVAL;
- default:
- return -EINVAL;
- }
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ val = i8k_get_bios_version();
+ break;
- if (val < 0) {
- return val;
- }
+ case I8K_MACHINE_ID:
+ memset(buff, 0, 16);
+ strlcpy(buff, i8k_get_dmi_data(DMI_PRODUCT_SERIAL), sizeof(buff));
+ break;
- switch (cmd) {
- case I8K_BIOS_VERSION:
- if (copy_to_user(argp, &val, 4)) {
- return -EFAULT;
- }
- break;
- case I8K_MACHINE_ID:
- if (copy_to_user(argp, buff, 16)) {
- return -EFAULT;
- }
- break;
- default:
- if (copy_to_user(argp, &val, sizeof(int))) {
- return -EFAULT;
- }
- break;
- }
+ case I8K_FN_STATUS:
+ val = i8k_get_fn_status();
+ break;
- return 0;
-}
+ case I8K_POWER_STATUS:
+ val = i8k_get_power_status();
+ break;
-/*
- * Print the information for /proc/i8k.
- */
-static int i8k_get_info(char *buffer, char **start, off_t fpos, int length)
-{
- int n, fn_key, cpu_temp, ac_power;
- int left_fan, right_fan, left_speed, right_speed;
-
- cpu_temp = i8k_get_cpu_temp(); /* 11100 µs */
- left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
- right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
- left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
- right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
- fn_key = i8k_get_fn_status(); /* 750 µs */
- if (power_status) {
- ac_power = i8k_get_power_status(); /* 14700 µs */
- } else {
- ac_power = -1;
- }
-
- /*
- * Info:
- *
- * 1) Format version (this will change if format changes)
- * 2) BIOS version
- * 3) BIOS machine ID
- * 4) Cpu temperature
- * 5) Left fan status
- * 6) Right fan status
- * 7) Left fan speed
- * 8) Right fan speed
- * 9) AC power
- * 10) Fn Key status
- */
- n = sprintf(buffer, "%s %s %s %d %d %d %d %d %d %d\n",
- I8K_PROC_FMT,
- bios_version,
- serial_number,
- cpu_temp,
- left_fan,
- right_fan,
- left_speed,
- right_speed,
- ac_power,
- fn_key);
-
- return n;
-}
+ case I8K_GET_TEMP:
+ val = i8k_get_temp(0);
+ break;
-static ssize_t i8k_read(struct file *f, char __user *buffer, size_t len, loff_t *fpos)
-{
- int n;
- char info[128];
+ case I8K_GET_SPEED:
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
- n = i8k_get_info(info, NULL, 0, 128);
- if (n <= 0) {
- return n;
- }
+ val = i8k_get_fan_speed(val);
+ break;
- if (*fpos >= n) {
- return 0;
- }
+ case I8K_GET_FAN:
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
- if ((*fpos + len) >= n) {
- len = n - *fpos;
- }
+ val = i8k_get_fan_status(val);
+ break;
- if (copy_to_user(buffer, info, len) != 0) {
- return -EFAULT;
- }
+ case I8K_SET_FAN:
+ if (restricted && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
- *fpos += len;
- return len;
-}
+ if (copy_from_user(&val, argp, sizeof(int)))
+ return -EFAULT;
-static char* __init string_trim(char *s, int size)
-{
- int len;
- char *p;
+ if (copy_from_user(&speed, argp + 1, sizeof(int)))
+ return -EFAULT;
- if ((len = strlen(s)) > size) {
- len = size;
- }
+ val = i8k_set_fan(val, speed);
+ break;
- for (p=s+len-1; len && (*p==' '); len--,p--) {
- *p = '\0';
- }
+ default:
+ return -EINVAL;
+ }
- return s;
-}
+ if (val < 0)
+ return val;
-/* DMI code, stolen from arch/i386/kernel/dmi_scan.c */
+ switch (cmd) {
+ case I8K_BIOS_VERSION:
+ if (copy_to_user(argp, &val, 4))
+ return -EFAULT;
-/*
- * |<-- dmi->length -->|
- * | |
- * |dmi header s=N | string1,\0, ..., stringN,\0, ..., \0
- * | |
- * +-----------------------+
- */
-static char* __init dmi_string(DMIHeader *dmi, u8 s)
-{
- u8 *p;
+ break;
+ case I8K_MACHINE_ID:
+ if (copy_to_user(argp, buff, 16))
+ return -EFAULT;
- if (!s) {
- return "";
- }
- s--;
+ break;
+ default:
+ if (copy_to_user(argp, &val, sizeof(int)))
+ return -EFAULT;
- p = (u8 *)dmi + dmi->length;
- while (s > 0) {
- p += strlen(p);
- p++;
- s--;
- }
+ break;
+ }
- return p;
+ return 0;
}
-static void __init dmi_decode(DMIHeader *dmi)
+/*
+ * Print the information for /proc/i8k.
+ */
+static int i8k_proc_show(struct seq_file *seq, void *offset)
{
- u8 *data = (u8 *) dmi;
- char *p;
-
-#ifdef I8K_DEBUG
- int i;
- printk("%08x ", (int)data);
- for (i=0; i<data[1] && i<64; i++) {
- printk("%02x ", data[i]);
- }
- printk("\n");
-#endif
-
- switch (dmi->type) {
- case 0: /* BIOS Information */
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(bios_version, p, sizeof(bios_version));
- string_trim(bios_version, sizeof(bios_version));
- }
- break;
- case 1: /* System Information */
- p = dmi_string(dmi,data[4]);
- if (*p) {
- strlcpy(system_vendor, p, sizeof(system_vendor));
- string_trim(system_vendor, sizeof(system_vendor));
- }
- p = dmi_string(dmi,data[5]);
- if (*p) {
- strlcpy(product_name, p, sizeof(product_name));
- string_trim(product_name, sizeof(product_name));
- }
- p = dmi_string(dmi,data[7]);
- if (*p) {
- strlcpy(serial_number, p, sizeof(serial_number));
- string_trim(serial_number, sizeof(serial_number));
- }
- break;
- }
-}
+ int fn_key, cpu_temp, ac_power;
+ int left_fan, right_fan, left_speed, right_speed;
+
+ cpu_temp = i8k_get_temp(0); /* 11100 µs */
+ left_fan = i8k_get_fan_status(I8K_FAN_LEFT); /* 580 µs */
+ right_fan = i8k_get_fan_status(I8K_FAN_RIGHT); /* 580 µs */
+ left_speed = i8k_get_fan_speed(I8K_FAN_LEFT); /* 580 µs */
+ right_speed = i8k_get_fan_speed(I8K_FAN_RIGHT); /* 580 µs */
+ fn_key = i8k_get_fn_status(); /* 750 µs */
+ if (power_status)
+ ac_power = i8k_get_power_status(); /* 14700 µs */
+ else
+ ac_power = -1;
-static int __init dmi_table(u32 base, int len, int num, void (*fn)(DMIHeader*))
-{
- u8 *buf;
- u8 *data;
- DMIHeader *dmi;
- int i = 1;
-
- buf = ioremap(base, len);
- if (buf == NULL) {
- return -1;
- }
- data = buf;
-
- /*
- * Stop when we see al the items the table claimed to have
- * or we run off the end of the table (also happens)
- */
- while ((i<num) && ((data-buf) < len)) {
- dmi = (DMIHeader *)data;
- /*
- * Avoid misparsing crud if the length of the last
- * record is crap
- */
- if ((data-buf+dmi->length) >= len) {
- break;
- }
- fn(dmi);
- data += dmi->length;
/*
- * Don't go off the end of the data if there is
- * stuff looking like string fill past the end
+ * Info:
+ *
+ * 1) Format version (this will change if format changes)
+ * 2) BIOS version
+ * 3) BIOS machine ID
+ * 4) Cpu temperature
+ * 5) Left fan status
+ * 6) Right fan status
+ * 7) Left fan speed
+ * 8) Right fan speed
+ * 9) AC power
+ * 10) Fn Key status
*/
- while (((data-buf) < len) && (*data || data[1])) {
- data++;
- }
- data += 2;
- i++;
- }
- iounmap(buf);
-
- return 0;
+ return seq_printf(seq, "%s %s %s %d %d %d %d %d %d %d\n",
+ I8K_PROC_FMT,
+ bios_version,
+ dmi_get_system_info(DMI_PRODUCT_SERIAL) ? : "N/A",
+ cpu_temp,
+ left_fan, right_fan, left_speed, right_speed,
+ ac_power, fn_key);
}
-static int __init dmi_iterate(void (*decode)(DMIHeader *))
+static int i8k_open_fs(struct inode *inode, struct file *file)
{
- unsigned char buf[20];
- void __iomem *p = ioremap(0xe0000, 0x20000), *q;
-
- if (!p)
- return -1;
-
- for (q = p; q < p + 0x20000; q += 16) {
- memcpy_fromio(buf, q, 20);
- if (memcmp(buf, "_DMI_", 5)==0) {
- u16 num = buf[13]<<8 | buf[12];
- u16 len = buf [7]<<8 | buf [6];
- u32 base = buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8];
-#ifdef I8K_DEBUG
- printk(KERN_INFO "DMI %d.%d present.\n",
- buf[14]>>4, buf[14]&0x0F);
- printk(KERN_INFO "%d structures occupying %d bytes.\n",
- buf[13]<<8 | buf[12],
- buf [7]<<8 | buf[6]);
- printk(KERN_INFO "DMI table at 0x%08X.\n",
- buf[11]<<24 | buf[10]<<16 | buf[9]<<8 | buf[8]);
-#endif
- if (dmi_table(base, len, num, decode)==0) {
- iounmap(p);
- return 0;
- }
- }
- }
- iounmap(p);
- return -1;
+ return single_open(file, i8k_proc_show, NULL);
}
-/* end of DMI code */
-
-/*
- * Get DMI information.
- */
-static int __init i8k_dmi_probe(void)
-{
- char **p;
-
- if (dmi_iterate(dmi_decode) != 0) {
- printk(KERN_INFO "i8k: unable to get DMI information\n");
- return -ENODEV;
- }
-
- if (strncmp(system_vendor,DELL_SIGNATURE,strlen(DELL_SIGNATURE)) != 0) {
- printk(KERN_INFO "i8k: not running on a Dell system\n");
- return -ENODEV;
- }
-
- for (p=supported_models; ; p++) {
- if (!*p) {
- printk(KERN_INFO "i8k: unsupported model: %s\n", product_name);
- return -ENODEV;
- }
- if (strncmp(product_name,*p,strlen(*p)) == 0) {
- break;
- }
- }
- return 0;
-}
+static struct dmi_system_id __initdata i8k_dmi_table[] = {
+ {
+ .ident = "Dell Inspiron",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
+ .ident = "Dell Latitude",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Computer"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+ },
+ },
+ {
+ .ident = "Dell Inspiron 2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Inspiron"),
+ },
+ },
+ {
+ .ident = "Dell Latitude 2",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
+ },
+ },
+ { }
+};
/*
* Probe for the presence of a supported laptop.
*/
static int __init i8k_probe(void)
{
- char buff[4];
- int version;
- int smm_found = 0;
-
- /*
- * Get DMI information
- */
- if (i8k_dmi_probe() != 0) {
- printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
- system_vendor, product_name, bios_version);
- }
-
- /*
- * Get SMM Dell signature
- */
- if (i8k_get_dell_signature() != 0) {
- printk(KERN_INFO "i8k: unable to get SMM Dell signature\n");
- } else {
- smm_found = 1;
- }
-
- /*
- * Get SMM BIOS version.
- */
- version = i8k_get_bios_version();
- if (version <= 0) {
- printk(KERN_INFO "i8k: unable to get SMM BIOS version\n");
- } else {
- smm_found = 1;
- buff[0] = (version >> 16) & 0xff;
- buff[1] = (version >> 8) & 0xff;
- buff[2] = (version) & 0xff;
- buff[3] = '\0';
+ char buff[4];
+ int version;
+
/*
- * If DMI BIOS version is unknown use SMM BIOS version.
+ * Get DMI information
*/
- if (bios_version[0] == '?') {
- strcpy(bios_version, buff);
+ if (!dmi_check_system(i8k_dmi_table)) {
+ if (!ignore_dmi && !force)
+ return -ENODEV;
+
+ printk(KERN_INFO "i8k: not running on a supported Dell system.\n");
+ printk(KERN_INFO "i8k: vendor=%s, model=%s, version=%s\n",
+ i8k_get_dmi_data(DMI_SYS_VENDOR),
+ i8k_get_dmi_data(DMI_PRODUCT_NAME),
+ i8k_get_dmi_data(DMI_BIOS_VERSION));
}
+
+ strlcpy(bios_version, i8k_get_dmi_data(DMI_BIOS_VERSION), sizeof(bios_version));
+
/*
- * Check if the two versions match.
+ * Get SMM Dell signature
*/
- if (strncmp(buff,bios_version,sizeof(bios_version)) != 0) {
- printk(KERN_INFO "i8k: BIOS version mismatch: %s != %s\n",
- buff, bios_version);
+ if (i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG1) &&
+ i8k_get_dell_signature(I8K_SMM_GET_DELL_SIG2)) {
+ printk(KERN_ERR "i8k: unable to get SMM Dell signature\n");
+ if (!force)
+ return -ENODEV;
}
- }
- if (!smm_found && !force) {
- return -ENODEV;
- }
+ /*
+ * Get SMM BIOS version.
+ */
+ version = i8k_get_bios_version();
+ if (version <= 0) {
+ printk(KERN_WARNING "i8k: unable to get SMM BIOS version\n");
+ } else {
+ buff[0] = (version >> 16) & 0xff;
+ buff[1] = (version >> 8) & 0xff;
+ buff[2] = (version) & 0xff;
+ buff[3] = '\0';
+ /*
+ * If DMI BIOS version is unknown use SMM BIOS version.
+ */
+ if (!dmi_get_system_info(DMI_BIOS_VERSION))
+ strlcpy(bios_version, buff, sizeof(bios_version));
+
+ /*
+ * Check if the two versions match.
+ */
+ if (strncmp(buff, bios_version, sizeof(bios_version)) != 0)
+ printk(KERN_WARNING "i8k: BIOS version mismatch: %s != %s\n",
+ buff, bios_version);
+ }
- return 0;
+ return 0;
}
-#ifdef MODULE
-static
-#endif
-int __init i8k_init(void)
+static int __init i8k_init(void)
{
- struct proc_dir_entry *proc_i8k;
-
- /* Are we running on an supported laptop? */
- if (i8k_probe() != 0) {
- return -ENODEV;
- }
-
- /* Register the proc entry */
- proc_i8k = create_proc_info_entry("i8k", 0, NULL, i8k_get_info);
- if (!proc_i8k) {
- return -ENOENT;
- }
- proc_i8k->proc_fops = &i8k_fops;
- proc_i8k->owner = THIS_MODULE;
-
- printk(KERN_INFO
- "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
- I8K_VERSION);
-
- return 0;
-}
+ struct proc_dir_entry *proc_i8k;
-#ifdef MODULE
-int init_module(void)
-{
- return i8k_init();
+ /* Are we running on an supported laptop? */
+ if (i8k_probe())
+ return -ENODEV;
+
+ /* Register the proc entry */
+ proc_i8k = create_proc_entry("i8k", 0, NULL);
+ if (!proc_i8k)
+ return -ENOENT;
+
+ proc_i8k->proc_fops = &i8k_fops;
+ proc_i8k->owner = THIS_MODULE;
+
+ printk(KERN_INFO
+ "Dell laptop SMM driver v%s Massimo Dal Zotto (dz@debian.org)\n",
+ I8K_VERSION);
+
+ return 0;
}
-void cleanup_module(void)
+static void __exit i8k_exit(void)
{
- /* Remove the proc entry */
- remove_proc_entry("i8k", NULL);
-
- printk(KERN_INFO "i8k: module unloaded\n");
+ remove_proc_entry("i8k", NULL);
}
-#endif
-/* end of file */
+module_init(i8k_init);
+module_exit(i8k_exit);
diff --git a/drivers/char/ip2/i2cmd.c b/drivers/char/ip2/i2cmd.c
index fd299d6c42ac..cb8f4198e9a3 100644
--- a/drivers/char/ip2/i2cmd.c
+++ b/drivers/char/ip2/i2cmd.c
@@ -97,7 +97,7 @@ static UCHAR ct41[] = { 1, BYP, 0x29 }; // RESUME
//static UCHAR ct44[]={ 2, BTH, 0x2C,0 }; // MS PING
//static UCHAR ct45[]={ 1, BTH, 0x2D }; // HOTENAB
//static UCHAR ct46[]={ 1, BTH, 0x2E }; // HOTDSAB
-static UCHAR ct47[] = { 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS
+//static UCHAR ct47[]={ 7, BTH, 0x2F,0,0,0,0,0,0 }; // UNIX FLAGS
//static UCHAR ct48[]={ 1, BTH, 0x30 }; // DSRFLOWENAB
//static UCHAR ct49[]={ 1, BTH, 0x31 }; // DSRFLOWDSAB
//static UCHAR ct50[]={ 1, BTH, 0x32 }; // DTRFLOWENAB
@@ -162,6 +162,7 @@ static UCHAR ct89[]={ 1, BYP, 0x59 }; // DSS_NOW
// This routine sets the parameters of command 47 and returns a pointer to the
// appropriate structure.
//******************************************************************************
+#if 0
cmdSyntaxPtr
i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
{
@@ -175,6 +176,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
pCM->cmd[6] = (unsigned char) (lflag >> 8);
return pCM;
}
+#endif /* 0 */
//******************************************************************************
// Function: i2cmdBaudDef(which, rate)
@@ -187,7 +189,7 @@ i2cmdUnixFlags(unsigned short iflag,unsigned short cflag,unsigned short lflag)
// This routine sets the parameters of commands 54 or 55 (according to the
// argument which), and returns a pointer to the appropriate structure.
//******************************************************************************
-cmdSyntaxPtr
+static cmdSyntaxPtr
i2cmdBaudDef(int which, unsigned short rate)
{
cmdSyntaxPtr pCM;
diff --git a/drivers/char/ip2/i2cmd.h b/drivers/char/ip2/i2cmd.h
index c41728a85710..baa4e721b758 100644
--- a/drivers/char/ip2/i2cmd.h
+++ b/drivers/char/ip2/i2cmd.h
@@ -64,16 +64,6 @@ typedef struct _cmdSyntax
// directly from user-level
#define VAR 0x10 // This command is of variable length!
-//-----------------------------------
-// External declarations for i2cmd.c
-//-----------------------------------
-// Routine to set up parameters for the "define hot-key sequence" command. Since
-// there is more than one parameter to assign, we must use a function rather
-// than a macro (used usually).
-//
-extern cmdSyntaxPtr i2cmdUnixFlags(USHORT iflag,USHORT cflag,USHORT lflag);
-extern cmdSyntaxPtr i2cmdBaudDef(int which, USHORT rate);
-
// Declarations for the global arrays used to bear the commands and their
// arguments.
//
@@ -433,6 +423,7 @@ static UCHAR cc02[];
#define CMD_HOT_ENAB (cmdSyntaxPtr)(ct45) // Enable Hot-key checking
#define CMD_HOT_DSAB (cmdSyntaxPtr)(ct46) // Disable Hot-key checking
+#if 0
// COMMAND 47: Send Protocol info via Unix flags:
// iflag = Unix tty t_iflag
// cflag = Unix tty t_cflag
@@ -441,6 +432,7 @@ static UCHAR cc02[];
// within these flags
//
#define CMD_UNIX_FLAGS(iflag,cflag,lflag) i2cmdUnixFlags(iflag,cflag,lflag)
+#endif /* 0 */
#define CMD_DSRFL_ENAB (cmdSyntaxPtr)(ct48) // Enable DSR receiver ctrl
#define CMD_DSRFL_DSAB (cmdSyntaxPtr)(ct49) // Disable DSR receiver ctrl
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 3b8314b4249a..cf0cd58d6305 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -2691,16 +2691,6 @@ no_xon:
pCh->flags |= ASYNC_CHECK_CD;
}
-#ifdef XXX
-do_flags_thing: // This is a test, we don't do the flags thing
-
- if ( (cflag & CRTSCTS) ) {
- cflag |= 014000000000;
- }
- i2QueueCommands(PTYPE_BYPASS, pCh, 100, 1,
- CMD_UNIX_FLAGS(iflag,cflag,lflag));
-#endif
-
service_it:
i2DrainOutput( pCh, 100 );
}
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index 88d1ad656e99..e0a53570fea1 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -45,6 +45,7 @@
#include <asm/semaphore.h>
#include <linux/init.h>
#include <linux/device.h>
+#include <linux/compat.h>
#define IPMI_DEVINTF_VERSION "v33"
@@ -500,10 +501,205 @@ static int ipmi_ioctl(struct inode *inode,
return rv;
}
+#ifdef CONFIG_COMPAT
+
+/*
+ * The following code contains code for supporting 32-bit compatible
+ * ioctls on 64-bit kernels. This allows running 32-bit apps on the
+ * 64-bit kernel
+ */
+#define COMPAT_IPMICTL_SEND_COMMAND \
+ _IOR(IPMI_IOC_MAGIC, 13, struct compat_ipmi_req)
+#define COMPAT_IPMICTL_SEND_COMMAND_SETTIME \
+ _IOR(IPMI_IOC_MAGIC, 21, struct compat_ipmi_req_settime)
+#define COMPAT_IPMICTL_RECEIVE_MSG \
+ _IOWR(IPMI_IOC_MAGIC, 12, struct compat_ipmi_recv)
+#define COMPAT_IPMICTL_RECEIVE_MSG_TRUNC \
+ _IOWR(IPMI_IOC_MAGIC, 11, struct compat_ipmi_recv)
+
+struct compat_ipmi_msg {
+ u8 netfn;
+ u8 cmd;
+ u16 data_len;
+ compat_uptr_t data;
+};
+
+struct compat_ipmi_req {
+ compat_uptr_t addr;
+ compat_uint_t addr_len;
+ compat_long_t msgid;
+ struct compat_ipmi_msg msg;
+};
+
+struct compat_ipmi_recv {
+ compat_int_t recv_type;
+ compat_uptr_t addr;
+ compat_uint_t addr_len;
+ compat_long_t msgid;
+ struct compat_ipmi_msg msg;
+};
+
+struct compat_ipmi_req_settime {
+ struct compat_ipmi_req req;
+ compat_int_t retries;
+ compat_uint_t retry_time_ms;
+};
+
+/*
+ * Define some helper functions for copying IPMI data
+ */
+static long get_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg __user *p32)
+{
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(p64->netfn, &p32->netfn) ||
+ __get_user(p64->cmd, &p32->cmd) ||
+ __get_user(p64->data_len, &p32->data_len) ||
+ __get_user(tmp, &p32->data))
+ return -EFAULT;
+ p64->data = compat_ptr(tmp);
+ return 0;
+}
+
+static long put_compat_ipmi_msg(struct ipmi_msg *p64,
+ struct compat_ipmi_msg __user *p32)
+{
+ if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+ __put_user(p64->netfn, &p32->netfn) ||
+ __put_user(p64->cmd, &p32->cmd) ||
+ __put_user(p64->data_len, &p32->data_len))
+ return -EFAULT;
+ return 0;
+}
+
+static long get_compat_ipmi_req(struct ipmi_req *p64,
+ struct compat_ipmi_req __user *p32)
+{
+
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(tmp, &p32->addr) ||
+ __get_user(p64->addr_len, &p32->addr_len) ||
+ __get_user(p64->msgid, &p32->msgid) ||
+ get_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ p64->addr = compat_ptr(tmp);
+ return 0;
+}
+
+static long get_compat_ipmi_req_settime(struct ipmi_req_settime *p64,
+ struct compat_ipmi_req_settime __user *p32)
+{
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ get_compat_ipmi_req(&p64->req, &p32->req) ||
+ __get_user(p64->retries, &p32->retries) ||
+ __get_user(p64->retry_time_ms, &p32->retry_time_ms))
+ return -EFAULT;
+ return 0;
+}
+
+static long get_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv __user *p32)
+{
+ compat_uptr_t tmp;
+
+ if (!access_ok(VERIFY_READ, p32, sizeof(*p32)) ||
+ __get_user(p64->recv_type, &p32->recv_type) ||
+ __get_user(tmp, &p32->addr) ||
+ __get_user(p64->addr_len, &p32->addr_len) ||
+ __get_user(p64->msgid, &p32->msgid) ||
+ get_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ p64->addr = compat_ptr(tmp);
+ return 0;
+}
+
+static long put_compat_ipmi_recv(struct ipmi_recv *p64,
+ struct compat_ipmi_recv __user *p32)
+{
+ if (!access_ok(VERIFY_WRITE, p32, sizeof(*p32)) ||
+ __put_user(p64->recv_type, &p32->recv_type) ||
+ __put_user(p64->addr_len, &p32->addr_len) ||
+ __put_user(p64->msgid, &p32->msgid) ||
+ put_compat_ipmi_msg(&p64->msg, &p32->msg))
+ return -EFAULT;
+ return 0;
+}
+
+/*
+ * Handle compatibility ioctls
+ */
+static long compat_ipmi_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long arg)
+{
+ int rc;
+ struct ipmi_file_private *priv = filep->private_data;
+
+ switch(cmd) {
+ case COMPAT_IPMICTL_SEND_COMMAND:
+ {
+ struct ipmi_req rp;
+
+ if (get_compat_ipmi_req(&rp, compat_ptr(arg)))
+ return -EFAULT;
+
+ return handle_send_req(priv->user, &rp,
+ priv->default_retries,
+ priv->default_retry_time_ms);
+ }
+ case COMPAT_IPMICTL_SEND_COMMAND_SETTIME:
+ {
+ struct ipmi_req_settime sp;
+
+ if (get_compat_ipmi_req_settime(&sp, compat_ptr(arg)))
+ return -EFAULT;
+
+ return handle_send_req(priv->user, &sp.req,
+ sp.retries, sp.retry_time_ms);
+ }
+ case COMPAT_IPMICTL_RECEIVE_MSG:
+ case COMPAT_IPMICTL_RECEIVE_MSG_TRUNC:
+ {
+ struct ipmi_recv *precv64, recv64;
+
+ if (get_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ return -EFAULT;
+
+ precv64 = compat_alloc_user_space(sizeof(recv64));
+ if (copy_to_user(precv64, &recv64, sizeof(recv64)))
+ return -EFAULT;
+
+ rc = ipmi_ioctl(filep->f_dentry->d_inode, filep,
+ ((cmd == COMPAT_IPMICTL_RECEIVE_MSG)
+ ? IPMICTL_RECEIVE_MSG
+ : IPMICTL_RECEIVE_MSG_TRUNC),
+ (long) precv64);
+ if (rc != 0)
+ return rc;
+
+ if (copy_from_user(&recv64, precv64, sizeof(recv64)))
+ return -EFAULT;
+
+ if (put_compat_ipmi_recv(&recv64, compat_ptr(arg)))
+ return -EFAULT;
+
+ return rc;
+ }
+ default:
+ return ipmi_ioctl(filep->f_dentry->d_inode, filep, cmd, arg);
+ }
+}
+#endif
static struct file_operations ipmi_fops = {
.owner = THIS_MODULE,
.ioctl = ipmi_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = compat_ipmi_ioctl,
+#endif
.open = ipmi_open,
.release = ipmi_release,
.fasync = ipmi_fasync,
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 0c81652eaba6..e16c13fe698d 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -54,7 +54,9 @@ static int ipmi_init_msghandler(void);
static int initialized = 0;
-static struct proc_dir_entry *proc_ipmi_root = NULL;
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_ipmi_root = NULL;
+#endif /* CONFIG_PROC_FS */
#define MAX_EVENTS_IN_QUEUE 25
@@ -124,11 +126,13 @@ struct ipmi_channel
unsigned char protocol;
};
+#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry
{
char *name;
struct ipmi_proc_entry *next;
};
+#endif
#define IPMI_IPMB_NUM_SEQ 64
#define IPMI_MAX_CHANNELS 8
@@ -156,10 +160,13 @@ struct ipmi_smi
struct ipmi_smi_handlers *handlers;
void *send_info;
+#ifdef CONFIG_PROC_FS
/* A list of proc entries for this interface. This does not
need a lock, only one thread creates it and only one thread
destroys it. */
+ spinlock_t proc_entry_lock;
struct ipmi_proc_entry *proc_entries;
+#endif
/* A table of sequence numbers for this interface. We use the
sequence numbers for IPMB messages that go out of the
@@ -1081,8 +1088,8 @@ static inline int i_ipmi_request(ipmi_user_t user,
long seqid;
int broadcast = 0;
- if (addr->channel > IPMI_NUM_CHANNELS) {
- spin_lock_irqsave(&intf->counter_lock, flags);
+ if (addr->channel >= IPMI_MAX_CHANNELS) {
+ spin_lock_irqsave(&intf->counter_lock, flags);
intf->sent_invalid_commands++;
spin_unlock_irqrestore(&intf->counter_lock, flags);
rv = -EINVAL;
@@ -1470,8 +1477,9 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
read_proc_t *read_proc, write_proc_t *write_proc,
void *data, struct module *owner)
{
- struct proc_dir_entry *file;
int rv = 0;
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *file;
struct ipmi_proc_entry *entry;
/* Create a list element. */
@@ -1497,10 +1505,13 @@ int ipmi_smi_add_proc_entry(ipmi_smi_t smi, char *name,
file->write_proc = write_proc;
file->owner = owner;
+ spin_lock(&smi->proc_entry_lock);
/* Stick it on the list. */
entry->next = smi->proc_entries;
smi->proc_entries = entry;
+ spin_unlock(&smi->proc_entry_lock);
}
+#endif /* CONFIG_PROC_FS */
return rv;
}
@@ -1509,6 +1520,7 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
{
int rv = 0;
+#ifdef CONFIG_PROC_FS
sprintf(smi->proc_dir_name, "%d", num);
smi->proc_dir = proc_mkdir(smi->proc_dir_name, proc_ipmi_root);
if (!smi->proc_dir)
@@ -1531,14 +1543,17 @@ static int add_proc_entries(ipmi_smi_t smi, int num)
rv = ipmi_smi_add_proc_entry(smi, "version",
version_file_read_proc, NULL,
smi, THIS_MODULE);
+#endif /* CONFIG_PROC_FS */
return rv;
}
static void remove_proc_entries(ipmi_smi_t smi)
{
+#ifdef CONFIG_PROC_FS
struct ipmi_proc_entry *entry;
+ spin_lock(&smi->proc_entry_lock);
while (smi->proc_entries) {
entry = smi->proc_entries;
smi->proc_entries = entry->next;
@@ -1547,7 +1562,9 @@ static void remove_proc_entries(ipmi_smi_t smi)
kfree(entry->name);
kfree(entry);
}
+ spin_unlock(&smi->proc_entry_lock);
remove_proc_entry(smi->proc_dir_name, proc_ipmi_root);
+#endif /* CONFIG_PROC_FS */
}
static int
@@ -1694,6 +1711,9 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
new_intf->seq_table[j].seqid = 0;
}
new_intf->curr_seq = 0;
+#ifdef CONFIG_PROC_FS
+ spin_lock_init(&(new_intf->proc_entry_lock));
+#endif
spin_lock_init(&(new_intf->waiting_msgs_lock));
INIT_LIST_HEAD(&(new_intf->waiting_msgs));
spin_lock_init(&(new_intf->events_lock));
@@ -2747,16 +2767,13 @@ static struct timer_list ipmi_timer;
the queue and this silliness can go away. */
#define IPMI_REQUEST_EV_TIME (1000 / (IPMI_TIMEOUT_TIME))
-static volatile int stop_operation = 0;
-static volatile int timer_stopped = 0;
+static atomic_t stop_operation;
static unsigned int ticks_to_req_ev = IPMI_REQUEST_EV_TIME;
static void ipmi_timeout(unsigned long data)
{
- if (stop_operation) {
- timer_stopped = 1;
+ if (atomic_read(&stop_operation))
return;
- }
ticks_to_req_ev--;
if (ticks_to_req_ev == 0) {
@@ -2766,8 +2783,7 @@ static void ipmi_timeout(unsigned long data)
ipmi_timeout_handler(IPMI_TIMEOUT_TIME);
- ipmi_timer.expires += IPMI_TIMEOUT_JIFFIES;
- add_timer(&ipmi_timer);
+ mod_timer(&ipmi_timer, jiffies + IPMI_TIMEOUT_JIFFIES);
}
@@ -3089,6 +3105,7 @@ static int ipmi_init_msghandler(void)
ipmi_interfaces[i] = NULL;
}
+#ifdef CONFIG_PROC_FS
proc_ipmi_root = proc_mkdir("ipmi", NULL);
if (!proc_ipmi_root) {
printk(KERN_ERR PFX "Unable to create IPMI proc dir");
@@ -3096,6 +3113,7 @@ static int ipmi_init_msghandler(void)
}
proc_ipmi_root->owner = THIS_MODULE;
+#endif /* CONFIG_PROC_FS */
init_timer(&ipmi_timer);
ipmi_timer.data = 0;
@@ -3130,13 +3148,12 @@ static __exit void cleanup_ipmi(void)
/* Tell the timer to stop, then wait for it to stop. This avoids
problems with race conditions removing the timer here. */
- stop_operation = 1;
- while (!timer_stopped) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- }
+ atomic_inc(&stop_operation);
+ del_timer_sync(&ipmi_timer);
+#ifdef CONFIG_PROC_FS
remove_proc_entry(proc_ipmi_root->name, &proc_root);
+#endif /* CONFIG_PROC_FS */
initialized = 0;
@@ -3177,4 +3194,5 @@ 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(proc_ipmi_root);
EXPORT_SYMBOL(ipmi_user_set_run_to_completion);
diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c
index cb5cdc6f14bf..f951c30236c9 100644
--- a/drivers/char/ipmi/ipmi_poweroff.c
+++ b/drivers/char/ipmi/ipmi_poweroff.c
@@ -31,10 +31,13 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <asm/semaphore.h>
-#include <linux/kdev_t.h>
+#include <linux/config.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
#include <linux/string.h>
+#include <linux/completion.h>
+#include <linux/kdev_t.h>
#include <linux/ipmi.h>
#include <linux/ipmi_smi.h>
@@ -44,6 +47,18 @@
/* Where to we insert our poweroff function? */
extern void (*pm_power_off)(void);
+/* Definitions for controlling power off (if the system supports it). It
+ * conveniently matches the IPMI chassis control values. */
+#define IPMI_CHASSIS_POWER_DOWN 0 /* power down, the default. */
+#define IPMI_CHASSIS_POWER_CYCLE 0x02 /* power cycle */
+
+/* the IPMI data command */
+static int poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+
+/* parameter definition to allow user to flag power cycle */
+module_param(poweroff_control, int, IPMI_CHASSIS_POWER_DOWN);
+MODULE_PARM_DESC(poweroff_control, " Set to 2 to enable power cycle instead of power down. Power cycle is contingent on hardware support, otherwise it defaults back to power down.");
+
/* Stuff from the get device id command. */
static unsigned int mfg_id;
static unsigned int prod_id;
@@ -75,10 +90,10 @@ static struct ipmi_recv_msg halt_recv_msg =
static void receive_handler(struct ipmi_recv_msg *recv_msg, void *handler_data)
{
- struct semaphore *sem = recv_msg->user_msg_data;
+ struct completion *comp = recv_msg->user_msg_data;
- if (sem)
- up(sem);
+ if (comp)
+ complete(comp);
}
static struct ipmi_user_hndl ipmi_poweroff_handler =
@@ -91,27 +106,27 @@ 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;
+ int rv;
+ struct completion comp;
- sema_init (&sem, 0);
+ init_completion(&comp);
- rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &sem,
+ rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, &comp,
&halt_smi_msg, &halt_recv_msg, 0);
if (rv)
return rv;
- down (&sem);
+ wait_for_completion(&comp);
return halt_recv_msg.msg.data[0];
}
-/* We are in run-to-completion mode, no semaphore is desired. */
+/* We are in run-to-completion mode, no completion 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;
+ int rv;
rv = ipmi_request_supply_msgs(user, addr, 0, send_msg, NULL,
&halt_smi_msg, &halt_recv_msg, 0);
@@ -349,26 +364,38 @@ static void ipmi_poweroff_chassis (ipmi_user_t user)
smi_addr.channel = IPMI_BMC_CHANNEL;
smi_addr.lun = 0;
- printk(KERN_INFO PFX "Powering down via IPMI chassis control command\n");
+ powercyclefailed:
+ printk(KERN_INFO PFX "Powering %s via IPMI chassis control command\n",
+ ((poweroff_control != IPMI_CHASSIS_POWER_CYCLE) ? "down" : "cycle"));
/*
* Power down
*/
send_msg.netfn = IPMI_NETFN_CHASSIS_REQUEST;
send_msg.cmd = IPMI_CHASSIS_CONTROL_CMD;
- data[0] = 0; /* Power down */
+ data[0] = poweroff_control;
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;
+ switch (poweroff_control) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ /* power cycle failed, default to power down */
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "cycle message, IPMI error 0x%x\n", rv);
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ goto powercyclefailed;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ default:
+ printk(KERN_ERR PFX "Unable to send chassis power " \
+ "down message, IPMI error 0x%x\n", rv);
+ break;
+ }
}
- out:
return;
}
@@ -430,7 +457,8 @@ static void ipmi_po_new_smi(int if_num)
if (ready)
return;
- rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL, &ipmi_user);
+ rv = ipmi_create_user(if_num, &ipmi_poweroff_handler, NULL,
+ &ipmi_user);
if (rv) {
printk(KERN_ERR PFX "could not create IPMI user, error %d\n",
rv);
@@ -509,21 +537,84 @@ static struct ipmi_smi_watcher smi_watcher =
};
+#ifdef CONFIG_PROC_FS
+/* displays properties to proc */
+static int proc_read_chassctrl(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ return sprintf(page, "%d\t[ 0=powerdown 2=powercycle ]\n",
+ poweroff_control);
+}
+
+/* process property writes from proc */
+static int proc_write_chassctrl(struct file *file, const char *buffer,
+ unsigned long count, void *data)
+{
+ int rv = count;
+ unsigned int newval = 0;
+
+ sscanf(buffer, "%d", &newval);
+ switch (newval) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ printk(KERN_INFO PFX "power cycle is now enabled\n");
+ poweroff_control = newval;
+ break;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ break;
+
+ default:
+ rv = -EINVAL;
+ break;
+ }
+
+ return rv;
+}
+#endif /* CONFIG_PROC_FS */
+
/*
* Startup and shutdown functions.
*/
static int ipmi_poweroff_init (void)
{
- int rv;
+ int rv;
+ struct proc_dir_entry *file;
printk ("Copyright (C) 2004 MontaVista Software -"
" IPMI Powerdown via sys_reboot version "
IPMI_POWEROFF_VERSION ".\n");
+ switch (poweroff_control) {
+ case IPMI_CHASSIS_POWER_CYCLE:
+ printk(KERN_INFO PFX "Power cycle is enabled.\n");
+ break;
+
+ case IPMI_CHASSIS_POWER_DOWN:
+ default:
+ poweroff_control = IPMI_CHASSIS_POWER_DOWN;
+ break;
+ }
+
rv = ipmi_smi_watcher_register(&smi_watcher);
- if (rv)
+ if (rv) {
printk(KERN_ERR PFX "Unable to register SMI watcher: %d\n", rv);
+ goto out_err;
+ }
+
+#ifdef CONFIG_PROC_FS
+ file = create_proc_entry("poweroff_control", 0, proc_ipmi_root);
+ if (!file) {
+ printk(KERN_ERR PFX "Unable to create proc power control\n");
+ } else {
+ file->nlink = 1;
+ file->read_proc = proc_read_chassctrl;
+ file->write_proc = proc_write_chassctrl;
+ file->owner = THIS_MODULE;
+ }
+#endif
+ out_err:
return rv;
}
@@ -532,6 +623,10 @@ static __exit void ipmi_poweroff_cleanup(void)
{
int rv;
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("poweroff_control", proc_ipmi_root);
+#endif
+
ipmi_smi_watcher_unregister(&smi_watcher);
if (ready) {
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 601c7fccb4cf..1bbf507adda5 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1756,7 +1756,7 @@ static void isicom_flush_buffer(struct tty_struct * tty)
}
-static int __init register_ioregion(void)
+static int __devinit register_ioregion(void)
{
int count, done=0;
for (count=0; count < BOARD_COUNT; count++ ) {
@@ -1771,7 +1771,7 @@ static int __init register_ioregion(void)
return done;
}
-static void __exit unregister_ioregion(void)
+static void unregister_ioregion(void)
{
int count;
for (count=0; count < BOARD_COUNT; count++ )
@@ -1803,7 +1803,7 @@ static struct tty_operations isicom_ops = {
.tiocmset = isicom_tiocmset,
};
-static int __init register_drivers(void)
+static int __devinit register_drivers(void)
{
int error;
@@ -1834,7 +1834,7 @@ static int __init register_drivers(void)
return 0;
}
-static void __exit unregister_drivers(void)
+static void unregister_drivers(void)
{
int error = tty_unregister_driver(isicom_normal);
if (error)
@@ -1842,7 +1842,7 @@ static void __exit unregister_drivers(void)
put_tty_driver(isicom_normal);
}
-static int __init register_isr(void)
+static int __devinit register_isr(void)
{
int count, done=0;
unsigned long irqflags;
@@ -1883,7 +1883,7 @@ static void __exit unregister_isr(void)
}
}
-static int __init isicom_init(void)
+static int __devinit isicom_init(void)
{
int card, channel, base;
struct isi_port * port;
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index c02a21dbad5d..52a073eee201 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -407,7 +407,6 @@ static unsigned long stli_eisamemprobeaddrs[] = {
};
static int stli_eisamempsize = sizeof(stli_eisamemprobeaddrs) / sizeof(unsigned long);
-int stli_eisaprobe = STLI_EISAPROBE;
/*
* Define the Stallion PCI vendor and device IDs.
@@ -4685,7 +4684,7 @@ static int stli_initbrds(void)
#ifdef MODULE
stli_argbrds();
#endif
- if (stli_eisaprobe)
+ if (STLI_EISAPROBE)
stli_findeisabrds();
#ifdef CONFIG_PCI
stli_findpcibrds();
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index e3085b22a365..42187381506b 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -23,7 +23,10 @@
#include <linux/devfs_fs_kernel.h>
#include <linux/ptrace.h>
#include <linux/device.h>
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
#include <linux/backing-dev.h>
+#include <linux/bootmem.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -273,6 +276,40 @@ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
return mmap_mem(file, vma);
}
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * Read memory corresponding to the old kernel.
+ */
+static ssize_t read_oldmem(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ unsigned long pfn, offset;
+ size_t read = 0, csize;
+ int rc = 0;
+
+ while (count) {
+ pfn = *ppos / PAGE_SIZE;
+ if (pfn > saved_max_pfn)
+ return read;
+
+ offset = (unsigned long)(*ppos % PAGE_SIZE);
+ if (count > PAGE_SIZE - offset)
+ csize = PAGE_SIZE - offset;
+ else
+ csize = count;
+
+ rc = copy_oldmem_page(pfn, buf, csize, offset, 1);
+ if (rc < 0)
+ return rc;
+ buf += csize;
+ *ppos += csize;
+ read += csize;
+ count -= csize;
+ }
+ return read;
+}
+#endif
+
extern long vread(char *buf, char *addr, unsigned long count);
extern long vwrite(char *buf, char *addr, unsigned long count);
@@ -721,6 +758,7 @@ static int open_port(struct inode * inode, struct file * filp)
#define read_full read_zero
#define open_mem open_port
#define open_kmem open_mem
+#define open_oldmem open_mem
static struct file_operations mem_fops = {
.llseek = memory_lseek,
@@ -770,6 +808,13 @@ static struct file_operations full_fops = {
.write = write_full,
};
+#ifdef CONFIG_CRASH_DUMP
+static struct file_operations oldmem_fops = {
+ .read = read_oldmem,
+ .open = open_oldmem,
+};
+#endif
+
static ssize_t kmsg_write(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
@@ -825,6 +870,11 @@ static int memory_open(struct inode * inode, struct file * filp)
case 11:
filp->f_op = &kmsg_fops;
break;
+#ifdef CONFIG_CRASH_DUMP
+ case 12:
+ filp->f_op = &oldmem_fops;
+ break;
+#endif
default:
return -ENXIO;
}
@@ -854,6 +904,9 @@ static const struct {
{8, "random", S_IRUGO | S_IWUSR, &random_fops},
{9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
{11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops},
+#ifdef CONFIG_CRASH_DUMP
+ {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
+#endif
};
static struct class *mem_class;
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 3115d318b997..931efd58f87a 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -66,8 +66,6 @@ static unsigned char misc_minors[DYNAMIC_MINORS / 8];
extern int rtc_DP8570A_init(void);
extern int rtc_MK48T08_init(void);
extern int pmu_device_init(void);
-extern int tosh_init(void);
-extern int i8k_init(void);
#ifdef CONFIG_PROC_FS
static void *misc_seq_start(struct seq_file *seq, loff_t *pos)
@@ -311,15 +309,6 @@ static int __init misc_init(void)
#ifdef CONFIG_BVME6000
rtc_DP8570A_init();
#endif
-#ifdef CONFIG_PMAC_PBOOK
- pmu_device_init();
-#endif
-#ifdef CONFIG_TOSHIBA
- tosh_init();
-#endif
-#ifdef CONFIG_I8K
- i8k_init();
-#endif
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops)) {
printk("unable to get major %d for misc devices\n",
MISC_MAJOR);
diff --git a/drivers/char/moxa.c b/drivers/char/moxa.c
index 7c24fbe831f8..95f7046ff059 100644
--- a/drivers/char/moxa.c
+++ b/drivers/char/moxa.c
@@ -451,7 +451,7 @@ static int __init moxa_init(void)
int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1;
i = 0;
while (i < n) {
- while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
+ while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
{
if (pci_enable_device(p))
continue;
diff --git a/drivers/char/mwave/3780i.c b/drivers/char/mwave/3780i.c
index ab00f51475df..613aed9e1840 100644
--- a/drivers/char/mwave/3780i.c
+++ b/drivers/char/mwave/3780i.c
@@ -107,8 +107,8 @@ void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
spin_unlock_irqrestore(&dsp_lock, flags);
}
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
- unsigned char ucValue)
+static void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
+ unsigned char ucValue)
{
DSP_ISA_SLAVE_CONTROL rSlaveControl;
DSP_ISA_SLAVE_CONTROL rSlaveControl_Save;
@@ -141,6 +141,7 @@ void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
}
+#if 0
unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
unsigned uIndex)
{
@@ -167,6 +168,7 @@ unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
return ucValue;
}
+#endif /* 0 */
int dsp3780I_EnableDSP(DSP_3780I_CONFIG_SETTINGS * pSettings,
unsigned short *pIrqMap,
diff --git a/drivers/char/mwave/3780i.h b/drivers/char/mwave/3780i.h
index 3e7d020d1bf4..270431ca7dae 100644
--- a/drivers/char/mwave/3780i.h
+++ b/drivers/char/mwave/3780i.h
@@ -338,10 +338,6 @@ unsigned short dsp3780I_ReadMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr);
void dsp3780I_WriteMsaCfg(unsigned short usDspBaseIO,
unsigned long ulMsaAddr, unsigned short usValue);
-void dsp3780I_WriteGenCfg(unsigned short usDspBaseIO, unsigned uIndex,
- unsigned char ucValue);
-unsigned char dsp3780I_ReadGenCfg(unsigned short usDspBaseIO,
- unsigned uIndex);
int dsp3780I_GetIPCSource(unsigned short usDspBaseIO,
unsigned short *pusIPCSource);
diff --git a/drivers/char/mwave/tp3780i.c b/drivers/char/mwave/tp3780i.c
index ab650cd6efc0..d6c72e0934e2 100644
--- a/drivers/char/mwave/tp3780i.c
+++ b/drivers/char/mwave/tp3780i.c
@@ -242,20 +242,14 @@ int tp3780I_ClaimResources(THINKPAD_BD_DATA * pBDData)
{
int retval = 0;
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
struct resource *pres;
-#endif
PRINTK_2(TRACE_TP3780I,
"tp3780i::tp3780I_ClaimResources entry pBDData %p\n", pBDData);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pres = request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
if ( pres == NULL ) retval = -EIO;
-#else
- retval = check_region(pSettings->usDspBaseIO, 16);
- if (!retval) request_region(pSettings->usDspBaseIO, 16, "mwave_3780i");
-#endif
+
if (retval) {
PRINTK_ERROR(KERN_ERR_MWAVE "tp3780i::tp3780I_ClaimResources: Error: Could not claim I/O region starting at %x\n", pSettings->usDspBaseIO);
retval = -EIO;
@@ -292,7 +286,7 @@ int tp3780I_ReleaseResources(THINKPAD_BD_DATA * pBDData)
int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
{
DSP_3780I_CONFIG_SETTINGS *pSettings = &pBDData->rDspSettings;
- BOOLEAN bDSPPoweredUp = FALSE, bDSPEnabled = FALSE, bInterruptAllocated = FALSE;
+ BOOLEAN bDSPPoweredUp = FALSE, bInterruptAllocated = FALSE;
PRINTK_2(TRACE_TP3780I, "tp3780i::tp3780I_EnableDSP entry pBDData %p\n", pBDData);
@@ -397,8 +391,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
if (dsp3780I_EnableDSP(pSettings, s_ausThinkpadIrqToField, s_ausThinkpadDmaToField)) {
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Error: dsp7880I_EnableDSP() failed\n");
goto exit_cleanup;
- } else {
- bDSPEnabled = TRUE;
}
EnableSRAM(pBDData);
@@ -411,8 +403,6 @@ int tp3780I_EnableDSP(THINKPAD_BD_DATA * pBDData)
exit_cleanup:
PRINTK_ERROR("tp3780i::tp3780I_EnableDSP: Cleaning up\n");
- if (bDSPEnabled)
- dsp3780I_DisableDSP(pSettings);
if (bDSPPoweredUp)
smapi_set_DSP_power_state(FALSE);
if (bInterruptAllocated) {
diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c
index edba5a35bf21..09103b3d8f05 100644
--- a/drivers/char/n_tty.c
+++ b/drivers/char/n_tty.c
@@ -770,10 +770,8 @@ send_signal:
}
if (c == '\n') {
if (L_ECHO(tty) || L_ECHONL(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+ if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty);
- return;
- }
opost('\n', tty);
}
goto handle_newline;
@@ -790,10 +788,8 @@ send_signal:
* XXX are EOL_CHAR and EOL2_CHAR echoed?!?
*/
if (L_ECHO(tty)) {
- if (tty->read_cnt >= N_TTY_BUF_SIZE-1) {
+ if (tty->read_cnt >= N_TTY_BUF_SIZE-1)
put_char('\a', tty);
- return;
- }
/* Record the column of first canon char. */
if (tty->canon_head == tty->read_head)
tty->canon_column = tty->column;
@@ -862,12 +858,9 @@ static int n_tty_receive_room(struct tty_struct *tty)
* that erase characters will be handled. Other excess
* characters will be beeped.
*/
- if (tty->icanon && !tty->canon_data)
- return N_TTY_BUF_SIZE;
-
- if (left > 0)
- return left;
- return 0;
+ if (left <= 0)
+ left = tty->icanon && !tty->canon_data;
+ return left;
}
/**
@@ -1473,13 +1466,17 @@ static ssize_t write_chan(struct tty_struct * tty, struct file * file,
if (tty->driver->flush_chars)
tty->driver->flush_chars(tty);
} else {
- c = tty->driver->write(tty, b, nr);
- if (c < 0) {
- retval = c;
- goto break_out;
+ while (nr > 0) {
+ c = tty->driver->write(tty, b, nr);
+ if (c < 0) {
+ retval = c;
+ goto break_out;
+ }
+ if (!c)
+ break;
+ b += c;
+ nr -= c;
}
- b += c;
- nr -= c;
}
if (!nr)
break;
diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c
index f63a3fd7ca6f..1af733d07321 100644
--- a/drivers/char/nvram.c
+++ b/drivers/char/nvram.c
@@ -211,12 +211,13 @@ nvram_check_checksum(void)
return rv;
}
-void
+static void
__nvram_set_checksum(void)
{
mach_set_checksum();
}
+#if 0
void
nvram_set_checksum(void)
{
@@ -226,6 +227,7 @@ nvram_set_checksum(void)
__nvram_set_checksum();
spin_unlock_irqrestore(&rtc_lock, flags);
}
+#endif /* 0 */
/*
* The are the file operation function for user access to /dev/nvram
@@ -921,6 +923,4 @@ EXPORT_SYMBOL(__nvram_write_byte);
EXPORT_SYMBOL(nvram_write_byte);
EXPORT_SYMBOL(__nvram_check_checksum);
EXPORT_SYMBOL(nvram_check_checksum);
-EXPORT_SYMBOL(__nvram_set_checksum);
-EXPORT_SYMBOL(nvram_set_checksum);
MODULE_ALIAS_MISCDEV(NVRAM_MINOR);
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
index 1c8d866a49dc..7a0c74648124 100644
--- a/drivers/char/pcmcia/synclink_cs.c
+++ b/drivers/char/pcmcia/synclink_cs.c
@@ -71,7 +71,6 @@
#include <linux/workqueue.h>
#include <linux/hdlc.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -581,7 +580,7 @@ static dev_link_t *mgslpc_attach(void)
/* Interrupt setup */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
- link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+ link->irq.IRQInfo1 = IRQ_LEVEL_ID;
link->irq.Handler = NULL;
link->conf.Attributes = 0;
@@ -593,11 +592,6 @@ static dev_link_t *mgslpc_attach(void)
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &mgslpc_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -3081,13 +3075,21 @@ void mgslpc_remove_device(MGSLPC_INFO *remove_info)
}
}
+static struct pcmcia_device_id mgslpc_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x02c5, 0x0050),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, mgslpc_ids);
+
static struct pcmcia_driver mgslpc_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "synclink_cs",
},
.attach = mgslpc_attach,
+ .event = mgslpc_event,
.detach = mgslpc_detach,
+ .id_table = mgslpc_ids,
};
static struct tty_operations mgslpc_ops = {
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 460b5d475edd..6b11d6b2129f 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -271,7 +271,7 @@ static int random_write_wakeup_thresh = 128;
* samples to avoid wasting CPU time and reduce lock contention.
*/
-static int trickle_thresh = INPUT_POOL_WORDS * 28;
+static int trickle_thresh __read_mostly = INPUT_POOL_WORDS * 28;
static DEFINE_PER_CPU(int, trickle_count) = 0;
diff --git a/drivers/char/rio/func.h b/drivers/char/rio/func.h
index e8f3860f4726..01987c6dc398 100644
--- a/drivers/char/rio/func.h
+++ b/drivers/char/rio/func.h
@@ -147,7 +147,6 @@ struct rio_info * rio_info_store( int cmd, struct rio_info * p);
extern int rio_pcicopy(char *src, char *dst, int n);
extern int rio_minor (struct tty_struct *tty);
extern int rio_ismodem (struct tty_struct *tty);
-extern void rio_udelay (int usecs);
extern void rio_start_card_running (struct Host * HostP);
diff --git a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
index 763893e289b3..d7d484024e2b 100644
--- a/drivers/char/rio/rio_linux.c
+++ b/drivers/char/rio/rio_linux.c
@@ -354,11 +354,6 @@ int rio_ismodem(struct tty_struct *tty)
}
-void rio_udelay (int usecs)
-{
- udelay (usecs);
-}
-
static int rio_set_real_termios (void *ptr)
{
int rv, modem;
@@ -1100,7 +1095,7 @@ static int __init rio_init(void)
#ifdef CONFIG_PCI
/* First look for the JET devices: */
- while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8,
pdev))) {
if (pci_enable_device(pdev)) continue;
@@ -1174,7 +1169,7 @@ static int __init rio_init(void)
*/
/* Then look for the older RIO/PCI devices: */
- while ((pdev = pci_find_device (PCI_VENDOR_ID_SPECIALIX,
+ while ((pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,
PCI_DEVICE_ID_SPECIALIX_RIO,
pdev))) {
if (pci_enable_device(pdev)) continue;
diff --git a/drivers/char/rio/rioinit.c b/drivers/char/rio/rioinit.c
index dca941ed10cf..898a126ae3e6 100644
--- a/drivers/char/rio/rioinit.c
+++ b/drivers/char/rio/rioinit.c
@@ -37,6 +37,7 @@ static char *_rioinit_c_sccs_ = "@(#)rioinit.c 1.3";
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/errno.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/string.h>
@@ -1560,14 +1561,14 @@ uint Slot;
INTERRUPT_DISABLE | BYTE_OPERATION |
SLOW_LINKS | SLOW_AT_BUS);
WBYTE(DpRamP->DpResetTpu, 0xFF);
- rio_udelay (3);
+ udelay(3);
rio_dprintk (RIO_DEBUG_INIT, "RIOHostReset: Don't know if it worked. Try reset again\n");
WBYTE(DpRamP->DpControl, BOOT_FROM_RAM | EXTERNAL_BUS_OFF |
INTERRUPT_DISABLE | BYTE_OPERATION |
SLOW_LINKS | SLOW_AT_BUS);
WBYTE(DpRamP->DpResetTpu, 0xFF);
- rio_udelay (3);
+ udelay(3);
break;
#ifdef FUTURE_RELEASE
case RIO_EISA:
@@ -1599,7 +1600,7 @@ uint Slot;
DpRamP->DpControl = RIO_PCI_BOOT_FROM_RAM;
DpRamP->DpResetInt = 0xFF;
DpRamP->DpResetTpu = 0xFF;
- rio_udelay (100);
+ udelay(100);
/* for (i=0; i<6000; i++); */
/* suspend( 3 ); */
break;
diff --git a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
index db655002671f..78a321afdf4f 100644
--- a/drivers/char/rio/riotty.c
+++ b/drivers/char/rio/riotty.c
@@ -524,16 +524,16 @@ riotclose(void *ptr)
register uint SysPort = dev;
struct ttystatics *tp; /* pointer to our ttystruct */
#endif
- struct Port *PortP =ptr; /* pointer to the port structure */
+ struct Port *PortP = ptr; /* pointer to the port structure */
int deleted = 0;
int try = -1; /* Disable the timeouts by setting them to -1 */
int repeat_this = -1; /* Congrats to those having 15 years of
uptime! (You get to break the driver.) */
- long end_time;
+ unsigned long end_time;
struct tty_struct * tty;
unsigned long flags;
int Modem;
- int rv =0;
+ int rv = 0;
rio_dprintk (RIO_DEBUG_TTY, "port close SysPort %d\n",PortP->PortNum);
@@ -620,7 +620,7 @@ riotclose(void *ptr)
if (repeat_this -- <= 0) {
rv = -EINTR;
rio_dprintk (RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
- RIOPreemptiveCmd(p, PortP, FCLOSE );
+ RIOPreemptiveCmd(p, PortP, FCLOSE);
goto close_end;
}
rio_dprintk (RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
@@ -656,14 +656,12 @@ riotclose(void *ptr)
goto close_end;
}
-
-
/* Can't call RIOShortCommand with the port locked. */
rio_spin_unlock_irqrestore(&PortP->portSem, flags);
if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
- RIOPreemptiveCmd(p, PortP,FCLOSE);
- goto close_end;
+ RIOPreemptiveCmd(p, PortP, FCLOSE);
+ goto close_end;
}
if (!deleted)
@@ -698,7 +696,6 @@ riotclose(void *ptr)
*/
PortP->Config &= ~(RIO_CTSFLOW|RIO_RTSFLOW);
-
#ifdef STATS
PortP->Stat.CloseCnt++;
#endif
diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c
index 5bcbeb0cb9ae..f463d6baa685 100644
--- a/drivers/char/rocket.c
+++ b/drivers/char/rocket.c
@@ -161,6 +161,64 @@ static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = {
UPCI_AIOP_INTR_BIT_3
};
+static Byte_t RData[RDATASIZE] = {
+ 0x00, 0x09, 0xf6, 0x82,
+ 0x02, 0x09, 0x86, 0xfb,
+ 0x04, 0x09, 0x00, 0x0a,
+ 0x06, 0x09, 0x01, 0x0a,
+ 0x08, 0x09, 0x8a, 0x13,
+ 0x0a, 0x09, 0xc5, 0x11,
+ 0x0c, 0x09, 0x86, 0x85,
+ 0x0e, 0x09, 0x20, 0x0a,
+ 0x10, 0x09, 0x21, 0x0a,
+ 0x12, 0x09, 0x41, 0xff,
+ 0x14, 0x09, 0x82, 0x00,
+ 0x16, 0x09, 0x82, 0x7b,
+ 0x18, 0x09, 0x8a, 0x7d,
+ 0x1a, 0x09, 0x88, 0x81,
+ 0x1c, 0x09, 0x86, 0x7a,
+ 0x1e, 0x09, 0x84, 0x81,
+ 0x20, 0x09, 0x82, 0x7c,
+ 0x22, 0x09, 0x0a, 0x0a
+};
+
+static Byte_t RRegData[RREGDATASIZE] = {
+ 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
+ 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
+ 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
+ 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
+ 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
+ 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
+ 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
+ 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
+ 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
+ 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
+ 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
+ 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
+ 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
+};
+
+static CONTROLLER_T sController[CTL_SIZE] = {
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
+ {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
+ {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
+};
+
+static Byte_t sBitMapClrTbl[8] = {
+ 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
+};
+
+static Byte_t sBitMapSetTbl[8] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
+};
+
+static int sClockPrescale = 0x14;
+
/*
* Line number is the ttySIx number (x), the Minor number. We
* assign them sequentially, starting at zero. The following
@@ -177,6 +235,26 @@ static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model);
static unsigned char GetLineNumber(int ctrl, int aiop, int ch);
static unsigned char SetLineNumber(int ctrl, int aiop, int ch);
static void rp_start(struct tty_struct *tty);
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+ int ChanNum);
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
+static void sFlushRxFIFO(CHANNEL_T * ChP);
+static void sFlushTxFIFO(CHANNEL_T * ChP);
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+ int PeriodicOnly, int altChanRingIndicator,
+ int UPCIRingInd);
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ int IRQNum, Byte_t Frequency, int PeriodicOnly);
+static int sReadAiopID(ByteIO_t io);
+static int sReadAiopNumChan(WordIO_t io);
#ifdef MODULE
MODULE_AUTHOR("Theodore Ts'o");
@@ -1798,7 +1876,7 @@ static void rp_flush_buffer(struct tty_struct *tty)
* init's aiopic and serial port hardware.
* Inputs: i is the board number (0-n)
*/
-__init int register_PCI(int i, struct pci_dev *dev)
+static __init int register_PCI(int i, struct pci_dev *dev)
{
int num_aiops, aiop, max_num_aiops, num_chan, chan;
unsigned int aiopio[MAX_AIOPS_PER_BOARD];
@@ -2453,72 +2531,6 @@ static void rp_cleanup_module(void)
}
#endif
-#ifndef TRUE
-#define TRUE 1
-#endif
-
-#ifndef FALSE
-#define FALSE 0
-#endif
-
-static Byte_t RData[RDATASIZE] = {
- 0x00, 0x09, 0xf6, 0x82,
- 0x02, 0x09, 0x86, 0xfb,
- 0x04, 0x09, 0x00, 0x0a,
- 0x06, 0x09, 0x01, 0x0a,
- 0x08, 0x09, 0x8a, 0x13,
- 0x0a, 0x09, 0xc5, 0x11,
- 0x0c, 0x09, 0x86, 0x85,
- 0x0e, 0x09, 0x20, 0x0a,
- 0x10, 0x09, 0x21, 0x0a,
- 0x12, 0x09, 0x41, 0xff,
- 0x14, 0x09, 0x82, 0x00,
- 0x16, 0x09, 0x82, 0x7b,
- 0x18, 0x09, 0x8a, 0x7d,
- 0x1a, 0x09, 0x88, 0x81,
- 0x1c, 0x09, 0x86, 0x7a,
- 0x1e, 0x09, 0x84, 0x81,
- 0x20, 0x09, 0x82, 0x7c,
- 0x22, 0x09, 0x0a, 0x0a
-};
-
-static Byte_t RRegData[RREGDATASIZE] = {
- 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
- 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
- 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
- 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
- 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
- 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
- 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
- 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
- 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
- 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
- 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
- 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
- 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
-};
-
-CONTROLLER_T sController[CTL_SIZE] = {
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}},
- {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0},
- {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}
-};
-
-Byte_t sBitMapClrTbl[8] = {
- 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f
-};
-
-Byte_t sBitMapSetTbl[8] = {
- 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
-};
-
-int sClockPrescale = 0x14;
-
/***************************************************************************
Function: sInitController
Purpose: Initialization of controller global registers and controller
@@ -2554,22 +2566,22 @@ Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
- int PeriodicOnly: TRUE if all interrupts except the periodic
+ int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
- FALSE is both the periodic interrupt and
+ 0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
- overidden, it is forced to a value of FALSE.
+ overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
- are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
- Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+ Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
@@ -2589,9 +2601,9 @@ Warnings: No range checking on any of the parameters is done.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
-int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
- ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum,
- Byte_t Frequency, int PeriodicOnly)
+static int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ int IRQNum, Byte_t Frequency, int PeriodicOnly)
{
int i;
ByteIO_t io;
@@ -2687,22 +2699,22 @@ Call: sPCIInitController(CtlP,CtlNum,AiopIOList,AiopIOListSize,
FREQ_4HZ - 4 Hertz
If IRQNum is set to 0 the Frequency parameter is
overidden, it is forced to a value of FREQ_DIS.
- int PeriodicOnly: TRUE if all interrupts except the periodic
+ int PeriodicOnly: 1 if all interrupts except the periodic
interrupt are to be blocked.
- FALSE is both the periodic interrupt and
+ 0 is both the periodic interrupt and
other channel interrupts are allowed.
If IRQNum is set to 0 the PeriodicOnly parameter is
- overidden, it is forced to a value of FALSE.
+ overidden, it is forced to a value of 0.
Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
initialization failed.
Comments:
If periodic interrupts are to be disabled but AIOP interrupts
- are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
+ are allowed, set Frequency to FREQ_DIS and PeriodicOnly to 0.
If interrupts are to be completely disabled set IRQNum to 0.
- Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
+ Setting Frequency to FREQ_DIS and PeriodicOnly to 1 is an
invalid combination.
This function performs initialization of global interrupt modes,
@@ -2722,11 +2734,11 @@ Warnings: No range checking on any of the parameters is done.
After this function all AIOPs on the controller are disabled,
they can be enabled with sEnAiop().
*/
-int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
- ByteIO_t * AiopIOList, int AiopIOListSize,
- WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
- int PeriodicOnly, int altChanRingIndicator,
- int UPCIRingInd)
+static int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum,
+ ByteIO_t * AiopIOList, int AiopIOListSize,
+ WordIO_t ConfigIO, int IRQNum, Byte_t Frequency,
+ int PeriodicOnly, int altChanRingIndicator,
+ int UPCIRingInd)
{
int i;
ByteIO_t io;
@@ -2784,7 +2796,7 @@ Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
Warnings: No context switches are allowed while executing this function.
*/
-int sReadAiopID(ByteIO_t io)
+static int sReadAiopID(ByteIO_t io)
{
Byte_t AiopID; /* ID byte from AIOP */
@@ -2810,7 +2822,7 @@ Comments: The number of channels is determined by write/reads from identical
AIOP, otherwise it is an 8 channel.
Warnings: No context switches are allowed while executing this function.
*/
-int sReadAiopNumChan(WordIO_t io)
+static int sReadAiopNumChan(WordIO_t io)
{
Word_t x;
static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 };
@@ -2834,15 +2846,15 @@ Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
CHANNEL_T *ChP; Ptr to channel structure
int AiopNum; AIOP number within controller
int ChanNum; Channel number within AIOP
-Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
+Return: int: 1 if initialization succeeded, 0 if it fails because channel
number exceeds number of channels available in AIOP.
Comments: This function must be called before a channel can be used.
Warnings: No range checking on any of the parameters is done.
No context switches are allowed while executing this function.
*/
-int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
- int ChanNum)
+static int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
+ int ChanNum)
{
int i;
WordIO_t AiopIO;
@@ -2853,7 +2865,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
int brd9600;
if (ChanNum >= CtlP->AiopNumChan[AiopNum])
- return (FALSE); /* exceeds num chans in AIOP */
+ return 0; /* exceeds num chans in AIOP */
/* Channel, AIOP, and controller identifiers */
ChP->CtlP = CtlP;
@@ -2968,7 +2980,7 @@ int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum,
ChP->TxPrioBuf = ChOff + _TXP_BUF;
sEnRxProcessor(ChP); /* start the Rx processor */
- return (TRUE);
+ return 1;
}
/***************************************************************************
@@ -2989,7 +3001,7 @@ Warnings: No context switches are allowed while executing this function.
After calling this function a delay of 4 uS is required to ensure
that the receive processor is no longer processing this channel.
*/
-void sStopRxProcessor(CHANNEL_T * ChP)
+static void sStopRxProcessor(CHANNEL_T * ChP)
{
Byte_t R[4];
@@ -3014,18 +3026,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
this function.
Warnings: No context switches are allowed while executing this function.
*/
-void sFlushRxFIFO(CHANNEL_T * ChP)
+static void sFlushRxFIFO(CHANNEL_T * ChP)
{
int i;
Byte_t Ch; /* channel number within AIOP */
- int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
+ int RxFIFOEnabled; /* 1 if Rx FIFO enabled */
if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
return; /* don't need to flush */
- RxFIFOEnabled = FALSE;
+ RxFIFOEnabled = 0;
if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */
- RxFIFOEnabled = TRUE;
+ RxFIFOEnabled = 1;
sDisRxFIFO(ChP); /* disable it */
for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */
sInB(ChP->IntChan); /* depends on bus i/o timing */
@@ -3056,18 +3068,18 @@ Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
this function.
Warnings: No context switches are allowed while executing this function.
*/
-void sFlushTxFIFO(CHANNEL_T * ChP)
+static void sFlushTxFIFO(CHANNEL_T * ChP)
{
int i;
Byte_t Ch; /* channel number within AIOP */
- int TxEnabled; /* TRUE if transmitter enabled */
+ int TxEnabled; /* 1 if transmitter enabled */
if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
return; /* don't need to flush */
- TxEnabled = FALSE;
+ TxEnabled = 0;
if (ChP->TxControl[3] & TX_ENABLE) {
- TxEnabled = TRUE;
+ TxEnabled = 1;
sDisTransmit(ChP); /* disable transmitter */
}
sStopRxProcessor(ChP); /* stop Rx processor */
@@ -3096,7 +3108,7 @@ Comments: The priority byte is transmitted before any data in the Tx FIFO.
Warnings: No context switches are allowed while executing this function.
*/
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
+static int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data)
{
Byte_t DWBuf[4]; /* buffer for double word writes */
Word_t *WordPtr; /* must be far because Win SS != DS */
@@ -3158,7 +3170,7 @@ Comments: If an interrupt enable flag is set in Flags, that interrupt will be
enable channel interrupts. This would allow the global interrupt
status register to be used to determine which AIOPs need service.
*/
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags)
{
Byte_t Mask; /* Interrupt Mask Register */
@@ -3202,7 +3214,7 @@ Comments: If an interrupt flag is set in Flags, that interrupt will be
this channel's bit from being set in the AIOP's Interrupt Channel
Register.
*/
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
+static void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
{
Byte_t Mask; /* Interrupt Mask Register */
@@ -3218,7 +3230,7 @@ void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags)
}
}
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
+static void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
{
sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum);
}
@@ -3227,7 +3239,7 @@ void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode)
* Not an official SSCI function, but how to reset RocketModems.
* ISA bus version
*/
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
{
ByteIO_t addr;
Byte_t val;
@@ -3252,7 +3264,7 @@ void sModemReset(CONTROLLER_T * CtlP, int chan, int on)
* Not an official SSCI function, but how to reset RocketModems.
* PCI bus version
*/
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
+static void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on)
{
ByteIO_t addr;
diff --git a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h
index 802687290ee1..3a8bcc85bc14 100644
--- a/drivers/char/rocket_int.h
+++ b/drivers/char/rocket_int.h
@@ -1130,46 +1130,6 @@ Warnings: This function writes the data byte without checking to see if
*/
#define sWriteTxByte(IO,DATA) sOutB(IO,DATA)
-int sInitController(CONTROLLER_T * CtlP,
- int CtlNum,
- ByteIO_t MudbacIO,
- ByteIO_t * AiopIOList,
- int AiopIOListSize,
- int IRQNum, Byte_t Frequency, int PeriodicOnly);
-
-int sPCIInitController(CONTROLLER_T * CtlP,
- int CtlNum,
- ByteIO_t * AiopIOList,
- int AiopIOListSize,
- WordIO_t ConfigIO,
- int IRQNum,
- Byte_t Frequency,
- int PeriodicOnly,
- int altChanRingIndicator, int UPCIRingInd);
-
-int sReadAiopID(ByteIO_t io);
-int sReadAiopNumChan(WordIO_t io);
-int sInitChan(CONTROLLER_T * CtlP,
- CHANNEL_T * ChP, int AiopNum, int ChanNum);
-Byte_t sGetRxErrStatus(CHANNEL_T * ChP);
-void sStopRxProcessor(CHANNEL_T * ChP);
-void sStopSWInFlowCtl(CHANNEL_T * ChP);
-void sFlushRxFIFO(CHANNEL_T * ChP);
-void sFlushTxFIFO(CHANNEL_T * ChP);
-int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data);
-void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags);
-void sModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on);
-void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode);
-
-extern Byte_t R[RDATASIZE];
-extern CONTROLLER_T sController[CTL_SIZE];
-extern Byte_t sIRQMap[16];
-extern Byte_t sBitMapClrTbl[8];
-extern Byte_t sBitMapSetTbl[8];
-extern int sClockPrescale;
-
/*
* Begin Linux specific definitions for the Rocketport driver
*
diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c
index ff4f09804865..d8f9e94ae475 100644
--- a/drivers/char/rtc.c
+++ b/drivers/char/rtc.c
@@ -78,6 +78,7 @@
#include <linux/sysctl.h>
#include <linux/wait.h>
#include <linux/bcd.h>
+#include <linux/delay.h>
#include <asm/current.h>
#include <asm/uaccess.h>
@@ -894,7 +895,6 @@ static int __init rtc_init(void)
struct proc_dir_entry *ent;
#if defined(__alpha__) || defined(__mips__)
unsigned int year, ctrl;
- unsigned long uip_watchdog;
char *guess = NULL;
#endif
#ifdef __sparc__
@@ -1000,12 +1000,8 @@ no_irq:
/* Each operating system on an Alpha uses its own epoch.
Let's try to guess which one we are using now. */
- uip_watchdog = jiffies;
if (rtc_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100) {
- barrier();
- cpu_relax();
- }
+ msleep(20);
spin_lock_irq(&rtc_lock);
year = CMOS_READ(RTC_YEAR);
@@ -1213,7 +1209,6 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
void rtc_get_rtc_time(struct rtc_time *rtc_tm)
{
- unsigned long uip_watchdog = jiffies;
unsigned char ctrl;
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
@@ -1221,7 +1216,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
/*
* read RTC once any update in progress is done. The update
- * can take just over 2ms. We wait 10 to 20ms. There is no need to
+ * can take just over 2ms. We wait 20ms. There is no need to
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
* If you need to know *exactly* when a second has started, enable
* periodic update complete interrupts, (via ioctl) and then
@@ -1230,10 +1225,7 @@ void rtc_get_rtc_time(struct rtc_time *rtc_tm)
*/
if (rtc_is_updating() != 0)
- while (jiffies - uip_watchdog < 2*HZ/100) {
- barrier();
- cpu_relax();
- }
+ msleep(20);
/*
* Only the values that we read from the RTC are set. We leave
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index f59f7cbd525b..12d563c648f7 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -35,6 +35,7 @@
#include <linux/spinlock.h>
#include <linux/vt_kern.h>
#include <linux/workqueue.h>
+#include <linux/kexec.h>
#include <asm/ptrace.h>
@@ -94,6 +95,21 @@ static struct sysrq_key_op sysrq_unraw_op = {
};
#endif /* CONFIG_VT */
+#ifdef CONFIG_KEXEC
+/* crashdump sysrq handler */
+static void sysrq_handle_crashdump(int key, struct pt_regs *pt_regs,
+ struct tty_struct *tty)
+{
+ crash_kexec(pt_regs);
+}
+static struct sysrq_key_op sysrq_crashdump_op = {
+ .handler = sysrq_handle_crashdump,
+ .help_msg = "Crashdump",
+ .action_msg = "Trigger a crashdump",
+ .enable_mask = SYSRQ_ENABLE_DUMP,
+};
+#endif
+
/* reboot sysrq handler */
static void sysrq_handle_reboot(int key, struct pt_regs *pt_regs,
struct tty_struct *tty)
@@ -212,7 +228,7 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(void *ignored)
{
- out_of_memory(GFP_KERNEL);
+ out_of_memory(GFP_KERNEL, 0);
}
static DECLARE_WORK(moom_work, moom_callback, NULL);
@@ -273,8 +289,12 @@ static struct sysrq_key_op *sysrq_key_table[SYSRQ_KEY_TABLE_LENGTH] = {
it is handled specially on the sparc
and will never arrive */
/* b */ &sysrq_reboot_op,
-/* c */ NULL,
-/* d */ NULL,
+#ifdef CONFIG_KEXEC
+/* c */ &sysrq_crashdump_op,
+#else
+/* c */ NULL,
+#endif
+/* d */ NULL,
/* e */ &sysrq_term_op,
/* f */ &sysrq_moom_op,
/* g */ NULL,
diff --git a/drivers/char/tb0219.c b/drivers/char/tb0219.c
index 5413f2908859..eb7058cbf015 100644
--- a/drivers/char/tb0219.c
+++ b/drivers/char/tb0219.c
@@ -24,6 +24,8 @@
#include <asm/io.h>
#include <asm/reboot.h>
+#include <asm/vr41xx/giu.h>
+#include <asm/vr41xx/tb0219.h>
MODULE_AUTHOR("Yoichi Yuasa <yuasa@hh.iij4u.or.jp>");
MODULE_DESCRIPTION("TANBAC TB0219 base board driver");
@@ -266,6 +268,21 @@ static void tb0219_restart(char *command)
tb0219_write(TB0219_RESET, 0);
}
+static void tb0219_pci_irq_init(void)
+{
+ /* PCI Slot 1 */
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT1_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT1_PIN, IRQ_LEVEL_LOW);
+
+ /* PCI Slot 2 */
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT2_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT2_PIN, IRQ_LEVEL_LOW);
+
+ /* PCI Slot 3 */
+ vr41xx_set_irq_trigger(TB0219_PCI_SLOT3_PIN, IRQ_TRIGGER_LEVEL, IRQ_SIGNAL_THROUGH);
+ vr41xx_set_irq_level(TB0219_PCI_SLOT3_PIN, IRQ_LEVEL_LOW);
+}
+
static int tb0219_probe(struct device *dev)
{
int retval;
@@ -292,6 +309,8 @@ static int tb0219_probe(struct device *dev)
old_machine_restart = _machine_restart;
_machine_restart = tb0219_restart;
+ tb0219_pci_irq_init();
+
if (major == 0) {
major = retval;
printk(KERN_INFO "TB0219: major number %d\n", major);
diff --git a/drivers/char/tipar.c b/drivers/char/tipar.c
index 659335d80ee7..ec78d2f161f7 100644
--- a/drivers/char/tipar.c
+++ b/drivers/char/tipar.c
@@ -396,7 +396,7 @@ static struct file_operations tipar_fops = {
static int __init
tipar_setup(char *str)
{
- int ints[2];
+ int ints[3];
str = get_options(str, ARRAY_SIZE(ints), ints);
diff --git a/drivers/char/toshiba.c b/drivers/char/toshiba.c
index 58e21fe44262..0c6f521abd0e 100644
--- a/drivers/char/toshiba.c
+++ b/drivers/char/toshiba.c
@@ -73,16 +73,20 @@
#define TOSH_MINOR_DEV 181
-static int tosh_id = 0x0000;
-static int tosh_bios = 0x0000;
-static int tosh_date = 0x0000;
-static int tosh_sci = 0x0000;
-static int tosh_fan = 0;
-
-static int tosh_fn = 0;
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
+MODULE_DESCRIPTION("Toshiba laptop SMM driver");
+MODULE_SUPPORTED_DEVICE("toshiba");
-module_param(tosh_fn, int, 0);
+static int tosh_fn;
+module_param_named(fn, tosh_fn, int, 0);
+MODULE_PARM_DESC(fn, "User specified Fn key detection port");
+static int tosh_id;
+static int tosh_bios;
+static int tosh_date;
+static int tosh_sci;
+static int tosh_fan;
static int tosh_ioctl(struct inode *, struct file *, unsigned int,
unsigned long);
@@ -359,7 +363,7 @@ static int tosh_get_machine_id(void)
unsigned long address;
id = (0x100*(int) isa_readb(0xffffe))+((int) isa_readb(0xffffa));
-
+
/* do we have a SCTTable machine identication number on our hands */
if (id==0xfc2f) {
@@ -424,7 +428,7 @@ static int tosh_probe(void)
}
/* call the Toshiba SCI support check routine */
-
+
regs.eax = 0xf0f0;
regs.ebx = 0x0000;
regs.ecx = 0x0000;
@@ -440,7 +444,7 @@ static int tosh_probe(void)
/* if we get this far then we are running on a Toshiba (probably)! */
tosh_sci = regs.edx & 0xffff;
-
+
/* next get the machine ID of the current laptop */
tosh_id = tosh_get_machine_id();
@@ -475,16 +479,15 @@ static int tosh_probe(void)
return 0;
}
-int __init tosh_init(void)
+static int __init toshiba_init(void)
{
int retval;
/* are we running on a Toshiba laptop */
- if (tosh_probe()!=0)
- return -EIO;
+ if (tosh_probe())
+ return -ENODEV;
- printk(KERN_INFO "Toshiba System Managment Mode driver v"
- TOSH_VERSION"\n");
+ printk(KERN_INFO "Toshiba System Managment Mode driver v" TOSH_VERSION "\n");
/* set the port to use for Fn status if not specified as a parameter */
if (tosh_fn==0x00)
@@ -492,12 +495,12 @@ int __init tosh_init(void)
/* register the device file */
retval = misc_register(&tosh_device);
- if(retval < 0)
+ if (retval < 0)
return retval;
#ifdef CONFIG_PROC_FS
/* register the proc entry */
- if(create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL){
+ if (create_proc_info_entry("toshiba", 0, NULL, tosh_get_info) == NULL) {
misc_deregister(&tosh_device);
return -ENOMEM;
}
@@ -506,27 +509,12 @@ int __init tosh_init(void)
return 0;
}
-#ifdef MODULE
-int init_module(void)
-{
- return tosh_init();
-}
-
-void cleanup_module(void)
+static void __exit toshiba_exit(void)
{
- /* remove the proc entry */
-
remove_proc_entry("toshiba", NULL);
-
- /* unregister the device file */
-
misc_deregister(&tosh_device);
}
-#endif
-MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(tosh_fn, "User specified Fn key detection port");
-MODULE_AUTHOR("Jonathan Buzzard <jonathan@buzzard.org.uk>");
-MODULE_DESCRIPTION("Toshiba laptop SMM driver");
-MODULE_SUPPORTED_DEVICE("toshiba");
+module_init(toshiba_init);
+module_exit(toshiba_exit);
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c
index 8ce508b29865..049d128ae7f0 100644
--- a/drivers/char/tpm/tpm.c
+++ b/drivers/char/tpm/tpm.c
@@ -19,7 +19,7 @@
*
* Note, the TPM chip is not interrupt driven (only polling)
* and can have very long timeouts (minutes!). Hence the unusual
- * calls to schedule_timeout.
+ * calls to msleep.
*
*/
@@ -28,19 +28,16 @@
#include <linux/spinlock.h>
#include "tpm.h"
-#define TPM_MINOR 224 /* officially assigned */
-
-#define TPM_BUFSIZE 2048
-
-/* PCI configuration addresses */
-#define PCI_GEN_PMCON_1 0xA0
-#define PCI_GEN1_DEC 0xE4
-#define PCI_LPC_EN 0xE6
-#define PCI_GEN2_DEC 0xEC
+enum tpm_const {
+ TPM_MINOR = 224, /* officially assigned */
+ TPM_BUFSIZE = 2048,
+ TPM_NUM_DEVICES = 256,
+ TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int))
+};
static LIST_HEAD(tpm_chip_list);
static DEFINE_SPINLOCK(driver_lock);
-static int dev_mask[32];
+static int dev_mask[TPM_NUM_MASK_ENTRIES];
static void user_reader_timeout(unsigned long ptr)
{
@@ -52,92 +49,17 @@ static void user_reader_timeout(unsigned long ptr)
up(&chip->buffer_mutex);
}
-void tpm_time_expired(unsigned long ptr)
-{
- int *exp = (int *) ptr;
- *exp = 1;
-}
-
-EXPORT_SYMBOL_GPL(tpm_time_expired);
-
-/*
- * Initialize the LPC bus and enable the TPM ports
- */
-int tpm_lpc_bus_init(struct pci_dev *pci_dev, u16 base)
-{
- u32 lpcenable, tmp;
- int is_lpcm = 0;
-
- switch (pci_dev->vendor) {
- case PCI_VENDOR_ID_INTEL:
- switch (pci_dev->device) {
- case PCI_DEVICE_ID_INTEL_82801CA_12:
- case PCI_DEVICE_ID_INTEL_82801DB_12:
- is_lpcm = 1;
- break;
- }
- /* init ICH (enable LPC) */
- pci_read_config_dword(pci_dev, PCI_GEN1_DEC, &lpcenable);
- lpcenable |= 0x20000000;
- pci_write_config_dword(pci_dev, PCI_GEN1_DEC, lpcenable);
-
- if (is_lpcm) {
- pci_read_config_dword(pci_dev, PCI_GEN1_DEC,
- &lpcenable);
- if ((lpcenable & 0x20000000) == 0) {
- dev_err(&pci_dev->dev,
- "cannot enable LPC\n");
- return -ENODEV;
- }
- }
-
- /* initialize TPM registers */
- pci_read_config_dword(pci_dev, PCI_GEN2_DEC, &tmp);
-
- if (!is_lpcm)
- tmp = (tmp & 0xFFFF0000) | (base & 0xFFF0);
- else
- tmp =
- (tmp & 0xFFFF0000) | (base & 0xFFF0) |
- 0x00000001;
-
- pci_write_config_dword(pci_dev, PCI_GEN2_DEC, tmp);
-
- if (is_lpcm) {
- pci_read_config_dword(pci_dev, PCI_GEN_PMCON_1,
- &tmp);
- tmp |= 0x00000004; /* enable CLKRUN */
- pci_write_config_dword(pci_dev, PCI_GEN_PMCON_1,
- tmp);
- }
- tpm_write_index(0x0D, 0x55); /* unlock 4F */
- tpm_write_index(0x0A, 0x00); /* int disable */
- tpm_write_index(0x08, base); /* base addr lo */
- tpm_write_index(0x09, (base & 0xFF00) >> 8); /* base addr hi */
- tpm_write_index(0x0D, 0xAA); /* lock 4F */
- break;
- case PCI_VENDOR_ID_AMD:
- /* nothing yet */
- break;
- }
-
- return 0;
-}
-
-EXPORT_SYMBOL_GPL(tpm_lpc_bus_init);
-
/*
* Internal kernel interface to transmit TPM commands
*/
static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
size_t bufsiz)
{
- ssize_t len;
+ ssize_t rc;
u32 count;
- __be32 *native_size;
+ unsigned long stop;
- native_size = (__force __be32 *) (buf + 2);
- count = be32_to_cpu(*native_size);
+ count = be32_to_cpu(*((__be32 *) (buf + 2)));
if (count == 0)
return -ENODATA;
@@ -149,53 +71,49 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
down(&chip->tpm_mutex);
- if ((len = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
+ if ((rc = chip->vendor->send(chip, (u8 *) buf, count)) < 0) {
dev_err(&chip->pci_dev->dev,
- "tpm_transmit: tpm_send: error %zd\n", len);
- return len;
+ "tpm_transmit: tpm_send: error %zd\n", rc);
+ goto out;
}
- down(&chip->timer_manipulation_mutex);
- chip->time_expired = 0;
- init_timer(&chip->device_timer);
- chip->device_timer.function = tpm_time_expired;
- chip->device_timer.expires = jiffies + 2 * 60 * HZ;
- chip->device_timer.data = (unsigned long) &chip->time_expired;
- add_timer(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
-
+ stop = jiffies + 2 * 60 * HZ;
do {
u8 status = inb(chip->vendor->base + 1);
if ((status & chip->vendor->req_complete_mask) ==
chip->vendor->req_complete_val) {
- down(&chip->timer_manipulation_mutex);
- del_singleshot_timer_sync(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
goto out_recv;
}
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+
+ if ((status == chip->vendor->req_canceled)) {
+ dev_err(&chip->pci_dev->dev, "Operation Canceled\n");
+ rc = -ECANCELED;
+ goto out;
+ }
+
+ msleep(TPM_TIMEOUT); /* CHECK */
rmb();
- } while (!chip->time_expired);
+ } while (time_before(jiffies, stop));
chip->vendor->cancel(chip);
- dev_err(&chip->pci_dev->dev, "Time expired\n");
- up(&chip->tpm_mutex);
- return -EIO;
+ dev_err(&chip->pci_dev->dev, "Operation Timed out\n");
+ rc = -ETIME;
+ goto out;
out_recv:
- len = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
- if (len < 0)
+ rc = chip->vendor->recv(chip, (u8 *) buf, bufsiz);
+ if (rc < 0)
dev_err(&chip->pci_dev->dev,
- "tpm_transmit: tpm_recv: error %zd\n", len);
+ "tpm_transmit: tpm_recv: error %zd\n", rc);
+out:
up(&chip->tpm_mutex);
- return len;
+ return rc;
}
#define TPM_DIGEST_SIZE 20
#define CAP_PCR_RESULT_SIZE 18
-static u8 cap_pcr[] = {
+static const u8 cap_pcr[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -205,75 +123,94 @@ static u8 cap_pcr[] = {
};
#define READ_PCR_RESULT_SIZE 30
-static u8 pcrread[] = {
+static const u8 pcrread[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 14, /* length */
0, 0, 0, 21, /* TPM_ORD_PcrRead */
0, 0, 0, 0 /* PCR index */
};
-static ssize_t show_pcrs(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pcrs(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
u8 data[READ_PCR_RESULT_SIZE];
ssize_t len;
- int i, j, index, num_pcrs;
+ int i, j, num_pcrs;
+ __be32 index;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
memcpy(data, cap_pcr, sizeof(cap_pcr));
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < CAP_PCR_RESULT_SIZE)
- return len;
+ < CAP_PCR_RESULT_SIZE) {
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+ "attempting to determine the number of PCRS\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ return 0;
+ }
- num_pcrs = be32_to_cpu(*((__force __be32 *) (data + 14)));
+ num_pcrs = be32_to_cpu(*((__be32 *) (data + 14)));
for (i = 0; i < num_pcrs; i++) {
memcpy(data, pcrread, sizeof(pcrread));
index = cpu_to_be32(i);
memcpy(data + 10, &index, 4);
if ((len = tpm_transmit(chip, data, sizeof(data)))
- < READ_PCR_RESULT_SIZE)
- return len;
+ < READ_PCR_RESULT_SIZE){
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred"
+ " attempting to read PCR %d of %d\n",
+ be32_to_cpu(*((__be32 *) (data + 6))), i, num_pcrs);
+ goto out;
+ }
str += sprintf(str, "PCR-%02d: ", i);
for (j = 0; j < TPM_DIGEST_SIZE; j++)
str += sprintf(str, "%02X ", *(data + 10 + j));
str += sprintf(str, "\n");
}
+out:
return str - buf;
}
-
-static DEVICE_ATTR(pcrs, S_IRUGO, show_pcrs, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pcrs);
#define READ_PUBEK_RESULT_SIZE 314
-static u8 readpubek[] = {
+static const u8 readpubek[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 30, /* length */
0, 0, 0, 124, /* TPM_ORD_ReadPubek */
};
-static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_pubek(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- u8 data[READ_PUBEK_RESULT_SIZE];
+ u8 *data;
ssize_t len;
- __be32 *native_val;
- int i;
+ int i, rc;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
+ data = kmalloc(READ_PUBEK_RESULT_SIZE, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
memcpy(data, readpubek, sizeof(readpubek));
memset(data + sizeof(readpubek), 0, 20); /* zero nonce */
- if ((len = tpm_transmit(chip, data, sizeof(data))) <
- READ_PUBEK_RESULT_SIZE)
- return len;
+ if ((len = tpm_transmit(chip, data, READ_PUBEK_RESULT_SIZE)) <
+ READ_PUBEK_RESULT_SIZE) {
+ dev_dbg(&chip->pci_dev->dev, "A TPM error (%d) occurred "
+ "attempting to read the PUBEK\n",
+ be32_to_cpu(*((__be32 *) (data + 6))));
+ rc = 0;
+ goto out;
+ }
/*
ignore header 10 bytes
@@ -286,8 +223,6 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
ignore checksum 20 bytes
*/
- native_val = (__force __be32 *) (data + 34);
-
str +=
sprintf(str,
"Algorithm: %02X %02X %02X %02X\nEncscheme: %02X %02X\n"
@@ -298,21 +233,23 @@ static ssize_t show_pubek(struct device *dev, struct device_attribute *attr, cha
data[15], data[16], data[17], data[22], data[23],
data[24], data[25], data[26], data[27], data[28],
data[29], data[30], data[31], data[32], data[33],
- be32_to_cpu(*native_val)
- );
+ be32_to_cpu(*((__be32 *) (data + 34))));
for (i = 0; i < 256; i++) {
- str += sprintf(str, "%02X ", data[i + 39]);
+ str += sprintf(str, "%02X ", data[i + 38]);
if ((i + 1) % 16 == 0)
str += sprintf(str, "\n");
}
- return str - buf;
+ rc = str - buf;
+out:
+ kfree(data);
+ return rc;
}
-static DEVICE_ATTR(pubek, S_IRUGO, show_pubek, NULL);
+EXPORT_SYMBOL_GPL(tpm_show_pubek);
#define CAP_VER_RESULT_SIZE 18
-static u8 cap_version[] = {
+static const u8 cap_version[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 18, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -321,7 +258,7 @@ static u8 cap_version[] = {
};
#define CAP_MANUFACTURER_RESULT_SIZE 18
-static u8 cap_manufacturer[] = {
+static const u8 cap_manufacturer[] = {
0, 193, /* TPM_TAG_RQU_COMMAND */
0, 0, 0, 22, /* length */
0, 0, 0, 101, /* TPM_ORD_GetCapability */
@@ -330,14 +267,15 @@ static u8 cap_manufacturer[] = {
0, 0, 1, 3
};
-static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char *buf)
+ssize_t tpm_show_caps(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- u8 data[READ_PUBEK_RESULT_SIZE];
+ u8 data[sizeof(cap_manufacturer)];
ssize_t len;
char *str = buf;
struct tpm_chip *chip =
- pci_get_drvdata(container_of(dev, struct pci_dev, dev));
+ pci_get_drvdata(to_pci_dev(dev));
if (chip == NULL)
return -ENODEV;
@@ -348,7 +286,7 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
return len;
str += sprintf(str, "Manufacturer: 0x%x\n",
- be32_to_cpu(*(data + 14)));
+ be32_to_cpu(*((__be32 *) (data + 14))));
memcpy(data, cap_version, sizeof(cap_version));
@@ -363,8 +301,20 @@ static ssize_t show_caps(struct device *dev, struct device_attribute *attr, char
return str - buf;
}
+EXPORT_SYMBOL_GPL(tpm_show_caps);
+
+ssize_t tpm_store_cancel(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+ if (chip == NULL)
+ return 0;
+
+ chip->vendor->cancel(chip);
+ return count;
+}
+EXPORT_SYMBOL_GPL(tpm_store_cancel);
-static DEVICE_ATTR(caps, S_IRUGO, show_caps, NULL);
/*
* Device file system interface to the TPM
@@ -422,24 +372,15 @@ EXPORT_SYMBOL_GPL(tpm_open);
int tpm_release(struct inode *inode, struct file *file)
{
struct tpm_chip *chip = file->private_data;
-
- file->private_data = NULL;
spin_lock(&driver_lock);
+ file->private_data = NULL;
chip->num_opens--;
- spin_unlock(&driver_lock);
-
- down(&chip->timer_manipulation_mutex);
- if (timer_pending(&chip->user_read_timer))
- del_singleshot_timer_sync(&chip->user_read_timer);
- else if (timer_pending(&chip->device_timer))
- del_singleshot_timer_sync(&chip->device_timer);
- up(&chip->timer_manipulation_mutex);
-
- kfree(chip->data_buffer);
+ del_singleshot_timer_sync(&chip->user_read_timer);
atomic_set(&chip->data_pending, 0);
-
pci_dev_put(chip->pci_dev);
+ kfree(chip->data_buffer);
+ spin_unlock(&driver_lock);
return 0;
}
@@ -453,10 +394,8 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
/* cannot perform a write until the read has cleared
either via tpm_read or a user_read_timer timeout */
- while (atomic_read(&chip->data_pending) != 0) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
- }
+ while (atomic_read(&chip->data_pending) != 0)
+ msleep(TPM_TIMEOUT);
down(&chip->buffer_mutex);
@@ -476,13 +415,7 @@ ssize_t tpm_write(struct file * file, const char __user * buf,
up(&chip->buffer_mutex);
/* Set a timeout by which the reader must come claim the result */
- down(&chip->timer_manipulation_mutex);
- init_timer(&chip->user_read_timer);
- chip->user_read_timer.function = user_reader_timeout;
- chip->user_read_timer.data = (unsigned long) chip;
- chip->user_read_timer.expires = jiffies + (60 * HZ);
- add_timer(&chip->user_read_timer);
- up(&chip->timer_manipulation_mutex);
+ mod_timer(&chip->user_read_timer, jiffies + (60 * HZ));
return in_size;
}
@@ -493,29 +426,19 @@ ssize_t tpm_read(struct file * file, char __user * buf,
size_t size, loff_t * off)
{
struct tpm_chip *chip = file->private_data;
- int ret_size = -ENODATA;
+ int ret_size;
- if (atomic_read(&chip->data_pending) != 0) { /* Result available */
- down(&chip->timer_manipulation_mutex);
- del_singleshot_timer_sync(&chip->user_read_timer);
- up(&chip->timer_manipulation_mutex);
+ del_singleshot_timer_sync(&chip->user_read_timer);
+ ret_size = atomic_read(&chip->data_pending);
+ atomic_set(&chip->data_pending, 0);
+ if (ret_size > 0) { /* relay data */
+ if (size < ret_size)
+ ret_size = size;
down(&chip->buffer_mutex);
-
- ret_size = atomic_read(&chip->data_pending);
- atomic_set(&chip->data_pending, 0);
-
- if (ret_size == 0) /* timeout just occurred */
- ret_size = -ETIME;
- else if (ret_size > 0) { /* relay data */
- if (size < ret_size)
- ret_size = size;
-
- if (copy_to_user((void __user *) buf,
- chip->data_buffer, ret_size)) {
- ret_size = -EFAULT;
- }
- }
+ if (copy_to_user
+ ((void __user *) buf, chip->data_buffer, ret_size))
+ ret_size = -EFAULT;
up(&chip->buffer_mutex);
}
@@ -541,14 +464,13 @@ void __devexit tpm_remove(struct pci_dev *pci_dev)
pci_set_drvdata(pci_dev, NULL);
misc_deregister(&chip->vendor->miscdev);
+ kfree(chip->vendor->miscdev.name);
- device_remove_file(&pci_dev->dev, &dev_attr_pubek);
- device_remove_file(&pci_dev->dev, &dev_attr_pcrs);
- device_remove_file(&pci_dev->dev, &dev_attr_caps);
+ sysfs_remove_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
pci_disable_device(pci_dev);
- dev_mask[chip->dev_num / 32] &= !(1 << (chip->dev_num % 32));
+ dev_mask[chip->dev_num / TPM_NUM_MASK_ENTRIES ] &= !(1 << (chip->dev_num % TPM_NUM_MASK_ENTRIES));
kfree(chip);
@@ -590,10 +512,6 @@ int tpm_pm_resume(struct pci_dev *pci_dev)
if (chip == NULL)
return -ENODEV;
- spin_lock(&driver_lock);
- tpm_lpc_bus_init(pci_dev, chip->vendor->base);
- spin_unlock(&driver_lock);
-
return 0;
}
@@ -609,7 +527,9 @@ EXPORT_SYMBOL_GPL(tpm_pm_resume);
int tpm_register_hardware(struct pci_dev *pci_dev,
struct tpm_vendor_specific *entry)
{
- char devname[7];
+#define DEVNAME_SIZE 7
+
+ char *devname;
struct tpm_chip *chip;
int i, j;
@@ -622,17 +542,21 @@ int tpm_register_hardware(struct pci_dev *pci_dev,
init_MUTEX(&chip->buffer_mutex);
init_MUTEX(&chip->tpm_mutex);
- init_MUTEX(&chip->timer_manipulation_mutex);
INIT_LIST_HEAD(&chip->list);
+ init_timer(&chip->user_read_timer);
+ chip->user_read_timer.function = user_reader_timeout;
+ chip->user_read_timer.data = (unsigned long) chip;
+
chip->vendor = entry;
chip->dev_num = -1;
- for (i = 0; i < 32; i++)
- for (j = 0; j < 8; j++)
+ for (i = 0; i < TPM_NUM_MASK_ENTRIES; i++)
+ for (j = 0; j < 8 * sizeof(int); j++)
if ((dev_mask[i] & (1 << j)) == 0) {
- chip->dev_num = i * 32 + j;
+ chip->dev_num =
+ i * TPM_NUM_MASK_ENTRIES + j;
dev_mask[i] |= 1 << j;
goto dev_num_search_complete;
}
@@ -648,7 +572,8 @@ dev_num_search_complete:
else
chip->vendor->miscdev.minor = MISC_DYNAMIC_MINOR;
- snprintf(devname, sizeof(devname), "%s%d", "tpm", chip->dev_num);
+ devname = kmalloc(DEVNAME_SIZE, GFP_KERNEL);
+ scnprintf(devname, DEVNAME_SIZE, "%s%d", "tpm", chip->dev_num);
chip->vendor->miscdev.name = devname;
chip->vendor->miscdev.dev = &(pci_dev->dev);
@@ -665,31 +590,20 @@ dev_num_search_complete:
return -ENODEV;
}
+ spin_lock(&driver_lock);
+
pci_set_drvdata(pci_dev, chip);
list_add(&chip->list, &tpm_chip_list);
- device_create_file(&pci_dev->dev, &dev_attr_pubek);
- device_create_file(&pci_dev->dev, &dev_attr_pcrs);
- device_create_file(&pci_dev->dev, &dev_attr_caps);
-
- return 0;
-}
+ spin_unlock(&driver_lock);
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
+ sysfs_create_group(&pci_dev->dev.kobj, chip->vendor->attr_group);
-static int __init init_tpm(void)
-{
return 0;
}
-static void __exit cleanup_tpm(void)
-{
-
-}
-
-module_init(init_tpm);
-module_exit(cleanup_tpm);
+EXPORT_SYMBOL_GPL(tpm_register_hardware);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index de0c796fce80..373b41f6b460 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -25,23 +25,38 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
-#define TPM_TIMEOUT msecs_to_jiffies(5)
+enum tpm_timeout {
+ TPM_TIMEOUT = 5, /* msecs */
+};
/* TPM addresses */
-#define TPM_ADDR 0x4E
-#define TPM_DATA 0x4F
+enum tpm_addr {
+ TPM_SUPERIO_ADDR = 0x2E,
+ TPM_ADDR = 0x4E,
+};
+
+extern ssize_t tpm_show_pubek(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_pcrs(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_show_caps(struct device *, struct device_attribute *attr,
+ char *);
+extern ssize_t tpm_store_cancel(struct device *, struct device_attribute *attr,
+ const char *, size_t);
struct tpm_chip;
struct tpm_vendor_specific {
u8 req_complete_mask;
u8 req_complete_val;
+ u8 req_canceled;
u16 base; /* TPM base address */
int (*recv) (struct tpm_chip *, u8 *, size_t);
int (*send) (struct tpm_chip *, u8 *, size_t);
void (*cancel) (struct tpm_chip *);
struct miscdevice miscdev;
+ struct attribute_group *attr_group;
};
struct tpm_chip {
@@ -58,29 +73,24 @@ struct tpm_chip {
struct timer_list user_read_timer; /* user needs to claim result */
struct semaphore tpm_mutex; /* tpm is processing */
- struct timer_list device_timer; /* tpm is processing */
- struct semaphore timer_manipulation_mutex;
struct tpm_vendor_specific *vendor;
struct list_head list;
};
-static inline int tpm_read_index(int index)
+static inline int tpm_read_index(int base, int index)
{
- outb(index, TPM_ADDR);
- return inb(TPM_DATA) & 0xFF;
+ outb(index, base);
+ return inb(base+1) & 0xFF;
}
-static inline void tpm_write_index(int index, int value)
+static inline void tpm_write_index(int base, int index, int value)
{
- outb(index, TPM_ADDR);
- outb(value & 0xFF, TPM_DATA);
+ outb(index, base);
+ outb(value & 0xFF, base+1);
}
-extern void tpm_time_expired(unsigned long);
-extern int tpm_lpc_bus_init(struct pci_dev *, u16);
-
extern int tpm_register_hardware(struct pci_dev *,
struct tpm_vendor_specific *);
extern int tpm_open(struct inode *, struct file *);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index f9333e729b62..cc2cc77fd174 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -22,17 +22,23 @@
#include "tpm.h"
/* Atmel definitions */
-#define TPM_ATML_BASE 0x400
+enum tpm_atmel_addr {
+ TPM_ATMEL_BASE_ADDR_LO = 0x08,
+ TPM_ATMEL_BASE_ADDR_HI = 0x09
+};
/* write status bits */
-#define ATML_STATUS_ABORT 0x01
-#define ATML_STATUS_LASTBYTE 0x04
-
+enum tpm_atmel_write_status {
+ ATML_STATUS_ABORT = 0x01,
+ ATML_STATUS_LASTBYTE = 0x04
+};
/* read status bits */
-#define ATML_STATUS_BUSY 0x01
-#define ATML_STATUS_DATA_AVAIL 0x02
-#define ATML_STATUS_REWRITE 0x04
-
+enum tpm_atmel_read_status {
+ ATML_STATUS_BUSY = 0x01,
+ ATML_STATUS_DATA_AVAIL = 0x02,
+ ATML_STATUS_REWRITE = 0x04,
+ ATML_STATUS_READY = 0x08
+};
static int tpm_atml_recv(struct tpm_chip *chip, u8 * buf, size_t count)
{
@@ -121,13 +127,29 @@ static struct file_operations atmel_ops = {
.release = tpm_release,
};
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR |S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute* atmel_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group atmel_attr_grp = { .attrs = atmel_attrs };
+
static struct tpm_vendor_specific tpm_atmel = {
.recv = tpm_atml_recv,
.send = tpm_atml_send,
.cancel = tpm_atml_cancel,
.req_complete_mask = ATML_STATUS_BUSY | ATML_STATUS_DATA_AVAIL,
.req_complete_val = ATML_STATUS_DATA_AVAIL,
- .base = TPM_ATML_BASE,
+ .req_canceled = ATML_STATUS_READY,
+ .attr_group = &atmel_attr_grp,
.miscdev = { .fops = &atmel_ops, },
};
@@ -136,27 +158,29 @@ static int __devinit tpm_atml_init(struct pci_dev *pci_dev,
{
u8 version[4];
int rc = 0;
+ int lo, hi;
if (pci_enable_device(pci_dev))
return -EIO;
- if (tpm_lpc_bus_init(pci_dev, TPM_ATML_BASE)) {
- rc = -ENODEV;
- goto out_err;
- }
+ lo = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_LO);
+ hi = tpm_read_index(TPM_ADDR, TPM_ATMEL_BASE_ADDR_HI);
+
+ tpm_atmel.base = (hi<<8)|lo;
+ dev_dbg( &pci_dev->dev, "Operating with base: 0x%x\n", tpm_atmel.base);
/* verify that it is an Atmel part */
- if (tpm_read_index(4) != 'A' || tpm_read_index(5) != 'T'
- || tpm_read_index(6) != 'M' || tpm_read_index(7) != 'L') {
+ if (tpm_read_index(TPM_ADDR, 4) != 'A' || tpm_read_index(TPM_ADDR, 5) != 'T'
+ || tpm_read_index(TPM_ADDR, 6) != 'M' || tpm_read_index(TPM_ADDR, 7) != 'L') {
rc = -ENODEV;
goto out_err;
}
/* query chip for its version number */
- if ((version[0] = tpm_read_index(0x00)) != 0xFF) {
- version[1] = tpm_read_index(0x01);
- version[2] = tpm_read_index(0x02);
- version[3] = tpm_read_index(0x03);
+ if ((version[0] = tpm_read_index(TPM_ADDR, 0x00)) != 0xFF) {
+ version[1] = tpm_read_index(TPM_ADDR, 0x01);
+ version[2] = tpm_read_index(TPM_ADDR, 0x02);
+ version[3] = tpm_read_index(TPM_ADDR, 0x03);
} else {
dev_info(&pci_dev->dev, "version query failed\n");
rc = -ENODEV;
@@ -183,6 +207,7 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
+ {PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_CSB6LPC)},
{0,}
};
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 9cce833a0923..b4127348c063 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -22,43 +22,52 @@
#include "tpm.h"
/* National definitions */
-#define TPM_NSC_BASE 0x360
-#define TPM_NSC_IRQ 0x07
+enum tpm_nsc_addr{
+ TPM_NSC_IRQ = 0x07,
+ TPM_NSC_BASE0_HI = 0x60,
+ TPM_NSC_BASE0_LO = 0x61,
+ TPM_NSC_BASE1_HI = 0x62,
+ TPM_NSC_BASE1_LO = 0x63
+};
-#define NSC_LDN_INDEX 0x07
-#define NSC_SID_INDEX 0x20
-#define NSC_LDC_INDEX 0x30
-#define NSC_DIO_INDEX 0x60
-#define NSC_CIO_INDEX 0x62
-#define NSC_IRQ_INDEX 0x70
-#define NSC_ITS_INDEX 0x71
+enum tpm_nsc_index {
+ NSC_LDN_INDEX = 0x07,
+ NSC_SID_INDEX = 0x20,
+ NSC_LDC_INDEX = 0x30,
+ NSC_DIO_INDEX = 0x60,
+ NSC_CIO_INDEX = 0x62,
+ NSC_IRQ_INDEX = 0x70,
+ NSC_ITS_INDEX = 0x71
+};
-#define NSC_STATUS 0x01
-#define NSC_COMMAND 0x01
-#define NSC_DATA 0x00
+enum tpm_nsc_status_loc {
+ NSC_STATUS = 0x01,
+ NSC_COMMAND = 0x01,
+ NSC_DATA = 0x00
+};
/* status bits */
-#define NSC_STATUS_OBF 0x01 /* output buffer full */
-#define NSC_STATUS_IBF 0x02 /* input buffer full */
-#define NSC_STATUS_F0 0x04 /* F0 */
-#define NSC_STATUS_A2 0x08 /* A2 */
-#define NSC_STATUS_RDY 0x10 /* ready to receive command */
-#define NSC_STATUS_IBR 0x20 /* ready to receive data */
+enum tpm_nsc_status {
+ NSC_STATUS_OBF = 0x01, /* output buffer full */
+ NSC_STATUS_IBF = 0x02, /* input buffer full */
+ NSC_STATUS_F0 = 0x04, /* F0 */
+ NSC_STATUS_A2 = 0x08, /* A2 */
+ NSC_STATUS_RDY = 0x10, /* ready to receive command */
+ NSC_STATUS_IBR = 0x20 /* ready to receive data */
+};
/* command bits */
-#define NSC_COMMAND_NORMAL 0x01 /* normal mode */
-#define NSC_COMMAND_EOC 0x03
-#define NSC_COMMAND_CANCEL 0x22
-
+enum tpm_nsc_cmd_mode {
+ NSC_COMMAND_NORMAL = 0x01, /* normal mode */
+ NSC_COMMAND_EOC = 0x03,
+ NSC_COMMAND_CANCEL = 0x22
+};
/*
* Wait for a certain status to appear
*/
static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
{
- int expired = 0;
- struct timer_list status_timer =
- TIMER_INITIALIZER(tpm_time_expired, jiffies + 10 * HZ,
- (unsigned long) &expired);
+ unsigned long stop;
/* status immediately available check */
*data = inb(chip->vendor->base + NSC_STATUS);
@@ -66,17 +75,14 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
return 0;
/* wait for status */
- add_timer(&status_timer);
+ stop = jiffies + 10 * HZ;
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+ msleep(TPM_TIMEOUT);
*data = inb(chip->vendor->base + 1);
- if ((*data & mask) == val) {
- del_singleshot_timer_sync(&status_timer);
+ if ((*data & mask) == val)
return 0;
- }
}
- while (!expired);
+ while (time_before(jiffies, stop));
return -EBUSY;
}
@@ -84,10 +90,7 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, u8 val, u8 * data)
static int nsc_wait_for_ready(struct tpm_chip *chip)
{
int status;
- int expired = 0;
- struct timer_list status_timer =
- TIMER_INITIALIZER(tpm_time_expired, jiffies + 100,
- (unsigned long) &expired);
+ unsigned long stop;
/* status immediately available check */
status = inb(chip->vendor->base + NSC_STATUS);
@@ -97,19 +100,16 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
return 0;
/* wait for status */
- add_timer(&status_timer);
+ stop = jiffies + 100;
do {
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(TPM_TIMEOUT);
+ msleep(TPM_TIMEOUT);
status = inb(chip->vendor->base + NSC_STATUS);
if (status & NSC_STATUS_OBF)
status = inb(chip->vendor->base + NSC_DATA);
- if (status & NSC_STATUS_RDY) {
- del_singleshot_timer_sync(&status_timer);
+ if (status & NSC_STATUS_RDY)
return 0;
- }
}
- while (!expired);
+ while (time_before(jiffies, stop));
dev_info(&chip->pci_dev->dev, "wait for ready failed\n");
return -EBUSY;
@@ -150,7 +150,8 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
*p = inb(chip->vendor->base + NSC_DATA);
}
- if ((data & NSC_STATUS_F0) == 0) {
+ if ((data & NSC_STATUS_F0) == 0 &&
+ (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
dev_err(&chip->pci_dev->dev, "F0 not set\n");
return -EIO;
}
@@ -228,100 +229,95 @@ static struct file_operations nsc_ops = {
.release = tpm_release,
};
+static DEVICE_ATTR(pubek, S_IRUGO, tpm_show_pubek, NULL);
+static DEVICE_ATTR(pcrs, S_IRUGO, tpm_show_pcrs, NULL);
+static DEVICE_ATTR(caps, S_IRUGO, tpm_show_caps, NULL);
+static DEVICE_ATTR(cancel, S_IWUSR|S_IWGRP, NULL, tpm_store_cancel);
+
+static struct attribute * nsc_attrs[] = {
+ &dev_attr_pubek.attr,
+ &dev_attr_pcrs.attr,
+ &dev_attr_caps.attr,
+ &dev_attr_cancel.attr,
+ 0,
+};
+
+static struct attribute_group nsc_attr_grp = { .attrs = nsc_attrs };
+
static struct tpm_vendor_specific tpm_nsc = {
.recv = tpm_nsc_recv,
.send = tpm_nsc_send,
.cancel = tpm_nsc_cancel,
.req_complete_mask = NSC_STATUS_OBF,
.req_complete_val = NSC_STATUS_OBF,
- .base = TPM_NSC_BASE,
+ .req_canceled = NSC_STATUS_RDY,
+ .attr_group = &nsc_attr_grp,
.miscdev = { .fops = &nsc_ops, },
-
};
static int __devinit tpm_nsc_init(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
int rc = 0;
+ int lo, hi;
+ int nscAddrBase = TPM_ADDR;
+
if (pci_enable_device(pci_dev))
return -EIO;
- if (tpm_lpc_bus_init(pci_dev, TPM_NSC_BASE)) {
- rc = -ENODEV;
- goto out_err;
- }
+ /* select PM channel 1 */
+ tpm_write_index(nscAddrBase,NSC_LDN_INDEX, 0x12);
/* verify that it is a National part (SID) */
- if (tpm_read_index(NSC_SID_INDEX) != 0xEF) {
- rc = -ENODEV;
- goto out_err;
+ if (tpm_read_index(TPM_ADDR, NSC_SID_INDEX) != 0xEF) {
+ nscAddrBase = (tpm_read_index(TPM_SUPERIO_ADDR, 0x2C)<<8)|
+ (tpm_read_index(TPM_SUPERIO_ADDR, 0x2B)&0xFE);
+ if (tpm_read_index(nscAddrBase, NSC_SID_INDEX) != 0xF6) {
+ rc = -ENODEV;
+ goto out_err;
+ }
}
+ hi = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_HI);
+ lo = tpm_read_index(nscAddrBase, TPM_NSC_BASE0_LO);
+ tpm_nsc.base = (hi<<8) | lo;
+
dev_dbg(&pci_dev->dev, "NSC TPM detected\n");
dev_dbg(&pci_dev->dev,
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
- tpm_read_index(0x07), tpm_read_index(0x20),
- tpm_read_index(0x27));
+ tpm_read_index(nscAddrBase,0x07), tpm_read_index(nscAddrBase,0x20),
+ tpm_read_index(nscAddrBase,0x27));
dev_dbg(&pci_dev->dev,
"NSC SIOCF1 0x%x SIOCF5 0x%x SIOCF6 0x%x SIOCF8 0x%x\n",
- tpm_read_index(0x21), tpm_read_index(0x25),
- tpm_read_index(0x26), tpm_read_index(0x28));
+ tpm_read_index(nscAddrBase,0x21), tpm_read_index(nscAddrBase,0x25),
+ tpm_read_index(nscAddrBase,0x26), tpm_read_index(nscAddrBase,0x28));
dev_dbg(&pci_dev->dev, "NSC IO Base0 0x%x\n",
- (tpm_read_index(0x60) << 8) | tpm_read_index(0x61));
+ (tpm_read_index(nscAddrBase,0x60) << 8) | tpm_read_index(nscAddrBase,0x61));
dev_dbg(&pci_dev->dev, "NSC IO Base1 0x%x\n",
- (tpm_read_index(0x62) << 8) | tpm_read_index(0x63));
+ (tpm_read_index(nscAddrBase,0x62) << 8) | tpm_read_index(nscAddrBase,0x63));
dev_dbg(&pci_dev->dev, "NSC Interrupt number and wakeup 0x%x\n",
- tpm_read_index(0x70));
+ tpm_read_index(nscAddrBase,0x70));
dev_dbg(&pci_dev->dev, "NSC IRQ type select 0x%x\n",
- tpm_read_index(0x71));
+ tpm_read_index(nscAddrBase,0x71));
dev_dbg(&pci_dev->dev,
"NSC DMA channel select0 0x%x, select1 0x%x\n",
- tpm_read_index(0x74), tpm_read_index(0x75));
+ tpm_read_index(nscAddrBase,0x74), tpm_read_index(nscAddrBase,0x75));
dev_dbg(&pci_dev->dev,
"NSC Config "
"0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
- tpm_read_index(0xF0), tpm_read_index(0xF1),
- tpm_read_index(0xF2), tpm_read_index(0xF3),
- tpm_read_index(0xF4), tpm_read_index(0xF5),
- tpm_read_index(0xF6), tpm_read_index(0xF7),
- tpm_read_index(0xF8), tpm_read_index(0xF9));
+ tpm_read_index(nscAddrBase,0xF0), tpm_read_index(nscAddrBase,0xF1),
+ tpm_read_index(nscAddrBase,0xF2), tpm_read_index(nscAddrBase,0xF3),
+ tpm_read_index(nscAddrBase,0xF4), tpm_read_index(nscAddrBase,0xF5),
+ tpm_read_index(nscAddrBase,0xF6), tpm_read_index(nscAddrBase,0xF7),
+ tpm_read_index(nscAddrBase,0xF8), tpm_read_index(nscAddrBase,0xF9));
dev_info(&pci_dev->dev,
- "NSC PC21100 TPM revision %d\n",
- tpm_read_index(0x27) & 0x1F);
-
- if (tpm_read_index(NSC_LDC_INDEX) == 0)
- dev_info(&pci_dev->dev, ": NSC TPM not active\n");
-
- /* select PM channel 1 */
- tpm_write_index(NSC_LDN_INDEX, 0x12);
- tpm_read_index(NSC_LDN_INDEX);
-
- /* disable the DPM module */
- tpm_write_index(NSC_LDC_INDEX, 0);
- tpm_read_index(NSC_LDC_INDEX);
-
- /* set the data register base addresses */
- tpm_write_index(NSC_DIO_INDEX, TPM_NSC_BASE >> 8);
- tpm_write_index(NSC_DIO_INDEX + 1, TPM_NSC_BASE);
- tpm_read_index(NSC_DIO_INDEX);
- tpm_read_index(NSC_DIO_INDEX + 1);
-
- /* set the command register base addresses */
- tpm_write_index(NSC_CIO_INDEX, (TPM_NSC_BASE + 1) >> 8);
- tpm_write_index(NSC_CIO_INDEX + 1, (TPM_NSC_BASE + 1));
- tpm_read_index(NSC_DIO_INDEX);
- tpm_read_index(NSC_DIO_INDEX + 1);
-
- /* set the interrupt number to be used for the host interface */
- tpm_write_index(NSC_IRQ_INDEX, TPM_NSC_IRQ);
- tpm_write_index(NSC_ITS_INDEX, 0x00);
- tpm_read_index(NSC_IRQ_INDEX);
+ "NSC TPM revision %d\n",
+ tpm_read_index(nscAddrBase, 0x27) & 0x1F);
/* enable the DPM module */
- tpm_write_index(NSC_LDC_INDEX, 0x01);
- tpm_read_index(NSC_LDC_INDEX);
+ tpm_write_index(nscAddrBase, NSC_LDC_INDEX, 0x01);
if ((rc = tpm_register_hardware(pci_dev, &tpm_nsc)) < 0)
goto out_err;
@@ -339,6 +335,9 @@ static struct pci_device_id tpm_pci_tbl[] __devinitdata = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_12)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_1)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0)},
{PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_LPC)},
{0,}
};
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index cc4b43bad703..6e4be3bb2d89 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -94,6 +94,7 @@
#include <linux/idr.h>
#include <linux/wait.h>
#include <linux/bitops.h>
+#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/system.h>
@@ -2180,12 +2181,11 @@ static int tiocsetd(struct tty_struct *tty, int __user *p)
return tty_set_ldisc(tty, ldisc);
}
-static int send_break(struct tty_struct *tty, int duration)
+static int send_break(struct tty_struct *tty, unsigned int duration)
{
tty->driver->break_ctl(tty, -1);
if (!signal_pending(current)) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(duration);
+ msleep_interruptible(duration);
}
tty->driver->break_ctl(tty, 0);
if (signal_pending(current))
@@ -2366,10 +2366,10 @@ int tty_ioctl(struct inode * inode, struct file * file,
* all by anyone?
*/
if (!arg)
- return send_break(tty, HZ/4);
+ return send_break(tty, 250);
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
- return send_break(tty, arg ? arg*(HZ/10) : HZ/4);
+ return send_break(tty, arg ? arg*100 : 250);
case TIOCMGET:
return tty_tiocmget(tty, file, p);
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 58597993954f..f19cf9d7792d 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -476,11 +476,11 @@ int n_tty_ioctl(struct tty_struct * tty, struct file * file,
ld = tty_ldisc_ref(tty);
switch (arg) {
case TCIFLUSH:
- if (ld->flush_buffer)
+ if (ld && ld->flush_buffer)
ld->flush_buffer(tty);
break;
case TCIOFLUSH:
- if (ld->flush_buffer)
+ if (ld && ld->flush_buffer)
ld->flush_buffer(tty);
/* fall through */
case TCOFLUSH:
diff --git a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
index 8971484b956b..1d44f69e1fda 100644
--- a/drivers/char/vt_ioctl.c
+++ b/drivers/char/vt_ioctl.c
@@ -25,6 +25,7 @@
#include <linux/fs.h>
#include <linux/console.h>
#include <linux/signal.h>
+#include <linux/timex.h>
#include <asm/io.h>
#include <asm/uaccess.h>
@@ -386,7 +387,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
if (!perm)
return -EPERM;
if (arg)
- arg = 1193182 / arg;
+ arg = CLOCK_TICK_RATE / arg;
kd_mksound(arg, 0);
return 0;
@@ -403,7 +404,7 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
ticks = HZ * ((arg >> 16) & 0xffff) / 1000;
count = ticks ? (arg & 0xffff) : 0;
if (count)
- count = 1193182 / count;
+ count = CLOCK_TICK_RATE / count;
kd_mksound(count, ticks);
return 0;
}
diff --git a/drivers/char/watchdog/i8xx_tco.c b/drivers/char/watchdog/i8xx_tco.c
index b14d642439ed..5d07ee59679d 100644
--- a/drivers/char/watchdog/i8xx_tco.c
+++ b/drivers/char/watchdog/i8xx_tco.c
@@ -401,7 +401,7 @@ static unsigned char __init i8xx_tco_getdevice (void)
*/
while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
- if (pci_match_device(i8xx_tco_pci_tbl, dev)) {
+ if (pci_match_id(i8xx_tco_pci_tbl, dev)) {
i8xx_tco_pci = dev;
break;
}
diff --git a/drivers/char/watchdog/ixp2000_wdt.c b/drivers/char/watchdog/ixp2000_wdt.c
index 4e98c215e5b1..4b039516cc86 100644
--- a/drivers/char/watchdog/ixp2000_wdt.c
+++ b/drivers/char/watchdog/ixp2000_wdt.c
@@ -162,7 +162,7 @@ ixp2000_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
wdt_disable();
} else {
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n");
}
diff --git a/drivers/char/watchdog/ixp4xx_wdt.c b/drivers/char/watchdog/ixp4xx_wdt.c
index 82396e06c8a8..83df369113a4 100644
--- a/drivers/char/watchdog/ixp4xx_wdt.c
+++ b/drivers/char/watchdog/ixp4xx_wdt.c
@@ -156,7 +156,7 @@ ixp4xx_wdt_release(struct inode *inode, struct file *file)
if (test_bit(WDT_OK_TO_CLOSE, &wdt_status)) {
wdt_disable();
} else {
- printk(KERN_CRIT "WATCHDOG: Device closed unexpectdly - "
+ printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
"timer will not stop\n");
}
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index bf62dfe4976a..7a7859dd0d98 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -869,7 +869,7 @@ EXPORT_SYMBOL(cpufreq_get);
* cpufreq_suspend - let the low level driver prepare for suspend
*/
-static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
+static int cpufreq_suspend(struct sys_device * sysdev, pm_message_t pmsg)
{
int cpu = sysdev->id;
unsigned int ret = 0;
@@ -897,7 +897,7 @@ static int cpufreq_suspend(struct sys_device * sysdev, u32 state)
}
if (cpufreq_driver->suspend) {
- ret = cpufreq_driver->suspend(cpu_policy, state);
+ ret = cpufreq_driver->suspend(cpu_policy, pmsg);
if (ret) {
printk(KERN_ERR "cpufreq: suspend failed in ->suspend "
"step on CPU %u\n", cpu_policy->cpu);
diff --git a/drivers/crypto/padlock-aes.c b/drivers/crypto/padlock-aes.c
index ed708b4427b0..71407c578afe 100644
--- a/drivers/crypto/padlock-aes.c
+++ b/drivers/crypto/padlock-aes.c
@@ -49,6 +49,7 @@
#include <linux/errno.h>
#include <linux/crypto.h>
#include <linux/interrupt.h>
+#include <linux/kernel.h>
#include <asm/byteorder.h>
#include "padlock.h"
@@ -59,8 +60,12 @@
#define AES_EXTENDED_KEY_SIZE_B (AES_EXTENDED_KEY_SIZE * sizeof(uint32_t))
struct aes_ctx {
- uint32_t e_data[AES_EXTENDED_KEY_SIZE+4];
- uint32_t d_data[AES_EXTENDED_KEY_SIZE+4];
+ uint32_t e_data[AES_EXTENDED_KEY_SIZE];
+ uint32_t d_data[AES_EXTENDED_KEY_SIZE];
+ struct {
+ struct cword encrypt;
+ struct cword decrypt;
+ } cword;
uint32_t *E;
uint32_t *D;
int key_length;
@@ -280,10 +285,15 @@ aes_hw_extkey_available(uint8_t key_len)
return 0;
}
+static inline struct aes_ctx *aes_ctx(void *ctx)
+{
+ return (struct aes_ctx *)ALIGN((unsigned long)ctx, PADLOCK_ALIGNMENT);
+}
+
static int
aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t *flags)
{
- struct aes_ctx *ctx = ctx_arg;
+ struct aes_ctx *ctx = aes_ctx(ctx_arg);
uint32_t i, t, u, v, w;
uint32_t P[AES_EXTENDED_KEY_SIZE];
uint32_t rounds;
@@ -295,25 +305,36 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t
ctx->key_length = key_len;
+ /*
+ * If the hardware is capable of generating the extended key
+ * itself we must supply the plain key for both encryption
+ * and decryption.
+ */
ctx->E = ctx->e_data;
- ctx->D = ctx->d_data;
-
- /* Ensure 16-Bytes alignmentation of keys for VIA PadLock. */
- if ((int)(ctx->e_data) & 0x0F)
- ctx->E += 4 - (((int)(ctx->e_data) & 0x0F) / sizeof (ctx->e_data[0]));
-
- if ((int)(ctx->d_data) & 0x0F)
- ctx->D += 4 - (((int)(ctx->d_data) & 0x0F) / sizeof (ctx->d_data[0]));
+ ctx->D = ctx->e_data;
E_KEY[0] = uint32_t_in (in_key);
E_KEY[1] = uint32_t_in (in_key + 4);
E_KEY[2] = uint32_t_in (in_key + 8);
E_KEY[3] = uint32_t_in (in_key + 12);
+ /* Prepare control words. */
+ memset(&ctx->cword, 0, sizeof(ctx->cword));
+
+ ctx->cword.decrypt.encdec = 1;
+ ctx->cword.encrypt.rounds = 10 + (key_len - 16) / 4;
+ ctx->cword.decrypt.rounds = ctx->cword.encrypt.rounds;
+ ctx->cword.encrypt.ksize = (key_len - 16) / 8;
+ ctx->cword.decrypt.ksize = ctx->cword.encrypt.ksize;
+
/* Don't generate extended keys if the hardware can do it. */
if (aes_hw_extkey_available(key_len))
return 0;
+ ctx->D = ctx->d_data;
+ ctx->cword.encrypt.keygen = 1;
+ ctx->cword.decrypt.keygen = 1;
+
switch (key_len) {
case 16:
t = E_KEY[3];
@@ -369,10 +390,9 @@ aes_set_key(void *ctx_arg, const uint8_t *in_key, unsigned int key_len, uint32_t
/* ====== Encryption/decryption routines ====== */
-/* This is the real call to PadLock. */
-static inline void
-padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key,
- void *control_word, uint32_t count)
+/* These are the real call to PadLock. */
+static inline void padlock_xcrypt_ecb(const u8 *input, u8 *output, void *key,
+ void *control_word, u32 count)
{
asm volatile ("pushfl; popfl"); /* enforce key reload. */
asm volatile (".byte 0xf3,0x0f,0xa7,0xc8" /* rep xcryptecb */
@@ -380,60 +400,70 @@ padlock_xcrypt_ecb(uint8_t *input, uint8_t *output, uint8_t *key,
: "d"(control_word), "b"(key), "c"(count));
}
-static void
-aes_padlock(void *ctx_arg, uint8_t *out_arg, const uint8_t *in_arg, int encdec)
+static inline u8 *padlock_xcrypt_cbc(const u8 *input, u8 *output, void *key,
+ u8 *iv, void *control_word, u32 count)
{
- /* Don't blindly modify this structure - the items must
- fit on 16-Bytes boundaries! */
- struct padlock_xcrypt_data {
- uint8_t buf[AES_BLOCK_SIZE];
- union cword cword;
- };
-
- struct aes_ctx *ctx = ctx_arg;
- char bigbuf[sizeof(struct padlock_xcrypt_data) + 16];
- struct padlock_xcrypt_data *data;
- void *key;
-
- /* Place 'data' at the first 16-Bytes aligned address in 'bigbuf'. */
- if (((long)bigbuf) & 0x0F)
- data = (void*)(bigbuf + 16 - ((long)bigbuf & 0x0F));
- else
- data = (void*)bigbuf;
-
- /* Prepare Control word. */
- memset (data, 0, sizeof(struct padlock_xcrypt_data));
- data->cword.b.encdec = !encdec; /* in the rest of cryptoapi ENC=1/DEC=0 */
- data->cword.b.rounds = 10 + (ctx->key_length - 16) / 4;
- data->cword.b.ksize = (ctx->key_length - 16) / 8;
-
- /* Is the hardware capable to generate the extended key? */
- if (!aes_hw_extkey_available(ctx->key_length))
- data->cword.b.keygen = 1;
-
- /* ctx->E starts with a plain key - if the hardware is capable
- to generate the extended key itself we must supply
- the plain key for both Encryption and Decryption. */
- if (encdec == CRYPTO_DIR_ENCRYPT || data->cword.b.keygen == 0)
- key = ctx->E;
- else
- key = ctx->D;
-
- memcpy(data->buf, in_arg, AES_BLOCK_SIZE);
- padlock_xcrypt_ecb(data->buf, data->buf, key, &data->cword, 1);
- memcpy(out_arg, data->buf, AES_BLOCK_SIZE);
+ /* Enforce key reload. */
+ asm volatile ("pushfl; popfl");
+ /* rep xcryptcbc */
+ asm volatile (".byte 0xf3,0x0f,0xa7,0xd0"
+ : "+S" (input), "+D" (output), "+a" (iv)
+ : "d" (control_word), "b" (key), "c" (count));
+ return iv;
}
static void
aes_encrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
{
- aes_padlock(ctx_arg, out, in, CRYPTO_DIR_ENCRYPT);
+ struct aes_ctx *ctx = aes_ctx(ctx_arg);
+ padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt, 1);
}
static void
aes_decrypt(void *ctx_arg, uint8_t *out, const uint8_t *in)
{
- aes_padlock(ctx_arg, out, in, CRYPTO_DIR_DECRYPT);
+ struct aes_ctx *ctx = aes_ctx(ctx_arg);
+ padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt, 1);
+}
+
+static unsigned int aes_encrypt_ecb(const struct cipher_desc *desc, u8 *out,
+ const u8 *in, unsigned int nbytes)
+{
+ struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+ padlock_xcrypt_ecb(in, out, ctx->E, &ctx->cword.encrypt,
+ nbytes / AES_BLOCK_SIZE);
+ return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_decrypt_ecb(const struct cipher_desc *desc, u8 *out,
+ const u8 *in, unsigned int nbytes)
+{
+ struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+ padlock_xcrypt_ecb(in, out, ctx->D, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_encrypt_cbc(const struct cipher_desc *desc, u8 *out,
+ const u8 *in, unsigned int nbytes)
+{
+ struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+ u8 *iv;
+
+ iv = padlock_xcrypt_cbc(in, out, ctx->E, desc->info,
+ &ctx->cword.encrypt, nbytes / AES_BLOCK_SIZE);
+ memcpy(desc->info, iv, AES_BLOCK_SIZE);
+
+ return nbytes & ~(AES_BLOCK_SIZE - 1);
+}
+
+static unsigned int aes_decrypt_cbc(const struct cipher_desc *desc, u8 *out,
+ const u8 *in, unsigned int nbytes)
+{
+ struct aes_ctx *ctx = aes_ctx(crypto_tfm_ctx(desc->tfm));
+ padlock_xcrypt_cbc(in, out, ctx->D, desc->info, &ctx->cword.decrypt,
+ nbytes / AES_BLOCK_SIZE);
+ return nbytes & ~(AES_BLOCK_SIZE - 1);
}
static struct crypto_alg aes_alg = {
@@ -441,6 +471,7 @@ static struct crypto_alg aes_alg = {
.cra_flags = CRYPTO_ALG_TYPE_CIPHER,
.cra_blocksize = AES_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct aes_ctx),
+ .cra_alignmask = PADLOCK_ALIGNMENT - 1,
.cra_module = THIS_MODULE,
.cra_list = LIST_HEAD_INIT(aes_alg.cra_list),
.cra_u = {
@@ -449,7 +480,11 @@ static struct crypto_alg aes_alg = {
.cia_max_keysize = AES_MAX_KEY_SIZE,
.cia_setkey = aes_set_key,
.cia_encrypt = aes_encrypt,
- .cia_decrypt = aes_decrypt
+ .cia_decrypt = aes_decrypt,
+ .cia_encrypt_ecb = aes_encrypt_ecb,
+ .cia_decrypt_ecb = aes_decrypt_ecb,
+ .cia_encrypt_cbc = aes_encrypt_cbc,
+ .cia_decrypt_cbc = aes_decrypt_cbc,
}
}
};
diff --git a/drivers/crypto/padlock.h b/drivers/crypto/padlock.h
index 7a500605e449..3cf2b7a12348 100644
--- a/drivers/crypto/padlock.h
+++ b/drivers/crypto/padlock.h
@@ -13,18 +13,18 @@
#ifndef _CRYPTO_PADLOCK_H
#define _CRYPTO_PADLOCK_H
+#define PADLOCK_ALIGNMENT 16
+
/* Control word. */
-union cword {
- uint32_t cword[4];
- struct {
- int rounds:4;
- int algo:3;
- int keygen:1;
- int interm:1;
- int encdec:1;
- int ksize:2;
- } b;
-};
+struct cword {
+ int __attribute__ ((__packed__))
+ rounds:4,
+ algo:3,
+ keygen:1,
+ interm:1,
+ encdec:1,
+ ksize:2;
+} __attribute__ ((__aligned__(PADLOCK_ALIGNMENT)));
#define PFX "padlock: "
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index a3451cb94004..33b17c6a46fb 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -618,8 +618,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
new_efivar = kmalloc(sizeof(struct efivar_entry), GFP_KERNEL);
if (!short_name || !new_efivar) {
- if (short_name) kfree(short_name);
- if (new_efivar) kfree(new_efivar);
+ kfree(short_name);
+ kfree(new_efivar);
return 1;
}
memset(short_name, 0, short_name_size+1);
@@ -644,7 +644,8 @@ efivar_create_sysfs_entry(unsigned long variable_name_size,
kobj_set_kset_s(new_efivar, vars_subsys);
kobject_register(&new_efivar->kobj);
- kfree(short_name); short_name = NULL;
+ kfree(short_name);
+ short_name = NULL;
spin_lock(&efivars_lock);
list_add(&new_efivar->list, &efivar_list);
diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c
index 839b44a7e08b..53c95c0bbf46 100644
--- a/drivers/firmware/pcdp.c
+++ b/drivers/firmware/pcdp.c
@@ -16,6 +16,7 @@
#include <linux/console.h>
#include <linux/efi.h>
#include <linux/serial.h>
+#include <asm/vga.h>
#include "pcdp.h"
static int __init
@@ -40,10 +41,27 @@ setup_serial_console(struct pcdp_uart *uart)
}
static int __init
-setup_vga_console(struct pcdp_vga *vga)
+setup_vga_console(struct pcdp_device *dev)
{
#if defined(CONFIG_VT) && defined(CONFIG_VGA_CONSOLE)
- if (efi_mem_type(0xA0000) == EFI_CONVENTIONAL_MEMORY) {
+ u8 *if_ptr;
+
+ if_ptr = ((u8 *)dev + sizeof(struct pcdp_device));
+ if (if_ptr[0] == PCDP_IF_PCI) {
+ struct pcdp_if_pci if_pci;
+
+ /* struct copy since ifptr might not be correctly aligned */
+
+ memcpy(&if_pci, if_ptr, sizeof(if_pci));
+
+ if (if_pci.trans & PCDP_PCI_TRANS_IOPORT)
+ vga_console_iobase = if_pci.ioport_tra;
+
+ if (if_pci.trans & PCDP_PCI_TRANS_MMIO)
+ vga_console_membase = if_pci.mmio_tra;
+ }
+
+ if (efi_mem_type(vga_console_membase + 0xA0000) == EFI_CONVENTIONAL_MEMORY) {
printk(KERN_ERR "PCDP: VGA selected, but frame buffer is not MMIO!\n");
return -ENODEV;
}
@@ -95,7 +113,7 @@ efi_setup_pcdp_console(char *cmdline)
dev = (struct pcdp_device *) ((u8 *) dev + dev->length)) {
if (dev->flags & PCDP_PRIMARY_CONSOLE) {
if (dev->type == PCDP_CONSOLE_VGA) {
- return setup_vga_console((struct pcdp_vga *) dev);
+ return setup_vga_console(dev);
}
}
}
diff --git a/drivers/firmware/pcdp.h b/drivers/firmware/pcdp.h
index 1dc7c88b7b4d..e72cc47de33b 100644
--- a/drivers/firmware/pcdp.h
+++ b/drivers/firmware/pcdp.h
@@ -52,11 +52,34 @@ struct pcdp_uart {
u32 clock_rate;
u8 pci_prog_intfc;
u8 flags;
-};
+} __attribute__((packed));
+
+#define PCDP_IF_PCI 1
+
+/* pcdp_if_pci.trans */
+#define PCDP_PCI_TRANS_IOPORT 0x02
+#define PCDP_PCI_TRANS_MMIO 0x01
+
+struct pcdp_if_pci {
+ u8 interconnect;
+ u8 reserved;
+ u16 length;
+ u8 segment;
+ u8 bus;
+ u8 dev;
+ u8 fun;
+ u16 dev_id;
+ u16 vendor_id;
+ u32 acpi_interrupt;
+ u64 mmio_tra;
+ u64 ioport_tra;
+ u8 flags;
+ u8 trans;
+} __attribute__((packed));
struct pcdp_vga {
u8 count; /* address space descriptors */
-};
+} __attribute__((packed));
/* pcdp_device.flags */
#define PCDP_PRIMARY_CONSOLE 1
@@ -66,7 +89,9 @@ struct pcdp_device {
u8 flags;
u16 length;
u16 efi_index;
-};
+ /* next data is pcdp_if_pci or pcdp_if_acpi (not yet supported) */
+ /* next data is device specific type (currently only pcdp_vga) */
+} __attribute__((packed));
struct pcdp {
u8 signature[4];
@@ -81,4 +106,4 @@ struct pcdp {
u32 num_uarts;
struct pcdp_uart uart[0]; /* actual size is num_uarts */
/* remainder of table is pcdp_device structures */
-};
+} __attribute__((packed));
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
new file mode 100644
index 000000000000..140d5f851a5b
--- /dev/null
+++ b/drivers/hwmon/Kconfig
@@ -0,0 +1,420 @@
+#
+# I2C Sensor chip drivers configuration
+#
+
+menu "Hardware Monitoring support"
+
+config HWMON
+ tristate "Hardware Monitoring support"
+ default y
+ help
+ Hardware monitoring devices let you monitor the hardware health
+ of a system. Most modern motherboards include such a device. It
+ can include temperature sensors, voltage sensors, fan speed
+ sensors and various additional features such as the ability to
+ control the speed of the fans.
+
+config SENSORS_ADM1021
+ tristate "Analog Devices ADM1021 and compatibles"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM1021
+ and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
+ Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10,
+ and the XEON processor built-in sensor.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm1021.
+
+config SENSORS_ADM1025
+ tristate "Analog Devices ADM1025 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM1025
+ and Philips NE1619 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm1025.
+
+config SENSORS_ADM1026
+ tristate "Analog Devices ADM1026 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM1026
+ sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm1026.
+
+config SENSORS_ADM1031
+ tristate "Analog Devices ADM1031 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM1031
+ and ADM1030 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm1031.
+
+config SENSORS_ADM9240
+ tristate "Analog Devices ADM9240 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Analog Devices ADM9240,
+ Dallas DS1780, National Semiconductor LM81 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called adm9240.
+
+config SENSORS_ASB100
+ tristate "Asus ASB100 Bach"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for the ASB100 Bach sensor
+ chip found on some Asus mainboards.
+
+ This driver can also be built as a module. If so, the module
+ will be called asb100.
+
+config SENSORS_ATXP1
+ tristate "Attansic ATXP1 VID controller"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for the Attansic ATXP1 VID
+ controller.
+
+ If your board have such a chip, you are able to control your CPU
+ core and other voltages.
+
+ This driver can also be built as a module. If so, the module
+ will be called atxp1.
+
+config SENSORS_DS1621
+ tristate "Dallas Semiconductor DS1621 and DS1625"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Dallas Semiconductor
+ DS1621 and DS1625 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called ds1621.
+
+config SENSORS_FSCHER
+ tristate "FSC Hermes"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Fujitsu Siemens
+ Computers Hermes sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called fscher.
+
+config SENSORS_FSCPOS
+ tristate "FSC Poseidon"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Fujitsu Siemens
+ Computers Poseidon sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called fscpos.
+
+config SENSORS_GL518SM
+ tristate "Genesys Logic GL518SM"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Genesys Logic GL518SM
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called gl518sm.
+
+config SENSORS_GL520SM
+ tristate "Genesys Logic GL520SM"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for Genesys Logic GL520SM
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called gl520sm.
+
+config SENSORS_IT87
+ tristate "ITE IT87xx and compatibles"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for ITE IT87xx sensor chips
+ and clones: SiS960.
+
+ This driver can also be built as a module. If so, the module
+ will be called it87.
+
+config SENSORS_LM63
+ tristate "National Semiconductor LM63"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for the National Semiconductor
+ LM63 remote diode digital temperature sensor with integrated fan
+ control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro)
+ motherboard, among others.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm63.
+
+config SENSORS_LM75
+ tristate "National Semiconductor LM75 and compatibles"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM75
+ sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
+ 9-bit precision mode), and TelCom (now Microchip) TCN75.
+
+ The DS75 and DS1775 in 10- to 12-bit precision modes will require
+ a force module parameter. The driver will not handle the extra
+ precision anyhow.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm75.
+
+config SENSORS_LM77
+ tristate "National Semiconductor LM77"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM77
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm77.
+
+config SENSORS_LM78
+ tristate "National Semiconductor LM78 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM78,
+ LM78-J and LM79.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm78.
+
+config SENSORS_LM80
+ tristate "National Semiconductor LM80"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor
+ LM80 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm80.
+
+config SENSORS_LM83
+ tristate "National Semiconductor LM83"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor
+ LM83 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm83.
+
+config SENSORS_LM85
+ tristate "National Semiconductor LM85 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM85
+ sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm85.
+
+config SENSORS_LM87
+ tristate "National Semiconductor LM87"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM87
+ sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm87.
+
+config SENSORS_LM90
+ tristate "National Semiconductor LM90 and compatibles"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM90,
+ LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
+ MAX6658 sensor chips.
+
+ The Analog Devices ADT7461 sensor chip is also supported, but only
+ if found in ADM1032 compatibility mode.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm90.
+
+config SENSORS_LM92
+ tristate "National Semiconductor LM92 and compatibles"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for National Semiconductor LM92
+ and Maxim MAX6635 sensor chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called lm92.
+
+config SENSORS_MAX1619
+ tristate "Maxim MAX1619 sensor chip"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for MAX1619 sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called max1619.
+
+config SENSORS_PC87360
+ tristate "National Semiconductor PC87360 family"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get access to the hardware monitoring
+ functions of the National Semiconductor PC8736x Super-I/O chips.
+ The PC87360, PC87363 and PC87364 only have fan monitoring and
+ control. The PC87365 and PC87366 additionally have voltage and
+ temperature monitoring.
+
+ This driver can also be built as a module. If so, the module
+ will be called pc87360.
+
+config SENSORS_SIS5595
+ tristate "Silicon Integrated Systems Corp. SiS5595"
+ depends on HWMON && I2C && PCI && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get support for the integrated sensors in
+ SiS5595 South Bridges.
+
+ This driver can also be built as a module. If so, the module
+ will be called sis5595.
+
+config SENSORS_SMSC47M1
+ tristate "SMSC LPC47M10x and compatibles"
+ depends on HWMON && 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, LPC47M14x, LPC47M15x and LPC47M192 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called smsc47m1.
+
+config SENSORS_SMSC47B397
+ tristate "SMSC LPC47B397-NC"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get support for the SMSC LPC47B397-NC
+ sensor chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called smsc47b397.
+
+config SENSORS_VIA686A
+ tristate "VIA686A"
+ depends on HWMON && I2C && PCI
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get support for the integrated sensors in
+ Via 686A/B South Bridges.
+
+ This driver can also be built as a module. If so, the module
+ will be called via686a.
+
+config SENSORS_W83781D
+ tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
+ depends on HWMON && I2C
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for the Winbond W8378x series
+ of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
+ and the similar Asus AS99127F.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83781d.
+
+config SENSORS_W83L785TS
+ tristate "Winbond W83L785TS-S"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ help
+ If you say yes here you get support for the Winbond W83L785TS-S
+ sensor chip, which is used on the Asus A7N8X, among other
+ motherboards.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83l785ts.
+
+config SENSORS_W83627HF
+ tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get support for the Winbond W836X7 series
+ of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
+
+ This driver can also be built as a module. If so, the module
+ will be called w83627hf.
+
+config SENSORS_W83627EHF
+ tristate "Winbond W83627EHF"
+ depends on HWMON && I2C && EXPERIMENTAL
+ select I2C_SENSOR
+ select I2C_ISA
+ help
+ If you say yes here you get preliminary support for the hardware
+ monitoring functionality of the Winbond W83627EHF Super-I/O chip.
+ Only fan and temperature inputs are supported at the moment, while
+ the chip does much more than that.
+
+ This driver can also be built as a module. If so, the module
+ will be called w83627ehf.
+
+config HWMON_DEBUG_CHIP
+ bool "Hardware Monitoring Chip debugging messages"
+ depends on HWMON
+ default n
+ help
+ Say Y here if you want the I2C chip drivers to produce a bunch of
+ debug messages to the system log. Select this if you are having
+ a problem with I2C support and want to see more of what is going
+ on.
+
+endmenu
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
new file mode 100644
index 000000000000..2781403a0236
--- /dev/null
+++ b/drivers/hwmon/Makefile
@@ -0,0 +1,44 @@
+#
+# Makefile for sensor chip drivers.
+#
+
+# asb100, then w83781d go first, as they can override other drivers' addresses.
+obj-$(CONFIG_SENSORS_ASB100) += asb100.o
+obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
+obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
+
+obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
+obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
+obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
+obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
+obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
+obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
+obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
+obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
+obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
+obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
+obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
+obj-$(CONFIG_SENSORS_IT87) += it87.o
+obj-$(CONFIG_SENSORS_LM63) += lm63.o
+obj-$(CONFIG_SENSORS_LM75) += lm75.o
+obj-$(CONFIG_SENSORS_LM77) += lm77.o
+obj-$(CONFIG_SENSORS_LM78) += lm78.o
+obj-$(CONFIG_SENSORS_LM80) += lm80.o
+obj-$(CONFIG_SENSORS_LM83) += lm83.o
+obj-$(CONFIG_SENSORS_LM85) += lm85.o
+obj-$(CONFIG_SENSORS_LM87) += lm87.o
+obj-$(CONFIG_SENSORS_LM90) += lm90.o
+obj-$(CONFIG_SENSORS_LM92) += lm92.o
+obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
+obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
+obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
+obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
+obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
+obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
+obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
+obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
+
+ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/drivers/i2c/chips/adm1021.c b/drivers/hwmon/adm1021.c
index d2c774c32f45..d2c774c32f45 100644
--- a/drivers/i2c/chips/adm1021.c
+++ b/drivers/hwmon/adm1021.c
diff --git a/drivers/i2c/chips/adm1025.c b/drivers/hwmon/adm1025.c
index e452d0daf906..e452d0daf906 100644
--- a/drivers/i2c/chips/adm1025.c
+++ b/drivers/hwmon/adm1025.c
diff --git a/drivers/i2c/chips/adm1026.c b/drivers/hwmon/adm1026.c
index 3c85fe150cd7..3c85fe150cd7 100644
--- a/drivers/i2c/chips/adm1026.c
+++ b/drivers/hwmon/adm1026.c
diff --git a/drivers/i2c/chips/adm1031.c b/drivers/hwmon/adm1031.c
index 9168e983ca1d..9168e983ca1d 100644
--- a/drivers/i2c/chips/adm1031.c
+++ b/drivers/hwmon/adm1031.c
diff --git a/drivers/i2c/chips/adm9240.c b/drivers/hwmon/adm9240.c
index 5c68e9c311aa..5c68e9c311aa 100644
--- a/drivers/i2c/chips/adm9240.c
+++ b/drivers/hwmon/adm9240.c
diff --git a/drivers/i2c/chips/asb100.c b/drivers/hwmon/asb100.c
index 70d996d6fe0a..70d996d6fe0a 100644
--- a/drivers/i2c/chips/asb100.c
+++ b/drivers/hwmon/asb100.c
diff --git a/drivers/i2c/chips/atxp1.c b/drivers/hwmon/atxp1.c
index 5c6597aa2c7f..0bcf82b4c07b 100644
--- a/drivers/i2c/chips/atxp1.c
+++ b/drivers/hwmon/atxp1.c
@@ -144,7 +144,7 @@ static ssize_t atxp1_storevcore(struct device *dev, struct device_attribute *att
if (vid == cvid)
return count;
- dev_info(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
+ dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", vcore, vid);
/* Write every 25 mV step to increase stability */
if (cvid > vid) {
diff --git a/drivers/i2c/chips/ds1621.c b/drivers/hwmon/ds1621.c
index 5360d58804f6..5360d58804f6 100644
--- a/drivers/i2c/chips/ds1621.c
+++ b/drivers/hwmon/ds1621.c
diff --git a/drivers/i2c/chips/fscher.c b/drivers/hwmon/fscher.c
index da411741c2c5..da411741c2c5 100644
--- a/drivers/i2c/chips/fscher.c
+++ b/drivers/hwmon/fscher.c
diff --git a/drivers/i2c/chips/fscpos.c b/drivers/hwmon/fscpos.c
index 3beaa6191ef4..3beaa6191ef4 100644
--- a/drivers/i2c/chips/fscpos.c
+++ b/drivers/hwmon/fscpos.c
diff --git a/drivers/i2c/chips/gl518sm.c b/drivers/hwmon/gl518sm.c
index 6bedf729dcf5..6bedf729dcf5 100644
--- a/drivers/i2c/chips/gl518sm.c
+++ b/drivers/hwmon/gl518sm.c
diff --git a/drivers/i2c/chips/gl520sm.c b/drivers/hwmon/gl520sm.c
index a13a504f5bfa..a13a504f5bfa 100644
--- a/drivers/i2c/chips/gl520sm.c
+++ b/drivers/hwmon/gl520sm.c
diff --git a/drivers/i2c/chips/it87.c b/drivers/hwmon/it87.c
index db20c9e47393..db20c9e47393 100644
--- a/drivers/i2c/chips/it87.c
+++ b/drivers/hwmon/it87.c
diff --git a/drivers/i2c/chips/lm63.c b/drivers/hwmon/lm63.c
index 7c6f9ea5a254..7c6f9ea5a254 100644
--- a/drivers/i2c/chips/lm63.c
+++ b/drivers/hwmon/lm63.c
diff --git a/drivers/i2c/chips/lm75.c b/drivers/hwmon/lm75.c
index 5be164ed278e..5be164ed278e 100644
--- a/drivers/i2c/chips/lm75.c
+++ b/drivers/hwmon/lm75.c
diff --git a/drivers/i2c/chips/lm75.h b/drivers/hwmon/lm75.h
index 63e3f2fb4c21..63e3f2fb4c21 100644
--- a/drivers/i2c/chips/lm75.h
+++ b/drivers/hwmon/lm75.h
diff --git a/drivers/i2c/chips/lm77.c b/drivers/hwmon/lm77.c
index b98f44952997..b98f44952997 100644
--- a/drivers/i2c/chips/lm77.c
+++ b/drivers/hwmon/lm77.c
diff --git a/drivers/i2c/chips/lm78.c b/drivers/hwmon/lm78.c
index 29241469dcba..29241469dcba 100644
--- a/drivers/i2c/chips/lm78.c
+++ b/drivers/hwmon/lm78.c
diff --git a/drivers/i2c/chips/lm80.c b/drivers/hwmon/lm80.c
index 8100595feb44..8100595feb44 100644
--- a/drivers/i2c/chips/lm80.c
+++ b/drivers/hwmon/lm80.c
diff --git a/drivers/i2c/chips/lm83.c b/drivers/hwmon/lm83.c
index a49008b444c8..a49008b444c8 100644
--- a/drivers/i2c/chips/lm83.c
+++ b/drivers/hwmon/lm83.c
diff --git a/drivers/i2c/chips/lm85.c b/drivers/hwmon/lm85.c
index b4d7fd418264..b4d7fd418264 100644
--- a/drivers/i2c/chips/lm85.c
+++ b/drivers/hwmon/lm85.c
diff --git a/drivers/i2c/chips/lm87.c b/drivers/hwmon/lm87.c
index 1921ed1af182..1921ed1af182 100644
--- a/drivers/i2c/chips/lm87.c
+++ b/drivers/hwmon/lm87.c
diff --git a/drivers/i2c/chips/lm90.c b/drivers/hwmon/lm90.c
index a67dcadf7cb0..a67dcadf7cb0 100644
--- a/drivers/i2c/chips/lm90.c
+++ b/drivers/hwmon/lm90.c
diff --git a/drivers/i2c/chips/lm92.c b/drivers/hwmon/lm92.c
index 215c8e40ffdd..215c8e40ffdd 100644
--- a/drivers/i2c/chips/lm92.c
+++ b/drivers/hwmon/lm92.c
diff --git a/drivers/i2c/chips/max1619.c b/drivers/hwmon/max1619.c
index bf553dcd97d6..bf553dcd97d6 100644
--- a/drivers/i2c/chips/max1619.c
+++ b/drivers/hwmon/max1619.c
diff --git a/drivers/i2c/chips/pc87360.c b/drivers/hwmon/pc87360.c
index 876c68f3af31..876c68f3af31 100644
--- a/drivers/i2c/chips/pc87360.c
+++ b/drivers/hwmon/pc87360.c
diff --git a/drivers/i2c/chips/sis5595.c b/drivers/hwmon/sis5595.c
index 6bbfc8fb4f13..6bbfc8fb4f13 100644
--- a/drivers/i2c/chips/sis5595.c
+++ b/drivers/hwmon/sis5595.c
diff --git a/drivers/i2c/chips/smsc47b397.c b/drivers/hwmon/smsc47b397.c
index 251ac2659554..251ac2659554 100644
--- a/drivers/i2c/chips/smsc47b397.c
+++ b/drivers/hwmon/smsc47b397.c
diff --git a/drivers/i2c/chips/smsc47m1.c b/drivers/hwmon/smsc47m1.c
index 897117a7213f..897117a7213f 100644
--- a/drivers/i2c/chips/smsc47m1.c
+++ b/drivers/hwmon/smsc47m1.c
diff --git a/drivers/i2c/chips/via686a.c b/drivers/hwmon/via686a.c
index 137d9b7cacd4..164d47948390 100644
--- a/drivers/i2c/chips/via686a.c
+++ b/drivers/hwmon/via686a.c
@@ -1,9 +1,9 @@
/*
via686a.c - Part of lm_sensors, Linux kernel modules
- for hardware monitoring
+ for hardware monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
- Kyösti Mälkki <kmalkki@cc.hut.fi>,
+ Kyösti Mälkki <kmalkki@cc.hut.fi>,
Mark Studebaker <mdsxyz123@yahoo.com>,
and Bob Dougherty <bobd@stanford.edu>
(Some conversion-factor data were contributed by Jonathan Teh Soon Yew
@@ -171,18 +171,18 @@ static inline u8 FAN_TO_REG(long rpm, int div)
/******** TEMP CONVERSIONS (Bob Dougherty) *********/
/* linear fits from HWMon.cpp (Copyright 1998-2000 Jonathan Teh Soon Yew)
if(temp<169)
- return double(temp)*0.427-32.08;
+ return double(temp)*0.427-32.08;
else if(temp>=169 && temp<=202)
- return double(temp)*0.582-58.16;
+ return double(temp)*0.582-58.16;
else
- return double(temp)*0.924-127.33;
+ return double(temp)*0.924-127.33;
A fifth-order polynomial fits the unofficial data (provided by Alex van
Kaam <darkside@chello.nl>) a bit better. It also give more reasonable
numbers on my machine (ie. they agree with what my BIOS tells me).
Here's the fifth-order fit to the 8-bit data:
temp = 1.625093e-10*val^5 - 1.001632e-07*val^4 + 2.457653e-05*val^3 -
- 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
+ 2.967619e-03*val^2 + 2.175144e-01*val - 7.090067e+0.
(2000-10-25- RFD: thanks to Uwe Andersen <uandersen@mayah.com> for
finding my typos in this formula!)
diff --git a/drivers/i2c/chips/w83627ehf.c b/drivers/hwmon/w83627ehf.c
index 8a40b6976e1a..8a40b6976e1a 100644
--- a/drivers/i2c/chips/w83627ehf.c
+++ b/drivers/hwmon/w83627ehf.c
diff --git a/drivers/i2c/chips/w83627hf.c b/drivers/hwmon/w83627hf.c
index bd87a42e068a..bd87a42e068a 100644
--- a/drivers/i2c/chips/w83627hf.c
+++ b/drivers/hwmon/w83627hf.c
diff --git a/drivers/i2c/chips/w83781d.c b/drivers/hwmon/w83781d.c
index 0bb131ce09eb..0bb131ce09eb 100644
--- a/drivers/i2c/chips/w83781d.c
+++ b/drivers/hwmon/w83781d.c
diff --git a/drivers/i2c/chips/w83l785ts.c b/drivers/hwmon/w83l785ts.c
index 4469d52aba4c..4469d52aba4c 100644
--- a/drivers/i2c/chips/w83l785ts.c
+++ b/drivers/hwmon/w83l785ts.c
diff --git a/drivers/i2c/algos/i2c-algo-ite.c b/drivers/i2c/algos/i2c-algo-ite.c
index 68e9e6832ca0..e6cae39f47aa 100644
--- a/drivers/i2c/algos/i2c-algo-ite.c
+++ b/drivers/i2c/algos/i2c-algo-ite.c
@@ -208,7 +208,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
goto bailout;
}
sdalo(adap);
- printk("test_bus:1 scl: %d sda: %d \n",getscl(adap),
+ printk("test_bus:1 scl: %d sda: %d\n", getscl(adap),
getsda(adap));
if ( 0 != getsda(adap) ) {
printk("test_bus: %s SDA stuck high!\n",name);
@@ -221,7 +221,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
goto bailout;
}
sdahi(adap);
- printk("test_bus:2 scl: %d sda: %d \n",getscl(adap),
+ printk("test_bus:2 scl: %d sda: %d\n", getscl(adap),
getsda(adap));
if ( 0 == getsda(adap) ) {
printk("test_bus: %s SDA stuck low!\n",name);
@@ -234,7 +234,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
goto bailout;
}
scllo(adap);
- printk("test_bus:3 scl: %d sda: %d \n",getscl(adap),
+ printk("test_bus:3 scl: %d sda: %d\n", getscl(adap),
getsda(adap));
if ( 0 != getscl(adap) ) {
@@ -247,7 +247,7 @@ static int test_bus(struct i2c_algo_iic_data *adap, char *name) {
goto bailout;
}
sclhi(adap);
- printk("test_bus:4 scl: %d sda: %d \n",getscl(adap),
+ printk("test_bus:4 scl: %d sda: %d\n", getscl(adap),
getsda(adap));
if ( 0 == getscl(adap) ) {
printk("test_bus: %s SCL stuck low!\n",name);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 45e6efb1dcd1..0ab7e37f5b00 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -194,7 +194,7 @@ static int i801_transaction(void)
/* Make sure the SMBus host is ready to start transmitting */
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
- dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting... \n",
+ dev_dbg(&I801_dev->dev, "SMBus busy (%02x). Resetting...\n",
temp);
outb_p(temp, SMBHSTSTS);
if ((temp = (0x1f & inb_p(SMBHSTSTS))) != 0x00) {
@@ -315,7 +315,7 @@ static int i801_block_transaction(union i2c_smbus_data *data, char read_write,
}
if (temp & errmask) {
dev_dbg(&I801_dev->dev, "SMBus busy (%02x). "
- "Resetting... \n", temp);
+ "Resetting...\n", temp);
outb_p(temp, SMBHSTSTS);
if (((temp = inb_p(SMBHSTSTS)) & errmask) != 0x00) {
dev_err(&I801_dev->dev,
diff --git a/drivers/i2c/busses/i2c-ixp2000.c b/drivers/i2c/busses/i2c-ixp2000.c
index ec943cad2314..1956af382cd8 100644
--- a/drivers/i2c/busses/i2c-ixp2000.c
+++ b/drivers/i2c/busses/i2c-ixp2000.c
@@ -33,7 +33,8 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
-#include <asm/hardware.h> /* Pick up IXP42000-specific bits */
+#include <asm/hardware.h> /* Pick up IXP2000-specific bits */
+#include <asm/arch/gpio.h>
static inline int ixp2000_scl_pin(void *data)
{
diff --git a/drivers/i2c/busses/i2c-keywest.c b/drivers/i2c/busses/i2c-keywest.c
index 363e545fc01f..94ae808314f7 100644
--- a/drivers/i2c/busses/i2c-keywest.c
+++ b/drivers/i2c/busses/i2c-keywest.c
@@ -698,7 +698,7 @@ dispose_iface(struct device *dev)
}
static int
-create_iface_macio(struct macio_dev* dev, const struct of_match *match)
+create_iface_macio(struct macio_dev* dev, const struct of_device_id *match)
{
return create_iface(dev->ofdev.node, &dev->ofdev.dev);
}
@@ -710,7 +710,7 @@ dispose_iface_macio(struct macio_dev* dev)
}
static int
-create_iface_of_platform(struct of_device* dev, const struct of_match *match)
+create_iface_of_platform(struct of_device* dev, const struct of_device_id *match)
{
return create_iface(dev->node, &dev->dev);
}
@@ -721,10 +721,9 @@ dispose_iface_of_platform(struct of_device* dev)
return dispose_iface(&dev->dev);
}
-static struct of_match i2c_keywest_match[] =
+static struct of_device_id i2c_keywest_match[] =
{
{
- .name = OF_ANY_MATCH,
.type = "i2c",
.compatible = "keywest"
},
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index d41ca31dbcb2..03c23ce98edb 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -20,13 +20,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <asm/io.h>
-#ifdef CONFIG_FSL_OCP
-#include <asm/ocp.h>
-#define FSL_I2C_DEV_SEPARATE_DFSRR FS_I2C_SEPARATE_DFSRR
-#define FSL_I2C_DEV_CLOCK_5200 FS_I2C_CLOCK_5200
-#else
#include <linux/fsl_devices.h>
-#endif
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@@ -294,204 +288,6 @@ static struct i2c_adapter mpc_ops = {
.retries = 1
};
-#ifdef CONFIG_FSL_OCP
-static int __devinit mpc_i2c_probe(struct ocp_device *ocp)
-{
- int result = 0;
- struct mpc_i2c *i2c;
-
- if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
- return -ENOMEM;
- }
- memset(i2c, 0, sizeof(*i2c));
-
- i2c->irq = ocp->def->irq;
- i2c->flags = ((struct ocp_fs_i2c_data *)ocp->def->additions)->flags;
- init_waitqueue_head(&i2c->queue);
-
- if (!request_mem_region(ocp->def->paddr, MPC_I2C_REGION, "i2c-mpc")) {
- printk(KERN_ERR "i2c-mpc - resource unavailable\n");
- return -ENODEV;
- }
-
- i2c->base = ioremap(ocp->def->paddr, MPC_I2C_REGION);
-
- if (!i2c->base) {
- printk(KERN_ERR "i2c-mpc - failed to map controller\n");
- result = -ENOMEM;
- goto fail_map;
- }
-
- if (i2c->irq != OCP_IRQ_NA)
- {
- if ((result = request_irq(ocp->def->irq, mpc_i2c_isr,
- SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
- printk(KERN_ERR
- "i2c-mpc - failed to attach interrupt\n");
- goto fail_irq;
- }
- } else
- i2c->irq = 0;
-
- mpc_i2c_setclock(i2c);
- ocp_set_drvdata(ocp, i2c);
-
- i2c->adap = mpc_ops;
- i2c_set_adapdata(&i2c->adap, i2c);
-
- if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
- printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
- goto fail_add;
- }
-
- return result;
-
- fail_add:
- if (ocp->def->irq != OCP_IRQ_NA)
- free_irq(ocp->def->irq, 0);
- fail_irq:
- iounmap(i2c->base);
- fail_map:
- release_mem_region(ocp->def->paddr, MPC_I2C_REGION);
- kfree(i2c);
- return result;
-}
-static void __devexit mpc_i2c_remove(struct ocp_device *ocp)
-{
- struct mpc_i2c *i2c = ocp_get_drvdata(ocp);
- i2c_del_adapter(&i2c->adap);
- ocp_set_drvdata(ocp, NULL);
-
- if (ocp->def->irq != OCP_IRQ_NA)
- free_irq(i2c->irq, i2c);
- iounmap(i2c->base);
- release_mem_region(ocp->def->paddr, MPC_I2C_REGION);
- kfree(i2c);
-}
-
-static struct ocp_device_id mpc_iic_ids[] __devinitdata = {
- {.vendor = OCP_VENDOR_FREESCALE,.function = OCP_FUNC_IIC},
- {.vendor = OCP_VENDOR_INVALID}
-};
-
-MODULE_DEVICE_TABLE(ocp, mpc_iic_ids);
-
-static struct ocp_driver mpc_iic_driver = {
- .name = "iic",
- .id_table = mpc_iic_ids,
- .probe = mpc_i2c_probe,
- .remove = __devexit_p(mpc_i2c_remove)
-};
-
-static int __init iic_init(void)
-{
- return ocp_register_driver(&mpc_iic_driver);
-}
-
-static void __exit iic_exit(void)
-{
- ocp_unregister_driver(&mpc_iic_driver);
-}
-
-module_init(iic_init);
-module_exit(iic_exit);
-#else
-static int fsl_i2c_probe(struct device *device)
-{
- int result = 0;
- struct mpc_i2c *i2c;
- struct platform_device *pdev = to_platform_device(device);
- struct fsl_i2c_platform_data *pdata;
- struct resource *r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
- pdata = (struct fsl_i2c_platform_data *) pdev->dev.platform_data;
-
- if (!(i2c = kmalloc(sizeof(*i2c), GFP_KERNEL))) {
- return -ENOMEM;
- }
- memset(i2c, 0, sizeof(*i2c));
-
- i2c->irq = platform_get_irq(pdev, 0);
- i2c->flags = pdata->device_flags;
- init_waitqueue_head(&i2c->queue);
-
- i2c->base = ioremap((phys_addr_t)r->start, MPC_I2C_REGION);
-
- if (!i2c->base) {
- printk(KERN_ERR "i2c-mpc - failed to map controller\n");
- result = -ENOMEM;
- goto fail_map;
- }
-
- if (i2c->irq != 0)
- if ((result = request_irq(i2c->irq, mpc_i2c_isr,
- SA_SHIRQ, "i2c-mpc", i2c)) < 0) {
- printk(KERN_ERR
- "i2c-mpc - failed to attach interrupt\n");
- goto fail_irq;
- }
-
- mpc_i2c_setclock(i2c);
- dev_set_drvdata(device, i2c);
-
- i2c->adap = mpc_ops;
- i2c_set_adapdata(&i2c->adap, i2c);
- i2c->adap.dev.parent = &pdev->dev;
- if ((result = i2c_add_adapter(&i2c->adap)) < 0) {
- printk(KERN_ERR "i2c-mpc - failed to add adapter\n");
- goto fail_add;
- }
-
- return result;
-
- fail_add:
- if (i2c->irq != 0)
- free_irq(i2c->irq, NULL);
- fail_irq:
- iounmap(i2c->base);
- fail_map:
- kfree(i2c);
- return result;
-};
-
-static int fsl_i2c_remove(struct device *device)
-{
- struct mpc_i2c *i2c = dev_get_drvdata(device);
-
- i2c_del_adapter(&i2c->adap);
- dev_set_drvdata(device, NULL);
-
- if (i2c->irq != 0)
- free_irq(i2c->irq, i2c);
-
- iounmap(i2c->base);
- kfree(i2c);
- return 0;
-};
-
-/* Structure for a device driver */
-static struct device_driver fsl_i2c_driver = {
- .name = "fsl-i2c",
- .bus = &platform_bus_type,
- .probe = fsl_i2c_probe,
- .remove = fsl_i2c_remove,
-};
-
-static int __init fsl_i2c_init(void)
-{
- return driver_register(&fsl_i2c_driver);
-}
-
-static void __exit fsl_i2c_exit(void)
-{
- driver_unregister(&fsl_i2c_driver);
-}
-
-module_init(fsl_i2c_init);
-module_exit(fsl_i2c_exit);
-
-#endif /* CONFIG_FSL_OCP */
-
MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
MODULE_DESCRIPTION
("I2C-Bus adapter for MPC107 bridge and MPC824x/85xx/52xx processors");
diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
index 1f80ba9da6f1..6d34ee381ce1 100644
--- a/drivers/i2c/busses/i2c-piix4.c
+++ b/drivers/i2c/busses/i2c-piix4.c
@@ -243,7 +243,7 @@ static int piix4_transaction(void)
/* Make sure the SMBus host is ready to start transmitting */
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
dev_dbg(&piix4_adapter.dev, "SMBus busy (%02x). "
- "Resetting... \n", temp);
+ "Resetting...\n", temp);
outb_p(temp, SMBHSTSTS);
if ((temp = inb_p(SMBHSTSTS)) != 0x00) {
dev_err(&piix4_adapter.dev, "Failed! (%02x)\n", temp);
diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c
index 2b5911cfb7b5..bbd5e4e52f09 100644
--- a/drivers/i2c/busses/i2c-sis5595.c
+++ b/drivers/i2c/busses/i2c-sis5595.c
@@ -228,7 +228,7 @@ static int sis5595_transaction(struct i2c_adapter *adap)
/* Make sure the SMBus host is ready to start transmitting */
temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8);
if (temp != 0x00) {
- dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting... \n", temp);
+ dev_dbg(&adap->dev, "SMBus busy (%04x). Resetting...\n", temp);
sis5595_write(SMB_STS_LO, temp & 0xff);
sis5595_write(SMB_STS_HI, temp >> 8);
if ((temp = sis5595_read(SMB_STS_LO) + (sis5595_read(SMB_STS_HI) << 8)) != 0x00) {
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index a0982da09803..43f70dbfc03f 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -1,409 +1,12 @@
#
-# I2C Sensor and "other" chip configuration
+# Miscellaneous I2C chip drivers configuration
#
-menu "Hardware Sensors Chip support"
- depends on I2C
-
config I2C_SENSOR
tristate
default n
-config SENSORS_ADM1021
- tristate "Analog Devices ADM1021 and compatibles"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for Analog Devices ADM1021
- and ADM1023 sensor chips and clones: Maxim MAX1617 and MAX1617A,
- Genesys Logic GL523SM, National Semiconductor LM84, TI THMC10,
- and the XEON processor built-in sensor.
-
- This driver can also be built as a module. If so, the module
- will be called adm1021.
-
-config SENSORS_ADM1025
- tristate "Analog Devices ADM1025 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Analog Devices ADM1025
- and Philips NE1619 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called adm1025.
-
-config SENSORS_ADM1026
- tristate "Analog Devices ADM1026 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Analog Devices ADM1026
- sensor chip.
-
- This driver can also be built as a module. If so, the module
- will be called adm1026.
-
-config SENSORS_ADM1031
- tristate "Analog Devices ADM1031 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Analog Devices ADM1031
- and ADM1030 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called adm1031.
-
-config SENSORS_ADM9240
- tristate "Analog Devices ADM9240 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Analog Devices ADM9240,
- Dallas DS1780, National Semiconductor LM81 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called adm9240.
-
-config SENSORS_ASB100
- tristate "Asus ASB100 Bach"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for the ASB100 Bach sensor
- chip found on some Asus mainboards.
-
- This driver can also be built as a module. If so, the module
- will be called asb100.
-
-config SENSORS_ATXP1
- tristate "Attansic ATXP1 VID controller"
- depends on I2C && EXPERIMENTAL
- help
- If you say yes here you get support for the Attansic ATXP1 VID
- controller.
-
- If your board have such a chip, you are able to control your CPU
- core and other voltages.
-
- This driver can also be built as a module. If so, the module
- will be called atxp1.
-
-config SENSORS_DS1621
- tristate "Dallas Semiconductor DS1621 and DS1625"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Dallas Semiconductor
- DS1621 and DS1625 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called ds1621.
-
-config SENSORS_FSCHER
- tristate "FSC Hermes"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Fujitsu Siemens
- Computers Hermes sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called fscher.
-
-config SENSORS_FSCPOS
- tristate "FSC Poseidon"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Fujitsu Siemens
- Computers Poseidon sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called fscpos.
-
-config SENSORS_GL518SM
- tristate "Genesys Logic GL518SM"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for Genesys Logic GL518SM
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called gl518sm.
-
-config SENSORS_GL520SM
- tristate "Genesys Logic GL520SM"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for Genesys Logic GL520SM
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called gl520sm.
-
-config SENSORS_IT87
- tristate "ITE IT87xx and compatibles"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for ITE IT87xx sensor chips
- and clones: SiS960.
-
- This driver can also be built as a module. If so, the module
- will be called it87.
-
-config SENSORS_LM63
- tristate "National Semiconductor LM63"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for the National Semiconductor
- LM63 remote diode digital temperature sensor with integrated fan
- control. Such chips are found on the Tyan S4882 (Thunder K8QS Pro)
- motherboard, among others.
-
- This driver can also be built as a module. If so, the module
- will be called lm63.
-
-config SENSORS_LM75
- tristate "National Semiconductor LM75 and compatibles"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM75
- sensor chips and clones: Dallas Semiconductor DS75 and DS1775 (in
- 9-bit precision mode), and TelCom (now Microchip) TCN75.
-
- The DS75 and DS1775 in 10- to 12-bit precision modes will require
- a force module parameter. The driver will not handle the extra
- precision anyhow.
-
- This driver can also be built as a module. If so, the module
- will be called lm75.
-
-config SENSORS_LM77
- tristate "National Semiconductor LM77"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM77
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called lm77.
-
-config SENSORS_LM78
- tristate "National Semiconductor LM78 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM78,
- LM78-J and LM79.
-
- This driver can also be built as a module. If so, the module
- will be called lm78.
-
-config SENSORS_LM80
- tristate "National Semiconductor LM80"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor
- LM80 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called lm80.
-
-config SENSORS_LM83
- tristate "National Semiconductor LM83"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor
- LM83 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called lm83.
-
-config SENSORS_LM85
- tristate "National Semiconductor LM85 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM85
- sensor chips and clones: ADT7463, EMC6D100, EMC6D102 and ADM1027.
-
- This driver can also be built as a module. If so, the module
- will be called lm85.
-
-config SENSORS_LM87
- tristate "National Semiconductor LM87"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM87
- sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called lm87.
-
-config SENSORS_LM90
- tristate "National Semiconductor LM90 and compatibles"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM90,
- LM86, LM89 and LM99, Analog Devices ADM1032 and Maxim MAX6657 and
- MAX6658 sensor chips.
-
- The Analog Devices ADT7461 sensor chip is also supported, but only
- if found in ADM1032 compatibility mode.
-
- This driver can also be built as a module. If so, the module
- will be called lm90.
-
-config SENSORS_LM92
- tristate "National Semiconductor LM92 and compatibles"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for National Semiconductor LM92
- and Maxim MAX6635 sensor chips.
-
- This driver can also be built as a module. If so, the module
- will be called lm92.
-
-config SENSORS_MAX1619
- tristate "Maxim MAX1619 sensor chip"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for MAX1619 sensor chip.
-
- This driver can also be built as a module. If so, the module
- will be called max1619.
-
-config SENSORS_PC87360
- tristate "National Semiconductor PC87360 family"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get access to the hardware monitoring
- functions of the National Semiconductor PC8736x Super-I/O chips.
- The PC87360, PC87363 and PC87364 only have fan monitoring and
- control. The PC87365 and PC87366 additionally have voltage and
- temperature monitoring.
-
- This driver can also be built as a module. If so, the module
- will be called pc87360.
-
-config SENSORS_SMSC47B397
- tristate "SMSC LPC47B397-NC"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get support for the SMSC LPC47B397-NC
- sensor chip.
-
- This driver can also be built as a module. If so, the module
- will be called smsc47b397.
-
-config SENSORS_SIS5595
- tristate "Silicon Integrated Systems Corp. SiS5595"
- depends on I2C && PCI && EXPERIMENTAL
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get support for the integrated sensors in
- SiS5595 South Bridges.
-
- This driver can also be built as a module. If so, the module
- will be called sis5595.
-
-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, LPC47M14x, LPC47M15x and LPC47M192 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
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get support for the integrated sensors in
- Via 686A/B South Bridges.
-
- This driver can also be built as a module. If so, the module
- will be called via686a.
-
-config SENSORS_W83781D
- tristate "Winbond W83781D, W83782D, W83783S, W83627HF, Asus AS99127F"
- depends on I2C
- select I2C_SENSOR
- help
- If you say yes here you get support for the Winbond W8378x series
- of sensor chips: the W83781D, W83782D, W83783S and W83627HF,
- and the similar Asus AS99127F.
-
- This driver can also be built as a module. If so, the module
- will be called w83781d.
-
-config SENSORS_W83L785TS
- tristate "Winbond W83L785TS-S"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- help
- If you say yes here you get support for the Winbond W83L785TS-S
- sensor chip, which is used on the Asus A7N8X, among other
- motherboards.
-
- This driver can also be built as a module. If so, the module
- will be called w83l785ts.
-
-config SENSORS_W83627HF
- tristate "Winbond W83627HF, W83627THF, W83637HF, W83697HF"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get support for the Winbond W836X7 series
- of sensor chips: the W83627HF, W83627THF, W83637HF, and the W83697HF
-
- This driver can also be built as a module. If so, the module
- will be called w83627hf.
-
-config SENSORS_W83627EHF
- tristate "Winbond W83627EHF"
- depends on I2C && EXPERIMENTAL
- select I2C_SENSOR
- select I2C_ISA
- help
- If you say yes here you get preliminary support for the hardware
- monitoring functionality of the Winbond W83627EHF Super-I/O chip.
- Only fan and temperature inputs are supported at the moment, while
- the chip does much more than that.
-
- This driver can also be built as a module. If so, the module
- will be called w83627ehf.
-
-endmenu
-
-menu "Other I2C Chip support"
+menu "Miscellaneous I2C Chip support"
depends on I2C
config SENSORS_DS1337
@@ -509,7 +112,6 @@ config TPS65010
This driver can also be built as a module. If so, the module
will be called tps65010.
-
config SENSORS_M41T00
tristate "ST M41T00 RTC chip"
depends on I2C && PPC32
@@ -520,13 +122,16 @@ config SENSORS_M41T00
will be called m41t00.
config SENSORS_MAX6875
- tristate "MAXIM MAX6875 Power supply supervisor"
+ tristate "Maxim MAX6875 Power supply supervisor"
depends on I2C && EXPERIMENTAL
help
- If you say yes here you get support for the MAX6875
- EEPROM-Programmable, Hex/Quad, Power-Suppy Sequencers/Supervisors.
+ If you say yes here you get support for the Maxim MAX6875
+ EEPROM-programmable, quad power-supply sequencer/supervisor.
+
+ This provides an interface to program the EEPROM and reset the chip.
- This provides a interface to program the EEPROM and reset the chip.
+ This driver also supports the Maxim MAX6874 hex power-supply
+ sequencer/supervisor if found at a compatible address.
This driver can also be built as a module. If so, the module
will be called max6875.
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index b5e6d2f84f97..a876dd42b860 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -1,52 +1,16 @@
#
-# Makefile for sensor and "other" I2C chip drivers.
+# Makefile for miscellaneous I2C chip drivers.
#
-# asb100, then w83781d go first, as they can override other drivers' addresses.
-obj-$(CONFIG_SENSORS_ASB100) += asb100.o
-obj-$(CONFIG_SENSORS_W83627HF) += w83627hf.o
-obj-$(CONFIG_SENSORS_W83781D) += w83781d.o
-
-obj-$(CONFIG_SENSORS_ADM1021) += adm1021.o
-obj-$(CONFIG_SENSORS_ADM1025) += adm1025.o
-obj-$(CONFIG_SENSORS_ADM1026) += adm1026.o
-obj-$(CONFIG_SENSORS_ADM1031) += adm1031.o
-obj-$(CONFIG_SENSORS_ADM9240) += adm9240.o
-obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
obj-$(CONFIG_SENSORS_DS1337) += ds1337.o
obj-$(CONFIG_SENSORS_DS1374) += ds1374.o
-obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
obj-$(CONFIG_SENSORS_EEPROM) += eeprom.o
-obj-$(CONFIG_SENSORS_FSCHER) += fscher.o
-obj-$(CONFIG_SENSORS_FSCPOS) += fscpos.o
-obj-$(CONFIG_SENSORS_GL518SM) += gl518sm.o
-obj-$(CONFIG_SENSORS_GL520SM) += gl520sm.o
-obj-$(CONFIG_SENSORS_IT87) += it87.o
-obj-$(CONFIG_SENSORS_LM63) += lm63.o
-obj-$(CONFIG_SENSORS_LM75) += lm75.o
-obj-$(CONFIG_SENSORS_LM77) += lm77.o
-obj-$(CONFIG_SENSORS_LM78) += lm78.o
-obj-$(CONFIG_SENSORS_LM80) += lm80.o
-obj-$(CONFIG_SENSORS_LM83) += lm83.o
-obj-$(CONFIG_SENSORS_LM85) += lm85.o
-obj-$(CONFIG_SENSORS_LM87) += lm87.o
-obj-$(CONFIG_SENSORS_LM90) += lm90.o
-obj-$(CONFIG_SENSORS_LM92) += lm92.o
-obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
-obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
obj-$(CONFIG_SENSORS_RTC8564) += rtc8564.o
-obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
-obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
-obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
-obj-$(CONFIG_SENSORS_VIA686A) += via686a.o
-obj-$(CONFIG_SENSORS_W83627EHF) += w83627ehf.o
-obj-$(CONFIG_SENSORS_W83L785TS) += w83l785ts.o
-
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
diff --git a/drivers/i2c/chips/eeprom.c b/drivers/i2c/chips/eeprom.c
index addf0adc24d4..6ea413f6d5e5 100644
--- a/drivers/i2c/chips/eeprom.c
+++ b/drivers/i2c/chips/eeprom.c
@@ -173,9 +173,6 @@ int eeprom_detect(struct i2c_adapter *adapter, int address, int kind)
| I2C_FUNC_SMBUS_BYTE))
goto exit;
- /* OK. For now, we presume we have a valid client. We now create the
- client structure, even though we cannot fill it completely yet.
- But it allows us to access eeprom_{read,write}_value. */
if (!(data = kmalloc(sizeof(struct eeprom_data), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
diff --git a/drivers/i2c/chips/m41t00.c b/drivers/i2c/chips/m41t00.c
index 5e463c47bfbc..778d7e12859d 100644
--- a/drivers/i2c/chips/m41t00.c
+++ b/drivers/i2c/chips/m41t00.c
@@ -207,7 +207,7 @@ m41t00_detach(struct i2c_client *client)
int rc;
if ((rc = i2c_detach_client(client)) == 0) {
- kfree(i2c_get_clientdata(client));
+ kfree(client);
tasklet_kill(&m41t00_tasklet);
}
return rc;
diff --git a/drivers/i2c/chips/max6875.c b/drivers/i2c/chips/max6875.c
index fe6b150ec4c2..c4f14d9623c4 100644
--- a/drivers/i2c/chips/max6875.c
+++ b/drivers/i2c/chips/max6875.c
@@ -37,7 +37,8 @@
#include <linux/i2c-sensor.h>
/* Addresses to scan */
-static unsigned short normal_i2c[] = {0x50, 0x52, I2C_CLIENT_END};
+/* No address scanned by default, as this could corrupt standard EEPROMS. */
+static unsigned short normal_i2c[] = {I2C_CLIENT_END};
static unsigned int normal_isa[] = {I2C_CLIENT_ISA_END};
/* Insmod parameters */
@@ -369,6 +370,9 @@ static int max6875_detect(struct i2c_adapter *adapter, int address, int kind)
new_client->driver = &max6875_driver;
new_client->flags = 0;
+ /* Prevent 24RF08 corruption */
+ i2c_smbus_write_quick(new_client, 0);
+
/* Setup the user section */
data->blocks[max6875_eeprom_user].type = max6875_eeprom_user;
data->blocks[max6875_eeprom_user].slices = USER_EEPROM_SLICES;
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index c0ac01b60039..280e9638c0f8 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -18,7 +18,6 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#undef DEBUG
#include <linux/config.h>
#include <linux/kernel.h>
@@ -49,11 +48,7 @@
MODULE_DESCRIPTION("TPS6501x Power Management Driver");
MODULE_LICENSE("GPL");
-/* only two addresses possible */
-#define TPS_BASE 0x48
-static unsigned short normal_i2c[] = {
- TPS_BASE,
- I2C_CLIENT_END };
+static unsigned short normal_i2c[] = { 0x48, /* 0x49, */ I2C_CLIENT_END };
static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };
I2C_CLIENT_INSMOD;
@@ -102,7 +97,7 @@ struct tps65010 {
u8 chgstatus, regstatus, chgconf;
u8 nmask1, nmask2;
- /* plus four GPIOs, probably used to switch power */
+ /* not currently tracking GPIO state */
};
#define POWER_POLL_DELAY msecs_to_jiffies(800)
@@ -135,7 +130,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus)
(regstatus & TPS_REG_COVER) ? " uncover" : "",
(regstatus & TPS_REG_UVLO) ? " UVLO" : "",
(regstatus & TPS_REG_NO_CHG) ? " NO_CHG" : "",
- (regstatus & TPS_REG_PG_LD02) ? " ld01_bad" : "",
+ (regstatus & TPS_REG_PG_LD02) ? " ld02_bad" : "",
(regstatus & TPS_REG_PG_LD01) ? " ld01_bad" : "",
(regstatus & TPS_REG_PG_MAIN) ? " main_bad" : "",
(regstatus & TPS_REG_PG_CORE) ? " core_bad" : "");
@@ -143,7 +138,7 @@ static void dbg_regstat(char *buf, size_t len, u8 regstatus)
static void dbg_chgconf(int por, char *buf, size_t len, u8 chgconfig)
{
- char *hibit;
+ const char *hibit;
if (por)
hibit = (chgconfig & TPS_CHARGE_POR)
@@ -295,7 +290,7 @@ static int dbg_show(struct seq_file *s, void *_)
seq_printf(s, "defgpio %02x mask3 %02x\n", value, v2);
for (i = 0; i < 4; i++) {
- if (value & (1 << (4 +i)))
+ if (value & (1 << (4 + i)))
seq_printf(s, " gpio%d-out %s\n", i + 1,
(value & (1 << i)) ? "low" : "hi ");
else
@@ -481,7 +476,7 @@ static int __exit tps65010_detach_client(struct i2c_client *client)
debugfs_remove(tps->file);
if (i2c_detach_client(client) == 0)
kfree(tps);
- the_tps = 0;
+ the_tps = NULL;
return 0;
}
@@ -514,7 +509,6 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
INIT_WORK(&tps->work, tps65010_work, tps);
tps->irq = -1;
tps->client.addr = address;
- i2c_set_clientdata(&tps->client, tps);
tps->client.adapter = bus;
tps->client.driver = &tps65010_driver;
strlcpy(tps->client.name, DRIVER_NAME, I2C_NAME_SIZE);
@@ -523,9 +517,7 @@ tps65010_probe(struct i2c_adapter *bus, int address, int kind)
if (status < 0) {
dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
DRIVER_NAME, address, status);
-fail1:
- kfree(tps);
- return 0;
+ goto fail1;
}
#ifdef CONFIG_ARM
@@ -535,7 +527,7 @@ fail1:
tps->irq = OMAP_GPIO_IRQ(58);
omap_request_gpio(58);
omap_set_gpio_direction(58, 1);
- omap_set_gpio_edge_ctrl(58, OMAP_GPIO_FALLING_EDGE);
+ set_irq_type(tps->irq, IRQT_FALLING);
}
if (machine_is_omap_osk()) {
tps->model = TPS65010;
@@ -543,7 +535,7 @@ fail1:
tps->irq = OMAP_GPIO_IRQ(OMAP_MPUIO(1));
omap_request_gpio(OMAP_MPUIO(1));
omap_set_gpio_direction(OMAP_MPUIO(1), 1);
- omap_set_gpio_edge_ctrl(OMAP_MPUIO(1), OMAP_GPIO_FALLING_EDGE);
+ set_irq_type(tps->irq, IRQT_FALLING);
}
if (machine_is_omap_h3()) {
tps->model = TPS65013;
@@ -633,6 +625,9 @@ fail1:
tps->file = debugfs_create_file(DRIVER_NAME, S_IRUGO, NULL,
tps, DEBUG_FOPS);
return 0;
+fail1:
+ kfree(tps);
+ return 0;
}
static int __init tps65010_scan_bus(struct i2c_adapter *bus)
@@ -645,7 +640,6 @@ static int __init tps65010_scan_bus(struct i2c_adapter *bus)
static struct i2c_driver tps65010_driver = {
.owner = THIS_MODULE,
.name = "tps65010",
- .id = 888, /* FIXME assign "official" value */
.flags = I2C_DF_NOTIFY,
.attach_adapter = tps65010_scan_bus,
.detach_client = __exit_p(tps65010_detach_client),
@@ -744,7 +738,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
if (!the_tps)
return -ENODEV;
- if(led == LED1)
+ if (led == LED1)
offs = 0;
else {
offs = 2;
@@ -753,11 +747,13 @@ int tps65010_set_led(unsigned led, unsigned mode)
down(&the_tps->lock);
- dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
+ pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
+ i2c_smbus_read_byte_data(&the_tps->client,
+ TPS_LED1_ON + offs));
- dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
+ pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
+ i2c_smbus_read_byte_data(&the_tps->client,
+ TPS_LED1_PER + offs));
switch (mode) {
case OFF:
@@ -773,7 +769,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
led_per = 0x08 | (1 << 7);
break;
default:
- printk(KERN_ERR "%s: Wrong mode parameter for tps65010_set_led()\n",
+ printk(KERN_ERR "%s: Wrong mode parameter for set_led()\n",
DRIVER_NAME);
up(&the_tps->lock);
return -EINVAL;
@@ -789,7 +785,7 @@ int tps65010_set_led(unsigned led, unsigned mode)
return status;
}
- dev_dbg (&the_tps->client.dev, "led%i_on 0x%02x\n", led,
+ pr_debug("%s: led%i_on 0x%02x\n", DRIVER_NAME, led,
i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_ON + offs));
status = i2c_smbus_write_byte_data(&the_tps->client,
@@ -802,8 +798,9 @@ int tps65010_set_led(unsigned led, unsigned mode)
return status;
}
- dev_dbg (&the_tps->client.dev, "led%i_per 0x%02x\n", led,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_LED1_PER + offs));
+ pr_debug("%s: led%i_per 0x%02x\n", DRIVER_NAME, led,
+ i2c_smbus_read_byte_data(&the_tps->client,
+ TPS_LED1_PER + offs));
up(&the_tps->lock);
@@ -874,7 +871,7 @@ int tps65010_set_low_pwr(unsigned mode)
if (status != 0)
printk(KERN_ERR "%s: Failed to write vdcdc1 register\n",
- DRIVER_NAME);
+ DRIVER_NAME);
else
pr_debug("%s: vdcdc1 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(&the_tps->client, TPS_VDCDC1));
@@ -900,14 +897,14 @@ int tps65010_config_vregs1(unsigned value)
down(&the_tps->lock);
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
- i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
+ i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
status = i2c_smbus_write_byte_data(&the_tps->client,
TPS_VREGS1, value);
if (status != 0)
printk(KERN_ERR "%s: Failed to write vregs1 register\n",
- DRIVER_NAME);
+ DRIVER_NAME);
else
pr_debug("%s: vregs1 0x%02x\n", DRIVER_NAME,
i2c_smbus_read_byte_data(&the_tps->client, TPS_VREGS1));
@@ -1009,7 +1006,7 @@ static int __init tps_init(void)
msleep(10);
}
-#if defined(CONFIG_ARM)
+#ifdef CONFIG_ARM
if (machine_is_omap_osk()) {
// FIXME: More should be placed in the initialization code
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 51ce268998cd..4fd4f52c8e9b 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -156,7 +156,7 @@ int i2c_add_adapter(struct i2c_adapter *adap)
goto out_unlock;
}
- res = idr_get_new(&i2c_adapter_idr, NULL, &id);
+ res = idr_get_new(&i2c_adapter_idr, adap, &id);
if (res < 0) {
if (res == -EAGAIN)
res = -ENOMEM;
@@ -765,20 +765,15 @@ int i2c_adapter_id(struct i2c_adapter *adap)
struct i2c_adapter* i2c_get_adapter(int id)
{
- struct list_head *item;
struct i2c_adapter *adapter;
down(&core_lists);
- list_for_each(item,&adapters) {
- adapter = list_entry(item, struct i2c_adapter, list);
- if (id == adapter->nr &&
- try_module_get(adapter->owner)) {
- up(&core_lists);
- return adapter;
- }
- }
+ adapter = (struct i2c_adapter *)idr_find(&i2c_adapter_idr, id);
+ if (adapter && !try_module_get(adapter->owner))
+ adapter = NULL;
+
up(&core_lists);
- return NULL;
+ return adapter;
}
void i2c_put_adapter(struct i2c_adapter *adap)
diff --git a/drivers/ide/Kconfig b/drivers/ide/Kconfig
index 0273f124a4f7..5f33df47aa74 100644
--- a/drivers/ide/Kconfig
+++ b/drivers/ide/Kconfig
@@ -606,6 +606,12 @@ config BLK_DEV_IT8172
<http://www.ite.com.tw/ia/brief_it8172bsp.htm>; picture of the
board at <http://www.mvista.com/partners/semiconductor/ite.html>.
+config BLK_DEV_IT821X
+ tristate "IT821X IDE support"
+ help
+ This driver adds support for the ITE 8211 IDE controller and the
+ IT 8212 IDE RAID controller in both RAID and pass-through mode.
+
config BLK_DEV_NS87415
tristate "NS87415 chipset support"
help
diff --git a/drivers/ide/Makefile b/drivers/ide/Makefile
index 5be8ad6dc9ed..cca9c075966d 100644
--- a/drivers/ide/Makefile
+++ b/drivers/ide/Makefile
@@ -20,7 +20,6 @@ ide-core-$(CONFIG_BLK_DEV_CMD640) += pci/cmd640.o
# Core IDE code - must come before legacy
ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
ide-core-$(CONFIG_BLK_DEV_IDEDMA) += ide-dma.o
-ide-core-$(CONFIG_BLK_DEV_IDE_TCQ) += ide-tcq.o
ide-core-$(CONFIG_PROC_FS) += ide-proc.o
ide-core-$(CONFIG_BLK_DEV_IDEPNP) += ide-pnp.o
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 0a31cfda08a0..74af7e074868 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -431,7 +431,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
#if VERBOSE_IDE_CD_ERRORS
{
int i;
- const char *s;
+ const char *s = "bad sense key!";
char buf[80];
printk ("ATAPI device %s:\n", drive->name);
@@ -446,8 +446,6 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
if (sense->sense_key < ARY_LEN(sense_key_texts))
s = sense_key_texts[sense->sense_key];
- else
- s = "bad sense key!";
printk("%s -- (Sense key=0x%02x)\n", s, sense->sense_key);
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index d6f934886b04..f9c1acb4ed6a 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -119,6 +119,10 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
{
unsigned long lba_sects, chs_sects, head, tail;
+ /* No non-LBA info .. so valid! */
+ if (id->cyls == 0)
+ return 1;
+
/*
* The ATA spec tells large drives to return
* C/H/S = 16383/16/63 independent of their size.
diff --git a/drivers/ide/ide-dma.c b/drivers/ide/ide-dma.c
index 2d2eefb610dd..1e1531334c25 100644
--- a/drivers/ide/ide-dma.c
+++ b/drivers/ide/ide-dma.c
@@ -132,7 +132,6 @@ static const struct drive_list_entry drive_blacklist [] = {
{ "SAMSUNG CD-ROM SC-148C", "ALL" },
{ "SAMSUNG CD-ROM SC", "ALL" },
{ "SanDisk SDP3B-64" , "ALL" },
- { "SAMSUNG CD-ROM SN-124", "ALL" },
{ "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" },
{ "_NEC DV5800A", "ALL" },
{ NULL , NULL }
diff --git a/drivers/ide/ide-iops.c b/drivers/ide/ide-iops.c
index 53024942a7eb..b443b04a4c5a 100644
--- a/drivers/ide/ide-iops.c
+++ b/drivers/ide/ide-iops.c
@@ -1181,7 +1181,8 @@ static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi)
pre_reset(drive);
SELECT_DRIVE(drive);
udelay (20);
- hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);
+ hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG);
+ ndelay(400);
hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
hwgroup->polling = 1;
__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
diff --git a/drivers/ide/ide-lib.c b/drivers/ide/ide-lib.c
index 6806d407e9c1..b09a6537c7a8 100644
--- a/drivers/ide/ide-lib.c
+++ b/drivers/ide/ide-lib.c
@@ -487,8 +487,7 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
u8 err = 0;
local_irq_set(flags);
- printk("%s: %s: status=0x%02x", drive->name, msg, stat);
- printk(" { ");
+ printk("%s: %s: status=0x%02x { ", drive->name, msg, stat);
if (stat & BUSY_STAT)
printk("Busy ");
else {
@@ -500,15 +499,13 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
if (stat & INDEX_STAT) printk("Index ");
if (stat & ERR_STAT) printk("Error ");
}
- printk("}");
- printk("\n");
+ 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);
- printk(" { ");
+ printk("%s: %s: error=0x%02x { ", drive->name, msg, err);
if (err & ABRT_ERR) printk("DriveStatusError ");
if (err & ICRC_ERR)
- printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");
+ printk((err & ABRT_ERR) ? "BadCRC " : "BadSector ");
if (err & ECC_ERR) printk("UncorrectableError ");
if (err & ID_ERR) printk("SectorIdNotFound ");
if (err & TRK0_ERR) printk("TrackZeroNotFound ");
@@ -546,8 +543,8 @@ static u8 ide_dump_ata_status(ide_drive_t *drive, const char *msg, u8 stat)
printk(", sector=%llu",
(unsigned long long)HWGROUP(drive)->rq->sector);
}
+ printk("\n");
}
- printk("\n");
ide_dump_opcode(drive);
local_irq_restore(flags);
return err;
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index e884cd4b22fd..242029c9c0ca 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -156,11 +156,13 @@ else \
#if (HD_DELAY > 0)
+
+#include <asm/i8253.h>
+
unsigned long last_req;
unsigned long read_timer(void)
{
- extern spinlock_t i8253_lock;
unsigned long t, flags;
int i;
diff --git a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c
index e20327e54b1a..aac59751e1b4 100644
--- a/drivers/ide/legacy/ide-cs.c
+++ b/drivers/ide/legacy/ide-cs.c
@@ -46,7 +46,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@ static dev_link_t *ide_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ide_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -457,13 +451,49 @@ int ide_event(event_t event, int priority,
return 0;
} /* ide_event */
+static struct pcmcia_device_id ide_ids[] = {
+ PCMCIA_DEVICE_FUNC_ID(4),
+ PCMCIA_DEVICE_MANF_CARD(0x0032, 0x0704),
+ PCMCIA_DEVICE_MANF_CARD(0x00a4, 0x002d),
+ PCMCIA_DEVICE_MANF_CARD(0x2080, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x0045, 0x0401),
+ PCMCIA_DEVICE_PROD_ID123("Caravelle", "PSC-IDE ", "PSC000", 0x8c36137c, 0xd0693ab8, 0x2768a9f0),
+ PCMCIA_DEVICE_PROD_ID123("CDROM", "IDE", "MCD-601p", 0x1b9179ca, 0xede88951, 0x0d902f74),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "IDE CARD", "F1", 0x281f1c5d, 0x1907960c, 0xf7fde8b9),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "CD-ROM", 0x78f308dc, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "PnPIDE", 0x78f308dc, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("CNF CD-M", "CD-ROM", 0x7d93b852, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card", 0xff8c8a45, 0xfe8020c4),
+ PCMCIA_DEVICE_PROD_ID12("Digital Equipment Corporation.", "Digital Mobile Media CD-ROM", 0x17692a66, 0xef1dcbde),
+ PCMCIA_DEVICE_PROD_ID12("EXP", "CD", 0x6f58c983, 0xaae5994f),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "CD-ROM", 0x0a5c52fd, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("EXP ", "PnPIDE", 0x0a5c52fd, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("FREECOM", "PCCARD-IDE", 0x5714cbf7, 0x48e0ab8e),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "IBM17JSSFP20", 0xb569a6e5, 0xf2508753),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "CBIDE2 ", 0x547e66dc, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDE", 0x547e66dc, 0x5c5ab149),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCIDEII", 0x547e66dc, 0xb3662674),
+ PCMCIA_DEVICE_PROD_ID12("LOOKMEET", "CBIDE2 ", 0xe37be2b5, 0x8671043b),
+ PCMCIA_DEVICE_PROD_ID12(" ", "NinjaATA-", 0x3b6e20c8, 0xebe0bd79),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "CD-ROM", 0x281f1c5d, 0x66536591),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "PnPIDE", 0x281f1c5d, 0x0c694728),
+ PCMCIA_DEVICE_PROD_ID12("SHUTTLE TECHNOLOGY LTD.", "PCCARD-IDE/ATAPI Adapter", 0x4a3f0ba0, 0x322560e1),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "MK2001MPL", 0xb4585a1a, 0x3489e003),
+ PCMCIA_DEVICE_PROD_ID12("WIT", "IDE16", 0x244e5994, 0x3e232852),
+ PCMCIA_DEVICE_PROD_ID1("STI Flash", 0xe4a13209),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ide_ids);
+
static struct pcmcia_driver ide_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "ide-cs",
},
.attach = ide_attach,
+ .event = ide_event,
.detach = ide_detach,
+ .id_table = ide_ids,
};
static int __init init_ide_cs(void)
diff --git a/drivers/ide/pci/Makefile b/drivers/ide/pci/Makefile
index 55e6e553e497..af46226c1796 100644
--- a/drivers/ide/pci/Makefile
+++ b/drivers/ide/pci/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o
obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o
#obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o
obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o
+obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o
obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o
obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o
obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o
diff --git a/drivers/ide/pci/alim15x3.c b/drivers/ide/pci/alim15x3.c
index 67efb38a9f6c..6cf49394a80f 100644
--- a/drivers/ide/pci/alim15x3.c
+++ b/drivers/ide/pci/alim15x3.c
@@ -583,7 +583,7 @@ static int ali15x3_dma_setup(ide_drive_t *drive)
* appropriate also sets up the 1533 southbridge.
*/
-static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_ali15x3 (struct pci_dev *dev, const char *name)
{
unsigned long flags;
u8 tmpbyte;
@@ -677,7 +677,7 @@ static unsigned int __init init_chipset_ali15x3 (struct pci_dev *dev, const char
* FIXME: frobs bits that are not defined on newer ALi devicea
*/
-static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_ali15x3 (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ata66 = 0;
@@ -748,7 +748,7 @@ static unsigned int __init ata66_ali15x3 (ide_hwif_t *hwif)
* Initialize the IDE structure side of the ALi 15x3 driver.
*/
-static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
+static void __devinit init_hwif_common_ali15x3 (ide_hwif_t *hwif)
{
hwif->autodma = 0;
hwif->tuneproc = &ali15x3_tune_drive;
@@ -794,7 +794,7 @@ static void __init init_hwif_common_ali15x3 (ide_hwif_t *hwif)
* Sparc systems
*/
-static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
+static void __devinit init_hwif_ali15x3 (ide_hwif_t *hwif)
{
u8 ideic, inmir;
s8 irq_routing_table[] = { -1, 9, 3, 10, 4, 5, 7, 6,
@@ -847,7 +847,7 @@ static void __init init_hwif_ali15x3 (ide_hwif_t *hwif)
* the actual work.
*/
-static void __init init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
+static void __devinit init_dma_ali15x3 (ide_hwif_t *hwif, unsigned long dmabase)
{
if (m5229_revision < 0x20)
return;
diff --git a/drivers/ide/pci/amd74xx.c b/drivers/ide/pci/amd74xx.c
index 4e0f13d1d060..844a6c9fb949 100644
--- a/drivers/ide/pci/amd74xx.c
+++ b/drivers/ide/pci/amd74xx.c
@@ -73,6 +73,7 @@ static struct amd_ide_chip {
{ PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, 0x50, AMD_UDMA_133 },
{ PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, 0x50, AMD_UDMA_133 },
+ { PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, 0x50, AMD_UDMA_133 },
{ 0 }
};
@@ -309,7 +310,7 @@ static int amd74xx_ide_dma_check(ide_drive_t *drive)
* and initialize its drive independent registers.
*/
-static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_amd74xx(struct pci_dev *dev, const char *name)
{
unsigned char t;
unsigned int u;
@@ -413,7 +414,7 @@ static unsigned int __init init_chipset_amd74xx(struct pci_dev *dev, const char
return dev->irq;
}
-static void __init init_hwif_amd74xx(ide_hwif_t *hwif)
+static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
{
int i;
@@ -489,6 +490,7 @@ static ide_pci_device_t amd74xx_chipsets[] __devinitdata = {
/* 13 */ DECLARE_NV_DEV("NFORCE-CK804"),
/* 14 */ DECLARE_NV_DEV("NFORCE-MCP04"),
/* 15 */ DECLARE_NV_DEV("NFORCE-MCP51"),
+ /* 16 */ DECLARE_NV_DEV("NFORCE-MCP55"),
};
static int __devinit amd74xx_probe(struct pci_dev *dev, const struct pci_device_id *id)
@@ -524,6 +526,7 @@ static struct pci_device_id amd74xx_pci_tbl[] = {
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 14 },
{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 15 },
+ { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 16 },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, amd74xx_pci_tbl);
diff --git a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c
index 0381961db263..09269e574b3e 100644
--- a/drivers/ide/pci/cs5530.c
+++ b/drivers/ide/pci/cs5530.c
@@ -217,7 +217,7 @@ static int cs5530_config_dma (ide_drive_t *drive)
* Initialize the cs5530 bridge for reliable IDE DMA operation.
*/
-static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_cs5530 (struct pci_dev *dev, const char *name)
{
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
unsigned long flags;
@@ -308,7 +308,7 @@ static unsigned int __init init_chipset_cs5530 (struct pci_dev *dev, const char
* performs channel-specific pre-initialization before drive probing.
*/
-static void __init init_hwif_cs5530 (ide_hwif_t *hwif)
+static void __devinit init_hwif_cs5530 (ide_hwif_t *hwif)
{
unsigned long basereg;
u32 d0_timings;
diff --git a/drivers/ide/pci/cy82c693.c b/drivers/ide/pci/cy82c693.c
index 80d67e99ccb5..5a33513f3dd1 100644
--- a/drivers/ide/pci/cy82c693.c
+++ b/drivers/ide/pci/cy82c693.c
@@ -391,7 +391,7 @@ static void cy82c693_tune_drive (ide_drive_t *drive, u8 pio)
/*
* this function is called during init and is used to setup the cy82c693 chip
*/
-static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_cy82c693(struct pci_dev *dev, const char *name)
{
if (PCI_FUNC(dev->devfn) != 1)
return 0;
@@ -443,7 +443,7 @@ static unsigned int __init init_chipset_cy82c693(struct pci_dev *dev, const char
/*
* the init function - called for each ide channel once
*/
-static void __init init_hwif_cy82c693(ide_hwif_t *hwif)
+static void __devinit init_hwif_cy82c693(ide_hwif_t *hwif)
{
hwif->autodma = 0;
@@ -467,9 +467,9 @@ static void __init init_hwif_cy82c693(ide_hwif_t *hwif)
hwif->drives[1].autodma = hwif->autodma;
}
-static __initdata ide_hwif_t *primary;
+static __devinitdata ide_hwif_t *primary;
-void __init init_iops_cy82c693(ide_hwif_t *hwif)
+void __devinit init_iops_cy82c693(ide_hwif_t *hwif)
{
if (PCI_FUNC(hwif->pci_dev->devfn) == 1)
primary = hwif;
diff --git a/drivers/ide/pci/generic.c b/drivers/ide/pci/generic.c
index 4565cc311ff3..da46577380f3 100644
--- a/drivers/ide/pci/generic.c
+++ b/drivers/ide/pci/generic.c
@@ -39,6 +39,17 @@
#include <asm/io.h>
+static int ide_generic_all; /* Set to claim all devices */
+
+static int __init ide_generic_all_on(char *unused)
+{
+ ide_generic_all = 1;
+ printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n");
+ return 1;
+}
+
+__setup("all-generic-ide", ide_generic_all_on);
+
static void __devinit init_hwif_generic (ide_hwif_t *hwif)
{
switch(hwif->pci_dev->device) {
@@ -78,79 +89,85 @@ static void __devinit init_hwif_generic (ide_hwif_t *hwif)
static ide_pci_device_t generic_chipsets[] __devinitdata = {
{ /* 0 */
+ .name = "Unknown",
+ .init_hwif = init_hwif_generic,
+ .channels = 2,
+ .autodma = AUTODMA,
+ .bootable = ON_BOARD,
+ },{ /* 1 */
.name = "NS87410",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}},
.bootable = ON_BOARD,
- },{ /* 1 */
+ },{ /* 2 */
.name = "SAMURAI",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 2 */
+ },{ /* 3 */
.name = "HT6565",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 3 */
+ },{ /* 4 */
.name = "UM8673F",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 4 */
+ },{ /* 5 */
.name = "UM8886A",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 5 */
+ },{ /* 6 */
.name = "UM8886BF",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NODMA,
.bootable = ON_BOARD,
- },{ /* 6 */
+ },{ /* 7 */
.name = "HINT_IDE",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = ON_BOARD,
- },{ /* 7 */
+ },{ /* 8 */
.name = "VIA_IDE",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 8 */
+ },{ /* 9 */
.name = "OPTI621V",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 9 */
+ },{ /* 10 */
.name = "VIA8237SATA",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = AUTODMA,
.bootable = OFF_BOARD,
- },{ /* 10 */
+ },{ /* 11 */
.name = "Piccolo0102",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 11 */
+ },{ /* 12 */
.name = "Piccolo0103",
.init_hwif = init_hwif_generic,
.channels = 2,
.autodma = NOAUTODMA,
.bootable = ON_BOARD,
- },{ /* 12 */
+ },{ /* 13 */
.name = "Piccolo0105",
.init_hwif = init_hwif_generic,
.channels = 2,
@@ -174,6 +191,10 @@ static int __devinit generic_init_one(struct pci_dev *dev, const struct pci_devi
u16 command;
int ret = -ENODEV;
+ /* Don't use the generic entry unless instructed to do so */
+ if (id->driver_data == 0 && ide_generic_all == 0)
+ goto out;
+
if (dev->vendor == PCI_VENDOR_ID_UMC &&
dev->device == PCI_DEVICE_ID_UMC_UM8886A &&
(!(PCI_FUNC(dev->devfn) & 1)))
@@ -195,21 +216,23 @@ out:
}
static struct pci_device_id generic_pci_tbl[] = {
- { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
- { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
- { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
- { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
- { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
- { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+ { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+ { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+ { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+ { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6},
+ { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8},
+ { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
#ifdef CONFIG_BLK_DEV_IDE_SATA
- { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9},
+ { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
#endif
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
- { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12},
+ { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13},
+ /* Must come last. If you add entries adjust this table appropriately and the init_one code */
+ { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0},
{ 0, },
};
MODULE_DEVICE_TABLE(pci, generic_pci_tbl);
diff --git a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c
index c8ee0b8c0292..7b64db10d1b0 100644
--- a/drivers/ide/pci/hpt366.c
+++ b/drivers/ide/pci/hpt366.c
@@ -10,6 +10,11 @@
* donation of an ABit BP6 mainboard, processor, and memory acellerated
* development and support.
*
+ *
+ * Highpoint have their own driver (source except for the raid part)
+ * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz
+ * This may be useful to anyone wanting to work on the mainstream hpt IDE.
+ *
* Note that final HPT370 support was done by force extraction of GPL.
*
* - add function for getting/setting power status of drive
@@ -446,44 +451,29 @@ static struct chipset_bus_clock_list_entry sixty_six_base_hpt374[] = {
#define F_LOW_PCI_50 0x2d
#define F_LOW_PCI_66 0x42
-/* FIXME: compare with driver's code before removing */
-#if 0
- if (hpt_minimum_revision(dev, 3)) {
- u8 cbl;
- cbl = inb(iobase + 0x7b);
- outb(cbl | 1, iobase + 0x7b);
- outb(cbl & ~1, iobase + 0x7b);
- cbl = inb(iobase + 0x7a);
- p += sprintf(p, "Cable: ATA-%d"
- " ATA-%d\n",
- (cbl & 0x02) ? 33 : 66,
- (cbl & 0x01) ? 33 : 66);
- p += sprintf(p, "\n");
- }
- {
- u8 c2, c3;
- /* older revs don't have these registers mapped
- * into io space */
- pci_read_config_byte(dev, 0x43, &c0);
- pci_read_config_byte(dev, 0x47, &c1);
- pci_read_config_byte(dev, 0x4b, &c2);
- pci_read_config_byte(dev, 0x4f, &c3);
-
- p += sprintf(p, "Mode: %s %s"
- " %s %s\n",
- (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " :
- (c0 & 0x80) ? "PIO " : "off ",
- (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " :
- (c1 & 0x80) ? "PIO " : "off ",
- (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " :
- (c2 & 0x80) ? "PIO " : "off ",
- (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " :
- (c3 & 0x80) ? "PIO " : "off ");
- }
- }
-#endif
+/*
+ * Hold all the highpoint quirks and revision information in one
+ * place.
+ */
-static u32 hpt_revision (struct pci_dev *dev)
+struct hpt_info
+{
+ u8 max_mode; /* Speeds allowed */
+ int revision; /* Chipset revision */
+ int flags; /* Chipset properties */
+#define PLL_MODE 1
+#define IS_372N 2
+ /* Speed table */
+ struct chipset_bus_clock_list_entry *speed;
+};
+
+/*
+ * This wants fixing so that we do everything not by classrev
+ * (which breaks on the newest chips) but by creating an
+ * enumeration of chip variants and using that
+ */
+
+static __devinit u32 hpt_revision (struct pci_dev *dev)
{
u32 class_rev;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev);
@@ -507,37 +497,33 @@ static u32 hpt_revision (struct pci_dev *dev)
return class_rev;
}
-static u32 hpt_minimum_revision (struct pci_dev *dev, int revision)
-{
- unsigned int class_rev = hpt_revision(dev);
- revision--;
- return ((int) (class_rev > revision) ? 1 : 0);
-}
-
static int check_in_drive_lists(ide_drive_t *drive, const char **list);
static u8 hpt3xx_ratemask (ide_drive_t *drive)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 mode = 0;
- if (hpt_minimum_revision(dev, 8)) { /* HPT374 */
+ /* FIXME: TODO - move this to set info->mode once at boot */
+
+ if (info->revision >= 8) { /* HPT374 */
mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */
+ } else if (info->revision >= 7) { /* HPT371 */
mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */
+ } else if (info->revision >= 6) { /* HPT302 */
mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */
+ } else if (info->revision >= 5) { /* HPT372 */
mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3;
- } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */
+ } else if (info->revision >= 4) { /* HPT370A */
mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
- } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */
+ } else if (info->revision >= 3) { /* HPT370 */
mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2;
mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode;
} else { /* HPT366 and HPT368 */
mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2;
}
- if (!eighty_ninty_three(drive) && (mode))
+ if (!eighty_ninty_three(drive) && mode)
mode = min(mode, (u8)1);
return mode;
}
@@ -549,7 +535,8 @@ static u8 hpt3xx_ratemask (ide_drive_t *drive)
static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 mode = hpt3xx_ratemask(drive);
if (drive->media != ide_disk)
@@ -561,7 +548,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
break;
case 0x03:
speed = min(speed, (u8)XFER_UDMA_5);
- if (hpt_minimum_revision(dev, 5))
+ if (info->revision >= 5)
break;
if (check_in_drive_lists(drive, bad_ata100_5))
speed = min(speed, (u8)XFER_UDMA_4);
@@ -571,7 +558,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
/*
* CHECK ME, Does this need to be set to 5 ??
*/
- if (hpt_minimum_revision(dev, 3))
+ if (info->revision >= 3)
break;
if ((check_in_drive_lists(drive, bad_ata66_4)) ||
(!(HPT366_ALLOW_ATA66_4)))
@@ -585,7 +572,7 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed)
/*
* CHECK ME, Does this need to be set to 5 ??
*/
- if (hpt_minimum_revision(dev, 3))
+ if (info->revision >= 3)
break;
if (check_in_drive_lists(drive, bad_ata33))
speed = min(speed, (u8)XFER_MW_DMA_2);
@@ -624,11 +611,12 @@ static unsigned int pci_bus_clock_list (u8 speed, struct chipset_bus_clock_list_
static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40;
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (hwif->channel) ? 0x55 : 0x51;
u8 drive_fast = 0;
u32 reg1 = 0, reg2 = 0;
@@ -636,16 +624,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
* Disable the "fast interrupt" prediction.
*/
pci_read_config_byte(dev, regfast, &drive_fast);
-#if 0
- if (drive_fast & 0x02)
- pci_write_config_byte(dev, regfast, drive_fast & ~0x20);
-#else
if (drive_fast & 0x80)
pci_write_config_byte(dev, regfast, drive_fast & ~0x80);
-#endif
- reg2 = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev));
+ reg2 = pci_bus_clock_list(speed, info->speed);
+
/*
* Disable on-chip PIO FIFO/buffer
* (to avoid problems handling I/O errors later)
@@ -665,10 +648,11 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
u8 drive_pci = 0x40 + (drive->dn * 4);
u8 new_fast = 0, drive_fast = 0;
u32 list_conf = 0, drive_conf = 0;
@@ -693,17 +677,13 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
if (new_fast != drive_fast)
pci_write_config_byte(dev, regfast, new_fast);
- list_conf = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *)
- pci_get_drvdata(dev));
+ list_conf = pci_bus_clock_list(speed, info->speed);
pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
- if (speed < XFER_MW_DMA_0) {
+ if (speed < XFER_MW_DMA_0)
list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */
- }
-
pci_write_config_dword(dev, drive_pci, list_conf);
return ide_config_drive_speed(drive, speed);
@@ -711,10 +691,11 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 speed = hpt3xx_ratefilter(drive, xferspeed);
-// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed);
- u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51;
+ u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51;
u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4);
u32 list_conf = 0, drive_conf = 0;
u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000;
@@ -726,10 +707,8 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
pci_read_config_byte(dev, regfast, &drive_fast);
drive_fast &= ~0x07;
pci_write_config_byte(dev, regfast, drive_fast);
-
- list_conf = pci_bus_clock_list(speed,
- (struct chipset_bus_clock_list_entry *)
- pci_get_drvdata(dev));
+
+ list_conf = pci_bus_clock_list(speed, info->speed);
pci_read_config_dword(dev, drive_pci, &drive_conf);
list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask);
if (speed < XFER_MW_DMA_0)
@@ -741,19 +720,14 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed)
static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
- if (hpt_minimum_revision(dev, 8))
+ if (info->revision >= 8)
return hpt372_tune_chipset(drive, speed); /* not a typo */
-#if 0
- else if (hpt_minimum_revision(dev, 7))
- hpt371_tune_chipset(drive, speed);
- else if (hpt_minimum_revision(dev, 6))
- hpt302_tune_chipset(drive, speed);
-#endif
- else if (hpt_minimum_revision(dev, 5))
+ else if (info->revision >= 5)
return hpt372_tune_chipset(drive, speed);
- else if (hpt_minimum_revision(dev, 3))
+ else if (info->revision >= 3)
return hpt370_tune_chipset(drive, speed);
else /* hpt368: hpt_minimum_revision(dev, 2) */
return hpt36x_tune_chipset(drive, speed);
@@ -779,8 +753,14 @@ static void hpt3xx_tune_drive (ide_drive_t *drive, u8 pio)
static int config_chipset_for_dma (ide_drive_t *drive)
{
u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive));
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
- if (!(speed))
+ if (!speed)
+ return 0;
+
+ /* If we don't have any timings we can't do a lot */
+ if (info->speed == NULL)
return 0;
(void) hpt3xx_tune_chipset(drive, speed);
@@ -794,7 +774,7 @@ static int hpt3xx_quirkproc (ide_drive_t *drive)
static void hpt3xx_intrproc (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
if (drive->quirk_list)
return;
@@ -804,24 +784,26 @@ static void hpt3xx_intrproc (ide_drive_t *drive)
static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
{
- struct pci_dev *dev = HWIF(drive)->pci_dev;
+ ide_hwif_t *hwif = drive->hwif;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct pci_dev *dev = hwif->pci_dev;
if (drive->quirk_list) {
- if (hpt_minimum_revision(dev,3)) {
+ if (info->revision >= 3) {
u8 reg5a = 0;
pci_read_config_byte(dev, 0x5a, &reg5a);
if (((reg5a & 0x10) >> 4) != mask)
pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10));
} else {
if (mask) {
- disable_irq(HWIF(drive)->irq);
+ disable_irq(hwif->irq);
} else {
- enable_irq(HWIF(drive)->irq);
+ enable_irq(hwif->irq);
}
}
} else {
if (IDE_CONTROL_REG)
- HWIF(drive)->OUTB(mask ? (drive->ctl | 2) :
+ hwif->OUTB(mask ? (drive->ctl | 2) :
(drive->ctl & ~2),
IDE_CONTROL_REG);
}
@@ -829,12 +811,12 @@ static void hpt3xx_maskproc (ide_drive_t *drive, int mask)
static int hpt366_config_drive_xfer_rate (ide_drive_t *drive)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
struct hd_driveid *id = drive->id;
drive->init_speed = 0;
- if (id && (id->capability & 1) && drive->autodma) {
+ if ((id->capability & 1) && drive->autodma) {
if (ide_use_dma(drive)) {
if (config_chipset_for_dma(drive))
@@ -868,15 +850,6 @@ static int hpt366_ide_dma_lostirq (ide_drive_t *drive)
drive->name, __FUNCTION__, reg50h, reg52h, reg5ah);
if (reg5ah & 0x10)
pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
-#if 0
- /* how about we flush and reset, mmmkay? */
- pci_write_config_byte(dev, 0x51, 0x1F);
- /* fall through to a reset */
- case dma_start:
- case ide_dma_end:
- /* reset the chips state over and over.. */
- pci_write_config_byte(dev, 0x51, 0x13);
-#endif
return __ide_dma_lostirq(drive);
}
@@ -919,7 +892,7 @@ static void hpt370_lostirq_timeout (ide_drive_t *drive)
u8 dma_stat = 0, dma_cmd = 0;
pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo);
- printk("%s: %d bytes in FIFO\n", drive->name, bfifo);
+ printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo);
hpt370_clear_engine(drive);
/* get dma command mode */
dma_cmd = hwif->INB(hwif->dma_command);
@@ -1047,15 +1020,6 @@ static void hpt372n_rw_disk(ide_drive_t *drive, struct request *rq)
static void hpt3xx_reset (ide_drive_t *drive)
{
-#if 0
- unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4);
- u8 reset = (HWIF(drive)->channel) ? 0x80 : 0x40;
- u8 reg59h = 0;
-
- pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, &reg59h);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset);
- pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h);
-#endif
}
static int hpt3xx_tristate (ide_drive_t * drive, int state)
@@ -1065,8 +1029,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;
-// hwif->bus_state = state;
-
pci_read_config_byte(dev, 0x59, &reg59h);
pci_read_config_byte(dev, state_reg, &regXXh);
@@ -1093,7 +1055,7 @@ static int hpt3xx_tristate (ide_drive_t * drive, int state)
#define TRISTATE_BIT 0x8000
static int hpt370_busproc(ide_drive_t * drive, int state)
{
- ide_hwif_t *hwif = HWIF(drive);
+ ide_hwif_t *hwif = drive->hwif;
struct pci_dev *dev = hwif->pci_dev;
u8 tristate = 0, resetmask = 0, bus_reg = 0;
u16 tri_reg;
@@ -1148,33 +1110,44 @@ static int hpt370_busproc(ide_drive_t * drive, int state)
return 0;
}
-static int __devinit init_hpt37x(struct pci_dev *dev)
+static void __devinit hpt366_clocking(ide_hwif_t *hwif)
{
+ u32 reg1 = 0;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+
+ pci_read_config_dword(hwif->pci_dev, 0x40, &reg1);
+
+ /* detect bus speed by looking at control reg timing: */
+ switch((reg1 >> 8) & 7) {
+ case 5:
+ info->speed = forty_base_hpt366;
+ break;
+ case 9:
+ info->speed = twenty_five_base_hpt366;
+ break;
+ case 7:
+ default:
+ info->speed = thirty_three_base_hpt366;
+ break;
+ }
+}
+
+static void __devinit hpt37x_clocking(ide_hwif_t *hwif)
+{
+ struct hpt_info *info = ide_get_hwifdata(hwif);
+ struct pci_dev *dev = hwif->pci_dev;
int adjust, i;
u16 freq;
u32 pll;
u8 reg5bh;
- u8 reg5ah = 0;
- unsigned long dmabase = pci_resource_start(dev, 4);
- u8 did, rid;
- int is_372n = 0;
- pci_read_config_byte(dev, 0x5a, &reg5ah);
- /* interrupt force enable */
- pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
-
- if(dmabase)
- {
- did = inb(dmabase + 0x22);
- rid = inb(dmabase + 0x28);
-
- if((did == 4 && rid == 6) || (did == 5 && rid > 1))
- is_372n = 1;
- }
-
/*
* default to pci clock. make sure MA15/16 are set to output
- * to prevent drives having problems with 40-pin cables.
+ * to prevent drives having problems with 40-pin cables. Needed
+ * for some drives such as IBM-DTLA which will not enter ready
+ * state on reset when PDIAG is a input.
+ *
+ * ToDo: should we set 0x21 when using PLL mode ?
*/
pci_write_config_byte(dev, 0x5b, 0x23);
@@ -1197,9 +1170,7 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
* Currently we always set up the PLL for the 372N
*/
- pci_set_drvdata(dev, NULL);
-
- if(is_372n)
+ if(info->flags & IS_372N)
{
printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n");
if(freq < 0x55)
@@ -1227,39 +1198,38 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
pll = F_LOW_PCI_66;
if (pll == F_LOW_PCI_33) {
- if (hpt_minimum_revision(dev,8))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt374);
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = thirty_three_base_hpt374;
+ else if (info->revision >= 5)
+ info->speed = thirty_three_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = thirty_three_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt370);
- printk("HPT37X: using 33MHz PCI clock\n");
+ info->speed = thirty_three_base_hpt370;
+ printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n");
} else if (pll == F_LOW_PCI_40) {
/* Unsupported */
} else if (pll == F_LOW_PCI_50) {
- if (hpt_minimum_revision(dev,8))
- 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))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = fifty_base_hpt370a;
+ else if (info->revision >= 5)
+ info->speed = fifty_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = fifty_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
- printk("HPT37X: using 50MHz PCI clock\n");
+ info->speed = fifty_base_hpt370a;
+ printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n");
} else {
- if (hpt_minimum_revision(dev,8))
- {
+ if (info->revision >= 8) {
printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n");
}
- else if (hpt_minimum_revision(dev,5))
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt372);
- else if (hpt_minimum_revision(dev,4))
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a);
+ else if (info->revision >= 5)
+ info->speed = sixty_six_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = sixty_six_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) sixty_six_base_hpt370);
- printk("HPT37X: using 66MHz PCI clock\n");
+ info->speed = sixty_six_base_hpt370;
+ printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n");
}
}
@@ -1269,11 +1239,19 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
* result in slow reads when using a 33MHz PCI clock. we also
* don't like to use the PLL because it will cause glitches
* on PRST/SRST when the HPT state engine gets reset.
+ *
+ * ToDo: Use 66MHz PLL when ATA133 devices are present on a
+ * 372 device so we can get ATA133 support
*/
- if (pci_get_drvdata(dev))
+ if (info->speed)
goto init_hpt37X_done;
+
+ info->flags |= PLL_MODE;
/*
+ * FIXME: make this work correctly, esp with 372N as per
+ * reference driver code.
+ *
* adjust PLL based upon PCI clock, enable it, and wait for
* stabilization.
*/
@@ -1298,14 +1276,14 @@ static int __devinit init_hpt37x(struct pci_dev *dev)
pci_write_config_dword(dev, 0x5c,
pll & ~0x100);
pci_write_config_byte(dev, 0x5b, 0x21);
- if (hpt_minimum_revision(dev,8))
- 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))
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ if (info->revision >= 8)
+ info->speed = fifty_base_hpt370a;
+ else if (info->revision >= 5)
+ info->speed = fifty_base_hpt372;
+ else if (info->revision >= 4)
+ info->speed = fifty_base_hpt370a;
else
- pci_set_drvdata(dev, (void *) fifty_base_hpt370a);
+ info->speed = fifty_base_hpt370a;
printk("HPT37X: using 50MHz internal PLL\n");
goto init_hpt37X_done;
}
@@ -1318,10 +1296,22 @@ pll_recal:
}
init_hpt37X_done:
+ if (!info->speed)
+ printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n",
+ (info->flags & IS_372N)?"N":"", pll, freq);
/* reset state engine */
pci_write_config_byte(dev, 0x50, 0x37);
pci_write_config_byte(dev, 0x54, 0x37);
udelay(100);
+}
+
+static int __devinit init_hpt37x(struct pci_dev *dev)
+{
+ u8 reg5ah;
+
+ pci_read_config_byte(dev, 0x5a, &reg5ah);
+ /* interrupt force enable */
+ pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10));
return 0;
}
@@ -1338,59 +1328,27 @@ static int __devinit init_hpt366(struct pci_dev *dev)
pci_write_config_byte(dev, 0x51, drive_fast & ~0x80);
pci_read_config_dword(dev, 0x40, &reg1);
- /* detect bus speed by looking at control reg timing: */
- switch((reg1 >> 8) & 7) {
- case 5:
- pci_set_drvdata(dev, (void *) forty_base_hpt366);
- break;
- case 9:
- pci_set_drvdata(dev, (void *) twenty_five_base_hpt366);
- break;
- case 7:
- default:
- pci_set_drvdata(dev, (void *) thirty_three_base_hpt366);
- break;
- }
-
- if (!pci_get_drvdata(dev))
- {
- printk(KERN_ERR "hpt366: unknown bus timing.\n");
- pci_set_drvdata(dev, NULL);
- }
return 0;
}
static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name)
{
int ret = 0;
- u8 test = 0;
-
+ /* FIXME: Not portable */
if (dev->resource[PCI_ROM_RESOURCE].start)
pci_write_config_byte(dev, PCI_ROM_ADDRESS,
dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE);
- pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test);
- if (test != (L1_CACHE_BYTES / 4))
- pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
- (L1_CACHE_BYTES / 4));
-
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test);
- if (test != 0x78)
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4));
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78);
+ pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
+ pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
- pci_read_config_byte(dev, PCI_MIN_GNT, &test);
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_MIN_GNT, 0x08);
-
- pci_read_config_byte(dev, PCI_MAX_LAT, &test);
- if (test != 0x08)
- pci_write_config_byte(dev, PCI_MAX_LAT, 0x08);
-
- if (hpt_minimum_revision(dev, 3)) {
+ if (hpt_revision(dev) >= 3)
ret = init_hpt37x(dev);
- } else {
- ret =init_hpt366(dev);
- }
+ else
+ ret = init_hpt366(dev);
+
if (ret)
return ret;
@@ -1400,27 +1358,16 @@ static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const cha
static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02;
- u8 did, rid;
- unsigned long dmabase = hwif->dma_base;
- int is_372n = 0;
- if(dmabase)
- {
- did = inb(dmabase + 0x22);
- rid = inb(dmabase + 0x28);
-
- if((did == 4 && rid == 6) || (did == 5 && rid > 1))
- is_372n = 1;
- }
-
hwif->tuneproc = &hpt3xx_tune_drive;
hwif->speedproc = &hpt3xx_tune_chipset;
hwif->quirkproc = &hpt3xx_quirkproc;
hwif->intrproc = &hpt3xx_intrproc;
hwif->maskproc = &hpt3xx_maskproc;
- if(is_372n)
+ if(info->flags & IS_372N)
hwif->rw_disk = &hpt372n_rw_disk;
/*
@@ -1428,7 +1375,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
* address lines to access an external eeprom. To read valid
* cable detect state the pins must be enabled as inputs.
*/
- if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) {
+ if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) {
/*
* HPT374 PCI function 1
* - set bit 15 of reg 0x52 to enable TCBLID as input
@@ -1443,7 +1390,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
pci_read_config_byte(dev, 0x5a, &ata66);
pci_write_config_word(dev, 0x52, mcr3);
pci_write_config_word(dev, 0x56, mcr6);
- } else if (hpt_minimum_revision(dev, 3)) {
+ } else if (info->revision >= 3) {
/*
* HPT370/372 and 374 pcifn 0
* - clear bit 0 of 0x5b to enable P/SCBLID as inputs
@@ -1470,7 +1417,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->serialized = hwif->mate->serialized = 1;
#endif
- if (hpt_minimum_revision(dev,3)) {
+ if (info->revision >= 3) {
u8 reg5ah = 0;
pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10);
/*
@@ -1480,8 +1427,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
*/
hwif->resetproc = &hpt3xx_reset;
hwif->busproc = &hpt370_busproc;
-// hwif->drives[0].autotune = hwif->drives[1].autotune = 1;
- } else if (hpt_minimum_revision(dev,2)) {
+ } else if (info->revision >= 2) {
hwif->resetproc = &hpt3xx_reset;
hwif->busproc = &hpt3xx_tristate;
} else {
@@ -1502,18 +1448,18 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
hwif->udma_four = ((ata66 & regmask) ? 0 : 1);
hwif->ide_dma_check = &hpt366_config_drive_xfer_rate;
- if (hpt_minimum_revision(dev,8)) {
+ if (info->revision >= 8) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (hpt_minimum_revision(dev,5)) {
+ } else if (info->revision >= 5) {
hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq;
hwif->ide_dma_end = &hpt374_ide_dma_end;
- } else if (hpt_minimum_revision(dev,3)) {
+ } else if (info->revision >= 3) {
hwif->dma_start = &hpt370_ide_dma_start;
hwif->ide_dma_end = &hpt370_ide_dma_end;
hwif->ide_dma_timeout = &hpt370_ide_dma_timeout;
hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq;
- } else if (hpt_minimum_revision(dev,2))
+ } else if (info->revision >= 2)
hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
else
hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq;
@@ -1526,6 +1472,7 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif)
static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
{
+ struct hpt_info *info = ide_get_hwifdata(hwif);
u8 masterdma = 0, slavedma = 0;
u8 dma_new = 0, dma_old = 0;
u8 primary = hwif->channel ? 0x4b : 0x43;
@@ -1535,8 +1482,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
if (!dmabase)
return;
- if(pci_get_drvdata(hwif->pci_dev) == NULL)
- {
+ if(info->speed == NULL) {
printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n");
return;
}
@@ -1559,6 +1505,40 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase)
ide_setup_dma(hwif, dmabase, 8);
}
+/*
+ * We "borrow" this hook in order to set the data structures
+ * up early enough before dma or init_hwif calls are made.
+ */
+
+static void __devinit init_iops_hpt366(ide_hwif_t *hwif)
+{
+ struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL);
+ unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4);
+ u8 did, rid;
+
+ if(info == NULL) {
+ printk(KERN_WARNING "hpt366: out of memory.\n");
+ return;
+ }
+ memset(info, 0, sizeof(struct hpt_info));
+ ide_set_hwifdata(hwif, info);
+
+ if(dmabase) {
+ did = inb(dmabase + 0x22);
+ rid = inb(dmabase + 0x28);
+
+ if((did == 4 && rid == 6) || (did == 5 && rid > 1))
+ info->flags |= IS_372N;
+ }
+
+ info->revision = hpt_revision(hwif->pci_dev);
+
+ if (info->revision >= 3)
+ hpt37x_clocking(hwif);
+ else
+ hpt366_clocking(hwif);
+}
+
static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d)
{
struct pci_dev *findev = NULL;
@@ -1646,6 +1626,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT366",
.init_setup = init_setup_hpt366,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1656,6 +1637,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT372A",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1665,6 +1647,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT302",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1674,6 +1657,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT371",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2,
@@ -1683,6 +1667,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT374",
.init_setup = init_setup_hpt374,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
@@ -1692,6 +1677,7 @@ static ide_pci_device_t hpt366_chipsets[] __devinitdata = {
.name = "HPT372N",
.init_setup = init_setup_hpt37x,
.init_chipset = init_chipset_hpt366,
+ .init_iops = init_iops_hpt366,
.init_hwif = init_hwif_hpt366,
.init_dma = init_dma_hpt366,
.channels = 2, /* 4 */
diff --git a/drivers/ide/pci/it8172.c b/drivers/ide/pci/it8172.c
index 631927cf17d4..93462926b9d5 100644
--- a/drivers/ide/pci/it8172.c
+++ b/drivers/ide/pci/it8172.c
@@ -216,7 +216,7 @@ fast_ata_pio:
return 0;
}
-static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_it8172 (struct pci_dev *dev, const char *name)
{
unsigned char progif;
@@ -230,7 +230,7 @@ static unsigned int __init init_chipset_it8172 (struct pci_dev *dev, const char
}
-static void __init init_hwif_it8172 (ide_hwif_t *hwif)
+static void __devinit init_hwif_it8172 (ide_hwif_t *hwif)
{
struct pci_dev* dev = hwif->pci_dev;
unsigned long cmdBase, ctrlBase;
diff --git a/drivers/ide/pci/it821x.c b/drivers/ide/pci/it821x.c
new file mode 100644
index 000000000000..e440036e651f
--- /dev/null
+++ b/drivers/ide/pci/it821x.c
@@ -0,0 +1,812 @@
+
+/*
+ * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004
+ *
+ * Copyright (C) 2004 Red Hat <alan@redhat.com>
+ *
+ * May be copied or modified under the terms of the GNU General Public License
+ * Based in part on the ITE vendor provided SCSI driver.
+ *
+ * Documentation available from
+ * http://www.ite.com.tw/pc/IT8212F_V04.pdf
+ * Some other documents are NDA.
+ *
+ * The ITE8212 isn't exactly a standard IDE controller. It has two
+ * modes. In pass through mode then it is an IDE controller. In its smart
+ * mode its actually quite a capable hardware raid controller disguised
+ * as an IDE controller. Smart mode only understands DMA read/write and
+ * identify, none of the fancier commands apply. The IT8211 is identical
+ * in other respects but lacks the raid mode.
+ *
+ * Errata:
+ * o Rev 0x10 also requires master/slave hold the same DMA timings and
+ * cannot do ATAPI MWDMA.
+ * o The identify data for raid volumes lacks CHS info (technically ok)
+ * but also fails to set the LBA28 and other bits. We fix these in
+ * the IDE probe quirk code.
+ * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode
+ * raid then the controller firmware dies
+ * o Smart mode without RAID doesn't clear all the necessary identify
+ * bits to reduce the command set to the one used
+ *
+ * This has a few impacts on the driver
+ * - In pass through mode we do all the work you would expect
+ * - In smart mode the clocking set up is done by the controller generally
+ * but we must watch the other limits and filter.
+ * - There are a few extra vendor commands that actually talk to the
+ * controller but only work PIO with no IRQ.
+ *
+ * Vendor areas of the identify block in smart mode are used for the
+ * timing and policy set up. Each HDD in raid mode also has a serial
+ * block on the disk. The hardware extra commands are get/set chip status,
+ * rebuild, get rebuild status.
+ *
+ * In Linux the driver supports pass through mode as if the device was
+ * just another IDE controller. If the smart mode is running then
+ * volumes are managed by the controller firmware and each IDE "disk"
+ * is a raid volume. Even more cute - the controller can do automated
+ * hotplug and rebuild.
+ *
+ * The pass through controller itself is a little demented. It has a
+ * flaw that it has a single set of PIO/MWDMA timings per channel so
+ * non UDMA devices restrict each others performance. It also has a
+ * single clock source per channel so mixed UDMA100/133 performance
+ * isn't perfect and we have to pick a clock. Thankfully none of this
+ * matters in smart mode. ATAPI DMA is not currently supported.
+ *
+ * It seems the smart mode is a win for RAID1/RAID10 but otherwise not.
+ *
+ * TODO
+ * - ATAPI UDMA is ok but not MWDMA it seems
+ * - RAID configuration ioctls
+ * - Move to libata once it grows up
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/hdreg.h>
+#include <linux/ide.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+
+struct it821x_dev
+{
+ unsigned int smart:1, /* Are we in smart raid mode */
+ timing10:1; /* Rev 0x10 */
+ u8 clock_mode; /* 0, ATA_50 or ATA_66 */
+ u8 want[2][2]; /* Mode/Pri log for master slave */
+ /* We need these for switching the clock when DMA goes on/off
+ The high byte is the 66Mhz timing */
+ u16 pio[2]; /* Cached PIO values */
+ u16 mwdma[2]; /* Cached MWDMA values */
+ u16 udma[2]; /* Cached UDMA values (per drive) */
+};
+
+#define ATA_66 0
+#define ATA_50 1
+#define ATA_ANY 2
+
+#define UDMA_OFF 0
+#define MWDMA_OFF 0
+
+/*
+ * We allow users to force the card into non raid mode without
+ * flashing the alternative BIOS. This is also neccessary right now
+ * for embedded platforms that cannot run a PC BIOS but are using this
+ * device.
+ */
+
+static int it8212_noraid;
+
+/**
+ * it821x_program - program the PIO/MWDMA registers
+ * @drive: drive to tune
+ *
+ * Program the PIO/MWDMA timing for this channel according to the
+ * current clock.
+ */
+
+static void it821x_program(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ u8 conf;
+
+ /* Program PIO/MWDMA timing bits */
+ if(itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf);
+}
+
+/**
+ * it821x_program_udma - program the UDMA registers
+ * @drive: drive to tune
+ *
+ * Program the UDMA timing for this drive according to the
+ * current clock.
+ */
+
+static void it821x_program_udma(ide_drive_t *drive, u16 timing)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int channel = hwif->channel;
+ int unit = drive->select.b.unit;
+ u8 conf;
+
+ /* Program UDMA timing bits */
+ if(itdev->clock_mode == ATA_66)
+ conf = timing >> 8;
+ else
+ conf = timing & 0xFF;
+ if(itdev->timing10 == 0)
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf);
+ else {
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf);
+ pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf);
+ }
+}
+
+
+/**
+ * it821x_clock_strategy
+ * @hwif: hardware interface
+ *
+ * Select between the 50 and 66Mhz base clocks to get the best
+ * results for this interface.
+ */
+
+static void it821x_clock_strategy(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+
+ u8 unit = drive->select.b.unit;
+ ide_drive_t *pair = &hwif->drives[1-unit];
+
+ int clock, altclock;
+ u8 v;
+ int sel = 0;
+
+ if(itdev->want[0][0] > itdev->want[1][0]) {
+ clock = itdev->want[0][1];
+ altclock = itdev->want[1][1];
+ } else {
+ clock = itdev->want[1][1];
+ altclock = itdev->want[0][1];
+ }
+
+ /* Master doesn't care does the slave ? */
+ if(clock == ATA_ANY)
+ clock = altclock;
+
+ /* Nobody cares - keep the same clock */
+ if(clock == ATA_ANY)
+ return;
+ /* No change */
+ if(clock == itdev->clock_mode)
+ return;
+
+ /* Load this into the controller ? */
+ if(clock == ATA_66)
+ itdev->clock_mode = ATA_66;
+ else {
+ itdev->clock_mode = ATA_50;
+ sel = 1;
+ }
+ pci_read_config_byte(hwif->pci_dev, 0x50, &v);
+ v &= ~(1 << (1 + hwif->channel));
+ v |= sel << (1 + hwif->channel);
+ pci_write_config_byte(hwif->pci_dev, 0x50, v);
+
+ /*
+ * Reprogram the UDMA/PIO of the pair drive for the switch
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if(pair && itdev->udma[1-unit] != UDMA_OFF) {
+ it821x_program_udma(pair, itdev->udma[1-unit]);
+ it821x_program(pair, itdev->pio[1-unit]);
+ }
+ /*
+ * Reprogram the UDMA/PIO of our drive for the switch.
+ * MWDMA will be dealt with by the dma switcher
+ */
+ if(itdev->udma[unit] != UDMA_OFF) {
+ it821x_program_udma(drive, itdev->udma[unit]);
+ it821x_program(drive, itdev->pio[unit]);
+ }
+}
+
+/**
+ * it821x_ratemask - Compute available modes
+ * @drive: IDE drive
+ *
+ * Compute the available speeds for the devices on the interface. This
+ * is all modes to ATA133 clipped by drive cable setup.
+ */
+
+static u8 it821x_ratemask (ide_drive_t *drive)
+{
+ u8 mode = 4;
+ if (!eighty_ninty_three(drive))
+ mode = min(mode, (u8)1);
+ return mode;
+}
+
+/**
+ * it821x_tuneproc - tune a drive
+ * @drive: drive to tune
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller. By the time we are called the mode has been
+ * modified as neccessary to handle the absence of seperate
+ * master/slave timers for MWDMA/PIO.
+ *
+ * This code is only used in pass through mode.
+ */
+
+static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+
+ /* Spec says 89 ref driver uses 88 */
+ static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 };
+ static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY };
+
+ if(itdev->smart)
+ return;
+
+ /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */
+ itdev->want[unit][1] = pio_want[mode_wanted];
+ itdev->want[unit][0] = 1; /* PIO is lowest priority */
+ itdev->pio[unit] = pio[mode_wanted];
+ it821x_clock_strategy(drive);
+ it821x_program(drive, itdev->pio[unit]);
+}
+
+/**
+ * it821x_tune_mwdma - tune a channel for MWDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing MWDMA in pass through mode. The caller
+ * must manage the whole lack of per device MWDMA/PIO timings and
+ * the shared MWDMA/PIO timing register.
+ */
+
+static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ int channel = hwif->channel;
+ u8 conf;
+
+ static u16 dma[] = { 0x8866, 0x3222, 0x3121 };
+ static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY };
+
+ itdev->want[unit][1] = mwdma_want[mode_wanted];
+ itdev->want[unit][0] = 2; /* MWDMA is low priority */
+ itdev->mwdma[unit] = dma[mode_wanted];
+ itdev->udma[unit] = UDMA_OFF;
+
+ /* UDMA bits off - Revision 0x10 do them in pairs */
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(itdev->timing10)
+ conf |= channel ? 0x60: 0x18;
+ else
+ conf |= 1 << (3 + 2 * channel + unit);
+ pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ /* FIXME: do we need to program this ? */
+ /* it821x_program(drive, itdev->mwdma[unit]); */
+}
+
+/**
+ * it821x_tune_udma - tune a channel for UDMA
+ * @drive: drive to set up
+ * @mode_wanted: the target operating mode
+ *
+ * Load the timing settings for this device mode into the
+ * controller when doing UDMA modes in pass through.
+ */
+
+static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ int channel = hwif->channel;
+ u8 conf;
+
+ static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 };
+ static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 };
+
+ itdev->want[unit][1] = udma_want[mode_wanted];
+ itdev->want[unit][0] = 3; /* UDMA is high priority */
+ itdev->mwdma[unit] = MWDMA_OFF;
+ itdev->udma[unit] = udma[mode_wanted];
+ if(mode_wanted >= 5)
+ itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */
+
+ /* UDMA on. Again revision 0x10 must do the pair */
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(itdev->timing10)
+ conf &= channel ? 0x9F: 0xE7;
+ else
+ conf &= ~ (1 << (3 + 2 * channel + unit));
+ pci_write_config_byte(hwif->pci_dev, 0x50, conf);
+
+ it821x_clock_strategy(drive);
+ it821x_program_udma(drive, itdev->udma[unit]);
+
+}
+
+/**
+ * config_it821x_chipset_for_pio - set drive timings
+ * @drive: drive to tune
+ * @speed we want
+ *
+ * Compute the best pio mode we can for a given device. We must
+ * pick a speed that does not cause problems with the other device
+ * on the cable.
+ */
+
+static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed)
+{
+ u8 unit = drive->select.b.unit;
+ ide_hwif_t *hwif = drive->hwif;
+ ide_drive_t *pair = &hwif->drives[1-unit];
+ u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL);
+ u8 pair_pio;
+
+ /* We have to deal with this mess in pairs */
+ if(pair != NULL) {
+ pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL);
+ /* Trim PIO to the slowest of the master/slave */
+ if(pair_pio < set_pio)
+ set_pio = pair_pio;
+ }
+ it821x_tuneproc(drive, set_pio);
+ speed = XFER_PIO_0 + set_pio;
+ /* XXX - We trim to the lowest of the pair so the other drive
+ will always be fine at this point until we do hotplug passthru */
+
+ if (set_speed)
+ (void) ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * it821x_dma_read - DMA hook
+ * @drive: drive for DMA
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock. In addition the rev 0x10 device only works if the same
+ * timing value is loaded into the master and slave UDMA clock
+ * so we must also reload that.
+ *
+ * FIXME: we could figure out in advance if we need to do reloads
+ */
+
+static void it821x_dma_start(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int unit = drive->select.b.unit;
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->mwdma[unit]);
+ else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10)
+ it821x_program_udma(drive, itdev->udma[unit]);
+ ide_dma_start(drive);
+}
+
+/**
+ * it821x_dma_write - DMA hook
+ * @drive: drive for DMA stop
+ *
+ * The IT821x has a single timing register for MWDMA and for PIO
+ * operations. As we flip back and forth we have to reload the
+ * clock.
+ */
+
+static int it821x_dma_end(ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+ int unit = drive->select.b.unit;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int ret = __ide_dma_end(drive);
+ if(itdev->mwdma[unit] != MWDMA_OFF)
+ it821x_program(drive, itdev->pio[unit]);
+ return ret;
+}
+
+
+/**
+ * it821x_tune_chipset - set controller timings
+ * @drive: Drive to set up
+ * @xferspeed: speed we want to achieve
+ *
+ * Tune the ITE chipset for the desired mode. If we can't achieve
+ * the desired mode then tune for a lower one, but ultimately
+ * make the thing work.
+ */
+
+static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed)
+{
+
+ ide_hwif_t *hwif = drive->hwif;
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed);
+
+ if(!itdev->smart) {
+ switch(speed) {
+ case XFER_PIO_4:
+ case XFER_PIO_3:
+ case XFER_PIO_2:
+ case XFER_PIO_1:
+ case XFER_PIO_0:
+ it821x_tuneproc(drive, (speed - XFER_PIO_0));
+ break;
+ /* MWDMA tuning is really hard because our MWDMA and PIO
+ timings are kept in the same place. We can switch in the
+ host dma on/off callbacks */
+ case XFER_MW_DMA_2:
+ case XFER_MW_DMA_1:
+ case XFER_MW_DMA_0:
+ it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0));
+ break;
+ case XFER_UDMA_6:
+ case XFER_UDMA_5:
+ case XFER_UDMA_4:
+ case XFER_UDMA_3:
+ case XFER_UDMA_2:
+ case XFER_UDMA_1:
+ case XFER_UDMA_0:
+ it821x_tune_udma(drive, (speed - XFER_UDMA_0));
+ break;
+ default:
+ return 1;
+ }
+ }
+ /*
+ * In smart mode the clocking is done by the host controller
+ * snooping the mode we picked. The rest of it is not our problem
+ */
+ return ide_config_drive_speed(drive, speed);
+}
+
+/**
+ * config_chipset_for_dma - configure for DMA
+ * @drive: drive to configure
+ *
+ * Called by the IDE layer when it wants the timings set up.
+ */
+
+static int config_chipset_for_dma (ide_drive_t *drive)
+{
+ u8 speed = ide_dma_speed(drive, it821x_ratemask(drive));
+
+ config_it821x_chipset_for_pio(drive, !speed);
+ it821x_tune_chipset(drive, speed);
+ return ide_dma_enable(drive);
+}
+
+/**
+ * it821x_configure_drive_for_dma - set up for DMA transfers
+ * @drive: drive we are going to set up
+ *
+ * Set up the drive for DMA, tune the controller and drive as
+ * required. If the drive isn't suitable for DMA or we hit
+ * other problems then we will drop down to PIO and set up
+ * PIO appropriately
+ */
+
+static int it821x_config_drive_for_dma (ide_drive_t *drive)
+{
+ ide_hwif_t *hwif = drive->hwif;
+
+ if (ide_use_dma(drive)) {
+ if (config_chipset_for_dma(drive))
+ return hwif->ide_dma_on(drive);
+ }
+ config_it821x_chipset_for_pio(drive, 1);
+ return hwif->ide_dma_off_quietly(drive);
+}
+
+/**
+ * ata66_it821x - check for 80 pin cable
+ * @hwif: interface to check
+ *
+ * Check for the presence of an ATA66 capable cable on the
+ * interface. Problematic as it seems some cards don't have
+ * the needed logic onboard.
+ */
+
+static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif)
+{
+ /* The reference driver also only does disk side */
+ return 1;
+}
+
+/**
+ * it821x_fixup - post init callback
+ * @hwif: interface
+ *
+ * This callback is run after the drives have been probed but
+ * before anything gets attached. It allows drivers to do any
+ * final tuning that is needed, or fixups to work around bugs.
+ */
+
+static void __devinit it821x_fixups(ide_hwif_t *hwif)
+{
+ struct it821x_dev *itdev = ide_get_hwifdata(hwif);
+ int i;
+
+ if(!itdev->smart) {
+ /*
+ * If we are in pass through mode then not much
+ * needs to be done, but we do bother to clear the
+ * IRQ mask as we may well be in PIO (eg rev 0x10)
+ * for now and we know unmasking is safe on this chipset.
+ */
+ for (i = 0; i < 2; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+ if(drive->present)
+ drive->unmask = 1;
+ }
+ return;
+ }
+ /*
+ * Perform fixups on smart mode. We need to "lose" some
+ * capabilities the firmware lacks but does not filter, and
+ * also patch up some capability bits that it forgets to set
+ * in RAID mode.
+ */
+
+ for(i = 0; i < 2; i++) {
+ ide_drive_t *drive = &hwif->drives[i];
+ struct hd_driveid *id;
+ u16 *idbits;
+
+ if(!drive->present)
+ continue;
+ id = drive->id;
+ idbits = (u16 *)drive->id;
+
+ /* Check for RAID v native */
+ if(strstr(id->model, "Integrated Technology Express")) {
+ /* In raid mode the ident block is slightly buggy
+ We need to set the bits so that the IDE layer knows
+ LBA28. LBA48 and DMA ar valid */
+ id->capability |= 3; /* LBA28, DMA */
+ id->command_set_2 |= 0x0400; /* LBA48 valid */
+ id->cfs_enable_2 |= 0x0400; /* LBA48 on */
+ /* Reporting logic */
+ printk(KERN_INFO "%s: IT8212 %sRAID %d volume",
+ drive->name,
+ idbits[147] ? "Bootable ":"",
+ idbits[129]);
+ if(idbits[129] != 1)
+ printk("(%dK stripe)", idbits[146]);
+ printk(".\n");
+ /* Now the core code will have wrongly decided no DMA
+ so we need to fix this */
+ hwif->ide_dma_off_quietly(drive);
+#ifdef CONFIG_IDEDMA_ONLYDISK
+ if (drive->media == ide_disk)
+#endif
+ hwif->ide_dma_check(drive);
+ } else {
+ /* Non RAID volume. Fixups to stop the core code
+ doing unsupported things */
+ id->field_valid &= 1;
+ id->queue_depth = 0;
+ id->command_set_1 = 0;
+ id->command_set_2 &= 0xC400;
+ id->cfsse &= 0xC000;
+ id->cfs_enable_1 = 0;
+ id->cfs_enable_2 &= 0xC400;
+ id->csf_default &= 0xC000;
+ id->word127 = 0;
+ id->dlf = 0;
+ id->csfo = 0;
+ id->cfa_power = 0;
+ printk(KERN_INFO "%s: Performing identify fixups.\n",
+ drive->name);
+ }
+ }
+
+}
+
+/**
+ * init_hwif_it821x - set up hwif structs
+ * @hwif: interface to set up
+ *
+ * We do the basic set up of the interface structure. The IT8212
+ * requires several custom handlers so we override the default
+ * ide DMA handlers appropriately
+ */
+
+static void __devinit init_hwif_it821x(ide_hwif_t *hwif)
+{
+ struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL);
+ u8 conf;
+
+ if(idev == NULL) {
+ printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n");
+ goto fallback;
+ }
+ memset(idev, 0, sizeof(struct it821x_dev));
+ ide_set_hwifdata(hwif, idev);
+
+ pci_read_config_byte(hwif->pci_dev, 0x50, &conf);
+ if(conf & 1) {
+ idev->smart = 1;
+ hwif->atapi_dma = 0;
+ /* Long I/O's although allowed in LBA48 space cause the
+ onboard firmware to enter the twighlight zone */
+ hwif->rqsize = 256;
+ }
+
+ /* Pull the current clocks from 0x50 also */
+ if (conf & (1 << (1 + hwif->channel)))
+ idev->clock_mode = ATA_50;
+ else
+ idev->clock_mode = ATA_66;
+
+ idev->want[0][1] = ATA_ANY;
+ idev->want[1][1] = ATA_ANY;
+
+ /*
+ * Not in the docs but according to the reference driver
+ * this is neccessary.
+ */
+
+ pci_read_config_byte(hwif->pci_dev, 0x08, &conf);
+ if(conf == 0x10) {
+ idev->timing10 = 1;
+ hwif->atapi_dma = 0;
+ if(!idev->smart)
+ printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n");
+ }
+
+ hwif->speedproc = &it821x_tune_chipset;
+ hwif->tuneproc = &it821x_tuneproc;
+
+ /* MWDMA/PIO clock switching for pass through mode */
+ if(!idev->smart) {
+ hwif->dma_start = &it821x_dma_start;
+ hwif->ide_dma_end = &it821x_dma_end;
+ }
+
+ hwif->drives[0].autotune = 1;
+ hwif->drives[1].autotune = 1;
+
+ if (!hwif->dma_base)
+ goto fallback;
+
+ hwif->ultra_mask = 0x7f;
+ hwif->mwdma_mask = 0x07;
+ hwif->swdma_mask = 0x07;
+
+ hwif->ide_dma_check = &it821x_config_drive_for_dma;
+ if (!(hwif->udma_four))
+ hwif->udma_four = ata66_it821x(hwif);
+
+ /*
+ * The BIOS often doesn't set up DMA on this controller
+ * so we always do it.
+ */
+
+ hwif->autodma = 1;
+ hwif->drives[0].autodma = hwif->autodma;
+ hwif->drives[1].autodma = hwif->autodma;
+ return;
+fallback:
+ hwif->autodma = 0;
+ return;
+}
+
+static void __devinit it8212_disable_raid(struct pci_dev *dev)
+{
+ /* Reset local CPU, and set BIOS not ready */
+ pci_write_config_byte(dev, 0x5E, 0x01);
+
+ /* Set to bypass mode, and reset PCI bus */
+ pci_write_config_byte(dev, 0x50, 0x00);
+ pci_write_config_word(dev, PCI_COMMAND,
+ PCI_COMMAND_PARITY | PCI_COMMAND_IO |
+ PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+ pci_write_config_word(dev, 0x40, 0xA0F3);
+
+ pci_write_config_dword(dev,0x4C, 0x02040204);
+ pci_write_config_byte(dev, 0x42, 0x36);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0);
+}
+
+static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name)
+{
+ u8 conf;
+ static char *mode[2] = { "pass through", "smart" };
+
+ /* Force the card into bypass mode if so requested */
+ if (it8212_noraid) {
+ printk(KERN_INFO "it8212: forcing bypass mode.\n");
+ it8212_disable_raid(dev);
+ }
+ pci_read_config_byte(dev, 0x50, &conf);
+ printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]);
+ return 0;
+}
+
+
+#define DECLARE_ITE_DEV(name_str) \
+ { \
+ .name = name_str, \
+ .init_chipset = init_chipset_it821x, \
+ .init_hwif = init_hwif_it821x, \
+ .channels = 2, \
+ .autodma = AUTODMA, \
+ .bootable = ON_BOARD, \
+ .fixup = it821x_fixups \
+ }
+
+static ide_pci_device_t it821x_chipsets[] __devinitdata = {
+ /* 0 */ DECLARE_ITE_DEV("IT8212"),
+};
+
+/**
+ * it821x_init_one - pci layer discovery entry
+ * @dev: PCI device
+ * @id: ident table entry
+ *
+ * Called by the PCI code when it finds an ITE821x controller.
+ * We then use the IDE PCI generic helper to do most of the work.
+ */
+
+static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]);
+ return 0;
+}
+
+static struct pci_device_id it821x_pci_tbl[] = {
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, it821x_pci_tbl);
+
+static struct pci_driver driver = {
+ .name = "ITE821x IDE",
+ .id_table = it821x_pci_tbl,
+ .probe = it821x_init_one,
+};
+
+static int __init it821x_ide_init(void)
+{
+ return ide_pci_register_driver(&driver);
+}
+
+module_init(it821x_ide_init);
+
+module_param_named(noraid, it8212_noraid, int, S_IRUGO);
+MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode");
+
+MODULE_AUTHOR("Alan Cox");
+MODULE_DESCRIPTION("PCI driver module for the ITE 821x");
+MODULE_LICENSE("GPL");
diff --git a/drivers/ide/pci/ns87415.c b/drivers/ide/pci/ns87415.c
index 205a32fbc2f0..fcd5142f5cfe 100644
--- a/drivers/ide/pci/ns87415.c
+++ b/drivers/ide/pci/ns87415.c
@@ -195,7 +195,7 @@ static int ns87415_ide_dma_check (ide_drive_t *drive)
return __ide_dma_check(drive);
}
-static void __init init_hwif_ns87415 (ide_hwif_t *hwif)
+static void __devinit init_hwif_ns87415 (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
unsigned int ctrl, using_inta;
diff --git a/drivers/ide/pci/opti621.c b/drivers/ide/pci/opti621.c
index cf4fd91d396a..7a7c2ef78ac2 100644
--- a/drivers/ide/pci/opti621.c
+++ b/drivers/ide/pci/opti621.c
@@ -326,7 +326,7 @@ static void opti621_tune_drive (ide_drive_t *drive, u8 pio)
/*
* init_hwif_opti621() is called once for each hwif found at boot.
*/
-static void __init init_hwif_opti621 (ide_hwif_t *hwif)
+static void __devinit init_hwif_opti621 (ide_hwif_t *hwif)
{
hwif->autodma = 0;
hwif->drives[0].drive_data = PIO_DONT_KNOW;
diff --git a/drivers/ide/pci/sc1200.c b/drivers/ide/pci/sc1200.c
index 3bc3bf1be49b..10592cec6c43 100644
--- a/drivers/ide/pci/sc1200.c
+++ b/drivers/ide/pci/sc1200.c
@@ -459,7 +459,7 @@ printk("%s: SC1200: resume\n", hwif->name);
* This gets invoked by the IDE driver once for each channel,
* and performs channel-specific pre-initialization before drive probing.
*/
-static void __init init_hwif_sc1200 (ide_hwif_t *hwif)
+static void __devinit init_hwif_sc1200 (ide_hwif_t *hwif)
{
if (hwif->mate)
hwif->serialized = hwif->mate->serialized = 1;
diff --git a/drivers/ide/pci/serverworks.c b/drivers/ide/pci/serverworks.c
index 82a1103b2413..c6f5fa4b4ca6 100644
--- a/drivers/ide/pci/serverworks.c
+++ b/drivers/ide/pci/serverworks.c
@@ -442,7 +442,7 @@ static unsigned int __devinit init_chipset_svwks (struct pci_dev *dev, const cha
return (dev->irq) ? dev->irq : 0;
}
-static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_svwks (ide_hwif_t *hwif)
{
return 1;
}
@@ -454,7 +454,7 @@ static unsigned int __init ata66_svwks_svwks (ide_hwif_t *hwif)
* Bit 14 clear = primary IDE channel does not have 80-pin cable.
* Bit 14 set = primary IDE channel has 80-pin cable.
*/
-static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_dell (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_DELL &&
@@ -472,7 +472,7 @@ static unsigned int __init ata66_svwks_dell (ide_hwif_t *hwif)
*
* WARNING: this only works on Alpine hardware!
*/
-static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks_cobalt (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
if (dev->subsystem_vendor == PCI_VENDOR_ID_SUN &&
@@ -483,7 +483,7 @@ static unsigned int __init ata66_svwks_cobalt (ide_hwif_t *hwif)
return 0;
}
-static unsigned int __init ata66_svwks (ide_hwif_t *hwif)
+static unsigned int __devinit ata66_svwks (ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
@@ -573,7 +573,7 @@ static int __devinit init_setup_svwks (struct pci_dev *dev, ide_pci_device_t *d)
return ide_setup_pci_device(dev, d);
}
-static int __init init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
+static int __devinit init_setup_csb6 (struct pci_dev *dev, ide_pci_device_t *d)
{
if (!(PCI_FUNC(dev->devfn) & 1)) {
d->bootable = NEVER_BOARD;
diff --git a/drivers/ide/pci/sl82c105.c b/drivers/ide/pci/sl82c105.c
index 1d970a0de21a..ea0806c82be0 100644
--- a/drivers/ide/pci/sl82c105.c
+++ b/drivers/ide/pci/sl82c105.c
@@ -386,7 +386,7 @@ static unsigned int sl82c105_bridge_revision(struct pci_dev *dev)
* channel 0 here at least, but channel 1 has to be enabled by
* firmware or arch code. We still set both to 16 bits mode.
*/
-static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
+static unsigned int __devinit init_chipset_sl82c105(struct pci_dev *dev, const char *msg)
{
u32 val;
@@ -399,7 +399,7 @@ static unsigned int __init init_chipset_sl82c105(struct pci_dev *dev, const char
return dev->irq;
}
-static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
+static void __devinit init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
{
unsigned int rev;
u8 dma_state;
@@ -431,7 +431,7 @@ static void __init init_dma_sl82c105(ide_hwif_t *hwif, unsigned long dma_base)
* Initialise the chip
*/
-static void __init init_hwif_sl82c105(ide_hwif_t *hwif)
+static void __devinit init_hwif_sl82c105(ide_hwif_t *hwif)
{
struct pci_dev *dev = hwif->pci_dev;
u32 val;
diff --git a/drivers/ide/pci/slc90e66.c b/drivers/ide/pci/slc90e66.c
index 7fbf36342f73..5112c726633b 100644
--- a/drivers/ide/pci/slc90e66.c
+++ b/drivers/ide/pci/slc90e66.c
@@ -196,7 +196,7 @@ fast_ata_pio:
}
#endif /* CONFIG_BLK_DEV_IDEDMA */
-static void __init init_hwif_slc90e66 (ide_hwif_t *hwif)
+static void __devinit init_hwif_slc90e66 (ide_hwif_t *hwif)
{
u8 reg47 = 0;
u8 mask = hwif->channel ? 0x01 : 0x02; /* bit0:Primary */
diff --git a/drivers/ide/pci/triflex.c b/drivers/ide/pci/triflex.c
index a1df2bfe3631..f96b56838f33 100644
--- a/drivers/ide/pci/triflex.c
+++ b/drivers/ide/pci/triflex.c
@@ -130,7 +130,7 @@ static int triflex_config_drive_xfer_rate(ide_drive_t *drive)
return hwif->ide_dma_off_quietly(drive);
}
-static void __init init_hwif_triflex(ide_hwif_t *hwif)
+static void __devinit init_hwif_triflex(ide_hwif_t *hwif)
{
hwif->tuneproc = &triflex_tune_drive;
hwif->speedproc = &triflex_tune_chipset;
diff --git a/drivers/ide/pci/via82cxxx.c b/drivers/ide/pci/via82cxxx.c
index 069dbffe2116..a4d099c937ff 100644
--- a/drivers/ide/pci/via82cxxx.c
+++ b/drivers/ide/pci/via82cxxx.c
@@ -415,7 +415,7 @@ static int via82cxxx_ide_dma_check (ide_drive_t *drive)
* and initialize its drive independent registers.
*/
-static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
+static unsigned int __devinit init_chipset_via82cxxx(struct pci_dev *dev, const char *name)
{
struct pci_dev *isa = NULL;
u8 t, v;
@@ -576,7 +576,7 @@ static unsigned int __init init_chipset_via82cxxx(struct pci_dev *dev, const cha
return 0;
}
-static void __init init_hwif_via82cxxx(ide_hwif_t *hwif)
+static void __devinit init_hwif_via82cxxx(ide_hwif_t *hwif)
{
int i;
diff --git a/drivers/ide/ppc/pmac.c b/drivers/ide/ppc/pmac.c
index 569f16767442..be0fcc8f4b15 100644
--- a/drivers/ide/ppc/pmac.c
+++ b/drivers/ide/ppc/pmac.c
@@ -1324,9 +1324,9 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
/* XXX FIXME: Media bay stuff need re-organizing */
if (np->parent && np->parent->name
&& strcasecmp(np->parent->name, "media-bay") == 0) {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
media_bay_set_ide_infos(np->parent, pmif->regbase, pmif->irq, hwif->index);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
pmif->mediabay = 1;
if (!bidp)
pmif->aapl_bus_id = 1;
@@ -1382,10 +1382,10 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
hwif->index, model_name[pmif->kind], pmif->aapl_bus_id,
pmif->mediabay ? " (mediabay)" : "", hwif->irq);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PMAC_MEDIABAY
if (pmif->mediabay && check_media_bay_by_base(pmif->regbase, MB_CD) == 0)
hwif->noprobe = 0;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PMAC_MEDIABAY */
hwif->sg_max_nents = MAX_DCMDS;
@@ -1419,7 +1419,7 @@ pmac_ide_setup_device(pmac_ide_hwif_t *pmif, ide_hwif_t *hwif)
* Attach to a macio probed interface
*/
static int __devinit
-pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_match *match)
+pmac_ide_macio_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
void __iomem *base;
unsigned long regbase;
@@ -1637,27 +1637,19 @@ pmac_ide_pci_resume(struct pci_dev *pdev)
return rc;
}
-static struct of_match pmac_ide_macio_match[] =
+static struct of_device_id pmac_ide_macio_match[] =
{
{
.name = "IDE",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
.name = "ATA",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
- .name = OF_ANY_MATCH,
.type = "ide",
- .compatible = OF_ANY_MATCH
},
{
- .name = OF_ANY_MATCH,
.type = "ata",
- .compatible = OF_ANY_MATCH
},
{},
};
diff --git a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c
index e501675ad72e..77da827b2898 100644
--- a/drivers/ide/setup-pci.c
+++ b/drivers/ide/setup-pci.c
@@ -847,7 +847,7 @@ static int __init ide_scan_pcidev(struct pci_dev *dev)
d = list_entry(l, struct pci_driver, node);
if(d->id_table)
{
- const struct pci_device_id *id = pci_match_device(d->id_table, dev);
+ const struct pci_device_id *id = pci_match_id(d->id_table, dev);
if(id != NULL)
{
if(d->probe(dev, id) >= 0)
diff --git a/drivers/ieee1394/Kconfig b/drivers/ieee1394/Kconfig
index 7d58af1ae306..25103a0ef9b3 100644
--- a/drivers/ieee1394/Kconfig
+++ b/drivers/ieee1394/Kconfig
@@ -66,6 +66,18 @@ config IEEE1394_CONFIG_ROM_IP1394
with MacOSX and WinXP IP-over-1394), enable this option and the
eth1394 option below.
+config IEEE1394_EXPORT_FULL_API
+ bool "Export all symbols of ieee1394's API"
+ depends on IEEE1394
+ default n
+ help
+ Export all symbols of ieee1394's driver programming interface, even
+ those that are not currently used by the standard IEEE 1394 drivers.
+
+ This option does not affect the interface to userspace applications.
+ Say Y here if you want to compile externally developed drivers that
+ make extended use of ieee1394's API. It is otherwise safe to say N.
+
comment "Device Drivers"
depends on IEEE1394
diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c
index 1b98684aebcd..149573db91c5 100644
--- a/drivers/ieee1394/csr.c
+++ b/drivers/ieee1394/csr.c
@@ -28,6 +28,7 @@
#include "hosts.h"
#include "ieee1394.h"
#include "highlevel.h"
+#include "ieee1394_core.h"
/* Module Parameters */
/* this module parameter can be used to disable mapping of the FCP registers */
@@ -232,7 +233,7 @@ static void add_host(struct hpsb_host *host)
host->csr.generation = 2;
bus_info[1] = __constant_cpu_to_be32(0x31333934);
- bus_info[2] = cpu_to_be32((1 << CSR_IRMC_SHIFT) |
+ bus_info[2] = cpu_to_be32((hpsb_disable_irm ? 0 : 1 << CSR_IRMC_SHIFT) |
(1 << CSR_CMC_SHIFT) |
(1 << CSR_ISC_SHIFT) |
(0 << CSR_BMC_SHIFT) |
diff --git a/drivers/ieee1394/csr1212.c b/drivers/ieee1394/csr1212.c
index 7c4330e2e875..61ddd5d37eff 100644
--- a/drivers/ieee1394/csr1212.c
+++ b/drivers/ieee1394/csr1212.c
@@ -209,7 +209,15 @@ void csr1212_init_local_csr(struct csr1212_csr *csr,
{
static const int mr_map[] = { 4, 64, 1024, 0 };
+#ifdef __KERNEL__
+ BUG_ON(max_rom & ~0x3);
csr->max_rom = mr_map[max_rom];
+#else
+ if (max_rom & ~0x3) /* caller supplied invalid argument */
+ csr->max_rom = 0;
+ else
+ csr->max_rom = mr_map[max_rom];
+#endif
memcpy(csr->bus_info_data, bus_info_data, csr->bus_info_len);
}
@@ -533,12 +541,15 @@ struct csr1212_keyval *csr1212_new_icon_descriptor_leaf(u_int32_t version,
static const int pd[4] = { 0, 4, 16, 256 };
static const int cs[16] = { 4, 2 };
struct csr1212_keyval *kv;
- int palette_size = pd[palette_depth] * cs[color_space];
+ int palette_size;
int pixel_size = (hscan * vscan + 3) & ~0x3;
- if ((palette_depth && !palette) || !pixels)
+ if (!pixels || (!palette && palette_depth) ||
+ (palette_depth & ~0x3) || (color_space & ~0xf))
return NULL;
+ palette_size = pd[palette_depth] * cs[color_space];
+
kv = csr1212_new_descriptor_leaf(1, 0, NULL,
palette_size + pixel_size +
CSR1212_ICON_DESCRIPTOR_LEAF_OVERHEAD);
@@ -760,9 +771,9 @@ static int csr1212_append_new_cache(struct csr1212_csr *csr, size_t romsize)
struct csr1212_csr_rom_cache *cache;
u_int64_t csr_addr;
- if (!csr || !csr->ops->allocate_addr_range ||
- !csr->ops->release_addr)
- return CSR1212_ENOMEM;
+ if (!csr || !csr->ops || !csr->ops->allocate_addr_range ||
+ !csr->ops->release_addr || csr->max_rom < 1)
+ return CSR1212_EINVAL;
/* ROM size must be a multiple of csr->max_rom */
romsize = (romsize + (csr->max_rom - 1)) & ~(csr->max_rom - 1);
@@ -1145,6 +1156,8 @@ int csr1212_generate_csr_image(struct csr1212_csr *csr)
/* Make sure the Extended ROM leaf is a multiple of
* max_rom in size. */
+ if (csr->max_rom < 1)
+ return CSR1212_EINVAL;
leaf_size = (cache->len + (csr->max_rom - 1)) &
~(csr->max_rom - 1);
@@ -1409,7 +1422,7 @@ int _csr1212_read_keyval(struct csr1212_csr *csr, struct csr1212_keyval *kv)
u_int32_t *cache_ptr;
u_int16_t kv_len = 0;
- if (!csr || !kv)
+ if (!csr || !kv || csr->max_rom < 1)
return CSR1212_EINVAL;
/* First find which cache the data should be in (or go in if not read
@@ -1572,7 +1585,7 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
struct csr1212_dentry *dentry;
int ret;
- if (!csr || !csr->ops->bus_read)
+ if (!csr || !csr->ops || !csr->ops->bus_read)
return CSR1212_EINVAL;
ret = csr1212_parse_bus_info_block(csr);
@@ -1581,9 +1594,13 @@ int csr1212_parse_csr(struct csr1212_csr *csr)
if (!csr->ops->get_max_rom)
csr->max_rom = mr_map[0]; /* default value */
- else
- csr->max_rom = mr_map[csr->ops->get_max_rom(csr->bus_info_data,
- csr->private)];
+ else {
+ int i = csr->ops->get_max_rom(csr->bus_info_data,
+ csr->private);
+ if (i & ~0x3)
+ return CSR1212_EINVAL;
+ csr->max_rom = mr_map[i];
+ }
csr->cache_head->layout_head = csr->root_kv;
csr->cache_head->layout_tail = csr->root_kv;
diff --git a/drivers/ieee1394/dma.c b/drivers/ieee1394/dma.c
index 758819d1999d..b79ddb43e746 100644
--- a/drivers/ieee1394/dma.c
+++ b/drivers/ieee1394/dma.c
@@ -158,7 +158,7 @@ static inline int dma_region_find(struct dma_region *dma, unsigned long offset,
dma_addr_t dma_region_offset_to_bus(struct dma_region *dma, unsigned long offset)
{
- unsigned long rem;
+ unsigned long rem = 0;
struct scatterlist *sg = &dma->sglist[dma_region_find(dma, offset, &rem)];
return sg_dma_address(sg) + rem;
diff --git a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
index 654da76bf811..cd53c174ced1 100644
--- a/drivers/ieee1394/eth1394.c
+++ b/drivers/ieee1394/eth1394.c
@@ -89,7 +89,7 @@
#define TRACE() printk(KERN_ERR "%s:%s[%d] ---- TRACE\n", driver_name, __FUNCTION__, __LINE__)
static char version[] __devinitdata =
- "$Rev: 1247 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 1264 $ Ben Collins <bcollins@debian.org>";
struct fragment_info {
struct list_head list;
@@ -706,7 +706,7 @@ static void ether1394_host_reset (struct hpsb_host *host)
return;
dev = hi->dev;
- priv = netdev_priv(dev);
+ priv = (struct eth1394_priv *)netdev_priv(dev);
/* Reset our private host data, but not our mtu */
netif_stop_queue (dev);
@@ -1770,7 +1770,7 @@ fail:
static void ether1394_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
strcpy (info->driver, driver_name);
- strcpy (info->version, "$Rev: 1247 $");
+ strcpy (info->version, "$Rev: 1264 $");
/* FIXME XXX provide sane businfo */
strcpy (info->bus_info, "ieee1394");
}
diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c
index 2d9a9b74e687..b248d89de8b4 100644
--- a/drivers/ieee1394/ieee1394_core.c
+++ b/drivers/ieee1394/ieee1394_core.c
@@ -52,7 +52,7 @@
/*
* Disable the nodemgr detection and config rom reading functionality.
*/
-static int disable_nodemgr = 0;
+static int disable_nodemgr;
module_param(disable_nodemgr, int, 0444);
MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
@@ -520,6 +520,9 @@ int hpsb_send_packet(struct hpsb_packet *packet)
if (!packet->no_waiter || packet->expect_response) {
atomic_inc(&packet->refcnt);
+ /* Set the initial "sendtime" to 10 seconds from now, to
+ prevent premature expiry. If a packet takes more than
+ 10 seconds to hit the wire, we have bigger problems :) */
packet->sendtime = jiffies + 10 * HZ;
skb_queue_tail(&host->pending_packet_queue, packet->skb);
}
@@ -1041,10 +1044,8 @@ static int hpsbpkt_thread(void *__hi)
while (1) {
if (down_interruptible(&khpsbpkt_sig)) {
- if (current->flags & PF_FREEZE) {
- refrigerator(0);
+ if (try_to_freeze())
continue;
- }
printk("khpsbpkt: received unexpected signal?!\n" );
break;
}
@@ -1225,9 +1226,7 @@ EXPORT_SYMBOL(hpsb_protocol_class);
EXPORT_SYMBOL(hpsb_set_packet_complete_task);
EXPORT_SYMBOL(hpsb_alloc_packet);
EXPORT_SYMBOL(hpsb_free_packet);
-EXPORT_SYMBOL(hpsb_send_phy_config);
EXPORT_SYMBOL(hpsb_send_packet);
-EXPORT_SYMBOL(hpsb_send_packet_and_wait);
EXPORT_SYMBOL(hpsb_reset_bus);
EXPORT_SYMBOL(hpsb_bus_reset);
EXPORT_SYMBOL(hpsb_selfid_received);
@@ -1235,6 +1234,10 @@ EXPORT_SYMBOL(hpsb_selfid_complete);
EXPORT_SYMBOL(hpsb_packet_sent);
EXPORT_SYMBOL(hpsb_packet_received);
EXPORT_SYMBOL_GPL(hpsb_disable_irm);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
+EXPORT_SYMBOL(hpsb_send_phy_config);
+EXPORT_SYMBOL(hpsb_send_packet_and_wait);
+#endif
/** ieee1394_transactions.c **/
EXPORT_SYMBOL(hpsb_get_tlabel);
@@ -1264,9 +1267,11 @@ EXPORT_SYMBOL(hpsb_destroy_hostinfo);
EXPORT_SYMBOL(hpsb_set_hostinfo_key);
EXPORT_SYMBOL(hpsb_get_hostinfo_bykey);
EXPORT_SYMBOL(hpsb_set_hostinfo);
+EXPORT_SYMBOL(highlevel_host_reset);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
EXPORT_SYMBOL(highlevel_add_host);
EXPORT_SYMBOL(highlevel_remove_host);
-EXPORT_SYMBOL(highlevel_host_reset);
+#endif
/** nodemgr.c **/
EXPORT_SYMBOL(hpsb_node_fill_packet);
@@ -1274,7 +1279,9 @@ EXPORT_SYMBOL(hpsb_node_write);
EXPORT_SYMBOL(hpsb_register_protocol);
EXPORT_SYMBOL(hpsb_unregister_protocol);
EXPORT_SYMBOL(ieee1394_bus_type);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
EXPORT_SYMBOL(nodemgr_for_each_host);
+#endif
/** csr.c **/
EXPORT_SYMBOL(hpsb_update_config_rom);
@@ -1311,19 +1318,21 @@ EXPORT_SYMBOL(hpsb_iso_wake);
EXPORT_SYMBOL(hpsb_iso_recv_flush);
/** csr1212.c **/
-EXPORT_SYMBOL(csr1212_create_csr);
-EXPORT_SYMBOL(csr1212_init_local_csr);
-EXPORT_SYMBOL(csr1212_new_immediate);
EXPORT_SYMBOL(csr1212_new_directory);
-EXPORT_SYMBOL(csr1212_associate_keyval);
EXPORT_SYMBOL(csr1212_attach_keyval_to_directory);
-EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
EXPORT_SYMBOL(csr1212_detach_keyval_from_directory);
EXPORT_SYMBOL(csr1212_release_keyval);
-EXPORT_SYMBOL(csr1212_destroy_csr);
EXPORT_SYMBOL(csr1212_read);
-EXPORT_SYMBOL(csr1212_generate_csr_image);
EXPORT_SYMBOL(csr1212_parse_keyval);
-EXPORT_SYMBOL(csr1212_parse_csr);
EXPORT_SYMBOL(_csr1212_read_keyval);
EXPORT_SYMBOL(_csr1212_destroy_keyval);
+#ifdef CONFIG_IEEE1394_EXPORT_FULL_API
+EXPORT_SYMBOL(csr1212_create_csr);
+EXPORT_SYMBOL(csr1212_init_local_csr);
+EXPORT_SYMBOL(csr1212_new_immediate);
+EXPORT_SYMBOL(csr1212_associate_keyval);
+EXPORT_SYMBOL(csr1212_new_string_descriptor_leaf);
+EXPORT_SYMBOL(csr1212_destroy_csr);
+EXPORT_SYMBOL(csr1212_generate_csr_image);
+EXPORT_SYMBOL(csr1212_parse_csr);
+#endif
diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h
index 73bd8efd2b6c..0b31429d0a68 100644
--- a/drivers/ieee1394/ieee1394_core.h
+++ b/drivers/ieee1394/ieee1394_core.h
@@ -38,8 +38,8 @@ struct hpsb_packet {
/* These are core internal. */
signed char tlabel;
- char ack_code;
- char tcode;
+ signed char ack_code;
+ unsigned char tcode;
unsigned expect_response:1;
unsigned no_waiter:1;
diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
index f05759107f7e..615541b8b90f 100644
--- a/drivers/ieee1394/iso.c
+++ b/drivers/ieee1394/iso.c
@@ -62,10 +62,10 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i
if ((dma_mode < HPSB_ISO_DMA_DEFAULT) || (dma_mode > HPSB_ISO_DMA_PACKET_PER_BUFFER))
dma_mode=HPSB_ISO_DMA_DEFAULT;
+ if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
+ irq_interval = buf_packets / 4;
if (irq_interval == 0) /* really interrupt for each packet*/
irq_interval = 1;
- else if ((irq_interval < 0) || (irq_interval > buf_packets / 4))
- irq_interval = buf_packets / 4;
if (channel < -1 || channel >= 64)
return NULL;
@@ -106,6 +106,7 @@ static struct hpsb_iso* hpsb_iso_common_init(struct hpsb_host *host, enum hpsb_i
}
atomic_set(&iso->overflows, 0);
+ iso->bytes_discarded = 0;
iso->flags = 0;
iso->prebuffer = 0;
@@ -241,12 +242,12 @@ int hpsb_iso_xmit_start(struct hpsb_iso *iso, int cycle, int prebuffer)
iso->xmit_cycle = cycle;
if (prebuffer < 0)
- prebuffer = iso->buf_packets;
+ prebuffer = iso->buf_packets - 1;
else if (prebuffer == 0)
prebuffer = 1;
- if (prebuffer > iso->buf_packets)
- prebuffer = iso->buf_packets;
+ if (prebuffer >= iso->buf_packets)
+ prebuffer = iso->buf_packets - 1;
iso->prebuffer = prebuffer;
@@ -395,7 +396,7 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error)
}
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 cycle, u8 channel, u8 tag, u8 sy)
+ u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy)
{
unsigned long flags;
spin_lock_irqsave(&iso->lock, flags);
@@ -403,10 +404,13 @@ void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
if (iso->n_ready_packets == iso->buf_packets) {
/* overflow! */
atomic_inc(&iso->overflows);
+ /* Record size of this discarded packet */
+ iso->bytes_discarded += total_len;
} else {
struct hpsb_iso_packet_info *info = &iso->infos[iso->pkt_dma];
info->offset = offset;
info->len = len;
+ info->total_len = total_len;
info->cycle = cycle;
info->channel = channel;
info->tag = tag;
@@ -437,6 +441,17 @@ int hpsb_iso_recv_release_packets(struct hpsb_iso *iso, unsigned int n_packets)
iso->first_packet = (iso->first_packet+1) % iso->buf_packets;
iso->n_ready_packets--;
+
+ /* release memory from packets discarded when queue was full */
+ if (iso->n_ready_packets == 0) { /* Release only after all prior packets handled */
+ if (iso->bytes_discarded != 0) {
+ struct hpsb_iso_packet_info inf;
+ inf.total_len = iso->bytes_discarded;
+ iso->host->driver->isoctl(iso, RECV_RELEASE,
+ (unsigned long) &inf);
+ iso->bytes_discarded = 0;
+ }
+ }
}
spin_unlock_irqrestore(&iso->lock, flags);
return rv;
diff --git a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
index fb654d9639a7..3efc60b33a88 100644
--- a/drivers/ieee1394/iso.h
+++ b/drivers/ieee1394/iso.h
@@ -47,6 +47,14 @@ struct hpsb_iso_packet_info {
/* 2-bit 'tag' and 4-bit 'sy' fields of the isochronous header */
__u8 tag;
__u8 sy;
+
+ /*
+ * length in bytes of the packet including header/trailer.
+ * MUST be at structure end, since the first part of this structure is also
+ * defined in raw1394.h (i.e. struct raw1394_iso_packet_info), is copied to
+ * userspace and is accessed there through libraw1394.
+ */
+ __u16 total_len;
};
enum hpsb_iso_type { HPSB_ISO_RECV = 0, HPSB_ISO_XMIT = 1 };
@@ -111,6 +119,9 @@ struct hpsb_iso {
/* how many times the buffer has overflowed or underflowed */
atomic_t overflows;
+ /* Current number of bytes lost in discarded packets */
+ int bytes_discarded;
+
/* private flags to track initialization progress */
#define HPSB_ISO_DRIVER_INIT (1<<0)
#define HPSB_ISO_DRIVER_STARTED (1<<1)
@@ -193,7 +204,7 @@ void hpsb_iso_packet_sent(struct hpsb_iso *iso, int cycle, int error);
/* call after a packet has been received (interrupt context OK) */
void hpsb_iso_packet_received(struct hpsb_iso *iso, u32 offset, u16 len,
- u16 cycle, u8 channel, u8 tag, u8 sy);
+ u16 total_len, u16 cycle, u8 channel, u8 tag, u8 sy);
/* call to wake waiting processes after buffer space has opened up. */
void hpsb_iso_wake(struct hpsb_iso *iso);
diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c
index 32abb6dda888..bebcc47ab06c 100644
--- a/drivers/ieee1394/nodemgr.c
+++ b/drivers/ieee1394/nodemgr.c
@@ -30,7 +30,7 @@
#include "csr.h"
#include "nodemgr.h"
-static int ignore_drivers = 0;
+static int ignore_drivers;
module_param(ignore_drivers, int, 0444);
MODULE_PARM_DESC(ignore_drivers, "Disable automatic probing for drivers.");
@@ -1510,7 +1510,7 @@ static int nodemgr_host_thread(void *__hi)
if (down_interruptible(&hi->reset_sem) ||
down_interruptible(&nodemgr_serialize)) {
- if (try_to_freeze(PF_FREEZE))
+ if (try_to_freeze())
continue;
printk("NodeMgr: received unexpected signal?!\n" );
break;
diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
index 36e25ac823dc..a485f47bb21e 100644
--- a/drivers/ieee1394/ohci1394.c
+++ b/drivers/ieee1394/ohci1394.c
@@ -162,7 +162,7 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args)
static char version[] __devinitdata =
- "$Rev: 1250 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 1299 $ Ben Collins <bcollins@debian.org>";
/* Module Parameters */
static int phys_dma = 1;
@@ -483,7 +483,9 @@ static void ohci_initialize(struct ti_ohci *ohci)
/* Put some defaults to these undefined bus options */
buf = reg_read(ohci, OHCI1394_BusOptions);
buf |= 0x60000000; /* Enable CMC and ISC */
- if (!hpsb_disable_irm)
+ if (hpsb_disable_irm)
+ buf &= ~0x80000000;
+ else
buf |= 0x80000000; /* Enable IRMC */
buf &= ~0x00ff0000; /* XXX: Set cyc_clk_acc to zero for now */
buf &= ~0x18000000; /* Disable PMC and BMC */
@@ -503,8 +505,12 @@ static void ohci_initialize(struct ti_ohci *ohci)
reg_write(ohci, OHCI1394_LinkControlSet,
OHCI1394_LinkControl_CycleTimerEnable |
OHCI1394_LinkControl_CycleMaster);
- set_phy_reg_mask(ohci, 4, PHY_04_LCTRL |
- (hpsb_disable_irm ? 0 : PHY_04_CONTENDER));
+ i = get_phy_reg(ohci, 4) | PHY_04_LCTRL;
+ if (hpsb_disable_irm)
+ i &= ~PHY_04_CONTENDER;
+ else
+ i |= PHY_04_CONTENDER;
+ set_phy_reg(ohci, 4, i);
/* Set up self-id dma buffer */
reg_write(ohci, OHCI1394_SelfIDBuffer, ohci->selfid_buf_bus);
@@ -1566,6 +1572,10 @@ static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
struct dma_cmd *next = &recv->block[next_i];
struct dma_cmd *prev = &recv->block[prev_i];
+
+ /* ignore out-of-range requests */
+ if ((block < 0) || (block > recv->nblocks))
+ return;
/* 'next' becomes the new end of the DMA chain,
so disable branch and enable interrupt */
@@ -1593,19 +1603,8 @@ static void ohci_iso_recv_release_block(struct ohci_iso_recv *recv, int block)
static void ohci_iso_recv_bufferfill_release(struct ohci_iso_recv *recv,
struct hpsb_iso_packet_info *info)
{
- int len;
-
/* release the memory where the packet was */
- len = info->len;
-
- /* add the wasted space for padding to 4 bytes */
- if (len % 4)
- len += 4 - (len % 4);
-
- /* add 8 bytes for the OHCI DMA data format overhead */
- len += 8;
-
- recv->released_bytes += len;
+ recv->released_bytes += info->total_len;
/* have we released enough memory for one block? */
while (recv->released_bytes > recv->buf_stride) {
@@ -1637,7 +1636,7 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso
/* note: packet layout is as shown in section 10.6.1.1 of the OHCI spec */
unsigned int offset;
- unsigned short len, cycle;
+ unsigned short len, cycle, total_len;
unsigned char channel, tag, sy;
unsigned char *p = iso->data_buf.kvirt;
@@ -1688,9 +1687,11 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso
/* advance to xferStatus/timeStamp */
recv->dma_offset += len;
+ total_len = len + 8; /* 8 bytes header+trailer in OHCI packet */
/* payload is padded to 4 bytes */
if (len % 4) {
recv->dma_offset += 4 - (len%4);
+ total_len += 4 - (len%4);
}
/* check for wrap-around */
@@ -1724,7 +1725,7 @@ static void ohci_iso_recv_bufferfill_parse(struct hpsb_iso *iso, struct ohci_iso
recv->dma_offset -= recv->buf_stride*recv->nblocks;
}
- hpsb_iso_packet_received(iso, offset, len, cycle, channel, tag, sy);
+ hpsb_iso_packet_received(iso, offset, len, total_len, cycle, channel, tag, sy);
}
if (wake)
@@ -1850,7 +1851,8 @@ static void ohci_iso_recv_packetperbuf_task(struct hpsb_iso *iso, struct ohci_is
tag = hdr[5] >> 6;
sy = hdr[4] & 0xF;
- hpsb_iso_packet_received(iso, offset, packet_len, cycle, channel, tag, sy);
+ hpsb_iso_packet_received(iso, offset, packet_len,
+ recv->buf_stride, cycle, channel, tag, sy);
}
/* reset the DMA descriptor */
@@ -3538,8 +3540,8 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
static int ohci1394_pci_resume (struct pci_dev *pdev)
{
-#ifdef CONFIG_PMAC_PBOOK
- {
+#ifdef CONFIG_PPC_PMAC
+ if (_machine == _MACH_Pmac) {
struct device_node *of_node;
/* Re-enable 1394 */
@@ -3547,7 +3549,7 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
if (of_node)
pmac_call_feature (PMAC_FTR_1394_ENABLE, of_node, 0, 1);
}
-#endif
+#endif /* CONFIG_PPC_PMAC */
pci_enable_device(pdev);
@@ -3557,8 +3559,8 @@ static int ohci1394_pci_resume (struct pci_dev *pdev)
static int ohci1394_pci_suspend (struct pci_dev *pdev, pm_message_t state)
{
-#ifdef CONFIG_PMAC_PBOOK
- {
+#ifdef CONFIG_PPC_PMAC
+ if (_machine == _MACH_Pmac) {
struct device_node *of_node;
/* Disable 1394 */
diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c
index bdb3a85cafa6..36074e6eeebb 100644
--- a/drivers/ieee1394/pcilynx.c
+++ b/drivers/ieee1394/pcilynx.c
@@ -76,7 +76,7 @@
/* Module Parameters */
-static int skip_eeprom = 0;
+static int skip_eeprom;
module_param(skip_eeprom, int, 0444);
MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
@@ -1422,7 +1422,7 @@ static int __devinit add_card(struct pci_dev *dev,
i = get_phy_reg(lynx, 4);
i |= PHY_04_LCTRL;
if (hpsb_disable_irm)
- i &= !PHY_04_CONTENDER;
+ i &= ~PHY_04_CONTENDER;
else
i |= PHY_04_CONTENDER;
if (i != -1) set_phy_reg(lynx, 4, i);
diff --git a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
index 7419af450bd1..b4fa14793fe5 100644
--- a/drivers/ieee1394/raw1394.c
+++ b/drivers/ieee1394/raw1394.c
@@ -98,7 +98,7 @@ static struct hpsb_address_ops arm_ops = {
static void queue_complete_cb(struct pending_request *req);
-static struct pending_request *__alloc_pending_request(int flags)
+static struct pending_request *__alloc_pending_request(unsigned int __nocast flags)
{
struct pending_request *req;
@@ -2506,9 +2506,12 @@ static int raw1394_iso_send_packets(struct file_info *fi, void __user * uaddr)
if (copy_from_user(&upackets, uaddr, sizeof(upackets)))
return -EFAULT;
- if (upackets.n_packets > hpsb_iso_n_ready(fi->iso_handle))
+ if (upackets.n_packets >= fi->iso_handle->buf_packets)
return -EINVAL;
+ if (upackets.n_packets >= hpsb_iso_n_ready(fi->iso_handle))
+ return -EAGAIN;
+
/* ensure user-supplied buffer is accessible and big enough */
if (!access_ok(VERIFY_READ, upackets.infos,
upackets.n_packets *
diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
index 32368f3428ec..fe3e1703fa61 100644
--- a/drivers/ieee1394/sbp2.c
+++ b/drivers/ieee1394/sbp2.c
@@ -81,7 +81,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
- "$Rev: 1219 $ Ben Collins <bcollins@debian.org>";
+ "$Rev: 1306 $ Ben Collins <bcollins@debian.org>";
/*
* Module load parameter definitions
@@ -104,7 +104,7 @@ MODULE_PARM_DESC(max_speed, "Force max speed (3 = 800mb, 2 = 400mb default, 1 =
* down to us at a time (debugging). This might be necessary for very
* badly behaved sbp2 devices.
*/
-static int serialize_io = 0;
+static int serialize_io;
module_param(serialize_io, int, 0444);
MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
@@ -145,7 +145,7 @@ MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)"
* please submit the logged sbp2_firmware_revision value of this device to
* the linux1394-devel mailing list.
*/
-static int force_inquiry_hack = 0;
+static int force_inquiry_hack;
module_param(force_inquiry_hack, int, 0444);
MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
@@ -2112,6 +2112,102 @@ static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
*/
static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd)
{
+ unchar new_cmd[16];
+ u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
+
+ SBP2_DEBUG("sbp2_check_sbp2_command");
+
+ switch (*cmd) {
+
+ case READ_6:
+
+ if (sbp2_command_conversion_device_type(device_type)) {
+
+ SBP2_DEBUG("Convert READ_6 to READ_10");
+
+ /*
+ * Need to turn read_6 into read_10
+ */
+ new_cmd[0] = 0x28;
+ new_cmd[1] = (cmd[1] & 0xe0);
+ new_cmd[2] = 0x0;
+ new_cmd[3] = (cmd[1] & 0x1f);
+ new_cmd[4] = cmd[2];
+ new_cmd[5] = cmd[3];
+ new_cmd[6] = 0x0;
+ new_cmd[7] = 0x0;
+ new_cmd[8] = cmd[4];
+ new_cmd[9] = cmd[5];
+
+ memcpy(cmd, new_cmd, 10);
+
+ }
+
+ break;
+
+ case WRITE_6:
+
+ if (sbp2_command_conversion_device_type(device_type)) {
+
+ SBP2_DEBUG("Convert WRITE_6 to WRITE_10");
+
+ /*
+ * Need to turn write_6 into write_10
+ */
+ new_cmd[0] = 0x2a;
+ new_cmd[1] = (cmd[1] & 0xe0);
+ new_cmd[2] = 0x0;
+ new_cmd[3] = (cmd[1] & 0x1f);
+ new_cmd[4] = cmd[2];
+ new_cmd[5] = cmd[3];
+ new_cmd[6] = 0x0;
+ new_cmd[7] = 0x0;
+ new_cmd[8] = cmd[4];
+ new_cmd[9] = cmd[5];
+
+ memcpy(cmd, new_cmd, 10);
+
+ }
+
+ break;
+
+ case MODE_SENSE:
+
+ if (sbp2_command_conversion_device_type(device_type)) {
+
+ SBP2_DEBUG("Convert MODE_SENSE_6 to MODE_SENSE_10");
+
+ /*
+ * Need to turn mode_sense_6 into mode_sense_10
+ */
+ new_cmd[0] = 0x5a;
+ new_cmd[1] = cmd[1];
+ new_cmd[2] = cmd[2];
+ new_cmd[3] = 0x0;
+ new_cmd[4] = 0x0;
+ new_cmd[5] = 0x0;
+ new_cmd[6] = 0x0;
+ new_cmd[7] = 0x0;
+ new_cmd[8] = cmd[4];
+ new_cmd[9] = cmd[5];
+
+ memcpy(cmd, new_cmd, 10);
+
+ }
+
+ break;
+
+ case MODE_SELECT:
+
+ /*
+ * TODO. Probably need to change mode select to 10 byte version
+ */
+
+ default:
+ break;
+ }
+
+ return;
}
/*
@@ -2152,6 +2248,7 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
struct scsi_cmnd *SCpnt)
{
u8 *scsi_buf = SCpnt->request_buffer;
+ u8 device_type = SBP2_DEVICE_TYPE (scsi_id->sbp2_device_type_and_lun);
SBP2_DEBUG("sbp2_check_sbp2_response");
@@ -2176,6 +2273,14 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
}
/*
+ * Check for Simple Direct Access Device and change it to TYPE_DISK
+ */
+ if ((scsi_buf[0] & 0x1f) == TYPE_RBC) {
+ SBP2_DEBUG("Changing TYPE_RBC to TYPE_DISK");
+ scsi_buf[0] &= 0xe0;
+ }
+
+ /*
* Fix ansi revision and response data format
*/
scsi_buf[2] |= 2;
@@ -2183,6 +2288,27 @@ static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id,
break;
+ case MODE_SENSE:
+
+ if (sbp2_command_conversion_device_type(device_type)) {
+
+ SBP2_DEBUG("Modify mode sense response (10 byte version)");
+
+ scsi_buf[0] = scsi_buf[1]; /* Mode data length */
+ scsi_buf[1] = scsi_buf[2]; /* Medium type */
+ scsi_buf[2] = scsi_buf[3]; /* Device specific parameter */
+ scsi_buf[3] = scsi_buf[7]; /* Block descriptor length */
+ memcpy(scsi_buf + 4, scsi_buf + 8, scsi_buf[0]);
+ }
+
+ break;
+
+ case MODE_SELECT:
+
+ /*
+ * TODO. Probably need to change mode select to 10 byte version
+ */
+
default:
break;
}
@@ -2559,8 +2685,7 @@ static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
static int sbp2scsi_slave_configure (struct scsi_device *sdev)
{
blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
- sdev->use_10_for_rw = 1;
- sdev->use_10_for_ms = 1;
+
return 0;
}
diff --git a/drivers/infiniband/Kconfig b/drivers/infiniband/Kconfig
index 3cc3ff0cccb1..79c8e2dd9c33 100644
--- a/drivers/infiniband/Kconfig
+++ b/drivers/infiniband/Kconfig
@@ -7,6 +7,16 @@ config INFINIBAND
any protocols you wish to use as well as drivers for your
InfiniBand hardware.
+config INFINIBAND_USER_VERBS
+ tristate "InfiniBand userspace verbs support"
+ depends on INFINIBAND
+ ---help---
+ Userspace InfiniBand verbs support. This is the kernel side
+ of userspace verbs, which allows userspace processes to
+ directly access InfiniBand hardware for fast-path
+ operations. You will also need libibverbs and a hardware
+ driver library from <http://www.openib.org>.
+
source "drivers/infiniband/hw/mthca/Kconfig"
source "drivers/infiniband/ulp/ipoib/Kconfig"
diff --git a/drivers/infiniband/core/Makefile b/drivers/infiniband/core/Makefile
index d2dbfb52c0a3..e1a7cf3e8636 100644
--- a/drivers/infiniband/core/Makefile
+++ b/drivers/infiniband/core/Makefile
@@ -1,6 +1,7 @@
EXTRA_CFLAGS += -Idrivers/infiniband/include
-obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND) += ib_core.o ib_mad.o ib_sa.o ib_umad.o
+obj-$(CONFIG_INFINIBAND_USER_VERBS) += ib_uverbs.o
ib_core-y := packer.o ud_header.o verbs.o sysfs.o \
device.o fmr_pool.o cache.o
@@ -10,3 +11,5 @@ ib_mad-y := mad.o smi.o agent.o
ib_sa-y := sa_query.o
ib_umad-y := user_mad.o
+
+ib_uverbs-y := uverbs_main.o uverbs_cmd.o uverbs_mem.o
diff --git a/drivers/infiniband/core/packer.c b/drivers/infiniband/core/packer.c
index 5f15feffeae2..eb5ff54c10d7 100644
--- a/drivers/infiniband/core/packer.c
+++ b/drivers/infiniband/core/packer.c
@@ -96,7 +96,7 @@ void ib_pack(const struct ib_field *desc,
else
val = 0;
- mask = cpu_to_be64(((1ull << desc[i].size_bits) - 1) << shift);
+ mask = cpu_to_be64((~0ull >> (64 - desc[i].size_bits)) << shift);
addr = (__be64 *) ((__be32 *) buf + desc[i].offset_words);
*addr = (*addr & ~mask) | (cpu_to_be64(val) & mask);
} else {
@@ -176,7 +176,7 @@ void ib_unpack(const struct ib_field *desc,
__be64 *addr;
shift = 64 - desc[i].offset_bits - desc[i].size_bits;
- mask = ((1ull << desc[i].size_bits) - 1) << shift;
+ mask = (~0ull >> (64 - desc[i].size_bits)) << shift;
addr = (__be64 *) buf + desc[i].offset_words;
val = (be64_to_cpup(addr) & mask) >> shift;
value_write(desc[i].struct_offset_bytes,
diff --git a/drivers/infiniband/core/sa_query.c b/drivers/infiniband/core/sa_query.c
index 276e1a53010d..5a08e81fa827 100644
--- a/drivers/infiniband/core/sa_query.c
+++ b/drivers/infiniband/core/sa_query.c
@@ -507,7 +507,13 @@ retry:
spin_unlock_irqrestore(&idr_lock, flags);
}
- return ret;
+ /*
+ * It's not safe to dereference query any more, because the
+ * send may already have completed and freed the query in
+ * another context. So use wr.wr_id, which has a copy of the
+ * query's id.
+ */
+ return ret ? ret : wr.wr_id;
}
static void ib_sa_path_rec_callback(struct ib_sa_query *sa_query,
@@ -598,14 +604,15 @@ int ib_sa_path_rec_get(struct ib_device *device, u8 port_num,
rec, query->sa_query.mad->data);
*sa_query = &query->sa_query;
+
ret = send_mad(&query->sa_query, timeout_ms);
- if (ret) {
+ if (ret < 0) {
*sa_query = NULL;
kfree(query->sa_query.mad);
kfree(query);
}
- return ret ? ret : query->sa_query.id;
+ return ret;
}
EXPORT_SYMBOL(ib_sa_path_rec_get);
@@ -674,14 +681,15 @@ int ib_sa_mcmember_rec_query(struct ib_device *device, u8 port_num,
rec, query->sa_query.mad->data);
*sa_query = &query->sa_query;
+
ret = send_mad(&query->sa_query, timeout_ms);
- if (ret) {
+ if (ret < 0) {
*sa_query = NULL;
kfree(query->sa_query.mad);
kfree(query);
}
- return ret ? ret : query->sa_query.id;
+ return ret;
}
EXPORT_SYMBOL(ib_sa_mcmember_rec_query);
diff --git a/drivers/infiniband/core/uverbs.h b/drivers/infiniband/core/uverbs.h
new file mode 100644
index 000000000000..57347f1e82c1
--- /dev/null
+++ b/drivers/infiniband/core/uverbs.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id: uverbs.h 2559 2005-06-06 19:43:16Z roland $
+ */
+
+#ifndef UVERBS_H
+#define UVERBS_H
+
+/* Include device.h and fs.h until cdev.h is self-sufficient */
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/kref.h>
+#include <linux/idr.h>
+
+#include <ib_verbs.h>
+#include <ib_user_verbs.h>
+
+struct ib_uverbs_device {
+ int devnum;
+ struct cdev dev;
+ struct class_device class_dev;
+ struct ib_device *ib_dev;
+ int num_comp;
+};
+
+struct ib_uverbs_event_file {
+ struct kref ref;
+ struct ib_uverbs_file *uverbs_file;
+ spinlock_t lock;
+ int fd;
+ int is_async;
+ wait_queue_head_t poll_wait;
+ struct list_head event_list;
+};
+
+struct ib_uverbs_file {
+ struct kref ref;
+ struct ib_uverbs_device *device;
+ struct ib_ucontext *ucontext;
+ struct ib_event_handler event_handler;
+ struct ib_uverbs_event_file async_file;
+ struct ib_uverbs_event_file comp_file[1];
+};
+
+struct ib_uverbs_async_event {
+ struct ib_uverbs_async_event_desc desc;
+ struct list_head list;
+};
+
+struct ib_uverbs_comp_event {
+ struct ib_uverbs_comp_event_desc desc;
+ struct list_head list;
+};
+
+struct ib_uobject_mr {
+ struct ib_uobject uobj;
+ struct page *page_list;
+ struct scatterlist *sg_list;
+};
+
+extern struct semaphore ib_uverbs_idr_mutex;
+extern struct idr ib_uverbs_pd_idr;
+extern struct idr ib_uverbs_mr_idr;
+extern struct idr ib_uverbs_mw_idr;
+extern struct idr ib_uverbs_ah_idr;
+extern struct idr ib_uverbs_cq_idr;
+extern struct idr ib_uverbs_qp_idr;
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context);
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr);
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr);
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+ void *addr, size_t size, int write);
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem);
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem);
+
+#define IB_UVERBS_DECLARE_CMD(name) \
+ ssize_t ib_uverbs_##name(struct ib_uverbs_file *file, \
+ const char __user *buf, int in_len, \
+ int out_len)
+
+IB_UVERBS_DECLARE_CMD(query_params);
+IB_UVERBS_DECLARE_CMD(get_context);
+IB_UVERBS_DECLARE_CMD(query_device);
+IB_UVERBS_DECLARE_CMD(query_port);
+IB_UVERBS_DECLARE_CMD(query_gid);
+IB_UVERBS_DECLARE_CMD(query_pkey);
+IB_UVERBS_DECLARE_CMD(alloc_pd);
+IB_UVERBS_DECLARE_CMD(dealloc_pd);
+IB_UVERBS_DECLARE_CMD(reg_mr);
+IB_UVERBS_DECLARE_CMD(dereg_mr);
+IB_UVERBS_DECLARE_CMD(create_cq);
+IB_UVERBS_DECLARE_CMD(destroy_cq);
+IB_UVERBS_DECLARE_CMD(create_qp);
+IB_UVERBS_DECLARE_CMD(modify_qp);
+IB_UVERBS_DECLARE_CMD(destroy_qp);
+IB_UVERBS_DECLARE_CMD(attach_mcast);
+IB_UVERBS_DECLARE_CMD(detach_mcast);
+
+#endif /* UVERBS_H */
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
new file mode 100644
index 000000000000..5f2bbcda4c73
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -0,0 +1,1006 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id: uverbs_cmd.c 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+#define INIT_UDATA(udata, ibuf, obuf, ilen, olen) \
+ do { \
+ (udata)->inbuf = (void __user *) (ibuf); \
+ (udata)->outbuf = (void __user *) (obuf); \
+ (udata)->inlen = (ilen); \
+ (udata)->outlen = (olen); \
+ } while (0)
+
+ssize_t ib_uverbs_query_params(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_params cmd;
+ struct ib_uverbs_query_params_resp resp;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.num_cq_events = file->device->num_comp;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response, &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_get_context cmd;
+ struct ib_uverbs_get_context_resp resp;
+ struct ib_udata udata;
+ struct ib_device *ibdev = file->device->ib_dev;
+ int i;
+ int ret = in_len;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ file->ucontext = ibdev->alloc_ucontext(ibdev, &udata);
+ if (IS_ERR(file->ucontext)) {
+ ret = PTR_ERR(file->ucontext);
+ file->ucontext = NULL;
+ return ret;
+ }
+
+ file->ucontext->device = ibdev;
+ INIT_LIST_HEAD(&file->ucontext->pd_list);
+ INIT_LIST_HEAD(&file->ucontext->mr_list);
+ INIT_LIST_HEAD(&file->ucontext->mw_list);
+ INIT_LIST_HEAD(&file->ucontext->cq_list);
+ INIT_LIST_HEAD(&file->ucontext->qp_list);
+ INIT_LIST_HEAD(&file->ucontext->srq_list);
+ INIT_LIST_HEAD(&file->ucontext->ah_list);
+ spin_lock_init(&file->ucontext->lock);
+
+ resp.async_fd = file->async_file.fd;
+ for (i = 0; i < file->device->num_comp; ++i)
+ if (copy_to_user((void __user *) (unsigned long) cmd.cq_fd_tab +
+ i * sizeof (__u32),
+ &file->comp_file[i].fd, sizeof (__u32)))
+ goto err;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ goto err;
+
+ return in_len;
+
+err:
+ ibdev->dealloc_ucontext(file->ucontext);
+ file->ucontext = NULL;
+
+ return -EFAULT;
+}
+
+ssize_t ib_uverbs_query_device(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_device cmd;
+ struct ib_uverbs_query_device_resp resp;
+ struct ib_device_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_query_device(file->device->ib_dev, &attr);
+ if (ret)
+ return ret;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.fw_ver = attr.fw_ver;
+ resp.node_guid = attr.node_guid;
+ resp.sys_image_guid = attr.sys_image_guid;
+ resp.max_mr_size = attr.max_mr_size;
+ resp.page_size_cap = attr.page_size_cap;
+ resp.vendor_id = attr.vendor_id;
+ resp.vendor_part_id = attr.vendor_part_id;
+ resp.hw_ver = attr.hw_ver;
+ resp.max_qp = attr.max_qp;
+ resp.max_qp_wr = attr.max_qp_wr;
+ resp.device_cap_flags = attr.device_cap_flags;
+ resp.max_sge = attr.max_sge;
+ resp.max_sge_rd = attr.max_sge_rd;
+ resp.max_cq = attr.max_cq;
+ resp.max_cqe = attr.max_cqe;
+ resp.max_mr = attr.max_mr;
+ resp.max_pd = attr.max_pd;
+ resp.max_qp_rd_atom = attr.max_qp_rd_atom;
+ resp.max_ee_rd_atom = attr.max_ee_rd_atom;
+ resp.max_res_rd_atom = attr.max_res_rd_atom;
+ resp.max_qp_init_rd_atom = attr.max_qp_init_rd_atom;
+ resp.max_ee_init_rd_atom = attr.max_ee_init_rd_atom;
+ resp.atomic_cap = attr.atomic_cap;
+ resp.max_ee = attr.max_ee;
+ resp.max_rdd = attr.max_rdd;
+ resp.max_mw = attr.max_mw;
+ resp.max_raw_ipv6_qp = attr.max_raw_ipv6_qp;
+ resp.max_raw_ethy_qp = attr.max_raw_ethy_qp;
+ resp.max_mcast_grp = attr.max_mcast_grp;
+ resp.max_mcast_qp_attach = attr.max_mcast_qp_attach;
+ resp.max_total_mcast_qp_attach = attr.max_total_mcast_qp_attach;
+ resp.max_ah = attr.max_ah;
+ resp.max_fmr = attr.max_fmr;
+ resp.max_map_per_fmr = attr.max_map_per_fmr;
+ resp.max_srq = attr.max_srq;
+ resp.max_srq_wr = attr.max_srq_wr;
+ resp.max_srq_sge = attr.max_srq_sge;
+ resp.max_pkeys = attr.max_pkeys;
+ resp.local_ca_ack_delay = attr.local_ca_ack_delay;
+ resp.phys_port_cnt = file->device->ib_dev->phys_port_cnt;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_port(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_port cmd;
+ struct ib_uverbs_query_port_resp resp;
+ struct ib_port_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ ret = ib_query_port(file->device->ib_dev, cmd.port_num, &attr);
+ if (ret)
+ return ret;
+
+ memset(&resp, 0, sizeof resp);
+
+ resp.state = attr.state;
+ resp.max_mtu = attr.max_mtu;
+ resp.active_mtu = attr.active_mtu;
+ resp.gid_tbl_len = attr.gid_tbl_len;
+ resp.port_cap_flags = attr.port_cap_flags;
+ resp.max_msg_sz = attr.max_msg_sz;
+ resp.bad_pkey_cntr = attr.bad_pkey_cntr;
+ resp.qkey_viol_cntr = attr.qkey_viol_cntr;
+ resp.pkey_tbl_len = attr.pkey_tbl_len;
+ resp.lid = attr.lid;
+ resp.sm_lid = attr.sm_lid;
+ resp.lmc = attr.lmc;
+ resp.max_vl_num = attr.max_vl_num;
+ resp.sm_sl = attr.sm_sl;
+ resp.subnet_timeout = attr.subnet_timeout;
+ resp.init_type_reply = attr.init_type_reply;
+ resp.active_width = attr.active_width;
+ resp.active_speed = attr.active_speed;
+ resp.phys_state = attr.phys_state;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_gid(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_gid cmd;
+ struct ib_uverbs_query_gid_resp resp;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ ret = ib_query_gid(file->device->ib_dev, cmd.port_num, cmd.index,
+ (union ib_gid *) resp.gid);
+ if (ret)
+ return ret;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_query_pkey(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_query_pkey cmd;
+ struct ib_uverbs_query_pkey_resp resp;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ memset(&resp, 0, sizeof resp);
+
+ ret = ib_query_pkey(file->device->ib_dev, cmd.port_num, cmd.index,
+ &resp.pkey);
+ if (ret)
+ return ret;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp))
+ return -EFAULT;
+
+ return in_len;
+}
+
+ssize_t ib_uverbs_alloc_pd(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_alloc_pd cmd;
+ struct ib_uverbs_alloc_pd_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_pd *pd;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ uobj->context = file->ucontext;
+
+ pd = file->device->ib_dev->alloc_pd(file->device->ib_dev,
+ file->ucontext, &udata);
+ if (IS_ERR(pd)) {
+ ret = PTR_ERR(pd);
+ goto err;
+ }
+
+ pd->device = file->device->ib_dev;
+ pd->uobject = uobj;
+ atomic_set(&pd->usecnt, 0);
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_pd_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_pd;
+ }
+
+ down(&ib_uverbs_idr_mutex);
+ ret = idr_get_new(&ib_uverbs_pd_idr, pd, &uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_pd;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->pd_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ memset(&resp, 0, sizeof resp);
+ resp.pd_handle = uobj->id;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ down(&ib_uverbs_idr_mutex);
+ idr_remove(&ib_uverbs_pd_idr, uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+err_pd:
+ ib_dealloc_pd(pd);
+
+err:
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_dealloc_pd(struct ib_uverbs_file *file,
+ const char __user *buf,
+ int in_len, int out_len)
+{
+ struct ib_uverbs_dealloc_pd cmd;
+ struct ib_pd *pd;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ if (!pd || pd->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = pd->uobject;
+
+ ret = ib_dealloc_pd(pd);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_pd_idr, cmd.pd_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_reg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_reg_mr cmd;
+ struct ib_uverbs_reg_mr_resp resp;
+ struct ib_udata udata;
+ struct ib_umem_object *obj;
+ struct ib_pd *pd;
+ struct ib_mr *mr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ if ((cmd.start & ~PAGE_MASK) != (cmd.hca_va & ~PAGE_MASK))
+ return -EINVAL;
+
+ obj = kmalloc(sizeof *obj, GFP_KERNEL);
+ if (!obj)
+ return -ENOMEM;
+
+ obj->uobject.context = file->ucontext;
+
+ /*
+ * We ask for writable memory if any access flags other than
+ * "remote read" are set. "Local write" and "remote write"
+ * obviously require write access. "Remote atomic" can do
+ * things like fetch and add, which will modify memory, and
+ * "MW bind" can change permissions by binding a window.
+ */
+ ret = ib_umem_get(file->device->ib_dev, &obj->umem,
+ (void *) (unsigned long) cmd.start, cmd.length,
+ !!(cmd.access_flags & ~IB_ACCESS_REMOTE_READ));
+ if (ret)
+ goto err_free;
+
+ obj->umem.virt_base = cmd.hca_va;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ if (!pd || pd->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto err_up;
+ }
+
+ if (!pd->device->reg_user_mr) {
+ ret = -ENOSYS;
+ goto err_up;
+ }
+
+ mr = pd->device->reg_user_mr(pd, &obj->umem, cmd.access_flags, &udata);
+ if (IS_ERR(mr)) {
+ ret = PTR_ERR(mr);
+ goto err_up;
+ }
+
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = &obj->uobject;
+ atomic_inc(&pd->usecnt);
+ atomic_set(&mr->usecnt, 0);
+
+ memset(&resp, 0, sizeof resp);
+ resp.lkey = mr->lkey;
+ resp.rkey = mr->rkey;
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_mr_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_unreg;
+ }
+
+ ret = idr_get_new(&ib_uverbs_mr_idr, mr, &obj->uobject.id);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_unreg;
+
+ resp.mr_handle = obj->uobject.id;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&obj->uobject.list, &file->ucontext->mr_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&obj->uobject.list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+err_unreg:
+ ib_dereg_mr(mr);
+
+err_up:
+ up(&ib_uverbs_idr_mutex);
+
+ ib_umem_release(file->device->ib_dev, &obj->umem);
+
+err_free:
+ kfree(obj);
+ return ret;
+}
+
+ssize_t ib_uverbs_dereg_mr(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_dereg_mr cmd;
+ struct ib_mr *mr;
+ struct ib_umem_object *memobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ mr = idr_find(&ib_uverbs_mr_idr, cmd.mr_handle);
+ if (!mr || mr->uobject->context != file->ucontext)
+ goto out;
+
+ memobj = container_of(mr->uobject, struct ib_umem_object, uobject);
+
+ ret = ib_dereg_mr(mr);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_mr_idr, cmd.mr_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&memobj->uobject.list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ ib_umem_release(file->device->ib_dev, &memobj->umem);
+ kfree(memobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_cq(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_create_cq cmd;
+ struct ib_uverbs_create_cq_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_cq *cq;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ if (cmd.event_handler >= file->device->num_comp)
+ return -EINVAL;
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ uobj->user_handle = cmd.user_handle;
+ uobj->context = file->ucontext;
+
+ cq = file->device->ib_dev->create_cq(file->device->ib_dev, cmd.cqe,
+ file->ucontext, &udata);
+ if (IS_ERR(cq)) {
+ ret = PTR_ERR(cq);
+ goto err;
+ }
+
+ cq->device = file->device->ib_dev;
+ cq->uobject = uobj;
+ cq->comp_handler = ib_uverbs_comp_handler;
+ cq->event_handler = ib_uverbs_cq_event_handler;
+ cq->cq_context = file;
+ atomic_set(&cq->usecnt, 0);
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_cq_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_cq;
+ }
+
+ down(&ib_uverbs_idr_mutex);
+ ret = idr_get_new(&ib_uverbs_cq_idr, cq, &uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_cq;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->cq_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ memset(&resp, 0, sizeof resp);
+ resp.cq_handle = uobj->id;
+ resp.cqe = cq->cqe;
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ down(&ib_uverbs_idr_mutex);
+ idr_remove(&ib_uverbs_cq_idr, uobj->id);
+ up(&ib_uverbs_idr_mutex);
+
+err_cq:
+ ib_destroy_cq(cq);
+
+err:
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_destroy_cq(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_destroy_cq cmd;
+ struct ib_cq *cq;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ cq = idr_find(&ib_uverbs_cq_idr, cmd.cq_handle);
+ if (!cq || cq->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = cq->uobject;
+
+ ret = ib_destroy_cq(cq);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_cq_idr, cmd.cq_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_create_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_create_qp cmd;
+ struct ib_uverbs_create_qp_resp resp;
+ struct ib_udata udata;
+ struct ib_uobject *uobj;
+ struct ib_pd *pd;
+ struct ib_cq *scq, *rcq;
+ struct ib_qp *qp;
+ struct ib_qp_init_attr attr;
+ int ret;
+
+ if (out_len < sizeof resp)
+ return -ENOSPC;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ INIT_UDATA(&udata, buf + sizeof cmd,
+ (unsigned long) cmd.response + sizeof resp,
+ in_len - sizeof cmd, out_len - sizeof resp);
+
+ uobj = kmalloc(sizeof *uobj, GFP_KERNEL);
+ if (!uobj)
+ return -ENOMEM;
+
+ down(&ib_uverbs_idr_mutex);
+
+ pd = idr_find(&ib_uverbs_pd_idr, cmd.pd_handle);
+ scq = idr_find(&ib_uverbs_cq_idr, cmd.send_cq_handle);
+ rcq = idr_find(&ib_uverbs_cq_idr, cmd.recv_cq_handle);
+
+ if (!pd || pd->uobject->context != file->ucontext ||
+ !scq || scq->uobject->context != file->ucontext ||
+ !rcq || rcq->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto err_up;
+ }
+
+ attr.event_handler = ib_uverbs_qp_event_handler;
+ attr.qp_context = file;
+ attr.send_cq = scq;
+ attr.recv_cq = rcq;
+ attr.srq = NULL;
+ attr.sq_sig_type = cmd.sq_sig_all ? IB_SIGNAL_ALL_WR : IB_SIGNAL_REQ_WR;
+ attr.qp_type = cmd.qp_type;
+
+ attr.cap.max_send_wr = cmd.max_send_wr;
+ attr.cap.max_recv_wr = cmd.max_recv_wr;
+ attr.cap.max_send_sge = cmd.max_send_sge;
+ attr.cap.max_recv_sge = cmd.max_recv_sge;
+ attr.cap.max_inline_data = cmd.max_inline_data;
+
+ uobj->user_handle = cmd.user_handle;
+ uobj->context = file->ucontext;
+
+ qp = pd->device->create_qp(pd, &attr, &udata);
+ if (IS_ERR(qp)) {
+ ret = PTR_ERR(qp);
+ goto err_up;
+ }
+
+ qp->device = pd->device;
+ qp->pd = pd;
+ qp->send_cq = attr.send_cq;
+ qp->recv_cq = attr.recv_cq;
+ qp->srq = attr.srq;
+ qp->uobject = uobj;
+ qp->event_handler = attr.event_handler;
+ qp->qp_context = attr.qp_context;
+ qp->qp_type = attr.qp_type;
+ atomic_inc(&pd->usecnt);
+ atomic_inc(&attr.send_cq->usecnt);
+ atomic_inc(&attr.recv_cq->usecnt);
+ if (attr.srq)
+ atomic_inc(&attr.srq->usecnt);
+
+ memset(&resp, 0, sizeof resp);
+ resp.qpn = qp->qp_num;
+
+retry:
+ if (!idr_pre_get(&ib_uverbs_qp_idr, GFP_KERNEL)) {
+ ret = -ENOMEM;
+ goto err_destroy;
+ }
+
+ ret = idr_get_new(&ib_uverbs_qp_idr, qp, &uobj->id);
+
+ if (ret == -EAGAIN)
+ goto retry;
+ if (ret)
+ goto err_destroy;
+
+ resp.qp_handle = uobj->id;
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_add_tail(&uobj->list, &file->ucontext->qp_list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ if (copy_to_user((void __user *) (unsigned long) cmd.response,
+ &resp, sizeof resp)) {
+ ret = -EFAULT;
+ goto err_list;
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return in_len;
+
+err_list:
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+err_destroy:
+ ib_destroy_qp(qp);
+
+err_up:
+ up(&ib_uverbs_idr_mutex);
+
+ kfree(uobj);
+ return ret;
+}
+
+ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_modify_qp cmd;
+ struct ib_qp *qp;
+ struct ib_qp_attr *attr;
+ int ret;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ attr = kmalloc(sizeof *attr, GFP_KERNEL);
+ if (!attr)
+ return -ENOMEM;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (!qp || qp->uobject->context != file->ucontext) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ attr->qp_state = cmd.qp_state;
+ attr->cur_qp_state = cmd.cur_qp_state;
+ attr->path_mtu = cmd.path_mtu;
+ attr->path_mig_state = cmd.path_mig_state;
+ attr->qkey = cmd.qkey;
+ attr->rq_psn = cmd.rq_psn;
+ attr->sq_psn = cmd.sq_psn;
+ attr->dest_qp_num = cmd.dest_qp_num;
+ attr->qp_access_flags = cmd.qp_access_flags;
+ attr->pkey_index = cmd.pkey_index;
+ attr->alt_pkey_index = cmd.pkey_index;
+ attr->en_sqd_async_notify = cmd.en_sqd_async_notify;
+ attr->max_rd_atomic = cmd.max_rd_atomic;
+ attr->max_dest_rd_atomic = cmd.max_dest_rd_atomic;
+ attr->min_rnr_timer = cmd.min_rnr_timer;
+ attr->port_num = cmd.port_num;
+ attr->timeout = cmd.timeout;
+ attr->retry_cnt = cmd.retry_cnt;
+ attr->rnr_retry = cmd.rnr_retry;
+ attr->alt_port_num = cmd.alt_port_num;
+ attr->alt_timeout = cmd.alt_timeout;
+
+ memcpy(attr->ah_attr.grh.dgid.raw, cmd.dest.dgid, 16);
+ attr->ah_attr.grh.flow_label = cmd.dest.flow_label;
+ attr->ah_attr.grh.sgid_index = cmd.dest.sgid_index;
+ attr->ah_attr.grh.hop_limit = cmd.dest.hop_limit;
+ attr->ah_attr.grh.traffic_class = cmd.dest.traffic_class;
+ attr->ah_attr.dlid = cmd.dest.dlid;
+ attr->ah_attr.sl = cmd.dest.sl;
+ attr->ah_attr.src_path_bits = cmd.dest.src_path_bits;
+ attr->ah_attr.static_rate = cmd.dest.static_rate;
+ attr->ah_attr.ah_flags = cmd.dest.is_global ? IB_AH_GRH : 0;
+ attr->ah_attr.port_num = cmd.dest.port_num;
+
+ memcpy(attr->alt_ah_attr.grh.dgid.raw, cmd.alt_dest.dgid, 16);
+ attr->alt_ah_attr.grh.flow_label = cmd.alt_dest.flow_label;
+ attr->alt_ah_attr.grh.sgid_index = cmd.alt_dest.sgid_index;
+ attr->alt_ah_attr.grh.hop_limit = cmd.alt_dest.hop_limit;
+ attr->alt_ah_attr.grh.traffic_class = cmd.alt_dest.traffic_class;
+ attr->alt_ah_attr.dlid = cmd.alt_dest.dlid;
+ attr->alt_ah_attr.sl = cmd.alt_dest.sl;
+ attr->alt_ah_attr.src_path_bits = cmd.alt_dest.src_path_bits;
+ attr->alt_ah_attr.static_rate = cmd.alt_dest.static_rate;
+ attr->alt_ah_attr.ah_flags = cmd.alt_dest.is_global ? IB_AH_GRH : 0;
+ attr->alt_ah_attr.port_num = cmd.alt_dest.port_num;
+
+ ret = ib_modify_qp(qp, attr, cmd.attr_mask);
+ if (ret)
+ goto out;
+
+ ret = in_len;
+
+out:
+ up(&ib_uverbs_idr_mutex);
+ kfree(attr);
+
+ return ret;
+}
+
+ssize_t ib_uverbs_destroy_qp(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_destroy_qp cmd;
+ struct ib_qp *qp;
+ struct ib_uobject *uobj;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (!qp || qp->uobject->context != file->ucontext)
+ goto out;
+
+ uobj = qp->uobject;
+
+ ret = ib_destroy_qp(qp);
+ if (ret)
+ goto out;
+
+ idr_remove(&ib_uverbs_qp_idr, cmd.qp_handle);
+
+ spin_lock_irq(&file->ucontext->lock);
+ list_del(&uobj->list);
+ spin_unlock_irq(&file->ucontext->lock);
+
+ kfree(uobj);
+
+out:
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_attach_mcast(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_attach_mcast cmd;
+ struct ib_qp *qp;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (qp && qp->uobject->context == file->ucontext)
+ ret = ib_attach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
+
+ssize_t ib_uverbs_detach_mcast(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len)
+{
+ struct ib_uverbs_detach_mcast cmd;
+ struct ib_qp *qp;
+ int ret = -EINVAL;
+
+ if (copy_from_user(&cmd, buf, sizeof cmd))
+ return -EFAULT;
+
+ down(&ib_uverbs_idr_mutex);
+
+ qp = idr_find(&ib_uverbs_qp_idr, cmd.qp_handle);
+ if (qp && qp->uobject->context == file->ucontext)
+ ret = ib_detach_mcast(qp, (union ib_gid *) cmd.gid, cmd.mlid);
+
+ up(&ib_uverbs_idr_mutex);
+
+ return ret ? ret : in_len;
+}
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
new file mode 100644
index 000000000000..fbbe03d8c901
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id: uverbs_main.c 2733 2005-06-28 19:14:34Z roland $
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+
+#include <asm/uaccess.h>
+
+#include "uverbs.h"
+
+MODULE_AUTHOR("Roland Dreier");
+MODULE_DESCRIPTION("InfiniBand userspace verbs access");
+MODULE_LICENSE("Dual BSD/GPL");
+
+#define INFINIBANDEVENTFS_MAGIC 0x49426576 /* "IBev" */
+
+enum {
+ IB_UVERBS_MAJOR = 231,
+ IB_UVERBS_BASE_MINOR = 192,
+ IB_UVERBS_MAX_DEVICES = 32
+};
+
+#define IB_UVERBS_BASE_DEV MKDEV(IB_UVERBS_MAJOR, IB_UVERBS_BASE_MINOR)
+
+DECLARE_MUTEX(ib_uverbs_idr_mutex);
+DEFINE_IDR(ib_uverbs_pd_idr);
+DEFINE_IDR(ib_uverbs_mr_idr);
+DEFINE_IDR(ib_uverbs_mw_idr);
+DEFINE_IDR(ib_uverbs_ah_idr);
+DEFINE_IDR(ib_uverbs_cq_idr);
+DEFINE_IDR(ib_uverbs_qp_idr);
+
+static spinlock_t map_lock;
+static DECLARE_BITMAP(dev_map, IB_UVERBS_MAX_DEVICES);
+
+static ssize_t (*uverbs_cmd_table[])(struct ib_uverbs_file *file,
+ const char __user *buf, int in_len,
+ int out_len) = {
+ [IB_USER_VERBS_CMD_QUERY_PARAMS] = ib_uverbs_query_params,
+ [IB_USER_VERBS_CMD_GET_CONTEXT] = ib_uverbs_get_context,
+ [IB_USER_VERBS_CMD_QUERY_DEVICE] = ib_uverbs_query_device,
+ [IB_USER_VERBS_CMD_QUERY_PORT] = ib_uverbs_query_port,
+ [IB_USER_VERBS_CMD_QUERY_GID] = ib_uverbs_query_gid,
+ [IB_USER_VERBS_CMD_QUERY_PKEY] = ib_uverbs_query_pkey,
+ [IB_USER_VERBS_CMD_ALLOC_PD] = ib_uverbs_alloc_pd,
+ [IB_USER_VERBS_CMD_DEALLOC_PD] = ib_uverbs_dealloc_pd,
+ [IB_USER_VERBS_CMD_REG_MR] = ib_uverbs_reg_mr,
+ [IB_USER_VERBS_CMD_DEREG_MR] = ib_uverbs_dereg_mr,
+ [IB_USER_VERBS_CMD_CREATE_CQ] = ib_uverbs_create_cq,
+ [IB_USER_VERBS_CMD_DESTROY_CQ] = ib_uverbs_destroy_cq,
+ [IB_USER_VERBS_CMD_CREATE_QP] = ib_uverbs_create_qp,
+ [IB_USER_VERBS_CMD_MODIFY_QP] = ib_uverbs_modify_qp,
+ [IB_USER_VERBS_CMD_DESTROY_QP] = ib_uverbs_destroy_qp,
+ [IB_USER_VERBS_CMD_ATTACH_MCAST] = ib_uverbs_attach_mcast,
+ [IB_USER_VERBS_CMD_DETACH_MCAST] = ib_uverbs_detach_mcast,
+};
+
+static struct vfsmount *uverbs_event_mnt;
+
+static void ib_uverbs_add_one(struct ib_device *device);
+static void ib_uverbs_remove_one(struct ib_device *device);
+
+static int ib_dealloc_ucontext(struct ib_ucontext *context)
+{
+ struct ib_uobject *uobj, *tmp;
+
+ if (!context)
+ return 0;
+
+ down(&ib_uverbs_idr_mutex);
+
+ /* XXX Free AHs */
+
+ list_for_each_entry_safe(uobj, tmp, &context->qp_list, list) {
+ struct ib_qp *qp = idr_find(&ib_uverbs_qp_idr, uobj->id);
+ idr_remove(&ib_uverbs_qp_idr, uobj->id);
+ ib_destroy_qp(qp);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ list_for_each_entry_safe(uobj, tmp, &context->cq_list, list) {
+ struct ib_cq *cq = idr_find(&ib_uverbs_cq_idr, uobj->id);
+ idr_remove(&ib_uverbs_cq_idr, uobj->id);
+ ib_destroy_cq(cq);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ /* XXX Free SRQs */
+ /* XXX Free MWs */
+
+ list_for_each_entry_safe(uobj, tmp, &context->mr_list, list) {
+ struct ib_mr *mr = idr_find(&ib_uverbs_mr_idr, uobj->id);
+ struct ib_umem_object *memobj;
+
+ idr_remove(&ib_uverbs_mr_idr, uobj->id);
+ ib_dereg_mr(mr);
+
+ memobj = container_of(uobj, struct ib_umem_object, uobject);
+ ib_umem_release_on_close(mr->device, &memobj->umem);
+
+ list_del(&uobj->list);
+ kfree(memobj);
+ }
+
+ list_for_each_entry_safe(uobj, tmp, &context->pd_list, list) {
+ struct ib_pd *pd = idr_find(&ib_uverbs_pd_idr, uobj->id);
+ idr_remove(&ib_uverbs_pd_idr, uobj->id);
+ ib_dealloc_pd(pd);
+ list_del(&uobj->list);
+ kfree(uobj);
+ }
+
+ up(&ib_uverbs_idr_mutex);
+
+ return context->device->dealloc_ucontext(context);
+}
+
+static void ib_uverbs_release_file(struct kref *ref)
+{
+ struct ib_uverbs_file *file =
+ container_of(ref, struct ib_uverbs_file, ref);
+
+ module_put(file->device->ib_dev->owner);
+ kfree(file);
+}
+
+static ssize_t ib_uverbs_event_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ib_uverbs_event_file *file = filp->private_data;
+ void *event;
+ int eventsz;
+ int ret = 0;
+
+ spin_lock_irq(&file->lock);
+
+ while (list_empty(&file->event_list) && file->fd >= 0) {
+ spin_unlock_irq(&file->lock);
+
+ if (filp->f_flags & O_NONBLOCK)
+ return -EAGAIN;
+
+ if (wait_event_interruptible(file->poll_wait,
+ !list_empty(&file->event_list) ||
+ file->fd < 0))
+ return -ERESTARTSYS;
+
+ spin_lock_irq(&file->lock);
+ }
+
+ if (file->fd < 0) {
+ spin_unlock_irq(&file->lock);
+ return -ENODEV;
+ }
+
+ if (file->is_async) {
+ event = list_entry(file->event_list.next,
+ struct ib_uverbs_async_event, list);
+ eventsz = sizeof (struct ib_uverbs_async_event_desc);
+ } else {
+ event = list_entry(file->event_list.next,
+ struct ib_uverbs_comp_event, list);
+ eventsz = sizeof (struct ib_uverbs_comp_event_desc);
+ }
+
+ if (eventsz > count) {
+ ret = -EINVAL;
+ event = NULL;
+ } else
+ list_del(file->event_list.next);
+
+ spin_unlock_irq(&file->lock);
+
+ if (event) {
+ if (copy_to_user(buf, event, eventsz))
+ ret = -EFAULT;
+ else
+ ret = eventsz;
+ }
+
+ kfree(event);
+
+ return ret;
+}
+
+static unsigned int ib_uverbs_event_poll(struct file *filp,
+ struct poll_table_struct *wait)
+{
+ unsigned int pollflags = 0;
+ struct ib_uverbs_event_file *file = filp->private_data;
+
+ poll_wait(filp, &file->poll_wait, wait);
+
+ spin_lock_irq(&file->lock);
+ if (file->fd < 0)
+ pollflags = POLLERR;
+ else if (!list_empty(&file->event_list))
+ pollflags = POLLIN | POLLRDNORM;
+ spin_unlock_irq(&file->lock);
+
+ return pollflags;
+}
+
+static void ib_uverbs_event_release(struct ib_uverbs_event_file *file)
+{
+ struct list_head *entry, *tmp;
+
+ spin_lock_irq(&file->lock);
+ if (file->fd != -1) {
+ file->fd = -1;
+ list_for_each_safe(entry, tmp, &file->event_list)
+ if (file->is_async)
+ kfree(list_entry(entry, struct ib_uverbs_async_event, list));
+ else
+ kfree(list_entry(entry, struct ib_uverbs_comp_event, list));
+ }
+ spin_unlock_irq(&file->lock);
+}
+
+static int ib_uverbs_event_close(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_event_file *file = filp->private_data;
+
+ ib_uverbs_event_release(file);
+ kref_put(&file->uverbs_file->ref, ib_uverbs_release_file);
+
+ return 0;
+}
+
+static struct file_operations uverbs_event_fops = {
+ /*
+ * No .owner field since we artificially create event files,
+ * so there is no increment to the module reference count in
+ * the open path. All event files come from a uverbs command
+ * file, which already takes a module reference, so this is OK.
+ */
+ .read = ib_uverbs_event_read,
+ .poll = ib_uverbs_event_poll,
+ .release = ib_uverbs_event_close
+};
+
+void ib_uverbs_comp_handler(struct ib_cq *cq, void *cq_context)
+{
+ struct ib_uverbs_file *file = cq_context;
+ struct ib_uverbs_comp_event *entry;
+ unsigned long flags;
+
+ entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+ if (!entry)
+ return;
+
+ entry->desc.cq_handle = cq->uobject->user_handle;
+
+ spin_lock_irqsave(&file->comp_file[0].lock, flags);
+ list_add_tail(&entry->list, &file->comp_file[0].event_list);
+ spin_unlock_irqrestore(&file->comp_file[0].lock, flags);
+
+ wake_up_interruptible(&file->comp_file[0].poll_wait);
+}
+
+static void ib_uverbs_async_handler(struct ib_uverbs_file *file,
+ __u64 element, __u64 event)
+{
+ struct ib_uverbs_async_event *entry;
+ unsigned long flags;
+
+ entry = kmalloc(sizeof *entry, GFP_ATOMIC);
+ if (!entry)
+ return;
+
+ entry->desc.element = element;
+ entry->desc.event_type = event;
+
+ spin_lock_irqsave(&file->async_file.lock, flags);
+ list_add_tail(&entry->list, &file->async_file.event_list);
+ spin_unlock_irqrestore(&file->async_file.lock, flags);
+
+ wake_up_interruptible(&file->async_file.poll_wait);
+}
+
+void ib_uverbs_cq_event_handler(struct ib_event *event, void *context_ptr)
+{
+ ib_uverbs_async_handler(context_ptr,
+ event->element.cq->uobject->user_handle,
+ event->event);
+}
+
+void ib_uverbs_qp_event_handler(struct ib_event *event, void *context_ptr)
+{
+ ib_uverbs_async_handler(context_ptr,
+ event->element.qp->uobject->user_handle,
+ event->event);
+}
+
+static void ib_uverbs_event_handler(struct ib_event_handler *handler,
+ struct ib_event *event)
+{
+ struct ib_uverbs_file *file =
+ container_of(handler, struct ib_uverbs_file, event_handler);
+
+ ib_uverbs_async_handler(file, event->element.port_num, event->event);
+}
+
+static int ib_uverbs_event_init(struct ib_uverbs_event_file *file,
+ struct ib_uverbs_file *uverbs_file)
+{
+ struct file *filp;
+
+ spin_lock_init(&file->lock);
+ INIT_LIST_HEAD(&file->event_list);
+ init_waitqueue_head(&file->poll_wait);
+ file->uverbs_file = uverbs_file;
+
+ file->fd = get_unused_fd();
+ if (file->fd < 0)
+ return file->fd;
+
+ filp = get_empty_filp();
+ if (!filp) {
+ put_unused_fd(file->fd);
+ return -ENFILE;
+ }
+
+ filp->f_op = &uverbs_event_fops;
+ filp->f_vfsmnt = mntget(uverbs_event_mnt);
+ filp->f_dentry = dget(uverbs_event_mnt->mnt_root);
+ filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_flags = O_RDONLY;
+ filp->f_mode = FMODE_READ;
+ filp->private_data = file;
+
+ fd_install(file->fd, filp);
+
+ return 0;
+}
+
+static ssize_t ib_uverbs_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+ struct ib_uverbs_cmd_hdr hdr;
+
+ if (count < sizeof hdr)
+ return -EINVAL;
+
+ if (copy_from_user(&hdr, buf, sizeof hdr))
+ return -EFAULT;
+
+ if (hdr.in_words * 4 != count)
+ return -EINVAL;
+
+ if (hdr.command < 0 || hdr.command >= ARRAY_SIZE(uverbs_cmd_table))
+ return -EINVAL;
+
+ if (!file->ucontext &&
+ hdr.command != IB_USER_VERBS_CMD_QUERY_PARAMS &&
+ hdr.command != IB_USER_VERBS_CMD_GET_CONTEXT)
+ return -EINVAL;
+
+ return uverbs_cmd_table[hdr.command](file, buf + sizeof hdr,
+ hdr.in_words * 4, hdr.out_words * 4);
+}
+
+static int ib_uverbs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+
+ if (!file->ucontext)
+ return -ENODEV;
+ else
+ return file->device->ib_dev->mmap(file->ucontext, vma);
+}
+
+static int ib_uverbs_open(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_device *dev =
+ container_of(inode->i_cdev, struct ib_uverbs_device, dev);
+ struct ib_uverbs_file *file;
+ int i = 0;
+ int ret;
+
+ if (!try_module_get(dev->ib_dev->owner))
+ return -ENODEV;
+
+ file = kmalloc(sizeof *file +
+ (dev->num_comp - 1) * sizeof (struct ib_uverbs_event_file),
+ GFP_KERNEL);
+ if (!file)
+ return -ENOMEM;
+
+ file->device = dev;
+ kref_init(&file->ref);
+
+ file->ucontext = NULL;
+
+ ret = ib_uverbs_event_init(&file->async_file, file);
+ if (ret)
+ goto err;
+
+ file->async_file.is_async = 1;
+
+ kref_get(&file->ref);
+
+ for (i = 0; i < dev->num_comp; ++i) {
+ ret = ib_uverbs_event_init(&file->comp_file[i], file);
+ if (ret)
+ goto err_async;
+ kref_get(&file->ref);
+ file->comp_file[i].is_async = 0;
+ }
+
+
+ filp->private_data = file;
+
+ INIT_IB_EVENT_HANDLER(&file->event_handler, dev->ib_dev,
+ ib_uverbs_event_handler);
+ if (ib_register_event_handler(&file->event_handler))
+ goto err_async;
+
+ return 0;
+
+err_async:
+ while (i--)
+ ib_uverbs_event_release(&file->comp_file[i]);
+
+ ib_uverbs_event_release(&file->async_file);
+
+err:
+ kref_put(&file->ref, ib_uverbs_release_file);
+
+ return ret;
+}
+
+static int ib_uverbs_close(struct inode *inode, struct file *filp)
+{
+ struct ib_uverbs_file *file = filp->private_data;
+ int i;
+
+ ib_unregister_event_handler(&file->event_handler);
+ ib_uverbs_event_release(&file->async_file);
+ ib_dealloc_ucontext(file->ucontext);
+
+ for (i = 0; i < file->device->num_comp; ++i)
+ ib_uverbs_event_release(&file->comp_file[i]);
+
+ kref_put(&file->ref, ib_uverbs_release_file);
+
+ return 0;
+}
+
+static struct file_operations uverbs_fops = {
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
+ .open = ib_uverbs_open,
+ .release = ib_uverbs_close
+};
+
+static struct file_operations uverbs_mmap_fops = {
+ .owner = THIS_MODULE,
+ .write = ib_uverbs_write,
+ .mmap = ib_uverbs_mmap,
+ .open = ib_uverbs_open,
+ .release = ib_uverbs_close
+};
+
+static struct ib_client uverbs_client = {
+ .name = "uverbs",
+ .add = ib_uverbs_add_one,
+ .remove = ib_uverbs_remove_one
+};
+
+static ssize_t show_ibdev(struct class_device *class_dev, char *buf)
+{
+ struct ib_uverbs_device *dev =
+ container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+ return sprintf(buf, "%s\n", dev->ib_dev->name);
+}
+static CLASS_DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
+
+static void ib_uverbs_release_class_dev(struct class_device *class_dev)
+{
+ struct ib_uverbs_device *dev =
+ container_of(class_dev, struct ib_uverbs_device, class_dev);
+
+ cdev_del(&dev->dev);
+ clear_bit(dev->devnum, dev_map);
+ kfree(dev);
+}
+
+static struct class uverbs_class = {
+ .name = "infiniband_verbs",
+ .release = ib_uverbs_release_class_dev
+};
+
+static ssize_t show_abi_version(struct class *class, char *buf)
+{
+ return sprintf(buf, "%d\n", IB_USER_VERBS_ABI_VERSION);
+}
+static CLASS_ATTR(abi_version, S_IRUGO, show_abi_version, NULL);
+
+static void ib_uverbs_add_one(struct ib_device *device)
+{
+ struct ib_uverbs_device *uverbs_dev;
+
+ if (!device->alloc_ucontext)
+ return;
+
+ uverbs_dev = kmalloc(sizeof *uverbs_dev, GFP_KERNEL);
+ if (!uverbs_dev)
+ return;
+
+ memset(uverbs_dev, 0, sizeof *uverbs_dev);
+
+ spin_lock(&map_lock);
+ uverbs_dev->devnum = find_first_zero_bit(dev_map, IB_UVERBS_MAX_DEVICES);
+ if (uverbs_dev->devnum >= IB_UVERBS_MAX_DEVICES) {
+ spin_unlock(&map_lock);
+ goto err;
+ }
+ set_bit(uverbs_dev->devnum, dev_map);
+ spin_unlock(&map_lock);
+
+ uverbs_dev->ib_dev = device;
+ uverbs_dev->num_comp = 1;
+
+ if (device->mmap)
+ cdev_init(&uverbs_dev->dev, &uverbs_mmap_fops);
+ else
+ cdev_init(&uverbs_dev->dev, &uverbs_fops);
+ uverbs_dev->dev.owner = THIS_MODULE;
+ kobject_set_name(&uverbs_dev->dev.kobj, "uverbs%d", uverbs_dev->devnum);
+ if (cdev_add(&uverbs_dev->dev, IB_UVERBS_BASE_DEV + uverbs_dev->devnum, 1))
+ goto err;
+
+ uverbs_dev->class_dev.class = &uverbs_class;
+ uverbs_dev->class_dev.dev = device->dma_device;
+ uverbs_dev->class_dev.devt = uverbs_dev->dev.dev;
+ snprintf(uverbs_dev->class_dev.class_id, BUS_ID_SIZE, "uverbs%d", uverbs_dev->devnum);
+ if (class_device_register(&uverbs_dev->class_dev))
+ goto err_cdev;
+
+ if (class_device_create_file(&uverbs_dev->class_dev, &class_device_attr_ibdev))
+ goto err_class;
+
+ ib_set_client_data(device, &uverbs_client, uverbs_dev);
+
+ return;
+
+err_class:
+ class_device_unregister(&uverbs_dev->class_dev);
+
+err_cdev:
+ cdev_del(&uverbs_dev->dev);
+ clear_bit(uverbs_dev->devnum, dev_map);
+
+err:
+ kfree(uverbs_dev);
+ return;
+}
+
+static void ib_uverbs_remove_one(struct ib_device *device)
+{
+ struct ib_uverbs_device *uverbs_dev = ib_get_client_data(device, &uverbs_client);
+
+ if (!uverbs_dev)
+ return;
+
+ class_device_unregister(&uverbs_dev->class_dev);
+}
+
+static struct super_block *uverbs_event_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return get_sb_pseudo(fs_type, "infinibandevent:", NULL,
+ INFINIBANDEVENTFS_MAGIC);
+}
+
+static struct file_system_type uverbs_event_fs = {
+ /* No owner field so module can be unloaded */
+ .name = "infinibandeventfs",
+ .get_sb = uverbs_event_get_sb,
+ .kill_sb = kill_litter_super
+};
+
+static int __init ib_uverbs_init(void)
+{
+ int ret;
+
+ spin_lock_init(&map_lock);
+
+ ret = register_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES,
+ "infiniband_verbs");
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register device number\n");
+ goto out;
+ }
+
+ ret = class_register(&uverbs_class);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't create class infiniband_verbs\n");
+ goto out_chrdev;
+ }
+
+ ret = class_create_file(&uverbs_class, &class_attr_abi_version);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't create abi_version attribute\n");
+ goto out_class;
+ }
+
+ ret = register_filesystem(&uverbs_event_fs);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register infinibandeventfs\n");
+ goto out_class;
+ }
+
+ uverbs_event_mnt = kern_mount(&uverbs_event_fs);
+ if (IS_ERR(uverbs_event_mnt)) {
+ ret = PTR_ERR(uverbs_event_mnt);
+ printk(KERN_ERR "user_verbs: couldn't mount infinibandeventfs\n");
+ goto out_fs;
+ }
+
+ ret = ib_register_client(&uverbs_client);
+ if (ret) {
+ printk(KERN_ERR "user_verbs: couldn't register client\n");
+ goto out_mnt;
+ }
+
+ return 0;
+
+out_mnt:
+ mntput(uverbs_event_mnt);
+
+out_fs:
+ unregister_filesystem(&uverbs_event_fs);
+
+out_class:
+ class_unregister(&uverbs_class);
+
+out_chrdev:
+ unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+
+out:
+ return ret;
+}
+
+static void __exit ib_uverbs_cleanup(void)
+{
+ ib_unregister_client(&uverbs_client);
+ mntput(uverbs_event_mnt);
+ unregister_filesystem(&uverbs_event_fs);
+ class_unregister(&uverbs_class);
+ unregister_chrdev_region(IB_UVERBS_BASE_DEV, IB_UVERBS_MAX_DEVICES);
+}
+
+module_init(ib_uverbs_init);
+module_exit(ib_uverbs_cleanup);
diff --git a/drivers/infiniband/core/uverbs_mem.c b/drivers/infiniband/core/uverbs_mem.c
new file mode 100644
index 000000000000..ed550f6595bd
--- /dev/null
+++ b/drivers/infiniband/core/uverbs_mem.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id: uverbs_mem.c 2743 2005-06-28 22:27:59Z roland $
+ */
+
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+
+#include "uverbs.h"
+
+struct ib_umem_account_work {
+ struct work_struct work;
+ struct mm_struct *mm;
+ unsigned long diff;
+};
+
+
+static void __ib_umem_release(struct ib_device *dev, struct ib_umem *umem, int dirty)
+{
+ struct ib_umem_chunk *chunk, *tmp;
+ int i;
+
+ list_for_each_entry_safe(chunk, tmp, &umem->chunk_list, list) {
+ dma_unmap_sg(dev->dma_device, chunk->page_list,
+ chunk->nents, DMA_BIDIRECTIONAL);
+ for (i = 0; i < chunk->nents; ++i) {
+ if (umem->writable && dirty)
+ set_page_dirty_lock(chunk->page_list[i].page);
+ put_page(chunk->page_list[i].page);
+ }
+
+ kfree(chunk);
+ }
+}
+
+int ib_umem_get(struct ib_device *dev, struct ib_umem *mem,
+ void *addr, size_t size, int write)
+{
+ struct page **page_list;
+ struct ib_umem_chunk *chunk;
+ unsigned long locked;
+ unsigned long lock_limit;
+ unsigned long cur_base;
+ unsigned long npages;
+ int ret = 0;
+ int off;
+ int i;
+
+ if (!can_do_mlock())
+ return -EPERM;
+
+ page_list = (struct page **) __get_free_page(GFP_KERNEL);
+ if (!page_list)
+ return -ENOMEM;
+
+ mem->user_base = (unsigned long) addr;
+ mem->length = size;
+ mem->offset = (unsigned long) addr & ~PAGE_MASK;
+ mem->page_size = PAGE_SIZE;
+ mem->writable = write;
+
+ INIT_LIST_HEAD(&mem->chunk_list);
+
+ npages = PAGE_ALIGN(size + mem->offset) >> PAGE_SHIFT;
+
+ down_write(&current->mm->mmap_sem);
+
+ locked = npages + current->mm->locked_vm;
+ lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT;
+
+ if ((locked > lock_limit) && !capable(CAP_IPC_LOCK)) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ cur_base = (unsigned long) addr & PAGE_MASK;
+
+ while (npages) {
+ ret = get_user_pages(current, current->mm, cur_base,
+ min_t(int, npages,
+ PAGE_SIZE / sizeof (struct page *)),
+ 1, !write, page_list, NULL);
+
+ if (ret < 0)
+ goto out;
+
+ cur_base += ret * PAGE_SIZE;
+ npages -= ret;
+
+ off = 0;
+
+ while (ret) {
+ chunk = kmalloc(sizeof *chunk + sizeof (struct scatterlist) *
+ min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK),
+ GFP_KERNEL);
+ if (!chunk) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ chunk->nents = min_t(int, ret, IB_UMEM_MAX_PAGE_CHUNK);
+ for (i = 0; i < chunk->nents; ++i) {
+ chunk->page_list[i].page = page_list[i + off];
+ chunk->page_list[i].offset = 0;
+ chunk->page_list[i].length = PAGE_SIZE;
+ }
+
+ chunk->nmap = dma_map_sg(dev->dma_device,
+ &chunk->page_list[0],
+ chunk->nents,
+ DMA_BIDIRECTIONAL);
+ if (chunk->nmap <= 0) {
+ for (i = 0; i < chunk->nents; ++i)
+ put_page(chunk->page_list[i].page);
+ kfree(chunk);
+
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret -= chunk->nents;
+ off += chunk->nents;
+ list_add_tail(&chunk->list, &mem->chunk_list);
+ }
+
+ ret = 0;
+ }
+
+out:
+ if (ret < 0)
+ __ib_umem_release(dev, mem, 0);
+ else
+ current->mm->locked_vm = locked;
+
+ up_write(&current->mm->mmap_sem);
+ free_page((unsigned long) page_list);
+
+ return ret;
+}
+
+void ib_umem_release(struct ib_device *dev, struct ib_umem *umem)
+{
+ __ib_umem_release(dev, umem, 1);
+
+ down_write(&current->mm->mmap_sem);
+ current->mm->locked_vm -=
+ PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+ up_write(&current->mm->mmap_sem);
+}
+
+static void ib_umem_account(void *work_ptr)
+{
+ struct ib_umem_account_work *work = work_ptr;
+
+ down_write(&work->mm->mmap_sem);
+ work->mm->locked_vm -= work->diff;
+ up_write(&work->mm->mmap_sem);
+ mmput(work->mm);
+ kfree(work);
+}
+
+void ib_umem_release_on_close(struct ib_device *dev, struct ib_umem *umem)
+{
+ struct ib_umem_account_work *work;
+ struct mm_struct *mm;
+
+ __ib_umem_release(dev, umem, 1);
+
+ mm = get_task_mm(current);
+ if (!mm)
+ return;
+
+ /*
+ * We may be called with the mm's mmap_sem already held. This
+ * can happen when a userspace munmap() is the call that drops
+ * the last reference to our file and calls our release
+ * method. If there are memory regions to destroy, we'll end
+ * up here and not be able to take the mmap_sem. Therefore we
+ * defer the vm_locked accounting to the system workqueue.
+ */
+
+ work = kmalloc(sizeof *work, GFP_KERNEL);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, ib_umem_account, work);
+ work->mm = mm;
+ work->diff = PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT;
+
+ schedule_work(&work->work);
+}
diff --git a/drivers/infiniband/core/verbs.c b/drivers/infiniband/core/verbs.c
index 7c08ed0cd7dd..2516f9646515 100644
--- a/drivers/infiniband/core/verbs.c
+++ b/drivers/infiniband/core/verbs.c
@@ -4,6 +4,7 @@
* Copyright (c) 2004 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -47,10 +48,11 @@ struct ib_pd *ib_alloc_pd(struct ib_device *device)
{
struct ib_pd *pd;
- pd = device->alloc_pd(device);
+ pd = device->alloc_pd(device, NULL, NULL);
if (!IS_ERR(pd)) {
- pd->device = device;
+ pd->device = device;
+ pd->uobject = NULL;
atomic_set(&pd->usecnt, 0);
}
@@ -76,8 +78,9 @@ struct ib_ah *ib_create_ah(struct ib_pd *pd, struct ib_ah_attr *ah_attr)
ah = pd->device->create_ah(pd, ah_attr);
if (!IS_ERR(ah)) {
- ah->device = pd->device;
- ah->pd = pd;
+ ah->device = pd->device;
+ ah->pd = pd;
+ ah->uobject = NULL;
atomic_inc(&pd->usecnt);
}
@@ -122,7 +125,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
{
struct ib_qp *qp;
- qp = pd->device->create_qp(pd, qp_init_attr);
+ qp = pd->device->create_qp(pd, qp_init_attr, NULL);
if (!IS_ERR(qp)) {
qp->device = pd->device;
@@ -130,6 +133,7 @@ struct ib_qp *ib_create_qp(struct ib_pd *pd,
qp->send_cq = qp_init_attr->send_cq;
qp->recv_cq = qp_init_attr->recv_cq;
qp->srq = qp_init_attr->srq;
+ qp->uobject = NULL;
qp->event_handler = qp_init_attr->event_handler;
qp->qp_context = qp_init_attr->qp_context;
qp->qp_type = qp_init_attr->qp_type;
@@ -197,10 +201,11 @@ struct ib_cq *ib_create_cq(struct ib_device *device,
{
struct ib_cq *cq;
- cq = device->create_cq(device, cqe);
+ cq = device->create_cq(device, cqe, NULL, NULL);
if (!IS_ERR(cq)) {
cq->device = device;
+ cq->uobject = NULL;
cq->comp_handler = comp_handler;
cq->event_handler = event_handler;
cq->cq_context = cq_context;
@@ -245,8 +250,9 @@ struct ib_mr *ib_get_dma_mr(struct ib_pd *pd, int mr_access_flags)
mr = pd->device->get_dma_mr(pd, mr_access_flags);
if (!IS_ERR(mr)) {
- mr->device = pd->device;
- mr->pd = pd;
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
}
@@ -267,8 +273,9 @@ struct ib_mr *ib_reg_phys_mr(struct ib_pd *pd,
mr_access_flags, iova_start);
if (!IS_ERR(mr)) {
- mr->device = pd->device;
- mr->pd = pd;
+ mr->device = pd->device;
+ mr->pd = pd;
+ mr->uobject = NULL;
atomic_inc(&pd->usecnt);
atomic_set(&mr->usecnt, 0);
}
@@ -344,8 +351,9 @@ struct ib_mw *ib_alloc_mw(struct ib_pd *pd)
mw = pd->device->alloc_mw(pd);
if (!IS_ERR(mw)) {
- mw->device = pd->device;
- mw->pd = pd;
+ mw->device = pd->device;
+ mw->pd = pd;
+ mw->uobject = NULL;
atomic_inc(&pd->usecnt);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_av.c b/drivers/infiniband/hw/mthca/mthca_av.c
index 085baf393ca4..d58dcbe66488 100644
--- a/drivers/infiniband/hw/mthca/mthca_av.c
+++ b/drivers/infiniband/hw/mthca/mthca_av.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.c b/drivers/infiniband/hw/mthca/mthca_cmd.c
index cd9ed958d92f..1557a522d831 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.c
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.c
@@ -431,6 +431,36 @@ static int mthca_cmd_imm(struct mthca_dev *dev,
timeout, status);
}
+int mthca_cmd_init(struct mthca_dev *dev)
+{
+ sema_init(&dev->cmd.hcr_sem, 1);
+ sema_init(&dev->cmd.poll_sem, 1);
+ dev->cmd.use_events = 0;
+
+ dev->hcr = ioremap(pci_resource_start(dev->pdev, 0) + MTHCA_HCR_BASE,
+ MTHCA_HCR_SIZE);
+ if (!dev->hcr) {
+ mthca_err(dev, "Couldn't map command register.");
+ return -ENOMEM;
+ }
+
+ dev->cmd.pool = pci_pool_create("mthca_cmd", dev->pdev,
+ MTHCA_MAILBOX_SIZE,
+ MTHCA_MAILBOX_SIZE, 0);
+ if (!dev->cmd.pool) {
+ iounmap(dev->hcr);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void mthca_cmd_cleanup(struct mthca_dev *dev)
+{
+ pci_pool_destroy(dev->cmd.pool);
+ iounmap(dev->hcr);
+}
+
/*
* Switch to using events to issue FW commands (should be called after
* event queue to command events has been initialized).
@@ -489,6 +519,33 @@ void mthca_cmd_use_polling(struct mthca_dev *dev)
up(&dev->cmd.poll_sem);
}
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+ unsigned int gfp_mask)
+{
+ struct mthca_mailbox *mailbox;
+
+ mailbox = kmalloc(sizeof *mailbox, gfp_mask);
+ if (!mailbox)
+ return ERR_PTR(-ENOMEM);
+
+ mailbox->buf = pci_pool_alloc(dev->cmd.pool, gfp_mask, &mailbox->dma);
+ if (!mailbox->buf) {
+ kfree(mailbox);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return mailbox;
+}
+
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox)
+{
+ if (!mailbox)
+ return;
+
+ pci_pool_free(dev->cmd.pool, mailbox->buf, mailbox->dma);
+ kfree(mailbox);
+}
+
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status)
{
u64 out;
@@ -513,20 +570,20 @@ int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status)
static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
u64 virt, u8 *status)
{
- u32 *inbox;
- dma_addr_t indma;
+ struct mthca_mailbox *mailbox;
struct mthca_icm_iter iter;
+ __be64 *pages;
int lg;
int nent = 0;
int i;
int err = 0;
int ts = 0, tc = 0;
- inbox = pci_alloc_consistent(dev->pdev, PAGE_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
-
- memset(inbox, 0, PAGE_SIZE);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ memset(mailbox->buf, 0, MTHCA_MAILBOX_SIZE);
+ pages = mailbox->buf;
for (mthca_icm_first(icm, &iter);
!mthca_icm_last(&iter);
@@ -546,19 +603,17 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
for (i = 0; i < mthca_icm_size(&iter) / (1 << lg); ++i, ++nent) {
if (virt != -1) {
- *((__be64 *) (inbox + nent * 4)) =
- cpu_to_be64(virt);
+ pages[nent * 2] = cpu_to_be64(virt);
virt += 1 << lg;
}
- *((__be64 *) (inbox + nent * 4 + 2)) =
- cpu_to_be64((mthca_icm_addr(&iter) +
- (i << lg)) | (lg - 12));
+ pages[nent * 2 + 1] = cpu_to_be64((mthca_icm_addr(&iter) +
+ (i << lg)) | (lg - 12));
ts += 1 << (lg - 10);
++tc;
- if (nent == PAGE_SIZE / 16) {
- err = mthca_cmd(dev, indma, nent, 0, op,
+ if (nent == MTHCA_MAILBOX_SIZE / 16) {
+ err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
CMD_TIME_CLASS_B, status);
if (err || *status)
goto out;
@@ -568,7 +623,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
if (nent)
- err = mthca_cmd(dev, indma, nent, 0, op,
+ err = mthca_cmd(dev, mailbox->dma, nent, 0, op,
CMD_TIME_CLASS_B, status);
switch (op) {
@@ -585,7 +640,7 @@ static int mthca_map_cmd(struct mthca_dev *dev, u16 op, struct mthca_icm *icm,
}
out:
- pci_free_consistent(dev->pdev, PAGE_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -606,8 +661,8 @@ int mthca_RUN_FW(struct mthca_dev *dev, u8 *status)
int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
u8 lg;
@@ -625,12 +680,12 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
#define QUERY_FW_EQ_ARM_BASE_OFFSET 0x40
#define QUERY_FW_EQ_SET_CI_BASE_OFFSET 0x48
- outbox = pci_alloc_consistent(dev->pdev, QUERY_FW_OUT_SIZE, &outdma);
- if (!outbox) {
- return -ENOMEM;
- }
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_FW,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_FW,
CMD_TIME_CLASS_A, status);
if (err)
@@ -681,15 +736,15 @@ int mthca_QUERY_FW(struct mthca_dev *dev, u8 *status)
}
out:
- pci_free_consistent(dev->pdev, QUERY_FW_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u8 info;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
#define ENABLE_LAM_OUT_SIZE 0x100
@@ -700,11 +755,12 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
#define ENABLE_LAM_INFO_HIDDEN_FLAG (1 << 4)
#define ENABLE_LAM_INFO_ECC_MASK 0x3
- outbox = pci_alloc_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_ENABLE_LAM,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_ENABLE_LAM,
CMD_TIME_CLASS_C, status);
if (err)
@@ -733,7 +789,7 @@ int mthca_ENABLE_LAM(struct mthca_dev *dev, u8 *status)
(unsigned long long) dev->ddr_end);
out:
- pci_free_consistent(dev->pdev, ENABLE_LAM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -744,9 +800,9 @@ int mthca_DISABLE_LAM(struct mthca_dev *dev, u8 *status)
int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u8 info;
u32 *outbox;
- dma_addr_t outdma;
int err = 0;
#define QUERY_DDR_OUT_SIZE 0x100
@@ -757,11 +813,12 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
#define QUERY_DDR_INFO_HIDDEN_FLAG (1 << 4)
#define QUERY_DDR_INFO_ECC_MASK 0x3
- outbox = pci_alloc_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DDR,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DDR,
CMD_TIME_CLASS_A, status);
if (err)
@@ -787,15 +844,15 @@ int mthca_QUERY_DDR(struct mthca_dev *dev, u8 *status)
(unsigned long long) dev->ddr_end);
out:
- pci_free_consistent(dev->pdev, QUERY_DDR_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
struct mthca_dev_lim *dev_lim, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
u8 field;
u16 size;
int err;
@@ -860,11 +917,12 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
#define QUERY_DEV_LIM_LAMR_OFFSET 0x9f
#define QUERY_DEV_LIM_MAX_ICM_SZ_OFFSET 0xa0
- outbox = pci_alloc_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_DEV_LIM,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_DEV_LIM,
CMD_TIME_CLASS_A, status);
if (err)
@@ -1020,15 +1078,15 @@ int mthca_QUERY_DEV_LIM(struct mthca_dev *dev,
}
out:
- pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
struct mthca_adapter *adapter, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *outbox;
- dma_addr_t outdma;
int err;
#define QUERY_ADAPTER_OUT_SIZE 0x100
@@ -1037,23 +1095,24 @@ int mthca_QUERY_ADAPTER(struct mthca_dev *dev,
#define QUERY_ADAPTER_REVISION_ID_OFFSET 0x08
#define QUERY_ADAPTER_INTA_PIN_OFFSET 0x10
- outbox = pci_alloc_consistent(dev->pdev, QUERY_ADAPTER_OUT_SIZE, &outdma);
- if (!outbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ outbox = mailbox->buf;
- err = mthca_cmd_box(dev, 0, outdma, 0, 0, CMD_QUERY_ADAPTER,
+ err = mthca_cmd_box(dev, 0, mailbox->dma, 0, 0, CMD_QUERY_ADAPTER,
CMD_TIME_CLASS_A, status);
if (err)
goto out;
- MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
- MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
+ MTHCA_GET(adapter->vendor_id, outbox, QUERY_ADAPTER_VENDOR_ID_OFFSET);
+ MTHCA_GET(adapter->device_id, outbox, QUERY_ADAPTER_DEVICE_ID_OFFSET);
MTHCA_GET(adapter->revision_id, outbox, QUERY_ADAPTER_REVISION_ID_OFFSET);
- MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
+ MTHCA_GET(adapter->inta_pin, outbox, QUERY_ADAPTER_INTA_PIN_OFFSET);
out:
- pci_free_consistent(dev->pdev, QUERY_DEV_LIM_OUT_SIZE, outbox, outdma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1061,8 +1120,8 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
struct mthca_init_hca_param *param,
u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
#define INIT_HCA_IN_SIZE 0x200
@@ -1102,9 +1161,10 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
#define INIT_HCA_UAR_SCATCH_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x10)
#define INIT_HCA_UAR_CTX_BASE_OFFSET (INIT_HCA_UAR_OFFSET + 0x18)
- inbox = pci_alloc_consistent(dev->pdev, INIT_HCA_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, INIT_HCA_IN_SIZE);
@@ -1167,10 +1227,9 @@ int mthca_INIT_HCA(struct mthca_dev *dev,
MTHCA_PUT(inbox, param->uarc_base, INIT_HCA_UAR_CTX_BASE_OFFSET);
}
- err = mthca_cmd(dev, indma, 0, 0, CMD_INIT_HCA,
- HZ, status);
+ err = mthca_cmd(dev, mailbox->dma, 0, 0, CMD_INIT_HCA, HZ, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1178,8 +1237,8 @@ int mthca_INIT_IB(struct mthca_dev *dev,
struct mthca_init_ib_param *param,
int port, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
u32 flags;
@@ -1199,9 +1258,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
#define INIT_IB_NODE_GUID_OFFSET 0x18
#define INIT_IB_SI_GUID_OFFSET 0x20
- inbox = pci_alloc_consistent(dev->pdev, INIT_IB_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, INIT_IB_IN_SIZE);
@@ -1221,10 +1281,10 @@ int mthca_INIT_IB(struct mthca_dev *dev,
MTHCA_PUT(inbox, param->node_guid, INIT_IB_NODE_GUID_OFFSET);
MTHCA_PUT(inbox, param->si_guid, INIT_IB_SI_GUID_OFFSET);
- err = mthca_cmd(dev, indma, port, 0, CMD_INIT_IB,
+ err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_INIT_IB,
CMD_TIME_CLASS_A, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1241,8 +1301,8 @@ int mthca_CLOSE_HCA(struct mthca_dev *dev, int panic, u8 *status)
int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
int port, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u32 *inbox;
- dma_addr_t indma;
int err;
u32 flags = 0;
@@ -1253,9 +1313,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
#define SET_IB_CAP_MASK_OFFSET 0x04
#define SET_IB_SI_GUID_OFFSET 0x08
- inbox = pci_alloc_consistent(dev->pdev, SET_IB_IN_SIZE, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
memset(inbox, 0, SET_IB_IN_SIZE);
@@ -1266,10 +1327,10 @@ int mthca_SET_IB(struct mthca_dev *dev, struct mthca_set_ib_param *param,
MTHCA_PUT(inbox, param->cap_mask, SET_IB_CAP_MASK_OFFSET);
MTHCA_PUT(inbox, param->si_guid, SET_IB_SI_GUID_OFFSET);
- err = mthca_cmd(dev, indma, port, 0, CMD_SET_IB,
+ err = mthca_cmd(dev, mailbox->dma, port, 0, CMD_SET_IB,
CMD_TIME_CLASS_B, status);
- pci_free_consistent(dev->pdev, INIT_HCA_IN_SIZE, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
@@ -1280,20 +1341,22 @@ int mthca_MAP_ICM(struct mthca_dev *dev, struct mthca_icm *icm, u64 virt, u8 *st
int mthca_MAP_ICM_page(struct mthca_dev *dev, u64 dma_addr, u64 virt, u8 *status)
{
+ struct mthca_mailbox *mailbox;
u64 *inbox;
- dma_addr_t indma;
int err;
- inbox = pci_alloc_consistent(dev->pdev, 16, &indma);
- if (!inbox)
- return -ENOMEM;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ inbox = mailbox->buf;
inbox[0] = cpu_to_be64(virt);
inbox[1] = cpu_to_be64(dma_addr);
- err = mthca_cmd(dev, indma, 1, 0, CMD_MAP_ICM, CMD_TIME_CLASS_B, status);
+ err = mthca_cmd(dev, mailbox->dma, 1, 0, CMD_MAP_ICM,
+ CMD_TIME_CLASS_B, status);
- pci_free_consistent(dev->pdev, 16, inbox, indma);
+ mthca_free_mailbox(dev, mailbox);
if (!err)
mthca_dbg(dev, "Mapped page at %llx to %llx for ICM.\n",
@@ -1338,69 +1401,26 @@ int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
return 0;
}
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mpt_entry,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, mpt_index, 0, CMD_SW2HW_MPT,
- CMD_TIME_CLASS_B, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_MPT_ENTRY_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, mpt_index, 0, CMD_SW2HW_MPT,
+ CMD_TIME_CLASS_B, status);
}
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- if (mpt_entry) {
- outdma = pci_map_single(dev->pdev, mpt_entry,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
- }
-
- err = mthca_cmd_box(dev, 0, outdma, mpt_index, !mpt_entry,
- CMD_HW2SW_MPT,
- CMD_TIME_CLASS_B, status);
-
- if (mpt_entry)
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_MPT_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0, mpt_index,
+ !mailbox, CMD_HW2SW_MPT,
+ CMD_TIME_CLASS_B, status);
}
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int num_mtt, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mtt_entry,
- (num_mtt + 2) * 8,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, num_mtt, 0, CMD_WRITE_MTT,
- CMD_TIME_CLASS_B, status);
-
- pci_unmap_single(dev->pdev, indma,
- (num_mtt + 2) * 8, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, num_mtt, 0, CMD_WRITE_MTT,
+ CMD_TIME_CLASS_B, status);
}
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status)
@@ -1418,92 +1438,38 @@ int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
0, CMD_MAP_EQ, CMD_TIME_CLASS_B, status);
}
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, eq_context,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, eq_num, 0, CMD_SW2HW_EQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_EQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, eq_num, 0, CMD_SW2HW_EQ,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, eq_context,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, eq_num, 0,
- CMD_HW2SW_EQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_EQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, eq_num, 0,
+ CMD_HW2SW_EQ,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, cq_context,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, cq_num, 0, CMD_SW2HW_CQ,
+ return mthca_cmd(dev, mailbox->dma, cq_num, 0, CMD_SW2HW_CQ,
CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_CQ_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- return err;
}
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, cq_context,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, cq_num, 0,
- CMD_HW2SW_CQ,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_CQ_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, cq_num, 0,
+ CMD_HW2SW_CQ,
+ CMD_TIME_CLASS_A, status);
}
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, void *qp_context, u32 optmask,
+ int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
u8 *status)
{
static const u16 op[] = {
@@ -1520,36 +1486,34 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
[MTHCA_TRANS_ANY2RST] = CMD_ERR2RST_QPEE
};
u8 op_mod = 0;
-
- dma_addr_t indma;
+ int my_mailbox = 0;
int err;
if (trans < 0 || trans >= ARRAY_SIZE(op))
return -EINVAL;
if (trans == MTHCA_TRANS_ANY2RST) {
- indma = 0;
op_mod = 3; /* don't write outbox, any->reset */
/* For debugging */
- qp_context = pci_alloc_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
- &indma);
- op_mod = 2; /* write outbox, any->reset */
+ if (!mailbox) {
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (!IS_ERR(mailbox)) {
+ my_mailbox = 1;
+ op_mod = 2; /* write outbox, any->reset */
+ } else
+ mailbox = NULL;
+ }
} else {
- indma = pci_map_single(dev->pdev, qp_context,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
if (0) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" opt param mask: %08x\n", be32_to_cpup(qp_context));
+ printk(" opt param mask: %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
printk(" [%02x] ", i * 4);
- printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+ printk(" %08x",
+ be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
printk("\n");
}
@@ -1557,55 +1521,39 @@ int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
}
if (trans == MTHCA_TRANS_ANY2RST) {
- err = mthca_cmd_box(dev, 0, indma, (!!is_ee << 24) | num,
- op_mod, op[trans], CMD_TIME_CLASS_C, status);
+ err = mthca_cmd_box(dev, 0, mailbox ? mailbox->dma : 0,
+ (!!is_ee << 24) | num, op_mod,
+ op[trans], CMD_TIME_CLASS_C, status);
- if (0) {
+ if (0 && mailbox) {
int i;
mthca_dbg(dev, "Dumping QP context:\n");
- printk(" %08x\n", be32_to_cpup(qp_context));
+ printk(" %08x\n", be32_to_cpup(mailbox->buf));
for (i = 0; i < 0x100 / 4; ++i) {
if (i % 8 == 0)
printk("[%02x] ", i * 4);
- printk(" %08x", be32_to_cpu(((u32 *) qp_context)[i + 2]));
+ printk(" %08x",
+ be32_to_cpu(((u32 *) mailbox->buf)[i + 2]));
if ((i + 1) % 8 == 0)
printk("\n");
}
}
} else
- err = mthca_cmd(dev, indma, (!!is_ee << 24) | num,
+ err = mthca_cmd(dev, mailbox->dma, (!!is_ee << 24) | num,
op_mod, op[trans], CMD_TIME_CLASS_C, status);
- if (trans != MTHCA_TRANS_ANY2RST)
- pci_unmap_single(dev->pdev, indma,
- MTHCA_QP_CONTEXT_SIZE, PCI_DMA_TODEVICE);
- else
- pci_free_consistent(dev->pdev, MTHCA_QP_CONTEXT_SIZE,
- qp_context, indma);
+ if (my_mailbox)
+ mthca_free_mailbox(dev, mailbox);
+
return err;
}
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
- void *qp_context, u8 *status)
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, qp_context,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, (!!is_ee << 24) | num, 0,
- CMD_QUERY_QPEE,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_QP_CONTEXT_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, (!!is_ee << 24) | num, 0,
+ CMD_QUERY_QPEE, CMD_TIME_CLASS_A, status);
}
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
@@ -1635,11 +1583,11 @@ int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
}
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
- int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
void *in_mad, void *response_mad, u8 *status)
{
- void *box;
- dma_addr_t dma;
+ struct mthca_mailbox *inmailbox, *outmailbox;
+ void *inbox;
int err;
u32 in_modifier = port;
u8 op_modifier = 0;
@@ -1653,11 +1601,18 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
#define MAD_IFC_PKEY_OFFSET 0x10e
#define MAD_IFC_GRH_OFFSET 0x140
- box = pci_alloc_consistent(dev->pdev, MAD_IFC_BOX_SIZE, &dma);
- if (!box)
- return -ENOMEM;
+ inmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(inmailbox))
+ return PTR_ERR(inmailbox);
+ inbox = inmailbox->buf;
- memcpy(box, in_mad, 256);
+ outmailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(outmailbox)) {
+ mthca_free_mailbox(dev, inmailbox);
+ return PTR_ERR(outmailbox);
+ }
+
+ memcpy(inbox, in_mad, 256);
/*
* Key check traps can't be generated unless we have in_wc to
@@ -1671,97 +1626,65 @@ int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
if (in_wc) {
u8 val;
- memset(box + 256, 0, 256);
+ memset(inbox + 256, 0, 256);
- MTHCA_PUT(box, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
- MTHCA_PUT(box, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->qp_num, MAD_IFC_MY_QPN_OFFSET);
+ MTHCA_PUT(inbox, in_wc->src_qp, MAD_IFC_RQPN_OFFSET);
val = in_wc->sl << 4;
- MTHCA_PUT(box, val, MAD_IFC_SL_OFFSET);
+ MTHCA_PUT(inbox, val, MAD_IFC_SL_OFFSET);
val = in_wc->dlid_path_bits |
(in_wc->wc_flags & IB_WC_GRH ? 0x80 : 0);
- MTHCA_PUT(box, val, MAD_IFC_GRH_OFFSET);
+ MTHCA_PUT(inbox, val, MAD_IFC_GRH_OFFSET);
- MTHCA_PUT(box, in_wc->slid, MAD_IFC_RLID_OFFSET);
- MTHCA_PUT(box, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
+ MTHCA_PUT(inbox, in_wc->slid, MAD_IFC_RLID_OFFSET);
+ MTHCA_PUT(inbox, in_wc->pkey_index, MAD_IFC_PKEY_OFFSET);
if (in_grh)
- memcpy((u8 *) box + MAD_IFC_GRH_OFFSET, in_grh, 40);
+ memcpy(inbox + MAD_IFC_GRH_OFFSET, in_grh, 40);
op_modifier |= 0x10;
in_modifier |= in_wc->slid << 16;
}
- err = mthca_cmd_box(dev, dma, dma + 512, in_modifier, op_modifier,
+ err = mthca_cmd_box(dev, inmailbox->dma, outmailbox->dma,
+ in_modifier, op_modifier,
CMD_MAD_IFC, CMD_TIME_CLASS_C, status);
if (!err && !*status)
- memcpy(response_mad, box + 512, 256);
+ memcpy(response_mad, outmailbox->buf, 256);
- pci_free_consistent(dev->pdev, MAD_IFC_BOX_SIZE, box, dma);
+ mthca_free_mailbox(dev, inmailbox);
+ mthca_free_mailbox(dev, outmailbox);
return err;
}
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status)
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t outdma = 0;
- int err;
-
- outdma = pci_map_single(dev->pdev, mgm,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(outdma))
- return -ENOMEM;
-
- err = mthca_cmd_box(dev, 0, outdma, index, 0,
- CMD_READ_MGM,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, outdma,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_FROMDEVICE);
- return err;
+ return mthca_cmd_box(dev, 0, mailbox->dma, index, 0,
+ CMD_READ_MGM, CMD_TIME_CLASS_A, status);
}
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status)
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status)
{
- dma_addr_t indma;
- int err;
-
- indma = pci_map_single(dev->pdev, mgm,
- MTHCA_MGM_ENTRY_SIZE,
- PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd(dev, indma, index, 0, CMD_WRITE_MGM,
- CMD_TIME_CLASS_A, status);
-
- pci_unmap_single(dev->pdev, indma,
- MTHCA_MGM_ENTRY_SIZE, PCI_DMA_TODEVICE);
- return err;
+ return mthca_cmd(dev, mailbox->dma, index, 0, CMD_WRITE_MGM,
+ CMD_TIME_CLASS_A, status);
}
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
- u8 *status)
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+ u16 *hash, u8 *status)
{
- dma_addr_t indma;
u64 imm;
int err;
- indma = pci_map_single(dev->pdev, gid, 16, PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(indma))
- return -ENOMEM;
-
- err = mthca_cmd_imm(dev, indma, &imm, 0, 0, CMD_MGID_HASH,
+ err = mthca_cmd_imm(dev, mailbox->dma, &imm, 0, 0, CMD_MGID_HASH,
CMD_TIME_CLASS_A, status);
- *hash = imm;
- pci_unmap_single(dev->pdev, indma, 16, PCI_DMA_TODEVICE);
+ *hash = imm;
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_cmd.h b/drivers/infiniband/hw/mthca/mthca_cmd.h
index adf039b3c540..ed517f175dd6 100644
--- a/drivers/infiniband/hw/mthca/mthca_cmd.h
+++ b/drivers/infiniband/hw/mthca/mthca_cmd.h
@@ -37,8 +37,7 @@
#include <ib_verbs.h>
-#define MTHCA_CMD_MAILBOX_ALIGN 16UL
-#define MTHCA_CMD_MAILBOX_EXTRA (MTHCA_CMD_MAILBOX_ALIGN - 1)
+#define MTHCA_MAILBOX_SIZE 4096
enum {
/* command completed successfully: */
@@ -112,6 +111,11 @@ enum {
DEV_LIM_FLAG_UD_MULTI = 1 << 21,
};
+struct mthca_mailbox {
+ dma_addr_t dma;
+ void *buf;
+};
+
struct mthca_dev_lim {
int max_srq_sz;
int max_qp_sz;
@@ -235,11 +239,17 @@ struct mthca_set_ib_param {
u32 cap_mask;
};
+int mthca_cmd_init(struct mthca_dev *dev);
+void mthca_cmd_cleanup(struct mthca_dev *dev);
int mthca_cmd_use_events(struct mthca_dev *dev);
void mthca_cmd_use_polling(struct mthca_dev *dev);
void mthca_cmd_event(struct mthca_dev *dev, u16 token,
u8 status, u64 out_param);
+struct mthca_mailbox *mthca_alloc_mailbox(struct mthca_dev *dev,
+ unsigned int gfp_mask);
+void mthca_free_mailbox(struct mthca_dev *dev, struct mthca_mailbox *mailbox);
+
int mthca_SYS_EN(struct mthca_dev *dev, u8 *status);
int mthca_SYS_DIS(struct mthca_dev *dev, u8 *status);
int mthca_MAP_FA(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
@@ -270,41 +280,39 @@ int mthca_MAP_ICM_AUX(struct mthca_dev *dev, struct mthca_icm *icm, u8 *status);
int mthca_UNMAP_ICM_AUX(struct mthca_dev *dev, u8 *status);
int mthca_SET_ICM_SIZE(struct mthca_dev *dev, u64 icm_size, u64 *aux_pages,
u8 *status);
-int mthca_SW2HW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_SW2HW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status);
-int mthca_HW2SW_MPT(struct mthca_dev *dev, void *mpt_entry,
+int mthca_HW2SW_MPT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int mpt_index, u8 *status);
-int mthca_WRITE_MTT(struct mthca_dev *dev, u64 *mtt_entry,
+int mthca_WRITE_MTT(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int num_mtt, u8 *status);
int mthca_SYNC_TPT(struct mthca_dev *dev, u8 *status);
int mthca_MAP_EQ(struct mthca_dev *dev, u64 event_mask, int unmap,
int eq_num, u8 *status);
-int mthca_SW2HW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_SW2HW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status);
-int mthca_HW2SW_EQ(struct mthca_dev *dev, void *eq_context,
+int mthca_HW2SW_EQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int eq_num, u8 *status);
-int mthca_SW2HW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_SW2HW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
-int mthca_HW2SW_CQ(struct mthca_dev *dev, void *cq_context,
+int mthca_HW2SW_CQ(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
int cq_num, u8 *status);
int mthca_MODIFY_QP(struct mthca_dev *dev, int trans, u32 num,
- int is_ee, void *qp_context, u32 optmask,
+ int is_ee, struct mthca_mailbox *mailbox, u32 optmask,
u8 *status);
int mthca_QUERY_QP(struct mthca_dev *dev, u32 num, int is_ee,
- void *qp_context, u8 *status);
+ struct mthca_mailbox *mailbox, u8 *status);
int mthca_CONF_SPECIAL_QP(struct mthca_dev *dev, int type, u32 qpn,
u8 *status);
int mthca_MAD_IFC(struct mthca_dev *dev, int ignore_mkey, int ignore_bkey,
- int port, struct ib_wc* in_wc, struct ib_grh* in_grh,
+ int port, struct ib_wc *in_wc, struct ib_grh *in_grh,
void *in_mad, void *response_mad, u8 *status);
-int mthca_READ_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status);
-int mthca_WRITE_MGM(struct mthca_dev *dev, int index, void *mgm,
- u8 *status);
-int mthca_MGID_HASH(struct mthca_dev *dev, void *gid, u16 *hash,
- u8 *status);
+int mthca_READ_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status);
+int mthca_WRITE_MGM(struct mthca_dev *dev, int index,
+ struct mthca_mailbox *mailbox, u8 *status);
+int mthca_MGID_HASH(struct mthca_dev *dev, struct mthca_mailbox *mailbox,
+ u16 *hash, u8 *status);
int mthca_NOP(struct mthca_dev *dev, u8 *status);
-#define MAILBOX_ALIGN(x) ((void *) ALIGN((unsigned long) (x), MTHCA_CMD_MAILBOX_ALIGN))
-
#endif /* MTHCA_CMD_H */
diff --git a/drivers/infiniband/hw/mthca/mthca_cq.c b/drivers/infiniband/hw/mthca/mthca_cq.c
index 2bf347b84c31..b5aea7b869f6 100644
--- a/drivers/infiniband/hw/mthca/mthca_cq.c
+++ b/drivers/infiniband/hw/mthca/mthca_cq.c
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -171,6 +173,17 @@ static inline void set_cqe_hw(struct mthca_cqe *cqe)
cqe->owner = MTHCA_CQ_ENTRY_OWNER_HW;
}
+static void dump_cqe(struct mthca_dev *dev, void *cqe_ptr)
+{
+ __be32 *cqe = cqe_ptr;
+
+ (void) cqe; /* avoid warning if mthca_dbg compiled away... */
+ mthca_dbg(dev, "CQE contents %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ be32_to_cpu(cqe[0]), be32_to_cpu(cqe[1]), be32_to_cpu(cqe[2]),
+ be32_to_cpu(cqe[3]), be32_to_cpu(cqe[4]), be32_to_cpu(cqe[5]),
+ be32_to_cpu(cqe[6]), be32_to_cpu(cqe[7]));
+}
+
/*
* incr is ignored in native Arbel (mem-free) mode, so cq->cons_index
* should be correct before calling update_cons_index().
@@ -280,16 +293,12 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
int dbd;
u32 new_wqe;
- if (1 && cqe->syndrome != SYNDROME_WR_FLUSH_ERR) {
- int j;
-
- mthca_dbg(dev, "%x/%d: error CQE -> QPN %06x, WQE @ %08x\n",
- cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
- be32_to_cpu(cqe->wqe));
-
- for (j = 0; j < 8; ++j)
- printk(KERN_DEBUG " [%2x] %08x\n",
- j * 4, be32_to_cpu(((u32 *) cqe)[j]));
+ if (cqe->syndrome == SYNDROME_LOCAL_QP_OP_ERR) {
+ mthca_dbg(dev, "local QP operation err "
+ "(QPN %06x, WQE @ %08x, CQN %06x, index %d)\n",
+ be32_to_cpu(cqe->my_qpn), be32_to_cpu(cqe->wqe),
+ cq->cqn, cq->cons_index);
+ dump_cqe(dev, cqe);
}
/*
@@ -377,15 +386,6 @@ static int handle_error_cqe(struct mthca_dev *dev, struct mthca_cq *cq,
return 0;
}
-static void dump_cqe(struct mthca_cqe *cqe)
-{
- int j;
-
- for (j = 0; j < 8; ++j)
- printk(KERN_DEBUG " [%2x] %08x\n",
- j * 4, be32_to_cpu(((u32 *) cqe)[j]));
-}
-
static inline int mthca_poll_one(struct mthca_dev *dev,
struct mthca_cq *cq,
struct mthca_qp **cur_qp,
@@ -414,8 +414,7 @@ static inline int mthca_poll_one(struct mthca_dev *dev,
mthca_dbg(dev, "%x/%d: CQE -> QPN %06x, WQE @ %08x\n",
cq->cqn, cq->cons_index, be32_to_cpu(cqe->my_qpn),
be32_to_cpu(cqe->wqe));
-
- dump_cqe(cqe);
+ dump_cqe(dev, cqe);
}
is_error = (cqe->opcode & MTHCA_ERROR_CQE_OPCODE_MASK) ==
@@ -638,19 +637,19 @@ static void mthca_free_cq_buf(struct mthca_dev *dev, struct mthca_cq *cq)
int size;
if (cq->is_direct)
- pci_free_consistent(dev->pdev,
- (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
- cq->queue.direct.buf,
- pci_unmap_addr(&cq->queue.direct,
- mapping));
+ dma_free_coherent(&dev->pdev->dev,
+ (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE,
+ cq->queue.direct.buf,
+ pci_unmap_addr(&cq->queue.direct,
+ mapping));
else {
size = (cq->ibcq.cqe + 1) * MTHCA_CQ_ENTRY_SIZE;
for (i = 0; i < (size + PAGE_SIZE - 1) / PAGE_SIZE; ++i)
if (cq->queue.page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- cq->queue.page_list[i].buf,
- pci_unmap_addr(&cq->queue.page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ cq->queue.page_list[i].buf,
+ pci_unmap_addr(&cq->queue.page_list[i],
+ mapping));
kfree(cq->queue.page_list);
}
@@ -670,8 +669,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
npages = 1;
shift = get_order(size) + PAGE_SHIFT;
- cq->queue.direct.buf = pci_alloc_consistent(dev->pdev,
- size, &t);
+ cq->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+ size, &t, GFP_KERNEL);
if (!cq->queue.direct.buf)
return -ENOMEM;
@@ -709,7 +708,8 @@ static int mthca_alloc_cq_buf(struct mthca_dev *dev, int size,
for (i = 0; i < npages; ++i) {
cq->queue.page_list[i].buf =
- pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+ dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ &t, GFP_KERNEL);
if (!cq->queue.page_list[i].buf)
goto err_free;
@@ -743,10 +743,11 @@ err_out:
}
int mthca_init_cq(struct mthca_dev *dev, int nent,
+ struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq)
{
int size = nent * MTHCA_CQ_ENTRY_SIZE;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_cq_context *cq_context;
int err = -ENOMEM;
u8 status;
@@ -754,45 +755,49 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
might_sleep();
- cq->ibcq.cqe = nent - 1;
+ cq->ibcq.cqe = nent - 1;
+ cq->is_kernel = !ctx;
cq->cqn = mthca_alloc(&dev->cq_table.alloc);
if (cq->cqn == -1)
return -ENOMEM;
if (mthca_is_memfree(dev)) {
- cq->arm_sn = 1;
-
err = mthca_table_get(dev, dev->cq_table.table, cq->cqn);
if (err)
goto err_out;
- err = -ENOMEM;
+ if (cq->is_kernel) {
+ cq->arm_sn = 1;
- cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
- cq->cqn, &cq->set_ci_db);
- if (cq->set_ci_db_index < 0)
- goto err_out_icm;
+ err = -ENOMEM;
- cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
- cq->cqn, &cq->arm_db);
- if (cq->arm_db_index < 0)
- goto err_out_ci;
+ cq->set_ci_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_SET_CI,
+ cq->cqn, &cq->set_ci_db);
+ if (cq->set_ci_db_index < 0)
+ goto err_out_icm;
+
+ cq->arm_db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_CQ_ARM,
+ cq->cqn, &cq->arm_db);
+ if (cq->arm_db_index < 0)
+ goto err_out_ci;
+ }
}
- mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
- goto err_out_mailbox;
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ goto err_out_arm;
- cq_context = MAILBOX_ALIGN(mailbox);
+ cq_context = mailbox->buf;
- err = mthca_alloc_cq_buf(dev, size, cq);
- if (err)
- goto err_out_mailbox;
+ if (cq->is_kernel) {
+ err = mthca_alloc_cq_buf(dev, size, cq);
+ if (err)
+ goto err_out_mailbox;
- for (i = 0; i < nent; ++i)
- set_cqe_hw(get_cqe(cq, i));
+ for (i = 0; i < nent; ++i)
+ set_cqe_hw(get_cqe(cq, i));
+ }
spin_lock_init(&cq->lock);
atomic_set(&cq->refcount, 1);
@@ -803,11 +808,14 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
MTHCA_CQ_STATE_DISARMED |
MTHCA_CQ_FLAG_TR);
cq_context->start = cpu_to_be64(0);
- cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24 |
- dev->driver_uar.index);
+ cq_context->logsize_usrpage = cpu_to_be32((ffs(nent) - 1) << 24);
+ if (ctx)
+ cq_context->logsize_usrpage |= cpu_to_be32(ctx->uar.index);
+ else
+ cq_context->logsize_usrpage |= cpu_to_be32(dev->driver_uar.index);
cq_context->error_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_ASYNC].eqn);
cq_context->comp_eqn = cpu_to_be32(dev->eq_table.eq[MTHCA_EQ_COMP].eqn);
- cq_context->pd = cpu_to_be32(dev->driver_pd.pd_num);
+ cq_context->pd = cpu_to_be32(pdn);
cq_context->lkey = cpu_to_be32(cq->mr.ibmr.lkey);
cq_context->cqn = cpu_to_be32(cq->cqn);
@@ -816,7 +824,7 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq_context->state_db = cpu_to_be32(cq->arm_db_index);
}
- err = mthca_SW2HW_CQ(dev, cq_context, cq->cqn, &status);
+ err = mthca_SW2HW_CQ(dev, mailbox, cq->cqn, &status);
if (err) {
mthca_warn(dev, "SW2HW_CQ failed (%d)\n", err);
goto err_out_free_mr;
@@ -840,22 +848,25 @@ int mthca_init_cq(struct mthca_dev *dev, int nent,
cq->cons_index = 0;
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return 0;
err_out_free_mr:
- mthca_free_mr(dev, &cq->mr);
- mthca_free_cq_buf(dev, cq);
+ if (cq->is_kernel) {
+ mthca_free_mr(dev, &cq->mr);
+ mthca_free_cq_buf(dev, cq);
+ }
err_out_mailbox:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
- if (mthca_is_memfree(dev))
+err_out_arm:
+ if (cq->is_kernel && mthca_is_memfree(dev))
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
err_out_ci:
- if (mthca_is_memfree(dev))
+ if (cq->is_kernel && mthca_is_memfree(dev))
mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
err_out_icm:
@@ -870,32 +881,31 @@ err_out:
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq)
{
- void *mailbox;
+ struct mthca_mailbox *mailbox;
int err;
u8 status;
might_sleep();
- mailbox = kmalloc(sizeof (struct mthca_cq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox) {
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox)) {
mthca_warn(dev, "No memory for mailbox to free CQ.\n");
return;
}
- err = mthca_HW2SW_CQ(dev, MAILBOX_ALIGN(mailbox), cq->cqn, &status);
+ err = mthca_HW2SW_CQ(dev, mailbox, cq->cqn, &status);
if (err)
mthca_warn(dev, "HW2SW_CQ failed (%d)\n", err);
else if (status)
- mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n",
- status);
+ mthca_warn(dev, "HW2SW_CQ returned status 0x%02x\n", status);
if (0) {
- u32 *ctx = MAILBOX_ALIGN(mailbox);
+ u32 *ctx = mailbox->buf;
int j;
printk(KERN_ERR "context for CQN %x (cons index %x, next sw %d)\n",
- cq->cqn, cq->cons_index, !!next_cqe_sw(cq));
+ cq->cqn, cq->cons_index,
+ cq->is_kernel ? !!next_cqe_sw(cq) : 0);
for (j = 0; j < 16; ++j)
printk(KERN_ERR "[%2x] %08x\n", j * 4, be32_to_cpu(ctx[j]));
}
@@ -913,17 +923,18 @@ void mthca_free_cq(struct mthca_dev *dev,
atomic_dec(&cq->refcount);
wait_event(cq->wait, !atomic_read(&cq->refcount));
- mthca_free_mr(dev, &cq->mr);
- mthca_free_cq_buf(dev, cq);
-
- if (mthca_is_memfree(dev)) {
- mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
- mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
- mthca_table_put(dev, dev->cq_table.table, cq->cqn);
+ if (cq->is_kernel) {
+ mthca_free_mr(dev, &cq->mr);
+ mthca_free_cq_buf(dev, cq);
+ if (mthca_is_memfree(dev)) {
+ mthca_free_db(dev, MTHCA_DB_TYPE_CQ_ARM, cq->arm_db_index);
+ mthca_free_db(dev, MTHCA_DB_TYPE_CQ_SET_CI, cq->set_ci_db_index);
+ }
}
+ mthca_table_put(dev, dev->cq_table.table, cq->cqn);
mthca_free(&dev->cq_table.alloc, cq->cqn);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
}
int __devinit mthca_init_cq_table(struct mthca_dev *dev)
diff --git a/drivers/infiniband/hw/mthca/mthca_dev.h b/drivers/infiniband/hw/mthca/mthca_dev.h
index e3d79e267dc9..5ecdd2eeeb0f 100644
--- a/drivers/infiniband/hw/mthca/mthca_dev.h
+++ b/drivers/infiniband/hw/mthca/mthca_dev.h
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -46,8 +48,8 @@
#define DRV_NAME "ib_mthca"
#define PFX DRV_NAME ": "
-#define DRV_VERSION "0.06-pre"
-#define DRV_RELDATE "November 8, 2004"
+#define DRV_VERSION "0.06"
+#define DRV_RELDATE "June 23, 2005"
enum {
MTHCA_FLAG_DDR_HIDDEN = 1 << 1,
@@ -98,6 +100,7 @@ enum {
};
struct mthca_cmd {
+ struct pci_pool *pool;
int use_events;
struct semaphore hcr_sem;
struct semaphore poll_sem;
@@ -376,9 +379,15 @@ void mthca_unregister_device(struct mthca_dev *dev);
int mthca_uar_alloc(struct mthca_dev *dev, struct mthca_uar *uar);
void mthca_uar_free(struct mthca_dev *dev, struct mthca_uar *uar);
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd);
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd);
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd);
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size);
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt);
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len);
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+ u64 iova, u64 total_size, u32 access, struct mthca_mr *mr);
int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
u32 access, struct mthca_mr *mr);
int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
@@ -405,6 +414,7 @@ int mthca_poll_cq(struct ib_cq *ibcq, int num_entries,
int mthca_tavor_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
int mthca_arbel_arm_cq(struct ib_cq *cq, enum ib_cq_notify notify);
int mthca_init_cq(struct mthca_dev *dev, int nent,
+ struct mthca_ucontext *ctx, u32 pdn,
struct mthca_cq *cq);
void mthca_free_cq(struct mthca_dev *dev,
struct mthca_cq *cq);
@@ -430,12 +440,14 @@ int mthca_alloc_qp(struct mthca_dev *dev,
struct mthca_cq *recv_cq,
enum ib_qp_type type,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
struct mthca_qp *qp);
int mthca_alloc_sqp(struct mthca_dev *dev,
struct mthca_pd *pd,
struct mthca_cq *send_cq,
struct mthca_cq *recv_cq,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
int qpn,
int port,
struct mthca_sqp *sqp);
diff --git a/drivers/infiniband/hw/mthca/mthca_doorbell.h b/drivers/infiniband/hw/mthca/mthca_doorbell.h
index 821039a49049..535fad7710fb 100644
--- a/drivers/infiniband/hw/mthca/mthca_doorbell.h
+++ b/drivers/infiniband/hw/mthca/mthca_doorbell.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
diff --git a/drivers/infiniband/hw/mthca/mthca_eq.c b/drivers/infiniband/hw/mthca/mthca_eq.c
index f46d615d396f..cbcf2b4722e4 100644
--- a/drivers/infiniband/hw/mthca/mthca_eq.c
+++ b/drivers/infiniband/hw/mthca/mthca_eq.c
@@ -469,7 +469,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
PAGE_SIZE;
u64 *dma_list = NULL;
dma_addr_t t;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_eq_context *eq_context;
int err = -ENOMEM;
int i;
@@ -494,17 +494,16 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
if (!dma_list)
goto err_out_free;
- mailbox = kmalloc(sizeof *eq_context + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
goto err_out_free;
- eq_context = MAILBOX_ALIGN(mailbox);
+ eq_context = mailbox->buf;
for (i = 0; i < npages; ++i) {
- eq->page_list[i].buf = pci_alloc_consistent(dev->pdev,
- PAGE_SIZE, &t);
+ eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
+ PAGE_SIZE, &t, GFP_KERNEL);
if (!eq->page_list[i].buf)
- goto err_out_free;
+ goto err_out_free_pages;
dma_list[i] = t;
pci_unmap_addr_set(&eq->page_list[i], mapping, t);
@@ -517,7 +516,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
eq->eqn = mthca_alloc(&dev->eq_table.alloc);
if (eq->eqn == -1)
- goto err_out_free;
+ goto err_out_free_pages;
err = mthca_mr_alloc_phys(dev, dev->driver_pd.pd_num,
dma_list, PAGE_SHIFT, npages,
@@ -548,7 +547,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
eq_context->intr = intr;
eq_context->lkey = cpu_to_be32(eq->mr.ibmr.lkey);
- err = mthca_SW2HW_EQ(dev, eq_context, eq->eqn, &status);
+ err = mthca_SW2HW_EQ(dev, mailbox, eq->eqn, &status);
if (err) {
mthca_warn(dev, "SW2HW_EQ failed (%d)\n", err);
goto err_out_free_mr;
@@ -561,7 +560,7 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
}
kfree(dma_list);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
eq->eqn_mask = swab32(1 << eq->eqn);
eq->cons_index = 0;
@@ -579,17 +578,19 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
err_out_free_eq:
mthca_free(&dev->eq_table.alloc, eq->eqn);
- err_out_free:
+ err_out_free_pages:
for (i = 0; i < npages; ++i)
if (eq->page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- eq->page_list[i].buf,
- pci_unmap_addr(&eq->page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ eq->page_list[i].buf,
+ pci_unmap_addr(&eq->page_list[i],
+ mapping));
+
+ mthca_free_mailbox(dev, mailbox);
+ err_out_free:
kfree(eq->page_list);
kfree(dma_list);
- kfree(mailbox);
err_out:
return err;
@@ -598,25 +599,22 @@ static int __devinit mthca_create_eq(struct mthca_dev *dev,
static void mthca_free_eq(struct mthca_dev *dev,
struct mthca_eq *eq)
{
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
int err;
u8 status;
int npages = (eq->nent * MTHCA_EQ_ENTRY_SIZE + PAGE_SIZE - 1) /
PAGE_SIZE;
int i;
- mailbox = kmalloc(sizeof (struct mthca_eq_context) + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
return;
- err = mthca_HW2SW_EQ(dev, MAILBOX_ALIGN(mailbox),
- eq->eqn, &status);
+ err = mthca_HW2SW_EQ(dev, mailbox, eq->eqn, &status);
if (err)
mthca_warn(dev, "HW2SW_EQ failed (%d)\n", err);
if (status)
- mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n",
- status);
+ mthca_warn(dev, "HW2SW_EQ returned status 0x%02x\n", status);
dev->eq_table.arm_mask &= ~eq->eqn_mask;
@@ -625,7 +623,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
for (i = 0; i < sizeof (struct mthca_eq_context) / 4; ++i) {
if (i % 4 == 0)
printk("[%02x] ", i * 4);
- printk(" %08x", be32_to_cpup(MAILBOX_ALIGN(mailbox) + i * 4));
+ printk(" %08x", be32_to_cpup(mailbox->buf + i * 4));
if ((i + 1) % 4 == 0)
printk("\n");
}
@@ -638,7 +636,7 @@ static void mthca_free_eq(struct mthca_dev *dev,
pci_unmap_addr(&eq->page_list[i], mapping));
kfree(eq->page_list);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
}
static void mthca_free_irqs(struct mthca_dev *dev)
@@ -709,8 +707,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
if (mthca_map_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
&dev->eq_regs.arbel.eq_arm)) {
- mthca_err(dev, "Couldn't map interrupt clear register, "
- "aborting.\n");
+ mthca_err(dev, "Couldn't map EQ arm register, aborting.\n");
mthca_unmap_reg(dev, (pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.clr_int_base, MTHCA_CLR_INT_SIZE,
dev->clr_base);
@@ -721,8 +718,7 @@ static int __devinit mthca_map_eq_regs(struct mthca_dev *dev)
dev->fw.arbel.eq_set_ci_base,
MTHCA_EQ_SET_CI_SIZE,
&dev->eq_regs.arbel.eq_set_ci_base)) {
- mthca_err(dev, "Couldn't map interrupt clear register, "
- "aborting.\n");
+ mthca_err(dev, "Couldn't map EQ CI register, aborting.\n");
mthca_unmap_reg(dev, ((pci_resource_len(dev->pdev, 0) - 1) &
dev->fw.arbel.eq_arm_base) + 4, 4,
dev->eq_regs.arbel.eq_arm);
diff --git a/drivers/infiniband/hw/mthca/mthca_main.c b/drivers/infiniband/hw/mthca/mthca_main.c
index d40590356df8..2ef916859e17 100644
--- a/drivers/infiniband/hw/mthca/mthca_main.c
+++ b/drivers/infiniband/hw/mthca/mthca_main.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -69,7 +70,7 @@ MODULE_PARM_DESC(msi, "attempt to use MSI if nonzero");
#endif /* CONFIG_PCI_MSI */
static const char mthca_version[] __devinitdata =
- "ib_mthca: Mellanox InfiniBand HCA driver v"
+ DRV_NAME ": Mellanox InfiniBand HCA driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
static struct mthca_profile default_profile = {
@@ -664,7 +665,7 @@ static int __devinit mthca_setup_hca(struct mthca_dev *dev)
goto err_pd_table_free;
}
- err = mthca_pd_alloc(dev, &dev->driver_pd);
+ err = mthca_pd_alloc(dev, 1, &dev->driver_pd);
if (err) {
mthca_err(dev, "Failed to create driver PD, "
"aborting.\n");
@@ -927,13 +928,13 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
*/
if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM) ||
pci_resource_len(pdev, 0) != 1 << 20) {
- dev_err(&pdev->dev, "Missing DCS, aborting.");
+ dev_err(&pdev->dev, "Missing DCS, aborting.\n");
err = -ENODEV;
goto err_disable_pdev;
}
if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM) ||
pci_resource_len(pdev, 2) != 1 << 23) {
- dev_err(&pdev->dev, "Missing UAR, aborting.");
+ dev_err(&pdev->dev, "Missing UAR, aborting.\n");
err = -ENODEV;
goto err_disable_pdev;
}
@@ -1004,25 +1005,18 @@ static int __devinit mthca_init_one(struct pci_dev *pdev,
!pci_enable_msi(pdev))
mdev->mthca_flags |= MTHCA_FLAG_MSI;
- sema_init(&mdev->cmd.hcr_sem, 1);
- sema_init(&mdev->cmd.poll_sem, 1);
- mdev->cmd.use_events = 0;
-
- mdev->hcr = ioremap(pci_resource_start(pdev, 0) + MTHCA_HCR_BASE, MTHCA_HCR_SIZE);
- if (!mdev->hcr) {
- mthca_err(mdev, "Couldn't map command register, "
- "aborting.\n");
- err = -ENOMEM;
+ if (mthca_cmd_init(mdev)) {
+ mthca_err(mdev, "Failed to init command interface, aborting.\n");
goto err_free_dev;
}
err = mthca_tune_pci(mdev);
if (err)
- goto err_iounmap;
+ goto err_cmd;
err = mthca_init_hca(mdev);
if (err)
- goto err_iounmap;
+ goto err_cmd;
if (mdev->fw_ver < mthca_hca_table[id->driver_data].latest_fw) {
mthca_warn(mdev, "HCA FW version %x.%x.%x is old (%x.%x.%x is current).\n",
@@ -1070,8 +1064,8 @@ err_cleanup:
err_close:
mthca_close_hca(mdev);
-err_iounmap:
- iounmap(mdev->hcr);
+err_cmd:
+ mthca_cmd_cleanup(mdev);
err_free_dev:
if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
@@ -1118,10 +1112,8 @@ static void __devexit mthca_remove_one(struct pci_dev *pdev)
iounmap(mdev->kar);
mthca_uar_free(mdev, &mdev->driver_uar);
mthca_cleanup_uar_table(mdev);
-
mthca_close_hca(mdev);
-
- iounmap(mdev->hcr);
+ mthca_cmd_cleanup(mdev);
if (mdev->mthca_flags & MTHCA_FLAG_MSI_X)
pci_disable_msix(pdev);
@@ -1163,7 +1155,7 @@ static struct pci_device_id mthca_pci_table[] = {
MODULE_DEVICE_TABLE(pci, mthca_pci_table);
static struct pci_driver mthca_driver = {
- .name = "ib_mthca",
+ .name = DRV_NAME,
.id_table = mthca_pci_table,
.probe = mthca_init_one,
.remove = __devexit_p(mthca_remove_one)
diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c
index 70a6553a588e..5be7d949dbf6 100644
--- a/drivers/infiniband/hw/mthca/mthca_mcg.c
+++ b/drivers/infiniband/hw/mthca/mthca_mcg.c
@@ -66,22 +66,23 @@ static const u8 zero_gid[16]; /* automatically initialized to 0 */
* entry in hash chain and *mgm holds end of hash chain.
*/
static int find_mgm(struct mthca_dev *dev,
- u8 *gid, struct mthca_mgm *mgm,
+ u8 *gid, struct mthca_mailbox *mgm_mailbox,
u16 *hash, int *prev, int *index)
{
- void *mailbox;
+ struct mthca_mailbox *mailbox;
+ struct mthca_mgm *mgm = mgm_mailbox->buf;
u8 *mgid;
int err;
u8 status;
- mailbox = kmalloc(16 + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
return -ENOMEM;
- mgid = MAILBOX_ALIGN(mailbox);
+ mgid = mailbox->buf;
memcpy(mgid, gid, 16);
- err = mthca_MGID_HASH(dev, mgid, hash, &status);
+ err = mthca_MGID_HASH(dev, mailbox, hash, &status);
if (err)
goto out;
if (status) {
@@ -103,7 +104,7 @@ static int find_mgm(struct mthca_dev *dev,
*prev = -1;
do {
- err = mthca_READ_MGM(dev, *index, mgm, &status);
+ err = mthca_READ_MGM(dev, *index, mgm_mailbox, &status);
if (err)
goto out;
if (status) {
@@ -129,14 +130,14 @@ static int find_mgm(struct mthca_dev *dev,
*index = -1;
out:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
- void *mailbox;
+ struct mthca_mailbox *mailbox;
struct mthca_mgm *mgm;
u16 hash;
int index, prev;
@@ -145,15 +146,15 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
int err;
u8 status;
- mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- mgm = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mgm = mailbox->buf;
if (down_interruptible(&dev->mcg_table.sem))
return -EINTR;
- err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+ err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -170,7 +171,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
goto out;
}
- err = mthca_READ_MGM(dev, index, mgm, &status);
+ err = mthca_READ_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -195,7 +196,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
goto out;
}
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -206,7 +207,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (!link)
goto out;
- err = mthca_READ_MGM(dev, prev, mgm, &status);
+ err = mthca_READ_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -217,7 +218,7 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->next_gid_index = cpu_to_be32(index << 5);
- err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+ err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -227,14 +228,14 @@ int mthca_multicast_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
out:
up(&dev->mcg_table.sem);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
struct mthca_dev *dev = to_mdev(ibqp->device);
- void *mailbox;
+ struct mthca_mailbox *mailbox;
struct mthca_mgm *mgm;
u16 hash;
int prev, index;
@@ -242,15 +243,15 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
int err;
u8 status;
- mailbox = kmalloc(sizeof *mgm + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- mgm = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mgm = mailbox->buf;
if (down_interruptible(&dev->mcg_table.sem))
return -EINTR;
- err = find_mgm(dev, gid->raw, mgm, &hash, &prev, &index);
+ err = find_mgm(dev, gid->raw, mailbox, &hash, &prev, &index);
if (err)
goto out;
@@ -285,7 +286,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->qp[loc] = mgm->qp[i - 1];
mgm->qp[i - 1] = 0;
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -304,7 +305,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
if (be32_to_cpu(mgm->next_gid_index) >> 5) {
err = mthca_READ_MGM(dev,
be32_to_cpu(mgm->next_gid_index) >> 5,
- mgm, &status);
+ mailbox, &status);
if (err)
goto out;
if (status) {
@@ -316,7 +317,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
} else
memset(mgm->gid, 0, 16);
- err = mthca_WRITE_MGM(dev, index, mgm, &status);
+ err = mthca_WRITE_MGM(dev, index, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -327,7 +328,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
} else {
/* Remove entry from AMGM */
index = be32_to_cpu(mgm->next_gid_index) >> 5;
- err = mthca_READ_MGM(dev, prev, mgm, &status);
+ err = mthca_READ_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -338,7 +339,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
mgm->next_gid_index = cpu_to_be32(index << 5);
- err = mthca_WRITE_MGM(dev, prev, mgm, &status);
+ err = mthca_WRITE_MGM(dev, prev, mailbox, &status);
if (err)
goto out;
if (status) {
@@ -350,7 +351,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
out:
up(&dev->mcg_table.sem);
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
}
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
index 637b30e35592..2a8646150355 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.c
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -47,6 +48,15 @@ enum {
MTHCA_TABLE_CHUNK_SIZE = 1 << 18
};
+struct mthca_user_db_table {
+ struct semaphore mutex;
+ struct {
+ u64 uvirt;
+ struct scatterlist mem;
+ int refcount;
+ } page[0];
+};
+
void mthca_free_icm(struct mthca_dev *dev, struct mthca_icm *icm)
{
struct mthca_icm_chunk *chunk, *tmp;
@@ -179,9 +189,14 @@ out:
void mthca_table_put(struct mthca_dev *dev, struct mthca_icm_table *table, int obj)
{
- int i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+ int i;
u8 status;
+ if (!mthca_is_memfree(dev))
+ return;
+
+ i = (obj & (table->num_obj - 1)) * table->obj_size / MTHCA_TABLE_CHUNK_SIZE;
+
down(&table->mutex);
if (--table->icm[i]->refcount == 0) {
@@ -256,6 +271,9 @@ void mthca_table_put_range(struct mthca_dev *dev, struct mthca_icm_table *table,
{
int i;
+ if (!mthca_is_memfree(dev))
+ return;
+
for (i = start; i <= end; i += MTHCA_TABLE_CHUNK_SIZE / table->obj_size)
mthca_table_put(dev, table, i);
}
@@ -336,13 +354,133 @@ void mthca_free_icm_table(struct mthca_dev *dev, struct mthca_icm_table *table)
kfree(table);
}
-static u64 mthca_uarc_virt(struct mthca_dev *dev, int page)
+static u64 mthca_uarc_virt(struct mthca_dev *dev, struct mthca_uar *uar, int page)
{
return dev->uar_table.uarc_base +
- dev->driver_uar.index * dev->uar_table.uarc_size +
+ uar->index * dev->uar_table.uarc_size +
page * 4096;
}
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index, u64 uaddr)
+{
+ int ret = 0;
+ u8 status;
+ int i;
+
+ if (!mthca_is_memfree(dev))
+ return 0;
+
+ if (index < 0 || index > dev->uar_table.uarc_size / 8)
+ return -EINVAL;
+
+ down(&db_tab->mutex);
+
+ i = index / MTHCA_DB_REC_PER_PAGE;
+
+ if ((db_tab->page[i].refcount >= MTHCA_DB_REC_PER_PAGE) ||
+ (db_tab->page[i].uvirt && db_tab->page[i].uvirt != uaddr) ||
+ (uaddr & 4095)) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (db_tab->page[i].refcount) {
+ ++db_tab->page[i].refcount;
+ goto out;
+ }
+
+ ret = get_user_pages(current, current->mm, uaddr & PAGE_MASK, 1, 1, 0,
+ &db_tab->page[i].mem.page, NULL);
+ if (ret < 0)
+ goto out;
+
+ db_tab->page[i].mem.length = 4096;
+ db_tab->page[i].mem.offset = uaddr & ~PAGE_MASK;
+
+ ret = pci_map_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ if (ret < 0) {
+ put_page(db_tab->page[i].mem.page);
+ goto out;
+ }
+
+ ret = mthca_MAP_ICM_page(dev, sg_dma_address(&db_tab->page[i].mem),
+ mthca_uarc_virt(dev, uar, i), &status);
+ if (!ret && status)
+ ret = -EINVAL;
+ if (ret) {
+ pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ put_page(db_tab->page[i].mem.page);
+ goto out;
+ }
+
+ db_tab->page[i].uvirt = uaddr;
+ db_tab->page[i].refcount = 1;
+
+out:
+ up(&db_tab->mutex);
+ return ret;
+}
+
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index)
+{
+ if (!mthca_is_memfree(dev))
+ return;
+
+ /*
+ * To make our bookkeeping simpler, we don't unmap DB
+ * pages until we clean up the whole db table.
+ */
+
+ down(&db_tab->mutex);
+
+ --db_tab->page[index / MTHCA_DB_REC_PER_PAGE].refcount;
+
+ up(&db_tab->mutex);
+}
+
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev)
+{
+ struct mthca_user_db_table *db_tab;
+ int npages;
+ int i;
+
+ if (!mthca_is_memfree(dev))
+ return NULL;
+
+ npages = dev->uar_table.uarc_size / 4096;
+ db_tab = kmalloc(sizeof *db_tab + npages * sizeof *db_tab->page, GFP_KERNEL);
+ if (!db_tab)
+ return ERR_PTR(-ENOMEM);
+
+ init_MUTEX(&db_tab->mutex);
+ for (i = 0; i < npages; ++i) {
+ db_tab->page[i].refcount = 0;
+ db_tab->page[i].uvirt = 0;
+ }
+
+ return db_tab;
+}
+
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab)
+{
+ int i;
+ u8 status;
+
+ if (!mthca_is_memfree(dev))
+ return;
+
+ for (i = 0; i < dev->uar_table.uarc_size / 4096; ++i) {
+ if (db_tab->page[i].uvirt) {
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, uar, i), 1, &status);
+ pci_unmap_sg(dev->pdev, &db_tab->page[i].mem, 1, PCI_DMA_TODEVICE);
+ put_page(db_tab->page[i].mem.page);
+ }
+ }
+}
+
int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
{
int group;
@@ -399,7 +537,8 @@ int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db)
}
memset(page->db_rec, 0, 4096);
- ret = mthca_MAP_ICM_page(dev, page->mapping, mthca_uarc_virt(dev, i), &status);
+ ret = mthca_MAP_ICM_page(dev, page->mapping,
+ mthca_uarc_virt(dev, &dev->driver_uar, i), &status);
if (!ret && status)
ret = -EINVAL;
if (ret) {
@@ -453,7 +592,7 @@ void mthca_free_db(struct mthca_dev *dev, int type, int db_index)
if (bitmap_empty(page->used, MTHCA_DB_REC_PER_PAGE) &&
i >= dev->db_tab->max_group1 - 1) {
- mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
dma_free_coherent(&dev->pdev->dev, 4096,
page->db_rec, page->mapping);
@@ -522,7 +661,7 @@ void mthca_cleanup_db_tab(struct mthca_dev *dev)
if (!bitmap_empty(dev->db_tab->page[i].used, MTHCA_DB_REC_PER_PAGE))
mthca_warn(dev, "Kernel UARC page %d not empty\n", i);
- mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, i), 1, &status);
+ mthca_UNMAP_ICM(dev, mthca_uarc_virt(dev, &dev->driver_uar, i), 1, &status);
dma_free_coherent(&dev->pdev->dev, 4096,
dev->db_tab->page[i].db_rec,
diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.h b/drivers/infiniband/hw/mthca/mthca_memfree.h
index fe7be2a6bc4a..4761d844cb5f 100644
--- a/drivers/infiniband/hw/mthca/mthca_memfree.h
+++ b/drivers/infiniband/hw/mthca/mthca_memfree.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -148,7 +149,7 @@ struct mthca_db_table {
struct semaphore mutex;
};
-enum {
+enum mthca_db_type {
MTHCA_DB_TYPE_INVALID = 0x0,
MTHCA_DB_TYPE_CQ_SET_CI = 0x1,
MTHCA_DB_TYPE_CQ_ARM = 0x2,
@@ -158,6 +159,17 @@ enum {
MTHCA_DB_TYPE_GROUP_SEP = 0x7
};
+struct mthca_user_db_table;
+struct mthca_uar;
+
+int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index, u64 uaddr);
+void mthca_unmap_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab, int index);
+struct mthca_user_db_table *mthca_init_user_db_tab(struct mthca_dev *dev);
+void mthca_cleanup_user_db_tab(struct mthca_dev *dev, struct mthca_uar *uar,
+ struct mthca_user_db_table *db_tab);
+
int mthca_init_db_tab(struct mthca_dev *dev);
void mthca_cleanup_db_tab(struct mthca_dev *dev);
int mthca_alloc_db(struct mthca_dev *dev, int type, u32 qn, u32 **db);
diff --git a/drivers/infiniband/hw/mthca/mthca_mr.c b/drivers/infiniband/hw/mthca/mthca_mr.c
index 8960fc2306be..cbe50feaf680 100644
--- a/drivers/infiniband/hw/mthca/mthca_mr.c
+++ b/drivers/infiniband/hw/mthca/mthca_mr.c
@@ -40,6 +40,12 @@
#include "mthca_cmd.h"
#include "mthca_memfree.h"
+struct mthca_mtt {
+ struct mthca_buddy *buddy;
+ int order;
+ u32 first_seg;
+};
+
/*
* Must be packed because mtt_seg is 64 bits but only aligned to 32 bits.
*/
@@ -173,8 +179,8 @@ static void __devexit mthca_buddy_cleanup(struct mthca_buddy *buddy)
kfree(buddy->bits);
}
-static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
- struct mthca_buddy *buddy)
+static u32 mthca_alloc_mtt_range(struct mthca_dev *dev, int order,
+ struct mthca_buddy *buddy)
{
u32 seg = mthca_buddy_alloc(buddy, order);
@@ -191,14 +197,102 @@ static u32 mthca_alloc_mtt(struct mthca_dev *dev, int order,
return seg;
}
-static void mthca_free_mtt(struct mthca_dev *dev, u32 seg, int order,
- struct mthca_buddy* buddy)
+static struct mthca_mtt *__mthca_alloc_mtt(struct mthca_dev *dev, int size,
+ struct mthca_buddy *buddy)
{
- mthca_buddy_free(buddy, seg, order);
+ struct mthca_mtt *mtt;
+ int i;
- if (mthca_is_memfree(dev))
- mthca_table_put_range(dev, dev->mr_table.mtt_table, seg,
- seg + (1 << order) - 1);
+ if (size <= 0)
+ return ERR_PTR(-EINVAL);
+
+ mtt = kmalloc(sizeof *mtt, GFP_KERNEL);
+ if (!mtt)
+ return ERR_PTR(-ENOMEM);
+
+ mtt->buddy = buddy;
+ mtt->order = 0;
+ for (i = MTHCA_MTT_SEG_SIZE / 8; i < size; i <<= 1)
+ ++mtt->order;
+
+ mtt->first_seg = mthca_alloc_mtt_range(dev, mtt->order, buddy);
+ if (mtt->first_seg == -1) {
+ kfree(mtt);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ return mtt;
+}
+
+struct mthca_mtt *mthca_alloc_mtt(struct mthca_dev *dev, int size)
+{
+ return __mthca_alloc_mtt(dev, size, &dev->mr_table.mtt_buddy);
+}
+
+void mthca_free_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt)
+{
+ if (!mtt)
+ return;
+
+ mthca_buddy_free(mtt->buddy, mtt->first_seg, mtt->order);
+
+ mthca_table_put_range(dev, dev->mr_table.mtt_table,
+ mtt->first_seg,
+ mtt->first_seg + (1 << mtt->order) - 1);
+
+ kfree(mtt);
+}
+
+int mthca_write_mtt(struct mthca_dev *dev, struct mthca_mtt *mtt,
+ int start_index, u64 *buffer_list, int list_len)
+{
+ struct mthca_mailbox *mailbox;
+ u64 *mtt_entry;
+ int err = 0;
+ u8 status;
+ int i;
+
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ mtt_entry = mailbox->buf;
+
+ while (list_len > 0) {
+ mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
+ mtt->first_seg * MTHCA_MTT_SEG_SIZE +
+ start_index * 8);
+ mtt_entry[1] = 0;
+ for (i = 0; i < list_len && i < MTHCA_MAILBOX_SIZE / 8 - 2; ++i)
+ mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
+ MTHCA_MTT_FLAG_PRESENT);
+
+ /*
+ * If we have an odd number of entries to write, add
+ * one more dummy entry for firmware efficiency.
+ */
+ if (i & 1)
+ mtt_entry[i + 2] = 0;
+
+ err = mthca_WRITE_MTT(dev, mailbox, (i + 1) & ~1, &status);
+ if (err) {
+ mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
+ goto out;
+ }
+ if (status) {
+ mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
+ status);
+ err = -EINVAL;
+ goto out;
+ }
+
+ list_len -= i;
+ start_index += i;
+ buffer_list += i;
+ }
+
+out:
+ mthca_free_mailbox(dev, mailbox);
+ return err;
}
static inline u32 tavor_hw_index_to_key(u32 ind)
@@ -237,91 +331,18 @@ static inline u32 key_to_hw_index(struct mthca_dev *dev, u32 key)
return tavor_key_to_hw_index(key);
}
-int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
- u32 access, struct mthca_mr *mr)
+int mthca_mr_alloc(struct mthca_dev *dev, u32 pd, int buffer_size_shift,
+ u64 iova, u64 total_size, u32 access, struct mthca_mr *mr)
{
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_mpt_entry *mpt_entry;
u32 key;
+ int i;
int err;
u8 status;
might_sleep();
- mr->order = -1;
- key = mthca_alloc(&dev->mr_table.mpt_alloc);
- if (key == -1)
- return -ENOMEM;
- mr->ibmr.rkey = mr->ibmr.lkey = hw_index_to_key(dev, key);
-
- if (mthca_is_memfree(dev)) {
- err = mthca_table_get(dev, dev->mr_table.mpt_table, key);
- if (err)
- goto err_out_mpt_free;
- }
-
- mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox) {
- err = -ENOMEM;
- goto err_out_table;
- }
- mpt_entry = MAILBOX_ALIGN(mailbox);
-
- mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
- MTHCA_MPT_FLAG_MIO |
- MTHCA_MPT_FLAG_PHYSICAL |
- MTHCA_MPT_FLAG_REGION |
- access);
- mpt_entry->page_size = 0;
- mpt_entry->key = cpu_to_be32(key);
- mpt_entry->pd = cpu_to_be32(pd);
- mpt_entry->start = 0;
- mpt_entry->length = ~0ULL;
-
- memset(&mpt_entry->lkey, 0,
- sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
-
- err = mthca_SW2HW_MPT(dev, mpt_entry,
- key & (dev->limits.num_mpts - 1),
- &status);
- if (err) {
- mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
- goto err_out_table;
- } else if (status) {
- mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
- status);
- err = -EINVAL;
- goto err_out_table;
- }
-
- kfree(mailbox);
- return err;
-
-err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
-
-err_out_mpt_free:
- mthca_free(&dev->mr_table.mpt_alloc, key);
- kfree(mailbox);
- return err;
-}
-
-int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
- u64 *buffer_list, int buffer_size_shift,
- int list_len, u64 iova, u64 total_size,
- u32 access, struct mthca_mr *mr)
-{
- void *mailbox;
- u64 *mtt_entry;
- struct mthca_mpt_entry *mpt_entry;
- u32 key;
- int err = -ENOMEM;
- u8 status;
- int i;
-
- might_sleep();
WARN_ON(buffer_size_shift >= 32);
key = mthca_alloc(&dev->mr_table.mpt_alloc);
@@ -335,75 +356,33 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
goto err_out_mpt_free;
}
- for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
- i < list_len;
- i <<= 1, ++mr->order)
- ; /* nothing */
-
- mr->first_seg = mthca_alloc_mtt(dev, mr->order,
- &dev->mr_table.mtt_buddy);
- if (mr->first_seg == -1)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox)) {
+ err = PTR_ERR(mailbox);
goto err_out_table;
-
- /*
- * If list_len is odd, we add one more dummy entry for
- * firmware efficiency.
- */
- mailbox = kmalloc(max(sizeof *mpt_entry,
- (size_t) 8 * (list_len + (list_len & 1) + 2)) +
- MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
- goto err_out_free_mtt;
-
- mtt_entry = MAILBOX_ALIGN(mailbox);
-
- mtt_entry[0] = cpu_to_be64(dev->mr_table.mtt_base +
- mr->first_seg * MTHCA_MTT_SEG_SIZE);
- mtt_entry[1] = 0;
- for (i = 0; i < list_len; ++i)
- mtt_entry[i + 2] = cpu_to_be64(buffer_list[i] |
- MTHCA_MTT_FLAG_PRESENT);
- if (list_len & 1) {
- mtt_entry[i + 2] = 0;
- ++list_len;
- }
-
- if (0) {
- mthca_dbg(dev, "Dumping MPT entry\n");
- for (i = 0; i < list_len + 2; ++i)
- printk(KERN_ERR "[%2d] %016llx\n",
- i, (unsigned long long) be64_to_cpu(mtt_entry[i]));
- }
-
- err = mthca_WRITE_MTT(dev, mtt_entry, list_len, &status);
- if (err) {
- mthca_warn(dev, "WRITE_MTT failed (%d)\n", err);
- goto err_out_mailbox_free;
- }
- if (status) {
- mthca_warn(dev, "WRITE_MTT returned status 0x%02x\n",
- status);
- err = -EINVAL;
- goto err_out_mailbox_free;
}
-
- mpt_entry = MAILBOX_ALIGN(mailbox);
+ mpt_entry = mailbox->buf;
mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
MTHCA_MPT_FLAG_MIO |
MTHCA_MPT_FLAG_REGION |
access);
+ if (!mr->mtt)
+ mpt_entry->flags |= cpu_to_be32(MTHCA_MPT_FLAG_PHYSICAL);
mpt_entry->page_size = cpu_to_be32(buffer_size_shift - 12);
mpt_entry->key = cpu_to_be32(key);
mpt_entry->pd = cpu_to_be32(pd);
mpt_entry->start = cpu_to_be64(iova);
mpt_entry->length = cpu_to_be64(total_size);
+
memset(&mpt_entry->lkey, 0,
sizeof *mpt_entry - offsetof(struct mthca_mpt_entry, lkey));
- mpt_entry->mtt_seg = cpu_to_be64(dev->mr_table.mtt_base +
- mr->first_seg * MTHCA_MTT_SEG_SIZE);
+
+ if (mr->mtt)
+ mpt_entry->mtt_seg =
+ cpu_to_be64(dev->mr_table.mtt_base +
+ mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE);
if (0) {
mthca_dbg(dev, "Dumping MPT entry %08x:\n", mr->ibmr.lkey);
@@ -416,45 +395,70 @@ int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
}
}
- err = mthca_SW2HW_MPT(dev, mpt_entry,
+ err = mthca_SW2HW_MPT(dev, mailbox,
key & (dev->limits.num_mpts - 1),
&status);
- if (err)
+ if (err) {
mthca_warn(dev, "SW2HW_MPT failed (%d)\n", err);
- else if (status) {
+ goto err_out_mailbox;
+ } else if (status) {
mthca_warn(dev, "SW2HW_MPT returned status 0x%02x\n",
status);
err = -EINVAL;
+ goto err_out_mailbox;
}
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return err;
-err_out_mailbox_free:
- kfree(mailbox);
-
-err_out_free_mtt:
- mthca_free_mtt(dev, mr->first_seg, mr->order, &dev->mr_table.mtt_buddy);
+err_out_mailbox:
+ mthca_free_mailbox(dev, mailbox);
err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
+ mthca_table_put(dev, dev->mr_table.mpt_table, key);
err_out_mpt_free:
mthca_free(&dev->mr_table.mpt_alloc, key);
return err;
}
-/* Free mr or fmr */
-static void mthca_free_region(struct mthca_dev *dev, u32 lkey, int order,
- u32 first_seg, struct mthca_buddy *buddy)
+int mthca_mr_alloc_notrans(struct mthca_dev *dev, u32 pd,
+ u32 access, struct mthca_mr *mr)
{
- if (order >= 0)
- mthca_free_mtt(dev, first_seg, order, buddy);
+ mr->mtt = NULL;
+ return mthca_mr_alloc(dev, pd, 12, 0, ~0ULL, access, mr);
+}
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table,
- arbel_key_to_hw_index(lkey));
+int mthca_mr_alloc_phys(struct mthca_dev *dev, u32 pd,
+ u64 *buffer_list, int buffer_size_shift,
+ int list_len, u64 iova, u64 total_size,
+ u32 access, struct mthca_mr *mr)
+{
+ int err;
+
+ mr->mtt = mthca_alloc_mtt(dev, list_len);
+ if (IS_ERR(mr->mtt))
+ return PTR_ERR(mr->mtt);
+
+ err = mthca_write_mtt(dev, mr->mtt, 0, buffer_list, list_len);
+ if (err) {
+ mthca_free_mtt(dev, mr->mtt);
+ return err;
+ }
+
+ err = mthca_mr_alloc(dev, pd, buffer_size_shift, iova,
+ total_size, access, mr);
+ if (err)
+ mthca_free_mtt(dev, mr->mtt);
+
+ return err;
+}
+
+/* Free mr or fmr */
+static void mthca_free_region(struct mthca_dev *dev, u32 lkey)
+{
+ mthca_table_put(dev, dev->mr_table.mpt_table,
+ arbel_key_to_hw_index(lkey));
mthca_free(&dev->mr_table.mpt_alloc, key_to_hw_index(dev, lkey));
}
@@ -476,15 +480,15 @@ void mthca_free_mr(struct mthca_dev *dev, struct mthca_mr *mr)
mthca_warn(dev, "HW2SW_MPT returned status 0x%02x\n",
status);
- mthca_free_region(dev, mr->ibmr.lkey, mr->order, mr->first_seg,
- &dev->mr_table.mtt_buddy);
+ mthca_free_region(dev, mr->ibmr.lkey);
+ mthca_free_mtt(dev, mr->mtt);
}
int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
u32 access, struct mthca_fmr *mr)
{
struct mthca_mpt_entry *mpt_entry;
- void *mailbox;
+ struct mthca_mailbox *mailbox;
u64 mtt_seg;
u32 key, idx;
u8 status;
@@ -522,31 +526,24 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
mr->mem.tavor.mpt = dev->mr_table.tavor_fmr.mpt_base +
sizeof *(mr->mem.tavor.mpt) * idx;
- for (i = MTHCA_MTT_SEG_SIZE / 8, mr->order = 0;
- i < list_len;
- i <<= 1, ++mr->order)
- ; /* nothing */
-
- mr->first_seg = mthca_alloc_mtt(dev, mr->order,
- dev->mr_table.fmr_mtt_buddy);
- if (mr->first_seg == -1)
+ mr->mtt = __mthca_alloc_mtt(dev, list_len, dev->mr_table.fmr_mtt_buddy);
+ if (IS_ERR(mr->mtt))
goto err_out_table;
- mtt_seg = mr->first_seg * MTHCA_MTT_SEG_SIZE;
+ mtt_seg = mr->mtt->first_seg * MTHCA_MTT_SEG_SIZE;
if (mthca_is_memfree(dev)) {
mr->mem.arbel.mtts = mthca_table_find(dev->mr_table.mtt_table,
- mr->first_seg);
+ mr->mtt->first_seg);
BUG_ON(!mr->mem.arbel.mtts);
} else
mr->mem.tavor.mtts = dev->mr_table.tavor_fmr.mtt_base + mtt_seg;
- mailbox = kmalloc(sizeof *mpt_entry + MTHCA_CMD_MAILBOX_EXTRA,
- GFP_KERNEL);
- if (!mailbox)
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
goto err_out_free_mtt;
- mpt_entry = MAILBOX_ALIGN(mailbox);
+ mpt_entry = mailbox->buf;
mpt_entry->flags = cpu_to_be32(MTHCA_MPT_FLAG_SW_OWNS |
MTHCA_MPT_FLAG_MIO |
@@ -571,7 +568,7 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
}
}
- err = mthca_SW2HW_MPT(dev, mpt_entry,
+ err = mthca_SW2HW_MPT(dev, mailbox,
key & (dev->limits.num_mpts - 1),
&status);
if (err) {
@@ -585,19 +582,17 @@ int mthca_fmr_alloc(struct mthca_dev *dev, u32 pd,
goto err_out_mailbox_free;
}
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
return 0;
err_out_mailbox_free:
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
err_out_free_mtt:
- mthca_free_mtt(dev, mr->first_seg, mr->order,
- dev->mr_table.fmr_mtt_buddy);
+ mthca_free_mtt(dev, mr->mtt);
err_out_table:
- if (mthca_is_memfree(dev))
- mthca_table_put(dev, dev->mr_table.mpt_table, key);
+ mthca_table_put(dev, dev->mr_table.mpt_table, key);
err_out_mpt_free:
mthca_free(&dev->mr_table.mpt_alloc, mr->ibmr.lkey);
@@ -609,8 +604,9 @@ int mthca_free_fmr(struct mthca_dev *dev, struct mthca_fmr *fmr)
if (fmr->maps)
return -EBUSY;
- mthca_free_region(dev, fmr->ibmr.lkey, fmr->order, fmr->first_seg,
- dev->mr_table.fmr_mtt_buddy);
+ mthca_free_region(dev, fmr->ibmr.lkey);
+ mthca_free_mtt(dev, fmr->mtt);
+
return 0;
}
@@ -826,7 +822,8 @@ int __devinit mthca_init_mr_table(struct mthca_dev *dev)
if (dev->limits.reserved_mtts) {
i = fls(dev->limits.reserved_mtts - 1);
- if (mthca_alloc_mtt(dev, i, dev->mr_table.fmr_mtt_buddy) == -1) {
+ if (mthca_alloc_mtt_range(dev, i,
+ dev->mr_table.fmr_mtt_buddy) == -1) {
mthca_warn(dev, "MTT table of order %d is too small.\n",
dev->mr_table.fmr_mtt_buddy->max_order);
err = -ENOMEM;
diff --git a/drivers/infiniband/hw/mthca/mthca_pd.c b/drivers/infiniband/hw/mthca/mthca_pd.c
index ea66847e4ea3..c2c899844e98 100644
--- a/drivers/infiniband/hw/mthca/mthca_pd.c
+++ b/drivers/infiniband/hw/mthca/mthca_pd.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -37,23 +38,27 @@
#include "mthca_dev.h"
-int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd)
+int mthca_pd_alloc(struct mthca_dev *dev, int privileged, struct mthca_pd *pd)
{
- int err;
+ int err = 0;
might_sleep();
+ pd->privileged = privileged;
+
atomic_set(&pd->sqp_count, 0);
pd->pd_num = mthca_alloc(&dev->pd_table.alloc);
if (pd->pd_num == -1)
return -ENOMEM;
- err = mthca_mr_alloc_notrans(dev, pd->pd_num,
- MTHCA_MPT_FLAG_LOCAL_READ |
- MTHCA_MPT_FLAG_LOCAL_WRITE,
- &pd->ntmr);
- if (err)
- mthca_free(&dev->pd_table.alloc, pd->pd_num);
+ if (privileged) {
+ err = mthca_mr_alloc_notrans(dev, pd->pd_num,
+ MTHCA_MPT_FLAG_LOCAL_READ |
+ MTHCA_MPT_FLAG_LOCAL_WRITE,
+ &pd->ntmr);
+ if (err)
+ mthca_free(&dev->pd_table.alloc, pd->pd_num);
+ }
return err;
}
@@ -61,7 +66,8 @@ int mthca_pd_alloc(struct mthca_dev *dev, struct mthca_pd *pd)
void mthca_pd_free(struct mthca_dev *dev, struct mthca_pd *pd)
{
might_sleep();
- mthca_free_mr(dev, &pd->ntmr);
+ if (pd->privileged)
+ mthca_free_mr(dev, &pd->ntmr);
mthca_free(&dev->pd_table.alloc, pd->pd_num);
}
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.c b/drivers/infiniband/hw/mthca/mthca_provider.c
index 159f4e6c312d..7a58ce90e179 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.c
+++ b/drivers/infiniband/hw/mthca/mthca_provider.c
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2004, 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -33,9 +35,12 @@
*/
#include <ib_smi.h>
+#include <linux/mm.h>
#include "mthca_dev.h"
#include "mthca_cmd.h"
+#include "mthca_user.h"
+#include "mthca_memfree.h"
static int mthca_query_device(struct ib_device *ibdev,
struct ib_device_attr *props)
@@ -52,7 +57,7 @@ static int mthca_query_device(struct ib_device *ibdev,
if (!in_mad || !out_mad)
goto out;
- memset(props, 0, sizeof props);
+ memset(props, 0, sizeof *props);
props->fw_ver = mdev->fw_ver;
@@ -283,7 +288,78 @@ static int mthca_query_gid(struct ib_device *ibdev, u8 port,
return err;
}
-static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev)
+static struct ib_ucontext *mthca_alloc_ucontext(struct ib_device *ibdev,
+ struct ib_udata *udata)
+{
+ struct mthca_alloc_ucontext_resp uresp;
+ struct mthca_ucontext *context;
+ int err;
+
+ memset(&uresp, 0, sizeof uresp);
+
+ uresp.qp_tab_size = to_mdev(ibdev)->limits.num_qps;
+ if (mthca_is_memfree(to_mdev(ibdev)))
+ uresp.uarc_size = to_mdev(ibdev)->uar_table.uarc_size;
+ else
+ uresp.uarc_size = 0;
+
+ context = kmalloc(sizeof *context, GFP_KERNEL);
+ if (!context)
+ return ERR_PTR(-ENOMEM);
+
+ err = mthca_uar_alloc(to_mdev(ibdev), &context->uar);
+ if (err) {
+ kfree(context);
+ return ERR_PTR(err);
+ }
+
+ context->db_tab = mthca_init_user_db_tab(to_mdev(ibdev));
+ if (IS_ERR(context->db_tab)) {
+ err = PTR_ERR(context->db_tab);
+ mthca_uar_free(to_mdev(ibdev), &context->uar);
+ kfree(context);
+ return ERR_PTR(err);
+ }
+
+ if (ib_copy_to_udata(udata, &uresp, sizeof uresp)) {
+ mthca_cleanup_user_db_tab(to_mdev(ibdev), &context->uar, context->db_tab);
+ mthca_uar_free(to_mdev(ibdev), &context->uar);
+ kfree(context);
+ return ERR_PTR(-EFAULT);
+ }
+
+ return &context->ibucontext;
+}
+
+static int mthca_dealloc_ucontext(struct ib_ucontext *context)
+{
+ mthca_cleanup_user_db_tab(to_mdev(context->device), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab);
+ mthca_uar_free(to_mdev(context->device), &to_mucontext(context)->uar);
+ kfree(to_mucontext(context));
+
+ return 0;
+}
+
+static int mthca_mmap_uar(struct ib_ucontext *context,
+ struct vm_area_struct *vma)
+{
+ if (vma->vm_end - vma->vm_start != PAGE_SIZE)
+ return -EINVAL;
+
+ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+
+ if (remap_pfn_range(vma, vma->vm_start,
+ to_mucontext(context)->uar.pfn,
+ PAGE_SIZE, vma->vm_page_prot))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
{
struct mthca_pd *pd;
int err;
@@ -292,12 +368,20 @@ static struct ib_pd *mthca_alloc_pd(struct ib_device *ibdev)
if (!pd)
return ERR_PTR(-ENOMEM);
- err = mthca_pd_alloc(to_mdev(ibdev), pd);
+ err = mthca_pd_alloc(to_mdev(ibdev), !context, pd);
if (err) {
kfree(pd);
return ERR_PTR(err);
}
+ if (context) {
+ if (ib_copy_to_udata(udata, &pd->pd_num, sizeof (__u32))) {
+ mthca_pd_free(to_mdev(ibdev), pd);
+ kfree(pd);
+ return ERR_PTR(-EFAULT);
+ }
+ }
+
return &pd->ibpd;
}
@@ -337,8 +421,10 @@ static int mthca_ah_destroy(struct ib_ah *ah)
}
static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
- struct ib_qp_init_attr *init_attr)
+ struct ib_qp_init_attr *init_attr,
+ struct ib_udata *udata)
{
+ struct mthca_create_qp ucmd;
struct mthca_qp *qp;
int err;
@@ -347,41 +433,82 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
case IB_QPT_UC:
case IB_QPT_UD:
{
+ struct mthca_ucontext *context;
+
qp = kmalloc(sizeof *qp, GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
- qp->sq.max = init_attr->cap.max_send_wr;
- qp->rq.max = init_attr->cap.max_recv_wr;
- qp->sq.max_gs = init_attr->cap.max_send_sge;
- qp->rq.max_gs = init_attr->cap.max_recv_sge;
+ if (pd->uobject) {
+ context = to_mucontext(pd->uobject->context);
+
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
+ err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index, ucmd.sq_db_page);
+ if (err) {
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ err = mthca_map_user_db(to_mdev(pd->device), &context->uar,
+ context->db_tab,
+ ucmd.rq_db_index, ucmd.rq_db_page);
+ if (err) {
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index);
+ kfree(qp);
+ return ERR_PTR(err);
+ }
+
+ qp->mr.ibmr.lkey = ucmd.lkey;
+ qp->sq.db_index = ucmd.sq_db_index;
+ qp->rq.db_index = ucmd.rq_db_index;
+ }
err = mthca_alloc_qp(to_mdev(pd->device), to_mpd(pd),
to_mcq(init_attr->send_cq),
to_mcq(init_attr->recv_cq),
init_attr->qp_type, init_attr->sq_sig_type,
- qp);
+ &init_attr->cap, qp);
+
+ if (err && pd->uobject) {
+ context = to_mucontext(pd->uobject->context);
+
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.sq_db_index);
+ mthca_unmap_user_db(to_mdev(pd->device),
+ &context->uar,
+ context->db_tab,
+ ucmd.rq_db_index);
+ }
+
qp->ibqp.qp_num = qp->qpn;
break;
}
case IB_QPT_SMI:
case IB_QPT_GSI:
{
+ /* Don't allow userspace to create special QPs */
+ if (pd->uobject)
+ return ERR_PTR(-EINVAL);
+
qp = kmalloc(sizeof (struct mthca_sqp), GFP_KERNEL);
if (!qp)
return ERR_PTR(-ENOMEM);
- qp->sq.max = init_attr->cap.max_send_wr;
- qp->rq.max = init_attr->cap.max_recv_wr;
- qp->sq.max_gs = init_attr->cap.max_send_sge;
- qp->rq.max_gs = init_attr->cap.max_recv_sge;
-
qp->ibqp.qp_num = init_attr->qp_type == IB_QPT_SMI ? 0 : 1;
err = mthca_alloc_sqp(to_mdev(pd->device), to_mpd(pd),
to_mcq(init_attr->send_cq),
to_mcq(init_attr->recv_cq),
- init_attr->sq_sig_type,
+ init_attr->sq_sig_type, &init_attr->cap,
qp->ibqp.qp_num, init_attr->port_num,
to_msqp(qp));
break;
@@ -396,42 +523,115 @@ static struct ib_qp *mthca_create_qp(struct ib_pd *pd,
return ERR_PTR(err);
}
- init_attr->cap.max_inline_data = 0;
+ init_attr->cap.max_inline_data = 0;
+ init_attr->cap.max_send_wr = qp->sq.max;
+ init_attr->cap.max_recv_wr = qp->rq.max;
+ init_attr->cap.max_send_sge = qp->sq.max_gs;
+ init_attr->cap.max_recv_sge = qp->rq.max_gs;
return &qp->ibqp;
}
static int mthca_destroy_qp(struct ib_qp *qp)
{
+ if (qp->uobject) {
+ mthca_unmap_user_db(to_mdev(qp->device),
+ &to_mucontext(qp->uobject->context)->uar,
+ to_mucontext(qp->uobject->context)->db_tab,
+ to_mqp(qp)->sq.db_index);
+ mthca_unmap_user_db(to_mdev(qp->device),
+ &to_mucontext(qp->uobject->context)->uar,
+ to_mucontext(qp->uobject->context)->db_tab,
+ to_mqp(qp)->rq.db_index);
+ }
mthca_free_qp(to_mdev(qp->device), to_mqp(qp));
kfree(qp);
return 0;
}
-static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries)
+static struct ib_cq *mthca_create_cq(struct ib_device *ibdev, int entries,
+ struct ib_ucontext *context,
+ struct ib_udata *udata)
{
+ struct mthca_create_cq ucmd;
struct mthca_cq *cq;
int nent;
int err;
+ if (context) {
+ if (ib_copy_from_udata(&ucmd, udata, sizeof ucmd))
+ return ERR_PTR(-EFAULT);
+
+ err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab,
+ ucmd.set_db_index, ucmd.set_db_page);
+ if (err)
+ return ERR_PTR(err);
+
+ err = mthca_map_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab,
+ ucmd.arm_db_index, ucmd.arm_db_page);
+ if (err)
+ goto err_unmap_set;
+ }
+
cq = kmalloc(sizeof *cq, GFP_KERNEL);
- if (!cq)
- return ERR_PTR(-ENOMEM);
+ if (!cq) {
+ err = -ENOMEM;
+ goto err_unmap_arm;
+ }
+
+ if (context) {
+ cq->mr.ibmr.lkey = ucmd.lkey;
+ cq->set_ci_db_index = ucmd.set_db_index;
+ cq->arm_db_index = ucmd.arm_db_index;
+ }
for (nent = 1; nent <= entries; nent <<= 1)
; /* nothing */
- err = mthca_init_cq(to_mdev(ibdev), nent, cq);
- if (err) {
- kfree(cq);
- cq = ERR_PTR(err);
+ err = mthca_init_cq(to_mdev(ibdev), nent,
+ context ? to_mucontext(context) : NULL,
+ context ? ucmd.pdn : to_mdev(ibdev)->driver_pd.pd_num,
+ cq);
+ if (err)
+ goto err_free;
+
+ if (context && ib_copy_to_udata(udata, &cq->cqn, sizeof (__u32))) {
+ mthca_free_cq(to_mdev(ibdev), cq);
+ goto err_free;
}
return &cq->ibcq;
+
+err_free:
+ kfree(cq);
+
+err_unmap_arm:
+ if (context)
+ mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab, ucmd.arm_db_index);
+
+err_unmap_set:
+ if (context)
+ mthca_unmap_user_db(to_mdev(ibdev), &to_mucontext(context)->uar,
+ to_mucontext(context)->db_tab, ucmd.set_db_index);
+
+ return ERR_PTR(err);
}
static int mthca_destroy_cq(struct ib_cq *cq)
{
+ if (cq->uobject) {
+ mthca_unmap_user_db(to_mdev(cq->device),
+ &to_mucontext(cq->uobject->context)->uar,
+ to_mucontext(cq->uobject->context)->db_tab,
+ to_mcq(cq)->arm_db_index);
+ mthca_unmap_user_db(to_mdev(cq->device),
+ &to_mucontext(cq->uobject->context)->uar,
+ to_mucontext(cq->uobject->context)->db_tab,
+ to_mcq(cq)->set_ci_db_index);
+ }
mthca_free_cq(to_mdev(cq->device), to_mcq(cq));
kfree(cq);
@@ -558,6 +758,7 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
convert_access(acc), mr);
if (err) {
+ kfree(page_list);
kfree(mr);
return ERR_PTR(err);
}
@@ -566,6 +767,87 @@ static struct ib_mr *mthca_reg_phys_mr(struct ib_pd *pd,
return &mr->ibmr;
}
+static struct ib_mr *mthca_reg_user_mr(struct ib_pd *pd, struct ib_umem *region,
+ int acc, struct ib_udata *udata)
+{
+ struct mthca_dev *dev = to_mdev(pd->device);
+ struct ib_umem_chunk *chunk;
+ struct mthca_mr *mr;
+ u64 *pages;
+ int shift, n, len;
+ int i, j, k;
+ int err = 0;
+
+ shift = ffs(region->page_size) - 1;
+
+ mr = kmalloc(sizeof *mr, GFP_KERNEL);
+ if (!mr)
+ return ERR_PTR(-ENOMEM);
+
+ n = 0;
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ n += chunk->nents;
+
+ mr->mtt = mthca_alloc_mtt(dev, n);
+ if (IS_ERR(mr->mtt)) {
+ err = PTR_ERR(mr->mtt);
+ goto err;
+ }
+
+ pages = (u64 *) __get_free_page(GFP_KERNEL);
+ if (!pages) {
+ err = -ENOMEM;
+ goto err_mtt;
+ }
+
+ i = n = 0;
+
+ list_for_each_entry(chunk, &region->chunk_list, list)
+ for (j = 0; j < chunk->nmap; ++j) {
+ len = sg_dma_len(&chunk->page_list[j]) >> shift;
+ for (k = 0; k < len; ++k) {
+ pages[i++] = sg_dma_address(&chunk->page_list[j]) +
+ region->page_size * k;
+ /*
+ * Be friendly to WRITE_MTT command
+ * and leave two empty slots for the
+ * index and reserved fields of the
+ * mailbox.
+ */
+ if (i == PAGE_SIZE / sizeof (u64) - 2) {
+ err = mthca_write_mtt(dev, mr->mtt,
+ n, pages, i);
+ if (err)
+ goto mtt_done;
+ n += i;
+ i = 0;
+ }
+ }
+ }
+
+ if (i)
+ err = mthca_write_mtt(dev, mr->mtt, n, pages, i);
+mtt_done:
+ free_page((unsigned long) pages);
+ if (err)
+ goto err_mtt;
+
+ err = mthca_mr_alloc(dev, to_mpd(pd)->pd_num, shift, region->virt_base,
+ region->length, convert_access(acc), mr);
+
+ if (err)
+ goto err_mtt;
+
+ return &mr->ibmr;
+
+err_mtt:
+ mthca_free_mtt(dev, mr->mtt);
+
+err:
+ kfree(mr);
+ return ERR_PTR(err);
+}
+
static int mthca_dereg_mr(struct ib_mr *mr)
{
struct mthca_mr *mmr = to_mmr(mr);
@@ -690,6 +972,8 @@ int mthca_register_device(struct mthca_dev *dev)
int i;
strlcpy(dev->ib_dev.name, "mthca%d", IB_DEVICE_NAME_MAX);
+ dev->ib_dev.owner = THIS_MODULE;
+
dev->ib_dev.node_type = IB_NODE_CA;
dev->ib_dev.phys_port_cnt = dev->limits.num_ports;
dev->ib_dev.dma_device = &dev->pdev->dev;
@@ -699,6 +983,9 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.modify_port = mthca_modify_port;
dev->ib_dev.query_pkey = mthca_query_pkey;
dev->ib_dev.query_gid = mthca_query_gid;
+ dev->ib_dev.alloc_ucontext = mthca_alloc_ucontext;
+ dev->ib_dev.dealloc_ucontext = mthca_dealloc_ucontext;
+ dev->ib_dev.mmap = mthca_mmap_uar;
dev->ib_dev.alloc_pd = mthca_alloc_pd;
dev->ib_dev.dealloc_pd = mthca_dealloc_pd;
dev->ib_dev.create_ah = mthca_ah_create;
@@ -711,6 +998,7 @@ int mthca_register_device(struct mthca_dev *dev)
dev->ib_dev.poll_cq = mthca_poll_cq;
dev->ib_dev.get_dma_mr = mthca_get_dma_mr;
dev->ib_dev.reg_phys_mr = mthca_reg_phys_mr;
+ dev->ib_dev.reg_user_mr = mthca_reg_user_mr;
dev->ib_dev.dereg_mr = mthca_dereg_mr;
if (dev->mthca_flags & MTHCA_FLAG_FMR) {
diff --git a/drivers/infiniband/hw/mthca/mthca_provider.h b/drivers/infiniband/hw/mthca/mthca_provider.h
index 619710f95a87..1d032791cc8b 100644
--- a/drivers/infiniband/hw/mthca/mthca_provider.h
+++ b/drivers/infiniband/hw/mthca/mthca_provider.h
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -54,18 +55,26 @@ struct mthca_uar {
int index;
};
+struct mthca_user_db_table;
+
+struct mthca_ucontext {
+ struct ib_ucontext ibucontext;
+ struct mthca_uar uar;
+ struct mthca_user_db_table *db_tab;
+};
+
+struct mthca_mtt;
+
struct mthca_mr {
- struct ib_mr ibmr;
- int order;
- u32 first_seg;
+ struct ib_mr ibmr;
+ struct mthca_mtt *mtt;
};
struct mthca_fmr {
- struct ib_fmr ibmr;
+ struct ib_fmr ibmr;
struct ib_fmr_attr attr;
- int order;
- u32 first_seg;
- int maps;
+ struct mthca_mtt *mtt;
+ int maps;
union {
struct {
struct mthca_mpt_entry __iomem *mpt;
@@ -83,6 +92,7 @@ struct mthca_pd {
u32 pd_num;
atomic_t sqp_count;
struct mthca_mr ntmr;
+ int privileged;
};
struct mthca_eq {
@@ -167,6 +177,7 @@ struct mthca_cq {
int cqn;
u32 cons_index;
int is_direct;
+ int is_kernel;
/* Next fields are Arbel only */
int set_ci_db_index;
@@ -236,6 +247,11 @@ struct mthca_sqp {
dma_addr_t header_dma;
};
+static inline struct mthca_ucontext *to_mucontext(struct ib_ucontext *ibucontext)
+{
+ return container_of(ibucontext, struct mthca_ucontext, ibucontext);
+}
+
static inline struct mthca_fmr *to_mfmr(struct ib_fmr *ibmr)
{
return container_of(ibmr, struct mthca_fmr, ibmr);
diff --git a/drivers/infiniband/hw/mthca/mthca_qp.c b/drivers/infiniband/hw/mthca/mthca_qp.c
index ca73bab11a02..f7126b14d5ae 100644
--- a/drivers/infiniband/hw/mthca/mthca_qp.c
+++ b/drivers/infiniband/hw/mthca/mthca_qp.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -46,7 +47,9 @@ enum {
MTHCA_MAX_DIRECT_QP_SIZE = 4 * PAGE_SIZE,
MTHCA_ACK_REQ_FREQ = 10,
MTHCA_FLIGHT_LIMIT = 9,
- MTHCA_UD_HEADER_SIZE = 72 /* largest UD header possible */
+ MTHCA_UD_HEADER_SIZE = 72, /* largest UD header possible */
+ MTHCA_INLINE_HEADER_SIZE = 4, /* data segment overhead for inline */
+ MTHCA_INLINE_CHUNK_SIZE = 16 /* inline data segment chunk */
};
enum {
@@ -357,6 +360,9 @@ static const struct {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
+ [UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
[RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
@@ -378,6 +384,9 @@ static const struct {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_QKEY),
+ [UC] = (IB_QP_PKEY_INDEX |
+ IB_QP_PORT |
+ IB_QP_ACCESS_FLAGS),
[RC] = (IB_QP_PKEY_INDEX |
IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
@@ -388,6 +397,11 @@ static const struct {
[IB_QPS_RTR] = {
.trans = MTHCA_TRANS_INIT2RTR,
.req_param = {
+ [UC] = (IB_QP_AV |
+ IB_QP_PATH_MTU |
+ IB_QP_DEST_QPN |
+ IB_QP_RQ_PSN |
+ IB_QP_MAX_DEST_RD_ATOMIC),
[RC] = (IB_QP_AV |
IB_QP_PATH_MTU |
IB_QP_DEST_QPN |
@@ -398,6 +412,9 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
+ [UC] = (IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX),
[RC] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
@@ -413,6 +430,8 @@ static const struct {
.trans = MTHCA_TRANS_RTR2RTS,
.req_param = {
[UD] = IB_QP_SQ_PSN,
+ [UC] = (IB_QP_SQ_PSN |
+ IB_QP_MAX_QP_RD_ATOMIC),
[RC] = (IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
@@ -423,6 +442,11 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
@@ -442,6 +466,9 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_ACCESS_FLAGS |
+ IB_QP_ALT_PATH |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE |
@@ -462,6 +489,10 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
@@ -476,6 +507,14 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_PKEY_INDEX |
IB_QP_QKEY),
+ [UC] = (IB_QP_AV |
+ IB_QP_MAX_QP_RD_ATOMIC |
+ IB_QP_MAX_DEST_RD_ATOMIC |
+ IB_QP_CUR_STATE |
+ IB_QP_ALT_PATH |
+ IB_QP_ACCESS_FLAGS |
+ IB_QP_PKEY_INDEX |
+ IB_QP_PATH_MIG_STATE),
[RC] = (IB_QP_AV |
IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
@@ -501,6 +540,7 @@ static const struct {
.opt_param = {
[UD] = (IB_QP_CUR_STATE |
IB_QP_QKEY),
+ [UC] = (IB_QP_CUR_STATE),
[RC] = (IB_QP_CUR_STATE |
IB_QP_MIN_RNR_TIMER),
[MLX] = (IB_QP_CUR_STATE |
@@ -552,7 +592,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
struct mthca_dev *dev = to_mdev(ibqp->device);
struct mthca_qp *qp = to_mqp(ibqp);
enum ib_qp_state cur_state, new_state;
- void *mailbox = NULL;
+ struct mthca_mailbox *mailbox;
struct mthca_qp_param *qp_param;
struct mthca_qp_context *qp_context;
u32 req_param, opt_param;
@@ -609,10 +649,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
return -EINVAL;
}
- mailbox = kmalloc(sizeof (*qp_param) + MTHCA_CMD_MAILBOX_EXTRA, GFP_KERNEL);
- if (!mailbox)
- return -ENOMEM;
- qp_param = MAILBOX_ALIGN(mailbox);
+ mailbox = mthca_alloc_mailbox(dev, GFP_KERNEL);
+ if (IS_ERR(mailbox))
+ return PTR_ERR(mailbox);
+ qp_param = mailbox->buf;
qp_context = &qp_param->context;
memset(qp_param, 0, sizeof *qp_param);
@@ -652,7 +692,11 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
/* leave arbel_sched_queue as 0 */
- qp_context->usr_page = cpu_to_be32(dev->driver_uar.index);
+ if (qp->ibqp.uobject)
+ qp_context->usr_page =
+ cpu_to_be32(to_mucontext(qp->ibqp.uobject->context)->uar.index);
+ else
+ qp_context->usr_page = cpu_to_be32(dev->driver_uar.index);
qp_context->local_qpn = cpu_to_be32(qp->qpn);
if (attr_mask & IB_QP_DEST_QPN) {
qp_context->remote_qpn = cpu_to_be32(attr->dest_qp_num);
@@ -683,7 +727,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (attr_mask & IB_QP_AV) {
qp_context->pri_path.g_mylmc = attr->ah_attr.src_path_bits & 0x7f;
qp_context->pri_path.rlid = cpu_to_be16(attr->ah_attr.dlid);
- qp_context->pri_path.static_rate = (!!attr->ah_attr.static_rate) << 3;
+ qp_context->pri_path.static_rate = !!attr->ah_attr.static_rate;
if (attr->ah_attr.ah_flags & IB_AH_GRH) {
qp_context->pri_path.g_mylmc |= 1 << 7;
qp_context->pri_path.mgid_index = attr->ah_attr.grh.sgid_index;
@@ -724,9 +768,9 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RETRY_COUNT);
}
- if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- qp_context->params1 |= cpu_to_be32(min(attr->max_dest_rd_atomic ?
- ffs(attr->max_dest_rd_atomic) - 1 : 0,
+ if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ qp_context->params1 |= cpu_to_be32(min(attr->max_rd_atomic ?
+ ffs(attr->max_rd_atomic) - 1 : 0,
7) << 21);
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_SRA_MAX);
}
@@ -764,10 +808,10 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp->atomic_rd_en = attr->qp_access_flags;
}
- if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
+ if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
u8 rra_max;
- if (qp->resp_depth && !attr->max_rd_atomic) {
+ if (qp->resp_depth && !attr->max_dest_rd_atomic) {
/*
* Lowering our responder resources to zero.
* Turn off RDMA/atomics as responder.
@@ -778,7 +822,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
MTHCA_QP_OPTPAR_RAE);
}
- if (!qp->resp_depth && attr->max_rd_atomic) {
+ if (!qp->resp_depth && attr->max_dest_rd_atomic) {
/*
* Increasing our responder resources from
* zero. Turn on RDMA/atomics as appropriate.
@@ -799,7 +843,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
for (rra_max = 0;
- 1 << rra_max < attr->max_rd_atomic &&
+ 1 << rra_max < attr->max_dest_rd_atomic &&
rra_max < dev->qp_table.rdb_shift;
++rra_max)
; /* nothing */
@@ -807,7 +851,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
qp_context->params2 |= cpu_to_be32(rra_max << 21);
qp_param->opt_param_mask |= cpu_to_be32(MTHCA_QP_OPTPAR_RRA_MAX);
- qp->resp_depth = attr->max_rd_atomic;
+ qp->resp_depth = attr->max_dest_rd_atomic;
}
qp_context->params2 |= cpu_to_be32(MTHCA_QP_BIT_RSC);
@@ -835,7 +879,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
}
err = mthca_MODIFY_QP(dev, state_table[cur_state][new_state].trans,
- qp->qpn, 0, qp_param, 0, &status);
+ qp->qpn, 0, mailbox, 0, &status);
if (status) {
mthca_warn(dev, "modify QP %d returned status %02x.\n",
state_table[cur_state][new_state].trans, status);
@@ -845,7 +889,7 @@ int mthca_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr, int attr_mask)
if (!err)
qp->state = new_state;
- kfree(mailbox);
+ mthca_free_mailbox(dev, mailbox);
if (is_sqp(dev, qp))
store_attrs(to_msqp(qp), attr, attr_mask);
@@ -917,6 +961,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
qp->send_wqe_offset = ALIGN(qp->rq.max << qp->rq.wqe_shift,
1 << qp->sq.wqe_shift);
+
+ /*
+ * If this is a userspace QP, we don't actually have to
+ * allocate anything. All we need is to calculate the WQE
+ * sizes and the send_wqe_offset, so we're done now.
+ */
+ if (pd->ibpd.uobject)
+ return 0;
+
size = PAGE_ALIGN(qp->send_wqe_offset +
(qp->sq.max << qp->sq.wqe_shift));
@@ -934,7 +987,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
mthca_dbg(dev, "Creating direct QP of size %d (shift %d)\n",
size, shift);
- qp->queue.direct.buf = pci_alloc_consistent(dev->pdev, size, &t);
+ qp->queue.direct.buf = dma_alloc_coherent(&dev->pdev->dev, size,
+ &t, GFP_KERNEL);
if (!qp->queue.direct.buf)
goto err_out;
@@ -973,7 +1027,8 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
for (i = 0; i < npages; ++i) {
qp->queue.page_list[i].buf =
- pci_alloc_consistent(dev->pdev, PAGE_SIZE, &t);
+ dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ &t, GFP_KERNEL);
if (!qp->queue.page_list[i].buf)
goto err_out_free;
@@ -996,16 +1051,15 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
err_out_free:
if (qp->is_direct) {
- pci_free_consistent(dev->pdev, size,
- qp->queue.direct.buf,
- pci_unmap_addr(&qp->queue.direct, mapping));
+ dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+ pci_unmap_addr(&qp->queue.direct, mapping));
} else
for (i = 0; i < npages; ++i) {
if (qp->queue.page_list[i].buf)
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- qp->queue.page_list[i].buf,
- pci_unmap_addr(&qp->queue.page_list[i],
- mapping));
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ qp->queue.page_list[i].buf,
+ pci_unmap_addr(&qp->queue.page_list[i],
+ mapping));
}
@@ -1015,10 +1069,32 @@ static int mthca_alloc_wqe_buf(struct mthca_dev *dev,
return err;
}
-static int mthca_alloc_memfree(struct mthca_dev *dev,
+static void mthca_free_wqe_buf(struct mthca_dev *dev,
struct mthca_qp *qp)
{
- int ret = 0;
+ int i;
+ int size = PAGE_ALIGN(qp->send_wqe_offset +
+ (qp->sq.max << qp->sq.wqe_shift));
+
+ if (qp->is_direct) {
+ dma_free_coherent(&dev->pdev->dev, size, qp->queue.direct.buf,
+ pci_unmap_addr(&qp->queue.direct, mapping));
+ } else {
+ for (i = 0; i < size / PAGE_SIZE; ++i) {
+ dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ qp->queue.page_list[i].buf,
+ pci_unmap_addr(&qp->queue.page_list[i],
+ mapping));
+ }
+ }
+
+ kfree(qp->wrid);
+}
+
+static int mthca_map_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ int ret;
if (mthca_is_memfree(dev)) {
ret = mthca_table_get(dev, dev->qp_table.qp_table, qp->qpn);
@@ -1029,35 +1105,15 @@ static int mthca_alloc_memfree(struct mthca_dev *dev,
if (ret)
goto err_qpc;
- ret = mthca_table_get(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- if (ret)
- goto err_eqpc;
-
- qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
- qp->qpn, &qp->rq.db);
- if (qp->rq.db_index < 0) {
- ret = -ENOMEM;
- goto err_rdb;
- }
+ ret = mthca_table_get(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ if (ret)
+ goto err_eqpc;
- qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
- qp->qpn, &qp->sq.db);
- if (qp->sq.db_index < 0) {
- ret = -ENOMEM;
- goto err_rq_db;
- }
}
return 0;
-err_rq_db:
- mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
-
-err_rdb:
- mthca_table_put(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
-
err_eqpc:
mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
@@ -1067,16 +1123,41 @@ err_qpc:
return ret;
}
+static void mthca_unmap_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ mthca_table_put(dev, dev->qp_table.rdb_table,
+ qp->qpn << dev->qp_table.rdb_shift);
+ mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
+ mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
+}
+
+static int mthca_alloc_memfree(struct mthca_dev *dev,
+ struct mthca_qp *qp)
+{
+ int ret = 0;
+
+ if (mthca_is_memfree(dev)) {
+ qp->rq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_RQ,
+ qp->qpn, &qp->rq.db);
+ if (qp->rq.db_index < 0)
+ return ret;
+
+ qp->sq.db_index = mthca_alloc_db(dev, MTHCA_DB_TYPE_SQ,
+ qp->qpn, &qp->sq.db);
+ if (qp->sq.db_index < 0)
+ mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
+ }
+
+ return ret;
+}
+
static void mthca_free_memfree(struct mthca_dev *dev,
struct mthca_qp *qp)
{
if (mthca_is_memfree(dev)) {
mthca_free_db(dev, MTHCA_DB_TYPE_SQ, qp->sq.db_index);
mthca_free_db(dev, MTHCA_DB_TYPE_RQ, qp->rq.db_index);
- mthca_table_put(dev, dev->qp_table.rdb_table,
- qp->qpn << dev->qp_table.rdb_shift);
- mthca_table_put(dev, dev->qp_table.eqp_table, qp->qpn);
- mthca_table_put(dev, dev->qp_table.qp_table, qp->qpn);
}
}
@@ -1108,13 +1189,28 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
mthca_wq_init(&qp->sq);
mthca_wq_init(&qp->rq);
- ret = mthca_alloc_memfree(dev, qp);
+ ret = mthca_map_memfree(dev, qp);
if (ret)
return ret;
ret = mthca_alloc_wqe_buf(dev, pd, qp);
if (ret) {
- mthca_free_memfree(dev, qp);
+ mthca_unmap_memfree(dev, qp);
+ return ret;
+ }
+
+ /*
+ * If this is a userspace QP, we're done now. The doorbells
+ * will be allocated and buffers will be initialized in
+ * userspace.
+ */
+ if (pd->ibpd.uobject)
+ return 0;
+
+ ret = mthca_alloc_memfree(dev, qp);
+ if (ret) {
+ mthca_free_wqe_buf(dev, qp);
+ mthca_unmap_memfree(dev, qp);
return ret;
}
@@ -1147,22 +1243,39 @@ static int mthca_alloc_qp_common(struct mthca_dev *dev,
return 0;
}
-static void mthca_align_qp_size(struct mthca_dev *dev, struct mthca_qp *qp)
+static int mthca_set_qp_size(struct mthca_dev *dev, struct ib_qp_cap *cap,
+ struct mthca_qp *qp)
{
- int i;
-
- if (!mthca_is_memfree(dev))
- return;
+ /* Sanity check QP size before proceeding */
+ if (cap->max_send_wr > 65536 || cap->max_recv_wr > 65536 ||
+ cap->max_send_sge > 64 || cap->max_recv_sge > 64)
+ return -EINVAL;
- for (i = 0; 1 << i < qp->rq.max; ++i)
- ; /* nothing */
+ if (mthca_is_memfree(dev)) {
+ qp->rq.max = cap->max_recv_wr ?
+ roundup_pow_of_two(cap->max_recv_wr) : 0;
+ qp->sq.max = cap->max_send_wr ?
+ roundup_pow_of_two(cap->max_send_wr) : 0;
+ } else {
+ qp->rq.max = cap->max_recv_wr;
+ qp->sq.max = cap->max_send_wr;
+ }
- qp->rq.max = 1 << i;
+ qp->rq.max_gs = cap->max_recv_sge;
+ qp->sq.max_gs = max_t(int, cap->max_send_sge,
+ ALIGN(cap->max_inline_data + MTHCA_INLINE_HEADER_SIZE,
+ MTHCA_INLINE_CHUNK_SIZE) /
+ sizeof (struct mthca_data_seg));
- for (i = 0; 1 << i < qp->sq.max; ++i)
- ; /* nothing */
+ /*
+ * For MLX transport we need 2 extra S/G entries:
+ * one for the header and one for the checksum at the end
+ */
+ if ((qp->transport == MLX && qp->sq.max_gs + 2 > dev->limits.max_sg) ||
+ qp->sq.max_gs > dev->limits.max_sg || qp->rq.max_gs > dev->limits.max_sg)
+ return -EINVAL;
- qp->sq.max = 1 << i;
+ return 0;
}
int mthca_alloc_qp(struct mthca_dev *dev,
@@ -1171,11 +1284,14 @@ int mthca_alloc_qp(struct mthca_dev *dev,
struct mthca_cq *recv_cq,
enum ib_qp_type type,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
struct mthca_qp *qp)
{
int err;
- mthca_align_qp_size(dev, qp);
+ err = mthca_set_qp_size(dev, cap, qp);
+ if (err)
+ return err;
switch (type) {
case IB_QPT_RC: qp->transport = RC; break;
@@ -1208,14 +1324,17 @@ int mthca_alloc_sqp(struct mthca_dev *dev,
struct mthca_cq *send_cq,
struct mthca_cq *recv_cq,
enum ib_sig_type send_policy,
+ struct ib_qp_cap *cap,
int qpn,
int port,
struct mthca_sqp *sqp)
{
- int err = 0;
u32 mqpn = qpn * 2 + dev->qp_table.sqp_start + port - 1;
+ int err;
- mthca_align_qp_size(dev, &sqp->qp);
+ err = mthca_set_qp_size(dev, cap, &sqp->qp);
+ if (err)
+ return err;
sqp->header_buf_size = sqp->qp.sq.max * MTHCA_UD_HEADER_SIZE;
sqp->header_buf = dma_alloc_coherent(&dev->pdev->dev, sqp->header_buf_size,
@@ -1274,8 +1393,6 @@ void mthca_free_qp(struct mthca_dev *dev,
struct mthca_qp *qp)
{
u8 status;
- int size;
- int i;
struct mthca_cq *send_cq;
struct mthca_cq *recv_cq;
@@ -1305,31 +1422,22 @@ void mthca_free_qp(struct mthca_dev *dev,
if (qp->state != IB_QPS_RESET)
mthca_MODIFY_QP(dev, MTHCA_TRANS_ANY2RST, qp->qpn, 0, NULL, 0, &status);
- mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
- if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
- mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
-
- mthca_free_mr(dev, &qp->mr);
-
- size = PAGE_ALIGN(qp->send_wqe_offset +
- (qp->sq.max << qp->sq.wqe_shift));
+ /*
+ * If this is a userspace QP, the buffers, MR, CQs and so on
+ * will be cleaned up in userspace, so all we have to do is
+ * unref the mem-free tables and free the QPN in our table.
+ */
+ if (!qp->ibqp.uobject) {
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.send_cq)->cqn, qp->qpn);
+ if (qp->ibqp.send_cq != qp->ibqp.recv_cq)
+ mthca_cq_clean(dev, to_mcq(qp->ibqp.recv_cq)->cqn, qp->qpn);
- if (qp->is_direct) {
- pci_free_consistent(dev->pdev, size,
- qp->queue.direct.buf,
- pci_unmap_addr(&qp->queue.direct, mapping));
- } else {
- for (i = 0; i < size / PAGE_SIZE; ++i) {
- pci_free_consistent(dev->pdev, PAGE_SIZE,
- qp->queue.page_list[i].buf,
- pci_unmap_addr(&qp->queue.page_list[i],
- mapping));
- }
+ mthca_free_mr(dev, &qp->mr);
+ mthca_free_memfree(dev, qp);
+ mthca_free_wqe_buf(dev, qp);
}
- kfree(qp->wrid);
-
- mthca_free_memfree(dev, qp);
+ mthca_unmap_memfree(dev, qp);
if (is_sqp(dev, qp)) {
atomic_dec(&(to_mpd(qp->ibqp.pd)->sqp_count));
@@ -1529,6 +1637,26 @@ int mthca_tavor_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
break;
+ case UC:
+ switch (wr->opcode) {
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ ((struct mthca_raddr_seg *) wqe)->raddr =
+ cpu_to_be64(wr->wr.rdma.remote_addr);
+ ((struct mthca_raddr_seg *) wqe)->rkey =
+ cpu_to_be32(wr->wr.rdma.rkey);
+ ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+ wqe += sizeof (struct mthca_raddr_seg);
+ size += sizeof (struct mthca_raddr_seg) / 16;
+ break;
+
+ default:
+ /* No extra segments required for sends */
+ break;
+ }
+
+ break;
+
case UD:
((struct mthca_tavor_ud_seg *) wqe)->lkey =
cpu_to_be32(to_mah(wr->wr.ud.ah)->key);
@@ -1814,9 +1942,29 @@ int mthca_arbel_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
sizeof (struct mthca_atomic_seg);
break;
+ case IB_WR_RDMA_READ:
+ case IB_WR_RDMA_WRITE:
+ case IB_WR_RDMA_WRITE_WITH_IMM:
+ ((struct mthca_raddr_seg *) wqe)->raddr =
+ cpu_to_be64(wr->wr.rdma.remote_addr);
+ ((struct mthca_raddr_seg *) wqe)->rkey =
+ cpu_to_be32(wr->wr.rdma.rkey);
+ ((struct mthca_raddr_seg *) wqe)->reserved = 0;
+ wqe += sizeof (struct mthca_raddr_seg);
+ size += sizeof (struct mthca_raddr_seg) / 16;
+ break;
+
+ default:
+ /* No extra segments required for sends */
+ break;
+ }
+
+ break;
+
+ case UC:
+ switch (wr->opcode) {
case IB_WR_RDMA_WRITE:
case IB_WR_RDMA_WRITE_WITH_IMM:
- case IB_WR_RDMA_READ:
((struct mthca_raddr_seg *) wqe)->raddr =
cpu_to_be64(wr->wr.rdma.remote_addr);
((struct mthca_raddr_seg *) wqe)->rkey =
diff --git a/drivers/infiniband/hw/mthca/mthca_user.h b/drivers/infiniband/hw/mthca/mthca_user.h
new file mode 100644
index 000000000000..3024c1b4547d
--- /dev/null
+++ b/drivers/infiniband/hw/mthca/mthca_user.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef MTHCA_USER_H
+#define MTHCA_USER_H
+
+#include <linux/types.h>
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct mthca_alloc_ucontext_resp {
+ __u32 qp_tab_size;
+ __u32 uarc_size;
+};
+
+struct mthca_alloc_pd_resp {
+ __u32 pdn;
+ __u32 reserved;
+};
+
+struct mthca_create_cq {
+ __u32 lkey;
+ __u32 pdn;
+ __u64 arm_db_page;
+ __u64 set_db_page;
+ __u32 arm_db_index;
+ __u32 set_db_index;
+};
+
+struct mthca_create_cq_resp {
+ __u32 cqn;
+ __u32 reserved;
+};
+
+struct mthca_create_qp {
+ __u32 lkey;
+ __u32 reserved;
+ __u64 sq_db_page;
+ __u64 rq_db_page;
+ __u32 sq_db_index;
+ __u32 rq_db_index;
+};
+
+#endif /* MTHCA_USER_H */
diff --git a/drivers/infiniband/include/ib_user_verbs.h b/drivers/infiniband/include/ib_user_verbs.h
new file mode 100644
index 000000000000..7c613706af72
--- /dev/null
+++ b/drivers/infiniband/include/ib_user_verbs.h
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2005 Topspin Communications. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * 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.
+ *
+ * $Id: ib_user_verbs.h 2708 2005-06-24 17:27:21Z roland $
+ */
+
+#ifndef IB_USER_VERBS_H
+#define IB_USER_VERBS_H
+
+#include <linux/types.h>
+
+/*
+ * Increment this value if any changes that break userspace ABI
+ * compatibility are made.
+ */
+#define IB_USER_VERBS_ABI_VERSION 1
+
+enum {
+ IB_USER_VERBS_CMD_QUERY_PARAMS,
+ IB_USER_VERBS_CMD_GET_CONTEXT,
+ IB_USER_VERBS_CMD_QUERY_DEVICE,
+ IB_USER_VERBS_CMD_QUERY_PORT,
+ IB_USER_VERBS_CMD_QUERY_GID,
+ IB_USER_VERBS_CMD_QUERY_PKEY,
+ IB_USER_VERBS_CMD_ALLOC_PD,
+ IB_USER_VERBS_CMD_DEALLOC_PD,
+ IB_USER_VERBS_CMD_CREATE_AH,
+ IB_USER_VERBS_CMD_MODIFY_AH,
+ IB_USER_VERBS_CMD_QUERY_AH,
+ IB_USER_VERBS_CMD_DESTROY_AH,
+ IB_USER_VERBS_CMD_REG_MR,
+ IB_USER_VERBS_CMD_REG_SMR,
+ IB_USER_VERBS_CMD_REREG_MR,
+ IB_USER_VERBS_CMD_QUERY_MR,
+ IB_USER_VERBS_CMD_DEREG_MR,
+ IB_USER_VERBS_CMD_ALLOC_MW,
+ IB_USER_VERBS_CMD_BIND_MW,
+ IB_USER_VERBS_CMD_DEALLOC_MW,
+ IB_USER_VERBS_CMD_CREATE_CQ,
+ IB_USER_VERBS_CMD_RESIZE_CQ,
+ IB_USER_VERBS_CMD_DESTROY_CQ,
+ IB_USER_VERBS_CMD_POLL_CQ,
+ IB_USER_VERBS_CMD_PEEK_CQ,
+ IB_USER_VERBS_CMD_REQ_NOTIFY_CQ,
+ IB_USER_VERBS_CMD_CREATE_QP,
+ IB_USER_VERBS_CMD_QUERY_QP,
+ IB_USER_VERBS_CMD_MODIFY_QP,
+ IB_USER_VERBS_CMD_DESTROY_QP,
+ IB_USER_VERBS_CMD_POST_SEND,
+ IB_USER_VERBS_CMD_POST_RECV,
+ IB_USER_VERBS_CMD_ATTACH_MCAST,
+ IB_USER_VERBS_CMD_DETACH_MCAST
+};
+
+/*
+ * Make sure that all structs defined in this file remain laid out so
+ * that they pack the same way on 32-bit and 64-bit architectures (to
+ * avoid incompatibility between 32-bit userspace and 64-bit kernels).
+ * In particular do not use pointer types -- pass pointers in __u64
+ * instead.
+ */
+
+struct ib_uverbs_async_event_desc {
+ __u64 element;
+ __u32 event_type; /* enum ib_event_type */
+ __u32 reserved;
+};
+
+struct ib_uverbs_comp_event_desc {
+ __u64 cq_handle;
+};
+
+/*
+ * All commands from userspace should start with a __u32 command field
+ * followed by __u16 in_words and out_words fields (which give the
+ * length of the command block and response buffer if any in 32-bit
+ * words). The kernel driver will read these fields first and read
+ * the rest of the command struct based on these value.
+ */
+
+struct ib_uverbs_cmd_hdr {
+ __u32 command;
+ __u16 in_words;
+ __u16 out_words;
+};
+
+/*
+ * No driver_data for "query params" command, since this is intended
+ * to be a core function with no possible device dependence.
+ */
+struct ib_uverbs_query_params {
+ __u64 response;
+};
+
+struct ib_uverbs_query_params_resp {
+ __u32 num_cq_events;
+};
+
+struct ib_uverbs_get_context {
+ __u64 response;
+ __u64 cq_fd_tab;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_get_context_resp {
+ __u32 async_fd;
+ __u32 reserved;
+};
+
+struct ib_uverbs_query_device {
+ __u64 response;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_device_resp {
+ __u64 fw_ver;
+ __u64 node_guid;
+ __u64 sys_image_guid;
+ __u64 max_mr_size;
+ __u64 page_size_cap;
+ __u32 vendor_id;
+ __u32 vendor_part_id;
+ __u32 hw_ver;
+ __u32 max_qp;
+ __u32 max_qp_wr;
+ __u32 device_cap_flags;
+ __u32 max_sge;
+ __u32 max_sge_rd;
+ __u32 max_cq;
+ __u32 max_cqe;
+ __u32 max_mr;
+ __u32 max_pd;
+ __u32 max_qp_rd_atom;
+ __u32 max_ee_rd_atom;
+ __u32 max_res_rd_atom;
+ __u32 max_qp_init_rd_atom;
+ __u32 max_ee_init_rd_atom;
+ __u32 atomic_cap;
+ __u32 max_ee;
+ __u32 max_rdd;
+ __u32 max_mw;
+ __u32 max_raw_ipv6_qp;
+ __u32 max_raw_ethy_qp;
+ __u32 max_mcast_grp;
+ __u32 max_mcast_qp_attach;
+ __u32 max_total_mcast_qp_attach;
+ __u32 max_ah;
+ __u32 max_fmr;
+ __u32 max_map_per_fmr;
+ __u32 max_srq;
+ __u32 max_srq_wr;
+ __u32 max_srq_sge;
+ __u16 max_pkeys;
+ __u8 local_ca_ack_delay;
+ __u8 phys_port_cnt;
+ __u8 reserved[4];
+};
+
+struct ib_uverbs_query_port {
+ __u64 response;
+ __u8 port_num;
+ __u8 reserved[7];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_port_resp {
+ __u32 port_cap_flags;
+ __u32 max_msg_sz;
+ __u32 bad_pkey_cntr;
+ __u32 qkey_viol_cntr;
+ __u32 gid_tbl_len;
+ __u16 pkey_tbl_len;
+ __u16 lid;
+ __u16 sm_lid;
+ __u8 state;
+ __u8 max_mtu;
+ __u8 active_mtu;
+ __u8 lmc;
+ __u8 max_vl_num;
+ __u8 sm_sl;
+ __u8 subnet_timeout;
+ __u8 init_type_reply;
+ __u8 active_width;
+ __u8 active_speed;
+ __u8 phys_state;
+ __u8 reserved[3];
+};
+
+struct ib_uverbs_query_gid {
+ __u64 response;
+ __u8 port_num;
+ __u8 index;
+ __u8 reserved[6];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_gid_resp {
+ __u8 gid[16];
+};
+
+struct ib_uverbs_query_pkey {
+ __u64 response;
+ __u8 port_num;
+ __u8 index;
+ __u8 reserved[6];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_query_pkey_resp {
+ __u16 pkey;
+ __u16 reserved;
+};
+
+struct ib_uverbs_alloc_pd {
+ __u64 response;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_alloc_pd_resp {
+ __u32 pd_handle;
+};
+
+struct ib_uverbs_dealloc_pd {
+ __u32 pd_handle;
+};
+
+struct ib_uverbs_reg_mr {
+ __u64 response;
+ __u64 start;
+ __u64 length;
+ __u64 hca_va;
+ __u32 pd_handle;
+ __u32 access_flags;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_reg_mr_resp {
+ __u32 mr_handle;
+ __u32 lkey;
+ __u32 rkey;
+};
+
+struct ib_uverbs_dereg_mr {
+ __u32 mr_handle;
+};
+
+struct ib_uverbs_create_cq {
+ __u64 response;
+ __u64 user_handle;
+ __u32 cqe;
+ __u32 event_handler;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_cq_resp {
+ __u32 cq_handle;
+ __u32 cqe;
+};
+
+struct ib_uverbs_destroy_cq {
+ __u32 cq_handle;
+};
+
+struct ib_uverbs_create_qp {
+ __u64 response;
+ __u64 user_handle;
+ __u32 pd_handle;
+ __u32 send_cq_handle;
+ __u32 recv_cq_handle;
+ __u32 srq_handle;
+ __u32 max_send_wr;
+ __u32 max_recv_wr;
+ __u32 max_send_sge;
+ __u32 max_recv_sge;
+ __u32 max_inline_data;
+ __u8 sq_sig_all;
+ __u8 qp_type;
+ __u8 is_srq;
+ __u8 reserved;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_create_qp_resp {
+ __u32 qp_handle;
+ __u32 qpn;
+};
+
+/*
+ * This struct needs to remain a multiple of 8 bytes to keep the
+ * alignment of the modify QP parameters.
+ */
+struct ib_uverbs_qp_dest {
+ __u8 dgid[16];
+ __u32 flow_label;
+ __u16 dlid;
+ __u16 reserved;
+ __u8 sgid_index;
+ __u8 hop_limit;
+ __u8 traffic_class;
+ __u8 sl;
+ __u8 src_path_bits;
+ __u8 static_rate;
+ __u8 is_global;
+ __u8 port_num;
+};
+
+struct ib_uverbs_modify_qp {
+ struct ib_uverbs_qp_dest dest;
+ struct ib_uverbs_qp_dest alt_dest;
+ __u32 qp_handle;
+ __u32 attr_mask;
+ __u32 qkey;
+ __u32 rq_psn;
+ __u32 sq_psn;
+ __u32 dest_qp_num;
+ __u32 qp_access_flags;
+ __u16 pkey_index;
+ __u16 alt_pkey_index;
+ __u8 qp_state;
+ __u8 cur_qp_state;
+ __u8 path_mtu;
+ __u8 path_mig_state;
+ __u8 en_sqd_async_notify;
+ __u8 max_rd_atomic;
+ __u8 max_dest_rd_atomic;
+ __u8 min_rnr_timer;
+ __u8 port_num;
+ __u8 timeout;
+ __u8 retry_cnt;
+ __u8 rnr_retry;
+ __u8 alt_port_num;
+ __u8 alt_timeout;
+ __u8 reserved[2];
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_modify_qp_resp {
+};
+
+struct ib_uverbs_destroy_qp {
+ __u32 qp_handle;
+};
+
+struct ib_uverbs_attach_mcast {
+ __u8 gid[16];
+ __u32 qp_handle;
+ __u16 mlid;
+ __u16 reserved;
+ __u64 driver_data[0];
+};
+
+struct ib_uverbs_detach_mcast {
+ __u8 gid[16];
+ __u32 qp_handle;
+ __u16 mlid;
+ __u16 reserved;
+ __u64 driver_data[0];
+};
+
+#endif /* IB_USER_VERBS_H */
diff --git a/drivers/infiniband/include/ib_verbs.h b/drivers/infiniband/include/ib_verbs.h
index cf01f044a223..e5bd9a10c201 100644
--- a/drivers/infiniband/include/ib_verbs.h
+++ b/drivers/infiniband/include/ib_verbs.h
@@ -4,6 +4,7 @@
* Copyright (c) 2004 Intel Corporation. All rights reserved.
* Copyright (c) 2004 Topspin Corporation. All rights reserved.
* Copyright (c) 2004 Voltaire Corporation. All rights reserved.
+ * Copyright (c) 2005 Cisco Systems. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
@@ -41,7 +42,10 @@
#include <linux/types.h>
#include <linux/device.h>
+
#include <asm/atomic.h>
+#include <asm/scatterlist.h>
+#include <asm/uaccess.h>
union ib_gid {
u8 raw[16];
@@ -544,7 +548,7 @@ struct ib_send_wr {
int num_sge;
enum ib_wr_opcode opcode;
int send_flags;
- u32 imm_data;
+ __be32 imm_data;
union {
struct {
u64 remote_addr;
@@ -618,29 +622,86 @@ struct ib_fmr_attr {
u8 page_size;
};
+struct ib_ucontext {
+ struct ib_device *device;
+ struct list_head pd_list;
+ struct list_head mr_list;
+ struct list_head mw_list;
+ struct list_head cq_list;
+ struct list_head qp_list;
+ struct list_head srq_list;
+ struct list_head ah_list;
+ spinlock_t lock;
+};
+
+struct ib_uobject {
+ u64 user_handle; /* handle given to us by userspace */
+ struct ib_ucontext *context; /* associated user context */
+ struct list_head list; /* link to context's list */
+ u32 id; /* index into kernel idr */
+};
+
+struct ib_umem {
+ unsigned long user_base;
+ unsigned long virt_base;
+ size_t length;
+ int offset;
+ int page_size;
+ int writable;
+ struct list_head chunk_list;
+};
+
+struct ib_umem_chunk {
+ struct list_head list;
+ int nents;
+ int nmap;
+ struct scatterlist page_list[0];
+};
+
+struct ib_udata {
+ void __user *inbuf;
+ void __user *outbuf;
+ size_t inlen;
+ size_t outlen;
+};
+
+#define IB_UMEM_MAX_PAGE_CHUNK \
+ ((PAGE_SIZE - offsetof(struct ib_umem_chunk, page_list)) / \
+ ((void *) &((struct ib_umem_chunk *) 0)->page_list[1] - \
+ (void *) &((struct ib_umem_chunk *) 0)->page_list[0]))
+
+struct ib_umem_object {
+ struct ib_uobject uobject;
+ struct ib_umem umem;
+};
+
struct ib_pd {
- struct ib_device *device;
- atomic_t usecnt; /* count all resources */
+ struct ib_device *device;
+ struct ib_uobject *uobject;
+ atomic_t usecnt; /* count all resources */
};
struct ib_ah {
struct ib_device *device;
struct ib_pd *pd;
+ struct ib_uobject *uobject;
};
typedef void (*ib_comp_handler)(struct ib_cq *cq, void *cq_context);
struct ib_cq {
- struct ib_device *device;
- ib_comp_handler comp_handler;
- void (*event_handler)(struct ib_event *, void *);
- void * cq_context;
- int cqe;
- atomic_t usecnt; /* count number of work queues */
+ struct ib_device *device;
+ struct ib_uobject *uobject;
+ ib_comp_handler comp_handler;
+ void (*event_handler)(struct ib_event *, void *);
+ void * cq_context;
+ int cqe;
+ atomic_t usecnt; /* count number of work queues */
};
struct ib_srq {
struct ib_device *device;
+ struct ib_uobject *uobject;
struct ib_pd *pd;
void *srq_context;
atomic_t usecnt;
@@ -652,6 +713,7 @@ struct ib_qp {
struct ib_cq *send_cq;
struct ib_cq *recv_cq;
struct ib_srq *srq;
+ struct ib_uobject *uobject;
void (*event_handler)(struct ib_event *, void *);
void *qp_context;
u32 qp_num;
@@ -659,16 +721,18 @@ struct ib_qp {
};
struct ib_mr {
- struct ib_device *device;
- struct ib_pd *pd;
- u32 lkey;
- u32 rkey;
- atomic_t usecnt; /* count number of MWs */
+ struct ib_device *device;
+ struct ib_pd *pd;
+ struct ib_uobject *uobject;
+ u32 lkey;
+ u32 rkey;
+ atomic_t usecnt; /* count number of MWs */
};
struct ib_mw {
struct ib_device *device;
struct ib_pd *pd;
+ struct ib_uobject *uobject;
u32 rkey;
};
@@ -737,7 +801,14 @@ struct ib_device {
int (*modify_port)(struct ib_device *device,
u8 port_num, int port_modify_mask,
struct ib_port_modify *port_modify);
- struct ib_pd * (*alloc_pd)(struct ib_device *device);
+ struct ib_ucontext * (*alloc_ucontext)(struct ib_device *device,
+ struct ib_udata *udata);
+ int (*dealloc_ucontext)(struct ib_ucontext *context);
+ int (*mmap)(struct ib_ucontext *context,
+ struct vm_area_struct *vma);
+ struct ib_pd * (*alloc_pd)(struct ib_device *device,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
int (*dealloc_pd)(struct ib_pd *pd);
struct ib_ah * (*create_ah)(struct ib_pd *pd,
struct ib_ah_attr *ah_attr);
@@ -747,7 +818,8 @@ struct ib_device {
struct ib_ah_attr *ah_attr);
int (*destroy_ah)(struct ib_ah *ah);
struct ib_qp * (*create_qp)(struct ib_pd *pd,
- struct ib_qp_init_attr *qp_init_attr);
+ struct ib_qp_init_attr *qp_init_attr,
+ struct ib_udata *udata);
int (*modify_qp)(struct ib_qp *qp,
struct ib_qp_attr *qp_attr,
int qp_attr_mask);
@@ -762,8 +834,9 @@ struct ib_device {
int (*post_recv)(struct ib_qp *qp,
struct ib_recv_wr *recv_wr,
struct ib_recv_wr **bad_recv_wr);
- struct ib_cq * (*create_cq)(struct ib_device *device,
- int cqe);
+ struct ib_cq * (*create_cq)(struct ib_device *device, int cqe,
+ struct ib_ucontext *context,
+ struct ib_udata *udata);
int (*destroy_cq)(struct ib_cq *cq);
int (*resize_cq)(struct ib_cq *cq, int *cqe);
int (*poll_cq)(struct ib_cq *cq, int num_entries,
@@ -780,6 +853,10 @@ struct ib_device {
int num_phys_buf,
int mr_access_flags,
u64 *iova_start);
+ struct ib_mr * (*reg_user_mr)(struct ib_pd *pd,
+ struct ib_umem *region,
+ int mr_access_flags,
+ struct ib_udata *udata);
int (*query_mr)(struct ib_mr *mr,
struct ib_mr_attr *mr_attr);
int (*dereg_mr)(struct ib_mr *mr);
@@ -817,6 +894,7 @@ struct ib_device {
struct ib_mad *in_mad,
struct ib_mad *out_mad);
+ struct module *owner;
struct class_device class_dev;
struct kobject ports_parent;
struct list_head port_list;
@@ -852,6 +930,16 @@ void *ib_get_client_data(struct ib_device *device, struct ib_client *client);
void ib_set_client_data(struct ib_device *device, struct ib_client *client,
void *data);
+static inline int ib_copy_from_udata(void *dest, struct ib_udata *udata, size_t len)
+{
+ return copy_from_user(dest, udata->inbuf, len) ? -EFAULT : 0;
+}
+
+static inline int ib_copy_to_udata(struct ib_udata *udata, void *src, size_t len)
+{
+ return copy_to_user(udata->outbuf, src, len) ? -EFAULT : 0;
+}
+
int ib_register_event_handler (struct ib_event_handler *event_handler);
int ib_unregister_event_handler(struct ib_event_handler *event_handler);
void ib_dispatch_event(struct ib_event *event);
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 556264b43425..374f404e81da 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -21,6 +21,7 @@
#include <linux/smp_lock.h>
#include <linux/device.h>
#include <linux/devfs_fs_kernel.h>
+#include <linux/compat.h>
struct evdev {
int exist;
@@ -145,6 +146,41 @@ static int evdev_open(struct inode * inode, struct file * file)
return 0;
}
+#ifdef CONFIG_COMPAT
+struct input_event_compat {
+ struct compat_timeval time;
+ __u16 type;
+ __u16 code;
+ __s32 value;
+};
+
+#ifdef CONFIG_X86_64
+# define COMPAT_TEST test_thread_flag(TIF_IA32)
+#elif defined(CONFIG_IA64)
+# define COMPAT_TEST IS_IA32_PROCESS(ia64_task_regs(current))
+#elif defined(CONFIG_ARCH_S390)
+# define COMPAT_TEST test_thread_flag(TIF_31BIT)
+#else
+# define COMPAT_TEST test_thread_flag(TIF_32BIT)
+#endif
+
+static ssize_t evdev_write_compat(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
+{
+ struct evdev_list *list = file->private_data;
+ struct input_event_compat event;
+ int retval = 0;
+
+ while (retval < count) {
+ if (copy_from_user(&event, buffer + retval, sizeof(struct input_event_compat)))
+ return -EFAULT;
+ input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+ retval += sizeof(struct input_event_compat);
+ }
+
+ return retval;
+}
+#endif
+
static ssize_t evdev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
@@ -153,6 +189,11 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
if (!list->evdev->exist) return -ENODEV;
+#ifdef CONFIG_COMPAT
+ if (COMPAT_TEST)
+ return evdev_write_compat(file, buffer, count, ppos);
+#endif
+
while (retval < count) {
if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
@@ -164,11 +205,56 @@ static ssize_t evdev_write(struct file * file, const char __user * buffer, size_
return retval;
}
+#ifdef CONFIG_COMPAT
+static ssize_t evdev_read_compat(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
+{
+ struct evdev_list *list = file->private_data;
+ int retval;
+
+ if (count < sizeof(struct input_event_compat))
+ return -EINVAL;
+
+ if (list->head == list->tail && list->evdev->exist && (file->f_flags & O_NONBLOCK))
+ return -EAGAIN;
+
+ retval = wait_event_interruptible(list->evdev->wait,
+ list->head != list->tail || (!list->evdev->exist));
+
+ if (retval)
+ return retval;
+
+ if (!list->evdev->exist)
+ return -ENODEV;
+
+ while (list->head != list->tail && retval + sizeof(struct input_event_compat) <= count) {
+ struct input_event *event = (struct input_event *) list->buffer + list->tail;
+ struct input_event_compat event_compat;
+ event_compat.time.tv_sec = event->time.tv_sec;
+ event_compat.time.tv_usec = event->time.tv_usec;
+ event_compat.type = event->type;
+ event_compat.code = event->code;
+ event_compat.value = event->value;
+
+ if (copy_to_user(buffer + retval, &event_compat,
+ sizeof(struct input_event_compat))) return -EFAULT;
+ list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
+ retval += sizeof(struct input_event_compat);
+ }
+
+ return retval;
+}
+#endif
+
static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{
struct evdev_list *list = file->private_data;
int retval;
+#ifdef CONFIG_COMPAT
+ if (COMPAT_TEST)
+ return evdev_read_compat(file, buffer, count, ppos);
+#endif
+
if (count < sizeof(struct input_event))
return -EINVAL;
@@ -186,7 +272,7 @@ static ssize_t evdev_read(struct file * file, char __user * buffer, size_t count
while (list->head != list->tail && retval + sizeof(struct input_event) <= count) {
if (copy_to_user(buffer + retval, list->buffer + list->tail,
- sizeof(struct input_event))) return -EFAULT;
+ sizeof(struct input_event))) return -EFAULT;
list->tail = (list->tail + 1) & (EVDEV_BUFFER_SIZE - 1);
retval += sizeof(struct input_event);
}
@@ -203,7 +289,7 @@ static unsigned int evdev_poll(struct file *file, poll_table *wait)
(list->evdev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct evdev_list *list = file->private_data;
struct evdev *evdev = list->evdev;
@@ -285,109 +371,267 @@ static int evdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
default:
- if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
+ if (_IOC_TYPE(cmd) != 'E')
return -EINVAL;
- if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
-
- long *bits;
- int len;
-
- switch (_IOC_NR(cmd) & EV_MAX) {
- case 0: bits = dev->evbit; len = EV_MAX; break;
- case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
- case EV_REL: bits = dev->relbit; len = REL_MAX; break;
- case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
- case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
- case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
- case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
- case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
- default: return -EINVAL;
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+
+ long *bits;
+ int len;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; len = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; len = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
+ default: return -EINVAL;
+ }
+ len = NBITS(len) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, bits, len) ? -EFAULT : len;
}
- len = NBITS(len) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, bits, len) ? -EFAULT : len;
- }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
- int len;
- len = NBITS(KEY_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->key, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) {
+ int len;
+ len = NBITS(KEY_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->key, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
- int len;
- len = NBITS(LED_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->led, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) {
+ int len;
+ len = NBITS(LED_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->led, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
- int len;
- len = NBITS(SND_MAX) * sizeof(long);
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) {
+ int len;
+ len = NBITS(SND_MAX) * sizeof(long);
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->snd, len) ? -EFAULT : len;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
- int len;
- if (!dev->name) return -ENOENT;
- len = strlen(dev->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->name, len) ? -EFAULT : len;
- }
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len;
+ if (!dev->name) return -ENOENT;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+ int len;
+ if (!dev->phys) return -ENOENT;
+ len = strlen(dev->phys) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+ int len;
+ if (!dev->uniq) return -ENOENT;
+ len = strlen(dev->uniq) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ }
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
+
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
- int len;
- if (!dev->phys) return -ENOENT;
- len = strlen(dev->phys) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
}
- if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
- int len;
- if (!dev->uniq) return -ENOENT;
- len = strlen(dev->uniq) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ return 0;
+ }
}
+ }
+ return -EINVAL;
+}
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+#ifdef CONFIG_COMPAT
+
+#define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8)
+#define NBITS_COMPAT(x) ((((x)-1)/BITS_PER_LONG_COMPAT)+1)
+#define OFF_COMPAT(x) ((x)%BITS_PER_LONG_COMPAT)
+#define BIT_COMPAT(x) (1UL<<OFF_COMPAT(x))
+#define LONG_COMPAT(x) ((x)/BITS_PER_LONG_COMPAT)
+#define test_bit_compat(bit, array) ((array[LONG_COMPAT(bit)] >> OFF_COMPAT(bit)) & 1)
+
+#ifdef __BIG_ENDIAN
+#define bit_to_user(bit, max) \
+do { \
+ int i; \
+ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+ for (i = 0; i < len / sizeof(compat_long_t); i++) \
+ if (copy_to_user((compat_long_t*) p + i, \
+ (compat_long_t*) (bit) + i + 1 - ((i % 2) << 1), \
+ sizeof(compat_long_t))) \
+ return -EFAULT; \
+ return len; \
+} while (0)
+#else
+#define bit_to_user(bit, max) \
+do { \
+ int len = NBITS_COMPAT((max)) * sizeof(compat_long_t); \
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); \
+ return copy_to_user(p, (bit), len) ? -EFAULT : len; \
+} while (0)
+#endif
+
+static long evdev_ioctl_compat(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct evdev_list *list = file->private_data;
+ struct evdev *evdev = list->evdev;
+ struct input_dev *dev = evdev->handle.dev;
+ struct input_absinfo abs;
+ void __user *p = compat_ptr(arg);
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if (!evdev->exist) return -ENODEV;
- abs.value = dev->abs[t];
- abs.minimum = dev->absmin[t];
- abs.maximum = dev->absmax[t];
- abs.fuzz = dev->absfuzz[t];
- abs.flat = dev->absflat[t];
+ switch (cmd) {
- if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
- return -EFAULT;
+ case EVIOCGVERSION:
+ case EVIOCGID:
+ case EVIOCGKEYCODE:
+ case EVIOCSKEYCODE:
+ case EVIOCSFF:
+ case EVIOCRMFF:
+ case EVIOCGEFFECTS:
+ case EVIOCGRAB:
+ return evdev_ioctl(file, cmd, (unsigned long) p);
- return 0;
+ default:
+
+ if (_IOC_TYPE(cmd) != 'E')
+ return -EINVAL;
+
+ if (_IOC_DIR(cmd) == _IOC_READ) {
+
+ if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0,0))) {
+ long *bits;
+ int max;
+
+ switch (_IOC_NR(cmd) & EV_MAX) {
+ case 0: bits = dev->evbit; max = EV_MAX; break;
+ case EV_KEY: bits = dev->keybit; max = KEY_MAX; break;
+ case EV_REL: bits = dev->relbit; max = REL_MAX; break;
+ case EV_ABS: bits = dev->absbit; max = ABS_MAX; break;
+ case EV_MSC: bits = dev->mscbit; max = MSC_MAX; break;
+ case EV_LED: bits = dev->ledbit; max = LED_MAX; break;
+ case EV_SND: bits = dev->sndbit; max = SND_MAX; break;
+ case EV_FF: bits = dev->ffbit; max = FF_MAX; break;
+ default: return -EINVAL;
+ }
+ bit_to_user(bits, max);
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
+ bit_to_user(dev->key, KEY_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0)))
+ bit_to_user(dev->led, LED_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0)))
+ bit_to_user(dev->snd, SND_MAX);
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) {
+ int len;
+ if (!dev->name) return -ENOENT;
+ len = strlen(dev->name) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->name, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) {
+ int len;
+ if (!dev->phys) return -ENOENT;
+ len = strlen(dev->phys) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->phys, len) ? -EFAULT : len;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) {
+ int len;
+ if (!dev->uniq) return -ENOENT;
+ len = strlen(dev->uniq) + 1;
+ if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+ return copy_to_user(p, dev->uniq, len) ? -EFAULT : len;
+ }
+
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) {
+
+ int t = _IOC_NR(cmd) & ABS_MAX;
+
+ abs.value = dev->abs[t];
+ abs.minimum = dev->absmin[t];
+ abs.maximum = dev->absmax[t];
+ abs.fuzz = dev->absfuzz[t];
+ abs.flat = dev->absflat[t];
+
+ if (copy_to_user(p, &abs, sizeof(struct input_absinfo)))
+ return -EFAULT;
+
+ return 0;
+ }
}
- if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
+ if (_IOC_DIR(cmd) == _IOC_WRITE) {
- int t = _IOC_NR(cmd) & ABS_MAX;
+ if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) {
- if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
- return -EFAULT;
+ int t = _IOC_NR(cmd) & ABS_MAX;
- dev->abs[t] = abs.value;
- dev->absmin[t] = abs.minimum;
- dev->absmax[t] = abs.maximum;
- dev->absfuzz[t] = abs.fuzz;
- dev->absflat[t] = abs.flat;
+ if (copy_from_user(&abs, p, sizeof(struct input_absinfo)))
+ return -EFAULT;
- return 0;
+ dev->abs[t] = abs.value;
+ dev->absmin[t] = abs.minimum;
+ dev->absmax[t] = abs.maximum;
+ dev->absfuzz[t] = abs.fuzz;
+ dev->absflat[t] = abs.flat;
+
+ return 0;
+ }
}
}
return -EINVAL;
}
+#endif
static struct file_operations evdev_fops = {
.owner = THIS_MODULE,
@@ -396,7 +640,10 @@ static struct file_operations evdev_fops = {
.poll = evdev_poll,
.open = evdev_open,
.release = evdev_release,
- .ioctl = evdev_ioctl,
+ .unlocked_ioctl = evdev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = evdev_ioctl_compat,
+#endif
.fasync = evdev_fasync,
.flush = evdev_flush
};
diff --git a/drivers/input/gameport/Kconfig b/drivers/input/gameport/Kconfig
index 1d93f5092904..7524bd7d8b8f 100644
--- a/drivers/input/gameport/Kconfig
+++ b/drivers/input/gameport/Kconfig
@@ -49,22 +49,8 @@ config GAMEPORT_EMU10K1
To compile this driver as a module, choose M here: the
module will be called emu10k1-gp.
-config GAMEPORT_VORTEX
- tristate "Aureal Vortex, Vortex 2 gameport support"
- depends on PCI
- help
- Say Y here if you have an Aureal Vortex 1 or 2 card and want
- to use its gameport.
-
- To compile this driver as a module, choose M here: the
- module will be called vortex.
-
config GAMEPORT_FM801
tristate "ForteMedia FM801 gameport support"
depends on PCI
-config GAMEPORT_CS461X
- tristate "Crystal SoundFusion gameport support"
- depends on PCI
-
endif
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
index 5367b4267adf..b6f6097bd8c4 100644
--- a/drivers/input/gameport/Makefile
+++ b/drivers/input/gameport/Makefile
@@ -5,9 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_GAMEPORT) += gameport.o
-obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
obj-$(CONFIG_GAMEPORT_FM801) += fm801-gp.o
obj-$(CONFIG_GAMEPORT_L4) += lightning.o
obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
-obj-$(CONFIG_GAMEPORT_VORTEX) += vortex.o
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
deleted file mode 100644
index d4013ff98623..000000000000
--- a/drivers/input/gameport/cs461x.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- The all defines and part of code (such as cs461x_*) are
- contributed from ALSA 0.5.8 sources.
- See http://www.alsa-project.org/ for sources
-
- Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin");
-MODULE_LICENSE("GPL");
-
-/*
- These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT 0x00000480
-#define BA0_JSCTL 0x00000484
-#define BA0_JSC1 0x00000488
-#define BA0_JSC2 0x0000048C
-#define BA0_JSIO 0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX 0x00000001
-#define JSPT_CAY 0x00000002
-#define JSPT_CBX 0x00000004
-#define JSPT_CBY 0x00000008
-#define JSPT_BA1 0x00000010
-#define JSPT_BA2 0x00000020
-#define JSPT_BB1 0x00000040
-#define JSPT_BB2 0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK 0x00000003
-#define JSCTL_SP_SLOW 0x00000000
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001
-#define JSCTL_SP_MEDIUM_FAST 0x00000002
-#define JSCTL_SP_FAST 0x00000003
-#define JSCTL_ARE 0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK 0x0000FFFF
-#define JSC1_X1V_MASK 0xFFFF0000
-#define JSC1_Y1V_SHIFT 0
-#define JSC1_X1V_SHIFT 16
-#define JSC2_Y2V_MASK 0x0000FFFF
-#define JSC2_X2V_MASK 0xFFFF0000
-#define JSC2_Y2V_SHIFT 0
-#define JSC2_X2V_SHIFT 16
-
-/* JS GPIO */
-
-#define JSIO_DAX 0x00000001
-#define JSIO_DAY 0x00000002
-#define JSIO_DBX 0x00000004
-#define JSIO_DBY 0x00000008
-#define JSIO_AXOE 0x00000010
-#define JSIO_AYOE 0x00000020
-#define JSIO_BXOE 0x00000040
-#define JSIO_BYOE 0x00000080
-
-/*
- The card initialization code is obfuscated; the module cs461x
- need to be loaded after ALSA modules initialized and something
- played on the CS 4610 chip (see sources for details of CS4610
- initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE 0x2000
-#define CS461X_BA1_DATA0_SIZE 0x3000
-#define CS461X_BA1_DATA1_SIZE 0x3800
-#define CS461X_BA1_PRG_SIZE 0x7000
-#define CS461X_BA1_REG_SIZE 0x0100
-
-#define BA1_SP_DMEM0 0x00000000
-#define BA1_SP_DMEM1 0x00010000
-#define BA1_SP_PMEM 0x00020000
-#define BA1_SP_REG 0x00030000
-
-#define BA1_DWORD_SIZE (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT 3
-
-/*
- Only one CS461x card is still suppoted; the code requires
- redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int __iomem *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
- struct {
- unsigned int __iomem *data0;
- unsigned int __iomem *data1;
- unsigned int __iomem *pmem;
- unsigned int __iomem *reg;
- } name;
- unsigned int __iomem *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
- writel(val, &ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
- return readl(&ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff]);
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
- writel(val, &ba0[reg >> 2]);
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
- return readl(&ba0[reg >> 2]);
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
- struct gameport *port = pci_get_drvdata(pdev);
-
- if (port)
- gameport_unregister_port(port);
-
- if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
- if (ba1.name.data0) iounmap(ba1.name.data0);
- if (ba1.name.data1) iounmap(ba1.name.data1);
- if (ba1.name.pmem) iounmap(ba1.name.pmem);
- if (ba1.name.reg) iounmap(ba1.name.reg);
-#endif
- return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
- cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
- return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- unsigned js1, js2, jst;
-
- js1 = cs461x_peekBA0(BA0_JSC1);
- js2 = cs461x_peekBA0(BA0_JSC2);
- jst = cs461x_peekBA0(BA0_JSPT);
-
- *buttons = (~jst >> 4) & 0x0F;
-
- axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
- axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
- axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
- axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
- for(jst=0;jst<4;++jst)
- if(axes[jst]==0xFFFF) axes[jst] = -1;
- return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- case GAMEPORT_MODE_RAW:
- return 0;
- default:
- return -1;
- }
- return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] = {
- { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
- { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
- { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
- struct gameport* port;
-
- rc = pci_enable_device(pdev);
- if (rc) {
- printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
- pdev->bus->number, pdev->devfn, rc);
- return rc;
- }
-
- ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
- ba1_addr = pci_resource_start(pdev, 1);
-#endif
- if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
- || ba1_addr == 0 || ba1_addr == ~0
-#endif
- ) {
- printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
- printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
- ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
- ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
- ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
- ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
- if (ba0 == NULL || ba1.name.data0 == NULL ||
- ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
- ba1.name.reg == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#else
- if (ba0 == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#endif
-
- if (!(port = gameport_allocate_port())) {
- printk(KERN_ERR "cs461x: Memory allocation failed\n");
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- pci_set_drvdata(pdev, port);
-
- port->open = cs461x_gameport_open;
- port->trigger = cs461x_gameport_trigger;
- port->read = cs461x_gameport_read;
- port->cooked_read = cs461x_gameport_cooked_read;
-
- gameport_set_name(port, "CS416x");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(pdev));
- port->dev.parent = &pdev->dev;
-
- cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
- cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
- cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
- .name = "CS461x_gameport",
- .id_table = cs461x_pci_tbl,
- .probe = cs461x_pci_probe,
- .remove = __devexit_p(cs461x_pci_remove),
-};
-
-static int __init cs461x_init(void)
-{
- return pci_register_driver(&cs461x_pci_driver);
-}
-
-static void __exit cs461x_exit(void)
-{
- pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(cs461x_init);
-module_exit(cs461x_exit);
-
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
index e152d0fa0cdd..ab09cf4093e3 100644
--- a/drivers/input/gameport/gameport.c
+++ b/drivers/input/gameport/gameport.c
@@ -17,11 +17,10 @@
#include <linux/init.h>
#include <linux/gameport.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/kthread.h>
/*#include <asm/io.h>*/
@@ -61,12 +60,13 @@ static void gameport_disconnect_port(struct gameport *gameport);
#if defined(__i386__)
+#include <asm/i8253.h>
+
#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193182/HZ:0))
#define GET_TIME(x) do { x = get_time_pit(); } while (0)
static unsigned int get_time_pit(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
@@ -238,8 +238,7 @@ struct gameport_event {
static DEFINE_SPINLOCK(gameport_event_lock); /* protects gameport_event_list */
static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
-static DECLARE_COMPLETION(gameport_exited);
-static int gameport_pid;
+static struct task_struct *gameport_task;
static void gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
@@ -250,12 +249,12 @@ static void gameport_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&gameport_event_lock, flags);
/*
- * Scan event list for the other events for the same gameport port,
+ * Scan event list for the other events for the same gameport port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &gameport_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -432,20 +431,15 @@ static struct gameport *gameport_get_pending_child(struct gameport *parent)
static int gameport_thread(void *nothing)
{
- lock_kernel();
- daemonize("kgameportd");
- allow_signal(SIGTERM);
-
do {
gameport_handle_events();
- wait_event_interruptible(gameport_wait, !list_empty(&gameport_event_list));
- try_to_freeze(PF_FREEZE);
- } while (!signal_pending(current));
+ wait_event_interruptible(gameport_wait,
+ kthread_should_stop() || !list_empty(&gameport_event_list));
+ try_to_freeze();
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "gameport: kgameportd exiting\n");
-
- unlock_kernel();
- complete_and_exit(&gameport_exited, 0);
+ return 0;
}
@@ -773,9 +767,10 @@ void gameport_close(struct gameport *gameport)
static int __init gameport_init(void)
{
- if (!(gameport_pid = kernel_thread(gameport_thread, NULL, CLONE_KERNEL))) {
+ gameport_task = kthread_run(gameport_thread, NULL, "kgameportd");
+ if (IS_ERR(gameport_task)) {
printk(KERN_ERR "gameport: Failed to start kgameportd\n");
- return -1;
+ return PTR_ERR(gameport_task);
}
gameport_bus.dev_attrs = gameport_device_attrs;
@@ -789,8 +784,7 @@ static int __init gameport_init(void)
static void __exit gameport_exit(void)
{
bus_unregister(&gameport_bus);
- kill_proc(gameport_pid, SIGTERM, 1);
- wait_for_completion(&gameport_exited);
+ kthread_stop(gameport_task);
}
module_init(gameport_init);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
index 7c5c6318eeb9..1ab5f2dc8a2a 100644
--- a/drivers/input/gameport/ns558.c
+++ b/drivers/input/gameport/ns558.c
@@ -258,18 +258,18 @@ static int __init ns558_init(void)
{
int i = 0;
+ if (pnp_register_driver(&ns558_pnp_driver) >= 0)
+ pnp_registered = 1;
+
/*
- * Probe ISA ports first so that PnP gets to choose free port addresses
- * not occupied by the ISA ports.
+ * Probe ISA ports after PnP, so that PnP ports that are already
+ * enabled get detected as PnP. This may be suboptimal in multi-device
+ * configurations, but saves hassle with simple setups.
*/
while (ns558_isa_portlist[i])
ns558_isa_probe(ns558_isa_portlist[i++]);
- if (pnp_register_driver(&ns558_pnp_driver) >= 0)
- pnp_registered = 1;
-
-
return (list_empty(&ns558_list) && !pnp_registered) ? -ENODEV : 0;
}
diff --git a/drivers/input/gameport/vortex.c b/drivers/input/gameport/vortex.c
deleted file mode 100644
index 36b0309c8bf6..000000000000
--- a/drivers/input/gameport/vortex.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * $Id: vortex.c,v 1.5 2002/07/01 15:39:30 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Raymond Ingles
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport 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
- * 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 <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/gameport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_DESCRIPTION("Aureal Vortex and Vortex2 gameport driver");
-MODULE_LICENSE("GPL");
-
-#define VORTEX_GCR 0x0c /* Gameport control register */
-#define VORTEX_LEG 0x08 /* Legacy port location */
-#define VORTEX_AXD 0x10 /* Axes start */
-#define VORTEX_DATA_WAIT 20 /* 20 ms */
-
-struct vortex {
- struct gameport *gameport;
- struct pci_dev *dev;
- unsigned char __iomem *base;
- unsigned char __iomem *io;
-};
-
-static unsigned char vortex_read(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- return readb(vortex->io + VORTEX_LEG);
-}
-
-static void vortex_trigger(struct gameport *gameport)
-{
- struct vortex *vortex = gameport->port_data;
- writeb(0xff, vortex->io + VORTEX_LEG);
-}
-
-static int vortex_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct vortex *vortex = gameport->port_data;
- int i;
-
- *buttons = (~readb(vortex->base + VORTEX_LEG) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = readw(vortex->io + VORTEX_AXD + i * sizeof(u32));
- if (axes[i] == 0x1fff) axes[i] = -1;
- }
-
- return 0;
-}
-
-static int vortex_open(struct gameport *gameport, int mode)
-{
- struct vortex *vortex = gameport->port_data;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- writeb(0x40, vortex->io + VORTEX_GCR);
- msleep(VORTEX_DATA_WAIT);
- return 0;
- case GAMEPORT_MODE_RAW:
- writeb(0x00, vortex->io + VORTEX_GCR);
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit vortex_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct vortex *vortex;
- struct gameport *port;
- int i;
-
- vortex = kcalloc(1, sizeof(struct vortex), GFP_KERNEL);
- port = gameport_allocate_port();
- if (!vortex || !port) {
- printk(KERN_ERR "vortex: Memory allocation failed.\n");
- kfree(vortex);
- gameport_free_port(port);
- return -ENOMEM;
- }
-
- for (i = 0; i < 6; i++)
- if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
- break;
-
- pci_enable_device(dev);
-
- vortex->dev = dev;
- vortex->gameport = port;
- vortex->base = ioremap(pci_resource_start(vortex->dev, i),
- pci_resource_len(vortex->dev, i));
- vortex->io = vortex->base + id->driver_data;
-
- pci_set_drvdata(dev, vortex);
-
- port->port_data = vortex;
- port->fuzz = 64;
-
- gameport_set_name(port, "AU88x0");
- gameport_set_phys(port, "pci%s/gameport0", pci_name(dev));
- port->dev.parent = &dev->dev;
- port->read = vortex_read;
- port->trigger = vortex_trigger;
- port->cooked_read = vortex_cooked_read;
- port->open = vortex_open;
-
- gameport_register_port(port);
-
- return 0;
-}
-
-static void __devexit vortex_remove(struct pci_dev *dev)
-{
- struct vortex *vortex = pci_get_drvdata(dev);
-
- gameport_unregister_port(vortex->gameport);
- iounmap(vortex->base);
- kfree(vortex);
-}
-
-static struct pci_device_id vortex_id_table[] = {
- { 0x12eb, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x11000 },
- { 0x12eb, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0x28800 },
- { 0 }
-};
-
-static struct pci_driver vortex_driver = {
- .name = "vortex_gameport",
- .id_table = vortex_id_table,
- .probe = vortex_probe,
- .remove = __devexit_p(vortex_remove),
-};
-
-static int __init vortex_init(void)
-{
- return pci_register_driver(&vortex_driver);
-}
-
-static void __exit vortex_exit(void)
-{
- pci_unregister_driver(&vortex_driver);
-}
-
-module_init(vortex_init);
-module_exit(vortex_exit);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 83c77c990dda..7c4b4d37b3e6 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -219,10 +219,24 @@ void input_release_device(struct input_handle *handle)
int input_open_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+ int err;
+
+ err = down_interruptible(&dev->sem);
+ if (err)
+ return err;
+
handle->open++;
- if (handle->dev->open)
- return handle->dev->open(handle->dev);
- return 0;
+
+ if (!dev->users++ && dev->open)
+ err = dev->open(dev);
+
+ if (err)
+ handle->open--;
+
+ up(&dev->sem);
+
+ return err;
}
int input_flush_device(struct input_handle* handle, struct file* file)
@@ -235,10 +249,17 @@ int input_flush_device(struct input_handle* handle, struct file* file)
void input_close_device(struct input_handle *handle)
{
+ struct input_dev *dev = handle->dev;
+
input_release_device(handle);
- if (handle->dev->close)
- handle->dev->close(handle->dev);
+
+ down(&dev->sem);
+
+ if (!--dev->users && dev->close)
+ dev->close(dev);
handle->open--;
+
+ up(&dev->sem);
}
static void input_link_handle(struct input_handle *handle)
@@ -415,6 +436,8 @@ void input_register_device(struct input_dev *dev)
set_bit(EV_SYN, dev->evbit);
+ init_MUTEX(&dev->sem);
+
/*
* If delay and period are pre-set by the driver, then autorepeating
* is handled by the driver itself and we don't do it in input.c.
@@ -674,6 +697,8 @@ static int input_handlers_read(char *buf, char **start, off_t pos, int count, in
return (count > cnt) ? cnt : count;
}
+static struct file_operations input_fileops;
+
static int __init input_proc_init(void)
{
struct proc_dir_entry *entry;
@@ -688,6 +713,8 @@ static int __init input_proc_init(void)
return -ENOMEM;
}
entry->owner = THIS_MODULE;
+ input_fileops = *entry->proc_fops;
+ entry->proc_fops = &input_fileops;
entry->proc_fops->poll = input_devices_poll;
entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL);
if (entry == NULL) {
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c
index 39775fc380c7..ff8e1bbd0e13 100644
--- a/drivers/input/joydev.c
+++ b/drivers/input/joydev.c
@@ -285,48 +285,33 @@ static unsigned int joydev_poll(struct file *file, poll_table *wait)
(POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR));
}
-static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp)
{
- struct joydev_list *list = file->private_data;
- struct joydev *joydev = list->joydev;
struct input_dev *dev = joydev->handle.dev;
- void __user *argp = (void __user *)arg;
int i, j;
- if (!joydev->exist) return -ENODEV;
-
switch (cmd) {
case JS_SET_CAL:
return copy_from_user(&joydev->glue.JS_CORR, argp,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_GET_CAL:
return copy_to_user(argp, &joydev->glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
+ sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0;
case JS_SET_TIMEOUT:
- return get_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
+ return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JS_GET_TIMEOUT:
- return put_user(joydev->glue.JS_TIMEOUT, (int __user *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
- case JS_SET_ALL:
- return copy_from_user(&joydev->glue, argp,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user(argp, &joydev->glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
+ return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp);
case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 __user *) arg);
+ return put_user(JS_VERSION, (__u32 __user *) argp);
case JSIOCGAXES:
- return put_user(joydev->nabs, (__u8 __user *) arg);
+ return put_user(joydev->nabs, (__u8 __user *) argp);
case JSIOCGBUTTONS:
- return put_user(joydev->nkey, (__u8 __user *) arg);
+ return put_user(joydev->nkey, (__u8 __user *) argp);
case JSIOCSCORR:
if (copy_from_user(joydev->corr, argp,
- sizeof(struct js_corr) * joydev->nabs))
+ sizeof(joydev->corr[0]) * joydev->nabs))
return -EFAULT;
for (i = 0; i < joydev->nabs; i++) {
j = joydev->abspam[i];
@@ -335,7 +320,7 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return 0;
case JSIOCGCORR:
return copy_to_user(argp, joydev->corr,
- sizeof(struct js_corr) * joydev->nabs) ? -EFAULT : 0;
+ sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0;
case JSIOCSAXMAP:
if (copy_from_user(joydev->abspam, argp, sizeof(__u8) * (ABS_MAX + 1)))
return -EFAULT;
@@ -371,6 +356,84 @@ static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
}
+#ifdef CONFIG_COMPAT
+static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+ s32 tmp32;
+ struct JS_DATA_SAVE_TYPE_32 ds32;
+ int err;
+
+ if (!joydev->exist) return -ENODEV;
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ err = get_user(tmp32, (s32 __user *) arg);
+ if (err == 0)
+ joydev->glue.JS_TIMELIMIT = tmp32;
+ break;
+ case JS_GET_TIMELIMIT:
+ tmp32 = joydev->glue.JS_TIMELIMIT;
+ err = put_user(tmp32, (s32 __user *) arg);
+ break;
+
+ case JS_SET_ALL:
+ err = copy_from_user(&ds32, argp,
+ sizeof(ds32)) ? -EFAULT : 0;
+ if (err == 0) {
+ joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT;
+ joydev->glue.BUSY = ds32.BUSY;
+ joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME;
+ joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT;
+ joydev->glue.JS_SAVE = ds32.JS_SAVE;
+ joydev->glue.JS_CORR = ds32.JS_CORR;
+ }
+ break;
+
+ case JS_GET_ALL:
+ ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT;
+ ds32.BUSY = joydev->glue.BUSY;
+ ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME;
+ ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT;
+ ds32.JS_SAVE = joydev->glue.JS_SAVE;
+ ds32.JS_CORR = joydev->glue.JS_CORR;
+
+ err = copy_to_user(argp, &ds32,
+ sizeof(ds32)) ? -EFAULT : 0;
+ break;
+
+ default:
+ err = joydev_ioctl_common(joydev, cmd, argp);
+ }
+ return err;
+}
+#endif /* CONFIG_COMPAT */
+
+static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct joydev_list *list = file->private_data;
+ struct joydev *joydev = list->joydev;
+ void __user *argp = (void __user *)arg;
+
+ if (!joydev->exist) return -ENODEV;
+
+ switch(cmd) {
+ case JS_SET_TIMELIMIT:
+ return get_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_GET_TIMELIMIT:
+ return put_user(joydev->glue.JS_TIMELIMIT, (long __user *) arg);
+ case JS_SET_ALL:
+ return copy_from_user(&joydev->glue, argp,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ case JS_GET_ALL:
+ return copy_to_user(argp, &joydev->glue,
+ sizeof(joydev->glue)) ? -EFAULT : 0;
+ default:
+ return joydev_ioctl_common(joydev, cmd, argp);
+ }
+}
+
static struct file_operations joydev_fops = {
.owner = THIS_MODULE,
.read = joydev_read,
@@ -379,6 +442,9 @@ static struct file_operations joydev_fops = {
.open = joydev_open,
.release = joydev_release,
.ioctl = joydev_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = joydev_compat_ioctl,
+#endif
.fasync = joydev_fasync,
};
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
index ad39fe4bf35f..bf34f75b9467 100644
--- a/drivers/input/joystick/a3d.c
+++ b/drivers/input/joystick/a3d.c
@@ -185,7 +185,7 @@ static void a3d_poll(struct gameport *gameport)
a3d->reads++;
if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length ||
data[0] != a3d->mode || a3d_csum(data, a3d->length))
- a3d->bads++;
+ a3d->bads++;
else
a3d_read(a3d, data);
}
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index 83f6dafc1716..265962956c63 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -82,7 +82,7 @@ static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
@@ -183,7 +183,7 @@ static void adi_move_bits(struct adi_port *port, int length)
int i;
struct adi *adi = port->adi;
- adi[0].idx = adi[1].idx = 0;
+ adi[0].idx = adi[1].idx = 0;
if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
index cf36ca9b92f3..033456bb9fe0 100644
--- a/drivers/input/joystick/amijoy.c
+++ b/drivers/input/joystick/amijoy.c
@@ -51,7 +51,8 @@ MODULE_PARM_DESC(map, "Map of attached joysticks in form of <a>,<b> (default is
__obsolete_setup("amijoy=");
-static int amijoy_used[2] = { 0, 0 };
+static int amijoy_used;
+static DECLARE_MUTEX(amijoy_sem);
static struct input_dev amijoy_dev[2];
static char *amijoy_phys[2] = { "amijoy/input0", "amijoy/input1" };
@@ -84,26 +85,30 @@ static irqreturn_t amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
static int amijoy_open(struct input_dev *dev)
{
- int *used = dev->private;
+ int err;
- if ((*used)++)
- return 0;
+ err = down_interruptible(&amijoy_sem);
+ if (err)
+ return err;
- if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
- (*used)--;
+ if (!amijoy_used && request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", amijoy_interrupt)) {
printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
- return -EBUSY;
+ err = -EBUSY;
+ goto out;
}
- return 0;
+ amijoy_used++;
+out:
+ up(&amijoy_sem);
+ return err;
}
static void amijoy_close(struct input_dev *dev)
{
- int *used = dev->private;
-
- if (!--(*used))
+ down(&amijoysem);
+ if (!--amijoy_used)
free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+ up(&amijoy_sem);
}
static int __init amijoy_init(void)
@@ -138,8 +143,6 @@ static int __init amijoy_init(void)
amijoy_dev[i].id.product = 0x0003;
amijoy_dev[i].id.version = 0x0100;
- amijoy_dev[i].private = amijoy_used + i;
-
input_register_device(amijoy_dev + i);
printk(KERN_INFO "input: %s at joy%ddat\n", amijoy_name, i);
}
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
index 504b7d550567..c3a5739030c3 100644
--- a/drivers/input/joystick/analog.c
+++ b/drivers/input/joystick/analog.c
@@ -140,12 +140,14 @@ struct analog_port {
*/
#ifdef __i386__
+
+#include <asm/i8253.h>
+
#define GET_TIME(x) do { if (cpu_has_tsc) rdtscl(x); else x = get_time_pit(); } while (0)
#define DELTA(x,y) (cpu_has_tsc ? ((y) - (x)) : ((x) - (y) + ((x) < (y) ? CLOCK_TICK_RATE / HZ : 0)))
#define TIME_NAME (cpu_has_tsc?"TSC":"PIT")
static unsigned int get_time_pit(void)
{
- extern spinlock_t i8253_lock;
unsigned long flags;
unsigned int count;
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
index cfdd3acf06a1..fbd3eed07f90 100644
--- a/drivers/input/joystick/db9.c
+++ b/drivers/input/joystick/db9.c
@@ -87,7 +87,7 @@ __obsolete_setup("db9_3=");
#define DB9_NORMAL 0x0a
#define DB9_NOSELECT 0x08
-#define DB9_MAX_DEVICES 2
+#define DB9_MAX_DEVICES 2
#define DB9_GENESIS6_DELAY 14
#define DB9_REFRESH_TIME HZ/100
@@ -98,6 +98,7 @@ struct db9 {
struct pardevice *pd;
int mode;
int used;
+ struct semaphore sem;
char phys[2][32];
};
@@ -503,6 +504,11 @@ static int db9_open(struct input_dev *dev)
{
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ int err;
+
+ err = down_interruptible(&db9->sem);
+ if (err)
+ return err;
if (!db9->used++) {
parport_claim(db9->pd);
@@ -514,6 +520,7 @@ static int db9_open(struct input_dev *dev)
mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
}
+ up(&db9->sem);
return 0;
}
@@ -522,12 +529,14 @@ static void db9_close(struct input_dev *dev)
struct db9 *db9 = dev->private;
struct parport *port = db9->pd->port;
+ down(&db9->sem);
if (!--db9->used) {
- del_timer(&db9->timer);
+ del_timer_sync(&db9->timer);
parport_write_control(port, 0x00);
parport_data_forward(port);
parport_release(db9->pd);
}
+ up(&db9->sem);
}
static struct db9 __init *db9_probe(int *config, int nargs)
@@ -563,12 +572,12 @@ static struct db9 __init *db9_probe(int *config, int nargs)
}
}
- if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL))) {
+ if (!(db9 = kcalloc(1, sizeof(struct db9), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(db9, 0, sizeof(struct db9));
+ init_MUTEX(&db9->sem);
db9->mode = config[1];
init_timer(&db9->timer);
db9->timer.data = (long) db9;
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
index 8732f52bdd08..95bbdd302aad 100644
--- a/drivers/input/joystick/gamecon.c
+++ b/drivers/input/joystick/gamecon.c
@@ -1,12 +1,12 @@
/*
* NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux
*
- * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
+ * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org>
*
* Based on the work of:
- * Andree Borrmann John Dahlstrom
- * David Kuder Nathan Hand
+ * Andree Borrmann John Dahlstrom
+ * David Kuder Nathan Hand
*/
/*
@@ -81,6 +81,7 @@ struct gc {
struct timer_list timer;
unsigned char pads[GC_MAX + 1];
int used;
+ struct semaphore sem;
char phys[5][32];
};
@@ -433,7 +434,7 @@ static void gc_timer(unsigned long private)
gc_psx_read_packet(gc, data_psx, data);
for (i = 0; i < 5; i++) {
- switch (data[i]) {
+ switch (data[i]) {
case GC_PSX_RUMBLE:
@@ -503,22 +504,33 @@ static void gc_timer(unsigned long private)
static int gc_open(struct input_dev *dev)
{
struct gc *gc = dev->private;
+ int err;
+
+ err = down_interruptible(&gc->sem);
+ if (err)
+ return err;
+
if (!gc->used++) {
parport_claim(gc->pd);
parport_write_control(gc->pd->port, 0x04);
mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
}
+
+ up(&gc->sem);
return 0;
}
static void gc_close(struct input_dev *dev)
{
struct gc *gc = dev->private;
+
+ down(&gc->sem);
if (!--gc->used) {
- del_timer(&gc->timer);
+ del_timer_sync(&gc->timer);
parport_write_control(gc->pd->port, 0x00);
parport_release(gc->pd);
}
+ up(&gc->sem);
}
static struct gc __init *gc_probe(int *config, int nargs)
@@ -542,11 +554,12 @@ static struct gc __init *gc_probe(int *config, int nargs)
return NULL;
}
- if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL))) {
+ if (!(gc = kcalloc(1, sizeof(struct gc), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(gc, 0, sizeof(struct gc));
+
+ init_MUTEX(&gc->sem);
gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
index ad13f09a4e71..7d969420066c 100644
--- a/drivers/input/joystick/gf2k.c
+++ b/drivers/input/joystick/gf2k.c
@@ -329,7 +329,7 @@ static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv)
for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
- gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+ gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
gf2k->dev.absmin[gf2k_abs[i]] = 32;
gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
diff --git a/drivers/input/joystick/grip_mp.c b/drivers/input/joystick/grip_mp.c
index 42e5005d621f..0da7bd133ccf 100644
--- a/drivers/input/joystick/grip_mp.c
+++ b/drivers/input/joystick/grip_mp.c
@@ -171,7 +171,7 @@ static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *pa
*packet = 0;
raw_data = gameport_read(gameport);
if (raw_data & 1)
- return IO_RETRY;
+ return IO_RETRY;
for (i = 0; i < 64; i++) {
raw_data = gameport_read(gameport);
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c
index 028f3513629a..e31b7b93fde2 100644
--- a/drivers/input/joystick/iforce/iforce-main.c
+++ b/drivers/input/joystick/iforce/iforce-main.c
@@ -78,6 +78,7 @@ static struct iforce_device iforce_device[] = {
{ 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //?
{ 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //?
+ { 0x06f8, 0x0004, "Gullemot Jet Leader 3D", btn_joystick, abs_joystick, ff_iforce }, //?
{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
};
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c
index 617c0b0e5a39..6369a24684fe 100644
--- a/drivers/input/joystick/iforce/iforce-usb.c
+++ b/drivers/input/joystick/iforce/iforce-usb.c
@@ -229,6 +229,7 @@ static struct usb_device_id iforce_usb_ids [] = {
{ USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */
{ USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
{ USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */
+ { USB_DEVICE(0x06f8, 0xa302) }, /* Guillemot Jet Leader 3D */
{ } /* Terminating entry */
};
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
index ec0a2a64d49c..a436f2220856 100644
--- a/drivers/input/joystick/spaceball.c
+++ b/drivers/input/joystick/spaceball.c
@@ -4,8 +4,8 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
- * Joseph Krahn
+ * David Thompson
+ * Joseph Krahn
*/
/*
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
index 874367bfab08..01fd2e4791ae 100644
--- a/drivers/input/joystick/spaceorb.c
+++ b/drivers/input/joystick/spaceorb.c
@@ -4,7 +4,7 @@
* Copyright (c) 1999-2001 Vojtech Pavlik
*
* Based on the work of:
- * David Thompson
+ * David Thompson
*/
/*
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
index aaee52ceb920..9eb9954cac6e 100644
--- a/drivers/input/joystick/tmdc.c
+++ b/drivers/input/joystick/tmdc.c
@@ -79,7 +79,7 @@ static short tmdc_btn_pad[TMDC_BTN] =
{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
static short tmdc_btn_joy[TMDC_BTN] =
{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+ BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
static short tmdc_btn_fm[TMDC_BTN] =
{ BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
static short tmdc_btn_at[TMDC_BTN] =
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
index dd88b9cb49fa..28100d461cb7 100644
--- a/drivers/input/joystick/turbografx.c
+++ b/drivers/input/joystick/turbografx.c
@@ -84,6 +84,7 @@ static struct tgfx {
char phys[7][32];
int sticks;
int used;
+ struct semaphore sem;
} *tgfx_base[3];
/*
@@ -99,7 +100,7 @@ static void tgfx_timer(unsigned long private)
for (i = 0; i < 7; i++)
if (tgfx->sticks & (1 << i)) {
- dev = tgfx->dev + i;
+ dev = tgfx->dev + i;
parport_write_data(tgfx->pd->port, ~(1 << i));
data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
@@ -122,23 +123,34 @@ static void tgfx_timer(unsigned long private)
static int tgfx_open(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!tgfx->used++) {
+ struct tgfx *tgfx = dev->private;
+ int err;
+
+ err = down_interruptible(&tgfx->sem);
+ if (err)
+ return err;
+
+ if (!tgfx->used++) {
parport_claim(tgfx->pd);
parport_write_control(tgfx->pd->port, 0x04);
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
}
- return 0;
+
+ up(&tgfx->sem);
+ return 0;
}
static void tgfx_close(struct input_dev *dev)
{
- struct tgfx *tgfx = dev->private;
- if (!--tgfx->used) {
- del_timer(&tgfx->timer);
+ struct tgfx *tgfx = dev->private;
+
+ down(&tgfx->sem);
+ if (!--tgfx->used) {
+ del_timer_sync(&tgfx->timer);
parport_write_control(tgfx->pd->port, 0x00);
- parport_release(tgfx->pd);
+ parport_release(tgfx->pd);
}
+ up(&tgfx->sem);
}
/*
@@ -166,11 +178,12 @@ static struct tgfx __init *tgfx_probe(int *config, int nargs)
return NULL;
}
- if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL))) {
+ if (!(tgfx = kcalloc(1, sizeof(struct tgfx), GFP_KERNEL))) {
parport_put_port(pp);
return NULL;
}
- memset(tgfx, 0, sizeof(struct tgfx));
+
+ init_MUTEX(&tgfx->sem);
tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index 82fad9a23ace..4d4985b59abf 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -227,7 +227,7 @@ static ssize_t atkbd_do_set_##_name(struct device *d, struct device_attribute *a
{ \
return atkbd_attr_set_helper(d, b, s, atkbd_set_##_name); \
} \
-static struct device_attribute atkbd_attr_##_name = \
+static struct device_attribute atkbd_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, atkbd_do_show_##_name, atkbd_do_set_##_name);
ATKBD_DEFINE_ATTR(extra);
@@ -388,7 +388,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
value = atkbd->release ? 0 :
(1 + (!atkbd->softrepeat && test_bit(atkbd->keycode[code], atkbd->dev.key)));
- switch (value) { /* Workaround Toshiba laptop multiple keypress */
+ switch (value) { /* Workaround Toshiba laptop multiple keypress */
case 0:
atkbd->last = 0;
break;
@@ -894,7 +894,7 @@ static int atkbd_reconnect(struct serio *serio)
if (atkbd->write) {
param[0] = (test_bit(LED_SCROLLL, atkbd->dev.led) ? 1 : 0)
| (test_bit(LED_NUML, atkbd->dev.led) ? 2 : 0)
- | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
+ | (test_bit(LED_CAPSL, atkbd->dev.led) ? 4 : 0);
if (atkbd_probe(atkbd))
return -1;
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c
index 0f1220a0ceb5..a8551711e8d6 100644
--- a/drivers/input/keyboard/corgikbd.c
+++ b/drivers/input/keyboard/corgikbd.c
@@ -39,6 +39,7 @@
#define CORGI_KEY_CALENDER KEY_F1
#define CORGI_KEY_ADDRESS KEY_F2
#define CORGI_KEY_FN KEY_F3
+#define CORGI_KEY_CANCEL KEY_F4
#define CORGI_KEY_OFF KEY_SUSPEND
#define CORGI_KEY_EXOK KEY_F5
#define CORGI_KEY_EXCANCEL KEY_F6
@@ -46,6 +47,7 @@
#define CORGI_KEY_EXJOGUP KEY_F8
#define CORGI_KEY_JAP1 KEY_LEFTCTRL
#define CORGI_KEY_JAP2 KEY_LEFTALT
+#define CORGI_KEY_MAIL KEY_F10
#define CORGI_KEY_OK KEY_F11
#define CORGI_KEY_MENU KEY_F12
#define CORGI_HINGE_0 KEY_KP0
@@ -59,8 +61,8 @@ static unsigned char corgikbd_keycode[NR_SCANCODES] = {
KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */
CORGI_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */
CORGI_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, 0, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, /* 65-80 */
- KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
- KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
+ CORGI_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, 0, CORGI_KEY_FN, 0, 0, 0, 0, /* 81-96 */
+ KEY_SYSRQ, CORGI_KEY_JAP1, CORGI_KEY_JAP2, CORGI_KEY_CANCEL, CORGI_KEY_OK, CORGI_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0, /* 97-112 */
CORGI_KEY_OFF, CORGI_KEY_EXOK, CORGI_KEY_EXCANCEL, CORGI_KEY_EXJOGDOWN, CORGI_KEY_EXJOGUP, 0, 0, 0, 0, 0, 0, 0, /* 113-124 */
CORGI_HINGE_0, CORGI_HINGE_1, CORGI_HINGE_2 /* 125-127 */
};
diff --git a/drivers/input/keyboard/lkkbd.c b/drivers/input/keyboard/lkkbd.c
index 2694ff2b5beb..098963c7cdd6 100644
--- a/drivers/input/keyboard/lkkbd.c
+++ b/drivers/input/keyboard/lkkbd.c
@@ -15,10 +15,10 @@
* information given below, I will _not_ be liable!
*
* RJ10 pinout: To DE9: Or DB25:
- * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
- * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
- * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
- * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
+ * 1 - RxD <----> Pin 3 (TxD) <-> Pin 2 (TxD)
+ * 2 - GND <----> Pin 5 (GND) <-> Pin 7 (GND)
+ * 4 - TxD <----> Pin 2 (RxD) <-> Pin 3 (RxD)
+ * 3 - +12V (from HDD drive connector), DON'T connect to DE9 or DB25!!!
*
* Pin numbers for DE9 and DB25 are noted on the plug (quite small:). For
* RJ10, it's like this:
diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
index d3e9dd6a13cd..8935290256b3 100644
--- a/drivers/input/keyboard/locomokbd.c
+++ b/drivers/input/keyboard/locomokbd.c
@@ -42,7 +42,7 @@ MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>");
MODULE_DESCRIPTION("LoCoMo keyboard driver");
MODULE_LICENSE("GPL");
-#define LOCOMOKBD_NUMKEYS 128
+#define LOCOMOKBD_NUMKEYS 128
#define KEY_ACTIVITY KEY_F16
#define KEY_CONTACT KEY_F18
@@ -61,7 +61,7 @@ static unsigned char locomokbd_keycode[LOCOMOKBD_NUMKEYS] = {
KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */
0, 0, KEY_DOT, 0, KEY_COMMA, KEY_N, KEY_B, KEY_C, KEY_Z, KEY_A, /* 100 - 109 */
KEY_LEFTSHIFT, KEY_TAB, KEY_LEFTCTRL, 0, 0, 0, 0, 0, 0, 0, /* 110 - 119 */
- KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
+ KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */
};
#define KB_ROWS 16
@@ -82,7 +82,7 @@ struct locomokbd {
struct locomo_dev *ldev;
unsigned long base;
spinlock_t lock;
-
+
struct timer_list timer;
};
@@ -95,7 +95,7 @@ static inline void locomokbd_charge_all(unsigned long membase)
static inline void locomokbd_activate_all(unsigned long membase)
{
unsigned long r;
-
+
locomo_writel(0, membase + LOCOMO_KSC);
r = locomo_readl(membase + LOCOMO_KIC);
r &= 0xFEFF;
@@ -127,7 +127,7 @@ static inline void locomokbd_reset_col(unsigned long membase, int col)
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
-static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
+static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *regs)
{
unsigned int row, col, rowd, scancode;
unsigned long flags;
@@ -138,7 +138,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
if (regs)
input_regs(&locomokbd->input, regs);
-
+
locomokbd_charge_all(membase);
num_pressed = 0;
@@ -146,9 +146,9 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
locomokbd_activate_col(membase, col);
udelay(KB_DELAY);
-
+
rowd = ~locomo_readl(membase + LOCOMO_KIB);
- for (row = 0; row < KB_ROWS; row++ ) {
+ for (row = 0; row < KB_ROWS; row++) {
scancode = SCANCODE(col, row);
if (rowd & KB_ROWMASK(row)) {
num_pressed += 1;
@@ -170,7 +170,7 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd, struct pt_regs *
spin_unlock_irqrestore(&locomokbd->lock, flags);
}
-/*
+/*
* LoCoMo keyboard interrupt handler.
*/
static irqreturn_t locomokbd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
@@ -205,8 +205,8 @@ static int locomokbd_probe(struct locomo_dev *dev)
memset(locomokbd, 0, sizeof(struct locomokbd));
/* try and claim memory region */
- if (!request_mem_region((unsigned long) dev->mapbase,
- dev->length,
+ if (!request_mem_region((unsigned long) dev->mapbase,
+ dev->length,
LOCOMO_DRIVER_NAME(dev))) {
ret = -EBUSY;
printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n");
@@ -225,7 +225,7 @@ static int locomokbd_probe(struct locomo_dev *dev)
locomokbd->timer.data = (unsigned long) locomokbd;
locomokbd->input.evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
-
+
init_input_dev(&locomokbd->input);
locomokbd->input.keycode = locomokbd->keycode;
locomokbd->input.keycodesize = sizeof(unsigned char);
@@ -271,11 +271,11 @@ free:
static int locomokbd_remove(struct locomo_dev *dev)
{
struct locomokbd *locomokbd = locomo_get_drvdata(dev);
-
+
free_irq(dev->irq[0], locomokbd);
del_timer_sync(&locomokbd->timer);
-
+
input_unregister_device(&locomokbd->input);
locomo_set_drvdata(dev, NULL);
diff --git a/drivers/input/keyboard/maple_keyb.c b/drivers/input/keyboard/maple_keyb.c
index 859ed771ee0a..eecbde294f1f 100644
--- a/drivers/input/keyboard/maple_keyb.c
+++ b/drivers/input/keyboard/maple_keyb.c
@@ -1,6 +1,6 @@
/*
* $Id: maple_keyb.c,v 1.4 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast keyboard driver
+ * SEGA Dreamcast keyboard driver
* Based on drivers/usb/usbkbd.c
*/
@@ -40,7 +40,6 @@ struct dc_kbd {
struct input_dev dev;
unsigned char new[8];
unsigned char old[8];
- int open;
};
@@ -95,22 +94,6 @@ static void dc_kbd_callback(struct mapleq *mq)
}
}
-
-static int dc_kbd_open(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open++;
- return 0;
-}
-
-
-static void dc_kbd_close(struct input_dev *dev)
-{
- struct dc_kbd *kbd = dev->private;
- kbd->open--;
-}
-
-
static int dc_kbd_connect(struct maple_device *dev)
{
int i;
@@ -133,9 +116,6 @@ static int dc_kbd_connect(struct maple_device *dev)
clear_bit(0, kbd->dev.keybit);
kbd->dev.private = kbd;
- kbd->dev.open = dc_kbd_open;
- kbd->dev.close = dc_kbd_close;
- kbd->dev.event = NULL;
kbd->dev.name = dev->product_name;
kbd->dev.id.bustype = BUS_MAPLE;
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index 158c8e845ff9..98710997aaaa 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -298,9 +298,11 @@ static int uinput_alloc_device(struct file *file, const char __user *buffer, siz
/* check if absmin/absmax/absfuzz/absflat are filled as
* told in Documentation/input/input-programming.txt */
if (test_bit(EV_ABS, dev->evbit)) {
- retval = uinput_validate_absbits(dev);
- if (retval < 0)
+ int err = uinput_validate_absbits(dev);
+ if (err < 0) {
+ retval = err;
kfree(dev->name);
+ }
}
exit:
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index a7864195806a..c4909b49337d 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -15,4 +15,4 @@ obj-$(CONFIG_MOUSE_SERIAL) += sermouse.o
obj-$(CONFIG_MOUSE_HIL) += hil_ptr.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
-psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o
+psmouse-objs := psmouse-base.o alps.o logips2pp.o synaptics.o lifebook.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index 7bf4be733e9a..a12e98158a75 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -30,10 +30,11 @@
#define ALPS_DUALPOINT 0x01
#define ALPS_WHEEL 0x02
-#define ALPS_FW_BK 0x04
+#define ALPS_FW_BK_1 0x04
#define ALPS_4BTN 0x08
#define ALPS_OLDPROTO 0x10
#define ALPS_PASS 0x20
+#define ALPS_FW_BK_2 0x40
static struct alps_model_info alps_model_data[] = {
{ { 0x33, 0x02, 0x0a }, 0x88, 0xf8, ALPS_OLDPROTO }, /* UMAX-530T */
@@ -43,11 +44,11 @@ static struct alps_model_info alps_model_data[] = {
{ { 0x63, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x28 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x02, 0x3c }, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x50 }, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
{ { 0x63, 0x02, 0x64 }, 0xf8, 0xf8, 0 },
{ { 0x63, 0x03, 0xc8 }, 0xf8, 0xf8, ALPS_PASS }, /* Dell Latitude D800 */
{ { 0x73, 0x02, 0x0a }, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, 0 },
+ { { 0x73, 0x02, 0x14 }, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
@@ -61,11 +62,11 @@ static struct alps_model_info alps_model_data[] = {
/*
* ALPS abolute Mode - new format
- *
- * byte 0: 1 ? ? ? 1 ? ? ?
+ *
+ * byte 0: 1 ? ? ? 1 ? ? ?
* byte 1: 0 x6 x5 x4 x3 x2 x1 x0
* byte 2: 0 x10 x9 x8 x7 ? fin ges
- * byte 3: 0 y9 y8 y7 1 M R L
+ * byte 3: 0 y9 y8 y7 1 M R L
* byte 4: 0 y6 y5 y4 y3 y2 y1 y0
* byte 5: 0 z6 z5 z4 z3 z2 z1 z0
*
@@ -81,11 +82,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
struct input_dev *dev = &psmouse->dev;
struct input_dev *dev2 = &priv->dev2;
int x, y, z, ges, fin, left, right, middle;
+ int back = 0, forward = 0;
input_regs(dev, regs);
if ((packet[0] & 0xc8) == 0x08) { /* 3-byte PS/2 packet */
- input_report_key(dev2, BTN_LEFT, packet[0] & 1);
+ input_report_key(dev2, BTN_LEFT, packet[0] & 1);
input_report_key(dev2, BTN_RIGHT, packet[0] & 2);
input_report_key(dev2, BTN_MIDDLE, packet[0] & 4);
input_report_rel(dev2, REL_X,
@@ -112,6 +114,18 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
z = packet[5];
}
+ if (priv->i->flags & ALPS_FW_BK_1) {
+ back = packet[2] & 4;
+ forward = packet[0] & 0x10;
+ }
+
+ if (priv->i->flags & ALPS_FW_BK_2) {
+ back = packet[3] & 4;
+ forward = packet[2] & 4;
+ if ((middle = forward && back))
+ forward = back = 0;
+ }
+
ges = packet[2] & 1;
fin = packet[2] & 2;
@@ -155,13 +169,12 @@ static void alps_process_packet(struct psmouse *psmouse, struct pt_regs *regs)
input_report_abs(dev, ABS_PRESSURE, z);
input_report_key(dev, BTN_TOOL_FINGER, z > 0);
-
if (priv->i->flags & ALPS_WHEEL)
input_report_rel(dev, REL_WHEEL, ((packet[0] >> 4) & 0x07) | ((packet[2] >> 2) & 0x08));
- if (priv->i->flags & ALPS_FW_BK) {
- input_report_key(dev, BTN_FORWARD, packet[0] & 0x10);
- input_report_key(dev, BTN_BACK, packet[2] & 0x04);
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
+ input_report_key(dev, BTN_FORWARD, forward);
+ input_report_key(dev, BTN_BACK, back);
}
input_sync(dev);
@@ -257,7 +270,6 @@ static struct alps_model_info *alps_get_model(struct psmouse *psmouse, int *vers
static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- unsigned char param[3];
int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
if (ps2_command(ps2dev, NULL, cmd) ||
@@ -267,7 +279,7 @@ static int alps_passthrough_mode(struct psmouse *psmouse, int enable)
return -1;
/* we may get 3 more bytes, just ignore them */
- ps2_command(ps2dev, param, 0x0300);
+ ps2_drain(ps2dev, 3, 100);
return 0;
}
@@ -425,7 +437,7 @@ int alps_init(struct psmouse *psmouse)
psmouse->dev.relbit[LONG(REL_WHEEL)] |= BIT(REL_WHEEL);
}
- if (priv->i->flags & ALPS_FW_BK) {
+ if (priv->i->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
psmouse->dev.keybit[LONG(BTN_FORWARD)] |= BIT(BTN_FORWARD);
psmouse->dev.keybit[LONG(BTN_BACK)] |= BIT(BTN_BACK);
}
@@ -436,8 +448,8 @@ int alps_init(struct psmouse *psmouse)
priv->dev2.id.bustype = BUS_I8042;
priv->dev2.id.vendor = 0x0002;
priv->dev2.id.product = PSMOUSE_ALPS;
- priv->dev2.id.version = 0x0000;
-
+ priv->dev2.id.version = 0x0000;
+
priv->dev2.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
priv->dev2.relbit[LONG(REL_X)] |= BIT(REL_X) | BIT(REL_Y);
priv->dev2.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
@@ -461,17 +473,15 @@ init_fail:
int alps_detect(struct psmouse *psmouse, int set_properties)
{
int version;
- struct alps_model_info *model;
+ struct alps_model_info *model;
if (!(model = alps_get_model(psmouse, &version)))
return -1;
if (set_properties) {
psmouse->vendor = "ALPS";
- if (model->flags & ALPS_DUALPOINT)
- psmouse->name = "DualPoint TouchPad";
- else
- psmouse->name = "GlidePoint";
+ psmouse->name = model->flags & ALPS_DUALPOINT ?
+ "DualPoint TouchPad" : "GlidePoint";
psmouse->model = version;
}
return 0;
diff --git a/drivers/input/mouse/amimouse.c b/drivers/input/mouse/amimouse.c
index 7baa09cca7c5..e994849efb8f 100644
--- a/drivers/input/mouse/amimouse.c
+++ b/drivers/input/mouse/amimouse.c
@@ -33,7 +33,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Amiga mouse driver");
MODULE_LICENSE("GPL");
-static int amimouse_used = 0;
static int amimouse_lastx, amimouse_lasty;
static struct input_dev amimouse_dev;
@@ -81,16 +80,12 @@ static int amimouse_open(struct input_dev *dev)
{
unsigned short joy0dat;
- if (amimouse_used++)
- return 0;
-
joy0dat = custom.joy0dat;
amimouse_lastx = joy0dat & 0xff;
amimouse_lasty = joy0dat >> 8;
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
- amimouse_used--;
printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
return -EBUSY;
}
@@ -100,8 +95,7 @@ static int amimouse_open(struct input_dev *dev)
static void amimouse_close(struct input_dev *dev)
{
- if (!--amimouse_used)
- free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
+ free_irq(IRQ_AMIGA_VERTB, amimouse_interrupt);
}
static int __init amimouse_init(void)
diff --git a/drivers/input/mouse/inport.c b/drivers/input/mouse/inport.c
index ca4e96886627..1f62c0134010 100644
--- a/drivers/input/mouse/inport.c
+++ b/drivers/input/mouse/inport.c
@@ -17,18 +17,18 @@
/*
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -87,29 +87,23 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("inport_irq=");
-static int inport_used;
-
static irqreturn_t inport_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int inport_open(struct input_dev *dev)
{
- if (!inport_used++) {
- if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
- return -EBUSY;
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
- }
+ if (request_irq(inport_irq, inport_interrupt, 0, "inport", NULL))
+ return -EBUSY;
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_IRQ | INPORT_MODE_BASE, INPORT_DATA_PORT);
return 0;
}
static void inport_close(struct input_dev *dev)
{
- if (!--inport_used) {
- outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
- outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
- free_irq(inport_irq, NULL);
- }
+ outb(INPORT_REG_MODE, INPORT_CONTROL_PORT);
+ outb(INPORT_MODE_BASE, INPORT_DATA_PORT);
+ free_irq(inport_irq, NULL);
}
static struct input_dev inport_dev = {
@@ -120,11 +114,11 @@ static struct input_dev inport_dev = {
.close = inport_close,
.name = INPORT_NAME,
.phys = "isa023c/input0",
- .id = {
- .bustype = BUS_ISA,
- .vendor = INPORT_VENDOR,
- .product = 0x0001,
- .version = 0x0100,
+ .id = {
+ .bustype = BUS_ISA,
+ .vendor = INPORT_VENDOR,
+ .product = 0x0001,
+ .version = 0x0100,
},
};
diff --git a/drivers/input/mouse/lifebook.c b/drivers/input/mouse/lifebook.c
new file mode 100644
index 000000000000..bd9df9b28325
--- /dev/null
+++ b/drivers/input/mouse/lifebook.c
@@ -0,0 +1,134 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2005 Kenan Esau <kenan.esau@conan.de>
+ *
+ * TouchScreen detection, absolute mode setting and packet layout is taken from
+ * Harald Hoyer's description of the device.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/libps2.h>
+#include <linux/dmi.h>
+
+#include "psmouse.h"
+#include "lifebook.h"
+
+static struct dmi_system_id lifebook_dmi_table[] = {
+ {
+ .ident = "Lifebook B",
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK B Series"),
+ },
+ },
+ { }
+};
+
+
+static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse, struct pt_regs *regs)
+{
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = &psmouse->dev;
+
+ if (psmouse->pktcnt != 3)
+ return PSMOUSE_GOOD_DATA;
+
+ input_regs(dev, regs);
+
+ /* calculate X and Y */
+ if ((packet[0] & 0x08) == 0x00) {
+ input_report_abs(dev, ABS_X,
+ (packet[1] | ((packet[0] & 0x30) << 4)));
+ input_report_abs(dev, ABS_Y,
+ 1024 - (packet[2] | ((packet[0] & 0xC0) << 2)));
+ } else {
+ input_report_rel(dev, REL_X,
+ ((packet[0] & 0x10) ? packet[1] - 256 : packet[1]));
+ input_report_rel(dev, REL_Y,
+ -(int)((packet[0] & 0x20) ? packet[2] - 256 : packet[2]));
+ }
+
+ input_report_key(dev, BTN_LEFT, packet[0] & 0x01);
+ input_report_key(dev, BTN_RIGHT, packet[0] & 0x02);
+ input_report_key(dev, BTN_TOUCH, packet[0] & 0x04);
+
+ input_sync(dev);
+
+ return PSMOUSE_FULL_PACKET;
+}
+
+static int lifebook_absolute_mode(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param;
+
+ if (psmouse_reset(psmouse))
+ return -1;
+
+ /*
+ Enable absolute output -- ps2_command fails always but if
+ you leave this call out the touchsreen will never send
+ absolute coordinates
+ */
+ param = 0x07;
+ ps2_command(ps2dev, &param, PSMOUSE_CMD_SETRES);
+
+ return 0;
+}
+
+static void lifebook_set_resolution(struct psmouse *psmouse, unsigned int resolution)
+{
+ unsigned char params[] = { 0, 1, 2, 2, 3 };
+
+ if (resolution == 0 || resolution > 400)
+ resolution = 400;
+
+ ps2_command(&psmouse->ps2dev, &params[resolution / 100], PSMOUSE_CMD_SETRES);
+ psmouse->resolution = 50 << params[resolution / 100];
+}
+
+static void lifebook_disconnect(struct psmouse *psmouse)
+{
+ psmouse_reset(psmouse);
+}
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties)
+{
+ if (!dmi_check_system(lifebook_dmi_table))
+ return -1;
+
+ if (set_properties) {
+ psmouse->vendor = "Fujitsu";
+ psmouse->name = "Lifebook TouchScreen";
+ }
+
+ return 0;
+}
+
+int lifebook_init(struct psmouse *psmouse)
+{
+ if (lifebook_absolute_mode(psmouse))
+ return -1;
+
+ psmouse->dev.evbit[0] = BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+ psmouse->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ psmouse->dev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+ psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y);
+ input_set_abs_params(&psmouse->dev, ABS_X, 0, 1024, 0, 0);
+ input_set_abs_params(&psmouse->dev, ABS_Y, 0, 1024, 0, 0);
+
+ psmouse->protocol_handler = lifebook_process_byte;
+ psmouse->set_resolution = lifebook_set_resolution;
+ psmouse->disconnect = lifebook_disconnect;
+ psmouse->reconnect = lifebook_absolute_mode;
+ psmouse->pktsize = 3;
+
+ return 0;
+}
+
diff --git a/drivers/input/mouse/lifebook.h b/drivers/input/mouse/lifebook.h
new file mode 100644
index 000000000000..be1c0943825d
--- /dev/null
+++ b/drivers/input/mouse/lifebook.h
@@ -0,0 +1,17 @@
+/*
+ * Fujitsu B-series Lifebook PS/2 TouchScreen driver
+ *
+ * Copyright (c) 2005 Vojtech Pavlik
+ *
+ * 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 _LIFEBOOK_H
+#define _LIFEBOOK_H
+
+int lifebook_detect(struct psmouse *psmouse, int set_properties);
+int lifebook_init(struct psmouse *psmouse);
+
+#endif
diff --git a/drivers/input/mouse/logibm.c b/drivers/input/mouse/logibm.c
index 77eb83e87f61..8b5243167227 100644
--- a/drivers/input/mouse/logibm.c
+++ b/drivers/input/mouse/logibm.c
@@ -18,18 +18,18 @@
/*
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -77,16 +77,11 @@ MODULE_PARM_DESC(irq, "IRQ number (5=default)");
__obsolete_setup("logibm_irq=");
-static int logibm_used = 0;
-
static irqreturn_t logibm_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static int logibm_open(struct input_dev *dev)
{
- if (logibm_used++)
- return 0;
if (request_irq(logibm_irq, logibm_interrupt, 0, "logibm", NULL)) {
- logibm_used--;
printk(KERN_ERR "logibm.c: Can't allocate irq %d\n", logibm_irq);
return -EBUSY;
}
@@ -96,8 +91,6 @@ static int logibm_open(struct input_dev *dev)
static void logibm_close(struct input_dev *dev)
{
- if (--logibm_used)
- return;
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
free_irq(logibm_irq, NULL);
}
@@ -167,7 +160,7 @@ static int __init logibm_init(void)
outb(LOGIBM_DISABLE_IRQ, LOGIBM_CONTROL_PORT);
input_register_device(&logibm_dev);
-
+
printk(KERN_INFO "input: Logitech bus mouse at %#x irq %d\n", LOGIBM_BASE, logibm_irq);
return 0;
diff --git a/drivers/input/mouse/maplemouse.c b/drivers/input/mouse/maplemouse.c
index 12dc0ef5020f..e90c60cbbf05 100644
--- a/drivers/input/mouse/maplemouse.c
+++ b/drivers/input/mouse/maplemouse.c
@@ -1,6 +1,6 @@
/*
* $Id: maplemouse.c,v 1.2 2004/03/22 01:18:15 lethal Exp $
- * SEGA Dreamcast mouse driver
+ * SEGA Dreamcast mouse driver
* Based on drivers/usb/usbmouse.c
*/
@@ -15,80 +15,51 @@
MODULE_AUTHOR("YAEGASHI Takeshi <t@keshi.org>");
MODULE_DESCRIPTION("SEGA Dreamcast mouse driver");
-struct dc_mouse {
- struct input_dev dev;
- int open;
-};
-
-
static void dc_mouse_callback(struct mapleq *mq)
{
int buttons, relx, rely, relz;
struct maple_device *mapledev = mq->dev;
- struct dc_mouse *mouse = mapledev->private_data;
- struct input_dev *dev = &mouse->dev;
+ struct input_dev *dev = mapledev->private_data;
unsigned char *res = mq->recvbuf;
buttons = ~res[8];
- relx=*(unsigned short *)(res+12)-512;
- rely=*(unsigned short *)(res+14)-512;
- relz=*(unsigned short *)(res+16)-512;
+ relx = *(unsigned short *)(res + 12) - 512;
+ rely = *(unsigned short *)(res + 14) - 512;
+ relz = *(unsigned short *)(res + 16) - 512;
- input_report_key(dev, BTN_LEFT, buttons&4);
- input_report_key(dev, BTN_MIDDLE, buttons&9);
- input_report_key(dev, BTN_RIGHT, buttons&2);
+ input_report_key(dev, BTN_LEFT, buttons & 4);
+ input_report_key(dev, BTN_MIDDLE, buttons & 9);
+ input_report_key(dev, BTN_RIGHT, buttons & 2);
input_report_rel(dev, REL_X, relx);
input_report_rel(dev, REL_Y, rely);
input_report_rel(dev, REL_WHEEL, relz);
input_sync(dev);
}
-
-static int dc_mouse_open(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open++;
- return 0;
-}
-
-
-static void dc_mouse_close(struct input_dev *dev)
-{
- struct dc_mouse *mouse = dev->private;
- mouse->open--;
-}
-
-
static int dc_mouse_connect(struct maple_device *dev)
{
unsigned long data = be32_to_cpu(dev->devinfo.function_data[0]);
- struct dc_mouse *mouse;
+ struct input_dev *input_dev;
- if (!(mouse = kmalloc(sizeof(struct dc_mouse), GFP_KERNEL)))
+ if (!(input_dev = kmalloc(sizeof(struct input_dev), GFP_KERNEL)))
return -1;
- memset(mouse, 0, sizeof(struct dc_mouse));
-
- dev->private_data = mouse;
- mouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- mouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- mouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
+ dev->private_data = input_dev;
- init_input_dev(&mouse->dev);
+ memset(input_dev, 0, sizeof(struct dc_mouse));
+ init_input_dev(input_dev);
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
+ input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
- mouse->dev.private = mouse;
- mouse->dev.open = dc_mouse_open;
- mouse->dev.close = dc_mouse_close;
- mouse->dev.event = NULL;
+ input_dev->name = dev->product_name;
+ input_dev->id.bustype = BUS_MAPLE;
- mouse->dev.name = dev->product_name;
- mouse->dev.id.bustype = BUS_MAPLE;
-
- input_register_device(&mouse->dev);
+ input_register_device(input_dev);
maple_getcond_callback(dev, dc_mouse_callback, 1, MAPLE_FUNC_MOUSE);
- printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, mouse->dev.name);
+ printk(KERN_INFO "input: mouse(0x%lx): %s\n", data, input_dev->name);
return 0;
}
@@ -96,10 +67,10 @@ static int dc_mouse_connect(struct maple_device *dev)
static void dc_mouse_disconnect(struct maple_device *dev)
{
- struct dc_mouse *mouse = dev->private_data;
+ struct input_dev *input_dev = dev->private_data;
- input_unregister_device(&mouse->dev);
- kfree(mouse);
+ input_unregister_device(input_dev);
+ kfree(input_dev);
}
diff --git a/drivers/input/mouse/pc110pad.c b/drivers/input/mouse/pc110pad.c
index 0c74918fe254..93393d5c0078 100644
--- a/drivers/input/mouse/pc110pad.c
+++ b/drivers/input/mouse/pc110pad.c
@@ -4,7 +4,7 @@
* Copyright (c) 2000-2001 Vojtech Pavlik
*
* Based on the work of:
- * Alan Cox Robin O'Leary
+ * Alan Cox Robin O'Leary
*/
/*
@@ -56,7 +56,6 @@ static int pc110pad_io = 0x15e0;
static struct input_dev pc110pad_dev;
static int pc110pad_data[3];
static int pc110pad_count;
-static int pc110pad_used;
static char *pc110pad_name = "IBM PC110 TouchPad";
static char *pc110pad_phys = "isa15e0/input0";
@@ -74,7 +73,7 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
if (pc110pad_count < 3)
return IRQ_HANDLED;
-
+
input_regs(&pc110pad_dev, regs);
input_report_key(&pc110pad_dev, BTN_TOUCH,
pc110pad_data[0] & 0x01);
@@ -90,15 +89,11 @@ static irqreturn_t pc110pad_interrupt(int irq, void *ptr, struct pt_regs *regs)
static void pc110pad_close(struct input_dev *dev)
{
- if (!--pc110pad_used)
- outb(PC110PAD_OFF, pc110pad_io + 2);
+ outb(PC110PAD_OFF, pc110pad_io + 2);
}
static int pc110pad_open(struct input_dev *dev)
{
- if (pc110pad_used++)
- return 0;
-
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
pc110pad_interrupt(0,NULL,NULL);
@@ -145,7 +140,7 @@ static int __init pc110pad_init(void)
pc110pad_dev.absmax[ABS_X] = 0x1ff;
pc110pad_dev.absmax[ABS_Y] = 0x0ff;
-
+
pc110pad_dev.open = pc110pad_open;
pc110pad_dev.close = pc110pad_close;
@@ -156,17 +151,17 @@ static int __init pc110pad_init(void)
pc110pad_dev.id.product = 0x0001;
pc110pad_dev.id.version = 0x0100;
- input_register_device(&pc110pad_dev);
+ input_register_device(&pc110pad_dev);
printk(KERN_INFO "input: %s at %#x irq %d\n",
pc110pad_name, pc110pad_io, pc110pad_irq);
-
+
return 0;
}
-
+
static void __exit pc110pad_exit(void)
{
- input_unregister_device(&pc110pad_dev);
+ input_unregister_device(&pc110pad_dev);
outb(PC110PAD_OFF, pc110pad_io + 2);
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 019034b21a0b..19785a6c5abd 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -24,6 +24,7 @@
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
+#include "lifebook.h"
#define DRIVER_DESC "PS/2 mouse driver"
@@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-static unsigned int psmouse_max_proto = -1U;
+static unsigned int psmouse_max_proto = PSMOUSE_AUTO;
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp);
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp);
-static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL };
#define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int)
#define param_set_proto_abbrev psmouse_set_maxproto
#define param_get_proto_abbrev psmouse_get_maxproto
@@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter;
module_param_named(resetafter, psmouse_resetafter, uint, 0644);
MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never).");
+PSMOUSE_DEFINE_ATTR(protocol);
PSMOUSE_DEFINE_ATTR(rate);
PSMOUSE_DEFINE_ATTR(resolution);
PSMOUSE_DEFINE_ATTR(resetafter);
@@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll=");
__obsolete_setup("psmouse_resetafter=");
__obsolete_setup("psmouse_rate=");
-static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" };
+/*
+ * psmouse_sem protects all operations changing state of mouse
+ * (connecting, disconnecting, changing rate or resolution via
+ * sysfs). We could use a per-device semaphore but since there
+ * rarely more than one PS/2 mouse connected and since semaphore
+ * is taken in "slow" paths it is not worth it.
+ */
+static DECLARE_MUTEX(psmouse_sem);
+
+struct psmouse_protocol {
+ enum psmouse_type type;
+ char *name;
+ char *alias;
+ int maxproto;
+ int (*detect)(struct psmouse *, int);
+ int (*init)(struct psmouse *);
+};
/*
* psmouse_process_byte() analyzes the PS/2 data stream and reports
@@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties)
*/
static int ps2bare_detect(struct psmouse *psmouse, int set_properties)
{
- if (!psmouse->vendor) psmouse->vendor = "Generic";
- if (!psmouse->name) psmouse->name = "Mouse";
+ if (set_properties) {
+ if (!psmouse->vendor) psmouse->vendor = "Generic";
+ if (!psmouse->name) psmouse->name = "Mouse";
+ }
return 0;
}
+
/*
* psmouse_extensions() probes for any extensions to the basic PS/2 protocol
* the mouse may have.
@@ -424,6 +444,17 @@ static int psmouse_extensions(struct psmouse *psmouse,
int synaptics_hardware = 0;
/*
+ * We always check for lifebook because it does not disturb mouse
+ * (it only checks DMI information).
+ */
+ if (lifebook_detect(psmouse, set_properties) == 0) {
+ if (max_proto > PSMOUSE_IMEX) {
+ if (!set_properties || lifebook_init(psmouse) == 0)
+ return PSMOUSE_LIFEBOOK;
+ }
+ }
+
+/*
* Try Kensington ThinkingMouse (we try first, because synaptics probe
* upsets the thinkingmouse).
*/
@@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse,
return PSMOUSE_PS2;
}
+static struct psmouse_protocol psmouse_protocols[] = {
+ {
+ .type = PSMOUSE_PS2,
+ .name = "PS/2",
+ .alias = "bare",
+ .maxproto = 1,
+ .detect = ps2bare_detect,
+ },
+ {
+ .type = PSMOUSE_PS2PP,
+ .name = "PS2++",
+ .alias = "logitech",
+ .detect = ps2pp_init,
+ },
+ {
+ .type = PSMOUSE_THINKPS,
+ .name = "ThinkPS/2",
+ .alias = "thinkps",
+ .detect = thinking_detect,
+ },
+ {
+ .type = PSMOUSE_GENPS,
+ .name = "GenPS/2",
+ .alias = "genius",
+ .detect = genius_detect,
+ },
+ {
+ .type = PSMOUSE_IMPS,
+ .name = "ImPS/2",
+ .alias = "imps",
+ .maxproto = 1,
+ .detect = intellimouse_detect,
+ },
+ {
+ .type = PSMOUSE_IMEX,
+ .name = "ImExPS/2",
+ .alias = "exps",
+ .maxproto = 1,
+ .detect = im_explorer_detect,
+ },
+ {
+ .type = PSMOUSE_SYNAPTICS,
+ .name = "SynPS/2",
+ .alias = "synaptics",
+ .detect = synaptics_detect,
+ .init = synaptics_init,
+ },
+ {
+ .type = PSMOUSE_ALPS,
+ .name = "AlpsPS/2",
+ .alias = "alps",
+ .detect = alps_detect,
+ .init = alps_init,
+ },
+ {
+ .type = PSMOUSE_LIFEBOOK,
+ .name = "LBPS/2",
+ .alias = "lifebook",
+ .init = lifebook_init,
+ },
+ {
+ .type = PSMOUSE_AUTO,
+ .name = "auto",
+ .alias = "any",
+ .maxproto = 1,
+ },
+};
+
+static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++)
+ if (psmouse_protocols[i].type == type)
+ return &psmouse_protocols[i];
+
+ WARN_ON(1);
+ return &psmouse_protocols[0];
+}
+
+static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len)
+{
+ struct psmouse_protocol *p;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) {
+ p = &psmouse_protocols[i];
+
+ if ((strlen(p->name) == len && !strncmp(p->name, name, len)) ||
+ (strlen(p->alias) == len && !strncmp(p->alias, name, len)))
+ return &psmouse_protocols[i];
+ }
+
+ return NULL;
+}
+
+
/*
* psmouse_probe() probes for a PS/2 mouse.
*/
@@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio)
static void psmouse_disconnect(struct serio *serio)
{
- struct psmouse *psmouse, *parent;
+ struct psmouse *psmouse, *parent = NULL;
+ psmouse = serio_get_drvdata(serio);
+
+ device_remove_file(&serio->dev, &psmouse_attr_protocol);
device_remove_file(&serio->dev, &psmouse_attr_rate);
device_remove_file(&serio->dev, &psmouse_attr_resolution);
device_remove_file(&serio->dev, &psmouse_attr_resetafter);
- psmouse = serio_get_drvdata(serio);
+ down(&psmouse_sem);
+
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
- if (parent->pt_deactivate)
- parent->pt_deactivate(parent);
+ psmouse_deactivate(parent);
}
if (psmouse->disconnect)
psmouse->disconnect(psmouse);
+ if (parent && parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
input_unregister_device(&psmouse->dev);
serio_close(serio);
serio_set_drvdata(serio, NULL);
kfree(psmouse);
+
+ if (parent)
+ psmouse_activate(parent);
+
+ up(&psmouse_sem);
+}
+
+static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto)
+{
+ memset(&psmouse->dev, 0, sizeof(struct input_dev));
+
+ init_input_dev(&psmouse->dev);
+
+ psmouse->dev.private = psmouse;
+ psmouse->dev.dev = &psmouse->ps2dev.serio->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->set_rate = psmouse_set_rate;
+ psmouse->set_resolution = psmouse_set_resolution;
+ psmouse->protocol_handler = psmouse_process_byte;
+ psmouse->pktsize = 3;
+
+ if (proto && (proto->detect || proto->init)) {
+ if (proto->detect && proto->detect(psmouse, 1) < 0)
+ return -1;
+
+ if (proto->init && proto->init(psmouse) < 0)
+ return -1;
+
+ psmouse->type = proto->type;
+ }
+ else
+ psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
+
+ sprintf(psmouse->devname, "%s %s %s",
+ psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name);
+
+ psmouse->dev.name = psmouse->devname;
+ psmouse->dev.phys = psmouse->phys;
+ psmouse->dev.id.bustype = BUS_I8042;
+ psmouse->dev.id.vendor = 0x0002;
+ psmouse->dev.id.product = psmouse->type;
+ psmouse->dev.id.version = psmouse->model;
+
+ return 0;
}
/*
@@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
struct psmouse *psmouse, *parent = NULL;
int retval;
+ down(&psmouse_sem);
+
/*
* If this is a pass-through port deactivate parent so the device
* connected to this port can be successfully identified
@@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse_deactivate(parent);
}
- if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) {
+ if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
retval = -ENOMEM;
goto out;
}
- memset(psmouse, 0, sizeof(struct psmouse));
-
ps2_init(&psmouse->ps2dev, serio);
sprintf(psmouse->phys, "%s/input0", serio->phys);
- 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->dev.private = psmouse;
- psmouse->dev.dev = &serio->dev;
+
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
serio_set_drvdata(serio, psmouse);
@@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
psmouse->resolution = psmouse_resolution;
psmouse->resetafter = psmouse_resetafter;
psmouse->smartscroll = psmouse_smartscroll;
- psmouse->set_rate = psmouse_set_rate;
- psmouse->set_resolution = psmouse_set_resolution;
- psmouse->protocol_handler = psmouse_process_byte;
- psmouse->pktsize = 3;
- psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1);
-
- sprintf(psmouse->devname, "%s %s %s",
- psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name);
-
- psmouse->dev.name = psmouse->devname;
- psmouse->dev.phys = psmouse->phys;
- psmouse->dev.id.bustype = BUS_I8042;
- psmouse->dev.id.vendor = 0x0002;
- psmouse->dev.id.product = psmouse->type;
- psmouse->dev.id.version = psmouse->model;
+ psmouse_switch_protocol(psmouse, NULL);
input_register_device(&psmouse->dev);
-
printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
@@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
if (parent && parent->pt_activate)
parent->pt_activate(parent);
+ device_create_file(&serio->dev, &psmouse_attr_protocol);
device_create_file(&serio->dev, &psmouse_attr_rate);
device_create_file(&serio->dev, &psmouse_attr_resolution);
device_create_file(&serio->dev, &psmouse_attr_resetafter);
@@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
retval = 0;
out:
- /* If this is a pass-through port the parent awaits to be activated */
+ /* If this is a pass-through port the parent needs to be re-activated */
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return retval;
}
@@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio)
return -1;
}
+ down(&psmouse_sem);
+
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
@@ -823,6 +990,7 @@ out:
if (parent)
psmouse_activate(parent);
+ up(&psmouse_sem);
return rc;
}
@@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
if (serio->drv != &psmouse_drv) {
retval = -ENODEV;
- goto out;
+ goto out_unpin;
+ }
+
+ retval = down_interruptible(&psmouse_sem);
+ if (retval)
+ goto out_unpin;
+
+ if (psmouse->state == PSMOUSE_IGNORE) {
+ retval = -ENODEV;
+ goto out_up;
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
}
+
psmouse_deactivate(psmouse);
retval = handler(psmouse, buf, count);
- psmouse_activate(psmouse);
+ if (retval != -ENODEV)
+ psmouse_activate(psmouse);
+
if (parent)
psmouse_activate(parent);
-out:
+ out_up:
+ up(&psmouse_sem);
+ out_unpin:
serio_unpin_driver(serio);
return retval;
}
+static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf)
+{
+ return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name);
+}
+
+static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count)
+{
+ struct serio *serio = psmouse->ps2dev.serio;
+ struct psmouse *parent = NULL;
+ struct psmouse_protocol *proto;
+ int retry = 0;
+
+ if (!(proto = psmouse_protocol_by_name(buf, count)))
+ return -EINVAL;
+
+ if (psmouse->type == proto->type)
+ return count;
+
+ while (serio->child) {
+ if (++retry > 3) {
+ printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n");
+ return -EIO;
+ }
+
+ up(&psmouse_sem);
+ serio_unpin_driver(serio);
+ serio_unregister_child_port(serio);
+ serio_pin_driver_uninterruptible(serio);
+ down(&psmouse_sem);
+
+ if (serio->drv != &psmouse_drv)
+ return -ENODEV;
+
+ if (psmouse->type == proto->type)
+ return count; /* switched by other thread */
+ }
+
+ if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
+ parent = serio_get_drvdata(serio->parent);
+ if (parent->pt_deactivate)
+ parent->pt_deactivate(parent);
+ }
+
+ if (psmouse->disconnect)
+ psmouse->disconnect(psmouse);
+
+ psmouse_set_state(psmouse, PSMOUSE_IGNORE);
+ input_unregister_device(&psmouse->dev);
+
+ psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
+
+ if (psmouse_switch_protocol(psmouse, proto) < 0) {
+ psmouse_reset(psmouse);
+ /* default to PSMOUSE_PS2 */
+ psmouse_switch_protocol(psmouse, &psmouse_protocols[0]);
+ }
+
+ psmouse_initialize(psmouse);
+ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
+
+ input_register_device(&psmouse->dev);
+ printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys);
+
+ if (parent && parent->pt_activate)
+ parent->pt_activate(parent);
+
+ return count;
+}
+
static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf)
{
return sprintf(buf, "%d\n", psmouse->rate);
@@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char *
static int psmouse_set_maxproto(const char *val, struct kernel_param *kp)
{
- int i;
+ struct psmouse_protocol *proto;
if (!val)
return -EINVAL;
- if (!strncmp(val, "any", 3)) {
- *((unsigned int *)kp->arg) = -1U;
- return 0;
- }
+ proto = psmouse_protocol_by_name(val, strlen(val));
- for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) {
- if (!psmouse_proto_abbrev[i])
- continue;
+ if (!proto || !proto->maxproto)
+ return -EINVAL;
- if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) {
- *((unsigned int *)kp->arg) = i;
- return 0;
- }
- }
+ *((unsigned int *)kp->arg) = proto->type;
- return -EINVAL; \
+ return 0; \
}
static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp)
{
- return sprintf(buffer, "%s\n",
- psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ?
- psmouse_proto_abbrev[psmouse_max_proto] : "any");
+ int type = *((unsigned int *)kp->arg);
+
+ return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name);
}
static int __init psmouse_init(void)
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index 79e17a0c4664..86691cf43433 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -77,6 +77,8 @@ enum psmouse_type {
PSMOUSE_IMEX,
PSMOUSE_SYNAPTICS,
PSMOUSE_ALPS,
+ PSMOUSE_LIFEBOOK,
+ PSMOUSE_AUTO /* This one should always be last */
};
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
@@ -99,7 +101,7 @@ static ssize_t psmouse_do_set_##_name(struct device *d, struct device_attribute
{ \
return psmouse_attr_set_helper(d, b, s, psmouse_attr_set_##_name); \
} \
-static struct device_attribute psmouse_attr_##_name = \
+static struct device_attribute psmouse_attr_##_name = \
__ATTR(_name, S_IWUSR | S_IRUGO, \
psmouse_do_show_##_name, psmouse_do_set_##_name);
diff --git a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
index 7280f68afcee..8fe1212b8fd7 100644
--- a/drivers/input/mouse/rpcmouse.c
+++ b/drivers/input/mouse/rpcmouse.c
@@ -59,7 +59,7 @@ static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
b = (short) (__raw_readl(0xe0310000) ^ 0x70);
dx = x - rpcmouse_lastx;
- dy = y - rpcmouse_lasty;
+ dy = y - rpcmouse_lasty;
rpcmouse_lastx = x;
rpcmouse_lasty = y;
diff --git a/drivers/input/mouse/vsxxxaa.c b/drivers/input/mouse/vsxxxaa.c
index b2cb101c8110..f024be9b44d2 100644
--- a/drivers/input/mouse/vsxxxaa.c
+++ b/drivers/input/mouse/vsxxxaa.c
@@ -1,7 +1,7 @@
/*
* Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
- * DEC VSXXX-GA mouse (rectangular mouse, with ball)
- * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
+ * DEC VSXXX-GA mouse (rectangular mouse, with ball)
+ * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
*
* Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
*
diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 062848ac7e6b..c6194a9dd174 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -220,6 +220,7 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
+ int wake_readers = 0;
list_for_each_entry(list, &mousedev->list, node) {
spin_lock_irqsave(&list->packet_lock, flags);
@@ -255,11 +256,14 @@ static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_h
spin_unlock_irqrestore(&list->packet_lock, flags);
- if (list->ready)
+ if (list->ready) {
kill_fasync(&list->fasync, SIGIO, POLL_IN);
+ wake_readers = 1;
+ }
}
- wake_up_interruptible(&mousedev->wait);
+ if (wake_readers)
+ wake_up_interruptible(&mousedev->wait);
}
static void mousedev_touchpad_touch(struct mousedev *mousedev, int value)
diff --git a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
index 5900de3c3f4f..a9bf549c8dc5 100644
--- a/drivers/input/serio/i8042.c
+++ b/drivers/input/serio/i8042.c
@@ -396,7 +396,7 @@ static void i8042_stop(struct serio *serio)
struct i8042_port *port = serio->port_data;
port->exists = 0;
- synchronize_kernel();
+ synchronize_sched();
port->serio = NULL;
}
diff --git a/drivers/input/serio/libps2.c b/drivers/input/serio/libps2.c
index c978657068c5..d4c990f7c85e 100644
--- a/drivers/input/serio/libps2.c
+++ b/drivers/input/serio/libps2.c
@@ -29,6 +29,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(ps2_init);
EXPORT_SYMBOL(ps2_sendbyte);
+EXPORT_SYMBOL(ps2_drain);
EXPORT_SYMBOL(ps2_command);
EXPORT_SYMBOL(ps2_schedule_command);
EXPORT_SYMBOL(ps2_handle_ack);
@@ -45,11 +46,11 @@ struct ps2work {
/*
- * ps2_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.
+ * ps2_sendbyte() sends a byte to the device and waits for acknowledge.
+ * It doesn't handle retransmission, though it could - because if there
+ * is a need for retransmissions device has to be replaced anyway.
*
- * ps2_sendbyte() can only be called from a process context
+ * ps2_sendbyte() can only be called from a process context.
*/
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
@@ -72,6 +73,91 @@ int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout)
}
/*
+ * ps2_drain() waits for device to transmit requested number of bytes
+ * and discards them.
+ */
+
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout)
+{
+ if (maxbytes > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ maxbytes = sizeof(ps2dev->cmdbuf);
+ }
+
+ down(&ps2dev->cmd_sem);
+
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = PS2_FLAG_CMD;
+ ps2dev->cmdcnt = maxbytes;
+ serio_continue_rx(ps2dev->serio);
+
+ wait_event_timeout(ps2dev->wait,
+ !(ps2dev->flags & PS2_FLAG_CMD),
+ msecs_to_jiffies(timeout));
+ up(&ps2dev->cmd_sem);
+}
+
+/*
+ * ps2_is_keyboard_id() checks received ID byte against the list of
+ * known keyboard IDs.
+ */
+
+static inline int ps2_is_keyboard_id(char id_byte)
+{
+ static char keyboard_ids[] = {
+ 0xab, /* Regular keyboards */
+ 0xac, /* NCD Sun keyboard */
+ 0x2b, /* Trust keyboard, translated */
+ 0x5d, /* Trust keyboard */
+ 0x60, /* NMB SGI keyboard, translated */
+ 0x47, /* NMB SGI keyboard */
+ };
+
+ return memchr(keyboard_ids, id_byte, sizeof(keyboard_ids)) != NULL;
+}
+
+/*
+ * ps2_adjust_timeout() is called after receiving 1st byte of command
+ * response and tries to reduce remaining timeout to speed up command
+ * completion.
+ */
+
+static int ps2_adjust_timeout(struct ps2dev *ps2dev, int command, int timeout)
+{
+ switch (command) {
+ case PS2_CMD_RESET_BAT:
+ /*
+ * Device has sent the first response byte after
+ * reset command, reset is thus done, so we can
+ * shorten the timeout.
+ * The next byte will come soon (keyboard) or not
+ * at all (mouse).
+ */
+ if (timeout > msecs_to_jiffies(100))
+ timeout = msecs_to_jiffies(100);
+ break;
+
+ case PS2_CMD_GETID:
+ /*
+ * If device behind the port is not a keyboard there
+ * won't be 2nd byte of ID response.
+ */
+ if (!ps2_is_keyboard_id(ps2dev->cmdbuf[1])) {
+ serio_pause_rx(ps2dev->serio);
+ ps2dev->flags = ps2dev->cmdcnt = 0;
+ serio_continue_rx(ps2dev->serio);
+ timeout = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return timeout;
+}
+
+/*
* ps2_command() sends a command and its parameters to the mouse,
* then waits for the response and puts it in the param array.
*
@@ -86,6 +172,11 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
int rc = -1;
int i;
+ if (receive > sizeof(ps2dev->cmdbuf)) {
+ WARN_ON(1);
+ return -1;
+ }
+
down(&ps2dev->cmd_sem);
serio_pause_rx(ps2dev->serio);
@@ -101,10 +192,9 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
* ACKing the reset command, and so it can take a long
* time before the ACK arrrives.
*/
- if (command & 0xff)
- if (ps2_sendbyte(ps2dev, command & 0xff,
- command == PS2_CMD_RESET_BAT ? 1000 : 200))
- goto out;
+ if (ps2_sendbyte(ps2dev, command & 0xff,
+ command == PS2_CMD_RESET_BAT ? 1000 : 200))
+ goto out;
for (i = 0; i < send; i++)
if (ps2_sendbyte(ps2dev, param[i], 200))
@@ -120,33 +210,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
if (ps2dev->cmdcnt && timeout > 0) {
- if (command == PS2_CMD_RESET_BAT && timeout > msecs_to_jiffies(100)) {
- /*
- * Device has sent the first response byte
- * after a reset command, reset is thus done,
- * shorten the timeout. The next byte will come
- * soon (keyboard) or not at all (mouse).
- */
- timeout = msecs_to_jiffies(100);
- }
-
- if (command == PS2_CMD_GETID &&
- ps2dev->cmdbuf[receive - 1] != 0xab && /* Regular keyboards */
- ps2dev->cmdbuf[receive - 1] != 0xac && /* NCD Sun keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x2b && /* Trust keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x5d && /* Trust keyboard */
- ps2dev->cmdbuf[receive - 1] != 0x60 && /* NMB SGI keyboard, translated */
- ps2dev->cmdbuf[receive - 1] != 0x47) { /* NMB SGI keyboard */
- /*
- * Device behind the port is not a keyboard
- * so we don't need to wait for the 2nd byte
- * of ID response.
- */
- serio_pause_rx(ps2dev->serio);
- ps2dev->flags = ps2dev->cmdcnt = 0;
- serio_continue_rx(ps2dev->serio);
- }
-
+ timeout = ps2_adjust_timeout(ps2dev, command, timeout);
wait_event_timeout(ps2dev->wait,
!(ps2dev->flags & PS2_FLAG_CMD), timeout);
}
@@ -160,7 +224,7 @@ int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command)
rc = 0;
-out:
+ out:
serio_pause_rx(ps2dev->serio);
ps2dev->flags = 0;
serio_continue_rx(ps2dev->serio);
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index feab4970406e..f367695e69b5 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -31,10 +31,9 @@
#include <linux/serio.h>
#include <linux/errno.h>
#include <linux/wait.h>
-#include <linux/completion.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/kthread.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
MODULE_DESCRIPTION("Serio abstraction core");
@@ -43,6 +42,7 @@ MODULE_LICENSE("GPL");
EXPORT_SYMBOL(serio_interrupt);
EXPORT_SYMBOL(__serio_register_port);
EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_unregister_child_port);
EXPORT_SYMBOL(__serio_unregister_port_delayed);
EXPORT_SYMBOL(__serio_register_driver);
EXPORT_SYMBOL(serio_unregister_driver);
@@ -68,6 +68,37 @@ static void serio_destroy_port(struct serio *serio);
static void serio_reconnect_port(struct serio *serio);
static void serio_disconnect_port(struct serio *serio);
+static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
+{
+ int retval;
+
+ down(&serio->drv_sem);
+ retval = drv->connect(serio, drv);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static int serio_reconnect_driver(struct serio *serio)
+{
+ int retval = -1;
+
+ down(&serio->drv_sem);
+ if (serio->drv && serio->drv->reconnect)
+ retval = serio->drv->reconnect(serio);
+ up(&serio->drv_sem);
+
+ return retval;
+}
+
+static void serio_disconnect_driver(struct serio *serio)
+{
+ down(&serio->drv_sem);
+ if (serio->drv)
+ serio->drv->disconnect(serio);
+ up(&serio->drv_sem);
+}
+
static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
{
while (ids->type || ids->proto) {
@@ -91,7 +122,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
if (serio_match_port(drv->id_table, serio)) {
serio->dev.driver = &drv->driver;
- if (drv->connect(serio, drv)) {
+ if (serio_connect_driver(serio, drv)) {
serio->dev.driver = NULL;
goto out;
}
@@ -138,8 +169,7 @@ struct serio_event {
static DEFINE_SPINLOCK(serio_event_lock); /* 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 struct task_struct *serio_task;
static void serio_queue_event(void *object, struct module *owner,
enum serio_event_type event_type)
@@ -150,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner,
spin_lock_irqsave(&serio_event_lock, flags);
/*
- * Scan event list for the other events for the same serio port,
+ * Scan event list for the other events for the same serio port,
* starting with the most recent one. If event is the same we
* do not need add new one. If event is of different type we
* need to add this event and should not look further because
* we need to preseve sequence of distinct events.
- */
+ */
list_for_each_entry_reverse(event, &serio_event_list, node) {
if (event->object == object) {
if (event->type == event_type)
@@ -337,20 +367,15 @@ static struct serio *serio_get_pending_child(struct serio *parent)
static int serio_thread(void *nothing)
{
- lock_kernel();
- daemonize("kseriod");
- allow_signal(SIGTERM);
-
do {
serio_handle_events();
- wait_event_interruptible(serio_wait, !list_empty(&serio_event_list));
- try_to_freeze(PF_FREEZE);
- } while (!signal_pending(current));
+ wait_event_interruptible(serio_wait,
+ kthread_should_stop() || !list_empty(&serio_event_list));
+ try_to_freeze();
+ } while (!kthread_should_stop());
printk(KERN_DEBUG "serio: kseriod exiting\n");
-
- unlock_kernel();
- complete_and_exit(&serio_exited, 0);
+ return 0;
}
@@ -557,7 +582,7 @@ static void serio_destroy_port(struct serio *serio)
static void serio_reconnect_port(struct serio *serio)
{
do {
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
serio_disconnect_port(serio);
serio_find_driver(serio);
/* Ok, old children are now gone, we are done */
@@ -630,6 +655,19 @@ void serio_unregister_port(struct serio *serio)
}
/*
+ * Safely unregisters child port if one is present.
+ */
+void serio_unregister_child_port(struct serio *serio)
+{
+ down(&serio_sem);
+ if (serio->child) {
+ serio_disconnect_port(serio->child);
+ serio_destroy_port(serio->child);
+ }
+ up(&serio_sem);
+}
+
+/*
* Submits register request to kseriod for subsequent execution.
* Can be used when it is not obvious whether the serio_sem is
* taken or not and when delayed execution is feasible.
@@ -686,15 +724,14 @@ static int serio_driver_probe(struct device *dev)
struct serio *serio = to_serio_port(dev);
struct serio_driver *drv = to_serio_driver(dev->driver);
- return drv->connect(serio, drv);
+ return serio_connect_driver(serio, drv);
}
static int serio_driver_remove(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- struct serio_driver *drv = to_serio_driver(dev->driver);
- drv->disconnect(serio);
+ serio_disconnect_driver(serio);
return 0;
}
@@ -730,11 +767,9 @@ start_over:
static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
{
- down(&serio->drv_sem);
serio_pause_rx(serio);
serio->drv = drv;
serio_continue_rx(serio);
- up(&serio->drv_sem);
}
static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -794,7 +829,7 @@ static int serio_resume(struct device *dev)
{
struct serio *serio = to_serio_port(dev);
- if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) {
+ if (serio_reconnect_driver(serio)) {
/*
* Driver re-probing can take a while, so better let kseriod
* deal with it.
@@ -848,9 +883,10 @@ irqreturn_t serio_interrupt(struct serio *serio,
static int __init serio_init(void)
{
- if (!(serio_pid = kernel_thread(serio_thread, NULL, CLONE_KERNEL))) {
+ serio_task = kthread_run(serio_thread, NULL, "kseriod");
+ if (IS_ERR(serio_task)) {
printk(KERN_ERR "serio: Failed to start kseriod\n");
- return -1;
+ return PTR_ERR(serio_task);
}
serio_bus.dev_attrs = serio_device_attrs;
@@ -866,8 +902,7 @@ static int __init serio_init(void)
static void __exit serio_exit(void)
{
bus_unregister(&serio_bus);
- kill_proc(serio_pid, SIGTERM, 1);
- wait_for_completion(&serio_exited);
+ kthread_stop(serio_task);
}
module_init(serio_init);
diff --git a/drivers/input/touchscreen/elo.c b/drivers/input/touchscreen/elo.c
index 546ce599334e..3cdc9cab688d 100644
--- a/drivers/input/touchscreen/elo.c
+++ b/drivers/input/touchscreen/elo.c
@@ -226,7 +226,7 @@ static int elo_connect(struct serio *serio, struct serio_driver *drv)
input_set_abs_params(&elo->dev, ABS_Y, 96, 4000, 0, 0);
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 255, 0, 0);
break;
-
+
case 1: /* 6-byte protocol */
input_set_abs_params(&elo->dev, ABS_PRESSURE, 0, 15, 0, 0);
diff --git a/drivers/input/touchscreen/h3600_ts_input.c b/drivers/input/touchscreen/h3600_ts_input.c
index acb9137a0226..bcfa1e36f957 100644
--- a/drivers/input/touchscreen/h3600_ts_input.c
+++ b/drivers/input/touchscreen/h3600_ts_input.c
@@ -89,9 +89,9 @@ MODULE_LICENSE("GPL");
#define H3600_SCANCODE_Q 4 /* 4 -> Q button */
#define H3600_SCANCODE_START 5 /* 5 -> start menu */
#define H3600_SCANCODE_UP 6 /* 6 -> up */
-#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
-#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
-#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
+#define H3600_SCANCODE_RIGHT 7 /* 7 -> right */
+#define H3600_SCANCODE_LEFT 8 /* 8 -> left */
+#define H3600_SCANCODE_DOWN 9 /* 9 -> down */
static char *h3600_name = "H3600 TouchScreen";
@@ -113,7 +113,7 @@ struct h3600_dev {
static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_ACTION_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
input_regs(dev, regs);
@@ -125,7 +125,7 @@ static irqreturn_t action_button_handler(int irq, void *dev_id, struct pt_regs *
static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *regs)
{
- int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
+ int down = (GPLR & GPIO_BITSY_NPOWER_BUTTON) ? 0 : 1;
struct input_dev *dev = (struct input_dev *) dev_id;
/*
@@ -145,8 +145,8 @@ static irqreturn_t npower_button_handler(int irq, void *dev_id, struct pt_regs *
static int flite_brightness = 25;
enum flite_pwr {
- FLITE_PWR_OFF = 0,
- FLITE_PWR_ON = 1
+ FLITE_PWR_OFF = 0,
+ FLITE_PWR_ON = 1
};
/*
@@ -157,9 +157,9 @@ unsigned int h3600_flite_power(struct input_dev *dev, enum flite_pwr pwr)
struct h3600_dev *ts = dev->private;
/* Must be in this order */
- ts->serio->write(ts->serio, 1);
+ ts->serio->write(ts->serio, 1);
ts->serio->write(ts->serio, pwr);
- ts->serio->write(ts->serio, brightness);
+ ts->serio->write(ts->serio, brightness);
return 0;
}
@@ -169,26 +169,26 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
{
struct input_dev *dev = (struct input_dev *) data;
- switch (req) {
- case PM_SUSPEND: /* enter D1-D3 */
- suspended = 1;
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_BLANK:
- if (!suspended)
- h3600_flite_power(dev, FLITE_PWR_OFF);
- break;
- case PM_RESUME: /* enter D0 */
- /* same as unblank */
- case PM_UNBLANK:
- if (suspended) {
- //initSerial();
- suspended = 0;
- }
- h3600_flite_power(dev, FLITE_PWR_ON);
- break;
- }
- return 0;
+ switch (req) {
+ case PM_SUSPEND: /* enter D1-D3 */
+ suspended = 1;
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_BLANK:
+ if (!suspended)
+ h3600_flite_power(dev, FLITE_PWR_OFF);
+ break;
+ case PM_RESUME: /* enter D0 */
+ /* same as unblank */
+ case PM_UNBLANK:
+ if (suspended) {
+ //initSerial();
+ suspended = 0;
+ }
+ h3600_flite_power(dev, FLITE_PWR_ON);
+ break;
+ }
+ return 0;
}
#endif
@@ -199,25 +199,25 @@ static int h3600ts_pm_callback(struct pm_dev *pm_dev, pm_request_t req,
*/
static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
{
- struct input_dev *dev = &ts->dev;
+ struct input_dev *dev = &ts->dev;
static int touched = 0;
int key, down = 0;
input_regs(dev, regs);
- switch (ts->event) {
- /*
- Buttons - returned as a single byte
- 7 6 5 4 3 2 1 0
- S x x x N N N N
+ switch (ts->event) {
+ /*
+ Buttons - returned as a single byte
+ 7 6 5 4 3 2 1 0
+ S x x x N N N N
- S switch state ( 0=pressed 1=released)
- x Unused.
- NNNN switch number 0-15
+ S switch state ( 0=pressed 1=released)
+ x Unused.
+ NNNN switch number 0-15
- Note: This is true for non interrupt generated key events.
- */
- case KEYBD_ID:
+ Note: This is true for non interrupt generated key events.
+ */
+ case KEYBD_ID:
down = (ts->buf[0] & 0x80) ? 0 : 1;
switch (ts->buf[0] & 0x7f) {
@@ -229,40 +229,40 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
break;
case H3600_SCANCODE_CONTACTS:
key = KEY_PROG2;
- break;
+ break;
case H3600_SCANCODE_Q:
key = KEY_Q;
- break;
+ break;
case H3600_SCANCODE_START:
key = KEY_PROG3;
- break;
+ break;
case H3600_SCANCODE_UP:
key = KEY_UP;
- break;
+ break;
case H3600_SCANCODE_RIGHT:
key = KEY_RIGHT;
- break;
+ break;
case H3600_SCANCODE_LEFT:
key = KEY_LEFT;
- break;
+ break;
case H3600_SCANCODE_DOWN:
key = KEY_DOWN;
- break;
+ break;
default:
key = 0;
}
- if (key)
- input_report_key(dev, key, down);
- break;
- /*
- * Native touchscreen event data is formatted as shown below:-
- *
- * +-------+-------+-------+-------+
- * | Xmsb | Xlsb | Ymsb | Ylsb |
- * +-------+-------+-------+-------+
- * byte 0 1 2 3
- */
- case TOUCHS_ID:
+ if (key)
+ input_report_key(dev, key, down);
+ break;
+ /*
+ * Native touchscreen event data is formatted as shown below:-
+ *
+ * +-------+-------+-------+-------+
+ * | Xmsb | Xlsb | Ymsb | Ylsb |
+ * +-------+-------+-------+-------+
+ * byte 0 1 2 3
+ */
+ case TOUCHS_ID:
if (!touched) {
input_report_key(dev, BTN_TOUCH, 1);
touched = 1;
@@ -272,19 +272,19 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
unsigned short x, y;
x = ts->buf[0]; x <<= 8; x += ts->buf[1];
- y = ts->buf[2]; y <<= 8; y += ts->buf[3];
+ y = ts->buf[2]; y <<= 8; y += ts->buf[3];
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
} else {
- input_report_key(dev, BTN_TOUCH, 0);
+ input_report_key(dev, BTN_TOUCH, 0);
touched = 0;
}
- break;
+ break;
default:
/* Send a non input event elsewhere */
break;
- }
+ }
input_sync(dev);
}
@@ -293,7 +293,7 @@ static void h3600ts_process_packet(struct h3600_dev *ts, struct pt_regs *regs)
* h3600ts_event() handles events from the input module.
*/
static int h3600ts_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
+ unsigned int code, int value)
{
struct h3600_dev *ts = dev->private;
@@ -332,41 +332,41 @@ static int state;
static irqreturn_t h3600ts_interrupt(struct serio *serio, unsigned char data,
unsigned int flags, struct pt_regs *regs)
{
- struct h3600_dev *ts = serio_get_drvdata(serio);
+ struct h3600_dev *ts = serio_get_drvdata(serio);
/*
- * We have a new frame coming in.
- */
+ * We have a new frame coming in.
+ */
switch (state) {
case STATE_SOF:
- if (data == CHAR_SOF)
- state = STATE_ID;
+ if (data == CHAR_SOF)
+ state = STATE_ID;
break;
- case STATE_ID:
+ case STATE_ID:
ts->event = (data & 0xf0) >> 4;
ts->len = (data & 0xf);
ts->idx = 0;
if (ts->event >= MAX_ID) {
state = STATE_SOF;
- break;
+ break;
}
ts->chksum = data;
- state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
+ state = (ts->len > 0) ? STATE_DATA : STATE_EOF;
break;
case STATE_DATA:
ts->chksum += data;
ts->buf[ts->idx]= data;
- if(++ts->idx == ts->len)
- state = STATE_EOF;
+ if (++ts->idx == ts->len)
+ state = STATE_EOF;
break;
case STATE_EOF:
- state = STATE_SOF;
- if (data == CHAR_EOF || data == ts->chksum)
+ state = STATE_SOF;
+ if (data == CHAR_EOF || data == ts->chksum)
h3600ts_process_packet(ts, regs);
- break;
- default:
- printk("Error3\n");
- break;
+ break;
+ default:
+ printk("Error3\n");
+ break;
}
return IRQ_HANDLED;
@@ -390,10 +390,10 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
init_input_dev(&ts->dev);
/* Device specific stuff */
- set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
- set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
+ set_GPIO_IRQ_edge(GPIO_BITSY_ACTION_BUTTON, GPIO_BOTH_EDGES);
+ set_GPIO_IRQ_edge(GPIO_BITSY_NPOWER_BUTTON, GPIO_RISING_EDGE);
- if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, action_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_action", &ts->dev)) {
printk(KERN_ERR "h3600ts.c: Could not allocate Action Button IRQ!\n");
@@ -401,7 +401,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
return -EBUSY;
}
- if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
+ if (request_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, npower_button_handler,
SA_SHIRQ | SA_INTERRUPT | SA_SAMPLE_RANDOM,
"h3600_suspend", &ts->dev)) {
free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, &ts->dev);
@@ -433,7 +433,7 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
sprintf(ts->phys, "%s/input0", serio->phys);
- ts->dev.event = h3600ts_event;
+ ts->dev.event = h3600ts_event;
ts->dev.private = ts;
ts->dev.name = h3600_name;
ts->dev.phys = ts->phys;
@@ -446,8 +446,8 @@ static int h3600ts_connect(struct serio *serio, struct serio_driver *drv)
err = serio_open(serio, drv);
if (err) {
- free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
- free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_ACTION_BUTTON, ts);
+ free_irq(IRQ_GPIO_BITSY_NPOWER_BUTTON, ts);
serio_set_drvdata(serio, NULL);
kfree(ts);
return err;
diff --git a/drivers/input/touchscreen/mk712.c b/drivers/input/touchscreen/mk712.c
index 2d14a57a05e5..afaaebe5225b 100644
--- a/drivers/input/touchscreen/mk712.c
+++ b/drivers/input/touchscreen/mk712.c
@@ -17,7 +17,7 @@
* found in Gateway AOL Connected Touchpad computers.
*
* Documentation for ICS MK712 can be found at:
- * http://www.icst.com/pdf/mk712.pdf
+ * http://www.icst.com/pdf/mk712.pdf
*/
/*
@@ -77,7 +77,6 @@ MODULE_PARM_DESC(irq, "IRQ of MK712 touchscreen controller");
#define MK712_READ_ONE_POINT 0x20
#define MK712_POWERUP 0x40
-static int mk712_used = 0;
static struct input_dev mk712_dev;
static DEFINE_SPINLOCK(mk712_lock);
@@ -130,17 +129,14 @@ static int mk712_open(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!mk712_used++) {
+ outb(0, mk712_io + MK712_CONTROL); /* Reset */
- outb(0, mk712_io + MK712_CONTROL); /* Reset */
+ outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
+ MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
+ MK712_ENABLE_PERIODIC_CONVERSIONS |
+ MK712_POWERUP, mk712_io + MK712_CONTROL);
- outb(MK712_ENABLE_INT | MK712_INT_ON_CONVERSION_COMPLETE |
- MK712_INT_ON_CHANGE_IN_TOUCH_STATUS |
- MK712_ENABLE_PERIODIC_CONVERSIONS |
- MK712_POWERUP, mk712_io + MK712_CONTROL);
-
- outb(10, mk712_io + MK712_RATE); /* 187 points per second */
- }
+ outb(10, mk712_io + MK712_RATE); /* 187 points per second */
spin_unlock_irqrestore(&mk712_lock, flags);
@@ -153,8 +149,7 @@ static void mk712_close(struct input_dev *dev)
spin_lock_irqsave(&mk712_lock, flags);
- if (!--mk712_used)
- outb(0, mk712_io + MK712_CONTROL);
+ outb(0, mk712_io + MK712_CONTROL);
spin_unlock_irqrestore(&mk712_lock, flags);
}
diff --git a/drivers/isdn/act2000/capi.c b/drivers/isdn/act2000/capi.c
index 40395f567231..afa46681f983 100644
--- a/drivers/isdn/act2000/capi.c
+++ b/drivers/isdn/act2000/capi.c
@@ -224,6 +224,7 @@ actcapi_manufacturer_req_net(act2000_card *card)
/*
* Switch V.42 on or off
*/
+#if 0
int
actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
{
@@ -242,6 +243,7 @@ actcapi_manufacturer_req_v42(act2000_card *card, ulong arg)
ACTCAPI_QUEUE_TX;
return 0;
}
+#endif /* 0 */
/*
* Set error-handler
diff --git a/drivers/isdn/act2000/capi.h b/drivers/isdn/act2000/capi.h
index 04d2bcdd37a7..f6d5f530b86b 100644
--- a/drivers/isdn/act2000/capi.h
+++ b/drivers/isdn/act2000/capi.h
@@ -350,7 +350,6 @@ actcapi_nextsmsg(act2000_card *card)
extern int actcapi_chkhdr(act2000_card *, actcapi_msghdr *);
extern int actcapi_listen_req(act2000_card *);
extern int actcapi_manufacturer_req_net(act2000_card *);
-extern int actcapi_manufacturer_req_v42(act2000_card *, ulong);
extern int actcapi_manufacturer_req_errh(act2000_card *);
extern int actcapi_manufacturer_req_msn(act2000_card *);
extern int actcapi_connect_req(act2000_card *, act2000_chan *, char *, char, int, int);
diff --git a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c
index dc00c85e3e35..db9bad2b3d16 100644
--- a/drivers/isdn/hardware/avm/avm_cs.c
+++ b/drivers/isdn/hardware/avm/avm_cs.c
@@ -22,7 +22,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -161,11 +160,6 @@ static dev_link_t *avmcs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &avmcs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -486,13 +480,23 @@ static int avmcs_event(event_t event, int priority,
return 0;
} /* avmcs_event */
+static struct pcmcia_device_id avmcs_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN-Controller B1", 0x95d42008, 0x845dc335),
+ PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M1", 0x95d42008, 0x81e10430),
+ PCMCIA_DEVICE_PROD_ID12("AVM", "Mobile ISDN-Controller M2", 0x95d42008, 0x18e8558a),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avmcs_ids);
+
static struct pcmcia_driver avmcs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "avm_cs",
},
.attach = avmcs_attach,
+ .event = avmcs_event,
.detach = avmcs_detach,
+ .id_table = avmcs_ids,
};
static int __init avmcs_init(void)
diff --git a/drivers/isdn/hardware/avm/b1dma.c b/drivers/isdn/hardware/avm/b1dma.c
index 55bed00ca865..91dd0551fc7c 100644
--- a/drivers/isdn/hardware/avm/b1dma.c
+++ b/drivers/isdn/hardware/avm/b1dma.c
@@ -955,7 +955,7 @@ EXPORT_SYMBOL(b1dma_release_appl);
EXPORT_SYMBOL(b1dma_send_message);
EXPORT_SYMBOL(b1dmactl_read_proc);
-int b1dma_init(void)
+static int __init b1dma_init(void)
{
char *p;
char rev[32];
@@ -972,7 +972,7 @@ int b1dma_init(void)
return 0;
}
-void b1dma_exit(void)
+static void __exit b1dma_exit(void)
{
}
diff --git a/drivers/isdn/hardware/avm/c4.c b/drivers/isdn/hardware/avm/c4.c
index fa6b93b1a42d..724aac2c1cca 100644
--- a/drivers/isdn/hardware/avm/c4.c
+++ b/drivers/isdn/hardware/avm/c4.c
@@ -885,7 +885,7 @@ static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
}
-void c4_reset_ctr(struct capi_ctr *ctrl)
+static void c4_reset_ctr(struct capi_ctr *ctrl)
{
avmcard *card = ((avmctrl_info *)(ctrl->driverdata))->card;
avmctrl_info *cinfo;
@@ -933,7 +933,7 @@ static void c4_remove(struct pci_dev *pdev)
/* ------------------------------------------------------------- */
-void c4_register_appl(struct capi_ctr *ctrl,
+static void c4_register_appl(struct capi_ctr *ctrl,
u16 appl,
capi_register_params *rp)
{
@@ -978,7 +978,7 @@ void c4_register_appl(struct capi_ctr *ctrl,
/* ------------------------------------------------------------- */
-void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
+static void c4_release_appl(struct capi_ctr *ctrl, u16 appl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
diff --git a/drivers/isdn/hardware/avm/t1isa.c b/drivers/isdn/hardware/avm/t1isa.c
index cb9d9cee2a64..3b701d97bdf1 100644
--- a/drivers/isdn/hardware/avm/t1isa.c
+++ b/drivers/isdn/hardware/avm/t1isa.c
@@ -328,7 +328,7 @@ static int t1isa_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
return 0;
}
-void t1isa_reset_ctr(struct capi_ctr *ctrl)
+static void t1isa_reset_ctr(struct capi_ctr *ctrl)
{
avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata);
avmcard *card = cinfo->card;
diff --git a/drivers/isdn/hardware/eicon/dadapter.c b/drivers/isdn/hardware/eicon/dadapter.c
index 6e548a222ef1..89497890158d 100644
--- a/drivers/isdn/hardware/eicon/dadapter.c
+++ b/drivers/isdn/hardware/eicon/dadapter.c
@@ -44,7 +44,7 @@ static didd_adapter_change_notification_t\
Array to held adapter information
-------------------------------------------------------------------------- */
static DESCRIPTOR HandleTable[NEW_MAX_DESCRIPTORS];
-dword Adapters = 0; /* Number of adapters */
+static dword Adapters = 0; /* Number of adapters */
/* --------------------------------------------------------------------------
Shadow IDI_DIMAINT
and 'shadow' debug stuff
diff --git a/drivers/isdn/hisax/Makefile b/drivers/isdn/hisax/Makefile
index 8d6bb56754b8..293e27789d54 100644
--- a/drivers/isdn/hisax/Makefile
+++ b/drivers/isdn/hisax/Makefile
@@ -23,7 +23,7 @@ endif
# Multipart objects.
hisax_st5481-y := st5481_init.o st5481_usb.o st5481_d.o \
- st5481_b.o st5481_hdlc.o
+ st5481_b.o
hisax-y := config.o isdnl1.o tei.o isdnl2.o isdnl3.o \
lmgr.o q931.o callc.o fsm.o
diff --git a/drivers/isdn/hisax/amd7930_fn.c b/drivers/isdn/hisax/amd7930_fn.c
index c4f861a5db25..8ae08c41c853 100644
--- a/drivers/isdn/hisax/amd7930_fn.c
+++ b/drivers/isdn/hisax/amd7930_fn.c
@@ -97,7 +97,7 @@ static WORD initAMD[] = {
};
-void /* macro wWordAMD */
+static void /* macro wWordAMD */
WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
{
wByteAMD(cs, 0x00, reg);
@@ -105,7 +105,7 @@ WriteWordAmd7930(struct IsdnCardState *cs, BYTE reg, WORD val)
wByteAMD(cs, 0x01, HIBYTE(val));
}
-WORD /* macro rWordAMD */
+static WORD /* macro rWordAMD */
ReadWordAmd7930(struct IsdnCardState *cs, BYTE reg)
{
WORD res;
@@ -665,7 +665,7 @@ Amd7930_l1hw(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
{
@@ -676,7 +676,7 @@ setstack_Amd7930(struct PStack *st, struct IsdnCardState *cs)
}
-void
+static void
DC_Close_Amd7930(struct IsdnCardState *cs) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "Amd7930: DC_Close called");
diff --git a/drivers/isdn/hisax/asuscom.c b/drivers/isdn/hisax/asuscom.c
index 7546e2e4a94e..a98c5e38bbbc 100644
--- a/drivers/isdn/hisax/asuscom.c
+++ b/drivers/isdn/hisax/asuscom.c
@@ -22,7 +22,7 @@
extern const char *CardType[];
-const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
+static const char *Asuscom_revision = "$Revision: 1.14.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -239,7 +239,7 @@ Start_IPAC:
return IRQ_HANDLED;
}
-void
+static void
release_io_asuscom(struct IsdnCardState *cs)
{
int bytecnt = 8;
diff --git a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
index 6fcb2cf7b0b6..625799ab0d14 100644
--- a/drivers/isdn/hisax/avm_pci.c
+++ b/drivers/isdn/hisax/avm_pci.c
@@ -172,7 +172,7 @@ struct BCState *Sel_BCS(struct IsdnCardState *cs, int channel)
return(NULL);
}
-void
+static void
write_ctrl(struct BCState *bcs, int which) {
if (bcs->cs->debug & L1_DEB_HSCX)
@@ -193,7 +193,7 @@ write_ctrl(struct BCState *bcs, int which) {
}
}
-void
+static void
modehdlc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -451,7 +451,7 @@ HDLC_irq(struct BCState *bcs, u_int stat) {
}
}
-inline void
+static inline void
HDLC_irq_main(struct IsdnCardState *cs)
{
u_int stat;
@@ -487,7 +487,7 @@ HDLC_irq_main(struct IsdnCardState *cs)
}
}
-void
+static void
hdlc_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
@@ -547,7 +547,7 @@ hdlc_l2l1(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
close_hdlcstate(struct BCState *bcs)
{
modehdlc(bcs, 0, 0);
@@ -570,7 +570,7 @@ close_hdlcstate(struct BCState *bcs)
}
}
-int
+static int
open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
@@ -598,7 +598,7 @@ open_hdlcstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_hdlc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
@@ -612,6 +612,7 @@ setstack_hdlc(struct PStack *st, struct BCState *bcs)
return (0);
}
+#if 0
void __init
clear_pending_hdlc_ints(struct IsdnCardState *cs)
{
@@ -641,8 +642,9 @@ clear_pending_hdlc_ints(struct IsdnCardState *cs)
debugl1(cs, "HDLC 2 VIN %x", val);
}
}
+#endif /* 0 */
-void __init
+static void __init
inithdlc(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_hdlc;
diff --git a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c
index 663a0bf703b7..0e22991635e7 100644
--- a/drivers/isdn/hisax/avma1_cs.c
+++ b/drivers/isdn/hisax/avma1_cs.c
@@ -21,7 +21,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -183,11 +182,6 @@ static dev_link_t *avma1cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &avma1cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -501,13 +495,22 @@ static int avma1cs_event(event_t event, int priority,
return 0;
} /* avma1cs_event */
+static struct pcmcia_device_id avma1cs_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("AVM", "ISDN A", 0x95d42008, 0xadc9d4bb),
+ PCMCIA_DEVICE_PROD_ID12("ISDN", "CARD", 0x8d9761c8, 0x01c5aa7b),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, avma1cs_ids);
+
static struct pcmcia_driver avma1cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "avma1_cs",
},
.attach = avma1cs_attach,
+ .event = avma1cs_event,
.detach = avma1cs_detach,
+ .id_table = avma1cs_ids,
};
/*====================================================================*/
diff --git a/drivers/isdn/hisax/bkm_a4t.c b/drivers/isdn/hisax/bkm_a4t.c
index f410f628a3e2..dcb308aeb50c 100644
--- a/drivers/isdn/hisax/bkm_a4t.c
+++ b/drivers/isdn/hisax/bkm_a4t.c
@@ -23,7 +23,7 @@
extern const char *CardType[];
-const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
+static const char *bkm_a4t_revision = "$Revision: 1.22.2.4 $";
static inline u_char
@@ -167,7 +167,7 @@ bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
}
}
-void
+static void
release_io_bkm(struct IsdnCardState *cs)
{
if (cs->hw.ax.base) {
diff --git a/drivers/isdn/hisax/bkm_a8.c b/drivers/isdn/hisax/bkm_a8.c
index 94bb83ce7fd8..5f21b82c8c8d 100644
--- a/drivers/isdn/hisax/bkm_a8.c
+++ b/drivers/isdn/hisax/bkm_a8.c
@@ -27,7 +27,7 @@
extern const char *CardType[];
-const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
+static const char sct_quadro_revision[] = "$Revision: 1.22.2.4 $";
static const char *sct_quadro_subtypes[] =
{
@@ -193,7 +193,7 @@ bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_sct_quadro(struct IsdnCardState *cs)
{
release_region(cs->hw.ax.base & 0xffffffc0, 128);
@@ -261,7 +261,7 @@ BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
return (0);
}
-int __init
+static int __init
sct_alloc_io(u_int adr, u_int len)
{
if (!request_region(adr, len, "scitel")) {
diff --git a/drivers/isdn/hisax/callc.c b/drivers/isdn/hisax/callc.c
index 04065ab2610f..7c56c44f0fd1 100644
--- a/drivers/isdn/hisax/callc.c
+++ b/drivers/isdn/hisax/callc.c
@@ -874,7 +874,7 @@ release_b_st(struct Channel *chanp)
}
}
-struct Channel
+static struct Channel
*selectfreechannel(struct PStack *st, int bch)
{
struct IsdnCardState *cs = st->l1.hardware;
@@ -1429,7 +1429,7 @@ capi_debug(struct Channel *chanp, capi_msg *cm)
HiSax_putstatus(chanp->cs, "Ch", "%d CAPIMSG %s", chanp->chan, tmpbuf);
}
-void
+static void
lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
if ((cm->para[0] != 3) || (cm->para[1] != 0))
return;
@@ -1454,7 +1454,7 @@ lli_got_fac_req(struct Channel *chanp, capi_msg *cm) {
}
}
-void
+static void
lli_got_manufacturer(struct Channel *chanp, struct IsdnCardState *cs, capi_msg *cm) {
if ((cs->typ == ISDN_CTYPE_ELSA) || (cs->typ == ISDN_CTYPE_ELSA_PNP) ||
(cs->typ == ISDN_CTYPE_ELSA_PCI)) {
diff --git a/drivers/isdn/hisax/config.c b/drivers/isdn/hisax/config.c
index 1663ee69d41d..c542e6fb2bde 100644
--- a/drivers/isdn/hisax/config.c
+++ b/drivers/isdn/hisax/config.c
@@ -332,7 +332,7 @@ struct IsdnCard cards[HISAX_MAX_CARDS] = {
#define HISAX_IDSIZE (HISAX_MAX_CARDS*8)
static char HiSaxID[HISAX_IDSIZE] = { 0, };
-char *HiSax_id = HiSaxID;
+static char *HiSax_id = HiSaxID;
#ifdef MODULE
/* Variables for insmod */
static int type[HISAX_MAX_CARDS] = { 0, };
@@ -391,7 +391,7 @@ char *HiSax_getrev(const char *revision)
return rev;
}
-void __init HiSaxVersion(void)
+static void __init HiSaxVersion(void)
{
char tmp[64];
@@ -608,6 +608,7 @@ static inline struct IsdnCardState *hisax_findcard(int driverid)
/*
* Find card with given card number
*/
+#if 0
struct IsdnCardState *hisax_get_card(int cardnr)
{
if ((cardnr <= nrcards) && (cardnr > 0))
@@ -615,8 +616,9 @@ struct IsdnCardState *hisax_get_card(int cardnr)
return cards[cardnr - 1].cs;
return NULL;
}
+#endif /* 0 */
-int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
+static int HiSax_readstatus(u_char __user *buf, int len, int id, int channel)
{
int count, cnt;
u_char __user *p = buf;
@@ -768,7 +770,7 @@ int ll_run(struct IsdnCardState *cs, int addfeatures)
return 0;
}
-void ll_stop(struct IsdnCardState *cs)
+static void ll_stop(struct IsdnCardState *cs)
{
isdn_ctrl ic;
@@ -1184,7 +1186,7 @@ static int checkcard(int cardnr, char *id, int *busy_flag, struct module *lockow
return ret;
}
-void HiSax_shiftcards(int idx)
+static void HiSax_shiftcards(int idx)
{
int i;
@@ -1192,7 +1194,7 @@ void HiSax_shiftcards(int idx)
memcpy(&cards[i], &cards[i + 1], sizeof(cards[i]));
}
-int HiSax_inithardware(int *busy_flag)
+static int HiSax_inithardware(int *busy_flag)
{
int foundcards = 0;
int i = 0;
diff --git a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
index 394d481e093f..b62d6b30b72b 100644
--- a/drivers/isdn/hisax/diva.c
+++ b/drivers/isdn/hisax/diva.c
@@ -28,7 +28,7 @@
extern const char *CardType[];
-const char *Diva_revision = "$Revision: 1.33.2.6 $";
+static const char *Diva_revision = "$Revision: 1.33.2.6 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -706,7 +706,7 @@ diva_irq_ipacx_pci(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_diva(struct IsdnCardState *cs)
{
int bytecnt;
diff --git a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
index 4d7a0250d7e2..110e9fd669c5 100644
--- a/drivers/isdn/hisax/elsa.c
+++ b/drivers/isdn/hisax/elsa.c
@@ -33,13 +33,13 @@
extern const char *CardType[];
-const char *Elsa_revision = "$Revision: 2.32.2.4 $";
-const char *Elsa_Types[] =
+static const char *Elsa_revision = "$Revision: 2.32.2.4 $";
+static const char *Elsa_Types[] =
{"None", "PC", "PCC-8", "PCC-16", "PCF", "PCF-Pro",
"PCMCIA", "QS 1000", "QS 3000", "Microlink PCI", "QS 3000 PCI",
"PCMCIA-IPAC" };
-const char *ITACVer[] =
+static const char *ITACVer[] =
{"?0?", "?1?", "?2?", "?3?", "?4?", "V2.2",
"B1", "A1"};
@@ -425,7 +425,7 @@ Start_IPAC:
return IRQ_HANDLED;
}
-void
+static void
release_io_elsa(struct IsdnCardState *cs)
{
int bytecnt = 8;
diff --git a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c
index bfc013225f46..6fc6868de0b0 100644
--- a/drivers/isdn/hisax/elsa_cs.c
+++ b/drivers/isdn/hisax/elsa_cs.c
@@ -47,7 +47,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -212,11 +211,6 @@ static dev_link_t *elsa_cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &elsa_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -508,13 +502,22 @@ static int elsa_cs_event(event_t event, int priority,
return 0;
} /* elsa_cs_event */
+static struct pcmcia_device_id elsa_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", 0x983de2c4, 0x333ba257),
+ PCMCIA_DEVICE_PROD_ID12("ELSA GmbH, Aachen", "MicroLink ISDN/MC ", 0x639e5718, 0x333ba257),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, elsa_ids);
+
static struct pcmcia_driver elsa_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "elsa_cs",
},
.attach = elsa_cs_attach,
+ .event = elsa_cs_event,
.detach = elsa_cs_detach,
+ .id_table = elsa_ids,
};
static int __init init_elsa_cs(void)
diff --git a/drivers/isdn/hisax/elsa_ser.c b/drivers/isdn/hisax/elsa_ser.c
index 689c83395693..898ec0916195 100644
--- a/drivers/isdn/hisax/elsa_ser.c
+++ b/drivers/isdn/hisax/elsa_ser.c
@@ -237,7 +237,7 @@ static void mshutdown(struct IsdnCardState *cs)
#endif
}
-inline int
+static inline int
write_modem(struct BCState *bcs) {
int ret=0;
struct IsdnCardState *cs = bcs->cs;
@@ -275,7 +275,7 @@ write_modem(struct BCState *bcs) {
return(ret);
}
-inline void
+static inline void
modem_fill(struct BCState *bcs) {
if (bcs->tx_skb) {
@@ -422,7 +422,7 @@ extern int open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs);
extern void modehscx(struct BCState *bcs, int mode, int bc);
extern void hscx_l2l1(struct PStack *st, int pr, void *arg);
-void
+static void
close_elsastate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
@@ -442,7 +442,7 @@ close_elsastate(struct BCState *bcs)
}
}
-void
+static void
modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
int count, fp;
u_char *msg = buf;
@@ -472,7 +472,7 @@ modem_write_cmd(struct IsdnCardState *cs, u_char *buf, int len) {
}
}
-void
+static void
modem_set_init(struct IsdnCardState *cs) {
int timeout;
@@ -521,7 +521,7 @@ modem_set_init(struct IsdnCardState *cs) {
udelay(RCV_DELAY);
}
-void
+static void
modem_set_dial(struct IsdnCardState *cs, int outgoing) {
int timeout;
#define RCV_DELAY 20000
@@ -543,7 +543,7 @@ modem_set_dial(struct IsdnCardState *cs, int outgoing) {
udelay(RCV_DELAY);
}
-void
+static void
modem_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
@@ -579,7 +579,7 @@ modem_l2l1(struct PStack *st, int pr, void *arg)
}
}
-int
+static int
setstack_elsa(struct PStack *st, struct BCState *bcs)
{
@@ -614,7 +614,7 @@ setstack_elsa(struct PStack *st, struct BCState *bcs)
return (0);
}
-void
+static void
init_modem(struct IsdnCardState *cs) {
cs->bcs[0].BC_SetStack = setstack_elsa;
@@ -641,7 +641,7 @@ init_modem(struct IsdnCardState *cs) {
modem_set_init(cs);
}
-void
+static void
release_modem(struct IsdnCardState *cs) {
cs->hw.elsa.MFlag = 0;
diff --git a/drivers/isdn/hisax/enternow.h b/drivers/isdn/hisax/enternow.h
deleted file mode 100644
index ed2eec5874c5..000000000000
--- a/drivers/isdn/hisax/enternow.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/* 2001/10/02
- *
- * enternow.h Header-file included by
- * enternow_pci.c
- *
- * Author Christoph Ersfeld <info@formula-n.de>
- * Formula-n Europe AG (www.formula-n.com)
- * previously Gerdes AG
- *
- *
- * This file is (c) under GNU PUBLIC LICENSE
- */
-
-
-/* ***************************************************************************************** *
- * ****************************** datatypes and macros ************************************* *
- * ***************************************************************************************** */
-
-#define BYTE unsigned char
-#define WORD unsigned int
-#define HIBYTE(w) ((unsigned char)((w & 0xff00) / 256))
-#define LOBYTE(w) ((unsigned char)(w & 0x00ff))
-#define InByte(addr) inb(addr)
-#define OutByte(addr,val) outb(val,addr)
-
-
-
-/* ***************************************************************************************** *
- * *********************************** card-specific *************************************** *
- * ***************************************************************************************** */
-
-/* für PowerISDN PCI */
-#define TJ_AMD_IRQ 0x20
-#define TJ_LED1 0x40
-#define TJ_LED2 0x80
-
-
-/* Das Fenster zum AMD...
- * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
- * den TigerJet i/o-Raum gemappt
- * -> 0x01 des AMD bei hw.njet.base + 0C4 */
-#define TJ_AMD_PORT 0xC0
-
-
-
-/* ***************************************************************************************** *
- * *************************************** Prototypen ************************************** *
- * ***************************************************************************************** */
-
-BYTE ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset);
-void WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value);
diff --git a/drivers/isdn/hisax/enternow_pci.c b/drivers/isdn/hisax/enternow_pci.c
index 1cc4d11e007a..3341cf155531 100644
--- a/drivers/isdn/hisax/enternow_pci.c
+++ b/drivers/isdn/hisax/enternow_pci.c
@@ -65,7 +65,6 @@
#include "isac.h"
#include "isdnl1.h"
#include "amd7930_fn.h"
-#include "enternow.h"
#include <linux/interrupt.h>
#include <linux/ppp_defs.h>
#include <linux/pci.h>
@@ -74,58 +73,72 @@
-const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
+static const char *enternow_pci_rev = "$Revision: 1.1.4.5 $";
+
+
+/* für PowerISDN PCI */
+#define TJ_AMD_IRQ 0x20
+#define TJ_LED1 0x40
+#define TJ_LED2 0x80
+
+
+/* Das Fenster zum AMD...
+ * Ab Adresse hw.njet.base + TJ_AMD_PORT werden vom AMD jeweils 8 Bit in
+ * den TigerJet i/o-Raum gemappt
+ * -> 0x01 des AMD bei hw.njet.base + 0C4 */
+#define TJ_AMD_PORT 0xC0
+
/* *************************** I/O-Interface functions ************************************* */
/* cs->readisac, macro rByteAMD */
-BYTE
-ReadByteAmd7930(struct IsdnCardState *cs, BYTE offset)
+static unsigned char
+ReadByteAmd7930(struct IsdnCardState *cs, unsigned char offset)
{
/* direktes Register */
if(offset < 8)
- return (InByte(cs->hw.njet.isac + 4*offset));
+ return (inb(cs->hw.njet.isac + 4*offset));
/* indirektes Register */
else {
- OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
- return(InByte(cs->hw.njet.isac + 4*AMD_DR));
+ outb(offset, cs->hw.njet.isac + 4*AMD_CR);
+ return(inb(cs->hw.njet.isac + 4*AMD_DR));
}
}
/* cs->writeisac, macro wByteAMD */
-void
-WriteByteAmd7930(struct IsdnCardState *cs, BYTE offset, BYTE value)
+static void
+WriteByteAmd7930(struct IsdnCardState *cs, unsigned char offset, unsigned char value)
{
/* direktes Register */
if(offset < 8)
- OutByte(cs->hw.njet.isac + 4*offset, value);
+ outb(value, cs->hw.njet.isac + 4*offset);
/* indirektes Register */
else {
- OutByte(cs->hw.njet.isac + 4*AMD_CR, offset);
- OutByte(cs->hw.njet.isac + 4*AMD_DR, value);
+ outb(offset, cs->hw.njet.isac + 4*AMD_CR);
+ outb(value, cs->hw.njet.isac + 4*AMD_DR);
}
}
-void
-enpci_setIrqMask(struct IsdnCardState *cs, BYTE val) {
+static void
+enpci_setIrqMask(struct IsdnCardState *cs, unsigned char val) {
if (!val)
- OutByte(cs->hw.njet.base+NETJET_IRQMASK1, 0x00);
+ outb(0x00, cs->hw.njet.base+NETJET_IRQMASK1);
else
- OutByte(cs->hw.njet.base+NETJET_IRQMASK1, TJ_AMD_IRQ);
+ outb(TJ_AMD_IRQ, cs->hw.njet.base+NETJET_IRQMASK1);
}
-static BYTE dummyrr(struct IsdnCardState *cs, int chan, BYTE off)
+static unsigned char dummyrr(struct IsdnCardState *cs, int chan, unsigned char off)
{
return(5);
}
-static void dummywr(struct IsdnCardState *cs, int chan, BYTE off, BYTE value)
+static void dummywr(struct IsdnCardState *cs, int chan, unsigned char off, unsigned char value)
{
}
@@ -142,18 +155,18 @@ reset_enpci(struct IsdnCardState *cs)
/* Reset on, (also for AMD) */
cs->hw.njet.ctrl_reg = 0x07;
- OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(20);
/* Reset off */
cs->hw.njet.ctrl_reg = 0x30;
- OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20ms delay */
mdelay(20);
cs->hw.njet.auxd = 0; // LED-status
cs->hw.njet.dmactrl = 0;
- OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
- OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
- OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd); // LED off
+ outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+ outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+ outb(cs->hw.njet.auxd, cs->hw.njet.auxa); // LED off
}
@@ -161,7 +174,7 @@ static int
enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
u_long flags;
- BYTE *chan;
+ unsigned char *chan;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: card_msg: 0x%04X", mt);
@@ -187,16 +200,16 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
case MDL_ASSIGN:
/* TEI assigned, LED1 on */
cs->hw.njet.auxd = TJ_AMD_IRQ << 1;
- OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+ outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_REMOVE:
/* TEI removed, LEDs off */
cs->hw.njet.auxd = 0;
- OutByte(cs->hw.njet.base + NETJET_AUXDATA, 0x00);
+ outb(0x00, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_ASSIGN:
/* activate B-channel */
- chan = (BYTE *)arg;
+ chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: assign phys. BC %d in AMD LMR1", *chan);
@@ -204,11 +217,11 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
cs->dc.amd7930.ph_command(cs, (cs->dc.amd7930.lmr1 | (*chan + 1)), "MDL_BC_ASSIGN");
/* at least one b-channel in use, LED 2 on */
cs->hw.njet.auxd |= TJ_AMD_IRQ << 2;
- OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+ outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
break;
case MDL_BC_RELEASE:
/* deactivate B-channel */
- chan = (BYTE *)arg;
+ chan = (unsigned char *)arg;
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "enter:now PCI: release phys. BC %d in Amd LMR1", *chan);
@@ -217,7 +230,7 @@ enpci_card_msg(struct IsdnCardState *cs, int mt, void *arg)
/* no b-channel active -> LED2 off */
if (!(cs->dc.amd7930.lmr1 & 3)) {
cs->hw.njet.auxd &= ~(TJ_AMD_IRQ << 2);
- OutByte(cs->hw.njet.base + NETJET_AUXDATA, cs->hw.njet.auxd);
+ outb(cs->hw.njet.auxd, cs->hw.njet.base + NETJET_AUXDATA);
}
break;
default:
@@ -231,11 +244,11 @@ static irqreturn_t
enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
- BYTE s0val, s1val, ir;
+ unsigned char s0val, s1val, ir;
u_long flags;
spin_lock_irqsave(&cs->lock, flags);
- s1val = InByte(cs->hw.njet.base + NETJET_IRQSTAT1);
+ s1val = inb(cs->hw.njet.base + NETJET_IRQSTAT1);
/* AMD threw an interrupt */
if (!(s1val & TJ_AMD_IRQ)) {
@@ -245,13 +258,13 @@ enpci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
s1val = 1;
} else
s1val = 0;
- s0val = InByte(cs->hw.njet.base + NETJET_IRQSTAT0);
+ s0val = inb(cs->hw.njet.base + NETJET_IRQSTAT0);
if ((s0val | s1val)==0) { // shared IRQ
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_NONE;
}
if (s0val)
- OutByte(cs->hw.njet.base + NETJET_IRQSTAT0, s0val);
+ outb(s0val, cs->hw.njet.base + NETJET_IRQSTAT0);
/* DMA-Interrupt: B-channel-stuff */
/* set bits in sval to indicate which page is free */
@@ -342,20 +355,20 @@ setup_enternow_pci(struct IsdnCard *card)
/* Reset an */
cs->hw.njet.ctrl_reg = 0x07; // geändert von 0xff
- OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
/* 20 ms Pause */
mdelay(20);
cs->hw.njet.ctrl_reg = 0x30; /* Reset Off and status read clear */
- OutByte(cs->hw.njet.base + NETJET_CTRL, cs->hw.njet.ctrl_reg);
+ outb(cs->hw.njet.ctrl_reg, cs->hw.njet.base + NETJET_CTRL);
mdelay(10);
cs->hw.njet.auxd = 0x00; // war 0xc0
cs->hw.njet.dmactrl = 0;
- OutByte(cs->hw.njet.base + NETJET_AUXCTRL, ~TJ_AMD_IRQ);
- OutByte(cs->hw.njet.base + NETJET_IRQMASK1, TJ_AMD_IRQ);
- OutByte(cs->hw.njet.auxa, cs->hw.njet.auxd);
+ outb(~TJ_AMD_IRQ, cs->hw.njet.base + NETJET_AUXCTRL);
+ outb(TJ_AMD_IRQ, cs->hw.njet.base + NETJET_IRQMASK1);
+ outb(cs->hw.njet.auxd, cs->hw.njet.auxa);
break;
}
diff --git a/drivers/isdn/hisax/gazel.c b/drivers/isdn/hisax/gazel.c
index 24a05a43f33e..352b45ac5347 100644
--- a/drivers/isdn/hisax/gazel.c
+++ b/drivers/isdn/hisax/gazel.c
@@ -21,7 +21,7 @@
#include <linux/pci.h>
extern const char *CardType[];
-const char *gazel_revision = "$Revision: 2.19.2.4 $";
+static const char *gazel_revision = "$Revision: 2.19.2.4 $";
#define R647 1
#define R685 2
@@ -317,7 +317,8 @@ gazel_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
spin_unlock_irqrestore(&cs->lock, flags);
return IRQ_HANDLED;
}
-void
+
+static void
release_io_gazel(struct IsdnCardState *cs)
{
unsigned int i;
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index ba1d028343ec..7333377ab31d 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -312,7 +312,7 @@ wait_busy(hfc4s8s_hw * a)
/* function to read critical counter registers that */
/* may be udpated by the chip during read */
/******************************************************/
-static volatile u_char
+static u_char
Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
{
u_char ref8;
@@ -324,7 +324,7 @@ Read_hfc8_stable(hfc4s8s_hw * hw, int reg)
return in8;
}
-static volatile int
+static int
Read_hfc16_stable(hfc4s8s_hw * hw, int reg)
{
int ref16;
@@ -1358,7 +1358,7 @@ chipreset(hfc4s8s_hw * hw)
/********************************************/
/* disable/enable hardware in nt or te mode */
/********************************************/
-void
+static void
hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
{
u_long flags;
@@ -1465,7 +1465,7 @@ hfc_hardware_enable(hfc4s8s_hw * hw, int enable, int nt_mode)
/******************************************/
/* disable memory mapped ports / io ports */
/******************************************/
-void
+static void
release_pci_ports(hfc4s8s_hw * hw)
{
pci_write_config_word(hw->pdev, PCI_COMMAND, 0);
@@ -1481,7 +1481,7 @@ release_pci_ports(hfc4s8s_hw * hw)
/*****************************************/
/* enable memory mapped ports / io ports */
/*****************************************/
-void
+static void
enable_pci_ports(hfc4s8s_hw * hw)
{
#ifdef CONFIG_HISAX_HFC4S8S_PCIMEM
diff --git a/drivers/isdn/hisax/hfc_2bds0.c b/drivers/isdn/hisax/hfc_2bds0.c
index ebea3feef003..7cf87793e790 100644
--- a/drivers/isdn/hisax/hfc_2bds0.c
+++ b/drivers/isdn/hisax/hfc_2bds0.c
@@ -345,7 +345,7 @@ hfc_send_data(struct BCState *bcs)
debugl1(cs,"send_data %d blocked", bcs->channel);
}
-void
+static void
main_rec_2bds0(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
@@ -399,7 +399,7 @@ main_rec_2bds0(struct BCState *bcs)
return;
}
-void
+static void
mode_2bs0(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -505,7 +505,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
close_2bs0(struct BCState *bcs)
{
mode_2bs0(bcs, 0, bcs->channel);
@@ -534,7 +534,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_2b(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
@@ -1004,7 +1004,7 @@ HFCD_l1hw(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
setstack_hfcd(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = HFCD_l1hw;
@@ -1015,7 +1015,7 @@ hfc_dbusy_timer(struct IsdnCardState *cs)
{
}
-unsigned int __init
+static unsigned int __init
*init_send_hfcd(int cnt)
{
int i, *send;
diff --git a/drivers/isdn/hisax/hfc_2bs0.c b/drivers/isdn/hisax/hfc_2bs0.c
index bb376f39ac89..f978a5af8662 100644
--- a/drivers/isdn/hisax/hfc_2bs0.c
+++ b/drivers/isdn/hisax/hfc_2bs0.c
@@ -52,7 +52,7 @@ WaitNoBusy(struct IsdnCardState *cs)
return (to);
}
-int
+static int
GetFreeFifoBytes(struct BCState *bcs)
{
int s;
@@ -66,7 +66,7 @@ GetFreeFifoBytes(struct BCState *bcs)
return (s);
}
-int
+static int
ReadZReg(struct BCState *bcs, u_char reg)
{
int val;
@@ -394,7 +394,7 @@ main_irq_hfc(struct BCState *bcs)
return;
}
-void
+static void
mode_hfc(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -507,7 +507,7 @@ hfc_l2l1(struct PStack *st, int pr, void *arg)
}
-void
+static void
close_hfcstate(struct BCState *bcs)
{
mode_hfc(bcs, 0, bcs->channel);
@@ -537,7 +537,7 @@ open_hfcstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_hfc(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
@@ -551,7 +551,7 @@ setstack_hfc(struct PStack *st, struct BCState *bcs)
return (0);
}
-void __init
+static void __init
init_send(struct BCState *bcs)
{
int i;
diff --git a/drivers/isdn/hisax/hfc_pci.c b/drivers/isdn/hisax/hfc_pci.c
index c2db52696a86..8337b0f26cc4 100644
--- a/drivers/isdn/hisax/hfc_pci.c
+++ b/drivers/isdn/hisax/hfc_pci.c
@@ -70,7 +70,7 @@ static const PCI_ENTRY id_list[] =
/******************************************/
/* free hardware resources used by driver */
/******************************************/
-void
+static void
release_io_hfcpci(struct IsdnCardState *cs)
{
printk(KERN_INFO "HiSax: release hfcpci at %p\n",
@@ -394,7 +394,7 @@ receive_dmsg(struct IsdnCardState *cs)
/*******************************************************************************/
/* check for transparent receive data and read max one threshold size if avail */
/*******************************************************************************/
-int
+static int
hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
{
unsigned short *z1r, *z2r;
@@ -446,7 +446,7 @@ hfcpci_empty_fifo_trans(struct BCState *bcs, bzfifo_type * bz, u_char * bdata)
/**********************************/
/* B-channel main receive routine */
/**********************************/
-void
+static void
main_rec_hfcpci(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
@@ -1244,7 +1244,7 @@ HFCPCI_l1hw(struct PStack *st, int pr, void *arg)
/***********************************************/
/* called during init setting l1 stack pointer */
/***********************************************/
-void
+static void
setstack_hfcpci(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = HFCPCI_l1hw;
@@ -1268,7 +1268,7 @@ hfcpci_send_data(struct BCState *bcs)
/***************************************************************/
/* activate/deactivate hardware for selected channels and mode */
/***************************************************************/
-void
+static void
mode_hfcpci(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -1579,7 +1579,7 @@ hfcpci_bh(struct IsdnCardState *cs)
/********************************/
/* called for card init message */
/********************************/
-void __init
+static void __init
inithfcpci(struct IsdnCardState *cs)
{
cs->bcs[0].BC_SetStack = setstack_2b;
diff --git a/drivers/isdn/hisax/hfc_pci.h b/drivers/isdn/hisax/hfc_pci.h
index 4df036ed1af0..9ef2981e404e 100644
--- a/drivers/isdn/hisax/hfc_pci.h
+++ b/drivers/isdn/hisax/hfc_pci.h
@@ -232,5 +232,4 @@ typedef union {
#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
extern void main_irq_hcpci(struct BCState *bcs);
-extern void inithfcpci(struct IsdnCardState *cs);
extern void releasehfcpci(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_sx.c b/drivers/isdn/hisax/hfc_sx.c
index a307fcb6c634..f27c1608a3a7 100644
--- a/drivers/isdn/hisax/hfc_sx.c
+++ b/drivers/isdn/hisax/hfc_sx.c
@@ -308,7 +308,7 @@ read_fifo(struct IsdnCardState *cs, u_char fifo, int trans_max)
/******************************************/
/* free hardware resources used by driver */
/******************************************/
-void
+static void
release_io_hfcsx(struct IsdnCardState *cs)
{
cs->hw.hfcsx.int_m2 = 0; /* interrupt output off ! */
@@ -472,7 +472,7 @@ receive_dmsg(struct IsdnCardState *cs)
/**********************************/
/* B-channel main receive routine */
/**********************************/
-void
+static void
main_rec_hfcsx(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
@@ -1003,7 +1003,7 @@ HFCSX_l1hw(struct PStack *st, int pr, void *arg)
/***********************************************/
/* called during init setting l1 stack pointer */
/***********************************************/
-void
+static void
setstack_hfcsx(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = HFCSX_l1hw;
@@ -1027,7 +1027,7 @@ hfcsx_send_data(struct BCState *bcs)
/***************************************************************/
/* activate/deactivate hardware for selected channels and mode */
/***************************************************************/
-void
+static void
mode_hfcsx(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -1328,7 +1328,7 @@ hfcsx_bh(struct IsdnCardState *cs)
/********************************/
/* called for card init message */
/********************************/
-void __devinit
+static void __devinit
inithfcsx(struct IsdnCardState *cs)
{
cs->setstack_d = setstack_hfcsx;
diff --git a/drivers/isdn/hisax/hfc_sx.h b/drivers/isdn/hisax/hfc_sx.h
index 12f54159344a..6792f13dc220 100644
--- a/drivers/isdn/hisax/hfc_sx.h
+++ b/drivers/isdn/hisax/hfc_sx.h
@@ -193,5 +193,4 @@ struct hfcsx_extra {
};
extern void main_irq_hfcsx(struct BCState *bcs);
-extern void inithfcsx(struct IsdnCardState *cs);
extern void releasehfcsx(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hfc_usb.c b/drivers/isdn/hisax/hfc_usb.c
index ffd74b84f502..e2c3af49d72b 100644
--- a/drivers/isdn/hisax/hfc_usb.c
+++ b/drivers/isdn/hisax/hfc_usb.c
@@ -60,7 +60,7 @@ static const char *hfcusb_revision =
#include "hisax_debug.h"
static u_int debug;
module_param(debug, uint, 0);
-int hfc_debug;
+static int hfc_debug;
#endif
@@ -85,7 +85,7 @@ static struct usb_device_id hfc_usb_idtab[] = {
* VendorID, ProductID, Devicename, LED_SCHEME,
* LED's BitMask in HFCUSB_P_DATA Register : LED_USB, LED_S0, LED_B1, LED_B2
*/
-vendor_data vdata[] = {
+static vendor_data vdata[] = {
/* CologneChip Eval TA */
{0x0959, 0x2bd0, "ISDN USB TA (Cologne Chip HFC-S USB based)",
LED_OFF, {4, 0, 2, 1}
@@ -1137,7 +1137,7 @@ set_hfcmode(hfcusb_data * hfc, int channel, int mode)
}
}
-void
+static void
hfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg)
{
usb_fifo *fifo = my_hisax_if->priv;
diff --git a/drivers/isdn/hisax/hfc_usb.h b/drivers/isdn/hisax/hfc_usb.h
index b171600cf641..280dd29b30d6 100644
--- a/drivers/isdn/hisax/hfc_usb.h
+++ b/drivers/isdn/hisax/hfc_usb.h
@@ -168,7 +168,7 @@ static struct hfcusb_symbolic_list urb_errlist[] = {
* 3 entries are the configuration number, the minimum interval for
* Interrupt endpoints & boolean if E-channel logging possible
*/
-int validconf[][19] = {
+static int validconf[][19] = {
// INT in, ISO out config
{EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NUL, EP_INT, EP_NOP, EP_INT,
EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_ISO, EP_NUL, EP_NUL, EP_NUL,
@@ -187,7 +187,7 @@ int validconf[][19] = {
};
// string description of chosen config
-char *conf_str[] = {
+static char *conf_str[] = {
"4 Interrupt IN + 3 Isochron OUT",
"3 Interrupt IN + 3 Isochron OUT",
"4 Isochron IN + 3 Isochron OUT",
diff --git a/drivers/isdn/hisax/hfcscard.c b/drivers/isdn/hisax/hfcscard.c
index 6fc55fea1702..86ab1c13f6b1 100644
--- a/drivers/isdn/hisax/hfcscard.c
+++ b/drivers/isdn/hisax/hfcscard.c
@@ -52,7 +52,7 @@ hfcs_Timer(struct IsdnCardState *cs)
*/
}
-void
+static void
release_io_hfcs(struct IsdnCardState *cs)
{
release2bds0(cs);
diff --git a/drivers/isdn/hisax/hisax.h b/drivers/isdn/hisax/hisax.h
index dc5791728d53..17cf7663c582 100644
--- a/drivers/isdn/hisax/hisax.h
+++ b/drivers/isdn/hisax/hisax.h
@@ -1271,7 +1271,6 @@ extern void Logl2Frame(struct IsdnCardState *cs, struct sk_buff *skb, char *buf,
void init_bcstate(struct IsdnCardState *cs, int bc);
void setstack_HiSax(struct PStack *st, struct IsdnCardState *cs);
-unsigned int random_ri(void);
void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
@@ -1315,15 +1314,11 @@ int QuickHex(char *txt, u_char * p, int cnt);
void LogFrame(struct IsdnCardState *cs, u_char * p, int size);
void dlogframe(struct IsdnCardState *cs, struct sk_buff *skb, int dir);
void iecpy(u_char * dest, u_char * iestart, int ieoffset);
-#ifdef ISDN_CHIP_ISAC
-void setstack_isac(struct PStack *st, struct IsdnCardState *cs);
-#endif /* ISDN_CHIP_ISAC */
#endif /* __KERNEL__ */
#define HZDELAY(jiffs) {int tout = jiffs; while (tout--) udelay(1000000/HZ);}
int ll_run(struct IsdnCardState *cs, int addfeatures);
-void ll_stop(struct IsdnCardState *cs);
int CallcNew(void);
void CallcFree(void);
int CallcNewChan(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/hscx.c b/drivers/isdn/hisax/hscx.c
index 5bbbe3e95125..66dbaee77bfb 100644
--- a/drivers/isdn/hisax/hscx.c
+++ b/drivers/isdn/hisax/hscx.c
@@ -151,7 +151,7 @@ hscx_l2l1(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
close_hscxstate(struct BCState *bcs)
{
modehscx(bcs, 0, bcs->channel);
@@ -203,7 +203,7 @@ open_hscxstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_hscx(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
diff --git a/drivers/isdn/hisax/icc.c b/drivers/isdn/hisax/icc.c
index dcf31f83c600..b4ca5859b177 100644
--- a/drivers/isdn/hisax/icc.c
+++ b/drivers/isdn/hisax/icc.c
@@ -108,7 +108,7 @@ icc_bh(struct IsdnCardState *cs)
#endif
}
-void
+static void
icc_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
@@ -563,13 +563,13 @@ ICC_l1hw(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
setstack_icc(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ICC_l1hw;
}
-void
+static void
DC_Close_icc(struct IsdnCardState *cs) {
if (cs->dc.icc.mon_rx) {
kfree(cs->dc.icc.mon_rx);
diff --git a/drivers/isdn/hisax/ipacx.c b/drivers/isdn/hisax/ipacx.c
index 6485e232d869..efba2f448017 100644
--- a/drivers/isdn/hisax/ipacx.c
+++ b/drivers/isdn/hisax/ipacx.c
@@ -36,8 +36,6 @@ static void ph_command(struct IsdnCardState *cs, unsigned int command);
static inline void cic_int(struct IsdnCardState *cs);
static void dch_l2l1(struct PStack *st, int pr, void *arg);
static void dbusy_timer_handler(struct IsdnCardState *cs);
-static void ipacx_new_ph(struct IsdnCardState *cs);
-static void dch_bh(struct IsdnCardState *cs);
static void dch_empty_fifo(struct IsdnCardState *cs, int count);
static void dch_fill_fifo(struct IsdnCardState *cs);
static inline void dch_int(struct IsdnCardState *cs);
@@ -232,81 +230,6 @@ dbusy_timer_handler(struct IsdnCardState *cs)
}
//----------------------------------------------------------
-// L1 state machine intermediate layer to isdnl1 module
-//----------------------------------------------------------
-static void
-ipacx_new_ph(struct IsdnCardState *cs)
-{
- switch (cs->dc.isac.ph_state) {
- case (IPACX_IND_RES):
- ph_command(cs, IPACX_CMD_DI);
- l1_msg(cs, HW_RESET | INDICATION, NULL);
- break;
-
- case (IPACX_IND_DC):
- l1_msg(cs, HW_DEACTIVATE | CONFIRM, NULL);
- break;
-
- case (IPACX_IND_DR):
- l1_msg(cs, HW_DEACTIVATE | INDICATION, NULL);
- break;
-
- case (IPACX_IND_PU):
- l1_msg(cs, HW_POWERUP | CONFIRM, NULL);
- break;
-
- case (IPACX_IND_RSY):
- l1_msg(cs, HW_RSYNC | INDICATION, NULL);
- break;
-
- case (IPACX_IND_AR):
- l1_msg(cs, HW_INFO2 | INDICATION, NULL);
- break;
-
- case (IPACX_IND_AI8):
- l1_msg(cs, HW_INFO4_P8 | INDICATION, NULL);
- break;
-
- case (IPACX_IND_AI10):
- l1_msg(cs, HW_INFO4_P10 | INDICATION, NULL);
- break;
-
- default:
- break;
- }
-}
-
-//----------------------------------------------------------
-// bottom half handler for D channel
-//----------------------------------------------------------
-static void
-dch_bh(struct IsdnCardState *cs)
-{
- struct PStack *st;
-
- if (!cs) return;
-
- if (test_and_clear_bit(D_CLEARBUSY, &cs->event)) {
- if (cs->debug) debugl1(cs, "D-Channel Busy cleared");
- for (st = cs->stlist; st; st = st->next) {
- st->l1.l1l2(st, PH_PAUSE | CONFIRM, NULL);
- }
- }
-
- if (test_and_clear_bit(D_RCVBUFREADY, &cs->event)) {
- DChannel_proc_rcv(cs);
- }
-
- if (test_and_clear_bit(D_XMTBUFREADY, &cs->event)) {
- DChannel_proc_xmt(cs);
- }
-
- if (test_and_clear_bit(D_L1STATECHANGE, &cs->event)) {
- ipacx_new_ph(cs);
- }
-}
-
-//----------------------------------------------------------
// Fill buffer from receive FIFO
//----------------------------------------------------------
static void
@@ -991,14 +914,5 @@ init_ipacx(struct IsdnCardState *cs, int part)
}
}
-
-void __devinit
-setup_ipacx(struct IsdnCardState *cs)
-{
- INIT_WORK(&cs->tqueue, (void *)(void *) dch_bh, cs);
- cs->dbusytimer.function = (void *) dbusy_timer_handler;
- cs->dbusytimer.data = (long) cs;
- init_timer(&cs->dbusytimer);
-}
//----------------- end of file -----------------------
diff --git a/drivers/isdn/hisax/isac.c b/drivers/isdn/hisax/isac.c
index 20b949952952..85e063a08d23 100644
--- a/drivers/isdn/hisax/isac.c
+++ b/drivers/isdn/hisax/isac.c
@@ -112,7 +112,7 @@ isac_bh(struct IsdnCardState *cs)
#endif
}
-void
+static void
isac_empty_fifo(struct IsdnCardState *cs, int count)
{
u_char *ptr;
@@ -563,13 +563,13 @@ ISAC_l1hw(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
setstack_isac(struct PStack *st, struct IsdnCardState *cs)
{
st->l1.l1hw = ISAC_l1hw;
}
-void
+static void
DC_Close_isac(struct IsdnCardState *cs) {
if (cs->dc.isac.mon_rx) {
kfree(cs->dc.isac.mon_rx);
diff --git a/drivers/isdn/hisax/isar.c b/drivers/isdn/hisax/isar.c
index ee081321efb2..642a87c51295 100644
--- a/drivers/isdn/hisax/isar.c
+++ b/drivers/isdn/hisax/isar.c
@@ -21,13 +21,13 @@
#define ETX 0x03
#define FAXMODCNT 13
-const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
+static const u_char faxmodulation[] = {3,24,48,72,73,74,96,97,98,121,122,145,146};
static u_int modmask = 0x1fff;
static int frm_extra_delay = 2;
static int para_TOA = 6;
-const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
+static const u_char *FC1_CMD[] = {"FAE", "FTS", "FRS", "FTM", "FRM", "FTH", "FRH", "CTRL" };
-void isar_setup(struct IsdnCardState *cs);
+static void isar_setup(struct IsdnCardState *cs);
static void isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para);
static void ll_deliver_faxstat(struct BCState *bcs, u_char status);
@@ -45,7 +45,7 @@ waitforHIA(struct IsdnCardState *cs, int timeout)
}
-int
+static int
sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
u_char *msg)
{
@@ -85,7 +85,7 @@ sendmsg(struct IsdnCardState *cs, u_char his, u_char creg, u_char len,
}
/* Call only with IRQ disabled !!! */
-inline void
+static inline void
rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
{
int i;
@@ -114,7 +114,7 @@ rcv_mbox(struct IsdnCardState *cs, struct isar_reg *ireg, u_char *msg)
}
/* Call only with IRQ disabled !!! */
-inline void
+static inline void
get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
{
ireg->iis = cs->BC_Read_Reg(cs, 1, ISAR_IIS);
@@ -127,7 +127,7 @@ get_irq_infos(struct IsdnCardState *cs, struct isar_reg *ireg)
#endif
}
-int
+static int
waitrecmsg(struct IsdnCardState *cs, u_char *len,
u_char *msg, int maxdelay)
{
@@ -185,7 +185,7 @@ ISARVersion(struct IsdnCardState *cs, char *s)
return(ver);
}
-int
+static int
isar_load_firmware(struct IsdnCardState *cs, u_char __user *buf)
{
int ret, size, cnt, debug;
@@ -739,7 +739,7 @@ isar_fill_fifo(struct BCState *bcs)
}
}
-inline
+static inline
struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
{
if ((!dpath) || (dpath == 3))
@@ -751,7 +751,7 @@ struct BCState *sel_bcs_isar(struct IsdnCardState *cs, u_char dpath)
return(NULL);
}
-void
+static void
send_frames(struct BCState *bcs)
{
if (bcs->tx_skb) {
@@ -806,7 +806,7 @@ send_frames(struct BCState *bcs)
}
}
-inline void
+static inline void
check_send(struct IsdnCardState *cs, u_char rdm)
{
struct BCState *bcs;
@@ -828,11 +828,13 @@ check_send(struct IsdnCardState *cs, u_char rdm)
}
-const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200", "NODEF4",
- "300", "600", "1200", "2400", "4800", "7200",
- "9600nt", "9600t", "12000", "14400", "WRONG"};
-const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
- "Bell103", "V23", "Bell202", "V17", "V29", "V27ter"};
+static const char *dmril[] = {"NO SPEED", "1200/75", "NODEF2", "75/1200",
+ "NODEF4", "300", "600", "1200", "2400",
+ "4800", "7200", "9600nt", "9600t", "12000",
+ "14400", "WRONG"};
+static const char *dmrim[] = {"NO MOD", "NO DEF", "V32/V32b", "V22", "V21",
+ "Bell103", "V23", "Bell202", "V17", "V29",
+ "V27ter"};
static void
isar_pump_status_rsp(struct BCState *bcs, struct isar_reg *ireg) {
@@ -1388,7 +1390,7 @@ setup_iom2(struct BCState *bcs) {
udelay(1000);
}
-int
+static int
modeisar(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -1562,7 +1564,7 @@ isar_pump_cmd(struct BCState *bcs, u_char cmd, u_char para)
sendmsg(cs, dps | ISAR_HIS_PUMPCTRL, ctrl, nom, &p1);
}
-void
+static void
isar_setup(struct IsdnCardState *cs)
{
u_char msg;
@@ -1582,7 +1584,7 @@ isar_setup(struct IsdnCardState *cs)
}
}
-void
+static void
isar_l2l1(struct PStack *st, int pr, void *arg)
{
struct BCState *bcs = st->l1.bcs;
@@ -1681,7 +1683,7 @@ isar_l2l1(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
close_isarstate(struct BCState *bcs)
{
modeisar(bcs, 0, bcs->channel);
@@ -1703,7 +1705,7 @@ close_isarstate(struct BCState *bcs)
del_timer(&bcs->hw.isar.ftimer);
}
-int
+static int
open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
@@ -1725,7 +1727,7 @@ open_isarstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_isar(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
diff --git a/drivers/isdn/hisax/isdnl1.c b/drivers/isdn/hisax/isdnl1.c
index 4d08d27f1499..bab356886483 100644
--- a/drivers/isdn/hisax/isdnl1.c
+++ b/drivers/isdn/hisax/isdnl1.c
@@ -151,7 +151,7 @@ l1m_debug(struct FsmInst *fi, char *fmt, ...)
va_end(args);
}
-void
+static void
L1activated(struct IsdnCardState *cs)
{
struct PStack *st;
@@ -166,7 +166,7 @@ L1activated(struct IsdnCardState *cs)
}
}
-void
+static void
L1deactivated(struct IsdnCardState *cs)
{
struct PStack *st;
@@ -279,7 +279,8 @@ BChannel_proc_xmt(struct BCState *bcs)
if (test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags))
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
if (!test_bit(BC_FLG_ACTIV, &bcs->Flag)) {
- if (!test_bit(BC_FLG_BUSY, &bcs->Flag) && (!skb_queue_len(&bcs->squeue))) {
+ if (!test_bit(BC_FLG_BUSY, &bcs->Flag) &&
+ skb_queue_empty(&bcs->squeue)) {
st->l2.l2l1(st, PH_DEACTIVATE | CONFIRM, NULL);
}
}
@@ -370,7 +371,7 @@ init_bcstate(struct IsdnCardState *cs, int bc)
#ifdef L2FRAME_DEBUG /* psa */
-char *
+static char *
l2cmd(u_char cmd)
{
switch (cmd & ~0x10) {
@@ -404,7 +405,7 @@ l2cmd(u_char cmd)
static char tmpdeb[32];
-char *
+static char *
l2frames(u_char * ptr)
{
switch (ptr[2] & ~0x10) {
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index d311b5fbf895..1615c1a76ab8 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -108,7 +108,8 @@ static int l2addrsize(struct Layer2 *l2);
static void
set_peer_busy(struct Layer2 *l2) {
test_and_set_bit(FLG_PEER_BUSY, &l2->flag);
- if (skb_queue_len(&l2->i_queue) || skb_queue_len(&l2->ui_queue))
+ if (!skb_queue_empty(&l2->i_queue) ||
+ !skb_queue_empty(&l2->ui_queue))
test_and_set_bit(FLG_L2BLOCK, &l2->flag);
}
@@ -142,7 +143,7 @@ freewin1(struct Layer2 *l2)
return cnt;
}
-inline void
+static inline void
freewin(struct PStack *st)
{
freewin1(&st->l2);
@@ -157,7 +158,7 @@ ReleaseWin(struct Layer2 *l2)
printk(KERN_WARNING "isdl2 freed %d skbuffs in release\n", cnt);
}
-inline unsigned int
+static inline unsigned int
cansend(struct PStack *st)
{
unsigned int p1;
@@ -169,7 +170,7 @@ cansend(struct PStack *st)
return ((p1 < st->l2.window) && !test_bit(FLG_PEER_BUSY, &st->l2.flag));
}
-inline void
+static inline void
clear_exception(struct Layer2 *l2)
{
test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
@@ -178,7 +179,7 @@ clear_exception(struct Layer2 *l2)
clear_peer_busy(l2);
}
-inline int
+static inline int
l2headersize(struct Layer2 *l2, int ui)
{
return (((test_bit(FLG_MOD128, &l2->flag) && (!ui)) ? 2 : 1) +
@@ -223,40 +224,31 @@ enqueue_super(struct PStack *st,
#define enqueue_ui(a, b) enqueue_super(a, b)
-inline int
+static inline int
IsUI(u_char * data)
{
return ((data[0] & 0xef) == UI);
}
-inline int
+static inline int
IsUA(u_char * data)
{
return ((data[0] & 0xef) == UA);
}
-inline int
+static inline int
IsDM(u_char * data)
{
return ((data[0] & 0xef) == DM);
}
-inline int
+static inline int
IsDISC(u_char * data)
{
return ((data[0] & 0xef) == DISC);
}
-inline int
-IsRR(u_char * data, struct PStack *st)
-{
- if (test_bit(FLG_MOD128, &st->l2.flag))
- return (data[0] == RR);
- else
- return ((data[0] & 0xf) == 1);
-}
-
-inline int
+static inline int
IsSFrame(u_char * data, struct PStack *st)
{
register u_char d = *data;
@@ -266,7 +258,7 @@ IsSFrame(u_char * data, struct PStack *st)
return(((d & 0xf3) == 1) && ((d & 0x0c) != 0x0c));
}
-inline int
+static inline int
IsSABME(u_char * data, struct PStack *st)
{
u_char d = data[0] & ~0x10;
@@ -274,25 +266,25 @@ IsSABME(u_char * data, struct PStack *st)
return (test_bit(FLG_MOD128, &st->l2.flag) ? d == SABME : d == SABM);
}
-inline int
+static inline int
IsREJ(u_char * data, struct PStack *st)
{
return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == REJ : (data[0] & 0xf) == REJ);
}
-inline int
+static inline int
IsFRMR(u_char * data)
{
return ((data[0] & 0xef) == FRMR);
}
-inline int
+static inline int
IsRNR(u_char * data, struct PStack *st)
{
return (test_bit(FLG_MOD128, &st->l2.flag) ? data[0] == RNR : (data[0] & 0xf) == RNR);
}
-int
+static int
iframe_error(struct PStack *st, struct sk_buff *skb)
{
int i = l2addrsize(&st->l2) + (test_bit(FLG_MOD128, &st->l2.flag) ? 2 : 1);
@@ -315,7 +307,7 @@ iframe_error(struct PStack *st, struct sk_buff *skb)
return 0;
}
-int
+static int
super_error(struct PStack *st, struct sk_buff *skb)
{
if (skb->len != l2addrsize(&st->l2) +
@@ -325,7 +317,7 @@ super_error(struct PStack *st, struct sk_buff *skb)
return 0;
}
-int
+static int
unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
{
int rsp = (*skb->data & 0x2) >> 1;
@@ -341,7 +333,7 @@ unnum_error(struct PStack *st, struct sk_buff *skb, int wantrsp)
return 0;
}
-int
+static int
UI_error(struct PStack *st, struct sk_buff *skb)
{
int rsp = *skb->data & 0x2;
@@ -357,7 +349,7 @@ UI_error(struct PStack *st, struct sk_buff *skb)
return 0;
}
-int
+static int
FRMR_error(struct PStack *st, struct sk_buff *skb)
{
int headers = l2addrsize(&st->l2) + 1;
@@ -444,51 +436,44 @@ send_uframe(struct PStack *st, u_char cmd, u_char cr)
enqueue_super(st, skb);
}
-inline u_char
+static inline u_char
get_PollFlag(struct PStack * st, struct sk_buff * skb)
{
return (skb->data[l2addrsize(&(st->l2))] & 0x10);
}
-inline void
-FreeSkb(struct sk_buff *skb)
-{
- dev_kfree_skb(skb);
-}
-
-
-inline u_char
+static inline u_char
get_PollFlagFree(struct PStack *st, struct sk_buff *skb)
{
u_char PF;
PF = get_PollFlag(st, skb);
- FreeSkb(skb);
+ dev_kfree_skb(skb);
return (PF);
}
-inline void
+static inline void
start_t200(struct PStack *st, int i)
{
FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
}
-inline void
+static inline void
restart_t200(struct PStack *st, int i)
{
FsmRestartTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, i);
test_and_set_bit(FLG_T200_RUN, &st->l2.flag);
}
-inline void
+static inline void
stop_t200(struct PStack *st, int i)
{
if(test_and_clear_bit(FLG_T200_RUN, &st->l2.flag))
FsmDelTimer(&st->l2.t200, i);
}
-inline void
+static inline void
st5_dl_release_l2l3(struct PStack *st)
{
int pr;
@@ -501,7 +486,7 @@ st5_dl_release_l2l3(struct PStack *st)
st->l2.l2l3(st, pr, NULL);
}
-inline void
+static inline void
lapb_dl_release_l2l3(struct PStack *st, int f)
{
if (test_bit(FLG_LAPB, &st->l2.flag))
@@ -770,7 +755,7 @@ l2_restart_multi(struct FsmInst *fi, int event, void *arg)
st->l2.l2l3(st, DL_ESTABLISH | INDICATION, NULL);
if ((ST_L2_7==state) || (ST_L2_8 == state))
- if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+ if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
@@ -802,7 +787,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
l2_mdl_error_ua(fi, event, arg);
return;
}
- FreeSkb(skb);
+ dev_kfree_skb(skb);
if (test_and_clear_bit(FLG_PEND_REL, &st->l2.flag))
l2_disconnect(fi, event, arg);
@@ -826,7 +811,7 @@ l2_connected(struct FsmInst *fi, int event, void *arg)
if (pr != -1)
st->l2.l2l3(st, pr, NULL);
- if (skb_queue_len(&st->l2.i_queue) && cansend(st))
+ if (!skb_queue_empty(&st->l2.i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
@@ -840,7 +825,7 @@ l2_released(struct FsmInst *fi, int event, void *arg)
l2_mdl_error_ua(fi, event, arg);
return;
}
- FreeSkb(skb);
+ dev_kfree_skb(skb);
stop_t200(st, 6);
lapb_dl_release_l2l3(st, CONFIRM);
@@ -889,7 +874,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg)
}
}
-inline void
+static inline void
enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
{
struct sk_buff *skb;
@@ -912,7 +897,7 @@ enquiry_cr(struct PStack *st, u_char typ, u_char cr, u_char pf)
enqueue_super(st, skb);
}
-inline void
+static inline void
enquiry_response(struct PStack *st)
{
if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
@@ -922,7 +907,7 @@ enquiry_response(struct PStack *st)
test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
}
-inline void
+static inline void
transmit_enquiry(struct PStack *st)
{
if (test_bit(FLG_OWN_BUSY, &st->l2.flag))
@@ -1004,7 +989,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
PollFlag = (skb->data[0] & 0x10);
nr = (skb->data[0] >> 5) & 0x7;
}
- FreeSkb(skb);
+ dev_kfree_skb(skb);
if (PollFlag) {
if (rsp)
@@ -1030,7 +1015,7 @@ l2_st7_got_super(struct FsmInst *fi, int event, void *arg)
if(typ != RR) FsmDelTimer(&st->l2.t203, 9);
restart_t200(st, 12);
}
- if (skb_queue_len(&st->l2.i_queue) && (typ == RR))
+ if (!skb_queue_empty(&st->l2.i_queue) && (typ == RR))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
} else
nrerrorrecovery(fi);
@@ -1047,7 +1032,7 @@ l2_feed_i_if_reest(struct FsmInst *fi, int event, void *arg)
if (!test_bit(FLG_L3_INIT, &st->l2.flag))
skb_queue_tail(&st->l2.i_queue, skb);
else
- FreeSkb(skb);
+ dev_kfree_skb(skb);
}
static void
@@ -1093,7 +1078,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
nr = (skb->data[i] >> 5) & 0x7;
}
if (test_bit(FLG_OWN_BUSY, &l2->flag)) {
- FreeSkb(skb);
+ dev_kfree_skb(skb);
if(PollFlag) enquiry_response(st);
} else if (l2->vr == ns) {
(l2->vr)++;
@@ -1111,7 +1096,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
st->l2.l2l3(st, DL_DATA | INDICATION, skb);
} else {
/* n(s)!=v(r) */
- FreeSkb(skb);
+ dev_kfree_skb(skb);
if (test_and_set_bit(FLG_REJEXC, &l2->flag)) {
if (PollFlag)
enquiry_response(st);
@@ -1136,7 +1121,7 @@ l2_got_iframe(struct FsmInst *fi, int event, void *arg)
return;
}
- if (skb_queue_len(&st->l2.i_queue) && (fi->state == ST_L2_7))
+ if (!skb_queue_empty(&st->l2.i_queue) && (fi->state == ST_L2_7))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
if (test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag))
enquiry_cr(st, RR, RSP, 0);
@@ -1154,7 +1139,7 @@ l2_got_tei(struct FsmInst *fi, int event, void *arg)
test_and_set_bit(FLG_L3_INIT, &st->l2.flag);
} else
FsmChangeState(fi, ST_L2_4);
- if (skb_queue_len(&st->l2.ui_queue))
+ if (!skb_queue_empty(&st->l2.ui_queue))
tx_ui(st);
}
@@ -1309,7 +1294,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
skb = alloc_skb(oskb->len + i, GFP_ATOMIC);
memcpy(skb_put(skb, i), header, i);
memcpy(skb_put(skb, oskb->len), oskb->data, oskb->len);
- FreeSkb(oskb);
+ dev_kfree_skb(oskb);
}
st->l2.l2l1(st, PH_PULL | INDICATION, skb);
test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
@@ -1317,7 +1302,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
FsmDelTimer(&st->l2.t203, 13);
FsmAddTimer(&st->l2.t200, st->l2.T200, EV_L2_T200, NULL, 11);
}
- if (skb_queue_len(&l2->i_queue) && cansend(st))
+ if (!skb_queue_empty(&l2->i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
}
@@ -1349,7 +1334,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
PollFlag = (skb->data[0] & 0x10);
nr = (skb->data[0] >> 5) & 0x7;
}
- FreeSkb(skb);
+ dev_kfree_skb(skb);
if (rsp && PollFlag) {
if (legalnr(st, nr)) {
@@ -1363,7 +1348,7 @@ l2_st8_got_super(struct FsmInst *fi, int event, void *arg)
}
invoke_retransmission(st, nr);
FsmChangeState(fi, ST_L2_7);
- if (skb_queue_len(&l2->i_queue) && cansend(st))
+ if (!skb_queue_empty(&l2->i_queue) && cansend(st))
st->l2.l2l1(st, PH_PULL | REQUEST, NULL);
} else
nrerrorrecovery(fi);
@@ -1391,7 +1376,7 @@ l2_got_FRMR(struct FsmInst *fi, int event, void *arg)
establishlink(fi);
test_and_clear_bit(FLG_L3_INIT, &st->l2.flag);
}
- FreeSkb(skb);
+ dev_kfree_skb(skb);
}
static void
@@ -1655,7 +1640,7 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
datap += len;
else {
FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'N');
- FreeSkb(skb);
+ dev_kfree_skb(skb);
return;
}
if (!(*datap & 1)) { /* I-Frame */
@@ -1684,16 +1669,16 @@ isdnl2_l1l2(struct PStack *st, int pr, void *arg)
ret = FsmEvent(&st->l2.l2m, EV_L2_FRMR, skb);
} else {
FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *) 'L');
- FreeSkb(skb);
+ dev_kfree_skb(skb);
ret = 0;
}
if(c) {
- FreeSkb(skb);
+ dev_kfree_skb(skb);
FsmEvent(&st->l2.l2m, EV_L2_FRAME_ERROR, (void *)(long)c);
ret = 0;
}
if (ret)
- FreeSkb(skb);
+ dev_kfree_skb(skb);
break;
case (PH_PULL | CONFIRM):
FsmEvent(&st->l2.l2m, EV_L2_ACK_PULL, arg);
diff --git a/drivers/isdn/hisax/isdnl3.c b/drivers/isdn/hisax/isdnl3.c
index f571b5d18e91..c9917cd2132b 100644
--- a/drivers/isdn/hisax/isdnl3.c
+++ b/drivers/isdn/hisax/isdnl3.c
@@ -302,7 +302,7 @@ release_l3_process(struct l3_process *p)
!test_bit(FLG_PTP, &p->st->l2.flag)) {
if (p->debug)
l3_debug(p->st, "release_l3_process: last process");
- if (!skb_queue_len(&p->st->l3.squeue)) {
+ if (skb_queue_empty(&p->st->l3.squeue)) {
if (p->debug)
l3_debug(p->st, "release_l3_process: release link");
if (p->st->protocol != ISDN_PTYPE_NI1)
@@ -390,7 +390,7 @@ setstack_l3dc(struct PStack *st, struct Channel *chanp)
}
}
-void
+static void
isdnl3_trans(struct PStack *st, int pr, void *arg) {
st->l3.l3l2(st, pr, arg);
}
diff --git a/drivers/isdn/hisax/isurf.c b/drivers/isdn/hisax/isurf.c
index af5171da7345..33747afc984d 100644
--- a/drivers/isdn/hisax/isurf.c
+++ b/drivers/isdn/hisax/isurf.c
@@ -122,7 +122,7 @@ isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_isurf(struct IsdnCardState *cs)
{
release_region(cs->hw.isurf.reset, 1);
diff --git a/drivers/isdn/hisax/ix1_micro.c b/drivers/isdn/hisax/ix1_micro.c
index b843b7509ae2..908a7e144421 100644
--- a/drivers/isdn/hisax/ix1_micro.c
+++ b/drivers/isdn/hisax/ix1_micro.c
@@ -25,7 +25,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *ix1_revision = "$Revision: 2.12.2.4 $";
+static const char *ix1_revision = "$Revision: 2.12.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -162,7 +162,7 @@ ix1micro_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_ix1micro(struct IsdnCardState *cs)
{
if (cs->hw.ix1.cfg_reg)
diff --git a/drivers/isdn/hisax/jade.c b/drivers/isdn/hisax/jade.c
index f05d52757557..363ae3179bbd 100644
--- a/drivers/isdn/hisax/jade.c
+++ b/drivers/isdn/hisax/jade.c
@@ -74,7 +74,7 @@ jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
-void
+static void
modejade(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -190,7 +190,7 @@ jade_l2l1(struct PStack *st, int pr, void *arg)
}
}
-void
+static void
close_jadestate(struct BCState *bcs)
{
modejade(bcs, 0, bcs->channel);
@@ -243,7 +243,7 @@ open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
}
-int
+static int
setstack_jade(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
diff --git a/drivers/isdn/hisax/jade.h b/drivers/isdn/hisax/jade.h
index fa2944485994..29055e1ee381 100644
--- a/drivers/isdn/hisax/jade.h
+++ b/drivers/isdn/hisax/jade.h
@@ -128,7 +128,6 @@
#define jade_TXAUDIOCH2CFG 0x1A
extern int JadeVersion(struct IsdnCardState *cs, char *s);
-extern void modejade(struct BCState *bcs, int mode, int bc);
extern void clear_pending_jade_ints(struct IsdnCardState *cs);
extern void initjade(struct IsdnCardState *cs);
diff --git a/drivers/isdn/hisax/l3_1tr6.c b/drivers/isdn/hisax/l3_1tr6.c
index d6c1c8f8329d..c5c36eeff261 100644
--- a/drivers/isdn/hisax/l3_1tr6.c
+++ b/drivers/isdn/hisax/l3_1tr6.c
@@ -19,7 +19,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
+static const char *l3_1tr6_revision = "$Revision: 2.15.2.3 $";
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c
index ec92308c1efc..a6d2abdb478a 100644
--- a/drivers/isdn/hisax/l3dss1.c
+++ b/drivers/isdn/hisax/l3dss1.c
@@ -26,7 +26,7 @@
#include <linux/config.h>
extern char *HiSax_getrev(const char *revision);
-const char *dss1_revision = "$Revision: 2.32.2.3 $";
+static const char *dss1_revision = "$Revision: 2.32.2.3 $";
#define EXT_BEARER_CAPS 1
diff --git a/drivers/isdn/hisax/l3ni1.c b/drivers/isdn/hisax/l3ni1.c
index 3ab3a54daac1..f7041d5ba64e 100644
--- a/drivers/isdn/hisax/l3ni1.c
+++ b/drivers/isdn/hisax/l3ni1.c
@@ -24,7 +24,7 @@
#include <linux/ctype.h>
extern char *HiSax_getrev(const char *revision);
-const char *ni1_revision = "$Revision: 2.8.2.3 $";
+static const char *ni1_revision = "$Revision: 2.8.2.3 $";
#define EXT_BEARER_CAPS 1
@@ -2665,7 +2665,7 @@ static void l3ni1_spid_send( struct l3_process *pc, u_char pr, void *arg )
l3ni1_SendSpid( pc, pr, arg, 20 );
}
-void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
+static void l3ni1_spid_epid( struct l3_process *pc, u_char pr, void *arg )
{
struct sk_buff *skb = arg;
diff --git a/drivers/isdn/hisax/mic.c b/drivers/isdn/hisax/mic.c
index 3ac4484a4886..fe11f226b285 100644
--- a/drivers/isdn/hisax/mic.c
+++ b/drivers/isdn/hisax/mic.c
@@ -18,7 +18,7 @@
extern const char *CardType[];
-const char *mic_revision = "$Revision: 1.12.2.4 $";
+static const char *mic_revision = "$Revision: 1.12.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -157,7 +157,7 @@ mic_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_mic(struct IsdnCardState *cs)
{
int bytecnt = 8;
diff --git a/drivers/isdn/hisax/netjet.c b/drivers/isdn/hisax/netjet.c
index fe61d26365d3..94da03c30c51 100644
--- a/drivers/isdn/hisax/netjet.c
+++ b/drivers/isdn/hisax/netjet.c
@@ -25,8 +25,6 @@
#include <asm/io.h>
#include "netjet.h"
-const char *NETjet_revision = "$Revision: 1.29.2.4 $";
-
/* Interface functions */
u_char
@@ -66,7 +64,7 @@ NETjet_WriteICfifo(struct IsdnCardState *cs, u_char *data, int size)
outsb(cs->hw.njet.isac, data, size);
}
-void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
+static void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
{
u_int mask=0x000000ff, val = 0, *p=pos;
u_int i;
@@ -85,7 +83,7 @@ void fill_mem(struct BCState *bcs, u_int *pos, u_int cnt, int chan, u_char fill)
}
}
-void
+static void
mode_tiger(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
@@ -852,7 +850,7 @@ tiger_l2l1(struct PStack *st, int pr, void *arg)
}
-void
+static void
close_tigerstate(struct BCState *bcs)
{
mode_tiger(bcs, 0, bcs->channel);
@@ -900,7 +898,7 @@ open_tigerstate(struct IsdnCardState *cs, struct BCState *bcs)
return (0);
}
-int
+static int
setstack_tiger(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
@@ -966,7 +964,7 @@ inittiger(struct IsdnCardState *cs)
cs->bcs[1].BC_Close = close_tigerstate;
}
-void
+static void
releasetiger(struct IsdnCardState *cs)
{
if (cs->bcs[0].hw.tiger.send) {
diff --git a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
index cf77d8360975..68a2159cbd11 100644
--- a/drivers/isdn/hisax/niccy.c
+++ b/drivers/isdn/hisax/niccy.c
@@ -24,7 +24,7 @@
#include <linux/isapnp.h>
extern const char *CardType[];
-const char *niccy_revision = "$Revision: 1.21.2.4 $";
+static const char *niccy_revision = "$Revision: 1.21.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -178,7 +178,7 @@ niccy_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_niccy(struct IsdnCardState *cs)
{
if (cs->subtyp == NICCY_PCI) {
diff --git a/drivers/isdn/hisax/nj_s.c b/drivers/isdn/hisax/nj_s.c
index fd664697f821..a7d3cd3f36fd 100644
--- a/drivers/isdn/hisax/nj_s.c
+++ b/drivers/isdn/hisax/nj_s.c
@@ -15,7 +15,7 @@
#include <linux/ppp_defs.h>
#include "netjet.h"
-const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
+static const char *NETjet_S_revision = "$Revision: 2.13.2.4 $";
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
diff --git a/drivers/isdn/hisax/nj_u.c b/drivers/isdn/hisax/nj_u.c
index 3d6441e9633c..1ae7cac98a87 100644
--- a/drivers/isdn/hisax/nj_u.c
+++ b/drivers/isdn/hisax/nj_u.c
@@ -15,7 +15,7 @@
#include <linux/ppp_defs.h>
#include "netjet.h"
-const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
+static const char *NETjet_U_revision = "$Revision: 2.14.2.3 $";
static u_char dummyrr(struct IsdnCardState *cs, int chan, u_char off)
{
diff --git a/drivers/isdn/hisax/q931.c b/drivers/isdn/hisax/q931.c
index 170fcd4a3984..abecabf8c271 100644
--- a/drivers/isdn/hisax/q931.c
+++ b/drivers/isdn/hisax/q931.c
@@ -516,7 +516,7 @@ struct MessageType cause_1tr6[] =
{CAUSE_UserInfoDiscarded, "User Info Discarded"}
};
-int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
+static int cause_1tr6_len = (sizeof(cause_1tr6) / sizeof(struct MessageType));
static int
prcause_1tr6(char *dest, u_char * p)
@@ -935,7 +935,7 @@ display(char *dest, u_char * p)
return (dp - dest);
}
-int
+static int
prfacility(char *dest, u_char * p)
{
char *dp = dest;
diff --git a/drivers/isdn/hisax/s0box.c b/drivers/isdn/hisax/s0box.c
index f3c481384a4e..7b63085ea6e5 100644
--- a/drivers/isdn/hisax/s0box.c
+++ b/drivers/isdn/hisax/s0box.c
@@ -17,7 +17,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *s0box_revision = "$Revision: 2.6.2.4 $";
+static const char *s0box_revision = "$Revision: 2.6.2.4 $";
static inline void
writereg(unsigned int padr, signed int addr, u_char off, u_char val) {
@@ -183,7 +183,7 @@ s0box_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_s0box(struct IsdnCardState *cs)
{
release_region(cs->hw.teles3.cfg_reg, 8);
diff --git a/drivers/isdn/hisax/saphir.c b/drivers/isdn/hisax/saphir.c
index 9e6d3d686cce..821776e1561a 100644
--- a/drivers/isdn/hisax/saphir.c
+++ b/drivers/isdn/hisax/saphir.c
@@ -171,7 +171,7 @@ SaphirWatchDog(struct IsdnCardState *cs)
mod_timer(&cs->hw.saphir.timer, jiffies+1*HZ);
}
-void
+static void
release_io_saphir(struct IsdnCardState *cs)
{
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
diff --git a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
index 8390f1606853..8c044a6a7fe3 100644
--- a/drivers/isdn/hisax/sedlbauer.c
+++ b/drivers/isdn/hisax/sedlbauer.c
@@ -51,9 +51,9 @@
extern const char *CardType[];
-const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
+static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
-const char *Sedlbauer_Types[] =
+static const char *Sedlbauer_Types[] =
{"None", "speed card/win", "speed star", "speed fax+",
"speed win II / ISDN PC/104", "speed star II", "speed pci",
"speed fax+ pyramid", "speed fax+ pci", "HST Saphir III"};
@@ -394,7 +394,7 @@ sedlbauer_interrupt_isar(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_sedlbauer(struct IsdnCardState *cs)
{
int bytecnt = 8;
diff --git a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c
index 449651241477..c6b5bf7d2aca 100644
--- a/drivers/isdn/hisax/sedlbauer_cs.c
+++ b/drivers/isdn/hisax/sedlbauer_cs.c
@@ -47,7 +47,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@ static dev_link_t *sedlbauer_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &sedlbauer_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -616,13 +610,27 @@ static int sedlbauer_event(event_t event, int priority,
return 0;
} /* sedlbauer_event */
+static struct pcmcia_device_id sedlbauer_ids[] = {
+ PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", "speed star II", "V 3.1", "(c) 93 - 98 cb ", 0x81fb79f5, 0xf3612e1d, 0x6b95c78a, 0x50d4149c),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D67", 0x81fb79f5, 0xe4e9bc12, 0x397b7e90),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", "4D98", 0x81fb79f5, 0xe4e9bc12, 0x2e5c7fce),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (C) 93-94 VK", 0x81fb79f5, 0xe4e9bc12, 0x8db143fe),
+ PCMCIA_DEVICE_PROD_ID123("SEDLBAUER", "ISDN-Adapter", " (c) 93-95 VK", 0x81fb79f5, 0xe4e9bc12, 0xb391ab4c),
+ PCMCIA_DEVICE_PROD_ID12("HST High Soft Tech GmbH", "Saphir II B", 0xd79e0b84, 0x21d083ae),
+/* PCMCIA_DEVICE_PROD_ID1234("SEDLBAUER", 0x81fb79f5), */ /* too generic*/
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, sedlbauer_ids);
+
static struct pcmcia_driver sedlbauer_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "sedlbauer_cs",
},
.attach = sedlbauer_attach,
+ .event = sedlbauer_event,
.detach = sedlbauer_detach,
+ .id_table = sedlbauer_ids,
};
static int __init init_sedlbauer_cs(void)
diff --git a/drivers/isdn/hisax/sportster.c b/drivers/isdn/hisax/sportster.c
index 132840b750ce..cdf35dc564c4 100644
--- a/drivers/isdn/hisax/sportster.c
+++ b/drivers/isdn/hisax/sportster.c
@@ -19,7 +19,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *sportster_revision = "$Revision: 1.16.2.4 $";
+static const char *sportster_revision = "$Revision: 1.16.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -132,7 +132,7 @@ sportster_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_sportster(struct IsdnCardState *cs)
{
int i, adr;
@@ -144,7 +144,7 @@ release_io_sportster(struct IsdnCardState *cs)
}
}
-void
+static void
reset_sportster(struct IsdnCardState *cs)
{
cs->hw.spt.res_irq |= SPORTSTER_RESET; /* Reset On */
diff --git a/drivers/isdn/hisax/st5481.h b/drivers/isdn/hisax/st5481.h
index e8177b017b1d..0fda5c89429b 100644
--- a/drivers/isdn/hisax/st5481.h
+++ b/drivers/isdn/hisax/st5481.h
@@ -450,12 +450,8 @@ int st5481_setup_isocpipes(struct urb* urb[2], struct usb_device *dev,
usb_complete_t complete, void *context);
void st5481_release_isocpipes(struct urb* urb[2]);
-int st5481_isoc_flatten(struct urb *urb);
void st5481_usb_pipe_reset(struct st5481_adapter *adapter,
u_char pipe, ctrl_complete_t complete, void *context);
-void st5481_usb_ctrl_msg(struct st5481_adapter *adapter,
- u8 request, u8 requesttype, u16 value, u16 index,
- ctrl_complete_t complete, void *context);
void st5481_usb_device_ctrl_msg(struct st5481_adapter *adapter,
u8 request, u16 value,
ctrl_complete_t complete, void *context);
diff --git a/drivers/isdn/hisax/st5481_hdlc.c b/drivers/isdn/hisax/st5481_hdlc.c
deleted file mode 100644
index 680f42e9a993..000000000000
--- a/drivers/isdn/hisax/st5481_hdlc.c
+++ /dev/null
@@ -1,580 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#include <linux/crc-ccitt.h>
-#include "st5481_hdlc.h"
-
-
-enum {
- HDLC_FAST_IDLE,HDLC_GET_FLAG_B0,HDLC_GETFLAG_B1A6,HDLC_GETFLAG_B7,
- HDLC_GET_DATA,HDLC_FAST_FLAG
-};
-
-enum {
- HDLC_SEND_DATA,HDLC_SEND_CRC1,HDLC_SEND_FAST_FLAG,
- HDLC_SEND_FIRST_FLAG,HDLC_SEND_CRC2,HDLC_SEND_CLOSING_FLAG,
- HDLC_SEND_IDLE1,HDLC_SEND_FAST_IDLE,HDLC_SENDFLAG_B0,
- HDLC_SENDFLAG_B1A6,HDLC_SENDFLAG_B7,STOPPED
-};
-
-void
-hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56)
-{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
- hdlc->state = HDLC_GET_DATA;
- hdlc->do_adapt56 = do_adapt56;
- hdlc->dchannel = 0;
- hdlc->crc = 0;
- hdlc->cbin = 0;
- hdlc->shift_reg = 0;
- hdlc->ffvalue = 0;
- hdlc->dstpos = 0;
-}
-
-void
-hdlc_out_init(struct hdlc_vars *hdlc, int is_d_channel, int do_adapt56)
-{
- hdlc->bit_shift = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->ffbit_shift = 0;
- hdlc->data_received = 0;
- hdlc->do_closing = 0;
- hdlc->ffvalue = 0;
- if (is_d_channel) {
- hdlc->dchannel = 1;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- hdlc->dchannel = 0;
- hdlc->state = HDLC_SEND_FAST_FLAG;
- hdlc->ffvalue = 0x7e;
- }
- hdlc->cbin = 0x7e;
- hdlc->bit_shift = 0;
- if(do_adapt56){
- hdlc->do_adapt56 = 1;
- hdlc->data_bits = 0;
- hdlc->state = HDLC_SENDFLAG_B0;
- } else {
- hdlc->do_adapt56 = 0;
- hdlc->data_bits = 8;
- }
- hdlc->shift_reg = 0;
-}
-
-/*
- hdlc_decode - decodes HDLC frames from a transparent bit stream.
-
- The source buffer is scanned for valid HDLC frames looking for
- flags (01111110) to indicate the start of a frame. If the start of
- the frame is found, the bit stuffing is removed (0 after 5 1's).
- When a new flag is found, the complete frame has been received
- and the CRC is checked.
- If a valid frame is found, the function returns the frame length
- excluding the CRC with the bit HDLC_END_OF_FRAME set.
- If the beginning of a valid frame is found, the function returns
- the length.
- If a framing error is found (too many 1s and not a flag) the function
- returns the length with the bit HDLC_FRAMING_ERROR set.
- If a CRC error is found the function returns the length with the
- bit HDLC_CRC_ERROR set.
- If the frame length exceeds the destination buffer size, the function
- returns the length with the bit HDLC_LENGTH_ERROR set.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (decoded) from the source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of decoded bytes in the destination buffer and status
- flag.
- */
-int hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src,
- int slen, int *count, unsigned char *dst, int dsize)
-{
- int status=0;
-
- static const unsigned char fast_flag[]={
- 0x00,0x00,0x00,0x20,0x30,0x38,0x3c,0x3e,0x3f
- };
-
- static const unsigned char fast_flag_value[]={
- 0x00,0x7e,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f
- };
-
- static const unsigned char fast_abort[]={
- 0x00,0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff
- };
-
- *count = slen;
-
- while(slen > 0){
- if(hdlc->bit_shift==0){
- hdlc->cbin = *src++;
- slen--;
- hdlc->bit_shift = 8;
- if(hdlc->do_adapt56){
- hdlc->bit_shift --;
- }
- }
-
- switch(hdlc->state){
- case STOPPED:
- return 0;
- case HDLC_FAST_IDLE:
- if(hdlc->cbin == 0xff){
- hdlc->bit_shift = 0;
- break;
- }
- hdlc->state = HDLC_GET_FLAG_B0;
- hdlc->hdlc_bits1 = 0;
- hdlc->bit_shift = 8;
- break;
- case HDLC_GET_FLAG_B0:
- if(!(hdlc->cbin & 0x80)) {
- hdlc->state = HDLC_GETFLAG_B1A6;
- hdlc->hdlc_bits1 = 0;
- } else {
- if(!hdlc->do_adapt56){
- if(++hdlc->hdlc_bits1 >=8 ) if(hdlc->bit_shift==1)
- hdlc->state = HDLC_FAST_IDLE;
- }
- }
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
- break;
- case HDLC_GETFLAG_B1A6:
- if(hdlc->cbin & 0x80){
- hdlc->hdlc_bits1++;
- if(hdlc->hdlc_bits1==6){
- hdlc->state = HDLC_GETFLAG_B7;
- }
- } else {
- hdlc->hdlc_bits1 = 0;
- }
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
- break;
- case HDLC_GETFLAG_B7:
- if(hdlc->cbin & 0x80) {
- hdlc->state = HDLC_GET_FLAG_B0;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = 0;
- hdlc->data_received = 0;
- }
- hdlc->cbin<<=1;
- hdlc->bit_shift --;
- break;
- case HDLC_GET_DATA:
- if(hdlc->cbin & 0x80){
- hdlc->hdlc_bits1++;
- switch(hdlc->hdlc_bits1){
- case 6:
- break;
- case 7:
- if(hdlc->data_received) {
- // bad frame
- status = -HDLC_FRAMING_ERROR;
- }
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_abort[hdlc->bit_shift+1]){
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=1;
- break;
- }
- } else {
- hdlc->state = HDLC_GET_FLAG_B0;
- }
- break;
- default:
- hdlc->shift_reg>>=1;
- hdlc->shift_reg |= 0x80;
- hdlc->data_bits++;
- break;
- }
- } else {
- switch(hdlc->hdlc_bits1){
- case 5:
- break;
- case 6:
- if(hdlc->data_received){
- if (hdlc->dstpos < 2) {
- status = -HDLC_FRAMING_ERROR;
- } else if (hdlc->crc != 0xf0b8){
- // crc error
- status = -HDLC_CRC_ERROR;
- } else {
- // remove CRC
- hdlc->dstpos -= 2;
- // good frame
- status = hdlc->dstpos;
- }
- }
- hdlc->crc = 0xffff;
- hdlc->shift_reg = 0;
- hdlc->data_bits = 0;
- if(!hdlc->do_adapt56){
- if(hdlc->cbin==fast_flag[hdlc->bit_shift]){
- hdlc->ffvalue = fast_flag_value[hdlc->bit_shift];
- hdlc->state = HDLC_FAST_FLAG;
- hdlc->ffbit_shift = hdlc->bit_shift;
- hdlc->bit_shift = 1;
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- } else {
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- break;
- default:
- hdlc->shift_reg>>=1;
- hdlc->data_bits++;
- break;
- }
- hdlc->hdlc_bits1 = 0;
- }
- if (status) {
- hdlc->dstpos = 0;
- *count -= slen;
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- return status;
- }
- if(hdlc->data_bits==8){
- hdlc->data_bits = 0;
- hdlc->data_received = 1;
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
-
- // good byte received
- if (dsize--) {
- dst[hdlc->dstpos++] = hdlc->shift_reg;
- } else {
- // frame too long
- status = -HDLC_LENGTH_ERROR;
- hdlc->dstpos = 0;
- }
- }
- hdlc->cbin <<= 1;
- hdlc->bit_shift--;
- break;
- case HDLC_FAST_FLAG:
- if(hdlc->cbin==hdlc->ffvalue){
- hdlc->bit_shift = 0;
- break;
- } else {
- if(hdlc->cbin == 0xff){
- hdlc->state = HDLC_FAST_IDLE;
- hdlc->bit_shift=0;
- } else if(hdlc->ffbit_shift==8){
- hdlc->state = HDLC_GETFLAG_B7;
- break;
- } else {
- hdlc->shift_reg = fast_abort[hdlc->ffbit_shift-1];
- hdlc->hdlc_bits1 = hdlc->ffbit_shift-2;
- if(hdlc->hdlc_bits1<0)hdlc->hdlc_bits1 = 0;
- hdlc->data_bits = hdlc->ffbit_shift-1;
- hdlc->state = HDLC_GET_DATA;
- hdlc->data_received = 0;
- }
- }
- break;
- default:
- break;
- }
- }
- *count -= slen;
- return 0;
-}
-
-/*
- hdlc_encode - encodes HDLC frames to a transparent bit stream.
-
- The bit stream starts with a beginning flag (01111110). After
- that each byte is added to the bit stream with bit stuffing added
- (0 after 5 1's).
- When the last byte has been removed from the source buffer, the
- CRC (2 bytes is added) and the frame terminates with the ending flag.
- For the dchannel, the idle character (all 1's) is also added at the end.
- If this function is called with empty source buffer (slen=0), flags or
- idle character will be generated.
-
- src - source buffer
- slen - source buffer length
- count - number of bytes removed (encoded) from source buffer
- dst _ destination buffer
- dsize - destination buffer size
- returns - number of encoded bytes in the destination buffer
-*/
-int hdlc_encode(struct hdlc_vars *hdlc, const unsigned char *src,
- unsigned short slen, int *count,
- unsigned char *dst, int dsize)
-{
- static const unsigned char xfast_flag_value[] = {
- 0x7e,0x3f,0x9f,0xcf,0xe7,0xf3,0xf9,0xfc,0x7e
- };
-
- int len = 0;
-
- *count = slen;
-
- while (dsize > 0) {
- if(hdlc->bit_shift==0){
- if(slen && !hdlc->do_closing){
- hdlc->shift_reg = *src++;
- slen--;
- if (slen == 0)
- hdlc->do_closing = 1; /* closing sequence, CRC + flag(s) */
- hdlc->bit_shift = 8;
- } else {
- if(hdlc->state == HDLC_SEND_DATA){
- if(hdlc->data_received){
- hdlc->state = HDLC_SEND_CRC1;
- hdlc->crc ^= 0xffff;
- hdlc->bit_shift = 8;
- hdlc->shift_reg = hdlc->crc & 0xff;
- } else if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- }
- }
-
- }
- }
-
- switch(hdlc->state){
- case STOPPED:
- while (dsize--)
- *dst++ = 0xff;
-
- return dsize;
- case HDLC_SEND_FAST_FLAG:
- hdlc->do_closing = 0;
- if(slen == 0){
- *dst++ = hdlc->ffvalue;
- len++;
- dsize--;
- break;
- }
- if(hdlc->bit_shift==8){
- hdlc->cbin = hdlc->ffvalue>>(8-hdlc->data_bits);
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SENDFLAG_B0:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->hdlc_bits1 = 0;
- hdlc->state = HDLC_SENDFLAG_B1A6;
- break;
- case HDLC_SENDFLAG_B1A6:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- hdlc->cbin++;
- if(++hdlc->hdlc_bits1 == 6)
- hdlc->state = HDLC_SENDFLAG_B7;
- break;
- case HDLC_SENDFLAG_B7:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(slen == 0){
- hdlc->state = HDLC_SENDFLAG_B0;
- break;
- }
- if(hdlc->bit_shift==8){
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- hdlc->data_received = 1;
- }
- break;
- case HDLC_SEND_FIRST_FLAG:
- hdlc->data_received = 1;
- if(hdlc->data_bits==8){
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- break;
- }
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(hdlc->shift_reg & 0x01)
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
- hdlc->state = HDLC_SEND_DATA;
- hdlc->crc = 0xffff;
- hdlc->hdlc_bits1 = 0;
- }
- break;
- case HDLC_SEND_DATA:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if(hdlc->bit_shift==8){
- hdlc->crc = crc_ccitt_byte(hdlc->crc, hdlc->shift_reg);
- }
- if(hdlc->shift_reg & 0x01){
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- break;
- case HDLC_SEND_CRC1:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if(hdlc->shift_reg & 0x01){
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if(hdlc->bit_shift==0){
- hdlc->shift_reg = (hdlc->crc >> 8);
- hdlc->state = HDLC_SEND_CRC2;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CRC2:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if(hdlc->shift_reg & 0x01){
- hdlc->hdlc_bits1++;
- hdlc->cbin++;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- } else {
- hdlc->hdlc_bits1 = 0;
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- }
- if(hdlc->bit_shift==0){
- hdlc->shift_reg = 0x7e;
- hdlc->state = HDLC_SEND_CLOSING_FLAG;
- hdlc->bit_shift = 8;
- }
- break;
- case HDLC_SEND_CLOSING_FLAG:
- hdlc->cbin <<= 1;
- hdlc->data_bits++;
- if(hdlc->hdlc_bits1 == 5){
- hdlc->hdlc_bits1 = 0;
- break;
- }
- if(hdlc->shift_reg & 0x01){
- hdlc->cbin++;
- }
- hdlc->shift_reg >>= 1;
- hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
- hdlc->ffvalue = xfast_flag_value[hdlc->data_bits];
- if(hdlc->dchannel){
- hdlc->ffvalue = 0x7e;
- hdlc->state = HDLC_SEND_IDLE1;
- hdlc->bit_shift = 8-hdlc->data_bits;
- if(hdlc->bit_shift==0)
- hdlc->state = HDLC_SEND_FAST_IDLE;
- } else {
- if(!hdlc->do_adapt56){
- hdlc->state = HDLC_SEND_FAST_FLAG;
- hdlc->data_received = 0;
- } else {
- hdlc->state = HDLC_SENDFLAG_B0;
- hdlc->data_received = 0;
- }
- // Finished with this frame, send flags
- if (dsize > 1) dsize = 1;
- }
- }
- break;
- case HDLC_SEND_IDLE1:
- hdlc->do_closing = 0;
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- hdlc->bit_shift--;
- if(hdlc->bit_shift==0){
- hdlc->state = HDLC_SEND_FAST_IDLE;
- hdlc->bit_shift = 0;
- }
- break;
- case HDLC_SEND_FAST_IDLE:
- hdlc->do_closing = 0;
- hdlc->cbin = 0xff;
- hdlc->data_bits = 8;
- if(hdlc->bit_shift == 8){
- hdlc->cbin = 0x7e;
- hdlc->state = HDLC_SEND_FIRST_FLAG;
- } else {
- *dst++ = hdlc->cbin;
- hdlc->bit_shift = hdlc->data_bits = 0;
- len++;
- dsize = 0;
- }
- break;
- default:
- break;
- }
- if(hdlc->do_adapt56){
- if(hdlc->data_bits==7){
- hdlc->cbin <<= 1;
- hdlc->cbin++;
- hdlc->data_bits++;
- }
- }
- if(hdlc->data_bits==8){
- *dst++ = hdlc->cbin;
- hdlc->data_bits = 0;
- len++;
- dsize--;
- }
- }
- *count -= slen;
-
- return len;
-}
-
diff --git a/drivers/isdn/hisax/st5481_hdlc.h b/drivers/isdn/hisax/st5481_hdlc.h
deleted file mode 100644
index 495432f0f6ba..000000000000
--- a/drivers/isdn/hisax/st5481_hdlc.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Driver for ST5481 USB ISDN modem
- *
- * Author Frode Isaksen
- * Copyright 2001 by Frode Isaksen <fisaksen@bewan.com>
- * 2001 by Kai Germaschewski <kai.germaschewski@gmx.de>
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- */
-
-#ifndef __ST5481_HDLC_H__
-#define __ST5481_HDLC_H__
-
-struct hdlc_vars {
- int bit_shift;
- int hdlc_bits1;
- int data_bits;
- int ffbit_shift; // encoding only
- int state;
- int dstpos;
-
- int data_received:1; // set if transferring data
- int dchannel:1; // set if D channel (send idle instead of flags)
- int do_adapt56:1; // set if 56K adaptation
- int do_closing:1; // set if in closing phase (need to send CRC + flag
-
- unsigned short crc;
-
- unsigned char cbin;
- unsigned char shift_reg;
- unsigned char ffvalue;
-
-};
-
-
-/*
- The return value from hdlc_decode is
- the frame length, 0 if no complete frame was decoded,
- or a negative error number
-*/
-
-#define HDLC_FRAMING_ERROR 1
-#define HDLC_CRC_ERROR 2
-#define HDLC_LENGTH_ERROR 3
-
-void
-hdlc_rcv_init(struct hdlc_vars *hdlc, int do_adapt56);
-
-int
-hdlc_decode(struct hdlc_vars *hdlc, const unsigned char *src, int slen,int *count,
- unsigned char *dst, int dsize);
-
-void
-hdlc_out_init(struct hdlc_vars *hdlc,int is_d_channel,int do_adapt56);
-
-int
-hdlc_encode(struct hdlc_vars *hdlc,const unsigned char *src,unsigned short slen,int *count,
- unsigned char *dst,int dsize);
-
-#endif
diff --git a/drivers/isdn/hisax/st5481_usb.c b/drivers/isdn/hisax/st5481_usb.c
index 2369180b1cb1..ab62223297a5 100644
--- a/drivers/isdn/hisax/st5481_usb.c
+++ b/drivers/isdn/hisax/st5481_usb.c
@@ -15,6 +15,8 @@
#include <linux/slab.h>
#include "st5481.h"
+static int st5481_isoc_flatten(struct urb *urb);
+
/* ======================================================================
* control pipe
*/
@@ -55,9 +57,9 @@ static void usb_next_ctrl_msg(struct urb *urb,
* Asynchronous endpoint 0 request (async version of usb_control_msg).
* The request will be queued up in a FIFO if the endpoint is busy.
*/
-void usb_ctrl_msg(struct st5481_adapter *adapter,
- u8 request, u8 requesttype, u16 value, u16 index,
- ctrl_complete_t complete, void *context)
+static void usb_ctrl_msg(struct st5481_adapter *adapter,
+ u8 request, u8 requesttype, u16 value, u16 index,
+ ctrl_complete_t complete, void *context)
{
struct st5481_ctrl *ctrl = &adapter->ctrl;
int w_index;
@@ -571,7 +573,7 @@ void st5481_release_in(struct st5481_in *in)
* Make the transfer_buffer contiguous by
* copying from the iso descriptors if necessary.
*/
-int st5481_isoc_flatten(struct urb *urb)
+static int st5481_isoc_flatten(struct urb *urb)
{
struct usb_iso_packet_descriptor *pipd,*pend;
unsigned char *src,*dst;
diff --git a/drivers/isdn/hisax/tei.c b/drivers/isdn/hisax/tei.c
index 082726db3985..ceb0df92fd3e 100644
--- a/drivers/isdn/hisax/tei.c
+++ b/drivers/isdn/hisax/tei.c
@@ -74,7 +74,7 @@ static char *strTeiEvent[] =
"EV_T202",
};
-unsigned int
+static unsigned int
random_ri(void)
{
unsigned int x;
diff --git a/drivers/isdn/hisax/teleint.c b/drivers/isdn/hisax/teleint.c
index ef8984c5f1f7..a2b1816af37a 100644
--- a/drivers/isdn/hisax/teleint.c
+++ b/drivers/isdn/hisax/teleint.c
@@ -18,7 +18,7 @@
extern const char *CardType[];
-const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
+static const char *TeleInt_revision = "$Revision: 1.16.2.5 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -203,7 +203,7 @@ TeleInt_Timer(struct IsdnCardState *cs)
add_timer(&cs->hw.hfc.timer);
}
-void
+static void
release_io_TeleInt(struct IsdnCardState *cs)
{
del_timer(&cs->hw.hfc.timer);
diff --git a/drivers/isdn/hisax/teles0.c b/drivers/isdn/hisax/teles0.c
index 5ec5ec3e1eab..2b7df8f98233 100644
--- a/drivers/isdn/hisax/teles0.c
+++ b/drivers/isdn/hisax/teles0.c
@@ -23,7 +23,7 @@
extern const char *CardType[];
-const char *teles0_revision = "$Revision: 2.15.2.4 $";
+static const char *teles0_revision = "$Revision: 2.15.2.4 $";
#define TELES_IOMEM_SIZE 0x400
#define byteout(addr,val) outb(val,addr)
@@ -183,7 +183,7 @@ teles0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_teles0(struct IsdnCardState *cs)
{
if (cs->hw.teles0.cfg_reg)
diff --git a/drivers/isdn/hisax/teles3.c b/drivers/isdn/hisax/teles3.c
index c5b1f65f7275..adeaad62d35c 100644
--- a/drivers/isdn/hisax/teles3.c
+++ b/drivers/isdn/hisax/teles3.c
@@ -21,7 +21,7 @@
#include "isdnl1.h"
extern const char *CardType[];
-const char *teles3_revision = "$Revision: 2.19.2.4 $";
+static const char *teles3_revision = "$Revision: 2.19.2.4 $";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
@@ -154,7 +154,7 @@ release_ioregs(struct IsdnCardState *cs, int mask)
release_region(cs->hw.teles3.hscx[1] + 32, 32);
}
-void
+static void
release_io_teles3(struct IsdnCardState *cs)
{
if (cs->typ == ISDN_CTYPE_TELESPCMCIA) {
diff --git a/drivers/isdn/hisax/teles_cs.c b/drivers/isdn/hisax/teles_cs.c
index 63e8e20c17a8..0ddef1bf778b 100644
--- a/drivers/isdn/hisax/teles_cs.c
+++ b/drivers/isdn/hisax/teles_cs.c
@@ -28,7 +28,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -193,11 +192,6 @@ static dev_link_t *teles_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &teles_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -489,13 +483,21 @@ static int teles_cs_event(event_t event, int priority,
return 0;
} /* teles_cs_event */
+static struct pcmcia_device_id teles_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("TELES", "S0/PC", 0x67b50eae, 0xe9e70119),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, teles_ids);
+
static struct pcmcia_driver teles_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "teles_cs",
},
.attach = teles_attach,
+ .event = teles_cs_event,
.detach = teles_detach,
+ .id_table = teles_ids,
};
static int __init init_teles_cs(void)
diff --git a/drivers/isdn/hisax/telespci.c b/drivers/isdn/hisax/telespci.c
index 0661c6c31ad0..e2bb4fd8e25e 100644
--- a/drivers/isdn/hisax/telespci.c
+++ b/drivers/isdn/hisax/telespci.c
@@ -21,7 +21,7 @@
#include <linux/pci.h>
extern const char *CardType[];
-const char *telespci_revision = "$Revision: 2.23.2.3 $";
+static const char *telespci_revision = "$Revision: 2.23.2.3 $";
#define ZORAN_PO_RQ_PEN 0x02000000
#define ZORAN_PO_WR 0x00800000
@@ -257,7 +257,7 @@ telespci_interrupt(int intno, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-void
+static void
release_io_telespci(struct IsdnCardState *cs)
{
iounmap(cs->hw.teles0.membase);
diff --git a/drivers/isdn/hisax/w6692.c b/drivers/isdn/hisax/w6692.c
index d2b6b8e72980..7baf8e488471 100644
--- a/drivers/isdn/hisax/w6692.c
+++ b/drivers/isdn/hisax/w6692.c
@@ -41,7 +41,7 @@ static const PCI_ENTRY id_list[] =
extern const char *CardType[];
-const char *w6692_revision = "$Revision: 1.18.2.4 $";
+static const char *w6692_revision = "$Revision: 1.18.2.4 $";
#define DBUSY_TIMER_VALUE 80
@@ -880,7 +880,7 @@ setstack_w6692(struct PStack *st, struct BCState *bcs)
return (0);
}
-void resetW6692(struct IsdnCardState *cs)
+static void resetW6692(struct IsdnCardState *cs)
{
cs->writeW6692(cs, W_D_CTL, W_D_CTL_SRST);
mdelay(10);
@@ -902,7 +902,7 @@ void resetW6692(struct IsdnCardState *cs)
}
}
-void __init initW6692(struct IsdnCardState *cs, int part)
+static void __init initW6692(struct IsdnCardState *cs, int part)
{
if (part & 1) {
cs->setstack_d = setstack_W6692;
diff --git a/drivers/isdn/hysdn/hycapi.c b/drivers/isdn/hysdn/hycapi.c
index 8ee25b2ccce1..1fd3d4e5f284 100644
--- a/drivers/isdn/hysdn/hycapi.c
+++ b/drivers/isdn/hysdn/hycapi.c
@@ -42,6 +42,8 @@ typedef struct _hycapi_appl {
static hycapi_appl hycapi_applications[CAPI_MAXAPPL];
+static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb);
+
static inline int _hycapi_appCheck(int app_id, int ctrl_no)
{
if((ctrl_no <= 0) || (ctrl_no > CAPI_MAXCONTR) || (app_id <= 0) ||
@@ -57,7 +59,7 @@ static inline int _hycapi_appCheck(int app_id, int ctrl_no)
Kernel-Capi callback reset_ctr
******************************/
-void
+static void
hycapi_reset_ctr(struct capi_ctr *ctrl)
{
hycapictrl_info *cinfo = ctrl->driverdata;
@@ -73,7 +75,7 @@ hycapi_reset_ctr(struct capi_ctr *ctrl)
Kernel-Capi callback remove_ctr
******************************/
-void
+static void
hycapi_remove_ctr(struct capi_ctr *ctrl)
{
int i;
@@ -215,7 +217,7 @@ Error-checking is done for CAPI-compliance.
The application is recorded in the internal list.
*************************************************************/
-void
+static void
hycapi_register_appl(struct capi_ctr *ctrl, __u16 appl,
capi_register_params *rp)
{
@@ -291,7 +293,7 @@ Release the application from the internal list an remove it's
registration at controller-level
******************************************************************/
-void
+static void
hycapi_release_appl(struct capi_ctr *ctrl, __u16 appl)
{
int chk;
@@ -364,7 +366,7 @@ firmware-releases that do not check the MsgLen-Indication!
***************************************************************/
-u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
+static u16 hycapi_send_message(struct capi_ctr *ctrl, struct sk_buff *skb)
{
__u16 appl_id;
int _len, _len2;
@@ -437,8 +439,8 @@ Informations provided in the /proc/capi-entries.
*********************************************************************/
-int hycapi_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *ctrl)
+static int hycapi_read_proc(char *page, char **start, off_t off,
+ int count, int *eof, struct capi_ctr *ctrl)
{
hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
hysdn_card *card = cinfo->card;
@@ -485,7 +487,7 @@ on capi-interface registration.
**************************************************************/
-int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
+static int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
{
#ifdef HYCAPI_PRINTFNAMES
printk(KERN_NOTICE "hycapi_load_firmware\n");
@@ -494,7 +496,7 @@ int hycapi_load_firmware(struct capi_ctr *ctrl, capiloaddata *data)
}
-char *hycapi_procinfo(struct capi_ctr *ctrl)
+static char *hycapi_procinfo(struct capi_ctr *ctrl)
{
hycapictrl_info *cinfo = (hycapictrl_info *)(ctrl->driverdata);
#ifdef HYCAPI_PRINTFNAMES
diff --git a/drivers/isdn/hysdn/hysdn_boot.c b/drivers/isdn/hysdn/hysdn_boot.c
index 6c04281e57b8..7bfba196f315 100644
--- a/drivers/isdn/hysdn/hysdn_boot.c
+++ b/drivers/isdn/hysdn/hysdn_boot.c
@@ -53,7 +53,7 @@ struct boot_data {
/* to be called at start of POF file reading, */
/* before starting any decryption on any POF record. */
/*****************************************************/
-void
+static void
StartDecryption(struct boot_data *boot)
{
boot->Cryptor = CRYPT_STARTTERM;
@@ -66,7 +66,7 @@ StartDecryption(struct boot_data *boot)
/* to HI and LO boot loader and (all) seq tags, because */
/* global Cryptor is started for whole POF. */
/***************************************************************/
-void
+static void
DecryptBuf(struct boot_data *boot, int cnt)
{
uchar *bufp = boot->buf.BootBuf;
diff --git a/drivers/isdn/hysdn/hysdn_defs.h b/drivers/isdn/hysdn/hysdn_defs.h
index 4cee26e558ee..432f6f99089e 100644
--- a/drivers/isdn/hysdn/hysdn_defs.h
+++ b/drivers/isdn/hysdn/hysdn_defs.h
@@ -227,7 +227,6 @@ typedef struct hycapictrl_info hycapictrl_info;
/*****************/
/* exported vars */
/*****************/
-extern int cardmax; /* number of found cards */
extern hysdn_card *card_root; /* pointer to first card */
@@ -244,7 +243,6 @@ extern void hysdn_procconf_release(void); /* deinit proc config filesys */
/* hysdn_proclog.c */
extern int hysdn_proclog_init(hysdn_card *); /* init proc log entry */
extern void hysdn_proclog_release(hysdn_card *); /* deinit proc log entry */
-extern void put_log_buffer(hysdn_card *, char *); /* output log data */
extern void hysdn_addlog(hysdn_card *, char *,...); /* output data to log */
extern void hysdn_card_errlog(hysdn_card *, tErrLogEntry *, int); /* output card log */
@@ -278,16 +276,6 @@ extern unsigned int hycapi_enable;
extern int hycapi_capi_create(hysdn_card *); /* create a new capi device */
extern int hycapi_capi_release(hysdn_card *); /* delete the device */
extern int hycapi_capi_stop(hysdn_card *card); /* suspend */
-extern int hycapi_load_firmware(struct capi_ctr *, capiloaddata *);
-extern void hycapi_reset_ctr(struct capi_ctr *);
-extern void hycapi_remove_ctr(struct capi_ctr *);
-extern void hycapi_register_appl(struct capi_ctr *, __u16 appl,
- capi_register_params *);
-extern void hycapi_release_appl(struct capi_ctr *, __u16 appl);
-extern u16 hycapi_send_message(struct capi_ctr *, struct sk_buff *skb);
-extern char *hycapi_procinfo(struct capi_ctr *);
-extern int hycapi_read_proc(char *page, char **start, off_t off,
- int count, int *eof, struct capi_ctr *card);
extern void hycapi_rx_capipkt(hysdn_card * card, uchar * buf, word len);
extern void hycapi_tx_capiack(hysdn_card * card);
extern struct sk_buff *hycapi_tx_capiget(hysdn_card *card);
diff --git a/drivers/isdn/hysdn/hysdn_init.c b/drivers/isdn/hysdn/hysdn_init.c
index 5cac2bf5f4b0..12c8137b5161 100644
--- a/drivers/isdn/hysdn/hysdn_init.c
+++ b/drivers/isdn/hysdn/hysdn_init.c
@@ -34,7 +34,7 @@ MODULE_AUTHOR("Werner Cornelius");
MODULE_LICENSE("GPL");
static char *hysdn_init_revision = "$Revision: 1.6.6.6 $";
-int cardmax; /* number of found cards */
+static int cardmax; /* number of found cards */
hysdn_card *card_root = NULL; /* pointer to first card */
/**********************************************/
diff --git a/drivers/isdn/hysdn/hysdn_proclog.c b/drivers/isdn/hysdn/hysdn_proclog.c
index 8ef2b7c952a6..4d57011c5737 100644
--- a/drivers/isdn/hysdn/hysdn_proclog.c
+++ b/drivers/isdn/hysdn/hysdn_proclog.c
@@ -22,6 +22,8 @@
/* the proc subdir for the interface is defined in the procconf module */
extern struct proc_dir_entry *hysdn_proc_entry;
+static void put_log_buffer(hysdn_card * card, char *cp);
+
/*************************************************/
/* structure keeping ascii log for device output */
/*************************************************/
@@ -93,7 +95,7 @@ hysdn_addlog(hysdn_card * card, char *fmt,...)
/* opened for read got the contents. */
/* Flushes buffers not longer in use. */
/********************************************/
-void
+static void
put_log_buffer(hysdn_card * card, char *cp)
{
struct log_data *ib;
diff --git a/drivers/isdn/i4l/isdn_audio.c b/drivers/isdn/i4l/isdn_audio.c
index 5350836a4f98..2cc56d6a9fae 100644
--- a/drivers/isdn/i4l/isdn_audio.c
+++ b/drivers/isdn/i4l/isdn_audio.c
@@ -392,16 +392,6 @@ isdn_audio_adpcm2xlaw(adpcm_state * s, int fmt, unsigned char *in,
}
int
-isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out)
-{
- int olen = 0;
-
- if (s->nleft)
- isdn_audio_put_bits(0, 8 - s->nleft, s, &out, &olen);
- return olen;
-}
-
-int
isdn_audio_xlaw2adpcm(adpcm_state * s, int fmt, unsigned char *in,
unsigned char *out, int len)
{
diff --git a/drivers/isdn/i4l/isdn_audio.h b/drivers/isdn/i4l/isdn_audio.h
index 5a977b21dcfa..013c3582e0d1 100644
--- a/drivers/isdn/i4l/isdn_audio.h
+++ b/drivers/isdn/i4l/isdn_audio.h
@@ -35,7 +35,6 @@ extern void isdn_audio_alaw2ulaw(unsigned char *, unsigned long);
extern adpcm_state *isdn_audio_adpcm_init(adpcm_state *, int);
extern int isdn_audio_adpcm2xlaw(adpcm_state *, int, unsigned char *, unsigned char *, int);
extern int isdn_audio_xlaw2adpcm(adpcm_state *, int, unsigned char *, unsigned char *, int);
-extern int isdn_audio_2adpcm_flush(adpcm_state * s, unsigned char *out);
extern void isdn_audio_calc_dtmf(modem_info *, unsigned char *, int, int);
extern void isdn_audio_eval_dtmf(modem_info *);
dtmf_state *isdn_audio_dtmf_init(dtmf_state *);
diff --git a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
index c406df6f268a..eebcb0b97f0e 100644
--- a/drivers/isdn/i4l/isdn_common.c
+++ b/drivers/isdn/i4l/isdn_common.c
@@ -67,7 +67,7 @@ static isdn_divert_if *divert_if; /* = NULL */
static int isdn_writebuf_stub(int, int, const u_char __user *, int);
static void set_global_features(void);
static int isdn_wildmat(char *s, char *p);
-
+static int isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding);
static inline void
isdn_lock_driver(isdn_driver_t *drv)
@@ -388,7 +388,7 @@ isdn_all_eaz(int di, int ch)
*/
#include <linux/isdn/capicmd.h>
-int
+static int
isdn_capi_rec_hl_msg(capi_msg *cm) {
int di;
@@ -1923,7 +1923,7 @@ isdn_writebuf_skb_stub(int drvidx, int chan, int ack, struct sk_buff *skb)
return ret;
}
-int
+static int
isdn_add_channels(isdn_driver_t *d, int drvidx, int n, int adding)
{
int j, k, m;
diff --git a/drivers/isdn/i4l/isdn_common.h b/drivers/isdn/i4l/isdn_common.h
index 808135c427ad..e27e9c3a81ed 100644
--- a/drivers/isdn/i4l/isdn_common.h
+++ b/drivers/isdn/i4l/isdn_common.h
@@ -41,7 +41,6 @@ extern int isdn_get_free_channel(int, int, int, int, int, char *);
extern int isdn_writebuf_skb_stub(int, int, int, struct sk_buff *);
extern int register_isdn(isdn_if * i);
extern int isdn_msncmp( const char *, const char *);
-extern int isdn_add_channels(isdn_driver_t *, int, int, int);
#if defined(ISDN_DEBUG_NET_DUMP) || defined(ISDN_DEBUG_MODEM_DUMP)
extern void isdn_dumppkt(char *, u_char *, int, int);
#endif
diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c
index 83a4f5382bc2..0193b6f7c70c 100644
--- a/drivers/isdn/i4l/isdn_concap.c
+++ b/drivers/isdn/i4l/isdn_concap.c
@@ -39,7 +39,7 @@
*/
-int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
+static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
{
struct net_device *ndev = concap -> net_dev;
isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev;
@@ -58,7 +58,7 @@ int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb)
}
-int isdn_concap_dl_connect_req(struct concap_proto *concap)
+static int isdn_concap_dl_connect_req(struct concap_proto *concap)
{
struct net_device *ndev = concap -> net_dev;
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -71,7 +71,7 @@ int isdn_concap_dl_connect_req(struct concap_proto *concap)
return ret;
}
-int isdn_concap_dl_disconn_req(struct concap_proto *concap)
+static int isdn_concap_dl_disconn_req(struct concap_proto *concap)
{
IX25DEBUG( "isdn_concap_dl_disconn_req: %s \n", concap -> net_dev -> name);
@@ -85,15 +85,6 @@ struct concap_device_ops isdn_concap_reliable_dl_dops = {
&isdn_concap_dl_disconn_req
};
-struct concap_device_ops isdn_concap_demand_dial_dops = {
- NULL, /* set this first entry to something like &isdn_net_start_xmit,
- but the entry part of the current isdn_net_start_xmit must be
- separated first. */
- /* no connection control for demand dial semantics */
- NULL,
- NULL,
-};
-
/* The following should better go into a dedicated source file such that
this sourcefile does not need to include any protocol specific header
files. For now:
diff --git a/drivers/isdn/i4l/isdn_concap.h b/drivers/isdn/i4l/isdn_concap.h
index 306eb180438f..6ac7e0445ea5 100644
--- a/drivers/isdn/i4l/isdn_concap.h
+++ b/drivers/isdn/i4l/isdn_concap.h
@@ -8,7 +8,6 @@
*/
extern struct concap_device_ops isdn_concap_reliable_dl_dops;
-extern struct concap_device_ops isdn_concap_demand_dial_dops;
extern struct concap_proto * isdn_concap_new( int );
diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c
index e2b790e34510..f30e8e63ae0d 100644
--- a/drivers/isdn/i4l/isdn_net.c
+++ b/drivers/isdn/i4l/isdn_net.c
@@ -176,7 +176,7 @@ static __inline__ void isdn_net_zero_frame_cnt(isdn_net_local *lp)
/* Prototypes */
-int isdn_net_force_dial_lp(isdn_net_local *);
+static int isdn_net_force_dial_lp(isdn_net_local *);
static int isdn_net_start_xmit(struct sk_buff *, struct net_device *);
static void isdn_net_ciscohdlck_connected(isdn_net_local *lp);
@@ -312,7 +312,7 @@ isdn_net_unbind_channel(isdn_net_local * lp)
* Since this function is called every second, simply reset the
* byte-counter of the interface after copying it to the cps-variable.
*/
-unsigned long last_jiffies = -HZ;
+static unsigned long last_jiffies = -HZ;
void
isdn_net_autohup(void)
@@ -1131,7 +1131,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev)
}
-void isdn_net_tx_timeout(struct net_device * ndev)
+static void isdn_net_tx_timeout(struct net_device * ndev)
{
isdn_net_local *lp = (isdn_net_local *) ndev->priv;
@@ -1424,7 +1424,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len)
}
/* cisco hdlck device private ioctls */
-int
+static int
isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
isdn_net_local *lp = (isdn_net_local *) dev->priv;
@@ -2461,7 +2461,7 @@ isdn_net_findif(char *name)
* This is called from the userlevel-routine below or
* from isdn_net_start_xmit().
*/
-int
+static int
isdn_net_force_dial_lp(isdn_net_local * lp)
{
if ((!(lp->flags & ISDN_NET_CONNECTED)) && !lp->dialstate) {
diff --git a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c
index e21007eca0f0..b37ef1f06b3d 100644
--- a/drivers/isdn/i4l/isdn_tty.c
+++ b/drivers/isdn/i4l/isdn_tty.c
@@ -273,7 +273,7 @@ isdn_tty_rcv_skb(int i, int di, int channel, struct sk_buff *skb)
return 1;
}
-void
+static void
isdn_tty_cleanup_xmit(modem_info * info)
{
skb_queue_purge(&info->xmit_queue);
@@ -560,7 +560,7 @@ isdn_tty_modem_ncarrier(modem_info * info)
/*
* return the usage calculated by si and layer 2 protocol
*/
-int
+static int
isdn_calc_usage(int si, int l2)
{
int usg = ISDN_USAGE_MODEM;
@@ -1223,7 +1223,7 @@ isdn_tty_write(struct tty_struct *tty, const u_char * buf, int count)
total += c;
}
atomic_dec(&info->xmit_lock);
- if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue))) {
+ if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue)) {
if (m->mdmreg[REG_DXMT] & BIT_DXMT) {
isdn_tty_senddown(info);
isdn_tty_tint(info);
@@ -1284,7 +1284,7 @@ isdn_tty_flush_chars(struct tty_struct *tty)
if (isdn_tty_paranoia_check(info, tty->name, "isdn_tty_flush_chars"))
return;
- if ((info->xmit_count) || (skb_queue_len(&info->xmit_queue)))
+ if ((info->xmit_count) || !skb_queue_empty(&info->xmit_queue))
isdn_timer_ctrl(ISDN_TIMER_MODEMXMIT, 1);
}
diff --git a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h
index 2423a7ff0cc3..9f0fa9501f4d 100644
--- a/drivers/isdn/i4l/isdn_tty.h
+++ b/drivers/isdn/i4l/isdn_tty.h
@@ -109,7 +109,6 @@ extern int isdn_tty_modem_init(void);
extern void isdn_tty_exit(void);
extern void isdn_tty_readmodem(void);
extern int isdn_tty_find_icall(int, int, setup_parm *);
-extern void isdn_tty_cleanup_xmit(modem_info *);
extern int isdn_tty_stat_callback(int, isdn_ctrl *);
extern int isdn_tty_rcv_skb(int, int, int, struct sk_buff *);
extern int isdn_tty_capi_facility(capi_msg *cm);
diff --git a/drivers/isdn/i4l/isdn_ttyfax.c b/drivers/isdn/i4l/isdn_ttyfax.c
index ce2c3ef92e46..a943d078bacc 100644
--- a/drivers/isdn/i4l/isdn_ttyfax.c
+++ b/drivers/isdn/i4l/isdn_ttyfax.c
@@ -148,7 +148,7 @@ isdn_tty_fax_modem_result(int code, modem_info * info)
}
}
-int
+static int
isdn_tty_fax_command1(modem_info * info, isdn_ctrl * c)
{
static char *msg[] =
@@ -316,7 +316,7 @@ isdn_tty_fax_bitorder(modem_info * info, struct sk_buff *skb)
* Parse AT+F.. FAX class 1 commands
*/
-int
+static int
isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
{
static char *cmd[] =
@@ -408,7 +408,7 @@ isdn_tty_cmd_FCLASS1(char **p, modem_info * info)
* Parse AT+F.. FAX class 2 commands
*/
-int
+static int
isdn_tty_cmd_FCLASS2(char **p, modem_info * info)
{
atemu *m = &info->emu;
diff --git a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
index 4ab7600cf9c1..edf14a2aa3c8 100644
--- a/drivers/isdn/i4l/isdn_x25iface.c
+++ b/drivers/isdn/i4l/isdn_x25iface.c
@@ -40,15 +40,15 @@ typedef struct isdn_x25iface_proto_data {
/* is now in header file (extern): struct concap_proto * isdn_x25iface_proto_new(void); */
-void isdn_x25iface_proto_del( struct concap_proto * );
-int isdn_x25iface_proto_close( struct concap_proto * );
-int isdn_x25iface_proto_restart( struct concap_proto *,
- struct net_device *,
- struct concap_device_ops *);
-int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
-int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
-int isdn_x25iface_connect_ind( struct concap_proto * );
-int isdn_x25iface_disconn_ind( struct concap_proto * );
+static void isdn_x25iface_proto_del( struct concap_proto * );
+static int isdn_x25iface_proto_close( struct concap_proto * );
+static int isdn_x25iface_proto_restart( struct concap_proto *,
+ struct net_device *,
+ struct concap_device_ops *);
+static int isdn_x25iface_xmit( struct concap_proto *, struct sk_buff * );
+static int isdn_x25iface_receive( struct concap_proto *, struct sk_buff * );
+static int isdn_x25iface_connect_ind( struct concap_proto * );
+static int isdn_x25iface_disconn_ind( struct concap_proto * );
static struct concap_proto_ops ix25_pops = {
@@ -102,7 +102,7 @@ struct concap_proto * isdn_x25iface_proto_new(void)
/* close the x25iface encapsulation protocol
*/
-int isdn_x25iface_proto_close(struct concap_proto *cprot){
+static int isdn_x25iface_proto_close(struct concap_proto *cprot){
ix25_pdata_t *tmp;
int ret = 0;
@@ -129,7 +129,7 @@ int isdn_x25iface_proto_close(struct concap_proto *cprot){
/* Delete the x25iface encapsulation protocol instance
*/
-void isdn_x25iface_proto_del(struct concap_proto *cprot){
+static void isdn_x25iface_proto_del(struct concap_proto *cprot){
ix25_pdata_t * tmp;
@@ -158,9 +158,9 @@ void isdn_x25iface_proto_del(struct concap_proto *cprot){
/* (re-)initialize the data structures for x25iface encapsulation
*/
-int isdn_x25iface_proto_restart(struct concap_proto *cprot,
- struct net_device *ndev,
- struct concap_device_ops *dops)
+static int isdn_x25iface_proto_restart(struct concap_proto *cprot,
+ struct net_device *ndev,
+ struct concap_device_ops *dops)
{
ix25_pdata_t * pda = cprot -> proto_data ;
ulong flags;
@@ -187,7 +187,7 @@ int isdn_x25iface_proto_restart(struct concap_proto *cprot,
/* deliver a dl_data frame received from i4l HL driver to the network layer
*/
-int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
+static int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
{
IX25DEBUG( "isdn_x25iface_receive %s \n", MY_DEVNAME(cprot->net_dev) );
if ( ( (ix25_pdata_t*) (cprot->proto_data) )
@@ -206,7 +206,7 @@ int isdn_x25iface_receive(struct concap_proto *cprot, struct sk_buff *skb)
/* a connection set up is indicated by lower layer
*/
-int isdn_x25iface_connect_ind(struct concap_proto *cprot)
+static int isdn_x25iface_connect_ind(struct concap_proto *cprot)
{
struct sk_buff * skb = dev_alloc_skb(1);
enum wan_states *state_p
@@ -235,7 +235,7 @@ int isdn_x25iface_connect_ind(struct concap_proto *cprot)
/* a disconnect is indicated by lower layer
*/
-int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
+static int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
{
struct sk_buff *skb;
enum wan_states *state_p
@@ -264,7 +264,7 @@ int isdn_x25iface_disconn_ind(struct concap_proto *cprot)
/* process a frame handed over to us from linux network layer. First byte
semantics as defined in Documentation/networking/x25-iface.txt
*/
-int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
+static int isdn_x25iface_xmit(struct concap_proto *cprot, struct sk_buff *skb)
{
unsigned char firstbyte = skb->data[0];
enum wan_states *state = &((ix25_pdata_t*)cprot->proto_data)->state;
diff --git a/drivers/isdn/icn/icn.c b/drivers/isdn/icn/icn.c
index 9fc0c1e03732..e0d1b01cc74c 100644
--- a/drivers/isdn/icn/icn.c
+++ b/drivers/isdn/icn/icn.c
@@ -304,12 +304,12 @@ icn_pollbchan_send(int channel, icn_card * card)
isdn_ctrl cmd;
if (!(card->sndcount[channel] || card->xskb[channel] ||
- skb_queue_len(&card->spqueue[channel])))
+ !skb_queue_empty(&card->spqueue[channel])))
return;
if (icn_trymaplock_channel(card, mch)) {
while (sbfree &&
(card->sndcount[channel] ||
- skb_queue_len(&card->spqueue[channel]) ||
+ !skb_queue_empty(&card->spqueue[channel]) ||
card->xskb[channel])) {
spin_lock_irqsave(&card->lock, flags);
if (card->xmit_lock[channel]) {
diff --git a/drivers/isdn/pcbit/callbacks.c b/drivers/isdn/pcbit/callbacks.c
index 692ec72d1ee8..f151f36c8255 100644
--- a/drivers/isdn/pcbit/callbacks.c
+++ b/drivers/isdn/pcbit/callbacks.c
@@ -125,23 +125,6 @@ void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
/*
- * Disconnect received (actually RELEASE COMPLETE)
- * This means we were not able to establish connection with remote
- * Inform the big boss above
- */
-void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
- struct callb_data *data)
-{
- isdn_ctrl ictl;
-
- ictl.command = ISDN_STAT_DHUP;
- ictl.driver=dev->id;
- ictl.arg=chan->id;
- dev->dev_if->statcallb(&ictl);
-}
-
-
-/*
* Incoming call received
* inform user
*/
diff --git a/drivers/isdn/pcbit/callbacks.h b/drivers/isdn/pcbit/callbacks.h
index f510dc56b57e..17aa0f54bfc3 100644
--- a/drivers/isdn/pcbit/callbacks.h
+++ b/drivers/isdn/pcbit/callbacks.h
@@ -19,9 +19,6 @@ extern void cb_out_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
extern void cb_out_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
-extern void cb_out_3(struct pcbit_dev * dev, struct pcbit_chan* chan,
- struct callb_data *data);
-
extern void cb_in_1(struct pcbit_dev * dev, struct pcbit_chan* chan,
struct callb_data *data);
extern void cb_in_2(struct pcbit_dev * dev, struct pcbit_chan* chan,
diff --git a/drivers/isdn/pcbit/capi.c b/drivers/isdn/pcbit/capi.c
index 29eb03a8c29d..bef321d0e51d 100644
--- a/drivers/isdn/pcbit/capi.c
+++ b/drivers/isdn/pcbit/capi.c
@@ -627,16 +627,6 @@ int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
return 0;
}
-int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb)
-{
- ushort errcode;
-
- errcode = *((ushort*) skb->data);
- skb_pull(skb, 2);
-
- return errcode;
-}
-
#ifdef DEBUG
int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
{
diff --git a/drivers/isdn/pcbit/capi.h b/drivers/isdn/pcbit/capi.h
index 18e6aa360a8f..df8e73c04d7f 100644
--- a/drivers/isdn/pcbit/capi.h
+++ b/drivers/isdn/pcbit/capi.h
@@ -54,7 +54,6 @@ extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff ** skb);
/* Connection Termination */
extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
-extern int capi_decode_disc_conf(struct pcbit_chan *chan, struct sk_buff *skb);
extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
diff --git a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
index e98f9c48c184..5de861f40816 100644
--- a/drivers/isdn/pcbit/drv.c
+++ b/drivers/isdn/pcbit/drv.c
@@ -56,10 +56,10 @@ static char* pcbit_devname[MAX_PCBIT_CARDS] = {
* prototypes
*/
-int pcbit_command(isdn_ctrl* ctl);
-int pcbit_stat(u_char __user * buf, int len, int, int);
-int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
-int pcbit_writecmd(const u_char __user *, int, int, int);
+static int pcbit_command(isdn_ctrl* ctl);
+static int pcbit_stat(u_char __user * buf, int len, int, int);
+static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
+static int pcbit_writecmd(const u_char __user *, int, int, int);
static int set_protocol_running(struct pcbit_dev * dev);
@@ -238,7 +238,7 @@ void pcbit_terminate(int board)
}
#endif
-int pcbit_command(isdn_ctrl* ctl)
+static int pcbit_command(isdn_ctrl* ctl)
{
struct pcbit_dev *dev;
struct pcbit_chan *chan;
@@ -330,7 +330,7 @@ static void pcbit_block_timer(unsigned long data)
}
#endif
-int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
+static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
{
ushort hdrlen;
int refnum, len;
@@ -389,7 +389,7 @@ int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
return len;
}
-int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
+static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
{
struct pcbit_dev * dev;
int i, j;
@@ -713,7 +713,7 @@ static char statbuf[STATBUF_LEN];
static int stat_st = 0;
static int stat_end = 0;
-int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
+static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
{
int stat_count;
stat_count = stat_end - stat_st;
diff --git a/drivers/isdn/sc/Makefile b/drivers/isdn/sc/Makefile
index 9cc474cd0c44..0f2b7d602ac0 100644
--- a/drivers/isdn/sc/Makefile
+++ b/drivers/isdn/sc/Makefile
@@ -6,5 +6,5 @@ obj-$(CONFIG_ISDN_DRV_SC) += sc.o
# Multipart objects.
-sc-y := shmem.o init.o debug.o packet.o command.o event.o \
+sc-y := shmem.o init.o packet.o command.o event.o \
ioctl.o interrupt.o message.o timer.o
diff --git a/drivers/isdn/sc/command.c b/drivers/isdn/sc/command.c
index b2c4eac7cef5..19f2fcf0ae4a 100644
--- a/drivers/isdn/sc/command.c
+++ b/drivers/isdn/sc/command.c
@@ -22,14 +22,14 @@
#include "card.h"
#include "scioc.h"
-int dial(int card, unsigned long channel, setup_parm setup);
-int hangup(int card, unsigned long channel);
-int answer(int card, unsigned long channel);
-int clreaz(int card, unsigned long channel);
-int seteaz(int card, unsigned long channel, char *);
-int setl2(int card, unsigned long arg);
-int setl3(int card, unsigned long arg);
-int acceptb(int card, unsigned long channel);
+static int dial(int card, unsigned long channel, setup_parm setup);
+static int hangup(int card, unsigned long channel);
+static int answer(int card, unsigned long channel);
+static int clreaz(int card, unsigned long channel);
+static int seteaz(int card, unsigned long channel, char *);
+static int setl2(int card, unsigned long arg);
+static int setl3(int card, unsigned long arg);
+static int acceptb(int card, unsigned long channel);
extern int cinst;
extern board *sc_adapter[];
@@ -148,56 +148,6 @@ int command(isdn_ctrl *cmd)
}
/*
- * Confirm our ability to communicate with the board. This test assumes no
- * other message activity is present
- */
-int loopback(int card)
-{
-
- int status;
- static char testmsg[] = "Test Message";
- RspMessage rspmsg;
-
- if(!IS_VALID_CARD(card)) {
- pr_debug("Invalid param: %d is not a valid card id\n", card);
- return -ENODEV;
- }
-
- pr_debug("%s: Sending loopback message\n",
- sc_adapter[card]->devicename);
-
- /*
- * Send the loopback message to confirm that memory transfer is
- * operational
- */
- status = send_and_receive(card, CMPID, cmReqType1,
- cmReqClass0,
- cmReqMsgLpbk,
- 0,
- (unsigned char) strlen(testmsg),
- (unsigned char *)testmsg,
- &rspmsg, SAR_TIMEOUT);
-
-
- if (!status) {
- pr_debug("%s: Loopback message successfully sent\n",
- sc_adapter[card]->devicename);
- if(strcmp(rspmsg.msg_data.byte_array, testmsg)) {
- pr_debug("%s: Loopback return != sent\n",
- sc_adapter[card]->devicename);
- return -EIO;
- }
- return 0;
- }
- else {
- pr_debug("%s: Send loopback message failed\n",
- sc_adapter[card]->devicename);
- return -EIO;
- }
-
-}
-
-/*
* start the onboard firmware
*/
int startproc(int card)
@@ -222,16 +172,10 @@ int startproc(int card)
}
-int loadproc(int card, char *data)
-{
- return -1;
-}
-
-
/*
* Dials the number passed in
*/
-int dial(int card, unsigned long channel, setup_parm setup)
+static int dial(int card, unsigned long channel, setup_parm setup)
{
int status;
char Phone[48];
@@ -261,7 +205,7 @@ int dial(int card, unsigned long channel, setup_parm setup)
/*
* Answer an incoming call
*/
-int answer(int card, unsigned long channel)
+static int answer(int card, unsigned long channel)
{
if(!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -282,7 +226,7 @@ int answer(int card, unsigned long channel)
/*
* Hangup up the call on specified channel
*/
-int hangup(int card, unsigned long channel)
+static int hangup(int card, unsigned long channel)
{
int status;
@@ -305,7 +249,7 @@ int hangup(int card, unsigned long channel)
/*
* Set the layer 2 protocol (X.25, HDLC, Raw)
*/
-int setl2(int card, unsigned long arg)
+static int setl2(int card, unsigned long arg)
{
int status =0;
int protocol,channel;
@@ -340,7 +284,7 @@ int setl2(int card, unsigned long arg)
/*
* Set the layer 3 protocol
*/
-int setl3(int card, unsigned long channel)
+static int setl3(int card, unsigned long channel)
{
int protocol = channel >> 8;
@@ -355,7 +299,7 @@ int setl3(int card, unsigned long channel)
return 0;
}
-int acceptb(int card, unsigned long channel)
+static int acceptb(int card, unsigned long channel)
{
if(!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -374,7 +318,7 @@ int acceptb(int card, unsigned long channel)
return 0;
}
-int clreaz(int card, unsigned long arg)
+static int clreaz(int card, unsigned long arg)
{
if(!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
@@ -388,7 +332,7 @@ int clreaz(int card, unsigned long arg)
return 0;
}
-int seteaz(int card, unsigned long arg, char *num)
+static int seteaz(int card, unsigned long arg, char *num)
{
if(!IS_VALID_CARD(card)) {
pr_debug("Invalid param: %d is not a valid card id\n", card);
diff --git a/drivers/isdn/sc/debug.c b/drivers/isdn/sc/debug.c
deleted file mode 100644
index 1a992a75868b..000000000000
--- a/drivers/isdn/sc/debug.c
+++ /dev/null
@@ -1,46 +0,0 @@
-/* $Id: debug.c,v 1.5.6.1 2001/09/23 22:24:59 kai Exp $
- *
- * Copyright (C) 1996 SpellCaster Telecommunications Inc.
- *
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * For more information, please contact gpl-info@spellcast.com or write:
- *
- * SpellCaster Telecommunications Inc.
- * 5621 Finch Avenue East, Unit #3
- * Scarborough, Ontario Canada
- * M1B 2T9
- * +1 (416) 297-8565
- * +1 (416) 297-6433 Facsimile
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-int dbg_level = 0;
-static char dbg_funcname[255];
-
-void dbg_endfunc(void)
-{
- if (dbg_level) {
- printk("<-- Leaving function %s\n", dbg_funcname);
- strcpy(dbg_funcname, "");
- }
-}
-
-void dbg_func(char *func)
-{
- strcpy(dbg_funcname, func);
- if(dbg_level)
- printk("--> Entering function %s\n", dbg_funcname);
-}
-
-inline void pullphone(char *dn, char *str)
-{
- int i = 0;
-
- while(dn[i] != ',')
- str[i] = dn[i], i++;
- str[i] = 0x0;
-}
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index efefedea37b9..40b0df04ed9f 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -20,9 +20,9 @@ board *sc_adapter[MAX_CARDS];
int cinst;
static char devname[] = "scX";
-const char version[] = "2.0b1";
+static const char version[] = "2.0b1";
-const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
+static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCommute/BRI" };
/* insmod set parameters */
static unsigned int io[] = {0,0,0,0};
@@ -35,26 +35,13 @@ module_param_array(irq, int, NULL, 0);
module_param_array(ram, int, NULL, 0);
module_param(do_reset, bool, 0);
-static int sup_irq[] = { 11, 10, 9, 5, 12, 14, 7, 3, 4, 6 };
-#define MAX_IRQS 10
-
extern irqreturn_t interrupt_handler(int, void *, struct pt_regs *);
extern int sndpkt(int, int, int, struct sk_buff *);
extern int command(isdn_ctrl *);
extern int indicate_status(int, int, ulong, char*);
extern int reset(int);
-int identify_board(unsigned long, unsigned int);
-
-int irq_supported(int irq_x)
-{
- int i;
- for(i=0 ; i < MAX_IRQS ; i++) {
- if(sup_irq[i] == irq_x)
- return 1;
- }
- return 0;
-}
+static int identify_board(unsigned long, unsigned int);
static int __init sc_init(void)
{
@@ -454,7 +441,7 @@ static void __exit sc_exit(void)
pr_info("SpellCaster ISA ISDN Adapter Driver Unloaded.\n");
}
-int identify_board(unsigned long rambase, unsigned int iobase)
+static int identify_board(unsigned long rambase, unsigned int iobase)
{
unsigned int pgport;
unsigned long sig;
diff --git a/drivers/isdn/sc/interrupt.c b/drivers/isdn/sc/interrupt.c
index e5e164aca7fa..8631d338d69a 100644
--- a/drivers/isdn/sc/interrupt.c
+++ b/drivers/isdn/sc/interrupt.c
@@ -31,7 +31,7 @@ extern void rcvpkt(int, RspMessage *);
extern int cinst;
extern board *sc_adapter[];
-int get_card_from_irq(int irq)
+static int get_card_from_irq(int irq)
{
int i;
diff --git a/drivers/isdn/sc/ioctl.c b/drivers/isdn/sc/ioctl.c
index 1371a990416a..3314a5a19854 100644
--- a/drivers/isdn/sc/ioctl.c
+++ b/drivers/isdn/sc/ioctl.c
@@ -14,7 +14,6 @@
extern int indicate_status(int, int, unsigned long, char *);
extern int startproc(int);
-extern int loadproc(int, char *record);
extern int reset(int);
extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
unsigned char,unsigned char,
@@ -23,7 +22,7 @@ extern int send_and_receive(int, unsigned int, unsigned char,unsigned char,
extern board *sc_adapter[];
-int GetStatus(int card, boardInfo *);
+static int GetStatus(int card, boardInfo *);
/*
* Process private IOCTL messages (typically from scctrl)
@@ -428,7 +427,7 @@ int sc_ioctl(int card, scs_ioctl *data)
return 0;
}
-int GetStatus(int card, boardInfo *bi)
+static int GetStatus(int card, boardInfo *bi)
{
RspMessage rcvmsg;
int i, status;
diff --git a/drivers/isdn/sc/packet.c b/drivers/isdn/sc/packet.c
index 8e3fac3ba1a1..f50defc38ae5 100644
--- a/drivers/isdn/sc/packet.c
+++ b/drivers/isdn/sc/packet.c
@@ -213,19 +213,3 @@ int setup_buffers(int card, int c)
return 0;
}
-int print_skb(int card,char *skb_p, int len){
- int i,data;
- pr_debug("%s: data at 0x%x len: 0x%x\n", sc_adapter[card]->devicename,
- skb_p,len);
- for(i=1;i<=len;i++,skb_p++){
- data = (int) (0xff & (*skb_p));
- pr_debug("%s: data = 0x%x", sc_adapter[card]->devicename,data);
- if(!(i%4))
- pr_debug(" ");
- if(!(i%32))
- pr_debug("\n");
- }
- pr_debug("\n");
- return 0;
-}
-
diff --git a/drivers/isdn/sc/shmem.c b/drivers/isdn/sc/shmem.c
index 7bc2dfad0775..24854826ca45 100644
--- a/drivers/isdn/sc/shmem.c
+++ b/drivers/isdn/sc/shmem.c
@@ -108,6 +108,7 @@ void memcpy_fromshmem(int card, void *dest, const void *src, size_t n)
sc_adapter[card]->rambase + ((unsigned long) src %0x4000), (unsigned long) dest); */
}
+#if 0
void memset_shmem(int card, void *dest, int c, size_t n)
{
unsigned long flags;
@@ -141,3 +142,4 @@ void memset_shmem(int card, void *dest, int c, size_t n)
((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
}
+#endif /* 0 */
diff --git a/drivers/isdn/sc/timer.c b/drivers/isdn/sc/timer.c
index 710d0f47ca35..aced19aac5a2 100644
--- a/drivers/isdn/sc/timer.c
+++ b/drivers/isdn/sc/timer.c
@@ -32,7 +32,7 @@ extern int sendmessage(int, unsigned int, unsigned int, unsigned int,
/*
* Write the proper values into the I/O ports following a reset
*/
-void setup_ports(int card)
+static void setup_ports(int card)
{
outb((sc_adapter[card]->rambase >> 12), sc_adapter[card]->ioport[EXP_BASE]);
@@ -129,19 +129,3 @@ void check_phystat(unsigned long data)
ceReqPhyStatus,0,0,NULL);
}
-/*
- * When in trace mode, this callback is used to swap the working shared
- * RAM page to the trace page(s) and process all received messages. It
- * must be called often enough to get all of the messages out of RAM before
- * it loops around.
- * Trace messages are \n terminated strings.
- * We output the messages in 64 byte chunks through readstat. Each chunk
- * is scanned for a \n followed by a time stamp. If the timerstamp is older
- * than the current time, scanning stops and the page and offset are recorded
- * as the starting point the next time the trace timer is called. The final
- * step is to restore the working page and reset the timer.
- */
-void trace_timer(unsigned long data)
-{
- /* not implemented */
-}
diff --git a/drivers/macintosh/Kconfig b/drivers/macintosh/Kconfig
index 8a7117a08cf0..91691a6c004e 100644
--- a/drivers/macintosh/Kconfig
+++ b/drivers/macintosh/Kconfig
@@ -86,33 +86,18 @@ config PMAC_SMU
on the "SMU" system control chip which replaces the old PMU.
If you don't know, say Y.
-config PMAC_PBOOK
- bool "Power management support for PowerBooks"
- depends on ADB_PMU
- ---help---
- This provides support for putting a PowerBook to sleep; it also
- enables media bay support. Power management works on the
- PB2400/3400/3500, Wallstreet, Lombard, and Bronze PowerBook G3 and
- the Titanium Powerbook G4, as well as the iBooks. You should get
- the power management daemon, pmud, to make it work and you must have
- the /dev/pmu device (see the pmud README).
-
- Get pmud from <ftp://ftp.samba.org/pub/ppclinux/pmud/>.
-
- If you have a PowerBook, you should say Y here.
-
- You may also want to compile the dma sound driver as a module and
- have it autoloaded. The act of removing the module shuts down the
- sound hardware for more power savings.
-
-config PM
- bool
- depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK
- default y
-
config PMAC_APM_EMU
tristate "APM emulation"
- depends on PMAC_PBOOK
+ depends on PPC_PMAC && PPC32 && PM
+
+config PMAC_MEDIABAY
+ bool "Support PowerBook hotswap media bay"
+ depends on PPC_PMAC && PPC32
+ help
+ This option adds support for older PowerBook's hotswap media bay
+ that can contains batteries, floppy drives, or IDE devices. PCI
+ devices are not fully supported in the bay as I never had one to
+ try with
# made a separate option since backlight may end up beeing used
# on non-powerbook machines (but only on PMU based ones AFAIK)
@@ -126,13 +111,6 @@ config PMAC_BACKLIGHT
events; also, the PowerBook button device will be enabled so you can
change the screen brightness.
-config MAC_SERIAL
- tristate "Support for PowerMac serial ports (OBSOLETE DRIVER)"
- depends on PPC_PMAC && BROKEN
- help
- This driver is obsolete. Use CONFIG_SERIAL_PMACZILOG in
- "Character devices --> Serial drivers --> PowerMac z85c30" option.
-
config ADB_MACIO
bool "Include MacIO (CHRP) ADB driver"
depends on ADB && PPC_CHRP && !PPC_PMAC64
diff --git a/drivers/macintosh/Makefile b/drivers/macintosh/Makefile
index c3a4705a8295..236291bd48a4 100644
--- a/drivers/macintosh/Makefile
+++ b/drivers/macintosh/Makefile
@@ -4,10 +4,9 @@
# Each configuration option enables a list of files.
-obj-$(CONFIG_PPC_PMAC) += macio_asic.o
+obj-$(CONFIG_PPC_PMAC) += macio_asic.o macio_sysfs.o
-obj-$(CONFIG_PMAC_PBOOK) += mediabay.o
-obj-$(CONFIG_MAC_SERIAL) += macserial.o
+obj-$(CONFIG_PMAC_MEDIABAY) += mediabay.o
obj-$(CONFIG_MAC_EMUMOUSEBTN) += mac_hid.o
obj-$(CONFIG_INPUT_ADBHID) += adbhid.o
obj-$(CONFIG_ANSLCD) += ans-lcd.o
diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
index 493e2afa191c..c0dc1e3fa58b 100644
--- a/drivers/macintosh/adb.c
+++ b/drivers/macintosh/adb.c
@@ -90,7 +90,7 @@ static int sleepy_trackpad;
static int autopoll_devs;
int __adb_probe_sync;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static int adb_notify_sleep(struct pmu_sleep_notifier *self, int when);
static struct pmu_sleep_notifier adb_sleep_notifier = {
adb_notify_sleep,
@@ -320,9 +320,9 @@ int __init adb_init(void)
printk(KERN_WARNING "Warning: no ADB interface detected\n");
adb_controller = NULL;
} else {
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
pmu_register_sleep_notifier(&adb_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
#ifdef CONFIG_PPC
if (machine_is_compatible("AAPL,PowerBook1998") ||
machine_is_compatible("PowerBook1,1"))
@@ -337,7 +337,7 @@ int __init adb_init(void)
__initcall(adb_init);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* notify clients before sleep and reset bus afterwards
*/
@@ -378,7 +378,7 @@ adb_notify_sleep(struct pmu_sleep_notifier *self, int when)
}
return PBOOK_SLEEP_OK;
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
static int
do_adb_reset_bus(void)
diff --git a/drivers/macintosh/macio_asic.c b/drivers/macintosh/macio_asic.c
index d0bda7e3e6aa..1ee003346923 100644
--- a/drivers/macintosh/macio_asic.c
+++ b/drivers/macintosh/macio_asic.c
@@ -33,7 +33,7 @@ static int macio_bus_match(struct device *dev, struct device_driver *drv)
{
struct macio_dev * macio_dev = to_macio_device(dev);
struct macio_driver * macio_drv = to_macio_driver(drv);
- const struct of_match * matches = macio_drv->match_table;
+ const struct of_device_id * matches = macio_drv->match_table;
if (!matches)
return 0;
@@ -66,7 +66,7 @@ static int macio_device_probe(struct device *dev)
int error = -ENODEV;
struct macio_driver *drv;
struct macio_dev *macio_dev;
- const struct of_match *match;
+ const struct of_device_id *match;
drv = to_macio_driver(dev->driver);
macio_dev = to_macio_device(dev);
@@ -126,11 +126,85 @@ static int macio_device_resume(struct device * dev)
return 0;
}
+static int macio_hotplug (struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct macio_dev * macio_dev;
+ struct of_device * of;
+ char *scratch, *compat;
+ int i = 0;
+ int length = 0;
+ int cplen, seen = 0;
+
+ if (!dev)
+ return -ENODEV;
+
+ macio_dev = to_macio_device(dev);
+ if (!macio_dev)
+ return -ENODEV;
+
+ of = &macio_dev->ofdev;
+ scratch = buffer;
+
+ /* stuff we want to pass to /sbin/hotplug */
+ envp[i++] = scratch;
+ length += scnprintf (scratch, buffer_size - length, "OF_NAME=%s",
+ of->node->name);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ ++length;
+ scratch += length;
+
+ envp[i++] = scratch;
+ length += scnprintf (scratch, buffer_size - length, "OF_TYPE=%s",
+ of->node->type);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ ++length;
+ scratch += length;
+
+ /* Since the compatible field can contain pretty much anything
+ * it's not really legal to split it out with commas. We split it
+ * up using a number of environment variables instead. */
+
+ compat = (char *) get_property(of->node, "compatible", &cplen);
+ while (compat && cplen > 0) {
+ int l;
+ envp[i++] = scratch;
+ length += scnprintf (scratch, buffer_size - length,
+ "OF_COMPATIBLE_%d=%s", seen, compat);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ length++;
+ scratch += length;
+ l = strlen (compat) + 1;
+ compat += l;
+ cplen -= l;
+ seen++;
+ }
+
+ envp[i++] = scratch;
+ length += scnprintf (scratch, buffer_size - length,
+ "OF_COMPATIBLE_N=%d", seen);
+ if ((buffer_size - length <= 0) || (i >= num_envp))
+ return -ENOMEM;
+ ++length;
+ scratch += length;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+extern struct device_attribute macio_dev_attrs[];
+
struct bus_type macio_bus_type = {
.name = "macio",
.match = macio_bus_match,
+ .hotplug = macio_hotplug,
.suspend = macio_device_suspend,
.resume = macio_device_resume,
+ .dev_attrs = macio_dev_attrs,
};
static int __init macio_bus_driver_init(void)
diff --git a/drivers/macintosh/macio_sysfs.c b/drivers/macintosh/macio_sysfs.c
new file mode 100644
index 000000000000..97d22bb4516a
--- /dev/null
+++ b/drivers/macintosh/macio_sysfs.c
@@ -0,0 +1,50 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <asm/macio.h>
+
+
+#define macio_config_of_attr(field, format_string) \
+static ssize_t \
+field##_show (struct device *dev, struct device_attribute *attr, \
+ char *buf) \
+{ \
+ struct macio_dev *mdev = to_macio_device (dev); \
+ return sprintf (buf, format_string, mdev->ofdev.node->field); \
+}
+
+static ssize_t
+compatible_show (struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct of_device *of;
+ char *compat;
+ int cplen;
+ int length = 0;
+
+ of = &to_macio_device (dev)->ofdev;
+ compat = (char *) get_property(of->node, "compatible", &cplen);
+ if (!compat) {
+ *buf = '\0';
+ return 0;
+ }
+ while (cplen > 0) {
+ int l;
+ length += sprintf (buf, "%s\n", compat);
+ buf += length;
+ l = strlen (compat) + 1;
+ compat += l;
+ cplen -= l;
+ }
+
+ return length;
+}
+
+macio_config_of_attr (name, "%s\n");
+macio_config_of_attr (type, "%s\n");
+
+struct device_attribute macio_dev_attrs[] = {
+ __ATTR_RO(name),
+ __ATTR_RO(type),
+ __ATTR_RO(compatible),
+ __ATTR_NULL
+};
diff --git a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
deleted file mode 100644
index 0be3ac6cc169..000000000000
--- a/drivers/macintosh/macserial.c
+++ /dev/null
@@ -1,3036 +0,0 @@
-/*
- * macserial.c: Serial port driver for Power Macintoshes.
- *
- * Derived from drivers/sbus/char/sunserial.c by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- *
- * Receive DMA code by Takashi Oe <toe@unlserve.unl.edu>.
- *
- * $Id: macserial.c,v 1.24.2.4 1999/10/19 04:36:42 paulus Exp $
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/workqueue.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/major.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#ifdef CONFIG_SERIAL_CONSOLE
-#include <linux/console.h>
-#endif
-#include <linux/slab.h>
-#include <linux/bitops.h>
-
-#include <asm/sections.h>
-#include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/prom.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#ifdef CONFIG_KGDB
-#include <asm/kgdb.h>
-#endif
-#include <asm/dbdma.h>
-
-#include "macserial.h"
-
-#ifdef CONFIG_PMAC_PBOOK
-static int serial_notify_sleep(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier serial_sleep_notifier = {
- serial_notify_sleep,
- SLEEP_LEVEL_MISC,
-};
-#endif
-
-#define SUPPORT_SERIAL_DMA
-#define MACSERIAL_VERSION "2.0"
-
-/*
- * It would be nice to dynamically allocate everything that
- * depends on NUM_SERIAL, so we could support any number of
- * Z8530s, but for now...
- */
-#define NUM_SERIAL 2 /* Max number of ZS chips supported */
-#define NUM_CHANNELS (NUM_SERIAL * 2) /* 2 channels per chip */
-
-/* On PowerMacs, the hardware takes care of the SCC recovery time,
- but we need the eieio to make sure that the accesses occur
- in the order we want. */
-#define RECOVERY_DELAY eieio()
-
-static struct tty_driver *serial_driver;
-
-struct mac_zschannel zs_channels[NUM_CHANNELS];
-
-struct mac_serial zs_soft[NUM_CHANNELS];
-int zs_channels_found;
-struct mac_serial *zs_chain; /* list of all channels */
-
-struct tty_struct zs_ttys[NUM_CHANNELS];
-
-static int is_powerbook;
-
-#ifdef CONFIG_SERIAL_CONSOLE
-static struct console sercons;
-#endif
-
-#ifdef CONFIG_KGDB
-struct mac_zschannel *zs_kgdbchan;
-static unsigned char scc_inittab[] = {
- 9, 0x80, /* reset A side (CHRA) */
- 13, 0, /* set baud rate divisor */
- 12, 1,
- 14, 1, /* baud rate gen enable, src=rtxc (BRENABL) */
- 11, 0x50, /* clocks = br gen (RCBR | TCBR) */
- 5, 0x6a, /* tx 8 bits, assert RTS (Tx8 | TxENAB | RTS) */
- 4, 0x44, /* x16 clock, 1 stop (SB1 | X16CLK)*/
- 3, 0xc1, /* rx enable, 8 bits (RxENABLE | Rx8)*/
-};
-#endif
-#define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */
-
-/* serial subtype definitions */
-#define SERIAL_TYPE_NORMAL 1
-
-/* number of characters left in xmit buffer before we ask for more */
-#define WAKEUP_CHARS 256
-
-/*
- * Debugging.
- */
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_POWER
-#undef SERIAL_DEBUG_THROTTLE
-#undef SERIAL_DEBUG_STOP
-#undef SERIAL_DEBUG_BAUDS
-
-#define RS_STROBE_TIME 10
-#define RS_ISR_PASS_LIMIT 256
-
-#define _INLINE_ inline
-
-#ifdef SERIAL_DEBUG_OPEN
-#define OPNDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
-#else
-#define OPNDBG(fmt, arg...) do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_POWER
-#define PWRDBG(fmt, arg...) printk(KERN_DEBUG fmt , ## arg)
-#else
-#define PWRDBG(fmt, arg...) do { } while (0)
-#endif
-#ifdef SERIAL_DEBUG_BAUDS
-#define BAUDBG(fmt, arg...) printk(fmt , ## arg)
-#else
-#define BAUDBG(fmt, arg...) do { } while (0)
-#endif
-
-static void probe_sccs(void);
-static void change_speed(struct mac_serial *info, struct termios *old);
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
-static int set_scc_power(struct mac_serial * info, int state);
-static int setup_scc(struct mac_serial * info);
-static void dbdma_reset(volatile struct dbdma_regs *dma);
-static void dbdma_flush(volatile struct dbdma_regs *dma);
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs);
-static void dma_init(struct mac_serial * info);
-static void rxdma_start(struct mac_serial * info, int curr);
-static void rxdma_to_tty(struct mac_serial * info);
-
-/*
- * 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,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char *tmp_buf;
-static DECLARE_MUTEX(tmp_buf_sem);
-
-
-static inline int __pmac
-serial_paranoia_check(struct mac_serial *info,
- char *name, const char *routine)
-{
-#ifdef SERIAL_PARANOIA_CHECK
- static const char badmagic[] = KERN_WARNING
- "Warning: bad magic number for serial struct %s in %s\n";
- static const char badinfo[] = KERN_WARNING
- "Warning: null mac_serial for %s in %s\n";
-
- if (!info) {
- printk(badinfo, name, routine);
- return 1;
- }
- if (info->magic != SERIAL_MAGIC) {
- printk(badmagic, name, routine);
- return 1;
- }
-#endif
- return 0;
-}
-
-/*
- * Reading and writing Z8530 registers.
- */
-static inline unsigned char __pmac read_zsreg(struct mac_zschannel *channel,
- unsigned char reg)
-{
- unsigned char retval;
- unsigned long flags;
-
- /*
- * We have to make this atomic.
- */
- spin_lock_irqsave(&channel->lock, flags);
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- retval = *channel->control;
- RECOVERY_DELAY;
- spin_unlock_irqrestore(&channel->lock, flags);
- return retval;
-}
-
-static inline void __pmac write_zsreg(struct mac_zschannel *channel,
- unsigned char reg, unsigned char value)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&channel->lock, flags);
- if (reg != 0) {
- *channel->control = reg;
- RECOVERY_DELAY;
- }
- *channel->control = value;
- RECOVERY_DELAY;
- spin_unlock_irqrestore(&channel->lock, flags);
- return;
-}
-
-static inline unsigned char __pmac read_zsdata(struct mac_zschannel *channel)
-{
- unsigned char retval;
-
- retval = *channel->data;
- RECOVERY_DELAY;
- return retval;
-}
-
-static inline void write_zsdata(struct mac_zschannel *channel,
- unsigned char value)
-{
- *channel->data = value;
- RECOVERY_DELAY;
- return;
-}
-
-static inline void load_zsregs(struct mac_zschannel *channel,
- unsigned char *regs)
-{
- ZS_CLEARERR(channel);
- ZS_CLEARFIFO(channel);
- /* Load 'em up */
- write_zsreg(channel, R4, regs[R4]);
- write_zsreg(channel, R10, regs[R10]);
- write_zsreg(channel, R3, regs[R3] & ~RxENABLE);
- write_zsreg(channel, R5, regs[R5] & ~TxENAB);
- write_zsreg(channel, R1, regs[R1]);
- write_zsreg(channel, R9, regs[R9]);
- write_zsreg(channel, R11, regs[R11]);
- write_zsreg(channel, R12, regs[R12]);
- write_zsreg(channel, R13, regs[R13]);
- write_zsreg(channel, R14, regs[R14]);
- write_zsreg(channel, R15, regs[R15]);
- write_zsreg(channel, R3, regs[R3]);
- write_zsreg(channel, R5, regs[R5]);
- return;
-}
-
-/* Sets or clears DTR/RTS on the requested line */
-static inline void zs_rtsdtr(struct mac_serial *ss, int set)
-{
- if (set)
- ss->curregs[5] |= (RTS | DTR);
- else
- ss->curregs[5] &= ~(RTS | DTR);
- write_zsreg(ss->zs_channel, 5, ss->curregs[5]);
- return;
-}
-
-/* Utility routines for the Zilog */
-static inline int get_zsbaud(struct mac_serial *ss)
-{
- struct mac_zschannel *channel = ss->zs_channel;
- int brg;
-
- if ((ss->curregs[R11] & TCBR) == 0) {
- /* higher rates don't use the baud rate generator */
- return (ss->curregs[R4] & X32CLK)? ZS_CLOCK/32: ZS_CLOCK/16;
- }
- /* The baud rate is split up between two 8-bit registers in
- * what is termed 'BRG time constant' format in my docs for
- * the chip, it is a function of the clk rate the chip is
- * receiving which happens to be constant.
- */
- brg = (read_zsreg(channel, 13) << 8);
- brg |= read_zsreg(channel, 12);
- return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor)));
-}
-
-/* On receive, this clears errors and the receiver interrupts */
-static inline void rs_recv_clear(struct mac_zschannel *zsc)
-{
- write_zsreg(zsc, 0, ERR_RES);
- write_zsreg(zsc, 0, RES_H_IUS); /* XXX this is unnecessary */
-}
-
-/*
- * Reset a Descriptor-Based DMA channel.
- */
-static void dbdma_reset(volatile struct dbdma_regs *dma)
-{
- int i;
-
- out_le32(&dma->control, (WAKE|FLUSH|PAUSE|RUN) << 16);
-
- /*
- * Yes this looks peculiar, but apparently it needs to be this
- * way on some machines. (We need to make sure the DBDMA
- * engine has actually got the write above and responded
- * to it. - paulus)
- */
- for (i = 200; i > 0; --i)
- if (ld_le32(&dma->status) & RUN)
- udelay(1);
-}
-
-/*
- * Tells a DBDMA channel to stop and write any buffered data
- * it might have to memory.
- */
-static _INLINE_ void dbdma_flush(volatile struct dbdma_regs *dma)
-{
- int i = 0;
-
- out_le32(&dma->control, (FLUSH << 16) | FLUSH);
- while (((in_le32(&dma->status) & FLUSH) != 0) && (i++ < 100))
- udelay(1);
-}
-
-/*
- * ----------------------------------------------------------------------
- *
- * Here starts the interrupt handling routines. All of the following
- * subroutines are declared as inline and are folded into
- * rs_interrupt(). They were separated out for readability's sake.
- *
- * - Ted Ts'o (tytso@mit.edu), 7-Mar-93
- * -----------------------------------------------------------------------
- */
-
-/*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- */
-static _INLINE_ void rs_sched_event(struct mac_serial *info,
- int event)
-{
- info->event |= 1 << event;
- schedule_work(&info->tqueue);
-}
-
-/* Work out the flag value for a z8530 status value. */
-static _INLINE_ int stat_to_flag(int stat)
-{
- int flag;
-
- if (stat & Rx_OVR) {
- flag = TTY_OVERRUN;
- } else if (stat & FRM_ERR) {
- flag = TTY_FRAME;
- } else if (stat & PAR_ERR) {
- flag = TTY_PARITY;
- } else
- flag = 0;
- return flag;
-}
-
-static _INLINE_ void receive_chars(struct mac_serial *info,
- struct pt_regs *regs)
-{
- struct tty_struct *tty = info->tty;
- unsigned char ch, stat, flag;
-
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) != 0) {
-
- stat = read_zsreg(info->zs_channel, R1);
- ch = read_zsdata(info->zs_channel);
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- if (ch == 0x03 || ch == '$')
- breakpoint();
- if (stat & (Rx_OVR|FRM_ERR|PAR_ERR))
- write_zsreg(info->zs_channel, 0, ERR_RES);
- return;
- }
-#endif
- if (!tty)
- continue;
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- tty_flip_buffer_push(tty);
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- static int flip_buf_ovf;
- if (++flip_buf_ovf <= 1)
- printk(KERN_WARNING "FB. overflow: %d\n",
- flip_buf_ovf);
- break;
- }
- tty->flip.count++;
- {
- static int flip_max_cnt;
- if (flip_max_cnt < tty->flip.count)
- flip_max_cnt = tty->flip.count;
- }
- flag = stat_to_flag(stat);
- if (flag)
- /* reset the error indication */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- *tty->flip.flag_buf_ptr++ = flag;
- *tty->flip.char_buf_ptr++ = ch;
- }
- if (tty)
- tty_flip_buffer_push(tty);
-}
-
-static void transmit_chars(struct mac_serial *info)
-{
- if ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0)
- return;
- info->tx_active = 0;
-
- if (info->x_char && !info->power_wait) {
- /* Send next char */
- write_zsdata(info->zs_channel, info->x_char);
- info->x_char = 0;
- info->tx_active = 1;
- return;
- }
-
- if ((info->xmit_cnt <= 0) || info->tty->stopped || info->tx_stopped
- || info->power_wait) {
- write_zsreg(info->zs_channel, 0, RES_Tx_P);
- return;
- }
-
- /* Send char */
- write_zsdata(info->zs_channel, info->xmit_buf[info->xmit_tail++]);
- info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
- info->xmit_cnt--;
- info->tx_active = 1;
-
- if (info->xmit_cnt < WAKEUP_CHARS)
- rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
-}
-
-static void powerup_done(unsigned long data)
-{
- struct mac_serial *info = (struct mac_serial *) data;
- unsigned long flags;
-
- spin_lock_irqsave(&info->lock, flags);
- info->power_wait = 0;
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static _INLINE_ void status_handle(struct mac_serial *info)
-{
- unsigned char status;
-
- /* Get status from Read Register 0 */
- status = read_zsreg(info->zs_channel, 0);
-
- /* Check for DCD transitions */
- if (((status ^ info->read_reg_zero) & DCD) != 0
- && info->tty && !C_CLOCAL(info->tty)) {
- if (status & DCD) {
- wake_up_interruptible(&info->open_wait);
- } else {
- if (info->tty)
- tty_hangup(info->tty);
- }
- }
-
- /* Check for CTS transitions */
- if (info->tty && C_CRTSCTS(info->tty)) {
- /*
- * For some reason, on the Power Macintosh,
- * it seems that the CTS bit is 1 when CTS is
- * *negated* and 0 when it is asserted.
- * The DCD bit doesn't seem to be inverted
- * like this.
- */
- if ((status & CTS) == 0) {
- if (info->tx_stopped) {
-#ifdef SERIAL_DEBUG_FLOW
- printk(KERN_DEBUG "CTS up\n");
-#endif
- info->tx_stopped = 0;
- if (!info->tx_active)
- transmit_chars(info);
- }
- } else {
-#ifdef SERIAL_DEBUG_FLOW
- printk(KERN_DEBUG "CTS down\n");
-#endif
- info->tx_stopped = 1;
- }
- }
-
- /* Clear status condition... */
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- info->read_reg_zero = status;
-}
-
-static _INLINE_ void receive_special_dma(struct mac_serial *info)
-{
- unsigned char stat, flag;
- volatile struct dbdma_regs *rd = &info->rx->dma;
- int where = RX_BUF_SIZE;
-
- spin_lock(&info->rx_dma_lock);
- if ((ld_le32(&rd->status) & ACTIVE) != 0)
- dbdma_flush(rd);
- if (in_le32(&rd->cmdptr)
- == virt_to_bus(info->rx_cmds[info->rx_cbuf] + 1))
- where -= in_le16(&info->rx->res_count);
- where--;
-
- stat = read_zsreg(info->zs_channel, R1);
-
- flag = stat_to_flag(stat);
- if (flag) {
- info->rx_flag_buf[info->rx_cbuf][where] = flag;
- /* reset the error indication */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- }
-
- spin_unlock(&info->rx_dma_lock);
-}
-
-/*
- * This is the serial driver's generic interrupt routine
- */
-static irqreturn_t rs_interrupt(int irq, void *dev_id, struct pt_regs * regs)
-{
- struct mac_serial *info = (struct mac_serial *) dev_id;
- unsigned char zs_intreg;
- int shift;
- unsigned long flags;
- int handled = 0;
-
- if (!(info->flags & ZILOG_INITIALIZED)) {
- printk(KERN_WARNING "rs_interrupt: irq %d, port not "
- "initialized\n", irq);
- disable_irq(irq);
- return IRQ_NONE;
- }
-
- /* NOTE: The read register 3, which holds the irq status,
- * does so for both channels on each chip. Although
- * the status value itself must be read from the A
- * channel and is only valid when read from channel A.
- * Yes... broken hardware...
- */
-#define CHAN_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT)
-
- if (info->zs_chan_a == info->zs_channel)
- shift = 3; /* Channel A */
- else
- shift = 0; /* Channel B */
-
- spin_lock_irqsave(&info->lock, flags);
- for (;;) {
- zs_intreg = read_zsreg(info->zs_chan_a, 3) >> shift;
-#ifdef SERIAL_DEBUG_INTR
- printk(KERN_DEBUG "rs_interrupt: irq %d, zs_intreg 0x%x\n",
- irq, (int)zs_intreg);
-#endif
-
- if ((zs_intreg & CHAN_IRQMASK) == 0)
- break;
- handled = 1;
-
- if (zs_intreg & CHBRxIP) {
- /* If we are doing DMA, we only ask for interrupts
- on characters with errors or special conditions. */
- if (info->dma_initted)
- receive_special_dma(info);
- else
- receive_chars(info, regs);
- }
- if (zs_intreg & CHBTxIP)
- transmit_chars(info);
- if (zs_intreg & CHBEXT)
- status_handle(info);
- }
- spin_unlock_irqrestore(&info->lock, flags);
- return IRQ_RETVAL(handled);
-}
-
-/* Transmit DMA interrupt - not used at present */
-static irqreturn_t rs_txdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- return IRQ_HANDLED;
-}
-
-/*
- * Receive DMA interrupt.
- */
-static irqreturn_t rs_rxdma_irq(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct mac_serial *info = (struct mac_serial *) dev_id;
- volatile struct dbdma_cmd *cd;
-
- if (!info->dma_initted)
- return IRQ_NONE;
- spin_lock(&info->rx_dma_lock);
- /* First, confirm that this interrupt is, indeed, coming */
- /* from Rx DMA */
- cd = info->rx_cmds[info->rx_cbuf] + 2;
- if ((in_le16(&cd->xfer_status) & (RUN | ACTIVE)) != (RUN | ACTIVE)) {
- spin_unlock(&info->rx_dma_lock);
- return IRQ_NONE;
- }
- if (info->rx_fbuf != RX_NO_FBUF) {
- info->rx_cbuf = info->rx_fbuf;
- if (++info->rx_fbuf == info->rx_nbuf)
- info->rx_fbuf = 0;
- if (info->rx_fbuf == info->rx_ubuf)
- info->rx_fbuf = RX_NO_FBUF;
- }
- spin_unlock(&info->rx_dma_lock);
- return IRQ_HANDLED;
-}
-
-/*
- * -------------------------------------------------------------------
- * Here ends the serial interrupt routines.
- * -------------------------------------------------------------------
- */
-
-/*
- * ------------------------------------------------------------
- * rs_stop() and rs_start()
- *
- * This routines are called before setting or resetting tty->stopped.
- * ------------------------------------------------------------
- */
-static void rs_stop(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
-#ifdef SERIAL_DEBUG_STOP
- printk(KERN_DEBUG "rs_stop %ld....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_stop"))
- return;
-
-#if 0
- spin_lock_irqsave(&info->lock, flags);
- if (info->curregs[5] & TxENAB) {
- info->curregs[5] &= ~TxENAB;
- info->pendregs[5] &= ~TxENAB;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- }
- spin_unlock_irqrestore(&info->lock, flags);
-#endif
-}
-
-static void rs_start(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
-#ifdef SERIAL_DEBUG_STOP
- printk(KERN_DEBUG "rs_start %ld....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_start"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
-#if 0
- if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) {
- info->curregs[5] |= TxENAB;
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- }
-#else
- if (info->xmit_cnt && info->xmit_buf && !info->tx_active) {
- transmit_chars(info);
- }
-#endif
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void do_softint(void *private_)
-{
- struct mac_serial *info = (struct mac_serial *) private_;
- struct tty_struct *tty;
-
- tty = info->tty;
- if (!tty)
- return;
-
- if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event))
- tty_wakeup(tty);
-}
-
-static int startup(struct mac_serial * info)
-{
- int delay;
-
- OPNDBG("startup() (ttyS%d, irq %d)\n", info->line, info->irq);
-
- if (info->flags & ZILOG_INITIALIZED) {
- OPNDBG(" -> already inited\n");
- return 0;
- }
-
- if (!info->xmit_buf) {
- info->xmit_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL);
- if (!info->xmit_buf)
- return -ENOMEM;
- }
-
- OPNDBG("starting up ttyS%d (irq %d)...\n", info->line, info->irq);
-
- delay = set_scc_power(info, 1);
-
- setup_scc(info);
-
- if (delay) {
- unsigned long flags;
-
- /* delay is in ms */
- spin_lock_irqsave(&info->lock, flags);
- info->power_wait = 1;
- mod_timer(&info->powerup_timer,
- jiffies + (delay * HZ + 999) / 1000);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- OPNDBG("enabling IRQ on ttyS%d (irq %d)...\n", info->line, info->irq);
-
- info->flags |= ZILOG_INITIALIZED;
- enable_irq(info->irq);
- if (info->dma_initted) {
- enable_irq(info->rx_dma_irq);
- }
-
- return 0;
-}
-
-static _INLINE_ void rxdma_start(struct mac_serial * info, int curr)
-{
- volatile struct dbdma_regs *rd = &info->rx->dma;
- volatile struct dbdma_cmd *cd = info->rx_cmds[curr];
-
-//printk(KERN_DEBUG "SCC: rxdma_start\n");
-
- st_le32(&rd->cmdptr, virt_to_bus(cd));
- out_le32(&rd->control, (RUN << 16) | RUN);
-}
-
-static void rxdma_to_tty(struct mac_serial *info)
-{
- struct tty_struct *tty = info->tty;
- volatile struct dbdma_regs *rd = &info->rx->dma;
- unsigned long flags;
- int residue, available, space, do_queue;
-
- if (!tty)
- return;
-
- do_queue = 0;
- spin_lock_irqsave(&info->rx_dma_lock, flags);
-more:
- space = TTY_FLIPBUF_SIZE - tty->flip.count;
- if (!space) {
- do_queue++;
- goto out;
- }
- residue = 0;
- if (info->rx_ubuf == info->rx_cbuf) {
- if ((ld_le32(&rd->status) & ACTIVE) != 0) {
- dbdma_flush(rd);
- if (in_le32(&rd->cmdptr)
- == virt_to_bus(info->rx_cmds[info->rx_cbuf]+1))
- residue = in_le16(&info->rx->res_count);
- }
- }
- available = RX_BUF_SIZE - residue - info->rx_done_bytes;
- if (available > space)
- available = space;
- if (available) {
- memcpy(tty->flip.char_buf_ptr,
- info->rx_char_buf[info->rx_ubuf] + info->rx_done_bytes,
- available);
- memcpy(tty->flip.flag_buf_ptr,
- info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
- available);
- tty->flip.char_buf_ptr += available;
- tty->flip.count += available;
- tty->flip.flag_buf_ptr += available;
- memset(info->rx_flag_buf[info->rx_ubuf] + info->rx_done_bytes,
- 0, available);
- info->rx_done_bytes += available;
- do_queue++;
- }
- if (info->rx_done_bytes == RX_BUF_SIZE) {
- volatile struct dbdma_cmd *cd = info->rx_cmds[info->rx_ubuf];
-
- if (info->rx_ubuf == info->rx_cbuf)
- goto out;
- /* mark rx_char_buf[rx_ubuf] free */
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le32(&cd->cmd_dep, 0);
- st_le32((unsigned int *)&cd->res_count, 0);
- cd++;
- st_le16(&cd->xfer_status, 0);
-
- if (info->rx_fbuf == RX_NO_FBUF) {
- info->rx_fbuf = info->rx_ubuf;
- if (!(ld_le32(&rd->status) & ACTIVE)) {
- dbdma_reset(&info->rx->dma);
- rxdma_start(info, info->rx_ubuf);
- info->rx_cbuf = info->rx_ubuf;
- }
- }
- info->rx_done_bytes = 0;
- if (++info->rx_ubuf == info->rx_nbuf)
- info->rx_ubuf = 0;
- if (info->rx_fbuf == info->rx_ubuf)
- info->rx_fbuf = RX_NO_FBUF;
- goto more;
- }
-out:
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
- if (do_queue)
- tty_flip_buffer_push(tty);
-}
-
-static void poll_rxdma(unsigned long private_)
-{
- struct mac_serial *info = (struct mac_serial *) private_;
- unsigned long flags;
-
- rxdma_to_tty(info);
- spin_lock_irqsave(&info->rx_dma_lock, flags);
- mod_timer(&info->poll_dma_timer, RX_DMA_TIMER);
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
-}
-
-static void dma_init(struct mac_serial * info)
-{
- int i, size;
- volatile struct dbdma_cmd *cd;
- unsigned char *p;
-
- info->rx_nbuf = 8;
-
- /* various mem set up */
- size = sizeof(struct dbdma_cmd) * (3 * info->rx_nbuf + 2)
- + (RX_BUF_SIZE * 2 + sizeof(*info->rx_cmds)
- + sizeof(*info->rx_char_buf) + sizeof(*info->rx_flag_buf))
- * info->rx_nbuf;
- info->dma_priv = kmalloc(size, GFP_KERNEL | GFP_DMA);
- if (info->dma_priv == NULL)
- return;
- memset(info->dma_priv, 0, size);
-
- info->rx_cmds = (volatile struct dbdma_cmd **)info->dma_priv;
- info->rx_char_buf = (unsigned char **) (info->rx_cmds + info->rx_nbuf);
- info->rx_flag_buf = info->rx_char_buf + info->rx_nbuf;
- p = (unsigned char *) (info->rx_flag_buf + info->rx_nbuf);
- for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
- info->rx_char_buf[i] = p;
- for (i = 0; i < info->rx_nbuf; i++, p += RX_BUF_SIZE)
- info->rx_flag_buf[i] = p;
-
- /* a bit of DMA programming */
- cd = info->rx_cmds[0] = (volatile struct dbdma_cmd *) DBDMA_ALIGN(p);
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le16(&cd->req_count, RX_BUF_SIZE);
- st_le16(&cd->command, INPUT_MORE);
- st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[0]));
- cd++;
- st_le16(&cd->req_count, 4);
- st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
- st_le32(&cd->phy_addr, virt_to_bus(cd-2));
- st_le32(&cd->cmd_dep, DBDMA_STOP);
- for (i = 1; i < info->rx_nbuf; i++) {
- info->rx_cmds[i] = ++cd;
- st_le16(&cd->command, DBDMA_NOP);
- cd++;
- st_le16(&cd->req_count, RX_BUF_SIZE);
- st_le16(&cd->command, INPUT_MORE);
- st_le32(&cd->phy_addr, virt_to_bus(info->rx_char_buf[i]));
- cd++;
- st_le16(&cd->req_count, 4);
- st_le16(&cd->command, STORE_WORD | INTR_ALWAYS);
- st_le32(&cd->phy_addr, virt_to_bus(cd-2));
- st_le32(&cd->cmd_dep, DBDMA_STOP);
- }
- cd++;
- st_le16(&cd->command, DBDMA_NOP | BR_ALWAYS);
- st_le32(&cd->cmd_dep, virt_to_bus(info->rx_cmds[0]));
-
- /* setup DMA to our liking */
- dbdma_reset(&info->rx->dma);
- st_le32(&info->rx->dma.intr_sel, 0x10001);
- st_le32(&info->rx->dma.br_sel, 0x10001);
- out_le32(&info->rx->dma.wait_sel, 0x10001);
-
- /* set various flags */
- info->rx_ubuf = 0;
- info->rx_cbuf = 0;
- info->rx_fbuf = info->rx_ubuf + 1;
- if (info->rx_fbuf == info->rx_nbuf)
- info->rx_fbuf = RX_NO_FBUF;
- info->rx_done_bytes = 0;
-
- /* setup polling */
- init_timer(&info->poll_dma_timer);
- info->poll_dma_timer.function = (void *)&poll_rxdma;
- info->poll_dma_timer.data = (unsigned long)info;
-
- info->dma_initted = 1;
-}
-
-/*
- * FixZeroBug....Works around a bug in the SCC receving channel.
- * Taken from Darwin code, 15 Sept. 2000 -DanM
- *
- * The following sequence prevents a problem that is seen with O'Hare ASICs
- * (most versions -- also with some Heathrow and Hydra ASICs) where a zero
- * at the input to the receiver becomes 'stuck' and locks up the receiver.
- * This problem can occur as a result of a zero bit at the receiver input
- * coincident with any of the following events:
- *
- * The SCC is initialized (hardware or software).
- * A framing error is detected.
- * The clocking option changes from synchronous or X1 asynchronous
- * clocking to X16, X32, or X64 asynchronous clocking.
- * The decoding mode is changed among NRZ, NRZI, FM0, or FM1.
- *
- * This workaround attempts to recover from the lockup condition by placing
- * the SCC in synchronous loopback mode with a fast clock before programming
- * any of the asynchronous modes.
- */
-static void fix_zero_bug_scc(struct mac_serial * info)
-{
- write_zsreg(info->zs_channel, 9,
- (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
- udelay(10);
- write_zsreg(info->zs_channel, 9,
- ((info->zs_channel == info->zs_chan_a? CHRA: CHRB) | NV));
-
- write_zsreg(info->zs_channel, 4, (X1CLK | EXTSYNC));
-
- /* I think this is wrong....but, I just copying code....
- */
- write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
- write_zsreg(info->zs_channel, 5, (8 & ~TxENAB));
- write_zsreg(info->zs_channel, 9, NV); /* Didn't we already do this? */
- write_zsreg(info->zs_channel, 11, (RCBR | TCBR));
- write_zsreg(info->zs_channel, 12, 0);
- write_zsreg(info->zs_channel, 13, 0);
- write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR));
- write_zsreg(info->zs_channel, 14, (LOOPBAK | SSBR | BRENABL));
- write_zsreg(info->zs_channel, 3, (8 | RxENABLE));
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- write_zsreg(info->zs_channel, 0, RES_EXT_INT); /* to kill some time */
-
- /* The channel should be OK now, but it is probably receiving
- * loopback garbage.
- * Switch to asynchronous mode, disable the receiver,
- * and discard everything in the receive buffer.
- */
- write_zsreg(info->zs_channel, 9, NV);
- write_zsreg(info->zs_channel, 4, PAR_ENA);
- write_zsreg(info->zs_channel, 3, (8 & ~RxENABLE));
-
- while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV) {
- (void)read_zsreg(info->zs_channel, 8);
- write_zsreg(info->zs_channel, 0, RES_EXT_INT);
- write_zsreg(info->zs_channel, 0, ERR_RES);
- }
-}
-
-static int setup_scc(struct mac_serial * info)
-{
- unsigned long flags;
-
- OPNDBG("setting up ttyS%d SCC...\n", info->line);
-
- spin_lock_irqsave(&info->lock, flags);
-
- /* Nice buggy HW ... */
- fix_zero_bug_scc(info);
-
- /*
- * Reset the chip.
- */
- write_zsreg(info->zs_channel, 9,
- (info->zs_channel == info->zs_chan_a? CHRA: CHRB));
- udelay(10);
- write_zsreg(info->zs_channel, 9, 0);
-
- /*
- * Clear the receive FIFO.
- */
- ZS_CLEARFIFO(info->zs_channel);
- info->xmit_fifo_size = 1;
-
- /*
- * Reset DMAs
- */
- if (info->has_dma)
- dma_init(info);
-
- /*
- * Clear the interrupt registers.
- */
- write_zsreg(info->zs_channel, 0, ERR_RES);
- write_zsreg(info->zs_channel, 0, RES_H_IUS);
-
- /*
- * Turn on RTS and DTR.
- */
- if (!info->is_irda)
- zs_rtsdtr(info, 1);
-
- /*
- * Finally, enable sequencing and interrupts
- */
- if (!info->dma_initted) {
- /* interrupt on ext/status changes, all received chars,
- transmit ready */
- info->curregs[1] = (info->curregs[1] & ~0x18)
- | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);
- } else {
- /* interrupt on ext/status changes, W/Req pin is
- receive DMA request */
- info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))
- | (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- /* enable W/Req pin */
- info->curregs[1] |= WT_RDY_ENAB;
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- /* enable interrupts on transmit ready and receive errors */
- info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;
- }
- info->pendregs[1] = info->curregs[1];
- info->curregs[3] |= (RxENABLE | Rx8);
- info->pendregs[3] = info->curregs[3];
- info->curregs[5] |= (TxENAB | Tx8);
- info->pendregs[5] = info->curregs[5];
- info->curregs[9] |= (NV | MIE);
- info->pendregs[9] = info->curregs[9];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- write_zsreg(info->zs_channel, 9, info->curregs[9]);
-
- if (info->tty)
- clear_bit(TTY_IO_ERROR, &info->tty->flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- /*
- * Set the speed of the serial port
- */
- change_speed(info, 0);
-
- /* Save the current value of RR0 */
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
-
- if (info->dma_initted) {
- spin_lock_irqsave(&info->rx_dma_lock, flags);
- rxdma_start(info, 0);
- info->poll_dma_timer.expires = RX_DMA_TIMER;
- add_timer(&info->poll_dma_timer);
- spin_unlock_irqrestore(&info->rx_dma_lock, flags);
- }
-
- return 0;
-}
-
-/*
- * This routine will shutdown a serial port; interrupts are disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void shutdown(struct mac_serial * info)
-{
- OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,
- info->irq);
-
- if (!(info->flags & ZILOG_INITIALIZED)) {
- OPNDBG("(already shutdown)\n");
- return;
- }
-
- if (info->has_dma) {
- del_timer(&info->poll_dma_timer);
- dbdma_reset(info->tx_dma);
- dbdma_reset(&info->rx->dma);
- disable_irq(info->tx_dma_irq);
- disable_irq(info->rx_dma_irq);
- }
- disable_irq(info->irq);
-
- info->pendregs[1] = info->curregs[1] = 0;
- write_zsreg(info->zs_channel, 1, 0); /* no interrupts */
-
- info->curregs[3] &= ~RxENABLE;
- info->pendregs[3] = info->curregs[3];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
-
- info->curregs[5] &= ~TxENAB;
- if (!info->tty || C_HUPCL(info->tty))
- info->curregs[5] &= ~DTR;
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- set_scc_power(info, 0);
-
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = 0;
- }
-
- if (info->has_dma && info->dma_priv) {
- kfree(info->dma_priv);
- info->dma_priv = NULL;
- info->dma_initted = 0;
- }
-
- memset(info->curregs, 0, sizeof(info->curregs));
- memset(info->pendregs, 0, sizeof(info->pendregs));
-
- info->flags &= ~ZILOG_INITIALIZED;
-}
-
-/*
- * Turn power on or off to the SCC and associated stuff
- * (port drivers, modem, IR port, etc.)
- * Returns the number of milliseconds we should wait before
- * trying to use the port.
- */
-static int set_scc_power(struct mac_serial * info, int state)
-{
- int delay = 0;
-
- if (state) {
- PWRDBG("ttyS%d: powering up hardware\n", info->line);
- pmac_call_feature(
- PMAC_FTR_SCC_ENABLE,
- info->dev_node, info->port_type, 1);
- if (info->is_internal_modem) {
- pmac_call_feature(
- PMAC_FTR_MODEM_ENABLE,
- info->dev_node, 0, 1);
- delay = 2500; /* wait for 2.5s before using */
- } else if (info->is_irda)
- mdelay(50); /* Do better here once the problems
- * with blocking have been ironed out
- */
- } else {
- /* TODO: Make that depend on a timer, don't power down
- * immediately
- */
- PWRDBG("ttyS%d: shutting down hardware\n", info->line);
- if (info->is_internal_modem) {
- PWRDBG("ttyS%d: shutting down modem\n", info->line);
- pmac_call_feature(
- PMAC_FTR_MODEM_ENABLE,
- info->dev_node, 0, 0);
- }
- pmac_call_feature(
- PMAC_FTR_SCC_ENABLE,
- info->dev_node, info->port_type, 0);
- }
- return delay;
-}
-
-static void irda_rts_pulses(struct mac_serial *info, int w)
-{
- udelay(w);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
- udelay(2);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
- udelay(8);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);
- udelay(4);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-}
-
-/*
- * Set the irda codec on the imac to the specified baud rate.
- */
-static void irda_setup(struct mac_serial *info)
-{
- int code, speed, t;
-
- speed = info->tty->termios->c_cflag & CBAUD;
- if (speed < B2400 || speed > B115200)
- return;
- code = 0x4d + B115200 - speed;
-
- /* disable serial interrupts and receive DMA */
- write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);
-
- /* wait for transmitter to drain */
- t = 10000;
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0
- || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "transmitter didn't drain\n");
- return;
- }
- udelay(10);
- }
- udelay(100);
-
- /* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */
- write_zsreg(info->zs_channel, 4, X16CLK | SB1);
- write_zsreg(info->zs_channel, 11, TCBR | RCBR);
- t = BPS_TO_BRG(19200, ZS_CLOCK/16);
- write_zsreg(info->zs_channel, 12, t);
- write_zsreg(info->zs_channel, 13, t >> 8);
- write_zsreg(info->zs_channel, 14, BRENABL);
- write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
-
- /* set TxD low for ~104us and pulse RTS */
- udelay(1000);
- write_zsdata(info->zs_channel, 0xfe);
- irda_rts_pulses(info, 150);
- irda_rts_pulses(info, 180);
- irda_rts_pulses(info, 50);
- udelay(100);
-
- /* assert DTR, wait 30ms, talk to the chip */
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);
- mdelay(30);
- while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)
- read_zsdata(info->zs_channel);
-
- write_zsdata(info->zs_channel, 1);
- t = 1000;
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "irda_setup timed out on 1st byte\n");
- goto out;
- }
- udelay(10);
- }
- t = read_zsdata(info->zs_channel);
- if (t != 4)
- printk(KERN_ERR "irda_setup 1st byte = %x\n", t);
-
- write_zsdata(info->zs_channel, code);
- t = 1000;
- while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {
- if (--t <= 0) {
- printk(KERN_ERR "irda_setup timed out on 2nd byte\n");
- goto out;
- }
- udelay(10);
- }
- t = read_zsdata(info->zs_channel);
- if (t != code)
- printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);
-
- /* Drop DTR again and do some more RTS pulses */
- out:
- udelay(100);
- write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);
- irda_rts_pulses(info, 80);
-
- /* We should be right to go now. We assume that load_zsregs
- will get called soon to load up the correct baud rate etc. */
- info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;
- info->pendregs[5] = info->curregs[5];
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static void change_speed(struct mac_serial *info, struct termios *old_termios)
-{
- unsigned cflag;
- int bits;
- int brg, baud;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return;
-
- cflag = info->tty->termios->c_cflag;
- baud = tty_get_baud_rate(info->tty);
- if (baud == 0) {
- if (old_termios) {
- info->tty->termios->c_cflag &= ~CBAUD;
- info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);
- cflag = info->tty->termios->c_cflag;
- baud = tty_get_baud_rate(info->tty);
- }
- else
- baud = info->zs_baud;
- }
- if (baud > 230400)
- baud = 230400;
- else if (baud == 0)
- baud = 38400;
-
- spin_lock_irqsave(&info->lock, flags);
- info->zs_baud = baud;
- info->clk_divisor = 16;
-
- BAUDBG(KERN_DEBUG "set speed to %d bds, ", baud);
-
- switch (baud) {
- case ZS_CLOCK/16: /* 230400 */
- info->curregs[4] = X16CLK;
- info->curregs[11] = 0;
- break;
- case ZS_CLOCK/32: /* 115200 */
- info->curregs[4] = X32CLK;
- info->curregs[11] = 0;
- break;
- default:
- info->curregs[4] = X16CLK;
- info->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor);
- info->curregs[12] = (brg & 255);
- info->curregs[13] = ((brg >> 8) & 255);
- info->curregs[14] = BRENABL;
- }
-
- /* byte size and parity */
- info->curregs[3] &= ~RxNBITS_MASK;
- info->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- info->curregs[3] |= Rx5;
- info->curregs[5] |= Tx5;
- BAUDBG("5 bits, ");
- bits = 7;
- break;
- case CS6:
- info->curregs[3] |= Rx6;
- info->curregs[5] |= Tx6;
- BAUDBG("6 bits, ");
- bits = 8;
- break;
- case CS7:
- info->curregs[3] |= Rx7;
- info->curregs[5] |= Tx7;
- BAUDBG("7 bits, ");
- bits = 9;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- info->curregs[3] |= Rx8;
- info->curregs[5] |= Tx8;
- BAUDBG("8 bits, ");
- bits = 10;
- break;
- }
- info->pendregs[3] = info->curregs[3];
- info->pendregs[5] = info->curregs[5];
-
- info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->curregs[4] |= SB2;
- bits++;
- BAUDBG("2 stop, ");
- } else {
- info->curregs[4] |= SB1;
- BAUDBG("1 stop, ");
- }
- if (cflag & PARENB) {
- bits++;
- info->curregs[4] |= PAR_ENA;
- BAUDBG("parity, ");
- }
- if (!(cflag & PARODD)) {
- info->curregs[4] |= PAR_EVEN;
- }
- info->pendregs[4] = info->curregs[4];
-
- if (!(cflag & CLOCAL)) {
- if (!(info->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->curregs[15] |= DCDIE;
- } else
- info->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
- info->tx_stopped = 1;
- } else {
- info->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
- info->pendregs[15] = info->curregs[15];
-
- /* Calc timeout value. This is pretty broken with high baud rates with HZ=100.
- This code would love a larger HZ and a >1 fifo size, but this is not
- a priority. The resulting value must be >HZ/2
- */
- info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);
- info->timeout += HZ/50+1; /* Add .02 seconds of slop */
-
- BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,
- (int)info->baud_base);
-
- /* set the irda codec to the right rate */
- if (info->is_irda)
- irda_setup(info);
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->curregs);
-
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static void rs_flush_chars(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
- if (!(info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||
- !info->xmit_buf))
- /* Enable transmitter */
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_write(struct tty_struct * tty,
- const unsigned char *buf, int count)
-{
- int c, ret = 0;
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_write"))
- return 0;
-
- if (!tty || !info->xmit_buf || !tmp_buf)
- return 0;
-
- while (1) {
- spin_lock_irqsave(&info->lock, flags);
- 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->lock, flags);
- break;
- }
- memcpy(info->xmit_buf + info->xmit_head, buf, c);
- info->xmit_head = ((info->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- info->xmit_cnt += c;
- spin_unlock_irqrestore(&info->lock, flags);
- buf += c;
- count -= c;
- ret += c;
- }
- spin_lock_irqsave(&info->lock, flags);
- if (info->xmit_cnt && !tty->stopped && !info->tx_stopped
- && !info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
- return ret;
-}
-
-static int rs_write_room(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- int ret;
-
- if (serial_paranoia_check(info, tty->name, "rs_write_room"))
- return 0;
- ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
- if (ret < 0)
- ret = 0;
- return ret;
-}
-
-static int rs_chars_in_buffer(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))
- return 0;
- return info->xmit_cnt;
-}
-
-static void rs_flush_buffer(struct tty_struct *tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))
- return;
- spin_lock_irqsave(&info->lock, flags);
- info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
- spin_unlock_irqrestore(&info->lock, flags);
- tty_wakeup(tty);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_throttle()
- *
- * This routine is called by the upper-layer tty layer to signal that
- * incoming characters should be throttled.
- * ------------------------------------------------------------
- */
-static void rs_throttle(struct tty_struct * tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- printk(KERN_DEBUG "throttle %ld....\n",tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_throttle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&info->lock, flags);
- info->x_char = STOP_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- if (C_CRTSCTS(tty)) {
- /*
- * Here we want to turn off the RTS line. On Macintoshes,
- * the external serial ports using a DIN-8 or DIN-9
- * connector only have the DTR line (which is usually
- * wired to both RTS and DTR on an external modem in
- * the cable). RTS doesn't go out to the serial port
- * socket, it acts as an output enable for the transmit
- * data line. So in this case we don't drop RTS.
- *
- * Macs with internal modems generally do have both RTS
- * and DTR wired to the modem, so in that case we do
- * drop RTS.
- */
- if (info->is_internal_modem) {
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] &= ~RTS;
- info->pendregs[5] &= ~RTS;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
- }
-
-#ifdef CDTRCTS
- if (tty->termios->c_cflag & CDTRCTS) {
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] &= ~DTR;
- info->pendregs[5] &= ~DTR;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-#endif /* CDTRCTS */
-}
-
-static void rs_unthrottle(struct tty_struct * tty)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-#ifdef SERIAL_DEBUG_THROTTLE
- printk(KERN_DEBUG "unthrottle %s: %d....\n",
- tty->ldisc.chars_in_buffer(tty));
-#endif
-
- if (serial_paranoia_check(info, tty->name, "rs_unthrottle"))
- return;
-
- if (I_IXOFF(tty)) {
- spin_lock_irqsave(&info->lock, flags);
- if (info->x_char)
- info->x_char = 0;
- else {
- info->x_char = START_CHAR(tty);
- if (!info->tx_active)
- transmit_chars(info);
- }
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
- if (C_CRTSCTS(tty) && info->is_internal_modem) {
- /* Assert RTS line */
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] |= RTS;
- info->pendregs[5] |= RTS;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-
-#ifdef CDTRCTS
- if (tty->termios->c_cflag & CDTRCTS) {
- /* Assert DTR line */
- spin_lock_irqsave(&info->lock, flags);
- info->curregs[5] |= DTR;
- info->pendregs[5] |= DTR;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- }
-#endif
-}
-
-/*
- * ------------------------------------------------------------
- * rs_ioctl() and friends
- * ------------------------------------------------------------
- */
-
-static int get_serial_info(struct mac_serial * info,
- struct serial_struct __user * retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return -EFAULT;
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->line;
- tmp.port = info->port;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
- return -EFAULT;
- return 0;
-}
-
-static int set_serial_info(struct mac_serial * info,
- struct serial_struct __user * new_info)
-{
- struct serial_struct new_serial;
- struct mac_serial old_info;
- int retval = 0;
-
- if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
- return -EFAULT;
- old_info = *info;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) ||
- (new_serial.type != info->type) ||
- (new_serial.close_delay != info->close_delay) ||
- ((new_serial.flags & ~ZILOG_USR_MASK) !=
- (info->flags & ~ZILOG_USR_MASK)))
- return -EPERM;
- info->flags = ((info->flags & ~ZILOG_USR_MASK) |
- (new_serial.flags & ZILOG_USR_MASK));
- info->custom_divisor = new_serial.custom_divisor;
- goto check_and_exit;
- }
-
- if (info->count > 1)
- return -EBUSY;
-
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
-
- info->baud_base = new_serial.baud_base;
- info->flags = ((info->flags & ~ZILOG_FLAGS) |
- (new_serial.flags & ZILOG_FLAGS));
- info->type = new_serial.type;
- info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
-
-check_and_exit:
- if (info->flags & ZILOG_INITIALIZED)
- retval = setup_scc(info);
- return retval;
-}
-
-/*
- * get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int get_lsr_info(struct mac_serial * info, unsigned int *value)
-{
- unsigned char status;
- unsigned long flags;
-
- spin_lock_irqsave(&info->lock, flags);
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irqrestore(&info->lock, flags);
- status = (status & Tx_BUF_EMP)? TIOCSER_TEMT: 0;
- return put_user(status,value);
-}
-
-static int rs_tiocmget(struct tty_struct *tty, struct file *file)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned char control, status;
- unsigned long flags;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- spin_lock_irqsave(&info->lock, flags);
- control = info->curregs[5];
- status = read_zsreg(info->zs_channel, 0);
- spin_unlock_irqrestore(&info->lock, flags);
- return ((control & RTS) ? TIOCM_RTS: 0)
- | ((control & DTR) ? TIOCM_DTR: 0)
- | ((status & DCD) ? TIOCM_CAR: 0)
- | ((status & CTS) ? 0: TIOCM_CTS);
-}
-
-static int rs_tiocmset(struct tty_struct *tty, struct file *file,
- unsigned int set, unsigned int clear)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned int arg, bits;
- unsigned long flags;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, __FUNCTION__))
- return -ENODEV;
-
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
-
- spin_lock_irqsave(&info->lock, flags);
- if (set & TIOCM_RTS)
- info->curregs[5] |= RTS;
- if (set & TIOCM_DTR)
- info->curregs[5] |= DTR;
- if (clear & TIOCM_RTS)
- info->curregs[5] &= ~RTS;
- if (clear & TIOCM_DTR)
- info->curregs[5] &= ~DTR;
-
- info->pendregs[5] = info->curregs[5];
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
- return 0;
-}
-
-/*
- * rs_break - turn transmit break condition on/off
- */
-static void rs_break(struct tty_struct *tty, int break_state)
-{
- struct mac_serial *info = (struct mac_serial *) tty->driver_data;
- unsigned long flags;
-
- if (serial_paranoia_check(info, tty->name, "rs_break"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
- if (break_state == -1)
- info->curregs[5] |= SND_BRK;
- else
- info->curregs[5] &= ~SND_BRK;
- write_zsreg(info->zs_channel, 5, info->curregs[5]);
- spin_unlock_irqrestore(&info->lock, flags);
-}
-
-static int rs_ioctl(struct tty_struct *tty, struct file * file,
- unsigned int cmd, unsigned long arg)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel)
- return -ENODEV;
-#endif
- if (serial_paranoia_check(info, tty->name, "rs_ioctl"))
- return -ENODEV;
-
- if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&
- (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT)) {
- if (tty->flags & (1 << TTY_IO_ERROR))
- return -EIO;
- }
-
- switch (cmd) {
- case TIOCGSERIAL:
- return get_serial_info(info,
- (struct serial_struct __user *) arg);
- case TIOCSSERIAL:
- return set_serial_info(info,
- (struct serial_struct __user *) arg);
- case TIOCSERGETLSR: /* Get line status register */
- return get_lsr_info(info, (unsigned int *) arg);
-
- case TIOCSERGSTRUCT:
- if (copy_to_user((struct mac_serial __user *) arg,
- info, sizeof(struct mac_serial)))
- return -EFAULT;
- return 0;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios)
-{
- struct mac_serial *info = (struct mac_serial *)tty->driver_data;
- int was_stopped;
-
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- was_stopped = info->tx_stopped;
-
- change_speed(info, old_termios);
-
- if (was_stopped && !info->tx_stopped) {
- tty->hw_stopped = 0;
- rs_start(tty);
- }
-}
-
-/*
- * ------------------------------------------------------------
- * rs_close()
- *
- * This routine is called when the serial port gets closed.
- * Wait for the last remaining data to be sent.
- * ------------------------------------------------------------
- */
-static void rs_close(struct tty_struct *tty, struct file * filp)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
- unsigned long flags;
-
- if (!info || serial_paranoia_check(info, tty->name, "rs_close"))
- return;
-
- spin_lock_irqsave(&info->lock, flags);
-
- if (tty_hung_up_p(filp)) {
- spin_unlock_irqrestore(&info->lock, flags);
- return;
- }
-
- OPNDBG("rs_close ttyS%d, count = %d\n", info->line, info->count);
- if ((tty->count == 1) && (info->count != 1)) {
- /*
- * Uh, oh. tty->count is 1, which means that the tty
- * structure will be freed. Info->count should always
- * be one in these conditions. If it's greater than
- * one, we've got real problems, since it means the
- * serial port won't be shutdown.
- */
- printk(KERN_ERR "rs_close: bad serial port count; tty->count "
- "is 1, info->count is %d\n", info->count);
- info->count = 1;
- }
- if (--info->count < 0) {
- printk(KERN_ERR "rs_close: bad serial port count for "
- "ttyS%d: %d\n", info->line, info->count);
- info->count = 0;
- }
- if (info->count) {
- spin_unlock_irqrestore(&info->lock, flags);
- return;
- }
- info->flags |= ZILOG_CLOSING;
- /*
- * Now we wait for the transmit buffer to clear; and we notify
- * the line discipline to only process XON/XOFF characters.
- */
- OPNDBG("waiting end of Tx... (timeout:%d)\n", info->closing_wait);
- tty->closing = 1;
- if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) {
- spin_unlock_irqrestore(&info->lock, flags);
- tty_wait_until_sent(tty, info->closing_wait);
- spin_lock_irqsave(&info->lock, flags);
- }
-
- /*
- * At this point we stop accepting input. To do this, we
- * disable the receiver and receive interrupts.
- */
- info->curregs[3] &= ~RxENABLE;
- info->pendregs[3] = info->curregs[3];
- write_zsreg(info->zs_channel, 3, info->curregs[3]);
- info->curregs[1] &= ~(0x18); /* disable any rx ints */
- info->pendregs[1] = info->curregs[1];
- write_zsreg(info->zs_channel, 1, info->curregs[1]);
- ZS_CLEARFIFO(info->zs_channel);
- if (info->flags & ZILOG_INITIALIZED) {
- /*
- * Before we drop DTR, make sure the SCC transmitter
- * has completely drained.
- */
- OPNDBG("waiting end of Rx...\n");
- spin_unlock_irqrestore(&info->lock, flags);
- rs_wait_until_sent(tty, info->timeout);
- spin_lock_irqsave(&info->lock, flags);
- }
-
- shutdown(info);
- /* restore flags now since shutdown() will have disabled this port's
- specific irqs */
- spin_unlock_irqrestore(&info->lock, flags);
-
- if (tty->driver->flush_buffer)
- tty->driver->flush_buffer(tty);
- tty_ldisc_flush(tty);
- tty->closing = 0;
- info->event = 0;
- info->tty = 0;
-
- if (info->blocked_open) {
- if (info->close_delay) {
- msleep_interruptible(jiffies_to_msecs(info->close_delay));
- }
- wake_up_interruptible(&info->open_wait);
- }
- info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING);
- wake_up_interruptible(&info->close_wait);
-}
-
-/*
- * rs_wait_until_sent() --- wait until the transmitter is empty
- */
-static void rs_wait_until_sent(struct tty_struct *tty, int timeout)
-{
- struct mac_serial *info = (struct mac_serial *) tty->driver_data;
- unsigned long orig_jiffies, char_time;
-
- if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent"))
- return;
-
-/* printk("rs_wait_until_sent, timeout:%d, tty_stopped:%d, tx_stopped:%d\n",
- timeout, tty->stopped, info->tx_stopped);
-*/
- orig_jiffies = jiffies;
- /*
- * Set the check interval to be 1/5 of the estimated time to
- * send a single character, and make it at least 1. The check
- * interval should also be less than the timeout.
- */
- if (info->timeout <= HZ/50) {
- printk(KERN_INFO "macserial: invalid info->timeout=%d\n",
- info->timeout);
- info->timeout = HZ/50+1;
- }
-
- char_time = (info->timeout - HZ/50) / info->xmit_fifo_size;
- char_time = char_time / 5;
- if (char_time > HZ) {
- printk(KERN_WARNING "macserial: char_time %ld >HZ !!!\n",
- char_time);
- char_time = 1;
- } else if (char_time == 0)
- char_time = 1;
- if (timeout)
- char_time = min_t(unsigned long, char_time, timeout);
- while ((read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {
- msleep_interruptible(jiffies_to_msecs(char_time));
- if (signal_pending(current))
- break;
- if (timeout && time_after(jiffies, orig_jiffies + timeout))
- break;
- }
- current->state = TASK_RUNNING;
-}
-
-/*
- * rs_hangup() --- called by tty_hangup() when a hangup is signaled.
- */
-static void rs_hangup(struct tty_struct *tty)
-{
- struct mac_serial * info = (struct mac_serial *)tty->driver_data;
-
- if (serial_paranoia_check(info, tty->name, "rs_hangup"))
- return;
-
- rs_flush_buffer(tty);
- shutdown(info);
- info->event = 0;
- info->count = 0;
- info->flags &= ~ZILOG_NORMAL_ACTIVE;
- info->tty = 0;
- wake_up_interruptible(&info->open_wait);
-}
-
-/*
- * ------------------------------------------------------------
- * rs_open() and friends
- * ------------------------------------------------------------
- */
-static int block_til_ready(struct tty_struct *tty, struct file * filp,
- struct mac_serial *info)
-{
- DECLARE_WAITQUEUE(wait,current);
- int retval;
- int do_clocal = 0;
-
- /*
- * If the device is in the middle of being closed, then block
- * until it's done, and then try again.
- */
- if (info->flags & ZILOG_CLOSING) {
- interruptible_sleep_on(&info->close_wait);
- return -EAGAIN;
- }
-
- /*
- * If non-blocking mode is set, or the port is not enabled,
- * then make the check up front and then exit.
- */
- if ((filp->f_flags & O_NONBLOCK) ||
- (tty->flags & (1 << TTY_IO_ERROR))) {
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
- }
-
- if (tty->termios->c_cflag & CLOCAL)
- do_clocal = 1;
-
- /*
- * Block waiting for the carrier detect and the line to become
- * free (i.e., not in use by the callout). While we are in
- * this loop, info->count is dropped by one, so that
- * rs_close() knows when to free things. We restore it upon
- * exit, either normal or abnormal.
- */
- retval = 0;
- add_wait_queue(&info->open_wait, &wait);
- OPNDBG("block_til_ready before block: ttyS%d, count = %d\n",
- info->line, info->count);
- spin_lock_irq(&info->lock);
- if (!tty_hung_up_p(filp))
- info->count--;
- spin_unlock_irq(&info->lock);
- info->blocked_open++;
- while (1) {
- spin_lock_irq(&info->lock);
- if ((tty->termios->c_cflag & CBAUD) &&
- !info->is_irda)
- zs_rtsdtr(info, 1);
- spin_unlock_irq(&info->lock);
- set_current_state(TASK_INTERRUPTIBLE);
- if (tty_hung_up_p(filp) ||
- !(info->flags & ZILOG_INITIALIZED)) {
- retval = -EAGAIN;
- break;
- }
- if (!(info->flags & ZILOG_CLOSING) &&
- (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD)))
- break;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- OPNDBG("block_til_ready blocking: ttyS%d, count = %d\n",
- info->line, info->count);
- schedule();
- }
- current->state = TASK_RUNNING;
- remove_wait_queue(&info->open_wait, &wait);
- if (!tty_hung_up_p(filp))
- info->count++;
- info->blocked_open--;
- OPNDBG("block_til_ready after blocking: ttyS%d, count = %d\n",
- info->line, info->count);
- if (retval)
- return retval;
- info->flags |= ZILOG_NORMAL_ACTIVE;
- return 0;
-}
-
-/*
- * This routine is called whenever a serial port is opened. It
- * enables interrupts for a serial port, linking in its ZILOG structure into
- * the IRQ chain. It also performs the serial-specific
- * initialization for the tty structure.
- */
-static int rs_open(struct tty_struct *tty, struct file * filp)
-{
- struct mac_serial *info;
- int retval, line;
- unsigned long page;
-
- line = tty->index;
- if ((line < 0) || (line >= zs_channels_found)) {
- return -ENODEV;
- }
- info = zs_soft + line;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- return -ENODEV;
- }
-#endif
- if (serial_paranoia_check(info, tty->name, "rs_open"))
- return -ENODEV;
- OPNDBG("rs_open %s, count = %d, tty=%p\n", tty->name,
- info->count, tty);
-
- info->count++;
- tty->driver_data = info;
- info->tty = tty;
-
- if (!tmp_buf) {
- page = get_zeroed_page(GFP_KERNEL);
- if (!page)
- return -ENOMEM;
- if (tmp_buf)
- free_page(page);
- else
- tmp_buf = (unsigned char *) page;
- }
-
- /*
- * If the port is the middle of closing, bail out now
- */
- if (tty_hung_up_p(filp) ||
- (info->flags & ZILOG_CLOSING)) {
- if (info->flags & ZILOG_CLOSING)
- interruptible_sleep_on(&info->close_wait);
- return -EAGAIN;
- }
-
- /*
- * Start up serial port
- */
-
- retval = startup(info);
- if (retval)
- return retval;
-
- retval = block_til_ready(tty, filp, info);
- if (retval) {
- OPNDBG("rs_open returning after block_til_ready with %d\n",
- retval);
- return retval;
- }
-
-#ifdef CONFIG_SERIAL_CONSOLE
- if (sercons.cflag && sercons.index == line) {
- tty->termios->c_cflag = sercons.cflag;
- sercons.cflag = 0;
- change_speed(info, 0);
- }
-#endif
-
- OPNDBG("rs_open %s successful...\n", tty->name);
- return 0;
-}
-
-/* Finally, routines used to initialize the serial driver. */
-
-static void show_serial_version(void)
-{
- printk(KERN_INFO "PowerMac Z8530 serial driver version " MACSERIAL_VERSION "\n");
-}
-
-/*
- * Initialize one channel, both the mac_serial and mac_zschannel
- * structs. We use the dev_node field of the mac_serial struct.
- */
-static int
-chan_init(struct mac_serial *zss, struct mac_zschannel *zs_chan,
- struct mac_zschannel *zs_chan_a)
-{
- struct device_node *ch = zss->dev_node;
- char *conn;
- int len;
- struct slot_names_prop {
- int count;
- char name[1];
- } *slots;
-
- zss->irq = ch->intrs[0].line;
- zss->has_dma = 0;
-#if !defined(CONFIG_KGDB) && defined(SUPPORT_SERIAL_DMA)
- if (ch->n_addrs >= 3 && ch->n_intrs == 3)
- zss->has_dma = 1;
-#endif
- zss->dma_initted = 0;
-
- zs_chan->control = (volatile unsigned char *)
- ioremap(ch->addrs[0].address, 0x1000);
- zs_chan->data = zs_chan->control + 0x10;
- spin_lock_init(&zs_chan->lock);
- zs_chan->parent = zss;
- zss->zs_channel = zs_chan;
- zss->zs_chan_a = zs_chan_a;
-
- /* setup misc varariables */
- zss->kgdb_channel = 0;
-
- /* For now, we assume you either have a slot-names property
- * with "Modem" in it, or your channel is compatible with
- * "cobalt". Might need additional fixups
- */
- zss->is_internal_modem = device_is_compatible(ch, "cobalt");
- conn = get_property(ch, "AAPL,connector", &len);
- zss->is_irda = conn && (strcmp(conn, "infrared") == 0);
- zss->port_type = PMAC_SCC_ASYNC;
- /* 1999 Powerbook G3 has slot-names property instead */
- slots = (struct slot_names_prop *)get_property(ch, "slot-names", &len);
- if (slots && slots->count > 0) {
- if (strcmp(slots->name, "IrDA") == 0)
- zss->is_irda = 1;
- else if (strcmp(slots->name, "Modem") == 0)
- zss->is_internal_modem = 1;
- }
- if (zss->is_irda)
- zss->port_type = PMAC_SCC_IRDA;
- if (zss->is_internal_modem) {
- struct device_node* i2c_modem = find_devices("i2c-modem");
- if (i2c_modem) {
- char* mid = get_property(i2c_modem, "modem-id", NULL);
- if (mid) switch(*mid) {
- case 0x04 :
- case 0x05 :
- case 0x07 :
- case 0x08 :
- case 0x0b :
- case 0x0c :
- zss->port_type = PMAC_SCC_I2S1;
- }
- printk(KERN_INFO "macserial: i2c-modem detected, id: %d\n",
- mid ? (*mid) : 0);
- } else {
- printk(KERN_INFO "macserial: serial modem detected\n");
- }
- }
-
- while (zss->has_dma) {
- zss->dma_priv = NULL;
- /* it seems that the last two addresses are the
- DMA controllers */
- zss->tx_dma = (volatile struct dbdma_regs *)
- ioremap(ch->addrs[ch->n_addrs - 2].address, 0x100);
- zss->rx = (volatile struct mac_dma *)
- ioremap(ch->addrs[ch->n_addrs - 1].address, 0x100);
- zss->tx_dma_irq = ch->intrs[1].line;
- zss->rx_dma_irq = ch->intrs[2].line;
- spin_lock_init(&zss->rx_dma_lock);
- break;
- }
-
- init_timer(&zss->powerup_timer);
- zss->powerup_timer.function = powerup_done;
- zss->powerup_timer.data = (unsigned long) zss;
- return 0;
-}
-
-/*
- * /proc fs routines. TODO: Add status lines & error stats
- */
-static inline int
-line_info(char *buf, struct mac_serial *info)
-{
- int ret=0;
- unsigned char* connector;
- int lenp;
-
- ret += sprintf(buf, "%d: port:0x%X irq:%d", info->line, info->port, info->irq);
-
- connector = get_property(info->dev_node, "AAPL,connector", &lenp);
- if (connector)
- ret+=sprintf(buf+ret," con:%s ", connector);
- if (info->is_internal_modem) {
- if (!connector)
- ret+=sprintf(buf+ret," con:");
- ret+=sprintf(buf+ret,"%s", " (internal modem)");
- }
- if (info->is_irda) {
- if (!connector)
- ret+=sprintf(buf+ret," con:");
- ret+=sprintf(buf+ret,"%s", " (IrDA)");
- }
- ret+=sprintf(buf+ret,"\n");
-
- return ret;
-}
-
-int macserial_read_proc(char *page, char **start, off_t off, int count,
- int *eof, void *data)
-{
- int l, len = 0;
- off_t begin = 0;
- struct mac_serial *info;
-
- len += sprintf(page, "serinfo:1.0 driver:" MACSERIAL_VERSION "\n");
- for (info = zs_chain; info && len < 4000; info = info->zs_next) {
- l = line_info(page + len, info);
- len += l;
- if (len+begin > off+count)
- goto done;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- *eof = 1;
-done:
- if (off >= len+begin)
- return 0;
- *start = page + (off-begin);
- return ((count < begin+len-off) ? count : begin+len-off);
-}
-
-/* Ask the PROM how many Z8530s we have and initialize their zs_channels */
-static void
-probe_sccs(void)
-{
- struct device_node *dev, *ch;
- struct mac_serial **pp;
- int n, chip, nchan;
- struct mac_zschannel *zs_chan;
- int chan_a_index;
-
- n = 0;
- pp = &zs_chain;
- zs_chan = zs_channels;
- for (dev = find_devices("escc"); dev != 0; dev = dev->next) {
- nchan = 0;
- chip = n;
- if (n >= NUM_CHANNELS) {
- printk(KERN_WARNING "Sorry, can't use %s: no more "
- "channels\n", dev->full_name);
- continue;
- }
- chan_a_index = 0;
- for (ch = dev->child; ch != 0; ch = ch->sibling) {
- if (nchan >= 2) {
- printk(KERN_WARNING "SCC: Only 2 channels per "
- "chip are supported\n");
- break;
- }
- if (ch->n_addrs < 1 || (ch ->n_intrs < 1)) {
- printk("Can't use %s: %d addrs %d intrs\n",
- ch->full_name, ch->n_addrs, ch->n_intrs);
- continue;
- }
-
- /* The channel with the higher address
- will be the A side. */
- if (nchan > 0 &&
- ch->addrs[0].address
- > zs_soft[n-1].dev_node->addrs[0].address)
- chan_a_index = 1;
-
- /* minimal initialization for now */
- zs_soft[n].dev_node = ch;
- *pp = &zs_soft[n];
- pp = &zs_soft[n].zs_next;
- ++nchan;
- ++n;
- }
- if (nchan == 0)
- continue;
-
- /* set up A side */
- if (chan_init(&zs_soft[chip + chan_a_index], zs_chan, zs_chan))
- continue;
- ++zs_chan;
-
- /* set up B side, if it exists */
- if (nchan > 1)
- if (chan_init(&zs_soft[chip + 1 - chan_a_index],
- zs_chan, zs_chan - 1))
- continue;
- ++zs_chan;
- }
- *pp = 0;
-
- zs_channels_found = n;
-#ifdef CONFIG_PMAC_PBOOK
- if (n)
- pmu_register_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-static struct tty_operations serial_ops = {
- .open = rs_open,
- .close = rs_close,
- .write = rs_write,
- .flush_chars = rs_flush_chars,
- .write_room = rs_write_room,
- .chars_in_buffer = rs_chars_in_buffer,
- .flush_buffer = rs_flush_buffer,
- .ioctl = rs_ioctl,
- .throttle = rs_throttle,
- .unthrottle = rs_unthrottle,
- .set_termios = rs_set_termios,
- .stop = rs_stop,
- .start = rs_start,
- .hangup = rs_hangup,
- .break_ctl = rs_break,
- .wait_until_sent = rs_wait_until_sent,
- .read_proc = macserial_read_proc,
- .tiocmget = rs_tiocmget,
- .tiocmset = rs_tiocmset,
-};
-
-static int macserial_init(void)
-{
- int channel, i;
- struct mac_serial *info;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- serial_driver = alloc_tty_driver(zs_channels_found);
- if (!serial_driver)
- return -ENOMEM;
-
- /* XXX assume it's a powerbook if we have a via-pmu
- *
- * This is OK for core99 machines as well.
- */
- is_powerbook = find_devices("via-pmu") != 0;
-
- /* Register the interrupt handler for each one
- * We also request the OF resources here as probe_sccs()
- * might be called too early for that
- */
- for (i = 0; i < zs_channels_found; ++i) {
- struct device_node* ch = zs_soft[i].dev_node;
- if (!request_OF_resource(ch, 0, NULL)) {
- printk(KERN_ERR "macserial: can't request IO resource !\n");
- put_tty_driver(serial_driver);
- return -ENODEV;
- }
- if (zs_soft[i].has_dma) {
- if (!request_OF_resource(ch, ch->n_addrs - 2, " (tx dma)")) {
- printk(KERN_ERR "macserial: can't request TX DMA resource !\n");
- zs_soft[i].has_dma = 0;
- goto no_dma;
- }
- if (!request_OF_resource(ch, ch->n_addrs - 1, " (rx dma)")) {
- release_OF_resource(ch, ch->n_addrs - 2);
- printk(KERN_ERR "macserial: can't request RX DMA resource !\n");
- zs_soft[i].has_dma = 0;
- goto no_dma;
- }
- if (request_irq(zs_soft[i].tx_dma_irq, rs_txdma_irq, 0,
- "SCC-txdma", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].tx_dma_irq);
- disable_irq(zs_soft[i].tx_dma_irq);
- if (request_irq(zs_soft[i].rx_dma_irq, rs_rxdma_irq, 0,
- "SCC-rxdma", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].rx_dma_irq);
- disable_irq(zs_soft[i].rx_dma_irq);
- }
-no_dma:
- if (request_irq(zs_soft[i].irq, rs_interrupt, 0,
- "SCC", &zs_soft[i]))
- printk(KERN_ERR "macserial: can't get irq %d\n",
- zs_soft[i].irq);
- disable_irq(zs_soft[i].irq);
- }
-
- show_serial_version();
-
- /* Initialize the tty_driver structure */
- /* Not all of this is exactly right for us. */
-
- serial_driver->owner = THIS_MODULE;
- serial_driver->driver_name = "macserial";
- serial_driver->devfs_name = "tts/";
- serial_driver->name = "ttyS";
- serial_driver->major = TTY_MAJOR;
- serial_driver->minor_start = 64;
- serial_driver->type = TTY_DRIVER_TYPE_SERIAL;
- serial_driver->subtype = SERIAL_TYPE_NORMAL;
- serial_driver->init_termios = tty_std_termios;
- serial_driver->init_termios.c_cflag =
- B38400 | CS8 | CREAD | HUPCL | CLOCAL;
- serial_driver->flags = TTY_DRIVER_REAL_RAW;
- tty_set_operations(serial_driver, &serial_ops);
-
- if (tty_register_driver(serial_driver))
- printk(KERN_ERR "Error: couldn't register serial driver\n");
-
- for (channel = 0; channel < zs_channels_found; ++channel) {
-#ifdef CONFIG_KGDB
- if (zs_soft[channel].kgdb_channel) {
- kgdb_interruptible(1);
- continue;
- }
-#endif
- zs_soft[channel].clk_divisor = 16;
-/* -- we are not sure the SCC is powered ON at this point
- zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]);
-*/
- zs_soft[channel].zs_baud = 38400;
-
- /* If console serial line, then enable interrupts. */
- if (zs_soft[channel].is_cons) {
- printk(KERN_INFO "macserial: console line, enabling "
- "interrupt %d\n", zs_soft[channel].irq);
- panic("macserial: console not supported yet !");
- write_zsreg(zs_soft[channel].zs_channel, R1,
- (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));
- write_zsreg(zs_soft[channel].zs_channel, R9,
- (NV | MIE));
- }
- }
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
- {
- unsigned char* connector;
- int lenp;
-
-#ifdef CONFIG_KGDB
- if (info->kgdb_channel) {
- continue;
- }
-#endif
- info->magic = SERIAL_MAGIC;
- info->port = (int) info->zs_channel->control;
- info->line = i;
- info->tty = 0;
- info->custom_divisor = 16;
- info->timeout = 0;
- info->close_delay = 50;
- info->closing_wait = 3000;
- info->x_char = 0;
- info->event = 0;
- info->count = 0;
- info->blocked_open = 0;
- INIT_WORK(&info->tqueue, do_softint, info);
- spin_lock_init(&info->lock);
- init_waitqueue_head(&info->open_wait);
- init_waitqueue_head(&info->close_wait);
- info->timeout = HZ;
- printk(KERN_INFO "tty%02d at 0x%08x (irq = %d)", info->line,
- info->port, info->irq);
- printk(" is a Z8530 ESCC");
- connector = get_property(info->dev_node, "AAPL,connector", &lenp);
- if (connector)
- printk(", port = %s", connector);
- if (info->is_internal_modem)
- printk(" (internal modem)");
- if (info->is_irda)
- printk(" (IrDA)");
- printk("\n");
- }
- tmp_buf = 0;
-
- return 0;
-}
-
-void macserial_cleanup(void)
-{
- int i;
- unsigned long flags;
- struct mac_serial *info;
-
- for (info = zs_chain, i = 0; info; info = info->zs_next, i++)
- set_scc_power(info, 0);
- spin_lock_irqsave(&info->lock, flags);
- for (i = 0; i < zs_channels_found; ++i) {
- free_irq(zs_soft[i].irq, &zs_soft[i]);
- if (zs_soft[i].has_dma) {
- free_irq(zs_soft[i].tx_dma_irq, &zs_soft[i]);
- free_irq(zs_soft[i].rx_dma_irq, &zs_soft[i]);
- }
- release_OF_resource(zs_soft[i].dev_node, 0);
- if (zs_soft[i].has_dma) {
- struct device_node* ch = zs_soft[i].dev_node;
- release_OF_resource(ch, ch->n_addrs - 2);
- release_OF_resource(ch, ch->n_addrs - 1);
- }
- }
- spin_unlock_irqrestore(&info->lock, flags);
- tty_unregister_driver(serial_driver);
- put_tty_driver(serial_driver);
-
- if (tmp_buf) {
- free_page((unsigned long) tmp_buf);
- tmp_buf = 0;
- }
-
-#ifdef CONFIG_PMAC_PBOOK
- if (zs_channels_found)
- pmu_unregister_sleep_notifier(&serial_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
-}
-
-module_init(macserial_init);
-module_exit(macserial_cleanup);
-MODULE_LICENSE("GPL");
-
-#if 0
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* PowerMac: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
- return -1;
-}
-
-void unregister_serial(int line)
-{
- return;
-}
-#endif
-
-/*
- * ------------------------------------------------------------
- * Serial console driver
- * ------------------------------------------------------------
- */
-#ifdef CONFIG_SERIAL_CONSOLE
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- */
-static void serial_console_write(struct console *co, const char *s,
- unsigned count)
-{
- struct mac_serial *info = zs_soft + co->index;
- int i;
-
- /* Turn of interrupts and enable the transmitter. */
- write_zsreg(info->zs_channel, R1, info->curregs[1] & ~TxINT_ENAB);
- write_zsreg(info->zs_channel, R5, info->curregs[5] | TxENAB | RTS | DTR);
-
- for (i=0; i<count; i++) {
- /* Wait for the transmit buffer to empty. */
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0) {
- eieio();
- }
-
- write_zsdata(info->zs_channel, s[i]);
- if (s[i] == 10) {
- while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP)
- == 0)
- eieio();
-
- write_zsdata(info->zs_channel, 13);
- }
- }
-
- /* Restore the values in the registers. */
- write_zsreg(info->zs_channel, R1, info->curregs[1]);
- /* Don't disable the transmitter. */
-}
-
-static struct tty_driver *serial_driver;
-
-static struct tty_driver *serial_console_device(struct console *c, int *index)
-{
- *index = c->index;
- return serial_driver;
-}
-
-/*
- * Setup initial baud/bits/parity. We do two things here:
- * - construct a cflag setting for the first rs_open()
- * - initialize the serial port
- * Return non-zero if we didn't find a serial port.
- */
-static int __init serial_console_setup(struct console *co, char *options)
-{
- struct mac_serial *info;
- int baud = 38400;
- int bits = 8;
- int parity = 'n';
- int cflag = CREAD | HUPCL | CLOCAL;
- int brg;
- char *s;
- long flags;
-
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- if (zs_chain == 0)
- return -1;
-
- /* Do we have the device asked for? */
- if (co->index >= zs_channels_found)
- return -1;
- info = zs_soft + co->index;
-
- set_scc_power(info, 1);
-
- /* Reset the channel */
- write_zsreg(info->zs_channel, R9, CHRA);
-
- if (options) {
- baud = simple_strtoul(options, NULL, 10);
- s = options;
- while(*s >= '0' && *s <= '9')
- s++;
- if (*s)
- parity = *s++;
- if (*s)
- bits = *s - '0';
- }
-
- /*
- * Now construct a cflag setting.
- */
- switch(baud) {
- case 1200:
- cflag |= B1200;
- break;
- case 2400:
- cflag |= B2400;
- break;
- case 4800:
- cflag |= B4800;
- break;
- case 9600:
- cflag |= B9600;
- break;
- case 19200:
- cflag |= B19200;
- break;
- case 57600:
- cflag |= B57600;
- break;
- case 115200:
- cflag |= B115200;
- break;
- case 38400:
- default:
- cflag |= B38400;
- break;
- }
- switch(bits) {
- case 7:
- cflag |= CS7;
- break;
- default:
- case 8:
- cflag |= CS8;
- break;
- }
- switch(parity) {
- case 'o': case 'O':
- cflag |= PARENB | PARODD;
- break;
- case 'e': case 'E':
- cflag |= PARENB;
- break;
- }
- co->cflag = cflag;
-
- spin_lock_irqsave(&info->lock, flags);
- memset(info->curregs, 0, sizeof(info->curregs));
-
- info->zs_baud = baud;
- info->clk_divisor = 16;
- switch (info->zs_baud) {
- case ZS_CLOCK/16: /* 230400 */
- info->curregs[4] = X16CLK;
- info->curregs[11] = 0;
- break;
- case ZS_CLOCK/32: /* 115200 */
- info->curregs[4] = X32CLK;
- info->curregs[11] = 0;
- break;
- default:
- info->curregs[4] = X16CLK;
- info->curregs[11] = TCBR | RCBR;
- brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);
- info->curregs[12] = (brg & 255);
- info->curregs[13] = ((brg >> 8) & 255);
- info->curregs[14] = BRENABL;
- }
-
- /* byte size and parity */
- info->curregs[3] &= ~RxNBITS_MASK;
- info->curregs[5] &= ~TxNBITS_MASK;
- switch (cflag & CSIZE) {
- case CS5:
- info->curregs[3] |= Rx5;
- info->curregs[5] |= Tx5;
- break;
- case CS6:
- info->curregs[3] |= Rx6;
- info->curregs[5] |= Tx6;
- break;
- case CS7:
- info->curregs[3] |= Rx7;
- info->curregs[5] |= Tx7;
- break;
- case CS8:
- default: /* defaults to 8 bits */
- info->curregs[3] |= Rx8;
- info->curregs[5] |= Tx8;
- break;
- }
- info->curregs[5] |= TxENAB | RTS | DTR;
- info->pendregs[3] = info->curregs[3];
- info->pendregs[5] = info->curregs[5];
-
- info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);
- if (cflag & CSTOPB) {
- info->curregs[4] |= SB2;
- } else {
- info->curregs[4] |= SB1;
- }
- if (cflag & PARENB) {
- info->curregs[4] |= PAR_ENA;
- if (!(cflag & PARODD)) {
- info->curregs[4] |= PAR_EVEN;
- }
- }
- info->pendregs[4] = info->curregs[4];
-
- if (!(cflag & CLOCAL)) {
- if (!(info->curregs[15] & DCDIE))
- info->read_reg_zero = read_zsreg(info->zs_channel, 0);
- info->curregs[15] |= DCDIE;
- } else
- info->curregs[15] &= ~DCDIE;
- if (cflag & CRTSCTS) {
- info->curregs[15] |= CTSIE;
- if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)
- info->tx_stopped = 1;
- } else {
- info->curregs[15] &= ~CTSIE;
- info->tx_stopped = 0;
- }
- info->pendregs[15] = info->curregs[15];
-
- /* Load up the new values */
- load_zsregs(info->zs_channel, info->curregs);
-
- spin_unlock_irqrestore(&info->lock, flags);
-
- return 0;
-}
-
-static struct console sercons = {
- .name = "ttyS",
- .write = serial_console_write,
- .device = serial_console_device,
- .setup = serial_console_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
-};
-
-/*
- * Register console.
- */
-static void __init mac_scc_console_init(void)
-{
- register_console(&sercons);
-}
-console_initcall(mac_scc_console_init);
-
-#endif /* ifdef CONFIG_SERIAL_CONSOLE */
-
-#ifdef CONFIG_KGDB
-/* These are for receiving and sending characters under the kgdb
- * source level kernel debugger.
- */
-void putDebugChar(char kgdb_char)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)
- udelay(5);
- write_zsdata(chan, kgdb_char);
-}
-
-char getDebugChar(void)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- while((read_zsreg(chan, 0) & Rx_CH_AV) == 0)
- eieio(); /*barrier();*/
- return read_zsdata(chan);
-}
-
-void kgdb_interruptible(int yes)
-{
- struct mac_zschannel *chan = zs_kgdbchan;
- int one, nine;
- nine = read_zsreg(chan, 9);
- if (yes == 1) {
- one = EXT_INT_ENAB|INT_ALL_Rx;
- nine |= MIE;
- printk("turning serial ints on\n");
- } else {
- one = RxINT_DISAB;
- nine &= ~MIE;
- printk("turning serial ints off\n");
- }
- write_zsreg(chan, 1, one);
- write_zsreg(chan, 9, nine);
-}
-
-/* This sets up the serial port we're using, and turns on
- * interrupts for that channel, so kgdb is usable once we're done.
- */
-static inline void kgdb_chaninit(struct mac_zschannel *ms, int intson, int bps)
-{
- int brg;
- int i, x;
- volatile char *sccc = ms->control;
- brg = BPS_TO_BRG(bps, ZS_CLOCK/16);
- printk("setting bps on kgdb line to %d [brg=%x]\n", bps, brg);
- for (i = 20000; i != 0; --i) {
- x = *sccc; eieio();
- }
- for (i = 0; i < sizeof(scc_inittab); ++i) {
- write_zsreg(ms, scc_inittab[i], scc_inittab[i+1]);
- i++;
- }
-}
-
-/* This is called at boot time to prime the kgdb serial debugging
- * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1
- * for /dev/ttyb which is determined in setup_arch() from the
- * boot command line flags.
- * XXX at the moment probably only channel A will work
- */
-void __init zs_kgdb_hook(int tty_num)
-{
- /* Find out how many Z8530 SCCs we have */
- if (zs_chain == 0)
- probe_sccs();
-
- set_scc_power(&zs_soft[tty_num], 1);
-
- zs_kgdbchan = zs_soft[tty_num].zs_channel;
- zs_soft[tty_num].change_needed = 0;
- zs_soft[tty_num].clk_divisor = 16;
- zs_soft[tty_num].zs_baud = 38400;
- zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */
-
- /* Turn on transmitter/receiver at 8-bits/char */
- kgdb_chaninit(zs_soft[tty_num].zs_channel, 1, 38400);
- printk("KGDB: on channel %d initialized\n", tty_num);
- set_debug_traps(); /* init stub */
-}
-#endif /* ifdef CONFIG_KGDB */
-
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * notify clients before sleep and reset bus afterwards
- */
-int
-serial_notify_sleep(struct pmu_sleep_notifier *self, int when)
-{
- int i;
-
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- case PBOOK_SLEEP_REJECT:
- break;
-
- case PBOOK_SLEEP_NOW:
- for (i=0; i<zs_channels_found; i++) {
- struct mac_serial *info = &zs_soft[i];
- if (info->flags & ZILOG_INITIALIZED) {
- shutdown(info);
- info->flags |= ZILOG_SLEEPING;
- }
- }
- break;
- case PBOOK_WAKE:
- for (i=0; i<zs_channels_found; i++) {
- struct mac_serial *info = &zs_soft[i];
- if (info->flags & ZILOG_SLEEPING) {
- info->flags &= ~ZILOG_SLEEPING;
- startup(info);
- }
- }
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
diff --git a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h
deleted file mode 100644
index bade11a7a5c3..000000000000
--- a/drivers/macintosh/macserial.h
+++ /dev/null
@@ -1,461 +0,0 @@
-/*
- * macserial.h: Definitions for the Macintosh Z8530 serial driver.
- *
- * Adapted from drivers/sbus/char/sunserial.h by Paul Mackerras.
- *
- * Copyright (C) 1996 Paul Mackerras (Paul.Mackerras@cs.anu.edu.au)
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
- */
-#ifndef _MACSERIAL_H
-#define _MACSERIAL_H
-
-#include <linux/spinlock.h>
-
-#define NUM_ZSREGS 16
-
-struct serial_struct {
- int type;
- int line;
- int port;
- int irq;
- int flags;
- int xmit_fifo_size;
- int custom_divisor;
- int baud_base;
- unsigned short close_delay;
- char reserved_char[2];
- int hub6;
- unsigned short closing_wait; /* time to wait before closing */
- unsigned short closing_wait2; /* no longer used... */
- int reserved[4];
-};
-
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ZILOG_CLOSING_WAIT_INF 0
-#define ZILOG_CLOSING_WAIT_NONE 65535
-
-/*
- * Definitions for ZILOG_struct (and serial_struct) flags field
- */
-#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes
- * on the callout port */
-#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */
-#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */
-#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */
-
-#define ZILOG_SPD_MASK 0x0030
-#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */
-
-#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */
-#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */
-
-#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */
-#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */
-#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */
-#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */
-#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */
-
-#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */
-#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged
- * users can set or reset */
-
-/* Internal flags used only by kernel/chr_drv/serial.c */
-#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */
-#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */
-#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */
-#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */
-#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */
-#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */
-#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */
-#define ZILOG_SLEEPING 0x01000000 /* have shut it down for sleep */
-
-/* Software state per channel */
-
-#ifdef __KERNEL__
-/*
- * This is our internal structure for each serial port's state.
- *
- * Many fields are paralleled by the structure used by the serial_struct
- * structure.
- *
- * For definitions of the flags field, see tty.h
- */
-
-struct mac_serial;
-
-struct mac_zschannel {
- volatile unsigned char* control;
- volatile unsigned char* data;
- spinlock_t lock;
- /* Used for debugging */
- struct mac_serial* parent;
-};
-
-struct mac_dma {
- volatile struct dbdma_regs dma;
- volatile unsigned short res_count;
- volatile unsigned short command;
- volatile unsigned int buf_addr;
-};
-
-struct mac_serial {
- struct mac_serial *zs_next; /* For IRQ servicing chain */
- struct mac_zschannel *zs_channel; /* Channel registers */
- struct mac_zschannel *zs_chan_a; /* A side registers */
- unsigned char read_reg_zero;
- struct device_node* dev_node;
- spinlock_t lock;
-
- char soft_carrier; /* Use soft carrier on this channel */
- char break_abort; /* Is serial console in, so process brk/abrt */
- char kgdb_channel; /* Kgdb is running on this channel */
- char is_cons; /* Is this our console. */
- char is_internal_modem; /* is connected to an internal modem */
- char is_irda; /* is connected to an IrDA codec */
- int port_type; /* Port type for pmac_feature */
- unsigned char tx_active; /* character is being xmitted */
- unsigned char tx_stopped; /* output is suspended */
- unsigned char power_wait; /* waiting for power-up delay to expire */
-
- /* We need to know the current clock divisor
- * to read the bps rate the chip has currently
- * loaded.
- */
- unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */
- int zs_baud;
-
- /* Current write register values */
- unsigned char curregs[NUM_ZSREGS];
-
- /* Values we need to set next opportunity */
- unsigned char pendregs[NUM_ZSREGS];
-
- char change_needed;
-
- int magic;
- int baud_base;
- int port;
- int irq;
- int flags; /* defined in tty.h */
- int type; /* UART type */
- struct tty_struct *tty;
- int read_status_mask;
- int ignore_status_mask;
- int timeout;
- int xmit_fifo_size;
- int custom_divisor;
- int x_char; /* xon/xoff character */
- int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
- unsigned long event;
- unsigned long last_active;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- unsigned char *xmit_buf;
- int xmit_head;
- int xmit_tail;
- int xmit_cnt;
- struct work_struct tqueue;
- wait_queue_head_t open_wait;
- wait_queue_head_t close_wait;
-
- volatile struct dbdma_regs *tx_dma;
- int tx_dma_irq;
- volatile struct dbdma_cmd *tx_cmds;
- volatile struct mac_dma *rx;
- int rx_dma_irq;
- volatile struct dbdma_cmd **rx_cmds;
- unsigned char **rx_char_buf;
- unsigned char **rx_flag_buf;
-#define RX_BUF_SIZE 256
- int rx_nbuf;
- int rx_done_bytes;
- int rx_ubuf;
- int rx_fbuf;
-#define RX_NO_FBUF (-1)
- int rx_cbuf;
- spinlock_t rx_dma_lock;
- int has_dma;
- int dma_initted;
- void *dma_priv;
- struct timer_list poll_dma_timer;
-#define RX_DMA_TIMER (jiffies + 10*HZ/1000)
-
- struct timer_list powerup_timer;
-};
-
-
-#define SERIAL_MAGIC 0x5301
-
-/*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
-#define RS_EVENT_WRITE_WAKEUP 0
-
-#endif /* __KERNEL__ */
-
-/* Conversion routines to/from brg time constants from/to bits
- * per second.
- */
-#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2))
-#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2)
-
-/* The Zilog register set */
-
-#define FLAG 0x7e
-
-/* Write Register 0 */
-#define R0 0 /* Register selects */
-#define R1 1
-#define R2 2
-#define R3 3
-#define R4 4
-#define R5 5
-#define R6 6
-#define R7 7
-#define R8 8
-#define R9 9
-#define R10 10
-#define R11 11
-#define R12 12
-#define R13 13
-#define R14 14
-#define R15 15
-
-#define NULLCODE 0 /* Null Code */
-#define POINT_HIGH 0x8 /* Select upper half of registers */
-#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */
-#define SEND_ABORT 0x18 /* HDLC Abort */
-#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */
-#define RES_Tx_P 0x28 /* Reset TxINT Pending */
-#define ERR_RES 0x30 /* Error Reset */
-#define RES_H_IUS 0x38 /* Reset highest IUS */
-
-#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */
-#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */
-#define RES_EOM_L 0xC0 /* Reset EOM latch */
-
-/* Write Register 1 */
-
-#define EXT_INT_ENAB 0x1 /* Ext Int Enable */
-#define TxINT_ENAB 0x2 /* Tx Int Enable */
-#define PAR_SPEC 0x4 /* Parity is special condition */
-
-#define RxINT_DISAB 0 /* Rx Int Disable */
-#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */
-#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */
-#define INT_ERR_Rx 0x18 /* Int on error only */
-
-#define WT_RDY_RT 0x20 /* W/Req reflects recv if 1, xmit if 0 */
-#define WT_FN_RDYFN 0x40 /* W/Req pin is DMA request if 1, wait if 0 */
-#define WT_RDY_ENAB 0x80 /* Enable W/Req pin */
-
-/* Write Register #2 (Interrupt Vector) */
-
-/* Write Register 3 */
-
-#define RxENABLE 0x1 /* Rx Enable */
-#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */
-#define ADD_SM 0x4 /* Address Search Mode (SDLC) */
-#define RxCRC_ENAB 0x8 /* Rx CRC Enable */
-#define ENT_HM 0x10 /* Enter Hunt Mode */
-#define AUTO_ENAB 0x20 /* Auto Enables */
-#define Rx5 0x0 /* Rx 5 Bits/Character */
-#define Rx7 0x40 /* Rx 7 Bits/Character */
-#define Rx6 0x80 /* Rx 6 Bits/Character */
-#define Rx8 0xc0 /* Rx 8 Bits/Character */
-#define RxNBITS_MASK 0xc0
-
-/* Write Register 4 */
-
-#define PAR_ENA 0x1 /* Parity Enable */
-#define PAR_EVEN 0x2 /* Parity Even/Odd* */
-
-#define SYNC_ENAB 0 /* Sync Modes Enable */
-#define SB1 0x4 /* 1 stop bit/char */
-#define SB15 0x8 /* 1.5 stop bits/char */
-#define SB2 0xc /* 2 stop bits/char */
-#define SB_MASK 0xc
-
-#define MONSYNC 0 /* 8 Bit Sync character */
-#define BISYNC 0x10 /* 16 bit sync character */
-#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */
-#define EXTSYNC 0x30 /* External Sync Mode */
-
-#define X1CLK 0x0 /* x1 clock mode */
-#define X16CLK 0x40 /* x16 clock mode */
-#define X32CLK 0x80 /* x32 clock mode */
-#define X64CLK 0xC0 /* x64 clock mode */
-#define XCLK_MASK 0xC0
-
-/* Write Register 5 */
-
-#define TxCRC_ENAB 0x1 /* Tx CRC Enable */
-#define RTS 0x2 /* RTS */
-#define SDLC_CRC 0x4 /* SDLC/CRC-16 */
-#define TxENAB 0x8 /* Tx Enable */
-#define SND_BRK 0x10 /* Send Break */
-#define Tx5 0x0 /* Tx 5 bits (or less)/character */
-#define Tx7 0x20 /* Tx 7 bits/character */
-#define Tx6 0x40 /* Tx 6 bits/character */
-#define Tx8 0x60 /* Tx 8 bits/character */
-#define TxNBITS_MASK 0x60
-#define DTR 0x80 /* DTR */
-
-/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */
-
-/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */
-
-/* Write Register 7' (Some enhanced feature control) */
-#define ENEXREAD 0x40 /* Enable read of some write registers */
-
-/* Write Register 8 (transmit buffer) */
-
-/* Write Register 9 (Master interrupt control) */
-#define VIS 1 /* Vector Includes Status */
-#define NV 2 /* No Vector */
-#define DLC 4 /* Disable Lower Chain */
-#define MIE 8 /* Master Interrupt Enable */
-#define STATHI 0x10 /* Status high */
-#define NORESET 0 /* No reset on write to R9 */
-#define CHRB 0x40 /* Reset channel B */
-#define CHRA 0x80 /* Reset channel A */
-#define FHWRES 0xc0 /* Force hardware reset */
-
-/* Write Register 10 (misc control bits) */
-#define BIT6 1 /* 6 bit/8bit sync */
-#define LOOPMODE 2 /* SDLC Loop mode */
-#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */
-#define MARKIDLE 8 /* Mark/flag on idle */
-#define GAOP 0x10 /* Go active on poll */
-#define NRZ 0 /* NRZ mode */
-#define NRZI 0x20 /* NRZI mode */
-#define FM1 0x40 /* FM1 (transition = 1) */
-#define FM0 0x60 /* FM0 (transition = 0) */
-#define CRCPS 0x80 /* CRC Preset I/O */
-
-/* Write Register 11 (Clock Mode control) */
-#define TRxCXT 0 /* TRxC = Xtal output */
-#define TRxCTC 1 /* TRxC = Transmit clock */
-#define TRxCBR 2 /* TRxC = BR Generator Output */
-#define TRxCDP 3 /* TRxC = DPLL output */
-#define TRxCOI 4 /* TRxC O/I */
-#define TCRTxCP 0 /* Transmit clock = RTxC pin */
-#define TCTRxCP 8 /* Transmit clock = TRxC pin */
-#define TCBR 0x10 /* Transmit clock = BR Generator output */
-#define TCDPLL 0x18 /* Transmit clock = DPLL output */
-#define RCRTxCP 0 /* Receive clock = RTxC pin */
-#define RCTRxCP 0x20 /* Receive clock = TRxC pin */
-#define RCBR 0x40 /* Receive clock = BR Generator output */
-#define RCDPLL 0x60 /* Receive clock = DPLL output */
-#define RTxCX 0x80 /* RTxC Xtal/No Xtal */
-
-/* Write Register 12 (lower byte of baud rate generator time constant) */
-
-/* Write Register 13 (upper byte of baud rate generator time constant) */
-
-/* Write Register 14 (Misc control bits) */
-#define BRENABL 1 /* Baud rate generator enable */
-#define BRSRC 2 /* Baud rate generator source */
-#define DTRREQ 4 /* DTR/Request function */
-#define AUTOECHO 8 /* Auto Echo */
-#define LOOPBAK 0x10 /* Local loopback */
-#define SEARCH 0x20 /* Enter search mode */
-#define RMC 0x40 /* Reset missing clock */
-#define DISDPLL 0x60 /* Disable DPLL */
-#define SSBR 0x80 /* Set DPLL source = BR generator */
-#define SSRTxC 0xa0 /* Set DPLL source = RTxC */
-#define SFMM 0xc0 /* Set FM mode */
-#define SNRZI 0xe0 /* Set NRZI mode */
-
-/* Write Register 15 (external/status interrupt control) */
-#define EN85C30 1 /* Enable some 85c30-enhanced registers */
-#define ZCIE 2 /* Zero count IE */
-#define ENSTFIFO 4 /* Enable status FIFO (SDLC) */
-#define DCDIE 8 /* DCD IE */
-#define SYNCIE 0x10 /* Sync/hunt IE */
-#define CTSIE 0x20 /* CTS IE */
-#define TxUIE 0x40 /* Tx Underrun/EOM IE */
-#define BRKIE 0x80 /* Break/Abort IE */
-
-
-/* Read Register 0 */
-#define Rx_CH_AV 0x1 /* Rx Character Available */
-#define ZCOUNT 0x2 /* Zero count */
-#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */
-#define DCD 0x8 /* DCD */
-#define SYNC_HUNT 0x10 /* Sync/hunt */
-#define CTS 0x20 /* CTS */
-#define TxEOM 0x40 /* Tx underrun */
-#define BRK_ABRT 0x80 /* Break/Abort */
-
-/* Read Register 1 */
-#define ALL_SNT 0x1 /* All sent */
-/* Residue Data for 8 Rx bits/char programmed */
-#define RES3 0x8 /* 0/3 */
-#define RES4 0x4 /* 0/4 */
-#define RES5 0xc /* 0/5 */
-#define RES6 0x2 /* 0/6 */
-#define RES7 0xa /* 0/7 */
-#define RES8 0x6 /* 0/8 */
-#define RES18 0xe /* 1/8 */
-#define RES28 0x0 /* 2/8 */
-/* Special Rx Condition Interrupts */
-#define PAR_ERR 0x10 /* Parity error */
-#define Rx_OVR 0x20 /* Rx Overrun Error */
-#define FRM_ERR 0x40 /* CRC/Framing Error */
-#define END_FR 0x80 /* End of Frame (SDLC) */
-
-/* Read Register 2 (channel b only) - Interrupt vector */
-#define CHB_Tx_EMPTY 0x00
-#define CHB_EXT_STAT 0x02
-#define CHB_Rx_AVAIL 0x04
-#define CHB_SPECIAL 0x06
-#define CHA_Tx_EMPTY 0x08
-#define CHA_EXT_STAT 0x0a
-#define CHA_Rx_AVAIL 0x0c
-#define CHA_SPECIAL 0x0e
-#define STATUS_MASK 0x06
-
-/* Read Register 3 (interrupt pending register) ch a only */
-#define CHBEXT 0x1 /* Channel B Ext/Stat IP */
-#define CHBTxIP 0x2 /* Channel B Tx IP */
-#define CHBRxIP 0x4 /* Channel B Rx IP */
-#define CHAEXT 0x8 /* Channel A Ext/Stat IP */
-#define CHATxIP 0x10 /* Channel A Tx IP */
-#define CHARxIP 0x20 /* Channel A Rx IP */
-
-/* Read Register 8 (receive data register) */
-
-/* Read Register 10 (misc status bits) */
-#define ONLOOP 2 /* On loop */
-#define LOOPSEND 0x10 /* Loop sending */
-#define CLK2MIS 0x40 /* Two clocks missing */
-#define CLK1MIS 0x80 /* One clock missing */
-
-/* Read Register 12 (lower byte of baud rate generator constant) */
-
-/* Read Register 13 (upper byte of baud rate generator constant) */
-
-/* Read Register 15 (value of WR 15) */
-
-/* Misc macros */
-#define ZS_CLEARERR(channel) (write_zsreg(channel, 0, ERR_RES))
-#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- garbage = read_zsdata(channel); \
- } while(0)
-
-#endif /* !(_MACSERIAL_H) */
diff --git a/drivers/macintosh/mediabay.c b/drivers/macintosh/mediabay.c
index 4be709e13eec..7c16c25fc5d4 100644
--- a/drivers/macintosh/mediabay.c
+++ b/drivers/macintosh/mediabay.c
@@ -642,7 +642,7 @@ static int __pmac media_bay_task(void *x)
}
}
-static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit media_bay_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct media_bay_info* bay;
u32 __iomem *regbase;
@@ -797,23 +797,20 @@ static struct mb_ops keylargo_mb_ops __pmacdata = {
* Therefore we do it all by polling the media bay once each tick.
*/
-static struct of_match media_bay_match[] =
+static struct of_device_id media_bay_match[] =
{
{
.name = "media-bay",
- .type = OF_ANY_MATCH,
.compatible = "keylargo-media-bay",
.data = &keylargo_mb_ops,
},
{
.name = "media-bay",
- .type = OF_ANY_MATCH,
.compatible = "heathrow-media-bay",
.data = &heathrow_mb_ops,
},
{
.name = "media-bay",
- .type = OF_ANY_MATCH,
.compatible = "ohare-media-bay",
.data = &ohare_mb_ops,
},
diff --git a/drivers/macintosh/therm_adt746x.c b/drivers/macintosh/therm_adt746x.c
index 5ba190ce14a0..c9ca1118e449 100644
--- a/drivers/macintosh/therm_adt746x.c
+++ b/drivers/macintosh/therm_adt746x.c
@@ -328,9 +328,7 @@ static int monitor_task(void *arg)
struct thermostat* th = arg;
while(!kthread_should_stop()) {
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
-
+ try_to_freeze();
msleep_interruptible(2000);
#ifndef DEBUG
diff --git a/drivers/macintosh/therm_pm72.c b/drivers/macintosh/therm_pm72.c
index feb4e2413858..703e31973314 100644
--- a/drivers/macintosh/therm_pm72.c
+++ b/drivers/macintosh/therm_pm72.c
@@ -120,6 +120,7 @@
#include <asm/system.h>
#include <asm/sections.h>
#include <asm/of_device.h>
+#include <asm/macio.h>
#include "therm_pm72.h"
@@ -1986,7 +1987,7 @@ static void fcu_lookup_fans(struct device_node *fcu_node)
}
}
-static int fcu_of_probe(struct of_device* dev, const struct of_match *match)
+static int fcu_of_probe(struct of_device* dev, const struct of_device_id *match)
{
int rc;
@@ -2009,12 +2010,10 @@ static int fcu_of_remove(struct of_device* dev)
return 0;
}
-static struct of_match fcu_of_match[] =
+static struct of_device_id fcu_match[] =
{
{
- .name = OF_ANY_MATCH,
.type = "fcu",
- .compatible = OF_ANY_MATCH
},
{},
};
@@ -2022,7 +2021,7 @@ static struct of_match fcu_of_match[] =
static struct of_platform_driver fcu_of_platform_driver =
{
.name = "temperature",
- .match_table = fcu_of_match,
+ .match_table = fcu_match,
.probe = fcu_of_probe,
.remove = fcu_of_remove
};
diff --git a/drivers/macintosh/therm_windtunnel.c b/drivers/macintosh/therm_windtunnel.c
index 61400f04015e..cbb72eb0426d 100644
--- a/drivers/macintosh/therm_windtunnel.c
+++ b/drivers/macintosh/therm_windtunnel.c
@@ -43,6 +43,7 @@
#include <asm/system.h>
#include <asm/sections.h>
#include <asm/of_device.h>
+#include <asm/macio.h>
#define LOG_TEMP 0 /* continously log temperature */
@@ -450,7 +451,7 @@ do_probe( struct i2c_adapter *adapter, int addr, int kind )
/************************************************************************/
static int
-therm_of_probe( struct of_device *dev, const struct of_match *match )
+therm_of_probe( struct of_device *dev, const struct of_device_id *match )
{
return i2c_add_driver( &g4fan_driver );
}
@@ -461,9 +462,8 @@ therm_of_remove( struct of_device *dev )
return i2c_del_driver( &g4fan_driver );
}
-static struct of_match therm_of_match[] = {{
+static struct of_device_id therm_of_match[] = {{
.name = "fan",
- .type = OF_ANY_MATCH,
.compatible = "adm1030"
}, {}
};
diff --git a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c
index b941ee220997..4a0a0ad2d03c 100644
--- a/drivers/macintosh/via-pmu.c
+++ b/drivers/macintosh/via-pmu.c
@@ -63,6 +63,10 @@
#include <asm/backlight.h>
#endif
+#ifdef CONFIG_PPC32
+#include <asm/open_pic.h>
+#endif
+
/* Some compile options */
#undef SUSPEND_USES_PMU
#define DEBUG_SLEEP
@@ -151,10 +155,10 @@ static spinlock_t pmu_lock;
static u8 pmu_intr_mask;
static int pmu_version;
static int drop_interrupts;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static int option_lid_wakeup = 1;
static int sleep_in_progress;
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
static unsigned long async_req_locks;
static unsigned int pmu_irq_stats[11];
@@ -164,7 +168,6 @@ static struct proc_dir_entry *proc_pmu_irqstats;
static struct proc_dir_entry *proc_pmu_options;
static int option_server_mode;
-#ifdef CONFIG_PMAC_PBOOK
int pmu_battery_count;
int pmu_cur_battery;
unsigned int pmu_power_flags;
@@ -172,7 +175,6 @@ struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
static int query_batt_timer = BATTERY_POLLING_COUNT;
static struct adb_request batt_req;
static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
-#endif /* CONFIG_PMAC_PBOOK */
#if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
extern int disable_kernel_backlight;
@@ -206,11 +208,9 @@ static int proc_get_irqstats(char *page, char **start, off_t off,
static int pmu_set_backlight_level(int level, void* data);
static int pmu_set_backlight_enable(int on, int level, void* data);
#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
static void pmu_pass_intr(unsigned char *data, int len);
static int proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data);
-#endif /* CONFIG_PMAC_PBOOK */
static int proc_read_options(char *page, char **start, off_t off,
int count, int *eof, void *data);
static int proc_write_options(struct file *file, const char __user *buffer,
@@ -403,8 +403,12 @@ static int __init via_pmu_start(void)
bright_req_1.complete = 1;
bright_req_2.complete = 1;
-#ifdef CONFIG_PMAC_PBOOK
batt_req.complete = 1;
+
+#ifdef CONFIG_PPC32
+ if (pmu_kind == PMU_KEYLARGO_BASED)
+ openpic_set_irq_priority(vias->intrs[0].line,
+ OPENPIC_PRIORITY_DEFAULT + 1);
#endif
if (request_irq(vias->intrs[0].line, via_pmu_interrupt, 0, "VIA-PMU",
@@ -458,7 +462,7 @@ static int __init via_pmu_dev_init(void)
register_backlight_controller(&pmu_backlight_controller, NULL, "pmu");
#endif /* CONFIG_PMAC_BACKLIGHT */
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC32
if (machine_is_compatible("AAPL,3400/2400") ||
machine_is_compatible("AAPL,3500")) {
int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
@@ -486,20 +490,19 @@ static int __init via_pmu_dev_init(void)
pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
}
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC32 */
+
/* Create /proc/pmu */
proc_pmu_root = proc_mkdir("pmu", NULL);
if (proc_pmu_root) {
-#ifdef CONFIG_PMAC_PBOOK
- int i;
+ long i;
for (i=0; i<pmu_battery_count; i++) {
char title[16];
- sprintf(title, "battery_%d", i);
+ sprintf(title, "battery_%ld", i);
proc_pmu_batt[i] = create_proc_read_entry(title, 0, proc_pmu_root,
proc_get_batt, (void *)i);
}
-#endif /* CONFIG_PMAC_PBOOK */
proc_pmu_info = create_proc_read_entry("info", 0, proc_pmu_root,
proc_get_info, NULL);
@@ -619,8 +622,6 @@ static void pmu_set_server_mode(int server_mode)
pmu_wait_complete(&req);
}
-#ifdef CONFIG_PMAC_PBOOK
-
/* This new version of the code for 2400/3400/3500 powerbooks
* is inspired from the implementation in gkrellm-pmu
*/
@@ -803,8 +804,6 @@ query_battery_state(void)
2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
}
-#endif /* CONFIG_PMAC_PBOOK */
-
static int __pmac
proc_get_info(char *page, char **start, off_t off,
int count, int *eof, void *data)
@@ -813,11 +812,9 @@ proc_get_info(char *page, char **start, off_t off,
p += sprintf(p, "PMU driver version : %d\n", PMU_DRIVER_VERSION);
p += sprintf(p, "PMU firmware version : %02x\n", pmu_version);
-#ifdef CONFIG_PMAC_PBOOK
p += sprintf(p, "AC Power : %d\n",
((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0));
p += sprintf(p, "Battery count : %d\n", pmu_battery_count);
-#endif /* CONFIG_PMAC_PBOOK */
return p - page;
}
@@ -849,12 +846,11 @@ proc_get_irqstats(char *page, char **start, off_t off,
return p - page;
}
-#ifdef CONFIG_PMAC_PBOOK
static int __pmac
proc_get_batt(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
- int batnum = (int)data;
+ long batnum = (long)data;
char *p = page;
p += sprintf(p, "\n");
@@ -873,7 +869,6 @@ proc_get_batt(char *page, char **start, off_t off,
return p - page;
}
-#endif /* CONFIG_PMAC_PBOOK */
static int __pmac
proc_read_options(char *page, char **start, off_t off,
@@ -881,11 +876,11 @@ proc_read_options(char *page, char **start, off_t off,
{
char *p = page;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
p += sprintf(p, "lid_wakeup=%d\n", option_lid_wakeup);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
if (pmu_kind == PMU_KEYLARGO_BASED)
p += sprintf(p, "server_mode=%d\n", option_server_mode);
@@ -922,12 +917,12 @@ proc_write_options(struct file *file, const char __user *buffer,
*(val++) = 0;
while(*val == ' ')
val++;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
if (pmu_kind == PMU_KEYLARGO_BASED &&
pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
if (!strcmp(label, "lid_wakeup"))
option_lid_wakeup = ((*val) == '1');
-#endif /* CONFIG_PMAC_PBOOK */
+#endif
if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
int new_value;
new_value = ((*val) == '1');
@@ -1422,7 +1417,6 @@ next:
}
/* Tick interrupt */
else if ((1 << pirq) & PMU_INT_TICK) {
-#ifdef CONFIG_PMAC_PBOOK
/* Environement or tick interrupt, query batteries */
if (pmu_battery_count) {
if ((--query_batt_timer) == 0) {
@@ -1437,7 +1431,6 @@ next:
pmu_pass_intr(data, len);
} else {
pmu_pass_intr(data, len);
-#endif /* CONFIG_PMAC_PBOOK */
}
goto next;
}
@@ -2052,7 +2045,7 @@ pmu_i2c_simple_write(int bus, int addr, u8* data, int len)
return -1;
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static LIST_HEAD(sleep_notifiers);
@@ -2705,6 +2698,8 @@ powerbook_sleep_3400(void)
return 0;
}
+#endif /* CONFIG_PM */
+
/*
* Support for /dev/pmu device
*/
@@ -2884,11 +2879,11 @@ static int __pmac
pmu_ioctl(struct inode * inode, struct file *filp,
u_int cmd, u_long arg)
{
- struct pmu_private *pp = filp->private_data;
__u32 __user *argp = (__u32 __user *)arg;
- int error;
+ int error = -EINVAL;
switch (cmd) {
+#ifdef CONFIG_PM
case PMU_IOC_SLEEP:
if (!capable(CAP_SYS_ADMIN))
return -EACCES;
@@ -2910,12 +2905,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
error = -ENOSYS;
}
sleep_in_progress = 0;
- return error;
+ break;
case PMU_IOC_CAN_SLEEP:
if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0)
return put_user(0, argp);
else
return put_user(1, argp);
+#endif /* CONFIG_PM */
#ifdef CONFIG_PMAC_BACKLIGHT
/* Backlight should have its own device or go via
@@ -2936,11 +2932,13 @@ pmu_ioctl(struct inode * inode, struct file *filp,
error = get_user(value, argp);
if (!error)
error = set_backlight_level(value);
- return error;
+ break;
}
#ifdef CONFIG_INPUT_ADBHID
case PMU_IOC_GRAB_BACKLIGHT: {
+ struct pmu_private *pp = filp->private_data;
unsigned long flags;
+
if (pp->backlight_locker)
return 0;
pp->backlight_locker = 1;
@@ -2956,7 +2954,7 @@ pmu_ioctl(struct inode * inode, struct file *filp,
case PMU_IOC_HAS_ADB:
return put_user(pmu_has_adb, argp);
}
- return -EINVAL;
+ return error;
}
static struct file_operations pmu_device_fops __pmacdata = {
@@ -2972,14 +2970,16 @@ static struct miscdevice pmu_device __pmacdata = {
PMU_MINOR, "pmu", &pmu_device_fops
};
-void pmu_device_init(void)
+static int pmu_device_init(void)
{
if (!via)
- return;
+ return 0;
if (misc_register(&pmu_device) < 0)
printk(KERN_ERR "via-pmu: cannot register misc device.\n");
+ return 0;
}
-#endif /* CONFIG_PMAC_PBOOK */
+device_initcall(pmu_device_init);
+
#ifdef DEBUG_SLEEP
static inline void __pmac
@@ -3147,12 +3147,12 @@ EXPORT_SYMBOL(pmu_i2c_combined_read);
EXPORT_SYMBOL(pmu_i2c_stdsub_write);
EXPORT_SYMBOL(pmu_i2c_simple_read);
EXPORT_SYMBOL(pmu_i2c_simple_write);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
EXPORT_SYMBOL(pmu_register_sleep_notifier);
EXPORT_SYMBOL(pmu_unregister_sleep_notifier);
EXPORT_SYMBOL(pmu_enable_irled);
EXPORT_SYMBOL(pmu_battery_count);
EXPORT_SYMBOL(pmu_batteries);
EXPORT_SYMBOL(pmu_power_flags);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
diff --git a/drivers/mca/mca-legacy.c b/drivers/mca/mca-legacy.c
index af56313ba0af..0c7bfa74c8ef 100644
--- a/drivers/mca/mca-legacy.c
+++ b/drivers/mca/mca-legacy.c
@@ -180,7 +180,6 @@ struct mca_device *mca_find_device_by_slot(int slot)
return info.mca_dev;
}
-EXPORT_SYMBOL(mca_find_device_by_slot);
/**
* mca_read_stored_pos - read POS register from boot data
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 0c1b8520ef86..785806bdb248 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -63,6 +63,7 @@ struct multipath {
unsigned nr_priority_groups;
struct list_head priority_groups;
unsigned pg_init_required; /* pg_init needs calling? */
+ unsigned pg_init_in_progress; /* Only one pg_init allowed at once */
unsigned nr_valid_paths; /* Total number of usable paths */
struct pgpath *current_pgpath;
@@ -72,7 +73,7 @@ struct multipath {
unsigned queue_io; /* Must we queue all I/O? */
unsigned queue_if_no_path; /* Queue I/O if last path fails? */
- unsigned suspended; /* Has dm core suspended our I/O? */
+ unsigned saved_queue_if_no_path;/* Saved state during suspension */
struct work_struct process_queued_ios;
struct bio_list queued_ios;
@@ -304,11 +305,12 @@ static int map_io(struct multipath *m, struct bio *bio, struct mpath_io *mpio,
m->queue_size--;
if ((pgpath && m->queue_io) ||
- (!pgpath && m->queue_if_no_path && !m->suspended)) {
+ (!pgpath && m->queue_if_no_path)) {
/* Queue for the daemon to resubmit */
bio_list_add(&m->queued_ios, bio);
m->queue_size++;
- if (m->pg_init_required || !m->queue_io)
+ if ((m->pg_init_required && !m->pg_init_in_progress) ||
+ !m->queue_io)
queue_work(kmultipathd, &m->process_queued_ios);
pgpath = NULL;
r = 0;
@@ -333,8 +335,9 @@ static int queue_if_no_path(struct multipath *m, unsigned queue_if_no_path)
spin_lock_irqsave(&m->lock, flags);
+ m->saved_queue_if_no_path = m->queue_if_no_path;
m->queue_if_no_path = queue_if_no_path;
- if (!m->queue_if_no_path)
+ if (!m->queue_if_no_path && m->queue_size)
queue_work(kmultipathd, &m->process_queued_ios);
spin_unlock_irqrestore(&m->lock, flags);
@@ -379,25 +382,31 @@ static void process_queued_ios(void *data)
{
struct multipath *m = (struct multipath *) data;
struct hw_handler *hwh = &m->hw_handler;
- struct pgpath *pgpath;
- unsigned init_required, must_queue = 0;
+ struct pgpath *pgpath = NULL;
+ unsigned init_required = 0, must_queue = 1;
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
+ if (!m->queue_size)
+ goto out;
+
if (!m->current_pgpath)
__choose_pgpath(m);
pgpath = m->current_pgpath;
- if ((pgpath && m->queue_io) ||
- (!pgpath && m->queue_if_no_path && !m->suspended))
- must_queue = 1;
+ if ((pgpath && !m->queue_io) ||
+ (!pgpath && !m->queue_if_no_path))
+ must_queue = 0;
- init_required = m->pg_init_required;
- if (init_required)
+ if (m->pg_init_required && !m->pg_init_in_progress) {
m->pg_init_required = 0;
+ m->pg_init_in_progress = 1;
+ init_required = 1;
+ }
+out:
spin_unlock_irqrestore(&m->lock, flags);
if (init_required)
@@ -752,6 +761,8 @@ static int multipath_ctr(struct dm_target *ti, unsigned int argc,
static void multipath_dtr(struct dm_target *ti)
{
struct multipath *m = (struct multipath *) ti->private;
+
+ flush_workqueue(kmultipathd);
free_multipath(m);
}
@@ -765,6 +776,9 @@ static int multipath_map(struct dm_target *ti, struct bio *bio,
struct mpath_io *mpio;
struct multipath *m = (struct multipath *) ti->private;
+ if (bio_barrier(bio))
+ return -EOPNOTSUPP;
+
mpio = mempool_alloc(m->mpio_pool, GFP_NOIO);
dm_bio_record(&mpio->details, bio);
@@ -837,7 +851,7 @@ static int reinstate_path(struct pgpath *pgpath)
pgpath->path.is_active = 1;
m->current_pgpath = NULL;
- if (!m->nr_valid_paths++)
+ if (!m->nr_valid_paths++ && m->queue_size)
queue_work(kmultipathd, &m->process_queued_ios);
queue_work(kmultipathd, &m->trigger_event);
@@ -963,12 +977,13 @@ void dm_pg_init_complete(struct path *path, unsigned err_flags)
bypass_pg(m, pg, 1);
spin_lock_irqsave(&m->lock, flags);
- if (!err_flags)
- m->queue_io = 0;
- else {
+ if (err_flags) {
m->current_pgpath = NULL;
m->current_pg = NULL;
- }
+ } else if (!m->pg_init_required)
+ m->queue_io = 0;
+
+ m->pg_init_in_progress = 0;
queue_work(kmultipathd, &m->process_queued_ios);
spin_unlock_irqrestore(&m->lock, flags);
}
@@ -988,9 +1003,12 @@ static int do_end_io(struct multipath *m, struct bio *bio,
if ((error == -EWOULDBLOCK) && bio_rw_ahead(bio))
return error;
+ if (error == -EOPNOTSUPP)
+ return error;
+
spin_lock(&m->lock);
if (!m->nr_valid_paths) {
- if (!m->queue_if_no_path || m->suspended) {
+ if (!m->queue_if_no_path) {
spin_unlock(&m->lock);
return -EIO;
} else {
@@ -1051,27 +1069,27 @@ static int multipath_end_io(struct dm_target *ti, struct bio *bio,
/*
* Suspend can't complete until all the I/O is processed so if
- * the last path failed we will now error any queued I/O.
+ * the last path fails we must error any remaining I/O.
+ * Note that if the freeze_bdev fails while suspending, the
+ * queue_if_no_path state is lost - userspace should reset it.
*/
static void multipath_presuspend(struct dm_target *ti)
{
struct multipath *m = (struct multipath *) ti->private;
- unsigned long flags;
- spin_lock_irqsave(&m->lock, flags);
- m->suspended = 1;
- if (m->queue_if_no_path)
- queue_work(kmultipathd, &m->process_queued_ios);
- spin_unlock_irqrestore(&m->lock, flags);
+ queue_if_no_path(m, 0);
}
+/*
+ * Restore the queue_if_no_path setting.
+ */
static void multipath_resume(struct dm_target *ti)
{
struct multipath *m = (struct multipath *) ti->private;
unsigned long flags;
spin_lock_irqsave(&m->lock, flags);
- m->suspended = 0;
+ m->queue_if_no_path = m->saved_queue_if_no_path;
spin_unlock_irqrestore(&m->lock, flags);
}
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 6e3cf7e13451..12031c9d3f1e 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -1060,6 +1060,7 @@ static int mirror_ctr(struct dm_target *ti, unsigned int argc, char **argv)
}
ti->private = ms;
+ ti->split_io = ms->rh.region_size;
r = kcopyd_client_create(DM_IO_PAGES, &ms->kcopyd_client);
if (r) {
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 7e691ab9a748..ab54f99b7c3b 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -777,7 +777,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio,
/* Full snapshots are not usable */
if (!s->valid)
- return -1;
+ return -EIO;
/*
* Write to snapshot - higher level takes care of RW/RO
@@ -931,6 +931,10 @@ static int __origin_write(struct list_head *snapshots, struct bio *bio)
if (!snap->valid)
continue;
+ /* Nothing to do if writing beyond end of snapshot */
+ if (bio->bi_sector >= dm_table_get_size(snap->table))
+ continue;
+
down_write(&snap->lock);
/*
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 18e9b9953fcd..a5a4c0ed8a14 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -943,6 +943,7 @@ EXPORT_SYMBOL(dm_vcalloc);
EXPORT_SYMBOL(dm_get_device);
EXPORT_SYMBOL(dm_put_device);
EXPORT_SYMBOL(dm_table_event);
+EXPORT_SYMBOL(dm_table_get_size);
EXPORT_SYMBOL(dm_table_get_mode);
EXPORT_SYMBOL(dm_table_put);
EXPORT_SYMBOL(dm_table_get);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index f6b03957efc7..54fabbf06678 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -384,7 +384,7 @@ static void __map_bio(struct dm_target *ti, struct bio *clone,
/* error the io and bail out */
struct dm_io *io = tio->io;
free_tio(tio->io->md, tio);
- dec_pending(io, -EIO);
+ dec_pending(io, r);
bio_put(clone);
}
}
@@ -966,23 +966,20 @@ static void __flush_deferred_io(struct mapped_device *md, struct bio *c)
*/
int dm_swap_table(struct mapped_device *md, struct dm_table *table)
{
- int r;
+ int r = -EINVAL;
down_write(&md->lock);
/* device must be suspended */
- if (!test_bit(DMF_SUSPENDED, &md->flags)) {
- up_write(&md->lock);
- return -EPERM;
- }
+ if (!test_bit(DMF_SUSPENDED, &md->flags))
+ goto out;
__unbind(md);
r = __bind(md, table);
- if (r)
- return r;
+out:
up_write(&md->lock);
- return 0;
+ return r;
}
/*
@@ -1055,14 +1052,17 @@ int dm_suspend(struct mapped_device *md)
if (test_bit(DMF_BLOCK_IO, &md->flags))
goto out_read_unlock;
- error = __lock_fs(md);
- if (error)
- goto out_read_unlock;
-
map = dm_get_table(md);
if (map)
+ /* This does not get reverted if there's an error later. */
dm_table_presuspend_targets(map);
+ error = __lock_fs(md);
+ if (error) {
+ dm_table_put(map);
+ goto out_read_unlock;
+ }
+
up_read(&md->lock);
/*
@@ -1121,7 +1121,6 @@ int dm_suspend(struct mapped_device *md)
return 0;
out_unfreeze:
- /* FIXME Undo dm_table_presuspend_targets */
__unlock_fs(md);
clear_bit(DMF_BLOCK_IO, &md->flags);
out_write_unlock:
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0c6b5b6baff6..4a0c57db2b67 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -338,6 +338,7 @@ static int super_written(struct bio *bio, unsigned int bytes_done, int error)
if (atomic_dec_and_test(&rdev->mddev->pending_writes))
wake_up(&rdev->mddev->sb_wait);
+ bio_put(bio);
return 0;
}
@@ -2976,8 +2977,7 @@ static int md_thread(void * arg)
wait_event_interruptible_timeout(thread->wqueue,
test_bit(THREAD_WAKEUP, &thread->flags),
thread->timeout);
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
clear_bit(THREAD_WAKEUP, &thread->flags);
diff --git a/drivers/media/common/ir-common.c b/drivers/media/common/ir-common.c
index 84a49d2ec919..ab7a1fba4427 100644
--- a/drivers/media/common/ir-common.c
+++ b/drivers/media/common/ir-common.c
@@ -1,5 +1,5 @@
/*
- * $Id: ir-common.c,v 1.8 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-common.c,v 1.11 2005/07/07 14:44:43 mchehab Exp $
*
* some common structs and functions to handle infrared remotes via
* input layer ...
@@ -46,79 +46,49 @@ module_param(debug, int, 0644);
/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
/* used by old (black) Hauppauge remotes */
IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_KP0, // 0
- [ 0x01 ] = KEY_KP1, // 1
- [ 0x02 ] = KEY_KP2, // 2
- [ 0x03 ] = KEY_KP3, // 3
- [ 0x04 ] = KEY_KP4, // 4
- [ 0x05 ] = KEY_KP5, // 5
- [ 0x06 ] = KEY_KP6, // 6
- [ 0x07 ] = KEY_KP7, // 7
- [ 0x08 ] = KEY_KP8, // 8
- [ 0x09 ] = KEY_KP9, // 9
-
- [ 0x0b ] = KEY_CHANNEL, // channel / program (japan: 11)
- [ 0x0c ] = KEY_POWER, // standby
- [ 0x0d ] = KEY_MUTE, // mute / demute
- [ 0x0f ] = KEY_TV, // display
- [ 0x10 ] = KEY_VOLUMEUP, // volume +
- [ 0x11 ] = KEY_VOLUMEDOWN, // volume -
- [ 0x12 ] = KEY_BRIGHTNESSUP, // brightness +
- [ 0x13 ] = KEY_BRIGHTNESSDOWN, // brightness -
- [ 0x1e ] = KEY_SEARCH, // search +
- [ 0x20 ] = KEY_CHANNELUP, // channel / program +
- [ 0x21 ] = KEY_CHANNELDOWN, // channel / program -
- [ 0x22 ] = KEY_CHANNEL, // alt / channel
- [ 0x23 ] = KEY_LANGUAGE, // 1st / 2nd language
- [ 0x26 ] = KEY_SLEEP, // sleeptimer
- [ 0x2e ] = KEY_MENU, // 2nd controls (USA: menu)
- [ 0x30 ] = KEY_PAUSE, // pause
- [ 0x32 ] = KEY_REWIND, // rewind
- [ 0x33 ] = KEY_GOTO, // go to
- [ 0x35 ] = KEY_PLAY, // play
- [ 0x36 ] = KEY_STOP, // stop
- [ 0x37 ] = KEY_RECORD, // recording
- [ 0x3c ] = KEY_TEXT, // teletext submode (Japan: 12)
- [ 0x3d ] = KEY_SUSPEND, // system standby
-
-#if 0 /* FIXME */
- [ 0x0a ] = KEY_RESERVED, // 1/2/3 digits (japan: 10)
- [ 0x0e ] = KEY_RESERVED, // P.P. (personal preference)
- [ 0x14 ] = KEY_RESERVED, // colour saturation +
- [ 0x15 ] = KEY_RESERVED, // colour saturation -
- [ 0x16 ] = KEY_RESERVED, // bass +
- [ 0x17 ] = KEY_RESERVED, // bass -
- [ 0x18 ] = KEY_RESERVED, // treble +
- [ 0x19 ] = KEY_RESERVED, // treble -
- [ 0x1a ] = KEY_RESERVED, // balance right
- [ 0x1b ] = KEY_RESERVED, // balance left
- [ 0x1c ] = KEY_RESERVED, // contrast +
- [ 0x1d ] = KEY_RESERVED, // contrast -
- [ 0x1f ] = KEY_RESERVED, // tint/hue +
- [ 0x24 ] = KEY_RESERVED, // spacial stereo on/off
- [ 0x25 ] = KEY_RESERVED, // mono / stereo (USA)
- [ 0x27 ] = KEY_RESERVED, // tint / hue -
- [ 0x28 ] = KEY_RESERVED, // RF switch/PIP select
- [ 0x29 ] = KEY_RESERVED, // vote
- [ 0x2a ] = KEY_RESERVED, // timed page/channel clck
- [ 0x2b ] = KEY_RESERVED, // increment (USA)
- [ 0x2c ] = KEY_RESERVED, // decrement (USA)
- [ 0x2d ] = KEY_RESERVED, //
- [ 0x2f ] = KEY_RESERVED, // PIP shift
- [ 0x31 ] = KEY_RESERVED, // erase
- [ 0x34 ] = KEY_RESERVED, // wind
- [ 0x38 ] = KEY_RESERVED, // external 1
- [ 0x39 ] = KEY_RESERVED, // external 2
- [ 0x3a ] = KEY_RESERVED, // PIP display mode
- [ 0x3b ] = KEY_RESERVED, // view data mode / advance
- [ 0x3e ] = KEY_RESERVED, // crispener on/off
- [ 0x3f ] = KEY_RESERVED, // system select
-#endif
+ /* Keys 0 to 9 */
+ [ 0x00 ] = KEY_KP0,
+ [ 0x01 ] = KEY_KP1,
+ [ 0x02 ] = KEY_KP2,
+ [ 0x03 ] = KEY_KP3,
+ [ 0x04 ] = KEY_KP4,
+ [ 0x05 ] = KEY_KP5,
+ [ 0x06 ] = KEY_KP6,
+ [ 0x07 ] = KEY_KP7,
+ [ 0x08 ] = KEY_KP8,
+ [ 0x09 ] = KEY_KP9,
+
+ [ 0x0b ] = KEY_CHANNEL, /* channel / program (japan: 11) */
+ [ 0x0c ] = KEY_POWER, /* standby */
+ [ 0x0d ] = KEY_MUTE, /* mute / demute */
+ [ 0x0f ] = KEY_TV, /* display */
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x12 ] = KEY_BRIGHTNESSUP,
+ [ 0x13 ] = KEY_BRIGHTNESSDOWN,
+ [ 0x1e ] = KEY_SEARCH, /* search + */
+ [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x22 ] = KEY_CHANNEL, /* alt / channel */
+ [ 0x23 ] = KEY_LANGUAGE, /* 1st / 2nd language */
+ [ 0x26 ] = KEY_SLEEP, /* sleeptimer */
+ [ 0x2e ] = KEY_MENU, /* 2nd controls (USA: menu) */
+ [ 0x30 ] = KEY_PAUSE,
+ [ 0x32 ] = KEY_REWIND,
+ [ 0x33 ] = KEY_GOTO,
+ [ 0x35 ] = KEY_PLAY,
+ [ 0x36 ] = KEY_STOP,
+ [ 0x37 ] = KEY_RECORD, /* recording */
+ [ 0x3c ] = KEY_TEXT, /* teletext submode (Japan: 12) */
+ [ 0x3d ] = KEY_SUSPEND, /* system standby */
+
};
EXPORT_SYMBOL_GPL(ir_codes_rc5_tv);
/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [ 18 ] = KEY_KP0,
[ 5 ] = KEY_KP1,
[ 6 ] = KEY_KP2,
[ 7 ] = KEY_KP3,
@@ -128,39 +98,31 @@ IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE] = {
[ 13 ] = KEY_KP7,
[ 14 ] = KEY_KP8,
[ 15 ] = KEY_KP9,
- [ 18 ] = KEY_KP0,
[ 0 ] = KEY_POWER,
- [ 27 ] = KEY_LANGUAGE, //MTS button
- [ 2 ] = KEY_TUNER, // TV/FM
+ [ 2 ] = KEY_TUNER, /* TV/FM */
[ 30 ] = KEY_VIDEO,
- [ 22 ] = KEY_INFO, //display button
[ 4 ] = KEY_VOLUMEUP,
[ 8 ] = KEY_VOLUMEDOWN,
[ 12 ] = KEY_CHANNELUP,
[ 16 ] = KEY_CHANNELDOWN,
- [ 3 ] = KEY_ZOOM, // fullscreen
- [ 31 ] = KEY_SUBTITLE, // closed caption/teletext
+ [ 3 ] = KEY_ZOOM, /* fullscreen */
+ [ 31 ] = KEY_SUBTITLE, /* closed caption/teletext */
[ 32 ] = KEY_SLEEP,
- [ 41 ] = KEY_SEARCH, //boss key
[ 20 ] = KEY_MUTE,
[ 43 ] = KEY_RED,
[ 44 ] = KEY_GREEN,
[ 45 ] = KEY_YELLOW,
[ 46 ] = KEY_BLUE,
- [ 24 ] = KEY_KPPLUS, //fine tune +
- [ 25 ] = KEY_KPMINUS, //fine tune -
- [ 42 ] = KEY_ANGLE, //picture in picture
- [ 33 ] = KEY_KPDOT,
+ [ 24 ] = KEY_KPPLUS, /* fine tune + */
+ [ 25 ] = KEY_KPMINUS, /* fine tune - */
+ [ 33 ] = KEY_KPDOT,
[ 19 ] = KEY_KPENTER,
- [ 17 ] = KEY_AGAIN, //recall
[ 34 ] = KEY_BACK,
[ 35 ] = KEY_PLAYPAUSE,
[ 36 ] = KEY_NEXT,
- [ 37 ] = KEY_T, //time shifting
[ 38 ] = KEY_STOP,
- [ 39 ] = KEY_RECORD,
- [ 40 ] = KEY_SHUFFLE //snapshot
+ [ 39 ] = KEY_RECORD
};
EXPORT_SYMBOL_GPL(ir_codes_winfast);
@@ -174,45 +136,97 @@ EXPORT_SYMBOL_GPL(ir_codes_empty);
* slightly different versions), shipped with cx88+ivtv cards.
* almost rc5 coding, but some non-standard keys */
IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_KP0, // 0
- [ 0x01 ] = KEY_KP1, // 1
- [ 0x02 ] = KEY_KP2, // 2
- [ 0x03 ] = KEY_KP3, // 3
- [ 0x04 ] = KEY_KP4, // 4
- [ 0x05 ] = KEY_KP5, // 5
- [ 0x06 ] = KEY_KP6, // 6
- [ 0x07 ] = KEY_KP7, // 7
- [ 0x08 ] = KEY_KP8, // 8
- [ 0x09 ] = KEY_KP9, // 9
- [ 0x0b ] = KEY_RED, // red button
- [ 0x0c ] = KEY_OPTION, // black key without text
- [ 0x0d ] = KEY_MENU, // menu
- [ 0x0f ] = KEY_MUTE, // mute
- [ 0x10 ] = KEY_VOLUMEUP, // volume +
- [ 0x11 ] = KEY_VOLUMEDOWN, // volume -
- [ 0x1e ] = KEY_NEXT, // skip >|
- [ 0x1f ] = KEY_EXIT, // back/exit
- [ 0x20 ] = KEY_CHANNELUP, // channel / program +
- [ 0x21 ] = KEY_CHANNELDOWN, // channel / program -
- [ 0x22 ] = KEY_CHANNEL, // source (old black remote)
- [ 0x24 ] = KEY_PREVIOUS, // replay |<
- [ 0x25 ] = KEY_ENTER, // OK
- [ 0x26 ] = KEY_SLEEP, // minimize (old black remote)
- [ 0x29 ] = KEY_BLUE, // blue key
- [ 0x2e ] = KEY_GREEN, // green button
- [ 0x30 ] = KEY_PAUSE, // pause
- [ 0x32 ] = KEY_REWIND, // backward <<
- [ 0x34 ] = KEY_FASTFORWARD, // forward >>
- [ 0x35 ] = KEY_PLAY, // play
- [ 0x36 ] = KEY_STOP, // stop
- [ 0x37 ] = KEY_RECORD, // recording
- [ 0x38 ] = KEY_YELLOW, // yellow key
- [ 0x3b ] = KEY_SELECT, // top right button
- [ 0x3c ] = KEY_ZOOM, // full
- [ 0x3d ] = KEY_POWER, // system power (green button)
+ /* Keys 0 to 9 */
+ [ 0x00 ] = KEY_KP0,
+ [ 0x01 ] = KEY_KP1,
+ [ 0x02 ] = KEY_KP2,
+ [ 0x03 ] = KEY_KP3,
+ [ 0x04 ] = KEY_KP4,
+ [ 0x05 ] = KEY_KP5,
+ [ 0x06 ] = KEY_KP6,
+ [ 0x07 ] = KEY_KP7,
+ [ 0x08 ] = KEY_KP8,
+ [ 0x09 ] = KEY_KP9,
+
+ [ 0x0a ] = KEY_TEXT, /* keypad asterisk as well */
+ [ 0x0b ] = KEY_RED, /* red button */
+ [ 0x0c ] = KEY_RADIO,
+ [ 0x0d ] = KEY_MENU,
+ [ 0x0e ] = KEY_SUBTITLE, /* also the # key */
+ [ 0x0f ] = KEY_MUTE,
+ [ 0x10 ] = KEY_VOLUMEUP,
+ [ 0x11 ] = KEY_VOLUMEDOWN,
+ [ 0x12 ] = KEY_PREVIOUS, /* previous channel */
+ [ 0x14 ] = KEY_UP,
+ [ 0x15 ] = KEY_DOWN,
+ [ 0x16 ] = KEY_LEFT,
+ [ 0x17 ] = KEY_RIGHT,
+ [ 0x18 ] = KEY_VIDEO, /* Videos */
+ [ 0x19 ] = KEY_AUDIO, /* Music */
+ /* 0x1a: Pictures - presume this means
+ "Multimedia Home Platform" -
+ no "PICTURES" key in input.h
+ */
+ [ 0x1a ] = KEY_MHP,
+
+ [ 0x1b ] = KEY_EPG, /* Guide */
+ [ 0x1c ] = KEY_TV,
+ [ 0x1e ] = KEY_NEXTSONG, /* skip >| */
+ [ 0x1f ] = KEY_EXIT, /* back/exit */
+ [ 0x20 ] = KEY_CHANNELUP, /* channel / program + */
+ [ 0x21 ] = KEY_CHANNELDOWN, /* channel / program - */
+ [ 0x22 ] = KEY_CHANNEL, /* source (old black remote) */
+ [ 0x24 ] = KEY_PREVIOUSSONG, /* replay |< */
+ [ 0x25 ] = KEY_ENTER, /* OK */
+ [ 0x26 ] = KEY_SLEEP, /* minimize (old black remote) */
+ [ 0x29 ] = KEY_BLUE, /* blue key */
+ [ 0x2e ] = KEY_GREEN, /* green button */
+ [ 0x30 ] = KEY_PAUSE, /* pause */
+ [ 0x32 ] = KEY_REWIND, /* backward << */
+ [ 0x34 ] = KEY_FASTFORWARD, /* forward >> */
+ [ 0x35 ] = KEY_PLAY,
+ [ 0x36 ] = KEY_STOP,
+ [ 0x37 ] = KEY_RECORD, /* recording */
+ [ 0x38 ] = KEY_YELLOW, /* yellow key */
+ [ 0x3b ] = KEY_SELECT, /* top right button */
+ [ 0x3c ] = KEY_ZOOM, /* full */
+ [ 0x3d ] = KEY_POWER, /* system power (green button) */
};
EXPORT_SYMBOL(ir_codes_hauppauge_new);
+IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
+ [ 2 ] = KEY_KP0,
+ [ 1 ] = KEY_KP1,
+ [ 11 ] = KEY_KP2,
+ [ 27 ] = KEY_KP3,
+ [ 5 ] = KEY_KP4,
+ [ 9 ] = KEY_KP5,
+ [ 21 ] = KEY_KP6,
+ [ 6 ] = KEY_KP7,
+ [ 10 ] = KEY_KP8,
+ [ 18 ] = KEY_KP9,
+
+ [ 3 ] = KEY_TUNER, /* TV/FM */
+ [ 7 ] = KEY_SEARCH, /* scan */
+ [ 28 ] = KEY_ZOOM, /* full screen */
+ [ 30 ] = KEY_POWER,
+ [ 23 ] = KEY_VOLUMEDOWN,
+ [ 31 ] = KEY_VOLUMEUP,
+ [ 20 ] = KEY_CHANNELDOWN,
+ [ 22 ] = KEY_CHANNELUP,
+ [ 24 ] = KEY_MUTE,
+
+ [ 0 ] = KEY_LIST, /* source */
+ [ 19 ] = KEY_INFO, /* loop */
+ [ 16 ] = KEY_LAST, /* +100 */
+ [ 13 ] = KEY_CLEAR, /* reset */
+ [ 12 ] = BTN_RIGHT, /* fun++ */
+ [ 4 ] = BTN_LEFT, /* fun-- */
+ [ 14 ] = KEY_GOTO, /* function */
+ [ 15 ] = KEY_STOP, /* freeze */
+};
+EXPORT_SYMBOL(ir_codes_pixelview);
+
/* -------------------------------------------------------------------------- */
static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
@@ -276,10 +290,6 @@ void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
ir->keypressed = 1;
ir_input_key_event(dev,ir);
}
-#if 0
- /* maybe do something like this ??? */
- input_event(a, EV_IR, ir->ir_type, ir->ir_raw);
-#endif
}
/* -------------------------------------------------------------------------- */
@@ -379,3 +389,4 @@ EXPORT_SYMBOL_GPL(ir_decode_biphase);
* c-basic-offset: 8
* End:
*/
+
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 50e8b8654018..cd5828b5e9e3 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -62,13 +62,15 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data)
int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
{
unsigned long start;
+ int err;
/* wait for registers to be programmed */
start = jiffies;
while (1) {
- if (saa7146_read(dev, MC2) & 2)
- break;
- if (time_after(jiffies, start + HZ/20)) {
+ err = time_after(jiffies, start + HZ/20);
+ if (saa7146_read(dev, MC2) & 2)
+ break;
+ if (err) {
DEB_S(("timed out while waiting for registers getting programmed\n"));
return -ETIMEDOUT;
}
@@ -79,10 +81,11 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop)
/* wait for transfer to complete */
start = jiffies;
while (1) {
+ err = time_after(jiffies, start + HZ/4);
if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S))
break;
saa7146_read(dev, MC2);
- if (time_after(jiffies, start + HZ/4)) {
+ if (err) {
DEB_S(("timed out while waiting for transfer completion\n"));
return -ETIMEDOUT;
}
@@ -512,7 +515,7 @@ int saa7146_register_extension(struct saa7146_extension* ext)
ext->driver.remove = saa7146_remove_one;
printk("saa7146: register extension '%s'.\n",ext->name);
- return pci_module_init(&ext->driver);
+ return pci_register_driver(&ext->driver);
}
int saa7146_unregister_extension(struct saa7146_extension* ext)
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index cb826c9adfe7..c04fd11526e0 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -403,7 +403,7 @@ static struct file_operations video_fops =
.llseek = no_llseek,
};
-void vv_callback(struct saa7146_dev *dev, unsigned long status)
+static void vv_callback(struct saa7146_dev *dev, unsigned long status)
{
u32 isr = status;
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig
index 4983e1b1bb1d..3f0ec6be03ae 100644
--- a/drivers/media/dvb/Kconfig
+++ b/drivers/media/dvb/Kconfig
@@ -27,9 +27,9 @@ source "drivers/media/dvb/ttpci/Kconfig"
comment "Supported USB Adapters"
depends on DVB_CORE && USB
+source "drivers/media/dvb/dvb-usb/Kconfig"
source "drivers/media/dvb/ttusb-budget/Kconfig"
source "drivers/media/dvb/ttusb-dec/Kconfig"
-source "drivers/media/dvb/dibusb/Kconfig"
source "drivers/media/dvb/cinergyT2/Kconfig"
comment "Supported FlexCopII (B2C2) Adapters"
@@ -40,6 +40,10 @@ comment "Supported BT878 Adapters"
depends on DVB_CORE && PCI
source "drivers/media/dvb/bt8xx/Kconfig"
+comment "Supported Pluto2 Adapters"
+ depends on DVB_CORE && PCI
+source "drivers/media/dvb/pluto2/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile
index 520fc3902819..a7ad0841e6fc 100644
--- a/drivers/media/dvb/Makefile
+++ b/drivers/media/dvb/Makefile
@@ -2,4 +2,4 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dibusb/ cinergyT2/
+obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ cinergyT2/ dvb-usb/ pluto2/
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 99bd675df955..d7417eac2aba 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -6,6 +6,7 @@ config DVB_B2C2_FLEXCOP
select DVB_MT312
select DVB_NXT2002
select DVB_STV0297
+ select DVB_BCM3510
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.
@@ -34,17 +35,3 @@ config DVB_B2C2_FLEXCOP_DEBUG
help
Say Y if you want to enable the module option to control debug messages
of all B2C2 FlexCop drivers.
-
-config DVB_B2C2_SKYSTAR
- tristate "B2C2/Technisat Air/Sky/CableStar 2 PCI"
- depends on DVB_CORE && PCI
- select DVB_STV0299
- select DVB_MT352
- select DVB_MT312
- select DVB_NXT2002
- help
- Support for the Skystar2 PCI DVB card by Technisat, which
- is equipped with the FlexCopII chipset by B2C2, and
- for the B2C2/BBTI Air2PC-ATSC card.
-
- Say Y if you own such a device and want to use it.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index 7703812af34f..1a1c3bca55fa 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -9,6 +9,4 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
-obj-$(CONFIG_DVB_B2C2_SKYSTAR) += skystar2.o
-
EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 773d158032df..a94912ac1872 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -108,6 +108,8 @@ void flexcop_device_kfree(struct flexcop_device*);
int flexcop_device_initialize(struct flexcop_device*);
void flexcop_device_exit(struct flexcop_device *fc);
+void flexcop_reset_block_300(struct flexcop_device *fc);
+
/* from flexcop-dma.c */
int flexcop_dma_allocate(struct pci_dev *pdev, struct flexcop_dma *dma, u32 size);
void flexcop_dma_free(struct flexcop_dma *dma);
@@ -115,7 +117,8 @@ void flexcop_dma_free(struct flexcop_dma *dma);
int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index);
+int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx);
+int flexcop_dma_xfer_control(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index, int onoff);
int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles);
int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets);
@@ -151,6 +154,7 @@ int flexcop_sram_init(struct flexcop_device *fc);
/* from flexcop-misc.c */
void flexcop_determine_revision(struct flexcop_device *fc);
void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const char *suffix);
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num);
/* from flexcop-hw-filter.c */
int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *dvbdmxfeed, int onoff);
diff --git a/drivers/media/dvb/b2c2/flexcop-dma.c b/drivers/media/dvb/b2c2/flexcop-dma.c
index 8d2706075360..cf4ed1df6086 100644
--- a/drivers/media/dvb/b2c2/flexcop-dma.c
+++ b/drivers/media/dvb/b2c2/flexcop-dma.c
@@ -37,22 +37,90 @@ void flexcop_dma_free(struct flexcop_dma *dma)
}
EXPORT_SYMBOL(flexcop_dma_free);
-int flexcop_dma_control_timer_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_config(struct flexcop_device *fc,
+ struct flexcop_dma *dma,
+ flexcop_dma_index_t dma_idx)
{
- flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
+ flexcop_ibi_value v0x0,v0x4,v0xc;
+ v0x0.raw = v0x4.raw = v0xc.raw = 0;
- if (no & FC_DMA_1)
- v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
+ v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
+ v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
+ v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
- if (no & FC_DMA_2)
- v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
+ if ((dma_idx & FC_DMA_1) == dma_idx) {
+ fc->write_ibi_reg(fc,dma1_000,v0x0);
+ fc->write_ibi_reg(fc,dma1_004,v0x4);
+ fc->write_ibi_reg(fc,dma1_00c,v0xc);
+ } else if ((dma_idx & FC_DMA_2) == dma_idx) {
+ fc->write_ibi_reg(fc,dma2_010,v0x0);
+ fc->write_ibi_reg(fc,dma2_014,v0x4);
+ fc->write_ibi_reg(fc,dma2_01c,v0xc);
+ } else {
+ err("either DMA1 or DMA2 can be configured at the within one flexcop_dma_config call.");
+ return -EINVAL;
+ }
- fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
+EXPORT_SYMBOL(flexcop_dma_config);
+
+/* start the DMA transfers, but not the DMA IRQs */
+int flexcop_dma_xfer_control(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ flexcop_dma_addr_index_t index,
+ int onoff)
+{
+ flexcop_ibi_value v0x0,v0xc;
+ flexcop_ibi_register r0x0,r0xc;
+
+ if ((dma_idx & FC_DMA_1) == dma_idx) {
+ r0x0 = dma1_000;
+ r0xc = dma1_00c;
+ } else if ((dma_idx & FC_DMA_2) == dma_idx) {
+ r0x0 = dma2_010;
+ r0xc = dma2_01c;
+ } else {
+ err("either transfer DMA1 or DMA2 can be started within one flexcop_dma_xfer_control call.");
+ return -EINVAL;
+ }
+
+ v0x0 = fc->read_ibi_reg(fc,r0x0);
+ v0xc = fc->read_ibi_reg(fc,r0xc);
+
+ deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+ deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+
+ if (index & FC_DMA_SUBADDR_0)
+ v0x0.dma_0x0.dma_0start = onoff;
+
+ if (index & FC_DMA_SUBADDR_1)
+ v0xc.dma_0xc.dma_1start = onoff;
+
+ fc->write_ibi_reg(fc,r0x0,v0x0);
+ fc->write_ibi_reg(fc,r0xc,v0xc);
+
+ deb_rdump("reg: %03x: %x\n",r0x0,v0x0.raw);
+ deb_rdump("reg: %03x: %x\n",r0xc,v0xc.raw);
+ return 0;
+}
+EXPORT_SYMBOL(flexcop_dma_xfer_control);
+
+static int flexcop_dma_remap(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ int onoff)
+{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ deb_info("%s\n",__FUNCTION__);
+ v.dma_0xc.remap_enable = onoff;
+ fc->write_ibi_reg(fc,r,v);
+ return 0;
+}
-int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_control_size_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
@@ -67,75 +135,64 @@ int flexcop_dma_control_size_irq(struct flexcop_device *fc, flexcop_dma_index_t
}
EXPORT_SYMBOL(flexcop_dma_control_size_irq);
-int flexcop_dma_control_packet_irq(struct flexcop_device *fc, flexcop_dma_index_t no, int onoff)
+int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
if (no & FC_DMA_1)
- v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+ v.ctrl_208.DMA1_Timer_Enable_sig = onoff;
if (no & FC_DMA_2)
- v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+ v.ctrl_208.DMA2_Timer_Enable_sig = onoff;
fc->write_ibi_reg(fc,ctrl_208,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
+EXPORT_SYMBOL(flexcop_dma_control_timer_irq);
-int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma, flexcop_dma_index_t dma_idx,flexcop_dma_addr_index_t index)
+/* 1 cycles = 1.97 msec */
+int flexcop_dma_config_timer(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ u8 cycles)
{
+ flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
- flexcop_ibi_value v0x0,v0x4,v0xc;
- v0x0.raw = v0x4.raw = v0xc.raw = 0;
-
- v0x0.dma_0x0.dma_address0 = dma->dma_addr0 >> 2;
- v0xc.dma_0xc.dma_address1 = dma->dma_addr1 >> 2;
- v0x4.dma_0x4_write.dma_addr_size = dma->size / 4;
-
- if (index & FC_DMA_SUBADDR_0)
- v0x0.dma_0x0.dma_0start = 1;
-
- if (index & FC_DMA_SUBADDR_1)
- v0xc.dma_0xc.dma_1start = 1;
-
- if (dma_idx & FC_DMA_1) {
- fc->write_ibi_reg(fc,dma1_000,v0x0);
- fc->write_ibi_reg(fc,dma1_004,v0x4);
- fc->write_ibi_reg(fc,dma1_00c,v0xc);
- } else { /* (dma_idx & FC_DMA_2) */
- fc->write_ibi_reg(fc,dma2_010,v0x0);
- fc->write_ibi_reg(fc,dma2_014,v0x4);
- fc->write_ibi_reg(fc,dma2_01c,v0xc);
- }
-
- return 0;
-}
-EXPORT_SYMBOL(flexcop_dma_config);
+ flexcop_dma_remap(fc,dma_idx,0);
-static int flexcop_dma_remap(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, int onoff)
-{
- flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_00c : dma2_01c;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
- v.dma_0xc.remap_enable = onoff;
+ deb_info("%s\n",__FUNCTION__);
+ v.dma_0x4_write.dmatimer = cycles;
fc->write_ibi_reg(fc,r,v);
return 0;
}
+EXPORT_SYMBOL(flexcop_dma_config_timer);
-/* 1 cycles = 1.97 msec */
-int flexcop_dma_config_timer(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 cycles)
+/* packet IRQ does not exist in FCII or FCIIb - according to data book and tests */
+int flexcop_dma_control_packet_irq(struct flexcop_device *fc,
+ flexcop_dma_index_t no,
+ int onoff)
{
- flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,ctrl_208);
- flexcop_dma_remap(fc,dma_idx,0);
+ deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
+ if (no & FC_DMA_1)
+ v.ctrl_208.DMA1_Size_IRQ_Enable_sig = onoff;
+
+ if (no & FC_DMA_2)
+ v.ctrl_208.DMA2_Size_IRQ_Enable_sig = onoff;
+
+ fc->write_ibi_reg(fc,ctrl_208,v);
+ deb_rdump("reg: %03x: %x\n",ctrl_208,v.raw);
- v.dma_0x4_write.dmatimer = cycles >> 1;
- fc->write_ibi_reg(fc,r,v);
return 0;
}
-EXPORT_SYMBOL(flexcop_dma_config_timer);
+EXPORT_SYMBOL(flexcop_dma_control_packet_irq);
-int flexcop_dma_config_packet_count(struct flexcop_device *fc, flexcop_dma_index_t dma_idx, u8 packets)
+int flexcop_dma_config_packet_count(struct flexcop_device *fc,
+ flexcop_dma_index_t dma_idx,
+ u8 packets)
{
flexcop_ibi_register r = (dma_idx & FC_DMA_1) ? dma1_004 : dma2_014;
flexcop_ibi_value v = fc->read_ibi_reg(fc,r);
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 71be400e9aeb..0410cc96a48e 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -10,6 +10,7 @@
#include "stv0299.h"
#include "mt352.h"
#include "nxt2002.h"
+#include "bcm3510.h"
#include "stv0297.h"
#include "mt312.h"
@@ -285,21 +286,25 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front
}
static struct mt352_config samsung_tdtc9251dh0_config = {
-
.demod_address = 0x0f,
- .demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
+ .demod_init = samsung_tdtc9251dh0_demod_init,
+ .pll_set = samsung_tdtc9251dh0_pll_set,
};
-static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
struct flexcop_device *fc = fe->dvb->priv;
return request_firmware(fw, name, fc->dev);
}
static struct nxt2002_config samsung_tbmv_config = {
- .demod_address = 0x0a,
- .request_firmware = nxt2002_request_firmware,
+ .demod_address = 0x0a,
+ .request_firmware = flexcop_fe_request_firmware,
+};
+
+static struct bcm3510_config air2pc_atsc_first_gen_config = {
+ .demod_address = 0x0f,
+ .request_firmware = flexcop_fe_request_firmware,
};
static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
@@ -354,11 +359,16 @@ int flexcop_frontend_init(struct flexcop_device *fc)
fc->dev_type = FC_AIR_DVB;
info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
} else
- /* try the air atsc (nxt2002) */
+ /* try the air atsc 2nd generation (nxt2002) */
if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
- fc->dev_type = FC_AIR_ATSC;
+ fc->dev_type = FC_AIR_ATSC2;
info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
} else
+ /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
+ if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
+ fc->dev_type = FC_AIR_ATSC1;
+ info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
+ } else
/* try the cable dvb (stv0297) */
if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
fc->dev_type = FC_CABLE;
diff --git a/drivers/media/dvb/b2c2/flexcop-hw-filter.c b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
index 2baf43d3ce8f..75cf237196eb 100644
--- a/drivers/media/dvb/b2c2/flexcop-hw-filter.c
+++ b/drivers/media/dvb/b2c2/flexcop-hw-filter.c
@@ -10,6 +10,8 @@
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208,Rcv_Data_sig,onoff);
+
+ deb_ts("rcv_data is now: '%s'\n",onoff ? "on" : "off");
}
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
@@ -151,7 +153,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
{
int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
- fc->feedcount += onoff ? 1 : -1;
+ fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
if (dvbdmxfeed->index >= max_pid_filter)
fc->extra_feedcount += onoff ? 1 : -1;
@@ -178,8 +180,14 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
/* if it was the first or last feed request change the stream-status */
if (fc->feedcount == onoff) {
flexcop_rcv_data_ctrl(fc,onoff);
- if (fc->stream_control)
+ if (fc->stream_control) /* device specific stream control */
fc->stream_control(fc,onoff);
+
+ /* feeding stopped -> reset the flexcop filter*/
+ if (onoff == 0) {
+ flexcop_reset_block_300(fc);
+ flexcop_hw_filter_init(fc);
+ }
}
return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-misc.c b/drivers/media/dvb/b2c2/flexcop-misc.c
index 19e06da46774..3a08d38b318a 100644
--- a/drivers/media/dvb/b2c2/flexcop-misc.c
+++ b/drivers/media/dvb/b2c2/flexcop-misc.c
@@ -45,11 +45,12 @@ const char *flexcop_revision_names[] = {
const char *flexcop_device_names[] = {
"Unkown device",
- "AirStar 2 DVB-T",
- "AirStar 2 ATSC",
- "SkyStar 2 DVB-S",
- "SkyStar 2 DVB-S (old version)",
- "CableStar 2 DVB-C",
+ "Air2PC/AirStar 2 DVB-T",
+ "Air2PC/AirStar 2 ATSC 1st generation",
+ "Air2PC/AirStar 2 ATSC 2nd generation",
+ "Sky2PC/SkyStar 2 DVB-S",
+ "Sky2PC/SkyStar 2 DVB-S (old version)",
+ "Cable2PC/CableStar 2 DVB-C",
};
const char *flexcop_bus_names[] = {
@@ -64,3 +65,15 @@ void flexcop_device_name(struct flexcop_device *fc,const char *prefix,const
flexcop_device_names[fc->dev_type],flexcop_bus_names[fc->bus_type],
flexcop_revision_names[fc->rev],suffix);
}
+
+void flexcop_dump_reg(struct flexcop_device *fc, flexcop_ibi_register reg, int num)
+{
+ flexcop_ibi_value v;
+ int i;
+ for (i = 0; i < num; i++) {
+ v = fc->read_ibi_reg(fc,reg+4*i);
+ deb_rdump("0x%03x: %08x, ",reg+4*i, v.raw);
+ }
+ deb_rdump("\n");
+}
+EXPORT_SYMBOL(flexcop_dump_reg);
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index ed717c0073d5..2f76eb3fea40 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -13,6 +13,10 @@ static int enable_pid_filtering = 1;
module_param(enable_pid_filtering, int, 0444);
MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
+static int irq_chk_intv;
+module_param(irq_chk_intv, int, 0644);
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
+
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) printk(args); } while (0)
@@ -26,6 +30,7 @@ MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported
#define deb_reg(args...) dprintk(0x02,args)
#define deb_ts(args...) dprintk(0x04,args)
#define deb_irq(args...) dprintk(0x08,args)
+#define deb_chk(args...) dprintk(0x10,args)
static int debug = 0;
module_param(debug, int, 0644);
@@ -56,6 +61,10 @@ struct flexcop_pci {
spinlock_t irq_lock;
+ unsigned long last_irq;
+
+ struct work_struct irq_check_work;
+
struct flexcop_device *fc_dev;
};
@@ -88,18 +97,55 @@ static int flexcop_pci_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi
return 0;
}
+static void flexcop_pci_irq_check_work(void *data)
+{
+ struct flexcop_pci *fc_pci = data;
+ struct flexcop_device *fc = fc_pci->fc_dev;
+
+ flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
+
+ flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
+
+ if (v.sram_dest_reg_714.net_ovflow_error)
+ deb_chk("sram net_ovflow_error\n");
+ if (v.sram_dest_reg_714.media_ovflow_error)
+ deb_chk("sram media_ovflow_error\n");
+ if (v.sram_dest_reg_714.cai_ovflow_error)
+ deb_chk("sram cai_ovflow_error\n");
+ if (v.sram_dest_reg_714.cai_ovflow_error)
+ deb_chk("sram cai_ovflow_error\n");
+
+ schedule_delayed_work(&fc_pci->irq_check_work,
+ msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+}
+
/* When PID filtering is turned on, we use the timer IRQ, because small amounts
* of data need to be passed to the user space instantly as well. When PID
* filtering is turned off, we use the page-change-IRQ */
-static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t flexcop_pci_isr(int irq, void *dev_id, struct pt_regs *regs)
{
struct flexcop_pci *fc_pci = dev_id;
struct flexcop_device *fc = fc_pci->fc_dev;
- flexcop_ibi_value v = fc->read_ibi_reg(fc,irq_20c);
+ flexcop_ibi_value v;
irqreturn_t ret = IRQ_HANDLED;
spin_lock_irq(&fc_pci->irq_lock);
+ v = fc->read_ibi_reg(fc,irq_20c);
+
+ /* errors */
+ if (v.irq_20c.Data_receiver_error)
+ deb_chk("data receiver error\n");
+ if (v.irq_20c.Continuity_error_flag)
+ deb_chk("Contunuity error flag is set\n");
+ if (v.irq_20c.LLC_SNAP_FLAG_set)
+ deb_chk("LLC_SNAP_FLAG_set is set\n");
+ if (v.irq_20c.Transport_Error)
+ deb_chk("Transport error\n");
+
+ if ((fc_pci->count % 1000) == 0)
+ deb_chk("%d valid irq took place so far\n",fc_pci->count);
+
if (v.irq_20c.DMA1_IRQ_Status == 1) {
if (fc_pci->active_dma1_addr == 0)
flexcop_pass_dmx_packets(fc_pci->fc_dev,fc_pci->dma[0].cpu_addr0,fc_pci->dma[0].size / 188);
@@ -115,8 +161,9 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
fc->read_ibi_reg(fc,dma1_008).dma_0x8.dma_cur_addr << 2;
u32 cur_pos = cur_addr - fc_pci->dma[0].dma_addr0;
- deb_irq("irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
- v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+ deb_irq("%u irq: %08x cur_addr: %08x: cur_pos: %08x, last_cur_pos: %08x ",
+ jiffies_to_usecs(jiffies - fc_pci->last_irq),v.raw,cur_addr,cur_pos,fc_pci->last_dma1_cur_pos);
+ fc_pci->last_irq = jiffies;
/* buffer end was reached, restarted from the beginning
* pass the data from last_cur_pos to the buffer end to the demux
@@ -127,7 +174,6 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
fc_pci->dma[0].cpu_addr0 + fc_pci->last_dma1_cur_pos,
(fc_pci->dma[0].size*2) - fc_pci->last_dma1_cur_pos);
fc_pci->last_dma1_cur_pos = 0;
- fc_pci->count = 0;
}
if (cur_pos > fc_pci->last_dma1_cur_pos) {
@@ -139,16 +185,14 @@ static irqreturn_t flexcop_pci_irq(int irq, void *dev_id, struct pt_regs *regs)
deb_irq("\n");
fc_pci->last_dma1_cur_pos = cur_pos;
- } else
+ fc_pci->count++;
+ } else {
+ deb_irq("isr for flexcop called, apparently without reason (%08x)\n",v.raw);
ret = IRQ_NONE;
+ }
spin_unlock_irq(&fc_pci->irq_lock);
-/* packet count would be ideal for hw filtering, but it isn't working. Either
- * the data book is wrong, or I'm unable to read it correctly */
-
-/* if (v.irq_20c.DMA1_Size_IRQ_Status == 1) { packet counter */
-
return ret;
}
@@ -156,30 +200,35 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
{
struct flexcop_pci *fc_pci = fc->bus_specific;
if (onoff) {
- flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
- flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1);
- flexcop_dma_config_timer(fc,FC_DMA_1,1);
+ flexcop_dma_config(fc,&fc_pci->dma[0],FC_DMA_1);
+ flexcop_dma_config(fc,&fc_pci->dma[1],FC_DMA_2);
- if (fc_pci->fc_dev->pid_filtering) {
- fc_pci->last_dma1_cur_pos = 0;
- flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
- } else {
- fc_pci->active_dma1_addr = 0;
- flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
- }
+ flexcop_dma_config_timer(fc,FC_DMA_1,0);
-/* flexcop_dma_config_packet_count(fc,FC_DMA_1,0xc0);
- flexcop_dma_control_packet_irq(fc,FC_DMA_1,1); */
+ flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,1);
+ deb_irq("DMA xfer enabled\n");
- deb_irq("irqs enabled\n");
+ fc_pci->last_dma1_cur_pos = 0;
+ flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
+ deb_irq("IRQ enabled\n");
+
+// fc_pci->active_dma1_addr = 0;
+// flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
+
+ if (irq_chk_intv > 0)
+ schedule_delayed_work(&fc_pci->irq_check_work,
+ msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
} else {
- if (fc_pci->fc_dev->pid_filtering)
- flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
- else
- flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+ if (irq_chk_intv > 0)
+ cancel_delayed_work(&fc_pci->irq_check_work);
+
+ flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
+ deb_irq("IRQ disabled\n");
-// flexcop_dma_control_packet_irq(fc,FC_DMA_1,0);
- deb_irq("irqs disabled\n");
+// flexcop_dma_control_size_irq(fc,FC_DMA_1,0);
+
+ flexcop_dma_xfer_control(fc,FC_DMA_1,FC_DMA_SUBADDR_0 | FC_DMA_SUBADDR_1,0);
+ deb_irq("DMA xfer disabled\n");
}
return 0;
@@ -198,6 +247,7 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci)
flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2);
fc_pci->init_state |= FC_PCI_DMA_INIT;
+
goto success;
dma1_free:
flexcop_dma_free(&fc_pci->dma[0]);
@@ -244,7 +294,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
pci_set_drvdata(fc_pci->pdev, fc_pci);
- if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_irq,
+ if ((ret = request_irq(fc_pci->pdev->irq, flexcop_pci_isr,
SA_SHIRQ, DRIVER_NAME, fc_pci)) != 0)
goto err_pci_iounmap;
@@ -324,6 +374,8 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
if ((ret = flexcop_pci_dma_init(fc_pci)) != 0)
goto err_fc_exit;
+ INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci);
+
goto success;
err_fc_exit:
flexcop_device_exit(fc);
@@ -350,17 +402,17 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
static struct pci_device_id flexcop_pci_tbl[] = {
{ PCI_DEVICE(0x13d0, 0x2103) },
-/* { PCI_DEVICE(0x13d0, 0x2200) }, PCI FlexCopIII ? */
+/* { PCI_DEVICE(0x13d0, 0x2200) }, ? */
{ },
};
MODULE_DEVICE_TABLE(pci, flexcop_pci_tbl);
static struct pci_driver flexcop_pci_driver = {
- .name = "Technisat/B2C2 FlexCop II/IIb/III PCI",
+ .name = "b2c2_flexcop_pci",
.id_table = flexcop_pci_tbl,
- .probe = flexcop_pci_probe,
- .remove = flexcop_pci_remove,
+ .probe = flexcop_pci_probe,
+ .remove = flexcop_pci_remove,
};
static int __init flexcop_pci_module_init(void)
diff --git a/drivers/media/dvb/b2c2/flexcop-reg.h b/drivers/media/dvb/b2c2/flexcop-reg.h
index 5e131be55cb3..4ae1eb5bfe98 100644
--- a/drivers/media/dvb/b2c2/flexcop-reg.h
+++ b/drivers/media/dvb/b2c2/flexcop-reg.h
@@ -21,7 +21,8 @@ extern const char *flexcop_revision_names[];
typedef enum {
FC_UNK = 0,
FC_AIR_DVB,
- FC_AIR_ATSC,
+ FC_AIR_ATSC1,
+ FC_AIR_ATSC2,
FC_SKY,
FC_SKY_OLD,
FC_CABLE,
@@ -35,555 +36,21 @@ typedef enum {
extern const char *flexcop_device_names[];
/* FlexCop IBI Registers */
+#if defined(__LITTLE_ENDIAN)
+ #include "flexcop_ibi_value_le.h"
+#elif defined(__BIG_ENDIAN)
+ #include "flexcop_ibi_value_be.h"
+#else
+ #error no endian defined
+#endif
-/* flexcop_ibi_reg - a huge union representing the register structure */
-typedef union {
- u32 raw;
-
-/* DMA 0x000 to 0x01c
- * DMA1 0x000 to 0x00c
- * DMA2 0x010 to 0x01c
- */
- struct {
- u32 dma_0start : 1; /* set: data will be delivered to dma1_address0 */
- u32 dma_0No_update : 1; /* set: dma1_cur_address will be updated, unset: no update */
- u32 dma_address0 :30; /* physical/virtual host memory address0 DMA */
- } dma_0x0;
-
- struct {
- u32 DMA_maxpackets : 8; /* (remapped) PCI DMA1 Packet Count Interrupt. This variable
- is able to be read and written while bit(1) of register
- 0x00c (remap_enable) is set. This variable represents
- the number of packets that will be transmitted to the PCI
- host using PCI DMA1 before an interrupt to the PCI is
- asserted. This functionality may be enabled using bit(20)
- of register 0x208. N=0 disables the IRQ. */
- u32 dma_addr_size :24; /* size of memory buffer in DWORDs (bytesize / 4) for DMA */
- } dma_0x4_remap;
-
- struct {
- u32 dma1timer : 7; /* reading PCI DMA1 timer ... when remap_enable is 0 */
- u32 unused : 1;
- u32 dma_addr_size :24;
- } dma_0x4_read;
-
- struct {
- u32 unused : 1;
- u32 dmatimer : 7; /* writing PCI DMA1 timer ... when remap_enable is 0 */
- u32 dma_addr_size :24;
- } dma_0x4_write;
-
- struct {
- u32 unused : 2;
- u32 dma_cur_addr :30; /* current physical host memory address pointer for DMA */
- } dma_0x8;
-
- struct {
- u32 dma_1start : 1; /* set: data will be delivered to dma_address1, when dma_address0 is full */
- u32 remap_enable : 1; /* remap enable for 0x0x4(7:0) */
- u32 dma_address1 :30; /* Physical/virtual address 1 on DMA */
- } dma_0xc;
-
-/* Two-wire Serial Master and Clock 0x100-0x110 */
- struct {
-// u32 slave_transmitter : 1; /* ???*/
- u32 chipaddr : 7; /* two-line serial address of the target slave */
- u32 reserved1 : 1;
- u32 baseaddr : 8; /* address of the location of the read/write operation */
- u32 data1_reg : 8; /* first byte in two-line serial read/write operation */
- u32 working_start : 1; /* when doing a write operation this indicator is 0 when ready
- * set to 1 when doing a write operation */
- u32 twoWS_rw : 1; /* read/write indicator (1 = read, 0 write) */
- u32 total_bytes : 2; /* number of data bytes in each two-line serial transaction (0 = 1 byte, 11 = 4byte)*/
- u32 twoWS_port_reg : 2; /* port selection: 01 - Front End/Demod, 10 - EEPROM, 11 - Tuner */
- u32 no_base_addr_ack_error : 1; /* writing: write-req: frame is produced w/o baseaddr, read-req: read-cycles w/o
- * preceding address assignment write frame
- * ACK_ERROR = 1 when no ACK from slave in the last transaction */
- u32 st_done : 1; /* indicator for transaction is done */
- } tw_sm_c_100;
-
- struct {
- u32 data2_reg : 8; /* 2nd data byte */
- u32 data3_reg : 8; /* 3rd data byte */
- u32 data4_reg : 8; /* 4th data byte */
- u32 exlicit_stops : 1; /* when set, transactions are produced w/o trailing STOP flag, then send isolated STOP flags */
- u32 force_stop : 1; /* isolated stop flag */
- u32 unused : 6;
- } tw_sm_c_104;
-
-/* Clock. The register allows the FCIII to convert an incoming Master clock
- * (MCLK) signal into a lower frequency clock through the use of a LowCounter
- * (TLO) and a High- Counter (THI). The time counts for THI and TLO are
- * measured in MCLK; each count represents 4 MCLK input clock cycles.
- *
- * The default output for port #1 is set for Front End Demod communication. (0x108)
- * The default output for port #2 is set for EEPROM communication. (0x10c)
- * The default output for port #3 is set for Tuner communication. (0x110)
- */
- struct {
- u32 thi1 : 6; /* Thi for port #1 (def: 100110b; 38) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #1 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_108;
-
- struct {
- u32 thi1 : 6; /* Thi for port #2 (def: 111001b; 57) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #2 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_10c;
-
- struct {
- u32 thi1 : 6; /* Thi for port #3 (def: 111001b; 57) */
- u32 reserved1 : 2;
- u32 tlo1 : 5; /* Tlo for port #3 (def: 11100b; 28) */
- u32 reserved2 :19;
- } tw_sm_c_110;
-
-/* LNB Switch Frequency 0x200
- * Clock that creates the LNB switch tone. The default is set to have a fixed
- * low output (not oscillating) to the LNB_CTL line.
- */
- struct {
- u32 LNB_CTLHighCount_sig :15; /* It is the number of pre-scaled clock cycles that will be low. */
- u32 LNB_CTLLowCount_sig :15; /* For example, to obtain a 22KHz output given a 45 Mhz Master
- Clock signal (MCLK), set PreScalar=01 and LowCounter value to 0x1ff. */
- u32 LNB_CTLPrescaler_sig : 2; /* pre-scaler divides MCLK: 00 (no division), 01 by 2, 10 by 4, 11 by 12 */
- } lnb_switch_freq_200;
-
-/* ACPI, Peripheral Reset, LNB Polarity
- * ACPI power conservation mode, LNB polarity selection (low or high voltage),
- * and peripheral reset.
- */
- struct {
- u32 ACPI1_sig : 1; /* turn of the power of tuner and LNB, not implemented in FCIII */
- u32 ACPI3_sig : 1; /* turn of power of the complete satelite receiver board (except FCIII) */
- u32 LNB_L_H_sig : 1; /* low or high voltage for LNB. (0 = low, 1 = high) */
- u32 Per_reset_sig : 1; /* misc. init reset (default: 1), to reset set to low and back to high */
- u32 reserved :20;
- u32 Rev_N_sig_revision_hi : 4;/* 0xc in case of FCIII */
- u32 Rev_N_sig_reserved1 : 2;
- u32 Rev_N_sig_caps : 1; /* if 1, FCIII has 32 PID- and MAC-filters and is capable of IP multicast */
- u32 Rev_N_sig_reserved2 : 1;
- } misc_204;
-
-/* Control and Status 0x208 to 0x21c */
-/* Gross enable and disable control */
- struct {
- u32 Stream1_filter_sig : 1; /* Stream1 PID filtering */
- u32 Stream2_filter_sig : 1; /* Stream2 PID filtering */
- u32 PCR_filter_sig : 1; /* PCR PID filter */
- u32 PMT_filter_sig : 1; /* PMT PID filter */
-
- u32 EMM_filter_sig : 1; /* EMM PID filter */
- u32 ECM_filter_sig : 1; /* ECM PID filter */
- u32 Null_filter_sig : 1; /* Filters null packets, PID=0x1fff. */
- u32 Mask_filter_sig : 1; /* mask PID filter */
-
- u32 WAN_Enable_sig : 1; /* WAN output line through V8 memory space is activated. */
- u32 WAN_CA_Enable_sig : 1; /* not in FCIII */
- u32 CA_Enable_sig : 1; /* not in FCIII */
- u32 SMC_Enable_sig : 1; /* CI stream data (CAI) goes directly to the smart card intf (opposed IBI 0x600 or SC-cmd buf). */
-
- u32 Per_CA_Enable_sig : 1; /* not in FCIII */
- u32 Multi2_Enable_sig : 1; /* ? */
- u32 MAC_filter_Mode_sig : 1; /* (MAC_filter_enable) Globally enables MAC filters for Net PID filteres. */
- u32 Rcv_Data_sig : 1; /* PID filtering module enable. When this bit is a one, the PID filter will
- examine and process packets according to all other (individual) PID
- filtering controls. If it a zero, no packet processing of any kind will
- take place. All data from the tuner will be thrown away. */
-
- u32 DMA1_IRQ_Enable_sig : 1; /* When set, a DWORD counter is enabled on PCI DMA1 that asserts the PCI
- * interrupt after the specified count for filling the buffer. */
- u32 DMA1_Timer_Enable_sig : 1; /* When set, a timer is enabled on PCI DMA1 that asserts the PCI interrupt
- after a specified amount of time. */
- u32 DMA2_IRQ_Enable_sig : 1; /* same as DMA1_IRQ_Enable_sig but for DMA2 */
- u32 DMA2_Timer_Enable_sig : 1; /* same as DMA1_Timer_Enable_sig but for DMA2 */
-
- u32 DMA1_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA1 that asserts the PCI interrupt. */
- u32 DMA2_Size_IRQ_Enable_sig : 1; /* When set, a packet count detector is enabled on PCI DMA2 that asserts the PCI interrupt. */
- u32 Mailbox_from_V8_Enable_sig: 1; /* When set, writes to the mailbox register produce an interrupt to the
- PCI host to indicate that mailbox data is available. */
-
- u32 unused : 9;
- } ctrl_208;
-
-/* General status. When a PCI interrupt occurs, this register is read to
- * discover the reason for the interrupt.
- */
- struct {
- u32 DMA1_IRQ_Status : 1; /* When set(1) the DMA1 counter had generated an IRQ. Read Only. */
- u32 DMA1_Timer_Status : 1; /* When set(1) the DMA1 timer had generated an IRQ. Read Only. */
- u32 DMA2_IRQ_Status : 1; /* When set(1) the DMA2 counter had generated an IRQ. Read Only. */
- u32 DMA2_Timer_Status : 1; /* When set(1) the DMA2 timer had generated an IRQ. Read Only. */
- u32 DMA1_Size_IRQ_Status : 1; /* (Read only). This register is read after an interrupt to */
- u32 DMA2_Size_IRQ_Status : 1; /* find out why we had an IRQ. Reading this register will clear this bit. Packet count*/
- u32 Mailbox_from_V8_Status_sig: 1; /* Same as above. Reading this register will clear this bit. */
- u32 Data_receiver_error : 1; /* 1 indicate an error in the receiver Front End (Tuner module) */
- u32 Continuity_error_flag : 1; /* 1 indicates a continuity error in the TS stream. */
- u32 LLC_SNAP_FLAG_set : 1; /* 1 indicates that the LCC_SNAP_FLAG was set. */
- u32 Transport_Error : 1; /* When set indicates that an unexpected packet was received. */
- u32 reserved :21;
- } irq_20c;
-
-
-/* Software reset register */
- struct {
- u32 reset_blocks : 8; /* Enabled when Block_reset_enable = 0xB2 and 0x208 bits 15:8 = 0x00.
- Each bit location represents a 0x100 block of registers. Writing
- a one in a bit location resets that block of registers and the logic
- that it controls. */
- u32 Block_reset_enable : 8; /* This variable is set to 0xB2 when the register is written. */
- u32 Special_controls :16; /* Asserts Reset_V8 => 0xC258; Turns on pci encryption => 0xC25A;
- Turns off pci encryption => 0xC259 Note: pci_encryption default
- at power-up is ON. */
- } sw_reset_210;
-
- struct {
- u32 vuart_oe_sig : 1; /* When clear, the V8 processor has sole control of the serial UART
- (RS-232 Smart Card interface). When set, the IBI interface
- defined by register 0x600 controls the serial UART. */
- u32 v2WS_oe_sig : 1; /* When clear, the V8 processor has direct control of the Two-line
- Serial Master EEPROM target. When set, the Two-line Serial Master
- EEPROM target interface is controlled by IBI register 0x100. */
- u32 halt_V8_sig : 1; /* When set, contiguous wait states are applied to the V8-space
- bus masters. Once this signal is cleared, normal V8-space
- operations resume. */
- u32 section_pkg_enable_sig: 1; /* When set, this signal enables the front end translation circuitry
- to process section packed transport streams. */
- u32 s2p_sel_sig : 1; /* Serial to parallel conversion. When set, polarized transport data
- within the FlexCop3 front end circuitry is converted from a serial
- stream into parallel data before downstream processing otherwise
- interprets the data. */
- u32 unused1 : 3;
- u32 polarity_PS_CLK_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream CLOCK signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_VALID_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream VALID signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_SYNC_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream SYNC signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 polarity_PS_ERR_sig: 1; /* This signal is used to invert the input polarity of the tranport
- stream ERROR signal before any processing occurs on the transport
- stream within FlexCop3. */
- u32 unused2 :20;
- } misc_214;
-
-/* Mailbox from V8 to host */
- struct {
- u32 Mailbox_from_V8 :32; /* When this register is written by either the V8 processor or by an
- end host, an interrupt is generated to the PCI host to indicate
- that mailbox data is available. Reading register 20c will clear
- the IRQ. */
- } mbox_v8_to_host_218;
-
-/* Mailbox from host to v8 Mailbox_to_V8
- * Mailbox_to_V8 mailbox storage register
- * used to send messages from PCI to V8. Writing to this register will send an
- * IRQ to the V8. Then it can read the data from here. Reading this register
- * will clear the IRQ. If the V8 is halted and bit 31 of this register is set,
- * then this register is used instead as a direct interface to access the
- * V8space memory.
- */
- struct {
- u32 sysramaccess_data : 8; /* Data byte written or read from the specified address in V8 SysRAM. */
- u32 sysramaccess_addr :15; /* 15 bit address used to access V8 Sys-RAM. */
- u32 unused : 7;
- u32 sysramaccess_write: 1; /* Write flag used to latch data into the V8 SysRAM. */
- u32 sysramaccess_busmuster: 1; /* Setting this bit when the V8 is halted at 0x214 Bit(2) allows
- this IBI register interface to directly drive the V8-space memory. */
- } mbox_host_to_v8_21c;
-
-
-/* PIDs, Translation Bit, SMC Filter Select 0x300 to 0x31c */
- struct {
- u32 Stream1_PID :13; /* Primary use is receiving Net data, so these 13 bits normally
- hold the PID value for the desired network stream. */
- u32 Stream1_trans : 1; /* When set, Net translation will take place for Net data ferried in TS packets. */
- u32 MAC_Multicast_filter : 1; /* When clear, multicast MAC filtering is not allowed for Stream1 and PID_n filters. */
- u32 debug_flag_pid_saved : 1;
- u32 Stream2_PID :13; /* 13 bits for Stream 2 PID filter value. General use. */
- u32 Stream2_trans : 1; /* When set Tables/CAI translation will take place for the data ferried in
- Stream2_PID TS packets. */
- u32 debug_flag_write_status00 : 1;
- u32 debug_fifo_problem : 1;
- } pid_filter_300;
-
- struct {
- u32 PCR_PID :13; /* PCR stream PID filter value. Primary use is Program Clock Reference stream filtering. */
- u32 PCR_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 debug_overrun3 : 1;
- u32 debug_overrun2 : 1;
- u32 PMT_PID :13; /* stream PID filter value. Primary use is Program Management Table segment filtering. */
- u32 PMT_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 reserved : 2;
- } pid_filter_304;
-
- struct {
- u32 EMM_PID :13; /* EMM PID filter value. Primary use is Entitlement Management Messaging for
- conditional access-related data. */
- u32 EMM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 EMM_filter_4 : 1; /* When set will pass only EMM data possessing the same ID code as the
- first four bytes (32 bits) of the end-user s 6-byte Smart Card ID number Select */
- u32 EMM_filter_6 : 1; /* When set will pass only EMM data possessing the same 6-byte code as the end-users
- complete 6-byte Smart Card ID number. */
- u32 ECM_PID :13; /* ECM PID filter value. Primary use is Entitlement Control Messaging for conditional
- access-related data. */
- u32 ECM_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 reserved : 2;
- } pid_filter_308;
-
- struct {
- u32 Group_PID :13; /* PID value for group filtering. */
- u32 Group_trans : 1; /* When set, Tables/CAI translation will take place for these packets. */
- u32 unused1 : 2;
- u32 Group_mask :13; /* Mask value used in logical "and" equation that defines group filtering */
- u32 unused2 : 3;
- } pid_filter_30c_ext_ind_0_7;
-
- struct {
- u32 net_master_read :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_1;
-
- struct {
- u32 net_master_write :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_2;
-
- struct {
- u32 next_net_master_write :17;
- u32 unused :15;
- } pid_filter_30c_ext_ind_3;
-
- struct {
- u32 unused1 : 1;
- u32 state_write :10;
- u32 reserved1 : 6; /* default: 000100 */
- u32 stack_read :10;
- u32 reserved2 : 5; /* default: 00100 */
- } pid_filter_30c_ext_ind_4;
-
- struct {
- u32 stack_cnt :10;
- u32 unused :22;
- } pid_filter_30c_ext_ind_5;
-
- struct {
- u32 pid_fsm_save_reg0 : 2;
- u32 pid_fsm_save_reg1 : 2;
- u32 pid_fsm_save_reg2 : 2;
- u32 pid_fsm_save_reg3 : 2;
- u32 pid_fsm_save_reg4 : 2;
- u32 pid_fsm_save_reg300 : 2;
- u32 write_status1 : 2;
- u32 write_status4 : 2;
- u32 data_size_reg :12;
- u32 unused : 4;
- } pid_filter_30c_ext_ind_6;
-
- struct {
- u32 index_reg : 5; /* (Index pointer) Points at an internal PIDn register. A binary code
- representing one of 32 internal PIDn registers as well as its
- corresponding internal MAC_lown register. */
- u32 extra_index_reg : 3; /* This vector is used to select between sets of debug signals routed to register 0x30c. */
- u32 AB_select : 1; /* Used in conjunction with 0x31c. read/write to the MAC_highA or MAC_highB register
- 0=MAC_highB register, 1=MAC_highA */
- u32 pass_alltables : 1; /* 1=Net packets are not filtered against the Network Table ID found in register 0x400.
- All types of networks (DVB, ATSC, ISDB) are passed. */
- u32 unused :22;
- } index_reg_310;
-
- struct {
- u32 PID :13; /* PID value */
- u32 PID_trans : 1; /* translation will take place for packets filtered */
- u32 PID_enable_bit : 1; /* When set this PID filter is enabled */
- u32 reserved :17;
- } pid_n_reg_314;
-
- struct {
- u32 A4_byte : 8;
- u32 A5_byte : 8;
- u32 A6_byte : 8;
- u32 Enable_bit : 1; /* enabled (1) or disabled (1) */
- u32 HighAB_bit : 1; /* use MAC_highA (1) or MAC_highB (0) as MSB */
- u32 reserved : 6;
- } mac_low_reg_318;
-
- struct {
- u32 A1_byte : 8;
- u32 A2_byte : 8;
- u32 A3_byte : 8;
- u32 reserved : 8;
- } mac_high_reg_31c;
-
-/* Table, SMCID,MACDestination Filters 0x400 to 0x41c */
- struct {
- u32 reserved :16;
#define fc_data_Tag_ID_DVB 0x3e
#define fc_data_Tag_ID_ATSC 0x3f
#define fc_data_Tag_ID_IDSB 0x8b
- u32 data_Tag_ID :16;
- } data_tag_400;
-
- struct {
- u32 Card_IDbyte6 : 8;
- u32 Card_IDbyte5 : 8;
- u32 Card_IDbyte4 : 8;
- u32 Card_IDbyte3 : 8;
- } card_id_408;
-
- struct {
- u32 Card_IDbyte2 : 8;
- u32 Card_IDbyte1 : 8;
- } card_id_40c;
-
- /* holding the unique mac address of the receiver which houses the FlexCopIII */
- struct {
- u32 MAC1 : 8;
- u32 MAC2 : 8;
- u32 MAC3 : 8;
- u32 MAC6 : 8;
- } mac_address_418;
-
- struct {
- u32 MAC7 : 8;
- u32 MAC8 : 8;
- u32 reserved : 16;
- } mac_address_41c;
-
- struct {
- u32 transmitter_data_byte : 8;
- u32 ReceiveDataReady : 1;
- u32 ReceiveByteFrameError: 1;
- u32 txbuffempty : 1;
- u32 reserved :21;
- } ci_600;
-
- struct {
- u32 pi_d : 8;
- u32 pi_ha :20;
- u32 pi_rw : 1;
- u32 pi_component_reg : 3;
- } pi_604;
-
- struct {
- u32 serialReset : 1;
- u32 oncecycle_read : 1;
- u32 Timer_Read_req : 1;
- u32 Timer_Load_req : 1;
- u32 timer_data : 7;
- u32 unused : 1; /* ??? not mentioned in data book */
- u32 Timer_addr : 5;
- u32 reserved : 3;
- u32 pcmcia_a_mod_pwr_n : 1;
- u32 pcmcia_b_mod_pwr_n : 1;
- u32 config_Done_stat : 1;
- u32 config_Init_stat : 1;
- u32 config_Prog_n : 1;
- u32 config_wr_n : 1;
- u32 config_cs_n : 1;
- u32 config_cclk : 1;
- u32 pi_CiMax_IRQ_n : 1;
- u32 pi_timeout_status : 1;
- u32 pi_wait_n : 1;
- u32 pi_busy_n : 1;
- } pi_608;
- struct {
- u32 PID :13;
- u32 key_enable : 1;
#define fc_key_code_default 0x1
#define fc_key_code_even 0x2
#define fc_key_code_odd 0x3
- u32 key_code : 2;
- u32 key_array_col : 3;
- u32 key_array_row : 5;
- u32 dvb_en : 1; /* 0=TS bypasses the Descrambler */
- u32 rw_flag : 1;
- u32 reserved : 6;
- } dvb_reg_60c;
-
-/* SRAM and Output Destination 0x700 to 0x714 */
- struct {
- u32 sram_addr :15;
- u32 sram_rw : 1; /* 0=write, 1=read */
- u32 sram_data : 8;
- u32 sc_xfer_bit : 1;
- u32 reserved1 : 3;
- u32 oe_pin_reg : 1;
- u32 ce_pin_reg : 1;
- u32 reserved2 : 1;
- u32 start_sram_ibi : 1;
- } sram_ctrl_reg_700;
-
- struct {
- u32 net_addr_read :16;
- u32 net_addr_write :16;
- } net_buf_reg_704;
-
- struct {
- u32 cai_read :11;
- u32 reserved1 : 5;
- u32 cai_write :11;
- u32 reserved2 : 6;
- u32 cai_cnt : 4;
- } cai_buf_reg_708;
-
- struct {
- u32 cao_read :11;
- u32 reserved1 : 5;
- u32 cap_write :11;
- u32 reserved2 : 6;
- u32 cao_cnt : 4;
- } cao_buf_reg_70c;
-
- struct {
- u32 media_read :11;
- u32 reserved1 : 5;
- u32 media_write :11;
- u32 reserved2 : 6;
- u32 media_cnt : 4;
- } media_buf_reg_710;
-
- struct {
- u32 NET_Dest : 2;
- u32 CAI_Dest : 2;
- u32 CAO_Dest : 2;
- u32 MEDIA_Dest : 2;
- u32 net_ovflow_error : 1;
- u32 media_ovflow_error : 1;
- u32 cai_ovflow_error : 1;
- u32 cao_ovflow_error : 1;
- u32 ctrl_usb_wan : 1;
- u32 ctrl_sramdma : 1;
- u32 ctrl_maximumfill : 1;
- u32 reserved :17;
- } sram_dest_reg_714;
-
- struct {
- u32 net_cnt :12;
- u32 reserved1 : 4;
- u32 net_addr_read : 1;
- u32 reserved2 : 3;
- u32 net_addr_write : 1;
- u32 reserved3 :11;
- } net_buf_reg_718;
-
- struct {
- u32 wan_speed_sig : 2;
- u32 reserved1 : 6;
- u32 wan_wait_state : 8;
- u32 sram_chip : 2;
- u32 sram_memmap : 2;
- u32 reserved2 : 4;
- u32 wan_pkt_frame : 4;
- u32 reserved3 : 4;
- } wan_ctrl_reg_71c;
-} flexcop_ibi_value;
extern flexcop_ibi_value ibi_zero;
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 0113449abd15..0a78ba3737a5 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -545,7 +545,7 @@ static struct usb_device_id flexcop_usb_table [] = {
/* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver flexcop_usb_driver = {
.owner = THIS_MODULE,
- .name = "Technisat/B2C2 FlexCop II/IIb/III USB",
+ .name = "b2c2_flexcop_usb",
.probe = flexcop_usb_probe,
.disconnect = flexcop_usb_disconnect,
.id_table = flexcop_usb_table,
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 8b5d14dd36e3..12873d435406 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -46,7 +46,7 @@
int b2c2_flexcop_debug;
module_param_named(debug, b2c2_flexcop_debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug, "set debug level (1=info,2=tuner,4=i2c,8=ts,16=sram,32=reg (|-able))." DEBSTATUS);
#undef DEBSTATUS
/* global zero for ibi values */
@@ -173,9 +173,20 @@ static void flexcop_reset(struct flexcop_device *fc)
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
v210.raw = 0;
- v210.sw_reset_210.reset_blocks = 0xff;
+ v210.sw_reset_210.reset_block_000 = 1;
+ v210.sw_reset_210.reset_block_100 = 1;
+ v210.sw_reset_210.reset_block_200 = 1;
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.reset_block_400 = 1;
+ v210.sw_reset_210.reset_block_500 = 1;
+ v210.sw_reset_210.reset_block_600 = 1;
+ v210.sw_reset_210.reset_block_700 = 1;
v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ v210.sw_reset_210.Special_controls = 0xc259;
+
fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
/* reset the periphical devices */
@@ -186,6 +197,25 @@ static void flexcop_reset(struct flexcop_device *fc)
fc->write_ibi_reg(fc,misc_204,v204);
}
+void flexcop_reset_block_300(struct flexcop_device *fc)
+{
+ flexcop_ibi_value v208_save = fc->read_ibi_reg(fc,ctrl_208),
+ v210 = fc->read_ibi_reg(fc,sw_reset_210);
+
+ deb_rdump("208: %08x, 210: %08x\n",v208_save.raw,v210.raw);
+
+ fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
+
+ v210.sw_reset_210.reset_block_300 = 1;
+ v210.sw_reset_210.Block_reset_enable = 0xb2;
+
+ fc->write_ibi_reg(fc,sw_reset_210,v210);
+ msleep(1);
+
+ fc->write_ibi_reg(fc,ctrl_208,v208_save);
+}
+EXPORT_SYMBOL(flexcop_reset_block_300);
+
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
{
void *bus;
diff --git a/drivers/media/dvb/b2c2/flexcop.h b/drivers/media/dvb/b2c2/flexcop.h
index caa343a97bdc..0cebe1d92e0b 100644
--- a/drivers/media/dvb/b2c2/flexcop.h
+++ b/drivers/media/dvb/b2c2/flexcop.h
@@ -26,5 +26,6 @@ extern int b2c2_flexcop_debug;
#define deb_i2c(args...) dprintk(0x04,args)
#define deb_ts(args...) dprintk(0x08,args)
#define deb_sram(args...) dprintk(0x10,args)
+#define deb_rdump(args...) dprintk(0x20,args)
#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
new file mode 100644
index 000000000000..ed9a6756b194
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_be.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+ u32 raw;
+
+ struct {
+ u32 dma_address0 :30;
+ u32 dma_0No_update : 1;
+ u32 dma_0start : 1;
+ } dma_0x0;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 DMA_maxpackets : 8;
+ } dma_0x4_remap;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 unused : 1;
+ u32 dma1timer : 7;
+ } dma_0x4_read;
+
+ struct {
+ u32 dma_addr_size :24;
+ u32 dmatimer : 7;
+ u32 unused : 1;
+ } dma_0x4_write;
+
+ struct {
+ u32 dma_cur_addr :30;
+ u32 unused : 2;
+ } dma_0x8;
+
+ struct {
+ u32 dma_address1 :30;
+ u32 remap_enable : 1;
+ u32 dma_1start : 1;
+ } dma_0xc;
+
+ struct {
+ u32 st_done : 1;
+ u32 no_base_addr_ack_error : 1;
+ u32 twoWS_port_reg : 2;
+ u32 total_bytes : 2;
+ u32 twoWS_rw : 1;
+ u32 working_start : 1;
+ u32 data1_reg : 8;
+ u32 baseaddr : 8;
+ u32 reserved1 : 1;
+ u32 chipaddr : 7;
+ } tw_sm_c_100;
+
+ struct {
+ u32 unused : 6;
+ u32 force_stop : 1;
+ u32 exlicit_stops : 1;
+ u32 data4_reg : 8;
+ u32 data3_reg : 8;
+ u32 data2_reg : 8;
+ } tw_sm_c_104;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_108;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_10c;
+
+ struct {
+ u32 reserved2 :19;
+ u32 tlo1 : 5;
+ u32 reserved1 : 2;
+ u32 thi1 : 6;
+ } tw_sm_c_110;
+
+ struct {
+ u32 LNB_CTLPrescaler_sig : 2;
+ u32 LNB_CTLLowCount_sig :15;
+ u32 LNB_CTLHighCount_sig :15;
+ } lnb_switch_freq_200;
+
+ struct {
+ u32 Rev_N_sig_reserved2 : 1;
+ u32 Rev_N_sig_caps : 1;
+ u32 Rev_N_sig_reserved1 : 2;
+ u32 Rev_N_sig_revision_hi : 4;
+ u32 reserved :20;
+ u32 Per_reset_sig : 1;
+ u32 LNB_L_H_sig : 1;
+ u32 ACPI3_sig : 1;
+ u32 ACPI1_sig : 1;
+ } misc_204;
+
+ struct {
+ u32 unused : 9;
+ u32 Mailbox_from_V8_Enable_sig : 1;
+ u32 DMA2_Size_IRQ_Enable_sig : 1;
+ u32 DMA1_Size_IRQ_Enable_sig : 1;
+ u32 DMA2_Timer_Enable_sig : 1;
+ u32 DMA2_IRQ_Enable_sig : 1;
+ u32 DMA1_Timer_Enable_sig : 1;
+ u32 DMA1_IRQ_Enable_sig : 1;
+ u32 Rcv_Data_sig : 1;
+ u32 MAC_filter_Mode_sig : 1;
+ u32 Multi2_Enable_sig : 1;
+ u32 Per_CA_Enable_sig : 1;
+ u32 SMC_Enable_sig : 1;
+ u32 CA_Enable_sig : 1;
+ u32 WAN_CA_Enable_sig : 1;
+ u32 WAN_Enable_sig : 1;
+ u32 Mask_filter_sig : 1;
+ u32 Null_filter_sig : 1;
+ u32 ECM_filter_sig : 1;
+ u32 EMM_filter_sig : 1;
+ u32 PMT_filter_sig : 1;
+ u32 PCR_filter_sig : 1;
+ u32 Stream2_filter_sig : 1;
+ u32 Stream1_filter_sig : 1;
+ } ctrl_208;
+
+ struct {
+ u32 reserved :21;
+ u32 Transport_Error : 1;
+ u32 LLC_SNAP_FLAG_set : 1;
+ u32 Continuity_error_flag : 1;
+ u32 Data_receiver_error : 1;
+ u32 Mailbox_from_V8_Status_sig : 1;
+ u32 DMA2_Size_IRQ_Status : 1;
+ u32 DMA1_Size_IRQ_Status : 1;
+ u32 DMA2_Timer_Status : 1;
+ u32 DMA2_IRQ_Status : 1;
+ u32 DMA1_Timer_Status : 1;
+ u32 DMA1_IRQ_Status : 1;
+ } irq_20c;
+
+ struct {
+ u32 Special_controls :16;
+ u32 Block_reset_enable : 8;
+ u32 reset_block_700 : 1;
+ u32 reset_block_600 : 1;
+ u32 reset_block_500 : 1;
+ u32 reset_block_400 : 1;
+ u32 reset_block_300 : 1;
+ u32 reset_block_200 : 1;
+ u32 reset_block_100 : 1;
+ u32 reset_block_000 : 1;
+ } sw_reset_210;
+
+ struct {
+ u32 unused2 :20;
+ u32 polarity_PS_ERR_sig : 1;
+ u32 polarity_PS_SYNC_sig : 1;
+ u32 polarity_PS_VALID_sig : 1;
+ u32 polarity_PS_CLK_sig : 1;
+ u32 unused1 : 3;
+ u32 s2p_sel_sig : 1;
+ u32 section_pkg_enable_sig : 1;
+ u32 halt_V8_sig : 1;
+ u32 v2WS_oe_sig : 1;
+ u32 vuart_oe_sig : 1;
+ } misc_214;
+
+ struct {
+ u32 Mailbox_from_V8 :32;
+ } mbox_v8_to_host_218;
+
+ struct {
+ u32 sysramaccess_busmuster : 1;
+ u32 sysramaccess_write : 1;
+ u32 unused : 7;
+ u32 sysramaccess_addr :15;
+ u32 sysramaccess_data : 8;
+ } mbox_host_to_v8_21c;
+
+ struct {
+ u32 debug_fifo_problem : 1;
+ u32 debug_flag_write_status00 : 1;
+ u32 Stream2_trans : 1;
+ u32 Stream2_PID :13;
+ u32 debug_flag_pid_saved : 1;
+ u32 MAC_Multicast_filter : 1;
+ u32 Stream1_trans : 1;
+ u32 Stream1_PID :13;
+ } pid_filter_300;
+
+ struct {
+ u32 reserved : 2;
+ u32 PMT_trans : 1;
+ u32 PMT_PID :13;
+ u32 debug_overrun2 : 1;
+ u32 debug_overrun3 : 1;
+ u32 PCR_trans : 1;
+ u32 PCR_PID :13;
+ } pid_filter_304;
+
+ struct {
+ u32 reserved : 2;
+ u32 ECM_trans : 1;
+ u32 ECM_PID :13;
+ u32 EMM_filter_6 : 1;
+ u32 EMM_filter_4 : 1;
+ u32 EMM_trans : 1;
+ u32 EMM_PID :13;
+ } pid_filter_308;
+
+ struct {
+ u32 unused2 : 3;
+ u32 Group_mask :13;
+ u32 unused1 : 2;
+ u32 Group_trans : 1;
+ u32 Group_PID :13;
+ } pid_filter_30c_ext_ind_0_7;
+
+ struct {
+ u32 unused :15;
+ u32 net_master_read :17;
+ } pid_filter_30c_ext_ind_1;
+
+ struct {
+ u32 unused :15;
+ u32 net_master_write :17;
+ } pid_filter_30c_ext_ind_2;
+
+ struct {
+ u32 unused :15;
+ u32 next_net_master_write :17;
+ } pid_filter_30c_ext_ind_3;
+
+ struct {
+ u32 reserved2 : 5;
+ u32 stack_read :10;
+ u32 reserved1 : 6;
+ u32 state_write :10;
+ u32 unused1 : 1;
+ } pid_filter_30c_ext_ind_4;
+
+ struct {
+ u32 unused :22;
+ u32 stack_cnt :10;
+ } pid_filter_30c_ext_ind_5;
+
+ struct {
+ u32 unused : 4;
+ u32 data_size_reg :12;
+ u32 write_status4 : 2;
+ u32 write_status1 : 2;
+ u32 pid_fsm_save_reg300 : 2;
+ u32 pid_fsm_save_reg4 : 2;
+ u32 pid_fsm_save_reg3 : 2;
+ u32 pid_fsm_save_reg2 : 2;
+ u32 pid_fsm_save_reg1 : 2;
+ u32 pid_fsm_save_reg0 : 2;
+ } pid_filter_30c_ext_ind_6;
+
+ struct {
+ u32 unused :22;
+ u32 pass_alltables : 1;
+ u32 AB_select : 1;
+ u32 extra_index_reg : 3;
+ u32 index_reg : 5;
+ } index_reg_310;
+
+ struct {
+ u32 reserved :17;
+ u32 PID_enable_bit : 1;
+ u32 PID_trans : 1;
+ u32 PID :13;
+ } pid_n_reg_314;
+
+ struct {
+ u32 reserved : 6;
+ u32 HighAB_bit : 1;
+ u32 Enable_bit : 1;
+ u32 A6_byte : 8;
+ u32 A5_byte : 8;
+ u32 A4_byte : 8;
+ } mac_low_reg_318;
+
+ struct {
+ u32 reserved : 8;
+ u32 A3_byte : 8;
+ u32 A2_byte : 8;
+ u32 A1_byte : 8;
+ } mac_high_reg_31c;
+
+ struct {
+ u32 data_Tag_ID :16;
+ u32 reserved :16;
+ } data_tag_400;
+
+ struct {
+ u32 Card_IDbyte3 : 8;
+ u32 Card_IDbyte4 : 8;
+ u32 Card_IDbyte5 : 8;
+ u32 Card_IDbyte6 : 8;
+ } card_id_408;
+
+ struct {
+ u32 Card_IDbyte1 : 8;
+ u32 Card_IDbyte2 : 8;
+ } card_id_40c;
+
+ struct {
+ u32 MAC6 : 8;
+ u32 MAC3 : 8;
+ u32 MAC2 : 8;
+ u32 MAC1 : 8;
+ } mac_address_418;
+
+ struct {
+ u32 reserved :16;
+ u32 MAC8 : 8;
+ u32 MAC7 : 8;
+ } mac_address_41c;
+
+ struct {
+ u32 reserved :21;
+ u32 txbuffempty : 1;
+ u32 ReceiveByteFrameError : 1;
+ u32 ReceiveDataReady : 1;
+ u32 transmitter_data_byte : 8;
+ } ci_600;
+
+ struct {
+ u32 pi_component_reg : 3;
+ u32 pi_rw : 1;
+ u32 pi_ha :20;
+ u32 pi_d : 8;
+ } pi_604;
+
+ struct {
+ u32 pi_busy_n : 1;
+ u32 pi_wait_n : 1;
+ u32 pi_timeout_status : 1;
+ u32 pi_CiMax_IRQ_n : 1;
+ u32 config_cclk : 1;
+ u32 config_cs_n : 1;
+ u32 config_wr_n : 1;
+ u32 config_Prog_n : 1;
+ u32 config_Init_stat : 1;
+ u32 config_Done_stat : 1;
+ u32 pcmcia_b_mod_pwr_n : 1;
+ u32 pcmcia_a_mod_pwr_n : 1;
+ u32 reserved : 3;
+ u32 Timer_addr : 5;
+ u32 unused : 1;
+ u32 timer_data : 7;
+ u32 Timer_Load_req : 1;
+ u32 Timer_Read_req : 1;
+ u32 oncecycle_read : 1;
+ u32 serialReset : 1;
+ } pi_608;
+
+ struct {
+ u32 reserved : 6;
+ u32 rw_flag : 1;
+ u32 dvb_en : 1;
+ u32 key_array_row : 5;
+ u32 key_array_col : 3;
+ u32 key_code : 2;
+ u32 key_enable : 1;
+ u32 PID :13;
+ } dvb_reg_60c;
+
+ struct {
+ u32 start_sram_ibi : 1;
+ u32 reserved2 : 1;
+ u32 ce_pin_reg : 1;
+ u32 oe_pin_reg : 1;
+ u32 reserved1 : 3;
+ u32 sc_xfer_bit : 1;
+ u32 sram_data : 8;
+ u32 sram_rw : 1;
+ u32 sram_addr :15;
+ } sram_ctrl_reg_700;
+
+ struct {
+ u32 net_addr_write :16;
+ u32 net_addr_read :16;
+ } net_buf_reg_704;
+
+ struct {
+ u32 cai_cnt : 4;
+ u32 reserved2 : 6;
+ u32 cai_write :11;
+ u32 reserved1 : 5;
+ u32 cai_read :11;
+ } cai_buf_reg_708;
+
+ struct {
+ u32 cao_cnt : 4;
+ u32 reserved2 : 6;
+ u32 cap_write :11;
+ u32 reserved1 : 5;
+ u32 cao_read :11;
+ } cao_buf_reg_70c;
+
+ struct {
+ u32 media_cnt : 4;
+ u32 reserved2 : 6;
+ u32 media_write :11;
+ u32 reserved1 : 5;
+ u32 media_read :11;
+ } media_buf_reg_710;
+
+ struct {
+ u32 reserved :17;
+ u32 ctrl_maximumfill : 1;
+ u32 ctrl_sramdma : 1;
+ u32 ctrl_usb_wan : 1;
+ u32 cao_ovflow_error : 1;
+ u32 cai_ovflow_error : 1;
+ u32 media_ovflow_error : 1;
+ u32 net_ovflow_error : 1;
+ u32 MEDIA_Dest : 2;
+ u32 CAO_Dest : 2;
+ u32 CAI_Dest : 2;
+ u32 NET_Dest : 2;
+ } sram_dest_reg_714;
+
+ struct {
+ u32 reserved3 :11;
+ u32 net_addr_write : 1;
+ u32 reserved2 : 3;
+ u32 net_addr_read : 1;
+ u32 reserved1 : 4;
+ u32 net_cnt :12;
+ } net_buf_reg_718;
+
+ struct {
+ u32 reserved3 : 4;
+ u32 wan_pkt_frame : 4;
+ u32 reserved2 : 4;
+ u32 sram_memmap : 2;
+ u32 sram_chip : 2;
+ u32 wan_wait_state : 8;
+ u32 reserved1 : 6;
+ u32 wan_speed_sig : 2;
+ } wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
new file mode 100644
index 000000000000..49f2315b6e58
--- /dev/null
+++ b/drivers/media/dvb/b2c2/flexcop_ibi_value_le.h
@@ -0,0 +1,458 @@
+/* This file is part of linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
+ *
+ * register descriptions
+ *
+ * see flexcop.c for copyright information.
+ */
+
+/* This file is automatically generated, do not edit things here. */
+#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
+#define __FLEXCOP_IBI_VALUE_INCLUDED__
+
+typedef union {
+ u32 raw;
+
+ struct {
+ u32 dma_0start : 1;
+ u32 dma_0No_update : 1;
+ u32 dma_address0 :30;
+ } dma_0x0;
+
+ struct {
+ u32 DMA_maxpackets : 8;
+ u32 dma_addr_size :24;
+ } dma_0x4_remap;
+
+ struct {
+ u32 dma1timer : 7;
+ u32 unused : 1;
+ u32 dma_addr_size :24;
+ } dma_0x4_read;
+
+ struct {
+ u32 unused : 1;
+ u32 dmatimer : 7;
+ u32 dma_addr_size :24;
+ } dma_0x4_write;
+
+ struct {
+ u32 unused : 2;
+ u32 dma_cur_addr :30;
+ } dma_0x8;
+
+ struct {
+ u32 dma_1start : 1;
+ u32 remap_enable : 1;
+ u32 dma_address1 :30;
+ } dma_0xc;
+
+ struct {
+ u32 chipaddr : 7;
+ u32 reserved1 : 1;
+ u32 baseaddr : 8;
+ u32 data1_reg : 8;
+ u32 working_start : 1;
+ u32 twoWS_rw : 1;
+ u32 total_bytes : 2;
+ u32 twoWS_port_reg : 2;
+ u32 no_base_addr_ack_error : 1;
+ u32 st_done : 1;
+ } tw_sm_c_100;
+
+ struct {
+ u32 data2_reg : 8;
+ u32 data3_reg : 8;
+ u32 data4_reg : 8;
+ u32 exlicit_stops : 1;
+ u32 force_stop : 1;
+ u32 unused : 6;
+ } tw_sm_c_104;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_108;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_10c;
+
+ struct {
+ u32 thi1 : 6;
+ u32 reserved1 : 2;
+ u32 tlo1 : 5;
+ u32 reserved2 :19;
+ } tw_sm_c_110;
+
+ struct {
+ u32 LNB_CTLHighCount_sig :15;
+ u32 LNB_CTLLowCount_sig :15;
+ u32 LNB_CTLPrescaler_sig : 2;
+ } lnb_switch_freq_200;
+
+ struct {
+ u32 ACPI1_sig : 1;
+ u32 ACPI3_sig : 1;
+ u32 LNB_L_H_sig : 1;
+ u32 Per_reset_sig : 1;
+ u32 reserved :20;
+ u32 Rev_N_sig_revision_hi : 4;
+ u32 Rev_N_sig_reserved1 : 2;
+ u32 Rev_N_sig_caps : 1;
+ u32 Rev_N_sig_reserved2 : 1;
+ } misc_204;
+
+ struct {
+ u32 Stream1_filter_sig : 1;
+ u32 Stream2_filter_sig : 1;
+ u32 PCR_filter_sig : 1;
+ u32 PMT_filter_sig : 1;
+ u32 EMM_filter_sig : 1;
+ u32 ECM_filter_sig : 1;
+ u32 Null_filter_sig : 1;
+ u32 Mask_filter_sig : 1;
+ u32 WAN_Enable_sig : 1;
+ u32 WAN_CA_Enable_sig : 1;
+ u32 CA_Enable_sig : 1;
+ u32 SMC_Enable_sig : 1;
+ u32 Per_CA_Enable_sig : 1;
+ u32 Multi2_Enable_sig : 1;
+ u32 MAC_filter_Mode_sig : 1;
+ u32 Rcv_Data_sig : 1;
+ u32 DMA1_IRQ_Enable_sig : 1;
+ u32 DMA1_Timer_Enable_sig : 1;
+ u32 DMA2_IRQ_Enable_sig : 1;
+ u32 DMA2_Timer_Enable_sig : 1;
+ u32 DMA1_Size_IRQ_Enable_sig : 1;
+ u32 DMA2_Size_IRQ_Enable_sig : 1;
+ u32 Mailbox_from_V8_Enable_sig : 1;
+ u32 unused : 9;
+ } ctrl_208;
+
+ struct {
+ u32 DMA1_IRQ_Status : 1;
+ u32 DMA1_Timer_Status : 1;
+ u32 DMA2_IRQ_Status : 1;
+ u32 DMA2_Timer_Status : 1;
+ u32 DMA1_Size_IRQ_Status : 1;
+ u32 DMA2_Size_IRQ_Status : 1;
+ u32 Mailbox_from_V8_Status_sig : 1;
+ u32 Data_receiver_error : 1;
+ u32 Continuity_error_flag : 1;
+ u32 LLC_SNAP_FLAG_set : 1;
+ u32 Transport_Error : 1;
+ u32 reserved :21;
+ } irq_20c;
+
+ struct {
+ u32 reset_block_000 : 1;
+ u32 reset_block_100 : 1;
+ u32 reset_block_200 : 1;
+ u32 reset_block_300 : 1;
+ u32 reset_block_400 : 1;
+ u32 reset_block_500 : 1;
+ u32 reset_block_600 : 1;
+ u32 reset_block_700 : 1;
+ u32 Block_reset_enable : 8;
+ u32 Special_controls :16;
+ } sw_reset_210;
+
+ struct {
+ u32 vuart_oe_sig : 1;
+ u32 v2WS_oe_sig : 1;
+ u32 halt_V8_sig : 1;
+ u32 section_pkg_enable_sig : 1;
+ u32 s2p_sel_sig : 1;
+ u32 unused1 : 3;
+ u32 polarity_PS_CLK_sig : 1;
+ u32 polarity_PS_VALID_sig : 1;
+ u32 polarity_PS_SYNC_sig : 1;
+ u32 polarity_PS_ERR_sig : 1;
+ u32 unused2 :20;
+ } misc_214;
+
+ struct {
+ u32 Mailbox_from_V8 :32;
+ } mbox_v8_to_host_218;
+
+ struct {
+ u32 sysramaccess_data : 8;
+ u32 sysramaccess_addr :15;
+ u32 unused : 7;
+ u32 sysramaccess_write : 1;
+ u32 sysramaccess_busmuster : 1;
+ } mbox_host_to_v8_21c;
+
+ struct {
+ u32 Stream1_PID :13;
+ u32 Stream1_trans : 1;
+ u32 MAC_Multicast_filter : 1;
+ u32 debug_flag_pid_saved : 1;
+ u32 Stream2_PID :13;
+ u32 Stream2_trans : 1;
+ u32 debug_flag_write_status00 : 1;
+ u32 debug_fifo_problem : 1;
+ } pid_filter_300;
+
+ struct {
+ u32 PCR_PID :13;
+ u32 PCR_trans : 1;
+ u32 debug_overrun3 : 1;
+ u32 debug_overrun2 : 1;
+ u32 PMT_PID :13;
+ u32 PMT_trans : 1;
+ u32 reserved : 2;
+ } pid_filter_304;
+
+ struct {
+ u32 EMM_PID :13;
+ u32 EMM_trans : 1;
+ u32 EMM_filter_4 : 1;
+ u32 EMM_filter_6 : 1;
+ u32 ECM_PID :13;
+ u32 ECM_trans : 1;
+ u32 reserved : 2;
+ } pid_filter_308;
+
+ struct {
+ u32 Group_PID :13;
+ u32 Group_trans : 1;
+ u32 unused1 : 2;
+ u32 Group_mask :13;
+ u32 unused2 : 3;
+ } pid_filter_30c_ext_ind_0_7;
+
+ struct {
+ u32 net_master_read :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_1;
+
+ struct {
+ u32 net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_2;
+
+ struct {
+ u32 next_net_master_write :17;
+ u32 unused :15;
+ } pid_filter_30c_ext_ind_3;
+
+ struct {
+ u32 unused1 : 1;
+ u32 state_write :10;
+ u32 reserved1 : 6;
+ u32 stack_read :10;
+ u32 reserved2 : 5;
+ } pid_filter_30c_ext_ind_4;
+
+ struct {
+ u32 stack_cnt :10;
+ u32 unused :22;
+ } pid_filter_30c_ext_ind_5;
+
+ struct {
+ u32 pid_fsm_save_reg0 : 2;
+ u32 pid_fsm_save_reg1 : 2;
+ u32 pid_fsm_save_reg2 : 2;
+ u32 pid_fsm_save_reg3 : 2;
+ u32 pid_fsm_save_reg4 : 2;
+ u32 pid_fsm_save_reg300 : 2;
+ u32 write_status1 : 2;
+ u32 write_status4 : 2;
+ u32 data_size_reg :12;
+ u32 unused : 4;
+ } pid_filter_30c_ext_ind_6;
+
+ struct {
+ u32 index_reg : 5;
+ u32 extra_index_reg : 3;
+ u32 AB_select : 1;
+ u32 pass_alltables : 1;
+ u32 unused :22;
+ } index_reg_310;
+
+ struct {
+ u32 PID :13;
+ u32 PID_trans : 1;
+ u32 PID_enable_bit : 1;
+ u32 reserved :17;
+ } pid_n_reg_314;
+
+ struct {
+ u32 A4_byte : 8;
+ u32 A5_byte : 8;
+ u32 A6_byte : 8;
+ u32 Enable_bit : 1;
+ u32 HighAB_bit : 1;
+ u32 reserved : 6;
+ } mac_low_reg_318;
+
+ struct {
+ u32 A1_byte : 8;
+ u32 A2_byte : 8;
+ u32 A3_byte : 8;
+ u32 reserved : 8;
+ } mac_high_reg_31c;
+
+ struct {
+ u32 reserved :16;
+ u32 data_Tag_ID :16;
+ } data_tag_400;
+
+ struct {
+ u32 Card_IDbyte6 : 8;
+ u32 Card_IDbyte5 : 8;
+ u32 Card_IDbyte4 : 8;
+ u32 Card_IDbyte3 : 8;
+ } card_id_408;
+
+ struct {
+ u32 Card_IDbyte2 : 8;
+ u32 Card_IDbyte1 : 8;
+ } card_id_40c;
+
+ struct {
+ u32 MAC1 : 8;
+ u32 MAC2 : 8;
+ u32 MAC3 : 8;
+ u32 MAC6 : 8;
+ } mac_address_418;
+
+ struct {
+ u32 MAC7 : 8;
+ u32 MAC8 : 8;
+ u32 reserved :16;
+ } mac_address_41c;
+
+ struct {
+ u32 transmitter_data_byte : 8;
+ u32 ReceiveDataReady : 1;
+ u32 ReceiveByteFrameError : 1;
+ u32 txbuffempty : 1;
+ u32 reserved :21;
+ } ci_600;
+
+ struct {
+ u32 pi_d : 8;
+ u32 pi_ha :20;
+ u32 pi_rw : 1;
+ u32 pi_component_reg : 3;
+ } pi_604;
+
+ struct {
+ u32 serialReset : 1;
+ u32 oncecycle_read : 1;
+ u32 Timer_Read_req : 1;
+ u32 Timer_Load_req : 1;
+ u32 timer_data : 7;
+ u32 unused : 1;
+ u32 Timer_addr : 5;
+ u32 reserved : 3;
+ u32 pcmcia_a_mod_pwr_n : 1;
+ u32 pcmcia_b_mod_pwr_n : 1;
+ u32 config_Done_stat : 1;
+ u32 config_Init_stat : 1;
+ u32 config_Prog_n : 1;
+ u32 config_wr_n : 1;
+ u32 config_cs_n : 1;
+ u32 config_cclk : 1;
+ u32 pi_CiMax_IRQ_n : 1;
+ u32 pi_timeout_status : 1;
+ u32 pi_wait_n : 1;
+ u32 pi_busy_n : 1;
+ } pi_608;
+
+ struct {
+ u32 PID :13;
+ u32 key_enable : 1;
+ u32 key_code : 2;
+ u32 key_array_col : 3;
+ u32 key_array_row : 5;
+ u32 dvb_en : 1;
+ u32 rw_flag : 1;
+ u32 reserved : 6;
+ } dvb_reg_60c;
+
+ struct {
+ u32 sram_addr :15;
+ u32 sram_rw : 1;
+ u32 sram_data : 8;
+ u32 sc_xfer_bit : 1;
+ u32 reserved1 : 3;
+ u32 oe_pin_reg : 1;
+ u32 ce_pin_reg : 1;
+ u32 reserved2 : 1;
+ u32 start_sram_ibi : 1;
+ } sram_ctrl_reg_700;
+
+ struct {
+ u32 net_addr_read :16;
+ u32 net_addr_write :16;
+ } net_buf_reg_704;
+
+ struct {
+ u32 cai_read :11;
+ u32 reserved1 : 5;
+ u32 cai_write :11;
+ u32 reserved2 : 6;
+ u32 cai_cnt : 4;
+ } cai_buf_reg_708;
+
+ struct {
+ u32 cao_read :11;
+ u32 reserved1 : 5;
+ u32 cap_write :11;
+ u32 reserved2 : 6;
+ u32 cao_cnt : 4;
+ } cao_buf_reg_70c;
+
+ struct {
+ u32 media_read :11;
+ u32 reserved1 : 5;
+ u32 media_write :11;
+ u32 reserved2 : 6;
+ u32 media_cnt : 4;
+ } media_buf_reg_710;
+
+ struct {
+ u32 NET_Dest : 2;
+ u32 CAI_Dest : 2;
+ u32 CAO_Dest : 2;
+ u32 MEDIA_Dest : 2;
+ u32 net_ovflow_error : 1;
+ u32 media_ovflow_error : 1;
+ u32 cai_ovflow_error : 1;
+ u32 cao_ovflow_error : 1;
+ u32 ctrl_usb_wan : 1;
+ u32 ctrl_sramdma : 1;
+ u32 ctrl_maximumfill : 1;
+ u32 reserved :17;
+ } sram_dest_reg_714;
+
+ struct {
+ u32 net_cnt :12;
+ u32 reserved1 : 4;
+ u32 net_addr_read : 1;
+ u32 reserved2 : 3;
+ u32 net_addr_write : 1;
+ u32 reserved3 :11;
+ } net_buf_reg_718;
+
+ struct {
+ u32 wan_speed_sig : 2;
+ u32 reserved1 : 6;
+ u32 wan_wait_state : 8;
+ u32 sram_chip : 2;
+ u32 sram_memmap : 2;
+ u32 reserved2 : 4;
+ u32 wan_pkt_frame : 4;
+ u32 reserved3 : 4;
+ } wan_ctrl_reg_71c;
+} flexcop_ibi_value;
+
+#endif
diff --git a/drivers/media/dvb/b2c2/skystar2.c b/drivers/media/dvb/b2c2/skystar2.c
deleted file mode 100644
index acbc4c34f72a..000000000000
--- a/drivers/media/dvb/b2c2/skystar2.c
+++ /dev/null
@@ -1,2644 +0,0 @@
-/*
- * skystar2.c - driver for the Technisat SkyStar2 PCI DVB card
- * based on the FlexCopII by B2C2,Inc.
- *
- * Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
- *
- * FIX: DISEQC Tone Burst in flexcop_diseqc_ioctl()
- * FIX: FULL soft DiSEqC for skystar2 (FlexCopII rev 130) VP310 equipped
- * Vincenzo Di Massa, hawk.it at tiscalinet.it
- *
- * Converted to Linux coding style
- * Misc reorganization, polishing, restyling
- * Roberto Ragusa, skystar2-c5b8 at robertoragusa dot it
- *
- * Added hardware filtering support,
- * Niklas Peinecke, peinecke at gdv.uni-hannover.de
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public License
- * as published by the Free Software Foundation; either version 2.1
- * 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 Lesser 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 <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/version.h>
-
-#include <asm/io.h>
-
-#include "dvb_frontend.h"
-
-#include <linux/dvb/frontend.h>
-#include <linux/dvb/dmx.h>
-#include "dvb_demux.h"
-#include "dmxdev.h"
-#include "dvb_filter.h"
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_net.h"
-#include "stv0299.h"
-#include "mt352.h"
-#include "mt312.h"
-#include "nxt2002.h"
-
-static int debug;
-static int enable_hw_filters = 2;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Set debugging level (0 = default, 1 = most messages, 2 = all messages).");
-module_param(enable_hw_filters, int, 0444);
-MODULE_PARM_DESC(enable_hw_filters, "enable hardware filters: supported values: 0 (none), 1, 2");
-
-#define dprintk(x...) do { if (debug>=1) printk(x); } while (0)
-#define ddprintk(x...) do { if (debug>=2) printk(x); } while (0)
-
-#define SIZE_OF_BUF_DMA1 0x3ac00
-#define SIZE_OF_BUF_DMA2 0x758
-
-#define MAX_N_HW_FILTERS (6+32)
-#define N_PID_SLOTS 256
-
-struct dmaq {
- u32 bus_addr;
- u32 head;
- u32 tail;
- u32 buffer_size;
- u8 *buffer;
-};
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
-#define __iomem
-#endif
-
-struct adapter {
- struct pci_dev *pdev;
-
- u8 card_revision;
- u32 b2c2_revision;
- u32 pid_filter_max;
- u32 mac_filter_max;
- u32 irq;
- void __iomem *io_mem;
- unsigned long io_port;
- u8 mac_addr[8];
- u32 dw_sram_type;
-
- struct dvb_adapter dvb_adapter;
- struct dvb_demux demux;
- struct dmxdev dmxdev;
- struct dmx_frontend hw_frontend;
- struct dmx_frontend mem_frontend;
- struct i2c_adapter i2c_adap;
- struct dvb_net dvbnet;
-
- struct semaphore i2c_sem;
-
- struct dmaq dmaq1;
- struct dmaq dmaq2;
-
- u32 dma_ctrl;
- u32 dma_status;
-
- int capturing;
-
- spinlock_t lock;
-
- int useable_hw_filters;
- u16 hw_pids[MAX_N_HW_FILTERS];
- u16 pid_list[N_PID_SLOTS];
- int pid_rc[N_PID_SLOTS]; // ref counters for the pids
- int pid_count;
- int whole_bandwidth_count;
- u32 mac_filter;
-
- struct dvb_frontend* fe;
- int (*fe_sleep)(struct dvb_frontend* fe);
-};
-
-#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
-#define read_reg_dw(adapter,reg) readl(adapter->io_mem + reg)
-
-static void write_reg_bitfield(struct adapter *adapter, u32 reg, u32 zeromask, u32 orvalue)
-{
- u32 tmp;
-
- tmp = read_reg_dw(adapter, reg);
- tmp = (tmp & ~zeromask) | orvalue;
- write_reg_dw(adapter, reg, tmp);
-}
-
-/* i2c functions */
-static int i2c_main_write_for_flex2(struct adapter *adapter, u32 command, u8 *buf, int retries)
-{
- int i;
- u32 value;
-
- write_reg_dw(adapter, 0x100, 0);
- write_reg_dw(adapter, 0x100, command);
-
- for (i = 0; i < retries; i++) {
- value = read_reg_dw(adapter, 0x100);
-
- if ((value & 0x40000000) == 0) {
- if ((value & 0x81000000) == 0x80000000) {
- if (buf != 0)
- *buf = (value >> 0x10) & 0xff;
-
- return 1;
- }
- } else {
- write_reg_dw(adapter, 0x100, 0);
- write_reg_dw(adapter, 0x100, command);
- }
- }
-
- return 0;
-}
-
-/* device = 0x10000000 for tuner, 0x20000000 for eeprom */
-static void i2c_main_setup(u32 device, u32 chip_addr, u8 op, u8 addr, u32 value, u32 len, u32 *command)
-{
- *command = device | ((len - 1) << 26) | (value << 16) | (addr << 8) | chip_addr;
-
- if (op != 0)
- *command = *command | 0x03000000;
- else
- *command = *command | 0x01000000;
-}
-
-static int flex_i2c_read4(struct adapter *adapter, u32 device, u32 chip_addr, u16 addr, u8 *buf, u8 len)
-{
- u32 command;
- u32 value;
-
- int result, i;
-
- i2c_main_setup(device, chip_addr, 1, addr, 0, len, &command);
-
- result = i2c_main_write_for_flex2(adapter, command, buf, 100000);
-
- if ((result & 0xff) != 0) {
- if (len > 1) {
- value = read_reg_dw(adapter, 0x104);
-
- for (i = 1; i < len; i++) {
- buf[i] = value & 0xff;
- value = value >> 8;
- }
- }
- }
-
- return result;
-}
-
-static int flex_i2c_write4(struct adapter *adapter, u32 device, u32 chip_addr, u32 addr, u8 *buf, u8 len)
-{
- u32 command;
- u32 value;
- int i;
-
- if (len > 1) {
- value = 0;
-
- for (i = len; i > 1; i--) {
- value = value << 8;
- value = value | buf[i - 1];
- }
-
- write_reg_dw(adapter, 0x104, value);
- }
-
- i2c_main_setup(device, chip_addr, 0, addr, buf[0], len, &command);
-
- return i2c_main_write_for_flex2(adapter, command, NULL, 100000);
-}
-
-static void fixchipaddr(u32 device, u32 bus, u32 addr, u32 *ret)
-{
- if (device == 0x20000000)
- *ret = bus | ((addr >> 8) & 3);
- else
- *ret = bus;
-}
-
-static u32 flex_i2c_read(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
- u32 chipaddr;
- u32 bytes_to_transfer;
- u8 *start;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- start = buf;
-
- while (len != 0) {
- bytes_to_transfer = len;
-
- if (bytes_to_transfer > 4)
- bytes_to_transfer = 4;
-
- fixchipaddr(device, bus, addr, &chipaddr);
-
- if (flex_i2c_read4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
- return buf - start;
-
- buf = buf + bytes_to_transfer;
- addr = addr + bytes_to_transfer;
- len = len - bytes_to_transfer;
- };
-
- return buf - start;
-}
-
-static u32 flex_i2c_write(struct adapter *adapter, u32 device, u32 bus, u32 addr, u8 *buf, u32 len)
-{
- u32 chipaddr;
- u32 bytes_to_transfer;
- u8 *start;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- start = buf;
-
- while (len != 0) {
- bytes_to_transfer = len;
-
- if (bytes_to_transfer > 4)
- bytes_to_transfer = 4;
-
- fixchipaddr(device, bus, addr, &chipaddr);
-
- if (flex_i2c_write4(adapter, device, chipaddr, addr, buf, bytes_to_transfer) == 0)
- return buf - start;
-
- buf = buf + bytes_to_transfer;
- addr = addr + bytes_to_transfer;
- len = len - bytes_to_transfer;
- }
-
- return buf - start;
-}
-
-static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msgs, int num)
-{
- struct adapter *tmp = i2c_get_adapdata(adapter);
- int i, ret = 0;
-
- if (down_interruptible(&tmp->i2c_sem))
- return -ERESTARTSYS;
-
- ddprintk("%s: %d messages to transfer\n", __FUNCTION__, num);
-
- for (i = 0; i < num; i++) {
- ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
- }
-
- // read command
- if ((num == 2) && (msgs[0].flags == 0) && (msgs[1].flags == I2C_M_RD) && (msgs[0].buf != NULL) && (msgs[1].buf != NULL)) {
-
- ret = flex_i2c_read(tmp, 0x10000000, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
-
- up(&tmp->i2c_sem);
-
- if (ret != msgs[1].len) {
- dprintk("%s: read error !\n", __FUNCTION__);
-
- for (i = 0; i < 2; i++) {
- dprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
- }
-
- return -EREMOTEIO;
- }
-
- return num;
- }
- // write command
- for (i = 0; i < num; i++) {
-
- if ((msgs[i].flags != 0) || (msgs[i].buf == NULL) || (msgs[i].len < 2))
- return -EINVAL;
-
- ret = flex_i2c_write(tmp, 0x10000000, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
-
- up(&tmp->i2c_sem);
-
- if (ret != msgs[0].len - 1) {
- dprintk("%s: write error %i !\n", __FUNCTION__, ret);
-
- dprintk("message %d: flags=0x%x, addr=0x%x, buf[0]=0x%x, len=%d \n", i,
- msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
-
- return -EREMOTEIO;
- }
-
- return num;
- }
-
- printk("%s: unknown command format !\n", __FUNCTION__);
-
- return -EINVAL;
-}
-
-/* SRAM (Skystar2 rev2.3 has one "ISSI IS61LV256" chip on board,
- but it seems that FlexCopII can work with more than one chip) */
-static void sram_set_net_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xfffffffc) | (dest & 3);
-
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_cai_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xfffffff3) | ((dest & 3) << 2);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_cao_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xffffffcf) | ((dest & 3) << 4);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-static void sram_set_media_dest(struct adapter *adapter, u8 dest)
-{
- u32 tmp;
-
- udelay(1000);
-
- tmp = (read_reg_dw(adapter, 0x714) & 0xffffff3f) | ((dest & 3) << 6);
-
- udelay(1000);
- udelay(1000);
-
- write_reg_dw(adapter, 0x714, tmp);
- write_reg_dw(adapter, 0x714, tmp);
-
- udelay(1000);
-
- /* return value is never used? */
-/* return tmp; */
-}
-
-/* SRAM memory is accessed through a buffer register in the FlexCop
- chip (0x700). This register has the following structure:
- bits 0-14 : address
- bit 15 : read/write flag
- bits 16-23 : 8-bit word to write
- bits 24-27 : = 4
- bits 28-29 : memory bank selector
- bit 31 : busy flag
-*/
-static void flex_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
- int i, retries;
- u32 command;
-
- for (i = 0; i < len; i++) {
- command = bank | addr | 0x04000000 | (*buf << 0x10);
-
- retries = 2;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- write_reg_dw(adapter, 0x700, command);
-
- buf++;
- addr++;
- }
-}
-
-static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
-{
- int i, retries;
- u32 command, value;
-
- for (i = 0; i < len; i++) {
- command = bank | addr | 0x04008000;
-
- retries = 10000;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- write_reg_dw(adapter, 0x700, command);
-
- retries = 10000;
-
- while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
- mdelay(1);
- retries--;
- };
-
- if (retries == 0)
- printk("%s: SRAM timeout\n", __FUNCTION__);
-
- value = read_reg_dw(adapter, 0x700) >> 0x10;
-
- *buf = (value & 0xff);
-
- addr++;
- buf++;
- }
-}
-
-static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
- u32 bank;
-
- bank = 0;
-
- if (adapter->dw_sram_type == 0x20000) {
- bank = (addr & 0x18000) << 0x0d;
- }
-
- if (adapter->dw_sram_type == 0x00000) {
- if ((addr >> 0x0f) == 0)
- bank = 0x20000000;
- else
- bank = 0x10000000;
- }
-
- flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
-{
- u32 bank;
-
- bank = 0;
-
- if (adapter->dw_sram_type == 0x20000) {
- bank = (addr & 0x18000) << 0x0d;
- }
-
- if (adapter->dw_sram_type == 0x00000) {
- if ((addr >> 0x0f) == 0)
- bank = 0x20000000;
- else
- bank = 0x10000000;
- }
-
- flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
-}
-
-static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
- u32 length;
-
- while (len != 0) {
- length = len;
-
- // check if the address range belongs to the same
- // 32K memory chip. If not, the data is read from
- // one chip at a time.
- if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
- length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
- }
-
- sram_read_chunk(adapter, addr, buf, length);
-
- addr = addr + length;
- buf = buf + length;
- len = len - length;
- }
-}
-
-static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
-{
- u32 length;
-
- while (len != 0) {
- length = len;
-
- // check if the address range belongs to the same
- // 32K memory chip. If not, the data is written to
- // one chip at a time.
- if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
- length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
- }
-
- sram_write_chunk(adapter, addr, buf, length);
-
- addr = addr + length;
- buf = buf + length;
- len = len - length;
- }
-}
-
-static void sram_set_size(struct adapter *adapter, u32 mask)
-{
- write_reg_dw(adapter, 0x71c, (mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
-}
-
-static void sram_init(struct adapter *adapter)
-{
- u32 tmp;
-
- tmp = read_reg_dw(adapter, 0x71c);
-
- write_reg_dw(adapter, 0x71c, 1);
-
- if (read_reg_dw(adapter, 0x71c) != 0) {
- write_reg_dw(adapter, 0x71c, tmp);
-
- adapter->dw_sram_type = tmp & 0x30000;
-
- ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
-
- } else {
-
- adapter->dw_sram_type = 0x10000;
-
- ddprintk("%s: dw_sram_type = %x\n", __FUNCTION__, adapter->dw_sram_type);
- }
-
- /* return value is never used? */
-/* return adapter->dw_sram_type; */
-}
-
-static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
-{
- u8 tmp1, tmp2;
-
- dprintk("%s: mask = %x, addr = %x\n", __FUNCTION__, mask, addr);
-
- sram_set_size(adapter, mask);
- sram_init(adapter);
-
- tmp2 = 0xa5;
- tmp1 = 0x4f;
-
- sram_write(adapter, addr, &tmp2, 1);
- sram_write(adapter, addr + 4, &tmp1, 1);
-
- tmp2 = 0;
-
- mdelay(20);
-
- sram_read(adapter, addr, &tmp2, 1);
- sram_read(adapter, addr, &tmp2, 1);
-
- dprintk("%s: wrote 0xa5, read 0x%2x\n", __FUNCTION__, tmp2);
-
- if (tmp2 != 0xa5)
- return 0;
-
- tmp2 = 0x5a;
- tmp1 = 0xf4;
-
- sram_write(adapter, addr, &tmp2, 1);
- sram_write(adapter, addr + 4, &tmp1, 1);
-
- tmp2 = 0;
-
- mdelay(20);
-
- sram_read(adapter, addr, &tmp2, 1);
- sram_read(adapter, addr, &tmp2, 1);
-
- dprintk("%s: wrote 0x5a, read 0x%2x\n", __FUNCTION__, tmp2);
-
- if (tmp2 != 0x5a)
- return 0;
-
- return 1;
-}
-
-static u32 sram_length(struct adapter *adapter)
-{
- if (adapter->dw_sram_type == 0x10000)
- return 32768; // 32K
- if (adapter->dw_sram_type == 0x00000)
- return 65536; // 64K
- if (adapter->dw_sram_type == 0x20000)
- return 131072; // 128K
-
- return 32768; // 32K
-}
-
-/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
- - for 128K there are 4x32K chips at bank 0,1,2,3.
- - for 64K there are 2x32K chips at bank 1,2.
- - for 32K there is one 32K chip at bank 0.
-
- FlexCop works only with one bank at a time. The bank is selected
- by bits 28-29 of the 0x700 register.
-
- bank 0 covers addresses 0x00000-0x07fff
- bank 1 covers addresses 0x08000-0x0ffff
- bank 2 covers addresses 0x10000-0x17fff
- bank 3 covers addresses 0x18000-0x1ffff
-*/
-static int sram_detect_for_flex2(struct adapter *adapter)
-{
- u32 tmp, tmp2, tmp3;
-
- dprintk("%s:\n", __FUNCTION__);
-
- tmp = read_reg_dw(adapter, 0x208);
- write_reg_dw(adapter, 0x208, 0);
-
- tmp2 = read_reg_dw(adapter, 0x71c);
-
- dprintk("%s: tmp2 = %x\n", __FUNCTION__, tmp2);
-
- write_reg_dw(adapter, 0x71c, 1);
-
- tmp3 = read_reg_dw(adapter, 0x71c);
-
- dprintk("%s: tmp3 = %x\n", __FUNCTION__, tmp3);
-
- write_reg_dw(adapter, 0x71c, tmp2);
-
- // check for internal SRAM ???
- tmp3--;
- if (tmp3 != 0) {
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
- return 32;
- }
-
- if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
- sram_set_size(adapter, 0x20000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 128K\n", __FUNCTION__);
-
- return 128;
- }
-
- if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
- sram_set_size(adapter, 0x00000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 64K\n", __FUNCTION__);
-
- return 64;
- }
-
- if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: sram size = 32K\n", __FUNCTION__);
-
- return 32;
- }
-
- sram_set_size(adapter, 0x10000);
- sram_init(adapter);
- write_reg_dw(adapter, 0x208, tmp);
-
- dprintk("%s: SRAM detection failed. Set to 32K \n", __FUNCTION__);
-
- return 0;
-}
-
-static void sll_detect_sram_size(struct adapter *adapter)
-{
- sram_detect_for_flex2(adapter);
-}
-
-/* EEPROM (Skystar2 has one "24LC08B" chip on board) */
-/*
-static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
- return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-*/
-
-static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
-{
- return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len);
-}
-
-static u8 calc_lrc(u8 *buf, int len)
-{
- int i;
- u8 sum;
-
- sum = 0;
-
- for (i = 0; i < len; i++)
- sum = sum ^ buf[i];
-
- return sum;
-}
-
-static int eeprom_lrc_read(struct adapter *adapter, u32 addr, u32 len, u8 *buf, int retries)
-{
- int i;
-
- for (i = 0; i < retries; i++) {
- if (eeprom_read(adapter, addr, buf, len) == len) {
- if (calc_lrc(buf, len - 1) == buf[len - 1])
- return 1;
- }
- }
-
- return 0;
-}
-
-/*
-static int eeprom_lrc_write(struct adapter *adapter, u32 addr, u32 len, u8 *wbuf, u8 *rbuf, int retries)
-{
- int i;
-
- for (i = 0; i < retries; i++) {
- if (eeprom_write(adapter, addr, wbuf, len) == len) {
- if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
- return 1;
- }
- }
-
- return 0;
-}
-*/
-
-
-/* These functions could be used to unlock SkyStar2 cards. */
-
-/*
-static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
-{
- u8 rbuf[20];
- u8 wbuf[20];
-
- if (len != 16)
- return 0;
-
- memcpy(wbuf, key, len);
-
- wbuf[16] = 0;
- wbuf[17] = 0;
- wbuf[18] = 0;
- wbuf[19] = calc_lrc(wbuf, 19);
-
- return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
-}
-
-static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
-{
- u8 buf[20];
-
- if (len != 16)
- return 0;
-
- if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
- return 0;
-
- memcpy(key, buf, len);
-
- return 1;
-}
-*/
-
-static int eeprom_get_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
- u8 tmp[8];
-
- if (eeprom_lrc_read(adapter, 0x3f8, 8, tmp, 4) != 0) {
- if (type != 0) {
- mac[0] = tmp[0];
- mac[1] = tmp[1];
- mac[2] = tmp[2];
- mac[3] = 0xfe;
- mac[4] = 0xff;
- mac[5] = tmp[3];
- mac[6] = tmp[4];
- mac[7] = tmp[5];
-
- } else {
-
- mac[0] = tmp[0];
- mac[1] = tmp[1];
- mac[2] = tmp[2];
- mac[3] = tmp[3];
- mac[4] = tmp[4];
- mac[5] = tmp[5];
- }
-
- return 1;
-
- } else {
-
- if (type == 0) {
- memset(mac, 0, 6);
-
- } else {
-
- memset(mac, 0, 8);
- }
-
- return 0;
- }
-}
-
-/*
-static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
-{
- u8 tmp[8];
-
- if (type != 0) {
- tmp[0] = mac[0];
- tmp[1] = mac[1];
- tmp[2] = mac[2];
- tmp[3] = mac[5];
- tmp[4] = mac[6];
- tmp[5] = mac[7];
-
- } else {
-
- tmp[0] = mac[0];
- tmp[1] = mac[1];
- tmp[2] = mac[2];
- tmp[3] = mac[3];
- tmp[4] = mac[4];
- tmp[5] = mac[5];
- }
-
- tmp[6] = 0;
- tmp[7] = calc_lrc(tmp, 7);
-
- if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
- return 1;
-
- return 0;
-}
-*/
-
-/* PID filter */
-
-/* every flexcop has 6 "lower" hw PID filters */
-/* these are enabled by setting bits 0-5 of 0x208 */
-/* for the 32 additional filters we have to select one */
-/* of them through 0x310 and modify through 0x314 */
-/* op: 0=disable, 1=enable */
-static void filter_enable_hw_filter(struct adapter *adapter, int id, u8 op)
-{
- dprintk("%s: id=%d op=%d\n", __FUNCTION__, id, op);
- if (id <= 5) {
- u32 mask = (0x00000001 << id);
- write_reg_bitfield(adapter, 0x208, mask, op ? mask : 0);
- } else {
- /* select */
- write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
- /* modify */
- write_reg_bitfield(adapter, 0x314, 0x00006000, op ? 0x00004000 : 0);
- }
-}
-
-/* this sets the PID that should pass the specified filter */
-static void pid_set_hw_pid(struct adapter *adapter, int id, u16 pid)
-{
- dprintk("%s: id=%d pid=%d\n", __FUNCTION__, id, pid);
- if (id <= 5) {
- u32 adr = 0x300 + ((id & 6) << 1);
- int shift = (id & 1) ? 16 : 0;
- dprintk("%s: id=%d addr=%x %c pid=%d\n", __FUNCTION__, id, adr, (id & 1) ? 'h' : 'l', pid);
- write_reg_bitfield(adapter, adr, (0x7fff) << shift, (pid & 0x1fff) << shift);
- } else {
- /* select */
- write_reg_bitfield(adapter, 0x310, 0x1f, (id - 6) & 0x1f);
- /* modify */
- write_reg_bitfield(adapter, 0x314, 0x1fff, pid & 0x1fff);
- }
-}
-
-
-/*
-static void filter_enable_null_filter(struct adapter *adapter, u32 op)
-{
- dprintk("%s: op=%x\n", __FUNCTION__, op);
-
- write_reg_bitfield(adapter, 0x208, 0x00000040, op?0x00000040:0);
-}
-*/
-
-static void filter_enable_mask_filter(struct adapter *adapter, u32 op)
-{
- dprintk("%s: op=%x\n", __FUNCTION__, op);
-
- write_reg_bitfield(adapter, 0x208, 0x00000080, op ? 0x00000080 : 0);
-}
-
-
-static void ctrl_enable_mac(struct adapter *adapter, u32 op)
-{
- write_reg_bitfield(adapter, 0x208, 0x00004000, op ? 0x00004000 : 0);
-}
-
-static int ca_set_mac_dst_addr_filter(struct adapter *adapter, u8 *mac)
-{
- u32 tmp1, tmp2;
-
- tmp1 = (mac[3] << 0x18) | (mac[2] << 0x10) | (mac[1] << 0x08) | mac[0];
- tmp2 = (mac[5] << 0x08) | mac[4];
-
- write_reg_dw(adapter, 0x418, tmp1);
- write_reg_dw(adapter, 0x41c, tmp2);
-
- return 0;
-}
-
-/*
-static void set_ignore_mac_filter(struct adapter *adapter, u8 op)
-{
- if (op != 0) {
- write_reg_bitfield(adapter, 0x208, 0x00004000, 0);
- adapter->mac_filter = 1;
- } else {
- if (adapter->mac_filter != 0) {
- adapter->mac_filter = 0;
- write_reg_bitfield(adapter, 0x208, 0x00004000, 0x00004000);
- }
- }
-}
-*/
-
-/*
-static void check_null_filter_enable(struct adapter *adapter)
-{
- filter_enable_null_filter(adapter, 1);
- filter_enable_mask_filter(adapter, 1);
-}
-*/
-
-static void pid_set_group_pid(struct adapter *adapter, u16 pid)
-{
- u32 value;
-
- dprintk("%s: pid=%x\n", __FUNCTION__, pid);
- value = (pid & 0x3fff) | (read_reg_dw(adapter, 0x30c) & 0xffff0000);
- write_reg_dw(adapter, 0x30c, value);
-}
-
-static void pid_set_group_mask(struct adapter *adapter, u16 pid)
-{
- u32 value;
-
- dprintk("%s: pid=%x\n", __FUNCTION__, pid);
- value = ((pid & 0x3fff) << 0x10) | (read_reg_dw(adapter, 0x30c) & 0xffff);
- write_reg_dw(adapter, 0x30c, value);
-}
-
-/*
-static int pid_get_group_pid(struct adapter *adapter)
-{
- return read_reg_dw(adapter, 0x30c) & 0x00001fff;
-}
-
-static int pid_get_group_mask(struct adapter *adapter)
-{
- return (read_reg_dw(adapter, 0x30c) >> 0x10)& 0x00001fff;
-}
-*/
-
-/*
-static void reset_hardware_pid_filter(struct adapter *adapter)
-{
- pid_set_stream1_pid(adapter, 0x1fff);
-
- pid_set_stream2_pid(adapter, 0x1fff);
- filter_enable_stream2_filter(adapter, 0);
-
- pid_set_pcr_pid(adapter, 0x1fff);
- filter_enable_pcr_filter(adapter, 0);
-
- pid_set_pmt_pid(adapter, 0x1fff);
- filter_enable_pmt_filter(adapter, 0);
-
- pid_set_ecm_pid(adapter, 0x1fff);
- filter_enable_ecm_filter(adapter, 0);
-
- pid_set_emm_pid(adapter, 0x1fff);
- filter_enable_emm_filter(adapter, 0);
-}
-*/
-
-static void init_pids(struct adapter *adapter)
-{
- int i;
-
- adapter->pid_count = 0;
- adapter->whole_bandwidth_count = 0;
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: setting filter %d to 0x1fff\n", __FUNCTION__, i);
- adapter->hw_pids[i] = 0x1fff;
- pid_set_hw_pid(adapter, i, 0x1fff);
-}
-
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0x1fe0);
-}
-
-static void open_whole_bandwidth(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0);
-/*
- filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void close_whole_bandwidth(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
- pid_set_group_pid(adapter, 0);
- pid_set_group_mask(adapter, 0x1fe0);
-/*
- filter_enable_mask_filter(adapter, 1);
-*/
-}
-
-static void whole_bandwidth_inc(struct adapter *adapter)
-{
- if (adapter->whole_bandwidth_count++ == 0)
- open_whole_bandwidth(adapter);
-}
-
-static void whole_bandwidth_dec(struct adapter *adapter)
-{
- if (--adapter->whole_bandwidth_count <= 0)
- close_whole_bandwidth(adapter);
-}
-
-/* The specified PID has to be let through the
- hw filters.
- We try to allocate an hardware filter and open whole
- bandwidth when allocation is impossible.
- All pids<=0x1f pass through the group filter.
- Returns 1 on success, -1 on error */
-static int add_hw_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid <= 0x1f)
- return 1;
-
- /* we can't use a filter for 0x2000, so no search */
- if (pid != 0x2000) {
- /* find an unused hardware filter */
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
- if (adapter->hw_pids[i] == 0x1fff) {
- dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
- adapter->hw_pids[i] = pid;
- pid_set_hw_pid(adapter, i, pid);
- filter_enable_hw_filter(adapter, i, 1);
- return 1;
- }
- }
- }
- /* if we have not used a filter, this pid depends on whole bandwidth */
- dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
- whole_bandwidth_inc(adapter);
- return 1;
- }
-
-/* returns -1 if the pid was not present in the filters */
-static int remove_hw_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid <= 0x1f)
- return 1;
-
- /* we can't use a filter for 0x2000, so no search */
- if (pid != 0x2000) {
- for (i = 0; i < adapter->useable_hw_filters; i++) {
- dprintk("%s: pid=%d searching slot=%d\n", __FUNCTION__, pid, i);
- if (adapter->hw_pids[i] == pid) { // find the pid slot
- dprintk("%s: pid=%d slot=%d\n", __FUNCTION__, pid, i);
- adapter->hw_pids[i] = 0x1fff;
- pid_set_hw_pid(adapter, i, 0x1fff);
- filter_enable_hw_filter(adapter, i, 0);
- return 1;
- }
- }
- }
- /* if we have not used a filter, this pid depended on whole bandwith */
- dprintk("%s: pid=%d whole_bandwidth\n", __FUNCTION__, pid);
- whole_bandwidth_dec(adapter);
- return 1;
- }
-
-/* Adds a PID to the filters.
- Adding a pid more than once is possible, we keep reference counts.
- Whole stream available through pid==0x2000.
- Returns 1 on success, -1 on error */
-static int add_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid > 0x1ffe && pid != 0x2000)
- return -1;
-
- // check if the pid is already present
- for (i = 0; i < adapter->pid_count; i++)
- if (adapter->pid_list[i] == pid) {
- adapter->pid_rc[i]++; // increment ref counter
- return 1;
- }
-
- if (adapter->pid_count == N_PID_SLOTS)
- return -1; // no more pids can be added
- adapter->pid_list[adapter->pid_count] = pid; // register pid
- adapter->pid_rc[adapter->pid_count] = 1;
- adapter->pid_count++;
- // hardware setting
- add_hw_pid(adapter, pid);
-
- return 1;
- }
-
-/* Removes a PID from the filters. */
-static int remove_pid(struct adapter *adapter, u16 pid)
-{
- int i;
-
- dprintk("%s: pid=%d\n", __FUNCTION__, pid);
-
- if (pid > 0x1ffe && pid != 0x2000)
- return -1;
-
- // check if the pid is present (it must be!)
- for (i = 0; i < adapter->pid_count; i++) {
- if (adapter->pid_list[i] == pid) {
- adapter->pid_rc[i]--;
- if (adapter->pid_rc[i] <= 0) {
- // remove from the list
- adapter->pid_count--;
- adapter->pid_list[i]=adapter->pid_list[adapter->pid_count];
- adapter->pid_rc[i] = adapter->pid_rc[adapter->pid_count];
- // hardware setting
- remove_hw_pid(adapter, pid);
- }
- return 1;
- }
- }
-
- return -1;
-}
-
-
-/* dma & irq */
-static void ctrl_enable_smc(struct adapter *adapter, u32 op)
-{
- write_reg_bitfield(adapter, 0x208, 0x00000800, op ? 0x00000800 : 0);
-}
-
-static void dma_enable_disable_irq(struct adapter *adapter, u32 flag1, u32 flag2, u32 flag3)
-{
- adapter->dma_ctrl = adapter->dma_ctrl & 0x000f0000;
-
- if (flag1 == 0) {
- if (flag2 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00010000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00010000;
-
- if (flag3 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00020000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00020000;
-
- } else {
-
- if (flag2 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00040000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00040000;
-
- if (flag3 == 0)
- adapter->dma_ctrl = adapter->dma_ctrl & ~0x00080000;
- else
- adapter->dma_ctrl = adapter->dma_ctrl | 0x00080000;
- }
-}
-
-static void irq_dma_enable_disable_irq(struct adapter *adapter, u32 op)
-{
- u32 value;
-
- value = read_reg_dw(adapter, 0x208) & 0xfff0ffff;
-
- if (op != 0)
- value = value | (adapter->dma_ctrl & 0x000f0000);
-
- write_reg_dw(adapter, 0x208, value);
-}
-
-/* FlexCopII has 2 dma channels. DMA1 is used to transfer TS data to
- system memory.
-
- The DMA1 buffer is divided in 2 subbuffers of equal size.
- FlexCopII will transfer TS data to one subbuffer, signal an interrupt
- when the subbuffer is full and continue fillig the second subbuffer.
-
- For DMA1:
- subbuffer size in 32-bit words is stored in the first 24 bits of
- register 0x004. The last 8 bits of register 0x004 contain the number
- of subbuffers.
-
- the first 30 bits of register 0x000 contain the address of the first
- subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
- when dma1 is enabled.
-
- the first 30 bits of register 0x00c contain the address of the second
- subbuffer. the last 2 bits contain 1.
-
- register 0x008 will contain the address of the subbuffer that was filled
- with TS data, when FlexCopII will generate an interrupt.
-
- For DMA2:
- subbuffer size in 32-bit words is stored in the first 24 bits of
- register 0x014. The last 8 bits of register 0x014 contain the number
- of subbuffers.
-
- the first 30 bits of register 0x010 contain the address of the first
- subbuffer. The last 2 bits contain 0, when dma1 is disabled and 1,
- when dma1 is enabled.
-
- the first 30 bits of register 0x01c contain the address of the second
- subbuffer. the last 2 bits contain 1.
-
- register 0x018 contains the address of the subbuffer that was filled
- with TS data, when FlexCopII generates an interrupt.
-*/
-static int dma_init_dma(struct adapter *adapter, u32 dma_channel)
-{
- u32 subbuffers, subbufsize, subbuf0, subbuf1;
-
- if (dma_channel == 0) {
- dprintk("%s: Initializing DMA1 channel\n", __FUNCTION__);
-
- subbuffers = 2;
-
- subbufsize = (((adapter->dmaq1.buffer_size / 2) / 4) << 8) | subbuffers;
-
- subbuf0 = adapter->dmaq1.bus_addr & 0xfffffffc;
-
- subbuf1 = ((adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) & 0xfffffffc) | 1;
-
- dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
- udelay(1000);
- write_reg_dw(adapter, 0x000, subbuf0);
-
- dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
- udelay(1000);
- write_reg_dw(adapter, 0x004, subbufsize);
-
- dprintk("%s: second subbuffer address = 0x%x\n", __FUNCTION__, subbuf1);
- udelay(1000);
- write_reg_dw(adapter, 0x00c, subbuf1);
-
- dprintk("%s: counter = 0x%x\n", __FUNCTION__, adapter->dmaq1.bus_addr & 0xfffffffc);
- write_reg_dw(adapter, 0x008, adapter->dmaq1.bus_addr & 0xfffffffc);
- udelay(1000);
-
- dma_enable_disable_irq(adapter, 0, 1, subbuffers ? 1 : 0);
-
- irq_dma_enable_disable_irq(adapter, 1);
-
- sram_set_media_dest(adapter, 1);
- sram_set_net_dest(adapter, 1);
- sram_set_cai_dest(adapter, 2);
- sram_set_cao_dest(adapter, 2);
- }
-
- if (dma_channel == 1) {
- dprintk("%s: Initializing DMA2 channel\n", __FUNCTION__);
-
- subbuffers = 2;
-
- subbufsize = (((adapter->dmaq2.buffer_size / 2) / 4) << 8) | subbuffers;
-
- subbuf0 = adapter->dmaq2.bus_addr & 0xfffffffc;
-
- subbuf1 = ((adapter->dmaq2.bus_addr + adapter->dmaq2.buffer_size / 2) & 0xfffffffc) | 1;
-
- dprintk("%s: first subbuffer address = 0x%x\n", __FUNCTION__, subbuf0);
- udelay(1000);
- write_reg_dw(adapter, 0x010, subbuf0);
-
- dprintk("%s: subbuffer size = 0x%x\n", __FUNCTION__, (subbufsize >> 8) * 4);
- udelay(1000);
- write_reg_dw(adapter, 0x014, subbufsize);
-
- dprintk("%s: second buffer address = 0x%x\n", __FUNCTION__, subbuf1);
- udelay(1000);
- write_reg_dw(adapter, 0x01c, subbuf1);
-
- sram_set_cai_dest(adapter, 2);
- }
-
- return 0;
-}
-
-static void ctrl_enable_receive_data(struct adapter *adapter, u32 op)
-{
- if (op == 0) {
- write_reg_bitfield(adapter, 0x208, 0x00008000, 0);
- adapter->dma_status = adapter->dma_status & ~0x00000004;
- } else {
- write_reg_bitfield(adapter, 0x208, 0x00008000, 0x00008000);
- adapter->dma_status = adapter->dma_status | 0x00000004;
- }
-}
-
-/* bit 0 of dma_mask is set to 1 if dma1 channel has to be enabled/disabled
- bit 1 of dma_mask is set to 1 if dma2 channel has to be enabled/disabled
-*/
-static void dma_start_stop(struct adapter *adapter, u32 dma_mask, int start_stop)
-{
- u32 dma_enable, dma1_enable, dma2_enable;
-
- dprintk("%s: dma_mask=%x\n", __FUNCTION__, dma_mask);
-
- if (start_stop == 1) {
- dprintk("%s: starting dma\n", __FUNCTION__);
-
- dma1_enable = 0;
- dma2_enable = 0;
-
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) == 0) && (adapter->dmaq1.bus_addr != 0)) {
- adapter->dma_status = adapter->dma_status | 1;
- dma1_enable = 1;
- }
-
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) == 0) && (adapter->dmaq2.bus_addr != 0)) {
- adapter->dma_status = adapter->dma_status | 2;
- dma2_enable = 1;
- }
- // enable dma1 and dma2
- if ((dma1_enable == 1) && (dma2_enable == 1)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // enable dma1
- if ((dma1_enable == 1) && (dma2_enable == 0)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr | 1);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // enable dma2
- if ((dma1_enable == 0) && (dma2_enable == 1)) {
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr | 1);
-
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
- // start dma
- if ((dma1_enable == 0) && (dma2_enable == 0)) {
- ctrl_enable_receive_data(adapter, 1);
-
- return;
- }
-
- } else {
-
- dprintk("%s: stopping dma\n", __FUNCTION__);
-
- dma_enable = adapter->dma_status & 0x00000003;
-
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0)) {
- dma_enable = dma_enable & 0xfffffffe;
- }
-
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0)) {
- dma_enable = dma_enable & 0xfffffffd;
- }
- //stop dma
- if ((dma_enable == 0) && ((adapter->dma_status & 4) != 0)) {
- ctrl_enable_receive_data(adapter, 0);
-
- udelay(3000);
- }
- //disable dma1
- if (((dma_mask & 1) != 0) && ((adapter->dma_status & 1) != 0) && (adapter->dmaq1.bus_addr != 0)) {
- write_reg_dw(adapter, 0x000, adapter->dmaq1.bus_addr);
- write_reg_dw(adapter, 0x00c, (adapter->dmaq1.bus_addr + adapter->dmaq1.buffer_size / 2) | 1);
-
- adapter->dma_status = adapter->dma_status & ~0x00000001;
- }
- //disable dma2
- if (((dma_mask & 2) != 0) && ((adapter->dma_status & 2) != 0) && (adapter->dmaq2.bus_addr != 0)) {
- write_reg_dw(adapter, 0x010, adapter->dmaq2.bus_addr);
-
- adapter->dma_status = adapter->dma_status & ~0x00000002;
- }
- }
-}
-
-static void open_stream(struct adapter *adapter, u16 pid)
-{
- u32 dma_mask;
-
- ++adapter->capturing;
-
- filter_enable_mask_filter(adapter, 1);
-
- add_pid(adapter, pid);
-
- dprintk("%s: adapter->dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
- if ((adapter->dma_status & 7) != 7) {
- dma_mask = 0;
-
- if (((adapter->dma_status & 0x10000000) != 0) && ((adapter->dma_status & 1) == 0)) {
- dma_mask = dma_mask | 1;
-
- adapter->dmaq1.head = 0;
- adapter->dmaq1.tail = 0;
-
- memset(adapter->dmaq1.buffer, 0, adapter->dmaq1.buffer_size);
- }
-
- if (((adapter->dma_status & 0x20000000) != 0) && ((adapter->dma_status & 2) == 0)) {
- dma_mask = dma_mask | 2;
-
- adapter->dmaq2.head = 0;
- adapter->dmaq2.tail = 0;
- }
-
- if (dma_mask != 0) {
- irq_dma_enable_disable_irq(adapter, 1);
-
- dma_start_stop(adapter, dma_mask, 1);
- }
- }
-}
-
-static void close_stream(struct adapter *adapter, u16 pid)
-{
- if (adapter->capturing > 0)
- --adapter->capturing;
-
- dprintk("%s: dma_status=%x\n", __FUNCTION__, adapter->dma_status);
-
- if (adapter->capturing == 0) {
- u32 dma_mask = 0;
-
- if ((adapter->dma_status & 1) != 0)
- dma_mask = dma_mask | 0x00000001;
- if ((adapter->dma_status & 2) != 0)
- dma_mask = dma_mask | 0x00000002;
-
- if (dma_mask != 0) {
- dma_start_stop(adapter, dma_mask, 0);
- }
- }
- remove_pid(adapter, pid);
-}
-
-static void interrupt_service_dma1(struct adapter *adapter)
-{
- struct dvb_demux *dvbdmx = &adapter->demux;
-
- int n_cur_dma_counter;
- u32 n_num_bytes_parsed;
- u32 n_num_new_bytes_transferred;
- u32 dw_default_packet_size = 188;
- u8 gb_tmp_buffer[188];
- u8 *pb_dma_buf_cur_pos;
-
- n_cur_dma_counter = readl(adapter->io_mem + 0x008) - adapter->dmaq1.bus_addr;
- n_cur_dma_counter = (n_cur_dma_counter / dw_default_packet_size) * dw_default_packet_size;
-
- if ((n_cur_dma_counter < 0) || (n_cur_dma_counter > adapter->dmaq1.buffer_size)) {
- dprintk("%s: dma counter outside dma buffer\n", __FUNCTION__);
- return;
- }
-
- adapter->dmaq1.head = n_cur_dma_counter;
-
- if (adapter->dmaq1.tail <= n_cur_dma_counter) {
- n_num_new_bytes_transferred = n_cur_dma_counter - adapter->dmaq1.tail;
-
- } else {
-
- n_num_new_bytes_transferred = (adapter->dmaq1.buffer_size - adapter->dmaq1.tail) + n_cur_dma_counter;
- }
-
- ddprintk("%s: n_cur_dma_counter = %d\n", __FUNCTION__, n_cur_dma_counter);
- ddprintk("%s: dmaq1.tail = %d\n", __FUNCTION__, adapter->dmaq1.tail);
- ddprintk("%s: bytes_transferred = %d\n", __FUNCTION__, n_num_new_bytes_transferred);
-
- if (n_num_new_bytes_transferred < dw_default_packet_size)
- return;
-
- n_num_bytes_parsed = 0;
-
- while (n_num_bytes_parsed < n_num_new_bytes_transferred) {
- pb_dma_buf_cur_pos = adapter->dmaq1.buffer + adapter->dmaq1.tail;
-
- if (adapter->dmaq1.buffer + adapter->dmaq1.buffer_size < adapter->dmaq1.buffer + adapter->dmaq1.tail + 188) {
- memcpy(gb_tmp_buffer, adapter->dmaq1.buffer + adapter->dmaq1.tail,
- adapter->dmaq1.buffer_size - adapter->dmaq1.tail);
- memcpy(gb_tmp_buffer + (adapter->dmaq1.buffer_size - adapter->dmaq1.tail), adapter->dmaq1.buffer,
- (188 - (adapter->dmaq1.buffer_size - adapter->dmaq1.tail)));
-
- pb_dma_buf_cur_pos = gb_tmp_buffer;
- }
-
- if (adapter->capturing != 0) {
- dvb_dmx_swfilter_packets(dvbdmx, pb_dma_buf_cur_pos, dw_default_packet_size / 188);
- }
-
- n_num_bytes_parsed = n_num_bytes_parsed + dw_default_packet_size;
-
- adapter->dmaq1.tail = adapter->dmaq1.tail + dw_default_packet_size;
-
- if (adapter->dmaq1.tail >= adapter->dmaq1.buffer_size)
- adapter->dmaq1.tail = adapter->dmaq1.tail - adapter->dmaq1.buffer_size;
- };
-}
-
-static void interrupt_service_dma2(struct adapter *adapter)
-{
- printk("%s:\n", __FUNCTION__);
-}
-
-static irqreturn_t isr(int irq, void *dev_id, struct pt_regs *regs)
-{
- struct adapter *tmp = dev_id;
-
- u32 value;
-
- ddprintk("%s:\n", __FUNCTION__);
-
- spin_lock_irq(&tmp->lock);
-
- if (0 == ((value = read_reg_dw(tmp, 0x20c)) & 0x0f)) {
- spin_unlock_irq(&tmp->lock);
- return IRQ_NONE;
- }
-
- while (value != 0) {
- if ((value & 0x03) != 0)
- interrupt_service_dma1(tmp);
- if ((value & 0x0c) != 0)
- interrupt_service_dma2(tmp);
- value = read_reg_dw(tmp, 0x20c) & 0x0f;
- }
-
- spin_unlock_irq(&tmp->lock);
- return IRQ_HANDLED;
-}
-
-static int init_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq,
- int size, int dmaq_offset)
-{
- struct pci_dev *pdev = adapter->pdev;
- dma_addr_t dma_addr;
-
- dmaq->head = 0;
- dmaq->tail = 0;
-
- dmaq->buffer = pci_alloc_consistent(pdev, size + 0x80, &dma_addr);
- if (!dmaq->buffer)
- return -ENOMEM;
-
- dmaq->bus_addr = dma_addr;
- dmaq->buffer_size = size;
-
- dma_init_dma(adapter, dmaq_offset);
-
- ddprintk("%s: allocated dma buffer at 0x%p, length=%d\n",
- __FUNCTION__, dmaq->buffer, size);
-
- return 0;
- }
-
-static int init_dma_queue(struct adapter *adapter)
-{
- struct {
- struct dmaq *dmaq;
- u32 dma_status;
- int size;
- } dmaq_desc[] = {
- { &adapter->dmaq1, 0x10000000, SIZE_OF_BUF_DMA1 },
- { &adapter->dmaq2, 0x20000000, SIZE_OF_BUF_DMA2 }
- }, *p = dmaq_desc;
- int i;
-
- for (i = 0; i < 2; i++, p++) {
- if (init_dma_queue_one(adapter, p->dmaq, p->size, i) < 0)
- adapter->dma_status &= ~p->dma_status;
- else
- adapter->dma_status |= p->dma_status;
- }
- return (adapter->dma_status & 0x30000000) ? 0 : -ENOMEM;
-}
-
-static void free_dma_queue_one(struct adapter *adapter, struct dmaq *dmaq)
-{
- if (dmaq->buffer) {
- pci_free_consistent(adapter->pdev, dmaq->buffer_size + 0x80,
- dmaq->buffer, dmaq->bus_addr);
- memset(dmaq, 0, sizeof(*dmaq));
- }
-}
-
-static void free_dma_queue(struct adapter *adapter)
-{
- struct dmaq *dmaq[] = {
- &adapter->dmaq1,
- &adapter->dmaq2,
- NULL
- }, **p;
-
- for (p = dmaq; *p; p++)
- free_dma_queue_one(adapter, *p);
- }
-
-static void release_adapter(struct adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
-
- iounmap(adapter->io_mem);
- pci_disable_device(pdev);
- pci_release_region(pdev, 0);
- pci_release_region(pdev, 1);
-}
-
-static void free_adapter_object(struct adapter *adapter)
-{
- dprintk("%s:\n", __FUNCTION__);
-
- close_stream(adapter, 0);
- free_irq(adapter->irq, adapter);
- free_dma_queue(adapter);
- release_adapter(adapter);
- kfree(adapter);
-}
-
-static struct pci_driver skystar2_pci_driver;
-
-static int claim_adapter(struct adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
- u16 var;
- int ret;
-
- ret = pci_request_region(pdev, 1, skystar2_pci_driver.name);
- if (ret < 0)
- goto out;
-
- ret = pci_request_region(pdev, 0, skystar2_pci_driver.name);
- if (ret < 0)
- goto err_pci_release_1;
-
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &adapter->card_revision);
-
- dprintk("%s: card revision %x \n", __FUNCTION__, adapter->card_revision);
-
- ret = pci_enable_device(pdev);
- if (ret < 0)
- goto err_pci_release_0;
-
- pci_read_config_word(pdev, 4, &var);
-
- if ((var & 4) == 0)
- pci_set_master(pdev);
-
- adapter->io_port = pdev->resource[1].start;
-
- adapter->io_mem = ioremap(pdev->resource[0].start, 0x800);
-
- if (!adapter->io_mem) {
- dprintk("%s: can not map io memory\n", __FUNCTION__);
- ret = -EIO;
- goto err_pci_disable;
- }
-
- dprintk("%s: io memory maped at %p\n", __FUNCTION__, adapter->io_mem);
-
- ret = 1;
-out:
- return ret;
-
-err_pci_disable:
- pci_disable_device(pdev);
-err_pci_release_0:
- pci_release_region(pdev, 0);
-err_pci_release_1:
- pci_release_region(pdev, 1);
- goto out;
-}
-
-/*
-static int sll_reset_flexcop(struct adapter *adapter)
-{
- write_reg_dw(adapter, 0x208, 0);
- write_reg_dw(adapter, 0x210, 0xb2ff);
-
- return 0;
-}
-*/
-
-static void decide_how_many_hw_filters(struct adapter *adapter)
-{
- int hw_filters;
- int mod_option_hw_filters;
-
- // FlexCop IIb & III have 6+32 hw filters
- // FlexCop II has 6 hw filters, every other should have at least 6
- switch (adapter->b2c2_revision) {
- case 0x82: /* II */
- hw_filters = 6;
- break;
- case 0xc3: /* IIB */
- hw_filters = 6 + 32;
- break;
- case 0xc0: /* III */
- hw_filters = 6 + 32;
- break;
- default:
- hw_filters = 6;
- break;
- }
- printk("%s: the chip has %i hardware filters", __FILE__, hw_filters);
-
- mod_option_hw_filters = 0;
- if (enable_hw_filters >= 1)
- mod_option_hw_filters += 6;
- if (enable_hw_filters >= 2)
- mod_option_hw_filters += 32;
-
- if (mod_option_hw_filters >= hw_filters) {
- adapter->useable_hw_filters = hw_filters;
- } else {
- adapter->useable_hw_filters = mod_option_hw_filters;
- printk(", but only %d will be used because of module option", mod_option_hw_filters);
- }
- printk("\n");
- dprintk("%s: useable_hardware_filters set to %i\n", __FILE__, adapter->useable_hw_filters);
-}
-
-static int driver_initialize(struct pci_dev *pdev)
-{
- struct adapter *adapter;
- u32 tmp;
- int ret = -ENOMEM;
-
- adapter = kmalloc(sizeof(struct adapter), GFP_KERNEL);
- if (!adapter) {
- dprintk("%s: out of memory!\n", __FUNCTION__);
- goto out;
- }
-
- memset(adapter, 0, sizeof(struct adapter));
-
- pci_set_drvdata(pdev,adapter);
-
- adapter->pdev = pdev;
- adapter->irq = pdev->irq;
-
- ret = claim_adapter(adapter);
- if (ret < 0)
- goto err_kfree;
-
- irq_dma_enable_disable_irq(adapter, 0);
-
- ret = request_irq(pdev->irq, isr, 0x4000000, "Skystar2", adapter);
- if (ret < 0) {
- dprintk("%s: unable to allocate irq=%d !\n", __FUNCTION__, pdev->irq);
- goto err_release_adapter;
- }
-
- read_reg_dw(adapter, 0x208);
- write_reg_dw(adapter, 0x208, 0);
- write_reg_dw(adapter, 0x210, 0xb2ff);
- write_reg_dw(adapter, 0x208, 0x40);
-
- ret = init_dma_queue(adapter);
- if (ret < 0)
- goto err_free_irq;
-
- adapter->b2c2_revision = (read_reg_dw(adapter, 0x204) >> 0x18);
-
- switch (adapter->b2c2_revision) {
- case 0x82:
- printk("%s: FlexCopII(rev.130) chip found\n", __FILE__);
- break;
- case 0xc3:
- printk("%s: FlexCopIIB(rev.195) chip found\n", __FILE__);
- break;
- case 0xc0:
- printk("%s: FlexCopIII(rev.192) chip found\n", __FILE__);
- break;
- default:
- printk("%s: The revision of the FlexCop chip on your card is %d\n", __FILE__, adapter->b2c2_revision);
- printk("%s: This driver works only with FlexCopII(rev.130), FlexCopIIB(rev.195) and FlexCopIII(rev.192).\n", __FILE__);
- ret = -ENODEV;
- goto err_free_dma_queue;
- }
-
- decide_how_many_hw_filters(adapter);
-
- init_pids(adapter);
-
- tmp = read_reg_dw(adapter, 0x204);
-
- write_reg_dw(adapter, 0x204, 0);
- mdelay(20);
-
- write_reg_dw(adapter, 0x204, tmp);
- mdelay(10);
-
- tmp = read_reg_dw(adapter, 0x308);
- write_reg_dw(adapter, 0x308, 0x4000 | tmp);
-
- adapter->dw_sram_type = 0x10000;
-
- sll_detect_sram_size(adapter);
-
- dprintk("%s sram length = %d, sram type= %x\n", __FUNCTION__, sram_length(adapter), adapter->dw_sram_type);
-
- sram_set_media_dest(adapter, 1);
- sram_set_net_dest(adapter, 1);
-
- ctrl_enable_smc(adapter, 0);
-
- sram_set_cai_dest(adapter, 2);
- sram_set_cao_dest(adapter, 2);
-
- dma_enable_disable_irq(adapter, 1, 0, 0);
-
- if (eeprom_get_mac_addr(adapter, 0, adapter->mac_addr) != 0) {
- printk("%s MAC address = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x \n", __FUNCTION__, adapter->mac_addr[0],
- adapter->mac_addr[1], adapter->mac_addr[2], adapter->mac_addr[3], adapter->mac_addr[4], adapter->mac_addr[5],
- adapter->mac_addr[6], adapter->mac_addr[7]
- );
-
- ca_set_mac_dst_addr_filter(adapter, adapter->mac_addr);
- ctrl_enable_mac(adapter, 1);
- }
-
- spin_lock_init(&adapter->lock);
-
-out:
- return ret;
-
-err_free_dma_queue:
- free_dma_queue(adapter);
-err_free_irq:
- free_irq(pdev->irq, adapter);
-err_release_adapter:
- release_adapter(adapter);
-err_kfree:
- pci_set_drvdata(pdev, NULL);
- kfree(adapter);
- goto out;
-}
-
-static void driver_halt(struct pci_dev *pdev)
-{
- struct adapter *adapter = pci_get_drvdata(pdev);
-
- irq_dma_enable_disable_irq(adapter, 0);
-
- ctrl_enable_receive_data(adapter, 0);
-
- free_adapter_object(adapter);
-
- pci_set_drvdata(pdev, NULL);
-}
-
-static int dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
- dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
- open_stream(adapter, dvbdmxfeed->pid);
-
- return 0;
-}
-
-static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
- struct adapter *adapter = (struct adapter *) dvbdmx->priv;
-
- dprintk("%s: PID=%d, type=%d\n", __FUNCTION__, dvbdmxfeed->pid, dvbdmxfeed->type);
-
- close_stream(adapter, dvbdmxfeed->pid);
-
- return 0;
-}
-
-/* lnb control */
-static void set_tuner_tone(struct adapter *adapter, u8 tone)
-{
- u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc };
- u16 ax;
-
- dprintk("%s: %u\n", __FUNCTION__, tone);
-
- switch (tone) {
- case 1:
- ax = wz_half_period_for_45_mhz[0];
- break;
- case 2:
- ax = wz_half_period_for_45_mhz[1];
- break;
- case 3:
- ax = wz_half_period_for_45_mhz[2];
- break;
- case 4:
- ax = wz_half_period_for_45_mhz[3];
- break;
-
- default:
- ax = 0;
- }
-
- if (ax != 0) {
- write_reg_dw(adapter, 0x200, ((ax << 0x0f) + (ax & 0x7fff)) | 0x40000000);
-
- } else {
-
- write_reg_dw(adapter, 0x200, 0x40ff8000);
- }
-}
-
-static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
-{
- u32 var;
-
- dprintk("%s : polarity = %u \n", __FUNCTION__, polarity);
-
- var = read_reg_dw(adapter, 0x204);
-
- if (polarity == 0) {
- dprintk("%s: LNB power off\n", __FUNCTION__);
- var = var | 1;
- };
-
- if (polarity == 1) {
- var = var & ~1;
- var = var & ~4;
- };
-
- if (polarity == 2) {
- var = var & ~1;
- var = var | 4;
- }
-
- write_reg_dw(adapter, 0x204, var);
-}
-
-static void diseqc_send_bit(struct adapter *adapter, int data)
-{
- set_tuner_tone(adapter, 1);
- udelay(data ? 500 : 1000);
- set_tuner_tone(adapter, 0);
- udelay(data ? 1000 : 500);
-}
-
-
-static void diseqc_send_byte(struct adapter *adapter, int data)
- {
- int i, par = 1, d;
-
- for (i = 7; i >= 0; i--) {
- d = (data >> i) & 1;
- par ^= d;
- diseqc_send_bit(adapter, d);
- }
-
- diseqc_send_bit(adapter, par);
- }
-
-
-static int send_diseqc_msg(struct adapter *adapter, int len, u8 *msg, unsigned long burst)
-{
- int i;
-
- set_tuner_tone(adapter, 0);
- mdelay(16);
-
- for (i = 0; i < len; i++)
- diseqc_send_byte(adapter, msg[i]);
-
- mdelay(16);
-
- if (burst != -1) {
- if (burst)
- diseqc_send_byte(adapter, 0xff);
- else {
- set_tuner_tone(adapter, 1);
- udelay(12500);
- set_tuner_tone(adapter, 0);
- }
- msleep(20);
- }
-
- return 0;
-}
-
-static int flexcop_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- switch(tone) {
- case SEC_TONE_ON:
- set_tuner_tone(adapter, 1);
- break;
- case SEC_TONE_OFF:
- set_tuner_tone(adapter, 0);
- break;
- default:
- return -EINVAL;
- };
-
- return 0;
-}
-
-static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- send_diseqc_msg(adapter, cmd->msg_len, cmd->msg, 0);
-
- return 0;
- }
-
-static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- send_diseqc_msg(adapter, 0, NULL, minicmd);
-
- return 0;
-}
-
-static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
-
- switch (voltage) {
- case SEC_VOLTAGE_13:
- dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
- set_tuner_polarity(adapter, 1);
- return 0;
-
- case SEC_VOLTAGE_18:
- dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
- set_tuner_polarity(adapter, 2);
- return 0;
-
- default:
- return -EINVAL;
- }
- }
-
-static int flexcop_sleep(struct dvb_frontend* fe)
- {
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- dprintk("%s: FE_SLEEP\n", __FUNCTION__);
- set_tuner_polarity(adapter, 0);
-
- if (adapter->fe_sleep) return adapter->fe_sleep(fe);
- return 0;
- }
-
-static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
- {
- printk("flexcop_i2c_func\n");
-
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm flexcop_algo = {
- .name = "flexcop i2c algorithm",
- .id = I2C_ALGO_BIT,
- .master_xfer = master_xfer,
- .functionality = flexcop_i2c_func,
-};
-
-
-
-
-static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
-{
- u8 aclk = 0;
- u8 bclk = 0;
-
- if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
- else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
- else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
- else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
- else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
- else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
-
- stv0299_writereg (fe, 0x13, aclk);
- stv0299_writereg (fe, 0x14, bclk);
- stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
- stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
- stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
-
- return 0;
-}
-
-static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- div = params->frequency / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = 0x84; // 0xC4
- buf[3] = 0x08;
-
- if (params->frequency < 1500000) buf[3] |= 0x10;
-
- if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static u8 samsung_tbmu24112_inittab[] = {
- 0x01, 0x15,
- 0x02, 0x30,
- 0x03, 0x00,
- 0x04, 0x7D,
- 0x05, 0x35,
- 0x06, 0x02,
- 0x07, 0x00,
- 0x08, 0xC3,
- 0x0C, 0x00,
- 0x0D, 0x81,
- 0x0E, 0x23,
- 0x0F, 0x12,
- 0x10, 0x7E,
- 0x11, 0x84,
- 0x12, 0xB9,
- 0x13, 0x88,
- 0x14, 0x89,
- 0x15, 0xC9,
- 0x16, 0x00,
- 0x17, 0x5C,
- 0x18, 0x00,
- 0x19, 0x00,
- 0x1A, 0x00,
- 0x1C, 0x00,
- 0x1D, 0x00,
- 0x1E, 0x00,
- 0x1F, 0x3A,
- 0x20, 0x2E,
- 0x21, 0x80,
- 0x22, 0xFF,
- 0x23, 0xC1,
- 0x28, 0x00,
- 0x29, 0x1E,
- 0x2A, 0x14,
- 0x2B, 0x0F,
- 0x2C, 0x09,
- 0x2D, 0x05,
- 0x31, 0x1F,
- 0x32, 0x19,
- 0x33, 0xFE,
- 0x34, 0x93,
- 0xff, 0xff,
- };
-
-static struct stv0299_config samsung_tbmu24112_config = {
- .demod_address = 0x68,
- .inittab = samsung_tbmu24112_inittab,
- .mclk = 88000000UL,
- .invert = 0,
- .enhanced_tuning = 0,
- .skip_reinit = 0,
- .lock_output = STV0229_LOCKOUTPUT_LK,
- .volt13_op0_op1 = STV0299_VOLT13_OP1,
- .min_delay_ms = 100,
- .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
- .pll_set = samsung_tbmu24112_pll_set,
-};
-
-
-
-static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
-{
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- return request_firmware(fw, name, &adapter->pdev->dev);
-}
-
-
-static struct nxt2002_config samsung_tbmv_config = {
- .demod_address = 0x0A,
- .request_firmware = nxt2002_request_firmware,
-};
-
-static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
-{
- static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
- static u8 mt352_reset [] = { 0x50, 0x80 };
- static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
- static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
-
- mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(fe, mt352_reset, sizeof(mt352_reset));
- mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
-
- mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
- mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
-
- return 0;
-}
-
-static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
-{
- u32 div;
- unsigned char bs = 0;
-
- #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
- div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
-
- if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
- if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
- if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
-
- pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address
- pllbuf[1] = div >> 8;
- pllbuf[2] = div & 0xff;
- pllbuf[3] = 0xcc;
- pllbuf[4] = bs;
-
- return 0;
-}
-
-static struct mt352_config samsung_tdtc9251dh0_config = {
-
- .demod_address = 0x0f,
- .demod_init = samsung_tdtc9251dh0_demod_init,
- .pll_set = samsung_tdtc9251dh0_pll_set,
-};
-
-static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
-{
- u8 buf[4];
- u32 div;
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- struct adapter* adapter = (struct adapter*) fe->dvb->priv;
-
- div = (params->frequency + (125/2)) / 125;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = (div >> 0) & 0xff;
- buf[2] = 0x84 | ((div >> 10) & 0x60);
- buf[3] = 0x80;
-
- if (params->frequency < 1550000)
- buf[3] |= 0x02;
-
- if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO;
- return 0;
-}
-
-static struct mt312_config skystar23_samsung_tbdu18132_config = {
-
- .demod_address = 0x0e,
- .pll_set = skystar23_samsung_tbdu18132_pll_set,
-};
-
-
-
-
-static void frontend_init(struct adapter *skystar2)
-{
- switch(skystar2->pdev->device) {
- case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 (DVB-T or ATSC)
-
- // Attempt to load the Nextwave nxt2002 for ATSC support
- skystar2->fe = nxt2002_attach(&samsung_tbmv_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
- }
-
- // try the skystar2 v2.6 first (stv0299/Samsung tbmu24112(sl1935))
- skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->set_voltage = flexcop_set_voltage;
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
-}
-
- // try the airstar2 (mt352/Samsung tdtc9251dh0(??))
- skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->info.frequency_min = 474000000;
- skystar2->fe->ops->info.frequency_max = 858000000;
- break;
- }
-
- // try the skystar2 v2.3 (vp310/Samsung tbdu18132(tsa5059))
- skystar2->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &skystar2->i2c_adap);
- if (skystar2->fe != NULL) {
- skystar2->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
- skystar2->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
- skystar2->fe->ops->set_tone = flexcop_set_tone;
- skystar2->fe->ops->set_voltage = flexcop_set_voltage;
- skystar2->fe_sleep = skystar2->fe->ops->sleep;
- skystar2->fe->ops->sleep = flexcop_sleep;
- break;
- }
- break;
- }
-
- if (skystar2->fe == NULL) {
- printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
- skystar2->pdev->vendor,
- skystar2->pdev->device,
- skystar2->pdev->subsystem_vendor,
- skystar2->pdev->subsystem_device);
- } else {
- if (dvb_register_frontend(&skystar2->dvb_adapter, skystar2->fe)) {
- printk("skystar2: Frontend registration failed!\n");
- if (skystar2->fe->ops->release)
- skystar2->fe->ops->release(skystar2->fe);
- skystar2->fe = NULL;
- }
- }
-}
-
-
-static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- struct adapter *adapter;
- struct dvb_adapter *dvb_adapter;
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
- int ret = -ENODEV;
-
- if (!pdev)
- goto out;
-
- ret = driver_initialize(pdev);
- if (ret < 0)
- goto out;
-
- adapter = pci_get_drvdata(pdev);
- dvb_adapter = &adapter->dvb_adapter;
-
- ret = dvb_register_adapter(dvb_adapter, skystar2_pci_driver.name,
- THIS_MODULE);
- if (ret < 0) {
- printk("%s: Error registering DVB adapter\n", __FUNCTION__);
- goto err_halt;
- }
-
- dvb_adapter->priv = adapter;
-
-
- init_MUTEX(&adapter->i2c_sem);
-
-
- memset(&adapter->i2c_adap, 0, sizeof(struct i2c_adapter));
- strcpy(adapter->i2c_adap.name, "SkyStar2");
-
- i2c_set_adapdata(&adapter->i2c_adap, adapter);
-
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- adapter->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL;
-#else
- adapter->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-#endif
- adapter->i2c_adap.algo = &flexcop_algo;
- adapter->i2c_adap.algo_data = NULL;
- adapter->i2c_adap.id = I2C_ALGO_BIT;
-
- ret = i2c_add_adapter(&adapter->i2c_adap);
- if (ret < 0)
- goto err_dvb_unregister;
-
- dvbdemux = &adapter->demux;
-
- dvbdemux->priv = adapter;
- dvbdemux->filternum = N_PID_SLOTS;
- dvbdemux->feednum = N_PID_SLOTS;
- dvbdemux->start_feed = dvb_start_feed;
- dvbdemux->stop_feed = dvb_stop_feed;
- dvbdemux->write_to_decoder = NULL;
- dvbdemux->dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
-
- ret = dvb_dmx_init(&adapter->demux);
- if (ret < 0)
- goto err_i2c_del;
-
- dmx = &dvbdemux->dmx;
-
- adapter->hw_frontend.source = DMX_FRONTEND_0;
- adapter->dmxdev.filternum = N_PID_SLOTS;
- adapter->dmxdev.demux = dmx;
- adapter->dmxdev.capabilities = 0;
-
- ret = dvb_dmxdev_init(&adapter->dmxdev, &adapter->dvb_adapter);
- if (ret < 0)
- goto err_dmx_release;
-
- ret = dmx->add_frontend(dmx, &adapter->hw_frontend);
- if (ret < 0)
- goto err_dmxdev_release;
-
- adapter->mem_frontend.source = DMX_MEMORY_FE;
-
- ret = dmx->add_frontend(dmx, &adapter->mem_frontend);
- if (ret < 0)
- goto err_remove_hw_frontend;
-
- ret = dmx->connect_frontend(dmx, &adapter->hw_frontend);
- if (ret < 0)
- goto err_remove_mem_frontend;
-
- dvb_net_init(&adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
-
- frontend_init(adapter);
-out:
- return ret;
-
-err_remove_mem_frontend:
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->mem_frontend);
-err_remove_hw_frontend:
- dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &adapter->hw_frontend);
-err_dmxdev_release:
- dvb_dmxdev_release(&adapter->dmxdev);
-err_dmx_release:
- dvb_dmx_release(&adapter->demux);
-err_i2c_del:
- i2c_del_adapter(&adapter->i2c_adap);
-err_dvb_unregister:
- dvb_unregister_adapter(&adapter->dvb_adapter);
-err_halt:
- driver_halt(pdev);
- goto out;
-}
-
-static void skystar2_remove(struct pci_dev *pdev)
-{
- struct adapter *adapter = pci_get_drvdata(pdev);
- struct dvb_demux *dvbdemux;
- struct dmx_demux *dmx;
-
- if (!adapter)
- return;
-
- dvb_net_release(&adapter->dvbnet);
- dvbdemux = &adapter->demux;
- dmx = &dvbdemux->dmx;
-
- dmx->close(dmx);
- dmx->remove_frontend(dmx, &adapter->hw_frontend);
- dmx->remove_frontend(dmx, &adapter->mem_frontend);
-
- dvb_dmxdev_release(&adapter->dmxdev);
- dvb_dmx_release(dvbdemux);
-
- if (adapter->fe != NULL)
- dvb_unregister_frontend(adapter->fe);
-
- dvb_unregister_adapter(&adapter->dvb_adapter);
-
- i2c_del_adapter(&adapter->i2c_adap);
-
- driver_halt(pdev);
- }
-
-static struct pci_device_id skystar2_pci_tbl[] = {
- {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
-/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII
- {0,},
-};
-
-MODULE_DEVICE_TABLE(pci, skystar2_pci_tbl);
-
-static struct pci_driver skystar2_pci_driver = {
- .name = "SkyStar2",
- .id_table = skystar2_pci_tbl,
- .probe = skystar2_probe,
- .remove = skystar2_remove,
-};
-
-static int skystar2_init(void)
-{
- return pci_register_driver(&skystar2_pci_driver);
-}
-
-static void skystar2_cleanup(void)
-{
- pci_unregister_driver(&skystar2_pci_driver);
-}
-
-module_init(skystar2_init);
-module_exit(skystar2_cleanup);
-
-MODULE_DESCRIPTION("Technisat SkyStar2 DVB PCI Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 1339912c308b..07a0b0a968a6 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -258,10 +258,10 @@ int write_dst(struct dst_state *state, u8 *data, u8 len)
if (debug && (verbose > 4)) {
u8 i;
if (verbose > 4) {
- dprintk("%s writing", __FUNCTION__);
+ dprintk("%s writing [ ", __FUNCTION__);
for (i = 0; i < len; i++)
- dprintk(" %02x", data[i]);
- dprintk("\n");
+ dprintk("%02x ", data[i]);
+ dprintk("]\n");
}
}
for (cnt = 0; cnt < 2; cnt++) {
@@ -320,10 +320,29 @@ int read_dst(struct dst_state *state, u8 * ret, u8 len)
}
EXPORT_SYMBOL(read_dst);
-static int dst_set_freq(struct dst_state *state, u32 freq)
+static int dst_set_polarization(struct dst_state *state)
{
- u8 *val;
+ switch (state->voltage) {
+ case SEC_VOLTAGE_13: // vertical
+ printk("%s: Polarization=[Vertical]\n", __FUNCTION__);
+ state->tx_tuna[8] &= ~0x40; //1
+ break;
+
+ case SEC_VOLTAGE_18: // horizontal
+ printk("%s: Polarization=[Horizontal]\n", __FUNCTION__);
+ state->tx_tuna[8] |= 0x40; // 0
+ break;
+
+ case SEC_VOLTAGE_OFF:
+
+ break;
+ }
+
+ return 0;
+}
+static int dst_set_freq(struct dst_state *state, u32 freq)
+{
state->frequency = freq;
if (debug > 4)
dprintk("%s: set Frequency %u\n", __FUNCTION__, freq);
@@ -332,46 +351,30 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
freq = freq / 1000;
if (freq < 950 || freq > 2150)
return -EINVAL;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 8) & 0x7f;
- val[3] = (u8) freq;
- val[4] = 1;
- val[8] &= ~4;
- if (freq < 1531)
- val[8] |= 4;
+
+ state->tx_tuna[2] = (freq >> 8);
+ state->tx_tuna[3] = (u8) freq;
+ state->tx_tuna[4] = 0x01;
+ state->tx_tuna[8] &= ~0x04;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS) {
+ if (freq < 1531)
+ state->tx_tuna[8] |= 0x04;
+ }
+
} else if (state->dst_type == DST_TYPE_IS_TERR) {
freq = freq / 1000;
if (freq < 137000 || freq > 858000)
return -EINVAL;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
- val[5] = 0;
- switch (state->bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
- case BANDWIDTH_7_MHZ:
- case BANDWIDTH_AUTO:
- val[6] = 7;
- break;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
- }
-
- val[7] = 0;
- val[8] = 0;
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
- /* guess till will get one */
- freq = freq / 1000;
- val = &state->tx_tuna[0];
- val[2] = (freq >> 16) & 0xff;
- val[3] = (freq >> 8) & 0xff;
- val[4] = (u8) freq;
+ state->tx_tuna[2] = (freq >> 16) & 0xff;
+ state->tx_tuna[3] = (freq >> 8) & 0xff;
+ state->tx_tuna[4] = (u8) freq;
+
} else
return -EINVAL;
return 0;
@@ -379,51 +382,58 @@ static int dst_set_freq(struct dst_state *state, u32 freq)
static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth)
{
- u8 *val;
-
state->bandwidth = bandwidth;
if (state->dst_type != DST_TYPE_IS_TERR)
return 0;
- val = &state->tx_tuna[0];
switch (bandwidth) {
- case BANDWIDTH_6_MHZ:
- val[6] = 6;
- break;
+ case BANDWIDTH_6_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x06;
+ else {
+ state->tx_tuna[6] = 0x06;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- case BANDWIDTH_7_MHZ:
- val[6] = 7;
- break;
+ case BANDWIDTH_7_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x07;
+ else {
+ state->tx_tuna[6] = 0x07;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- case BANDWIDTH_8_MHZ:
- val[6] = 8;
- break;
+ case BANDWIDTH_8_MHZ:
+ if (state->dst_hw_cap & DST_TYPE_HAS_CA)
+ state->tx_tuna[7] = 0x08;
+ else {
+ state->tx_tuna[6] = 0x08;
+ state->tx_tuna[7] = 0x00;
+ }
+ break;
- default:
- return -EINVAL;
+ default:
+ return -EINVAL;
}
return 0;
}
static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion)
{
- u8 *val;
-
state->inversion = inversion;
-
- val = &state->tx_tuna[0];
-
- val[8] &= ~0x80;
-
switch (inversion) {
- case INVERSION_OFF:
- break;
- case INVERSION_ON:
- val[8] |= 0x80;
- break;
- default:
- return -EINVAL;
+ case INVERSION_OFF: // Inversion = Normal
+ state->tx_tuna[8] &= ~0x80;
+ break;
+
+ case INVERSION_ON:
+ state->tx_tuna[8] |= 0x80;
+ break;
+ default:
+ return -EINVAL;
}
return 0;
}
@@ -478,6 +488,52 @@ static int dst_set_symbolrate(struct dst_state* state, u32 srate)
return 0;
}
+
+static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation)
+{
+ if (state->dst_type != DST_TYPE_IS_CABLE)
+ return 0;
+
+ state->modulation = modulation;
+ switch (modulation) {
+ case QAM_16:
+ state->tx_tuna[8] = 0x10;
+ break;
+
+ case QAM_32:
+ state->tx_tuna[8] = 0x20;
+ break;
+
+ case QAM_64:
+ state->tx_tuna[8] = 0x40;
+ break;
+
+ case QAM_128:
+ state->tx_tuna[8] = 0x80;
+ break;
+
+ case QAM_256:
+ state->tx_tuna[8] = 0x00;
+ break;
+
+ case QPSK:
+ case QAM_AUTO:
+ case VSB_8:
+ case VSB_16:
+ default:
+ return -EINVAL;
+
+ }
+
+ return 0;
+}
+
+static fe_modulation_t dst_get_modulation(struct dst_state *state)
+{
+ return state->modulation;
+}
+
+
u8 dst_check_sum(u8 * buf, u32 len)
{
u32 i;
@@ -577,7 +633,7 @@ struct dst_types dst_tlist[] = {
.device_id = "200103A",
.offset = 0,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1,
+ .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS,
.dst_feature = 0
}, /* obsolete */
@@ -626,7 +682,7 @@ struct dst_types dst_tlist[] = {
.device_id = "DSTMCI",
.offset = 1,
.dst_type = DST_TYPE_IS_SAT,
- .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD,
+ .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT,
.dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4
| DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC
},
@@ -872,7 +928,7 @@ static int dst_get_signal(struct dst_state* state)
{
int retval;
u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
-
+ dprintk("%s: Getting Signal strength and other parameters\n", __FUNCTION__);
if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
state->decode_lock = state->decode_strength = state->decode_snr = 0;
return 0;
@@ -954,15 +1010,8 @@ static int dst_get_tuna(struct dst_state* state)
state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3];
state->decode_lock = 1;
- /*
- dst->decode_n1 = (dst->rx_tuna[4] << 8) +
- (dst->rx_tuna[5]);
-
- dst->decode_n2 = (dst->rx_tuna[8] << 8) +
- (dst->rx_tuna[7]);
- */
state->diseq_flags |= HAS_LOCK;
- /* dst->cur_jiff = jiffies; */
+
return 1;
}
@@ -1098,7 +1147,11 @@ static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_OFF:
- state->tx_tuna[2] = 0xff;
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ state->tx_tuna[2] = 0x00;
+ else
+ state->tx_tuna[2] = 0xff;
+
break;
case SEC_TONE_ON:
@@ -1145,7 +1198,8 @@ static int dst_init(struct dvb_frontend* fe)
static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
- state->inversion = INVERSION_ON;
+// state->inversion = INVERSION_ON;
+ state->inversion = INVERSION_OFF;
state->voltage = SEC_VOLTAGE_13;
state->tone = SEC_TONE_OFF;
state->symbol_rate = 29473000;
@@ -1174,7 +1228,7 @@ static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status)
*status = 0;
if (state->diseq_flags & HAS_LOCK) {
- dst_get_signal(state);
+// dst_get_signal(state); // don't require(?) to ask MCU
if (state->decode_lock)
*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
}
@@ -1208,20 +1262,25 @@ static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
dst_set_freq(state, p->frequency);
if (verbose > 4)
- dprintk("Set Frequency = [%d]\n", p->frequency);
+ dprintk("Set Frequency=[%d]\n", p->frequency);
- dst_set_inversion(state, p->inversion);
+// dst_set_inversion(state, p->inversion);
if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ dst_set_inversion(state, p->inversion);
+
dst_set_fec(state, p->u.qpsk.fec_inner);
dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
+ dst_set_polarization(state);
if (verbose > 4)
- dprintk("Set Symbolrate = [%d]\n", p->u.qpsk.symbol_rate);
+ dprintk("Set Symbolrate=[%d]\n", p->u.qpsk.symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
dst_set_bandwidth(state, p->u.ofdm.bandwidth);
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(state, p->u.qam.fec_inner);
dst_set_symbolrate(state, p->u.qam.symbol_rate);
+ dst_set_modulation(state, p->u.qam.modulation);
}
dst_write_tuna(fe);
@@ -1233,8 +1292,11 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
struct dst_state* state = fe->demodulator_priv;
p->frequency = state->decode_freq;
- p->inversion = state->inversion;
+// p->inversion = state->inversion;
if (state->dst_type == DST_TYPE_IS_SAT) {
+ if (state->type_flags & DST_TYPE_HAS_OBS_REGS)
+ p->inversion = state->inversion;
+
p->u.qpsk.symbol_rate = state->symbol_rate;
p->u.qpsk.fec_inner = dst_get_fec(state);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
@@ -1242,7 +1304,8 @@ static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_paramet
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
p->u.qam.symbol_rate = state->symbol_rate;
p->u.qam.fec_inner = dst_get_fec(state);
- p->u.qam.modulation = QAM_AUTO;
+// p->u.qam.modulation = QAM_AUTO;
+ p->u.qam.modulation = dst_get_modulation(state);
}
return 0;
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index d781504cc2fa..bfaacd5fc20f 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -32,7 +32,7 @@
#include "dst_ca.h"
#include "dst_common.h"
-static unsigned int verbose = 1;
+static unsigned int verbose = 5;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
@@ -295,34 +295,28 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message,
return 0;
}
-static int handle_en50221_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
+static int handle_dst_tag(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u32 length)
{
if (state->dst_hw_cap & DST_TYPE_HAS_SESSION) {
hw_buffer->msg[2] = p_ca_message->msg[1]; /* MSB */
hw_buffer->msg[3] = p_ca_message->msg[2]; /* LSB */
}
else {
+ hw_buffer->msg[0] = (length & 0xff) + 7;
+ hw_buffer->msg[1] = 0x40;
hw_buffer->msg[2] = 0x03;
hw_buffer->msg[3] = 0x00;
+ hw_buffer->msg[4] = 0x03;
+ hw_buffer->msg[5] = length & 0xff;
+ hw_buffer->msg[6] = 0x00;
}
return 0;
}
-static int debug_8820_buffer(struct ca_msg *hw_buffer)
-{
- unsigned int i;
-
- dprintk("%s:Debug=[", __FUNCTION__);
- for (i = 0; i < (hw_buffer->msg[0] + 1); i++)
- dprintk(" %02x", hw_buffer->msg[i]);
- dprintk("]\n");
-
- return 0;
-}
-static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 reply)
+static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 length, u8 reply)
{
- if ((dst_put_ci(state, hw_buffer->msg, (hw_buffer->length + 1), hw_buffer->msg, reply)) < 0) {
+ if ((dst_put_ci(state, hw_buffer->msg, length, hw_buffer->msg, reply)) < 0) {
dprintk("%s: DST-CI Command failed.\n", __FUNCTION__);
dprintk("%s: Resetting DST.\n", __FUNCTION__);
rdc_reset_state(state);
@@ -334,234 +328,141 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 r
return 0;
}
-
-static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+u32 asn_1_decode(u8 *asn_1_array)
{
- u32 hw_offset, buf_offset, i, k;
- u32 program_info_length = 0, es_info_length = 0, length = 0, words = 0;
- u8 found_prog_ca_desc = 0, found_stream_ca_desc = 0, error_condition = 0, hw_buffer_length = 0;
-
- if (verbose > 3)
- dprintk("%s, p_ca_message length %d (0x%x)\n", __FUNCTION__,p_ca_message->length,p_ca_message->length );
-
- handle_en50221_tag(state, p_ca_message, hw_buffer); /* EN50221 tag */
-
- /* Handle the length field (variable) */
- if (!(p_ca_message->msg[3] & 0x80)) { /* Length = 1 */
- length = p_ca_message->msg[3] & 0x7f;
- words = 0; /* domi's suggestion */
- }
- else { /* Length = words */
- words = p_ca_message->msg[3] & 0x7f;
- for (i = 0; i < words; i++) {
- length = length << 8;
- length = length | p_ca_message->msg[4 + i];
+ u8 length_field = 0, word_count = 0, count = 0;
+ u32 length = 0;
+
+ length_field = asn_1_array[0];
+ dprintk("%s: Length field=[%02x]\n", __FUNCTION__, length_field);
+ if (length_field < 0x80) {
+ length = length_field & 0x7f;
+ dprintk("%s: Length=[%02x]\n", __FUNCTION__, length);
+ } else {
+ word_count = length_field & 0x7f;
+ for (count = 0; count < word_count; count++) {
+ length = (length | asn_1_array[count + 1]) << 8;
+ dprintk("%s: Length=[%04x]\n", __FUNCTION__, length);
}
}
- if (verbose > 4) {
- dprintk("%s:Length=[%d (0x%x)], Words=[%d]\n", __FUNCTION__, length,length, words);
-
- /* Debug Input string */
- for (i = 0; i < length; i++)
- dprintk(" %02x", p_ca_message->msg[i]);
- dprintk("]\n");
- }
-
- hw_offset = 7;
- buf_offset = words + 4;
-
- /* Program Header */
- if (verbose > 4)
- dprintk("\n%s:Program Header=[", __FUNCTION__);
- for (i = 0; i < 6; i++) {
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- if (verbose > 4)
- dprintk(" %02x", p_ca_message->msg[buf_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++;
- }
- if (verbose > 4)
- dprintk("]\n");
+ return length;
+}
- program_info_length = 0;
- program_info_length = (((program_info_length | p_ca_message->msg[words + 8]) & 0x0f) << 8) | p_ca_message->msg[words + 9];
- if (verbose > 4)
- dprintk("%s:Program info Length=[%d][%02x], hw_offset=[%d], buf_offset=[%d] \n",
- __FUNCTION__, program_info_length, program_info_length, hw_offset, buf_offset);
+static int init_buffer(u8 *buffer, u32 length)
+{
+ u32 i;
+ for (i = 0; i < length; i++)
+ buffer[i] = 0;
- if (program_info_length && (program_info_length < 256)) { /* If program_info_length */
- hw_buffer->msg[11] = hw_buffer->msg[11] & 0x0f; /* req only 4 bits */
- hw_buffer->msg[12] = hw_buffer->msg[12] + 1; /* increment! ASIC bug! */
+ return 0;
+}
- if (p_ca_message->msg[buf_offset + 1] == 0x09) { /* Check CA descriptor */
- found_prog_ca_desc = 1;
- if (verbose > 4)
- dprintk("%s: Found CA descriptor @ Program level\n", __FUNCTION__);
- }
+static int debug_string(u8 *msg, u32 length, u32 offset)
+{
+ u32 i;
- if (found_prog_ca_desc) { /* Command only if CA descriptor */
- hw_buffer->msg[13] = p_ca_message->msg[buf_offset]; /* CA PMT command ID */
- hw_offset++, buf_offset++, hw_buffer_length++;
- }
+ dprintk(" String=[ ");
+ for (i = offset; i < length; i++)
+ dprintk("%02x ", msg[i]);
+ dprintk("]\n");
- /* Program descriptors */
- if (verbose > 4) {
- dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
- dprintk("%s:Program descriptors=[", __FUNCTION__);
- }
- while (program_info_length && !error_condition) { /* Copy prog descriptors */
- if (program_info_length > p_ca_message->length) { /* Error situation */
- dprintk ("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d]\n",
- __FUNCTION__, __LINE__, program_info_length);
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- error_condition = 1;
- break;
- }
+ return 0;
+}
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- dprintk(" %02x", p_ca_message->msg[buf_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++, program_info_length--;
- }
- if (verbose > 4) {
- dprintk("]\n");
- dprintk("%s:**********>buf_offset=[%d], hw_offset=[%d]\n", __FUNCTION__, buf_offset, hw_offset);
- }
- if (found_prog_ca_desc) {
- if (!reply) {
- hw_buffer->msg[13] = 0x01; /* OK descrambling */
- if (verbose > 1)
- dprintk("CA PMT Command = OK Descrambling\n");
- }
- else {
- hw_buffer->msg[13] = 0x02; /* Ok MMI */
- if (verbose > 1)
- dprintk("CA PMT Command = Ok MMI\n");
- }
- if (query) {
- hw_buffer->msg[13] = 0x03; /* Query */
- if (verbose > 1)
- dprintk("CA PMT Command = CA PMT query\n");
- }
- }
- }
- else {
- hw_buffer->msg[11] = hw_buffer->msg[11] & 0xf0; /* Don't write to ASIC */
- hw_buffer->msg[12] = hw_buffer->msg[12] = 0x00;
+static int copy_string(u8 *destination, u8 *source, u32 dest_offset, u32 source_offset, u32 length)
+{
+ u32 i;
+ dprintk("%s: Copying [", __FUNCTION__);
+ for (i = 0; i < length; i++) {
+ destination[i + dest_offset] = source[i + source_offset];
+ dprintk(" %02x", source[i + source_offset]);
}
- if (verbose > 4)
- dprintk("%s:**********>p_ca_message->length=[%d], buf_offset=[%d], hw_offset=[%d]\n",
- __FUNCTION__, p_ca_message->length, buf_offset, hw_offset);
-
- while ((buf_offset < p_ca_message->length) && !error_condition) {
- /* Bail out in case of an indefinite loop */
- if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
- dprintk("%s:\"WARNING\" Length error, line=[%d], prog_info_length=[%d], buf_offset=[%d]\n",
- __FUNCTION__, __LINE__, program_info_length, buf_offset);
-
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- error_condition = 1;
- break;
- }
-
- /* Stream Header */
-
- for (k = 0; k < 5; k++) {
- hw_buffer->msg[hw_offset + k] = p_ca_message->msg[buf_offset + k];
- }
+ dprintk("]\n");
- es_info_length = 0;
- es_info_length = (es_info_length | (p_ca_message->msg[buf_offset + 3] & 0x0f)) << 8 | p_ca_message->msg[buf_offset + 4];
+ return i;
+}
- if (verbose > 4) {
- dprintk("\n%s:----->Stream header=[%02x %02x %02x %02x %02x]\n", __FUNCTION__,
- p_ca_message->msg[buf_offset + 0], p_ca_message->msg[buf_offset + 1],
- p_ca_message->msg[buf_offset + 2], p_ca_message->msg[buf_offset + 3],
- p_ca_message->msg[buf_offset + 4]);
+static int modify_4_bits(u8 *message, u32 pos)
+{
+ message[pos] &= 0x0f;
- dprintk("%s:----->Stream type=[%02x], es length=[%d (0x%x)], Chars=[%02x] [%02x], buf_offset=[%d]\n", __FUNCTION__,
- p_ca_message->msg[buf_offset + 0], es_info_length, es_info_length,
- p_ca_message->msg[buf_offset + 3], p_ca_message->msg[buf_offset + 4], buf_offset);
- }
+ return 0;
+}
- hw_buffer->msg[hw_offset + 3] &= 0x0f; /* req only 4 bits */
- if (found_prog_ca_desc) {
- hw_buffer->msg[hw_offset + 3] = 0x00;
- hw_buffer->msg[hw_offset + 4] = 0x00;
- }
- hw_offset += 5, buf_offset += 5, hw_buffer_length += 5;
+static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query)
+{
+ u32 length = 0, count = 0;
+ u8 asn_1_words, program_header_length;
+ u16 program_info_length = 0, es_info_length = 0;
+ u32 hw_offset = 0, buf_offset = 0, i;
+ u8 dst_tag_length;
- /* Check for CA descriptor */
- if (p_ca_message->msg[buf_offset + 1] == 0x09) {
- if (verbose > 4)
- dprintk("%s:Found CA descriptor @ Stream level\n", __FUNCTION__);
- found_stream_ca_desc = 1;
- }
+ length = asn_1_decode(&p_ca_message->msg[3]);
+ dprintk("%s: CA Message length=[%d]\n", __FUNCTION__, length);
+ dprintk("%s: ASN.1 ", __FUNCTION__);
+ debug_string(&p_ca_message->msg[4], length, 0); // length does not include tag and length
- /* ES descriptors */
-
- if (es_info_length && !error_condition && !found_prog_ca_desc && found_stream_ca_desc) {
-// if (!ca_pmt_done) {
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset]; /* CA PMT cmd(es) */
- if (verbose > 4)
- printk("%s:----->CA PMT Command ID=[%02x]\n", __FUNCTION__, p_ca_message->msg[buf_offset]);
-// hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--, ca_pmt_done = 1;
- hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
-// }
- if (verbose > 4)
- dprintk("%s:----->ES descriptors=[", __FUNCTION__);
-
- while (es_info_length && !error_condition) { /* ES descriptors */
- if ((es_info_length > p_ca_message->length) || (buf_offset > p_ca_message->length)) {
- if (verbose > 4) {
- dprintk("%s:\"WARNING\" ES Length error, line=[%d], es_info_length=[%d], buf_offset=[%d]\n",
- __FUNCTION__, __LINE__, es_info_length, buf_offset);
-
- dprintk("%s:\"WARNING\" Bailing out of possible loop\n", __FUNCTION__);
- }
- error_condition = 1;
- break;
- }
+ init_buffer(hw_buffer->msg, length);
+ handle_dst_tag(state, p_ca_message, hw_buffer, length);
- hw_buffer->msg[hw_offset] = p_ca_message->msg[buf_offset];
- if (verbose > 3)
- dprintk("%02x ", hw_buffer->msg[hw_offset]);
- hw_offset++, buf_offset++, hw_buffer_length++, es_info_length--;
- }
- found_stream_ca_desc = 0; /* unset for new streams */
- dprintk("]\n");
+ hw_offset = 7;
+ asn_1_words = 1; // just a hack to test, should compute this one
+ buf_offset = 3;
+ program_header_length = 6;
+ dst_tag_length = 7;
+
+// debug_twinhan_ca_params(state, p_ca_message, hw_buffer, reply, query, length, hw_offset, buf_offset);
+// dprintk("%s: Program Header(BUF)", __FUNCTION__);
+// debug_string(&p_ca_message->msg[4], program_header_length, 0);
+// dprintk("%s: Copying Program header\n", __FUNCTION__);
+ copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + asn_1_words), program_header_length);
+ buf_offset += program_header_length, hw_offset += program_header_length;
+ modify_4_bits(hw_buffer->msg, (hw_offset - 2));
+ if (state->type_flags & DST_TYPE_HAS_INC_COUNT) { // workaround
+ dprintk("%s: Probably an ASIC bug !!!\n", __FUNCTION__);
+ debug_string(hw_buffer->msg, (hw_offset + program_header_length), 0);
+ hw_buffer->msg[hw_offset - 1] += 1;
+ }
+
+// dprintk("%s: Program Header(HW), Count=[%d]", __FUNCTION__, count);
+// debug_string(hw_buffer->msg, hw_offset, 0);
+
+ program_info_length = ((program_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+ dprintk("%s: Program info length=[%02x]\n", __FUNCTION__, program_info_length);
+ if (program_info_length) {
+ count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, (buf_offset + 1), (program_info_length + 1) ); // copy next elem, not current
+ buf_offset += count, hw_offset += count;
+// dprintk("%s: Program level ", __FUNCTION__);
+// debug_string(hw_buffer->msg, hw_offset, 0);
+ }
+
+ buf_offset += 1;// hw_offset += 1;
+ for (i = buf_offset; i < length; i++) {
+// dprintk("%s: Stream Header ", __FUNCTION__);
+ count = copy_string(hw_buffer->msg, p_ca_message->msg, hw_offset, buf_offset, 5);
+ modify_4_bits(hw_buffer->msg, (hw_offset + 3));
+
+ hw_offset += 5, buf_offset += 5, i += 4;
+// debug_string(hw_buffer->msg, hw_offset, (hw_offset - 5));
+ es_info_length = ((es_info_length | (p_ca_message->msg[buf_offset - 1] & 0x0f)) << 8) | p_ca_message->msg[buf_offset];
+ dprintk("%s: ES info length=[%02x]\n", __FUNCTION__, es_info_length);
+ if (es_info_length) {
+ // copy descriptors @ STREAM level
+ dprintk("%s: Descriptors @ STREAM level...!!! \n", __FUNCTION__);
}
- }
-
- /* MCU Magic words */
-
- hw_buffer_length += 7;
- hw_buffer->msg[0] = hw_buffer_length;
- hw_buffer->msg[1] = 64;
- hw_buffer->msg[4] = 3;
- hw_buffer->msg[5] = hw_buffer->msg[0] - 7;
- hw_buffer->msg[6] = 0;
-
- /* Fix length */
- hw_buffer->length = hw_buffer->msg[0];
-
- put_checksum(&hw_buffer->msg[0], hw_buffer->msg[0]);
- /* Do the actual write */
- if (verbose > 4) {
- dprintk("%s:======================DEBUGGING================================\n", __FUNCTION__);
- dprintk("%s: Actual Length=[%d]\n", __FUNCTION__, hw_buffer_length);
}
- /* Only for debugging! */
- if (verbose > 2)
- debug_8820_buffer(hw_buffer);
- if (verbose > 3)
- dprintk("%s: Reply = [%d]\n", __FUNCTION__, reply);
- write_to_8820(state, hw_buffer, reply);
+ hw_buffer->msg[length + dst_tag_length] = dst_check_sum(hw_buffer->msg, (length + dst_tag_length));
+// dprintk("%s: Total length=[%d], Checksum=[%02x]\n", __FUNCTION__, (length + dst_tag_length), hw_buffer->msg[length + dst_tag_length]);
+ debug_string(hw_buffer->msg, (length + dst_tag_length + 1), 0); // dst tags also
+ write_to_8820(state, hw_buffer, (length + dst_tag_length + 1), reply); // checksum
return 0;
}
+
/* Board supports CA PMT reply ? */
static int dst_check_ca_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer)
{
@@ -605,7 +506,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
struct ca_msg *hw_buffer;
if ((hw_buffer = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if (verbose > 3)
@@ -630,8 +531,10 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
switch (command) {
case CA_PMT:
if (verbose > 3)
+// dprintk("Command = SEND_CA_PMT\n");
dprintk("Command = SEND_CA_PMT\n");
- if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+// if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) {
+ if ((ca_set_pmt(state, p_ca_message, hw_buffer, 0, 0)) < 0) { // code simplification started
dprintk("%s: -->CA_PMT Failed !\n", __FUNCTION__);
return -1;
}
@@ -664,7 +567,7 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message,
return -1;
}
if (verbose > 3)
- printk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
+ dprintk("%s: -->CA_APP_INFO_ENQUIRY Success !\n", __FUNCTION__);
break;
}
@@ -681,17 +584,17 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd
struct ca_msg *p_ca_message;
if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) {
- printk("%s: Memory allocation failure\n", __FUNCTION__);
+ dprintk("%s: Memory allocation failure\n", __FUNCTION__);
return -ENOMEM;
}
diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h
index 0b3da29245fb..ef532a6aceaa 100644
--- a/drivers/media/dvb/bt8xx/dst_common.h
+++ b/drivers/media/dvb/bt8xx/dst_common.h
@@ -47,6 +47,8 @@
#define DST_TYPE_HAS_FW_2 16
#define DST_TYPE_HAS_FW_3 32
#define DST_TYPE_HAS_FW_BUILD 64
+#define DST_TYPE_HAS_OBS_REGS 128
+#define DST_TYPE_HAS_INC_COUNT 256
/* Card capability list */
@@ -110,6 +112,7 @@ struct dst_state {
u32 dst_hw_cap;
u8 dst_fw_version;
fe_sec_mini_cmd_t minicmd;
+ fe_modulation_t modulation;
u8 messages[256];
};
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c
index 96c57fde95a0..7d8b3cad350b 100644
--- a/drivers/media/dvb/cinergyT2/cinergyT2.c
+++ b/drivers/media/dvb/cinergyT2/cinergyT2.c
@@ -699,6 +699,8 @@ static void cinergyt2_query_rc (void *data)
for (n=0; len>0 && n<(len/sizeof(rc_events[0])); n++) {
int i;
+/* dprintk(1,"rc_events[%d].value = %x, type=%x\n",n,le32_to_cpu(rc_events[n].value),rc_events[n].type);*/
+
if (rc_events[n].type == CINERGYT2_RC_EVENT_TYPE_NEC &&
rc_events[n].value == ~0)
{
@@ -714,7 +716,7 @@ static void cinergyt2_query_rc (void *data)
cinergyt2->rc_input_event = KEY_MAX;
for (i=0; i<sizeof(rc_keys)/sizeof(rc_keys[0]); i+=3) {
if (rc_keys[i+0] == rc_events[n].type &&
- rc_keys[i+1] == rc_events[n].value)
+ rc_keys[i+1] == le32_to_cpu(rc_events[n].value))
{
cinergyt2->rc_input_event = rc_keys[i+2];
break;
diff --git a/drivers/media/dvb/dibusb/Kconfig b/drivers/media/dvb/dibusb/Kconfig
deleted file mode 100644
index 74dfc73ae5b0..000000000000
--- a/drivers/media/dvb/dibusb/Kconfig
+++ /dev/null
@@ -1,62 +0,0 @@
-config DVB_DIBUSB
- tristate "DiBcom USB DVB-T devices (see help for a complete device list)"
- depends on DVB_CORE && USB
- select FW_LOADER
- select DVB_DIB3000MB
- select DVB_DIB3000MC
- select DVB_MT352
- help
- Support for USB 1.1 and 2.0 DVB-T devices based on reference designs made by
- DiBcom (http://www.dibcom.fr) and C&E.
-
- Devices supported by this driver:
-
- TwinhanDTV USB-Ter (VP7041)
- TwinhanDTV Magic Box (VP7041e)
- KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
- Hama DVB-T USB-Box
- DiBcom reference devices (non-public)
- Ultima Electronic/Artec T1 USB TVBOX
- Compro Videomate DVB-U2000 - DVB-T USB
- Grandtec DVB-T USB
- Avermedia AverTV DVBT USB
- Artec T1 USB1.1 and USB2.0 boxes
- Yakumo/Typhoon DVB-T USB2.0
- Hanftek UMT-010 USB2.0
- Hauppauge WinTV NOVA-T USB2
-
- The VP7041 seems to be identical to "CTS Portable" (Chinese
- Television System).
-
- These devices can be understood as budget ones, they "only" deliver
- (a part of) the MPEG2 transport stream.
-
- A firmware is needed to get the device working. See Documentation/dvb/README.dibusb
- details.
-
- Say Y if you own such a device and want to use it. You should build it as
- a module.
-
-config DVB_DIBUSB_MISDESIGNED_DEVICES
- bool "Enable support for some misdesigned (see help) devices, which identify with wrong IDs"
- depends on DVB_DIBUSB
- help
- Somehow Artec/Ultima Electronic forgot to program the eeprom of some of their
- USB1.1/USB2.0 devices.
- So comes that they identify with the default Vendor and Product ID of the Cypress
- CY7C64613 (AN2235) or Cypress FX2.
-
- Affected device IDs:
- 0x0574:0x2235 (Artec T1 USB1.1, cold)
- 0x04b4:0x8613 (Artec T1 USB2.0, cold)
- 0x0574:0x1002 (Artec T1 USB2.0, warm)
- 0x0574:0x2131 (aged DiBcom USB1.1 test device)
-
- Say Y if your device has one of the mentioned IDs.
-
-config DVB_DIBCOM_DEBUG
- bool "Enable extended debug support for DiBcom USB device"
- depends on DVB_DIBUSB
- help
- Say Y if you want to enable debuging. See modinfo dvb-dibusb for
- debug levels.
diff --git a/drivers/media/dvb/dibusb/Makefile b/drivers/media/dvb/dibusb/Makefile
deleted file mode 100644
index e941c508624e..000000000000
--- a/drivers/media/dvb/dibusb/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-dvb-dibusb-objs = dvb-dibusb-core.o \
- dvb-dibusb-dvb.o \
- dvb-dibusb-fe-i2c.o \
- dvb-dibusb-firmware.o \
- dvb-dibusb-remote.o \
- dvb-dibusb-usb.o \
- dvb-fe-dtt200u.o
-
-obj-$(CONFIG_DVB_DIBUSB) += dvb-dibusb.o
-
-EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-core.c b/drivers/media/dvb/dibusb/dvb-dibusb-core.c
deleted file mode 100644
index 26235f9247e4..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-core.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Driver for mobile USB Budget DVB-T devices based on reference
- * design made by DiBcom (http://www.dibcom.fr/)
- *
- * dvb-dibusb-core.c
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * based on GPL code from DiBcom, which has
- * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
- *
- * Remote control code added by David Matthews (dm@prolingua.co.uk)
- *
- * 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.
- *
- * Acknowledgements
- *
- * Amaury Demol (ademol@dibcom.fr) from DiBcom for providing specs and driver
- * sources, on which this driver (and the dib3000mb/mc/p frontends) are based.
- *
- * see Documentation/dvb/README.dibusb for more information
- */
-#include "dvb-dibusb.h"
-
-#include <linux/moduleparam.h>
-
-/* debug */
-int dvb_dibusb_debug;
-module_param_named(debug, dvb_dibusb_debug, int, 0644);
-
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define DBSTATUS ""
-#else
-#define DBSTATUS " (debugging is not enabled)"
-#endif
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=alotmore,8=ts,16=err,32=rc (|-able))." DBSTATUS);
-#undef DBSTATUS
-
-static int pid_parse;
-module_param(pid_parse, int, 0644);
-MODULE_PARM_DESC(pid_parse, "enable pid parsing (filtering) when running at USB2.0");
-
-static int rc_query_interval = 100;
-module_param(rc_query_interval, int, 0644);
-MODULE_PARM_DESC(rc_query_interval, "interval in msecs for remote control query (default: 100; min: 40)");
-
-static int rc_key_repeat_count = 2;
-module_param(rc_key_repeat_count, int, 0644);
-MODULE_PARM_DESC(rc_key_repeat_count, "how many key repeats will be dropped before passing the key event again (default: 2)");
-
-/* Vendor IDs */
-#define USB_VID_ADSTECH 0x06e1
-#define USB_VID_ANCHOR 0x0547
-#define USB_VID_AVERMEDIA 0x14aa
-#define USB_VID_COMPRO 0x185b
-#define USB_VID_COMPRO_UNK 0x145f
-#define USB_VID_CYPRESS 0x04b4
-#define USB_VID_DIBCOM 0x10b8
-#define USB_VID_EMPIA 0xeb1a
-#define USB_VID_GRANDTEC 0x5032
-#define USB_VID_HANFTEK 0x15f4
-#define USB_VID_HAUPPAUGE 0x2040
-#define USB_VID_HYPER_PALTEK 0x1025
-#define USB_VID_IMC_NETWORKS 0x13d3
-#define USB_VID_TWINHAN 0x1822
-#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
-
-/* Product IDs */
-#define USB_PID_ADSTECH_USB2_COLD 0xa333
-#define USB_PID_ADSTECH_USB2_WARM 0xa334
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
-#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
-#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
-#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
-#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
-#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
-#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
-#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
-#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
-#define USB_PID_TWINHAN_VP7041_COLD 0x3201
-#define USB_PID_TWINHAN_VP7041_WARM 0x3202
-#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
-#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
-#define USB_PID_YAKUMO_DTT200U_COLD 0x0201
-#define USB_PID_YAKUMO_DTT200U_WARM 0x0301
-#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
-
-/* USB Driver stuff
- * table of devices that this driver is working with
- *
- * ATTENTION: Never ever change the order of this table, the particular
- * devices depend on this order
- *
- * Each entry is used as a reference in the device_struct. Currently this is
- * the only non-redundant way of assigning USB ids to actual devices I'm aware
- * of, because there is only one place in the code where the assignment of
- * vendor and product id is done, here.
- */
-static struct usb_device_id dib_table [] = {
-/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
-/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
-/* 02 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_COLD) },
-/* 03 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_YAKUMO_DTT200U_WARM) },
-
-/* 04 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
-/* 05 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
-/* 06 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
-/* 07 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
-/* 08 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
-/* 09 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
-/* 10 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
-/* 11 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
-/* 12 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
-/* 13 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
-/* 14 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
-/* 15 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
-/* 16 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
-/* 17 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
-/* 18 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
-/* 19 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_COLD) },
-/* 20 */ { USB_DEVICE(USB_VID_IMC_NETWORKS, USB_PID_TWINHAN_VP7041_WARM) },
-/* 21 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
-/* 22 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
-/* 23 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
-/* 24 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
-/* 25 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
-/* 26 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
-/* 27 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
-
-/* 28 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
-/* 29 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
-
-/* 30 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
-/* 31 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
-/* 32 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
-/* 33 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
-/*
- * activate the following define when you have one of the devices and want to
- * build it from build-2.6 in dvb-kernel
- */
-// #define CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
-/* 34 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
-/* 35 */ { USB_DEVICE(USB_VID_CYPRESS, USB_PID_ULTIMA_TVBOX_USB2_FX_COLD) },
-/* 36 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_USB2_FX_WARM) },
-/* 37 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_DIBCOM_ANCHOR_2135_COLD) },
-#endif
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, dib_table);
-
-static struct dibusb_usb_controller dibusb_usb_ctrl[] = {
- { .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
- { .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
- { .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
-};
-
-struct dibusb_tuner dibusb_tuner[] = {
- { DIBUSB_TUNER_CABLE_THOMSON,
- 0x61
- },
- { DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
- 0x60
- },
- { DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
- 0x61
- },
- { DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
- 0x60
- },
-};
-
-static struct dibusb_demod dibusb_demod[] = {
- { DIBUSB_DIB3000MB,
- 16,
- { 0x8, 0 },
- },
- { DIBUSB_DIB3000MC,
- 32,
- { 0x9, 0xa, 0xb, 0xc },
- },
- { DIBUSB_MT352,
- 254,
- { 0xf, 0 },
- },
- { DTT200U_FE,
- 8,
- { 0xff,0 }, /* there is no i2c bus in this device */
- }
-};
-
-static struct dibusb_device_class dibusb_device_classes[] = {
- { .id = DIBUSB1_1, .usb_ctrl = &dibusb_usb_ctrl[0],
- .firmware = "dvb-dibusb-5.0.0.11.fw",
- .pipe_cmd = 0x01, .pipe_data = 0x02,
- .urb_count = 7, .urb_buffer_size = 4096,
- DIBUSB_RC_NEC_PROTOCOL,
- &dibusb_demod[DIBUSB_DIB3000MB],
- &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
- },
- { DIBUSB1_1_AN2235, &dibusb_usb_ctrl[1],
- "dvb-dibusb-an2235-1.fw",
- 0x01, 0x02,
- 7, 4096,
- DIBUSB_RC_NEC_PROTOCOL,
- &dibusb_demod[DIBUSB_DIB3000MB],
- &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
- },
- { DIBUSB2_0,&dibusb_usb_ctrl[2],
- "dvb-dibusb-6.0.0.5.fw",
- 0x01, 0x06,
- 7, 4096,
- DIBUSB_RC_NEC_PROTOCOL,
- &dibusb_demod[DIBUSB_DIB3000MC],
- &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
- },
- { UMT2_0, &dibusb_usb_ctrl[2],
- "dvb-dibusb-umt-2.fw",
- 0x01, 0x06,
- 20, 512,
- DIBUSB_RC_NO,
- &dibusb_demod[DIBUSB_MT352],
- &dibusb_tuner[DIBUSB_TUNER_CABLE_LG_TDTP_E102P],
- },
- { DIBUSB2_0B,&dibusb_usb_ctrl[2],
- "dvb-dibusb-adstech-usb2-1.fw",
- 0x01, 0x06,
- 7, 4096,
- DIBUSB_RC_NEC_PROTOCOL,
- &dibusb_demod[DIBUSB_DIB3000MB],
- &dibusb_tuner[DIBUSB_TUNER_CABLE_THOMSON],
- },
- { NOVAT_USB2,&dibusb_usb_ctrl[2],
- "dvb-dibusb-nova-t-1.fw",
- 0x01, 0x06,
- 7, 4096,
- DIBUSB_RC_HAUPPAUGE_PROTO,
- &dibusb_demod[DIBUSB_DIB3000MC],
- &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5],
- },
- { DTT200U,&dibusb_usb_ctrl[2],
- "dvb-dtt200u-1.fw",
- 0x01, 0x02,
- 7, 4096,
- DIBUSB_RC_NO,
- &dibusb_demod[DTT200U_FE],
- NULL, /* no explicit tuner/pll-programming necessary (it has the ENV57H1XD5) */
- },
-};
-
-static struct dibusb_usb_device dibusb_devices[] = {
- { "TwinhanDTV USB1.1 / Magic Box / HAMA USB1.1 DVB-T device",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[19], &dib_table[21], NULL},
- { &dib_table[20], &dib_table[22], NULL},
- },
- { "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[11], NULL },
- { &dib_table[12], NULL },
- },
- { "Grandtec USB1.1 DVB-T",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[13], &dib_table[15], NULL },
- { &dib_table[14], &dib_table[16], NULL },
- },
- { "DiBcom USB1.1 DVB-T reference design (MOD3000)",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[7], NULL },
- { &dib_table[8], NULL },
- },
- { "Artec T1 USB1.1 TVBOX with AN2135",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[23], NULL },
- { &dib_table[24], NULL },
- },
- { "Artec T1 USB1.1 TVBOX with AN2235",
- &dibusb_device_classes[DIBUSB1_1_AN2235],
- { &dib_table[25], NULL },
- { &dib_table[26], NULL },
- },
- { "Avermedia AverTV DVBT USB1.1",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[0], NULL },
- { &dib_table[1], NULL },
- },
- { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[4], &dib_table[6], NULL},
- { &dib_table[5], NULL },
- },
- { "Unkown USB1.1 DVB-T device ???? please report the name to the author",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[17], NULL },
- { &dib_table[18], NULL },
- },
- { "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
- &dibusb_device_classes[DIBUSB2_0],
- { &dib_table[9], NULL },
- { &dib_table[10], NULL },
- },
- { "Artec T1 USB2.0 TVBOX (please report the warm ID)",
- &dibusb_device_classes[DIBUSB2_0],
- { &dib_table[27], NULL },
- { NULL },
- },
- { "Hauppauge WinTV NOVA-T USB2",
- &dibusb_device_classes[NOVAT_USB2],
- { &dib_table[30], NULL },
- { &dib_table[31], NULL },
- },
- { "DTT200U (Yakumo/Hama/Typhoon) DVB-T USB2.0",
- &dibusb_device_classes[DTT200U],
- { &dib_table[2], NULL },
- { &dib_table[3], NULL },
- },
- { "Hanftek UMT-010 DVB-T USB2.0",
- &dibusb_device_classes[UMT2_0],
- { &dib_table[28], NULL },
- { &dib_table[29], NULL },
- },
- { "KWorld/ADSTech Instant DVB-T USB 2.0",
- &dibusb_device_classes[DIBUSB2_0B],
- { &dib_table[32], NULL },
- { &dib_table[33], NULL }, /* device ID with default DIBUSB2_0-firmware */
- },
-#ifdef CONFIG_DVB_DIBUSB_MISDESIGNED_DEVICES
- { "Artec T1 USB1.1 TVBOX with AN2235 (misdesigned)",
- &dibusb_device_classes[DIBUSB1_1_AN2235],
- { &dib_table[34], NULL },
- { NULL },
- },
- { "Artec T1 USB2.0 TVBOX with FX2 IDs (misdesigned, please report the warm ID)",
- &dibusb_device_classes[DTT200U],
- { &dib_table[35], NULL },
- { &dib_table[36], NULL }, /* undefined, it could be that the device will get another USB ID in warm state */
- },
- { "DiBcom USB1.1 DVB-T reference design (MOD3000) with AN2135 default IDs",
- &dibusb_device_classes[DIBUSB1_1],
- { &dib_table[37], NULL },
- { NULL },
- },
-#endif
-};
-
-static int dibusb_exit(struct usb_dibusb *dib)
-{
- deb_info("init_state before exiting everything: %x\n",dib->init_state);
- dibusb_remote_exit(dib);
- dibusb_fe_exit(dib);
- dibusb_i2c_exit(dib);
- dibusb_dvb_exit(dib);
- dibusb_urb_exit(dib);
- deb_info("init_state should be zero now: %x\n",dib->init_state);
- dib->init_state = DIBUSB_STATE_INIT;
- kfree(dib);
- return 0;
-}
-
-static int dibusb_init(struct usb_dibusb *dib)
-{
- int ret = 0;
- sema_init(&dib->usb_sem, 1);
- sema_init(&dib->i2c_sem, 1);
-
- dib->init_state = DIBUSB_STATE_INIT;
-
- if ((ret = dibusb_urb_init(dib)) ||
- (ret = dibusb_dvb_init(dib)) ||
- (ret = dibusb_i2c_init(dib))) {
- dibusb_exit(dib);
- return ret;
- }
-
- if ((ret = dibusb_fe_init(dib)))
- err("could not initialize a frontend.");
-
- if ((ret = dibusb_remote_init(dib)))
- err("could not initialize remote control.");
-
- return 0;
-}
-
-static struct dibusb_usb_device * dibusb_device_class_quirk(struct usb_device *udev, struct dibusb_usb_device *dev)
-{
- int i;
-
- /* Quirk for the Kworld/ADSTech Instant USB2.0 device. It has the same USB
- * IDs like the USB1.1 KWorld after loading the firmware. Which is a bad
- * idea and make this quirk necessary.
- */
- if (dev->dev_cl->id == DIBUSB1_1 && udev->speed == USB_SPEED_HIGH) {
- info("this seems to be the Kworld/ADSTech Instant USB2.0 device or equal.");
- for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
- if (dibusb_devices[i].dev_cl->id == DIBUSB2_0B) {
- dev = &dibusb_devices[i];
- break;
- }
- }
- }
-
- return dev;
-}
-
-static struct dibusb_usb_device * dibusb_find_device (struct usb_device *udev,int *cold)
-{
- int i,j;
- struct dibusb_usb_device *dev = NULL;
- *cold = -1;
-
- for (i = 0; i < sizeof(dibusb_devices)/sizeof(struct dibusb_usb_device); i++) {
- for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].cold_ids[j] != NULL; j++) {
- deb_info("check for cold %x %x\n",dibusb_devices[i].cold_ids[j]->idVendor, dibusb_devices[i].cold_ids[j]->idProduct);
- if (dibusb_devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
- dibusb_devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
- *cold = 1;
- dev = &dibusb_devices[i];
- break;
- }
- }
-
- if (dev != NULL)
- break;
-
- for (j = 0; j < DIBUSB_ID_MAX_NUM && dibusb_devices[i].warm_ids[j] != NULL; j++) {
- deb_info("check for warm %x %x\n",dibusb_devices[i].warm_ids[j]->idVendor, dibusb_devices[i].warm_ids[j]->idProduct);
- if (dibusb_devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
- dibusb_devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
- *cold = 0;
- dev = &dibusb_devices[i];
- break;
- }
- }
- }
-
- if (dev != NULL)
- dev = dibusb_device_class_quirk(udev,dev);
-
- return dev;
-}
-
-/*
- * USB
- */
-static int dibusb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_dibusb *dib = NULL;
- struct dibusb_usb_device *dibdev = NULL;
-
- int ret = -ENOMEM,cold=0;
-
- if ((dibdev = dibusb_find_device(udev,&cold)) == NULL) {
- err("something went very wrong, "
- "unknown product ID: %.4x",le16_to_cpu(udev->descriptor.idProduct));
- return -ENODEV;
- }
-
- if (cold == 1) {
- info("found a '%s' in cold state, will try to load a firmware",dibdev->name);
- ret = dibusb_loadfirmware(udev,dibdev);
- } else {
- info("found a '%s' in warm state.",dibdev->name);
- dib = kmalloc(sizeof(struct usb_dibusb),GFP_KERNEL);
- if (dib == NULL) {
- err("no memory");
- return ret;
- }
- memset(dib,0,sizeof(struct usb_dibusb));
-
- dib->udev = udev;
- dib->dibdev = dibdev;
-
- /* store parameters to structures */
- dib->rc_query_interval = rc_query_interval;
- dib->pid_parse = pid_parse;
- dib->rc_key_repeat_count = rc_key_repeat_count;
-
- usb_set_intfdata(intf, dib);
-
- ret = dibusb_init(dib);
- }
-
- if (ret == 0)
- info("%s successfully initialized and connected.",dibdev->name);
- else
- info("%s error while loading driver (%d)",dibdev->name,ret);
- return ret;
-}
-
-static void dibusb_disconnect(struct usb_interface *intf)
-{
- struct usb_dibusb *dib = usb_get_intfdata(intf);
- const char *name = DRIVER_DESC;
-
- usb_set_intfdata(intf,NULL);
- if (dib != NULL && dib->dibdev != NULL) {
- name = dib->dibdev->name;
- dibusb_exit(dib);
- }
- info("%s successfully deinitialized and disconnected.",name);
-
-}
-
-/* usb specific object needed to register this driver with the usb subsystem */
-static struct usb_driver dibusb_driver = {
- .owner = THIS_MODULE,
- .name = DRIVER_DESC,
- .probe = dibusb_probe,
- .disconnect = dibusb_disconnect,
- .id_table = dib_table,
-};
-
-/* module stuff */
-static int __init usb_dibusb_init(void)
-{
- int result;
- if ((result = usb_register(&dibusb_driver))) {
- err("usb_register failed. Error number %d",result);
- return result;
- }
-
- return 0;
-}
-
-static void __exit usb_dibusb_exit(void)
-{
- /* deregister this driver from the USB subsystem */
- usb_deregister(&dibusb_driver);
-}
-
-module_init (usb_dibusb_init);
-module_exit (usb_dibusb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c b/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
deleted file mode 100644
index 400b439e804e..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-dvb.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * dvb-dibusb-dvb.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the
- * linux-dvb API.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/usb.h>
-#include <linux/version.h>
-
-static u32 urb_compl_count;
-
-/*
- * MPEG2 TS DVB stuff
- */
-void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
-{
- struct usb_dibusb *dib = urb->context;
-
- deb_ts("urb complete feedcount: %d, status: %d, length: %d\n",dib->feedcount,urb->status,
- urb->actual_length);
-
- urb_compl_count++;
- if (urb_compl_count % 1000 == 0)
- deb_info("%d urbs completed so far.\n",urb_compl_count);
-
- switch (urb->status) {
- case 0: /* success */
- case -ETIMEDOUT: /* NAK */
- break;
- case -ECONNRESET: /* kill */
- case -ENOENT:
- case -ESHUTDOWN:
- return;
- default: /* error */
- deb_ts("urb completition error %d.", urb->status);
- break;
- }
-
- if (dib->feedcount > 0 && urb->actual_length > 0) {
- if (dib->init_state & DIBUSB_STATE_DVB)
- dvb_dmx_swfilter(&dib->demux, (u8*) urb->transfer_buffer,urb->actual_length);
- } else
- deb_ts("URB dropped because of feedcount.\n");
-
- usb_submit_urb(urb,GFP_ATOMIC);
-}
-
-static int dibusb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
-{
- struct usb_dibusb *dib = dvbdmxfeed->demux->priv;
- int newfeedcount;
-
- if (dib == NULL)
- return -ENODEV;
-
- newfeedcount = dib->feedcount + (onoff ? 1 : -1);
-
- /*
- * stop feed before setting a new pid if there will be no pid anymore
- */
- if (newfeedcount == 0) {
- deb_ts("stop feeding\n");
- if (dib->xfer_ops.fifo_ctrl != NULL) {
- if (dib->xfer_ops.fifo_ctrl(dib->fe,0)) {
- err("error while inhibiting fifo.");
- return -ENODEV;
- }
- }
- dibusb_streaming(dib,0);
- }
-
- dib->feedcount = newfeedcount;
-
- /* activate the pid on the device specific pid_filter */
- deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
- if (dib->pid_parse && dib->xfer_ops.pid_ctrl != NULL)
- dib->xfer_ops.pid_ctrl(dib->fe,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
-
- /*
- * start the feed if this was the first pid to set and there is still a pid
- * for reception.
- */
- if (dib->feedcount == onoff && dib->feedcount > 0) {
-
- deb_ts("controlling pid parser\n");
- if (dib->xfer_ops.pid_parse != NULL) {
- if (dib->xfer_ops.pid_parse(dib->fe,dib->pid_parse) < 0) {
- err("could not handle pid_parser");
- }
- }
-
- deb_ts("start feeding\n");
- if (dib->xfer_ops.fifo_ctrl != NULL) {
- if (dib->xfer_ops.fifo_ctrl(dib->fe,1)) {
- err("error while enabling fifo.");
- return -ENODEV;
- }
- }
- dibusb_streaming(dib,1);
- }
- return 0;
-}
-
-static int dibusb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
- return dibusb_ctrl_feed(dvbdmxfeed,1);
-}
-
-static int dibusb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
-{
- deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
- return dibusb_ctrl_feed(dvbdmxfeed,0);
-}
-
-int dibusb_dvb_init(struct usb_dibusb *dib)
-{
- int ret;
-
- urb_compl_count = 0;
-
- if ((ret = dvb_register_adapter(&dib->adapter, DRIVER_DESC,
- THIS_MODULE)) < 0) {
- deb_info("dvb_register_adapter failed: error %d", ret);
- goto err;
- }
- dib->adapter.priv = dib;
-
-/* i2c is done in dibusb_i2c_init */
-
- dib->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
-
- dib->demux.priv = (void *)dib;
- /* get pidcount from demod */
- dib->demux.feednum = dib->demux.filternum = 255;
- dib->demux.start_feed = dibusb_start_feed;
- dib->demux.stop_feed = dibusb_stop_feed;
- dib->demux.write_to_decoder = NULL;
- if ((ret = dvb_dmx_init(&dib->demux)) < 0) {
- err("dvb_dmx_init failed: error %d",ret);
- goto err_dmx;
- }
-
- dib->dmxdev.filternum = dib->demux.filternum;
- dib->dmxdev.demux = &dib->demux.dmx;
- dib->dmxdev.capabilities = 0;
- if ((ret = dvb_dmxdev_init(&dib->dmxdev, &dib->adapter)) < 0) {
- err("dvb_dmxdev_init failed: error %d",ret);
- goto err_dmx_dev;
- }
-
- dvb_net_init(&dib->adapter, &dib->dvb_net, &dib->demux.dmx);
-
- goto success;
-err_dmx_dev:
- dvb_dmx_release(&dib->demux);
-err_dmx:
- dvb_unregister_adapter(&dib->adapter);
-err:
- return ret;
-success:
- dib->init_state |= DIBUSB_STATE_DVB;
- return 0;
-}
-
-int dibusb_dvb_exit(struct usb_dibusb *dib)
-{
- if (dib->init_state & DIBUSB_STATE_DVB) {
- dib->init_state &= ~DIBUSB_STATE_DVB;
- deb_info("unregistering DVB part\n");
- dvb_net_release(&dib->dvb_net);
- dib->demux.dmx.close(&dib->demux.dmx);
- dvb_dmxdev_release(&dib->dmxdev);
- dvb_dmx_release(&dib->demux);
- dvb_unregister_adapter(&dib->adapter);
- }
- return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c b/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
deleted file mode 100644
index 5a71b88797d9..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-fe-i2c.c
+++ /dev/null
@@ -1,582 +0,0 @@
-/*
- * dvb-dibusb-fe-i2c.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for attaching, initializing of an appropriate
- * demodulator/frontend. I2C-stuff is also located here.
- *
- */
-#include "dvb-dibusb.h"
-
-#include <linux/usb.h>
-
-static int dibusb_i2c_msg(struct usb_dibusb *dib, u8 addr,
- u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
-{
- u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
- /* write only ? */
- int wo = (rbuf == NULL || rlen == 0),
- len = 2 + wlen + (wo ? 0 : 2);
-
- sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
- sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
-
- memcpy(&sndbuf[2],wbuf,wlen);
-
- if (!wo) {
- sndbuf[wlen+2] = (rlen >> 8) & 0xff;
- sndbuf[wlen+3] = rlen & 0xff;
- }
-
- return dibusb_readwrite_usb(dib,sndbuf,len,rbuf,rlen);
-}
-
-/*
- * I2C master xfer function
- */
-static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg *msg,int num)
-{
- struct usb_dibusb *dib = i2c_get_adapdata(adap);
- int i;
-
- if (down_interruptible(&dib->i2c_sem) < 0)
- return -EAGAIN;
-
- if (num > 2)
- warn("more than 2 i2c messages at a time is not handled yet. TODO.");
-
- for (i = 0; i < num; i++) {
- /* write/read request */
- if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
- if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,
- msg[i+1].buf,msg[i+1].len) < 0)
- break;
- i++;
- } else
- if (dibusb_i2c_msg(dib, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
- break;
- }
-
- up(&dib->i2c_sem);
- return i;
-}
-
-static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static struct i2c_algorithm dibusb_algo = {
- .name = "DiBcom USB i2c algorithm",
- .id = I2C_ALGO_BIT,
- .master_xfer = dibusb_i2c_xfer,
- .functionality = dibusb_i2c_func,
-};
-
-static int dibusb_general_demod_init(struct dvb_frontend *fe);
-static u8 dibusb_general_pll_addr(struct dvb_frontend *fe);
-static int dibusb_general_pll_init(struct dvb_frontend *fe, u8 pll_buf[5]);
-static int dibusb_general_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters* params, u8 pll_buf[5]);
-
-static struct mt352_config mt352_hanftek_umt_010_config = {
- .demod_address = 0x1e,
- .demod_init = dibusb_general_demod_init,
- .pll_set = dibusb_general_pll_set,
-};
-
-static int dibusb_tuner_quirk(struct usb_dibusb *dib)
-{
- switch (dib->dibdev->dev_cl->id) {
- case DIBUSB1_1: /* some these device have the ENV77H11D5 and some the THOMSON CABLE */
- case DIBUSB1_1_AN2235: { /* actually its this device, but in warm state they are indistinguishable */
- struct dibusb_tuner *t;
- u8 b[2] = { 0,0 } ,b2[1];
- struct i2c_msg msg[2] = {
- { .flags = 0, .buf = b, .len = 2 },
- { .flags = I2C_M_RD, .buf = b2, .len = 1},
- };
-
- t = &dibusb_tuner[DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5];
-
- msg[0].addr = msg[1].addr = t->pll_addr;
-
- if (dib->xfer_ops.tuner_pass_ctrl != NULL)
- dib->xfer_ops.tuner_pass_ctrl(dib->fe,1,t->pll_addr);
- dibusb_i2c_xfer(&dib->i2c_adap,msg,2);
- if (dib->xfer_ops.tuner_pass_ctrl != NULL)
- dib->xfer_ops.tuner_pass_ctrl(dib->fe,0,t->pll_addr);
-
- if (b2[0] == 0xfe)
- info("this device has the Thomson Cable onboard. Which is default.");
- else {
- dib->tuner = t;
- info("this device has the Panasonic ENV77H11D5 onboard.");
- }
- break;
- }
- default:
- break;
- }
- return 0;
-}
-
-int dibusb_fe_init(struct usb_dibusb* dib)
-{
- struct dib3000_config demod_cfg;
- int i;
-
- if (dib->init_state & DIBUSB_STATE_I2C) {
- for (i = 0; i < sizeof(dib->dibdev->dev_cl->demod->i2c_addrs) / sizeof(unsigned char) &&
- dib->dibdev->dev_cl->demod->i2c_addrs[i] != 0; i++) {
-
- demod_cfg.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
- demod_cfg.pll_addr = dibusb_general_pll_addr;
- demod_cfg.pll_set = dibusb_general_pll_set;
- demod_cfg.pll_init = dibusb_general_pll_init;
-
- deb_info("demod id: %d %d\n",dib->dibdev->dev_cl->demod->id,DTT200U_FE);
-
- switch (dib->dibdev->dev_cl->demod->id) {
- case DIBUSB_DIB3000MB:
- dib->fe = dib3000mb_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
- break;
- case DIBUSB_DIB3000MC:
- dib->fe = dib3000mc_attach(&demod_cfg,&dib->i2c_adap,&dib->xfer_ops);
- break;
- case DIBUSB_MT352:
- mt352_hanftek_umt_010_config.demod_address = dib->dibdev->dev_cl->demod->i2c_addrs[i];
- dib->fe = mt352_attach(&mt352_hanftek_umt_010_config, &dib->i2c_adap);
- break;
- case DTT200U_FE:
- dib->fe = dtt200u_fe_attach(dib,&dib->xfer_ops);
- break;
- }
- if (dib->fe != NULL) {
- info("found demodulator at i2c address 0x%x",dib->dibdev->dev_cl->demod->i2c_addrs[i]);
- break;
- }
- }
- /* if a frontend was found */
- if (dib->fe != NULL) {
- if (dib->fe->ops->sleep != NULL)
- dib->fe_sleep = dib->fe->ops->sleep;
- dib->fe->ops->sleep = dibusb_hw_sleep;
-
- if (dib->fe->ops->init != NULL )
- dib->fe_init = dib->fe->ops->init;
- dib->fe->ops->init = dibusb_hw_wakeup;
-
- /* setting the default tuner */
- dib->tuner = dib->dibdev->dev_cl->tuner;
-
- /* check which tuner is mounted on this device, in case this is unsure */
- dibusb_tuner_quirk(dib);
- }
- }
- if (dib->fe == NULL) {
- err("A frontend driver was not found for device '%s'.",
- dib->dibdev->name);
- return -ENODEV;
- } else {
- if (dvb_register_frontend(&dib->adapter, dib->fe)) {
- err("Frontend registration failed.");
- if (dib->fe->ops->release)
- dib->fe->ops->release(dib->fe);
- dib->fe = NULL;
- return -ENODEV;
- }
- }
-
- return 0;
-}
-
-int dibusb_fe_exit(struct usb_dibusb *dib)
-{
- if (dib->fe != NULL)
- dvb_unregister_frontend(dib->fe);
- return 0;
-}
-
-int dibusb_i2c_init(struct usb_dibusb *dib)
-{
- int ret = 0;
-
- dib->adapter.priv = dib;
-
- strncpy(dib->i2c_adap.name,dib->dibdev->name,I2C_NAME_SIZE);
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- dib->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
- dib->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
- dib->i2c_adap.algo = &dibusb_algo;
- dib->i2c_adap.algo_data = NULL;
- dib->i2c_adap.id = I2C_ALGO_BIT;
-
- i2c_set_adapdata(&dib->i2c_adap, dib);
-
- if ((ret = i2c_add_adapter(&dib->i2c_adap)) < 0)
- err("could not add i2c adapter");
-
- dib->init_state |= DIBUSB_STATE_I2C;
-
- return ret;
-}
-
-int dibusb_i2c_exit(struct usb_dibusb *dib)
-{
- if (dib->init_state & DIBUSB_STATE_I2C)
- i2c_del_adapter(&dib->i2c_adap);
- dib->init_state &= ~DIBUSB_STATE_I2C;
- return 0;
-}
-
-
-/* pll stuff, maybe removed soon (thx to Gerd/Andrew in advance) */
-static int thomson_cable_eu_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
-{
- u32 tfreq = (fep->frequency + 36125000) / 62500;
- int vu,p0,p1,p2;
-
- if (fep->frequency > 403250000)
- vu = 1, p2 = 1, p1 = 0, p0 = 1;
- else if (fep->frequency > 115750000)
- vu = 0, p2 = 1, p1 = 1, p0 = 0;
- else if (fep->frequency > 44250000)
- vu = 0, p2 = 0, p1 = 1, p0 = 1;
- else
- return -EINVAL;
-
- pllbuf[0] = (tfreq >> 8) & 0x7f;
- pllbuf[1] = tfreq & 0xff;
- pllbuf[2] = 0x8e;
- pllbuf[3] = (vu << 7) | (p2 << 2) | (p1 << 1) | p0;
- return 0;
-}
-
-static int panasonic_cofdm_env57h1xd5_pll_set(struct dvb_frontend_parameters *fep, u8 pllbuf[4])
-{
- u32 freq_khz = fep->frequency / 1000;
- u32 tfreq = ((freq_khz + 36125)*6 + 500) / 1000;
- u8 TA, T210, R210, ctrl1, cp210, p4321;
- if (freq_khz > 858000) {
- err("frequency cannot be larger than 858 MHz.");
- return -EINVAL;
- }
-
- // contol data 1 : 1 | T/A=1 | T2,T1,T0 = 0,0,0 | R2,R1,R0 = 0,1,0
- TA = 1;
- T210 = 0;
- R210 = 0x2;
- ctrl1 = (1 << 7) | (TA << 6) | (T210 << 3) | R210;
-
-// ******** CHARGE PUMP CONFIG vs RF FREQUENCIES *****************
- if (freq_khz < 470000)
- cp210 = 2; // VHF Low and High band ch E12 to E4 to E12
- else if (freq_khz < 526000)
- cp210 = 4; // UHF band Ch E21 to E27
- else // if (freq < 862000000)
- cp210 = 5; // UHF band ch E28 to E69
-
-//********************* BW select *******************************
- if (freq_khz < 153000)
- p4321 = 1; // BW selected for VHF low
- else if (freq_khz < 470000)
- p4321 = 2; // BW selected for VHF high E5 to E12
- else // if (freq < 862000000)
- p4321 = 4; // BW selection for UHF E21 to E69
-
- pllbuf[0] = (tfreq >> 8) & 0xff;
- pllbuf[1] = (tfreq >> 0) & 0xff;
- pllbuf[2] = 0xff & ctrl1;
- pllbuf[3] = (cp210 << 5) | (p4321);
-
- return 0;
-}
-
-/*
- * 7 6 5 4 3 2 1 0
- * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0
- *
- * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8
- * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0
- *
- * Control byte 1 1 T/A=1 T2 T1 T0 R2 R1 R0
- * 1 T/A=0 0 0 ATC AL2 AL1 AL0
- *
- * Control byte 2 CP2 CP1 CP0 BS5 BS4 BS3 BS2 BS1
- *
- * MA0/1 = programmable address bits
- * R/~W = read/write bit (0 for writing)
- * N14-0 = programmable LO frequency
- *
- * T/A = test AGC bit (0 = next 6 bits AGC setting,
- * 1 = next 6 bits test and reference divider ratio settings)
- * T2-0 = test bits
- * R2-0 = reference divider ratio and programmable frequency step
- * ATC = AGC current setting and time constant
- * ATC = 0: AGC current = 220nA, AGC time constant = 2s
- * ATC = 1: AGC current = 9uA, AGC time constant = 50ms
- * AL2-0 = AGC take-over point bits
- * CP2-0 = charge pump current
- * BS5-1 = PMOS ports control bits;
- * BSn = 0 corresponding port is off, high-impedance state (at power-on)
- * BSn = 1 corresponding port is on
- */
-static int panasonic_cofdm_env77h11d5_tda6650_init(struct dvb_frontend *fe, u8 pllbuf[4])
-{
- pllbuf[0] = 0x0b;
- pllbuf[1] = 0xf5;
- pllbuf[2] = 0x85;
- pllbuf[3] = 0xab;
- return 0;
-}
-
-static int panasonic_cofdm_env77h11d5_tda6650_set (struct dvb_frontend_parameters *fep,u8 pllbuf[4])
-{
- int tuner_frequency = 0;
- u8 band, cp, filter;
-
- // determine charge pump
- tuner_frequency = fep->frequency + 36166000;
- if (tuner_frequency < 87000000)
- return -EINVAL;
- else if (tuner_frequency < 130000000)
- cp = 3;
- else if (tuner_frequency < 160000000)
- cp = 5;
- else if (tuner_frequency < 200000000)
- cp = 6;
- else if (tuner_frequency < 290000000)
- cp = 3;
- else if (tuner_frequency < 420000000)
- cp = 5;
- else if (tuner_frequency < 480000000)
- cp = 6;
- else if (tuner_frequency < 620000000)
- cp = 3;
- else if (tuner_frequency < 830000000)
- cp = 5;
- else if (tuner_frequency < 895000000)
- cp = 7;
- else
- return -EINVAL;
-
- // determine band
- if (fep->frequency < 49000000)
- return -EINVAL;
- else if (fep->frequency < 161000000)
- band = 1;
- else if (fep->frequency < 444000000)
- band = 2;
- else if (fep->frequency < 861000000)
- band = 4;
- else
- return -EINVAL;
-
- // setup PLL filter
- switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_6_MHZ:
- case BANDWIDTH_7_MHZ:
- filter = 0;
- break;
- case BANDWIDTH_8_MHZ:
- filter = 1;
- break;
- default:
- return -EINVAL;
- }
-
- // calculate divisor
- // ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
- tuner_frequency = (((fep->frequency / 1000) * 6) + 217496) / 1000;
-
- // setup tuner buffer
- pllbuf[0] = (tuner_frequency >> 8) & 0x7f;
- pllbuf[1] = tuner_frequency & 0xff;
- pllbuf[2] = 0xca;
- pllbuf[3] = (cp << 5) | (filter << 3) | band;
- return 0;
-}
-
-/*
- * 7 6 5 4 3 2 1 0
- * Address Byte 1 1 0 0 0 MA1 MA0 R/~W=0
- *
- * Program divider byte 1 0 n14 n13 n12 n11 n10 n9 n8
- * Program divider byte 2 n7 n6 n5 n4 n3 n2 n1 n0
- *
- * Control byte 1 CP T2 T1 T0 RSA RSB OS
- *
- * Band Switch byte X X X P4 P3 P2 P1 P0
- *
- * Auxiliary byte ATC AL2 AL1 AL0 0 0 0 0
- *
- * Address: MA1 MA0 Address
- * 0 0 c0
- * 0 1 c2 (always valid)
- * 1 0 c4
- * 1 1 c6
- */
-static int lg_tdtp_e102p_tua6034(struct dvb_frontend_parameters* fep, u8 pllbuf[4])
-{
- u32 div;
- u8 p210, p3;
-
-#define TUNER_MUL 62500
-
- div = (fep->frequency + 36125000 + TUNER_MUL / 2) / TUNER_MUL;
-// div = ((fep->frequency/1000 + 36166) * 6) / 1000;
-
- if (fep->frequency < 174500000)
- p210 = 1; // not supported by the tdtp_e102p
- else if (fep->frequency < 230000000) // VHF
- p210 = 2;
- else
- p210 = 4;
-
- if (fep->u.ofdm.bandwidth == BANDWIDTH_7_MHZ)
- p3 = 0;
- else
- p3 = 1;
-
- pllbuf[0] = (div >> 8) & 0x7f;
- pllbuf[1] = div & 0xff;
- pllbuf[2] = 0xce;
-// pllbuf[2] = 0xcc;
- pllbuf[3] = (p3 << 3) | p210;
-
- return 0;
-}
-
-static int lg_tdtp_e102p_mt352_demod_init(struct dvb_frontend *fe)
-{
- static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
- static u8 mt352_reset[] = { 0x50, 0x80 };
- static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
- static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
- static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
-
- static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
- static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
- static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
- static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
- static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
-
- static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
- static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
-
- mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
- udelay(2000);
- mt352_write(fe, mt352_reset, sizeof(mt352_reset));
- mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
-
- mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
- mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
-
- mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
- mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
- mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
- mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
- mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
-
- mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
- mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
-
- return 0;
-}
-
-static int dibusb_general_demod_init(struct dvb_frontend *fe)
-{
- struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
- switch (dib->dibdev->dev_cl->id) {
- case UMT2_0:
- return lg_tdtp_e102p_mt352_demod_init(fe);
- default: /* other device classes do not have device specific demod inits */
- break;
- }
- return 0;
-}
-
-static u8 dibusb_general_pll_addr(struct dvb_frontend *fe)
-{
- struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
- return dib->tuner->pll_addr;
-}
-
-static int dibusb_pll_i2c_helper(struct usb_dibusb *dib, u8 pll_buf[5], u8 buf[4])
-{
- if (pll_buf == NULL) {
- struct i2c_msg msg = {
- .addr = dib->tuner->pll_addr,
- .flags = 0,
- .buf = buf,
- .len = sizeof(buf)
- };
- if (i2c_transfer (&dib->i2c_adap, &msg, 1) != 1)
- return -EIO;
- msleep(1);
- } else {
- pll_buf[0] = dib->tuner->pll_addr << 1;
- memcpy(&pll_buf[1],buf,4);
- }
-
- return 0;
-}
-
-static int dibusb_general_pll_init(struct dvb_frontend *fe,
- u8 pll_buf[5])
-{
- struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
- u8 buf[4];
- int ret=0;
- switch (dib->tuner->id) {
- case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
- ret = panasonic_cofdm_env77h11d5_tda6650_init(fe,buf);
- break;
- default:
- break;
- }
-
- if (ret)
- return ret;
-
- return dibusb_pll_i2c_helper(dib,pll_buf,buf);
-}
-
-static int dibusb_general_pll_set(struct dvb_frontend *fe,
- struct dvb_frontend_parameters *fep, u8 pll_buf[5])
-{
- struct usb_dibusb* dib = (struct usb_dibusb*) fe->dvb->priv;
- u8 buf[4];
- int ret=0;
-
- switch (dib->tuner->id) {
- case DIBUSB_TUNER_CABLE_THOMSON:
- ret = thomson_cable_eu_pll_set(fep, buf);
- break;
- case DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5:
- ret = panasonic_cofdm_env57h1xd5_pll_set(fep, buf);
- break;
- case DIBUSB_TUNER_CABLE_LG_TDTP_E102P:
- ret = lg_tdtp_e102p_tua6034(fep, buf);
- break;
- case DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5:
- ret = panasonic_cofdm_env77h11d5_tda6650_set(fep,buf);
- break;
- default:
- warn("no pll programming routine found for tuner %d.\n",dib->tuner->id);
- ret = -ENODEV;
- break;
- }
-
- if (ret)
- return ret;
-
- return dibusb_pll_i2c_helper(dib,pll_buf,buf);
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c b/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
deleted file mode 100644
index 504ba47afdf3..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-firmware.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * dvb-dibusb-firmware.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for downloading the firmware to the device.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/firmware.h>
-#include <linux/usb.h>
-
-/*
- * load a firmware packet to the device
- */
-static int dibusb_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
-{
- return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
- 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5000);
-}
-
-int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev)
-{
- const struct firmware *fw = NULL;
- u16 addr;
- u8 *b,*p;
- int ret = 0,i;
-
- if ((ret = request_firmware(&fw, dibdev->dev_cl->firmware, &udev->dev)) != 0) {
- err("did not find the firmware file. (%s) "
- "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
- dibdev->dev_cl->firmware);
- return ret;
- }
-
- info("downloading firmware from file '%s'.",dibdev->dev_cl->firmware);
-
- p = kmalloc(fw->size,GFP_KERNEL);
- if (p != NULL) {
- u8 reset;
- /*
- * you cannot use the fw->data as buffer for
- * usb_control_msg, a new buffer has to be
- * created
- */
- memcpy(p,fw->data,fw->size);
-
- /* stop the CPU */
- reset = 1;
- if ((ret = dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1)) != 1)
- err("could not stop the USB controller CPU.");
- for(i = 0; p[i+3] == 0 && i < fw->size; ) {
- b = (u8 *) &p[i];
- addr = *((u16 *) &b[1]);
-
- ret = dibusb_writemem(udev,addr,&b[4],b[0]);
-
- if (ret != b[0]) {
- err("error while transferring firmware "
- "(transferred size: %d, block size: %d)",
- ret,b[0]);
- ret = -EINVAL;
- break;
- }
- i += 5 + b[0];
- }
- /* length in ret */
- if (ret > 0)
- ret = 0;
- /* restart the CPU */
- reset = 0;
- if (ret || dibusb_writemem(udev,dibdev->dev_cl->usb_ctrl->cpu_cs_register,&reset,1) != 1) {
- err("could not restart the USB controller CPU.");
- ret = -EINVAL;
- }
-
- kfree(p);
- } else {
- ret = -ENOMEM;
- }
- release_firmware(fw);
-
- return ret;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c b/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
deleted file mode 100644
index 9dc8b15517b7..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-remote.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * dvb-dibusb-remote.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for handling the event device on the software
- * side and the remote control on the hardware side.
- */
-#include "dvb-dibusb.h"
-
-/* Table to map raw key codes to key events. This should not be hard-wired
- into the kernel. */
-static const struct { u8 c0, c1, c2; uint32_t key; } nec_rc_keys [] =
-{
- /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
- { 0x00, 0xff, 0x16, KEY_POWER },
- { 0x00, 0xff, 0x10, KEY_MUTE },
- { 0x00, 0xff, 0x03, KEY_1 },
- { 0x00, 0xff, 0x01, KEY_2 },
- { 0x00, 0xff, 0x06, KEY_3 },
- { 0x00, 0xff, 0x09, KEY_4 },
- { 0x00, 0xff, 0x1d, KEY_5 },
- { 0x00, 0xff, 0x1f, KEY_6 },
- { 0x00, 0xff, 0x0d, KEY_7 },
- { 0x00, 0xff, 0x19, KEY_8 },
- { 0x00, 0xff, 0x1b, KEY_9 },
- { 0x00, 0xff, 0x15, KEY_0 },
- { 0x00, 0xff, 0x05, KEY_CHANNELUP },
- { 0x00, 0xff, 0x02, KEY_CHANNELDOWN },
- { 0x00, 0xff, 0x1e, KEY_VOLUMEUP },
- { 0x00, 0xff, 0x0a, KEY_VOLUMEDOWN },
- { 0x00, 0xff, 0x11, KEY_RECORD },
- { 0x00, 0xff, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
- { 0x00, 0xff, 0x14, KEY_PLAY },
- { 0x00, 0xff, 0x1a, KEY_STOP },
- { 0x00, 0xff, 0x40, KEY_REWIND },
- { 0x00, 0xff, 0x12, KEY_FASTFORWARD },
- { 0x00, 0xff, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
- { 0x00, 0xff, 0x4c, KEY_PAUSE },
- { 0x00, 0xff, 0x4d, KEY_SCREEN }, /* Full screen mode. */
- { 0x00, 0xff, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
- /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
- { 0x00, 0xff, 0x0c, KEY_CANCEL }, /* Cancel */
- { 0x00, 0xff, 0x1c, KEY_EPG }, /* EPG */
- { 0x00, 0xff, 0x00, KEY_TAB }, /* Tab */
- { 0x00, 0xff, 0x48, KEY_INFO }, /* Preview */
- { 0x00, 0xff, 0x04, KEY_LIST }, /* RecordList */
- { 0x00, 0xff, 0x0f, KEY_TEXT }, /* Teletext */
- /* Key codes for the KWorld/ADSTech/JetWay remote. */
- { 0x86, 0x6b, 0x12, KEY_POWER },
- { 0x86, 0x6b, 0x0f, KEY_SELECT }, /* source */
- { 0x86, 0x6b, 0x0c, KEY_UNKNOWN }, /* scan */
- { 0x86, 0x6b, 0x0b, KEY_EPG },
- { 0x86, 0x6b, 0x10, KEY_MUTE },
- { 0x86, 0x6b, 0x01, KEY_1 },
- { 0x86, 0x6b, 0x02, KEY_2 },
- { 0x86, 0x6b, 0x03, KEY_3 },
- { 0x86, 0x6b, 0x04, KEY_4 },
- { 0x86, 0x6b, 0x05, KEY_5 },
- { 0x86, 0x6b, 0x06, KEY_6 },
- { 0x86, 0x6b, 0x07, KEY_7 },
- { 0x86, 0x6b, 0x08, KEY_8 },
- { 0x86, 0x6b, 0x09, KEY_9 },
- { 0x86, 0x6b, 0x0a, KEY_0 },
- { 0x86, 0x6b, 0x18, KEY_ZOOM },
- { 0x86, 0x6b, 0x1c, KEY_UNKNOWN }, /* preview */
- { 0x86, 0x6b, 0x13, KEY_UNKNOWN }, /* snap */
- { 0x86, 0x6b, 0x00, KEY_UNDO },
- { 0x86, 0x6b, 0x1d, KEY_RECORD },
- { 0x86, 0x6b, 0x0d, KEY_STOP },
- { 0x86, 0x6b, 0x0e, KEY_PAUSE },
- { 0x86, 0x6b, 0x16, KEY_PLAY },
- { 0x86, 0x6b, 0x11, KEY_BACK },
- { 0x86, 0x6b, 0x19, KEY_FORWARD },
- { 0x86, 0x6b, 0x14, KEY_UNKNOWN }, /* pip */
- { 0x86, 0x6b, 0x15, KEY_ESC },
- { 0x86, 0x6b, 0x1a, KEY_UP },
- { 0x86, 0x6b, 0x1e, KEY_DOWN },
- { 0x86, 0x6b, 0x1f, KEY_LEFT },
- { 0x86, 0x6b, 0x1b, KEY_RIGHT },
-};
-
-/* Hauppauge NOVA-T USB2 keys */
-static const struct { u16 raw; uint32_t key; } haupp_rc_keys [] = {
- { 0xddf, KEY_GOTO },
- { 0xdef, KEY_POWER },
- { 0xce7, KEY_TV },
- { 0xcc7, KEY_VIDEO },
- { 0xccf, KEY_AUDIO },
- { 0xcd7, KEY_MEDIA },
- { 0xcdf, KEY_EPG },
- { 0xca7, KEY_UP },
- { 0xc67, KEY_RADIO },
- { 0xcb7, KEY_LEFT },
- { 0xd2f, KEY_OK },
- { 0xcbf, KEY_RIGHT },
- { 0xcff, KEY_BACK },
- { 0xcaf, KEY_DOWN },
- { 0xc6f, KEY_MENU },
- { 0xc87, KEY_VOLUMEUP },
- { 0xc8f, KEY_VOLUMEDOWN },
- { 0xc97, KEY_CHANNEL },
- { 0xc7f, KEY_MUTE },
- { 0xd07, KEY_CHANNELUP },
- { 0xd0f, KEY_CHANNELDOWN },
- { 0xdbf, KEY_RECORD },
- { 0xdb7, KEY_STOP },
- { 0xd97, KEY_REWIND },
- { 0xdaf, KEY_PLAY },
- { 0xda7, KEY_FASTFORWARD },
- { 0xd27, KEY_LAST }, /* Skip backwards */
- { 0xd87, KEY_PAUSE },
- { 0xcf7, KEY_NEXT },
- { 0xc07, KEY_0 },
- { 0xc0f, KEY_1 },
- { 0xc17, KEY_2 },
- { 0xc1f, KEY_3 },
- { 0xc27, KEY_4 },
- { 0xc2f, KEY_5 },
- { 0xc37, KEY_6 },
- { 0xc3f, KEY_7 },
- { 0xc47, KEY_8 },
- { 0xc4f, KEY_9 },
- { 0xc57, KEY_KPASTERISK },
- { 0xc77, KEY_GRAVE }, /* # */
- { 0xc5f, KEY_RED },
- { 0xd77, KEY_GREEN },
- { 0xdc7, KEY_YELLOW },
- { 0xd4f, KEY_BLUE},
-};
-
-static int dibusb_key2event_nec(struct usb_dibusb *dib,u8 rb[5])
-{
- int i;
- switch (rb[0]) {
- case DIBUSB_RC_NEC_KEY_PRESSED:
- /* rb[1-3] is the actual key, rb[4] is a checksum */
- deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x, 0x%02x\n",
- rb[1], rb[2], rb[3], rb[4]);
-
- if ((0xff - rb[3]) != rb[4]) {
- deb_rc("remote control checksum failed.\n");
- break;
- }
-
- /* See if we can match the raw key code. */
- for (i = 0; i < sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++) {
- if (nec_rc_keys[i].c0 == rb[1] &&
- nec_rc_keys[i].c1 == rb[2] &&
- nec_rc_keys[i].c2 == rb[3]) {
-
- dib->last_event = nec_rc_keys[i].key;
- return 1;
- }
- }
- break;
- case DIBUSB_RC_NEC_KEY_REPEATED:
- /* rb[1]..rb[4] are always zero.*/
- /* Repeats often seem to occur so for the moment just ignore this. */
- return 0;
- case DIBUSB_RC_NEC_EMPTY: /* No (more) remote control keys. */
- default:
- break;
- }
- return -1;
-}
-
-static int dibusb_key2event_hauppauge(struct usb_dibusb *dib,u8 rb[4])
-{
- u16 raw;
- int i,state;
- switch (rb[0]) {
- case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
- raw = ((rb[1] & 0x0f) << 8) | rb[2];
-
- state = !!(rb[1] & 0x40);
-
- deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to %04x state: %d\n",rb[1],rb[2],rb[3],raw,state);
- for (i = 0; i < sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++) {
- if (haupp_rc_keys[i].raw == raw) {
- if (dib->last_event == haupp_rc_keys[i].key &&
- dib->last_state == state) {
- deb_rc("key repeat\n");
- return 0;
- } else {
- dib->last_event = haupp_rc_keys[i].key;
- dib->last_state = state;
- return 1;
- }
- }
- }
-
- break;
- case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
- default:
- break;
- }
- return -1;
-}
-
-/*
- * Read the remote control and feed the appropriate event.
- * NEC protocol is used for remote controls
- */
-static int dibusb_read_remote_control(struct usb_dibusb *dib)
-{
- u8 b[1] = { DIBUSB_REQ_POLL_REMOTE }, rb[5];
- int ret,event = 0;
-
- if ((ret = dibusb_readwrite_usb(dib,b,1,rb,5)))
- return ret;
-
- switch (dib->dibdev->dev_cl->remote_type) {
- case DIBUSB_RC_NEC_PROTOCOL:
- event = dibusb_key2event_nec(dib,rb);
- break;
- case DIBUSB_RC_HAUPPAUGE_PROTO:
- event = dibusb_key2event_hauppauge(dib,rb);
- default:
- break;
- }
-
- /* key repeat */
- if (event == 0)
- if (++dib->repeat_key_count < dib->rc_key_repeat_count) {
- deb_rc("key repeat dropped. (%d)\n",dib->repeat_key_count);
- event = -1; /* skip this key repeat */
- }
-
- if (event == 1 || event == 0) {
- deb_rc("Translated key 0x%04x\n",event);
-
- /* Signal down and up events for this key. */
- input_report_key(&dib->rc_input_dev, dib->last_event, 1);
- input_report_key(&dib->rc_input_dev, dib->last_event, 0);
- input_sync(&dib->rc_input_dev);
-
- if (event == 1)
- dib->repeat_key_count = 0;
- }
- return 0;
-}
-
-/* Remote-control poll function - called every dib->rc_query_interval ms to see
- whether the remote control has received anything. */
-static void dibusb_remote_query(void *data)
-{
- struct usb_dibusb *dib = (struct usb_dibusb *) data;
- /* TODO: need a lock here. We can simply skip checking for the remote control
- if we're busy. */
- dibusb_read_remote_control(dib);
- schedule_delayed_work(&dib->rc_query_work,
- msecs_to_jiffies(dib->rc_query_interval));
-}
-
-int dibusb_remote_init(struct usb_dibusb *dib)
-{
- int i;
-
- if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
- return 0;
-
- /* Initialise the remote-control structures.*/
- init_input_dev(&dib->rc_input_dev);
-
- dib->rc_input_dev.evbit[0] = BIT(EV_KEY);
- dib->rc_input_dev.keycodesize = sizeof(unsigned char);
- dib->rc_input_dev.keycodemax = KEY_MAX;
- dib->rc_input_dev.name = DRIVER_DESC " remote control";
-
- switch (dib->dibdev->dev_cl->remote_type) {
- case DIBUSB_RC_NEC_PROTOCOL:
- for (i=0; i<sizeof(nec_rc_keys)/sizeof(nec_rc_keys[0]); i++)
- set_bit(nec_rc_keys[i].key, dib->rc_input_dev.keybit);
- break;
- case DIBUSB_RC_HAUPPAUGE_PROTO:
- for (i=0; i<sizeof(haupp_rc_keys)/sizeof(haupp_rc_keys[0]); i++)
- set_bit(haupp_rc_keys[i].key, dib->rc_input_dev.keybit);
- break;
- default:
- break;
- }
-
-
- input_register_device(&dib->rc_input_dev);
-
- INIT_WORK(&dib->rc_query_work, dibusb_remote_query, dib);
-
- /* Start the remote-control polling. */
- if (dib->rc_query_interval < 40)
- dib->rc_query_interval = 100; /* default */
-
- info("schedule remote query interval to %d msecs.",dib->rc_query_interval);
- schedule_delayed_work(&dib->rc_query_work,msecs_to_jiffies(dib->rc_query_interval));
-
- dib->init_state |= DIBUSB_STATE_REMOTE;
-
- return 0;
-}
-
-int dibusb_remote_exit(struct usb_dibusb *dib)
-{
- if (dib->dibdev->dev_cl->remote_type == DIBUSB_RC_NO)
- return 0;
-
- if (dib->init_state & DIBUSB_STATE_REMOTE) {
- cancel_delayed_work(&dib->rc_query_work);
- flush_scheduled_work();
- input_unregister_device(&dib->rc_input_dev);
- }
- dib->init_state &= ~DIBUSB_STATE_REMOTE;
- return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c b/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
deleted file mode 100644
index 642f0596a5ba..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb-usb.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * dvb-dibusb-usb.c is part of the driver for mobile USB Budget DVB-T devices
- * based on reference design made by DiBcom (http://www.dibcom.fr/)
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * see dvb-dibusb-core.c for more copyright details.
- *
- * This file contains functions for initializing and handling the
- * usb specific stuff.
- */
-#include "dvb-dibusb.h"
-
-#include <linux/version.h>
-#include <linux/pci.h>
-
-int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
- u16 rlen)
-{
- int actlen,ret = -ENOMEM;
-
- if (wbuf == NULL || wlen == 0)
- return -EINVAL;
-
- if ((ret = down_interruptible(&dib->usb_sem)))
- return ret;
-
- debug_dump(wbuf,wlen);
-
- ret = usb_bulk_msg(dib->udev,usb_sndbulkpipe(dib->udev,
- dib->dibdev->dev_cl->pipe_cmd), wbuf,wlen,&actlen,
- DIBUSB_I2C_TIMEOUT);
-
- if (ret)
- err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
- else
- ret = actlen != wlen ? -1 : 0;
-
- /* an answer is expected, and no error before */
- if (!ret && rbuf && rlen) {
- ret = usb_bulk_msg(dib->udev,usb_rcvbulkpipe(dib->udev,
- dib->dibdev->dev_cl->pipe_cmd),rbuf,rlen,&actlen,
- DIBUSB_I2C_TIMEOUT);
-
- if (ret)
- err("recv bulk message failed: %d",ret);
- else {
- deb_alot("rlen: %d\n",rlen);
- debug_dump(rbuf,actlen);
- }
- }
-
- up(&dib->usb_sem);
- return ret;
-}
-
-/*
- * Cypress controls
- */
-int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len)
-{
- return dibusb_readwrite_usb(dib,buf,len,NULL,0);
-}
-
-#if 0
-/*
- * #if 0'ing the following functions as they are not in use _now_,
- * but probably will be sometime.
- */
-/*
- * do not use this, just a workaround for a bug,
- * which will hopefully never occur :).
- */
-int dibusb_interrupt_read_loop(struct usb_dibusb *dib)
-{
- u8 b[1] = { DIBUSB_REQ_INTR_READ };
- return dibusb_write_usb(dib,b,1);
-}
-#endif
-
-/*
- * ioctl for the firmware
- */
-static int dibusb_ioctl_cmd(struct usb_dibusb *dib, u8 cmd, u8 *param, int plen)
-{
- u8 b[34];
- int size = plen > 32 ? 32 : plen;
- memset(b,0,34);
- b[0] = DIBUSB_REQ_SET_IOCTL;
- b[1] = cmd;
-
- if (size > 0)
- memcpy(&b[2],param,size);
-
- return dibusb_write_usb(dib,b,34); //2+size);
-}
-
-/*
- * ioctl for power control
- */
-int dibusb_hw_wakeup(struct dvb_frontend *fe)
-{
- struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
- u8 b[1] = { DIBUSB_IOCTL_POWER_WAKEUP };
- deb_info("dibusb-device is getting up.\n");
-
- switch (dib->dibdev->dev_cl->id) {
- case DTT200U:
- break;
- default:
- dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
- break;
- }
-
- if (dib->fe_init)
- return dib->fe_init(fe);
-
- return 0;
-}
-
-int dibusb_hw_sleep(struct dvb_frontend *fe)
-{
- struct usb_dibusb *dib = (struct usb_dibusb *) fe->dvb->priv;
- u8 b[1] = { DIBUSB_IOCTL_POWER_SLEEP };
- deb_info("dibusb-device is going to bed.\n");
- /* workaround, something is wrong, when dibusb 1.1 device are going to bed too late */
- switch (dib->dibdev->dev_cl->id) {
- case DIBUSB1_1:
- case NOVAT_USB2:
- case DTT200U:
- break;
- default:
- dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_POWER_MODE, b,1);
- break;
- }
- if (dib->fe_sleep)
- return dib->fe_sleep(fe);
-
- return 0;
-}
-
-int dibusb_set_streaming_mode(struct usb_dibusb *dib,u8 mode)
-{
- u8 b[2] = { DIBUSB_REQ_SET_STREAMING_MODE, mode };
- return dibusb_readwrite_usb(dib,b,2,NULL,0);
-}
-
-static int dibusb_urb_kill(struct usb_dibusb *dib)
-{
- int i;
-deb_info("trying to kill urbs\n");
- if (dib->init_state & DIBUSB_STATE_URB_SUBMIT) {
- for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
- deb_info("killing URB no. %d.\n",i);
-
- /* stop the URB */
- usb_kill_urb(dib->urb_list[i]);
- }
- } else
- deb_info(" URBs not killed.\n");
- dib->init_state &= ~DIBUSB_STATE_URB_SUBMIT;
- return 0;
-}
-
-static int dibusb_urb_submit(struct usb_dibusb *dib)
-{
- int i,ret;
- if (dib->init_state & DIBUSB_STATE_URB_INIT) {
- for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
- deb_info("submitting URB no. %d\n",i);
- if ((ret = usb_submit_urb(dib->urb_list[i],GFP_ATOMIC))) {
- err("could not submit buffer urb no. %d - get them all back\n",i);
- dibusb_urb_kill(dib);
- return ret;
- }
- dib->init_state |= DIBUSB_STATE_URB_SUBMIT;
- }
- }
- return 0;
-}
-
-int dibusb_streaming(struct usb_dibusb *dib,int onoff)
-{
- if (onoff)
- dibusb_urb_submit(dib);
- else
- dibusb_urb_kill(dib);
-
- switch (dib->dibdev->dev_cl->id) {
- case DIBUSB2_0:
- case DIBUSB2_0B:
- case NOVAT_USB2:
- case UMT2_0:
- if (onoff)
- return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_ENABLE_STREAM,NULL,0);
- else
- return dibusb_ioctl_cmd(dib,DIBUSB_IOCTL_CMD_DISABLE_STREAM,NULL,0);
- break;
- default:
- break;
- }
- return 0;
-}
-
-int dibusb_urb_init(struct usb_dibusb *dib)
-{
- int i,bufsize,def_pid_parse = 1;
-
- /*
- * when reloading the driver w/o replugging the device
- * a timeout occures, this helps
- */
- usb_clear_halt(dib->udev,usb_sndbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
- usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_cmd));
- usb_clear_halt(dib->udev,usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data));
-
- /* allocate the array for the data transfer URBs */
- dib->urb_list = kmalloc(dib->dibdev->dev_cl->urb_count*sizeof(struct urb *),GFP_KERNEL);
- if (dib->urb_list == NULL)
- return -ENOMEM;
- memset(dib->urb_list,0,dib->dibdev->dev_cl->urb_count*sizeof(struct urb *));
-
- dib->init_state |= DIBUSB_STATE_URB_LIST;
-
- bufsize = dib->dibdev->dev_cl->urb_count*dib->dibdev->dev_cl->urb_buffer_size;
- deb_info("allocate %d bytes as buffersize for all URBs\n",bufsize);
- /* allocate the actual buffer for the URBs */
- if ((dib->buffer = pci_alloc_consistent(NULL,bufsize,&dib->dma_handle)) == NULL) {
- deb_info("not enough memory.\n");
- return -ENOMEM;
- }
- deb_info("allocation complete\n");
- memset(dib->buffer,0,bufsize);
-
- dib->init_state |= DIBUSB_STATE_URB_BUF;
-
- /* allocate and submit the URBs */
- for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
- if (!(dib->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC))) {
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb( dib->urb_list[i], dib->udev,
- usb_rcvbulkpipe(dib->udev,dib->dibdev->dev_cl->pipe_data),
- &dib->buffer[i*dib->dibdev->dev_cl->urb_buffer_size],
- dib->dibdev->dev_cl->urb_buffer_size,
- dibusb_urb_complete, dib);
-
- dib->urb_list[i]->transfer_flags = 0;
-
- dib->init_state |= DIBUSB_STATE_URB_INIT;
- }
-
- /* dib->pid_parse here contains the value of the module parameter */
- /* decide if pid parsing can be deactivated:
- * is possible (by device type) and wanted (by user)
- */
- switch (dib->dibdev->dev_cl->id) {
- case DIBUSB2_0:
- case DIBUSB2_0B:
- if (dib->udev->speed == USB_SPEED_HIGH && !dib->pid_parse) {
- def_pid_parse = 0;
- info("running at HIGH speed, will deliver the complete TS.");
- } else
- info("will use pid_parsing.");
- break;
- default:
- break;
- }
- /* from here on it contains the device and user decision */
- dib->pid_parse = def_pid_parse;
-
- return 0;
-}
-
-int dibusb_urb_exit(struct usb_dibusb *dib)
-{
- int i;
-
- dibusb_urb_kill(dib);
-
- if (dib->init_state & DIBUSB_STATE_URB_LIST) {
- for (i = 0; i < dib->dibdev->dev_cl->urb_count; i++) {
- if (dib->urb_list[i] != NULL) {
- deb_info("freeing URB no. %d.\n",i);
- /* free the URBs */
- usb_free_urb(dib->urb_list[i]);
- }
- }
- /* free the urb array */
- kfree(dib->urb_list);
- dib->init_state &= ~DIBUSB_STATE_URB_LIST;
- }
-
- if (dib->init_state & DIBUSB_STATE_URB_BUF)
- pci_free_consistent(NULL,
- dib->dibdev->dev_cl->urb_buffer_size*dib->dibdev->dev_cl->urb_count,
- dib->buffer,dib->dma_handle);
-
- dib->init_state &= ~DIBUSB_STATE_URB_BUF;
- dib->init_state &= ~DIBUSB_STATE_URB_INIT;
- return 0;
-}
diff --git a/drivers/media/dvb/dibusb/dvb-dibusb.h b/drivers/media/dvb/dibusb/dvb-dibusb.h
deleted file mode 100644
index c965b64fb1ab..000000000000
--- a/drivers/media/dvb/dibusb/dvb-dibusb.h
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * dvb-dibusb.h
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
- *
- * 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.
- *
- * for more information see dvb-dibusb-core.c .
- */
-#ifndef __DVB_DIBUSB_H__
-#define __DVB_DIBUSB_H__
-
-#include <linux/input.h>
-#include <linux/config.h>
-#include <linux/usb.h>
-
-#include "dvb_frontend.h"
-#include "dvb_demux.h"
-#include "dvb_net.h"
-#include "dmxdev.h"
-
-#include "dib3000.h"
-#include "mt352.h"
-
-/* debug */
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-#define dprintk(level,args...) \
- do { if ((dvb_dibusb_debug & level)) { printk(args); } } while (0)
-
-#define debug_dump(b,l) {\
- int i; \
- for (i = 0; i < l; i++) deb_xfer("%02x ", b[i]); \
- deb_xfer("\n");\
-}
-
-#else
-#define dprintk(args...)
-#define debug_dump(b,l)
-#endif
-
-extern int dvb_dibusb_debug;
-
-/* Version information */
-#define DRIVER_VERSION "0.3"
-#define DRIVER_DESC "DiBcom based USB Budget DVB-T device"
-#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-
-#define deb_info(args...) dprintk(0x01,args)
-#define deb_xfer(args...) dprintk(0x02,args)
-#define deb_alot(args...) dprintk(0x04,args)
-#define deb_ts(args...) dprintk(0x08,args)
-#define deb_err(args...) dprintk(0x10,args)
-#define deb_rc(args...) dprintk(0x20,args)
-
-/* generic log methods - taken from usb.h */
-#undef err
-#define err(format, arg...) printk(KERN_ERR "dvb-dibusb: " format "\n" , ## arg)
-#undef info
-#define info(format, arg...) printk(KERN_INFO "dvb-dibusb: " format "\n" , ## arg)
-#undef warn
-#define warn(format, arg...) printk(KERN_WARNING "dvb-dibusb: " format "\n" , ## arg)
-
-struct dibusb_usb_controller {
- const char *name; /* name of the usb controller */
- u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
-};
-
-typedef enum {
- DIBUSB1_1 = 0,
- DIBUSB1_1_AN2235,
- DIBUSB2_0,
- UMT2_0,
- DIBUSB2_0B,
- NOVAT_USB2,
- DTT200U,
-} dibusb_class_t;
-
-typedef enum {
- DIBUSB_TUNER_CABLE_THOMSON = 0,
- DIBUSB_TUNER_COFDM_PANASONIC_ENV57H1XD5,
- DIBUSB_TUNER_CABLE_LG_TDTP_E102P,
- DIBUSB_TUNER_COFDM_PANASONIC_ENV77H11D5,
-} dibusb_tuner_t;
-
-typedef enum {
- DIBUSB_DIB3000MB = 0,
- DIBUSB_DIB3000MC,
- DIBUSB_MT352,
- DTT200U_FE,
-} dibusb_demodulator_t;
-
-typedef enum {
- DIBUSB_RC_NO = 0,
- DIBUSB_RC_NEC_PROTOCOL,
- DIBUSB_RC_HAUPPAUGE_PROTO,
-} dibusb_remote_t;
-
-struct dibusb_tuner {
- dibusb_tuner_t id;
-
- u8 pll_addr; /* tuner i2c address */
-};
-extern struct dibusb_tuner dibusb_tuner[];
-
-#define DIBUSB_POSSIBLE_I2C_ADDR_NUM 4
-struct dibusb_demod {
- dibusb_demodulator_t id;
-
- int pid_filter_count; /* counter of the internal pid_filter */
- u8 i2c_addrs[DIBUSB_POSSIBLE_I2C_ADDR_NUM]; /* list of possible i2c addresses of the demod */
-};
-
-#define DIBUSB_MAX_TUNER_NUM 2
-struct dibusb_device_class {
- dibusb_class_t id;
-
- const struct dibusb_usb_controller *usb_ctrl; /* usb controller */
- const char *firmware; /* valid firmware filenames */
-
- int pipe_cmd; /* command pipe (read/write) */
- int pipe_data; /* data pipe */
-
- int urb_count; /* number of data URBs to be submitted */
- int urb_buffer_size; /* the size of the buffer for each URB */
-
- dibusb_remote_t remote_type; /* does this device have a ir-receiver */
-
- struct dibusb_demod *demod; /* which demodulator is mount */
- struct dibusb_tuner *tuner; /* which tuner can be found here */
-};
-
-#define DIBUSB_ID_MAX_NUM 15
-struct dibusb_usb_device {
- const char *name; /* real name of the box */
- struct dibusb_device_class *dev_cl; /* which dibusb_device_class is this device part of */
-
- struct usb_device_id *cold_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at pre firmware state */
- struct usb_device_id *warm_ids[DIBUSB_ID_MAX_NUM]; /* list of USB ids when this device is at post firmware state */
-};
-
-/* a PID for the pid_filter list, when in use */
-struct dibusb_pid
-{
- int index;
- u16 pid;
- int active;
-};
-
-struct usb_dibusb {
- /* usb */
- struct usb_device * udev;
-
- struct dibusb_usb_device * dibdev;
-
-#define DIBUSB_STATE_INIT 0x000
-#define DIBUSB_STATE_URB_LIST 0x001
-#define DIBUSB_STATE_URB_BUF 0x002
-#define DIBUSB_STATE_URB_INIT 0x004
-#define DIBUSB_STATE_DVB 0x008
-#define DIBUSB_STATE_I2C 0x010
-#define DIBUSB_STATE_REMOTE 0x020
-#define DIBUSB_STATE_URB_SUBMIT 0x040
- int init_state;
-
- int feedcount;
- struct dib_fe_xfer_ops xfer_ops;
-
- struct dibusb_tuner *tuner;
-
- struct urb **urb_list;
- u8 *buffer;
- dma_addr_t dma_handle;
-
- /* I2C */
- struct i2c_adapter i2c_adap;
-
- /* locking */
- struct semaphore usb_sem;
- struct semaphore i2c_sem;
-
- /* dvb */
- struct dvb_adapter adapter;
- struct dmxdev dmxdev;
- struct dvb_demux demux;
- struct dvb_net dvb_net;
- struct dvb_frontend* fe;
-
- int (*fe_sleep) (struct dvb_frontend *);
- int (*fe_init) (struct dvb_frontend *);
-
- /* remote control */
- struct input_dev rc_input_dev;
- struct work_struct rc_query_work;
- int last_event;
- int last_state; /* for Hauppauge RC protocol */
- int repeat_key_count;
- int rc_key_repeat_count; /* module parameter */
-
- /* module parameters */
- int pid_parse;
- int rc_query_interval;
-};
-
-/* commonly used functions in the separated files */
-
-/* dvb-dibusb-firmware.c */
-int dibusb_loadfirmware(struct usb_device *udev, struct dibusb_usb_device *dibdev);
-
-/* dvb-dibusb-remote.c */
-int dibusb_remote_exit(struct usb_dibusb *dib);
-int dibusb_remote_init(struct usb_dibusb *dib);
-
-/* dvb-dibusb-fe-i2c.c */
-int dibusb_fe_init(struct usb_dibusb* dib);
-int dibusb_fe_exit(struct usb_dibusb *dib);
-int dibusb_i2c_init(struct usb_dibusb *dib);
-int dibusb_i2c_exit(struct usb_dibusb *dib);
-
-/* dvb-dibusb-dvb.c */
-void dibusb_urb_complete(struct urb *urb, struct pt_regs *ptregs);
-int dibusb_dvb_init(struct usb_dibusb *dib);
-int dibusb_dvb_exit(struct usb_dibusb *dib);
-
-/* dvb-dibusb-usb.c */
-int dibusb_readwrite_usb(struct usb_dibusb *dib, u8 *wbuf, u16 wlen, u8 *rbuf,
- u16 rlen);
-int dibusb_write_usb(struct usb_dibusb *dib, u8 *buf, u16 len);
-
-int dibusb_hw_wakeup(struct dvb_frontend *);
-int dibusb_hw_sleep(struct dvb_frontend *);
-int dibusb_set_streaming_mode(struct usb_dibusb *,u8);
-int dibusb_streaming(struct usb_dibusb *,int);
-
-int dibusb_urb_init(struct usb_dibusb *);
-int dibusb_urb_exit(struct usb_dibusb *);
-
-/* dvb-fe-dtt200u.c */
-struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *,struct dib_fe_xfer_ops *);
-
-/* i2c and transfer stuff */
-#define DIBUSB_I2C_TIMEOUT 5000
-
-/*
- * protocol of all dibusb related devices
- */
-
-/*
- * bulk msg to/from endpoint 0x01
- *
- * general structure:
- * request_byte parameter_bytes
- */
-
-#define DIBUSB_REQ_START_READ 0x00
-#define DIBUSB_REQ_START_DEMOD 0x01
-
-/*
- * i2c read
- * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
- * bulk read: byte_buffer (length_word bytes)
- */
-#define DIBUSB_REQ_I2C_READ 0x02
-
-/*
- * i2c write
- * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
- */
-#define DIBUSB_REQ_I2C_WRITE 0x03
-
-/*
- * polling the value of the remote control
- * bulk write: 0x04
- * bulk read: byte_buffer (5 bytes)
- *
- * first byte of byte_buffer shows the status (0x00, 0x01, 0x02)
- */
-#define DIBUSB_REQ_POLL_REMOTE 0x04
-
-#define DIBUSB_RC_NEC_EMPTY 0x00
-#define DIBUSB_RC_NEC_KEY_PRESSED 0x01
-#define DIBUSB_RC_NEC_KEY_REPEATED 0x02
-
-/* additional status values for Hauppauge Remote Control Protocol */
-#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
-#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
-
-/* streaming mode:
- * bulk write: 0x05 mode_byte
- *
- * mode_byte is mostly 0x00
- */
-#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
-
-/* interrupt the internal read loop, when blocking */
-#define DIBUSB_REQ_INTR_READ 0x06
-
-/* io control
- * 0x07 cmd_byte param_bytes
- *
- * param_bytes can be up to 32 bytes
- *
- * cmd_byte function parameter name
- * 0x00 power mode
- * 0x00 sleep
- * 0x01 wakeup
- *
- * 0x01 enable streaming
- * 0x02 disable streaming
- *
- *
- */
-#define DIBUSB_REQ_SET_IOCTL 0x07
-
-/* IOCTL commands */
-
-/* change the power mode in firmware */
-#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00
-#define DIBUSB_IOCTL_POWER_SLEEP 0x00
-#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
-
-/* modify streaming of the FX2 */
-#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
-#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index c225de7ffd82..68050cd527cb 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -42,12 +42,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk if (debug) printk
-static inline struct dmxdev_filter *
-dvb_dmxdev_file_to_filter(struct file *file)
-{
- return (struct dmxdev_filter *) file->private_data;
-}
-
static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
{
buffer->data=NULL;
@@ -669,8 +663,10 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
ret = filter->feed.ts->start_filtering(filter->feed.ts);
- if (ret < 0)
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
return ret;
+ }
break;
}
@@ -842,7 +838,7 @@ static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
static ssize_t
dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter= file->private_data;
int ret=0;
if (down_interruptible(&dmxdevfilter->mutex))
@@ -863,7 +859,7 @@ dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg)
{
- struct dmxdev_filter *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev=dmxdevfilter->dev;
unsigned long arg=(unsigned long) parg;
int ret=0;
@@ -960,7 +956,7 @@ static int dvb_demux_ioctl(struct inode *inode, struct file *file,
static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
{
- struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0;
if (!dmxdevfilter)
@@ -985,7 +981,7 @@ static unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
static int dvb_demux_release(struct inode *inode, struct file *file)
{
- struct dmxdev_filter *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
+ struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
@@ -1109,7 +1105,6 @@ dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dmxdev->dvr[i].dev=dmxdev;
dmxdev->dvr[i].buffer.data=NULL;
- dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
}
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index d19301d90a09..a8bc84240b50 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -35,12 +35,15 @@
#include <linux/moduleparam.h>
#include <linux/list.h>
#include <linux/suspend.h>
+#include <linux/jiffies.h>
#include <asm/processor.h>
#include <asm/semaphore.h>
#include "dvb_frontend.h"
#include "dvbdev.h"
+// #define DEBUG_LOCKLOSS 1
+
static int dvb_frontend_debug;
static int dvb_shutdown_timeout = 5;
static int dvb_force_auto_inversion;
@@ -112,6 +115,7 @@ struct dvb_frontend_private {
int exit;
int wakeup;
fe_status_t status;
+ fe_sec_tone_mode_t tone;
};
@@ -327,7 +331,8 @@ static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
return 1;
if (fepriv->dvbdev->writers == 1)
- if (jiffies - fepriv->release_jiffies > dvb_shutdown_timeout * HZ)
+ if (time_after(jiffies, fepriv->release_jiffies +
+ dvb_shutdown_timeout * HZ))
return 1;
return 0;
@@ -389,8 +394,7 @@ static int dvb_frontend_thread(void *data)
break;
}
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
if (down_interruptible(&fepriv->sem))
break;
@@ -433,9 +437,26 @@ static int dvb_frontend_thread(void *data)
/* we're tuned, and the lock is still good... */
if (s & FE_HAS_LOCK)
continue;
- else {
- /* if we _WERE_ tuned, but now don't have a lock,
- * need to zigzag */
+ else { /* if we _WERE_ tuned, but now don't have a lock */
+#ifdef DEBUG_LOCKLOSS
+ /* first of all try setting the tone again if it was on - this
+ * sometimes works around problems with noisy power supplies */
+ if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) {
+ fe->ops->set_tone(fe, fepriv->tone);
+ mdelay(100);
+ s = 0;
+ fe->ops->read_status(fe, &s);
+ if (s & FE_HAS_LOCK) {
+ printk("DVB%i: Lock was lost, but regained by setting "
+ "the tone. This may indicate your power supply "
+ "is noisy/slightly incompatable with this DVB-S "
+ "adapter\n", fe->dvb->num);
+ fepriv->state = FESTATE_TUNED;
+ continue;
+ }
+ }
+#endif
+ /* some other reason for losing the lock - start zigzagging */
fepriv->state = FESTATE_ZIGZAG_FAST;
fepriv->started_auto_step = fepriv->auto_step;
check_wrapped = 0;
@@ -625,11 +646,21 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
break;
}
- case FE_READ_STATUS:
+ case FE_READ_STATUS: {
+ fe_status_t* status = parg;
+
+ /* if retune was requested but hasn't occured yet, prevent
+ * that user get signal state from previous tuning */
+ if(fepriv->state == FESTATE_RETUNE) {
+ err=0;
+ *status = 0;
+ break;
+ }
+
if (fe->ops->read_status)
- err = fe->ops->read_status(fe, (fe_status_t*) parg);
+ err = fe->ops->read_status(fe, status);
break;
-
+ }
case FE_READ_BER:
if (fe->ops->read_ber)
err = fe->ops->read_ber(fe, (__u32*) parg);
@@ -680,6 +711,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file,
err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg);
fepriv->state = FESTATE_DISEQC;
fepriv->status = 0;
+ fepriv->tone = (fe_sec_tone_mode_t) parg;
}
break;
@@ -882,6 +914,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
init_MUTEX (&fepriv->events.sem);
fe->dvb = dvb;
fepriv->inversion = INVERSION_OFF;
+ fepriv->tone = SEC_TONE_OFF;
printk ("DVB: registering frontend %i (%s)...\n",
fe->dvb->num,
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index d2b021792791..9c2c1d1136bd 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -40,28 +40,6 @@
#include "dvbdev.h"
-/* FIXME: Move to i2c-id.h */
-#define I2C_DRIVERID_DVBFE_SP8870 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22700 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_AT76C651 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX24110 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_CX22702 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DIB3000MB I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DST I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_DUMMY I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_L64781 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT312 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_MT352 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_NXT6000 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_SP887X I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_STV0299 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA1004X I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA8083 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1820 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_VES1X93 I2C_DRIVERID_EXP2
-#define I2C_DRIVERID_DVBFE_TDA80XX I2C_DRIVERID_EXP2
-
-
struct dvb_frontend_tune_settings {
int min_delay_ms;
int step_size;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
new file mode 100644
index 000000000000..612e5b087b1c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -0,0 +1,119 @@
+config DVB_USB
+ tristate "Support for various USB DVB devices"
+ depends on DVB_CORE && USB
+ select FW_LOADER
+ help
+ By enabling this you will be able to choose the various supported
+ USB1.1 and USB2.0 DVB devices.
+
+ Almost every USB device needs a firmware, please look into
+ <file:Documentation/dvb/README.dvb-usb>.
+
+ For a complete list of supported USB devices see the LinuxTV DVB Wiki:
+ <http://www.linuxtv.org/wiki/index.php/DVB_USB>
+
+ Say Y if you own a USB DVB device.
+
+config DVB_USB_DEBUG
+ bool "Enable extended debug support for all DVB-USB devices"
+ depends on DVB_USB
+ help
+ Say Y if you want to enable debugging. See modinfo dvb-usb (and the
+ appropriate drivers) for debug levels.
+
+config DVB_USB_A800
+ tristate "AVerMedia AverTV DVB-T USB 2.0 (A800)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ help
+ Say Y here to support the AVerMedia AverTV DVB-T USB 2.0 (A800) receiver.
+
+config DVB_USB_DIBUSB_MB
+ tristate "DiBcom USB DVB-T devices (based on the DiB3000M-B) (see help for device list)"
+ depends on DVB_USB
+ select DVB_DIB3000MB
+ help
+ Support for USB 1.1 and 2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-B demodulator.
+
+ Devices supported by this driver:
+ TwinhanDTV USB-Ter (VP7041)
+ TwinhanDTV Magic Box (VP7041e)
+ KWorld/JetWay/ADSTech V-Stream XPERT DTV - DVB-T USB1.1 and USB2.0
+ Hama DVB-T USB1.1-Box
+ DiBcom USB1.1 reference devices (non-public)
+ Ultima Electronic/Artec T1 USB TVBOX
+ Compro Videomate DVB-U2000 - DVB-T USB
+ Grandtec DVB-T USB
+ Avermedia AverTV DVBT USB1.1
+ Artec T1 USB1.1 boxes
+
+ The VP7041 seems to be identical to "CTS Portable" (Chinese
+ Television System).
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_DIBUSB_MC
+ tristate "DiBcom USB DVB-T devices (based on the DiB3000M-C/P) (see help for device list)"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ help
+ Support for 2.0 DVB-T receivers based on reference designs made by
+ DiBcom (<http://www.dibcom.fr>) equipped with a DiB3000M-C/P demodulator.
+
+ Devices supported by this driver:
+ DiBcom USB2.0 reference devices (non-public)
+ Artec T1 USB2.0 boxes
+
+ Say Y if you own such a device and want to use it. You should build it as
+ a module.
+
+config DVB_USB_UMT_010
+ tristate "HanfTek UMT-010 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ help
+ Say Y here to support the HanfTek UMT-010 USB2.0 stick-sized DVB-T receiver.
+
+config DVB_USB_CXUSB
+ tristate "Medion MD95700 hybrid USB2.0 (Conexant) support"
+ depends on DVB_USB
+ select DVB_CX22702
+ help
+ Say Y here to support the Medion MD95700 hybrid USB2.0 device. Currently
+ only the DVB-T part is supported.
+
+config DVB_USB_DIGITV
+ tristate "Nebula Electronics uDigiTV DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_NXT6000
+ select DVB_MT352
+ help
+ Say Y here to support the Nebula Electronics uDigitV USB2.0 DVB-T receiver.
+
+config DVB_USB_VP7045
+ tristate "TwinhanDTV Alpha/MagicBoxII and DNTV tinyUSB2 DVB-T USB2.0 support"
+ depends on DVB_USB
+ help
+ Say Y here to support the
+ TwinhanDTV Alpha (stick) (VP-7045),
+ TwinhanDTV MagicBox II (VP-7046) and
+ DigitalNow TinyUSB 2 DVB-t DVB-T USB2.0 receivers.
+
+config DVB_USB_NOVA_T_USB2
+ tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support"
+ depends on DVB_USB
+ select DVB_DIB3000MC
+ help
+ Say Y here to support the Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 receiver.
+
+config DVB_USB_DTT200U
+ tristate "WideView WT-200U and WT-220U (pen) DVB-T USB2.0 support (Yakumo/Hama/Typhoon/Yuan)"
+ depends on DVB_USB
+ help
+ Say Y here to support the WideView/Yakumo/Hama/Typhoon/Yuan DVB-T USB2.0 receiver.
+
+ The receivers are also known as DTT200U (Yakumo) and UB300 (Yuan).
+
+ The WT-220U and its clones are pen-sized.
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
new file mode 100644
index 000000000000..746d87ed6f32
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -0,0 +1,33 @@
+dvb-usb-objs = dvb-usb-firmware.o dvb-usb-init.o dvb-usb-urb.o dvb-usb-i2c.o dvb-usb-dvb.o dvb-usb-remote.o
+obj-$(CONFIG_DVB_USB) += dvb-usb.o
+
+dvb-usb-vp7045-objs = vp7045.o vp7045-fe.o
+obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o
+
+dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o
+obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o
+
+dvb-usb-dibusb-common-objs = dibusb-common.o
+
+dvb-usb-a800-objs = a800.o
+obj-$(CONFIG_DVB_USB_A800) += dvb-usb-dibusb-common.o dvb-usb-a800.o
+
+dvb-usb-dibusb-mb-objs = dibusb-mb.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MB) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mb.o
+
+dvb-usb-dibusb-mc-objs = dibusb-mc.o
+obj-$(CONFIG_DVB_USB_DIBUSB_MC) += dvb-usb-dibusb-common.o dvb-usb-dibusb-mc.o
+
+dvb-usb-nova-t-usb2-objs = nova-t-usb2.o
+obj-$(CONFIG_DVB_USB_NOVA_T_USB2) += dvb-usb-dibusb-common.o dvb-usb-nova-t-usb2.o
+
+dvb-usb-umt-010-objs = umt-010.o
+obj-$(CONFIG_DVB_USB_UMT_010) += dvb-usb-dibusb-common.o dvb-usb-umt-010.o
+
+dvb-usb-digitv-objs = digitv.o
+obj-$(CONFIG_DVB_USB_DIGITV) += dvb-usb-digitv.o
+
+dvb-usb-cxusb-objs = cxusb.o
+obj-$(CONFIG_DVB_USB_CXUSB) += dvb-usb-cxusb.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
new file mode 100644
index 000000000000..f2fcc2f1f846
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -0,0 +1,182 @@
+/* DVB USB framework compliant Linux driver for the AVerMedia AverTV DVB-T
+ * USB2.0 (A800) DVB-T receiver.
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to
+ * - AVerMedia who kindly provided information and
+ * - Glen Harris who suffered from my mistakes during development.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (rc=1 (or-able))." DVB_USB_DEBUG_STATUS);
+#define deb_rc(args...) dprintk(debug,0x01,args)
+
+static int a800_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ /* do nothing for the AVerMedia */
+ return 0;
+}
+
+static struct dvb_usb_rc_key a800_rc_keys[] = {
+ { 0x02, 0x01, KEY_PROG1 }, /* SOURCE */
+ { 0x02, 0x00, KEY_POWER }, /* POWER */
+ { 0x02, 0x05, KEY_1 }, /* 1 */
+ { 0x02, 0x06, KEY_2 }, /* 2 */
+ { 0x02, 0x07, KEY_3 }, /* 3 */
+ { 0x02, 0x09, KEY_4 }, /* 4 */
+ { 0x02, 0x0a, KEY_5 }, /* 5 */
+ { 0x02, 0x0b, KEY_6 }, /* 6 */
+ { 0x02, 0x0d, KEY_7 }, /* 7 */
+ { 0x02, 0x0e, KEY_8 }, /* 8 */
+ { 0x02, 0x0f, KEY_9 }, /* 9 */
+ { 0x02, 0x12, KEY_LEFT }, /* L / DISPLAY */
+ { 0x02, 0x11, KEY_0 }, /* 0 */
+ { 0x02, 0x13, KEY_RIGHT }, /* R / CH RTN */
+ { 0x02, 0x17, KEY_PROG2 }, /* SNAP SHOT */
+ { 0x02, 0x10, KEY_PROG3 }, /* 16-CH PREV */
+ { 0x02, 0x03, KEY_CHANNELUP }, /* CH UP */
+ { 0x02, 0x1e, KEY_VOLUMEDOWN }, /* VOL DOWN */
+ { 0x02, 0x0c, KEY_ZOOM }, /* FULL SCREEN */
+ { 0x02, 0x1f, KEY_VOLUMEUP }, /* VOL UP */
+ { 0x02, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
+ { 0x02, 0x14, KEY_MUTE }, /* MUTE */
+ { 0x02, 0x08, KEY_AUDIO }, /* AUDIO */
+ { 0x02, 0x19, KEY_RECORD }, /* RECORD */
+ { 0x02, 0x18, KEY_PLAY }, /* PLAY */
+ { 0x02, 0x1b, KEY_STOP }, /* STOP */
+ { 0x02, 0x1a, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
+ { 0x02, 0x1d, KEY_BACK }, /* << / RED */
+ { 0x02, 0x1c, KEY_FORWARD }, /* >> / YELLOW */
+ { 0x02, 0x03, KEY_TEXT }, /* TELETEXT */
+ { 0x02, 0x01, KEY_FIRST }, /* |<< / GREEN */
+ { 0x02, 0x00, KEY_LAST }, /* >>| / BLUE */
+ { 0x02, 0x04, KEY_EPG }, /* EPG */
+ { 0x02, 0x15, KEY_MENU }, /* MENU */
+
+ { 0x03, 0x03, KEY_CHANNELUP }, /* CH UP */
+ { 0x03, 0x02, KEY_CHANNELDOWN }, /* CH DOWN */
+ { 0x03, 0x01, KEY_FIRST }, /* |<< / GREEN */
+ { 0x03, 0x00, KEY_LAST }, /* >>| / BLUE */
+
+};
+
+int a800_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[5];
+ if (usb_control_msg(d->udev,usb_rcvctrlpipe(d->udev,0),
+ 0x04, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0, key, 5,
+ 2000) != 5)
+ return -ENODEV;
+
+ /* call the universal NEC remote processor, to find out the key's state and event */
+ dvb_usb_nec_rc_key_to_event(d,key,event,state);
+ if (key[0] != 0)
+ deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+ return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties a800_properties;
+
+static int a800_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&a800_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id a800_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_DVBT_USB2_WARM) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, a800_table);
+
+static struct dvb_usb_properties a800_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 32,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .firmware = "dvb-usb-avertv-a800-02.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = a800_power_ctrl,
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = a800_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(a800_rc_keys),
+ .rc_query = a800_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "AVerMedia AverTV DVB-T USB 2.0 (A800)",
+ { &a800_table[0], NULL },
+ { &a800_table[1], NULL },
+ },
+ }
+};
+
+static struct usb_driver a800_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_a800",
+ .probe = a800_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = a800_table,
+};
+
+/* module stuff */
+static int __init a800_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&a800_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit a800_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&a800_driver);
+}
+
+module_init (a800_module_init);
+module_exit (a800_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("AVerMedia AverTV DVB-T USB 2.0 (A800)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
new file mode 100644
index 000000000000..c3e1b661aae6
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -0,0 +1,295 @@
+/* DVB USB compliant linux driver for Conexant USB reference design.
+ *
+ * The Conexant reference design I saw on their website was only for analogue
+ * capturing (using the cx25842). The box I took to write this driver (reverse
+ * engineered) is the one labeled Medion MD95700. In addition to the cx25842
+ * for analogue capturing it also has a cx22702 DVB-T demodulator on the main
+ * board. Besides it has a atiremote (X10) and a USB2.0 hub onboard.
+ *
+ * Maybe it is a little bit premature to call this driver cxusb, but I assume
+ * the USB protocol is identical or at least inherited from the reference
+ * design, so it can be reused for the "analogue-only" device (if it will
+ * appear at all).
+ *
+ * TODO: check if the cx25840-driver (from ivtv) can be used for the analogue
+ * part
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "cxusb.h"
+
+#include "cx22702.h"
+
+/* debug */
+int dvb_usb_cxusb_debug;
+module_param_named(debug,dvb_usb_cxusb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int cxusb_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 sndbuf[1+wlen];
+ memset(sndbuf,0,1+wlen);
+
+ sndbuf[0] = cmd;
+ memcpy(&sndbuf[1],wbuf,wlen);
+ if (wo)
+ dvb_usb_generic_write(d,sndbuf,1+wlen);
+ else
+ dvb_usb_generic_rw(d,sndbuf,1+wlen,rbuf,rlen,0);
+
+ return 0;
+}
+
+/* I2C */
+static void cxusb_set_i2c_path(struct dvb_usb_device *d, enum cxusb_i2c_pathes path)
+{
+ struct cxusb_state *st = d->priv;
+ u8 o[2],i;
+
+ if (path == st->cur_i2c_path)
+ return;
+
+ o[0] = IOCTL_SET_I2C_PATH;
+ switch (path) {
+ case PATH_CX22702:
+ o[1] = 0;
+ break;
+ case PATH_TUNER_OTHER:
+ o[1] = 1;
+ break;
+ default:
+ err("unkown i2c path");
+ return;
+ }
+ cxusb_ctrl_msg(d,CMD_IOCTL,o,2,&i,1);
+
+ if (i != 0x01)
+ deb_info("i2c_path setting failed.\n");
+
+ st->cur_i2c_path = path;
+}
+
+static int cxusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (down_interruptible(&d->i2c_sem) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+
+ switch (msg[i].addr) {
+ case 0x63:
+ cxusb_set_i2c_path(d,PATH_CX22702);
+ break;
+ default:
+ cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+ break;
+ }
+
+ /* read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ u8 obuf[3+msg[i].len], ibuf[1+msg[i+1].len];
+ obuf[0] = msg[i].len;
+ obuf[1] = msg[i+1].len;
+ obuf[2] = msg[i].addr;
+ memcpy(&obuf[3],msg[i].buf,msg[i].len);
+
+ if (cxusb_ctrl_msg(d, CMD_I2C_READ,
+ obuf, 3+msg[i].len,
+ ibuf, 1+msg[i+1].len) < 0)
+ break;
+
+ if (ibuf[0] != 0x08)
+ deb_info("i2c read could have been failed\n");
+
+ memcpy(msg[i+1].buf,&ibuf[1],msg[i+1].len);
+
+ i++;
+ } else { /* write */
+ u8 obuf[2+msg[i].len], ibuf;
+ obuf[0] = msg[i].addr;
+ obuf[1] = msg[i].len;
+ memcpy(&obuf[2],msg[i].buf,msg[i].len);
+
+ if (cxusb_ctrl_msg(d,CMD_I2C_WRITE, obuf, 2+msg[i].len, &ibuf,1) < 0)
+ break;
+ if (ibuf != 0x08)
+ deb_info("i2c write could have been failed\n");
+ }
+ }
+
+ up(&d->i2c_sem);
+ return i;
+}
+
+static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cxusb_i2c_algo = {
+ .name = "Conexant USB I2C algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = cxusb_i2c_xfer,
+ .functionality = cxusb_i2c_func,
+};
+
+static int cxusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ return 0;
+}
+
+static int cxusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 buf[2] = { 0x03, 0x00 };
+ if (onoff)
+ cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+ else
+ cxusb_ctrl_msg(d,0x37, NULL, 0, NULL, 0);
+
+ return 0;
+}
+
+struct cx22702_config cxusb_cx22702_config = {
+ .demod_address = 0x63,
+
+ .output_mode = CX22702_PARALLEL_OUTPUT,
+
+ .pll_init = dvb_usb_pll_init_i2c,
+ .pll_set = dvb_usb_pll_set_i2c,
+};
+
+/* Callbacks for DVB USB */
+static int cxusb_tuner_attach(struct dvb_usb_device *d)
+{
+ u8 bpll[4] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+ d->pll_addr = 0x61;
+ memcpy(d->pll_init,bpll,4);
+ d->pll_desc = &dvb_pll_fmd1216me;
+ return 0;
+}
+
+static int cxusb_frontend_attach(struct dvb_usb_device *d)
+{
+ u8 buf[2] = { 0x03, 0x00 };
+ u8 b = 0;
+
+ if (usb_set_interface(d->udev,0,0) < 0)
+ err("set interface to alts=0 failed");
+
+ cxusb_ctrl_msg(d,0xde,&b,0,NULL,0);
+ cxusb_set_i2c_path(d,PATH_TUNER_OTHER);
+ cxusb_ctrl_msg(d,CMD_POWER_OFF, NULL, 0, &b, 1);
+
+ if (usb_set_interface(d->udev,0,6) < 0)
+ err("set interface failed");
+
+ cxusb_ctrl_msg(d,0x36, buf, 2, NULL, 0);
+ cxusb_set_i2c_path(d,PATH_CX22702);
+ cxusb_ctrl_msg(d,CMD_POWER_ON, NULL, 0, &b, 1);
+
+ if ((d->fe = cx22702_attach(&cxusb_cx22702_config, &d->i2c_adap)) != NULL)
+ return 0;
+
+ return -EIO;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_properties cxusb_properties;
+
+static int cxusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&cxusb_properties,THIS_MODULE);
+}
+
+static struct usb_device_id cxusb_table [] = {
+ { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) },
+ {} /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, cxusb_table);
+
+static struct dvb_usb_properties cxusb_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct cxusb_state),
+
+ .streaming_ctrl = cxusb_streaming_ctrl,
+ .power_ctrl = cxusb_power_ctrl,
+ .frontend_attach = cxusb_frontend_attach,
+ .tuner_attach = cxusb_tuner_attach,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_ISOC,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 32,
+ .framesize = 940,
+ .interval = 5,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Medion MD95700 (MDUSBTV-HYBRID)",
+ { NULL },
+ { &cxusb_table[0], NULL },
+ },
+ }
+};
+
+static struct usb_driver cxusb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_cxusb",
+ .probe = cxusb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = cxusb_table,
+};
+
+/* module stuff */
+static int __init cxusb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&cxusb_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit cxusb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&cxusb_driver);
+}
+
+module_init (cxusb_module_init);
+module_exit (cxusb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Conexant USB2.0 hybrid reference design");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/cxusb.h b/drivers/media/dvb/dvb-usb/cxusb.h
new file mode 100644
index 000000000000..1d79016e3195
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/cxusb.h
@@ -0,0 +1,30 @@
+#ifndef _DVB_USB_CXUSB_H_
+#define _DVB_USB_CXUSB_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+extern int dvb_usb_cxusb_debug;
+#define deb_info(args...) dprintk(dvb_usb_cxusb_debug,0x01,args)
+
+/* usb commands - some of it are guesses, don't have a reference yet */
+#define CMD_I2C_WRITE 0x08
+#define CMD_I2C_READ 0x09
+
+#define CMD_IOCTL 0x0e
+#define IOCTL_SET_I2C_PATH 0x02
+
+#define CMD_POWER_OFF 0x50
+#define CMD_POWER_ON 0x51
+
+enum cxusb_i2c_pathes {
+ PATH_UNDEF = 0x00,
+ PATH_CX22702 = 0x01,
+ PATH_TUNER_OTHER = 0x02,
+};
+
+struct cxusb_state {
+ enum cxusb_i2c_pathes cur_i2c_path;
+};
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
new file mode 100644
index 000000000000..63b626f70c81
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -0,0 +1,272 @@
+/* Common methods for dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
+MODULE_LICENSE("GPL");
+
+#define deb_info(args...) dprintk(debug,0x01,args)
+
+/* common stuff used by the different dibusb modules */
+int dibusb_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ if (d->priv != NULL) {
+ struct dib_fe_xfer_ops *ops = d->priv;
+ if (ops->fifo_ctrl != NULL)
+ if (ops->fifo_ctrl(d->fe,onoff)) {
+ err("error while controlling the fifo of the demod.");
+ return -ENODEV;
+ }
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dibusb_streaming_ctrl);
+
+int dibusb_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+{
+ if (d->priv != NULL) {
+ struct dib_fe_xfer_ops *ops = d->priv;
+ if (d->pid_filtering && ops->pid_ctrl != NULL)
+ ops->pid_ctrl(d->fe,index,pid,onoff);
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter);
+
+int dibusb_pid_filter_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ if (d->priv != NULL) {
+ struct dib_fe_xfer_ops *ops = d->priv;
+ if (ops->pid_parse != NULL)
+ if (ops->pid_parse(d->fe,onoff) < 0)
+ err("could not handle pid_parser");
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dibusb_pid_filter_ctrl);
+
+int dibusb_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b[3];
+ int ret;
+ b[0] = DIBUSB_REQ_SET_IOCTL;
+ b[1] = DIBUSB_IOCTL_CMD_POWER_MODE;
+ b[2] = onoff ? DIBUSB_IOCTL_POWER_WAKEUP : DIBUSB_IOCTL_POWER_SLEEP;
+ ret = dvb_usb_generic_write(d,b,3);
+ msleep(10);
+ return ret;
+}
+EXPORT_SYMBOL(dibusb_power_ctrl);
+
+int dibusb2_0_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b[2];
+ b[0] = DIBUSB_REQ_SET_IOCTL;
+ b[1] = onoff ? DIBUSB_IOCTL_CMD_ENABLE_STREAM : DIBUSB_IOCTL_CMD_DISABLE_STREAM;
+
+ dvb_usb_generic_write(d,b,3);
+
+ return dibusb_streaming_ctrl(d,onoff);
+}
+EXPORT_SYMBOL(dibusb2_0_streaming_ctrl);
+
+int dibusb2_0_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ if (onoff) {
+ u8 b[3] = { DIBUSB_REQ_SET_IOCTL, DIBUSB_IOCTL_CMD_POWER_MODE, DIBUSB_IOCTL_POWER_WAKEUP };
+ return dvb_usb_generic_write(d,b,3);
+ } else
+ return 0;
+}
+EXPORT_SYMBOL(dibusb2_0_power_ctrl);
+
+static int dibusb_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u8 sndbuf[wlen+4]; /* lead(1) devaddr,direction(1) addr(2) data(wlen) (len(2) (when reading)) */
+ /* write only ? */
+ int wo = (rbuf == NULL || rlen == 0),
+ len = 2 + wlen + (wo ? 0 : 2);
+
+ sndbuf[0] = wo ? DIBUSB_REQ_I2C_WRITE : DIBUSB_REQ_I2C_READ;
+ sndbuf[1] = (addr << 1) | (wo ? 0 : 1);
+
+ memcpy(&sndbuf[2],wbuf,wlen);
+
+ if (!wo) {
+ sndbuf[wlen+2] = (rlen >> 8) & 0xff;
+ sndbuf[wlen+3] = rlen & 0xff;
+ }
+
+ return dvb_usb_generic_rw(d,sndbuf,len,rbuf,rlen,0);
+}
+
+/*
+ * I2C master xfer function
+ */
+static int dibusb_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (down_interruptible(&d->i2c_sem) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,
+ msg[i+1].buf,msg[i+1].len) < 0)
+ break;
+ i++;
+ } else
+ if (dibusb_i2c_msg(d, msg[i].addr, msg[i].buf,msg[i].len,NULL,0) < 0)
+ break;
+ }
+
+ up(&d->i2c_sem);
+ return i;
+}
+
+static u32 dibusb_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+struct i2c_algorithm dibusb_i2c_algo = {
+ .name = "DiBcom USB I2C algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = dibusb_i2c_xfer,
+ .functionality = dibusb_i2c_func,
+};
+EXPORT_SYMBOL(dibusb_i2c_algo);
+
+int dibusb_read_eeprom_byte(struct dvb_usb_device *d, u8 offs, u8 *val)
+{
+ u8 wbuf[1] = { offs };
+ return dibusb_i2c_msg(d, 0x50, wbuf, 1, val, 1);
+}
+EXPORT_SYMBOL(dibusb_read_eeprom_byte);
+
+int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d)
+{
+ struct dib3000_config demod_cfg;
+ struct dibusb_state *st = d->priv;
+
+ demod_cfg.pll_set = dvb_usb_pll_set_i2c;
+ demod_cfg.pll_init = dvb_usb_pll_init_i2c;
+
+ for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++)
+ if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) {
+ d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+ return 0;
+ }
+
+ return -ENODEV;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_frontend_attach);
+
+int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x60;
+ d->pll_desc = &dvb_pll_env57h1xd5;
+ return 0;
+}
+EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
+
+/*
+ * common remote control stuff
+ */
+struct dvb_usb_rc_key dibusb_rc_keys[] = {
+ /* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
+ { 0x00, 0x16, KEY_POWER },
+ { 0x00, 0x10, KEY_MUTE },
+ { 0x00, 0x03, KEY_1 },
+ { 0x00, 0x01, KEY_2 },
+ { 0x00, 0x06, KEY_3 },
+ { 0x00, 0x09, KEY_4 },
+ { 0x00, 0x1d, KEY_5 },
+ { 0x00, 0x1f, KEY_6 },
+ { 0x00, 0x0d, KEY_7 },
+ { 0x00, 0x19, KEY_8 },
+ { 0x00, 0x1b, KEY_9 },
+ { 0x00, 0x15, KEY_0 },
+ { 0x00, 0x05, KEY_CHANNELUP },
+ { 0x00, 0x02, KEY_CHANNELDOWN },
+ { 0x00, 0x1e, KEY_VOLUMEUP },
+ { 0x00, 0x0a, KEY_VOLUMEDOWN },
+ { 0x00, 0x11, KEY_RECORD },
+ { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+ { 0x00, 0x14, KEY_PLAY },
+ { 0x00, 0x1a, KEY_STOP },
+ { 0x00, 0x40, KEY_REWIND },
+ { 0x00, 0x12, KEY_FASTFORWARD },
+ { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+ { 0x00, 0x4c, KEY_PAUSE },
+ { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+ { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+ /* additional keys TwinHan VisionPlus, the Artec seemingly not have */
+ { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
+ { 0x00, 0x1c, KEY_EPG }, /* EPG */
+ { 0x00, 0x00, KEY_TAB }, /* Tab */
+ { 0x00, 0x48, KEY_INFO }, /* Preview */
+ { 0x00, 0x04, KEY_LIST }, /* RecordList */
+ { 0x00, 0x0f, KEY_TEXT }, /* Teletext */
+ /* Key codes for the KWorld/ADSTech/JetWay remote. */
+ { 0x86, 0x12, KEY_POWER },
+ { 0x86, 0x0f, KEY_SELECT }, /* source */
+ { 0x86, 0x0c, KEY_UNKNOWN }, /* scan */
+ { 0x86, 0x0b, KEY_EPG },
+ { 0x86, 0x10, KEY_MUTE },
+ { 0x86, 0x01, KEY_1 },
+ { 0x86, 0x02, KEY_2 },
+ { 0x86, 0x03, KEY_3 },
+ { 0x86, 0x04, KEY_4 },
+ { 0x86, 0x05, KEY_5 },
+ { 0x86, 0x06, KEY_6 },
+ { 0x86, 0x07, KEY_7 },
+ { 0x86, 0x08, KEY_8 },
+ { 0x86, 0x09, KEY_9 },
+ { 0x86, 0x0a, KEY_0 },
+ { 0x86, 0x18, KEY_ZOOM },
+ { 0x86, 0x1c, KEY_UNKNOWN }, /* preview */
+ { 0x86, 0x13, KEY_UNKNOWN }, /* snap */
+ { 0x86, 0x00, KEY_UNDO },
+ { 0x86, 0x1d, KEY_RECORD },
+ { 0x86, 0x0d, KEY_STOP },
+ { 0x86, 0x0e, KEY_PAUSE },
+ { 0x86, 0x16, KEY_PLAY },
+ { 0x86, 0x11, KEY_BACK },
+ { 0x86, 0x19, KEY_FORWARD },
+ { 0x86, 0x14, KEY_UNKNOWN }, /* pip */
+ { 0x86, 0x15, KEY_ESC },
+ { 0x86, 0x1a, KEY_UP },
+ { 0x86, 0x1e, KEY_DOWN },
+ { 0x86, 0x1f, KEY_LEFT },
+ { 0x86, 0x1b, KEY_RIGHT },
+};
+EXPORT_SYMBOL(dibusb_rc_keys);
+
+int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[5],cmd = DIBUSB_REQ_POLL_REMOTE;
+ dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+ dvb_usb_nec_rc_key_to_event(d,key,event,state);
+ if (key[0] != 0)
+ deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+ return 0;
+}
+EXPORT_SYMBOL(dibusb_rc_query);
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
new file mode 100644
index 000000000000..828b5182e16c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -0,0 +1,350 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-B)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d)
+{
+ struct dib3000_config demod_cfg;
+ struct dibusb_state *st = d->priv;
+
+ demod_cfg.demod_address = 0x8;
+ demod_cfg.pll_set = dvb_usb_pll_set_i2c;
+ demod_cfg.pll_init = dvb_usb_pll_init_i2c;
+
+ if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL)
+ return -ENODEV;
+
+ d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl;
+
+ return 0;
+}
+
+static int dibusb_thomson_tuner_attach(struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x61;
+ d->pll_desc = &dvb_pll_tua6010xs;
+ return 0;
+}
+
+/* Some of the Artec 1.1 device aren't equipped with the default tuner
+ * (Thomson Cable), but with a Panasonic ENV77H11D5. This function figures
+ * this out. */
+static int dibusb_tuner_probe_and_attach(struct dvb_usb_device *d)
+{
+ u8 b[2] = { 0,0 }, b2[1];
+ int ret = 0;
+ struct i2c_msg msg[2] = {
+ { .flags = 0, .buf = b, .len = 2 },
+ { .flags = I2C_M_RD, .buf = b2, .len = 1 },
+ };
+
+ /* the Panasonic sits on I2C addrass 0x60, the Thomson on 0x61 */
+ msg[0].addr = msg[1].addr = 0x60;
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(d->fe,1,msg[0].addr);
+
+ if (i2c_transfer (&d->i2c_adap, msg, 2) != 2) {
+ err("tuner i2c write failed.");
+ ret = -EREMOTEIO;
+ }
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(d->fe,0,msg[0].addr);
+
+ if (b2[0] == 0xfe) {
+ info("this device has the Thomson Cable onboard. Which is default.");
+ dibusb_thomson_tuner_attach(d);
+ } else {
+ u8 bpll[4] = { 0x0b, 0xf5, 0x85, 0xab };
+ info("this device has the Panasonic ENV77H11D5 onboard.");
+ d->pll_addr = 0x60;
+ memcpy(d->pll_init,bpll,4);
+ d->pll_desc = &dvb_pll_tda665x;
+ }
+
+ return ret;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties dibusb1_1_properties;
+static struct dvb_usb_properties dibusb1_1_an2235_properties;
+static struct dvb_usb_properties dibusb2_0b_properties;
+
+static int dibusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ if (dvb_usb_device_init(intf,&dibusb1_1_properties,THIS_MODULE) == 0 ||
+ dvb_usb_device_init(intf,&dibusb1_1_an2235_properties,THIS_MODULE) == 0 ||
+ dvb_usb_device_init(intf,&dibusb2_0b_properties,THIS_MODULE) == 0)
+ return 0;
+
+ return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mb_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_COLD)},
+/* 01 */ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_AVERMEDIA_DVBT_USB_WARM)},
+/* 02 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_COLD) },
+/* 03 */ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_DVBU2000_WARM) },
+/* 04 */ { USB_DEVICE(USB_VID_COMPRO_UNK, USB_PID_COMPRO_DVBU2000_UNK_COLD) },
+/* 05 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_COLD) },
+/* 06 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3000_WARM) },
+/* 07 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_COLD) },
+/* 08 */ { USB_DEVICE(USB_VID_EMPIA, USB_PID_KWORLD_VSTREAM_WARM) },
+/* 09 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_COLD) },
+/* 10 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_GRANDTEC_DVBT_USB_WARM) },
+/* 11 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_COLD) },
+/* 12 */ { USB_DEVICE(USB_VID_GRANDTEC, USB_PID_DIBCOM_MOD3000_WARM) },
+/* 13 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_COLD) },
+/* 14 */ { USB_DEVICE(USB_VID_HYPER_PALTEK, USB_PID_UNK_HYPER_PALTEK_WARM) },
+/* 15 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_COLD) },
+/* 16 */ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7041_WARM) },
+/* 17 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_COLD) },
+/* 18 */ { USB_DEVICE(USB_VID_TWINHAN, USB_PID_TWINHAN_VP7041_WARM) },
+/* 19 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_COLD) },
+/* 20 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_WARM) },
+/* 21 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_COLD) },
+/* 22 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_AN2235_WARM) },
+/* 23 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_COLD) },
+
+/* device ID with default DIBUSB2_0-firmware and with the hacked firmware */
+/* 24 */ { USB_DEVICE(USB_VID_ADSTECH, USB_PID_ADSTECH_USB2_WARM) },
+/* 25 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_COLD) },
+/* 26 */ { USB_DEVICE(USB_VID_KYE, USB_PID_KYE_DVB_T_WARM) },
+
+// #define DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+/* 27 */ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_ULTIMA_TVBOX_ANCHOR_COLD) },
+#endif
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mb_table);
+
+static struct dvb_usb_properties dibusb1_1_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 16,
+
+ .usb_ctrl = CYPRESS_AN2135,
+
+ .firmware = "dvb-usb-dibusb-5.0.0.11.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb_power_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 9,
+ .devices = {
+ { "AVerMedia AverTV DVBT USB1.1",
+ { &dibusb_dib3000mb_table[0], NULL },
+ { &dibusb_dib3000mb_table[1], NULL },
+ },
+ { "Compro Videomate DVB-U2000 - DVB-T USB1.1 (please confirm to linux-dvb)",
+ { &dibusb_dib3000mb_table[2], &dibusb_dib3000mb_table[4], NULL},
+ { &dibusb_dib3000mb_table[3], NULL },
+ },
+ { "DiBcom USB1.1 DVB-T reference design (MOD3000)",
+ { &dibusb_dib3000mb_table[5], NULL },
+ { &dibusb_dib3000mb_table[6], NULL },
+ },
+ { "KWorld V-Stream XPERT DTV - DVB-T USB1.1",
+ { &dibusb_dib3000mb_table[7], NULL },
+ { &dibusb_dib3000mb_table[8], NULL },
+ },
+ { "Grandtec USB1.1 DVB-T",
+ { &dibusb_dib3000mb_table[9], &dibusb_dib3000mb_table[11], NULL },
+ { &dibusb_dib3000mb_table[10], &dibusb_dib3000mb_table[12], NULL },
+ },
+ { "Unkown USB1.1 DVB-T device ???? please report the name to the author",
+ { &dibusb_dib3000mb_table[13], NULL },
+ { &dibusb_dib3000mb_table[14], NULL },
+ },
+ { "TwinhanDTV USB-Ter USB1.1 / Magic Box I / HAMA USB1.1 DVB-T device",
+ { &dibusb_dib3000mb_table[15], &dibusb_dib3000mb_table[17], NULL},
+ { &dibusb_dib3000mb_table[16], &dibusb_dib3000mb_table[18], NULL},
+ },
+ { "Artec T1 USB1.1 TVBOX with AN2135",
+ { &dibusb_dib3000mb_table[19], NULL },
+ { &dibusb_dib3000mb_table[20], NULL },
+ },
+ { "VideoWalker DVB-T USB",
+ { &dibusb_dib3000mb_table[25], NULL },
+ { &dibusb_dib3000mb_table[26], NULL },
+ },
+ }
+};
+
+static struct dvb_usb_properties dibusb1_1_an2235_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 16,
+
+ .usb_ctrl = CYPRESS_AN2235,
+
+ .firmware = "dvb-usb-dibusb-an2235-01.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb_power_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_tuner_probe_and_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+ .num_device_descs = 2,
+#else
+ .num_device_descs = 1,
+#endif
+ .devices = {
+ { "Artec T1 USB1.1 TVBOX with AN2235",
+ { &dibusb_dib3000mb_table[20], NULL },
+ { &dibusb_dib3000mb_table[21], NULL },
+ },
+#ifdef DVB_USB_DIBUSB_MB_FAULTY_USB_IDs
+ { "Artec T1 USB1.1 TVBOX with AN2235 (faulty USB IDs)",
+ { &dibusb_dib3000mb_table[27], NULL },
+ { NULL },
+ },
+#endif
+ }
+};
+
+static struct dvb_usb_properties dibusb2_0b_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 32,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .firmware = "dvb-usb-adstech-usb2-02.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb2_0_power_ctrl,
+ .frontend_attach = dibusb_dib3000mb_frontend_attach,
+ .tuner_attach = dibusb_thomson_tuner_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 63, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "KWorld/ADSTech Instant DVB-T USB 2.0",
+ { &dibusb_dib3000mb_table[23], NULL },
+ { &dibusb_dib3000mb_table[24], NULL },
+ },
+ }
+};
+
+static struct usb_driver dibusb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_dibusb_mb",
+ .probe = dibusb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dibusb_dib3000mb_table,
+};
+
+/* module stuff */
+static int __init dibusb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&dibusb_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit dibusb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dibusb_driver);
+}
+
+module_init (dibusb_module_init);
+module_exit (dibusb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB DVB-T devices (DiB3000M-B based)");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
new file mode 100644
index 000000000000..e9dac430f37d
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -0,0 +1,116 @@
+/* DVB USB compliant linux driver for mobile DVB-T USB devices based on
+ * reference designs made by DiBcom (http://www.dibcom.fr/) (DiB3000M-C/P)
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * based on GPL code from DiBcom, which has
+ * Copyright (C) 2004 Amaury Demol for DiBcom (ademol@dibcom.fr)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+/* USB Driver stuff */
+static struct dvb_usb_properties dibusb_mc_properties;
+
+static int dibusb_mc_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&dibusb_mc_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id dibusb_dib3000mc_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_MOD3001_WARM) },
+/* 02 */ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ULTIMA_TVBOX_USB2_COLD) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, dibusb_dib3000mc_table);
+
+static struct dvb_usb_properties dibusb_mc_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 32,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-dibusb-6.0.0.8.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb2_0_power_ctrl,
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
+
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dibusb_rc_keys,
+ .rc_key_map_size = 63, /* FIXME */
+ .rc_query = dibusb_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { "DiBcom USB2.0 DVB-T reference design (MOD3000P)",
+ { &dibusb_dib3000mc_table[0], NULL },
+ { &dibusb_dib3000mc_table[1], NULL },
+ },
+ { "Artec T1 USB2.0 TVBOX (please report the warm ID)",
+ { &dibusb_dib3000mc_table[2], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver dibusb_mc_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_dibusb_mc",
+ .probe = dibusb_mc_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dibusb_dib3000mc_table,
+};
+
+/* module stuff */
+static int __init dibusb_mc_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&dibusb_mc_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit dibusb_mc_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dibusb_mc_driver);
+}
+
+module_init (dibusb_mc_module_init);
+module_exit (dibusb_mc_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for DiBcom USB2.0 DVB-T (DiB3000M-C/P based) devices");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
new file mode 100644
index 000000000000..6611f62977c0
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -0,0 +1,122 @@
+/* Header file for all dibusb-based-receivers.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DIBUSB_H_
+#define _DVB_USB_DIBUSB_H_
+
+#define DVB_USB_LOG_PREFIX "dibusb"
+#include "dvb-usb.h"
+
+#include "dib3000.h"
+
+/*
+ * protocol of all dibusb related devices
+ */
+
+/*
+ * bulk msg to/from endpoint 0x01
+ *
+ * general structure:
+ * request_byte parameter_bytes
+ */
+
+#define DIBUSB_REQ_START_READ 0x00
+#define DIBUSB_REQ_START_DEMOD 0x01
+
+/*
+ * i2c read
+ * bulk write: 0x02 ((7bit i2c_addr << 1) & 0x01) register_bytes length_word
+ * bulk read: byte_buffer (length_word bytes)
+ */
+#define DIBUSB_REQ_I2C_READ 0x02
+
+/*
+ * i2c write
+ * bulk write: 0x03 (7bit i2c_addr << 1) register_bytes value_bytes
+ */
+#define DIBUSB_REQ_I2C_WRITE 0x03
+
+/*
+ * polling the value of the remote control
+ * bulk write: 0x04
+ * bulk read: byte_buffer (5 bytes)
+ */
+#define DIBUSB_REQ_POLL_REMOTE 0x04
+
+/* additional status values for Hauppauge Remote Control Protocol */
+#define DIBUSB_RC_HAUPPAUGE_KEY_PRESSED 0x01
+#define DIBUSB_RC_HAUPPAUGE_KEY_EMPTY 0x03
+
+/* streaming mode:
+ * bulk write: 0x05 mode_byte
+ *
+ * mode_byte is mostly 0x00
+ */
+#define DIBUSB_REQ_SET_STREAMING_MODE 0x05
+
+/* interrupt the internal read loop, when blocking */
+#define DIBUSB_REQ_INTR_READ 0x06
+
+/* io control
+ * 0x07 cmd_byte param_bytes
+ *
+ * param_bytes can be up to 32 bytes
+ *
+ * cmd_byte function parameter name
+ * 0x00 power mode
+ * 0x00 sleep
+ * 0x01 wakeup
+ *
+ * 0x01 enable streaming
+ * 0x02 disable streaming
+ *
+ *
+ */
+#define DIBUSB_REQ_SET_IOCTL 0x07
+
+/* IOCTL commands */
+
+/* change the power mode in firmware */
+#define DIBUSB_IOCTL_CMD_POWER_MODE 0x00
+#define DIBUSB_IOCTL_POWER_SLEEP 0x00
+#define DIBUSB_IOCTL_POWER_WAKEUP 0x01
+
+/* modify streaming of the FX2 */
+#define DIBUSB_IOCTL_CMD_ENABLE_STREAM 0x01
+#define DIBUSB_IOCTL_CMD_DISABLE_STREAM 0x02
+
+struct dibusb_state {
+ struct dib_fe_xfer_ops ops;
+
+ /* for RC5 remote control */
+ int old_toggle;
+ int last_repeat_count;
+};
+
+extern struct i2c_algorithm dibusb_i2c_algo;
+
+extern int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *);
+extern int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *);
+
+extern int dibusb_streaming_ctrl(struct dvb_usb_device *, int);
+extern int dibusb_pid_filter(struct dvb_usb_device *, int, u16, int);
+extern int dibusb_pid_filter_ctrl(struct dvb_usb_device *, int);
+extern int dibusb_power_ctrl(struct dvb_usb_device *, int);
+extern int dibusb2_0_streaming_ctrl(struct dvb_usb_device *, int);
+extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
+
+#define DEFAULT_RC_INTERVAL 150
+//#define DEFAULT_RC_INTERVAL 100000
+
+extern struct dvb_usb_rc_key dibusb_rc_keys[];
+extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
+extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
new file mode 100644
index 000000000000..9a676afc1d6e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -0,0 +1,261 @@
+/* DVB USB compliant linux driver for Nebula Electronics uDigiTV DVB-T USB2.0
+ * receiver
+ *
+ * Copyright (C) 2005 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * partly based on the SDK published by Nebula Electronics
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "digitv.h"
+
+#include "mt352.h"
+#include "nxt6000.h"
+
+/* debug */
+int dvb_usb_digitv_debug;
+module_param_named(debug,dvb_usb_digitv_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int digitv_ctrl_msg(struct dvb_usb_device *d,
+ u8 cmd, u8 vv, u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 sndbuf[7],rcvbuf[7];
+ memset(sndbuf,0,7); memset(rcvbuf,0,7);
+
+ sndbuf[0] = cmd;
+ sndbuf[1] = vv;
+ sndbuf[2] = wo ? wlen : rlen;
+
+ if (!wo) {
+ memcpy(&sndbuf[3],wbuf,wlen);
+ dvb_usb_generic_write(d,sndbuf,7);
+ } else {
+ dvb_usb_generic_rw(d,sndbuf,7,rcvbuf,7,10);
+ memcpy(rbuf,&rcvbuf[3],rlen);
+ }
+ return 0;
+}
+
+/* I2C */
+static int digitv_i2c_xfer(struct i2c_adapter *adap,struct i2c_msg msg[],int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+ if (down_interruptible(&d->i2c_sem) < 0)
+ return -EAGAIN;
+
+ if (num > 2)
+ warn("more than 2 i2c messages at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i+1 < num && (msg[i+1].flags & I2C_M_RD)) {
+ if (digitv_ctrl_msg(d, USB_READ_COFDM, msg[i].buf[0], NULL, 0,
+ msg[i+1].buf,msg[i+1].len) < 0)
+ break;
+ i++;
+ } else
+ if (digitv_ctrl_msg(d,USB_WRITE_COFDM, msg[i].buf[0],
+ &msg[i].buf[1],msg[i].len-1,NULL,0) < 0)
+ break;
+ }
+
+ up(&d->i2c_sem);
+ return i;
+}
+
+static u32 digitv_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm digitv_i2c_algo = {
+ .name = "Nebula DigiTV USB I2C algorithm",
+ .id = I2C_ALGO_BIT,
+ .master_xfer = digitv_i2c_xfer,
+ .functionality = digitv_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int digitv_identify_state (struct usb_device *udev, struct
+ dvb_usb_properties *props, struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ *cold = udev->descriptor.iManufacturer == 0 && udev->descriptor.iProduct == 0;
+ return 0;
+}
+
+static int digitv_mt352_demod_init(struct dvb_frontend *fe)
+{
+ static u8 reset_buf[] = { 0x89, 0x38, 0x8a, 0x2d, 0x50, 0x80 };
+ static u8 init_buf[] = { 0x68, 0xa0, 0x8e, 0x40, 0x53, 0x50,
+ 0x67, 0x20, 0x7d, 0x01, 0x7c, 0x00, 0x7a, 0x00,
+ 0x79, 0x20, 0x57, 0x05, 0x56, 0x31, 0x88, 0x0f,
+ 0x75, 0x32 };
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(reset_buf); i += 2)
+ mt352_write(fe, &reset_buf[i], 2);
+
+ msleep(1);
+
+ for (i = 0; i < ARRAY_SIZE(init_buf); i += 2)
+ mt352_write(fe, &init_buf[i], 2);
+
+ return 0;
+}
+
+static struct mt352_config digitv_mt352_config = {
+ .demod_address = 0x0, /* ignored by the digitv anyway */
+ .demod_init = digitv_mt352_demod_init,
+ .pll_set = dvb_usb_pll_set,
+};
+
+static struct nxt6000_config digitv_nxt6000_config = {
+ .demod_address = 0x0, /* ignored by the digitv anyway */
+ .clock_inversion = 0x0,
+
+ .pll_init = NULL,
+ .pll_set = NULL,
+};
+
+static int digitv_frontend_attach(struct dvb_usb_device *d)
+{
+ if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL)
+ return 0;
+ if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) {
+
+ warn("nxt6000 support is not done yet, in fact you are one of the first "
+ "person who wants to use this device in Linux. Please report to "
+ "linux-dvb@linuxtv.org");
+
+ return 0;
+ }
+ return -EIO;
+}
+
+static int digitv_tuner_attach(struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x60;
+ d->pll_desc = &dvb_pll_tded4;
+ return 0;
+}
+
+static struct dvb_usb_rc_key digitv_rc_keys[] = {
+ { 0x00, 0x16, KEY_POWER }, /* dummy key */
+};
+
+/* TODO is it really the NEC protocol ? */
+int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[5];
+
+ digitv_ctrl_msg(d,USB_READ_REMOTE,0,NULL,0,&key[1],4);
+ /* TODO state, maybe it is VV ? */
+ if (key[1] != 0)
+ key[0] = 0x01; /* if something is inside the buffer, simulate key press */
+
+ /* call the universal NEC remote processor, to find out the key's state and event */
+ dvb_usb_nec_rc_key_to_event(d,key,event,state);
+ if (key[0] != 0)
+ deb_rc("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_properties digitv_properties;
+
+static int digitv_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&digitv_properties,THIS_MODULE);
+}
+
+static struct usb_device_id digitv_table [] = {
+ { USB_DEVICE(USB_VID_ANCHOR, USB_PID_NEBULA_DIGITV) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, digitv_table);
+
+static struct dvb_usb_properties digitv_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-digitv-01.fw",
+
+ .size_of_priv = 0,
+
+ .frontend_attach = digitv_frontend_attach,
+ .tuner_attach = digitv_tuner_attach,
+
+ .rc_interval = 1000,
+ .rc_key_map = digitv_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(digitv_rc_keys),
+ .rc_query = digitv_rc_query,
+
+ .identify_state = digitv_identify_state,
+
+ .i2c_algo = &digitv_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Nebula Electronics uDigiTV DVB-T USB2.0)",
+ { &digitv_table[0], NULL },
+ { NULL },
+ },
+ }
+};
+
+static struct usb_driver digitv_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_digitv",
+ .probe = digitv_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = digitv_table,
+};
+
+/* module stuff */
+static int __init digitv_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&digitv_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit digitv_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&digitv_driver);
+}
+
+module_init (digitv_module_init);
+module_exit (digitv_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Nebula Electronics uDigiTV DVB-T USB2.0");
+MODULE_VERSION("1.0-alpha");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/digitv.h b/drivers/media/dvb/dvb-usb/digitv.h
new file mode 100644
index 000000000000..477ee428a70e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/digitv.h
@@ -0,0 +1,65 @@
+#ifndef _DVB_USB_DIGITV_H_
+#define _DVB_USB_DIGITV_H_
+
+#define DVB_USB_LOG_PREFIX "digitv"
+#include "dvb-usb.h"
+
+extern int dvb_usb_digitv_debug;
+#define deb_rc(args...) dprintk(dvb_usb_digitv_debug,0x01,args)
+
+/* protocol (from usblogging and the SDK:
+ *
+ * Always 7 bytes bulk message(s) for controlling
+ *
+ * First byte describes the command. Reads are 2 consecutive transfer (as always).
+ *
+ * General structure:
+ *
+ * write or first message of a read:
+ * <cmdbyte> VV <len> B0 B1 B2 B3
+ *
+ * second message of a read
+ * <cmdbyte> VV <len> R0 R1 R2 R3
+ *
+ * whereas 0 < len <= 4
+ *
+ * I2C address is stored somewhere inside the device.
+ *
+ * 0x01 read from EEPROM
+ * VV = offset; B* = 0; R* = value(s)
+ *
+ * 0x02 read register of the COFDM
+ * VV = register; B* = 0; R* = value(s)
+ *
+ * 0x05 write register of the COFDM
+ * VV = register; B* = value(s);
+ *
+ * 0x06 write to the tuner (only for NXT6000)
+ * VV = 0; B* = PLL data; len = 4;
+ *
+ * 0x03 read remote control
+ * VV = 0; B* = 0; len = 4; R* = key
+ *
+ * 0x07 write to the remote (don't know why one should this, resetting ?)
+ * VV = 0; B* = key; len = 4;
+ *
+ * 0x08 write remote type
+ * VV = 0; B[0] = 0x01, len = 4
+ *
+ * 0x09 write device init
+ * TODO
+ */
+#define USB_READ_EEPROM 1
+
+#define USB_READ_COFDM 2
+#define USB_WRITE_COFDM 5
+
+#define USB_WRITE_TUNER 6
+
+#define USB_READ_REMOTE 3
+#define USB_WRITE_REMOTE 7
+#define USB_WRITE_REMOTE_TYPE 8
+
+#define USB_DEV_INIT 9
+
+#endif
diff --git a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
index 1872aa6d200a..b032523b07bc 100644
--- a/drivers/media/dvb/dibusb/dvb-fe-dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c
@@ -1,100 +1,72 @@
-/*
- * dvb-dtt200u-fe.c is a driver which implements the frontend-part of the
- * Yakumo/Typhoon/Hama USB2.0 boxes. It is hard-wired to the dibusb-driver as
- * it uses the usb-transfer functions directly (maybe creating a
- * generic-dvb-usb-lib for all usb-drivers will be reduce some more code.)
+/* Frontend part of the Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
*
* Copyright (C) 2005 Patrick Boettcher <patrick.boettcher@desy.de>
*
- * see dvb-dibusb-core.c for copyright details.
- */
-
-/* guessed protocol description (reverse engineered):
- * read
- * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
- * 81 - <TS_LOCK> <current frequency divided by 250000>
- * 82 - crash - do not touch
- * 83 - crash - do not touch
- * 84 - remote control
- * 85 - crash - do not touch (OK, stop testing here)
- * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
- * 89 - noise-to-signal
- * 8a - unkown 1 byte - signal_strength
- * 8c - ber ???
- * 8d - ber
- * 8e - unc
+ * 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.
*
- * write
- * 02 - bandwidth
- * 03 - frequency (divided by 250000)
- * 04 - pid table (index pid(7:0) pid(12:8))
- * 05 - reset the pid table
- * 08 - demod transfer enabled or not (FX2 transfer is enabled by default)
+ * see Documentation/dvb/README.dvb-usb for more information
*/
-
-#include "dvb-dibusb.h"
-#include "dvb_frontend.h"
+#include "dtt200u.h"
struct dtt200u_fe_state {
- struct usb_dibusb *dib;
+ struct dvb_usb_device *d;
+
+ fe_status_t stat;
struct dvb_frontend_parameters fep;
struct dvb_frontend frontend;
};
-#define moan(which,what) info("unexpected value in '%s' for cmd '%02x' - please report to linux-dvb@linuxtv.org",which,what)
-
static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw[1] = { 0x81 };
- u8 br[3] = { 0 };
-// u8 bdeb[5] = { 0 };
+ u8 st = GET_TUNE_STATUS, b[3];
+
+ dvb_usb_generic_rw(state->d,&st,1,b,3,0);
- dibusb_readwrite_usb(state->dib,bw,1,br,3);
- switch (br[0]) {
+ switch (b[0]) {
case 0x01:
- *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+ *stat = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
break;
- case 0x00:
- *stat = 0;
+ case 0x00: /* pending */
+ *stat = FE_TIMEDOUT; /* during set_frontend */
break;
default:
- moan("br[0]",0x81);
+ case 0x02: /* failed */
+ *stat = 0;
break;
}
-
-// bw[0] = 0x88;
-// dibusb_readwrite_usb(state->dib,bw,1,bdeb,5);
-
-// deb_info("%02x: %02x %02x %02x %02x %02x\n",bw[0],bdeb[0],bdeb[1],bdeb[2],bdeb[3],bdeb[4]);
-
return 0;
}
+
static int dtt200u_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw[1] = { 0x8d };
- *ber = 0;
- dibusb_readwrite_usb(state->dib,bw,1,(u8*) ber, 3);
+ u8 bw = GET_VIT_ERR_CNT,b[3];
+ dvb_usb_generic_rw(state->d,&bw,1,b,3,0);
+ *ber = (b[0] << 16) | (b[1] << 8) | b[2];
return 0;
}
static int dtt200u_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw[1] = { 0x8c };
- *unc = 0;
- dibusb_readwrite_usb(state->dib,bw,1,(u8*) unc, 3);
+ u8 bw = GET_RS_UNCOR_BLK_CNT,b[2];
+
+ dvb_usb_generic_rw(state->d,&bw,1,b,2,0);
+ *unc = (b[0] << 8) | b[1];
return 0;
}
static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw[1] = { 0x8a };
- u8 b;
- dibusb_readwrite_usb(state->dib,bw,1,&b, 1);
+ u8 bw = GET_AGC, b;
+ dvb_usb_generic_rw(state->d,&bw,1,&b,1,0);
*strength = (b << 8) | b;
return 0;
}
@@ -102,18 +74,17 @@ static int dtt200u_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strengt
static int dtt200u_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 bw[1] = { 0x89 };
- u8 br[1] = { 0 };
- dibusb_readwrite_usb(state->dib,bw,1,br,1);
- *snr = ((0xff - br[0]) << 8) | (0xff - br[0]);
+ u8 bw = GET_SNR,br;
+ dvb_usb_generic_rw(state->d,&bw,1,&br,1,0);
+ *snr = ~((br << 8) | br);
return 0;
}
static int dtt200u_fe_init(struct dvb_frontend* fe)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
- u8 b[] = { 0x01 };
- return dibusb_write_usb(state->dib,b,1);
+ u8 b = SET_INIT;
+ return dvb_usb_generic_write(state->d,&b,1);
}
static int dtt200u_fe_sleep(struct dvb_frontend* fe)
@@ -124,8 +95,8 @@ static int dtt200u_fe_sleep(struct dvb_frontend* fe)
static int dtt200u_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 1500;
- tune->step_size = 166667;
- tune->max_drift = 166667 * 2;
+ tune->step_size = 0;
+ tune->max_drift = 0;
return 0;
}
@@ -133,27 +104,32 @@ static int dtt200u_fe_set_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep)
{
struct dtt200u_fe_state *state = fe->demodulator_priv;
+ int i;
+ fe_status_t st;
u16 freq = fep->frequency / 250000;
- u8 bw,bwbuf[2] = { 0x03, 0 }, freqbuf[3] = { 0x02, 0, 0 };
+ u8 bwbuf[2] = { SET_BANDWIDTH, 0 },freqbuf[3] = { SET_RF_FREQ, 0, 0 };
switch (fep->u.ofdm.bandwidth) {
- case BANDWIDTH_8_MHZ: bw = 8; break;
- case BANDWIDTH_7_MHZ: bw = 7; break;
- case BANDWIDTH_6_MHZ: bw = 6; break;
+ case BANDWIDTH_8_MHZ: bwbuf[1] = 8; break;
+ case BANDWIDTH_7_MHZ: bwbuf[1] = 7; break;
+ case BANDWIDTH_6_MHZ: bwbuf[1] = 6; break;
case BANDWIDTH_AUTO: return -EOPNOTSUPP;
default:
return -EINVAL;
}
- deb_info("set_frontend\n");
- bwbuf[1] = bw;
- dibusb_write_usb(state->dib,bwbuf,2);
+ dvb_usb_generic_write(state->d,bwbuf,2);
freqbuf[1] = freq & 0xff;
freqbuf[2] = (freq >> 8) & 0xff;
- dibusb_write_usb(state->dib,freqbuf,3);
+ dvb_usb_generic_write(state->d,freqbuf,3);
- memcpy(&state->fep,fep,sizeof(struct dvb_frontend_parameters));
+ for (i = 0; i < 30; i++) {
+ msleep(20);
+ dtt200u_fe_read_status(fe, &st);
+ if (st & FE_TIMEDOUT)
+ continue;
+ }
return 0;
}
@@ -172,37 +148,9 @@ static void dtt200u_fe_release(struct dvb_frontend* fe)
kfree(state);
}
-static int dtt200u_pid_control(struct dvb_frontend *fe,int index, int pid,int onoff)
-{
- struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
- u8 b_pid[4];
- pid = onoff ? pid : 0;
-
- b_pid[0] = 0x04;
- b_pid[1] = index;
- b_pid[2] = pid & 0xff;
- b_pid[3] = (pid >> 8) & 0xff;
-
- dibusb_write_usb(state->dib,b_pid,4);
- return 0;
-}
-
-static int dtt200u_fifo_control(struct dvb_frontend *fe, int onoff)
-{
- struct dtt200u_fe_state *state = (struct dtt200u_fe_state*) fe->demodulator_priv;
- u8 b_streaming[2] = { 0x08, onoff };
- u8 b_rst_pid[1] = { 0x05 };
-
- dibusb_write_usb(state->dib,b_streaming,2);
-
- if (!onoff)
- dibusb_write_usb(state->dib,b_rst_pid,1);
- return 0;
-}
-
static struct dvb_frontend_ops dtt200u_fe_ops;
-struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfer_ops *xfer_ops)
+struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d)
{
struct dtt200u_fe_state* state = NULL;
@@ -214,14 +162,11 @@ struct dvb_frontend* dtt200u_fe_attach(struct usb_dibusb *dib, struct dib_fe_xfe
deb_info("attaching frontend dtt200u\n");
- state->dib = dib;
+ state->d = d;
state->frontend.ops = &dtt200u_fe_ops;
state->frontend.demodulator_priv = state;
- xfer_ops->fifo_ctrl = dtt200u_fifo_control;
- xfer_ops->pid_ctrl = dtt200u_pid_control;
-
goto success;
error:
return NULL;
@@ -231,7 +176,7 @@ success:
static struct dvb_frontend_ops dtt200u_fe_ops = {
.info = {
- .name = "DTT200U (Yakumo/Typhoon/Hama) DVB-T",
+ .name = "WideView USB DVB-T",
.type = FE_OFDM,
.frequency_min = 44250000,
.frequency_max = 867250000,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
new file mode 100644
index 000000000000..47dba6e45968
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -0,0 +1,233 @@
+/* DVB USB library compliant Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Steve Chang from WideView for providing support for the WT-220U.
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dtt200u.h"
+
+/* debug */
+int dvb_usb_dtt200u_debug;
+module_param_named(debug,dvb_usb_dtt200u_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2 (or-able))." DVB_USB_DEBUG_STATUS);
+
+static int dtt200u_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b = SET_INIT;
+
+ if (onoff)
+ dvb_usb_generic_write(d,&b,2);
+
+ return 0;
+}
+
+static int dtt200u_streaming_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 b_streaming[2] = { SET_STREAMING, onoff };
+ u8 b_rst_pid = RESET_PID_FILTER;
+
+ dvb_usb_generic_write(d,b_streaming,2);
+
+ if (onoff == 0)
+ dvb_usb_generic_write(d,&b_rst_pid,1);
+ return 0;
+}
+
+static int dtt200u_pid_filter(struct dvb_usb_device *d, int index, u16 pid, int onoff)
+{
+ u8 b_pid[4];
+ pid = onoff ? pid : 0;
+
+ b_pid[0] = SET_PID_FILTER;
+ b_pid[1] = index;
+ b_pid[2] = pid & 0xff;
+ b_pid[3] = (pid >> 8) & 0x1f;
+
+ return dvb_usb_generic_write(d,b_pid,4);
+}
+
+/* remote control */
+/* key list for the tiny remote control (Yakumo, don't know about the others) */
+static struct dvb_usb_rc_key dtt200u_rc_keys[] = {
+ { 0x80, 0x01, KEY_MUTE },
+ { 0x80, 0x02, KEY_CHANNELDOWN },
+ { 0x80, 0x03, KEY_VOLUMEDOWN },
+ { 0x80, 0x04, KEY_1 },
+ { 0x80, 0x05, KEY_2 },
+ { 0x80, 0x06, KEY_3 },
+ { 0x80, 0x07, KEY_4 },
+ { 0x80, 0x08, KEY_5 },
+ { 0x80, 0x09, KEY_6 },
+ { 0x80, 0x0a, KEY_7 },
+ { 0x80, 0x0c, KEY_ZOOM },
+ { 0x80, 0x0d, KEY_0 },
+ { 0x80, 0x0e, KEY_SELECT },
+ { 0x80, 0x12, KEY_POWER },
+ { 0x80, 0x1a, KEY_CHANNELUP },
+ { 0x80, 0x1b, KEY_8 },
+ { 0x80, 0x1e, KEY_VOLUMEUP },
+ { 0x80, 0x1f, KEY_9 },
+};
+
+static int dtt200u_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[5],cmd = GET_RC_CODE;
+ dvb_usb_generic_rw(d,&cmd,1,key,5,0);
+ dvb_usb_nec_rc_key_to_event(d,key,event,state);
+ if (key[0] != 0)
+ deb_info("key: %x %x %x %x %x\n",key[0],key[1],key[2],key[3],key[4]);
+ return 0;
+}
+
+static int dtt200u_frontend_attach(struct dvb_usb_device *d)
+{
+ d->fe = dtt200u_fe_attach(d);
+ return 0;
+}
+
+static struct dvb_usb_properties dtt200u_properties;
+static struct dvb_usb_properties wt220u_properties;
+
+static int dtt200u_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ if (dvb_usb_device_init(intf,&dtt200u_properties,THIS_MODULE) == 0 ||
+ dvb_usb_device_init(intf,&wt220u_properties,THIS_MODULE) == 0)
+ return 0;
+
+ return -ENODEV;
+}
+
+static struct usb_device_id dtt200u_usb_table [] = {
+// { USB_DEVICE(0x04b4,0x8613) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_DTT200U_WARM) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_COLD) },
+ { USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_WT220U_WARM) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(usb, dtt200u_usb_table);
+
+static struct dvb_usb_properties dtt200u_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-dtt200u-01.fw",
+
+ .power_ctrl = dtt200u_power_ctrl,
+ .streaming_ctrl = dtt200u_streaming_ctrl,
+ .pid_filter = dtt200u_pid_filter,
+ .frontend_attach = dtt200u_frontend_attach,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView/Yuan/Yakumo/Hama/Typhoon DVB-T USB2.0 (WT-200U)",
+ .cold_ids = { &dtt200u_usb_table[0], NULL },
+ .warm_ids = { &dtt200u_usb_table[1], NULL },
+ },
+ { 0 },
+ }
+};
+
+static struct dvb_usb_properties wt220u_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_NEED_PID_FILTERING,
+ .pid_filter_count = 15,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-wt220u-01.fw",
+
+ .power_ctrl = dtt200u_power_ctrl,
+ .streaming_ctrl = dtt200u_streaming_ctrl,
+ .pid_filter = dtt200u_pid_filter,
+ .frontend_attach = dtt200u_frontend_attach,
+
+ .rc_interval = 300,
+ .rc_key_map = dtt200u_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dtt200u_rc_keys),
+ .rc_query = dtt200u_rc_query,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { .name = "WideView WT-220U PenType Receiver (and clones)",
+ .cold_ids = { &dtt200u_usb_table[2], NULL },
+ .warm_ids = { &dtt200u_usb_table[3], NULL },
+ },
+ { 0 },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver dtt200u_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_dtt200u",
+ .probe = dtt200u_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = dtt200u_usb_table,
+};
+
+/* module stuff */
+static int __init dtt200u_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&dtt200u_usb_driver))) {
+ err("usb_register failed. (%d)",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit dtt200u_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&dtt200u_usb_driver);
+}
+
+module_init(dtt200u_usb_module_init);
+module_exit(dtt200u_usb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for the WideView/Yakumo/Hama/Typhoon DVB-T USB2.0 devices");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.h b/drivers/media/dvb/dvb-usb/dtt200u.h
new file mode 100644
index 000000000000..6f1f3042e21a
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dtt200u.h
@@ -0,0 +1,56 @@
+/* Common header file of Linux driver for the WideView/ Yakumo/ Hama/
+ * Typhoon/ Yuan DVB-T USB2.0 receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_DTT200U_H_
+#define _DVB_USB_DTT200U_H_
+
+#define DVB_USB_LOG_PREFIX "dtt200u"
+#include "dvb-usb.h"
+
+extern int dvb_usb_dtt200u_debug;
+#define deb_info(args...) dprintk(dvb_usb_dtt200u_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_dtt200u_debug,0x02,args)
+
+/* guessed protocol description (reverse engineered):
+ * read
+ * 00 - USB type 0x02 for usb2.0, 0x01 for usb1.1
+ * 88 - locking 2 bytes (0x80 0x40 == no signal, 0x89 0x20 == nice signal)
+ */
+
+#define GET_SPEED 0x00
+#define GET_TUNE_STATUS 0x81
+#define GET_RC_CODE 0x84
+#define GET_CONFIGURATION 0x88
+#define GET_AGC 0x89
+#define GET_SNR 0x8a
+#define GET_VIT_ERR_CNT 0x8c
+#define GET_RS_ERR_CNT 0x8d
+#define GET_RS_UNCOR_BLK_CNT 0x8e
+
+/* write
+ * 01 - init
+ * 02 - frequency (divided by 250000)
+ * 03 - bandwidth
+ * 04 - pid table (index pid(7:0) pid(12:8))
+ * 05 - reset the pid table
+ * 08 - transfer switch
+ */
+
+#define SET_INIT 0x01
+#define SET_RF_FREQ 0x02
+#define SET_BANDWIDTH 0x03
+#define SET_PID_FILTER 0x04
+#define RESET_PID_FILTER 0x05
+#define SET_STREAMING 0x08
+
+extern struct dvb_frontend * dtt200u_fe_attach(struct dvb_usb_device *d);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-common.h b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
new file mode 100644
index 000000000000..7300489d3e24
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-common.h
@@ -0,0 +1,46 @@
+/* dvb-usb-common.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * a header file containing prototypes and types for internal use of the dvb-usb-lib
+ */
+#ifndef _DVB_USB_COMMON_H_
+#define _DVB_USB_COMMON_H_
+
+#define DVB_USB_LOG_PREFIX "dvb-usb"
+#include "dvb-usb.h"
+
+extern int dvb_usb_debug;
+extern int dvb_usb_disable_rc_polling;
+
+#define deb_info(args...) dprintk(dvb_usb_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_debug,0x02,args)
+#define deb_pll(args...) dprintk(dvb_usb_debug,0x04,args)
+#define deb_ts(args...) dprintk(dvb_usb_debug,0x08,args)
+#define deb_err(args...) dprintk(dvb_usb_debug,0x10,args)
+#define deb_rc(args...) dprintk(dvb_usb_debug,0x20,args)
+#define deb_fw(args...) dprintk(dvb_usb_debug,0x40,args)
+#define deb_mem(args...) dprintk(dvb_usb_debug,0x80,args)
+
+/* commonly used methods */
+extern int usb_cypress_load_firmware(struct usb_device *, const char *, int);
+
+extern int dvb_usb_urb_submit(struct dvb_usb_device *);
+extern int dvb_usb_urb_kill(struct dvb_usb_device *);
+extern int dvb_usb_urb_init(struct dvb_usb_device *);
+extern int dvb_usb_urb_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_i2c_init(struct dvb_usb_device *);
+extern int dvb_usb_i2c_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_dvb_init(struct dvb_usb_device *);
+extern int dvb_usb_dvb_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_fe_init(struct dvb_usb_device *);
+extern int dvb_usb_fe_exit(struct dvb_usb_device *);
+
+extern int dvb_usb_remote_init(struct dvb_usb_device *);
+extern int dvb_usb_remote_exit(struct dvb_usb_device *);
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
new file mode 100644
index 000000000000..3491ff40885c
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c
@@ -0,0 +1,210 @@
+/* dvb-usb-dvb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * linux-dvb API.
+ */
+#include "dvb-usb-common.h"
+
+static int dvb_usb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ struct dvb_usb_device *d = dvbdmxfeed->demux->priv;
+ int newfeedcount,ret;
+
+ if (d == NULL)
+ return -ENODEV;
+
+ newfeedcount = d->feedcount + (onoff ? 1 : -1);
+
+ /*
+ * stop feed before setting a new pid if there will be no pid anymore
+ */
+ if (newfeedcount == 0) {
+ deb_ts("stop feeding\n");
+
+ if (d->props.streaming_ctrl != NULL)
+ if ((ret = d->props.streaming_ctrl(d,0)))
+ err("error while stopping stream.");
+
+ dvb_usb_urb_kill(d);
+ }
+
+ d->feedcount = newfeedcount;
+
+ /* activate the pid on the device specific pid_filter */
+ deb_ts("setting pid: %5d %04x at index %d '%s'\n",dvbdmxfeed->pid,dvbdmxfeed->pid,dvbdmxfeed->index,onoff ? "on" : "off");
+ if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
+ d->pid_filtering &&
+ d->props.pid_filter != NULL)
+ d->props.pid_filter(d,dvbdmxfeed->index,dvbdmxfeed->pid,onoff);
+
+ /* start the feed if this was the first feed and there is still a feed
+ * for reception.
+ */
+ if (d->feedcount == onoff && d->feedcount > 0) {
+
+ deb_ts("controlling pid parser\n");
+ if (d->props.caps & DVB_USB_HAS_PID_FILTER &&
+ d->props.caps & DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF &&
+ d->props.pid_filter_ctrl != NULL)
+ if (d->props.pid_filter_ctrl(d,d->pid_filtering) < 0)
+ err("could not handle pid_parser");
+
+ deb_ts("start feeding\n");
+ if (d->props.streaming_ctrl != NULL)
+ if (d->props.streaming_ctrl(d,1)) {
+ err("error while enabling fifo.");
+ return -ENODEV;
+ }
+
+ dvb_usb_urb_submit(d);
+ }
+ return 0;
+}
+
+static int dvb_usb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("start pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid,dvbdmxfeed->type);
+ return dvb_usb_ctrl_feed(dvbdmxfeed,1);
+}
+
+static int dvb_usb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ deb_ts("stop pid: 0x%04x, feedtype: %d\n", dvbdmxfeed->pid, dvbdmxfeed->type);
+ return dvb_usb_ctrl_feed(dvbdmxfeed,0);
+}
+
+int dvb_usb_dvb_init(struct dvb_usb_device *d)
+{
+ int ret;
+
+ if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name,
+ d->owner)) < 0) {
+ deb_info("dvb_register_adapter failed: error %d", ret);
+ goto err;
+ }
+ d->dvb_adap.priv = d;
+
+ if (d->props.read_mac_address) {
+ if (d->props.read_mac_address(d,d->dvb_adap.proposed_mac) == 0)
+ info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",d->dvb_adap.proposed_mac[0],
+ d->dvb_adap.proposed_mac[1],d->dvb_adap.proposed_mac[2],
+ d->dvb_adap.proposed_mac[3],d->dvb_adap.proposed_mac[4],
+ d->dvb_adap.proposed_mac[5]);
+ else
+ err("MAC address reading failed.");
+ }
+
+
+ d->demux.dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ d->demux.priv = d;
+
+ d->demux.feednum = d->demux.filternum = d->max_feed_count;
+ d->demux.start_feed = dvb_usb_start_feed;
+ d->demux.stop_feed = dvb_usb_stop_feed;
+ d->demux.write_to_decoder = NULL;
+ if ((ret = dvb_dmx_init(&d->demux)) < 0) {
+ err("dvb_dmx_init failed: error %d",ret);
+ goto err_dmx;
+ }
+
+ d->dmxdev.filternum = d->demux.filternum;
+ d->dmxdev.demux = &d->demux.dmx;
+ d->dmxdev.capabilities = 0;
+ if ((ret = dvb_dmxdev_init(&d->dmxdev, &d->dvb_adap)) < 0) {
+ err("dvb_dmxdev_init failed: error %d",ret);
+ goto err_dmx_dev;
+ }
+
+ dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx);
+
+ goto success;
+err_dmx_dev:
+ dvb_dmx_release(&d->demux);
+err_dmx:
+ dvb_unregister_adapter(&d->dvb_adap);
+err:
+ return ret;
+success:
+ d->state |= DVB_USB_STATE_DVB;
+ return 0;
+}
+
+int dvb_usb_dvb_exit(struct dvb_usb_device *d)
+{
+ if (d->state & DVB_USB_STATE_DVB) {
+ deb_info("unregistering DVB part\n");
+ dvb_net_release(&d->dvb_net);
+ d->demux.dmx.close(&d->demux.dmx);
+ dvb_dmxdev_release(&d->dmxdev);
+ dvb_dmx_release(&d->demux);
+ dvb_unregister_adapter(&d->dvb_adap);
+ d->state &= ~DVB_USB_STATE_DVB;
+ }
+ return 0;
+}
+
+static int dvb_usb_fe_wakeup(struct dvb_frontend *fe)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+
+ if (d->props.power_ctrl)
+ d->props.power_ctrl(d,1);
+
+ if (d->fe_init)
+ d->fe_init(fe);
+
+ return 0;
+}
+
+static int dvb_usb_fe_sleep(struct dvb_frontend *fe)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+
+ if (d->fe_sleep)
+ d->fe_sleep(fe);
+
+ if (d->props.power_ctrl)
+ d->props.power_ctrl(d,0);
+
+ return 0;
+}
+
+int dvb_usb_fe_init(struct dvb_usb_device* d)
+{
+ if (d->props.frontend_attach == NULL) {
+ err("strange '%s' doesn't want to attach a frontend.",d->desc->name);
+ return 0;
+ }
+
+ d->props.frontend_attach(d);
+
+ /* re-assign sleep and wakeup functions */
+ if (d->fe != NULL) {
+ d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup;
+ d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep;
+
+ if (dvb_register_frontend(&d->dvb_adap, d->fe)) {
+ err("Frontend registration failed.");
+ if (d->fe->ops->release)
+ d->fe->ops->release(d->fe);
+ d->fe = NULL;
+ return -ENODEV;
+ }
+ } else
+ err("no frontend was attached by '%s'",d->desc->name);
+
+ if (d->props.tuner_attach != NULL)
+ d->props.tuner_attach(d);
+
+ return 0;
+}
+
+int dvb_usb_fe_exit(struct dvb_usb_device *d)
+{
+ if (d->fe != NULL)
+ dvb_unregister_frontend(d->fe);
+ return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
new file mode 100644
index 000000000000..5244e39770a0
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-firmware.c
@@ -0,0 +1,100 @@
+/* dvb-usb-firmware.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for downloading the firmware to Cypress FX 1 and 2 based devices.
+ *
+ * FIXME: This part does actually not belong to dvb-usb, but to the usb-subsystem.
+ */
+#include "dvb-usb-common.h"
+
+#include <linux/firmware.h>
+#include <linux/usb.h>
+
+struct usb_cypress_controller {
+ int id;
+ const char *name; /* name of the usb controller */
+ u16 cpu_cs_register; /* needs to be restarted, when the firmware has been downloaded. */
+};
+
+static struct usb_cypress_controller cypress[] = {
+ { .id = CYPRESS_AN2135, .name = "Cypress AN2135", .cpu_cs_register = 0x7f92 },
+ { .id = CYPRESS_AN2235, .name = "Cypress AN2235", .cpu_cs_register = 0x7f92 },
+ { .id = CYPRESS_FX2, .name = "Cypress FX2", .cpu_cs_register = 0xe600 },
+};
+
+/*
+ * load a firmware packet to the device
+ */
+static int usb_cypress_writemem(struct usb_device *udev,u16 addr,u8 *data, u8 len)
+{
+ return usb_control_msg(udev, usb_sndctrlpipe(udev,0),
+ 0xa0, USB_TYPE_VENDOR, addr, 0x00, data, len, 5*HZ);
+}
+
+int usb_cypress_load_firmware(struct usb_device *udev, const char *filename, int type)
+{
+ const struct firmware *fw = NULL;
+ u16 addr;
+ u8 *b,*p;
+ int ret = 0,i;
+
+ if ((ret = request_firmware(&fw, filename, &udev->dev)) != 0) {
+ err("did not find the firmware file. (%s) "
+ "Please see linux/Documentation/dvb/ for more details on firmware-problems.",
+ filename);
+ return ret;
+ }
+
+ info("downloading firmware from file '%s' to the '%s'",filename,cypress[type].name);
+
+ p = kmalloc(fw->size,GFP_KERNEL);
+ if (p != NULL) {
+ u8 reset;
+ /*
+ * you cannot use the fw->data as buffer for
+ * usb_control_msg, a new buffer has to be
+ * created
+ */
+ memcpy(p,fw->data,fw->size);
+
+ /* stop the CPU */
+ reset = 1;
+ if ((ret = usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1)) != 1)
+ err("could not stop the USB controller CPU.");
+ for(i = 0; p[i+3] == 0 && i < fw->size; ) {
+ b = (u8 *) &p[i];
+ addr = cpu_to_le16( *((u16 *) &b[1]) );
+
+ deb_fw("writing to address 0x%04x (buffer: 0x%02x%02x)\n",addr,b[1],b[2]);
+
+ ret = usb_cypress_writemem(udev,addr,&b[4],b[0]);
+
+ if (ret != b[0]) {
+ err("error while transferring firmware "
+ "(transferred size: %d, block size: %d)",
+ ret,b[0]);
+ ret = -EINVAL;
+ break;
+ }
+ i += 5 + b[0];
+ }
+ /* length in ret */
+ if (ret > 0)
+ ret = 0;
+ /* restart the CPU */
+ reset = 0;
+ if (ret || usb_cypress_writemem(udev,cypress[type].cpu_cs_register,&reset,1) != 1) {
+ err("could not restart the USB controller CPU.");
+ ret = -EINVAL;
+ }
+
+ kfree(p);
+ } else {
+ ret = -ENOMEM;
+ }
+ release_firmware(fw);
+
+ return ret;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
new file mode 100644
index 000000000000..9f0a8d90d146
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -0,0 +1,118 @@
+/* dvb-usb-i2c.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for (de-)initializing an I2C adapter.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_i2c_init(struct dvb_usb_device *d)
+{
+ int ret = 0;
+
+ if (!(d->props.caps & DVB_USB_IS_AN_I2C_ADAPTER))
+ return 0;
+
+ if (d->props.i2c_algo == NULL) {
+ err("no i2c algorithm specified");
+ return -EINVAL;
+ }
+
+ strncpy(d->i2c_adap.name,d->desc->name,I2C_NAME_SIZE);
+#ifdef I2C_ADAP_CLASS_TV_DIGITAL
+ d->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
+#else
+ d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
+#endif
+ d->i2c_adap.algo = d->props.i2c_algo;
+ d->i2c_adap.algo_data = NULL;
+ d->i2c_adap.id = I2C_ALGO_BIT;
+
+ i2c_set_adapdata(&d->i2c_adap, d);
+
+ if ((ret = i2c_add_adapter(&d->i2c_adap)) < 0)
+ err("could not add i2c adapter");
+
+ d->state |= DVB_USB_STATE_I2C;
+
+ return ret;
+}
+
+int dvb_usb_i2c_exit(struct dvb_usb_device *d)
+{
+ if (d->state & DVB_USB_STATE_I2C)
+ i2c_del_adapter(&d->i2c_adap);
+ d->state &= ~DVB_USB_STATE_I2C;
+ return 0;
+}
+
+int dvb_usb_pll_init_i2c(struct dvb_frontend *fe)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+ struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 };
+ int ret = 0;
+
+ /* if there is nothing to initialize */
+ if (d->pll_init[0] == 0x00 && d->pll_init[1] == 0x00 &&
+ d->pll_init[2] == 0x00 && d->pll_init[3] == 0x00)
+ return 0;
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(fe,1,d->pll_addr);
+
+ deb_pll("pll init: %x\n",d->pll_addr);
+ deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1],
+ d->pll_init[2],d->pll_init[3]);
+
+ if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+ err("tuner i2c write failed for pll_init.");
+ ret = -EREMOTEIO;
+ }
+ msleep(1);
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(fe,0,d->pll_addr);
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usb_pll_init_i2c);
+
+int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5])
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+
+ deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc);
+
+ b[0] = d->pll_addr << 1;
+ dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth);
+
+ deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]);
+
+ return 0;
+}
+EXPORT_SYMBOL(dvb_usb_pll_set);
+
+int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+ struct dvb_usb_device *d = fe->dvb->priv;
+ int ret = 0;
+ u8 b[5];
+ struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 };
+
+ dvb_usb_pll_set(fe,fep,b);
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(fe,1,d->pll_addr);
+
+ if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) {
+ err("tuner i2c write failed for pll_set.");
+ ret = -EREMOTEIO;
+ }
+ msleep(1);
+
+ if (d->tuner_pass_ctrl)
+ d->tuner_pass_ctrl(fe,0,d->pll_addr);
+
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usb_pll_set_i2c);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
new file mode 100644
index 000000000000..794d513a8480
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -0,0 +1,89 @@
+/* dvb-usb-ids.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
+ * dvb-usb-init.c for copyright information.
+ *
+ * a header file containing define's for the USB device supported by the
+ * various drivers.
+ */
+#ifndef _DVB_USB_IDS_H_
+#define _DVB_USB_IDS_H_
+
+/* Vendor IDs */
+#define USB_VID_ADSTECH 0x06e1
+#define USB_VID_ANCHOR 0x0547
+#define USB_VID_WIDEVIEW 0x14aa
+#define USB_VID_AVERMEDIA 0x07ca
+#define USB_VID_COMPRO 0x185b
+#define USB_VID_COMPRO_UNK 0x145f
+#define USB_VID_CYPRESS 0x04b4
+#define USB_VID_DIBCOM 0x10b8
+#define USB_VID_DVICO 0x0fe9
+#define USB_VID_EMPIA 0xeb1a
+#define USB_VID_GRANDTEC 0x5032
+#define USB_VID_HANFTEK 0x15f4
+#define USB_VID_HAUPPAUGE 0x2040
+#define USB_VID_HYPER_PALTEK 0x1025
+#define USB_VID_KYE 0x0458
+#define USB_VID_MEDION 0x1660
+#define USB_VID_VISIONPLUS 0x13d3
+#define USB_VID_TWINHAN 0x1822
+#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
+
+/* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD 0xa333
+#define USB_PID_ADSTECH_USB2_WARM 0xa334
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD 0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM 0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD 0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM 0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD 0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM 0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD 0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM 0x010d
+#define USB_PID_DIBCOM_MOD3000_COLD 0x0bb8
+#define USB_PID_DIBCOM_MOD3000_WARM 0x0bb9
+#define USB_PID_DIBCOM_MOD3001_COLD 0x0bc6
+#define USB_PID_DIBCOM_MOD3001_WARM 0x0bc7
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD 0x2131
+#define USB_PID_GRANDTEC_DVBT_USB_COLD 0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM 0x0fa1
+#define USB_PID_KWORLD_VSTREAM_COLD 0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
+#define USB_PID_TWINHAN_VP7041_COLD 0x3201
+#define USB_PID_TWINHAN_VP7041_WARM 0x3202
+#define USB_PID_TWINHAN_VP7045_COLD 0x3205
+#define USB_PID_TWINHAN_VP7045_WARM 0x3206
+#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
+#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
+#define USB_PID_TWINHAN_VP7021_COLD 0x3207
+#define USB_PID_TWINHAN_VP7021_WARM 0x3208
+#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM 0x8106
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD 0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM 0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD 0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD 0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD 0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM 0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD 0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM 0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD 0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM 0x0015
+#define USB_PID_DTT200U_COLD 0x0201
+#define USB_PID_DTT200U_WARM 0x0301
+#define USB_PID_WT220U_COLD 0x0222
+#define USB_PID_WT220U_WARM 0x0221
+#define USB_PID_WINTV_NOVA_T_USB2_COLD 0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM 0x9301
+#define USB_PID_NEBULA_DIGITV 0x0201
+#define USB_PID_DVICO_BLUEBIRD_LGZ201 0xdb00
+#define USB_PID_DVICO_BLUEBIRD_TH7579 0xdb10
+#define USB_PID_DVICO_BLUEBIRD_LGDT 0xd820
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_1 0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_2 0xdb11
+#define USB_PID_MEDION_MD95700 0x0932
+#define USB_PID_KYE_DVB_T_COLD 0x701e
+#define USB_PID_KYE_DVB_T_WARM 0x701f
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
new file mode 100644
index 000000000000..65f0c095abc9
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -0,0 +1,215 @@
+/*
+ * DVB USB library - provides a generic interface for a DVB USB device driver.
+ *
+ * dvb-usb-init.c
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dvb-usb-common.h"
+
+/* debug */
+int dvb_usb_debug;
+module_param_named(debug,dvb_usb_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int dvb_usb_disable_rc_polling;
+module_param_named(disable_rc_polling, dvb_usb_disable_rc_polling, int, 0644);
+MODULE_PARM_DESC(disable_rc_polling, "disable remote control polling (default: 0).");
+
+/* general initialization functions */
+int dvb_usb_exit(struct dvb_usb_device *d)
+{
+ deb_info("state before exiting everything: %x\n",d->state);
+ dvb_usb_remote_exit(d);
+ dvb_usb_fe_exit(d);
+ dvb_usb_i2c_exit(d);
+ dvb_usb_dvb_exit(d);
+ dvb_usb_urb_exit(d);
+ deb_info("state should be zero now: %x\n",d->state);
+ d->state = DVB_USB_STATE_INIT;
+ kfree(d->priv);
+ kfree(d);
+ return 0;
+}
+
+static int dvb_usb_init(struct dvb_usb_device *d)
+{
+ int ret = 0;
+
+ sema_init(&d->usb_sem, 1);
+ sema_init(&d->i2c_sem, 1);
+
+ d->state = DVB_USB_STATE_INIT;
+
+/* check the capabilites and set appropriate variables */
+
+/* speed - when running at FULL speed we need a HW PID filter */
+ if (d->udev->speed == USB_SPEED_FULL && !(d->props.caps & DVB_USB_HAS_PID_FILTER)) {
+ err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
+ return -ENODEV;
+ }
+
+ if ((d->udev->speed == USB_SPEED_FULL && d->props.caps & DVB_USB_HAS_PID_FILTER) ||
+ (d->props.caps & DVB_USB_NEED_PID_FILTERING)) {
+ info("will use the device's hardware PID filter (table count: %d).",d->props.pid_filter_count);
+ d->pid_filtering = 1;
+ d->max_feed_count = d->props.pid_filter_count;
+ } else {
+ info("will pass the complete MPEG2 transport stream to the software demuxer.");
+ d->pid_filtering = 0;
+ d->max_feed_count = 255;
+ }
+
+ if (d->props.power_ctrl)
+ d->props.power_ctrl(d,1);
+
+ if ((ret = dvb_usb_urb_init(d)) ||
+ (ret = dvb_usb_dvb_init(d)) ||
+ (ret = dvb_usb_i2c_init(d)) ||
+ (ret = dvb_usb_fe_init(d))) {
+ dvb_usb_exit(d);
+ return ret;
+ }
+
+ if ((ret = dvb_usb_remote_init(d)))
+ err("could not initialize remote control.");
+
+ if (d->props.power_ctrl)
+ d->props.power_ctrl(d,0);
+
+ return 0;
+}
+
+/* determine the name and the state of the just found USB device */
+static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_properties *props, int *cold)
+{
+ int i,j;
+ struct dvb_usb_device_description *desc = NULL;
+ *cold = -1;
+
+ for (i = 0; i < props->num_device_descs; i++) {
+
+ for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
+ deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+ if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+ props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+ *cold = 1;
+ desc = &props->devices[i];
+ break;
+ }
+ }
+
+ if (desc != NULL)
+ break;
+
+ for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
+ deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+ if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
+ props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
+ *cold = 0;
+ desc = &props->devices[i];
+ break;
+ }
+ }
+ }
+
+ if (desc != NULL && props->identify_state != NULL)
+ props->identify_state(udev,props,&desc,cold);
+
+ return desc;
+}
+
+/*
+ * USB
+ */
+int dvb_usb_device_init(struct usb_interface *intf, struct dvb_usb_properties *props, struct module *owner)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct dvb_usb_device *d = NULL;
+ struct dvb_usb_device_description *desc = NULL;
+
+ int ret = -ENOMEM,cold=0;
+
+ if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+ deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
+ return -ENODEV;
+ }
+
+ if (cold) {
+ info("found a '%s' in cold state, will try to load a firmware",desc->name);
+ ret = usb_cypress_load_firmware(udev,props->firmware,props->usb_ctrl);
+ } else {
+ info("found a '%s' in warm state.",desc->name);
+ d = kmalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+ if (d == NULL) {
+ err("no memory for 'struct dvb_usb_device'");
+ return ret;
+ }
+ memset(d,0,sizeof(struct dvb_usb_device));
+
+ d->udev = udev;
+ memcpy(&d->props,props,sizeof(struct dvb_usb_properties));
+ d->desc = desc;
+ d->owner = owner;
+
+ if (d->props.size_of_priv > 0) {
+ d->priv = kmalloc(d->props.size_of_priv,GFP_KERNEL);
+ if (d->priv == NULL) {
+ err("no memory for priv in 'struct dvb_usb_device'");
+ kfree(d);
+ return -ENOMEM;
+ }
+ memset(d->priv,0,d->props.size_of_priv);
+ }
+
+ usb_set_intfdata(intf, d);
+
+ ret = dvb_usb_init(d);
+ }
+
+ if (ret == 0)
+ info("%s successfully initialized and connected.",desc->name);
+ else
+ info("%s error while loading driver (%d)",desc->name,ret);
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usb_device_init);
+
+void dvb_usb_device_exit(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ const char *name = "generic DVB-USB module";
+
+ usb_set_intfdata(intf,NULL);
+ if (d != NULL && d->desc != NULL) {
+ name = d->desc->name;
+ dvb_usb_exit(d);
+ }
+ info("%s successfully deinitialized and disconnected.",name);
+
+}
+EXPORT_SYMBOL(dvb_usb_device_exit);
+
+/* module stuff */
+static int __init dvb_usb_module_init(void)
+{
+ return 0;
+}
+
+static void __exit dvb_usb_module_exit(void)
+{
+}
+
+module_init (dvb_usb_module_init);
+module_exit (dvb_usb_module_exit);
+
+MODULE_VERSION("0.3");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("A library module containing commonly used USB and DVB function USB DVB devices");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
new file mode 100644
index 000000000000..fc7800f1743e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -0,0 +1,181 @@
+/* dvb-usb-remote.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing the the input-device and for handling remote-control-queries.
+ */
+#include "dvb-usb-common.h"
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(void *data)
+{
+ struct dvb_usb_device *d = data;
+ u32 event;
+ int state;
+
+ /* TODO: need a lock here. We can simply skip checking for the remote control
+ if we're busy. */
+
+ /* when the parameter has been set to 1 via sysfs while the driver was running */
+ if (dvb_usb_disable_rc_polling)
+ return;
+
+ if (d->props.rc_query(d,&event,&state)) {
+ err("error while querying for an remote control event.");
+ goto schedule;
+ }
+
+
+ switch (state) {
+ case REMOTE_NO_KEY_PRESSED:
+ break;
+ case REMOTE_KEY_PRESSED:
+ deb_rc("key pressed\n");
+ d->last_event = event;
+ case REMOTE_KEY_REPEAT:
+ deb_rc("key repeated\n");
+ input_event(&d->rc_input_dev, EV_KEY, d->last_event, 1);
+ input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
+ input_sync(&d->rc_input_dev);
+ break;
+ default:
+ break;
+ }
+
+/* improved repeat handling ???
+ switch (state) {
+ case REMOTE_NO_KEY_PRESSED:
+ deb_rc("NO KEY PRESSED\n");
+ if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+ deb_rc("releasing event %d\n",d->last_event);
+ input_event(&d->rc_input_dev, EV_KEY, d->last_event, 0);
+ input_sync(&d->rc_input_dev);
+ }
+ d->last_state = REMOTE_NO_KEY_PRESSED;
+ d->last_event = 0;
+ break;
+ case REMOTE_KEY_PRESSED:
+ deb_rc("KEY PRESSED\n");
+ deb_rc("pressing event %d\n",event);
+
+ input_event(&d->rc_input_dev, EV_KEY, event, 1);
+ input_sync(&d->rc_input_dev);
+
+ d->last_event = event;
+ d->last_state = REMOTE_KEY_PRESSED;
+ break;
+ case REMOTE_KEY_REPEAT:
+ deb_rc("KEY_REPEAT\n");
+ if (d->last_state != REMOTE_NO_KEY_PRESSED) {
+ deb_rc("repeating event %d\n",d->last_event);
+ input_event(&d->rc_input_dev, EV_KEY, d->last_event, 2);
+ input_sync(&d->rc_input_dev);
+ d->last_state = REMOTE_KEY_REPEAT;
+ }
+ default:
+ break;
+ }
+*/
+
+schedule:
+ schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+}
+
+int dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+ int i;
+ if (d->props.rc_key_map == NULL ||
+ d->props.rc_query == NULL ||
+ dvb_usb_disable_rc_polling)
+ return 0;
+
+ /* Initialise the remote-control structures.*/
+ init_input_dev(&d->rc_input_dev);
+
+ d->rc_input_dev.evbit[0] = BIT(EV_KEY);
+ d->rc_input_dev.keycodesize = sizeof(unsigned char);
+ d->rc_input_dev.keycodemax = KEY_MAX;
+ d->rc_input_dev.name = "IR-receiver inside an USB DVB receiver";
+
+ /* set the bits for the keys */
+ deb_rc("key map size: %d\n",d->props.rc_key_map_size);
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ deb_rc("setting bit for event %d item %d\n",d->props.rc_key_map[i].event, i);
+ set_bit(d->props.rc_key_map[i].event, d->rc_input_dev.keybit);
+ }
+
+ /* Start the remote-control polling. */
+ if (d->props.rc_interval < 40)
+ d->props.rc_interval = 100; /* default */
+
+ /* setting these two values to non-zero, we have to manage key repeats */
+ d->rc_input_dev.rep[REP_PERIOD] = d->props.rc_interval;
+ d->rc_input_dev.rep[REP_DELAY] = d->props.rc_interval + 150;
+
+ input_register_device(&d->rc_input_dev);
+
+ INIT_WORK(&d->rc_query_work, dvb_usb_read_remote_control, d);
+
+ info("schedule remote query interval to %d msecs.",d->props.rc_interval);
+ schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+
+ d->state |= DVB_USB_STATE_REMOTE;
+
+ return 0;
+}
+
+int dvb_usb_remote_exit(struct dvb_usb_device *d)
+{
+ if (d->state & DVB_USB_STATE_REMOTE) {
+ cancel_delayed_work(&d->rc_query_work);
+ flush_scheduled_work();
+ input_unregister_device(&d->rc_input_dev);
+ }
+ d->state &= ~DVB_USB_STATE_REMOTE;
+ return 0;
+}
+
+#define DVB_USB_RC_NEC_EMPTY 0x00
+#define DVB_USB_RC_NEC_KEY_PRESSED 0x01
+#define DVB_USB_RC_NEC_KEY_REPEATED 0x02
+int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
+ u8 keybuf[5], u32 *event, int *state)
+{
+ int i;
+ struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ *event = 0;
+ *state = REMOTE_NO_KEY_PRESSED;
+ switch (keybuf[0]) {
+ case DVB_USB_RC_NEC_EMPTY:
+ break;
+ case DVB_USB_RC_NEC_KEY_PRESSED:
+ if ((u8) ~keybuf[1] != keybuf[2] ||
+ (u8) ~keybuf[3] != keybuf[4]) {
+ deb_err("remote control checksum failed.\n");
+ break;
+ }
+ /* See if we can match the raw key code. */
+ for (i = 0; i < d->props.rc_key_map_size; i++)
+ if (keymap[i].custom == keybuf[1] &&
+ keymap[i].data == keybuf[3]) {
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ return 0;
+ }
+ deb_err("key mapping failed - no appropriate key found in keymapping\n");
+ break;
+ case DVB_USB_RC_NEC_KEY_REPEATED:
+ *state = REMOTE_KEY_REPEAT;
+ break;
+ default:
+ deb_err("unkown type of remote status: %d\n",keybuf[0]);
+ break;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(dvb_usb_nec_rc_key_to_event);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-urb.c b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
new file mode 100644
index 000000000000..f5799a4c228e
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-urb.c
@@ -0,0 +1,325 @@
+/* dvb-usb-urb.c is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * This file contains functions for initializing and handling the
+ * USB and URB stuff.
+ */
+#include "dvb-usb-common.h"
+
+int dvb_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen, u8 *rbuf,
+ u16 rlen, int delay_ms)
+{
+ int actlen,ret = -ENOMEM;
+
+ if (d->props.generic_bulk_ctrl_endpoint == 0) {
+ err("endpoint for generic control not specified.");
+ return -EINVAL;
+ }
+
+ if (wbuf == NULL || wlen == 0)
+ return -EINVAL;
+
+ if ((ret = down_interruptible(&d->usb_sem)))
+ return ret;
+
+ deb_xfer(">>> ");
+ debug_dump(wbuf,wlen,deb_xfer);
+
+ ret = usb_bulk_msg(d->udev,usb_sndbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint), wbuf,wlen,&actlen,
+ 2000);
+
+ if (ret)
+ err("bulk message failed: %d (%d/%d)",ret,wlen,actlen);
+ else
+ ret = actlen != wlen ? -1 : 0;
+
+ /* an answer is expected, and no error before */
+ if (!ret && rbuf && rlen) {
+ if (delay_ms)
+ msleep(delay_ms);
+
+ ret = usb_bulk_msg(d->udev,usb_rcvbulkpipe(d->udev,
+ d->props.generic_bulk_ctrl_endpoint),rbuf,rlen,&actlen,
+ 2000);
+
+ if (ret)
+ err("recv bulk message failed: %d",ret);
+ else {
+ deb_xfer("<<< ");
+ debug_dump(rbuf,actlen,deb_xfer);
+ }
+ }
+
+ up(&d->usb_sem);
+ return ret;
+}
+EXPORT_SYMBOL(dvb_usb_generic_rw);
+
+int dvb_usb_generic_write(struct dvb_usb_device *d, u8 *buf, u16 len)
+{
+ return dvb_usb_generic_rw(d,buf,len,NULL,0,0);
+}
+EXPORT_SYMBOL(dvb_usb_generic_write);
+
+
+/* URB stuff for streaming */
+static void dvb_usb_urb_complete(struct urb *urb, struct pt_regs *ptregs)
+{
+ struct dvb_usb_device *d = urb->context;
+ int ptype = usb_pipetype(urb->pipe);
+ int i;
+ u8 *b;
+
+ deb_ts("'%s' urb completed. feedcount: %d, status: %d, length: %d/%d, pack_num: %d, errors: %d\n",
+ ptype == PIPE_ISOCHRONOUS ? "isoc" : "bulk", d->feedcount,
+ urb->status,urb->actual_length,urb->transfer_buffer_length,
+ urb->number_of_packets,urb->error_count);
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ deb_ts("urb completition error %d.", urb->status);
+ break;
+ }
+
+ if (d->feedcount > 0) {
+ if (d->state & DVB_USB_STATE_DVB) {
+ switch (ptype) {
+ case PIPE_ISOCHRONOUS:
+ b = (u8 *) urb->transfer_buffer;
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (urb->iso_frame_desc[i].status != 0)
+ deb_ts("iso frame descriptor has an error: %d\n",urb->iso_frame_desc[i].status);
+ else if (urb->iso_frame_desc[i].actual_length > 0) {
+ dvb_dmx_swfilter(&d->demux,b + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+ urb->iso_frame_desc[i].status = 0;
+ urb->iso_frame_desc[i].actual_length = 0;
+ }
+ debug_dump(b,20,deb_ts);
+ break;
+ case PIPE_BULK:
+ if (urb->actual_length > 0)
+ dvb_dmx_swfilter(&d->demux, (u8 *) urb->transfer_buffer,urb->actual_length);
+ break;
+ default:
+ err("unkown endpoint type in completition handler.");
+ return;
+ }
+ }
+ }
+
+ usb_submit_urb(urb,GFP_ATOMIC);
+}
+
+int dvb_usb_urb_kill(struct dvb_usb_device *d)
+{
+ int i;
+ for (i = 0; i < d->urbs_submitted; i++) {
+ deb_ts("killing URB no. %d.\n",i);
+
+ /* stop the URB */
+ usb_kill_urb(d->urb_list[i]);
+ }
+ d->urbs_submitted = 0;
+ return 0;
+}
+
+int dvb_usb_urb_submit(struct dvb_usb_device *d)
+{
+ int i,ret;
+ for (i = 0; i < d->urbs_initialized; i++) {
+ deb_ts("submitting URB no. %d\n",i);
+ if ((ret = usb_submit_urb(d->urb_list[i],GFP_ATOMIC))) {
+ err("could not submit URB no. %d - get them all back",i);
+ dvb_usb_urb_kill(d);
+ return ret;
+ }
+ d->urbs_submitted++;
+ }
+ return 0;
+}
+
+static int dvb_usb_free_stream_buffers(struct dvb_usb_device *d)
+{
+ if (d->state & DVB_USB_STATE_URB_BUF) {
+ while (d->buf_num) {
+ d->buf_num--;
+ deb_mem("freeing buffer %d\n",d->buf_num);
+ usb_buffer_free(d->udev, d->buf_size,
+ d->buf_list[d->buf_num], d->dma_addr[d->buf_num]);
+ }
+ kfree(d->buf_list);
+ kfree(d->dma_addr);
+ }
+
+ d->state &= ~DVB_USB_STATE_URB_BUF;
+
+ return 0;
+}
+
+static int dvb_usb_allocate_stream_buffers(struct dvb_usb_device *d, int num, unsigned long size)
+{
+ d->buf_num = 0;
+ d->buf_size = size;
+
+ deb_mem("all in all I will use %lu bytes for streaming\n",num*size);
+
+ if ((d->buf_list = kmalloc(num*sizeof(u8 *), GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ if ((d->dma_addr = kmalloc(num*sizeof(dma_addr_t), GFP_ATOMIC)) == NULL) {
+ kfree(d->buf_list);
+ return -ENOMEM;
+ }
+ memset(d->buf_list,0,num*sizeof(u8 *));
+ memset(d->dma_addr,0,num*sizeof(dma_addr_t));
+
+ d->state |= DVB_USB_STATE_URB_BUF;
+
+ for (d->buf_num = 0; d->buf_num < num; d->buf_num++) {
+ deb_mem("allocating buffer %d\n",d->buf_num);
+ if (( d->buf_list[d->buf_num] =
+ usb_buffer_alloc(d->udev, size, SLAB_ATOMIC,
+ &d->dma_addr[d->buf_num]) ) == NULL) {
+ deb_mem("not enough memory for urb-buffer allocation.\n");
+ dvb_usb_free_stream_buffers(d);
+ return -ENOMEM;
+ }
+ deb_mem("buffer %d: %p (dma: %d)\n",d->buf_num,d->buf_list[d->buf_num],d->dma_addr[d->buf_num]);
+ memset(d->buf_list[d->buf_num],0,size);
+ }
+ deb_mem("allocation successful\n");
+
+ return 0;
+}
+
+static int dvb_usb_bulk_urb_init(struct dvb_usb_device *d)
+{
+ int i;
+
+ if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+ d->props.urb.u.bulk.buffersize)) < 0)
+ return i;
+
+ /* allocate the URBs */
+ for (i = 0; i < d->props.urb.count; i++) {
+ if ((d->urb_list[i] = usb_alloc_urb(0,GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ usb_fill_bulk_urb( d->urb_list[i], d->udev,
+ usb_rcvbulkpipe(d->udev,d->props.urb.endpoint),
+ d->buf_list[i],
+ d->props.urb.u.bulk.buffersize,
+ dvb_usb_urb_complete, d);
+
+ d->urb_list[i]->transfer_flags = 0;
+ d->urbs_initialized++;
+ }
+ return 0;
+}
+
+static int dvb_usb_isoc_urb_init(struct dvb_usb_device *d)
+{
+ int i,j;
+
+ if ((i = dvb_usb_allocate_stream_buffers(d,d->props.urb.count,
+ d->props.urb.u.isoc.framesize*d->props.urb.u.isoc.framesperurb)) < 0)
+ return i;
+
+ /* allocate the URBs */
+ for (i = 0; i < d->props.urb.count; i++) {
+ struct urb *urb;
+ int frame_offset = 0;
+ if ((d->urb_list[i] =
+ usb_alloc_urb(d->props.urb.u.isoc.framesperurb,GFP_ATOMIC)) == NULL)
+ return -ENOMEM;
+
+ urb = d->urb_list[i];
+
+ urb->dev = d->udev;
+ urb->context = d;
+ urb->complete = dvb_usb_urb_complete;
+ urb->pipe = usb_rcvisocpipe(d->udev,d->props.urb.endpoint);
+ urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = d->props.urb.u.isoc.interval;
+ urb->number_of_packets = d->props.urb.u.isoc.framesperurb;
+ urb->transfer_buffer_length = d->buf_size;
+ urb->transfer_buffer = d->buf_list[i];
+ urb->transfer_dma = d->dma_addr[i];
+
+ for (j = 0; j < d->props.urb.u.isoc.framesperurb; j++) {
+ urb->iso_frame_desc[j].offset = frame_offset;
+ urb->iso_frame_desc[j].length = d->props.urb.u.isoc.framesize;
+ frame_offset += d->props.urb.u.isoc.framesize;
+ }
+
+ d->urbs_initialized++;
+ }
+ return 0;
+
+}
+
+int dvb_usb_urb_init(struct dvb_usb_device *d)
+{
+ /*
+ * when reloading the driver w/o replugging the device
+ * sometimes a timeout occures, this helps
+ */
+ if (d->props.generic_bulk_ctrl_endpoint != 0) {
+ usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ }
+ usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.urb.endpoint));
+
+ /* allocate the array for the data transfer URBs */
+ d->urb_list = kmalloc(d->props.urb.count * sizeof(struct urb *),GFP_KERNEL);
+ if (d->urb_list == NULL)
+ return -ENOMEM;
+ memset(d->urb_list,0,d->props.urb.count * sizeof(struct urb *));
+ d->state |= DVB_USB_STATE_URB_LIST;
+
+ switch (d->props.urb.type) {
+ case DVB_USB_BULK:
+ return dvb_usb_bulk_urb_init(d);
+ case DVB_USB_ISOC:
+ return dvb_usb_isoc_urb_init(d);
+ default:
+ err("unkown URB-type for data transfer.");
+ return -EINVAL;
+ }
+}
+
+int dvb_usb_urb_exit(struct dvb_usb_device *d)
+{
+ int i;
+
+ dvb_usb_urb_kill(d);
+
+ if (d->state & DVB_USB_STATE_URB_LIST) {
+ for (i = 0; i < d->urbs_initialized; i++) {
+ if (d->urb_list[i] != NULL) {
+ deb_mem("freeing URB no. %d.\n",i);
+ /* free the URBs */
+ usb_free_urb(d->urb_list[i]);
+ }
+ }
+ d->urbs_initialized = 0;
+ /* free the urb array */
+ kfree(d->urb_list);
+ d->state &= ~DVB_USB_STATE_URB_LIST;
+ }
+
+ dvb_usb_free_stream_buffers(d);
+ return 0;
+}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
new file mode 100644
index 000000000000..a80567caf508
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -0,0 +1,329 @@
+/* dvb-usb.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ * see dvb-usb-init.c for copyright information.
+ *
+ * the headerfile, all dvb-usb-drivers have to include.
+ */
+#ifndef __DVB_USB_H__
+#define __DVB_USB_H__
+
+#include <linux/config.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+
+#include "dvb-pll.h"
+
+#include "dvb-usb-ids.h"
+
+/* debug */
+#ifdef CONFIG_DVB_USB_DEBUG
+#define dprintk(var,level,args...) \
+ do { if ((var & level)) { printk(args); } } while (0)
+
+#define debug_dump(b,l,func) {\
+ int loop_; \
+ for (loop_ = 0; loop_ < l; loop_++) func("%02x ", b[loop_]); \
+ func("\n");\
+}
+#define DVB_USB_DEBUG_STATUS
+#else
+#define dprintk(args...)
+#define debug_dump(b,l,func)
+
+#define DVB_USB_DEBUG_STATUS " (debugging is not enabled)"
+
+#endif
+
+/* generic log methods - taken from usb.h */
+#ifndef DVB_USB_LOG_PREFIX
+ #define DVB_USB_LOG_PREFIX "dvb-usb (please define a log prefix)"
+#endif
+
+#undef err
+#define err(format, arg...) printk(KERN_ERR DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING DVB_USB_LOG_PREFIX ": " format "\n" , ## arg)
+
+/**
+ * struct dvb_usb_device_description - name and its according USB IDs
+ * @name: real name of the box, regardless which DVB USB device class is in use
+ * @cold_ids: array of struct usb_device_id which describe the device in
+ * pre-firmware state
+ * @warm_ids: array of struct usb_device_id which describe the device in
+ * post-firmware state
+ *
+ * Each DVB USB device class can have one or more actual devices, this struct
+ * assigns a name to it.
+ */
+struct dvb_usb_device_description {
+ const char *name;
+
+#define DVB_USB_ID_MAX_NUM 15
+ struct usb_device_id *cold_ids[DVB_USB_ID_MAX_NUM];
+ struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
+};
+
+/**
+ * struct dvb_usb_rc_key - a remote control key and its input-event
+ * @custom: the vendor/custom part of the key
+ * @data: the actual key part
+ * @event: the input event assigned to key identified by custom and data
+ */
+struct dvb_usb_rc_key {
+ u8 custom,data;
+ u32 event;
+};
+
+struct dvb_usb_device;
+
+/**
+ * struct dvb_usb_properties - properties of a dvb-usb-device
+ * @caps: capabilites of the DVB USB device.
+ * @pid_filter_count: number of PID filter position in the optional hardware
+ * PID-filter.
+ *
+ * @usb_ctrl: which USB device-side controller is in use. Needed for firmware
+ * download.
+ * @firmware: name of the firmware file.
+ *
+ * @size_of_priv: how many bytes shall be allocated for the private field
+ * of struct dvb_usb_device.
+ *
+ * @power_ctrl: called to enable/disable power of the device.
+ * @streaming_crtl: called to start and stop the MPEG2-TS streaming of the
+ * device (not URB submitting/killing).
+ * @pid_filter_ctrl: called to en/disable the PID filter, if any.
+ * @pid_filter: called to set/unset a PID for filtering.
+ *
+ * @read_mac_address: called to read the MAC address of the device.
+ *
+ * @frontend_attach: called to attach the possible frontends (fill fe-field
+ * of struct dvb_usb_device).
+ * @tuner_attach: called to attach the correct tuner and to fill pll_addr,
+ * pll_desc and pll_init_buf of struct dvb_usb_device).
+ * @identify_state: called to determine the state (cold or warm), when it
+ * is not distinguishable by the USB IDs.
+ *
+ * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
+ * remote control handling).
+ * @rc_key_map_size: number of items in @rc_key_map.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ *
+ * @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
+ *
+ * @generic_bulk_ctrl_endpoint: most of the DVB USB devices have a generic
+ * endpoint which received control messages with bulk transfers. When this
+ * is non-zero, one can use dvb_usb_generic_rw and dvb_usb_generic_write-
+ * helper functions.
+ *
+ * @urb: describes the kind of USB transfer used for MPEG2-TS-streaming.
+ * Currently only BULK is implemented
+ *
+ * @num_device_descs: number of struct dvb_usb_device_description in @devices
+ * @devices: array of struct dvb_usb_device_description compatibles with these
+ * properties.
+ */
+struct dvb_usb_properties {
+
+#define DVB_USB_HAS_PID_FILTER 0x01
+#define DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF 0x02
+#define DVB_USB_NEED_PID_FILTERING 0x04
+#define DVB_USB_IS_AN_I2C_ADAPTER 0x08
+ int caps;
+ int pid_filter_count;
+
+#define CYPRESS_AN2135 0
+#define CYPRESS_AN2235 1
+#define CYPRESS_FX2 2
+ int usb_ctrl;
+ const char *firmware;
+
+ int size_of_priv;
+
+ int (*power_ctrl) (struct dvb_usb_device *, int);
+ int (*streaming_ctrl) (struct dvb_usb_device *, int);
+ int (*pid_filter_ctrl) (struct dvb_usb_device *, int);
+ int (*pid_filter) (struct dvb_usb_device *, int, u16, int);
+
+ int (*read_mac_address) (struct dvb_usb_device *, u8 []);
+ int (*frontend_attach) (struct dvb_usb_device *);
+ int (*tuner_attach) (struct dvb_usb_device *);
+
+ int (*identify_state) (struct usb_device *, struct dvb_usb_properties *,
+ struct dvb_usb_device_description **, int *);
+
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED 0x00
+#define REMOTE_KEY_PRESSED 0x01
+#define REMOTE_KEY_REPEAT 0x02
+ struct dvb_usb_rc_key *rc_key_map;
+ int rc_key_map_size;
+ int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+ int rc_interval;
+
+ struct i2c_algorithm *i2c_algo;
+
+ int generic_bulk_ctrl_endpoint;
+
+ struct {
+#define DVB_USB_BULK 1
+#define DVB_USB_ISOC 2
+ int type;
+ int count;
+ int endpoint;
+
+ union {
+ struct {
+ int buffersize; /* per URB */
+ } bulk;
+ struct {
+ int framesperurb;
+ int framesize;
+ int interval;
+ } isoc;
+ } u;
+ } urb;
+
+ int num_device_descs;
+ struct dvb_usb_device_description devices[9];
+};
+
+
+/**
+ * struct dvb_usb_device - object of a DVB USB device
+ * @props: copy of the struct dvb_usb_properties this device belongs to.
+ * @desc: pointer to the device's struct dvb_usb_device_description.
+ * @state: initialization and runtime state of the device.
+ *
+ * @udev: pointer to the device's struct usb_device.
+ * @urb_list: array of dynamically allocated struct urb for the MPEG2-TS-
+ * streaming.
+ *
+ * @buf_num: number of buffer allocated.
+ * @buf_size: size of each buffer in buf_list.
+ * @buf_list: array containing all allocate buffers for streaming.
+ * @dma_addr: list of dma_addr_t for each buffer in buf_list.
+ *
+ * @urbs_initialized: number of URBs initialized.
+ * @urbs_submitted: number of URBs submitted.
+ *
+ * @feedcount: number of reqested feeds (used for streaming-activation)
+ * @pid_filtering: is hardware pid_filtering used or not.
+ *
+ * @usb_sem: semaphore of USB control messages (reading needs two messages)
+ * @i2c_sem: semaphore for i2c-transfers
+ *
+ * @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
+ * @pll_addr: I2C address of the tuner for programming
+ * @pll_init: array containing the initialization buffer
+ * @pll_desc: pointer to the appropriate struct dvb_pll_desc
+ *
+ * @tuner_pass_ctrl: called to (de)activate tuner passthru of the demod or the board
+ *
+ * @dvb_adap: device's dvb_adapter.
+ * @dmxdev: device's dmxdev.
+ * @demux: device's software demuxer.
+ * @dvb_net: device's dvb_net interfaces.
+ * @dvb_frontend: device's frontend.
+ * @max_feed_count: how many feeds can be handled simultaneously by this
+ * device
+ * @fe_sleep: rerouted frontend-sleep function.
+ * @fe_init: rerouted frontend-init (wakeup) function.
+ * @rc_input_dev: input device for the remote control.
+ * @rc_query_work: struct work_struct frequent rc queries
+ * @last_event: last triggered event
+ * @last_state: last state (no, pressed, repeat)
+ * @owner: owner of the dvb_adapter
+ * @priv: private data of the actual driver (allocate by dvb-usb, size defined
+ * in size_of_priv of dvb_usb_properties).
+ */
+struct dvb_usb_device {
+ struct dvb_usb_properties props;
+ struct dvb_usb_device_description *desc;
+
+#define DVB_USB_STATE_INIT 0x000
+#define DVB_USB_STATE_URB_LIST 0x001
+#define DVB_USB_STATE_URB_BUF 0x002
+#define DVB_USB_STATE_DVB 0x004
+#define DVB_USB_STATE_I2C 0x008
+#define DVB_USB_STATE_REMOTE 0x010
+#define DVB_USB_STATE_URB_SUBMIT 0x020
+ int state;
+
+ /* usb */
+ struct usb_device *udev;
+ struct urb **urb_list;
+
+ int buf_num;
+ unsigned long buf_size;
+ u8 **buf_list;
+ dma_addr_t *dma_addr;
+
+ int urbs_initialized;
+ int urbs_submitted;
+
+ int feedcount;
+ int pid_filtering;
+
+ /* locking */
+ struct semaphore usb_sem;
+
+ /* i2c */
+ struct semaphore i2c_sem;
+ struct i2c_adapter i2c_adap;
+
+ /* tuner programming information */
+ u8 pll_addr;
+ u8 pll_init[4];
+ struct dvb_pll_desc *pll_desc;
+ int (*tuner_pass_ctrl)(struct dvb_frontend *, int, u8);
+
+ /* dvb */
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+ struct dvb_frontend* fe;
+ int max_feed_count;
+
+ int (*fe_sleep) (struct dvb_frontend *);
+ int (*fe_init) (struct dvb_frontend *);
+
+ /* remote control */
+ struct input_dev rc_input_dev;
+ struct work_struct rc_query_work;
+ u32 last_event;
+ int last_state;
+
+ struct module *owner;
+
+ void *priv;
+};
+
+extern int dvb_usb_device_init(struct usb_interface *, struct dvb_usb_properties *, struct module *);
+extern void dvb_usb_device_exit(struct usb_interface *);
+
+/* the generic read/write method for device control */
+extern int dvb_usb_generic_rw(struct dvb_usb_device *, u8 *, u16, u8 *, u16,int);
+extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16);
+
+/* commonly used remote control parsing */
+extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *);
+
+/* commonly used pll init and set functions */
+extern int dvb_usb_pll_init_i2c(struct dvb_frontend *);
+extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]);
+extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *);
+
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
new file mode 100644
index 000000000000..258a92bfbcc7
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -0,0 +1,236 @@
+/* DVB USB framework compliant Linux driver for the Hauppauge WinTV-NOVA-T usb2
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=rc,2=eeprom (|-able))." DVB_USB_DEBUG_STATUS);
+
+#define deb_rc(args...) dprintk(debug,0x01,args)
+#define deb_ee(args...) dprintk(debug,0x02,args)
+
+/* Hauppauge NOVA-T USB2 keys */
+static struct dvb_usb_rc_key haupp_rc_keys [] = {
+ { 0x1e, 0x00, KEY_0 },
+ { 0x1e, 0x01, KEY_1 },
+ { 0x1e, 0x02, KEY_2 },
+ { 0x1e, 0x03, KEY_3 },
+ { 0x1e, 0x04, KEY_4 },
+ { 0x1e, 0x05, KEY_5 },
+ { 0x1e, 0x06, KEY_6 },
+ { 0x1e, 0x07, KEY_7 },
+ { 0x1e, 0x08, KEY_8 },
+ { 0x1e, 0x09, KEY_9 },
+ { 0x1e, 0x0a, KEY_KPASTERISK },
+ { 0x1e, 0x0b, KEY_RED },
+ { 0x1e, 0x0c, KEY_RADIO },
+ { 0x1e, 0x0d, KEY_MENU },
+ { 0x1e, 0x0e, KEY_GRAVE }, /* # */
+ { 0x1e, 0x0f, KEY_MUTE },
+ { 0x1e, 0x10, KEY_VOLUMEUP },
+ { 0x1e, 0x11, KEY_VOLUMEDOWN },
+ { 0x1e, 0x12, KEY_CHANNEL },
+ { 0x1e, 0x14, KEY_UP },
+ { 0x1e, 0x15, KEY_DOWN },
+ { 0x1e, 0x16, KEY_LEFT },
+ { 0x1e, 0x17, KEY_RIGHT },
+ { 0x1e, 0x18, KEY_VIDEO },
+ { 0x1e, 0x19, KEY_AUDIO },
+ { 0x1e, 0x1a, KEY_MEDIA },
+ { 0x1e, 0x1b, KEY_EPG },
+ { 0x1e, 0x1c, KEY_TV },
+ { 0x1e, 0x1e, KEY_NEXT },
+ { 0x1e, 0x1f, KEY_BACK },
+ { 0x1e, 0x20, KEY_CHANNELUP },
+ { 0x1e, 0x21, KEY_CHANNELDOWN },
+ { 0x1e, 0x24, KEY_LAST }, /* Skip backwards */
+ { 0x1e, 0x25, KEY_OK },
+ { 0x1e, 0x29, KEY_BLUE},
+ { 0x1e, 0x2e, KEY_GREEN },
+ { 0x1e, 0x30, KEY_PAUSE },
+ { 0x1e, 0x32, KEY_REWIND },
+ { 0x1e, 0x34, KEY_FASTFORWARD },
+ { 0x1e, 0x35, KEY_PLAY },
+ { 0x1e, 0x36, KEY_STOP },
+ { 0x1e, 0x37, KEY_RECORD },
+ { 0x1e, 0x38, KEY_YELLOW },
+ { 0x1e, 0x3b, KEY_GOTO },
+ { 0x1e, 0x3d, KEY_POWER },
+};
+
+/* Firmware bug? sometimes, when a new key is pressed, the previous pressed key
+ * is delivered. No workaround yet, maybe a new firmware.
+ */
+static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key[5],cmd[2] = { DIBUSB_REQ_POLL_REMOTE, 0x35 }, data,toggle,custom;
+ u16 raw;
+ int i;
+ struct dibusb_state *st = d->priv;
+
+ dvb_usb_generic_rw(d,cmd,2,key,5,0);
+
+ *state = REMOTE_NO_KEY_PRESSED;
+ switch (key[0]) {
+ case DIBUSB_RC_HAUPPAUGE_KEY_PRESSED:
+ raw = ((key[1] << 8) | key[2]) >> 3;
+ toggle = !!(raw & 0x800);
+ data = raw & 0x3f;
+ custom = (raw >> 6) & 0x1f;
+
+ deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
+
+ for (i = 0; i < ARRAY_SIZE(haupp_rc_keys); i++) {
+ deb_rc("c: %x, d: %x\n",haupp_rc_keys[i].data,haupp_rc_keys[i].custom);
+ if (haupp_rc_keys[i].data == data &&
+ haupp_rc_keys[i].custom == custom) {
+ *event = haupp_rc_keys[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ if (st->old_toggle == toggle) {
+ if (st->last_repeat_count++ < 2)
+ *state = REMOTE_NO_KEY_PRESSED;
+ } else {
+ st->last_repeat_count = 0;
+ st->old_toggle = toggle;
+ }
+ break;
+ }
+ }
+
+ break;
+ case DIBUSB_RC_HAUPPAUGE_KEY_EMPTY:
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int nova_t_read_mac_address (struct dvb_usb_device *d, u8 mac[6])
+{
+ int i;
+ u8 b;
+
+ mac[0] = 0x00;
+ mac[1] = 0x0d;
+ mac[2] = 0xfe;
+
+ /* this is a complete guess, but works for my box */
+ for (i = 136; i < 139; i++) {
+ dibusb_read_eeprom_byte(d,i, &b);
+
+ mac[5 - (i - 136)] = b;
+
+/* deb_ee("%02x ",b);
+ if ((i+1) % 16 == 0)
+ deb_ee("\n");*/
+ }
+
+ return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties nova_t_properties;
+
+static int nova_t_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&nova_t_properties,THIS_MODULE);
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id nova_t_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_WINTV_NOVA_T_USB2_WARM) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, nova_t_table);
+
+static struct dvb_usb_properties nova_t_properties = {
+ .caps = DVB_USB_HAS_PID_FILTER | DVB_USB_PID_FILTER_CAN_BE_TURNED_OFF | DVB_USB_IS_AN_I2C_ADAPTER,
+ .pid_filter_count = 32,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-nova-t-usb2-01.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .pid_filter = dibusb_pid_filter,
+ .pid_filter_ctrl = dibusb_pid_filter_ctrl,
+ .power_ctrl = dibusb2_0_power_ctrl,
+ .frontend_attach = dibusb_dib3000mc_frontend_attach,
+ .tuner_attach = dibusb_dib3000mc_tuner_attach,
+ .read_mac_address = nova_t_read_mac_address,
+
+ .rc_interval = 100,
+ .rc_key_map = haupp_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(haupp_rc_keys),
+ .rc_query = nova_t_rc_query,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Hauppauge WinTV-NOVA-T usb2",
+ { &nova_t_table[0], NULL },
+ { &nova_t_table[1], NULL },
+ },
+ }
+};
+
+static struct usb_driver nova_t_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_nova_t_usb2",
+ .probe = nova_t_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = nova_t_table,
+};
+
+/* module stuff */
+static int __init nova_t_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&nova_t_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit nova_t_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&nova_t_driver);
+}
+
+module_init (nova_t_module_init);
+module_exit (nova_t_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Hauppauge WinTV-NOVA-T usb2");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c
new file mode 100644
index 000000000000..2112ac3cf5e2
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/umt-010.c
@@ -0,0 +1,162 @@
+/* DVB USB framework compliant Linux driver for the HanfTek UMT-010 USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * 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.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "dibusb.h"
+
+#include "mt352.h"
+
+static int umt_mt352_demod_init(struct dvb_frontend *fe)
+{
+ static u8 mt352_clock_config[] = { 0x89, 0xb8, 0x2d };
+ static u8 mt352_reset[] = { 0x50, 0x80 };
+ static u8 mt352_mclk_ratio[] = { 0x8b, 0x00 };
+ static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
+ static u8 mt352_agc_cfg[] = { 0x67, 0x10, 0xa0 };
+
+ static u8 mt352_sec_agc_cfg1[] = { 0x6a, 0xff };
+ static u8 mt352_sec_agc_cfg2[] = { 0x6d, 0xff };
+ static u8 mt352_sec_agc_cfg3[] = { 0x70, 0x40 };
+ static u8 mt352_sec_agc_cfg4[] = { 0x7b, 0x03 };
+ static u8 mt352_sec_agc_cfg5[] = { 0x7d, 0x0f };
+
+ static u8 mt352_acq_ctl[] = { 0x53, 0x50 };
+ static u8 mt352_input_freq_1[] = { 0x56, 0x31, 0x06 };
+
+ mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
+ udelay(2000);
+ mt352_write(fe, mt352_reset, sizeof(mt352_reset));
+ mt352_write(fe, mt352_mclk_ratio, sizeof(mt352_mclk_ratio));
+
+ mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
+ mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
+
+ mt352_write(fe, mt352_sec_agc_cfg1, sizeof(mt352_sec_agc_cfg1));
+ mt352_write(fe, mt352_sec_agc_cfg2, sizeof(mt352_sec_agc_cfg2));
+ mt352_write(fe, mt352_sec_agc_cfg3, sizeof(mt352_sec_agc_cfg3));
+ mt352_write(fe, mt352_sec_agc_cfg4, sizeof(mt352_sec_agc_cfg4));
+ mt352_write(fe, mt352_sec_agc_cfg5, sizeof(mt352_sec_agc_cfg5));
+
+ mt352_write(fe, mt352_acq_ctl, sizeof(mt352_acq_ctl));
+ mt352_write(fe, mt352_input_freq_1, sizeof(mt352_input_freq_1));
+
+ return 0;
+}
+
+static int umt_mt352_frontend_attach(struct dvb_usb_device *d)
+{
+ struct mt352_config umt_config;
+
+ memset(&umt_config,0,sizeof(struct mt352_config));
+ umt_config.demod_init = umt_mt352_demod_init;
+ umt_config.demod_address = 0xf;
+ umt_config.pll_set = dvb_usb_pll_set;
+
+ d->fe = mt352_attach(&umt_config, &d->i2c_adap);
+
+ return 0;
+}
+
+static int umt_tuner_attach (struct dvb_usb_device *d)
+{
+ d->pll_addr = 0x61;
+ d->pll_desc = &dvb_pll_tua6034;
+ return 0;
+}
+
+/* USB Driver stuff */
+static struct dvb_usb_properties umt_properties;
+
+static int umt_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ if (dvb_usb_device_init(intf,&umt_properties,THIS_MODULE) == 0)
+ return 0;
+ return -EINVAL;
+}
+
+/* do not change the order of the ID table */
+static struct usb_device_id umt_table [] = {
+/* 00 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_COLD) },
+/* 01 */ { USB_DEVICE(USB_VID_HANFTEK, USB_PID_HANFTEK_UMT_010_WARM) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE (usb, umt_table);
+
+static struct dvb_usb_properties umt_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-umt-010-02.fw",
+
+ .size_of_priv = sizeof(struct dibusb_state),
+
+ .streaming_ctrl = dibusb2_0_streaming_ctrl,
+ .power_ctrl = dibusb_power_ctrl,
+ .frontend_attach = umt_mt352_frontend_attach,
+ .tuner_attach = umt_tuner_attach,
+
+ .i2c_algo = &dibusb_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 20,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 512,
+ }
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Hanftek UMT-010 DVB-T USB2.0",
+ { &umt_table[0], NULL },
+ { &umt_table[1], NULL },
+ },
+ }
+};
+
+static struct usb_driver umt_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_umt_010",
+ .probe = umt_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = umt_table,
+};
+
+/* module stuff */
+static int __init umt_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&umt_driver))) {
+ err("usb_register failed. Error number %d",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit umt_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&umt_driver);
+}
+
+module_init (umt_module_init);
+module_exit (umt_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for HanfTek UMT 010 USB2.0 DVB-T device");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c
new file mode 100644
index 000000000000..2746edfeccba
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c
@@ -0,0 +1,196 @@
+/* DVB frontend part of the Linux driver for TwinhanDTV Alpha/MagicBoxII USB2.0
+ * DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ */
+#include "vp7045.h"
+
+/* It is a Zarlink MT352 within a Samsung Tuner (DNOS404ZH102A) - 040929 - AAT
+ *
+ * Programming is hidden inside the firmware, so set_frontend is very easy.
+ * Even though there is a Firmware command that one can use to access the demod
+ * via its registers. This is used for status information.
+ */
+
+struct vp7045_fe_state {
+ struct dvb_frontend fe;
+ struct dvb_usb_device *d;
+};
+
+
+static int vp7045_fe_read_status(struct dvb_frontend* fe, fe_status_t *status)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ u8 s0 = vp7045_read_reg(state->d,0x00),
+ s1 = vp7045_read_reg(state->d,0x01),
+ s3 = vp7045_read_reg(state->d,0x03);
+
+ *status = 0;
+ if (s0 & (1 << 4))
+ *status |= FE_HAS_CARRIER;
+ if (s0 & (1 << 1))
+ *status |= FE_HAS_VITERBI;
+ if (s0 & (1 << 5))
+ *status |= FE_HAS_LOCK;
+ if (s1 & (1 << 1))
+ *status |= FE_HAS_SYNC;
+ if (s3 & (1 << 6))
+ *status |= FE_HAS_SIGNAL;
+
+ if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) !=
+ (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC))
+ *status &= ~FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int vp7045_fe_read_ber(struct dvb_frontend* fe, u32 *ber)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ *ber = (vp7045_read_reg(state->d, 0x0D) << 16) |
+ (vp7045_read_reg(state->d, 0x0E) << 8) |
+ vp7045_read_reg(state->d, 0x0F);
+ return 0;
+}
+
+static int vp7045_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ *unc = (vp7045_read_reg(state->d, 0x10) << 8) |
+ vp7045_read_reg(state->d, 0x11);
+ return 0;
+}
+
+static int vp7045_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ u16 signal = (vp7045_read_reg(state->d, 0x14) << 8) |
+ vp7045_read_reg(state->d, 0x15);
+
+ *strength = ~signal;
+ return 0;
+}
+
+static int vp7045_fe_read_snr(struct dvb_frontend* fe, u16 *snr)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ u8 _snr = vp7045_read_reg(state->d, 0x09);
+ *snr = (_snr << 8) | _snr;
+ return 0;
+}
+
+static int vp7045_fe_init(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int vp7045_fe_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int vp7045_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 800;
+ return 0;
+}
+
+static int vp7045_fe_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ u8 buf[5];
+ u32 freq = fep->frequency / 1000;
+
+ buf[0] = (freq >> 16) & 0xff;
+ buf[1] = (freq >> 8) & 0xff;
+ buf[2] = freq & 0xff;
+ buf[3] = 0;
+
+ switch (fep->u.ofdm.bandwidth) {
+ case BANDWIDTH_8_MHZ: buf[4] = 8; break;
+ case BANDWIDTH_7_MHZ: buf[4] = 7; break;
+ case BANDWIDTH_6_MHZ: buf[4] = 6; break;
+ case BANDWIDTH_AUTO: return -EOPNOTSUPP;
+ default:
+ return -EINVAL;
+ }
+
+ vp7045_usb_op(state->d,LOCK_TUNER_COMMAND,buf,5,NULL,0,200);
+ return 0;
+}
+
+static int vp7045_fe_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *fep)
+{
+ return 0;
+}
+
+static void vp7045_fe_release(struct dvb_frontend* fe)
+{
+ struct vp7045_fe_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops vp7045_fe_ops;
+
+struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d)
+{
+ struct vp7045_fe_state *s = kmalloc(sizeof(struct vp7045_fe_state), GFP_KERNEL);
+ if (s == NULL)
+ goto error;
+ memset(s,0,sizeof(struct vp7045_fe_state));
+
+ s->d = d;
+ s->fe.ops = &vp7045_fe_ops;
+ s->fe.demodulator_priv = s;
+
+ goto success;
+error:
+ return NULL;
+success:
+ return &s->fe;
+}
+
+
+static struct dvb_frontend_ops vp7045_fe_ops = {
+ .info = {
+ .name = "Twinhan VP7045/46 USB DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 44250000,
+ .frequency_max = 867250000,
+ .frequency_stepsize = 1000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = vp7045_fe_release,
+
+ .init = vp7045_fe_init,
+ .sleep = vp7045_fe_sleep,
+
+ .set_frontend = vp7045_fe_set_frontend,
+ .get_frontend = vp7045_fe_get_frontend,
+ .get_tune_settings = vp7045_fe_get_tune_settings,
+
+ .read_status = vp7045_fe_read_status,
+ .read_ber = vp7045_fe_read_ber,
+ .read_signal_strength = vp7045_fe_read_signal_strength,
+ .read_snr = vp7045_fe_read_snr,
+ .read_ucblocks = vp7045_fe_read_unc_blocks,
+};
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
new file mode 100644
index 000000000000..9ac95f54f9fc
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -0,0 +1,288 @@
+/* DVB USB compliant Linux driver for the
+ * - TwinhanDTV Alpha/MagicBoxII USB2.0 DVB-T receiver
+ * - DigitalNow TinyUSB2 DVB-t receiver
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "vp7045.h"
+
+/* debug */
+int dvb_usb_vp7045_debug;
+module_param_named(debug,dvb_usb_vp7045_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS);
+
+int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen, int msec)
+{
+ int ret = 0;
+ u8 inbuf[12] = { 0 }, outbuf[20] = { 0 };
+
+ outbuf[0] = cmd;
+
+ if (outlen > 19)
+ outlen = 19;
+
+ if (inlen > 11)
+ inlen = 11;
+
+ if (out != NULL && outlen > 0)
+ memcpy(&outbuf[1], out, outlen);
+
+ deb_xfer("out buffer: ");
+ debug_dump(outbuf,outlen+1,deb_xfer);
+
+ if ((ret = down_interruptible(&d->usb_sem)))
+ return ret;
+
+ if (usb_control_msg(d->udev,
+ usb_sndctrlpipe(d->udev,0),
+ TH_COMMAND_OUT, USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0,
+ outbuf, 20, 2000) != 20) {
+ err("USB control message 'out' went wrong.");
+ ret = -EIO;
+ goto unlock;
+ }
+
+ msleep(msec);
+
+ if (usb_control_msg(d->udev,
+ usb_rcvctrlpipe(d->udev,0),
+ TH_COMMAND_IN, USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+ inbuf, 12, 2000) != 12) {
+ err("USB control message 'in' went wrong.");
+ ret = -EIO;
+ goto unlock;
+ }
+
+ deb_xfer("in buffer: ");
+ debug_dump(inbuf,12,deb_xfer);
+
+ if (in != NULL && inlen > 0)
+ memcpy(in,&inbuf[1],inlen);
+
+unlock:
+ up(&d->usb_sem);
+
+ return ret;
+}
+
+u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg)
+{
+ u8 obuf[2] = { 0 },v;
+ obuf[1] = reg;
+
+ vp7045_usb_op(d,TUNER_REG_READ,obuf,2,&v,1,30);
+
+ return v;
+}
+
+static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ u8 v = onoff;
+ return vp7045_usb_op(d,SET_TUNER_POWER,&v,1,NULL,0,150);
+}
+
+/* remote control stuff */
+
+/* The keymapping struct. Somehow this should be loaded to the driver, but
+ * currently it is hardcoded. */
+static struct dvb_usb_rc_key vp7045_rc_keys[] = {
+ { 0x00, 0x16, KEY_POWER },
+ { 0x00, 0x10, KEY_MUTE },
+ { 0x00, 0x03, KEY_1 },
+ { 0x00, 0x01, KEY_2 },
+ { 0x00, 0x06, KEY_3 },
+ { 0x00, 0x09, KEY_4 },
+ { 0x00, 0x1d, KEY_5 },
+ { 0x00, 0x1f, KEY_6 },
+ { 0x00, 0x0d, KEY_7 },
+ { 0x00, 0x19, KEY_8 },
+ { 0x00, 0x1b, KEY_9 },
+ { 0x00, 0x15, KEY_0 },
+ { 0x00, 0x05, KEY_CHANNELUP },
+ { 0x00, 0x02, KEY_CHANNELDOWN },
+ { 0x00, 0x1e, KEY_VOLUMEUP },
+ { 0x00, 0x0a, KEY_VOLUMEDOWN },
+ { 0x00, 0x11, KEY_RECORD },
+ { 0x00, 0x17, KEY_FAVORITES }, /* Heart symbol - Channel list. */
+ { 0x00, 0x14, KEY_PLAY },
+ { 0x00, 0x1a, KEY_STOP },
+ { 0x00, 0x40, KEY_REWIND },
+ { 0x00, 0x12, KEY_FASTFORWARD },
+ { 0x00, 0x0e, KEY_PREVIOUS }, /* Recall - Previous channel. */
+ { 0x00, 0x4c, KEY_PAUSE },
+ { 0x00, 0x4d, KEY_SCREEN }, /* Full screen mode. */
+ { 0x00, 0x54, KEY_AUDIO }, /* MTS - Switch to secondary audio. */
+ { 0x00, 0x0c, KEY_CANCEL }, /* Cancel */
+ { 0x00, 0x1c, KEY_EPG }, /* EPG */
+ { 0x00, 0x00, KEY_TAB }, /* Tab */
+ { 0x00, 0x48, KEY_INFO }, /* Preview */
+ { 0x00, 0x04, KEY_LIST }, /* RecordList */
+ { 0x00, 0x0f, KEY_TEXT } /* Teletext */
+};
+
+static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+{
+ u8 key;
+ int i;
+ vp7045_usb_op(d,RC_VAL_READ,NULL,0,&key,1,20);
+
+ deb_rc("remote query key: %x %d\n",key,key);
+
+ if (key == 0x44) {
+ *state = REMOTE_NO_KEY_PRESSED;
+ return 0;
+ }
+
+ for (i = 0; i < sizeof(vp7045_rc_keys)/sizeof(struct dvb_usb_rc_key); i++)
+ if (vp7045_rc_keys[i].data == key) {
+ *state = REMOTE_KEY_PRESSED;
+ *event = vp7045_rc_keys[i].event;
+ break;
+ }
+ return 0;
+}
+
+static int vp7045_read_eeprom(struct dvb_usb_device *d,u8 *buf, int len, int offset)
+{
+ int i = 0;
+ u8 v,br[2];
+ for (i=0; i < len; i++) {
+ v = offset + i;
+ vp7045_usb_op(d,GET_EE_VALUE,&v,1,br,2,5);
+ buf[i] = br[1];
+ }
+ deb_info("VP7045 EEPROM read (offs: %d, len: %d) : ",offset, i);
+ debug_dump(buf,i,deb_info);
+ return 0;
+}
+
+
+static int vp7045_read_mac_addr(struct dvb_usb_device *d,u8 mac[6])
+{
+ return vp7045_read_eeprom(d,mac, 6, MAC_0_ADDR);
+}
+
+static int vp7045_frontend_attach(struct dvb_usb_device *d)
+{
+ u8 buf[255] = { 0 };
+
+ vp7045_usb_op(d,VENDOR_STRING_READ,NULL,0,buf,20,0);
+ buf[10] = '\0';
+ deb_info("firmware says: %s ",buf);
+
+ vp7045_usb_op(d,PRODUCT_STRING_READ,NULL,0,buf,20,0);
+ buf[10] = '\0';
+ deb_info("%s ",buf);
+
+ vp7045_usb_op(d,FW_VERSION_READ,NULL,0,buf,20,0);
+ buf[10] = '\0';
+ deb_info("v%s\n",buf);
+
+/* Dump the EEPROM */
+/* vp7045_read_eeprom(d,buf, 255, FX2_ID_ADDR); */
+
+ d->fe = vp7045_fe_attach(d);
+
+ return 0;
+}
+
+static struct dvb_usb_properties vp7045_properties;
+
+static int vp7045_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return dvb_usb_device_init(intf,&vp7045_properties,THIS_MODULE);
+}
+
+static struct usb_device_id vp7045_usb_table [] = {
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_COLD) },
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_TWINHAN_VP7045_WARM) },
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_COLD) },
+ { USB_DEVICE(USB_VID_VISIONPLUS, USB_PID_DNTV_TINYUSB2_WARM) },
+ { 0 },
+};
+MODULE_DEVICE_TABLE(usb, vp7045_usb_table);
+
+static struct dvb_usb_properties vp7045_properties = {
+ .caps = 0,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-vp7045-01.fw",
+
+ .power_ctrl = vp7045_power_ctrl,
+ .frontend_attach = vp7045_frontend_attach,
+ .read_mac_address = vp7045_read_mac_addr,
+
+ .rc_interval = 400,
+ .rc_key_map = vp7045_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(vp7045_rc_keys),
+ .rc_query = vp7045_rc_query,
+
+ /* parameter for the MPEG2-data transfer */
+ .urb = {
+ .type = DVB_USB_BULK,
+ .count = 7,
+ .endpoint = 0x02,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+ }
+ }
+ },
+
+ .num_device_descs = 2,
+ .devices = {
+ { .name = "Twinhan USB2.0 DVB-T receiver (TwinhanDTV Alpha/MagicBox II)",
+ .cold_ids = { &vp7045_usb_table[0], NULL },
+ .warm_ids = { &vp7045_usb_table[1], NULL },
+ },
+ { .name = "DigitalNow TinyUSB 2 DVB-t Receiver",
+ .cold_ids = { &vp7045_usb_table[2], NULL },
+ .warm_ids = { &vp7045_usb_table[3], NULL },
+ },
+ { 0 },
+ }
+};
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver vp7045_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = "dvb_usb_vp7045",
+ .probe = vp7045_usb_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = vp7045_usb_table,
+};
+
+/* module stuff */
+static int __init vp7045_usb_module_init(void)
+{
+ int result;
+ if ((result = usb_register(&vp7045_usb_driver))) {
+ err("usb_register failed. (%d)",result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit vp7045_usb_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&vp7045_usb_driver);
+}
+
+module_init(vp7045_usb_module_init);
+module_exit(vp7045_usb_module_exit);
+
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_DESCRIPTION("Driver for Twinhan MagicBox/Alpha and DNTV tinyUSB2 DVB-T USB2.0");
+MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/vp7045.h b/drivers/media/dvb/dvb-usb/vp7045.h
new file mode 100644
index 000000000000..9ce21a20fa86
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/vp7045.h
@@ -0,0 +1,78 @@
+/* Common header-file of the Linux driver for the TwinhanDTV Alpha/MagicBoxII
+ * USB2.0 DVB-T receiver.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de)
+ *
+ * Thanks to Twinhan who kindly provided hardware and 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, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_VP7045_H_
+#define _DVB_USB_VP7045_H_
+
+#define DVB_USB_LOG_PREFIX "vp7045"
+#include "dvb-usb.h"
+
+extern int dvb_usb_vp7045_debug;
+#define deb_info(args...) dprintk(dvb_usb_vp7045_debug,0x01,args)
+#define deb_xfer(args...) dprintk(dvb_usb_vp7045_debug,0x02,args)
+#define deb_rc(args...) dprintk(dvb_usb_vp7045_debug,0x04,args)
+
+/* vp7045 commands */
+
+/* Twinhan Vendor requests */
+#define TH_COMMAND_IN 0xC0
+#define TH_COMMAND_OUT 0xC1
+
+/* command bytes */
+#define TUNER_REG_READ 0x03
+#define TUNER_REG_WRITE 0x04
+
+#define RC_VAL_READ 0x05
+ #define RC_NO_KEY 0x44
+
+#define SET_TUNER_POWER 0x06
+#define CHECK_TUNER_POWER 0x12
+ #define Tuner_Power_ON 1
+ #define Tuner_Power_OFF 0
+
+#define GET_USB_SPEED 0x07
+ #define USB_SPEED_LOW 0
+ #define USB_SPEED_FULL 1
+ #define USB_SPEED_HIGH 2
+
+#define LOCK_TUNER_COMMAND 0x09
+
+#define TUNER_SIGNAL_READ 0x0A
+
+/* FX2 eeprom */
+#define SET_EE_VALUE 0x10
+#define GET_EE_VALUE 0x11
+ #define FX2_ID_ADDR 0x00
+ #define VID_MSB_ADDR 0x02
+ #define VID_LSB_ADDR 0x01
+ #define PID_MSB_ADDR 0x04
+ #define PID_LSB_ADDR 0x03
+ #define MAC_0_ADDR 0x07
+ #define MAC_1_ADDR 0x08
+ #define MAC_2_ADDR 0x09
+ #define MAC_3_ADDR 0x0a
+ #define MAC_4_ADDR 0x0b
+ #define MAC_5_ADDR 0x0c
+
+#define RESET_FX2 0x13
+
+#define FW_VERSION_READ 0x0B
+#define VENDOR_STRING_READ 0x0C
+#define PRODUCT_STRING_READ 0x0D
+#define FW_BCD_VERSION_READ 0x14
+
+extern struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d);
+extern int vp7045_usb_op(struct dvb_usb_device *d, u8 cmd, u8 *out, int outlen, u8 *in, int inlen,int msec);
+extern u8 vp7045_read_reg(struct dvb_usb_device *d, u8 reg);
+
+#endif
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 75fb556ec01f..d847c62bd837 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -40,6 +40,12 @@ config DVB_VES1X93
help
A DVB-S tuner module. Say Y when you want to support this frontend.
+config DVB_S5H1420
+ tristate "Samsung S5H1420 based"
+ depends on DVB_CORE
+ help
+ A DVB-S tuner module. Say Y when you want to support this frontend.
+
comment "DVB-T (terrestrial) frontends"
depends on DVB_CORE
@@ -173,4 +179,19 @@ config DVB_OR51132
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_BCM3510
+ tristate "Broadcom BCM3510"
+ depends on DVB_CORE
+ select FW_LOADER
+ help
+ An ATSC 8VSB/16VSB and QAM64/256 tuner module. Say Y when you want to
+ support this frontend.
+
+config DVB_LGDT3302
+ tristate "LGDT3302 based (DViCO FusionHDTV3 Gold)"
+ depends on DVB_CORE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
endmenu
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 7f8784870eab..de5e240cba7f 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -28,3 +28,6 @@ obj-$(CONFIG_DVB_STV0297) += stv0297.o
obj-$(CONFIG_DVB_NXT2002) += nxt2002.o
obj-$(CONFIG_DVB_OR51211) += or51211.o
obj-$(CONFIG_DVB_OR51132) += or51132.o
+obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
+obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
+obj-$(CONFIG_DVB_LGDT3302) += lgdt3302.o
diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c
new file mode 100644
index 000000000000..f5fdc5c3e605
--- /dev/null
+++ b/drivers/media/dvb/frontends/bcm3510.c
@@ -0,0 +1,853 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ * Copyright (C) 2001-5, B2C2 inc.
+ *
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * This driver is "hard-coded" to be used with the 1st generation of
+ * Technisat/B2C2's Air2PC ATSC PCI/USB cards/boxes. The pll-programming
+ * (Panasonic CT10S) is located here, which is actually wrong. Unless there is
+ * another device with a BCM3510, this is no problem.
+ *
+ * The driver works also with QAM64 DVB-C, but had an unreasonable high
+ * UNC. (Tested with the Air2PC ATSC 1st generation)
+ *
+ * You'll need a firmware for this driver in order to get it running. It is
+ * called "dvb-fe-bcm3510-01.fw".
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+
+#include "dvb_frontend.h"
+#include "bcm3510.h"
+#include "bcm3510_priv.h"
+
+struct bcm3510_state {
+
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+ const struct bcm3510_config* config;
+ struct dvb_frontend frontend;
+
+ /* demodulator private data */
+ struct semaphore hab_sem;
+ u8 firmware_loaded:1;
+
+ unsigned long next_status_check;
+ unsigned long status_check_interval;
+ struct bcm3510_hab_cmd_status1 status1;
+ struct bcm3510_hab_cmd_status2 status2;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c (|-able)).");
+
+#define dprintk(level,x...) if (level & debug) printk(x)
+#define dbufout(b,l,m) {\
+ int i; \
+ for (i = 0; i < l; i++) \
+ m("%02x ",b[i]); \
+}
+#define deb_info(args...) dprintk(0x01,args)
+#define deb_i2c(args...) dprintk(0x02,args)
+#define deb_hab(args...) dprintk(0x04,args)
+
+/* transfer functions */
+static int bcm3510_writebytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+ u8 b[256];
+ int err;
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = len + 1 };
+
+ b[0] = reg;
+ memcpy(&b[1],buf,len);
+
+ deb_i2c("i2c wr %02x: ",reg);
+ dbufout(buf,len,deb_i2c);
+ deb_i2c("\n");
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+
+ deb_info("%s: i2c write error (addr %02x, reg %02x, err == %i)\n",
+ __FUNCTION__, state->config->demod_address, reg, err);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int bcm3510_readbytes (struct bcm3510_state *state, u8 reg, u8 *buf, u8 len)
+{
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = buf, .len = len }
+ };
+ int err;
+
+ memset(buf,0,len);
+
+ if ((err = i2c_transfer (state->i2c, msg, 2)) != 2) {
+ deb_info("%s: i2c read error (addr %02x, reg %02x, err == %i)\n",
+ __FUNCTION__, state->config->demod_address, reg, err);
+ return -EREMOTEIO;
+ }
+ deb_i2c("i2c rd %02x: ",reg);
+ dbufout(buf,len,deb_i2c);
+ deb_i2c("\n");
+
+ return 0;
+}
+
+static int bcm3510_writeB(struct bcm3510_state *state, u8 reg, bcm3510_register_value v)
+{
+ return bcm3510_writebytes(state,reg,&v.raw,1);
+}
+
+static int bcm3510_readB(struct bcm3510_state *state, u8 reg, bcm3510_register_value *v)
+{
+ return bcm3510_readbytes(state,reg,&v->raw,1);
+}
+
+/* Host Access Buffer transfers */
+static int bcm3510_hab_get_response(struct bcm3510_state *st, u8 *buf, int len)
+{
+ bcm3510_register_value v;
+ int ret,i;
+
+ v.HABADR_a6.HABADR = 0;
+ if ((ret = bcm3510_writeB(st,0xa6,v)) < 0)
+ return ret;
+
+ for (i = 0; i < len; i++) {
+ if ((ret = bcm3510_readB(st,0xa7,&v)) < 0)
+ return ret;
+ buf[i] = v.HABDATA_a7;
+ }
+ return 0;
+}
+
+static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len)
+{
+ bcm3510_register_value v,hab;
+ int ret,i;
+ unsigned long t;
+
+/* Check if any previous HAB request still needs to be serviced by the
+ * Aquisition Processor before sending new request */
+ if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+ return ret;
+ if (v.HABSTAT_a8.HABR) {
+ deb_info("HAB is running already - clearing it.\n");
+ v.HABSTAT_a8.HABR = 0;
+ bcm3510_writeB(st,0xa8,v);
+// return -EBUSY;
+ }
+
+/* Send the start HAB Address (automatically incremented after write of
+ * HABDATA) and write the HAB Data */
+ hab.HABADR_a6.HABADR = 0;
+ if ((ret = bcm3510_writeB(st,0xa6,hab)) < 0)
+ return ret;
+
+ for (i = 0; i < len; i++) {
+ hab.HABDATA_a7 = buf[i];
+ if ((ret = bcm3510_writeB(st,0xa7,hab)) < 0)
+ return ret;
+ }
+
+/* Set the HABR bit to indicate AP request in progress (LBHABR allows HABR to
+ * be written) */
+ v.raw = 0; v.HABSTAT_a8.HABR = 1; v.HABSTAT_a8.LDHABR = 1;
+ if ((ret = bcm3510_writeB(st,0xa8,v)) < 0)
+ return ret;
+
+/* Polling method: Wait until the AP finishes processing the HAB request */
+ t = jiffies + 1*HZ;
+ while (time_before(jiffies, t)) {
+ deb_info("waiting for HAB to complete\n");
+ msleep(10);
+ if ((ret = bcm3510_readB(st,0xa8,&v)) < 0)
+ return ret;
+
+ if (!v.HABSTAT_a8.HABR)
+ return 0;
+ }
+
+ deb_info("send_request execution timed out.\n");
+ return -ETIMEDOUT;
+}
+
+static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen)
+{
+ u8 ob[olen+2],ib[ilen+2];
+ int ret = 0;
+
+ ob[0] = cmd;
+ ob[1] = msgid;
+ memcpy(&ob[2],obuf,olen);
+
+ deb_hab("hab snd: ");
+ dbufout(ob,olen+2,deb_hab);
+ deb_hab("\n");
+
+ if (down_interruptible(&st->hab_sem) < 0)
+ return -EAGAIN;
+
+ if ((ret = bcm3510_hab_send_request(st, ob, olen+2)) < 0 ||
+ (ret = bcm3510_hab_get_response(st, ib, ilen+2)) < 0)
+ goto error;
+
+ deb_hab("hab get: ");
+ dbufout(ib,ilen+2,deb_hab);
+ deb_hab("\n");
+
+ memcpy(ibuf,&ib[2],ilen);
+error:
+ up(&st->hab_sem);
+ return ret;
+}
+
+#if 0
+/* not needed, we use a semaphore to prevent HAB races */
+static int bcm3510_is_ap_ready(struct bcm3510_state *st)
+{
+ bcm3510_register_value ap,hab;
+ int ret;
+
+ if ((ret = bcm3510_readB(st,0xa8,&hab)) < 0 ||
+ (ret = bcm3510_readB(st,0xa2,&ap) < 0))
+ return ret;
+
+ if (ap.APSTAT1_a2.RESET || ap.APSTAT1_a2.IDLE || ap.APSTAT1_a2.STOP || hab.HABSTAT_a8.HABR) {
+ deb_info("AP is busy\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+#endif
+
+static int bcm3510_bert_reset(struct bcm3510_state *st)
+{
+ bcm3510_register_value b;
+ int ret;
+
+ if ((ret < bcm3510_readB(st,0xfa,&b)) < 0)
+ return ret;
+
+ b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+ b.BERCTL_fa.RESYNC = 1; bcm3510_writeB(st,0xfa,b);
+ b.BERCTL_fa.RESYNC = 0; bcm3510_writeB(st,0xfa,b);
+ b.BERCTL_fa.CNTCTL = 1; b.BERCTL_fa.BITCNT = 1; bcm3510_writeB(st,0xfa,b);
+
+ /* clear residual bit counter TODO */
+ return 0;
+}
+
+static int bcm3510_refresh_state(struct bcm3510_state *st)
+{
+ if (time_after(jiffies,st->next_status_check)) {
+ bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS1, NULL,0, (u8 *)&st->status1, sizeof(st->status1));
+ bcm3510_do_hab_cmd(st, CMD_STATUS, MSGID_STATUS2, NULL,0, (u8 *)&st->status2, sizeof(st->status2));
+ st->next_status_check = jiffies + (st->status_check_interval*HZ)/1000;
+ }
+ return 0;
+}
+
+static int bcm3510_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ bcm3510_refresh_state(st);
+
+ *status = 0;
+ if (st->status1.STATUS1.RECEIVER_LOCK)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+
+ if (st->status1.STATUS1.FEC_LOCK)
+ *status |= FE_HAS_VITERBI;
+
+ if (st->status1.STATUS1.OUT_PLL_LOCK)
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+ if (*status & FE_HAS_LOCK)
+ st->status_check_interval = 1500;
+ else /* more frequently checks if no lock has been achieved yet */
+ st->status_check_interval = 500;
+
+ deb_info("real_status: %02x\n",*status);
+ return 0;
+}
+
+static int bcm3510_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ bcm3510_refresh_state(st);
+
+ *ber = (st->status2.LDBER0 << 16) | (st->status2.LDBER1 << 8) | st->status2.LDBER2;
+ return 0;
+}
+
+static int bcm3510_read_unc(struct dvb_frontend* fe, u32* unc)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ bcm3510_refresh_state(st);
+ *unc = (st->status2.LDUERC0 << 8) | st->status2.LDUERC1;
+ return 0;
+}
+
+static int bcm3510_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ s32 t;
+
+ bcm3510_refresh_state(st);
+ t = st->status2.SIGNAL;
+
+ if (t > 190)
+ t = 190;
+ if (t < 90)
+ t = 90;
+
+ t -= 90;
+ t = t * 0xff / 100;
+ /* normalize if necessary */
+ *strength = (t << 8) | t;
+ return 0;
+}
+
+static int bcm3510_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ bcm3510_refresh_state(st);
+
+ *snr = st->status1.SNR_EST0*1000 + ((st->status1.SNR_EST1*1000) >> 8);
+ return 0;
+}
+
+/* tuner frontend programming */
+static int bcm3510_tuner_cmd(struct bcm3510_state* st,u8 bc, u16 n, u8 a)
+{
+ struct bcm3510_hab_cmd_tune c;
+ memset(&c,0,sizeof(struct bcm3510_hab_cmd_tune));
+
+/* I2C Mode disabled, set 16 control / Data pairs */
+ c.length = 0x10;
+ c.clock_width = 0;
+/* CS1, CS0, DATA, CLK bits control the tuner RF_AGC_SEL pin is set to
+ * logic high (as Configuration) */
+ c.misc = 0x10;
+/* Set duration of the initial state of TUNCTL = 3.34 micro Sec */
+ c.TUNCTL_state = 0x40;
+
+/* PRESCALER DEVIDE RATIO | BC1_2_3_4; (band switch), 1stosc REFERENCE COUNTER REF_S12 and REF_S11 */
+ c.ctl_dat[0].ctrl.size = BITS_8;
+ c.ctl_dat[0].data = 0x80 | bc;
+
+/* Control DATA pin, 1stosc REFERENCE COUNTER REF_S10 to REF_S3 */
+ c.ctl_dat[1].ctrl.size = BITS_8;
+ c.ctl_dat[1].data = 4;
+
+/* set CONTROL BIT 1 to 1, 1stosc REFERENCE COUNTER REF_S2 to REF_S1 */
+ c.ctl_dat[2].ctrl.size = BITS_3;
+ c.ctl_dat[2].data = 0x20;
+
+/* control CS0 pin, pulse byte ? */
+ c.ctl_dat[3].ctrl.size = BITS_3;
+ c.ctl_dat[3].ctrl.clk_off = 1;
+ c.ctl_dat[3].ctrl.cs0 = 1;
+ c.ctl_dat[3].data = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+ c.ctl_dat[4].ctrl.size = BITS_8;
+ c.ctl_dat[4].data = n >> 3;
+
+/* PGM_S10 to PGM_S8, SWL_S7 to SWL_S3 */
+ c.ctl_dat[5].ctrl.size = BITS_8;
+ c.ctl_dat[5].data = ((n & 0x7) << 5) | (a >> 2);
+
+/* SWL_S2 and SWL_S1, set CONTROL BIT 2 to 0 */
+ c.ctl_dat[6].ctrl.size = BITS_3;
+ c.ctl_dat[6].data = (a << 6) & 0xdf;
+
+/* control CS0 pin, pulse byte ? */
+ c.ctl_dat[7].ctrl.size = BITS_3;
+ c.ctl_dat[7].ctrl.clk_off = 1;
+ c.ctl_dat[7].ctrl.cs0 = 1;
+ c.ctl_dat[7].data = 0x40;
+
+/* PRESCALER DEVIDE RATIO, 2ndosc REFERENCE COUNTER REF_S12 and REF_S11 */
+ c.ctl_dat[8].ctrl.size = BITS_8;
+ c.ctl_dat[8].data = 0x80;
+
+/* 2ndosc REFERENCE COUNTER REF_S10 to REF_S3 */
+ c.ctl_dat[9].ctrl.size = BITS_8;
+ c.ctl_dat[9].data = 0x10;
+
+/* set CONTROL BIT 1 to 1, 2ndosc REFERENCE COUNTER REF_S2 to REF_S1 */
+ c.ctl_dat[10].ctrl.size = BITS_3;
+ c.ctl_dat[10].data = 0x20;
+
+/* pulse byte */
+ c.ctl_dat[11].ctrl.size = BITS_3;
+ c.ctl_dat[11].ctrl.clk_off = 1;
+ c.ctl_dat[11].ctrl.cs1 = 1;
+ c.ctl_dat[11].data = 0x40;
+
+/* PGM_S18 to PGM_S11 */
+ c.ctl_dat[12].ctrl.size = BITS_8;
+ c.ctl_dat[12].data = 0x2a;
+
+/* PGM_S10 to PGM_S8 and SWL_S7 to SWL_S3 */
+ c.ctl_dat[13].ctrl.size = BITS_8;
+ c.ctl_dat[13].data = 0x8e;
+
+/* SWL_S2 and SWL_S1 and set CONTROL BIT 2 to 0 */
+ c.ctl_dat[14].ctrl.size = BITS_3;
+ c.ctl_dat[14].data = 0;
+
+/* Pulse Byte */
+ c.ctl_dat[15].ctrl.size = BITS_3;
+ c.ctl_dat[15].ctrl.clk_off = 1;
+ c.ctl_dat[15].ctrl.cs1 = 1;
+ c.ctl_dat[15].data = 0x40;
+
+ return bcm3510_do_hab_cmd(st,CMD_TUNE, MSGID_TUNE,(u8 *) &c,sizeof(c), NULL, 0);
+}
+
+static int bcm3510_set_freq(struct bcm3510_state* st,u32 freq)
+{
+ u8 bc,a;
+ u16 n;
+ s32 YIntercept,Tfvco1;
+
+ freq /= 1000;
+
+ deb_info("%dkHz:",freq);
+ /* set Band Switch */
+ if (freq <= 168000)
+ bc = 0x1c;
+ else if (freq <= 378000)
+ bc = 0x2c;
+ else
+ bc = 0x30;
+
+ if (freq >= 470000) {
+ freq -= 470001;
+ YIntercept = 18805;
+ } else if (freq >= 90000) {
+ freq -= 90001;
+ YIntercept = 15005;
+ } else if (freq >= 76000){
+ freq -= 76001;
+ YIntercept = 14865;
+ } else {
+ freq -= 54001;
+ YIntercept = 14645;
+ }
+
+ Tfvco1 = (((freq/6000)*60 + YIntercept)*4)/10;
+
+ n = Tfvco1 >> 6;
+ a = Tfvco1 & 0x3f;
+
+ deb_info(" BC1_2_3_4: %x, N: %x A: %x\n", bc, n, a);
+ if (n >= 16 && n <= 2047)
+ return bcm3510_tuner_cmd(st,bc,n,a);
+
+ return -EINVAL;
+}
+
+static int bcm3510_set_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ struct bcm3510_hab_cmd_ext_acquire cmd;
+ struct bcm3510_hab_cmd_bert_control bert;
+ int ret;
+
+ memset(&cmd,0,sizeof(cmd));
+ switch (p->u.vsb.modulation) {
+ case QAM_256:
+ cmd.ACQUIRE0.MODE = 0x1;
+ cmd.ACQUIRE1.SYM_RATE = 0x1;
+ cmd.ACQUIRE1.IF_FREQ = 0x1;
+ break;
+ case QAM_64:
+ cmd.ACQUIRE0.MODE = 0x2;
+ cmd.ACQUIRE1.SYM_RATE = 0x2;
+ cmd.ACQUIRE1.IF_FREQ = 0x1;
+ break;
+/* case QAM_256:
+ cmd.ACQUIRE0.MODE = 0x3;
+ break;
+ case QAM_128:
+ cmd.ACQUIRE0.MODE = 0x4;
+ break;
+ case QAM_64:
+ cmd.ACQUIRE0.MODE = 0x5;
+ break;
+ case QAM_32:
+ cmd.ACQUIRE0.MODE = 0x6;
+ break;
+ case QAM_16:
+ cmd.ACQUIRE0.MODE = 0x7;
+ break;*/
+ case VSB_8:
+ cmd.ACQUIRE0.MODE = 0x8;
+ cmd.ACQUIRE1.SYM_RATE = 0x0;
+ cmd.ACQUIRE1.IF_FREQ = 0x0;
+ break;
+ case VSB_16:
+ cmd.ACQUIRE0.MODE = 0x9;
+ cmd.ACQUIRE1.SYM_RATE = 0x0;
+ cmd.ACQUIRE1.IF_FREQ = 0x0;
+ default:
+ return -EINVAL;
+ };
+ cmd.ACQUIRE0.OFFSET = 0;
+ cmd.ACQUIRE0.NTSCSWEEP = 1;
+ cmd.ACQUIRE0.FA = 1;
+ cmd.ACQUIRE0.BW = 0;
+
+/* if (enableOffset) {
+ cmd.IF_OFFSET0 = xx;
+ cmd.IF_OFFSET1 = xx;
+
+ cmd.SYM_OFFSET0 = xx;
+ cmd.SYM_OFFSET1 = xx;
+ if (enableNtscSweep) {
+ cmd.NTSC_OFFSET0;
+ cmd.NTSC_OFFSET1;
+ }
+ } */
+ bcm3510_do_hab_cmd(st, CMD_ACQUIRE, MSGID_EXT_TUNER_ACQUIRE, (u8 *) &cmd, sizeof(cmd), NULL, 0);
+
+/* doing it with different MSGIDs, data book and source differs */
+ bert.BE = 0;
+ bert.unused = 0;
+ bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_CONTROL, (u8 *) &bert, sizeof(bert), NULL, 0);
+ bcm3510_do_hab_cmd(st, CMD_STATE_CONTROL, MSGID_BERT_SET, (u8 *) &bert, sizeof(bert), NULL, 0);
+
+ bcm3510_bert_reset(st);
+
+ if ((ret = bcm3510_set_freq(st,p->frequency)) < 0)
+ return ret;
+
+ memset(&st->status1,0,sizeof(st->status1));
+ memset(&st->status2,0,sizeof(st->status2));
+ st->status_check_interval = 500;
+
+/* Give the AP some time */
+ msleep(200);
+
+ return 0;
+}
+
+static int bcm3510_sleep(struct dvb_frontend* fe)
+{
+ return 0;
+}
+
+static int bcm3510_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 1000;
+ s->step_size = 0;
+ s->max_drift = 0;
+ return 0;
+}
+
+static void bcm3510_release(struct dvb_frontend* fe)
+{
+ struct bcm3510_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+/* firmware download:
+ * firmware file is build up like this:
+ * 16bit addr, 16bit length, 8byte of length
+ */
+#define BCM3510_DEFAULT_FIRMWARE "dvb-fe-bcm3510-01.fw"
+
+static int bcm3510_write_ram(struct bcm3510_state *st, u16 addr, u8 *b, u16 len)
+{
+ int ret = 0,i;
+ bcm3510_register_value vH, vL,vD;
+
+ vH.MADRH_a9 = addr >> 8;
+ vL.MADRL_aa = addr;
+ if ((ret = bcm3510_writeB(st,0xa9,vH)) < 0) return ret;
+ if ((ret = bcm3510_writeB(st,0xaa,vL)) < 0) return ret;
+
+ for (i = 0; i < len; i++) {
+ vD.MDATA_ab = b[i];
+ if ((ret = bcm3510_writeB(st,0xab,vD)) < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bcm3510_download_firmware(struct dvb_frontend* fe)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ const struct firmware *fw;
+ u16 addr,len;
+ u8 *b;
+ int ret,i;
+
+ deb_info("requesting firmware\n");
+ if ((ret = st->config->request_firmware(fe, &fw, BCM3510_DEFAULT_FIRMWARE)) < 0) {
+ err("could not load firmware (%s): %d",BCM3510_DEFAULT_FIRMWARE,ret);
+ return ret;
+ }
+ deb_info("got firmware: %d\n",fw->size);
+
+ b = fw->data;
+ for (i = 0; i < fw->size;) {
+ addr = le16_to_cpu( *( (u16 *)&b[i] ) );
+ len = le16_to_cpu( *( (u16 *)&b[i+2] ) );
+ deb_info("firmware chunk, addr: 0x%04x, len: 0x%04x, total length: 0x%04x\n",addr,len,fw->size);
+ if ((ret = bcm3510_write_ram(st,addr,&b[i+4],len)) < 0) {
+ err("firmware download failed: %d\n",ret);
+ return ret;
+ }
+ i += 4 + len;
+ }
+ release_firmware(fw);
+ deb_info("firmware download successfully completed\n");
+ return 0;
+}
+
+static int bcm3510_check_firmware_version(struct bcm3510_state *st)
+{
+ struct bcm3510_hab_cmd_get_version_info ver;
+ bcm3510_do_hab_cmd(st,CMD_GET_VERSION_INFO,MSGID_GET_VERSION_INFO,NULL,0,(u8*)&ver,sizeof(ver));
+
+ deb_info("Version information: 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ ver.microcode_version, ver.script_version, ver.config_version, ver.demod_version);
+
+ if (ver.script_version == BCM3510_DEF_SCRIPT_VERSION &&
+ ver.config_version == BCM3510_DEF_CONFIG_VERSION &&
+ ver.demod_version == BCM3510_DEF_DEMOD_VERSION)
+ return 0;
+
+ deb_info("version check failed\n");
+ return -ENODEV;
+}
+
+/* (un)resetting the AP */
+static int bcm3510_reset(struct bcm3510_state *st)
+{
+ int ret;
+ unsigned long t;
+ bcm3510_register_value v;
+
+ bcm3510_readB(st,0xa0,&v); v.HCTL1_a0.RESET = 1;
+ if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+ return ret;
+
+ t = jiffies + 3*HZ;
+ while (time_before(jiffies, t)) {
+ msleep(10);
+ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+ return ret;
+
+ if (v.APSTAT1_a2.RESET)
+ return 0;
+ }
+ deb_info("reset timed out\n");
+ return -ETIMEDOUT;
+}
+
+static int bcm3510_clear_reset(struct bcm3510_state *st)
+{
+ bcm3510_register_value v;
+ int ret;
+ unsigned long t;
+
+ v.raw = 0;
+ if ((ret = bcm3510_writeB(st,0xa0,v)) < 0)
+ return ret;
+
+ t = jiffies + 3*HZ;
+ while (time_before(jiffies, t)) {
+ msleep(10);
+ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+ return ret;
+
+ /* verify that reset is cleared */
+ if (!v.APSTAT1_a2.RESET)
+ return 0;
+ }
+ deb_info("reset clear timed out\n");
+ return -ETIMEDOUT;
+}
+
+static int bcm3510_init_cold(struct bcm3510_state *st)
+{
+ int ret;
+ bcm3510_register_value v;
+
+ /* read Acquisation Processor status register and check it is not in RUN mode */
+ if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
+ return ret;
+ if (v.APSTAT1_a2.RUN) {
+ deb_info("AP is already running - firmware already loaded.\n");
+ return 0;
+ }
+
+ deb_info("reset?\n");
+ if ((ret = bcm3510_reset(st)) < 0)
+ return ret;
+
+ deb_info("tristate?\n");
+ /* tri-state */
+ v.TSTCTL_2e.CTL = 0;
+ if ((ret = bcm3510_writeB(st,0x2e,v)) < 0)
+ return ret;
+
+ deb_info("firmware?\n");
+ if ((ret = bcm3510_download_firmware(&st->frontend)) < 0 ||
+ (ret = bcm3510_clear_reset(st)) < 0)
+ return ret;
+
+ /* anything left here to Let the acquisition processor begin execution at program counter 0000 ??? */
+
+ return 0;
+}
+
+static int bcm3510_init(struct dvb_frontend* fe)
+{
+ struct bcm3510_state* st = fe->demodulator_priv;
+ bcm3510_register_value j;
+ struct bcm3510_hab_cmd_set_agc c;
+ int ret;
+
+ if ((ret = bcm3510_readB(st,0xca,&j)) < 0)
+ return ret;
+
+ deb_info("JDEC: %02x\n",j.raw);
+
+ switch (j.JDEC_ca.JDEC) {
+ case JDEC_WAIT_AT_RAM:
+ deb_info("attempting to download firmware\n");
+ if ((ret = bcm3510_init_cold(st)) < 0)
+ return ret;
+ case JDEC_EEPROM_LOAD_WAIT: /* fall-through is wanted */
+ deb_info("firmware is loaded\n");
+ bcm3510_check_firmware_version(st);
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ memset(&c,0,1);
+ c.SEL = 1;
+ bcm3510_do_hab_cmd(st,CMD_AUTO_PARAM,MSGID_SET_RF_AGC_SEL,(u8 *)&c,sizeof(c),NULL,0);
+
+ return 0;
+}
+
+
+static struct dvb_frontend_ops bcm3510_ops;
+
+struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct bcm3510_state* state = NULL;
+ int ret;
+ bcm3510_register_value v;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct bcm3510_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+ memset(state,0,sizeof(struct bcm3510_state));
+
+ /* setup the state */
+
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops));
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+
+ sema_init(&state->hab_sem, 1);
+
+ if ((ret = bcm3510_readB(state,0xe0,&v)) < 0)
+ goto error;
+
+ deb_info("Revision: 0x%1x, Layer: 0x%1x.\n",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+ if ((v.REVID_e0.REV != 0x1 && v.REVID_e0.LAYER != 0xb) && /* cold */
+ (v.REVID_e0.REV != 0x8 && v.REVID_e0.LAYER != 0x0)) /* warm */
+ goto error;
+
+ info("Revision: 0x%1x, Layer: 0x%1x.",v.REVID_e0.REV,v.REVID_e0.LAYER);
+
+ bcm3510_reset(state);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(bcm3510_attach);
+
+static struct dvb_frontend_ops bcm3510_ops = {
+
+ .info = {
+ .name = "Broadcom BCM3510 VSB/QAM frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 803000000,
+ /* stepsize is just a guess */
+ .frequency_stepsize = 0,
+ .caps =
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_8VSB | FE_CAN_16VSB |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256
+ },
+
+ .release = bcm3510_release,
+
+ .init = bcm3510_init,
+ .sleep = bcm3510_sleep,
+
+ .set_frontend = bcm3510_set_frontend,
+ .get_tune_settings = bcm3510_get_tune_settings,
+
+ .read_status = bcm3510_read_status,
+ .read_ber = bcm3510_read_ber,
+ .read_signal_strength = bcm3510_read_signal_strength,
+ .read_snr = bcm3510_read_snr,
+ .read_ucblocks = bcm3510_read_unc,
+};
+
+MODULE_DESCRIPTION("Broadcom BCM3510 ATSC (8VSB/16VSB & ITU J83 AnnexB FEC QAM64/256) demodulator driver");
+MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/bcm3510.h b/drivers/media/dvb/frontends/bcm3510.h
new file mode 100644
index 000000000000..80f5d0953d02
--- /dev/null
+++ b/drivers/media/dvb/frontends/bcm3510.h
@@ -0,0 +1,40 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ * Copyright (C) 2001-5, B2C2 inc.
+ *
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * 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.
+ */
+#ifndef BCM3510_H
+#define BCM3510_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct bcm3510_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* request firmware for device */
+ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+};
+
+extern struct dvb_frontend* bcm3510_attach(const struct bcm3510_config* config,
+ struct i2c_adapter* i2c);
+
+#endif
diff --git a/drivers/media/dvb/frontends/bcm3510_priv.h b/drivers/media/dvb/frontends/bcm3510_priv.h
new file mode 100644
index 000000000000..3bb1bc2a04f0
--- /dev/null
+++ b/drivers/media/dvb/frontends/bcm3510_priv.h
@@ -0,0 +1,460 @@
+/*
+ * Support for the Broadcom BCM3510 ATSC demodulator (1st generation Air2PC)
+ *
+ * Copyright (C) 2001-5, B2C2 inc.
+ *
+ * GPL/Linux driver written by Patrick Boettcher <patrick.boettcher@desy.de>
+ *
+ * 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.
+ */
+#ifndef __BCM3510_PRIV_H__
+#define __BCM3510_PRIV_H__
+
+#define PACKED __attribute__((packed))
+
+#undef err
+#define err(format, arg...) printk(KERN_ERR "bcm3510: " format "\n" , ## arg)
+#undef info
+#define info(format, arg...) printk(KERN_INFO "bcm3510: " format "\n" , ## arg)
+#undef warn
+#define warn(format, arg...) printk(KERN_WARNING "bcm3510: " format "\n" , ## arg)
+
+
+#define PANASONIC_FIRST_IF_BASE_IN_KHz 1407500
+#define BCM3510_SYMBOL_RATE 5381000
+
+typedef union {
+ u8 raw;
+
+ struct {
+ u8 CTL :8;
+ } TSTCTL_2e;
+
+ u8 LDCERC_4e;
+ u8 LDUERC_4f;
+ u8 LD_BER0_65;
+ u8 LD_BER1_66;
+ u8 LD_BER2_67;
+ u8 LD_BER3_68;
+
+ struct {
+ u8 RESET :1;
+ u8 IDLE :1;
+ u8 STOP :1;
+ u8 HIRQ0 :1;
+ u8 HIRQ1 :1;
+ u8 na0 :1;
+ u8 HABAV :1;
+ u8 na1 :1;
+ } HCTL1_a0;
+
+ struct {
+ u8 na0 :1;
+ u8 IDLMSK :1;
+ u8 STMSK :1;
+ u8 I0MSK :1;
+ u8 I1MSK :1;
+ u8 na1 :1;
+ u8 HABMSK :1;
+ u8 na2 :1;
+ } HCTLMSK_a1;
+
+ struct {
+ u8 RESET :1;
+ u8 IDLE :1;
+ u8 STOP :1;
+ u8 RUN :1;
+ u8 HABAV :1;
+ u8 MEMAV :1;
+ u8 ALDONE :1;
+ u8 REIRQ :1;
+ } APSTAT1_a2;
+
+ struct {
+ u8 RSTMSK :1;
+ u8 IMSK :1;
+ u8 SMSK :1;
+ u8 RMSK :1;
+ u8 HABMSK :1;
+ u8 MAVMSK :1;
+ u8 ALDMSK :1;
+ u8 REMSK :1;
+ } APMSK1_a3;
+
+ u8 APSTAT2_a4;
+ u8 APMSK2_a5;
+
+ struct {
+ u8 HABADR :7;
+ u8 na :1;
+ } HABADR_a6;
+
+ u8 HABDATA_a7;
+
+ struct {
+ u8 HABR :1;
+ u8 LDHABR :1;
+ u8 APMSK :1;
+ u8 HMSK :1;
+ u8 LDMSK :1;
+ u8 na :3;
+ } HABSTAT_a8;
+
+ u8 MADRH_a9;
+ u8 MADRL_aa;
+ u8 MDATA_ab;
+
+ struct {
+#define JDEC_WAIT_AT_RAM 0x7
+#define JDEC_EEPROM_LOAD_WAIT 0x4
+ u8 JDEC :3;
+ u8 na :5;
+ } JDEC_ca;
+
+ struct {
+ u8 REV :4;
+ u8 LAYER :4;
+ } REVID_e0;
+
+ struct {
+ u8 unk0 :1;
+ u8 CNTCTL :1;
+ u8 BITCNT :1;
+ u8 unk1 :1;
+ u8 RESYNC :1;
+ u8 unk2 :3;
+ } BERCTL_fa;
+
+ struct {
+ u8 CSEL0 :1;
+ u8 CLKED0 :1;
+ u8 CSEL1 :1;
+ u8 CLKED1 :1;
+ u8 CLKLEV :1;
+ u8 SPIVAR :1;
+ u8 na :2;
+ } TUNSET_fc;
+
+ struct {
+ u8 CLK :1;
+ u8 DATA :1;
+ u8 CS0 :1;
+ u8 CS1 :1;
+ u8 AGCSEL :1;
+ u8 na0 :1;
+ u8 TUNSEL :1;
+ u8 na1 :1;
+ } TUNCTL_fd;
+
+ u8 TUNSEL0_fe;
+ u8 TUNSEL1_ff;
+
+} bcm3510_register_value;
+
+/* HAB commands */
+
+/* version */
+#define CMD_GET_VERSION_INFO 0x3D
+#define MSGID_GET_VERSION_INFO 0x15
+struct bcm3510_hab_cmd_get_version_info {
+ u8 microcode_version;
+ u8 script_version;
+ u8 config_version;
+ u8 demod_version;
+} PACKED;
+
+#define BCM3510_DEF_MICROCODE_VERSION 0x0E
+#define BCM3510_DEF_SCRIPT_VERSION 0x06
+#define BCM3510_DEF_CONFIG_VERSION 0x01
+#define BCM3510_DEF_DEMOD_VERSION 0xB1
+
+/* acquire */
+#define CMD_ACQUIRE 0x38
+
+#define MSGID_EXT_TUNER_ACQUIRE 0x0A
+struct bcm3510_hab_cmd_ext_acquire {
+ struct {
+ u8 MODE :4;
+ u8 BW :1;
+ u8 FA :1;
+ u8 NTSCSWEEP :1;
+ u8 OFFSET :1;
+ } PACKED ACQUIRE0; /* control_byte */
+
+ struct {
+ u8 IF_FREQ :3;
+ u8 zero0 :1;
+ u8 SYM_RATE :3;
+ u8 zero1 :1;
+ } PACKED ACQUIRE1; /* sym_if */
+
+ u8 IF_OFFSET0; /* IF_Offset_10hz */
+ u8 IF_OFFSET1;
+ u8 SYM_OFFSET0; /* SymbolRateOffset */
+ u8 SYM_OFFSET1;
+ u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+ u8 NTSC_OFFSET1;
+} PACKED;
+
+#define MSGID_INT_TUNER_ACQUIRE 0x0B
+struct bcm3510_hab_cmd_int_acquire {
+ struct {
+ u8 MODE :4;
+ u8 BW :1;
+ u8 FA :1;
+ u8 NTSCSWEEP :1;
+ u8 OFFSET :1;
+ } PACKED ACQUIRE0; /* control_byte */
+
+ struct {
+ u8 IF_FREQ :3;
+ u8 zero0 :1;
+ u8 SYM_RATE :3;
+ u8 zero1 :1;
+ } PACKED ACQUIRE1; /* sym_if */
+
+ u8 TUNER_FREQ0;
+ u8 TUNER_FREQ1;
+ u8 TUNER_FREQ2;
+ u8 TUNER_FREQ3;
+ u8 IF_OFFSET0; /* IF_Offset_10hz */
+ u8 IF_OFFSET1;
+ u8 SYM_OFFSET0; /* SymbolRateOffset */
+ u8 SYM_OFFSET1;
+ u8 NTSC_OFFSET0; /* NTSC_Offset_10hz */
+ u8 NTSC_OFFSET1;
+} PACKED;
+
+/* modes */
+#define BCM3510_QAM16 = 0x01
+#define BCM3510_QAM32 = 0x02
+#define BCM3510_QAM64 = 0x03
+#define BCM3510_QAM128 = 0x04
+#define BCM3510_QAM256 = 0x05
+#define BCM3510_8VSB = 0x0B
+#define BCM3510_16VSB = 0x0D
+
+/* IF_FREQS */
+#define BCM3510_IF_TERRESTRIAL 0x0
+#define BCM3510_IF_CABLE 0x1
+#define BCM3510_IF_USE_CMD 0x7
+
+/* SYM_RATE */
+#define BCM3510_SR_8VSB 0x0 /* 5381119 s/sec */
+#define BCM3510_SR_256QAM 0x1 /* 5360537 s/sec */
+#define BCM3510_SR_16QAM 0x2 /* 5056971 s/sec */
+#define BCM3510_SR_MISC 0x3 /* 5000000 s/sec */
+#define BCM3510_SR_USE_CMD 0x7
+
+/* special symbol rate */
+#define CMD_SET_VALUE_NOT_LISTED 0x2d
+#define MSGID_SET_SYMBOL_RATE_NOT_LISTED 0x0c
+struct bcm3510_hab_cmd_set_sr_not_listed {
+ u8 HOST_SYM_RATE0;
+ u8 HOST_SYM_RATE1;
+ u8 HOST_SYM_RATE2;
+ u8 HOST_SYM_RATE3;
+} PACKED;
+
+/* special IF */
+#define MSGID_SET_IF_FREQ_NOT_LISTED 0x0d
+struct bcm3510_hab_cmd_set_if_freq_not_listed {
+ u8 HOST_IF_FREQ0;
+ u8 HOST_IF_FREQ1;
+ u8 HOST_IF_FREQ2;
+ u8 HOST_IF_FREQ3;
+} PACKED;
+
+/* auto reacquire */
+#define CMD_AUTO_PARAM 0x2a
+#define MSGID_AUTO_REACQUIRE 0x0e
+struct bcm3510_hab_cmd_auto_reacquire {
+ u8 ACQ :1; /* on/off*/
+ u8 unused :7;
+} PACKED;
+
+#define MSGID_SET_RF_AGC_SEL 0x12
+struct bcm3510_hab_cmd_set_agc {
+ u8 LVL :1;
+ u8 unused :6;
+ u8 SEL :1;
+} PACKED;
+
+#define MSGID_SET_AUTO_INVERSION 0x14
+struct bcm3510_hab_cmd_auto_inversion {
+ u8 AI :1;
+ u8 unused :7;
+} PACKED;
+
+
+/* bert control */
+#define CMD_STATE_CONTROL 0x12
+#define MSGID_BERT_CONTROL 0x0e
+#define MSGID_BERT_SET 0xfa
+struct bcm3510_hab_cmd_bert_control {
+ u8 BE :1;
+ u8 unused :7;
+} PACKED;
+
+#define MSGID_TRI_STATE 0x2e
+struct bcm3510_hab_cmd_tri_state {
+ u8 RE :1; /* a/d ram port pins */
+ u8 PE :1; /* baud clock pin */
+ u8 AC :1; /* a/d clock pin */
+ u8 BE :1; /* baud clock pin */
+ u8 unused :4;
+} PACKED;
+
+
+/* tune */
+#define CMD_TUNE 0x38
+#define MSGID_TUNE 0x16
+struct bcm3510_hab_cmd_tune_ctrl_data_pair {
+ struct {
+#define BITS_8 0x07
+#define BITS_7 0x06
+#define BITS_6 0x05
+#define BITS_5 0x04
+#define BITS_4 0x03
+#define BITS_3 0x02
+#define BITS_2 0x01
+#define BITS_1 0x00
+ u8 size :3;
+ u8 unk :2;
+ u8 clk_off :1;
+ u8 cs0 :1;
+ u8 cs1 :1;
+
+ } PACKED ctrl;
+
+ u8 data;
+} PACKED;
+
+struct bcm3510_hab_cmd_tune {
+ u8 length;
+ u8 clock_width;
+ u8 misc;
+ u8 TUNCTL_state;
+
+ struct bcm3510_hab_cmd_tune_ctrl_data_pair ctl_dat[16];
+} PACKED;
+
+#define CMD_STATUS 0x38
+#define MSGID_STATUS1 0x08
+struct bcm3510_hab_cmd_status1 {
+ struct {
+ u8 EQ_MODE :4;
+ u8 reserved :2;
+ u8 QRE :1; /* if QSE and the spectrum is inversed */
+ u8 QSE :1; /* automatic spectral inversion */
+ } PACKED STATUS0;
+
+ struct {
+ u8 RECEIVER_LOCK :1;
+ u8 FEC_LOCK :1;
+ u8 OUT_PLL_LOCK :1;
+ u8 reserved :5;
+ } PACKED STATUS1;
+
+ struct {
+ u8 reserved :2;
+ u8 BW :1;
+ u8 NTE :1; /* NTSC filter sweep enabled */
+ u8 AQI :1; /* currently acquiring */
+ u8 FA :1; /* fast acquisition */
+ u8 ARI :1; /* auto reacquire */
+ u8 TI :1; /* programming the tuner */
+ } PACKED STATUS2;
+ u8 STATUS3;
+ u8 SNR_EST0;
+ u8 SNR_EST1;
+ u8 TUNER_FREQ0;
+ u8 TUNER_FREQ1;
+ u8 TUNER_FREQ2;
+ u8 TUNER_FREQ3;
+ u8 SYM_RATE0;
+ u8 SYM_RATE1;
+ u8 SYM_RATE2;
+ u8 SYM_RATE3;
+ u8 SYM_OFFSET0;
+ u8 SYM_OFFSET1;
+ u8 SYM_ERROR0;
+ u8 SYM_ERROR1;
+ u8 IF_FREQ0;
+ u8 IF_FREQ1;
+ u8 IF_FREQ2;
+ u8 IF_FREQ3;
+ u8 IF_OFFSET0;
+ u8 IF_OFFSET1;
+ u8 IF_ERROR0;
+ u8 IF_ERROR1;
+ u8 NTSC_FILTER0;
+ u8 NTSC_FILTER1;
+ u8 NTSC_FILTER2;
+ u8 NTSC_FILTER3;
+ u8 NTSC_OFFSET0;
+ u8 NTSC_OFFSET1;
+ u8 NTSC_ERROR0;
+ u8 NTSC_ERROR1;
+ u8 INT_AGC_LEVEL0;
+ u8 INT_AGC_LEVEL1;
+ u8 EXT_AGC_LEVEL0;
+ u8 EXT_AGC_LEVEL1;
+} PACKED;
+
+#define MSGID_STATUS2 0x14
+struct bcm3510_hab_cmd_status2 {
+ struct {
+ u8 EQ_MODE :4;
+ u8 reserved :2;
+ u8 QRE :1;
+ u8 QSR :1;
+ } PACKED STATUS0;
+ struct {
+ u8 RL :1;
+ u8 FL :1;
+ u8 OL :1;
+ u8 reserved :5;
+ } PACKED STATUS1;
+ u8 SYMBOL_RATE0;
+ u8 SYMBOL_RATE1;
+ u8 SYMBOL_RATE2;
+ u8 SYMBOL_RATE3;
+ u8 LDCERC0;
+ u8 LDCERC1;
+ u8 LDCERC2;
+ u8 LDCERC3;
+ u8 LDUERC0;
+ u8 LDUERC1;
+ u8 LDUERC2;
+ u8 LDUERC3;
+ u8 LDBER0;
+ u8 LDBER1;
+ u8 LDBER2;
+ u8 LDBER3;
+ struct {
+ u8 MODE_TYPE :4; /* acquire mode 0 */
+ u8 reservd :4;
+ } MODE_TYPE;
+ u8 SNR_EST0;
+ u8 SNR_EST1;
+ u8 SIGNAL;
+} PACKED;
+
+#define CMD_SET_RF_BW_NOT_LISTED 0x3f
+#define MSGID_SET_RF_BW_NOT_LISTED 0x11
+/* TODO */
+
+#endif
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index f4aa44136c7c..9f639297a9f2 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -76,7 +76,6 @@ static u8 init_tab [] = {
0x49, 0x56,
0x6b, 0x1e,
0xc8, 0x02,
- 0xf8, 0x02,
0xf9, 0x00,
0xfa, 0x00,
0xfb, 0x00,
@@ -203,7 +202,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
struct cx22702_state* state = fe->demodulator_priv;
/* set PLL */
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
if (state->config->pll_set) {
state->config->pll_set(fe, p);
} else if (state->config->pll_desc) {
@@ -217,7 +216,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
} else {
BUG();
}
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
/* set inversion */
cx22702_set_inversion (state, p->inversion);
@@ -256,7 +255,7 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet
cx22702_writereg(state, 0x0B, cx22702_readreg(state, 0x0B) & 0xfc );
cx22702_writereg(state, 0x0C, (cx22702_readreg(state, 0x0C) & 0xBF) | 0x40 );
cx22702_writereg(state, 0x00, 0x01); /* Begin aquisition */
- printk("%s: Autodetecting\n",__FUNCTION__);
+ dprintk("%s: Autodetecting\n",__FUNCTION__);
return 0;
}
@@ -347,10 +346,11 @@ static int cx22702_init (struct dvb_frontend* fe)
for (i=0; i<sizeof(init_tab); i+=2)
cx22702_writereg (state, init_tab[i], init_tab[i+1]);
+ cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
/* init PLL */
if (state->config->pll_init) {
- cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+ cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
state->config->pll_init(fe);
cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
}
@@ -440,8 +440,10 @@ static int cx22702_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
/* RS Uncorrectable Packet Count then reset */
_ucblocks = cx22702_readreg (state, 0xE3);
- if (state->prevUCBlocks < _ucblocks) *ucblocks = (_ucblocks - state->prevUCBlocks);
- else *ucblocks = state->prevUCBlocks - _ucblocks;
+ if (state->prevUCBlocks < _ucblocks)
+ *ucblocks = (_ucblocks - state->prevUCBlocks);
+ else
+ *ucblocks = state->prevUCBlocks - _ucblocks;
state->prevUCBlocks = _ucblocks;
return 0;
@@ -457,6 +459,12 @@ static int cx22702_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
return cx22702_get_tps (state, &p->u.ofdm);
}
+static int cx22702_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
static void cx22702_release(struct dvb_frontend* fe)
{
struct cx22702_state* state = fe->demodulator_priv;
@@ -472,7 +480,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
/* allocate memory for the internal state */
state = kmalloc(sizeof(struct cx22702_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ goto error;
/* setup the state */
state->config = config;
@@ -481,7 +490,8 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config,
state->prevUCBlocks = 0;
/* check if the demod is there */
- if (cx22702_readreg(state, 0x1f) != 0x3) goto error;
+ if (cx22702_readreg(state, 0x1f) != 0x3)
+ goto error;
/* create dvb_frontend */
state->frontend.ops = &state->ops;
@@ -514,6 +524,7 @@ static struct dvb_frontend_ops cx22702_ops = {
.set_frontend = cx22702_set_tps,
.get_frontend = cx22702_get_frontend,
+ .get_tune_settings = cx22702_get_tune_settings,
.read_status = cx22702_read_status,
.read_ber = cx22702_read_ber,
diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h
index 559fdb906669..11f86806756e 100644
--- a/drivers/media/dvb/frontends/cx22702.h
+++ b/drivers/media/dvb/frontends/cx22702.h
@@ -35,6 +35,11 @@ struct cx22702_config
/* the demodulator's i2c address */
u8 demod_address;
+ /* serial/parallel output */
+#define CX22702_PARALLEL_OUTPUT 0
+#define CX22702_SERIAL_OUTPUT 1
+ u8 output_mode;
+
/* PLL maintenance */
u8 pll_address;
struct dvb_pll_desc *pll_desc;
diff --git a/drivers/media/dvb/frontends/dib3000-common.c b/drivers/media/dvb/frontends/dib3000-common.c
index 47ab02e133d1..1a4f1f7c228a 100644
--- a/drivers/media/dvb/frontends/dib3000-common.c
+++ b/drivers/media/dvb/frontends/dib3000-common.c
@@ -73,7 +73,7 @@ u16 dib3000_seq[2][2][2] = /* fft,gua, inv */
};
MODULE_AUTHOR("Patrick Boettcher <patrick.boettcher@desy.de");
-MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb-frontend drivers");
+MODULE_DESCRIPTION("Common functions for the dib3000mb/dib3000mc dvb frontend drivers");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(dib3000_seq);
diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h
index 80687c130836..2d5475b5c063 100644
--- a/drivers/media/dvb/frontends/dib3000.h
+++ b/drivers/media/dvb/frontends/dib3000.h
@@ -32,9 +32,8 @@ struct dib3000_config
u8 demod_address;
/* PLL maintenance and the i2c address of the PLL */
- u8 (*pll_addr)(struct dvb_frontend *fe);
- int (*pll_init)(struct dvb_frontend *fe, u8 pll_buf[5]);
- int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params, u8 pll_buf[5]);
+ int (*pll_init)(struct dvb_frontend *fe);
+ int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params);
};
struct dib_fe_xfer_ops
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index 6f52d649e97e..cd434b7cf9db 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
-static int dib3000mb_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
-
static int dib3000mb_get_frontend(struct dvb_frontend* fe,
struct dvb_frontend_parameters *fep);
@@ -61,10 +59,8 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe,
fe_code_rate_t fe_cr = FEC_NONE;
int search_state, seq;
- if (tuner && state->config.pll_addr && state->config.pll_set) {
- dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
- state->config.pll_set(fe, fep, NULL);
- dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+ if (tuner && state->config.pll_set) {
+ state->config.pll_set(fe, fep);
deb_setf("bandwidth: ");
switch (ofdm->bandwidth) {
@@ -389,11 +385,8 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode)
wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF);
- if (state->config.pll_init) {
- dib3000mb_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
- state->config.pll_init(fe,NULL);
- dib3000mb_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
- }
+ if (state->config.pll_init)
+ state->config.pll_init(fe);
return 0;
}
@@ -623,7 +616,7 @@ static int dib3000mb_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dib3000_state* state = fe->demodulator_priv;
- *unc = rd(DIB3000MB_REG_UNC);
+ *unc = rd(DIB3000MB_REG_PACKET_ERROR_RATE);
return 0;
}
@@ -638,9 +631,6 @@ static int dib3000mb_sleep(struct dvb_frontend* fe)
static int dib3000mb_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
tune->min_delay_ms = 800;
- tune->step_size = 166667;
- tune->max_drift = 166667 * 2;
-
return 0;
}
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 57e61aa5b07b..999b19047816 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -294,7 +294,7 @@ static u16 dib3000mb_reg_filter_coeffs[] = {
static u16 dib3000mb_filter_coeffs[] = {
226, 160, 29,
- 979, 998, 19,
+ 979, 998, 19,
22, 1019, 1006,
1022, 12, 6,
1017, 1017, 3,
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index 888f10a5e96b..cd33705a4320 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -48,8 +48,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe,16=s
#define deb_getf(args...) dprintk(0x08,args)
#define deb_stat(args...) dprintk(0x10,args)
-static int dib3000mc_tuner_pass_ctrl(struct dvb_frontend *fe, int onoff, u8 pll_addr);
-
static int dib3000mc_set_impulse_noise(struct dib3000_state * state, int mode,
fe_transmit_mode_t transmission_mode, fe_bandwidth_t bandwidth)
{
@@ -463,10 +461,8 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
int search_state,auto_val;
u16 val;
- if (tuner && state->config.pll_addr && state->config.pll_set) { /* initial call from dvb */
- dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
- state->config.pll_set(fe,fep,NULL);
- dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
+ if (tuner && state->config.pll_set) { /* initial call from dvb */
+ state->config.pll_set(fe,fep);
state->last_tuned_freq = fep->frequency;
// if (!scanboost) {
@@ -554,19 +550,15 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe,
dib3000mc_set_adp_cfg(state,ofdm->constellation);
wr_foreach(dib3000mc_reg_offset,
dib3000mc_offset[(ofdm->transmission_mode == TRANSMISSION_MODE_8K)+1]);
-
-
}
return 0;
}
static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
{
- struct dib3000_state *state;
-
+ struct dib3000_state *state = fe->demodulator_priv;
deb_info("init start\n");
- state = fe->demodulator_priv;
state->timing_offset = 0;
state->timing_offset_comp_done = 0;
@@ -649,11 +641,9 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode)
set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF);
-/* if (state->config->pll_init) {
- dib3000mc_tuner_pass_ctrl(fe,1,state->config.pll_addr(fe));
- state->config->pll_init(fe,NULL);
- dib3000mc_tuner_pass_ctrl(fe,0,state->config.pll_addr(fe));
- }*/
+ if (state->config.pll_init)
+ state->config.pll_init(fe);
+
deb_info("init end\n");
return 0;
}
@@ -688,7 +678,7 @@ static int dib3000mc_read_unc_blocks(struct dvb_frontend* fe, u32 *unc)
{
struct dib3000_state* state = fe->demodulator_priv;
- *unc = rd(DIB3000MC_REG_PACKET_ERROR_COUNT);
+ *unc = rd(DIB3000MC_REG_PACKET_ERRORS);
return 0;
}
@@ -737,10 +727,7 @@ static int dib3000mc_sleep(struct dvb_frontend* fe)
static int dib3000mc_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
- tune->min_delay_ms = 2000;
- tune->step_size = 166667;
- tune->max_drift = 166667 * 2;
-
+ tune->min_delay_ms = 1000;
return 0;
}
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 2a3c2ce7b2aa..5afeaa9b43b4 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -1,6 +1,4 @@
/*
- * $Id: dvb-pll.c,v 1.7 2005/02/10 11:52:02 kraxel Exp $
- *
* descriptions + helper functions for simple dvb plls.
*
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
@@ -57,7 +55,7 @@ struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
};
EXPORT_SYMBOL(dvb_pll_thomson_dtt7610);
-static void thomson_dtt759x_bw(u8 *buf, int bandwidth)
+static void thomson_dtt759x_bw(u8 *buf, u32 freq, int bandwidth)
{
if (BANDWIDTH_7_MHZ == bandwidth)
buf[3] |= 0x10;
@@ -95,6 +93,32 @@ struct dvb_pll_desc dvb_pll_lg_z201 = {
};
EXPORT_SYMBOL(dvb_pll_lg_z201);
+struct dvb_pll_desc dvb_pll_microtune_4042 = {
+ .name = "Microtune 4042 FI5",
+ .min = 57000000,
+ .max = 858000000,
+ .count = 3,
+ .entries = {
+ { 162000000, 44000000, 62500, 0x8e, 0xa1 },
+ { 457000000, 44000000, 62500, 0x8e, 0x91 },
+ { 999999999, 44000000, 62500, 0x8e, 0x31 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_microtune_4042);
+
+struct dvb_pll_desc dvb_pll_thomson_dtt7611 = {
+ .name = "Thomson dtt7611",
+ .min = 44000000,
+ .max = 958000000,
+ .count = 3,
+ .entries = {
+ { 157250000, 44000000, 62500, 0x8e, 0x39 },
+ { 454000000, 44000000, 62500, 0x8e, 0x3a },
+ { 999999999, 44000000, 62500, 0x8e, 0x3c },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_thomson_dtt7611);
+
struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
@@ -114,6 +138,143 @@ struct dvb_pll_desc dvb_pll_unknown_1 = {
};
EXPORT_SYMBOL(dvb_pll_unknown_1);
+/* Infineon TUA6010XS
+ * used in Thomson Cable Tuner
+ */
+struct dvb_pll_desc dvb_pll_tua6010xs = {
+ .name = "Infineon TUA6010XS",
+ .min = 44250000,
+ .max = 858000000,
+ .count = 3,
+ .entries = {
+ { 115750000, 36125000, 62500, 0x8e, 0x03 },
+ { 403250000, 36125000, 62500, 0x8e, 0x06 },
+ { 999999999, 36125000, 62500, 0x8e, 0x85 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_tua6010xs);
+
+/* Panasonic env57h1xd5 (some Philips PLL ?) */
+struct dvb_pll_desc dvb_pll_env57h1xd5 = {
+ .name = "Panasonic ENV57H1XD5",
+ .min = 44250000,
+ .max = 858000000,
+ .count = 4,
+ .entries = {
+ { 153000000, 36291666, 166666, 0xc2, 0x41 },
+ { 470000000, 36291666, 166666, 0xc2, 0x42 },
+ { 526000000, 36291666, 166666, 0xc2, 0x84 },
+ { 999999999, 36291666, 166666, 0xc2, 0xa4 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_env57h1xd5);
+
+/* Philips TDA6650/TDA6651
+ * used in Panasonic ENV77H11D5
+ */
+static void tda665x_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ if (bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_tda665x = {
+ .name = "Philips TDA6650/TDA6651",
+ .min = 44250000,
+ .max = 858000000,
+ .setbw = tda665x_bw,
+ .count = 12,
+ .entries = {
+ { 93834000, 36249333, 166667, 0xca, 0x61 /* 011 0 0 0 01 */ },
+ { 123834000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
+ { 161000000, 36249333, 166667, 0xca, 0xa1 /* 101 0 0 0 01 */ },
+ { 163834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
+ { 253834000, 36249333, 166667, 0xca, 0x62 /* 011 0 0 0 10 */ },
+ { 383834000, 36249333, 166667, 0xca, 0xa2 /* 101 0 0 0 10 */ },
+ { 443834000, 36249333, 166667, 0xca, 0xc2 /* 110 0 0 0 10 */ },
+ { 444000000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
+ { 583834000, 36249333, 166667, 0xca, 0x63 /* 011 0 0 0 11 */ },
+ { 793834000, 36249333, 166667, 0xca, 0xa3 /* 101 0 0 0 11 */ },
+ { 444834000, 36249333, 166667, 0xca, 0xc3 /* 110 0 0 0 11 */ },
+ { 861000000, 36249333, 166667, 0xca, 0xe3 /* 111 0 0 0 11 */ },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_tda665x);
+
+/* Infineon TUA6034
+ * used in LG TDTP E102P
+ */
+static void tua6034_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ if (BANDWIDTH_7_MHZ != bandwidth)
+ buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_tua6034 = {
+ .name = "Infineon TUA6034",
+ .min = 44250000,
+ .max = 858000000,
+ .count = 3,
+ .setbw = tua6034_bw,
+ .entries = {
+ { 174500000, 36166667, 62500, 0xce, 0x01 },
+ { 230000000, 36166667, 62500, 0xce, 0x02 },
+ { 999999999, 36166667, 62500, 0xce, 0x04 },
+ },
+};
+EXPORT_SYMBOL(dvb_pll_tua6034);
+
+/* Philips FMD1216ME
+ * used in Medion Hybrid PCMCIA card and USB Box
+ */
+static void fmd1216me_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ if (bandwidth == BANDWIDTH_8_MHZ && freq >= 158870000)
+ buf[3] |= 0x08;
+}
+
+struct dvb_pll_desc dvb_pll_fmd1216me = {
+ .name = "Philips FMD1216ME",
+ .min = 50870000,
+ .max = 858000000,
+ .setbw = fmd1216me_bw,
+ .count = 7,
+ .entries = {
+ { 143870000, 36213333, 166667, 0xbc, 0x41 },
+ { 158870000, 36213333, 166667, 0xf4, 0x41 },
+ { 329870000, 36213333, 166667, 0xbc, 0x42 },
+ { 441870000, 36213333, 166667, 0xf4, 0x42 },
+ { 625870000, 36213333, 166667, 0xbc, 0x44 },
+ { 803870000, 36213333, 166667, 0xf4, 0x44 },
+ { 999999999, 36213333, 166667, 0xfc, 0x44 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_fmd1216me);
+
+/* ALPS TDED4
+ * used in Nebula-Cards and USB boxes
+ */
+static void tded4_bw(u8 *buf, u32 freq, int bandwidth)
+{
+ if (bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 0x04;
+}
+
+struct dvb_pll_desc dvb_pll_tded4 = {
+ .name = "ALPS TDED4",
+ .min = 47000000,
+ .max = 863000000,
+ .setbw = tded4_bw,
+ .count = 4,
+ .entries = {
+ { 153000000, 36166667, 166667, 0x85, 0x01 },
+ { 470000000, 36166667, 166667, 0x85, 0x02 },
+ { 823000000, 36166667, 166667, 0x85, 0x08 },
+ { 999999999, 36166667, 166667, 0x85, 0x88 },
+ }
+};
+EXPORT_SYMBOL(dvb_pll_tded4);
+
/* ----------------------------------------------------------- */
/* code */
@@ -147,7 +308,7 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
buf[3] = desc->entries[i].cb2;
if (desc->setbw)
- desc->setbw(buf, bandwidth);
+ desc->setbw(buf, freq, bandwidth);
if (debug)
printk("pll: %s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
@@ -160,9 +321,3 @@ EXPORT_SYMBOL(dvb_pll_configure);
MODULE_DESCRIPTION("dvb pll library");
MODULE_AUTHOR("Gerd Knorr");
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index c4c3c56c4a81..cb794759d89e 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -1,5 +1,5 @@
/*
- * $Id: dvb-pll.h,v 1.2 2005/02/10 11:43:41 kraxel Exp $
+ * descriptions + helper functions for simple dvb plls.
*/
#ifndef __DVB_PLL_H__
@@ -9,7 +9,7 @@ struct dvb_pll_desc {
char *name;
u32 min;
u32 max;
- void (*setbw)(u8 *buf, int bandwidth);
+ void (*setbw)(u8 *buf, u32 freq, int bandwidth);
int count;
struct {
u32 limit;
@@ -17,15 +17,24 @@ struct dvb_pll_desc {
u32 stepsize;
u8 cb1;
u8 cb2;
- } entries[9];
+ } entries[12];
};
extern struct dvb_pll_desc dvb_pll_thomson_dtt7579;
extern struct dvb_pll_desc dvb_pll_thomson_dtt759x;
extern struct dvb_pll_desc dvb_pll_thomson_dtt7610;
extern struct dvb_pll_desc dvb_pll_lg_z201;
+extern struct dvb_pll_desc dvb_pll_microtune_4042;
+extern struct dvb_pll_desc dvb_pll_thomson_dtt7611;
extern struct dvb_pll_desc dvb_pll_unknown_1;
+extern struct dvb_pll_desc dvb_pll_tua6010xs;
+extern struct dvb_pll_desc dvb_pll_env57h1xd5;
+extern struct dvb_pll_desc dvb_pll_tua6034;
+extern struct dvb_pll_desc dvb_pll_tda665x;
+extern struct dvb_pll_desc dvb_pll_fmd1216me;
+extern struct dvb_pll_desc dvb_pll_tded4;
+
int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf,
u32 freq, int bandwidth);
diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c
index 031a1ddc7d11..faaad1ae8559 100644
--- a/drivers/media/dvb/frontends/l64781.c
+++ b/drivers/media/dvb/frontends/l64781.c
@@ -474,11 +474,12 @@ static int l64781_init(struct dvb_frontend* fe)
return 0;
}
-static int l64781_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int l64781_get_tune_settings(struct dvb_frontend* fe,
+ struct dvb_frontend_tune_settings* fesettings)
{
- fesettings->min_delay_ms = 200;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
+ fesettings->min_delay_ms = 4000;
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
diff --git a/drivers/media/dvb/frontends/lgdt3302.c b/drivers/media/dvb/frontends/lgdt3302.c
new file mode 100644
index 000000000000..2eea03d218cd
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.c
@@ -0,0 +1,609 @@
+/*
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * Based on code from Kirk Lapray <kirk_lapray@bigfoot.com>
+ * Copyright (C) 2005
+ *
+ * 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.
+ *
+ */
+
+/*
+ * NOTES ABOUT THIS DRIVER
+ *
+ * This driver supports DViCO FusionHDTV 3 Gold under Linux.
+ *
+ * TODO:
+ * BER and signal strength always return 0.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/byteorder.h>
+
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "lgdt3302_priv.h"
+#include "lgdt3302.h"
+
+static int debug = 0;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug,"Turn on/off lgdt3302 frontend debugging (default:off).");
+#define dprintk(args...) \
+do { \
+if (debug) printk(KERN_DEBUG "lgdt3302: " args); \
+} while (0)
+
+struct lgdt3302_state
+{
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+
+ /* Configuration settings */
+ const struct lgdt3302_config* config;
+
+ struct dvb_frontend frontend;
+
+ /* Demodulator private data */
+ fe_modulation_t current_modulation;
+
+ /* Tuner private data */
+ u32 current_frequency;
+};
+
+static int i2c_writebytes (struct lgdt3302_state* state,
+ u8 addr, /* demod_address or pll_address */
+ u8 *buf, /* data bytes to send */
+ int len /* number of bytes to send */ )
+{
+ if (addr == state->config->pll_address) {
+ struct i2c_msg msg =
+ { .addr = addr, .flags = 0, .buf = buf, .len = len };
+ int err;
+
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+ } else {
+ u8 tmp[] = { buf[0], buf[1] };
+ struct i2c_msg msg =
+ { .addr = addr, .flags = 0, .buf = tmp, .len = 2 };
+ int err;
+ int i;
+
+ for (i=1; i<len; i++) {
+ tmp[1] = buf[i];
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x <- %02x, err == %i)\n", __FUNCTION__, addr, buf[0], err);
+ if (err < 0)
+ return err;
+ else
+ return -EREMOTEIO;
+ }
+ tmp[0]++;
+ }
+ }
+ return 0;
+}
+static int i2c_readbytes (struct lgdt3302_state* state,
+ u8 addr, /* demod_address or pll_address */
+ u8 *buf, /* holds data bytes read */
+ int len /* number of bytes to read */ )
+{
+ struct i2c_msg msg =
+ { .addr = addr, .flags = I2C_M_RD, .buf = buf, .len = len };
+ int err;
+
+ if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
+ printk(KERN_WARNING "lgdt3302: %s error (addr %02x, err == %i)\n", __FUNCTION__, addr, err);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/*
+ * This routine writes the register (reg) to the demod bus
+ * then reads the data returned for (len) bytes.
+ */
+
+static u8 i2c_selectreadbytes (struct lgdt3302_state* state,
+ enum I2C_REG reg, u8* buf, int len)
+{
+ u8 wr [] = { reg };
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address,
+ .flags = 0, .buf = wr, .len = 1 },
+ { .addr = state->config->demod_address,
+ .flags = I2C_M_RD, .buf = buf, .len = len },
+ };
+ int ret;
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret != 2) {
+ printk(KERN_WARNING "lgdt3302: %s: addr 0x%02x select 0x%02x error (ret == %i)\n", __FUNCTION__, state->config->demod_address, reg, ret);
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+/* Software reset */
+int lgdt3302_SwReset(struct lgdt3302_state* state)
+{
+ u8 ret;
+ u8 reset[] = {
+ IRQ_MASK,
+ 0x00 /* bit 6 is active low software reset
+ * bits 5-0 are 1 to mask interrupts */
+ };
+
+ ret = i2c_writebytes(state,
+ state->config->demod_address,
+ reset, sizeof(reset));
+ if (ret == 0) {
+ /* spec says reset takes 100 ns why wait */
+ /* mdelay(100); */ /* keep low for 100mS */
+ reset[1] = 0x7f; /* force reset high (inactive)
+ * and unmask interrupts */
+ ret = i2c_writebytes(state,
+ state->config->demod_address,
+ reset, sizeof(reset));
+ }
+ /* Spec does not indicate a need for this either */
+ /*mdelay(5); */ /* wait 5 msec before doing more */
+ return ret;
+}
+
+static int lgdt3302_init(struct dvb_frontend* fe)
+{
+ /* Hardware reset is done using gpio[0] of cx23880x chip.
+ * I'd like to do it here, but don't know how to find chip address.
+ * cx88-cards.c arranges for the reset bit to be inactive (high).
+ * Maybe there needs to be a callable function in cx88-core or
+ * the caller of this function needs to do it. */
+
+ dprintk("%s entered\n", __FUNCTION__);
+ return lgdt3302_SwReset((struct lgdt3302_state*) fe->demodulator_priv);
+}
+
+static int lgdt3302_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ *ber = 0; /* Dummy out for now */
+ return 0;
+}
+
+static int lgdt3302_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ u8 buf[2];
+
+ i2c_selectreadbytes(state, PACKET_ERR_COUNTER1, buf, sizeof(buf));
+
+ *ucblocks = (buf[0] << 8) | buf[1];
+ return 0;
+}
+
+static int lgdt3302_set_parameters(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters *param)
+{
+ u8 buf[4];
+ struct lgdt3302_state* state =
+ (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* Use 50MHz parameter values from spec sheet since xtal is 50 */
+ static u8 top_ctrl_cfg[] = { TOP_CONTROL, 0x03 };
+ static u8 vsb_freq_cfg[] = { VSB_CARRIER_FREQ0, 0x00, 0x87, 0x8e, 0x01 };
+ static u8 demux_ctrl_cfg[] = { DEMUX_CONTROL, 0xfb };
+ static u8 agc_rf_cfg[] = { AGC_RF_BANDWIDTH0, 0x40, 0x93, 0x00 };
+ static u8 agc_ctrl_cfg[] = { AGC_FUNC_CTRL2, 0xc6, 0x40 };
+ static u8 agc_delay_cfg[] = { AGC_DELAY0, 0x00, 0x00, 0x00 };
+ static u8 agc_loop_cfg[] = { AGC_LOOP_BANDWIDTH0, 0x08, 0x9a };
+
+ /* Change only if we are actually changing the modulation */
+ if (state->current_modulation != param->u.vsb.modulation) {
+ int value;
+
+ switch(param->u.vsb.modulation) {
+ case VSB_8:
+ dprintk("%s: VSB_8 MODE\n", __FUNCTION__);
+
+ /* Select VSB mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x07;
+ break;
+
+ case QAM_64:
+ dprintk("%s: QAM_64 MODE\n", __FUNCTION__);
+
+ /* Select QAM_64 mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x04;
+ break;
+
+ case QAM_256:
+ dprintk("%s: QAM_256 MODE\n", __FUNCTION__);
+
+ /* Select QAM_256 mode and serial MPEG interface */
+ top_ctrl_cfg[1] = 0x05;
+ break;
+ default:
+ printk(KERN_WARNING "lgdt3302: %s: Modulation type(%d) UNSUPPORTED\n", __FUNCTION__, param->u.vsb.modulation);
+ return -1;
+ }
+ /* Initializations common to all modes */
+
+ /* Select the requested mode */
+ i2c_writebytes(state, state->config->demod_address,
+ top_ctrl_cfg, sizeof(top_ctrl_cfg));
+
+ /* Change the value of IFBW[11:0]
+ of AGC IF/RF loop filter bandwidth register */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_rf_cfg, sizeof(agc_rf_cfg));
+
+ /* Change the value of bit 6, 'nINAGCBY' and
+ 'NSSEL[1:0] of ACG function control register 2 */
+ /* Change the value of bit 6 'RFFIX'
+ of AGC function control register 3 */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_ctrl_cfg, sizeof(agc_ctrl_cfg));
+
+ /* Change the TPCLK pin polarity
+ data is valid on falling clock */
+ i2c_writebytes(state, state->config->demod_address,
+ demux_ctrl_cfg, sizeof(demux_ctrl_cfg));
+
+ /* Change the value of NCOCTFV[25:0] of carrier
+ recovery center frequency register */
+ i2c_writebytes(state, state->config->demod_address,
+ vsb_freq_cfg, sizeof(vsb_freq_cfg));
+ /* Set the value of 'INLVTHD' register 0x2a/0x2c
+ to value from 'IFACC' register 0x39/0x3b -1 */
+ i2c_selectreadbytes(state, AGC_RFIF_ACC0,
+ &agc_delay_cfg[1], 3);
+ value = ((agc_delay_cfg[1] & 0x0f) << 8) | agc_delay_cfg[3];
+ value = value -1;
+ dprintk("%s IFACC -1 = 0x%03x\n", __FUNCTION__, value);
+ agc_delay_cfg[1] = (value >> 8) & 0x0f;
+ agc_delay_cfg[2] = 0x00;
+ agc_delay_cfg[3] = value & 0xff;
+ i2c_writebytes(state, state->config->demod_address,
+ agc_delay_cfg, sizeof(agc_delay_cfg));
+
+ /* Change the value of IAGCBW[15:8]
+ of inner AGC loop filter bandwith */
+ i2c_writebytes(state, state->config->demod_address,
+ agc_loop_cfg, sizeof(agc_loop_cfg));
+
+ state->config->set_ts_params(fe, 0);
+ state->current_modulation = param->u.vsb.modulation;
+ }
+
+ /* Change only if we are actually changing the channel */
+ if (state->current_frequency != param->frequency) {
+ dvb_pll_configure(state->config->pll_desc, buf,
+ param->frequency, 0);
+ dprintk("%s: tuner bytes: 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n", __FUNCTION__, buf[0],buf[1],buf[2],buf[3]);
+ i2c_writebytes(state, state->config->pll_address ,buf, 4);
+
+ /* Check the status of the tuner pll */
+ i2c_readbytes(state, state->config->pll_address, buf, 1);
+ dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+
+ /* Update current frequency */
+ state->current_frequency = param->frequency;
+ }
+ lgdt3302_SwReset(state);
+ return 0;
+}
+
+static int lgdt3302_get_frontend(struct dvb_frontend* fe,
+ struct dvb_frontend_parameters* param)
+{
+ struct lgdt3302_state *state = fe->demodulator_priv;
+ param->frequency = state->current_frequency;
+ return 0;
+}
+
+static int lgdt3302_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ u8 buf[3];
+
+ *status = 0; /* Reset status result */
+
+ /* Check the status of the tuner pll */
+ i2c_readbytes(state, state->config->pll_address, buf, 1);
+ dprintk("%s: tuner status byte = 0x%02x\n", __FUNCTION__, buf[0]);
+ if ((buf[0] & 0xc0) != 0x40)
+ return 0; /* Tuner PLL not locked or not powered on */
+
+ /*
+ * You must set the Mask bits to 1 in the IRQ_MASK in order
+ * to see that status bit in the IRQ_STATUS register.
+ * This is done in SwReset();
+ */
+
+ /* AGC status register */
+ i2c_selectreadbytes(state, AGC_STATUS, buf, 1);
+ dprintk("%s: AGC_STATUS = 0x%02x\n", __FUNCTION__, buf[0]);
+ if ((buf[0] & 0x0c) == 0x8){
+ /* Test signal does not exist flag */
+ /* as well as the AGC lock flag. */
+ *status |= FE_HAS_SIGNAL;
+ } else {
+ /* Without a signal all other status bits are meaningless */
+ return 0;
+ }
+
+ /* signal status */
+ i2c_selectreadbytes(state, TOP_CONTROL, buf, sizeof(buf));
+ dprintk("%s: TOP_CONTROL = 0x%02x, IRO_MASK = 0x%02x, IRQ_STATUS = 0x%02x\n", __FUNCTION__, buf[0], buf[1], buf[2]);
+
+#if 0
+ /* Alternative method to check for a signal */
+ /* using the SNR good/bad interrupts. */
+ if ((buf[2] & 0x30) == 0x10)
+ *status |= FE_HAS_SIGNAL;
+#endif
+
+ /* sync status */
+ if ((buf[2] & 0x03) == 0x01) {
+ *status |= FE_HAS_SYNC;
+ }
+
+ /* FEC error status */
+ if ((buf[2] & 0x0c) == 0x08) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI;
+ }
+
+ /* Carrier Recovery Lock Status Register */
+ i2c_selectreadbytes(state, CARRIER_LOCK, buf, 1);
+ dprintk("%s: CARRIER_LOCK = 0x%02x\n", __FUNCTION__, buf[0]);
+ switch (state->current_modulation) {
+ case QAM_256:
+ case QAM_64:
+ /* Need to undestand why there are 3 lock levels here */
+ if ((buf[0] & 0x07) == 0x07)
+ *status |= FE_HAS_CARRIER;
+ break;
+ case VSB_8:
+ if ((buf[0] & 0x80) == 0x80)
+ *status |= FE_HAS_CARRIER;
+ break;
+ default:
+ printk("KERN_WARNING lgdt3302: %s: Modulation set to unsupported value\n", __FUNCTION__);
+ }
+
+ return 0;
+}
+
+static int lgdt3302_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ /* not directly available. */
+ return 0;
+}
+
+static int lgdt3302_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+#ifdef SNR_IN_DB
+ /*
+ * Spec sheet shows formula for SNR_EQ = 10 log10(25 * 24**2 / noise)
+ * and SNR_PH = 10 log10(25 * 32**2 / noise) for equalizer and phase tracker
+ * respectively. The following tables are built on these formulas.
+ * The usual definition is SNR = 20 log10(signal/noise)
+ * If the specification is wrong the value retuned is 1/2 the actual SNR in db.
+ *
+ * This table is a an ordered list of noise values computed by the
+ * formula from the spec sheet such that the index into the table
+ * starting at 43 or 45 is the SNR value in db. There are duplicate noise
+ * value entries at the beginning because the SNR varies more than
+ * 1 db for a change of 1 digit in noise at very small values of noise.
+ *
+ * Examples from SNR_EQ table:
+ * noise SNR
+ * 0 43
+ * 1 42
+ * 2 39
+ * 3 37
+ * 4 36
+ * 5 35
+ * 6 34
+ * 7 33
+ * 8 33
+ * 9 32
+ * 10 32
+ * 11 31
+ * 12 31
+ * 13 30
+ */
+
+ static const u32 SNR_EQ[] =
+ { 1, 2, 2, 2, 3, 3, 4, 4, 5, 7,
+ 9, 11, 13, 17, 21, 26, 33, 41, 52, 65,
+ 81, 102, 129, 162, 204, 257, 323, 406, 511, 644,
+ 810, 1020, 1284, 1616, 2035, 2561, 3224, 4059, 5110, 6433,
+ 8098, 10195, 12835, 16158, 20341, 25608, 32238, 40585, 51094, 64323,
+ 80978, 101945, 128341, 161571, 203406, 256073, 0x40000
+ };
+
+ static const u32 SNR_PH[] =
+ { 1, 2, 2, 2, 3, 3, 4, 5, 6, 8,
+ 10, 12, 15, 19, 23, 29, 37, 46, 58, 73,
+ 91, 115, 144, 182, 229, 288, 362, 456, 574, 722,
+ 909, 1144, 1440, 1813, 2282, 2873, 3617, 4553, 5732, 7216,
+ 9084, 11436, 14396, 18124, 22817, 28724, 36161, 45524, 57312, 72151,
+ 90833, 114351, 143960, 181235, 228161, 0x040000
+ };
+
+ static u8 buf[5];/* read data buffer */
+ static u32 noise; /* noise value */
+ static u32 snr_db; /* index into SNR_EQ[] */
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* read both equalizer and pase tracker noise data */
+ i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+ if (state->current_modulation == VSB_8) {
+ /* Equalizer Mean-Square Error Register for VSB */
+ noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+
+ /*
+ * Look up noise value in table.
+ * A better search algorithm could be used...
+ * watch out there are duplicate entries.
+ */
+ for (snr_db = 0; snr_db < sizeof(SNR_EQ); snr_db++) {
+ if (noise < SNR_EQ[snr_db]) {
+ *snr = 43 - snr_db;
+ break;
+ }
+ }
+ } else {
+ /* Phase Tracker Mean-Square Error Register for QAM */
+ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+
+ /* Look up noise value in table. */
+ for (snr_db = 0; snr_db < sizeof(SNR_PH); snr_db++) {
+ if (noise < SNR_PH[snr_db]) {
+ *snr = 45 - snr_db;
+ break;
+ }
+ }
+ }
+#else
+ /* Return the raw noise value */
+ static u8 buf[5];/* read data buffer */
+ static u32 noise; /* noise value */
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+
+ /* read both equalizer and pase tracker noise data */
+ i2c_selectreadbytes(state, EQPH_ERR0, buf, sizeof(buf));
+
+ if (state->current_modulation == VSB_8) {
+ /* Equalizer Mean-Square Error Register for VSB */
+ noise = ((buf[0] & 7) << 16) | (buf[1] << 8) | buf[2];
+ } else {
+ /* Phase Tracker Mean-Square Error Register for QAM */
+ noise = ((buf[0] & 7<<3) << 13) | (buf[3] << 8) | buf[4];
+ }
+
+ /* Small values for noise mean signal is better so invert noise */
+ /* Noise is 19 bit value so discard 3 LSB*/
+ *snr = ~noise>>3;
+#endif
+
+ dprintk("%s: noise = 0x%05x, snr = %idb\n",__FUNCTION__, noise, *snr);
+
+ return 0;
+}
+
+static int lgdt3302_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fe_tune_settings)
+{
+ /* I have no idea about this - it may not be needed */
+ fe_tune_settings->min_delay_ms = 500;
+ fe_tune_settings->step_size = 0;
+ fe_tune_settings->max_drift = 0;
+ return 0;
+}
+
+static void lgdt3302_release(struct dvb_frontend* fe)
+{
+ struct lgdt3302_state* state = (struct lgdt3302_state*) fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops lgdt3302_ops;
+
+struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+ struct i2c_adapter* i2c)
+{
+ struct lgdt3302_state* state = NULL;
+ u8 buf[1];
+
+ /* Allocate memory for the internal state */
+ state = (struct lgdt3302_state*) kmalloc(sizeof(struct lgdt3302_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+ memset(state,0,sizeof(*state));
+
+ /* Setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops));
+ /* Verify communication with demod chip */
+ if (i2c_selectreadbytes(state, 2, buf, 1))
+ goto error;
+
+ state->current_frequency = -1;
+ state->current_modulation = -1;
+
+ /* Create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ if (state)
+ kfree(state);
+ dprintk("%s: ERROR\n",__FUNCTION__);
+ return NULL;
+}
+
+static struct dvb_frontend_ops lgdt3302_ops = {
+ .info = {
+ .name= "LG Electronics LGDT3302 VSB/QAM Frontend",
+ .type = FE_ATSC,
+ .frequency_min= 54000000,
+ .frequency_max= 858000000,
+ .frequency_stepsize= 62500,
+ /* Symbol rate is for all VSB modes need to check QAM */
+ .symbol_rate_min = 10762000,
+ .symbol_rate_max = 10762000,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .init = lgdt3302_init,
+ .set_frontend = lgdt3302_set_parameters,
+ .get_frontend = lgdt3302_get_frontend,
+ .get_tune_settings = lgdt3302_get_tune_settings,
+ .read_status = lgdt3302_read_status,
+ .read_ber = lgdt3302_read_ber,
+ .read_signal_strength = lgdt3302_read_signal_strength,
+ .read_snr = lgdt3302_read_snr,
+ .read_ucblocks = lgdt3302_read_ucblocks,
+ .release = lgdt3302_release,
+};
+
+MODULE_DESCRIPTION("LGDT3302 [DViCO FusionHDTV 3 Gold] (ATSC 8VSB & ITU-T J.83 AnnexB 64/256 QAM) Demodulator Driver");
+MODULE_AUTHOR("Wilson Michaels");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(lgdt3302_attach);
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * compile-command: "make DVB=1"
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302.h b/drivers/media/dvb/frontends/lgdt3302.h
new file mode 100644
index 000000000000..81587a40032b
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302.h
@@ -0,0 +1,49 @@
+/*
+ * $Id: lgdt3302.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * 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.
+ *
+ */
+
+#ifndef LGDT3302_H
+#define LGDT3302_H
+
+#include <linux/dvb/frontend.h>
+
+struct lgdt3302_config
+{
+ /* The demodulator's i2c address */
+ u8 demod_address;
+ u8 pll_address;
+ struct dvb_pll_desc *pll_desc;
+
+ /* Need to set device param for start_dma */
+ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured);
+};
+
+extern struct dvb_frontend* lgdt3302_attach(const struct lgdt3302_config* config,
+ struct i2c_adapter* i2c);
+
+#endif /* LGDT3302_H */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/lgdt3302_priv.h b/drivers/media/dvb/frontends/lgdt3302_priv.h
new file mode 100644
index 000000000000..6193fa7a569d
--- /dev/null
+++ b/drivers/media/dvb/frontends/lgdt3302_priv.h
@@ -0,0 +1,72 @@
+/*
+ * $Id: lgdt3302_priv.h,v 1.2 2005/06/28 23:50:48 mkrufky Exp $
+ *
+ * Support for LGDT3302 (DViCO FustionHDTV 3 Gold) - VSB/QAM
+ *
+ * Copyright (C) 2005 Wilson Michaels <wilsonmichaels@earthlink.net>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _LGDT3302_PRIV_
+#define _LGDT3302_PRIV_
+
+/* i2c control register addresses */
+enum I2C_REG {
+ TOP_CONTROL= 0x00,
+ IRQ_MASK= 0x01,
+ IRQ_STATUS= 0x02,
+ VSB_CARRIER_FREQ0= 0x16,
+ VSB_CARRIER_FREQ1= 0x17,
+ VSB_CARRIER_FREQ2= 0x18,
+ VSB_CARRIER_FREQ3= 0x19,
+ CARRIER_MSEQAM1= 0x1a,
+ CARRIER_MSEQAM2= 0x1b,
+ CARRIER_LOCK= 0x1c,
+ TIMING_RECOVERY= 0x1d,
+ AGC_DELAY0= 0x2a,
+ AGC_DELAY1= 0x2b,
+ AGC_DELAY2= 0x2c,
+ AGC_RF_BANDWIDTH0= 0x2d,
+ AGC_RF_BANDWIDTH1= 0x2e,
+ AGC_RF_BANDWIDTH2= 0x2f,
+ AGC_LOOP_BANDWIDTH0= 0x30,
+ AGC_LOOP_BANDWIDTH1= 0x31,
+ AGC_FUNC_CTRL1= 0x32,
+ AGC_FUNC_CTRL2= 0x33,
+ AGC_FUNC_CTRL3= 0x34,
+ AGC_RFIF_ACC0= 0x39,
+ AGC_RFIF_ACC1= 0x3a,
+ AGC_RFIF_ACC2= 0x3b,
+ AGC_STATUS= 0x3f,
+ SYNC_STATUS_VSB= 0x43,
+ EQPH_ERR0= 0x47,
+ EQ_ERR1= 0x48,
+ EQ_ERR2= 0x49,
+ PH_ERR1= 0x4a,
+ PH_ERR2= 0x4b,
+ DEMUX_CONTROL= 0x66,
+ PACKET_ERR_COUNTER1= 0x6a,
+ PACKET_ERR_COUNTER2= 0x6b,
+};
+
+#endif /* _LGDT3302_PRIV_ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
new file mode 100644
index 000000000000..4f396ac8de77
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -0,0 +1,800 @@
+/*
+Driver for Samsung S5H1420 QPSK Demodulator
+
+Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+
+#include "dvb_frontend.h"
+#include "s5h1420.h"
+
+
+
+#define TONE_FREQ 22000
+
+struct s5h1420_state {
+ struct i2c_adapter* i2c;
+ struct dvb_frontend_ops ops;
+ const struct s5h1420_config* config;
+ struct dvb_frontend frontend;
+
+ u8 postlocked:1;
+ u32 fclk;
+ u32 tunedfreq;
+ fe_code_rate_t fec_inner;
+ u32 symbol_rate;
+};
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings);
+
+
+static int debug = 0;
+#define dprintk if (debug) printk
+
+static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
+{
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+ int err;
+
+ if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
+ dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 };
+ struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 };
+
+ if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1)
+ return ret;
+
+ if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
+ return ret;
+
+ return b1[0];
+}
+
+static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ switch(voltage) {
+ case SEC_VOLTAGE_13:
+ s5h1420_writereg(state, 0x3c, (s5h1420_readreg(state, 0x3c) & 0xfe) | 0x02);
+ break;
+
+ case SEC_VOLTAGE_18:
+ s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) | 0x03);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ s5h1420_writereg(state, 0x3c, s5h1420_readreg(state, 0x3c) & 0xfd);
+ break;
+ }
+
+ return 0;
+}
+
+static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ switch(tone) {
+ case SEC_TONE_ON:
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x08);
+ break;
+
+ case SEC_TONE_OFF:
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
+ break;
+ }
+
+ return 0;
+}
+
+static int s5h1420_send_master_cmd (struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ unsigned long timeout;
+ int result = 0;
+
+ /* setup for DISEQC */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x02);
+ msleep(15);
+
+ /* write the DISEQC command bytes */
+ for(i=0; i< cmd->msg_len; i++) {
+ s5h1420_writereg(state, 0x3c + i, cmd->msg[i]);
+ }
+
+ /* kick off transmission */
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | ((cmd->msg_len-1) << 4) | 0x08);
+
+ /* wait for transmission to complete */
+ timeout = jiffies + ((100*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (s5h1420_readreg(state, 0x3b) & 0x08)
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout))
+ result = -ETIMEDOUT;
+
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static int s5h1420_recv_slave_reply (struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int i;
+ int length;
+ unsigned long timeout;
+ int result = 0;
+
+ /* setup for DISEQC recieve */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, 0x82); /* FIXME: guess - do we need to set DIS_RDY(0x08) in receive mode? */
+ msleep(15);
+
+ /* wait for reception to complete */
+ timeout = jiffies + ((reply->timeout*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (!(s5h1420_readreg(state, 0x3b) & 0x80)) /* FIXME: do we test DIS_RDY(0x08) or RCV_EN(0x80)? */
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout)) {
+ result = -ETIMEDOUT;
+ goto exit;
+ }
+
+ /* check error flag - FIXME: not sure what this does - docs do not describe
+ * beyond "error flag for diseqc receive data :( */
+ if (s5h1420_readreg(state, 0x49)) {
+ result = -EIO;
+ goto exit;
+ }
+
+ /* check length */
+ length = (s5h1420_readreg(state, 0x3b) & 0x70) >> 4;
+ if (length > sizeof(reply->msg)) {
+ result = -EOVERFLOW;
+ goto exit;
+ }
+ reply->msg_len = length;
+
+ /* extract data */
+ for(i=0; i< length; i++) {
+ reply->msg[i] = s5h1420_readreg(state, 0x3c + i);
+ }
+
+exit:
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static int s5h1420_send_burst (struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+ int result = 0;
+ unsigned long timeout;
+
+ /* setup for tone burst */
+ val = s5h1420_readreg(state, 0x3b);
+ s5h1420_writereg(state, 0x3b, (s5h1420_readreg(state, 0x3b) & 0x70) | 0x01);
+
+ /* set value for B position if requested */
+ if (minicmd == SEC_MINI_B) {
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x04);
+ }
+ msleep(15);
+
+ /* start transmission */
+ s5h1420_writereg(state, 0x3b, s5h1420_readreg(state, 0x3b) | 0x08);
+
+ /* wait for transmission to complete */
+ timeout = jiffies + ((20*HZ) / 1000);
+ while(time_before(jiffies, timeout)) {
+ if (!(s5h1420_readreg(state, 0x3b) & 0x08))
+ break;
+
+ msleep(5);
+ }
+ if (time_after(jiffies, timeout))
+ result = -ETIMEDOUT;
+
+ /* restore original settings */
+ s5h1420_writereg(state, 0x3b, val);
+ msleep(15);
+ return result;
+}
+
+static fe_status_t s5h1420_get_status_bits(struct s5h1420_state* state)
+{
+ u8 val;
+ fe_status_t status = 0;
+
+ val = s5h1420_readreg(state, 0x14);
+ if (val & 0x02)
+ status |= FE_HAS_SIGNAL; // FIXME: not sure if this is right
+ if (val & 0x01)
+ status |= FE_HAS_CARRIER; // FIXME: not sure if this is right
+ val = s5h1420_readreg(state, 0x36);
+ if (val & 0x01)
+ status |= FE_HAS_VITERBI;
+ if (val & 0x20)
+ status |= FE_HAS_SYNC;
+ if (status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI|FE_HAS_SYNC))
+ status |= FE_HAS_LOCK;
+
+ return status;
+}
+
+static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u8 val;
+
+ if (status == NULL)
+ return -EINVAL;
+
+ /* determine lock state */
+ *status = s5h1420_get_status_bits(state);
+
+ /* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert the inversion,
+ wait a bit and check again */
+ if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) {
+ val = s5h1420_readreg(state, 0x32);
+ if ((val & 0x07) == 0x03) {
+ if (val & 0x08)
+ s5h1420_writereg(state, 0x31, 0x13);
+ else
+ s5h1420_writereg(state, 0x31, 0x1b);
+
+ /* wait a bit then update lock status */
+ mdelay(200);
+ *status = s5h1420_get_status_bits(state);
+ }
+ }
+
+ /* perform post lock setup */
+ if ((*status & FE_HAS_LOCK) && (!state->postlocked)) {
+
+ /* calculate the data rate */
+ u32 tmp = s5h1420_getsymbolrate(state);
+ switch(s5h1420_readreg(state, 0x32) & 0x07) {
+ case 0:
+ tmp = (tmp * 2 * 1) / 2;
+ break;
+
+ case 1:
+ tmp = (tmp * 2 * 2) / 3;
+ break;
+
+ case 2:
+ tmp = (tmp * 2 * 3) / 4;
+ break;
+
+ case 3:
+ tmp = (tmp * 2 * 5) / 6;
+ break;
+
+ case 4:
+ tmp = (tmp * 2 * 6) / 7;
+ break;
+
+ case 5:
+ tmp = (tmp * 2 * 7) / 8;
+ break;
+ }
+ tmp = state->fclk / tmp;
+
+ /* set the MPEG_CLK_INTL for the calculated data rate */
+ if (tmp < 4)
+ val = 0x00;
+ else if (tmp < 8)
+ val = 0x01;
+ else if (tmp < 12)
+ val = 0x02;
+ else if (tmp < 16)
+ val = 0x03;
+ else if (tmp < 24)
+ val = 0x04;
+ else if (tmp < 32)
+ val = 0x05;
+ else
+ val = 0x06;
+ s5h1420_writereg(state, 0x22, val);
+
+ /* DC freeze */
+ s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
+
+ /* kicker disable + remove DC offset */
+ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
+
+ /* post-lock processing has been done! */
+ state->postlocked = 1;
+ }
+
+ return 0;
+}
+
+static int s5h1420_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ s5h1420_writereg(state, 0x46, 0x1d);
+ mdelay(25);
+ return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static int s5h1420_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ u8 val = 0xff - s5h1420_readreg(state, 0x15);
+
+ return (int) ((val << 8) | val);
+}
+
+static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ s5h1420_writereg(state, 0x46, 0x1f);
+ mdelay(25);
+ return (s5h1420_readreg(state, 0x48) << 8) | s5h1420_readreg(state, 0x47);
+}
+
+static void s5h1420_reset(struct s5h1420_state* state)
+{
+ s5h1420_writereg (state, 0x01, 0x08);
+ s5h1420_writereg (state, 0x01, 0x00);
+ udelay(10);
+}
+
+static void s5h1420_setsymbolrate(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ u64 val;
+
+ val = (p->u.qpsk.symbol_rate / 1000) * (1<<24);
+ if (p->u.qpsk.symbol_rate <= 21000000) {
+ val *= 2;
+ }
+ do_div(val, (state->fclk / 1000));
+
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
+ s5h1420_writereg(state, 0x11, val >> 16);
+ s5h1420_writereg(state, 0x12, val >> 8);
+ s5h1420_writereg(state, 0x13, val & 0xff);
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
+}
+
+static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
+{
+ u64 val;
+ int sampling = 2;
+
+ if (s5h1420_readreg(state, 0x05) & 0x2)
+ sampling = 1;
+
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+ val = s5h1420_readreg(state, 0x11) << 16;
+ val |= s5h1420_readreg(state, 0x12) << 8;
+ val |= s5h1420_readreg(state, 0x13);
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+ val *= (state->fclk / 1000);
+ do_div(val, ((1<<24) * sampling));
+
+ return (u32) (val * 1000);
+}
+
+static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
+{
+ int val;
+
+ /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+ * divide fclk by 1000000 to get the correct value. */
+ val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
+
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);
+ s5h1420_writereg(state, 0x0e, val >> 16);
+ s5h1420_writereg(state, 0x0f, val >> 8);
+ s5h1420_writereg(state, 0x10, val & 0xff);
+ s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);
+}
+
+static int s5h1420_getfreqoffset(struct s5h1420_state* state)
+{
+ int val;
+
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
+ val = s5h1420_readreg(state, 0x0e) << 16;
+ val |= s5h1420_readreg(state, 0x0f) << 8;
+ val |= s5h1420_readreg(state, 0x10);
+ s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+
+ if (val & 0x800000)
+ val |= 0xff000000;
+
+ /* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
+ * divide fclk by 1000000 to get the correct value. */
+ val = - ((val * (state->fclk/1000000)) / (1<<24));
+
+ return val;
+}
+
+static void s5h1420_setfec(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+ s5h1420_writereg(state, 0x31, 0x00);
+ s5h1420_writereg(state, 0x30, 0x3f);
+ } else {
+ switch(p->u.qpsk.fec_inner) {
+ case FEC_1_2:
+ s5h1420_writereg(state, 0x31, 0x10);
+ s5h1420_writereg(state, 0x30, 0x01);
+ break;
+
+ case FEC_2_3:
+ s5h1420_writereg(state, 0x31, 0x11);
+ s5h1420_writereg(state, 0x30, 0x02);
+ break;
+
+ case FEC_3_4:
+ s5h1420_writereg(state, 0x31, 0x12);
+ s5h1420_writereg(state, 0x30, 0x04);
+ break;
+
+ case FEC_5_6:
+ s5h1420_writereg(state, 0x31, 0x13);
+ s5h1420_writereg(state, 0x30, 0x08);
+ break;
+
+ case FEC_6_7:
+ s5h1420_writereg(state, 0x31, 0x14);
+ s5h1420_writereg(state, 0x30, 0x10);
+ break;
+
+ case FEC_7_8:
+ s5h1420_writereg(state, 0x31, 0x15);
+ s5h1420_writereg(state, 0x30, 0x20);
+ break;
+
+ default:
+ return;
+ }
+ }
+}
+
+static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
+{
+ switch(s5h1420_readreg(state, 0x32) & 0x07) {
+ case 0:
+ return FEC_1_2;
+
+ case 1:
+ return FEC_2_3;
+
+ case 2:
+ return FEC_3_4;
+
+ case 3:
+ return FEC_5_6;
+
+ case 4:
+ return FEC_6_7;
+
+ case 5:
+ return FEC_7_8;
+ }
+
+ return FEC_NONE;
+}
+
+static void s5h1420_setinversion(struct s5h1420_state* state, struct dvb_frontend_parameters *p)
+{
+ if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
+ s5h1420_writereg(state, 0x31, 0x00);
+ s5h1420_writereg(state, 0x30, 0x3f);
+ } else {
+ u8 tmp = s5h1420_readreg(state, 0x31) & 0xf7;
+ tmp |= 0x10;
+
+ if (p->inversion == INVERSION_ON)
+ tmp |= 0x80;
+
+ s5h1420_writereg(state, 0x31, tmp);
+ }
+}
+
+static fe_spectral_inversion_t s5h1420_getinversion(struct s5h1420_state* state)
+{
+ if (s5h1420_readreg(state, 0x32) & 0x08)
+ return INVERSION_ON;
+
+ return INVERSION_OFF;
+}
+
+static int s5h1420_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ u32 frequency_delta;
+ struct dvb_frontend_tune_settings fesettings;
+
+ /* check if we should do a fast-tune */
+ memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
+ s5h1420_get_tune_settings(fe, &fesettings);
+ frequency_delta = p->frequency - state->tunedfreq;
+ if ((frequency_delta > -fesettings.max_drift) && (frequency_delta < fesettings.max_drift) &&
+ (frequency_delta != 0) &&
+ (state->fec_inner == p->u.qpsk.fec_inner) &&
+ (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+
+ s5h1420_setfreqoffset(state, frequency_delta);
+ return 0;
+ }
+
+ /* first of all, software reset */
+ s5h1420_reset(state);
+
+ /* set tuner PLL */
+ if (state->config->pll_set) {
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ state->config->pll_set(fe, p, &state->tunedfreq);
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+
+ /* set s5h1420 fclk PLL according to desired symbol rate */
+ if (p->u.qpsk.symbol_rate > 28000000) {
+ state->fclk = 88000000;
+ s5h1420_writereg(state, 0x03, 0x50);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xae);
+ } else if (p->u.qpsk.symbol_rate > 21000000) {
+ state->fclk = 59000000;
+ s5h1420_writereg(state, 0x03, 0x33);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xae);
+ } else {
+ state->fclk = 88000000;
+ s5h1420_writereg(state, 0x03, 0x50);
+ s5h1420_writereg(state, 0x04, 0x40);
+ s5h1420_writereg(state, 0x05, 0xac);
+ }
+
+ /* set misc registers */
+ s5h1420_writereg(state, 0x02, 0x00);
+ s5h1420_writereg(state, 0x07, 0xb0);
+ s5h1420_writereg(state, 0x0a, 0x67);
+ s5h1420_writereg(state, 0x0b, 0x78);
+ s5h1420_writereg(state, 0x0c, 0x48);
+ s5h1420_writereg(state, 0x0d, 0x6b);
+ s5h1420_writereg(state, 0x2e, 0x8e);
+ s5h1420_writereg(state, 0x35, 0x33);
+ s5h1420_writereg(state, 0x38, 0x01);
+ s5h1420_writereg(state, 0x39, 0x7d);
+ s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+ s5h1420_writereg(state, 0x3c, 0x00);
+ s5h1420_writereg(state, 0x45, 0x61);
+ s5h1420_writereg(state, 0x46, 0x1d);
+
+ /* start QPSK */
+ s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+
+ /* set the frequency offset to adjust for PLL inaccuracy */
+ s5h1420_setfreqoffset(state, p->frequency - state->tunedfreq);
+
+ /* set the reset of the parameters */
+ s5h1420_setsymbolrate(state, p);
+ s5h1420_setinversion(state, p);
+ s5h1420_setfec(state, p);
+
+ state->fec_inner = p->u.qpsk.fec_inner;
+ state->symbol_rate = p->u.qpsk.symbol_rate;
+ state->postlocked = 0;
+ return 0;
+}
+
+static int s5h1420_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ p->frequency = state->tunedfreq + s5h1420_getfreqoffset(state);
+ p->inversion = s5h1420_getinversion(state);
+ p->u.qpsk.symbol_rate = s5h1420_getsymbolrate(state);
+ p->u.qpsk.fec_inner = s5h1420_getfec(state);
+
+ return 0;
+}
+
+static int s5h1420_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+{
+ if (fesettings->parameters.u.qpsk.symbol_rate > 20000000) {
+ fesettings->min_delay_ms = 50;
+ fesettings->step_size = 2000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 12000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1500;
+ fesettings->max_drift = 9000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 8000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 1000;
+ fesettings->max_drift = 8000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 4000000) {
+ fesettings->min_delay_ms = 100;
+ fesettings->step_size = 500;
+ fesettings->max_drift = 7000;
+ } else if (fesettings->parameters.u.qpsk.symbol_rate > 2000000) {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 14 * fesettings->step_size;
+ } else {
+ fesettings->min_delay_ms = 200;
+ fesettings->step_size = (fesettings->parameters.u.qpsk.symbol_rate / 8000);
+ fesettings->max_drift = 18 * fesettings->step_size;
+ }
+
+ return 0;
+}
+
+static int s5h1420_init (struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ /* disable power down and do reset */
+ s5h1420_writereg(state, 0x02, 0x10);
+ msleep(10);
+ s5h1420_reset(state);
+
+ /* init PLL */
+ if (state->config->pll_init) {
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
+ state->config->pll_init(fe);
+ s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
+ }
+
+ return 0;
+}
+
+static int s5h1420_sleep(struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+
+ return s5h1420_writereg(state, 0x02, 0x12);
+}
+
+static void s5h1420_release(struct dvb_frontend* fe)
+{
+ struct s5h1420_state* state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1420_ops;
+
+struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, struct i2c_adapter* i2c)
+{
+ struct s5h1420_state* state = NULL;
+ u8 identity;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
+ state->postlocked = 0;
+ state->fclk = 88000000;
+ state->tunedfreq = 0;
+ state->fec_inner = FEC_NONE;
+ state->symbol_rate = 0;
+
+ /* check if the demod is there + identify it */
+ identity = s5h1420_readreg(state, 0x00);
+ if (identity != 0x03)
+ goto error;
+
+ /* create dvb_frontend */
+ state->frontend.ops = &state->ops;
+ state->frontend.demodulator_priv = state;
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops s5h1420_ops = {
+
+ .info = {
+ .name = "Samsung S5H1420 DVB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 125, /* kHz for QPSK frontends */
+ .frequency_tolerance = 29500,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+ /* .symbol_rate_tolerance = ???,*/
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK
+ },
+
+ .release = s5h1420_release,
+
+ .init = s5h1420_init,
+ .sleep = s5h1420_sleep,
+
+ .set_frontend = s5h1420_set_frontend,
+ .get_frontend = s5h1420_get_frontend,
+ .get_tune_settings = s5h1420_get_tune_settings,
+
+ .read_status = s5h1420_read_status,
+ .read_ber = s5h1420_read_ber,
+ .read_signal_strength = s5h1420_read_signal_strength,
+ .read_ucblocks = s5h1420_read_ucblocks,
+
+ .diseqc_send_master_cmd = s5h1420_send_master_cmd,
+ .diseqc_recv_slave_reply = s5h1420_recv_slave_reply,
+ .diseqc_send_burst = s5h1420_send_burst,
+ .set_tone = s5h1420_set_tone,
+ .set_voltage = s5h1420_set_voltage,
+};
+
+module_param(debug, int, 0644);
+
+MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(s5h1420_attach);
diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h
new file mode 100644
index 000000000000..b687fc77ceb3
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1420.h
@@ -0,0 +1,41 @@
+/*
+ Driver for S5H1420 QPSK Demodulators
+
+ Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+
+ 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.
+
+*/
+
+#ifndef S5H1420_H
+#define S5H1420_H
+
+#include <linux/dvb/frontend.h>
+
+struct s5h1420_config
+{
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* PLL maintenance */
+ int (*pll_init)(struct dvb_frontend* fe);
+ int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout);
+};
+
+extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
+ struct i2c_adapter* i2c);
+
+#endif // S5H1420_H
diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c
index e681263bf079..928aca052afe 100644
--- a/drivers/media/dvb/frontends/stv0297.c
+++ b/drivers/media/dvb/frontends/stv0297.c
@@ -617,7 +617,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
/* wait for WGAGC lock */
starttime = jiffies;
- timeout = jiffies + (200 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(2000);
while (time_before(jiffies, timeout)) {
msleep(10);
if (stv0297_readreg(state, 0x43) & 0x08)
@@ -629,7 +629,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
msleep(20);
/* wait for equaliser partial convergence */
- timeout = jiffies + (50 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(500);
while (time_before(jiffies, timeout)) {
msleep(10);
@@ -642,7 +642,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
}
/* wait for equaliser full convergence */
- timeout = jiffies + (delay * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(delay);
while (time_before(jiffies, timeout)) {
msleep(10);
@@ -659,7 +659,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
stv0297_writereg_mask(state, 0x88, 8, 0);
/* wait for main lock */
- timeout = jiffies + (20 * HZ) / 1000;
+ timeout = jiffies + msecs_to_jiffies(20);
while (time_before(jiffies, timeout)) {
msleep(10);
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index 0beb370792ae..ab0c032472cc 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -49,10 +49,8 @@ struct tda1004x_state {
/* private demod data */
u8 initialised;
enum tda1004x_demod demod_type;
- u8 fw_version;
};
-
static int debug;
#define dprintk(args...) \
do { \
@@ -122,6 +120,8 @@ static int debug;
#define TDA10046H_GPIO_OUT_SEL 0x41
#define TDA10046H_GPIO_SELECT 0x42
#define TDA10046H_AGC_CONF 0x43
+#define TDA10046H_AGC_THR 0x44
+#define TDA10046H_AGC_RENORM 0x45
#define TDA10046H_AGC_GAINS 0x46
#define TDA10046H_AGC_TUN_MIN 0x47
#define TDA10046H_AGC_TUN_MAX 0x48
@@ -274,14 +274,26 @@ static int tda10046h_set_bandwidth(struct tda1004x_state *state,
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_6mhz, sizeof(bandwidth_6mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x09);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x4f);
+ }
break;
case BANDWIDTH_7_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_7mhz, sizeof(bandwidth_7mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0a);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x79);
+ }
break;
case BANDWIDTH_8_MHZ:
tda1004x_write_buf(state, TDA10046H_TIME_WREF1, bandwidth_8mhz, sizeof(bandwidth_8mhz));
+ if (state->config->if_freq == TDA10046_FREQ_045) {
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+ }
break;
default:
@@ -315,20 +327,35 @@ static int tda1004x_do_upload(struct tda1004x_state *state,
memcpy(buf + 1, mem + pos, tx_size);
fw_msg.len = tx_size + 1;
if (i2c_transfer(state->i2c, &fw_msg, 1) != 1) {
- printk("tda1004x: Error during firmware upload\n");
+ printk(KERN_ERR "tda1004x: Error during firmware upload\n");
return -EIO;
}
pos += tx_size;
dprintk("%s: fw_pos=0x%x\n", __FUNCTION__, pos);
}
+ // give the DSP a chance to settle 03/10/05 Hac
+ msleep(100);
return 0;
}
-static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
+static int tda1004x_check_upload_ok(struct tda1004x_state *state)
{
u8 data1, data2;
+ unsigned long timeout;
+
+ if (state->demod_type == TDA1004X_DEMOD_TDA10046) {
+ timeout = jiffies + 2 * HZ;
+ while(!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "tda1004x: timeout waiting for DSP ready\n");
+ break;
+ }
+ msleep(1);
+ }
+ } else
+ msleep(100);
// check upload was OK
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x10, 0); // we want to read from the DSP
@@ -336,9 +363,11 @@ static int tda1004x_check_upload_ok(struct tda1004x_state *state, u8 dspVersion)
data1 = tda1004x_read_byte(state, TDA1004X_DSP_DATA1);
data2 = tda1004x_read_byte(state, TDA1004X_DSP_DATA2);
- if ((data1 != 0x67) || (data2 != dspVersion))
+ if (data1 != 0x67 || data2 < 0x20 || data2 > 0x2e) {
+ printk(KERN_INFO "tda1004x: found firmware revision %x -- invalid\n", data2);
return -EIO;
-
+ }
+ printk(KERN_INFO "tda1004x: found firmware revision %x -- ok\n", data2);
return 0;
}
@@ -349,14 +378,14 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
const struct firmware *fw;
/* don't re-upload unless necessary */
- if (tda1004x_check_upload_ok(state, 0x2c) == 0)
+ if (tda1004x_check_upload_ok(state) == 0)
return 0;
/* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
+ printk(KERN_INFO "tda1004x: waiting for firmware upload (%s)...\n", TDA10045_DEFAULT_FIRMWARE);
ret = state->config->request_firmware(fe, &fw, TDA10045_DEFAULT_FIRMWARE);
if (ret) {
- printk("tda1004x: no firmware upload (timeout or file not found?)\n");
+ printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
return ret;
}
@@ -370,95 +399,93 @@ static int tda10045_fwupload(struct dvb_frontend* fe)
tda10045h_set_bandwidth(state, BANDWIDTH_8_MHZ);
ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10045H_FWPAGE, TDA10045H_CODE_IN);
+ release_firmware(fw);
if (ret)
return ret;
- printk("tda1004x: firmware upload complete\n");
+ printk(KERN_INFO "tda1004x: firmware upload complete\n");
/* wait for DSP to initialise */
/* DSPREADY doesn't seem to work on the TDA10045H */
msleep(100);
- return tda1004x_check_upload_ok(state, 0x2c);
+ return tda1004x_check_upload_ok(state);
}
-static int tda10046_get_fw_version(struct tda1004x_state *state,
- const struct firmware *fw)
+static void tda10046_init_plls(struct dvb_frontend* fe)
{
- const unsigned char pattern[] = { 0x67, 0x00, 0x50, 0x62, 0x5e, 0x18, 0x67 };
- unsigned int i;
-
- /* area guessed from firmware v20, v21 and v25 */
- for (i = 0x660; i < 0x700; i++) {
- if (!memcmp(&fw->data[i], pattern, sizeof(pattern))) {
- state->fw_version = fw->data[i + sizeof(pattern)];
- printk(KERN_INFO "tda1004x: using firmware v%02x\n",
- state->fw_version);
- return 0;
- }
- }
+ struct tda1004x_state* state = fe->demodulator_priv;
- return -EINVAL;
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL1, 0xf0);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
+ if (state->config->xtal_freq == TDA10046_XTAL_4M ) {
+ dprintk("%s: setting up PLLs for a 4 MHz Xtal\n", __FUNCTION__);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 0); // PLL P = N = 0
+ } else {
+ dprintk("%s: setting up PLLs for a 16 MHz Xtal\n", __FUNCTION__);
+ tda1004x_write_byteI(state, TDA10046H_CONFPLL3, 3); // PLL P = 0, N = 3
+ }
+ tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
+ switch (state->config->if_freq) {
+ case TDA10046_FREQ_3617:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
+ break;
+ case TDA10046_FREQ_3613:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x13);
+ break;
+ case TDA10046_FREQ_045:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0b);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0xa3);
+ break;
+ case TDA10046_FREQ_052:
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0x0c);
+ tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x06);
+ break;
+ }
+ tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
}
static int tda10046_fwupload(struct dvb_frontend* fe)
{
struct tda1004x_state* state = fe->demodulator_priv;
- unsigned long timeout;
int ret;
const struct firmware *fw;
/* reset + wake up chip */
- tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0);
+ tda1004x_write_byteI(state, TDA1004X_CONFC4, 0);
tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 1, 0);
- msleep(100);
+ /* let the clocks recover from sleep */
+ msleep(5);
/* don't re-upload unless necessary */
- if (tda1004x_check_upload_ok(state, state->fw_version) == 0)
+ if (tda1004x_check_upload_ok(state) == 0)
return 0;
- /* request the firmware, this will block until someone uploads it */
- printk("tda1004x: waiting for firmware upload (%s)...\n", TDA10046_DEFAULT_FIRMWARE);
- ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
- if (ret) {
- printk("tda1004x: no firmware upload (timeout or file not found?)\n");
- return ret;
- }
-
- if (fw->size < 24478) { /* size of firmware v20, which is the smallest of v20, v21 and v25 */
- printk("tda1004x: firmware file seems to be too small (%d bytes)\n", fw->size);
- return -EINVAL;
- }
-
- ret = tda10046_get_fw_version(state, fw);
- if (ret < 0) {
- printk("tda1004x: unable to find firmware version\n");
- return ret;
- }
-
/* set parameters */
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10);
- tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c);
- tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99);
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4);
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c);
- tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
-
- ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
- if (ret)
- return ret;
- printk("tda1004x: firmware upload complete\n");
-
- /* wait for DSP to initialise */
- timeout = jiffies + HZ;
- while (!(tda1004x_read_byte(state, TDA1004X_STATUS_CD) & 0x20)) {
- if (time_after(jiffies, timeout)) {
- printk("tda1004x: DSP failed to initialised.\n");
- return -EIO;
+ tda10046_init_plls(fe);
+
+ if (state->config->request_firmware != NULL) {
+ /* request the firmware, this will block until someone uploads it */
+ printk(KERN_INFO "tda1004x: waiting for firmware upload...\n");
+ ret = state->config->request_firmware(fe, &fw, TDA10046_DEFAULT_FIRMWARE);
+ if (ret) {
+ printk(KERN_ERR "tda1004x: no firmware upload (timeout or file not found?)\n");
+ return ret;
}
- msleep(1);
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 8, 8); // going to boot from HOST
+ ret = tda1004x_do_upload(state, fw->data, fw->size, TDA10046H_CODE_CPT, TDA10046H_CODE_IN);
+ release_firmware(fw);
+ if (ret)
+ return ret;
+ } else {
+ /* boot from firmware eeprom */
+ /* Hac Note: we might need to do some GPIO Magic here */
+ printk(KERN_INFO "tda1004x: booting from eeprom\n");
+ tda1004x_write_mask(state, TDA1004X_CONFC4, 4, 4);
+ msleep(300);
}
-
- return tda1004x_check_upload_ok(state, state->fw_version);
+ return tda1004x_check_upload_ok(state);
}
static int tda1004x_encode_fec(int fec)
@@ -560,12 +587,10 @@ static int tda10046_init(struct dvb_frontend* fe)
if (tda10046_fwupload(fe)) {
printk("tda1004x: firmware upload failed\n");
- return -EIO;
+ return -EIO;
}
- tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 0); // wake up the chip
-
- // Init the PLL
+ // Init the tuner PLL
if (state->config->pll_init) {
tda1004x_enable_tuner_i2c(state);
state->config->pll_init(fe);
@@ -574,32 +599,44 @@ static int tda10046_init(struct dvb_frontend* fe)
// tda setup
tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer
- tda1004x_write_mask(state, TDA1004X_CONFC1, 0x40, 0x40);
- tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream
- tda1004x_write_mask(state, TDA1004X_CONFC1, 0x80, 0); // disable pulse killer
- tda1004x_write_byteI(state, TDA10046H_CONFPLL2, 10); // PLL M = 10
- tda1004x_write_byteI(state, TDA10046H_CONFPLL3, state->config->n_i2c); // PLL P = N = 0
- tda1004x_write_byteI(state, TDA10046H_FREQ_OFFSET, 99); // FREQOFFS = 99
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_MSB, 0xd4); // } PHY2 = -11221
- tda1004x_write_byteI(state, TDA10046H_FREQ_PHY2_LSB, 0x2c); // }
- tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0); // AGC setup
- tda1004x_write_mask(state, TDA10046H_CONF_POLARITY, 0x60, 0x60); // set AGC polarities
+ tda1004x_write_byteI(state, TDA1004X_AUTO, 7); // select HP stream
+ tda1004x_write_byteI(state, TDA1004X_CONFC1, 8); // disable pulse killer
+
+ tda10046_init_plls(fe);
+ switch (state->config->agc_config) {
+ case TDA10046_AGC_DEFAULT:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x00); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ case TDA10046_AGC_IFO_AUTO_NEG:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ case TDA10046_AGC_IFO_AUTO_POS:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x0a); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x00); // set AGC polarities
+ break;
+ case TDA10046_AGC_TDA827X:
+ tda1004x_write_byteI(state, TDA10046H_AGC_CONF, 0x02); // AGC setup
+ tda1004x_write_byteI(state, TDA10046H_AGC_THR, 0x70); // AGC Threshold
+ tda1004x_write_byteI(state, TDA10046H_AGC_RENORM, 0x0E); // Gain Renormalize
+ tda1004x_write_byteI(state, TDA10046H_CONF_POLARITY, 0x60); // set AGC polarities
+ break;
+ }
+ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0x61); // Turn both AGC outputs on
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_TUN_MAX, 0xff); // } AGC min/max values
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MIN, 0); // }
tda1004x_write_byteI(state, TDA10046H_AGC_IF_MAX, 0xff); // }
- tda1004x_write_mask(state, TDA10046H_CVBER_CTRL, 0x30, 0x10); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA10046H_AGC_GAINS, 1); // IF gain 2, TUN gain 1
- tda1004x_write_mask(state, TDA1004X_AUTO, 0x80, 0); // crystal is 50ppm
+ tda1004x_write_byteI(state, TDA10046H_CVBER_CTRL, 0x1a); // 10^6 VBER measurement bits
tda1004x_write_byteI(state, TDA1004X_CONF_TS1, 7); // MPEG2 interface config
- tda1004x_write_mask(state, TDA1004X_CONF_TS2, 0x31, 0); // MPEG2 interface config
- tda1004x_write_mask(state, TDA10046H_CONF_TRISTATE1, 0x9e, 0); // disable AGC_TUN
+ tda1004x_write_byteI(state, TDA1004X_CONF_TS2, 0xc0); // MPEG2 interface config
+ tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+
tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE2, 0xe1); // tristate setup
tda1004x_write_byteI(state, TDA10046H_GPIO_OUT_SEL, 0xcc); // GPIO output config
- tda1004x_write_mask(state, TDA10046H_GPIO_SELECT, 8, 8); // GPIO select
- tda10046h_set_bandwidth(state, BANDWIDTH_8_MHZ); // default bandwidth 8 MHz
-
- tda1004x_write_mask(state, 0x3a, 0x80, state->config->invert_oclk << 7);
+ tda1004x_write_byteI(state, TDA10046H_GPIO_SELECT, 8); // GPIO select
state->initialised = 1;
return 0;
@@ -629,9 +666,6 @@ static int tda1004x_set_fe(struct dvb_frontend* fe,
state->config->pll_set(fe, fe_params);
tda1004x_disable_tuner_i2c(state);
- if (state->demod_type == TDA1004X_DEMOD_TDA10046)
- tda1004x_write_mask(state, TDA10046H_AGC_CONF, 4, 4);
-
// Hardcoded to use auto as much as possible on the TDA10045 as it
// is very unreliable if AUTO mode is _not_ used.
if (state->demod_type == TDA1004X_DEMOD_TDA10045) {
@@ -1089,6 +1123,11 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
break;
case TDA1004X_DEMOD_TDA10046:
+ if (state->config->pll_sleep != NULL) {
+ tda1004x_enable_tuner_i2c(state);
+ state->config->pll_sleep(fe);
+ tda1004x_disable_tuner_i2c(state);
+ }
tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1);
break;
}
@@ -1100,8 +1139,9 @@ static int tda1004x_sleep(struct dvb_frontend* fe)
static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
{
fesettings->min_delay_ms = 800;
- fesettings->step_size = 166667;
- fesettings->max_drift = 166667*2;
+ /* Drift compensation makes no sense for DVB-T */
+ fesettings->step_size = 0;
+ fesettings->max_drift = 0;
return 0;
}
@@ -1216,7 +1256,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config,
memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops));
state->initialised = 0;
state->demod_type = TDA1004X_DEMOD_TDA10046;
- state->fw_version = 0x20; /* dummy default value */
/* check if the demod is there */
if (tda1004x_read_byte(state, TDA1004X_CHIPID) != 0x46) {
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index c8e1d54ff262..8659c52647ad 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -26,6 +26,25 @@
#include <linux/dvb/frontend.h>
#include <linux/firmware.h>
+enum tda10046_xtal {
+ TDA10046_XTAL_4M,
+ TDA10046_XTAL_16M,
+};
+
+enum tda10046_agc {
+ TDA10046_AGC_DEFAULT, /* original configuration */
+ TDA10046_AGC_IFO_AUTO_NEG, /* IF AGC only, automatic, negtive */
+ TDA10046_AGC_IFO_AUTO_POS, /* IF AGC only, automatic, positive */
+ TDA10046_AGC_TDA827X, /* IF AGC only, special setup for tda827x */
+};
+
+enum tda10046_if {
+ TDA10046_FREQ_3617, /* original config, 36,166 MHZ */
+ TDA10046_FREQ_3613, /* 36,13 MHZ */
+ TDA10046_FREQ_045, /* low IF, 4.0, 4.5, or 5.0 MHZ */
+ TDA10046_FREQ_052, /* low IF, 5.1667 MHZ for tda9889 */
+};
+
struct tda1004x_config
{
/* the demodulator's i2c address */
@@ -37,14 +56,22 @@ struct tda1004x_config
/* Does the OCLK signal need inverted? */
u8 invert_oclk;
- /* value of N_I2C of the CONF_PLL3 register */
- u8 n_i2c;
+ /* Xtal frequency, 4 or 16MHz*/
+ enum tda10046_xtal xtal_freq;
+
+ /* IF frequency */
+ enum tda10046_if if_freq;
+
+ /* AGC configuration */
+ enum tda10046_agc agc_config;
/* PLL maintenance */
int (*pll_init)(struct dvb_frontend* fe);
+ void (*pll_sleep)(struct dvb_frontend* fe);
int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params);
/* request firmware for device */
+ /* set this to NULL if the card has a firmware EEPROM */
int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
};
diff --git a/drivers/media/dvb/frontends/tda80xx.c b/drivers/media/dvb/frontends/tda80xx.c
index 032d348dafb7..88e125079ca1 100644
--- a/drivers/media/dvb/frontends/tda80xx.c
+++ b/drivers/media/dvb/frontends/tda80xx.c
@@ -27,7 +27,6 @@
#include <linux/spinlock.h>
#include <linux/threads.h>
#include <linux/interrupt.h>
-#include <linux/irq.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/media/dvb/pluto2/Kconfig b/drivers/media/dvb/pluto2/Kconfig
new file mode 100644
index 000000000000..f02842be0d60
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Kconfig
@@ -0,0 +1,16 @@
+config DVB_PLUTO2
+ tristate "Pluto2 cards"
+ depends on DVB_CORE && PCI
+ select I2C
+ select I2C_ALGOBIT
+ select DVB_TDA1004X
+ help
+ Support for PCI cards based on the Pluto2 FPGA like the Satelco
+ Easywatch Mobile Terrestrial DVB-T Receiver.
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the PCI bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y or M if you own such a device and want to use it.
+
diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile
new file mode 100644
index 000000000000..86ca84b2be6e
--- /dev/null
+++ b/drivers/media/dvb/pluto2/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_DVB_PLUTO2) = pluto2.o
+
+EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
new file mode 100644
index 000000000000..706e0bcb5ede
--- /dev/null
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -0,0 +1,809 @@
+/*
+ * pluto2.c - Satelco Easywatch Mobile Terrestrial Receiver [DVB-T]
+ *
+ * Copyright (C) 2005 Andreas Oberritter <obi@linuxtv.org>
+ *
+ * based on pluto2.c 1.10 - http://instinct-wp8.no-ip.org/pluto/
+ * by Dany Salman <salmandany@yahoo.fr>
+ * Copyright (c) 2004 TDF
+ *
+ * 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 <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+#include "tda1004x.h"
+
+#define DRIVER_NAME "pluto2"
+
+#define REG_PIDn(n) ((n) << 2) /* PID n pattern registers */
+#define REG_PCAR 0x0020 /* PC address register */
+#define REG_TSCR 0x0024 /* TS ctrl & status */
+#define REG_MISC 0x0028 /* miscellaneous */
+#define REG_MMAC 0x002c /* MSB MAC address */
+#define REG_IMAC 0x0030 /* ISB MAC address */
+#define REG_LMAC 0x0034 /* LSB MAC address */
+#define REG_SPID 0x0038 /* SPI data */
+#define REG_SLCS 0x003c /* serial links ctrl/status */
+
+#define PID0_NOFIL (0x0001 << 16)
+#define PIDn_ENP (0x0001 << 15)
+#define PID0_END (0x0001 << 14)
+#define PID0_AFIL (0x0001 << 13)
+#define PIDn_PID (0x1fff << 0)
+
+#define TSCR_NBPACKETS (0x00ff << 24)
+#define TSCR_DEM (0x0001 << 17)
+#define TSCR_DE (0x0001 << 16)
+#define TSCR_RSTN (0x0001 << 15)
+#define TSCR_MSKO (0x0001 << 14)
+#define TSCR_MSKA (0x0001 << 13)
+#define TSCR_MSKL (0x0001 << 12)
+#define TSCR_OVR (0x0001 << 11)
+#define TSCR_AFUL (0x0001 << 10)
+#define TSCR_LOCK (0x0001 << 9)
+#define TSCR_IACK (0x0001 << 8)
+#define TSCR_ADEF (0x007f << 0)
+
+#define MISC_DVR (0x0fff << 4)
+#define MISC_ALED (0x0001 << 3)
+#define MISC_FRST (0x0001 << 2)
+#define MISC_LED1 (0x0001 << 1)
+#define MISC_LED0 (0x0001 << 0)
+
+#define SPID_SPIDR (0x00ff << 0)
+
+#define SLCS_SCL (0x0001 << 7)
+#define SLCS_SDA (0x0001 << 6)
+#define SLCS_CSN (0x0001 << 2)
+#define SLCS_OVR (0x0001 << 1)
+#define SLCS_SWC (0x0001 << 0)
+
+#define TS_DMA_PACKETS (8)
+#define TS_DMA_BYTES (188 * TS_DMA_PACKETS)
+
+#define I2C_ADDR_TDA10046 0x10
+#define I2C_ADDR_TUA6034 0xc2
+#define NHWFILTERS 8
+
+struct pluto {
+ /* pci */
+ struct pci_dev *pdev;
+ u8 __iomem *io_mem;
+
+ /* dvb */
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_frontend *fe;
+ struct dvb_net dvbnet;
+ unsigned int full_ts_users;
+ unsigned int users;
+
+ /* i2c */
+ struct i2c_algo_bit_data i2c_bit;
+ struct i2c_adapter i2c_adap;
+ unsigned int i2cbug;
+
+ /* irq */
+ unsigned int overflow;
+
+ /* dma */
+ dma_addr_t dma_addr;
+ u8 dma_buf[TS_DMA_BYTES];
+ u8 dummy[4096];
+};
+
+static inline struct pluto *feed_to_pluto(struct dvb_demux_feed *feed)
+{
+ return container_of(feed->demux, struct pluto, demux);
+}
+
+static inline struct pluto *frontend_to_pluto(struct dvb_frontend *fe)
+{
+ return container_of(fe->dvb, struct pluto, dvb_adapter);
+}
+
+static inline u32 pluto_readreg(struct pluto *pluto, u32 reg)
+{
+ return readl(&pluto->io_mem[reg]);
+}
+
+static inline void pluto_writereg(struct pluto *pluto, u32 reg, u32 val)
+{
+ writel(val, &pluto->io_mem[reg]);
+}
+
+static inline void pluto_rw(struct pluto *pluto, u32 reg, u32 mask, u32 bits)
+{
+ u32 val = readl(&pluto->io_mem[reg]);
+ val &= ~mask;
+ val |= bits;
+ writel(val, &pluto->io_mem[reg]);
+}
+
+static void pluto_setsda(void *data, int state)
+{
+ struct pluto *pluto = data;
+
+ if (state)
+ pluto_rw(pluto, REG_SLCS, SLCS_SDA, SLCS_SDA);
+ else
+ pluto_rw(pluto, REG_SLCS, SLCS_SDA, 0);
+}
+
+static void pluto_setscl(void *data, int state)
+{
+ struct pluto *pluto = data;
+
+ if (state)
+ pluto_rw(pluto, REG_SLCS, SLCS_SCL, SLCS_SCL);
+ else
+ pluto_rw(pluto, REG_SLCS, SLCS_SCL, 0);
+
+ /* try to detect i2c_inb() to workaround hardware bug:
+ * reset SDA to high after SCL has been set to low */
+ if ((state) && (pluto->i2cbug == 0)) {
+ pluto->i2cbug = 1;
+ } else {
+ if ((!state) && (pluto->i2cbug == 1))
+ pluto_setsda(pluto, 1);
+ pluto->i2cbug = 0;
+ }
+}
+
+static int pluto_getsda(void *data)
+{
+ struct pluto *pluto = data;
+
+ return pluto_readreg(pluto, REG_SLCS) & SLCS_SDA;
+}
+
+static int pluto_getscl(void *data)
+{
+ struct pluto *pluto = data;
+
+ return pluto_readreg(pluto, REG_SLCS) & SLCS_SCL;
+}
+
+static void pluto_reset_frontend(struct pluto *pluto, int reenable)
+{
+ u32 val = pluto_readreg(pluto, REG_MISC);
+
+ if (val & MISC_FRST) {
+ val &= ~MISC_FRST;
+ pluto_writereg(pluto, REG_MISC, val);
+ }
+ if (reenable) {
+ val |= MISC_FRST;
+ pluto_writereg(pluto, REG_MISC, val);
+ }
+}
+
+static void pluto_reset_ts(struct pluto *pluto, int reenable)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ if (val & TSCR_RSTN) {
+ val &= ~TSCR_RSTN;
+ pluto_writereg(pluto, REG_TSCR, val);
+ }
+ if (reenable) {
+ val |= TSCR_RSTN;
+ pluto_writereg(pluto, REG_TSCR, val);
+ }
+}
+
+static void pluto_set_dma_addr(struct pluto *pluto)
+{
+ pluto_writereg(pluto, REG_PCAR, cpu_to_le32(pluto->dma_addr));
+}
+
+static int __devinit pluto_dma_map(struct pluto *pluto)
+{
+ pluto->dma_addr = pci_map_single(pluto->pdev, pluto->dma_buf,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+ return pci_dma_mapping_error(pluto->dma_addr);
+}
+
+static void pluto_dma_unmap(struct pluto *pluto)
+{
+ pci_unmap_single(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static int pluto_start_feed(struct dvb_demux_feed *f)
+{
+ struct pluto *pluto = feed_to_pluto(f);
+
+ /* enable PID filtering */
+ if (pluto->users++ == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_AFIL | PID0_NOFIL, 0);
+
+ if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+ pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, PIDn_ENP | f->pid);
+ else if (pluto->full_ts_users++ == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, PID0_NOFIL);
+
+ return 0;
+}
+
+static int pluto_stop_feed(struct dvb_demux_feed *f)
+{
+ struct pluto *pluto = feed_to_pluto(f);
+
+ /* disable PID filtering */
+ if (--pluto->users == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_AFIL, PID0_AFIL);
+
+ if ((f->pid < 0x2000) && (f->index < NHWFILTERS))
+ pluto_rw(pluto, REG_PIDn(f->index), PIDn_ENP | PIDn_PID, 0x1fff);
+ else if (--pluto->full_ts_users == 0)
+ pluto_rw(pluto, REG_PIDn(0), PID0_NOFIL, 0);
+
+ return 0;
+}
+
+static void pluto_dma_end(struct pluto *pluto, unsigned int nbpackets)
+{
+ /* synchronize the DMA transfer with the CPU
+ * first so that we see updated contents. */
+ pci_dma_sync_single_for_cpu(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+
+ /* Workaround for broken hardware:
+ * [1] On startup NBPACKETS seems to contain an uninitialized value,
+ * but no packets have been transfered.
+ * [2] Sometimes (actually very often) NBPACKETS stays at zero
+ * although one packet has been transfered.
+ */
+ if ((nbpackets == 0) || (nbpackets > TS_DMA_PACKETS)) {
+ unsigned int i = 0, valid;
+ while (pluto->dma_buf[i] == 0x47)
+ i += 188;
+ valid = i / 188;
+ if (nbpackets != valid) {
+ dev_err(&pluto->pdev->dev, "nbpackets=%u valid=%u\n",
+ nbpackets, valid);
+ nbpackets = valid;
+ }
+ }
+
+ dvb_dmx_swfilter_packets(&pluto->demux, pluto->dma_buf, nbpackets);
+
+ /* clear the dma buffer. this is needed to be able to identify
+ * new valid ts packets above */
+ memset(pluto->dma_buf, 0, nbpackets * 188);
+
+ /* reset the dma address */
+ pluto_set_dma_addr(pluto);
+
+ /* sync the buffer and give it back to the card */
+ pci_dma_sync_single_for_device(pluto->pdev, pluto->dma_addr,
+ TS_DMA_BYTES, PCI_DMA_FROMDEVICE);
+}
+
+static irqreturn_t pluto_irq(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct pluto *pluto = dev_id;
+ u32 tscr;
+
+ /* check whether an interrupt occured on this device */
+ tscr = pluto_readreg(pluto, REG_TSCR);
+ if (!(tscr & (TSCR_DE | TSCR_OVR)))
+ return IRQ_NONE;
+
+ if (tscr == 0xffffffff) {
+ // FIXME: maybe recover somehow
+ dev_err(&pluto->pdev->dev, "card hung up :(\n");
+ return IRQ_HANDLED;
+ }
+
+ /* dma end interrupt */
+ if (tscr & TSCR_DE) {
+ pluto_dma_end(pluto, (tscr & TSCR_NBPACKETS) >> 24);
+ /* overflow interrupt */
+ if (tscr & TSCR_OVR)
+ pluto->overflow++;
+ if (pluto->overflow) {
+ dev_err(&pluto->pdev->dev, "overflow irq (%d)\n",
+ pluto->overflow);
+ pluto_reset_ts(pluto, 1);
+ pluto->overflow = 0;
+ }
+ } else if (tscr & TSCR_OVR) {
+ pluto->overflow++;
+ }
+
+ /* ACK the interrupt */
+ pluto_writereg(pluto, REG_TSCR, tscr | TSCR_IACK);
+
+ return IRQ_HANDLED;
+}
+
+static void __devinit pluto_enable_irqs(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ /* set the number of packets */
+ val &= ~TSCR_ADEF;
+ val |= TS_DMA_PACKETS / 2;
+ /* disable AFUL and LOCK interrupts */
+ val |= (TSCR_MSKA | TSCR_MSKL);
+ /* enable DMA and OVERFLOW interrupts */
+ val &= ~(TSCR_DEM | TSCR_MSKO);
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+ pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static void pluto_disable_irqs(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_TSCR);
+
+ /* disable all interrupts */
+ val |= (TSCR_DEM | TSCR_MSKO | TSCR_MSKA | TSCR_MSKL);
+ /* clear pending interrupts */
+ val |= TSCR_IACK;
+
+ pluto_writereg(pluto, REG_TSCR, val);
+}
+
+static int __devinit pluto_hw_init(struct pluto *pluto)
+{
+ pluto_reset_frontend(pluto, 1);
+
+ /* set automatic LED control by FPGA */
+ pluto_rw(pluto, REG_MISC, MISC_ALED, MISC_ALED);
+
+ /* set data endianess */
+#ifdef __LITTLE_ENDIAN
+ pluto_rw(pluto, REG_PIDn(0), PID0_END, PID0_END);
+#else
+ pluto_rw(pluto, REG_PIDn(0), PID0_END, 0);
+#endif
+ /* map DMA and set address */
+ pluto_dma_map(pluto);
+ pluto_set_dma_addr(pluto);
+
+ /* enable interrupts */
+ pluto_enable_irqs(pluto);
+
+ /* reset TS logic */
+ pluto_reset_ts(pluto, 1);
+
+ return 0;
+}
+
+static void pluto_hw_exit(struct pluto *pluto)
+{
+ /* disable interrupts */
+ pluto_disable_irqs(pluto);
+
+ pluto_reset_ts(pluto, 0);
+
+ /* LED: disable automatic control, enable yellow, disable green */
+ pluto_rw(pluto, REG_MISC, MISC_ALED | MISC_LED1 | MISC_LED0, MISC_LED1);
+
+ /* unmap DMA */
+ pluto_dma_unmap(pluto);
+
+ pluto_reset_frontend(pluto, 0);
+}
+
+static inline u32 divide(u32 numerator, u32 denominator)
+{
+ if (denominator == 0)
+ return ~0;
+
+ return (numerator + denominator / 2) / denominator;
+}
+
+/* LG Innotek TDTE-E001P (Infineon TUA6034) */
+static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct pluto *pluto = frontend_to_pluto(fe);
+ struct i2c_msg msg;
+ int ret;
+ u8 buf[4];
+ u32 div;
+
+ // Fref = 166.667 Hz
+ // Fref * 3 = 500.000 Hz
+ // IF = 36166667
+ // IF / Fref = 217
+ //div = divide(p->frequency + 36166667, 166667);
+ div = divide(p->frequency * 3, 500000) + 217;
+ buf[0] = (div >> 8) & 0x7f;
+ buf[1] = (div >> 0) & 0xff;
+
+ if (p->frequency < 611000000)
+ buf[2] = 0xb4;
+ else if (p->frequency < 811000000)
+ buf[2] = 0xbc;
+ else
+ buf[2] = 0xf4;
+
+ // VHF: 174-230 MHz
+ // center: 350 MHz
+ // UHF: 470-862 MHz
+ if (p->frequency < 350000000)
+ buf[3] = 0x02;
+ else
+ buf[3] = 0x04;
+
+ if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 0x08;
+
+ if (sizeof(buf) == 6) {
+ buf[4] = buf[2];
+ buf[4] &= ~0x1c;
+ buf[4] |= 0x18;
+
+ buf[5] = (0 << 7) | (2 << 4);
+ }
+
+ msg.addr = I2C_ADDR_TUA6034 >> 1;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = sizeof(buf);
+
+ ret = i2c_transfer(&pluto->i2c_adap, &msg, 1);
+ if (ret < 0)
+ return ret;
+ else if (ret == 0)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int pluto2_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char *name)
+{
+ struct pluto *pluto = frontend_to_pluto(fe);
+
+ return request_firmware(fw, name, &pluto->pdev->dev);
+}
+
+static struct tda1004x_config pluto2_fe_config __devinitdata = {
+ .demod_address = I2C_ADDR_TDA10046 >> 1,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .pll_set = lg_tdtpe001p_pll_set,
+ .pll_sleep = NULL,
+ .request_firmware = pluto2_request_firmware,
+};
+
+static int __devinit frontend_init(struct pluto *pluto)
+{
+ int ret;
+
+ pluto->fe = tda10046_attach(&pluto2_fe_config, &pluto->i2c_adap);
+ if (!pluto->fe) {
+ dev_err(&pluto->pdev->dev, "could not attach frontend\n");
+ return -ENODEV;
+ }
+
+ ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe);
+ if (ret < 0) {
+ if (pluto->fe->ops->release)
+ pluto->fe->ops->release(pluto->fe);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void __devinit pluto_read_rev(struct pluto *pluto)
+{
+ u32 val = pluto_readreg(pluto, REG_MISC) & MISC_DVR;
+ dev_info(&pluto->pdev->dev, "board revision %d.%d\n",
+ (val >> 12) & 0x0f, (val >> 4) & 0xff);
+}
+
+static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac)
+{
+ u32 val = pluto_readreg(pluto, REG_MMAC);
+ mac[0] = (val >> 8) & 0xff;
+ mac[1] = (val >> 0) & 0xff;
+
+ val = pluto_readreg(pluto, REG_IMAC);
+ mac[2] = (val >> 8) & 0xff;
+ mac[3] = (val >> 0) & 0xff;
+
+ val = pluto_readreg(pluto, REG_LMAC);
+ mac[4] = (val >> 8) & 0xff;
+ mac[5] = (val >> 0) & 0xff;
+
+ dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+}
+
+static int __devinit pluto_read_serial(struct pluto *pluto)
+{
+ struct pci_dev *pdev = pluto->pdev;
+ unsigned int i, j;
+ u8 __iomem *cis;
+
+ cis = pci_iomap(pdev, 1, 0);
+ if (!cis)
+ return -EIO;
+
+ dev_info(&pdev->dev, "S/N ");
+
+ for (i = 0xe0; i < 0x100; i += 4) {
+ u32 val = readl(&cis[i]);
+ for (j = 0; j < 32; j += 8) {
+ if ((val & 0xff) == 0xff)
+ goto out;
+ printk("%c", val & 0xff);
+ val >>= 8;
+ }
+ }
+out:
+ printk("\n");
+ pci_iounmap(pdev, cis);
+
+ return 0;
+}
+
+static int __devinit pluto2_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct pluto *pluto;
+ struct dvb_adapter *dvb_adapter;
+ struct dvb_demux *dvbdemux;
+ struct dmx_demux *dmx;
+ int ret = -ENOMEM;
+
+ pluto = kmalloc(sizeof(struct pluto), GFP_KERNEL);
+ if (!pluto)
+ goto out;
+
+ memset(pluto, 0, sizeof(struct pluto));
+ pluto->pdev = pdev;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err_kfree;
+
+ /* enable interrupts */
+ pci_write_config_dword(pdev, 0x6c, 0x8000);
+
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ pluto->io_mem = pci_iomap(pdev, 0, 0x40);
+ if (!pluto->io_mem) {
+ ret = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ pci_set_drvdata(pdev, pluto);
+
+ ret = request_irq(pdev->irq, pluto_irq, SA_SHIRQ, DRIVER_NAME, pluto);
+ if (ret < 0)
+ goto err_pci_iounmap;
+
+ ret = pluto_hw_init(pluto);
+ if (ret < 0)
+ goto err_free_irq;
+
+ /* i2c */
+ i2c_set_adapdata(&pluto->i2c_adap, pluto);
+ strcpy(pluto->i2c_adap.name, DRIVER_NAME);
+ pluto->i2c_adap.owner = THIS_MODULE;
+ pluto->i2c_adap.id = I2C_ALGO_BIT;
+ pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
+ pluto->i2c_adap.dev.parent = &pdev->dev;
+ pluto->i2c_adap.algo_data = &pluto->i2c_bit;
+ pluto->i2c_bit.data = pluto;
+ pluto->i2c_bit.setsda = pluto_setsda;
+ pluto->i2c_bit.setscl = pluto_setscl;
+ pluto->i2c_bit.getsda = pluto_getsda;
+ pluto->i2c_bit.getscl = pluto_getscl;
+ pluto->i2c_bit.udelay = 10;
+ pluto->i2c_bit.timeout = 10;
+
+ /* Raise SCL and SDA */
+ pluto_setsda(pluto, 1);
+ pluto_setscl(pluto, 1);
+
+ ret = i2c_bit_add_bus(&pluto->i2c_adap);
+ if (ret < 0)
+ goto err_pluto_hw_exit;
+
+ /* dvb */
+ ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE);
+ if (ret < 0)
+ goto err_i2c_bit_del_bus;
+
+ dvb_adapter = &pluto->dvb_adapter;
+
+ pluto_read_rev(pluto);
+ pluto_read_serial(pluto);
+ pluto_read_mac(pluto, dvb_adapter->proposed_mac);
+
+ dvbdemux = &pluto->demux;
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = pluto_start_feed;
+ dvbdemux->stop_feed = pluto_stop_feed;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
+ ret = dvb_dmx_init(dvbdemux);
+ if (ret < 0)
+ goto err_dvb_unregister_adapter;
+
+ dmx = &dvbdemux->dmx;
+
+ pluto->hw_frontend.source = DMX_FRONTEND_0;
+ pluto->mem_frontend.source = DMX_MEMORY_FE;
+ pluto->dmxdev.filternum = NHWFILTERS;
+ pluto->dmxdev.demux = dmx;
+
+ ret = dvb_dmxdev_init(&pluto->dmxdev, dvb_adapter);
+ if (ret < 0)
+ goto err_dvb_dmx_release;
+
+ ret = dmx->add_frontend(dmx, &pluto->hw_frontend);
+ if (ret < 0)
+ goto err_dvb_dmxdev_release;
+
+ ret = dmx->add_frontend(dmx, &pluto->mem_frontend);
+ if (ret < 0)
+ goto err_remove_hw_frontend;
+
+ ret = dmx->connect_frontend(dmx, &pluto->hw_frontend);
+ if (ret < 0)
+ goto err_remove_mem_frontend;
+
+ ret = frontend_init(pluto);
+ if (ret < 0)
+ goto err_disconnect_frontend;
+
+ dvb_net_init(dvb_adapter, &pluto->dvbnet, dmx);
+out:
+ return ret;
+
+err_disconnect_frontend:
+ dmx->disconnect_frontend(dmx);
+err_remove_mem_frontend:
+ dmx->remove_frontend(dmx, &pluto->mem_frontend);
+err_remove_hw_frontend:
+ dmx->remove_frontend(dmx, &pluto->hw_frontend);
+err_dvb_dmxdev_release:
+ dvb_dmxdev_release(&pluto->dmxdev);
+err_dvb_dmx_release:
+ dvb_dmx_release(dvbdemux);
+err_dvb_unregister_adapter:
+ dvb_unregister_adapter(dvb_adapter);
+err_i2c_bit_del_bus:
+ i2c_bit_del_bus(&pluto->i2c_adap);
+err_pluto_hw_exit:
+ pluto_hw_exit(pluto);
+err_free_irq:
+ free_irq(pdev->irq, pluto);
+err_pci_iounmap:
+ pci_iounmap(pdev, pluto->io_mem);
+err_pci_release_regions:
+ pci_release_regions(pdev);
+err_pci_disable_device:
+ pci_disable_device(pdev);
+err_kfree:
+ pci_set_drvdata(pdev, NULL);
+ kfree(pluto);
+ goto out;
+}
+
+static void __devexit pluto2_remove(struct pci_dev *pdev)
+{
+ struct pluto *pluto = pci_get_drvdata(pdev);
+ struct dvb_adapter *dvb_adapter = &pluto->dvb_adapter;
+ struct dvb_demux *dvbdemux = &pluto->demux;
+ struct dmx_demux *dmx = &dvbdemux->dmx;
+
+ dmx->close(dmx);
+ dvb_net_release(&pluto->dvbnet);
+ if (pluto->fe)
+ dvb_unregister_frontend(pluto->fe);
+
+ dmx->disconnect_frontend(dmx);
+ dmx->remove_frontend(dmx, &pluto->mem_frontend);
+ dmx->remove_frontend(dmx, &pluto->hw_frontend);
+ dvb_dmxdev_release(&pluto->dmxdev);
+ dvb_dmx_release(dvbdemux);
+ dvb_unregister_adapter(dvb_adapter);
+ i2c_bit_del_bus(&pluto->i2c_adap);
+ pluto_hw_exit(pluto);
+ free_irq(pdev->irq, pluto);
+ pci_iounmap(pdev, pluto->io_mem);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ pci_set_drvdata(pdev, NULL);
+ kfree(pluto);
+}
+
+#ifndef PCI_VENDOR_ID_SCM
+#define PCI_VENDOR_ID_SCM 0x0432
+#endif
+#ifndef PCI_DEVICE_ID_PLUTO2
+#define PCI_DEVICE_ID_PLUTO2 0x0001
+#endif
+
+static struct pci_device_id pluto2_id_table[] __devinitdata = {
+ {
+ .vendor = PCI_VENDOR_ID_SCM,
+ .device = PCI_DEVICE_ID_PLUTO2,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ }, {
+ /* empty */
+ },
+};
+
+MODULE_DEVICE_TABLE(pci, pluto2_id_table);
+
+static struct pci_driver pluto2_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pluto2_id_table,
+ .probe = pluto2_probe,
+ .remove = __devexit_p(pluto2_remove),
+};
+
+static int __init pluto2_init(void)
+{
+ return pci_register_driver(&pluto2_driver);
+}
+
+static void __exit pluto2_exit(void)
+{
+ pci_unregister_driver(&pluto2_driver);
+}
+
+module_init(pluto2_init);
+module_exit(pluto2_exit);
+
+MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
+MODULE_DESCRIPTION("Pluto2 driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index 7ffa2c7315b3..bf3c011d2cfb 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -12,7 +12,7 @@ config DVB_AV7110
select DVB_STV0297
select DVB_L64781
help
- Support for SAA7146 and AV7110 based DVB cards as produced
+ Support for SAA7146 and AV7110 based DVB cards as produced
by Fujitsu-Siemens, Technotrend, Hauppauge and others.
This driver only supports the fullfeatured cards with
@@ -33,7 +33,7 @@ config DVB_AV7110_FIRMWARE
If you want to compile the firmware into the driver you need to say
Y here and provide the correct path of the firmware. You need this
option if you want to compile the whole driver statically into the
- kernel.
+ kernel.
All other people say N.
@@ -66,6 +66,7 @@ config DVB_BUDGET
select DVB_L64781
select DVB_TDA8083
select DVB_TDA10021
+ select DVB_S5H1420
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
@@ -119,9 +120,9 @@ config DVB_BUDGET_PATCH
select DVB_VES1X93
select DVB_TDA8083
help
- Support for Budget Patch (full TS) modification on
+ Support for Budget Patch (full TS) modification on
SAA7146+AV7110 based cards (DVB-S cards). This
- driver doesn't use onboard MPEG2 decoder. The
+ driver doesn't use onboard MPEG2 decoder. The
card is driven in Budget-only mode. Card is
required to have loaded firmware to tune properly.
Firmware can be loaded by insertion and removal of
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index 8e33a850e13e..e4c6e87f6c5d 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -116,13 +116,18 @@ static int av7110_num = 0;
static void init_av7110_av(struct av7110 *av7110)
{
+ int ret;
struct saa7146_dev *dev = av7110->dev;
/* set internal volume control to maximum */
av7110->adac_type = DVB_ADAC_TI;
- av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
- av7710_set_video_mode(av7110, vidmode);
+ ret = av7710_set_video_mode(av7110, vidmode);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set video mode:%d\n",ret);
/* handle different card types */
/* remaining inits according to card and frontend type */
@@ -156,8 +161,12 @@ static void init_av7110_av(struct av7110 *av7110)
if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP) {
// switch DVB SCART on
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+ ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
+ ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
if (rgb_on &&
(av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI); // RGB on, SCART pin 16
@@ -165,8 +174,12 @@ static void init_av7110_av(struct av7110 *av7110)
}
}
- av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
- av7110_setup_irc_config(av7110, 0);
+ ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot set volume :%d\n",ret);
+ ret = av7110_setup_irc_config(av7110, 0);
+ if (ret < 0)
+ printk("dvb-ttpci:cannot setup irc config :%d\n",ret);
}
static void recover_arm(struct av7110 *av7110)
@@ -258,8 +271,9 @@ static int arm_thread(void *data)
*
* If we want to support multiple controls we would have to do much more...
*/
-void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
+int av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
{
+ int ret = 0;
static struct av7110 *last;
dprintk(4, "%p\n", av7110);
@@ -270,9 +284,10 @@ void av7110_setup_irc_config(struct av7110 *av7110, u32 ir_config)
last = av7110;
if (av7110) {
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetIR, 1, ir_config);
av7110->ir_config = ir_config;
}
+ return ret;
}
static void (*irc_handler)(u32);
@@ -765,13 +780,14 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
pcrpid, vpid, apid, ttpid, subpid);
}
-void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid)
{
+ int ret = 0;
dprintk(4, "%p\n", av7110);
if (down_interruptible(&av7110->pid_mutex))
- return;
+ return -ERESTARTSYS;
if (!(vpid & 0x8000))
av7110->pids[DMX_PES_VIDEO] = vpid;
@@ -786,10 +802,11 @@ void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
if (av7110->fe_synced) {
pcrpid = av7110->pids[DMX_PES_PCR];
- SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
+ ret = SetPIDs(av7110, vpid, apid, ttpid, subpid, pcrpid);
}
up(&av7110->pid_mutex);
+ return ret;
}
@@ -832,11 +849,13 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
if (ret != 0 || handle >= 32) {
printk("dvb-ttpci: %s error buf %04x %04x %04x %04x "
- "ret %x handle %04x\n",
+ "ret %d handle %04x\n",
__FUNCTION__, buf[0], buf[1], buf[2], buf[3],
ret, handle);
dvbdmxfilter->hw_handle = 0xffff;
- return -1;
+ if (!ret)
+ ret = -1;
+ return ret;
}
av7110->handle2filter[handle] = dvbdmxfilter;
@@ -859,7 +878,7 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
if (handle >= 32) {
printk("%s tried to stop invalid filter %04x, filter type = %x\n",
__FUNCTION__, handle, dvbdmxfilter->type);
- return 0;
+ return -EINVAL;
}
av7110->handle2filter[handle] = NULL;
@@ -873,18 +892,20 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
"resp %04x %04x pid %d\n",
__FUNCTION__, buf[0], buf[1], buf[2], ret,
answ[0], answ[1], dvbdmxfilter->feed->pid);
- ret = -1;
+ if (!ret)
+ ret = -1;
}
return ret;
}
-static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
+ int ret = 0;
dprintk(4, "%p\n", av7110);
@@ -893,36 +914,49 @@ static void dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
npids[i] = 0;
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
- StartHWFilter(dvbdmxfeed->filter);
- return;
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (!ret)
+ ret = StartHWFilter(dvbdmxfeed->filter);
+ return ret;
+ }
+ if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4) {
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (ret)
+ return ret;
}
- if (dvbdmxfeed->pes_type <= 2 || dvbdmxfeed->pes_type == 4)
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
if (dvbdmxfeed->pes_type < 2 && npids[0])
if (av7110->fe_synced)
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ {
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (ret)
+ return ret;
+ }
if ((dvbdmxfeed->ts_type & TS_PACKET)) {
if (dvbdmxfeed->pes_type == 0 && !(dvbdmx->pids[0] & 0x8000))
- av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
+ ret = av7110_av_start_record(av7110, RP_AUDIO, dvbdmxfeed);
if (dvbdmxfeed->pes_type == 1 && !(dvbdmx->pids[1] & 0x8000))
- av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
+ ret = av7110_av_start_record(av7110, RP_VIDEO, dvbdmxfeed);
}
+ return ret;
}
-static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
+static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
struct av7110 *av7110 = (struct av7110 *) dvbdmx->priv;
u16 *pid = dvbdmx->pids, npids[5];
int i;
+ int ret = 0;
+
dprintk(4, "%p\n", av7110);
if (dvbdmxfeed->pes_type <= 1) {
- av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO);
+ ret = av7110_av_stop(av7110, dvbdmxfeed->pes_type ? RP_VIDEO : RP_AUDIO);
+ if (ret)
+ return ret;
if (!av7110->rec_mode)
dvbdmx->recording = 0;
if (!av7110->playing)
@@ -933,24 +967,27 @@ static void dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
switch (i) {
case 2: //teletext
if (dvbdmxfeed->ts_type & TS_PACKET)
- StopHWFilter(dvbdmxfeed->filter);
+ ret = StopHWFilter(dvbdmxfeed->filter);
npids[2] = 0;
break;
case 0:
case 1:
case 4:
if (!pids_off)
- return;
+ return 0;
npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
break;
}
- ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ if (!ret)
+ ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
+ return ret;
}
static int av7110_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
+ int ret = 0;
dprintk(4, "%p\n", av7110);
@@ -971,21 +1008,22 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
!(demux->pids[1] & 0x8000)) {
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
- av7110_av_start_play(av7110,RP_AV);
- demux->playing = 1;
+ ret = av7110_av_start_play(av7110,RP_AV);
+ if (!ret)
+ demux->playing = 1;
}
break;
default:
- dvb_feed_start_pid(feed);
+ ret = dvb_feed_start_pid(feed);
break;
}
} else if ((feed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE)) {
- StartHWFilter(feed->filter);
+ ret = StartHWFilter(feed->filter);
}
}
- if (feed->type == DMX_TYPE_SEC) {
+ else if (feed->type == DMX_TYPE_SEC) {
int i;
for (i = 0; i < demux->filternum; i++) {
@@ -996,12 +1034,15 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
if (demux->filter[i].filter.parent != &feed->feed.sec)
continue;
demux->filter[i].state = DMX_STATE_GO;
- if (demux->dmx.frontend->source != DMX_MEMORY_FE)
- StartHWFilter(&demux->filter[i]);
+ if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+ ret = StartHWFilter(&demux->filter[i]);
+ if (ret)
+ break;
+ }
}
}
- return 0;
+ return ret;
}
@@ -1009,7 +1050,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
-
+ int i, rc, ret = 0;
dprintk(4, "%p\n", av7110);
if (feed->type == DMX_TYPE_TS) {
@@ -1022,26 +1063,29 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
}
if (feed->ts_type & TS_DECODER &&
feed->pes_type < DMX_TS_PES_OTHER) {
- dvb_feed_stop_pid(feed);
+ ret = dvb_feed_stop_pid(feed);
} else
if ((feed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE))
- StopHWFilter(feed->filter);
+ ret = StopHWFilter(feed->filter);
}
- if (feed->type == DMX_TYPE_SEC) {
- int i;
-
- for (i = 0; i<demux->filternum; i++)
+ if (!ret && feed->type == DMX_TYPE_SEC) {
+ for (i = 0; i<demux->filternum; i++) {
if (demux->filter[i].state == DMX_STATE_GO &&
demux->filter[i].filter.parent == &feed->feed.sec) {
demux->filter[i].state = DMX_STATE_READY;
- if (demux->dmx.frontend->source != DMX_MEMORY_FE)
- StopHWFilter(&demux->filter[i]);
+ if (demux->dmx.frontend->source != DMX_MEMORY_FE) {
+ rc = StopHWFilter(&demux->filter[i]);
+ if (!ret)
+ ret = rc;
+ /* keep going, stop as many filters as possible */
+ }
+ }
}
}
- return 0;
+ return ret;
}
@@ -1093,7 +1137,7 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
if (ret) {
printk(KERN_ERR "%s: av7110_fw_request error\n", __FUNCTION__);
- return -EIO;
+ return ret;
}
dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
@@ -1119,18 +1163,14 @@ static int av7110_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
- Set22K(av7110, 1);
- break;
+ return Set22K(av7110, 1);
case SEC_TONE_OFF:
- Set22K(av7110, 0);
- break;
+ return Set22K(av7110, 0);
default:
return -EINVAL;
}
-
- return 0;
}
static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -1138,9 +1178,7 @@ static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
-
- return 0;
+ return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
}
static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
@@ -1148,9 +1186,7 @@ static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_diseqc_send(av7110, 0, NULL, minicmd);
-
- return 0;
+ return av7110_diseqc_send(av7110, 0, NULL, minicmd);
}
/* simplified code from budget-core.c */
@@ -1992,76 +2028,85 @@ static struct l64781_config grundig_29504_401_config = {
-static void av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
+static int av7110_fe_lock_fix(struct av7110* av7110, fe_status_t status)
{
+ int ret = 0;
int synced = (status & FE_HAS_LOCK) ? 1 : 0;
av7110->fe_status = status;
if (av7110->fe_synced == synced)
- return;
-
- av7110->fe_synced = synced;
+ return 0;
if (av7110->playing)
- return;
+ return 0;
if (down_interruptible(&av7110->pid_mutex))
- return;
+ return -ERESTARTSYS;
- if (av7110->fe_synced) {
- SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ if (synced) {
+ ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT], 0,
av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (!ret)
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
} else {
- SetPIDs(av7110, 0, 0, 0, 0, 0);
- av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
- av7110_wait_msgstate(av7110, GPMQBusy);
+ ret = SetPIDs(av7110, 0, 0, 0, 0, 0);
+ if (!ret) {
+ ret = av7110_fw_cmd(av7110, COMTYPE_PID_FILTER, FlushTSQueue, 0);
+ if (!ret)
+ ret = av7110_wait_msgstate(av7110, GPMQBusy);
+ }
}
+ if (!ret)
+ av7110->fe_synced = synced;
+
up(&av7110->pid_mutex);
+ return ret;
}
static int av7110_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_frontend(fe, params);
+
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_frontend(fe, params);
+ return ret;
}
static int av7110_fe_init(struct dvb_frontend* fe)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_init(fe);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_init(fe);
+ return ret;
}
static int av7110_fe_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct av7110* av7110 = fe->dvb->priv;
- int ret;
/* call the real implementation */
- ret = av7110->fe_read_status(fe, status);
- if (ret)
- return ret;
-
- if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK)) {
- av7110_fe_lock_fix(av7110, *status);
- }
-
- return 0;
+ int ret = av7110->fe_read_status(fe, status);
+ if (!ret)
+ if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
+ ret = av7110_fe_lock_fix(av7110, *status);
+ return ret;
}
static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_reset_overload(fe);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_reset_overload(fe);
+ return ret;
}
static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
@@ -2069,40 +2114,50 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_send_master_cmd(fe, cmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
+ return ret;
}
static int av7110_fe_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_diseqc_send_burst(fe, minicmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_diseqc_send_burst(fe, minicmd);
+ return ret;
}
static int av7110_fe_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_tone(fe, tone);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_tone(fe, tone);
+ return ret;
}
static int av7110_fe_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_set_voltage(fe, voltage);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_set_voltage(fe, voltage);
+ return ret;
}
static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned int cmd)
{
struct av7110* av7110 = fe->dvb->priv;
- av7110_fe_lock_fix(av7110, 0);
- return av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+ int ret = av7110_fe_lock_fix(av7110, 0);
+ if (!ret)
+ ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
+ return ret;
}
static u8 read_pwm(struct av7110* av7110)
diff --git a/drivers/media/dvb/ttpci/av7110.h b/drivers/media/dvb/ttpci/av7110.h
index 4f69b4d01479..508b7739c609 100644
--- a/drivers/media/dvb/ttpci/av7110.h
+++ b/drivers/media/dvb/ttpci/av7110.h
@@ -119,8 +119,7 @@ struct av7110 {
volatile int bmp_state;
#define BMP_NONE 0
#define BMP_LOADING 1
-#define BMP_LOADINGS 2
-#define BMP_LOADED 3
+#define BMP_LOADED 2
wait_queue_head_t bmpq;
@@ -255,12 +254,12 @@ struct av7110 {
};
-extern void ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid);
extern void av7110_register_irc_handler(void (*func)(u32));
extern void av7110_unregister_irc_handler(void (*func)(u32));
-extern void av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
+extern int av7110_setup_irc_config (struct av7110 *av7110, u32 ir_config);
extern int av7110_ir_init (void);
extern void av7110_ir_exit (void);
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index ccf946125d02..0696a5a4f855 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -121,6 +121,7 @@ static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
int av7110_av_start_record(struct av7110 *av7110, int av,
struct dvb_demux_feed *dvbdmxfeed)
{
+ int ret = 0;
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
dprintk(2, "av7110:%p, , dvb_demux_feed:%p\n", av7110, dvbdmxfeed);
@@ -137,7 +138,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[0]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[0]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
break;
case RP_VIDEO:
@@ -145,7 +146,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[1]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
break;
case RP_AV:
@@ -157,14 +158,15 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
(void *) dvbdmx->pesfilter[1]);
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
break;
}
- return 0;
+ return ret;
}
int av7110_av_start_play(struct av7110 *av7110, int av)
{
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (av7110->rec_mode)
@@ -182,54 +184,57 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
av7110->playing |= av;
switch (av7110->playing) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
av7110->sinfo = 0;
break;
case RP_AV:
av7110->sinfo = 0;
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AV_PES, 0);
break;
}
- return av7110->playing;
+ if (!ret)
+ ret = av7110->playing;
+ return ret;
}
-void av7110_av_stop(struct av7110 *av7110, int av)
+int av7110_av_stop(struct av7110 *av7110, int av)
{
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (!(av7110->playing & av) && !(av7110->rec_mode & av))
- return;
-
+ return 0;
av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
if (av7110->playing) {
av7110->playing &= ~av;
switch (av7110->playing) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Play, 2, VideoPES, 0);
break;
case RP_NONE:
- av7110_set_vidmode(av7110, av7110->vidmode);
+ ret = av7110_set_vidmode(av7110, av7110->vidmode);
break;
}
} else {
av7110->rec_mode &= ~av;
switch (av7110->rec_mode) {
case RP_AUDIO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
break;
case RP_VIDEO:
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
break;
case RP_NONE:
break;
}
}
+ return ret;
}
@@ -317,19 +322,22 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright)
return 0;
}
-void av7110_set_vidmode(struct av7110 *av7110, int mode)
+int av7110_set_vidmode(struct av7110 *av7110, int mode)
{
+ int ret;
dprintk(2, "av7110:%p, \n", av7110);
- av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
+ ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
- if (!av7110->playing) {
- ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
+ if (!ret && !av7110->playing) {
+ ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT],
0, av7110->pids[DMX_PES_PCR]);
- av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
+ if (!ret)
+ ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
}
+ return ret;
}
@@ -340,17 +348,18 @@ static int sw2mode[16] = {
VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL, VIDEO_MODE_PAL,
};
-static void get_video_format(struct av7110 *av7110, u8 *buf, int count)
+static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
{
int i;
int hsize, vsize;
int sw;
u8 *p;
+ int ret = 0;
dprintk(2, "av7110:%p, \n", av7110);
if (av7110->sinfo)
- return;
+ return 0;
for (i = 7; i < count - 10; i++) {
p = buf + i;
if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
@@ -359,11 +368,14 @@ static void get_video_format(struct av7110 *av7110, u8 *buf, int count)
hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
vsize = ((p[1] &0x0F) << 8) | (p[2]);
sw = (p[3] & 0x0F);
- av7110_set_vidmode(av7110, sw2mode[sw]);
- dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
- av7110->sinfo = 1;
+ ret = av7110_set_vidmode(av7110, sw2mode[sw]);
+ if (!ret) {
+ dprintk(2, "playback %dx%d fr=%d\n", hsize, vsize, sw);
+ av7110->sinfo = 1;
+ }
break;
}
+ return ret;
}
@@ -974,7 +986,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
unsigned long arg = (unsigned long) parg;
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
@@ -987,49 +999,57 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_STOP:
av7110->videostate.play_state = VIDEO_STOPPED;
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY)
- av7110_av_stop(av7110, RP_VIDEO);
+ ret = av7110_av_stop(av7110, RP_VIDEO);
else
- vidcom(av7110, VIDEO_CMD_STOP,
+ ret = vidcom(av7110, VIDEO_CMD_STOP,
av7110->videostate.video_blank ? 0 : 1);
- av7110->trickmode = TRICK_NONE;
+ if (!ret)
+ av7110->trickmode = TRICK_NONE;
break;
case VIDEO_PLAY:
av7110->trickmode = TRICK_NONE;
if (av7110->videostate.play_state == VIDEO_FREEZED) {
av7110->videostate.play_state = VIDEO_PLAYING;
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (ret)
+ break;
}
if (av7110->videostate.stream_source == VIDEO_SOURCE_MEMORY) {
if (av7110->playing == RP_AV) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Stop, 0);
+ if (ret)
+ break;
av7110->playing &= ~RP_VIDEO;
}
- av7110_av_start_play(av7110, RP_VIDEO);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- } else {
- //av7110_av_stop(av7110, RP_VIDEO);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ ret = av7110_av_start_play(av7110, RP_VIDEO);
}
- av7110->videostate.play_state = VIDEO_PLAYING;
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret)
+ av7110->videostate.play_state = VIDEO_PLAYING;
break;
case VIDEO_FREEZE:
av7110->videostate.play_state = VIDEO_FREEZED;
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Pause, 0);
else
- vidcom(av7110, VIDEO_CMD_FREEZE, 1);
- av7110->trickmode = TRICK_FREEZE;
+ ret = vidcom(av7110, VIDEO_CMD_FREEZE, 1);
+ if (!ret)
+ av7110->trickmode = TRICK_FREEZE;
break;
case VIDEO_CONTINUE:
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- av7110->videostate.play_state = VIDEO_PLAYING;
- av7110->trickmode = TRICK_NONE;
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Continue, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret) {
+ av7110->videostate.play_state = VIDEO_PLAYING;
+ av7110->trickmode = TRICK_NONE;
+ }
break;
case VIDEO_SELECT_SOURCE:
@@ -1045,7 +1065,7 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
break;
case VIDEO_GET_EVENT:
- ret=dvb_video_get_event(av7110, parg, file->f_flags);
+ ret = dvb_video_get_event(av7110, parg, file->f_flags);
break;
case VIDEO_GET_SIZE:
@@ -1105,25 +1125,32 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
case VIDEO_FAST_FORWARD:
//note: arg is ignored by firmware
if (av7110->playing & RP_VIDEO)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Scan_I, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Scan_I, 2, AV_PES, 0);
else
- vidcom(av7110, VIDEO_CMD_FFWD, arg);
- av7110->trickmode = TRICK_FAST;
- av7110->videostate.play_state = VIDEO_PLAYING;
+ ret = vidcom(av7110, VIDEO_CMD_FFWD, arg);
+ if (!ret) {
+ av7110->trickmode = TRICK_FAST;
+ av7110->videostate.play_state = VIDEO_PLAYING;
+ }
break;
case VIDEO_SLOWMOTION:
if (av7110->playing&RP_VIDEO) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
} else {
- vidcom(av7110, VIDEO_CMD_PLAY, 0);
- vidcom(av7110, VIDEO_CMD_STOP, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = vidcom(av7110, VIDEO_CMD_PLAY, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_STOP, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ }
+ if (!ret) {
+ av7110->trickmode = TRICK_SLOW;
+ av7110->videostate.play_state = VIDEO_PLAYING;
}
- av7110->trickmode = TRICK_SLOW;
- av7110->videostate.play_state = VIDEO_PLAYING;
break;
case VIDEO_GET_CAPABILITIES:
@@ -1136,18 +1163,21 @@ static int dvb_video_ioctl(struct inode *inode, struct file *file,
av7110_ipack_reset(&av7110->ipack[1]);
if (av7110->playing == RP_AV) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Play, 2, AV_PES, 0);
+ if (ret)
+ break;
if (av7110->trickmode == TRICK_FAST)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Scan_I, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Scan_I, 2, AV_PES, 0);
if (av7110->trickmode == TRICK_SLOW) {
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Slow, 2, 0, 0);
- vidcom(av7110, VIDEO_CMD_SLOW, arg);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Slow, 2, 0, 0);
+ if (!ret)
+ ret = vidcom(av7110, VIDEO_CMD_SLOW, arg);
}
if (av7110->trickmode == TRICK_FREEZE)
- vidcom(av7110, VIDEO_CMD_STOP, 1);
+ ret = vidcom(av7110, VIDEO_CMD_STOP, 1);
}
break;
@@ -1170,7 +1200,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
unsigned long arg = (unsigned long) parg;
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
(cmd != AUDIO_GET_STATUS))
@@ -1179,28 +1209,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case AUDIO_STOP:
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
- av7110_av_stop(av7110, RP_AUDIO);
+ ret = av7110_av_stop(av7110, RP_AUDIO);
else
- audcom(av7110, AUDIO_CMD_MUTE);
- av7110->audiostate.play_state = AUDIO_STOPPED;
+ ret = audcom(av7110, AUDIO_CMD_MUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_STOPPED;
break;
case AUDIO_PLAY:
if (av7110->audiostate.stream_source == AUDIO_SOURCE_MEMORY)
- av7110_av_start_play(av7110, RP_AUDIO);
- audcom(av7110, AUDIO_CMD_UNMUTE);
- av7110->audiostate.play_state = AUDIO_PLAYING;
+ ret = av7110_av_start_play(av7110, RP_AUDIO);
+ if (!ret)
+ ret = audcom(av7110, AUDIO_CMD_UNMUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_PLAYING;
break;
case AUDIO_PAUSE:
- audcom(av7110, AUDIO_CMD_MUTE);
- av7110->audiostate.play_state = AUDIO_PAUSED;
+ ret = audcom(av7110, AUDIO_CMD_MUTE);
+ if (!ret)
+ av7110->audiostate.play_state = AUDIO_PAUSED;
break;
case AUDIO_CONTINUE:
if (av7110->audiostate.play_state == AUDIO_PAUSED) {
av7110->audiostate.play_state = AUDIO_PLAYING;
- audcom(av7110, AUDIO_CMD_MUTE | AUDIO_CMD_PCM16);
+ ret = audcom(av7110, AUDIO_CMD_UNMUTE | AUDIO_CMD_PCM16);
}
break;
@@ -1210,14 +1244,15 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
case AUDIO_SET_MUTE:
{
- audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
- av7110->audiostate.mute_state = (int) arg;
+ ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
+ if (!ret)
+ av7110->audiostate.mute_state = (int) arg;
break;
}
case AUDIO_SET_AV_SYNC:
av7110->audiostate.AV_sync_state = (int) arg;
- audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
+ ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
break;
case AUDIO_SET_BYPASS_MODE:
@@ -1229,21 +1264,24 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
switch(av7110->audiostate.channel_select) {
case AUDIO_STEREO:
- audcom(av7110, AUDIO_CMD_STEREO);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x49);
+ ret = audcom(av7110, AUDIO_CMD_STEREO);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x49);
break;
case AUDIO_MONO_LEFT:
- audcom(av7110, AUDIO_CMD_MONO_L);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x4a);
+ ret = audcom(av7110, AUDIO_CMD_MONO_L);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x4a);
break;
case AUDIO_MONO_RIGHT:
- audcom(av7110, AUDIO_CMD_MONO_R);
- if (av7110->adac_type == DVB_ADAC_CRYSTAL)
- i2c_writereg(av7110, 0x20, 0x02, 0x45);
+ ret = audcom(av7110, AUDIO_CMD_MONO_R);
+ if (!ret)
+ if (av7110->adac_type == DVB_ADAC_CRYSTAL)
+ i2c_writereg(av7110, 0x20, 0x02, 0x45);
break;
default:
@@ -1264,8 +1302,8 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
av7110_ipack_reset(&av7110->ipack[0]);
if (av7110->playing == RP_AV)
- av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
- __Play, 2, AV_PES, 0);
+ ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY,
+ __Play, 2, AV_PES, 0);
break;
case AUDIO_SET_ID:
@@ -1274,7 +1312,7 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file,
{
struct audio_mixer *amix = (struct audio_mixer *)parg;
- av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
+ ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
break;
}
case AUDIO_SET_STREAMTYPE:
diff --git a/drivers/media/dvb/ttpci/av7110_av.h b/drivers/media/dvb/ttpci/av7110_av.h
index cc5e7a7e87c3..45dc144b8b43 100644
--- a/drivers/media/dvb/ttpci/av7110_av.h
+++ b/drivers/media/dvb/ttpci/av7110_av.h
@@ -3,14 +3,14 @@
struct av7110;
-extern void av7110_set_vidmode(struct av7110 *av7110, int mode);
+extern int av7110_set_vidmode(struct av7110 *av7110, int mode);
extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
extern int av7110_set_volume(struct av7110 *av7110, int volleft, int volright);
-extern void av7110_av_stop(struct av7110 *av7110, int av);
+extern int av7110_av_stop(struct av7110 *av7110, int av);
extern int av7110_av_start_record(struct av7110 *av7110, int av,
struct dvb_demux_feed *dvbdmxfeed);
extern int av7110_av_start_play(struct av7110 *av7110, int av);
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index 7fa4a0ebe133..1220826696c5 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -137,7 +137,7 @@ static int waitdebi(struct av7110 *av7110, int adr, int state)
return 0;
udelay(5);
}
- return -1;
+ return -ETIMEDOUT;
}
static int load_dram(struct av7110 *av7110, u32 *data, int len)
@@ -155,7 +155,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
for (i = 0; i < blocks; i++) {
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
- return -1;
+ return -ETIMEDOUT;
}
dprintk(4, "writing DRAM block %d\n", i);
mwdebi(av7110, DEBISWAB, bootblock,
@@ -170,7 +170,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
if (rest > 0) {
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
- return -1;
+ return -ETIMEDOUT;
}
if (rest > 4)
mwdebi(av7110, DEBISWAB, bootblock,
@@ -185,13 +185,13 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
}
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
- return -1;
+ return -ETIMEDOUT;
}
iwdebi(av7110, DEBINOSWAP, BOOT_SIZE, 0, 2);
iwdebi(av7110, DEBINOSWAP, BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
if (waitdebi(av7110, BOOT_STATE, BOOTSTATE_BOOT_COMPLETE) < 0) {
printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
- return -1;
+ return -ETIMEDOUT;
}
return 0;
}
@@ -263,7 +263,7 @@ int av7110_bootarm(struct av7110 *av7110)
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
"saa7146_wait_for_debi_done() timed out\n");
- return -1;
+ return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
mdelay(1);
@@ -284,7 +284,7 @@ int av7110_bootarm(struct av7110 *av7110)
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): "
"saa7146_wait_for_debi_done() timed out after loading DRAM\n");
- return -1;
+ return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
msleep(30); /* the firmware needs some time to initialize */
@@ -308,6 +308,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
{
unsigned long start;
u32 stat;
+ int err;
if (FW_VERSION(av7110->arm_app) <= 0x261c) {
/* not supported by old firmware */
@@ -318,17 +319,17 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
/* new firmware */
start = jiffies;
for (;;) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
if (down_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
up(&av7110->dcomlock);
- if ((stat & flags) == 0) {
+ if ((stat & flags) == 0)
break;
- }
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
__FUNCTION__, stat & flags);
- return -1;
+ return -ETIMEDOUT;
}
msleep(1);
}
@@ -342,6 +343,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
char *type = NULL;
u16 flags[2] = {0, 0};
u32 stat;
+ int err;
// dprintk(4, "%p\n", av7110);
@@ -351,24 +353,30 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
}
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __FUNCTION__);
return -ETIMEDOUT;
}
+ msleep(1);
}
wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0xffff, 2);
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
@@ -401,6 +409,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
/* non-immediate COMMAND type */
start = jiffies;
for (;;) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & flags[0]) {
printk(KERN_ERR "%s: %s QUEUE overflow\n",
@@ -409,10 +418,10 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
}
if ((stat & flags[1]) == 0)
break;
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ if (err) {
printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
__FUNCTION__, type);
- return -1;
+ return -ETIMEDOUT;
}
msleep(1);
}
@@ -432,13 +441,16 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
#ifdef COM_DEBUG
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND to complete\n",
- __FUNCTION__);
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
+ printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+ __FUNCTION__, (buf[0] >> 8) & 0xff);
return -ETIMEDOUT;
}
+ msleep(1);
}
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
@@ -470,7 +482,7 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
ret = __av7110_send_fw_cmd(av7110, buf, length);
up(&av7110->dcomlock);
- if (ret)
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
__FUNCTION__, ret);
return ret;
@@ -495,7 +507,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
}
ret = av7110_send_fw_cmd(av7110, buf, num + 2);
- if (ret)
+ if (ret && ret != -ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
return ret;
}
@@ -518,7 +530,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
}
ret = av7110_send_fw_cmd(av7110, cmd, 18);
- if (ret)
+ if (ret && ret != -ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
return ret;
}
@@ -551,26 +563,32 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
}
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2)) {
-#ifdef _NOHANDSHAKE
- msleep(1);
-#endif
- if (time_after(jiffies, start + ARM_WAIT_FREE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_FREE);
+ if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+#ifdef _NOHANDSHAKE
+ msleep(1);
+#endif
}
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2 )) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
@@ -667,10 +685,10 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
for (i = 0; i < len; i++)
buf[i + 4] = msg[i];
- if ((ret = av7110_send_fw_cmd(av7110, buf, 18)))
+ ret = av7110_send_fw_cmd(av7110, buf, 18);
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
-
- return 0;
+ return ret;
}
@@ -705,18 +723,22 @@ static inline int SetFont(struct av7110 *av7110, u8 windownr, u8 fontsize,
static int FlushText(struct av7110 *av7110)
{
unsigned long start;
+ int err;
if (down_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+ while (1) {
+ err = time_after(jiffies, start + ARM_WAIT_OSD);
+ if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+ break;
+ if (err) {
printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
up(&av7110->dcomlock);
return 0;
@@ -733,25 +755,31 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
return -ERESTARTSYS;
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_OSD)) {
+ while (1) {
+ ret = time_after(jiffies, start + ARM_WAIT_OSD);
+ if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
+ break;
+ if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#ifndef _NOHANDSHAKE
start = jiffies;
- while (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2)) {
- msleep(1);
- if (time_after(jiffies, start + ARM_WAIT_SHAKE)) {
+ while (1) {
+ ret = time_after(jiffies, start + ARM_WAIT_SHAKE);
+ if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
+ break;
+ if (ret) {
printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
__FUNCTION__);
up(&av7110->dcomlock);
- return -1;
+ return -ETIMEDOUT;
}
+ msleep(1);
}
#endif
for (i = 0; i < length / 2; i++)
@@ -761,7 +789,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, u8* buf)
wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
up(&av7110->dcomlock);
- if (ret)
+ if (ret && ret!=-ERESTARTSYS)
printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
return ret;
}
@@ -816,9 +844,25 @@ static osd_raw_window_t bpp2bit[8] = {
OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
};
-static inline int LoadBitmap(struct av7110 *av7110, u16 format,
+static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
+{
+ int ret = wait_event_interruptible_timeout(av7110->bmpq,
+ av7110->bmp_state != BMP_LOADING, 10*HZ);
+ if (ret == -ERESTARTSYS)
+ return ret;
+ if (ret == 0) {
+ printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
+ ret, av7110->bmp_state);
+ av7110->bmp_state = BMP_NONE;
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static inline int LoadBitmap(struct av7110 *av7110,
u16 dx, u16 dy, int inc, u8 __user * data)
{
+ u16 format;
int bpp;
int i;
int d, delta;
@@ -827,14 +871,7 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
dprintk(4, "%p\n", av7110);
- ret = wait_event_interruptible_timeout(av7110->bmpq, av7110->bmp_state != BMP_LOADING, HZ);
- if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
- ret, av7110->bmp_state);
- av7110->bmp_state = BMP_NONE;
- return -1;
- }
- BUG_ON (av7110->bmp_state == BMP_LOADING);
+ format = bpp2bit[av7110->osdbpp[av7110->osdwin]];
av7110->bmp_state = BMP_LOADING;
if (format == OSD_BITMAP8) {
@@ -847,18 +884,18 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
bpp=1; delta = 8;
} else {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
av7110->bmplen = ((dx * dy * bpp + 7) & ~7) / 8;
av7110->bmpp = 0;
if (av7110->bmplen > 32768) {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
for (i = 0; i < dy; i++) {
if (copy_from_user(av7110->bmpbuf + 1024 + i * dx, data + i * inc, dx)) {
av7110->bmp_state = BMP_NONE;
- return -1;
+ return -EINVAL;
}
}
if (format != OSD_BITMAP8) {
@@ -873,37 +910,27 @@ static inline int LoadBitmap(struct av7110 *av7110, u16 format,
}
av7110->bmplen += 1024;
dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
- return av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+ ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
+ if (!ret)
+ ret = WaitUntilBmpLoaded(av7110);
+ return ret;
}
-static int BlitBitmap(struct av7110 *av7110, u16 win, u16 x, u16 y, u16 trans)
+static int BlitBitmap(struct av7110 *av7110, u16 x, u16 y)
{
- int ret;
-
dprintk(4, "%p\n", av7110);
- BUG_ON (av7110->bmp_state == BMP_NONE);
-
- ret = wait_event_interruptible_timeout(av7110->bmpq,
- av7110->bmp_state != BMP_LOADING, 10*HZ);
- if (ret == -ERESTARTSYS || ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in BlitBitmap: %d, %d\n",
- ret, av7110->bmp_state);
- av7110->bmp_state = BMP_NONE;
- return (ret == 0) ? -ETIMEDOUT : ret;
- }
-
- BUG_ON (av7110->bmp_state != BMP_LOADED);
-
- return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, win, x, y, trans);
+ return av7110_fw_cmd(av7110, COMTYPE_OSD, BlitBmp, 4, av7110->osdwin, x, y, 0);
}
static inline int ReleaseBitmap(struct av7110 *av7110)
{
dprintk(4, "%p\n", av7110);
- if (av7110->bmp_state != BMP_LOADED)
+ if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
return -1;
+ if (av7110->bmp_state == BMP_LOADING)
+ dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
av7110->bmp_state = BMP_NONE;
return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
}
@@ -924,18 +951,22 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B)
return Cr | (Cb << 16) | (Y << 8);
}
-static void OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
+static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 blend)
{
+ int ret;
+
u16 ch, cl;
u32 yuv;
yuv = blend ? RGB2YUV(r,g,b) : 0;
cl = (yuv & 0xffff);
ch = ((yuv >> 16) & 0xffff);
- SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
- color, ch, cl);
- SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
- color, ((blend >> 4) & 0x0f));
+ ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+ color, ch, cl);
+ if (!ret)
+ ret = SetBlend_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
+ color, ((blend >> 4) & 0x0f));
+ return ret;
}
static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
@@ -968,14 +999,14 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
{
uint w, h, bpp, bpl, size, lpb, bnum, brest;
int i;
- int rc;
+ int rc,release_rc;
w = x1 - x0 + 1;
h = y1 - y0 + 1;
if (inc <= 0)
inc = w;
if (w <= 0 || w > 720 || h <= 0 || h > 576)
- return -1;
+ return -EINVAL;
bpp = av7110->osdbpp[av7110->osdwin] + 1;
bpl = ((w * bpp + 7) & ~7) / 8;
size = h * bpl;
@@ -983,176 +1014,186 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
bnum = size / (lpb * bpl);
brest = size - bnum * lpb * bpl;
- for (i = 0; i < bnum; i++) {
- rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
- w, lpb, inc, data);
- if (rc)
- return rc;
- rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + i * lpb, 0);
+ if (av7110->bmp_state == BMP_LOADING) {
+ /* possible if syscall is repeated by -ERESTARTSYS and if firmware cannot abort */
+ BUG_ON (FW_VERSION(av7110->arm_app) >= 0x261e);
+ rc = WaitUntilBmpLoaded(av7110);
if (rc)
return rc;
- data += lpb * inc;
+ /* just continue. This should work for all fw versions
+ * if bnum==1 && !brest && LoadBitmap was successful
+ */
}
- if (brest) {
- rc = LoadBitmap(av7110, bpp2bit[av7110->osdbpp[av7110->osdwin]],
- w, brest / bpl, inc, data);
+
+ rc = 0;
+ for (i = 0; i < bnum; i++) {
+ rc = LoadBitmap(av7110, w, lpb, inc, data);
if (rc)
- return rc;
- rc = BlitBitmap(av7110, av7110->osdwin, x0, y0 + bnum * lpb, 0);
+ break;
+ rc = BlitBitmap(av7110, x0, y0 + i * lpb);
if (rc)
- return rc;
+ break;
+ data += lpb * inc;
}
- ReleaseBitmap(av7110);
- return 0;
+ if (!rc && brest) {
+ rc = LoadBitmap(av7110, w, brest / bpl, inc, data);
+ if (!rc)
+ rc = BlitBitmap(av7110, x0, y0 + bnum * lpb);
+ }
+ release_rc = ReleaseBitmap(av7110);
+ if (!rc)
+ rc = release_rc;
+ if (rc)
+ dprintk(1,"returns %d\n",rc);
+ return rc;
}
int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
{
int ret;
- ret = down_interruptible(&av7110->osd_sema);
- if (ret)
+ if (down_interruptible(&av7110->osd_sema))
return -ERESTARTSYS;
- /* stupid, but OSD functions don't provide a return code anyway */
- ret = 0;
-
switch (dc->cmd) {
case OSD_Close:
- DestroyOSDWindow(av7110, av7110->osdwin);
- goto out;
+ ret = DestroyOSDWindow(av7110, av7110->osdwin);
+ break;
case OSD_Open:
av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
- CreateOSDWindow(av7110, av7110->osdwin,
+ ret = CreateOSDWindow(av7110, av7110->osdwin,
bpp2bit[av7110->osdbpp[av7110->osdwin]],
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+ if (ret)
+ break;
if (!dc->data) {
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (ret)
+ break;
+ ret = SetColorBlend(av7110, av7110->osdwin);
}
- goto out;
+ break;
case OSD_Show:
- MoveWindowRel(av7110, av7110->osdwin, 0, 0);
- goto out;
+ ret = MoveWindowRel(av7110, av7110->osdwin, 0, 0);
+ break;
case OSD_Hide:
- HideWindow(av7110, av7110->osdwin);
- goto out;
+ ret = HideWindow(av7110, av7110->osdwin);
+ break;
case OSD_Clear:
- DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
- goto out;
+ ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, 0);
+ break;
case OSD_Fill:
- DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
- goto out;
+ ret = DrawBlock(av7110, av7110->osdwin, 0, 0, 720, 576, dc->color);
+ break;
case OSD_SetColor:
- OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
- goto out;
+ ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
+ break;
case OSD_SetPalette:
- {
- if (FW_VERSION(av7110->arm_app) >= 0x2618) {
+ if (FW_VERSION(av7110->arm_app) >= 0x2618)
ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
- goto out;
- } else {
+ else {
int i, len = dc->x0-dc->color+1;
u8 __user *colors = (u8 __user *)dc->data;
u8 r, g, b, blend;
-
+ ret = 0;
for (i = 0; i<len; i++) {
if (get_user(r, colors + i * 4) ||
get_user(g, colors + i * 4 + 1) ||
get_user(b, colors + i * 4 + 2) ||
get_user(blend, colors + i * 4 + 3)) {
ret = -EFAULT;
- goto out;
+ break;
}
- OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+ ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
+ if (ret)
+ break;
}
}
- ret = 0;
- goto out;
- }
- case OSD_SetTrans:
- goto out;
+ break;
case OSD_SetPixel:
- DrawLine(av7110, av7110->osdwin,
+ ret = DrawLine(av7110, av7110->osdwin,
dc->x0, dc->y0, 0, 0, dc->color);
- goto out;
- case OSD_GetPixel:
- goto out;
+ break;
case OSD_SetRow:
dc->y1 = dc->y0;
/* fall through */
case OSD_SetBlock:
ret = OSDSetBlock(av7110, dc->x0, dc->y0, dc->x1, dc->y1, dc->color, dc->data);
- goto out;
+ break;
case OSD_FillRow:
- DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+ ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
dc->x1-dc->x0+1, dc->y1, dc->color);
- goto out;
+ break;
case OSD_FillBlock:
- DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
+ ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
- goto out;
+ break;
case OSD_Line:
- DrawLine(av7110, av7110->osdwin,
+ ret = DrawLine(av7110, av7110->osdwin,
dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
- goto out;
- case OSD_Query:
- goto out;
- case OSD_Test:
- goto out;
+ break;
case OSD_Text:
{
char textbuf[240];
if (strncpy_from_user(textbuf, dc->data, 240) < 0) {
ret = -EFAULT;
- goto out;
+ break;
}
textbuf[239] = 0;
if (dc->x1 > 3)
dc->x1 = 3;
- SetFont(av7110, av7110->osdwin, dc->x1,
+ ret = SetFont(av7110, av7110->osdwin, dc->x1,
(u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
- FlushText(av7110);
- WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
- goto out;
+ if (!ret)
+ ret = FlushText(av7110);
+ if (!ret)
+ ret = WriteText(av7110, av7110->osdwin, dc->x0, dc->y0, textbuf);
+ break;
}
case OSD_SetWindow:
- if (dc->x0 < 1 || dc->x0 > 7) {
+ if (dc->x0 < 1 || dc->x0 > 7)
ret = -EINVAL;
- goto out;
+ else {
+ av7110->osdwin = dc->x0;
+ ret = 0;
}
- av7110->osdwin = dc->x0;
- goto out;
+ break;
case OSD_MoveWindow:
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
- goto out;
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (!ret)
+ ret = SetColorBlend(av7110, av7110->osdwin);
+ break;
case OSD_OpenRaw:
if (dc->color < OSD_BITMAP1 || dc->color > OSD_CURSOR) {
ret = -EINVAL;
- goto out;
+ break;
}
- if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR) {
+ if (dc->color >= OSD_BITMAP1 && dc->color <= OSD_BITMAP8HR)
av7110->osdbpp[av7110->osdwin] = (1 << (dc->color & 3)) - 1;
- }
- else {
+ else
av7110->osdbpp[av7110->osdwin] = 0;
- }
- CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
+ ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+ if (ret)
+ break;
if (!dc->data) {
- MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
- SetColorBlend(av7110, av7110->osdwin);
+ ret = MoveWindowAbs(av7110, av7110->osdwin, dc->x0, dc->y0);
+ if (!ret)
+ ret = SetColorBlend(av7110, av7110->osdwin);
}
- goto out;
+ break;
default:
ret = -EINVAL;
- goto out;
+ break;
}
-out:
up(&av7110->osd_sema);
+ if (ret==-ERESTARTSYS)
+ dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+ else if (ret)
+ dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+
return ret;
}
diff --git a/drivers/media/dvb/ttpci/av7110_hw.h b/drivers/media/dvb/ttpci/av7110_hw.h
index 52061e17c6dd..fedd20f9815d 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.h
+++ b/drivers/media/dvb/ttpci/av7110_hw.h
@@ -458,27 +458,27 @@ static inline int SendDAC(struct av7110 *av7110, u8 addr, u8 data)
return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, AudioDAC, 2, addr, data);
}
-static inline void av7710_set_video_mode(struct av7110 *av7110, int mode)
+static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
{
- av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
+ return av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetVidMode, 1, mode);
}
-static int inline vidcom(struct av7110 *av7110, u32 com, u32 arg)
+static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
(com>>16), (com&0xffff),
(arg>>16), (arg&0xffff));
}
-static int inline audcom(struct av7110 *av7110, u32 com)
+static inline int audcom(struct av7110 *av7110, u32 com)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
(com>>16), (com&0xffff));
}
-static inline void Set22K(struct av7110 *av7110, int state)
+static inline int Set22K(struct av7110 *av7110, int state)
{
- av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
+ return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
}
diff --git a/drivers/media/dvb/ttpci/av7110_ipack.c b/drivers/media/dvb/ttpci/av7110_ipack.c
index 246640741888..699ef8b5b99a 100644
--- a/drivers/media/dvb/ttpci/av7110_ipack.c
+++ b/drivers/media/dvb/ttpci/av7110_ipack.c
@@ -24,7 +24,7 @@ int av7110_ipack_init(struct ipack *p, int size,
void (*func)(u8 *buf, int size, void *priv))
{
if (!(p->buf = vmalloc(size*sizeof(u8)))) {
- printk ("Couldn't allocate memory for ipack\n");
+ printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
return -ENOMEM;
}
p->size = size;
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 6e0f5d307c52..9746d2bb916f 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -570,9 +570,9 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p
buf[0] = (div >> 8) & 0x7f;
buf[1] = div & 0xff;
- buf[2] = 0x8e;
- buf[3] = (params->frequency < 174500000 ? 0xa1 :
- params->frequency < 454000000 ? 0x92 : 0x34);
+ buf[2] = 0x86;
+ buf[3] = (params->frequency < 150000000 ? 0x01 :
+ params->frequency < 445000000 ? 0x02 : 0x04);
if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)
return -EIO;
@@ -695,8 +695,12 @@ static struct tda1004x_config philips_tu1216_config = {
.demod_address = 0x8,
.invert = 1,
.invert_oclk = 1,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
.pll_init = philips_tu1216_pll_init,
.pll_set = philips_tu1216_pll_set,
+ .pll_sleep = NULL,
.request_firmware = philips_tu1216_request_firmware,
};
@@ -1018,7 +1022,7 @@ static struct pci_device_id pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension budget_extension = {
- .name = "budget dvb /w video in\0",
+ .name = "budget_av",
.pci_tbl = pci_tbl,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index dce116111376..a1267054bc01 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -69,6 +69,7 @@ struct budget_ci {
int slot_status;
struct dvb_ca_en50221 ca;
char ir_dev_name[50];
+ u8 tuner_pll_address; /* used for philips_tdm1316l configs */
};
/* from reading the following remotes:
@@ -723,7 +724,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe)
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
- struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = td1316_init,.len =
+ struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = td1316_init,.len =
sizeof(td1316_init) };
// setup PLL configuration
@@ -746,7 +747,7 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend
{
struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv;
u8 tuner_buf[4];
- struct i2c_msg tuner_msg = {.addr = 0x63,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
+ struct i2c_msg tuner_msg = {.addr = budget_ci->tuner_pll_address,.flags = 0,.buf = tuner_buf,.len = sizeof(tuner_buf) };
int tuner_frequency = 0;
u8 band, cp, filter;
@@ -838,8 +839,12 @@ static struct tda1004x_config philips_tdm1316l_config = {
.demod_address = 0x8,
.invert = 0,
.invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
.pll_init = philips_tdm1316l_pll_init,
.pll_set = philips_tdm1316l_pll_set,
+ .pll_sleep = NULL,
.request_firmware = philips_tdm1316l_request_firmware,
};
@@ -865,12 +870,22 @@ static void frontend_init(struct budget_ci *budget_ci)
break;
case 0x1011: // Hauppauge/TT Nova-T budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->tuner_pll_address = 0x63;
budget_ci->budget.dvb_frontend =
tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
if (budget_ci->budget.dvb_frontend) {
break;
}
break;
+
+ case 0x1012: // Hauppauge/TT Nova-T CI budget (tda10045/Philips tdm1316l(tda6651tt) + TDA9889)
+ budget_ci->tuner_pll_address = 0x60;
+ budget_ci->budget.dvb_frontend =
+ tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap);
+ if (budget_ci->budget.dvb_frontend) {
+ break;
+ }
+ break;
}
if (budget_ci->budget.dvb_frontend == NULL) {
@@ -950,11 +965,13 @@ static struct saa7146_extension budget_extension;
MAKE_BUDGET_INFO(ttbci, "TT-Budget/WinTV-NOVA-CI PCI", BUDGET_TT_HW_DISEQC);
MAKE_BUDGET_INFO(ttbt2, "TT-Budget/WinTV-NOVA-T PCI", BUDGET_TT);
+MAKE_BUDGET_INFO(ttbtci, "TT-Budget-T-CI PCI", BUDGET_TT);
static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100c),
MAKE_EXTENSION_PCI(ttbci, 0x13c2, 0x100f),
MAKE_EXTENSION_PCI(ttbt2, 0x13c2, 0x1011),
+ MAKE_EXTENSION_PCI(ttbtci, 0x13c2, 0x1012),
{
.vendor = 0,
}
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 083fd44e5f90..9961917e8a7f 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -40,6 +40,7 @@
#include "ves1820.h"
#include "l64781.h"
#include "tda8083.h"
+#include "s5h1420.h"
static void Set22K (struct budget *budget, int state)
{
@@ -177,6 +178,62 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m
return 0;
}
+static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf;
+ struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ switch(voltage) {
+ case SEC_VOLTAGE_13:
+ buf = (buf & 0xf7) | 0x04;
+ break;
+
+ case SEC_VOLTAGE_18:
+ buf = (buf & 0xf7) | 0x0c;
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ buf = buf & 0xf0;
+ break;
+ }
+
+ msg.flags = 0;
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ return 0;
+}
+
+static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend* fe, int arg)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u8 buf;
+ struct i2c_msg msg = { .addr = 0x08, .flags = I2C_M_RD, .buf = &buf, .len = sizeof(buf) };
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ if (arg) {
+ buf = buf | 0x10;
+ } else {
+ buf = buf & 0xef;
+ }
+
+ msg.flags = 0;
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ return 0;
+}
+
+static void lnbp21_init(struct budget* budget)
+{
+ u8 buf = 0x00;
+ struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = &buf, .len = sizeof(buf) };
+
+ i2c_transfer (&budget->i2c_adap, &msg, 1);
+}
+
static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct budget* budget = (struct budget*) fe->dvb->priv;
@@ -395,6 +452,38 @@ static struct tda8083_config grundig_29504_451_config = {
.pll_set = grundig_29504_451_pll_set,
};
+static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout)
+{
+ struct budget* budget = (struct budget*) fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = params->frequency / 1000;
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0xc2;
+
+ if (div < 1450)
+ data[3] = 0x00;
+ else if (div < 1850)
+ data[3] = 0x40;
+ else if (div < 2000)
+ data[3] = 0x80;
+ else
+ data[3] = 0xc0;
+
+ if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO;
+
+ *freqout = div * 1000;
+ return 0;
+}
+
+static struct s5h1420_config s5h1420_config = {
+ .demod_address = 0x53,
+ .pll_set = s5h1420_pll_set,
+};
+
static u8 read_pwm(struct budget* budget)
{
u8 b = 0xff;
@@ -459,6 +548,15 @@ static void frontend_init(struct budget *budget)
break;
}
break;
+
+ case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))
+ budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap);
+ if (budget->dvb_frontend) {
+ budget->dvb_frontend->ops->set_voltage = lnbp21_set_voltage;
+ budget->dvb_frontend->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage;
+ lnbp21_init(budget);
+ break;
+ }
}
if (budget->dvb_frontend == NULL) {
@@ -532,6 +630,7 @@ static struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(ttbc, 0x13c2, 0x1004),
MAKE_EXTENSION_PCI(ttbt, 0x13c2, 0x1005),
MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
+ MAKE_EXTENSION_PCI(ttbs, 0x13c2, 0x1016),
MAKE_EXTENSION_PCI(fsacs1,0x1131, 0x4f60),
MAKE_EXTENSION_PCI(fsacs0,0x1131, 0x4f61),
{
diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig
index 4aa714ab4c28..c6c1d41a2efb 100644
--- a/drivers/media/dvb/ttusb-budget/Kconfig
+++ b/drivers/media/dvb/ttusb-budget/Kconfig
@@ -3,6 +3,7 @@ config DVB_TTUSB_BUDGET
depends on DVB_CORE && USB
select DVB_CX22700
select DVB_TDA1004X
+ select DVB_VES1820
select DVB_TDA8083
select DVB_STV0299
help
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index afa0e7a0e506..aa43b5fcb8e7 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -24,6 +24,7 @@
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_net.h"
+#include "ves1820.h"
#include "cx22700.h"
#include "tda1004x.h"
#include "stv0299.h"
@@ -1367,6 +1368,47 @@ static struct tda8083_config ttusb_novas_grundig_29504_491_config = {
.pll_set = ttusb_novas_grundig_29504_491_pll_set,
};
+static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+ struct ttusb* ttusb = fe->dvb->priv;
+ u32 div;
+ u8 data[4];
+ struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
+
+ div = (params->frequency + 35937500 + 31250) / 62500;
+
+ data[0] = (div >> 8) & 0x7f;
+ data[1] = div & 0xff;
+ data[2] = 0x85 | ((div >> 10) & 0x60);
+ data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81);
+
+ if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1)
+ return -EIO;
+
+ return 0;
+}
+
+
+static struct ves1820_config alps_tdbe2_config = {
+ .demod_address = 0x09,
+ .xin = 57840000UL,
+ .invert = 1,
+ .selagc = VES1820_SELAGC_SIGNAMPERR,
+ .pll_set = alps_tdbe2_pll_set,
+};
+
+static u8 read_pwm(struct ttusb* ttusb)
+{
+ u8 b = 0xff;
+ u8 pwm;
+ struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
+ { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+
+ if ((i2c_transfer(&ttusb->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
+ pwm = 0x48;
+
+ return pwm;
+}
static void frontend_init(struct ttusb* ttusb)
@@ -1394,6 +1436,12 @@ static void frontend_init(struct ttusb* ttusb)
break;
+ case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))
+ ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb));
+ if (ttusb->fe != NULL)
+ break;
+ break;
+
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
@@ -1570,7 +1618,7 @@ static void ttusb_disconnect(struct usb_interface *intf)
static struct usb_device_id ttusb_table[] = {
{USB_DEVICE(0xb48, 0x1003)},
-/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */
+ {USB_DEVICE(0xb48, 0x1004)},
{USB_DEVICE(0xb48, 0x1005)},
{}
};
@@ -1578,7 +1626,7 @@ static struct usb_device_id ttusb_table[] = {
MODULE_DEVICE_TABLE(usb, ttusb_table);
static struct usb_driver ttusb_driver = {
- .name = "Technotrend/Hauppauge USB-Nova",
+ .name = "ttusb",
.probe = ttusb_probe,
.disconnect = ttusb_disconnect,
.id_table = ttusb_table,
diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
index 505bdaff5a7e..45c9a9a08e4d 100644
--- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c
@@ -1281,6 +1281,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
if (firmware_size < 60) {
printk("%s: firmware size too small for DSP code (%zu < 60).\n",
__FUNCTION__, firmware_size);
+ release_firmware(fw_entry);
return -1;
}
@@ -1294,6 +1295,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
printk("%s: crc32 check of DSP code failed (calculated "
"0x%08x != 0x%08x in file), file invalid.\n",
__FUNCTION__, crc32_csum, crc32_check);
+ release_firmware(fw_entry);
return -1;
}
memcpy(idstring, &firmware[36], 20);
@@ -1308,15 +1310,19 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL);
- if (result)
+ if (result) {
+ release_firmware(fw_entry);
return result;
+ }
trans_count = 0;
j = 0;
b = kmalloc(ARM_PACKET_SIZE, GFP_KERNEL);
- if (b == NULL)
+ if (b == NULL) {
+ release_firmware(fw_entry);
return -ENOMEM;
+ }
for (i = 0; i < firmware_size; i += COMMAND_PACKET_SIZE) {
size = firmware_size - i;
@@ -1345,6 +1351,7 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
result = ttusb_dec_send_command(dec, 0x43, sizeof(b1), b1, NULL, NULL);
+ release_firmware(fw_entry);
kfree(b);
return result;
diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
index 1699cc9f6bb0..725af3af5b27 100644
--- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
+++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c
@@ -157,7 +157,8 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
/* allocate memory for the internal state */
state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ return NULL;
/* setup the state */
state->config = config;
@@ -167,10 +168,6 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
-
-error:
- kfree(state);
- return NULL;
}
static struct dvb_frontend_ops ttusbdecfe_dvbs_ops;
@@ -181,7 +178,8 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
/* allocate memory for the internal state */
state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ if (state == NULL)
+ return NULL;
/* setup the state */
state->config = config;
@@ -193,10 +191,6 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
-
-error:
- kfree(state);
- return NULL;
}
static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = {
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 6c05fddb69ab..f461750c7646 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -330,6 +330,8 @@ config VIDEO_CX88_DVB
select VIDEO_BUF_DVB
select DVB_MT352
select DVB_OR51132
+ select DVB_CX22702
+ select DVB_LGDT3302
---help---
This adds support for DVB/ATSC cards based on the
Connexant 2388x chip.
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2dc906fdfa55..810e7aac0a53 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -7,8 +7,7 @@ bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
zoran-objs := zr36120.o zr36120_i2c.o zr36120_mem.o
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
-tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o
-
+tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o
obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o
obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \
diff --git a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
index 07f72f64c5f7..a070417e65e6 100644
--- a/drivers/media/video/bt832.c
+++ b/drivers/media/video/bt832.c
@@ -6,7 +6,7 @@
It outputs an 8-bit 4:2:2 YUV or YCrCb video signal which can be directly
connected to bt848/bt878 GPIO pins on this purpose.
(see: VLSI Vision Ltd. www.vvl.co.uk for camera datasheets)
-
+
Supported Cards:
- Pixelview Rev.4E: 0x8a
GPIO 0x400000 toggles Bt832 RESET, and the chip changes to i2c 0x88 !
@@ -31,8 +31,8 @@
#include <linux/errno.h>
#include <linux/slab.h>
-#include "id.h"
-#include "audiochip.h"
+#include <media/audiochip.h>
+#include <media/id.h>
#include "bttv.h"
#include "bt832.h"
@@ -95,7 +95,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf=kmalloc(65,GFP_KERNEL);
bt832_hexdump(i2c_client_s,buf);
-
+
if(buf[0x40] != 0x31) {
printk("bt832: this i2c chip is no bt832 (id=%02x). Detaching.\n",buf[0x40]);
kfree(buf);
@@ -135,28 +135,16 @@ int bt832_init(struct i2c_client *i2c_client_s)
buf[1]= 0x27 & (~0x01); // Default | !skip
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error EO: rc == %d (should be 2)\n",rc);
-
- bt832_hexdump(i2c_client_s,buf);
-
-#if 0
- // Full 30/25 Frame rate
- printk("Full 30/25 Frame rate\n");
- buf[0]=BT832_VP_CONTROL0; // Reg.39
- buf[1]= 0x00;
- if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
- printk("bt832: i2c i/o error FFR: rc == %d (should be 2)\n",rc);
bt832_hexdump(i2c_client_s,buf);
-#endif
-#if 1
+
// for testing (even works when no camera attached)
printk("bt832: *** Generate NTSC M Bars *****\n");
buf[0]=BT832_VP_TESTCONTROL0; // Reg. 42
buf[1]=3; // Generate NTSC System M bars, Generate Frame timing internally
if (2 != (rc = i2c_master_send(i2c_client_s,buf,2)))
printk("bt832: i2c i/o error MBAR: rc == %d (should be 2)\n",rc);
-#endif
printk("Bt832: Camera Present: %s\n",
(buf[1+BT832_CAM_STATUS] & BT832_56_CAMERA_PRESENT) ? "yes":"no");
@@ -168,8 +156,7 @@ int bt832_init(struct i2c_client *i2c_client_s)
-static int bt832_attach(struct i2c_adapter *adap, int addr,
- unsigned short flags, int kind)
+static int bt832_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct bt832 *t;
@@ -184,27 +171,32 @@ static int bt832_attach(struct i2c_adapter *adap, int addr,
return -ENOMEM;
memset(t,0,sizeof(*t));
t->client = client_template;
- t->client.data = t;
+ i2c_set_clientdata(&t->client, t);
i2c_attach_client(&t->client);
if(! bt832_init(&t->client)) {
bt832_detach(&t->client);
return -1;
}
-
+
return 0;
}
static int bt832_probe(struct i2c_adapter *adap)
{
+#ifdef I2C_CLASS_TV_ANALOG
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, bt832_attach);
+#else
+ if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+ return i2c_probe(adap, &addr_data, bt832_attach);
+#endif
return 0;
}
static int bt832_detach(struct i2c_client *client)
{
- struct bt832 *t = (struct bt832*)client->data;
+ struct bt832 *t = i2c_get_clientdata(client);
printk("bt832: detach.\n");
i2c_detach_client(client);
@@ -215,7 +207,7 @@ static int bt832_detach(struct i2c_client *client)
static int
bt832_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
- struct bt832 *t = (struct bt832*)client->data;
+ struct bt832 *t = i2c_get_clientdata(client);
printk("bt832: command %x\n",cmd);
@@ -249,19 +241,18 @@ static struct i2c_driver driver = {
};
static struct i2c_client client_template =
{
- .name = "bt832",
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
+ I2C_DEVNAME("bt832"),
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
};
-int bt832_init_module(void)
+static int __init bt832_init_module(void)
{
- i2c_add_driver(&driver);
- return 0;
+ return i2c_add_driver(&driver);
}
-static void bt832_cleanup_module(void)
+static void __exit bt832_cleanup_module(void)
{
i2c_del_driver(&driver);
}
@@ -269,3 +260,10 @@ static void bt832_cleanup_module(void)
module_init(bt832_init_module);
module_exit(bt832_cleanup_module);
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * End:
+ */
diff --git a/drivers/media/video/bt832.h b/drivers/media/video/bt832.h
index 7a98c06e0e34..9b6a8d2c96b5 100644
--- a/drivers/media/video/bt832.h
+++ b/drivers/media/video/bt832.h
@@ -1,6 +1,6 @@
/* Bt832 CMOS Camera Video Processor (VP)
- The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
+ The Bt832 CMOS Camera Video Processor chip connects a Quartsight CMOS
color digital camera directly to video capture devices via an 8-bit,
4:2:2 YUV or YCrCb video interface.
@@ -85,7 +85,7 @@
#define BT832_DEVICE_ID 63
# define BT832_DEVICE_ID__31 0x31 // Bt832 has ID 0x31
-/* STMicroelectronivcs VV5404 camera module
+/* STMicroelectronivcs VV5404 camera module
i2c: 0x20: sensor address
i2c: 0xa0: eeprom for ccd defect map
*/
@@ -256,26 +256,26 @@ For the CCIR-601 standards, the sampling is based on a static orthogonal samplin
//===========================================================================
// Timing generator SRAM table values for CCIR601 720x480 NTSC
//===========================================================================
-// For NTSC CCIR656
+// For NTSC CCIR656
BYTE BtCard::SRAMTable_NTSC[] =
{
// SRAM Timing Table for NTSC
- 0x0c, 0xc0, 0x00,
- 0x00, 0x90, 0xc2,
- 0x03, 0x10, 0x03,
- 0x06, 0x10, 0x34,
- 0x12, 0x12, 0x65,
- 0x02, 0x13, 0x24,
- 0x19, 0x00, 0x24,
- 0x39, 0x00, 0x96,
- 0x59, 0x08, 0x93,
+ 0x0c, 0xc0, 0x00,
+ 0x00, 0x90, 0xc2,
+ 0x03, 0x10, 0x03,
+ 0x06, 0x10, 0x34,
+ 0x12, 0x12, 0x65,
+ 0x02, 0x13, 0x24,
+ 0x19, 0x00, 0x24,
+ 0x39, 0x00, 0x96,
+ 0x59, 0x08, 0x93,
0x83, 0x08, 0x97,
- 0x03, 0x50, 0x30,
- 0xc0, 0x40, 0x30,
- 0x86, 0x01, 0x01,
- 0xa6, 0x0d, 0x62,
- 0x03, 0x11, 0x61,
- 0x05, 0x37, 0x30,
+ 0x03, 0x50, 0x30,
+ 0xc0, 0x40, 0x30,
+ 0x86, 0x01, 0x01,
+ 0xa6, 0x0d, 0x62,
+ 0x03, 0x11, 0x61,
+ 0x05, 0x37, 0x30,
0xac, 0x21, 0x50
};
diff --git a/drivers/media/video/bttv-cards.c b/drivers/media/video/bttv-cards.c
index 6334122704ae..2dbf5ec43abd 100644
--- a/drivers/media/video/bttv-cards.c
+++ b/drivers/media/video/bttv-cards.c
@@ -1,5 +1,5 @@
/*
- $Id: bttv-cards.c,v 1.47 2005/02/22 14:06:32 kraxel Exp $
+ $Id: bttv-cards.c,v 1.53 2005/07/05 17:37:35 nsh Exp $
bttv-cards.c
@@ -39,9 +39,6 @@
#include <asm/io.h>
#include "bttvp.h"
-#if 0 /* not working yet */
-#include "bt832.h"
-#endif
/* fwd decl */
static void boot_msp34xx(struct bttv *btv, int pin);
@@ -51,6 +48,7 @@ static void avermedia_eeprom(struct bttv *btv);
static void osprey_eeprom(struct bttv *btv);
static void modtec_eeprom(struct bttv *btv);
static void init_PXC200(struct bttv *btv);
+static void init_RTV24(struct bttv *btv);
static void winview_audio(struct bttv *btv, struct video_audio *v, int set);
static void lt9415_audio(struct bttv *btv, struct video_audio *v, int set);
@@ -512,13 +510,8 @@ struct tvcard bttv_tvcards[] = {
.svhs = 2,
.gpiomask = 0x01fe00,
.muxsel = { 2, 3, 1, 1},
-#if 0
- // old
- .audiomux = { 0x01c000, 0, 0x018000, 0x014000, 0x002000, 0 },
-#else
// 2003-10-20 by "Anton A. Arapov" <arapov@mail.ru>
.audiomux = { 0x001e00, 0, 0x018000, 0x014000, 0x002000, 0 },
-#endif
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = -1,
@@ -765,14 +758,9 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 1, 0}, // TV, CVid, SVid, CVid over SVid connector
-#if 0
- .gpiomask = 0xc33000,
- .audiomux = { 0x422000,0x1000,0x0000,0x620000,0x800000 },
-#else
/* Alexander Varakin <avarakin@hotmail.com> [stereo version] */
.gpiomask = 0xb33000,
.audiomux = { 0x122000,0x1000,0x0000,0x620000,0x800000 },
-#endif
/* Audio Routing for "WinFast 2000 XP" (no tv stereo !)
gpio23 -- hef4052:nEnable (0x800000)
gpio12 -- hef4052:A1
@@ -1602,20 +1590,11 @@ struct tvcard bttv_tvcards[] = {
.video_inputs = 4,
.audio_inputs = 1,
.tuner = -1,
-#if 0 /* TODO ... */
- .svhs = OSPREY540_SVID_ANALOG,
- .muxsel = { [OSPREY540_COMP_ANALOG] = 2,
- [OSPREY540_SVID_ANALOG] = 3, },
-#endif
.pll = PLL_28,
.tuner_type = -1,
.no_msp34xx = 1,
.no_tda9875 = 1,
.no_tda7432 = 1,
-#if 0 /* TODO ... */
- .muxsel_hook = osprey_540_muxsel,
- .picture_hook = osprey_540_set_picture,
-#endif
},{
/* ---- card 0x5C ---------------------------------- */
@@ -2251,6 +2230,20 @@ struct tvcard bttv_tvcards[] = {
.no_tda7432 = 1,
.no_tda9875 = 1,
.muxsel_hook = kodicom4400r_muxsel,
+},
+{
+ /* ---- card 0x85---------------------------------- */
+ /* Michael Henson <mhenson@clarityvi.com> */
+ /* Adlink RTV24 with special unlock codes */
+ .name = "Adlink RTV24",
+ .video_inputs = 4,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .muxsel = { 2, 3, 1, 0},
+ .tuner_type = -1,
+ .pll = PLL_28,
+
}};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -2531,21 +2524,12 @@ static void eagle_muxsel(struct bttv *btv, unsigned int input)
btaor((2)<<5, ~(3<<5), BT848_IFORM);
gpio_bits(3,bttv_tvcards[btv->c.type].muxsel[input&7]);
-#if 0
- /* svhs */
- /* wake chroma ADC */
- btand(~BT848_ADC_C_SLEEP, BT848_ADC);
- /* set to YC video */
- btor(BT848_CONTROL_COMP, BT848_E_CONTROL);
- btor(BT848_CONTROL_COMP, BT848_O_CONTROL);
-#else
/* composite */
/* set chroma ADC to sleep */
btor(BT848_ADC_C_SLEEP, BT848_ADC);
/* set to composite video */
btand(~BT848_CONTROL_COMP, BT848_E_CONTROL);
btand(~BT848_CONTROL_COMP, BT848_O_CONTROL);
-#endif
/* switch sync drive off */
gpio_bits(LM1882_SYNC_DRIVE,LM1882_SYNC_DRIVE);
@@ -2636,6 +2620,10 @@ void __devinit bttv_init_card1(struct bttv *btv)
case BTTV_AVDVBT_771:
btv->use_i2c_hw = 1;
break;
+ case BTTV_ADLINK_RTV24:
+ init_RTV24( btv );
+ break;
+
}
if (!bttv_tvcards[btv->c.type].has_dvb)
bttv_reset_audio(btv);
@@ -2784,6 +2772,8 @@ void __devinit bttv_init_card2(struct bttv *btv)
}
btv->pll.pll_current = -1;
+ bttv_reset_audio(btv);
+
/* tuner configuration (from card list / autodetect / insmod option) */
if (UNSET != bttv_tvcards[btv->c.type].tuner_type)
if(UNSET == btv->tuner_type)
@@ -2792,10 +2782,18 @@ void __devinit bttv_init_card2(struct bttv *btv)
btv->tuner_type = tuner[btv->c.nr];
printk("bttv%d: using tuner=%d\n",btv->c.nr,btv->tuner_type);
if (btv->pinnacle_id != UNSET)
- bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
+ bttv_call_i2c_clients(btv, AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
- if (btv->tuner_type != UNSET)
- bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+ if (btv->tuner_type != UNSET) {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = ADDR_UNSET;
+
+ bttv_call_i2c_clients(btv, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
btv->svhs = bttv_tvcards[btv->c.type].svhs;
if (svhs[btv->c.nr] != UNSET)
btv->svhs = svhs[btv->c.nr];
@@ -3104,14 +3102,6 @@ static int tuner_0_table[] = {
TUNER_PHILIPS_SECAM, TUNER_PHILIPS_SECAM,
TUNER_PHILIPS_SECAM, TUNER_PHILIPS_PAL,
TUNER_PHILIPS_FM1216ME_MK3 };
-#if 0
-int tuner_0_fm_table[] = {
- PHILIPS_FR1236_NTSC, PHILIPS_FR1216_PAL,
- PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL,
- PHILIPS_FR1216_PAL, PHILIPS_FR1216_PAL,
- PHILIPS_FR1236_SECAM, PHILIPS_FR1236_SECAM,
- PHILIPS_FR1236_SECAM, PHILIPS_FR1216_PAL};
-#endif
static int tuner_1_table[] = {
TUNER_TEMIC_NTSC, TUNER_TEMIC_PAL,
@@ -3197,36 +3187,6 @@ static void __devinit boot_msp34xx(struct bttv *btv, int pin)
static void __devinit boot_bt832(struct bttv *btv)
{
-#if 0 /* not working yet */
- int resetbit=0;
-
- switch (btv->c.type) {
- case BTTV_PXELVWPLTVPAK:
- resetbit = 0x400000;
- break;
- case BTTV_MODTEC_205:
- resetbit = 1<<9;
- break;
- default:
- BUG();
- }
-
- request_module("bt832");
- bttv_call_i2c_clients(btv, BT832_HEXDUMP, NULL);
-
- printk("bttv%d: Reset Bt832 [line=0x%x]\n",btv->c.nr,resetbit);
- gpio_write(0);
- gpio_inout(resetbit, resetbit);
- udelay(5);
- gpio_bits(resetbit, resetbit);
- udelay(5);
- gpio_bits(resetbit, 0);
- udelay(5);
-
- // bt832 on pixelview changes from i2c 0x8a to 0x88 after
- // being reset as above. So we must follow by this:
- bttv_call_i2c_clients(btv, BT832_REATTACH, NULL);
-#endif
}
/* ----------------------------------------------------------------------- */
@@ -3304,6 +3264,83 @@ static void __devinit init_PXC200(struct bttv *btv)
}
+
+/* ----------------------------------------------------------------------- */
+/*
+ * The Adlink RTV-24 (aka Angelo) has some special initialisation to unlock
+ * it. This apparently involves the following procedure for each 878 chip:
+ *
+ * 1) write 0x00C3FEFF to the GPIO_OUT_EN register
+ *
+ * 2) write to GPIO_DATA
+ * - 0x0E
+ * - sleep 1ms
+ * - 0x10 + 0x0E
+ * - sleep 10ms
+ * - 0x0E
+ * read from GPIO_DATA into buf (uint_32)
+ * - if ( data>>18 & 0x01 != 0) || ( buf>>19 & 0x01 != 1 )
+ * error. ERROR_CPLD_Check_Failed stop.
+ *
+ * 3) write to GPIO_DATA
+ * - write 0x4400 + 0x0E
+ * - sleep 10ms
+ * - write 0x4410 + 0x0E
+ * - sleep 1ms
+ * - write 0x0E
+ * read from GPIO_DATA into buf (uint_32)
+ * - if ( buf>>18 & 0x01 ) || ( buf>>19 && 0x01 != 0 )
+ * error. ERROR_CPLD_Check_Failed.
+ */
+/* ----------------------------------------------------------------------- */
+void
+init_RTV24 (struct bttv *btv)
+{
+ uint32_t dataRead = 0;
+ long watchdog_value = 0x0E;
+
+ printk (KERN_INFO
+ "bttv%d: Adlink RTV-24 initialisation in progress ...\n",
+ btv->c.nr);
+
+ btwrite (0x00c3feff, BT848_GPIO_OUT_EN);
+
+ btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+ msleep (1);
+ btwrite (0x10 + watchdog_value, BT848_GPIO_DATA);
+ msleep (10);
+ btwrite (0 + watchdog_value, BT848_GPIO_DATA);
+
+ dataRead = btread (BT848_GPIO_DATA);
+
+ if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 1)) {
+ printk (KERN_INFO
+ "bttv%d: Adlink RTV-24 initialisation(1) ERROR_CPLD_Check_Failed (read %d)\n",
+ btv->c.nr, dataRead);
+ }
+
+ btwrite (0x4400 + watchdog_value, BT848_GPIO_DATA);
+ msleep (10);
+ btwrite (0x4410 + watchdog_value, BT848_GPIO_DATA);
+ msleep (1);
+ btwrite (watchdog_value, BT848_GPIO_DATA);
+ msleep (1);
+ dataRead = btread (BT848_GPIO_DATA);
+
+ if ((((dataRead >> 18) & 0x01) != 0) || (((dataRead >> 19) & 0x01) != 0)) {
+ printk (KERN_INFO
+ "bttv%d: Adlink RTV-24 initialisation(2) ERROR_CPLD_Check_Failed (read %d)\n",
+ btv->c.nr, dataRead);
+
+ return;
+ }
+
+ printk (KERN_INFO
+ "bttv%d: Adlink RTV-24 initialisation complete.\n", btv->c.nr);
+}
+
+
+
/* ----------------------------------------------------------------------- */
/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */
/*
@@ -3474,11 +3511,6 @@ void tea5757_set_freq(struct bttv *btv, unsigned short freq)
{
dprintk("tea5757_set_freq %d\n",freq);
tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-#if 0
- /* breaks Miro PCTV */
- value = tea5757_read(btv);
- dprintk("bttv%d: tea5757 readback=0x%x\n",btv->c.nr,value);
-#endif
}
@@ -3558,13 +3590,8 @@ gvbctv5pci_audio(struct bttv *btv, struct video_audio *v, int set)
{
unsigned int val, con;
-#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
if (btv->radio_user)
return;
-#else
- if (btv->radio)
- return;
-#endif
val = gpio_read();
if (set) {
@@ -3753,13 +3780,8 @@ pvbt878p9b_audio(struct bttv *btv, struct video_audio *v, int set)
{
unsigned int val = 0;
-#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
if (btv->radio_user)
return;
-#else
- if (btv->radio)
- return;
-#endif
if (set) {
if (v->mode & VIDEO_SOUND_MONO) {
@@ -3790,13 +3812,8 @@ fv2000s_audio(struct bttv *btv, struct video_audio *v, int set)
{
unsigned int val = 0xffff;
-#if BTTV_VERSION_CODE > KERNEL_VERSION(0,8,0)
if (btv->radio_user)
return;
-#else
- if (btv->radio)
- return;
-#endif
if (set) {
if (v->mode & VIDEO_SOUND_MONO) {
val = 0x0000;
@@ -4273,11 +4290,6 @@ void __devinit bttv_check_chipset(void)
latency = 0x0A;
#endif
-#if 0
- /* print which chipset we have */
- while ((dev = pci_find_class(PCI_CLASS_BRIDGE_HOST << 8,dev)))
- printk(KERN_INFO "bttv: Host bridge is %s\n",pci_name(dev));
-#endif
/* print warnings about any quirks found */
if (triton1)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 033cc5498f23..51a0f6d68e73 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -1,5 +1,5 @@
/*
- $Id: bttv-driver.c,v 1.37 2005/02/21 13:57:59 kraxel Exp $
+ $Id: bttv-driver.c,v 1.42 2005/07/05 17:37:35 nsh Exp $
bttv - Bt848 frame grabber driver
@@ -35,6 +35,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -76,6 +77,9 @@ static unsigned int whitecrush_upper = 0xCF;
static unsigned int whitecrush_lower = 0x7F;
static unsigned int vcr_hack = 0;
static unsigned int irq_iswitch = 0;
+static unsigned int uv_ratio = 50;
+static unsigned int full_luma_range = 0;
+static unsigned int coring = 0;
/* API features (turn on/off stuff for testing) */
static unsigned int v4l2 = 1;
@@ -106,6 +110,9 @@ module_param(adc_crush, int, 0444);
module_param(whitecrush_upper, int, 0444);
module_param(whitecrush_lower, int, 0444);
module_param(vcr_hack, int, 0444);
+module_param(uv_ratio, int, 0444);
+module_param(full_luma_range, int, 0444);
+module_param(coring, int, 0444);
module_param_array(radio, int, NULL, 0444);
@@ -124,6 +131,9 @@ MODULE_PARM_DESC(whitecrush_upper,"sets the white crush upper value, default is
MODULE_PARM_DESC(whitecrush_lower,"sets the white crush lower value, default is 127");
MODULE_PARM_DESC(vcr_hack,"enables the VCR hack (improves synch on poor VCR tapes), default is 0 (no)");
MODULE_PARM_DESC(irq_iswitch,"switch inputs in irq handler");
+MODULE_PARM_DESC(uv_ratio,"ratio between u and v gains, default is 50");
+MODULE_PARM_DESC(full_luma_range,"use the full luma range, default is 0 (no)");
+MODULE_PARM_DESC(coring,"set the luma coring level, default is 0 (no)");
MODULE_DESCRIPTION("bttv - v4l/v4l2 driver module for bt848/878 based cards");
MODULE_AUTHOR("Ralph Metzler & Marcus Metzler & Gerd Knorr");
@@ -484,7 +494,10 @@ static const unsigned int BTTV_FORMATS = ARRAY_SIZE(bttv_formats);
#define V4L2_CID_PRIVATE_VCR_HACK (V4L2_CID_PRIVATE_BASE + 5)
#define V4L2_CID_PRIVATE_WHITECRUSH_UPPER (V4L2_CID_PRIVATE_BASE + 6)
#define V4L2_CID_PRIVATE_WHITECRUSH_LOWER (V4L2_CID_PRIVATE_BASE + 7)
-#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_UV_RATIO (V4L2_CID_PRIVATE_BASE + 8)
+#define V4L2_CID_PRIVATE_FULL_LUMA_RANGE (V4L2_CID_PRIVATE_BASE + 9)
+#define V4L2_CID_PRIVATE_CORING (V4L2_CID_PRIVATE_BASE + 10)
+#define V4L2_CID_PRIVATE_LASTP1 (V4L2_CID_PRIVATE_BASE + 11)
static const struct v4l2_queryctrl no_ctl = {
.name = "42",
@@ -618,8 +631,32 @@ static const struct v4l2_queryctrl bttv_ctls[] = {
.step = 1,
.default_value = 0x7F,
.type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_PRIVATE_UV_RATIO,
+ .name = "uv ratio",
+ .minimum = 0,
+ .maximum = 100,
+ .step = 1,
+ .default_value = 50,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ },{
+ .id = V4L2_CID_PRIVATE_FULL_LUMA_RANGE,
+ .name = "full luma range",
+ .minimum = 0,
+ .maximum = 1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },{
+ .id = V4L2_CID_PRIVATE_CORING,
+ .name = "coring",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ .type = V4L2_CTRL_TYPE_INTEGER,
}
+
+
};
static const int BTTV_CTLS = ARRAY_SIZE(bttv_ctls);
@@ -662,12 +699,10 @@ int locked_btres(struct bttv *btv, int bit)
static
void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
{
-#if 1 /* DEBUG */
if ((fh->resources & bits) != bits) {
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
-#endif
down(&btv->reslock);
fh->resources &= ~bits;
btv->resources &= ~bits;
@@ -833,8 +868,8 @@ static void bt848_sat(struct bttv *btv, int color)
btv->saturation = color;
/* 0-511 for the color */
- val_u = color >> 7;
- val_v = ((color>>7)*180L)/254;
+ val_u = ((color * btv->opt_uv_ratio) / 50) >> 7;
+ val_v = (((color * (100 - btv->opt_uv_ratio) / 50) >>7)*180L)/254;
hibits = (val_u >> 7) & 2;
hibits |= (val_v >> 8) & 1;
btwrite(val_u & 0xff, BT848_SAT_U_LO);
@@ -907,11 +942,6 @@ audio_mux(struct bttv *btv, int mode)
i2c_mux = mux = (btv->audio & AUDIO_MUTE) ? AUDIO_OFF : btv->audio;
if (btv->opt_automute && !signal && !btv->radio_user)
mux = AUDIO_OFF;
-#if 0
- printk("bttv%d: amux: mode=%d audio=%d signal=%s mux=%d/%d irq=%s\n",
- btv->c.nr, mode, btv->audio, signal ? "yes" : "no",
- mux, i2c_mux, in_interrupt() ? "yes" : "no");
-#endif
val = bttv_tvcards[btv->c.type].audiomux[mux];
gpio_bits(bttv_tvcards[btv->c.type].gpiomask,val);
@@ -958,11 +988,6 @@ set_tvnorm(struct bttv *btv, unsigned int norm)
case BTTV_VOODOOTV_FM:
bttv_tda9880_setnorm(btv,norm);
break;
-#if 0
- case BTTV_OSPREY540:
- osprey_540_set_norm(btv,norm);
- break;
-#endif
}
return 0;
}
@@ -1151,6 +1176,15 @@ static int get_control(struct bttv *btv, struct v4l2_control *c)
case V4L2_CID_PRIVATE_WHITECRUSH_LOWER:
c->value = btv->opt_whitecrush_lower;
break;
+ case V4L2_CID_PRIVATE_UV_RATIO:
+ c->value = btv->opt_uv_ratio;
+ break;
+ case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+ c->value = btv->opt_full_luma_range;
+ break;
+ case V4L2_CID_PRIVATE_CORING:
+ c->value = btv->opt_coring;
+ break;
default:
return -EINVAL;
}
@@ -1247,6 +1281,18 @@ static int set_control(struct bttv *btv, struct v4l2_control *c)
btv->opt_whitecrush_lower = c->value;
btwrite(c->value, BT848_WC_DOWN);
break;
+ case V4L2_CID_PRIVATE_UV_RATIO:
+ btv->opt_uv_ratio = c->value;
+ bt848_sat(btv, btv->saturation);
+ break;
+ case V4L2_CID_PRIVATE_FULL_LUMA_RANGE:
+ btv->opt_full_luma_range = c->value;
+ btaor((c->value<<7), ~BT848_OFORM_RANGE, BT848_OFORM);
+ break;
+ case V4L2_CID_PRIVATE_CORING:
+ btv->opt_coring = c->value;
+ btaor((c->value<<5), ~BT848_OFORM_CORE32, BT848_OFORM);
+ break;
default:
return -EINVAL;
}
@@ -1792,7 +1838,7 @@ static int bttv_common_ioctls(struct bttv *btv, unsigned int cmd, void *arg)
if (unlikely(f->tuner != 0))
return -EINVAL;
- if (unlikely(f->type != V4L2_TUNER_ANALOG_TV))
+ if (unlikely (f->type != V4L2_TUNER_ANALOG_TV))
return -EINVAL;
down(&btv->lock);
btv->freq = f->frequency;
@@ -3117,11 +3163,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
memset(v,0,sizeof(*v));
strcpy(v->name, "Radio");
- /* japan: 76.0 MHz - 89.9 MHz
- western europe: 87.5 MHz - 108.0 MHz
- russia: 65.0 MHz - 108.0 MHz */
- v->rangelow=(int)(65*16);
- v->rangehigh=(int)(108*16);
bttv_call_i2c_clients(btv,cmd,v);
return 0;
}
@@ -3813,7 +3854,7 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->c.nr);
return -EIO;
}
- if (pci_set_dma_mask(dev, 0xffffffff)) {
+ if (pci_set_dma_mask(dev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "bttv%d: No suitable DMA available.\n",
btv->c.nr);
return -EIO;
@@ -3876,6 +3917,9 @@ static int __devinit bttv_probe(struct pci_dev *dev,
btv->opt_vcr_hack = vcr_hack;
btv->opt_whitecrush_upper = whitecrush_upper;
btv->opt_whitecrush_lower = whitecrush_lower;
+ btv->opt_uv_ratio = uv_ratio;
+ btv->opt_full_luma_range = full_luma_range;
+ btv->opt_coring = coring;
/* fill struct bttv with some useful defaults */
btv->init.btv = btv;
diff --git a/drivers/media/video/bttv-i2c.c b/drivers/media/video/bttv-i2c.c
index c2368bc832ed..234a85563769 100644
--- a/drivers/media/video/bttv-i2c.c
+++ b/drivers/media/video/bttv-i2c.c
@@ -1,5 +1,5 @@
/*
- $Id: bttv-i2c.c,v 1.18 2005/02/16 12:14:10 kraxel Exp $
+ $Id: bttv-i2c.c,v 1.25 2005/07/05 17:37:35 nsh Exp $
bttv-i2c.c -- all the i2c code is here
@@ -295,14 +295,26 @@ static int attach_inform(struct i2c_client *client)
{
struct bttv *btv = i2c_get_adapdata(client->adapter);
- if (btv->tuner_type != UNSET)
- bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
+ if (bttv_debug)
+ printk(KERN_DEBUG "bttv%d: %s i2c attach [addr=0x%x,client=%s]\n",
+ btv->c.nr,client->driver->name,client->addr,
+ i2c_clientname(client));
+ if (!client->driver->command)
+ return 0;
+
+ if (btv->tuner_type != UNSET) {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = btv->tuner_type;
+ tun_setup.addr = ADDR_UNSET;
+
+ client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+
if (btv->pinnacle_id != UNSET)
- bttv_call_i2c_clients(btv,AUDC_CONFIG_PINNACLE,
+ client->driver->command(client,AUDC_CONFIG_PINNACLE,
&btv->pinnacle_id);
- if (bttv_debug)
- printk("bttv%d: i2c attach [client=%s]\n",
- btv->c.nr, i2c_clientname(client));
return 0;
}
diff --git a/drivers/media/video/bttv-risc.c b/drivers/media/video/bttv-risc.c
index bdc5ce6c43b9..9ed21fd190c6 100644
--- a/drivers/media/video/bttv-risc.c
+++ b/drivers/media/video/bttv-risc.c
@@ -334,10 +334,6 @@ bttv_calc_geo(struct bttv *btv, struct bttv_geometry *geo,
}
vdelay = tvnorm->vdelay;
-#if 0 /* FIXME */
- if (vdelay < btv->vbi.lines*2)
- vdelay = btv->vbi.lines*2;
-#endif
xsf = (width*scaledtwidth)/swidth;
geo->hscale = ((totalwidth*4096UL)/xsf-4096);
@@ -776,13 +772,8 @@ bttv_overlay_risc(struct bttv *btv,
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 0);
break;
case V4L2_FIELD_INTERLACED:
-#if 0
- bttv_risc_overlay(btv, &buf->top, fmt, ov, 1, 0);
- bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 0, 1);
-#else
bttv_risc_overlay(btv, &buf->top, fmt, ov, 0, 1);
bttv_risc_overlay(btv, &buf->bottom, fmt, ov, 1, 0);
-#endif
break;
default:
BUG();
diff --git a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
index 8322b66e0905..191eaf1714ba 100644
--- a/drivers/media/video/bttv.h
+++ b/drivers/media/video/bttv.h
@@ -1,5 +1,5 @@
/*
- * $Id: bttv.h,v 1.17 2005/02/22 14:06:32 kraxel Exp $
+ * $Id: bttv.h,v 1.18 2005/05/24 23:41:42 nsh Exp $
*
* bttv - Bt848 frame grabber driver
*
@@ -135,6 +135,7 @@
#define BTTV_DVICO_DVBT_LITE 0x80
#define BTTV_TIBET_CS16 0x83
#define BTTV_KODICOM_4400R 0x84
+#define BTTV_ADLINK_RTV24 0x85
/* i2c address list */
#define I2C_TSA5522 0xc2
diff --git a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
index 1a9ba7e1cf51..f3293e4a15ad 100644
--- a/drivers/media/video/bttvp.h
+++ b/drivers/media/video/bttvp.h
@@ -1,5 +1,5 @@
/*
- $Id: bttvp.h,v 1.17 2005/02/16 12:14:10 kraxel Exp $
+ $Id: bttvp.h,v 1.19 2005/06/16 21:38:45 nsh Exp $
bttv - Bt848 frame grabber driver
@@ -226,10 +226,6 @@ extern int fini_bttv_i2c(struct bttv *btv);
#define dprintk if (bttv_debug >= 1) printk
#define d2printk if (bttv_debug >= 2) printk
-/* our devices */
-#define BTTV_MAX 16
-extern unsigned int bttv_num;
-
#define BTTV_MAX_FBUF 0x208000
#define VBIBUF_SIZE (2048*VBI_MAXLINES*2)
#define BTTV_TIMEOUT (HZ/2) /* 0.5 seconds */
@@ -330,6 +326,9 @@ struct bttv {
int opt_vcr_hack;
int opt_whitecrush_upper;
int opt_whitecrush_lower;
+ int opt_uv_ratio;
+ int opt_full_luma_range;
+ int opt_coring;
/* radio data/state */
int has_radio;
@@ -375,6 +374,10 @@ struct bttv {
unsigned int users;
struct bttv_fh init;
};
+
+/* our devices */
+#define BTTV_MAX 16
+extern unsigned int bttv_num;
extern struct bttv bttvs[BTTV_MAX];
/* private ioctls */
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index 46d6778b863b..4f39688f780a 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-blackbird.c,v 1.26 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-blackbird.c,v 1.27 2005/06/03 13:31:50 mchehab Exp $
*
* Support for a cx23416 mpeg encoder via cx2388x host port.
* "blackbird" reference design.
@@ -61,37 +61,304 @@ static LIST_HEAD(cx8802_devlist);
#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
-/*Firmware API commands*/
-#define IVTV_API_ENC_PING_FW 0x00000080
-#define IVTV_API_ENC_GETVER 0x000000C4
-#define IVTV_API_ENC_HALT_FW 0x000000C3
-#define IVTV_API_STD_TIMEOUT 0x00010000 /*units??*/
-//#define IVTV_API_ASSIGN_PGM_INDEX_INFO 0x000000c7
-#define IVTV_API_ASSIGN_STREAM_TYPE 0x000000b9
-#define IVTV_API_ASSIGN_OUTPUT_PORT 0x000000bb
-#define IVTV_API_ASSIGN_FRAMERATE 0x0000008f
-#define IVTV_API_ASSIGN_FRAME_SIZE 0x00000091
-#define IVTV_API_ASSIGN_ASPECT_RATIO 0x00000099
-#define IVTV_API_ASSIGN_BITRATES 0x00000095
-#define IVTV_API_ASSIGN_GOP_PROPERTIES 0x00000097
-#define IVTV_API_ASSIGN_3_2_PULLDOWN 0x000000b1
-#define IVTV_API_ASSIGN_GOP_CLOSURE 0x000000c5
-#define IVTV_API_ASSIGN_AUDIO_PROPERTIES 0x000000bd
-#define IVTV_API_ASSIGN_DNR_FILTER_MODE 0x0000009b
-#define IVTV_API_ASSIGN_DNR_FILTER_PROPS 0x0000009d
-#define IVTV_API_ASSIGN_CORING_LEVELS 0x0000009f
-#define IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE 0x000000a1
-#define IVTV_API_ASSIGN_FRAME_DROP_RATE 0x000000d0
-#define IVTV_API_ASSIGN_PLACEHOLDER 0x000000d8
-#define IVTV_API_MUTE_VIDEO 0x000000d9
-#define IVTV_API_MUTE_AUDIO 0x000000da
-#define IVTV_API_INITIALIZE_INPUT 0x000000cd
-#define IVTV_API_REFRESH_INPUT 0x000000d3
-#define IVTV_API_ASSIGN_NUM_VSYNC_LINES 0x000000d6
-#define IVTV_API_BEGIN_CAPTURE 0x00000081
-//#define IVTV_API_PAUSE_ENCODER 0x000000d2
-//#define IVTV_API_EVENT_NOTIFICATION 0x000000d5
-#define IVTV_API_END_CAPTURE 0x00000082
+/* Firmware API commands */
+/* #define IVTV_API_STD_TIMEOUT 0x00010000 // 65536, units?? */
+#define IVTV_API_STD_TIMEOUT 500
+
+#define BLACKBIRD_API_PING 0x80
+#define BLACKBIRD_API_BEGIN_CAPTURE 0x81
+enum blackbird_capture_type {
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_CAPTURE,
+ BLACKBIRD_RAW_PASSTHRU_CAPTURE
+};
+enum blackbird_capture_bits {
+ BLACKBIRD_RAW_BITS_NONE = 0x00,
+ BLACKBIRD_RAW_BITS_YUV_CAPTURE = 0x01,
+ BLACKBIRD_RAW_BITS_PCM_CAPTURE = 0x02,
+ BLACKBIRD_RAW_BITS_VBI_CAPTURE = 0x04,
+ BLACKBIRD_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ BLACKBIRD_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+#define BLACKBIRD_API_END_CAPTURE 0x82
+enum blackbird_capture_end {
+ BLACKBIRD_END_AT_GOP, /* stop at the end of gop, generate irq */
+ BLACKBIRD_END_NOW, /* stop immediately, no irq */
+};
+#define BLACKBIRD_API_SET_AUDIO_ID 0x89
+#define BLACKBIRD_API_SET_VIDEO_ID 0x8B
+#define BLACKBIRD_API_SET_PCR_ID 0x8D
+#define BLACKBIRD_API_SET_FRAMERATE 0x8F
+enum blackbird_framerate {
+ BLACKBIRD_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ BLACKBIRD_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+#define BLACKBIRD_API_SET_RESOLUTION 0x91
+#define BLACKBIRD_API_SET_VIDEO_BITRATE 0x95
+enum blackbird_video_bitrate_type {
+ BLACKBIRD_VIDEO_VBR,
+ BLACKBIRD_VIDEO_CBR
+};
+#define BLACKBIRD_PEAK_RATE_DIVISOR 400
+enum blackbird_mux_rate {
+ BLACKBIRD_MUX_RATE_DEFAULT,
+ /* dvd mux rate: multiply by 400 to get the actual rate */
+ BLACKBIRD_MUX_RATE_DVD = 25200
+};
+#define BLACKBIRD_API_SET_GOP_STRUCTURE 0x97
+#define BLACKBIRD_API_SET_ASPECT_RATIO 0x99
+enum blackbird_aspect_ratio {
+ BLACKBIRD_ASPECT_RATIO_FORBIDDEN,
+ BLACKBIRD_ASPECT_RATIO_1_1_SQUARE,
+ BLACKBIRD_ASPECT_RATIO_4_3,
+ BLACKBIRD_ASPECT_RATIO_16_9,
+ BLACKBIRD_ASPECT_RATIO_221_100,
+ BLACKBIRD_ASPECT_RATIO_RESERVED
+};
+#define BLACKBIRD_API_SET_DNR_MODE 0x9B
+enum blackbird_dnr_bits {
+ BLACKBIRD_DNR_BITS_MANUAL,
+ BLACKBIRD_DNR_BITS_AUTO_SPATIAL,
+ BLACKBIRD_DNR_BITS_AUTO_TEMPORAL,
+ BLACKBIRD_DNR_BITS_AUTO
+};
+enum blackbird_median_filter {
+ BLACKBIRD_MEDIAN_FILTER_DISABLED,
+ BLACKBIRD_MEDIAN_FILTER_HORIZONTAL,
+ BLACKBIRD_MEDIAN_FILTER_VERTICAL,
+ BLACKBIRD_MEDIAN_FILTER_HV,
+ BLACKBIRD_MEDIAN_FILTER_DIAGONAL
+};
+#define BLACKBIRD_API_SET_MANUAL_DNR 0x9D
+#define BLACKBIRD_API_SET_DNR_MEDIAN 0x9F
+#define BLACKBIRD_API_SET_SPATIAL_FILTER 0xA1
+enum blackbird_spatial_filter_luma {
+ BLACKBIRD_SPATIAL_FILTER_LUMA_DISABLED,
+ BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+ BLACKBIRD_SPATIAL_FILTER_LUMA_1D_VERT,
+ BLACKBIRD_SPATIAL_FILTER_LUMA_2D_HV, /* separable, default */
+ BLACKBIRD_SPATIAL_FILTER_LUMA_2D_SYMM /* symmetric non-separable */
+};
+enum blackbird_spatial_filter_chroma {
+ BLACKBIRD_SPATIAL_FILTER_CHROMA_DISABLED,
+ BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ /* default */
+};
+#define BLACKBIRD_API_SET_3_2_PULLDOWN 0xB1
+enum blackbird_pulldown {
+ BLACKBIRD_3_2_PULLDOWN_DISABLED,
+ BLACKBIRD_3_2_PULLDOWN_ENABLED
+};
+#define BLACKBIRD_API_SET_VBI_LINE_NO 0xB7
+enum blackbird_vbi_line_bits {
+ BLACKBIRD_VBI_LINE_BITS_TOP_FIELD,
+ BLACKBIRD_VBI_LINE_BITS_BOT_FIELD = (1 << 31),
+ BLACKBIRD_VBI_LINE_BITS_ALL_LINES = 0xFFFFFFFF
+};
+enum blackbird_vbi_line {
+ BLACKBIRD_VBI_LINE_DISABLED,
+ BLACKBIRD_VBI_LINE_ENABLED
+};
+enum blackbird_vbi_slicing {
+ BLACKBIRD_VBI_SLICING_NONE,
+ BLACKBIRD_VBI_SLICING_CLOSED_CAPTION
+};
+#define BLACKBIRD_API_SET_STREAM_TYPE 0xB9
+enum blackbird_stream_type {
+ BLACKBIRD_STREAM_PROGRAM,
+ BLACKBIRD_STREAM_TRANSPORT,
+ BLACKBIRD_STREAM_MPEG1,
+ BLACKBIRD_STREAM_PES_AV,
+ BLACKBIRD_STREAM_UNKNOWN4,
+ BLACKBIRD_STREAM_PES_VIDEO,
+ BLACKBIRD_STREAM_UNKNOWN6,
+ BLACKBIRD_STREAM_PES_AUDIO,
+ BLACKBIRD_STREAM_UNKNOWN8,
+ BLACKBIRD_STREAM_UNKNOWN9, /* audio/pcm ? */
+ BLACKBIRD_STREAM_DVD,
+ BLACKBIRD_STREAM_VCD,
+ BLACKBIRD_STREAM_UNKNOWN12 /* svcd/xvcd ? */
+};
+#define BLACKBIRD_API_SET_OUTPUT_PORT 0xBB
+enum blackbird_stream_port {
+ BLACKBIRD_OUTPUT_PORT_MEMORY,
+ BLACKBIRD_OUTPUT_PORT_STREAMING,
+ BLACKBIRD_OUTPUT_PORT_SERIAL
+};
+#define BLACKBIRD_API_SET_AUDIO_PARAMS 0xBD
+enum blackbird_audio_bits_sample_rate {
+ BLACKBIRD_AUDIO_BITS_44100HZ,
+ BLACKBIRD_AUDIO_BITS_48000HZ,
+ BLACKBIRD_AUDIO_BITS_32000HZ,
+ BLACKBIRD_AUDIO_BITS_RESERVED_HZ,
+};
+enum blackbird_audio_bits_encoding {
+ BLACKBIRD_AUDIO_BITS_LAYER_1 = 0x1 << 2,
+ BLACKBIRD_AUDIO_BITS_LAYER_2 = 0x2 << 2,
+};
+enum blackbird_audio_bits_bitrate_layer_1 {
+ BLACKBIRD_AUDIO_BITS_LAYER_1_FREE_FORMAT,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_32 = 0x01 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_64 = 0x02 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_96 = 0x03 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_128 = 0x04 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_160 = 0x05 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_192 = 0x06 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_224 = 0x07 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_256 = 0x08 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_288 = 0x09 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_320 = 0x0A << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_352 = 0x0B << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_384 = 0x0C << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_416 = 0x0D << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_1_448 = 0x0E << 4,
+};
+enum blackbird_audio_bits_bitrate_layer_2 {
+ BLACKBIRD_AUDIO_BITS_LAYER_2_FREE_FORMAT,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_32 = 0x01 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_48 = 0x02 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_56 = 0x03 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_64 = 0x04 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_80 = 0x05 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_96 = 0x06 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_112 = 0x07 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_128 = 0x08 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_160 = 0x09 << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_192 = 0x0A << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_224 = 0x0B << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_256 = 0x0C << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_320 = 0x0D << 4,
+ BLACKBIRD_AUDIO_BITS_LAYER_2_384 = 0x0E << 4,
+};
+enum blackbird_audio_bits_mode {
+ BLACKBIRD_AUDIO_BITS_STEREO,
+ BLACKBIRD_AUDIO_BITS_JOINT_STEREO = 0x1 << 8,
+ BLACKBIRD_AUDIO_BITS_DUAL = 0x2 << 8,
+ BLACKBIRD_AUDIO_BITS_MONO = 0x3 << 8,
+};
+enum blackbird_audio_bits_mode_extension {
+ BLACKBIRD_AUDIO_BITS_BOUND_4,
+ BLACKBIRD_AUDIO_BITS_BOUND_8 = 0x1 << 10,
+ BLACKBIRD_AUDIO_BITS_BOUND_12 = 0x2 << 10,
+ BLACKBIRD_AUDIO_BITS_BOUND_16 = 0x3 << 10,
+};
+enum blackbird_audio_bits_emphasis {
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE,
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_50_15 = 0x1 << 12,
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_RESERVED = 0x2 << 12,
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_CCITT_J17 = 0x3 << 12,
+};
+enum blackbird_audio_bits_crc {
+ BLACKBIRD_AUDIO_BITS_CRC_OFF,
+ BLACKBIRD_AUDIO_BITS_CRC_ON = 0x1 << 14,
+};
+enum blackbird_audio_bits_copyright {
+ BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF,
+ BLACKBIRD_AUDIO_BITS_COPYRIGHT_ON = 0x1 << 15,
+};
+enum blackbird_audio_bits_original {
+ BLACKBIRD_AUDIO_BITS_COPY,
+ BLACKBIRD_AUDIO_BITS_ORIGINAL = 0x1 << 16,
+};
+#define BLACKBIRD_API_HALT 0xC3
+#define BLACKBIRD_API_GET_VERSION 0xC4
+#define BLACKBIRD_API_SET_GOP_CLOSURE 0xC5
+enum blackbird_gop_closure {
+ BLACKBIRD_GOP_CLOSURE_OFF,
+ BLACKBIRD_GOP_CLOSURE_ON,
+};
+#define BLACKBIRD_API_DATA_XFER_STATUS 0xC6
+enum blackbird_data_xfer_status {
+ BLACKBIRD_MORE_BUFFERS_FOLLOW,
+ BLACKBIRD_LAST_BUFFER,
+};
+#define BLACKBIRD_API_PROGRAM_INDEX_INFO 0xC7
+enum blackbird_picture_mask {
+ BLACKBIRD_PICTURE_MASK_NONE,
+ BLACKBIRD_PICTURE_MASK_I_FRAMES,
+ BLACKBIRD_PICTURE_MASK_I_P_FRAMES = 0x3,
+ BLACKBIRD_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+#define BLACKBIRD_API_SET_VBI_PARAMS 0xC8
+enum blackbird_vbi_mode_bits {
+ BLACKBIRD_VBI_BITS_SLICED,
+ BLACKBIRD_VBI_BITS_RAW,
+};
+enum blackbird_vbi_insertion_bits {
+ BLACKBIRD_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ BLACKBIRD_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ BLACKBIRD_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ BLACKBIRD_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ BLACKBIRD_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+#define BLACKBIRD_API_SET_DMA_BLOCK_SIZE 0xC9
+enum blackbird_dma_unit {
+ BLACKBIRD_DMA_BYTES,
+ BLACKBIRD_DMA_FRAMES,
+};
+#define BLACKBIRD_API_DMA_TRANSFER_INFO 0xCA
+#define BLACKBIRD_API_DMA_TRANSFER_STAT 0xCB
+enum blackbird_dma_transfer_status_bits {
+ BLACKBIRD_DMA_TRANSFER_BITS_DONE = 0x01,
+ BLACKBIRD_DMA_TRANSFER_BITS_ERROR = 0x04,
+ BLACKBIRD_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+#define BLACKBIRD_API_SET_DMA2HOST_ADDR 0xCC
+#define BLACKBIRD_API_INIT_VIDEO_INPUT 0xCD
+#define BLACKBIRD_API_SET_FRAMESKIP 0xD0
+#define BLACKBIRD_API_PAUSE 0xD2
+enum blackbird_pause {
+ BLACKBIRD_PAUSE_ENCODING,
+ BLACKBIRD_RESUME_ENCODING,
+};
+#define BLACKBIRD_API_REFRESH_INPUT 0xD3
+#define BLACKBIRD_API_SET_COPYRIGHT 0xD4
+enum blackbird_copyright {
+ BLACKBIRD_COPYRIGHT_OFF,
+ BLACKBIRD_COPYRIGHT_ON,
+};
+#define BLACKBIRD_API_SET_NOTIFICATION 0xD5
+enum blackbird_notification_type {
+ BLACKBIRD_NOTIFICATION_REFRESH,
+};
+enum blackbird_notification_status {
+ BLACKBIRD_NOTIFICATION_OFF,
+ BLACKBIRD_NOTIFICATION_ON,
+};
+enum blackbird_notification_mailbox {
+ BLACKBIRD_NOTIFICATION_NO_MAILBOX = -1,
+};
+#define BLACKBIRD_API_SET_CAPTURE_LINES 0xD6
+enum blackbird_field1_lines {
+ BLACKBIRD_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ BLACKBIRD_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ BLACKBIRD_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum blackbird_field2_lines {
+ BLACKBIRD_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ BLACKBIRD_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ BLACKBIRD_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+#define BLACKBIRD_API_SET_CUSTOM_DATA 0xD7
+enum blackbird_custom_data_type {
+ BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+ BLACKBIRD_CUSTOM_PRIVATE_PACKET,
+};
+#define BLACKBIRD_API_MUTE_VIDEO 0xD9
+enum blackbird_mute {
+ BLACKBIRD_UNMUTE,
+ BLACKBIRD_MUTE,
+};
+enum blackbird_mute_video_mask {
+ BLACKBIRD_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ BLACKBIRD_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ BLACKBIRD_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum blackbird_mute_video_shift {
+ BLACKBIRD_MUTE_VIDEO_V_SHIFT = 8,
+ BLACKBIRD_MUTE_VIDEO_U_SHIFT = 16,
+ BLACKBIRD_MUTE_VIDEO_Y_SHIFT = 24,
+};
+#define BLACKBIRD_API_MUTE_AUDIO 0xDA
/* Registers */
#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8 /*| IVTV_REG_OFFSET*/)
@@ -405,68 +672,98 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
return 0;
}
+/**
+ Settings used by the windows tv app for PVR2000:
+=================================================================================================================
+Profile | Codec | Resolution | CBR/VBR | Video Qlty | V. Bitrate | Frmrate | Audio Codec | A. Bitrate | A. Mode
+-----------------------------------------------------------------------------------------------------------------
+MPEG-1 | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 2000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo
+MPEG-2 | MPEG2 | 720x576PAL | VBR | 600 :Good | 4000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo
+VCD | MPEG1 | 352x288PAL | (CBR) | 1000:Optimal | 1150 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo
+DVD | MPEG2 | 720x576PAL | VBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo
+DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | MPG1 Layer2 | 224kbps | Stereo
+=================================================================================================================
+*DB: "DirectBurn"
+*/
static void blackbird_codec_settings(struct cx8802_dev *dev)
{
int bitrate_mode = 1;
int bitrate = 7500000;
int bitrate_peak = 7500000;
+ bitrate_mode = BLACKBIRD_VIDEO_CBR;
+ bitrate = 4000*1024;
+ bitrate_peak = 4000*1024;
/* assign stream type */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 0); /* program stream */
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 2); /* MPEG1 stream */
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 3); /* PES A/V */
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_STREAM_TYPE, 1, 0, 10); /* DVD stream */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_PROGRAM);
+ /* blackbird_api_cmd(dev, BLACKBIRD_API_SET_STREAM_TYPE, 1, 0, BLACKBIRD_STREAM_TRANSPORT); */
- /* assign output port */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_OUTPUT_PORT, 1, 0, 1); /* 1 = Host */
+ /* assign output port */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_OUTPUT_PORT, 1, 0, BLACKBIRD_OUTPUT_PORT_STREAMING); /* Host */
- /* assign framerate */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAMERATE, 1, 0, 0);
+ /* assign framerate */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_FRAMERATE, 1, 0, BLACKBIRD_FRAMERATE_PAL_25);
- /* assign frame size */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_SIZE, 2, 0,
+ /* assign frame size */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_RESOLUTION, 2, 0,
dev->height, dev->width);
- /* assign aspect ratio */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_ASPECT_RATIO, 1, 0, 2);
+ /* assign aspect ratio */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_ASPECT_RATIO, 1, 0, BLACKBIRD_ASPECT_RATIO_4_3);
- /* assign bitrates */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_BITRATES, 5, 0,
+ /* assign bitrates */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_VIDEO_BITRATE, 5, 0,
bitrate_mode, /* mode */
bitrate, /* bps */
- bitrate_peak / 400, /* peak/400 */
- 0, 0x70); /* encoding buffer, ckennedy */
-
- /* assign gop properties */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 15, 3);
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_PROPERTIES, 2, 0, 2, 1);
-
- /* assign 3 2 pulldown */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_3_2_PULLDOWN, 1, 0, 0);
-
- /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
+ bitrate_peak / BLACKBIRD_PEAK_RATE_DIVISOR, /* peak/400 */
+ BLACKBIRD_MUX_RATE_DEFAULT /*, 0x70*/); /* encoding buffer, ckennedy */
+
+ /* assign gop properties */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_STRUCTURE, 2, 0, 15, 3);
+
+ /* assign 3 2 pulldown */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_3_2_PULLDOWN, 1, 0, BLACKBIRD_3_2_PULLDOWN_DISABLED);
+
+ /* assign audio properties */
+ /* note: it's not necessary to set the samplerate, the mpeg encoder seems to autodetect/adjust */
+ /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, (2<<2) | (8<<4));
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4)); */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_AUDIO_PARAMS, 1, 0,
+ BLACKBIRD_AUDIO_BITS_44100HZ |
+ BLACKBIRD_AUDIO_BITS_LAYER_2 |
+ BLACKBIRD_AUDIO_BITS_LAYER_2_224 |
+ BLACKBIRD_AUDIO_BITS_STEREO |
+ /* BLACKBIRD_AUDIO_BITS_BOUND_4 | */
+ BLACKBIRD_AUDIO_BITS_EMPHASIS_NONE |
+ BLACKBIRD_AUDIO_BITS_CRC_OFF |
+ BLACKBIRD_AUDIO_BITS_COPYRIGHT_OFF |
+ BLACKBIRD_AUDIO_BITS_COPY
+ );
/* assign gop closure */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_GOP_CLOSURE, 1, 0, 0);
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_GOP_CLOSURE, 1, 0, BLACKBIRD_GOP_CLOSURE_OFF);
- /* assign audio properties */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_AUDIO_PROPERTIES, 1, 0, 0 | (2 << 2) | (14 << 4));
- /* assign dnr filter mode */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_MODE, 2, 0, 0, 0);
+ /* assign dnr filter mode */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MODE, 2, 0,
+ BLACKBIRD_DNR_BITS_MANUAL,
+ BLACKBIRD_MEDIAN_FILTER_DISABLED
+ );
- /* assign dnr filter props*/
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_DNR_FILTER_PROPS, 2, 0, 0, 0);
+ /* assign dnr filter props*/
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_MANUAL_DNR, 2, 0, 0, 0);
- /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_CORING_LEVELS, 4, 0, 0, 255, 0, 255);
+ /* assign coring levels (luma_h, luma_l, chroma_h, chroma_l) */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_DNR_MEDIAN, 4, 0, 0, 255, 0, 255);
- /* assign spatial filter type: luma_t: 1 = horiz_only, chroma_t: 1 = horiz_only */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_SPATIAL_FILTER_TYPE, 2, 0, 1, 1);
+ /* assign spatial filter type: luma_t: horiz_only, chroma_t: horiz_only */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_SPATIAL_FILTER, 2, 0,
+ BLACKBIRD_SPATIAL_FILTER_LUMA_1D_HORIZ,
+ BLACKBIRD_SPATIAL_FILTER_CHROMA_1D_HORIZ
+ );
- /* assign frame drop rate */
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0);
+ /* assign frame drop rate */
+ /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_FRAME_DROP_RATE, 1, 0, 0); */
}
static int blackbird_initialize_codec(struct cx8802_dev *dev)
@@ -476,7 +773,7 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
int retval;
dprintk(1,"Initialize codec\n");
- retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
if (retval < 0) {
/* ping was not successful, reset and upload firmware */
cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
@@ -491,13 +788,13 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
if (dev->mailbox < 0)
return -1;
- retval = blackbird_api_cmd(dev, IVTV_API_ENC_PING_FW, 0, 0); /* ping */
+ retval = blackbird_api_cmd(dev, BLACKBIRD_API_PING, 0, 0); /* ping */
if (retval < 0) {
dprintk(0, "ERROR: Firmware ping failed!\n");
return -1;
}
- retval = blackbird_api_cmd(dev, IVTV_API_ENC_GETVER, 0, 1, &version);
+ retval = blackbird_api_cmd(dev, BLACKBIRD_API_GET_VERSION, 0, 1, &version);
if (retval < 0) {
dprintk(0, "ERROR: Firmware get encoder version failed!\n");
return -1;
@@ -511,31 +808,39 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
cx_write(MO_VBOS_CONTROL, 0x84A00); /* no 656 mode, 8-bit pixels, disable VBI */
cx_clear(MO_OUTPUT_FORMAT, 0x0008); /* Normal Y-limits to let the mpeg encoder sync */
-#if 0 /* FIXME */
- set_scale(dev, 720, 480, V4L2_FIELD_INTERLACED);
-#endif
blackbird_codec_settings(dev);
msleep(1);
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
- //blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180);
- blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xef, 0xef);
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0xf0, 0xf0);
+ blackbird_api_cmd(dev, IVTV_API_ASSIGN_NUM_VSYNC_LINES, 4, 0, 0x180, 0x180); */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_CAPTURE_LINES, 2, 0,
+ BLACKBIRD_FIELD1_SAA7115,
+ BLACKBIRD_FIELD1_SAA7115
+ );
+
+ /* blackbird_api_cmd(dev, IVTV_API_ASSIGN_PLACEHOLDER, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); */
+ blackbird_api_cmd(dev, BLACKBIRD_API_SET_CUSTOM_DATA, 12, 0,
+ BLACKBIRD_CUSTOM_EXTENSION_USR_DATA,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
- blackbird_api_cmd(dev, IVTV_API_INITIALIZE_INPUT, 0, 0); /* initialize the video input */
+ blackbird_api_cmd(dev, BLACKBIRD_API_INIT_VIDEO_INPUT, 0, 0); /* initialize the video input */
msleep(1);
- blackbird_api_cmd(dev, IVTV_API_MUTE_VIDEO, 1, 0, 0);
+ blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_VIDEO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
- blackbird_api_cmd(dev, IVTV_API_MUTE_AUDIO, 1, 0, 0);
+ blackbird_api_cmd(dev, BLACKBIRD_API_MUTE_AUDIO, 1, 0, BLACKBIRD_UNMUTE);
msleep(1);
- blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); /* start capturing to the host interface */
- //blackbird_api_cmd(dev, IVTV_API_BEGIN_CAPTURE, 2, 0, 0, 0); /* start capturing to the host interface */
- msleep(1);
+ /* blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0, 0, 0x13); // start capturing to the host interface */
+ blackbird_api_cmd(dev, BLACKBIRD_API_BEGIN_CAPTURE, 2, 0,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE
+ ); /* start capturing to the host interface */
+ msleep(10);
- blackbird_api_cmd(dev, IVTV_API_REFRESH_INPUT, 0,0);
+ blackbird_api_cmd(dev, BLACKBIRD_API_REFRESH_INPUT, 0,0);
return 0;
}
@@ -709,7 +1014,12 @@ static int mpeg_release(struct inode *inode, struct file *file)
{
struct cx8802_fh *fh = file->private_data;
- blackbird_api_cmd(fh->dev, IVTV_API_END_CAPTURE, 3, 0, 1, 0, 0x13);
+ /* blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0, BLACKBIRD_END_NOW, 0, 0x13); */
+ blackbird_api_cmd(fh->dev, BLACKBIRD_API_END_CAPTURE, 3, 0,
+ BLACKBIRD_END_NOW,
+ BLACKBIRD_MPEG_CAPTURE,
+ BLACKBIRD_RAW_BITS_NONE
+ );
/* stop mpeg capture */
if (fh->mpegq.streaming)
@@ -908,4 +1218,5 @@ module_exit(blackbird_fini);
* Local variables:
* c-basic-offset: 8
* End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
*/
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 367624822d77..b0b47c3cde3c 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-cards.c,v 1.66 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88-cards.c,v 1.85 2005/07/04 19:35:05 mkrufky Exp $
*
* device driver for Conexant 2388x based TV cards
* card-specific stuff.
@@ -35,6 +35,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_UNKNOWN] = {
.name = "UNKNOWN/GENERIC",
.tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
@@ -52,6 +55,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_HAUPPAUGE] = {
.name = "Hauppauge WinTV 34xxx models",
.tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -78,6 +84,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_GDI] = {
.name = "GDI Black Gold",
.tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -85,7 +94,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_PIXELVIEW] = {
.name = "PixelView",
- .tuner_type = 5,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -104,7 +116,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_ATI_WONDER_PRO] = {
.name = "ATI TV Wonder Pro",
- .tuner_type = 44,
+ .tuner_type = TUNER_PHILIPS_4IN1,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -122,7 +137,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_WINFAST2000XP_EXPERT] = {
.name = "Leadtek Winfast 2000XP Expert",
- .tuner_type = 44,
+ .tuner_type = TUNER_PHILIPS_4IN1,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -156,7 +174,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_AVERTV_303] = {
.name = "AverTV Studio 303 (M126)",
- .tuner_type = 38,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -179,7 +200,10 @@ struct cx88_board cx88_boards[] = {
// added gpio values thanks to Michal
// values for PAL from DScaler
.name = "MSI TV-@nywhere Master",
- .tuner_type = 33,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -206,7 +230,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_WINFAST_DV2000] = {
.name = "Leadtek Winfast DV2000",
- .tuner_type = 38,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -239,34 +266,40 @@ struct cx88_board cx88_boards[] = {
.gpio3 = 0x02000000,
},
},
- [CX88_BOARD_LEADTEK_PVR2000] = {
+ [CX88_BOARD_LEADTEK_PVR2000] = {
// gpio values for PAL version from regspy by DScaler
- .name = "Leadtek PVR 2000",
- .tuner_type = 38,
+ .name = "Leadtek PVR 2000",
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .input = {{
- .type = CX88_VMUX_TELEVISION,
- .vmux = 0,
- .gpio0 = 0x0000bde6,
- },{
- .type = CX88_VMUX_COMPOSITE1,
- .vmux = 1,
- .gpio0 = 0x0000bde6,
- },{
- .type = CX88_VMUX_SVIDEO,
- .vmux = 2,
- .gpio0 = 0x0000bde6,
- }},
- .radio = {
- .type = CX88_RADIO,
- .gpio0 = 0x0000bd62,
- },
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0000bde2,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0000bde6,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0000bde6,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x0000bd62,
+ },
.blackbird = 1,
- },
+ },
[CX88_BOARD_IODATA_GVVCP3PCI] = {
.name = "IODATA GV-VCP3/PCI",
.tuner_type = TUNER_ABSENT,
- .input = {{
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 0,
},{
@@ -279,7 +312,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_PROLINK_PLAYTVPVR] = {
.name = "Prolink PlayTV PVR",
- .tuner_type = 43,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -301,8 +337,11 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_ASUS_PVR_416] = {
.name = "ASUS PVR-416",
- .tuner_type = 43,
- .tda9887_conf = TDA9887_PRESENT,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -320,7 +359,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_MSI_TVANYWHERE] = {
.name = "MSI TV-@nywhere",
- .tuner_type = 33,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -342,6 +384,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_KWORLD_DVB_T] = {
.name = "KWorld/VStream XPert DVB-T",
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -356,8 +401,11 @@ struct cx88_board cx88_boards[] = {
.dvb = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
- .name = "DVICO FusionHDTV DVB-T1",
+ .name = "DViCO FusionHDTV DVB-T1",
.tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -371,7 +419,10 @@ struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_KWORLD_LTV883] = {
.name = "KWorld LTV883RF",
- .tuner_type = 48,
+ .tuner_type = TUNER_TNF_8831BGFF,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -394,9 +445,12 @@ struct cx88_board cx88_boards[] = {
.gpio0 = 0x000007f8,
},
},
- [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD] = {
- .name = "DViCO - FusionHDTV 3 Gold",
+ [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q] = {
+ .name = "DViCO FusionHDTV 3 Gold-Q",
.tuner_type = TUNER_MICROTUNE_4042FI5,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
/*
GPIO[0] resets DT3302 DTV receiver
0 - reset asserted
@@ -410,6 +464,9 @@ struct cx88_board cx88_boards[] = {
GPIO[3] selects RF input connector on tuner module
0 - RF connector labeled CABLE
1 - RF connector labeled ANT
+ GPIO[4] selects high RF for QAM256 mode
+ 0 - normal RF
+ 1 - high RF
*/
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -428,17 +485,15 @@ struct cx88_board cx88_boards[] = {
.vmux = 2,
.gpio0 = 0x0f00,
}},
-#if 0
- .ts = {
- .type = CX88_TS,
- .gpio0 = 0x00000f01, /* Hooked to tuner reset bit */
- }
-#endif
+ .dvb = 1,
},
[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
- .name = "Hauppauge Nova-T DVB-T",
+ .name = "Hauppauge Nova-T DVB-T",
.tuner_type = TUNER_ABSENT,
- .input = {{
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
}},
@@ -447,6 +502,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_CONEXANT_DVB_T1] = {
.name = "Conexant DVB-T reference design",
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
@@ -456,6 +514,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_PROVIDEO_PV259] = {
.name = "Provideo PV259",
.tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -463,8 +524,11 @@ struct cx88_board cx88_boards[] = {
.blackbird = 1,
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
- .name = "DVICO FusionHDTV DVB-T Plus",
+ .name = "DViCO FusionHDTV DVB-T Plus",
.tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -479,6 +543,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
.name = "digitalnow DNTV Live! DVB-T",
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
@@ -495,6 +562,9 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_PCHDTV_HD3000] = {
.name = "pcHDTV HD3000 HDTV",
.tuner_type = TUNER_THOMSON_DTT7610,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -530,8 +600,11 @@ struct cx88_board cx88_boards[] = {
[CX88_BOARD_HAUPPAUGE_ROSLYN] = {
// entry added by Kaustubh D. Bhalerao <bhalerao.1@osu.edu>
// GPIO values obtained from regspy, courtesy Sean Covel
- .name = "Hauppauge WinTV 28xxx (Roslyn) models",
- .tuner_type = UNSET,
+ .name = "Hauppauge WinTV 28xxx (Roslyn) models",
+ .tuner_type = UNSET,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
@@ -559,33 +632,37 @@ struct cx88_board cx88_boards[] = {
.blackbird = 1,
},
[CX88_BOARD_DIGITALLOGIC_MEC] = {
- /* params copied over from Leadtek PVR 2000 */
.name = "Digital-Logic MICROSPACE Entertainment Center (MEC)",
- /* not sure yet about the tuner type */
- .tuner_type = 38,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
.vmux = 0,
- .gpio0 = 0x0000bde6,
+ .gpio0 = 0x00009d80,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
- .gpio0 = 0x0000bde6,
+ .gpio0 = 0x00009d76,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
- .gpio0 = 0x0000bde6,
+ .gpio0 = 0x00009d76,
}},
.radio = {
.type = CX88_RADIO,
- .gpio0 = 0x0000bd62,
+ .gpio0 = 0x00009d00,
},
.blackbird = 1,
},
[CX88_BOARD_IODATA_GVBCTV7E] = {
.name = "IODATA GV/BCTV7E",
.tuner_type = TUNER_PHILIPS_FQ1286,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.input = {{
.type = CX88_VMUX_TELEVISION,
@@ -601,6 +678,81 @@ struct cx88_board cx88_boards[] = {
.gpio1 = 0x0000e07f,
}}
},
+ [CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO] = {
+ .name = "PixelView PlayTV Ultra Pro (Stereo)",
+ /* May be also TUNER_YMEC_TVF_5533MF for NTSC/M or PAL/M */
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0xc2>>1,
+ .radio_addr = 0xc0>>1,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0xbf61, /* internal decoder */
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0xbf63,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0xbf63,
+ }},
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xbf60,
+ },
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T] = {
+ .name = "DViCO FusionHDTV 3 Gold-T",
+ .tuner_type = TUNER_THOMSON_DTT7611,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* See DViCO FusionHDTV 3 Gold-Q for GPIO documentation. */
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0f0d,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0f00,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0f00,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_ADSTECH_DVB_T_PCI] = {
+ .name = "ADS Tech Instant TV DVB-T PCI",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x0700,
+ .gpio2 = 0x0101,
+ }},
+ .dvb = 1,
+ },
+ [CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
+ .name = "TerraTec Cinergy 1400 DVB-T",
+ .tuner_type = TUNER_ABSENT,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ }},
+ .dvb = 1,
+ },
};
const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
@@ -671,7 +823,11 @@ struct cx88_subid cx88_subids[] = {
},{
.subvendor = 0x18ac,
.subdevice = 0xd810,
- .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q,
+ },{
+ .subvendor = 0x18ac,
+ .subdevice = 0xd820,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T,
},{
.subvendor = 0x18AC,
.subdevice = 0xDB00,
@@ -716,7 +872,15 @@ struct cx88_subid cx88_subids[] = {
.subvendor = 0x10fc,
.subdevice = 0xd035,
.card = CX88_BOARD_IODATA_GVBCTV7E,
- }
+ },{
+ .subvendor = 0x1421,
+ .subdevice = 0x0334,
+ .card = CX88_BOARD_ADSTECH_DVB_T_PCI,
+ },{
+ .subvendor = 0x153b,
+ .subdevice = 0x1166,
+ .card = CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1,
+ },
};
const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
@@ -935,4 +1099,5 @@ EXPORT_SYMBOL(cx88_card_setup);
* Local variables:
* c-basic-offset: 8
* End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
*/
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 1ff79b5a8835..5e868f5cd0c0 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-core.c,v 1.24 2005/01/19 12:01:55 kraxel Exp $
+ * $Id: cx88-core.c,v 1.33 2005/07/07 14:17:47 mchehab Exp $
*
* device driver for Conexant 2388x based TV cards
* driver core
@@ -51,12 +51,15 @@ module_param(latency,int,0444);
MODULE_PARM_DESC(latency,"pci latency timer");
static unsigned int tuner[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
+static unsigned int radio[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
static unsigned int card[] = {[0 ... (CX88_MAXBOARDS - 1)] = UNSET };
module_param_array(tuner, int, NULL, 0444);
+module_param_array(radio, int, NULL, 0444);
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(tuner,"tuner type");
+MODULE_PARM_DESC(radio,"radio tuner type");
MODULE_PARM_DESC(card,"card type");
static unsigned int nicam = 0;
@@ -429,7 +432,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
/* ------------------------------------------------------------------ */
/* debug helper code */
-static int cx88_risc_decode(u32 risc)
+int cx88_risc_decode(u32 risc)
{
static char *instr[16] = {
[ RISC_SYNC >> 28 ] = "sync",
@@ -467,25 +470,6 @@ static int cx88_risc_decode(u32 risc)
return incr[risc >> 28] ? incr[risc >> 28] : 1;
}
-#if 0 /* currently unused, but useful for debugging */
-void cx88_risc_disasm(struct cx88_core *core,
- struct btcx_riscmem *risc)
-{
- unsigned int i,j,n;
-
- printk("%s: risc disasm: %p [dma=0x%08lx]\n",
- core->name, risc->cpu, (unsigned long)risc->dma);
- for (i = 0; i < (risc->size >> 2); i += n) {
- printk("%s: %04d: ", core->name, i);
- n = cx88_risc_decode(risc->cpu[i]);
- for (j = 1; j < n; j++)
- printk("%s: %04d: 0x%08x [ arg #%d ]\n",
- core->name, i+j, risc->cpu[i+j], j);
- if (risc->cpu[i] == RISC_JUMP)
- break;
- }
-}
-#endif
void cx88_sram_channel_dump(struct cx88_core *core,
struct sram_channel *ch)
@@ -548,21 +532,6 @@ static char *cx88_pci_irqs[32] = {
"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
"i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
};
-char *cx88_vid_irqs[32] = {
- "y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
- "y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
- "y_oflow", "u_oflow", "v_oflow", "vbi_oflow",
- "y_sync", "u_sync", "v_sync", "vbi_sync",
- "opc_err", "par_err", "rip_err", "pci_abort",
-};
-char *cx88_mpeg_irqs[32] = {
- "ts_risci1", NULL, NULL, NULL,
- "ts_risci2", NULL, NULL, NULL,
- "ts_oflow", NULL, NULL, NULL,
- "ts_sync", NULL, NULL, NULL,
- "opc_err", "par_err", "rip_err", "pci_abort",
- "ts_err?",
-};
void cx88_print_irqbits(char *name, char *tag, char **strings,
u32 bits, u32 mask)
@@ -612,16 +581,11 @@ void cx88_wakeup(struct cx88_core *core,
break;
buf = list_entry(q->active.next,
struct cx88_buffer, vb.queue);
-#if 0
- if (buf->count > count)
- break;
-#else
/* count comes from the hw and is is 16bit wide --
* this trick handles wrap-arounds correctly for
* up to 32767 buffers in flight... */
if ((s16) (count - buf->count) < 0)
break;
-#endif
do_gettimeofday(&buf->vb.ts);
dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
count, buf->count);
@@ -736,6 +700,10 @@ static unsigned int inline norm_fsc8(struct cx88_tvnorm *norm)
{
static const unsigned int ntsc = 28636360;
static const unsigned int pal = 35468950;
+ static const unsigned int palm = 28604892;
+
+ if (norm->id & V4L2_STD_PAL_M)
+ return palm;
return (norm->id & V4L2_STD_625_50) ? pal : ntsc;
}
@@ -749,6 +717,11 @@ static unsigned int inline norm_notchfilter(struct cx88_tvnorm *norm)
static unsigned int inline norm_htotal(struct cx88_tvnorm *norm)
{
+ /* Should always be Line Draw Time / (4*FSC) */
+
+ if (norm->id & V4L2_STD_PAL_M)
+ return 909;
+
return (norm->id & V4L2_STD_625_50) ? 1135 : 910;
}
@@ -940,12 +913,10 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
norm->cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
cx_andor(MO_INPUT_FORMAT, 0xf, norm->cxiformat);
-#if 1
// FIXME: as-is from DScaler
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
norm->cxoformat, cx_read(MO_OUTPUT_FORMAT));
cx_write(MO_OUTPUT_FORMAT, norm->cxoformat);
-#endif
// MO_SCONV_REG = adc clock / video dec clock * 2^17
tmp64 = adc_clock * (u64)(1 << 17);
@@ -994,21 +965,7 @@ int cx88_set_tvnorm(struct cx88_core *core, struct cx88_tvnorm *norm)
set_tvaudio(core);
// tell i2c chips
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(core,VIDIOC_S_STD,&norm->id);
-#else
- {
- struct video_channel c;
- memset(&c,0,sizeof(c));
- c.channel = core->input;
- c.norm = VIDEO_MODE_PAL;
- if ((norm->id & (V4L2_STD_NTSC_M|V4L2_STD_NTSC_M_JP)))
- c.norm = VIDEO_MODE_NTSC;
- if (norm->id & V4L2_STD_SECAM)
- c.norm = VIDEO_MODE_SECAM;
- cx88_call_i2c_clients(core,VIDIOCSCHAN,&c);
- }
-#endif
// done
return 0;
@@ -1164,8 +1121,20 @@ struct cx88_core* cx88_core_get(struct pci_dev *pci)
"insmod option" : "autodetected");
core->tuner_type = tuner[core->nr];
+ core->radio_type = radio[core->nr];
if (UNSET == core->tuner_type)
core->tuner_type = cx88_boards[core->board].tuner_type;
+ if (UNSET == core->radio_type)
+ core->radio_type = cx88_boards[core->board].radio_type;
+ if (!core->tuner_addr)
+ core->tuner_addr = cx88_boards[core->board].tuner_addr;
+ if (!core->radio_addr)
+ core->radio_addr = cx88_boards[core->board].radio_addr;
+
+ printk(KERN_INFO "TV tuner %d at 0x%02x, Radio tuner %d at 0x%02x\n",
+ core->tuner_type, core->tuner_addr<<1,
+ core->radio_type, core->radio_addr<<1);
+
core->tda9887_conf = cx88_boards[core->board].tda9887_conf;
/* init hardware */
@@ -1206,8 +1175,6 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci)
/* ------------------------------------------------------------------ */
EXPORT_SYMBOL(cx88_print_ioctl);
-EXPORT_SYMBOL(cx88_vid_irqs);
-EXPORT_SYMBOL(cx88_mpeg_irqs);
EXPORT_SYMBOL(cx88_print_irqbits);
EXPORT_SYMBOL(cx88_core_irq);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index 9d15d3d5a2b7..8db68f2d1351 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-dvb.c,v 1.31 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-dvb.c,v 1.41 2005/07/04 19:35:05 mkrufky Exp $
*
* device driver for Conexant 2388x based TV cards
* MPEG Transport Stream (DVB) routines
@@ -30,20 +30,27 @@
#include <linux/file.h>
#include <linux/suspend.h>
-/* those two frontends need merging via linuxtv cvs ... */
-#define HAVE_CX22702 1
-#define HAVE_OR51132 1
+#define CONFIG_DVB_MT352 1
+#define CONFIG_DVB_CX22702 1
+#define CONFIG_DVB_OR51132 1
+#define CONFIG_DVB_LGDT3302 1
#include "cx88.h"
#include "dvb-pll.h"
-#include "mt352.h"
-#include "mt352_priv.h"
-#if HAVE_CX22702
+
+#if CONFIG_DVB_MT352
+# include "mt352.h"
+# include "mt352_priv.h"
+#endif
+#if CONFIG_DVB_CX22702
# include "cx22702.h"
#endif
-#if HAVE_OR51132
+#if CONFIG_DVB_OR51132
# include "or51132.h"
#endif
+#if CONFIG_DVB_LGDT3302
+# include "lgdt3302.h"
+#endif
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -100,6 +107,7 @@ static struct videobuf_queue_ops dvb_qops = {
/* ------------------------------------------------------------------ */
+#if CONFIG_DVB_MT352
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
@@ -167,8 +175,9 @@ static struct mt352_config dntv_live_dvbt_config = {
.demod_init = dntv_live_dvbt_demod_init,
.pll_set = mt352_pll_set,
};
+#endif
-#if HAVE_CX22702
+#if CONFIG_DVB_CX22702
static struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.pll_address = 0x60,
@@ -182,7 +191,7 @@ static struct cx22702_config hauppauge_novat_config = {
};
#endif
-#if HAVE_OR51132
+#if CONFIG_DVB_OR51132
static int or51132_set_ts_param(struct dvb_frontend* fe,
int is_punctured)
{
@@ -199,6 +208,32 @@ static struct or51132_config pchdtv_hd3000 = {
};
#endif
+#if CONFIG_DVB_LGDT3302
+static int lgdt3302_set_ts_param(struct dvb_frontend* fe, int is_punctured)
+{
+ struct cx8802_dev *dev= fe->dvb->priv;
+ if (is_punctured)
+ dev->ts_gen_cntrl |= 0x04;
+ else
+ dev->ts_gen_cntrl &= ~0x04;
+ return 0;
+}
+
+static struct lgdt3302_config fusionhdtv_3_gold_q = {
+ .demod_address = 0x0e,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_microtune_4042,
+ .set_ts_params = lgdt3302_set_ts_param,
+};
+
+static struct lgdt3302_config fusionhdtv_3_gold_t = {
+ .demod_address = 0x0e,
+ .pll_address = 0x61,
+ .pll_desc = &dvb_pll_thomson_dtt7611,
+ .set_ts_params = lgdt3302_set_ts_param,
+};
+#endif
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -207,16 +242,18 @@ static int dvb_register(struct cx8802_dev *dev)
/* init frontend */
switch (dev->core->board) {
-#if HAVE_CX22702
+#if CONFIG_DVB_CX22702
case CX88_BOARD_HAUPPAUGE_DVB_T1:
dev->dvb.frontend = cx22702_attach(&hauppauge_novat_config,
&dev->core->i2c_adap);
break;
+ case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
case CX88_BOARD_CONEXANT_DVB_T1:
dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
&dev->core->i2c_adap);
break;
#endif
+#if CONFIG_DVB_MT352
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_lg_z201;
@@ -231,17 +268,49 @@ static int dvb_register(struct cx8802_dev *dev)
break;
case CX88_BOARD_KWORLD_DVB_T:
case CX88_BOARD_DNTV_LIVE_DVB_T:
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
dev->core->pll_addr = 0x61;
dev->core->pll_desc = &dvb_pll_unknown_1;
dev->dvb.frontend = mt352_attach(&dntv_live_dvbt_config,
&dev->core->i2c_adap);
break;
-#if HAVE_OR51132
+#endif
+#if CONFIG_DVB_OR51132
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = or51132_attach(&pchdtv_hd3000,
&dev->core->i2c_adap);
break;
#endif
+#if CONFIG_DVB_LGDT3302
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 9); // ANT connector too FIXME
+ mdelay(200);
+ dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_q,
+ &dev->core->i2c_adap);
+ }
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T:
+ dev->ts_gen_cntrl = 0x08;
+ {
+ /* Do a hardware reset of chip before using it. */
+ struct cx88_core *core = dev->core;
+
+ cx_clear(MO_GP0_IO, 1);
+ mdelay(100);
+ cx_set(MO_GP0_IO, 9); /* ANT connector too FIXME */
+ mdelay(200);
+ dev->dvb.frontend = lgdt3302_attach(&fusionhdtv_3_gold_t,
+ &dev->core->i2c_adap);
+ }
+ break;
+#endif
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 0725b1288f4f..8403c4e95050 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -1,5 +1,5 @@
/*
- $Id: cx88-i2c.c,v 1.20 2005/02/15 15:59:35 kraxel Exp $
+ $Id: cx88-i2c.c,v 1.28 2005/07/05 17:37:35 nsh Exp $
cx88-i2c.c -- all the i2c code is here
@@ -91,15 +91,34 @@ static int cx8800_bit_getsda(void *data)
static int attach_inform(struct i2c_client *client)
{
+ struct tuner_setup tun_setup;
struct cx88_core *core = i2c_get_adapdata(client->adapter);
- dprintk(1, "i2c attach [addr=0x%x,client=%s]\n",
- client->addr, i2c_clientname(client));
+ dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->name,client->addr,i2c_clientname(client));
if (!client->driver->command)
return 0;
- if (core->tuner_type != UNSET)
- client->driver->command(client, TUNER_SET_TYPE, &core->tuner_type);
+ if (core->radio_type != UNSET) {
+ if ((core->radio_addr==ADDR_UNSET)||(core->radio_addr==client->addr)) {
+ tun_setup.mode_mask = T_RADIO;
+ tun_setup.type = core->radio_type;
+ tun_setup.addr = core->radio_addr;
+
+ client->driver->command (client, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ }
+ if (core->tuner_type != UNSET) {
+ if ((core->tuner_addr==ADDR_UNSET)||(core->tuner_addr==client->addr)) {
+
+ tun_setup.mode_mask = T_ANALOG_TV;
+ tun_setup.type = core->tuner_type;
+ tun_setup.addr = core->tuner_addr;
+
+ client->driver->command (client,TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ }
+
if (core->tda9887_conf)
client->driver->command(client, TDA9887_SET_CONFIG, &core->tda9887_conf);
return 0;
@@ -145,6 +164,7 @@ static struct i2c_client cx8800_i2c_client_template = {
};
static char *i2c_devs[128] = {
+ [ 0x1c >> 1 ] = "lgdt3302",
[ 0x86 >> 1 ] = "tda9887/cx22702",
[ 0xa0 >> 1 ] = "eeprom",
[ 0xc0 >> 1 ] = "tuner (analog)",
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index af6ad8cdbdb7..214887798192 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-input.c,v 1.9 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88-input.c,v 1.15 2005/07/07 13:58:38 mchehab Exp $
*
* Device driver for GPIO attached remote control interfaces
* on Conexant 2388x based TV/DVB cards.
@@ -38,119 +38,206 @@
/* DigitalNow DNTV Live DVB-T Remote */
static IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE] = {
- [ 0x00 ] = KEY_ESC, // 'go up a level?'
- [ 0x01 ] = KEY_KP1, // '1'
- [ 0x02 ] = KEY_KP2, // '2'
- [ 0x03 ] = KEY_KP3, // '3'
- [ 0x04 ] = KEY_KP4, // '4'
- [ 0x05 ] = KEY_KP5, // '5'
- [ 0x06 ] = KEY_KP6, // '6'
- [ 0x07 ] = KEY_KP7, // '7'
- [ 0x08 ] = KEY_KP8, // '8'
- [ 0x09 ] = KEY_KP9, // '9'
- [ 0x0a ] = KEY_KP0, // '0'
- [ 0x0b ] = KEY_TUNER, // 'tv/fm'
- [ 0x0c ] = KEY_SEARCH, // 'scan'
- [ 0x0d ] = KEY_STOP, // 'stop'
- [ 0x0e ] = KEY_PAUSE, // 'pause'
- [ 0x0f ] = KEY_LIST, // 'source'
-
- [ 0x10 ] = KEY_MUTE, // 'mute'
- [ 0x11 ] = KEY_REWIND, // 'backward <<'
- [ 0x12 ] = KEY_POWER, // 'power'
- [ 0x13 ] = KEY_S, // 'snap'
- [ 0x14 ] = KEY_AUDIO, // 'stereo'
- [ 0x15 ] = KEY_CLEAR, // 'reset'
- [ 0x16 ] = KEY_PLAY, // 'play'
- [ 0x17 ] = KEY_ENTER, // 'enter'
- [ 0x18 ] = KEY_ZOOM, // 'full screen'
- [ 0x19 ] = KEY_FASTFORWARD, // 'forward >>'
- [ 0x1a ] = KEY_CHANNELUP, // 'channel +'
- [ 0x1b ] = KEY_VOLUMEUP, // 'volume +'
- [ 0x1c ] = KEY_INFO, // 'preview'
- [ 0x1d ] = KEY_RECORD, // 'record'
- [ 0x1e ] = KEY_CHANNELDOWN, // 'channel -'
- [ 0x1f ] = KEY_VOLUMEDOWN, // 'volume -'
+ [0x00] = KEY_ESC, /* 'go up a level?' */
+ /* Keys 0 to 9 */
+ [0x0a] = KEY_KP0,
+ [0x01] = KEY_KP1,
+ [0x02] = KEY_KP2,
+ [0x03] = KEY_KP3,
+ [0x04] = KEY_KP4,
+ [0x05] = KEY_KP5,
+ [0x06] = KEY_KP6,
+ [0x07] = KEY_KP7,
+ [0x08] = KEY_KP8,
+ [0x09] = KEY_KP9,
+
+ [0x0b] = KEY_TUNER, /* tv/fm */
+ [0x0c] = KEY_SEARCH, /* scan */
+ [0x0d] = KEY_STOP,
+ [0x0e] = KEY_PAUSE,
+ [0x0f] = KEY_LIST, /* source */
+
+ [0x10] = KEY_MUTE,
+ [0x11] = KEY_REWIND, /* backward << */
+ [0x12] = KEY_POWER,
+ [0x13] = KEY_S, /* snap */
+ [0x14] = KEY_AUDIO, /* stereo */
+ [0x15] = KEY_CLEAR, /* reset */
+ [0x16] = KEY_PLAY,
+ [0x17] = KEY_ENTER,
+ [0x18] = KEY_ZOOM, /* full screen */
+ [0x19] = KEY_FASTFORWARD, /* forward >> */
+ [0x1a] = KEY_CHANNELUP,
+ [0x1b] = KEY_VOLUMEUP,
+ [0x1c] = KEY_INFO, /* preview */
+ [0x1d] = KEY_RECORD, /* record */
+ [0x1e] = KEY_CHANNELDOWN,
+ [0x1f] = KEY_VOLUMEDOWN,
};
/* ---------------------------------------------------------------------- */
/* IO-DATA BCTV7E Remote */
static IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE] = {
- [ 0x40 ] = KEY_TV, // TV
- [ 0x20 ] = KEY_RADIO, // FM
- [ 0x60 ] = KEY_EPG, // EPG
- [ 0x00 ] = KEY_POWER, // power
-
- [ 0x50 ] = KEY_KP1, // 1
- [ 0x30 ] = KEY_KP2, // 2
- [ 0x70 ] = KEY_KP3, // 3
- [ 0x10 ] = KEY_L, // Live
-
- [ 0x48 ] = KEY_KP4, // 4
- [ 0x28 ] = KEY_KP5, // 5
- [ 0x68 ] = KEY_KP6, // 6
- [ 0x08 ] = KEY_T, // Time Shift
-
- [ 0x58 ] = KEY_KP7, // 7
- [ 0x38 ] = KEY_KP8, // 8
- [ 0x78 ] = KEY_KP9, // 9
- [ 0x18 ] = KEY_PLAYPAUSE, // Play
-
- [ 0x44 ] = KEY_KP0, // 10
- [ 0x24 ] = KEY_ENTER, // 11
- [ 0x64 ] = KEY_ESC, // 12
- [ 0x04 ] = KEY_M, // Multi
-
- [ 0x54 ] = KEY_VIDEO, // VIDEO
- [ 0x34 ] = KEY_CHANNELUP, // channel +
- [ 0x74 ] = KEY_VOLUMEUP, // volume +
- [ 0x14 ] = KEY_MUTE, // Mute
-
- [ 0x4c ] = KEY_S, // SVIDEO
- [ 0x2c ] = KEY_CHANNELDOWN, // channel -
- [ 0x6c ] = KEY_VOLUMEDOWN, // volume -
- [ 0x0c ] = KEY_ZOOM, // Zoom
-
- [ 0x5c ] = KEY_PAUSE, // pause
- [ 0x3c ] = KEY_C, // || (red)
- [ 0x7c ] = KEY_RECORD, // recording
- [ 0x1c ] = KEY_STOP, // stop
-
- [ 0x41 ] = KEY_REWIND, // backward <<
- [ 0x21 ] = KEY_PLAY, // play
- [ 0x61 ] = KEY_FASTFORWARD, // forward >>
- [ 0x01 ] = KEY_NEXT, // skip >|
+ [0x40] = KEY_TV,
+ [0x20] = KEY_RADIO, /* FM */
+ [0x60] = KEY_EPG,
+ [0x00] = KEY_POWER,
+
+ /* Keys 0 to 9 */
+ [0x44] = KEY_KP0, /* 10 */
+ [0x50] = KEY_KP1,
+ [0x30] = KEY_KP2,
+ [0x70] = KEY_KP3,
+ [0x48] = KEY_KP4,
+ [0x28] = KEY_KP5,
+ [0x68] = KEY_KP6,
+ [0x58] = KEY_KP7,
+ [0x38] = KEY_KP8,
+ [0x78] = KEY_KP9,
+
+ [0x10] = KEY_L, /* Live */
+ [0x08] = KEY_T, /* Time Shift */
+
+ [0x18] = KEY_PLAYPAUSE, /* Play */
+
+ [0x24] = KEY_ENTER, /* 11 */
+ [0x64] = KEY_ESC, /* 12 */
+ [0x04] = KEY_M, /* Multi */
+
+ [0x54] = KEY_VIDEO,
+ [0x34] = KEY_CHANNELUP,
+ [0x74] = KEY_VOLUMEUP,
+ [0x14] = KEY_MUTE,
+
+ [0x4c] = KEY_S, /* SVIDEO */
+ [0x2c] = KEY_CHANNELDOWN,
+ [0x6c] = KEY_VOLUMEDOWN,
+ [0x0c] = KEY_ZOOM,
+
+ [0x5c] = KEY_PAUSE,
+ [0x3c] = KEY_C, /* || (red) */
+ [0x7c] = KEY_RECORD, /* recording */
+ [0x1c] = KEY_STOP,
+
+ [0x41] = KEY_REWIND, /* backward << */
+ [0x21] = KEY_PLAY,
+ [0x61] = KEY_FASTFORWARD, /* forward >> */
+ [0x01] = KEY_NEXT, /* skip >| */
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* ADS Tech Instant TV DVB-T PCI Remote */
+static IR_KEYTAB_TYPE ir_codes_adstech_dvb_t_pci[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [0x4d] = KEY_0,
+ [0x57] = KEY_1,
+ [0x4f] = KEY_2,
+ [0x53] = KEY_3,
+ [0x56] = KEY_4,
+ [0x4e] = KEY_5,
+ [0x5e] = KEY_6,
+ [0x54] = KEY_7,
+ [0x4c] = KEY_8,
+ [0x5c] = KEY_9,
+
+ [0x5b] = KEY_POWER,
+ [0x5f] = KEY_MUTE,
+ [0x55] = KEY_GOTO,
+ [0x5d] = KEY_SEARCH,
+ [0x17] = KEY_EPG, /* Guide */
+ [0x1f] = KEY_MENU,
+ [0x0f] = KEY_UP,
+ [0x46] = KEY_DOWN,
+ [0x16] = KEY_LEFT,
+ [0x1e] = KEY_RIGHT,
+ [0x0e] = KEY_SELECT, /* Enter */
+ [0x5a] = KEY_INFO,
+ [0x52] = KEY_EXIT,
+ [0x59] = KEY_PREVIOUS,
+ [0x51] = KEY_NEXT,
+ [0x58] = KEY_REWIND,
+ [0x50] = KEY_FORWARD,
+ [0x44] = KEY_PLAYPAUSE,
+ [0x07] = KEY_STOP,
+ [0x1b] = KEY_RECORD,
+ [0x13] = KEY_TUNER, /* Live */
+ [0x0a] = KEY_A,
+ [0x12] = KEY_B,
+ [0x03] = KEY_PROG1, /* 1 */
+ [0x01] = KEY_PROG2, /* 2 */
+ [0x00] = KEY_PROG3, /* 3 */
+ [0x06] = KEY_DVD,
+ [0x48] = KEY_AUX, /* Photo */
+ [0x40] = KEY_VIDEO,
+ [0x19] = KEY_AUDIO, /* Music */
+ [0x0b] = KEY_CHANNELUP,
+ [0x08] = KEY_CHANNELDOWN,
+ [0x15] = KEY_VOLUMEUP,
+ [0x1c] = KEY_VOLUMEDOWN,
+};
+
+/* ---------------------------------------------------------------------- */
+
+/* MSI TV@nywhere remote */
+static IR_KEYTAB_TYPE ir_codes_msi_tvanywhere[IR_KEYTAB_SIZE] = {
+ /* Keys 0 to 9 */
+ [0x00] = KEY_0,
+ [0x01] = KEY_1,
+ [0x02] = KEY_2,
+ [0x03] = KEY_3,
+ [0x04] = KEY_4,
+ [0x05] = KEY_5,
+ [0x06] = KEY_6,
+ [0x07] = KEY_7,
+ [0x08] = KEY_8,
+ [0x09] = KEY_9,
+
+ [0x0c] = KEY_MUTE,
+ [0x0f] = KEY_SCREEN, /* Full Screen */
+ [0x10] = KEY_F, /* Funtion */
+ [0x11] = KEY_T, /* Time shift */
+ [0x12] = KEY_POWER,
+ [0x13] = KEY_MEDIA, /* MTS */
+ [0x14] = KEY_SLOW,
+ [0x16] = KEY_REWIND, /* backward << */
+ [0x17] = KEY_ENTER, /* Return */
+ [0x18] = KEY_FASTFORWARD, /* forward >> */
+ [0x1a] = KEY_CHANNELUP,
+ [0x1b] = KEY_VOLUMEUP,
+ [0x1e] = KEY_CHANNELDOWN,
+ [0x1f] = KEY_VOLUMEDOWN,
};
/* ---------------------------------------------------------------------- */
struct cx88_IR {
- struct cx88_core *core;
- struct input_dev input;
- struct ir_input_state ir;
- char name[32];
- char phys[32];
+ struct cx88_core *core;
+ struct input_dev input;
+ struct ir_input_state ir;
+ char name[32];
+ char phys[32];
/* sample from gpio pin 16 */
- int sampling;
- u32 samples[16];
- int scount;
- unsigned long release;
+ int sampling;
+ u32 samples[16];
+ int scount;
+ unsigned long release;
/* poll external decoder */
- int polling;
- struct work_struct work;
- struct timer_list timer;
- u32 gpio_addr;
- u32 last_gpio;
- u32 mask_keycode;
- u32 mask_keydown;
- u32 mask_keyup;
+ int polling;
+ struct work_struct work;
+ struct timer_list timer;
+ u32 gpio_addr;
+ u32 last_gpio;
+ u32 mask_keycode;
+ u32 mask_keydown;
+ u32 mask_keyup;
};
static int ir_debug = 0;
-module_param(ir_debug, int, 0644); /* debug level [IR] */
+module_param(ir_debug, int, 0644); /* debug level [IR] */
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define ir_dprintk(fmt, arg...) if (ir_debug) \
@@ -174,37 +261,37 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
/* extract data */
data = ir_extract_bits(gpio, ir->mask_keycode);
ir_dprintk("irq gpio=0x%x code=%d | %s%s%s\n",
- gpio, data,
- ir->polling ? "poll" : "irq",
- (gpio & ir->mask_keydown) ? " down" : "",
- (gpio & ir->mask_keyup) ? " up" : "");
+ gpio, data,
+ ir->polling ? "poll" : "irq",
+ (gpio & ir->mask_keydown) ? " down" : "",
+ (gpio & ir->mask_keyup) ? " up" : "");
if (ir->mask_keydown) {
/* bit set on keydown */
if (gpio & ir->mask_keydown) {
- ir_input_keydown(&ir->input,&ir->ir,data,data);
+ ir_input_keydown(&ir->input, &ir->ir, data, data);
} else {
- ir_input_nokey(&ir->input,&ir->ir);
+ ir_input_nokey(&ir->input, &ir->ir);
}
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
if (0 == (gpio & ir->mask_keyup)) {
- ir_input_keydown(&ir->input,&ir->ir,data,data);
+ ir_input_keydown(&ir->input, &ir->ir, data, data);
} else {
- ir_input_nokey(&ir->input,&ir->ir);
+ ir_input_nokey(&ir->input, &ir->ir);
}
} else {
/* can't distinguish keydown/up :-/ */
- ir_input_keydown(&ir->input,&ir->ir,data,data);
- ir_input_nokey(&ir->input,&ir->ir);
+ ir_input_keydown(&ir->input, &ir->ir, data, data);
+ ir_input_nokey(&ir->input, &ir->ir);
}
}
static void ir_timer(unsigned long data)
{
- struct cx88_IR *ir = (struct cx88_IR*)data;
+ struct cx88_IR *ir = (struct cx88_IR *)data;
schedule_work(&ir->work);
}
@@ -227,41 +314,64 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
IR_KEYTAB_TYPE *ir_codes = NULL;
int ir_type = IR_TYPE_OTHER;
- ir = kmalloc(sizeof(*ir),GFP_KERNEL);
+ ir = kmalloc(sizeof(*ir), GFP_KERNEL);
if (NULL == ir)
return -ENOMEM;
- memset(ir,0,sizeof(*ir));
+ memset(ir, 0, sizeof(*ir));
/* detect & configure */
switch (core->board) {
case CX88_BOARD_DNTV_LIVE_DVB_T:
- ir_codes = ir_codes_dntv_live_dvb_t;
- ir->gpio_addr = MO_GP1_IO;
+ case CX88_BOARD_KWORLD_DVB_T:
+ ir_codes = ir_codes_dntv_live_dvb_t;
+ ir->gpio_addr = MO_GP1_IO;
ir->mask_keycode = 0x1f;
- ir->mask_keyup = 0x60;
- ir->polling = 50; // ms
+ ir->mask_keyup = 0x60;
+ ir->polling = 50; /* ms */
break;
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
- ir_codes = ir_codes_hauppauge_new;
- ir_type = IR_TYPE_RC5;
- ir->sampling = 1;
+ ir_codes = ir_codes_hauppauge_new;
+ ir_type = IR_TYPE_RC5;
+ ir->sampling = 1;
break;
case CX88_BOARD_WINFAST2000XP_EXPERT:
- ir_codes = ir_codes_winfast;
- ir->gpio_addr = MO_GP0_IO;
+ ir_codes = ir_codes_winfast;
+ ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0x8f8;
- ir->mask_keyup = 0x100;
- ir->polling = 1; // ms
+ ir->mask_keyup = 0x100;
+ ir->polling = 1; /* ms */
break;
case CX88_BOARD_IODATA_GVBCTV7E:
- ir_codes = ir_codes_iodata_bctv7e;
- ir->gpio_addr = MO_GP0_IO;
+ ir_codes = ir_codes_iodata_bctv7e;
+ ir->gpio_addr = MO_GP0_IO;
ir->mask_keycode = 0xfd;
ir->mask_keydown = 0x02;
- ir->polling = 5; // ms
+ ir->polling = 5; /* ms */
+ break;
+ case CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO:
+ ir_codes = ir_codes_pixelview;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x1f;
+ ir->mask_keyup = 0x80;
+ ir->polling = 1; /* ms */
+ break;
+ case CX88_BOARD_ADSTECH_DVB_T_PCI:
+ ir_codes = ir_codes_adstech_dvb_t_pci;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0xbf;
+ ir->mask_keyup = 0x40;
+ ir->polling = 50; /* ms */
+ break;
+ case CX88_BOARD_MSI_TVANYWHERE_MASTER:
+ ir_codes = ir_codes_msi_tvanywhere;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x1f;
+ ir->mask_keyup = 0x40;
+ ir->polling = 1; /* ms */
break;
}
+
if (NULL == ir_codes) {
kfree(ir);
return -ENODEV;
@@ -270,8 +380,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
/* init input device */
snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)",
cx88_boards[core->board].name);
- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
- pci_name(pci));
+ snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
ir_input_init(&ir->input, &ir->ir, ir_type, ir_codes);
ir->input.name = ir->name;
@@ -279,10 +388,10 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->input.id.bustype = BUS_PCI;
ir->input.id.version = 1;
if (pci->subsystem_vendor) {
- ir->input.id.vendor = pci->subsystem_vendor;
+ ir->input.id.vendor = pci->subsystem_vendor;
ir->input.id.product = pci->subsystem_device;
} else {
- ir->input.id.vendor = pci->vendor;
+ ir->input.id.vendor = pci->vendor;
ir->input.id.product = pci->device;
}
@@ -294,13 +403,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
INIT_WORK(&ir->work, cx88_ir_work, ir);
init_timer(&ir->timer);
ir->timer.function = ir_timer;
- ir->timer.data = (unsigned long)ir;
+ ir->timer.data = (unsigned long)ir;
schedule_work(&ir->work);
}
if (ir->sampling) {
- core->pci_irqmask |= (1<<18); // IR_SMP_INT
- cx_write(MO_DDS_IO, 0xa80a80); // 4 kHz sample rate
- cx_write(MO_DDSCFG_IO, 0x5); // enable
+ core->pci_irqmask |= (1 << 18); /* IR_SMP_INT */
+ cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
+ cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
/* all done */
@@ -336,7 +445,7 @@ int cx88_ir_fini(struct cx88_core *core)
void cx88_ir_irq(struct cx88_core *core)
{
struct cx88_IR *ir = core->ir;
- u32 samples,rc5;
+ u32 samples, rc5;
int i;
if (NULL == ir)
@@ -345,7 +454,7 @@ void cx88_ir_irq(struct cx88_core *core)
return;
samples = cx_read(MO_SAMPLE_IO);
- if (0 != samples && 0xffffffff != samples) {
+ if (0 != samples && 0xffffffff != samples) {
/* record sample data */
if (ir->scount < ARRAY_SIZE(ir->samples))
ir->samples[ir->scount++] = samples;
@@ -353,8 +462,8 @@ void cx88_ir_irq(struct cx88_core *core)
}
if (!ir->scount) {
/* nothing to sample */
- if (ir->ir.keypressed && time_after(jiffies,ir->release))
- ir_input_nokey(&ir->input,&ir->ir);
+ if (ir->ir.keypressed && time_after(jiffies, ir->release))
+ ir_input_nokey(&ir->input, &ir->ir);
return;
}
@@ -364,14 +473,14 @@ void cx88_ir_irq(struct cx88_core *core)
for (i = 0; i < ir->scount; i++)
ir->samples[i] = ~ir->samples[i];
if (ir_debug)
- ir_dump_samples(ir->samples,ir->scount);
+ ir_dump_samples(ir->samples, ir->scount);
/* decode it */
switch (core->board) {
case CX88_BOARD_HAUPPAUGE:
case CX88_BOARD_HAUPPAUGE_DVB_T1:
- rc5 = ir_decode_biphase(ir->samples,ir->scount,5,7);
- ir_dprintk("biphase decoded: %x\n",rc5);
+ rc5 = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
+ ir_dprintk("biphase decoded: %x\n", rc5);
if ((rc5 & 0xfffff000) != 0x3000)
break;
ir_input_keydown(&ir->input, &ir->ir, rc5 & 0x3f, rc5);
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 07aae1899e17..fe2767c0ff94 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-mpeg.c,v 1.25 2005/03/07 14:18:00 kraxel Exp $
+ * $Id: cx88-mpeg.c,v 1.31 2005/07/07 14:17:47 mchehab Exp $
*
* Support for the mpeg transport stream transfers
* PCI function #2 of the cx2388x.
@@ -55,7 +55,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
{
struct cx88_core *core = dev->core;
- dprintk(1, "cx8802_start_mpegport_dma %d\n", buf->vb.width);
+ dprintk(0, "cx8802_start_dma %d\n", buf->vb.width);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
@@ -64,17 +64,21 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
/* write TS length to chip */
cx_write(MO_TS_LNGTH, buf->vb.width);
-#if 1
/* FIXME: this needs a review.
* also: move to cx88-blackbird + cx88-dvb source files? */
if (cx88_boards[core->board].dvb) {
/* negedge driven & software reset */
- cx_write(TS_GEN_CNTRL, 0x40);
+ cx_write(TS_GEN_CNTRL, 0x0040 | dev->ts_gen_cntrl);
udelay(100);
cx_write(MO_PINMUX_IO, 0x00);
- cx_write(TS_HW_SOP_CNTRL,47<<16|188<<4|0x00);
- cx_write(TS_SOP_STAT,0x00);
+ cx_write(TS_HW_SOP_CNTRL,0x47<<16|188<<4|0x01);
+ if ((core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q) ||
+ (core->board == CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T)) {
+ cx_write(TS_SOP_STAT, 1<<13);
+ } else {
+ cx_write(TS_SOP_STAT, 0x00);
+ }
cx_write(TS_GEN_CNTRL, dev->ts_gen_cntrl);
udelay(100);
}
@@ -93,25 +97,27 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
udelay(100);
}
-#endif
/* reset counter */
cx_write(MO_TS_GPCNTRL, GP_COUNT_CONTROL_RESET);
q->count = 1;
/* enable irqs */
+ dprintk( 0, "setting the interrupt mask\n" );
cx_set(MO_PCI_INTMSK, core->pci_irqmask | 0x04);
- cx_write(MO_TS_INTMSK, 0x1f0011);
+ cx_set(MO_TS_INTMSK, 0x1f0011);
+ //cx_write(MO_TS_INTMSK, 0x0f0011);
/* start dma */
- cx_write(MO_DEV_CNTRL2, (1<<5)); /* FIXME: s/write/set/ ??? */
- cx_write(MO_TS_DMACNTRL, 0x11);
+ cx_set(MO_DEV_CNTRL2, (1<<5));
+ cx_set(MO_TS_DMACNTRL, 0x11);
return 0;
}
static int cx8802_stop_dma(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
+ dprintk( 0, "cx8802_stop_dma\n" );
/* stop dma */
cx_clear(MO_TS_DMACNTRL, 0x11);
@@ -131,8 +137,12 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
struct cx88_buffer *buf;
struct list_head *item;
+ dprintk( 0, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
+ {
+ dprintk( 0, "cx8802_restart_queue: queue is empty\n" );
return 0;
+ }
buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
@@ -182,27 +192,32 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
struct cx88_buffer *prev;
struct cx88_dmaqueue *q = &dev->mpegq;
+ dprintk( 1, "cx8802_buf_queue\n" );
/* add jump to stopper */
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
if (list_empty(&q->active)) {
+ dprintk( 0, "queue is empty - first active\n" );
list_add_tail(&buf->vb.queue,&q->active);
cx8802_start_dma(dev, q, buf);
buf->vb.state = STATE_ACTIVE;
buf->count = q->count++;
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2,"[%p/%d] %s - first active\n",
+ dprintk(0,"[%p/%d] %s - first active\n",
buf, buf->vb.i, __FUNCTION__);
+ //udelay(100);
} else {
+ dprintk( 1, "queue is not empty - append to active\n" );
prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
list_add_tail(&buf->vb.queue,&q->active);
buf->vb.state = STATE_ACTIVE;
buf->count = q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(2,"[%p/%d] %s - append to active\n",
+ dprintk( 1, "[%p/%d] %s - append to active\n",
buf, buf->vb.i, __FUNCTION__);
+ //udelay(100);
}
}
@@ -224,7 +239,10 @@ static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
}
if (restart)
+ {
+ dprintk(0, "restarting queue\n" );
cx8802_restart_queue(dev,q);
+ }
spin_unlock_irqrestore(&dev->slock,flags);
}
@@ -232,6 +250,7 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev)
{
struct cx88_dmaqueue *q = &dev->mpegq;
+ dprintk( 1, "cx8802_cancel_buffers" );
del_timer_sync(&q->timeout);
cx8802_stop_dma(dev);
do_cancel_buffers(dev,"cancel",0);
@@ -241,7 +260,7 @@ static void cx8802_timeout(unsigned long data)
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(1, "%s\n",__FUNCTION__);
+ dprintk(0, "%s\n",__FUNCTION__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -249,17 +268,28 @@ static void cx8802_timeout(unsigned long data)
do_cancel_buffers(dev,"timeout",1);
}
+static char *cx88_mpeg_irqs[32] = {
+ "ts_risci1", NULL, NULL, NULL,
+ "ts_risci2", NULL, NULL, NULL,
+ "ts_oflow", NULL, NULL, NULL,
+ "ts_sync", NULL, NULL, NULL,
+ "opc_err", "par_err", "rip_err", "pci_abort",
+ "ts_err?",
+};
+
static void cx8802_mpeg_irq(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
u32 status, mask, count;
+ dprintk( 1, "cx8802_mpeg_irq\n" );
status = cx_read(MO_TS_INTSTAT);
mask = cx_read(MO_TS_INTMSK);
if (0 == (status & mask))
return;
cx_write(MO_TS_INTSTAT, status);
+
if (debug || (status & mask & ~0xff))
cx88_print_irqbits(core->name, "irq mpeg ",
cx88_mpeg_irqs, status, mask);
@@ -273,6 +303,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
/* risc1 y */
if (status & 0x01) {
+ dprintk( 1, "wake up\n" );
spin_lock(&dev->slock);
count = cx_read(MO_TS_GPCNT);
cx88_wakeup(dev->core, &dev->mpegq, count);
@@ -288,6 +319,7 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
/* other general errors */
if (status & 0x1f0100) {
+ dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
spin_lock(&dev->slock);
cx8802_stop_dma(dev);
cx8802_restart_queue(dev,&dev->mpegq);
@@ -295,6 +327,8 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
}
}
+#define MAX_IRQ_LOOP 10
+
static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
{
struct cx8802_dev *dev = dev_id;
@@ -302,10 +336,13 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
u32 status;
int loop, handled = 0;
- for (loop = 0; loop < 10; loop++) {
+ for (loop = 0; loop < MAX_IRQ_LOOP; loop++) {
status = cx_read(MO_PCI_INTSTAT) & (core->pci_irqmask | 0x04);
if (0 == status)
goto out;
+ dprintk( 1, "cx8802_irq\n" );
+ dprintk( 1, " loop: %d/%d\n", loop, MAX_IRQ_LOOP );
+ dprintk( 1, " status: %d\n", status );
handled = 1;
cx_write(MO_PCI_INTSTAT, status);
@@ -314,7 +351,8 @@ static irqreturn_t cx8802_irq(int irq, void *dev_id, struct pt_regs *regs)
if (status & 0x04)
cx8802_mpeg_irq(dev);
};
- if (10 == loop) {
+ if (MAX_IRQ_LOOP == loop) {
+ dprintk( 0, "clearing mask\n" );
printk(KERN_WARNING "%s/0: irq loop -- clearing mask\n",
core->name);
cx_write(MO_PCI_INTMSK,0);
@@ -378,6 +416,7 @@ int cx8802_init_common(struct cx8802_dev *dev)
void cx8802_fini_common(struct cx8802_dev *dev)
{
+ dprintk( 2, "cx8802_fini_common\n" );
cx8802_stop_dma(dev);
pci_disable_device(dev->pci);
@@ -399,16 +438,15 @@ int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
/* stop mpeg dma */
spin_lock(&dev->slock);
if (!list_empty(&dev->mpegq.active)) {
+ dprintk( 2, "suspend\n" );
printk("%s: suspend mpeg\n", core->name);
cx8802_stop_dma(dev);
del_timer(&dev->mpegq.timeout);
}
spin_unlock(&dev->slock);
-#if 1
/* FIXME -- shutdown device */
cx88_shutdown(dev->core);
-#endif
pci_save_state(pci_dev);
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
@@ -430,10 +468,8 @@ int cx8802_resume_common(struct pci_dev *pci_dev)
pci_set_power_state(pci_dev, PCI_D0);
pci_restore_state(pci_dev);
-#if 1
/* FIXME: re-initialize hardware */
cx88_reset(dev->core);
-#endif
/* restart video+vbi capture */
spin_lock(&dev->slock);
@@ -463,4 +499,5 @@ EXPORT_SYMBOL(cx8802_resume_common);
* Local variables:
* c-basic-offset: 8
* End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
*/
diff --git a/drivers/media/video/cx88/cx88-reg.h b/drivers/media/video/cx88/cx88-reg.h
index 8638ce57d84c..37f82662d265 100644
--- a/drivers/media/video/cx88/cx88-reg.h
+++ b/drivers/media/video/cx88/cx88-reg.h
@@ -1,5 +1,5 @@
/*
- $Id: cx88-reg.h,v 1.6 2004/10/13 10:39:00 kraxel Exp $
+ $Id: cx88-reg.h,v 1.8 2005/07/07 13:58:38 mchehab Exp $
cx88x-hw.h - CX2388x register offsets
@@ -397,6 +397,7 @@
#define AUD_RATE_ADJ4 0x3205e4
#define AUD_RATE_ADJ5 0x3205e8
#define AUD_APB_IN_RATE_ADJ 0x3205ec
+#define AUD_I2SCNTL 0x3205ec
#define AUD_PHASE_FIX_CTL 0x3205f0
#define AUD_PLL_PRESCALE 0x320600
#define AUD_PLL_DDS 0x320604
@@ -603,20 +604,11 @@
#define EN_I2SIN_STR2DAC 0x00004000
#define EN_I2SIN_ENABLE 0x00008000
-#if 0
-/* old */
-#define EN_DMTRX_SUMDIFF 0x00000800
-#define EN_DMTRX_SUMR 0x00000880
-#define EN_DMTRX_LR 0x00000900
-#define EN_DMTRX_MONO 0x00000980
-#else
-/* dscaler cvs */
#define EN_DMTRX_SUMDIFF (0 << 7)
#define EN_DMTRX_SUMR (1 << 7)
#define EN_DMTRX_LR (2 << 7)
#define EN_DMTRX_MONO (3 << 7)
#define EN_DMTRX_BYPASS (1 << 11)
-#endif
// Video
#define VID_CAPTURE_CONTROL 0x310180
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index f2a9475a2fee..91207f10bae7 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -1,5 +1,5 @@
/*
- $Id: cx88-tvaudio.c,v 1.34 2005/03/07 16:10:51 kraxel Exp $
+ $Id: cx88-tvaudio.c,v 1.37 2005/07/07 13:58:38 mchehab Exp $
cx88x-audio.c - Conexant CX23880/23881 audio downstream driver driver
@@ -127,7 +127,8 @@ static void set_audio_start(struct cx88_core *core,
cx_write(AUD_VOL_CTL, (1 << 6));
// increase level of input by 12dB
- cx_write(AUD_AFE_12DB_EN, 0x0001);
+// cx_write(AUD_AFE_12DB_EN, 0x0001);
+ cx_write(AUD_AFE_12DB_EN, 0x0000);
// start programming
cx_write(AUD_CTL, 0x0000);
@@ -143,9 +144,15 @@ static void set_audio_finish(struct cx88_core *core)
u32 volume;
if (cx88_boards[core->board].blackbird) {
+ // sets sound input from external adc
+ cx_set(AUD_CTL, EN_I2SIN_ENABLE);
+ //cx_write(AUD_I2SINPUTCNTL, 0);
+ cx_write(AUD_I2SINPUTCNTL, 4);
+ cx_write(AUD_BAUDRATE, 1);
// 'pass-thru mode': this enables the i2s output to the mpeg encoder
- cx_set(AUD_CTL, 0x2000);
+ cx_set(AUD_CTL, EN_I2SOUT_ENABLE);
cx_write(AUD_I2SOUTPUTCNTL, 1);
+ cx_write(AUD_I2SCNTL, 0);
//cx_write(AUD_APB_IN_RATE_ADJ, 0);
}
@@ -271,80 +278,6 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap)
set_audio_finish(core);
}
-#if 0
-static void set_audio_standard_NICAM(struct cx88_core *core)
-{
- static const struct rlist nicam_common[] = {
- /* from dscaler */
- { AUD_RATE_ADJ1, 0x00000010 },
- { AUD_RATE_ADJ2, 0x00000040 },
- { AUD_RATE_ADJ3, 0x00000100 },
- { AUD_RATE_ADJ4, 0x00000400 },
- { AUD_RATE_ADJ5, 0x00001000 },
- // { AUD_DMD_RA_DDS, 0x00c0d5ce },
-
- // Deemphasis 1:
- { AUD_DEEMPHGAIN_R, 0x000023c2 },
- { AUD_DEEMPHNUMER1_R, 0x0002a7bc },
- { AUD_DEEMPHNUMER2_R, 0x0003023e },
- { AUD_DEEMPHDENOM1_R, 0x0000f3d0 },
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
-
-#if 0
- // Deemphasis 2: (other tv norm?)
- { AUD_DEEMPHGAIN_R, 0x0000c600 },
- { AUD_DEEMPHNUMER1_R, 0x00066738 },
- { AUD_DEEMPHNUMER2_R, 0x00066739 },
- { AUD_DEEMPHDENOM1_R, 0x0001e88c },
- { AUD_DEEMPHDENOM2_R, 0x0001e88c },
-#endif
-
- { AUD_DEEMPHDENOM2_R, 0x00000000 },
- { AUD_ERRLOGPERIOD_R, 0x00000fff },
- { AUD_ERRINTRPTTHSHLD1_R, 0x000003ff },
- { AUD_ERRINTRPTTHSHLD2_R, 0x000000ff },
- { AUD_ERRINTRPTTHSHLD3_R, 0x0000003f },
- { AUD_POLYPH80SCALEFAC, 0x00000003 },
-
- // setup QAM registers
- { AUD_PDF_DDS_CNST_BYTE2, 0x06 },
- { AUD_PDF_DDS_CNST_BYTE1, 0x82 },
- { AUD_PDF_DDS_CNST_BYTE0, 0x16 },
- { AUD_QAM_MODE, 0x05 },
-
- { /* end of list */ },
- };
- static const struct rlist nicam_pal_i[] = {
- { AUD_PDF_DDS_CNST_BYTE0, 0x12 },
- { AUD_PHACC_FREQ_8MSB, 0x3a },
- { AUD_PHACC_FREQ_8LSB, 0x93 },
-
- { /* end of list */ },
- };
- static const struct rlist nicam_default[] = {
- { AUD_PDF_DDS_CNST_BYTE0, 0x16 },
- { AUD_PHACC_FREQ_8MSB, 0x34 },
- { AUD_PHACC_FREQ_8LSB, 0x4c },
-
- { /* end of list */ },
- };
-
- set_audio_start(core, 0x0010,
- EN_DMTRX_LR | EN_DMTRX_BYPASS | EN_NICAM_AUTO_STEREO);
- set_audio_registers(core, nicam_common);
- switch (core->tvaudio) {
- case WW_NICAM_I:
- dprintk("%s PAL-I NICAM (status: unknown)\n",__FUNCTION__);
- set_audio_registers(core, nicam_pal_i);
- break;
- case WW_NICAM_BGDKL:
- dprintk("%s PAL-BGDK NICAM (status: unknown)\n",__FUNCTION__);
- set_audio_registers(core, nicam_default);
- break;
- };
- set_audio_finish(core);
-}
-#endif
static void set_audio_standard_NICAM_L(struct cx88_core *core, int stereo)
{
@@ -707,50 +640,65 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
set_audio_finish(core);
}
-static void set_audio_standard_FM(struct cx88_core *core)
+static void set_audio_standard_FM(struct cx88_core *core, enum cx88_deemph_type deemph)
{
-#if 0 /* FIXME */
- switch (dev->audio_properties.FM_deemphasis)
- {
- case WW_FM_DEEMPH_50:
- //Set De-emphasis filter coefficients for 50 usec
- cx_write(AUD_DEEMPH0_G0, 0x0C45);
- cx_write(AUD_DEEMPH0_A0, 0x6262);
- cx_write(AUD_DEEMPH0_B0, 0x1C29);
- cx_write(AUD_DEEMPH0_A1, 0x3FC66);
- cx_write(AUD_DEEMPH0_B1, 0x399A);
-
- cx_write(AUD_DEEMPH1_G0, 0x0D80);
- cx_write(AUD_DEEMPH1_A0, 0x6262);
- cx_write(AUD_DEEMPH1_B0, 0x1C29);
- cx_write(AUD_DEEMPH1_A1, 0x3FC66);
- cx_write(AUD_DEEMPH1_B1, 0x399A);
+ static const struct rlist fm_deemph_50[] = {
+ { AUD_DEEMPH0_G0, 0x0C45 },
+ { AUD_DEEMPH0_A0, 0x6262 },
+ { AUD_DEEMPH0_B0, 0x1C29 },
+ { AUD_DEEMPH0_A1, 0x3FC66},
+ { AUD_DEEMPH0_B1, 0x399A },
+
+ { AUD_DEEMPH1_G0, 0x0D80 },
+ { AUD_DEEMPH1_A0, 0x6262 },
+ { AUD_DEEMPH1_B0, 0x1C29 },
+ { AUD_DEEMPH1_A1, 0x3FC66},
+ { AUD_DEEMPH1_B1, 0x399A},
+
+ { AUD_POLYPH80SCALEFAC, 0x0003},
+ { /* end of list */ },
+ };
+ static const struct rlist fm_deemph_75[] = {
+ { AUD_DEEMPH0_G0, 0x091B },
+ { AUD_DEEMPH0_A0, 0x6B68 },
+ { AUD_DEEMPH0_B0, 0x11EC },
+ { AUD_DEEMPH0_A1, 0x3FC66},
+ { AUD_DEEMPH0_B1, 0x399A },
+
+ { AUD_DEEMPH1_G0, 0x0AA0 },
+ { AUD_DEEMPH1_A0, 0x6B68 },
+ { AUD_DEEMPH1_B0, 0x11EC },
+ { AUD_DEEMPH1_A1, 0x3FC66},
+ { AUD_DEEMPH1_B1, 0x399A},
+
+ { AUD_POLYPH80SCALEFAC, 0x0003},
+ { /* end of list */ },
+ };
- break;
+ /* It is enough to leave default values? */
+ static const struct rlist fm_no_deemph[] = {
- case WW_FM_DEEMPH_75:
- //Set De-emphasis filter coefficients for 75 usec
- cx_write(AUD_DEEMPH0_G0, 0x91B );
- cx_write(AUD_DEEMPH0_A0, 0x6B68);
- cx_write(AUD_DEEMPH0_B0, 0x11EC);
- cx_write(AUD_DEEMPH0_A1, 0x3FC66);
- cx_write(AUD_DEEMPH0_B1, 0x399A);
+ { AUD_POLYPH80SCALEFAC, 0x0003},
+ { /* end of list */ },
+ };
- cx_write(AUD_DEEMPH1_G0, 0xAA0 );
- cx_write(AUD_DEEMPH1_A0, 0x6B68);
- cx_write(AUD_DEEMPH1_B0, 0x11EC);
- cx_write(AUD_DEEMPH1_A1, 0x3FC66);
- cx_write(AUD_DEEMPH1_B1, 0x399A);
+ dprintk("%s (status: unknown)\n",__FUNCTION__);
+ set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
+ switch (deemph)
+ {
+ case FM_NO_DEEMPH:
+ set_audio_registers(core, fm_no_deemph);
break;
- }
-#endif
- dprintk("%s (status: unknown)\n",__FUNCTION__);
- set_audio_start(core, 0x0020, EN_FMRADIO_AUTO_STEREO);
+ case FM_DEEMPH_50:
+ set_audio_registers(core, fm_deemph_50);
+ break;
- // AB: 10/2/01: this register is not being reset appropriately on occasion.
- cx_write(AUD_POLYPH80SCALEFAC,3);
+ case FM_DEEMPH_75:
+ set_audio_registers(core, fm_deemph_75);
+ break;
+ }
set_audio_finish(core);
}
@@ -778,7 +726,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
set_audio_standard_EIAJ(core);
break;
case WW_FM:
- set_audio_standard_FM(core);
+ set_audio_standard_FM(core,FM_NO_DEEMPH);
break;
case WW_SYSTEM_L_AM:
set_audio_standard_NICAM_L(core, 1);
@@ -1029,4 +977,5 @@ EXPORT_SYMBOL(cx88_audio_thread);
* Local variables:
* c-basic-offset: 8
* End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
*/
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index 0584ff476387..320d57888bbd 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-vbi.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: cx88-vbi.c,v 1.17 2005/06/12 04:19:19 mchehab Exp $
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -47,8 +47,8 @@ void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f)
}
static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
- struct cx88_dmaqueue *q,
- struct cx88_buffer *buf)
+ struct cx88_dmaqueue *q,
+ struct cx88_buffer *buf)
{
struct cx88_core *core = dev->core;
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index d1f5c92f0ce5..c44a079d08c0 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -1,5 +1,5 @@
/*
- * $Id: cx88-video.c,v 1.58 2005/03/07 15:58:05 kraxel Exp $
+ * $Id: cx88-video.c,v 1.79 2005/07/07 14:17:47 mchehab Exp $
*
* device driver for Conexant 2388x based TV cards
* video4linux video interface
@@ -86,13 +86,6 @@ static struct cx88_tvnorm tvnorms[] = {
.id = V4L2_STD_NTSC_M_JP,
.cxiformat = VideoFormatNTSCJapan,
.cxoformat = 0x181f0008,
-#if 0
- },{
- .name = "NTSC-4.43",
- .id = FIXME,
- .cxiformat = VideoFormatNTSC443,
- .cxoformat = 0x181f0008,
-#endif
},{
.name = "PAL-BG",
.id = V4L2_STD_PAL_BG,
@@ -248,6 +241,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
},
+ .off = 0,
.reg = MO_CONTR_BRIGHT,
.mask = 0xff00,
.shift = 8,
@@ -261,7 +255,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
},
- .off = 0,
+ .off = 128,
.reg = MO_HUE,
.mask = 0x00ff,
.shift = 0,
@@ -674,231 +668,6 @@ static struct videobuf_queue_ops cx8800_video_qops = {
/* ------------------------------------------------------------------ */
-#if 0 /* overlay support not finished yet */
-static u32* ov_risc_field(struct cx8800_dev *dev, struct cx8800_fh *fh,
- u32 *rp, struct btcx_skiplist *skips,
- u32 sync_line, int skip_even, int skip_odd)
-{
- int line,maxy,start,end,skip,nskips;
- u32 ri,ra;
- u32 addr;
-
- /* sync instruction */
- *(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
-
- addr = (unsigned long)dev->fbuf.base;
- addr += dev->fbuf.fmt.bytesperline * fh->win.w.top;
- addr += (fh->fmt->depth >> 3) * fh->win.w.left;
-
- /* scan lines */
- for (maxy = -1, line = 0; line < fh->win.w.height;
- line++, addr += dev->fbuf.fmt.bytesperline) {
- if ((line%2) == 0 && skip_even)
- continue;
- if ((line%2) == 1 && skip_odd)
- continue;
-
- /* calculate clipping */
- if (line > maxy)
- btcx_calc_skips(line, fh->win.w.width, &maxy,
- skips, &nskips, fh->clips, fh->nclips);
-
- /* write out risc code */
- for (start = 0, skip = 0; start < fh->win.w.width; start = end) {
- if (skip >= nskips) {
- ri = RISC_WRITE;
- end = fh->win.w.width;
- } else if (start < skips[skip].start) {
- ri = RISC_WRITE;
- end = skips[skip].start;
- } else {
- ri = RISC_SKIP;
- end = skips[skip].end;
- skip++;
- }
- if (RISC_WRITE == ri)
- ra = addr + (fh->fmt->depth>>3)*start;
- else
- ra = 0;
-
- if (0 == start)
- ri |= RISC_SOL;
- if (fh->win.w.width == end)
- ri |= RISC_EOL;
- ri |= (fh->fmt->depth>>3) * (end-start);
-
- *(rp++)=cpu_to_le32(ri);
- if (0 != ra)
- *(rp++)=cpu_to_le32(ra);
- }
- }
- kfree(skips);
- return rp;
-}
-
-static int ov_risc_frame(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct cx88_buffer *buf)
-{
- struct btcx_skiplist *skips;
- u32 instructions,fields;
- u32 *rp;
- int rc;
-
- /* skip list for window clipping */
- if (NULL == (skips = kmalloc(sizeof(*skips) * fh->nclips,GFP_KERNEL)))
- return -ENOMEM;
-
- fields = 0;
- if (V4L2_FIELD_HAS_TOP(fh->win.field))
- fields++;
- if (V4L2_FIELD_HAS_BOTTOM(fh->win.field))
- fields++;
-
- /* estimate risc mem: worst case is (clip+1) * lines instructions
- + syncs + jump (all 2 dwords) */
- instructions = (fh->nclips+1) * fh->win.w.height;
- instructions += 3 + 4;
- if ((rc = btcx_riscmem_alloc(dev->pci,&buf->risc,instructions*8)) < 0) {
- kfree(skips);
- return rc;
- }
-
- /* write risc instructions */
- rp = buf->risc.cpu;
- switch (fh->win.field) {
- case V4L2_FIELD_TOP:
- rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 0);
- break;
- case V4L2_FIELD_BOTTOM:
- rp = ov_risc_field(dev, fh, rp, skips, 0x200, 0, 0);
- break;
- case V4L2_FIELD_INTERLACED:
- rp = ov_risc_field(dev, fh, rp, skips, 0, 0, 1);
- rp = ov_risc_field(dev, fh, rp, skips, 0x200, 1, 0);
- break;
- default:
- BUG();
- }
-
- /* save pointer to jmp instruction address */
- buf->risc.jmp = rp;
- kfree(skips);
- return 0;
-}
-
-static int verify_window(struct cx8800_dev *dev, struct v4l2_window *win)
-{
- enum v4l2_field field;
- int maxw, maxh;
-
- if (NULL == dev->fbuf.base)
- return -EINVAL;
- if (win->w.width < 48 || win->w.height < 32)
- return -EINVAL;
- if (win->clipcount > 2048)
- return -EINVAL;
-
- field = win->field;
- maxw = norm_maxw(core->tvnorm);
- maxh = norm_maxh(core->tvnorm);
-
- if (V4L2_FIELD_ANY == field) {
- field = (win->w.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_TOP;
- }
- switch (field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
- case V4L2_FIELD_INTERLACED:
- break;
- default:
- return -EINVAL;
- }
-
- win->field = field;
- if (win->w.width > maxw)
- win->w.width = maxw;
- if (win->w.height > maxh)
- win->w.height = maxh;
- return 0;
-}
-
-static int setup_window(struct cx8800_dev *dev, struct cx8800_fh *fh,
- struct v4l2_window *win)
-{
- struct v4l2_clip *clips = NULL;
- int n,size,retval = 0;
-
- if (NULL == fh->fmt)
- return -EINVAL;
- retval = verify_window(dev,win);
- if (0 != retval)
- return retval;
-
- /* copy clips -- luckily v4l1 + v4l2 are binary
- compatible here ...*/
- n = win->clipcount;
- size = sizeof(*clips)*(n+4);
- clips = kmalloc(size,GFP_KERNEL);
- if (NULL == clips)
- return -ENOMEM;
- if (n > 0) {
- if (copy_from_user(clips,win->clips,sizeof(struct v4l2_clip)*n)) {
- kfree(clips);
- return -EFAULT;
- }
- }
-
- /* clip against screen */
- if (NULL != dev->fbuf.base)
- n = btcx_screen_clips(dev->fbuf.fmt.width, dev->fbuf.fmt.height,
- &win->w, clips, n);
- btcx_sort_clips(clips,n);
-
- /* 4-byte alignments */
- switch (fh->fmt->depth) {
- case 8:
- case 24:
- btcx_align(&win->w, clips, n, 3);
- break;
- case 16:
- btcx_align(&win->w, clips, n, 1);
- break;
- case 32:
- /* no alignment fixups needed */
- break;
- default:
- BUG();
- }
-
- down(&fh->vidq.lock);
- if (fh->clips)
- kfree(fh->clips);
- fh->clips = clips;
- fh->nclips = n;
- fh->win = *win;
-#if 0
- fh->ov.setup_ok = 1;
-#endif
-
- /* update overlay if needed */
- retval = 0;
-#if 0
- if (check_btres(fh, RESOURCE_OVERLAY)) {
- struct bttv_buffer *new;
-
- new = videobuf_alloc(sizeof(*new));
- bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
- retval = bttv_switch_overlay(btv,fh,new);
- }
-#endif
- up(&fh->vidq.lock);
- return retval;
-}
-#endif
/* ------------------------------------------------------------------ */
@@ -1187,9 +956,24 @@ static void init_controls(struct cx8800_dev *dev)
.id = V4L2_CID_AUDIO_VOLUME,
.value = 0x3f,
};
+ static struct v4l2_control hue = {
+ .id = V4L2_CID_HUE,
+ .value = 0x80,
+ };
+ static struct v4l2_control contrast = {
+ .id = V4L2_CID_CONTRAST,
+ .value = 0x80,
+ };
+ static struct v4l2_control brightness = {
+ .id = V4L2_CID_BRIGHTNESS,
+ .value = 0x80,
+ };
set_control(dev,&mute);
set_control(dev,&volume);
+ set_control(dev,&hue);
+ set_control(dev,&contrast);
+ set_control(dev,&brightness);
}
/* ------------------------------------------------------------------ */
@@ -1312,9 +1096,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
struct cx8800_fh *fh = file->private_data;
struct cx8800_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
-#if 0
- unsigned long flags;
-#endif
int err;
if (video_debug > 1)
@@ -1335,9 +1116,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_VBI_CAPTURE |
-#if 0
- V4L2_CAP_VIDEO_OVERLAY |
-#endif
0;
if (UNSET != core->tuner_type)
cap->capabilities |= V4L2_CAP_TUNER;
@@ -1438,36 +1216,6 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
}
-#if 0
- /* needs review */
- case VIDIOC_G_AUDIO:
- {
- struct v4l2_audio *a = arg;
- unsigned int n = a->index;
-
- memset(a,0,sizeof(*a));
- a->index = n;
- switch (n) {
- case 0:
- if ((CX88_VMUX_TELEVISION == INPUT(n)->type)
- || (CX88_VMUX_CABLE == INPUT(n)->type)) {
- strcpy(a->name,"Television");
- // FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO.
- return 0;
- }
- break;
- case 1:
- if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD == core->board) {
- strcpy(a->name,"Line In");
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
- }
- break;
- }
- // Audio input not available.
- return -EINVAL;
- }
-#endif
/* --- capture ioctls ---------------------------------------- */
case VIDIOC_ENUM_FMT:
@@ -1570,13 +1318,16 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
{
struct v4l2_frequency *f = arg;
+ memset(f,0,sizeof(*f));
+
if (UNSET == core->tuner_type)
return -EINVAL;
- if (f->tuner != 0)
- return -EINVAL;
- memset(f,0,sizeof(*f));
+
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = dev->freq;
+
+ cx88_call_i2c_clients(dev->core,VIDIOC_G_FREQUENCY,f);
+
return 0;
}
case VIDIOC_S_FREQUENCY:
@@ -1594,11 +1345,7 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
down(&dev->lock);
dev->freq = f->frequency;
cx88_newstation(core);
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(dev->core,VIDIOC_S_FREQUENCY,f);
-#else
- cx88_call_i2c_clients(dev->core,VIDIOCSFREQ,&dev->freq);
-#endif
up(&dev->lock);
return 0;
}
@@ -1708,19 +1455,8 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
- t->rangelow = (int)(65*16);
- t->rangehigh = (int)(108*16);
-#ifdef V4L2_I2C_CLIENTS
cx88_call_i2c_clients(dev->core,VIDIOC_G_TUNER,t);
-#else
- {
- struct video_tuner vt;
- memset(&vt,0,sizeof(vt));
- cx88_call_i2c_clients(dev,VIDIOCGTUNER,&vt);
- t->signal = vt.signal;
- }
-#endif
return 0;
}
case VIDIOC_ENUMINPUT:
@@ -1753,8 +1489,29 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
*id = 0;
return 0;
}
- case VIDIOC_S_AUDIO:
+ case VIDIOCSTUNER:
+ {
+ struct video_tuner *v = arg;
+
+ if (v->tuner) /* Only tuner 0 */
+ return -EINVAL;
+
+ cx88_call_i2c_clients(dev->core,VIDIOCSTUNER,v);
+ return 0;
+ }
case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ cx88_call_i2c_clients(dev->core,VIDIOC_S_TUNER,t);
+
+ return 0;
+ }
+
+ case VIDIOC_S_AUDIO:
case VIDIOC_S_INPUT:
case VIDIOC_S_STD:
return 0;
@@ -1825,6 +1582,14 @@ static void cx8800_vid_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
+static char *cx88_vid_irqs[32] = {
+ "y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
+ "y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
+ "y_oflow", "u_oflow", "v_oflow", "vbi_oflow",
+ "y_sync", "u_sync", "v_sync", "vbi_sync",
+ "opc_err", "par_err", "rip_err", "pci_abort",
+};
+
static void cx8800_vid_irq(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -2065,11 +1830,6 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
request_module("tuner");
if (core->tda9887_conf)
request_module("tda9887");
- if (core->tuner_type != UNSET)
- cx88_call_i2c_clients(dev->core,TUNER_SET_TYPE,&core->tuner_type);
- if (core->tda9887_conf)
- cx88_call_i2c_clients(dev->core,TDA9887_SET_CONFIG,&core->tda9887_conf);
-
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
&cx8800_video_template,"video");
@@ -2162,7 +1922,7 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
/* stop video+vbi capture */
@@ -2179,10 +1939,8 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
}
spin_unlock(&dev->slock);
-#if 1
/* FIXME -- shutdown device */
cx88_shutdown(dev->core);
-#endif
pci_save_state(pci_dev);
if (0 != pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state))) {
@@ -2194,7 +1952,7 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
static int cx8800_resume(struct pci_dev *pci_dev)
{
- struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
+ struct cx8800_dev *dev = pci_get_drvdata(pci_dev);
struct cx88_core *core = dev->core;
if (dev->state.disabled) {
@@ -2204,10 +1962,8 @@ static int cx8800_resume(struct pci_dev *pci_dev)
pci_set_power_state(pci_dev, PCI_D0);
pci_restore_state(pci_dev);
-#if 1
/* FIXME: re-initialize hardware */
cx88_reset(dev->core);
-#endif
/* restart video+vbi capture */
spin_lock(&dev->slock);
@@ -2230,8 +1986,8 @@ static struct pci_device_id cx8800_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8800,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
},{
/* --- end of list --- */
}
@@ -2239,10 +1995,10 @@ static struct pci_device_id cx8800_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, cx8800_pci_tbl);
static struct pci_driver cx8800_pci_driver = {
- .name = "cx8800",
- .id_table = cx8800_pci_tbl,
- .probe = cx8800_initdev,
- .remove = __devexit_p(cx8800_finidev),
+ .name = "cx8800",
+ .id_table = cx8800_pci_tbl,
+ .probe = cx8800_initdev,
+ .remove = __devexit_p(cx8800_finidev),
.suspend = cx8800_suspend,
.resume = cx8800_resume,
@@ -2274,4 +2030,5 @@ module_exit(cx8800_fini);
* Local variables:
* c-basic-offset: 8
* End:
+ * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
*/
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 88eaaaba5ad8..307beae04f2a 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -1,5 +1,5 @@
/*
- * $Id: cx88.h,v 1.56 2005/03/04 09:12:23 kraxel Exp $
+ * $Id: cx88.h,v 1.68 2005/07/07 14:17:47 mchehab Exp $
*
* v4l2 device driver for cx2388x based TV cards
*
@@ -51,8 +51,6 @@
/* ----------------------------------------------------------- */
/* defines and enums */
-#define V4L2_I2C_CLIENTS 1
-
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
@@ -64,6 +62,13 @@
#define SHADOW_AUD_BAL_CTL 2
#define SHADOW_MAX 2
+/* FM Radio deemphasis type */
+enum cx88_deemph_type {
+ FM_NO_DEEMPH = 0,
+ FM_DEEMPH_50,
+ FM_DEEMPH_75
+};
+
/* ----------------------------------------------------------- */
/* tv norms */
@@ -77,9 +82,9 @@ struct cx88_tvnorm {
static unsigned int inline norm_maxw(struct cx88_tvnorm *norm)
{
return (norm->id & V4L2_STD_625_50) ? 768 : 640;
-// return (norm->id & V4L2_STD_625_50) ? 720 : 640;
}
+
static unsigned int inline norm_maxh(struct cx88_tvnorm *norm)
{
return (norm->id & V4L2_STD_625_50) ? 576 : 480;
@@ -152,7 +157,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_KWORLD_DVB_T 14
#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1 15
#define CX88_BOARD_KWORLD_LTV883 16
-#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD 17
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q 17
#define CX88_BOARD_HAUPPAUGE_DVB_T1 18
#define CX88_BOARD_CONEXANT_DVB_T1 19
#define CX88_BOARD_PROVIDEO_PV259 20
@@ -160,8 +165,12 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_PCHDTV_HD3000 22
#define CX88_BOARD_DNTV_LIVE_DVB_T 23
#define CX88_BOARD_HAUPPAUGE_ROSLYN 24
-#define CX88_BOARD_DIGITALLOGIC_MEC 25
+#define CX88_BOARD_DIGITALLOGIC_MEC 25
#define CX88_BOARD_IODATA_GVBCTV7E 26
+#define CX88_BOARD_PIXELVIEW_PLAYTV_ULTRA_PRO 27
+#define CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_T 28
+#define CX88_BOARD_ADSTECH_DVB_T_PCI 29
+#define CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1 30
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -185,6 +194,9 @@ struct cx88_input {
struct cx88_board {
char *name;
unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
int tda9887_conf;
struct cx88_input input[8];
struct cx88_input radio;
@@ -208,7 +220,6 @@ struct cx88_subid {
#define RESOURCE_VBI 4
#define BUFFER_TIMEOUT (HZ/2) /* 0.5 seconds */
-//#define BUFFER_TIMEOUT (HZ*2)
/* buffer for one video frame */
struct cx88_buffer {
@@ -255,6 +266,9 @@ struct cx88_core {
/* config info -- analog */
unsigned int board;
unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
unsigned int tda9887_conf;
unsigned int has_radio;
@@ -321,11 +335,6 @@ struct cx8800_dev {
struct pci_dev *pci;
unsigned char pci_rev,pci_lat;
-#if 0
- /* video overlay */
- struct v4l2_framebuffer fbuf;
- struct cx88_buffer *screen;
-#endif
/* capture queues */
struct cx88_dmaqueue vidq;
@@ -420,8 +429,6 @@ struct cx8802_dev {
/* ----------------------------------------------------------- */
/* cx88-core.c */
-extern char *cx88_vid_irqs[32];
-extern char *cx88_mpeg_irqs[32];
extern void cx88_print_irqbits(char *name, char *tag, char **strings,
u32 bits, u32 mask);
extern void cx88_print_ioctl(char *name, unsigned int cmd);
@@ -471,6 +478,11 @@ extern void cx88_core_put(struct cx88_core *core,
/* cx88-vbi.c */
void cx8800_vbi_fmt(struct cx8800_dev *dev, struct v4l2_format *f);
+/*
+int cx8800_start_vbi_dma(struct cx8800_dev *dev,
+ struct cx88_dmaqueue *q,
+ struct cx88_buffer *buf);
+*/
int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q);
diff --git a/drivers/media/video/ir-kbd-gpio.c b/drivers/media/video/ir-kbd-gpio.c
index ab6620de4b3b..a565823330aa 100644
--- a/drivers/media/video/ir-kbd-gpio.c
+++ b/drivers/media/video/ir-kbd-gpio.c
@@ -1,5 +1,5 @@
/*
- * $Id: ir-kbd-gpio.c,v 1.12 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-kbd-gpio.c,v 1.13 2005/05/15 19:01:26 mchehab Exp $
*
* Copyright (c) 2003 Gerd Knorr
* Copyright (c) 2003 Pavel Machek
@@ -114,38 +114,6 @@ static IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE] = {
[ 0x3e ] = KEY_VOLUMEUP, // 'volume +'
};
-static IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
- [ 2 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 11 ] = KEY_KP2,
- [ 27 ] = KEY_KP3,
- [ 5 ] = KEY_KP4,
- [ 9 ] = KEY_KP5,
- [ 21 ] = KEY_KP6,
- [ 6 ] = KEY_KP7,
- [ 10 ] = KEY_KP8,
- [ 18 ] = KEY_KP9,
-
- [ 3 ] = KEY_TUNER, // TV/FM
- [ 7 ] = KEY_SEARCH, // scan
- [ 28 ] = KEY_ZOOM, // full screen
- [ 30 ] = KEY_POWER,
- [ 23 ] = KEY_VOLUMEDOWN,
- [ 31 ] = KEY_VOLUMEUP,
- [ 20 ] = KEY_CHANNELDOWN,
- [ 22 ] = KEY_CHANNELUP,
- [ 24 ] = KEY_MUTE,
-
- [ 0 ] = KEY_LIST, // source
- [ 19 ] = KEY_INFO, // loop
- [ 16 ] = KEY_LAST, // +100
- [ 13 ] = KEY_CLEAR, // reset
- [ 12 ] = BTN_RIGHT, // fun++
- [ 4 ] = BTN_LEFT, // fun--
- [ 14 ] = KEY_GOTO, // function
- [ 15 ] = KEY_STOP, // freeze
-};
-
/* Attila Kondoros <attila.kondoros@chello.hu> */
static IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE] = {
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 92664f75d327..9fc5055e001c 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -1,5 +1,5 @@
/*
- * $Id: ir-kbd-i2c.c,v 1.10 2004/12/09 12:51:35 kraxel Exp $
+ * $Id: ir-kbd-i2c.c,v 1.11 2005/07/07 16:42:11 mchehab Exp $
*
* keyboard input driver for i2c IR remote controls
*
@@ -66,26 +66,26 @@ static IR_KEYTAB_TYPE ir_codes_pv951[IR_KEYTAB_SIZE] = {
[ 29 ] = KEY_PAGEDOWN,
[ 19 ] = KEY_SOUND,
- [ 24 ] = KEY_KPPLUSMINUS, // CH +/-
- [ 22 ] = KEY_SUBTITLE, // CC
- [ 13 ] = KEY_TEXT, // TTX
- [ 11 ] = KEY_TV, // AIR/CBL
- [ 17 ] = KEY_PC, // PC/TV
- [ 23 ] = KEY_OK, // CH RTN
- [ 25 ] = KEY_MODE, // FUNC
- [ 12 ] = KEY_SEARCH, // AUTOSCAN
+ [ 24 ] = KEY_KPPLUSMINUS, /* CH +/- */
+ [ 22 ] = KEY_SUBTITLE, /* CC */
+ [ 13 ] = KEY_TEXT, /* TTX */
+ [ 11 ] = KEY_TV, /* AIR/CBL */
+ [ 17 ] = KEY_PC, /* PC/TV */
+ [ 23 ] = KEY_OK, /* CH RTN */
+ [ 25 ] = KEY_MODE, /* FUNC */
+ [ 12 ] = KEY_SEARCH, /* AUTOSCAN */
/* Not sure what to do with these ones! */
- [ 15 ] = KEY_SELECT, // SOURCE
- [ 10 ] = KEY_KPPLUS, // +100
- [ 20 ] = KEY_KPEQUAL, // SYNC
- [ 28 ] = KEY_MEDIA, // PC/TV
+ [ 15 ] = KEY_SELECT, /* SOURCE */
+ [ 10 ] = KEY_KPPLUS, /* +100 */
+ [ 20 ] = KEY_KPEQUAL, /* SYNC */
+ [ 28 ] = KEY_MEDIA, /* PC/TV */
};
static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
[ 0x3 ] = KEY_POWER,
[ 0x6f ] = KEY_MUTE,
- [ 0x10 ] = KEY_BACKSPACE, // Recall
+ [ 0x10 ] = KEY_BACKSPACE, /* Recall */
[ 0x11 ] = KEY_KP0,
[ 0x4 ] = KEY_KP1,
@@ -97,7 +97,7 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
[ 0xc ] = KEY_KP7,
[ 0xd ] = KEY_KP8,
[ 0xe ] = KEY_KP9,
- [ 0x12 ] = KEY_KPDOT, // 100+
+ [ 0x12 ] = KEY_KPDOT, /* 100+ */
[ 0x7 ] = KEY_VOLUMEUP,
[ 0xb ] = KEY_VOLUMEDOWN,
@@ -109,25 +109,16 @@ static IR_KEYTAB_TYPE ir_codes_purpletv[IR_KEYTAB_SIZE] = {
[ 0x13 ] = KEY_CHANNELDOWN,
[ 0x48 ] = KEY_ZOOM,
- [ 0x1b ] = KEY_VIDEO, // Video source
-#if 0
- [ 0x1f ] = KEY_S, // Snapshot
-#endif
- [ 0x49 ] = KEY_LANGUAGE, // MTS Select
- [ 0x19 ] = KEY_SEARCH, // Auto Scan
+ [ 0x1b ] = KEY_VIDEO, /* Video source */
+ [ 0x49 ] = KEY_LANGUAGE, /* MTS Select */
+ [ 0x19 ] = KEY_SEARCH, /* Auto Scan */
[ 0x4b ] = KEY_RECORD,
[ 0x46 ] = KEY_PLAY,
- [ 0x45 ] = KEY_PAUSE, // Pause
+ [ 0x45 ] = KEY_PAUSE, /* Pause */
[ 0x44 ] = KEY_STOP,
-#if 0
- [ 0x43 ] = KEY_T, // Time Shift
- [ 0x47 ] = KEY_Y, // Time Shift OFF
- [ 0x4a ] = KEY_O, // TOP
- [ 0x17 ] = KEY_F, // SURF CH
-#endif
- [ 0x40 ] = KEY_FORWARD, // Forward ?
- [ 0x42 ] = KEY_REWIND, // Backward ?
+ [ 0x40 ] = KEY_FORWARD, /* Forward ? */
+ [ 0x42 ] = KEY_REWIND, /* Backward ? */
};
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
index 09464d624a6b..6239254db27e 100644
--- a/drivers/media/video/msp3400.c
+++ b/drivers/media/video/msp3400.c
@@ -567,10 +567,6 @@ static void msp3400c_set_audmode(struct i2c_client *client, int audmode)
switch (audmode) {
case V4L2_TUNER_MODE_STEREO:
src = 0x0020 | nicam;
-#if 0
- /* spatial effect */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0005,0x4000);
-#endif
break;
case V4L2_TUNER_MODE_MONO:
if (msp->mode == MSP_MODE_AM_NICAM) {
@@ -735,28 +731,21 @@ static int msp34xx_sleep(struct msp3400c *msp, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
-again:
add_wait_queue(&msp->wq, &wait);
if (!kthread_should_stop()) {
if (timeout < 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} else {
-#if 0
- /* hmm, that one doesn't return on wakeup ... */
- msleep_interruptible(timeout);
-#else
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(timeout));
-#endif
}
}
+ if (current->flags & PF_FREEZE) {
+ refrigerator ();
+ }
remove_wait_queue(&msp->wq, &wait);
-
- if (try_to_freeze(PF_FREEZE))
- goto again;
-
return msp->restart;
}
@@ -1159,17 +1148,10 @@ static int msp3410d_thread(void *data)
MSP_CARRIER(10.7));
/* scart routing */
msp3400c_set_scart(client,SCART_IN2,0);
-#if 0
- /* radio from SCART_IN2 */
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220);
- msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220);
-#else
/* msp34xx does radio decoding */
msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
-#endif
break;
case 0x0003:
case 0x0004:
@@ -1436,7 +1418,7 @@ static int msp_detach(struct i2c_client *client);
static int msp_probe(struct i2c_adapter *adap);
static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg);
-static int msp_suspend(struct device * dev, pm_message_t state, u32 level);
+static int msp_suspend(struct device * dev, u32 state, u32 level);
static int msp_resume(struct device * dev, u32 level);
static void msp_wake_thread(struct i2c_client *client);
@@ -1512,10 +1494,6 @@ static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
return -1;
}
-#if 0
- /* this will turn on a 1kHz beep - might be useful for debugging... */
- msp3400c_write(c,I2C_MSP3400C_DFP, 0x0014, 0x1040);
-#endif
msp3400c_setvolume(c, msp->muted, msp->volume, msp->balance);
snprintf(c->name, sizeof(c->name), "MSP34%02d%c-%c%d",
@@ -1841,7 +1819,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
}
-static int msp_suspend(struct device * dev, pm_message_t state, u32 level)
+static int msp_suspend(struct device * dev, u32 state, u32 level)
{
struct i2c_client *c = container_of(dev, struct i2c_client, dev);
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h
index d70a954e13aa..023f33056a4f 100644
--- a/drivers/media/video/msp3400.h
+++ b/drivers/media/video/msp3400.h
@@ -1,3 +1,7 @@
+/*
+ * $Id: msp3400.h,v 1.3 2005/06/12 04:19:19 mchehab Exp $
+ */
+
#ifndef MSP3400_H
#define MSP3400_H
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 95ad17b7f38e..2fb7c2d1787a 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -1,5 +1,5 @@
/*
- * $Id: mt20xx.c,v 1.4 2005/03/04 09:24:56 kraxel Exp $
+ * $Id: mt20xx.c,v 1.5 2005/06/16 08:29:49 nsh Exp $
*
* i2c tv tuner chip device driver
* controls microtune tuners, mt2032 + mt2050 at the moment.
@@ -295,8 +295,8 @@ static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
int if2 = t->radio_if2;
// per Manual for FM tuning: first if center freq. 1085 MHz
- mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
- 1085*1000*1000,if2,if2,if2);
+ mt2032_set_if_freq(c, freq * 1000 / 16,
+ 1085*1000*1000,if2,if2,if2);
}
// Initalization as described in "MT203x Programming Procedures", Rev 1.2, Feb.2001
@@ -511,22 +511,6 @@ int microtune_init(struct i2c_client *c)
tuner_info("microtune: companycode=%04x part=%02x rev=%02x\n",
company_code,buf[0x13],buf[0x14]);
-#if 0
- /* seems to cause more problems than it solves ... */
- switch (company_code) {
- case 0x30bf:
- case 0x3cbf:
- case 0x3dbf:
- case 0x4d54:
- case 0x8e81:
- case 0x8e91:
- /* ok (?) */
- break;
- default:
- tuner_warn("tuner: microtune: unknown companycode\n");
- return 0;
- }
-#endif
if (buf[0x13] < ARRAY_SIZE(microtune_part) &&
NULL != microtune_part[buf[0x13]])
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index 70bf1f1fad59..486234d41b56 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -326,6 +326,7 @@ static int mxb_init_done(struct saa7146_dev* dev)
struct mxb* mxb = (struct mxb*)dev->ext_priv;
struct video_decoder_init init;
struct i2c_msg msg;
+ struct tuner_setup tun_setup;
int i = 0, err = 0;
struct tea6415c_multiplex vm;
@@ -349,8 +350,10 @@ static int mxb_init_done(struct saa7146_dev* dev)
mxb->saa7111a->driver->command(mxb->saa7111a,DECODER_SET_VBI_BYPASS, &i);
/* select a tuner type */
- i = 5;
- mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE, &i);
+ tun_setup.mode_mask = T_ANALOG_TV;
+ tun_setup.addr = ADDR_UNSET;
+ tun_setup.type = 5;
+ mxb->tuner->driver->command(mxb->tuner,TUNER_SET_TYPE_ADDR, &tun_setup);
/* mute audio on tea6420s */
mxb->tea6420_1->driver->command(mxb->tea6420_1,TEA6420_SWITCH, &TEA6420_line[6][0]);
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 42c2b565c9fe..79d05ea1b69b 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -41,16 +41,16 @@ enum saa6752hs_videoformat {
static const struct v4l2_format v4l2_format_table[] =
{
- [SAA6752HS_VF_D1] = {
- .fmt = { .pix = { .width = 720, .height = 576 }, }, },
- [SAA6752HS_VF_2_3_D1] = {
- .fmt = { .pix = { .width = 480, .height = 576 }, }, },
- [SAA6752HS_VF_1_2_D1] = {
- .fmt = { .pix = { .width = 352, .height = 576 }, }, },
- [SAA6752HS_VF_SIF] = {
- .fmt = { .pix = { .width = 352, .height = 288 }, }, },
- [SAA6752HS_VF_UNKNOWN] = {
- .fmt = { .pix = { .width = 0, .height = 0 }, }, },
+ [SAA6752HS_VF_D1] =
+ { .fmt = { .pix = { .width = 720, .height = 576 }}},
+ [SAA6752HS_VF_2_3_D1] =
+ { .fmt = { .pix = { .width = 480, .height = 576 }}},
+ [SAA6752HS_VF_1_2_D1] =
+ { .fmt = { .pix = { .width = 352, .height = 576 }}},
+ [SAA6752HS_VF_SIF] =
+ { .fmt = { .pix = { .width = 352, .height = 288 }}},
+ [SAA6752HS_VF_UNKNOWN] =
+ { .fmt = { .pix = { .width = 0, .height = 0}}},
};
struct saa6752hs_state {
@@ -155,10 +155,6 @@ static struct v4l2_mpeg_compression param_defaults =
.target = 256,
},
-#if 0
- /* FIXME: size? via S_FMT? */
- .video_format = MPEG_VIDEO_FORMAT_D1,
-#endif
};
/* ---------------------------------------------------------------------- */
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index c51eb7f078d3..88b71a20b602 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -1,6 +1,5 @@
-
/*
- * $Id: saa7134-cards.c,v 1.54 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: saa7134-cards.c,v 1.80 2005/07/07 01:49:30 mkrufky Exp $
*
* device driver for philips saa7134 based TV cards
* card-specific stuff.
@@ -47,6 +46,10 @@ struct saa7134_board saa7134_boards[] = {
.name = "UNKNOWN/GENERIC",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.inputs = {{
.name = "default",
.vmux = 0,
@@ -58,6 +61,10 @@ struct saa7134_board saa7134_boards[] = {
.name = "Proteus Pro [philips reference design]",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.inputs = {{
.name = name_comp1,
.vmux = 0,
@@ -83,6 +90,10 @@ struct saa7134_board saa7134_boards[] = {
.name = "LifeView FlyVIDEO3000",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.gpiomask = 0xe000,
.inputs = {{
.name = name_tv,
@@ -90,7 +101,7 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.gpio = 0x8000,
.tv = 1,
- },{
+ },{
.name = name_tv_mono,
.vmux = 1,
.amux = LINE2,
@@ -117,12 +128,21 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.gpio = 0x2000,
},
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x8000,
+ },
},
[SAA7134_BOARD_FLYVIDEO2000] = {
/* "TC Wan" <tcwan@cs.usm.my> */
.name = "LifeView FlyVIDEO2000",
.audio_clock = 0x00200000,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.gpiomask = 0xe000,
.inputs = {{
.name = name_tv,
@@ -146,14 +166,14 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.gpio = 0x4000,
}},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
.gpio = 0x2000,
- },
+ },
.mute = {
.name = name_mute,
- .amux = LINE2,
+ .amux = LINE2,
.gpio = 0x8000,
},
},
@@ -162,10 +182,14 @@ struct saa7134_board saa7134_boards[] = {
.name = "LifeView FlyTV Platinum Mini",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.inputs = {{
.name = name_tv,
.vmux = 1,
- .amux = LINE2,
+ .amux = TV,
.tv = 1,
},{
.name = name_comp1,
@@ -183,6 +207,10 @@ struct saa7134_board saa7134_boards[] = {
.name = "LifeView FlyTV Platinum FM",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.gpiomask = 0x1E000, /* Set GP16 and unused 15,14,13 to Output */
.inputs = {{
.name = name_tv,
@@ -190,7 +218,7 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
.gpio = 0x10000, /* GP16=1 selects TV input */
.tv = 1,
- },{
+ },{
/* .name = name_tv_mono,
.vmux = 1,
.amux = LINE2,
@@ -200,29 +228,38 @@ struct saa7134_board saa7134_boards[] = {
*/ .name = name_comp1, /* Composite signal on S-Video input */
.vmux = 0,
.amux = LINE2,
-// .gpio = 0x4000,
+/* .gpio = 0x4000, */
},{
.name = name_comp2, /* Composite input */
.vmux = 3,
.amux = LINE2,
-// .gpio = 0x4000,
+/* .gpio = 0x4000, */
},{
.name = name_svideo, /* S-Video signal on S-Video input */
.vmux = 8,
.amux = LINE2,
-// .gpio = 0x4000,
+/* .gpio = 0x4000, */
}},
.radio = {
.name = name_radio,
.amux = TV,
.gpio = 0x00000, /* GP16=0 selects FM radio antenna */
},
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x10000,
+ },
},
[SAA7134_BOARD_EMPRESS] = {
/* "Gert Vervoort" <gert.vervoort@philips.com> */
.name = "EMPRESS",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
.inputs = {{
.name = name_comp1,
.vmux = 0,
@@ -245,33 +282,40 @@ struct saa7134_board saa7134_boards[] = {
.video_out = CCIR656,
},
[SAA7134_BOARD_MONSTERTV] = {
- /* "K.Ohta" <alpha292@bremen.or.jp> */
- .name = "SKNet Monster TV",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
- },
+ /* "K.Ohta" <alpha292@bremen.or.jp> */
+ .name = "SKNet Monster TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
},
[SAA7134_BOARD_MD9717] = {
.name = "Tevion MD 9717",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -302,10 +346,13 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_TVSTATION_RDS] = {
- /* Typhoon TV Tuner RDS: Art.Nr. 50694 */
+ /* Typhoon TV Tuner RDS: Art.Nr. 50694 */
.name = "KNC One TV-Station RDS / Typhoon TV Tuner RDS",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -314,10 +361,10 @@ struct saa7134_board saa7134_boards[] = {
.tv = 1,
},{
.name = name_tv_mono,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- },{
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ },{
.name = name_svideo,
.vmux = 8,
@@ -328,10 +375,10 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
},{
- .name = "CVid over SVid",
- .vmux = 0,
- .amux = LINE1,
- }},
+ .name = "CVid over SVid",
+ .vmux = 0,
+ .amux = LINE1,
+ }},
.radio = {
.name = name_radio,
.amux = LINE2,
@@ -341,6 +388,9 @@ struct saa7134_board saa7134_boards[] = {
.name = "KNC One TV-Station DVR",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x820000,
.inputs = {{
@@ -369,32 +419,38 @@ struct saa7134_board saa7134_boards[] = {
.video_out = CCIR656,
},
[SAA7134_BOARD_CINERGY400] = {
- .name = "Terratec Cinergy 400 TV",
- .audio_clock = 0x00200000,
- .tuner_type = TUNER_PHILIPS_PAL,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp2, // CVideo over SVideo Connector
- .vmux = 0,
- .amux = LINE1,
- }}
- },
+ .name = "Terratec Cinergy 400 TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp2, /* CVideo over SVideo Connector */
+ .vmux = 0,
+ .amux = LINE1,
+ }}
+ },
[SAA7134_BOARD_MD5044] = {
.name = "Medion 5044",
- .audio_clock = 0x00187de7, // was: 0x00200000,
+ .audio_clock = 0x00187de7, /* was: 0x00200000, */
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -426,57 +482,65 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_KWORLD] = {
- .name = "Kworld/KuroutoShikou SAA7130-TVPCI",
+ .name = "Kworld/KuroutoShikou SAA7130-TVPCI",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC_M,
- .inputs = {{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- }},
- },
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }},
+ },
[SAA7134_BOARD_CINERGY600] = {
- .name = "Terratec Cinergy 600 TV",
- .audio_clock = 0x00200000,
- .tuner_type = TUNER_PHILIPS_PAL,
+ .name = "Terratec Cinergy 600 TV",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp2, // CVideo over SVideo Connector
- .vmux = 0,
- .amux = LINE1,
- }},
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp2, /* CVideo over SVideo Connector */
+ .vmux = 0,
+ .amux = LINE1,
+ }},
.radio = {
.name = name_radio,
.amux = LINE2,
- },
- },
+ },
+ },
[SAA7134_BOARD_MD7134] = {
.name = "Medion 7134",
- //.audio_clock = 0x00200000,
.audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .tuner_type = TUNER_PHILIPS_FMD1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.mpeg = SAA7134_MPEG_DVB,
.inputs = {{
@@ -504,6 +568,9 @@ struct saa7134_board saa7134_boards[] = {
.name = "Typhoon TV+Radio 90031",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -523,11 +590,14 @@ struct saa7134_board saa7134_boards[] = {
.name = name_radio,
.amux = LINE2,
},
- },
+ },
[SAA7134_BOARD_ELSA] = {
.name = "ELSA EX-VISION 300TV",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -542,11 +612,14 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.tv = 1,
}},
- },
+ },
[SAA7134_BOARD_ELSA_500TV] = {
.name = "ELSA EX-VISION 500TV",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_HITACHI_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_svideo,
.vmux = 7,
@@ -562,83 +635,100 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.tv = 1,
}},
- },
+ },
[SAA7134_BOARD_ASUSTeK_TVFM7134] = {
- .name = "ASUS TV-FM 7134",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
- .tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE2,
- },{
- .name = name_svideo,
- .vmux = 6,
- .amux = LINE2,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE1,
- },
- },
- [SAA7135_BOARD_ASUSTeK_TVFM7135] = {
- .name = "ASUS TV-FM 7135",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_TDA8290,
+ .name = "ASUS TV-FM 7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_ASUSTeK_TVFM7135] = {
+ .name = "ASUS TV-FM 7135",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.gpiomask = 0x200000,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
.gpio = 0x0000,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE2,
.gpio = 0x0000,
- },{
- .name = name_svideo,
- .vmux = 6,
- .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE2,
.gpio = 0x0000,
- }},
- .radio = {
- .name = name_radio,
- .amux = TV,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
.gpio = 0x200000,
- },
+ },
+ .mute = {
+ .name = name_mute,
+ .gpio = 0x0000,
+ },
+
},
[SAA7134_BOARD_VA1000POWER] = {
- .name = "AOPEN VA1000 POWER",
+ .name = "AOPEN VA1000 POWER",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC,
- .inputs = {{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- }},
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }},
},
[SAA7134_BOARD_10MOONSTVMASTER] = {
/* "lilicheng" <llc@linuxfans.org> */
.name = "10MOONS PCI TV CAPTURE CARD",
.audio_clock = 0x00200000,
.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.gpiomask = 0xe000,
.inputs = {{
.name = name_tv,
@@ -662,14 +752,14 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.gpio = 0x4000,
}},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
.gpio = 0x2000,
- },
+ },
.mute = {
.name = name_mute,
- .amux = LINE2,
+ .amux = LINE2,
.gpio = 0x8000,
},
},
@@ -678,6 +768,9 @@ struct saa7134_board saa7134_boards[] = {
.name = "BMK MPEX No Tuner",
.audio_clock = 0x200000,
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_comp1,
.vmux = 4,
@@ -706,80 +799,94 @@ struct saa7134_board saa7134_boards[] = {
.name = "Compro VideoMate TV",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC_M,
- .inputs = {{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- }},
- },
- [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }},
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS] = {
.name = "Compro VideoMate TV Gold+",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC_M,
.gpiomask = 0x800c0000,
- .inputs = {{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- .gpio = 0x06c00012,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- .gpio = 0x0ac20012,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2,
- .gpio = 0x08c20012,
- .tv = 1,
- }},
- },
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x06c00012,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x0ac20012,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .gpio = 0x08c20012,
+ .tv = 1,
+ }}, /* radio and probably mute is missing */
+ },
[SAA7134_BOARD_CRONOS_PLUS] = {
- /* gpio pins:
- 0 .. 3 BASE_ID
- 4 .. 7 PROTECT_ID
- 8 .. 11 USER_OUT
- 12 .. 13 USER_IN
- 14 .. 15 VIDIN_SEL */
+ /*
+ gpio pins:
+ 0 .. 3 BASE_ID
+ 4 .. 7 PROTECT_ID
+ 8 .. 11 USER_OUT
+ 12 .. 13 USER_IN
+ 14 .. 15 VIDIN_SEL
+ */
.name = "Matrox CronosPlus",
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.gpiomask = 0xcf00,
- .inputs = {{
- .name = name_comp1,
- .vmux = 0,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
.gpio = 2 << 14,
},{
- .name = name_comp2,
- .vmux = 0,
+ .name = name_comp2,
+ .vmux = 0,
.gpio = 1 << 14,
},{
- .name = name_comp3,
- .vmux = 0,
+ .name = name_comp3,
+ .vmux = 0,
.gpio = 0 << 14,
},{
- .name = name_comp4,
- .vmux = 0,
+ .name = name_comp4,
+ .vmux = 0,
.gpio = 3 << 14,
},{
.name = name_svideo,
.vmux = 8,
.gpio = 2 << 14,
- }},
- },
+ }},
+ },
[SAA7134_BOARD_MD2819] = {
.name = "AverMedia M156 / Medion 2819",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_tv,
@@ -809,6 +916,9 @@ struct saa7134_board saa7134_boards[] = {
.name = "BMK MPEX Tuner",
.audio_clock = 0x200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_comp1,
.vmux = 1,
@@ -825,62 +935,72 @@ struct saa7134_board saa7134_boards[] = {
}},
.mpeg = SAA7134_MPEG_EMPRESS,
.video_out = CCIR656,
- },
- [SAA7134_BOARD_ASUSTEK_TVFM7133] = {
- .name = "ASUS TV-FM 7133",
- .audio_clock = 0x00187de7,
- // probably wrong, the 7133 one is the NTSC version ...
- // .tuner_type = TUNER_PHILIPS_FM1236_MK3
- .tuner_type = TUNER_LG_NTSC_NEW_TAPC,
- .tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE2,
- },{
- .name = name_svideo,
- .vmux = 6,
- .amux = LINE2,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE1,
- },
- },
+ },
+ [SAA7134_BOARD_ASUSTEK_TVFM7133] = {
+ .name = "ASUS TV-FM 7133",
+ .audio_clock = 0x00187de7,
+ /* probably wrong, the 7133 one is the NTSC version ...
+ * .tuner_type = TUNER_PHILIPS_FM1236_MK3 */
+ .tuner_type = TUNER_LG_NTSC_NEW_TAPC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
[SAA7134_BOARD_PINNACLE_PCTV_STEREO] = {
- .name = "Pinnacle PCTV Stereo (saa7134)",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_MT2032,
- .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
- .inputs = {{
- .name = name_tv,
- .vmux = 3,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE2,
- },{
- .name = name_comp2,
- .vmux = 1,
- .amux = LINE2,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE2,
- }},
- },
+ .name = "Pinnacle PCTV Stereo (saa7134)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
[SAA7134_BOARD_MANLI_MTV002] = {
/* Ognjen Nastic <ognjen@logosoft.ba> */
- .name = "Manli MuchTV M-TV002",
+ .name = "Manli MuchTV M-TV002/Behold TV 403 FM",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -899,16 +1019,15 @@ struct saa7134_board saa7134_boards[] = {
.name = name_radio,
.amux = LINE2,
},
- .mute = {
- .name = name_mute,
- .amux = LINE1,
- },
},
[SAA7134_BOARD_MANLI_MTV001] = {
/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
- .name = "Manli MuchTV M-TV001",
+ .name = "Manli MuchTV M-TV001/Behold TV 401",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -923,12 +1042,19 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
.tv = 1,
}},
- },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
[SAA7134_BOARD_TG3000TV] = {
/* TransGear 3000TV */
.name = "Nagase Sangyo TransGear 3000TV",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -944,81 +1070,90 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
}},
},
- [SAA7134_BOARD_ECS_TVP3XP] = {
- .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
- .audio_clock = 0x187de7, // xtal 32.1 MHz
- .tuner_type = TUNER_PHILIPS_PAL,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_tv_mono,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
+ [SAA7134_BOARD_ECS_TVP3XP] = {
+ .name = "Elitegroup ECS TVP3XP FM1216 Tuner Card(PAL-BG,FM) ",
+ .audio_clock = 0x187de7, /* xtal 32.1 MHz */
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = "CVid over SVid",
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
+ .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_tv_mono,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
},{
.name = "CVid over SVid",
.vmux = 0,
.amux = LINE1,
}},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
- },
- },
- [SAA7134_BOARD_ECS_TVP3XP_4CB5] = {
- .name = "Elitegroup ECS TVP3XP FM1236 Tuner Card (NTSC,FM)",
- .audio_clock = 0x187de7,
- .tuner_type = TUNER_PHILIPS_NTSC,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_tv_mono,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = "CVid over SVid",
- .vmux = 0,
- .amux = LINE1,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
- },
- },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
[SAA7134_BOARD_AVACSSMARTTV] = {
/* Roman Pszonczenko <romka@kolos.math.uni.lodz.pl> */
.name = "AVACS SmartTV",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_tv,
.vmux = 1,
.amux = TV,
.tv = 1,
- },{
+ },{
.name = name_tv_mono,
.vmux = 1,
.amux = LINE2,
@@ -1047,38 +1182,46 @@ struct saa7134_board saa7134_boards[] = {
.name = "AVerMedia DVD EZMaker",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 3,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ }},
+ },
+ [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
+ /* toshii@netbsd.org */
+ .name = "Noval Prime TV 7133",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ALPS_TSBH1_NTSC,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_comp1,
.vmux = 3,
},{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
.name = name_svideo,
.vmux = 8,
}},
},
- [SAA7134_BOARD_NOVAC_PRIMETV7133] = {
- /* toshii@netbsd.org */
- .name = "Noval Prime TV 7133",
- .audio_clock = 0x00200000,
- .tuner_type = TUNER_ALPS_TSBH1_NTSC,
- .inputs = {{
- .name = name_comp1,
- .vmux = 3,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_svideo,
- .vmux = 8,
- }},
- },
[SAA7134_BOARD_AVERMEDIA_STUDIO_305] = {
.name = "AverMedia AverTV Studio 305",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0x3,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -1098,35 +1241,41 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
}},
.radio = {
- .name = name_radio,
- .amux = LINE2,
- },
+ .name = name_radio,
+ .amux = LINE2,
+ },
.mute = {
- .name = name_mute,
- .amux = LINE1,
+ .name = name_mute,
+ .amux = LINE1,
},
},
- [SAA7133_BOARD_UPMOST_PURPLE_TV] = {
- .name = "UPMOST PURPLE TV",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_FM1236_MK3,
- .tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
- .name = name_tv,
- .vmux = 7,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_svideo,
- .vmux = 7,
- .amux = LINE1,
- }},
+ [SAA7134_BOARD_UPMOST_PURPLE_TV] = {
+ .name = "UPMOST PURPLE TV",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FM1236_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 7,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_svideo,
+ .vmux = 7,
+ .amux = LINE1,
+ }},
},
[SAA7134_BOARD_ITEMS_MTV005] = {
/* Norman Jonas <normanjonas@arcor.de> */
.name = "Items MuchTV Plus / IT-005",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -1150,27 +1299,30 @@ struct saa7134_board saa7134_boards[] = {
.name = "Terratec Cinergy 200 TV",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.inputs = {{
- .name = name_tv,
+ .name = name_tv,
.vmux = 1,
.amux = LINE2,
.tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp2, // CVideo over SVideo Connector
- .vmux = 0,
- .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp2, /* CVideo over SVideo Connector */
+ .vmux = 0,
+ .amux = LINE1,
}},
.mute = {
- .name = name_mute,
- .amux = LINE2,
+ .name = name_mute,
+ .amux = LINE2,
},
},
[SAA7134_BOARD_VIDEOMATE_TV_PVR] = {
@@ -1178,84 +1330,96 @@ struct saa7134_board saa7134_boards[] = {
.name = "Compro VideoMate TV PVR/FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.gpiomask = 0x808c0080,
- .inputs = {{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
.gpio = 0x00080,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
.gpio = 0x00080,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2_LEFT,
- .tv = 1,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2_LEFT,
+ .tv = 1,
.gpio = 0x00080,
- }},
+ }},
.radio = {
.name = name_radio,
.amux = LINE2,
.gpio = 0x80000,
- },
+ },
.mute = {
.name = name_mute,
- .amux = LINE2,
+ .amux = LINE2,
.gpio = 0x40000,
},
- },
- [SAA7134_BOARD_SABRENT_SBTTVFM] = {
+ },
+ [SAA7134_BOARD_SABRENT_SBTTVFM] = {
/* Michael Rodriguez-Torrent <mrtorrent@asu.edu> */
- .name = "Sabrent SBT-TVFM (saa7130)",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_NTSC_M,
- .inputs = {{
+ .name = "Sabrent SBT-TVFM (saa7130)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
.name = name_comp1,
.vmux = 1,
.amux = LINE2,
},{
- .name = name_tv,
- .vmux = 3,
- .amux = LINE2,
- .tv = 1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE2,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
- },
- },
+ .name = name_tv,
+ .vmux = 3,
+ .amux = LINE2,
+ .tv = 1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
[SAA7134_BOARD_ZOLID_XPERT_TV7134] = {
/* Helge Jensen <helge.jensen@slog.dk> */
- .name = ":Zolid Xpert TV7134",
+ .name = ":Zolid Xpert TV7134",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_NTSC,
- .inputs = {{
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
.name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = LINE2,
- .tv = 1,
- }},
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = LINE2,
+ .tv = 1,
+ }},
},
[SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE] = {
/* "Matteo Az" <matte.az@nospam.libero.it> ;-) */
.name = "Empire PCI TV-Radio LE",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.gpiomask = 0x4000,
.inputs = {{
.name = name_tv_mono,
@@ -1274,18 +1438,18 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
.gpio = 0x8000,
}},
- .radio = {
- .name = name_radio,
- .amux = LINE1,
- .gpio = 0x8000,
- },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ .gpio = 0x8000,
+ },
.mute = {
- .name = name_mute,
- .amux = TV,
- .gpio =0x8000,
- }
+ .name = name_mute,
+ .amux = TV,
+ .gpio =0x8000,
+ }
},
- [SAA7134_BOARD_AVERMEDIA_307] = {
+ [SAA7134_BOARD_AVERMEDIA_STUDIO_307] = {
/*
Nickolay V. Shmyrev <nshmyrev@yandex.ru>
Lots of thanks to Andrey Zolotarev <zolotarev_andrey@mail.ru>
@@ -1293,6 +1457,9 @@ struct saa7134_board saa7134_boards[] = {
.name = "Avermedia AVerTV Studio 307",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1256_IH3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x03,
.inputs = {{
@@ -1322,16 +1489,61 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE1,
.gpio = 0x01,
},
- },
- [SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
- /* Jon Westgate <oryn@oryn.fsck.tv> */
- .name = "AVerMedia Cardbus TV/Radio",
- .audio_clock = 0x00200000,
- .tuner_type = TUNER_PHILIPS_PAL,
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ .gpio = 0x00,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_GO_007_FM] = {
+ .name = "Avermedia AVerTV GO 007 FM",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00300003,
+ /* .gpiomask = 0x8c240003, */
.inputs = {{
.name = name_tv,
.vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x01,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ .gpio = 0x02,
+ },{
+ .name = name_svideo,
+ .vmux = 6,
.amux = LINE2,
+ .gpio = 0x02,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ .gpio = 0x00300001,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_CARDBUS] = {
+ /* Kees.Blom@cwi.nl */
+ .name = "AVerMedia Cardbus TV/Radio (E500)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
.tv = 1,
},{
.name = name_comp1,
@@ -1340,10 +1552,10 @@ struct saa7134_board saa7134_boards[] = {
},{
.name = name_svideo,
.vmux = 8,
- .amux = LINE2,
+ .amux = LINE1,
}},
.radio = {
- .name = name_radio,
+ .name = name_radio,
.amux = LINE1,
},
},
@@ -1351,119 +1563,134 @@ struct saa7134_board saa7134_boards[] = {
.name = "Terratec Cinergy 400 mobile",
.audio_clock = 0x187de7,
.tuner_type = TUNER_ALPS_TSBE5_PAL,
- .tda9887_conf = TDA9887_PRESENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
.inputs = {{
- .name = name_tv,
+ .name = name_tv,
.vmux = 1,
.amux = TV,
.tv = 1,
- },{
+ },{
.name = name_tv_mono,
.vmux = 1,
.amux = LINE2,
.tv = 1,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
}},
},
[SAA7134_BOARD_CINERGY600_MK3] = {
- .name = "Terratec Cinergy 600 TV MK3",
- .audio_clock = 0x00200000,
+ .name = "Terratec Cinergy 600 TV MK3",
+ .audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
- .tda9887_conf = TDA9887_PRESENT,
- .inputs = {{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 4,
- .amux = LINE1,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE1,
- },{
- .name = name_comp2, // CVideo over SVideo Connector
- .vmux = 0,
- .amux = LINE1,
- }},
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 4,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ },{
+ .name = name_comp2, /* CVideo over SVideo Connector */
+ .vmux = 0,
+ .amux = LINE1,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
+ /* Dylan Walkden <dylan_walkden@hotmail.com> */
+ .name = "Compro VideoMate Gold+ Pal",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x1ce780,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 0, /* CVideo over SVideo Connector - ok? */
+ .amux = LINE1,
+ .gpio = 0x008080,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x008080,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x008080,
+ }},
.radio = {
.name = name_radio,
.amux = LINE2,
- },
- },
- [SAA7134_BOARD_VIDEOMATE_GOLD_PLUS] = {
- /* Dylan Walkden <dylan_walkden@hotmail.com> */
- .name = "Compro VideoMate Gold+ Pal",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_PHILIPS_PAL,
- .gpiomask = 0x1ce780,
- .inputs = {{
- .name = name_svideo,
- .vmux = 0, // CVideo over SVideo Connector - ok?
- .amux = LINE1,
- .gpio = 0x008080,
- },{
- .name = name_comp1,
- .vmux = 3,
- .amux = LINE1,
- .gpio = 0x008080,
- },{
- .name = name_tv,
- .vmux = 1,
- .amux = TV,
- .tv = 1,
- .gpio = 0x008080,
- }},
- .radio = {
- .name = name_radio,
- .amux = LINE2,
- .gpio = 0x80000,
- },
- .mute = {
- .name = name_mute,
- .amux = LINE2,
- .gpio = 0x0c8000,
- },
- },
+ .gpio = 0x80000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x0c8000,
+ },
+ },
[SAA7134_BOARD_PINNACLE_300I_DVBT_PAL] = {
- .name = "Pinnacle PCTV 300i DVB-T + PAL",
- .audio_clock = 0x00187de7,
- .tuner_type = TUNER_MT2032,
- .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
+ .name = "Pinnacle PCTV 300i DVB-T + PAL",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_MT2032,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_INTERCARRIER,
.mpeg = SAA7134_MPEG_DVB,
- .inputs = {{
- .name = name_tv,
- .vmux = 3,
- .amux = TV,
- .tv = 1,
- },{
- .name = name_comp1,
- .vmux = 0,
- .amux = LINE2,
- },{
- .name = name_comp2,
- .vmux = 1,
- .amux = LINE2,
- },{
- .name = name_svideo,
- .vmux = 8,
- .amux = LINE2,
- }},
- },
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2,
+ .vmux = 1,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
[SAA7134_BOARD_PROVIDEO_PV952] = {
/* andreas.kretschmer@web.de */
.name = "ProVideo PV952",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
.inputs = {{
.name = name_comp1,
@@ -1487,12 +1714,14 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_AVERMEDIA_305] = {
/* much like the "studio" version but without radio
- * and another tuner (sirspiritus@yandex.ru) */
+ * and another tuner (sirspiritus@yandex.ru) */
.name = "AverMedia AverTV/305",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0x3,
.inputs = {{
.name = name_tv,
.vmux = 1,
@@ -1512,41 +1741,269 @@ struct saa7134_board saa7134_boards[] = {
.amux = LINE2,
}},
.mute = {
- .name = name_mute,
- .amux = LINE1,
+ .name = name_mute,
+ .amux = LINE1,
},
},
[SAA7134_BOARD_FLYDVBTDUO] = {
/* LifeView FlyDVB-T DUO */
- /* "Nico Sabbi <nsabbi@tiscali.it> */
+ /* "Nico Sabbi <nsabbi@tiscali.it> Hartmut Hackmann hartmut.hackmann@t-online.de*/
.name = "LifeView FlyDVB-T DUO",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_TDA8290,
-// .gpiomask = 0xe000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1, /* Composite signal on S-Video input */
+ .vmux = 0,
+ .amux = LINE2,
+ },{
+ .name = name_comp2, /* Composite input */
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo, /* S-Video signal on S-Video input */
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_PHILIPS_TOUGH] = {
+ .name = "Philips TOUGH DVB-T reference design",
+ .tuner_type = TUNER_ABSENT,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_AVERMEDIA_307] = {
+ /*
+ Davydov Vladimir <vladimir@iqmedia.com>
+ */
+ .name = "Avermedia AVerTV 307",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_FQ1216ME,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ },{
+ .name = name_comp2,
+ .vmux = 3,
+ .amux = LINE1,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ }},
+ },
+ [SAA7134_BOARD_ADS_INSTANT_TV] = {
+ .name = "ADS Tech Instant TV (saa7135)",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ },{
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ }},
+ },
+ [SAA7134_BOARD_KWORLD_VSTREAM_XPERT] = {
+ .name = "Kworld/Tevion V-Stream Xpert TV PVR7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_PAL_I,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x0700,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x000,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200, /* gpio by DScaler */
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x000,
+ },
+ },
+ [SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS] = {
+ .name = "Typhoon DVB-T Duo Digital/Analog Cardbus",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ /* .gpiomask = 0xe000, */
.inputs = {{
.name = name_tv,
.vmux = 1,
.amux = TV,
-// .gpio = 0x0000,
+ /* .gpio = 0x0000, */
.tv = 1,
- },{
+ },{
.name = name_comp1, /* Composite signal on S-Video input */
.vmux = 0,
.amux = LINE2,
-// .gpio = 0x4000,
+ /* .gpio = 0x4000, */
},{
.name = name_comp2, /* Composite input */
.vmux = 3,
.amux = LINE2,
-// .gpio = 0x4000,
+ /* .gpio = 0x4000, */
},{
.name = name_svideo, /* S-Video signal on S-Video input */
.vmux = 8,
.amux = LINE2,
-// .gpio = 0x4000,
+ /* .gpio = 0x4000, */
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE2,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII] = {
+ .name = "Compro VideoMate TV Gold+II",
+ .audio_clock = 0x002187de7,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x63,
+ .radio_addr = 0x60,
+ .gpiomask = 0x8c1880,
+ .inputs = {{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x800800,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x801000,
+ },{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x800000,
+ }},
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x880000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = LINE2,
+ .gpio = 0x840000,
+ },
+ },
+ [SAA7134_BOARD_KWORLD_XPERT] = {
+ /*
+ FIXME:
+ - Remote control doesn't initialize properly.
+ - Audio volume starts muted,
+ then gradually increases after channel change.
+ - Overlay scaling problems (application error?)
+ - Composite S-Video untested.
+ From: Konrad Rzepecki <hannibal@megapolis.pl>
+ */
+ .name = "Kworld Xpert TV PVR7134",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_TENA_9533_DI,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0x61,
+ .radio_addr = 0x60,
+ .gpiomask = 0x0700,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ .gpio = 0x000,
+ },{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200, /* gpio by DScaler */
+ },{
+ .name = name_svideo,
+ .vmux = 0,
+ .amux = LINE1,
+ .gpio = 0x200,
}},
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x000,
+ },
},
};
+
+
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
/* ------------------------------------------------------------------ */
@@ -1559,13 +2016,13 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0x2001,
.driver_data = SAA7134_BOARD_PROTEUS_PRO,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0x2001,
.driver_data = SAA7134_BOARD_PROTEUS_PRO,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = PCI_VENDOR_ID_PHILIPS,
@@ -1574,70 +2031,70 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x1131,
- .subdevice = 0x4e85,
+ .subvendor = 0x1131,
+ .subdevice = 0x4e85,
.driver_data = SAA7134_BOARD_MONSTERTV,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
- .subdevice = 0x1142,
- .driver_data = SAA7134_BOARD_CINERGY400,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
- .subdevice = 0x1143,
- .driver_data = SAA7134_BOARD_CINERGY600,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x153B,
- .subdevice = 0x1158,
- .driver_data = SAA7134_BOARD_CINERGY600_MK3,
- },{
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153B,
+ .subdevice = 0x1142,
+ .driver_data = SAA7134_BOARD_CINERGY400,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153B,
+ .subdevice = 0x1143,
+ .driver_data = SAA7134_BOARD_CINERGY600,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x153B,
+ .subdevice = 0x1158,
+ .driver_data = SAA7134_BOARD_CINERGY600_MK3,
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x153b,
.subdevice = 0x1162,
.driver_data = SAA7134_BOARD_CINERGY400_CARDBUS,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x5168,
.subdevice = 0x0138,
.driver_data = SAA7134_BOARD_FLYVIDEO3000,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x4e42, //"Typhoon PCI Capture TV Card" Art.No. 50673
- .subdevice = 0x0138,
- .driver_data = SAA7134_BOARD_FLYVIDEO3000,
- },{
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x4e42, /* "Typhoon PCI Capture TV Card" Art.No. 50673 */
+ .subdevice = 0x0138,
+ .driver_data = SAA7134_BOARD_FLYVIDEO3000,
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x5168,
.subdevice = 0x0138,
.driver_data = SAA7134_BOARD_FLYVIDEO2000,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7135,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5168,
.subdevice = 0x0212, /* minipci, LR212 */
.driver_data = SAA7134_BOARD_FLYTVPLATINUM_MINI,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5168, /* Animation Technologies (LifeView) */
.subdevice = 0x0214, /* Standard PCI, LR214WF */
.driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x1489, /* KYE */
.subdevice = 0x0214, /* Genius VideoWonder ProTV */
.driver_data = SAA7134_BOARD_FLYTVPLATINUM_FM, /* is an LR214WF actually */
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x16be,
@@ -1656,36 +2113,36 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x226b,
.driver_data = SAA7134_BOARD_ELSA_500TV,
},{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = PCI_VENDOR_ID_ASUSTEK,
- .subdevice = 0x4842,
- .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4842,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
},{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = PCI_VENDOR_ID_ASUSTEK,
- .subdevice = 0x4845,
- .driver_data = SAA7135_BOARD_ASUSTeK_TVFM7135,
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4845,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7135,
},{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = PCI_VENDOR_ID_ASUSTEK,
- .subdevice = 0x4830,
- .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = PCI_VENDOR_ID_ASUSTEK,
- .subdevice = 0x4843,
- .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133,
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4830,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4843,
+ .driver_data = SAA7134_BOARD_ASUSTEK_TVFM7133,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_ASUSTEK,
+ .subdevice = 0x4840,
+ .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
},{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = PCI_VENDOR_ID_ASUSTEK,
- .subdevice = 0x4840,
- .driver_data = SAA7134_BOARD_ASUSTeK_TVFM7134,
- },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = PCI_VENDOR_ID_PHILIPS,
@@ -1706,124 +2163,130 @@ struct pci_device_id saa7134_pci_tbl[] = {
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x1131,
- .subdevice = 0x7133,
+ .subvendor = 0x1131,
+ .subdevice = 0x7133,
.driver_data = SAA7134_BOARD_VA1000POWER,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = PCI_VENDOR_ID_PHILIPS,
- .subdevice = 0x2001,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2001,
.driver_data = SAA7134_BOARD_10MOONSTVMASTER,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x185b,
- .subdevice = 0xc100,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
.driver_data = SAA7134_BOARD_VIDEOMATE_TV,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x185b,
- .subdevice = 0xc100,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
.driver_data = SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUS,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = PCI_VENDOR_ID_MATROX,
- .subdevice = 0x48d0,
+ .subvendor = PCI_VENDOR_ID_MATROX,
+ .subdevice = 0x48d0,
.driver_data = SAA7134_BOARD_CRONOS_PLUS,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0xa70b,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa70b,
.driver_data = SAA7134_BOARD_MD2819,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0x2115,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2115,
.driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_305,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0x2108,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x2108,
.driver_data = SAA7134_BOARD_AVERMEDIA_305,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0x10ff,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x10ff,
.driver_data = SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER,
- },{
+ },{
/* AVerMedia CardBus */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0xd6ee,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xd6ee,
.driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS,
},{
/* TransGear 3000TV */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x1461, /* Avermedia Technologies Inc */
- .subdevice = 0x050c,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x050c,
.driver_data = SAA7134_BOARD_TG3000TV,
},{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x11bd,
- .subdevice = 0x002b,
- .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x11bd,
- .subdevice = 0x002d,
- .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = 0x1019,
- .subdevice = 0x4cb4,
- .driver_data = SAA7134_BOARD_ECS_TVP3XP,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x1019,
- .subdevice = 0x4cb5,
- .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5,
- },{
.vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x12ab,
- .subdevice = 0x0800,
- .driver_data = SAA7133_BOARD_UPMOST_PURPLE_TV,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002b,
+ .driver_data = SAA7134_BOARD_PINNACLE_PCTV_STEREO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x11bd,
+ .subdevice = 0x002d,
+ .driver_data = SAA7134_BOARD_PINNACLE_300I_DVBT_PAL,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1019,
+ .subdevice = 0x4cb4,
+ .driver_data = SAA7134_BOARD_ECS_TVP3XP,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1019,
+ .subdevice = 0x4cb5,
+ .driver_data = SAA7134_BOARD_ECS_TVP3XP_4CB5,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x12ab,
+ .subdevice = 0x0800,
+ .driver_data = SAA7134_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,
+ .subvendor = 0x185b,
+ .subdevice = 0xc100,
.driver_data = SAA7134_BOARD_VIDEOMATE_TV_PVR,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = 0x1131,
- .subdevice = 0,
+ .subvendor = 0x1131,
+ .subdevice = 0,
.driver_data = SAA7134_BOARD_SABRENT_SBTTVFM,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0x9715,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_STUDIO_307,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa70a,
.driver_data = SAA7134_BOARD_AVERMEDIA_307,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
@@ -1831,31 +2294,70 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x185b,
.subdevice = 0xc200,
.driver_data = SAA7134_BOARD_VIDEOMATE_GOLD_PLUS,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
.subvendor = 0x1540,
.subdevice = 0x9524,
.driver_data = SAA7134_BOARD_PROVIDEO_PV952,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
.subvendor = 0x5168,
- .subdevice = 0x0306,
+ .subdevice = 0x0502, /* Cardbus version */
.driver_data = SAA7134_BOARD_FLYDVBTDUO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5168,
+ .subdevice = 0x0306, /* PCI version */
+ .driver_data = SAA7134_BOARD_FLYDVBTDUO,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf31f,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_GO_007_FM,
+
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_PHILIPS_TOUGH,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x0350, /* PCI version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
- },{
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1421,
+ .subdevice = 0x0370, /* cardbus version */
+ .driver_data = SAA7134_BOARD_ADS_INSTANT_TV,
+
+ },{ /* Typhoon DVB-T Duo Digital/Analog Cardbus */
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x4e42,
+ .subdevice = 0x0502,
+ .driver_data = SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS,
+
+ },{
/* --- boards without eeprom + subsystem ID --- */
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7134,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0,
.driver_data = SAA7134_BOARD_NOAUTO,
- },{
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = PCI_VENDOR_ID_PHILIPS,
+ },{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7130,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0,
.driver_data = SAA7134_BOARD_NOAUTO,
},{
@@ -1863,26 +2365,26 @@ struct pci_device_id saa7134_pci_tbl[] = {
/* --- default catch --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
- },{
+ },{
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7135,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
},{
/* --- end of list --- */
@@ -1893,46 +2395,9 @@ MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl);
/* ----------------------------------------------------------- */
/* flyvideo tweaks */
-#if 0
-static struct {
- char *model;
- int tuner_type;
-} fly_list[0x20] = {
- /* default catch ... */
- [ 0 ... 0x1f ] = {
- .model = "UNKNOWN",
- .tuner_type = TUNER_ABSENT,
- },
- /* ... the ones known so far */
- [ 0x05 ] = {
- .model = "PAL-BG",
- .tuner_type = TUNER_LG_PAL_NEW_TAPC,
- },
- [ 0x10 ] = {
- .model = "PAL-BG / PAL-DK",
- .tuner_type = TUNER_PHILIPS_PAL,
- },
- [ 0x15 ] = {
- .model = "NTSC",
- .tuner_type = TUNER_ABSENT /* FIXME */,
- },
-};
-#endif
static void board_flyvideo(struct saa7134_dev *dev)
{
-#if 0
- /* non-working attempt to detect the correct tuner type ... */
- u32 value;
- int index;
-
- value = dev->gpio_value;
- index = (value & 0x1f00) >> 8;
- printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n",
- dev->name, value, fly_list[index].model,
- 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=<nr> insmod\n"
"%s: option to override the default value.\n",
@@ -1943,7 +2408,7 @@ static void board_flyvideo(struct saa7134_dev *dev)
int saa7134_board_init1(struct saa7134_dev *dev)
{
- // Always print gpio, often manufacturers encode tuner type and other info.
+ /* Always print gpio, often manufacturers encode tuner type and other info. */
saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0);
dev->gpio_value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
printk(KERN_INFO "%s: board init: gpio is %x\n", dev->name, dev->gpio_value);
@@ -1961,21 +2426,26 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_ECS_TVP3XP:
case SAA7134_BOARD_ECS_TVP3XP_4CB5:
case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
+ case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
case SAA7134_BOARD_AVERMEDIA_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
case SAA7134_BOARD_AVERMEDIA_307:
-// case SAA7134_BOARD_SABRENT_SBTTVFM: /* not finished yet */
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
+/* case SAA7134_BOARD_SABRENT_SBTTVFM: */ /* not finished yet */
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
- dev->has_remote = 1;
- break;
+ case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_MANLI_MTV001:
+ case SAA7134_BOARD_MANLI_MTV002:
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);
+ "%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;
case SAA7134_BOARD_CINERGY400_CARDBUS:
/* power-up tuner chip */
@@ -1983,11 +2453,19 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x00040000, 0x00000000);
msleep(1);
break;
+ case SAA7134_BOARD_FLYDVBTDUO:
+ case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
+ /* turn the fan on Hac: static for the time being */
+ saa_writeb(SAA7134_GPIO_GPMODE3, 0x08);
+ saa_writeb(SAA7134_GPIO_GPSTATUS3, 0x06);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
+ msleep(1);
+ break;
}
- if (dev->has_remote)
- dev->irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
- SAA7134_IRQ2_INTE_GPIO18A |
- SAA7134_IRQ2_INTE_GPIO16 );
return 0;
}
@@ -2008,10 +2486,85 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
dev->board = board;
printk("%s: board type fixup: %s\n", dev->name,
- saa7134_boards[dev->board].name);
+ saa7134_boards[dev->board].name);
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
- if (TUNER_ABSENT != dev->tuner_type)
- saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&dev->tuner_type);
+
+ if (TUNER_ABSENT != dev->tuner_type) {
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = ADDR_UNSET;
+
+ saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ break;
+case SAA7134_BOARD_MD7134:
+ {
+ struct tuner_setup tun_setup;
+ u8 subaddr;
+ u8 data[3];
+ int ret, tuner_t;
+
+ struct i2c_msg msg[] = {{.addr=0x50, .flags=0, .buf=&subaddr, .len = 1},
+ {.addr=0x50, .flags=I2C_M_RD, .buf=data, .len = 3}};
+ subaddr= 0x14;
+ tuner_t = 0;
+ ret = i2c_transfer(&dev->i2c_adap, msg, 2);
+ if (ret != 2) {
+ printk(KERN_ERR "EEPROM read failure\n");
+ } else if ((data[0] != 0) && (data[0] != 0xff)) {
+ /* old config structure */
+ subaddr = data[0] + 2;
+ msg[1].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ tuner_t = (data[0] << 8) + data[1];
+ switch (tuner_t){
+ case 0x0103:
+ dev->tuner_type = TUNER_PHILIPS_PAL;
+ break;
+ case 0x010C:
+ dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+ break;
+ default:
+ printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+ }
+ } else if ((data[1] != 0) && (data[1] != 0xff)) {
+ /* new config structure */
+ subaddr = data[1] + 1;
+ msg[1].len = 1;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ subaddr = data[0] + 1;
+ msg[1].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 2);
+ tuner_t = (data[1] << 8) + data[0];
+ switch (tuner_t) {
+ case 0x0005:
+ dev->tuner_type = TUNER_PHILIPS_FM1216ME_MK3;
+ break;
+ case 0x001d:
+ dev->tuner_type = TUNER_PHILIPS_FMD1216ME_MK3;
+ printk(KERN_INFO "%s Board has DVB-T\n", dev->name);
+ break;
+ default:
+ printk(KERN_ERR "%s Cant determine tuner type %x from EEPROM\n", dev->name, tuner_t);
+ }
+ } else {
+ printk(KERN_ERR "%s unexpected config structure\n", dev->name);
+ }
+
+ printk(KERN_INFO "%s Tuner type is %d\n", dev->name, dev->tuner_type);
+ if (dev->tuner_type == TUNER_PHILIPS_FMD1216ME_MK3) {
+ dev->tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE | TDA9887_PORT2_ACTIVE;
+ saa7134_i2c_call_clients(dev,TDA9887_SET_CONFIG, &dev->tda9887_conf);
+ }
+
+ tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = ADDR_UNSET;
+
+ saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+ }
break;
}
return 0;
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index d506cafba8ff..1dbe61755e9f 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-core.c,v 1.28 2005/02/22 09:56:29 kraxel Exp $
+ * $Id: saa7134-core.c,v 1.39 2005/07/05 17:37:35 nsh Exp $
*
* device driver for philips saa7134 based TV cards
* driver core
@@ -183,46 +183,6 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg)
/* ------------------------------------------------------------------ */
-#if 0
-static char *dec1_bits[8] = {
- "DCSTD0", "DCSCT1", "WIPA", "GLIMB",
- "GLIMT", "SLTCA", "HLCK"
-};
-static char *dec2_bits[8] = {
- "RDCAP", "COPRO", "COLSTR", "TYPE3",
- NULL, "FIDT", "HLVLN", "INTL"
-};
-static char *scale1_bits[8] = {
- "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B"
-};
-static char *scale2_bits[8] = {
- "TRERR", "CFERR", "LDERR", "WASRST",
- "FIDSCI", "FIDSCO", "D6^D5", "TASK"
-};
-
-static void dump_statusreg(struct saa7134_dev *dev, int reg,
- char *regname, char **bits)
-{
- int value,i;
-
- value = saa_readb(reg);
- printk(KERN_DEBUG "%s: %s:", dev->name, regname);
- for (i = 7; i >= 0; i--) {
- if (NULL == bits[i])
- continue;
- printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0);
- }
- printk("\n");
-}
-
-static void dump_statusregs(struct saa7134_dev *dev)
-{
- dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits);
- dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits);
- dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits);
- dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits);
-}
-#endif
/* ----------------------------------------------------------- */
/* delayed request_module */
@@ -316,7 +276,7 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf)
int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt)
{
- u32 *cpu;
+ __le32 *cpu;
dma_addr_t dma_addr;
cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr);
@@ -332,7 +292,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
struct scatterlist *list, unsigned int length,
unsigned int startpage)
{
- u32 *ptr;
+ __le32 *ptr;
unsigned int i,p;
BUG_ON(NULL == pt || NULL == pt->cpu);
@@ -340,7 +300,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
ptr = pt->cpu + startpage;
for (i = 0; i < length; i++, list++)
for (p = 0; p * 4096 < list->length; p++, ptr++)
- *ptr = sg_dma_address(list) - list->offset;
+ *ptr = cpu_to_le32(sg_dma_address(list) - list->offset);
return 0;
}
@@ -616,10 +576,6 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs)
if (irq_debug)
print_irqstatus(dev,loop,report,status);
-#if 0
- if (report & SAA7134_IRQ_REPORT_CONF_ERR)
- dump_statusregs(dev);
-#endif
if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */)
saa7134_irq_video_intl(dev);
@@ -711,7 +667,6 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
SAA7134_MAIN_CTRL_EVFE1 |
SAA7134_MAIN_CTRL_EVFE2 |
SAA7134_MAIN_CTRL_ESFE |
- SAA7134_MAIN_CTRL_EBADC |
SAA7134_MAIN_CTRL_EBDAC);
/* enable peripheral devices */
@@ -726,14 +681,28 @@ static int saa7134_hwinit1(struct saa7134_dev *dev)
/* late init (with i2c + irq) */
static int saa7134_hwinit2(struct saa7134_dev *dev)
{
+ unsigned int irq2_mask;
dprintk("hwinit2\n");
saa7134_video_init2(dev);
saa7134_tvaudio_init2(dev);
/* enable IRQ's */
+ irq2_mask =
+ SAA7134_IRQ2_INTE_DEC3 |
+ SAA7134_IRQ2_INTE_DEC2 |
+ SAA7134_IRQ2_INTE_DEC1 |
+ SAA7134_IRQ2_INTE_DEC0 |
+ SAA7134_IRQ2_INTE_PE |
+ SAA7134_IRQ2_INTE_AR;
+
+ if (dev->has_remote)
+ irq2_mask |= (SAA7134_IRQ2_INTE_GPIO18 |
+ SAA7134_IRQ2_INTE_GPIO18A |
+ SAA7134_IRQ2_INTE_GPIO16 );
+
saa_writel(SAA7134_IRQ1, 0);
- saa_writel(SAA7134_IRQ2, dev->irq2_mask);
+ saa_writel(SAA7134_IRQ2, irq2_mask);
return 0;
}
@@ -954,13 +923,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
}
/* initialize hardware #1 */
- dev->irq2_mask =
- SAA7134_IRQ2_INTE_DEC3 |
- SAA7134_IRQ2_INTE_DEC2 |
- SAA7134_IRQ2_INTE_DEC1 |
- SAA7134_IRQ2_INTE_DEC0 |
- SAA7134_IRQ2_INTE_PE |
- SAA7134_IRQ2_INTE_AR;
saa7134_board_init1(dev);
saa7134_hwinit1(dev);
@@ -990,6 +952,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
request_module("saa6752hs");
request_module_depend("saa7134-empress",&need_empress);
}
+
if (card_is_dvb(dev))
request_module_depend("saa7134-dvb",&need_dvb);
@@ -1144,9 +1107,6 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
release_mem_region(pci_resource_start(pci_dev,0),
pci_resource_len(pci_dev,0));
-#if 0 /* causes some trouble when reinserting the driver ... */
- pci_disable_device(pci_dev);
-#endif
pci_set_drvdata(pci_dev, NULL);
/* free memory */
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index c2873ae029f9..334bc1850092 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1,8 +1,11 @@
/*
- * $Id: saa7134-dvb.c,v 1.12 2005/02/18 12:28:29 kraxel Exp $
+ * $Id: saa7134-dvb.c,v 1.18 2005/07/04 16:05:50 mkrufky Exp $
*
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
+ * Extended 3 / 2005 by Hartmut Hackmann to support various
+ * cards with the tda10046 DVB-T channel decoder
+ *
* 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
@@ -27,23 +30,31 @@
#include <linux/kthread.h>
#include <linux/suspend.h>
+#define CONFIG_DVB_MT352 1
+#define CONFIG_DVB_TDA1004X 1
+
#include "saa7134-reg.h"
#include "saa7134.h"
-#include "dvb-pll.h"
-#include "mt352.h"
-#include "mt352_priv.h" /* FIXME */
-#include "tda1004x.h"
+#if CONFIG_DVB_MT352
+# include "mt352.h"
+# include "mt352_priv.h" /* FIXME */
+#endif
+#if CONFIG_DVB_TDA1004X
+# include "tda1004x.h"
+#endif
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
static unsigned int antenna_pwr = 0;
+
module_param(antenna_pwr, int, 0444);
MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
/* ------------------------------------------------------------------ */
+#if CONFIG_DVB_MT352
static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
{
u32 ok;
@@ -138,51 +149,390 @@ static struct mt352_config pinnacle_300i = {
.demod_init = mt352_pinnacle_init,
.pll_set = mt352_pinnacle_pll_set,
};
+#endif
/* ------------------------------------------------------------------ */
-static int medion_cardbus_init(struct dvb_frontend* fe)
+#if CONFIG_DVB_TDA1004X
+static int philips_tu1216_pll_init(struct dvb_frontend *fe)
{
- /* anything to do here ??? */
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab };
+ struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) };
+
+ /* setup PLL configuration */
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
return 0;
}
-static int medion_cardbus_pll_set(struct dvb_frontend* fe,
- struct dvb_frontend_parameters* params)
+static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
{
struct saa7134_dev *dev = fe->dvb->priv;
- struct v4l2_frequency f;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,.len =
+ sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ u8 band, cp, filter;
+
+ /* determine charge pump */
+ tuner_frequency = params->frequency + 36166000;
+ if (tuner_frequency < 87000000)
+ return -EINVAL;
+ else if (tuner_frequency < 130000000)
+ cp = 3;
+ else if (tuner_frequency < 160000000)
+ cp = 5;
+ else if (tuner_frequency < 200000000)
+ cp = 6;
+ else if (tuner_frequency < 290000000)
+ cp = 3;
+ else if (tuner_frequency < 420000000)
+ cp = 5;
+ else if (tuner_frequency < 480000000)
+ cp = 6;
+ else if (tuner_frequency < 620000000)
+ cp = 3;
+ else if (tuner_frequency < 830000000)
+ cp = 5;
+ else if (tuner_frequency < 895000000)
+ cp = 7;
+ else
+ return -EINVAL;
+
+ /* determine band */
+ if (params->frequency < 49000000)
+ return -EINVAL;
+ else if (params->frequency < 161000000)
+ band = 1;
+ else if (params->frequency < 444000000)
+ band = 2;
+ else if (params->frequency < 861000000)
+ band = 4;
+ else
+ return -EINVAL;
+
+ /* setup PLL filter */
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ filter = 0;
+ break;
- /*
- * this instructs tuner.o to set the frequency, the call will
- * end up in tuner_command(), VIDIOC_S_FREQUENCY switch.
- * tda9887.o will see that as well.
+ case BANDWIDTH_7_MHZ:
+ filter = 0;
+ break;
+
+ case BANDWIDTH_8_MHZ:
+ filter = 1;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ /* calculate divisor
+ * ((36166000+((1000000/6)/2)) + Finput)/(1000000/6)
*/
- f.tuner = 0;
- f.type = V4L2_TUNER_DIGITAL_TV;
- f.frequency = params->frequency / 1000 * 16 / 1000;
- saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,&f);
+ tuner_frequency = (((params->frequency / 1000) * 6) + 217496) / 1000;
+
+ /* setup tuner buffer */
+ tuner_buf[0] = (tuner_frequency >> 8) & 0x7f;
+ tuner_buf[1] = tuner_frequency & 0xff;
+ tuner_buf[2] = 0xca;
+ tuner_buf[3] = (cp << 5) | (filter << 3) | band;
+
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+
+ msleep(1);
return 0;
}
-static int fe_request_firmware(struct dvb_frontend* fe,
- const struct firmware **fw, char* name)
+static int philips_tu1216_request_firmware(struct dvb_frontend *fe,
+ const struct firmware **fw, char *name)
{
struct saa7134_dev *dev = fe->dvb->priv;
return request_firmware(fw, name, &dev->pci->dev);
}
+static struct tda1004x_config philips_tu1216_config = {
+
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 1,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .pll_init = philips_tu1216_pll_init,
+ .pll_set = philips_tu1216_pll_set,
+ .pll_sleep = NULL,
+ .request_firmware = philips_tu1216_request_firmware,
+};
+
+/* ------------------------------------------------------------------ */
+
+
+static int philips_fmd1216_pll_init(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* this message is to set up ATC and ALC */
+ static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0xa0 };
+ struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+ msleep(1);
+
+ return 0;
+}
+
+static void philips_fmd1216_analog(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ /* this message actually turns the tuner back to analog mode */
+ static u8 fmd1216_init[] = { 0x0b, 0xdc, 0x9c, 0x60 };
+ struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = fmd1216_init,.len = sizeof(fmd1216_init) };
+
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ msleep(1);
+ fmd1216_init[2] = 0x86;
+ fmd1216_init[3] = 0x54;
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+ msleep(1);
+}
+
+static int philips_fmd1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 tuner_buf[4];
+ struct i2c_msg tuner_msg = {.addr = 0x61,.flags = 0,.buf = tuner_buf,.len =
+ sizeof(tuner_buf) };
+ int tuner_frequency = 0;
+ int divider = 0;
+ u8 band, mode, cp;
+
+ /* determine charge pump */
+ tuner_frequency = params->frequency + 36130000;
+ if (tuner_frequency < 87000000)
+ return -EINVAL;
+ /* low band */
+ else if (tuner_frequency < 180000000) {
+ band = 1;
+ mode = 7;
+ cp = 0;
+ } else if (tuner_frequency < 195000000) {
+ band = 1;
+ mode = 6;
+ cp = 1;
+ /* mid band */
+ } else if (tuner_frequency < 366000000) {
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ band = 10;
+ } else {
+ band = 2;
+ }
+ mode = 7;
+ cp = 0;
+ } else if (tuner_frequency < 478000000) {
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ band = 10;
+ } else {
+ band = 2;
+ }
+ mode = 6;
+ cp = 1;
+ /* high band */
+ } else if (tuner_frequency < 662000000) {
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ band = 12;
+ } else {
+ band = 4;
+ }
+ mode = 7;
+ cp = 0;
+ } else if (tuner_frequency < 840000000) {
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ band = 12;
+ } else {
+ band = 4;
+ }
+ mode = 6;
+ cp = 1;
+ } else {
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) {
+ band = 12;
+ } else {
+ band = 4;
+ }
+ mode = 7;
+ cp = 1;
+
+ }
+ /* calculate divisor */
+ /* ((36166000 + Finput) / 166666) rounded! */
+ divider = (tuner_frequency + 83333) / 166667;
+
+ /* setup tuner buffer */
+ tuner_buf[0] = (divider >> 8) & 0x7f;
+ tuner_buf[1] = divider & 0xff;
+ tuner_buf[2] = 0x80 | (cp << 6) | (mode << 3) | 4;
+ tuner_buf[3] = 0x40 | band;
+
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+ return 0;
+}
+
+
static struct tda1004x_config medion_cardbus = {
- .demod_address = 0x08, /* not sure this is correct */
- .invert = 0,
- .invert_oclk = 0,
- .pll_init = medion_cardbus_init,
- .pll_set = medion_cardbus_pll_set,
- .request_firmware = fe_request_firmware,
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_IFO_AUTO_NEG,
+ .if_freq = TDA10046_FREQ_3613,
+ .pll_init = philips_fmd1216_pll_init,
+ .pll_set = philips_fmd1216_pll_set,
+ .pll_sleep = philips_fmd1216_analog,
+ .request_firmware = NULL,
};
/* ------------------------------------------------------------------ */
+struct tda827x_data {
+ u32 lomax;
+ u8 spd;
+ u8 bs;
+ u8 bp;
+ u8 cp;
+ u8 gc3;
+ u8 div1p5;
+};
+
+static struct tda827x_data tda827x_dvbt[] = {
+ { .lomax = 62000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+ { .lomax = 66000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 1},
+ { .lomax = 76000000, .spd = 3, .bs = 1, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+ { .lomax = 84000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 3, .div1p5 = 0},
+ { .lomax = 93000000, .spd = 3, .bs = 2, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 98000000, .spd = 3, .bs = 3, .bp = 0, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 109000000, .spd = 3, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 123000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 133000000, .spd = 2, .bs = 3, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 151000000, .spd = 2, .bs = 1, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 154000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 181000000, .spd = 2, .bs = 2, .bp = 1, .cp = 0, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 185000000, .spd = 2, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 217000000, .spd = 2, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 244000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 265000000, .spd = 1, .bs = 3, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 302000000, .spd = 1, .bs = 1, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 324000000, .spd = 1, .bs = 2, .bp = 2, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 370000000, .spd = 1, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 454000000, .spd = 1, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 493000000, .spd = 0, .bs = 2, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 530000000, .spd = 0, .bs = 3, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 1},
+ { .lomax = 554000000, .spd = 0, .bs = 1, .bp = 3, .cp = 0, .gc3 = 1, .div1p5 = 0},
+ { .lomax = 604000000, .spd = 0, .bs = 1, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 696000000, .spd = 0, .bs = 2, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 740000000, .spd = 0, .bs = 2, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 820000000, .spd = 0, .bs = 3, .bp = 4, .cp = 0, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 865000000, .spd = 0, .bs = 3, .bp = 4, .cp = 1, .gc3 = 0, .div1p5 = 0},
+ { .lomax = 0, .spd = 0, .bs = 0, .bp = 0, .cp = 0, .gc3 = 0, .div1p5 = 0}
+};
+
+static int philips_tda827x_pll_init(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int philips_tda827x_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 tuner_buf[14];
+
+ struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tuner_buf,
+ .len = sizeof(tuner_buf) };
+ int i, tuner_freq, if_freq;
+ u32 N;
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ if_freq = 4000000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_freq = 4500000;
+ break;
+ default: /* 8 MHz or Auto */
+ if_freq = 5000000;
+ break;
+ }
+ tuner_freq = params->frequency + if_freq;
+
+ i = 0;
+ while (tda827x_dvbt[i].lomax < tuner_freq) {
+ if(tda827x_dvbt[i + 1].lomax == 0)
+ break;
+ i++;
+ }
+
+ N = ((tuner_freq + 125000) / 250000) << (tda827x_dvbt[i].spd + 2);
+ tuner_buf[0] = 0;
+ tuner_buf[1] = (N>>8) | 0x40;
+ tuner_buf[2] = N & 0xff;
+ tuner_buf[3] = 0;
+ tuner_buf[4] = 0x52;
+ tuner_buf[5] = (tda827x_dvbt[i].spd << 6) + (tda827x_dvbt[i].div1p5 << 5) +
+ (tda827x_dvbt[i].bs << 3) + tda827x_dvbt[i].bp;
+ tuner_buf[6] = (tda827x_dvbt[i].gc3 << 4) + 0x8f;
+ tuner_buf[7] = 0xbf;
+ tuner_buf[8] = 0x2a;
+ tuner_buf[9] = 0x05;
+ tuner_buf[10] = 0xff;
+ tuner_buf[11] = 0x00;
+ tuner_buf[12] = 0x00;
+ tuner_buf[13] = 0x40;
+
+ tuner_msg.len = 14;
+ if (i2c_transfer(&dev->i2c_adap, &tuner_msg, 1) != 1)
+ return -EIO;
+
+ msleep(500);
+ /* correct CP value */
+ tuner_buf[0] = 0x30;
+ tuner_buf[1] = 0x50 + tda827x_dvbt[i].cp;
+ tuner_msg.len = 2;
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+
+ return 0;
+}
+
+static void philips_tda827x_pll_sleep(struct dvb_frontend *fe)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ static u8 tda827x_sleep[] = { 0x30, 0xd0};
+ struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tda827x_sleep,
+ .len = sizeof(tda827x_sleep) };
+ i2c_transfer(&dev->i2c_adap, &tuner_msg, 1);
+}
+
+static struct tda1004x_config tda827x_lifeview_config = {
+ .demod_address = 0x08,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_16M,
+ .agc_config = TDA10046_AGC_TDA827X,
+ .if_freq = TDA10046_FREQ_045,
+ .pll_init = philips_tda827x_pll_init,
+ .pll_set = philips_tda827x_pll_set,
+ .pll_sleep = philips_tda827x_pll_sleep,
+ .request_firmware = NULL,
+};
+#endif
+
+/* ------------------------------------------------------------------ */
+
static int dvb_init(struct saa7134_dev *dev)
{
/* init struct videobuf_dvb */
@@ -197,18 +547,31 @@ static int dvb_init(struct saa7134_dev *dev)
dev);
switch (dev->board) {
+#if CONFIG_DVB_MT352
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
printk("%s: pinnacle 300i dvb setup\n",dev->name);
dev->dvb.frontend = mt352_attach(&pinnacle_300i,
&dev->i2c_adap);
break;
+#endif
+#if CONFIG_DVB_TDA1004X
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = tda10046_attach(&medion_cardbus,
&dev->i2c_adap);
- if (NULL == dev->dvb.frontend)
- printk("%s: Hmm, looks like this is the old MD7134 "
- "version without DVB-T support\n",dev->name);
break;
+ case SAA7134_BOARD_PHILIPS_TOUGH:
+ dev->dvb.frontend = tda10046_attach(&philips_tu1216_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_FLYDVBTDUO:
+ dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+ &dev->i2c_adap);
+ break;
+ case SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS:
+ dev->dvb.frontend = tda10046_attach(&tda827x_lifeview_config,
+ &dev->i2c_adap);
+ break;
+#endif
default:
printk("%s: Huh? unknown DVB card?\n",dev->name);
break;
@@ -227,8 +590,6 @@ static int dvb_fini(struct saa7134_dev *dev)
{
static int on = TDA9887_PRESENT | TDA9887_PORT2_INACTIVE;
- printk("%s: %s\n",dev->name,__FUNCTION__);
-
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
/* otherwise we don't detect the tuner on next insmod */
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index fa1357336907..c85348d0239f 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-empress.c,v 1.10 2005/02/03 10:24:33 kraxel Exp $
+ * $Id: saa7134-empress.c,v 1.11 2005/05/22 19:23:39 nsh Exp $
*
* (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
*
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index 702bb63d9813..93dd61978541 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-i2c.c,v 1.10 2005/01/24 17:37:23 kraxel Exp $
+ * $Id: saa7134-i2c.c,v 1.19 2005/07/07 01:49:30 mkrufky Exp $
*
* device driver for philips saa7134 based TV cards
* i2c interface support
@@ -197,10 +197,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev,
enum i2c_status status;
__u32 dword;
-#if 0
- i2c_set_attr(dev,attr);
- saa_writeb(SAA7134_I2C_DATA, data);
-#else
/* have to write both attr + data in one 32bit word */
dword = saa_readl(SAA7134_I2C_ATTR_STATUS >> 2);
dword &= 0x0f;
@@ -210,7 +206,6 @@ static inline int i2c_send_byte(struct saa7134_dev *dev,
// dword |= 0x40 << 16; /* 400 kHz */
dword |= 0xf0 << 24;
saa_writel(SAA7134_I2C_ATTR_STATUS >> 2, dword);
-#endif
d2printk(KERN_DEBUG "%s: i2c data => 0x%x\n",dev->name,data);
if (!i2c_is_busy_wait(dev))
@@ -331,12 +326,44 @@ static u32 functionality(struct i2c_adapter *adap)
static int attach_inform(struct i2c_client *client)
{
- struct saa7134_dev *dev = client->adapter->algo_data;
+ struct saa7134_dev *dev = client->adapter->algo_data;
int tuner = dev->tuner_type;
int conf = dev->tda9887_conf;
+ struct tuner_setup tun_setup;
+
+ d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->name,client->addr,i2c_clientname(client));
+
+ if (!client->driver->command)
+ return 0;
+
+ if (saa7134_boards[dev->board].radio_type != UNSET) {
+
+ tun_setup.type = saa7134_boards[dev->board].radio_type;
+ tun_setup.addr = saa7134_boards[dev->board].radio_addr;
+
+ if ((tun_setup.addr == ADDR_UNSET) || (tun_setup.addr == client->addr)) {
+ tun_setup.mode_mask = T_RADIO;
+
+ client->driver->command(client, TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ }
+
+ if (tuner != UNSET) {
+
+ tun_setup.type = tuner;
+ tun_setup.addr = saa7134_boards[dev->board].tuner_addr;
+
+ if ((tun_setup.addr == ADDR_UNSET)||(tun_setup.addr == client->addr)) {
+
+ tun_setup.mode_mask = T_ANALOG_TV;
+
+ client->driver->command(client,TUNER_SET_TYPE_ADDR, &tun_setup);
+ }
+ }
+
+ client->driver->command(client, TDA9887_SET_CONFIG, &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-input.c b/drivers/media/video/saa7134/saa7134-input.c
index ca50cf531f20..213740122fe6 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-input.c,v 1.16 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-input.c,v 1.21 2005/06/22 23:37:34 nsh Exp $
*
* handle saa7134 IR remotes via linux kernel input layer.
*
@@ -68,10 +68,8 @@ static IR_KEYTAB_TYPE flyvideo_codes[IR_KEYTAB_SIZE] = {
[ 6 ] = KEY_AGAIN, // Recal
[ 16 ] = KEY_KPENTER, // Enter
-#if 1 /* FIXME */
[ 26 ] = KEY_F22, // Stereo
[ 24 ] = KEY_EDIT, // AV Source
-#endif
};
static IR_KEYTAB_TYPE cinergy_codes[IR_KEYTAB_SIZE] = {
@@ -172,45 +170,45 @@ static IR_KEYTAB_TYPE eztv_codes[IR_KEYTAB_SIZE] = {
};
static IR_KEYTAB_TYPE avacssmart_codes[IR_KEYTAB_SIZE] = {
- [ 30 ] = KEY_POWER, // power
+ [ 30 ] = KEY_POWER, // power
[ 28 ] = KEY_SEARCH, // scan
- [ 7 ] = KEY_SELECT, // source
+ [ 7 ] = KEY_SELECT, // source
[ 22 ] = KEY_VOLUMEUP,
[ 20 ] = KEY_VOLUMEDOWN,
- [ 31 ] = KEY_CHANNELUP,
+ [ 31 ] = KEY_CHANNELUP,
[ 23 ] = KEY_CHANNELDOWN,
[ 24 ] = KEY_MUTE,
[ 2 ] = KEY_KP0,
- [ 1 ] = KEY_KP1,
- [ 11 ] = KEY_KP2,
- [ 27 ] = KEY_KP3,
- [ 5 ] = KEY_KP4,
- [ 9 ] = KEY_KP5,
- [ 21 ] = KEY_KP6,
+ [ 1 ] = KEY_KP1,
+ [ 11 ] = KEY_KP2,
+ [ 27 ] = KEY_KP3,
+ [ 5 ] = KEY_KP4,
+ [ 9 ] = KEY_KP5,
+ [ 21 ] = KEY_KP6,
[ 6 ] = KEY_KP7,
- [ 10 ] = KEY_KP8,
+ [ 10 ] = KEY_KP8,
[ 18 ] = KEY_KP9,
[ 16 ] = KEY_KPDOT,
[ 3 ] = KEY_TUNER, // tv/fm
- [ 4 ] = KEY_REWIND, // fm tuning left or function left
- [ 12 ] = KEY_FORWARD, // fm tuning right or function right
+ [ 4 ] = KEY_REWIND, // fm tuning left or function left
+ [ 12 ] = KEY_FORWARD, // fm tuning right or function right
[ 0 ] = KEY_RECORD,
- [ 8 ] = KEY_STOP,
- [ 17 ] = KEY_PLAY,
+ [ 8 ] = KEY_STOP,
+ [ 17 ] = KEY_PLAY,
[ 25 ] = KEY_ZOOM,
[ 14 ] = KEY_MENU, // function
[ 19 ] = KEY_AGAIN, // recall
[ 29 ] = KEY_RESTART, // reset
+ [ 26 ] = KEY_SHUFFLE, // snapshot/shuffle
// FIXME
[ 13 ] = KEY_F21, // mts
- [ 15 ] = KEY_F22, // min
- [ 26 ] = KEY_F23, // freeze
+ [ 15 ] = KEY_F22, // min
};
/* Alex Hermann <gaaf@gmx.net> */
@@ -308,6 +306,102 @@ static IR_KEYTAB_TYPE videomate_tv_pvr_codes[IR_KEYTAB_SIZE] = {
[ 32 ] = KEY_LANGUAGE,
[ 33 ] = KEY_SLEEP,
};
+
+/* Michael Tokarev <mjt@tls.msk.ru>
+ http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
+ keytable is used by MANLI MTV00[12] and BeholdTV 40[13] at
+ least, and probably other cards too.
+ The "ascii-art picture" below (in comments, first row
+ is the keycode in hex, and subsequent row(s) shows
+ the button labels (several variants when appropriate)
+ helps to descide which keycodes to assign to the buttons.
+ */
+static IR_KEYTAB_TYPE manli_codes[IR_KEYTAB_SIZE] = {
+
+ /* 0x1c 0x12 *
+ * FUNCTION POWER *
+ * FM (|) *
+ * */
+ [ 0x1c ] = KEY_RADIO, /*XXX*/
+ [ 0x12 ] = KEY_POWER,
+
+ /* 0x01 0x02 0x03 *
+ * 1 2 3 *
+ * *
+ * 0x04 0x05 0x06 *
+ * 4 5 6 *
+ * *
+ * 0x07 0x08 0x09 *
+ * 7 8 9 *
+ * */
+ [ 0x01 ] = KEY_KP1,
+ [ 0x02 ] = KEY_KP2,
+ [ 0x03 ] = KEY_KP3,
+ [ 0x04 ] = KEY_KP4,
+ [ 0x05 ] = KEY_KP5,
+ [ 0x06 ] = KEY_KP6,
+ [ 0x07 ] = KEY_KP7,
+ [ 0x08 ] = KEY_KP8,
+ [ 0x09 ] = KEY_KP9,
+
+ /* 0x0a 0x00 0x17 *
+ * RECALL 0 +100 *
+ * PLUS *
+ * */
+ [ 0x0a ] = KEY_AGAIN, /*XXX KEY_REWIND? */
+ [ 0x00 ] = KEY_KP0,
+ [ 0x17 ] = KEY_DIGITS, /*XXX*/
+
+ /* 0x14 0x10 *
+ * MENU INFO *
+ * OSD */
+ [ 0x14 ] = KEY_MENU,
+ [ 0x10 ] = KEY_INFO,
+
+ /* 0x0b *
+ * Up *
+ * *
+ * 0x18 0x16 0x0c *
+ * Left Ok Right *
+ * *
+ * 0x015 *
+ * Down *
+ * */
+ [ 0x0b ] = KEY_UP, /*XXX KEY_SCROLLUP? */
+ [ 0x18 ] = KEY_LEFT, /*XXX KEY_BACK? */
+ [ 0x16 ] = KEY_OK, /*XXX KEY_SELECT? KEY_ENTER? */
+ [ 0x0c ] = KEY_RIGHT, /*XXX KEY_FORWARD? */
+ [ 0x15 ] = KEY_DOWN, /*XXX KEY_SCROLLDOWN? */
+
+ /* 0x11 0x0d *
+ * TV/AV MODE *
+ * SOURCE STEREO *
+ * */
+ [ 0x11 ] = KEY_TV, /*XXX*/
+ [ 0x0d ] = KEY_MODE, /*XXX there's no KEY_STEREO */
+
+ /* 0x0f 0x1b 0x1a *
+ * AUDIO Vol+ Chan+ *
+ * TIMESHIFT??? *
+ * *
+ * 0x0e 0x1f 0x1e *
+ * SLEEP Vol- Chan- *
+ * */
+ [ 0x0f ] = KEY_AUDIO,
+ [ 0x1b ] = KEY_VOLUMEUP,
+ [ 0x1a ] = KEY_CHANNELUP,
+ [ 0x0e ] = KEY_SLEEP, /*XXX maybe KEY_PAUSE */
+ [ 0x1f ] = KEY_VOLUMEDOWN,
+ [ 0x1e ] = KEY_CHANNELDOWN,
+
+ /* 0x13 0x19 *
+ * MUTE SNAPSHOT*
+ * */
+ [ 0x13 ] = KEY_MUTE,
+ [ 0x19 ] = KEY_RECORD, /*XXX*/
+
+ // 0x1d unused ?
+};
/* ---------------------------------------------------------------------- */
static int build_key(struct saa7134_dev *dev)
@@ -379,7 +473,7 @@ int saa7134_input_init1(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_FLYVIDEO2000:
case SAA7134_BOARD_FLYVIDEO3000:
- case SAA7134_BOARD_FLYTVPLATINUM_FM:
+ case SAA7134_BOARD_FLYTVPLATINUM_FM:
ir_codes = flyvideo_codes;
mask_keycode = 0xEC00000;
mask_keydown = 0x0040000;
@@ -393,20 +487,25 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ECS_TVP3XP:
case SAA7134_BOARD_ECS_TVP3XP_4CB5:
- ir_codes = eztv_codes;
- mask_keycode = 0x00017c;
- mask_keyup = 0x000002;
+ ir_codes = eztv_codes;
+ mask_keycode = 0x00017c;
+ mask_keyup = 0x000002;
polling = 50; // ms
- break;
+ break;
+ case SAA7134_BOARD_KWORLD_XPERT:
case SAA7134_BOARD_AVACSSMARTTV:
- ir_codes = avacssmart_codes;
+ ir_codes = avacssmart_codes;
mask_keycode = 0x00001F;
mask_keyup = 0x000020;
polling = 50; // ms
break;
case SAA7134_BOARD_MD2819:
+ case SAA7134_BOARD_KWORLD_VSTREAM_XPERT:
case SAA7134_BOARD_AVERMEDIA_305:
case SAA7134_BOARD_AVERMEDIA_307:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_305:
+ case SAA7134_BOARD_AVERMEDIA_STUDIO_307:
+ case SAA7134_BOARD_AVERMEDIA_GO_007_FM:
ir_codes = md2819_codes;
mask_keycode = 0x0007C8;
mask_keydown = 0x000010;
@@ -415,7 +514,16 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPMODE0, 0x4);
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
+ case SAA7134_BOARD_MANLI_MTV001:
+ case SAA7134_BOARD_MANLI_MTV002:
+ ir_codes = manli_codes;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ mask_keydown = 0x002000;
+ polling = 50; // ms
+ break;
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
+ case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
ir_codes = videomate_tv_pvr_codes;
mask_keycode = 0x00003F;
mask_keyup = 0x400000;
diff --git a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
index 6b6a643bf1cd..b5bede95dbf5 100644
--- a/drivers/media/video/saa7134/saa7134-oss.c
+++ b/drivers/media/video/saa7134/saa7134-oss.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-oss.c,v 1.13 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-oss.c,v 1.17 2005/06/28 23:41:47 mkrufky Exp $
*
* device driver for philips saa7134 based TV cards
* oss dsp interface
@@ -49,7 +49,6 @@ MODULE_PARM_DESC(oss_rate,"sample rate (valid are: 32000,48000)");
static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
{
- blksize &= ~0xff;
if (blksize < 0x100)
blksize = 0x100;
if (blksize > 0x10000)
@@ -57,8 +56,6 @@ static int dsp_buffer_conf(struct saa7134_dev *dev, int blksize, int blocks)
if (blocks < 2)
blocks = 2;
- while ((blksize * blocks) & ~PAGE_MASK)
- blocks++;
if ((blksize * blocks) > 1024*1024)
blocks = 1024*1024 / blksize;
@@ -79,7 +76,7 @@ static int dsp_buffer_init(struct saa7134_dev *dev)
BUG();
videobuf_dma_init(&dev->oss.dma);
err = videobuf_dma_init_kernel(&dev->oss.dma, PCI_DMA_FROMDEVICE,
- dev->oss.bufsize >> PAGE_SHIFT);
+ (dev->oss.bufsize + PAGE_SIZE) >> PAGE_SHIFT);
if (0 != err)
return err;
return 0;
@@ -163,10 +160,11 @@ static int dsp_rec_start(struct saa7134_dev *dev)
fmt |= 0x04;
fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
- saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff));
- saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >> 8);
- saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16);
+ saa_writeb(SAA7134_NUM_SAMPLES0, ((dev->oss.blksize - 1) & 0x0000ff));
+ saa_writeb(SAA7134_NUM_SAMPLES1, ((dev->oss.blksize - 1) & 0x00ff00) >> 8);
+ saa_writeb(SAA7134_NUM_SAMPLES2, ((dev->oss.blksize - 1) & 0xff0000) >> 16);
saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+
break;
case PCI_DEVICE_ID_PHILIPS_SAA7133:
case PCI_DEVICE_ID_PHILIPS_SAA7135:
@@ -558,21 +556,28 @@ mixer_recsrc_7134(struct saa7134_dev *dev)
static int
mixer_recsrc_7133(struct saa7134_dev *dev)
{
- u32 value = 0xbbbbbb;
+ u32 anabar, xbarin;
+ xbarin = 0x03; // adc
+ anabar = 0;
switch (dev->oss.input) {
case TV:
- value = 0xbbbb10; /* MAIN */
+ xbarin = 0; // Demodulator
+ anabar = 2; // DACs
break;
case LINE1:
- value = 0xbbbb32; /* AUX1 */
+ anabar = 0; // aux1, aux1
break;
case LINE2:
case LINE2_LEFT:
- value = 0xbbbb54; /* AUX2 */
+ anabar = 9; // aux2, aux2
break;
}
- saa_dsp_writel(dev, 0x46c >> 2, value);
+ /* output xbar always main channel */
+ saa_dsp_writel(dev, 0x46c >> 2, 0xbbbb10);
+ saa_dsp_writel(dev, 0x464 >> 2, xbarin);
+ saa_writel(0x594 >> 2, anabar);
+
return 0;
}
@@ -817,7 +822,7 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status)
reg = SAA7134_RS_BA1(6);
} else {
/* even */
- if (0 == (dev->oss.dma_blk & 0x00))
+ if (1 == (dev->oss.dma_blk & 0x01))
reg = SAA7134_RS_BA2(6);
}
if (0 == reg) {
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index 345eb2a8c28d..4dd9f1b23928 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-ts.c,v 1.14 2005/02/03 10:24:33 kraxel Exp $
+ * $Id: saa7134-ts.c,v 1.15 2005/06/14 22:48:18 hhackmann Exp $
*
* device driver for philips saa7134 based TV cards
* video4linux video interface
@@ -221,10 +221,10 @@ void saa7134_irq_ts_done(struct saa7134_dev *dev, unsigned long status)
if (dev->ts_q.curr) {
field = dev->ts_q.curr->vb.field;
if (field == V4L2_FIELD_TOP) {
- if ((status & 0x100000) != 0x000000)
+ if ((status & 0x100000) != 0x100000)
goto done;
} else {
- if ((status & 0x100000) != 0x100000)
+ if ((status & 0x100000) != 0x000000)
goto done;
}
saa7134_buffer_finish(dev,&dev->ts_q,STATE_DONE);
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index ecac13c006d5..eeafa5a71d2b 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-tvaudio.c,v 1.22 2005/01/07 13:11:19 kraxel Exp $
+ * $Id: saa7134-tvaudio.c,v 1.30 2005/06/28 23:41:47 mkrufky Exp $
*
* device driver for philips saa7134 based TV cards
* tv audio decoder (fm stereo, nicam, ...)
@@ -169,7 +169,7 @@ static void tvaudio_init(struct saa7134_dev *dev)
int clock = saa7134_boards[dev->board].audio_clock;
if (UNSET != audio_clock_override)
- clock = audio_clock_override;
+ clock = audio_clock_override;
/* init all audio registers */
saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x00);
@@ -181,7 +181,8 @@ static void tvaudio_init(struct saa7134_dev *dev)
saa_writeb(SAA7134_AUDIO_CLOCK0, clock & 0xff);
saa_writeb(SAA7134_AUDIO_CLOCK1, (clock >> 8) & 0xff);
saa_writeb(SAA7134_AUDIO_CLOCK2, (clock >> 16) & 0xff);
- saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x01);
+ // frame locked audio was reported not to be reliable
+ saa_writeb(SAA7134_AUDIO_PLL_CTRL, 0x02);
saa_writeb(SAA7134_NICAM_ERROR_LOW, 0x14);
saa_writeb(SAA7134_NICAM_ERROR_HIGH, 0x50);
@@ -218,14 +219,17 @@ static void mute_input_7134(struct saa7134_dev *dev)
in = dev->input;
mute = (dev->ctl_mute ||
(dev->automute && (&card(dev).radio) != in));
- if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device &&
- card(dev).mute.name) {
- /* 7130 - we'll mute using some unconnected audio input */
+ if (card(dev).mute.name) {
+ /*
+ * 7130 - we'll mute using some unconnected audio input
+ * 7134 - we'll probably should switch external mux with gpio
+ */
if (mute)
in = &card(dev).mute;
}
+
if (dev->hw_mute == mute &&
- dev->hw_input == in) {
+ dev->hw_input == in) {
dprintk("mute/input: nothing to do [mute=%d,input=%s]\n",
mute,in->name);
return;
@@ -250,10 +254,16 @@ static void mute_input_7134(struct saa7134_dev *dev)
saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, ausel);
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x08, ics);
saa_andorb(SAA7134_ANALOG_IO_SELECT, 0x07, ocs);
+ // for oss, we need to change the clock configuration
+ if (in->amux == TV)
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x00);
+ else
+ saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, 0x01);
/* switch gpio-connected external audio mux */
if (0 == card(dev).gpiomask)
return;
+
mask = card(dev).gpiomask;
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
@@ -333,13 +343,8 @@ static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
set_current_state(TASK_INTERRUPTIBLE);
schedule();
} else {
-#if 0
- /* hmm, that one doesn't return on wakeup ... */
- msleep_interruptible(timeout);
-#else
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(msecs_to_jiffies(timeout));
-#endif
}
}
remove_wait_queue(&dev->thread.wq, &wait);
@@ -394,27 +399,10 @@ static int tvaudio_checkcarrier(struct saa7134_dev *dev, struct mainscan *scan)
return value;
}
-#if 0
-static void sifdebug_dump_regs(struct saa7134_dev *dev)
-{
- print_regb(AUDIO_STATUS);
- print_regb(IDENT_SIF);
- print_regb(LEVEL_READOUT1);
- print_regb(LEVEL_READOUT2);
- print_regb(DCXO_IDENT_CTRL);
- print_regb(DEMODULATOR);
- print_regb(AGC_GAIN_SELECT);
- print_regb(MONITOR_SELECT);
- print_regb(FM_DEEMPHASIS);
- print_regb(FM_DEMATRIX);
- print_regb(SIF_SAMPLE_FREQ);
- print_regb(ANALOG_IO_SELECT);
-}
-#endif
static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio)
{
- __u32 idp,nicam;
+ __u32 idp, nicam, nicam_status;
int retval = -1;
switch (audio->mode) {
@@ -436,19 +424,24 @@ static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
break;
case TVAUDIO_NICAM_FM:
case TVAUDIO_NICAM_AM:
- nicam = saa_readb(SAA7134_NICAM_STATUS);
+ nicam = saa_readb(SAA7134_AUDIO_STATUS);
dprintk("getstereo: nicam=0x%x\n",nicam);
- switch (nicam & 0x0b) {
- case 0x09:
- retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
- break;
- case 0x0a:
- retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
- break;
- case 0x08:
- default:
- retval = V4L2_TUNER_SUB_MONO;
- break;
+ if (nicam & 0x1) {
+ nicam_status = saa_readb(SAA7134_NICAM_STATUS);
+ dprintk("getstereo: nicam_status=0x%x\n", nicam_status);
+
+ switch (nicam_status & 0x03) {
+ case 0x01:
+ retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+ break;
+ case 0x02:
+ retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ break;
+ default:
+ retval = V4L2_TUNER_SUB_MONO;
+ }
+ } else {
+ /* No nicam detected */
}
break;
}
@@ -484,15 +477,15 @@ static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *au
break;
case TVAUDIO_FM_K_STEREO:
case TVAUDIO_FM_BG_STEREO:
+ case TVAUDIO_NICAM_AM:
+ case TVAUDIO_NICAM_FM:
dprintk("setstereo [fm] => %s\n",
name[ mode % ARRAY_SIZE(name) ]);
reg = fm[ mode % ARRAY_SIZE(fm) ];
saa_writeb(SAA7134_FM_DEMATRIX, reg);
break;
case TVAUDIO_FM_SAT_STEREO:
- case TVAUDIO_NICAM_AM:
- case TVAUDIO_NICAM_FM:
- /* FIXME */
+ /* Not implemented */
break;
}
return 0;
@@ -572,14 +565,14 @@ static int tvaudio_thread(void *data)
} else if (0 != dev->last_carrier) {
/* no carrier -- try last detected one as fallback */
carrier = dev->last_carrier;
- printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+ dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
"using %d.%03d MHz [last detected]\n",
dev->name, carrier/1000, carrier%1000);
} else {
/* no carrier + no fallback -- use default */
carrier = default_carrier;
- printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+ dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
"using %d.%03d MHz [default]\n",
dev->name, carrier/1000, carrier%1000);
}
@@ -591,7 +584,7 @@ static int tvaudio_thread(void *data)
/* find the exact tv audio norm */
for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
if (dev->tvnorm->id != UNSET &&
- !(dev->tvnorm->id & tvaudio[i].std))
+ !(dev->tvnorm->id & tvaudio[i].std))
continue;
if (tvaudio[i].carr1 != carrier)
continue;
@@ -698,24 +691,6 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
return 0;
}
-#if 0
-static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value)
-{
- int err;
-
- d2printk("dsp read reg 0x%x\n", reg<<2);
- saa_readl(reg);
- err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB);
- if (err < 0)
- return err;
- *value = saa_readl(reg);
- d2printk("dsp read => 0x%06x\n", *value & 0xffffff);
- err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA);
- if (err < 0)
- return err;
- return 0;
-}
-#endif
int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
{
@@ -748,31 +723,50 @@ static int getstereo_7133(struct saa7134_dev *dev)
static int mute_input_7133(struct saa7134_dev *dev)
{
u32 reg = 0;
+ u32 xbarin, xbarout;
int mask;
+ struct saa7134_input *in;
+ /* Hac 0506 route OSS sound simultanously */
+ xbarin = 0x03;
switch (dev->input->amux) {
case TV:
reg = 0x02;
+ xbarin = 0;
break;
case LINE1:
reg = 0x00;
break;
case LINE2:
case LINE2_LEFT:
- reg = 0x01;
+ reg = 0x09;
break;
}
- if (dev->ctl_mute)
+ saa_dsp_writel(dev, 0x464 >> 2, xbarin);
+ if (dev->ctl_mute) {
reg = 0x07;
+ xbarout = 0xbbbbbb;
+ } else
+ xbarout = 0xbbbb10;
+ saa_dsp_writel(dev, 0x46c >> 2, xbarout);
+
saa_writel(0x594 >> 2, reg);
+
/* switch gpio-connected external audio mux */
if (0 != card(dev).gpiomask) {
mask = card(dev).gpiomask;
+
+ if (card(dev).mute.name && dev->ctl_mute)
+ in = &card(dev).mute;
+ else
+ in = dev->input;
+
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
- saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, dev->input->gpio);
- saa7134_track_gpio(dev,dev->input->name);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, in->gpio);
+ saa7134_track_gpio(dev,in->name);
}
+
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index 86954cc7c377..29e51cad2aaf 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-vbi.c,v 1.6 2004/12/10 12:33:39 kraxel Exp $
+ * $Id: saa7134-vbi.c,v 1.7 2005/05/24 23:13:06 nsh Exp $
*
* device driver for philips saa7134 based TV cards
* video4linux video interface
@@ -60,10 +60,10 @@ static void task_init(struct saa7134_dev *dev, struct saa7134_buf *buf,
saa_writeb(SAA7134_VBI_H_START2(task), norm->h_start >> 8);
saa_writeb(SAA7134_VBI_H_STOP1(task), norm->h_stop & 0xff);
saa_writeb(SAA7134_VBI_H_STOP2(task), norm->h_stop >> 8);
- saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start & 0xff);
- saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start >> 8);
- saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop & 0xff);
- saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop >> 8);
+ saa_writeb(SAA7134_VBI_V_START1(task), norm->vbi_v_start_0 & 0xff);
+ saa_writeb(SAA7134_VBI_V_START2(task), norm->vbi_v_start_0 >> 8);
+ saa_writeb(SAA7134_VBI_V_STOP1(task), norm->vbi_v_stop_0 & 0xff);
+ saa_writeb(SAA7134_VBI_V_STOP2(task), norm->vbi_v_stop_0 >> 8);
saa_writeb(SAA7134_VBI_H_SCALE_INC1(task), VBI_SCALE & 0xff);
saa_writeb(SAA7134_VBI_H_SCALE_INC2(task), VBI_SCALE >> 8);
@@ -127,16 +127,10 @@ static int buffer_prepare(struct videobuf_queue *q,
unsigned int lines, llength, size;
int err;
- lines = norm->vbi_v_stop - norm->vbi_v_start +1;
+ lines = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
if (lines > VBI_LINE_COUNT)
lines = VBI_LINE_COUNT;
-#if 1
llength = VBI_LINE_LENGTH;
-#else
- llength = (norm->h_stop - norm->h_start +1) * 2;
- if (llength > VBI_LINE_LENGTH)
- llength = VBI_LINE_LENGTH;
-#endif
size = lines * llength * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
@@ -177,14 +171,8 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
struct saa7134_dev *dev = fh->dev;
int llength,lines;
- lines = dev->tvnorm->vbi_v_stop - dev->tvnorm->vbi_v_start +1;
-#if 1
+ lines = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
llength = VBI_LINE_LENGTH;
-#else
- llength = (norm->h_stop - norm->h_start +1) * 2;
- if (llength > VBI_LINE_LENGTH)
- llength = VBI_LINE_LENGTH;
-#endif
*size = lines * llength * 2;
if (0 == *count)
*count = vbibufs;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 5d66060026ff..a4c2f751d097 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134-video.c,v 1.28 2005/02/15 15:59:35 kraxel Exp $
+ * $Id: saa7134-video.c,v 1.36 2005/06/28 23:41:47 mkrufky Exp $
*
* device driver for philips saa7134 based TV cards
* video4linux video interface
@@ -31,8 +31,6 @@
#include "saa7134-reg.h"
#include "saa7134.h"
-#define V4L2_I2C_CLIENTS 1
-
/* ------------------------------------------------------------------ */
static unsigned int video_debug = 0;
@@ -158,18 +156,20 @@ static struct saa7134_format formats[] = {
.h_stop = 719, \
.video_v_start = 24, \
.video_v_stop = 311, \
- .vbi_v_start = 7, \
- .vbi_v_stop = 22, \
+ .vbi_v_start_0 = 7, \
+ .vbi_v_stop_0 = 22, \
+ .vbi_v_start_1 = 319, \
.src_timing = 4
#define NORM_525_60 \
.h_start = 0, \
.h_stop = 703, \
- .video_v_start = 22, \
- .video_v_stop = 22+239, \
- .vbi_v_start = 10, /* FIXME */ \
- .vbi_v_stop = 21, /* FIXME */ \
- .src_timing = 1
+ .video_v_start = 23, \
+ .video_v_stop = 262, \
+ .vbi_v_start_0 = 10, \
+ .vbi_v_stop_0 = 21, \
+ .vbi_v_start_1 = 273, \
+ .src_timing = 7
static struct saa7134_tvnorm tvnorms[] = {
{
@@ -274,11 +274,12 @@ static struct saa7134_tvnorm tvnorms[] = {
.h_start = 0,
.h_stop = 719,
- .video_v_start = 22,
- .video_v_stop = 22+239,
- .vbi_v_start = 10, /* FIXME */
- .vbi_v_stop = 21, /* FIXME */
- .src_timing = 1,
+ .video_v_start = 23,
+ .video_v_stop = 262,
+ .vbi_v_start_0 = 10,
+ .vbi_v_stop_0 = 21,
+ .vbi_v_start_1 = 273,
+ .src_timing = 7,
.sync_control = 0x18,
.luma_control = 0x40,
@@ -335,8 +336,8 @@ static const struct v4l2_queryctrl video_ctrls[] = {
.default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
},{
- .id = V4L2_CID_VFLIP,
- .name = "vertical flip",
+ .id = V4L2_CID_HFLIP,
+ .name = "Mirror",
.minimum = 0,
.maximum = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -482,7 +483,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
dev->crop_bounds.width = norm->h_stop - norm->h_start +1;
dev->crop_defrect.width = norm->h_stop - norm->h_start +1;
- dev->crop_bounds.top = (norm->vbi_v_stop+1)*2;
+ dev->crop_bounds.top = (norm->vbi_v_stop_0+1)*2;
dev->crop_defrect.top = norm->video_v_start*2;
dev->crop_bounds.height = ((norm->id & V4L2_STD_525_60) ? 524 : 624)
- dev->crop_bounds.top;
@@ -521,22 +522,7 @@ static void set_tvnorm(struct saa7134_dev *dev, struct saa7134_tvnorm *norm)
saa_writeb(SAA7134_RAW_DATA_GAIN, 0x40);
saa_writeb(SAA7134_RAW_DATA_OFFSET, 0x80);
-#ifdef V4L2_I2C_CLIENTS
saa7134_i2c_call_clients(dev,VIDIOC_S_STD,&norm->id);
-#else
- {
- /* pass down info to the i2c chips (v4l1) */
- struct video_channel c;
- memset(&c,0,sizeof(c));
- c.channel = dev->ctl_input;
- c.norm = VIDEO_MODE_PAL;
- if (norm->id & V4L2_STD_NTSC)
- c.norm = VIDEO_MODE_NTSC;
- if (norm->id & V4L2_STD_SECAM)
- c.norm = VIDEO_MODE_SECAM;
- saa7134_i2c_call_clients(dev,VIDIOCSCHAN,&c);
- }
-#endif
}
static void video_mux(struct saa7134_dev *dev, int input)
@@ -1064,7 +1050,7 @@ static int get_control(struct saa7134_dev *dev, struct v4l2_control *c)
case V4L2_CID_PRIVATE_INVERT:
c->value = dev->ctl_invert;
break;
- case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
c->value = dev->ctl_mirror;
break;
case V4L2_CID_PRIVATE_Y_EVEN:
@@ -1139,7 +1125,7 @@ static int set_control(struct saa7134_dev *dev, struct saa7134_fh *fh,
saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
break;
- case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
dev->ctl_mirror = c->value;
restart_overlay = 1;
break;
@@ -1218,7 +1204,6 @@ static int video_open(struct inode *inode, struct file *file)
struct list_head *list;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
int radio = 0;
-
list_for_each(list,&saa7134_devlist) {
h = list_entry(list, struct saa7134_dev, devlist);
if (h->video_dev && (h->video_dev->minor == minor))
@@ -1270,12 +1255,12 @@ static int video_open(struct inode *inode, struct file *file)
if (fh->radio) {
/* switch to radio mode */
saa7134_tvaudio_setinput(dev,&card(dev).radio);
- saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL);
+ saa7134_i2c_call_clients(dev,AUDC_SET_RADIO, NULL);
} else {
/* switch to video/vbi mode */
video_mux(dev,dev->ctl_input);
}
- return 0;
+ return 0;
}
static ssize_t
@@ -1318,10 +1303,10 @@ video_poll(struct file *file, struct poll_table_struct *wait)
} else {
down(&fh->cap.lock);
if (UNSET == fh->cap.read_off) {
- /* need to capture a new frame */
+ /* need to capture a new frame */
if (res_locked(fh->dev,RESOURCE_VIDEO)) {
- up(&fh->cap.lock);
- return POLLERR;
+ up(&fh->cap.lock);
+ return POLLERR;
}
if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field)) {
up(&fh->cap.lock);
@@ -1377,6 +1362,36 @@ static int video_release(struct inode *inode, struct file *file)
res_free(dev,fh,RESOURCE_VBI);
}
+ /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
+ saa_andorb(SAA7134_OFMT_VIDEO_A, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_VIDEO_B, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_DATA_A, 0x1f, 0);
+ saa_andorb(SAA7134_OFMT_DATA_B, 0x1f, 0);
+
+ if (dev->tuner_type == TUNER_PHILIPS_TDA8290) {
+ u8 data[2];
+ int ret;
+ struct i2c_msg msg = {.addr=I2C_ADDR_TDA8290, .flags=0, .buf=data, .len = 2};
+ data[0] = 0x21;
+ data[1] = 0xc0;
+ ret = i2c_transfer(&dev->i2c_adap, &msg, 1);
+ if (ret != 1)
+ printk(KERN_ERR "TDA8290 access failure\n");
+ msg.addr = I2C_ADDR_TDA8275;
+ data[0] = 0x30;
+ data[1] = 0xd0;
+ ret = i2c_transfer(&dev->i2c_adap, &msg, 1);
+ if (ret != 1)
+ printk(KERN_ERR "TDA8275 access failure\n");
+ msg.addr = I2C_ADDR_TDA8290;
+ data[0] = 0x21;
+ data[1] = 0x80;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ data[0] = 0x00;
+ data[1] = 0x02;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+
/* free stuff */
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
@@ -1407,19 +1422,12 @@ static void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 64 * 4;
- f->fmt.vbi.start[0] = norm->vbi_v_start;
- f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
- f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;
+ f->fmt.vbi.start[0] = norm->vbi_v_start_0;
+ f->fmt.vbi.count[0] = norm->vbi_v_stop_0 - norm->vbi_v_start_0 +1;
+ f->fmt.vbi.start[1] = norm->vbi_v_start_1;
f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */
-#if 0
- if (V4L2_STD_PAL == norm->id) {
- /* FIXME */
- f->fmt.vbi.start[0] += 3;
- f->fmt.vbi.start[1] += 3*2;
- }
-#endif
}
static int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
@@ -1880,11 +1888,9 @@ static int video_do_ioctl(struct inode *inode, struct file *file,
return -EINVAL;
down(&dev->lock);
dev->ctl_freq = f->frequency;
-#ifdef V4L2_I2C_CLIENTS
+
saa7134_i2c_call_clients(dev,VIDIOC_S_FREQUENCY,f);
-#else
- saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&dev->ctl_freq);
-#endif
+
saa7134_tvaudio_do_scan(dev);
up(&dev->lock);
return 0;
@@ -2136,19 +2142,20 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
memset(t,0,sizeof(*t));
strcpy(t->name, "Radio");
- t->rangelow = (int)(65*16);
- t->rangehigh = (int)(108*16);
-
-#ifdef V4L2_I2C_CLIENTS
- saa7134_i2c_call_clients(dev,VIDIOC_G_TUNER,t);
-#else
- {
- struct video_tuner vt;
- memset(&vt,0,sizeof(vt));
- saa7134_i2c_call_clients(dev,VIDIOCGTUNER,&vt);
- t->signal = vt.signal;
- }
-#endif
+
+ saa7134_i2c_call_clients(dev, VIDIOC_G_TUNER, t);
+
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ saa7134_i2c_call_clients(dev,VIDIOC_S_TUNER,t);
+
return 0;
}
case VIDIOC_ENUMINPUT:
@@ -2182,7 +2189,6 @@ static int radio_do_ioctl(struct inode *inode, struct file *file,
return 0;
}
case VIDIOC_S_AUDIO:
- case VIDIOC_S_TUNER:
case VIDIOC_S_INPUT:
case VIDIOC_S_STD:
return 0;
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index ac90a9853236..6836c07794fc 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -1,5 +1,5 @@
/*
- * $Id: saa7134.h,v 1.38 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: saa7134.h,v 1.48 2005/07/01 08:22:24 nsh Exp $
*
* v4l2 device driver for philips saa7134 based TV cards
*
@@ -21,7 +21,7 @@
*/
#include <linux/version.h>
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,12)
+#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,13)
#include <linux/pci.h>
#include <linux/i2c.h>
@@ -46,8 +46,6 @@
#endif
#define UNSET (-1U)
-/* 2.4 / 2.5 driver compatibility stuff */
-
/* ----------------------------------------------------------- */
/* enums */
@@ -91,9 +89,10 @@ struct saa7134_tvnorm {
unsigned int h_stop;
unsigned int video_v_start;
unsigned int video_v_stop;
- unsigned int vbi_v_start;
- unsigned int vbi_v_stop;
+ unsigned int vbi_v_start_0;
+ unsigned int vbi_v_stop_0;
unsigned int src_timing;
+ unsigned int vbi_v_start_1;
};
struct saa7134_tvaudio {
@@ -158,7 +157,7 @@ struct saa7134_format {
#define SAA7134_BOARD_AVERMEDIA_DVD_EZMAKER 33
#define SAA7134_BOARD_NOVAC_PRIMETV7133 34
#define SAA7134_BOARD_AVERMEDIA_STUDIO_305 35
-#define SAA7133_BOARD_UPMOST_PURPLE_TV 36
+#define SAA7134_BOARD_UPMOST_PURPLE_TV 36
#define SAA7134_BOARD_ITEMS_MTV005 37
#define SAA7134_BOARD_CINERGY200 38
#define SAA7134_BOARD_FLYTVPLATINUM_MINI 39
@@ -167,7 +166,7 @@ struct saa7134_format {
#define SAA7134_BOARD_SABRENT_SBTTVFM 42
#define SAA7134_BOARD_ZOLID_XPERT_TV7134 43
#define SAA7134_BOARD_EMPIRE_PCI_TV_RADIO_LE 44
-#define SAA7134_BOARD_AVERMEDIA_307 45
+#define SAA7134_BOARD_AVERMEDIA_STUDIO_307 45
#define SAA7134_BOARD_AVERMEDIA_CARDBUS 46
#define SAA7134_BOARD_CINERGY400_CARDBUS 47
#define SAA7134_BOARD_CINERGY600_MK3 48
@@ -175,9 +174,17 @@ struct saa7134_format {
#define SAA7134_BOARD_PINNACLE_300I_DVBT_PAL 50
#define SAA7134_BOARD_PROVIDEO_PV952 51
#define SAA7134_BOARD_AVERMEDIA_305 52
-#define SAA7135_BOARD_ASUSTeK_TVFM7135 53
+#define SAA7134_BOARD_ASUSTeK_TVFM7135 53
#define SAA7134_BOARD_FLYTVPLATINUM_FM 54
#define SAA7134_BOARD_FLYDVBTDUO 55
+#define SAA7134_BOARD_AVERMEDIA_307 56
+#define SAA7134_BOARD_AVERMEDIA_GO_007_FM 57
+#define SAA7134_BOARD_ADS_INSTANT_TV 58
+#define SAA7134_BOARD_KWORLD_VSTREAM_XPERT 59
+#define SAA7134_BOARD_THYPHOON_DVBT_DUO_CARDBUS 60
+#define SAA7134_BOARD_PHILIPS_TOUGH 61
+#define SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII 62
+#define SAA7134_BOARD_KWORLD_XPERT 63
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -208,6 +215,10 @@ struct saa7134_board {
/* i2c chip info */
unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+
unsigned int tda9887_conf;
/* peripheral I/O */
@@ -241,7 +252,7 @@ struct saa7134_dma;
/* saa7134 page table */
struct saa7134_pgtable {
unsigned int size;
- u32 *cpu;
+ __le32 *cpu;
dma_addr_t dma;
};
@@ -398,9 +409,12 @@ struct saa7134_dev {
/* config info */
unsigned int board;
unsigned int tuner_type;
+ unsigned int radio_type;
+ unsigned char tuner_addr;
+ unsigned char radio_addr;
+
unsigned int tda9887_conf;
unsigned int gpio_value;
- unsigned int irq2_mask;
/* i2c i/o */
struct i2c_adapter i2c_adap;
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 07ba6d3ed08c..7cb1fb3e66f9 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -243,19 +243,6 @@ static int tda7432_write(struct i2c_client *client, int subaddr, int val)
}
/* I don't think we ever actually _read_ the chip... */
-#if 0
-static int tda7432_read(struct i2c_client *client)
-{
- unsigned char buffer;
- d2printk("tda7432: In tda7432_read\n");
- if (1 != i2c_master_recv(client,&buffer,1)) {
- printk(KERN_WARNING "tda7432: I/O error, trying (read)\n");
- return -1;
- }
- dprintk("tda7432: Read 0x%02x\n", buffer);
- return buffer;
-}
-#endif
static int tda7432_set(struct i2c_client *client)
{
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index b27cc348d95c..a8b6a8df5109 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -1,5 +1,5 @@
/*
- * $Id: tda8290.c,v 1.7 2005/03/07 12:01:51 kraxel Exp $
+ * $Id: tda8290.c,v 1.15 2005/07/08 20:21:33 mchehab Exp $
*
* i2c tv tuner chip device driver
* controls the philips tda8290+75 tuner chip combo.
@@ -69,7 +69,7 @@ static __u8 get_freq_entry( struct freq_entry* table, __u16 freq)
static unsigned char i2c_enable_bridge[2] = { 0x21, 0xC0 };
static unsigned char i2c_disable_bridge[2] = { 0x21, 0x80 };
static unsigned char i2c_init_tda8275[14] = { 0x00, 0x00, 0x00, 0x00,
- 0x7C, 0x04, 0xA3, 0x3F,
+ 0xfC, 0x04, 0xA3, 0x3F,
0x2A, 0x04, 0xFF, 0x00,
0x00, 0x40 };
static unsigned char i2c_set_VS[2] = { 0x30, 0x6F };
@@ -136,18 +136,23 @@ static int tda8290_tune(struct i2c_client *c)
return 0;
}
-static void set_frequency(struct tuner *t, u16 ifc)
+static void set_frequency(struct tuner *t, u16 ifc, unsigned int freq)
{
- u32 N = (((t->freq<<3)+ifc)&0x3fffc);
+ u32 N;
- N = N >> get_freq_entry(div_table, t->freq);
+ if (t->mode == V4L2_TUNER_RADIO)
+ freq = freq / 1000;
+
+ N = (((freq<<3)+ifc)&0x3fffc);
+
+ N = N >> get_freq_entry(div_table, freq);
t->i2c_set_freq[0] = 0;
t->i2c_set_freq[1] = (unsigned char)(N>>8);
t->i2c_set_freq[2] = (unsigned char) N;
t->i2c_set_freq[3] = 0x40;
t->i2c_set_freq[4] = 0x52;
- t->i2c_set_freq[5] = get_freq_entry(band_table, t->freq);
- t->i2c_set_freq[6] = get_freq_entry(agc_table, t->freq);
+ t->i2c_set_freq[5] = get_freq_entry(band_table, freq);
+ t->i2c_set_freq[6] = get_freq_entry(agc_table, freq);
t->i2c_set_freq[7] = 0x8f;
}
@@ -179,14 +184,14 @@ static void set_tv_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
set_audio(t);
- set_frequency(t, 864);
+ set_frequency(t, 864, freq);
tda8290_tune(c);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
- set_frequency(t, 704);
+ set_frequency(t, 704, freq);
tda8290_tune(c);
}
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
index 97b113e070f3..566e1a5ca135 100644
--- a/drivers/media/video/tda9875.c
+++ b/drivers/media/video/tda9875.c
@@ -123,19 +123,6 @@ static int tda9875_write(struct i2c_client *client, int subaddr, unsigned char v
return 0;
}
-#if 0
-static int tda9875_read(struct i2c_client *client)
-{
- unsigned char buffer;
- dprintk("In tda9875_read\n");
- if (1 != i2c_master_recv(client,&buffer,1)) {
- printk(KERN_WARNING "tda9875: I/O error, trying (read)\n");
- return -1;
- }
- dprintk("Read 0x%02x\n", buffer);
- return buffer;
-}
-#endif
static int i2c_read_register(struct i2c_adapter *adap, int addr, int reg)
{
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 7e6e6dd966a2..108c3ad7d622 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -53,6 +53,7 @@ struct tda9887 {
unsigned int config;
unsigned int pinnacle_id;
unsigned int using_v4l2;
+ unsigned int radio_mode;
};
struct tvnorm {
@@ -212,12 +213,22 @@ static struct tvnorm tvnorms[] = {
}
};
-static struct tvnorm radio = {
- .name = "radio",
+static struct tvnorm radio_stereo = {
+ .name = "Radio Stereo",
+ .b = ( cFmRadio |
+ cQSS ),
+ .c = ( cDeemphasisOFF |
+ cAudioGain6 ),
+ .e = ( cAudioIF_5_5 |
+ cRadioIF_38_90 ),
+};
+
+static struct tvnorm radio_mono = {
+ .name = "Radio Mono",
.b = ( cFmRadio |
cQSS ),
.c = ( cDeemphasisON |
- cDeemphasis50 ),
+ cDeemphasis50),
.e = ( cAudioIF_5_5 |
cRadioIF_38_90 ),
};
@@ -354,7 +365,10 @@ static int tda9887_set_tvnorm(struct tda9887 *t, char *buf)
int i;
if (t->radio) {
- norm = &radio;
+ if (t->radio_mode == V4L2_TUNER_MODE_MONO)
+ norm = &radio_mono;
+ else
+ norm = &radio_stereo;
} else {
for (i = 0; i < ARRAY_SIZE(tvnorms); i++) {
if (tvnorms[i].std & t->std) {
@@ -545,23 +559,16 @@ static int tda9887_configure(struct tda9887 *t)
memset(buf,0,sizeof(buf));
tda9887_set_tvnorm(t,buf);
+
buf[1] |= cOutputPort1Inactive;
buf[1] |= cOutputPort2Inactive;
+
if (UNSET != t->pinnacle_id) {
tda9887_set_pinnacle(t,buf);
}
tda9887_set_config(t,buf);
tda9887_set_insmod(t,buf);
-#if 0
- /* This as-is breaks some cards, must be fixed in a
- * card-specific way, probably using TDA9887_SET_CONFIG to
- * turn on/off port2 */
- if (t->std & V4L2_STD_SECAM_L) {
- /* secam fixup (FIXME: move this to tvnorms array?) */
- buf[1] &= ~cOutputPort2Inactive;
- }
-#endif
dprintk(PREFIX "writing: b=0x%02x c=0x%02x e=0x%02x\n",
buf[1],buf[2],buf[3]);
@@ -592,11 +599,14 @@ static int tda9887_attach(struct i2c_adapter *adap, int addr, int kind)
if (NULL == (t = kmalloc(sizeof(*t), GFP_KERNEL)))
return -ENOMEM;
memset(t,0,sizeof(*t));
+
t->client = client_template;
t->std = 0;
t->pinnacle_id = UNSET;
- i2c_set_clientdata(&t->client, t);
- i2c_attach_client(&t->client);
+ t->radio_mode = V4L2_TUNER_MODE_STEREO;
+
+ i2c_set_clientdata(&t->client, t);
+ i2c_attach_client(&t->client);
return 0;
}
@@ -733,6 +743,16 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
}
break;
}
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner* tuner = arg;
+
+ if (t->radio) {
+ t->radio_mode = tuner->audmode;
+ tda9887_configure (t);
+ }
+ break;
+ }
default:
/* nothing */
break;
@@ -740,7 +760,7 @@ tda9887_command(struct i2c_client *client, unsigned int cmd, void *arg)
return 0;
}
-static int tda9887_suspend(struct device * dev, pm_message_t state, u32 level)
+static int tda9887_suspend(struct device * dev, u32 state, u32 level)
{
dprintk("tda9887: suspend\n");
return 0;
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
new file mode 100644
index 000000000000..b53c748caf2a
--- /dev/null
+++ b/drivers/media/video/tea5767.c
@@ -0,0 +1,338 @@
+/*
+ * For Philips TEA5767 FM Chip used on some TV Cards like Prolink Pixelview
+ * I2C address is allways 0xC0.
+ *
+ * $Id: tea5767.c,v 1.18 2005/07/07 03:02:55 mchehab Exp $
+ *
+ * Copyright (c) 2005 Mauro Carvalho Chehab (mchehab@brturbo.com.br)
+ * This code is placed under the terms of the GNU General Public License
+ *
+ * tea5767 autodetection thanks to Torsten Seeboth and Atsushi Nakagawa
+ * from their contributions on DScaler.
+ */
+
+#include <linux/i2c.h>
+#include <linux/videodev.h>
+#include <linux/delay.h>
+#include <media/tuner.h>
+#include <media/tuner.h>
+
+#define PREFIX "TEA5767 "
+
+/*****************************************************************************/
+
+/******************************
+ * Write mode register values *
+ ******************************/
+
+/* First register */
+#define TEA5767_MUTE 0x80 /* Mutes output */
+#define TEA5767_SEARCH 0x40 /* Activates station search */
+/* Bits 0-5 for divider MSB */
+
+/* Second register */
+/* Bits 0-7 for divider LSB */
+
+/* Third register */
+
+/* Station search from botton to up */
+#define TEA5767_SEARCH_UP 0x80
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_HIGH_LVL 0x60
+
+/* Searches with ADC output = 10 */
+#define TEA5767_SRCH_MID_LVL 0x40
+
+/* Searches with ADC output = 5 */
+#define TEA5767_SRCH_LOW_LVL 0x20
+
+/* if on, div=4*(Frf+Fif)/Fref otherwise, div=4*(Frf-Fif)/Freq) */
+#define TEA5767_HIGH_LO_INJECT 0x10
+
+/* Disable stereo */
+#define TEA5767_MONO 0x08
+
+/* Disable right channel and turns to mono */
+#define TEA5767_MUTE_RIGHT 0x04
+
+/* Disable left channel and turns to mono */
+#define TEA5767_MUTE_LEFT 0x02
+
+#define TEA5767_PORT1_HIGH 0x01
+
+/* Forth register */
+#define TEA5767_PORT2_HIGH 0x80
+/* Chips stops working. Only I2C bus remains on */
+#define TEA5767_STDBY 0x40
+
+/* Japan freq (76-108 MHz. If disabled, 87.5-108 MHz */
+#define TEA5767_JAPAN_BAND 0x20
+
+/* Unselected means 32.768 KHz freq as reference. Otherwise Xtal at 13 MHz */
+#define TEA5767_XTAL_32768 0x10
+
+/* Cuts weak signals */
+#define TEA5767_SOFT_MUTE 0x08
+
+/* Activates high cut control */
+#define TEA5767_HIGH_CUT_CTRL 0x04
+
+/* Activates stereo noise control */
+#define TEA5767_ST_NOISE_CTL 0x02
+
+/* If activate PORT 1 indicates SEARCH or else it is used as PORT1 */
+#define TEA5767_SRCH_IND 0x01
+
+/* Fiveth register */
+
+/* By activating, it will use Xtal at 13 MHz as reference for divider */
+#define TEA5767_PLLREF_ENABLE 0x80
+
+/* By activating, deemphasis=50, or else, deemphasis of 50us */
+#define TEA5767_DEEMPH_75 0X40
+
+/*****************************
+ * Read mode register values *
+ *****************************/
+
+/* First register */
+#define TEA5767_READY_FLAG_MASK 0x80
+#define TEA5767_BAND_LIMIT_MASK 0X40
+/* Bits 0-5 for divider MSB after search or preset */
+
+/* Second register */
+/* Bits 0-7 for divider LSB after search or preset */
+
+/* Third register */
+#define TEA5767_STEREO_MASK 0x80
+#define TEA5767_IF_CNTR_MASK 0x7f
+
+/* Four register */
+#define TEA5767_ADC_LEVEL_MASK 0xf0
+
+/* should be 0 */
+#define TEA5767_CHIP_ID_MASK 0x0f
+
+/* Fiveth register */
+/* Reserved for future extensions */
+#define TEA5767_RESERVED_MASK 0xff
+
+enum tea5767_xtal_freq {
+ TEA5767_LOW_LO_32768 = 0,
+ TEA5767_HIGH_LO_32768 = 1,
+ TEA5767_LOW_LO_13MHz = 2,
+ TEA5767_HIGH_LO_13MHz = 3,
+};
+
+
+/*****************************************************************************/
+
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ tuner_warn("This tuner doesn't support TV freq.\n");
+}
+
+static void tea5767_status_dump(unsigned char *buffer)
+{
+ unsigned int div, frq;
+
+ if (TEA5767_READY_FLAG_MASK & buffer[0])
+ printk(PREFIX "Ready Flag ON\n");
+ else
+ printk(PREFIX "Ready Flag OFF\n");
+
+ if (TEA5767_BAND_LIMIT_MASK & buffer[0])
+ printk(PREFIX "Tuner at band limit\n");
+ else
+ printk(PREFIX "Tuner not at band limit\n");
+
+ div = ((buffer[0] & 0x3f) << 8) | buffer[1];
+
+ switch (TEA5767_HIGH_LO_32768) {
+ case TEA5767_HIGH_LO_13MHz:
+ frq = 1000 * (div * 50 - 700 - 225) / 4; /* Freq in KHz */
+ break;
+ case TEA5767_LOW_LO_13MHz:
+ frq = 1000 * (div * 50 + 700 + 225) / 4; /* Freq in KHz */
+ break;
+ case TEA5767_LOW_LO_32768:
+ frq = 1000 * (div * 32768 / 1000 + 700 + 225) / 4; /* Freq in KHz */
+ break;
+ case TEA5767_HIGH_LO_32768:
+ default:
+ frq = 1000 * (div * 32768 / 1000 - 700 - 225) / 4; /* Freq in KHz */
+ break;
+ }
+ buffer[0] = (div >> 8) & 0x3f;
+ buffer[1] = div & 0xff;
+
+ printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ frq / 1000, frq % 1000, div);
+
+ if (TEA5767_STEREO_MASK & buffer[2])
+ printk(PREFIX "Stereo\n");
+ else
+ printk(PREFIX "Mono\n");
+
+ printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
+
+ printk(PREFIX "ADC Level = %d\n",
+ (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
+
+ printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
+
+ printk(PREFIX "Reserved = 0x%02x\n",
+ (buffer[4] & TEA5767_RESERVED_MASK));
+}
+
+/* Freq should be specifyed at 62.5 Hz */
+static void set_radio_freq(struct i2c_client *c, unsigned int frq)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buffer[5];
+ unsigned div;
+ int rc;
+
+ tuner_dbg (PREFIX "radio freq counter %d\n", frq);
+
+ /* Rounds freq to next decimal value - for 62.5 KHz step */
+ /* frq = 20*(frq/16)+radio_frq[frq%16]; */
+
+ buffer[2] = TEA5767_PORT1_HIGH;
+ buffer[3] = TEA5767_PORT2_HIGH | TEA5767_HIGH_CUT_CTRL |
+ TEA5767_ST_NOISE_CTL | TEA5767_JAPAN_BAND;
+ buffer[4] = 0;
+
+ if (t->mode == T_STANDBY) {
+ tuner_dbg("TEA5767 set to standby mode\n");
+ buffer[3] |= TEA5767_STDBY;
+ }
+
+ if (t->audmode == V4L2_TUNER_MODE_MONO) {
+ tuner_dbg("TEA5767 set to mono\n");
+ buffer[2] |= TEA5767_MONO;
+ } else {
+ tuner_dbg("TEA5767 set to stereo\n");
+ }
+
+ /* Should be replaced */
+ switch (TEA5767_HIGH_LO_32768) {
+ case TEA5767_HIGH_LO_13MHz:
+ tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 13 MHz\n");
+ buffer[2] |= TEA5767_HIGH_LO_INJECT;
+ buffer[4] |= TEA5767_PLLREF_ENABLE;
+ div = (frq * 4 / 16 + 700 + 225 + 25) / 50;
+ break;
+ case TEA5767_LOW_LO_13MHz:
+ tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 13 MHz\n");
+
+ buffer[4] |= TEA5767_PLLREF_ENABLE;
+ div = (frq * 4 / 16 - 700 - 225 + 25) / 50;
+ break;
+ case TEA5767_LOW_LO_32768:
+ tuner_dbg ("TEA5767 radio LOW LO inject xtal @ 32,768 MHz\n");
+ buffer[3] |= TEA5767_XTAL_32768;
+ /* const 700=4000*175 Khz - to adjust freq to right value */
+ div = (1000 * (frq * 4 / 16 - 700 - 225) + 16384) >> 15;
+ break;
+ case TEA5767_HIGH_LO_32768:
+ default:
+ tuner_dbg ("TEA5767 radio HIGH LO inject xtal @ 32,768 MHz\n");
+
+ buffer[2] |= TEA5767_HIGH_LO_INJECT;
+ buffer[3] |= TEA5767_XTAL_32768;
+ div = (1000 * (frq * 4 / 16 + 700 + 225) + 16384) >> 15;
+ break;
+ }
+ buffer[0] = (div >> 8) & 0x3f;
+ buffer[1] = div & 0xff;
+
+ if (tuner_debug)
+ tea5767_status_dump(buffer);
+
+ if (5 != (rc = i2c_master_send(c, buffer, 5)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+}
+
+static int tea5767_signal(struct i2c_client *c)
+{
+ unsigned char buffer[5];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ return ((buffer[3] & TEA5767_ADC_LEVEL_MASK) << (13 - 4));
+}
+
+static int tea5767_stereo(struct i2c_client *c)
+{
+ unsigned char buffer[5];
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ memset(buffer, 0, sizeof(buffer));
+ if (5 != (rc = i2c_master_recv(c, buffer, 5)))
+ tuner_warn("i2c i/o error: rc == %d (should be 5)\n", rc);
+
+ rc = buffer[2] & TEA5767_STEREO_MASK;
+
+ tuner_dbg("TEA5767 radio ST GET = %02x\n", rc);
+
+ return ((buffer[2] & TEA5767_STEREO_MASK) ? V4L2_TUNER_SUB_STEREO : 0);
+}
+
+int tea5767_autodetection(struct i2c_client *c)
+{
+ unsigned char buffer[5] = { 0xff, 0xff, 0xff, 0xff, 0xff };
+ int rc;
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (5 != (rc = i2c_master_recv(c, buffer, 5))) {
+ tuner_warn("it is not a TEA5767. Received %i chars.\n", rc);
+ return EINVAL;
+ }
+
+ /* If all bytes are the same then it's a TV tuner and not a tea5767 chip. */
+ if (buffer[0] == buffer[1] && buffer[0] == buffer[2] &&
+ buffer[0] == buffer[3] && buffer[0] == buffer[4]) {
+ tuner_warn("All bytes are equal. It is not a TEA5767\n");
+ return EINVAL;
+ }
+
+ /* Status bytes:
+ * Byte 4: bit 3:1 : CI (Chip Identification) == 0
+ * bit 0 : internally set to 0
+ * Byte 5: bit 7:0 : == 0
+ */
+
+ if (!((buffer[3] & 0x0f) == 0x00) && (buffer[4] == 0x00)) {
+ tuner_warn("Chip ID is not zero. It is not a TEA5767\n");
+ return EINVAL;
+ }
+ tuner_warn("TEA5767 detected.\n");
+ return 0;
+}
+
+int tea5767_tuner_init(struct i2c_client *c)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (tea5767_autodetection(c) == EINVAL)
+ return EINVAL;
+
+ tuner_info("type set to %d (%s)\n", t->type, "Philips TEA5767HN FM Radio");
+ strlcpy(c->name, "tea5767", sizeof(c->name));
+
+ t->tv_freq = set_tv_freq;
+ t->radio_freq = set_radio_freq;
+ t->has_signal = tea5767_signal;
+ t->is_stereo = tea5767_stereo;
+
+ return (0);
+}
diff --git a/drivers/media/video/tuner-3036.c b/drivers/media/video/tuner-3036.c
index 51748c6578d1..7d825e510ffd 100644
--- a/drivers/media/video/tuner-3036.c
+++ b/drivers/media/video/tuner-3036.c
@@ -152,7 +152,7 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
switch (cmd)
{
- case TUNER_SET_TVFREQ:
+ case VIDIOCSFREQ:
set_tv_freq(client, *iarg);
break;
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 81882ddab859..de190630babb 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -1,5 +1,5 @@
/*
- * $Id: tuner-core.c,v 1.5 2005/02/15 15:59:35 kraxel Exp $
+ * $Id: tuner-core.c,v 1.55 2005/07/08 13:20:33 mchehab Exp $
*
* i2c tv tuner chip device driver
* core core, i.e. kernel interfaces, registering and so on
@@ -27,61 +27,56 @@
/* standard i2c insmod options */
static unsigned short normal_i2c[] = {
- 0x4b, /* tda8290 */
+ 0x4b, /* tda8290 */
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
I2C_CLIENT_END
};
+
I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
-static unsigned int addr = 0;
+static unsigned int addr = 0;
module_param(addr, int, 0444);
/* insmod options used at runtime => read/write */
-unsigned int tuner_debug = 0;
-module_param(tuner_debug, int, 0644);
+unsigned int tuner_debug = 0;
+module_param(tuner_debug, int, 0644);
-static unsigned int tv_range[2] = { 44, 958 };
+static unsigned int tv_range[2] = { 44, 958 };
static unsigned int radio_range[2] = { 65, 108 };
-module_param_array(tv_range, int, NULL, 0644);
+module_param_array(tv_range, int, NULL, 0644);
module_param_array(radio_range, int, NULL, 0644);
MODULE_DESCRIPTION("device driver for various TV and TV+FM radio tuners");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
-static int this_adap;
-
static struct i2c_driver driver;
static struct i2c_client client_template;
/* ---------------------------------------------------------------------- */
-// Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz
+/* Set tuner frequency, freq in Units of 62.5kHz = 1/16MHz */
static void set_tv_freq(struct i2c_client *c, unsigned int freq)
{
struct tuner *t = i2c_get_clientdata(c);
if (t->type == UNSET) {
- tuner_info("tuner type not set\n");
+ tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->tv_freq) {
- tuner_info("Huh? tv_set is NULL?\n");
+ tuner_warn ("Tuner has no way to set tv freq\n");
return;
}
- if (freq < tv_range[0]*16 || freq > tv_range[1]*16) {
- /* FIXME: better do that chip-specific, but
- right now we don't have that in the config
- struct and this way is still better than no
- check at all */
- tuner_info("TV freq (%d.%02d) out of range (%d-%d)\n",
- freq/16,freq%16*100/16,tv_range[0],tv_range[1]);
- return;
+ if (freq < tv_range[0] * 16 || freq > tv_range[1] * 16) {
+ tuner_dbg ("TV freq (%d.%02d) out of range (%d-%d)\n",
+ freq / 16, freq % 16 * 100 / 16, tv_range[0],
+ tv_range[1]);
}
- t->tv_freq(c,freq);
+ t->tv_freq(c, freq);
}
static void set_radio_freq(struct i2c_client *c, unsigned int freq)
@@ -89,20 +84,21 @@ static void set_radio_freq(struct i2c_client *c, unsigned int freq)
struct tuner *t = i2c_get_clientdata(c);
if (t->type == UNSET) {
- tuner_info("tuner type not set\n");
+ tuner_warn ("tuner type not set\n");
return;
}
if (NULL == t->radio_freq) {
- tuner_info("no radio tuning for this one, sorry.\n");
+ tuner_warn ("tuner has no way to set radio frequency\n");
return;
}
- if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
- tuner_info("radio freq (%d.%02d) out of range (%d-%d)\n",
- freq/16,freq%16*100/16,
- radio_range[0],radio_range[1]);
- return;
+ if (freq <= radio_range[0] * 16000 || freq >= radio_range[1] * 16000) {
+ tuner_dbg ("radio freq (%d.%02d) out of range (%d-%d)\n",
+ freq / 16000, freq % 16000 * 100 / 16000,
+ radio_range[0], radio_range[1]);
}
- t->radio_freq(c,freq);
+
+ t->radio_freq(c, freq);
+ return;
}
static void set_freq(struct i2c_client *c, unsigned long freq)
@@ -112,40 +108,45 @@ static void set_freq(struct i2c_client *c, unsigned long freq)
switch (t->mode) {
case V4L2_TUNER_RADIO:
tuner_dbg("radio freq set to %lu.%02lu\n",
- freq/16,freq%16*100/16);
- set_radio_freq(c,freq);
+ freq / 16000, freq % 16000 * 100 / 16000);
+ set_radio_freq(c, freq);
break;
case V4L2_TUNER_ANALOG_TV:
case V4L2_TUNER_DIGITAL_TV:
tuner_dbg("tv freq set to %lu.%02lu\n",
- freq/16,freq%16*100/16);
+ freq / 16, freq % 16 * 100 / 16);
set_tv_freq(c, freq);
break;
}
t->freq = freq;
}
-static void set_type(struct i2c_client *c, unsigned int type)
+static void set_type(struct i2c_client *c, unsigned int type,
+ unsigned int new_mode_mask)
{
struct tuner *t = i2c_get_clientdata(c);
+ unsigned char buffer[4];
- /* sanity check */
- if (type == UNSET || type == TUNER_ABSENT)
+ if (type == UNSET || type == TUNER_ABSENT) {
+ tuner_dbg ("tuner 0x%02x: Tuner type absent\n",c->addr);
return;
- if (type >= tuner_count)
+ }
+
+ if (type >= tuner_count) {
+ tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
return;
+ }
+ /* This code detects calls by card attach_inform */
if (NULL == t->i2c.dev.driver) {
- /* not registered yet */
- t->type = type;
+ tuner_dbg ("tuner 0x%02x: called during i2c_client register by adapter's attach_inform\n", c->addr);
+
+ t->type=type;
return;
}
- if (t->initialized)
- /* run only once */
- return;
- t->initialized = 1;
t->type = type;
+
switch (t->type) {
case TUNER_MT2032:
microtune_init(c);
@@ -153,70 +154,195 @@ static void set_type(struct i2c_client *c, unsigned int type)
case TUNER_PHILIPS_TDA8290:
tda8290_init(c);
break;
+ case TUNER_TEA5767:
+ if (tea5767_tuner_init(c) == EINVAL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
+ t->mode_mask = T_RADIO;
+ break;
+ case TUNER_PHILIPS_FMD1216ME_MK3:
+ buffer[0] = 0x0b;
+ buffer[1] = 0xdc;
+ buffer[2] = 0x9c;
+ buffer[3] = 0x60;
+ i2c_master_send(c, buffer, 4);
+ mdelay(1);
+ buffer[2] = 0x86;
+ buffer[3] = 0x54;
+ i2c_master_send(c, buffer, 4);
+ default_tuner_init(c);
+ break;
default:
default_tuner_init(c);
break;
}
+
+ if (t->mode_mask == T_UNINITIALIZED)
+ t->mode_mask = new_mode_mask;
+
+ set_freq(c, t->freq);
+ tuner_dbg("%s %s I2C addr 0x%02x with type %d used for 0x%02x\n",
+ c->adapter->name, c->driver->name, c->addr << 1, type,
+ t->mode_mask);
+}
+
+/*
+ * This function apply tuner config to tuner specified
+ * by tun_setup structure. I addr is unset, then admin status
+ * and tun addr status is more precise then current status,
+ * it's applied. Otherwise status and type are applied only to
+ * tuner with exactly the same addr.
+*/
+
+static void set_addr(struct i2c_client *c, struct tuner_setup *tun_setup)
+{
+ struct tuner *t = i2c_get_clientdata(c);
+
+ if (tun_setup->addr == ADDR_UNSET) {
+ if (t->mode_mask & tun_setup->mode_mask)
+ set_type(c, tun_setup->type, tun_setup->mode_mask);
+ } else if (tun_setup->addr == c->addr) {
+ set_type(c, tun_setup->type, tun_setup->mode_mask);
+ }
+}
+
+static inline int check_mode(struct tuner *t, char *cmd)
+{
+ if (1 << t->mode & t->mode_mask) {
+ switch (t->mode) {
+ case V4L2_TUNER_RADIO:
+ tuner_dbg("Cmd %s accepted for radio\n", cmd);
+ break;
+ case V4L2_TUNER_ANALOG_TV:
+ tuner_dbg("Cmd %s accepted for analog TV\n", cmd);
+ break;
+ case V4L2_TUNER_DIGITAL_TV:
+ tuner_dbg("Cmd %s accepted for digital TV\n", cmd);
+ break;
+ }
+ return 0;
+ }
+ return EINVAL;
}
static char pal[] = "-";
module_param_string(pal, pal, sizeof(pal), 0644);
+static char secam[] = "-";
+module_param_string(secam, secam, sizeof(secam), 0644);
+/* get more precise norm info from insmod option */
static int tuner_fixup_std(struct tuner *t)
{
if ((t->std & V4L2_STD_PAL) == V4L2_STD_PAL) {
- /* get more precise norm info from insmod option */
switch (pal[0]) {
case 'b':
case 'B':
case 'g':
case 'G':
- tuner_dbg("insmod fixup: PAL => PAL-BG\n");
+ tuner_dbg ("insmod fixup: PAL => PAL-BG\n");
t->std = V4L2_STD_PAL_BG;
break;
case 'i':
case 'I':
- tuner_dbg("insmod fixup: PAL => PAL-I\n");
+ tuner_dbg ("insmod fixup: PAL => PAL-I\n");
t->std = V4L2_STD_PAL_I;
break;
case 'd':
case 'D':
case 'k':
case 'K':
- tuner_dbg("insmod fixup: PAL => PAL-DK\n");
+ tuner_dbg ("insmod fixup: PAL => PAL-DK\n");
t->std = V4L2_STD_PAL_DK;
break;
+ case 'M':
+ case 'm':
+ tuner_dbg ("insmod fixup: PAL => PAL-M\n");
+ t->std = V4L2_STD_PAL_M;
+ break;
+ case 'N':
+ case 'n':
+ tuner_dbg ("insmod fixup: PAL => PAL-N\n");
+ t->std = V4L2_STD_PAL_N;
+ break;
}
}
+ if ((t->std & V4L2_STD_SECAM) == V4L2_STD_SECAM) {
+ switch (secam[0]) {
+ case 'd':
+ case 'D':
+ case 'k':
+ case 'K':
+ tuner_dbg ("insmod fixup: SECAM => SECAM-DK\n");
+ t->std = V4L2_STD_SECAM_DK;
+ break;
+ case 'l':
+ case 'L':
+ tuner_dbg ("insmod fixup: SECAM => SECAM-L\n");
+ t->std = V4L2_STD_SECAM_L;
+ break;
+ }
+ }
+
return 0;
}
/* ---------------------------------------------------------------------- */
+/* static var Used only in tuner_attach and tuner_probe */
+static unsigned default_mode_mask;
+
+/* During client attach, set_type is called by adapter's attach_inform callback.
+ set_type must then be completed by tuner_attach.
+ */
static int tuner_attach(struct i2c_adapter *adap, int addr, int kind)
{
struct tuner *t;
- if (this_adap > 0)
- return -1;
- this_adap++;
-
- client_template.adapter = adap;
- client_template.addr = addr;
+ client_template.adapter = adap;
+ client_template.addr = addr;
- t = kmalloc(sizeof(struct tuner),GFP_KERNEL);
- if (NULL == t)
- return -ENOMEM;
- memset(t,0,sizeof(struct tuner));
- memcpy(&t->i2c,&client_template,sizeof(struct i2c_client));
+ t = kmalloc(sizeof(struct tuner), GFP_KERNEL);
+ if (NULL == t)
+ return -ENOMEM;
+ memset(t, 0, sizeof(struct tuner));
+ memcpy(&t->i2c, &client_template, sizeof(struct i2c_client));
i2c_set_clientdata(&t->i2c, t);
- t->type = UNSET;
- t->radio_if2 = 10700*1000; // 10.7MHz - FM radio
+ t->type = UNSET;
+ t->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
+ t->audmode = V4L2_TUNER_MODE_STEREO;
+ t->mode_mask = T_UNINITIALIZED;
+
+
+ tuner_info("chip found @ 0x%x (%s)\n", addr << 1, adap->name);
+
+ /* TEA5767 autodetection code - only for addr = 0xc0 */
+ if (addr == 0x60) {
+ if (tea5767_autodetection(&t->i2c) != EINVAL) {
+ t->type = TUNER_TEA5767;
+ t->mode_mask = T_RADIO;
+ t->mode = T_STANDBY;
+ t->freq = 87.5 * 16; /* Sets freq to FM range */
+ default_mode_mask &= ~T_RADIO;
+
+ i2c_attach_client (&t->i2c);
+ set_type(&t->i2c,t->type, t->mode_mask);
+ return 0;
+ }
+ }
- i2c_attach_client(&t->i2c);
- tuner_info("chip found @ 0x%x (%s)\n",
- addr << 1, adap->name);
- set_type(&t->i2c, t->type);
+ /* Initializes only the first adapter found */
+ if (default_mode_mask != T_UNINITIALIZED) {
+ tuner_dbg ("Setting mode_mask to 0x%02x\n", default_mode_mask);
+ t->mode_mask = default_mode_mask;
+ t->freq = 400 * 16; /* Sets freq to VHF High */
+ default_mode_mask = T_UNINITIALIZED;
+ }
+
+ /* Should be just before return */
+ i2c_attach_client (&t->i2c);
+ set_type (&t->i2c,t->type, t->mode_mask);
return 0;
}
@@ -226,7 +352,8 @@ static int tuner_probe(struct i2c_adapter *adap)
normal_i2c[0] = addr;
normal_i2c[1] = I2C_CLIENT_END;
}
- this_adap = 0;
+
+ default_mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
if (adap->class & I2C_CLASS_TV_ANALOG)
return i2c_probe(adap, &addr_data, tuner_attach);
@@ -236,38 +363,78 @@ static int tuner_probe(struct i2c_adapter *adap)
static int tuner_detach(struct i2c_client *client)
{
struct tuner *t = i2c_get_clientdata(client);
+ int err;
+
+ err = i2c_detach_client(&t->i2c);
+ if (err) {
+ tuner_warn
+ ("Client deregistration failed, client not detached.\n");
+ return err;
+ }
- i2c_detach_client(&t->i2c);
kfree(t);
return 0;
}
-#define SWITCH_V4L2 if (!t->using_v4l2 && tuner_debug) \
- tuner_info("switching to v4l2\n"); \
- t->using_v4l2 = 1;
-#define CHECK_V4L2 if (t->using_v4l2) { if (tuner_debug) \
- tuner_info("ignore v4l1 call\n"); \
- return 0; }
+/*
+ * Switch tuner to other mode. If tuner support both tv and radio,
+ * set another frequency to some value (This is needed for some pal
+ * tuners to avoid locking). Otherwise, just put second tuner in
+ * standby mode.
+ */
-static int
-tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+static inline int set_mode(struct i2c_client *client, struct tuner *t, int mode, char *cmd)
{
- struct tuner *t = i2c_get_clientdata(client);
- unsigned int *iarg = (int*)arg;
+ if (mode != t->mode) {
+
+ t->mode = mode;
+ if (check_mode(t, cmd) == EINVAL) {
+ t->mode = T_STANDBY;
+ if (V4L2_TUNER_RADIO == mode) {
+ set_tv_freq(client, 400 * 16);
+ } else {
+ set_radio_freq(client, 87.5 * 16000);
+ }
+ return EINVAL;
+ }
+ }
+ return 0;
+}
+
+#define switch_v4l2() if (!t->using_v4l2) \
+ tuner_dbg("switching to v4l2\n"); \
+ t->using_v4l2 = 1;
- switch (cmd) {
+static inline int check_v4l2(struct tuner *t)
+{
+ if (t->using_v4l2) {
+ tuner_dbg ("ignore v4l1 call\n");
+ return EINVAL;
+ }
+ return 0;
+}
+static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
+{
+ struct tuner *t = i2c_get_clientdata(client);
+ unsigned int *iarg = (int *)arg;
+
+ switch (cmd) {
/* --- configuration --- */
- case TUNER_SET_TYPE:
- set_type(client,*iarg);
+ case TUNER_SET_TYPE_ADDR:
+ tuner_dbg ("Calling set_type_addr for type=%d, addr=0x%02x, mode=0x%02x\n",
+ ((struct tuner_setup *)arg)->type,
+ ((struct tuner_setup *)arg)->addr,
+ ((struct tuner_setup *)arg)->mode_mask);
+
+ set_addr(client, (struct tuner_setup *)arg);
break;
case AUDC_SET_RADIO:
- if (V4L2_TUNER_RADIO != t->mode) {
- set_tv_freq(client,400 * 16);
- t->mode = V4L2_TUNER_RADIO;
- }
+ set_mode(client,t,V4L2_TUNER_RADIO, "AUDC_SET_RADIO");
break;
case AUDC_CONFIG_PINNACLE:
+ if (check_mode(t, "AUDC_CONFIG_PINNACLE") == EINVAL)
+ return 0;
switch (*iarg) {
case 2:
tuner_dbg("pinnacle pal\n");
@@ -278,154 +445,239 @@ tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
t->radio_if2 = 41300 * 1000;
break;
}
- break;
-
+ break;
+ case TDA9887_SET_CONFIG:
+ break;
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
case VIDIOCSCHAN:
- {
- static const v4l2_std_id map[] = {
- [ VIDEO_MODE_PAL ] = V4L2_STD_PAL,
- [ VIDEO_MODE_NTSC ] = V4L2_STD_NTSC_M,
- [ VIDEO_MODE_SECAM ] = V4L2_STD_SECAM,
- [ 4 /* bttv */ ] = V4L2_STD_PAL_M,
- [ 5 /* bttv */ ] = V4L2_STD_PAL_N,
- [ 6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
- };
- struct video_channel *vc = arg;
-
- CHECK_V4L2;
- t->mode = V4L2_TUNER_ANALOG_TV;
- if (vc->norm < ARRAY_SIZE(map))
- t->std = map[vc->norm];
- tuner_fixup_std(t);
- if (t->freq)
- set_tv_freq(client,t->freq);
- return 0;
- }
+ {
+ static const v4l2_std_id map[] = {
+ [VIDEO_MODE_PAL] = V4L2_STD_PAL,
+ [VIDEO_MODE_NTSC] = V4L2_STD_NTSC_M,
+ [VIDEO_MODE_SECAM] = V4L2_STD_SECAM,
+ [4 /* bttv */ ] = V4L2_STD_PAL_M,
+ [5 /* bttv */ ] = V4L2_STD_PAL_N,
+ [6 /* bttv */ ] = V4L2_STD_NTSC_M_JP,
+ };
+ struct video_channel *vc = arg;
+
+ if (check_v4l2(t) == EINVAL)
+ return 0;
+
+ if (set_mode(client,t,V4L2_TUNER_ANALOG_TV, "VIDIOCSCHAN")==EINVAL)
+ return 0;
+
+ if (vc->norm < ARRAY_SIZE(map))
+ t->std = map[vc->norm];
+ tuner_fixup_std(t);
+ if (t->freq)
+ set_tv_freq(client, t->freq);
+ return 0;
+ }
case VIDIOCSFREQ:
- {
- unsigned long *v = arg;
+ {
+ unsigned long *v = arg;
- CHECK_V4L2;
- set_freq(client,*v);
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *vt = arg;
+ if (check_mode(t, "VIDIOCSFREQ") == EINVAL)
+ return 0;
+ if (check_v4l2(t) == EINVAL)
+ return 0;
- CHECK_V4L2;
- if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
- vt->signal = t->has_signal(client);
- return 0;
- }
+ set_freq(client, *v);
+ return 0;
+ }
+ case VIDIOCGTUNER:
+ {
+ struct video_tuner *vt = arg;
+
+ if (check_mode(t, "VIDIOCGTUNER") == EINVAL)
+ return 0;
+ if (check_v4l2(t) == EINVAL)
+ return 0;
+
+ if (V4L2_TUNER_RADIO == t->mode) {
+ if (t->has_signal)
+ vt->signal = t->has_signal(client);
+ if (t->is_stereo) {
+ if (t->is_stereo(client))
+ vt->flags |=
+ VIDEO_TUNER_STEREO_ON;
+ else
+ vt->flags &=
+ ~VIDEO_TUNER_STEREO_ON;
+ }
+ vt->flags |= VIDEO_TUNER_LOW; /* Allow freqs at 62.5 Hz */
+
+ vt->rangelow = radio_range[0] * 16000;
+ vt->rangehigh = radio_range[1] * 16000;
+
+ } else {
+ vt->rangelow = tv_range[0] * 16;
+ vt->rangehigh = tv_range[1] * 16;
+ }
+
+ return 0;
+ }
case VIDIOCGAUDIO:
- {
- struct video_audio *va = arg;
-
- CHECK_V4L2;
- if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
- va->mode = t->is_stereo(client)
- ? VIDEO_SOUND_STEREO
- : VIDEO_SOUND_MONO;
- return 0;
- }
+ {
+ struct video_audio *va = arg;
+
+ if (check_mode(t, "VIDIOCGAUDIO") == EINVAL)
+ return 0;
+ if (check_v4l2(t) == EINVAL)
+ return 0;
+
+ if (V4L2_TUNER_RADIO == t->mode && t->is_stereo)
+ va->mode = t->is_stereo(client)
+ ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO;
+ return 0;
+ }
case VIDIOC_S_STD:
- {
- v4l2_std_id *id = arg;
-
- SWITCH_V4L2;
- t->mode = V4L2_TUNER_ANALOG_TV;
- t->std = *id;
- tuner_fixup_std(t);
- if (t->freq)
- set_freq(client,t->freq);
- break;
- }
+ {
+ v4l2_std_id *id = arg;
+
+ if (set_mode (client, t, V4L2_TUNER_ANALOG_TV, "VIDIOC_S_STD")
+ == EINVAL)
+ return 0;
+
+ switch_v4l2();
+
+ t->std = *id;
+ tuner_fixup_std(t);
+ if (t->freq)
+ set_freq(client, t->freq);
+ break;
+ }
case VIDIOC_S_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
-
- SWITCH_V4L2;
- if (V4L2_TUNER_RADIO == f->type &&
- V4L2_TUNER_RADIO != t->mode)
- set_tv_freq(client,400*16);
- t->mode = f->type;
- set_freq(client,f->frequency);
- break;
- }
- case VIDIOC_G_FREQUENCY:
- {
- struct v4l2_frequency *f = arg;
+ {
+ struct v4l2_frequency *f = arg;
+
+ t->freq = f->frequency;
+ switch_v4l2();
+ if (V4L2_TUNER_RADIO == f->type &&
+ V4L2_TUNER_RADIO != t->mode) {
+ if (set_mode (client, t, f->type, "VIDIOC_S_FREQUENCY")
+ == EINVAL)
+ return 0;
+ }
+ set_freq(client,t->freq);
- SWITCH_V4L2;
- f->type = t->mode;
- f->frequency = t->freq;
- break;
- }
+ break;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ if (check_mode(t, "VIDIOC_G_FREQUENCY") == EINVAL)
+ return 0;
+ switch_v4l2();
+ f->type = t->mode;
+ f->frequency = t->freq;
+ break;
+ }
case VIDIOC_G_TUNER:
- {
- struct v4l2_tuner *tuner = arg;
-
- SWITCH_V4L2;
- if (V4L2_TUNER_RADIO == t->mode && t->has_signal)
- tuner->signal = t->has_signal(client);
- tuner->rangelow = tv_range[0] * 16;
- tuner->rangehigh = tv_range[1] * 16;
- break;
- }
+ {
+ struct v4l2_tuner *tuner = arg;
+
+ if (check_mode(t, "VIDIOC_G_TUNER") == EINVAL)
+ return 0;
+ switch_v4l2();
+
+ if (V4L2_TUNER_RADIO == t->mode) {
+
+ if (t->has_signal)
+ tuner->signal = t->has_signal(client);
+
+ if (t->is_stereo) {
+ if (t->is_stereo(client)) {
+ tuner->rxsubchans =
+ V4L2_TUNER_SUB_STEREO |
+ V4L2_TUNER_SUB_MONO;
+ } else {
+ tuner->rxsubchans =
+ V4L2_TUNER_SUB_MONO;
+ }
+ }
+
+ tuner->capability |=
+ V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+
+ tuner->audmode = t->audmode;
+
+ tuner->rangelow = radio_range[0] * 16000;
+ tuner->rangehigh = radio_range[1] * 16000;
+ } else {
+ tuner->rangelow = tv_range[0] * 16;
+ tuner->rangehigh = tv_range[1] * 16;
+ }
+ break;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *tuner = arg;
+
+ if (check_mode(t, "VIDIOC_S_TUNER") == EINVAL)
+ return 0;
+
+ switch_v4l2();
+
+ if (V4L2_TUNER_RADIO == t->mode) {
+ t->audmode = tuner->audmode;
+ set_radio_freq(client, t->freq);
+ }
+ break;
+ }
default:
- /* nothing */
+ tuner_dbg("Unimplemented IOCTL 0x%08x called to tuner.\n", cmd);
break;
}
return 0;
}
-static int tuner_suspend(struct device * dev, pm_message_t state, u32 level)
+static int tuner_suspend(struct device *dev, u32 state, u32 level)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tuner *t = i2c_get_clientdata(c);
+ struct i2c_client *c = container_of (dev, struct i2c_client, dev);
+ struct tuner *t = i2c_get_clientdata (c);
- tuner_dbg("suspend\n");
+ tuner_dbg ("suspend\n");
/* FIXME: power down ??? */
return 0;
}
-static int tuner_resume(struct device * dev, u32 level)
+static int tuner_resume(struct device *dev, u32 level)
{
- struct i2c_client *c = container_of(dev, struct i2c_client, dev);
- struct tuner *t = i2c_get_clientdata(c);
+ struct i2c_client *c = container_of (dev, struct i2c_client, dev);
+ struct tuner *t = i2c_get_clientdata (c);
- tuner_dbg("resume\n");
+ tuner_dbg ("resume\n");
if (t->freq)
- set_freq(c,t->freq);
+ set_freq(c, t->freq);
return 0;
}
/* ----------------------------------------------------------------------- */
static struct i2c_driver driver = {
- .owner = THIS_MODULE,
- .name = "tuner",
- .id = I2C_DRIVERID_TUNER,
- .flags = I2C_DF_NOTIFY,
- .attach_adapter = tuner_probe,
- .detach_client = tuner_detach,
- .command = tuner_command,
+ .owner = THIS_MODULE,
+ .name = "tuner",
+ .id = I2C_DRIVERID_TUNER,
+ .flags = I2C_DF_NOTIFY,
+ .attach_adapter = tuner_probe,
+ .detach_client = tuner_detach,
+ .command = tuner_command,
.driver = {
- .suspend = tuner_suspend,
- .resume = tuner_resume,
- },
+ .suspend = tuner_suspend,
+ .resume = tuner_resume,
+ },
};
-static struct i2c_client client_template =
-{
+static struct i2c_client client_template = {
I2C_DEVNAME("(tuner unset)"),
- .flags = I2C_CLIENT_ALLOW_USE,
- .driver = &driver,
+ .flags = I2C_CLIENT_ALLOW_USE,
+ .driver = &driver,
};
static int __init tuner_init_module(void)
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index 48c6ceff1dc2..a3f8e83f5314 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -1,5 +1,5 @@
/*
- * $Id: tuner-simple.c,v 1.10 2005/03/08 08:38:00 kraxel Exp $
+ * $Id: tuner-simple.c,v 1.39 2005/07/07 01:49:30 mkrufky Exp $
*
* i2c tv tuner chip device driver
* controls all those simple 4-control-bytes style tuners.
@@ -54,6 +54,27 @@
#define PHILIPS_MF_SET_PAL_L 0x03 // France
#define PHILIPS_MF_SET_PAL_L2 0x02 // L'
+/* Control byte */
+
+#define TUNER_RATIO_MASK 0x06 /* Bit cb1:cb2 */
+#define TUNER_RATIO_SELECT_50 0x00
+#define TUNER_RATIO_SELECT_32 0x02
+#define TUNER_RATIO_SELECT_166 0x04
+#define TUNER_RATIO_SELECT_62 0x06
+
+#define TUNER_CHARGE_PUMP 0x40 /* Bit cb6 */
+
+/* Status byte */
+
+#define TUNER_POR 0x80
+#define TUNER_FL 0x40
+#define TUNER_MODE 0x38
+#define TUNER_AFC 0x07
+#define TUNER_SIGNAL 0x07
+#define TUNER_STEREO 0x10
+
+#define TUNER_PLL_LOCKED 0x40
+#define TUNER_STEREO_MK3 0x04
/* ---------------------------------------------------------------------- */
@@ -207,12 +228,25 @@ static struct tunertype tuners[] = {
{ "LG PAL (TAPE series)", LGINNOTEK, PAL,
16*170.00, 16*450.00, 0x01,0x02,0x08,0xce,623},
- { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
- 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
- { "Philips FQ1236A MK4", Philips, NTSC,
- 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+ { "Philips PAL/SECAM multi (FQ1216AME MK4)", Philips, PAL,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0xce,623 },
+ { "Philips FQ1236A MK4", Philips, NTSC,
+ 16*160.00,16*442.00,0x01,0x02,0x04,0x8e,732 },
+ { "Ymec TVision TVF-8531MF/8831MF/8731MF", Philips, NTSC,
+ 16*160.00,16*454.00,0xa0,0x90,0x30,0x8e,732},
+ { "Ymec TVision TVF-5533MF", Philips, NTSC,
+ 16*160.00,16*454.00,0x01,0x02,0x04,0x8e,732},
+ { "Thomson DDT 7611 (ATSC/NTSC)", THOMSON, ATSC,
+ 16*157.25,16*454.00,0x39,0x3a,0x3c,0x8e,732},
+ { "Tena TNF9533-D/IF/TNF9533-B/DF", Philips, PAL,
+ 16*160.25,16*464.25,0x01,0x02,0x04,0x8e,623},
+ { "Philips TEA5767HN FM Radio", Philips, RADIO,
+ /* see tea5767.c for details */},
+ { "Philips FMD1216ME MK3 Hybrid Tuner", Philips, PAL,
+ 16*160.00,16*442.00,0x51,0x52,0x54,0x86,623 },
};
+
unsigned const int tuner_count = ARRAY_SIZE(tuners);
/* ---------------------------------------------------------------------- */
@@ -223,43 +257,35 @@ static int tuner_getstatus(struct i2c_client *c)
if (1 != i2c_master_recv(c,&byte,1))
return 0;
+
return byte;
}
-#define TUNER_POR 0x80
-#define TUNER_FL 0x40
-#define TUNER_MODE 0x38
-#define TUNER_AFC 0x07
-
-#define TUNER_STEREO 0x10 /* radio mode */
-#define TUNER_SIGNAL 0x07 /* radio mode */
-
static int tuner_signal(struct i2c_client *c)
{
- return (tuner_getstatus(c) & TUNER_SIGNAL)<<13;
+ return (tuner_getstatus(c) & TUNER_SIGNAL) << 13;
}
static int tuner_stereo(struct i2c_client *c)
{
- return (tuner_getstatus (c) & TUNER_STEREO);
-}
+ int stereo, status;
+ struct tuner *t = i2c_get_clientdata(c);
-#if 0 /* unused */
-static int tuner_islocked (struct i2c_client *c)
-{
- return (tuner_getstatus (c) & TUNER_FL);
-}
+ status = tuner_getstatus (c);
-static int tuner_afcstatus (struct i2c_client *c)
-{
- return (tuner_getstatus (c) & TUNER_AFC) - 2;
-}
+ switch (t->type) {
+ case TUNER_PHILIPS_FM1216ME_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FM1256_IH3:
+ stereo = ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+ break;
+ default:
+ stereo = status & TUNER_STEREO;
+ }
-static int tuner_mode (struct i2c_client *c)
-{
- return (tuner_getstatus (c) & TUNER_MODE) >> 3;
+ return stereo;
}
-#endif
+
/* ---------------------------------------------------------------------- */
@@ -342,7 +368,7 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
case TUNER_MICROTUNE_4042FI5:
/* Set the charge pump for fast tuning */
- tun->config |= 0x40;
+ tun->config |= TUNER_CHARGE_PUMP;
break;
}
@@ -391,14 +417,13 @@ static void default_set_tv_freq(struct i2c_client *c, unsigned int freq)
tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
break;
}
- /* bit 6 is PLL locked indicator */
- if (status_byte & 0x40)
+ if (status_byte & TUNER_PLL_LOCKED)
break;
udelay(10);
}
/* Set the charge pump for optimized phase noise figure */
- tun->config &= ~0x40;
+ tun->config &= ~TUNER_CHARGE_PUMP;
buffer[0] = (div>>8) & 0x7f;
buffer[1] = div & 0xff;
buffer[2] = tun->config;
@@ -419,18 +444,22 @@ static void default_set_radio_freq(struct i2c_client *c, unsigned int freq)
unsigned div;
int rc;
- tun=&tuners[t->type];
- div = freq + (int)(16*10.7);
- buffer[2] = tun->config;
+ tun = &tuners[t->type];
+ div = (20 * freq / 16000) + (int)(20*10.7); /* IF 10.7 MHz */
+ buffer[2] = (tun->config & ~TUNER_RATIO_MASK) | TUNER_RATIO_SELECT_50; /* 50 kHz step */
switch (t->type) {
+ case TUNER_TENA_9533_DI:
+ case TUNER_YMEC_TVF_5533MF:
+ tuner_dbg ("This tuner doesn't have FM. Most cards has a TEA5767 for FM\n");
+ return;
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FMD1216ME_MK3:
buffer[3] = 0x19;
break;
case TUNER_PHILIPS_FM1256_IH3:
- div = (20 * freq)/16 + 333 * 2;
- buffer[2] = 0x80;
+ div = (20 * freq) / 16000 + (int)(33.3 * 20); /* IF 33.3 MHz */
buffer[3] = 0x19;
break;
case TUNER_LG_PAL_FM:
@@ -462,6 +491,7 @@ int default_tuner_init(struct i2c_client *c)
t->radio_freq = default_set_radio_freq;
t->has_signal = tuner_signal;
t->is_stereo = tuner_stereo;
+
return 0;
}
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 41b635e0d3c6..d8b78f1d686b 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -285,7 +285,6 @@ static int chip_thread(void *data)
schedule();
}
remove_wait_queue(&chip->wq, &wait);
- try_to_freeze(PF_FREEZE);
if (chip->done || signal_pending(current))
break;
dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
@@ -865,13 +864,8 @@ static int tda9874a_getmode(struct CHIPSTATE *chip)
* But changing the mode to VIDEO_SOUND_MONO would switch
* external 4052 multiplexer in audio_hook().
*/
-#if 0
- if((nsr & 0x02) && !(dsr & 0x10)) /* NSR.S/MB=1 and DSR.AMSTAT=0 */
- mode |= VIDEO_SOUND_STEREO;
-#else
if(nsr & 0x02) /* NSR.S/MB=1 */
mode |= VIDEO_SOUND_STEREO;
-#endif
if(nsr & 0x01) /* NSR.D/SB=1 */
mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
} else {
@@ -1237,17 +1231,17 @@ static int ta8874z_checkit(struct CHIPSTATE *chip)
/* audio chip descriptions - struct CHIPDESC */
/* insmod options to enable/disable individual audio chips */
-int tda8425 = 1;
-int tda9840 = 1;
-int tda9850 = 1;
-int tda9855 = 1;
-int tda9873 = 1;
-int tda9874a = 1;
-int tea6300 = 0; // address clash with msp34xx
-int tea6320 = 0; // address clash with msp34xx
-int tea6420 = 1;
-int pic16c54 = 1;
-int ta8874z = 0; // address clash with tda9840
+static int tda8425 = 1;
+static int tda9840 = 1;
+static int tda9850 = 1;
+static int tda9855 = 1;
+static int tda9873 = 1;
+static int tda9874a = 1;
+static int tea6300 = 0; // address clash with msp34xx
+static int tea6320 = 0; // address clash with msp34xx
+static int tea6420 = 1;
+static int pic16c54 = 1;
+static int ta8874z = 0; // address clash with tda9840
module_param(tda8425, int, 0444);
module_param(tda9840, int, 0444);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 3d216973798c..e8d9440977cb 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -75,7 +75,7 @@ hauppauge_tuner_fmt[] =
{ 0x00000007, "PAL(B/G)" },
{ 0x00001000, "NTSC(M)" },
{ 0x00000010, "PAL(I)" },
- { 0x00400000, "SECAM(L/L�)" },
+ { 0x00400000, "SECAM(L/L´)" },
{ 0x00000e00, "PAL(D/K)" },
{ 0x03000000, "ATSC Digital" },
};
@@ -400,14 +400,6 @@ void tveeprom_hauppauge_analog(struct tveeprom *tvee, unsigned char *eeprom_data
}
}
-#if 0
- if (t_format < sizeof(hauppauge_tuner_fmt)/sizeof(struct HAUPPAUGE_TUNER_FMT)) {
- tvee->tuner_formats = hauppauge_tuner_fmt[t_format].id;
- t_fmt_name = hauppauge_tuner_fmt[t_format].name;
- } else {
- t_fmt_name = "<unknown>";
- }
-#endif
TVEEPROM_KERN_INFO("Hauppauge: model = %d, rev = %s, serial# = %d\n",
tvee->model,
@@ -482,6 +474,7 @@ static unsigned short normal_i2c[] = {
0xa0 >> 1,
I2C_CLIENT_END,
};
+
I2C_CLIENT_INSMOD;
struct i2c_driver i2c_driver_tveeprom;
diff --git a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
index eafd7061b310..51b99cdbf29e 100644
--- a/drivers/media/video/tvmixer.c
+++ b/drivers/media/video/tvmixer.c
@@ -1,3 +1,7 @@
+/*
+ * $Id: tvmixer.c,v 1.8 2005/06/12 04:19:19 mchehab Exp $
+ */
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index b0d4bcb027d0..70ecbdb80277 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -1,4 +1,6 @@
/*
+ * $Id: v4l1-compat.c,v 1.9 2005/06/12 04:19:19 mchehab Exp $
+ *
* Video for Linux Two
* Backward Compatibility Layer
*
@@ -15,14 +17,11 @@
*
*/
-#ifndef __KERNEL__
-#define __KERNEL__
-#endif
-
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -787,12 +786,15 @@ v4l_compat_translate_ioctl(struct inode *inode,
!(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
aud->step = qctrl2.step;
aud->mode = 0;
+
+ memset(&tun2,0,sizeof(tun2));
err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
if (err < 0) {
dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n",err);
err = 0;
break;
}
+
if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
diff --git a/drivers/media/video/video-buf-dvb.c b/drivers/media/video/video-buf-dvb.c
index 5f870075b55e..15f5bb486963 100644
--- a/drivers/media/video/video-buf-dvb.c
+++ b/drivers/media/video/video-buf-dvb.c
@@ -62,8 +62,7 @@ static int videobuf_dvb_thread(void *data)
break;
if (kthread_should_stop())
break;
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
/* feed buffer data to demux */
if (buf->state == STATE_DONE)
diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c
index 8b623278ccd2..ffbe6f4720e1 100644
--- a/drivers/message/fusion/mptbase.c
+++ b/drivers/message/fusion/mptbase.c
@@ -1363,19 +1363,7 @@ mpt_suspend(struct pci_dev *pdev, pm_message_t state)
u32 device_state;
MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
- switch(state)
- {
- case 1: /* S1 */
- device_state=1; /* D1 */;
- break;
- case 3: /* S3 */
- case 4: /* S4 */
- device_state=3; /* D3 */;
- break;
- default:
- return -EAGAIN /*FIXME*/;
- break;
- }
+ device_state=pci_choose_state(pdev, state);
printk(MYIOC_s_INFO_FMT
"pci-suspend: pdev=0x%p, slot=%s, Entering operating state [D%d]\n",
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c
index d8d65397e06e..353deb25e397 100644
--- a/drivers/message/fusion/mptfc.c
+++ b/drivers/message/fusion/mptfc.c
@@ -364,9 +364,7 @@ static struct pci_driver mptfc_driver = {
.id_table = mptfc_pci_table,
.probe = mptfc_probe,
.remove = __devexit_p(mptscsih_remove),
- .driver = {
- .shutdown = mptscsih_shutdown,
- },
+ .shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
.resume = mptscsih_resume,
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index a0078ae5b9b8..4f973a49be4c 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -170,7 +170,7 @@ static void mptscsih_fillbuf(char *buffer, int size, int index, int width);
#endif
void mptscsih_remove(struct pci_dev *);
-void mptscsih_shutdown(struct device *);
+void mptscsih_shutdown(struct pci_dev *);
#ifdef CONFIG_PM
int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
int mptscsih_resume(struct pci_dev *pdev);
@@ -988,7 +988,7 @@ mptscsih_remove(struct pci_dev *pdev)
#endif
#endif
- mptscsih_shutdown(&pdev->dev);
+ mptscsih_shutdown(pdev);
sz1=0;
@@ -1026,9 +1026,9 @@ mptscsih_remove(struct pci_dev *pdev)
*
*/
void
-mptscsih_shutdown(struct device * dev)
+mptscsih_shutdown(struct pci_dev *pdev)
{
- MPT_ADAPTER *ioc = pci_get_drvdata(to_pci_dev(dev));
+ MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
struct Scsi_Host *host = ioc->sh;
MPT_SCSI_HOST *hd;
@@ -1054,7 +1054,7 @@ mptscsih_shutdown(struct device * dev)
int
mptscsih_suspend(struct pci_dev *pdev, pm_message_t state)
{
- mptscsih_shutdown(&pdev->dev);
+ mptscsih_shutdown(pdev);
return mpt_suspend(pdev,state);
}
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index d73aec33e16a..debb8ac59545 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -82,9 +82,9 @@
#endif
extern void mptscsih_remove(struct pci_dev *);
-extern void mptscsih_shutdown(struct device *);
+extern void mptscsih_shutdown(struct pci_dev *);
#ifdef CONFIG_PM
-extern int mptscsih_suspend(struct pci_dev *pdev, u32 state);
+extern int mptscsih_suspend(struct pci_dev *pdev, pm_message_t state);
extern int mptscsih_resume(struct pci_dev *pdev);
#endif
extern int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int func);
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 5f9a61b85b3b..e0c0ee5bc966 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -419,9 +419,7 @@ static struct pci_driver mptspi_driver = {
.id_table = mptspi_pci_table,
.probe = mptspi_probe,
.remove = __devexit_p(mptscsih_remove),
- .driver = {
- .shutdown = mptscsih_shutdown,
- },
+ .shutdown = mptscsih_shutdown,
#ifdef CONFIG_PM
.suspend = mptscsih_suspend,
.resume = mptscsih_resume,
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
index 8d132b0d6b12..06e8eb19a05c 100644
--- a/drivers/message/i2o/Kconfig
+++ b/drivers/message/i2o/Kconfig
@@ -24,10 +24,28 @@ config I2O
If unsure, say N.
+config I2O_EXT_ADAPTEC
+ bool "Enable Adaptec extensions"
+ depends on I2O
+ default y
+ ---help---
+ Say Y for support of raidutils for Adaptec I2O controllers. You also
+ have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
+ and to "SCSI generic support" under "SCSI device configuration".
+
+config I2O_EXT_ADAPTEC_DMA64
+ bool "Enable 64-bit DMA"
+ depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
+ default y
+ ---help---
+ Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
+ controllers.
+ Note: You need at least firmware version 3709.
+
config I2O_CONFIG
tristate "I2O Configuration support"
- depends on PCI && I2O
- help
+ depends on I2O
+ ---help---
Say Y for support of the configuration interface for the I2O adapters.
If you have a RAID controller from Adaptec and you want to use the
raidutils to manage your RAID array, you have to say Y here.
@@ -35,10 +53,28 @@ config I2O_CONFIG
To compile this support as a module, choose M here: the
module will be called i2o_config.
+config I2O_CONFIG_OLD_IOCTL
+ bool "Enable ioctls (OBSOLETE)"
+ depends on I2O_CONFIG
+ default y
+ ---help---
+ Enables old ioctls.
+
+config I2O_BUS
+ tristate "I2O Bus Adapter OSM"
+ depends on I2O
+ ---help---
+ Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
+ provides access to the busses on the I2O controller. The main purpose
+ is to rescan the bus to find new devices.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_bus.
+
config I2O_BLOCK
tristate "I2O Block OSM"
depends on I2O
- help
+ ---help---
Include support for the I2O Block OSM. The Block OSM presents disk
and other structured block devices to the operating system. If you
are using an RAID controller, you could access the array only by
@@ -51,7 +87,7 @@ config I2O_BLOCK
config I2O_SCSI
tristate "I2O SCSI OSM"
depends on I2O && SCSI
- help
+ ---help---
Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
I2O controller. You can use both the SCSI and Block OSM together if
you wish. To access a RAID array, you must use the Block OSM driver.
@@ -63,7 +99,7 @@ config I2O_SCSI
config I2O_PROC
tristate "I2O /proc support"
depends on I2O
- help
+ ---help---
If you say Y here and to "/proc file system support", you will be
able to read I2O related information from the virtual directory
/proc/i2o.
diff --git a/drivers/message/i2o/Makefile b/drivers/message/i2o/Makefile
index aabc6cdc3fce..2c2e39aa1efa 100644
--- a/drivers/message/i2o/Makefile
+++ b/drivers/message/i2o/Makefile
@@ -6,8 +6,11 @@
#
i2o_core-y += iop.o driver.o device.o debug.o pci.o exec-osm.o
+i2o_bus-y += bus-osm.o
+i2o_config-y += config-osm.o
obj-$(CONFIG_I2O) += i2o_core.o
obj-$(CONFIG_I2O_CONFIG)+= i2o_config.o
+obj-$(CONFIG_I2O_BUS) += i2o_bus.o
obj-$(CONFIG_I2O_BLOCK) += i2o_block.o
obj-$(CONFIG_I2O_SCSI) += i2o_scsi.o
obj-$(CONFIG_I2O_PROC) += i2o_proc.o
diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
new file mode 100644
index 000000000000..151b228e1cb3
--- /dev/null
+++ b/drivers/message/i2o/bus-osm.c
@@ -0,0 +1,164 @@
+/*
+ * Bus Adapter OSM
+ *
+ * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+
+#define OSM_NAME "bus-osm"
+#define OSM_VERSION "$Rev$"
+#define OSM_DESCRIPTION "I2O Bus Adapter OSM"
+
+static struct i2o_driver i2o_bus_driver;
+
+/* Bus OSM class handling definition */
+static struct i2o_class_id i2o_bus_class_id[] = {
+ {I2O_CLASS_BUS_ADAPTER},
+ {I2O_CLASS_END}
+};
+
+/**
+ * i2o_bus_scan - Scan the bus for new devices
+ * @dev: I2O device of the bus, which should be scanned
+ *
+ * Scans the bus dev for new / removed devices. After the scan a new LCT
+ * will be fetched automatically.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_bus_scan(struct i2o_device *dev)
+{
+ struct i2o_message __iomem *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_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.tid,
+ &msg->u.head[1]);
+
+ return i2o_msg_post_wait(dev->iop, m, 60);
+};
+
+/**
+ * i2o_bus_store_scan - Scan the I2O Bus Adapter
+ * @d: device which should be scanned
+ *
+ * Returns count.
+ */
+static ssize_t i2o_bus_store_scan(struct device *d, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(d);
+ int rc;
+
+ if ((rc = i2o_bus_scan(i2o_dev)))
+ osm_warn("bus scan failed %d\n", rc);
+
+ return count;
+}
+
+/* Bus Adapter OSM device attributes */
+static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
+
+/**
+ * i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
+ * @dev: device to verify if it is a I2O Bus Adapter device
+ *
+ * Because we want all Bus Adapters always return 0.
+ *
+ * Returns 0.
+ */
+static int i2o_bus_probe(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
+
+ device_create_file(dev, &dev_attr_scan);
+
+ osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ return 0;
+};
+
+/**
+ * i2o_bus_remove - remove the I2O Bus Adapter device from the system again
+ * @dev: I2O Bus Adapter device which should be removed
+ *
+ * Always returns 0.
+ */
+static int i2o_bus_remove(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+ device_remove_file(dev, &dev_attr_scan);
+
+ put_device(dev);
+
+ osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ return 0;
+};
+
+/* Bus Adapter OSM driver struct */
+static struct i2o_driver i2o_bus_driver = {
+ .name = OSM_NAME,
+ .classes = i2o_bus_class_id,
+ .driver = {
+ .probe = i2o_bus_probe,
+ .remove = i2o_bus_remove,
+ },
+};
+
+/**
+ * i2o_bus_init - Bus Adapter OSM initialization function
+ *
+ * Only register the Bus Adapter OSM in the I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_bus_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ /* Register Bus Adapter OSM into I2O core */
+ rc = i2o_driver_register(&i2o_bus_driver);
+ if (rc) {
+ osm_err("Could not register Bus Adapter OSM\n");
+ return rc;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_bus_exit - Bus Adapter OSM exit function
+ *
+ * Unregisters Bus Adapter OSM from I2O core.
+ */
+static void __exit i2o_bus_exit(void)
+{
+ i2o_driver_unregister(&i2o_bus_driver);
+};
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_bus_init);
+module_exit(i2o_bus_exit);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
new file mode 100644
index 000000000000..fe2e7afc9eae
--- /dev/null
+++ b/drivers/message/i2o/config-osm.c
@@ -0,0 +1,581 @@
+/*
+ * Configuration OSM
+ *
+ * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/module.h>
+#include <linux/i2o.h>
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+
+#define OSM_NAME "config-osm"
+#define OSM_VERSION "1.248"
+#define OSM_DESCRIPTION "I2O Configuration OSM"
+
+/* access mode user rw */
+#define S_IWRSR (S_IRUSR | S_IWUSR)
+
+static struct i2o_driver i2o_config_driver;
+
+/* Special file operations for sysfs */
+struct fops_attribute {
+ struct bin_attribute bin;
+ struct file_operations fops;
+};
+
+/**
+ * sysfs_read_dummy
+ */
+static ssize_t sysfs_read_dummy(struct kobject *kobj, char *buf, loff_t offset,
+ size_t count)
+{
+ return 0;
+};
+
+/**
+ * sysfs_write_dummy
+ */
+static ssize_t sysfs_write_dummy(struct kobject *kobj, char *buf, loff_t offset,
+ size_t count)
+{
+ return 0;
+};
+
+/**
+ * sysfs_create_fops_file - Creates attribute with special file operations
+ * @kobj: kobject which should contains the attribute
+ * @attr: attributes which should be used to create file
+ *
+ * First creates attribute @attr in kobject @kobj. If it is the first time
+ * this function is called, merge old fops from sysfs with new one and
+ * write it back. Afterwords the new fops will be set for the created
+ * attribute.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int sysfs_create_fops_file(struct kobject *kobj,
+ struct fops_attribute *attr)
+{
+ struct file_operations tmp, *fops;
+ struct dentry *d;
+ struct qstr qstr;
+ int rc;
+
+ fops = &attr->fops;
+
+ if (fops->read)
+ attr->bin.read = sysfs_read_dummy;
+
+ if (fops->write)
+ attr->bin.write = sysfs_write_dummy;
+
+ if ((rc = sysfs_create_bin_file(kobj, &attr->bin)))
+ return rc;
+
+ qstr.name = attr->bin.attr.name;
+ qstr.len = strlen(qstr.name);
+ qstr.hash = full_name_hash(qstr.name, qstr.len);
+
+ if ((d = lookup_hash(&qstr, kobj->dentry))) {
+ if (!fops->owner) {
+ memcpy(&tmp, d->d_inode->i_fop, sizeof(tmp));
+ if (fops->read)
+ tmp.read = fops->read;
+ if (fops->write)
+ tmp.write = fops->write;
+ memcpy(fops, &tmp, sizeof(tmp));
+ }
+
+ d->d_inode->i_fop = fops;
+ } else
+ sysfs_remove_bin_file(kobj, &attr->bin);
+
+ return -ENOENT;
+};
+
+/**
+ * sysfs_remove_fops_file - Remove attribute with special file operations
+ * @kobj: kobject which contains the attribute
+ * @attr: attributes which are used to create file
+ *
+ * Only wrapper arround sysfs_remove_bin_file()
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static inline int sysfs_remove_fops_file(struct kobject *kobj,
+ struct fops_attribute *attr)
+{
+ return sysfs_remove_bin_file(kobj, &attr->bin);
+};
+
+/**
+ * i2o_config_read_hrt - Returns the HRT of the controller
+ * @kob: kernel object handle
+ * @buf: buffer into which the HRT should be copied
+ * @off: file offset
+ * @count: number of bytes to read
+ *
+ * Put @count bytes starting at @off into @buf from the HRT of the I2O
+ * controller corresponding to @kobj.
+ *
+ * Returns number of bytes copied into buffer.
+ */
+static ssize_t i2o_config_read_hrt(struct kobject *kobj, char *buf,
+ loff_t offset, size_t count)
+{
+ struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+ i2o_hrt *hrt = c->hrt.virt;
+
+ u32 size = (hrt->num_entries * hrt->entry_len + 2) * 4;
+
+ if (offset > size)
+ return 0;
+
+ if (offset + count > size)
+ count = size - offset;
+
+ memcpy(buf, (u8 *) hrt + offset, count);
+
+ return count;
+};
+
+/**
+ * i2o_config_read_lct - Returns the LCT of the controller
+ * @kob: kernel object handle
+ * @buf: buffer into which the LCT should be copied
+ * @off: file offset
+ * @count: number of bytes to read
+ *
+ * Put @count bytes starting at @off into @buf from the LCT of the I2O
+ * controller corresponding to @kobj.
+ *
+ * Returns number of bytes copied into buffer.
+ */
+static ssize_t i2o_config_read_lct(struct kobject *kobj, char *buf,
+ loff_t offset, size_t count)
+{
+ struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+ u32 size = c->lct->table_size * 4;
+
+ if (offset > size)
+ return 0;
+
+ if (offset + count > size)
+ count = size - offset;
+
+ memcpy(buf, (u8 *) c->lct + offset, count);
+
+ return count;
+};
+
+#define I2O_CONFIG_SW_ATTR(_name,_mode,_type,_swid) \
+static ssize_t i2o_config_##_name##_read(struct file *file, char __user *buf, size_t count, loff_t * offset) { \
+ return i2o_config_sw_read(file, buf, count, offset, _type, _swid); \
+};\
+\
+static ssize_t i2o_config_##_name##_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) { \
+ return i2o_config_sw_write(file, buf, count, offset, _type, _swid); \
+}; \
+\
+static struct fops_attribute i2o_config_attr_##_name = { \
+ .bin = { .attr = { .name = __stringify(_name), .mode = _mode, \
+ .owner = THIS_MODULE }, \
+ .size = 0, }, \
+ .fops = { .write = i2o_config_##_name##_write, \
+ .read = i2o_config_##_name##_read} \
+};
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+
+/**
+ * i2o_config_dpt_reagion - Converts type and id to flash region
+ * @swtype: type of software module reading
+ * @swid: id of software which should be read
+ *
+ * Converts type and id from I2O spec to the matching region for DPT /
+ * Adaptec controllers.
+ *
+ * Returns region which match type and id or -1 on error.
+ */
+static u32 i2o_config_dpt_region(u8 swtype, u8 swid)
+{
+ switch (swtype) {
+ case I2O_SOFTWARE_MODULE_IRTOS:
+ /*
+ * content: operation firmware
+ * region size:
+ * 0xbc000 for 2554, 3754, 2564, 3757
+ * 0x170000 for 2865
+ * 0x17c000 for 3966
+ */
+ if (!swid)
+ return 0;
+
+ break;
+
+ case I2O_SOFTWARE_MODULE_IOP_PRIVATE:
+ /*
+ * content: BIOS and SMOR
+ * BIOS size: first 0x8000 bytes
+ * region size:
+ * 0x40000 for 2554, 3754, 2564, 3757
+ * 0x80000 for 2865, 3966
+ */
+ if (!swid)
+ return 1;
+
+ break;
+
+ case I2O_SOFTWARE_MODULE_IOP_CONFIG:
+ switch (swid) {
+ case 0:
+ /*
+ * content: NVRAM defaults
+ * region size: 0x2000 bytes
+ */
+ return 2;
+ case 1:
+ /*
+ * content: serial number
+ * region size: 0x2000 bytes
+ */
+ return 3;
+ }
+ break;
+ }
+
+ return -1;
+};
+
+#endif
+
+/**
+ * i2o_config_sw_read - Read a software module from controller
+ * @file: file pointer
+ * @buf: buffer into which the data should be copied
+ * @count: number of bytes to read
+ * @off: file offset
+ * @swtype: type of software module reading
+ * @swid: id of software which should be read
+ *
+ * Transfers @count bytes at offset @offset from IOP into buffer using
+ * type @swtype and id @swid as described in I2O spec.
+ *
+ * Returns number of bytes copied into buffer or error code on failure.
+ */
+static ssize_t i2o_config_sw_read(struct file *file, char __user * buf,
+ size_t count, loff_t * offset, u8 swtype,
+ u32 swid)
+{
+ struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata;
+ struct kobject *kobj = sd->s_element;
+ struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+ u32 m, function = I2O_CMD_SW_UPLOAD;
+ struct i2o_dma buffer;
+ struct i2o_message __iomem *msg;
+ u32 __iomem *mptr;
+ int rc, status;
+
+ m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+ if (m == I2O_QUEUE_EMPTY)
+ return -EBUSY;
+
+ mptr = &msg->body[3];
+
+ if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL))) {
+ i2o_msg_nop(c, m);
+ return rc;
+ }
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ mptr = &msg->body[4];
+ function = I2O_CMD_PRIVATE;
+
+ writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]);
+
+ writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_READ,
+ &msg->body[0]);
+ writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]);
+ writel(*offset, &msg->body[2]);
+ writel(count, &msg->body[3]);
+ } else
+#endif
+ writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
+
+ writel(0xD0000000 | count, mptr++);
+ writel(buffer.phys, mptr);
+
+ writel(function << 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]);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (!c->adaptec)
+#endif
+ {
+ writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]);
+ writel(0, &msg->body[1]);
+ writel(swid, &msg->body[2]);
+ }
+
+ status = i2o_msg_post_wait_mem(c, m, 60, &buffer);
+
+ if (status == I2O_POST_WAIT_OK) {
+ if (!(rc = copy_to_user(buf, buffer.virt, count))) {
+ rc = count;
+ *offset += count;
+ }
+ } else
+ rc = -EIO;
+
+ if (status != -ETIMEDOUT)
+ i2o_dma_free(&c->pdev->dev, &buffer);
+
+ return rc;
+};
+
+/**
+ * i2o_config_sw_write - Write a software module to controller
+ * @file: file pointer
+ * @buf: buffer into which the data should be copied
+ * @count: number of bytes to read
+ * @off: file offset
+ * @swtype: type of software module writing
+ * @swid: id of software which should be written
+ *
+ * Transfers @count bytes at offset @offset from buffer to IOP using
+ * type @swtype and id @swid as described in I2O spec.
+ *
+ * Returns number of bytes copied from buffer or error code on failure.
+ */
+static ssize_t i2o_config_sw_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * offset, u8 swtype,
+ u32 swid)
+{
+ struct sysfs_dirent *sd = file->f_dentry->d_parent->d_fsdata;
+ struct kobject *kobj = sd->s_element;
+ struct i2o_controller *c = kobj_to_i2o_device(kobj)->iop;
+ u32 m, function = I2O_CMD_SW_DOWNLOAD;
+ struct i2o_dma buffer;
+ struct i2o_message __iomem *msg;
+ u32 __iomem *mptr;
+ int rc, status;
+
+ m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
+ if (m == I2O_QUEUE_EMPTY)
+ return -EBUSY;
+
+ mptr = &msg->body[3];
+
+ if ((rc = i2o_dma_alloc(&c->pdev->dev, &buffer, count, GFP_KERNEL)))
+ goto nop_msg;
+
+ if ((rc = copy_from_user(buffer.virt, buf, count)))
+ goto free_buffer;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ mptr = &msg->body[4];
+ function = I2O_CMD_PRIVATE;
+
+ writel(TEN_WORD_MSG_SIZE | SGL_OFFSET_8, &msg->u.head[0]);
+
+ writel(I2O_VENDOR_DPT << 16 | I2O_DPT_FLASH_WRITE,
+ &msg->body[0]);
+ writel(i2o_config_dpt_region(swtype, swid), &msg->body[1]);
+ writel(*offset, &msg->body[2]);
+ writel(count, &msg->body[3]);
+ } else
+#endif
+ writel(NINE_WORD_MSG_SIZE | SGL_OFFSET_7, &msg->u.head[0]);
+
+ writel(0xD4000000 | count, mptr++);
+ writel(buffer.phys, mptr);
+
+ writel(function << 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]);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (!c->adaptec)
+#endif
+ {
+ writel((u32) swtype << 16 | (u32) 1 << 8, &msg->body[0]);
+ writel(0, &msg->body[1]);
+ writel(swid, &msg->body[2]);
+ }
+
+ 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)
+ return -EIO;
+
+ *offset += count;
+
+ return count;
+
+ free_buffer:
+ i2o_dma_free(&c->pdev->dev, &buffer);
+
+ nop_msg:
+ i2o_msg_nop(c, m);
+
+ return rc;
+};
+
+/* attribute for HRT in sysfs */
+static struct bin_attribute i2o_config_hrt_attr = {
+ .attr = {
+ .name = "hrt",
+ .mode = S_IRUGO,
+ .owner = THIS_MODULE},
+ .size = 0,
+ .read = i2o_config_read_hrt
+};
+
+/* attribute for LCT in sysfs */
+static struct bin_attribute i2o_config_lct_attr = {
+ .attr = {
+ .name = "lct",
+ .mode = S_IRUGO,
+ .owner = THIS_MODULE},
+ .size = 0,
+ .read = i2o_config_read_lct
+};
+
+/* IRTOS firmware access */
+I2O_CONFIG_SW_ATTR(irtos, S_IWRSR, I2O_SOFTWARE_MODULE_IRTOS, 0);
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+
+/*
+ * attribute for BIOS / SMOR, nvram and serial number access on DPT / Adaptec
+ * controllers
+ */
+I2O_CONFIG_SW_ATTR(bios, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_PRIVATE, 0);
+I2O_CONFIG_SW_ATTR(nvram, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 0);
+I2O_CONFIG_SW_ATTR(serial, S_IWRSR, I2O_SOFTWARE_MODULE_IOP_CONFIG, 1);
+
+#endif
+
+/**
+ * i2o_config_notify_controller_add - Notify of added controller
+ * @c: the controller which was added
+ *
+ * If a I2O controller is added, we catch the notification to add sysfs
+ * entries.
+ */
+static void i2o_config_notify_controller_add(struct i2o_controller *c)
+{
+ struct kobject *kobj = &c->exec->device.kobj;
+
+ sysfs_create_bin_file(kobj, &i2o_config_hrt_attr);
+ sysfs_create_bin_file(kobj, &i2o_config_lct_attr);
+
+ sysfs_create_fops_file(kobj, &i2o_config_attr_irtos);
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ sysfs_create_fops_file(kobj, &i2o_config_attr_bios);
+ sysfs_create_fops_file(kobj, &i2o_config_attr_nvram);
+ sysfs_create_fops_file(kobj, &i2o_config_attr_serial);
+ }
+#endif
+};
+
+/**
+ * i2o_config_notify_controller_remove - Notify of removed controller
+ * @c: the controller which was removed
+ *
+ * If a I2O controller is removed, we catch the notification to remove the
+ * sysfs entries.
+ */
+static void i2o_config_notify_controller_remove(struct i2o_controller *c)
+{
+ struct kobject *kobj = &c->exec->device.kobj;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ sysfs_remove_fops_file(kobj, &i2o_config_attr_serial);
+ sysfs_remove_fops_file(kobj, &i2o_config_attr_nvram);
+ sysfs_remove_fops_file(kobj, &i2o_config_attr_bios);
+ }
+#endif
+ sysfs_remove_fops_file(kobj, &i2o_config_attr_irtos);
+
+ sysfs_remove_bin_file(kobj, &i2o_config_lct_attr);
+ sysfs_remove_bin_file(kobj, &i2o_config_hrt_attr);
+};
+
+/* Config OSM driver struct */
+static struct i2o_driver i2o_config_driver = {
+ .name = OSM_NAME,
+ .notify_controller_add = i2o_config_notify_controller_add,
+ .notify_controller_remove = i2o_config_notify_controller_remove
+};
+
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+#include "i2o_config.c"
+#endif
+
+/**
+ * i2o_config_init - Configuration OSM initialization function
+ *
+ * Registers Configuration OSM in the I2O core and if old ioctl's are
+ * compiled in initialize them.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_config_init(void)
+{
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ if (i2o_driver_register(&i2o_config_driver)) {
+ osm_err("handler register failed.\n");
+ return -EBUSY;
+ }
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+ if (i2o_config_old_init())
+ i2o_driver_unregister(&i2o_config_driver);
+#endif
+
+ return 0;
+}
+
+/**
+ * i2o_config_exit - Configuration OSM exit function
+ *
+ * If old ioctl's are compiled in exit remove them and unregisters
+ * Configuration OSM from I2O core.
+ */
+static void i2o_config_exit(void)
+{
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+ i2o_config_old_exit();
+#endif
+
+ i2o_driver_unregister(&i2o_config_driver);
+}
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_config_init);
+module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/core.h b/drivers/message/i2o/core.h
new file mode 100644
index 000000000000..c5bcfd70f711
--- /dev/null
+++ b/drivers/message/i2o/core.h
@@ -0,0 +1,58 @@
+/*
+ * I2O core internal declarations
+ *
+ * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+/* Exec-OSM */
+extern struct bus_type i2o_bus_type;
+
+extern struct i2o_driver i2o_exec_driver;
+extern int i2o_exec_lct_get(struct i2o_controller *);
+
+extern int __init i2o_exec_init(void);
+extern void __exit i2o_exec_exit(void);
+
+/* driver */
+extern int i2o_driver_dispatch(struct i2o_controller *, u32);
+
+extern int __init i2o_driver_init(void);
+extern void __exit i2o_driver_exit(void);
+
+/* PCI */
+extern int __init i2o_pci_init(void);
+extern void __exit i2o_pci_exit(void);
+
+/* device */
+extern void i2o_device_remove(struct i2o_device *);
+extern int i2o_device_parse_lct(struct i2o_controller *);
+
+extern int i2o_device_init(void);
+extern void i2o_device_exit(void);
+
+/* IOP */
+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 *);
+
+/* config */
+extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+
+/* control registers relative to c->base */
+#define I2O_IRQ_STATUS 0x30
+#define I2O_IRQ_MASK 0x34
+#define I2O_IN_PORT 0x40
+#define I2O_OUT_PORT 0x44
+
+#define I2O_IRQ_OUTBOUND_POST 0x00000008
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
index 2a5d478fc60e..018ca887ca85 100644
--- a/drivers/message/i2o/debug.c
+++ b/drivers/message/i2o/debug.c
@@ -4,8 +4,6 @@
#include <linux/pci.h>
#include <linux/i2o.h>
-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);
static void i2o_report_fail_status(u8 req_status, u32 * msg);
@@ -23,7 +21,6 @@ void i2o_report_status(const char *severity, const char *str,
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
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
index eb907e87bc7b..21f16ba3ac38 100644
--- a/drivers/message/i2o/device.c
+++ b/drivers/message/i2o/device.c
@@ -16,9 +16,7 @@
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
-
-/* Exec OSM functions */
-extern struct bus_type i2o_bus_type;
+#include "core.h"
/**
* i2o_device_issue_claim - claim or release a device
@@ -282,8 +280,7 @@ int i2o_device_parse_lct(struct i2o_controller *c)
down(&c->lct_lock);
- if (c->lct)
- kfree(c->lct);
+ kfree(c->lct);
lct = c->dlct.virt;
@@ -294,12 +291,12 @@ int i2o_device_parse_lct(struct i2o_controller *c)
}
if (lct->table_size * 4 > c->dlct.len) {
- memcpy_fromio(c->lct, c->dlct.virt, c->dlct.len);
+ memcpy(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);
+ memcpy(c->lct, c->dlct.virt, lct->table_size * 4);
lct = c->lct;
@@ -354,7 +351,7 @@ static ssize_t i2o_device_class_show_class_id(struct class_device *cd,
{
struct i2o_device *dev = to_i2o_device(cd->dev);
- sprintf(buf, "%03x\n", dev->lct_data.class_id);
+ sprintf(buf, "0x%03x\n", dev->lct_data.class_id);
return strlen(buf) + 1;
};
@@ -369,7 +366,7 @@ 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);
+ sprintf(buf, "0x%03x\n", dev->lct_data.tid);
return strlen(buf) + 1;
};
@@ -401,25 +398,27 @@ static int i2o_device_class_add(struct class_device *cd)
/* create user entries for this device */
tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
- if (tmp)
+ if (tmp && (tmp != i2o_dev))
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)
+ if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+ && (tmp != i2o_dev))
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)
+ if (tmp && (tmp != i2o_dev))
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)
+ if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+ && (tmp != i2o_dev))
sysfs_create_link(&tmp->device.kobj,
&i2o_dev->device.kobj, "parent");
@@ -444,9 +443,8 @@ static struct class_interface i2o_device_class_interface = {
* 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)
+ int oplen, void *reslist, int reslen)
{
struct i2o_message __iomem *msg;
u32 m;
@@ -489,7 +487,7 @@ int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
if (rc == -ETIMEDOUT)
return rc;
- memcpy_fromio(reslist, res.virt, res.len);
+ memcpy(reslist, res.virt, res.len);
i2o_dma_free(dev, &res);
/* Query failed */
@@ -531,17 +529,23 @@ 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 */
+ u8 *resblk; /* 8 bytes for header */
int size;
if (field == -1) /* whole group */
opblk[4] = -1;
+ resblk = kmalloc(buflen + 8, GFP_KERNEL | GFP_ATOMIC);
+ if (!resblk)
+ return -ENOMEM;
+
size = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
- sizeof(opblk), resblk, sizeof(resblk));
+ sizeof(opblk), resblk, buflen + 8);
memcpy(buf, resblk + 8, buflen); /* cut off header */
+ kfree(resblk);
+
if (size > buflen)
return buflen;
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
index 91f4edbb2a27..739bfdef0c6d 100644
--- a/drivers/message/i2o/driver.c
+++ b/drivers/message/i2o/driver.c
@@ -17,9 +17,12 @@
#include <linux/module.h>
#include <linux/rwsem.h>
#include <linux/i2o.h>
+#include "core.h"
+
+#define OSM_NAME "i2o"
/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
-unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
+static 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");
@@ -76,17 +79,16 @@ int i2o_driver_register(struct i2o_driver *drv)
int rc = 0;
unsigned long flags;
- pr_debug("i2o: Register driver %s\n", drv->name);
+ osm_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);
+ osm_err("Could not initialize event queue for driver "
+ "%s\n", drv->name);
return -EFAULT;
}
- pr_debug("i2o: Event queue initialized for driver %s\n",
- drv->name);
+ osm_debug("Event queue initialized for driver %s\n", drv->name);
} else
drv->event_queue = NULL;
@@ -97,8 +99,8 @@ int i2o_driver_register(struct i2o_driver *drv)
for (i = 0; i2o_drivers[i]; i++)
if (i >= i2o_max_drivers) {
- printk(KERN_ERR "i2o: too many drivers registered, "
- "increase max_drivers\n");
+ osm_err("too many drivers registered, increase "
+ "max_drivers\n");
spin_unlock_irqrestore(&i2o_drivers_lock, flags);
return -EFAULT;
}
@@ -108,18 +110,16 @@ int i2o_driver_register(struct i2o_driver *drv)
spin_unlock_irqrestore(&i2o_drivers_lock, flags);
- pr_debug("i2o: driver %s gets context id %d\n", drv->name,
- drv->context);
+ osm_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);
+ i2o_driver_notify_device_add(drv, i2o_dev);
}
-
rc = driver_register(&drv->driver);
if (rc)
destroy_workqueue(drv->event_queue);
@@ -139,7 +139,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
struct i2o_controller *c;
unsigned long flags;
- pr_debug("i2o: unregister driver %s\n", drv->name);
+ osm_debug("unregister driver %s\n", drv->name);
driver_unregister(&drv->driver);
@@ -159,7 +159,7 @@ void i2o_driver_unregister(struct i2o_driver *drv)
if (drv->event_queue) {
destroy_workqueue(drv->event_queue);
drv->event_queue = NULL;
- pr_debug("i2o: event queue removed for %s\n", drv->name);
+ osm_debug("event queue removed for %s\n", drv->name);
}
};
@@ -176,68 +176,70 @@ void i2o_driver_unregister(struct i2o_driver *drv)
* 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 __iomem *msg)
+int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
{
struct i2o_driver *drv;
- u32 context = readl(&msg->u.s.icntxt);
+ struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
+ u32 context = le32_to_cpu(msg->u.s.icntxt);
+ unsigned long flags;
- if (likely(context < i2o_max_drivers)) {
- spin_lock(&i2o_drivers_lock);
- drv = i2o_drivers[context];
- spin_unlock(&i2o_drivers_lock);
+ if (unlikely(context >= i2o_max_drivers)) {
+ osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+ context);
+ return -EIO;
+ }
- if (unlikely(!drv)) {
- printk(KERN_WARNING "%s: Spurious reply to unknown "
- "driver %d\n", c->name, context);
- return -EIO;
- }
+ spin_lock_irqsave(&i2o_drivers_lock, flags);
+ drv = i2o_drivers[context];
+ spin_unlock_irqrestore(&i2o_drivers_lock, flags);
- 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;
+ if (unlikely(!drv)) {
+ osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+ context);
+ return -EIO;
+ }
- tid = readl(&msg->u.head[1]) & 0x1fff;
+ if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
+ struct i2o_device *dev, *tmp;
+ struct i2o_event *evt;
+ u16 size;
+ u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
- pr_debug("%s: event received from device %d\n", c->name,
- tid);
+ osm_debug("event received from device %d\n", tid);
- /* cut of header from message size (in 32-bit words) */
- size = (readl(&msg->u.head[0]) >> 16) - 5;
+ if (!drv->event)
+ return -EIO;
- evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
- if (!evt)
- return -ENOMEM;
- memset(evt, 0, size * 4 + sizeof(*evt));
+ /* cut of header from message size (in 32-bit words) */
+ size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
- evt->size = size;
- memcpy_fromio(&evt->tcntxt, &msg->u.s.tcntxt,
- (size + 2) * 4);
+ evt = kmalloc(size * 4 + sizeof(*evt), GFP_ATOMIC | __GFP_ZERO);
+ if (!evt)
+ return -ENOMEM;
- list_for_each_entry_safe(dev, tmp, &c->devices, list)
- if (dev->lct_data.tid == tid) {
- evt->i2o_dev = dev;
- break;
- }
+ evt->size = size;
+ evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
+ evt->event_indicator = le32_to_cpu(msg->body[0]);
+ memcpy(&evt->tcntxt, &msg->u.s.tcntxt, size * 4);
- INIT_WORK(&evt->work, (void (*)(void *))drv->event,
- evt);
- queue_work(drv->event_queue, &evt->work);
- return 1;
+ list_for_each_entry_safe(dev, tmp, &c->devices, list)
+ if (dev->lct_data.tid == tid) {
+ evt->i2o_dev = dev;
+ break;
}
- 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);
+ INIT_WORK(&evt->work, (void (*)(void *))drv->event, evt);
+ queue_work(drv->event_queue, &evt->work);
+ return 1;
+ }
+
+ if (unlikely(!drv->reply)) {
+ osm_debug("%s: Reply to driver %s, but no reply function"
+ " defined!\n", c->name, drv->name);
return -EIO;
- } else
- printk(KERN_WARNING "%s: Spurious reply to unknown driver "
- "%d\n", c->name, readl(&msg->u.s.icntxt));
- return -EIO;
+ }
+
+ return drv->reply(c, m, msg);
}
/**
@@ -334,11 +336,11 @@ int __init i2o_driver_init(void)
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);
+ osm_warn("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);
+ osm_info("max drivers = %d\n", i2o_max_drivers);
i2o_drivers =
kmalloc(i2o_max_drivers * sizeof(*i2o_drivers), GFP_KERNEL);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
index 79c1cbfb8f44..bda2c62648ba 100644
--- a/drivers/message/i2o/exec-osm.c
+++ b/drivers/message/i2o/exec-osm.c
@@ -30,6 +30,7 @@
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
+#include "core.h"
#define OSM_NAME "exec-osm"
@@ -37,9 +38,6 @@ struct i2o_driver i2o_exec_driver;
static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind);
-/* 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);
@@ -50,7 +48,7 @@ struct i2o_exec_wait {
u32 tcntxt; /* transaction context from reply */
int complete; /* 1 if reply received otherwise 0 */
u32 m; /* message id */
- struct i2o_message __iomem *msg; /* pointer to the reply message */
+ struct i2o_message *msg; /* pointer to the reply message */
struct list_head list; /* node in global wait list */
};
@@ -108,7 +106,8 @@ static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
* 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.
+ * Returns 0 on success, negative error code on timeout or positive error
+ * code from reply.
*/
int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
timeout, struct i2o_dma *dma)
@@ -116,7 +115,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
DECLARE_WAIT_QUEUE_HEAD(wq);
struct i2o_exec_wait *wait;
static u32 tcntxt = 0x80000000;
- struct i2o_message __iomem *msg = c->in_queue.virt + m;
+ struct i2o_message __iomem *msg = i2o_msg_in_to_virt(c, m);
int rc = 0;
wait = i2o_exec_wait_alloc();
@@ -153,7 +152,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
list_add(&wait->list, &i2o_exec_wait_list);
wait_event_interruptible_timeout(wq, wait->complete,
- timeout * HZ);
+ timeout * HZ);
wait->wq = NULL;
}
@@ -161,8 +160,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
barrier();
if (wait->complete) {
- if (readl(&wait->msg->body[0]) >> 24)
- rc = readl(&wait->msg->body[0]) & 0xff;
+ rc = le32_to_cpu(wait->msg->body[0]) >> 24;
i2o_flush_reply(c, wait->m);
i2o_exec_wait_free(wait);
} else {
@@ -187,6 +185,7 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
* @c: I2O controller which answers
* @m: message id
* @msg: pointer to the I2O reply message
+ * @context: transaction context of request
*
* 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
@@ -201,16 +200,12 @@ int i2o_msg_post_wait_mem(struct i2o_controller *c, u32 m, unsigned long
* 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 __iomem *msg)
+ struct i2o_message *msg, u32 context)
{
struct i2o_exec_wait *wait, *tmp;
- static spinlock_t lock;
+ unsigned long flags;
+ static spinlock_t lock = SPIN_LOCK_UNLOCKED;
int rc = 1;
- u32 context;
-
- spin_lock_init(&lock);
-
- context = readl(&msg->u.s.tcntxt);
/*
* We need to search through the i2o_exec_wait_list to see if the given
@@ -219,11 +214,13 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
* already expired. Not much we can do about that except log it for
* debug purposes, increase timeout, and recompile.
*/
- spin_lock(&lock);
+ spin_lock_irqsave(&lock, flags);
list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
if (wait->tcntxt == context) {
list_del(&wait->list);
+ spin_unlock_irqrestore(&lock, flags);
+
wait->m = m;
wait->msg = msg;
wait->complete = 1;
@@ -245,21 +242,63 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
rc = -1;
}
- spin_unlock(&lock);
-
return rc;
}
}
- spin_unlock(&lock);
+ spin_unlock_irqrestore(&lock, flags);
- pr_debug("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
+ osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
context);
return -1;
};
/**
+ * i2o_exec_show_vendor_id - Displays Vendor ID of controller
+ * @d: device of which the Vendor ID should be displayed
+ * @buf: buffer into which the Vendor ID should be printed
+ *
+ * Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_vendor_id(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct i2o_device *dev = to_i2o_device(d);
+ u16 id;
+
+ if (i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
+ sprintf(buf, "0x%04x", id);
+ return strlen(buf) + 1;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_exec_show_product_id - Displays Product ID of controller
+ * @d: device of which the Product ID should be displayed
+ * @buf: buffer into which the Product ID should be printed
+ *
+ * Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_product_id(struct device *d, struct device_attribute *attr, char *buf)
+{
+ struct i2o_device *dev = to_i2o_device(d);
+ u16 id;
+
+ if (i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
+ sprintf(buf, "0x%04x", id);
+ return strlen(buf) + 1;
+ }
+
+ return 0;
+};
+
+/* Exec-OSM device attributes */
+static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
+
+/**
* i2o_exec_probe - Called if a new I2O device (executive class) appears
* @dev: I2O device which should be probed
*
@@ -271,10 +310,16 @@ static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
static int i2o_exec_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_controller *c = i2o_dev->iop;
i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
- i2o_dev->iop->exec = i2o_dev;
+ c->exec = i2o_dev;
+
+ i2o_exec_lct_notify(c, c->lct->change_ind + 1);
+
+ device_create_file(dev, &dev_attr_vendor_id);
+ device_create_file(dev, &dev_attr_product_id);
return 0;
};
@@ -289,6 +334,9 @@ static int i2o_exec_probe(struct device *dev)
*/
static int i2o_exec_remove(struct device *dev)
{
+ device_remove_file(dev, &dev_attr_product_id);
+ device_remove_file(dev, &dev_attr_vendor_id);
+
i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
return 0;
@@ -300,12 +348,16 @@ static int i2o_exec_remove(struct device *dev)
*
* 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.
+ * again, otherwise send LCT NOTIFY to get informed on next LCT change.
*/
static void i2o_exec_lct_modified(struct i2o_controller *c)
{
- if (i2o_device_parse_lct(c) == -EAGAIN)
- i2o_exec_lct_notify(c, 0);
+ u32 change_ind = 0;
+
+ if (i2o_device_parse_lct(c) != -EAGAIN)
+ change_ind = c->lct->change_ind + 1;
+
+ i2o_exec_lct_notify(c, change_ind);
};
/**
@@ -325,8 +377,14 @@ static void i2o_exec_lct_modified(struct i2o_controller *c)
static int i2o_exec_reply(struct i2o_controller *c, u32 m,
struct i2o_message *msg)
{
- if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) { // Fail bit is set
- struct i2o_message __iomem *pmsg; /* preserved message */
+ u32 context;
+
+ if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
+ /*
+ * If Fail bit is set we must take the transaction context of
+ * the preserved message to find the right request again.
+ */
+ struct i2o_message __iomem *pmsg;
u32 pm;
pm = le32_to_cpu(msg->body[3]);
@@ -335,15 +393,15 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
i2o_report_status(KERN_INFO, "i2o_core", msg);
- /* Release the preserved msg by resubmitting it as a NOP */
- i2o_msg_nop(c, pm);
+ context = readl(&pmsg->u.s.tcntxt);
- /* If reply to i2o_post_wait failed, return causes a timeout */
- return -1;
- }
+ /* Release the preserved msg */
+ i2o_msg_nop(c, pm);
+ } else
+ context = le32_to_cpu(msg->u.s.tcntxt);
- if (le32_to_cpu(msg->u.s.tcntxt) & 0x80000000)
- return i2o_msg_post_wait_complete(c, m, msg);
+ if (context & 0x80000000)
+ return i2o_msg_post_wait_complete(c, m, msg, context);
if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
struct work_struct *work;
@@ -381,8 +439,9 @@ static int i2o_exec_reply(struct i2o_controller *c, u32 m,
*/
static void i2o_exec_event(struct i2o_event *evt)
{
- osm_info("Event received from device: %d\n",
- evt->i2o_dev->lct_data.tid);
+ if (likely(evt->i2o_dev))
+ osm_debug("Event received from device: %d\n",
+ evt->i2o_dev->lct_data.tid);
kfree(evt);
};
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 4830b7759061..f283b5bafdd3 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -62,7 +62,7 @@
#include "i2o_block.h"
#define OSM_NAME "block-osm"
-#define OSM_VERSION "$Rev$"
+#define OSM_VERSION "1.287"
#define OSM_DESCRIPTION "I2O Block Device OSM"
static struct i2o_driver i2o_block_driver;
@@ -104,7 +104,8 @@ 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);
- osm_info("Device removed %s\n", i2o_blk_dev->gd->disk_name);
+ osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+ i2o_blk_dev->gd->disk_name);
i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
@@ -146,6 +147,29 @@ static int i2o_block_device_flush(struct i2o_device *dev)
};
/**
+ * i2o_block_issue_flush - device-flush interface for block-layer
+ * @queue: the request queue of the device which should be flushed
+ * @disk: gendisk
+ * @error_sector: error offset
+ *
+ * Helper function to provide flush functionality to block-layer.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+
+static int i2o_block_issue_flush(request_queue_t * queue, struct gendisk *disk,
+ sector_t * error_sector)
+{
+ struct i2o_block_device *i2o_blk_dev = queue->queuedata;
+ int rc = -ENODEV;
+
+ if (likely(i2o_blk_dev))
+ rc = i2o_block_device_flush(i2o_blk_dev->i2o_dev);
+
+ return rc;
+}
+
+/**
* i2o_block_device_mount - Mount (load) the media of device dev
* @dev: I2O device which should receive the mount request
* @media_id: Media Identifier
@@ -298,28 +322,31 @@ static inline void i2o_block_request_free(struct i2o_block_request *ireq)
/**
* i2o_block_sglist_alloc - Allocate the SG list and map it
+ * @c: I2O controller to which the request belongs
* @ireq: I2O block request
*
- * Builds the SG list and map it into to be accessable by the controller.
+ * Builds the SG list and map it to be accessable by the controller.
*
- * Returns the number of elements in the SG list or 0 on failure.
+ * Returns 0 on failure or 1 on success.
*/
-static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq)
+static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
+ struct i2o_block_request *ireq,
+ u32 __iomem ** mptr)
{
- struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev;
int nents;
+ enum dma_data_direction direction;
+ ireq->dev = &c->pdev->dev;
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;
+ direction = PCI_DMA_FROMDEVICE;
else
- ireq->sg_dma_direction = PCI_DMA_TODEVICE;
+ direction = PCI_DMA_TODEVICE;
- ireq->sg_nents = dma_map_sg(dev, ireq->sg_table, nents,
- ireq->sg_dma_direction);
+ ireq->sg_nents = nents;
- return ireq->sg_nents;
+ return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
};
/**
@@ -330,10 +357,14 @@ static inline int i2o_block_sglist_alloc(struct i2o_block_request *ireq)
*/
static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
{
- struct device *dev = &ireq->i2o_blk_dev->i2o_dev->iop->pdev->dev;
+ enum dma_data_direction direction;
- dma_unmap_sg(dev, ireq->sg_table, ireq->sg_nents,
- ireq->sg_dma_direction);
+ if (rq_data_dir(ireq->req) == READ)
+ direction = PCI_DMA_FROMDEVICE;
+ else
+ direction = PCI_DMA_TODEVICE;
+
+ dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
};
/**
@@ -351,6 +382,11 @@ 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;
+ if (unlikely(!i2o_blk_dev)) {
+ osm_err("block device already removed\n");
+ return BLKPREP_KILL;
+ }
+
/* request is already processed by us, so return */
if (req->flags & REQ_SPECIAL) {
osm_debug("REQ_SPECIAL already set!\n");
@@ -400,71 +436,65 @@ static void i2o_block_delayed_request_fn(void *delayed_request)
};
/**
- * 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
+ * i2o_block_end_request - Post-processing of completed commands
+ * @req: request which should be completed
+ * @uptodate: 1 for success, 0 for I/O error, < 0 for specific error
+ * @nr_bytes: number of bytes to complete
*
- * This function gets all the message replies.
+ * Mark the request as complete. The lock must not be held when entering.
*
*/
-static int i2o_block_reply(struct i2o_controller *c, u32 m,
- struct i2o_message *msg)
+static void i2o_block_end_request(struct request *req, int uptodate,
+ int nr_bytes)
{
- struct i2o_block_request *ireq;
- struct request *req;
- struct i2o_block_device *dev;
- struct request_queue *q;
- u8 st;
+ struct i2o_block_request *ireq = req->special;
+ struct i2o_block_device *dev = ireq->i2o_blk_dev;
+ request_queue_t *q = req->q;
unsigned long flags;
- /* FAILed message */
- if (unlikely(le32_to_cpu(msg->u.head[0]) & (1 << 13))) {
- struct i2o_message *pmsg;
- u32 pm;
+ if (end_that_request_chunk(req, uptodate, nr_bytes)) {
+ int leftover = (req->hard_nr_sectors << KERNEL_SECTOR_SHIFT);
- /*
- * FAILed message from controller
- * We increment the error count and abort it
- *
- * In theory this will never happen. The I2O block class
- * specification states that block devices never return
- * FAILs but instead use the REQ status field...but
- * better be on the safe side since no one really follows
- * the spec to the book :)
- */
- pm = le32_to_cpu(msg->body[3]);
- pmsg = i2o_msg_in_to_virt(c, pm);
+ if (blk_pc_request(req))
+ leftover = req->data_len;
- req = i2o_cntxt_list_get(c, le32_to_cpu(pmsg->u.s.tcntxt));
- if (unlikely(!req)) {
- osm_err("NULL reply received!\n");
- return -1;
- }
+ if (end_io_error(uptodate))
+ end_that_request_chunk(req, 0, leftover);
+ }
- ireq = req->special;
- dev = ireq->i2o_blk_dev;
- q = dev->gd->queue;
+ add_disk_randomness(req->rq_disk);
- req->errors++;
-
- spin_lock_irqsave(q->queue_lock, flags);
+ spin_lock_irqsave(q->queue_lock, flags);
- while (end_that_request_chunk(req, !req->errors,
- le32_to_cpu(pmsg->body[1]))) ;
- end_that_request_last(req);
+ end_that_request_last(req);
+ if (likely(dev)) {
dev->open_queue_depth--;
list_del(&ireq->queue);
- blk_start_queue(q);
+ }
- spin_unlock_irqrestore(q->queue_lock, flags);
+ blk_start_queue(q);
- /* Now flush the message by making it a NOP */
- i2o_msg_nop(c, pm);
+ spin_unlock_irqrestore(q->queue_lock, flags);
- return -1;
- }
+ i2o_block_sglist_free(ireq);
+ i2o_block_request_free(ireq);
+};
+
+/**
+ * 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 int i2o_block_reply(struct i2o_controller *c, u32 m,
+ struct i2o_message *msg)
+{
+ struct request *req;
+ int uptodate = 1;
req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
if (unlikely(!req)) {
@@ -472,61 +502,13 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
return -1;
}
- 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
- * by the OS. We have to check for a reply from a
- * non-existent device and flag it as an error or the system
- * goes kaput...
- */
- req->errors++;
- osm_warn("Data transfer to deleted device!\n");
- spin_lock_irqsave(q->queue_lock, flags);
- while (end_that_request_chunk
- (req, !req->errors, le32_to_cpu(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.
*/
- st = le32_to_cpu(msg->body[0]) >> 24;
-
- if (st != 0) {
- int err;
- char *bsa_errors[] = {
- "Success",
- "Media Error",
- "Failure communicating to device",
- "Device Failure",
- "Device is not ready",
- "Media not present",
- "Media is locked by another user",
- "Media has failed",
- "Failure communicating to device",
- "Device bus failure",
- "Device is locked by another user",
- "Device is write protected",
- "Device has reset",
- "Volume has changed, waiting for acknowledgement"
- };
-
- err = le32_to_cpu(msg->body[0]) & 0xffff;
-
+ if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
+ u32 status = le32_to_cpu(msg->body[0]);
/*
* Device not ready means two things. One is that the
* the thing went offline (but not a removal media)
@@ -539,40 +521,23 @@ static int i2o_block_reply(struct i2o_controller *c, u32 m,
* Don't stick a supertrak100 into cache aggressive modes
*/
- osm_err("block-osm: /dev/%s error: %s", dev->gd->disk_name,
- bsa_errors[le32_to_cpu(msg->body[0]) & 0xffff]);
- if (le32_to_cpu(msg->body[0]) & 0x00ff0000)
- printk(KERN_ERR " - DDM attempted %d retries",
- (le32_to_cpu(msg->body[0]) >> 16) & 0x00ff);
- printk(KERN_ERR ".\n");
- req->errors++;
- } else
- req->errors = 0;
+ osm_err("TID %03x error status: 0x%02x, detailed status: "
+ "0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
+ status >> 24, status & 0xffff);
- if (!end_that_request_chunk
- (req, !req->errors, le32_to_cpu(msg->body[1]))) {
- add_disk_randomness(req->rq_disk);
- spin_lock_irqsave(q->queue_lock, flags);
-
- end_that_request_last(req);
+ req->errors++;
- dev->open_queue_depth--;
- list_del(&ireq->queue);
- blk_start_queue(q);
+ uptodate = 0;
+ }
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- i2o_block_sglist_free(ireq);
- i2o_block_request_free(ireq);
- } else
- osm_err("still remaining chunks\n");
+ i2o_block_end_request(req, uptodate, le32_to_cpu(msg->body[1]));
return 1;
};
static void i2o_block_event(struct i2o_event *evt)
{
- osm_info("block-osm: event received\n");
+ osm_debug("event received\n");
kfree(evt);
};
@@ -778,18 +743,25 @@ static int i2o_block_media_changed(struct gendisk *disk)
static int i2o_block_transfer(struct request *req)
{
struct i2o_block_device *dev = req->rq_disk->private_data;
- struct i2o_controller *c = dev->i2o_dev->iop;
+ struct i2o_controller *c;
int tid = dev->i2o_dev->lct_data.tid;
struct i2o_message __iomem *msg;
- void __iomem *mptr;
+ u32 __iomem *mptr;
struct i2o_block_request *ireq = req->special;
- struct scatterlist *sg;
- int sgnum;
- int i;
u32 m;
u32 tcntxt;
- u32 sg_flags;
+ u32 sgl_offset = SGL_OFFSET_8;
+ u32 ctl_flags = 0x00000000;
int rc;
+ u32 cmd;
+
+ if (unlikely(!dev->i2o_dev)) {
+ osm_err("transfer to removed drive\n");
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ c = dev->i2o_dev->iop;
m = i2o_msg_get(c, &msg);
if (m == I2O_QUEUE_EMPTY) {
@@ -803,82 +775,109 @@ static int i2o_block_transfer(struct request *req)
goto nop_msg;
}
- if ((sgnum = i2o_block_sglist_alloc(ireq)) <= 0) {
- rc = -ENOMEM;
- goto context_remove;
- }
-
- /* 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]);
-
- writel((((u64) req->sector) << 9) & 0xffffffff, &msg->body[2]);
- writel(req->sector >> 23, &msg->body[3]);
- mptr = &msg->body[4];
-
- sg = ireq->sg_table;
+ mptr = &msg->body[0];
if (rq_data_dir(req) == READ) {
- writel(I2O_CMD_BLOCK_READ << 24 | HOST_TID << 12 | tid,
- &msg->u.head[1]);
- sg_flags = 0x10000000;
+ cmd = I2O_CMD_BLOCK_READ << 24;
+
switch (dev->rcache) {
- case CACHE_NULL:
- writel(0, &msg->body[0]);
- break;
case CACHE_PREFETCH:
- writel(0x201F0008, &msg->body[0]);
+ ctl_flags = 0x201F0008;
break;
+
case CACHE_SMARTFETCH:
if (req->nr_sectors > 16)
- writel(0x201F0008, &msg->body[0]);
+ ctl_flags = 0x201F0008;
else
- writel(0x001F0000, &msg->body[0]);
+ ctl_flags = 0x001F0000;
+ break;
+
+ default:
break;
}
} else {
- writel(I2O_CMD_BLOCK_WRITE << 24 | HOST_TID << 12 | tid,
- &msg->u.head[1]);
- sg_flags = 0x14000000;
+ cmd = I2O_CMD_BLOCK_WRITE << 24;
+
switch (dev->wcache) {
- case CACHE_NULL:
- writel(0, &msg->body[0]);
- break;
case CACHE_WRITETHROUGH:
- writel(0x001F0008, &msg->body[0]);
+ ctl_flags = 0x001F0008;
break;
case CACHE_WRITEBACK:
- writel(0x001F0010, &msg->body[0]);
+ ctl_flags = 0x001F0010;
break;
case CACHE_SMARTBACK:
if (req->nr_sectors > 16)
- writel(0x001F0004, &msg->body[0]);
+ ctl_flags = 0x001F0004;
else
- writel(0x001F0010, &msg->body[0]);
+ ctl_flags = 0x001F0010;
break;
case CACHE_SMARTTHROUGH:
if (req->nr_sectors > 16)
- writel(0x001F0004, &msg->body[0]);
+ ctl_flags = 0x001F0004;
else
- writel(0x001F0010, &msg->body[0]);
+ ctl_flags = 0x001F0010;
+ default:
+ break;
+ }
+ }
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u8 cmd[10];
+ u32 scsi_flags;
+ u16 hwsec = queue_hardsect_size(req->q) >> KERNEL_SECTOR_SHIFT;
+
+ memset(cmd, 0, 10);
+
+ sgl_offset = SGL_OFFSET_12;
+
+ writel(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid,
+ &msg->u.head[1]);
+
+ writel(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC, mptr++);
+ writel(tid, mptr++);
+
+ /*
+ * ENABLE_DISCONNECT
+ * SIMPLE_TAG
+ * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+ */
+ if (rq_data_dir(req) == READ) {
+ cmd[0] = 0x28;
+ scsi_flags = 0x60a0000a;
+ } else {
+ cmd[0] = 0x2A;
+ scsi_flags = 0xa0a0000a;
}
+
+ writel(scsi_flags, mptr++);
+
+ *((u32 *) & cmd[2]) = cpu_to_be32(req->sector * hwsec);
+ *((u16 *) & cmd[7]) = cpu_to_be16(req->nr_sectors * hwsec);
+
+ memcpy_toio(mptr, cmd, 10);
+ mptr += 4;
+ writel(req->nr_sectors << KERNEL_SECTOR_SHIFT, mptr++);
+ } else
+#endif
+ {
+ writel(cmd | HOST_TID << 12 | tid, &msg->u.head[1]);
+ writel(ctl_flags, mptr++);
+ writel(req->nr_sectors << KERNEL_SECTOR_SHIFT, mptr++);
+ writel((u32) (req->sector << KERNEL_SECTOR_SHIFT), mptr++);
+ writel(req->sector >> (32 - KERNEL_SECTOR_SHIFT), mptr++);
}
- 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++;
+ if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
+ rc = -ENOMEM;
+ goto context_remove;
}
- writel(I2O_MESSAGE_SIZE
- (((unsigned long)mptr -
- (unsigned long)&msg->u.head[0]) >> 2) | SGL_OFFSET_8,
- &msg->u.head[0]);
+ writel(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) |
+ sgl_offset, &msg->u.head[0]);
list_add_tail(&ireq->queue, &dev->open_queue);
dev->open_queue_depth++;
@@ -921,11 +920,13 @@ static void i2o_block_request_fn(struct request_queue *q)
queue_depth = ireq->i2o_blk_dev->open_queue_depth;
- if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS)
+ if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
if (!i2o_block_transfer(req)) {
blkdev_dequeue_request(req);
continue;
- }
+ } else
+ osm_info("transfer error\n");
+ }
if (queue_depth)
break;
@@ -939,7 +940,6 @@ static void i2o_block_request_fn(struct request_queue *q)
INIT_WORK(&dreq->work, i2o_block_delayed_request_fn,
dreq);
- osm_info("transfer error\n");
if (!queue_delayed_work(i2o_block_driver.event_queue,
&dreq->work,
I2O_BLOCK_RETRY_TIME))
@@ -1008,6 +1008,7 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
}
blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
+ blk_queue_issue_flush_fn(queue, i2o_block_issue_flush);
gd->major = I2O_MAJOR;
gd->queue = queue;
@@ -1040,17 +1041,27 @@ static struct i2o_block_device *i2o_block_device_alloc(void)
static int i2o_block_probe(struct device *dev)
{
struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_block_device *i2o_blk_dev;
struct i2o_controller *c = i2o_dev->iop;
+ struct i2o_block_device *i2o_blk_dev;
struct gendisk *gd;
struct request_queue *queue;
static int unit = 0;
int rc;
u64 size;
u32 blocksize;
- u16 power;
u32 flags, status;
- int segments;
+ u16 body_size = 4;
+ unsigned short max_sectors;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec)
+ body_size = 8;
+#endif
+
+ if (c->limit_sectors)
+ max_sectors = I2O_MAX_SECTORS_LIMITED;
+ else
+ max_sectors = I2O_MAX_SECTORS;
/* skip devices which are used by IOP */
if (i2o_dev->lct_data.user_tid != 0xfff) {
@@ -1058,8 +1069,6 @@ static int i2o_block_probe(struct device *dev)
return -ENODEV;
}
- osm_info("New device detected (TID: %03x)\n", i2o_dev->lct_data.tid);
-
if (i2o_device_claim(i2o_dev)) {
osm_warn("Unable to claim device. Installation aborted\n");
rc = -EFAULT;
@@ -1087,50 +1096,44 @@ static int i2o_block_probe(struct device *dev)
queue = gd->queue;
queue->queuedata = i2o_blk_dev;
- blk_queue_max_phys_segments(queue, I2O_MAX_SEGMENTS);
- blk_queue_max_sectors(queue, I2O_MAX_SECTORS);
-
- if (c->short_req)
- segments = 8;
- else {
- i2o_status_block *sb;
+ blk_queue_max_phys_segments(queue, I2O_MAX_PHYS_SEGMENTS);
+ blk_queue_max_sectors(queue, max_sectors);
+ blk_queue_max_hw_segments(queue, i2o_sg_tablesize(c, body_size));
- sb = c->status_block.virt;
-
- segments = (sb->inbound_frame_size -
- sizeof(struct i2o_message) / 4 - 4) / 2;
- }
-
- blk_queue_max_hw_segments(queue, segments);
-
- osm_debug("max sectors = %d\n", I2O_MAX_SECTORS);
- osm_debug("phys segments = %d\n", I2O_MAX_SEGMENTS);
- osm_debug("hw segments = %d\n", segments);
+ osm_debug("max sectors = %d\n", queue->max_phys_segments);
+ osm_debug("phys segments = %d\n", queue->max_sectors);
+ osm_debug("max hw segments = %d\n", queue->max_hw_segments);
/*
* Ask for the current media data. If that isn't supported
* then we ask for the device capacity data
*/
- 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);
- }
- osm_debug("blocksize = %d\n", blocksize);
+ if (i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
+ i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
+ blk_queue_hardsect_size(queue, blocksize);
+ } else
+ osm_warn("unable to get blocksize of %s\n", gd->disk_name);
- if (i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
- power = 0;
+ if (i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
+ i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
+ set_capacity(gd, size >> KERNEL_SECTOR_SHIFT);
+ } else
+ osm_warn("could not get size of %s\n", gd->disk_name);
+
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &i2o_blk_dev->power, 2))
+ i2o_blk_dev->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++;
+ osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+ i2o_blk_dev->gd->disk_name);
+
return 0;
claim_release:
@@ -1178,7 +1181,7 @@ static int __init i2o_block_init(void)
goto exit;
}
- i2o_blk_req_pool.pool = mempool_create(I2O_REQ_MEMPOOL_SIZE,
+ i2o_blk_req_pool.pool = mempool_create(I2O_BLOCK_REQ_MEMPOOL_SIZE,
mempool_alloc_slab,
mempool_free_slab,
i2o_blk_req_pool.slab);
diff --git a/drivers/message/i2o/i2o_block.h b/drivers/message/i2o/i2o_block.h
index ddd9a15679c0..4fdaa5bda412 100644
--- a/drivers/message/i2o/i2o_block.h
+++ b/drivers/message/i2o/i2o_block.h
@@ -56,42 +56,46 @@
#define I2O_BLOCK_RETRY_TIME HZ/4
#define I2O_BLOCK_MAX_OPEN_REQUESTS 50
+/* request queue sizes */
+#define I2O_BLOCK_REQ_MEMPOOL_SIZE 32
+
+#define KERNEL_SECTOR_SHIFT 9
+#define KERNEL_SECTOR_SIZE (1 << KERNEL_SECTOR_SHIFT)
+
/* I2O Block OSM mempool struct */
struct i2o_block_mempool {
- kmem_cache_t *slab;
- mempool_t *pool;
+ 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 */
+ 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 rcache; /* read cache flags */
+ int wcache; /* write cache flags */
int flags;
- int power; /* power state */
- int media_change_flag; /* media changed flag */
+ u16 power; /* power state */
+ int media_change_flag; /* media changed flag */
};
/* I2O Block device request */
-struct i2o_block_request
-{
+struct i2o_block_request {
struct list_head queue;
- struct request *req; /* corresponding request */
+ 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 */
+ struct device *dev; /* device used for DMA */
+ int sg_nents; /* number of SG elements */
+ struct scatterlist sg_table[I2O_MAX_PHYS_SEGMENTS]; /* SG table */
};
/* I2O Block device delayed request */
-struct i2o_block_delayed_request
-{
+struct i2o_block_delayed_request {
struct work_struct work;
struct request_queue *queue;
};
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/message/i2o/i2o_config.c
index 1fb5cdf67f8f..3c3a7abebb1b 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/message/i2o/i2o_config.c
@@ -30,29 +30,15 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
#include <linux/miscdevice.h>
-#include <linux/mm.h>
-#include <linux/spinlock.h>
#include <linux/smp_lock.h>
-#include <linux/ioctl32.h>
#include <linux/compat.h>
-#include <linux/syscalls.h>
#include <asm/uaccess.h>
-#include <asm/io.h>
-#define OSM_NAME "config-osm"
-#define OSM_VERSION "$Rev$"
-#define OSM_DESCRIPTION "I2O Configuration OSM"
+#include "core.h"
-extern int i2o_parm_issue(struct i2o_device *, int, void *, int, void *, int);
+#define SG_TABLESIZE 30
static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
unsigned long arg);
@@ -80,15 +66,6 @@ struct i2o_cfg_info {
static struct i2o_cfg_info *open_files = NULL;
static ulong i2o_cfg_info_id = 0;
-/*
- * Each of these describes an i2o message handler. They are
- * multiplexed by the i2o_core code
- */
-
-static struct i2o_driver i2o_config_driver = {
- .name = OSM_NAME
-};
-
static int i2o_cfg_getiops(unsigned long arg)
{
struct i2o_controller *c;
@@ -391,9 +368,9 @@ static int i2o_cfg_swul(unsigned long arg)
i2o_dma_free(&c->pdev->dev, &buffer);
-return_ret:
+ return_ret:
return ret;
-return_fault:
+ return_fault:
ret = -EFAULT;
goto return_ret;
};
@@ -540,8 +517,10 @@ static int i2o_cfg_evt_get(unsigned long arg, struct file *fp)
return 0;
}
+#ifdef CONFIG_I2O_EXT_ADAPTEC
#ifdef CONFIG_COMPAT
-static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long arg)
+static int i2o_cfg_passthru32(struct file *file, unsigned cmnd,
+ unsigned long arg)
{
struct i2o_cmd_passthru32 __user *cmd;
struct i2o_controller *c;
@@ -555,6 +534,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
u32 sg_offset = 0;
u32 sg_count = 0;
u32 i = 0;
+ u32 sg_index = 0;
i2o_status_block *sb;
struct i2o_message *msg;
u32 m;
@@ -634,8 +614,8 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
if (sg_count > SG_TABLESIZE) {
printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
c->name, sg_count);
- kfree(reply);
- return -EINVAL;
+ rcode = -EINVAL;
+ goto cleanup;
}
for (i = 0; i < sg_count; i++) {
@@ -651,7 +631,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
goto cleanup;
}
sg_size = sg[i].flag_count & 0xffffff;
- p = &(sg_list[i]);
+ p = &(sg_list[sg_index++]);
/* Allocate memory for the transfer */
if (i2o_dma_alloc
(&c->pdev->dev, p, sg_size,
@@ -660,20 +640,21 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
"%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;
+ goto sg_list_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)) {
+ (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;
+ goto sg_list_cleanup;
}
}
//TODO 64bit fix
@@ -683,10 +664,10 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
rcode = i2o_msg_post_wait(c, m, 60);
if (rcode)
- goto cleanup;
+ goto sg_list_cleanup;
if (sg_offset) {
- u32 msg[128];
+ u32 msg[I2O_OUTBOUND_MSG_FRAME_SIZE];
/* Copy back the Scatter Gather buffers back to user space */
u32 j;
// TODO 64bit fix
@@ -694,18 +675,18 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, MSG_FRAME_SIZE * 4);
+ memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
- goto cleanup;
+ goto sg_list_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;
+ goto sg_list_cleanup;
}
sg_count =
(size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -727,7 +708,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
c->name, sg_list[j].virt,
sg[j].addr_bus);
rcode = -EFAULT;
- goto cleanup;
+ goto sg_list_cleanup;
}
}
}
@@ -741,6 +722,7 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
"%s: Could not copy message context FROM user\n",
c->name);
rcode = -EFAULT;
+ goto sg_list_cleanup;
}
if (copy_to_user(user_reply, reply, reply_size)) {
printk(KERN_WARNING
@@ -749,16 +731,21 @@ static int i2o_cfg_passthru32(struct file *file, unsigned cmnd, unsigned long ar
}
}
+ sg_list_cleanup:
+ for (i = 0; i < sg_index; i++)
+ i2o_dma_free(&c->pdev->dev, &sg_list[i]);
+
cleanup:
kfree(reply);
return rcode;
}
-static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+static long i2o_cfg_compat_ioctl(struct file *file, unsigned cmd,
+ unsigned long arg)
{
int ret;
- lock_kernel();
- switch (cmd) {
+ lock_kernel();
+ switch (cmd) {
case I2OGETIOPS:
ret = i2o_cfg_ioctl(NULL, file, cmd, arg);
break;
@@ -862,8 +849,8 @@ static int i2o_cfg_passthru(unsigned long arg)
if (sg_count > SG_TABLESIZE) {
printk(KERN_DEBUG "%s:IOCTL SG List too large (%u)\n",
c->name, sg_count);
- kfree(reply);
- return -EINVAL;
+ rcode = -EINVAL;
+ goto cleanup;
}
for (i = 0; i < sg_count; i++) {
@@ -875,7 +862,7 @@ static int i2o_cfg_passthru(unsigned long arg)
"%s:Bad SG element %d - not simple (%x)\n",
c->name, i, sg[i].flag_count);
rcode = -EINVAL;
- goto cleanup;
+ goto sg_list_cleanup;
}
sg_size = sg[i].flag_count & 0xffffff;
/* Allocate memory for the transfer */
@@ -885,7 +872,7 @@ static int i2o_cfg_passthru(unsigned long arg)
"%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;
+ goto sg_list_cleanup;
}
sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
/* Copy in the user's SG buffer if necessary */
@@ -899,7 +886,7 @@ static int i2o_cfg_passthru(unsigned long arg)
"%s: Could not copy SG buf %d FROM user\n",
c->name, i);
rcode = -EFAULT;
- goto cleanup;
+ goto sg_list_cleanup;
}
}
//TODO 64bit fix
@@ -909,7 +896,7 @@ static int i2o_cfg_passthru(unsigned long arg)
rcode = i2o_msg_post_wait(c, m, 60);
if (rcode)
- goto cleanup;
+ goto sg_list_cleanup;
if (sg_offset) {
u32 msg[128];
@@ -920,18 +907,18 @@ static int i2o_cfg_passthru(unsigned long arg)
int sg_size;
// re-acquire the original message to handle correctly the sg copy operation
- memset(&msg, 0, MSG_FRAME_SIZE * 4);
+ memset(&msg, 0, I2O_OUTBOUND_MSG_FRAME_SIZE * 4);
// get user msg size in u32s
if (get_user(size, &user_msg[0])) {
rcode = -EFAULT;
- goto cleanup;
+ goto sg_list_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;
+ goto sg_list_cleanup;
}
sg_count =
(size - sg_offset * 4) / sizeof(struct sg_simple_element);
@@ -953,7 +940,7 @@ static int i2o_cfg_passthru(unsigned long arg)
c->name, sg_list[j],
sg[j].addr_bus);
rcode = -EFAULT;
- goto cleanup;
+ goto sg_list_cleanup;
}
}
}
@@ -975,10 +962,15 @@ static int i2o_cfg_passthru(unsigned long arg)
}
}
+ sg_list_cleanup:
+ for (i = 0; i < sg_index; i++)
+ kfree(sg_list[i]);
+
cleanup:
kfree(reply);
return rcode;
}
+#endif
/*
* IOCTL Handler
@@ -1033,9 +1025,11 @@ static int i2o_cfg_ioctl(struct inode *inode, struct file *fp, unsigned int cmd,
ret = i2o_cfg_evt_get(arg, fp);
break;
+#ifdef CONFIG_I2O_EXT_ADAPTEC
case I2OPASSTHRU:
ret = i2o_cfg_passthru(arg);
break;
+#endif
default:
osm_debug("unknown ioctl called!\n");
@@ -1137,37 +1131,21 @@ static struct miscdevice i2o_miscdev = {
&config_fops
};
-static int __init i2o_config_init(void)
+static int __init i2o_config_old_init(void)
{
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
spin_lock_init(&i2o_config_lock);
if (misc_register(&i2o_miscdev) < 0) {
osm_err("can't register device.\n");
return -EBUSY;
}
- /*
- * Install our handler
- */
- if (i2o_driver_register(&i2o_config_driver)) {
- osm_err("handler register failed.\n");
- misc_deregister(&i2o_miscdev);
- return -EBUSY;
- }
+
return 0;
}
-static void i2o_config_exit(void)
+static void i2o_config_old_exit(void)
{
misc_deregister(&i2o_miscdev);
- i2o_driver_unregister(&i2o_config_driver);
}
MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_config_init);
-module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
index b176d0eeff7f..d559a1758363 100644
--- a/drivers/message/i2o/i2o_proc.c
+++ b/drivers/message/i2o/i2o_proc.c
@@ -28,7 +28,7 @@
*/
#define OSM_NAME "proc-osm"
-#define OSM_VERSION "$Rev$"
+#define OSM_VERSION "1.145"
#define OSM_DESCRIPTION "I2O ProcFS OSM"
#define I2O_MAX_MODULES 4
@@ -228,7 +228,7 @@ static const char *i2o_get_class_name(int class)
case I2O_CLASS_FLOPPY_DEVICE:
idx = 12;
break;
- case I2O_CLASS_BUS_ADAPTER_PORT:
+ case I2O_CLASS_BUS_ADAPTER:
idx = 13;
break;
case I2O_CLASS_PEER_TRANSPORT_AGENT:
@@ -490,7 +490,7 @@ static int i2o_seq_show_lct(struct seq_file *seq, void *v)
seq_printf(seq, ", Unknown Device Type");
break;
- case I2O_CLASS_BUS_ADAPTER_PORT:
+ case I2O_CLASS_BUS_ADAPTER:
if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
seq_printf(seq, ", %s",
bus_ports[lct->lct_entry[i].
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
index 43f5875e0be5..9f1744c3933b 100644
--- a/drivers/message/i2o/i2o_scsi.c
+++ b/drivers/message/i2o/i2o_scsi.c
@@ -54,6 +54,7 @@
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/i2o.h>
+#include <linux/scatterlist.h>
#include <asm/dma.h>
#include <asm/system.h>
@@ -64,19 +65,23 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
+#include <scsi/sg_request.h>
#define OSM_NAME "scsi-osm"
-#define OSM_VERSION "$Rev$"
+#define OSM_VERSION "1.282"
#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM"
static struct i2o_driver i2o_scsi_driver;
-static int i2o_scsi_max_id = 16;
-static int i2o_scsi_max_lun = 8;
+static unsigned int i2o_scsi_max_id = 16;
+static unsigned int i2o_scsi_max_lun = 255;
struct i2o_scsi_host {
struct Scsi_Host *scsi_host; /* pointer to the SCSI host */
struct i2o_controller *iop; /* pointer to the I2O controller */
+ unsigned int lun; /* lun's used for block devices */
struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */
};
@@ -99,11 +104,17 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
u8 type;
int i;
size_t size;
- i2o_status_block *sb;
+ u16 body_size = 6;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec)
+ body_size = 8;
+#endif
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 */
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
max_channel++;
}
@@ -125,20 +136,18 @@ static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
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;
+ scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
i2o_shost->scsi_host = scsi_host;
i2o_shost->iop = c;
+ i2o_shost->lun = 1;
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 */
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* only SCSI bus */
i2o_shost->channel[i++] = i2o_dev;
if (i >= max_channel)
@@ -178,10 +187,13 @@ static int i2o_scsi_remove(struct device *dev)
struct i2o_scsi_host *i2o_shost;
struct scsi_device *scsi_dev;
+ osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
i2o_shost = i2o_scsi_get_host(c);
shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
if (scsi_dev->hostdata == i2o_dev) {
+ sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
scsi_remove_device(scsi_dev);
scsi_device_put(scsi_dev);
break;
@@ -207,8 +219,8 @@ static int i2o_scsi_probe(struct device *dev)
struct Scsi_Host *scsi_host;
struct i2o_device *parent;
struct scsi_device *scsi_dev;
- u32 id;
- u64 lun;
+ u32 id = -1;
+ u64 lun = -1;
int channel = -1;
int i;
@@ -218,8 +230,56 @@ static int i2o_scsi_probe(struct device *dev)
scsi_host = i2o_shost->scsi_host;
- if (i2o_parm_field_get(i2o_dev, 0, 3, &id, 4) < 0)
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ case I2O_CLASS_EXECUTIVE:
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u8 type;
+ struct i2o_device *d = i2o_shost->channel[0];
+
+ if (i2o_parm_field_get(d, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
+ if (i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
+ channel = 0;
+ if (i2o_dev->lct_data.class_id ==
+ I2O_CLASS_RANDOM_BLOCK_STORAGE)
+ lun = i2o_shost->lun++;
+ else
+ lun = 0;
+ }
+ }
+#endif
+ break;
+
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4) < 0)
+ return -EFAULT;
+
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8) < 0)
+ return -EFAULT;
+
+ parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
+ if (!parent) {
+ osm_warn("can not find parent of device %03x\n",
+ i2o_dev->lct_data.tid);
+ return -EFAULT;
+ }
+
+ for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
+ if (i2o_shost->channel[i] == parent)
+ channel = i;
+ break;
+
+ default:
return -EFAULT;
+ }
+
+ if (channel == -1) {
+ osm_warn("can not find channel of device %03x\n",
+ i2o_dev->lct_data.tid);
+ return -EFAULT;
+ }
if (id >= scsi_host->max_id) {
osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)", id,
@@ -227,42 +287,26 @@ static int i2o_scsi_probe(struct device *dev)
return -EFAULT;
}
- if (i2o_parm_field_get(i2o_dev, 0, 4, &lun, 8) < 0)
- return -EFAULT;
if (lun >= scsi_host->max_lun) {
osm_warn("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) {
- osm_warn("can not find parent of device %03x\n",
- i2o_dev->lct_data.tid);
- return -EFAULT;
- }
-
- for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
- if (i2o_shost->channel[i] == parent)
- channel = i;
-
- if (channel == -1) {
- osm_warn("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) {
+ if (IS_ERR(scsi_dev)) {
osm_warn("can not add SCSI device %03x\n",
i2o_dev->lct_data.tid);
- return -EFAULT;
+ return PTR_ERR(scsi_dev);
}
- osm_debug("added new SCSI device %03x (cannel: %d, id: %d, lun: %d)\n",
- i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
+ sysfs_create_link(&i2o_dev->device.kobj, &scsi_dev->sdev_gendev.kobj,
+ "scsi");
+
+ osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %d\n",
+ i2o_dev->lct_data.tid, channel, id, (unsigned int)lun);
return 0;
};
@@ -293,162 +337,89 @@ static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
struct i2o_message *msg)
{
struct scsi_cmnd *cmd;
+ u32 error;
struct device *dev;
- u8 as, ds, st;
cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
-
- if (msg->u.head[0] & (1 << 13)) {
- struct i2o_message __iomem *pmsg; /* preserved message */
- u32 pm;
- int err = DID_ERROR;
-
- pm = le32_to_cpu(msg->body[3]);
-
- pmsg = i2o_msg_in_to_virt(c, pm);
-
- osm_err("IOP fail.\n");
- osm_err("From %d To %d Cmd %d.\n",
- (msg->u.head[1] >> 12) & 0xFFF,
- msg->u.head[1] & 0xFFF, msg->u.head[1] >> 24);
- osm_err("Failure Code %d.\n", msg->body[0] >> 24);
- if (msg->body[0] & (1 << 16))
- osm_err("Format error.\n");
- if (msg->body[0] & (1 << 17))
- osm_err("Path error.\n");
- if (msg->body[0] & (1 << 18))
- osm_err("Path State.\n");
- if (msg->body[0] & (1 << 18))
- {
- osm_err("Congestion.\n");
- err = DID_BUS_BUSY;
- }
-
- osm_debug("Failing message is %p.\n", pmsg);
-
- cmd = i2o_cntxt_list_get(c, readl(&pmsg->u.s.tcntxt));
- if (!cmd)
- return 1;
-
- cmd->result = err << 16;
- cmd->scsi_done(cmd);
-
- /* Now flush the message by making it a NOP */
- i2o_msg_nop(c, pm);
-
- return 1;
+ if (unlikely(!cmd)) {
+ osm_err("NULL reply received!\n");
+ return -1;
}
/*
* Low byte is device status, next is adapter status,
* (then one byte reserved), then request status.
*/
- ds = (u8) le32_to_cpu(msg->body[0]);
- as = (u8) (le32_to_cpu(msg->body[0]) >> 8);
- st = (u8) (le32_to_cpu(msg->body[0]) >> 24);
+ error = le32_to_cpu(msg->body[0]);
+
+ osm_debug("Completed %ld\n", cmd->serial_number);
+ cmd->result = error & 0xff;
/*
- * Is this a control request coming back - eg an abort ?
+ * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+ * the SCSI layer handle the error
*/
+ if (cmd->result)
+ memcpy(cmd->sense_buffer, &msg->body[3],
+ min(sizeof(cmd->sense_buffer), (size_t) 40));
- if (!cmd) {
- if (st)
- osm_warn("SCSI abort: %08X", le32_to_cpu(msg->body[0]));
- osm_info("SCSI abort completed.\n");
- return -EFAULT;
- }
+ /* only output error code if AdapterStatus is not HBA_SUCCESS */
+ if ((error >> 8) & 0xff)
+ osm_err("SCSI error %08x\n", error);
- osm_debug("Completed %ld\n", cmd->serial_number);
+ dev = &c->pdev->dev;
+ if (cmd->use_sg)
+ dma_unmap_sg(dev, cmd->request_buffer, cmd->use_sg,
+ cmd->sc_data_direction);
+ else if (cmd->SCp.dma_handle)
+ dma_unmap_single(dev, cmd->SCp.dma_handle, cmd->request_bufflen,
+ cmd->sc_data_direction);
- if (st) {
- u32 count, error;
- /* An error has occurred */
-
- switch (st) {
- case 0x06:
- count = le32_to_cpu(msg->body[1]);
- if (count < cmd->underflow) {
- int i;
-
- osm_err("SCSI underflow 0x%08X 0x%08X\n", count,
- cmd->underflow);
- osm_debug("Cmd: ");
- for (i = 0; i < 15; i++)
- pr_debug("%02X ", cmd->cmnd[i]);
- pr_debug(".\n");
- cmd->result = (DID_ERROR << 16);
- }
- break;
+ cmd->scsi_done(cmd);
- default:
- error = le32_to_cpu(msg->body[0]);
-
- osm_err("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++)
- osm_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;
- }
-
- 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;
- }
+ return 1;
+};
- break;
- }
+/**
+ * i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ * @i2o_dev: the I2O device which was added
+ *
+ * If a I2O device is added we catch the notification, because I2O classes
+ * other then SCSI peripheral will not be received through
+ * i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_probe(&i2o_dev->device);
+ break;
- cmd->scsi_done(cmd);
- return 1;
+ default:
+ break;
}
+};
- 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);
+/**
+ * i2o_scsi_notify_device_remove - Retrieve notifications of removed
+ * devices
+ * @i2o_dev: the I2O device which was removed
+ *
+ * If a I2O device is removed, we catch the notification to remove the
+ * corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_remove(&i2o_dev->device);
+ break;
- return 1;
+ default:
+ break;
+ }
};
/**
@@ -501,7 +472,7 @@ static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
scsi_remove_host(i2o_shost->scsi_host);
scsi_host_put(i2o_shost->scsi_host);
- pr_info("I2O SCSI host removed\n");
+ osm_debug("I2O SCSI host removed\n");
};
/* SCSI OSM driver struct */
@@ -509,6 +480,8 @@ static struct i2o_driver i2o_scsi_driver = {
.name = OSM_NAME,
.reply = i2o_scsi_reply,
.classes = i2o_scsi_class_id,
+ .notify_device_add = i2o_scsi_notify_device_add,
+ .notify_device_remove = i2o_scsi_notify_device_remove,
.notify_controller_add = i2o_scsi_notify_controller_add,
.notify_controller_remove = i2o_scsi_notify_controller_remove,
.driver = {
@@ -535,26 +508,26 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
void (*done) (struct scsi_cmnd *))
{
struct i2o_controller *c;
- struct Scsi_Host *host;
struct i2o_device *i2o_dev;
- struct device *dev;
int tid;
struct i2o_message __iomem *msg;
u32 m;
- u32 scsi_flags, sg_flags;
+ /*
+ * ENABLE_DISCONNECT
+ * SIMPLE_TAG
+ * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+ */
+ u32 scsi_flags = 0x20a00000;
+ u32 sgl_offset;
u32 __iomem *mptr;
- u32 __iomem *lenptr;
- u32 len, reqlen;
- int i;
+ u32 cmd = I2O_CMD_SCSI_EXEC << 24;
+ int rc = 0;
/*
* Do the incoming paperwork
*/
-
i2o_dev = SCpnt->device->hostdata;
- host = SCpnt->device->host;
c = i2o_dev->iop;
- dev = &c->pdev->dev;
SCpnt->scsi_done = done;
@@ -562,7 +535,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
osm_warn("no I2O device in request\n");
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
- return 0;
+ goto exit;
}
tid = i2o_dev->lct_data.tid;
@@ -571,44 +544,85 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
osm_debug("Real scsi messages.\n");
/*
- * 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;
-
- /*
* Put together a scsi execscb message
*/
-
- len = SCpnt->request_bufflen;
-
switch (SCpnt->sc_data_direction) {
case PCI_DMA_NONE:
- scsi_flags = 0x00000000; // DATA NO XFER
- sg_flags = 0x00000000;
+ /* DATA NO XFER */
+ sgl_offset = SGL_OFFSET_0;
break;
case PCI_DMA_TODEVICE:
- scsi_flags = 0x80000000; // DATA OUT (iop-->dev)
- sg_flags = 0x14000000;
+ /* DATA OUT (iop-->dev) */
+ scsi_flags |= 0x80000000;
+ sgl_offset = SGL_OFFSET_10;
break;
case PCI_DMA_FROMDEVICE:
- scsi_flags = 0x40000000; // DATA IN (iop<--dev)
- sg_flags = 0x10000000;
+ /* DATA IN (iop<--dev) */
+ scsi_flags |= 0x40000000;
+ sgl_offset = SGL_OFFSET_10;
break;
default:
/* Unknown - kill the command */
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
- return 0;
+ goto exit;
}
- writel(I2O_CMD_SCSI_EXEC << 24 | HOST_TID << 12 | tid, &msg->u.head[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) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit;
+ }
+
+ mptr = &msg->body[0];
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u32 adpt_flags = 0;
+
+ if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
+ i2o_sg_io_hdr_t __user *usr_ptr =
+ ((Sg_request *) (SCpnt->sc_request->
+ upper_private_data))->header.
+ usr_ptr;
+
+ if (usr_ptr)
+ get_user(adpt_flags, &usr_ptr->flags);
+ }
+
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ /* interpret flag has to be set for executive */
+ adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * for Adaptec controllers we use the PRIVATE command, because
+ * the normal SCSI EXEC doesn't support all SCSI commands on
+ * all controllers (for example READ CAPACITY).
+ */
+ if (sgl_offset == SGL_OFFSET_10)
+ sgl_offset = SGL_OFFSET_12;
+ cmd = I2O_CMD_PRIVATE << 24;
+ writel(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC, mptr++);
+ writel(adpt_flags | tid, mptr++);
+ }
+#endif
+
+ writel(cmd | HOST_TID << 12 | tid, &msg->u.head[1]);
writel(i2o_scsi_driver.context, &msg->u.s.icntxt);
/* We want the SCSI control block back */
@@ -626,7 +640,7 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
*/
/* Attach tags to the devices */
- /*
+ /* FIXME: implement
if(SCpnt->device->tagged_supported) {
if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
scsi_flags |= 0x01000000;
@@ -635,67 +649,35 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
}
*/
- /* Direction, disconnect ok, tag, CDBLen */
- writel(scsi_flags | 0x20200000 | SCpnt->cmd_len, &msg->body[0]);
-
- mptr = &msg->body[1];
+ writel(scsi_flags | SCpnt->cmd_len, mptr++);
/* 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 */
-
- reqlen = 12; // SINGLE SGE
-
- /* Now fill in the SGList and command */
- if (SCpnt->use_sg) {
- struct scatterlist *sg;
- int sg_count;
-
- sg = SCpnt->request_buffer;
- len = 0;
-
- sg_count = dma_map_sg(dev, sg, SCpnt->use_sg,
- SCpnt->sc_data_direction);
- 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++;
+ if (sgl_offset != SGL_OFFSET_0) {
+ /* write size of data addressed by SGL */
+ writel(SCpnt->request_bufflen, mptr++);
+
+ /* Now fill in the SGList and command */
+ if (SCpnt->use_sg) {
+ if (!i2o_dma_map_sg(c, SCpnt->request_buffer,
+ SCpnt->use_sg,
+ SCpnt->sc_data_direction, &mptr))
+ goto nomem;
+ } else {
+ SCpnt->SCp.dma_handle =
+ i2o_dma_map_single(c, SCpnt->request_buffer,
+ SCpnt->request_bufflen,
+ SCpnt->sc_data_direction, &mptr);
+ if (dma_mapping_error(SCpnt->SCp.dma_handle))
+ goto nomem;
}
-
- 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 = 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 */
- writel(reqlen << 16 | SGL_OFFSET_10, &msg->u.head[0]);
+ writel(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset,
+ &msg->u.head[0]);
/* Queue the message */
i2o_msg_post(c, m);
@@ -703,6 +685,13 @@ static int i2o_scsi_queuecommand(struct scsi_cmnd *SCpnt,
osm_debug("Issued %ld\n", SCpnt->serial_number);
return 0;
+
+ nomem:
+ rc = -ENOMEM;
+ i2o_msg_nop(c, m);
+
+ exit:
+ return rc;
};
/**
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
index 50c8cedf7a2d..42f8b810d6e5 100644
--- a/drivers/message/i2o/iop.c
+++ b/drivers/message/i2o/iop.c
@@ -28,8 +28,10 @@
#include <linux/module.h>
#include <linux/i2o.h>
#include <linux/delay.h>
+#include "core.h"
-#define OSM_VERSION "$Rev$"
+#define OSM_NAME "i2o"
+#define OSM_VERSION "1.288"
#define OSM_DESCRIPTION "I2O subsystem"
/* global I2O controller list */
@@ -43,20 +45,6 @@ static struct i2o_dma i2o_systab;
static int i2o_hrt_get(struct i2o_controller *c);
-/* 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
@@ -68,7 +56,7 @@ extern void i2o_device_exit(void);
*/
void i2o_msg_nop(struct i2o_controller *c, u32 m)
{
- struct i2o_message __iomem *msg = c->in_queue.virt + m;
+ struct i2o_message __iomem *msg = i2o_msg_in_to_virt(c, m);
writel(THREE_WORD_MSG_SIZE | SGL_OFFSET_0, &msg->u.head[0]);
writel(I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID,
@@ -92,16 +80,16 @@ void i2o_msg_nop(struct i2o_controller *c, u32 m)
* 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 __iomem **msg,
- int wait)
+u32 i2o_msg_get_wait(struct i2o_controller *c,
+ struct i2o_message __iomem ** 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);
+ osm_debug("%s: Timeout waiting for message frame.\n",
+ c->name);
return I2O_QUEUE_EMPTY;
}
set_current_state(TASK_UNINTERRUPTIBLE);
@@ -129,13 +117,13 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
unsigned long flags;
if (!ptr)
- printk(KERN_ERR "%s: couldn't add NULL pointer to context list!"
- "\n", c->name);
+ osm_err("%s: couldn't add NULL pointer to context list!\n",
+ c->name);
entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
if (!entry) {
- printk(KERN_ERR "%s: Could not allocate memory for context "
- "list element\n", c->name);
+ osm_err("%s: Could not allocate memory for context list element"
+ "\n", c->name);
return 0;
}
@@ -154,7 +142,7 @@ u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
spin_unlock_irqrestore(&c->context_list_lock, flags);
- pr_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
+ osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
return entry->context;
};
@@ -186,11 +174,11 @@ u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
spin_unlock_irqrestore(&c->context_list_lock, flags);
if (!context)
- printk(KERN_WARNING "%s: Could not remove nonexistent ptr "
- "%p\n", c->name, ptr);
+ osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
+ ptr);
- pr_debug("%s: remove ptr from context list %d -> %p\n", c->name,
- context, ptr);
+ osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
+ context, ptr);
return context;
};
@@ -220,11 +208,10 @@ void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
spin_unlock_irqrestore(&c->context_list_lock, flags);
if (!ptr)
- printk(KERN_WARNING "%s: context id %d not found\n", c->name,
- context);
+ osm_warn("%s: context id %d not found\n", c->name, context);
- pr_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
- ptr);
+ osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
+ ptr);
return ptr;
};
@@ -252,11 +239,11 @@ u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
spin_unlock_irqrestore(&c->context_list_lock, flags);
if (!context)
- printk(KERN_WARNING "%s: Could not find nonexistent ptr "
- "%p\n", c->name, ptr);
+ osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
+ ptr);
- pr_debug("%s: get context id from context list %p -> %d\n", c->name,
- ptr, context);
+ osm_debug("%s: get context id from context list %p -> %d\n", c->name,
+ ptr, context);
return context;
};
@@ -336,10 +323,9 @@ static int i2o_iop_quiesce(struct i2o_controller *c)
/* 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);
+ osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
else
- pr_debug("%s: Quiesced.\n", c->name);
+ osm_debug("%s: Quiesced.\n", c->name);
i2o_status_get(c); // Entered READY state
@@ -377,10 +363,9 @@ static int i2o_iop_enable(struct i2o_controller *c)
/* 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);
+ osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
else
- pr_debug("%s: Enabled.\n", c->name);
+ osm_debug("%s: Enabled.\n", c->name);
i2o_status_get(c); // entered OPERATIONAL state
@@ -444,20 +429,78 @@ static int i2o_iop_clear(struct i2o_controller *c)
&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);
+ osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
else
- pr_debug("%s: Cleared.\n", c->name);
+ osm_debug("%s: Cleared.\n", c->name);
/* Enable all IOPs */
i2o_iop_enable_all();
- i2o_status_get(c);
-
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.
+ */
+static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+{
+ volatile u8 *status = c->status.virt;
+ u32 m;
+ struct i2o_message __iomem *msg;
+ ulong timeout;
+ int i;
+
+ osm_debug("%s: Initializing Outbound Queue...\n", c->name);
+
+ memset(c->status.virt, 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 | SGL_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(0x00000000, &msg->u.s.tcntxt);
+ writel(PAGE_SIZE, &msg->body[0]);
+ /* Outbound msg frame size in words and Initcode */
+ writel(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80, &msg->body[1]);
+ writel(0xd0000004, &msg->body[2]);
+ writel(i2o_dma_low(c->status.phys), &msg->body[3]);
+ writel(i2o_dma_high(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)) {
+ osm_warn("%s: Timeout Initializing\n", c->name);
+ return -ETIMEDOUT;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ }
+
+ m = c->out_queue.phys;
+
+ /* Post frames */
+ for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
+ i2o_flush_reply(c, m);
+ udelay(1); /* Promise */
+ m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
+ }
+
+ return 0;
+}
+
+/**
* i2o_iop_reset - reset an I2O controller
* @c: controller to reset
*
@@ -468,20 +511,20 @@ static int i2o_iop_clear(struct i2o_controller *c)
*/
static int i2o_iop_reset(struct i2o_controller *c)
{
- u8 *status = c->status.virt;
+ volatile u8 *status = c->status.virt;
struct i2o_message __iomem *msg;
u32 m;
unsigned long timeout;
i2o_status_block *sb = c->status_block.virt;
int rc = 0;
- pr_debug("%s: Resetting controller\n", c->name);
+ osm_debug("%s: Resetting controller\n", c->name);
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
return -ETIMEDOUT;
- memset(status, 0, 8);
+ memset(c->status_block.virt, 0, 8);
/* Quiesce all IOPs first */
i2o_iop_quiesce_all();
@@ -493,49 +536,43 @@ static int i2o_iop_reset(struct i2o_controller *c)
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]);
+ writel(i2o_dma_low(c->status.phys), &msg->body[2]);
+ writel(i2o_dma_high(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 "%s: IOP reset timeout.\n", c->name);
- rc = -ETIMEDOUT;
- goto exit;
- }
-
- /* Promise bug */
- if (status[1] || status[4]) {
- *status = 0;
+ if (time_after(jiffies, timeout))
break;
- }
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
-
- rmb();
}
- if (*status == I2O_CMD_IN_PROGRESS) {
+ switch (*status) {
+ case I2O_CMD_REJECTED:
+ osm_warn("%s: IOP reset rejected\n", c->name);
+ rc = -EPERM;
+ break;
+
+ case 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.
+ * 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);
+ osm_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 "%s: IOP reset timeout.\n",
- c->name);
+ osm_err("%s: IOP reset timeout.\n", c->name);
rc = -ETIMEDOUT;
goto exit;
}
@@ -545,19 +582,26 @@ static int i2o_iop_reset(struct i2o_controller *c)
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;
+ /* 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);
+ /* verify if controller is in state RESET */
+ i2o_status_get(c);
+
+ if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
+ osm_warn("%s: reset completed, but adapter not in RESET"
+ " state.\n", c->name);
+ else
+ osm_debug("%s: reset completed.\n", c->name);
+
+ break;
+
+ default:
+ osm_err("%s: IOP reset timeout.\n", c->name);
+ rc = -ETIMEDOUT;
+ break;
+ }
exit:
/* Enable all IOPs */
@@ -567,88 +611,6 @@ static int i2o_iop_reset(struct i2o_controller *c)
};
/**
- * 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.
- */
-static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
-{
- u8 *status = c->status.virt;
- u32 m;
- struct i2o_message __iomem *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);
- udelay(1); /* Promise */
- m += MSG_FRAME_SIZE * 4;
- }
-
- return 0;
-}
-
-/**
- * i2o_iop_send_nop - send a core NOP message
- * @c: controller
- *
- * Send a no-operation message with a reply set to cause no
- * action either. Needed for bringing up promise controllers.
- */
-static int i2o_iop_send_nop(struct i2o_controller *c)
-{
- struct i2o_message __iomem *msg;
- u32 m = i2o_msg_get_wait(c, &msg, HZ);
- if (m == I2O_QUEUE_EMPTY)
- return -ETIMEDOUT;
- i2o_msg_nop(c, m);
- return 0;
-}
-
-/**
* i2o_iop_activate - Bring controller up to HOLD
* @c: controller
*
@@ -659,78 +621,62 @@ static int i2o_iop_send_nop(struct i2o_controller *c)
*/
static int i2o_iop_activate(struct i2o_controller *c)
{
- struct pci_dev *i960 = NULL;
i2o_status_block *sb = c->status_block.virt;
int rc;
-
- if (c->promise) {
- /* Beat up the hardware first of all */
- i960 =
- pci_find_slot(c->pdev->bus->number,
- PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
- if (i960)
- pci_write_config_word(i960, 0x42, 0);
-
- /* Follow this sequence precisely or the controller
- ceases to perform useful functions until reboot */
- if ((rc = i2o_iop_send_nop(c)))
- return rc;
-
- if ((rc = i2o_iop_reset(c)))
- return rc;
- }
+ int state;
/* 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 "%s: Unable to obtain status, "
- "attempting a reset.\n", c->name);
- if (i2o_iop_reset(c))
+ osm_info("%s: Unable to obtain status, attempting a reset.\n",
+ c->name);
+ rc = i2o_iop_reset(c);
+ if (rc)
return rc;
}
if (sb->i2o_version > I2OVER15) {
- printk(KERN_ERR "%s: Not running version 1.5 of the I2O "
- "Specification.\n", c->name);
+ osm_err("%s: Not running version 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;
+ osm_err("%s: hardware fault\n", c->name);
+ return -EFAULT;
case ADAPTER_STATE_READY:
case ADAPTER_STATE_OPERATIONAL:
case ADAPTER_STATE_HOLD:
case ADAPTER_STATE_FAILED:
- pr_debug("%s: already running, trying to reset...\n", c->name);
- if (i2o_iop_reset(c))
- return -ENODEV;
+ osm_debug("%s: already running, trying to reset...\n", c->name);
+ rc = i2o_iop_reset(c);
+ if (rc)
+ return rc;
}
+ /* preserve state */
+ state = sb->iop_state;
+
rc = i2o_iop_init_outbound_queue(c);
if (rc)
return rc;
- if (c->promise) {
- if ((rc = i2o_iop_send_nop(c)))
- return rc;
+ /* if adapter was not in RESET state clear now */
+ if (state != ADAPTER_STATE_RESET)
+ i2o_iop_clear(c);
- if ((rc = i2o_status_get(c)))
- return rc;
+ i2o_status_get(c);
- if (i960)
- pci_write_config_word(i960, 0x42, 0x3FF);
+ if (sb->iop_state != ADAPTER_STATE_HOLD) {
+ osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
+ return -EIO;
}
- /* In HOLD state */
-
- rc = i2o_hrt_get(c);
-
- return rc;
+ return i2o_hrt_get(c);
};
/**
@@ -756,20 +702,18 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
res->flags = IORESOURCE_MEM;
res->start = 0;
res->end = 0;
- printk(KERN_INFO "%s: requires private memory resources.\n",
- c->name);
+ osm_info("%s: requires private memory resources.\n", c->name);
root = pci_find_parent_resource(c->pdev, res);
if (root == NULL)
- printk(KERN_WARNING "%s: Can't find parent resource!\n",
- c->name);
+ osm_warn("%s: Can't find parent resource!\n", c->name);
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);
+ osm_info("%s: allocated %ld bytes of PCI memory at "
+ "0x%08lX.\n", c->name,
+ 1 + res->end - res->start, res->start);
}
}
@@ -779,20 +723,18 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
res->flags = IORESOURCE_IO;
res->start = 0;
res->end = 0;
- printk(KERN_INFO "%s: requires private memory resources.\n",
- c->name);
+ osm_info("%s: requires private memory resources.\n", c->name);
root = pci_find_parent_resource(c->pdev, res);
if (root == NULL)
- printk(KERN_WARNING "%s: Can't find parent resource!\n",
- c->name);
+ osm_warn("%s: Can't find parent resource!\n", c->name);
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);
+ osm_info("%s: allocated %ld bytes of PCI I/O at 0x%08lX"
+ ".\n", c->name, 1 + res->end - res->start,
+ res->start);
}
}
@@ -836,10 +778,10 @@ static int i2o_iop_systab_set(struct i2o_controller *c)
PCI_DMA_TODEVICE);
if (rc < 0)
- printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n",
- c->name, -rc);
+ osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
+ -rc);
else
- pr_debug("%s: SysTab set.\n", c->name);
+ osm_debug("%s: SysTab set.\n", c->name);
i2o_status_get(c); // Entered READY state
@@ -863,7 +805,7 @@ static int i2o_iop_online(struct i2o_controller *c)
return rc;
/* In READY state */
- pr_debug("%s: Attempting to enable...\n", c->name);
+ osm_debug("%s: Attempting to enable...\n", c->name);
rc = i2o_iop_enable(c);
if (rc)
return rc;
@@ -882,7 +824,7 @@ void i2o_iop_remove(struct i2o_controller *c)
{
struct i2o_device *dev, *tmp;
- pr_debug("%s: deleting controller\n", c->name);
+ osm_debug("%s: deleting controller\n", c->name);
i2o_driver_notify_controller_remove_all(c);
@@ -891,8 +833,12 @@ void i2o_iop_remove(struct i2o_controller *c)
list_for_each_entry_safe(dev, tmp, &c->devices, list)
i2o_device_remove(dev);
+ device_del(&c->device);
+
/* Ask the IOP to switch to RESET state */
i2o_iop_reset(c);
+
+ put_device(&c->device);
}
/**
@@ -927,8 +873,7 @@ static int i2o_systab_build(void)
systab = i2o_systab.virt = kmalloc(i2o_systab.len, GFP_KERNEL);
if (!systab) {
- printk(KERN_ERR "i2o: unable to allocate memory for System "
- "Table\n");
+ osm_err("unable to allocate memory for System Table\n");
return -ENOMEM;
}
memset(systab, 0, i2o_systab.len);
@@ -940,8 +885,8 @@ static int i2o_systab_build(void)
i2o_status_block *sb;
if (count >= num_controllers) {
- printk(KERN_ERR "i2o: controller added while building "
- "system table\n");
+ osm_err("controller added while building system table"
+ "\n");
break;
}
@@ -955,9 +900,8 @@ static int i2o_systab_build(void)
* 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);
+ osm_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
}
@@ -971,8 +915,10 @@ static int i2o_systab_build(void)
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);
+ systab->iops[count].inbound_low =
+ i2o_dma_low(c->base.phys + I2O_IN_PORT);
+ systab->iops[count].inbound_high =
+ i2o_dma_high(c->base.phys + I2O_IN_PORT);
count++;
}
@@ -1010,11 +956,11 @@ int i2o_status_get(struct i2o_controller *c)
{
struct i2o_message __iomem *msg;
u32 m;
- u8 *status_block;
+ volatile u8 *status_block;
unsigned long timeout;
status_block = (u8 *) c->status_block.virt;
- memset(status_block, 0, sizeof(i2o_status_block));
+ memset(c->status_block.virt, 0, sizeof(i2o_status_block));
m = i2o_msg_get_wait(c, &msg, I2O_TIMEOUT_MESSAGE_GET);
if (m == I2O_QUEUE_EMPTY)
@@ -1027,8 +973,8 @@ int i2o_status_get(struct i2o_controller *c)
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(i2o_dma_low(c->status_block.phys), &msg->body[2]);
+ writel(i2o_dma_high(c->status_block.phys), &msg->body[3]);
writel(sizeof(i2o_status_block), &msg->body[4]); /* always 88 bytes */
i2o_msg_post(c, m);
@@ -1037,14 +983,12 @@ int i2o_status_get(struct i2o_controller *c)
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);
+ osm_err("%s: Get status timeout.\n", c->name);
return -ETIMEDOUT;
}
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
-
- rmb();
}
#ifdef DEBUG
@@ -1088,8 +1032,8 @@ static int i2o_hrt_get(struct i2o_controller *c)
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);
+ osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
+ -rc);
return rc;
}
@@ -1103,13 +1047,41 @@ static int i2o_hrt_get(struct i2o_controller *c)
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);
+ osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
+ I2O_HRT_GET_TRIES);
return -EBUSY;
}
/**
+ * 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_release - release the memory for a I2O controller
+ * @dev: I2O controller which should be released
+ *
+ * Release the allocated memory. This function is called if refcount of
+ * device reaches 0 automatically.
+ */
+static void i2o_iop_release(struct device *dev)
+{
+ struct i2o_controller *c = to_i2o_controller(dev);
+
+ i2o_iop_free(c);
+};
+
+/* I2O controller class */
+static struct class i2o_controller_class = {
+ .name = "i2o_controller",
+};
+
+/**
* i2o_iop_alloc - Allocate and initialize a i2o_controller struct
*
* Allocate the necessary memory for a i2o_controller struct and
@@ -1125,8 +1097,8 @@ struct i2o_controller *i2o_iop_alloc(void)
c = kmalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
- printk(KERN_ERR "i2o: Insufficient memory to allocate a I2O "
- "controller.\n");
+ osm_err("i2o: Insufficient memory to allocate a I2O controller."
+ "\n");
return ERR_PTR(-ENOMEM);
}
memset(c, 0, sizeof(*c));
@@ -1137,6 +1109,16 @@ struct i2o_controller *i2o_iop_alloc(void)
c->unit = unit++;
sprintf(c->name, "iop%d", c->unit);
+ device_initialize(&c->device);
+ class_device_initialize(&c->classdev);
+
+ c->device.release = &i2o_iop_release;
+ c->classdev.class = &i2o_controller_class;
+ c->classdev.dev = &c->device;
+
+ snprintf(c->device.bus_id, BUS_ID_SIZE, "iop%d", c->unit);
+ snprintf(c->classdev.class_id, BUS_ID_SIZE, "iop%d", c->unit);
+
#if BITS_PER_LONG == 64
spin_lock_init(&c->context_list_lock);
atomic_set(&c->context_list_counter, 0);
@@ -1147,15 +1129,6 @@ struct i2o_controller *i2o_iop_alloc(void)
};
/**
- * 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
*
@@ -1168,45 +1141,58 @@ 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 = device_add(&c->device))) {
+ osm_err("%s: could not add controller\n", c->name);
+ goto iop_reset;
+ }
- if ((rc = i2o_iop_activate(c))) {
- printk(KERN_ERR "%s: could not activate controller\n",
- c->name);
- i2o_iop_reset(c);
- return rc;
+ if ((rc = class_device_add(&c->classdev))) {
+ osm_err("%s: could not add controller class\n", c->name);
+ goto device_del;
}
- pr_debug("%s: building sys table...\n", c->name);
+ osm_info("%s: Activating I2O controller...\n", c->name);
+ osm_info("%s: This may take a few minutes if there are many devices\n",
+ c->name);
- if ((rc = i2o_systab_build())) {
- i2o_iop_reset(c);
- return rc;
+ if ((rc = i2o_iop_activate(c))) {
+ osm_err("%s: could not activate controller\n", c->name);
+ goto class_del;
}
- pr_debug("%s: online controller...\n", c->name);
+ osm_debug("%s: building sys table...\n", c->name);
- if ((rc = i2o_iop_online(c))) {
- i2o_iop_reset(c);
- return rc;
- }
+ if ((rc = i2o_systab_build()))
+ goto class_del;
- pr_debug("%s: getting LCT...\n", c->name);
+ osm_debug("%s: online controller...\n", c->name);
- if ((rc = i2o_exec_lct_get(c))) {
- i2o_iop_reset(c);
- return rc;
- }
+ if ((rc = i2o_iop_online(c)))
+ goto class_del;
+
+ osm_debug("%s: getting LCT...\n", c->name);
+
+ if ((rc = i2o_exec_lct_get(c)))
+ goto class_del;
list_add(&c->list, &i2o_controllers);
i2o_driver_notify_controller_add_all(c);
- printk(KERN_INFO "%s: Controller added\n", c->name);
+ osm_info("%s: Controller added\n", c->name);
return 0;
+
+ class_del:
+ class_device_del(&c->classdev);
+
+ device_del:
+ device_del(&c->device);
+
+ iop_reset:
+ i2o_iop_reset(c);
+
+ return rc;
};
/**
@@ -1264,16 +1250,18 @@ static int __init i2o_iop_init(void)
if (rc)
goto exit;
- rc = i2o_driver_init();
- if (rc)
+ if ((rc = class_register(&i2o_controller_class))) {
+ osm_err("can't register class i2o_controller\n");
goto device_exit;
+ }
- rc = i2o_exec_init();
- if (rc)
+ if ((rc = i2o_driver_init()))
+ goto class_exit;
+
+ if ((rc = i2o_exec_init()))
goto driver_exit;
- rc = i2o_pci_init();
- if (rc < 0)
+ if ((rc = i2o_pci_init()))
goto exec_exit;
return 0;
@@ -1284,6 +1272,9 @@ static int __init i2o_iop_init(void)
driver_exit:
i2o_driver_exit();
+ class_exit:
+ class_unregister(&i2o_controller_class);
+
device_exit:
i2o_device_exit();
@@ -1301,6 +1292,7 @@ static void __exit i2o_iop_exit(void)
i2o_pci_exit();
i2o_exec_exit();
i2o_driver_exit();
+ class_unregister(&i2o_controller_class);
i2o_device_exit();
};
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
index e772752f056d..7a60fd7be8ad 100644
--- a/drivers/message/i2o/pci.c
+++ b/drivers/message/i2o/pci.c
@@ -30,53 +30,18 @@
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/i2o.h>
-
-#ifdef CONFIG_MTRR
-#include <asm/mtrr.h>
-#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 *);
+#include "core.h"
/* 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)},
+ {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
+ .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
{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
*
@@ -91,19 +56,11 @@ static void i2o_pci_free(struct i2o_controller *c)
i2o_dma_free(dev, &c->out_queue);
i2o_dma_free(dev, &c->status_block);
- if (c->lct)
- kfree(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);
@@ -178,14 +135,15 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
c->name, (unsigned long)c->base.phys,
(unsigned long)c->base.len);
- c->base.virt = ioremap(c->base.phys, c->base.len);
+ c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
if (!c->base.virt) {
printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
return -ENOMEM;
}
if (c->raptor) {
- c->in_queue.virt = ioremap(c->in_queue.phys, c->in_queue.len);
+ c->in_queue.virt =
+ ioremap_nocache(c->in_queue.phys, c->in_queue.len);
if (!c->in_queue.virt) {
printk(KERN_ERR "%s: Unable to map controller.\n",
c->name);
@@ -195,43 +153,10 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
} 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 "%s: could not enable write combining "
- "MTRR\n", c->name);
- else
- printk(KERN_INFO "%s: using write combining MTRR\n", c->name);
-
- /*
- * 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 "%s: MTRR workaround for Intel i960 processor"
- "\n", c->name);
- c->mtrr_reg1 = mtrr_add(c->base.phys, 0x10000,
- MTRR_TYPE_UNCACHABLE, 1);
-
- if (c->mtrr_reg1 < 0) {
- printk(KERN_WARNING "%s: Error in setting "
- "MTRR_TYPE_UNCACHABLE\n", c->name);
- mtrr_del(c->mtrr_reg0, c->in_queue.phys,
- c->in_queue.len);
- c->mtrr_reg0 = -1;
- }
- }
-#endif
+ c->irq_status = c->base.virt + I2O_IRQ_STATUS;
+ c->irq_mask = c->base.virt + I2O_IRQ_MASK;
+ c->in_port = c->base.virt + I2O_IN_PORT;
+ c->out_port = c->base.virt + I2O_OUT_PORT;
if (i2o_dma_alloc(dev, &c->status, 8, GFP_KERNEL)) {
i2o_pci_free(c);
@@ -254,7 +179,10 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
return -ENOMEM;
}
- if (i2o_dma_alloc(dev, &c->out_queue, MSG_POOL_SIZE, GFP_KERNEL)) {
+ if (i2o_dma_alloc
+ (dev, &c->out_queue,
+ I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+ sizeof(u32), GFP_KERNEL)) {
i2o_pci_free(c);
return -ENOMEM;
}
@@ -276,51 +204,30 @@ static int __devinit i2o_pci_alloc(struct i2o_controller *c)
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;
-
- /*
- * 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("%s: 960 bug detected\n", c->name);
- }
-
- 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 = i2o_msg_out_to_virt(c, mv);
-
- /*
- * Ensure this message is seen coherently but cachably by
- * the processor
- */
- dma_sync_single_for_cpu(dev, mv, MSG_FRAME_SIZE * 4,
- PCI_DMA_FROMDEVICE);
+ u32 m;
+ irqreturn_t rc = IRQ_NONE;
+
+ while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
+ m = readl(c->out_port);
+ if (m == I2O_QUEUE_EMPTY) {
+ /*
+ * Old 960 steppings had a bug in the I2O unit that
+ * caused the queue to appear empty when it wasn't.
+ */
+ m = readl(c->out_port);
+ if (unlikely(m == I2O_QUEUE_EMPTY))
+ break;
+ }
/* dispatch it */
- if (i2o_driver_dispatch(c, mv, m))
+ if (i2o_driver_dispatch(c, m))
/* flush it if result != 0 */
- i2o_flush_reply(c, mv);
+ i2o_flush_reply(c, m);
- /*
- * That 960 bug again...
- */
- mv = I2O_REPLY_READ32(c);
- if (mv == I2O_QUEUE_EMPTY)
- mv = I2O_REPLY_READ32(c);
+ rc = IRQ_HANDLED;
}
- return IRQ_HANDLED;
+
+ return rc;
}
/**
@@ -336,7 +243,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
struct pci_dev *pdev = c->pdev;
int rc;
- I2O_IRQ_WRITE32(c, 0xffffffff);
+ writel(0xffffffff, c->irq_mask);
if (pdev->irq) {
rc = request_irq(pdev->irq, i2o_pci_interrupt, SA_SHIRQ,
@@ -348,7 +255,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
}
}
- I2O_IRQ_WRITE32(c, 0x00000000);
+ writel(0x00000000, c->irq_mask);
printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
@@ -363,7 +270,7 @@ static int i2o_pci_irq_enable(struct i2o_controller *c)
*/
static void i2o_pci_irq_disable(struct i2o_controller *c)
{
- I2O_IRQ_WRITE32(c, 0xffffffff);
+ writel(0xffffffff, c->irq_mask);
if (c->pdev->irq > 0)
free_irq(c->pdev->irq, c);
@@ -385,28 +292,25 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
{
struct i2o_controller *c;
int rc;
+ struct pci_dev *i960 = NULL;
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");
+ printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
+ "(skipping).\n", pci_name(pdev));
return -ENODEV;
}
if ((rc = pci_enable_device(pdev))) {
- printk(KERN_WARNING "i2o: I2O controller found but could not be"
- " enabled.\n");
+ printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+ pci_name(pdev));
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);
+ printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
+ pci_name(pdev));
rc = -ENODEV;
goto disable;
}
@@ -415,14 +319,16 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
c = i2o_iop_alloc();
if (IS_ERR(c)) {
- printk(KERN_ERR "i2o: memory for I2O controller could not be "
- "allocated\n");
+ printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
+ pci_name(pdev));
rc = PTR_ERR(c);
goto disable;
- }
+ } else
+ printk(KERN_INFO "%s: controller found (%s)\n", c->name,
+ pci_name(pdev));
c->pdev = pdev;
- c->device = pdev->dev;
+ c->device.parent = get_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) {
@@ -432,16 +338,48 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
}
if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
+ /*
+ * Expose the ship behind i960 for initialization, or it will
+ * failed
+ */
+ i960 =
+ pci_find_slot(c->pdev->bus->number,
+ PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+
+ if (i960)
+ pci_write_config_word(i960, 0x42, 0);
+
c->promise = 1;
- printk(KERN_INFO "%s: Promise workarounds activated.\n",
- c->name);
+ c->limit_sectors = 1;
}
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
+ c->adaptec = 1;
+
/* 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 (pdev->subsystem_device == 0xc05a) {
+ c->limit_sectors = 1;
+ printk(KERN_INFO
+ "%s: limit sectors per request to %d\n", c->name,
+ I2O_MAX_SECTORS_LIMITED);
+ }
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if (sizeof(dma_addr_t) > 4) {
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+ printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
+ c->name);
+ else {
+ c->pae_support = 1;
+ printk(KERN_INFO "%s: using 64-bit DMA\n",
+ c->name);
+ }
+ }
+#endif
}
if ((rc = i2o_pci_alloc(c))) {
@@ -459,6 +397,11 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
if ((rc = i2o_iop_add(c)))
goto uninstall;
+ get_device(&c->device);
+
+ if (i960)
+ pci_write_config_word(i960, 0x42, 0x03ff);
+
return 0;
uninstall:
@@ -469,6 +412,7 @@ static int __devinit i2o_pci_probe(struct pci_dev *pdev,
free_controller:
i2o_iop_free(c);
+ put_device(c->device.parent);
disable:
pci_disable_device(pdev);
@@ -492,15 +436,17 @@ static void __devexit i2o_pci_remove(struct pci_dev *pdev)
i2o_pci_irq_disable(c);
i2o_pci_free(c);
+ pci_disable_device(pdev);
+
printk(KERN_INFO "%s: Controller removed.\n", c->name);
- i2o_iop_free(c);
- pci_disable_device(pdev);
+ put_device(c->device.parent);
+ put_device(&c->device);
};
/* PCI driver for I2O controller */
static struct pci_driver i2o_pci_driver = {
- .name = "I2O controller",
+ .name = "PCI_I2O",
.id_table = i2o_pci_ids,
.probe = i2o_pci_probe,
.remove = __devexit_p(i2o_pci_remove),
@@ -523,6 +469,4 @@ void __exit i2o_pci_exit(void)
{
pci_unregister_driver(&i2o_pci_driver);
};
-
-EXPORT_SYMBOL(i2o_dma_realloc);
MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 4cecdafeb87d..7fc692a8f5b0 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -6,8 +6,7 @@ menu "Misc devices"
config IBM_ASM
tristate "Device driver for IBM RSA service processor"
- depends on X86 && EXPERIMENTAL
- default n
+ depends on X86 && PCI && EXPERIMENTAL
---help---
This option enables device driver support for in-band access to the
IBM RSA (Condor) service processor in eServer xSeries systems.
@@ -22,7 +21,7 @@ config IBM_ASM
WARNING: This software may not be supported or function
correctly on your IBM server. Please consult the IBM ServerProven
- website <http://www.pc.ibm/ww/eserver/xseries/serverproven> for
+ website <http://www.pc.ibm.com/ww/eserver/xseries/serverproven> for
information on the specific driver level and support statement
for your IBM server.
diff --git a/drivers/mmc/mmci.c b/drivers/mmc/mmci.c
index 3a5f6ac5b364..7a42966d755b 100644
--- a/drivers/mmc/mmci.c
+++ b/drivers/mmc/mmci.c
@@ -20,6 +20,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/protocol.h>
+#include <asm/div64.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/scatterlist.h>
@@ -70,6 +71,7 @@ static void mmci_stop_data(struct mmci_host *host)
static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
{
unsigned int datactrl, timeout, irqmask;
+ unsigned long long clks;
void __iomem *base;
DBG(host, "blksz %04x blks %04x flags %08x\n",
@@ -81,9 +83,10 @@ static void mmci_start_data(struct mmci_host *host, struct mmc_data *data)
mmci_init_sg(host, data);
- timeout = data->timeout_clks +
- ((unsigned long long)data->timeout_ns * host->cclk) /
- 1000000000ULL;
+ clks = (unsigned long long)data->timeout_ns * host->cclk;
+ do_div(clks, 1000000000UL);
+
+ timeout = data->timeout_clks + (unsigned int)clks;
base = host->base;
writel(timeout, base + MMCIDATATIMER);
diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c
index b7fbd30b49a0..0c41d4b41a65 100644
--- a/drivers/mmc/wbsd.c
+++ b/drivers/mmc/wbsd.c
@@ -54,28 +54,6 @@
#define DBGF(x...) do { } while (0)
#endif
-#ifdef CONFIG_MMC_DEBUG
-void DBG_REG(int reg, u8 value)
-{
- int i;
-
- printk(KERN_DEBUG "wbsd: Register %d: 0x%02X %3d '%c' ",
- reg, (int)value, (int)value, (value < 0x20)?'.':value);
-
- for (i = 7;i >= 0;i--)
- {
- if (value & (1 << i))
- printk("x");
- else
- printk(".");
- }
-
- printk("\n");
-}
-#else
-#define DBG_REG(r, v) do {} while (0)
-#endif
-
/*
* Device resources
*/
@@ -92,6 +70,13 @@ MODULE_DEVICE_TABLE(pnp, pnp_dev_table);
#endif /* CONFIG_PNP */
+static const int config_ports[] = { 0x2E, 0x4E };
+static const int unlock_codes[] = { 0x83, 0x87 };
+
+static const int valid_ids[] = {
+ 0x7112,
+ };
+
#ifdef CONFIG_PNP
static unsigned int nopnp = 0;
#else
@@ -1051,6 +1036,20 @@ static struct mmc_host_ops wbsd_ops = {
\*****************************************************************************/
/*
+ * Helper function for card detection
+ */
+static void wbsd_detect_card(unsigned long data)
+{
+ struct wbsd_host *host = (struct wbsd_host*)data;
+
+ BUG_ON(host == NULL);
+
+ DBG("Executing card detection\n");
+
+ mmc_detect_change(host->mmc);
+}
+
+/*
* Tasklets
*/
@@ -1075,7 +1074,6 @@ static void wbsd_tasklet_card(unsigned long param)
{
struct wbsd_host* host = (struct wbsd_host*)param;
u8 csr;
- int change = 0;
spin_lock(&host->lock);
@@ -1094,14 +1092,20 @@ static void wbsd_tasklet_card(unsigned long param)
{
DBG("Card inserted\n");
host->flags |= WBSD_FCARD_PRESENT;
- change = 1;
+
+ /*
+ * Delay card detection to allow electrical connections
+ * to stabilise.
+ */
+ mod_timer(&host->timer, jiffies + HZ/2);
}
+
+ spin_unlock(&host->lock);
}
else if (host->flags & WBSD_FCARD_PRESENT)
{
DBG("Card removed\n");
host->flags &= ~WBSD_FCARD_PRESENT;
- change = 1;
if (host->mrq)
{
@@ -1112,15 +1116,14 @@ static void wbsd_tasklet_card(unsigned long param)
host->mrq->cmd->error = MMC_ERR_FAILED;
tasklet_schedule(&host->finish_tasklet);
}
- }
-
- /*
- * Unlock first since we might get a call back.
- */
- spin_unlock(&host->lock);
+
+ /*
+ * Unlock first since we might get a call back.
+ */
+ spin_unlock(&host->lock);
- if (change)
mmc_detect_change(host->mmc);
+ }
}
static void wbsd_tasklet_fifo(unsigned long param)
@@ -1325,6 +1328,13 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
spin_lock_init(&host->lock);
/*
+ * Set up detection timer
+ */
+ init_timer(&host->timer);
+ host->timer.data = (unsigned long)host;
+ host->timer.function = wbsd_detect_card;
+
+ /*
* Maximum number of segments. Worst case is one sector per segment
* so this will be 64kB/512.
*/
@@ -1351,11 +1361,17 @@ static int __devinit wbsd_alloc_mmc(struct device* dev)
static void __devexit wbsd_free_mmc(struct device* dev)
{
struct mmc_host* mmc;
+ struct wbsd_host* host;
mmc = dev_get_drvdata(dev);
if (!mmc)
return;
+ host = mmc_priv(mmc);
+ BUG_ON(host == NULL);
+
+ del_timer_sync(&host->timer);
+
mmc_free_host(mmc);
dev_set_drvdata(dev, NULL);
diff --git a/drivers/mmc/wbsd.h b/drivers/mmc/wbsd.h
index 864f30828d01..661a9f6a6e6f 100644
--- a/drivers/mmc/wbsd.h
+++ b/drivers/mmc/wbsd.h
@@ -8,13 +8,6 @@
* published by the Free Software Foundation.
*/
-const int config_ports[] = { 0x2E, 0x4E };
-const int unlock_codes[] = { 0x83, 0x87 };
-
-const int valid_ids[] = {
- 0x7112,
- };
-
#define LOCK_CODE 0xAA
#define WBSD_CONF_SWRST 0x02
@@ -187,4 +180,6 @@ struct wbsd_host
struct tasklet_struct timeout_tasklet;
struct tasklet_struct finish_tasklet;
struct tasklet_struct block_tasklet;
+
+ struct timer_list timer; /* Card detection timer */
};
diff --git a/drivers/mtd/afs.c b/drivers/mtd/afs.c
index 801e6c7d0892..7363e101eb0f 100644
--- a/drivers/mtd/afs.c
+++ b/drivers/mtd/afs.c
@@ -219,7 +219,7 @@ static int parse_afs_partitions(struct mtd_info *mtd,
*/
for (idx = off = 0; off < mtd->size; off += mtd->erasesize) {
struct image_info_struct iis;
- u_int iis_ptr, img_ptr, size;
+ u_int iis_ptr, img_ptr;
/* Read the footer. */
ret = afs_read_footer(mtd, &img_ptr, &iis_ptr, off, mask);
@@ -236,21 +236,9 @@ static int parse_afs_partitions(struct mtd_info *mtd,
continue;
strcpy(str, iis.name);
- size = mtd->erasesize + off - img_ptr;
-
- /*
- * In order to support JFFS2 partitions on this layout,
- * we must lie to MTD about the real size of JFFS2
- * partitions; this ensures that the AFS flash footer
- * won't be erased by JFFS2. Please ensure that your
- * JFFS2 partitions are given image numbers between
- * 1000 and 2000 inclusive.
- */
- if (iis.imageNumber >= 1000 && iis.imageNumber < 2000)
- size -= mtd->erasesize;
parts[idx].name = str;
- parts[idx].size = size;
+ parts[idx].size = (iis.length + mtd->erasesize - 1) & ~(mtd->erasesize - 1);
parts[idx].offset = img_ptr;
parts[idx].mask_flags = 0;
diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
index d682dbc8157e..b5dc59389bb3 100644
--- a/drivers/mtd/chips/Kconfig
+++ b/drivers/mtd/chips/Kconfig
@@ -1,5 +1,5 @@
# drivers/mtd/chips/Kconfig
-# $Id: Kconfig,v 1.13 2004/12/01 15:49:10 nico Exp $
+# $Id: Kconfig,v 1.15 2005/06/06 23:04:35 tpoynor Exp $
menu "RAM/ROM/Flash chip drivers"
depends on MTD!=n
@@ -155,6 +155,31 @@ config MTD_CFI_I8
If your flash chips are interleaved in eights - i.e. you have eight
flash chips addressed by each bus cycle, then say 'Y'.
+config MTD_OTP
+ bool "Protection Registers aka one-time programmable (OTP) bits"
+ depends on MTD_CFI_ADV_OPTIONS
+ default n
+ help
+ This enables support for reading, writing and locking so called
+ "Protection Registers" present on some flash chips.
+ A subset of them are pre-programmed at the factory with a
+ unique set of values. The rest is user-programmable.
+
+ The user-programmable Protection Registers contain one-time
+ programmable (OTP) bits; when programmed, register bits cannot be
+ erased. Each Protection Register can be accessed multiple times to
+ program individual bits, as long as the register remains unlocked.
+
+ Each Protection Register has an associated Lock Register bit. When a
+ Lock Register bit is programmed, the associated Protection Register
+ can only be read; it can no longer be programmed. Additionally,
+ because the Lock Register bits themselves are OTP, when programmed,
+ Lock Register bits cannot be erased. Therefore, when a Protection
+ Register is locked, it cannot be unlocked.
+
+ This feature should therefore be used with extreme care. Any mistake
+ in the programming of OTP bits will waste them.
+
config MTD_CFI_INTELEXT
tristate "Support for Intel/Sharp flash chips"
depends on MTD_GEN_PROBE
@@ -275,7 +300,7 @@ config MTD_JEDEC
config MTD_XIP
bool "XIP aware MTD support"
- depends on !SMP && MTD_CFI_INTELEXT && EXPERIMENTAL
+ depends on !SMP && (MTD_CFI_INTELEXT || MTD_CFI_AMDSTD) && EXPERIMENTAL
default y if XIP_KERNEL
help
This allows MTD support to work with flash memory which is also
diff --git a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c
index 41e2e3e31603..2dafeba3f3d5 100644
--- a/drivers/mtd/chips/amd_flash.c
+++ b/drivers/mtd/chips/amd_flash.c
@@ -3,7 +3,7 @@
*
* Author: Jonas Holmberg <jonas.holmberg@axis.com>
*
- * $Id: amd_flash.c,v 1.26 2004/11/20 12:49:04 dwmw2 Exp $
+ * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
*
* Copyright (c) 2001 Axis Communications AB
*
@@ -67,7 +67,6 @@
#define AM29LV160DT 0x22C4
#define AM29LV160DB 0x2249
#define AM29BDS323D 0x22D1
-#define AM29BDS643D 0x227E
/* Atmel */
#define AT49xV16x 0x00C0
@@ -618,17 +617,6 @@ static struct mtd_info *amd_flash_probe(struct map_info *map)
{ .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 },
}
}, {
- .mfr_id = MANUFACTURER_AMD,
- .dev_id = AM29BDS643D,
- .name = "AMD AM29BDS643D",
- .size = 0x00800000,
- .numeraseregions = 3,
- .regions = {
- { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 },
- { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 },
- { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 },
- }
- }, {
.mfr_id = MANUFACTURER_ATMEL,
.dev_id = AT49xV16x,
.name = "Atmel AT49xV16x",
diff --git a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
index c268bcd71720..0cfcd88468e0 100644
--- a/drivers/mtd/chips/cfi_cmdset_0001.c
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c
@@ -4,7 +4,7 @@
*
* (C) 2000 Red Hat. GPL'd
*
- * $Id: cfi_cmdset_0001.c,v 1.164 2004/11/16 18:29:00 dwmw2 Exp $
+ * $Id: cfi_cmdset_0001.c,v 1.178 2005/05/19 17:05:43 nico Exp $
*
*
* 10/10/2000 Nicolas Pitre <nico@cam.org>
@@ -29,6 +29,7 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/reboot.h>
#include <linux/mtd/xip.h>
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
@@ -48,16 +49,25 @@
#define M50LPW080 0x002F
static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
-//static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *);
static void cfi_intelext_sync (struct mtd_info *);
static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len);
static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len);
+#ifdef CONFIG_MTD_OTP
+static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
+static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
+static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
+ struct otp_info *, size_t);
+static int cfi_intelext_get_user_prot_info (struct mtd_info *,
+ struct otp_info *, size_t);
+#endif
static int cfi_intelext_suspend (struct mtd_info *);
static void cfi_intelext_resume (struct mtd_info *);
+static int cfi_intelext_reboot (struct notifier_block *, unsigned long, void *);
static void cfi_intelext_destroy(struct mtd_info *);
@@ -252,7 +262,8 @@ read_pri_intelext(struct map_info *map, __u16 adr)
int nb_parts, i;
/* Protection Register info */
- extra_size += (extp->NumProtectionFields - 1) * (4 + 6);
+ extra_size += (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
extra_size += 6;
@@ -324,7 +335,9 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
mtd->resume = cfi_intelext_resume;
mtd->flags = MTD_CAP_NORFLASH;
mtd->name = map->name;
-
+
+ mtd->reboot_notifier.notifier_call = cfi_intelext_reboot;
+
if (cfi->cfi_mode == CFI_MODE_CFI) {
/*
* It's a real CFI chip, not one for which the probe
@@ -422,9 +435,13 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
mtd->eraseregions[i].numblocks);
}
-#if 0
- mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+#ifdef CONFIG_MTD_OTP
mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg;
+ mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg;
+ mtd->write_user_prot_reg = cfi_intelext_write_user_prot_reg;
+ mtd->lock_user_prot_reg = cfi_intelext_lock_user_prot_reg;
+ mtd->get_fact_prot_info = cfi_intelext_get_fact_prot_info;
+ mtd->get_user_prot_info = cfi_intelext_get_user_prot_info;
#endif
/* This function has the potential to distort the reality
@@ -433,6 +450,7 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
goto setup_err;
__module_get(THIS_MODULE);
+ register_reboot_notifier(&mtd->reboot_notifier);
return mtd;
setup_err:
@@ -471,7 +489,8 @@ static int cfi_intelext_partition_fixup(struct mtd_info *mtd,
int offs, numregions, numparts, partshift, numvirtchips, i, j;
/* Protection Register info */
- offs = (extp->NumProtectionFields - 1) * (4 + 6);
+ offs = (extp->NumProtectionFields - 1) *
+ sizeof(struct cfi_intelext_otpinfo);
/* Burst Read info */
offs += 6;
@@ -563,7 +582,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
resettime:
timeo = jiffies + HZ;
retry:
- if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING)) {
+ if (chip->priv && (mode == FL_WRITING || mode == FL_ERASING || mode == FL_OTP_WRITE)) {
/*
* OK. We have possibility for contension on the write/erase
* operations which are global to the real chip and not per
@@ -807,10 +826,6 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
* assembly to make sure inline functions were actually inlined and that gcc
* didn't emit calls to its own support functions). Also configuring MTD CFI
* support to a single buswidth and a single interleave is also recommended.
- * Note that not only IRQs are disabled but the preemption count is also
- * increased to prevent other locking primitives (namely spin_unlock) from
- * decrementing the preempt count to zero and scheduling the CPU away while
- * not in array mode.
*/
static void xip_disable(struct map_info *map, struct flchip *chip,
@@ -818,7 +833,6 @@ static void xip_disable(struct map_info *map, struct flchip *chip,
{
/* TODO: chips with no XIP use should ignore and return */
(void) map_read(map, adr); /* ensure mmu mapping is up to date */
- preempt_disable();
local_irq_disable();
}
@@ -831,9 +845,8 @@ static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
chip->state = FL_READY;
}
(void) map_read(map, adr);
- asm volatile (".rep 8; nop; .endr"); /* fill instruction prefetch */
+ xip_iprefetch();
local_irq_enable();
- preempt_enable();
}
/*
@@ -909,7 +922,7 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
(void) map_read(map, adr);
asm volatile (".rep 8; nop; .endr");
local_irq_enable();
- preempt_enable();
+ spin_unlock(chip->mutex);
asm volatile (".rep 8; nop; .endr");
cond_resched();
@@ -919,15 +932,15 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* a suspended erase state. If so let's wait
* until it's done.
*/
- preempt_disable();
+ spin_lock(chip->mutex);
while (chip->state != newstate) {
DECLARE_WAITQUEUE(wait, current);
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- preempt_enable();
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- preempt_disable();
+ spin_lock(chip->mutex);
}
/* Disallow XIP again */
local_irq_disable();
@@ -956,12 +969,14 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
* The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
* the flash is actively programming or erasing since we have to poll for
* the operation to complete anyway. We can't do that in a generic way with
- * a XIP setup so do it before the actual flash operation in this case.
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
*/
-#undef INVALIDATE_CACHED_RANGE
-#define INVALIDATE_CACHED_RANGE(x...)
-#define XIP_INVAL_CACHED_RANGE(map, from, size) \
- do { if(map->inval_cache) map->inval_cache(map, from, size); } while(0)
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+ INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+ UDELAY(map, chip, adr, usec)
/*
* Extra notes:
@@ -984,11 +999,23 @@ static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
#define xip_disable(map, chip, adr)
#define xip_enable(map, chip, adr)
-
-#define UDELAY(map, chip, adr, usec) cfi_udelay(usec)
-
#define XIP_INVAL_CACHED_RANGE(x...)
+#define UDELAY(map, chip, adr, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ INVALIDATE_CACHED_RANGE(map, adr, len); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
#endif
static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len)
@@ -1176,111 +1203,11 @@ static int cfi_intelext_read (struct mtd_info *mtd, loff_t from, size_t len, siz
return ret;
}
-#if 0
-static int __xipram cfi_intelext_read_prot_reg (struct mtd_info *mtd,
- loff_t from, size_t len,
- size_t *retlen,
- u_char *buf,
- int base_offst, int reg_sz)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp = cfi->cmdset_priv;
- struct flchip *chip;
- int ofs_factor = cfi->interleave * cfi->device_type;
- int count = len;
- int chip_num, offst;
- int ret;
-
- chip_num = ((unsigned int)from/reg_sz);
- offst = from - (reg_sz*chip_num)+base_offst;
-
- while (count) {
- /* Calculate which chip & protection register offset we need */
-
- if (chip_num >= cfi->numchips)
- goto out;
-
- chip = &cfi->chips[chip_num];
-
- spin_lock(chip->mutex);
- ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
- if (ret) {
- spin_unlock(chip->mutex);
- return (len-count)?:ret;
- }
-
- xip_disable(map, chip, chip->start);
-
- if (chip->state != FL_JEDEC_QUERY) {
- map_write(map, CMD(0x90), chip->start);
- chip->state = FL_JEDEC_QUERY;
- }
-
- while (count && ((offst-base_offst) < reg_sz)) {
- *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst));
- buf++;
- offst++;
- count--;
- }
-
- xip_enable(map, chip, chip->start);
- put_chip(map, chip, chip->start);
- spin_unlock(chip->mutex);
-
- /* Move on to the next chip */
- chip_num++;
- offst = base_offst;
- }
-
- out:
- return len-count;
-}
-
-static int cfi_intelext_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
- int base_offst,reg_sz;
-
- /* Check that we actually have some protection registers */
- if(!extp || !(extp->FeatureSupport&64)){
- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- return 0;
- }
-
- base_offst=(1<<extp->FactProtRegSize);
- reg_sz=(1<<extp->UserProtRegSize);
-
- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-
-static int cfi_intelext_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
-{
- struct map_info *map = mtd->priv;
- struct cfi_private *cfi = map->fldrv_priv;
- struct cfi_pri_intelext *extp=cfi->cmdset_priv;
- int base_offst,reg_sz;
-
- /* Check that we actually have some protection registers */
- if(!extp || !(extp->FeatureSupport&64)){
- printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name);
- return 0;
- }
-
- base_offst=0;
- reg_sz=(1<<extp->FactProtRegSize);
-
- return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz);
-}
-#endif
-
static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
- unsigned long adr, map_word datum)
+ unsigned long adr, map_word datum, int mode)
{
struct cfi_private *cfi = map->fldrv_priv;
- map_word status, status_OK;
+ map_word status, status_OK, write_cmd;
unsigned long timeo;
int z, ret=0;
@@ -1288,9 +1215,14 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
/* Let's determine this according to the interleave only once */
status_OK = CMD(0x80);
+ switch (mode) {
+ case FL_WRITING: write_cmd = CMD(0x40); break;
+ case FL_OTP_WRITE: write_cmd = CMD(0xc0); break;
+ default: return -EINVAL;
+ }
spin_lock(chip->mutex);
- ret = get_chip(map, chip, adr, FL_WRITING);
+ ret = get_chip(map, chip, adr, mode);
if (ret) {
spin_unlock(chip->mutex);
return ret;
@@ -1299,19 +1231,18 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
ENABLE_VPP(map);
xip_disable(map, chip, adr);
- map_write(map, CMD(0x40), adr);
+ map_write(map, write_cmd, adr);
map_write(map, datum, adr);
- chip->state = FL_WRITING;
+ chip->state = mode;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, map_bankwidth(map));
- UDELAY(map, chip, adr, chip->word_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
timeo = jiffies + (HZ/2);
z = 0;
for (;;) {
- if (chip->state != FL_WRITING) {
+ if (chip->state != mode) {
/* Someone's suspended the write. Sleep */
DECLARE_WAITQUEUE(wait, current);
@@ -1339,10 +1270,8 @@ static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
z++;
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
if (!z) {
chip->word_write_time--;
@@ -1399,7 +1328,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
datum = map_word_load_partial(map, datum, buf, gap, n);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- bus_ofs, datum);
+ bus_ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1420,7 +1349,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
map_word datum = map_word_load(map, buf);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum);
+ ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1444,7 +1373,7 @@ static int cfi_intelext_write_words (struct mtd_info *mtd, loff_t to , size_t le
datum = map_word_load_partial(map, datum, buf, 0, len);
ret = do_write_oneword(map, &cfi->chips[chipnum],
- ofs, datum);
+ ofs, datum, FL_WRITING);
if (ret)
return ret;
@@ -1506,9 +1435,7 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
if (map_word_andequal(map, status, status_OK, status_OK))
break;
- spin_unlock(chip->mutex);
UDELAY(map, chip, cmd_adr, 1);
- spin_lock(chip->mutex);
if (++z > 20) {
/* Argh. Not ready for write to buffer */
@@ -1554,10 +1481,9 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0xd0), cmd_adr);
chip->state = FL_WRITING;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, cmd_adr, chip->buffer_write_time);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ cmd_adr, len,
+ chip->buffer_write_time);
timeo = jiffies + (HZ/2);
z = 0;
@@ -1589,10 +1515,8 @@ static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
- UDELAY(map, chip, cmd_adr, 1);
z++;
- spin_lock(chip->mutex);
+ UDELAY(map, chip, cmd_adr, 1);
}
if (!z) {
chip->buffer_write_time--;
@@ -1720,10 +1644,9 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
chip->state = FL_ERASING;
chip->erase_suspended = 0;
- spin_unlock(chip->mutex);
- INVALIDATE_CACHED_RANGE(map, adr, len);
- UDELAY(map, chip, adr, chip->erase_time*1000/2);
- spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, len,
+ chip->erase_time*1000/2);
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1768,9 +1691,7 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
}
/* We've broken this before. It doesn't hurt to be safe */
@@ -1780,44 +1701,34 @@ static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip,
/* check for lock bit */
if (map_word_bitsset(map, status, CMD(0x3a))) {
- unsigned char chipstatus;
+ unsigned long chipstatus;
/* Reset the error bits */
map_write(map, CMD(0x50), adr);
map_write(map, CMD(0x70), adr);
xip_enable(map, chip, adr);
- chipstatus = status.x[0];
- if (!map_word_equal(map, status, CMD(chipstatus))) {
- int i, w;
- for (w=0; w<map_words(map); w++) {
- for (i = 0; i<cfi_interleave(cfi); i++) {
- chipstatus |= status.x[w] >> (cfi->device_type * 8);
- }
- }
- printk(KERN_WARNING "Status is not identical for all chips: 0x%lx. Merging to give 0x%02x\n",
- status.x[0], chipstatus);
- }
+ chipstatus = MERGESTATUS(status);
if ((chipstatus & 0x30) == 0x30) {
- printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", chipstatus);
+ printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%lx\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x02) {
/* Protection bit set */
ret = -EROFS;
} else if (chipstatus & 0x8) {
/* Voltage */
- printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", chipstatus);
+ printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%lx\n", chipstatus);
ret = -EIO;
} else if (chipstatus & 0x20) {
if (retries--) {
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, chipstatus);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx. Retrying...\n", adr, chipstatus);
timeo = jiffies + HZ;
put_chip(map, chip, adr);
spin_unlock(chip->mutex);
goto retry;
}
- printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, chipstatus);
+ printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%lx\n", adr, chipstatus);
ret = -EIO;
}
} else {
@@ -1882,6 +1793,7 @@ static void cfi_intelext_sync (struct mtd_info *mtd)
if (chip->state == FL_SYNCING) {
chip->state = chip->oldstate;
+ chip->oldstate = FL_READY;
wake_up(&chip->wq);
}
spin_unlock(chip->mutex);
@@ -1897,8 +1809,9 @@ static int __xipram do_printlockstatus_oneblock(struct map_info *map,
struct cfi_private *cfi = map->fldrv_priv;
int status, ofs_factor = cfi->interleave * cfi->device_type;
+ adr += chip->start;
xip_disable(map, chip, adr+(2*ofs_factor));
- cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL);
+ map_write(map, CMD(0x90), adr+(2*ofs_factor));
chip->state = FL_JEDEC_QUERY;
status = cfi_read_query(map, adr+(2*ofs_factor));
xip_enable(map, chip, 0);
@@ -1915,6 +1828,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
map_word status, status_OK;
unsigned long timeo = jiffies + HZ;
int ret;
@@ -1944,9 +1858,13 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
} else
BUG();
- spin_unlock(chip->mutex);
- UDELAY(map, chip, adr, 1000000/HZ);
- spin_lock(chip->mutex);
+ /*
+ * If Instant Individual Block Locking supported then no need
+ * to delay.
+ */
+
+ if (!extp || !(extp->FeatureSupport & (1 << 5)))
+ UDELAY(map, chip, adr, 1000000/HZ);
/* FIXME. Use a timer to check this, and return immediately. */
/* Once the state machine's known to be working I'll do that */
@@ -1973,9 +1891,7 @@ static int __xipram do_xxlock_oneblock(struct map_info *map, struct flchip *chip
}
/* Latency issues. Drop the lock, wait a while and retry */
- spin_unlock(chip->mutex);
UDELAY(map, chip, adr, 1);
- spin_lock(chip->mutex);
}
/* Done and happy. */
@@ -2034,6 +1950,274 @@ static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
return ret;
}
+#ifdef CONFIG_MTD_OTP
+
+typedef int (*otp_op_t)(struct map_info *map, struct flchip *chip,
+ u_long data_offset, u_char *buf, u_int size,
+ u_long prot_offset, u_int groupno, u_int groupsize);
+
+static int __xipram
+do_otp_read(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ int ret;
+
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY);
+ if (ret) {
+ spin_unlock(chip->mutex);
+ return ret;
+ }
+
+ /* let's ensure we're not reading back cached data from array mode */
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+ xip_disable(map, chip, chip->start);
+ if (chip->state != FL_JEDEC_QUERY) {
+ map_write(map, CMD(0x90), chip->start);
+ chip->state = FL_JEDEC_QUERY;
+ }
+ map_copy_from(map, buf, chip->start + offset, size);
+ xip_enable(map, chip, chip->start);
+
+ /* then ensure we don't keep OTP data in the cache */
+ INVALIDATE_CACHED_RANGE(map, chip->start + offset, size);
+
+ put_chip(map, chip, chip->start);
+ spin_unlock(chip->mutex);
+ return 0;
+}
+
+static int
+do_otp_write(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ int ret;
+
+ while (size) {
+ unsigned long bus_ofs = offset & ~(map_bankwidth(map)-1);
+ int gap = offset - bus_ofs;
+ int n = min_t(int, size, map_bankwidth(map)-gap);
+ map_word datum = map_word_ff(map);
+
+ datum = map_word_load_partial(map, datum, buf, gap, n);
+ ret = do_write_oneword(map, chip, bus_ofs, datum, FL_OTP_WRITE);
+ if (ret)
+ return ret;
+
+ offset += n;
+ buf += n;
+ size -= n;
+ }
+
+ return 0;
+}
+
+static int
+do_otp_lock(struct map_info *map, struct flchip *chip, u_long offset,
+ u_char *buf, u_int size, u_long prot, u_int grpno, u_int grpsz)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ map_word datum;
+
+ /* make sure area matches group boundaries */
+ if (size != grpsz)
+ return -EXDEV;
+
+ datum = map_word_ff(map);
+ datum = map_word_clr(map, datum, CMD(1 << grpno));
+ return do_write_oneword(map, chip, prot, datum, FL_OTP_WRITE);
+}
+
+static int cfi_intelext_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf,
+ otp_op_t action, int user_regs)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_intelext *extp = cfi->cmdset_priv;
+ struct flchip *chip;
+ struct cfi_intelext_otpinfo *otp;
+ u_long devsize, reg_prot_offset, data_offset;
+ u_int chip_num, chip_step, field, reg_fact_size, reg_user_size;
+ u_int groups, groupno, groupsize, reg_fact_groups, reg_user_groups;
+ int ret;
+
+ *retlen = 0;
+
+ /* Check that we actually have some OTP registers */
+ if (!extp || !(extp->FeatureSupport & 64) || !extp->NumProtectionFields)
+ return -ENODATA;
+
+ /* we need real chips here not virtual ones */
+ devsize = (1 << cfi->cfiq->DevSize) * cfi->interleave;
+ chip_step = devsize >> cfi->chipshift;
+ chip_num = 0;
+
+ /* Some chips have OTP located in the _top_ partition only.
+ For example: Intel 28F256L18T (T means top-parameter device) */
+ if (cfi->mfr == MANUFACTURER_INTEL) {
+ switch (cfi->id) {
+ case 0x880b:
+ case 0x880c:
+ case 0x880d:
+ chip_num = chip_step - 1;
+ }
+ }
+
+ for ( ; chip_num < cfi->numchips; chip_num += chip_step) {
+ chip = &cfi->chips[chip_num];
+ otp = (struct cfi_intelext_otpinfo *)&extp->extra[0];
+
+ /* first OTP region */
+ field = 0;
+ reg_prot_offset = extp->ProtRegAddr;
+ reg_fact_groups = 1;
+ reg_fact_size = 1 << extp->FactProtRegSize;
+ reg_user_groups = 1;
+ reg_user_size = 1 << extp->UserProtRegSize;
+
+ while (len > 0) {
+ /* flash geometry fixup */
+ data_offset = reg_prot_offset + 1;
+ data_offset *= cfi->interleave * cfi->device_type;
+ reg_prot_offset *= cfi->interleave * cfi->device_type;
+ reg_fact_size *= cfi->interleave;
+ reg_user_size *= cfi->interleave;
+
+ if (user_regs) {
+ groups = reg_user_groups;
+ groupsize = reg_user_size;
+ /* skip over factory reg area */
+ groupno = reg_fact_groups;
+ data_offset += reg_fact_groups * reg_fact_size;
+ } else {
+ groups = reg_fact_groups;
+ groupsize = reg_fact_size;
+ groupno = 0;
+ }
+
+ while (len > 0 && groups > 0) {
+ if (!action) {
+ /*
+ * Special case: if action is NULL
+ * we fill buf with otp_info records.
+ */
+ struct otp_info *otpinfo;
+ map_word lockword;
+ len -= sizeof(struct otp_info);
+ if (len <= 0)
+ return -ENOSPC;
+ ret = do_otp_read(map, chip,
+ reg_prot_offset,
+ (u_char *)&lockword,
+ map_bankwidth(map),
+ 0, 0, 0);
+ if (ret)
+ return ret;
+ otpinfo = (struct otp_info *)buf;
+ otpinfo->start = from;
+ otpinfo->length = groupsize;
+ otpinfo->locked =
+ !map_word_bitsset(map, lockword,
+ CMD(1 << groupno));
+ from += groupsize;
+ buf += sizeof(*otpinfo);
+ *retlen += sizeof(*otpinfo);
+ } else if (from >= groupsize) {
+ from -= groupsize;
+ data_offset += groupsize;
+ } else {
+ int size = groupsize;
+ data_offset += from;
+ size -= from;
+ from = 0;
+ if (size > len)
+ size = len;
+ ret = action(map, chip, data_offset,
+ buf, size, reg_prot_offset,
+ groupno, groupsize);
+ if (ret < 0)
+ return ret;
+ buf += size;
+ len -= size;
+ *retlen += size;
+ data_offset += size;
+ }
+ groupno++;
+ groups--;
+ }
+
+ /* next OTP region */
+ if (++field == extp->NumProtectionFields)
+ break;
+ reg_prot_offset = otp->ProtRegAddr;
+ reg_fact_groups = otp->FactGroups;
+ reg_fact_size = 1 << otp->FactProtRegSize;
+ reg_user_groups = otp->UserGroups;
+ reg_user_size = 1 << otp->UserProtRegSize;
+ otp++;
+ }
+ }
+
+ return 0;
+}
+
+static int cfi_intelext_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_read, 0);
+}
+
+static int cfi_intelext_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_read, 1);
+}
+
+static int cfi_intelext_write_user_prot_reg(struct mtd_info *mtd, loff_t from,
+ size_t len, size_t *retlen,
+ u_char *buf)
+{
+ return cfi_intelext_otp_walk(mtd, from, len, retlen,
+ buf, do_otp_write, 1);
+}
+
+static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
+ loff_t from, size_t len)
+{
+ size_t retlen;
+ return cfi_intelext_otp_walk(mtd, from, len, &retlen,
+ NULL, do_otp_lock, 1);
+}
+
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
+ return ret ? : retlen;
+}
+
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ size_t retlen;
+ int ret;
+
+ ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
+ return ret ? : retlen;
+}
+
+#endif
+
static int cfi_intelext_suspend(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
@@ -2125,10 +2309,46 @@ static void cfi_intelext_resume(struct mtd_info *mtd)
}
}
+static int cfi_intelext_reset(struct mtd_info *mtd)
+{
+ struct map_info *map = mtd->priv;
+ struct cfi_private *cfi = map->fldrv_priv;
+ int i, ret;
+
+ for (i=0; i < cfi->numchips; i++) {
+ struct flchip *chip = &cfi->chips[i];
+
+ /* force the completion of any ongoing operation
+ and switch to array mode so any bootloader in
+ flash is accessible for soft reboot. */
+ spin_lock(chip->mutex);
+ ret = get_chip(map, chip, chip->start, FL_SYNCING);
+ if (!ret) {
+ map_write(map, CMD(0xff), chip->start);
+ chip->state = FL_READY;
+ }
+ spin_unlock(chip->mutex);
+ }
+
+ return 0;
+}
+
+static int cfi_intelext_reboot(struct notifier_block *nb, unsigned long val,
+ void *v)
+{
+ struct mtd_info *mtd;
+
+ mtd = container_of(nb, struct mtd_info, reboot_notifier);
+ cfi_intelext_reset(mtd);
+ return NOTIFY_DONE;
+}
+
static void cfi_intelext_destroy(struct mtd_info *mtd)
{
struct map_info *map = mtd->priv;
struct cfi_private *cfi = map->fldrv_priv;
+ cfi_intelext_reset(mtd);
+ unregister_reboot_notifier(&mtd->reboot_notifier);
kfree(cfi->cmdset_priv);
kfree(cfi->cfiq);
kfree(cfi->chips[0].priv);
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
index fca8ff6f7e14..8505f118f2db 100644
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -4,16 +4,20 @@
*
* Copyright (C) 2000 Crossnet Co. <info@crossnet.co.jp>
* Copyright (C) 2004 Arcom Control Systems Ltd <linux@arcom.com>
+ * Copyright (C) 2005 MontaVista Software Inc. <source@mvista.com>
*
* 2_by_8 routines added by Simon Munton
*
* 4_by_16 work by Carolyn J. Smith
*
+ * XIP support hooks by Vitaly Wool (based on code for Intel flash
+ * by Nicolas Pitre)
+ *
* Occasionally maintained by Thayne Harbaugh tharbaugh at lnxi dot com
*
* This code is GPL
*
- * $Id: cfi_cmdset_0002.c,v 1.114 2004/12/11 15:43:53 dedekind Exp $
+ * $Id: cfi_cmdset_0002.c,v 1.118 2005/07/04 22:34:29 gleixner Exp $
*
*/
@@ -34,6 +38,7 @@
#include <linux/mtd/map.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/cfi.h>
+#include <linux/mtd/xip.h>
#define AMD_BOOTLOC_BUG
#define FORCE_WORD_WRITE 0
@@ -43,6 +48,7 @@
#define MANUFACTURER_AMD 0x0001
#define MANUFACTURER_SST 0x00BF
#define SST49LF004B 0x0060
+#define SST49LF008A 0x005a
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -191,6 +197,7 @@ static struct cfi_fixup cfi_fixup_table[] = {
};
static struct cfi_fixup jedec_fixup_table[] = {
{ MANUFACTURER_SST, SST49LF004B, fixup_use_fwh_lock, NULL, },
+ { MANUFACTURER_SST, SST49LF008A, fixup_use_fwh_lock, NULL, },
{ 0, 0, NULL, NULL }
};
@@ -391,7 +398,7 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
* correctly and is therefore not done (particulary with interleaved chips
* as each chip must be checked independantly of the others).
*/
-static int chip_ready(struct map_info *map, unsigned long addr)
+static int __xipram chip_ready(struct map_info *map, unsigned long addr)
{
map_word d, t;
@@ -401,6 +408,32 @@ static int chip_ready(struct map_info *map, unsigned long addr)
return map_word_equal(map, d, t);
}
+/*
+ * Return true if the chip is ready and has the correct value.
+ *
+ * Ready is one of: read mode, query mode, erase-suspend-read mode (in any
+ * non-suspended sector) and it is indicated by no bits toggling.
+ *
+ * Error are indicated by toggling bits or bits held with the wrong value,
+ * or with bits toggling.
+ *
+ * Note that anything more complicated than checking if no bits are toggling
+ * (including checking DQ5 for an error status) is tricky to get working
+ * correctly and is therefore not done (particulary with interleaved chips
+ * as each chip must be checked independantly of the others).
+ *
+ */
+static int __xipram chip_good(struct map_info *map, unsigned long addr, map_word expected)
+{
+ map_word oldd, curd;
+
+ oldd = map_read(map, addr);
+ curd = map_read(map, addr);
+
+ return map_word_equal(map, oldd, curd) &&
+ map_word_equal(map, curd, expected);
+}
+
static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode)
{
DECLARE_WAITQUEUE(wait, current);
@@ -420,12 +453,12 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
if (time_after(jiffies, timeo)) {
printk(KERN_ERR "Waiting for chip to be ready timed out.\n");
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return -EIO;
}
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
/* Someone else might have been playing with it. */
goto retry;
}
@@ -473,15 +506,23 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
return -EIO;
}
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
/* Nobody will touch it while it's in state FL_ERASE_SUSPENDING.
So we can just loop here. */
}
chip->state = FL_READY;
return 0;
+ case FL_XIP_WHILE_ERASING:
+ if (mode != FL_READY && mode != FL_POINT &&
+ (!cfip || !(cfip->EraseSuspend&2)))
+ goto sleep;
+ chip->oldstate = chip->state;
+ chip->state = FL_READY;
+ return 0;
+
case FL_POINT:
/* Only if there's no operation suspended... */
if (mode == FL_READY && chip->oldstate == FL_READY)
@@ -491,10 +532,10 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
sleep:
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
goto resettime;
}
}
@@ -512,6 +553,11 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
chip->state = FL_ERASING;
break;
+ case FL_XIP_WHILE_ERASING:
+ chip->state = chip->oldstate;
+ chip->oldstate = FL_READY;
+ break;
+
case FL_READY:
case FL_STATUS:
/* We should really make set_vpp() count, rather than doing this */
@@ -523,6 +569,198 @@ static void put_chip(struct map_info *map, struct flchip *chip, unsigned long ad
wake_up(&chip->wq);
}
+#ifdef CONFIG_MTD_XIP
+
+/*
+ * No interrupt what so ever can be serviced while the flash isn't in array
+ * mode. This is ensured by the xip_disable() and xip_enable() functions
+ * enclosing any code path where the flash is known not to be in array mode.
+ * And within a XIP disabled code path, only functions marked with __xipram
+ * may be called and nothing else (it's a good thing to inspect generated
+ * assembly to make sure inline functions were actually inlined and that gcc
+ * didn't emit calls to its own support functions). Also configuring MTD CFI
+ * support to a single buswidth and a single interleave is also recommended.
+ */
+
+static void xip_disable(struct map_info *map, struct flchip *chip,
+ unsigned long adr)
+{
+ /* TODO: chips with no XIP use should ignore and return */
+ (void) map_read(map, adr); /* ensure mmu mapping is up to date */
+ local_irq_disable();
+}
+
+static void __xipram xip_enable(struct map_info *map, struct flchip *chip,
+ unsigned long adr)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+
+ if (chip->state != FL_POINT && chip->state != FL_READY) {
+ map_write(map, CMD(0xf0), adr);
+ chip->state = FL_READY;
+ }
+ (void) map_read(map, adr);
+ xip_iprefetch();
+ local_irq_enable();
+}
+
+/*
+ * When a delay is required for the flash operation to complete, the
+ * xip_udelay() function is polling for both the given timeout and pending
+ * (but still masked) hardware interrupts. Whenever there is an interrupt
+ * pending then the flash erase operation is suspended, array mode restored
+ * and interrupts unmasked. Task scheduling might also happen at that
+ * point. The CPU eventually returns from the interrupt or the call to
+ * schedule() and the suspended flash operation is resumed for the remaining
+ * of the delay period.
+ *
+ * Warning: this function _will_ fool interrupt latency tracing tools.
+ */
+
+static void __xipram xip_udelay(struct map_info *map, struct flchip *chip,
+ unsigned long adr, int usec)
+{
+ struct cfi_private *cfi = map->fldrv_priv;
+ struct cfi_pri_amdstd *extp = cfi->cmdset_priv;
+ map_word status, OK = CMD(0x80);
+ unsigned long suspended, start = xip_currtime();
+ flstate_t oldstate;
+
+ do {
+ cpu_relax();
+ if (xip_irqpending() && extp &&
+ ((chip->state == FL_ERASING && (extp->EraseSuspend & 2))) &&
+ (cfi_interleave_is_1(cfi) || chip->oldstate == FL_READY)) {
+ /*
+ * Let's suspend the erase operation when supported.
+ * Note that we currently don't try to suspend
+ * interleaved chips if there is already another
+ * operation suspended (imagine what happens
+ * when one chip was already done with the current
+ * operation while another chip suspended it, then
+ * we resume the whole thing at once). Yes, it
+ * can happen!
+ */
+ map_write(map, CMD(0xb0), adr);
+ usec -= xip_elapsed_since(start);
+ suspended = xip_currtime();
+ do {
+ if (xip_elapsed_since(suspended) > 100000) {
+ /*
+ * The chip doesn't want to suspend
+ * after waiting for 100 msecs.
+ * This is a critical error but there
+ * is not much we can do here.
+ */
+ return;
+ }
+ status = map_read(map, adr);
+ } while (!map_word_andequal(map, status, OK, OK));
+
+ /* Suspend succeeded */
+ oldstate = chip->state;
+ if (!map_word_bitsset(map, status, CMD(0x40)))
+ break;
+ chip->state = FL_XIP_WHILE_ERASING;
+ chip->erase_suspended = 1;
+ map_write(map, CMD(0xf0), adr);
+ (void) map_read(map, adr);
+ asm volatile (".rep 8; nop; .endr");
+ local_irq_enable();
+ spin_unlock(chip->mutex);
+ asm volatile (".rep 8; nop; .endr");
+ cond_resched();
+
+ /*
+ * We're back. However someone else might have
+ * decided to go write to the chip if we are in
+ * a suspended erase state. If so let's wait
+ * until it's done.
+ */
+ spin_lock(chip->mutex);
+ while (chip->state != FL_XIP_WHILE_ERASING) {
+ DECLARE_WAITQUEUE(wait, current);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&chip->wq, &wait);
+ spin_unlock(chip->mutex);
+ schedule();
+ remove_wait_queue(&chip->wq, &wait);
+ spin_lock(chip->mutex);
+ }
+ /* Disallow XIP again */
+ local_irq_disable();
+
+ /* Resume the write or erase operation */
+ map_write(map, CMD(0x30), adr);
+ chip->state = oldstate;
+ start = xip_currtime();
+ } else if (usec >= 1000000/HZ) {
+ /*
+ * Try to save on CPU power when waiting delay
+ * is at least a system timer tick period.
+ * No need to be extremely accurate here.
+ */
+ xip_cpu_idle();
+ }
+ status = map_read(map, adr);
+ } while (!map_word_andequal(map, status, OK, OK)
+ && xip_elapsed_since(start) < usec);
+}
+
+#define UDELAY(map, chip, adr, usec) xip_udelay(map, chip, adr, usec)
+
+/*
+ * The INVALIDATE_CACHED_RANGE() macro is normally used in parallel while
+ * the flash is actively programming or erasing since we have to poll for
+ * the operation to complete anyway. We can't do that in a generic way with
+ * a XIP setup so do it before the actual flash operation in this case
+ * and stub it out from INVALIDATE_CACHE_UDELAY.
+ */
+#define XIP_INVAL_CACHED_RANGE(map, from, size) \
+ INVALIDATE_CACHED_RANGE(map, from, size)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+ UDELAY(map, chip, adr, usec)
+
+/*
+ * Extra notes:
+ *
+ * Activating this XIP support changes the way the code works a bit. For
+ * example the code to suspend the current process when concurrent access
+ * happens is never executed because xip_udelay() will always return with the
+ * same chip state as it was entered with. This is why there is no care for
+ * the presence of add_wait_queue() or schedule() calls from within a couple
+ * xip_disable()'d areas of code, like in do_erase_oneblock for example.
+ * The queueing and scheduling are always happening within xip_udelay().
+ *
+ * Similarly, get_chip() and put_chip() just happen to always be executed
+ * with chip->state set to FL_READY (or FL_XIP_WHILE_*) where flash state
+ * is in array mode, therefore never executing many cases therein and not
+ * causing any problem with XIP.
+ */
+
+#else
+
+#define xip_disable(map, chip, adr)
+#define xip_enable(map, chip, adr)
+#define XIP_INVAL_CACHED_RANGE(x...)
+
+#define UDELAY(map, chip, adr, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#define INVALIDATE_CACHE_UDELAY(map, chip, adr, len, usec) \
+do { \
+ spin_unlock(chip->mutex); \
+ INVALIDATE_CACHED_RANGE(map, adr, len); \
+ cfi_udelay(usec); \
+ spin_lock(chip->mutex); \
+} while (0)
+
+#endif
static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf)
{
@@ -535,10 +773,10 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
/* Ensure cmd read/writes are aligned. */
cmd_addr = adr & ~(map_bankwidth(map)-1);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, cmd_addr, FL_READY);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -551,7 +789,7 @@ static inline int do_read_onechip(struct map_info *map, struct flchip *chip, lof
put_chip(map, chip, cmd_addr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return 0;
}
@@ -605,7 +843,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
struct cfi_private *cfi = map->fldrv_priv;
retry:
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
if (chip->state != FL_READY){
#if 0
@@ -614,7 +852,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
@@ -643,7 +881,7 @@ static inline int do_read_secsi_onechip(struct map_info *map, struct flchip *chi
cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
wake_up(&chip->wq);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return 0;
}
@@ -692,7 +930,7 @@ static int cfi_amdstd_secsi_read (struct mtd_info *mtd, loff_t from, size_t len,
}
-static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
+static int __xipram do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, map_word datum)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
@@ -712,10 +950,10 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
adr += chip->start;
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -735,7 +973,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
goto op_done;
}
+ XIP_INVAL_CACHED_RANGE(map, adr, map_bankwidth(map));
ENABLE_VPP(map);
+ xip_disable(map, chip, adr);
retry:
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
@@ -743,9 +983,9 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
map_write(map, datum, adr);
chip->state = FL_WRITING;
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(chip->word_write_time);
- cfi_spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
/* See comment above for timeout value. */
timeo = jiffies + uWriteTimeout;
@@ -756,39 +996,43 @@ static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + (HZ / 2); /* FIXME */
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
continue;
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ xip_enable(map, chip, adr);
+ printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
+ xip_disable(map, chip, adr);
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
+ UDELAY(map, chip, adr, 1);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, datum)) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n", __func__);
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
- if (++retry_cnt <= MAX_WORD_RETRIES)
- goto retry;
+ if (++retry_cnt <= MAX_WORD_RETRIES)
+ goto retry;
- ret = -EIO;
+ ret = -EIO;
+ }
+ xip_enable(map, chip, adr);
op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -820,7 +1064,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
map_word tmp_buf;
retry:
- cfi_spin_lock(cfi->chips[chipnum].mutex);
+ spin_lock(cfi->chips[chipnum].mutex);
if (cfi->chips[chipnum].state != FL_READY) {
#if 0
@@ -829,7 +1073,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&cfi->chips[chipnum].wq, &wait);
- cfi_spin_unlock(cfi->chips[chipnum].mutex);
+ spin_unlock(cfi->chips[chipnum].mutex);
schedule();
remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
@@ -843,7 +1087,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
/* Load 'tmp_buf' with old contents of flash */
tmp_buf = map_read(map, bus_ofs+chipstart);
- cfi_spin_unlock(cfi->chips[chipnum].mutex);
+ spin_unlock(cfi->chips[chipnum].mutex);
/* Number of bytes to copy from buffer */
n = min_t(int, len, map_bankwidth(map)-i);
@@ -898,7 +1142,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
map_word tmp_buf;
retry1:
- cfi_spin_lock(cfi->chips[chipnum].mutex);
+ spin_lock(cfi->chips[chipnum].mutex);
if (cfi->chips[chipnum].state != FL_READY) {
#if 0
@@ -907,7 +1151,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&cfi->chips[chipnum].wq, &wait);
- cfi_spin_unlock(cfi->chips[chipnum].mutex);
+ spin_unlock(cfi->chips[chipnum].mutex);
schedule();
remove_wait_queue(&cfi->chips[chipnum].wq, &wait);
@@ -920,7 +1164,7 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
tmp_buf = map_read(map, ofs + chipstart);
- cfi_spin_unlock(cfi->chips[chipnum].mutex);
+ spin_unlock(cfi->chips[chipnum].mutex);
tmp_buf = map_word_load_partial(map, tmp_buf, buf, 0, len);
@@ -939,8 +1183,9 @@ static int cfi_amdstd_write_words(struct mtd_info *mtd, loff_t to, size_t len,
/*
* FIXME: interleaved mode not tested, and probably not supported!
*/
-static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
- unsigned long adr, const u_char *buf, int len)
+static int __xipram do_write_buffer(struct map_info *map, struct flchip *chip,
+ unsigned long adr, const u_char *buf,
+ int len)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
@@ -954,10 +1199,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
adr += chip->start;
cmd_adr = adr;
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -966,7 +1211,10 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8lx)\n",
__func__, adr, datum.x[0] );
+ XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
+ xip_disable(map, chip, cmd_adr);
+
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
//cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -996,9 +1244,9 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
map_write(map, CMD(0x29), cmd_adr);
chip->state = FL_WRITING;
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(chip->buffer_write_time);
- cfi_spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map_bankwidth(map),
+ chip->word_write_time);
timeo = jiffies + uWriteTimeout;
@@ -1009,38 +1257,39 @@ static inline int do_write_buffer(struct map_info *map, struct flchip *chip,
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
timeo = jiffies + (HZ / 2); /* FIXME */
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
continue;
}
- if (chip_ready(map, adr))
+ if (chip_ready(map, adr)) {
+ xip_enable(map, chip, adr);
goto op_done;
+ }
if( time_after(jiffies, timeo))
break;
/* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
- cfi_udelay(1);
- cfi_spin_lock(chip->mutex);
+ UDELAY(map, chip, adr, 1);
}
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
/* reset on all failures. */
map_write( map, CMD(0xF0), chip->start );
+ xip_enable(map, chip, adr);
/* FIXME - should have reset delay before continuing */
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
+
ret = -EIO;
op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -1130,7 +1379,7 @@ static int cfi_amdstd_write_buffers(struct mtd_info *mtd, loff_t to, size_t len,
* Handle devices with one erase region, that only implement
* the chip erase command.
*/
-static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
+static int __xipram do_erase_chip(struct map_info *map, struct flchip *chip)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
@@ -1140,17 +1389,20 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
adr = cfi->addr_unlock1;
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_WRITING);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
__func__, chip->start );
+ XIP_INVAL_CACHED_RANGE(map, adr, map->size);
ENABLE_VPP(map);
+ xip_disable(map, chip, adr);
+
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1162,9 +1414,9 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
chip->erase_suspended = 0;
chip->in_progress_block_addr = adr;
- cfi_spin_unlock(chip->mutex);
- msleep(chip->erase_time/2);
- cfi_spin_lock(chip->mutex);
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, map->size,
+ chip->erase_time*500);
timeo = jiffies + (HZ*20);
@@ -1173,10 +1425,10 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
/* Someone's suspended the erase. Sleep */
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
continue;
}
if (chip->erase_suspended) {
@@ -1187,36 +1439,36 @@ static inline int do_erase_chip(struct map_info *map, struct flchip *chip)
}
if (chip_ready(map, adr))
- goto op_done;
+ break;
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- cfi_spin_lock(chip->mutex);
+ UDELAY(map, chip, adr, 1000000/HZ);
}
+ /* Did we succeed? */
+ if (!chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
+ ret = -EIO;
+ }
- ret = -EIO;
- op_done:
chip->state = FL_READY;
+ xip_enable(map, chip, adr);
put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
-static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
+static int __xipram do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, int len, void *thunk)
{
struct cfi_private *cfi = map->fldrv_priv;
unsigned long timeo = jiffies + HZ;
@@ -1225,17 +1477,20 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
adr += chip->start;
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_ERASING);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n",
__func__, adr );
+ XIP_INVAL_CACHED_RANGE(map, adr, len);
ENABLE_VPP(map);
+ xip_disable(map, chip, adr);
+
cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL);
cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL);
@@ -1246,10 +1501,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
chip->state = FL_ERASING;
chip->erase_suspended = 0;
chip->in_progress_block_addr = adr;
-
- cfi_spin_unlock(chip->mutex);
- msleep(chip->erase_time/2);
- cfi_spin_lock(chip->mutex);
+
+ INVALIDATE_CACHE_UDELAY(map, chip,
+ adr, len,
+ chip->erase_time*500);
timeo = jiffies + (HZ*20);
@@ -1258,10 +1513,10 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
/* Someone's suspended the erase. Sleep */
set_current_state(TASK_UNINTERRUPTIBLE);
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
remove_wait_queue(&chip->wq, &wait);
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
continue;
}
if (chip->erase_suspended) {
@@ -1271,31 +1526,33 @@ static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, u
chip->erase_suspended = 0;
}
- if (chip_ready(map, adr))
- goto op_done;
+ if (chip_ready(map, adr)) {
+ xip_enable(map, chip, adr);
+ break;
+ }
- if (time_after(jiffies, timeo))
+ if (time_after(jiffies, timeo)) {
+ xip_enable(map, chip, adr);
+ printk(KERN_WARNING "MTD %s(): software timeout\n",
+ __func__ );
break;
+ }
/* Latency issues. Drop the lock, wait a while and retry */
- cfi_spin_unlock(chip->mutex);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- cfi_spin_lock(chip->mutex);
+ UDELAY(map, chip, adr, 1000000/HZ);
+ }
+ /* Did we succeed? */
+ if (!chip_good(map, adr, map_word_ff(map))) {
+ /* reset on all failures. */
+ map_write( map, CMD(0xF0), chip->start );
+ /* FIXME - should have reset delay before continuing */
+
+ ret = -EIO;
}
-
- printk(KERN_WARNING "MTD %s(): software timeout\n",
- __func__ );
-
- /* reset on all failures. */
- map_write( map, CMD(0xF0), chip->start );
- /* FIXME - should have reset delay before continuing */
- ret = -EIO;
- op_done:
chip->state = FL_READY;
put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -1355,7 +1612,7 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
chip = &cfi->chips[i];
retry:
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
switch(chip->state) {
case FL_READY:
@@ -1369,14 +1626,14 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
* with the chip now anyway.
*/
case FL_SYNCING:
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
break;
default:
/* Not an idle state */
add_wait_queue(&chip->wq, &wait);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
schedule();
@@ -1391,13 +1648,13 @@ static void cfi_amdstd_sync (struct mtd_info *mtd)
for (i--; i >=0; i--) {
chip = &cfi->chips[i];
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
if (chip->state == FL_SYNCING) {
chip->state = chip->oldstate;
wake_up(&chip->wq);
}
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
}
}
@@ -1413,7 +1670,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
for (i=0; !ret && i<cfi->numchips; i++) {
chip = &cfi->chips[i];
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
switch(chip->state) {
case FL_READY:
@@ -1433,7 +1690,7 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
ret = -EAGAIN;
break;
}
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
}
/* Unlock the chips again */
@@ -1442,13 +1699,13 @@ static int cfi_amdstd_suspend(struct mtd_info *mtd)
for (i--; i >=0; i--) {
chip = &cfi->chips[i];
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
if (chip->state == FL_PM_SUSPENDED) {
chip->state = chip->oldstate;
wake_up(&chip->wq);
}
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
}
}
@@ -1467,7 +1724,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
chip = &cfi->chips[i];
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
if (chip->state == FL_PM_SUSPENDED) {
chip->state = FL_READY;
@@ -1477,7 +1734,7 @@ static void cfi_amdstd_resume(struct mtd_info *mtd)
else
printk(KERN_ERR "Argh. Chip not in PM_SUSPENDED state upon resume()\n");
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
}
}
diff --git a/drivers/mtd/chips/fwh_lock.h b/drivers/mtd/chips/fwh_lock.h
index fbf44708a861..e1a5b76596c5 100644
--- a/drivers/mtd/chips/fwh_lock.h
+++ b/drivers/mtd/chips/fwh_lock.h
@@ -58,10 +58,10 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
* to flash memory - that means that we don't have to check status
* and timeout.
*/
- cfi_spin_lock(chip->mutex);
+ spin_lock(chip->mutex);
ret = get_chip(map, chip, adr, FL_LOCKING);
if (ret) {
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return ret;
}
@@ -71,7 +71,7 @@ static int fwh_xxlock_oneblock(struct map_info *map, struct flchip *chip,
/* Done and happy. */
chip->state = FL_READY;
put_chip(map, chip, adr);
- cfi_spin_unlock(chip->mutex);
+ spin_unlock(chip->mutex);
return 0;
}
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c
index fc982c4671f0..dc065b22f79e 100644
--- a/drivers/mtd/chips/gen_probe.c
+++ b/drivers/mtd/chips/gen_probe.c
@@ -2,7 +2,7 @@
* Routines common to all CFI-type probes.
* (C) 2001-2003 Red Hat, Inc.
* GPL'd
- * $Id: gen_probe.c,v 1.21 2004/08/14 15:14:05 dwmw2 Exp $
+ * $Id: gen_probe.c,v 1.22 2005/01/24 23:49:50 rmk Exp $
*/
#include <linux/kernel.h>
@@ -162,7 +162,7 @@ static int genprobe_new_chip(struct map_info *map, struct chip_probe *cp,
int max_chips = map_bankwidth(map); /* And minimum 1 */
int nr_chips, type;
- for (nr_chips = min_chips; nr_chips <= max_chips; nr_chips <<= 1) {
+ for (nr_chips = max_chips; nr_chips >= min_chips; nr_chips >>= 1) {
if (!cfi_interleave_supported(nr_chips))
continue;
diff --git a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c
index 30325a25ab95..30da428eb7b9 100644
--- a/drivers/mtd/chips/jedec_probe.c
+++ b/drivers/mtd/chips/jedec_probe.c
@@ -1,7 +1,7 @@
/*
Common Flash Interface probe code.
(C) 2000 Red Hat. GPL'd.
- $Id: jedec_probe.c,v 1.61 2004/11/19 20:52:16 thayne Exp $
+ $Id: jedec_probe.c,v 1.63 2005/02/14 16:30:32 bjd Exp $
See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5)
for the standard this probe goes back to.
@@ -142,6 +142,7 @@
#define SST29LE512 0x003d
#define SST39LF800 0x2781
#define SST39LF160 0x2782
+#define SST39VF1601 0x234b
#define SST39LF512 0x00D4
#define SST39LF010 0x00D5
#define SST39LF020 0x00D6
@@ -1448,6 +1449,21 @@ static const struct amd_flash_info jedec_table[] = {
ERASEINFO(0x1000,256),
ERASEINFO(0x1000,256)
}
+ }, {
+ .mfr_id = MANUFACTURER_SST, /* should be CFI */
+ .dev_id = SST39VF1601,
+ .name = "SST 39VF1601",
+ .uaddr = {
+ [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */
+ [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */
+ },
+ .DevSize = SIZE_2MiB,
+ .CmdSet = P_ID_AMD_STD,
+ .NumEraseRegions= 2,
+ .regions = {
+ ERASEINFO(0x1000,256),
+ ERASEINFO(0x1000,256)
+ }
}, {
.mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */
@@ -1856,6 +1872,16 @@ static inline int jedec_match( __u32 base,
case CFI_DEVICETYPE_X8:
mfr = (__u8)finfo->mfr_id;
id = (__u8)finfo->dev_id;
+
+ /* bjd: it seems that if we do this, we can end up
+ * detecting 16bit flashes as an 8bit device, even though
+ * there aren't.
+ */
+ if (finfo->dev_id > 0xff) {
+ DEBUG( MTD_DEBUG_LEVEL3, "%s(): ID is not 8bit\n",
+ __func__);
+ goto match_done;
+ }
break;
case CFI_DEVICETYPE_X16:
mfr = (__u16)finfo->mfr_id;
diff --git a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c
index 60ab4b89a2f9..ef24837019d3 100644
--- a/drivers/mtd/cmdlinepart.c
+++ b/drivers/mtd/cmdlinepart.c
@@ -1,5 +1,5 @@
/*
- * $Id: cmdlinepart.c,v 1.17 2004/11/26 11:18:47 lavinen Exp $
+ * $Id: cmdlinepart.c,v 1.18 2005/06/07 15:04:26 joern Exp $
*
* Read flash partition table from command line
*
@@ -239,7 +239,8 @@ static int mtdpart_setup_real(char *s)
&num_parts, /* out: number of parts */
0, /* first partition */
(unsigned char**)&this_mtd, /* out: extra mem */
- mtd_id_len + 1 + sizeof(*this_mtd));
+ mtd_id_len + 1 + sizeof(*this_mtd) +
+ sizeof(void*)-1 /*alignment*/);
if(!parts)
{
/*
@@ -252,6 +253,9 @@ static int mtdpart_setup_real(char *s)
return 0;
}
+ /* align this_mtd */
+ this_mtd = (struct cmdline_mtd_partition *)
+ ALIGN((unsigned long)this_mtd, sizeof(void*));
/* enter results */
this_mtd->parts = parts;
this_mtd->num_parts = num_parts;
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
index cfe6ccf07972..4a7a805e7564 100644
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -1,10 +1,9 @@
/*
- * $Id: block2mtd.c,v 1.23 2005/01/05 17:05:46 dwmw2 Exp $
+ * $Id: block2mtd.c,v 1.28 2005/03/19 22:40:44 gleixner Exp $
*
* block2mtd.c - create an mtd from a block device
*
* Copyright (C) 2001,2002 Simon Evans <spse@secret.org.uk>
- * Copyright (C) 2004 Gareth Bult <Gareth@Encryptec.net>
* Copyright (C) 2004,2005 Jörn Engel <joern@wh.fh-wedel.de>
*
* Licence: GPL
@@ -20,7 +19,7 @@
#include <linux/mtd/mtd.h>
#include <linux/buffer_head.h>
-#define VERSION "$Revision: 1.23 $"
+#define VERSION "$Revision: 1.28 $"
#define ERROR(fmt, args...) printk(KERN_ERR "block2mtd: " fmt "\n" , ## args)
@@ -89,7 +88,6 @@ void cache_readahead(struct address_space *mapping, int index)
static struct page* page_readahead(struct address_space *mapping, int index)
{
filler_t *filler = (filler_t*)mapping->a_ops->readpage;
- //do_page_cache_readahead(mapping, index, XXX, 64);
cache_readahead(mapping, index);
return read_cache_page(mapping, index, filler, NULL);
}
@@ -157,7 +155,7 @@ static int block2mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
struct block2mtd_dev *dev = mtd->priv;
struct page *page;
int index = from >> PAGE_SHIFT;
- int offset = from & (PAGE_SHIFT-1);
+ int offset = from & (PAGE_SIZE-1);
int cpylen;
if (from > mtd->size)
@@ -370,16 +368,16 @@ static int ustrtoul(const char *cp, char **endp, unsigned int base)
}
-static int parse_num32(u32 *num32, const char *token)
+static int parse_num(size_t *num, const char *token)
{
char *endp;
- unsigned long n;
+ size_t n;
- n = ustrtoul(token, &endp, 0);
+ n = (size_t) ustrtoul(token, &endp, 0);
if (*endp)
return -EINVAL;
- *num32 = n;
+ *num = n;
return 0;
}
@@ -422,7 +420,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
char buf[80+12], *str=buf; /* 80 for device, 12 for erase size */
char *token[2];
char *name;
- u32 erase_size = PAGE_SIZE;
+ size_t erase_size = PAGE_SIZE;
int i, ret;
if (strnlen(val, sizeof(buf)) >= sizeof(buf))
@@ -449,7 +447,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
return 0;
if (token[1]) {
- ret = parse_num32(&erase_size, token[1]);
+ ret = parse_num(&erase_size, token[1]);
if (ret)
parse_err("illegal erase size");
}
diff --git a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c
index 380ff08d29e4..f5026cee087f 100644
--- a/drivers/mtd/devices/ms02-nv.c
+++ b/drivers/mtd/devices/ms02-nv.c
@@ -6,7 +6,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * $Id: ms02-nv.c,v 1.8 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: ms02-nv.c,v 1.10 2005/06/20 12:24:41 macro Exp $
*/
#include <linux/init.h>
@@ -99,8 +99,8 @@ static inline uint ms02nv_probe_one(ulong addr)
* The firmware writes MS02NV_ID at MS02NV_MAGIC and also
* a diagnostic status at MS02NV_DIAG.
*/
- ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG));
- ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC));
+ ms02nv_diagp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_DIAG));
+ ms02nv_magicp = (ms02nv_uint *)(CKSEG1ADDR(addr + MS02NV_MAGIC));
err = get_dbe(ms02nv_magic, ms02nv_magicp);
if (err)
return 0;
@@ -233,7 +233,7 @@ static int __init ms02nv_init_one(ulong addr)
goto err_out_csr_res;
}
- printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMiB.\n",
+ printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %zuMiB.\n",
mtd->index, ms02nv_name, addr, size >> 20);
mp->next = root_ms02nv_mtd;
diff --git a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c
index edac4156d69c..bb713fed2f37 100644
--- a/drivers/mtd/devices/mtdram.c
+++ b/drivers/mtd/devices/mtdram.c
@@ -1,9 +1,10 @@
/*
* mtdram - a test mtd device
- * $Id: mtdram.c,v 1.35 2005/01/05 18:05:12 dwmw2 Exp $
+ * $Id: mtdram.c,v 1.37 2005/04/21 03:42:11 joern Exp $
* Author: Alexander Larsson <alex@cendio.se>
*
* Copyright (c) 1999 Alexander Larsson <alex@cendio.se>
+ * Copyright (c) 2005 Joern Engel <joern@wh.fh-wedel.de>
*
* This code is GPL
*
@@ -18,213 +19,140 @@
#include <linux/mtd/compatmac.h>
#include <linux/mtd/mtd.h>
-#ifndef CONFIG_MTDRAM_ABS_POS
- #define CONFIG_MTDRAM_ABS_POS 0
-#endif
-
-#if CONFIG_MTDRAM_ABS_POS > 0
- #include <asm/io.h>
-#endif
-
-#ifdef MODULE
static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE;
static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE;
-module_param(total_size,ulong,0);
-MODULE_PARM_DESC(total_size, "Total device size in KiB");
-module_param(erase_size,ulong,0);
-MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
#define MTDRAM_TOTAL_SIZE (total_size * 1024)
#define MTDRAM_ERASE_SIZE (erase_size * 1024)
-#else
-#define MTDRAM_TOTAL_SIZE (CONFIG_MTDRAM_TOTAL_SIZE * 1024)
-#define MTDRAM_ERASE_SIZE (CONFIG_MTDRAM_ERASE_SIZE * 1024)
-#endif
+#ifdef MODULE
+module_param(total_size, ulong, 0);
+MODULE_PARM_DESC(total_size, "Total device size in KiB");
+module_param(erase_size, ulong, 0);
+MODULE_PARM_DESC(erase_size, "Device erase block size in KiB");
+#endif
// We could store these in the mtd structure, but we only support 1 device..
static struct mtd_info *mtd_info;
-
-static int
-ram_erase(struct mtd_info *mtd, struct erase_info *instr)
+static int ram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_erase(pos:%ld, len:%ld)\n", (long)instr->addr, (long)instr->len);
- if (instr->addr + instr->len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_erase() out of bounds (%ld > %ld)\n", (long)(instr->addr + instr->len), (long)mtd->size);
- return -EINVAL;
- }
-
- memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
-
- instr->state = MTD_ERASE_DONE;
- mtd_erase_callback(instr);
-
- return 0;
+ if (instr->addr + instr->len > mtd->size)
+ return -EINVAL;
+
+ memset((char *)mtd->priv + instr->addr, 0xff, instr->len);
+
+ instr->state = MTD_ERASE_DONE;
+ mtd_erase_callback(instr);
+
+ return 0;
}
-static int ram_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf)
+static int ram_point(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char **mtdbuf)
{
- if (from + len > mtd->size)
- return -EINVAL;
-
- *mtdbuf = mtd->priv + from;
- *retlen = len;
- return 0;
+ if (from + len > mtd->size)
+ return -EINVAL;
+
+ *mtdbuf = mtd->priv + from;
+ *retlen = len;
+ return 0;
}
-static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from,
- size_t len)
+static void ram_unpoint(struct mtd_info *mtd, u_char * addr, loff_t from,
+ size_t len)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n");
}
static int ram_read(struct mtd_info *mtd, loff_t from, size_t len,
- size_t *retlen, u_char *buf)
+ size_t *retlen, u_char *buf)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_read(pos:%ld, len:%ld)\n", (long)from, (long)len);
- if (from + len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_read() out of bounds (%ld > %ld)\n", (long)(from + len), (long)mtd->size);
- return -EINVAL;
- }
+ if (from + len > mtd->size)
+ return -EINVAL;
- memcpy(buf, mtd->priv + from, len);
+ memcpy(buf, mtd->priv + from, len);
- *retlen=len;
- return 0;
+ *retlen = len;
+ return 0;
}
static int ram_write(struct mtd_info *mtd, loff_t to, size_t len,
- size_t *retlen, const u_char *buf)
+ size_t *retlen, const u_char *buf)
{
- DEBUG(MTD_DEBUG_LEVEL2, "ram_write(pos:%ld, len:%ld)\n", (long)to, (long)len);
- if (to + len > mtd->size) {
- DEBUG(MTD_DEBUG_LEVEL1, "ram_write() out of bounds (%ld > %ld)\n", (long)(to + len), (long)mtd->size);
- return -EINVAL;
- }
+ if (to + len > mtd->size)
+ return -EINVAL;
- memcpy ((char *)mtd->priv + to, buf, len);
+ memcpy((char *)mtd->priv + to, buf, len);
- *retlen=len;
- return 0;
+ *retlen = len;
+ return 0;
}
static void __exit cleanup_mtdram(void)
{
- if (mtd_info) {
- del_mtd_device(mtd_info);
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
- if (mtd_info->priv)
-#if CONFIG_MTDRAM_ABS_POS > 0
- iounmap(mtd_info->priv);
-#else
- vfree(mtd_info->priv);
-#endif
-#endif
- kfree(mtd_info);
- }
-}
-
-int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
- unsigned long size, char *name)
-{
- memset(mtd, 0, sizeof(*mtd));
-
- /* Setup the MTD structure */
- mtd->name = name;
- mtd->type = MTD_RAM;
- mtd->flags = MTD_CAP_RAM;
- mtd->size = size;
- mtd->erasesize = MTDRAM_ERASE_SIZE;
- mtd->priv = mapped_address;
-
- mtd->owner = THIS_MODULE;
- mtd->erase = ram_erase;
- mtd->point = ram_point;
- mtd->unpoint = ram_unpoint;
- mtd->read = ram_read;
- mtd->write = ram_write;
-
- if (add_mtd_device(mtd)) {
- return -EIO;
- }
-
- return 0;
-}
-
-#if CONFIG_MTDRAM_TOTAL_SIZE > 0
-#if CONFIG_MTDRAM_ABS_POS > 0
-static int __init init_mtdram(void)
-{
- void *addr;
- int err;
- /* Allocate some memory */
- mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
- addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE);
- if (!addr) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n",
- (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS);
- kfree(mtd_info);
- mtd_info = NULL;
- return -ENOMEM;
- }
- err = mtdram_init_device(mtd_info, addr,
- MTDRAM_TOTAL_SIZE, "mtdram test device");
- if (err)
- {
- iounmap(addr);
- kfree(mtd_info);
- mtd_info = NULL;
- return err;
- }
- memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
- return err;
+ if (mtd_info) {
+ del_mtd_device(mtd_info);
+ if (mtd_info->priv)
+ vfree(mtd_info->priv);
+ kfree(mtd_info);
+ }
}
-#else /* CONFIG_MTDRAM_ABS_POS > 0 */
-
-static int __init init_mtdram(void)
+int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
+ unsigned long size, char *name)
{
- void *addr;
- int err;
- /* Allocate some memory */
- mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
- if (!mtd_info)
- return -ENOMEM;
-
- addr = vmalloc(MTDRAM_TOTAL_SIZE);
- if (!addr) {
- DEBUG(MTD_DEBUG_LEVEL1,
- "Failed to vmalloc memory region of size %ld\n",
- (long)MTDRAM_TOTAL_SIZE);
- kfree(mtd_info);
- mtd_info = NULL;
- return -ENOMEM;
- }
- err = mtdram_init_device(mtd_info, addr,
- MTDRAM_TOTAL_SIZE, "mtdram test device");
- if (err)
- {
- vfree(addr);
- kfree(mtd_info);
- mtd_info = NULL;
- return err;
- }
- memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
- return err;
+ memset(mtd, 0, sizeof(*mtd));
+
+ /* Setup the MTD structure */
+ mtd->name = name;
+ mtd->type = MTD_RAM;
+ mtd->flags = MTD_CAP_RAM;
+ mtd->size = size;
+ mtd->erasesize = MTDRAM_ERASE_SIZE;
+ mtd->priv = mapped_address;
+
+ mtd->owner = THIS_MODULE;
+ mtd->erase = ram_erase;
+ mtd->point = ram_point;
+ mtd->unpoint = ram_unpoint;
+ mtd->read = ram_read;
+ mtd->write = ram_write;
+
+ if (add_mtd_device(mtd)) {
+ return -EIO;
+ }
+
+ return 0;
}
-#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */
-
-#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */
static int __init init_mtdram(void)
{
- return 0;
+ void *addr;
+ int err;
+
+ if (!total_size)
+ return -EINVAL;
+
+ /* Allocate some memory */
+ mtd_info = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);
+ if (!mtd_info)
+ return -ENOMEM;
+
+ addr = vmalloc(MTDRAM_TOTAL_SIZE);
+ if (!addr) {
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return -ENOMEM;
+ }
+ err = mtdram_init_device(mtd_info, addr, MTDRAM_TOTAL_SIZE, "mtdram test device");
+ if (err) {
+ vfree(addr);
+ kfree(mtd_info);
+ mtd_info = NULL;
+ return err;
+ }
+ memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE);
+ return err;
}
-#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */
module_init(init_mtdram);
module_exit(cleanup_mtdram);
@@ -232,4 +160,3 @@ module_exit(cleanup_mtdram);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Alexander Larsson <alexl@redhat.com>");
MODULE_DESCRIPTION("Simulated MTD driver for testing");
-
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 5f8e164ddb71..a423a382095a 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -1,5 +1,5 @@
/**
- * $Id: phram.c,v 1.11 2005/01/05 18:05:13 dwmw2 Exp $
+ * $Id: phram.c,v 1.14 2005/03/07 21:43:38 joern Exp $
*
* Copyright (c) ???? Jochen Schäuble <psionic@psionic.de>
* Copyright (c) 2003-2004 Jörn Engel <joern@wh.fh-wedel.de>
@@ -15,9 +15,7 @@
*
* Example:
* phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
- *
*/
-
#include <asm/io.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -36,7 +34,6 @@ struct phram_mtd_list {
static LIST_HEAD(phram_list);
-
static int phram_erase(struct mtd_info *mtd, struct erase_info *instr)
{
u_char *start = mtd->priv;
@@ -71,7 +68,8 @@ static int phram_point(struct mtd_info *mtd, loff_t from, size_t len,
return 0;
}
-static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len)
+static void phram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from,
+ size_t len)
{
}
@@ -80,8 +78,11 @@ static int phram_read(struct mtd_info *mtd, loff_t from, size_t len,
{
u_char *start = mtd->priv;
- if (from + len > mtd->size)
+ if (from >= mtd->size)
return -EINVAL;
+
+ if (len > mtd->size - from)
+ len = mtd->size - from;
memcpy(buf, start + from, len);
@@ -94,8 +95,11 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
{
u_char *start = mtd->priv;
- if (to + len > mtd->size)
+ if (to >= mtd->size)
return -EINVAL;
+
+ if (len > mtd->size - to)
+ len = mtd->size - to;
memcpy(start + to, buf, len);
@@ -107,9 +111,9 @@ static int phram_write(struct mtd_info *mtd, loff_t to, size_t len,
static void unregister_devices(void)
{
- struct phram_mtd_list *this;
+ struct phram_mtd_list *this, *safe;
- list_for_each_entry(this, &phram_list, list) {
+ list_for_each_entry_safe(this, safe, &phram_list, list) {
del_mtd_device(&this->mtd);
iounmap(this->mtd.priv);
kfree(this);
@@ -145,7 +149,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
new->mtd.write = phram_write;
new->mtd.owner = THIS_MODULE;
new->mtd.type = MTD_RAM;
- new->mtd.erasesize = 0;
+ new->mtd.erasesize = PAGE_SIZE;
ret = -EAGAIN;
if (add_mtd_device(&new->mtd)) {
@@ -214,6 +218,15 @@ static int parse_name(char **pname, const char *token)
return 0;
}
+
+static inline void kill_final_newline(char *str)
+{
+ char *newline = strrchr(str, '\n');
+ if (newline && !newline[1])
+ *newline = 0;
+}
+
+
#define parse_err(fmt, args...) do { \
ERROR(fmt , ## args); \
return 0; \
@@ -232,6 +245,7 @@ static int phram_setup(const char *val, struct kernel_param *kp)
parse_err("parameter too long\n");
strcpy(str, val);
+ kill_final_newline(str);
for (i=0; i<3; i++)
token[i] = strsep(&str, ",");
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 5ab15e643be7..84fa91392a8c 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -1,6 +1,6 @@
/*======================================================================
- $Id: slram.c,v 1.33 2005/01/05 18:05:13 dwmw2 Exp $
+ $Id: slram.c,v 1.34 2005/01/06 21:16:42 jwboyer Exp $
This driver provides a method to access memory not used by the kernel
itself (i.e. if the kernel commandline mem=xxx is used). To actually
@@ -50,6 +50,7 @@
#include <linux/mtd/mtd.h>
#define SLRAM_MAX_DEVICES_PARAMS 6 /* 3 parameters / device */
+#define SLRAM_BLK_SZ 0x4000
#define T(fmt, args...) printk(KERN_DEBUG fmt, ## args)
#define E(fmt, args...) printk(KERN_NOTICE fmt, ## args)
@@ -108,6 +109,9 @@ static int slram_point(struct mtd_info *mtd, loff_t from, size_t len,
{
slram_priv_t *priv = mtd->priv;
+ if (from + len > mtd->size)
+ return -EINVAL;
+
*mtdbuf = priv->start + from;
*retlen = len;
return(0);
@@ -121,7 +125,13 @@ static int slram_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
slram_priv_t *priv = mtd->priv;
-
+
+ if (from > mtd->size)
+ return -EINVAL;
+
+ if (from + len > mtd->size)
+ len = mtd->size - from;
+
memcpy(buf, priv->start + from, len);
*retlen = len;
@@ -133,6 +143,9 @@ static int slram_write(struct mtd_info *mtd, loff_t to, size_t len,
{
slram_priv_t *priv = mtd->priv;
+ if (to + len > mtd->size)
+ return -EINVAL;
+
memcpy(priv->start + to, buf, len);
*retlen = len;
@@ -188,7 +201,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->name = name;
(*curmtd)->mtdinfo->size = length;
(*curmtd)->mtdinfo->flags = MTD_CLEAR_BITS | MTD_SET_BITS |
- MTD_WRITEB_WRITEABLE | MTD_VOLATILE;
+ MTD_WRITEB_WRITEABLE | MTD_VOLATILE | MTD_CAP_RAM;
(*curmtd)->mtdinfo->erase = slram_erase;
(*curmtd)->mtdinfo->point = slram_point;
(*curmtd)->mtdinfo->unpoint = slram_unpoint;
@@ -196,7 +209,7 @@ static int register_device(char *name, unsigned long start, unsigned long length
(*curmtd)->mtdinfo->write = slram_write;
(*curmtd)->mtdinfo->owner = THIS_MODULE;
(*curmtd)->mtdinfo->type = MTD_RAM;
- (*curmtd)->mtdinfo->erasesize = 0x0;
+ (*curmtd)->mtdinfo->erasesize = SLRAM_BLK_SZ;
if (add_mtd_device((*curmtd)->mtdinfo)) {
E("slram: Failed to register new device\n");
@@ -261,7 +274,7 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
}
T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
devname, devstart, devlength);
- if ((devstart < 0) || (devlength < 0)) {
+ if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
E("slram: Illegal start / length parameter.\n");
return(-EINVAL);
}
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 18cc8846e733..d9ab60b36fd4 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1,5 +1,5 @@
/* This version ported to the Linux-MTD system by dwmw2@infradead.org
- * $Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $
+ * $Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $
*
* Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups
@@ -357,6 +357,7 @@ static int erase_xfer(partition_t *part,
if (!erase)
return -ENOMEM;
+ erase->mtd = part->mbd.mtd;
erase->callback = ftl_erase_callback;
erase->addr = xfer->Offset;
erase->len = 1 << part->header.EraseUnitSize;
@@ -1096,7 +1097,7 @@ struct mtd_blktrans_ops ftl_tr = {
int init_ftl(void)
{
- DEBUG(0, "$Id: ftl.c,v 1.54 2004/11/16 18:33:15 dwmw2 Exp $\n");
+ DEBUG(0, "$Id: ftl.c,v 1.55 2005/01/17 13:47:21 hvr Exp $\n");
return register_mtd_blktrans(&ftl_tr);
}
diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
index 8480057eadb4..44781a83b2e7 100644
--- a/drivers/mtd/maps/Kconfig
+++ b/drivers/mtd/maps/Kconfig
@@ -1,5 +1,5 @@
# drivers/mtd/maps/Kconfig
-# $Id: Kconfig,v 1.42 2005/01/05 16:59:50 dwmw2 Exp $
+# $Id: Kconfig,v 1.55 2005/07/02 01:53:24 tpoynor Exp $
menu "Mapping drivers for chip access"
depends on MTD!=n
@@ -122,16 +122,6 @@ config MTD_SBC_GXX
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/SBC_GX1.htm>.
-config MTD_ELAN_104NC
- tristate "CFI Flash device mapped on Arcom ELAN-104NC"
- depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS
- help
- This provides a driver for the on-board flash of the Arcom Control
- System's ELAN-104NC development board. By default the flash
- is split into 3 partitions which are accessed as separate MTD
- devices. This board utilizes Intel StrataFlash. More info at
- <http://www.arcomcontrols.com/products/icp/pc104/processors/ELAN104NC.htm>.
-
config MTD_LUBBOCK
tristate "CFI Flash device mapped on Intel Lubbock XScale eval board"
depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS
@@ -139,6 +129,14 @@ config MTD_LUBBOCK
This provides a driver for the on-board flash of the Intel
'Lubbock' XScale evaluation board.
+config MTD_MAINSTONE
+ tristate "CFI Flash device mapped on Intel Mainstone XScale eval board"
+ depends on MACH_MAINSTONE && MTD_CFI_INTELEXT
+ select MTD_PARTITIONS
+ help
+ This provides a driver for the on-board flash of the Intel
+ 'Mainstone PXA27x evaluation board.
+
config MTD_OCTAGON
tristate "JEDEC Flash device mapped on Octagon 5066 SBC"
depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS
@@ -213,74 +211,11 @@ config MTD_NETtel
help
Support for flash chips on NETtel/SecureEdge/SnapGear boards.
-config MTD_PB1XXX
- tristate "Flash devices on Alchemy PB1xxx boards"
- depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 )
- help
- Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards
-
-config MTD_PB1XXX_BOOT
- bool "PB1x00 boot flash device"
- depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
- help
- Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board.
- You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use
- both banks.
-
-config MTD_PB1XXX_USER
- bool "PB1x00 user flash device"
- depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 )
- default y if MTD_PB1XX_BOOT = n
- help
- Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board.
- You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use
- both banks.
-
-config MTD_PB1550
- tristate "Flash devices on Alchemy PB1550 board"
- depends on MIPS && MIPS_PB1550
- help
- Flash memory access on Alchemy Pb1550 board
-
-config MTD_PB1550_BOOT
- bool "PB1550 boot flash device"
- depends on MTD_PB1550
- help
- Use the first of the two 64MiB flash banks on Pb1550 board.
- You can say 'Y' to both this and 'MTD_PB1550_USER' below, to use
- both banks.
-
-config MTD_PB1550_USER
- bool "PB1550 user flash device"
- depends on MTD_PB1550
- default y if MTD_PB1550_BOOT = n
- help
- Use the second of the two 64MiB flash banks on Pb1550 board.
- You can say 'Y' to both this and 'MTD_PB1550_BOOT' above, to use
- both banks.
-
-config MTD_DB1550
- tristate "Flash devices on Alchemy DB1550 board"
- depends on MIPS && MIPS_DB1550
- help
- Flash memory access on Alchemy Db1550 board
-
-config MTD_DB1550_BOOT
- bool "DB1550 boot flash device"
- depends on MTD_DB1550
- help
- Use the first of the two 64MiB flash banks on Db1550 board.
- You can say 'Y' to both this and 'MTD_DB1550_USER' below, to use
- both banks.
-
-config MTD_DB1550_USER
- bool "DB1550 user flash device"
- depends on MTD_DB1550
- default y if MTD_DB1550_BOOT = n
+config MTD_ALCHEMY
+ tristate ' AMD Alchemy Pb1xxx/Db1xxx/RDK MTD support'
+ depends on MIPS && SOC_AU1X00
help
- Use the second of the two 64MiB flash banks on Db1550 board.
- You can say 'Y' to both this and 'MTD_DB1550_BOOT' above, to use
- both banks.
+ Flash memory access on AMD Alchemy Pb/Db/RDK Reference Boards
config MTD_DILNETPC
tristate "CFI Flash device mapped on DIL/Net PC"
@@ -588,6 +523,15 @@ config MTD_MPC1211
This enables access to the flash chips on the Interface MPC-1211(CTP/PCI/MPC-SH02).
If you have such a board, say 'Y'.
+config MTD_OMAP_NOR
+ tristate "TI OMAP board mappings"
+ depends on MTD_CFI && ARCH_OMAP
+ help
+ This enables access to the NOR flash chips on TI OMAP-based
+ boards defining flash platform devices and flash platform data.
+ These boards include the Innovator, H2, H3, OSK, Perseus2, and
+ more. If you have such a board, say 'Y'.
+
# This needs CFI or JEDEC, depending on the cards found.
config MTD_PCI
tristate "PCI MTD driver"
@@ -607,6 +551,16 @@ config MTD_PCMCIA
cards are usually around 4-16MiB in size. This does not include
Compact Flash cards which are treated as IDE devices.
+config MTD_PCMCIA_ANONYMOUS
+ bool "Use PCMCIA MTD drivers for anonymous PCMCIA cards"
+ depends on MTD_PCMCIA
+ default N
+ help
+ If this option is enabled, PCMCIA cards which do not report
+ anything about themselves are assumed to be MTD cards.
+
+ If unsure, say N.
+
config MTD_UCLINUX
tristate "Generic uClinux RAM/ROM filesystem support"
depends on MTD_PARTITIONS && !MMU
@@ -637,13 +591,14 @@ config MTD_DMV182
Map driver for Dy-4 SVME/DMV-182 board.
config MTD_BAST
- tristate "Map driver for Simtec BAST (EB2410ITX)"
- depends on ARCH_BAST
+ tristate "Map driver for Simtec BAST (EB2410ITX) or Thorcom VR1000"
+ depends on ARCH_BAST || MACH_VR1000
select MTD_PARTITIONS
select MTD_MAP_BANK_WIDTH_16
select MTD_JEDECPROBE
help
- Map driver for NOR flash on the Simtec BAST (EB2410ITX).
+ Map driver for NOR flash on the Simtec BAST (EB2410ITX), or the
+ Thorcom VR1000
Note, this driver *cannot* over-ride the WP link on the
board, or currently detect the state of the link.
@@ -659,5 +614,15 @@ config MTD_SHARP_SL
help
This enables access to the flash chip on the Sharp SL Series of PDAs.
+config MTD_PLATRAM
+ tristate "Map driver for platform device RAM (mtd-ram)"
+ depends on MTD
+ select MTD_RAM
+ help
+ Map driver for RAM areas described via the platform device
+ system.
+
+ This selection automatically selects the map_ram driver.
+
endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index 7ffe02b85301..7bcbc49e329f 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -1,7 +1,7 @@
#
# linux/drivers/maps/Makefile
#
-# $Id: Makefile.common,v 1.23 2005/01/05 17:06:36 dwmw2 Exp $
+# $Id: Makefile.common,v 1.30 2005/07/02 01:53:24 tpoynor Exp $
ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y)
obj-$(CONFIG_MTD) += map_funcs.o
@@ -15,7 +15,6 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
obj-$(CONFIG_MTD_DC21285) += dc21285.o
obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o
-obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
@@ -23,6 +22,7 @@ obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o
obj-$(CONFIG_MTD_ICHXROM) += ichxrom.o
obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o
obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o
+obj-$(CONFIG_MTD_MAINSTONE) += mainstone-flash.o
obj-$(CONFIG_MTD_MBX860) += mbx860.o
obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
@@ -44,10 +44,7 @@ obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
obj-$(CONFIG_MTD_PCI) += pci.o
-obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o
-obj-$(CONFIG_MTD_DB1X00) += db1x00-flash.o
-obj-$(CONFIG_MTD_PB1550) += pb1550-flash.o
-obj-$(CONFIG_MTD_DB1550) += db1550-flash.o
+obj-$(CONFIG_MTD_ALCHEMY) += alchemy-flash.o
obj-$(CONFIG_MTD_LASAT) += lasat.o
obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
obj-$(CONFIG_MTD_EDB7312) += edb7312.o
@@ -71,3 +68,5 @@ obj-$(CONFIG_MTD_IXP2000) += ixp2000.o
obj-$(CONFIG_MTD_WRSBC8260) += wr_sbc82xx_flash.o
obj-$(CONFIG_MTD_DMV182) += dmv182.o
obj-$(CONFIG_MTD_SHARP_SL) += sharpsl-flash.o
+obj-$(CONFIG_MTD_PLATRAM) += plat-ram.o
+obj-$(CONFIG_MTD_OMAP_NOR) += omap_nor.o
diff --git a/drivers/mtd/maps/alchemy-flash.c b/drivers/mtd/maps/alchemy-flash.c
new file mode 100644
index 000000000000..27fd2a3c3b60
--- /dev/null
+++ b/drivers/mtd/maps/alchemy-flash.c
@@ -0,0 +1,192 @@
+/*
+ * Flash memory access on AMD Alchemy evaluation boards
+ *
+ * $Id: alchemy-flash.c,v 1.1 2005/02/27 21:50:21 ppopov Exp $
+ *
+ * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+
+#ifdef DEBUG_RW
+#define DBG(x...) printk(x)
+#else
+#define DBG(x...)
+#endif
+
+#ifdef CONFIG_MIPS_PB1000
+#define BOARD_MAP_NAME "Pb1000 Flash"
+#define BOARD_FLASH_SIZE 0x00800000 /* 8MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1500
+#define BOARD_MAP_NAME "Pb1500 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1100
+#define BOARD_MAP_NAME "Pb1100 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1550
+#define BOARD_MAP_NAME "Pb1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_PB1200
+#define BOARD_MAP_NAME "Pb1200 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1000
+#define BOARD_MAP_NAME "Db1000 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1500
+#define BOARD_MAP_NAME "Db1500 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1100
+#define BOARD_MAP_NAME "Db1100 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1550
+#define BOARD_MAP_NAME "Db1550 Flash"
+#define BOARD_FLASH_SIZE 0x08000000 /* 128MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#endif
+
+#ifdef CONFIG_MIPS_DB1200
+#define BOARD_MAP_NAME "Db1200 Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_HYDROGEN3
+#define BOARD_MAP_NAME "Hydrogen3 Flash"
+#define BOARD_FLASH_SIZE 0x02000000 /* 32MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+#ifdef CONFIG_MIPS_BOSPORUS
+#define BOARD_MAP_NAME "Bosporus Flash"
+#define BOARD_FLASH_SIZE 0x01000000 /* 16MB */
+#define BOARD_FLASH_WIDTH 2 /* 16-bits */
+#endif
+
+#ifdef CONFIG_MIPS_MIRAGE
+#define BOARD_MAP_NAME "Mirage Flash"
+#define BOARD_FLASH_SIZE 0x04000000 /* 64MB */
+#define BOARD_FLASH_WIDTH 4 /* 32-bits */
+#define USE_LOCAL_ACCESSORS /* why? */
+#endif
+
+static struct map_info alchemy_map = {
+ .name = BOARD_MAP_NAME,
+};
+
+static struct mtd_partition alchemy_partitions[] = {
+ {
+ .name = "User FS",
+ .size = BOARD_FLASH_SIZE - 0x00400000,
+ .offset = 0x0000000
+ },{
+ .name = "YAMON",
+ .size = 0x0100000,
+ .offset = MTDPART_OFS_APPEND,
+ .mask_flags = MTD_WRITEABLE
+ },{
+ .name = "raw kernel",
+ .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
+ .offset = MTDPART_OFS_APPEND,
+ }
+};
+
+#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
+
+static struct mtd_info *mymtd;
+
+int __init alchemy_mtd_init(void)
+{
+ struct mtd_partition *parts;
+ int nb_parts = 0;
+ unsigned long window_addr;
+ unsigned long window_size;
+
+ /* Default flash buswidth */
+ alchemy_map.bankwidth = BOARD_FLASH_WIDTH;
+
+ window_addr = 0x20000000 - BOARD_FLASH_SIZE;
+ window_size = BOARD_FLASH_SIZE;
+#ifdef CONFIG_MIPS_MIRAGE_WHY
+ /* Boot ROM flash bank only; no user bank */
+ window_addr = 0x1C000000;
+ window_size = 0x04000000;
+ /* USERFS from 0x1C00 0000 to 0x1FC00000 */
+ alchemy_partitions[0].size = 0x03C00000;
+#endif
+
+ /*
+ * Static partition definition selection
+ */
+ parts = alchemy_partitions;
+ nb_parts = NB_OF(alchemy_partitions);
+ alchemy_map.size = window_size;
+
+ /*
+ * Now let's probe for the actual flash. Do it here since
+ * specific machine settings might have been set above.
+ */
+ printk(KERN_NOTICE BOARD_MAP_NAME ": probing %d-bit flash bus\n",
+ alchemy_map.bankwidth*8);
+ alchemy_map.virt = ioremap(window_addr, window_size);
+ mymtd = do_map_probe("cfi_probe", &alchemy_map);
+ if (!mymtd) {
+ iounmap(alchemy_map.virt);
+ return -ENXIO;
+ }
+ mymtd->owner = THIS_MODULE;
+
+ add_mtd_partitions(mymtd, parts, nb_parts);
+ return 0;
+}
+
+static void __exit alchemy_mtd_cleanup(void)
+{
+ if (mymtd) {
+ del_mtd_partitions(mymtd);
+ map_destroy(mymtd);
+ iounmap(alchemy_map.virt);
+ }
+}
+
+module_init(alchemy_mtd_init);
+module_exit(alchemy_mtd_cleanup);
+
+MODULE_AUTHOR("Embedded Alley Solutions, Inc");
+MODULE_DESCRIPTION(BOARD_MAP_NAME " MTD driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c
index 51e97b05304e..e8a900a77685 100644
--- a/drivers/mtd/maps/amd76xrom.c
+++ b/drivers/mtd/maps/amd76xrom.c
@@ -2,7 +2,7 @@
* amd76xrom.c
*
* Normal mappings of chips in physical memory
- * $Id: amd76xrom.c,v 1.19 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: amd76xrom.c,v 1.20 2005/03/18 14:04:35 gleixner Exp $
*/
#include <linux/module.h>
@@ -314,7 +314,7 @@ static int __init init_amd76xrom(void)
}
return -ENXIO;
#if 0
- return pci_module_init(&amd76xrom_driver);
+ return pci_register_driver(&amd76xrom_driver);
#endif
}
diff --git a/drivers/mtd/maps/bast-flash.c b/drivers/mtd/maps/bast-flash.c
index 44de3a81b277..0c45464e3f7b 100644
--- a/drivers/mtd/maps/bast-flash.c
+++ b/drivers/mtd/maps/bast-flash.c
@@ -1,14 +1,15 @@
/* linux/drivers/mtd/maps/bast_flash.c
*
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
*
* Simtec Bast (EB2410ITX) NOR MTD Mapping driver
*
* Changelog:
* 20-Sep-2004 BJD Initial version
+ * 17-Jan-2005 BJD Add whole device if no partitions found
*
- * $Id: bast-flash.c,v 1.1 2004/09/21 14:29:04 bjd Exp $
+ * $Id: bast-flash.c,v 1.2 2005/01/18 11:13:47 bjd Exp $
*
* 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
@@ -46,9 +47,9 @@
#include <asm/arch/bast-cpld.h>
#ifdef CONFIG_MTD_BAST_MAXSIZE
-#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * (1024*1024))
+#define AREA_MAXSIZE (CONFIG_MTD_BAST_MAXSIZE * SZ_1M)
#else
-#define AREA_MAXSIZE (32*1024*1024)
+#define AREA_MAXSIZE (32 * SZ_1M)
#endif
#define PFX "bast-flash: "
@@ -189,6 +190,8 @@ static int bast_flash_probe(struct device *dev)
err = add_mtd_partitions(info->mtd, info->partitions, err);
if (err)
printk(KERN_ERR PFX "cannot add/parse partitions\n");
+ } else {
+ err = add_mtd_device(info->mtd);
}
if (err == 0)
diff --git a/drivers/mtd/maps/db1550-flash.c b/drivers/mtd/maps/db1550-flash.c
deleted file mode 100644
index d213888462a4..000000000000
--- a/drivers/mtd/maps/db1550-flash.c
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1550 board
- *
- * $Id: db1550-flash.c,v 1.7 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on db1550-flash.c:
- * (C) 2003, 2004 Pete Popov <ppopov@embeddedalley.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info db1550_map = {
- .name = "Db1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/*
- * Support only 64MB NOR Flash parts
- */
-
-#if defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1550_BOOT) && !defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1550_BOOT) && defined(CONFIG_MTD_DB1550_USER)
-#define DB1550_USER_ONLY
-#endif
-
-#ifdef DB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x1FC00000 - 0x18000000),
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1550_BOOT_ONLY)
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- */
- {
- .name = "User FS",
- .size = 0x03c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1550_USER_ONLY)
-static struct mtd_partition db1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_DB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
-#if defined(DB1550_BOTH_BANKS)
- window_addr = 0x18000000;
- window_size = 0x8000000;
-#elif defined(DB1550_BOOT_ONLY)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
-#else /* USER ONLY */
- window_addr = 0x18000000;
- window_size = 0x4000000;
-#endif
- return 0;
-}
-
-int __init db1550_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- /* Default flash bankwidth */
- db1550_map.bankwidth = flash_bankwidth;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = db1550_partitions;
- nb_parts = NB_OF(db1550_partitions);
- db1550_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Db1550 flash: probing %d-bit flash bus\n",
- db1550_map.bankwidth*8);
- db1550_map.virt = ioremap(window_addr, window_size);
- mymtd = do_map_probe("cfi_probe", &db1550_map);
- if (!mymtd) return -ENXIO;
- mymtd->owner = THIS_MODULE;
-
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit db1550_mtd_cleanup(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- iounmap((void *) db1550_map.virt);
- }
-}
-
-module_init(db1550_mtd_init);
-module_exit(db1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Db1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/db1x00-flash.c b/drivers/mtd/maps/db1x00-flash.c
deleted file mode 100644
index faa68ec56902..000000000000
--- a/drivers/mtd/maps/db1x00-flash.c
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Flash memory access on Alchemy Db1xxx boards
- *
- * $Id: db1x00-flash.c,v 1.6 2004/11/04 13:24:14 gleixner Exp $
- *
- * (C) 2003 Pete Popov <ppopov@embeddedalley.com>
- *
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-/* MTD CONFIG OPTIONS */
-#if defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOTH_BANKS
-#elif defined(CONFIG_MTD_DB1X00_BOOT) && !defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_BOOT_ONLY
-#elif !defined(CONFIG_MTD_DB1X00_BOOT) && defined(CONFIG_MTD_DB1X00_USER)
-#define DB1X00_USER_ONLY
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-static unsigned long flash_size;
-
-static unsigned short *bcsr = (unsigned short *)0xAE000000;
-static unsigned char flash_bankwidth = 4;
-
-/*
- * The Db1x boards support different flash densities. We setup
- * the mtd_partition structures below for default of 64Mbit
- * flash densities, and override the partitions sizes, if
- * necessary, after we check the board status register.
- */
-
-#ifdef DB1X00_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1X00_BOOT_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x00c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(DB1X00_USER_ONLY)
-static struct mtd_partition db1x00_partitions[] = {
- {
- .name = "User FS",
- .size = 0x0e00000,
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_DB1X00 define combo error /* should never happen */
-#endif
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-#define NAME "Db1x00 Linux Flash"
-
-static struct map_info db1xxx_mtd_map = {
- .name = NAME,
-};
-
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *db1xxx_mtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
- switch ((bcsr[2] >> 14) & 0x3) {
- case 0: /* 64Mbit devices */
- flash_size = 0x800000; /* 8MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- window_addr = 0x1E000000;
- window_size = 0x2000000;
-#elif defined(DB1X00_BOOT_ONLY)
- window_addr = 0x1F000000;
- window_size = 0x1000000;
-#else /* USER ONLY */
- window_addr = 0x1E000000;
- window_size = 0x1000000;
-#endif
- break;
- case 1:
- /* 128 Mbit devices */
- flash_size = 0x1000000; /* 16MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
- /* USERFS from 0x1C00 0000 to 0x1FC0 0000 */
- db1x00_partitions[0].size = 0x3C00000;
-#elif defined(DB1X00_BOOT_ONLY)
- window_addr = 0x1E000000;
- window_size = 0x2000000;
- /* USERFS from 0x1E00 0000 to 0x1FC0 0000 */
- db1x00_partitions[0].size = 0x1C00000;
-#else /* USER ONLY */
- window_addr = 0x1C000000;
- window_size = 0x2000000;
- /* USERFS from 0x1C00 0000 to 0x1DE00000 */
- db1x00_partitions[0].size = 0x1DE0000;
-#endif
- break;
- case 2:
- /* 256 Mbit devices */
- flash_size = 0x4000000; /* 64MB per part */
-#if defined(DB1X00_BOTH_BANKS)
- return 1;
-#elif defined(DB1X00_BOOT_ONLY)
- /* Boot ROM flash bank only; no user bank */
- window_addr = 0x1C000000;
- window_size = 0x4000000;
- /* USERFS from 0x1C00 0000 to 0x1FC00000 */
- db1x00_partitions[0].size = 0x3C00000;
-#else /* USER ONLY */
- return 1;
-#endif
- break;
- default:
- return 1;
- }
- db1xxx_mtd_map.size = window_size;
- db1xxx_mtd_map.bankwidth = flash_bankwidth;
- db1xxx_mtd_map.phys = window_addr;
- db1xxx_mtd_map.bankwidth = flash_bankwidth;
- return 0;
-}
-
-int __init db1x00_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = db1x00_partitions;
- nb_parts = NB_OF(db1x00_partitions);
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Db1xxx flash: probing %d-bit flash bus\n",
- db1xxx_mtd_map.bankwidth*8);
- db1xxx_mtd_map.virt = ioremap(window_addr, window_size);
- db1xxx_mtd = do_map_probe("cfi_probe", &db1xxx_mtd_map);
- if (!db1xxx_mtd) return -ENXIO;
- db1xxx_mtd->owner = THIS_MODULE;
-
- add_mtd_partitions(db1xxx_mtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit db1x00_mtd_cleanup(void)
-{
- if (db1xxx_mtd) {
- del_mtd_partitions(db1xxx_mtd);
- map_destroy(db1xxx_mtd);
- if (parsed_parts)
- kfree(parsed_parts);
- }
-}
-
-module_init(db1x00_mtd_init);
-module_exit(db1x00_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Db1x00 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c
deleted file mode 100644
index e9465f5c069e..000000000000
--- a/drivers/mtd/maps/elan-104nc.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/* elan-104nc.c -- MTD map driver for Arcom Control Systems ELAN-104NC
-
- Copyright (C) 2000 Arcom Control System 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.
-
- 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
-
- $Id: elan-104nc.c,v 1.25 2004/11/28 09:40:39 dwmw2 Exp $
-
-The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16
-mode. This drivers uses the CFI probe and Intel Extended Command Set drivers.
-
-The flash is accessed as follows:
-
- 32 kbyte memory window at 0xb0000-0xb7fff
-
- 16 bit I/O port (0x22) for some sort of paging.
-
-The single flash device is divided into 3 partition which appear as separate
-MTD devices.
-
-Linux thinks that the I/O port is used by the PIC and hence check_region() will
-always fail. So we don't do it. I just hope it doesn't break anything.
-*/
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <asm/io.h>
-
-#include <linux/mtd/map.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-
-#define WINDOW_START 0xb0000
-/* Number of bits in offset. */
-#define WINDOW_SHIFT 15
-#define WINDOW_LENGTH (1 << WINDOW_SHIFT)
-/* The bits for the offset into the window. */
-#define WINDOW_MASK (WINDOW_LENGTH-1)
-#define PAGE_IO 0x22
-#define PAGE_IO_SIZE 2
-
-static volatile int page_in_window = -1; // Current page in window.
-static void __iomem *iomapadr;
-static DEFINE_SPINLOCK(elan_104nc_spin);
-
-/* partition_info gives details on the logical partitions that the split the
- * single flash device into. If the size if zero we use up to the end of the
- * device. */
-static struct mtd_partition partition_info[]={
- { .name = "ELAN-104NC flash boot partition",
- .offset = 0,
- .size = 640*1024 },
- { .name = "ELAN-104NC flash partition 1",
- .offset = 640*1024,
- .size = 896*1024 },
- { .name = "ELAN-104NC flash partition 2",
- .offset = (640+896)*1024 }
-};
-#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0]))
-
-/*
- * If no idea what is going on here. This is taken from the FlashFX stuff.
- */
-#define ROMCS 1
-
-static inline void elan_104nc_setup(void)
-{
- u16 t;
-
- outw( 0x0023 + ROMCS*2, PAGE_IO );
- t=inb( PAGE_IO+1 );
-
- t=(t & 0xf9) | 0x04;
-
- outw( ((0x0023 + ROMCS*2) | (t << 8)), PAGE_IO );
-}
-
-static inline void elan_104nc_page(struct map_info *map, unsigned long ofs)
-{
- unsigned long page = ofs >> WINDOW_SHIFT;
-
- if( page!=page_in_window ) {
- int cmd1;
- int cmd2;
-
- cmd1=(page & 0x700) + 0x0833 + ROMCS*0x4000;
- cmd2=((page & 0xff) << 8) + 0x0032;
-
- outw( cmd1, PAGE_IO );
- outw( cmd2, PAGE_IO );
-
- page_in_window = page;
- }
-}
-
-
-static map_word elan_104nc_read16(struct map_info *map, unsigned long ofs)
-{
- map_word ret;
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, ofs);
- ret.x[0] = readw(iomapadr + (ofs & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
- return ret;
-}
-
-static void elan_104nc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
-{
- while (len) {
- unsigned long thislen = len;
- if (len > (WINDOW_LENGTH - (from & WINDOW_MASK)))
- thislen = WINDOW_LENGTH-(from & WINDOW_MASK);
-
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, from);
- memcpy_fromio(to, iomapadr + (from & WINDOW_MASK), thislen);
- spin_unlock(&elan_104nc_spin);
- to += thislen;
- from += thislen;
- len -= thislen;
- }
-}
-
-static void elan_104nc_write16(struct map_info *map, map_word d, unsigned long adr)
-{
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, adr);
- writew(d.x[0], iomapadr + (adr & WINDOW_MASK));
- spin_unlock(&elan_104nc_spin);
-}
-
-static void elan_104nc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
-{
- while(len) {
- unsigned long thislen = len;
- if (len > (WINDOW_LENGTH - (to & WINDOW_MASK)))
- thislen = WINDOW_LENGTH-(to & WINDOW_MASK);
-
- spin_lock(&elan_104nc_spin);
- elan_104nc_page(map, to);
- memcpy_toio(iomapadr + (to & WINDOW_MASK), from, thislen);
- spin_unlock(&elan_104nc_spin);
- to += thislen;
- from += thislen;
- len -= thislen;
- }
-}
-
-static struct map_info elan_104nc_map = {
- .name = "ELAN-104NC flash",
- .phys = NO_XIP,
- .size = 8*1024*1024, /* this must be set to a maximum possible amount
- of flash so the cfi probe routines find all
- the chips */
- .bankwidth = 2,
- .read = elan_104nc_read16,
- .copy_from = elan_104nc_copy_from,
- .write = elan_104nc_write16,
- .copy_to = elan_104nc_copy_to
-};
-
-/* MTD device for all of the flash. */
-static struct mtd_info *all_mtd;
-
-static void cleanup_elan_104nc(void)
-{
- if( all_mtd ) {
- del_mtd_partitions( all_mtd );
- map_destroy( all_mtd );
- }
-
- iounmap(iomapadr);
-}
-
-static int __init init_elan_104nc(void)
-{
- /* Urg! We use I/O port 0x22 without request_region()ing it,
- because it's already allocated to the PIC. */
-
- iomapadr = ioremap(WINDOW_START, WINDOW_LENGTH);
- if (!iomapadr) {
- printk( KERN_ERR"%s: failed to ioremap memory region\n",
- elan_104nc_map.name );
- return -EIO;
- }
-
- printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n",
- elan_104nc_map.name,
- PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1,
- WINDOW_START, WINDOW_START+WINDOW_LENGTH-1 );
-
- elan_104nc_setup();
-
- /* Probe for chip. */
- all_mtd = do_map_probe("cfi_probe", &elan_104nc_map );
- if( !all_mtd ) {
- cleanup_elan_104nc();
- return -ENXIO;
- }
-
- all_mtd->owner = THIS_MODULE;
-
- /* Create MTD devices for each partition. */
- add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS );
-
- return 0;
-}
-
-module_init(init_elan_104nc);
-module_exit(cleanup_elan_104nc);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Arcom Control Systems Ltd.");
-MODULE_DESCRIPTION("MTD map driver for Arcom Control Systems ELAN-104NC");
diff --git a/drivers/mtd/maps/ichxrom.c b/drivers/mtd/maps/ichxrom.c
index 29d1cc1bb426..e505207cd489 100644
--- a/drivers/mtd/maps/ichxrom.c
+++ b/drivers/mtd/maps/ichxrom.c
@@ -2,7 +2,7 @@
* ichxrom.c
*
* Normal mappings of chips in physical memory
- * $Id: ichxrom.c,v 1.16 2004/11/28 09:40:39 dwmw2 Exp $
+ * $Id: ichxrom.c,v 1.18 2005/07/07 10:26:20 dwmw2 Exp $
*/
#include <linux/module.h>
@@ -338,9 +338,9 @@ static struct pci_device_id ichxrom_pci_tbl[] __devinitdata = {
{ 0, },
};
+#if 0
MODULE_DEVICE_TABLE(pci, ichxrom_pci_tbl);
-#if 0
static struct pci_driver ichxrom_driver = {
.name = MOD_NAME,
.id_table = ichxrom_pci_tbl,
@@ -366,7 +366,7 @@ static int __init init_ichxrom(void)
}
return -ENXIO;
#if 0
- return pci_module_init(&ichxrom_driver);
+ return pci_register_driver(&ichxrom_driver);
#endif
}
diff --git a/drivers/mtd/maps/ixp2000.c b/drivers/mtd/maps/ixp2000.c
index c5b5f447e34b..3e94b616743d 100644
--- a/drivers/mtd/maps/ixp2000.c
+++ b/drivers/mtd/maps/ixp2000.c
@@ -1,5 +1,5 @@
/*
- * $Id: ixp2000.c,v 1.5 2004/11/16 17:15:48 dsaxena Exp $
+ * $Id: ixp2000.c,v 1.6 2005/03/18 14:07:46 gleixner Exp $
*
* drivers/mtd/maps/ixp2000.c
*
@@ -216,11 +216,6 @@ static int ixp2000_flash_probe(struct device *_dev)
goto Error;
}
- /*
- * Setup read mode for FLASH
- */
- *IXP2000_SLOWPORT_FRM = 1;
-
#if defined(__ARMEB__)
/*
* Enable erratum 44 workaround for NPUs with broken slowport
diff --git a/drivers/mtd/maps/mainstone-flash.c b/drivers/mtd/maps/mainstone-flash.c
new file mode 100644
index 000000000000..87e93fa60588
--- /dev/null
+++ b/drivers/mtd/maps/mainstone-flash.c
@@ -0,0 +1,178 @@
+/*
+ * $Id: $
+ *
+ * Map driver for the Mainstone developer platform.
+ *
+ * Author: Nicolas Pitre
+ * Copyright: (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/mainstone.h>
+
+
+#define ROM_ADDR 0x00000000
+#define FLASH_ADDR 0x04000000
+
+#define WINDOW_SIZE 0x04000000
+
+static void mainstone_map_inval_cache(struct map_info *map, unsigned long from,
+ ssize_t len)
+{
+ consistent_sync((char *)map->cached + from, len, DMA_FROM_DEVICE);
+}
+
+static struct map_info mainstone_maps[2] = { {
+ .size = WINDOW_SIZE,
+ .phys = PXA_CS0_PHYS,
+ .inval_cache = mainstone_map_inval_cache,
+}, {
+ .size = WINDOW_SIZE,
+ .phys = PXA_CS1_PHYS,
+ .inval_cache = mainstone_map_inval_cache,
+} };
+
+static struct mtd_partition mainstone_partitions[] = {
+ {
+ .name = "Bootloader",
+ .size = 0x00040000,
+ .offset = 0,
+ .mask_flags = MTD_WRITEABLE /* force read-only */
+ },{
+ .name = "Kernel",
+ .size = 0x00400000,
+ .offset = 0x00040000,
+ },{
+ .name = "Filesystem",
+ .size = MTDPART_SIZ_FULL,
+ .offset = 0x00440000
+ }
+};
+
+static struct mtd_info *mymtds[2];
+static struct mtd_partition *parsed_parts[2];
+static int nr_parsed_parts[2];
+
+static const char *probes[] = { "RedBoot", "cmdlinepart", NULL };
+
+static int __init init_mainstone(void)
+{
+ int SW7 = 0; /* FIXME: get from SCR (Mst doc section 3.2.1.1) */
+ int ret = 0, i;
+
+ mainstone_maps[0].bankwidth = (BOOT_DEF & 1) ? 2 : 4;
+ mainstone_maps[1].bankwidth = 4;
+
+ /* Compensate for SW7 which swaps the flash banks */
+ mainstone_maps[SW7].name = "processor flash";
+ mainstone_maps[SW7 ^ 1].name = "main board flash";
+
+ printk(KERN_NOTICE "Mainstone configured to boot from %s\n",
+ mainstone_maps[0].name);
+
+ for (i = 0; i < 2; i++) {
+ mainstone_maps[i].virt = ioremap(mainstone_maps[i].phys,
+ WINDOW_SIZE);
+ if (!mainstone_maps[i].virt) {
+ printk(KERN_WARNING "Failed to ioremap %s\n",
+ mainstone_maps[i].name);
+ if (!ret)
+ ret = -ENOMEM;
+ continue;
+ }
+ mainstone_maps[i].cached =
+ ioremap_cached(mainstone_maps[i].phys, WINDOW_SIZE);
+ if (!mainstone_maps[i].cached)
+ printk(KERN_WARNING "Failed to ioremap cached %s\n",
+ mainstone_maps[i].name);
+ simple_map_init(&mainstone_maps[i]);
+
+ printk(KERN_NOTICE
+ "Probing %s at physical address 0x%08lx"
+ " (%d-bit bankwidth)\n",
+ mainstone_maps[i].name, mainstone_maps[i].phys,
+ mainstone_maps[i].bankwidth * 8);
+
+ mymtds[i] = do_map_probe("cfi_probe", &mainstone_maps[i]);
+
+ if (!mymtds[i]) {
+ iounmap((void *)mainstone_maps[i].virt);
+ if (mainstone_maps[i].cached)
+ iounmap(mainstone_maps[i].cached);
+ if (!ret)
+ ret = -EIO;
+ continue;
+ }
+ mymtds[i]->owner = THIS_MODULE;
+
+ ret = parse_mtd_partitions(mymtds[i], probes,
+ &parsed_parts[i], 0);
+
+ if (ret > 0)
+ nr_parsed_parts[i] = ret;
+ }
+
+ if (!mymtds[0] && !mymtds[1])
+ return ret;
+
+ for (i = 0; i < 2; i++) {
+ if (!mymtds[i]) {
+ printk(KERN_WARNING "%s is absent. Skipping\n",
+ mainstone_maps[i].name);
+ } else if (nr_parsed_parts[i]) {
+ add_mtd_partitions(mymtds[i], parsed_parts[i],
+ nr_parsed_parts[i]);
+ } else if (!i) {
+ printk("Using static partitions on %s\n",
+ mainstone_maps[i].name);
+ add_mtd_partitions(mymtds[i], mainstone_partitions,
+ ARRAY_SIZE(mainstone_partitions));
+ } else {
+ printk("Registering %s as whole device\n",
+ mainstone_maps[i].name);
+ add_mtd_device(mymtds[i]);
+ }
+ }
+ return 0;
+}
+
+static void __exit cleanup_mainstone(void)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ if (!mymtds[i])
+ continue;
+
+ if (nr_parsed_parts[i] || !i)
+ del_mtd_partitions(mymtds[i]);
+ else
+ del_mtd_device(mymtds[i]);
+
+ map_destroy(mymtds[i]);
+ iounmap((void *)mainstone_maps[i].virt);
+ if (mainstone_maps[i].cached)
+ iounmap(mainstone_maps[i].cached);
+ kfree(parsed_parts[i]);
+ }
+}
+
+module_init(init_mainstone);
+module_exit(cleanup_mainstone);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>");
+MODULE_DESCRIPTION("MTD map driver for Intel Mainstone");
diff --git a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c
index 38f6a7af53f8..9105e6ca0aa6 100644
--- a/drivers/mtd/maps/map_funcs.c
+++ b/drivers/mtd/maps/map_funcs.c
@@ -1,5 +1,5 @@
/*
- * $Id: map_funcs.c,v 1.9 2004/07/13 22:33:15 dwmw2 Exp $
+ * $Id: map_funcs.c,v 1.10 2005/06/06 23:04:36 tpoynor Exp $
*
* Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS
* is enabled.
@@ -9,23 +9,24 @@
#include <linux/module.h>
#include <linux/mtd/map.h>
+#include <linux/mtd/xip.h>
-static map_word simple_map_read(struct map_info *map, unsigned long ofs)
+static map_word __xipram simple_map_read(struct map_info *map, unsigned long ofs)
{
return inline_map_read(map, ofs);
}
-static void simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
+static void __xipram simple_map_write(struct map_info *map, const map_word datum, unsigned long ofs)
{
inline_map_write(map, datum, ofs);
}
-static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+static void __xipram simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
{
inline_map_copy_from(map, to, from, len);
}
-static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+static void __xipram simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
{
inline_map_copy_to(map, to, from, len);
}
diff --git a/drivers/mtd/maps/omap_nor.c b/drivers/mtd/maps/omap_nor.c
new file mode 100644
index 000000000000..8cc71409a328
--- /dev/null
+++ b/drivers/mtd/maps/omap_nor.c
@@ -0,0 +1,179 @@
+/*
+ * Flash memory support for various TI OMAP boards
+ *
+ * Copyright (C) 2001-2002 MontaVista Software Inc.
+ * Copyright (C) 2003-2004 Texas Instruments
+ * Copyright (C) 2004 Nokia Corporation
+ *
+ * Assembled using driver code copyright the companies above
+ * and written by David Brownell, Jian Zhang <jzhang@ti.com>,
+ * Tony Lindgren <tony@atomide.com> and others.
+ *
+ * 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 <linux/device.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/flash.h>
+#include <asm/arch/tc.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { /* "RedBoot", */ "cmdlinepart", NULL };
+#endif
+
+struct omapflash_info {
+ struct mtd_partition *parts;
+ struct mtd_info *mtd;
+ struct map_info map;
+};
+
+static void omap_set_vpp(struct map_info *map, int enable)
+{
+ static int count;
+
+ if (enable) {
+ if (count++ == 0)
+ OMAP_EMIFS_CONFIG_REG |= OMAP_EMIFS_CONFIG_WP;
+ } else {
+ if (count && (--count == 0))
+ OMAP_EMIFS_CONFIG_REG &= ~OMAP_EMIFS_CONFIG_WP;
+ }
+}
+
+static int __devinit omapflash_probe(struct device *dev)
+{
+ int err;
+ struct omapflash_info *info;
+ struct platform_device *pdev = to_platform_device(dev);
+ struct flash_platform_data *pdata = pdev->dev.platform_data;
+ struct resource *res = pdev->resource;
+ unsigned long size = res->end - res->start + 1;
+
+ info = kmalloc(sizeof(struct omapflash_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ memset(info, 0, sizeof(struct omapflash_info));
+
+ if (!request_mem_region(res->start, size, "flash")) {
+ err = -EBUSY;
+ goto out_free_info;
+ }
+
+ info->map.virt = ioremap(res->start, size);
+ if (!info->map.virt) {
+ err = -ENOMEM;
+ goto out_release_mem_region;
+ }
+ info->map.name = pdev->dev.bus_id;
+ info->map.phys = res->start;
+ info->map.size = size;
+ info->map.bankwidth = pdata->width;
+ info->map.set_vpp = omap_set_vpp;
+
+ simple_map_init(&info->map);
+ info->mtd = do_map_probe(pdata->map_name, &info->map);
+ if (!info->mtd) {
+ err = -EIO;
+ goto out_iounmap;
+ }
+ info->mtd->owner = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+ err = parse_mtd_partitions(info->mtd, part_probes, &info->parts, 0);
+ if (err > 0)
+ add_mtd_partitions(info->mtd, info->parts, err);
+ else if (err < 0 && pdata->parts)
+ add_mtd_partitions(info->mtd, pdata->parts, pdata->nr_parts);
+ else
+#endif
+ add_mtd_device(info->mtd);
+
+ dev_set_drvdata(&pdev->dev, info);
+
+ return 0;
+
+out_iounmap:
+ iounmap(info->map.virt);
+out_release_mem_region:
+ release_mem_region(res->start, size);
+out_free_info:
+ kfree(info);
+
+ return err;
+}
+
+static int __devexit omapflash_remove(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct omapflash_info *info = dev_get_drvdata(&pdev->dev);
+
+ dev_set_drvdata(&pdev->dev, NULL);
+
+ if (info) {
+ if (info->parts) {
+ del_mtd_partitions(info->mtd);
+ kfree(info->parts);
+ } else
+ del_mtd_device(info->mtd);
+ map_destroy(info->mtd);
+ release_mem_region(info->map.phys, info->map.size);
+ iounmap((void __iomem *) info->map.virt);
+ kfree(info);
+ }
+
+ return 0;
+}
+
+static struct device_driver omapflash_driver = {
+ .name = "omapflash",
+ .bus = &platform_bus_type,
+ .probe = omapflash_probe,
+ .remove = __devexit_p(omapflash_remove),
+};
+
+static int __init omapflash_init(void)
+{
+ return driver_register(&omapflash_driver);
+}
+
+static void __exit omapflash_exit(void)
+{
+ driver_unregister(&omapflash_driver);
+}
+
+module_init(omapflash_init);
+module_exit(omapflash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MTD NOR map driver for TI OMAP boards");
+
diff --git a/drivers/mtd/maps/pb1550-flash.c b/drivers/mtd/maps/pb1550-flash.c
deleted file mode 100644
index 1424726a219e..000000000000
--- a/drivers/mtd/maps/pb1550-flash.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1550 board
- *
- * $Id: pb1550-flash.c,v 1.6 2004/11/04 13:24:15 gleixner Exp $
- *
- * (C) 2004 Embedded Edge, LLC, based on pb1550-flash.c:
- * (C) 2003 Pete Popov <ppopov@pacbell.net>
- *
- */
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-#include <asm/au1000.h>
-#include <asm/pb1550.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-static unsigned long window_addr;
-static unsigned long window_size;
-
-
-static struct map_info pb1550_map = {
- .name = "Pb1550 flash",
-};
-
-static unsigned char flash_bankwidth = 4;
-
-/*
- * Support only 64MB NOR Flash parts
- */
-
-#ifdef PB1550_BOTH_BANKS
-/* both banks will be used. Combine the first bank and the first
- * part of the second bank together into a single jffs/jffs2
- * partition.
- */
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x1FC00000 - 0x18000000),
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000 - 0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(PB1550_BOOT_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1C00 0000 1FFF FFFF CE0 64MB Boot NOR Flash
- */
- {
- .name = "User FS",
- .size = 0x03c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = MTDPART_OFS_APPEND,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = (0x300000-0x40000), /* last 256KB is yamon env */
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#elif defined(PB1550_USER_ONLY)
-static struct mtd_partition pb1550_partitions[] = {
- /* assume boot[2:0]:swap is '0000' or '1000', which translates to:
- * 1800 0000 1BFF FFFF CE0 64MB Param NOR Flash
- */
- {
- .name = "User FS",
- .size = (0x4000000 - 0x200000), /* reserve 2MB for raw kernel */
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND,
- }
-};
-#else
-#error MTD_PB1550 define combo error /* should never happen */
-#endif
-
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-static struct mtd_info *mymtd;
-
-/*
- * Probe the flash density and setup window address and size
- * based on user CONFIG options. There are times when we don't
- * want the MTD driver to be probing the boot or user flash,
- * so having the option to enable only one bank is important.
- */
-int setup_flash_params(void)
-{
- u16 boot_swapboot;
- boot_swapboot = (au_readl(MEM_STSTAT) & (0x7<<1)) |
- ((bcsr->status >> 6) & 0x1);
- printk("Pb1550 MTD: boot:swap %d\n", boot_swapboot);
-
- switch (boot_swapboot) {
- case 0: /* 512Mbit devices, both enabled */
- case 1:
- case 8:
- case 9:
-#if defined(PB1550_BOTH_BANKS)
- window_addr = 0x18000000;
- window_size = 0x8000000;
-#elif defined(PB1550_BOOT_ONLY)
- window_addr = 0x1C000000;
- window_size = 0x4000000;
-#else /* USER ONLY */
- window_addr = 0x1E000000;
- window_size = 0x4000000;
-#endif
- break;
- case 0xC:
- case 0xD:
- case 0xE:
- case 0xF:
- /* 64 MB Boot NOR Flash is disabled */
- /* and the start address is moved to 0x0C00000 */
- window_addr = 0x0C000000;
- window_size = 0x4000000;
- default:
- printk("Pb1550 MTD: unsupported boot:swap setting\n");
- return 1;
- }
- return 0;
-}
-
-int __init pb1550_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
-
- /* Default flash bankwidth */
- pb1550_map.bankwidth = flash_bankwidth;
-
- if (setup_flash_params())
- return -ENXIO;
-
- /*
- * Static partition definition selection
- */
- parts = pb1550_partitions;
- nb_parts = NB_OF(pb1550_partitions);
- pb1550_map.size = window_size;
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Pb1550 flash: probing %d-bit flash bus\n",
- pb1550_map.bankwidth*8);
- pb1550_map.virt = ioremap(window_addr, window_size);
- mymtd = do_map_probe("cfi_probe", &pb1550_map);
- if (!mymtd) return -ENXIO;
- mymtd->owner = THIS_MODULE;
-
- add_mtd_partitions(mymtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit pb1550_mtd_cleanup(void)
-{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- }
-}
-
-module_init(pb1550_mtd_init);
-module_exit(pb1550_mtd_cleanup);
-
-MODULE_AUTHOR("Embedded Edge, LLC");
-MODULE_DESCRIPTION("Pb1550 mtd map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c
deleted file mode 100644
index 06e731540552..000000000000
--- a/drivers/mtd/maps/pb1xxx-flash.c
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Flash memory access on Alchemy Pb1xxx boards
- *
- * (C) 2001 Pete Popov <ppopov@mvista.com>
- *
- * $Id: pb1xxx-flash.c,v 1.14 2004/11/04 13:24:15 gleixner Exp $
- */
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/map.h>
-#include <linux/mtd/partitions.h>
-
-#include <asm/io.h>
-
-#ifdef DEBUG_RW
-#define DBG(x...) printk(x)
-#else
-#define DBG(x...)
-#endif
-
-#ifdef CONFIG_MIPS_PB1000
-
-#define WINDOW_ADDR 0x1F800000
-#define WINDOW_SIZE 0x800000
-
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "yamon env",
- .size = 0x00020000,
- .offset = 0,
- .mask_flags = MTD_WRITEABLE},
- {
- .name = "User FS",
- .size = 0x003e0000,
- .offset = 0x20000,},
- {
- .name = "boot code",
- .size = 0x100000,
- .offset = 0x400000,
- .mask_flags = MTD_WRITEABLE},
- {
- .name = "raw/kernel",
- .size = 0x300000,
- .offset = 0x500000}
-};
-
-#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100)
-
-#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-/* both 32MB banks will be used. Combine the first 32MB bank and the
- * first 28MB of the second bank together into a single jffs/jffs2
- * partition.
- */
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x4000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x3c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x3c00000,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x3d00000
- }
-};
-#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1E000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1c00000,
- .offset = 0x0000000
- },{
- .name = "yamon",
- .size = 0x0100000,
- .offset = 0x1c00000,
- .mask_flags = MTD_WRITEABLE
- },{
- .name = "raw kernel",
- .size = 0x02c0000,
- .offset = 0x1d00000
- }
-};
-#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER)
-#define WINDOW_ADDR 0x1C000000
-#define WINDOW_SIZE 0x2000000
-static struct mtd_partition pb1xxx_partitions[] = {
- {
- .name = "User FS",
- .size = 0x1e00000,
- .offset = 0x0000000
- },{
- .name = "raw kernel",
- .size = 0x0200000,
- .offset = 0x1e00000,
- }
-};
-#else
-#error MTD_PB1500 define combo error /* should never happen */
-#endif
-#else
-#error Unsupported board
-#endif
-
-#define NAME "Pb1x00 Linux Flash"
-#define PADDR WINDOW_ADDR
-#define BUSWIDTH 4
-#define SIZE WINDOW_SIZE
-#define PARTITIONS 4
-
-static struct map_info pb1xxx_mtd_map = {
- .name = NAME,
- .size = SIZE,
- .bankwidth = BUSWIDTH,
- .phys = PADDR,
-};
-
-static struct mtd_info *pb1xxx_mtd;
-
-int __init pb1xxx_mtd_init(void)
-{
- struct mtd_partition *parts;
- int nb_parts = 0;
- char *part_type;
-
- /*
- * Static partition definition selection
- */
- part_type = "static";
- parts = pb1xxx_partitions;
- nb_parts = ARRAY_SIZE(pb1xxx_partitions);
-
- /*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
- */
- printk(KERN_NOTICE "Pb1xxx flash: probing %d-bit flash bus\n",
- BUSWIDTH*8);
- pb1xxx_mtd_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
-
- simple_map_init(&pb1xxx_mtd_map);
-
- pb1xxx_mtd = do_map_probe("cfi_probe", &pb1xxx_mtd_map);
- if (!pb1xxx_mtd) return -ENXIO;
- pb1xxx_mtd->owner = THIS_MODULE;
-
- add_mtd_partitions(pb1xxx_mtd, parts, nb_parts);
- return 0;
-}
-
-static void __exit pb1xxx_mtd_cleanup(void)
-{
- if (pb1xxx_mtd) {
- del_mtd_partitions(pb1xxx_mtd);
- map_destroy(pb1xxx_mtd);
- iounmap((void *) pb1xxx_mtd_map.virt);
- }
-}
-
-module_init(pb1xxx_mtd_init);
-module_exit(pb1xxx_mtd_cleanup);
-
-MODULE_AUTHOR("Pete Popov");
-MODULE_DESCRIPTION("Pb1xxx CFI map driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
index 08b60bdc5381..18dbd3af1eaa 100644
--- a/drivers/mtd/maps/pci.c
+++ b/drivers/mtd/maps/pci.c
@@ -7,7 +7,7 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
- * $Id: pci.c,v 1.9 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: pci.c,v 1.10 2005/03/18 14:04:35 gleixner Exp $
*
* Generic PCI memory map driver. We support the following boards:
* - Intel IQ80310 ATU.
@@ -370,7 +370,7 @@ static struct pci_driver mtd_pci_driver = {
static int __init mtd_pci_maps_init(void)
{
- return pci_module_init(&mtd_pci_driver);
+ return pci_register_driver(&mtd_pci_driver);
}
static void __exit mtd_pci_maps_exit(void)
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
index e37b4c1976e5..ff7c50d10180 100644
--- a/drivers/mtd/maps/pcmciamtd.c
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -18,7 +18,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -800,11 +799,6 @@ static dev_link_t *pcmciamtd_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &pcmciamtd_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
DEBUG(2, "Calling RegisterClient");
@@ -818,14 +812,42 @@ static dev_link_t *pcmciamtd_attach(void)
return link;
}
+static struct pcmcia_device_id pcmciamtd_ids[] = {
+ PCMCIA_DEVICE_FUNC_ID(1),
+ PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCS-2M", "2MB SRAM", 0x547e66dc, 0x1fed36cd, 0x36eadd21),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "2MB SRAM", 0xb569a6e5, 0x36eadd21),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "4MB FLASH", 0xb569a6e5, 0x8bc54d2a),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "8MB FLASH", 0xb569a6e5, 0x6df1be3e),
+ PCMCIA_DEVICE_PROD_ID12("Intel", "S2E20SW", 0x816cc815, 0xd14c9dcf),
+ PCMCIA_DEVICE_PROD_ID12("Intel", "S2E8 SW", 0x816cc815, 0xa2d7dedb),
+ PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-02 ", 0x40ade711, 0x145cea5c),
+ PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-04 ", 0x40ade711, 0x42064dda),
+ PCMCIA_DEVICE_PROD_ID12("intel", "SERIES2-20 ", 0x40ade711, 0x25ee5cb0),
+ PCMCIA_DEVICE_PROD_ID12("intel", "VALUE SERIES 100 ", 0x40ade711, 0xdf8506d8),
+ PCMCIA_DEVICE_PROD_ID12("KINGMAX TECHNOLOGY INC.", "SRAM 256K Bytes", 0x54d0c69c, 0xad12c29c),
+ PCMCIA_DEVICE_PROD_ID12("Maxtor", "MAXFL MobileMax Flash Memory Card", 0xb68968c8, 0x2dfb47b0),
+ PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB101EN20", 0xf9876baf, 0xad0b207b),
+ PCMCIA_DEVICE_PROD_ID12("SEIKO EPSON", "WWB513EN20", 0xf9876baf, 0xe8d884ad),
+ PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-3000", 0x05ddca47, 0xe7d67bca),
+ PCMCIA_DEVICE_PROD_ID12("Starfish, Inc.", "REX-4100", 0x05ddca47, 0x7bc32944),
+ /* the following was commented out in pcmcia-cs-3.2.7 */
+ /* PCMCIA_DEVICE_PROD_ID12("RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card", 0xf4a2fefe, 0x5885b2ae), */
+#ifdef CONFIG_MTD_PCMCIA_ANONYMOUS
+ { .match_flags = PCMCIA_DEV_ID_MATCH_ANONYMOUS, },
+#endif
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcmciamtd_ids);
static struct pcmcia_driver pcmciamtd_driver = {
.drv = {
.name = "pcmciamtd"
},
.attach = pcmciamtd_attach,
+ .event = pcmciamtd_event,
.detach = pcmciamtd_detach,
- .owner = THIS_MODULE
+ .owner = THIS_MODULE,
+ .id_table = pcmciamtd_ids,
};
diff --git a/drivers/mtd/maps/plat-ram.c b/drivers/mtd/maps/plat-ram.c
new file mode 100644
index 000000000000..118b04544cad
--- /dev/null
+++ b/drivers/mtd/maps/plat-ram.c
@@ -0,0 +1,278 @@
+/* drivers/mtd/maps/plat-ram.c
+ *
+ * (c) 2004-2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platfrom device based RAM map
+ *
+ * $Id: plat-ram.c,v 1.3 2005/03/19 22:41:27 gleixner Exp $
+ *
+ * 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 <linux/module.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/plat-ram.h>
+
+#include <asm/io.h>
+
+/* private structure for each mtd platform ram device created */
+
+struct platram_info {
+ struct device *dev;
+ struct mtd_info *mtd;
+ struct map_info map;
+ struct mtd_partition *partitions;
+ struct resource *area;
+ struct platdata_mtd_ram *pdata;
+};
+
+/* to_platram_info()
+ *
+ * device private data to struct platram_info conversion
+*/
+
+static inline struct platram_info *to_platram_info(struct device *dev)
+{
+ return (struct platram_info *)dev_get_drvdata(dev);
+}
+
+/* platram_setrw
+ *
+ * call the platform device's set rw/ro control
+ *
+ * to = 0 => read-only
+ * = 1 => read-write
+*/
+
+static inline void platram_setrw(struct platram_info *info, int to)
+{
+ if (info->pdata == NULL)
+ return;
+
+ if (info->pdata->set_rw != NULL)
+ (info->pdata->set_rw)(info->dev, to);
+}
+
+/* platram_remove
+ *
+ * called to remove the device from the driver's control
+*/
+
+static int platram_remove(struct device *dev)
+{
+ struct platram_info *info = to_platram_info(dev);
+
+ dev_set_drvdata(dev, NULL);
+
+ dev_dbg(dev, "removing device\n");
+
+ if (info == NULL)
+ return 0;
+
+ if (info->mtd) {
+#ifdef CONFIG_MTD_PARTITIONS
+ if (info->partitions) {
+ del_mtd_partitions(info->mtd);
+ kfree(info->partitions);
+ }
+#endif
+ del_mtd_device(info->mtd);
+ map_destroy(info->mtd);
+ }
+
+ /* ensure ram is left read-only */
+
+ platram_setrw(info, PLATRAM_RO);
+
+ /* release resources */
+
+ if (info->area) {
+ release_resource(info->area);
+ kfree(info->area);
+ }
+
+ if (info->map.virt != NULL)
+ iounmap(info->map.virt);
+
+ kfree(info);
+
+ return 0;
+}
+
+/* platram_probe
+ *
+ * called from device drive system when a device matching our
+ * driver is found.
+*/
+
+static int platram_probe(struct device *dev)
+{
+ struct platform_device *pd = to_platform_device(dev);
+ struct platdata_mtd_ram *pdata;
+ struct platram_info *info;
+ struct resource *res;
+ int err = 0;
+
+ dev_dbg(dev, "probe entered\n");
+
+ if (dev->platform_data == NULL) {
+ dev_err(dev, "no platform data supplied\n");
+ err = -ENOENT;
+ goto exit_error;
+ }
+
+ pdata = dev->platform_data;
+
+ info = kmalloc(sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ dev_err(dev, "no memory for flash info\n");
+ err = -ENOMEM;
+ goto exit_error;
+ }
+
+ memset(info, 0, sizeof(*info));
+ dev_set_drvdata(dev, info);
+
+ info->dev = dev;
+ info->pdata = pdata;
+
+ /* get the resource for the memory mapping */
+
+ res = platform_get_resource(pd, IORESOURCE_MEM, 0);
+
+ if (res == NULL) {
+ dev_err(dev, "no memory resource specified\n");
+ err = -ENOENT;
+ goto exit_free;
+ }
+
+ dev_dbg(dev, "got platform resource %p (0x%lx)\n", res, res->start);
+
+ /* setup map parameters */
+
+ info->map.phys = res->start;
+ info->map.size = (res->end - res->start) + 1;
+ info->map.name = pdata->mapname != NULL ? pdata->mapname : pd->name;
+ info->map.bankwidth = pdata->bankwidth;
+
+ /* register our usage of the memory area */
+
+ info->area = request_mem_region(res->start, info->map.size, pd->name);
+ if (info->area == NULL) {
+ dev_err(dev, "failed to request memory region\n");
+ err = -EIO;
+ goto exit_free;
+ }
+
+ /* remap the memory area */
+
+ info->map.virt = ioremap(res->start, info->map.size);
+ dev_dbg(dev, "virt %p, %lu bytes\n", info->map.virt, info->map.size);
+
+ if (info->map.virt == NULL) {
+ dev_err(dev, "failed to ioremap() region\n");
+ err = -EIO;
+ goto exit_free;
+ }
+
+ simple_map_init(&info->map);
+
+ dev_dbg(dev, "initialised map, probing for mtd\n");
+
+ /* probe for the right mtd map driver */
+
+ info->mtd = do_map_probe("map_ram" , &info->map);
+ if (info->mtd == NULL) {
+ dev_err(dev, "failed to probe for map_ram\n");
+ err = -ENOMEM;
+ goto exit_free;
+ }
+
+ info->mtd->owner = THIS_MODULE;
+
+ platram_setrw(info, PLATRAM_RW);
+
+ /* check to see if there are any available partitions, or wether
+ * to add this device whole */
+
+#ifdef CONFIG_MTD_PARTITIONS
+ if (pdata->nr_partitions > 0) {
+ const char **probes = { NULL };
+
+ if (pdata->probes)
+ probes = (const char **)pdata->probes;
+
+ err = parse_mtd_partitions(info->mtd, probes,
+ &info->partitions, 0);
+ if (err > 0) {
+ err = add_mtd_partitions(info->mtd, info->partitions,
+ err);
+ }
+ }
+#endif /* CONFIG_MTD_PARTITIONS */
+
+ if (add_mtd_device(info->mtd)) {
+ dev_err(dev, "add_mtd_device() failed\n");
+ err = -ENOMEM;
+ }
+
+ dev_info(dev, "registered mtd device\n");
+ return err;
+
+ exit_free:
+ platram_remove(dev);
+ exit_error:
+ return err;
+}
+
+/* device driver info */
+
+static struct device_driver platram_driver = {
+ .name = "mtd-ram",
+ .bus = &platform_bus_type,
+ .probe = platram_probe,
+ .remove = platram_remove,
+};
+
+/* module init/exit */
+
+static int __init platram_init(void)
+{
+ printk("Generic platform RAM MTD, (c) 2004 Simtec Electronics\n");
+ return driver_register(&platram_driver);
+}
+
+static void __exit platram_exit(void)
+{
+ driver_unregister(&platram_driver);
+}
+
+module_init(platram_init);
+module_exit(platram_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
+MODULE_DESCRIPTION("MTD platform RAM map driver");
diff --git a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c
index 5bb3b600e5d0..97a8dfd69258 100644
--- a/drivers/mtd/maps/scb2_flash.c
+++ b/drivers/mtd/maps/scb2_flash.c
@@ -1,6 +1,6 @@
/*
* MTD map driver for BIOS Flash on Intel SCB2 boards
- * $Id: scb2_flash.c,v 1.11 2004/11/28 09:40:40 dwmw2 Exp $
+ * $Id: scb2_flash.c,v 1.12 2005/03/18 14:04:35 gleixner Exp $
* Copyright (C) 2002 Sun Microsystems, Inc.
* Tim Hockin <thockin@sun.com>
*
@@ -238,7 +238,7 @@ static struct pci_driver scb2_flash_driver = {
static int __init
scb2_flash_init(void)
{
- return pci_module_init(&scb2_flash_driver);
+ return pci_register_driver(&scb2_flash_driver);
}
static void __exit
diff --git a/drivers/mtd/maps/sharpsl-flash.c b/drivers/mtd/maps/sharpsl-flash.c
index b3b39cb7c608..d15da6fd84c1 100644
--- a/drivers/mtd/maps/sharpsl-flash.c
+++ b/drivers/mtd/maps/sharpsl-flash.c
@@ -4,7 +4,7 @@
* Copyright (C) 2001 Lineo Japan, Inc.
* Copyright (C) 2002 SHARP
*
- * $Id: sharpsl-flash.c,v 1.2 2004/11/24 20:38:06 rpurdie Exp $
+ * $Id: sharpsl-flash.c,v 1.5 2005/03/21 08:42:11 rpurdie Exp $
*
* based on rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp
* Handle mapping of the flash on the RPX Lite and CLLF boards
@@ -24,13 +24,14 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
-#include <asm/io.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <asm/mach-types.h>
#define WINDOW_ADDR 0x00000000
-#define WINDOW_SIZE 0x01000000
+#define WINDOW_SIZE 0x00800000
#define BANK_WIDTH 2
static struct mtd_info *mymtd;
@@ -44,9 +45,7 @@ struct map_info sharpsl_map = {
static struct mtd_partition sharpsl_partitions[1] = {
{
- name: "Filesystem",
- size: 0x006d0000,
- offset: 0x00120000
+ name: "Boot PROM Filesystem",
}
};
@@ -58,12 +57,16 @@ int __init init_sharpsl(void)
int nb_parts = 0;
char *part_type = "static";
- printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);
+ printk(KERN_NOTICE "Sharp SL series flash device: %x at %x\n",
+ WINDOW_SIZE, WINDOW_ADDR);
sharpsl_map.virt = ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!sharpsl_map.virt) {
printk("Failed to ioremap\n");
return -EIO;
}
+
+ simple_map_init(&sharpsl_map);
+
mymtd = do_map_probe("map_rom", &sharpsl_map);
if (!mymtd) {
iounmap(sharpsl_map.virt);
@@ -72,6 +75,22 @@ int __init init_sharpsl(void)
mymtd->owner = THIS_MODULE;
+ if (machine_is_corgi() || machine_is_shepherd() || machine_is_husky()
+ || machine_is_poodle()) {
+ sharpsl_partitions[0].size=0x006d0000;
+ sharpsl_partitions[0].offset=0x00120000;
+ } else if (machine_is_tosa()) {
+ sharpsl_partitions[0].size=0x006a0000;
+ sharpsl_partitions[0].offset=0x00160000;
+ } else if (machine_is_spitz()) {
+ sharpsl_partitions[0].size=0x006b0000;
+ sharpsl_partitions[0].offset=0x00140000;
+ } else {
+ map_destroy(mymtd);
+ iounmap(sharpsl_map.virt);
+ return -ENODEV;
+ }
+
parts = sharpsl_partitions;
nb_parts = NB_OF(sharpsl_partitions);
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 510ad78312cc..1ed602a0f24c 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -1,5 +1,5 @@
/*
- * $Id: mtdchar.c,v 1.66 2005/01/05 18:05:11 dwmw2 Exp $
+ * $Id: mtdchar.c,v 1.73 2005/07/04 17:36:41 gleixner Exp $
*
* Character-device access to raw MTD devices.
*
@@ -15,27 +15,30 @@
#include <linux/fs.h>
#include <asm/uaccess.h>
-#ifdef CONFIG_DEVFS_FS
-#include <linux/devfs_fs_kernel.h>
+#include <linux/device.h>
+
+static struct class *mtd_class;
static void mtd_notify_add(struct mtd_info* mtd)
{
if (!mtd)
return;
- devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
- S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
-
- devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
- S_IFCHR | S_IRUGO, "mtd/%dro", mtd->index);
+ class_device_create(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+ NULL, "mtd%d", mtd->index);
+
+ class_device_create(mtd_class,
+ MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+ NULL, "mtd%dro", mtd->index);
}
static void mtd_notify_remove(struct mtd_info* mtd)
{
if (!mtd)
return;
- devfs_remove("mtd/%d", mtd->index);
- devfs_remove("mtd/%dro", mtd->index);
+
+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2));
+ class_device_destroy(mtd_class, MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1));
}
static struct mtd_notifier notifier = {
@@ -43,25 +46,25 @@ static struct mtd_notifier notifier = {
.remove = mtd_notify_remove,
};
-static inline void mtdchar_devfs_init(void)
-{
- devfs_mk_dir("mtd");
- register_mtd_user(&notifier);
-}
+/*
+ * We use file->private_data to store a pointer to the MTDdevice.
+ * Since alighment is at least 32 bits, we have 2 bits free for OTP
+ * modes as well.
+ */
-static inline void mtdchar_devfs_exit(void)
-{
- unregister_mtd_user(&notifier);
- devfs_remove("mtd");
-}
-#else /* !DEVFS */
-#define mtdchar_devfs_init() do { } while(0)
-#define mtdchar_devfs_exit() do { } while(0)
-#endif
+#define TO_MTD(file) (struct mtd_info *)((long)((file)->private_data) & ~3L)
+
+#define MTD_MODE_OTP_FACT 1
+#define MTD_MODE_OTP_USER 2
+#define MTD_MODE(file) ((long)((file)->private_data) & 3)
+
+#define SET_MTD_MODE(file, mode) \
+ do { long __p = (long)((file)->private_data); \
+ (file)->private_data = (void *)((__p & ~3L) | mode); } while (0)
static loff_t mtd_lseek (struct file *file, loff_t offset, int orig)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
switch (orig) {
case 0:
@@ -134,7 +137,7 @@ static int mtd_close(struct inode *inode, struct file *file)
DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
- mtd = file->private_data;
+ mtd = TO_MTD(file);
if (mtd->sync)
mtd->sync(mtd);
@@ -151,7 +154,7 @@ static int mtd_close(struct inode *inode, struct file *file)
static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
size_t retlen=0;
size_t total_retlen=0;
int ret=0;
@@ -178,7 +181,16 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
if (!kbuf)
return -ENOMEM;
- ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ ret = mtd->read_fact_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ case MTD_MODE_OTP_USER:
+ ret = mtd->read_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = MTD_READ(mtd, *ppos, len, &retlen, kbuf);
+ }
/* Nand returns -EBADMSG on ecc errors, but it returns
* the data. For our userspace tools it is important
* to dump areas with ecc errors !
@@ -196,6 +208,8 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
count -= retlen;
buf += retlen;
+ if (retlen == 0)
+ count = 0;
}
else {
kfree(kbuf);
@@ -210,7 +224,7 @@ static ssize_t mtd_read(struct file *file, char __user *buf, size_t count,loff_t
static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
char *kbuf;
size_t retlen;
size_t total_retlen=0;
@@ -245,7 +259,20 @@ static ssize_t mtd_write(struct file *file, const char __user *buf, size_t count
return -EFAULT;
}
- ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ ret = -EROFS;
+ break;
+ case MTD_MODE_OTP_USER:
+ if (!mtd->write_user_prot_reg) {
+ ret = -EOPNOTSUPP;
+ break;
+ }
+ ret = mtd->write_user_prot_reg(mtd, *ppos, len, &retlen, kbuf);
+ break;
+ default:
+ ret = (*(mtd->write))(mtd, *ppos, len, &retlen, kbuf);
+ }
if (!ret) {
*ppos += retlen;
total_retlen += retlen;
@@ -276,7 +303,7 @@ static void mtdchar_erase_callback (struct erase_info *instr)
static int mtd_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg)
{
- struct mtd_info *mtd = file->private_data;
+ struct mtd_info *mtd = TO_MTD(file);
void __user *argp = (void __user *)arg;
int ret = 0;
u_long size;
@@ -518,6 +545,80 @@ static int mtd_ioctl(struct inode *inode, struct file *file,
break;
}
+#ifdef CONFIG_MTD_OTP
+ case OTPSELECT:
+ {
+ int mode;
+ if (copy_from_user(&mode, argp, sizeof(int)))
+ return -EFAULT;
+ SET_MTD_MODE(file, 0);
+ switch (mode) {
+ case MTD_OTP_FACTORY:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ SET_MTD_MODE(file, MTD_MODE_OTP_FACT);
+ break;
+ case MTD_OTP_USER:
+ if (!mtd->read_fact_prot_reg)
+ ret = -EOPNOTSUPP;
+ else
+ SET_MTD_MODE(file, MTD_MODE_OTP_USER);
+ break;
+ default:
+ ret = -EINVAL;
+ case MTD_OTP_OFF:
+ break;
+ }
+ file->f_pos = 0;
+ break;
+ }
+
+ case OTPGETREGIONCOUNT:
+ case OTPGETREGIONINFO:
+ {
+ struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+ ret = -EOPNOTSUPP;
+ switch (MTD_MODE(file)) {
+ case MTD_MODE_OTP_FACT:
+ if (mtd->get_fact_prot_info)
+ ret = mtd->get_fact_prot_info(mtd, buf, 4096);
+ break;
+ case MTD_MODE_OTP_USER:
+ if (mtd->get_user_prot_info)
+ ret = mtd->get_user_prot_info(mtd, buf, 4096);
+ break;
+ }
+ if (ret >= 0) {
+ if (cmd == OTPGETREGIONCOUNT) {
+ int nbr = ret / sizeof(struct otp_info);
+ ret = copy_to_user(argp, &nbr, sizeof(int));
+ } else
+ ret = copy_to_user(argp, buf, ret);
+ if (ret)
+ ret = -EFAULT;
+ }
+ kfree(buf);
+ break;
+ }
+
+ case OTPLOCK:
+ {
+ struct otp_info info;
+
+ if (MTD_MODE(file) != MTD_MODE_OTP_USER)
+ return -EINVAL;
+ if (copy_from_user(&info, argp, sizeof(info)))
+ return -EFAULT;
+ if (!mtd->lock_user_prot_reg)
+ return -EOPNOTSUPP;
+ ret = mtd->lock_user_prot_reg(mtd, info.start, info.length);
+ break;
+ }
+#endif
+
default:
ret = -ENOTTY;
}
@@ -543,13 +644,22 @@ static int __init init_mtdchar(void)
return -EAGAIN;
}
- mtdchar_devfs_init();
+ mtd_class = class_create(THIS_MODULE, "mtd");
+
+ if (IS_ERR(mtd_class)) {
+ printk(KERN_ERR "Error creating mtd class.\n");
+ unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
+ return PTR_ERR(mtd_class);
+ }
+
+ register_mtd_user(&notifier);
return 0;
}
static void __exit cleanup_mtdchar(void)
{
- mtdchar_devfs_exit();
+ unregister_mtd_user(&notifier);
+ class_destroy(mtd_class);
unregister_chrdev(MTD_CHAR_MAJOR, "mtd");
}
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 9c0315d1b1c4..dc86df18e94b 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -1,5 +1,5 @@
/*
- * $Id: mtdcore.c,v 1.44 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdcore.c,v 1.45 2005/02/18 14:34:50 dedekind Exp $
*
* Core registration and callback routines for MTD
* drivers and users.
@@ -149,8 +149,8 @@ void register_mtd_user (struct mtd_notifier *new)
}
/**
- * register_mtd_user - unregister a 'user' of MTD devices.
- * @new: pointer to notifier info structure
+ * unregister_mtd_user - unregister a 'user' of MTD devices.
+ * @old: pointer to notifier info structure
*
* Removes a callback function pair from the list of 'users' to be
* notified upon addition or removal of MTD devices. Causes the
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index 96ebb52f24b1..b92e6bfffaf2 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -5,7 +5,7 @@
*
* This code is GPL
*
- * $Id: mtdpart.c,v 1.51 2004/11/16 18:28:59 dwmw2 Exp $
+ * $Id: mtdpart.c,v 1.53 2005/02/08 17:11:13 nico Exp $
*
* 02-21-2002 Thomas Gleixner <gleixner@autronix.de>
* added support for read_oob, write_oob
@@ -116,6 +116,13 @@ static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
len, retlen, buf);
}
+static int part_get_user_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_user_prot_info (part->master, buf, len);
+}
+
static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -124,6 +131,13 @@ static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t le
len, retlen, buf);
}
+static int part_get_fact_prot_info (struct mtd_info *mtd,
+ struct otp_info *buf, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->get_fact_prot_info (part->master, buf, len);
+}
+
static int part_write (struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
@@ -182,6 +196,12 @@ static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t l
len, retlen, buf);
}
+static int part_lock_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len)
+{
+ struct mtd_part *part = PART(mtd);
+ return part->master->lock_user_prot_reg (part->master, from, len);
+}
+
static int part_writev (struct mtd_info *mtd, const struct kvec *vecs,
unsigned long count, loff_t to, size_t *retlen)
{
@@ -409,6 +429,12 @@ int add_mtd_partitions(struct mtd_info *master,
slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg;
if(master->write_user_prot_reg)
slave->mtd.write_user_prot_reg = part_write_user_prot_reg;
+ if(master->lock_user_prot_reg)
+ slave->mtd.lock_user_prot_reg = part_lock_user_prot_reg;
+ if(master->get_user_prot_info)
+ slave->mtd.get_user_prot_info = part_get_user_prot_info;
+ if(master->get_fact_prot_info)
+ slave->mtd.get_fact_prot_info = part_get_fact_prot_info;
if (master->sync)
slave->mtd.sync = part_sync;
if (!i && master->suspend && master->resume) {
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index f7801eb730ce..36d34e5e5a5a 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -1,5 +1,5 @@
# drivers/mtd/nand/Kconfig
-# $Id: Kconfig,v 1.26 2005/01/05 12:42:24 dwmw2 Exp $
+# $Id: Kconfig,v 1.31 2005/06/20 12:03:21 bjd Exp $
menu "NAND Flash Device Drivers"
depends on MTD!=n
@@ -58,20 +58,6 @@ config MTD_NAND_TOTO
config MTD_NAND_IDS
tristate
-config MTD_NAND_TX4925NDFMC
- tristate "SmartMedia Card on Toshiba RBTX4925 reference board"
- depends on TOSHIBA_RBTX4925 && MTD_NAND && TOSHIBA_RBTX4925_MPLEX_NAND
- help
- This enables the driver for the NAND flash device found on the
- Toshiba RBTX4925 reference board, which is a SmartMediaCard.
-
-config MTD_NAND_TX4938NDFMC
- tristate "NAND Flash device on Toshiba RBTX4938 reference board"
- depends on TOSHIBA_RBTX4938 && MTD_NAND && TOSHIBA_RBTX4938_MPLEX_NAND
- help
- This enables the driver for the NAND flash device found on the
- Toshiba RBTX4938 reference board.
-
config MTD_NAND_AU1550
tristate "Au1550 NAND support"
depends on SOC_AU1550 && MTD_NAND
@@ -95,10 +81,11 @@ config MTD_NAND_PPCHAMELEONEVB
This enables the NAND flash driver on the PPChameleon EVB Board.
config MTD_NAND_S3C2410
- tristate "NAND Flash support for S3C2410 SoC"
+ tristate "NAND Flash support for S3C2410/S3C2440 SoC"
depends on ARCH_S3C2410 && MTD_NAND
help
- This enables the NAND flash controller on the S3C2410.
+ This enables the NAND flash controller on the S3C2410 and S3C2440
+ SoCs
No board specfic support is done by this driver, each board
must advertise a platform_device for the driver to attach.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index d9dc8cc2da8c..41742026a52e 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -10,8 +10,6 @@ obj-$(CONFIG_MTD_NAND_SPIA) += spia.o
obj-$(CONFIG_MTD_NAND_TOTO) += toto.o
obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o
obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o
-obj-$(CONFIG_MTD_NAND_TX4925NDFMC) += tx4925ndfmc.o
-obj-$(CONFIG_MTD_NAND_TX4938NDFMC) += tx4938ndfmc.o
obj-$(CONFIG_MTD_NAND_AU1550) += au1550nd.o
obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB) += ppchameleonevb.o
obj-$(CONFIG_MTD_NAND_S3C2410) += s3c2410.o
diff --git a/drivers/mtd/nand/diskonchip.c b/drivers/mtd/nand/diskonchip.c
index 02135c3ac29a..fdb5d4ad3d52 100644
--- a/drivers/mtd/nand/diskonchip.c
+++ b/drivers/mtd/nand/diskonchip.c
@@ -16,7 +16,7 @@
*
* Interface to generic NAND code for M-Systems DiskOnChip devices
*
- * $Id: diskonchip.c,v 1.45 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: diskonchip.c,v 1.54 2005/04/07 14:22:55 dbrown Exp $
*/
#include <linux/kernel.h>
@@ -35,13 +35,13 @@
#include <linux/mtd/inftl.h>
/* Where to look for the devices? */
-#ifndef CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS
-#define CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS 0
+#ifndef CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS
+#define CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS 0
#endif
static unsigned long __initdata doc_locations[] = {
#if defined (__alpha__) || defined(__i386__) || defined(__x86_64__)
-#ifdef CONFIG_MTD_DISKONCHIP_PROBE_HIGH
+#ifdef CONFIG_MTD_NAND_DISKONCHIP_PROBE_HIGH
0xfffc8000, 0xfffca000, 0xfffcc000, 0xfffce000,
0xfffd0000, 0xfffd2000, 0xfffd4000, 0xfffd6000,
0xfffd8000, 0xfffda000, 0xfffdc000, 0xfffde000,
@@ -81,11 +81,6 @@ struct doc_priv {
struct mtd_info *nextdoc;
};
-/* Max number of eraseblocks to scan (from start of device) for the (I)NFTL
- MediaHeader. The spec says to just keep going, I think, but that's just
- silly. */
-#define MAX_MEDIAHEADER_SCAN 8
-
/* This is the syndrome computed by the HW ecc generator upon reading an empty
page, one with all 0xff for data and stored ecc code. */
static u_char empty_read_syndrome[6] = { 0x26, 0xff, 0x6d, 0x47, 0x73, 0x7a };
@@ -111,10 +106,11 @@ module_param(try_dword, int, 0);
static int no_ecc_failures=0;
module_param(no_ecc_failures, int, 0);
-#ifdef CONFIG_MTD_PARTITIONS
static int no_autopart=0;
module_param(no_autopart, int, 0);
-#endif
+
+static int show_firmware_partition=0;
+module_param(show_firmware_partition, int, 0);
#ifdef MTD_NAND_DISKONCHIP_BBTWRITE
static int inftl_bbt_write=1;
@@ -123,7 +119,7 @@ static int inftl_bbt_write=0;
#endif
module_param(inftl_bbt_write, int, 0);
-static unsigned long doc_config_location = CONFIG_MTD_DISKONCHIP_PROBE_ADDRESS;
+static unsigned long doc_config_location = CONFIG_MTD_NAND_DISKONCHIP_PROBE_ADDRESS;
module_param(doc_config_location, ulong, 0);
MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip");
@@ -410,7 +406,12 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
doc200x_hwcontrol(mtd, NAND_CTL_SETALE);
this->write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
-
+
+ /* We cant' use dev_ready here, but at least we wait for the
+ * command to complete
+ */
+ udelay(50);
+
ret = this->read_byte(mtd) << 8;
ret |= this->read_byte(mtd);
@@ -429,6 +430,8 @@ static uint16_t __init doc200x_ident_chip(struct mtd_info *mtd, int nr)
doc2000_write_byte(mtd, 0);
doc200x_hwcontrol(mtd, NAND_CTL_CLRALE);
+ udelay(50);
+
ident.dword = readl(docptr + DoC_2k_CDSN_IO);
if (((ident.byte[0] << 8) | ident.byte[1]) == ret) {
printk(KERN_INFO "DiskOnChip 2000 responds to DWORD access\n");
@@ -1046,11 +1049,21 @@ static int doc200x_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_
//u_char mydatabuf[528];
+/* The strange out-of-order .oobfree list below is a (possibly unneeded)
+ * attempt to retain compatibility. It used to read:
+ * .oobfree = { {8, 8} }
+ * Since that leaves two bytes unusable, it was changed. But the following
+ * scheme might affect existing jffs2 installs by moving the cleanmarker:
+ * .oobfree = { {6, 10} }
+ * jffs2 seems to handle the above gracefully, but the current scheme seems
+ * safer. The only problem with it is that any code that parses oobfree must
+ * be able to handle out-of-order segments.
+ */
static struct nand_oobinfo doc200x_oobinfo = {
.useecc = MTD_NANDECC_AUTOPLACE,
.eccbytes = 6,
.eccpos = {0, 1, 2, 3, 4, 5},
- .oobfree = { {8, 8} }
+ .oobfree = { {8, 8}, {6, 2} }
};
/* Find the (I)NFTL Media Header, and optionally also the mirror media header.
@@ -1064,12 +1077,11 @@ static int __init find_media_headers(struct mtd_info *mtd, u_char *buf,
{
struct nand_chip *this = mtd->priv;
struct doc_priv *doc = this->priv;
- unsigned offs, end = (MAX_MEDIAHEADER_SCAN << this->phys_erase_shift);
+ unsigned offs;
int ret;
size_t retlen;
- end = min(end, mtd->size); // paranoia
- for (offs = 0; offs < end; offs += mtd->erasesize) {
+ for (offs = 0; offs < mtd->size; offs += mtd->erasesize) {
ret = mtd->read(mtd, offs, mtd->oobblock, &retlen, buf);
if (retlen != mtd->oobblock) continue;
if (ret) {
@@ -1111,6 +1123,7 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
u_char *buf;
struct NFTLMediaHeader *mh;
const unsigned psize = 1 << this->page_shift;
+ int numparts = 0;
unsigned blocks, maxblocks;
int offs, numheaders;
@@ -1122,8 +1135,10 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
if (!(numheaders=find_media_headers(mtd, buf, "ANAND", 1))) goto out;
mh = (struct NFTLMediaHeader *) buf;
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
+ mh->NumEraseUnits = le16_to_cpu(mh->NumEraseUnits);
+ mh->FirstPhysicalEUN = le16_to_cpu(mh->FirstPhysicalEUN);
+ mh->FormattedSize = le32_to_cpu(mh->FormattedSize);
+
printk(KERN_INFO " DataOrgID = %s\n"
" NumEraseUnits = %d\n"
" FirstPhysicalEUN = %d\n"
@@ -1132,7 +1147,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
mh->DataOrgID, mh->NumEraseUnits,
mh->FirstPhysicalEUN, mh->FormattedSize,
mh->UnitSizeFactor);
-//#endif
blocks = mtd->size >> this->phys_erase_shift;
maxblocks = min(32768U, mtd->erasesize - psize);
@@ -1175,23 +1189,28 @@ static inline int __init nftl_partscan(struct mtd_info *mtd,
offs <<= this->page_shift;
offs += mtd->erasesize;
- //parts[0].name = " DiskOnChip Boot / Media Header partition";
- //parts[0].offset = 0;
- //parts[0].size = offs;
+ if (show_firmware_partition == 1) {
+ parts[0].name = " DiskOnChip Firmware / Media Header partition";
+ parts[0].offset = 0;
+ parts[0].size = offs;
+ numparts = 1;
+ }
- parts[0].name = " DiskOnChip BDTL partition";
- parts[0].offset = offs;
- parts[0].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+ parts[numparts].name = " DiskOnChip BDTL partition";
+ parts[numparts].offset = offs;
+ parts[numparts].size = (mh->NumEraseUnits - numheaders) << this->bbt_erase_shift;
+
+ offs += parts[numparts].size;
+ numparts++;
- offs += parts[0].size;
if (offs < mtd->size) {
- parts[1].name = " DiskOnChip Remainder partition";
- parts[1].offset = offs;
- parts[1].size = mtd->size - offs;
- ret = 2;
- goto out;
+ parts[numparts].name = " DiskOnChip Remainder partition";
+ parts[numparts].offset = offs;
+ parts[numparts].size = mtd->size - offs;
+ numparts++;
}
- ret = 1;
+
+ ret = numparts;
out:
kfree(buf);
return ret;
@@ -1233,8 +1252,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
mh->FormatFlags = le32_to_cpu(mh->FormatFlags);
mh->PercentUsed = le32_to_cpu(mh->PercentUsed);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " bootRecordID = %s\n"
" NoOfBootImageBlocks = %d\n"
" NoOfBinaryPartitions = %d\n"
@@ -1252,7 +1269,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
((unsigned char *) &mh->OsakVersion)[2] & 0xf,
((unsigned char *) &mh->OsakVersion)[3] & 0xf,
mh->PercentUsed);
-//#endif
vshift = this->phys_erase_shift + mh->BlockMultiplierBits;
@@ -1278,8 +1294,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
ip->spareUnits = le32_to_cpu(ip->spareUnits);
ip->Reserved0 = le32_to_cpu(ip->Reserved0);
-//#ifdef CONFIG_MTD_DEBUG_VERBOSE
-// if (CONFIG_MTD_DEBUG_VERBOSE >= 2)
printk(KERN_INFO " PARTITION[%d] ->\n"
" virtualUnits = %d\n"
" firstUnit = %d\n"
@@ -1289,16 +1303,14 @@ static inline int __init inftl_partscan(struct mtd_info *mtd,
i, ip->virtualUnits, ip->firstUnit,
ip->lastUnit, ip->flags,
ip->spareUnits);
-//#endif
-/*
- if ((i == 0) && (ip->firstUnit > 0)) {
+ if ((show_firmware_partition == 1) &&
+ (i == 0) && (ip->firstUnit > 0)) {
parts[0].name = " DiskOnChip IPL / Media Header partition";
parts[0].offset = 0;
parts[0].size = mtd->erasesize * ip->firstUnit;
numparts = 1;
}
-*/
if (ip->flags & INFTL_BINARY)
parts[numparts].name = " DiskOnChip BDK partition";
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 44d5b128911f..1bd71a598c79 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -28,6 +28,24 @@
* among multiple independend devices. Suggestions and initial patch
* from Ben Dooks <ben-mtd@fluff.org>
*
+ * 12-05-2004 dmarlin: add workaround for Renesas AG-AND chips "disturb" issue.
+ * Basically, any block not rewritten may lose data when surrounding blocks
+ * are rewritten many times. JFFS2 ensures this doesn't happen for blocks
+ * it uses, but the Bad Block Table(s) may not be rewritten. To ensure they
+ * do not lose data, force them to be rewritten when some of the surrounding
+ * blocks are erased. Rather than tracking a specific nearby block (which
+ * could itself go bad), use a page address 'mask' to select several blocks
+ * in the same area, and rewrite the BBT when any of them are erased.
+ *
+ * 01-03-2005 dmarlin: added support for the device recovery command sequence for Renesas
+ * AG-AND chips. If there was a sudden loss of power during an erase operation,
+ * a "device recovery" operation must be performed when power is restored
+ * to ensure correct operation.
+ *
+ * 01-20-2005 dmarlin: added support for optional hardware specific callback routine to
+ * perform extra error status checks on erase and write failures. This required
+ * adding a wrapper function for nand_read_ecc.
+ *
* Credits:
* David Woodhouse for adding multichip support
*
@@ -41,7 +59,7 @@
* The AG-AND chips have nice features for speed improvement,
* which are not supported yet. Read / program 4 pages in one go.
*
- * $Id: nand_base.c,v 1.126 2004/12/13 11:22:25 lavinen Exp $
+ * $Id: nand_base.c,v 1.146 2005/06/17 15:02:06 gleixner Exp $
*
* 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
@@ -149,17 +167,21 @@ static void nand_release_device (struct mtd_info *mtd)
/* De-select the NAND device */
this->select_chip(mtd, -1);
- /* Do we have a hardware controller ? */
+
if (this->controller) {
+ /* Release the controller and the chip */
spin_lock(&this->controller->lock);
this->controller->active = NULL;
+ this->state = FL_READY;
+ wake_up(&this->controller->wq);
spin_unlock(&this->controller->lock);
+ } else {
+ /* Release the chip */
+ spin_lock(&this->chip_lock);
+ this->state = FL_READY;
+ wake_up(&this->wq);
+ spin_unlock(&this->chip_lock);
}
- /* Release the chip */
- spin_lock (&this->chip_lock);
- this->state = FL_READY;
- wake_up (&this->wq);
- spin_unlock (&this->chip_lock);
}
/**
@@ -443,7 +465,8 @@ static int nand_default_block_markbad(struct mtd_info *mtd, loff_t ofs)
/* Get block number */
block = ((int) ofs) >> this->bbt_erase_shift;
- this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
+ if (this->bbt)
+ this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
/* Do we have a flash based bad block table ? */
if (this->options & NAND_USE_FLASH_BBT)
@@ -466,7 +489,7 @@ static int nand_check_wp (struct mtd_info *mtd)
struct nand_chip *this = mtd->priv;
/* Check the WP bit */
this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1);
- return (this->read_byte(mtd) & 0x80) ? 0 : 1;
+ return (this->read_byte(mtd) & NAND_STATUS_WP) ? 0 : 1;
}
/**
@@ -490,6 +513,22 @@ static int nand_block_checkbad (struct mtd_info *mtd, loff_t ofs, int getchip, i
return nand_isbad_bbt (mtd, ofs, allowbbt);
}
+/*
+ * Wait for the ready pin, after a command
+ * The timeout is catched later.
+ */
+static void nand_wait_ready(struct mtd_info *mtd)
+{
+ struct nand_chip *this = mtd->priv;
+ unsigned long timeo = jiffies + 2;
+
+ /* wait until command is processed or timeout occures */
+ do {
+ if (this->dev_ready(mtd))
+ return;
+ } while (time_before(jiffies, timeo));
+}
+
/**
* nand_command - [DEFAULT] Send command to NAND device
* @mtd: MTD device structure
@@ -571,7 +610,7 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
/* This applies to read commands */
@@ -585,12 +624,11 @@ static void nand_command (struct mtd_info *mtd, unsigned command, int column, in
return;
}
}
-
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
+
+ nand_wait_ready(mtd);
}
/**
@@ -619,7 +657,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
/* Begin command latch cycle */
this->hwcontrol(mtd, NAND_CTL_SETCLE);
/* Write out the command to the device. */
- this->write_byte(mtd, command);
+ this->write_byte(mtd, (command & 0xff));
/* End command latch cycle */
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
@@ -647,8 +685,8 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
/*
* program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
+ * status, sequential in, and deplete1 need no delay
+ */
switch (command) {
case NAND_CMD_CACHEDPROG:
@@ -657,8 +695,19 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
case NAND_CMD_ERASE2:
case NAND_CMD_SEQIN:
case NAND_CMD_STATUS:
+ case NAND_CMD_DEPLETE1:
return;
+ /*
+ * read error status commands require only a short delay
+ */
+ case NAND_CMD_STATUS_ERROR:
+ case NAND_CMD_STATUS_ERROR0:
+ case NAND_CMD_STATUS_ERROR1:
+ case NAND_CMD_STATUS_ERROR2:
+ case NAND_CMD_STATUS_ERROR3:
+ udelay(this->chip_delay);
+ return;
case NAND_CMD_RESET:
if (this->dev_ready)
@@ -667,7 +716,7 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
this->hwcontrol(mtd, NAND_CTL_SETCLE);
this->write_byte(mtd, NAND_CMD_STATUS);
this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
+ while ( !(this->read_byte(mtd) & NAND_STATUS_READY));
return;
case NAND_CMD_READ0:
@@ -690,12 +739,12 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
return;
}
}
-
+
/* Apply this short delay always to ensure that we do wait tWB in
* any case on any machine. */
ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
+
+ nand_wait_ready(mtd);
}
/**
@@ -708,37 +757,34 @@ static void nand_command_lp (struct mtd_info *mtd, unsigned command, int column,
*/
static void nand_get_device (struct nand_chip *this, struct mtd_info *mtd, int new_state)
{
- struct nand_chip *active = this;
-
+ struct nand_chip *active;
+ spinlock_t *lock;
+ wait_queue_head_t *wq;
DECLARE_WAITQUEUE (wait, current);
- /*
- * Grab the lock and see if the device is available
- */
+ lock = (this->controller) ? &this->controller->lock : &this->chip_lock;
+ wq = (this->controller) ? &this->controller->wq : &this->wq;
retry:
+ active = this;
+ spin_lock(lock);
+
/* Hardware controller shared among independend devices */
if (this->controller) {
- spin_lock (&this->controller->lock);
if (this->controller->active)
active = this->controller->active;
else
this->controller->active = this;
- spin_unlock (&this->controller->lock);
}
-
- if (active == this) {
- spin_lock (&this->chip_lock);
- if (this->state == FL_READY) {
- this->state = new_state;
- spin_unlock (&this->chip_lock);
- return;
- }
- }
- set_current_state (TASK_UNINTERRUPTIBLE);
- add_wait_queue (&active->wq, &wait);
- spin_unlock (&active->chip_lock);
- schedule ();
- remove_wait_queue (&active->wq, &wait);
+ if (active == this && this->state == FL_READY) {
+ this->state = new_state;
+ spin_unlock(lock);
+ return;
+ }
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(wq, &wait);
+ spin_unlock(lock);
+ schedule();
+ remove_wait_queue(wq, &wait);
goto retry;
}
@@ -785,7 +831,7 @@ static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state)
if (this->read_byte(mtd) & NAND_STATUS_READY)
break;
}
- yield ();
+ cond_resched();
}
status = (int) this->read_byte(mtd);
return status;
@@ -871,8 +917,14 @@ static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int pa
if (!cached) {
/* call wait ready function */
status = this->waitfunc (mtd, this, FL_WRITING);
+
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_WRITING, status, page);
+ }
+
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page);
return -EIO;
}
@@ -975,7 +1027,7 @@ static int nand_verify_pages (struct mtd_info *mtd, struct nand_chip *this, int
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* All done, return happy */
if (!numpages)
@@ -997,23 +1049,24 @@ out:
#endif
/**
- * nand_read - [MTD Interface] MTD compability function for nand_read_ecc
+ * nand_read - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
* @retlen: pointer to variable to store the number of read bytes
* @buf: the databuffer to put data
*
- * This function simply calls nand_read_ecc with oob buffer and oobsel = NULL
-*/
+ * This function simply calls nand_do_read_ecc with oob buffer and oobsel = NULL
+ * and flags = 0xff
+ */
static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf)
{
- return nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL);
-}
+ return nand_do_read_ecc (mtd, from, len, retlen, buf, NULL, &mtd->oobinfo, 0xff);
+}
/**
- * nand_read_ecc - [MTD Interface] Read data with ECC
+ * nand_read_ecc - [MTD Interface] MTD compability function for nand_do_read_ecc
* @mtd: MTD device structure
* @from: offset to read from
* @len: number of bytes to read
@@ -1022,11 +1075,39 @@ static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * re
* @oob_buf: filesystem supplied oob data buffer
* @oobsel: oob selection structure
*
- * NAND read with ECC
+ * This function simply calls nand_do_read_ecc with flags = 0xff
*/
static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel)
{
+ /* use userspace supplied oobinfo, if zero */
+ if (oobsel == NULL)
+ oobsel = &mtd->oobinfo;
+ return nand_do_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel, 0xff);
+}
+
+
+/**
+ * nand_do_read_ecc - [MTD Interface] Read data with ECC
+ * @mtd: MTD device structure
+ * @from: offset to read from
+ * @len: number of bytes to read
+ * @retlen: pointer to variable to store the number of read bytes
+ * @buf: the databuffer to put data
+ * @oob_buf: filesystem supplied oob data buffer (can be NULL)
+ * @oobsel: oob selection structure
+ * @flags: flag to indicate if nand_get_device/nand_release_device should be preformed
+ * and how many corrected error bits are acceptable:
+ * bits 0..7 - number of tolerable errors
+ * bit 8 - 0 == do not get/release chip, 1 == get/release chip
+ *
+ * NAND read with ECC
+ */
+int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags)
+{
+
int i, j, col, realpage, page, end, ecc, chipnr, sndcmd = 1;
int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0;
struct nand_chip *this = mtd->priv;
@@ -1051,12 +1132,9 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Grab the lock and see if the device is available */
- nand_get_device (this, mtd ,FL_READING);
+ if (flags & NAND_GET_DEVICE)
+ nand_get_device (this, mtd, FL_READING);
- /* use userspace supplied oobinfo, if zero */
- if (oobsel == NULL)
- oobsel = &mtd->oobinfo;
-
/* Autoplace of oob data ? Use the default placement scheme */
if (oobsel->useecc == MTD_NANDECC_AUTOPLACE)
oobsel = this->autooob;
@@ -1118,7 +1196,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* get oob area, if we have no oob buffer from fs-driver */
- if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE)
+ if (!oob_buf || oobsel->useecc == MTD_NANDECC_AUTOPLACE ||
+ oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
oob_data = &this->data_buf[end];
eccsteps = this->eccsteps;
@@ -1155,7 +1234,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* We calc error correction directly, it checks the hw
* generator for an error, reads back the syndrome and
* does the error correction on the fly */
- if (this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]) == -1) {
+ ecc_status = this->correct_data(mtd, &data_poi[datidx], &oob_data[i], &ecc_code[i]);
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: "
"Failed ECC read, page 0x%08x on chip %d\n", page, chipnr);
ecc_failed++;
@@ -1194,7 +1274,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
p[i] = ecc_status;
}
- if (ecc_status == -1) {
+ if ((ecc_status == -1) || (ecc_status > (flags && 0xff))) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page);
ecc_failed++;
}
@@ -1206,14 +1286,14 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
/* without autoplace. Legacy mode used by YAFFS1 */
switch(oobsel->useecc) {
case MTD_NANDECC_AUTOPLACE:
+ case MTD_NANDECC_AUTOPL_USR:
/* Walk through the autoplace chunks */
- for (i = 0, j = 0; j < mtd->oobavail; i++) {
+ for (i = 0; oobsel->oobfree[i][1]; i++) {
int from = oobsel->oobfree[i][0];
int num = oobsel->oobfree[i][1];
memcpy(&oob_buf[oob], &oob_data[from], num);
- j+= num;
+ oob += num;
}
- oob += mtd->oobavail;
break;
case MTD_NANDECC_PLACE:
/* YAFFS1 legacy mode */
@@ -1239,7 +1319,7 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
if (read == len)
break;
@@ -1264,7 +1344,8 @@ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
}
/* Deselect and wake up anyone waiting on the device */
- nand_release_device(mtd);
+ if (flags & NAND_GET_DEVICE)
+ nand_release_device(mtd);
/*
* Return success, if no ECC failures, else -EBADMSG
@@ -1337,7 +1418,7 @@ static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* Read more ? */
if (i < len) {
@@ -1417,7 +1498,7 @@ int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_t len,
if (!this->dev_ready)
udelay (this->chip_delay);
else
- while (!this->dev_ready(mtd));
+ nand_wait_ready(mtd);
/* Check, if the chip supports auto page increment */
if (!NAND_CANAUTOINCR(this) || !(page & blockcheck))
@@ -1567,6 +1648,8 @@ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len,
oobsel = this->autooob;
autoplace = 1;
}
+ if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+ autoplace = 1;
/* Setup variables and oob buffer */
totalpages = len >> this->page_shift;
@@ -1733,7 +1816,7 @@ static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t *
status = this->waitfunc (mtd, this, FL_WRITING);
/* See if device thinks it succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page);
ret = -EIO;
goto out;
@@ -1841,6 +1924,8 @@ static int nand_writev_ecc (struct mtd_info *mtd, const struct kvec *vecs, unsig
oobsel = this->autooob;
autoplace = 1;
}
+ if (oobsel->useecc == MTD_NANDECC_AUTOPL_USR)
+ autoplace = 1;
/* Setup start page */
page = (int) (to >> this->page_shift);
@@ -1987,6 +2072,7 @@ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr)
return nand_erase_nand (mtd, instr, 0);
}
+#define BBT_PAGE_MASK 0xffffff3f
/**
* nand_erase_intern - [NAND Interface] erase block(s)
* @mtd: MTD device structure
@@ -1999,6 +2085,10 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
{
int page, len, status, pages_per_block, ret, chipnr;
struct nand_chip *this = mtd->priv;
+ int rewrite_bbt[NAND_MAX_CHIPS]={0}; /* flags to indicate the page, if bbt needs to be rewritten. */
+ unsigned int bbt_masked_page; /* bbt mask to compare to page being erased. */
+ /* It is used to see if the current page is in the same */
+ /* 256 block group and the same bank as the bbt. */
DEBUG (MTD_DEBUG_LEVEL3,
"nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len);
@@ -2044,6 +2134,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
goto erase_exit;
}
+ /* if BBT requires refresh, set the BBT page mask to see if the BBT should be rewritten */
+ if (this->options & BBT_AUTO_REFRESH) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ } else {
+ bbt_masked_page = 0xffffffff; /* should not match anything */
+ }
+
/* Loop through the pages */
len = instr->len;
@@ -2066,13 +2163,26 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
status = this->waitfunc (mtd, this, FL_ERASING);
+ /* See if operation failed and additional status checks are available */
+ if ((status & NAND_STATUS_FAIL) && (this->errstat)) {
+ status = this->errstat(mtd, this, FL_ERASING, status, page);
+ }
+
/* See if block erase succeeded */
- if (status & 0x01) {
+ if (status & NAND_STATUS_FAIL) {
DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
instr->state = MTD_ERASE_FAILED;
instr->fail_addr = (page << this->page_shift);
goto erase_exit;
}
+
+ /* if BBT requires refresh, set the BBT rewrite flag to the page being erased */
+ if (this->options & BBT_AUTO_REFRESH) {
+ if (((page & BBT_PAGE_MASK) == bbt_masked_page) &&
+ (page != this->bbt_td->pages[chipnr])) {
+ rewrite_bbt[chipnr] = (page << this->page_shift);
+ }
+ }
/* Increment page address and decrement length */
len -= (1 << this->phys_erase_shift);
@@ -2083,6 +2193,13 @@ int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbb
chipnr++;
this->select_chip(mtd, -1);
this->select_chip(mtd, chipnr);
+
+ /* if BBT requires refresh and BBT-PERCHIP,
+ * set the BBT page mask to see if this BBT should be rewritten */
+ if ((this->options & BBT_AUTO_REFRESH) && (this->bbt_td->options & NAND_BBT_PERCHIP)) {
+ bbt_masked_page = this->bbt_td->pages[chipnr] & BBT_PAGE_MASK;
+ }
+
}
}
instr->state = MTD_ERASE_DONE;
@@ -2097,6 +2214,18 @@ erase_exit:
/* Deselect and wake up anyone waiting on the device */
nand_release_device(mtd);
+ /* if BBT requires refresh and erase was successful, rewrite any selected bad block tables */
+ if ((this->options & BBT_AUTO_REFRESH) && (!ret)) {
+ for (chipnr = 0; chipnr < this->numchips; chipnr++) {
+ if (rewrite_bbt[chipnr]) {
+ /* update the BBT for chip */
+ DEBUG (MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
+ chipnr, rewrite_bbt[chipnr], this->bbt_td->pages[chipnr]);
+ nand_update_bbt (mtd, rewrite_bbt[chipnr]);
+ }
+ }
+ }
+
/* Return more or less happy */
return ret;
}
@@ -2168,7 +2297,7 @@ static int nand_block_markbad (struct mtd_info *mtd, loff_t ofs)
*/
int nand_scan (struct mtd_info *mtd, int maxchips)
{
- int i, j, nand_maf_id, nand_dev_id, busw;
+ int i, nand_maf_id, nand_dev_id, busw, maf_id;
struct nand_chip *this = mtd->priv;
/* Get buswidth to select the correct functions*/
@@ -2256,12 +2385,18 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
busw = nand_flash_ids[i].options & NAND_BUSWIDTH_16;
}
+ /* Try to identify manufacturer */
+ for (maf_id = 0; nand_manuf_ids[maf_id].id != 0x0; maf_id++) {
+ if (nand_manuf_ids[maf_id].id == nand_maf_id)
+ break;
+ }
+
/* Check, if buswidth is correct. Hardware drivers should set
* this correct ! */
if (busw != (this->options & NAND_BUSWIDTH_16)) {
printk (KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[i].name , mtd->name);
+ nand_manuf_ids[maf_id].name , mtd->name);
printk (KERN_WARNING
"NAND bus width %d instead %d bit\n",
(this->options & NAND_BUSWIDTH_16) ? 16 : 8,
@@ -2300,14 +2435,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
if (mtd->oobblock > 512 && this->cmdfunc == nand_command)
this->cmdfunc = nand_command_lp;
- /* Try to identify manufacturer */
- for (j = 0; nand_manuf_ids[j].id != 0x0; j++) {
- if (nand_manuf_ids[j].id == nand_maf_id)
- break;
- }
printk (KERN_INFO "NAND device: Manufacturer ID:"
" 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id,
- nand_manuf_ids[j].name , nand_flash_ids[i].name);
+ nand_manuf_ids[maf_id].name , nand_flash_ids[i].name);
break;
}
@@ -2388,12 +2518,9 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
/* The number of bytes available for the filesystem to place fs dependend
* oob data */
- if (this->options & NAND_BUSWIDTH_16) {
- mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 2);
- if (this->autooob->eccbytes & 0x01)
- mtd->oobavail--;
- } else
- mtd->oobavail = mtd->oobsize - (this->autooob->eccbytes + 1);
+ mtd->oobavail = 0;
+ for (i = 0; this->autooob->oobfree[i][1]; i++)
+ mtd->oobavail += this->autooob->oobfree[i][1];
/*
* check ECC mode, default to software
@@ -2524,6 +2651,10 @@ int nand_scan (struct mtd_info *mtd, int maxchips)
memcpy(&mtd->oobinfo, this->autooob, sizeof(mtd->oobinfo));
mtd->owner = THIS_MODULE;
+
+ /* Check, if we should skip the bad block table scan */
+ if (this->options & NAND_SKIP_BBTSCAN)
+ return 0;
/* Build bad block table */
return this->scan_bbt (mtd);
@@ -2555,8 +2686,8 @@ void nand_release (struct mtd_info *mtd)
kfree (this->data_buf);
}
-EXPORT_SYMBOL (nand_scan);
-EXPORT_SYMBOL (nand_release);
+EXPORT_SYMBOL_GPL (nand_scan);
+EXPORT_SYMBOL_GPL (nand_release);
MODULE_LICENSE ("GPL");
MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>");
diff --git a/drivers/mtd/nand/nand_bbt.c b/drivers/mtd/nand/nand_bbt.c
index 9a1949751c1f..5ac2d2962220 100644
--- a/drivers/mtd/nand/nand_bbt.c
+++ b/drivers/mtd/nand/nand_bbt.c
@@ -6,7 +6,7 @@
*
* Copyright (C) 2004 Thomas Gleixner (tglx@linutronix.de)
*
- * $Id: nand_bbt.c,v 1.28 2004/11/13 10:19:09 gleixner Exp $
+ * $Id: nand_bbt.c,v 1.33 2005/06/14 15:47:56 gleixner Exp $
*
* 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
@@ -77,7 +77,7 @@
*/
static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
{
- int i, end;
+ int i, end = 0;
uint8_t *p = buf;
end = paglen + td->offs;
@@ -95,9 +95,9 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
return -1;
}
- p += td->len;
- end += td->len;
if (td->options & NAND_BBT_SCANEMPTY) {
+ p += td->len;
+ end += td->len;
for (i = end; i < len; i++) {
if (*p++ != 0xff)
return -1;
@@ -106,6 +106,32 @@ static int check_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_des
return 0;
}
+/**
+ * check_short_pattern - [GENERIC] check if a pattern is in the buffer
+ * @buf: the buffer to search
+ * @len: the length of buffer to search
+ * @paglen: the pagelength
+ * @td: search pattern descriptor
+ *
+ * Check for a pattern at the given place. Used to search bad block
+ * tables and good / bad block identifiers. Same as check_pattern, but
+ * no optional empty check and the pattern is expected to start
+ * at offset 0.
+ *
+*/
+static int check_short_pattern (uint8_t *buf, int len, int paglen, struct nand_bbt_descr *td)
+{
+ int i;
+ uint8_t *p = buf;
+
+ /* Compare the pattern */
+ for (i = 0; i < td->len; i++) {
+ if (p[i] != td->pattern[i])
+ return -1;
+ }
+ return 0;
+}
+
/**
* read_bbt - [GENERIC] Read the bad block table starting from page
* @mtd: MTD device structure
@@ -252,7 +278,7 @@ static int read_abs_bbts (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_de
* Create a bad block table by scanning the device
* for the given good/bad block identify pattern
*/
-static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
+static int create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_descr *bd, int chip)
{
struct nand_chip *this = mtd->priv;
int i, j, numblocks, len, scanlen;
@@ -270,9 +296,17 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
else
len = 1;
}
- scanlen = mtd->oobblock + mtd->oobsize;
- readlen = len * mtd->oobblock;
- ooblen = len * mtd->oobsize;
+
+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+ /* We need only read few bytes from the OOB area */
+ scanlen = ooblen = 0;
+ readlen = bd->len;
+ } else {
+ /* Full page content should be read */
+ scanlen = mtd->oobblock + mtd->oobsize;
+ readlen = len * mtd->oobblock;
+ ooblen = len * mtd->oobsize;
+ }
if (chip == -1) {
/* Note that numblocks is 2 * (real numblocks) here, see i+=2 below as it
@@ -284,7 +318,7 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
if (chip >= this->numchips) {
printk (KERN_WARNING "create_bbt(): chipnr (%d) > available chips (%d)\n",
chip + 1, this->numchips);
- return;
+ return -EINVAL;
}
numblocks = this->chipsize >> (this->bbt_erase_shift - 1);
startblock = chip * numblocks;
@@ -293,18 +327,41 @@ static void create_bbt (struct mtd_info *mtd, uint8_t *buf, struct nand_bbt_desc
}
for (i = startblock; i < numblocks;) {
- nand_read_raw (mtd, buf, from, readlen, ooblen);
+ int ret;
+
+ if (bd->options & NAND_BBT_SCANEMPTY)
+ if ((ret = nand_read_raw (mtd, buf, from, readlen, ooblen)))
+ return ret;
+
for (j = 0; j < len; j++) {
- if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
- this->bbt[i >> 3] |= 0x03 << (i & 0x6);
- printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
- i >> 1, (unsigned int) from);
- break;
+ if (!(bd->options & NAND_BBT_SCANEMPTY)) {
+ size_t retlen;
+
+ /* No need to read pages fully, just read required OOB bytes */
+ ret = mtd->read_oob(mtd, from + j * mtd->oobblock + bd->offs,
+ readlen, &retlen, &buf[0]);
+ if (ret)
+ return ret;
+
+ if (check_short_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+ this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+ printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+ i >> 1, (unsigned int) from);
+ break;
+ }
+ } else {
+ if (check_pattern (&buf[j * scanlen], scanlen, mtd->oobblock, bd)) {
+ this->bbt[i >> 3] |= 0x03 << (i & 0x6);
+ printk (KERN_WARNING "Bad eraseblock %d at 0x%08x\n",
+ i >> 1, (unsigned int) from);
+ break;
+ }
}
}
i += 2;
from += (1 << this->bbt_erase_shift);
}
+ return 0;
}
/**
@@ -589,14 +646,12 @@ write:
* The function creates a memory based bbt by scanning the device
* for manufacturer / software marked good / bad blocks
*/
-static int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
+static inline int nand_memory_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
{
struct nand_chip *this = mtd->priv;
- /* Ensure that we only scan for the pattern and nothing else */
- bd->options = 0;
- create_bbt (mtd, this->data_buf, bd, -1);
- return 0;
+ bd->options &= ~NAND_BBT_SCANEMPTY;
+ return create_bbt (mtd, this->data_buf, bd, -1);
}
/**
@@ -808,8 +863,14 @@ int nand_scan_bbt (struct mtd_info *mtd, struct nand_bbt_descr *bd)
/* If no primary table decriptor is given, scan the device
* to build a memory based bad block table
*/
- if (!td)
- return nand_memory_bbt(mtd, bd);
+ if (!td) {
+ if ((res = nand_memory_bbt(mtd, bd))) {
+ printk (KERN_ERR "nand_bbt: Can't scan flash and build the RAM-based BBT\n");
+ kfree (this->bbt);
+ this->bbt = NULL;
+ }
+ return res;
+ }
/* Allocate a temporary buffer for one eraseblock incl. oob */
len = (1 << this->bbt_erase_shift);
@@ -904,14 +965,11 @@ out:
}
/* Define some generic bad / good block scan pattern which are used
- * while scanning a device for factory marked good / bad blocks
- *
- * The memory based patterns just
- */
+ * while scanning a device for factory marked good / bad blocks. */
static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
static struct nand_bbt_descr smallpage_memorybased = {
- .options = 0,
+ .options = NAND_BBT_SCAN2NDPAGE,
.offs = 5,
.len = 1,
.pattern = scan_ff_pattern
@@ -1042,7 +1100,7 @@ int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt)
res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
DEBUG (MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
- (unsigned int)offs, res, block >> 1);
+ (unsigned int)offs, block >> 1, res);
switch ((int)res) {
case 0x00: return 0;
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index 2d8c4321275b..efe246961b69 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -2,8 +2,8 @@
* drivers/mtd/nandids.c
*
* Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de)
- *
- * $Id: nand_ids.c,v 1.10 2004/05/26 13:40:12 gleixner Exp $
+ *
+ * $Id: nand_ids.c,v 1.14 2005/06/23 09:38:50 gleixner Exp $
*
* 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
@@ -56,17 +56,24 @@ struct nand_flash_dev nand_flash_ids[] = {
{"NAND 64MiB 3,3V 16-bit", 0x56, 512, 64, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 1,8V 8-bit", 0x78, 512, 128, 0x4000, 0},
+ {"NAND 128MiB 1,8V 8-bit", 0x39, 512, 128, 0x4000, 0},
{"NAND 128MiB 3,3V 8-bit", 0x79, 512, 128, 0x4000, 0},
{"NAND 128MiB 1,8V 16-bit", 0x72, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 1,8V 16-bit", 0x49, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 128MiB 3,3V 16-bit", 0x74, 512, 128, 0x4000, NAND_BUSWIDTH_16},
+ {"NAND 128MiB 3,3V 16-bit", 0x59, 512, 128, 0x4000, NAND_BUSWIDTH_16},
{"NAND 256MiB 3,3V 8-bit", 0x71, 512, 256, 0x4000, 0},
- {"NAND 512MiB 3,3V 8-bit", 0xDC, 512, 512, 0x4000, 0},
-
/* These are the new chips with large page size. The pagesize
* and the erasesize is determined from the extended id bytes
*/
+ /*512 Megabit */
+ {"NAND 64MiB 1,8V 8-bit", 0xA2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 64MiB 3,3V 8-bit", 0xF2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
+ {"NAND 64MiB 1,8V 16-bit", 0xB2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+ {"NAND 64MiB 3,3V 16-bit", 0xC2, 0, 64, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_BUSWIDTH_16 | NAND_NO_AUTOINCR},
+
/* 1 Gigabit */
{"NAND 128MiB 1,8V 8-bit", 0xA1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
{"NAND 128MiB 3,3V 8-bit", 0xF1, 0, 128, 0, NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR},
@@ -103,7 +110,7 @@ struct nand_flash_dev nand_flash_ids[] = {
* Anyway JFFS2 would increase the eraseblock size so we chose a combined one which can be erased in one go
* There are more speed improvements for reads and writes possible, but not implemented now
*/
- {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY},
+ {"AND 128MiB 3,3V 8-bit", 0x01, 2048, 128, 0x4000, NAND_IS_AND | NAND_NO_AUTOINCR | NAND_4PAGE_ARRAY | BBT_AUTO_REFRESH},
{NULL,}
};
@@ -118,6 +125,7 @@ struct nand_manufacturers nand_manuf_ids[] = {
{NAND_MFR_NATIONAL, "National"},
{NAND_MFR_RENESAS, "Renesas"},
{NAND_MFR_STMICRO, "ST Micro"},
+ {NAND_MFR_HYNIX, "Hynix"},
{0x0, "Unknown"}
};
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index 13feefd7d8ca..754b6ed7ce14 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -22,7 +22,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
*
- * $Id: nandsim.c,v 1.7 2004/12/06 11:53:06 dedekind Exp $
+ * $Id: nandsim.c,v 1.8 2005/03/19 15:33:56 dedekind Exp $
*/
#include <linux/config.h>
@@ -1484,33 +1484,6 @@ ns_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
}
/*
- * Having only NAND chip IDs we call nand_scan which detects NAND flash
- * parameters and then calls scan_bbt in order to scan/find/build the
- * NAND flash bad block table. But since at that moment the NAND flash
- * image isn't allocated in the simulator, errors arise. To avoid this
- * we redefine the scan_bbt callback and initialize the nandsim structure
- * before the flash media scanning.
- */
-int ns_scan_bbt(struct mtd_info *mtd)
-{
- struct nand_chip *chip = (struct nand_chip *)mtd->priv;
- struct nandsim *ns = (struct nandsim *)(chip->priv);
- int retval;
-
- if (!NS_IS_INITIALIZED(ns))
- if ((retval = init_nandsim(mtd)) != 0) {
- NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
- return retval;
- }
- if ((retval = nand_default_bbt(mtd)) != 0) {
- free_nandsim(ns);
- return retval;
- }
-
- return 0;
-}
-
-/*
* Module initialization function
*/
int __init ns_init_module(void)
@@ -1544,7 +1517,6 @@ int __init ns_init_module(void)
chip->hwcontrol = ns_hwcontrol;
chip->read_byte = ns_nand_read_byte;
chip->dev_ready = ns_device_ready;
- chip->scan_bbt = ns_scan_bbt;
chip->write_byte = ns_nand_write_byte;
chip->write_buf = ns_nand_write_buf;
chip->read_buf = ns_nand_read_buf;
@@ -1552,6 +1524,7 @@ int __init ns_init_module(void)
chip->write_word = ns_nand_write_word;
chip->read_word = ns_nand_read_word;
chip->eccmode = NAND_ECC_SOFT;
+ chip->options |= NAND_SKIP_BBTSCAN;
/*
* Perform minimum nandsim structure initialization to handle
@@ -1580,6 +1553,16 @@ int __init ns_init_module(void)
goto error;
}
+ if ((retval = init_nandsim(nsmtd)) != 0) {
+ NS_ERR("scan_bbt: can't initialize the nandsim structure\n");
+ goto error;
+ }
+
+ if ((retval = nand_default_bbt(nsmtd)) != 0) {
+ free_nandsim(nand);
+ goto error;
+ }
+
/* Register NAND as one big partition */
add_mtd_partitions(nsmtd, &nand->part, 1);
diff --git a/drivers/mtd/nand/rtc_from4.c b/drivers/mtd/nand/rtc_from4.c
index 02305a2adca7..031051cbde76 100644
--- a/drivers/mtd/nand/rtc_from4.c
+++ b/drivers/mtd/nand/rtc_from4.c
@@ -6,7 +6,7 @@
* Derived from drivers/mtd/nand/spia.c
* Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
*
- * $Id: rtc_from4.c,v 1.7 2004/11/04 12:53:10 gleixner Exp $
+ * $Id: rtc_from4.c,v 1.9 2005/01/24 20:40:11 dmarlin Exp $
*
* 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
@@ -83,13 +83,18 @@ static struct mtd_info *rtc_from4_mtd = NULL;
#define RTC_FROM4_RS_ECC_CHK (RTC_FROM4_NAND_ADDR_FPGA | 0x00000070)
#define RTC_FROM4_RS_ECC_CHK_ERROR (1 << 7)
+#define ERR_STAT_ECC_AVAILABLE 0x20
+
/* Undefine for software ECC */
#define RTC_FROM4_HWECC 1
+/* Define as 1 for no virtual erase blocks (in JFFS2) */
+#define RTC_FROM4_NO_VIRTBLOCKS 0
+
/*
* Module stuff
*/
-static void __iomem *rtc_from4_fio_base = P2SEGADDR(RTC_FROM4_FIO_BASE);
+static void __iomem *rtc_from4_fio_base = (void *)P2SEGADDR(RTC_FROM4_FIO_BASE);
const static struct mtd_partition partition_info[] = {
{
@@ -267,7 +272,6 @@ static void rtc_from4_nand_select_chip(struct mtd_info *mtd, int chip)
}
-
/*
* rtc_from4_nand_device_ready - hardware specific ready/busy check
* @mtd: MTD device structure
@@ -286,6 +290,40 @@ static int rtc_from4_nand_device_ready(struct mtd_info *mtd)
}
+
+/*
+ * deplete - code to perform device recovery in case there was a power loss
+ * @mtd: MTD device structure
+ * @chip: Chip to select (0 == slot 3, 1 == slot 4)
+ *
+ * If there was a sudden loss of power during an erase operation, a
+ * "device recovery" operation must be performed when power is restored
+ * to ensure correct operation. This routine performs the required steps
+ * for the requested chip.
+ *
+ * See page 86 of the data sheet for details.
+ *
+ */
+static void deplete(struct mtd_info *mtd, int chip)
+{
+ struct nand_chip *this = mtd->priv;
+
+ /* wait until device is ready */
+ while (!this->dev_ready(mtd));
+
+ this->select_chip(mtd, chip);
+
+ /* Send the commands for device recovery, phase 1 */
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0000);
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+ /* Send the commands for device recovery, phase 2 */
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE1, 0x0000, 0x0004);
+ this->cmdfunc (mtd, NAND_CMD_DEPLETE2, -1, -1);
+
+}
+
+
#ifdef RTC_FROM4_HWECC
/*
* rtc_from4_enable_hwecc - hardware specific hardware ECC enable function
@@ -329,6 +367,7 @@ static void rtc_from4_enable_hwecc(struct mtd_info *mtd, int mode)
}
+
/*
* rtc_from4_calculate_ecc - hardware specific code to read ECC code
* @mtd: MTD device structure
@@ -356,6 +395,7 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
ecc_code[7] |= 0x0f; /* set the last four bits (not used) */
}
+
/*
* rtc_from4_correct_data - hardware specific code to correct data using ECC code
* @mtd: MTD device structure
@@ -365,16 +405,14 @@ static void rtc_from4_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_c
*
* The FPGA tells us fast, if there's an error or not. If no, we go back happy
* else we read the ecc results from the fpga and call the rs library to decode
- * and hopefully correct the error
+ * and hopefully correct the error.
*
- * For now I use the code, which we read from the FLASH to use the RS lib,
- * as the syndrom conversion has a unresolved issue.
*/
static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_char *ecc1, u_char *ecc2)
{
int i, j, res;
unsigned short status;
- uint16_t par[6], syn[6], tmp;
+ uint16_t par[6], syn[6];
uint8_t ecc[8];
volatile unsigned short *rs_ecc;
@@ -416,15 +454,86 @@ static int rtc_from4_correct_data(struct mtd_info *mtd, const u_char *buf, u_cha
}
/* Let the library code do its magic.*/
- res = decode_rs8(rs_decoder, buf, par, 512, syn, 0, NULL, 0xff, NULL);
+ res = decode_rs8(rs_decoder, (uint8_t *)buf, par, 512, syn, 0, NULL, 0xff, NULL);
if (res > 0) {
DEBUG (MTD_DEBUG_LEVEL0, "rtc_from4_correct_data: "
"ECC corrected %d errors on read\n", res);
}
return res;
}
+
+
+/**
+ * rtc_from4_errstat - perform additional error status checks
+ * @mtd: MTD device structure
+ * @this: NAND chip structure
+ * @state: state or the operation
+ * @status: status code returned from read status
+ * @page: startpage inside the chip, must be called with (page & this->pagemask)
+ *
+ * Perform additional error status checks on erase and write failures
+ * to determine if errors are correctable. For this device, correctable
+ * 1-bit errors on erase and write are considered acceptable.
+ *
+ * note: see pages 34..37 of data sheet for details.
+ *
+ */
+static int rtc_from4_errstat(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page)
+{
+ int er_stat=0;
+ int rtn, retlen;
+ size_t len;
+ uint8_t *buf;
+ int i;
+
+ this->cmdfunc (mtd, NAND_CMD_STATUS_CLEAR, -1, -1);
+
+ if (state == FL_ERASING) {
+ for (i=0; i<4; i++) {
+ if (status & 1<<(i+1)) {
+ this->cmdfunc (mtd, (NAND_CMD_STATUS_ERROR + i + 1), -1, -1);
+ rtn = this->read_byte(mtd);
+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+ er_stat |= 1<<(i+1); /* err_ecc_not_avail */
+ }
+ }
+ }
+ } else if (state == FL_WRITING) {
+ /* single bank write logic */
+ this->cmdfunc (mtd, NAND_CMD_STATUS_ERROR, -1, -1);
+ rtn = this->read_byte(mtd);
+ this->cmdfunc (mtd, NAND_CMD_STATUS_RESET, -1, -1);
+ if (!(rtn & ERR_STAT_ECC_AVAILABLE)) {
+ er_stat |= 1<<1; /* err_ecc_not_avail */
+ } else {
+ len = mtd->oobblock;
+ buf = kmalloc (len, GFP_KERNEL);
+ if (!buf) {
+ printk (KERN_ERR "rtc_from4_errstat: Out of memory!\n");
+ er_stat = 1; /* if we can't check, assume failed */
+ } else {
+ /* recovery read */
+ /* page read */
+ rtn = nand_do_read_ecc (mtd, page, len, &retlen, buf, NULL, this->autooob, 1);
+ if (rtn) { /* if read failed or > 1-bit error corrected */
+ er_stat |= 1<<1; /* ECC read failed */
+ }
+ kfree(buf);
+ }
+ }
+ }
+
+ rtn = status;
+ if (er_stat == 0) { /* if ECC is available */
+ rtn = (status & ~NAND_STATUS_FAIL); /* clear the error bit */
+ }
+
+ return rtn;
+}
#endif
+
/*
* Main initialization routine
*/
@@ -432,6 +541,7 @@ int __init rtc_from4_init (void)
{
struct nand_chip *this;
unsigned short bcr1, bcr2, wcr2;
+ int i;
/* Allocate memory for MTD device structure and private data */
rtc_from4_mtd = kmalloc(sizeof(struct mtd_info) + sizeof (struct nand_chip),
@@ -483,6 +593,8 @@ int __init rtc_from4_init (void)
this->eccmode = NAND_ECC_HW8_512;
this->options |= NAND_HWECC_SYNDROME;
+ /* return the status of extra status and ECC checks */
+ this->errstat = rtc_from4_errstat;
/* set the nand_oobinfo to support FPGA H/W error detection */
this->autooob = &rtc_from4_nand_oobinfo;
this->enable_hwecc = rtc_from4_enable_hwecc;
@@ -504,6 +616,18 @@ int __init rtc_from4_init (void)
return -ENXIO;
}
+ /* Perform 'device recovery' for each chip in case there was a power loss. */
+ for (i=0; i < this->numchips; i++) {
+ deplete(rtc_from4_mtd, i);
+ }
+
+#if RTC_FROM4_NO_VIRTBLOCKS
+ /* use a smaller erase block to minimize wasted space when a block is bad */
+ /* note: this uses eight times as much RAM as using the default and makes */
+ /* mounts take four times as long. */
+ rtc_from4_mtd->flags |= MTD_NO_VIRTBLOCKS;
+#endif
+
/* Register the partitions */
add_mtd_partitions(rtc_from4_mtd, partition_info, NUM_PARTITIONS);
diff --git a/drivers/mtd/nand/s3c2410.c b/drivers/mtd/nand/s3c2410.c
index d05e9b97947d..891e3a1b9110 100644
--- a/drivers/mtd/nand/s3c2410.c
+++ b/drivers/mtd/nand/s3c2410.c
@@ -1,17 +1,24 @@
/* linux/drivers/mtd/nand/s3c2410.c
*
- * Copyright (c) 2004 Simtec Electronics
- * Ben Dooks <ben@simtec.co.uk>
+ * Copyright (c) 2004,2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
*
- * Samsung S3C2410 NAND driver
+ * Samsung S3C2410/S3C240 NAND driver
*
* Changelog:
* 21-Sep-2004 BJD Initial version
* 23-Sep-2004 BJD Mulitple device support
* 28-Sep-2004 BJD Fixed ECC placement for Hardware mode
* 12-Oct-2004 BJD Fixed errors in use of platform data
+ * 18-Feb-2005 BJD Fix sparse errors
+ * 14-Mar-2005 BJD Applied tglx's code reduction patch
+ * 02-May-2005 BJD Fixed s3c2440 support
+ * 02-May-2005 BJD Reduced hwcontrol decode
+ * 20-Jun-2005 BJD Updated s3c2440 support, fixed timing bug
+ * 08-Jul-2005 BJD Fix OOPS when no platform data supplied
*
- * $Id: s3c2410.c,v 1.7 2005/01/05 18:05:14 dwmw2 Exp $
+ * $Id: s3c2410.c,v 1.14 2005/07/06 20:05:06 bjd Exp $
*
* 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
@@ -69,10 +76,10 @@ static int hardware_ecc = 0;
*/
static struct nand_oobinfo nand_hw_eccoob = {
- .useecc = MTD_NANDECC_AUTOPLACE,
- .eccbytes = 3,
- .eccpos = {0, 1, 2 },
- .oobfree = { {8, 8} }
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 3,
+ .eccpos = {0, 1, 2 },
+ .oobfree = { {8, 8} }
};
/* controller and mtd information */
@@ -99,8 +106,10 @@ struct s3c2410_nand_info {
struct device *device;
struct resource *area;
struct clk *clk;
- void *regs;
+ void __iomem *regs;
int mtd_count;
+
+ unsigned char is_s3c2440;
};
/* conversion functions */
@@ -165,12 +174,12 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
/* calculate the timing information for the controller */
if (plat != NULL) {
- tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 8);
+ tacls = s3c2410_nand_calc_rate(plat->tacls, clkrate, 4);
twrph0 = s3c2410_nand_calc_rate(plat->twrph0, clkrate, 8);
twrph1 = s3c2410_nand_calc_rate(plat->twrph1, clkrate, 8);
} else {
/* default timings */
- tacls = 8;
+ tacls = 4;
twrph0 = 8;
twrph1 = 8;
}
@@ -185,10 +194,16 @@ static int s3c2410_nand_inithw(struct s3c2410_nand_info *info,
to_ns(twrph0, clkrate),
to_ns(twrph1, clkrate));
- cfg = S3C2410_NFCONF_EN;
- cfg |= S3C2410_NFCONF_TACLS(tacls-1);
- cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
- cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
+ if (!info->is_s3c2440) {
+ cfg = S3C2410_NFCONF_EN;
+ cfg |= S3C2410_NFCONF_TACLS(tacls-1);
+ cfg |= S3C2410_NFCONF_TWRPH0(twrph0-1);
+ cfg |= S3C2410_NFCONF_TWRPH1(twrph1-1);
+ } else {
+ cfg = S3C2440_NFCONF_TACLS(tacls-1);
+ cfg |= S3C2440_NFCONF_TWRPH0(twrph0-1);
+ cfg |= S3C2440_NFCONF_TWRPH1(twrph1-1);
+ }
pr_debug(PFX "NF_CONF is 0x%lx\n", cfg);
@@ -203,17 +218,22 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
struct s3c2410_nand_info *info;
struct s3c2410_nand_mtd *nmtd;
struct nand_chip *this = mtd->priv;
+ void __iomem *reg;
unsigned long cur;
+ unsigned long bit;
nmtd = this->priv;
info = nmtd->info;
- cur = readl(info->regs + S3C2410_NFCONF);
+ bit = (info->is_s3c2440) ? S3C2440_NFCONT_nFCE : S3C2410_NFCONF_nFCE;
+ reg = info->regs+((info->is_s3c2440) ? S3C2440_NFCONT:S3C2410_NFCONF);
+
+ cur = readl(reg);
if (chip == -1) {
- cur |= S3C2410_NFCONF_nFCE;
+ cur |= bit;
} else {
- if (chip > nmtd->set->nr_chips) {
+ if (nmtd->set != NULL && chip > nmtd->set->nr_chips) {
printk(KERN_ERR PFX "chip %d out of range\n", chip);
return;
}
@@ -223,143 +243,76 @@ static void s3c2410_nand_select_chip(struct mtd_info *mtd, int chip)
(info->platform->select_chip)(nmtd->set, chip);
}
- cur &= ~S3C2410_NFCONF_nFCE;
+ cur &= ~bit;
}
- writel(cur, info->regs + S3C2410_NFCONF);
+ writel(cur, reg);
}
-/* command and control functions */
+/* command and control functions
+ *
+ * Note, these all use tglx's method of changing the IO_ADDR_W field
+ * to make the code simpler, and use the nand layer's code to issue the
+ * command and address sequences via the proper IO ports.
+ *
+*/
static void s3c2410_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- unsigned long cur;
+ struct nand_chip *chip = mtd->priv;
switch (cmd) {
case NAND_CTL_SETNCE:
- cur = readl(info->regs + S3C2410_NFCONF);
- cur &= ~S3C2410_NFCONF_nFCE;
- writel(cur, info->regs + S3C2410_NFCONF);
- break;
-
case NAND_CTL_CLRNCE:
- cur = readl(info->regs + S3C2410_NFCONF);
- cur |= S3C2410_NFCONF_nFCE;
- writel(cur, info->regs + S3C2410_NFCONF);
+ printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
break;
- /* we don't need to implement these */
case NAND_CTL_SETCLE:
- case NAND_CTL_CLRCLE:
+ chip->IO_ADDR_W = info->regs + S3C2410_NFCMD;
+ break;
+
case NAND_CTL_SETALE:
- case NAND_CTL_CLRALE:
- pr_debug(PFX "s3c2410_nand_hwcontrol(%d) unusedn", cmd);
+ chip->IO_ADDR_W = info->regs + S3C2410_NFADDR;
+ break;
+
+ /* NAND_CTL_CLRCLE: */
+ /* NAND_CTL_CLRALE: */
+ default:
+ chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
break;
}
}
-/* s3c2410_nand_command
- *
- * This function implements sending commands and the relevant address
- * information to the chip, via the hardware controller. Since the
- * S3C2410 generates the correct ALE/CLE signaling automatically, we
- * do not need to use hwcontrol.
-*/
+/* command and control functions */
-static void s3c2410_nand_command (struct mtd_info *mtd, unsigned command,
- int column, int page_addr)
+static void s3c2440_nand_hwcontrol(struct mtd_info *mtd, int cmd)
{
- register struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
- register struct nand_chip *this = mtd->priv;
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ struct nand_chip *chip = mtd->priv;
- /*
- * Write out the command to the device.
- */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
-
- writeb(readcmd, info->regs + S3C2410_NFCMD);
- }
- writeb(command, info->regs + S3C2410_NFCMD);
+ switch (cmd) {
+ case NAND_CTL_SETNCE:
+ case NAND_CTL_CLRNCE:
+ printk(KERN_ERR "%s: called for NCE\n", __FUNCTION__);
+ break;
- /* Set ALE and clear CLE to start address cycle */
+ case NAND_CTL_SETCLE:
+ chip->IO_ADDR_W = info->regs + S3C2440_NFCMD;
+ break;
- if (column != -1 || page_addr != -1) {
+ case NAND_CTL_SETALE:
+ chip->IO_ADDR_W = info->regs + S3C2440_NFADDR;
+ break;
- /* Serially input address */
- if (column != -1) {
- /* Adjust columns for 16 bit buswidth */
- if (this->options & NAND_BUSWIDTH_16)
- column >>= 1;
- writeb(column, info->regs + S3C2410_NFADDR);
- }
- if (page_addr != -1) {
- writeb((unsigned char) (page_addr), info->regs + S3C2410_NFADDR);
- writeb((unsigned char) (page_addr >> 8), info->regs + S3C2410_NFADDR);
- /* One more address cycle for higher density devices */
- if (this->chipsize & 0x0c000000)
- writeb((unsigned char) ((page_addr >> 16) & 0x0f),
- info->regs + S3C2410_NFADDR);
- }
- /* Latch in address */
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_SEQIN:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
-
- udelay(this->chip_delay);
- writeb(NAND_CMD_STATUS, info->regs + S3C2410_NFCMD);
-
- while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
+ /* NAND_CTL_CLRCLE: */
+ /* NAND_CTL_CLRALE: */
default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
+ chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
+ break;
}
-
- /* Apply this short delay always to ensure that we do wait tWB in
- * any case on any machine. */
- ndelay (100);
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
}
-
/* s3c2410_nand_devready()
*
* returns 0 if the nand is busy, 1 if it is ready
@@ -369,9 +322,12 @@ static int s3c2410_nand_devready(struct mtd_info *mtd)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ if (info->is_s3c2440)
+ return readb(info->regs + S3C2440_NFSTAT) & S3C2440_NFSTAT_READY;
return readb(info->regs + S3C2410_NFSTAT) & S3C2410_NFSTAT_BUSY;
}
+
/* ECC handling functions */
static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
@@ -394,6 +350,12 @@ static int s3c2410_nand_correct_data(struct mtd_info *mtd, u_char *dat,
return -1;
}
+/* ECC functions
+ *
+ * These allow the s3c2410 and s3c2440 to use the controller's ECC
+ * generator block to ECC the data as it passes through]
+*/
+
static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
{
struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
@@ -404,6 +366,15 @@ static void s3c2410_nand_enable_hwecc(struct mtd_info *mtd, int mode)
writel(ctrl, info->regs + S3C2410_NFCONF);
}
+static void s3c2440_nand_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ unsigned long ctrl;
+
+ ctrl = readl(info->regs + S3C2440_NFCONT);
+ writel(ctrl | S3C2440_NFCONT_INITECC, info->regs + S3C2440_NFCONT);
+}
+
static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
const u_char *dat, u_char *ecc_code)
{
@@ -420,7 +391,26 @@ static int s3c2410_nand_calculate_ecc(struct mtd_info *mtd,
}
-/* over-ride the standard functions for a little more speed? */
+static int s3c2440_nand_calculate_ecc(struct mtd_info *mtd,
+ const u_char *dat, u_char *ecc_code)
+{
+ struct s3c2410_nand_info *info = s3c2410_nand_mtd_toinfo(mtd);
+ unsigned long ecc = readl(info->regs + S3C2440_NFMECC0);
+
+ ecc_code[0] = ecc;
+ ecc_code[1] = ecc >> 8;
+ ecc_code[2] = ecc >> 16;
+
+ pr_debug("calculate_ecc: returning ecc %02x,%02x,%02x\n",
+ ecc_code[0], ecc_code[1], ecc_code[2]);
+
+ return 0;
+}
+
+
+/* over-ride the standard functions for a little more speed. We can
+ * use read/write block to move the data buffers to/from the controller
+*/
static void s3c2410_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
{
@@ -523,11 +513,10 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
{
struct nand_chip *chip = &nmtd->chip;
- chip->IO_ADDR_R = (char *)info->regs + S3C2410_NFDATA;
- chip->IO_ADDR_W = (char *)info->regs + S3C2410_NFDATA;
+ chip->IO_ADDR_R = info->regs + S3C2410_NFDATA;
+ chip->IO_ADDR_W = info->regs + S3C2410_NFDATA;
chip->hwcontrol = s3c2410_nand_hwcontrol;
chip->dev_ready = s3c2410_nand_devready;
- chip->cmdfunc = s3c2410_nand_command;
chip->write_buf = s3c2410_nand_write_buf;
chip->read_buf = s3c2410_nand_read_buf;
chip->select_chip = s3c2410_nand_select_chip;
@@ -536,6 +525,12 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->options = 0;
chip->controller = &info->controller;
+ if (info->is_s3c2440) {
+ chip->IO_ADDR_R = info->regs + S3C2440_NFDATA;
+ chip->IO_ADDR_W = info->regs + S3C2440_NFDATA;
+ chip->hwcontrol = s3c2440_nand_hwcontrol;
+ }
+
nmtd->info = info;
nmtd->mtd.priv = chip;
nmtd->set = set;
@@ -546,6 +541,11 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
chip->calculate_ecc = s3c2410_nand_calculate_ecc;
chip->eccmode = NAND_ECC_HW3_512;
chip->autooob = &nand_hw_eccoob;
+
+ if (info->is_s3c2440) {
+ chip->enable_hwecc = s3c2440_nand_enable_hwecc;
+ chip->calculate_ecc = s3c2440_nand_calculate_ecc;
+ }
} else {
chip->eccmode = NAND_ECC_SOFT;
}
@@ -559,7 +559,7 @@ static void s3c2410_nand_init_chip(struct s3c2410_nand_info *info,
* nand layer to look for devices
*/
-static int s3c2410_nand_probe(struct device *dev)
+static int s3c24xx_nand_probe(struct device *dev, int is_s3c2440)
{
struct platform_device *pdev = to_platform_device(dev);
struct s3c2410_platform_nand *plat = to_nand_plat(dev);
@@ -585,6 +585,7 @@ static int s3c2410_nand_probe(struct device *dev)
dev_set_drvdata(dev, info);
spin_lock_init(&info->controller.lock);
+ init_waitqueue_head(&info->controller.wq);
/* get the clock source and enable it */
@@ -600,7 +601,8 @@ static int s3c2410_nand_probe(struct device *dev)
/* allocate and map the resource */
- res = pdev->resource; /* assume that the flash has one resource */
+ /* currently we assume we have the one resource */
+ res = pdev->resource;
size = res->end - res->start + 1;
info->area = request_mem_region(res->start, size, pdev->name);
@@ -611,9 +613,10 @@ static int s3c2410_nand_probe(struct device *dev)
goto exit_error;
}
- info->device = dev;
- info->platform = plat;
- info->regs = ioremap(res->start, size);
+ info->device = dev;
+ info->platform = plat;
+ info->regs = ioremap(res->start, size);
+ info->is_s3c2440 = is_s3c2440;
if (info->regs == NULL) {
printk(KERN_ERR PFX "cannot reserve register region\n");
@@ -678,6 +681,18 @@ static int s3c2410_nand_probe(struct device *dev)
return err;
}
+/* driver device registration */
+
+static int s3c2410_nand_probe(struct device *dev)
+{
+ return s3c24xx_nand_probe(dev, 0);
+}
+
+static int s3c2440_nand_probe(struct device *dev)
+{
+ return s3c24xx_nand_probe(dev, 1);
+}
+
static struct device_driver s3c2410_nand_driver = {
.name = "s3c2410-nand",
.bus = &platform_bus_type,
@@ -685,14 +700,24 @@ static struct device_driver s3c2410_nand_driver = {
.remove = s3c2410_nand_remove,
};
+static struct device_driver s3c2440_nand_driver = {
+ .name = "s3c2440-nand",
+ .bus = &platform_bus_type,
+ .probe = s3c2440_nand_probe,
+ .remove = s3c2410_nand_remove,
+};
+
static int __init s3c2410_nand_init(void)
{
- printk("S3C2410 NAND Driver, (c) 2004 Simtec Electronics\n");
+ printk("S3C24XX NAND Driver, (c) 2004 Simtec Electronics\n");
+
+ driver_register(&s3c2440_nand_driver);
return driver_register(&s3c2410_nand_driver);
}
static void __exit s3c2410_nand_exit(void)
{
+ driver_unregister(&s3c2440_nand_driver);
driver_unregister(&s3c2410_nand_driver);
}
@@ -701,4 +726,4 @@ module_exit(s3c2410_nand_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
-MODULE_DESCRIPTION("S3C2410 MTD NAND driver");
+MODULE_DESCRIPTION("S3C24XX MTD NAND driver");
diff --git a/drivers/mtd/nand/sharpsl.c b/drivers/mtd/nand/sharpsl.c
index 29572793334c..9853b87bb756 100755..100644
--- a/drivers/mtd/nand/sharpsl.c
+++ b/drivers/mtd/nand/sharpsl.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2004 Richard Purdie
*
- * $Id: sharpsl.c,v 1.3 2005/01/03 14:53:50 rpurdie Exp $
+ * $Id: sharpsl.c,v 1.4 2005/01/23 11:09:19 rpurdie Exp $
*
* Based on Sharp's NAND driver sharp_sl.c
*
@@ -216,7 +216,7 @@ sharpsl_nand_init(void)
nr_partitions = DEFAULT_NUM_PARTITIONS;
sharpsl_partition_info = sharpsl_nand_default_partition_info;
if (machine_is_poodle()) {
- sharpsl_partition_info[1].size=22 * 1024 * 1024;
+ sharpsl_partition_info[1].size=30 * 1024 * 1024;
} else if (machine_is_corgi() || machine_is_shepherd()) {
sharpsl_partition_info[1].size=25 * 1024 * 1024;
} else if (machine_is_husky()) {
diff --git a/drivers/mtd/nand/tx4925ndfmc.c b/drivers/mtd/nand/tx4925ndfmc.c
deleted file mode 100644
index bba688830c9b..000000000000
--- a/drivers/mtd/nand/tx4925ndfmc.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * drivers/mtd/tx4925ndfmc.c
- *
- * Overview:
- * This is a device driver for the NAND flash device found on the
- * Toshiba RBTX4925 reference board, which is a SmartMediaCard. It supports
- * 16MiB, 32MiB and 64MiB cards.
- *
- * Author: MontaVista Software, Inc. source@mvista.com
- *
- * Derived from drivers/mtd/autcpu12.c
- * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
- *
- * $Id: tx4925ndfmc.c,v 1.5 2004/10/05 13:50:20 gleixner Exp $
- *
- * Copyright (C) 2001 Toshiba Corporation
- *
- * 2003 (c) MontaVista Software, Inc. This file is licensed under
- * the terms of the GNU General Public License version 2. This program
- * is licensed "as is" without any warranty of any kind, whether express
- * or implied.
- *
- */
-
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/partitions.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <asm/tx4925/tx4925_nand.h>
-
-extern struct nand_oobinfo jffs2_oobinfo;
-
-/*
- * MTD structure for RBTX4925 board
- */
-static struct mtd_info *tx4925ndfmc_mtd = NULL;
-
-/*
- * Define partitions for flash devices
- */
-
-static struct mtd_partition partition_info16k[] = {
- { .name = "RBTX4925 flash partition 1",
- .offset = 0,
- .size = 8 * 0x00100000 },
- { .name = "RBTX4925 flash partition 2",
- .offset = 8 * 0x00100000,
- .size = 8 * 0x00100000 },
-};
-
-static struct mtd_partition partition_info32k[] = {
- { .name = "RBTX4925 flash partition 1",
- .offset = 0,
- .size = 8 * 0x00100000 },
- { .name = "RBTX4925 flash partition 2",
- .offset = 8 * 0x00100000,
- .size = 24 * 0x00100000 },
-};
-
-static struct mtd_partition partition_info64k[] = {
- { .name = "User FS",
- .offset = 0,
- .size = 16 * 0x00100000 },
- { .name = "RBTX4925 flash partition 2",
- .offset = 16 * 0x00100000,
- .size = 48 * 0x00100000},
-};
-
-static struct mtd_partition partition_info128k[] = {
- { .name = "Skip bad section",
- .offset = 0,
- .size = 16 * 0x00100000 },
- { .name = "User FS",
- .offset = 16 * 0x00100000,
- .size = 112 * 0x00100000 },
-};
-#define NUM_PARTITIONS16K 2
-#define NUM_PARTITIONS32K 2
-#define NUM_PARTITIONS64K 2
-#define NUM_PARTITIONS128K 2
-
-/*
- * hardware specific access to control-lines
-*/
-static void tx4925ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-{
-
- switch(cmd){
-
- case NAND_CTL_SETCLE:
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CLE;
- break;
- case NAND_CTL_CLRCLE:
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CLE;
- break;
- case NAND_CTL_SETALE:
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ALE;
- break;
- case NAND_CTL_CLRALE:
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ALE;
- break;
- case NAND_CTL_SETNCE:
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_CE;
- break;
- case NAND_CTL_CLRNCE:
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_CE;
- break;
- case NAND_CTL_SETWP:
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_WE;
- break;
- case NAND_CTL_CLRWP:
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_WE;
- break;
- }
-}
-
-/*
-* read device ready pin
-*/
-static int tx4925ndfmc_device_ready(struct mtd_info *mtd)
-{
- int ready;
- ready = (tx4925_ndfmcptr->sr & TX4925_NDSFR_BUSY) ? 0 : 1;
- return ready;
-}
-void tx4925ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-{
- /* reset first */
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_MASK;
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_ENAB;
-}
-static void tx4925ndfmc_disable_ecc(void)
-{
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
-}
-static void tx4925ndfmc_enable_read_ecc(void)
-{
- tx4925_ndfmcptr->mcr &= ~TX4925_NDFMCR_ECC_CNTL_MASK;
- tx4925_ndfmcptr->mcr |= TX4925_NDFMCR_ECC_CNTL_READ;
-}
-void tx4925ndfmc_readecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code){
- int i;
- u_char *ecc = ecc_code;
- tx4925ndfmc_enable_read_ecc();
- for (i = 0;i < 6;i++,ecc++)
- *ecc = tx4925_read_nfmc(&(tx4925_ndfmcptr->dtr));
- tx4925ndfmc_disable_ecc();
-}
-void tx4925ndfmc_device_setup(void)
-{
-
- *(unsigned char *)0xbb005000 &= ~0x08;
-
- /* reset NDFMC */
- tx4925_ndfmcptr->rstr |= TX4925_NDFRSTR_RST;
- while (tx4925_ndfmcptr->rstr & TX4925_NDFRSTR_RST);
-
- /* setup BusSeparete, Hold Time, Strobe Pulse Width */
- tx4925_ndfmcptr->mcr = TX4925_BSPRT ? TX4925_NDFMCR_BSPRT : 0;
- tx4925_ndfmcptr->spr = TX4925_HOLD << 4 | TX4925_SPW;
-}
-static u_char tx4925ndfmc_nand_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- return tx4925_read_nfmc(this->IO_ADDR_R);
-}
-
-static void tx4925ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-{
- struct nand_chip *this = mtd->priv;
- tx4925_write_nfmc(byte, this->IO_ADDR_W);
-}
-
-static void tx4925ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- tx4925_write_nfmc(buf[i], this->IO_ADDR_W);
-}
-
-static void tx4925ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- buf[i] = tx4925_read_nfmc(this->IO_ADDR_R);
-}
-
-static int tx4925ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- if (buf[i] != tx4925_read_nfmc(this->IO_ADDR_R))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Send command to NAND device
- */
-static void tx4925ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
- register struct nand_chip *this = mtd->priv;
-
- /* Begin command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- /*
- * Write out the command to the device.
- */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- this->write_byte(mtd, readcmd);
- }
- this->write_byte(mtd, command);
-
- /* Set ALE and clear CLE to start address cycle */
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-
- if (column != -1 || page_addr != -1) {
- this->hwcontrol(mtd, NAND_CTL_SETALE);
-
- /* Serially input address */
- if (column != -1)
- this->write_byte(mtd, column);
- if (page_addr != -1) {
- this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
- this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
- /* One more address cycle for higher density devices */
- if (mtd->size & 0x0c000000)
- this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
- }
- /* Latch in address */
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- /* Turn off WE */
- this->hwcontrol (mtd, NAND_CTL_CLRWP);
- return;
-
- case NAND_CMD_SEQIN:
- /* Turn on WE */
- this->hwcontrol (mtd, NAND_CTL_SETWP);
- return;
-
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- this->write_byte(mtd, NAND_CMD_STATUS);
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
- }
-
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
-}
-
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partitio
-n **pparts, char *);
-#endif
-
-/*
- * Main initialization routine
- */
-extern int nand_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
-int __init tx4925ndfmc_init (void)
-{
- struct nand_chip *this;
- int err = 0;
-
- /* Allocate memory for MTD device structure and private data */
- tx4925ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
- if (!tx4925ndfmc_mtd) {
- printk ("Unable to allocate RBTX4925 NAND MTD device structure.\n");
- err = -ENOMEM;
- goto out;
- }
-
- tx4925ndfmc_device_setup();
-
- /* io is indirect via a register so don't need to ioremap address */
-
- /* Get pointer to private data */
- this = (struct nand_chip *) (&tx4925ndfmc_mtd[1]);
-
- /* Initialize structures */
- memset((char *) tx4925ndfmc_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
-
- /* Link the private data with the MTD structure */
- tx4925ndfmc_mtd->priv = this;
-
- /* Set address of NAND IO lines */
- this->IO_ADDR_R = (void __iomem *)&(tx4925_ndfmcptr->dtr);
- this->IO_ADDR_W = (void __iomem *)&(tx4925_ndfmcptr->dtr);
- this->hwcontrol = tx4925ndfmc_hwcontrol;
- this->enable_hwecc = tx4925ndfmc_enable_hwecc;
- this->calculate_ecc = tx4925ndfmc_readecc;
- this->correct_data = nand_correct_data;
- this->eccmode = NAND_ECC_HW6_512;
- this->dev_ready = tx4925ndfmc_device_ready;
- /* 20 us command delay time */
- this->chip_delay = 20;
- this->read_byte = tx4925ndfmc_nand_read_byte;
- this->write_byte = tx4925ndfmc_nand_write_byte;
- this->cmdfunc = tx4925ndfmc_nand_command;
- this->write_buf = tx4925ndfmc_nand_write_buf;
- this->read_buf = tx4925ndfmc_nand_read_buf;
- this->verify_buf = tx4925ndfmc_nand_verify_buf;
-
- /* Scan to find existance of the device */
- if (nand_scan (tx4925ndfmc_mtd, 1)) {
- err = -ENXIO;
- goto out_ior;
- }
-
- /* Register the partitions */
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- {
- int mtd_parts_nb = 0;
- struct mtd_partition *mtd_parts = 0;
- mtd_parts_nb = parse_cmdline_partitions(tx4925ndfmc_mtd, &mtd_parts, "tx4925ndfmc");
- if (mtd_parts_nb > 0)
- add_mtd_partitions(tx4925ndfmc_mtd, mtd_parts, mtd_parts_nb);
- else
- add_mtd_device(tx4925ndfmc_mtd);
- }
-#else /* ifdef CONFIG_MTD_CMDLINE_PARTS */
- switch(tx4925ndfmc_mtd->size){
- case 0x01000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info16k, NUM_PARTITIONS16K); break;
- case 0x02000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info32k, NUM_PARTITIONS32K); break;
- case 0x04000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info64k, NUM_PARTITIONS64K); break;
- case 0x08000000: add_mtd_partitions(tx4925ndfmc_mtd, partition_info128k, NUM_PARTITIONS128K); break;
- default: {
- printk ("Unsupported SmartMedia device\n");
- err = -ENXIO;
- goto out_ior;
- }
- }
-#endif /* ifdef CONFIG_MTD_CMDLINE_PARTS */
- goto out;
-
-out_ior:
-out:
- return err;
-}
-
-module_init(tx4925ndfmc_init);
-
-/*
- * Clean up routine
- */
-#ifdef MODULE
-static void __exit tx4925ndfmc_cleanup (void)
-{
- /* Release resources, unregister device */
- nand_release (tx4925ndfmc_mtd);
-
- /* Free the MTD device structure */
- kfree (tx4925ndfmc_mtd);
-}
-module_exit(tx4925ndfmc_cleanup);
-#endif
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-MODULE_DESCRIPTION("Glue layer for SmartMediaCard on Toshiba RBTX4925");
diff --git a/drivers/mtd/nand/tx4938ndfmc.c b/drivers/mtd/nand/tx4938ndfmc.c
deleted file mode 100644
index df26e58820b3..000000000000
--- a/drivers/mtd/nand/tx4938ndfmc.c
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * drivers/mtd/nand/tx4938ndfmc.c
- *
- * Overview:
- * This is a device driver for the NAND flash device connected to
- * TX4938 internal NAND Memory Controller.
- * TX4938 NDFMC is almost same as TX4925 NDFMC, but register size are 64 bit.
- *
- * Author: source@mvista.com
- *
- * Based on spia.c by Steven J. Hill
- *
- * $Id: tx4938ndfmc.c,v 1.4 2004/10/05 13:50:20 gleixner Exp $
- *
- * Copyright (C) 2000-2001 Toshiba Corporation
- *
- * 2003 (c) MontaVista Software, Inc. This file is licensed under the
- * terms of the GNU General Public License version 2. This program is
- * licensed "as is" without any warranty of any kind, whether express
- * or implied.
- */
-#include <linux/config.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/nand.h>
-#include <linux/mtd/nand_ecc.h>
-#include <linux/mtd/partitions.h>
-#include <asm/io.h>
-#include <asm/bootinfo.h>
-#include <linux/delay.h>
-#include <asm/tx4938/rbtx4938.h>
-
-extern struct nand_oobinfo jffs2_oobinfo;
-
-/*
- * MTD structure for TX4938 NDFMC
- */
-static struct mtd_info *tx4938ndfmc_mtd;
-
-/*
- * Define partitions for flash device
- */
-#define flush_wb() (void)tx4938_ndfmcptr->mcr;
-
-#define NUM_PARTITIONS 3
-#define NUMBER_OF_CIS_BLOCKS 24
-#define SIZE_OF_BLOCK 0x00004000
-#define NUMBER_OF_BLOCK_PER_ZONE 1024
-#define SIZE_OF_ZONE (NUMBER_OF_BLOCK_PER_ZONE * SIZE_OF_BLOCK)
-#ifndef CONFIG_MTD_CMDLINE_PARTS
-/*
- * You can use the following sample of MTD partitions
- * on the NAND Flash Memory 32MB or more.
- *
- * The following figure shows the image of the sample partition on
- * the 32MB NAND Flash Memory.
- *
- * Block No.
- * 0 +-----------------------------+ ------
- * | CIS | ^
- * 24 +-----------------------------+ |
- * | kernel image | | Zone 0
- * | | |
- * +-----------------------------+ |
- * 1023 | unused area | v
- * +-----------------------------+ ------
- * 1024 | JFFS2 | ^
- * | | |
- * | | | Zone 1
- * | | |
- * | | |
- * | | v
- * 2047 +-----------------------------+ ------
- *
- */
-static struct mtd_partition partition_info[NUM_PARTITIONS] = {
- {
- .name = "RBTX4938 CIS Area",
- .offset = 0,
- .size = (NUMBER_OF_CIS_BLOCKS * SIZE_OF_BLOCK),
- .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
- },
- {
- .name = "RBTX4938 kernel image",
- .offset = MTDPART_OFS_APPEND,
- .size = 8 * 0x00100000, /* 8MB (Depends on size of kernel image) */
- .mask_flags = MTD_WRITEABLE /* This partition is NOT writable */
- },
- {
- .name = "Root FS (JFFS2)",
- .offset = (0 + SIZE_OF_ZONE), /* start address of next zone */
- .size = MTDPART_SIZ_FULL
- },
-};
-#endif
-
-static void tx4938ndfmc_hwcontrol(struct mtd_info *mtd, int cmd)
-{
- switch (cmd) {
- case NAND_CTL_SETCLE:
- tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CLE;
- break;
- case NAND_CTL_CLRCLE:
- tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CLE;
- break;
- case NAND_CTL_SETALE:
- tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_ALE;
- break;
- case NAND_CTL_CLRALE:
- tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_ALE;
- break;
- /* TX4938_NDFMCR_CE bit is 0:high 1:low */
- case NAND_CTL_SETNCE:
- tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_CE;
- break;
- case NAND_CTL_CLRNCE:
- tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_CE;
- break;
- case NAND_CTL_SETWP:
- tx4938_ndfmcptr->mcr |= TX4938_NDFMCR_WE;
- break;
- case NAND_CTL_CLRWP:
- tx4938_ndfmcptr->mcr &= ~TX4938_NDFMCR_WE;
- break;
- }
-}
-static int tx4938ndfmc_dev_ready(struct mtd_info *mtd)
-{
- flush_wb();
- return !(tx4938_ndfmcptr->sr & TX4938_NDFSR_BUSY);
-}
-static void tx4938ndfmc_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
-{
- u32 mcr = tx4938_ndfmcptr->mcr;
- mcr &= ~TX4938_NDFMCR_ECC_ALL;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_READ;
- ecc_code[1] = tx4938_ndfmcptr->dtr;
- ecc_code[0] = tx4938_ndfmcptr->dtr;
- ecc_code[2] = tx4938_ndfmcptr->dtr;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
-}
-static void tx4938ndfmc_enable_hwecc(struct mtd_info *mtd, int mode)
-{
- u32 mcr = tx4938_ndfmcptr->mcr;
- mcr &= ~TX4938_NDFMCR_ECC_ALL;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_RESET;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_OFF;
- tx4938_ndfmcptr->mcr = mcr | TX4938_NDFMCR_ECC_ON;
-}
-
-static u_char tx4938ndfmc_nand_read_byte(struct mtd_info *mtd)
-{
- struct nand_chip *this = mtd->priv;
- return tx4938_read_nfmc(this->IO_ADDR_R);
-}
-
-static void tx4938ndfmc_nand_write_byte(struct mtd_info *mtd, u_char byte)
-{
- struct nand_chip *this = mtd->priv;
- tx4938_write_nfmc(byte, this->IO_ADDR_W);
-}
-
-static void tx4938ndfmc_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- tx4938_write_nfmc(buf[i], this->IO_ADDR_W);
-}
-
-static void tx4938ndfmc_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- buf[i] = tx4938_read_nfmc(this->IO_ADDR_R);
-}
-
-static int tx4938ndfmc_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
-{
- int i;
- struct nand_chip *this = mtd->priv;
-
- for (i=0; i<len; i++)
- if (buf[i] != tx4938_read_nfmc(this->IO_ADDR_R))
- return -EFAULT;
-
- return 0;
-}
-
-/*
- * Send command to NAND device
- */
-static void tx4938ndfmc_nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
-{
- register struct nand_chip *this = mtd->priv;
-
- /* Begin command latch cycle */
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- /*
- * Write out the command to the device.
- */
- if (command == NAND_CMD_SEQIN) {
- int readcmd;
-
- if (column >= mtd->oobblock) {
- /* OOB area */
- column -= mtd->oobblock;
- readcmd = NAND_CMD_READOOB;
- } else if (column < 256) {
- /* First 256 bytes --> READ0 */
- readcmd = NAND_CMD_READ0;
- } else {
- column -= 256;
- readcmd = NAND_CMD_READ1;
- }
- this->write_byte(mtd, readcmd);
- }
- this->write_byte(mtd, command);
-
- /* Set ALE and clear CLE to start address cycle */
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
-
- if (column != -1 || page_addr != -1) {
- this->hwcontrol(mtd, NAND_CTL_SETALE);
-
- /* Serially input address */
- if (column != -1)
- this->write_byte(mtd, column);
- if (page_addr != -1) {
- this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
- this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
- /* One more address cycle for higher density devices */
- if (mtd->size & 0x0c000000)
- this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
- }
- /* Latch in address */
- this->hwcontrol(mtd, NAND_CTL_CLRALE);
- }
-
- /*
- * program and erase have their own busy handlers
- * status and sequential in needs no delay
- */
- switch (command) {
-
- case NAND_CMD_PAGEPROG:
- /* Turn off WE */
- this->hwcontrol (mtd, NAND_CTL_CLRWP);
- return;
-
- case NAND_CMD_SEQIN:
- /* Turn on WE */
- this->hwcontrol (mtd, NAND_CTL_SETWP);
- return;
-
- case NAND_CMD_ERASE1:
- case NAND_CMD_ERASE2:
- case NAND_CMD_STATUS:
- return;
-
- case NAND_CMD_RESET:
- if (this->dev_ready)
- break;
- this->hwcontrol(mtd, NAND_CTL_SETCLE);
- this->write_byte(mtd, NAND_CMD_STATUS);
- this->hwcontrol(mtd, NAND_CTL_CLRCLE);
- while ( !(this->read_byte(mtd) & 0x40));
- return;
-
- /* This applies to read commands */
- default:
- /*
- * If we don't have access to the busy pin, we apply the given
- * command delay
- */
- if (!this->dev_ready) {
- udelay (this->chip_delay);
- return;
- }
- }
-
- /* wait until command is processed */
- while (!this->dev_ready(mtd));
-}
-
-#ifdef CONFIG_MTD_CMDLINE_PARTS
-extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
-#endif
-/*
- * Main initialization routine
- */
-int __init tx4938ndfmc_init (void)
-{
- struct nand_chip *this;
- int bsprt = 0, hold = 0xf, spw = 0xf;
- int protected = 0;
-
- if ((*rbtx4938_piosel_ptr & 0x0c) != 0x08) {
- printk("TX4938 NDFMC: disabled by IOC PIOSEL\n");
- return -ENODEV;
- }
- bsprt = 1;
- hold = 2;
- spw = 9 - 1; /* 8 GBUSCLK = 80ns (@ GBUSCLK 100MHz) */
-
- if ((tx4938_ccfgptr->pcfg &
- (TX4938_PCFG_ATA_SEL|TX4938_PCFG_ISA_SEL|TX4938_PCFG_NDF_SEL))
- != TX4938_PCFG_NDF_SEL) {
- printk("TX4938 NDFMC: disabled by PCFG.\n");
- return -ENODEV;
- }
-
- /* reset NDFMC */
- tx4938_ndfmcptr->rstr |= TX4938_NDFRSTR_RST;
- while (tx4938_ndfmcptr->rstr & TX4938_NDFRSTR_RST)
- ;
- /* setup BusSeparete, Hold Time, Strobe Pulse Width */
- tx4938_ndfmcptr->mcr = bsprt ? TX4938_NDFMCR_BSPRT : 0;
- tx4938_ndfmcptr->spr = hold << 4 | spw;
-
- /* Allocate memory for MTD device structure and private data */
- tx4938ndfmc_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
- GFP_KERNEL);
- if (!tx4938ndfmc_mtd) {
- printk ("Unable to allocate TX4938 NDFMC MTD device structure.\n");
- return -ENOMEM;
- }
-
- /* Get pointer to private data */
- this = (struct nand_chip *) (&tx4938ndfmc_mtd[1]);
-
- /* Initialize structures */
- memset((char *) tx4938ndfmc_mtd, 0, sizeof(struct mtd_info));
- memset((char *) this, 0, sizeof(struct nand_chip));
-
- /* Link the private data with the MTD structure */
- tx4938ndfmc_mtd->priv = this;
-
- /* Set address of NAND IO lines */
- this->IO_ADDR_R = (unsigned long)&tx4938_ndfmcptr->dtr;
- this->IO_ADDR_W = (unsigned long)&tx4938_ndfmcptr->dtr;
- this->hwcontrol = tx4938ndfmc_hwcontrol;
- this->dev_ready = tx4938ndfmc_dev_ready;
- this->calculate_ecc = tx4938ndfmc_calculate_ecc;
- this->correct_data = nand_correct_data;
- this->enable_hwecc = tx4938ndfmc_enable_hwecc;
- this->eccmode = NAND_ECC_HW3_256;
- this->chip_delay = 100;
- this->read_byte = tx4938ndfmc_nand_read_byte;
- this->write_byte = tx4938ndfmc_nand_write_byte;
- this->cmdfunc = tx4938ndfmc_nand_command;
- this->write_buf = tx4938ndfmc_nand_write_buf;
- this->read_buf = tx4938ndfmc_nand_read_buf;
- this->verify_buf = tx4938ndfmc_nand_verify_buf;
-
- /* Scan to find existance of the device */
- if (nand_scan (tx4938ndfmc_mtd, 1)) {
- kfree (tx4938ndfmc_mtd);
- return -ENXIO;
- }
-
- if (protected) {
- printk(KERN_INFO "TX4938 NDFMC: write protected.\n");
- tx4938ndfmc_mtd->flags &= ~(MTD_WRITEABLE | MTD_ERASEABLE);
- }
-
-#ifdef CONFIG_MTD_CMDLINE_PARTS
- {
- int mtd_parts_nb = 0;
- struct mtd_partition *mtd_parts = 0;
- mtd_parts_nb = parse_cmdline_partitions(tx4938ndfmc_mtd, &mtd_parts, "tx4938ndfmc");
- if (mtd_parts_nb > 0)
- add_mtd_partitions(tx4938ndfmc_mtd, mtd_parts, mtd_parts_nb);
- else
- add_mtd_device(tx4938ndfmc_mtd);
- }
-#else
- add_mtd_partitions(tx4938ndfmc_mtd, partition_info, NUM_PARTITIONS );
-#endif
-
- return 0;
-}
-module_init(tx4938ndfmc_init);
-
-/*
- * Clean up routine
- */
-static void __exit tx4938ndfmc_cleanup (void)
-{
- /* Release resources, unregister device */
- nand_release (tx4938ndfmc_mtd);
-
- /* Free the MTD device structure */
- kfree (tx4938ndfmc_mtd);
-}
-module_exit(tx4938ndfmc_cleanup);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Alice Hennessy <ahennessy@mvista.com>");
-MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on TX4938 NDFMC");
diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c
index 29dfd47f41d2..5c5eebdb6914 100644
--- a/drivers/net/3c503.c
+++ b/drivers/net/3c503.c
@@ -171,12 +171,7 @@ struct net_device * __init el2_probe(int unit)
err = do_el2_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -356,6 +351,10 @@ el2_probe1(struct net_device *dev, int ioaddr)
dev->poll_controller = ei_poll;
#endif
+ retval = register_netdev(dev);
+ if (retval)
+ goto out1;
+
if (dev->mem_start)
printk("%s: %s - %dkB RAM, 8kB shared mem window at %#6lx-%#6lx.\n",
dev->name, ei_status.name, (wordlength+1)<<3,
@@ -715,11 +714,8 @@ init_module(void)
dev->base_addr = io[this_dev];
dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */
if (do_el2_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_el2[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_el2[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "3c503.c: No 3c503 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c
index 76fa8cc24085..ad17f17e8e7a 100644
--- a/drivers/net/3c505.c
+++ b/drivers/net/3c505.c
@@ -1317,8 +1317,7 @@ static int __init elp_sense(struct net_device *dev)
if (orig_HSR & DIR) {
/* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */
outb(0, dev->base_addr + PORT_CONTROL);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(30*HZ/100);
+ msleep(300);
if (inb_status(addr) & DIR) {
if (elp_debug > 0)
printk(notfound_msg, 2);
@@ -1327,8 +1326,7 @@ static int __init elp_sense(struct net_device *dev)
} else {
/* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */
outb(DIR, dev->base_addr + PORT_CONTROL);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(30*HZ/100);
+ msleep(300);
if (!(inb_status(addr) & DIR)) {
if (elp_debug > 0)
printk(notfound_msg, 3);
diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c
index e843109d4f62..977935a3d898 100644
--- a/drivers/net/3c509.c
+++ b/drivers/net/3c509.c
@@ -217,6 +217,7 @@ static void el3_poll_controller(struct net_device *dev);
static struct eisa_device_id el3_eisa_ids[] = {
{ "TCM5092" },
{ "TCM5093" },
+ { "TCM5095" },
{ "" }
};
diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c
index c4cf4fcd1344..91d1c4c24d9b 100644
--- a/drivers/net/3c515.c
+++ b/drivers/net/3c515.c
@@ -365,7 +365,7 @@ static int nopnp;
#endif /* __ISAPNP__ */
static struct net_device *corkscrew_scan(int unit);
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
struct pnp_dev *idev, int card_number);
static int corkscrew_open(struct net_device *dev);
static void corkscrew_timer(unsigned long arg);
@@ -539,10 +539,9 @@ static struct net_device *corkscrew_scan(int unit)
printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
/* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */
- corkscrew_setup(dev, ioaddr, idev, cards_found++);
SET_NETDEV_DEV(dev, &idev->dev);
pnp_cards++;
- err = register_netdev(dev);
+ err = corkscrew_setup(dev, ioaddr, idev, cards_found++);
if (!err)
return dev;
cleanup_card(dev);
@@ -558,8 +557,7 @@ no_pnp:
printk(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n",
inl(ioaddr + 0x2002), inw(ioaddr + 0x2000));
- corkscrew_setup(dev, ioaddr, NULL, cards_found++);
- err = register_netdev(dev);
+ err = corkscrew_setup(dev, ioaddr, NULL, cards_found++);
if (!err)
return dev;
cleanup_card(dev);
@@ -568,7 +566,7 @@ no_pnp:
return NULL;
}
-static void corkscrew_setup(struct net_device *dev, int ioaddr,
+static int corkscrew_setup(struct net_device *dev, int ioaddr,
struct pnp_dev *idev, int card_number)
{
struct corkscrew_private *vp = netdev_priv(dev);
@@ -691,6 +689,8 @@ static void corkscrew_setup(struct net_device *dev, int ioaddr,
dev->get_stats = &corkscrew_get_stats;
dev->set_multicast_list = &set_rx_mode;
dev->ethtool_ops = &netdev_ethtool_ops;
+
+ return register_netdev(dev);
}
@@ -822,7 +822,7 @@ static int corkscrew_open(struct net_device *dev)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = isa_virt_to_bus(skb->tail);
+ vp->rx_ring[i].addr = isa_virt_to_bus(skb->data);
}
vp->rx_ring[i - 1].next = isa_virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */
outl(isa_virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
@@ -1406,7 +1406,7 @@ static int boomerang_rx(struct net_device *dev)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[entry].addr = isa_virt_to_bus(skb->tail);
+ vp->rx_ring[entry].addr = isa_virt_to_bus(skb->data);
vp->rx_skbuff[entry] = skb;
}
vp->rx_ring[entry].status = 0; /* Clear complete bit. */
diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c
index 8f6b2fa13e28..9e1fe2e0478c 100644
--- a/drivers/net/3c523.c
+++ b/drivers/net/3c523.c
@@ -572,6 +572,10 @@ static int __init do_elmc_probe(struct net_device *dev)
dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */
#endif
+ retval = register_netdev(dev);
+ if (retval)
+ goto err_out;
+
return 0;
err_out:
mca_set_adapter_procfn(slot, NULL, NULL);
@@ -600,12 +604,7 @@ struct net_device * __init elmc_probe(int unit)
err = do_elmc_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -1275,6 +1274,7 @@ module_param_array(irq, int, NULL, 0);
module_param_array(io, int, NULL, 0);
MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");
MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");
+MODULE_LICENSE("GPL");
int init_module(void)
{
@@ -1288,12 +1288,9 @@ int init_module(void)
dev->irq=irq[this_dev];
dev->base_addr=io[this_dev];
if (do_elmc_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_elmc[this_dev] = dev;
- found++;
- continue;
- }
- cleanup_card(dev);
+ dev_elmc[this_dev] = dev;
+ found++;
+ continue;
}
free_netdev(dev);
if (io[this_dev]==0)
diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c
index 80ec9aa575bb..07746b95fd83 100644
--- a/drivers/net/3c59x.c
+++ b/drivers/net/3c59x.c
@@ -1802,7 +1802,7 @@ vortex_open(struct net_device *dev)
break; /* Bad news! */
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
+ vp->rx_ring[i].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
}
if (i != RX_RING_SIZE) {
int j;
@@ -2632,7 +2632,7 @@ boomerang_rx(struct net_device *dev)
pci_dma_sync_single_for_cpu(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
/* 'skb_put()' points to the start of sk_buff data area. */
memcpy(skb_put(skb, pkt_len),
- vp->rx_skbuff[entry]->tail,
+ vp->rx_skbuff[entry]->data,
pkt_len);
pci_dma_sync_single_for_device(VORTEX_PCI(vp), dma, PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
vp->rx_copy++;
@@ -2678,7 +2678,7 @@ boomerang_rx(struct net_device *dev)
}
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
- vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->tail, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
+ vp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(VORTEX_PCI(vp), skb->data, PKT_BUF_SZ, PCI_DMA_FROMDEVICE));
vp->rx_skbuff[entry] = skb;
}
vp->rx_ring[entry].status = 0; /* Clear complete bit. */
diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c
index 72cdf19e1be1..7b293f01c9ed 100644
--- a/drivers/net/8139cp.c
+++ b/drivers/net/8139cp.c
@@ -61,6 +61,7 @@
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/ethtool.h>
#include <linux/mii.h>
@@ -595,7 +596,7 @@ rx_status_loop:
mapping =
cp->rx_skb[rx_tail].mapping =
- pci_map_single(cp->pdev, new_skb->tail,
+ pci_map_single(cp->pdev, new_skb->data,
buflen, PCI_DMA_FROMDEVICE);
cp->rx_skb[rx_tail].skb = new_skb;
@@ -1100,7 +1101,7 @@ static int cp_refill_rx (struct cp_private *cp)
skb_reserve(skb, RX_OFFSET);
cp->rx_skb[i].mapping = pci_map_single(cp->pdev,
- skb->tail, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb->data, cp->rx_buf_sz, PCI_DMA_FROMDEVICE);
cp->rx_skb[i].skb = skb;
cp->rx_ring[i].opts2 = 0;
@@ -1515,22 +1516,22 @@ static void cp_get_ethtool_stats (struct net_device *dev,
struct ethtool_stats *estats, u64 *tmp_stats)
{
struct cp_private *cp = netdev_priv(dev);
- unsigned int work = 100;
int i;
+ memset(cp->nic_stats, 0, sizeof(struct cp_dma_stats));
+
/* begin NIC statistics dump */
cpw32(StatsAddr + 4, (cp->nic_stats_dma >> 16) >> 16);
cpw32(StatsAddr, (cp->nic_stats_dma & 0xffffffff) | DumpStats);
cpr32(StatsAddr);
- while (work-- > 0) {
+ for (i = 0; i < 1000; i++) {
if ((cpr32(StatsAddr) & DumpStats) == 0)
break;
- cpu_relax();
+ udelay(10);
}
-
- if (cpr32(StatsAddr) & DumpStats)
- return /* -EIO */;
+ cpw32(StatsAddr, 0);
+ cpw32(StatsAddr + 4, 0);
i = 0;
tmp_stats[i++] = le64_to_cpu(cp->nic_stats->tx_ok);
@@ -1732,19 +1733,19 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
/* Configure DMA attributes. */
if ((sizeof(dma_addr_t) > 4) &&
- !pci_set_consistent_dma_mask(pdev, 0xffffffffffffffffULL) &&
- !pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+ !pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) &&
+ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
pci_using_dac = 1;
} else {
pci_using_dac = 0;
- rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR PFX "No usable DMA configuration, "
"aborting.\n");
goto err_out_res;
}
- rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR PFX "No usable consistent DMA configuration, "
"aborting.\n");
diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c
index 047202c4d9a8..5a4a08a7c951 100644
--- a/drivers/net/8139too.c
+++ b/drivers/net/8139too.c
@@ -1606,7 +1606,7 @@ static int rtl8139_thread (void *data)
do {
timeout = interruptible_sleep_on_timeout (&tp->thr_wait, timeout);
/* make swsusp happy with our thread */
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
} while (!signal_pending (current) && (timeout > 0));
if (signal_pending (current)) {
diff --git a/drivers/net/82596.c b/drivers/net/82596.c
index 65f97b1dc581..13b745b39667 100644
--- a/drivers/net/82596.c
+++ b/drivers/net/82596.c
@@ -546,11 +546,11 @@ static inline void init_rx_bufs(struct net_device *dev)
rbd->b_next = WSWAPrbd(virt_to_bus(rbd+1));
rbd->b_addr = WSWAPrbd(virt_to_bus(rbd));
rbd->skb = skb;
- rbd->v_data = skb->tail;
- rbd->b_data = WSWAPchar(virt_to_bus(skb->tail));
+ rbd->v_data = skb->data;
+ rbd->b_data = WSWAPchar(virt_to_bus(skb->data));
rbd->size = PKT_BUF_SZ;
#ifdef __mc68000__
- cache_clear(virt_to_phys(skb->tail), PKT_BUF_SZ);
+ cache_clear(virt_to_phys(skb->data), PKT_BUF_SZ);
#endif
}
lp->rbd_head = lp->rbds;
@@ -816,10 +816,10 @@ static inline int i596_rx(struct net_device *dev)
rx_in_place = 1;
rbd->skb = newskb;
newskb->dev = dev;
- rbd->v_data = newskb->tail;
- rbd->b_data = WSWAPchar(virt_to_bus(newskb->tail));
+ rbd->v_data = newskb->data;
+ rbd->b_data = WSWAPchar(virt_to_bus(newskb->data));
#ifdef __mc68000__
- cache_clear(virt_to_phys(newskb->tail), PKT_BUF_SZ);
+ cache_clear(virt_to_phys(newskb->data), PKT_BUF_SZ);
#endif
}
else
@@ -840,7 +840,7 @@ memory_squeeze:
skb->protocol=eth_type_trans(skb,dev);
skb->len = pkt_len;
#ifdef __mc68000__
- cache_clear(virt_to_phys(rbd->skb->tail),
+ cache_clear(virt_to_phys(rbd->skb->data),
pkt_len);
#endif
netif_rx(skb);
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index fa9f76c953dd..9a07ff7a7777 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -3,6 +3,8 @@
# Network device configuration
#
+menu "Network device support"
+
config NETDEVICES
depends on NET
bool "Network device support"
@@ -1320,7 +1322,7 @@ config FORCEDETH
config CS89x0
tristate "CS89x0 support"
- depends on NET_PCI && (ISA || ARCH_IXDP2X01)
+ depends on (NET_PCI && (ISA || ARCH_IXDP2X01)) || ARCH_PNX0105
---help---
Support for CS89x0 chipset based Ethernet cards. If you have a
network (Ethernet) card of this type, say Y and read the
@@ -1488,14 +1490,14 @@ config 8139CP
will be called 8139cp. This is recommended.
config 8139TOO
- tristate "RealTek RTL-8139 PCI Fast Ethernet Adapter support"
+ tristate "RealTek RTL-8129/8130/8139 PCI Fast Ethernet Adapter support"
depends on NET_PCI && PCI
select CRC32
select MII
---help---
This is a driver for the Fast Ethernet PCI network cards based on
- the RTL8139 chips. If you have one of those, say Y and read
- the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
+ the RTL 8129/8130/8139 chips. If you have one of those, say Y and
+ read the Ethernet-HOWTO <http://www.tldp.org/docs.html#howto>.
To compile this driver as a module, choose M here: the module
will be called 8139too. This is recommended.
@@ -2547,3 +2549,4 @@ config NETCONSOLE
If you want to log kernel messages over the network, enable this.
See <file:Documentation/networking/netconsole.txt> for details.
+endmenu
diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c
index 24fba36b5c1d..91791ba37769 100644
--- a/drivers/net/ac3200.c
+++ b/drivers/net/ac3200.c
@@ -146,12 +146,7 @@ struct net_device * __init ac3200_probe(int unit)
err = do_ac3200_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -273,7 +268,14 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out2;
return 0;
+out2:
+ if (ei_status.reg0)
+ iounmap((void *)dev->mem_start);
out1:
free_irq(dev->irq, dev);
out:
@@ -392,11 +394,8 @@ init_module(void)
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev]; /* Currently ignored by driver */
if (do_ac3200_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_ac32[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_ac32[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "ac3200.c: No ac3200 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c
index 6eea3a8accb7..dbecc6bf7851 100644
--- a/drivers/net/acenic.c
+++ b/drivers/net/acenic.c
@@ -58,6 +58,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -1167,9 +1168,9 @@ static int __devinit ace_init(struct net_device *dev)
/*
* Configure DMA attributes.
*/
- if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
ap->pci_using_dac = 1;
- } else if (!pci_set_dma_mask(pdev, 0xffffffffULL)) {
+ } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
ap->pci_using_dac = 0;
} else {
ecode = -ENODEV;
diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
index b7dd7260cafb..8618012df06a 100755
--- a/drivers/net/amd8111e.c
+++ b/drivers/net/amd8111e.c
@@ -87,6 +87,7 @@ Revision History:
#include <linux/if_vlan.h>
#include <linux/ctype.h>
#include <linux/crc32.h>
+#include <linux/dma-mapping.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -2006,12 +2007,11 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
}
/* Initialize DMA */
- if(!pci_dma_supported(pdev, 0xffffffff)){
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) < 0) {
printk(KERN_ERR "amd8111e: DMA not supported,"
"exiting.\n");
- goto err_free_reg;
- } else
- pdev->dma_mask = 0xffffffff;
+ goto err_free_reg;
+ }
reg_addr = pci_resource_start(pdev, 0);
reg_len = pci_resource_len(pdev, 0);
diff --git a/drivers/net/appletalk/Kconfig b/drivers/net/appletalk/Kconfig
index 69c488d933a2..b14e89004c3a 100644
--- a/drivers/net/appletalk/Kconfig
+++ b/drivers/net/appletalk/Kconfig
@@ -1,6 +1,33 @@
#
# Appletalk driver configuration
#
+config ATALK
+ tristate "Appletalk protocol support"
+ select LLC
+ ---help---
+ AppleTalk is the protocol that Apple computers can use to communicate
+ on a network. If your Linux box is connected to such a network and you
+ wish to connect to it, say Y. You will need to use the netatalk package
+ so that your Linux box can act as a print and file server for Macs as
+ well as access AppleTalk printers. Check out
+ <http://www.zettabyte.net/netatalk/> on the WWW for details.
+ EtherTalk is the name used for AppleTalk over Ethernet and the
+ cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
+ network using serial links. EtherTalk and LocalTalk are fully
+ supported by Linux.
+
+ General information about how to connect Linux, Windows machines and
+ Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. The
+ NET-3-HOWTO, available from
+ <http://www.tldp.org/docs.html#howto>, contains valuable
+ information as well.
+
+ To compile this driver as a module, choose M here: the module will be
+ called appletalk. You almost certainly want to compile it as a
+ module so you can restart your AppleTalk stack without rebooting
+ your machine. I hear that the GNU boycott of Apple is over, so
+ even politically correct people are allowed to say Y here.
+
config DEV_APPLETALK
bool "Appletalk interfaces support"
depends on ATALK
diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
index 2e28c201dcc0..942a2819576c 100644
--- a/drivers/net/arm/etherh.c
+++ b/drivers/net/arm/etherh.c
@@ -68,7 +68,6 @@ struct etherh_priv {
void __iomem *dma_base;
unsigned int id;
void __iomem *ctrl_port;
- void __iomem *base;
unsigned char ctrl;
u32 supported;
};
@@ -178,7 +177,7 @@ etherh_setif(struct net_device *dev)
switch (etherh_priv(dev)->id) {
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
- addr = etherh_priv(dev)->base + EN0_RCNTHI;
+ addr = (void *)dev->base_addr + EN0_RCNTHI;
switch (dev->if_port) {
case IF_PORT_10BASE2:
@@ -219,7 +218,7 @@ etherh_getifstat(struct net_device *dev)
switch (etherh_priv(dev)->id) {
case PROD_I3_ETHERLAN600:
case PROD_I3_ETHERLAN600A:
- addr = etherh_priv(dev)->base + EN0_RCNTHI;
+ addr = (void *)dev->base_addr + EN0_RCNTHI;
switch (dev->if_port) {
case IF_PORT_10BASE2:
stat = 1;
@@ -282,7 +281,7 @@ static void
etherh_reset(struct net_device *dev)
{
struct ei_device *ei_local = netdev_priv(dev);
- void __iomem *addr = etherh_priv(dev)->base;
+ void __iomem *addr = (void *)dev->base_addr;
writeb(E8390_NODMA+E8390_PAGE0+E8390_STOP, addr);
@@ -328,7 +327,7 @@ etherh_block_output (struct net_device *dev, int count, const unsigned char *buf
ei_local->dmaing = 1;
- addr = etherh_priv(dev)->base;
+ addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base;
count = (count + 1) & ~1;
@@ -388,7 +387,7 @@ etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int
ei_local->dmaing = 1;
- addr = etherh_priv(dev)->base;
+ addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base;
buf = skb->data;
@@ -428,7 +427,7 @@ etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_p
ei_local->dmaing = 1;
- addr = etherh_priv(dev)->base;
+ addr = (void *)dev->base_addr;
dma_base = etherh_priv(dev)->dma_base;
writeb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
@@ -697,8 +696,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
eh->ctrl_port = eh->ioc_fast;
}
- eh->base = eh->memc + data->ns8390_offset;
- dev->base_addr = (unsigned long)eh->base;
+ dev->base_addr = (unsigned long)eh->memc + data->ns8390_offset;
eh->dma_base = eh->memc + data->dataport_offset;
eh->ctrl_port += data->ctrlport_offset;
diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c
index b8ab2b6355eb..e613cc289749 100644
--- a/drivers/net/at1700.c
+++ b/drivers/net/at1700.c
@@ -34,10 +34,6 @@
only is it difficult to detect, it also moves around in I/O space in
response to inb()s from other device probes!
*/
-/*
- 99/03/03 Allied Telesis RE1000 Plus support by T.Hagawa
- 99/12/30 port to 2.3.35 by K.Takai
-*/
#include <linux/config.h>
#include <linux/errno.h>
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 3fe8ba992c38..94939f570f78 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -1285,6 +1285,9 @@ static int b44_open(struct net_device *dev)
b44_init_hw(bp);
bp->flags |= B44_FLAG_INIT_COMPLETE;
+ netif_carrier_off(dev);
+ b44_check_phy(bp);
+
spin_unlock_irq(&bp->lock);
init_timer(&bp->timer);
@@ -1927,6 +1930,7 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state)
b44_free_rings(bp);
spin_unlock_irq(&bp->lock);
+ pci_disable_device(pdev);
return 0;
}
@@ -1936,6 +1940,8 @@ static int b44_resume(struct pci_dev *pdev)
struct b44 *bp = netdev_priv(dev);
pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
if (!netif_running(dev))
return 0;
diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c
index 00e5257b176f..8dc657fc8afb 100644
--- a/drivers/net/bmac.c
+++ b/drivers/net/bmac.c
@@ -1261,7 +1261,7 @@ static void bmac_reset_and_enable(struct net_device *dev)
spin_unlock_irqrestore(&bp->lock, flags);
}
-static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
int j, rev, ret;
struct bmac_data *bp;
@@ -1645,16 +1645,13 @@ static int __devexit bmac_remove(struct macio_dev *mdev)
return 0;
}
-static struct of_match bmac_match[] =
+static struct of_device_id bmac_match[] =
{
{
.name = "bmac",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH,
.data = (void *)0,
},
{
- .name = OF_ANY_MATCH,
.type = "network",
.compatible = "bmac+",
.data = (void *)1,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 6233c4ffb805..a2e8dda5afac 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -2346,7 +2346,6 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
{
struct slave *slave, *start_at;
struct bonding *bond = dev->priv;
- struct ethhdr *data = (struct ethhdr *)skb->data;
int slave_agg_no;
int slaves_in_agg;
int agg_id;
@@ -2377,7 +2376,7 @@ int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev)
goto out;
}
- slave_agg_no = (data->h_dest[5]^bond->dev->dev_addr[5]) % slaves_in_agg;
+ slave_agg_no = bond->xmit_hash_policy(skb, dev, slaves_in_agg);
bond_for_each_slave(bond, slave, i) {
struct aggregator *agg = SLAVE_AD_INFO(slave).port.aggregator;
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 269a5e407349..2c930da90a85 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -475,7 +475,18 @@
* Solution is to move call to dev_remove_pack outside of the
* spinlock.
* Set version to 2.6.1.
- *
+ * 2005/06/05 - Jay Vosburgh <fubar@us.ibm.com>
+ * - Support for generating gratuitous ARPs in active-backup mode.
+ * Includes support for VLAN tagging all bonding-generated ARPs
+ * as needed. Set version to 2.6.2.
+ * 2005/06/08 - Jason Gabler <jygabler at lbl dot gov>
+ * - alternate hashing policy support for mode 2
+ * * Added kernel parameter "xmit_hash_policy" to allow the selection
+ * of different hashing policies for mode 2. The original mode 2
+ * policy is the default, now found in xmit_hash_policy_layer2().
+ * * Added xmit_hash_policy_layer34()
+ * - Modified by Jay Vosburgh <fubar@us.ibm.com> to also support mode 4.
+ * Set version to 2.6.3.
*/
//#define BONDING_DEBUG 1
@@ -490,7 +501,10 @@
#include <linux/ptrace.h>
#include <linux/ioport.h>
#include <linux/in.h>
+#include <net/ip.h>
#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
@@ -519,6 +533,7 @@
#include <linux/ethtool.h>
#include <linux/if_vlan.h>
#include <linux/if_bonding.h>
+#include <net/route.h>
#include "bonding.h"
#include "bond_3ad.h"
#include "bond_alb.h"
@@ -537,6 +552,7 @@ static int use_carrier = 1;
static char *mode = NULL;
static char *primary = NULL;
static char *lacp_rate = NULL;
+static char *xmit_hash_policy = NULL;
static int arp_interval = BOND_LINK_ARP_INTERV;
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
@@ -556,6 +572,8 @@ module_param(primary, charp, 0);
MODULE_PARM_DESC(primary, "Primary network device to use");
module_param(lacp_rate, charp, 0);
MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner (slow/fast)");
+module_param(xmit_hash_policy, charp, 0);
+MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method : 0 for layer 2 (default), 1 for layer 3+4");
module_param(arp_interval, int, 0);
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
module_param_array(arp_ip_target, charp, NULL, 0);
@@ -574,8 +592,8 @@ static struct proc_dir_entry *bond_proc_dir = NULL;
static u32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ;
static int arp_ip_count = 0;
-static u32 my_ip = 0;
static int bond_mode = BOND_MODE_ROUNDROBIN;
+static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2;
static int lacp_fast = 0;
static int app_abi_ver = 0;
static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
@@ -585,7 +603,6 @@ static int orig_app_abi_ver = -1; /* This is used to save the first ABI version
* command comes from an application using
* another ABI version.
*/
-
struct bond_parm_tbl {
char *modename;
int mode;
@@ -608,9 +625,16 @@ static struct bond_parm_tbl bond_mode_tbl[] = {
{ NULL, -1},
};
+static struct bond_parm_tbl xmit_hashtype_tbl[] = {
+{ "layer2", BOND_XMIT_POLICY_LAYER2},
+{ "layer3+4", BOND_XMIT_POLICY_LAYER34},
+{ NULL, -1},
+};
+
/*-------------------------- Forward declarations ---------------------------*/
-static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode);
+static inline void bond_set_mode_ops(struct bonding *bond, int mode);
+static void bond_send_gratuitous_arp(struct bonding *bond);
/*---------------------------- General routines -----------------------------*/
@@ -659,6 +683,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id)
INIT_LIST_HEAD(&vlan->vlan_list);
vlan->vlan_id = vlan_id;
+ vlan->vlan_ip = 0;
write_lock_bh(&bond->lock);
@@ -1468,16 +1493,6 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act
}
}
- if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
- if (old_active) {
- bond_set_slave_inactive_flags(old_active);
- }
-
- if (new_active) {
- bond_set_slave_active_flags(new_active);
- }
- }
-
if (USES_PRIMARY(bond->params.mode)) {
bond_mc_swap(bond, new_active, old_active);
}
@@ -1488,6 +1503,17 @@ static void bond_change_active_slave(struct bonding *bond, struct slave *new_act
} else {
bond->curr_active_slave = new_active;
}
+
+ if (bond->params.mode == BOND_MODE_ACTIVEBACKUP) {
+ if (old_active) {
+ bond_set_slave_inactive_flags(old_active);
+ }
+
+ if (new_active) {
+ bond_set_slave_active_flags(new_active);
+ }
+ bond_send_gratuitous_arp(bond);
+ }
}
/**
@@ -2694,15 +2720,180 @@ out:
read_unlock(&bond->lock);
}
+
+static u32 bond_glean_dev_ip(struct net_device *dev)
+{
+ struct in_device *idev;
+ struct in_ifaddr *ifa;
+ u32 addr = 0;
+
+ if (!dev)
+ return 0;
+
+ rcu_read_lock();
+ idev = __in_dev_get(dev);
+ if (!idev)
+ goto out;
+
+ ifa = idev->ifa_list;
+ if (!ifa)
+ goto out;
+
+ addr = ifa->ifa_local;
+out:
+ rcu_read_unlock();
+ return addr;
+}
+
+static int bond_has_ip(struct bonding *bond)
+{
+ struct vlan_entry *vlan, *vlan_next;
+
+ if (bond->master_ip)
+ return 1;
+
+ if (list_empty(&bond->vlan_list))
+ return 0;
+
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ if (vlan->vlan_ip)
+ return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * We go to the (large) trouble of VLAN tagging ARP frames because
+ * switches in VLAN mode (especially if ports are configured as
+ * "native" to a VLAN) might not pass non-tagged frames.
+ */
+static void bond_arp_send(struct net_device *slave_dev, int arp_op, u32 dest_ip, u32 src_ip, unsigned short vlan_id)
+{
+ struct sk_buff *skb;
+
+ dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op,
+ slave_dev->name, dest_ip, src_ip, vlan_id);
+
+ skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip,
+ NULL, slave_dev->dev_addr, NULL);
+
+ if (!skb) {
+ printk(KERN_ERR DRV_NAME ": ARP packet allocation failed\n");
+ return;
+ }
+ if (vlan_id) {
+ skb = vlan_put_tag(skb, vlan_id);
+ if (!skb) {
+ printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n");
+ return;
+ }
+ }
+ arp_xmit(skb);
+}
+
+
static void bond_arp_send_all(struct bonding *bond, struct slave *slave)
{
- int i;
+ int i, vlan_id, rv;
u32 *targets = bond->params.arp_targets;
+ struct vlan_entry *vlan, *vlan_next;
+ struct net_device *vlan_dev;
+ struct flowi fl;
+ struct rtable *rt;
for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
- arp_send(ARPOP_REQUEST, ETH_P_ARP, targets[i], slave->dev,
- my_ip, NULL, slave->dev->dev_addr,
- NULL);
+ dprintk("basa: target %x\n", targets[i]);
+ if (list_empty(&bond->vlan_list)) {
+ dprintk("basa: empty vlan: arp_send\n");
+ bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+ bond->master_ip, 0);
+ continue;
+ }
+
+ /*
+ * If VLANs are configured, we do a route lookup to
+ * determine which VLAN interface would be used, so we
+ * can tag the ARP with the proper VLAN tag.
+ */
+ memset(&fl, 0, sizeof(fl));
+ fl.fl4_dst = targets[i];
+ fl.fl4_tos = RTO_ONLINK;
+
+ rv = ip_route_output_key(&rt, &fl);
+ if (rv) {
+ if (net_ratelimit()) {
+ printk(KERN_WARNING DRV_NAME
+ ": %s: no route to arp_ip_target %u.%u.%u.%u\n",
+ bond->dev->name, NIPQUAD(fl.fl4_dst));
+ }
+ continue;
+ }
+
+ /*
+ * This target is not on a VLAN
+ */
+ if (rt->u.dst.dev == bond->dev) {
+ dprintk("basa: rtdev == bond->dev: arp_send\n");
+ bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+ bond->master_ip, 0);
+ continue;
+ }
+
+ vlan_id = 0;
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ if (vlan_dev == rt->u.dst.dev) {
+ vlan_id = vlan->vlan_id;
+ dprintk("basa: vlan match on %s %d\n",
+ vlan_dev->name, vlan_id);
+ break;
+ }
+ }
+
+ if (vlan_id) {
+ bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i],
+ vlan->vlan_ip, vlan_id);
+ continue;
+ }
+
+ if (net_ratelimit()) {
+ printk(KERN_WARNING DRV_NAME
+ ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n",
+ bond->dev->name, NIPQUAD(fl.fl4_dst),
+ rt->u.dst.dev ? rt->u.dst.dev->name : "NULL");
+ }
+ }
+}
+
+/*
+ * Kick out a gratuitous ARP for an IP on the bonding master plus one
+ * for each VLAN above us.
+ */
+static void bond_send_gratuitous_arp(struct bonding *bond)
+{
+ struct slave *slave = bond->curr_active_slave;
+ struct vlan_entry *vlan;
+ struct net_device *vlan_dev;
+
+ dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name,
+ slave ? slave->dev->name : "NULL");
+ if (!slave)
+ return;
+
+ if (bond->master_ip) {
+ bond_arp_send(slave->dev, ARPOP_REPLY, bond->master_ip,
+ bond->master_ip, 0);
+ }
+
+ list_for_each_entry(vlan, &bond->vlan_list, vlan_list) {
+ vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ if (vlan->vlan_ip) {
+ bond_arp_send(slave->dev, ARPOP_REPLY, vlan->vlan_ip,
+ vlan->vlan_ip, vlan->vlan_id);
+ }
}
}
@@ -2781,7 +2972,7 @@ static void bond_loadbalance_arp_mon(struct net_device *bond_dev)
*/
if (((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
(((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
- my_ip)) {
+ bond_has_ip(bond))) {
slave->link = BOND_LINK_DOWN;
slave->state = BOND_STATE_BACKUP;
@@ -2920,7 +3111,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
if ((slave != bond->curr_active_slave) &&
(!bond->current_arp_slave) &&
(((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
- my_ip)) {
+ bond_has_ip(bond))) {
/* a backup slave has gone down; three times
* the delta allows the current slave to be
* taken out before the backup slave.
@@ -2966,8 +3157,8 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
* if it is up and needs to take over as the curr_active_slave
*/
if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
- (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
- my_ip)) &&
+ (((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
+ bond_has_ip(bond))) &&
((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
slave->link = BOND_LINK_DOWN;
@@ -3019,7 +3210,7 @@ static void bond_activebackup_arp_mon(struct net_device *bond_dev)
/* the current slave must tx an arp to ensure backup slaves
* rx traffic
*/
- if (slave && my_ip) {
+ if (slave && bond_has_ip(bond)) {
bond_arp_send_all(bond, slave);
}
}
@@ -3471,10 +3662,67 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
return NOTIFY_DONE;
}
+/*
+ * bond_inetaddr_event: handle inetaddr notifier chain events.
+ *
+ * We keep track of device IPs primarily to use as source addresses in
+ * ARP monitor probes (rather than spewing out broadcasts all the time).
+ *
+ * We track one IP for the main device (if it has one), plus one per VLAN.
+ */
+static int bond_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr)
+{
+ struct in_ifaddr *ifa = ptr;
+ struct net_device *vlan_dev, *event_dev = ifa->ifa_dev->dev;
+ struct bonding *bond, *bond_next;
+ struct vlan_entry *vlan, *vlan_next;
+
+ list_for_each_entry_safe(bond, bond_next, &bond_dev_list, bond_list) {
+ if (bond->dev == event_dev) {
+ switch (event) {
+ case NETDEV_UP:
+ bond->master_ip = ifa->ifa_local;
+ return NOTIFY_OK;
+ case NETDEV_DOWN:
+ bond->master_ip = bond_glean_dev_ip(bond->dev);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+
+ if (list_empty(&bond->vlan_list))
+ continue;
+
+ list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
+ vlan_list) {
+ vlan_dev = bond->vlgrp->vlan_devices[vlan->vlan_id];
+ if (vlan_dev == event_dev) {
+ switch (event) {
+ case NETDEV_UP:
+ vlan->vlan_ip = ifa->ifa_local;
+ return NOTIFY_OK;
+ case NETDEV_DOWN:
+ vlan->vlan_ip =
+ bond_glean_dev_ip(vlan_dev);
+ return NOTIFY_OK;
+ default:
+ return NOTIFY_DONE;
+ }
+ }
+ }
+ }
+ return NOTIFY_DONE;
+}
+
static struct notifier_block bond_netdev_notifier = {
.notifier_call = bond_netdev_event,
};
+static struct notifier_block bond_inetaddr_notifier = {
+ .notifier_call = bond_inetaddr_event,
+};
+
/*-------------------------- Packet type handling ---------------------------*/
/* register to receive lacpdus on a bond */
@@ -3496,6 +3744,46 @@ static void bond_unregister_lacpdu(struct bonding *bond)
dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
}
+/*---------------------------- Hashing Policies -----------------------------*/
+
+/*
+ * Hash for the the output device based upon layer 3 and layer 4 data. If
+ * the packet is a frag or not TCP or UDP, just use layer 3 data. If it is
+ * altogether not IP, mimic bond_xmit_hash_policy_l2()
+ */
+static int bond_xmit_hash_policy_l34(struct sk_buff *skb,
+ struct net_device *bond_dev, int count)
+{
+ struct ethhdr *data = (struct ethhdr *)skb->data;
+ struct iphdr *iph = skb->nh.iph;
+ u16 *layer4hdr = (u16 *)((u32 *)iph + iph->ihl);
+ int layer4_xor = 0;
+
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ if (!(iph->frag_off & __constant_htons(IP_MF|IP_OFFSET)) &&
+ (iph->protocol == IPPROTO_TCP ||
+ iph->protocol == IPPROTO_UDP)) {
+ layer4_xor = htons((*layer4hdr ^ *(layer4hdr + 1)));
+ }
+ return (layer4_xor ^
+ ((ntohl(iph->saddr ^ iph->daddr)) & 0xffff)) % count;
+
+ }
+
+ return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+}
+
+/*
+ * Hash for the output device based upon layer 2 data
+ */
+static int bond_xmit_hash_policy_l2(struct sk_buff *skb,
+ struct net_device *bond_dev, int count)
+{
+ struct ethhdr *data = (struct ethhdr *)skb->data;
+
+ return (data->h_dest[5] ^ bond_dev->dev_addr[5]) % count;
+}
+
/*-------------------------- Device entry points ----------------------------*/
static int bond_open(struct net_device *bond_dev)
@@ -4060,17 +4348,6 @@ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_d
struct bonding *bond = bond_dev->priv;
int res = 1;
- /* if we are sending arp packets, try to at least
- identify our own ip address */
- if (bond->params.arp_interval && !my_ip &&
- (skb->protocol == __constant_htons(ETH_P_ARP))) {
- char *the_ip = (char *)skb->data +
- sizeof(struct ethhdr) +
- sizeof(struct arphdr) +
- ETH_ALEN;
- memcpy(&my_ip, the_ip, 4);
- }
-
read_lock(&bond->lock);
read_lock(&bond->curr_slave_lock);
@@ -4093,14 +4370,13 @@ out:
}
/*
- * in XOR mode, we determine the output device by performing xor on
- * the source and destination hw adresses. If this device is not
- * enabled, find the next slave following this xor slave.
+ * In bond_xmit_xor() , we determine the output device by using a pre-
+ * determined xmit_hash_policy(), If the selected device is not enabled,
+ * find the next active slave.
*/
static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
{
struct bonding *bond = bond_dev->priv;
- struct ethhdr *data = (struct ethhdr *)skb->data;
struct slave *slave, *start_at;
int slave_no;
int i;
@@ -4112,7 +4388,7 @@ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev)
goto out;
}
- slave_no = (data->h_dest[5]^bond_dev->dev_addr[5]) % bond->slave_cnt;
+ slave_no = bond->xmit_hash_policy(skb, bond_dev, bond->slave_cnt);
bond_for_each_slave(bond, slave, i) {
slave_no--;
@@ -4208,8 +4484,10 @@ out:
/*
* set bond mode specific net device operations
*/
-static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode)
+static inline void bond_set_mode_ops(struct bonding *bond, int mode)
{
+ struct net_device *bond_dev = bond->dev;
+
switch (mode) {
case BOND_MODE_ROUNDROBIN:
bond_dev->hard_start_xmit = bond_xmit_roundrobin;
@@ -4219,12 +4497,20 @@ static inline void bond_set_mode_ops(struct net_device *bond_dev, int mode)
break;
case BOND_MODE_XOR:
bond_dev->hard_start_xmit = bond_xmit_xor;
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+ else
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
break;
case BOND_MODE_BROADCAST:
bond_dev->hard_start_xmit = bond_xmit_broadcast;
break;
case BOND_MODE_8023AD:
bond_dev->hard_start_xmit = bond_3ad_xmit_xor;
+ if (bond->params.xmit_policy == BOND_XMIT_POLICY_LAYER34)
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l34;
+ else
+ bond->xmit_hash_policy = bond_xmit_hash_policy_l2;
break;
case BOND_MODE_TLB:
case BOND_MODE_ALB:
@@ -4273,7 +4559,7 @@ static int __init bond_init(struct net_device *bond_dev, struct bond_params *par
bond_dev->change_mtu = bond_change_mtu;
bond_dev->set_mac_address = bond_set_mac_address;
- bond_set_mode_ops(bond_dev, bond->params.mode);
+ bond_set_mode_ops(bond, bond->params.mode);
bond_dev->destructor = free_netdev;
@@ -4384,6 +4670,25 @@ static int bond_check_params(struct bond_params *params)
}
}
+ if (xmit_hash_policy) {
+ if ((bond_mode != BOND_MODE_XOR) &&
+ (bond_mode != BOND_MODE_8023AD)) {
+ printk(KERN_INFO DRV_NAME
+ ": xor_mode param is irrelevant in mode %s\n",
+ bond_mode_name(bond_mode));
+ } else {
+ xmit_hashtype = bond_parse_parm(xmit_hash_policy,
+ xmit_hashtype_tbl);
+ if (xmit_hashtype == -1) {
+ printk(KERN_ERR DRV_NAME
+ ": Error: Invalid xmit_hash_policy \"%s\"\n",
+ xmit_hash_policy == NULL ? "NULL" :
+ xmit_hash_policy);
+ return -EINVAL;
+ }
+ }
+ }
+
if (lacp_rate) {
if (bond_mode != BOND_MODE_8023AD) {
printk(KERN_INFO DRV_NAME
@@ -4595,6 +4900,7 @@ static int bond_check_params(struct bond_params *params)
/* fill params struct with the proper values */
params->mode = bond_mode;
+ params->xmit_policy = xmit_hashtype;
params->miimon = miimon;
params->arp_interval = arp_interval;
params->updelay = updelay;
@@ -4669,6 +4975,7 @@ static int __init bonding_init(void)
rtnl_unlock();
register_netdevice_notifier(&bond_netdev_notifier);
+ register_inetaddr_notifier(&bond_inetaddr_notifier);
return 0;
@@ -4684,6 +4991,7 @@ out_err:
static void __exit bonding_exit(void)
{
unregister_netdevice_notifier(&bond_netdev_notifier);
+ unregister_inetaddr_notifier(&bond_inetaddr_notifier);
rtnl_lock();
bond_free_all();
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 8c325308489d..d27f377b3eeb 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -25,6 +25,10 @@
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
+ *
+ * 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
+ * - added "xmit_policy" kernel parameter for alternate hashing policy
+ * support for mode 2
*/
#ifndef _LINUX_BONDING_H
@@ -36,8 +40,8 @@
#include "bond_3ad.h"
#include "bond_alb.h"
-#define DRV_VERSION "2.6.1"
-#define DRV_RELDATE "October 29, 2004"
+#define DRV_VERSION "2.6.3"
+#define DRV_RELDATE "June 8, 2005"
#define DRV_NAME "bonding"
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
@@ -137,6 +141,7 @@
struct bond_params {
int mode;
+ int xmit_policy;
int miimon;
int arp_interval;
int use_carrier;
@@ -149,6 +154,7 @@ struct bond_params {
struct vlan_entry {
struct list_head vlan_list;
+ u32 vlan_ip;
unsigned short vlan_id;
};
@@ -197,6 +203,8 @@ struct bonding {
#endif /* CONFIG_PROC_FS */
struct list_head bond_list;
struct dev_mc_list *mc_list;
+ int (*xmit_hash_policy)(struct sk_buff *, struct net_device *, int);
+ u32 master_ip;
u16 flags;
struct ad_bond_info ad_info;
struct alb_bond_info alb_info;
diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
index 5c5f540da26a..b96d6fb1929e 100644
--- a/drivers/net/cs89x0.c
+++ b/drivers/net/cs89x0.c
@@ -174,6 +174,13 @@ static unsigned int cs8900_irq_map[] = {1,0,0,0};
#include <asm/irq.h>
static unsigned int netcard_portlist[] __initdata = {IXDP2X01_CS8900_VIRT_BASE, 0};
static unsigned int cs8900_irq_map[] = {IRQ_IXDP2X01_CS8900, 0, 0, 0};
+#elif defined(CONFIG_ARCH_PNX0105)
+#include <asm/irq.h>
+#include <asm/arch/gpio.h>
+#define CIRRUS_DEFAULT_BASE IO_ADDRESS(EXT_STATIC2_s0_BASE + 0x200000) /* = Physical address 0x48200000 */
+#define CIRRUS_DEFAULT_IRQ VH_INTC_INT_NUM_CASCADED_INTERRUPT_1 /* Event inputs bank 1 - ID 35/bit 3 */
+static unsigned int netcard_portlist[] __initdata = {CIRRUS_DEFAULT_BASE, 0};
+static unsigned int cs8900_irq_map[] = {CIRRUS_DEFAULT_IRQ, 0, 0, 0};
#else
static unsigned int netcard_portlist[] __initdata =
{ 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0};
@@ -319,13 +326,7 @@ struct net_device * __init cs89x0_probe(int unit)
}
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- outw(PP_ChipID, dev->base_addr + ADD_PORT);
- release_region(dev->base_addr, NETCARD_IO_EXTENT);
out:
free_netdev(dev);
printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n");
@@ -437,6 +438,30 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular)
#endif
}
+#ifdef CONFIG_ARCH_PNX0105
+ initialize_ebi();
+
+ /* Map GPIO registers for the pins connected to the CS8900a. */
+ if (map_cirrus_gpio() < 0)
+ return -ENODEV;
+
+ reset_cirrus();
+
+ /* Map event-router registers. */
+ if (map_event_router() < 0)
+ return -ENODEV;
+
+ enable_cirrus_irq();
+
+ unmap_cirrus_gpio();
+ unmap_event_router();
+
+ dev->base_addr = ioaddr;
+
+ for (i = 0 ; i < 3 ; i++)
+ readreg(dev, 0);
+#endif
+
/* Grab the region so we can find another board if autoIRQ fails. */
/* WTF is going on here? */
if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, DRV_NAME)) {
@@ -678,7 +703,7 @@ 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
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
i = cs8900_irq_map[0];
#else
/* Translate the IRQ using the IRQ mapping table. */
@@ -735,7 +760,13 @@ printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT));
printk("\n");
if (net_debug)
printk("cs89x0_probe1() successful\n");
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out3;
return 0;
+out3:
+ outw(PP_ChipID, dev->base_addr + ADD_PORT);
out2:
release_region(ioaddr & ~3, NETCARD_IO_EXTENT);
out1:
@@ -1145,7 +1176,7 @@ net_open(struct net_device *dev)
int i;
int ret;
-#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this won't work */
+#if !defined(CONFIG_SH_HICOSH4) && !defined(CONFIG_ARCH_PNX0105) /* uses irq#1, so this won't work */
if (dev->irq < 2) {
/* Allow interrupts to be generated by the chip */
/* Cirrus' release had this: */
@@ -1176,7 +1207,7 @@ net_open(struct net_device *dev)
else
#endif
{
-#ifndef CONFIG_ARCH_IXDP2X01
+#if !defined(CONFIG_ARCH_IXDP2X01) && !defined(CONFIG_ARCH_PNX0105)
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);
@@ -1261,6 +1292,9 @@ net_open(struct net_device *dev)
case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break;
default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2);
}
+#ifdef CONFIG_ARCH_PNX0105
+ result = A_CNF_10B_T;
+#endif
if (!result) {
printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name);
release_irq:
@@ -1831,13 +1865,6 @@ init_module(void)
if (ret)
goto out;
- if (register_netdev(dev) != 0) {
- printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io);
- ret = -ENXIO;
- outw(PP_ChipID, dev->base_addr + ADD_PORT);
- release_region(dev->base_addr, NETCARD_IO_EXTENT);
- goto out;
- }
dev_cs89x0 = dev;
return 0;
out:
diff --git a/drivers/net/cs89x0.h b/drivers/net/cs89x0.h
index b0ef7ad2baad..bd3ad8e6cce9 100644
--- a/drivers/net/cs89x0.h
+++ b/drivers/net/cs89x0.h
@@ -16,7 +16,7 @@
#include <linux/config.h>
-#ifdef CONFIG_ARCH_IXDP2X01
+#if defined(CONFIG_ARCH_IXDP2X01) || defined(CONFIG_ARCH_PNX0105)
/* IXDP2401/IXDP2801 uses dword-aligned register addressing */
#define CS89x0_PORT(reg) ((reg) * 2)
#else
diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c
index a6aa56598f27..5acd35c312ac 100644
--- a/drivers/net/defxx.c
+++ b/drivers/net/defxx.c
@@ -191,6 +191,7 @@
* Feb 2001 davej PCI enable cleanups.
* 04 Aug 2003 macro Converted to the DMA API.
* 14 Aug 2004 macro Fix device names reported.
+ * 14 Jun 2005 macro Use irqreturn_t.
*/
/* Include files */
@@ -217,8 +218,8 @@
/* Version information string should be updated prior to each new release! */
#define DRV_NAME "defxx"
-#define DRV_VERSION "v1.07"
-#define DRV_RELDATE "2004/08/14"
+#define DRV_VERSION "v1.08"
+#define DRV_RELDATE "2005/06/14"
static char version[] __devinitdata =
DRV_NAME ": " DRV_VERSION " " DRV_RELDATE
@@ -247,7 +248,8 @@ static int dfx_close(struct net_device *dev);
static void dfx_int_pr_halt_id(DFX_board_t *bp);
static void dfx_int_type_0_process(DFX_board_t *bp);
static void dfx_int_common(struct net_device *dev);
-static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t dfx_interrupt(int irq, void *dev_id,
+ struct pt_regs *regs);
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
static void dfx_ctl_set_multicast_list(struct net_device *dev);
@@ -437,7 +439,8 @@ static int __devinit dfx_init_one_pci_or_eisa(struct pci_dev *pdev, long ioaddr)
}
SET_MODULE_OWNER(dev);
- SET_NETDEV_DEV(dev, &pdev->dev);
+ if (pdev != NULL)
+ SET_NETDEV_DEV(dev, &pdev->dev);
bp = dev->priv;
@@ -1225,7 +1228,7 @@ static int dfx_open(struct net_device *dev)
/* Register IRQ - support shared interrupts by passing device ptr */
- ret = request_irq(dev->irq, (void *)dfx_interrupt, SA_SHIRQ, dev->name, dev);
+ ret = request_irq(dev->irq, dfx_interrupt, SA_SHIRQ, dev->name, dev);
if (ret) {
printk(KERN_ERR "%s: Requested IRQ %d is busy\n", dev->name, dev->irq);
return ret;
@@ -1680,13 +1683,13 @@ static void dfx_int_common(struct net_device *dev)
* =================
* = dfx_interrupt =
* =================
- *
+ *
* Overview:
* Interrupt processing routine
- *
+ *
* Returns:
- * None
- *
+ * Whether a valid interrupt was seen.
+ *
* Arguments:
* irq - interrupt vector
* dev_id - pointer to device information
@@ -1699,7 +1702,8 @@ static void dfx_int_common(struct net_device *dev)
* structure context.
*
* Return Codes:
- * None
+ * IRQ_HANDLED - an IRQ was handled.
+ * IRQ_NONE - no IRQ was handled.
*
* Assumptions:
* The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
@@ -1712,60 +1716,70 @@ static void dfx_int_common(struct net_device *dev)
* Interrupts are disabled, then reenabled at the adapter.
*/
-static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
- {
+static irqreturn_t dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
struct net_device *dev = dev_id;
DFX_board_t *bp; /* private board structure pointer */
- u8 tmp; /* used for disabling/enabling ints */
/* Get board pointer only if device structure is valid */
bp = dev->priv;
- spin_lock(&bp->lock);
-
/* See if we're already servicing an interrupt */
/* Service adapter interrupts */
- if (bp->bus_type == DFX_BUS_TYPE_PCI)
- {
- /* Disable PDQ-PFI interrupts at PFI */
+ if (bp->bus_type == DFX_BUS_TYPE_PCI) {
+ u32 status;
- dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL, PFI_MODE_M_DMA_ENB);
+ dfx_port_read_long(bp, PFI_K_REG_STATUS, &status);
+ if (!(status & PFI_STATUS_M_PDQ_INT))
+ return IRQ_NONE;
- /* Call interrupt service routine for this adapter */
+ spin_lock(&bp->lock);
+
+ /* Disable PDQ-PFI interrupts at PFI */
+ dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
+ PFI_MODE_M_DMA_ENB);
+ /* Call interrupt service routine for this adapter */
dfx_int_common(dev);
/* Clear PDQ interrupt status bit and reenable interrupts */
-
- dfx_port_write_long(bp, PFI_K_REG_STATUS, PFI_STATUS_M_PDQ_INT);
+ dfx_port_write_long(bp, PFI_K_REG_STATUS,
+ PFI_STATUS_M_PDQ_INT);
dfx_port_write_long(bp, PFI_K_REG_MODE_CTRL,
- (PFI_MODE_M_PDQ_INT_ENB + PFI_MODE_M_DMA_ENB));
- }
- else
- {
- /* Disable interrupts at the ESIC */
+ (PFI_MODE_M_PDQ_INT_ENB |
+ PFI_MODE_M_DMA_ENB));
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
- tmp &= ~PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
+ spin_unlock(&bp->lock);
+ } else {
+ u8 status;
- /* Call interrupt service routine for this adapter */
+ dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ if (!(status & PI_CONFIG_STAT_0_M_PEND))
+ return IRQ_NONE;
+ spin_lock(&bp->lock);
+
+ /* Disable interrupts at the ESIC */
+ status &= ~PI_CONFIG_STAT_0_M_INT_ENB;
+ dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
+
+ /* Call interrupt service routine for this adapter */
dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
+ dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &status);
+ status |= PI_CONFIG_STAT_0_M_INT_ENB;
+ dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, status);
- dfx_port_read_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, &tmp);
- tmp |= PI_CONFIG_STAT_0_M_INT_ENB;
- dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
- }
-
- spin_unlock(&bp->lock);
+ spin_unlock(&bp->lock);
}
+ return IRQ_HANDLED;
+}
+
/*
* =====================
diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c
index aa42b7a27735..430c628279b3 100644
--- a/drivers/net/dl2k.c
+++ b/drivers/net/dl2k.c
@@ -547,7 +547,7 @@ rio_timer (unsigned long data)
skb_reserve (skb, 2);
np->rx_ring[entry].fraginfo =
cpu_to_le64 (pci_map_single
- (np->pdev, skb->tail, np->rx_buf_sz,
+ (np->pdev, skb->data, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
}
np->rx_ring[entry].fraginfo |=
@@ -618,7 +618,7 @@ alloc_list (struct net_device *dev)
/* Rubicon now supports 40 bits of addressing space. */
np->rx_ring[i].fraginfo =
cpu_to_le64 ( pci_map_single (
- np->pdev, skb->tail, np->rx_buf_sz,
+ np->pdev, skb->data, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
np->rx_ring[i].fraginfo |= cpu_to_le64 (np->rx_buf_sz) << 48;
}
@@ -906,7 +906,7 @@ receive_packet (struct net_device *dev)
/* 16 byte align the IP header */
skb_reserve (skb, 2);
eth_copy_and_sum (skb,
- np->rx_skbuff[entry]->tail,
+ np->rx_skbuff[entry]->data,
pkt_len, 0);
skb_put (skb, pkt_len);
pci_dma_sync_single_for_device(np->pdev,
@@ -950,7 +950,7 @@ receive_packet (struct net_device *dev)
skb_reserve (skb, 2);
np->rx_ring[entry].fraginfo =
cpu_to_le64 (pci_map_single
- (np->pdev, skb->tail, np->rx_buf_sz,
+ (np->pdev, skb->data, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
}
np->rx_ring[entry].fraginfo |=
diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c
index f4ba0ffb8637..5fddc0ff8878 100644
--- a/drivers/net/dm9000.c
+++ b/drivers/net/dm9000.c
@@ -224,7 +224,7 @@ static void dm9000_outblk_32bit(void __iomem *reg, void *data, int count)
static void dm9000_inblk_8bit(void __iomem *reg, void *data, int count)
{
- readsb(reg, data, count+1);
+ readsb(reg, data, count);
}
@@ -364,7 +364,7 @@ dm9000_release_board(struct platform_device *pdev, struct board_info *db)
}
if (db->addr_res != NULL) {
- release_resource(db->data_req);
+ release_resource(db->addr_res);
kfree(db->addr_req);
}
}
diff --git a/drivers/net/e100.c b/drivers/net/e100.c
index 4a47df5a9ff9..d0fa2448761d 100644
--- a/drivers/net/e100.c
+++ b/drivers/net/e100.c
@@ -143,6 +143,7 @@
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/mii.h>
@@ -1092,11 +1093,16 @@ static int e100_phy_init(struct nic *nic)
}
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);
+ (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000))) {
+ /* enable/disable MDI/MDI-X auto-switching.
+ MDI/MDI-X auto-switching is disabled for 82551ER/QM chips */
+ if((nic->mac == mac_82551_E) || (nic->mac == mac_82551_F) ||
+ (nic->mac == mac_82551_10) || (nic->mii.force_media) ||
+ !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))
+ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, 0);
+ else
+ mdio_write(netdev, nic->mii.phy_id, MII_NCONFIG, NCONFIG_AUTO_SWITCH);
+ }
return 0;
}
@@ -1665,8 +1671,10 @@ static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs)
if(stat_ack & stat_ack_rnr)
nic->ru_running = RU_SUSPENDED;
- e100_disable_irq(nic);
- netif_rx_schedule(netdev);
+ if(likely(netif_rx_schedule_prep(netdev))) {
+ e100_disable_irq(nic);
+ __netif_rx_schedule(netdev);
+ }
return IRQ_HANDLED;
}
@@ -2286,7 +2294,7 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_disable_pdev;
}
- if((err = pci_set_dma_mask(pdev, 0xFFFFFFFFULL))) {
+ if((err = pci_set_dma_mask(pdev, DMA_32BIT_MASK))) {
DPRINTK(PROBE, ERR, "No usable DMA configuration, aborting.\n");
goto err_out_free_res;
}
@@ -2334,11 +2342,11 @@ static int __devinit e100_probe(struct pci_dev *pdev,
goto err_out_iounmap;
}
- e100_phy_init(nic);
-
if((err = e100_eeprom_load(nic)))
goto err_out_free;
+ e100_phy_init(nic);
+
memcpy(netdev->dev_addr, nic->eeprom, ETH_ALEN);
if(!is_valid_ether_addr(netdev->dev_addr)) {
DPRINTK(PROBE, ERR, "Invalid MAC address from "
@@ -2439,9 +2447,8 @@ static int e100_resume(struct pci_dev *pdev)
#endif
-static void e100_shutdown(struct device *dev)
+static void e100_shutdown(struct pci_dev *pdev)
{
- struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
struct net_device *netdev = pci_get_drvdata(pdev);
struct nic *nic = netdev_priv(netdev);
@@ -2462,11 +2469,7 @@ static struct pci_driver e100_driver = {
.suspend = e100_suspend,
.resume = e100_resume,
#endif
-
- .driver = {
- .shutdown = e100_shutdown,
- }
-
+ .shutdown = e100_shutdown,
};
static int __init e100_init_module(void)
diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h
index af1e82c5b808..092757bc721f 100644
--- a/drivers/net/e1000/e1000.h
+++ b/drivers/net/e1000/e1000.h
@@ -140,7 +140,7 @@ struct e1000_adapter;
#define E1000_RX_BUFFER_WRITE 16 /* Must be power of 2 */
#define AUTO_ALL_MODES 0
-#define E1000_EEPROM_82544_APM 0x0400
+#define E1000_EEPROM_82544_APM 0x0004
#define E1000_EEPROM_APME 0x0400
#ifndef E1000_MASTER_SLAVE
@@ -159,7 +159,7 @@ struct e1000_adapter;
* so a DMA handle can be stored along with the buffer */
struct e1000_buffer {
struct sk_buff *skb;
- uint64_t dma;
+ dma_addr_t dma;
unsigned long time_stamp;
uint16_t length;
uint16_t next_to_watch;
diff --git a/drivers/net/e1000/e1000_ethtool.c b/drivers/net/e1000/e1000_ethtool.c
index 237247f74df4..f133ff0b0b94 100644
--- a/drivers/net/e1000/e1000_ethtool.c
+++ b/drivers/net/e1000/e1000_ethtool.c
@@ -105,7 +105,7 @@ static const char e1000_gstrings_test[][ETH_GSTRING_LEN] = {
static int
e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
if(hw->media_type == e1000_media_type_copper) {
@@ -141,9 +141,9 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
SUPPORTED_FIBRE |
SUPPORTED_Autoneg);
- ecmd->advertising = (SUPPORTED_1000baseT_Full |
- SUPPORTED_FIBRE |
- SUPPORTED_Autoneg);
+ ecmd->advertising = (ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg);
ecmd->port = PORT_FIBRE;
@@ -179,13 +179,24 @@ e1000_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
static int
e1000_set_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
if(ecmd->autoneg == AUTONEG_ENABLE) {
hw->autoneg = 1;
- hw->autoneg_advertised = 0x002F;
- ecmd->advertising = 0x002F;
+ if(hw->media_type == e1000_media_type_fiber)
+ hw->autoneg_advertised = ADVERTISED_1000baseT_Full |
+ ADVERTISED_FIBRE |
+ ADVERTISED_Autoneg;
+ else
+ hw->autoneg_advertised = ADVERTISED_10baseT_Half |
+ ADVERTISED_10baseT_Full |
+ ADVERTISED_100baseT_Half |
+ ADVERTISED_100baseT_Full |
+ ADVERTISED_1000baseT_Full|
+ ADVERTISED_Autoneg |
+ ADVERTISED_TP;
+ ecmd->advertising = hw->autoneg_advertised;
} else
if(e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex))
return -EINVAL;
@@ -206,7 +217,7 @@ static void
e1000_get_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
pause->autoneg =
@@ -226,7 +237,7 @@ static int
e1000_set_pauseparam(struct net_device *netdev,
struct ethtool_pauseparam *pause)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
adapter->fc_autoneg = pause->autoneg;
@@ -259,14 +270,14 @@ e1000_set_pauseparam(struct net_device *netdev,
static uint32_t
e1000_get_rx_csum(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->rx_csum;
}
static int
e1000_set_rx_csum(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->rx_csum = data;
if(netif_running(netdev)) {
@@ -286,7 +297,7 @@ e1000_get_tx_csum(struct net_device *netdev)
static int
e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(adapter->hw.mac_type < e1000_82543) {
if (!data)
@@ -306,8 +317,8 @@ e1000_set_tx_csum(struct net_device *netdev, uint32_t data)
static int
e1000_set_tso(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
- if ((adapter->hw.mac_type < e1000_82544) ||
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ if((adapter->hw.mac_type < e1000_82544) ||
(adapter->hw.mac_type == e1000_82547))
return data ? -EINVAL : 0;
@@ -322,14 +333,14 @@ e1000_set_tso(struct net_device *netdev, uint32_t data)
static uint32_t
e1000_get_msglevel(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->msg_enable;
}
static void
e1000_set_msglevel(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->msg_enable = data;
}
@@ -344,7 +355,7 @@ static void
e1000_get_regs(struct net_device *netdev,
struct ethtool_regs *regs, void *p)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint32_t *regs_buff = p;
uint16_t phy_data;
@@ -432,7 +443,7 @@ e1000_get_regs(struct net_device *netdev,
static int
e1000_get_eeprom_len(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
return adapter->hw.eeprom.word_size * 2;
}
@@ -440,7 +451,7 @@ static int
e1000_get_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
int first_word, last_word;
@@ -486,7 +497,7 @@ static int
e1000_set_eeprom(struct net_device *netdev,
struct ethtool_eeprom *eeprom, uint8_t *bytes)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint16_t *eeprom_buff;
void *ptr;
@@ -547,7 +558,7 @@ static void
e1000_get_drvinfo(struct net_device *netdev,
struct ethtool_drvinfo *drvinfo)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
strncpy(drvinfo->driver, e1000_driver_name, 32);
strncpy(drvinfo->version, e1000_driver_version, 32);
@@ -563,7 +574,7 @@ static void
e1000_get_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
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;
@@ -584,7 +595,7 @@ static int
e1000_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *ring)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
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;
@@ -651,6 +662,9 @@ err_setup_rx:
E1000_WRITE_REG(&adapter->hw, R, (test[pat] & W)); \
value = E1000_READ_REG(&adapter->hw, R); \
if(value != (test[pat] & W & M)) { \
+ DPRINTK(DRV, ERR, "pattern test reg %04X failed: got " \
+ "0x%08X expected 0x%08X\n", \
+ E1000_##R, value, (test[pat] & W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -663,7 +677,9 @@ err_setup_rx:
uint32_t value; \
E1000_WRITE_REG(&adapter->hw, R, W & M); \
value = E1000_READ_REG(&adapter->hw, R); \
- if ((W & M) != (value & M)) { \
+ if((W & M) != (value & M)) { \
+ DPRINTK(DRV, ERR, "set/check reg %04X test failed: got 0x%08X "\
+ "expected 0x%08X\n", E1000_##R, (value & M), (W & M)); \
*data = (adapter->hw.mac_type < e1000_82543) ? \
E1000_82542_##R : E1000_##R; \
return 1; \
@@ -673,18 +689,33 @@ err_setup_rx:
static int
e1000_reg_test(struct e1000_adapter *adapter, uint64_t *data)
{
- uint32_t value;
- uint32_t i;
+ uint32_t value, before, after;
+ uint32_t i, toggle;
/* The status register is Read Only, so a write should fail.
* Some bits that get toggled are ignored.
*/
- value = (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833));
- E1000_WRITE_REG(&adapter->hw, STATUS, (0xFFFFFFFF));
- if(value != (E1000_READ_REG(&adapter->hw, STATUS) & (0xFFFFF833))) {
+ switch (adapter->hw.mac_type) {
+ case e1000_82573:
+ toggle = 0x7FFFF033;
+ break;
+ default:
+ toggle = 0xFFFFF833;
+ break;
+ }
+
+ before = E1000_READ_REG(&adapter->hw, STATUS);
+ value = (E1000_READ_REG(&adapter->hw, STATUS) & toggle);
+ E1000_WRITE_REG(&adapter->hw, STATUS, toggle);
+ after = E1000_READ_REG(&adapter->hw, STATUS) & toggle;
+ if(value != after) {
+ DPRINTK(DRV, ERR, "failed STATUS register test got: "
+ "0x%08X expected: 0x%08X\n", after, value);
*data = 1;
return 1;
}
+ /* restore previous status */
+ E1000_WRITE_REG(&adapter->hw, STATUS, before);
REG_PATTERN_TEST(FCAL, 0xFFFFFFFF, 0xFFFFFFFF);
REG_PATTERN_TEST(FCAH, 0x0000FFFF, 0xFFFFFFFF);
@@ -766,7 +797,7 @@ e1000_test_intr(int irq,
struct pt_regs *regs)
{
struct net_device *netdev = (struct net_device *) data;
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
adapter->test_icr |= E1000_READ_REG(&adapter->hw, ICR);
@@ -1214,6 +1245,7 @@ e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82541_rev_2:
case e1000_82547:
case e1000_82547_rev_2:
+ case e1000_82573:
return e1000_integrated_phy_loopback(adapter);
break;
@@ -1422,7 +1454,7 @@ static void
e1000_diag_test(struct net_device *netdev,
struct ethtool_test *eth_test, uint64_t *data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
boolean_t if_running = netif_running(netdev);
if(eth_test->flags == ETH_TEST_FL_OFFLINE) {
@@ -1482,7 +1514,7 @@ e1000_diag_test(struct net_device *netdev,
static void
e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
switch(adapter->hw.device_id) {
@@ -1527,7 +1559,7 @@ e1000_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
static int
e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
switch(adapter->hw.device_id) {
@@ -1588,22 +1620,31 @@ e1000_led_blink_callback(unsigned long data)
static int
e1000_phys_id(struct net_device *netdev, uint32_t data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(!data || data > (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (uint32_t)(MAX_SCHEDULE_TIMEOUT / HZ);
- if(!adapter->blink_timer.function) {
- init_timer(&adapter->blink_timer);
- adapter->blink_timer.function = e1000_led_blink_callback;
- adapter->blink_timer.data = (unsigned long) adapter;
+ if(adapter->hw.mac_type < e1000_82573) {
+ if(!adapter->blink_timer.function) {
+ init_timer(&adapter->blink_timer);
+ adapter->blink_timer.function = e1000_led_blink_callback;
+ adapter->blink_timer.data = (unsigned long) adapter;
+ }
+ e1000_setup_led(&adapter->hw);
+ mod_timer(&adapter->blink_timer, jiffies);
+ msleep_interruptible(data * 1000);
+ del_timer_sync(&adapter->blink_timer);
+ }
+ else {
+ E1000_WRITE_REG(&adapter->hw, LEDCTL, (E1000_LEDCTL_LED2_BLINK_RATE |
+ E1000_LEDCTL_LED1_BLINK | E1000_LEDCTL_LED2_BLINK |
+ (E1000_LEDCTL_MODE_LED_ON << E1000_LEDCTL_LED2_MODE_SHIFT) |
+ (E1000_LEDCTL_MODE_LINK_ACTIVITY << E1000_LEDCTL_LED1_MODE_SHIFT) |
+ (E1000_LEDCTL_MODE_LED_OFF << E1000_LEDCTL_LED0_MODE_SHIFT)));
+ msleep_interruptible(data * 1000);
}
- e1000_setup_led(&adapter->hw);
- mod_timer(&adapter->blink_timer, jiffies);
-
- msleep_interruptible(data * 1000);
- del_timer_sync(&adapter->blink_timer);
e1000_led_off(&adapter->hw);
clear_bit(E1000_LED_ON, &adapter->led_status);
e1000_cleanup_led(&adapter->hw);
@@ -1614,7 +1655,7 @@ e1000_phys_id(struct net_device *netdev, uint32_t data)
static int
e1000_nway_reset(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
if(netif_running(netdev)) {
e1000_down(adapter);
e1000_up(adapter);
@@ -1632,7 +1673,7 @@ static void
e1000_get_ethtool_stats(struct net_device *netdev,
struct ethtool_stats *stats, uint64_t *data)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int i;
e1000_update_stats(adapter);
diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c
index 723589b28be5..045f5426ab9a 100644
--- a/drivers/net/e1000/e1000_hw.c
+++ b/drivers/net/e1000/e1000_hw.c
@@ -354,18 +354,27 @@ e1000_set_media_type(struct e1000_hw *hw)
hw->media_type = e1000_media_type_internal_serdes;
break;
default:
- if(hw->mac_type >= e1000_82543) {
+ switch (hw->mac_type) {
+ case e1000_82542_rev2_0:
+ case e1000_82542_rev2_1:
+ hw->media_type = e1000_media_type_fiber;
+ break;
+ case e1000_82573:
+ /* The STATUS_TBIMODE bit is reserved or reused for the this
+ * device.
+ */
+ hw->media_type = e1000_media_type_copper;
+ break;
+ default:
status = E1000_READ_REG(hw, STATUS);
- if(status & E1000_STATUS_TBIMODE) {
+ if (status & E1000_STATUS_TBIMODE) {
hw->media_type = e1000_media_type_fiber;
/* tbi_compatibility not valid on fiber */
hw->tbi_compatibility_en = FALSE;
} else {
hw->media_type = e1000_media_type_copper;
}
- } else {
- /* This is an 82542 (fiber only) */
- hw->media_type = e1000_media_type_fiber;
+ break;
}
}
}
@@ -1189,9 +1198,9 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw)
ret_val = e1000_write_phy_reg(hw, PHY_1000T_CTRL, phy_data);
if(ret_val)
return ret_val;
- }
+ }
- return E1000_SUCCESS;
+ return E1000_SUCCESS;
}
diff --git a/drivers/net/e1000/e1000_hw.h b/drivers/net/e1000/e1000_hw.h
index a0263ee96c6b..93e9f8788751 100644
--- a/drivers/net/e1000/e1000_hw.h
+++ b/drivers/net/e1000/e1000_hw.h
@@ -66,6 +66,7 @@ typedef enum {
e1000_eeprom_spi,
e1000_eeprom_microwire,
e1000_eeprom_flash,
+ e1000_eeprom_none, /* No NVM support */
e1000_num_eeprom_types
} e1000_eeprom_type;
diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
index 137226d98d47..cb7f051a60ad 100644
--- a/drivers/net/e1000/e1000_main.c
+++ b/drivers/net/e1000/e1000_main.c
@@ -29,6 +29,8 @@
#include "e1000.h"
/* Change Log
+ * 6.0.58 4/20/05
+ * o Accepted ethtool cleanup patch from Stephen Hemminger
* 6.0.44+ 2/15/05
* o applied Anton's patch to resolve tx hang in hardware
* o Applied Andrew Mortons patch - e1000 stops working after resume
@@ -41,9 +43,9 @@ char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-#define DRV_VERSION "6.0.54-k2"DRIVERNAPI
+#define DRV_VERSION "6.0.60-k2"DRIVERNAPI
char e1000_driver_version[] = DRV_VERSION;
-char e1000_copyright[] = "Copyright (c) 1999-2004 Intel Corporation.";
+char e1000_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
/* e1000_pci_tbl - PCI Device ID Table
*
@@ -517,7 +519,7 @@ e1000_probe(struct pci_dev *pdev,
SET_NETDEV_DEV(netdev, &pdev->dev);
pci_set_drvdata(pdev, netdev);
- adapter = netdev->priv;
+ adapter = netdev_priv(netdev);
adapter->netdev = netdev;
adapter->pdev = pdev;
adapter->hw.back = adapter;
@@ -738,7 +740,7 @@ static void __devexit
e1000_remove(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t manc, swsm;
flush_scheduled_work();
@@ -871,7 +873,7 @@ e1000_sw_init(struct e1000_adapter *adapter)
static int
e1000_open(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int err;
/* allocate transmit descriptors */
@@ -919,7 +921,7 @@ err_setup_tx:
static int
e1000_close(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_down(adapter);
@@ -1599,7 +1601,7 @@ e1000_leave_82542_rst(struct e1000_adapter *adapter)
static int
e1000_set_mac(struct net_device *netdev, void *p)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct sockaddr *addr = p;
if(!is_valid_ether_addr(addr->sa_data))
@@ -1634,7 +1636,7 @@ e1000_set_mac(struct net_device *netdev, void *p)
static void
e1000_set_multi(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
struct dev_mc_list *mc_ptr;
unsigned long flags;
@@ -2213,7 +2215,7 @@ e1000_transfer_dhcp_info(struct e1000_adapter *adapter, struct sk_buff *skb)
static int
e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(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;
@@ -2344,7 +2346,7 @@ e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
static void
e1000_tx_timeout(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
/* Do the reset outside of interrupt context */
schedule_work(&adapter->tx_timeout_task);
@@ -2353,7 +2355,7 @@ e1000_tx_timeout(struct net_device *netdev)
static void
e1000_tx_timeout_task(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_down(adapter);
e1000_up(adapter);
@@ -2370,7 +2372,7 @@ e1000_tx_timeout_task(struct net_device *netdev)
static struct net_device_stats *
e1000_get_stats(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
e1000_update_stats(adapter);
return &adapter->net_stats;
@@ -2387,7 +2389,7 @@ e1000_get_stats(struct net_device *netdev)
static int
e1000_change_mtu(struct net_device *netdev, int new_mtu)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int max_frame = new_mtu + ENET_HEADER_SIZE + ETHERNET_FCS_SIZE;
if((max_frame < MINIMUM_ETHERNET_FRAME_SIZE) ||
@@ -2598,7 +2600,7 @@ static irqreturn_t
e1000_intr(int irq, void *data, struct pt_regs *regs)
{
struct net_device *netdev = data;
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
uint32_t icr = E1000_READ_REG(hw, ICR);
#ifndef CONFIG_E1000_NAPI
@@ -2661,7 +2663,7 @@ e1000_intr(int irq, void *data, struct pt_regs *regs)
static int
e1000_clean(struct net_device *netdev, int *budget)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int work_to_do = min(*budget, netdev->quota);
int tx_cleaned;
int work_done = 0;
@@ -2672,8 +2674,8 @@ e1000_clean(struct net_device *netdev, int *budget)
*budget -= work_done;
netdev->quota -= work_done;
- /* If no Tx and no Rx work done, exit the polling mode */
if ((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {
+ /* If no Tx and not enough Rx work done, exit the polling mode */
netif_rx_complete(netdev);
e1000_irq_enable(adapter);
return 0;
@@ -2769,13 +2771,13 @@ e1000_clean_tx_irq(struct e1000_adapter *adapter)
i = tx_ring->next_to_clean;
eop = tx_ring->buffer_info[i].next_to_watch;
eop_desc = E1000_TX_DESC(*tx_ring, eop);
- DPRINTK(TX_ERR, ERR, "Detected Tx Unit Hang\n"
+ DPRINTK(DRV, ERR, "Detected Tx Unit Hang\n"
" TDH <%x>\n"
" TDT <%x>\n"
" next_to_use <%x>\n"
" next_to_clean <%x>\n"
"buffer_info[next_to_clean]\n"
- " dma <%llx>\n"
+ " dma <%zx>\n"
" time_stamp <%lx>\n"
" next_to_watch <%x>\n"
" jiffies <%lx>\n"
@@ -2994,7 +2996,7 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
i = rx_ring->next_to_clean;
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
- staterr = rx_desc->wb.middle.status_error;
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
while(staterr & E1000_RXD_STAT_DD) {
buffer_info = &rx_ring->buffer_info[i];
@@ -3065,16 +3067,16 @@ e1000_clean_rx_irq_ps(struct e1000_adapter *adapter)
#ifdef CONFIG_E1000_NAPI
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_receive_skb(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->wb.middle.vlan &
- E1000_RXD_SPC_VLAN_MASK));
+ le16_to_cpu(rx_desc->wb.middle.vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
} else {
netif_receive_skb(skb);
}
#else /* CONFIG_E1000_NAPI */
if(unlikely(adapter->vlgrp && (staterr & E1000_RXD_STAT_VP))) {
vlan_hwaccel_rx(skb, adapter->vlgrp,
- le16_to_cpu(rx_desc->wb.middle.vlan &
- E1000_RXD_SPC_VLAN_MASK));
+ le16_to_cpu(rx_desc->wb.middle.vlan) &
+ E1000_RXD_SPC_VLAN_MASK);
} else {
netif_rx(skb);
}
@@ -3087,7 +3089,7 @@ next_desc:
if(unlikely(++i == rx_ring->count)) i = 0;
rx_desc = E1000_RX_DESC_PS(*rx_ring, i);
- staterr = rx_desc->wb.middle.status_error;
+ staterr = le32_to_cpu(rx_desc->wb.middle.status_error);
}
rx_ring->next_to_clean = i;
adapter->alloc_rx_buf(adapter);
@@ -3371,11 +3373,12 @@ e1000_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
static int
e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
struct mii_ioctl_data *data = if_mii(ifr);
int retval;
uint16_t mii_reg;
uint16_t spddplx;
+ unsigned long flags;
if(adapter->hw.media_type != e1000_media_type_copper)
return -EOPNOTSUPP;
@@ -3385,22 +3388,29 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
data->phy_id = adapter->hw.phy_addr;
break;
case SIOCGMIIREG:
- if (!capable(CAP_NET_ADMIN))
+ if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if (e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
- &data->val_out))
+ spin_lock_irqsave(&adapter->stats_lock, flags);
+ if(e1000_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+ &data->val_out)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
+ }
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
break;
case SIOCSMIIREG:
- if (!capable(CAP_NET_ADMIN))
+ if(!capable(CAP_NET_ADMIN))
return -EPERM;
- if (data->reg_num & ~(0x1F))
+ if(data->reg_num & ~(0x1F))
return -EFAULT;
mii_reg = data->val_in;
- if (e1000_write_phy_reg(&adapter->hw, data->reg_num,
- mii_reg))
+ spin_lock_irqsave(&adapter->stats_lock, flags);
+ if(e1000_write_phy_reg(&adapter->hw, data->reg_num,
+ mii_reg)) {
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
return -EIO;
- if (adapter->hw.phy_type == e1000_phy_m88) {
+ }
+ if(adapter->hw.phy_type == e1000_phy_m88) {
switch (data->reg_num) {
case PHY_CTRL:
if(mii_reg & MII_CR_POWER_DOWN)
@@ -3420,8 +3430,12 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
HALF_DUPLEX;
retval = e1000_set_spd_dplx(adapter,
spddplx);
- if(retval)
+ if(retval) {
+ spin_unlock_irqrestore(
+ &adapter->stats_lock,
+ flags);
return retval;
+ }
}
if(netif_running(adapter->netdev)) {
e1000_down(adapter);
@@ -3431,8 +3445,11 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
case M88E1000_PHY_SPEC_CTRL:
case M88E1000_EXT_PHY_SPEC_CTRL:
- if (e1000_phy_reset(&adapter->hw))
+ if(e1000_phy_reset(&adapter->hw)) {
+ spin_unlock_irqrestore(
+ &adapter->stats_lock, flags);
return -EIO;
+ }
break;
}
} else {
@@ -3448,6 +3465,7 @@ e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
break;
}
}
+ spin_unlock_irqrestore(&adapter->stats_lock, flags);
break;
default:
return -EOPNOTSUPP;
@@ -3504,7 +3522,7 @@ e1000_io_write(struct e1000_hw *hw, unsigned long port, uint32_t value)
static void
e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, rctl;
e1000_irq_disable(adapter);
@@ -3544,7 +3562,7 @@ e1000_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp)
static void
e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
if((adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN_SUPPORT) &&
@@ -3560,7 +3578,7 @@ e1000_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid)
static void
e1000_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t vfta, index;
e1000_irq_disable(adapter);
@@ -3601,6 +3619,13 @@ e1000_set_spd_dplx(struct e1000_adapter *adapter, uint16_t spddplx)
{
adapter->hw.autoneg = 0;
+ /* Fiber NICs only allow 1000 gbps Full duplex */
+ if((adapter->hw.media_type == e1000_media_type_fiber) &&
+ spddplx != (SPEED_1000 + DUPLEX_FULL)) {
+ DPRINTK(PROBE, ERR, "Unsupported Speed/Duplex configuration\n");
+ return -EINVAL;
+ }
+
switch(spddplx) {
case SPEED_10 + DUPLEX_HALF:
adapter->hw.forced_speed_duplex = e1000_10_half;
@@ -3647,7 +3672,7 @@ static int
e1000_suspend(struct pci_dev *pdev, uint32_t state)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
uint32_t ctrl, ctrl_ext, rctl, manc, status, swsm;
uint32_t wufc = adapter->wol;
@@ -3740,12 +3765,12 @@ static int
e1000_resume(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
- struct e1000_adapter *adapter = netdev->priv;
- uint32_t manc, ret, swsm;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
+ uint32_t manc, ret_val, swsm;
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
- ret = pci_enable_device(pdev);
+ ret_val = pci_enable_device(pdev);
pci_set_master(pdev);
pci_enable_wake(pdev, 3, 0);
@@ -3788,7 +3813,7 @@ e1000_resume(struct pci_dev *pdev)
static void
e1000_netpoll(struct net_device *netdev)
{
- struct e1000_adapter *adapter = netdev->priv;
+ struct e1000_adapter *adapter = netdev_priv(netdev);
disable_irq(adapter->pdev->irq);
e1000_intr(adapter->pdev->irq, netdev, NULL);
enable_irq(adapter->pdev->irq);
diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c
index 51c9fa260830..f5a4dd7d8564 100644
--- a/drivers/net/e2100.c
+++ b/drivers/net/e2100.c
@@ -162,12 +162,7 @@ struct net_device * __init e2100_probe(int unit)
err = do_e2100_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -286,6 +281,9 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr)
#endif
NS8390_init(dev, 0);
+ retval = register_netdev(dev);
+ if (retval)
+ goto out;
return 0;
out:
release_region(ioaddr, E21_IO_EXTENT);
@@ -453,11 +451,8 @@ init_module(void)
dev->mem_start = mem[this_dev];
dev->mem_end = xcvr[this_dev]; /* low 4bits = xcvr sel. */
if (do_e2100_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_e21[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_e21[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "e2100.c: No E2100 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c
index cd2475683027..dcb3028bb60f 100644
--- a/drivers/net/eepro.c
+++ b/drivers/net/eepro.c
@@ -600,12 +600,7 @@ struct net_device * __init eepro_probe(int unit)
err = do_eepro_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -758,6 +753,7 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
int i;
struct eepro_local *lp;
int ioaddr = dev->base_addr;
+ int err;
/* Grab the region so we can find another board if autoIRQ fails. */
if (!request_region(ioaddr, EEPRO_IO_EXTENT, DRV_NAME)) {
@@ -873,10 +869,16 @@ static int __init eepro_probe1(struct net_device *dev, int autoprobe)
/* reset 82595 */
eepro_reset(ioaddr);
+
+ err = register_netdev(dev);
+ if (err)
+ goto err;
return 0;
exit:
+ err = -ENODEV;
+err:
release_region(dev->base_addr, EEPRO_IO_EXTENT);
- return -ENODEV;
+ return err;
}
/* Open/initialize the board. This is called (in the current kernel)
@@ -1834,11 +1836,8 @@ init_module(void)
dev->irq = irq[i];
if (do_eepro_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_eepro[n_eepro++] = dev;
- continue;
- }
- release_region(dev->base_addr, EEPRO_IO_EXTENT);
+ dev_eepro[n_eepro++] = dev;
+ continue;
}
free_netdev(dev);
break;
diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c
index 98b3a2fdce90..1795425f512e 100644
--- a/drivers/net/eepro100.c
+++ b/drivers/net/eepro100.c
@@ -1269,7 +1269,7 @@ speedo_init_rx_ring(struct net_device *dev)
if (skb == NULL)
break; /* OK. Just initially short of Rx bufs. */
skb->dev = dev; /* Mark as being used by this device. */
- rxf = (struct RxFD *)skb->tail;
+ rxf = (struct RxFD *)skb->data;
sp->rx_ringp[i] = rxf;
sp->rx_ring_dma[i] =
pci_map_single(sp->pdev, rxf,
@@ -1661,7 +1661,7 @@ static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry)
sp->rx_ringp[entry] = NULL;
return NULL;
}
- rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->tail;
+ rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data;
sp->rx_ring_dma[entry] =
pci_map_single(sp->pdev, rxf,
PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE);
@@ -1808,10 +1808,10 @@ speedo_rx(struct net_device *dev)
#if 1 || USE_IP_CSUM
/* Packet is in one chunk -- we can copy + cksum. */
- eth_copy_and_sum(skb, sp->rx_skbuff[entry]->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, sp->rx_skbuff[entry]->data, pkt_len, 0);
skb_put(skb, pkt_len);
#else
- memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->tail,
+ memcpy(skb_put(skb, pkt_len), sp->rx_skbuff[entry]->data,
pkt_len);
#endif
pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry],
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
index fc8e7947b334..82bd356e4f3a 100644
--- a/drivers/net/eexpress.c
+++ b/drivers/net/eexpress.c
@@ -436,11 +436,8 @@ struct net_device * __init express_probe(int unit)
netdev_boot_setup_check(dev);
err = do_express_probe(dev);
- if (!err) {
- err = register_netdev(dev);
- if (!err)
- return dev;
- }
+ if (!err)
+ return dev;
free_netdev(dev);
return ERR_PTR(err);
}
@@ -1205,7 +1202,8 @@ static int __init eexp_hw_probe(struct net_device *dev, unsigned short ioaddr)
dev->set_multicast_list = &eexp_set_multicast;
dev->tx_timeout = eexp_timeout;
dev->watchdog_timeo = 2*HZ;
- return 0;
+
+ return register_netdev(dev);
}
/*
@@ -1716,7 +1714,7 @@ int init_module(void)
break;
printk(KERN_NOTICE "eexpress.c: Module autoprobe not recommended, give io=xx.\n");
}
- if (do_express_probe(dev) == 0 && register_netdev(dev) == 0) {
+ if (do_express_probe(dev) == 0) {
dev_eexp[this_dev] = dev;
found++;
continue;
diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c
index 81ebaedaa240..87f522738bfc 100644
--- a/drivers/net/epic100.c
+++ b/drivers/net/epic100.c
@@ -1003,7 +1003,7 @@ static void epic_init_ring(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
ep->rx_ring[i].bufaddr = pci_map_single(ep->pci_dev,
- skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
ep->rx_ring[i].rxstatus = cpu_to_le32(DescOwn);
}
ep->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1274,7 +1274,7 @@ static int epic_rx(struct net_device *dev, int budget)
ep->rx_ring[entry].bufaddr,
ep->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, ep->rx_skbuff[entry]->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, ep->rx_skbuff[entry]->data, pkt_len, 0);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(ep->pci_dev,
ep->rx_ring[entry].bufaddr,
@@ -1308,7 +1308,7 @@ static int epic_rx(struct net_device *dev, int budget)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
ep->rx_ring[entry].bufaddr = pci_map_single(ep->pci_dev,
- skb->tail, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb->data, ep->rx_buf_sz, PCI_DMA_FROMDEVICE);
work_done++;
}
ep->rx_ring[entry].rxstatus = cpu_to_le32(DescOwn);
diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c
index f1e8150ed2a0..50f8e23bb9e5 100644
--- a/drivers/net/es3210.c
+++ b/drivers/net/es3210.c
@@ -177,12 +177,7 @@ struct net_device * __init es_probe(int unit)
err = do_es_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -310,6 +305,10 @@ static int __init es_probe1(struct net_device *dev, int ioaddr)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out1;
return 0;
out1:
free_irq(dev->irq, dev);
@@ -445,11 +444,8 @@ init_module(void)
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev];
if (do_es_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_es3210[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_es3210[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "es3210.c: No es3210 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c
index ccae6ba5f7c5..f32a6b3acb2a 100644
--- a/drivers/net/eth16i.c
+++ b/drivers/net/eth16i.c
@@ -473,13 +473,7 @@ struct net_device * __init eth16i_probe(int unit)
err = do_eth16i_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, ETH16I_IO_EXTENT);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -569,7 +563,13 @@ static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
dev->tx_timeout = eth16i_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
spin_lock_init(&lp->lock);
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out1;
return 0;
+out1:
+ free_irq(dev->irq, dev);
out:
release_region(ioaddr, ETH16I_IO_EXTENT);
return retval;
@@ -1462,12 +1462,8 @@ int init_module(void)
}
if (do_eth16i_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_eth16i[found++] = dev;
- continue;
- }
- free_irq(dev->irq, dev);
- release_region(dev->base_addr, ETH16I_IO_EXTENT);
+ dev_eth16i[found++] = dev;
+ continue;
}
printk(KERN_WARNING "eth16i.c No Eth16i card found (i/o = 0x%x).\n",
io[this_dev]);
diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c
index dcf969b20be9..b987f9474730 100644
--- a/drivers/net/ewrk3.c
+++ b/drivers/net/ewrk3.c
@@ -1308,15 +1308,9 @@ static int __init eisa_probe(struct net_device *dev, u_long ioaddr)
if (ioaddr < 0x1000)
goto out;
- if (ioaddr == 0) { /* Autoprobing */
- iobase = EISA_SLOT_INC; /* Get the first slot address */
- i = 1;
- maxSlots = MAX_EISA_SLOTS;
- } else { /* Probe a specific location */
- iobase = ioaddr;
- i = (ioaddr >> 12);
- maxSlots = i + 1;
- }
+ iobase = ioaddr;
+ i = (ioaddr >> 12);
+ maxSlots = i + 1;
for (i = 1; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
if (EISA_signature(name, EISA_ID) == 0) {
diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c
index d05e9dd1e140..55dbe9a3fd56 100644
--- a/drivers/net/fealnx.c
+++ b/drivers/net/fealnx.c
@@ -1107,7 +1107,7 @@ static void allocate_rx_buffers(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
np->lack_rxbuf->skbuff = skb;
- np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->tail,
+ np->lack_rxbuf->buffer = pci_map_single(np->pci_dev, skb->data,
np->rx_buf_sz, PCI_DMA_FROMDEVICE);
np->lack_rxbuf->status = RXOWN;
++np->really_rx_count;
@@ -1300,7 +1300,7 @@ static void init_ring(struct net_device *dev)
++np->really_rx_count;
np->rx_ring[i].skbuff = skb;
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->tail,
+ np->rx_ring[i].buffer = pci_map_single(np->pci_dev, skb->data,
np->rx_buf_sz, PCI_DMA_FROMDEVICE);
np->rx_ring[i].status = RXOWN;
np->rx_ring[i].control |= RXIC;
@@ -1423,8 +1423,7 @@ static void reset_tx_descriptors(struct net_device *dev)
if (cur->skbuff) {
pci_unmap_single(np->pci_dev, cur->buffer,
cur->skbuff->len, PCI_DMA_TODEVICE);
- dev_kfree_skb(cur->skbuff);
- /* or dev_kfree_skb_irq(cur->skbuff); ? */
+ dev_kfree_skb_any(cur->skbuff);
cur->skbuff = NULL;
}
cur->status = 0;
@@ -1738,11 +1737,11 @@ static int netdev_rx(struct net_device *dev)
#if ! defined(__alpha__)
eth_copy_and_sum(skb,
- np->cur_rx->skbuff->tail, pkt_len, 0);
+ np->cur_rx->skbuff->data, pkt_len, 0);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
- np->cur_rx->skbuff->tail, pkt_len);
+ np->cur_rx->skbuff->data, pkt_len);
#endif
pci_dma_sync_single_for_device(np->pci_dev,
np->cur_rx->buffer,
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 4ebcd052e150..64f0f697c958 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -82,6 +82,9 @@
* 0.31: 14 Nov 2004: ethtool support for getting/setting link
* capabilities.
* 0.32: 16 Apr 2005: RX_ERROR4 handling added.
+ * 0.33: 16 May 2005: Support for MCP51 added.
+ * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics.
+ * 0.35: 26 Jun 2005: Support for MCP55 added.
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -93,7 +96,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.32"
+#define FORCEDETH_VERSION "0.35"
#define DRV_NAME "forcedeth"
#include <linux/module.h>
@@ -2005,7 +2008,9 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
/* handle different descriptor versions */
if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 ||
pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 ||
- pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3)
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3 ||
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_12 ||
+ pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_13)
np->desc_ver = DESC_VER_1;
else
np->desc_ver = DESC_VER_2;
@@ -2215,56 +2220,84 @@ static struct pci_device_id pci_tbl[] = {
.device = PCI_DEVICE_ID_NVIDIA_NVENET_4,
.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_5,
.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_6,
.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_7,
.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,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_8,
.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,
},
{ /* CK804 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_9,
.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,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_10,
.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,
},
{ /* MCP04 Ethernet Controller */
.vendor = PCI_VENDOR_ID_NVIDIA,
.device = PCI_DEVICE_ID_NVIDIA_NVENET_11,
.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,
+ },
+ { /* MCP51 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_12,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP51 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_13,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP55 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_14,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
+ },
+ { /* MCP55 Ethernet Controller */
+ .vendor = PCI_VENDOR_ID_NVIDIA,
+ .device = PCI_DEVICE_ID_NVIDIA_NVENET_15,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER,
},
{0,},
};
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c
index b43b2b11aacd..6518334b9280 100644
--- a/drivers/net/gianfar.c
+++ b/drivers/net/gianfar.c
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.c
*
* Gianfar Ethernet Driver
@@ -22,10 +22,9 @@
* B-V +1.62
*
* Theory of operation
- * This driver is designed for the Triple-speed Ethernet
- * controllers on the Freescale 8540/8560 integrated processors,
- * as well as the Fast Ethernet Controller on the 8540.
- *
+ * This driver is designed for the non-CPM ethernet controllers
+ * on the 85xx and 83xx family of integrated processors
+ *
* The driver is initialized through platform_device. Structures which
* define the configuration needed by the board are defined in a
* board structure in arch/ppc/platforms (though I do not
@@ -39,12 +38,12 @@
*
* The Gianfar Ethernet Controller uses a ring of buffer
* descriptors. The beginning is indicated by a register
- * pointing to the physical address of the start of the ring.
- * The end is determined by a "wrap" bit being set in the
+ * pointing to the physical address of the start of the ring.
+ * The end is determined by a "wrap" bit being set in the
* last descriptor of the ring.
*
* When a packet is received, the RXF bit in the
- * IEVENT register is set, triggering an interrupt when the
+ * IEVENT register is set, triggering an interrupt when the
* corresponding bit in the IMASK register is also set (if
* interrupt coalescing is active, then the interrupt may not
* happen immediately, but will wait until either a set number
@@ -52,7 +51,7 @@
* interrupt handler will signal there is work to be done, and
* exit. Without NAPI, the packet(s) will be handled
* immediately. Both methods will start at the last known empty
- * descriptor, and process every subsequent descriptor until there
+ * descriptor, and process every subsequent descriptor until there
* are none left with data (NAPI will stop after a set number of
* packets to give time to other tasks, but will eventually
* process all the packets). The data arrives inside a
@@ -83,9 +82,13 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/if_vlan.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/device.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -123,7 +126,7 @@ static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_transmit(int irq, void *dev_id, struct pt_regs *regs);
-irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static irqreturn_t phy_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void gfar_phy_change(void *data);
@@ -139,9 +142,12 @@ 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
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length);
static void gfar_phy_startup_timer(unsigned long data);
+static void gfar_vlan_rx_register(struct net_device *netdev,
+ struct vlan_group *grp);
+static void gfar_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid);
extern struct ethtool_ops gfar_ethtool_ops;
@@ -149,6 +155,13 @@ MODULE_AUTHOR("Freescale Semiconductor, Inc");
MODULE_DESCRIPTION("Gianfar Ethernet Driver");
MODULE_LICENSE("GPL");
+int gfar_uses_fcb(struct gfar_private *priv)
+{
+ if (priv->vlan_enable || priv->rx_csum_enable)
+ return 1;
+ else
+ return 0;
+}
static int gfar_probe(struct device *device)
{
u32 tempval;
@@ -159,7 +172,6 @@ static int gfar_probe(struct device *device)
struct resource *r;
int idx;
int err = 0;
- int dev_ethtool_ops = 0;
einfo = (struct gianfar_platform_data *) pdev->dev.platform_data;
@@ -265,15 +277,69 @@ static int gfar_probe(struct device *device)
dev->mtu = 1500;
dev->set_multicast_list = gfar_set_multi;
- /* Index into the array of possible ethtool
- * ops to catch all 4 possibilities */
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) == 0)
- dev_ethtool_ops += 1;
+ dev->ethtool_ops = &gfar_ethtool_ops;
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
+ priv->rx_csum_enable = 1;
+ dev->features |= NETIF_F_IP_CSUM;
+ } else
+ priv->rx_csum_enable = 0;
+
+ priv->vlgrp = NULL;
- if((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE) == 0)
- dev_ethtool_ops += 2;
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
+ dev->vlan_rx_register = gfar_vlan_rx_register;
+ dev->vlan_rx_kill_vid = gfar_vlan_rx_kill_vid;
- dev->ethtool_ops = gfar_op_array[dev_ethtool_ops];
+ dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
+
+ priv->vlan_enable = 1;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
+ priv->extended_hash = 1;
+ priv->hash_width = 9;
+
+ priv->hash_regs[0] = &priv->regs->igaddr0;
+ priv->hash_regs[1] = &priv->regs->igaddr1;
+ priv->hash_regs[2] = &priv->regs->igaddr2;
+ priv->hash_regs[3] = &priv->regs->igaddr3;
+ priv->hash_regs[4] = &priv->regs->igaddr4;
+ priv->hash_regs[5] = &priv->regs->igaddr5;
+ priv->hash_regs[6] = &priv->regs->igaddr6;
+ priv->hash_regs[7] = &priv->regs->igaddr7;
+ priv->hash_regs[8] = &priv->regs->gaddr0;
+ priv->hash_regs[9] = &priv->regs->gaddr1;
+ priv->hash_regs[10] = &priv->regs->gaddr2;
+ priv->hash_regs[11] = &priv->regs->gaddr3;
+ priv->hash_regs[12] = &priv->regs->gaddr4;
+ priv->hash_regs[13] = &priv->regs->gaddr5;
+ priv->hash_regs[14] = &priv->regs->gaddr6;
+ priv->hash_regs[15] = &priv->regs->gaddr7;
+
+ } else {
+ priv->extended_hash = 0;
+ priv->hash_width = 8;
+
+ priv->hash_regs[0] = &priv->regs->gaddr0;
+ priv->hash_regs[1] = &priv->regs->gaddr1;
+ priv->hash_regs[2] = &priv->regs->gaddr2;
+ priv->hash_regs[3] = &priv->regs->gaddr3;
+ priv->hash_regs[4] = &priv->regs->gaddr4;
+ priv->hash_regs[5] = &priv->regs->gaddr5;
+ priv->hash_regs[6] = &priv->regs->gaddr6;
+ priv->hash_regs[7] = &priv->regs->gaddr7;
+ }
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING)
+ priv->padding = DEFAULT_PADDING;
+ else
+ priv->padding = 0;
+
+ dev->hard_header_len += priv->padding;
+
+ if (dev->features & NETIF_F_IP_CSUM)
+ dev->hard_header_len += GMAC_FCB_LEN;
priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE;
#ifdef CONFIG_GFAR_BUFSTASH
@@ -289,6 +355,9 @@ static int gfar_probe(struct device *device)
priv->rxcount = DEFAULT_RXCOUNT;
priv->rxtime = DEFAULT_RXTIME;
+ /* Enable most messages by default */
+ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1;
+
err = register_netdev(dev);
if (err) {
@@ -360,8 +429,9 @@ static int init_phy(struct net_device *dev)
GFP_KERNEL);
if(NULL == mii_info) {
- printk(KERN_ERR "%s: Could not allocate mii_info\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate mii_info\n",
+ dev->name);
return -ENOMEM;
}
@@ -410,7 +480,8 @@ static int init_phy(struct net_device *dev)
curphy = get_phy_info(priv->mii_info);
if (curphy == NULL) {
- printk(KERN_ERR "%s: No PHY found\n", dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: No PHY found\n", dev->name);
err = -1;
goto no_phy;
}
@@ -421,7 +492,7 @@ static int init_phy(struct net_device *dev)
if(curphy->init) {
err = curphy->init(priv->mii_info);
- if (err)
+ if (err)
goto phy_init_fail;
}
@@ -446,14 +517,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->imask, IMASK_INIT_CLEAR);
/* Init hash registers to zero */
- gfar_write(&priv->regs->iaddr0, 0);
- gfar_write(&priv->regs->iaddr1, 0);
- gfar_write(&priv->regs->iaddr2, 0);
- gfar_write(&priv->regs->iaddr3, 0);
- gfar_write(&priv->regs->iaddr4, 0);
- gfar_write(&priv->regs->iaddr5, 0);
- gfar_write(&priv->regs->iaddr6, 0);
- gfar_write(&priv->regs->iaddr7, 0);
+ gfar_write(&priv->regs->igaddr0, 0);
+ gfar_write(&priv->regs->igaddr1, 0);
+ gfar_write(&priv->regs->igaddr2, 0);
+ gfar_write(&priv->regs->igaddr3, 0);
+ gfar_write(&priv->regs->igaddr4, 0);
+ gfar_write(&priv->regs->igaddr5, 0);
+ gfar_write(&priv->regs->igaddr6, 0);
+ gfar_write(&priv->regs->igaddr7, 0);
gfar_write(&priv->regs->gaddr0, 0);
gfar_write(&priv->regs->gaddr1, 0);
@@ -464,9 +535,6 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->gaddr6, 0);
gfar_write(&priv->regs->gaddr7, 0);
- /* Zero out rctrl */
- gfar_write(&priv->regs->rctrl, 0x00000000);
-
/* Zero out the rmon mib registers if it has them */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
memset((void *) &(priv->regs->rmon), 0,
@@ -497,20 +565,14 @@ static void init_registers(struct net_device *dev)
gfar_write(&priv->regs->tbipa, TBIPA_VALUE);
}
-void stop_gfar(struct net_device *dev)
+
+/* Halt the receive and transmit queues */
+void gfar_halt(struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- unsigned long flags;
u32 tempval;
- /* Lock it down */
- spin_lock_irqsave(&priv->lock, flags);
-
- /* Tell the kernel the link is down */
- priv->mii_info->link = 0;
- adjust_link(dev);
-
/* Mask all interrupts */
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
@@ -533,13 +595,29 @@ void stop_gfar(struct net_device *dev)
tempval = gfar_read(&regs->maccfg1);
tempval &= ~(MACCFG1_RX_EN | MACCFG1_TX_EN);
gfar_write(&regs->maccfg1, tempval);
+}
+
+void stop_gfar(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ unsigned long flags;
+
+ /* Lock it down */
+ spin_lock_irqsave(&priv->lock, flags);
+
+ /* Tell the kernel the link is down */
+ priv->mii_info->link = 0;
+ adjust_link(dev);
+
+ gfar_halt(dev);
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
/* Clear any pending interrupts */
mii_clear_phy_interrupt(priv->mii_info);
/* Disable PHY Interrupts */
- mii_configure_phy_interrupt(priv->mii_info,
+ mii_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_DISABLED);
}
@@ -566,7 +644,7 @@ void stop_gfar(struct net_device *dev)
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
}
/* If there are any tx skbs or rx skbs still around, free them.
@@ -620,6 +698,34 @@ void free_skb_resources(struct gfar_private *priv)
}
}
+void gfar_start(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ struct gfar *regs = priv->regs;
+ u32 tempval;
+
+ /* Enable Rx and Tx in MACCFG1 */
+ tempval = gfar_read(&regs->maccfg1);
+ tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
+ gfar_write(&regs->maccfg1, tempval);
+
+ /* Initialize DMACTRL to have WWR and WOP */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval |= DMACTRL_INIT_SETTINGS;
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Clear THLT, so that the DMA starts polling now */
+ gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+
+ /* Make sure we aren't stopped */
+ tempval = gfar_read(&priv->regs->dmactrl);
+ tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
+ gfar_write(&priv->regs->dmactrl, tempval);
+
+ /* Unmask the interrupts we look for */
+ gfar_write(&regs->imask, IMASK_DEFAULT);
+}
+
/* Bring the controller up and running */
int startup_gfar(struct net_device *dev)
{
@@ -630,33 +736,34 @@ int startup_gfar(struct net_device *dev)
int i;
struct gfar_private *priv = netdev_priv(dev);
struct gfar *regs = priv->regs;
- u32 tempval;
int err = 0;
+ u32 rctrl = 0;
gfar_write(&regs->imask, IMASK_INIT_CLEAR);
/* Allocate memory for the buffer descriptors */
- vaddr = (unsigned long) dma_alloc_coherent(NULL,
+ 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 (vaddr == 0) {
- printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate buffer descriptors!\n",
+ dev->name);
return -ENOMEM;
}
priv->tx_bd_base = (struct txbd8 *) vaddr;
/* enet DMA only understands physical addresses */
- gfar_write(&regs->tbase, addr);
+ gfar_write(&regs->tbase0, addr);
/* Start the rx descriptor ring where the tx ring leaves off */
addr = addr + sizeof (struct txbd8) * priv->tx_ring_size;
vaddr = vaddr + sizeof (struct txbd8) * priv->tx_ring_size;
priv->rx_bd_base = (struct rxbd8 *) vaddr;
- gfar_write(&regs->rbase, addr);
+ gfar_write(&regs->rbase0, addr);
/* Setup the skbuff rings */
priv->tx_skbuff =
@@ -664,8 +771,9 @@ int startup_gfar(struct net_device *dev)
priv->tx_ring_size, GFP_KERNEL);
if (priv->tx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate tx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto tx_skb_fail;
}
@@ -678,8 +786,9 @@ int startup_gfar(struct net_device *dev)
priv->rx_ring_size, GFP_KERNEL);
if (priv->rx_skbuff == NULL) {
- printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
- dev->name);
+ if (netif_msg_ifup(priv))
+ printk(KERN_ERR "%s: Could not allocate rx_skbuff\n",
+ dev->name);
err = -ENOMEM;
goto rx_skb_fail;
}
@@ -726,12 +835,13 @@ int startup_gfar(struct net_device *dev)
/* If the device has multiple interrupts, register for
* them. Otherwise, only register for the one */
if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) {
- /* Install our interrupt handlers for Error,
+ /* Install our interrupt handlers for Error,
* Transmit, and Receive */
if (request_irq(priv->interruptError, gfar_error,
0, "enet_error", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -739,8 +849,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptTransmit, gfar_transmit,
0, "enet_tx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptTransmit);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptTransmit);
err = -1;
@@ -749,8 +860,9 @@ int startup_gfar(struct net_device *dev)
if (request_irq(priv->interruptReceive, gfar_receive,
0, "enet_rx", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
- dev->name, priv->interruptReceive);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n",
+ dev->name, priv->interruptReceive);
err = -1;
goto rx_irq_fail;
@@ -758,8 +870,9 @@ int startup_gfar(struct net_device *dev)
} else {
if (request_irq(priv->interruptTransmit, gfar_interrupt,
0, "gfar_interrupt", dev) < 0) {
- printk(KERN_ERR "%s: Can't get IRQ %d\n",
- dev->name, priv->interruptError);
+ if (netif_msg_intr(priv))
+ printk(KERN_ERR "%s: Can't get IRQ %d\n",
+ dev->name, priv->interruptError);
err = -1;
goto err_irq_fail;
@@ -787,28 +900,22 @@ int startup_gfar(struct net_device *dev)
else
gfar_write(&regs->rxic, 0);
- init_waitqueue_head(&priv->rxcleanupq);
+ if (priv->rx_csum_enable)
+ rctrl |= RCTRL_CHECKSUMMING;
- /* Enable Rx and Tx in MACCFG1 */
- tempval = gfar_read(&regs->maccfg1);
- tempval |= (MACCFG1_RX_EN | MACCFG1_TX_EN);
- gfar_write(&regs->maccfg1, tempval);
+ if (priv->extended_hash)
+ rctrl |= RCTRL_EXTHASH;
- /* Initialize DMACTRL to have WWR and WOP */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= DMACTRL_INIT_SETTINGS;
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (priv->vlan_enable)
+ rctrl |= RCTRL_VLAN;
- /* Clear THLT, so that the DMA starts polling now */
- gfar_write(&regs->tstat, TSTAT_CLEAR_THALT);
+ /* Init rctrl based on our settings */
+ gfar_write(&priv->regs->rctrl, rctrl);
- /* Make sure we aren't stopped */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->features & NETIF_F_IP_CSUM)
+ gfar_write(&priv->regs->tctrl, TCTRL_INIT_CSUM);
- /* Unmask the interrupts we look for */
- gfar_write(&regs->imask, IMASK_DEFAULT);
+ gfar_start(dev);
return 0;
@@ -824,7 +931,7 @@ tx_skb_fail:
sizeof(struct txbd8)*priv->tx_ring_size
+ sizeof(struct rxbd8)*priv->rx_ring_size,
priv->tx_bd_base,
- gfar_read(&regs->tbase));
+ gfar_read(&regs->tbase0));
if (priv->mii_info->phyinfo->close)
priv->mii_info->phyinfo->close(priv->mii_info);
@@ -857,11 +964,62 @@ static int gfar_enet_open(struct net_device *dev)
return err;
}
+static struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp)
+{
+ struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN);
+
+ memset(fcb, 0, GMAC_FCB_LEN);
+
+ /* Flag the bd so the controller looks for the FCB */
+ bdp->status |= TXBD_TOE;
+
+ return fcb;
+}
+
+static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb)
+{
+ int len;
+
+ /* If we're here, it's a IP packet with a TCP or UDP
+ * payload. We set it to checksum, using a pseudo-header
+ * we provide
+ */
+ fcb->ip = 1;
+ fcb->tup = 1;
+ fcb->ctu = 1;
+ fcb->nph = 1;
+
+ /* Notify the controller what the protocol is */
+ if (skb->nh.iph->protocol == IPPROTO_UDP)
+ fcb->udp = 1;
+
+ /* l3os is the distance between the start of the
+ * frame (skb->data) and the start of the IP hdr.
+ * l4os is the distance between the start of the
+ * l3 hdr and the l4 hdr */
+ fcb->l3os = (u16)(skb->nh.raw - skb->data - GMAC_FCB_LEN);
+ fcb->l4os = (u16)(skb->h.raw - skb->nh.raw);
+
+ len = skb->nh.iph->tot_len - fcb->l4os;
+
+ /* Provide the pseudoheader csum */
+ fcb->phcs = ~csum_tcpudp_magic(skb->nh.iph->saddr,
+ skb->nh.iph->daddr, len,
+ skb->nh.iph->protocol, 0);
+}
+
+void gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
+{
+ fcb->vln = 1;
+ fcb->vlctl = vlan_tx_tag_get(skb);
+}
+
/* This is called by the kernel when a frame is ready for transmission. */
/* It is pointed to by the dev->hard_start_xmit function pointer */
static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct txfcb *fcb = NULL;
struct txbd8 *txbdp;
/* Update transmit stats */
@@ -876,9 +1034,24 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Clear all but the WRAP status flags */
txbdp->status &= TXBD_WRAP;
+ /* Set up checksumming */
+ if ((dev->features & NETIF_F_IP_CSUM)
+ && (CHECKSUM_HW == skb->ip_summed)) {
+ fcb = gfar_add_fcb(skb, txbdp);
+ gfar_tx_checksum(skb, fcb);
+ }
+
+ if (priv->vlan_enable &&
+ unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) {
+ if (NULL == fcb)
+ fcb = gfar_add_fcb(skb, txbdp);
+
+ gfar_tx_vlan(skb, fcb);
+ }
+
/* Set buffer length and pointer */
txbdp->length = skb->len;
- txbdp->bufPtr = dma_map_single(NULL, skb->data,
+ txbdp->bufPtr = dma_map_single(NULL, skb->data,
skb->len, DMA_TO_DEVICE);
/* Save the skb pointer so we can free it later */
@@ -972,15 +1145,78 @@ int gfar_set_mac_address(struct net_device *dev)
}
+/* Enables and disables VLAN insertion/extraction */
+static void gfar_vlan_rx_register(struct net_device *dev,
+ struct vlan_group *grp)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+ u32 tempval;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ priv->vlgrp = grp;
+
+ if (grp) {
+ /* Enable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval |= TCTRL_VLINS;
+
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Enable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval |= RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ } else {
+ /* Disable VLAN tag insertion */
+ tempval = gfar_read(&priv->regs->tctrl);
+ tempval &= ~TCTRL_VLINS;
+ gfar_write(&priv->regs->tctrl, tempval);
+
+ /* Disable VLAN tag extraction */
+ tempval = gfar_read(&priv->regs->rctrl);
+ tempval &= ~RCTRL_VLEX;
+ gfar_write(&priv->regs->rctrl, tempval);
+ }
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
+static void gfar_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
+ if (priv->vlgrp)
+ priv->vlgrp->vlan_devices[vid] = NULL;
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+
static int gfar_change_mtu(struct net_device *dev, int new_mtu)
{
int tempsize, tempval;
struct gfar_private *priv = netdev_priv(dev);
int oldsize = priv->rx_buffer_size;
- int frame_size = new_mtu + 18;
+ int frame_size = new_mtu + ETH_HLEN;
+
+ if (priv->vlan_enable)
+ frame_size += VLAN_ETH_HLEN;
+
+ if (gfar_uses_fcb(priv))
+ frame_size += GMAC_FCB_LEN;
+
+ frame_size += priv->padding;
if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) {
- printk(KERN_ERR "%s: Invalid MTU setting\n", dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_ERR "%s: Invalid MTU setting\n",
+ dev->name);
return -EINVAL;
}
@@ -1120,7 +1356,7 @@ struct sk_buff * gfar_new_skb(struct net_device *dev, struct rxbd8 *bdp)
skb->dev = dev;
bdp->bufPtr = dma_map_single(NULL, skb->data,
- priv->rx_buffer_size + RXBUF_ALIGNMENT,
+ priv->rx_buffer_size + RXBUF_ALIGNMENT,
DMA_FROM_DEVICE);
bdp->length = 0;
@@ -1190,11 +1426,10 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
__netif_rx_schedule(dev);
} else {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
- dev->name, gfar_read(&priv->regs->ievent),
- gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n",
+ dev->name, gfar_read(&priv->regs->ievent),
+ gfar_read(&priv->regs->imask));
}
#else
@@ -1209,15 +1444,43 @@ irqreturn_t gfar_receive(int irq, void *dev_id, struct pt_regs *regs)
else
gfar_write(&priv->regs->rxic, 0);
- /* Just in case we need to wake the ring param changer */
- priv->rxclean = 1;
-
spin_unlock(&priv->lock);
#endif
return IRQ_HANDLED;
}
+static inline int gfar_rx_vlan(struct sk_buff *skb,
+ struct vlan_group *vlgrp, unsigned short vlctl)
+{
+#ifdef CONFIG_GFAR_NAPI
+ return vlan_hwaccel_receive_skb(skb, vlgrp, vlctl);
+#else
+ return vlan_hwaccel_rx(skb, vlgrp, vlctl);
+#endif
+}
+
+static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb)
+{
+ /* If valid headers were found, and valid sums
+ * were verified, then we tell the kernel that no
+ * checksumming is necessary. Otherwise, it is */
+ if (fcb->cip && !fcb->eip && fcb->ctu && !fcb->etu)
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ else
+ skb->ip_summed = CHECKSUM_NONE;
+}
+
+
+static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb)
+{
+ struct rxfcb *fcb = (struct rxfcb *)skb->data;
+
+ /* Remove the FCB from the skb */
+ skb_pull(skb, GMAC_FCB_LEN);
+
+ return fcb;
+}
/* gfar_process_frame() -- handle one incoming packet if skb
* isn't NULL. */
@@ -1225,35 +1488,51 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb,
int length)
{
struct gfar_private *priv = netdev_priv(dev);
+ struct rxfcb *fcb = NULL;
if (skb == NULL) {
-#ifdef BRIEF_GFAR_ERRORS
- printk(KERN_WARNING "%s: Missing skb!!.\n",
- dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name);
priv->stats.rx_dropped++;
priv->extra_stats.rx_skbmissing++;
} else {
+ int ret;
+
/* Prep the skb for the packet */
skb_put(skb, length);
+ /* Grab the FCB if there is one */
+ if (gfar_uses_fcb(priv))
+ fcb = gfar_get_fcb(skb);
+
+ /* Remove the padded bytes, if there are any */
+ if (priv->padding)
+ skb_pull(skb, priv->padding);
+
+ if (priv->rx_csum_enable)
+ gfar_rx_checksum(skb, fcb);
+
/* 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) {
+ if (unlikely(priv->vlgrp && fcb->vln))
+ ret = gfar_rx_vlan(skb, priv->vlgrp, fcb->vlctl);
+ else
+ ret = RECEIVE(skb);
+
+ if (NET_RX_DROP == ret)
priv->extra_stats.kernel_dropped++;
- }
}
return 0;
}
/* gfar_clean_rx_ring() -- Processes each frame in the rx ring
- * until the budget/quota has been reached. Returns the number
+ * until the budget/quota has been reached. Returns the number
* of frames handled
*/
-static int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
+int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
{
struct rxbd8 *bdp;
struct sk_buff *skb;
@@ -1355,9 +1634,6 @@ static int gfar_poll(struct net_device *dev, int *budget)
mk_ic_value(priv->rxcount, priv->rxtime));
else
gfar_write(&priv->regs->rxic, 0);
-
- /* Signal to the ring size changer that it's safe to go */
- priv->rxclean = 1;
}
return (rx_work_limit < 0) ? 1 : 0;
@@ -1393,10 +1669,8 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_WARNING "%s: tx underrun. dropped packet\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_WARNING "%s: tx underrun. dropped packet\n", dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
@@ -1415,36 +1689,30 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
- }
- if (events & IEVENT_RXC) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
+ if ((events & IEVENT_RXC) && (netif_msg_rx_err(priv)))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
@@ -1510,7 +1778,7 @@ static void gfar_phy_timer(unsigned long data)
* 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
+ * 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)
{
@@ -1535,8 +1803,9 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Forcing failed! Give up */
if(result) {
- printk(KERN_ERR "%s: Forcing failed!\n",
- mii_info->dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_ERR "%s: Forcing failed!\n",
+ mii_info->dev->name);
return;
}
}
@@ -1546,16 +1815,17 @@ static void gfar_phy_startup_timer(unsigned long data)
/* Grab the PHY interrupt, if necessary/possible */
if (priv->einfo->board_flags & FSL_GIANFAR_BRD_HAS_PHY_INTR) {
- if (request_irq(priv->einfo->interruptPHY,
+ if (request_irq(priv->einfo->interruptPHY,
phy_interrupt,
- SA_SHIRQ,
- "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,
+ if (netif_msg_intr(priv))
+ 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_configure_phy_interrupt(priv->mii_info,
MII_INTERRUPT_ENABLED);
return;
}
@@ -1592,15 +1862,17 @@ static void adjust_link(struct net_device *dev)
tempval &= ~(MACCFG2_FULL_DUPLEX);
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Half Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Half Duplex\n",
+ dev->name);
} else {
tempval = gfar_read(&regs->maccfg2);
tempval |= MACCFG2_FULL_DUPLEX;
gfar_write(&regs->maccfg2, tempval);
- printk(KERN_INFO "%s: Full Duplex\n",
- dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Full Duplex\n",
+ dev->name);
}
priv->oldduplex = mii_info->duplex;
@@ -1622,27 +1894,32 @@ static void adjust_link(struct net_device *dev)
gfar_write(&regs->maccfg2, tempval);
break;
default:
- printk(KERN_WARNING
- "%s: Ack! Speed (%d) is not 10/100/1000!\n",
- dev->name, mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_WARNING
+ "%s: Ack! Speed (%d) is not 10/100/1000!\n",
+ dev->name, mii_info->speed);
break;
}
- printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
- mii_info->speed);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Speed %dBT\n", dev->name,
+ mii_info->speed);
priv->oldspeed = mii_info->speed;
}
if (!priv->oldlink) {
- printk(KERN_INFO "%s: Link is up\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is up\n", dev->name);
priv->oldlink = 1;
netif_carrier_on(dev);
netif_schedule(dev);
}
} else {
if (priv->oldlink) {
- printk(KERN_INFO "%s: Link is down\n", dev->name);
+ if (netif_msg_link(priv))
+ printk(KERN_INFO "%s: Link is down\n",
+ dev->name);
priv->oldlink = 0;
priv->oldspeed = 0;
priv->oldduplex = -1;
@@ -1664,8 +1941,9 @@ static void gfar_set_multi(struct net_device *dev)
u32 tempval;
if(dev->flags & IFF_PROMISC) {
- printk(KERN_INFO "%s: Entering promiscuous mode.\n",
- dev->name);
+ if (netif_msg_drv(priv))
+ printk(KERN_INFO "%s: Entering promiscuous mode.\n",
+ dev->name);
/* Set RCTRL to PROM */
tempval = gfar_read(&regs->rctrl);
tempval |= RCTRL_PROM;
@@ -1679,6 +1957,14 @@ static void gfar_set_multi(struct net_device *dev)
if(dev->flags & IFF_ALLMULTI) {
/* Set the hash to rx all multicast frames */
+ gfar_write(&regs->igaddr0, 0xffffffff);
+ gfar_write(&regs->igaddr1, 0xffffffff);
+ gfar_write(&regs->igaddr2, 0xffffffff);
+ gfar_write(&regs->igaddr3, 0xffffffff);
+ gfar_write(&regs->igaddr4, 0xffffffff);
+ gfar_write(&regs->igaddr5, 0xffffffff);
+ gfar_write(&regs->igaddr6, 0xffffffff);
+ gfar_write(&regs->igaddr7, 0xffffffff);
gfar_write(&regs->gaddr0, 0xffffffff);
gfar_write(&regs->gaddr1, 0xffffffff);
gfar_write(&regs->gaddr2, 0xffffffff);
@@ -1689,6 +1975,14 @@ static void gfar_set_multi(struct net_device *dev)
gfar_write(&regs->gaddr7, 0xffffffff);
} else {
/* zero out the hash */
+ gfar_write(&regs->igaddr0, 0x0);
+ gfar_write(&regs->igaddr1, 0x0);
+ gfar_write(&regs->igaddr2, 0x0);
+ gfar_write(&regs->igaddr3, 0x0);
+ gfar_write(&regs->igaddr4, 0x0);
+ gfar_write(&regs->igaddr5, 0x0);
+ gfar_write(&regs->igaddr6, 0x0);
+ gfar_write(&regs->igaddr7, 0x0);
gfar_write(&regs->gaddr0, 0x0);
gfar_write(&regs->gaddr1, 0x0);
gfar_write(&regs->gaddr2, 0x0);
@@ -1727,16 +2021,15 @@ static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr)
{
u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
- struct gfar *regs = priv->regs;
- u32 *hash = &regs->gaddr0;
u32 result = ether_crc(MAC_ADDR_LEN, addr);
- u8 whichreg = ((result >> 29) & 0x7);
- u8 whichbit = ((result >> 24) & 0x1f);
+ int width = priv->hash_width;
+ u8 whichbit = (result >> (32 - width)) & 0x1f;
+ u8 whichreg = result >> (32 - width + 5);
u32 value = (1 << (31-whichbit));
- tempval = gfar_read(&hash[whichreg]);
+ tempval = gfar_read(priv->hash_regs[whichreg]);
tempval |= value;
- gfar_write(&hash[whichreg], tempval);
+ gfar_write(priv->hash_regs[whichreg], tempval);
return;
}
@@ -1754,10 +2047,9 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->ievent, IEVENT_ERR_MASK);
/* Hmm... */
-#if defined (BRIEF_GFAR_ERRORS) || defined (VERBOSE_GFAR_ERRORS)
- printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
- dev->name, events, gfar_read(&priv->regs->imask));
-#endif
+ if (netif_msg_rx_err(priv) || netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: error interrupt (ievent=0x%08x imask=0x%08x)\n",
+ dev->name, events, gfar_read(&priv->regs->imask));
/* Update the error counters */
if (events & IEVENT_TXE) {
@@ -1768,19 +2060,17 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
if (events & IEVENT_CRL)
priv->stats.tx_aborted_errors++;
if (events & IEVENT_XFUN) {
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
- dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: underrun. packet dropped.\n",
+ dev->name);
priv->stats.tx_dropped++;
priv->extra_stats.tx_underrun++;
/* Reactivate the Tx Queues */
gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT);
}
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: Transmit Error\n", dev->name);
}
if (events & IEVENT_BSY) {
priv->stats.rx_errors++;
@@ -1793,35 +2083,31 @@ static irqreturn_t gfar_error(int irq, void *dev_id, struct pt_regs *regs)
gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT);
#endif
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n", dev->name,
- gfar_read(&priv->regs->rstat));
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: busy error (rhalt: %x)\n",
+ dev->name,
+ gfar_read(&priv->regs->rstat));
}
if (events & IEVENT_BABR) {
priv->stats.rx_errors++;
priv->extra_stats.rx_babr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babbling error\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: babbling error\n", dev->name);
}
if (events & IEVENT_EBERR) {
priv->extra_stats.eberr++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: EBERR\n", dev->name);
-#endif
+ if (netif_msg_rx_err(priv))
+ printk(KERN_DEBUG "%s: EBERR\n", dev->name);
}
- if (events & IEVENT_RXC)
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: control frame\n", dev->name);
-#endif
+ if ((events & IEVENT_RXC) && netif_msg_rx_status(priv))
+ if (netif_msg_rx_status(priv))
+ printk(KERN_DEBUG "%s: control frame\n", dev->name);
if (events & IEVENT_BABT) {
priv->extra_stats.tx_babt++;
-#ifdef VERBOSE_GFAR_ERRORS
- printk(KERN_DEBUG "%s: babt error\n", dev->name);
-#endif
+ if (netif_msg_tx_err(priv))
+ printk(KERN_DEBUG "%s: babt error\n", dev->name);
}
return IRQ_HANDLED;
}
diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h
index c2f783a6a9fa..28af087d9fbb 100644
--- a/drivers/net/gianfar.h
+++ b/drivers/net/gianfar.h
@@ -1,4 +1,4 @@
-/*
+/*
* drivers/net/gianfar.h
*
* Gianfar Ethernet Driver
@@ -53,6 +53,12 @@
/* The maximum number of packets to be handled in one call of gfar_poll */
#define GFAR_DEV_WEIGHT 64
+/* Length for FCB */
+#define GMAC_FCB_LEN 8
+
+/* Default padding amount */
+#define DEFAULT_PADDING 2
+
/* Number of bytes to align the rx bufs to */
#define RXBUF_ALIGNMENT 64
@@ -91,7 +97,7 @@ extern const char gfar_driver_version[];
#define JUMBO_FRAME_SIZE 9600
/* Latency of interface clock in nanoseconds */
-/* Interface clock latency , in this case, means the
+/* Interface clock latency , in this case, means the
* time described by a value of 1 in the interrupt
* coalescing registers' time fields. Since those fields
* refer to the time it takes for 64 clocks to pass, the
@@ -166,9 +172,28 @@ extern const char gfar_driver_version[];
mk_ic_icft(count) | \
mk_ic_ictt(time))
+#define RCTRL_PAL_MASK 0x001f0000
+#define RCTRL_VLEX 0x00002000
+#define RCTRL_FILREN 0x00001000
+#define RCTRL_GHTX 0x00000400
+#define RCTRL_IPCSEN 0x00000200
+#define RCTRL_TUCSEN 0x00000100
+#define RCTRL_PRSDEP_MASK 0x000000c0
+#define RCTRL_PRSDEP_INIT 0x000000c0
#define RCTRL_PROM 0x00000008
+#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \
+ | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT)
+#define RCTRL_EXTHASH (RCTRL_GHTX)
+#define RCTRL_VLAN (RCTRL_PRSDEP_INIT)
+
+
#define RSTAT_CLEAR_RHALT 0x00800000
+#define TCTRL_IPCSEN 0x00004000
+#define TCTRL_TUCSEN 0x00002000
+#define TCTRL_VLINS 0x00001000
+#define TCTRL_INIT_CSUM (TCTRL_TUCSEN | TCTRL_IPCSEN)
+
#define IEVENT_INIT_CLEAR 0xffffffff
#define IEVENT_BABR 0x80000000
#define IEVENT_RXC 0x40000000
@@ -187,12 +212,16 @@ extern const char gfar_driver_version[];
#define IEVENT_RXB0 0x00008000
#define IEVENT_GRSC 0x00000100
#define IEVENT_RXF0 0x00000080
+#define IEVENT_FIR 0x00000008
+#define IEVENT_FIQ 0x00000004
+#define IEVENT_DPE 0x00000002
+#define IEVENT_PERR 0x00000001
#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0)
#define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF)
#define IEVENT_ERR_MASK \
(IEVENT_RXC | IEVENT_BSY | IEVENT_EBERR | IEVENT_MSRO | \
IEVENT_BABT | IEVENT_TXC | IEVENT_TXE | IEVENT_LC \
- | IEVENT_CRL | IEVENT_XFUN)
+ | IEVENT_CRL | IEVENT_XFUN | IEVENT_DPE | IEVENT_PERR)
#define IMASK_INIT_CLEAR 0x00000000
#define IMASK_BABR 0x80000000
@@ -212,10 +241,15 @@ extern const char gfar_driver_version[];
#define IMASK_RXB0 0x00008000
#define IMASK_GTSC 0x00000100
#define IMASK_RXFEN0 0x00000080
+#define IMASK_FIR 0x00000008
+#define IMASK_FIQ 0x00000004
+#define IMASK_DPE 0x00000002
+#define IMASK_PERR 0x00000001
#define IMASK_RX_DISABLED ~(IMASK_RXFEN0 | IMASK_BSY)
#define IMASK_DEFAULT (IMASK_TXEEN | IMASK_TXFEN | IMASK_TXBEN | \
IMASK_RXFEN0 | IMASK_BSY | IMASK_EBERR | IMASK_BABR | \
- IMASK_XFUN | IMASK_RXC | IMASK_BABT)
+ IMASK_XFUN | IMASK_RXC | IMASK_BABT | IMASK_DPE \
+ | IMASK_PERR)
/* Attribute fields */
@@ -254,6 +288,18 @@ extern const char gfar_driver_version[];
#define TXBD_RETRYLIMIT 0x0040
#define TXBD_RETRYCOUNTMASK 0x003c
#define TXBD_UNDERRUN 0x0002
+#define TXBD_TOE 0x0002
+
+/* Tx FCB param bits */
+#define TXFCB_VLN 0x80
+#define TXFCB_IP 0x40
+#define TXFCB_IP6 0x20
+#define TXFCB_TUP 0x10
+#define TXFCB_UDP 0x08
+#define TXFCB_CIP 0x04
+#define TXFCB_CTU 0x02
+#define TXFCB_NPH 0x01
+#define TXFCB_DEFAULT (TXFCB_IP|TXFCB_TUP|TXFCB_CTU|TXFCB_NPH)
/* RxBD status field bits */
#define RXBD_EMPTY 0x8000
@@ -273,6 +319,18 @@ extern const char gfar_driver_version[];
#define RXBD_TRUNCATED 0x0001
#define RXBD_STATS 0x01ff
+/* Rx FCB status field bits */
+#define RXFCB_VLN 0x8000
+#define RXFCB_IP 0x4000
+#define RXFCB_IP6 0x2000
+#define RXFCB_TUP 0x1000
+#define RXFCB_CIP 0x0800
+#define RXFCB_CTU 0x0400
+#define RXFCB_EIP 0x0200
+#define RXFCB_ETU 0x0100
+#define RXFCB_PERR_MASK 0x000c
+#define RXFCB_PERR_BADL3 0x0008
+
struct txbd8
{
u16 status; /* Status Fields */
@@ -280,6 +338,22 @@ struct txbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct txfcb {
+ u8 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ udp:1,
+ cip:1,
+ ctu:1,
+ nph:1;
+ u8 reserved;
+ u8 l4os; /* Level 4 Header Offset */
+ u8 l3os; /* Level 3 Header Offset */
+ u16 phcs; /* Pseudo-header Checksum */
+ u16 vlctl; /* VLAN control word */
+};
+
struct rxbd8
{
u16 status; /* Status Fields */
@@ -287,6 +361,21 @@ struct rxbd8
u32 bufPtr; /* Buffer Pointer */
};
+struct rxfcb {
+ u16 vln:1,
+ ip:1,
+ ip6:1,
+ tup:1,
+ cip:1,
+ ctu:1,
+ eip:1,
+ etu:1;
+ u8 rq; /* Receive Queue index */
+ u8 pro; /* Layer 4 Protocol */
+ u16 reserved;
+ u16 vlctl; /* VLAN control word */
+};
+
struct rmon_mib
{
u32 tr64; /* 0x.680 - Transmit and Receive 64-byte Frame Counter */
@@ -371,90 +460,191 @@ struct gfar_stats {
struct gfar {
- u8 res1[16];
- u32 ievent; /* 0x.010 - Interrupt Event Register */
- u32 imask; /* 0x.014 - Interrupt Mask Register */
- u32 edis; /* 0x.018 - Error Disabled Register */
+ u32 tsec_id; /* 0x.000 - Controller ID register */
+ u8 res1[12];
+ u32 ievent; /* 0x.010 - Interrupt Event Register */
+ u32 imask; /* 0x.014 - Interrupt Mask Register */
+ u32 edis; /* 0x.018 - Error Disabled Register */
u8 res2[4];
- u32 ecntrl; /* 0x.020 - Ethernet Control Register */
- u32 minflr; /* 0x.024 - Minimum Frame Length Register */
- u32 ptv; /* 0x.028 - Pause Time Value Register */
- u32 dmactrl; /* 0x.02c - DMA Control Register */
- u32 tbipa; /* 0x.030 - TBI PHY Address Register */
+ u32 ecntrl; /* 0x.020 - Ethernet Control Register */
+ u32 minflr; /* 0x.024 - Minimum Frame Length Register */
+ u32 ptv; /* 0x.028 - Pause Time Value Register */
+ u32 dmactrl; /* 0x.02c - DMA Control Register */
+ u32 tbipa; /* 0x.030 - TBI PHY Address Register */
u8 res3[88];
- u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
+ u32 fifo_tx_thr; /* 0x.08c - FIFO transmit threshold register */
u8 res4[8];
- u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
+ u32 fifo_tx_starve; /* 0x.098 - FIFO transmit starve register */
u32 fifo_tx_starve_shutoff; /* 0x.09c - FIFO transmit starve shutoff register */
- u8 res5[96];
- u32 tctrl; /* 0x.100 - Transmit Control Register */
- u32 tstat; /* 0x.104 - Transmit Status Register */
- u8 res6[4];
- u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
- u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
- u8 res7[16];
- u32 ctbptr; /* 0x.124 - Current Transmit Buffer Descriptor Pointer Register */
- u8 res8[92];
- u32 tbptr; /* 0x.184 - Transmit Buffer Descriptor Pointer Low Register */
- u8 res9[124];
- u32 tbase; /* 0x.204 - Transmit Descriptor Base Address Register */
- u8 res10[168];
- u32 ostbd; /* 0x.2b0 - Out-of-Sequence Transmit Buffer Descriptor Register */
- u32 ostbdp; /* 0x.2b4 - Out-of-Sequence Transmit Data Buffer Pointer Register */
- u8 res11[72];
- u32 rctrl; /* 0x.300 - Receive Control Register */
- u32 rstat; /* 0x.304 - Receive Status Register */
- u8 res12[4];
- u32 rbdlen; /* 0x.30c - RxBD Data Length Register */
- u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
- u8 res13[16];
- u32 crbptr; /* 0x.324 - Current Receive Buffer Descriptor Pointer */
- u8 res14[24];
- u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
- u8 res15[64];
- u32 rbptr; /* 0x.384 - Receive Buffer Descriptor Pointer */
- u8 res16[124];
- u32 rbase; /* 0x.404 - Receive Descriptor Base Address */
- u8 res17[248];
- u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
- u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
- u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
- u32 hafdup; /* 0x.50c - Half Duplex Register */
- u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
+ u8 res5[4];
+ u32 fifo_rx_pause; /* 0x.0a4 - FIFO receive pause threshold register */
+ u32 fifo_rx_alarm; /* 0x.0a8 - FIFO receive alarm threshold register */
+ u8 res6[84];
+ u32 tctrl; /* 0x.100 - Transmit Control Register */
+ u32 tstat; /* 0x.104 - Transmit Status Register */
+ u32 dfvlan; /* 0x.108 - Default VLAN Control word */
+ u32 tbdlen; /* 0x.10c - Transmit Buffer Descriptor Data Length Register */
+ u32 txic; /* 0x.110 - Transmit Interrupt Coalescing Configuration Register */
+ u32 tqueue; /* 0x.114 - Transmit queue control register */
+ u8 res7[40];
+ u32 tr03wt; /* 0x.140 - TxBD Rings 0-3 round-robin weightings */
+ u32 tr47wt; /* 0x.144 - TxBD Rings 4-7 round-robin weightings */
+ u8 res8[52];
+ u32 tbdbph; /* 0x.17c - Tx data buffer pointer high */
+ u8 res9a[4];
+ u32 tbptr0; /* 0x.184 - TxBD Pointer for ring 0 */
+ u8 res9b[4];
+ u32 tbptr1; /* 0x.18c - TxBD Pointer for ring 1 */
+ u8 res9c[4];
+ u32 tbptr2; /* 0x.194 - TxBD Pointer for ring 2 */
+ u8 res9d[4];
+ u32 tbptr3; /* 0x.19c - TxBD Pointer for ring 3 */
+ u8 res9e[4];
+ u32 tbptr4; /* 0x.1a4 - TxBD Pointer for ring 4 */
+ u8 res9f[4];
+ u32 tbptr5; /* 0x.1ac - TxBD Pointer for ring 5 */
+ u8 res9g[4];
+ u32 tbptr6; /* 0x.1b4 - TxBD Pointer for ring 6 */
+ u8 res9h[4];
+ u32 tbptr7; /* 0x.1bc - TxBD Pointer for ring 7 */
+ u8 res9[64];
+ u32 tbaseh; /* 0x.200 - TxBD base address high */
+ u32 tbase0; /* 0x.204 - TxBD Base Address of ring 0 */
+ u8 res10a[4];
+ u32 tbase1; /* 0x.20c - TxBD Base Address of ring 1 */
+ u8 res10b[4];
+ u32 tbase2; /* 0x.214 - TxBD Base Address of ring 2 */
+ u8 res10c[4];
+ u32 tbase3; /* 0x.21c - TxBD Base Address of ring 3 */
+ u8 res10d[4];
+ u32 tbase4; /* 0x.224 - TxBD Base Address of ring 4 */
+ u8 res10e[4];
+ u32 tbase5; /* 0x.22c - TxBD Base Address of ring 5 */
+ u8 res10f[4];
+ u32 tbase6; /* 0x.234 - TxBD Base Address of ring 6 */
+ u8 res10g[4];
+ u32 tbase7; /* 0x.23c - TxBD Base Address of ring 7 */
+ u8 res10[192];
+ u32 rctrl; /* 0x.300 - Receive Control Register */
+ u32 rstat; /* 0x.304 - Receive Status Register */
+ u8 res12[8];
+ u32 rxic; /* 0x.310 - Receive Interrupt Coalescing Configuration Register */
+ u32 rqueue; /* 0x.314 - Receive queue control register */
+ u8 res13[24];
+ u32 rbifx; /* 0x.330 - Receive bit field extract control register */
+ u32 rqfar; /* 0x.334 - Receive queue filing table address register */
+ u32 rqfcr; /* 0x.338 - Receive queue filing table control register */
+ u32 rqfpr; /* 0x.33c - Receive queue filing table property register */
+ u32 mrblr; /* 0x.340 - Maximum Receive Buffer Length Register */
+ u8 res14[56];
+ u32 rbdbph; /* 0x.37c - Rx data buffer pointer high */
+ u8 res15a[4];
+ u32 rbptr0; /* 0x.384 - RxBD pointer for ring 0 */
+ u8 res15b[4];
+ u32 rbptr1; /* 0x.38c - RxBD pointer for ring 1 */
+ u8 res15c[4];
+ u32 rbptr2; /* 0x.394 - RxBD pointer for ring 2 */
+ u8 res15d[4];
+ u32 rbptr3; /* 0x.39c - RxBD pointer for ring 3 */
+ u8 res15e[4];
+ u32 rbptr4; /* 0x.3a4 - RxBD pointer for ring 4 */
+ u8 res15f[4];
+ u32 rbptr5; /* 0x.3ac - RxBD pointer for ring 5 */
+ u8 res15g[4];
+ u32 rbptr6; /* 0x.3b4 - RxBD pointer for ring 6 */
+ u8 res15h[4];
+ u32 rbptr7; /* 0x.3bc - RxBD pointer for ring 7 */
+ u8 res16[64];
+ u32 rbaseh; /* 0x.400 - RxBD base address high */
+ u32 rbase0; /* 0x.404 - RxBD base address of ring 0 */
+ u8 res17a[4];
+ u32 rbase1; /* 0x.40c - RxBD base address of ring 1 */
+ u8 res17b[4];
+ u32 rbase2; /* 0x.414 - RxBD base address of ring 2 */
+ u8 res17c[4];
+ u32 rbase3; /* 0x.41c - RxBD base address of ring 3 */
+ u8 res17d[4];
+ u32 rbase4; /* 0x.424 - RxBD base address of ring 4 */
+ u8 res17e[4];
+ u32 rbase5; /* 0x.42c - RxBD base address of ring 5 */
+ u8 res17f[4];
+ u32 rbase6; /* 0x.434 - RxBD base address of ring 6 */
+ u8 res17g[4];
+ u32 rbase7; /* 0x.43c - RxBD base address of ring 7 */
+ u8 res17[192];
+ u32 maccfg1; /* 0x.500 - MAC Configuration 1 Register */
+ u32 maccfg2; /* 0x.504 - MAC Configuration 2 Register */
+ u32 ipgifg; /* 0x.508 - Inter Packet Gap/Inter Frame Gap Register */
+ u32 hafdup; /* 0x.50c - Half Duplex Register */
+ u32 maxfrm; /* 0x.510 - Maximum Frame Length Register */
u8 res18[12];
- u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
- u32 miimcom; /* 0x.524 - MII Management Command Register */
- u32 miimadd; /* 0x.528 - MII Management Address Register */
- u32 miimcon; /* 0x.52c - MII Management Control Register */
- u32 miimstat; /* 0x.530 - MII Management Status Register */
- u32 miimind; /* 0x.534 - MII Management Indicator Register */
+ u32 miimcfg; /* 0x.520 - MII Management Configuration Register */
+ u32 miimcom; /* 0x.524 - MII Management Command Register */
+ u32 miimadd; /* 0x.528 - MII Management Address Register */
+ u32 miimcon; /* 0x.52c - MII Management Control Register */
+ u32 miimstat; /* 0x.530 - MII Management Status Register */
+ u32 miimind; /* 0x.534 - MII Management Indicator Register */
u8 res19[4];
- u32 ifstat; /* 0x.53c - Interface Status Register */
- u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
- u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
- u8 res20[312];
- struct rmon_mib rmon;
- u8 res21[192];
- u32 iaddr0; /* 0x.800 - Indivdual address register 0 */
- u32 iaddr1; /* 0x.804 - Indivdual address register 1 */
- u32 iaddr2; /* 0x.808 - Indivdual address register 2 */
- u32 iaddr3; /* 0x.80c - Indivdual address register 3 */
- u32 iaddr4; /* 0x.810 - Indivdual address register 4 */
- u32 iaddr5; /* 0x.814 - Indivdual address register 5 */
- u32 iaddr6; /* 0x.818 - Indivdual address register 6 */
- u32 iaddr7; /* 0x.81c - Indivdual address register 7 */
+ u32 ifstat; /* 0x.53c - Interface Status Register */
+ u32 macstnaddr1; /* 0x.540 - Station Address Part 1 Register */
+ u32 macstnaddr2; /* 0x.544 - Station Address Part 2 Register */
+ u32 mac01addr1; /* 0x.548 - MAC exact match address 1, part 1 */
+ u32 mac01addr2; /* 0x.54c - MAC exact match address 1, part 2 */
+ u32 mac02addr1; /* 0x.550 - MAC exact match address 2, part 1 */
+ u32 mac02addr2; /* 0x.554 - MAC exact match address 2, part 2 */
+ u32 mac03addr1; /* 0x.558 - MAC exact match address 3, part 1 */
+ u32 mac03addr2; /* 0x.55c - MAC exact match address 3, part 2 */
+ u32 mac04addr1; /* 0x.560 - MAC exact match address 4, part 1 */
+ u32 mac04addr2; /* 0x.564 - MAC exact match address 4, part 2 */
+ u32 mac05addr1; /* 0x.568 - MAC exact match address 5, part 1 */
+ u32 mac05addr2; /* 0x.56c - MAC exact match address 5, part 2 */
+ u32 mac06addr1; /* 0x.570 - MAC exact match address 6, part 1 */
+ u32 mac06addr2; /* 0x.574 - MAC exact match address 6, part 2 */
+ u32 mac07addr1; /* 0x.578 - MAC exact match address 7, part 1 */
+ u32 mac07addr2; /* 0x.57c - MAC exact match address 7, part 2 */
+ u32 mac08addr1; /* 0x.580 - MAC exact match address 8, part 1 */
+ u32 mac08addr2; /* 0x.584 - MAC exact match address 8, part 2 */
+ u32 mac09addr1; /* 0x.588 - MAC exact match address 9, part 1 */
+ u32 mac09addr2; /* 0x.58c - MAC exact match address 9, part 2 */
+ u32 mac10addr1; /* 0x.590 - MAC exact match address 10, part 1*/
+ u32 mac10addr2; /* 0x.594 - MAC exact match address 10, part 2*/
+ u32 mac11addr1; /* 0x.598 - MAC exact match address 11, part 1*/
+ u32 mac11addr2; /* 0x.59c - MAC exact match address 11, part 2*/
+ u32 mac12addr1; /* 0x.5a0 - MAC exact match address 12, part 1*/
+ u32 mac12addr2; /* 0x.5a4 - MAC exact match address 12, part 2*/
+ u32 mac13addr1; /* 0x.5a8 - MAC exact match address 13, part 1*/
+ u32 mac13addr2; /* 0x.5ac - MAC exact match address 13, part 2*/
+ u32 mac14addr1; /* 0x.5b0 - MAC exact match address 14, part 1*/
+ u32 mac14addr2; /* 0x.5b4 - MAC exact match address 14, part 2*/
+ u32 mac15addr1; /* 0x.5b8 - MAC exact match address 15, part 1*/
+ u32 mac15addr2; /* 0x.5bc - MAC exact match address 15, part 2*/
+ u8 res20[192];
+ struct rmon_mib rmon; /* 0x.680-0x.73c */
+ u32 rrej; /* 0x.740 - Receive filer rejected packet counter */
+ u8 res21[188];
+ u32 igaddr0; /* 0x.800 - Indivdual/Group address register 0*/
+ u32 igaddr1; /* 0x.804 - Indivdual/Group address register 1*/
+ u32 igaddr2; /* 0x.808 - Indivdual/Group address register 2*/
+ u32 igaddr3; /* 0x.80c - Indivdual/Group address register 3*/
+ u32 igaddr4; /* 0x.810 - Indivdual/Group address register 4*/
+ u32 igaddr5; /* 0x.814 - Indivdual/Group address register 5*/
+ u32 igaddr6; /* 0x.818 - Indivdual/Group address register 6*/
+ u32 igaddr7; /* 0x.81c - Indivdual/Group address register 7*/
u8 res22[96];
- u32 gaddr0; /* 0x.880 - Global address register 0 */
- u32 gaddr1; /* 0x.884 - Global address register 1 */
- u32 gaddr2; /* 0x.888 - Global address register 2 */
- u32 gaddr3; /* 0x.88c - Global address register 3 */
- u32 gaddr4; /* 0x.890 - Global address register 4 */
- u32 gaddr5; /* 0x.894 - Global address register 5 */
- u32 gaddr6; /* 0x.898 - Global address register 6 */
- u32 gaddr7; /* 0x.89c - Global address register 7 */
- u8 res23[856];
- u32 attr; /* 0x.bf8 - Attributes Register */
- u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
+ u32 gaddr0; /* 0x.880 - Group address register 0 */
+ u32 gaddr1; /* 0x.884 - Group address register 1 */
+ u32 gaddr2; /* 0x.888 - Group address register 2 */
+ u32 gaddr3; /* 0x.88c - Group address register 3 */
+ u32 gaddr4; /* 0x.890 - Group address register 4 */
+ u32 gaddr5; /* 0x.894 - Group address register 5 */
+ u32 gaddr6; /* 0x.898 - Group address register 6 */
+ u32 gaddr7; /* 0x.89c - Group address register 7 */
+ u8 res23a[352];
+ u32 fifocfg; /* 0x.a00 - FIFO interface config register */
+ u8 res23b[252];
+ u8 res23c[248];
+ u32 attr; /* 0x.bf8 - Attributes Register */
+ u32 attreli; /* 0x.bfc - Attributes Extract Length and Extract Index Register */
u8 res24[1024];
};
@@ -496,6 +686,8 @@ 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 */
+ u32 *hash_regs[16];
+ int hash_width;
struct gfar *phyregs;
struct work_struct tq;
struct timer_list phy_info_timer;
@@ -506,9 +698,12 @@ struct gfar_private {
unsigned int rx_stash_size;
unsigned int tx_ring_size;
unsigned int rx_ring_size;
- wait_queue_head_t rxcleanupq;
- unsigned int rxclean;
+ unsigned char vlan_enable:1,
+ rx_csum_enable:1,
+ extended_hash:1;
+ unsigned short padding;
+ struct vlan_group *vlgrp;
/* Info structure initialized by board setup code */
unsigned int interruptTransmit;
unsigned int interruptReceive;
@@ -519,6 +714,8 @@ struct gfar_private {
int oldspeed;
int oldduplex;
int oldlink;
+
+ uint32_t msg_enable;
};
extern inline u32 gfar_read(volatile unsigned *addr)
diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c
index 28046e9e88ba..a451de629197 100644
--- a/drivers/net/gianfar_ethtool.c
+++ b/drivers/net/gianfar_ethtool.c
@@ -46,16 +46,18 @@
extern int startup_gfar(struct net_device *dev);
extern void stop_gfar(struct net_device *dev);
-extern void gfar_receive(int irq, void *dev_id, struct pt_regs *regs);
+extern void gfar_halt(struct net_device *dev);
+extern void gfar_start(struct net_device *dev);
+extern int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit);
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
u64 * buf);
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
-void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf);
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals);
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals);
+static void gfar_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo);
static char stat_gstrings[][ETH_GSTRING_LEN] = {
"rx-dropped-by-kernel",
@@ -118,57 +120,56 @@ static char stat_gstrings[][ETH_GSTRING_LEN] = {
"tx-fragmented-frames",
};
+/* Fill in a buffer with the strings which correspond to the
+ * stats */
+static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
+ else
+ memcpy(buf, stat_gstrings,
+ GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+}
+
/* Fill in an array of 64-bit statistics from various sources.
* This array will be appended to the end of the ethtool_stats
* structure, and returned to user space
*/
-void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
+static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, u64 * buf)
{
int i;
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;
- for (i = 0; i < GFAR_RMON_LEN; i++) {
- stats->rmon[i] = (u64) (rmon[i]);
- }
-
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- stats->extra[i] = extra[i];
- }
-}
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) {
+ u32 *rmon = (u32 *) & priv->regs->rmon;
+ struct gfar_stats *stats = (struct gfar_stats *) buf;
-/* Returns the number of stats (and their corresponding strings) */
-int gfar_stats_count(struct net_device *dev)
-{
- return GFAR_STATS_LEN;
-}
+ for (i = 0; i < GFAR_RMON_LEN; i++)
+ stats->rmon[i] = (u64) (rmon[i]);
-void gfar_gstrings_normon(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_EXTRA_STATS_LEN * ETH_GSTRING_LEN);
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ stats->extra[i] = extra[i];
+ } else
+ for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++)
+ buf[i] = extra[i];
}
-void gfar_fill_stats_normon(struct net_device *dev,
- struct ethtool_stats *dummy, u64 * buf)
+/* Returns the number of stats (and their corresponding strings) */
+static int gfar_stats_count(struct net_device *dev)
{
- int i;
struct gfar_private *priv = netdev_priv(dev);
- u64 *extra = (u64 *) & priv->extra_stats;
- for (i = 0; i < GFAR_EXTRA_STATS_LEN; i++) {
- buf[i] = extra[i];
- }
+ if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON)
+ return GFAR_STATS_LEN;
+ else
+ return GFAR_EXTRA_STATS_LEN;
}
-
-int gfar_stats_count_normon(struct net_device *dev)
-{
- return GFAR_EXTRA_STATS_LEN;
-}
/* Fills in the drvinfo structure with some basic info */
-void gfar_gdrvinfo(struct net_device *dev, struct
+static void gfar_gdrvinfo(struct net_device *dev, struct
ethtool_drvinfo *drvinfo)
{
strncpy(drvinfo->driver, DRV_NAME, GFAR_INFOSTR_LEN);
@@ -182,7 +183,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)
+static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
{
struct gfar_private *priv = netdev_priv(dev);
uint gigabit_support =
@@ -216,13 +217,13 @@ int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd)
}
/* Return the length of the register structure */
-int gfar_reglen(struct net_device *dev)
+static int gfar_reglen(struct net_device *dev)
{
return sizeof (struct gfar);
}
/* Return a dump of the GFAR register space */
-void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
+static void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regbuf)
{
int i;
struct gfar_private *priv = netdev_priv(dev);
@@ -233,13 +234,6 @@ void gfar_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *regb
buf[i] = theregs[i];
}
-/* Fill in a buffer with the strings which correspond to the
- * stats */
-void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf)
-{
- memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN);
-}
-
/* Convert microseconds to ethernet clock ticks, which changes
* depending on what speed the controller is running at */
static unsigned int gfar_usecs2ticks(struct gfar_private *priv, unsigned int usecs)
@@ -291,9 +285,12 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic
/* Get the coalescing parameters, and put them in the cvals
* structure. */
-int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime);
cvals->rx_max_coalesced_frames = priv->rxcount;
@@ -337,10 +334,13 @@ int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
* Both cvals->*_usecs and cvals->*_frames have to be > 0
* in order for coalescing to be active
*/
-int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
+static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
{
struct gfar_private *priv = netdev_priv(dev);
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE))
+ return -EOPNOTSUPP;
+
/* Set up rx coalescing */
if ((cvals->rx_coalesce_usecs == 0) ||
(cvals->rx_max_coalesced_frames == 0))
@@ -379,7 +379,7 @@ int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals)
/* Fills in rvals with the current ring parameters. Currently,
* rx, rx_mini, and rx_jumbo rings are the same size, as mini and
* jumbo are ignored by the driver */
-void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
struct gfar_private *priv = netdev_priv(dev);
@@ -401,9 +401,8 @@ void gfar_gringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
* necessary so that we don't mess things up while we're in
* motion. We wait for the ring to be clean before reallocating
* the rings. */
-int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
+static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
{
- u32 tempval;
struct gfar_private *priv = netdev_priv(dev);
int err = 0;
@@ -425,37 +424,54 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return -EINVAL;
}
- /* Stop the controller so we don't rx any more frames */
- /* But first, make sure we clear the bits */
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval &= ~(DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
- tempval = gfar_read(&priv->regs->dmactrl);
- tempval |= (DMACTRL_GRS | DMACTRL_GTS);
- gfar_write(&priv->regs->dmactrl, tempval);
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
- while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC)))
- cpu_relax();
+ /* Now we take down the rings to rebuild them */
+ stop_gfar(dev);
+ }
- /* Note that rx is not clean right now */
- priv->rxclean = 0;
+ /* Change the size */
+ priv->rx_ring_size = rvals->rx_pending;
+ priv->tx_ring_size = rvals->tx_pending;
- if (dev->flags & IFF_UP) {
- /* Tell the driver to process the rest of the frames */
- gfar_receive(0, (void *) dev, NULL);
+ /* Rebuild the rings with the new size */
+ if (dev->flags & IFF_UP)
+ err = startup_gfar(dev);
- /* Now wait for it to be done */
- wait_event_interruptible(priv->rxcleanupq, priv->rxclean);
+ return err;
+}
- /* Ok, all packets have been handled. Now we bring it down,
- * change the ring size, and bring it up */
+static int gfar_set_rx_csum(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ int err = 0;
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ if (dev->flags & IFF_UP) {
+ unsigned long flags;
+
+ /* Halt TX and RX, and process the frames which
+ * have already been received */
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+ gfar_clean_rx_ring(dev, priv->rx_ring_size);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* Now we take down the rings to rebuild them */
stop_gfar(dev);
}
- priv->rx_ring_size = rvals->rx_pending;
- priv->tx_ring_size = rvals->tx_pending;
+ priv->rx_csum_enable = data;
if (dev->flags & IFF_UP)
err = startup_gfar(dev);
@@ -463,6 +479,61 @@ int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rvals)
return err;
}
+static uint32_t gfar_get_rx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return priv->rx_csum_enable;
+}
+
+static int gfar_set_tx_csum(struct net_device *dev, uint32_t data)
+{
+ unsigned long flags;
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return -EOPNOTSUPP;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ gfar_halt(dev);
+
+ if (data)
+ dev->features |= NETIF_F_IP_CSUM;
+ else
+ dev->features &= ~NETIF_F_IP_CSUM;
+
+ gfar_start(dev);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return 0;
+}
+
+static uint32_t gfar_get_tx_csum(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+
+ if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM))
+ return 0;
+
+ return (dev->features & NETIF_F_IP_CSUM) != 0;
+}
+
+static uint32_t gfar_get_msglevel(struct net_device *dev)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ return priv->msg_enable;
+}
+
+static void gfar_set_msglevel(struct net_device *dev, uint32_t data)
+{
+ struct gfar_private *priv = netdev_priv(dev);
+ priv->msg_enable = data;
+}
+
+
struct ethtool_ops gfar_ethtool_ops = {
.get_settings = gfar_gsettings,
.get_drvinfo = gfar_gdrvinfo,
@@ -476,52 +547,10 @@ struct ethtool_ops gfar_ethtool_ops = {
.get_strings = gfar_gstrings,
.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
+ .get_rx_csum = gfar_get_rx_csum,
+ .get_tx_csum = gfar_get_tx_csum,
+ .set_rx_csum = gfar_set_rx_csum,
+ .set_tx_csum = gfar_set_tx_csum,
+ .get_msglevel = gfar_get_msglevel,
+ .set_msglevel = gfar_set_msglevel,
};
diff --git a/drivers/net/gianfar_phy.c b/drivers/net/gianfar_phy.c
index 02b16abc89bd..7c965f268a82 100644
--- a/drivers/net/gianfar_phy.c
+++ b/drivers/net/gianfar_phy.c
@@ -572,7 +572,7 @@ static struct phy_info phy_info_dm9161 = {
static struct phy_info phy_info_marvell = {
.phy_id = 0x01410c00,
.phy_id_mask = 0xffffff00,
- .name = "Marvell 88E1101",
+ .name = "Marvell 88E1101/88E1111",
.features = MII_GBIT_FEATURES,
.config_aneg = &marvell_config_aneg,
.read_status = &marvell_read_status,
diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c
index 3d96714ed3cf..d9df1d9a5739 100644
--- a/drivers/net/hamachi.c
+++ b/drivers/net/hamachi.c
@@ -1149,7 +1149,7 @@ static void hamachi_tx_timeout(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
- skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
DescEndPacket | DescIntr | (hmp->rx_buf_sz - 2));
}
@@ -1210,7 +1210,7 @@ static void hamachi_init_ring(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
hmp->rx_ring[i].addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
- skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
/* -2 because it doesn't REALLY have that first 2 bytes -KDU */
hmp->rx_ring[i].status_n_length = cpu_to_le32(DescOwn |
DescEndPacket | DescIntr | (hmp->rx_buf_sz -2));
@@ -1509,7 +1509,7 @@ static int hamachi_rx(struct net_device *dev)
desc->addr,
hmp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- buf_addr = (u8 *) hmp->rx_skbuff[entry]->tail;
+ buf_addr = (u8 *) hmp->rx_skbuff[entry]->data;
frame_status = le32_to_cpu(get_unaligned((s32*)&(buf_addr[data_size - 12])));
if (hamachi_debug > 4)
printk(KERN_DEBUG " hamachi_rx() status was %8.8x.\n",
@@ -1678,7 +1678,7 @@ static int hamachi_rx(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
desc->addr = cpu_to_leXX(pci_map_single(hmp->pci_dev,
- skb->tail, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ skb->data, hmp->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
desc->status_n_length = cpu_to_le32(hmp->rx_buf_sz);
if (entry >= RX_RING_SIZE-1)
@@ -1772,9 +1772,9 @@ static int hamachi_close(struct net_device *dev)
readl(ioaddr + RxCurPtr) == (long)&hmp->rx_ring[i] ? '>' : ' ',
i, hmp->rx_ring[i].status_n_length, hmp->rx_ring[i].addr);
if (hamachi_debug > 6) {
- if (*(u8*)hmp->rx_skbuff[i]->tail != 0x69) {
+ if (*(u8*)hmp->rx_skbuff[i]->data != 0x69) {
u16 *addr = (u16 *)
- hmp->rx_skbuff[i]->tail;
+ hmp->rx_skbuff[i]->data;
int j;
for (j = 0; j < 0x50; j++)
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index ece1b1a13186..c27e417f32bf 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -304,7 +304,7 @@ static inline void scc_discard_buffers(struct scc_channel *scc)
scc->tx_buff = NULL;
}
- while (skb_queue_len(&scc->tx_queue))
+ while (!skb_queue_empty(&scc->tx_queue))
dev_kfree_skb(skb_dequeue(&scc->tx_queue));
spin_unlock_irqrestore(&scc->lock, flags);
@@ -1126,8 +1126,7 @@ static void t_dwait(unsigned long channel)
if (scc->stat.tx_state == TXS_WAIT) /* maxkeyup or idle timeout */
{
- if (skb_queue_len(&scc->tx_queue) == 0) /* nothing to send */
- {
+ if (skb_queue_empty(&scc->tx_queue)) { /* nothing to send */
scc->stat.tx_state = TXS_IDLE;
netif_wake_queue(scc->dev); /* t_maxkeyup locked it. */
return;
diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c
index 4834314b676d..0abf5dd08b4c 100644
--- a/drivers/net/hp-plus.c
+++ b/drivers/net/hp-plus.c
@@ -159,12 +159,7 @@ struct net_device * __init hp_plus_probe(int unit)
err = do_hpp_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -271,6 +266,9 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr)
/* Leave the 8390 and HP chip reset. */
outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION);
+ retval = register_netdev(dev);
+ if (retval)
+ goto out;
return 0;
out:
release_region(ioaddr, HP_IO_EXTENT);
@@ -463,11 +461,8 @@ init_module(void)
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
if (do_hpp_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_hpp[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_hpp[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "hp-plus.c: No HP-Plus card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/hp.c b/drivers/net/hp.c
index 026888611d6f..59cf841b14ab 100644
--- a/drivers/net/hp.c
+++ b/drivers/net/hp.c
@@ -123,12 +123,7 @@ struct net_device * __init hp_probe(int unit)
err = do_hp_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -227,7 +222,12 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr)
ei_status.block_output = &hp_block_output;
hp_init_card(dev);
+ retval = register_netdev(dev);
+ if (retval)
+ goto out1;
return 0;
+out1:
+ free_irq(dev->irq, dev);
out:
release_region(ioaddr, HP_IO_EXTENT);
return retval;
@@ -432,11 +432,8 @@ init_module(void)
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
if (do_hp_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_hp[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_hp[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "hp.c: No HP card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c
index b3a898c5a585..cf0ac6fda1a1 100644
--- a/drivers/net/hp100.c
+++ b/drivers/net/hp100.c
@@ -106,6 +106,7 @@
#include <linux/interrupt.h>
#include <linux/eisa.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -417,12 +418,7 @@ struct net_device * __init hp100_probe(int unit)
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
- out1:
- release_region(dev->base_addr, HP100_REGION_SIZE);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -562,7 +558,7 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
* Also, we can have EISA Busmaster cards (not tested),
* so beware !!! - Jean II */
if((bus == HP100_BUS_PCI) &&
- (pci_set_dma_mask(pci_dev, 0xffffffff))) {
+ (pci_set_dma_mask(pci_dev, DMA_32BIT_MASK))) {
/* Gracefully fallback to shared memory */
goto busmasterfail;
}
@@ -776,11 +772,22 @@ static int __devinit hp100_probe1(struct net_device *dev, int ioaddr,
printk("Warning! Link down.\n");
}
+ err = register_netdev(dev);
+ if (err)
+ goto out3;
+
return 0;
+out3:
+ if (local_mode == 1)
+ pci_free_consistent(lp->pci_dev, MAX_RINGSIZE + 0x0f,
+ lp->page_vaddr_algn,
+ virt_to_whatever(dev, lp->page_vaddr_algn));
+ if (mem_ptr_virt)
+ iounmap(mem_ptr_virt);
out2:
release_region(ioaddr, HP100_REGION_SIZE);
out1:
- return -ENODEV;
+ return err;
}
/* This procedure puts the card into a stable init state */
@@ -2875,18 +2882,12 @@ static int __init hp100_eisa_probe (struct device *gendev)
if (err)
goto out1;
- err = register_netdev(dev);
- if (err)
- goto out2;
-
#ifdef HP100_DEBUG
printk("hp100: %s: EISA adapter found at 0x%x\n", dev->name,
dev->base_addr);
#endif
gendev->driver_data = dev;
return 0;
- out2:
- release_region(dev->base_addr, HP100_REGION_SIZE);
out1:
free_netdev(dev);
return err;
@@ -2951,17 +2952,12 @@ static int __devinit hp100_pci_probe (struct pci_dev *pdev,
err = hp100_probe1(dev, ioaddr, HP100_BUS_PCI, pdev);
if (err)
goto out1;
- err = register_netdev(dev);
- if (err)
- goto out2;
#ifdef HP100_DEBUG
printk("hp100: %s: PCI adapter found at 0x%x\n", dev->name, ioaddr);
#endif
pci_set_drvdata(pdev, dev);
return 0;
- out2:
- release_region(dev->base_addr, HP100_REGION_SIZE);
out1:
free_netdev(dev);
out0:
@@ -3032,15 +3028,9 @@ static int __init hp100_isa_init(void)
SET_MODULE_OWNER(dev);
err = hp100_isa_probe(dev, hp100_port[i]);
- if (!err) {
- err = register_netdev(dev);
- if (!err)
- hp100_devlist[cards++] = dev;
- else
- release_region(dev->base_addr, HP100_REGION_SIZE);
- }
-
- if (err)
+ if (!err)
+ hp100_devlist[cards++] = dev;
+ else
free_netdev(dev);
}
diff --git a/drivers/net/irda/sir_kthread.c b/drivers/net/irda/sir_kthread.c
index 18cea1099530..c65054364bca 100644
--- a/drivers/net/irda/sir_kthread.c
+++ b/drivers/net/irda/sir_kthread.c
@@ -135,8 +135,7 @@ static int irda_thread(void *startup)
remove_wait_queue(&irda_rq_queue.kick, &wait);
/* make swsusp happy with our thread */
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
run_irda_queue();
}
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index 66f488c13717..15f207323d97 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -763,7 +763,7 @@ static int stir_transmit_thread(void *arg)
{
#ifdef CONFIG_PM
/* if suspending, then power off and wait */
- if (unlikely(current->flags & PF_FREEZE)) {
+ if (unlikely(freezing(current))) {
if (stir->receiving)
receive_stop(stir);
else
@@ -771,7 +771,7 @@ static int stir_transmit_thread(void *arg)
write_reg(stir, REG_CTRL1, CTRL1_TXPWD|CTRL1_RXPWD);
- refrigerator(PF_FREEZE);
+ refrigerator();
if (change_speed(stir, stir->speed))
break;
diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c
index 50bebb55e9ee..88ae8a04fabc 100644
--- a/drivers/net/isa-skeleton.c
+++ b/drivers/net/isa-skeleton.c
@@ -176,12 +176,7 @@ struct net_device * __init netcard_probe(int unit)
err = do_netcard_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -316,7 +311,15 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr)
dev->tx_timeout = &net_tx_timeout;
dev->watchdog_timeo = MY_TX_TIMEOUT;
+
+ err = register_netdev(dev);
+ if (err)
+ goto out2;
return 0;
+out2:
+#ifdef jumpered_dma
+ free_dma(dev->dma);
+#endif
out1:
#ifdef jumpered_interrupts
free_irq(dev->irq, dev);
@@ -691,11 +694,8 @@ int init_module(void)
dev->dma = dma;
dev->mem_start = mem;
if (do_netcard_probe(dev) == 0) {
- if (register_netdev(dev) == 0)
- this_device = dev;
- return 0;
- }
- cleanup_card(dev);
+ this_device = dev;
+ return 0;
}
free_netdev(dev);
return -ENXIO;
diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
index 35f6a7c271a2..097b90ccf575 100644
--- a/drivers/net/ixgb/ixgb_main.c
+++ b/drivers/net/ixgb/ixgb_main.c
@@ -47,7 +47,9 @@ char ixgb_driver_string[] = "Intel(R) PRO/10GbE Network Driver";
#else
#define DRIVERNAPI "-NAPI"
#endif
-char ixgb_driver_version[] = "1.0.95-k2"DRIVERNAPI;
+
+#define DRV_VERSION "1.0.95-k2"DRIVERNAPI
+char ixgb_driver_version[] = DRV_VERSION;
char ixgb_copyright[] = "Copyright (c) 1999-2005 Intel Corporation.";
/* ixgb_pci_tbl - PCI Device ID Table
@@ -140,6 +142,7 @@ static struct pci_driver ixgb_driver = {
MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");
MODULE_DESCRIPTION("Intel(R) PRO/10GbE Network Driver");
MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
/* some defines for controlling descriptor fetches in h/w */
#define RXDCTL_PTHRESH_DEFAULT 128 /* chip considers prefech below this */
diff --git a/drivers/net/lance.c b/drivers/net/lance.c
index dec557fb6a99..b4929beb33b2 100644
--- a/drivers/net/lance.c
+++ b/drivers/net/lance.c
@@ -356,11 +356,8 @@ int init_module(void)
dev->base_addr = io[this_dev];
dev->dma = dma[this_dev];
if (do_lance_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_lance[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_lance[found++] = dev;
+ continue;
}
free_netdev(dev);
break;
@@ -448,12 +445,7 @@ struct net_device * __init lance_probe(int unit)
err = do_lance_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -724,6 +716,9 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int
dev->tx_timeout = lance_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+ err = register_netdev(dev);
+ if (err)
+ goto out_dma;
return 0;
out_dma:
if (dev->dma != 4)
@@ -867,7 +862,7 @@ lance_init_ring(struct net_device *dev, int gfp)
lp->rx_skbuff[i] = skb;
if (skb) {
skb->dev = dev;
- rx_buff = skb->tail;
+ rx_buff = skb->data;
} else
rx_buff = kmalloc(PKT_BUF_SZ, GFP_DMA | gfp);
if (rx_buff == NULL)
diff --git a/drivers/net/lasi_82596.c b/drivers/net/lasi_82596.c
index 5e263fcba669..41bad07ac1ac 100644
--- a/drivers/net/lasi_82596.c
+++ b/drivers/net/lasi_82596.c
@@ -553,14 +553,14 @@ static inline void init_rx_bufs(struct net_device *dev)
if (skb == NULL)
panic("%s: alloc_skb() failed", __FILE__);
skb_reserve(skb, 2);
- dma_addr = dma_map_single(lp->dev, skb->tail,PKT_BUF_SZ,
+ dma_addr = dma_map_single(lp->dev, skb->data,PKT_BUF_SZ,
DMA_FROM_DEVICE);
skb->dev = dev;
rbd->v_next = rbd+1;
rbd->b_next = WSWAPrbd(virt_to_dma(lp,rbd+1));
rbd->b_addr = WSWAPrbd(virt_to_dma(lp,rbd));
rbd->skb = skb;
- rbd->v_data = skb->tail;
+ rbd->v_data = skb->data;
rbd->b_data = WSWAPchar(dma_addr);
rbd->size = PKT_BUF_SZ;
}
@@ -783,8 +783,8 @@ static inline int i596_rx(struct net_device *dev)
rx_in_place = 1;
rbd->skb = newskb;
newskb->dev = dev;
- dma_addr = dma_map_single(lp->dev, newskb->tail, PKT_BUF_SZ, DMA_FROM_DEVICE);
- rbd->v_data = newskb->tail;
+ dma_addr = dma_map_single(lp->dev, newskb->data, PKT_BUF_SZ, DMA_FROM_DEVICE);
+ rbd->v_data = newskb->data;
rbd->b_data = WSWAPchar(dma_addr);
CHECK_WBACK_INV(rbd, sizeof(struct i596_rbd));
}
diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c
index 179a97c0af69..27f0d8ac4c40 100644
--- a/drivers/net/lne390.c
+++ b/drivers/net/lne390.c
@@ -167,12 +167,7 @@ struct net_device * __init lne390_probe(int unit)
err = do_lne390_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -296,7 +291,14 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto unmap;
return 0;
+unmap:
+ if (ei_status.reg0)
+ iounmap((void *)dev->mem_start);
cleanup:
free_irq(dev->irq, dev);
return ret;
@@ -426,11 +428,8 @@ int init_module(void)
dev->base_addr = io[this_dev];
dev->mem_start = mem[this_dev];
if (do_lne390_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_lne[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_lne[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "lne390.c: No LNE390 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/mace.c b/drivers/net/mace.c
index 6ed2d7dbd44c..81d0a26e4f41 100644
--- a/drivers/net/mace.c
+++ b/drivers/net/mace.c
@@ -109,7 +109,7 @@ bitrev(int b)
}
-static int __devinit mace_probe(struct macio_dev *mdev, const struct of_match *match)
+static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mace = macio_get_of_node(mdev);
struct net_device *dev;
@@ -1009,12 +1009,10 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_HANDLED;
}
-static struct of_match mace_match[] =
+static struct of_device_id mace_match[] =
{
{
.name = "mace",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{},
};
diff --git a/drivers/net/myri_code.h b/drivers/net/myri_code.h
index 851eba8a3e00..e9c6e569d1f4 100644
--- a/drivers/net/myri_code.h
+++ b/drivers/net/myri_code.h
@@ -4775,1288 +4775,7 @@ static unsigned char lanai4_code[76256] __initdata = {
/* This is the LANai data */
static unsigned int lanai4_data_off = 0x94F0; /* half-word offset */
-static unsigned char lanai4_data[20472] __initdata = {
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,0x01,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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, 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,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,
-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,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, 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,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, 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,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, 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,0x00, 0x00,0x00, 0x00,0x00, 0x00,0x00,
-0x00,0x00, 0x00,0x00, 0x00,0x00, } ;
+static unsigned char lanai4_data[20472] __initdata;
#ifdef SYMBOL_DEFINES_COMPILED
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index aad5494c83cf..f0996ce5c268 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -369,7 +369,7 @@ static void myri_tx(struct myri_eth *mp, struct net_device *dev)
* assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol.
*/
-static unsigned short myri_type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 myri_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c
index babb59e146ea..9d6d2548c2d3 100644
--- a/drivers/net/natsemi.c
+++ b/drivers/net/natsemi.c
@@ -1926,7 +1926,7 @@ static void refill_rx(struct net_device *dev)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
np->rx_dma[entry] = pci_map_single(np->pci_dev,
- skb->tail, buflen, PCI_DMA_FROMDEVICE);
+ skb->data, buflen, PCI_DMA_FROMDEVICE);
np->rx_ring[entry].addr = cpu_to_le32(np->rx_dma[entry]);
}
np->rx_ring[entry].cmd_status = cpu_to_le32(np->rx_buf_sz);
@@ -2280,7 +2280,7 @@ static void netdev_rx(struct net_device *dev)
buflen,
PCI_DMA_FROMDEVICE);
eth_copy_and_sum(skb,
- np->rx_skbuff[entry]->tail, pkt_len, 0);
+ np->rx_skbuff[entry]->data, pkt_len, 0);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,
np->rx_dma[entry],
diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c
index 84e291e24935..8f40368cf2e9 100644
--- a/drivers/net/ne-h8300.c
+++ b/drivers/net/ne-h8300.c
@@ -180,12 +180,7 @@ struct net_device * __init ne_probe(int unit)
err = do_ne_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -325,8 +320,13 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
- return 0;
+ ret = register_netdev(dev);
+ if (ret)
+ goto out_irq;
+ return 0;
+out_irq:
+ free_irq(dev->irq, dev);
err_out:
release_region(ioaddr, NE_IO_EXTENT);
return ret;
@@ -633,11 +633,8 @@ int init_module(void)
err = init_reg_offset(dev, dev->base_addr);
if (!err) {
if (do_ne_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_ne[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_ne[found++] = dev;
+ continue;
}
}
free_netdev(dev);
diff --git a/drivers/net/ne.c b/drivers/net/ne.c
index 496433902ade..6c57096aa2e1 100644
--- a/drivers/net/ne.c
+++ b/drivers/net/ne.c
@@ -229,12 +229,7 @@ struct net_device * __init ne_probe(int unit)
err = do_ne_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -534,8 +529,14 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
+
+ ret = register_netdev(dev);
+ if (ret)
+ goto out_irq;
return 0;
+out_irq:
+ free_irq(dev->irq, dev);
err_out:
release_region(ioaddr, NE_IO_EXTENT);
return ret;
@@ -826,11 +827,8 @@ int init_module(void)
dev->mem_end = bad[this_dev];
dev->base_addr = io[this_dev];
if (do_ne_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_ne[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_ne[found++] = dev;
+ continue;
}
free_netdev(dev);
if (found)
diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c
index 6ebef27dbfae..6d62ada85de6 100644
--- a/drivers/net/ne2.c
+++ b/drivers/net/ne2.c
@@ -301,12 +301,7 @@ struct net_device * __init ne2_probe(int unit)
err = do_ne2_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -517,7 +512,14 @@ static int __init ne2_probe1(struct net_device *dev, int slot)
dev->poll_controller = ei_poll;
#endif
NS8390_init(dev, 0);
+
+ retval = register_netdev(dev);
+ if (retval)
+ goto out1;
return 0;
+out1:
+ mca_set_adapter_procfn( ei_status.priv, NULL, NULL);
+ free_irq(dev->irq, dev);
out:
release_region(base_addr, NE_IO_EXTENT);
return retval;
@@ -798,11 +800,8 @@ int init_module(void)
dev->mem_end = bad[this_dev];
dev->base_addr = io[this_dev];
if (do_ne2_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_ne[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_ne[found++] = dev;
+ continue;
}
free_netdev(dev);
break;
diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
index a1a6c08e7dcf..f1c01ac29102 100644
--- a/drivers/net/ne2k-pci.c
+++ b/drivers/net/ne2k-pci.c
@@ -660,6 +660,7 @@ static int ne2k_pci_suspend (struct pci_dev *pdev, pm_message_t state)
netif_device_detach(dev);
pci_save_state(pdev);
+ pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
return 0;
@@ -671,6 +672,8 @@ static int ne2k_pci_resume (struct pci_dev *pdev)
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
+ pci_enable_device(pdev);
+ pci_set_master(pdev);
NS8390_init(dev, 1);
netif_device_attach(dev);
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c
index c336b46bd332..e64df4d0800b 100644
--- a/drivers/net/ns83820.c
+++ b/drivers/net/ns83820.c
@@ -101,6 +101,7 @@
#include <linux/moduleparam.h>
#include <linux/types.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -573,7 +574,7 @@ static inline int ns83820_add_rx_skb(struct ns83820 *dev, struct sk_buff *skb)
dev->rx_info.next_empty = (next_empty + 1) % NR_RX_DESC;
cmdsts = REAL_RX_BUF_SIZE | CMDSTS_INTR;
- buf = pci_map_single(dev->pci_dev, skb->tail,
+ buf = pci_map_single(dev->pci_dev, skb->data,
REAL_RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
build_rx_desc(dev, sg, 0, buf, cmdsts, 0);
/* update link of previous rx */
@@ -603,7 +604,7 @@ static inline int rx_refill(struct net_device *ndev, int gfp)
if (unlikely(!skb))
break;
- res = (long)skb->tail & 0xf;
+ res = (long)skb->data & 0xf;
res = 0x10 - res;
res &= 0xf;
skb_reserve(skb, res);
diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c
index c6e8b25f9685..71fd41122c91 100644
--- a/drivers/net/pcmcia/3c574_cs.c
+++ b/drivers/net/pcmcia/3c574_cs.c
@@ -86,7 +86,6 @@ earlier 3Com products.
#include <linux/ethtool.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -312,11 +311,6 @@ static dev_link_t *tc574_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &tc574_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1286,13 +1280,22 @@ static int el3_close(struct net_device *dev)
return 0;
}
+static struct pcmcia_device_id tc574_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0574),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0556, "3CCFEM556.cis"),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc574_ids);
+
static struct pcmcia_driver tc574_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "3c574_cs",
},
.attach = tc574_attach,
+ .event = tc574_event,
.detach = tc574_detach,
+ .id_table = tc574_ids,
};
static int __init init_tc574(void)
diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
index 89abdda1d343..d83fdd8c1943 100644
--- a/drivers/net/pcmcia/3c589_cs.c
+++ b/drivers/net/pcmcia/3c589_cs.c
@@ -40,7 +40,6 @@
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -226,11 +225,6 @@ static dev_link_t *tc589_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &tc589_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1057,13 +1051,26 @@ static int el3_close(struct net_device *dev)
return 0;
}
+static struct pcmcia_device_id tc589_ids[] = {
+ PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0101, 0x0562),
+ PCMCIA_MFC_DEVICE_PROD_ID1(0, "Motorola MARQUIS", 0xf03e4e77),
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0589),
+ PCMCIA_DEVICE_PROD_ID12("Farallon", "ENet", 0x58d93fc4, 0x992c2202),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x0035, "3CXEM556.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0101, 0x003d, "3CXEM556.cis"),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, tc589_ids);
+
static struct pcmcia_driver tc589_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "3c589_cs",
},
.attach = tc589_attach,
+ .event = tc589_event,
.detach = tc589_detach,
+ .id_table = tc589_ids,
};
static int __init init_tc589(void)
diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c
index 853b586e481a..8bb4e85689ea 100644
--- a/drivers/net/pcmcia/axnet_cs.c
+++ b/drivers/net/pcmcia/axnet_cs.c
@@ -37,7 +37,6 @@
#include <linux/netdevice.h>
#include "../8390.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -181,11 +180,6 @@ static dev_link_t *axnet_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &axnet_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -850,13 +844,43 @@ static void block_output(struct net_device *dev, int count,
outsw(nic_base + AXNET_DATAPORT, buf, count>>1);
}
+static struct pcmcia_device_id axnet_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x016c, 0x0081),
+ PCMCIA_DEVICE_MANF_CARD(0x018a, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0303),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0309),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1106),
+ PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab),
+ PCMCIA_DEVICE_PROD_ID124("Fast Ethernet", "16-bit PC Card", "AX88190", 0xb4be14e3, 0x9a12eb6a, 0xab9be5ef),
+ PCMCIA_DEVICE_PROD_ID12("ASIX", "AX88190", 0x0959823b, 0xab9be5ef),
+ PCMCIA_DEVICE_PROD_ID12("Billionton", "LNA-100B", 0x552ab682, 0xbc3b87e1),
+ PCMCIA_DEVICE_PROD_ID12("CHEETAH ETHERCARD", "EN2228", 0x00fa7bc8, 0x00e990cc),
+ PCMCIA_DEVICE_PROD_ID12("CNet", "CNF301", 0xbc477dde, 0x78c5f40b),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEther PCC-TXD", 0x5261440f, 0x436768c5),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FEtherII PCC-TXD", 0x5261440f, 0x730df72e),
+ PCMCIA_DEVICE_PROD_ID12("Dynalink", "L100C16", 0x55632fd5, 0x66bc2a90),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V3)", 0x0733cc81, 0x232019a8),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC3-TX", 0x481e0094, 0xf91af609),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "100BASE", 0x281f1c5d, 0x7c2add04),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEtherCard", 0x281f1c5d, 0x7ef26116),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FEP501", 0x281f1c5d, 0x2e272058),
+ PCMCIA_DEVICE_PROD_ID14("Network Everywhere", "AX88190", 0x820a67b6, 0xab9be5ef),
+ /* this is not specific enough */
+ /* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, axnet_ids);
+
static struct pcmcia_driver axnet_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "axnet_cs",
},
.attach = axnet_attach,
+ .event = axnet_event,
.detach = axnet_detach,
+ .id_table = axnet_ids,
};
static int __init init_axnet_cs(void)
diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c
index 4294e1e3f156..b9355d9498a3 100644
--- a/drivers/net/pcmcia/com20020_cs.c
+++ b/drivers/net/pcmcia/com20020_cs.c
@@ -43,7 +43,6 @@
#include <linux/arcdevice.h>
#include <linux/com20020.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -200,11 +199,6 @@ static dev_link_t *com20020_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &com20020_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -483,7 +477,11 @@ static int com20020_event(event_t event, int priority,
return 0;
} /* com20020_event */
-
+static struct pcmcia_device_id com20020_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("Contemporary Control Systems, Inc.", "PCM20 Arcnet Adapter", 0x59991666, 0x95dfffaf),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, com20020_ids);
static struct pcmcia_driver com20020_cs_driver = {
.owner = THIS_MODULE,
@@ -491,7 +489,9 @@ static struct pcmcia_driver com20020_cs_driver = {
.name = "com20020_cs",
},
.attach = com20020_attach,
+ .event = com20020_event,
.detach = com20020_detach,
+ .id_table = com20020_ids,
};
static int __init init_com20020_cs(void)
diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
index 0424865e8094..9d8197bb293a 100644
--- a/drivers/net/pcmcia/fmvj18x_cs.c
+++ b/drivers/net/pcmcia/fmvj18x_cs.c
@@ -49,7 +49,6 @@
#include <linux/ioport.h>
#include <linux/crc32.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -288,11 +287,6 @@ static dev_link_t *fmvj18x_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &fmvj18x_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -435,7 +429,9 @@ static void fmvj18x_config(dev_link_t *link)
pcmcia_get_status(handle, &status);
if (status.CardState & CS_EVENT_3VCARD)
link->conf.Vcc = 33; /* inserted in 3.3V slot */
- } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410) {
+ } else if (le16_to_cpu(buf[1]) == PRODID_TDK_GN3410
+ || le16_to_cpu(buf[1]) == PRODID_TDK_NP9610
+ || le16_to_cpu(buf[1]) == PRODID_TDK_MN3200) {
/* MultiFunction Card */
link->conf.ConfigBase = 0x800;
link->conf.ConfigIndex = 0x47;
@@ -764,13 +760,40 @@ static int fmvj18x_event(event_t event, int priority,
return 0;
} /* fmvj18x_event */
+static struct pcmcia_device_id fmvj18x_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0004, 0x0004),
+ PCMCIA_DEVICE_PROD_ID12("EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04", 0x528c88c4, 0x74f91e59),
+ PCMCIA_DEVICE_PROD_ID12("Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT", 0x53af556e, 0x877f9922),
+ PCMCIA_DEVICE_PROD_ID12("Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT", 0xf47e6c66, 0x877f9922),
+ PCMCIA_DEVICE_PROD_ID12("FUJITSU", "LAN Card(FMV-J182)", 0x6ee5a3d8, 0x5baf31db),
+ PCMCIA_DEVICE_PROD_ID12("FUJITSU", "MBH10308", 0x6ee5a3d8, 0x3f04875e),
+ PCMCIA_DEVICE_PROD_ID12("FUJITSU TOWA", "LA501", 0xb8451188, 0x12939ba2),
+ PCMCIA_DEVICE_PROD_ID12("HITACHI", "HT-4840-11", 0xf4f43949, 0x773910f4),
+ PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310B Ver1.0 ", 0x8cef4d3a, 0x075fc7b6),
+ PCMCIA_DEVICE_PROD_ID12("NextComK.K.", "NC5310 Ver1.0 ", 0x8cef4d3a, 0xbccf43e6),
+ PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "10BASE_T CARD R280", 0x85c10e17, 0xd9413666),
+ PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CD02x", 0x1eae9475, 0x8fa0ee70),
+ PCMCIA_DEVICE_PROD_ID12("TDK", "LAC-CF010", 0x1eae9475, 0x7683bc9a),
+ PCMCIA_DEVICE_PROD_ID1("CONTEC Co.,Ltd.", 0x58d8fee2),
+ PCMCIA_DEVICE_PROD_ID1("PCMCIA LAN MBH10304 ES", 0x2599f454),
+ PCMCIA_DEVICE_PROD_ID1("PCMCIA MBH10302", 0x8f4005da),
+ PCMCIA_DEVICE_PROD_ID1("UBKK,V2.0", 0x90888080),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0d0a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0x0e0a),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fmvj18x_ids);
+
static struct pcmcia_driver fmvj18x_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "fmvj18x_cs",
},
.attach = fmvj18x_attach,
+ .event = fmvj18x_event,
.detach = fmvj18x_detach,
+ .id_table = fmvj18x_ids,
};
static int __init init_fmvj18x_cs(void)
diff --git a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
index 3107ccfe8f3d..b6c140eb9799 100644
--- a/drivers/net/pcmcia/ibmtr_cs.c
+++ b/drivers/net/pcmcia/ibmtr_cs.c
@@ -57,7 +57,6 @@
#include <linux/trdevice.h>
#include <linux/ibmtr.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -119,9 +118,6 @@ static void ibmtr_detach(dev_link_t *);
static dev_link_t *dev_list;
-extern int ibmtr_probe_card(struct net_device *dev);
-extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-
/*====================================================================*/
typedef struct ibmtr_dev_t {
@@ -193,11 +189,6 @@ static dev_link_t *ibmtr_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ibmtr_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -511,13 +502,22 @@ static void ibmtr_hw_setup(struct net_device *dev, u_int mmiobase)
return;
}
+static struct pcmcia_device_id ibmtr_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("3Com", "TokenLink Velocity PC Card", 0x41240e5b, 0x82c3734e),
+ PCMCIA_DEVICE_PROD_ID12("IBM", "TOKEN RING", 0xb569a6e5, 0xbf8eed47),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ibmtr_ids);
+
static struct pcmcia_driver ibmtr_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "ibmtr_cs",
},
.attach = ibmtr_attach,
+ .event = ibmtr_event,
.detach = ibmtr_detach,
+ .id_table = ibmtr_ids,
};
static int __init init_ibmtr_cs(void)
diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
index 4603807fcafb..dbb941004ae9 100644
--- a/drivers/net/pcmcia/nmclan_cs.c
+++ b/drivers/net/pcmcia/nmclan_cs.c
@@ -146,7 +146,6 @@ Include Files
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cisreg.h>
@@ -502,11 +501,6 @@ static dev_link_t *nmclan_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &nmclan_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1675,13 +1669,22 @@ static void set_multicast_list(struct net_device *dev)
} /* set_multicast_list */
+static struct pcmcia_device_id nmclan_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Ethernet", 0x085a850b, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("Portable Add-ons", "Ethernet", 0x0ebf1d60, 0x00b2e941),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, nmclan_ids);
+
static struct pcmcia_driver nmclan_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "nmclan_cs",
},
.attach = nmclan_attach,
+ .event = nmclan_event,
.detach = nmclan_detach,
+ .id_table = nmclan_ids,
};
static int __init init_nmclan_cs(void)
diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c
index 181b6ed55003..e1664aef3dfd 100644
--- a/drivers/net/pcmcia/pcnet_cs.c
+++ b/drivers/net/pcmcia/pcnet_cs.c
@@ -40,7 +40,6 @@
#include <linux/netdevice.h>
#include <../drivers/net/8390.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -276,11 +275,6 @@ static dev_link_t *pcnet_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &pcnet_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1155,11 +1149,13 @@ static int set_config(struct net_device *dev, struct ifmap *map)
static irqreturn_t ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
- pcnet_dev_t *info = PRIV(dev);
+ pcnet_dev_t *info;
irqreturn_t ret = ei_interrupt(irq, dev_id, regs);
- if (ret == IRQ_HANDLED)
+ if (ret == IRQ_HANDLED) {
+ info = PRIV(dev);
info->stale = 0;
+ }
return ret;
}
@@ -1350,7 +1346,7 @@ static void dma_block_input(struct net_device *dev, int count,
if (count & 0x01)
buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;
- /* This was for the ALPHA version only, but enough people have
+ /* This was for the ALPHA version only, but enough people have been
encountering problems that it is still here. */
#ifdef PCMCIA_DEBUG
if (ei_debug > 4) { /* DMA termination address check... */
@@ -1424,7 +1420,7 @@ static void dma_block_output(struct net_device *dev, int count,
dma_start = jiffies;
#ifdef PCMCIA_DEBUG
- /* This was for the ALPHA version only, but enough people have
+ /* This was for the ALPHA version only, but enough people have been
encountering problems that it is still here. */
if (ei_debug > 4) { /* DMA termination address check... */
int addr, tries = 20;
@@ -1635,13 +1631,217 @@ failed:
/*====================================================================*/
+static struct pcmcia_device_id pcnet_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0057, 0x0021),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0104, 0x000a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0105, 0xea15),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0x3341),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0143, 0xc0ab),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x021b, 0x0101),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x08a1, 0xc0ab),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+ PCMCIA_MFC_DEVICE_PROD_ID12(0, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+ PCMCIA_MFC_DEVICE_PROD_ID123(0, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+ PCMCIA_MFC_DEVICE_PROD_ID2(0, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+ PCMCIA_DEVICE_MANF_CARD(0x0057, 0x1004),
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x000d),
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0075),
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0145),
+ PCMCIA_DEVICE_MANF_CARD(0x0149, 0x0230),
+ PCMCIA_DEVICE_MANF_CARD(0x0149, 0x4530),
+/* PCMCIA_DEVICE_MANF_CARD(0x0149, 0xc1ab), conflict with axnet_cs */
+ PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0110),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x2328),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x8041),
+ PCMCIA_DEVICE_MANF_CARD(0x0213, 0x2452),
+/* PCMCIA_DEVICE_MANF_CARD(0x021b, 0x0202), conflict with axnet_cs */
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0300),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0307),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x030a),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1103),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1121),
+ PCMCIA_DEVICE_PROD_ID12("2408LAN", "Ethernet", 0x352fff7f, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID123("Cardwell", "PCMCIA", "ETHERNET", 0x9533672e, 0x281f1c5d, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID123("CNet ", "CN30BC", "ETHERNET", 0x9fe55d3d, 0x85601198, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID123("Digital", "Ethernet", "Adapter", 0x9999ab35, 0x00b2e941, 0x4b0d829e),
+ PCMCIA_DEVICE_PROD_ID123("Edimax Technology Inc.", "PCMCIA", "Ethernet Card", 0x738a0019, 0x281f1c5d, 0x5e9d92c0),
+ PCMCIA_DEVICE_PROD_ID123("EFA ", "EFA207", "ETHERNET", 0x3d294be4, 0xeb9aab6c, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID123("I-O DATA", "PCLA", "ETHERNET", 0x1d55d7ec, 0xe4c64d34, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID123("IO DATA", "PCLATE", "ETHERNET", 0x547e66dc, 0x6b260753, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID123("KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card", 0x932b7189, 0x699e4436, 0x6f6652e0),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216", 0x281f1c5d, 0xd4cd2f20, 0xb87add82),
+ PCMCIA_DEVICE_PROD_ID123("PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2620", 0x281f1c5d, 0xd4cd2f20, 0x7d3d83a8),
+ PCMCIA_DEVICE_PROD_ID1("2412LAN", 0x67f236ab),
+ PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2212", 0xdfc6b5b2, 0xcb112a11),
+ PCMCIA_DEVICE_PROD_ID12("ACCTON", "EN2216-PCMCIA-ETHERNET", 0xdfc6b5b2, 0x5542bfff),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA100-PCM-T V2 100/10M LAN PC Card", 0xbb7fbdd7, 0xcd91cc68),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM", 0xbb7fbdd7, 0x5ba10d49),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA100-PCM V2", 0x36634a66, 0xc6d05997),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis, K.K.", "CentreCOM LA-PCM_V2", 0xbb7fBdd7, 0x28e299f8),
+ PCMCIA_DEVICE_PROD_ID12("Allied Telesis K.K.", "LA-PCM V3", 0x36634a66, 0x62241d96),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8010", 0x5070a7f9, 0x82f96e96),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom", "AMB8610", 0x5070a7f9, 0x86741224),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002", 0x93b15570, 0x75ec3efb),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8002T", 0x93b15570, 0x461c5247),
+ PCMCIA_DEVICE_PROD_ID12("AmbiCom Inc", "AMB8010", 0x93b15570, 0x82f96e96),
+ PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet", 0x578ba6e7, 0x0a9888c1),
+ PCMCIA_DEVICE_PROD_ID12("AnyCom", "ECO Ethernet 10/100", 0x578ba6e7, 0x939fedbd),
+ PCMCIA_DEVICE_PROD_ID12("AROWANA", "PCMCIA Ethernet LAN Card", 0x313adbc8, 0x08d9f190),
+ PCMCIA_DEVICE_PROD_ID12("ASANTE", "FriendlyNet PC Card", 0x3a7ade0f, 0x41c64504),
+ PCMCIA_DEVICE_PROD_ID12("Billionton", "LNT-10TB", 0x552ab682, 0xeeb1ba6a),
+ PCMCIA_DEVICE_PROD_ID12("CF", "10Base-Ethernet", 0x44ebf863, 0x93ae4d79),
+ PCMCIA_DEVICE_PROD_ID12("CNet", "CN40BC Ethernet", 0xbc477dde, 0xfba775a7),
+ PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter", 0xfa2e424d, 0xe9190d8a),
+ PCMCIA_DEVICE_PROD_ID12("COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet", 0xfa2e424d, 0x3953d9b9),
+ PCMCIA_DEVICE_PROD_ID12("CONTEC", "C-NET(PC)C-10L", 0x21cab552, 0xf6f90722),
+ PCMCIA_DEVICE_PROD_ID12("corega", "FEther PCC-TXF", 0x0a21501a, 0xa51564a2),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega EtherII PCC-T", 0x5261440f, 0xfa9d85bd),
+ PCMCIA_DEVICE_PROD_ID12("Corega K.K.", "corega EtherII PCC-TD", 0xd4fdcbd8, 0xc49bd73d),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega Ether PCC-T", 0x5261440f, 0x6705fcaa),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "corega FastEther PCC-TX", 0x5261440f, 0x485e85d9),
+ PCMCIA_DEVICE_PROD_ID12("Corega,K.K.", "Ethernet LAN Card", 0x110d26d9, 0x9fd2f0a2),
+ PCMCIA_DEVICE_PROD_ID12("corega,K.K.", "Ethernet LAN Card", 0x9791a90e, 0x9fd2f0a2),
+ PCMCIA_DEVICE_PROD_ID12("CouplerlessPCMCIA", "100BASE", 0xee5af0ad, 0x7c2add04),
+ PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-010", 0x77008979, 0x9d8d445d),
+ PCMCIA_DEVICE_PROD_ID12("CyQ've", "ELA-110E 10/100M LAN Card", 0x77008979, 0xfd184814),
+ PCMCIA_DEVICE_PROD_ID12("DataTrek.", "NetCard ", 0x5cd66d9d, 0x84697ce0),
+ PCMCIA_DEVICE_PROD_ID12("Dayna Communications, Inc.", "CommuniCard E", 0x0c629325, 0xb4e7dbaf),
+ PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100", 0x697403d8, 0xe160b995),
+ PCMCIA_DEVICE_PROD_ID12("Digicom", "Palladio LAN 10/100 Dongless", 0x697403d8, 0xa6d3b233),
+ PCMCIA_DEVICE_PROD_ID12("DIGITAL", "DEPCM-XX", 0x69616cb3, 0xe600e76e),
+ PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-650", 0x1a424a1c, 0xf28c8398),
+ PCMCIA_DEVICE_PROD_ID12("D-Link", "DE-660", 0x1a424a1c, 0xd9a1d05b),
+ PCMCIA_DEVICE_PROD_ID12("D-Link", "DFE-650", 0x1a424a1c, 0x0f0073f9),
+ PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 PC Card", 0x725b842d, 0xf1efee84),
+ PCMCIA_DEVICE_PROD_ID12("Dual Speed", "10/100 Port Attached PC Card", 0x725b842d, 0x2db1f8e9),
+ PCMCIA_DEVICE_PROD_ID12("Dynalink", "L10BC", 0x55632fd5, 0xdc65f2b1),
+ PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10BC", 0x6a26d1cf, 0xdc65f2b1),
+ PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L10C", 0x6a26d1cf, 0xc4f84efb),
+ PCMCIA_DEVICE_PROD_ID12("E-CARD", "E-CARD", 0x6701da11, 0x6701da11),
+ PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet 10BaseT card", 0x53c864c6, 0xedd059f6),
+ PCMCIA_DEVICE_PROD_ID12("EIGER Labs Inc.", "Ethernet Combo card", 0x53c864c6, 0x929c486c),
+ PCMCIA_DEVICE_PROD_ID12("Ethernet", "Adapter", 0x00b2e941, 0x4b0d829e),
+ PCMCIA_DEVICE_PROD_ID12("Ethernet Adapter", "E2000 PCMCIA Ethernet", 0x96767301, 0x71fbbc61),
+ PCMCIA_DEVICE_PROD_ID12("Ethernet PCMCIA adapter", "EP-210", 0x8dd86181, 0xf2b52517),
+ PCMCIA_DEVICE_PROD_ID12("Fast Ethernet", "Adapter", 0xb4be14e3, 0x4b0d829e),
+ PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2000", 0x2a151fac, 0xf00555cb),
+ PCMCIA_DEVICE_PROD_ID12("Grey Cell", "GCS2220", 0x2a151fac, 0xc1b7e327),
+ PCMCIA_DEVICE_PROD_ID12("GVC", "NIC-2000p", 0x76e171bd, 0x6eb1c947),
+ PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "Ethernet", 0xe3736c88, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("IC-CARD", "IC-CARD", 0x60cb09a6, 0x60cb09a6),
+ PCMCIA_DEVICE_PROD_ID12("IO DATA", "PCETTX", 0x547e66dc, 0x6fc5459b),
+ PCMCIA_DEVICE_PROD_ID12("iPort", "10/100 Ethernet Card", 0x56c538d2, 0x11b0ffc0),
+ PCMCIA_DEVICE_PROD_ID12("KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T", 0xb18dc3b4, 0xcc51a956),
+ PCMCIA_DEVICE_PROD_ID12("KCI", "PE520 PCMCIA Ethernet Adapter", 0xa89b87d3, 0x1eb88e64),
+ PCMCIA_DEVICE_PROD_ID12("KINGMAX", "EN10T2T", 0x7bcb459a, 0xa5c81fa5),
+ PCMCIA_DEVICE_PROD_ID12("Kingston", "KNE-PC2", 0x1128e633, 0xce2a89b3),
+ PCMCIA_DEVICE_PROD_ID12("Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter", 0x313c7be3, 0x0afb54a2),
+ PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-10/100CD", 0x1b7827b2, 0xcda71d1c),
+ PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDF", 0x1b7827b2, 0xfec71e40),
+ PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDL/T", 0x1b7827b2, 0x79fba4f7),
+ PCMCIA_DEVICE_PROD_ID12("Laneed", "LD-CDS", 0x1b7827b2, 0x931afaab),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "Combo PCMCIA EthernetCard (EC2T)", 0x0733cc81, 0x32ee8c78),
+ PCMCIA_DEVICE_PROD_ID12("LINKSYS", "E-CARD", 0xf7cb0b07, 0x6701da11),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 Integrated PC Card (PCM100)", 0x0733cc81, 0x453c3f9d),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100)", 0x0733cc81, 0x66c5a389),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "EtherFast 10/100 PC Card (PCMPC100 V2)", 0x0733cc81, 0x3a3b28e9),
+ PCMCIA_DEVICE_PROD_ID12("Linksys", "HomeLink Phoneline ", 0x0733cc81, 0x5e07cfa0),
+ PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN100TX", 0x88fcdeda, 0x6d772737),
+ PCMCIA_DEVICE_PROD_ID12("Logitec", "LPM-LN20T", 0x88fcdeda, 0x81090922),
+ PCMCIA_DEVICE_PROD_ID12("LONGSHINE", "PCMCIA Ethernet Card", 0xf866b0b0, 0x6f6652e0),
+ PCMCIA_DEVICE_PROD_ID12("MACNICA", "ME1-JEIDA", 0x20841b68, 0xaf8a3578),
+ PCMCIA_DEVICE_PROD_ID12("Macsense", "MPC-10", 0xd830297f, 0xd265c307),
+ PCMCIA_DEVICE_PROD_ID12("Matsushita Electric Industrial Co.,LTD.", "CF-VEL211", 0x44445376, 0x8ded41d4),
+ PCMCIA_DEVICE_PROD_ID12("MAXTECH", "PCN2000", 0x78d64bc0, 0xca0ca4b8),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-T", 0x481e0094, 0xa2eb0cf3),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "LPC2-TX", 0x481e0094, 0x41a6916c),
+ PCMCIA_DEVICE_PROD_ID12("Microcom C.E.", "Travel Card LAN 10/100", 0x4b91cec7, 0xe70220d6),
+ PCMCIA_DEVICE_PROD_ID12("Microdyne", "NE4200", 0x2e6da59b, 0x0478e472),
+ PCMCIA_DEVICE_PROD_ID12("MIDORI ELEC.", "LT-PCMT", 0x648d55c1, 0xbde526c7),
+ PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover 4100", 0x36e1191f, 0x60c229b9),
+ PCMCIA_DEVICE_PROD_ID12("National Semiconductor", "InfoMover NE4100", 0x36e1191f, 0xa6617ec8),
+ PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J12", 0x18df0ba0, 0xbc912d76),
+ PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA410TX", 0x9aa79dc3, 0x60e5bc0e),
+ PCMCIA_DEVICE_PROD_ID12("NETGEAR", "FA411", 0x9aa79dc3, 0x40fad875),
+ PCMCIA_DEVICE_PROD_ID12("Network Everywhere", "Fast Ethernet 10/100 PC Card", 0x820a67b6, 0x31ed1a5f),
+ PCMCIA_DEVICE_PROD_ID12("NextCom K.K.", "Next Hawk", 0xaedaec74, 0xad050ef1),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100Mbps Ethernet Card", 0x281f1c5d, 0x6e41773b),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet", 0x281f1c5d, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET", 0x281f1c5d, 0x3ff7175b),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet 10BaseT Card", 0x281f1c5d, 0x4de2f6c8),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Card", 0x281f1c5d, 0x5e9d92c0),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Ethernet Combo card", 0x281f1c5d, 0x929c486c),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "ETHERNET V1.0", 0x281f1c5d, 0x4d8817c8),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FastEthernet", 0x281f1c5d, 0xfe871eeb),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast-Ethernet", 0x281f1c5d, 0x45f1f3b4),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "FAST ETHERNET CARD", 0x281f1c5d, 0xec5dbca7),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA LAN", "Ethernet", 0x7500e246, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "LNT-10TN", 0x281f1c5d, 0xe707f641),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "UE2212", 0x281f1c5d, 0xbf17199b),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", " Ethernet NE2000 Compatible", 0x281f1c5d, 0x42d5d7e1),
+ PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10baseT 3.3V", 0xebf91155, 0x30074c80),
+ PCMCIA_DEVICE_PROD_ID12("PRETEC", "Ethernet CompactLAN 10BaseT 3.3V", 0xebf91155, 0x7f5a4f50),
+ PCMCIA_DEVICE_PROD_ID12("Psion Dacom", "Gold Card Ethernet", 0xf5f025c2, 0x3a30e110),
+ PCMCIA_DEVICE_PROD_ID12("=RELIA==", "Ethernet", 0xcdd0644a, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("RP", "1625B Ethernet NE2000 Compatible", 0xe3e66e22, 0xb96150df),
+ PCMCIA_DEVICE_PROD_ID12("RPTI", "EP400 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4a7e2ae0),
+ PCMCIA_DEVICE_PROD_ID12("RPTI", "EP401 Ethernet NE2000 Compatible", 0xdc6f88fd, 0x4bcbd7fd),
+ PCMCIA_DEVICE_PROD_ID12("RPTI LTD.", "EP400", 0xc53ac515, 0x81e39388),
+ PCMCIA_DEVICE_PROD_ID12("SCM", "Ethernet Combo card", 0xbdc3b102, 0x929c486c),
+ PCMCIA_DEVICE_PROD_ID12("Seiko Epson Corp.", "Ethernet", 0x09928730, 0x00b2e941),
+ PCMCIA_DEVICE_PROD_ID12("SMC", "EZCard-10-PCMCIA", 0xc4f8b18b, 0xfb21d265),
+ PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision D", 0xc70a4760, 0x2ade483e),
+ PCMCIA_DEVICE_PROD_ID12("Socket Communications Inc", "Socket EA PCMCIA LAN Adapter Revision E", 0xc70a4760, 0x5dd978a8),
+ PCMCIA_DEVICE_PROD_ID12("TDK", "LAK-CD031 for PCMCIA", 0x1eae9475, 0x0ed386fa),
+ PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE450T", 0x466b05f0, 0x8b74bc4f),
+ PCMCIA_DEVICE_PROD_ID12("Telecom Device K.K.", "SuperSocket RE550T", 0x466b05f0, 0x33c8db2a),
+ PCMCIA_DEVICE_PROD_ID13("Hypertec", "EP401", 0x8787bec7, 0xf6e4a31e),
+ PCMCIA_DEVICE_PROD_ID13("KingMax Technology Inc.", "Ethernet Card", 0x932b7189, 0x5e9d92c0),
+ PCMCIA_DEVICE_PROD_ID13("LONGSHINE", "EP401", 0xf866b0b0, 0xf6e4a31e),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "CFE-10", 0x2e3ee845, 0x22a49f89),
+ PCMCIA_DEVICE_PROD_ID1("CyQ've 10 Base-T LAN CARD", 0x94faf360),
+ PCMCIA_DEVICE_PROD_ID1("EP-210 PCMCIA LAN CARD.", 0x8850b4de),
+ PCMCIA_DEVICE_PROD_ID1("ETHER-C16", 0x06a8514f),
+ PCMCIA_DEVICE_PROD_ID1("IC-CARD", 0x60cb09a6),
+ PCMCIA_DEVICE_PROD_ID1("NE2000 Compatible", 0x75b8ad5a),
+ PCMCIA_DEVICE_PROD_ID2("EN-6200P2", 0xa996d078),
+ /* too generic! */
+ /* PCMCIA_DEVICE_PROD_ID12("PCMCIA", "10/100 Ethernet Card", 0x281f1c5d, 0x11b0ffc0), */
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(0, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID12(0, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID4(0, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(0, 0x0175, 0x0000, "DP83903.cis"),
+ PCMCIA_DEVICE_CIS_MANF_CARD(0xc00f, 0x0002, "LA-PCM.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("KTI", "PE520 PLUS", 0xad180345, 0x9d58d392, "PE520.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("NDC", "Ethernet", 0x01c43ae1, 0x00b2e941, "NE2K.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("PMX ", "PE-200", 0x34f3f1c8, 0x10b59f8c, "PE-200.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("TAMARACK", "Ethernet", 0xcf434fba, 0x00b2e941, "tamarack.cis"),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, pcnet_ids);
+
static struct pcmcia_driver pcnet_driver = {
.drv = {
.name = "pcnet_cs",
},
.attach = pcnet_attach,
+ .event = pcnet_event,
.detach = pcnet_detach,
.owner = THIS_MODULE,
+ .id_table = pcnet_ids,
};
static int __init init_pcnet_cs(void)
diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
index 85a152173148..fbc2f58ff688 100644
--- a/drivers/net/pcmcia/smc91c92_cs.c
+++ b/drivers/net/pcmcia/smc91c92_cs.c
@@ -42,7 +42,6 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -127,6 +126,12 @@ struct smc_private {
int rx_ovrn;
};
+struct smc_cfg_mem {
+ tuple_t tuple;
+ cisparse_t parse;
+ u_char buf[255];
+};
+
/* Special definitions for Megahertz multifunction cards */
#define MEGAHERTZ_ISR 0x0380
@@ -364,10 +369,6 @@ static dev_link_t *smc91c92_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &smc91c92_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -498,14 +499,24 @@ static int mhz_mfc_config(dev_link_t *link)
{
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
- tuple_t tuple;
- cisparse_t parse;
- u_char buf[255];
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ cisparse_t *parse;
+ cistpl_cftable_entry_t *cf;
+ u_char *buf;
win_req_t req;
memreq_t mem;
int i, k;
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ return CS_OUT_OF_RESOURCE;
+
+ tuple = &cfg_mem->tuple;
+ parse = &cfg_mem->parse;
+ cf = &parse->cftable_entry;
+ buf = cfg_mem->buf;
+
link->conf.Attributes |= CONF_ENABLE_SPKR;
link->conf.Status = CCSR_AUDIO_ENA;
link->irq.Attributes =
@@ -514,12 +525,12 @@ static int mhz_mfc_config(dev_link_t *link)
link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
link->io.NumPorts2 = 8;
- tuple.Attributes = tuple.TupleOffset = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ tuple->Attributes = tuple->TupleOffset = 0;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 255;
+ tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
- i = first_tuple(link->handle, &tuple, &parse);
+ i = first_tuple(link->handle, tuple, parse);
/* The Megahertz combo cards have modem-like CIS entries, so
we have to explicitly try a bunch of port combinations. */
while (i == CS_SUCCESS) {
@@ -532,10 +543,10 @@ static int mhz_mfc_config(dev_link_t *link)
if (i == CS_SUCCESS) break;
}
if (i == CS_SUCCESS) break;
- i = next_tuple(link->handle, &tuple, &parse);
+ i = next_tuple(link->handle, tuple, parse);
}
if (i != CS_SUCCESS)
- return i;
+ goto free_cfg_mem;
dev->base_addr = link->io.BasePort1;
/* Allocate a memory window, for accessing the ISR */
@@ -544,7 +555,7 @@ static int mhz_mfc_config(dev_link_t *link)
req.AccessSpeed = 0;
i = pcmcia_request_window(&link->handle, &req, &link->win);
if (i != CS_SUCCESS)
- return i;
+ goto free_cfg_mem;
smc->base = ioremap(req.Base, req.Size);
mem.CardOffset = mem.Page = 0;
if (smc->manfid == MANFID_MOTOROLA)
@@ -556,6 +567,8 @@ static int mhz_mfc_config(dev_link_t *link)
&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
mhz_3288_power(link);
+free_cfg_mem:
+ kfree(cfg_mem);
return i;
}
@@ -563,39 +576,61 @@ static int mhz_setup(dev_link_t *link)
{
client_handle_t handle = link->handle;
struct net_device *dev = link->priv;
- tuple_t tuple;
- cisparse_t parse;
- u_char buf[255], *station_addr;
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ cisparse_t *parse;
+ u_char *buf, *station_addr;
+ int rc;
+
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ return -1;
+
+ tuple = &cfg_mem->tuple;
+ parse = &cfg_mem->parse;
+ buf = cfg_mem->buf;
- tuple.Attributes = tuple.TupleOffset = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
+ tuple->Attributes = tuple->TupleOffset = 0;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 255;
/* Read the station address from the CIS. It is stored as the last
(fourth) string in the Version 1 Version/ID tuple. */
- tuple.DesiredTuple = CISTPL_VERS_1;
- if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
- return -1;
+ tuple->DesiredTuple = CISTPL_VERS_1;
+ if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
+ }
/* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
- if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS)
- first_tuple(handle, &tuple, &parse);
- if (parse.version_1.ns > 3) {
- station_addr = parse.version_1.str + parse.version_1.ofs[3];
- if (cvt_ascii_address(dev, station_addr) == 0)
- return 0;
+ if (next_tuple(handle, tuple, parse) != CS_SUCCESS)
+ first_tuple(handle, tuple, parse);
+ if (parse->version_1.ns > 3) {
+ station_addr = parse->version_1.str + parse->version_1.ofs[3];
+ if (cvt_ascii_address(dev, station_addr) == 0) {
+ rc = 0;
+ goto free_cfg_mem;
+ }
}
/* Another possibility: for the EM3288, in a special tuple */
- tuple.DesiredTuple = 0x81;
- if (pcmcia_get_first_tuple(handle, &tuple) != CS_SUCCESS)
- return -1;
- if (pcmcia_get_tuple_data(handle, &tuple) != CS_SUCCESS)
- return -1;
+ tuple->DesiredTuple = 0x81;
+ if (pcmcia_get_first_tuple(handle, tuple) != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
+ }
+ if (pcmcia_get_tuple_data(handle, tuple) != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
+ }
buf[12] = '\0';
- if (cvt_ascii_address(dev, buf) == 0)
- return 0;
-
- return -1;
+ if (cvt_ascii_address(dev, buf) == 0) {
+ rc = 0;
+ goto free_cfg_mem;
+ }
+ rc = -1;
+free_cfg_mem:
+ kfree(cfg_mem);
+ return rc;
}
/*======================================================================
@@ -665,19 +700,29 @@ static int mot_setup(dev_link_t *link)
static int smc_config(dev_link_t *link)
{
struct net_device *dev = link->priv;
- tuple_t tuple;
- cisparse_t parse;
- u_char buf[255];
- cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ cisparse_t *parse;
+ cistpl_cftable_entry_t *cf;
+ u_char *buf;
int i;
- tuple.Attributes = tuple.TupleOffset = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ return CS_OUT_OF_RESOURCE;
+
+ tuple = &cfg_mem->tuple;
+ parse = &cfg_mem->parse;
+ cf = &parse->cftable_entry;
+ buf = cfg_mem->buf;
+
+ tuple->Attributes = tuple->TupleOffset = 0;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 255;
+ tuple->DesiredTuple = CISTPL_CFTABLE_ENTRY;
link->io.NumPorts1 = 16;
- i = first_tuple(link->handle, &tuple, &parse);
+ i = first_tuple(link->handle, tuple, parse);
while (i != CS_NO_MORE_ITEMS) {
if (i == CS_SUCCESS) {
link->conf.ConfigIndex = cf->index;
@@ -686,10 +731,12 @@ static int smc_config(dev_link_t *link)
i = pcmcia_request_io(link->handle, &link->io);
if (i == CS_SUCCESS) break;
}
- i = next_tuple(link->handle, &tuple, &parse);
+ i = next_tuple(link->handle, tuple, parse);
}
if (i == CS_SUCCESS)
dev->base_addr = link->io.BasePort1;
+
+ kfree(cfg_mem);
return i;
}
@@ -697,41 +744,58 @@ static int smc_setup(dev_link_t *link)
{
client_handle_t handle = link->handle;
struct net_device *dev = link->priv;
- tuple_t tuple;
- cisparse_t parse;
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ cisparse_t *parse;
cistpl_lan_node_id_t *node_id;
- u_char buf[255], *station_addr;
- int i;
+ u_char *buf, *station_addr;
+ int i, rc;
+
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ return CS_OUT_OF_RESOURCE;
- tuple.Attributes = tuple.TupleOffset = 0;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
+ tuple = &cfg_mem->tuple;
+ parse = &cfg_mem->parse;
+ buf = cfg_mem->buf;
+
+ tuple->Attributes = tuple->TupleOffset = 0;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 255;
/* Check for a LAN function extension tuple */
- tuple.DesiredTuple = CISTPL_FUNCE;
- i = first_tuple(handle, &tuple, &parse);
+ tuple->DesiredTuple = CISTPL_FUNCE;
+ i = first_tuple(handle, tuple, parse);
while (i == CS_SUCCESS) {
- if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID)
+ if (parse->funce.type == CISTPL_FUNCE_LAN_NODE_ID)
break;
- i = next_tuple(handle, &tuple, &parse);
+ i = next_tuple(handle, tuple, parse);
}
if (i == CS_SUCCESS) {
- node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+ node_id = (cistpl_lan_node_id_t *)parse->funce.data;
if (node_id->nb == 6) {
for (i = 0; i < 6; i++)
dev->dev_addr[i] = node_id->id[i];
- return 0;
+ rc = 0;
+ goto free_cfg_mem;
}
}
/* Try the third string in the Version 1 Version/ID tuple. */
- tuple.DesiredTuple = CISTPL_VERS_1;
- if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
- return -1;
- station_addr = parse.version_1.str + parse.version_1.ofs[2];
- if (cvt_ascii_address(dev, station_addr) == 0)
- return 0;
+ tuple->DesiredTuple = CISTPL_VERS_1;
+ if (first_tuple(handle, tuple, parse) != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
+ }
+ station_addr = parse->version_1.str + parse->version_1.ofs[2];
+ if (cvt_ascii_address(dev, station_addr) == 0) {
+ rc = 0;
+ goto free_cfg_mem;
+ }
- return -1;
+ rc = -1;
+free_cfg_mem:
+ kfree(cfg_mem);
+ return rc;
}
/*====================================================================*/
@@ -773,26 +837,36 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
{
client_handle_t handle = link->handle;
struct net_device *dev = link->priv;
- tuple_t tuple;
- u_char buf[255];
- int i;
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ u_char *buf;
+ int i, rc;
+
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ return -1;
+
+ tuple = &cfg_mem->tuple;
+ buf = cfg_mem->buf;
- tuple.Attributes = TUPLE_RETURN_COMMON;
- tuple.TupleData = buf;
- tuple.TupleDataMax = sizeof(buf);
- tuple.TupleOffset = 0;
+ tuple->Attributes = TUPLE_RETURN_COMMON;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 255;
+ tuple->TupleOffset = 0;
/* Read the station address from tuple 0x90, subtuple 0x04 */
- tuple.DesiredTuple = 0x90;
- i = pcmcia_get_first_tuple(handle, &tuple);
+ tuple->DesiredTuple = 0x90;
+ i = pcmcia_get_first_tuple(handle, tuple);
while (i == CS_SUCCESS) {
- i = pcmcia_get_tuple_data(handle, &tuple);
+ i = pcmcia_get_tuple_data(handle, tuple);
if ((i != CS_SUCCESS) || (buf[0] == 0x04))
break;
- i = pcmcia_get_next_tuple(handle, &tuple);
+ i = pcmcia_get_next_tuple(handle, tuple);
+ }
+ if (i != CS_SUCCESS) {
+ rc = -1;
+ goto free_cfg_mem;
}
- if (i != CS_SUCCESS)
- return -1;
for (i = 0; i < 6; i++)
dev->dev_addr[i] = buf[i+2];
@@ -814,8 +888,10 @@ static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
inw(link->io.BasePort1 + OSITECH_AUI_PWR),
inw(link->io.BasePort1 + OSITECH_RESET_ISR));
}
-
- return 0;
+ rc = 0;
+free_cfg_mem:
+ kfree(cfg_mem);
+ return rc;
}
/*======================================================================
@@ -887,9 +963,10 @@ static void smc91c92_config(dev_link_t *link)
client_handle_t handle = link->handle;
struct net_device *dev = link->priv;
struct smc_private *smc = netdev_priv(dev);
- tuple_t tuple;
- cisparse_t parse;
- u_short buf[32];
+ struct smc_cfg_mem *cfg_mem;
+ tuple_t *tuple;
+ cisparse_t *parse;
+ u_char *buf;
char *name;
int i, j, rev;
kio_addr_t ioaddr;
@@ -897,21 +974,29 @@ static void smc91c92_config(dev_link_t *link)
DEBUG(0, "smc91c92_config(0x%p)\n", link);
- tuple.Attributes = tuple.TupleOffset = 0;
- tuple.TupleData = (cisdata_t *)buf;
- tuple.TupleDataMax = sizeof(buf);
+ cfg_mem = kmalloc(sizeof(struct smc_cfg_mem), GFP_KERNEL);
+ if (!cfg_mem)
+ goto config_failed;
- tuple.DesiredTuple = CISTPL_CONFIG;
- i = first_tuple(handle, &tuple, &parse);
- CS_EXIT_TEST(i, ParseTuple, config_failed);
- link->conf.ConfigBase = parse.config.base;
- link->conf.Present = parse.config.rmask[0];
+ tuple = &cfg_mem->tuple;
+ parse = &cfg_mem->parse;
+ buf = cfg_mem->buf;
- tuple.DesiredTuple = CISTPL_MANFID;
- tuple.Attributes = TUPLE_RETURN_COMMON;
- if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
- smc->manfid = parse.manfid.manf;
- smc->cardid = parse.manfid.card;
+ tuple->Attributes = tuple->TupleOffset = 0;
+ tuple->TupleData = (cisdata_t *)buf;
+ tuple->TupleDataMax = 64;
+
+ tuple->DesiredTuple = CISTPL_CONFIG;
+ i = first_tuple(handle, tuple, parse);
+ CS_EXIT_TEST(i, ParseTuple, config_failed);
+ link->conf.ConfigBase = parse->config.base;
+ link->conf.Present = parse->config.rmask[0];
+
+ tuple->DesiredTuple = CISTPL_MANFID;
+ tuple->Attributes = TUPLE_RETURN_COMMON;
+ if (first_tuple(handle, tuple, parse) == CS_SUCCESS) {
+ smc->manfid = parse->manfid.manf;
+ smc->cardid = parse->manfid.card;
}
/* Configure card */
@@ -1046,7 +1131,7 @@ static void smc91c92_config(dev_link_t *link)
printk(KERN_NOTICE " No MII transceivers found!\n");
}
}
-
+ kfree(cfg_mem);
return;
config_undo:
@@ -1054,6 +1139,7 @@ config_undo:
config_failed: /* CS_EXIT_TEST() calls jump to here... */
smc91c92_release(link);
link->state &= ~DEV_CONFIG_PENDING;
+ kfree(cfg_mem);
} /* smc91c92_config */
@@ -2236,13 +2322,47 @@ static int smc_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
return rc;
}
+static struct pcmcia_device_id smc91c92_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0109, 0x0501),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0140, 0x000a),
+ PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+ PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+ PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+ PCMCIA_PFC_DEVICE_PROD_ID123(0, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x016c, 0x0020),
+ PCMCIA_DEVICE_MANF_CARD(0x016c, 0x0023),
+ PCMCIA_DEVICE_PROD_ID123("BASICS by New Media Corporation", "Ethernet", "SMC91C94", 0x23c78a9d, 0x00b2e941, 0xcef397fb),
+ PCMCIA_DEVICE_PROD_ID12("ARGOSY", "Fast Ethernet PCCard", 0x78f308dc, 0xdcea68bc),
+ PCMCIA_DEVICE_PROD_ID12("dit Co., Ltd.", "PC Card-10/100BTX", 0xe59365c8, 0x6a2161d1),
+ PCMCIA_DEVICE_PROD_ID12("DYNALINK", "L100C", 0x6a26d1cf, 0xc16ce9c5),
+ PCMCIA_DEVICE_PROD_ID12("Farallon", "Farallon Enet", 0x58d93fc4, 0x244734e9),
+ PCMCIA_DEVICE_PROD_ID12("Megahertz", "CC10BT/2", 0x33234748, 0x3c95b953),
+ PCMCIA_DEVICE_PROD_ID12("MELCO/SMC", "LPC-TX", 0xa2cd8e6d, 0x42da662a),
+ PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_DEVICE_PROD_ID12("Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA", "Fast Ethernet PCCard", 0x281f1c5d, 0xdcea68bc),
+ PCMCIA_DEVICE_PROD_ID12("Psion", "10Mb Ethernet", 0x4ef00b21, 0x844be9e9),
+ PCMCIA_DEVICE_PROD_ID12("SMC", "EtherEZ Ethernet 8020", 0xc4f8b18b, 0x4a0eeb2d),
+ /* These conflict with other cards! */
+ /* PCMCIA_DEVICE_MANF_CARD(0x0186, 0x0100), */
+ /* PCMCIA_DEVICE_MANF_CARD(0x8a01, 0xc1ab), */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, smc91c92_ids);
+
static struct pcmcia_driver smc91c92_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "smc91c92_cs",
},
.attach = smc91c92_attach,
+ .event = smc91c92_event,
.detach = smc91c92_detach,
+ .id_table = smc91c92_ids,
};
static int __init init_smc91c92_cs(void)
diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
index 58177d67ea12..9f33bad174e9 100644
--- a/drivers/net/pcmcia/xirc2ps_cs.c
+++ b/drivers/net/pcmcia/xirc2ps_cs.c
@@ -81,7 +81,6 @@
#include <linux/ioport.h>
#include <linux/bitops.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -619,11 +618,6 @@ xirc2ps_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &xirc2ps_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
if ((err = pcmcia_register_client(&link->handle, &client_reg))) {
@@ -1983,13 +1977,42 @@ do_stop(struct net_device *dev)
return 0;
}
+static struct pcmcia_device_id xirc2ps_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0089, 0x110a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(0, 0x0138, 0x110a),
+ PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+ PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+ PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+ PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+ PCMCIA_PFC_DEVICE_PROD_ID13(0, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+ PCMCIA_PFC_DEVICE_PROD_ID12(0, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x010a),
+ PCMCIA_DEVICE_PROD_ID13("Toshiba Information Systems", "TPCENET", 0x1b3b94fe, 0xf381c1a2),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "CE3-10/100", 0x2e3ee845, 0x0ec0ac37),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "PS-CE2-10", 0x2e3ee845, 0x947d9073),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "R2E-100BTX", 0x2e3ee845, 0x2464a6e3),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "RE-10", 0x2e3ee845, 0x3e08d609),
+ PCMCIA_DEVICE_PROD_ID13("Xircom", "XE2000", 0x2e3ee845, 0xf7188e46),
+ PCMCIA_DEVICE_PROD_ID12("Compaq", "Ethernet LAN Card", 0x54f7c49c, 0x9fd2f0a2),
+ PCMCIA_DEVICE_PROD_ID12("Compaq", "Netelligent 10/100 PC Card", 0x54f7c49c, 0xefe96769),
+ PCMCIA_DEVICE_PROD_ID12("Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16", 0x816cc815, 0x174397db),
+ PCMCIA_DEVICE_PROD_ID12("Toshiba", "10/100 Ethernet PC Card", 0x44a09d9c, 0xb44deecf),
+ /* also matches CFE-10 cards! */
+ /* PCMCIA_DEVICE_MANF_CARD(0x0105, 0x010a), */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, xirc2ps_ids);
+
+
static struct pcmcia_driver xirc2ps_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "xirc2ps_cs",
},
.attach = xirc2ps_attach,
+ .event = xirc2ps_event,
.detach = xirc2ps_detach,
+ .id_table = xirc2ps_ids,
};
static int __init
diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
index 13f114876965..113b68099216 100644
--- a/drivers/net/pcnet32.c
+++ b/drivers/net/pcnet32.c
@@ -850,7 +850,7 @@ static int pcnet32_phys_id(struct net_device *dev, u32 data)
if ((!data) || (data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ)))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
- schedule_timeout(data * HZ);
+ msleep_interruptible(data * 1000);
del_timer_sync(&lp->blink_timer);
/* Restore the original value of the bcrs */
@@ -1602,7 +1602,7 @@ pcnet32_init_ring(struct net_device *dev)
rmb();
if (lp->rx_dma_addr[i] == 0)
- lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail,
+ lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->data,
PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]);
lp->rx_ring[i].buf_length = le16_to_cpu(2-PKT_BUF_SZ);
@@ -1983,7 +1983,7 @@ pcnet32_rx(struct net_device *dev)
lp->rx_skbuff[entry] = newskb;
newskb->dev = dev;
lp->rx_dma_addr[entry] =
- pci_map_single(lp->pci_dev, newskb->tail,
+ pci_map_single(lp->pci_dev, newskb->data,
PKT_BUF_SZ-2, PCI_DMA_FROMDEVICE);
lp->rx_ring[entry].base = le32_to_cpu(lp->rx_dma_addr[entry]);
rx_in_place = 1;
@@ -2020,7 +2020,7 @@ pcnet32_rx(struct net_device *dev)
PKT_BUF_SZ-2,
PCI_DMA_FROMDEVICE);
eth_copy_and_sum(skb,
- (unsigned char *)(lp->rx_skbuff[entry]->tail),
+ (unsigned char *)(lp->rx_skbuff[entry]->data),
pkt_len,0);
pci_dma_sync_single_for_device(lp->pci_dev,
lp->rx_dma_addr[entry],
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index f4b62405d2e5..21537ee3a6a7 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -540,7 +540,7 @@ plip_receive(unsigned short nibble_timeout, struct net_device *dev,
* in far too many old systems not all even running Linux.
*/
-static unsigned short plip_type_trans(struct sk_buff *skb, struct net_device *dev)
+static __be16 plip_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c
index 5e48b9ab3045..59e8183c639e 100644
--- a/drivers/net/ppp_async.c
+++ b/drivers/net/ppp_async.c
@@ -364,7 +364,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_async_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
- if (skb_queue_len(&ap->rqueue))
+ if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
ap_put(ap);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
index ab726ab43798..a32668e88e09 100644
--- a/drivers/net/ppp_generic.c
+++ b/drivers/net/ppp_generic.c
@@ -1237,8 +1237,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
pch = list_entry(list, struct channel, clist);
navail += pch->avail = (pch->chan != NULL);
if (pch->avail) {
- if (skb_queue_len(&pch->file.xq) == 0
- || !pch->had_frag) {
+ if (skb_queue_empty(&pch->file.xq) ||
+ !pch->had_frag) {
pch->avail = 2;
++nfree;
}
@@ -1374,8 +1374,8 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
/* try to send it down the channel */
chan = pch->chan;
- if (skb_queue_len(&pch->file.xq)
- || !chan->ops->start_xmit(chan, frag))
+ if (!skb_queue_empty(&pch->file.xq) ||
+ !chan->ops->start_xmit(chan, frag))
skb_queue_tail(&pch->file.xq, frag);
pch->had_frag = 1;
p += flen;
@@ -1412,7 +1412,7 @@ ppp_channel_push(struct channel *pch)
spin_lock_bh(&pch->downl);
if (pch->chan != 0) {
- while (skb_queue_len(&pch->file.xq) > 0) {
+ while (!skb_queue_empty(&pch->file.xq)) {
skb = skb_dequeue(&pch->file.xq);
if (!pch->chan->ops->start_xmit(pch->chan, skb)) {
/* put the packet back and try again later */
@@ -1426,7 +1426,7 @@ ppp_channel_push(struct channel *pch)
}
spin_unlock_bh(&pch->downl);
/* see if there is anything from the attached unit to be sent */
- if (skb_queue_len(&pch->file.xq) == 0) {
+ if (skb_queue_empty(&pch->file.xq)) {
read_lock_bh(&pch->upl);
ppp = pch->ppp;
if (ppp != 0)
diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c
index fd9f50180355..4d51c0c8023d 100644
--- a/drivers/net/ppp_synctty.c
+++ b/drivers/net/ppp_synctty.c
@@ -406,7 +406,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
spin_lock_irqsave(&ap->recv_lock, flags);
ppp_sync_input(ap, buf, cflags, count);
spin_unlock_irqrestore(&ap->recv_lock, flags);
- if (skb_queue_len(&ap->rqueue))
+ if (!skb_queue_empty(&ap->rqueue))
tasklet_schedule(&ap->tsk);
sp_put(ap);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c
index ce449fe90e6d..d5afe05cd826 100644
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1876,7 +1876,7 @@ static int rtl8169_alloc_rx_skb(struct pci_dev *pdev, struct sk_buff **sk_buff,
skb_reserve(skb, NET_IP_ALIGN);
*sk_buff = skb;
- mapping = pci_map_single(pdev, skb->tail, rx_buf_sz,
+ mapping = pci_map_single(pdev, skb->data, rx_buf_sz,
PCI_DMA_FROMDEVICE);
rtl8169_map_to_asic(desc, mapping, rx_buf_sz);
@@ -2336,7 +2336,7 @@ static inline int rtl8169_try_rx_copy(struct sk_buff **sk_buff, int pkt_size,
skb = dev_alloc_skb(pkt_size + NET_IP_ALIGN);
if (skb) {
skb_reserve(skb, NET_IP_ALIGN);
- eth_copy_and_sum(skb, sk_buff[0]->tail, pkt_size, 0);
+ eth_copy_and_sum(skb, sk_buff[0]->data, pkt_size, 0);
*sk_buff = skb;
rtl8169_mark_to_asic(desc, rx_buf_sz);
ret = 0;
diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c
index 9c224eba057d..ea638b162d3f 100644
--- a/drivers/net/s2io.c
+++ b/drivers/net/s2io.c
@@ -42,6 +42,7 @@
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -1698,11 +1699,9 @@ static int fill_rx_buffers(struct s2io_nic *nic, int ring_no)
#else
ba = &nic->ba[ring_no][block_no][off];
skb_reserve(skb, BUF0_LEN);
- tmp = (unsigned long) skb->data;
- tmp += ALIGN_SIZE;
- tmp &= ~ALIGN_SIZE;
- skb->data = (void *) tmp;
- skb->tail = (void *) tmp;
+ tmp = ((unsigned long) skb->data & ALIGN_SIZE);
+ if (tmp)
+ skb_reserve(skb, (ALIGN_SIZE + 1) - tmp);
memset(rxdp, 0, sizeof(RxD_t));
rxdp->Buffer2_ptr = pci_map_single
@@ -4593,19 +4592,19 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre)
return ret;
}
- if (!pci_set_dma_mask(pdev, 0xffffffffffffffffULL)) {
+ if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 64bit DMA\n");
dma_flag = TRUE;
if (pci_set_consistent_dma_mask
- (pdev, 0xffffffffffffffffULL)) {
+ (pdev, DMA_64BIT_MASK)) {
DBG_PRINT(ERR_DBG,
"Unable to obtain 64bit DMA for \
consistent allocations\n");
pci_disable_device(pdev);
return -ENOMEM;
}
- } else if (!pci_set_dma_mask(pdev, 0xffffffffUL)) {
+ } else if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
DBG_PRINT(INIT_DBG, "s2io_init_nic: Using 32bit DMA\n");
} else {
pci_disable_device(pdev);
diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c
index e15369c8d165..d6388e1533f0 100644
--- a/drivers/net/sb1000.c
+++ b/drivers/net/sb1000.c
@@ -90,7 +90,6 @@ static int sb1000_close(struct net_device *dev);
/* SB1000 hardware routines to be used during open/configuration phases */
-static inline void nicedelay(unsigned long usecs);
static inline int card_wait_for_busy_clear(const int ioaddr[],
const char* name);
static inline int card_wait_for_ready(const int ioaddr[], const char* name,
@@ -254,13 +253,6 @@ static struct pnp_driver sb1000_driver = {
static const int TimeOutJiffies = (875 * HZ) / 100;
-static inline void nicedelay(unsigned long usecs)
-{
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ);
- return;
-}
-
/* Card Wait For Busy Clear (cannot be used during an interrupt) */
static inline int
card_wait_for_busy_clear(const int ioaddr[], const char* name)
@@ -475,7 +467,7 @@ sb1000_reset(const int ioaddr[], const char* name)
udelay(1000);
outb(0x0, port);
inb(port);
- nicedelay(60000);
+ ssleep(1);
outb(0x4, port);
inb(port);
udelay(1000);
@@ -537,7 +529,7 @@ sb1000_activate(const int ioaddr[], const char* name)
const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
- nicedelay(50000);
+ ssleep(1);
if ((status = card_send_command(ioaddr, name, Command0, st)))
return status;
if ((status = card_send_command(ioaddr, name, Command1, st)))
@@ -944,7 +936,7 @@ sb1000_open(struct net_device *dev)
/* initialize sb1000 */
if ((status = sb1000_reset(ioaddr, name)))
return status;
- nicedelay(200000);
+ ssleep(1);
if ((status = sb1000_check_CRC(ioaddr, name)))
return status;
diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c
index fd2e7c374906..7abd55a4fb21 100644
--- a/drivers/net/sb1250-mac.c
+++ b/drivers/net/sb1250-mac.c
@@ -963,11 +963,11 @@ static int sbdma_add_rcvbuffer(sbmacdma_t *d,struct sk_buff *sb)
/*
* Do not interrupt per DMA transfer.
*/
- dsc->dscr_a = virt_to_phys(sb_new->tail) |
+ dsc->dscr_a = virt_to_phys(sb_new->data) |
V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
0;
#else
- dsc->dscr_a = virt_to_phys(sb_new->tail) |
+ dsc->dscr_a = virt_to_phys(sb_new->data) |
V_DMA_DSCRA_A_SIZE(NUMCACHEBLKS(pktsize+ETHER_ALIGN)) |
M_DMA_DSCRA_INTERRUPT;
#endif
diff --git a/drivers/net/shaper.c b/drivers/net/shaper.c
index 20edeb345792..3ad0b6751f6f 100644
--- a/drivers/net/shaper.c
+++ b/drivers/net/shaper.c
@@ -135,10 +135,8 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct shaper *shaper = dev->priv;
struct sk_buff *ptr;
-
- if (down_trylock(&shaper->sem))
- return -1;
-
+
+ spin_lock(&shaper->lock);
ptr=shaper->sendq.prev;
/*
@@ -232,7 +230,7 @@ static int shaper_start_xmit(struct sk_buff *skb, struct net_device *dev)
shaper->stats.collisions++;
}
shaper_kick(shaper);
- up(&shaper->sem);
+ spin_unlock(&shaper->lock);
return 0;
}
@@ -271,11 +269,9 @@ static void shaper_timer(unsigned long data)
{
struct shaper *shaper = (struct shaper *)data;
- if (!down_trylock(&shaper->sem)) {
- shaper_kick(shaper);
- up(&shaper->sem);
- } else
- mod_timer(&shaper->timer, jiffies);
+ spin_lock(&shaper->lock);
+ shaper_kick(shaper);
+ spin_unlock(&shaper->lock);
}
/*
@@ -332,21 +328,6 @@ static void shaper_kick(struct shaper *shaper)
/*
- * Flush the shaper queues on a closedown
- */
-
-static void shaper_flush(struct shaper *shaper)
-{
- struct sk_buff *skb;
-
- down(&shaper->sem);
- while((skb=skb_dequeue(&shaper->sendq))!=NULL)
- dev_kfree_skb(skb);
- shaper_kick(shaper);
- up(&shaper->sem);
-}
-
-/*
* Bring the interface up. We just disallow this until a
* bind.
*/
@@ -375,7 +356,15 @@ static int shaper_open(struct net_device *dev)
static int shaper_close(struct net_device *dev)
{
struct shaper *shaper=dev->priv;
- shaper_flush(shaper);
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&shaper->sendq)) != NULL)
+ dev_kfree_skb(skb);
+
+ spin_lock_bh(&shaper->lock);
+ shaper_kick(shaper);
+ spin_unlock_bh(&shaper->lock);
+
del_timer_sync(&shaper->timer);
return 0;
}
@@ -576,6 +565,7 @@ static void shaper_init_priv(struct net_device *dev)
init_timer(&sh->timer);
sh->timer.function=shaper_timer;
sh->timer.data=(unsigned long)sh;
+ spin_lock_init(&sh->lock);
}
/*
diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c
index 3107aed0fb51..23b713c700b3 100644
--- a/drivers/net/sis900.c
+++ b/drivers/net/sis900.c
@@ -66,6 +66,7 @@
#include <linux/ethtool.h>
#include <linux/crc32.h>
#include <linux/bitops.h>
+#include <linux/dma-mapping.h>
#include <asm/processor.h> /* Processor type for cache alignment. */
#include <asm/io.h>
@@ -93,8 +94,6 @@ static int sis900_debug = -1; /* Use SIS900_DEF_MSG as value */
/* Time in jiffies before concluding the transmitter is hung. */
#define TX_TIMEOUT (4*HZ)
-/* SiS 900 is capable of 32 bits BM DMA */
-#define SIS900_DMA_MASK 0xffffffff
enum {
SIS_900 = 0,
@@ -414,7 +413,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev,
ret = pci_enable_device(pci_dev);
if(ret) return ret;
- i = pci_set_dma_mask(pci_dev, SIS900_DMA_MASK);
+ i = pci_set_dma_mask(pci_dev, DMA_32BIT_MASK);
if(i){
printk(KERN_ERR "sis900.c: architecture does not support"
"32bit PCI busmaster DMA\n");
@@ -1155,7 +1154,7 @@ sis900_init_rx_ring(struct net_device *net_dev)
sis_priv->rx_skbuff[i] = skb;
sis_priv->rx_ring[i].cmdsts = RX_BUF_SIZE;
sis_priv->rx_ring[i].bufptr = pci_map_single(sis_priv->pci_dev,
- skb->tail, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
+ skb->data, RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
}
sis_priv->dirty_rx = (unsigned int) (i - NUM_RX_DESC);
@@ -1777,7 +1776,7 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->rx_skbuff[entry] = skb;
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
sis_priv->rx_ring[entry].bufptr =
- pci_map_single(sis_priv->pci_dev, skb->tail,
+ pci_map_single(sis_priv->pci_dev, skb->data,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
sis_priv->dirty_rx++;
}
@@ -1810,7 +1809,7 @@ static int sis900_rx(struct net_device *net_dev)
sis_priv->rx_skbuff[entry] = skb;
sis_priv->rx_ring[entry].cmdsts = RX_BUF_SIZE;
sis_priv->rx_ring[entry].bufptr =
- pci_map_single(sis_priv->pci_dev, skb->tail,
+ pci_map_single(sis_priv->pci_dev, skb->data,
RX_BUF_SIZE, PCI_DMA_FROMDEVICE);
}
}
diff --git a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
index 1ccb2989001c..82570ec44d8e 100644
--- a/drivers/net/sk98lin/skge.c
+++ b/drivers/net/sk98lin/skge.c
@@ -112,6 +112,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
+#include <linux/dma-mapping.h>
#include "h/skdrv1st.h"
#include "h/skdrv2nd.h"
@@ -4912,8 +4913,8 @@ static int __devinit skge_probe_one(struct pci_dev *pdev,
goto out;
/* Configure DMA attributes. */
- if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) &&
- pci_set_dma_mask(pdev, (u64) 0xffffffff))
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) &&
+ pci_set_dma_mask(pdev, DMA_32BIT_MASK))
goto out_disable_device;
diff --git a/drivers/net/skfp/Makefile b/drivers/net/skfp/Makefile
index 6cfccfb7889f..cb23580fcffa 100644
--- a/drivers/net/skfp/Makefile
+++ b/drivers/net/skfp/Makefile
@@ -6,8 +6,8 @@ obj-$(CONFIG_SKFP) += skfp.o
skfp-objs := skfddi.o hwmtm.o fplustm.o smt.o cfm.o \
ecm.o pcmplc.o pmf.o queue.o rmt.o \
- smtdef.o smtinit.o smttimer.o srf.o lnkstat.o \
- smtparse.o hwt.o drvfbi.o ess.o
+ smtdef.o smtinit.o smttimer.o srf.o hwt.o \
+ drvfbi.o ess.o
# NOTE:
# Compiling this driver produces some warnings (and some more are
diff --git a/drivers/net/skfp/drvfbi.c b/drivers/net/skfp/drvfbi.c
index 052e841ba187..5b475833f645 100644
--- a/drivers/net/skfp/drvfbi.c
+++ b/drivers/net/skfp/drvfbi.c
@@ -105,8 +105,8 @@ extern int AIX_vpdReadByte() ;
#endif
-/* Prototypes of local functions. */
-void smt_stop_watchdog(struct s_smc *smc);
+/* Prototype of a local function. */
+static void smt_stop_watchdog(struct s_smc *smc);
#ifdef MCA
static int read_card_id() ;
@@ -631,7 +631,7 @@ void plc_clear_irq(struct s_smc *smc, int p)
* LED_Y_OFF just switch yellow LED off
* LED_Y_ON just switch yello LED on
*/
-void led_indication(struct s_smc *smc, int led_event)
+static void led_indication(struct s_smc *smc, int led_event)
{
/* use smc->hw.mac_ring_is_up == TRUE
* as indication for Ring Operational
@@ -764,122 +764,6 @@ void llc_recover_tx(struct s_smc *smc)
#endif
}
-/*--------------------------- DMA init ----------------------------*/
-#ifdef ISA
-
-/*
- * init DMA
- */
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- /*
- * set cascade mode,
- * clear mask bit (enable DMA cannal)
- */
- if (dma > 3) {
- outp(0xd6,(dma & 0x03) | 0xc0) ;
- outp(0xd4, dma & 0x03) ;
- }
- else {
- outp(0x0b,(dma & 0x03) | 0xc0) ;
- outp(0x0a,dma & 0x03) ;
- }
-}
-
-/*
- * disable DMA
- */
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- /*
- * set mask bit (disable DMA cannal)
- */
- if (dma > 3) {
- outp(0xd4,(dma & 0x03) | 0x04) ;
- }
- else {
- outp(0x0a,(dma & 0x03) | 0x04) ;
- }
-}
-
-#endif /* ISA */
-
-#ifdef EISA
-
-/*arrays with io addresses of dma controller length and address registers*/
-static const int cntr[8] = { 0x001,0x003,0x005,0x007,0,0x0c6,0x0ca,0x0ce } ;
-static const int base[8] = { 0x000,0x002,0x004,0x006,0,0x0c4,0x0c8,0x0cc } ;
-static const int page[8] = { 0x087,0x083,0x081,0x082,0,0x08b,0x089,0x08a } ;
-
-void init_dma(struct s_smc *smc, int dma)
-{
- /*
- * extended mode register
- * 32 bit IO
- * type c
- * TC output
- * disable stop
- */
-
- /* mode read (write) demand */
- smc->hw.dma_rmode = (dma & 3) | 0x08 | 0x0 ;
- smc->hw.dma_wmode = (dma & 3) | 0x04 | 0x0 ;
-
- /* 32 bit IO's, burst DMA mode (type "C") */
- smc->hw.dma_emode = (dma & 3) | 0x08 | 0x30 ;
-
- outp((dma < 4) ? 0x40b : 0x4d6,smc->hw.dma_emode) ;
-
- /* disable chaining */
- outp((dma < 4) ? 0x40a : 0x4d4,(dma&3)) ;
-
- /*load dma controller addresses for fast access during set dma*/
- smc->hw.dma_base_word_count = cntr[smc->hw.dma];
- smc->hw.dma_base_address = base[smc->hw.dma];
- smc->hw.dma_base_address_page = page[smc->hw.dma];
-
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
-
- outp((dma < 4) ? 0x0a : 0xd4,(dma&3)|4) ;/* mask bit */
-}
-#endif /* EISA */
-
-#ifdef MCA
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-#endif
-
-#ifdef PCI
-void init_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-
-void dis_dma(struct s_smc *smc, int dma)
-{
- SK_UNUSED(smc) ;
- SK_UNUSED(dma) ;
-}
-#endif
-
#ifdef MULT_OEM
static int is_equal_num(char comp1[], char comp2[], int num)
{
@@ -1407,7 +1291,7 @@ void smt_start_watchdog(struct s_smc *smc)
#endif /* DEBUG */
}
-void smt_stop_watchdog(struct s_smc *smc)
+static void smt_stop_watchdog(struct s_smc *smc)
{
SK_UNUSED(smc) ; /* Make LINT happy. */
#ifndef DEBUG
@@ -1422,104 +1306,6 @@ void smt_stop_watchdog(struct s_smc *smc)
}
#ifdef PCI
-static char get_rom_byte(struct s_smc *smc, u_short addr)
-{
- GET_PAGE(addr) ;
- return (READ_PROM(ADDR(B2_FDP))) ;
-}
-
-/*
- * ROM image defines
- */
-#define ROM_SIG_1 0
-#define ROM_SIG_2 1
-#define PCI_DATA_1 0x18
-#define PCI_DATA_2 0x19
-
-/*
- * PCI data structure defines
- */
-#define VPD_DATA_1 0x08
-#define VPD_DATA_2 0x09
-#define IMAGE_LEN_1 0x10
-#define IMAGE_LEN_2 0x11
-#define CODE_TYPE 0x14
-#define INDICATOR 0x15
-
-/*
- * BEGIN_MANUAL_ENTRY(mac_drv_vpd_read)
- * mac_drv_vpd_read(smc,buf,size,image)
- *
- * function DOWNCALL (FDDIWARE)
- * reads the VPD data of the FPROM and writes it into the
- * buffer
- *
- * para buf points to the buffer for the VPD data
- * size size of the VPD data buffer
- * image boot image; code type of the boot image
- * image = 0 Intel x86, PC-AT compatible
- * 1 OPENBOOT standard for PCI
- * 2-FF reserved
- *
- * returns len number of VPD data bytes read form the FPROM
- * <0 number of read bytes
- * >0 error: data invalid
- *
- * END_MANUAL_ENTRY
- */
-int mac_drv_vpd_read(struct s_smc *smc, char *buf, int size, char image)
-{
- u_short ibase ;
- u_short pci_base ;
- u_short vpd ;
- int len ;
-
- len = 0 ;
- ibase = 0 ;
- /*
- * as long images defined
- */
- while (get_rom_byte(smc,ibase+ROM_SIG_1) == 0x55 &&
- (u_char) get_rom_byte(smc,ibase+ROM_SIG_2) == 0xaa) {
- /*
- * get the pointer to the PCI data structure
- */
- pci_base = ibase + get_rom_byte(smc,ibase+PCI_DATA_1) +
- (get_rom_byte(smc,ibase+PCI_DATA_2) << 8) ;
-
- if (image == get_rom_byte(smc,pci_base+CODE_TYPE)) {
- /*
- * we have the right image, read the VPD data
- */
- vpd = ibase + get_rom_byte(smc,pci_base+VPD_DATA_1) +
- (get_rom_byte(smc,pci_base+VPD_DATA_2) << 8) ;
- if (vpd == ibase) {
- break ; /* no VPD data */
- }
- for (len = 0; len < size; len++,buf++,vpd++) {
- *buf = get_rom_byte(smc,vpd) ;
- }
- break ;
- }
- else {
- /*
- * try the next image
- */
- if (get_rom_byte(smc,pci_base+INDICATOR) & 0x80) {
- break ; /* this was the last image */
- }
- ibase = ibase + get_rom_byte(smc,ibase+IMAGE_LEN_1) +
- (get_rom_byte(smc,ibase+IMAGE_LEN_2) << 8) ;
- }
- }
-
- return(len) ;
-}
-
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value)
-{
- smc->hw.pci_fix_value = fix_value ;
-}
void mac_do_pci_fix(struct s_smc *smc)
{
diff --git a/drivers/net/skfp/ess.c b/drivers/net/skfp/ess.c
index fd39b4b2ef7d..62b01328c496 100644
--- a/drivers/net/skfp/ess.c
+++ b/drivers/net/skfp/ess.c
@@ -102,7 +102,7 @@ void ess_timer_poll(struct s_smc *smc);
void ess_para_change(struct s_smc *smc);
int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
int fs);
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead);
/*
@@ -375,7 +375,7 @@ int ess_raf_received_pack(struct s_smc *smc, SMbuf *mb, struct smt_header *sm,
* determines the synchronous bandwidth, set the TSYNC register and the
* mib variables SBAPayload, SBAOverhead and fddiMACT-NEG.
*/
-int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
+static int process_bw_alloc(struct s_smc *smc, long int payload, long int overhead)
{
/*
* determine the synchronous bandwidth (sync_bw) in bytes per T-NEG,
diff --git a/drivers/net/skfp/fplustm.c b/drivers/net/skfp/fplustm.c
index 76e78442fc24..a2ed47f1cc70 100644
--- a/drivers/net/skfp/fplustm.c
+++ b/drivers/net/skfp/fplustm.c
@@ -1117,30 +1117,6 @@ void mac_clear_multicast(struct s_smc *smc)
/*
BEGIN_MANUAL_ENTRY(if,func;others;2)
- int mac_set_func_addr(smc,f_addr)
- struct s_smc *smc ;
- u_long f_addr ;
-
-Function DOWNCALL (SMT, fplustm.c)
- Set a Token-Ring functional address, the address will
- be activated after calling mac_update_multicast()
-
-Para f_addr functional bits in non-canonical format
-
-Returns 0: always success
-
- END_MANUAL_ENTRY()
- */
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr)
-{
- smc->hw.fp.func_addr = f_addr ;
- return(0) ;
-}
-
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;2)
-
int mac_add_multicast(smc,addr,can)
struct s_smc *smc ;
struct fddi_addr *addr ;
@@ -1203,52 +1179,6 @@ int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
}
/*
- BEGIN_MANUAL_ENTRY(if,func;others;2)
-
- void mac_del_multicast(smc,addr,can)
- struct s_smc *smc ;
- struct fddi_addr *addr ;
- int can ;
-
-Function DOWNCALL (SMT, fplustm.c)
- Delete an entry from the multicast table
-
-Para addr pointer to a multicast address
- can = 0: the multicast address has the physical format
- = 1: the multicast address has the canonical format
- | 0x80 permanent
-
- END_MANUAL_ENTRY()
- */
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can)
-{
- SK_LOC_DECL(struct fddi_addr,own) ;
- struct s_fpmc *tb ;
-
- if (!(tb = mac_get_mc_table(smc,addr,&own,1,can & ~0x80)))
- return ;
- /*
- * permanent addresses must be deleted with perm bit
- * and vice versa
- */
- if (( tb->perm && (can & 0x80)) ||
- (!tb->perm && !(can & 0x80))) {
- /*
- * delete it
- */
- if (tb->n) {
- tb->n-- ;
- if (tb->perm) {
- smc->hw.fp.smt_slots_used-- ;
- }
- else {
- smc->hw.fp.os_slots_used-- ;
- }
- }
- }
-}
-
-/*
* mode
*/
diff --git a/drivers/net/skfp/h/cmtdef.h b/drivers/net/skfp/h/cmtdef.h
index 603982debc71..f2f771d8be76 100644
--- a/drivers/net/skfp/h/cmtdef.h
+++ b/drivers/net/skfp/h/cmtdef.h
@@ -507,7 +507,6 @@ void pcm_status_state(struct s_smc *smc, int np, int *type, int *state,
int *remote, int *mac);
void plc_config_mux(struct s_smc *smc, int mux);
void sm_lem_evaluate(struct s_smc *smc);
-void smt_clear_una_dna(struct s_smc *smc);
void mac_update_counter(struct s_smc *smc);
void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off);
void sm_ma_control(struct s_smc *smc, int mode);
@@ -541,11 +540,9 @@ void smt_timer_poll(struct s_smc *smc);
u_long smt_get_time(void);
u_long smt_get_tid(struct s_smc *smc);
void smt_timer_done(struct s_smc *smc);
-void smt_set_defaults(struct s_smc *smc);
void smt_fixup_mib(struct s_smc *smc);
void smt_reset_defaults(struct s_smc *smc, int level);
void smt_agent_task(struct s_smc *smc);
-void smt_please_reconnect(struct s_smc *smc, int reconn_time);
int smt_check_para(struct s_smc *smc, struct smt_header *sm,
const u_short list[]);
void driver_get_bia(struct s_smc *smc, struct fddi_addr *bia_addr);
@@ -568,7 +565,6 @@ int pcm_get_s_port(struct s_smc *smc);
int pcm_rooted_station(struct s_smc *smc);
int cfm_get_mac_input(struct s_smc *smc);
int cfm_get_mac_output(struct s_smc *smc);
-int port_to_mib(struct s_smc *smc, int p);
int cem_build_path(struct s_smc *smc, char *to, int path_index);
int sm_mac_get_tx_state(struct s_smc *smc);
char *get_pcmstate(struct s_smc *smc, int np);
@@ -580,8 +576,6 @@ void smt_send_frame(struct s_smc *smc, SMbuf *mb, int fc, int local);
void smt_set_timestamp(struct s_smc *smc, u_char *p);
void mac_set_rx_mode(struct s_smc *smc, int mode);
int mac_add_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
-int mac_set_func_addr(struct s_smc *smc, u_long f_addr);
-void mac_del_multicast(struct s_smc *smc, struct fddi_addr *addr, int can);
void mac_update_multicast(struct s_smc *smc);
void mac_clear_multicast(struct s_smc *smc);
void set_formac_tsync(struct s_smc *smc, long sync_bw);
@@ -599,7 +593,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd);
int smt_set_mac_opvalues(struct s_smc *smc);
#ifdef TAG_MODE
-void mac_drv_pci_fix(struct s_smc *smc, u_long fix_value);
void mac_do_pci_fix(struct s_smc *smc);
void mac_drv_clear_tx_queue(struct s_smc *smc);
void mac_drv_repair_descr(struct s_smc *smc);
diff --git a/drivers/net/skfp/h/hwmtm.h b/drivers/net/skfp/h/hwmtm.h
index 4e360af07d77..1a606d4bfe5e 100644
--- a/drivers/net/skfp/h/hwmtm.h
+++ b/drivers/net/skfp/h/hwmtm.h
@@ -262,31 +262,6 @@ struct os_debug {
(smc)->hw.fp.tx_q[queue].tx_curr_put
/*
- * BEGIN_MANUAL_ENTRY(HWM_TX_CHECK)
- * void HWM_TX_CHECK(smc,frame_status,low_water)
- *
- * function MACRO (hardware module, hwmtm.h)
- * This macro is invoked by the OS-specific before it left it's
- * driver_send function. This macro calls mac_drv_clear_txd
- * if the free TxDs of the current transmit queue is equal or
- * lower than the given low water mark.
- *
- * para frame_status status of the frame, see design description
- * low_water low water mark of free TxD's
- *
- * END_MANUAL_ENTRY
- */
-#ifndef HWM_NO_FLOW_CTL
-#define HWM_TX_CHECK(smc,frame_status,low_water) {\
- if ((low_water)>=(smc)->hw.fp.tx_q[(frame_status)&QUEUE_A0].tx_free) {\
- mac_drv_clear_txd(smc) ;\
- }\
-}
-#else
-#define HWM_TX_CHECK(smc,frame_status,low_water) mac_drv_clear_txd(smc)
-#endif
-
-/*
* BEGIN_MANUAL_ENTRY(HWM_GET_RX_FRAG_LEN)
* int HWM_GET_RX_FRAG_LEN(rxd)
*
diff --git a/drivers/net/skfp/h/osdef1st.h b/drivers/net/skfp/h/osdef1st.h
index 5359eb53008d..763ca18cbea8 100644
--- a/drivers/net/skfp/h/osdef1st.h
+++ b/drivers/net/skfp/h/osdef1st.h
@@ -20,6 +20,8 @@
// HWM (HardWare Module) Definitions
// -----------------------
+#include <asm/byteorder.h>
+
#ifdef __LITTLE_ENDIAN
#define LITTLE_ENDIAN
#else
diff --git a/drivers/net/skfp/hwmtm.c b/drivers/net/skfp/hwmtm.c
index 18d429021edb..438f424e6361 100644
--- a/drivers/net/skfp/hwmtm.c
+++ b/drivers/net/skfp/hwmtm.c
@@ -86,6 +86,7 @@ static u_long repair_txd_ring(struct s_smc *smc, struct s_smt_tx_queue *queue);
static u_long repair_rxd_ring(struct s_smc *smc, struct s_smt_rx_queue *queue);
static SMbuf* get_llc_rx(struct s_smc *smc);
static SMbuf* get_txd_mb(struct s_smc *smc);
+static void mac_drv_clear_txd(struct s_smc *smc);
/*
-------------------------------------------------------------
@@ -146,7 +147,6 @@ extern int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
*/
void process_receive(struct s_smc *smc);
void fddi_isr(struct s_smc *smc);
-void mac_drv_clear_txd(struct s_smc *smc);
void smt_free_mbuf(struct s_smc *smc, SMbuf *mb);
void init_driver_fplus(struct s_smc *smc);
void mac_drv_rx_mode(struct s_smc *smc, int mode);
@@ -158,7 +158,6 @@ void hwm_tx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
int frame_status);
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len);
int mac_drv_init(struct s_smc *smc);
int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count, int frame_len,
int frame_status);
@@ -1448,35 +1447,6 @@ void hwm_rx_frag(struct s_smc *smc, char far *virt, u_long phys, int len,
NDD_TRACE("RHfE",r,AIX_REVERSE(r->rxd_rbadr),0) ;
}
-#ifndef NDIS_OS2
-/*
- * BEGIN_MANUAL_ENTRY(mac_drv_rx_frag)
- * int mac_drv_rx_frag(smc,virt,len)
- *
- * function DOWNCALL (hwmtm.c)
- * mac_drv_rx_frag fills the fragment with a part of the frame.
- *
- * para virt the virtual address of the fragment
- * len the length in bytes of the fragment
- *
- * return 0: success code, no errors possible
- *
- * END_MANUAL_ENTRY
- */
-int mac_drv_rx_frag(struct s_smc *smc, void far *virt, int len)
-{
- NDD_TRACE("RHSB",virt,len,smc->os.hwm.r.mb_pos) ;
-
- DB_RX("receive from queue: len/virt: = %d/%x",len,virt,4) ;
- memcpy((char far *)virt,smc->os.hwm.r.mb_pos,len) ;
- smc->os.hwm.r.mb_pos += len ;
-
- NDD_TRACE("RHSE",smc->os.hwm.r.mb_pos,0,0) ;
- return(0) ;
-}
-#endif
-
-
/*
* BEGINN_MANUAL_ENTRY(mac_drv_clear_rx_queue)
*
@@ -1978,7 +1948,7 @@ void smt_send_mbuf(struct s_smc *smc, SMbuf *mb, int fc)
*
* END_MANUAL_ENTRY
*/
-void mac_drv_clear_txd(struct s_smc *smc)
+static void mac_drv_clear_txd(struct s_smc *smc)
{
struct s_smt_tx_queue *queue ;
struct s_smt_fp_txd volatile *t1 ;
diff --git a/drivers/net/skfp/lnkstat.c b/drivers/net/skfp/lnkstat.c
deleted file mode 100644
index 00a248044f86..000000000000
--- a/drivers/net/skfp/lnkstat.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further 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 of the License, or
- * (at your option) any later version.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-/*
- IBM FDDI read error log function
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/lnkstat.h"
-
-#ifndef lint
-static const char ID_sccs[] = "@(#)lnkstat.c 1.8 97/04/11 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-#define EL_IS_OK(x,l) ((((int)&(((struct s_error_log *)0)->x)) + \
- sizeof(er->x)) <= l)
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;11)
-
- u_long smt_get_error_word(smc)
- struct s_smc *smc ;
-
-Function DOWNCALL (SMT, lnkstat.c)
- This functions returns the SMT error work for AIX events.
-
-Return smt_error_word These bits are supported:
-
- SMT_ERL_ALC == [PS/PA].fddiPORTLerFlag
- SMT_ERL_BLC == [PB].fddiPORTLerFlag
- SMT_ERL_NCC == fddiMACNotCopiedFlag
- SMT_ERL_FEC == fddiMACFrameErrorFlag
-
- END_MANUAL_ENTRY()
- */
-u_long smt_get_error_word(struct s_smc *smc)
-{
- u_long st;
-
- /*
- * smt error word low
- */
- st = 0 ;
- if (smc->s.sas == SMT_SAS) {
- if (smc->mib.p[PS].fddiPORTLerFlag)
- st |= SMT_ERL_ALC ;
- }
- else {
- if (smc->mib.p[PA].fddiPORTLerFlag)
- st |= SMT_ERL_ALC ;
- if (smc->mib.p[PB].fddiPORTLerFlag)
- st |= SMT_ERL_BLC ;
- }
- if (smc->mib.m[MAC0].fddiMACNotCopiedFlag)
- st |= SMT_ERL_NCC ; /* not copied condition */
- if (smc->mib.m[MAC0].fddiMACFrameErrorFlag)
- st |= SMT_ERL_FEC ; /* frame error condition */
-
- return st;
-}
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;11)
-
- u_long smt_get_event_word(smc)
- struct s_smc *smc ;
-
-Function DOWNCALL (SMT, lnkstat.c)
- This functions returns the SMT event work for AIX events.
-
-Return smt_event_word always 0
-
- END_MANUAL_ENTRY()
- */
-u_long smt_get_event_word(struct s_smc *smc)
-{
- return (u_long) 0;
-}
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;11)
-
- u_long smt_get_port_event_word(smc)
- struct s_smc *smc ;
-
-Function DOWNCALL (SMT, lnkstat.c)
- This functions returns the SMT port event work for AIX events.
-
-Return smt_port_event_word always 0
-
- END_MANUAL_ENTRY()
- */
-u_long smt_get_port_event_word(struct s_smc *smc)
-{
- return (u_long) 0;
-}
-
-/*
- BEGIN_MANUAL_ENTRY(if,func;others;11)
-
- u_long smt_read_errorlog(smc,p,len)
- struct s_smc *smc ;
- char _far *p ;
- int len ;
-
-Function DOWNCALL (SMT, lnkstat.c)
- This functions returns the SMT error log field for AIX events.
-
-Para p pointer to the error log field
- len len of the error log field
-
-Return len used len of the error log field
-
- END_MANUAL_ENTRY()
- */
-int smt_read_errorlog(struct s_smc *smc, char _far *p, int len)
-{
- int i ;
- int st ;
- struct s_error_log _far *er ;
-
- er = (struct s_error_log _far *) p ;
- if (len > sizeof(struct s_error_log))
- len = sizeof(struct s_error_log) ;
- for (i = 0 ; i < len ; i++)
- *p++ = 0 ;
- /*
- * set count
- */
- if (EL_IS_OK(set_count_high,len)) {
- er->set_count_low = (u_short)smc->mib.fddiSMTSetCount.count ;
- er->set_count_high =
- (u_short)(smc->mib.fddiSMTSetCount.count >> 16L) ;
- }
- /*
- * aci
- */
- if (EL_IS_OK(aci_id_code,len)) {
- er->aci_id_code = 0 ;
- }
- /*
- * purge counter is missed frames; 16 bits only
- */
- if (EL_IS_OK(purge_frame_counter,len)) {
- if (smc->mib.m[MAC0].fddiMACCopied_Ct > 0xffff)
- er->purge_frame_counter = 0xffff ;
- else
- er->purge_frame_counter =
- (u_short)smc->mib.m[MAC0].fddiMACCopied_Ct ;
- }
- /*
- * CMT and RMT state machines
- */
- if (EL_IS_OK(ecm_state,len))
- er->ecm_state = smc->mib.fddiSMTECMState ;
-
- if (EL_IS_OK(pcm_b_state,len)) {
- if (smc->s.sas == SMT_SAS) {
- er->pcm_a_state = smc->y[PS].mib->fddiPORTPCMState ;
- er->pcm_b_state = 0 ;
- }
- else {
- er->pcm_a_state = smc->y[PA].mib->fddiPORTPCMState ;
- er->pcm_b_state = smc->y[PB].mib->fddiPORTPCMState ;
- }
- }
- if (EL_IS_OK(cfm_state,len))
- er->cfm_state = smc->mib.fddiSMTCF_State ;
- if (EL_IS_OK(rmt_state,len))
- er->rmt_state = smc->mib.m[MAC0].fddiMACRMTState ;
-
- /*
- * smt error word low (we only need the low order 16 bits.)
- */
-
- st = smt_get_error_word(smc) & 0xffff ;
-
- if (EL_IS_OK(smt_error_low,len))
- er->smt_error_low = st ;
-
- if (EL_IS_OK(ucode_version_level,len))
- er->ucode_version_level = 0x0101 ;
- return(len) ;
-}
-
diff --git a/drivers/net/skfp/pcmplc.c b/drivers/net/skfp/pcmplc.c
index 571f055c096b..cd0aa4c151b0 100644
--- a/drivers/net/skfp/pcmplc.c
+++ b/drivers/net/skfp/pcmplc.c
@@ -1861,13 +1861,6 @@ void plc_irq(struct s_smc *smc, int np, unsigned int cmd)
#endif
}
-void pcm_set_lct_short(struct s_smc *smc, int n)
-{
- if (n <= 0 || n > 1000)
- return ;
- smc->s.lct_short = n ;
-}
-
#ifdef DEBUG
/*
* fill state struct
diff --git a/drivers/net/skfp/pmf.c b/drivers/net/skfp/pmf.c
index f2b446d8b0bf..efc639c013fd 100644
--- a/drivers/net/skfp/pmf.c
+++ b/drivers/net/skfp/pmf.c
@@ -36,12 +36,13 @@ static int smt_authorize(struct s_smc *smc, struct smt_header *sm);
static int smt_check_set_count(struct s_smc *smc, struct smt_header *sm);
static const struct s_p_tab* smt_get_ptab(u_short para);
static int smt_mib_phys(struct s_smc *smc);
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
- int set);
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+ int local, int set);
void smt_add_para(struct s_smc *smc, struct s_pcon *pcon, u_short para,
int index, int local);
static SMbuf *smt_build_pmf_response(struct s_smc *smc, struct smt_header *req,
int set, int local);
+static int port_to_mib(struct s_smc *smc, int p);
#define MOFFSS(e) ((int)&(((struct fddi_mib *)0)->e))
#define MOFFSA(e) ((int) (((struct fddi_mib *)0)->e))
@@ -1078,8 +1079,8 @@ wrong_error:
/*
* set parameter
*/
-int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index, int local,
- int set)
+static int smt_set_para(struct s_smc *smc, struct smt_para *pa, int index,
+ int local, int set)
{
#define IFSET(x) if (set) (x)
@@ -1549,7 +1550,7 @@ static int smt_mib_phys(struct s_smc *smc)
#endif
}
-int port_to_mib(struct s_smc *smc, int p)
+static int port_to_mib(struct s_smc *smc, int p)
{
#ifdef CONCENTRATOR
SK_UNUSED(smc) ;
diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
index c88aad6edd74..4b5ed2c63177 100644
--- a/drivers/net/skfp/skfddi.c
+++ b/drivers/net/skfp/skfddi.c
@@ -149,7 +149,6 @@ extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
extern void mac_drv_clear_rx_queue(struct s_smc *smc);
extern void enable_tx_irq(struct s_smc *smc, u_short queue);
-extern void mac_drv_clear_txd(struct s_smc *smc);
static struct pci_device_id skfddi_pci_tbl[] = {
{ PCI_VENDOR_ID_SK, PCI_DEVICE_ID_SK_FP, PCI_ANY_ID, PCI_ANY_ID, },
diff --git a/drivers/net/skfp/smt.c b/drivers/net/skfp/smt.c
index 71935eaf9d4e..f17c05cbe44b 100644
--- a/drivers/net/skfp/smt.c
+++ b/drivers/net/skfp/smt.c
@@ -86,7 +86,7 @@ static void smt_send_sif_config(struct s_smc *smc, struct fddi_addr *dest,
static void smt_send_sif_operation(struct s_smc *smc, struct fddi_addr *dest,
u_long tid, int local);
#ifdef LITTLE_ENDIAN
-static void smt_string_swap(void);
+static void smt_string_swap(char *data, const char *format, int len);
#endif
static void smt_add_frame_len(SMbuf *mb, int len);
static void smt_fill_una(struct s_smc *smc, struct smt_p_una *una);
@@ -110,7 +110,7 @@ static void smt_fill_setcount(struct s_smc *smc, struct smt_p_setcount *setcount
static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long seed,
int len);
-void smt_clear_una_dna(struct s_smc *smc);
+static void smt_clear_una_dna(struct s_smc *smc);
static void smt_clear_old_una_dna(struct s_smc *smc);
#ifdef CONCENTRATOR
static int entity_to_index(void);
@@ -118,7 +118,7 @@ static int entity_to_index(void);
static void update_dac(struct s_smc *smc, int report);
static int div_ratio(u_long upper, u_long lower);
#ifdef USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len);
+static void hwm_conv_can(struct s_smc *smc, char *data, int len);
#else
#define hwm_conv_can(smc,data,len)
#endif
@@ -216,24 +216,6 @@ void smt_agent_task(struct s_smc *smc)
DB_SMT("SMT agent task\n",0,0) ;
}
-void smt_please_reconnect(struct s_smc *smc, int reconn_time)
-/* struct s_smc *smc; Pointer to SMT context */
-/* int reconn_time; Wait for reconnect time in seconds */
-{
- /*
- * The please reconnect variable is used as a timer.
- * It is decremented each time smt_event is called.
- * This happens every second or when smt_force_irq is called.
- * Note: smt_force_irq () is called on some packet receives and
- * when a multicast address is changed. Since nothing
- * is received during the disconnect and the multicast
- * address changes can be viewed as not very often and
- * the timer runs out close to its given value
- * (reconn_time).
- */
- smc->sm.please_reconnect = reconn_time ;
-}
-
#ifndef SMT_REAL_TOKEN_CT
void smt_emulate_token_ct(struct s_smc *smc, int mac_index)
{
@@ -1574,7 +1556,7 @@ static void smt_fill_echo(struct s_smc *smc, struct smt_p_echo *echo, u_long see
* clear DNA and UNA
* called from CFM if configuration changes
*/
-void smt_clear_una_dna(struct s_smc *smc)
+static void smt_clear_una_dna(struct s_smc *smc)
{
smc->mib.m[MAC0].fddiMACUpstreamNbr = SMT_Unknown ;
smc->mib.m[MAC0].fddiMACDownstreamNbr = SMT_Unknown ;
@@ -2058,30 +2040,10 @@ int smt_action(struct s_smc *smc, int class, int code, int index)
}
/*
- * change tneg
- * set T_Req in MIB (Path Attribute)
- * calculate new values for MAC
- * if change required
- * disconnect
- * set reconnect
- * end
- */
-void smt_change_t_neg(struct s_smc *smc, u_long tneg)
-{
- smc->mib.a[PATH0].fddiPATHMaxT_Req = tneg ;
-
- if (smt_set_mac_opvalues(smc)) {
- RS_SET(smc,RS_EVENT) ;
- smc->sm.please_reconnect = 1 ;
- queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
- }
-}
-
-/*
* canonical conversion of <len> bytes beginning form *data
*/
#ifdef USE_CAN_ADDR
-void hwm_conv_can(struct s_smc *smc, char *data, int len)
+static void hwm_conv_can(struct s_smc *smc, char *data, int len)
{
int i ;
diff --git a/drivers/net/skfp/smtdef.c b/drivers/net/skfp/smtdef.c
index 5a0c8db816d8..4e07ff7073f1 100644
--- a/drivers/net/skfp/smtdef.c
+++ b/drivers/net/skfp/smtdef.c
@@ -76,11 +76,6 @@ void smt_reset_defaults(struct s_smc *smc, int level);
static void smt_init_mib(struct s_smc *smc, int level);
static int set_min_max(int maxflag, u_long mib, u_long limit, u_long *oper);
-void smt_set_defaults(struct s_smc *smc)
-{
- smt_reset_defaults(smc,0) ;
-}
-
#define MS2BCLK(x) ((x)*12500L)
#define US2BCLK(x) ((x)*1250L)
diff --git a/drivers/net/skfp/smtparse.c b/drivers/net/skfp/smtparse.c
deleted file mode 100644
index d5779e414dbe..000000000000
--- a/drivers/net/skfp/smtparse.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/******************************************************************************
- *
- * (C)Copyright 1998,1999 SysKonnect,
- * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
- *
- * See the file "skfddi.c" for further 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 of the License, or
- * (at your option) any later version.
- *
- * The information in this file is provided "AS IS" without warranty.
- *
- ******************************************************************************/
-
-
-/*
- parser for SMT parameters
-*/
-
-#include "h/types.h"
-#include "h/fddi.h"
-#include "h/smc.h"
-#include "h/smt_p.h"
-
-#define KERNEL
-#include "h/smtstate.h"
-
-#ifndef lint
-static const char ID_sccs[] = "@(#)smtparse.c 1.12 98/10/06 (C) SK " ;
-#endif
-
-#ifdef sun
-#define _far
-#endif
-
-/*
- * convert to BCLK units
- */
-#define MS2BCLK(x) ((x)*12500L)
-#define US2BCLK(x) ((x/10)*125L)
-
-/*
- * parameter table
- */
-static struct s_ptab {
- char *pt_name ;
- u_short pt_num ;
- u_short pt_type ;
- u_long pt_min ;
- u_long pt_max ;
-} ptab[] = {
- { "PMFPASSWD",0, 0 } ,
- { "USERDATA",1, 0 } ,
- { "LERCUTOFFA",2, 1, 4, 15 } ,
- { "LERCUTOFFB",3, 1, 4, 15 } ,
- { "LERALARMA",4, 1, 4, 15 } ,
- { "LERALARMB",5, 1, 4, 15 } ,
- { "TMAX",6, 1, 5, 165 } ,
- { "TMIN",7, 1, 5, 165 } ,
- { "TREQ",8, 1, 5, 165 } ,
- { "TVX",9, 1, 2500, 10000 } ,
-#ifdef ESS
- { "SBAPAYLOAD",10, 1, 0, 1562 } ,
- { "SBAOVERHEAD",11, 1, 50, 5000 } ,
- { "MAXTNEG",12, 1, 5, 165 } ,
- { "MINSEGMENTSIZE",13, 1, 0, 4478 } ,
- { "SBACATEGORY",14, 1, 0, 0xffff } ,
- { "SYNCHTXMODE",15, 0 } ,
-#endif
-#ifdef SBA
- { "SBACOMMAND",16, 0 } ,
- { "SBAAVAILABLE",17, 1, 0, 100 } ,
-#endif
- { NULL }
-} ;
-
-/* Define maximum string size for values and keybuffer */
-#define MAX_VAL 40
-
-/*
- * local function declarations
- */
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
- u_long mx, int scale);
-static int parse_word(char *buf, char _far *text);
-
-#ifdef SIM
-#define DB_MAIN(a,b,c) printf(a,b,c)
-#else
-#define DB_MAIN(a,b,c)
-#endif
-
-/*
- * BEGIN_MANUAL_ENTRY()
- *
- * int smt_parse_arg(struct s_smc *,char _far *keyword,int type,
- char _far *value)
- *
- * parse SMT parameter
- * *keyword
- * pointer to keyword, must be \0, \n or \r terminated
- * *value pointer to value, either char * or u_long *
- * if char *
- * pointer to value, must be \0, \n or \r terminated
- * if u_long *
- * contains binary value
- *
- * type 0: integer
- * 1: string
- * return
- * 0 parameter parsed ok
- * != 0 error
- * NOTE:
- * function can be called with DS != SS
- *
- *
- * END_MANUAL_ENTRY()
- */
-int smt_parse_arg(struct s_smc *smc, char _far *keyword, int type,
- char _far *value)
-{
- char keybuf[MAX_VAL+1];
- char valbuf[MAX_VAL+1];
- char c ;
- char *p ;
- char *v ;
- char *d ;
- u_long val = 0 ;
- struct s_ptab *pt ;
- int st ;
- int i ;
-
- /*
- * parse keyword
- */
- if ((st = parse_word(keybuf,keyword)))
- return(st) ;
- /*
- * parse value if given as string
- */
- if (type == 1) {
- if ((st = parse_word(valbuf,value)))
- return(st) ;
- }
- /*
- * search in table
- */
- st = 0 ;
- for (pt = ptab ; (v = pt->pt_name) ; pt++) {
- for (p = keybuf ; (c = *p) ; p++,v++) {
- if (c != *v)
- break ;
- }
- if (!c && !*v)
- break ;
- }
- if (!v)
- return(-1) ;
-#if 0
- printf("=>%s<==>%s<=\n",pt->pt_name,valbuf) ;
-#endif
- /*
- * set value in MIB
- */
- if (pt->pt_type)
- val = parse_num(type,value,valbuf,pt->pt_min,pt->pt_max,1) ;
- switch (pt->pt_num) {
- case 0 :
- v = valbuf ;
- d = (char *) smc->mib.fddiPRPMFPasswd ;
- for (i = 0 ; i < (signed)sizeof(smc->mib.fddiPRPMFPasswd) ; i++)
- *d++ = *v++ ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiPRPMFPasswd) ;
- break ;
- case 1 :
- v = valbuf ;
- d = (char *) smc->mib.fddiSMTUserData ;
- for (i = 0 ; i < (signed)sizeof(smc->mib.fddiSMTUserData) ; i++)
- *d++ = *v++ ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,smc->mib.fddiSMTUserData) ;
- break ;
- case 2 :
- smc->mib.p[PA].fddiPORTLer_Cutoff = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PA].fddiPORTLer_Cutoff) ;
- break ;
- case 3 :
- smc->mib.p[PB].fddiPORTLer_Cutoff = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PB].fddiPORTLer_Cutoff) ;
- break ;
- case 4 :
- smc->mib.p[PA].fddiPORTLer_Alarm = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PA].fddiPORTLer_Alarm) ;
- break ;
- case 5 :
- smc->mib.p[PB].fddiPORTLer_Alarm = (u_char) val ;
- DB_MAIN("SET %s = %d\n",
- pt->pt_name,smc->mib.p[PB].fddiPORTLer_Alarm) ;
- break ;
- case 6 : /* TMAX */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHT_MaxLowerBound =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 7 : /* TMIN */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.m[MAC0].fddiMACT_Min =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 8 : /* TREQ */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHMaxT_Req =
- (u_long) -MS2BCLK((long)val) ;
- break ;
- case 9 : /* TVX */
- DB_MAIN("SET %s = %d \n",pt->pt_name,val) ;
- smc->mib.a[PATH0].fddiPATHTVXLowerBound =
- (u_long) -US2BCLK((long)val) ;
- break ;
-#ifdef ESS
- case 10 : /* SBAPAYLOAD */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- if (smc->mib.fddiESSPayload != val) {
- smc->ess.raf_act_timer_poll = TRUE ;
- smc->mib.fddiESSPayload = val ;
- }
- break ;
- case 11 : /* SBAOVERHEAD */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSOverhead = val ;
- break ;
- case 12 : /* MAXTNEG */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSMaxTNeg = (u_long) -MS2BCLK((long)val) ;
- break ;
- case 13 : /* MINSEGMENTSIZE */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSMinSegmentSize = val ;
- break ;
- case 14 : /* SBACATEGORY */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiESSCategory =
- (smc->mib.fddiESSCategory & 0xffff) |
- ((u_long)(val << 16)) ;
- break ;
- case 15 : /* SYNCHTXMODE */
- /* do not use memcmp(valbuf,"ALL",3) because DS != SS */
- if (valbuf[0] == 'A' && valbuf[1] == 'L' && valbuf[2] == 'L') {
- smc->mib.fddiESSSynchTxMode = TRUE ;
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- }
- /* if (!memcmp(valbuf,"SPLIT",5)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'P' && valbuf[2] == 'L' &&
- valbuf[3] == 'I' && valbuf[4] == 'T') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiESSSynchTxMode = FALSE ;
- }
- break ;
-#endif
-#ifdef SBA
- case 16 : /* SBACOMMAND */
- /* if (!memcmp(valbuf,"START",5)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'A' &&
- valbuf[3] == 'R' && valbuf[4] == 'T') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiSBACommand = SB_START ;
- }
- /* if (!memcmp(valbuf,"STOP",4)) { */
- if (valbuf[0] == 'S' && valbuf[1] == 'T' && valbuf[2] == 'O' &&
- valbuf[3] == 'P') {
- DB_MAIN("SET %s = %s\n",pt->pt_name,valbuf) ;
- smc->mib.fddiSBACommand = SB_STOP ;
- }
- break ;
- case 17 : /* SBAAVAILABLE */
- DB_MAIN("SET %s = %d\n",pt->pt_name,val) ;
- smc->mib.fddiSBAAvailable = (u_char) val ;
- break ;
-#endif
- }
- return(0) ;
-}
-
-static int parse_word(char *buf, char _far *text)
-{
- char c ;
- char *p ;
- int p_len ;
- int quote ;
- int i ;
- int ok ;
-
- /*
- * skip leading white space
- */
- p = buf ;
- for (i = 0 ; i < MAX_VAL ; i++)
- *p++ = 0 ;
- p = buf ;
- p_len = 0 ;
- ok = 0 ;
- while ( (c = *text++) && (c != '\n') && (c != '\r')) {
- if ((c != ' ') && (c != '\t')) {
- ok = 1 ;
- break ;
- }
- }
- if (!ok)
- return(-1) ;
- if (c == '"') {
- quote = 1 ;
- }
- else {
- quote = 0 ;
- text-- ;
- }
- /*
- * parse valbuf
- */
- ok = 0 ;
- while (!ok && p_len < MAX_VAL-1 && (c = *text++) && (c != '\n')
- && (c != '\r')) {
- switch (quote) {
- case 0 :
- if ((c == ' ') || (c == '\t') || (c == '=')) {
- ok = 1 ;
- break ;
- }
- *p++ = c ;
- p_len++ ;
- break ;
- case 2 :
- *p++ = c ;
- p_len++ ;
- quote = 1 ;
- break ;
- case 1 :
- switch (c) {
- case '"' :
- ok = 1 ;
- break ;
- case '\\' :
- quote = 2 ;
- break ;
- default :
- *p++ = c ;
- p_len++ ;
- }
- }
- }
- *p++ = 0 ;
- for (p = buf ; (c = *p) ; p++) {
- if (c >= 'a' && c <= 'z')
- *p = c + 'A' - 'a' ;
- }
- return(0) ;
-}
-
-static u_long parse_num(int type, char _far *value, char *v, u_long mn,
- u_long mx, int scale)
-{
- u_long x = 0 ;
- char c ;
-
- if (type == 0) { /* integer */
- u_long _far *l ;
- u_long u1 ;
-
- l = (u_long _far *) value ;
- u1 = *l ;
- /*
- * if the value is negative take the lower limit
- */
- if ((long)u1 < 0) {
- if (- ((long)u1) > (long) mx) {
- u1 = 0 ;
- }
- else {
- u1 = (u_long) - ((long)u1) ;
- }
- }
- x = u1 ;
- }
- else { /* string */
- int sign = 0 ;
-
- if (*v == '-') {
- sign = 1 ;
- }
- while ((c = *v++) && (c >= '0') && (c <= '9')) {
- x = x * 10 + c - '0' ;
- }
- if (scale == 10) {
- x *= 10 ;
- if (c == '.') {
- if ((c = *v++) && (c >= '0') && (c <= '9')) {
- x += c - '0' ;
- }
- }
- }
- if (sign)
- x = (u_long) - ((long)x) ;
- }
- /*
- * if the value is negative
- * and the absolute value is outside the limits
- * take the lower limit
- * else
- * take the absoute value
- */
- if ((long)x < 0) {
- if (- ((long)x) > (long) mx) {
- x = 0 ;
- }
- else {
- x = (u_long) - ((long)x) ;
- }
- }
- if (x < mn)
- return(mn) ;
- else if (x > mx)
- return(mx) ;
- return(x) ;
-}
-
-#if 0
-struct s_smc SMC ;
-main()
-{
- char *p ;
- char *v ;
- char buf[100] ;
- int toggle = 0 ;
-
- while (gets(buf)) {
- p = buf ;
- while (*p && ((*p == ' ') || (*p == '\t')))
- p++ ;
-
- while (*p && ((*p != ' ') && (*p != '\t')))
- p++ ;
-
- v = p ;
- while (*v && ((*v == ' ') || (*v == '\t')))
- v++ ;
- if ((*v >= '0') && (*v <= '9')) {
- toggle = !toggle ;
- if (toggle) {
- u_long l ;
- l = atol(v) ;
- smt_parse_arg(&SMC,buf,0,(char _far *)&l) ;
- }
- else
- smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
- }
- else {
- smt_parse_arg(&SMC,buf,1,(char _far *)p) ;
- }
- }
- exit(0) ;
-}
-#endif
-
diff --git a/drivers/net/skge.c b/drivers/net/skge.c
index 30e8d589d167..5cacc7ad9e79 100644
--- a/drivers/net/skge.c
+++ b/drivers/net/skge.c
@@ -7,7 +7,7 @@
* of the original driver such as link fail-over and link management because
* those should be done at higher levels.
*
- * Copyright (C) 2004, Stephen Hemminger <shemminger@osdl.org>
+ * Copyright (C) 2004, 2005 Stephen Hemminger <shemminger@osdl.org>
*
* 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
@@ -42,19 +42,20 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "0.6"
+#define DRV_VERSION "0.7"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
#define DEFAULT_RX_RING_SIZE 512
#define MAX_TX_RING_SIZE 1024
#define MAX_RX_RING_SIZE 4096
+#define RX_COPY_THRESHOLD 128
+#define RX_BUF_SIZE 1536
#define PHY_RETRIES 1000
#define ETH_JUMBO_MTU 9000
#define TX_WATCHDOG (5 * HZ)
#define NAPI_WEIGHT 64
#define BLINK_HZ (HZ/4)
-#define LINK_POLL_HZ (HZ/10)
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
@@ -70,28 +71,17 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
static const struct pci_device_id skge_id_table[] = {
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_SYSKONNECT, 0x9E00, /* SK-9Exx */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_MARVELL, 0x4320, /* Gigabit Ethernet Controller */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_MARVELL, 0x5005, /* Marvell (11ab), Belkin */
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032,
- PCI_ANY_ID, PCI_ANY_ID },
- { PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064,
- PCI_ANY_ID, PCI_ANY_ID },
+ { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940) },
+ { PCI_DEVICE(PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C940B) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_YU) },
+ { PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, 0x9E00) }, /* SK-9Exx */
+ { PCI_DEVICE(PCI_VENDOR_ID_DLINK, PCI_DEVICE_ID_DLINK_DGE510T), },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x4320) },
+ { PCI_DEVICE(PCI_VENDOR_ID_MARVELL, 0x5005) }, /* Belkin */
+ { PCI_DEVICE(PCI_VENDOR_ID_CNET, PCI_DEVICE_ID_CNET_GIGACARD) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1032) },
+ { PCI_DEVICE(PCI_VENDOR_ID_LINKSYS, PCI_DEVICE_ID_LINKSYS_EG1064) },
{ 0 }
};
MODULE_DEVICE_TABLE(pci, skge_id_table);
@@ -99,19 +89,22 @@ MODULE_DEVICE_TABLE(pci, skge_id_table);
static int skge_up(struct net_device *dev);
static int skge_down(struct net_device *dev);
static void skge_tx_clean(struct skge_port *skge);
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
static void yukon_init(struct skge_hw *hw, int port);
static void yukon_reset(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_reset(struct skge_hw *hw, int port);
+static void genesis_link_up(struct skge_port *skge);
+/* Avoid conditionals by using array */
static const int txqaddr[] = { Q_XA1, Q_XA2 };
static const int rxqaddr[] = { Q_R1, Q_R2 };
static const u32 rxirqmask[] = { IS_R1_F, IS_R2_F };
static const u32 txirqmask[] = { IS_XA1_F, IS_XA2_F };
+static const u32 portirqmask[] = { IS_PORT_1, IS_PORT_2 };
/* Don't need to look at whole 16K.
* last interesting register is descriptor poll timer.
@@ -154,7 +147,7 @@ static void skge_get_regs(struct net_device *dev, struct ethtool_regs *regs,
static int wol_supported(const struct skge_hw *hw)
{
return !((hw->chip_id == CHIP_ID_GENESIS ||
- (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)));
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)));
}
static void skge_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
@@ -170,7 +163,7 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
struct skge_port *skge = netdev_priv(dev);
struct skge_hw *hw = skge->hw;
- if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
+ if (wol->wolopts != WAKE_MAGIC && wol->wolopts != 0)
return -EOPNOTSUPP;
if (wol->wolopts == WAKE_MAGIC && !wol_supported(hw))
@@ -190,6 +183,36 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
return 0;
}
+/* Determine supported/adverised modes based on hardware.
+ * Note: ethtoool ADVERTISED_xxx == SUPPORTED_xxx
+ */
+static u32 skge_supported_modes(const struct skge_hw *hw)
+{
+ u32 supported;
+
+ if (iscopper(hw)) {
+ supported = SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full
+ | SUPPORTED_1000baseT_Half
+ | SUPPORTED_1000baseT_Full
+ | SUPPORTED_Autoneg| SUPPORTED_TP;
+
+ if (hw->chip_id == CHIP_ID_GENESIS)
+ supported &= ~(SUPPORTED_10baseT_Half
+ | SUPPORTED_10baseT_Full
+ | SUPPORTED_100baseT_Half
+ | SUPPORTED_100baseT_Full);
+
+ else if (hw->chip_id == CHIP_ID_YUKON)
+ supported &= ~SUPPORTED_1000baseT_Half;
+ } else
+ supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE
+ | SUPPORTED_Autoneg;
+
+ return supported;
+}
static int skge_get_settings(struct net_device *dev,
struct ethtool_cmd *ecmd)
@@ -198,38 +221,13 @@ static int skge_get_settings(struct net_device *dev,
struct skge_hw *hw = skge->hw;
ecmd->transceiver = XCVR_INTERNAL;
+ ecmd->supported = skge_supported_modes(hw);
if (iscopper(hw)) {
- if (hw->chip_id == CHIP_ID_GENESIS)
- ecmd->supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_Autoneg | SUPPORTED_TP;
- else {
- ecmd->supported = SUPPORTED_10baseT_Half
- | SUPPORTED_10baseT_Full
- | SUPPORTED_100baseT_Half
- | SUPPORTED_100baseT_Full
- | SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full
- | SUPPORTED_Autoneg| SUPPORTED_TP;
-
- if (hw->chip_id == CHIP_ID_YUKON)
- ecmd->supported &= ~SUPPORTED_1000baseT_Half;
-
- else if (hw->chip_id == CHIP_ID_YUKON_FE)
- ecmd->supported &= ~(SUPPORTED_1000baseT_Half
- | SUPPORTED_1000baseT_Full);
- }
-
ecmd->port = PORT_TP;
ecmd->phy_address = hw->phy_addr;
- } else {
- ecmd->supported = SUPPORTED_1000baseT_Full
- | SUPPORTED_FIBRE
- | SUPPORTED_Autoneg;
-
+ } else
ecmd->port = PORT_FIBRE;
- }
ecmd->advertising = skge->advertising;
ecmd->autoneg = skge->autoneg;
@@ -238,65 +236,57 @@ static int skge_get_settings(struct net_device *dev,
return 0;
}
-static u32 skge_modes(const struct skge_hw *hw)
-{
- u32 modes = ADVERTISED_Autoneg
- | ADVERTISED_1000baseT_Full | ADVERTISED_1000baseT_Half
- | ADVERTISED_100baseT_Full | ADVERTISED_100baseT_Half
- | ADVERTISED_10baseT_Full | ADVERTISED_10baseT_Half;
-
- if (iscopper(hw)) {
- modes |= ADVERTISED_TP;
- switch(hw->chip_id) {
- case CHIP_ID_GENESIS:
- modes &= ~(ADVERTISED_100baseT_Full
- | ADVERTISED_100baseT_Half
- | ADVERTISED_10baseT_Full
- | ADVERTISED_10baseT_Half);
- break;
-
- case CHIP_ID_YUKON:
- modes &= ~ADVERTISED_1000baseT_Half;
- break;
-
- case CHIP_ID_YUKON_FE:
- modes &= ~(ADVERTISED_1000baseT_Half|ADVERTISED_1000baseT_Full);
- break;
- }
- } else {
- modes |= ADVERTISED_FIBRE;
- modes &= ~ADVERTISED_1000baseT_Half;
- }
- return modes;
-}
-
static int skge_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
{
struct skge_port *skge = netdev_priv(dev);
const struct skge_hw *hw = skge->hw;
+ u32 supported = skge_supported_modes(hw);
if (ecmd->autoneg == AUTONEG_ENABLE) {
- if (ecmd->advertising & skge_modes(hw))
- return -EINVAL;
+ ecmd->advertising = supported;
+ skge->duplex = -1;
+ skge->speed = -1;
} else {
+ u32 setting;
+
switch(ecmd->speed) {
case SPEED_1000:
- if (hw->chip_id == CHIP_ID_YUKON_FE)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_1000baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_1000baseT_Half;
+ else
return -EINVAL;
break;
case SPEED_100:
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_100baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_100baseT_Half;
+ else
+ return -EINVAL;
+ break;
+
case SPEED_10:
- if (iscopper(hw) || hw->chip_id == CHIP_ID_GENESIS)
+ if (ecmd->duplex == DUPLEX_FULL)
+ setting = SUPPORTED_10baseT_Full;
+ else if (ecmd->duplex == DUPLEX_HALF)
+ setting = SUPPORTED_10baseT_Half;
+ else
return -EINVAL;
break;
default:
return -EINVAL;
}
+
+ if ((setting & supported) == 0)
+ return -EINVAL;
+
+ skge->speed = ecmd->speed;
+ skge->duplex = ecmd->duplex;
}
skge->autoneg = ecmd->autoneg;
- skge->speed = ecmd->speed;
- skge->duplex = ecmd->duplex;
skge->advertising = ecmd->advertising;
if (netif_running(dev)) {
@@ -393,7 +383,7 @@ static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
- switch(stringset) {
+ switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(skge_stats); i++)
memcpy(data + i * ETH_GSTRING_LEN,
@@ -511,14 +501,6 @@ static int skge_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
-/* Only Yukon II supports TSO (not implemented yet) */
-static int skge_set_tso(struct net_device *dev, u32 data)
-{
- if (data)
- return -EOPNOTSUPP;
- return 0;
-}
-
static void skge_get_pauseparam(struct net_device *dev,
struct ethtool_pauseparam *ecmd)
{
@@ -540,9 +522,9 @@ static int skge_set_pauseparam(struct net_device *dev,
skge->autoneg = ecmd->autoneg;
if (ecmd->rx_pause && ecmd->tx_pause)
skge->flow_control = FLOW_MODE_SYMMETRIC;
- else if(ecmd->rx_pause && !ecmd->tx_pause)
+ else if (ecmd->rx_pause && !ecmd->tx_pause)
skge->flow_control = FLOW_MODE_REM_SEND;
- else if(!ecmd->rx_pause && ecmd->tx_pause)
+ else if (!ecmd->rx_pause && ecmd->tx_pause)
skge->flow_control = FLOW_MODE_LOC_SEND;
else
skge->flow_control = FLOW_MODE_NONE;
@@ -559,8 +541,6 @@ static inline u32 hwkhz(const struct skge_hw *hw)
{
if (hw->chip_id == CHIP_ID_GENESIS)
return 53215; /* or: 53.125 MHz */
- else if (hw->chip_id == CHIP_ID_YUKON_EC)
- return 125000; /* or: 125.000 MHz */
else
return 78215; /* or: 78.125 MHz */
}
@@ -643,30 +623,18 @@ static int skge_set_coalesce(struct net_device *dev,
static void skge_led_on(struct skge_hw *hw, int port)
{
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
skge_write8(hw, B0_LED, LED_STAT_ON);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_TST), LED_T_ON);
- skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 100);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, RX_LED_TST), LED_T_ON);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
- switch (hw->phy_type) {
- case SK_PHY_BCOM:
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
- PHY_B_PEC_LED_ON);
- break;
- case SK_PHY_LONE:
- skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
- 0x0800);
- break;
- default:
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_TST), LED_T_ON);
- skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 100);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
- }
+ /* For Broadcom Phy only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER,
PHY_M_LED_MO_DUP(MO_LED_ON) |
PHY_M_LED_MO_10(MO_LED_ON) |
PHY_M_LED_MO_100(MO_LED_ON) |
@@ -678,28 +646,17 @@ static void skge_led_on(struct skge_hw *hw, int port)
static void skge_led_off(struct skge_hw *hw, int port)
{
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_OFF);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
skge_write8(hw, B0_LED, LED_STAT_OFF);
- skge_write32(hw, SKGEMAC_REG(port, RX_LED_VAL), 0);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_T_OFF);
+ skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
- switch (hw->phy_type) {
- case SK_PHY_BCOM:
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL,
- PHY_B_PEC_LED_OFF);
- break;
- case SK_PHY_LONE:
- skge_xm_phy_write(hw, port, PHY_LONE_LED_CFG,
- PHY_L_LC_LEDT);
- break;
- default:
- skge_write32(hw, SKGEMAC_REG(port, TX_LED_VAL), 0);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_T_OFF);
- }
+ /* Broadcom only */
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
} else {
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER,
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, 0);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER,
PHY_M_LED_MO_DUP(MO_LED_OFF) |
PHY_M_LED_MO_10(MO_LED_OFF) |
PHY_M_LED_MO_100(MO_LED_OFF) |
@@ -730,7 +687,7 @@ static int skge_phys_id(struct net_device *dev, u32 data)
{
struct skge_port *skge = netdev_priv(dev);
- if(!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
+ if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
/* start blinking */
@@ -763,8 +720,6 @@ static struct ethtool_ops skge_ethtool_ops = {
.set_pauseparam = skge_set_pauseparam,
.get_coalesce = skge_get_coalesce,
.set_coalesce = skge_set_coalesce,
- .get_tso = ethtool_op_get_tso,
- .set_tso = skge_set_tso,
.get_sg = ethtool_op_get_sg,
.set_sg = skge_set_sg,
.get_tx_csum = ethtool_op_get_tx_csum,
@@ -793,6 +748,7 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
for (i = 0, e = ring->start, d = vaddr; i < ring->count; i++, e++, d++) {
e->desc = d;
+ e->skb = NULL;
if (i == ring->count - 1) {
e->next = ring->start;
d->next_offset = base;
@@ -806,24 +762,23 @@ static int skge_ring_alloc(struct skge_ring *ring, void *vaddr, u64 base)
return 0;
}
-/* Setup buffer for receiving */
-static inline int skge_rx_alloc(struct skge_port *skge,
- struct skge_element *e)
+static struct sk_buff *skge_rx_alloc(struct net_device *dev, unsigned int size)
{
- unsigned long bufsize = skge->netdev->mtu + ETH_HLEN; /* VLAN? */
- struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb;
- u64 map;
+ struct sk_buff *skb = dev_alloc_skb(size);
- skb = dev_alloc_skb(bufsize + NET_IP_ALIGN);
- if (unlikely(!skb)) {
- printk(KERN_DEBUG PFX "%s: out of memory for receive\n",
- skge->netdev->name);
- return -ENOMEM;
+ if (likely(skb)) {
+ skb->dev = dev;
+ skb_reserve(skb, NET_IP_ALIGN);
}
+ return skb;
+}
- skb->dev = skge->netdev;
- skb_reserve(skb, NET_IP_ALIGN);
+/* Allocate and setup a new buffer for receiving */
+static void skge_rx_setup(struct skge_port *skge, struct skge_element *e,
+ struct sk_buff *skb, unsigned int bufsize)
+{
+ struct skge_rx_desc *rd = e->desc;
+ u64 map;
map = pci_map_single(skge->hw->pdev, skb->data, bufsize,
PCI_DMA_FROMDEVICE);
@@ -841,55 +796,69 @@ static inline int skge_rx_alloc(struct skge_port *skge,
rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | bufsize;
pci_unmap_addr_set(e, mapaddr, map);
pci_unmap_len_set(e, maplen, bufsize);
- return 0;
}
-/* Free all unused buffers in receive ring, assumes receiver stopped */
+/* Resume receiving using existing skb,
+ * Note: DMA address is not changed by chip.
+ * MTU not changed while receiver active.
+ */
+static void skge_rx_reuse(struct skge_element *e, unsigned int size)
+{
+ struct skge_rx_desc *rd = e->desc;
+
+ rd->csum2 = 0;
+ rd->csum2_start = ETH_HLEN;
+
+ wmb();
+
+ rd->control = BMU_OWN | BMU_STF | BMU_IRQ_EOF | BMU_TCP_CHECK | size;
+}
+
+
+/* Free all buffers in receive ring, assumes receiver stopped */
static void skge_rx_clean(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- for (e = ring->to_clean; e != ring->to_use; e = e->next) {
+ e = ring->start;
+ do {
struct skge_rx_desc *rd = e->desc;
rd->control = 0;
-
- pci_unmap_single(hw->pdev,
- pci_unmap_addr(e, mapaddr),
- pci_unmap_len(e, maplen),
- PCI_DMA_FROMDEVICE);
- dev_kfree_skb(e->skb);
- e->skb = NULL;
- }
- ring->to_clean = e;
+ if (e->skb) {
+ pci_unmap_single(hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ pci_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
+ dev_kfree_skb(e->skb);
+ e->skb = NULL;
+ }
+ } while ((e = e->next) != ring->start);
}
+
/* Allocate buffers for receive ring
- * For receive: to_use is refill location
- * to_clean is next received frame.
- *
- * if (to_use == to_clean)
- * then ring all frames in ring need buffers
- * if (to_use->next == to_clean)
- * then ring all frames in ring have buffers
+ * For receive: to_clean is next received frame.
*/
static int skge_rx_fill(struct skge_port *skge)
{
struct skge_ring *ring = &skge->rx_ring;
struct skge_element *e;
- int ret = 0;
+ unsigned int bufsize = skge->rx_buf_size;
- for (e = ring->to_use; e->next != ring->to_clean; e = e->next) {
- if (skge_rx_alloc(skge, e)) {
- ret = 1;
- break;
- }
+ e = ring->start;
+ do {
+ struct sk_buff *skb = skge_rx_alloc(skge->netdev, bufsize);
- }
- ring->to_use = e;
+ if (!skb)
+ return -ENOMEM;
+
+ skge_rx_setup(skge, e, skb, bufsize);
+ } while ( (e = e->next) != ring->start);
- return ret;
+ ring->to_clean = ring->start;
+ return 0;
}
static void skge_link_up(struct skge_port *skge)
@@ -919,50 +888,50 @@ static void skge_link_down(struct skge_port *skge)
printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name);
}
-static u16 skge_xm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
u16 v;
- skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
- v = skge_xm_read16(hw, port, XM_PHY_DATA);
- if (hw->phy_type != SK_PHY_XMAC) {
- for (i = 0; i < PHY_RETRIES; i++) {
- udelay(1);
- if (skge_xm_read16(hw, port, XM_MMU_CMD)
- & XM_MMU_PHY_RDY)
- goto ready;
- }
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ v = xm_read16(hw, port, XM_PHY_DATA);
- printk(KERN_WARNING PFX "%s: phy read timed out\n",
- hw->dev[port]->name);
- return 0;
- ready:
- v = skge_xm_read16(hw, port, XM_PHY_DATA);
+ /* Need to wait for external PHY */
+ for (i = 0; i < PHY_RETRIES; i++) {
+ udelay(1);
+ if (xm_read16(hw, port, XM_MMU_CMD)
+ & XM_MMU_PHY_RDY)
+ goto ready;
}
+ printk(KERN_WARNING PFX "%s: phy read timed out\n",
+ hw->dev[port]->name);
+ return 0;
+ ready:
+ v = xm_read16(hw, port, XM_PHY_DATA);
+
return v;
}
-static void skge_xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
- skge_xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
+ xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
for (i = 0; i < PHY_RETRIES; i++) {
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
goto ready;
- cpu_relax();
+ udelay(1);
}
printk(KERN_WARNING PFX "%s: phy write failed to come ready\n",
hw->dev[port]->name);
ready:
- skge_xm_write16(hw, port, XM_PHY_DATA, val);
+ xm_write16(hw, port, XM_PHY_DATA, val);
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (!(skge_xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
+ if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY))
return;
}
printk(KERN_WARNING PFX "%s: phy write timed out\n",
@@ -999,34 +968,112 @@ static void genesis_init(struct skge_hw *hw)
static void genesis_reset(struct skge_hw *hw, int port)
{
- int i;
- u64 zero = 0;
+ const u8 zero[8] = { 0 };
/* reset the statistics module */
- skge_xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
- skge_xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */
- skge_xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */
- skge_xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */
- skge_xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
+ xm_write32(hw, port, XM_GP_PORT, XM_GP_RES_STAT);
+ xm_write16(hw, port, XM_IMSK, 0xffff); /* disable XMAC IRQs */
+ xm_write32(hw, port, XM_MODE, 0); /* clear Mode Reg */
+ xm_write16(hw, port, XM_TX_CMD, 0); /* reset TX CMD Reg */
+ xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
- /* disable all PHY IRQs */
- if (hw->phy_type == SK_PHY_BCOM)
- skge_xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
+ /* disable Broadcom PHY IRQ */
+ xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
- skge_xm_outhash(hw, port, XM_HSM, (u8 *) &zero);
- for (i = 0; i < 15; i++)
- skge_xm_outaddr(hw, port, XM_EXM(i), (u8 *) &zero);
- skge_xm_outhash(hw, port, XM_SRC_CHK, (u8 *) &zero);
+ xm_outhash(hw, port, XM_HSM, zero);
}
-static void genesis_mac_init(struct skge_hw *hw, int port)
+/* Convert mode to MII values */
+static const u16 phy_pause_map[] = {
+ [FLOW_MODE_NONE] = 0,
+ [FLOW_MODE_LOC_SEND] = PHY_AN_PAUSE_ASYM,
+ [FLOW_MODE_SYMMETRIC] = PHY_AN_PAUSE_CAP,
+ [FLOW_MODE_REM_SEND] = PHY_AN_PAUSE_CAP | PHY_AN_PAUSE_ASYM,
+};
+
+
+/* Check status of Broadcom phy link */
+static void bcom_check_link(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ u16 status;
+
+ /* read twice because of latch */
+ (void) xm_phy_read(hw, port, PHY_BCOM_STAT);
+ status = xm_phy_read(hw, port, PHY_BCOM_STAT);
+
+ pr_debug("bcom_check_link status=0x%x\n", status);
+
+ if ((status & PHY_ST_LSYNC) == 0) {
+ u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
+ cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
+ /* dummy read to ensure writing */
+ (void) xm_read16(hw, port, XM_MMU_CMD);
+
+ if (netif_carrier_ok(dev))
+ skge_link_down(skge);
+ } else {
+ if (skge->autoneg == AUTONEG_ENABLE &&
+ (status & PHY_ST_AN_OVER)) {
+ u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
+ u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
+
+ if (lpa & PHY_B_AN_RF) {
+ printk(KERN_NOTICE PFX "%s: remote fault\n",
+ dev->name);
+ return;
+ }
+
+ /* Check Duplex mismatch */
+ switch(aux & PHY_B_AS_AN_RES_MSK) {
+ case PHY_B_RES_1000FD:
+ skge->duplex = DUPLEX_FULL;
+ break;
+ case PHY_B_RES_1000HD:
+ skge->duplex = DUPLEX_HALF;
+ break;
+ default:
+ printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
+ dev->name);
+ return;
+ }
+
+
+ /* We are using IEEE 802.3z/D5.0 Table 37-4 */
+ switch (aux & PHY_B_AS_PAUSE_MSK) {
+ case PHY_B_AS_PAUSE_MSK:
+ skge->flow_control = FLOW_MODE_SYMMETRIC;
+ break;
+ case PHY_B_AS_PRR:
+ skge->flow_control = FLOW_MODE_REM_SEND;
+ break;
+ case PHY_B_AS_PRT:
+ skge->flow_control = FLOW_MODE_LOC_SEND;
+ break;
+ default:
+ skge->flow_control = FLOW_MODE_NONE;
+ }
+
+ skge->speed = SPEED_1000;
+ }
+
+ if (!netif_carrier_ok(dev))
+ genesis_link_up(skge);
+ }
+}
+
+/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
+ * Phy on for 100 or 10Mbit operation
+ */
+static void bcom_phy_init(struct skge_port *skge, int jumbo)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
int i;
- u32 r;
- u16 id1;
- u16 ctrl1, ctrl2, ctrl3, ctrl4, ctrl5;
+ u16 id1, r, ext, ctl;
/* magic workaround patterns for Broadcom */
static const struct {
@@ -1042,16 +1089,120 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
{ 0x17, 0x0013 }, { 0x15, 0x0A04 }, { 0x18, 0x0420 },
};
+ pr_debug("bcom_phy_init\n");
+
+ /* read Id from external PHY (all have the same address) */
+ id1 = xm_phy_read(hw, port, PHY_XMAC_ID1);
+
+ /* Optimize MDIO transfer by suppressing preamble. */
+ r = xm_read16(hw, port, XM_MMU_CMD);
+ r |= XM_MMU_NO_PRE;
+ xm_write16(hw, port, XM_MMU_CMD,r);
+
+ switch(id1) {
+ case PHY_BCOM_ID1_C0:
+ /*
+ * Workaround BCOM Errata for the C0 type.
+ * Write magic patterns to reserved registers.
+ */
+ for (i = 0; i < ARRAY_SIZE(C0hack); i++)
+ xm_phy_write(hw, port,
+ C0hack[i].reg, C0hack[i].val);
+
+ break;
+ case PHY_BCOM_ID1_A1:
+ /*
+ * Workaround BCOM Errata for the A1 type.
+ * Write magic patterns to reserved registers.
+ */
+ for (i = 0; i < ARRAY_SIZE(A1hack); i++)
+ xm_phy_write(hw, port,
+ A1hack[i].reg, A1hack[i].val);
+ break;
+ }
+
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom PHYs.
+ * Disable Power Management after reset.
+ */
+ r = xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
+ r |= PHY_B_AC_DIS_PM;
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r);
+
+ /* Dummy read */
+ xm_read16(hw, port, XM_ISRC);
+
+ ext = PHY_B_PEC_EN_LTR; /* enable tx led */
+ ctl = PHY_CT_SP1000; /* always 1000mbit */
+
+ if (skge->autoneg == AUTONEG_ENABLE) {
+ /*
+ * Workaround BCOM Errata #1 for the C5 type.
+ * 1000Base-T Link Acquisition Failure in Slave Mode
+ * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
+ */
+ u16 adv = PHY_B_1000C_RD;
+ if (skge->advertising & ADVERTISED_1000baseT_Half)
+ adv |= PHY_B_1000C_AHD;
+ if (skge->advertising & ADVERTISED_1000baseT_Full)
+ adv |= PHY_B_1000C_AFD;
+ xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, adv);
+
+ ctl |= PHY_CT_ANE | PHY_CT_RE_CFG;
+ } else {
+ if (skge->duplex == DUPLEX_FULL)
+ ctl |= PHY_CT_DUP_MD;
+ /* Force to slave */
+ xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, PHY_B_1000C_MSE);
+ }
+
+ /* Set autonegotiation pause parameters */
+ xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV,
+ phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
+
+ /* Handle Jumbo frames */
+ if (jumbo) {
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
+
+ ext |= PHY_B_PEC_HIGH_LA;
+
+ }
+
+ xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ext);
+ xm_phy_write(hw, port, PHY_BCOM_CTRL, ctl);
+
+ /* Use link status change interrrupt */
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
+
+ bcom_check_link(hw, port);
+}
+
+static void genesis_mac_init(struct skge_hw *hw, int port)
+{
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ int jumbo = hw->dev[port]->mtu > ETH_DATA_LEN;
+ int i;
+ u32 r;
+ const u8 zero[6] = { 0 };
+
+ /* Clear MIB counters */
+ xm_write16(hw, port, XM_STAT_CMD,
+ XM_SC_CLR_RXC | XM_SC_CLR_TXC);
+ /* Clear two times according to Errata #3 */
+ xm_write16(hw, port, XM_STAT_CMD,
+ XM_SC_CLR_RXC | XM_SC_CLR_TXC);
/* initialize Rx, Tx and Link LED */
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_ON);
- skge_write8(hw, SKGEMAC_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_ON);
+ skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_LINKSYNC_ON);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_START);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
/* Unreset the XMAC. */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_CLR_MAC_RST);
/*
* Perform additional initialization for external PHYs,
@@ -1059,67 +1210,56 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* GMII mode.
*/
spin_lock_bh(&hw->phy_lock);
- if (hw->phy_type != SK_PHY_XMAC) {
- /* Take PHY out of reset. */
- r = skge_read32(hw, B2_GP_IO);
- if (port == 0)
- r |= GP_DIR_0|GP_IO_0;
- else
- r |= GP_DIR_2|GP_IO_2;
-
- skge_write32(hw, B2_GP_IO, r);
- skge_read32(hw, B2_GP_IO);
-
- /* Enable GMII mode on the XMAC. */
- skge_xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
-
- id1 = skge_xm_phy_read(hw, port, PHY_XMAC_ID1);
-
- /* Optimize MDIO transfer by suppressing preamble. */
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
- | XM_MMU_NO_PRE);
-
- if (id1 == PHY_BCOM_ID1_C0) {
- /*
- * Workaround BCOM Errata for the C0 type.
- * Write magic patterns to reserved registers.
- */
- for (i = 0; i < ARRAY_SIZE(C0hack); i++)
- skge_xm_phy_write(hw, port,
- C0hack[i].reg, C0hack[i].val);
-
- } else if (id1 == PHY_BCOM_ID1_A1) {
- /*
- * Workaround BCOM Errata for the A1 type.
- * Write magic patterns to reserved registers.
- */
- for (i = 0; i < ARRAY_SIZE(A1hack); i++)
- skge_xm_phy_write(hw, port,
- A1hack[i].reg, A1hack[i].val);
- }
+ /* Take external Phy out of reset */
+ r = skge_read32(hw, B2_GP_IO);
+ if (port == 0)
+ r |= GP_DIR_0|GP_IO_0;
+ else
+ r |= GP_DIR_2|GP_IO_2;
- /*
- * Workaround BCOM Errata (#10523) for all BCom PHYs.
- * Disable Power Management after reset.
- */
- r = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL);
- skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL, r | PHY_B_AC_DIS_PM);
- }
+ skge_write32(hw, B2_GP_IO, r);
+ skge_read32(hw, B2_GP_IO);
+ spin_unlock_bh(&hw->phy_lock);
- /* Dummy read */
- skge_xm_read16(hw, port, XM_ISRC);
+ /* Enable GMII interfac */
+ xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
+
+ bcom_phy_init(skge, jumbo);
+
+ /* Set Station Address */
+ xm_outaddr(hw, port, XM_SA, dev->dev_addr);
+
+ /* We don't use match addresses so clear */
+ for (i = 1; i < 16; i++)
+ xm_outaddr(hw, port, XM_EXM(i), zero);
- r = skge_xm_read32(hw, port, XM_MODE);
- skge_xm_write32(hw, port, XM_MODE, r|XM_MD_CSA);
+ /* configure Rx High Water Mark (XM_RX_HI_WM) */
+ xm_write16(hw, port, XM_RX_HI_WM, 1450);
/* We don't need the FCS appended to the packet. */
- r = skge_xm_read16(hw, port, XM_RX_CMD);
- skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_STRIP_FCS);
+ r = XM_RX_LENERR_OK | XM_RX_STRIP_FCS;
+ if (jumbo)
+ r |= XM_RX_BIG_PK_OK;
+
+ if (skge->duplex == DUPLEX_HALF) {
+ /*
+ * If in manual half duplex mode the other side might be in
+ * full duplex mode, so ignore if a carrier extension is not seen
+ * on frames received
+ */
+ r |= XM_RX_DIS_CEXT;
+ }
+ xm_write16(hw, port, XM_RX_CMD, r);
+
/* We want short frames padded to 60 bytes. */
- r = skge_xm_read16(hw, port, XM_TX_CMD);
- skge_xm_write16(hw, port, XM_TX_CMD, r | XM_TX_AUTO_PAD);
+ xm_write16(hw, port, XM_TX_CMD, XM_TX_AUTO_PAD);
+
+ /*
+ * Bump up the transmit threshold. This helps hold off transmit
+ * underruns when we're blasting traffic from both ports at once.
+ */
+ xm_write16(hw, port, XM_TX_THR, 512);
/*
* Enable the reception of all error frames. This is is
@@ -1135,19 +1275,22 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
* case the XMAC will start transfering frames out of the
* RX FIFO as soon as the FIFO threshold is reached.
*/
- r = skge_xm_read32(hw, port, XM_MODE);
- skge_xm_write32(hw, port, XM_MODE,
- XM_MD_RX_CRCE|XM_MD_RX_LONG|XM_MD_RX_RUNT|
- XM_MD_RX_ERR|XM_MD_RX_IRLE);
+ xm_write32(hw, port, XM_MODE, XM_DEF_MODE);
- skge_xm_outaddr(hw, port, XM_SA, hw->dev[port]->dev_addr);
- skge_xm_outaddr(hw, port, XM_EXM(0), hw->dev[port]->dev_addr);
/*
- * Bump up the transmit threshold. This helps hold off transmit
- * underruns when we're blasting traffic from both ports at once.
+ * Initialize the Receive Counter Event Mask (XM_RX_EV_MSK)
+ * - Enable all bits excepting 'Octets Rx OK Low CntOv'
+ * and 'Octets Rx OK Hi Cnt Ov'.
*/
- skge_xm_write16(hw, port, XM_TX_THR, 512);
+ xm_write32(hw, port, XM_RX_EV_MSK, XMR_DEF_MSK);
+
+ /*
+ * Initialize the Transmit Counter Event Mask (XM_TX_EV_MSK)
+ * - Enable all bits excepting 'Octets Tx OK Low CntOv'
+ * and 'Octets Tx OK Hi Cnt Ov'.
+ */
+ xm_write32(hw, port, XM_TX_EV_MSK, XMT_DEF_MSK);
/* Configure MAC arbiter */
skge_write16(hw, B3_MA_TO_CTRL, MA_RST_CLR);
@@ -1164,137 +1307,30 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
skge_write8(hw, B3_MA_RCINI_TX2, 0);
/* Configure Rx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_CLR);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_TIM_PAT);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_ENA_OP_MD);
/* Configure Tx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_CLR);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_TX_CTRL_DEF);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_ENA_OP_MD);
- if (hw->dev[port]->mtu > ETH_DATA_LEN) {
+ if (jumbo) {
/* Enable frame flushing if jumbo frames used */
- skge_write16(hw, SKGEMAC_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
+ skge_write16(hw, SK_REG(port,RX_MFF_CTRL1), MFF_ENA_FLUSH);
} else {
/* enable timeout timers if normal frames */
skge_write16(hw, B3_PA_CTRL,
- port == 0 ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
+ (port == 0) ? PA_ENA_TO_TX1 : PA_ENA_TO_TX2);
}
-
-
- r = skge_xm_read16(hw, port, XM_RX_CMD);
- if (hw->dev[port]->mtu > ETH_DATA_LEN)
- skge_xm_write16(hw, port, XM_RX_CMD, r | XM_RX_BIG_PK_OK);
- else
- skge_xm_write16(hw, port, XM_RX_CMD, r & ~(XM_RX_BIG_PK_OK));
-
- switch (hw->phy_type) {
- case SK_PHY_XMAC:
- if (skge->autoneg == AUTONEG_ENABLE) {
- ctrl1 = PHY_X_AN_FD | PHY_X_AN_HD;
-
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- ctrl1 |= PHY_X_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- ctrl1 |= PHY_X_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- ctrl1 |= PHY_X_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- ctrl1 |= PHY_X_P_BOTH_MD;
- break;
- }
-
- skge_xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl1);
- ctrl2 = PHY_CT_ANE | PHY_CT_RE_CFG;
- } else {
- ctrl2 = 0;
- if (skge->duplex == DUPLEX_FULL)
- ctrl2 |= PHY_CT_DUP_MD;
- }
-
- skge_xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl2);
- break;
-
- case SK_PHY_BCOM:
- ctrl1 = PHY_CT_SP1000;
- ctrl2 = 0;
- ctrl3 = PHY_SEL_TYPE;
- ctrl4 = PHY_B_PEC_EN_LTR;
- ctrl5 = PHY_B_AC_TX_TST;
-
- if (skge->autoneg == AUTONEG_ENABLE) {
- /*
- * Workaround BCOM Errata #1 for the C5 type.
- * 1000Base-T Link Acquisition Failure in Slave Mode
- * Set Repeater/DTE bit 10 of the 1000Base-T Control Register
- */
- ctrl2 |= PHY_B_1000C_RD;
- if (skge->advertising & ADVERTISED_1000baseT_Half)
- ctrl2 |= PHY_B_1000C_AHD;
- if (skge->advertising & ADVERTISED_1000baseT_Full)
- ctrl2 |= PHY_B_1000C_AFD;
-
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- ctrl3 |= PHY_B_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- ctrl3 |= PHY_B_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- ctrl3 |= PHY_B_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- ctrl3 |= PHY_B_P_BOTH_MD;
- break;
- }
-
- /* Restart Auto-negotiation */
- ctrl1 |= PHY_CT_ANE | PHY_CT_RE_CFG;
- } else {
- if (skge->duplex == DUPLEX_FULL)
- ctrl1 |= PHY_CT_DUP_MD;
-
- ctrl2 |= PHY_B_1000C_MSE; /* set it to Slave */
- }
-
- skge_xm_phy_write(hw, port, PHY_BCOM_1000T_CTRL, ctrl2);
- skge_xm_phy_write(hw, port, PHY_BCOM_AUNE_ADV, ctrl3);
-
- if (skge->netdev->mtu > ETH_DATA_LEN) {
- ctrl4 |= PHY_B_PEC_HIGH_LA;
- ctrl5 |= PHY_B_AC_LONG_PACK;
-
- skge_xm_phy_write(hw, port,PHY_BCOM_AUX_CTRL, ctrl5);
- }
-
- skge_xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, ctrl4);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL, ctrl1);
- break;
- }
- spin_unlock_bh(&hw->phy_lock);
-
- /* Clear MIB counters */
- skge_xm_write16(hw, port, XM_STAT_CMD,
- XM_SC_CLR_RXC | XM_SC_CLR_TXC);
- /* Clear two times according to Errata #3 */
- skge_xm_write16(hw, port, XM_STAT_CMD,
- XM_SC_CLR_RXC | XM_SC_CLR_TXC);
-
- /* Start polling for link status */
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
}
static void genesis_stop(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
+ u32 reg;
/* Clear Tx packet arbiter timeout IRQ */
skge_write16(hw, B3_PA_CTRL,
@@ -1304,33 +1340,30 @@ static void genesis_stop(struct skge_port *skge)
* If the transfer stucks at the MAC the STOP command will not
* terminate if we don't flush the XMAC's transmit FIFO !
*/
- skge_xm_write32(hw, port, XM_MODE,
- skge_xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE,
+ xm_read32(hw, port, XM_MODE)|XM_MD_FTF);
/* Reset the MAC */
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
/* For external PHYs there must be special handling */
- if (hw->phy_type != SK_PHY_XMAC) {
- u32 reg = skge_read32(hw, B2_GP_IO);
-
- if (port == 0) {
- reg |= GP_DIR_0;
- reg &= ~GP_IO_0;
- } else {
- reg |= GP_DIR_2;
- reg &= ~GP_IO_2;
- }
- skge_write32(hw, B2_GP_IO, reg);
- skge_read32(hw, B2_GP_IO);
+ reg = skge_read32(hw, B2_GP_IO);
+ if (port == 0) {
+ reg |= GP_DIR_0;
+ reg &= ~GP_IO_0;
+ } else {
+ reg |= GP_DIR_2;
+ reg &= ~GP_IO_2;
}
+ skge_write32(hw, B2_GP_IO, reg);
+ skge_read32(hw, B2_GP_IO);
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
+ xm_write16(hw, port, XM_MMU_CMD,
+ xm_read16(hw, port, XM_MMU_CMD)
& ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
- skge_xm_read16(hw, port, XM_MMU_CMD);
+ xm_read16(hw, port, XM_MMU_CMD);
}
@@ -1341,11 +1374,11 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
int i;
unsigned long timeout = jiffies + HZ;
- skge_xm_write16(hw, port,
+ xm_write16(hw, port,
XM_STAT_CMD, XM_SC_SNP_TXC | XM_SC_SNP_RXC);
/* wait for update to complete */
- while (skge_xm_read16(hw, port, XM_STAT_CMD)
+ while (xm_read16(hw, port, XM_STAT_CMD)
& (XM_SC_SNP_TXC | XM_SC_SNP_RXC)) {
if (time_after(jiffies, timeout))
break;
@@ -1353,68 +1386,60 @@ static void genesis_get_stats(struct skge_port *skge, u64 *data)
}
/* special case for 64 bit octet counter */
- data[0] = (u64) skge_xm_read32(hw, port, XM_TXO_OK_HI) << 32
- | skge_xm_read32(hw, port, XM_TXO_OK_LO);
- data[1] = (u64) skge_xm_read32(hw, port, XM_RXO_OK_HI) << 32
- | skge_xm_read32(hw, port, XM_RXO_OK_LO);
+ data[0] = (u64) xm_read32(hw, port, XM_TXO_OK_HI) << 32
+ | xm_read32(hw, port, XM_TXO_OK_LO);
+ data[1] = (u64) xm_read32(hw, port, XM_RXO_OK_HI) << 32
+ | xm_read32(hw, port, XM_RXO_OK_LO);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_xm_read32(hw, port, skge_stats[i].xmac_offset);
+ data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset);
}
static void genesis_mac_intr(struct skge_hw *hw, int port)
{
struct skge_port *skge = netdev_priv(hw->dev[port]);
- u16 status = skge_xm_read16(hw, port, XM_ISRC);
-
- pr_debug("genesis_intr status %x\n", status);
- if (hw->phy_type == SK_PHY_XMAC) {
- /* LInk down, start polling for state change */
- if (status & XM_IS_INP_ASS) {
- skge_xm_write16(hw, port, XM_IMSK,
- skge_xm_read16(hw, port, XM_IMSK) | XM_IS_INP_ASS);
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
- else if (status & XM_IS_AND)
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
+ u16 status = xm_read16(hw, port, XM_ISRC);
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+ skge->netdev->name, status);
if (status & XM_IS_TXF_UR) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FTF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FTF);
++skge->net_stats.tx_fifo_errors;
}
if (status & XM_IS_RXF_OV) {
- skge_xm_write32(hw, port, XM_MODE, XM_MD_FRF);
+ xm_write32(hw, port, XM_MODE, XM_MD_FRF);
++skge->net_stats.rx_fifo_errors;
}
}
-static void skge_gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
+static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_DATA, val);
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ gma_write16(hw, port, GM_SMI_DATA, val);
+ gma_write16(hw, port, GM_SMI_CTRL,
GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg));
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (!(skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
+ if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY))
break;
}
}
-static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
+static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg)
{
int i;
- skge_gma_write16(hw, port, GM_SMI_CTRL,
+ gma_write16(hw, port, GM_SMI_CTRL,
GM_SMI_CT_PHY_AD(hw->phy_addr)
| GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD);
for (i = 0; i < PHY_RETRIES; i++) {
udelay(1);
- if (skge_gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
+ if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL)
goto ready;
}
@@ -1422,24 +1447,7 @@ static u16 skge_gm_phy_read(struct skge_hw *hw, int port, u16 reg)
hw->dev[port]->name);
return 0;
ready:
- return skge_gma_read16(hw, port, GM_SMI_DATA);
-}
-
-static void genesis_link_down(struct skge_port *skge)
-{
- struct skge_hw *hw = skge->hw;
- int port = skge->port;
-
- pr_debug("genesis_link_down\n");
-
- skge_xm_write16(hw, port, XM_MMU_CMD,
- skge_xm_read16(hw, port, XM_MMU_CMD)
- & ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX));
-
- /* dummy read to ensure writing */
- (void) skge_xm_read16(hw, port, XM_MMU_CMD);
-
- skge_link_down(skge);
+ return gma_read16(hw, port, GM_SMI_DATA);
}
static void genesis_link_up(struct skge_port *skge)
@@ -1450,7 +1458,7 @@ static void genesis_link_up(struct skge_port *skge)
u32 mode, msk;
pr_debug("genesis_link_up\n");
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
/*
* enabling pause frame reception is required for 1000BT
@@ -1458,14 +1466,15 @@ static void genesis_link_up(struct skge_port *skge)
*/
if (skge->flow_control == FLOW_MODE_NONE ||
skge->flow_control == FLOW_MODE_LOC_SEND)
+ /* Disable Pause Frame Reception */
cmd |= XM_MMU_IGN_PF;
else
/* Enable Pause Frame Reception */
cmd &= ~XM_MMU_IGN_PF;
- skge_xm_write16(hw, port, XM_MMU_CMD, cmd);
+ xm_write16(hw, port, XM_MMU_CMD, cmd);
- mode = skge_xm_read32(hw, port, XM_MODE);
+ mode = xm_read32(hw, port, XM_MODE);
if (skge->flow_control == FLOW_MODE_SYMMETRIC ||
skge->flow_control == FLOW_MODE_LOC_SEND) {
/*
@@ -1479,10 +1488,10 @@ static void genesis_link_up(struct skge_port *skge)
/* XM_PAUSE_DA = '010000C28001' (default) */
/* XM_MAC_PTIME = 0xffff (maximum) */
/* remember this value is defined in big endian (!) */
- skge_xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
+ xm_write16(hw, port, XM_MAC_PTIME, 0xffff);
mode |= XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_ENA_PAUSE);
} else {
/*
* disable pause frame generation is required for 1000BT
@@ -1491,125 +1500,68 @@ static void genesis_link_up(struct skge_port *skge)
/* Disable Pause Mode in Mode Register */
mode &= ~XM_PAUSE_MODE;
- skge_write16(hw, SKGEMAC_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
+ skge_write16(hw, SK_REG(port, RX_MFF_CTRL1), MFF_DIS_PAUSE);
}
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
msk = XM_DEF_MSK;
- if (hw->phy_type != SK_PHY_XMAC)
- msk |= XM_IS_INP_ASS; /* disable GP0 interrupt bit */
+ /* disable GP0 interrupt bit for external Phy */
+ msk |= XM_IS_INP_ASS;
- skge_xm_write16(hw, port, XM_IMSK, msk);
- skge_xm_read16(hw, port, XM_ISRC);
+ xm_write16(hw, port, XM_IMSK, msk);
+ xm_read16(hw, port, XM_ISRC);
/* get MMU Command Reg. */
- cmd = skge_xm_read16(hw, port, XM_MMU_CMD);
- if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
+ cmd = xm_read16(hw, port, XM_MMU_CMD);
+ if (skge->duplex == DUPLEX_FULL)
cmd |= XM_MMU_GMII_FD;
- if (hw->phy_type == SK_PHY_BCOM) {
- /*
- * Workaround BCOM Errata (#10523) for all BCom Phys
- * Enable Power Management after link up
- */
- skge_xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
- skge_xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
- & ~PHY_B_AC_DIS_PM);
- skge_xm_phy_write(hw, port, PHY_BCOM_INT_MASK,
- PHY_B_DEF_MSK);
- }
+ /*
+ * Workaround BCOM Errata (#10523) for all BCom Phys
+ * Enable Power Management after link up
+ */
+ xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
+ xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
+ & ~PHY_B_AC_DIS_PM);
+ xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
/* enable Rx/Tx */
- skge_xm_write16(hw, port, XM_MMU_CMD,
+ xm_write16(hw, port, XM_MMU_CMD,
cmd | XM_MMU_ENA_RX | XM_MMU_ENA_TX);
skge_link_up(skge);
}
-static void genesis_bcom_intr(struct skge_port *skge)
+static inline void bcom_phy_intr(struct skge_port *skge)
{
struct skge_hw *hw = skge->hw;
int port = skge->port;
- u16 stat = skge_xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+ u16 isrc;
+
+ isrc = xm_phy_read(hw, port, PHY_BCOM_INT_STAT);
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x\n",
+ skge->netdev->name, isrc);
- pr_debug("genesis_bcom intr stat=%x\n", stat);
+ if (isrc & PHY_B_IS_PSE)
+ printk(KERN_ERR PFX "%s: uncorrectable pair swap error\n",
+ hw->dev[port]->name);
/* Workaround BCom Errata:
* enable and disable loopback mode if "NO HCD" occurs.
*/
- if (stat & PHY_B_IS_NO_HDCL) {
- u16 ctrl = skge_xm_phy_read(hw, port, PHY_BCOM_CTRL);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+ if (isrc & PHY_B_IS_NO_HDCL) {
+ u16 ctrl = xm_phy_read(hw, port, PHY_BCOM_CTRL);
+ xm_phy_write(hw, port, PHY_BCOM_CTRL,
ctrl | PHY_CT_LOOP);
- skge_xm_phy_write(hw, port, PHY_BCOM_CTRL,
+ xm_phy_write(hw, port, PHY_BCOM_CTRL,
ctrl & ~PHY_CT_LOOP);
}
- stat = skge_xm_phy_read(hw, port, PHY_BCOM_STAT);
- if (stat & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE)) {
- u16 aux = skge_xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
- if ( !(aux & PHY_B_AS_LS) && netif_carrier_ok(skge->netdev))
- genesis_link_down(skge);
-
- else if (stat & PHY_B_IS_LST_CHANGE) {
- if (aux & PHY_B_AS_AN_C) {
- switch (aux & PHY_B_AS_AN_RES_MSK) {
- case PHY_B_RES_1000FD:
- skge->duplex = DUPLEX_FULL;
- break;
- case PHY_B_RES_1000HD:
- skge->duplex = DUPLEX_HALF;
- break;
- }
-
- switch (aux & PHY_B_AS_PAUSE_MSK) {
- case PHY_B_AS_PAUSE_MSK:
- skge->flow_control = FLOW_MODE_SYMMETRIC;
- break;
- case PHY_B_AS_PRR:
- skge->flow_control = FLOW_MODE_REM_SEND;
- break;
- case PHY_B_AS_PRT:
- skge->flow_control = FLOW_MODE_LOC_SEND;
- break;
- default:
- skge->flow_control = FLOW_MODE_NONE;
- }
- skge->speed = SPEED_1000;
- }
- genesis_link_up(skge);
- }
- else
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- }
-}
+ if (isrc & (PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+ bcom_check_link(hw, port);
-/* Perodic poll of phy status to check for link transistion */
-static void skge_link_timer(unsigned long __arg)
-{
- struct skge_port *skge = (struct skge_port *) __arg;
- struct skge_hw *hw = skge->hw;
- int port = skge->port;
-
- if (hw->chip_id != CHIP_ID_GENESIS || !netif_running(skge->netdev))
- return;
-
- spin_lock_bh(&hw->phy_lock);
- if (hw->phy_type == SK_PHY_BCOM)
- genesis_bcom_intr(skge);
- else {
- int i;
- for (i = 0; i < 3; i++)
- if (skge_xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
- break;
-
- if (i == 3)
- mod_timer(&skge->link_check, jiffies + LINK_POLL_HZ);
- else
- genesis_link_up(skge);
- }
- spin_unlock_bh(&hw->phy_lock);
}
/* Marvell Phy Initailization */
@@ -1621,31 +1573,27 @@ static void yukon_init(struct skge_hw *hw, int port)
pr_debug("yukon_init\n");
if (skge->autoneg == AUTONEG_ENABLE) {
- u16 ectrl = skge_gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
+ u16 ectrl = gm_phy_read(hw, port, PHY_MARV_EXT_CTRL);
ectrl &= ~(PHY_M_EC_M_DSC_MSK | PHY_M_EC_S_DSC_MSK |
PHY_M_EC_MAC_S_MSK);
ectrl |= PHY_M_EC_MAC_S(MAC_TX_CLK_25_MHZ);
- /* on PHY 88E1111 there is a change for downshift control */
- if (hw->chip_id == CHIP_ID_YUKON_EC)
- ectrl |= PHY_M_EC_M_DSC_2(0) | PHY_M_EC_DOWN_S_ENA;
- else
- ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
+ ectrl |= PHY_M_EC_M_DSC(0) | PHY_M_EC_S_DSC(1);
- skge_gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
+ gm_phy_write(hw, port, PHY_MARV_EXT_CTRL, ectrl);
}
- ctrl = skge_gm_phy_read(hw, port, PHY_MARV_CTRL);
+ ctrl = gm_phy_read(hw, port, PHY_MARV_CTRL);
if (skge->autoneg == AUTONEG_DISABLE)
ctrl &= ~PHY_CT_ANE;
ctrl |= PHY_CT_RESET;
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
ctrl = 0;
ct1000 = 0;
- adv = PHY_SEL_TYPE;
+ adv = PHY_AN_CSMA;
if (skge->autoneg == AUTONEG_ENABLE) {
if (iscopper(hw)) {
@@ -1661,41 +1609,12 @@ static void yukon_init(struct skge_hw *hw, int port)
adv |= PHY_M_AN_10_FD;
if (skge->advertising & ADVERTISED_10baseT_Half)
adv |= PHY_M_AN_10_HD;
-
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- adv |= PHY_B_P_NO_PAUSE;
- break;
- case FLOW_MODE_LOC_SEND:
- adv |= PHY_B_P_ASYM_MD;
- break;
- case FLOW_MODE_SYMMETRIC:
- adv |= PHY_B_P_SYM_MD;
- break;
- case FLOW_MODE_REM_SEND:
- adv |= PHY_B_P_BOTH_MD;
- break;
- }
- } else { /* special defines for FIBER (88E1011S only) */
+ } else /* special defines for FIBER (88E1011S only) */
adv |= PHY_M_AN_1000X_AHD | PHY_M_AN_1000X_AFD;
- /* Set Flow-control capabilities */
- switch (skge->flow_control) {
- case FLOW_MODE_NONE:
- adv |= PHY_M_P_NO_PAUSE_X;
- break;
- case FLOW_MODE_LOC_SEND:
- adv |= PHY_M_P_ASYM_MD_X;
- break;
- case FLOW_MODE_SYMMETRIC:
- adv |= PHY_M_P_SYM_MD_X;
- break;
- case FLOW_MODE_REM_SEND:
- adv |= PHY_M_P_BOTH_MD_X;
- break;
- }
- }
+ /* Set Flow-control capabilities */
+ adv |= phy_pause_map[skge->flow_control];
+
/* Restart Auto-negotiation */
ctrl |= PHY_CT_ANE | PHY_CT_RE_CFG;
} else {
@@ -1717,36 +1636,23 @@ static void yukon_init(struct skge_hw *hw, int port)
ctrl |= PHY_CT_RESET;
}
- if (hw->chip_id != CHIP_ID_YUKON_FE)
- skge_gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
+ gm_phy_write(hw, port, PHY_MARV_1000T_CTRL, ct1000);
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
- skge_gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV, adv);
+ gm_phy_write(hw, port, PHY_MARV_CTRL, ctrl);
/* Setup Phy LED's */
ledctrl = PHY_M_LED_PULS_DUR(PULS_170MS);
ledover = 0;
- if (hw->chip_id == CHIP_ID_YUKON_FE) {
- /* on 88E3082 these bits are at 11..9 (shifted left) */
- ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) << 1;
-
- skge_gm_phy_write(hw, port, PHY_MARV_FE_LED_PAR,
- ((skge_gm_phy_read(hw, port, PHY_MARV_FE_LED_PAR)
-
- & ~PHY_M_FELP_LED1_MSK)
- | PHY_M_FELP_LED1_CTRL(LED_PAR_CTRL_ACT_BL)));
- } else {
- /* set Tx LED (LED_TX) to blink mode on Rx OR Tx activity */
- ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
+ ledctrl |= PHY_M_LED_BLINK_RT(BLINK_84MS) | PHY_M_LEDC_TX_CTRL;
- /* turn off the Rx LED (LED_RX) */
- ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
- }
+ /* turn off the Rx LED (LED_RX) */
+ ledover |= PHY_M_LED_MO_RX(MO_LED_OFF);
/* disable blink mode (LED_DUPLEX) on collisions */
ctrl |= PHY_M_LEDC_DP_CTRL;
- skge_gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
+ gm_phy_write(hw, port, PHY_MARV_LED_CTRL, ledctrl);
if (skge->autoneg == AUTONEG_DISABLE || skge->speed == SPEED_100) {
/* turn on 100 Mbps LED (LED_LINK100) */
@@ -1754,25 +1660,25 @@ static void yukon_init(struct skge_hw *hw, int port)
}
if (ledover)
- skge_gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
+ gm_phy_write(hw, port, PHY_MARV_LED_OVER, ledover);
/* Enable phy interrupt on autonegotiation complete (or link up) */
if (skge->autoneg == AUTONEG_ENABLE)
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_IS_AN_COMPL);
else
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
}
static void yukon_reset(struct skge_hw *hw, int port)
{
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
- skge_gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */
- skge_gma_write16(hw, port, GM_MC_ADDR_H2, 0);
- skge_gma_write16(hw, port, GM_MC_ADDR_H3, 0);
- skge_gma_write16(hw, port, GM_MC_ADDR_H4, 0);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);/* disable PHY IRQs */
+ gma_write16(hw, port, GM_MC_ADDR_H1, 0); /* clear MC hash */
+ gma_write16(hw, port, GM_MC_ADDR_H2, 0);
+ gma_write16(hw, port, GM_MC_ADDR_H3, 0);
+ gma_write16(hw, port, GM_MC_ADDR_H4, 0);
- skge_gma_write16(hw, port, GM_RX_CTRL,
- skge_gma_read16(hw, port, GM_RX_CTRL)
+ gma_write16(hw, port, GM_RX_CTRL,
+ gma_read16(hw, port, GM_RX_CTRL)
| GM_RXCR_UCF_ENA | GM_RXCR_MCF_ENA);
}
@@ -1785,17 +1691,17 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
/* WA code for COMA mode -- set PHY reset */
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
skge_write32(hw, B2_GP_IO,
(skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9));
/* hard reset */
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), GPC_RST_SET);
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_RST_SET);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), GPC_RST_SET);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_RST_SET);
/* WA code for COMA mode -- clear PHY reset */
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
skge_write32(hw, B2_GP_IO,
(skge_read32(hw, B2_GP_IO) | GP_DIR_9)
& ~GP_IO_9);
@@ -1806,13 +1712,13 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg |= iscopper(hw) ? GPC_HWCFG_GMII_COP : GPC_HWCFG_GMII_FIB;
/* Clear GMC reset */
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
- skge_write32(hw, SKGEMAC_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_SET);
+ skge_write32(hw, SK_REG(port, GPHY_CTRL), reg | GPC_RST_CLR);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON | GMC_RST_CLR);
if (skge->autoneg == AUTONEG_DISABLE) {
reg = GM_GPCR_AU_ALL_DIS;
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL) | reg);
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL) | reg);
switch (skge->speed) {
case SPEED_1000:
@@ -1828,7 +1734,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg = GM_GPCR_SPEED_1000 | GM_GPCR_SPEED_100 | GM_GPCR_DUP_FULL;
switch (skge->flow_control) {
case FLOW_MODE_NONE:
- skge_write32(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write32(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
reg |= GM_GPCR_FC_TX_DIS | GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
break;
case FLOW_MODE_LOC_SEND:
@@ -1836,7 +1742,7 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
reg |= GM_GPCR_FC_RX_DIS | GM_GPCR_AU_FCT_DIS;
}
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
skge_read16(hw, GMAC_IRQ_SRC);
spin_lock_bh(&hw->phy_lock);
@@ -1844,25 +1750,25 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
spin_unlock_bh(&hw->phy_lock);
/* MIB clear */
- reg = skge_gma_read16(hw, port, GM_PHY_ADDR);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+ reg = gma_read16(hw, port, GM_PHY_ADDR);
+ gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
for (i = 0; i < GM_MIB_CNT_SIZE; i++)
- skge_gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
- skge_gma_write16(hw, port, GM_PHY_ADDR, reg);
+ gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+ gma_write16(hw, port, GM_PHY_ADDR, reg);
/* transmit control */
- skge_gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
+ gma_write16(hw, port, GM_TX_CTRL, TX_COL_THR(TX_COL_DEF));
/* receive control reg: unicast + multicast + no FCS */
- skge_gma_write16(hw, port, GM_RX_CTRL,
+ gma_write16(hw, port, GM_RX_CTRL,
GM_RXCR_UCF_ENA | GM_RXCR_CRC_DIS | GM_RXCR_MCF_ENA);
/* transmit flow control */
- skge_gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
+ gma_write16(hw, port, GM_TX_FLOW_CTRL, 0xffff);
/* transmit parameter */
- skge_gma_write16(hw, port, GM_TX_PARAM,
+ gma_write16(hw, port, GM_TX_PARAM,
TX_JAM_LEN_VAL(TX_JAM_LEN_DEF) |
TX_JAM_IPG_VAL(TX_JAM_IPG_DEF) |
TX_IPG_JAM_DATA(TX_IPG_JAM_DEF));
@@ -1872,33 +1778,33 @@ static void yukon_mac_init(struct skge_hw *hw, int port)
if (hw->dev[port]->mtu > 1500)
reg |= GM_SMOD_JUMBO_ENA;
- skge_gma_write16(hw, port, GM_SERIAL_MODE, reg);
+ gma_write16(hw, port, GM_SERIAL_MODE, reg);
/* physical address: used for pause frames */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_1L, addr);
/* virtual address for data */
- skge_gm_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
+ gma_set_addr(hw, port, GM_SRC_ADDR_2L, addr);
/* enable interrupt mask for counter overflows */
- skge_gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
- skge_gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
- skge_gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_TX_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_RX_IRQ_MSK, 0);
+ gma_write16(hw, port, GM_TR_IRQ_MSK, 0);
/* Initialize Mac Fifo */
/* Configure Rx MAC FIFO */
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
+ skge_write16(hw, SK_REG(port, RX_GMF_FL_MSK), RX_FF_FL_DEF_MSK);
reg = GMF_OPER_ON | GMF_RX_F_FL_ON;
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3)
+ hw->chip_rev == CHIP_REV_YU_LITE_A3)
reg &= ~GMF_RX_F_FL_ON;
- skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), reg);
- skge_write16(hw, SKGEMAC_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_CLR);
+ skge_write16(hw, SK_REG(port, RX_GMF_CTRL_T), reg);
+ skge_write16(hw, SK_REG(port, RX_GMF_FL_THR), RX_GMF_FL_THR_DEF);
/* Configure Tx MAC FIFO */
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
- skge_write16(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_CLR);
+ skge_write16(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_OPER_ON);
}
static void yukon_stop(struct skge_port *skge)
@@ -1907,19 +1813,19 @@ static void yukon_stop(struct skge_port *skge)
int port = skge->port;
if (hw->chip_id == CHIP_ID_YUKON_LITE &&
- chip_rev(hw) == CHIP_REV_YU_LITE_A3) {
+ hw->chip_rev == CHIP_REV_YU_LITE_A3) {
skge_write32(hw, B2_GP_IO,
skge_read32(hw, B2_GP_IO) | GP_DIR_9 | GP_IO_9);
}
- skge_gma_write16(hw, port, GM_GP_CTRL,
- skge_gma_read16(hw, port, GM_GP_CTRL)
+ gma_write16(hw, port, GM_GP_CTRL,
+ gma_read16(hw, port, GM_GP_CTRL)
& ~(GM_GPCR_RX_ENA|GM_GPCR_RX_ENA));
- skge_gma_read16(hw, port, GM_GP_CTRL);
+ gma_read16(hw, port, GM_GP_CTRL);
/* set GPHY Control reset */
- skge_gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
- skge_gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
+ gma_write32(hw, port, GPHY_CTRL, GPC_RST_SET);
+ gma_write32(hw, port, GMAC_CTRL, GMC_RST_SET);
}
static void yukon_get_stats(struct skge_port *skge, u64 *data)
@@ -1928,39 +1834,40 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data)
int port = skge->port;
int i;
- data[0] = (u64) skge_gma_read32(hw, port, GM_TXO_OK_HI) << 32
- | skge_gma_read32(hw, port, GM_TXO_OK_LO);
- data[1] = (u64) skge_gma_read32(hw, port, GM_RXO_OK_HI) << 32
- | skge_gma_read32(hw, port, GM_RXO_OK_LO);
+ data[0] = (u64) gma_read32(hw, port, GM_TXO_OK_HI) << 32
+ | gma_read32(hw, port, GM_TXO_OK_LO);
+ data[1] = (u64) gma_read32(hw, port, GM_RXO_OK_HI) << 32
+ | gma_read32(hw, port, GM_RXO_OK_LO);
for (i = 2; i < ARRAY_SIZE(skge_stats); i++)
- data[i] = skge_gma_read32(hw, port,
+ data[i] = gma_read32(hw, port,
skge_stats[i].gma_offset);
}
static void yukon_mac_intr(struct skge_hw *hw, int port)
{
- struct skge_port *skge = netdev_priv(hw->dev[port]);
- u8 status = skge_read8(hw, SKGEMAC_REG(port, GMAC_IRQ_SRC));
+ struct net_device *dev = hw->dev[port];
+ struct skge_port *skge = netdev_priv(dev);
+ u8 status = skge_read8(hw, SK_REG(port, GMAC_IRQ_SRC));
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: mac interrupt status 0x%x\n",
+ dev->name, status);
- pr_debug("yukon_intr status %x\n", status);
if (status & GM_IS_RX_FF_OR) {
++skge->net_stats.rx_fifo_errors;
- skge_gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
+ gma_write8(hw, port, RX_GMF_CTRL_T, GMF_CLI_RX_FO);
}
if (status & GM_IS_TX_FF_UR) {
++skge->net_stats.tx_fifo_errors;
- skge_gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
+ gma_write8(hw, port, TX_GMF_CTRL_T, GMF_CLI_TX_FU);
}
}
static u16 yukon_speed(const struct skge_hw *hw, u16 aux)
{
- if (hw->chip_id == CHIP_ID_YUKON_FE)
- return (aux & PHY_M_PS_SPEED_100) ? SPEED_100 : SPEED_10;
-
- switch(aux & PHY_M_PS_SPEED_MSK) {
+ switch (aux & PHY_M_PS_SPEED_MSK) {
case PHY_M_PS_SPEED_1000:
return SPEED_1000;
case PHY_M_PS_SPEED_100:
@@ -1981,15 +1888,15 @@ static void yukon_link_up(struct skge_port *skge)
/* Enable Transmit FIFO Underrun */
skge_write8(hw, GMAC_IRQ_MSK, GMAC_DEF_MSK);
- reg = skge_gma_read16(hw, port, GM_GP_CTRL);
+ reg = gma_read16(hw, port, GM_GP_CTRL);
if (skge->duplex == DUPLEX_FULL || skge->autoneg == AUTONEG_ENABLE)
reg |= GM_GPCR_DUP_FULL;
/* enable Rx/Tx */
reg |= GM_GPCR_RX_ENA | GM_GPCR_TX_ENA;
- skge_gma_write16(hw, port, GM_GP_CTRL, reg);
+ gma_write16(hw, port, GM_GP_CTRL, reg);
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, PHY_M_DEF_MSK);
skge_link_up(skge);
}
@@ -1999,16 +1906,15 @@ static void yukon_link_down(struct skge_port *skge)
int port = skge->port;
pr_debug("yukon_link_down\n");
- skge_gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
- skge_gm_phy_write(hw, port, GM_GP_CTRL,
- skge_gm_phy_read(hw, port, GM_GP_CTRL)
+ gm_phy_write(hw, port, PHY_MARV_INT_MASK, 0);
+ gm_phy_write(hw, port, GM_GP_CTRL,
+ gm_phy_read(hw, port, GM_GP_CTRL)
& ~(GM_GPCR_RX_ENA | GM_GPCR_TX_ENA));
- if (hw->chip_id != CHIP_ID_YUKON_FE &&
- skge->flow_control == FLOW_MODE_REM_SEND) {
+ if (skge->flow_control == FLOW_MODE_REM_SEND) {
/* restore Asymmetric Pause bit */
- skge_gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
- skge_gm_phy_read(hw, port,
+ gm_phy_write(hw, port, PHY_MARV_AUNE_ADV,
+ gm_phy_read(hw, port,
PHY_MARV_AUNE_ADV)
| PHY_M_AN_ASP);
@@ -2027,20 +1933,21 @@ static void yukon_phy_intr(struct skge_port *skge)
const char *reason = NULL;
u16 istatus, phystat;
- istatus = skge_gm_phy_read(hw, port, PHY_MARV_INT_STAT);
- phystat = skge_gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
- pr_debug("yukon phy intr istat=%x phy_stat=%x\n", istatus, phystat);
+ istatus = gm_phy_read(hw, port, PHY_MARV_INT_STAT);
+ phystat = gm_phy_read(hw, port, PHY_MARV_PHY_STAT);
+
+ if (netif_msg_intr(skge))
+ printk(KERN_DEBUG PFX "%s: phy interrupt status 0x%x 0x%x\n",
+ skge->netdev->name, istatus, phystat);
if (istatus & PHY_M_IS_AN_COMPL) {
- if (skge_gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
+ if (gm_phy_read(hw, port, PHY_MARV_AUNE_LP)
& PHY_M_AN_RF) {
reason = "remote fault";
goto failed;
}
- if (!(hw->chip_id == CHIP_ID_YUKON_FE || hw->chip_id == CHIP_ID_YUKON_EC)
- && (skge_gm_phy_read(hw, port, PHY_MARV_1000T_STAT)
- & PHY_B_1000S_MSF)) {
+ if (gm_phy_read(hw, port, PHY_MARV_1000T_STAT) & PHY_B_1000S_MSF) {
reason = "master/slave fault";
goto failed;
}
@@ -2054,10 +1961,6 @@ static void yukon_phy_intr(struct skge_port *skge)
? DUPLEX_FULL : DUPLEX_HALF;
skge->speed = yukon_speed(hw, phystat);
- /* Tx & Rx Pause Enabled bits are at 9..8 */
- if (hw->chip_id == CHIP_ID_YUKON_XL)
- phystat >>= 6;
-
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
switch (phystat & PHY_M_PS_PAUSE_MSK) {
case PHY_M_PS_PAUSE_MSK:
@@ -2075,9 +1978,9 @@ static void yukon_phy_intr(struct skge_port *skge)
if (skge->flow_control == FLOW_MODE_NONE ||
(skge->speed < SPEED_1000 && skge->duplex == DUPLEX_HALF))
- skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_OFF);
else
- skge_write8(hw, SKGEMAC_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
+ skge_write8(hw, SK_REG(port, GMAC_CTRL), GMC_PAUSE_ON);
yukon_link_up(skge);
return;
}
@@ -2161,6 +2064,12 @@ static int skge_up(struct net_device *dev)
if (netif_msg_ifup(skge))
printk(KERN_INFO PFX "%s: enabling interface\n", dev->name);
+ if (dev->mtu > RX_BUF_SIZE)
+ skge->rx_buf_size = dev->mtu + ETH_HLEN + NET_IP_ALIGN;
+ else
+ skge->rx_buf_size = RX_BUF_SIZE;
+
+
rx_size = skge->rx_ring.count * sizeof(struct skge_rx_desc);
tx_size = skge->tx_ring.count * sizeof(struct skge_tx_desc);
skge->mem_size = tx_size + rx_size;
@@ -2173,7 +2082,8 @@ static int skge_up(struct net_device *dev)
if ((err = skge_ring_alloc(&skge->rx_ring, skge->mem, skge->dma)))
goto free_pci_mem;
- if (skge_rx_fill(skge))
+ err = skge_rx_fill(skge);
+ if (err)
goto free_rx_ring;
if ((err = skge_ring_alloc(&skge->tx_ring, skge->mem + rx_size,
@@ -2182,6 +2092,10 @@ static int skge_up(struct net_device *dev)
skge->tx_avail = skge->tx_ring.count - 1;
+ /* Enable IRQ from port */
+ hw->intr_mask |= portirqmask[port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+
/* Initialze MAC */
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_init(hw, port);
@@ -2189,7 +2103,7 @@ static int skge_up(struct net_device *dev)
yukon_mac_init(hw, port);
/* Configure RAMbuffers */
- chunk = hw->ram_size / (isdualport(hw) ? 4 : 2);
+ chunk = hw->ram_size / ((hw->ports + 1)*2);
ram_addr = hw->ram_offset + 2 * chunk * port;
skge_ramset(hw, rxqaddr[port], ram_addr, chunk);
@@ -2227,7 +2141,6 @@ static int skge_down(struct net_device *dev)
netif_stop_queue(dev);
del_timer_sync(&skge->led_blink);
- del_timer_sync(&skge->link_check);
/* Stop transmitter */
skge_write8(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_STOP);
@@ -2240,12 +2153,12 @@ static int skge_down(struct net_device *dev)
yukon_stop(skge);
/* Disable Force Sync bit and Enable Alloc bit */
- skge_write8(hw, SKGEMAC_REG(port, TXA_CTRL),
+ skge_write8(hw, SK_REG(port, TXA_CTRL),
TXA_DIS_FSYNC | TXA_DIS_ALLOC | TXA_STOP_RC);
/* Stop Interval Timer and Limit Counter of Tx Arbiter */
- skge_write32(hw, SKGEMAC_REG(port, TXA_ITI_INI), 0L);
- skge_write32(hw, SKGEMAC_REG(port, TXA_LIM_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_ITI_INI), 0L);
+ skge_write32(hw, SK_REG(port, TXA_LIM_INI), 0L);
/* Reset PCI FIFO */
skge_write32(hw, Q_ADDR(txqaddr[port], Q_CSR), CSR_SET_RESET);
@@ -2260,13 +2173,13 @@ static int skge_down(struct net_device *dev)
skge_write32(hw, Q_ADDR(rxqaddr[port], Q_CSR), CSR_SET_RESET);
if (hw->chip_id == CHIP_ID_GENESIS) {
- skge_write8(hw, SKGEMAC_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, TX_LED_CTRL), LED_STOP);
- skge_write8(hw, SKGEMAC_REG(port, RX_LED_CTRL), LED_STOP);
+ skge_write8(hw, SK_REG(port, TX_MFF_CTRL2), MFF_RST_SET);
+ skge_write8(hw, SK_REG(port, RX_MFF_CTRL2), MFF_RST_SET);
+ skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_STOP);
+ skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_STOP);
} else {
- skge_write8(hw, SKGEMAC_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
+ skge_write8(hw, SK_REG(port, RX_GMF_CTRL_T), GMF_RST_SET);
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T), GMF_RST_SET);
}
/* turn off led's */
@@ -2299,10 +2212,10 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
local_irq_save(flags);
if (!spin_trylock(&skge->tx_lock)) {
- /* Collision - tell upper layer to requeue */
- local_irq_restore(flags);
- return NETDEV_TX_LOCKED;
- }
+ /* Collision - tell upper layer to requeue */
+ local_irq_restore(flags);
+ return NETDEV_TX_LOCKED;
+ }
if (unlikely(skge->tx_avail < skb_shinfo(skb)->nr_frags +1)) {
netif_stop_queue(dev);
@@ -2333,7 +2246,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
* does. Looks like hardware is wrong?
*/
if (ip->protocol == IPPROTO_UDP
- && chip_rev(hw) == 0 && hw->chip_id == CHIP_ID_YUKON)
+ && hw->chip_rev == 0 && hw->chip_id == CHIP_ID_YUKON)
control = BMU_TCP_CHECK;
else
control = BMU_UDP_CHECK;
@@ -2394,6 +2307,7 @@ static int skge_xmit_frame(struct sk_buff *skb, struct net_device *dev)
static inline void skge_tx_free(struct skge_hw *hw, struct skge_element *e)
{
+ /* This ring element can be skb or fragment */
if (e->skb) {
pci_unmap_single(hw->pdev,
pci_unmap_addr(e, mapaddr),
@@ -2438,16 +2352,17 @@ static void skge_tx_timeout(struct net_device *dev)
static int skge_change_mtu(struct net_device *dev, int new_mtu)
{
int err = 0;
+ int running = netif_running(dev);
- if(new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
+ if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
return -EINVAL;
- dev->mtu = new_mtu;
- if (netif_running(dev)) {
+ if (running)
skge_down(dev);
+ dev->mtu = new_mtu;
+ if (running)
skge_up(dev);
- }
return err;
}
@@ -2462,7 +2377,9 @@ static void genesis_set_multicast(struct net_device *dev)
u32 mode;
u8 filter[8];
- mode = skge_xm_read32(hw, port, XM_MODE);
+ pr_debug("genesis_set_multicast flags=%x count=%d\n", dev->flags, dev->mc_count);
+
+ mode = xm_read32(hw, port, XM_MODE);
mode |= XM_MD_ENA_HASH;
if (dev->flags & IFF_PROMISC)
mode |= XM_MD_ENA_PROM;
@@ -2473,17 +2390,16 @@ static void genesis_set_multicast(struct net_device *dev)
memset(filter, 0xff, sizeof(filter));
else {
memset(filter, 0, sizeof(filter));
- for(i = 0; list && i < count; i++, list = list->next) {
- u32 crc = crc32_le(~0, list->dmi_addr, ETH_ALEN);
- u8 bit = 63 - (crc & 63);
-
+ for (i = 0; list && i < count; i++, list = list->next) {
+ u32 crc, bit;
+ crc = ether_crc_le(ETH_ALEN, list->dmi_addr);
+ bit = ~crc & 0x3f;
filter[bit/8] |= 1 << (bit%8);
}
}
- skge_xm_outhash(hw, port, XM_HSM, filter);
-
- skge_xm_write32(hw, port, XM_MODE, mode);
+ xm_write32(hw, port, XM_MODE, mode);
+ xm_outhash(hw, port, XM_HSM, filter);
}
static void yukon_set_multicast(struct net_device *dev)
@@ -2497,7 +2413,7 @@ static void yukon_set_multicast(struct net_device *dev)
memset(filter, 0, sizeof(filter));
- reg = skge_gma_read16(hw, port, GM_RX_CTRL);
+ reg = gma_read16(hw, port, GM_RX_CTRL);
reg |= GM_RXCR_UCF_ENA;
if (dev->flags & IFF_PROMISC) /* promiscious */
@@ -2510,23 +2426,23 @@ static void yukon_set_multicast(struct net_device *dev)
int i;
reg |= GM_RXCR_MCF_ENA;
- for(i = 0; list && i < dev->mc_count; i++, list = list->next) {
+ for (i = 0; list && i < dev->mc_count; i++, list = list->next) {
u32 bit = ether_crc(ETH_ALEN, list->dmi_addr) & 0x3f;
filter[bit/8] |= 1 << (bit%8);
}
}
- skge_gma_write16(hw, port, GM_MC_ADDR_H1,
+ gma_write16(hw, port, GM_MC_ADDR_H1,
(u16)filter[0] | ((u16)filter[1] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H2,
+ gma_write16(hw, port, GM_MC_ADDR_H2,
(u16)filter[2] | ((u16)filter[3] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H3,
+ gma_write16(hw, port, GM_MC_ADDR_H3,
(u16)filter[4] | ((u16)filter[5] << 8));
- skge_gma_write16(hw, port, GM_MC_ADDR_H4,
+ gma_write16(hw, port, GM_MC_ADDR_H4,
(u16)filter[6] | ((u16)filter[7] << 8));
- skge_gma_write16(hw, port, GM_RX_CTRL, reg);
+ gma_write16(hw, port, GM_RX_CTRL, reg);
}
static inline int bad_phy_status(const struct skge_hw *hw, u32 status)
@@ -2545,28 +2461,76 @@ static void skge_rx_error(struct skge_port *skge, int slot,
printk(KERN_DEBUG PFX "%s: rx err, slot %d control 0x%x status 0x%x\n",
skge->netdev->name, slot, control, status);
- if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
- || (control & BMU_BBC) > skge->netdev->mtu + VLAN_ETH_HLEN)
+ if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF))
skge->net_stats.rx_length_errors++;
- else {
- if (skge->hw->chip_id == CHIP_ID_GENESIS) {
- if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
- skge->net_stats.rx_length_errors++;
- if (status & XMR_FS_FRA_ERR)
- skge->net_stats.rx_frame_errors++;
- if (status & XMR_FS_FCS_ERR)
- skge->net_stats.rx_crc_errors++;
- } else {
- if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
- skge->net_stats.rx_length_errors++;
- if (status & GMR_FS_FRAGMENT)
- skge->net_stats.rx_frame_errors++;
- if (status & GMR_FS_CRC_ERR)
- skge->net_stats.rx_crc_errors++;
+ else if (skge->hw->chip_id == CHIP_ID_GENESIS) {
+ if (status & (XMR_FS_RUNT|XMR_FS_LNG_ERR))
+ skge->net_stats.rx_length_errors++;
+ if (status & XMR_FS_FRA_ERR)
+ skge->net_stats.rx_frame_errors++;
+ if (status & XMR_FS_FCS_ERR)
+ skge->net_stats.rx_crc_errors++;
+ } else {
+ if (status & (GMR_FS_LONG_ERR|GMR_FS_UN_SIZE))
+ skge->net_stats.rx_length_errors++;
+ if (status & GMR_FS_FRAGMENT)
+ skge->net_stats.rx_frame_errors++;
+ if (status & GMR_FS_CRC_ERR)
+ skge->net_stats.rx_crc_errors++;
+ }
+}
+
+/* Get receive buffer from descriptor.
+ * Handles copy of small buffers and reallocation failures
+ */
+static inline struct sk_buff *skge_rx_get(struct skge_port *skge,
+ struct skge_element *e,
+ unsigned int len)
+{
+ struct sk_buff *nskb, *skb;
+
+ if (len < RX_COPY_THRESHOLD) {
+ nskb = skge_rx_alloc(skge->netdev, len + NET_IP_ALIGN);
+ if (unlikely(!nskb))
+ return NULL;
+
+ pci_dma_sync_single_for_cpu(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ len, PCI_DMA_FROMDEVICE);
+ memcpy(nskb->data, e->skb->data, len);
+ pci_dma_sync_single_for_device(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ len, PCI_DMA_FROMDEVICE);
+
+ if (skge->rx_csum) {
+ struct skge_rx_desc *rd = e->desc;
+ nskb->csum = le16_to_cpu(rd->csum2);
+ nskb->ip_summed = CHECKSUM_HW;
}
+ skge_rx_reuse(e, skge->rx_buf_size);
+ return nskb;
+ } else {
+ nskb = skge_rx_alloc(skge->netdev, skge->rx_buf_size);
+ if (unlikely(!nskb))
+ return NULL;
+
+ pci_unmap_single(skge->hw->pdev,
+ pci_unmap_addr(e, mapaddr),
+ pci_unmap_len(e, maplen),
+ PCI_DMA_FROMDEVICE);
+ skb = e->skb;
+ if (skge->rx_csum) {
+ struct skge_rx_desc *rd = e->desc;
+ skb->csum = le16_to_cpu(rd->csum2);
+ skb->ip_summed = CHECKSUM_HW;
+ }
+
+ skge_rx_setup(skge, e, nskb, skge->rx_buf_size);
+ return skb;
}
}
+
static int skge_poll(struct net_device *dev, int *budget)
{
struct skge_port *skge = netdev_priv(dev);
@@ -2575,13 +2539,12 @@ static int skge_poll(struct net_device *dev, int *budget)
struct skge_element *e;
unsigned int to_do = min(dev->quota, *budget);
unsigned int work_done = 0;
- int done;
- static const u32 irqmask[] = { IS_PORT_1, IS_PORT_2 };
- for (e = ring->to_clean; e != ring->to_use && work_done < to_do;
- e = e->next) {
+ pr_debug("skge_poll\n");
+
+ for (e = ring->to_clean; work_done < to_do; e = e->next) {
struct skge_rx_desc *rd = e->desc;
- struct sk_buff *skb = e->skb;
+ struct sk_buff *skb;
u32 control, len, status;
rmb();
@@ -2590,19 +2553,12 @@ static int skge_poll(struct net_device *dev, int *budget)
break;
len = control & BMU_BBC;
- e->skb = NULL;
-
- pci_unmap_single(hw->pdev,
- pci_unmap_addr(e, mapaddr),
- pci_unmap_len(e, maplen),
- PCI_DMA_FROMDEVICE);
-
status = rd->status;
- if ((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
- || len > dev->mtu + VLAN_ETH_HLEN
- || bad_phy_status(hw, status)) {
+
+ if (unlikely((control & (BMU_EOF|BMU_STF)) != (BMU_STF|BMU_EOF)
+ || bad_phy_status(hw, status))) {
skge_rx_error(skge, e - ring->start, control, status);
- dev_kfree_skb(skb);
+ skge_rx_reuse(e, skge->rx_buf_size);
continue;
}
@@ -2610,43 +2566,37 @@ static int skge_poll(struct net_device *dev, int *budget)
printk(KERN_DEBUG PFX "%s: rx slot %td status 0x%x len %d\n",
dev->name, e - ring->start, rd->status, len);
- skb_put(skb, len);
- skb->protocol = eth_type_trans(skb, dev);
-
- if (skge->rx_csum) {
- skb->csum = le16_to_cpu(rd->csum2);
- skb->ip_summed = CHECKSUM_HW;
- }
+ skb = skge_rx_get(skge, e, len);
+ if (likely(skb)) {
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, dev);
- dev->last_rx = jiffies;
- netif_receive_skb(skb);
+ dev->last_rx = jiffies;
+ netif_receive_skb(skb);
- ++work_done;
+ ++work_done;
+ } else
+ skge_rx_reuse(e, skge->rx_buf_size);
}
ring->to_clean = e;
- *budget -= work_done;
- dev->quota -= work_done;
- done = work_done < to_do;
-
- if (skge_rx_fill(skge))
- done = 0;
-
/* restart receiver */
wmb();
skge_write8(hw, Q_ADDR(rxqaddr[skge->port], Q_CSR),
CSR_START | CSR_IRQ_CL_F);
- if (done) {
- local_irq_disable();
- hw->intr_mask |= irqmask[skge->port];
- /* Order is important since data can get interrupted */
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_complete(dev);
- local_irq_enable();
- }
+ *budget -= work_done;
+ dev->quota -= work_done;
- return !done;
+ if (work_done >= to_do)
+ return 1; /* not done */
+
+ local_irq_disable();
+ __netif_rx_complete(dev);
+ hw->intr_mask |= portirqmask[skge->port];
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
+ local_irq_enable();
+ return 0;
}
static inline void skge_tx_intr(struct net_device *dev)
@@ -2657,7 +2607,7 @@ static inline void skge_tx_intr(struct net_device *dev)
struct skge_element *e;
spin_lock(&skge->tx_lock);
- for(e = ring->to_clean; e != ring->to_use; e = e->next) {
+ for (e = ring->to_clean; e != ring->to_use; e = e->next) {
struct skge_tx_desc *td = e->desc;
u32 control;
@@ -2690,12 +2640,12 @@ static void skge_mac_parity(struct skge_hw *hw, int port)
: (port == 0 ? "(port A)": "(port B"));
if (hw->chip_id == CHIP_ID_GENESIS)
- skge_write16(hw, SKGEMAC_REG(port, TX_MFF_CTRL1),
+ skge_write16(hw, SK_REG(port, TX_MFF_CTRL1),
MFF_CLR_PERR);
else
/* HW-Bug #8: cleared by GMF_CLI_TX_FC instead of GMF_CLI_TX_PE */
- skge_write8(hw, SKGEMAC_REG(port, TX_GMF_CTRL_T),
- (hw->chip_id == CHIP_ID_YUKON && chip_rev(hw) == 0)
+ skge_write8(hw, SK_REG(port, TX_GMF_CTRL_T),
+ (hw->chip_id == CHIP_ID_YUKON && hw->chip_rev == 0)
? GMF_CLI_TX_FC : GMF_CLI_TX_PE);
}
@@ -2703,16 +2653,16 @@ static void skge_pci_clear(struct skge_hw *hw)
{
u16 status;
- status = skge_read16(hw, SKGEPCI_REG(PCI_STATUS));
+ pci_read_config_word(hw->pdev, PCI_STATUS, &status);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_ON);
- skge_write16(hw, SKGEPCI_REG(PCI_STATUS),
- status | PCI_STATUS_ERROR_BITS);
+ pci_write_config_word(hw->pdev, PCI_STATUS,
+ status | PCI_STATUS_ERROR_BITS);
skge_write8(hw, B2_TST_CTRL1, TST_CFG_WRITE_OFF);
}
static void skge_mac_intr(struct skge_hw *hw, int port)
{
- if (hw->chip_id == CHIP_ID_GENESIS)
+ if (hw->chip_id == CHIP_ID_GENESIS)
genesis_mac_intr(hw, port);
else
yukon_mac_intr(hw, port);
@@ -2726,9 +2676,9 @@ static void skge_error_irq(struct skge_hw *hw)
if (hw->chip_id == CHIP_ID_GENESIS) {
/* clear xmac errors */
if (hwstatus & (IS_NO_STAT_M1|IS_NO_TIST_M1))
- skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL1), MFF_CLR_INSTAT);
if (hwstatus & (IS_NO_STAT_M2|IS_NO_TIST_M2))
- skge_write16(hw, SKGEMAC_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
+ skge_write16(hw, SK_REG(0, RX_MFF_CTRL2), MFF_CLR_INSTAT);
} else {
/* Timestamp (unused) overflow */
if (hwstatus & IS_IRQ_TIST_OV)
@@ -2803,8 +2753,8 @@ static void skge_extirq(unsigned long data)
if (hw->chip_id != CHIP_ID_GENESIS)
yukon_phy_intr(skge);
- else if (hw->phy_type == SK_PHY_BCOM)
- genesis_bcom_intr(skge);
+ else
+ bcom_phy_intr(skge);
}
}
spin_unlock(&hw->phy_lock);
@@ -2824,19 +2774,14 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
return IRQ_NONE;
status &= hw->intr_mask;
-
- if ((status & IS_R1_F) && netif_rx_schedule_prep(hw->dev[0])) {
- status &= ~IS_R1_F;
+ if (status & IS_R1_F) {
hw->intr_mask &= ~IS_R1_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[0]);
+ netif_rx_schedule(hw->dev[0]);
}
- if ((status & IS_R2_F) && netif_rx_schedule_prep(hw->dev[1])) {
- status &= ~IS_R2_F;
+ if (status & IS_R2_F) {
hw->intr_mask &= ~IS_R2_F;
- skge_write32(hw, B0_IMSK, hw->intr_mask);
- __netif_rx_schedule(hw->dev[1]);
+ netif_rx_schedule(hw->dev[1]);
}
if (status & IS_XA1_F)
@@ -2845,9 +2790,27 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
if (status & IS_XA2_F)
skge_tx_intr(hw->dev[1]);
+ if (status & IS_PA_TO_RX1) {
+ struct skge_port *skge = netdev_priv(hw->dev[0]);
+ ++skge->net_stats.rx_over_errors;
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX1);
+ }
+
+ if (status & IS_PA_TO_RX2) {
+ struct skge_port *skge = netdev_priv(hw->dev[1]);
+ ++skge->net_stats.rx_over_errors;
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_RX2);
+ }
+
+ if (status & IS_PA_TO_TX1)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX1);
+
+ if (status & IS_PA_TO_TX2)
+ skge_write16(hw, B3_PA_CTRL, PA_CLR_TO_TX2);
+
if (status & IS_MAC1)
skge_mac_intr(hw, 0);
-
+
if (status & IS_MAC2)
skge_mac_intr(hw, 1);
@@ -2859,8 +2822,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id, struct pt_regs *regs)
tasklet_schedule(&hw->ext_tasklet);
}
- if (status)
- skge_write32(hw, B0_IMSK, hw->intr_mask);
+ skge_write32(hw, B0_IMSK, hw->intr_mask);
return IRQ_HANDLED;
}
@@ -2904,9 +2866,6 @@ static const struct {
{ CHIP_ID_YUKON, "Yukon" },
{ CHIP_ID_YUKON_LITE, "Yukon-Lite"},
{ CHIP_ID_YUKON_LP, "Yukon-LP"},
- { CHIP_ID_YUKON_XL, "Yukon-2 XL"},
- { CHIP_ID_YUKON_EC, "YUKON-2 EC"},
- { CHIP_ID_YUKON_FE, "YUKON-2 FE"},
};
static const char *skge_board_name(const struct skge_hw *hw)
@@ -2930,8 +2889,8 @@ static const char *skge_board_name(const struct skge_hw *hw)
static int skge_reset(struct skge_hw *hw)
{
u16 ctst;
- u8 t8;
- int i, ports;
+ u8 t8, mac_cfg;
+ int i;
ctst = skge_read16(hw, B0_CTST);
@@ -2952,12 +2911,9 @@ static int skge_reset(struct skge_hw *hw)
hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
hw->pmd_type = skge_read8(hw, B2_PMD_TYP);
- switch(hw->chip_id) {
+ switch (hw->chip_id) {
case CHIP_ID_GENESIS:
switch (hw->phy_type) {
- case SK_PHY_XMAC:
- hw->phy_addr = PHY_ADDR_XMAC;
- break;
case SK_PHY_BCOM:
hw->phy_addr = PHY_ADDR_BCOM;
break;
@@ -2986,8 +2942,9 @@ static int skge_reset(struct skge_hw *hw)
return -EOPNOTSUPP;
}
- hw->mac_cfg = skge_read8(hw, B2_MAC_CFG);
- ports = isdualport(hw) ? 2 : 1;
+ mac_cfg = skge_read8(hw, B2_MAC_CFG);
+ hw->ports = (mac_cfg & CFG_SNG_MAC) ? 1 : 2;
+ hw->chip_rev = (mac_cfg & CFG_CHIP_R_MSK) >> 4;
/* read the adapters RAM size */
t8 = skge_read8(hw, B2_E_0);
@@ -3010,9 +2967,9 @@ static int skge_reset(struct skge_hw *hw)
/* switch power to VCC (WA for VAUX problem) */
skge_write8(hw, B0_POWER_CTRL,
PC_VAUX_ENA | PC_VCC_ENA | PC_VAUX_OFF | PC_VCC_ON);
- for (i = 0; i < ports; i++) {
- skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
- skge_write16(hw, SKGEMAC_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
+ for (i = 0; i < hw->ports; i++) {
+ skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_SET);
+ skge_write16(hw, SK_REG(i, GMAC_LINK_CTRL), GMLC_RST_CLR);
}
}
@@ -3022,8 +2979,8 @@ static int skge_reset(struct skge_hw *hw)
skge_write8(hw, B0_LED, LED_STAT_ON);
/* enable the Tx Arbiters */
- for (i = 0; i < ports; i++)
- skge_write8(hw, SKGEMAC_REG(i, TXA_CTRL), TXA_ENA_ARB);
+ for (i = 0; i < hw->ports; i++)
+ skge_write8(hw, SK_REG(i, TXA_CTRL), TXA_ENA_ARB);
/* Initialize ram interface */
skge_write16(hw, B3_RI_CTRL, RI_RST_CLR);
@@ -3050,16 +3007,14 @@ static int skge_reset(struct skge_hw *hw)
skge_write32(hw, B2_IRQM_INI, skge_usecs2clk(hw, 100));
skge_write32(hw, B2_IRQM_CTRL, TIM_START);
- hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
- if (isdualport(hw))
- hw->intr_mask |= IS_PORT_2;
+ hw->intr_mask = IS_HW_ERR | IS_EXT_REG;
skge_write32(hw, B0_IMSK, hw->intr_mask);
if (hw->chip_id != CHIP_ID_GENESIS)
skge_write8(hw, GMAC_IRQ_MSK, 0);
spin_lock_bh(&hw->phy_lock);
- for (i = 0; i < ports; i++) {
+ for (i = 0; i < hw->ports; i++) {
if (hw->chip_id == CHIP_ID_GENESIS)
genesis_reset(hw, i);
else
@@ -3071,7 +3026,8 @@ static int skge_reset(struct skge_hw *hw)
}
/* Initialize network device */
-static struct net_device *skge_devinit(struct skge_hw *hw, int port)
+static struct net_device *skge_devinit(struct skge_hw *hw, int port,
+ int highmem)
{
struct skge_port *skge;
struct net_device *dev = alloc_etherdev(sizeof(*skge));
@@ -3104,6 +3060,8 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
#endif
dev->irq = hw->pdev->irq;
dev->features = NETIF_F_LLTX;
+ if (highmem)
+ dev->features |= NETIF_F_HIGHDMA;
skge = netdev_priv(dev);
skge->netdev = dev;
@@ -3117,7 +3075,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
skge->flow_control = FLOW_MODE_SYMMETRIC;
skge->duplex = -1;
skge->speed = -1;
- skge->advertising = skge_modes(hw);
+ skge->advertising = skge_supported_modes(hw);
hw->dev[port] = dev;
@@ -3125,10 +3083,6 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port)
spin_lock_init(&skge->tx_lock);
- init_timer(&skge->link_check);
- skge->link_check.function = skge_link_timer;
- skge->link_check.data = (unsigned long) skge;
-
init_timer(&skge->led_blink);
skge->led_blink.function = skge_blink_timer;
skge->led_blink.data = (unsigned long) skge;
@@ -3232,14 +3186,11 @@ static int __devinit skge_probe(struct pci_dev *pdev,
printk(KERN_INFO PFX "addr 0x%lx irq %d chip %s rev %d\n",
pci_resource_start(pdev, 0), pdev->irq,
- skge_board_name(hw), chip_rev(hw));
+ skge_board_name(hw), hw->chip_rev);
- if ((dev = skge_devinit(hw, 0)) == NULL)
+ if ((dev = skge_devinit(hw, 0, using_dac)) == NULL)
goto err_out_led_off;
- if (using_dac)
- dev->features |= NETIF_F_HIGHDMA;
-
if ((err = register_netdev(dev))) {
printk(KERN_ERR PFX "%s: cannot register net device\n",
pci_name(pdev));
@@ -3248,10 +3199,7 @@ static int __devinit skge_probe(struct pci_dev *pdev,
skge_show_addr(dev);
- if (isdualport(hw) && (dev1 = skge_devinit(hw, 1))) {
- if (using_dac)
- dev1->features |= NETIF_F_HIGHDMA;
-
+ if (hw->ports > 1 && (dev1 = skge_devinit(hw, 1, using_dac))) {
if (register_netdev(dev1) == 0)
skge_show_addr(dev1);
else {
@@ -3288,7 +3236,7 @@ static void __devexit skge_remove(struct pci_dev *pdev)
struct skge_hw *hw = pci_get_drvdata(pdev);
struct net_device *dev0, *dev1;
- if(!hw)
+ if (!hw)
return;
if ((dev1 = hw->dev[1]))
@@ -3311,12 +3259,12 @@ static void __devexit skge_remove(struct pci_dev *pdev)
}
#ifdef CONFIG_PM
-static int skge_suspend(struct pci_dev *pdev, u32 state)
+static int skge_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct skge_hw *hw = pci_get_drvdata(pdev);
int i, wol = 0;
- for(i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
struct net_device *dev = hw->dev[i];
if (dev) {
@@ -3331,7 +3279,7 @@ static int skge_suspend(struct pci_dev *pdev, u32 state)
}
pci_save_state(pdev);
- pci_enable_wake(pdev, state, wol);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), wol);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
@@ -3349,11 +3297,11 @@ static int skge_resume(struct pci_dev *pdev)
skge_reset(hw);
- for(i = 0; i < 2; i++) {
+ for (i = 0; i < 2; i++) {
struct net_device *dev = hw->dev[i];
if (dev) {
netif_device_attach(dev);
- if(netif_running(dev))
+ if (netif_running(dev))
skge_up(dev);
}
}
diff --git a/drivers/net/skge.h b/drivers/net/skge.h
index 36c62b68fab4..fced3d2bc072 100644
--- a/drivers/net/skge.h
+++ b/drivers/net/skge.h
@@ -7,31 +7,7 @@
/* PCI config registers */
#define PCI_DEV_REG1 0x40
#define PCI_DEV_REG2 0x44
-#ifndef PCI_VPD
-#define PCI_VPD 0x50
-#endif
-
-/* PCI_OUR_REG_2 32 bit Our Register 2 */
-enum {
- PCI_VPD_WR_THR = 0xff<<24, /* Bit 31..24: VPD Write Threshold */
- PCI_DEV_SEL = 0x7f<<17, /* Bit 23..17: EEPROM Device Select */
- PCI_VPD_ROM_SZ = 7 <<14, /* Bit 16..14: VPD ROM Size */
- /* Bit 13..12: reserved */
- PCI_EN_DUMMY_RD = 1<<3, /* Enable Dummy Read */
- PCI_REV_DESC = 1<<2, /* Reverse Desc. Bytes */
- PCI_USEDATA64 = 1<<0, /* Use 64Bit Data bus ext */
-};
-
-/* PCI_VPD_ADR_REG 16 bit VPD Address Register */
-enum {
- PCI_VPD_FLAG = 1<<15, /* starts VPD rd/wr cycle */
- PCI_VPD_ADR_MSK =0x7fffL, /* Bit 14.. 0: VPD Address Mask */
- VPD_RES_ID = 0x82,
- VPD_RES_READ = 0x90,
- VPD_RES_WRITE = 0x81,
- VPD_RES_END = 0x78,
-};
-
+#define PCI_REV_DESC 0x4
#define PCI_STATUS_ERROR_BITS (PCI_STATUS_DETECTED_PARITY | \
PCI_STATUS_SIG_SYSTEM_ERROR | \
@@ -39,7 +15,6 @@ enum {
PCI_STATUS_REC_TARGET_ABORT | \
PCI_STATUS_PARITY)
-
enum csr_regs {
B0_RAP = 0x0000,
B0_CTST = 0x0004,
@@ -229,8 +204,11 @@ enum {
IS_XA2_F = 1<<1, /* Q_XA2 End of Frame */
IS_XA2_C = 1<<0, /* Q_XA2 Encoding Error */
- IS_PORT_1 = IS_XA1_F| IS_R1_F| IS_MAC1,
- IS_PORT_2 = IS_XA2_F| IS_R2_F| IS_MAC2,
+ IS_TO_PORT1 = IS_PA_TO_RX1 | IS_PA_TO_TX1,
+ IS_TO_PORT2 = IS_PA_TO_RX2 | IS_PA_TO_TX2,
+
+ IS_PORT_1 = IS_XA1_F| IS_R1_F | IS_TO_PORT1 | IS_MAC1,
+ IS_PORT_2 = IS_XA2_F| IS_R2_F | IS_TO_PORT2 | IS_MAC2,
};
@@ -288,14 +266,6 @@ enum {
CHIP_REV_YU_LITE_A3 = 7, /* Chip Rev. for YUKON-Lite A3 */
};
-/* B2_LD_TEST 8 bit EPROM loader test register */
-enum {
- LD_T_ON = 1<<3, /* Loader Test mode on */
- LD_T_OFF = 1<<2, /* Loader Test mode off */
- LD_T_STEP = 1<<1, /* Decrement FPROM addr. Counter */
- LD_START = 1<<0, /* Start loading FPROM */
-};
-
/* B2_TI_CTRL 8 bit Timer control */
/* B2_IRQM_CTRL 8 bit IRQ Moderation Timer Control */
enum {
@@ -313,16 +283,6 @@ enum {
TIM_T_STEP = 1<<0, /* Test step */
};
-/* B28_DPT_INI 32 bit Descriptor Poll Timer Init Val */
-/* B28_DPT_VAL 32 bit Descriptor Poll Timer Curr Val */
-/* B28_DPT_CTRL 8 bit Descriptor Poll Timer Ctrl Reg */
-enum {
- DPT_MSK = 0x00ffffffL, /* Bit 23.. 0: Desc Poll Timer Bits */
-
- DPT_START = 1<<1, /* Start Descriptor Poll Timer */
- DPT_STOP = 1<<0, /* Stop Descriptor Poll Timer */
-};
-
/* B2_GP_IO 32 bit General Purpose I/O Register */
enum {
GP_DIR_9 = 1<<25, /* IO_9 direct, 0=In/1=Out */
@@ -348,30 +308,6 @@ enum {
GP_IO_0 = 1<<0, /* IO_0 pin */
};
-/* Rx/Tx Path related Arbiter Test Registers */
-/* B3_MA_TO_TEST 16 bit MAC Arbiter Timeout Test Reg */
-/* B3_MA_RC_TEST 16 bit MAC Arbiter Recovery Test Reg */
-/* B3_PA_TEST 16 bit Packet Arbiter Test Register */
-/* Bit 15, 11, 7, and 3 are reserved in B3_PA_TEST */
-enum {
- TX2_T_EV = 1<<15,/* TX2 Timeout/Recv Event occured */
- TX2_T_ON = 1<<14,/* TX2 Timeout/Recv Timer Test On */
- TX2_T_OFF = 1<<13,/* TX2 Timeout/Recv Timer Tst Off */
- TX2_T_STEP = 1<<12,/* TX2 Timeout/Recv Timer Step */
- TX1_T_EV = 1<<11,/* TX1 Timeout/Recv Event occured */
- TX1_T_ON = 1<<10,/* TX1 Timeout/Recv Timer Test On */
- TX1_T_OFF = 1<<9, /* TX1 Timeout/Recv Timer Tst Off */
- TX1_T_STEP = 1<<8, /* TX1 Timeout/Recv Timer Step */
- RX2_T_EV = 1<<7, /* RX2 Timeout/Recv Event occured */
- RX2_T_ON = 1<<6, /* RX2 Timeout/Recv Timer Test On */
- RX2_T_OFF = 1<<5, /* RX2 Timeout/Recv Timer Tst Off */
- RX2_T_STEP = 1<<4, /* RX2 Timeout/Recv Timer Step */
- RX1_T_EV = 1<<3, /* RX1 Timeout/Recv Event occured */
- RX1_T_ON = 1<<2, /* RX1 Timeout/Recv Timer Test On */
- RX1_T_OFF = 1<<1, /* RX1 Timeout/Recv Timer Tst Off */
- RX1_T_STEP = 1<<0, /* RX1 Timeout/Recv Timer Step */
-};
-
/* Descriptor Bit Definition */
/* TxCtrl Transmit Buffer Control Field */
/* RxCtrl Receive Buffer Control Field */
@@ -428,14 +364,6 @@ enum {
RI_RST_SET = 1<<0, /* Set RAM Interface Reset */
};
-/* B3_RI_TEST 8 bit RAM Iface Test Register */
-enum {
- RI_T_EV = 1<<3, /* Timeout Event occured */
- RI_T_ON = 1<<2, /* Timeout Timer Test On */
- RI_T_OFF = 1<<1, /* Timeout Timer Test Off */
- RI_T_STEP = 1<<0, /* Timeout Timer Step */
-};
-
/* MAC Arbiter Registers */
/* B3_MA_TO_CTRL 16 bit MAC Arbiter Timeout Ctrl Reg */
enum {
@@ -452,19 +380,6 @@ enum {
#define SK_PKT_TO_MAX 0xffff /* Maximum value */
#define SK_RI_TO_53 36 /* RAM interface timeout */
-
-/* B3_MA_RC_CTRL 16 bit MAC Arbiter Recovery Ctrl Reg */
-enum {
- MA_ENA_REC_TX2 = 1<<7, /* Enable Recovery Timer TX2 */
- MA_DIS_REC_TX2 = 1<<6, /* Disable Recovery Timer TX2 */
- MA_ENA_REC_TX1 = 1<<5, /* Enable Recovery Timer TX1 */
- MA_DIS_REC_TX1 = 1<<4, /* Disable Recovery Timer TX1 */
- MA_ENA_REC_RX2 = 1<<3, /* Enable Recovery Timer RX2 */
- MA_DIS_REC_RX2 = 1<<2, /* Disable Recovery Timer RX2 */
- MA_ENA_REC_RX1 = 1<<1, /* Enable Recovery Timer RX1 */
- MA_DIS_REC_RX1 = 1<<0, /* Disable Recovery Timer RX1 */
-};
-
/* Packet Arbiter Registers */
/* B3_PA_CTRL 16 bit Packet Arbiter Ctrl Register */
enum {
@@ -488,7 +403,7 @@ enum {
PA_ENA_TO_TX1 | PA_ENA_TO_TX2)
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
/* TXA_ITI_INI 32 bit Tx Arb Interval Timer Init Val */
/* TXA_ITI_VAL 32 bit Tx Arb Interval Timer Value */
/* TXA_LIM_INI 32 bit Tx Arb Limit Counter Init Val */
@@ -511,7 +426,7 @@ enum {
/*
* Bank 4 - 5
*/
-/* Transmit Arbiter Registers MAC 1 and 2, use MR_ADDR() to access */
+/* Transmit Arbiter Registers MAC 1 and 2, use SK_REG() to access */
enum {
TXA_ITI_INI = 0x0200,/* 32 bit Tx Arb Interval Timer Init Val*/
TXA_ITI_VAL = 0x0204,/* 32 bit Tx Arb Interval Timer Value */
@@ -537,7 +452,7 @@ enum {
/* Queue Register Offsets, use Q_ADDR() to access */
enum {
- B8_Q_REGS = 0x0400, /* base of Queue registers */
+ B8_Q_REGS = 0x0400, /* base of Queue registers */
Q_D = 0x00, /* 8*32 bit Current Descriptor */
Q_DA_L = 0x20, /* 32 bit Current Descriptor Address Low dWord */
Q_DA_H = 0x24, /* 32 bit Current Descriptor Address High dWord */
@@ -618,8 +533,7 @@ enum {
enum {
PHY_ADDR_XMAC = 0<<8,
PHY_ADDR_BCOM = 1<<8,
- PHY_ADDR_LONE = 3<<8,
- PHY_ADDR_NAT = 0<<8,
+
/* GPHY address (bits 15..11 of SMI control reg) */
PHY_ADDR_MARV = 0,
};
@@ -986,7 +900,7 @@ enum {
LINKLED_BLINK_OFF = 0x10,
LINKLED_BLINK_ON = 0x20,
};
-
+
/* GMAC and GPHY Control Registers (YUKON only) */
enum {
GMAC_CTRL = 0x0f00,/* 32 bit GMAC Control Reg */
@@ -1151,54 +1065,6 @@ enum {
PHY_MARV_FE_SPEC_2 = 0x1c,/* 16 bit r/w Specific Control Reg. 2 */
};
-/* Level One-PHY Registers, indirect addressed over XMAC */
-enum {
- PHY_LONE_CTRL = 0x00,/* 16 bit r/w PHY Control Register */
- PHY_LONE_STAT = 0x01,/* 16 bit r/o PHY Status Register */
- PHY_LONE_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */
- PHY_LONE_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */
- PHY_LONE_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
- PHY_LONE_AUNE_LP = 0x05,/* 16 bit r/o Link Part Ability Reg */
- PHY_LONE_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_LONE_NEPG = 0x07,/* 16 bit r/w Next Page Register */
- PHY_LONE_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
- /* Level One-specific registers */
- PHY_LONE_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */
- PHY_LONE_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */
- PHY_LONE_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Reg */
- PHY_LONE_PORT_CFG = 0x10,/* 16 bit r/w Port Configuration Reg*/
- PHY_LONE_Q_STAT = 0x11,/* 16 bit r/o Quick Status Reg */
- PHY_LONE_INT_ENAB = 0x12,/* 16 bit r/w Interrupt Enable Reg */
- PHY_LONE_INT_STAT = 0x13,/* 16 bit r/o Interrupt Status Reg */
- PHY_LONE_LED_CFG = 0x14,/* 16 bit r/w LED Configuration Reg */
- PHY_LONE_PORT_CTRL = 0x15,/* 16 bit r/w Port Control Reg */
- PHY_LONE_CIM = 0x16,/* 16 bit r/o CIM Reg */
-};
-
-/* National-PHY Registers, indirect addressed over XMAC */
-enum {
- PHY_NAT_CTRL = 0x00,/* 16 bit r/w PHY Control Register */
- PHY_NAT_STAT = 0x01,/* 16 bit r/w PHY Status Register */
- PHY_NAT_ID0 = 0x02,/* 16 bit r/o PHY ID0 Register */
- PHY_NAT_ID1 = 0x03,/* 16 bit r/o PHY ID1 Register */
- PHY_NAT_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
- PHY_NAT_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Ability Reg */
- PHY_NAT_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
- PHY_NAT_NEPG = 0x07,/* 16 bit r/w Next Page Register */
- PHY_NAT_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner Reg */
- /* National-specific registers */
- PHY_NAT_1000T_CTRL = 0x09,/* 16 bit r/w 1000Base-T Control Reg */
- PHY_NAT_1000T_STAT = 0x0a,/* 16 bit r/o 1000Base-T Status Reg */
- PHY_NAT_EXT_STAT = 0x0f,/* 16 bit r/o Extended Status Register */
- PHY_NAT_EXT_CTRL1 = 0x10,/* 16 bit r/o Extended Control Reg1 */
- PHY_NAT_Q_STAT1 = 0x11,/* 16 bit r/o Quick Status Reg1 */
- PHY_NAT_10B_OP = 0x12,/* 16 bit r/o 10Base-T Operations Reg */
- PHY_NAT_EXT_CTRL2 = 0x13,/* 16 bit r/o Extended Control Reg1 */
- PHY_NAT_Q_STAT2 = 0x14,/* 16 bit r/o Quick Status Reg2 */
-
- PHY_NAT_PHY_ADDR = 0x19,/* 16 bit r/o PHY Address Register */
-};
-
enum {
PHY_CT_RESET = 1<<15, /* Bit 15: (sc) clear all PHY related regs */
PHY_CT_LOOP = 1<<14, /* Bit 14: enable Loopback over PHY */
@@ -1253,8 +1119,29 @@ enum {
PHY_MARV_ID1_Y2 = 0x0C91, /* Yukon-2 (PHY 88E1112) */
};
+/* Advertisement register bits */
enum {
PHY_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */
+ PHY_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */
+ PHY_AN_RF = 1<<13, /* Bit 13: Remote Fault Bits */
+
+ PHY_AN_PAUSE_ASYM = 1<<11,/* Bit 11: Try for asymmetric */
+ PHY_AN_PAUSE_CAP = 1<<10, /* Bit 10: Try for pause */
+ PHY_AN_100BASE4 = 1<<9, /* Bit 9: Try for 100mbps 4k packets */
+ PHY_AN_100FULL = 1<<8, /* Bit 8: Try for 100mbps full-duplex */
+ PHY_AN_100HALF = 1<<7, /* Bit 7: Try for 100mbps half-duplex */
+ PHY_AN_10FULL = 1<<6, /* Bit 6: Try for 10mbps full-duplex */
+ PHY_AN_10HALF = 1<<5, /* Bit 5: Try for 10mbps half-duplex */
+ PHY_AN_CSMA = 1<<0, /* Bit 0: Only selector supported */
+ PHY_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
+ PHY_AN_FULL = PHY_AN_100FULL | PHY_AN_10FULL | PHY_AN_CSMA,
+ PHY_AN_ALL = PHY_AN_10HALF | PHY_AN_10FULL |
+ PHY_AN_100HALF | PHY_AN_100FULL,
+};
+
+/* Xmac Specific */
+enum {
+ PHY_X_AN_NXT_PG = 1<<15, /* Bit 15: Request Next Page */
PHY_X_AN_ACK = 1<<14, /* Bit 14: (ro) Acknowledge Received */
PHY_X_AN_RFB = 3<<12,/* Bit 13..12: Remote Fault Bits */
@@ -1263,82 +1150,6 @@ enum {
PHY_X_AN_FD = 1<<5, /* Bit 5: Full Duplex */
};
-enum {
- PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */
-
- PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
- PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */
- PHY_B_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-enum {
- PHY_L_AN_RF = 1<<13, /* Bit 13: Remote Fault */
- /* Bit 12: reserved */
- PHY_L_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
- PHY_L_AN_PC = 1<<10, /* Bit 10: Pause Capable */
-
- PHY_L_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-/* PHY_NAT_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement */
-/* PHY_NAT_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
-/* PHY_AN_NXT_PG (see XMAC) Bit 15: Request Next Page */
-enum {
- PHY_N_AN_RF = 1<<13, /* Bit 13: Remote Fault */
-
- PHY_N_AN_100F = 1<<11, /* Bit 11: 100Base-T2 FD Support */
- PHY_N_AN_100H = 1<<10, /* Bit 10: 100Base-T2 HD Support */
-
- PHY_N_AN_SEL = 0x1f, /* Bit 4..0: Selector Field, 00001=Ethernet*/
-};
-
-/* field type definition for PHY_x_AN_SEL */
-enum {
- PHY_SEL_TYPE = 1, /* 00001 = Ethernet */
-};
-
-enum {
- PHY_ANE_LP_NP = 1<<3, /* Bit 3: Link Partner can Next Page */
- PHY_ANE_LOC_NP = 1<<2, /* Bit 2: Local PHY can Next Page */
- PHY_ANE_RX_PG = 1<<1, /* Bit 1: Page Received */
-};
-
-enum {
- PHY_ANE_PAR_DF = 1<<4, /* Bit 4: Parallel Detection Fault */
-
- PHY_ANE_LP_CAP = 1<<0, /* Bit 0: Link Partner Auto-Neg. Cap. */
-};
-
-enum {
- PHY_NP_MORE = 1<<15, /* Bit 15: More, Next Pages to follow */
- PHY_NP_ACK1 = 1<<14, /* Bit 14: (ro) Ack1, for receiving a message */
- PHY_NP_MSG_VAL = 1<<13, /* Bit 13: Message Page valid */
- PHY_NP_ACK2 = 1<<12, /* Bit 12: Ack2, comply with msg content */
- PHY_NP_TOG = 1<<11, /* Bit 11: Toggle Bit, ensure sync */
- PHY_NP_MSG = 0x07ff, /* Bit 10..0: Message from/to Link Partner */
-};
-
-enum {
- PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
- PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
-};
-
-enum {
- PHY_X_RS_PAUSE = 3<<7,/* Bit 8..7: selected Pause Mode */
- PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
- PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
- PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
- PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
-};
-
-/** Remote Fault Bits (PHY_X_AN_RFB) encoding */
-enum {
- X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
- X_RFB_LF = 1<<12, /* Bit 13..12 Link Failure */
- X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
- X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
-};
-
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
enum {
PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
@@ -1418,6 +1229,16 @@ enum {
PHY_B_PES_MLT3_ER = 1<<0, /* Bit 0: MLT3 code Error */
};
+/* PHY_BCOM_AUNE_ADV 16 bit r/w Auto-Negotiation Advertisement *****/
+/* PHY_BCOM_AUNE_LP 16 bit r/o Link Partner Ability Reg *****/
+enum {
+ PHY_B_AN_RF = 1<<13, /* Bit 13: Remote Fault */
+
+ PHY_B_AN_ASP = 1<<11, /* Bit 11: Asymmetric Pause */
+ PHY_B_AN_PC = 1<<10, /* Bit 10: Pause Capable */
+};
+
+
/***** PHY_BCOM_FC_CTR 16 bit r/w False Carrier Counter *****/
enum {
PHY_B_FC_CTR = 0xff, /* Bit 7..0: False Carrier Counter */
@@ -1478,7 +1299,9 @@ enum {
PHY_B_IS_LST_CHANGE = 1<<1, /* Bit 1: Link Status Changed */
PHY_B_IS_CRC_ER = 1<<0, /* Bit 0: CRC Error */
};
-#define PHY_B_DEF_MSK (~(PHY_B_IS_AN_PR | PHY_B_IS_LST_CHANGE))
+#define PHY_B_DEF_MSK \
+ (~(PHY_B_IS_PSE | PHY_B_IS_AN_PR | PHY_B_IS_DUP_CHANGE | \
+ PHY_B_IS_LSP_CHANGE | PHY_B_IS_LST_CHANGE))
/* Pause Bits (PHY_B_AN_ASP and PHY_B_AN_PC) encoding */
enum {
@@ -1495,166 +1318,6 @@ enum {
PHY_B_RES_1000HD = 6<<8,/* Bit 10..8: 1000Base-T Half Dup. */
};
-/*
- * Level One-Specific
- */
-/***** PHY_LONE_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
-enum {
- PHY_L_1000C_TEST = 7<<13,/* Bit 15..13: Test Modes */
- PHY_L_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */
- PHY_L_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */
- PHY_L_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */
- PHY_L_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */
- PHY_L_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */
-};
-
-/***** PHY_LONE_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
-enum {
- PHY_L_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */
- PHY_L_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */
- PHY_L_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */
- PHY_L_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status */
- PHY_L_1000S_LP_FD = 1<<11, /* Bit 11: Link Partner can FD */
- PHY_L_1000S_LP_HD = 1<<10, /* Bit 10: Link Partner can HD */
-
- PHY_L_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */
-
-/***** PHY_LONE_EXT_STAT 16 bit r/o Extended Status Register *****/
- PHY_L_ES_X_FD_CAP = 1<<15, /* Bit 15: 1000Base-X FD capable */
- PHY_L_ES_X_HD_CAP = 1<<14, /* Bit 14: 1000Base-X HD capable */
- PHY_L_ES_T_FD_CAP = 1<<13, /* Bit 13: 1000Base-T FD capable */
- PHY_L_ES_T_HD_CAP = 1<<12, /* Bit 12: 1000Base-T HD capable */
-};
-
-/***** PHY_LONE_PORT_CFG 16 bit r/w Port Configuration Reg *****/
-enum {
- PHY_L_PC_REP_MODE = 1<<15, /* Bit 15: Repeater Mode */
-
- PHY_L_PC_TX_DIS = 1<<13, /* Bit 13: Tx output Disabled */
- PHY_L_PC_BY_SCR = 1<<12, /* Bit 12: Bypass Scrambler */
- PHY_L_PC_BY_45 = 1<<11, /* Bit 11: Bypass 4B5B-Decoder */
- PHY_L_PC_JAB_DIS = 1<<10, /* Bit 10: Jabber Disabled */
- PHY_L_PC_SQE = 1<<9, /* Bit 9: Enable Heartbeat */
- PHY_L_PC_TP_LOOP = 1<<8, /* Bit 8: TP Loopback */
- PHY_L_PC_SSS = 1<<7, /* Bit 7: Smart Speed Selection */
- PHY_L_PC_FIFO_SIZE = 1<<6, /* Bit 6: FIFO Size */
- PHY_L_PC_PRE_EN = 1<<5, /* Bit 5: Preamble Enable */
- PHY_L_PC_CIM = 1<<4, /* Bit 4: Carrier Integrity Mon */
- PHY_L_PC_10_SER = 1<<3, /* Bit 3: Use Serial Output */
- PHY_L_PC_ANISOL = 1<<2, /* Bit 2: Unisolate Port */
- PHY_L_PC_TEN_BIT = 1<<1, /* Bit 1: 10bit iface mode on */
- PHY_L_PC_ALTCLOCK = 1<<0, /* Bit 0: (ro) ALTCLOCK Mode on */
-};
-
-/***** PHY_LONE_Q_STAT 16 bit r/o Quick Status Reg *****/
-enum {
- PHY_L_QS_D_RATE = 3<<14,/* Bit 15..14: Data Rate */
- PHY_L_QS_TX_STAT = 1<<13, /* Bit 13: Transmitting */
- PHY_L_QS_RX_STAT = 1<<12, /* Bit 12: Receiving */
- PHY_L_QS_COL_STAT = 1<<11, /* Bit 11: Collision */
- PHY_L_QS_L_STAT = 1<<10, /* Bit 10: Link is up */
- PHY_L_QS_DUP_MOD = 1<<9, /* Bit 9: Full/Half Duplex */
- PHY_L_QS_AN = 1<<8, /* Bit 8: AutoNeg is On */
- PHY_L_QS_AN_C = 1<<7, /* Bit 7: AN is Complete */
- PHY_L_QS_LLE = 7<<4,/* Bit 6..4: Line Length Estim. */
- PHY_L_QS_PAUSE = 1<<3, /* Bit 3: LP advertised Pause */
- PHY_L_QS_AS_PAUSE = 1<<2, /* Bit 2: LP adv. asym. Pause */
- PHY_L_QS_ISOLATE = 1<<1, /* Bit 1: CIM Isolated */
- PHY_L_QS_EVENT = 1<<0, /* Bit 0: Event has occurred */
-};
-
-/***** PHY_LONE_INT_ENAB 16 bit r/w Interrupt Enable Reg *****/
-/***** PHY_LONE_INT_STAT 16 bit r/o Interrupt Status Reg *****/
-enum {
- PHY_L_IS_AN_F = 1<<13, /* Bit 13: Auto-Negotiation fault */
- PHY_L_IS_CROSS = 1<<11, /* Bit 11: Crossover used */
- PHY_L_IS_POL = 1<<10, /* Bit 10: Polarity correct. used */
- PHY_L_IS_SS = 1<<9, /* Bit 9: Smart Speed Downgrade */
- PHY_L_IS_CFULL = 1<<8, /* Bit 8: Counter Full */
- PHY_L_IS_AN_C = 1<<7, /* Bit 7: AutoNeg Complete */
- PHY_L_IS_SPEED = 1<<6, /* Bit 6: Speed Changed */
- PHY_L_IS_DUP = 1<<5, /* Bit 5: Duplex Changed */
- PHY_L_IS_LS = 1<<4, /* Bit 4: Link Status Changed */
- PHY_L_IS_ISOL = 1<<3, /* Bit 3: Isolate Occured */
- PHY_L_IS_MDINT = 1<<2, /* Bit 2: (ro) STAT: MII Int Pending */
- PHY_L_IS_INTEN = 1<<1, /* Bit 1: ENAB: Enable IRQs */
- PHY_L_IS_FORCE = 1<<0, /* Bit 0: ENAB: Force Interrupt */
-};
-
-/* int. mask */
-#define PHY_L_DEF_MSK (PHY_L_IS_LS | PHY_L_IS_ISOL | PHY_L_IS_INTEN)
-
-/***** PHY_LONE_LED_CFG 16 bit r/w LED Configuration Reg *****/
-enum {
- PHY_L_LC_LEDC = 3<<14,/* Bit 15..14: Col/Blink/On/Off */
- PHY_L_LC_LEDR = 3<<12,/* Bit 13..12: Rx/Blink/On/Off */
- PHY_L_LC_LEDT = 3<<10,/* Bit 11..10: Tx/Blink/On/Off */
- PHY_L_LC_LEDG = 3<<8,/* Bit 9..8: Giga/Blink/On/Off */
- PHY_L_LC_LEDS = 3<<6,/* Bit 7..6: 10-100/Blink/On/Off */
- PHY_L_LC_LEDL = 3<<4,/* Bit 5..4: Link/Blink/On/Off */
- PHY_L_LC_LEDF = 3<<2,/* Bit 3..2: Duplex/Blink/On/Off */
- PHY_L_LC_PSTRECH= 1<<1, /* Bit 1: Strech LED Pulses */
- PHY_L_LC_FREQ = 1<<0, /* Bit 0: 30/100 ms */
-};
-
-/***** PHY_LONE_PORT_CTRL 16 bit r/w Port Control Reg *****/
-enum {
- PHY_L_PC_TX_TCLK = 1<<15, /* Bit 15: Enable TX_TCLK */
- PHY_L_PC_ALT_NP = 1<<13, /* Bit 14: Alternate Next Page */
- PHY_L_PC_GMII_ALT= 1<<12, /* Bit 13: Alternate GMII driver */
- PHY_L_PC_TEN_CRS = 1<<10, /* Bit 10: Extend CRS*/
-};
-
-/***** PHY_LONE_CIM 16 bit r/o CIM Reg *****/
-enum {
- PHY_L_CIM_ISOL = 0xff<<8,/* Bit 15..8: Isolate Count */
- PHY_L_CIM_FALSE_CAR = 0xff, /* Bit 7..0: False Carrier Count */
-};
-
-/*
- * Pause Bits (PHY_L_AN_ASP and PHY_L_AN_PC) encoding
- */
-enum {
- PHY_L_P_NO_PAUSE= 0<<10,/* Bit 11..10: no Pause Mode */
- PHY_L_P_SYM_MD = 1<<10, /* Bit 11..10: symmetric Pause Mode */
- PHY_L_P_ASYM_MD = 2<<10,/* Bit 11..10: asymmetric Pause Mode */
- PHY_L_P_BOTH_MD = 3<<10,/* Bit 11..10: both Pause Mode */
-};
-
-/*
- * National-Specific
- */
-/***** PHY_NAT_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
-enum {
- PHY_N_1000C_TEST= 7<<13,/* Bit 15..13: Test Modes */
- PHY_N_1000C_MSE = 1<<12, /* Bit 12: Master/Slave Enable */
- PHY_N_1000C_MSC = 1<<11, /* Bit 11: M/S Configuration */
- PHY_N_1000C_RD = 1<<10, /* Bit 10: Repeater/DTE */
- PHY_N_1000C_AFD = 1<<9, /* Bit 9: Advertise Full Duplex */
- PHY_N_1000C_AHD = 1<<8, /* Bit 8: Advertise Half Duplex */
- PHY_N_1000C_APC = 1<<7, /* Bit 7: Asymmetric Pause Cap. */};
-
-
-/***** PHY_NAT_1000T_STAT 16 bit r/o 1000Base-T Status Reg *****/
-enum {
- PHY_N_1000S_MSF = 1<<15, /* Bit 15: Master/Slave Fault */
- PHY_N_1000S_MSR = 1<<14, /* Bit 14: Master/Slave Result */
- PHY_N_1000S_LRS = 1<<13, /* Bit 13: Local Receiver Status */
- PHY_N_1000S_RRS = 1<<12, /* Bit 12: Remote Receiver Status*/
- PHY_N_1000S_LP_FD= 1<<11, /* Bit 11: Link Partner can FD */
- PHY_N_1000S_LP_HD= 1<<10, /* Bit 10: Link Partner can HD */
- PHY_N_1000C_LP_APC= 1<<9, /* Bit 9: LP Asym. Pause Cap. */
- PHY_N_1000S_IEC = 0xff, /* Bit 7..0: Idle Error Count */
-};
-
-/***** PHY_NAT_EXT_STAT 16 bit r/o Extended Status Register *****/
-enum {
- PHY_N_ES_X_FD_CAP= 1<<15, /* Bit 15: 1000Base-X FD capable */
- PHY_N_ES_X_HD_CAP= 1<<14, /* Bit 14: 1000Base-X HD capable */
- PHY_N_ES_T_FD_CAP= 1<<13, /* Bit 13: 1000Base-T FD capable */
- PHY_N_ES_T_HD_CAP= 1<<12, /* Bit 12: 1000Base-T HD capable */
-};
-
/** Marvell-Specific */
enum {
PHY_M_AN_NXT_PG = 1<<15, /* Request Next Page */
@@ -1718,7 +1381,7 @@ enum {
PHY_M_PC_EN_DET_PLUS = 3<<8, /* Energy Detect Plus (Mode 2) */
};
-#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK)
+#define PHY_M_PC_MDI_XMODE(x) (((x)<<5) & PHY_M_PC_MDIX_MSK)
enum {
PHY_M_PC_MAN_MDI = 0, /* 00 = Manual MDI configuration */
@@ -2105,7 +1768,7 @@ enum {
GM_GPSR_FC_RX_DIS = 1<<2, /* Bit 2: Rx Flow-Control Mode Disabled */
GM_GPSR_PROM_EN = 1<<1, /* Bit 1: Promiscuous Mode Enabled */
};
-
+
/* GM_GP_CTRL 16 bit r/w General Purpose Control Register */
enum {
GM_GPCR_PROM_ENA = 1<<14, /* Bit 14: Enable Promiscuous Mode */
@@ -2127,7 +1790,7 @@ enum {
#define GM_GPCR_SPEED_1000 (GM_GPCR_GIGS_ENA | GM_GPCR_SPEED_100)
#define GM_GPCR_AU_ALL_DIS (GM_GPCR_AU_DUP_DIS | GM_GPCR_AU_FCT_DIS|GM_GPCR_AU_SPD_DIS)
-
+
/* GM_TX_CTRL 16 bit r/w Transmit Control Register */
enum {
GM_TXCR_FORCE_JAM = 1<<15, /* Bit 15: Force Jam / Flow-Control */
@@ -2138,7 +1801,7 @@ enum {
#define TX_COL_THR(x) (((x)<<10) & GM_TXCR_COL_THR_MSK)
#define TX_COL_DEF 0x04
-
+
/* GM_RX_CTRL 16 bit r/w Receive Control Register */
enum {
GM_RXCR_UCF_ENA = 1<<15, /* Bit 15: Enable Unicast filtering */
@@ -2146,7 +1809,7 @@ enum {
GM_RXCR_CRC_DIS = 1<<13, /* Bit 13: Remove 4-byte CRC */
GM_RXCR_PASS_FC = 1<<12, /* Bit 12: Pass FC packets to FIFO */
};
-
+
/* GM_TX_PARAM 16 bit r/w Transmit Parameter Register */
enum {
GM_TXPA_JAMLEN_MSK = 0x03<<14, /* Bit 15..14: Jam Length */
@@ -2171,7 +1834,7 @@ enum {
GM_SMOD_JUMBO_ENA = 1<<8, /* Bit 8: Enable Jumbo (Max. Frame Len) */
GM_SMOD_IPG_MSK = 0x1f /* Bit 4..0: Inter-Packet Gap (IPG) */
};
-
+
#define DATA_BLIND_VAL(x) (((x)<<11) & GM_SMOD_DATABL_MSK)
#define DATA_BLIND_DEF 0x04
@@ -2186,7 +1849,7 @@ enum {
GM_SMI_CT_RD_VAL = 1<<4, /* Bit 4: Read Valid (Read completed) */
GM_SMI_CT_BUSY = 1<<3, /* Bit 3: Busy (Operation in progress) */
};
-
+
#define GM_SMI_CT_PHY_AD(x) (((x)<<11) & GM_SMI_CT_PHY_A_MSK)
#define GM_SMI_CT_REG_AD(x) (((x)<<6) & GM_SMI_CT_REG_A_MSK)
@@ -2195,7 +1858,7 @@ enum {
GM_PAR_MIB_CLR = 1<<5, /* Bit 5: Set MIB Clear Counter Mode */
GM_PAR_MIB_TST = 1<<4, /* Bit 4: MIB Load Counter (Test Mode) */
};
-
+
/* Receive Frame Status Encoding */
enum {
GMR_FS_LEN = 0xffff<<16, /* Bit 31..16: Rx Frame Length */
@@ -2217,12 +1880,12 @@ enum {
/*
* GMR_FS_ANY_ERR (analogous to XMR_FS_ANY_ERR)
*/
- GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
- GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
+ GMR_FS_ANY_ERR = GMR_FS_CRC_ERR | GMR_FS_LONG_ERR |
+ GMR_FS_MII_ERR | GMR_FS_BAD_FC | GMR_FS_GOOD_FC |
GMR_FS_JABBER,
/* Rx GMAC FIFO Flush Mask (default) */
RX_FF_FL_DEF_MSK = GMR_FS_CRC_ERR | GMR_FS_RX_FF_OV |GMR_FS_MII_ERR |
- GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
+ GMR_FS_BAD_FC | GMR_FS_GOOD_FC | GMR_FS_UN_SIZE |
GMR_FS_JABBER,
};
@@ -2540,10 +2203,6 @@ enum {
};
-/* XM_PHY_ADDR 16 bit r/w PHY Address Register */
-#define XM_PHY_ADDR_SZ 0x1f /* Bit 4..0: PHY Address bits */
-
-
/* XM_GP_PORT 32 bit r/w General Purpose Port Register */
enum {
XM_GP_ANIP = 1<<6, /* Bit 6: (ro) Auto-Neg. in progress */
@@ -2662,8 +2321,8 @@ enum {
};
#define XM_PAUSE_MODE (XM_MD_SPOE_E | XM_MD_SPOL_I | XM_MD_SPOH_I)
-#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
- XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA | XM_MD_CAA)
+#define XM_DEF_MODE (XM_MD_RX_RUNT | XM_MD_RX_IRLE | XM_MD_RX_LONG |\
+ XM_MD_RX_CRCE | XM_MD_RX_ERR | XM_MD_CSA)
/* XM_STAT_CMD 16 bit r/w Statistics Command Register */
enum {
@@ -2793,28 +2452,20 @@ struct skge_hw {
u32 intr_mask;
struct net_device *dev[2];
- u8 mac_cfg;
u8 chip_id;
+ u8 chip_rev;
u8 phy_type;
u8 pmd_type;
u16 phy_addr;
+ u8 ports;
u32 ram_size;
u32 ram_offset;
-
+
struct tasklet_struct ext_tasklet;
spinlock_t phy_lock;
};
-static inline int isdualport(const struct skge_hw *hw)
-{
- return !(hw->mac_cfg & CFG_SNG_MAC);
-}
-
-static inline u8 chip_rev(const struct skge_hw *hw)
-{
- return (hw->mac_cfg & CFG_CHIP_R_MSK) >> 4;
-}
static inline int iscopper(const struct skge_hw *hw)
{
@@ -2827,7 +2478,7 @@ enum {
FLOW_MODE_REM_SEND = 2, /* Symmetric or just remote */
FLOW_MODE_SYMMETRIC = 3, /* Both stations may send PAUSE */
};
-
+
struct skge_port {
u32 msg_enable;
struct skge_hw *hw;
@@ -2853,8 +2504,8 @@ struct skge_port {
void *mem; /* PCI memory for rings */
dma_addr_t dma;
unsigned long mem_size;
+ unsigned int rx_buf_size;
- struct timer_list link_check;
struct timer_list led_blink;
};
@@ -2863,7 +2514,6 @@ struct skge_port {
static inline u32 skge_read32(const struct skge_hw *hw, int reg)
{
return readl(hw->regs + reg);
-
}
static inline u16 skge_read16(const struct skge_hw *hw, int reg)
@@ -2892,114 +2542,87 @@ static inline void skge_write8(const struct skge_hw *hw, int reg, u8 val)
}
/* MAC Related Registers inside the device. */
-#define SKGEMAC_REG(port,reg) (((port)<<7)+(reg))
-
-/* PCI config space can be accessed via memory mapped space */
-#define SKGEPCI_REG(reg) ((reg)+ 0x380)
-
-#define SKGEXM_REG(port, reg) \
+#define SK_REG(port,reg) (((port)<<7)+(reg))
+#define SK_XMAC_REG(port, reg) \
((BASE_XMAC_1 + (port) * (BASE_XMAC_2 - BASE_XMAC_1)) | (reg) << 1)
-static inline u32 skge_xm_read32(const struct skge_hw *hw, int port, int reg)
-{
- return skge_read32(hw, SKGEXM_REG(port,reg));
-}
-
-static inline u16 skge_xm_read16(const struct skge_hw *hw, int port, int reg)
+static inline u32 xm_read32(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEXM_REG(port,reg));
+ u32 v;
+ v = skge_read16(hw, SK_XMAC_REG(port, reg));
+ v |= (u32)skge_read16(hw, SK_XMAC_REG(port, reg+2)) << 16;
+ return v;
}
-static inline u8 skge_xm_read8(const struct skge_hw *hw, int port, int reg)
+static inline u16 xm_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read8(hw, SKGEXM_REG(port,reg));
+ return skge_read16(hw, SK_XMAC_REG(port,reg));
}
-static inline void skge_xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void xm_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write32(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v & 0xffff);
+ skge_write16(hw, SK_XMAC_REG(port,r+2), v >> 16);
}
-static inline void skge_xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void xm_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- skge_write16(hw, SKGEXM_REG(port,r), v);
+ skge_write16(hw, SK_XMAC_REG(port,r), v);
}
-static inline void skge_xm_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
- skge_write8(hw, SKGEXM_REG(port,r), v);
-}
-
-static inline void skge_xm_outhash(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outhash(const struct skge_hw *hw, int port, int reg,
const u8 *hash)
{
- skge_xm_write16(hw, port, reg,
- (u16)hash[0] | ((u16)hash[1] << 8));
- skge_xm_write16(hw, port, reg+2,
- (u16)hash[2] | ((u16)hash[3] << 8));
- skge_xm_write16(hw, port, reg+4,
- (u16)hash[4] | ((u16)hash[5] << 8));
- skge_xm_write16(hw, port, reg+6,
- (u16)hash[6] | ((u16)hash[7] << 8));
+ xm_write16(hw, port, reg, (u16)hash[0] | ((u16)hash[1] << 8));
+ xm_write16(hw, port, reg+2, (u16)hash[2] | ((u16)hash[3] << 8));
+ xm_write16(hw, port, reg+4, (u16)hash[4] | ((u16)hash[5] << 8));
+ xm_write16(hw, port, reg+6, (u16)hash[6] | ((u16)hash[7] << 8));
}
-static inline void skge_xm_outaddr(const struct skge_hw *hw, int port, int reg,
+static inline void xm_outaddr(const struct skge_hw *hw, int port, int reg,
const u8 *addr)
{
- skge_xm_write16(hw, port, reg,
- (u16)addr[0] | ((u16)addr[1] << 8));
- skge_xm_write16(hw, port, reg,
- (u16)addr[2] | ((u16)addr[3] << 8));
- skge_xm_write16(hw, port, reg,
- (u16)addr[4] | ((u16)addr[5] << 8));
+ xm_write16(hw, port, reg, (u16)addr[0] | ((u16)addr[1] << 8));
+ xm_write16(hw, port, reg+2, (u16)addr[2] | ((u16)addr[3] << 8));
+ xm_write16(hw, port, reg+4, (u16)addr[4] | ((u16)addr[5] << 8));
}
+#define SK_GMAC_REG(port,reg) \
+ (BASE_GMAC_1 + (port) * (BASE_GMAC_2-BASE_GMAC_1) + (reg))
-#define SKGEGMA_REG(port,reg) \
- ((reg) + BASE_GMAC_1 + \
- (port) * (BASE_GMAC_2-BASE_GMAC_1))
-
-static inline u16 skge_gma_read16(const struct skge_hw *hw, int port, int reg)
+static inline u16 gma_read16(const struct skge_hw *hw, int port, int reg)
{
- return skge_read16(hw, SKGEGMA_REG(port,reg));
+ return skge_read16(hw, SK_GMAC_REG(port,reg));
}
-static inline u32 skge_gma_read32(const struct skge_hw *hw, int port, int reg)
+static inline u32 gma_read32(const struct skge_hw *hw, int port, int reg)
{
- return (u32) skge_read16(hw, SKGEGMA_REG(port,reg))
- | ((u32)skge_read16(hw, SKGEGMA_REG(port,reg+4)) << 16);
+ return (u32) skge_read16(hw, SK_GMAC_REG(port,reg))
+ | ((u32)skge_read16(hw, SK_GMAC_REG(port,reg+4)) << 16);
}
-static inline u8 skge_gma_read8(const struct skge_hw *hw, int port, int reg)
+static inline void gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
{
- return skge_read8(hw, SKGEGMA_REG(port,reg));
+ skge_write16(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write16(const struct skge_hw *hw, int port, int r, u16 v)
+static inline void gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
{
- skge_write16(hw, SKGEGMA_REG(port,r), v);
+ skge_write16(hw, SK_GMAC_REG(port, r), (u16) v);
+ skge_write32(hw, SK_GMAC_REG(port, r+4), (u16)(v >> 16));
}
-static inline void skge_gma_write32(const struct skge_hw *hw, int port, int r, u32 v)
+static inline void gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
{
- skge_write16(hw, SKGEGMA_REG(port, r), (u16) v);
- skge_write32(hw, SKGEGMA_REG(port, r+4), (u16)(v >> 16));
+ skge_write8(hw, SK_GMAC_REG(port,r), v);
}
-static inline void skge_gma_write8(const struct skge_hw *hw, int port, int r, u8 v)
-{
- skge_write8(hw, SKGEGMA_REG(port,r), v);
-}
-
-static inline void skge_gm_set_addr(struct skge_hw *hw, int port, int reg,
+static inline void gma_set_addr(struct skge_hw *hw, int port, int reg,
const u8 *addr)
{
- skge_gma_write16(hw, port, reg,
- (u16) addr[0] | ((u16) addr[1] << 8));
- skge_gma_write16(hw, port, reg+4,
- (u16) addr[2] | ((u16) addr[3] << 8));
- skge_gma_write16(hw, port, reg+8,
- (u16) addr[4] | ((u16) addr[5] << 8));
+ gma_write16(hw, port, reg, (u16) addr[0] | ((u16) addr[1] << 8));
+ gma_write16(hw, port, reg+4,(u16) addr[2] | ((u16) addr[3] << 8));
+ gma_write16(hw, port, reg+8,(u16) addr[4] | ((u16) addr[5] << 8));
}
-
+
#endif
diff --git a/drivers/net/slip.c b/drivers/net/slip.c
index 19112712daf0..404ea4297e32 100644
--- a/drivers/net/slip.c
+++ b/drivers/net/slip.c
@@ -74,6 +74,7 @@
#include <linux/rtnetlink.h>
#include <linux/if_arp.h>
#include <linux/if_slip.h>
+#include <linux/delay.h>
#include <linux/init.h>
#include "slip.h"
#ifdef CONFIG_INET
@@ -198,18 +199,12 @@ err_exit:
static void
sl_free_bufs(struct slip *sl)
{
- void * tmp;
-
/* Free all SLIP frame buffers. */
- tmp = xchg(&sl->rbuff, NULL);
- kfree(tmp);
- tmp = xchg(&sl->xbuff, NULL);
- kfree(tmp);
+ kfree(xchg(&sl->rbuff, NULL));
+ kfree(xchg(&sl->xbuff, NULL));
#ifdef SL_INCLUDE_CSLIP
- tmp = xchg(&sl->cbuff, NULL);
- kfree(tmp);
- if ((tmp = xchg(&sl->slcomp, NULL)) != NULL)
- slhc_free(tmp);
+ kfree(xchg(&sl->cbuff, NULL));
+ slhc_free(xchg(&sl->slcomp, NULL));
#endif
}
@@ -1389,10 +1384,8 @@ static void __exit slip_exit(void)
/* First of all: check for active disciplines and hangup them.
*/
do {
- if (busy) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 10);
- }
+ if (busy)
+ msleep_interruptible(100);
busy = 0;
for (i = 0; i < slip_maxdev; i++) {
diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
index 990201f42ba0..f00c476064f0 100644
--- a/drivers/net/smc-mca.c
+++ b/drivers/net/smc-mca.c
@@ -49,7 +49,6 @@
#include <asm/system.h>
#include "8390.h"
-#include "smc-mca.h"
#define DRV_NAME "smc-mca"
@@ -100,6 +99,63 @@ module_param_array(ultra_irq, int, NULL, 0);
MODULE_PARM_DESC(ultra_io, "SMC Ultra/EtherEZ MCA I/O base address(es)");
MODULE_PARM_DESC(ultra_irq, "SMC Ultra/EtherEZ MCA IRQ number(s)");
+static const struct {
+ unsigned int base_addr;
+} addr_table[] = {
+ { 0x0800 },
+ { 0x1800 },
+ { 0x2800 },
+ { 0x3800 },
+ { 0x4800 },
+ { 0x5800 },
+ { 0x6800 },
+ { 0x7800 },
+ { 0x8800 },
+ { 0x9800 },
+ { 0xa800 },
+ { 0xb800 },
+ { 0xc800 },
+ { 0xd800 },
+ { 0xe800 },
+ { 0xf800 }
+};
+
+#define MEM_MASK 64
+
+static const struct {
+ unsigned char mem_index;
+ unsigned long mem_start;
+ unsigned char num_pages;
+} mem_table[] = {
+ { 16, 0x0c0000, 40 },
+ { 18, 0x0c4000, 40 },
+ { 20, 0x0c8000, 40 },
+ { 22, 0x0cc000, 40 },
+ { 24, 0x0d0000, 40 },
+ { 26, 0x0d4000, 40 },
+ { 28, 0x0d8000, 40 },
+ { 30, 0x0dc000, 40 },
+ {144, 0xfc0000, 40 },
+ {148, 0xfc8000, 40 },
+ {154, 0xfd0000, 40 },
+ {156, 0xfd8000, 40 },
+ { 0, 0x0c0000, 20 },
+ { 1, 0x0c2000, 20 },
+ { 2, 0x0c4000, 20 },
+ { 3, 0x0c6000, 20 }
+};
+
+#define IRQ_MASK 243
+static const struct {
+ unsigned char new_irq;
+ unsigned char old_irq;
+} irq_table[] = {
+ { 3, 3 },
+ { 4, 4 },
+ { 10, 10 },
+ { 14, 15 }
+};
+
static short smc_mca_adapter_ids[] __initdata = {
0x61c8,
0x61c9,
@@ -126,7 +182,7 @@ static char *smc_mca_adapter_names[] __initdata = {
static int ultra_found = 0;
-int __init ultramca_probe(struct device *gen_dev)
+static int __init ultramca_probe(struct device *gen_dev)
{
unsigned short ioaddr;
struct net_device *dev;
diff --git a/drivers/net/smc-mca.h b/drivers/net/smc-mca.h
deleted file mode 100644
index ac50117a7e84..000000000000
--- a/drivers/net/smc-mca.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * djweis weisd3458@uni.edu
- * most of this file was taken from ps2esdi.h
- */
-
-struct {
- unsigned int base_addr;
-} addr_table[] = {
- { 0x0800 },
- { 0x1800 },
- { 0x2800 },
- { 0x3800 },
- { 0x4800 },
- { 0x5800 },
- { 0x6800 },
- { 0x7800 },
- { 0x8800 },
- { 0x9800 },
- { 0xa800 },
- { 0xb800 },
- { 0xc800 },
- { 0xd800 },
- { 0xe800 },
- { 0xf800 }
-};
-
-#define MEM_MASK 64
-
-struct {
- unsigned char mem_index;
- unsigned long mem_start;
- unsigned char num_pages;
-} mem_table[] = {
- { 16, 0x0c0000, 40 },
- { 18, 0x0c4000, 40 },
- { 20, 0x0c8000, 40 },
- { 22, 0x0cc000, 40 },
- { 24, 0x0d0000, 40 },
- { 26, 0x0d4000, 40 },
- { 28, 0x0d8000, 40 },
- { 30, 0x0dc000, 40 },
- {144, 0xfc0000, 40 },
- {148, 0xfc8000, 40 },
- {154, 0xfd0000, 40 },
- {156, 0xfd8000, 40 },
- { 0, 0x0c0000, 20 },
- { 1, 0x0c2000, 20 },
- { 2, 0x0c4000, 20 },
- { 3, 0x0c6000, 20 }
-};
-
-#define IRQ_MASK 243
-struct {
- unsigned char new_irq;
- unsigned char old_irq;
-} irq_table[] = {
- { 3, 3 },
- { 4, 4 },
- { 10, 10 },
- { 14, 15 }
-};
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
index b564c677c6d2..6d9dae60a697 100644
--- a/drivers/net/smc-ultra.c
+++ b/drivers/net/smc-ultra.c
@@ -194,12 +194,7 @@ struct net_device * __init ultra_probe(int unit)
err = do_ultra_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -325,6 +320,9 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr)
#endif
NS8390_init(dev, 0);
+ retval = register_netdev(dev);
+ if (retval)
+ goto out;
return 0;
out:
release_region(ioaddr, ULTRA_IO_EXTENT);
@@ -583,11 +581,8 @@ init_module(void)
dev->irq = irq[this_dev];
dev->base_addr = io[this_dev];
if (do_ultra_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_ultra[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_ultra[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "smc-ultra.c: No SMC Ultra card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c
index fd80048f7f7a..1438fdd20826 100644
--- a/drivers/net/smc91x.c
+++ b/drivers/net/smc91x.c
@@ -315,15 +315,25 @@ static void smc_reset(struct net_device *dev)
struct smc_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
unsigned int ctl, cfg;
+ struct sk_buff *pending_skb;
DBG(2, "%s: %s\n", dev->name, __FUNCTION__);
- /* Disable all interrupts */
+ /* Disable all interrupts, block TX tasklet */
spin_lock(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
+ pending_skb = lp->pending_tx_skb;
+ lp->pending_tx_skb = NULL;
spin_unlock(&lp->lock);
+ /* free any pending tx skb */
+ if (pending_skb) {
+ dev_kfree_skb(pending_skb);
+ lp->stats.tx_errors++;
+ lp->stats.tx_aborted_errors++;
+ }
+
/*
* This resets the registers mostly to defaults, but doesn't
* affect EEPROM. That seems unnecessary
@@ -389,14 +399,6 @@ static void smc_reset(struct net_device *dev)
SMC_SELECT_BANK(2);
SMC_SET_MMU_CMD(MC_RESET);
SMC_WAIT_MMU_BUSY();
-
- /* clear anything saved */
- if (lp->pending_tx_skb != NULL) {
- dev_kfree_skb (lp->pending_tx_skb);
- lp->pending_tx_skb = NULL;
- lp->stats.tx_errors++;
- lp->stats.tx_aborted_errors++;
- }
}
/*
@@ -440,6 +442,7 @@ static void smc_shutdown(struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
void __iomem *ioaddr = lp->base;
+ struct sk_buff *pending_skb;
DBG(2, "%s: %s\n", CARDNAME, __FUNCTION__);
@@ -447,7 +450,11 @@ static void smc_shutdown(struct net_device *dev)
spin_lock(&lp->lock);
SMC_SELECT_BANK(2);
SMC_SET_INT_MASK(0);
+ pending_skb = lp->pending_tx_skb;
+ lp->pending_tx_skb = NULL;
spin_unlock(&lp->lock);
+ if (pending_skb)
+ dev_kfree_skb(pending_skb);
/* and tell the card to stay away from that nasty outside world */
SMC_SELECT_BANK(0);
@@ -627,7 +634,12 @@ static void smc_hardware_send_pkt(unsigned long data)
}
skb = lp->pending_tx_skb;
+ if (unlikely(!skb)) {
+ smc_special_unlock(&lp->lock);
+ return;
+ }
lp->pending_tx_skb = NULL;
+
packet_no = SMC_GET_AR();
if (unlikely(packet_no & AR_FAILED)) {
printk("%s: Memory allocation failed.\n", dev->name);
@@ -702,7 +714,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
DBG(3, "%s: %s\n", dev->name, __FUNCTION__);
BUG_ON(lp->pending_tx_skb != NULL);
- lp->pending_tx_skb = skb;
/*
* The MMU wants the number of pages to be the number of 256 bytes
@@ -718,7 +729,6 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
numPages = ((skb->len & ~1) + (6 - 1)) >> 8;
if (unlikely(numPages > 7)) {
printk("%s: Far too big packet error.\n", dev->name);
- lp->pending_tx_skb = NULL;
lp->stats.tx_errors++;
lp->stats.tx_dropped++;
dev_kfree_skb(skb);
@@ -745,6 +755,7 @@ static int smc_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
smc_special_unlock(&lp->lock);
+ lp->pending_tx_skb = skb;
if (!poll_count) {
/* oh well, wait until the chip finds memory later */
netif_stop_queue(dev);
@@ -1062,7 +1073,7 @@ static void smc_phy_powerdown(struct net_device *dev)
above). linkwatch_event() also wants the netlink semaphore.
*/
while(lp->work_pending)
- schedule();
+ yield();
bmcr = smc_phy_read(dev, phy, MII_BMCR);
smc_phy_write(dev, phy, MII_BMCR, bmcr | BMCR_PDOWN);
@@ -1606,14 +1617,8 @@ static int smc_close(struct net_device *dev)
/* clear everything */
smc_shutdown(dev);
-
+ tasklet_kill(&lp->tx_task);
smc_phy_powerdown(dev);
-
- if (lp->pending_tx_skb) {
- dev_kfree_skb(lp->pending_tx_skb);
- lp->pending_tx_skb = NULL;
- }
-
return 0;
}
@@ -1993,7 +1998,7 @@ static int __init smc_probe(struct net_device *dev, void __iomem *ioaddr)
if (retval)
goto err_out;
- set_irq_type(dev->irq, IRQT_RISING);
+ set_irq_type(dev->irq, SMC_IRQ_TRIGGER_TYPE);
#ifdef SMC_USE_PXA_DMA
{
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h
index 946528e6b742..7089d86e857a 100644
--- a/drivers/net/smc91x.h
+++ b/drivers/net/smc91x.h
@@ -182,6 +182,16 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+#include <asm/mach-types.h>
+#include <asm/arch/cpu.h>
+
+#define SMC_IRQ_TRIGGER_TYPE (( \
+ machine_is_omap_h2() \
+ || machine_is_omap_h3() \
+ || (machine_is_omap_innovator() && !cpu_is_omap150()) \
+ ) ? IRQT_FALLING : IRQT_RISING)
+
+
#elif defined(CONFIG_SH_SH4202_MICRODEV)
#define SMC_CAN_USE_8BIT 0
@@ -300,6 +310,9 @@ static inline void SMC_outsw (unsigned long a, int r, unsigned char* p, int l)
#endif
+#ifndef SMC_IRQ_TRIGGER_TYPE
+#define SMC_IRQ_TRIGGER_TYPE IRQT_RISING
+#endif
#ifdef SMC_USE_PXA_DMA
/*
diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c
index 12e2b6826fa3..88b89dc95c77 100644
--- a/drivers/net/starfire.c
+++ b/drivers/net/starfire.c
@@ -1286,7 +1286,7 @@ static void init_ring(struct net_device *dev)
np->rx_info[i].skb = skb;
if (skb == NULL)
break;
- np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
/* Grrr, we cannot offset to correctly align the IP header. */
np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
@@ -1572,7 +1572,7 @@ static int __netdev_rx(struct net_device *dev, int *quota)
pci_dma_sync_single_for_cpu(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_info[entry].skb->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_info[entry].skb->data, pkt_len, 0);
pci_dma_sync_single_for_device(np->pci_dev,
np->rx_info[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
@@ -1696,7 +1696,7 @@ static void refill_rx_ring(struct net_device *dev)
if (skb == NULL)
break; /* Better luck next round. */
np->rx_info[entry].mapping =
- pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
skb->dev = dev; /* Mark as being used by this device. */
np->rx_ring[entry].rxaddr =
cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c
index 08cb7177a175..d500a5771dbc 100644
--- a/drivers/net/sundance.c
+++ b/drivers/net/sundance.c
@@ -1028,7 +1028,7 @@ static void init_ring(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
np->rx_ring[i].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->tail, np->rx_buf_sz,
+ pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz,
PCI_DMA_FROMDEVICE));
np->rx_ring[i].frag[0].length = cpu_to_le32(np->rx_buf_sz | LastFrag);
}
@@ -1341,7 +1341,7 @@ static void rx_poll(unsigned long data)
np->rx_buf_sz,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
pci_dma_sync_single_for_device(np->pci_dev,
desc->frag[0].addr,
np->rx_buf_sz,
@@ -1400,7 +1400,7 @@ static void refill_rx (struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
np->rx_ring[entry].frag[0].addr = cpu_to_le32(
- pci_map_single(np->pci_dev, skb->tail,
+ pci_map_single(np->pci_dev, skb->data,
np->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
/* Perhaps we need not reset this field. */
diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c
index 5cd50fd53c12..2608e7a3d214 100644
--- a/drivers/net/sungem.c
+++ b/drivers/net/sungem.c
@@ -44,6 +44,7 @@
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -2989,10 +2990,10 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
*/
if (pdev->vendor == PCI_VENDOR_ID_SUN &&
pdev->device == PCI_DEVICE_ID_SUN_GEM &&
- !pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) {
+ !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
pci_using_dac = 1;
} else {
- err = pci_set_dma_mask(pdev, (u64) 0xffffffff);
+ err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (err) {
printk(KERN_ERR PFX "No usable DMA configuration, "
"aborting.\n");
@@ -3078,7 +3079,9 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
gp->phy_mii.dev = dev;
gp->phy_mii.mdio_read = _phy_read;
gp->phy_mii.mdio_write = _phy_write;
-
+#ifdef CONFIG_PPC_PMAC
+ gp->phy_mii.platform_data = gp->of_node;
+#endif
/* By default, we start with autoneg */
gp->want_autoneg = 1;
diff --git a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
index 0fca414d3657..d3ddb41d6e5c 100644
--- a/drivers/net/sungem_phy.c
+++ b/drivers/net/sungem_phy.c
@@ -32,6 +32,10 @@
#include <linux/ethtool.h>
#include <linux/delay.h>
+#ifdef CONFIG_PPC_PMAC
+#include <asm/prom.h>
+#endif
+
#include "sungem_phy.h"
/* Link modes of the BCM5400 PHY */
@@ -281,10 +285,12 @@ static int bcm5411_suspend(struct mii_phy* phy)
static int bcm5421_init(struct mii_phy* phy)
{
u16 data;
- int rev;
+ unsigned int id;
- rev = phy_read(phy, MII_PHYSID2) & 0x000f;
- if (rev == 0) {
+ id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2));
+
+ /* Revision 0 of 5421 needs some fixups */
+ if (id == 0x002060e0) {
/* This is borrowed from MacOS
*/
phy_write(phy, 0x18, 0x1007);
@@ -297,21 +303,28 @@ static int bcm5421_init(struct mii_phy* phy)
data = phy_read(phy, 0x15);
phy_write(phy, 0x15, data | 0x0200);
}
-#if 0
- /* This has to be verified before I enable it */
- /* Enable automatic low-power */
- phy_write(phy, 0x1c, 0x9002);
- phy_write(phy, 0x1c, 0xa821);
- phy_write(phy, 0x1c, 0x941d);
-#endif
- return 0;
-}
-static int bcm5421k2_init(struct mii_phy* phy)
-{
- /* Init code borrowed from OF */
- phy_write(phy, 4, 0x01e1);
- phy_write(phy, 9, 0x0300);
+ /* Pick up some init code from OF for K2 version */
+ if ((id & 0xfffffff0) == 0x002062e0) {
+ phy_write(phy, 4, 0x01e1);
+ phy_write(phy, 9, 0x0300);
+ }
+
+ /* Check if we can enable automatic low power */
+#ifdef CONFIG_PPC_PMAC
+ if (phy->platform_data) {
+ struct device_node *np = of_get_parent(phy->platform_data);
+ int can_low_power = 1;
+ if (np == NULL || get_property(np, "no-autolowpower", NULL))
+ can_low_power = 0;
+ if (can_low_power) {
+ /* Enable automatic low-power */
+ phy_write(phy, 0x1c, 0x9002);
+ phy_write(phy, 0x1c, 0xa821);
+ phy_write(phy, 0x1c, 0x941d);
+ }
+ }
+#endif /* CONFIG_PPC_PMAC */
return 0;
}
@@ -762,7 +775,7 @@ static struct mii_phy_def bcm5421_phy_def = {
/* Broadcom BCM 5421 built-in K2 */
static struct mii_phy_ops bcm5421k2_phy_ops = {
- .init = bcm5421k2_init,
+ .init = bcm5421_init,
.suspend = bcm5411_suspend,
.setup_aneg = bcm54xx_setup_aneg,
.setup_forced = bcm54xx_setup_forced,
@@ -779,6 +792,25 @@ static struct mii_phy_def bcm5421k2_phy_def = {
.ops = &bcm5421k2_phy_ops
};
+/* Broadcom BCM 5462 built-in Vesta */
+static struct mii_phy_ops bcm5462V_phy_ops = {
+ .init = bcm5421_init,
+ .suspend = bcm5411_suspend,
+ .setup_aneg = bcm54xx_setup_aneg,
+ .setup_forced = bcm54xx_setup_forced,
+ .poll_link = genmii_poll_link,
+ .read_link = bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5462V_phy_def = {
+ .phy_id = 0x002060d0,
+ .phy_id_mask = 0xfffffff0,
+ .name = "BCM5462-Vesta",
+ .features = MII_GBIT_FEATURES,
+ .magic_aneg = 1,
+ .ops = &bcm5462V_phy_ops
+};
+
/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
* I masked out the 8 last bits to get both, but some specs
* would be useful here) --BenH.
@@ -824,6 +856,7 @@ static struct mii_phy_def* mii_phy_table[] = {
&bcm5411_phy_def,
&bcm5421_phy_def,
&bcm5421k2_phy_def,
+ &bcm5462V_phy_def,
&marvell_phy_def,
&genmii_phy_def,
NULL
diff --git a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
index 822cb58174ea..430544496c52 100644
--- a/drivers/net/sungem_phy.h
+++ b/drivers/net/sungem_phy.h
@@ -43,9 +43,10 @@ struct mii_phy
int pause;
/* Provided by host chip */
- struct net_device* dev;
+ struct net_device *dev;
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);
+ void *platform_data;
};
/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index a0b8848049c9..54640686e983 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -66,8 +66,8 @@
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
-#define DRV_MODULE_VERSION "3.31"
-#define DRV_MODULE_RELDATE "June 8, 2005"
+#define DRV_MODULE_VERSION "3.33"
+#define DRV_MODULE_RELDATE "July 5, 2005"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
@@ -337,12 +337,10 @@ static struct {
static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
{
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
- unsigned long flags;
-
- spin_lock_irqsave(&tp->indirect_lock, flags);
+ spin_lock_bh(&tp->indirect_lock);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
- spin_unlock_irqrestore(&tp->indirect_lock, flags);
+ spin_unlock_bh(&tp->indirect_lock);
} else {
writel(val, tp->regs + off);
if ((tp->tg3_flags & TG3_FLAG_5701_REG_WRITE_BUG) != 0)
@@ -353,12 +351,10 @@ static void tg3_write_indirect_reg32(struct tg3 *tp, u32 off, u32 val)
static void _tw32_flush(struct tg3 *tp, u32 off, u32 val)
{
if ((tp->tg3_flags & TG3_FLAG_PCIX_TARGET_HWBUG) != 0) {
- unsigned long flags;
-
- spin_lock_irqsave(&tp->indirect_lock, flags);
+ spin_lock_bh(&tp->indirect_lock);
pci_write_config_dword(tp->pdev, TG3PCI_REG_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_REG_DATA, val);
- spin_unlock_irqrestore(&tp->indirect_lock, flags);
+ spin_unlock_bh(&tp->indirect_lock);
} else {
void __iomem *dest = tp->regs + off;
writel(val, dest);
@@ -398,28 +394,24 @@ static inline void _tw32_tx_mbox(struct tg3 *tp, u32 off, u32 val)
static void tg3_write_mem(struct tg3 *tp, u32 off, u32 val)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tp->indirect_lock, flags);
+ spin_lock_bh(&tp->indirect_lock);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
/* Always leave this as zero. */
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
- spin_unlock_irqrestore(&tp->indirect_lock, flags);
+ spin_unlock_bh(&tp->indirect_lock);
}
static void tg3_read_mem(struct tg3 *tp, u32 off, u32 *val)
{
- unsigned long flags;
-
- spin_lock_irqsave(&tp->indirect_lock, flags);
+ spin_lock_bh(&tp->indirect_lock);
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, off);
pci_read_config_dword(tp->pdev, TG3PCI_MEM_WIN_DATA, val);
/* Always leave this as zero. */
pci_write_config_dword(tp->pdev, TG3PCI_MEM_WIN_BASE_ADDR, 0);
- spin_unlock_irqrestore(&tp->indirect_lock, flags);
+ spin_unlock_bh(&tp->indirect_lock);
}
static void tg3_disable_ints(struct tg3 *tp)
@@ -438,12 +430,14 @@ static inline void tg3_cond_int(struct tg3 *tp)
static void tg3_enable_ints(struct tg3 *tp)
{
+ tp->irq_sync = 0;
+ wmb();
+
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
(tp->last_tag << 24));
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
-
tg3_cond_int(tp);
}
@@ -492,6 +486,7 @@ static void tg3_restart_ints(struct tg3 *tp)
static inline void tg3_netif_stop(struct tg3 *tp)
{
+ tp->dev->trans_start = jiffies; /* prevent tx timeout */
netif_poll_disable(tp->dev);
netif_tx_disable(tp->dev);
}
@@ -504,7 +499,8 @@ static inline void tg3_netif_start(struct tg3 *tp)
* (such as after tg3_init_hw)
*/
netif_poll_enable(tp->dev);
- tg3_cond_int(tp);
+ tp->hw_status->status |= SD_STATUS_UPDATED;
+ tg3_enable_ints(tp);
}
static void tg3_switch_clocks(struct tg3 *tp)
@@ -2578,7 +2574,7 @@ static void tg3_tx(struct tg3 *tp)
sw_idx = NEXT_TX(sw_idx);
}
- dev_kfree_skb_irq(skb);
+ dev_kfree_skb(skb);
}
tp->tx_cons = sw_idx;
@@ -2884,11 +2880,8 @@ static int tg3_poll(struct net_device *netdev, int *budget)
{
struct tg3 *tp = netdev_priv(netdev);
struct tg3_hw_status *sblk = tp->hw_status;
- unsigned long flags;
int done;
- spin_lock_irqsave(&tp->lock, flags);
-
/* handle link change and other phy events */
if (!(tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
@@ -2896,7 +2889,9 @@ static int tg3_poll(struct net_device *netdev, int *budget)
if (sblk->status & SD_STATUS_LINK_CHG) {
sblk->status = SD_STATUS_UPDATED |
(sblk->status & ~SD_STATUS_LINK_CHG);
+ spin_lock(&tp->lock);
tg3_setup_phy(tp, 0);
+ spin_unlock(&tp->lock);
}
}
@@ -2907,8 +2902,6 @@ static int tg3_poll(struct net_device *netdev, int *budget)
spin_unlock(&tp->tx_lock);
}
- spin_unlock_irqrestore(&tp->lock, flags);
-
/* run RX thread, within the bounds set by NAPI.
* All RX "locking" is done by ensuring outside
* code synchronizes with dev->poll()
@@ -2929,19 +2922,54 @@ static int tg3_poll(struct net_device *netdev, int *budget)
if (tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)
tp->last_tag = sblk->status_tag;
rmb();
+ sblk->status &= ~SD_STATUS_UPDATED;
/* if no more work, tell net stack and NIC we're done */
done = !tg3_has_work(tp);
if (done) {
- spin_lock_irqsave(&tp->lock, flags);
- __netif_rx_complete(netdev);
+ spin_lock(&tp->lock);
+ netif_rx_complete(netdev);
tg3_restart_ints(tp);
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_unlock(&tp->lock);
}
return (done ? 0 : 1);
}
+static void tg3_irq_quiesce(struct tg3 *tp)
+{
+ BUG_ON(tp->irq_sync);
+
+ tp->irq_sync = 1;
+ smp_mb();
+
+ synchronize_irq(tp->pdev->irq);
+}
+
+static inline int tg3_irq_sync(struct tg3 *tp)
+{
+ return tp->irq_sync;
+}
+
+/* Fully shutdown all tg3 driver activity elsewhere in the system.
+ * If irq_sync is non-zero, then the IRQ handler must be synchronized
+ * with as well. Most of the time, this is not necessary except when
+ * shutting down the device.
+ */
+static inline void tg3_full_lock(struct tg3 *tp, int irq_sync)
+{
+ if (irq_sync)
+ tg3_irq_quiesce(tp);
+ spin_lock_bh(&tp->lock);
+ spin_lock(&tp->tx_lock);
+}
+
+static inline void tg3_full_unlock(struct tg3 *tp)
+{
+ spin_unlock(&tp->tx_lock);
+ spin_unlock_bh(&tp->lock);
+}
+
/* MSI ISR - No need to check for interrupt sharing and no need to
* flush status block and interrupt mailbox. PCI ordering rules
* guarantee that MSI will arrive after the status block.
@@ -2951,9 +2979,6 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
struct tg3_hw_status *sblk = tp->hw_status;
- unsigned long flags;
-
- spin_lock_irqsave(&tp->lock, flags);
/*
* Writing any value to intr-mbox-0 clears PCI INTA# and
@@ -2964,6 +2989,9 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
tp->last_tag = sblk->status_tag;
+ rmb();
+ if (tg3_irq_sync(tp))
+ goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp)))
netif_rx_schedule(dev); /* schedule NAPI poll */
@@ -2972,9 +3000,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id, struct pt_regs *regs)
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
tp->last_tag << 24);
}
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
return IRQ_RETVAL(1);
}
@@ -2983,11 +3009,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
struct tg3_hw_status *sblk = tp->hw_status;
- unsigned long flags;
unsigned int handled = 1;
- spin_lock_irqsave(&tp->lock, flags);
-
/* In INTx mode, it is possible for the interrupt to arrive at
* the CPU before the status block posted prior to the interrupt.
* Reading the PCI State register will confirm whether the
@@ -3004,6 +3027,8 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
+ if (tg3_irq_sync(tp))
+ goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp)))
netif_rx_schedule(dev); /* schedule NAPI poll */
@@ -3018,9 +3043,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
} else { /* shared interrupt */
handled = 0;
}
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
return IRQ_RETVAL(handled);
}
@@ -3029,11 +3052,8 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
struct net_device *dev = dev_id;
struct tg3 *tp = netdev_priv(dev);
struct tg3_hw_status *sblk = tp->hw_status;
- unsigned long flags;
unsigned int handled = 1;
- spin_lock_irqsave(&tp->lock, flags);
-
/* In INTx mode, it is possible for the interrupt to arrive at
* the CPU before the status block posted prior to the interrupt.
* Reading the PCI State register will confirm whether the
@@ -3051,6 +3071,9 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
tp->last_tag = sblk->status_tag;
+ rmb();
+ if (tg3_irq_sync(tp))
+ goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp)))
netif_rx_schedule(dev); /* schedule NAPI poll */
@@ -3065,9 +3088,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id, struct pt_regs *r
} else { /* shared interrupt */
handled = 0;
}
-
- spin_unlock_irqrestore(&tp->lock, flags);
-
+out:
return IRQ_RETVAL(handled);
}
@@ -3106,8 +3127,7 @@ static void tg3_reset_task(void *_data)
tg3_netif_stop(tp);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 1);
restart_timer = tp->tg3_flags2 & TG3_FLG2_RESTART_TIMER;
tp->tg3_flags2 &= ~TG3_FLG2_RESTART_TIMER;
@@ -3117,8 +3137,7 @@ static void tg3_reset_task(void *_data)
tg3_netif_start(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
if (restart_timer)
mod_timer(&tp->timer, jiffies + 1);
@@ -3224,39 +3243,21 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
unsigned int i;
u32 len, entry, base_flags, mss;
int would_hit_hwbug;
- unsigned long flags;
len = skb_headlen(skb);
/* No BH disabling for tx_lock here. We are running in BH disabled
* context and TX reclaim runs via tp->poll inside of a software
- * interrupt. Rejoice!
- *
- * Actually, things are not so simple. If we are to take a hw
- * IRQ here, we can deadlock, consider:
- *
- * CPU1 CPU2
- * tg3_start_xmit
- * take tp->tx_lock
- * tg3_timer
- * take tp->lock
- * tg3_interrupt
- * spin on tp->lock
- * spin on tp->tx_lock
- *
- * So we really do need to disable interrupts when taking
- * tx_lock here.
+ * interrupt. Furthermore, IRQ processing runs lockless so we have
+ * no IRQ context deadlocks to worry about either. Rejoice!
*/
- local_irq_save(flags);
- if (!spin_trylock(&tp->tx_lock)) {
- local_irq_restore(flags);
+ if (!spin_trylock(&tp->tx_lock))
return NETDEV_TX_LOCKED;
- }
/* This is a hard error, log it. */
if (unlikely(TX_BUFFS_AVAIL(tp) <= (skb_shinfo(skb)->nr_frags + 1))) {
netif_stop_queue(dev);
- spin_unlock_irqrestore(&tp->tx_lock, flags);
+ spin_unlock(&tp->tx_lock);
printk(KERN_ERR PFX "%s: BUG! Tx Ring full when queue awake!\n",
dev->name);
return NETDEV_TX_BUSY;
@@ -3421,7 +3422,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
out_unlock:
mmiowb();
- spin_unlock_irqrestore(&tp->tx_lock, flags);
+ spin_unlock(&tp->tx_lock);
dev->trans_start = jiffies;
@@ -3455,8 +3456,8 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
}
tg3_netif_stop(tp);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+
+ tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
@@ -3466,8 +3467,7 @@ static int tg3_change_mtu(struct net_device *dev, int new_mtu)
tg3_netif_start(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
return 0;
}
@@ -5088,9 +5088,9 @@ static int tg3_set_mac_addr(struct net_device *dev, void *p)
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
__tg3_set_mac_addr(tp);
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
return 0;
}
@@ -5117,7 +5117,7 @@ static void tg3_set_bdinfo(struct tg3 *tp, u32 bdinfo_addr,
}
static void __tg3_set_rx_mode(struct net_device *);
-static void tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
+static void __tg3_set_coalesce(struct tg3 *tp, struct ethtool_coalesce *ec)
{
tw32(HOSTCC_RXCOL_TICKS, ec->rx_coalesce_usecs);
tw32(HOSTCC_TXCOL_TICKS, ec->tx_coalesce_usecs);
@@ -5460,7 +5460,7 @@ static int tg3_reset_hw(struct tg3 *tp)
udelay(10);
}
- tg3_set_coalesce(tp, &tp->coal);
+ __tg3_set_coalesce(tp, &tp->coal);
/* set status block DMA address */
tw32(HOSTCC_STATUS_BLK_HOST_ADDR + TG3_64BIT_REG_HIGH,
@@ -5727,9 +5727,6 @@ static int tg3_reset_hw(struct tg3 *tp)
tg3_write_sig_post_reset(tp, RESET_KIND_INIT);
- if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
- tg3_enable_ints(tp);
-
return 0;
}
@@ -5802,10 +5799,8 @@ static void tg3_periodic_fetch_stats(struct tg3 *tp)
static void tg3_timer(unsigned long __opaque)
{
struct tg3 *tp = (struct tg3 *) __opaque;
- unsigned long flags;
- spin_lock_irqsave(&tp->lock, flags);
- spin_lock(&tp->tx_lock);
+ spin_lock(&tp->lock);
if (!(tp->tg3_flags & TG3_FLAG_TAGGED_STATUS)) {
/* All of this garbage is because when using non-tagged
@@ -5822,8 +5817,7 @@ static void tg3_timer(unsigned long __opaque)
if (!(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
tp->tg3_flags2 |= TG3_FLG2_RESTART_TIMER;
- spin_unlock(&tp->tx_lock);
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_unlock(&tp->lock);
schedule_work(&tp->reset_task);
return;
}
@@ -5891,8 +5885,7 @@ static void tg3_timer(unsigned long __opaque)
tp->asf_counter = tp->asf_multiplier;
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_unlock(&tp->lock);
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
@@ -6007,14 +6000,12 @@ static int tg3_test_msi(struct tg3 *tp)
/* Need to reset the chip because the MSI cycle may have terminated
* with Master Abort.
*/
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 1);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
err = tg3_init_hw(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
if (err)
free_irq(tp->pdev->irq, dev);
@@ -6027,14 +6018,12 @@ static int tg3_open(struct net_device *dev)
struct tg3 *tp = netdev_priv(dev);
int err;
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tg3_disable_ints(tp);
tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
/* The placement of this call is tied
* to the setup and use of Host TX descriptors.
@@ -6081,8 +6070,7 @@ static int tg3_open(struct net_device *dev)
return err;
}
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
err = tg3_init_hw(tp);
if (err) {
@@ -6106,8 +6094,7 @@ static int tg3_open(struct net_device *dev)
tp->timer.function = tg3_timer;
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
if (err) {
free_irq(tp->pdev->irq, dev);
@@ -6123,8 +6110,7 @@ static int tg3_open(struct net_device *dev)
err = tg3_test_msi(tp);
if (err) {
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
pci_disable_msi(tp->pdev);
@@ -6134,22 +6120,19 @@ static int tg3_open(struct net_device *dev)
tg3_free_rings(tp);
tg3_free_consistent(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
return err;
}
}
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
add_timer(&tp->timer);
tp->tg3_flags |= TG3_FLAG_INIT_COMPLETE;
tg3_enable_ints(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
netif_start_queue(dev);
@@ -6395,8 +6378,7 @@ static int tg3_close(struct net_device *dev)
del_timer_sync(&tp->timer);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 1);
#if 0
tg3_dump_state(tp);
#endif
@@ -6410,8 +6392,7 @@ static int tg3_close(struct net_device *dev)
TG3_FLAG_GOT_SERDES_FLOWCTL);
netif_carrier_off(tp->dev);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
free_irq(tp->pdev->irq, dev);
if (tp->tg3_flags2 & TG3_FLG2_USING_MSI) {
@@ -6448,16 +6429,15 @@ static unsigned long calc_crc_errors(struct tg3 *tp)
if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES) &&
(GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 ||
GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701)) {
- unsigned long flags;
u32 val;
- spin_lock_irqsave(&tp->lock, flags);
+ spin_lock_bh(&tp->lock);
if (!tg3_readphy(tp, 0x1e, &val)) {
tg3_writephy(tp, 0x1e, val | 0x8000);
tg3_readphy(tp, 0x14, &val);
} else
val = 0;
- spin_unlock_irqrestore(&tp->lock, flags);
+ spin_unlock_bh(&tp->lock);
tp->phy_crc_errors += val;
@@ -6719,11 +6699,9 @@ static void tg3_set_rx_mode(struct net_device *dev)
{
struct tg3 *tp = netdev_priv(dev);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
__tg3_set_rx_mode(dev);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
}
#define TG3_REGDUMP_LEN (32 * 1024)
@@ -6745,8 +6723,7 @@ static void tg3_get_regs(struct net_device *dev,
memset(p, 0, TG3_REGDUMP_LEN);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
#define __GET_REG32(reg) (*(p)++ = tr32(reg))
#define GET_REG32_LOOP(base,len) \
@@ -6796,8 +6773,7 @@ do { p = (u32 *)(orig_p + (reg)); \
#undef GET_REG32_LOOP
#undef GET_REG32_1
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
}
static int tg3_get_eeprom_len(struct net_device *dev)
@@ -6973,8 +6949,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return -EINVAL;
}
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tp->link_config.autoneg = cmd->autoneg;
if (cmd->autoneg == AUTONEG_ENABLE) {
@@ -6990,8 +6965,7 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
if (netif_running(dev))
tg3_setup_phy(tp, 1);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
return 0;
}
@@ -7027,12 +7001,12 @@ static int tg3_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
!(tp->tg3_flags & TG3_FLAG_SERDES_WOL_CAP))
return -EINVAL;
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
if (wol->wolopts & WAKE_MAGIC)
tp->tg3_flags |= TG3_FLAG_WOL_ENABLE;
else
tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE;
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
return 0;
}
@@ -7072,7 +7046,7 @@ static int tg3_nway_reset(struct net_device *dev)
if (!netif_running(dev))
return -EAGAIN;
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
r = -EINVAL;
tg3_readphy(tp, MII_BMCR, &bmcr);
if (!tg3_readphy(tp, MII_BMCR, &bmcr) &&
@@ -7080,7 +7054,7 @@ static int tg3_nway_reset(struct net_device *dev)
tg3_writephy(tp, MII_BMCR, bmcr | BMCR_ANRESTART);
r = 0;
}
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
return r;
}
@@ -7102,17 +7076,19 @@ static void tg3_get_ringparam(struct net_device *dev, struct ethtool_ringparam *
static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
{
struct tg3 *tp = netdev_priv(dev);
+ int irq_sync = 0;
if ((ering->rx_pending > TG3_RX_RING_SIZE - 1) ||
(ering->rx_jumbo_pending > TG3_RX_JUMBO_RING_SIZE - 1) ||
(ering->tx_pending > TG3_TX_RING_SIZE - 1))
return -EINVAL;
- if (netif_running(dev))
+ if (netif_running(dev)) {
tg3_netif_stop(tp);
+ irq_sync = 1;
+ }
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, irq_sync);
tp->rx_pending = ering->rx_pending;
@@ -7128,8 +7104,7 @@ static int tg3_set_ringparam(struct net_device *dev, struct ethtool_ringparam *e
tg3_netif_start(tp);
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
return 0;
}
@@ -7146,12 +7121,15 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam
static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
{
struct tg3 *tp = netdev_priv(dev);
+ int irq_sync = 0;
- if (netif_running(dev))
+ if (netif_running(dev)) {
tg3_netif_stop(tp);
+ irq_sync = 1;
+ }
+
+ tg3_full_lock(tp, irq_sync);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
if (epause->autoneg)
tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG;
else
@@ -7170,8 +7148,8 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam
tg3_init_hw(tp);
tg3_netif_start(tp);
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+
+ tg3_full_unlock(tp);
return 0;
}
@@ -7192,12 +7170,12 @@ static int tg3_set_rx_csum(struct net_device *dev, u32 data)
return 0;
}
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
if (data)
tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS;
else
tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS;
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
return 0;
}
@@ -7606,8 +7584,6 @@ static int tg3_test_loopback(struct tg3 *tp)
tg3_abort_hw(tp, 1);
- /* Clearing this flag to keep interrupts disabled */
- tp->tg3_flags &= ~TG3_FLAG_INIT_COMPLETE;
tg3_reset_hw(tp);
mac_mode = (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK) |
@@ -7716,11 +7692,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
data[1] = 1;
}
if (etest->flags & ETH_TEST_FL_OFFLINE) {
- if (netif_running(dev))
+ int irq_sync = 0;
+
+ if (netif_running(dev)) {
tg3_netif_stop(tp);
+ irq_sync = 1;
+ }
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, irq_sync);
tg3_halt(tp, RESET_KIND_SUSPEND, 1);
tg3_nvram_lock(tp);
@@ -7742,14 +7721,14 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
data[4] = 1;
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
+
if (tg3_test_interrupt(tp) != 0) {
etest->flags |= ETH_TEST_FL_FAILED;
data[5] = 1;
}
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+
+ tg3_full_lock(tp, 0);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
if (netif_running(dev)) {
@@ -7757,8 +7736,8 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest,
tg3_init_hw(tp);
tg3_netif_start(tp);
}
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+
+ tg3_full_unlock(tp);
}
}
@@ -7779,9 +7758,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)
break; /* We have no PHY */
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
err = tg3_readphy(tp, data->reg_num & 0x1f, &mii_regval);
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
data->val_out = mii_regval;
@@ -7795,9 +7774,9 @@ static int tg3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- spin_lock_irq(&tp->lock);
+ spin_lock_bh(&tp->lock);
err = tg3_writephy(tp, data->reg_num & 0x1f, data->val_in);
- spin_unlock_irq(&tp->lock);
+ spin_unlock_bh(&tp->lock);
return err;
@@ -7813,28 +7792,24 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
{
struct tg3 *tp = netdev_priv(dev);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tp->vlgrp = grp;
/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
__tg3_set_rx_mode(dev);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
}
static void tg3_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
{
struct tg3 *tp = netdev_priv(dev);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
if (tp->vlgrp)
tp->vlgrp->vlan_devices[vid] = NULL;
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
}
#endif
@@ -7846,6 +7821,60 @@ static int tg3_get_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
return 0;
}
+static int tg3_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
+{
+ struct tg3 *tp = netdev_priv(dev);
+ u32 max_rxcoal_tick_int = 0, max_txcoal_tick_int = 0;
+ u32 max_stat_coal_ticks = 0, min_stat_coal_ticks = 0;
+
+ if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) {
+ max_rxcoal_tick_int = MAX_RXCOAL_TICK_INT;
+ max_txcoal_tick_int = MAX_TXCOAL_TICK_INT;
+ max_stat_coal_ticks = MAX_STAT_COAL_TICKS;
+ min_stat_coal_ticks = MIN_STAT_COAL_TICKS;
+ }
+
+ if ((ec->rx_coalesce_usecs > MAX_RXCOL_TICKS) ||
+ (ec->tx_coalesce_usecs > MAX_TXCOL_TICKS) ||
+ (ec->rx_max_coalesced_frames > MAX_RXMAX_FRAMES) ||
+ (ec->tx_max_coalesced_frames > MAX_TXMAX_FRAMES) ||
+ (ec->rx_coalesce_usecs_irq > max_rxcoal_tick_int) ||
+ (ec->tx_coalesce_usecs_irq > max_txcoal_tick_int) ||
+ (ec->rx_max_coalesced_frames_irq > MAX_RXCOAL_MAXF_INT) ||
+ (ec->tx_max_coalesced_frames_irq > MAX_TXCOAL_MAXF_INT) ||
+ (ec->stats_block_coalesce_usecs > max_stat_coal_ticks) ||
+ (ec->stats_block_coalesce_usecs < min_stat_coal_ticks))
+ return -EINVAL;
+
+ /* No rx interrupts will be generated if both are zero */
+ if ((ec->rx_coalesce_usecs == 0) &&
+ (ec->rx_max_coalesced_frames == 0))
+ return -EINVAL;
+
+ /* No tx interrupts will be generated if both are zero */
+ if ((ec->tx_coalesce_usecs == 0) &&
+ (ec->tx_max_coalesced_frames == 0))
+ return -EINVAL;
+
+ /* Only copy relevant parameters, ignore all others. */
+ tp->coal.rx_coalesce_usecs = ec->rx_coalesce_usecs;
+ tp->coal.tx_coalesce_usecs = ec->tx_coalesce_usecs;
+ tp->coal.rx_max_coalesced_frames = ec->rx_max_coalesced_frames;
+ tp->coal.tx_max_coalesced_frames = ec->tx_max_coalesced_frames;
+ tp->coal.rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq;
+ tp->coal.tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq;
+ tp->coal.rx_max_coalesced_frames_irq = ec->rx_max_coalesced_frames_irq;
+ tp->coal.tx_max_coalesced_frames_irq = ec->tx_max_coalesced_frames_irq;
+ tp->coal.stats_block_coalesce_usecs = ec->stats_block_coalesce_usecs;
+
+ if (netif_running(dev)) {
+ tg3_full_lock(tp, 0);
+ __tg3_set_coalesce(tp, &tp->coal);
+ tg3_full_unlock(tp);
+ }
+ return 0;
+}
+
static struct ethtool_ops tg3_ethtool_ops = {
.get_settings = tg3_get_settings,
.set_settings = tg3_set_settings,
@@ -7881,6 +7910,7 @@ static struct ethtool_ops tg3_ethtool_ops = {
.get_stats_count = tg3_get_stats_count,
.get_ethtool_stats = tg3_get_ethtool_stats,
.get_coalesce = tg3_get_coalesce,
+ .set_coalesce = tg3_set_coalesce,
};
static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
@@ -9825,6 +9855,12 @@ static void __devinit tg3_init_coal(struct tg3 *tp)
ec->tx_coalesce_usecs = LOW_TXCOL_TICKS_CLRTCKS;
ec->tx_coalesce_usecs_irq = DEFAULT_TXCOAL_TICK_INT_CLRTCKS;
}
+
+ if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) {
+ ec->rx_coalesce_usecs_irq = 0;
+ ec->tx_coalesce_usecs_irq = 0;
+ ec->stats_block_coalesce_usecs = 0;
+ }
}
static int __devinit tg3_init_one(struct pci_dev *pdev,
@@ -10165,24 +10201,19 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
del_timer_sync(&tp->timer);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 1);
tg3_disable_ints(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
netif_device_detach(dev);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
err = tg3_set_power_state(tp, pci_choose_state(pdev, state));
if (err) {
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tg3_init_hw(tp);
@@ -10192,8 +10223,7 @@ static int tg3_suspend(struct pci_dev *pdev, pm_message_t state)
netif_device_attach(dev);
tg3_netif_start(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
}
return err;
@@ -10216,20 +10246,16 @@ static int tg3_resume(struct pci_dev *pdev)
netif_device_attach(dev);
- spin_lock_irq(&tp->lock);
- spin_lock(&tp->tx_lock);
+ tg3_full_lock(tp, 0);
tg3_init_hw(tp);
tp->timer.expires = jiffies + tp->timer_offset;
add_timer(&tp->timer);
- tg3_enable_ints(tp);
-
tg3_netif_start(tp);
- spin_unlock(&tp->tx_lock);
- spin_unlock_irq(&tp->lock);
+ tg3_full_unlock(tp);
return 0;
}
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 993f84c93dc4..70ad450733e6 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -879,31 +879,41 @@
#define LOW_RXCOL_TICKS_CLRTCKS 0x00000014
#define DEFAULT_RXCOL_TICKS 0x00000048
#define HIGH_RXCOL_TICKS 0x00000096
+#define MAX_RXCOL_TICKS 0x000003ff
#define HOSTCC_TXCOL_TICKS 0x00003c0c
#define LOW_TXCOL_TICKS 0x00000096
#define LOW_TXCOL_TICKS_CLRTCKS 0x00000048
#define DEFAULT_TXCOL_TICKS 0x0000012c
#define HIGH_TXCOL_TICKS 0x00000145
+#define MAX_TXCOL_TICKS 0x000003ff
#define HOSTCC_RXMAX_FRAMES 0x00003c10
#define LOW_RXMAX_FRAMES 0x00000005
#define DEFAULT_RXMAX_FRAMES 0x00000008
#define HIGH_RXMAX_FRAMES 0x00000012
+#define MAX_RXMAX_FRAMES 0x000000ff
#define HOSTCC_TXMAX_FRAMES 0x00003c14
#define LOW_TXMAX_FRAMES 0x00000035
#define DEFAULT_TXMAX_FRAMES 0x0000004b
#define HIGH_TXMAX_FRAMES 0x00000052
+#define MAX_TXMAX_FRAMES 0x000000ff
#define HOSTCC_RXCOAL_TICK_INT 0x00003c18
#define DEFAULT_RXCOAL_TICK_INT 0x00000019
#define DEFAULT_RXCOAL_TICK_INT_CLRTCKS 0x00000014
+#define MAX_RXCOAL_TICK_INT 0x000003ff
#define HOSTCC_TXCOAL_TICK_INT 0x00003c1c
#define DEFAULT_TXCOAL_TICK_INT 0x00000019
#define DEFAULT_TXCOAL_TICK_INT_CLRTCKS 0x00000014
+#define MAX_TXCOAL_TICK_INT 0x000003ff
#define HOSTCC_RXCOAL_MAXF_INT 0x00003c20
#define DEFAULT_RXCOAL_MAXF_INT 0x00000005
+#define MAX_RXCOAL_MAXF_INT 0x000000ff
#define HOSTCC_TXCOAL_MAXF_INT 0x00003c24
#define DEFAULT_TXCOAL_MAXF_INT 0x00000005
+#define MAX_TXCOAL_MAXF_INT 0x000000ff
#define HOSTCC_STAT_COAL_TICKS 0x00003c28
#define DEFAULT_STAT_COAL_TICKS 0x000f4240
+#define MAX_STAT_COAL_TICKS 0xd693d400
+#define MIN_STAT_COAL_TICKS 0x00000064
/* 0x3c2c --> 0x3c30 unused */
#define HOSTCC_STATS_BLK_HOST_ADDR 0x00003c30 /* 64-bit */
#define HOSTCC_STATUS_BLK_HOST_ADDR 0x00003c38 /* 64-bit */
@@ -2006,17 +2016,31 @@ struct tg3_ethtool_stats {
struct tg3 {
/* begin "general, frequently-used members" cacheline section */
+ /* If the IRQ handler (which runs lockless) needs to be
+ * quiesced, the following bitmask state is used. The
+ * SYNC flag is set by non-IRQ context code to initiate
+ * the quiescence.
+ *
+ * When the IRQ handler notices that SYNC is set, it
+ * disables interrupts and returns.
+ *
+ * When all outstanding IRQ handlers have returned after
+ * the SYNC flag has been set, the setter can be assured
+ * that interrupts will no longer get run.
+ *
+ * In this way all SMP driver locks are never acquired
+ * in hw IRQ context, only sw IRQ context or lower.
+ */
+ unsigned int irq_sync;
+
/* SMP locking strategy:
*
* lock: Held during all operations except TX packet
* processing.
*
- * tx_lock: Held during tg3_start_xmit{,_4gbug} and tg3_tx
+ * tx_lock: Held during tg3_start_xmit and tg3_tx
*
- * If you want to shut up all asynchronous processing you must
- * acquire both locks, 'lock' taken before 'tx_lock'. IRQs must
- * be disabled to take 'lock' but only softirq disabling is
- * necessary for acquisition of 'tx_lock'.
+ * Both of these locks are to be held with BH safety.
*/
spinlock_t lock;
spinlock_t indirect_lock;
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c
index cf31c0629852..942fae0f2130 100644
--- a/drivers/net/tlan.c
+++ b/drivers/net/tlan.c
@@ -171,6 +171,7 @@
#include <linux/ioport.h>
#include <linux/eisa.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/delay.h>
@@ -566,7 +567,7 @@ static int __devinit TLan_probe1(struct pci_dev *pdev,
priv->adapter = &board_info[ent->driver_data];
- rc = pci_set_dma_mask(pdev, 0xFFFFFFFF);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n");
goto err_out_free_dev;
diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c
index 0d1dcf421771..41e0cd8f4786 100644
--- a/drivers/net/tokenring/3c359.c
+++ b/drivers/net/tokenring/3c359.c
@@ -276,7 +276,8 @@ static void xl_ee_write(struct net_device *dev, int ee_addr, u16 ee_value)
return ;
}
-int __devinit xl_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static int __devinit xl_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct net_device *dev ;
struct xl_private *xl_priv ;
diff --git a/drivers/net/tokenring/3c359_microcode.h b/drivers/net/tokenring/3c359_microcode.h
index 81354afa3d34..0400c029c077 100644
--- a/drivers/net/tokenring/3c359_microcode.h
+++ b/drivers/net/tokenring/3c359_microcode.h
@@ -22,7 +22,7 @@
static int mc_size = 24880 ;
-u8 microcode[] = {
+static const u8 microcode[] = {
0xfe,0x3a,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,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c
index bd4a2bccf867..87103c400999 100644
--- a/drivers/net/tokenring/abyss.c
+++ b/drivers/net/tokenring/abyss.c
@@ -468,14 +468,3 @@ static void __exit abyss_rmmod (void)
module_init(abyss_init);
module_exit(abyss_rmmod);
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c abyss.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c
index 3873917a9c22..e7b001017b9a 100644
--- a/drivers/net/tokenring/ibmtr.c
+++ b/drivers/net/tokenring/ibmtr.c
@@ -151,7 +151,7 @@ static char version[] __initdata =
/* this allows displaying full adapter information */
-char *channel_def[] __devinitdata = { "ISA", "MCA", "ISA P&P" };
+static char *channel_def[] __devinitdata = { "ISA", "MCA", "ISA P&P" };
static char pcchannelid[] __devinitdata = {
0x05, 0x00, 0x04, 0x09,
@@ -171,7 +171,7 @@ static char mcchannelid[] __devinitdata = {
0x03, 0x08, 0x02, 0x00
};
-char __devinit *adapter_def(char type)
+static char __devinit *adapter_def(char type)
{
switch (type) {
case 0xF: return "PC Adapter | PC Adapter II | Adapter/A";
@@ -184,7 +184,7 @@ char __devinit *adapter_def(char type)
#define TRC_INIT 0x01 /* Trace initialization & PROBEs */
#define TRC_INITV 0x02 /* verbose init trace points */
-unsigned char ibmtr_debug_trace = 0;
+static unsigned char ibmtr_debug_trace = 0;
static int ibmtr_probe(struct net_device *dev);
static int ibmtr_probe1(struct net_device *dev, int ioaddr);
@@ -192,20 +192,20 @@ static unsigned char get_sram_size(struct tok_info *adapt_info);
static int trdev_init(struct net_device *dev);
static int tok_open(struct net_device *dev);
static int tok_init_card(struct net_device *dev);
-void tok_open_adapter(unsigned long dev_addr);
+static void tok_open_adapter(unsigned long dev_addr);
static void open_sap(unsigned char type, struct net_device *dev);
static void tok_set_multicast_list(struct net_device *dev);
static int tok_send_packet(struct sk_buff *skb, struct net_device *dev);
static int tok_close(struct net_device *dev);
-irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void initial_tok_int(struct net_device *dev);
static void tr_tx(struct net_device *dev);
static void tr_rx(struct net_device *dev);
-void ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
+static void ibmtr_reset_timer(struct timer_list*tmr,struct net_device *dev);
static void tok_rerun(unsigned long dev_addr);
-void ibmtr_readlog(struct net_device *dev);
+static void ibmtr_readlog(struct net_device *dev);
static struct net_device_stats *tok_get_stats(struct net_device *dev);
-int ibmtr_change_mtu(struct net_device *dev, int mtu);
+static int ibmtr_change_mtu(struct net_device *dev, int mtu);
static void find_turbo_adapters(int *iolist);
static int ibmtr_portlist[IBMTR_MAX_ADAPTERS+1] __devinitdata = {
@@ -928,7 +928,7 @@ static int tok_open(struct net_device *dev)
#define DLC_MAX_SAP_OFST 32
#define DLC_MAX_STA_OFST 33
-void tok_open_adapter(unsigned long dev_addr)
+static void tok_open_adapter(unsigned long dev_addr)
{
struct net_device *dev = (struct net_device *) dev_addr;
struct tok_info *ti;
@@ -1099,7 +1099,7 @@ static void __iomem *map_address(struct tok_info *ti, unsigned index, __u8 *page
return ti->sram_virt + index;
}
-void dir_open_adapter (struct net_device *dev)
+static void dir_open_adapter (struct net_device *dev)
{
struct tok_info *ti = (struct tok_info *) dev->priv;
unsigned char ret_code;
@@ -1172,7 +1172,7 @@ void dir_open_adapter (struct net_device *dev)
/******************************************************************************/
-irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t tok_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
unsigned char status;
/* unsigned char status_even ; */
@@ -1840,7 +1840,7 @@ static void tr_rx(struct net_device *dev)
/*****************************************************************************/
-void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
+static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev)
{
tmr->expires = jiffies + TR_RETRY_INTERVAL;
tmr->data = (unsigned long) dev;
@@ -1872,7 +1872,7 @@ void tok_rerun(unsigned long dev_addr){
/*****************************************************************************/
-void ibmtr_readlog(struct net_device *dev)
+static void ibmtr_readlog(struct net_device *dev)
{
struct tok_info *ti;
@@ -1905,7 +1905,7 @@ static struct net_device_stats *tok_get_stats(struct net_device *dev)
/*****************************************************************************/
-int ibmtr_change_mtu(struct net_device *dev, int mtu)
+static int ibmtr_change_mtu(struct net_device *dev, int mtu)
{
struct tok_info *ti = (struct tok_info *) dev->priv;
diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c
index 99e0b03b69a8..97712c3c4e07 100644
--- a/drivers/net/tokenring/lanstreamer.c
+++ b/drivers/net/tokenring/lanstreamer.c
@@ -118,6 +118,7 @@
#include <linux/stddef.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/spinlock.h>
#include <linux/version.h>
#include <linux/bitops.h>
@@ -257,7 +258,7 @@ static int __devinit streamer_init_one(struct pci_dev *pdev,
#endif
#endif
- rc = pci_set_dma_mask(pdev, 0xFFFFFFFFULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR "%s: No suitable PCI mapping available.\n",
dev->name);
@@ -454,8 +455,7 @@ static int streamer_reset(struct net_device *dev)
writew(readw(streamer_mmio + BCTL) | BCTL_SOFTRESET, streamer_mmio + BCTL);
t = jiffies;
/* Hold soft reset bit for a while */
- current->state = TASK_UNINTERRUPTIBLE;
- schedule_timeout(HZ);
+ ssleep(1);
writew(readw(streamer_mmio + BCTL) & ~BCTL_SOFTRESET,
streamer_mmio + BCTL);
@@ -511,8 +511,7 @@ static int streamer_reset(struct net_device *dev)
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
while (!((readw(streamer_mmio + SISR)) & SISR_SRB_REPLY)) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/10);
+ msleep_interruptible(100);
if (jiffies - t > 40 * HZ) {
printk(KERN_ERR
"IBM PCI tokenring card not responding\n");
diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c
index cfae2bbf2167..659cbdbef7f3 100644
--- a/drivers/net/tokenring/madgemc.c
+++ b/drivers/net/tokenring/madgemc.c
@@ -625,7 +625,7 @@ static int madgemc_chipset_init(struct net_device *dev)
/*
* Disable the board, and put back into power-up state.
*/
-void madgemc_chipset_close(struct net_device *dev)
+static void madgemc_chipset_close(struct net_device *dev)
{
/* disable interrupts */
madgemc_setint(dev, 0);
@@ -786,15 +786,3 @@ module_exit(madgemc_exit);
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c madgemc.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
-
diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c
index 675b063508e3..40ad0fde28af 100644
--- a/drivers/net/tokenring/proteon.c
+++ b/drivers/net/tokenring/proteon.c
@@ -419,14 +419,3 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c proteon.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c
index 3fab54a26466..f26796e2d0e5 100644
--- a/drivers/net/tokenring/skisa.c
+++ b/drivers/net/tokenring/skisa.c
@@ -429,14 +429,3 @@ void cleanup_module(void)
}
#endif /* MODULE */
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c skisa.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c skisa.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c
index 5c8aeacb8318..67d2b596ce22 100644
--- a/drivers/net/tokenring/smctr.c
+++ b/drivers/net/tokenring/smctr.c
@@ -77,7 +77,7 @@ static int ringspeed;
/* SMC Name of the Adapter. */
static char smctr_name[] = "SMC TokenCard";
-char *smctr_model = "Unknown";
+static char *smctr_model = "Unknown";
/* Use 0 for production, 1 for verification, 2 for debug, and
* 3 for very verbose debug.
diff --git a/drivers/net/tokenring/smctr_firmware.h b/drivers/net/tokenring/smctr_firmware.h
index 53f2cbc817c9..48994b043b7c 100644
--- a/drivers/net/tokenring/smctr_firmware.h
+++ b/drivers/net/tokenring/smctr_firmware.h
@@ -21,7 +21,7 @@
#if defined(CONFIG_SMCTR) || defined(CONFIG_SMCTR_MODULE)
-unsigned char smctr_code[] = {
+static const unsigned char smctr_code[] = {
0x0BC, 0x01D, 0x012, 0x03B, 0x063, 0x0B4, 0x0E9, 0x000,
0x000, 0x01F, 0x000, 0x001, 0x001, 0x000, 0x002, 0x005,
0x001, 0x000, 0x006, 0x003, 0x001, 0x000, 0x004, 0x009,
diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c
index df43b449e429..5e0b0ce98ed7 100644
--- a/drivers/net/tokenring/tms380tr.c
+++ b/drivers/net/tokenring/tms380tr.c
@@ -2379,7 +2379,7 @@ EXPORT_SYMBOL(tmsdev_init);
EXPORT_SYMBOL(tmsdev_term);
EXPORT_SYMBOL(tms380tr_wait);
-struct module *TMS380_module = NULL;
+static struct module *TMS380_module = NULL;
int init_module(void)
{
@@ -2397,14 +2397,3 @@ void cleanup_module(void)
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tms380tr.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c
index 37ddb5c2bec3..2e18c0a46482 100644
--- a/drivers/net/tokenring/tmspci.c
+++ b/drivers/net/tokenring/tmspci.c
@@ -254,14 +254,3 @@ static void __exit tms_pci_rmmod (void)
module_init(tms_pci_init);
module_exit(tms_pci_rmmod);
-
-/*
- * Local variables:
- * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c"
- * alt-compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -I/usr/src/linux/drivers/net/tokenring/ -c tmspci.c"
- * c-set-style "K&R"
- * c-indent-level: 8
- * c-basic-offset: 8
- * tab-width: 8
- * End:
- */
diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
index dd357dd8c370..fc353e348f9a 100644
--- a/drivers/net/tulip/de2104x.c
+++ b/drivers/net/tulip/de2104x.c
@@ -446,13 +446,13 @@ static void de_rx (struct de_private *de)
mapping =
de->rx_skb[rx_tail].mapping =
- pci_map_single(de->pdev, copy_skb->tail,
+ pci_map_single(de->pdev, copy_skb->data,
buflen, PCI_DMA_FROMDEVICE);
de->rx_skb[rx_tail].skb = copy_skb;
} else {
pci_dma_sync_single_for_cpu(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
skb_reserve(copy_skb, RX_OFFSET);
- memcpy(skb_put(copy_skb, len), skb->tail, len);
+ memcpy(skb_put(copy_skb, len), skb->data, len);
pci_dma_sync_single_for_device(de->pdev, mapping, len, PCI_DMA_FROMDEVICE);
@@ -1269,7 +1269,7 @@ static int de_refill_rx (struct de_private *de)
skb->dev = de->dev;
de->rx_skb[i].mapping = pci_map_single(de->pdev,
- skb->tail, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ skb->data, de->rx_buf_sz, PCI_DMA_FROMDEVICE);
de->rx_skb[i].skb = skb;
de->rx_ring[i].opts1 = cpu_to_le32(DescOwn);
diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
index e25f33df223e..74e9075d9c48 100644
--- a/drivers/net/tulip/dmfe.c
+++ b/drivers/net/tulip/dmfe.c
@@ -78,6 +78,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
@@ -354,7 +355,7 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev,
SET_MODULE_OWNER(dev);
SET_NETDEV_DEV(dev, &pdev->dev);
- if (pci_set_dma_mask(pdev, 0xffffffff)) {
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
err = -ENODEV;
goto err_out_free;
@@ -743,11 +744,6 @@ static irqreturn_t dmfe_interrupt(int irq, void *dev_id, struct pt_regs *regs)
DMFE_DBUG(0, "dmfe_interrupt()", 0);
- if (!dev) {
- DMFE_DBUG(1, "dmfe_interrupt() without DEVICE arg", 0);
- return IRQ_NONE;
- }
-
spin_lock_irqsave(&db->lock, flags);
/* Got DM910X status */
@@ -949,8 +945,8 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
/* Received Packet CRC check need or not */
if ( (db->dm910x_chk_mode & 1) &&
- (cal_CRC(skb->tail, rxlen, 1) !=
- (*(u32 *) (skb->tail+rxlen) ))) { /* FIXME (?) */
+ (cal_CRC(skb->data, rxlen, 1) !=
+ (*(u32 *) (skb->data+rxlen) ))) { /* FIXME (?) */
/* Found a error received packet */
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
db->dm910x_chk_mode = 3;
@@ -963,7 +959,7 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db)
/* size less than COPY_SIZE, allocate a rxlen SKB */
skb->dev = dev;
skb_reserve(skb, 2); /* 16byte align */
- memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->tail, rxlen);
+ memcpy(skb_put(skb, rxlen), rxptr->rx_skb_ptr->data, rxlen);
dmfe_reuse_skb(db, rxptr->rx_skb_ptr);
} else {
skb->dev = dev;
@@ -1256,7 +1252,7 @@ static void dmfe_reuse_skb(struct dmfe_board_info *db, struct sk_buff * skb)
if (!(rxptr->rdes0 & cpu_to_le32(0x80000000))) {
rxptr->rx_skb_ptr = skb;
- rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
db->rx_avail_cnt++;
@@ -1467,7 +1463,7 @@ static void allocate_rx_buffer(struct dmfe_board_info *db)
if ( ( skb = dev_alloc_skb(RX_ALLOC_SIZE) ) == NULL )
break;
rxptr->rx_skb_ptr = skb; /* FIXME (?) */
- rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->tail, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
+ rxptr->rdes2 = cpu_to_le32( pci_map_single(db->pdev, skb->data, RX_ALLOC_SIZE, PCI_DMA_FROMDEVICE) );
wmb();
rxptr->rdes0 = cpu_to_le32(0x80000000);
rxptr = rxptr->next_rx_desc;
@@ -1806,7 +1802,7 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
if ( ( (int) srom[18] & 0xff) == SROM_V41_CODE) {
/* SROM V4.01 */
/* Get NIC support media mode */
- db->NIC_capability = le16_to_cpup(srom + 34);
+ db->NIC_capability = le16_to_cpup((__le16 *)srom + 34/2);
db->PHY_reg4 = 0;
for (tmp_reg = 1; tmp_reg < 0x10; tmp_reg <<= 1) {
switch( db->NIC_capability & tmp_reg ) {
@@ -1818,7 +1814,8 @@ static void dmfe_parse_srom(struct dmfe_board_info * db)
}
/* Media Mode Force or not check */
- dmfe_mode = le32_to_cpup(srom + 34) & le32_to_cpup(srom + 36);
+ dmfe_mode = le32_to_cpup((__le32 *)srom + 34/4) &
+ le32_to_cpup((__le32 *)srom + 36/4);
switch(dmfe_mode) {
case 0x4: dmfe_media_mode = DMFE_100MHF; break; /* 100MHF */
case 0x2: dmfe_media_mode = DMFE_10MFD; break; /* 10MFD */
diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c
index ac5bf49ff60f..fbd9ab60b052 100644
--- a/drivers/net/tulip/eeprom.c
+++ b/drivers/net/tulip/eeprom.c
@@ -63,6 +63,22 @@ static struct eeprom_fixup eeprom_fixups[] __devinitdata = {
*/
{ 0x1e00, 0x0000, 0x000b, 0x8f01, 0x0103, 0x0300, 0x0821, 0x000, 0x0001, 0x0000, 0x01e1 }
},
+ {"Cobalt Microserver", 0, 0x10, 0xE0, {0x1e00, /* 0 == controller #, 1e == offset */
+ 0x0000, /* 0 == high offset, 0 == gap */
+ 0x0800, /* Default Autoselect */
+ 0x8001, /* 1 leaf, extended type, bogus len */
+ 0x0003, /* Type 3 (MII), PHY #0 */
+ 0x0400, /* 0 init instr, 4 reset instr */
+ 0x0801, /* Set control mode, GP0 output */
+ 0x0000, /* Drive GP0 Low (RST is active low) */
+ 0x0800, /* control mode, GP0 input (undriven) */
+ 0x0000, /* clear control mode */
+ 0x7800, /* 100TX FDX + HDX, 10bT FDX + HDX */
+ 0x01e0, /* Advertise all above */
+ 0x5000, /* FDX all above */
+ 0x1800, /* Set fast TTM in 100bt modes */
+ 0x0000, /* PHY cannot be unplugged */
+ }},
{NULL}};
diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c
index afb5cda9d8e1..bb3558164a5b 100644
--- a/drivers/net/tulip/interrupt.c
+++ b/drivers/net/tulip/interrupt.c
@@ -78,7 +78,7 @@ int tulip_refill_rx(struct net_device *dev)
if (skb == NULL)
break;
- mapping = pci_map_single(tp->pdev, skb->tail, PKT_BUF_SZ,
+ mapping = pci_map_single(tp->pdev, skb->data, PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
tp->rx_buffers[entry].mapping = mapping;
@@ -199,12 +199,12 @@ int tulip_poll(struct net_device *dev, int *budget)
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
- eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
+ eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
pkt_len, 0);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
- tp->rx_buffers[entry].skb->tail,
+ tp->rx_buffers[entry].skb->data,
pkt_len);
#endif
pci_dma_sync_single_for_device(tp->pdev,
@@ -423,12 +423,12 @@ static int tulip_rx(struct net_device *dev)
tp->rx_buffers[entry].mapping,
pkt_len, PCI_DMA_FROMDEVICE);
#if ! defined(__alpha__)
- eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->tail,
+ eth_copy_and_sum(skb, tp->rx_buffers[entry].skb->data,
pkt_len, 0);
skb_put(skb, pkt_len);
#else
memcpy(skb_put(skb, pkt_len),
- tp->rx_buffers[entry].skb->tail,
+ tp->rx_buffers[entry].skb->data,
pkt_len);
#endif
pci_dma_sync_single_for_device(tp->pdev,
diff --git a/drivers/net/tulip/media.c b/drivers/net/tulip/media.c
index 919c40cd635c..e26c31f944bf 100644
--- a/drivers/net/tulip/media.c
+++ b/drivers/net/tulip/media.c
@@ -400,6 +400,9 @@ void tulip_select_media(struct net_device *dev, int startup)
}
tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+
+ mdelay(1);
+
return;
}
diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
index e0ae3ed6e578..d45d8f56e5b4 100644
--- a/drivers/net/tulip/tulip_core.c
+++ b/drivers/net/tulip/tulip_core.c
@@ -242,6 +242,7 @@ static struct pci_device_id tulip_pci_tbl[] = {
{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */
{ 0x10b9, 0x5263, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ULI526X }, /* ALi 1563 integrated ethernet */
{ 0x10b7, 0x9300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* 3Com 3CSOHO100B-TX */
+ { 0x14ea, 0xab08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET }, /* Planex FNW-3602-TX */
{ } /* terminate list */
};
MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -624,7 +625,7 @@ static void tulip_init_ring(struct net_device *dev)
tp->rx_buffers[i].skb = skb;
if (skb == NULL)
break;
- mapping = pci_map_single(tp->pdev, skb->tail,
+ mapping = pci_map_single(tp->pdev, skb->data,
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
tp->rx_buffers[i].mapping = mapping;
skb->dev = dev; /* Mark as being used by this device. */
@@ -1514,8 +1515,8 @@ static int __devinit tulip_init_one (struct pci_dev *pdev,
(PCI_SLOT(pdev->devfn) == 12))) {
/* Cobalt MAC address in first EEPROM locations. */
sa_offset = 0;
- /* No media table either */
- tp->flags &= ~HAS_MEDIA_TABLE;
+ /* Ensure our media table fixup get's applied */
+ memcpy(ee_data + 16, ee_data, 8);
}
#endif
#ifdef CONFIG_GSC
@@ -1756,11 +1757,19 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
- if (dev && netif_running (dev) && netif_device_present (dev)) {
- netif_device_detach (dev);
- tulip_down (dev);
- /* pci_power_off(pdev, -1); */
- }
+ if (!dev)
+ return -EINVAL;
+
+ if (netif_running(dev))
+ tulip_down(dev);
+
+ netif_device_detach(dev);
+ free_irq(dev->irq, dev);
+
+ pci_save_state(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
return 0;
}
@@ -1768,15 +1777,26 @@ static int tulip_suspend (struct pci_dev *pdev, pm_message_t state)
static int tulip_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
+ int retval;
- if (dev && netif_running (dev) && !netif_device_present (dev)) {
-#if 1
- pci_enable_device (pdev);
-#endif
- /* pci_power_on(pdev); */
- tulip_up (dev);
- netif_device_attach (dev);
+ if (!dev)
+ return -EINVAL;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+
+ pci_enable_device(pdev);
+
+ if ((retval = request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))) {
+ printk (KERN_ERR "tulip: request_irq failed in resume\n");
+ return retval;
}
+
+ netif_device_attach(dev);
+
+ if (netif_running(dev))
+ tulip_up(dev);
+
return 0;
}
diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
index caff2f590165..5b1af3986abf 100644
--- a/drivers/net/tulip/winbond-840.c
+++ b/drivers/net/tulip/winbond-840.c
@@ -121,6 +121,7 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -394,7 +395,7 @@ static int __devinit w840_probe1 (struct pci_dev *pdev,
irq = pdev->irq;
- if (pci_set_dma_mask(pdev,0xFFFFffff)) {
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "Winbond-840: Device %s disabled due to DMA limitations.\n",
pci_name(pdev));
return -EIO;
@@ -848,7 +849,7 @@ static void init_rxtx_rings(struct net_device *dev)
if (skb == NULL)
break;
skb->dev = dev; /* Mark as being used by this device. */
- np->rx_addr[i] = pci_map_single(np->pci_dev,skb->tail,
+ np->rx_addr[i] = pci_map_single(np->pci_dev,skb->data,
skb->len,PCI_DMA_FROMDEVICE);
np->rx_ring[i].buffer1 = np->rx_addr[i];
@@ -1268,7 +1269,7 @@ static int netdev_rx(struct net_device *dev)
pci_dma_sync_single_for_cpu(np->pci_dev,np->rx_addr[entry],
np->rx_skbuff[entry]->len,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(skb, np->rx_skbuff[entry]->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, np->rx_skbuff[entry]->data, pkt_len, 0);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(np->pci_dev,np->rx_addr[entry],
np->rx_skbuff[entry]->len,
@@ -1314,7 +1315,7 @@ static int netdev_rx(struct net_device *dev)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
np->rx_addr[entry] = pci_map_single(np->pci_dev,
- skb->tail,
+ skb->data,
skb->len, PCI_DMA_FROMDEVICE);
np->rx_ring[entry].buffer1 = np->rx_addr[entry];
}
diff --git a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
index b8a9b395c5ea..887d7245fe7b 100644
--- a/drivers/net/tulip/xircom_tulip_cb.c
+++ b/drivers/net/tulip/xircom_tulip_cb.c
@@ -899,7 +899,7 @@ static void xircom_init_ring(struct net_device *dev)
break;
skb->dev = dev; /* Mark as being used by this device. */
tp->rx_ring[i].status = Rx0DescOwned; /* Owned by Xircom chip */
- tp->rx_ring[i].buffer1 = virt_to_bus(skb->tail);
+ tp->rx_ring[i].buffer1 = virt_to_bus(skb->data);
}
tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1291,7 +1291,7 @@ xircom_rx(struct net_device *dev)
if (skb == NULL)
break;
skb->dev = dev; /* Mark as being used by this device. */
- tp->rx_ring[entry].buffer1 = virt_to_bus(skb->tail);
+ tp->rx_ring[entry].buffer1 = virt_to_bus(skb->data);
work_done++;
}
tp->rx_ring[entry].status = Rx0DescOwned;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 7bfee366297b..effab0b9adca 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -215,7 +215,7 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
poll_wait(file, &tun->read_wait, wait);
- if (skb_queue_len(&tun->readq))
+ if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;
return mask;
diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c
index 8f3392989a06..ecfa6f8805ce 100644
--- a/drivers/net/typhoon.c
+++ b/drivers/net/typhoon.c
@@ -1661,7 +1661,7 @@ typhoon_alloc_rx_skb(struct typhoon *tp, u32 idx)
#endif
skb->dev = tp->dev;
- dma_addr = pci_map_single(tp->pdev, skb->tail,
+ dma_addr = pci_map_single(tp->pdev, skb->data,
PKT_BUF_SZ, PCI_DMA_FROMDEVICE);
/* Since no card does 64 bit DAC, the high bits will never
@@ -1721,7 +1721,7 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile u32 * ready,
pci_dma_sync_single_for_cpu(tp->pdev, dma_addr,
PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
- eth_copy_and_sum(new_skb, skb->tail, pkt_len, 0);
+ eth_copy_and_sum(new_skb, skb->data, pkt_len, 0);
pci_dma_sync_single_for_device(tp->pdev, dma_addr,
PKT_BUF_SZ,
PCI_DMA_FROMDEVICE);
@@ -1906,9 +1906,9 @@ typhoon_sleep(struct typhoon *tp, pci_power_t state, u16 events)
*/
netif_carrier_off(tp->dev);
- pci_enable_wake(tp->pdev, pci_choose_state(pdev, state), 1);
+ pci_enable_wake(tp->pdev, state, 1);
pci_disable_device(pdev);
- return pci_set_power_state(pdev, pci_choose_state(pdev, state));
+ return pci_set_power_state(pdev, state);
}
static int
@@ -2274,7 +2274,7 @@ typhoon_suspend(struct pci_dev *pdev, pm_message_t state)
goto need_resume;
}
- if(typhoon_sleep(tp, state, tp->wol_events) < 0) {
+ if(typhoon_sleep(tp, pci_choose_state(pdev, state), tp->wol_events) < 0) {
printk(KERN_ERR "%s: unable to put card to sleep\n", dev->name);
goto need_resume;
}
diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
index 7b57d552094a..fc7738ffbfff 100644
--- a/drivers/net/via-rhine.c
+++ b/drivers/net/via-rhine.c
@@ -186,6 +186,7 @@ static const int multicast_filter_limit = 32;
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -506,7 +507,7 @@ 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);
+static void rhine_shutdown (struct pci_dev *pdev);
#define RHINE_WAIT_FOR(condition) do { \
int i=1024; \
@@ -740,7 +741,7 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
goto err_out;
/* this should always be supported */
- rc = pci_set_dma_mask(pdev, 0xffffffff);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc) {
printk(KERN_ERR "32-bit PCI DMA addresses not supported by "
"the card!?\n");
@@ -989,7 +990,7 @@ static void alloc_rbufs(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
rp->rx_skbuff_dma[i] =
- pci_map_single(rp->pdev, skb->tail, rp->rx_buf_sz,
+ pci_map_single(rp->pdev, skb->data, rp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
rp->rx_ring[i].addr = cpu_to_le32(rp->rx_skbuff_dma[i]);
@@ -1397,7 +1398,7 @@ static void rhine_tx(struct net_device *dev)
while (rp->dirty_tx != rp->cur_tx) {
txstatus = le32_to_cpu(rp->tx_ring[entry].tx_status);
if (debug > 6)
- printk(KERN_DEBUG " Tx scavenge %d status %8.8x.\n",
+ printk(KERN_DEBUG "Tx scavenge %d status %8.8x.\n",
entry, txstatus);
if (txstatus & DescOwn)
break;
@@ -1468,7 +1469,7 @@ static void rhine_rx(struct net_device *dev)
int data_size = desc_status >> 16;
if (debug > 4)
- printk(KERN_DEBUG " rhine_rx() status is %8.8x.\n",
+ printk(KERN_DEBUG "rhine_rx() status is %8.8x.\n",
desc_status);
if (--boguscnt < 0)
break;
@@ -1486,7 +1487,7 @@ static void rhine_rx(struct net_device *dev)
} else if (desc_status & RxErr) {
/* There was a error. */
if (debug > 2)
- printk(KERN_DEBUG " rhine_rx() Rx "
+ printk(KERN_DEBUG "rhine_rx() Rx "
"error was %8.8x.\n",
desc_status);
rp->stats.rx_errors++;
@@ -1517,7 +1518,7 @@ static void rhine_rx(struct net_device *dev)
PCI_DMA_FROMDEVICE);
eth_copy_and_sum(skb,
- rp->rx_skbuff[entry]->tail,
+ rp->rx_skbuff[entry]->data,
pkt_len, 0);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(rp->pdev,
@@ -1560,7 +1561,7 @@ static void rhine_rx(struct net_device *dev)
break; /* Better luck next round. */
skb->dev = dev; /* Mark as being used by this device. */
rp->rx_skbuff_dma[entry] =
- pci_map_single(rp->pdev, skb->tail,
+ pci_map_single(rp->pdev, skb->data,
rp->rx_buf_sz,
PCI_DMA_FROMDEVICE);
rp->rx_ring[entry].addr = cpu_to_le32(rp->rx_skbuff_dma[entry]);
@@ -1894,9 +1895,8 @@ static void __devexit rhine_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
-static void rhine_shutdown (struct device *gendev)
+static void rhine_shutdown (struct pci_dev *pdev)
{
- struct pci_dev *pdev = to_pci_dev(gendev);
struct net_device *dev = pci_get_drvdata(pdev);
struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
@@ -1955,7 +1955,7 @@ static int rhine_suspend(struct pci_dev *pdev, pm_message_t state)
pci_save_state(pdev);
spin_lock_irqsave(&rp->lock, flags);
- rhine_shutdown(&pdev->dev);
+ rhine_shutdown(pdev);
spin_unlock_irqrestore(&rp->lock, flags);
free_irq(dev->irq, dev);
@@ -2009,9 +2009,7 @@ static struct pci_driver rhine_driver = {
.suspend = rhine_suspend,
.resume = rhine_resume,
#endif /* CONFIG_PM */
- .driver = {
- .shutdown = rhine_shutdown,
- }
+ .shutdown = rhine_shutdown,
};
diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c
index 15e710283493..abc5cee6eedc 100644
--- a/drivers/net/via-velocity.c
+++ b/drivers/net/via-velocity.c
@@ -1335,7 +1335,7 @@ static inline int velocity_rx_copy(struct sk_buff **rx_skb, int pkt_size,
if (vptr->flags & VELOCITY_FLAGS_IP_ALIGN)
skb_reserve(new_skb, 2);
- memcpy(new_skb->data, rx_skb[0]->tail, pkt_size);
+ memcpy(new_skb->data, rx_skb[0]->data, pkt_size);
*rx_skb = new_skb;
ret = 0;
}
@@ -1456,9 +1456,9 @@ static int velocity_alloc_rx_buf(struct velocity_info *vptr, int idx)
* Do the gymnastics to get the buffer head for data at
* 64byte alignment.
*/
- skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->tail & 63);
+ skb_reserve(rd_info->skb, (unsigned long) rd_info->skb->data & 63);
rd_info->skb->dev = vptr->dev;
- rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->tail, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
+ rd_info->skb_dma = pci_map_single(vptr->pdev, rd_info->skb->data, vptr->rx_buf_sz, PCI_DMA_FROMDEVICE);
/*
* Fill in the descriptor to match
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 66b94668ddd8..18c27e1e7884 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -435,7 +435,7 @@ config VENDOR_SANGOMA
the driver to support.
If you have one or more of these cards, say M to this option;
- and read <file:Documentation/networking/wanpipe.txt>.
+ and read <file:Documentation/networking/wan-router.txt>.
To compile this driver as a module, choose M here: the
module will be called wanpipe.
diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c
index 7575b799ce53..2c83cca34b86 100644
--- a/drivers/net/wan/farsync.c
+++ b/drivers/net/wan/farsync.c
@@ -861,8 +861,7 @@ fst_tx_dma_complete(struct fst_card_info *card, struct fst_port_info *port,
/*
* Mark it for our own raw sockets interface
*/
-static unsigned short farsync_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static __be16 farsync_type_trans(struct sk_buff *skb, struct net_device *dev)
{
skb->dev = dev;
skb->mac.raw = skb->data;
@@ -981,6 +980,7 @@ fst_issue_cmd(struct fst_port_info *port, unsigned short cmd)
/* Wait for any previous command to complete */
while (mbval > NAK) {
spin_unlock_irqrestore(&card->card_lock, flags);
+ set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(1);
spin_lock_irqsave(&card->card_lock, flags);
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index c1b6896d7007..48c03c11cd9a 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -72,7 +72,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
}
skb_reserve(skb, 4);
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
- data = (cisco_packet*)skb->tail;
+ data = (cisco_packet*)skb->data;
data->type = htonl(type);
data->par1 = htonl(par1);
@@ -91,8 +91,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
-static unsigned short cisco_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
{
hdlc_header *data = (hdlc_header*)skb->data;
diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c
index 7cd6195a2e46..b81263eaede0 100644
--- a/drivers/net/wan/hdlc_ppp.c
+++ b/drivers/net/wan/hdlc_ppp.c
@@ -66,8 +66,7 @@ static void ppp_close(struct net_device *dev)
-static unsigned short ppp_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
{
return __constant_htons(ETH_P_WAN_PPP);
}
diff --git a/drivers/net/wan/hdlc_raw.c b/drivers/net/wan/hdlc_raw.c
index c41fb70b6929..9456d31cb1c1 100644
--- a/drivers/net/wan/hdlc_raw.c
+++ b/drivers/net/wan/hdlc_raw.c
@@ -24,8 +24,7 @@
#include <linux/hdlc.h>
-static unsigned short raw_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
{
return __constant_htons(ETH_P_IP);
}
diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c
index 1e7b47704ad9..9c1e10602f2b 100644
--- a/drivers/net/wan/wanxl.c
+++ b/drivers/net/wan/wanxl.c
@@ -26,6 +26,7 @@
#include <linux/netdevice.h>
#include <linux/hdlc.h>
#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/delay.h>
@@ -624,8 +625,8 @@ static int __devinit wanxl_pci_init_one(struct pci_dev *pdev,
/* FIXME when PCI/DMA subsystems are fixed.
We set both dma_mask and consistent_dma_mask back to 32 bits
to indicate the card can do 32-bit DMA addressing */
- if (pci_set_consistent_dma_mask(pdev, 0xFFFFFFFF) ||
- pci_set_dma_mask(pdev, 0xFFFFFFFF)) {
+ if (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) ||
+ pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
printk(KERN_ERR "wanXL: No usable DMA configuration\n");
wanxl_pci_remove_one(pdev);
return -EIO;
diff --git a/drivers/net/wd.c b/drivers/net/wd.c
index 1f05d9bd05e4..b03feae459fc 100644
--- a/drivers/net/wd.c
+++ b/drivers/net/wd.c
@@ -149,12 +149,7 @@ struct net_device * __init wd_probe(int unit)
err = do_wd_probe(dev);
if (err)
goto out;
- err = register_netdev(dev);
- if (err)
- goto out1;
return dev;
-out1:
- cleanup_card(dev);
out:
free_netdev(dev);
return ERR_PTR(err);
@@ -164,6 +159,7 @@ out:
static int __init wd_probe1(struct net_device *dev, int ioaddr)
{
int i;
+ int err;
int checksum = 0;
int ancient = 0; /* An old card without config registers. */
int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */
@@ -356,7 +352,10 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr)
outb(inb(ioaddr+4)|0x80, ioaddr+4);
#endif
- return 0;
+ err = register_netdev(dev);
+ if (err)
+ free_irq(dev->irq, dev);
+ return err;
}
static int
@@ -527,11 +526,8 @@ init_module(void)
dev->mem_start = mem[this_dev];
dev->mem_end = mem_end[this_dev];
if (do_wd_probe(dev) == 0) {
- if (register_netdev(dev) == 0) {
- dev_wd[found++] = dev;
- continue;
- }
- cleanup_card(dev);
+ dev_wd[found++] = dev;
+ continue;
}
free_netdev(dev);
printk(KERN_WARNING "wd.c: No wd80x3 card found (i/o = 0x%x).\n", io[this_dev]);
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
index fb10a2db63ad..47f3c5d0203d 100644
--- a/drivers/net/wireless/airo.c
+++ b/drivers/net/wireless/airo.c
@@ -900,7 +900,7 @@ typedef struct aironet_ioctl {
unsigned char __user *data; // d-data
} aironet_ioctl;
-static char *swversion = "2.1";
+static char swversion[] = "2.1";
#endif /* CISCO_EXT */
#define NUM_MODULES 2
@@ -1209,7 +1209,7 @@ struct airo_info {
unsigned char __iomem *pciaux;
unsigned char *shared;
dma_addr_t shared_dma;
- int power;
+ pm_message_t power;
SsidRid *SSID;
APListRid *APList;
#define PCI_SHARED_LEN 2*MPI_MAX_FIDS*PKTSIZE+RIDSIZE
@@ -2374,7 +2374,7 @@ void stop_airo_card( struct net_device *dev, int freeres )
/*
* Clean out tx queue
*/
- if (test_bit(FLAG_MPI, &ai->flags) && skb_queue_len (&ai->txq) > 0) {
+ if (test_bit(FLAG_MPI, &ai->flags) && !skb_queue_empty(&ai->txq)) {
struct sk_buff *skb = NULL;
for (;(skb = skb_dequeue(&ai->txq));)
dev_kfree_skb(skb);
@@ -2918,7 +2918,7 @@ static int airo_thread(void *data) {
flush_signals(current);
/* make swsusp happy with our thread */
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
if (test_bit(JOB_DIE, &ai->flags))
break;
@@ -3287,7 +3287,7 @@ exitrx:
if (status & EV_TXEXC)
get_tx_error(apriv, -1);
spin_lock_irqsave(&apriv->aux_lock, flags);
- if (skb_queue_len (&apriv->txq)) {
+ if (!skb_queue_empty(&apriv->txq)) {
spin_unlock_irqrestore(&apriv->aux_lock,flags);
mpi_send_packet (dev);
} else {
@@ -5499,9 +5499,9 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state)
cmd.cmd=HOSTSLEEP;
issuecommand(ai, &cmd, &rsp);
- pci_enable_wake(pdev, state, 1);
+ pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
pci_save_state(pdev);
- return pci_set_power_state(pdev, state);
+ return pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
static int airo_pci_resume(struct pci_dev *pdev)
@@ -5512,7 +5512,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
pci_set_power_state(pdev, 0);
pci_restore_state(pdev);
- pci_enable_wake(pdev, ai->power, 0);
+ pci_enable_wake(pdev, pci_choose_state(pdev, ai->power), 0);
if (ai->power > 1) {
reset_card(dev, 0);
@@ -5541,7 +5541,7 @@ static int airo_pci_resume(struct pci_dev *pdev)
}
writeConfigRid(ai, 0);
enable_MAC(ai, &rsp, 0);
- ai->power = 0;
+ ai->power = PMSG_ON;
netif_device_attach(dev);
netif_wake_queue(dev);
enable_interrupts(ai);
diff --git a/drivers/net/wireless/airo_cs.c b/drivers/net/wireless/airo_cs.c
index fbf53af6cda4..bf25584d68d3 100644
--- a/drivers/net/wireless/airo_cs.c
+++ b/drivers/net/wireless/airo_cs.c
@@ -33,7 +33,6 @@
#include <linux/timer.h>
#include <linux/netdevice.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -210,11 +209,6 @@ static dev_link_t *airo_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &airo_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -559,13 +553,24 @@ static int airo_event(event_t event, int priority,
return 0;
} /* airo_event */
+static struct pcmcia_device_id airo_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x015f, 0x000a),
+ PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0005),
+ PCMCIA_DEVICE_MANF_CARD(0x015f, 0x0007),
+ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x0007),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, airo_ids);
+
static struct pcmcia_driver airo_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "airo_cs",
},
.attach = airo_attach,
+ .event = airo_event,
.detach = airo_detach,
+ .id_table = airo_ids,
};
static int airo_cs_init(void)
diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c
index b4f4bd7956a2..9d496703c465 100644
--- a/drivers/net/wireless/airport.c
+++ b/drivers/net/wireless/airport.c
@@ -184,7 +184,7 @@ static int airport_hard_reset(struct orinoco_private *priv)
}
static int
-airport_attach(struct macio_dev *mdev, const struct of_match *match)
+airport_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
struct orinoco_private *priv;
struct net_device *dev;
@@ -266,16 +266,16 @@ MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
MODULE_LICENSE("Dual MPL/GPL");
-static struct of_match airport_match[] =
+static struct of_device_id airport_match[] =
{
{
.name = "radio",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{},
};
+MODULE_DEVICE_TABLE (of, airport_match);
+
static struct macio_driver airport_driver =
{
.name = DRIVER_NAME,
diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c
index 4f304c6e693a..0e1ac338cac1 100644
--- a/drivers/net/wireless/arlan-main.c
+++ b/drivers/net/wireless/arlan-main.c
@@ -33,8 +33,6 @@ static int arlan_EEPROM_bad;
#ifdef ARLAN_DEBUGGING
-static int arlan_entry_debug;
-static int arlan_exit_debug;
static int testMemory = testMemoryUNKNOWN;
static int irq = irqUNKNOWN;
static int txScrambled = 1;
@@ -43,15 +41,13 @@ static int mdebug;
module_param(irq, int, 0);
module_param(mdebug, int, 0);
module_param(testMemory, int, 0);
-module_param(arlan_entry_debug, int, 0);
-module_param(arlan_exit_debug, int, 0);
module_param(txScrambled, int, 0);
MODULE_PARM_DESC(irq, "(unused)");
MODULE_PARM_DESC(testMemory, "(unused)");
MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)");
#endif
-module_param(arlan_debug, int, 0);
+module_param_named(debug, arlan_debug, int, 0);
module_param(spreadingCode, int, 0);
module_param(channelNumber, int, 0);
module_param(channelSet, int, 0);
@@ -63,17 +59,19 @@ module_param(keyStart, int, 0);
module_param(tx_delay_ms, int, 0);
module_param(retries, int, 0);
module_param(tx_queue_len, int, 0);
-module_param(arlan_EEPROM_bad, int, 0);
-MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)");
+module_param_named(EEPROM_bad, arlan_EEPROM_bad, int, 0);
+MODULE_PARM_DESC(debug, "Arlan debug enable (0-1)");
MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions");
#ifdef ARLAN_ENTRY_EXIT_DEBUGGING
-MODULE_PARM_DESC(arlan_entry_debug, "Arlan driver function entry debugging");
-MODULE_PARM_DESC(arlan_exit_debug, "Arlan driver function exit debugging");
-MODULE_PARM_DESC(arlan_entry_and_exit_debug, "Arlan driver function entry and exit debugging");
-#else
-MODULE_PARM_DESC(arlan_entry_debug, "(ignored)");
-MODULE_PARM_DESC(arlan_exit_debug, "(ignored)");
-MODULE_PARM_DESC(arlan_entry_and_exit_debug, "(ignored)");
+static int arlan_entry_debug;
+static int arlan_exit_debug;
+static int arlan_entry_and_exit_debug;
+module_param_named(entry_debug, arlan_entry_debug, int, 0);
+module_param_named(exit_debug, arlan_exit_debug, int, 0);
+module_param_named(entry_and_exit_debug, arlan_entry_and_exit_debug, int, 0);
+MODULE_PARM_DESC(entry_debug, "Arlan driver function entry debugging");
+MODULE_PARM_DESC(exit_debug, "Arlan driver function exit debugging");
+MODULE_PARM_DESC(entry_and_exit_debug, "Arlan driver function entry and exit debugging");
#endif
struct arlan_conf_stru arlan_conf[MAX_ARLANS];
diff --git a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c
index a4ed28d9c783..ff031a3985b3 100644
--- a/drivers/net/wireless/atmel_cs.c
+++ b/drivers/net/wireless/atmel_cs.c
@@ -43,7 +43,6 @@
#include <linux/moduleparam.h>
#include <linux/device.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -218,11 +217,6 @@ static dev_link_t *atmel_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &atmel_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -646,13 +640,36 @@ static int atmel_event(event_t event, int priority,
} /* atmel_event */
/*====================================================================*/
+static struct pcmcia_device_id atmel_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0620),
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0696),
+ PCMCIA_DEVICE_MANF_CARD(0x01bf, 0x3302),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0007),
+ PCMCIA_DEVICE_PROD_ID12("11WAVE", "11WP611AL-E", 0x9eb2da1f, 0xc9a0d3f9),
+ PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C502AR", 0xabda4164, 0x41b37e1f),
+ PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504", 0xabda4164, 0x5040670a),
+ PCMCIA_DEVICE_PROD_ID12("ATMEL", "AT76C504A", 0xabda4164, 0xe15ed87f),
+ PCMCIA_DEVICE_PROD_ID12("BT", "Voyager 1020 Laptop Adapter", 0xae49b86a, 0x1e957cd5),
+ PCMCIA_DEVICE_PROD_ID12("CNet", "CNWLC 11Mbps Wireless PC Card V-5", 0xbc477dde, 0x502fae6b),
+ PCMCIA_DEVICE_PROD_ID12("IEEE 802.11b", "Wireless LAN PC Card", 0x5b878724, 0x122f1df6),
+ PCMCIA_DEVICE_PROD_ID12("OEM", "11Mbps Wireless LAN PC Card V-3", 0xfea54c90, 0x1c5b0f68),
+ PCMCIA_DEVICE_PROD_ID12("SMC", "2632W", 0xc4f8b18b, 0x30f38774),
+ PCMCIA_DEVICE_PROD_ID12("SMC", "2632W-V2", 0xc4f8b18b, 0x172d1377),
+ PCMCIA_DEVICE_PROD_ID12("Wireless", "PC", 0xa407ecdd, 0x556e4d7e),
+ PCMCIA_DEVICE_PROD_ID12("WLAN", "802.11b PC CARD", 0x575c516c, 0xb1f6dbc4),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, atmel_ids);
+
static struct pcmcia_driver atmel_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "atmel_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "atmel_cs",
},
- .attach = atmel_attach,
- .detach = atmel_detach,
+ .attach = atmel_attach,
+ .event = atmel_event,
+ .detach = atmel_detach,
+ .id_table = atmel_ids,
};
static int atmel_cs_init(void)
diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
index 382241e7edbb..5f507c49907b 100644
--- a/drivers/net/wireless/netwave_cs.c
+++ b/drivers/net/wireless/netwave_cs.c
@@ -62,7 +62,6 @@
#endif /* WIRELESS_EXT > 12 */
#endif
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -491,11 +490,6 @@ static dev_link_t *netwave_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &netwave_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -1668,13 +1662,21 @@ static int netwave_close(struct net_device *dev) {
return 0;
}
+static struct pcmcia_device_id netwave_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("Xircom", "CreditCard Netwave", 0x2e3ee845, 0x54e28a28),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, netwave_ids);
+
static struct pcmcia_driver netwave_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "netwave_cs",
},
.attach = netwave_attach,
+ .event = netwave_event,
.detach = netwave_detach,
+ .id_table = netwave_ids,
};
static int __init init_netwave_cs(void)
diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c
index b1078baa1d5e..aabcdc2be05e 100644
--- a/drivers/net/wireless/orinoco.c
+++ b/drivers/net/wireless/orinoco.c
@@ -46,382 +46,9 @@
* under either the MPL or the GPL. */
/*
- * v0.01 -> v0.02 - 21/3/2001 - Jean II
- * o Allow to use regular ethX device name instead of dldwdX
- * o Warning on IBSS with ESSID=any for firmware 6.06
- * o Put proper range.throughput values (optimistic)
- * o IWSPY support (IOCTL and stat gather in Rx path)
- * o Allow setting frequency in Ad-Hoc mode
- * o Disable WEP setting if !has_wep to work on old firmware
- * o Fix txpower range
- * o Start adding support for Samsung/Compaq firmware
- *
- * v0.02 -> v0.03 - 23/3/2001 - Jean II
- * o Start adding Symbol support - need to check all that
- * o Fix Prism2/Symbol WEP to accept 128 bits keys
- * o Add Symbol WEP (add authentication type)
- * o Add Prism2/Symbol rate
- * 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
- * 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...
- * o Testing with various Wavelan firmwares
- *
- * v0.03 -> v0.04 - 30/3/2001 - Jean II
- * 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 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)
- * o Don't complain as much about Symbol cards...
- *
- * v0.04 -> v0.04b - 22/4/2001 - David Gibson
- * o Removed the 'eth' parameter - always use ethXX as the
- * interface name instead of dldwdXX. The other was racy
- * anyway.
- * o Clean up RID definitions in hermes.h, other cleanups
- *
- * v0.04b -> v0.04c - 24/4/2001 - Jean II
- * o Tim Hurley <timster AT seiki.bliztech.com> reported a D-Link card
- * with vendor 02 and firmware 0.08. Added in the capabilities...
- * o Tested Lucent firmware 7.28, everything works...
- *
- * v0.04c -> v0.05 - 3/5/2001 - Benjamin Herrenschmidt
- * o Spin-off Pcmcia code. This file is renamed orinoco.c,
- * and orinoco_cs.c now contains only the Pcmcia specific stuff
- * o Add Airport driver support on top of orinoco.c (see airport.c)
- *
- * v0.05 -> v0.05a - 4/5/2001 - Jean II
- * o Revert to old Pcmcia code to fix breakage of Ben's changes...
- *
- * v0.05a -> v0.05b - 4/5/2001 - Jean II
- * o add module parameter 'ignore_cis_vcc' for D-Link @ 5V
- * o D-Link firmware doesn't support multicast. We just print a few
- * error messages, but otherwise everything works...
- * o For David : set/getport3 works fine, just upgrade iwpriv...
- *
- * v0.05b -> v0.05c - 5/5/2001 - Benjamin Herrenschmidt
- * o Adapt airport.c to latest changes in orinoco.c
- * 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 <dliu AT research.bell-labs.com>
- * (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" <alin AT redhat.com>,
- * "Ian Kinner" <ikinner AT redhat.com>
- * and "David Smith" <dsmith AT redhat.com>
- * 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)
- * o Fix cor_reset to not lose bit 7 in the register
- * o flush_stale_links to remove zombie Pcmcia instances
- * o Ack previous hermes event before reset
- * Me (with my little hands)
- * o Allow orinoco.c to call cor_reset via priv->card_reset_handler
- * o Add priv->need_card_reset to toggle this feature
- * o Fix various buglets when setting WEP in Symbol firmware
- * Now, encryption is fully functional on Symbol cards. Youpi !
- *
- * v0.06 -> v0.06b - 25/5/2001 - Jean II
- * o IBSS on Symbol use port_mode = 4. Please don't ask...
- *
- * v0.06b -> v0.06c - 29/5/2001 - Jean II
- * o Show first spy address in /proc/net/wireless for IBSS mode as well
- *
- * 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 unnecessary messages.
- * o Removed bogus message on CRC error.
- * o Merged fixes for v0.08 Prism 2 firmware from William Waghorn
- * <willwaghorn AT yahoo.co.uk>
- * 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 metadata
- *
- * v0.06e -> v0.06f - 14/8/2001 - David Gibson
- * o Wording fix to license
- * o Added a 'use_alternate_encaps' module parameter for APs which need an
- * oui of 00:00:00. We really need a better way of handling this, but
- * the module flag is better than nothing for now.
- *
- * v0.06f -> v0.07 - 20/8/2001 - David Gibson
- * o Removed BAP error retries from hermes_bap_seek(). For Tx we now
- * let the upper layers handle the retry, we retry explicitly in the
- * Rx path, but don't make as much noise about it.
- * o Firmware detection cleanups.
- *
- * 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 <hidden AT xmission.com> 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
- * has changed (documentation needed).
- *
- * v0.07a -> v0.08 - 3/10/2001 - David Gibson
- * o Fixed a possible buffer overrun found by the Stanford checker (in
- * dldwd_ioctl_setiwencode()). Can only be called by root anyway, so not
- * a big problem.
- * 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
- * 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.
- * Setting use_old_encaps will mimic the old behaviour, but I think we
- * will be able to eliminate this.
- * 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 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 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.
- *
- * v0.08a -> v0.08b - 20/11/2001 - David Gibson
- * o Lots of cleanup and bugfixes in orinoco_plx.c
- * o Cleanup to handling of Tx rate setting.
- * o Removed support for old encapsulation method.
- * o Removed old "dldwd" names.
- * o Split RID constants into a new file hermes_rid.h
- * o Renamed RID constants to match linux-wlan-ng and prism2.o
- * o Bugfixes in hermes.c
- * o Poke the PLX's INTCSR register, so it actually starts
- * generating interrupts. These cards might actually work now.
- * o Update to wireless extensions v12 (Jean II)
- * o Support for tallies and inquire command (Jean II)
- * o Airport updates for newer PPC kernels (BenH)
- *
- * v0.08b -> v0.09 - 21/12/2001 - David Gibson
- * o Some new PCI IDs for PLX cards.
- * o Removed broken attempt to do ALLMULTI reception. Just use
- * promiscuous mode instead
- * o Preliminary work for list-AP (Jean II)
- * o Airport updates from (BenH)
- * o Eliminated racy hw_ready stuff
- * o Fixed generation of fake events in irq handler. This should
- * finally kill the EIO problems (Jean II & dgibson)
- * o Fixed breakage of bitrate set/get on Agere firmware (Jean II)
- *
- * v0.09 -> v0.09a - 2/1/2002 - David Gibson
- * o Fixed stupid mistake in multicast list handling, triggering
- * a BUG()
- *
- * v0.09a -> v0.09b - 16/1/2002 - David Gibson
- * o Fixed even stupider mistake in new interrupt handling, which
- * seriously broke things on big-endian machines.
- * o Removed a bunch of redundant includes and exports.
- * o Removed a redundant MOD_{INC,DEC}_USE_COUNT pair in airport.c
- * o Don't attempt to do hardware level multicast reception on
- * Intersil firmware, just go promisc instead.
- * o Typo fixed in hermes_issue_cmd()
- * o Eliminated WIRELESS_SPY #ifdefs
- * o Status code reported on Tx exceptions
- * o Moved netif_wake_queue() from ALLOC interrupts to TX and TXEXC
- * interrupts, which should fix the timeouts we're seeing.
- *
- * v0.09b -> v0.10 - 25 Feb 2002 - David Gibson
- * o Removed nested structures used for header parsing, so the
- * driver should now work without hackery on ARM
- * o Fix for WEP handling on Intersil (Hawk Newton)
- * o Eliminated the /proc/hermes/ethXX/regs debugging file. It
- * was never very useful.
- * o Make Rx errors less noisy.
- *
- * v0.10 -> v0.11 - 5 Apr 2002 - David Gibson
- * o Laid the groundwork in hermes.[ch] for devices which map
- * into PCI memory space rather than IO space.
- * o Fixed bug in multicast handling (cleared multicast list when
- * leaving promiscuous mode).
- * o Relegated Tx error messages to debug.
- * o Cleaned up / corrected handling of allocation lengths.
- * o Set OWNSSID in IBSS mode for WinXP interoperability (jimc).
- * o Change to using alloc_etherdev() for structure allocations.
- * o Check for and drop undersized packets.
- * o Fixed a race in stopping/waking the queue. This should fix
- * the timeout problems (Pavel Roskin)
- * o Reverted to netif_wake_queue() on the ALLOC event.
- * o Fixes for recent Symbol firmwares which lack AP density
- * (Pavel Roskin).
- *
- * v0.11 -> v0.11a - 29 Apr 2002 - David Gibson
- * o Handle different register spacing, necessary for Prism 2.5
- * PCI adaptors (Steve Hill).
- * o Cleaned up initialization of card structures in orinoco_cs
- * and airport. Removed card->priv field.
- * o Make response structure optional for hermes_docmd_wait()
- * Pavel Roskin)
- * o Added PCI id for Nortel emobility to orinoco_plx.c.
- * o Cleanup to handling of Symbol's allocation bug. (Pavel Roskin)
- * o Cleanups to firmware capability detection.
- * o Arrange for orinoco_pci.c to override firmware detection.
- * We should be able to support the PCI Intersil cards now.
- * o Cleanup handling of reset_cor and hard_reset (Pavel Roskin).
- * o Remove erroneous use of USER_BAP in the TxExc handler (Jouni
- * Malinen).
- * o Makefile changes for better integration into David Hinds
- * pcmcia-cs package.
- *
- * v0.11a -> v0.11b - 1 May 2002 - David Gibson
- * o Better error reporting in orinoco_plx_init_one()
- * o Fixed multiple bad kfree() bugs introduced by the
- * alloc_orinocodev() changes.
- *
- * v0.11b -> v0.12 - 19 Jun 2002 - David Gibson
- * o Support changing the MAC address.
- * o Correct display of Intersil firmware revision numbers.
- * o Entirely revised locking scheme. Should be both simpler and
- * better.
- * o Merged some common code in orinoco_plx, orinoco_pci and
- * airport by creating orinoco_default_{open,stop,reset}()
- * which are used as the dev->open, dev->stop, priv->reset
- * callbacks if none are specified when alloc_orinocodev() is
- * called.
- * o Removed orinoco_plx_interrupt() and orinoco_pci_interrupt().
- * They didn't do anything.
- *
- * v0.12 -> v0.12a - 4 Jul 2002 - David Gibson
- * o Some rearrangement of code.
- * o Numerous fixups to locking and rest handling, particularly
- * for PCMCIA.
- * o This allows open and stop net_device methods to be in
- * orinoco.c now, rather than in the init modules.
- * o In orinoco_cs.c link->priv now points to the struct
- * net_device not to the struct orinoco_private.
- * o Added a check for undersized SNAP frames, which could cause
- * crashes.
- *
- * v0.12a -> v0.12b - 11 Jul 2002 - David Gibson
- * o Fix hw->num_init testing code, so num_init is actually
- * incremented.
- * o Fix very stupid bug in orinoco_cs which broke compile with
- * CONFIG_SMP.
- * o Squashed a warning.
- *
- * v0.12b -> v0.12c - 26 Jul 2002 - David Gibson
- * o Change to C9X style designated initializers.
- * o Add support for 3Com AirConnect PCI.
- * o No longer ignore the hard_reset argument to
- * alloc_orinocodev(). Oops.
- *
- * v0.12c -> v0.13beta1 - 13 Sep 2002 - David Gibson
- * o Revert the broken 0.12* locking scheme and go to a new yet
- * simpler scheme.
- * o Do firmware resets only in orinoco_init() and when waking
- * the card from hard sleep.
- *
- * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson
- * o Re-introduced full resets (via schedule_task()) on Tx
- * timeout.
- *
- * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson
- * o Minor cleanups to info frame handling. Add basic support
- * for linkstatus info frames.
- * o Include required kernel headers in orinoco.h, to avoid
- * compile problems.
- *
- * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson
- * o Implemented hard reset for Airport cards
- * o Experimental suspend/resume implementation for orinoco_pci
- * o Abolished /proc debugging support, replaced with a debugging
- * iwpriv. Now it's ugly and simple instead of ugly and complex.
- * o Bugfix in hermes.c if the firmware returned a record length
- * of 0, we could go clobbering memory.
- * 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 confusing the firmware), and only
- * give LINKSTATUS printk()s if the status has changed.
- *
- * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson
- * o Cleanup: use dev instead of priv in various places.
- * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event
- * if we're in the middle of a (driver initiated) hard reset.
- * o Bug fix: ETH_ZLEN is supposed to include the header
- * (Dionysus Blazakis & Manish Karir)
- * o Convert to using workqueues instead of taskqueues (and
- * backwards compatibility macros for pre 2.5.41 kernels).
- * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in
- * airport.c
- * o New orinoco_tmd.c init module from Joerg Dorchain for
- * TMD7160 based PCI to PCMCIA bridges (similar to
- * orinoco_plx.c).
- *
- * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson
- * o Make hw_unavailable a counter, rather than just a flag, this
- * is necessary to avoid some races (such as a card being
- * removed in the middle of orinoco_reset().
- * o Restore Release/RequestConfiguration in the PCMCIA event handler
- * when dealing with a driver initiated hard reset. This is
- * necessary to prevent hangs due to a spurious interrupt while
- * the reset is in progress.
- * o Clear the 802.11 header when transmitting, even though we
- * don't use it. This fixes a long standing bug on some
- * firmwares, which seem to get confused if that isn't done.
- * o Be less eager to de-encapsulate SNAP frames, only do so if
- * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old
- * behaviour broke CDP (Cisco Discovery Protocol).
- * o Use dev instead of priv for free_irq() as well as
- * request_irq() (oops).
- * o Attempt to reset rather than giving up if we get too many
- * IRQs.
- * o Changed semantics of __orinoco_down() so it can be called
- * safely with hw_unavailable set. It also now clears the
- * linkstatus (since we're going to have to reassociate).
- *
- * v0.13d -> v0.13e - 12 May 2003 - David Gibson
- * o Support for post-2.5.68 return values from irq handler.
- * o Fixed bug where underlength packets would be double counted
- * in the rx_dropped statistics.
- * o Provided a module parameter to suppress linkstatus messages.
- *
- * v0.13e -> v0.14alpha1 - 30 Sep 2003 - David Gibson
- * o Replaced priv->connected logic with netif_carrier_on/off()
- * calls.
- * o Remove has_ibss_any and never set the CREATEIBSS RID when
- * the ESSID is empty. Too many firmwares break if we do.
- * o 2.6 merges: Replace pdev->slot_name with pci_name(), remove
- * __devinitdata from PCI ID tables, use free_netdev().
- * o Enabled shared-key authentication for Agere firmware (from
- * Robert J. Moore <Robert.J.Moore AT allanbank.com>
- * o Move netif_wake_queue() (back) to the Tx completion from the
- * ALLOC event. This seems to prevent/mitigate the rolling
- * error -110 problems at least on some Intersil firmwares.
- * Theoretically reduces performance, but I can't measure it.
- * Patch from Andrew Tridgell <tridge AT samba.org>
- *
- * v0.14alpha1 -> v0.14alpha2 - 20 Oct 2003 - David Gibson
- * o Correctly turn off shared-key authentication when requested
- * (bugfix from Robert J. Moore).
- * o Correct airport sleep interfaces for current 2.6 kernels.
- * o Add code for key change without disabling/enabling the MAC
- * port. This is supposed to allow 802.1x to work sanely, but
- * doesn't seem to yet.
- *
* TODO
- * o New wireless extensions API (patch from Moustafa
- * Youssef, updated by Jim Carter and Pavel Roskin).
* o Handle de-encapsulation within network layer, provide 802.11
* headers (patch from Thomas 'Dent' Mirlacher)
- * o RF monitor mode support
* o Fix possible races in SPY handling.
* o Disconnect wireless extensions from fundamental configuration.
* o (maybe) Software WEP support (patch from Stano Meduna).
@@ -462,7 +89,10 @@
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -496,6 +126,10 @@ static int ignore_disconnect; /* = 0 */
module_param(ignore_disconnect, int, 0644);
MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer");
+static int force_monitor; /* = 0 */
+module_param(force_monitor, int, 0644);
+MODULE_PARM_DESC(force_monitor, "Allow monitor mode for all firmware versions");
+
/********************************************************************/
/* Compile time configuration and compatibility stuff */
/********************************************************************/
@@ -511,6 +145,10 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
/* Internal constants */
/********************************************************************/
+/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
+static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
+
#define ORINOCO_MIN_MTU 256
#define ORINOCO_MAX_MTU (IEEE802_11_DATA_LEN - ENCAPS_OVERHEAD)
@@ -537,6 +175,11 @@ MODULE_PARM_DESC(ignore_disconnect, "Don't report lost link to the network layer
| HERMES_EV_WTERR | HERMES_EV_INFO \
| HERMES_EV_INFDROP )
+#define MAX_RID_LEN 1024
+
+static const struct iw_handler_def orinoco_handler_def;
+static struct ethtool_ops orinoco_ethtool_ops;
+
/********************************************************************/
/* Data tables */
/********************************************************************/
@@ -571,26 +214,45 @@ static struct {
/* Data types */
/********************************************************************/
-struct header_struct {
- /* 802.3 */
- u8 dest[ETH_ALEN];
- u8 src[ETH_ALEN];
- u16 len;
- /* 802.2 */
+/* Used in Event handling.
+ * We avoid nested structres as they break on ARM -- Moustafa */
+struct hermes_tx_descriptor_802_11 {
+ /* hermes_tx_descriptor */
+ u16 status;
+ u16 reserved1;
+ u16 reserved2;
+ u32 sw_support;
+ u8 retry_count;
+ u8 tx_rate;
+ u16 tx_control;
+
+ /* ieee802_11_hdr */
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+ u16 data_len;
+
+ /* ethhdr */
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ unsigned short h_proto; /* packet type ID field */
+
+ /* p8022_hdr */
u8 dsap;
u8 ssap;
u8 ctrl;
- /* SNAP */
u8 oui[3];
+
u16 ethertype;
} __attribute__ ((packed));
-/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */
-u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
-
-#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)
-
+/* Rx frame header except compatibility 802.3 header */
struct hermes_rx_descriptor {
+ /* Control */
u16 status;
u32 time;
u8 silence;
@@ -598,13 +260,24 @@ struct hermes_rx_descriptor {
u8 rate;
u8 rxflow;
u32 reserved;
+
+ /* 802.11 header */
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+
+ /* Data length */
+ u16 data_len;
} __attribute__ ((packed));
/********************************************************************/
/* Function prototypes */
/********************************************************************/
-static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static int __orinoco_program_rids(struct net_device *dev);
static void __orinoco_set_multicast_list(struct net_device *dev);
@@ -628,6 +301,10 @@ static inline void set_port_type(struct orinoco_private *priv)
priv->createibss = 1;
}
break;
+ case IW_MODE_MONITOR:
+ priv->port_type = 3;
+ priv->createibss = 0;
+ break;
default:
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n",
priv->ndev->name);
@@ -814,7 +491,7 @@ static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev)
return 1;
}
- if (! netif_carrier_ok(dev)) {
+ if (! netif_carrier_ok(dev) || (priv->iw_mode == IW_MODE_MONITOR)) {
/* Oops, the firmware hasn't established a connection,
silently drop the packet (this seems to be the
safest approach). */
@@ -951,26 +628,55 @@ 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;
+ struct hermes_tx_descriptor_802_11 hdr;
int err = 0;
if (fid == DUMMY_FID)
return; /* Nothing's really happened */
- err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0);
+ /* Read the frame header */
+ err = hermes_bap_pread(hw, IRQ_BAP, &hdr,
+ sizeof(struct hermes_tx_descriptor) +
+ sizeof(struct ieee80211_hdr),
+ fid, 0);
+
+ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
+ stats->tx_errors++;
+
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));
+ return;
}
- stats->tx_errors++;
+ DEBUG(1, "%s: Tx error, err %d (FID=%04X)\n", dev->name,
+ err, fid);
+
+ /* We produce a TXDROP event only for retry or lifetime
+ * exceeded, because that's the only status that really mean
+ * that this particular node went away.
+ * Other errors means that *we* screwed up. - Jean II */
+ hdr.status = le16_to_cpu(hdr.status);
+ if (hdr.status & (HERMES_TXSTAT_RETRYERR | HERMES_TXSTAT_AGEDERR)) {
+ union iwreq_data wrqu;
+
+ /* Copy 802.11 dest address.
+ * We use the 802.11 header because the frame may
+ * not be 802.3 or may be mangled...
+ * In Ad-Hoc mode, it will be the node address.
+ * In managed mode, it will be most likely the AP addr
+ * User space will figure out how to convert it to
+ * whatever it needs (IP address or else).
+ * - Jean II */
+ memcpy(wrqu.addr.sa_data, hdr.addr1, ETH_ALEN);
+ wrqu.addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(dev, IWEVTXDROP, &wrqu, NULL);
+ }
netif_wake_queue(dev);
- hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID);
}
static void orinoco_tx_timeout(struct net_device *dev)
@@ -1047,18 +753,127 @@ static void orinoco_stat_gather(struct net_device *dev,
}
}
+/*
+ * orinoco_rx_monitor - handle received monitor frames.
+ *
+ * Arguments:
+ * dev network device
+ * rxfid received FID
+ * desc rx descriptor of the frame
+ *
+ * Call context: interrupt
+ */
+static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid,
+ struct hermes_rx_descriptor *desc)
+{
+ u32 hdrlen = 30; /* return full header by default */
+ u32 datalen = 0;
+ u16 fc;
+ int err;
+ int len;
+ struct sk_buff *skb;
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct net_device_stats *stats = &priv->stats;
+ hermes_t *hw = &priv->hw;
+
+ len = le16_to_cpu(desc->data_len);
+
+ /* Determine the size of the header and the data */
+ fc = le16_to_cpu(desc->frame_ctl);
+ switch (fc & IEEE80211_FCTL_FTYPE) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_TODS)
+ && (fc & IEEE80211_FCTL_FROMDS))
+ hdrlen = 30;
+ else
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_MGMT:
+ hdrlen = 24;
+ datalen = len;
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (fc & IEEE80211_FCTL_STYPE) {
+ case IEEE80211_STYPE_PSPOLL:
+ case IEEE80211_STYPE_RTS:
+ case IEEE80211_STYPE_CFEND:
+ case IEEE80211_STYPE_CFENDACK:
+ hdrlen = 16;
+ break;
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = 10;
+ break;
+ }
+ break;
+ default:
+ /* Unknown frame type */
+ break;
+ }
+
+ /* sanity check the length */
+ if (datalen > IEEE80211_DATA_LEN + 12) {
+ printk(KERN_DEBUG "%s: oversized monitor frame, "
+ "data length = %d\n", dev->name, datalen);
+ err = -EIO;
+ stats->rx_length_errors++;
+ goto update_stats;
+ }
+
+ skb = dev_alloc_skb(hdrlen + datalen);
+ if (!skb) {
+ printk(KERN_WARNING "%s: Cannot allocate skb for monitor frame\n",
+ dev->name);
+ err = -ENOMEM;
+ goto drop;
+ }
+
+ /* Copy the 802.11 header to the skb */
+ memcpy(skb_put(skb, hdrlen), &(desc->frame_ctl), hdrlen);
+ skb->mac.raw = skb->data;
+
+ /* If any, copy the data from the card to the skb */
+ if (datalen > 0) {
+ err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, datalen),
+ ALIGN(datalen, 2), rxfid,
+ HERMES_802_2_OFFSET);
+ if (err) {
+ printk(KERN_ERR "%s: error %d reading monitor frame\n",
+ dev->name, err);
+ goto drop;
+ }
+ }
+
+ skb->dev = dev;
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->pkt_type = PACKET_OTHERHOST;
+ skb->protocol = __constant_htons(ETH_P_802_2);
+
+ dev->last_rx = jiffies;
+ stats->rx_packets++;
+ stats->rx_bytes += skb->len;
+
+ netif_rx(skb);
+ return;
+
+ drop:
+ dev_kfree_skb_irq(skb);
+ update_stats:
+ stats->rx_errors++;
+ stats->rx_dropped++;
+}
+
static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
{
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;
+ u16 rxfid, status, fc;
+ int length;
struct hermes_rx_descriptor desc;
- struct header_struct hdr;
- struct ethhdr *eh;
+ struct ethhdr *hdr;
int err;
rxfid = hermes_read_regn(hw, RXFID);
@@ -1068,53 +883,46 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if (err) {
printk(KERN_ERR "%s: error %d reading Rx descriptor. "
"Frame dropped.\n", dev->name, err);
- stats->rx_errors++;
- goto drop;
+ goto update_stats;
}
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;
+ if (status & HERMES_RXSTAT_BADCRC) {
+ DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n",
+ dev->name);
+ stats->rx_crc_errors++;
+ goto update_stats;
}
- /* For now we ignore the 802.11 header completely, assuming
- that the card's firmware has handled anything vital */
+ /* Handle frames in monitor mode */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ orinoco_rx_monitor(dev, rxfid, &desc);
+ return;
+ }
- 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;
+ if (status & HERMES_RXSTAT_UNDECRYPTABLE) {
+ DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n",
+ dev->name);
+ wstats->discard.code++;
+ goto update_stats;
}
- length = ntohs(hdr.len);
-
+ length = le16_to_cpu(desc.data_len);
+ fc = le16_to_cpu(desc.frame_ctl);
+
/* 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;
+ return;
}
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;
+ goto update_stats;
}
/* We need space for the packet data itself, plus an ethernet
@@ -1126,60 +934,53 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
if (!skb) {
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n",
dev->name);
- goto drop;
+ goto update_stats;
}
- skb_reserve(skb, 2); /* This way the IP header is aligned */
+ /* We'll prepend the header, so reserve space for it. The worst
+ case is no decapsulation, when 802.3 header is prepended and
+ nothing is removed. 2 is for aligning the IP header. */
+ skb_reserve(skb, ETH_HLEN + 2);
+
+ err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),
+ ALIGN(length, 2), rxfid,
+ HERMES_802_2_OFFSET);
+ if (err) {
+ printk(KERN_ERR "%s: error %d reading frame. "
+ "Frame dropped.\n", dev->name, err);
+ goto drop;
+ }
/* 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)) {
+ if (length >= ENCAPS_OVERHEAD &&
+ (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||
+ ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||
+ is_ethersnap(skb->data))) {
/* These indicate a SNAP within 802.2 LLC within
802.11 frame which we'll need to de-encapsulate to
the original EthernetII frame. */
-
- if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */
- stats->rx_length_errors++;
- goto drop;
- }
-
- /* 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);
-
- memcpy(eh, &hdr, 2 * ETH_ALEN);
- eh->h_proto = hdr.ethertype;
+ hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);
} 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 */
- }
-
- 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;
+ /* 802.3 frame - prepend 802.3 header as is */
+ hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);
+ hdr->h_proto = htons(length);
}
+ memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);
+ if (fc & IEEE80211_FCTL_FROMDS)
+ memcpy(hdr->h_source, desc.addr3, ETH_ALEN);
+ else
+ memcpy(hdr->h_source, desc.addr2, ETH_ALEN);
dev->last_rx = jiffies;
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
skb->ip_summed = CHECKSUM_NONE;
+ if (fc & IEEE80211_FCTL_TODS)
+ skb->pkt_type = PACKET_OTHERHOST;
/* Process the wireless stats if needed */
orinoco_stat_gather(dev, skb, &desc);
@@ -1192,11 +993,10 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw)
return;
drop:
+ dev_kfree_skb_irq(skb);
+ update_stats:
+ stats->rx_errors++;
stats->rx_dropped++;
-
- if (skb)
- dev_kfree_skb_irq(skb);
- return;
}
/********************************************************************/
@@ -1240,6 +1040,99 @@ static void print_linkstatus(struct net_device *dev, u16 status)
dev->name, s, status);
}
+/* Search scan results for requested BSSID, join it if found */
+static void orinoco_join_ap(struct net_device *dev)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ int err;
+ unsigned long flags;
+ struct join_req {
+ u8 bssid[ETH_ALEN];
+ u16 channel;
+ } __attribute__ ((packed)) req;
+ const int atom_len = offsetof(struct prism2_scan_apinfo, atim);
+ struct prism2_scan_apinfo *atom;
+ int offset = 4;
+ u8 *buf;
+ u16 len;
+
+ /* Allocate buffer for scan results */
+ buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);
+ if (! buf)
+ return;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ goto out;
+
+ /* Sanity checks in case user changed something in the meantime */
+ if (! priv->bssid_fixed)
+ goto out;
+
+ if (strlen(priv->desired_essid) == 0)
+ goto out;
+
+ /* Read scan results from the firmware */
+ err = hermes_read_ltv(hw, USER_BAP,
+ HERMES_RID_SCANRESULTSTABLE,
+ MAX_SCAN_LEN, &len, buf);
+ if (err) {
+ printk(KERN_ERR "%s: Cannot read scan results\n",
+ dev->name);
+ goto out;
+ }
+
+ len = HERMES_RECLEN_TO_BYTES(len);
+
+ /* Go through the scan results looking for the channel of the AP
+ * we were requested to join */
+ for (; offset + atom_len <= len; offset += atom_len) {
+ atom = (struct prism2_scan_apinfo *) (buf + offset);
+ if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0)
+ goto found;
+ }
+
+ DEBUG(1, "%s: Requested AP not found in scan results\n",
+ dev->name);
+ goto out;
+
+ found:
+ memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);
+ req.channel = atom->channel; /* both are little-endian */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,
+ &req);
+ if (err)
+ printk(KERN_ERR "%s: Error issuing join request\n", dev->name);
+
+ out:
+ kfree(buf);
+ orinoco_unlock(priv, &flags);
+}
+
+/* Send new BSSID to userspace */
+static void orinoco_send_wevents(struct net_device *dev)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ union iwreq_data wrqu;
+ int err;
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return;
+
+ err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,
+ ETH_ALEN, NULL, wrqu.ap_addr.sa_data);
+ if (err != 0)
+ return;
+
+ wrqu.ap_addr.sa_family = ARPHRD_ETHER;
+
+ /* Send event to user space */
+ wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL);
+ orinoco_unlock(priv, &flags);
+}
+
static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
{
struct orinoco_private *priv = netdev_priv(dev);
@@ -1307,6 +1200,9 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
u16 newstatus;
int connected;
+ if (priv->iw_mode == IW_MODE_MONITOR)
+ break;
+
if (len != sizeof(linkstatus)) {
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",
dev->name, len);
@@ -1319,6 +1215,15 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
break;
newstatus = le16_to_cpu(linkstatus.linkstatus);
+ /* Symbol firmware uses "out of range" to signal that
+ * the hostscan frame can be requested. */
+ if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&
+ priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&
+ priv->has_hostscan && priv->scan_inprogress) {
+ hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);
+ break;
+ }
+
connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)
|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)
|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);
@@ -1328,12 +1233,89 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw)
else if (!ignore_disconnect)
netif_carrier_off(dev);
- if (newstatus != priv->last_linkstatus)
+ if (newstatus != priv->last_linkstatus) {
+ priv->last_linkstatus = newstatus;
print_linkstatus(dev, newstatus);
+ /* The info frame contains only one word which is the
+ * status (see hermes.h). The status is pretty boring
+ * in itself, that's why we export the new BSSID...
+ * Jean II */
+ schedule_work(&priv->wevent_work);
+ }
+ }
+ break;
+ case HERMES_INQ_SCAN:
+ if (!priv->scan_inprogress && priv->bssid_fixed &&
+ priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {
+ schedule_work(&priv->join_work);
+ break;
+ }
+ /* fall through */
+ case HERMES_INQ_HOSTSCAN:
+ case HERMES_INQ_HOSTSCAN_SYMBOL: {
+ /* Result of a scanning. Contains information about
+ * cells in the vicinity - Jean II */
+ union iwreq_data wrqu;
+ unsigned char *buf;
+
+ /* Sanity check */
+ if (len > 4096) {
+ printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",
+ dev->name, len);
+ break;
+ }
- priv->last_linkstatus = newstatus;
+ /* We are a strict producer. If the previous scan results
+ * have not been consumed, we just have to drop this
+ * frame. We can't remove the previous results ourselves,
+ * that would be *very* racy... Jean II */
+ if (priv->scan_result != NULL) {
+ printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);
+ break;
+ }
+
+ /* Allocate buffer for results */
+ buf = kmalloc(len, GFP_ATOMIC);
+ if (buf == NULL)
+ /* No memory, so can't printk()... */
+ break;
+
+ /* Read scan data */
+ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,
+ infofid, sizeof(info));
+ if (err)
+ break;
+
+#ifdef ORINOCO_DEBUG
+ {
+ int i;
+ printk(KERN_DEBUG "Scan result [%02X", buf[0]);
+ for(i = 1; i < (len * 2); i++)
+ printk(":%02X", buf[i]);
+ printk("]\n");
+ }
+#endif /* ORINOCO_DEBUG */
+
+ /* Allow the clients to access the results */
+ priv->scan_len = len;
+ priv->scan_result = buf;
+
+ /* Send an empty event to user space.
+ * We don't send the received data on the event because
+ * it would require us to do complex transcoding, and
+ * we want to minimise the work done in the irq handler
+ * Use a request to extract the data - Jean II */
+ wrqu.data.length = 0;
+ wrqu.data.flags = 0;
+ wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);
}
break;
+ case HERMES_INQ_SEC_STAT_AGERE:
+ /* Security status (Agere specific) */
+ /* Ignore this frame for now */
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
+ break;
+ /* fall through */
default:
printk(KERN_DEBUG "%s: Unknown information frame received: "
"type 0x%04x, length %d\n", dev->name, type, len);
@@ -1470,6 +1452,36 @@ static int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
return err;
}
+/* Set fixed AP address */
+static int __orinoco_hw_set_wap(struct orinoco_private *priv)
+{
+ int roaming_flag;
+ int err = 0;
+ hermes_t *hw = &priv->hw;
+
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ /* not supported */
+ break;
+ case FIRMWARE_TYPE_INTERSIL:
+ if (priv->bssid_fixed)
+ roaming_flag = 2;
+ else
+ roaming_flag = 1;
+
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFROAMINGMODE,
+ roaming_flag);
+ break;
+ case FIRMWARE_TYPE_SYMBOL:
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
+ &priv->desired_bssid);
+ break;
+ }
+ return err;
+}
+
/* Change the WEP keys and/or the current keys. Can be called
* either from __orinoco_hw_setup_wep() or directly from
* orinoco_ioctl_setiwencode(). In the later case the association
@@ -1655,6 +1667,13 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
+ /* Set the desired BSSID */
+ err = __orinoco_hw_set_wap(priv);
+ if (err) {
+ printk(KERN_ERR "%s: Error %d setting AP address\n",
+ dev->name, err);
+ return err;
+ }
/* Set the desired ESSID */
idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
@@ -1793,6 +1812,20 @@ static int __orinoco_program_rids(struct net_device *dev)
}
}
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Enable monitor mode */
+ dev->type = ARPHRD_IEEE80211;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_MONITOR, 0, NULL);
+ } else {
+ /* Disable monitor mode */
+ dev->type = ARPHRD_ETHER;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_STOP, 0, NULL);
+ }
+ if (err)
+ return err;
+
/* Set promiscuity / multicast*/
priv->promiscuous = 0;
priv->mc_count = 0;
@@ -1869,55 +1902,6 @@ __orinoco_set_multicast_list(struct net_device *dev)
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;
- }
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- 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;
- }
-
- err = __orinoco_program_rids(dev);
- if (err) {
- printk(KERN_WARNING "%s: Unable to reconfigure card\n",
- dev->name);
- goto out;
- }
-
- err = hermes_enable_port(hw, 0);
- if (err) {
- printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
- dev->name);
- goto out;
- }
-
- out:
- if (err) {
- printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
- schedule_work(&priv->reset_work);
- err = 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)
@@ -1946,6 +1930,11 @@ static void orinoco_reset(struct net_device *dev)
orinoco_unlock(priv, &flags);
+ /* Scanning support: Cleanup of driver struct */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ priv->scan_inprogress = 0;
+
if (priv->hard_reset) {
err = (*priv->hard_reset)(priv);
if (err) {
@@ -2184,6 +2173,8 @@ static int determine_firmware(struct net_device *dev)
priv->has_mwo = (firmver >= 0x60000);
priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
priv->ibss_port = 1;
+ priv->has_hostscan = (firmver >= 0x8000a);
+ priv->broken_monitor = (firmver >= 0x80000);
/* Tested with Agere firmware :
* 1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
@@ -2229,6 +2220,8 @@ static int determine_firmware(struct net_device *dev)
priv->ibss_port = 4;
priv->broken_disableport = (firmver == 0x25013) ||
(firmver >= 0x30000 && firmver <= 0x31000);
+ priv->has_hostscan = (firmver >= 0x31001) ||
+ (firmver >= 0x29057 && firmver < 0x30000);
/* Tested with Intel firmware : 0x20015 => Jean II */
/* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
break;
@@ -2248,6 +2241,7 @@ static int determine_firmware(struct net_device *dev)
priv->has_ibss = (firmver >= 0x000700); /* FIXME */
priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
priv->has_pm = (firmver >= 0x000700);
+ priv->has_hostscan = (firmver >= 0x010301);
if (firmver >= 0x000800)
priv->ibss_port = 0;
@@ -2456,8 +2450,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
dev->tx_timeout = orinoco_tx_timeout;
dev->watchdog_timeo = HZ; /* 1 second timeout */
dev->get_stats = orinoco_get_stats;
+ dev->ethtool_ops = &orinoco_ethtool_ops;
dev->get_wireless_stats = orinoco_get_wireless_stats;
- dev->do_ioctl = orinoco_ioctl;
+ dev->wireless_handlers = (struct iw_handler_def *)&orinoco_handler_def;
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 */
@@ -2473,6 +2468,8 @@ struct net_device *alloc_orinocodev(int sizeof_card,
* before anything else touches the
* hardware */
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev);
+ INIT_WORK(&priv->join_work, (void (*)(void *))orinoco_join_ap, dev);
+ INIT_WORK(&priv->wevent_work, (void (*)(void *))orinoco_send_wevents, dev);
netif_carrier_off(dev);
priv->last_linkstatus = 0xffff;
@@ -2483,6 +2480,9 @@ struct net_device *alloc_orinocodev(int sizeof_card,
void free_orinocodev(struct net_device *dev)
{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ kfree(priv->scan_result);
free_netdev(dev);
}
@@ -2490,24 +2490,6 @@ void free_orinocodev(struct net_device *dev)
/* Wireless extensions */
/********************************************************************/
-static int orinoco_hw_get_bssid(struct orinoco_private *priv,
- char buf[ETH_ALEN])
-{
- hermes_t *hw = &priv->hw;
- int err = 0;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
-
- err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
- ETH_ALEN, NULL, buf);
-
- orinoco_unlock(priv, &flags);
-
- return err;
-}
-
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
char buf[IW_ESSID_MAX_SIZE+1])
{
@@ -2633,140 +2615,271 @@ static int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
return 0;
}
-static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq)
+static int orinoco_ioctl_getname(struct net_device *dev,
+ struct iw_request_info *info,
+ char *name,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
- int mode;
- struct iw_range range;
int numrates;
- int i, k;
+ int err;
+
+ err = orinoco_hw_get_bitratelist(priv, &numrates, NULL, 0);
+
+ if (!err && (numrates > 2))
+ strcpy(name, "IEEE 802.11b");
+ else
+ strcpy(name, "IEEE 802.11-DS");
+
+ return 0;
+}
+
+static int orinoco_ioctl_setwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
+ static const u8 off_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+ static const u8 any_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
- TRACE_ENTER(dev->name);
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ /* Enable automatic roaming - no sanity checks are needed */
+ if (memcmp(&ap_addr->sa_data, off_addr, ETH_ALEN) == 0 ||
+ memcmp(&ap_addr->sa_data, any_addr, ETH_ALEN) == 0) {
+ priv->bssid_fixed = 0;
+ memset(priv->desired_bssid, 0, ETH_ALEN);
+
+ /* "off" means keep existing connection */
+ if (ap_addr->sa_data[0] == 0) {
+ __orinoco_hw_set_wap(priv);
+ err = 0;
+ }
+ goto out;
+ }
+
+ if (priv->firmware_type == FIRMWARE_TYPE_AGERE) {
+ printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't "
+ "support manual roaming\n",
+ dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ if (priv->iw_mode != IW_MODE_INFRA) {
+ printk(KERN_WARNING "%s: Manual roaming supported only in "
+ "managed mode\n", dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Intersil firmware hangs without Desired ESSID */
+ if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL &&
+ strlen(priv->desired_essid) == 0) {
+ printk(KERN_WARNING "%s: Desired ESSID must be set for "
+ "manual roaming\n", dev->name);
+ err = -EOPNOTSUPP;
+ goto out;
+ }
+
+ /* Finally, enable manual roaming */
+ priv->bssid_fixed = 1;
+ memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
+
+static int orinoco_ioctl_getwap(struct net_device *dev,
+ struct iw_request_info *info,
+ struct sockaddr *ap_addr,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ hermes_t *hw = &priv->hw;
+ int err = 0;
+ unsigned long flags;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ ap_addr->sa_family = ARPHRD_ETHER;
+ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
+ ETH_ALEN, NULL, ap_addr->sa_data);
+
+ orinoco_unlock(priv, &flags);
+
+ return err;
+}
- if (!access_ok(VERIFY_WRITE, rrq->pointer, sizeof(range)))
- return -EFAULT;
+static int orinoco_ioctl_setmode(struct net_device *dev,
+ struct iw_request_info *info,
+ u32 *mode,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = -EINPROGRESS; /* Call commit handler */
+ unsigned long flags;
- rrq->length = sizeof(range);
+ if (priv->iw_mode == *mode)
+ return 0;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- mode = priv->iw_mode;
+ switch (*mode) {
+ case IW_MODE_ADHOC:
+ if (!priv->has_ibss && !priv->has_port3)
+ err = -EOPNOTSUPP;
+ break;
+
+ case IW_MODE_INFRA:
+ break;
+
+ case IW_MODE_MONITOR:
+ if (priv->broken_monitor && !force_monitor) {
+ printk(KERN_WARNING "%s: Monitor mode support is "
+ "buggy in this firmware, not enabling\n",
+ dev->name);
+ err = -EOPNOTSUPP;
+ }
+ break;
+
+ default:
+ err = -EOPNOTSUPP;
+ break;
+ }
+
+ if (err == -EINPROGRESS) {
+ priv->iw_mode = *mode;
+ set_port_type(priv);
+ }
+
orinoco_unlock(priv, &flags);
- memset(&range, 0, sizeof(range));
+ return err;
+}
+
+static int orinoco_ioctl_getmode(struct net_device *dev,
+ struct iw_request_info *info,
+ u32 *mode,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ *mode = priv->iw_mode;
+ return 0;
+}
+
+static int orinoco_ioctl_getiwrange(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *rrq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ struct iw_range *range = (struct iw_range *) extra;
+ int numrates;
+ int i, k;
+
+ TRACE_ENTER(dev->name);
- /* Much of this shamelessly taken from wvlan_cs.c. No idea
- * what it all means -dgibson */
- range.we_version_compiled = WIRELESS_EXT;
- range.we_version_source = 11;
+ rrq->length = sizeof(struct iw_range);
+ memset(range, 0, sizeof(struct iw_range));
- range.min_nwid = range.max_nwid = 0; /* We don't use nwids */
+ range->we_version_compiled = WIRELESS_EXT;
+ range->we_version_source = 14;
/* Set available channels/frequencies */
- range.num_channels = NUM_CHANNELS;
+ range->num_channels = NUM_CHANNELS;
k = 0;
for (i = 0; i < NUM_CHANNELS; i++) {
if (priv->channel_mask & (1 << i)) {
- range.freq[k].i = i + 1;
- range.freq[k].m = channel_frequency[i] * 100000;
- range.freq[k].e = 1;
+ range->freq[k].i = i + 1;
+ range->freq[k].m = channel_frequency[i] * 100000;
+ range->freq[k].e = 1;
k++;
}
if (k >= IW_MAX_FREQUENCIES)
break;
}
- range.num_frequency = k;
+ range->num_frequency = k;
+ range->sensitivity = 3;
- range.sensitivity = 3;
+ if (priv->has_wep) {
+ range->max_encoding_tokens = ORINOCO_MAX_KEYS;
+ range->encoding_size[0] = SMALL_KEY_SIZE;
+ range->num_encoding_sizes = 1;
- if ((mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
+ if (priv->has_big_wep) {
+ range->encoding_size[1] = LARGE_KEY_SIZE;
+ range->num_encoding_sizes = 2;
+ }
+ }
+
+ if ((priv->iw_mode == IW_MODE_ADHOC) && (priv->spy_number == 0)){
/* Quality stats meaningless in ad-hoc mode */
- range.max_qual.qual = 0;
- range.max_qual.level = 0;
- range.max_qual.noise = 0;
- range.avg_qual.qual = 0;
- range.avg_qual.level = 0;
- range.avg_qual.noise = 0;
} else {
- range.max_qual.qual = 0x8b - 0x2f;
- range.max_qual.level = 0x2f - 0x95 - 1;
- range.max_qual.noise = 0x2f - 0x95 - 1;
+ range->max_qual.qual = 0x8b - 0x2f;
+ range->max_qual.level = 0x2f - 0x95 - 1;
+ range->max_qual.noise = 0x2f - 0x95 - 1;
/* Need to get better values */
- range.avg_qual.qual = 0x24;
- range.avg_qual.level = 0xC2;
- range.avg_qual.noise = 0x9E;
+ range->avg_qual.qual = 0x24;
+ range->avg_qual.level = 0xC2;
+ range->avg_qual.noise = 0x9E;
}
err = orinoco_hw_get_bitratelist(priv, &numrates,
- range.bitrate, IW_MAX_BITRATES);
+ range->bitrate, IW_MAX_BITRATES);
if (err)
return err;
- range.num_bitrates = numrates;
-
+ range->num_bitrates = numrates;
+
/* Set an indication of the max TCP throughput in bit/s that we can
* expect using this interface. May be use for QoS stuff...
* Jean II */
- if(numrates > 2)
- range.throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
+ if (numrates > 2)
+ range->throughput = 5 * 1000 * 1000; /* ~5 Mb/s */
else
- range.throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
-
- range.min_rts = 0;
- range.max_rts = 2347;
- range.min_frag = 256;
- range.max_frag = 2346;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- if (priv->has_wep) {
- range.max_encoding_tokens = ORINOCO_MAX_KEYS;
-
- range.encoding_size[0] = SMALL_KEY_SIZE;
- range.num_encoding_sizes = 1;
-
- if (priv->has_big_wep) {
- range.encoding_size[1] = LARGE_KEY_SIZE;
- range.num_encoding_sizes = 2;
- }
- } else {
- range.num_encoding_sizes = 0;
- range.max_encoding_tokens = 0;
- }
- orinoco_unlock(priv, &flags);
-
- range.min_pmp = 0;
- range.max_pmp = 65535000;
- range.min_pmt = 0;
- range.max_pmt = 65535 * 1000; /* ??? */
- range.pmp_flags = IW_POWER_PERIOD;
- range.pmt_flags = IW_POWER_TIMEOUT;
- range.pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
-
- range.num_txpower = 1;
- range.txpower[0] = 15; /* 15dBm */
- range.txpower_capa = IW_TXPOW_DBM;
-
- range.retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
- range.retry_flags = IW_RETRY_LIMIT;
- range.r_time_flags = IW_RETRY_LIFETIME;
- range.min_retry = 0;
- range.max_retry = 65535; /* ??? */
- range.min_r_time = 0;
- range.max_r_time = 65535 * 1000; /* ??? */
-
- if (copy_to_user(rrq->pointer, &range, sizeof(range)))
- return -EFAULT;
+ range->throughput = 1.5 * 1000 * 1000; /* ~1.5 Mb/s */
+
+ range->min_rts = 0;
+ range->max_rts = 2347;
+ range->min_frag = 256;
+ range->max_frag = 2346;
+
+ range->min_pmp = 0;
+ range->max_pmp = 65535000;
+ range->min_pmt = 0;
+ range->max_pmt = 65535 * 1000; /* ??? */
+ range->pmp_flags = IW_POWER_PERIOD;
+ range->pmt_flags = IW_POWER_TIMEOUT;
+ range->pm_capa = IW_POWER_PERIOD | IW_POWER_TIMEOUT | IW_POWER_UNICAST_R;
+
+ range->retry_capa = IW_RETRY_LIMIT | IW_RETRY_LIFETIME;
+ range->retry_flags = IW_RETRY_LIMIT;
+ range->r_time_flags = IW_RETRY_LIFETIME;
+ range->min_retry = 0;
+ range->max_retry = 65535; /* ??? */
+ range->min_r_time = 0;
+ range->max_r_time = 65535 * 1000; /* ??? */
TRACE_EXIT(dev->name);
return 0;
}
-static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setiwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *keybuf)
{
struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
@@ -2774,8 +2887,7 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
int enable = priv->wep_on;
int restricted = priv->wep_restrict;
u16 xlen = 0;
- int err = 0;
- char keybuf[ORINOCO_MAX_KEY_SIZE];
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (! priv->has_wep)
@@ -2788,9 +2900,6 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
if ( (erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep )
return -E2BIG;
-
- if (copy_from_user(keybuf, erq->pointer, erq->length))
- return -EFAULT;
}
if (orinoco_lock(priv, &flags) != 0)
@@ -2864,12 +2973,14 @@ static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *er
return err;
}
-static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getiwencode(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *keybuf)
{
struct orinoco_private *priv = netdev_priv(dev);
int index = (erq->flags & IW_ENCODE_INDEX) - 1;
u16 xlen = 0;
- char keybuf[ORINOCO_MAX_KEY_SIZE];
unsigned long flags;
if (! priv->has_wep)
@@ -2898,51 +3009,47 @@ static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *er
memcpy(keybuf, priv->keys[index].data, ORINOCO_MAX_KEY_SIZE);
orinoco_unlock(priv, &flags);
-
- if (erq->pointer) {
- if (copy_to_user(erq->pointer, keybuf, xlen))
- return -EFAULT;
- }
-
return 0;
}
-static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_setessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *essidbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char essidbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
/* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it
* anyway... - Jean II */
- memset(&essidbuf, 0, sizeof(essidbuf));
-
- if (erq->flags) {
- /* iwconfig includes the NUL in the specified length */
- if (erq->length > IW_ESSID_MAX_SIZE+1)
- return -E2BIG;
-
- if (copy_from_user(&essidbuf, erq->pointer, erq->length))
- return -EFAULT;
-
- essidbuf[IW_ESSID_MAX_SIZE] = '\0';
- }
+ /* Hum... Should not use Wireless Extension constant (may change),
+ * should use our own... - Jean II */
+ if (erq->length > IW_ESSID_MAX_SIZE)
+ return -E2BIG;
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(priv->desired_essid, essidbuf, sizeof(priv->desired_essid));
+ /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */
+ memset(priv->desired_essid, 0, sizeof(priv->desired_essid));
+
+ /* If not ANY, get the new ESSID */
+ if (erq->flags) {
+ memcpy(priv->desired_essid, essidbuf, erq->length);
+ }
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
+static int orinoco_ioctl_getessid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *erq,
+ char *essidbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char essidbuf[IW_ESSID_MAX_SIZE+1];
int active;
int err = 0;
unsigned long flags;
@@ -2956,51 +3063,46 @@ static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq)
} else {
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(essidbuf, priv->desired_essid, sizeof(essidbuf));
+ memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE + 1);
orinoco_unlock(priv, &flags);
}
erq->flags = 1;
erq->length = strlen(essidbuf) + 1;
- if (erq->pointer)
- if (copy_to_user(erq->pointer, essidbuf, erq->length))
- return -EFAULT;
TRACE_EXIT(dev->name);
return 0;
}
-static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_setnick(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *nrq,
+ char *nickbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
if (nrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
- memset(nickbuf, 0, sizeof(nickbuf));
-
- if (copy_from_user(nickbuf, nrq->pointer, nrq->length))
- return -EFAULT;
-
- nickbuf[nrq->length] = '\0';
-
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- memcpy(priv->nick, nickbuf, sizeof(priv->nick));
+ memset(priv->nick, 0, sizeof(priv->nick));
+ memcpy(priv->nick, nickbuf, nrq->length);
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
+static int orinoco_ioctl_getnick(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *nrq,
+ char *nickbuf)
{
struct orinoco_private *priv = netdev_priv(dev);
- char nickbuf[IW_ESSID_MAX_SIZE+1];
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3011,23 +3113,22 @@ static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq)
nrq->length = strlen(nickbuf)+1;
- if (copy_to_user(nrq->pointer, nickbuf, sizeof(nickbuf)))
- return -EFAULT;
-
return 0;
}
-static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
+static int orinoco_ioctl_setfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int chan = -1;
unsigned long flags;
+ int err = -EINPROGRESS; /* Call commit handler */
- /* We can only use this in Ad-Hoc demo mode to set the operating
- * frequency, or in IBSS mode to set the frequency where the IBSS
- * will be created - Jean II */
- if (priv->iw_mode != IW_MODE_ADHOC)
- return -EOPNOTSUPP;
+ /* In infrastructure mode the AP sets the channel */
+ if (priv->iw_mode == IW_MODE_INFRA)
+ return -EBUSY;
if ( (frq->e == 0) && (frq->m <= 1000) ) {
/* Setting by channel number */
@@ -3051,13 +3152,44 @@ static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq)
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
+
priv->channel = chan;
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ /* Fast channel change - no commit if successful */
+ hermes_t *hw = &priv->hw;
+ err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
+ HERMES_TEST_SET_CHANNEL,
+ chan, NULL);
+ }
orinoco_unlock(priv, &flags);
+ return err;
+}
+
+static int orinoco_ioctl_getfreq(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_freq *frq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int tmp;
+
+ /* Locking done in there */
+ tmp = orinoco_hw_get_freq(priv);
+ if (tmp < 0) {
+ return tmp;
+ }
+
+ frq->m = tmp;
+ frq->e = 1;
+
return 0;
}
-static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_getsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3083,7 +3215,10 @@ static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq)
return 0;
}
-static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
+static int orinoco_ioctl_setsens(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int val = srq->value;
@@ -3100,10 +3235,13 @@ static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq)
priv->ap_density = val;
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
int val = rrq->value;
@@ -3121,13 +3259,30 @@ static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq)
priv->rts_thresh = val;
orinoco_unlock(priv, &flags);
+ return -EINPROGRESS; /* Call commit handler */
+}
+
+static int orinoco_ioctl_getrts(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+
+ rrq->value = priv->rts_thresh;
+ rrq->disabled = (rrq->value == 2347);
+ rrq->fixed = 1;
+
return 0;
}
-static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_setfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3159,11 +3314,14 @@ static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq)
return err;
}
-static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
+static int orinoco_ioctl_getfrag(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *frq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
- int err = 0;
+ int err;
u16 val;
unsigned long flags;
@@ -3196,10 +3354,12 @@ static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq)
return err;
}
-static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_setrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
int ratemode = -1;
int bitrate; /* 100s of kilobits */
int i;
@@ -3235,10 +3395,13 @@ static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *rrq)
priv->bitratemode = ratemode;
orinoco_unlock(priv, &flags);
- return err;
+ return -EINPROGRESS;
}
-static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getrate(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3303,10 +3466,13 @@ static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *rrq)
return err;
}
-static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_setpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *prq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int err = 0;
+ int err = -EINPROGRESS; /* Call commit handler */
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3355,7 +3521,10 @@ static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq)
return err;
}
-static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
+static int orinoco_ioctl_getpower(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *prq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3403,7 +3572,10 @@ static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq)
return err;
}
-static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
+static int orinoco_ioctl_getretry(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *rrq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
hermes_t *hw = &priv->hw;
@@ -3454,10 +3626,38 @@ static int orinoco_ioctl_getretry(struct net_device *dev, struct iw_param *rrq)
return err;
}
-static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_reset(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int val = *( (int *) wrq->u.name );
+
+ if (! capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) {
+ printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name);
+
+ /* Firmware reset */
+ orinoco_reset(dev);
+ } else {
+ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+
+ schedule_work(&priv->reset_work);
+ }
+
+ return 0;
+}
+
+static int orinoco_ioctl_setibssport(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int val = *( (int *) extra );
unsigned long flags;
if (orinoco_lock(priv, &flags) != 0)
@@ -3469,28 +3669,28 @@ static int orinoco_ioctl_setibssport(struct net_device *dev, struct iwreq *wrq)
set_port_type(priv);
orinoco_unlock(priv, &flags);
- return 0;
+ return -EINPROGRESS; /* Call commit handler */
}
-static int orinoco_ioctl_getibssport(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getibssport(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int *val = (int *)wrq->u.name;
- unsigned long flags;
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
+ int *val = (int *) extra;
*val = priv->ibss_port;
- orinoco_unlock(priv, &flags);
-
return 0;
}
-static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_setport3(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int val = *( (int *) wrq->u.name );
+ int val = *( (int *) extra );
int err = 0;
unsigned long flags;
@@ -3519,51 +3719,131 @@ static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq)
err = -EINVAL;
}
- if (! err)
+ if (! err) {
/* Actually update the mode we are using */
set_port_type(priv);
+ err = -EINPROGRESS;
+ }
orinoco_unlock(priv, &flags);
return err;
}
-static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq)
+static int orinoco_ioctl_getport3(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int *val = (int *) extra;
+
+ *val = priv->prefer_port3;
+ return 0;
+}
+
+static int orinoco_ioctl_setpreamble(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- int *val = (int *)wrq->u.name;
unsigned long flags;
+ int val;
+
+ if (! priv->has_preamble)
+ return -EOPNOTSUPP;
+
+ /* 802.11b has recently defined some short preamble.
+ * Basically, the Phy header has been reduced in size.
+ * This increase performance, especially at high rates
+ * (the preamble is transmitted at 1Mb/s), unfortunately
+ * this give compatibility troubles... - Jean II */
+ val = *( (int *) extra );
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
- *val = priv->prefer_port3;
+ if (val)
+ priv->preamble = 1;
+ else
+ priv->preamble = 0;
+
orinoco_unlock(priv, &flags);
+
+ return -EINPROGRESS; /* Call commit handler */
+}
+
+static int orinoco_ioctl_getpreamble(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int *val = (int *) extra;
+
+ if (! priv->has_preamble)
+ return -EOPNOTSUPP;
+
+ *val = priv->preamble;
return 0;
}
+/* ioctl interface to hermes_read_ltv()
+ * To use with iwpriv, pass the RID as the token argument, e.g.
+ * iwpriv get_rid [0xfc00]
+ * At least Wireless Tools 25 is required to use iwpriv.
+ * For Wireless Tools 25 and 26 append "dummy" are the end. */
+static int orinoco_ioctl_getrid(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *data,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ hermes_t *hw = &priv->hw;
+ int rid = data->flags;
+ u16 length;
+ int err;
+ unsigned long flags;
+
+ /* It's a "get" function, but we don't want users to access the
+ * WEP key and other raw firmware data */
+ if (! capable(CAP_NET_ADMIN))
+ return -EPERM;
+
+ if (rid < 0xfc00 || rid > 0xffff)
+ return -EINVAL;
+
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
+
+ err = hermes_read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length,
+ extra);
+ if (err)
+ goto out;
+
+ data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length),
+ MAX_RID_LEN);
+
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
+
/* Spy is used for link quality/strength measurements in Ad-Hoc mode
* Jean II */
-static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_setspy(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
+
{
struct orinoco_private *priv = netdev_priv(dev);
- struct sockaddr address[IW_MAX_SPY];
+ struct sockaddr *address = (struct sockaddr *) extra;
int number = srq->length;
int i;
- int err = 0;
unsigned long flags;
- /* Check the number of addresses */
- if (number > IW_MAX_SPY)
- return -E2BIG;
-
- /* Get the data in the driver */
- if (srq->pointer) {
- if (copy_from_user(address, srq->pointer,
- sizeof(struct sockaddr) * number))
- return -EFAULT;
- }
-
/* Make sure nobody mess with the structure while we do */
if (orinoco_lock(priv, &flags) != 0)
return -EBUSY;
@@ -3587,14 +3867,17 @@ static int orinoco_ioctl_setspy(struct net_device *dev, struct iw_point *srq)
/* Now, let the others play */
orinoco_unlock(priv, &flags);
- return err;
+ /* Do NOT call commit handler */
+ return 0;
}
-static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
+static int orinoco_ioctl_getspy(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- struct sockaddr address[IW_MAX_SPY];
- struct iw_quality spy_stat[IW_MAX_SPY];
+ struct sockaddr *address = (struct sockaddr *) extra;
int number;
int i;
unsigned long flags;
@@ -3603,7 +3886,12 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
return -EBUSY;
number = priv->spy_number;
- if ((number > 0) && (srq->pointer)) {
+ /* Create address struct */
+ for (i = 0; i < number; i++) {
+ memcpy(address[i].sa_data, priv->spy_address[i], ETH_ALEN);
+ address[i].sa_family = AF_UNIX;
+ }
+ if (number > 0) {
/* Create address struct */
for (i = 0; i < number; i++) {
memcpy(address[i].sa_data, priv->spy_address[i],
@@ -3614,344 +3902,503 @@ static int orinoco_ioctl_getspy(struct net_device *dev, struct iw_point *srq)
/* In theory, we should disable irqs while copying the stats
* because the rx path might update it in the middle...
* Bah, who care ? - Jean II */
- memcpy(&spy_stat, priv->spy_stat,
- sizeof(struct iw_quality) * IW_MAX_SPY);
- for (i=0; i < number; i++)
- priv->spy_stat[i].updated = 0;
+ memcpy(extra + (sizeof(struct sockaddr) * number),
+ priv->spy_stat, sizeof(struct iw_quality) * number);
}
+ /* Reset updated flags. */
+ for (i = 0; i < number; i++)
+ priv->spy_stat[i].updated = 0;
orinoco_unlock(priv, &flags);
- /* Push stuff to user space */
srq->length = number;
- if(copy_to_user(srq->pointer, address,
- sizeof(struct sockaddr) * number))
- return -EFAULT;
- if(copy_to_user(srq->pointer + (sizeof(struct sockaddr)*number),
- &spy_stat, sizeof(struct iw_quality) * number))
- return -EFAULT;
return 0;
}
-static int
-orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/* Trigger a scan (look for other cells in the vicinity */
+static int orinoco_ioctl_setscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_param *srq,
+ char *extra)
{
struct orinoco_private *priv = netdev_priv(dev);
- struct iwreq *wrq = (struct iwreq *)rq;
+ hermes_t *hw = &priv->hw;
int err = 0;
- int tmp;
- int changed = 0;
unsigned long flags;
- TRACE_ENTER(dev->name);
+ /* Note : you may have realised that, as this is a SET operation,
+ * this is priviledged and therefore a normal user can't
+ * perform scanning.
+ * This is not an error, while the device perform scanning,
+ * traffic doesn't flow, so it's a perfect DoS...
+ * Jean II */
- /* In theory, we could allow most of the the SET stuff to be
- * done. In practice, the lapse of time at startup when the
- * card is not ready is very short, so why bother... Note
- * that netif_device_present is different from up/down
- * (ifconfig), when the device is not yet up, it is usually
- * already ready... Jean II */
- if (! netif_device_present(dev))
- return -ENODEV;
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
- switch (cmd) {
- case SIOCGIWNAME:
- strcpy(wrq->u.name, "IEEE 802.11-DS");
- break;
-
- case SIOCGIWAP:
- wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
- err = orinoco_hw_get_bssid(priv, wrq->u.ap_addr.sa_data);
- break;
+ /* Scanning with port 0 disabled would fail */
+ if (!netif_running(dev)) {
+ err = -ENETDOWN;
+ goto out;
+ }
- case SIOCGIWRANGE:
- err = orinoco_ioctl_getiwrange(dev, &wrq->u.data);
- break;
+ /* In monitor mode, the scan results are always empty.
+ * Probe responses are passed to the driver as received
+ * frames and could be processed in software. */
+ if (priv->iw_mode == IW_MODE_MONITOR) {
+ err = -EOPNOTSUPP;
+ goto out;
+ }
- case SIOCSIWMODE:
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- switch (wrq->u.mode) {
- case IW_MODE_ADHOC:
- if (! (priv->has_ibss || priv->has_port3) )
- err = -EINVAL;
- else {
- priv->iw_mode = IW_MODE_ADHOC;
- changed = 1;
- }
- break;
+ /* Note : because we don't lock out the irq handler, the way
+ * we access scan variables in priv is critical.
+ * o scan_inprogress : not touched by irq handler
+ * o scan_mode : not touched by irq handler
+ * o scan_result : irq is strict producer, non-irq is strict
+ * consumer.
+ * o scan_len : synchronised with scan_result
+ * Before modifying anything on those variables, please think hard !
+ * Jean II */
- case IW_MODE_INFRA:
- priv->iw_mode = IW_MODE_INFRA;
- changed = 1;
- break;
+ /* If there is still some left-over scan results, get rid of it */
+ if (priv->scan_result != NULL) {
+ /* What's likely is that a client did crash or was killed
+ * between triggering the scan request and reading the
+ * results, so we need to reset everything.
+ * Some clients that are too slow may suffer from that...
+ * Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+ }
- default:
- err = -EINVAL;
- break;
- }
- set_port_type(priv);
- orinoco_unlock(priv, &flags);
- break;
+ /* Save flags */
+ priv->scan_mode = srq->flags;
- case SIOCGIWMODE:
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- wrq->u.mode = priv->iw_mode;
- orinoco_unlock(priv, &flags);
- break;
+ /* Always trigger scanning, even if it's in progress.
+ * This way, if the info frame get lost, we will recover somewhat
+ * gracefully - Jean II */
- case SIOCSIWENCODE:
- err = orinoco_ioctl_setiwencode(dev, &wrq->u.encoding);
- if (! err)
- changed = 1;
+ if (priv->has_hostscan) {
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_SYMBOL:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN_SYMBOL,
+ HERMES_HOSTSCAN_SYMBOL_ONCE |
+ HERMES_HOSTSCAN_SYMBOL_BCAST);
+ break;
+ case FIRMWARE_TYPE_INTERSIL: {
+ u16 req[3];
+
+ req[0] = cpu_to_le16(0x3fff); /* All channels */
+ req[1] = cpu_to_le16(0x0001); /* rate 1 Mbps */
+ req[2] = 0; /* Any ESSID */
+ err = HERMES_WRITE_RECORD(hw, USER_BAP,
+ HERMES_RID_CNFHOSTSCAN, &req);
+ }
break;
+ case FIRMWARE_TYPE_AGERE:
+ err = hermes_write_wordrec(hw, USER_BAP,
+ HERMES_RID_CNFSCANSSID_AGERE,
+ 0); /* Any ESSID */
+ if (err)
+ break;
- case SIOCGIWENCODE:
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
break;
}
+ } else
+ err = hermes_inquire(hw, HERMES_INQ_SCAN);
- err = orinoco_ioctl_getiwencode(dev, &wrq->u.encoding);
- break;
-
- case SIOCSIWESSID:
- err = orinoco_ioctl_setessid(dev, &wrq->u.essid);
- if (! err)
- changed = 1;
- break;
+ /* One more client */
+ if (! err)
+ priv->scan_inprogress = 1;
- case SIOCGIWESSID:
- err = orinoco_ioctl_getessid(dev, &wrq->u.essid);
- break;
+ out:
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCSIWNICKN:
- err = orinoco_ioctl_setnick(dev, &wrq->u.data);
- if (! err)
- changed = 1;
- break;
+/* Translate scan data returned from the card to a card independant
+ * format that the Wireless Tools will understand - Jean II */
+static inline int orinoco_translate_scan(struct net_device *dev,
+ char *buffer,
+ char *scan,
+ int scan_len)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int offset; /* In the scan data */
+ union hermes_scan_info *atom;
+ int atom_len;
+ u16 capabilities;
+ u16 channel;
+ struct iw_event iwe; /* Temporary buffer */
+ char * current_ev = buffer;
+ char * end_buf = buffer + IW_SCAN_MAX_DATA;
- case SIOCGIWNICKN:
- err = orinoco_ioctl_getnick(dev, &wrq->u.data);
+ switch (priv->firmware_type) {
+ case FIRMWARE_TYPE_AGERE:
+ atom_len = sizeof(struct agere_scan_apinfo);
+ offset = 0;
break;
-
- case SIOCGIWFREQ:
- tmp = orinoco_hw_get_freq(priv);
- if (tmp < 0) {
- err = tmp;
- } else {
- wrq->u.freq.m = tmp;
- wrq->u.freq.e = 1;
- }
+ case FIRMWARE_TYPE_SYMBOL:
+ /* Lack of documentation necessitates this hack.
+ * Different firmwares have 68 or 76 byte long atoms.
+ * We try modulo first. If the length divides by both,
+ * we check what would be the channel in the second
+ * frame for a 68-byte atom. 76-byte atoms have 0 there.
+ * Valid channel cannot be 0. */
+ if (scan_len % 76)
+ atom_len = 68;
+ else if (scan_len % 68)
+ atom_len = 76;
+ else if (scan_len >= 1292 && scan[68] == 0)
+ atom_len = 76;
+ else
+ atom_len = 68;
+ offset = 0;
break;
-
- case SIOCSIWFREQ:
- err = orinoco_ioctl_setfreq(dev, &wrq->u.freq);
- if (! err)
- changed = 1;
+ case FIRMWARE_TYPE_INTERSIL:
+ offset = 4;
+ if (priv->has_hostscan)
+ atom_len = scan[0] + (scan[1] << 8);
+ else
+ atom_len = offsetof(struct prism2_scan_apinfo, atim);
break;
+ default:
+ return 0;
+ }
- case SIOCGIWSENS:
- err = orinoco_ioctl_getsens(dev, &wrq->u.sens);
- break;
+ /* Check that we got an whole number of atoms */
+ if ((scan_len - offset) % atom_len) {
+ printk(KERN_ERR "%s: Unexpected scan data length %d, "
+ "atom_len %d, offset %d\n", dev->name, scan_len,
+ atom_len, offset);
+ return 0;
+ }
- case SIOCSIWSENS:
- err = orinoco_ioctl_setsens(dev, &wrq->u.sens);
- if (! err)
- changed = 1;
- break;
+ /* Read the entries one by one */
+ for (; offset + atom_len <= scan_len; offset += atom_len) {
+ /* Get next atom */
+ atom = (union hermes_scan_info *) (scan + offset);
+
+ /* First entry *MUST* be the AP MAC address */
+ iwe.cmd = SIOCGIWAP;
+ iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwe.u.ap_addr.sa_data, atom->a.bssid, ETH_ALEN);
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_ADDR_LEN);
+
+ /* Other entries will be displayed in the order we give them */
+
+ /* Add the ESSID */
+ iwe.u.data.length = le16_to_cpu(atom->a.essid_len);
+ if (iwe.u.data.length > 32)
+ iwe.u.data.length = 32;
+ iwe.cmd = SIOCGIWESSID;
+ iwe.u.data.flags = 1;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+ /* Add mode */
+ iwe.cmd = SIOCGIWMODE;
+ capabilities = le16_to_cpu(atom->a.capabilities);
+ if (capabilities & 0x3) {
+ if (capabilities & 0x1)
+ iwe.u.mode = IW_MODE_MASTER;
+ else
+ iwe.u.mode = IW_MODE_ADHOC;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_UINT_LEN);
+ }
- case SIOCGIWRTS:
- wrq->u.rts.value = priv->rts_thresh;
- wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
- wrq->u.rts.fixed = 1;
- break;
+ channel = atom->s.channel;
+ if ( (channel >= 1) && (channel <= NUM_CHANNELS) ) {
+ /* Add frequency */
+ iwe.cmd = SIOCGIWFREQ;
+ iwe.u.freq.m = channel_frequency[channel-1] * 100000;
+ iwe.u.freq.e = 1;
+ current_ev = iwe_stream_add_event(current_ev, end_buf,
+ &iwe, IW_EV_FREQ_LEN);
+ }
- case SIOCSIWRTS:
- err = orinoco_ioctl_setrts(dev, &wrq->u.rts);
- if (! err)
- changed = 1;
- break;
+ /* Add quality statistics */
+ iwe.cmd = IWEVQUAL;
+ iwe.u.qual.updated = 0x10; /* no link quality */
+ iwe.u.qual.level = (__u8) le16_to_cpu(atom->a.level) - 0x95;
+ iwe.u.qual.noise = (__u8) le16_to_cpu(atom->a.noise) - 0x95;
+ /* Wireless tools prior to 27.pre22 will show link quality
+ * anyway, so we provide a reasonable value. */
+ if (iwe.u.qual.level > iwe.u.qual.noise)
+ iwe.u.qual.qual = iwe.u.qual.level - iwe.u.qual.noise;
+ else
+ iwe.u.qual.qual = 0;
+ current_ev = iwe_stream_add_event(current_ev, end_buf, &iwe, IW_EV_QUAL_LEN);
- case SIOCSIWFRAG:
- err = orinoco_ioctl_setfrag(dev, &wrq->u.frag);
- if (! err)
- changed = 1;
- break;
+ /* Add encryption capability */
+ iwe.cmd = SIOCGIWENCODE;
+ if (capabilities & 0x10)
+ iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
+ else
+ iwe.u.data.flags = IW_ENCODE_DISABLED;
+ iwe.u.data.length = 0;
+ current_ev = iwe_stream_add_point(current_ev, end_buf, &iwe, atom->a.essid);
+
+ /* Bit rate is not available in Lucent/Agere firmwares */
+ if (priv->firmware_type != FIRMWARE_TYPE_AGERE) {
+ char * current_val = current_ev + IW_EV_LCP_LEN;
+ int i;
+ int step;
+
+ if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL)
+ step = 2;
+ else
+ step = 1;
+
+ iwe.cmd = SIOCGIWRATE;
+ /* Those two flags are ignored... */
+ iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
+ /* Max 10 values */
+ for (i = 0; i < 10; i += step) {
+ /* NULL terminated */
+ if (atom->p.rates[i] == 0x0)
+ break;
+ /* Bit rate given in 500 kb/s units (+ 0x80) */
+ iwe.u.bitrate.value = ((atom->p.rates[i] & 0x7f) * 500000);
+ current_val = iwe_stream_add_value(current_ev, current_val,
+ end_buf, &iwe,
+ IW_EV_PARAM_LEN);
+ }
+ /* Check if we added any event */
+ if ((current_val - current_ev) > IW_EV_LCP_LEN)
+ current_ev = current_val;
+ }
- case SIOCGIWFRAG:
- err = orinoco_ioctl_getfrag(dev, &wrq->u.frag);
- break;
+ /* The other data in the scan result are not really
+ * interesting, so for now drop it - Jean II */
+ }
+ return current_ev - buffer;
+}
- case SIOCSIWRATE:
- err = orinoco_ioctl_setrate(dev, &wrq->u.bitrate);
- if (! err)
- changed = 1;
- break;
+/* Return results of a scan */
+static int orinoco_ioctl_getscan(struct net_device *dev,
+ struct iw_request_info *info,
+ struct iw_point *srq,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ int err = 0;
+ unsigned long flags;
- case SIOCGIWRATE:
- err = orinoco_ioctl_getrate(dev, &wrq->u.bitrate);
- break;
+ if (orinoco_lock(priv, &flags) != 0)
+ return -EBUSY;
- case SIOCSIWPOWER:
- err = orinoco_ioctl_setpower(dev, &wrq->u.power);
- if (! err)
- changed = 1;
- break;
+ /* If no results yet, ask to try again later */
+ if (priv->scan_result == NULL) {
+ if (priv->scan_inprogress)
+ /* Important note : we don't want to block the caller
+ * until results are ready for various reasons.
+ * First, managing wait queues is complex and racy.
+ * Second, we grab some rtnetlink lock before comming
+ * here (in dev_ioctl()).
+ * Third, we generate an Wireless Event, so the
+ * caller can wait itself on that - Jean II */
+ err = -EAGAIN;
+ else
+ /* Client error, no scan results...
+ * The caller need to restart the scan. */
+ err = -ENODATA;
+ } else {
+ /* We have some results to push back to user space */
+
+ /* Translate to WE format */
+ srq->length = orinoco_translate_scan(dev, extra,
+ priv->scan_result,
+ priv->scan_len);
+
+ /* Return flags */
+ srq->flags = (__u16) priv->scan_mode;
+
+ /* Results are here, so scan no longer in progress */
+ priv->scan_inprogress = 0;
+
+ /* In any case, Scan results will be cleaned up in the
+ * reset function and when exiting the driver.
+ * The person triggering the scanning may never come to
+ * pick the results, so we need to do it in those places.
+ * Jean II */
+
+#ifdef SCAN_SINGLE_READ
+ /* If you enable this option, only one client (the first
+ * one) will be able to read the result (and only one
+ * time). If there is multiple concurent clients that
+ * want to read scan results, this behavior is not
+ * advisable - Jean II */
+ kfree(priv->scan_result);
+ priv->scan_result = NULL;
+#endif /* SCAN_SINGLE_READ */
+ /* Here, if too much time has elapsed since last scan,
+ * we may want to clean up scan results... - Jean II */
+ }
+
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCGIWPOWER:
- err = orinoco_ioctl_getpower(dev, &wrq->u.power);
- break;
+/* Commit handler, called after set operations */
+static int orinoco_ioctl_commit(struct net_device *dev,
+ struct iw_request_info *info,
+ void *wrqu,
+ char *extra)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
+ struct hermes *hw = &priv->hw;
+ unsigned long flags;
+ int err = 0;
- case SIOCGIWTXPOW:
- /* The card only supports one tx power, so this is easy */
- wrq->u.txpower.value = 15; /* dBm */
- wrq->u.txpower.fixed = 1;
- wrq->u.txpower.disabled = 0;
- wrq->u.txpower.flags = IW_TXPOW_DBM;
- break;
+ if (!priv->open)
+ return 0;
- case SIOCSIWRETRY:
- err = -EOPNOTSUPP;
- break;
+ if (priv->broken_disableport) {
+ orinoco_reset(dev);
+ return 0;
+ }
- case SIOCGIWRETRY:
- err = orinoco_ioctl_getretry(dev, &wrq->u.retry);
- break;
+ if (orinoco_lock(priv, &flags) != 0)
+ return err;
- case SIOCSIWSPY:
- err = orinoco_ioctl_setspy(dev, &wrq->u.data);
- break;
+ 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;
+ }
- case SIOCGIWSPY:
- err = orinoco_ioctl_getspy(dev, &wrq->u.data);
- break;
+ err = __orinoco_program_rids(dev);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to reconfigure card\n",
+ dev->name);
+ goto out;
+ }
- case SIOCGIWPRIV:
- if (wrq->u.data.pointer) {
- struct iw_priv_args privtab[] = {
- { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
- { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
- { SIOCIWFIRSTPRIV + 0x2,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_port3" },
- { SIOCIWFIRSTPRIV + 0x3, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_port3" },
- { SIOCIWFIRSTPRIV + 0x4,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_preamble" },
- { SIOCIWFIRSTPRIV + 0x5, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_preamble" },
- { SIOCIWFIRSTPRIV + 0x6,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- 0, "set_ibssport" },
- { SIOCIWFIRSTPRIV + 0x7, 0,
- IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
- "get_ibssport" },
- };
-
- wrq->u.data.length = sizeof(privtab) / sizeof(privtab[0]);
- if (copy_to_user(wrq->u.data.pointer, privtab, sizeof(privtab)))
- err = -EFAULT;
- }
- break;
-
- case SIOCIWFIRSTPRIV + 0x0: /* force_reset */
- case SIOCIWFIRSTPRIV + 0x1: /* card_reset */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
-
- printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name);
+ err = hermes_enable_port(hw, 0);
+ if (err) {
+ printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n",
+ dev->name);
+ goto out;
+ }
+ out:
+ if (err) {
+ printk(KERN_WARNING "%s: Resetting instead...\n", dev->name);
schedule_work(&priv->reset_work);
- break;
-
- case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
-
- err = orinoco_ioctl_setport3(dev, wrq);
- if (! err)
- changed = 1;
- break;
+ err = 0;
+ }
- case SIOCIWFIRSTPRIV + 0x3: /* get_port3 */
- err = orinoco_ioctl_getport3(dev, wrq);
- break;
+ orinoco_unlock(priv, &flags);
+ return err;
+}
- case SIOCIWFIRSTPRIV + 0x4: /* set_preamble */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
+static const struct iw_priv_args orinoco_privtab[] = {
+ { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" },
+ { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" },
+ { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_port3" },
+ { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_port3" },
+ { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_preamble" },
+ { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_preamble" },
+ { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ 0, "set_ibssport" },
+ { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
+ "get_ibssport" },
+ { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN,
+ "get_rid" },
+};
- /* 802.11b has recently defined some short preamble.
- * Basically, the Phy header has been reduced in size.
- * This increase performance, especially at high rates
- * (the preamble is transmitted at 1Mb/s), unfortunately
- * this give compatibility troubles... - Jean II */
- if(priv->has_preamble) {
- int val = *( (int *) wrq->u.name );
-
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- if (val)
- priv->preamble = 1;
- else
- priv->preamble = 0;
- orinoco_unlock(priv, &flags);
- changed = 1;
- } else
- err = -EOPNOTSUPP;
- break;
- case SIOCIWFIRSTPRIV + 0x5: /* get_preamble */
- if(priv->has_preamble) {
- int *val = (int *)wrq->u.name;
+/*
+ * Structures to export the Wireless Handlers
+ */
- if (orinoco_lock(priv, &flags) != 0)
- return -EBUSY;
- *val = priv->preamble;
- orinoco_unlock(priv, &flags);
- } else
- err = -EOPNOTSUPP;
- break;
- case SIOCIWFIRSTPRIV + 0x6: /* set_ibssport */
- if (! capable(CAP_NET_ADMIN)) {
- err = -EPERM;
- break;
- }
+static const iw_handler orinoco_handler[] = {
+ [SIOCSIWCOMMIT-SIOCIWFIRST] (iw_handler) orinoco_ioctl_commit,
+ [SIOCGIWNAME -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getname,
+ [SIOCSIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfreq,
+ [SIOCGIWFREQ -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfreq,
+ [SIOCSIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setmode,
+ [SIOCGIWMODE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getmode,
+ [SIOCSIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setsens,
+ [SIOCGIWSENS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getsens,
+ [SIOCGIWRANGE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwrange,
+ [SIOCSIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setspy,
+ [SIOCGIWSPY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getspy,
+ [SIOCSIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setwap,
+ [SIOCGIWAP -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getwap,
+ [SIOCSIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setscan,
+ [SIOCGIWSCAN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getscan,
+ [SIOCSIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setessid,
+ [SIOCGIWESSID -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getessid,
+ [SIOCSIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setnick,
+ [SIOCGIWNICKN -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getnick,
+ [SIOCSIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrate,
+ [SIOCGIWRATE -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrate,
+ [SIOCSIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setrts,
+ [SIOCGIWRTS -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getrts,
+ [SIOCSIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setfrag,
+ [SIOCGIWFRAG -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getfrag,
+ [SIOCGIWRETRY -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getretry,
+ [SIOCSIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_setiwencode,
+ [SIOCGIWENCODE-SIOCIWFIRST] (iw_handler) orinoco_ioctl_getiwencode,
+ [SIOCSIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_setpower,
+ [SIOCGIWPOWER -SIOCIWFIRST] (iw_handler) orinoco_ioctl_getpower,
+};
- err = orinoco_ioctl_setibssport(dev, wrq);
- if (! err)
- changed = 1;
- break;
- case SIOCIWFIRSTPRIV + 0x7: /* get_ibssport */
- err = orinoco_ioctl_getibssport(dev, wrq);
- break;
+/*
+ Added typecasting since we no longer use iwreq_data -- Moustafa
+ */
+static const iw_handler orinoco_private_handler[] = {
+ [0] (iw_handler) orinoco_ioctl_reset,
+ [1] (iw_handler) orinoco_ioctl_reset,
+ [2] (iw_handler) orinoco_ioctl_setport3,
+ [3] (iw_handler) orinoco_ioctl_getport3,
+ [4] (iw_handler) orinoco_ioctl_setpreamble,
+ [5] (iw_handler) orinoco_ioctl_getpreamble,
+ [6] (iw_handler) orinoco_ioctl_setibssport,
+ [7] (iw_handler) orinoco_ioctl_getibssport,
+ [9] (iw_handler) orinoco_ioctl_getrid,
+};
- default:
- err = -EOPNOTSUPP;
- }
-
- if (! err && changed && netif_running(dev)) {
- err = orinoco_reconfigure(dev);
- }
+static const struct iw_handler_def orinoco_handler_def = {
+ .num_standard = ARRAY_SIZE(orinoco_handler),
+ .num_private = ARRAY_SIZE(orinoco_private_handler),
+ .num_private_args = ARRAY_SIZE(orinoco_privtab),
+ .standard = orinoco_handler,
+ .private = orinoco_private_handler,
+ .private_args = orinoco_privtab,
+};
- TRACE_EXIT(dev->name);
+static void orinoco_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *info)
+{
+ struct orinoco_private *priv = netdev_priv(dev);
- return err;
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver) - 1);
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1);
+ strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1);
+ if (dev->class_dev.dev)
+ strncpy(info->bus_info, dev->class_dev.dev->bus_id,
+ sizeof(info->bus_info) - 1);
+ else
+ snprintf(info->bus_info, sizeof(info->bus_info) - 1,
+ "PCMCIA %p", priv->hw.iobase);
}
+static struct ethtool_ops orinoco_ethtool_ops = {
+ .get_drvinfo = orinoco_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+};
/********************************************************************/
/* Debugging */
diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h
index f749b50d1088..2f213a7103fe 100644
--- a/drivers/net/wireless/orinoco.h
+++ b/drivers/net/wireless/orinoco.h
@@ -7,7 +7,7 @@
#ifndef _ORINOCO_H
#define _ORINOCO_H
-#define DRIVER_VERSION "0.14alpha2"
+#define DRIVER_VERSION "0.15rc2"
#include <linux/types.h>
#include <linux/spinlock.h>
@@ -22,6 +22,8 @@
#define WIRELESS_SPY // enable iwspy support
+#define MAX_SCAN_LEN 4096
+
#define ORINOCO_MAX_KEY_SIZE 14
#define ORINOCO_MAX_KEYS 4
@@ -30,6 +32,20 @@ struct orinoco_key {
char data[ORINOCO_MAX_KEY_SIZE];
} __attribute__ ((packed));
+struct header_struct {
+ /* 802.3 */
+ u8 dest[ETH_ALEN];
+ u8 src[ETH_ALEN];
+ u16 len;
+ /* 802.2 */
+ u8 dsap;
+ u8 ssap;
+ u8 ctrl;
+ /* SNAP */
+ u8 oui[3];
+ u16 ethertype;
+} __attribute__ ((packed));
+
typedef enum {
FIRMWARE_TYPE_AGERE,
FIRMWARE_TYPE_INTERSIL,
@@ -48,6 +64,8 @@ struct orinoco_private {
/* driver state */
int open;
u16 last_linkstatus;
+ struct work_struct join_work;
+ struct work_struct wevent_work;
/* Net device stuff */
struct net_device *ndev;
@@ -74,7 +92,9 @@ struct orinoco_private {
unsigned int has_pm:1;
unsigned int has_preamble:1;
unsigned int has_sensitivity:1;
+ unsigned int has_hostscan:1;
unsigned int broken_disableport:1;
+ unsigned int broken_monitor:1;
/* Configuration paramaters */
u32 iw_mode;
@@ -84,6 +104,8 @@ struct orinoco_private {
int bitratemode;
char nick[IW_ESSID_MAX_SIZE+1];
char desired_essid[IW_ESSID_MAX_SIZE+1];
+ char desired_bssid[ETH_ALEN];
+ int bssid_fixed;
u16 frag_thresh, mwo_robust;
u16 channel;
u16 ap_density, rts_thresh;
@@ -98,6 +120,12 @@ struct orinoco_private {
/* Configuration dependent variables */
int port_type, createibss;
int promiscuous, mc_count;
+
+ /* Scanning support */
+ int scan_inprogress; /* Scan pending... */
+ u32 scan_mode; /* Type of scan done */
+ char * scan_result; /* Result of previous scan */
+ int scan_len; /* Lenght of result */
};
#ifdef ORINOCO_DEBUG
diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c
index 74a8227256aa..368d2f962f67 100644
--- a/drivers/net/wireless/orinoco_cs.c
+++ b/drivers/net/wireless/orinoco_cs.c
@@ -31,7 +31,6 @@
#include <linux/etherdevice.h>
#include <linux/wireless.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -186,11 +185,6 @@ orinoco_cs_attach(void)
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &orinoco_cs_event;
client_reg.Version = 0x0210; /* FIXME: what does this mean? */
client_reg.event_callback_args.client_data = link;
@@ -608,13 +602,65 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION
" (David Gibson <hermes@gibson.dropbear.id.au>, "
"Pavel Roskin <proski@gnu.org>, et al)";
+static struct pcmcia_device_id orinoco_cs_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300),
+ PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a),
+ PCMCIA_DEVICE_MANF_CARD(0x0261, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x0268, 0x0001),
+ PCMCIA_DEVICE_MANF_CARD(0x026f, 0x0305),
+ PCMCIA_DEVICE_MANF_CARD(0x0274, 0x1613),
+ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x028a, 0x0673),
+ PCMCIA_DEVICE_MANF_CARD(0x02aa, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x02ac, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0x14ea, 0xb001),
+ PCMCIA_DEVICE_MANF_CARD(0x50c2, 0x7300),
+ PCMCIA_DEVICE_MANF_CARD(0x9005, 0x0021),
+ PCMCIA_DEVICE_MANF_CARD(0xc250, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0002),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0005),
+ PCMCIA_DEVICE_PROD_ID12("3Com", "3CRWE737A AirConnect Wireless LAN PC Card", 0x41240e5b, 0x56010af3),
+ PCMCIA_DEVICE_PROD_ID123("Instant Wireless ", " Network PC CARD", "Version 01.02", 0x11d901af, 0x6e9bd926, 0x4b74baa0),
+ PCMCIA_DEVICE_PROD_ID12("ACTIONTEC", "PRISM Wireless LAN PC Card", 0x393089da, 0xa71e69d5),
+ PCMCIA_DEVICE_PROD_ID12("Avaya Communication", "Avaya Wireless PC Card", 0xd8a43b78, 0x0d341169),
+ PCMCIA_DEVICE_PROD_ID12("BUFFALO", "WLI-PCM-L11G", 0x2decece3, 0xf57ca4b3),
+ PCMCIA_DEVICE_PROD_ID12("Cabletron", "RoamAbout 802.11 DS", 0x32d445f5, 0xedeffd90),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCC-11", 0x5261440f, 0xa6405584),
+ PCMCIA_DEVICE_PROD_ID12("corega K.K.", "Wireless LAN PCCA-11", 0x5261440f, 0xdf6115f9),
+ PCMCIA_DEVICE_PROD_ID12("D", "Link DRC-650 11Mbps WLAN Card", 0x71b18589, 0xf144e3ac),
+ PCMCIA_DEVICE_PROD_ID12("D", "Link DWL-650 11Mbps WLAN Card", 0x71b18589, 0xb6f1b0ab),
+ PCMCIA_DEVICE_PROD_ID12("ELSA", "AirLancer MC-11", 0x4507a33a, 0xef54f0e3),
+ PCMCIA_DEVICE_PROD_ID12("HyperLink", "Wireless PC Card 11Mbps", 0x56cc3f1a, 0x0bcf220c),
+ PCMCIA_DEVICE_PROD_ID12("INTERSIL", "HFA384x/IEEE", 0x74c5e40d, 0xdb472a18),
+ PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/IEEE", 0x23eb9949, 0xc562e72a),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11", 0x481e0094, 0x7360e410),
+ PCMCIA_DEVICE_PROD_ID12("MELCO", "WLI-PCM-L11G", 0x481e0094, 0xf57ca4b3),
+ PCMCIA_DEVICE_PROD_ID12("Microsoft", "Wireless Notebook Adapter MN-520", 0x5961bf85, 0x6eec8c01),
+ PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/IEEE", 0x24358cd4, 0xc562e72a),
+ PCMCIA_DEVICE_PROD_ID12("NETGEAR MA401RA Wireless PC", "Card", 0x0306467f, 0x9762e8f1),
+ PCMCIA_DEVICE_PROD_ID12("PLANEX", "GeoWave/GW-CF110", 0x209f40ab, 0xd9715264),
+ PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PC CARD HARMONY 80211B", 0xc6536a5e, 0x090c3cd9),
+ PCMCIA_DEVICE_PROD_ID12("PROXIM", "LAN PCI CARD HARMONY 80211B", 0xc6536a5e, 0x9f494e26),
+ PCMCIA_DEVICE_PROD_ID12("SAMSUNG", "11Mbps WLAN Card", 0x43d74cb4, 0x579bd91b),
+ PCMCIA_DEVICE_PROD_ID1("Symbol Technologies", 0x3f02b4d6),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, orinoco_cs_ids);
+
static struct pcmcia_driver orinoco_driver = {
.owner = THIS_MODULE,
.drv = {
.name = DRIVER_NAME,
},
.attach = orinoco_cs_attach,
+ .event = orinoco_cs_event,
.detach = orinoco_cs_detach,
+ .id_table = orinoco_cs_ids,
};
static int __init
diff --git a/drivers/net/wireless/prism54/isl_38xx.c b/drivers/net/wireless/prism54/isl_38xx.c
index 4481ec18c5a0..adc7499136dc 100644
--- a/drivers/net/wireless/prism54/isl_38xx.c
+++ b/drivers/net/wireless/prism54/isl_38xx.c
@@ -112,10 +112,10 @@ isl38xx_handle_wakeup(isl38xx_control_block *control_block,
void
isl38xx_trigger_device(int asleep, void __iomem *device_base)
{
- struct timeval current_time;
u32 reg, counter = 0;
#if VERBOSE > SHOW_ERROR_MESSAGES
+ struct timeval current_time;
DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
#endif
@@ -126,11 +126,11 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
do_gettimeofday(&current_time);
DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
current_time.tv_sec, (long)current_time.tv_usec);
-#endif
DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
udelay(ISL38XX_WRITEIO_DELAY);
reg = readl(device_base + ISL38XX_INT_IDENT_REG);
@@ -148,10 +148,12 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
counter++;
}
+#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_TRACING,
"%08li.%08li Device register read %08x\n",
current_time.tv_sec, (long)current_time.tv_usec,
readl(device_base + ISL38XX_CTRL_STAT_REG));
+#endif
udelay(ISL38XX_WRITEIO_DELAY);
#if VERBOSE > SHOW_ERROR_MESSAGES
diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c
index 6e5bda56b8f8..0e0ba614259a 100644
--- a/drivers/net/wireless/ray_cs.c
+++ b/drivers/net/wireless/ray_cs.c
@@ -46,7 +46,6 @@
#include <linux/skbuff.h>
#include <linux/ethtool.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -393,11 +392,6 @@ static dev_link_t *ray_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ray_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -2904,13 +2898,21 @@ static int write_int(struct file *file, const char __user *buffer, unsigned long
}
#endif
+static struct pcmcia_device_id ray_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, ray_ids);
+
static struct pcmcia_driver ray_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "ray_cs",
},
.attach = ray_attach,
+ .event = ray_event,
.detach = ray_detach,
+ .id_table = ray_ids,
};
static int __init init_ray_cs(void)
diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
index ec8329788e49..f6130a53b796 100644
--- a/drivers/net/wireless/wavelan_cs.c
+++ b/drivers/net/wireless/wavelan_cs.c
@@ -4684,12 +4684,6 @@ wavelan_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_REGISTRATION_COMPLETE |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &wavelan_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -4889,13 +4883,24 @@ wavelan_event(event_t event, /* The event received */
return 0;
}
+static struct pcmcia_device_id wavelan_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("AT&T","WaveLAN/PCMCIA", 0xe7c5affd, 0x1bc50975),
+ PCMCIA_DEVICE_PROD_ID12("Digital", "RoamAbout/DS", 0x9999ab35, 0x00d05e06),
+ PCMCIA_DEVICE_PROD_ID12("Lucent Technologies", "WaveLAN/PCMCIA", 0x23eb9949, 0x1bc50975),
+ PCMCIA_DEVICE_PROD_ID12("NCR", "WaveLAN/PCMCIA", 0x24358cd4, 0x1bc50975),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, wavelan_ids);
+
static struct pcmcia_driver wavelan_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "wavelan_cs",
},
.attach = wavelan_attach,
+ .event = wavelan_event,
.detach = wavelan_detach,
+ .id_table = wavelan_ids,
};
static int __init
diff --git a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
index ea2ef8dddb92..677ff71883cb 100644
--- a/drivers/net/wireless/wavelan_cs.p.h
+++ b/drivers/net/wireless/wavelan_cs.p.h
@@ -452,7 +452,6 @@
#include <pcmcia/cistpl.h>
#include <pcmcia/cisreg.h>
#include <pcmcia/ds.h>
-#include <pcmcia/version.h>
/* Wavelan declarations */
#include "i82593.h" /* Definitions for the Intel chip */
diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c
index 1433e5aaf1b4..dd902126d018 100644
--- a/drivers/net/wireless/wl3501_cs.c
+++ b/drivers/net/wireless/wl3501_cs.c
@@ -49,7 +49,6 @@
#include <net/iw_handler.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -2005,13 +2004,6 @@ static dev_link_t *wl3501_attach(void)
link->next = wl3501_dev_list;
wl3501_dev_list = link;
client_reg.dev_info = &wl3501_dev_info;
- client_reg.EventMask = CS_EVENT_CARD_INSERTION |
- CS_EVENT_RESET_PHYSICAL |
- CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND |
- CS_EVENT_PM_RESUME;
- client_reg.event_handler = wl3501_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2239,13 +2231,21 @@ static int wl3501_event(event_t event, int pri, event_callback_args_t *args)
return 0;
}
+static struct pcmcia_device_id wl3501_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0xd601, 0x0001),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, wl3501_ids);
+
static struct pcmcia_driver wl3501_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "wl3501_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "wl3501_cs",
},
- .attach = wl3501_attach,
- .detach = wl3501_detach,
+ .attach = wl3501_attach,
+ .event = wl3501_event,
+ .detach = wl3501_detach,
+ .id_table = wl3501_ids,
};
static int __init wl3501_init_module(void)
diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
index 9da925430109..1c2506535f7e 100644
--- a/drivers/net/yellowfin.c
+++ b/drivers/net/yellowfin.c
@@ -786,7 +786,7 @@ static void yellowfin_init_ring(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* 16 byte align the IP header. */
yp->rx_ring[i].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
- skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
yp->rx_ring[i-1].dbdma_cmd = cpu_to_le32(CMD_STOP);
yp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
@@ -1111,7 +1111,7 @@ static int yellowfin_rx(struct net_device *dev)
pci_dma_sync_single_for_cpu(yp->pci_dev, desc->addr,
yp->rx_buf_sz, PCI_DMA_FROMDEVICE);
desc_status = le32_to_cpu(desc->result_status) >> 16;
- buf_addr = rx_skb->tail;
+ buf_addr = rx_skb->data;
data_size = (le32_to_cpu(desc->dbdma_cmd) -
le32_to_cpu(desc->result_status)) & 0xffff;
frame_status = le16_to_cpu(get_unaligned((s16*)&(buf_addr[data_size - 2])));
@@ -1185,7 +1185,7 @@ static int yellowfin_rx(struct net_device *dev)
break;
skb->dev = dev;
skb_reserve(skb, 2); /* 16 byte align the IP header */
- eth_copy_and_sum(skb, rx_skb->tail, pkt_len, 0);
+ eth_copy_and_sum(skb, rx_skb->data, pkt_len, 0);
skb_put(skb, pkt_len);
pci_dma_sync_single_for_device(yp->pci_dev, desc->addr,
yp->rx_buf_sz,
@@ -1211,7 +1211,7 @@ static int yellowfin_rx(struct net_device *dev)
skb->dev = dev; /* Mark as being used by this device. */
skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */
yp->rx_ring[entry].addr = cpu_to_le32(pci_map_single(yp->pci_dev,
- skb->tail, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
+ skb->data, yp->rx_buf_sz, PCI_DMA_FROMDEVICE));
}
yp->rx_ring[entry].dbdma_cmd = cpu_to_le32(CMD_STOP);
yp->rx_ring[entry].result_status = 0; /* Clear complete bit. */
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
index 745a14183634..531b07313141 100644
--- a/drivers/oprofile/buffer_sync.c
+++ b/drivers/oprofile/buffer_sync.c
@@ -206,7 +206,7 @@ static inline unsigned long fast_get_dcookie(struct dentry * dentry,
*/
static unsigned long get_exec_dcookie(struct mm_struct * mm)
{
- unsigned long cookie = 0;
+ unsigned long cookie = NO_COOKIE;
struct vm_area_struct * vma;
if (!mm)
@@ -234,35 +234,42 @@ out:
*/
static unsigned long lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
{
- unsigned long cookie = 0;
+ unsigned long cookie = NO_COOKIE;
struct vm_area_struct * vma;
for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
- if (!vma->vm_file)
- continue;
-
if (addr < vma->vm_start || addr >= vma->vm_end)
continue;
- cookie = fast_get_dcookie(vma->vm_file->f_dentry,
- vma->vm_file->f_vfsmnt);
- *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
+ if (vma->vm_file) {
+ cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr -
+ vma->vm_start;
+ } else {
+ /* must be an anonymous map */
+ *offset = addr;
+ }
+
break;
}
+ if (!vma)
+ cookie = INVALID_COOKIE;
+
return cookie;
}
-static unsigned long last_cookie = ~0UL;
+static unsigned long last_cookie = INVALID_COOKIE;
static void add_cpu_switch(int i)
{
add_event_entry(ESCAPE_CODE);
add_event_entry(CPU_SWITCH_CODE);
add_event_entry(i);
- last_cookie = ~0UL;
+ last_cookie = INVALID_COOKIE;
}
static void add_kernel_ctx_switch(unsigned int in_kernel)
@@ -317,7 +324,7 @@ static int add_us_sample(struct mm_struct * mm, struct op_sample * s)
cookie = lookup_dcookie(mm, s->eip, &offset);
- if (!cookie) {
+ if (cookie == INVALID_COOKIE) {
atomic_inc(&oprofile_stats.sample_lost_no_mapping);
return 0;
}
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
index 442aaad391e0..018023630599 100644
--- a/drivers/oprofile/event_buffer.h
+++ b/drivers/oprofile/event_buffer.h
@@ -35,6 +35,9 @@ void wake_up_buffer_waiter(void);
#define TRACE_BEGIN_CODE 8
#define TRACE_END_CODE 9
+#define INVALID_COOKIE ~0UL
+#define NO_COOKIE 0UL
+
/* add data to the event buffer */
void add_event_entry(unsigned long data);
diff --git a/drivers/parisc/dino.c b/drivers/parisc/dino.c
index b0d2a73d1d47..2f2dbef2c3b7 100644
--- a/drivers/parisc/dino.c
+++ b/drivers/parisc/dino.c
@@ -993,6 +993,7 @@ dino_driver_callback(struct parisc_device *dev)
bus = pci_scan_bus_parented(&dev->dev, dino_current_bus,
&dino_cfg_ops, NULL);
if(bus) {
+ pci_bus_add_devices(bus);
/* This code *depends* on scanning being single threaded
* if it isn't, this global bus number count will fail
*/
diff --git a/drivers/parisc/lba_pci.c b/drivers/parisc/lba_pci.c
index dc838804c0dd..7fdd80b7eb47 100644
--- a/drivers/parisc/lba_pci.c
+++ b/drivers/parisc/lba_pci.c
@@ -1570,6 +1570,8 @@ lba_driver_probe(struct parisc_device *dev)
lba_bus = lba_dev->hba.hba_bus =
pci_scan_bus_parented(&dev->dev, lba_dev->hba.bus_num.start,
cfg_ops, NULL);
+ if (lba_bus)
+ pci_bus_add_devices(lba_bus);
/* This is in lieu of calling pci_assign_unassigned_resources() */
if (is_pdc_pat()) {
diff --git a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c
index a3fa8185af2a..24e6aacddb74 100644
--- a/drivers/parport/parport_cs.c
+++ b/drivers/parport/parport_cs.c
@@ -48,7 +48,6 @@
#include <linux/parport.h>
#include <linux/parport_pc.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -133,11 +132,6 @@ static dev_link_t *parport_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &parport_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -373,13 +367,23 @@ int parport_event(event_t event, int priority,
return 0;
} /* parport_event */
+static struct pcmcia_device_id parport_ids[] = {
+ PCMCIA_DEVICE_FUNC_ID(3),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0003),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, parport_ids);
+
static struct pcmcia_driver parport_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "parport_cs",
},
.attach = parport_attach,
+ .event = parport_event,
.detach = parport_detach,
+ .id_table = parport_ids,
+
};
static int __init init_parport_cs(void)
diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c
index 80edfa3abd29..4598c6a9212d 100644
--- a/drivers/parport/parport_pc.c
+++ b/drivers/parport/parport_pc.c
@@ -3008,7 +3008,7 @@ static int __init parport_pc_init_superio (int autoirq, int autodma)
int ret = 0;
while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) {
- id = pci_match_device (parport_pc_pci_tbl, pdev);
+ id = pci_match_id(parport_pc_pci_tbl, pdev);
if (id == NULL || id->driver_data >= last_sio)
continue;
diff --git a/drivers/pci/Makefile b/drivers/pci/Makefile
index 7dea494c0d7b..3657f6199c48 100644
--- a/drivers/pci/Makefile
+++ b/drivers/pci/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
#
# Some architectures use the generic PCI setup functions
#
+obj-$(CONFIG_X86) += setup-bus.o
obj-$(CONFIG_ALPHA) += setup-bus.o setup-irq.o
obj-$(CONFIG_ARM) += setup-bus.o setup-irq.o
obj-$(CONFIG_PARISC) += setup-bus.o
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index dbd33605cc10..fedae89d8f7d 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -121,10 +121,13 @@ void __devinit pci_bus_add_devices(struct pci_bus *bus)
* If there is an unattached subordinate bus, attach
* it and then scan for unattached PCI devices.
*/
- if (dev->subordinate && list_empty(&dev->subordinate->node)) {
- spin_lock(&pci_bus_lock);
- list_add_tail(&dev->subordinate->node, &dev->bus->children);
- spin_unlock(&pci_bus_lock);
+ if (dev->subordinate) {
+ if (list_empty(&dev->subordinate->node)) {
+ spin_lock(&pci_bus_lock);
+ list_add_tail(&dev->subordinate->node,
+ &dev->bus->children);
+ spin_unlock(&pci_bus_lock);
+ }
pci_bus_add_devices(dev->subordinate);
sysfs_create_link(&dev->subordinate->class_dev.kobj, &dev->dev.kobj, "bridge");
diff --git a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c
index 3903f8c559b6..b844bc972324 100644
--- a/drivers/pci/hotplug.c
+++ b/drivers/pci/hotplug.c
@@ -54,7 +54,7 @@ int pci_hotplug (struct device *dev, char **envp, int num_envp,
envp[i++] = scratch;
length += scnprintf (scratch, buffer_size - length,
- "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x\n",
+ "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
(u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
diff --git a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig
index 1a4d4ca2a4dc..9c4a39ee89b5 100644
--- a/drivers/pci/hotplug/Kconfig
+++ b/drivers/pci/hotplug/Kconfig
@@ -187,9 +187,10 @@ config HOTPLUG_PCI_RPA_DLPAR
config HOTPLUG_PCI_SGI
tristate "SGI PCI Hotplug Support"
- depends on HOTPLUG_PCI && IA64_SGI_SN2
+ depends on HOTPLUG_PCI && (IA64_SGI_SN2 || IA64_GENERIC)
help
- Say Y here if you have an SGI IA64 Altix system.
+ Say Y here if you want to use the SGI Altix Hotplug
+ Driver for PCI devices.
When in doubt, say N.
diff --git a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile
index 93c120ddbd39..31a307004b94 100644
--- a/drivers/pci/hotplug/Makefile
+++ b/drivers/pci/hotplug/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_HOTPLUG_PCI_PCIE) += pciehp.o
obj-$(CONFIG_HOTPLUG_PCI_SHPC) += shpchp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA) += rpaphp.o
obj-$(CONFIG_HOTPLUG_PCI_RPA_DLPAR) += rpadlpar_io.o
+obj-$(CONFIG_HOTPLUG_PCI_SGI) += sgi_hotplug.o
pci_hotplug-objs := pci_hotplug_core.o
@@ -36,9 +37,7 @@ ibmphp-objs := ibmphp_core.o \
ibmphp_hpc.o
acpiphp-objs := acpiphp_core.o \
- acpiphp_glue.o \
- acpiphp_pci.o \
- acpiphp_res.o
+ acpiphp_glue.o
rpaphp-objs := rpaphp_core.o \
rpaphp_pci.o \
diff --git a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h
index d9499874c8a9..293603e1b7c3 100644
--- a/drivers/pci/hotplug/acpiphp.h
+++ b/drivers/pci/hotplug/acpiphp.h
@@ -7,6 +7,8 @@
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
*
* All rights reserved.
*
@@ -52,7 +54,6 @@
struct acpiphp_bridge;
struct acpiphp_slot;
-struct pci_resource;
/*
* struct slot - slot information for each *physical* slot
@@ -65,15 +66,6 @@ struct slot {
struct acpiphp_slot *acpi_slot;
};
-/*
- * struct pci_resource - describes pci resource (mem, pfmem, io, bus)
- */
-struct pci_resource {
- struct pci_resource * next;
- u64 base;
- u32 length;
-};
-
/**
* struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters
* @cache_line_size in DWORD
@@ -101,10 +93,6 @@ struct acpiphp_bridge {
int type;
int nr_slots;
- u8 seg;
- u8 bus;
- u8 sub;
-
u32 flags;
/* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */
@@ -117,12 +105,6 @@ struct acpiphp_bridge {
struct hpp_param hpp;
spinlock_t res_lock;
-
- /* available resources on this bus */
- struct pci_resource *mem_head;
- struct pci_resource *p_mem_head;
- struct pci_resource *io_head;
- struct pci_resource *bus_head;
};
@@ -163,12 +145,6 @@ struct acpiphp_func {
u8 function; /* pci function# */
u32 flags; /* see below */
-
- /* resources used for this function */
- struct pci_resource *mem_head;
- struct pci_resource *p_mem_head;
- struct pci_resource *io_head;
- struct pci_resource *bus_head;
};
/**
@@ -243,25 +219,6 @@ extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot);
extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot);
extern u32 acpiphp_get_address (struct acpiphp_slot *slot);
-/* acpiphp_pci.c */
-extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn);
-extern int acpiphp_configure_slot (struct acpiphp_slot *slot);
-extern int acpiphp_configure_function (struct acpiphp_func *func);
-extern void acpiphp_unconfigure_function (struct acpiphp_func *func);
-extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge);
-extern int acpiphp_init_func_resource (struct acpiphp_func *func);
-
-/* acpiphp_res.c */
-extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size);
-extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size);
-extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size);
-extern int acpiphp_resource_sort_and_combine (struct pci_resource **head);
-extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length);
-extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to);
-extern void acpiphp_free_resource (struct pci_resource **res);
-extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */
-extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */
-
/* variables */
extern int acpiphp_debug;
diff --git a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c
index 4539e61a3dc1..60c4c38047a3 100644
--- a/drivers/pci/hotplug/acpiphp_core.c
+++ b/drivers/pci/hotplug/acpiphp_core.c
@@ -7,6 +7,8 @@
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
*
* All rights reserved.
*
@@ -53,8 +55,8 @@ int acpiphp_debug;
static int num_slots;
static struct acpiphp_attention_info *attention_info;
-#define DRIVER_VERSION "0.4"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>"
+#define DRIVER_VERSION "0.5"
+#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kochi@bq.jp.nec.com>, Matthew Wilcox <willy@hp.com>"
#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver"
MODULE_AUTHOR(DRIVER_AUTHOR);
@@ -281,8 +283,7 @@ static int get_adapter_status(struct hotplug_slot *hotplug_slot, u8 *value)
/**
* get_address - get pci address of a slot
* @hotplug_slot: slot to get status
- * @busdev: pointer to struct pci_busdev (seg, bus, dev)
- *
+ * @value: pointer to struct pci_busdev (seg, bus, dev)
*/
static int get_address(struct hotplug_slot *hotplug_slot, u32 *value)
{
diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c
index e7f41294f811..424e7de181ae 100644
--- a/drivers/pci/hotplug/acpiphp_glue.c
+++ b/drivers/pci/hotplug/acpiphp_glue.c
@@ -4,6 +4,10 @@
* Copyright (C) 2002,2003 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
* Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
* Copyright (C) 2002,2003 NEC Corporation
+ * Copyright (C) 2003-2005 Matthew Wilcox (matthew.wilcox@hp.com)
+ * Copyright (C) 2003-2005 Hewlett Packard
+ * Copyright (C) 2005 Rajesh Shah (rajesh.shah@intel.com)
+ * Copyright (C) 2005 Intel Corporation
*
* All rights reserved.
*
@@ -26,6 +30,16 @@
*
*/
+/*
+ * Lifetime rules for pci_dev:
+ * - The one in acpiphp_func has its refcount elevated by pci_get_slot()
+ * when the driver is loaded or when an insertion event occurs. It loses
+ * a refcount when its ejected or the driver unloads.
+ * - The one in acpiphp_bridge has its refcount elevated by pci_get_slot()
+ * when the bridge is scanned and it loses a refcount when the bridge
+ * is removed.
+ */
+
#include <linux/init.h>
#include <linux/module.h>
@@ -178,21 +192,18 @@ register_slot(acpi_handle handle, u32 lvl, void *context, void **rv)
bridge->nr_slots++;
- dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n",
- slot->bridge->bus, slot->device, slot->sun);
+ dbg("found ACPI PCI Hotplug slot %d at PCI %04x:%02x:%02x\n",
+ slot->sun, pci_domain_nr(bridge->pci_bus),
+ bridge->pci_bus->number, slot->device);
}
newfunc->slot = slot;
list_add_tail(&newfunc->sibling, &slot->funcs);
/* associate corresponding pci_dev */
- newfunc->pci_dev = pci_find_slot(bridge->bus,
+ newfunc->pci_dev = pci_get_slot(bridge->pci_bus,
PCI_DEVFN(device, function));
if (newfunc->pci_dev) {
- if (acpiphp_init_func_resource(newfunc) < 0) {
- kfree(newfunc);
- return AE_ERROR;
- }
slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON);
}
@@ -227,62 +238,6 @@ static int detect_ejectable_slots(acpi_handle *bridge_handle)
}
-/* decode ACPI _CRS data and convert into our internal resource list
- * TBD: _TRA, etc.
- */
-static acpi_status
-decode_acpi_resource(struct acpi_resource *resource, void *context)
-{
- struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context;
- struct acpi_resource_address64 address;
- struct pci_resource *res;
-
- if (resource->id != ACPI_RSTYPE_ADDRESS16 &&
- resource->id != ACPI_RSTYPE_ADDRESS32 &&
- resource->id != ACPI_RSTYPE_ADDRESS64)
- return AE_OK;
-
- acpi_resource_to_address64(resource, &address);
-
- if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) {
- dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type,
- (unsigned long long)address.min_address_range,
- (unsigned long long)address.max_address_range);
- res = acpiphp_make_resource(address.min_address_range,
- address.address_length);
- if (!res) {
- err("out of memory\n");
- return AE_OK;
- }
-
- switch (address.resource_type) {
- case ACPI_MEMORY_RANGE:
- if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) {
- res->next = bridge->p_mem_head;
- bridge->p_mem_head = res;
- } else {
- res->next = bridge->mem_head;
- bridge->mem_head = res;
- }
- break;
- case ACPI_IO_RANGE:
- res->next = bridge->io_head;
- bridge->io_head = res;
- break;
- case ACPI_BUS_NUMBER_RANGE:
- res->next = bridge->bus_head;
- bridge->bus_head = res;
- break;
- default:
- /* invalid type */
- kfree(res);
- break;
- }
- }
-
- return AE_OK;
-}
-
/* decode ACPI 2.0 _HPP hot plug parameters */
static void decode_hpp(struct acpiphp_bridge *bridge)
{
@@ -346,34 +301,29 @@ static void init_bridge_misc(struct acpiphp_bridge *bridge)
/* decode ACPI 2.0 _HPP (hot plug parameters) */
decode_hpp(bridge);
- /* subtract all resources already allocated */
- acpiphp_detect_pci_resource(bridge);
-
/* register all slot objects under this bridge */
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1,
register_slot, bridge, NULL);
/* install notify handler */
- status = acpi_install_notify_handler(bridge->handle,
+ if (bridge->type != BRIDGE_TYPE_HOST) {
+ status = acpi_install_notify_handler(bridge->handle,
ACPI_SYSTEM_NOTIFY,
handle_hotplug_event_bridge,
bridge);
- if (ACPI_FAILURE(status)) {
- err("failed to register interrupt notify handler\n");
+ if (ACPI_FAILURE(status)) {
+ err("failed to register interrupt notify handler\n");
+ }
}
list_add(&bridge->list, &bridge_list);
-
- dbg("Bridge resource:\n");
- acpiphp_dump_resource(bridge);
}
/* allocate and initialize host bridge data structure */
-static void add_host_bridge(acpi_handle *handle, int seg, int bus)
+static void add_host_bridge(acpi_handle *handle, struct pci_bus *pci_bus)
{
- acpi_status status;
struct acpiphp_bridge *bridge;
bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
@@ -384,52 +334,19 @@ static void add_host_bridge(acpi_handle *handle, int seg, int bus)
bridge->type = BRIDGE_TYPE_HOST;
bridge->handle = handle;
- bridge->seg = seg;
- bridge->bus = bus;
- bridge->pci_bus = pci_find_bus(seg, bus);
+ bridge->pci_bus = pci_bus;
spin_lock_init(&bridge->res_lock);
- /* to be overridden when we decode _CRS */
- bridge->sub = bridge->bus;
-
- /* decode resources */
-
- status = acpi_walk_resources(handle, METHOD_NAME__CRS,
- decode_acpi_resource, bridge);
-
- if (ACPI_FAILURE(status)) {
- err("failed to decode bridge resources\n");
- kfree(bridge);
- return;
- }
-
- acpiphp_resource_sort_and_combine(&bridge->io_head);
- acpiphp_resource_sort_and_combine(&bridge->mem_head);
- acpiphp_resource_sort_and_combine(&bridge->p_mem_head);
- acpiphp_resource_sort_and_combine(&bridge->bus_head);
-
- dbg("ACPI _CRS resource:\n");
- acpiphp_dump_resource(bridge);
-
- if (bridge->bus_head) {
- bridge->bus = bridge->bus_head->base;
- bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1;
- }
-
init_bridge_misc(bridge);
}
/* allocate and initialize PCI-to-PCI bridge data structure */
-static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int fn)
+static void add_p2p_bridge(acpi_handle *handle, struct pci_dev *pci_dev)
{
struct acpiphp_bridge *bridge;
- u8 tmp8;
- u16 tmp16;
- u64 base64, limit64;
- u32 base, limit, base32u, limit32u;
bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL);
if (bridge == NULL) {
@@ -441,133 +358,22 @@ static void add_p2p_bridge(acpi_handle *handle, int seg, int bus, int dev, int f
bridge->type = BRIDGE_TYPE_P2P;
bridge->handle = handle;
- bridge->seg = seg;
-
- bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn));
- if (!bridge->pci_dev) {
- err("Can't get pci_dev\n");
- kfree(bridge);
- return;
- }
- bridge->pci_bus = bridge->pci_dev->subordinate;
+ bridge->pci_dev = pci_dev_get(pci_dev);
+ bridge->pci_bus = pci_dev->subordinate;
if (!bridge->pci_bus) {
err("This is not a PCI-to-PCI bridge!\n");
- kfree(bridge);
- return;
+ goto err;
}
spin_lock_init(&bridge->res_lock);
- bridge->bus = bridge->pci_bus->number;
- bridge->sub = bridge->pci_bus->subordinate;
-
- /*
- * decode resources under this P2P bridge
- */
-
- /* I/O resources */
- pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8);
- base = tmp8;
- pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8);
- limit = tmp8;
-
- switch (base & PCI_IO_RANGE_TYPE_MASK) {
- case PCI_IO_RANGE_TYPE_16:
- base = (base << 8) & 0xf000;
- limit = ((limit << 8) & 0xf000) + 0xfff;
- bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
- if (!bridge->io_head) {
- err("out of memory\n");
- kfree(bridge);
- return;
- }
- dbg("16bit I/O range: %04x-%04x\n",
- (u32)bridge->io_head->base,
- (u32)(bridge->io_head->base + bridge->io_head->length - 1));
- break;
- case PCI_IO_RANGE_TYPE_32:
- pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16);
- base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000);
- pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16);
- limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff;
- bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1);
- if (!bridge->io_head) {
- err("out of memory\n");
- kfree(bridge);
- return;
- }
- dbg("32bit I/O range: %08x-%08x\n",
- (u32)bridge->io_head->base,
- (u32)(bridge->io_head->base + bridge->io_head->length - 1));
- break;
- case 0x0f:
- dbg("I/O space unsupported\n");
- break;
- default:
- warn("Unknown I/O range type\n");
- }
-
- /* Memory resources (mandatory for P2P bridge) */
- pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16);
- base = (tmp16 & 0xfff0) << 16;
- pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16);
- limit = ((tmp16 & 0xfff0) << 16) | 0xfffff;
- bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
- if (!bridge->mem_head) {
- err("out of memory\n");
- kfree(bridge);
- return;
- }
- dbg("32bit Memory range: %08x-%08x\n",
- (u32)bridge->mem_head->base,
- (u32)(bridge->mem_head->base + bridge->mem_head->length-1));
-
- /* Prefetchable Memory resources (optional) */
- pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16);
- base = tmp16;
- pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16);
- limit = tmp16;
-
- switch (base & PCI_MEMORY_RANGE_TYPE_MASK) {
- case PCI_PREF_RANGE_TYPE_32:
- base = (base & 0xfff0) << 16;
- limit = ((limit & 0xfff0) << 16) | 0xfffff;
- bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1);
- if (!bridge->p_mem_head) {
- err("out of memory\n");
- kfree(bridge);
- return;
- }
- dbg("32bit Prefetchable memory range: %08x-%08x\n",
- (u32)bridge->p_mem_head->base,
- (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1));
- break;
- case PCI_PREF_RANGE_TYPE_64:
- pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u);
- pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u);
- base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16);
- limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff;
-
- bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1);
- if (!bridge->p_mem_head) {
- err("out of memory\n");
- kfree(bridge);
- return;
- }
- dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n",
- (u32)(bridge->p_mem_head->base >> 32),
- (u32)(bridge->p_mem_head->base & 0xffffffff),
- (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32),
- (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff));
- break;
- case 0x0f:
- break;
- default:
- warn("Unknown prefetchale memory type\n");
- }
-
init_bridge_misc(bridge);
+ return;
+ err:
+ pci_dev_put(pci_dev);
+ kfree(bridge);
+ return;
}
@@ -577,14 +383,10 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
{
acpi_status status;
acpi_handle dummy_handle;
- unsigned long *segbus = context;
unsigned long tmp;
- int seg, bus, device, function;
+ int device, function;
struct pci_dev *dev;
-
- /* get PCI address */
- seg = (*segbus >> 8) & 0xff;
- bus = *segbus & 0xff;
+ struct pci_bus *pci_bus = context;
status = acpi_get_handle(handle, "_ADR", &dummy_handle);
if (ACPI_FAILURE(status))
@@ -599,20 +401,19 @@ find_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
device = (tmp >> 16) & 0xffff;
function = tmp & 0xffff;
- dev = pci_find_slot(bus, PCI_DEVFN(device, function));
+ dev = pci_get_slot(pci_bus, PCI_DEVFN(device, function));
- if (!dev)
- return AE_OK;
-
- if (!dev->subordinate)
- return AE_OK;
+ if (!dev || !dev->subordinate)
+ goto out;
/* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI-to-PCI bridge at PCI %s\n", pci_name(dev));
- add_p2p_bridge(handle, seg, bus, device, function);
+ add_p2p_bridge(handle, dev);
}
+ out:
+ pci_dev_put(dev);
return AE_OK;
}
@@ -624,6 +425,7 @@ static int add_bridge(acpi_handle handle)
unsigned long tmp;
int seg, bus;
acpi_handle dummy_handle;
+ struct pci_bus *pci_bus;
/* if the bridge doesn't have _STA, we assume it is always there */
status = acpi_get_handle(handle, "_STA", &dummy_handle);
@@ -653,18 +455,22 @@ static int add_bridge(acpi_handle handle)
bus = 0;
}
+ pci_bus = pci_find_bus(seg, bus);
+ if (!pci_bus) {
+ err("Can't find bus %04x:%02x\n", seg, bus);
+ return 0;
+ }
+
/* check if this bridge has ejectable slots */
if (detect_ejectable_slots(handle) > 0) {
dbg("found PCI host-bus bridge with hot-pluggable slots\n");
- add_host_bridge(handle, seg, bus);
+ add_host_bridge(handle, pci_bus);
return 0;
}
- tmp = seg << 8 | bus;
-
/* search P2P bridges under this host bridge */
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1,
- find_p2p_bridge, &tmp, NULL);
+ find_p2p_bridge, pci_bus, NULL);
if (ACPI_FAILURE(status))
warn("find_p2p_bridge faied (error code = 0x%x)\n",status);
@@ -672,12 +478,205 @@ static int add_bridge(acpi_handle handle)
return 0;
}
+static struct acpiphp_bridge *acpiphp_handle_to_bridge(acpi_handle handle)
+{
+ struct list_head *head;
+ list_for_each(head, &bridge_list) {
+ struct acpiphp_bridge *bridge = list_entry(head,
+ struct acpiphp_bridge, list);
+ if (bridge->handle == handle)
+ return bridge;
+ }
+
+ return NULL;
+}
+
+static void cleanup_bridge(struct acpiphp_bridge *bridge)
+{
+ struct list_head *list, *tmp;
+ struct acpiphp_slot *slot;
+ acpi_status status;
+ acpi_handle handle = bridge->handle;
+
+ status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_bridge);
+ if (ACPI_FAILURE(status))
+ err("failed to remove notify handler\n");
+
+ slot = bridge->slots;
+ while (slot) {
+ struct acpiphp_slot *next = slot->next;
+ list_for_each_safe (list, tmp, &slot->funcs) {
+ struct acpiphp_func *func;
+ func = list_entry(list, struct acpiphp_func, sibling);
+ status = acpi_remove_notify_handler(func->handle,
+ ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_func);
+ if (ACPI_FAILURE(status))
+ err("failed to remove notify handler\n");
+ pci_dev_put(func->pci_dev);
+ list_del(list);
+ kfree(func);
+ }
+ kfree(slot);
+ slot = next;
+ }
+
+ pci_dev_put(bridge->pci_dev);
+ list_del(&bridge->list);
+ kfree(bridge);
+}
+
+static acpi_status
+cleanup_p2p_bridge(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ struct acpiphp_bridge *bridge;
+
+ if (!(bridge = acpiphp_handle_to_bridge(handle)))
+ return AE_OK;
+ cleanup_bridge(bridge);
+ return AE_OK;
+}
static void remove_bridge(acpi_handle handle)
{
- /* No-op for now .. */
+ struct acpiphp_bridge *bridge;
+
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (bridge) {
+ cleanup_bridge(bridge);
+ } else {
+ /* clean-up p2p bridges under this host bridge */
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ (u32)1, cleanup_p2p_bridge, NULL, NULL);
+ }
+}
+
+static struct pci_dev * get_apic_pci_info(acpi_handle handle)
+{
+ struct acpi_pci_id id;
+ struct pci_bus *bus;
+ struct pci_dev *dev;
+
+ if (ACPI_FAILURE(acpi_get_pci_id(handle, &id)))
+ return NULL;
+
+ bus = pci_find_bus(id.segment, id.bus);
+ if (!bus)
+ return NULL;
+
+ dev = pci_get_slot(bus, PCI_DEVFN(id.device, id.function));
+ if (!dev)
+ return NULL;
+
+ if ((dev->class != PCI_CLASS_SYSTEM_PIC_IOAPIC) &&
+ (dev->class != PCI_CLASS_SYSTEM_PIC_IOXAPIC))
+ {
+ pci_dev_put(dev);
+ return NULL;
+ }
+
+ return dev;
+}
+
+static int get_gsi_base(acpi_handle handle, u32 *gsi_base)
+{
+ acpi_status status;
+ int result = -1;
+ unsigned long gsb;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ union acpi_object *obj;
+ void *table;
+
+ status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsb);
+ if (ACPI_SUCCESS(status)) {
+ *gsi_base = (u32)gsb;
+ return 0;
+ }
+
+ status = acpi_evaluate_object(handle, "_MAT", NULL, &buffer);
+ if (ACPI_FAILURE(status) || !buffer.length || !buffer.pointer)
+ return -1;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER)
+ goto out;
+
+ table = obj->buffer.pointer;
+ switch (((acpi_table_entry_header *)table)->type) {
+ case ACPI_MADT_IOSAPIC:
+ *gsi_base = ((struct acpi_table_iosapic *)table)->global_irq_base;
+ result = 0;
+ break;
+ case ACPI_MADT_IOAPIC:
+ *gsi_base = ((struct acpi_table_ioapic *)table)->global_irq_base;
+ result = 0;
+ break;
+ default:
+ break;
+ }
+ out:
+ acpi_os_free(buffer.pointer);
+ return result;
+}
+
+static acpi_status
+ioapic_add(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ acpi_status status;
+ unsigned long sta;
+ acpi_handle tmp;
+ struct pci_dev *pdev;
+ u32 gsi_base;
+ u64 phys_addr;
+
+ /* Evaluate _STA if present */
+ status = acpi_evaluate_integer(handle, "_STA", NULL, &sta);
+ if (ACPI_SUCCESS(status) && sta != ACPI_STA_ALL)
+ return AE_CTRL_DEPTH;
+
+ /* Scan only PCI bus scope */
+ status = acpi_get_handle(handle, "_HID", &tmp);
+ if (ACPI_SUCCESS(status))
+ return AE_CTRL_DEPTH;
+
+ if (get_gsi_base(handle, &gsi_base))
+ return AE_OK;
+
+ pdev = get_apic_pci_info(handle);
+ if (!pdev)
+ return AE_OK;
+
+ if (pci_enable_device(pdev)) {
+ pci_dev_put(pdev);
+ return AE_OK;
+ }
+
+ pci_set_master(pdev);
+
+ if (pci_request_region(pdev, 0, "I/O APIC(acpiphp)")) {
+ pci_disable_device(pdev);
+ pci_dev_put(pdev);
+ return AE_OK;
+ }
+
+ phys_addr = pci_resource_start(pdev, 0);
+ if (acpi_register_ioapic(handle, phys_addr, gsi_base)) {
+ pci_release_region(pdev, 0);
+ pci_disable_device(pdev);
+ pci_dev_put(pdev);
+ return AE_OK;
+ }
+
+ return AE_OK;
}
+static int acpiphp_configure_ioapics(acpi_handle handle)
+{
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, handle,
+ ACPI_UINT32_MAX, ioapic_add, NULL, NULL);
+ return 0;
+}
static int power_on_slot(struct acpiphp_slot *slot)
{
@@ -719,8 +718,6 @@ static int power_off_slot(struct acpiphp_slot *slot)
acpi_status status;
struct acpiphp_func *func;
struct list_head *l;
- struct acpi_object_list arg_list;
- union acpi_object arg;
int retval = 0;
@@ -731,7 +728,7 @@ static int power_off_slot(struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
- if (func->pci_dev && (func->flags & FUNC_HAS_PS3)) {
+ if (func->flags & FUNC_HAS_PS3) {
status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL);
if (ACPI_FAILURE(status)) {
warn("%s: _PS3 failed\n", __FUNCTION__);
@@ -742,27 +739,6 @@ static int power_off_slot(struct acpiphp_slot *slot)
}
}
- list_for_each (l, &slot->funcs) {
- func = list_entry(l, struct acpiphp_func, sibling);
-
- /* We don't want to call _EJ0 on non-existing functions. */
- if (func->pci_dev && (func->flags & FUNC_HAS_EJ0)) {
- /* _EJ0 method take one argument */
- arg_list.count = 1;
- arg_list.pointer = &arg;
- arg.type = ACPI_TYPE_INTEGER;
- arg.integer.value = 1;
-
- status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
- if (ACPI_FAILURE(status)) {
- warn("%s: _EJ0 failed\n", __FUNCTION__);
- retval = -1;
- goto err_exit;
- } else
- break;
- }
- }
-
/* TBD: evaluate _STA to check if the slot is disabled */
slot->flags &= (~SLOT_POWEREDON);
@@ -782,70 +758,56 @@ static int power_off_slot(struct acpiphp_slot *slot)
*/
static int enable_device(struct acpiphp_slot *slot)
{
- u8 bus;
struct pci_dev *dev;
- struct pci_bus *child;
+ struct pci_bus *bus = slot->bridge->pci_bus;
struct list_head *l;
struct acpiphp_func *func;
int retval = 0;
- int num;
+ int num, max, pass;
if (slot->flags & SLOT_ENABLED)
goto err_exit;
/* sanity check: dev should be NULL when hot-plugged in */
- dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
+ dev = pci_get_slot(bus, PCI_DEVFN(slot->device, 0));
if (dev) {
/* This case shouldn't happen */
err("pci_dev structure already exists.\n");
+ pci_dev_put(dev);
retval = -1;
goto err_exit;
}
- /* allocate resources to device */
- retval = acpiphp_configure_slot(slot);
- if (retval)
- goto err_exit;
-
- /* returned `dev' is the *first function* only! */
- num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
- if (num)
- pci_bus_add_devices(slot->bridge->pci_bus);
- dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
-
- if (!dev) {
+ num = pci_scan_slot(bus, PCI_DEVFN(slot->device, 0));
+ if (num == 0) {
err("No new device found\n");
retval = -1;
goto err_exit;
}
- if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
- pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus);
- child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus);
- pci_do_scan_bus(child);
+ max = bus->secondary;
+ for (pass = 0; pass < 2; pass++) {
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ if (PCI_SLOT(dev->devfn) != slot->device)
+ continue;
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
+ dev->hdr_type == PCI_HEADER_TYPE_CARDBUS)
+ max = pci_scan_bridge(bus, dev, max, pass);
+ }
}
+ pci_bus_assign_resources(bus);
+ pci_bus_add_devices(bus);
+
/* associate pci_dev to our representation */
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
-
- func->pci_dev = pci_find_slot(slot->bridge->bus,
- PCI_DEVFN(slot->device,
+ func->pci_dev = pci_get_slot(bus, PCI_DEVFN(slot->device,
func->function));
- if (!func->pci_dev)
- continue;
-
- /* configure device */
- retval = acpiphp_configure_function(func);
- if (retval)
- goto err_exit;
}
slot->flags |= SLOT_ENABLED;
- dbg("Available resources:\n");
- acpiphp_dump_resource(slot->bridge);
-
err_exit:
return retval;
}
@@ -866,9 +828,12 @@ static int disable_device(struct acpiphp_slot *slot)
list_for_each (l, &slot->funcs) {
func = list_entry(l, struct acpiphp_func, sibling);
+ if (!func->pci_dev)
+ continue;
- if (func->pci_dev)
- acpiphp_unconfigure_function(func);
+ pci_remove_bus_device(func->pci_dev);
+ pci_dev_put(func->pci_dev);
+ func->pci_dev = NULL;
}
slot->flags &= (~SLOT_ENABLED);
@@ -920,6 +885,39 @@ static unsigned int get_slot_status(struct acpiphp_slot *slot)
}
/**
+ * acpiphp_eject_slot - physically eject the slot
+ */
+static int acpiphp_eject_slot(struct acpiphp_slot *slot)
+{
+ acpi_status status;
+ struct acpiphp_func *func;
+ struct list_head *l;
+ struct acpi_object_list arg_list;
+ union acpi_object arg;
+
+ list_for_each (l, &slot->funcs) {
+ func = list_entry(l, struct acpiphp_func, sibling);
+
+ /* We don't want to call _EJ0 on non-existing functions. */
+ if ((func->flags & FUNC_HAS_EJ0)) {
+ /* _EJ0 method take one argument */
+ arg_list.count = 1;
+ arg_list.pointer = &arg;
+ arg.type = ACPI_TYPE_INTEGER;
+ arg.integer.value = 1;
+
+ status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL);
+ if (ACPI_FAILURE(status)) {
+ warn("%s: _EJ0 failed\n", __FUNCTION__);
+ return -1;
+ } else
+ break;
+ }
+ }
+ return 0;
+}
+
+/**
* acpiphp_check_bridge - re-enumerate devices
*
* Iterate over all slots under this bridge and make sure that if a
@@ -942,6 +940,8 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
if (retval) {
err("Error occurred in disabling\n");
goto err_exit;
+ } else {
+ acpiphp_eject_slot(slot);
}
disabled++;
} else {
@@ -962,6 +962,144 @@ static int acpiphp_check_bridge(struct acpiphp_bridge *bridge)
return retval;
}
+static void program_hpp(struct pci_dev *dev, struct acpiphp_bridge *bridge)
+{
+ u16 pci_cmd, pci_bctl;
+ struct pci_dev *cdev;
+
+ /* Program hpp values for this device */
+ if (!(dev->hdr_type == PCI_HEADER_TYPE_NORMAL ||
+ (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE &&
+ (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI)))
+ return;
+ pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+ bridge->hpp.cache_line_size);
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER,
+ bridge->hpp.latency_timer);
+ pci_read_config_word(dev, PCI_COMMAND, &pci_cmd);
+ if (bridge->hpp.enable_SERR)
+ pci_cmd |= PCI_COMMAND_SERR;
+ else
+ pci_cmd &= ~PCI_COMMAND_SERR;
+ if (bridge->hpp.enable_PERR)
+ pci_cmd |= PCI_COMMAND_PARITY;
+ else
+ pci_cmd &= ~PCI_COMMAND_PARITY;
+ pci_write_config_word(dev, PCI_COMMAND, pci_cmd);
+
+ /* Program bridge control value and child devices */
+ if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) {
+ pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER,
+ bridge->hpp.latency_timer);
+ pci_read_config_word(dev, PCI_BRIDGE_CONTROL, &pci_bctl);
+ if (bridge->hpp.enable_SERR)
+ pci_bctl |= PCI_BRIDGE_CTL_SERR;
+ else
+ pci_bctl &= ~PCI_BRIDGE_CTL_SERR;
+ if (bridge->hpp.enable_PERR)
+ pci_bctl |= PCI_BRIDGE_CTL_PARITY;
+ else
+ pci_bctl &= ~PCI_BRIDGE_CTL_PARITY;
+ pci_write_config_word(dev, PCI_BRIDGE_CONTROL, pci_bctl);
+ if (dev->subordinate) {
+ list_for_each_entry(cdev, &dev->subordinate->devices,
+ bus_list)
+ program_hpp(cdev, bridge);
+ }
+ }
+}
+
+static void acpiphp_set_hpp_values(acpi_handle handle, struct pci_bus *bus)
+{
+ struct acpiphp_bridge bridge;
+ struct pci_dev *dev;
+
+ memset(&bridge, 0, sizeof(bridge));
+ bridge.handle = handle;
+ decode_hpp(&bridge);
+ list_for_each_entry(dev, &bus->devices, bus_list)
+ program_hpp(dev, &bridge);
+
+}
+
+/*
+ * Remove devices for which we could not assign resources, call
+ * arch specific code to fix-up the bus
+ */
+static void acpiphp_sanitize_bus(struct pci_bus *bus)
+{
+ struct pci_dev *dev;
+ int i;
+ unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
+
+ list_for_each_entry(dev, &bus->devices, bus_list) {
+ for (i=0; i<PCI_BRIDGE_RESOURCES; i++) {
+ struct resource *res = &dev->resource[i];
+ if ((res->flags & type_mask) && !res->start &&
+ res->end) {
+ /* Could not assign a required resources
+ * for this device, remove it */
+ pci_remove_bus_device(dev);
+ break;
+ }
+ }
+ }
+}
+
+/* Program resources in newly inserted bridge */
+static int acpiphp_configure_bridge (acpi_handle handle)
+{
+ struct acpi_pci_id pci_id;
+ struct pci_bus *bus;
+
+ if (ACPI_FAILURE(acpi_get_pci_id(handle, &pci_id))) {
+ err("cannot get PCI domain and bus number for bridge\n");
+ return -EINVAL;
+ }
+ bus = pci_find_bus(pci_id.segment, pci_id.bus);
+ if (!bus) {
+ err("cannot find bus %d:%d\n",
+ pci_id.segment, pci_id.bus);
+ return -EINVAL;
+ }
+
+ pci_bus_size_bridges(bus);
+ pci_bus_assign_resources(bus);
+ acpiphp_sanitize_bus(bus);
+ acpiphp_set_hpp_values(handle, bus);
+ pci_enable_bridges(bus);
+ acpiphp_configure_ioapics(handle);
+ return 0;
+}
+
+static void handle_bridge_insertion(acpi_handle handle, u32 type)
+{
+ struct acpi_device *device, *pdevice;
+ acpi_handle phandle;
+
+ if ((type != ACPI_NOTIFY_BUS_CHECK) &&
+ (type != ACPI_NOTIFY_DEVICE_CHECK)) {
+ err("unexpected notification type %d\n", type);
+ return;
+ }
+
+ acpi_get_parent(handle, &phandle);
+ if (acpi_bus_get_device(phandle, &pdevice)) {
+ dbg("no parent device, assuming NULL\n");
+ pdevice = NULL;
+ }
+ if (acpi_bus_add(&device, pdevice, handle, ACPI_BUS_TYPE_DEVICE)) {
+ err("cannot add bridge to acpi list\n");
+ return;
+ }
+ if (!acpiphp_configure_bridge(handle) &&
+ !acpi_bus_start(device))
+ add_bridge(handle);
+ else
+ err("cannot configure and start bridge\n");
+
+}
+
/*
* ACPI event handlers
*/
@@ -982,8 +1120,19 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
char objname[64];
struct acpi_buffer buffer = { .length = sizeof(objname),
.pointer = objname };
+ struct acpi_device *device;
- bridge = (struct acpiphp_bridge *)context;
+ if (acpi_bus_get_device(handle, &device)) {
+ /* This bridge must have just been physically inserted */
+ handle_bridge_insertion(handle, type);
+ return;
+ }
+
+ bridge = acpiphp_handle_to_bridge(handle);
+ if (!bridge) {
+ err("cannot get bridge info\n");
+ return;
+ }
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
@@ -1031,7 +1180,6 @@ static void handle_hotplug_event_bridge(acpi_handle handle, u32 type, void *cont
}
}
-
/**
* handle_hotplug_event_func - handle ACPI event on functions (i.e. slots)
*
@@ -1074,7 +1222,8 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
case ACPI_NOTIFY_EJECT_REQUEST:
/* request device eject */
dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname);
- acpiphp_disable_slot(func->slot);
+ if (!(acpiphp_disable_slot(func->slot)))
+ acpiphp_eject_slot(func->slot);
break;
default:
@@ -1083,6 +1232,47 @@ static void handle_hotplug_event_func(acpi_handle handle, u32 type, void *contex
}
}
+static int is_root_bridge(acpi_handle handle)
+{
+ acpi_status status;
+ struct acpi_device_info *info;
+ struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
+ int i;
+
+ status = acpi_get_object_info(handle, &buffer);
+ if (ACPI_SUCCESS(status)) {
+ info = buffer.pointer;
+ if ((info->valid & ACPI_VALID_HID) &&
+ !strcmp(PCI_ROOT_HID_STRING,
+ info->hardware_id.value)) {
+ acpi_os_free(buffer.pointer);
+ return 1;
+ }
+ if (info->valid & ACPI_VALID_CID) {
+ for (i=0; i < info->compatibility_id.count; i++) {
+ if (!strcmp(PCI_ROOT_HID_STRING,
+ info->compatibility_id.id[i].value)) {
+ acpi_os_free(buffer.pointer);
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+static acpi_status
+find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv)
+{
+ int *count = (int *)context;
+
+ if (is_root_bridge(handle)) {
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ handle_hotplug_event_bridge, NULL);
+ (*count)++;
+ }
+ return AE_OK ;
+}
static struct acpi_pci_driver acpi_pci_hp_driver = {
.add = add_bridge,
@@ -1095,15 +1285,15 @@ static struct acpi_pci_driver acpi_pci_hp_driver = {
*/
int __init acpiphp_glue_init(void)
{
- int num;
-
- if (list_empty(&pci_root_buses))
- return -1;
+ int num = 0;
- num = acpi_pci_register_driver(&acpi_pci_hp_driver);
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX, find_root_bridges, &num, NULL);
if (num <= 0)
return -1;
+ else
+ acpi_pci_register_driver(&acpi_pci_hp_driver);
return 0;
}
@@ -1116,46 +1306,6 @@ int __init acpiphp_glue_init(void)
*/
void __exit acpiphp_glue_exit(void)
{
- struct list_head *l1, *l2, *n1, *n2;
- struct acpiphp_bridge *bridge;
- struct acpiphp_slot *slot, *next;
- struct acpiphp_func *func;
- acpi_status status;
-
- list_for_each_safe (l1, n1, &bridge_list) {
- bridge = (struct acpiphp_bridge *)l1;
- slot = bridge->slots;
- while (slot) {
- next = slot->next;
- list_for_each_safe (l2, n2, &slot->funcs) {
- func = list_entry(l2, struct acpiphp_func, sibling);
- acpiphp_free_resource(&func->io_head);
- acpiphp_free_resource(&func->mem_head);
- acpiphp_free_resource(&func->p_mem_head);
- acpiphp_free_resource(&func->bus_head);
- status = acpi_remove_notify_handler(func->handle,
- ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_func);
- if (ACPI_FAILURE(status))
- err("failed to remove notify handler\n");
- kfree(func);
- }
- kfree(slot);
- slot = next;
- }
- status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY,
- handle_hotplug_event_bridge);
- if (ACPI_FAILURE(status))
- err("failed to remove notify handler\n");
-
- acpiphp_free_resource(&bridge->io_head);
- acpiphp_free_resource(&bridge->mem_head);
- acpiphp_free_resource(&bridge->p_mem_head);
- acpiphp_free_resource(&bridge->bus_head);
-
- kfree(bridge);
- }
-
acpi_pci_unregister_driver(&acpi_pci_hp_driver);
}
@@ -1173,11 +1323,14 @@ int __init acpiphp_get_num_slots(void)
list_for_each (node, &bridge_list) {
bridge = (struct acpiphp_bridge *)node;
- dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots);
+ dbg("Bus %04x:%02x has %d slot%s\n",
+ pci_domain_nr(bridge->pci_bus),
+ bridge->pci_bus->number, bridge->nr_slots,
+ bridge->nr_slots == 1 ? "" : "s");
num_slots += bridge->nr_slots;
}
- dbg("Total %dslots\n", num_slots);
+ dbg("Total %d slots\n", num_slots);
return num_slots;
}
@@ -1254,7 +1407,6 @@ int acpiphp_enable_slot(struct acpiphp_slot *slot)
return retval;
}
-
/**
* acpiphp_disable_slot - power off slot
*/
@@ -1274,13 +1426,6 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
if (retval)
goto err_exit;
- acpiphp_resource_sort_and_combine(&slot->bridge->io_head);
- acpiphp_resource_sort_and_combine(&slot->bridge->mem_head);
- acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head);
- acpiphp_resource_sort_and_combine(&slot->bridge->bus_head);
- dbg("Available resources:\n");
- acpiphp_dump_resource(slot->bridge);
-
err_exit:
up(&slot->crit_sect);
return retval;
@@ -1293,11 +1438,7 @@ int acpiphp_disable_slot(struct acpiphp_slot *slot)
*/
u8 acpiphp_get_power_status(struct acpiphp_slot *slot)
{
- unsigned int sta;
-
- sta = get_slot_status(slot);
-
- return (sta & ACPI_STA_ENABLED) ? 1 : 0;
+ return (slot->flags & SLOT_POWEREDON);
}
@@ -1335,9 +1476,10 @@ u8 acpiphp_get_adapter_status(struct acpiphp_slot *slot)
u32 acpiphp_get_address(struct acpiphp_slot *slot)
{
u32 address;
+ struct pci_bus *pci_bus = slot->bridge->pci_bus;
- address = ((slot->bridge->seg) << 16) |
- ((slot->bridge->bus) << 8) |
+ address = (pci_domain_nr(pci_bus) << 16) |
+ (pci_bus->number << 8) |
slot->device;
return address;
diff --git a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c
deleted file mode 100644
index 54d97c9d1dff..000000000000
--- a/drivers/pci/hotplug/acpiphp_pci.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * ACPI PCI HotPlug PCI configuration space management
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001,2002 IBM Corp.
- * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (C) 2002 NEC Corporation
- *
- * 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 <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#include "../pci.h"
-#include "pci_hotplug.h"
-#include "acpiphp.h"
-
-#define MY_NAME "acpiphp_pci"
-
-
-/* allocate mem/pmem/io resource to a new function */
-static int init_config_space (struct acpiphp_func *func)
-{
- u32 bar, len;
- u32 address[] = {
- PCI_BASE_ADDRESS_0,
- PCI_BASE_ADDRESS_1,
- PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3,
- PCI_BASE_ADDRESS_4,
- PCI_BASE_ADDRESS_5,
- 0
- };
- int count;
- struct acpiphp_bridge *bridge;
- struct pci_resource *res;
- struct pci_bus *pbus;
- int bus, device, function;
- unsigned int devfn;
- u16 tmp;
-
- bridge = func->slot->bridge;
- pbus = bridge->pci_bus;
- bus = bridge->bus;
- device = func->slot->device;
- function = func->function;
- devfn = PCI_DEVFN(device, function);
-
- for (count = 0; address[count]; count++) { /* for 6 BARs */
- pci_bus_write_config_dword(pbus, devfn,
- address[count], 0xFFFFFFFF);
- pci_bus_read_config_dword(pbus, devfn, address[count], &bar);
-
- if (!bar) /* This BAR is not implemented */
- continue;
-
- dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar);
-
- if (bar & PCI_BASE_ADDRESS_SPACE_IO) {
- /* This is IO */
-
- len = bar & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
- len = len & ~(len - 1);
-
- dbg("len in IO %x, BAR %d\n", len, count);
-
- spin_lock(&bridge->res_lock);
- res = acpiphp_get_io_resource(&bridge->io_head, len);
- spin_unlock(&bridge->res_lock);
-
- if (!res) {
- err("cannot allocate requested io for %02x:%02x.%d len %x\n",
- bus, device, function, len);
- return -1;
- }
- pci_bus_write_config_dword(pbus, devfn,
- address[count],
- (u32)res->base);
- res->next = func->io_head;
- func->io_head = res;
-
- } else {
- /* This is Memory */
- if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- /* pfmem */
-
- len = bar & 0xFFFFFFF0;
- len = ~len + 1;
-
- dbg("len in PFMEM %x, BAR %d\n", len, count);
-
- spin_lock(&bridge->res_lock);
- res = acpiphp_get_resource(&bridge->p_mem_head, len);
- spin_unlock(&bridge->res_lock);
-
- if (!res) {
- err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
- bus, device, function, len);
- return -1;
- }
-
- pci_bus_write_config_dword(pbus, devfn,
- address[count],
- (u32)res->base);
-
- if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
- dbg("inside the pfmem 64 case, count %d\n", count);
- count += 1;
- pci_bus_write_config_dword(pbus, devfn,
- address[count],
- (u32)(res->base >> 32));
- }
-
- res->next = func->p_mem_head;
- func->p_mem_head = res;
-
- } else {
- /* regular memory */
-
- len = bar & 0xFFFFFFF0;
- len = ~len + 1;
-
- dbg("len in MEM %x, BAR %d\n", len, count);
-
- spin_lock(&bridge->res_lock);
- res = acpiphp_get_resource(&bridge->mem_head, len);
- spin_unlock(&bridge->res_lock);
-
- if (!res) {
- err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n",
- bus, device, function, len);
- return -1;
- }
-
- pci_bus_write_config_dword(pbus, devfn,
- address[count],
- (u32)res->base);
-
- if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- /* takes up another dword */
- dbg("inside mem 64 case, reg. mem, count %d\n", count);
- count += 1;
- pci_bus_write_config_dword(pbus, devfn,
- address[count],
- (u32)(res->base >> 32));
- }
-
- res->next = func->mem_head;
- func->mem_head = res;
-
- }
- }
- }
-
- /* disable expansion rom */
- pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000);
-
- /* set PCI parameters from _HPP */
- pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE,
- bridge->hpp.cache_line_size);
- pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER,
- bridge->hpp.latency_timer);
-
- pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp);
- if (bridge->hpp.enable_SERR)
- tmp |= PCI_COMMAND_SERR;
- if (bridge->hpp.enable_PERR)
- tmp |= PCI_COMMAND_PARITY;
- pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp);
-
- return 0;
-}
-
-/* detect_used_resource - subtract resource under dev from bridge */
-static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev)
-{
- int count;
-
- dbg("Device %s\n", pci_name(dev));
-
- for (count = 0; count < DEVICE_COUNT_RESOURCE; count++) {
- struct pci_resource *res;
- struct pci_resource **head;
- unsigned long base = dev->resource[count].start;
- unsigned long len = dev->resource[count].end - base + 1;
- unsigned long flags = dev->resource[count].flags;
-
- if (!flags)
- continue;
-
- dbg("BAR[%d] 0x%lx - 0x%lx (0x%lx)\n", count, base,
- base + len - 1, flags);
-
- if (flags & IORESOURCE_IO) {
- head = &bridge->io_head;
- } else if (flags & IORESOURCE_PREFETCH) {
- head = &bridge->p_mem_head;
- } else {
- head = &bridge->mem_head;
- }
-
- spin_lock(&bridge->res_lock);
- res = acpiphp_get_resource_with_base(head, base, len);
- spin_unlock(&bridge->res_lock);
- if (res)
- kfree(res);
- }
-
- return 0;
-}
-
-
-/**
- * acpiphp_detect_pci_resource - detect resources under bridge
- * @bridge: detect all resources already used under this bridge
- *
- * collect all resources already allocated for all devices under a bridge.
- */
-int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge)
-{
- struct list_head *l;
- struct pci_dev *dev;
-
- list_for_each (l, &bridge->pci_bus->devices) {
- dev = pci_dev_b(l);
- detect_used_resource(bridge, dev);
- }
-
- return 0;
-}
-
-
-/**
- * acpiphp_init_slot_resource - gather resource usage information of a slot
- * @slot: ACPI slot object to be checked, should have valid pci_dev member
- *
- * TBD: PCI-to-PCI bridge case
- * use pci_dev->resource[]
- */
-int acpiphp_init_func_resource (struct acpiphp_func *func)
-{
- u64 base;
- u32 bar, len;
- u32 address[] = {
- PCI_BASE_ADDRESS_0,
- PCI_BASE_ADDRESS_1,
- PCI_BASE_ADDRESS_2,
- PCI_BASE_ADDRESS_3,
- PCI_BASE_ADDRESS_4,
- PCI_BASE_ADDRESS_5,
- 0
- };
- int count;
- struct pci_resource *res;
- struct pci_dev *dev;
-
- dev = func->pci_dev;
- dbg("Hot-pluggable device %s\n", pci_name(dev));
-
- for (count = 0; address[count]; count++) { /* for 6 BARs */
- pci_read_config_dword(dev, address[count], &bar);
-
- if (!bar) /* This BAR is not implemented */
- continue;
-
- pci_write_config_dword(dev, address[count], 0xFFFFFFFF);
- pci_read_config_dword(dev, address[count], &len);
-
- if (len & PCI_BASE_ADDRESS_SPACE_IO) {
- /* This is IO */
- base = bar & 0xFFFFFFFC;
- len = len & (PCI_BASE_ADDRESS_IO_MASK & 0xFFFF);
- len = len & ~(len - 1);
-
- dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1);
-
- res = acpiphp_make_resource(base, len);
- if (!res)
- goto no_memory;
-
- res->next = func->io_head;
- func->io_head = res;
-
- } else {
- /* This is Memory */
- base = bar & 0xFFFFFFF0;
- if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) {
- /* pfmem */
-
- len &= 0xFFFFFFF0;
- len = ~len + 1;
-
- if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */
- dbg("prefetch mem 64\n");
- count += 1;
- }
- dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1);
- res = acpiphp_make_resource(base, len);
- if (!res)
- goto no_memory;
-
- res->next = func->p_mem_head;
- func->p_mem_head = res;
-
- } else {
- /* regular memory */
-
- len &= 0xFFFFFFF0;
- len = ~len + 1;
-
- if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) {
- /* takes up another dword */
- dbg("mem 64\n");
- count += 1;
- }
- dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1);
- res = acpiphp_make_resource(base, len);
- if (!res)
- goto no_memory;
-
- res->next = func->mem_head;
- func->mem_head = res;
-
- }
- }
-
- pci_write_config_dword(dev, address[count], bar);
- }
-#if 1
- acpiphp_dump_func_resource(func);
-#endif
-
- return 0;
-
- no_memory:
- err("out of memory\n");
- acpiphp_free_resource(&func->io_head);
- acpiphp_free_resource(&func->mem_head);
- acpiphp_free_resource(&func->p_mem_head);
-
- return -1;
-}
-
-
-/**
- * acpiphp_configure_slot - allocate PCI resources
- * @slot: slot to be configured
- *
- * initializes a PCI functions on a device inserted
- * into the slot
- *
- */
-int acpiphp_configure_slot (struct acpiphp_slot *slot)
-{
- struct acpiphp_func *func;
- struct list_head *l;
- u8 hdr;
- u32 dvid;
- int retval = 0;
- int is_multi = 0;
-
- pci_bus_read_config_byte(slot->bridge->pci_bus,
- PCI_DEVFN(slot->device, 0),
- PCI_HEADER_TYPE, &hdr);
-
- if (hdr & 0x80)
- is_multi = 1;
-
- list_for_each (l, &slot->funcs) {
- func = list_entry(l, struct acpiphp_func, sibling);
- if (is_multi || func->function == 0) {
- pci_bus_read_config_dword(slot->bridge->pci_bus,
- PCI_DEVFN(slot->device,
- func->function),
- PCI_VENDOR_ID, &dvid);
- if (dvid != 0xffffffff) {
- retval = init_config_space(func);
- if (retval)
- break;
- }
- }
- }
-
- return retval;
-}
-
-/**
- * acpiphp_configure_function - configure PCI function
- * @func: function to be configured
- *
- * initializes a PCI functions on a device inserted
- * into the slot
- *
- */
-int acpiphp_configure_function (struct acpiphp_func *func)
-{
- /* all handled by the pci core now */
- return 0;
-}
-
-/**
- * acpiphp_unconfigure_function - unconfigure PCI function
- * @func: function to be unconfigured
- *
- */
-void acpiphp_unconfigure_function (struct acpiphp_func *func)
-{
- struct acpiphp_bridge *bridge;
-
- /* if pci_dev is NULL, ignore it */
- if (!func->pci_dev)
- return;
-
- pci_remove_bus_device(func->pci_dev);
-
- /* free all resources */
- bridge = func->slot->bridge;
-
- spin_lock(&bridge->res_lock);
- acpiphp_move_resource(&func->io_head, &bridge->io_head);
- acpiphp_move_resource(&func->mem_head, &bridge->mem_head);
- acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head);
- acpiphp_move_resource(&func->bus_head, &bridge->bus_head);
- spin_unlock(&bridge->res_lock);
-}
diff --git a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c
deleted file mode 100644
index f54b1fa7b75a..000000000000
--- a/drivers/pci/hotplug/acpiphp_res.c
+++ /dev/null
@@ -1,700 +0,0 @@
-/*
- * ACPI PCI HotPlug Utility functions
- *
- * Copyright (C) 1995,2001 Compaq Computer Corporation
- * Copyright (C) 2001 Greg Kroah-Hartman (greg@kroah.com)
- * Copyright (C) 2001 IBM Corp.
- * Copyright (C) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com)
- * Copyright (C) 2002 Takayoshi Kochi (t-kochi@bq.jp.nec.com)
- * Copyright (C) 2002 NEC Corporation
- *
- * 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 <gregkh@us.ibm.com>, <t-kochi@bq.jp.nec.com>
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/sysctl.h>
-#include <linux/pci.h>
-#include <linux/smp.h>
-#include <linux/smp_lock.h>
-
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-
-#include <linux/ioctl.h>
-#include <linux/fcntl.h>
-
-#include <linux/list.h>
-
-#include "pci_hotplug.h"
-#include "acpiphp.h"
-
-#define MY_NAME "acpiphp_res"
-
-
-/*
- * sort_by_size - sort nodes by their length, smallest first
- */
-static int sort_by_size(struct pci_resource **head)
-{
- struct pci_resource *current_res;
- struct pci_resource *next_res;
- int out_of_order = 1;
-
- if (!(*head))
- return 1;
-
- if (!((*head)->next))
- return 0;
-
- while (out_of_order) {
- out_of_order = 0;
-
- /* Special case for swapping list head */
- if (((*head)->next) &&
- ((*head)->length > (*head)->next->length)) {
- out_of_order++;
- current_res = *head;
- *head = (*head)->next;
- current_res->next = (*head)->next;
- (*head)->next = current_res;
- }
-
- current_res = *head;
-
- while (current_res->next && current_res->next->next) {
- if (current_res->next->length > current_res->next->next->length) {
- out_of_order++;
- next_res = current_res->next;
- current_res->next = current_res->next->next;
- current_res = current_res->next;
- next_res->next = current_res->next;
- current_res->next = next_res;
- } else
- current_res = current_res->next;
- }
- } /* End of out_of_order loop */
-
- return 0;
-}
-
-#if 0
-/*
- * sort_by_max_size - sort nodes by their length, largest first
- */
-static int sort_by_max_size(struct pci_resource **head)
-{
- struct pci_resource *current_res;
- struct pci_resource *next_res;
- int out_of_order = 1;
-
- if (!(*head))
- return 1;
-
- if (!((*head)->next))
- return 0;
-
- while (out_of_order) {
- out_of_order = 0;
-
- /* Special case for swapping list head */
- if (((*head)->next) &&
- ((*head)->length < (*head)->next->length)) {
- out_of_order++;
- current_res = *head;
- *head = (*head)->next;
- current_res->next = (*head)->next;
- (*head)->next = current_res;
- }
-
- current_res = *head;
-
- while (current_res->next && current_res->next->next) {
- if (current_res->next->length < current_res->next->next->length) {
- out_of_order++;
- next_res = current_res->next;
- current_res->next = current_res->next->next;
- current_res = current_res->next;
- next_res->next = current_res->next;
- current_res->next = next_res;
- } else
- current_res = current_res->next;
- }
- } /* End of out_of_order loop */
-
- return 0;
-}
-#endif
-
-/**
- * get_io_resource - get resource for I/O ports
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length that is not in the
- * ISA aliasing window. If it finds a node larger than "size"
- * it will split it up.
- *
- * size must be a power of two.
- *
- * difference from get_resource is handling of ISA aliasing space.
- *
- */
-struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size)
-{
- struct pci_resource *prevnode;
- struct pci_resource *node;
- struct pci_resource *split_node;
- u64 temp_qword;
-
- if (!(*head))
- return NULL;
-
- if (acpiphp_resource_sort_and_combine(head))
- return NULL;
-
- if (sort_by_size(head))
- return NULL;
-
- for (node = *head; node; node = node->next) {
- if (node->length < size)
- continue;
-
- if (node->base & (size - 1)) {
- /* this one isn't base aligned properly
- so we'll make a new entry and split it up */
- temp_qword = (node->base | (size-1)) + 1;
-
- /* Short circuit if adjusted size is too small */
- if ((node->length - (temp_qword - node->base)) < size)
- continue;
-
- split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
- if (!split_node)
- return NULL;
-
- node->base = temp_qword;
- node->length -= split_node->length;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- } /* End of non-aligned base */
-
- /* Don't need to check if too small since we already did */
- if (node->length > size) {
- /* this one is longer than we need
- so we'll make a new entry and split it up */
- split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
- if (!split_node)
- return NULL;
-
- node->length = size;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- } /* End of too big on top end */
-
- /* For IO make sure it's not in the ISA aliasing space */
- if ((node->base & 0x300L) && !(node->base & 0xfffff000))
- continue;
-
- /* If we got here, then it is the right size
- Now take it out of the list */
- if (*head == node) {
- *head = node->next;
- } else {
- prevnode = *head;
- while (prevnode->next != node)
- prevnode = prevnode->next;
-
- prevnode->next = node->next;
- }
- node->next = NULL;
- /* Stop looping */
- break;
- }
-
- return node;
-}
-
-
-#if 0
-/**
- * get_max_resource - get the largest resource
- *
- * Gets the largest node that is at least "size" big from the
- * list pointed to by head. It aligns the node on top and bottom
- * to "size" alignment before returning it.
- */
-static struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size)
-{
- struct pci_resource *max;
- struct pci_resource *temp;
- struct pci_resource *split_node;
- u64 temp_qword;
-
- if (!(*head))
- return NULL;
-
- if (acpiphp_resource_sort_and_combine(head))
- return NULL;
-
- if (sort_by_max_size(head))
- return NULL;
-
- for (max = *head;max; max = max->next) {
-
- /* If not big enough we could probably just bail,
- instead we'll continue to the next. */
- if (max->length < size)
- continue;
-
- if (max->base & (size - 1)) {
- /* this one isn't base aligned properly
- so we'll make a new entry and split it up */
- temp_qword = (max->base | (size-1)) + 1;
-
- /* Short circuit if adjusted size is too small */
- if ((max->length - (temp_qword - max->base)) < size)
- continue;
-
- split_node = acpiphp_make_resource(max->base, temp_qword - max->base);
-
- if (!split_node)
- return NULL;
-
- max->base = temp_qword;
- max->length -= split_node->length;
-
- /* Put it next in the list */
- split_node->next = max->next;
- max->next = split_node;
- }
-
- if ((max->base + max->length) & (size - 1)) {
- /* this one isn't end aligned properly at the top
- so we'll make a new entry and split it up */
- temp_qword = ((max->base + max->length) & ~(size - 1));
-
- split_node = acpiphp_make_resource(temp_qword,
- max->length + max->base - temp_qword);
-
- if (!split_node)
- return NULL;
-
- max->length -= split_node->length;
-
- /* Put it in the list */
- split_node->next = max->next;
- max->next = split_node;
- }
-
- /* Make sure it didn't shrink too much when we aligned it */
- if (max->length < size)
- continue;
-
- /* Now take it out of the list */
- temp = (struct pci_resource*) *head;
- if (temp == max) {
- *head = max->next;
- } else {
- while (temp && temp->next != max) {
- temp = temp->next;
- }
-
- temp->next = max->next;
- }
-
- max->next = NULL;
- return max;
- }
-
- /* If we get here, we couldn't find one */
- return NULL;
-}
-#endif
-
-/**
- * get_resource - get resource (mem, pfmem)
- *
- * this function sorts the resource list by size and then
- * returns the first node of "size" length. If it finds a node
- * larger than "size" it will split it up.
- *
- * size must be a power of two.
- *
- */
-struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size)
-{
- struct pci_resource *prevnode;
- struct pci_resource *node;
- struct pci_resource *split_node;
- u64 temp_qword;
-
- if (!(*head))
- return NULL;
-
- if (acpiphp_resource_sort_and_combine(head))
- return NULL;
-
- if (sort_by_size(head))
- return NULL;
-
- for (node = *head; node; node = node->next) {
- dbg("%s: req_size =%x node=%p, base=%x, length=%x\n",
- __FUNCTION__, size, node, (u32)node->base, node->length);
- if (node->length < size)
- continue;
-
- if (node->base & (size - 1)) {
- dbg("%s: not aligned\n", __FUNCTION__);
- /* this one isn't base aligned properly
- so we'll make a new entry and split it up */
- temp_qword = (node->base | (size-1)) + 1;
-
- /* Short circuit if adjusted size is too small */
- if ((node->length - (temp_qword - node->base)) < size)
- continue;
-
- split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
- if (!split_node)
- return NULL;
-
- node->base = temp_qword;
- node->length -= split_node->length;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- } /* End of non-aligned base */
-
- /* Don't need to check if too small since we already did */
- if (node->length > size) {
- dbg("%s: too big\n", __FUNCTION__);
- /* this one is longer than we need
- so we'll make a new entry and split it up */
- split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
- if (!split_node)
- return NULL;
-
- node->length = size;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- } /* End of too big on top end */
-
- dbg("%s: got one!!!\n", __FUNCTION__);
- /* If we got here, then it is the right size
- Now take it out of the list */
- if (*head == node) {
- *head = node->next;
- } else {
- prevnode = *head;
- while (prevnode->next != node)
- prevnode = prevnode->next;
-
- prevnode->next = node->next;
- }
- node->next = NULL;
- /* Stop looping */
- break;
- }
- return node;
-}
-
-/**
- * get_resource_with_base - get resource with specific base address
- *
- * this function
- * returns the first node of "size" length located at specified base address.
- * If it finds a node larger than "size" it will split it up.
- *
- * size must be a power of two.
- *
- */
-struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size)
-{
- struct pci_resource *prevnode;
- struct pci_resource *node;
- struct pci_resource *split_node;
- u64 temp_qword;
-
- if (!(*head))
- return NULL;
-
- if (acpiphp_resource_sort_and_combine(head))
- return NULL;
-
- for (node = *head; node; node = node->next) {
- dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
- (u32)base, size, node, (u32)node->base, node->length);
- if (node->base > base)
- continue;
-
- if ((node->base + node->length) < (base + size))
- continue;
-
- if (node->base < base) {
- dbg(": split 1\n");
- /* this one isn't base aligned properly
- so we'll make a new entry and split it up */
- temp_qword = base;
-
- /* Short circuit if adjusted size is too small */
- if ((node->length - (temp_qword - node->base)) < size)
- continue;
-
- split_node = acpiphp_make_resource(node->base, temp_qword - node->base);
-
- if (!split_node)
- return NULL;
-
- node->base = temp_qword;
- node->length -= split_node->length;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- }
-
- dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n",
- (u32)base, size, node, (u32)node->base, node->length);
-
- /* Don't need to check if too small since we already did */
- if (node->length > size) {
- dbg(": split 2\n");
- /* this one is longer than we need
- so we'll make a new entry and split it up */
- split_node = acpiphp_make_resource(node->base + size, node->length - size);
-
- if (!split_node)
- return NULL;
-
- node->length = size;
-
- /* Put it in the list */
- split_node->next = node->next;
- node->next = split_node;
- } /* End of too big on top end */
-
- dbg(": got one!!!\n");
- /* If we got here, then it is the right size
- Now take it out of the list */
- if (*head == node) {
- *head = node->next;
- } else {
- prevnode = *head;
- while (prevnode->next != node)
- prevnode = prevnode->next;
-
- prevnode->next = node->next;
- }
- node->next = NULL;
- /* Stop looping */
- break;
- }
- return node;
-}
-
-
-/**
- * acpiphp_resource_sort_and_combine
- *
- * Sorts all of the nodes in the list in ascending order by
- * their base addresses. Also does garbage collection by
- * combining adjacent nodes.
- *
- * returns 0 if success
- */
-int acpiphp_resource_sort_and_combine (struct pci_resource **head)
-{
- struct pci_resource *node1;
- struct pci_resource *node2;
- int out_of_order = 1;
-
- if (!(*head))
- return 1;
-
- dbg("*head->next = %p\n",(*head)->next);
-
- if (!(*head)->next)
- return 0; /* only one item on the list, already sorted! */
-
- dbg("*head->base = 0x%x\n",(u32)(*head)->base);
- dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base);
- while (out_of_order) {
- out_of_order = 0;
-
- /* Special case for swapping list head */
- if (((*head)->next) &&
- ((*head)->base > (*head)->next->base)) {
- node1 = *head;
- (*head) = (*head)->next;
- node1->next = (*head)->next;
- (*head)->next = node1;
- out_of_order++;
- }
-
- node1 = (*head);
-
- while (node1->next && node1->next->next) {
- if (node1->next->base > node1->next->next->base) {
- out_of_order++;
- node2 = node1->next;
- node1->next = node1->next->next;
- node1 = node1->next;
- node2->next = node1->next;
- node1->next = node2;
- } else
- node1 = node1->next;
- }
- } /* End of out_of_order loop */
-
- node1 = *head;
-
- while (node1 && node1->next) {
- if ((node1->base + node1->length) == node1->next->base) {
- /* Combine */
- dbg("8..\n");
- node1->length += node1->next->length;
- node2 = node1->next;
- node1->next = node1->next->next;
- kfree(node2);
- } else
- node1 = node1->next;
- }
-
- return 0;
-}
-
-
-/**
- * acpiphp_make_resource - make resource structure
- * @base: base address of a resource
- * @length: length of a resource
- */
-struct pci_resource *acpiphp_make_resource (u64 base, u32 length)
-{
- struct pci_resource *res;
-
- res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL);
- if (res) {
- memset(res, 0, sizeof(struct pci_resource));
- res->base = base;
- res->length = length;
- }
-
- return res;
-}
-
-
-/**
- * acpiphp_move_resource - move linked resources from one to another
- * @from: head of linked resource list
- * @to: head of linked resource list
- */
-void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to)
-{
- struct pci_resource *tmp;
-
- while (*from) {
- tmp = (*from)->next;
- (*from)->next = *to;
- *to = *from;
- *from = tmp;
- }
-
- /* *from = NULL is guaranteed */
-}
-
-
-/**
- * acpiphp_free_resource - free all linked resources
- * @res: head of linked resource list
- */
-void acpiphp_free_resource (struct pci_resource **res)
-{
- struct pci_resource *tmp;
-
- while (*res) {
- tmp = (*res)->next;
- kfree(*res);
- *res = tmp;
- }
-
- /* *res = NULL is guaranteed */
-}
-
-
-/* debug support functions; will go away sometime :) */
-static void dump_resource(struct pci_resource *head)
-{
- struct pci_resource *p;
- int cnt;
-
- p = head;
- cnt = 0;
-
- while (p) {
- dbg("[%02d] %08x - %08x\n",
- cnt++, (u32)p->base, (u32)p->base + p->length - 1);
- p = p->next;
- }
-}
-
-void acpiphp_dump_resource(struct acpiphp_bridge *bridge)
-{
- dbg("I/O resource:\n");
- dump_resource(bridge->io_head);
- dbg("MEM resource:\n");
- dump_resource(bridge->mem_head);
- dbg("PMEM resource:\n");
- dump_resource(bridge->p_mem_head);
- dbg("BUS resource:\n");
- dump_resource(bridge->bus_head);
-}
-
-void acpiphp_dump_func_resource(struct acpiphp_func *func)
-{
- dbg("I/O resource:\n");
- dump_resource(func->io_head);
- dbg("MEM resource:\n");
- dump_resource(func->mem_head);
- dbg("PMEM resource:\n");
- dump_resource(func->p_mem_head);
- dbg("BUS resource:\n");
- dump_resource(func->bus_head);
-}
diff --git a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c
index afbccfa5217d..8c6d3987d461 100644
--- a/drivers/pci/hotplug/cpqphp_core.c
+++ b/drivers/pci/hotplug/cpqphp_core.c
@@ -60,6 +60,7 @@ static void __iomem *smbios_start;
static void __iomem *cpqhp_rom_start;
static int power_mode;
static int debug;
+static int initialized;
#define DRIVER_VERSION "0.9.8"
#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
@@ -1271,7 +1272,6 @@ static int one_time_init(void)
{
int loop;
int retval = 0;
- static int initialized = 0;
if (initialized)
return 0;
@@ -1441,7 +1441,8 @@ static void __exit unload_cpqphpd(void)
}
// Stop the notification mechanism
- cpqhp_event_stop_thread();
+ if (initialized)
+ cpqhp_event_stop_thread();
//unmap the rom address
if (cpqhp_rom_start)
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
new file mode 100644
index 000000000000..323041fd41dc
--- /dev/null
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -0,0 +1,611 @@
+/*
+ * 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) 2005 Silicon Graphics, Inc. All rights reserved.
+ *
+ * This work was based on the 2.4/2.6 kernel development by Dick Reigner.
+ * Work to add BIOS PROM support was completed by Mike Habeck.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/types.h>
+
+#include <asm/sn/addrs.h>
+#include <asm/sn/l1.h>
+#include <asm/sn/module.h>
+#include <asm/sn/pcibr_provider.h>
+#include <asm/sn/pcibus_provider_defs.h>
+#include <asm/sn/pcidev.h>
+#include <asm/sn/sn_sal.h>
+#include <asm/sn/types.h>
+
+#include "../pci.h"
+#include "pci_hotplug.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("SGI (prarit@sgi.com, dickie@sgi.com, habeck@sgi.com)");
+MODULE_DESCRIPTION("SGI Altix Hot Plug PCI Controller Driver");
+
+#define PCIIO_ASIC_TYPE_TIOCA 4
+#define PCI_SLOT_ALREADY_UP 2 /* slot already up */
+#define PCI_SLOT_ALREADY_DOWN 3 /* slot already down */
+#define PCI_L1_ERR 7 /* L1 console command error */
+#define PCI_EMPTY_33MHZ 15 /* empty 33 MHz bus */
+#define PCI_L1_QSIZE 128 /* our L1 message buffer size */
+#define SN_MAX_HP_SLOTS 32 /* max number of hotplug slots */
+#define SGI_HOTPLUG_PROM_REV 0x0420 /* Min. required PROM version */
+
+/* internal list head */
+static struct list_head sn_hp_list;
+
+/* hotplug_slot struct's private pointer */
+struct slot {
+ int device_num;
+ struct pci_bus *pci_bus;
+ /* this struct for glue internal only */
+ struct hotplug_slot *hotplug_slot;
+ struct list_head hp_list;
+};
+
+struct pcibr_slot_enable_resp {
+ int resp_sub_errno;
+ char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+struct pcibr_slot_disable_resp {
+ int resp_sub_errno;
+ char resp_l1_msg[PCI_L1_QSIZE + 1];
+};
+
+enum sn_pci_req_e {
+ PCI_REQ_SLOT_ELIGIBLE,
+ PCI_REQ_SLOT_DISABLE
+};
+
+static int enable_slot(struct hotplug_slot *slot);
+static int disable_slot(struct hotplug_slot *slot);
+static int get_power_status(struct hotplug_slot *slot, u8 *value);
+
+static struct hotplug_slot_ops sn_hotplug_slot_ops = {
+ .owner = THIS_MODULE,
+ .enable_slot = enable_slot,
+ .disable_slot = disable_slot,
+ .get_power_status = get_power_status,
+};
+
+static DECLARE_MUTEX(sn_hotplug_sem);
+
+static int sn_pci_slot_valid(struct pci_bus *pci_bus, int device)
+{
+ struct pcibus_info *pcibus_info;
+ int bricktype;
+ int bus_num;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+ /* Check to see if this is a valid slot on 'pci_bus' */
+ if (!(pcibus_info->pbi_valid_devices & (1 << device)))
+ return -EPERM;
+
+ bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid);
+ bus_num = pcibus_info->pbi_buscommon.bs_persist_busnum & 0xf;
+
+ /* Do not allow hotplug operations on base I/O cards */
+ if ((bricktype == L1_BRICKTYPE_IX || bricktype == L1_BRICKTYPE_IA) &&
+ (bus_num == 1 && device != 1))
+ return -EPERM;
+
+ return 1;
+}
+
+static int sn_pci_bus_valid(struct pci_bus *pci_bus)
+{
+ struct pcibus_info *pcibus_info;
+ int asic_type;
+ int bricktype;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+ /* Don't register slots hanging off the TIOCA bus */
+ asic_type = pcibus_info->pbi_buscommon.bs_asic_type;
+ if (asic_type == PCIIO_ASIC_TYPE_TIOCA)
+ return -EPERM;
+
+ /* Only register slots in I/O Bricks that support hotplug */
+ bricktype = MODULE_GET_BTYPE(pcibus_info->pbi_moduleid);
+ switch (bricktype) {
+ case L1_BRICKTYPE_IX:
+ case L1_BRICKTYPE_PX:
+ case L1_BRICKTYPE_IA:
+ case L1_BRICKTYPE_PA:
+ return 1;
+ break;
+ default:
+ return -EPERM;
+ break;
+ }
+
+ return -EIO;
+}
+
+static int sn_hp_slot_private_alloc(struct hotplug_slot *bss_hotplug_slot,
+ struct pci_bus *pci_bus, int device)
+{
+ struct pcibus_info *pcibus_info;
+ struct slot *slot;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(pci_bus);
+
+ bss_hotplug_slot->private = kcalloc(1, sizeof(struct slot),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot->private)
+ return -ENOMEM;
+ slot = (struct slot *)bss_hotplug_slot->private;
+
+ bss_hotplug_slot->name = kmalloc(33, GFP_KERNEL);
+ if (!bss_hotplug_slot->name) {
+ kfree(bss_hotplug_slot->private);
+ return -ENOMEM;
+ }
+
+ slot->device_num = device;
+ slot->pci_bus = pci_bus;
+
+ sprintf(bss_hotplug_slot->name, "module_%c%c%c%c%.2d_b_%d_s_%d",
+ '0'+RACK_GET_CLASS(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+ '0'+RACK_GET_GROUP(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+ '0'+RACK_GET_NUM(MODULE_GET_RACK(pcibus_info->pbi_moduleid)),
+ MODULE_GET_BTCHAR(pcibus_info->pbi_moduleid),
+ MODULE_GET_BPOS(pcibus_info->pbi_moduleid),
+ ((int)pcibus_info->pbi_buscommon.bs_persist_busnum) & 0xf,
+ device + 1);
+
+ slot->hotplug_slot = bss_hotplug_slot;
+ list_add(&slot->hp_list, &sn_hp_list);
+
+ return 0;
+}
+
+static struct hotplug_slot * sn_hp_destroy(void)
+{
+ struct slot *slot;
+ struct list_head *list;
+ struct hotplug_slot *bss_hotplug_slot = NULL;
+
+ list_for_each(list, &sn_hp_list) {
+ slot = list_entry(list, struct slot, hp_list);
+ bss_hotplug_slot = slot->hotplug_slot;
+ list_del(&((struct slot *)bss_hotplug_slot->private)->
+ hp_list);
+ break;
+ }
+ return bss_hotplug_slot;
+}
+
+static void sn_bus_alloc_data(struct pci_dev *dev)
+{
+ struct list_head *node;
+ struct pci_bus *subordinate_bus;
+ struct pci_dev *child;
+
+ sn_pci_fixup_slot(dev);
+
+ /* Recursively sets up the sn_irq_info structs */
+ if (dev->subordinate) {
+ subordinate_bus = dev->subordinate;
+ list_for_each(node, &subordinate_bus->devices) {
+ child = list_entry(node, struct pci_dev, bus_list);
+ sn_bus_alloc_data(child);
+ }
+ }
+}
+
+static void sn_bus_free_data(struct pci_dev *dev)
+{
+ struct list_head *node;
+ struct pci_bus *subordinate_bus;
+ struct pci_dev *child;
+
+ /* Recursively clean up sn_irq_info structs */
+ if (dev->subordinate) {
+ subordinate_bus = dev->subordinate;
+ list_for_each(node, &subordinate_bus->devices) {
+ child = list_entry(node, struct pci_dev, bus_list);
+ sn_bus_free_data(child);
+ }
+ }
+ sn_pci_unfixup_slot(dev);
+}
+
+static u8 sn_power_status_get(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ u8 retval;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+ retval = pcibus_info->pbi_enabled_devices & (1 << slot->device_num);
+
+ return retval ? 1 : 0;
+}
+
+static void sn_slot_mark_enable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+ pcibus_info->pbi_enabled_devices |= (1 << device_num);
+}
+
+static void sn_slot_mark_disable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+ pcibus_info->pbi_enabled_devices &= ~(1 << device_num);
+}
+
+static int sn_slot_enable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ struct pcibr_slot_enable_resp resp;
+ int rc;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+
+ /*
+ * Power-on and initialize the slot in the SN
+ * PCI infrastructure.
+ */
+ rc = sal_pcibr_slot_enable(pcibus_info, device_num, &resp);
+
+ if (rc == PCI_SLOT_ALREADY_UP) {
+ dev_dbg(slot->pci_bus->self, "is already active\n");
+ return -EPERM;
+ }
+
+ if (rc == PCI_L1_ERR) {
+ dev_dbg(slot->pci_bus->self,
+ "L1 failure %d with message: %s",
+ resp.resp_sub_errno, resp.resp_l1_msg);
+ return -EPERM;
+ }
+
+ if (rc) {
+ dev_dbg(slot->pci_bus->self,
+ "insert failed with error %d sub-error %d\n",
+ rc, resp.resp_sub_errno);
+ return -EIO;
+ }
+
+ sn_slot_mark_enable(bss_hotplug_slot, device_num);
+
+ return 0;
+}
+
+static int sn_slot_disable(struct hotplug_slot *bss_hotplug_slot,
+ int device_num, int action)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pcibus_info *pcibus_info;
+ struct pcibr_slot_disable_resp resp;
+ int rc;
+
+ pcibus_info = SN_PCIBUS_BUSSOFT_INFO(slot->pci_bus);
+
+ rc = sal_pcibr_slot_disable(pcibus_info, device_num, action, &resp);
+
+ if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_SLOT_ALREADY_DOWN) {
+ dev_dbg(slot->pci_bus->self, "Slot %s already inactive\n");
+ return -ENODEV;
+ }
+
+ if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_EMPTY_33MHZ) {
+ dev_dbg(slot->pci_bus->self,
+ "Cannot remove last 33MHz card\n");
+ return -EPERM;
+ }
+
+ if (action == PCI_REQ_SLOT_ELIGIBLE && rc == PCI_L1_ERR) {
+ dev_dbg(slot->pci_bus->self,
+ "L1 failure %d with message \n%s\n",
+ resp.resp_sub_errno, resp.resp_l1_msg);
+ return -EPERM;
+ }
+
+ if (action == PCI_REQ_SLOT_ELIGIBLE && rc) {
+ dev_dbg(slot->pci_bus->self,
+ "remove failed with error %d sub-error %d\n",
+ rc, resp.resp_sub_errno);
+ return -EIO;
+ }
+
+ if (action == PCI_REQ_SLOT_ELIGIBLE && !rc)
+ return 0;
+
+ if (action == PCI_REQ_SLOT_DISABLE && !rc) {
+ sn_slot_mark_disable(bss_hotplug_slot, device_num);
+ dev_dbg(slot->pci_bus->self, "remove successful\n");
+ return 0;
+ }
+
+ if (action == PCI_REQ_SLOT_DISABLE && rc) {
+ dev_dbg(slot->pci_bus->self,"remove failed rc = %d\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+static int enable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pci_bus *new_bus = NULL;
+ struct pci_dev *dev;
+ int func, num_funcs;
+ int new_ppb = 0;
+ int rc;
+
+ /* Serialize the Linux PCI infrastructure */
+ down(&sn_hotplug_sem);
+
+ /*
+ * Power-on and initialize the slot in the SN
+ * PCI infrastructure.
+ */
+ rc = sn_slot_enable(bss_hotplug_slot, slot->device_num);
+ if (rc) {
+ up(&sn_hotplug_sem);
+ return rc;
+ }
+
+ num_funcs = pci_scan_slot(slot->pci_bus, PCI_DEVFN(slot->device_num+1,
+ PCI_FUNC(0)));
+ if (!num_funcs) {
+ dev_dbg(slot->pci_bus->self, "no device in slot\n");
+ up(&sn_hotplug_sem);
+ return -ENODEV;
+ }
+
+ sn_pci_controller_fixup(pci_domain_nr(slot->pci_bus),
+ slot->pci_bus->number,
+ slot->pci_bus);
+ /*
+ * Map SN resources for all functions on the card
+ * to the Linux PCI interface and tell the drivers
+ * about them.
+ */
+ for (func = 0; func < num_funcs; func++) {
+ dev = pci_get_slot(slot->pci_bus,
+ PCI_DEVFN(slot->device_num + 1,
+ PCI_FUNC(func)));
+
+
+ if (dev) {
+ if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ unsigned char sec_bus;
+ pci_read_config_byte(dev, PCI_SECONDARY_BUS,
+ &sec_bus);
+ new_bus = pci_add_new_bus(dev->bus, dev,
+ sec_bus);
+ pci_scan_child_bus(new_bus);
+ sn_pci_controller_fixup(pci_domain_nr(new_bus),
+ new_bus->number,
+ new_bus);
+ new_ppb = 1;
+ }
+ sn_bus_alloc_data(dev);
+ pci_dev_put(dev);
+ }
+ }
+
+ /* Call the driver for the new device */
+ pci_bus_add_devices(slot->pci_bus);
+ /* Call the drivers for the new devices subordinate to PPB */
+ if (new_ppb)
+ pci_bus_add_devices(new_bus);
+
+ up(&sn_hotplug_sem);
+
+ if (rc == 0)
+ dev_dbg(slot->pci_bus->self,
+ "insert operation successful\n");
+ else
+ dev_dbg(slot->pci_bus->self,
+ "insert operation failed rc = %d\n", rc);
+
+ return rc;
+}
+
+static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ struct slot *slot = (struct slot *)bss_hotplug_slot->private;
+ struct pci_dev *dev;
+ int func;
+ int rc;
+
+ /* Acquire update access to the bus */
+ down(&sn_hotplug_sem);
+
+ /* is it okay to bring this slot down? */
+ rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
+ PCI_REQ_SLOT_ELIGIBLE);
+ if (rc)
+ goto leaving;
+
+ /* Free the SN resources assigned to the Linux device.*/
+ for (func = 0; func < 8; func++) {
+ dev = pci_get_slot(slot->pci_bus,
+ PCI_DEVFN(slot->device_num+1,
+ PCI_FUNC(func)));
+ if (dev) {
+ /*
+ * Some drivers may use dma accesses during the
+ * driver remove function. We release the sysdata
+ * areas after the driver remove functions have
+ * been called.
+ */
+ sn_bus_store_sysdata(dev);
+ sn_bus_free_data(dev);
+ pci_remove_bus_device(dev);
+ pci_dev_put(dev);
+ }
+ }
+
+ /* free the collected sysdata pointers */
+ sn_bus_free_sysdata();
+
+ /* Deactivate slot */
+ rc = sn_slot_disable(bss_hotplug_slot, slot->device_num,
+ PCI_REQ_SLOT_DISABLE);
+ leaving:
+ /* Release the bus lock */
+ up(&sn_hotplug_sem);
+
+ return rc;
+}
+
+static int get_power_status(struct hotplug_slot *bss_hotplug_slot, u8 *value)
+{
+ down(&sn_hotplug_sem);
+ *value = sn_power_status_get(bss_hotplug_slot);
+ up(&sn_hotplug_sem);
+ return 0;
+}
+
+static void sn_release_slot(struct hotplug_slot *bss_hotplug_slot)
+{
+ kfree(bss_hotplug_slot->info);
+ kfree(bss_hotplug_slot->name);
+ kfree(bss_hotplug_slot->private);
+ kfree(bss_hotplug_slot);
+}
+
+static int sn_hotplug_slot_register(struct pci_bus *pci_bus)
+{
+ int device;
+ struct hotplug_slot *bss_hotplug_slot;
+ int rc = 0;
+
+ /*
+ * Currently only four devices are supported,
+ * in the future there maybe more -- up to 32.
+ */
+
+ for (device = 0; device < SN_MAX_HP_SLOTS ; device++) {
+ if (sn_pci_slot_valid(pci_bus, device) != 1)
+ continue;
+
+ bss_hotplug_slot = kcalloc(1,sizeof(struct hotplug_slot),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot) {
+ rc = -ENOMEM;
+ goto alloc_err;
+ }
+
+ bss_hotplug_slot->info =
+ kcalloc(1,sizeof(struct hotplug_slot_info),
+ GFP_KERNEL);
+ if (!bss_hotplug_slot->info) {
+ rc = -ENOMEM;
+ goto alloc_err;
+ }
+
+ if (sn_hp_slot_private_alloc(bss_hotplug_slot,
+ pci_bus, device)) {
+ rc = -ENOMEM;
+ goto alloc_err;
+ }
+
+ bss_hotplug_slot->ops = &sn_hotplug_slot_ops;
+ bss_hotplug_slot->release = &sn_release_slot;
+
+ rc = pci_hp_register(bss_hotplug_slot);
+ if (rc)
+ goto register_err;
+ }
+ dev_dbg(pci_bus->self, "Registered bus with hotplug\n");
+ return rc;
+
+register_err:
+ dev_dbg(pci_bus->self, "bus failed to register with err = %d\n",
+ rc);
+
+alloc_err:
+ if (rc == -ENOMEM)
+ dev_dbg(pci_bus->self, "Memory allocation error\n");
+
+ /* destroy THIS element */
+ if (bss_hotplug_slot)
+ sn_release_slot(bss_hotplug_slot);
+
+ /* destroy anything else on the list */
+ while ((bss_hotplug_slot = sn_hp_destroy()))
+ pci_hp_deregister(bss_hotplug_slot);
+
+ return rc;
+}
+
+static int sn_pci_hotplug_init(void)
+{
+ struct pci_bus *pci_bus = NULL;
+ int rc;
+ int registered = 0;
+
+ INIT_LIST_HEAD(&sn_hp_list);
+
+ if (sn_sal_rev() < SGI_HOTPLUG_PROM_REV) {
+ printk(KERN_ERR "%s: PROM version must be greater than 4.05\n",
+ __FUNCTION__);
+ return -EPERM;
+ }
+
+ while ((pci_bus = pci_find_next_bus(pci_bus))) {
+ if (!pci_bus->sysdata)
+ continue;
+
+ rc = sn_pci_bus_valid(pci_bus);
+ if (rc != 1) {
+ dev_dbg(pci_bus->self, "not a valid hotplug bus\n");
+ continue;
+ }
+ dev_dbg(pci_bus->self, "valid hotplug bus\n");
+
+ rc = sn_hotplug_slot_register(pci_bus);
+ if (!rc)
+ registered = 1;
+ else {
+ registered = 0;
+ break;
+ }
+ }
+
+ return registered == 1 ? 0 : -ENODEV;
+}
+
+static void sn_pci_hotplug_exit(void)
+{
+ struct hotplug_slot *bss_hotplug_slot;
+
+ while ((bss_hotplug_slot = sn_hp_destroy())) {
+ pci_hp_deregister(bss_hotplug_slot);
+ }
+
+ if (!list_empty(&sn_hp_list))
+ printk(KERN_ERR "%s: internal list is not empty\n", __FILE__);
+}
+
+module_init(sn_pci_hotplug_init);
+module_exit(sn_pci_hotplug_exit);
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 30206ac43c44..b5ab9aa6ff7c 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -28,10 +28,10 @@ static struct msi_desc* msi_desc[NR_IRQS] = { [0 ... NR_IRQS-1] = NULL };
static kmem_cache_t* msi_cachep;
static int pci_msi_enable = 1;
-static int last_alloc_vector = 0;
-static int nr_released_vectors = 0;
+static int last_alloc_vector;
+static int nr_released_vectors;
static int nr_reserved_vectors = NR_HP_RESERVED_VECTORS;
-static int nr_msix_devices = 0;
+static int nr_msix_devices;
#ifndef CONFIG_X86_IO_APIC
int vector_irq[NR_VECTORS] = { [0 ... NR_VECTORS - 1] = -1};
@@ -170,44 +170,30 @@ static unsigned int startup_msi_irq_wo_maskbit(unsigned int vector)
return 0; /* never anything pending */
}
-static void release_msi(unsigned int vector);
-static void shutdown_msi_irq(unsigned int vector)
-{
- release_msi(vector);
-}
-
-#define shutdown_msi_irq_wo_maskbit shutdown_msi_irq
-static void enable_msi_irq_wo_maskbit(unsigned int vector) {}
-static void disable_msi_irq_wo_maskbit(unsigned int vector) {}
-static void ack_msi_irq_wo_maskbit(unsigned int vector) {}
-static void end_msi_irq_wo_maskbit(unsigned int vector)
+static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
{
- move_msi(vector);
- ack_APIC_irq();
+ startup_msi_irq_wo_maskbit(vector);
+ unmask_MSI_irq(vector);
+ return 0; /* never anything pending */
}
-static unsigned int startup_msi_irq_w_maskbit(unsigned int vector)
+static void shutdown_msi_irq(unsigned int vector)
{
struct msi_desc *entry;
unsigned long flags;
spin_lock_irqsave(&msi_lock, flags);
entry = msi_desc[vector];
- if (!entry || !entry->dev) {
- spin_unlock_irqrestore(&msi_lock, flags);
- return 0;
- }
- entry->msi_attrib.state = 1; /* Mark it active */
+ if (entry && entry->dev)
+ entry->msi_attrib.state = 0; /* Mark it not active */
spin_unlock_irqrestore(&msi_lock, flags);
-
- unmask_MSI_irq(vector);
- return 0; /* never anything pending */
}
-#define shutdown_msi_irq_w_maskbit shutdown_msi_irq
-#define enable_msi_irq_w_maskbit unmask_MSI_irq
-#define disable_msi_irq_w_maskbit mask_MSI_irq
-#define ack_msi_irq_w_maskbit mask_MSI_irq
+static void end_msi_irq_wo_maskbit(unsigned int vector)
+{
+ move_msi(vector);
+ ack_APIC_irq();
+}
static void end_msi_irq_w_maskbit(unsigned int vector)
{
@@ -216,6 +202,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector)
ack_APIC_irq();
}
+static void do_nothing(unsigned int vector)
+{
+}
+
/*
* Interrupt Type for MSI-X PCI/PCI-X/PCI-Express Devices,
* which implement the MSI-X Capability Structure.
@@ -223,10 +213,10 @@ static void end_msi_irq_w_maskbit(unsigned int vector)
static struct hw_interrupt_type msix_irq_type = {
.typename = "PCI-MSI-X",
.startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq_w_maskbit,
- .enable = enable_msi_irq_w_maskbit,
- .disable = disable_msi_irq_w_maskbit,
- .ack = ack_msi_irq_w_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = unmask_MSI_irq,
+ .disable = mask_MSI_irq,
+ .ack = mask_MSI_irq,
.end = end_msi_irq_w_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -239,10 +229,10 @@ static struct hw_interrupt_type msix_irq_type = {
static struct hw_interrupt_type msi_irq_w_maskbit_type = {
.typename = "PCI-MSI",
.startup = startup_msi_irq_w_maskbit,
- .shutdown = shutdown_msi_irq_w_maskbit,
- .enable = enable_msi_irq_w_maskbit,
- .disable = disable_msi_irq_w_maskbit,
- .ack = ack_msi_irq_w_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = unmask_MSI_irq,
+ .disable = mask_MSI_irq,
+ .ack = mask_MSI_irq,
.end = end_msi_irq_w_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -255,10 +245,10 @@ static struct hw_interrupt_type msi_irq_w_maskbit_type = {
static struct hw_interrupt_type msi_irq_wo_maskbit_type = {
.typename = "PCI-MSI",
.startup = startup_msi_irq_wo_maskbit,
- .shutdown = shutdown_msi_irq_wo_maskbit,
- .enable = enable_msi_irq_wo_maskbit,
- .disable = disable_msi_irq_wo_maskbit,
- .ack = ack_msi_irq_wo_maskbit,
+ .shutdown = shutdown_msi_irq,
+ .enable = do_nothing,
+ .disable = do_nothing,
+ .ack = do_nothing,
.end = end_msi_irq_wo_maskbit,
.set_affinity = set_msi_irq_affinity
};
@@ -407,7 +397,7 @@ static struct msi_desc* alloc_msi_entry(void)
{
struct msi_desc *entry;
- entry = (struct msi_desc*) kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
+ entry = kmem_cache_alloc(msi_cachep, SLAB_KERNEL);
if (!entry)
return NULL;
@@ -796,18 +786,6 @@ void pci_disable_msi(struct pci_dev* dev)
}
}
-static void release_msi(unsigned int vector)
-{
- struct msi_desc *entry;
- unsigned long flags;
-
- spin_lock_irqsave(&msi_lock, flags);
- entry = msi_desc[vector];
- if (entry && entry->dev)
- entry->msi_attrib.state = 0; /* Mark it not active */
- spin_unlock_irqrestore(&msi_lock, flags);
-}
-
static int msi_free_vector(struct pci_dev* dev, int vector, int reassign)
{
struct msi_desc *entry;
@@ -924,7 +902,7 @@ static int reroute_msix_table(int head, struct msix_entry *entries, int *nvec)
/**
* pci_enable_msix - configure device's MSI-X capability structure
* @dev: pointer to the pci_dev data structure of MSI-X device function
- * @data: pointer to an array of MSI-X entries
+ * @entries: pointer to an array of MSI-X entries
* @nvec: number of MSI-X vectors requested for allocation by device driver
*
* Setup the MSI-X capability structure of device function with the number
diff --git a/drivers/pci/msi.h b/drivers/pci/msi.h
index bef21ae3cbd0..390f1851c0f1 100644
--- a/drivers/pci/msi.h
+++ b/drivers/pci/msi.h
@@ -41,11 +41,11 @@ static inline void move_msi(int vector) {}
#define PCI_MSIX_FLAGS_BIRMASK (7 << 0)
#define PCI_MSIX_FLAGS_BITMASK (1 << 0)
-#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
-#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
-#define PCI_MSIX_ENTRY_DATA_OFFSET 8
-#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
#define PCI_MSIX_ENTRY_SIZE 16
+#define PCI_MSIX_ENTRY_LOWER_ADDR_OFFSET 0
+#define PCI_MSIX_ENTRY_UPPER_ADDR_OFFSET 4
+#define PCI_MSIX_ENTRY_DATA_OFFSET 8
+#define PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET 12
#define msi_control_reg(base) (base + PCI_MSI_FLAGS)
#define msi_lower_address_reg(base) (base + PCI_MSI_ADDRESS_LO)
@@ -64,7 +64,6 @@ static inline void move_msi(int vector) {}
#define msi_enable(control, num) multi_msi_enable(control, num); \
control |= PCI_MSI_FLAGS_ENABLE
-#define msix_control_reg msi_control_reg
#define msix_table_offset_reg(base) (base + 0x04)
#define msix_pba_offset_reg(base) (base + 0x08)
#define msix_enable(control) control |= PCI_MSIX_FLAGS_ENABLE
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index bc01d34e2634..e9e37abe1f76 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -1,9 +1,10 @@
/*
* File: pci-acpi.c
- * Purpose: Provide PCI supports in ACPI
+ * Purpose: Provide PCI support in ACPI
*
- * Copyright (C) 2004 Intel
- * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
+ * Copyright (C) 2005 David Shaohua Li <shaohua.li@intel.com>
+ * Copyright (C) 2004 Tom Long Nguyen <tom.l.nguyen@intel.com>
+ * Copyright (C) 2004 Intel Corp.
*/
#include <linux/delay.h>
@@ -16,6 +17,7 @@
#include <acpi/acpi_bus.h>
#include <linux/pci-acpi.h>
+#include "pci.h"
static u32 ctrlset_buf[3] = {0, 0, 0};
static u32 global_ctrlsets = 0;
@@ -207,3 +209,105 @@ acpi_status pci_osc_control_set(u32 flags)
return status;
}
EXPORT_SYMBOL(pci_osc_control_set);
+
+/*
+ * _SxD returns the D-state with the highest power
+ * (lowest D-state number) supported in the S-state "x".
+ *
+ * If the devices does not have a _PRW
+ * (Power Resources for Wake) supporting system wakeup from "x"
+ * then the OS is free to choose a lower power (higher number
+ * D-state) than the return value from _SxD.
+ *
+ * But if _PRW is enabled at S-state "x", the OS
+ * must not choose a power lower than _SxD --
+ * unless the device has an _SxW method specifying
+ * the lowest power (highest D-state number) the device
+ * may enter while still able to wake the system.
+ *
+ * ie. depending on global OS policy:
+ *
+ * if (_PRW at S-state x)
+ * choose from highest power _SxD to lowest power _SxW
+ * else // no _PRW at S-state x
+ * choose highest power _SxD or any lower power
+ *
+ * currently we simply return _SxD, if present.
+ */
+
+static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state)
+{
+ /* TBD */
+
+ return -ENODEV;
+}
+
+static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state)
+{
+ acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev);
+ static int state_conv[] = {
+ [0] = 0,
+ [1] = 1,
+ [2] = 2,
+ [3] = 3,
+ [4] = 3
+ };
+ int acpi_state = state_conv[(int __force) state];
+
+ if (!handle)
+ return -ENODEV;
+ return acpi_bus_set_power(handle, acpi_state);
+}
+
+
+/* ACPI bus type */
+static int pci_acpi_find_device(struct device *dev, acpi_handle *handle)
+{
+ struct pci_dev * pci_dev;
+ acpi_integer addr;
+
+ pci_dev = to_pci_dev(dev);
+ /* Please ref to ACPI spec for the syntax of _ADR */
+ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
+ *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+ if (!*handle)
+ return -ENODEV;
+ return 0;
+}
+
+static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle)
+{
+ int num;
+ unsigned int seg, bus;
+
+ /*
+ * The string should be the same as root bridge's name
+ * Please look at 'pci_scan_bus_parented'
+ */
+ num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus);
+ if (num != 2)
+ return -ENODEV;
+ *handle = acpi_get_pci_rootbridge_handle(seg, bus);
+ if (!*handle)
+ return -ENODEV;
+ return 0;
+}
+
+static struct acpi_bus_type pci_acpi_bus = {
+ .bus = &pci_bus_type,
+ .find_device = pci_acpi_find_device,
+ .find_bridge = pci_acpi_find_root_bridge,
+};
+
+static int __init pci_acpi_init(void)
+{
+ int ret;
+
+ ret = register_acpi_bus_type(&pci_acpi_bus);
+ if (ret)
+ return 0;
+ platform_pci_choose_state = acpi_pci_choose_state;
+ platform_pci_set_power_state = acpi_pci_set_power_state;
+ return 0;
+}
+arch_initcall(pci_acpi_init);
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index e65bf2b395aa..e4115a0d5ba6 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -7,7 +7,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/device.h>
-#include <linux/pci-dynids.h>
#include "pci.h"
/*
@@ -18,36 +17,12 @@
* Dynamic device IDs are disabled for !CONFIG_HOTPLUG
*/
-#ifdef CONFIG_HOTPLUG
-/**
- * pci_device_probe_dynamic()
- *
- * Walk the dynamic ID list looking for a match.
- * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
- */
-static int
-pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
-{
- int error = -ENODEV;
- struct list_head *pos;
- struct dynid *dynid;
+struct pci_dynid {
+ struct list_head node;
+ struct pci_device_id id;
+};
- spin_lock(&drv->dynids.lock);
- list_for_each(pos, &drv->dynids.list) {
- dynid = list_entry(pos, struct dynid, node);
- if (pci_match_one_device(&dynid->id, pci_dev)) {
- spin_unlock(&drv->dynids.lock);
- error = drv->probe(pci_dev, &dynid->id);
- if (error >= 0) {
- pci_dev->driver = drv;
- return 0;
- }
- return error;
- }
- }
- spin_unlock(&drv->dynids.lock);
- return error;
-}
+#ifdef CONFIG_HOTPLUG
/**
* store_new_id
@@ -58,8 +33,7 @@ pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
static inline ssize_t
store_new_id(struct device_driver *driver, const char *buf, size_t count)
{
- struct dynid *dynid;
- struct bus_type * bus;
+ struct pci_dynid *dynid;
struct pci_driver *pdrv = to_pci_driver(driver);
__u32 vendor=PCI_ANY_ID, device=PCI_ANY_ID, subvendor=PCI_ANY_ID,
subdevice=PCI_ANY_ID, class=0, class_mask=0;
@@ -91,37 +65,22 @@ store_new_id(struct device_driver *driver, const char *buf, size_t count)
list_add_tail(&pdrv->dynids.list, &dynid->node);
spin_unlock(&pdrv->dynids.lock);
- bus = get_bus(pdrv->driver.bus);
- if (bus) {
- if (get_driver(&pdrv->driver)) {
- down_write(&bus->subsys.rwsem);
- driver_attach(&pdrv->driver);
- up_write(&bus->subsys.rwsem);
- put_driver(&pdrv->driver);
- }
- put_bus(bus);
+ if (get_driver(&pdrv->driver)) {
+ driver_attach(&pdrv->driver);
+ put_driver(&pdrv->driver);
}
return count;
}
-
static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
-static inline void
-pci_init_dynids(struct pci_dynids *dynids)
-{
- spin_lock_init(&dynids->lock);
- INIT_LIST_HEAD(&dynids->list);
-}
static void
pci_free_dynids(struct pci_driver *drv)
{
- struct list_head *pos, *n;
- struct dynid *dynid;
+ struct pci_dynid *dynid, *n;
spin_lock(&drv->dynids.lock);
- list_for_each_safe(pos, n, &drv->dynids.list) {
- dynid = list_entry(pos, struct dynid, node);
+ list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
list_del(&dynid->node);
kfree(dynid);
}
@@ -138,83 +97,70 @@ pci_create_newid_file(struct pci_driver *drv)
return error;
}
-static int
-pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
-{
- struct list_head *pos;
- struct dynid *dynid;
-
- spin_lock(&pci_drv->dynids.lock);
- list_for_each(pos, &pci_drv->dynids.list) {
- dynid = list_entry(pos, struct dynid, node);
- if (pci_match_one_device(&dynid->id, pci_dev)) {
- spin_unlock(&pci_drv->dynids.lock);
- return 1;
- }
- }
- spin_unlock(&pci_drv->dynids.lock);
- return 0;
-}
-
#else /* !CONFIG_HOTPLUG */
-static inline int pci_device_probe_dynamic(struct pci_driver *drv, struct pci_dev *pci_dev)
-{
- return -ENODEV;
-}
-static inline void pci_init_dynids(struct pci_dynids *dynids) {}
static inline void pci_free_dynids(struct pci_driver *drv) {}
static inline int pci_create_newid_file(struct pci_driver *drv)
{
return 0;
}
-static inline int pci_bus_match_dynids(const struct pci_dev *pci_dev, struct pci_driver *pci_drv)
-{
- return 0;
-}
#endif
/**
- * pci_match_device - Tell if a PCI device structure has a matching
- * PCI device id structure
+ * pci_match_id - See if a pci device matches a given pci_id table
* @ids: array of PCI device id structures to search in
- * @dev: the PCI device structure to match against
- *
+ * @dev: the PCI device structure to match against.
+ *
* Used by a driver to check whether a PCI device present in the
- * system is in its list of supported devices.Returns the matching
+ * system is in its list of supported devices. Returns the matching
* pci_device_id structure or %NULL if there is no match.
+ *
+ * Depreciated, don't use this as it will not catch any dynamic ids
+ * that a driver might want to check for.
*/
-const struct pci_device_id *
-pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev)
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
+ struct pci_dev *dev)
{
- while (ids->vendor || ids->subvendor || ids->class_mask) {
- if (pci_match_one_device(ids, dev))
- return ids;
- ids++;
+ if (ids) {
+ while (ids->vendor || ids->subvendor || ids->class_mask) {
+ if (pci_match_one_device(ids, dev))
+ return ids;
+ ids++;
+ }
}
return NULL;
}
/**
- * pci_device_probe_static()
- *
- * returns 0 and sets pci_dev->driver when drv claims pci_dev, else error.
+ * pci_match_device - Tell if a PCI device structure has a matching
+ * PCI device id structure
+ * @ids: array of PCI device id structures to search in
+ * @dev: the PCI device structure to match against
+ * @drv: the PCI driver to match against
+ *
+ * Used by a driver to check whether a PCI device present in the
+ * system is in its list of supported devices. Returns the matching
+ * pci_device_id structure or %NULL if there is no match.
*/
-static int
-pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
-{
- int error = -ENODEV;
+const struct pci_device_id *pci_match_device(struct pci_driver *drv,
+ struct pci_dev *dev)
+{
const struct pci_device_id *id;
+ struct pci_dynid *dynid;
- if (!drv->id_table)
- return error;
- id = pci_match_device(drv->id_table, pci_dev);
+ id = pci_match_id(drv->id_table, dev);
if (id)
- error = drv->probe(pci_dev, id);
- if (error >= 0) {
- pci_dev->driver = drv;
- error = 0;
+ return id;
+
+ /* static ids didn't match, lets look at the dynamic ones */
+ spin_lock(&drv->dynids.lock);
+ list_for_each_entry(dynid, &drv->dynids.list, node) {
+ if (pci_match_one_device(&dynid->id, dev)) {
+ spin_unlock(&drv->dynids.lock);
+ return &dynid->id;
+ }
}
- return error;
+ spin_unlock(&drv->dynids.lock);
+ return NULL;
}
/**
@@ -225,13 +171,20 @@ pci_device_probe_static(struct pci_driver *drv, struct pci_dev *pci_dev)
*/
static int
__pci_device_probe(struct pci_driver *drv, struct pci_dev *pci_dev)
-{
+{
+ const struct pci_device_id *id;
int error = 0;
if (!pci_dev->driver && drv->probe) {
- error = pci_device_probe_static(drv, pci_dev);
- if (error == -ENODEV)
- error = pci_device_probe_dynamic(drv, pci_dev);
+ error = -ENODEV;
+
+ id = pci_match_device(drv, pci_dev);
+ if (id)
+ error = drv->probe(pci_dev, id);
+ if (error >= 0) {
+ pci_dev->driver = drv;
+ error = 0;
+ }
}
return error;
}
@@ -371,12 +324,6 @@ static struct kobj_type pci_driver_kobj_type = {
.sysfs_ops = &pci_driver_sysfs_ops,
};
-static int
-pci_populate_driver_dir(struct pci_driver *drv)
-{
- return pci_create_newid_file(drv);
-}
-
/**
* pci_register_driver - register a new pci driver
* @drv: the driver structure to register
@@ -401,13 +348,15 @@ int pci_register_driver(struct pci_driver *drv)
drv->driver.shutdown = pci_device_shutdown;
drv->driver.owner = drv->owner;
drv->driver.kobj.ktype = &pci_driver_kobj_type;
- pci_init_dynids(&drv->dynids);
+
+ spin_lock_init(&drv->dynids.lock);
+ INIT_LIST_HEAD(&drv->dynids.list);
/* register with core */
error = driver_register(&drv->driver);
if (!error)
- pci_populate_driver_dir(drv);
+ error = pci_create_newid_file(drv);
return error;
}
@@ -463,21 +412,17 @@ pci_dev_driver(const struct pci_dev *dev)
* system is in its list of supported devices.Returns the matching
* pci_device_id structure or %NULL if there is no match.
*/
-static int pci_bus_match(struct device * dev, struct device_driver * drv)
+static int pci_bus_match(struct device *dev, struct device_driver *drv)
{
- const struct pci_dev * pci_dev = to_pci_dev(dev);
- struct pci_driver * pci_drv = to_pci_driver(drv);
- const struct pci_device_id * ids = pci_drv->id_table;
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct pci_driver *pci_drv = to_pci_driver(drv);
const struct pci_device_id *found_id;
- if (!ids)
- return 0;
-
- found_id = pci_match_device(ids, pci_dev);
+ found_id = pci_match_device(pci_drv, pci_dev);
if (found_id)
return 1;
- return pci_bus_match_dynids(pci_dev, pci_drv);
+ return 0;
}
/**
@@ -536,6 +481,7 @@ static int __init pci_driver_init(void)
postcore_initcall(pci_driver_init);
+EXPORT_SYMBOL(pci_match_id);
EXPORT_SYMBOL(pci_match_device);
EXPORT_SYMBOL(pci_register_driver);
EXPORT_SYMBOL(pci_unregister_driver);
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index a15f94072a6f..cc9d65388e62 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -60,15 +60,18 @@ resource_show(struct device * dev, struct device_attribute *attr, char * buf)
char * str = buf;
int i;
int max = 7;
+ u64 start, end;
if (pci_dev->subordinate)
max = DEVICE_COUNT_RESOURCE;
for (i = 0; i < max; i++) {
- str += sprintf(str,"0x%016lx 0x%016lx 0x%016lx\n",
- pci_resource_start(pci_dev,i),
- pci_resource_end(pci_dev,i),
- pci_resource_flags(pci_dev,i));
+ struct resource *res = &pci_dev->resource[i];
+ pci_resource_to_user(pci_dev, i, res, &start, &end);
+ str += sprintf(str,"0x%016llx 0x%016llx 0x%016llx\n",
+ (unsigned long long)start,
+ (unsigned long long)end,
+ (unsigned long long)res->flags);
}
return (str - buf);
}
@@ -313,8 +316,21 @@ pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
struct device, kobj));
struct resource *res = (struct resource *)attr->private;
enum pci_mmap_state mmap_type;
+ u64 start, end;
+ int i;
- vma->vm_pgoff += res->start >> PAGE_SHIFT;
+ for (i = 0; i < PCI_ROM_RESOURCE; i++)
+ if (res == &pdev->resource[i])
+ break;
+ if (i >= PCI_ROM_RESOURCE)
+ return -ENODEV;
+
+ /* pci_mmap_page_range() expects the same kind of entry as coming
+ * from /proc/bus/pci/ which is a "user visible" value. If this is
+ * different from the resource itself, arch will do necessary fixup.
+ */
+ pci_resource_to_user(pdev, i, res, &start, &end);
+ vma->vm_pgoff += start >> PAGE_SHIFT;
mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
return pci_mmap_page_range(pdev, vma, mmap_type, 0);
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index f04b9ffe4153..1b34fc56067e 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -235,7 +235,7 @@ pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
* -EIO if device does not support PCI PM.
* 0 if we can successfully change the power state.
*/
-
+int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t t);
int
pci_set_power_state(struct pci_dev *dev, pci_power_t state)
{
@@ -299,11 +299,20 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
msleep(10);
else if (state == PCI_D2 || dev->current_state == PCI_D2)
udelay(200);
- dev->current_state = state;
+ /*
+ * Give firmware a chance to be called, such as ACPI _PRx, _PSx
+ * Firmware method after natice method ?
+ */
+ if (platform_pci_set_power_state)
+ platform_pci_set_power_state(dev, state);
+
+ dev->current_state = state;
return 0;
}
+int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+
/**
* pci_choose_state - Choose the power state of a PCI device
* @dev: PCI device to be suspended
@@ -316,10 +325,17 @@ pci_set_power_state(struct pci_dev *dev, pci_power_t state)
pci_power_t pci_choose_state(struct pci_dev *dev, pm_message_t state)
{
+ int ret;
+
if (!pci_find_capability(dev, PCI_CAP_ID_PM))
return PCI_D0;
- switch (state) {
+ if (platform_pci_choose_state) {
+ ret = platform_pci_choose_state(dev, state);
+ if (ret >= 0)
+ state = ret;
+ }
+ switch (state) {
case 0: return PCI_D0;
case 3: return PCI_D3hot;
default:
@@ -334,10 +350,6 @@ EXPORT_SYMBOL(pci_choose_state);
/**
* pci_save_state - save the PCI configuration space of a device before suspending
* @dev: - PCI device that we're dealing with
- * @buffer: - buffer to hold config space context
- *
- * @buffer must be large enough to hold the entire PCI 2.2 config space
- * (>= 64 bytes).
*/
int
pci_save_state(struct pci_dev *dev)
@@ -352,8 +364,6 @@ pci_save_state(struct pci_dev *dev)
/**
* pci_restore_state - Restore the saved state of a PCI device
* @dev: - PCI device that we're dealing with
- * @buffer: - saved PCI config space
- *
*/
int
pci_restore_state(struct pci_dev *dev)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 744da0d4ae5f..d94d7af4f7a0 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -11,6 +11,10 @@ extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
void (*alignf)(void *, struct resource *,
unsigned long, unsigned long),
void *alignf_data);
+/* Firmware callbacks */
+extern int (*platform_pci_choose_state)(struct pci_dev *dev, pm_message_t state);
+extern int (*platform_pci_set_power_state)(struct pci_dev *dev, pci_power_t state);
+
/* PCI /proc functions */
#ifdef CONFIG_PROC_FS
extern int pci_proc_attach_device(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/portdrv.h b/drivers/pci/pcie/portdrv.h
index 537b372dc340..a63bd8f72601 100644
--- a/drivers/pci/pcie/portdrv.h
+++ b/drivers/pci/pcie/portdrv.h
@@ -27,6 +27,11 @@
#define get_descriptor_id(type, service) (((type - 4) << 4) | service)
+struct pcie_port_device_ext {
+ int interrupt_mode; /* [0:INTx | 1:MSI | 2:MSI-X] */
+ unsigned int saved_msi_config_space[5];
+};
+
extern struct bus_type pcie_port_bus_type;
extern int pcie_port_device_probe(struct pci_dev *dev);
extern int pcie_port_device_register(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index f5c5f10a3d2f..393e0cee91a9 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -275,10 +275,17 @@ int pcie_port_device_probe(struct pci_dev *dev)
int pcie_port_device_register(struct pci_dev *dev)
{
+ struct pcie_port_device_ext *p_ext;
int status, type, capabilities, irq_mode, i;
int vectors[PCIE_PORT_DEVICE_MAXSERVICES];
u16 reg16;
+ /* Allocate port device extension */
+ if (!(p_ext = kmalloc(sizeof(struct pcie_port_device_ext), GFP_KERNEL)))
+ return -ENOMEM;
+
+ pci_set_drvdata(dev, p_ext);
+
/* Get port type */
pci_read_config_word(dev,
pci_find_capability(dev, PCI_CAP_ID_EXP) +
@@ -288,6 +295,7 @@ int pcie_port_device_register(struct pci_dev *dev)
/* Now get port services */
capabilities = get_port_device_capability(dev);
irq_mode = assign_interrupt_mode(dev, vectors, capabilities);
+ p_ext->interrupt_mode = irq_mode;
/* Allocate child services if any */
for (i = 0; i < PCIE_PORT_DEVICE_MAXSERVICES; i++) {
@@ -317,7 +325,7 @@ int pcie_port_device_register(struct pci_dev *dev)
static int suspend_iter(struct device *dev, void *data)
{
struct pcie_port_service_driver *service_driver;
- u32 state = (u32)data;
+ pm_message_t state = * (pm_message_t *) data;
if ((dev->bus == &pcie_port_bus_type) &&
(dev->driver)) {
@@ -328,9 +336,9 @@ static int suspend_iter(struct device *dev, void *data)
return 0;
}
-int pcie_port_device_suspend(struct pci_dev *dev, u32 state)
+int pcie_port_device_suspend(struct pci_dev *dev, pm_message_t state)
{
- device_for_each_child(&dev->dev, (void *)state, suspend_iter);
+ device_for_each_child(&dev->dev, &state, suspend_iter);
return 0;
}
diff --git a/drivers/pci/pcie/portdrv_pci.c b/drivers/pci/pcie/portdrv_pci.c
index e9095ee508e3..30bac7ed7c16 100644
--- a/drivers/pci/pcie/portdrv_pci.c
+++ b/drivers/pci/pcie/portdrv_pci.c
@@ -29,6 +29,78 @@ MODULE_LICENSE("GPL");
/* global data */
static const char device_name[] = "pcieport-driver";
+static void pci_save_msi_state(struct pci_dev *dev)
+{
+ struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
+ int i = 0, pos;
+ u16 control;
+
+ if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0)
+ return;
+
+ pci_read_config_dword(dev, pos, &p_ext->saved_msi_config_space[i++]);
+ control = p_ext->saved_msi_config_space[0] >> 16;
+ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+ &p_ext->saved_msi_config_space[i++]);
+ if (control & PCI_MSI_FLAGS_64BIT) {
+ pci_read_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+ &p_ext->saved_msi_config_space[i++]);
+ pci_read_config_dword(dev, pos + PCI_MSI_DATA_64,
+ &p_ext->saved_msi_config_space[i++]);
+ } else
+ pci_read_config_dword(dev, pos + PCI_MSI_DATA_32,
+ &p_ext->saved_msi_config_space[i++]);
+ if (control & PCI_MSI_FLAGS_MASKBIT)
+ pci_read_config_dword(dev, pos + PCI_MSI_MASK_BIT,
+ &p_ext->saved_msi_config_space[i++]);
+}
+
+static void pci_restore_msi_state(struct pci_dev *dev)
+{
+ struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
+ int i = 0, pos;
+ u16 control;
+
+ if ((pos = pci_find_capability(dev, PCI_CAP_ID_MSI)) <= 0)
+ return;
+
+ control = p_ext->saved_msi_config_space[i++] >> 16;
+ pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO,
+ p_ext->saved_msi_config_space[i++]);
+ if (control & PCI_MSI_FLAGS_64BIT) {
+ pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI,
+ p_ext->saved_msi_config_space[i++]);
+ pci_write_config_dword(dev, pos + PCI_MSI_DATA_64,
+ p_ext->saved_msi_config_space[i++]);
+ } else
+ pci_write_config_dword(dev, pos + PCI_MSI_DATA_32,
+ p_ext->saved_msi_config_space[i++]);
+ if (control & PCI_MSI_FLAGS_MASKBIT)
+ pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT,
+ p_ext->saved_msi_config_space[i++]);
+}
+
+static void pcie_portdrv_save_config(struct pci_dev *dev)
+{
+ struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
+
+ pci_save_state(dev);
+ if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE)
+ pci_save_msi_state(dev);
+}
+
+static void pcie_portdrv_restore_config(struct pci_dev *dev)
+{
+ struct pcie_port_device_ext *p_ext = pci_get_drvdata(dev);
+
+ pci_restore_state(dev);
+ if (p_ext->interrupt_mode == PCIE_PORT_MSI_MODE)
+ pci_restore_msi_state(dev);
+ pci_enable_device(dev);
+ pci_set_master(dev);
+}
+
/*
* pcie_portdrv_probe - Probe PCI-Express port devices
* @dev: PCI-Express port device being probed
@@ -64,16 +136,21 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
static void pcie_portdrv_remove (struct pci_dev *dev)
{
pcie_port_device_remove(dev);
+ kfree(pci_get_drvdata(dev));
}
#ifdef CONFIG_PM
static int pcie_portdrv_suspend (struct pci_dev *dev, pm_message_t state)
{
- return pcie_port_device_suspend(dev, state);
+ int ret = pcie_port_device_suspend(dev, state);
+
+ pcie_portdrv_save_config(dev);
+ return ret;
}
static int pcie_portdrv_resume (struct pci_dev *dev)
{
+ pcie_portdrv_restore_config(dev);
return pcie_port_device_resume(dev);
}
#endif
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index fd48b201eb53..df3bdae2040f 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -239,9 +239,8 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
if (dev->transparent) {
printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev));
- for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++)
- child->resource[i] = child->parent->resource[i];
- return;
+ for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
+ child->resource[i] = child->parent->resource[i - 3];
}
for(i=0; i<3; i++)
@@ -374,8 +373,11 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de
struct pci_bus *child;
child = pci_alloc_child_bus(parent, dev, busnr);
- if (child)
+ if (child) {
+ spin_lock(&pci_bus_lock);
list_add_tail(&child->node, &parent->children);
+ spin_unlock(&pci_bus_lock);
+ }
return child;
}
@@ -395,6 +397,16 @@ static void pci_enable_crs(struct pci_dev *dev)
pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl);
}
+static void __devinit pci_fixup_parent_subordinate_busnr(struct pci_bus *child, int max)
+{
+ struct pci_bus *parent = child->parent;
+ while (parent->parent && parent->subordinate < max) {
+ parent->subordinate = max;
+ pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, max);
+ parent = parent->parent;
+ }
+}
+
unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus);
/*
@@ -411,7 +423,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
{
struct pci_bus *child;
int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
- u32 buses;
+ u32 buses, i;
u16 bctl;
pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
@@ -447,7 +459,7 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
return max;
}
- child = pci_alloc_child_bus(bus, dev, busnr);
+ child = pci_add_new_bus(bus, dev, busnr);
if (!child)
return max;
child->primary = buses & 0xFF;
@@ -470,7 +482,11 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
/* Clear errors */
pci_write_config_word(dev, PCI_STATUS, 0xffff);
- child = pci_alloc_child_bus(bus, dev, ++max);
+ /* Prevent assigning a bus number that already exists.
+ * This can happen when a bridge is hot-plugged */
+ if (pci_find_bus(pci_domain_nr(bus), max+1))
+ return max;
+ child = pci_add_new_bus(bus, dev, ++max);
buses = (buses & 0xff000000)
| ((unsigned int)(child->primary) << 0)
| ((unsigned int)(child->secondary) << 8)
@@ -492,7 +508,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
if (!is_cardbus) {
child->bridge_ctl = PCI_BRIDGE_CTL_NO_ISA;
-
+ /*
+ * Adjust subordinate busnr in parent buses.
+ * We do this before scanning for children because
+ * some devices may not be detected if the bios
+ * was lazy.
+ */
+ pci_fixup_parent_subordinate_busnr(child, max);
/* Now we can scan all subordinate buses... */
max = pci_scan_child_bus(child);
} else {
@@ -501,7 +523,12 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max
* as cards with a PCI-to-PCI bridge can be
* inserted later.
*/
- max += CARDBUS_RESERVE_BUSNR;
+ for (i=0; i<CARDBUS_RESERVE_BUSNR; i++)
+ if (pci_find_bus(pci_domain_nr(bus),
+ max+i+1))
+ break;
+ max += i;
+ pci_fixup_parent_subordinate_busnr(child, max);
}
/*
* Set the subordinate bus number to its real value.
@@ -757,7 +784,9 @@ pci_scan_single_device(struct pci_bus *bus, int devfn)
* and the bus list for fixup functions, etc.
*/
INIT_LIST_HEAD(&dev->global_list);
+ spin_lock(&pci_bus_lock);
list_add_tail(&dev->bus_list, &bus->devices);
+ spin_unlock(&pci_bus_lock);
return dev;
}
@@ -878,7 +907,9 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
pr_debug("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
goto err_out;
}
+ spin_lock(&pci_bus_lock);
list_add_tail(&b->node, &pci_root_buses);
+ spin_unlock(&pci_bus_lock);
memset(dev, 0, sizeof(*dev));
dev->parent = parent;
@@ -911,8 +942,6 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
b->subordinate = pci_scan_child_bus(b);
- pci_bus_add_devices(b);
-
return b;
sys_create_link_err:
@@ -922,7 +951,9 @@ class_dev_create_file_err:
class_dev_reg_err:
device_unregister(dev);
dev_reg_err:
+ spin_lock(&pci_bus_lock);
list_del(&b->node);
+ spin_unlock(&pci_bus_lock);
err_out:
kfree(dev);
kfree(b);
diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c
index e68bbfb1e7c3..7988fc8df3fd 100644
--- a/drivers/pci/proc.c
+++ b/drivers/pci/proc.c
@@ -355,14 +355,20 @@ static int show_device(struct seq_file *m, void *v)
dev->device,
dev->irq);
/* Here should be 7 and not PCI_NUM_RESOURCES as we need to preserve compatibility */
- for(i=0; i<7; i++)
+ for (i=0; i<7; i++) {
+ u64 start, end;
+ pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, LONG_FORMAT,
- dev->resource[i].start |
+ ((unsigned long)start) |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK));
- for(i=0; i<7; i++)
+ }
+ for (i=0; i<7; i++) {
+ u64 start, end;
+ pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
seq_printf(m, LONG_FORMAT,
dev->resource[i].start < dev->resource[i].end ?
- dev->resource[i].end - dev->resource[i].start + 1 : 0);
+ (unsigned long)(end - start) + 1 : 0);
+ }
seq_putc(m, '\t');
if (drv)
seq_printf(m, "%s", drv->name);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index 968033fd29f0..1521fd5d95cc 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -767,6 +767,7 @@ static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
if (unlikely(dev->subsystem_vendor == PCI_VENDOR_ID_ASUSTEK)) {
if (dev->device == PCI_DEVICE_ID_INTEL_82845_HB)
switch(dev->subsystem_device) {
+ case 0x8025: /* P4B-LX */
case 0x8070: /* P4B */
case 0x8088: /* P4B533 */
case 0x1626: /* L3C notebook */
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 96f077f9a659..27a294b6965d 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -18,17 +18,21 @@ static void pci_free_resources(struct pci_dev *dev)
static void pci_destroy_dev(struct pci_dev *dev)
{
- pci_proc_detach_device(dev);
- pci_remove_sysfs_dev_files(dev);
- device_unregister(&dev->dev);
+ if (!list_empty(&dev->global_list)) {
+ pci_proc_detach_device(dev);
+ pci_remove_sysfs_dev_files(dev);
+ device_unregister(&dev->dev);
+ spin_lock(&pci_bus_lock);
+ list_del(&dev->global_list);
+ dev->global_list.next = dev->global_list.prev = NULL;
+ spin_unlock(&pci_bus_lock);
+ }
/* Remove the device from the device lists, and prevent any further
* list accesses from this device */
spin_lock(&pci_bus_lock);
list_del(&dev->bus_list);
- list_del(&dev->global_list);
dev->bus_list.next = dev->bus_list.prev = NULL;
- dev->global_list.next = dev->global_list.prev = NULL;
spin_unlock(&pci_bus_lock);
pci_free_resources(dev);
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index a90a533eba0f..05fa91a31c62 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -379,6 +379,7 @@ exit:
EXPORT_SYMBOL(pci_dev_present);
EXPORT_SYMBOL(pci_find_bus);
+EXPORT_SYMBOL(pci_find_next_bus);
EXPORT_SYMBOL(pci_find_device);
EXPORT_SYMBOL(pci_find_device_reverse);
EXPORT_SYMBOL(pci_find_slot);
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 1ba84be0b4c0..9fe48f712be9 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -72,7 +72,11 @@ pbus_assign_resources_sorted(struct pci_bus *bus)
for (list = head.next; list;) {
res = list->res;
idx = res - &list->dev->resource[0];
- pci_assign_resource(list->dev, idx);
+ if (pci_assign_resource(list->dev, idx)) {
+ res->start = 0;
+ res->end = 0;
+ res->flags = 0;
+ }
tmp = list;
list = list->next;
kfree(tmp);
@@ -270,6 +274,8 @@ find_free_bus_resource(struct pci_bus *bus, unsigned long type)
for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
r = bus->resource[i];
+ if (r == &ioport_resource || r == &iomem_resource)
+ continue;
if (r && (r->flags & type_mask) == type && !r->parent)
return r;
}
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 14e4124e1523..6485f75d2fb3 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -1,8 +1,5 @@
#
-# PCMCIA bus subsystem configuration
-#
-# Right now the non-CardBus choices are not supported
-# by the integrated kernel driver.
+# PCCARD (PCMCIA/CardBus) bus subsystem configuration
#
menu "PCCARD (PCMCIA/CardBus) support"
@@ -14,8 +11,8 @@ config PCCARD
Say Y here if you want to attach PCMCIA- or PC-cards to your Linux
computer. These are credit-card size devices such as network cards,
modems or hard drives often used with laptops computers. There are
- actually two varieties of these cards: the older 16 bit PCMCIA cards
- and the newer 32 bit CardBus cards.
+ actually two varieties of these cards: 16 bit PCMCIA and 32 bit
+ CardBus cards.
To compile this driver as modules, choose M here: the
module will be called pcmcia_core.
@@ -32,7 +29,7 @@ config PCMCIA_DEBUG
The kernel command line options are:
pcmcia_core.pc_debug=N
- ds.pc_debug=N
+ pcmcia.pc_debug=N
sa11xx_core.pc_debug=N
The module option is called pc_debug=N
@@ -42,22 +39,50 @@ config PCMCIA_DEBUG
config PCMCIA
tristate "16-bit PCMCIA support"
+ select CRC32
default y
---help---
This option enables support for 16-bit PCMCIA cards. Most older
PC-cards are such 16-bit PCMCIA cards, so unless you know you're
only using 32-bit CardBus cards, say Y or M here.
- To use 16-bit PCMCIA cards, you will need supporting software from
- David Hinds' pcmcia-cs package (see the file <file:Documentation/Changes>
- for location). Please also read the PCMCIA-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>.
+ To use 16-bit PCMCIA cards, you will need supporting software in
+ most cases. (see the file <file:Documentation/Changes> for
+ location and details).
To compile this driver as modules, choose M here: the
module will be called pcmcia.
If unsure, say Y.
+config PCMCIA_LOAD_CIS
+ bool "Load CIS updates from userspace (EXPERIMENTAL)"
+ depends on PCMCIA && EXPERIMENTAL
+ select FW_LOADER
+ default y
+ help
+ Some PCMCIA cards require an updated Card Information Structure (CIS)
+ to be loaded from userspace to work correctly. If you say Y here,
+ and your userspace is arranged correctly, this will be loaded
+ automatically using the in-kernel firmware loader and the hotplug
+ subsystem, instead of relying on cardmgr from pcmcia-cs to do so.
+
+ If unsure, say Y.
+
+config PCMCIA_IOCTL
+ bool "PCMCIA control ioctl (obsolete)"
+ depends on PCMCIA
+ default y
+ help
+ If you say Y here, the deprecated ioctl interface to the PCMCIA
+ subsystem will be built. It is needed by cardmgr and cardctl
+ (pcmcia-cs) to function properly.
+
+ You should use the new pcmciautils package instead (see
+ <file:Documentation/Changes> for location and details).
+
+ If unsure, say Y.
+
config CARDBUS
bool "32-bit CardBus support"
depends on PCI
@@ -78,8 +103,7 @@ comment "PC-card bridges"
config YENTA
tristate "CardBus yenta-compatible bridge support"
depends on PCI
-#fixme: remove dependendcy on CARDBUS
- depends on CARDBUS
+ select CARDBUS if !EMBEDDED
select PCCARD_NONSTATIC
---help---
This option enables support for CardBus host bridges. Virtually
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 50c29361bc5f..ef694c74dfb7 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -10,7 +10,8 @@ pcmcia_core-y += cs.o cistpl.o rsrc_mgr.o socket_sysfs.o
pcmcia_core-$(CONFIG_CARDBUS) += cardbus.o
obj-$(CONFIG_PCCARD) += pcmcia_core.o
-pcmcia-y += ds.o pcmcia_compat.o
+pcmcia-y += ds.o pcmcia_compat.o pcmcia_resource.o
+pcmcia-$(CONFIG_PCMCIA_IOCTL) += pcmcia_ioctl.o
obj-$(CONFIG_PCMCIA) += pcmcia.o
obj-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o
diff --git a/drivers/pcmcia/au1000_generic.h b/drivers/pcmcia/au1000_generic.h
index 417bc1500bad..d5122b1ea94b 100644
--- a/drivers/pcmcia/au1000_generic.h
+++ b/drivers/pcmcia/au1000_generic.h
@@ -22,7 +22,6 @@
#define __ASM_AU1000_PCMCIA_H
/* include the world */
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_pb1x00.c b/drivers/pcmcia/au1000_pb1x00.c
index df19ce1ea4f3..d414a3bb50b9 100644
--- a/drivers/pcmcia/au1000_pb1x00.c
+++ b/drivers/pcmcia/au1000_pb1x00.c
@@ -33,7 +33,6 @@
#include <linux/version.h>
#include <linux/types.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/au1000_xxs1500.c b/drivers/pcmcia/au1000_xxs1500.c
index 1dfc77653660..f113b69d699b 100644
--- a/drivers/pcmcia/au1000_xxs1500.c
+++ b/drivers/pcmcia/au1000_xxs1500.c
@@ -38,7 +38,6 @@
#include <linux/version.h>
#include <linux/types.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/cardbus.c b/drivers/pcmcia/cardbus.c
index 3ccb5247ec50..1d755e20880c 100644
--- a/drivers/pcmcia/cardbus.c
+++ b/drivers/pcmcia/cardbus.c
@@ -31,7 +31,6 @@
#include <asm/io.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index e29a6ddf2fd7..dd7651ff5b43 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -89,8 +89,10 @@ static void __iomem *
set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flags)
{
pccard_mem_map *mem = &s->cis_mem;
+ int ret;
+
if (!(s->features & SS_CAP_STATIC_MAP) && mem->res == NULL) {
- mem->res = find_mem_region(0, s->map_size, s->map_size, 0, s);
+ mem->res = pcmcia_find_mem_region(0, s->map_size, s->map_size, 0, s);
if (mem->res == NULL) {
printk(KERN_NOTICE "cs: unable to map card memory!\n");
return NULL;
@@ -99,7 +101,12 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
}
mem->card_start = card_offset;
mem->flags = flags;
- s->ops->set_mem_map(s, mem);
+ ret = s->ops->set_mem_map(s, mem);
+ if (ret) {
+ iounmap(s->cis_virt);
+ return NULL;
+ }
+
if (s->features & SS_CAP_STATIC_MAP) {
if (s->cis_virt)
iounmap(s->cis_virt);
@@ -119,13 +126,13 @@ set_cis_map(struct pcmcia_socket *s, unsigned int card_offset, unsigned int flag
#define IS_ATTR 1
#define IS_INDIRECT 8
-int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
{
void __iomem *sys, *end;
unsigned char *buf = ptr;
- cs_dbg(s, 3, "read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+ cs_dbg(s, 3, "pcmcia_read_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
@@ -182,14 +189,16 @@ int read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
*(u_char *)(ptr+2), *(u_char *)(ptr+3));
return 0;
}
+EXPORT_SYMBOL(pcmcia_read_cis_mem);
+
-void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
u_int len, void *ptr)
{
void __iomem *sys, *end;
unsigned char *buf = ptr;
- cs_dbg(s, 3, "write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+ cs_dbg(s, 3, "pcmcia_write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
if (attr & IS_INDIRECT) {
/* Indirect accesses use a bunch of special registers at fixed
@@ -239,6 +248,8 @@ void write_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
}
}
}
+EXPORT_SYMBOL(pcmcia_write_cis_mem);
+
/*======================================================================
@@ -274,7 +285,7 @@ static void read_cis_cache(struct pcmcia_socket *s, int attr, u_int addr,
ret = read_cb_mem(s, attr, addr, len, ptr);
else
#endif
- ret = read_cis_mem(s, attr, addr, len, ptr);
+ ret = pcmcia_read_cis_mem(s, attr, addr, len, ptr);
if (ret == 0) {
/* Copy data into the cache */
@@ -348,7 +359,7 @@ int verify_cis_cache(struct pcmcia_socket *s)
read_cb_mem(s, cis->attr, cis->addr, len, buf);
else
#endif
- read_cis_mem(s, cis->attr, cis->addr, len, buf);
+ pcmcia_read_cis_mem(s, cis->attr, cis->addr, len, buf);
if (memcmp(buf, cis->cache, len) != 0) {
kfree(buf);
@@ -381,6 +392,7 @@ int pcmcia_replace_cis(struct pcmcia_socket *s, cisdump_t *cis)
memcpy(s->fake_cis, cis->Data, cis->Length);
return CS_SUCCESS;
}
+EXPORT_SYMBOL(pcmcia_replace_cis);
/*======================================================================
diff --git a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
index d136b3c8fac9..e39178fc59d0 100644
--- a/drivers/pcmcia/cs.c
+++ b/drivers/pcmcia/cs.c
@@ -33,7 +33,6 @@
#include <asm/irq.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -43,36 +42,11 @@
#include <pcmcia/ds.h>
#include "cs_internal.h"
-#ifdef CONFIG_PCI
-#define PCI_OPT " [pci]"
-#else
-#define PCI_OPT ""
-#endif
-#ifdef CONFIG_CARDBUS
-#define CB_OPT " [cardbus]"
-#else
-#define CB_OPT ""
-#endif
-#ifdef CONFIG_PM
-#define PM_OPT " [pm]"
-#else
-#define PM_OPT ""
-#endif
-#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && !defined(CONFIG_PM)
-#define OPTIONS " none"
-#else
-#define OPTIONS PCI_OPT CB_OPT PM_OPT
-#endif
-
-static const char *release = "Linux Kernel Card Services";
-static const char *options = "options: " OPTIONS;
-
-/*====================================================================*/
/* Module parameters */
MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
-MODULE_DESCRIPTION("Linux Kernel Card Services\noptions:" OPTIONS);
+MODULE_DESCRIPTION("Linux Kernel Card Services");
MODULE_LICENSE("GPL");
#define INT_MODULE_PARM(n, v) static int n = v; module_param(n, int, 0444)
@@ -89,9 +63,6 @@ INT_MODULE_PARM(unreset_limit, 30); /* unreset_check's */
/* Access speed for attribute memory windows */
INT_MODULE_PARM(cis_speed, 300); /* ns */
-/* Access speed for IO windows */
-INT_MODULE_PARM(io_speed, 0); /* ns */
-
#ifdef DEBUG
static int pc_debug;
@@ -103,34 +74,26 @@ int cs_debug_level(int level)
}
#endif
-/*====================================================================*/
socket_state_t dead_socket = {
.csc_mask = SS_DETECT,
};
+EXPORT_SYMBOL(dead_socket);
/* List of all sockets, protected by a rwsem */
LIST_HEAD(pcmcia_socket_list);
-DECLARE_RWSEM(pcmcia_socket_list_rwsem);
EXPORT_SYMBOL(pcmcia_socket_list);
-EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
-
-#ifdef CONFIG_PCMCIA_PROBE
-/* mask ofIRQs already reserved by other cards, we should avoid using them */
-static u8 pcmcia_used_irq[NR_IRQS];
-#endif
-
-/*====================================================================
+DECLARE_RWSEM(pcmcia_socket_list_rwsem);
+EXPORT_SYMBOL(pcmcia_socket_list_rwsem);
- Low-level PC Card interface drivers need to register with Card
- Services using these calls.
-
-======================================================================*/
/**
- * socket drivers are expected to use the following callbacks in their
+ * Low-level PCMCIA socket drivers need to register with the PCCard
+ * core using pcmcia_register_socket.
+ *
+ * socket drivers are expected to use the following callbacks in their
* .drv struct:
* - pcmcia_socket_dev_suspend
* - pcmcia_socket_dev_resume
@@ -230,8 +193,8 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
}
/* try to obtain a socket number [yes, it gets ugly if we
- * register more than 2^sizeof(unsigned int) pcmcia
- * sockets... but the socket number is deprecated
+ * register more than 2^sizeof(unsigned int) pcmcia
+ * sockets... but the socket number is deprecated
* anyways, so I don't care] */
down_write(&pcmcia_socket_list_rwsem);
if (list_empty(&pcmcia_socket_list))
@@ -252,6 +215,13 @@ int pcmcia_register_socket(struct pcmcia_socket *socket)
list_add_tail(&socket->socket_list, &pcmcia_socket_list);
up_write(&pcmcia_socket_list_rwsem);
+#ifndef CONFIG_CARDBUS
+ /*
+ * If we do not support Cardbus, ensure that
+ * the Cardbus socket capability is disabled.
+ */
+ socket->features &= ~SS_CAP_CARDBUS;
+#endif
/* set proper values in socket->dev */
socket->dev.class_data = socket;
@@ -340,54 +310,49 @@ struct pcmcia_socket * pcmcia_get_socket_by_nr(unsigned int nr)
EXPORT_SYMBOL(pcmcia_get_socket_by_nr);
-/*======================================================================
-
- socket_setup() and shutdown_socket() are called by the main event
- handler when card insertion and removal events are received.
- socket_setup() turns on socket power and resets the socket, in two stages.
- shutdown_socket() unconfigures a socket and turns off socket power.
-
-======================================================================*/
-
+/**
+ * socket_setup() and shutdown_socket() are called by the main event
+ * handler when card insertion and removal events are received.
+ * socket_setup() turns on socket power and resets the socket, in two stages.
+ * shutdown_socket() unconfigures a socket and turns off socket power.
+ */
static void shutdown_socket(struct pcmcia_socket *s)
{
- cs_dbg(s, 1, "shutdown_socket\n");
-
- /* Blank out the socket state */
- s->socket = dead_socket;
- s->ops->init(s);
- s->ops->set_socket(s, &s->socket);
- s->irq.AssignedIRQ = s->irq.Config = 0;
- s->lock_count = 0;
- destroy_cis_cache(s);
+ cs_dbg(s, 1, "shutdown_socket\n");
+
+ /* Blank out the socket state */
+ s->socket = dead_socket;
+ s->ops->init(s);
+ s->ops->set_socket(s, &s->socket);
+ s->irq.AssignedIRQ = s->irq.Config = 0;
+ s->lock_count = 0;
+ destroy_cis_cache(s);
#ifdef CONFIG_CARDBUS
- cb_free(s);
+ cb_free(s);
#endif
- s->functions = 0;
- if (s->config) {
- kfree(s->config);
- s->config = NULL;
- }
-
- {
- int status;
- s->ops->get_status(s, &status);
- if (status & SS_POWERON) {
- printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+ s->functions = 0;
+ if (s->config) {
+ kfree(s->config);
+ s->config = NULL;
}
- }
-} /* shutdown_socket */
-/*======================================================================
+ {
+ int status;
+ s->ops->get_status(s, &status);
+ if (status & SS_POWERON) {
+ printk(KERN_ERR "PCMCIA: socket %p: *** DANGER *** unable to remove socket power\n", s);
+ }
+ }
+} /* shutdown_socket */
- The central event handler. Send_event() sends an event to the
- 16-bit subsystem, which then calls the relevant device drivers.
- Parse_events() interprets the event bits from
- a card status change report. Do_shutdown() handles the high
- priority stuff associated with a card removal.
-
-======================================================================*/
+/**
+ * The central event handler. Send_event() sends an event to the
+ * 16-bit subsystem, which then calls the relevant device drivers.
+ * Parse_events() interprets the event bits from
+ * a card status change report. Do_shutdown() handles the high
+ * priority stuff associated with a card removal.
+ */
/* NOTE: send_event needs to be called with skt->sem held. */
@@ -490,11 +455,11 @@ static int socket_setup(struct pcmcia_socket *skt, int initial_delay)
}
if (status & SS_CARDBUS) {
+ if (!(skt->features & SS_CAP_CARDBUS)) {
+ cs_err(skt, "cardbus cards are not supported.\n");
+ return CS_BAD_TYPE;
+ }
skt->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
- cs_err(skt, "cardbus cards are not supported.\n");
- return CS_BAD_TYPE;
-#endif
}
/*
@@ -718,7 +683,7 @@ static int pccardd(void *__skt)
}
schedule();
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
if (!skt->thread)
break;
@@ -746,420 +711,9 @@ void pcmcia_parse_events(struct pcmcia_socket *s, u_int events)
wake_up(&s->thread_wait);
}
} /* pcmcia_parse_events */
+EXPORT_SYMBOL(pcmcia_parse_events);
-/*======================================================================
-
- Special stuff for managing IO windows, because they are scarce.
-
-======================================================================*/
-
-static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
- ioaddr_t num, u_int lines)
-{
- int i;
- kio_addr_t try, align;
-
- align = (*base) ? (lines ? 1<<lines : 0) : 1;
- if (align && (align < num)) {
- if (*base) {
- cs_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
- num, align);
- align = 0;
- } else
- while (align && (align < num)) align <<= 1;
- }
- if (*base & ~(align-1)) {
- cs_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
- *base, align);
- align = 0;
- }
- if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
- *base = s->io_offset | (*base & 0x0fff);
- return 0;
- }
- /* Check for an already-allocated window that must conflict with
- what was asked for. It is a hack because it does not catch all
- potential conflicts, just the most obvious ones. */
- for (i = 0; i < MAX_IO_WIN; i++)
- if ((s->io[i].NumPorts != 0) &&
- ((s->io[i].BasePort & (align-1)) == *base))
- return 1;
- for (i = 0; i < MAX_IO_WIN; i++) {
- if (s->io[i].NumPorts == 0) {
- s->io[i].res = find_io_region(*base, num, align, s);
- if (s->io[i].res) {
- s->io[i].Attributes = attr;
- s->io[i].BasePort = *base = s->io[i].res->start;
- s->io[i].NumPorts = s->io[i].InUse = num;
- break;
- } else
- return 1;
- } else if (s->io[i].Attributes != attr)
- continue;
- /* Try to extend top of window */
- try = s->io[i].BasePort + s->io[i].NumPorts;
- if ((*base == 0) || (*base == try))
- if (adjust_io_region(s->io[i].res, s->io[i].res->start,
- s->io[i].res->end + num, s) == 0) {
- *base = try;
- s->io[i].NumPorts += num;
- s->io[i].InUse += num;
- break;
- }
- /* Try to extend bottom of window */
- try = s->io[i].BasePort - num;
- if ((*base == 0) || (*base == try))
- if (adjust_io_region(s->io[i].res, s->io[i].res->start - num,
- s->io[i].res->end, s) == 0) {
- s->io[i].BasePort = *base = try;
- s->io[i].NumPorts += num;
- s->io[i].InUse += num;
- break;
- }
- }
- return (i == MAX_IO_WIN);
-} /* alloc_io_space */
-
-static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
- ioaddr_t num)
-{
- int i;
-
- for (i = 0; i < MAX_IO_WIN; i++) {
- if ((s->io[i].BasePort <= base) &&
- (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
- s->io[i].InUse -= num;
- /* Free the window if no one else is using it */
- if (s->io[i].InUse == 0) {
- s->io[i].NumPorts = 0;
- release_resource(s->io[i].res);
- kfree(s->io[i].res);
- s->io[i].res = NULL;
- }
- }
- }
-}
-
-/*======================================================================
-
- Access_configuration_register() reads and writes configuration
- registers in attribute memory. Memory window 0 is reserved for
- this and the tuple reading services.
-
-======================================================================*/
-
-int pccard_access_configuration_register(struct pcmcia_socket *s,
- unsigned int function,
- conf_reg_t *reg)
-{
- config_t *c;
- int addr;
- u_char val;
-
- if (!s || !s->config)
- return CS_NO_CARD;
-
- c = &s->config[function];
-
- if (c == NULL)
- return CS_NO_CARD;
-
- if (!(c->state & CONFIG_LOCKED))
- return CS_CONFIGURATION_LOCKED;
-
- addr = (c->ConfigBase + reg->Offset) >> 1;
-
- switch (reg->Action) {
- case CS_READ:
- read_cis_mem(s, 1, addr, 1, &val);
- reg->Value = val;
- break;
- case CS_WRITE:
- val = reg->Value;
- write_cis_mem(s, 1, addr, 1, &val);
- break;
- default:
- return CS_BAD_ARGS;
- break;
- }
- return CS_SUCCESS;
-} /* access_configuration_register */
-EXPORT_SYMBOL(pccard_access_configuration_register);
-
-
-/*====================================================================*/
-
-int pccard_get_configuration_info(struct pcmcia_socket *s,
- unsigned int function,
- config_info_t *config)
-{
- config_t *c;
-
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
-
- config->Function = function;
-
-#ifdef CONFIG_CARDBUS
- if (s->state & SOCKET_CARDBUS) {
- memset(config, 0, sizeof(config_info_t));
- config->Vcc = s->socket.Vcc;
- config->Vpp1 = config->Vpp2 = s->socket.Vpp;
- config->Option = s->cb_dev->subordinate->number;
- if (s->state & SOCKET_CARDBUS_CONFIG) {
- config->Attributes = CONF_VALID_CLIENT;
- config->IntType = INT_CARDBUS;
- config->AssignedIRQ = s->irq.AssignedIRQ;
- if (config->AssignedIRQ)
- config->Attributes |= CONF_ENABLE_IRQ;
- config->BasePort1 = s->io[0].BasePort;
- config->NumPorts1 = s->io[0].NumPorts;
- }
- return CS_SUCCESS;
- }
-#endif
-
- c = (s->config != NULL) ? &s->config[function] : NULL;
-
- if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
- config->Attributes = 0;
- config->Vcc = s->socket.Vcc;
- config->Vpp1 = config->Vpp2 = s->socket.Vpp;
- return CS_SUCCESS;
- }
-
- /* !!! This is a hack !!! */
- memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
- config->Attributes |= CONF_VALID_CLIENT;
- config->CardValues = c->CardValues;
- config->IRQAttributes = c->irq.Attributes;
- config->AssignedIRQ = s->irq.AssignedIRQ;
- config->BasePort1 = c->io.BasePort1;
- config->NumPorts1 = c->io.NumPorts1;
- config->Attributes1 = c->io.Attributes1;
- config->BasePort2 = c->io.BasePort2;
- config->NumPorts2 = c->io.NumPorts2;
- config->Attributes2 = c->io.Attributes2;
- config->IOAddrLines = c->io.IOAddrLines;
-
- return CS_SUCCESS;
-} /* get_configuration_info */
-EXPORT_SYMBOL(pccard_get_configuration_info);
-
-/*======================================================================
-
- Return information about this version of Card Services.
-
-======================================================================*/
-
-int pcmcia_get_card_services_info(servinfo_t *info)
-{
- unsigned int socket_count = 0;
- struct list_head *tmp;
- info->Signature[0] = 'C';
- info->Signature[1] = 'S';
- down_read(&pcmcia_socket_list_rwsem);
- list_for_each(tmp, &pcmcia_socket_list)
- socket_count++;
- up_read(&pcmcia_socket_list_rwsem);
- info->Count = socket_count;
- info->Revision = CS_RELEASE_CODE;
- info->CSLevel = 0x0210;
- info->VendorString = (char *)release;
- return CS_SUCCESS;
-} /* get_card_services_info */
-
-
-/*====================================================================*/
-
-int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle, int idx, win_req_t *req)
-{
- window_t *win;
- int w;
-
- if (!s || !(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- for (w = idx; w < MAX_WIN; w++)
- if (s->state & SOCKET_WIN_REQ(w)) break;
- if (w == MAX_WIN)
- return CS_NO_MORE_ITEMS;
- win = &s->win[w];
- req->Base = win->ctl.res->start;
- req->Size = win->ctl.res->end - win->ctl.res->start + 1;
- req->AccessSpeed = win->ctl.speed;
- req->Attributes = 0;
- if (win->ctl.flags & MAP_ATTRIB)
- req->Attributes |= WIN_MEMORY_TYPE_AM;
- if (win->ctl.flags & MAP_ACTIVE)
- req->Attributes |= WIN_ENABLE;
- if (win->ctl.flags & MAP_16BIT)
- req->Attributes |= WIN_DATA_WIDTH_16;
- if (win->ctl.flags & MAP_USE_WAIT)
- req->Attributes |= WIN_USE_WAIT;
- *handle = win;
- return CS_SUCCESS;
-} /* get_window */
-EXPORT_SYMBOL(pcmcia_get_window);
-
-/*=====================================================================
-
- Return the PCI device associated with a card..
-
-======================================================================*/
-
-#ifdef CONFIG_CARDBUS
-
-struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
-{
- if (!s || !(s->state & SOCKET_CARDBUS))
- return NULL;
-
- return s->cb_dev->subordinate;
-}
-
-EXPORT_SYMBOL(pcmcia_lookup_bus);
-
-#endif
-
-/*======================================================================
-
- Get the current socket state bits. We don't support the latched
- SocketState yet: I haven't seen any point for it.
-
-======================================================================*/
-
-int pccard_get_status(struct pcmcia_socket *s, unsigned int function, cs_status_t *status)
-{
- config_t *c;
- int val;
-
- s->ops->get_status(s, &val);
- status->CardState = status->SocketState = 0;
- status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
- status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
- status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
- status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
- if (s->state & SOCKET_SUSPEND)
- status->CardState |= CS_EVENT_PM_SUSPEND;
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
-
- c = (s->config != NULL) ? &s->config[function] : NULL;
- if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
- (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
- u_char reg;
- if (c->Present & PRESENT_PIN_REPLACE) {
- read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
- status->CardState |=
- (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
- status->CardState |=
- (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
- status->CardState |=
- (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
- status->CardState |=
- (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
- } else {
- /* No PRR? Then assume we're always ready */
- status->CardState |= CS_EVENT_READY_CHANGE;
- }
- if (c->Present & PRESENT_EXT_STATUS) {
- read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
- status->CardState |=
- (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
- }
- return CS_SUCCESS;
- }
- status->CardState |=
- (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
- status->CardState |=
- (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
- status->CardState |=
- (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
- status->CardState |=
- (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
- return CS_SUCCESS;
-} /* get_status */
-EXPORT_SYMBOL(pccard_get_status);
-
-/*======================================================================
-
- Change the card address of an already open memory window.
-
-======================================================================*/
-
-int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
-{
- if ((win == NULL) || (win->magic != WINDOW_MAGIC))
- return CS_BAD_HANDLE;
- req->Page = 0;
- req->CardOffset = win->ctl.card_start;
- return CS_SUCCESS;
-} /* get_mem_page */
-
-int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
-{
- struct pcmcia_socket *s;
- if ((win == NULL) || (win->magic != WINDOW_MAGIC))
- return CS_BAD_HANDLE;
- if (req->Page != 0)
- return CS_BAD_PAGE;
- s = win->sock;
- win->ctl.card_start = req->CardOffset;
- if (s->ops->set_mem_map(s, &win->ctl) != 0)
- return CS_BAD_OFFSET;
- return CS_SUCCESS;
-} /* map_mem_page */
-
-/*======================================================================
-
- Modify a locked socket configuration
-
-======================================================================*/
-
-int pcmcia_modify_configuration(client_handle_t handle,
- modconf_t *mod)
-{
- struct pcmcia_socket *s;
- config_t *c;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle); c = CONFIG(handle);
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (!(c->state & CONFIG_LOCKED))
- return CS_CONFIGURATION_LOCKED;
-
- if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
- if (mod->Attributes & CONF_ENABLE_IRQ) {
- c->Attributes |= CONF_ENABLE_IRQ;
- s->socket.io_irq = s->irq.AssignedIRQ;
- } else {
- c->Attributes &= ~CONF_ENABLE_IRQ;
- s->socket.io_irq = 0;
- }
- s->ops->set_socket(s, &s->socket);
- }
-
- if (mod->Attributes & CONF_VCC_CHANGE_VALID)
- return CS_BAD_VCC;
-
- /* We only allow changing Vpp1 and Vpp2 to the same value */
- if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
- (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
- if (mod->Vpp1 != mod->Vpp2)
- return CS_BAD_VPP;
- c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
- if (s->ops->set_socket(s, &s->socket))
- return CS_BAD_VPP;
- } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
- (mod->Attributes & CONF_VPP2_CHANGE_VALID))
- return CS_BAD_VPP;
-
- return CS_SUCCESS;
-} /* modify_configuration */
-
/* register pcmcia_callback */
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
{
@@ -1188,543 +742,16 @@ int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c)
}
EXPORT_SYMBOL(pccard_register_pcmcia);
-/*====================================================================*/
-
-int pcmcia_release_configuration(client_handle_t handle)
-{
- pccard_io_map io = { 0, 0, 0, 0, 1 };
- struct pcmcia_socket *s;
- int i;
-
- if (CHECK_HANDLE(handle) ||
- !(handle->state & CLIENT_CONFIG_LOCKED))
- return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_CONFIG_LOCKED;
- s = SOCKET(handle);
-
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_SUCCESS;
-#endif
-
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
- if (--(s->lock_count) == 0) {
- s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
- s->socket.Vpp = 0;
- s->socket.io_irq = 0;
- s->ops->set_socket(s, &s->socket);
- }
- if (c->state & CONFIG_IO_REQ)
- for (i = 0; i < MAX_IO_WIN; i++) {
- if (s->io[i].NumPorts == 0)
- continue;
- s->io[i].Config--;
- if (s->io[i].Config != 0)
- continue;
- io.map = i;
- s->ops->set_io_map(s, &io);
- }
- c->state &= ~CONFIG_LOCKED;
- }
-
- return CS_SUCCESS;
-} /* release_configuration */
-
-/*======================================================================
- Release_io() releases the I/O ranges allocated by a client. This
- may be invoked some time after a card ejection has already dumped
- the actual socket configuration, so if the client is "stale", we
- don't bother checking the port ranges against the current socket
- values.
-
-======================================================================*/
-
-int pcmcia_release_io(client_handle_t handle, io_req_t *req)
-{
- struct pcmcia_socket *s;
-
- if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IO_REQ))
- return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_IO_REQ;
- s = SOCKET(handle);
-
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_SUCCESS;
-#endif
-
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if ((c->io.BasePort1 != req->BasePort1) ||
- (c->io.NumPorts1 != req->NumPorts1) ||
- (c->io.BasePort2 != req->BasePort2) ||
- (c->io.NumPorts2 != req->NumPorts2))
- return CS_BAD_ARGS;
- c->state &= ~CONFIG_IO_REQ;
- }
-
- release_io_space(s, req->BasePort1, req->NumPorts1);
- if (req->NumPorts2)
- release_io_space(s, req->BasePort2, req->NumPorts2);
-
- return CS_SUCCESS;
-} /* release_io */
-
-/*====================================================================*/
-
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req)
-{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle) || !(handle->state & CLIENT_IRQ_REQ))
- return CS_BAD_HANDLE;
- handle->state &= ~CLIENT_IRQ_REQ;
- s = SOCKET(handle);
-
- if (!(handle->state & CLIENT_STALE)) {
- config_t *c = CONFIG(handle);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if (c->irq.Attributes != req->Attributes)
- return CS_BAD_ATTRIBUTE;
- if (s->irq.AssignedIRQ != req->AssignedIRQ)
- return CS_BAD_IRQ;
- if (--s->irq.Config == 0) {
- c->state &= ~CONFIG_IRQ_REQ;
- s->irq.AssignedIRQ = 0;
- }
- }
-
- if (req->Attributes & IRQ_HANDLE_PRESENT) {
- free_irq(req->AssignedIRQ, req->Instance);
- }
-
-#ifdef CONFIG_PCMCIA_PROBE
- pcmcia_used_irq[req->AssignedIRQ]--;
-#endif
-
- return CS_SUCCESS;
-} /* cs_release_irq */
-
-/*====================================================================*/
-
-int pcmcia_release_window(window_handle_t win)
-{
- struct pcmcia_socket *s;
-
- if ((win == NULL) || (win->magic != WINDOW_MAGIC))
- return CS_BAD_HANDLE;
- s = win->sock;
- if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
- return CS_BAD_HANDLE;
-
- /* Shut down memory window */
- win->ctl.flags &= ~MAP_ACTIVE;
- s->ops->set_mem_map(s, &win->ctl);
- s->state &= ~SOCKET_WIN_REQ(win->index);
-
- /* Release system memory */
- if (win->ctl.res) {
- release_resource(win->ctl.res);
- kfree(win->ctl.res);
- win->ctl.res = NULL;
- }
- win->handle->state &= ~CLIENT_WIN_REQ(win->index);
-
- win->magic = 0;
-
- return CS_SUCCESS;
-} /* release_window */
-
-/*====================================================================*/
-
-int pcmcia_request_configuration(client_handle_t handle,
- config_req_t *req)
-{
- int i;
- u_int base;
- struct pcmcia_socket *s;
- config_t *c;
- pccard_io_map iomap;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
-
-#ifdef CONFIG_CARDBUS
- if (handle->state & CLIENT_CARDBUS)
- return CS_UNSUPPORTED_MODE;
-#endif
-
- if (req->IntType & INT_CARDBUS)
- return CS_UNSUPPORTED_MODE;
- c = CONFIG(handle);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
-
- /* Do power control. We don't allow changes in Vcc. */
- if (s->socket.Vcc != req->Vcc)
- return CS_BAD_VCC;
- if (req->Vpp1 != req->Vpp2)
- return CS_BAD_VPP;
- s->socket.Vpp = req->Vpp1;
- if (s->ops->set_socket(s, &s->socket))
- return CS_BAD_VPP;
-
- c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
-
- /* Pick memory or I/O card, DMA mode, interrupt */
- c->IntType = req->IntType;
- c->Attributes = req->Attributes;
- if (req->IntType & INT_MEMORY_AND_IO)
- s->socket.flags |= SS_IOCARD;
- if (req->IntType & INT_ZOOMED_VIDEO)
- s->socket.flags |= SS_ZVCARD | SS_IOCARD;
- if (req->Attributes & CONF_ENABLE_DMA)
- s->socket.flags |= SS_DMA_MODE;
- if (req->Attributes & CONF_ENABLE_SPKR)
- s->socket.flags |= SS_SPKR_ENA;
- if (req->Attributes & CONF_ENABLE_IRQ)
- s->socket.io_irq = s->irq.AssignedIRQ;
- else
- s->socket.io_irq = 0;
- s->ops->set_socket(s, &s->socket);
- s->lock_count++;
-
- /* Set up CIS configuration registers */
- base = c->ConfigBase = req->ConfigBase;
- c->Present = c->CardValues = req->Present;
- if (req->Present & PRESENT_COPY) {
- c->Copy = req->Copy;
- write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
- }
- if (req->Present & PRESENT_OPTION) {
- if (s->functions == 1) {
- c->Option = req->ConfigIndex & COR_CONFIG_MASK;
- } else {
- c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
- c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
- if (req->Present & PRESENT_IOBASE_0)
- c->Option |= COR_ADDR_DECODE;
- }
- if (c->state & CONFIG_IRQ_REQ)
- if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
- c->Option |= COR_LEVEL_REQ;
- write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
- mdelay(40);
- }
- if (req->Present & PRESENT_STATUS) {
- c->Status = req->Status;
- write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
- }
- if (req->Present & PRESENT_PIN_REPLACE) {
- c->Pin = req->Pin;
- write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
- }
- if (req->Present & PRESENT_EXT_STATUS) {
- c->ExtStatus = req->ExtStatus;
- write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
- }
- if (req->Present & PRESENT_IOBASE_0) {
- u_char b = c->io.BasePort1 & 0xff;
- write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
- b = (c->io.BasePort1 >> 8) & 0xff;
- write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
- }
- if (req->Present & PRESENT_IOSIZE) {
- u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
- write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
- }
-
- /* Configure I/O windows */
- if (c->state & CONFIG_IO_REQ) {
- iomap.speed = io_speed;
- for (i = 0; i < MAX_IO_WIN; i++)
- if (s->io[i].NumPorts != 0) {
- iomap.map = i;
- iomap.flags = MAP_ACTIVE;
- switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
- case IO_DATA_PATH_WIDTH_16:
- iomap.flags |= MAP_16BIT; break;
- case IO_DATA_PATH_WIDTH_AUTO:
- iomap.flags |= MAP_AUTOSZ; break;
- default:
- break;
- }
- iomap.start = s->io[i].BasePort;
- iomap.stop = iomap.start + s->io[i].NumPorts - 1;
- s->ops->set_io_map(s, &iomap);
- s->io[i].Config++;
- }
- }
-
- c->state |= CONFIG_LOCKED;
- handle->state |= CLIENT_CONFIG_LOCKED;
- return CS_SUCCESS;
-} /* request_configuration */
-
-/*======================================================================
-
- Request_io() reserves ranges of port addresses for a socket.
- I have not implemented range sharing or alias addressing.
-
-======================================================================*/
-
-int pcmcia_request_io(client_handle_t handle, io_req_t *req)
-{
- struct pcmcia_socket *s;
- config_t *c;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
-
- if (handle->state & CLIENT_CARDBUS) {
-#ifdef CONFIG_CARDBUS
- handle->state |= CLIENT_IO_REQ;
- return CS_SUCCESS;
-#else
- return CS_UNSUPPORTED_FUNCTION;
-#endif
- }
-
- if (!req)
- return CS_UNSUPPORTED_MODE;
- c = CONFIG(handle);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if (c->state & CONFIG_IO_REQ)
- return CS_IN_USE;
- if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
- return CS_BAD_ATTRIBUTE;
- if ((req->NumPorts2 > 0) &&
- (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
- return CS_BAD_ATTRIBUTE;
-
- if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
- req->NumPorts1, req->IOAddrLines))
- return CS_IN_USE;
-
- if (req->NumPorts2) {
- if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
- req->NumPorts2, req->IOAddrLines)) {
- release_io_space(s, req->BasePort1, req->NumPorts1);
- return CS_IN_USE;
- }
- }
-
- c->io = *req;
- c->state |= CONFIG_IO_REQ;
- handle->state |= CLIENT_IO_REQ;
- return CS_SUCCESS;
-} /* request_io */
-
-/*======================================================================
-
- Request_irq() reserves an irq for this client.
-
- Also, since Linux only reserves irq's when they are actually
- hooked, we don't guarantee that an irq will still be available
- when the configuration is locked. Now that I think about it,
- there might be a way to fix this using a dummy handler.
-
-======================================================================*/
-
-#ifdef CONFIG_PCMCIA_PROBE
-static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
-{
- return IRQ_NONE;
-}
-#endif
-
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req)
-{
- struct pcmcia_socket *s;
- config_t *c;
- int ret = CS_IN_USE, irq = 0;
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- c = CONFIG(handle);
- if (c->state & CONFIG_LOCKED)
- return CS_CONFIGURATION_LOCKED;
- if (c->state & CONFIG_IRQ_REQ)
- return CS_IN_USE;
-
-#ifdef CONFIG_PCMCIA_PROBE
- if (s->irq.AssignedIRQ != 0) {
- /* If the interrupt is already assigned, it must be the same */
- irq = s->irq.AssignedIRQ;
- } else {
- int try;
- u32 mask = s->irq_mask;
- void *data = NULL;
-
- for (try = 0; try < 64; try++) {
- irq = try % 32;
-
- /* marked as available by driver, and not blocked by userspace? */
- if (!((mask >> irq) & 1))
- continue;
-
- /* avoid an IRQ which is already used by a PCMCIA card */
- if ((try < 32) && pcmcia_used_irq[irq])
- continue;
-
- /* register the correct driver, if possible, of check whether
- * registering a dummy handle works, i.e. if the IRQ isn't
- * marked as used by the kernel resource management core */
- ret = request_irq(irq,
- (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
- ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
- (s->functions > 1) ||
- (irq == s->pci_irq)) ? SA_SHIRQ : 0,
- p_dev->dev.bus_id,
- (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
- if (!ret) {
- if (!(req->Attributes & IRQ_HANDLE_PRESENT))
- free_irq(irq, data);
- break;
- }
- }
- }
-#endif
- if (ret) {
- if (!s->pci_irq)
- return ret;
- irq = s->pci_irq;
- }
-
- if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
- if (request_irq(irq, req->Handler,
- ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
- (s->functions > 1) ||
- (irq == s->pci_irq)) ? SA_SHIRQ : 0,
- p_dev->dev.bus_id, req->Instance))
- return CS_IN_USE;
- }
-
- c->irq.Attributes = req->Attributes;
- s->irq.AssignedIRQ = req->AssignedIRQ = irq;
- s->irq.Config++;
-
- c->state |= CONFIG_IRQ_REQ;
- handle->state |= CLIENT_IRQ_REQ;
-
-#ifdef CONFIG_PCMCIA_PROBE
- pcmcia_used_irq[irq]++;
-#endif
-
- return CS_SUCCESS;
-} /* pcmcia_request_irq */
-
-/*======================================================================
-
- Request_window() establishes a mapping between card memory space
- and system memory space.
-
-======================================================================*/
-
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh)
-{
- struct pcmcia_socket *s;
- window_t *win;
- u_long align;
- int w;
-
- if (CHECK_HANDLE(*handle))
- return CS_BAD_HANDLE;
- s = (*handle)->Socket;
- if (!(s->state & SOCKET_PRESENT))
- return CS_NO_CARD;
- if (req->Attributes & (WIN_PAGED | WIN_SHARED))
- return CS_BAD_ATTRIBUTE;
-
- /* Window size defaults to smallest available */
- if (req->Size == 0)
- req->Size = s->map_size;
- align = (((s->features & SS_CAP_MEM_ALIGN) ||
- (req->Attributes & WIN_STRICT_ALIGN)) ?
- req->Size : s->map_size);
- if (req->Size & (s->map_size-1))
- return CS_BAD_SIZE;
- if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
- (req->Base & (align-1)))
- return CS_BAD_BASE;
- if (req->Base)
- align = 0;
-
- /* Allocate system memory window */
- for (w = 0; w < MAX_WIN; w++)
- if (!(s->state & SOCKET_WIN_REQ(w))) break;
- if (w == MAX_WIN)
- return CS_OUT_OF_RESOURCE;
-
- win = &s->win[w];
- win->magic = WINDOW_MAGIC;
- win->index = w;
- win->handle = *handle;
- win->sock = s;
-
- if (!(s->features & SS_CAP_STATIC_MAP)) {
- win->ctl.res = find_mem_region(req->Base, req->Size, align,
- (req->Attributes & WIN_MAP_BELOW_1MB), s);
- if (!win->ctl.res)
- return CS_IN_USE;
- }
- (*handle)->state |= CLIENT_WIN_REQ(w);
-
- /* Configure the socket controller */
- win->ctl.map = w+1;
- win->ctl.flags = 0;
- win->ctl.speed = req->AccessSpeed;
- if (req->Attributes & WIN_MEMORY_TYPE)
- win->ctl.flags |= MAP_ATTRIB;
- if (req->Attributes & WIN_ENABLE)
- win->ctl.flags |= MAP_ACTIVE;
- if (req->Attributes & WIN_DATA_WIDTH_16)
- win->ctl.flags |= MAP_16BIT;
- if (req->Attributes & WIN_USE_WAIT)
- win->ctl.flags |= MAP_USE_WAIT;
- win->ctl.card_start = 0;
- if (s->ops->set_mem_map(s, &win->ctl) != 0)
- return CS_BAD_ARGS;
- s->state |= SOCKET_WIN_REQ(w);
-
- /* Return window handle */
- 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;
-} /* request_window */
-
-/*======================================================================
-
- I'm not sure which "reset" function this is supposed to use,
- but for now, it uses the low-level interface's reset, not the
- CIS register.
-
-======================================================================*/
+/* I'm not sure which "reset" function this is supposed to use,
+ * but for now, it uses the low-level interface's reset, not the
+ * CIS register.
+ */
int pccard_reset_card(struct pcmcia_socket *skt)
{
int ret;
-
+
cs_dbg(skt, 1, "resetting socket\n");
down(&skt->skt_sem);
@@ -1757,17 +784,14 @@ int pccard_reset_card(struct pcmcia_socket *skt)
} /* reset_card */
EXPORT_SYMBOL(pccard_reset_card);
-/*======================================================================
-
- These shut down or wake up a socket. They are sort of user
- initiated versions of the APM suspend and resume actions.
-
-======================================================================*/
+/* These shut down or wake up a socket. They are sort of user
+ * initiated versions of the APM suspend and resume actions.
+ */
int pcmcia_suspend_card(struct pcmcia_socket *skt)
{
int ret;
-
+
cs_dbg(skt, 1, "suspending socket\n");
down(&skt->skt_sem);
@@ -1786,6 +810,8 @@ int pcmcia_suspend_card(struct pcmcia_socket *skt)
return ret;
} /* suspend_card */
+EXPORT_SYMBOL(pcmcia_suspend_card);
+
int pcmcia_resume_card(struct pcmcia_socket *skt)
{
@@ -1809,13 +835,10 @@ int pcmcia_resume_card(struct pcmcia_socket *skt)
return ret;
} /* resume_card */
+EXPORT_SYMBOL(pcmcia_resume_card);
-/*======================================================================
-
- These handle user requests to eject or insert a card.
-
-======================================================================*/
+/* These handle user requests to eject or insert a card. */
int pcmcia_eject_card(struct pcmcia_socket *skt)
{
int ret;
@@ -1842,6 +865,8 @@ int pcmcia_eject_card(struct pcmcia_socket *skt)
return ret;
} /* eject_card */
+EXPORT_SYMBOL(pcmcia_eject_card);
+
int pcmcia_insert_card(struct pcmcia_socket *skt)
{
@@ -1865,37 +890,38 @@ int pcmcia_insert_card(struct pcmcia_socket *skt)
return ret;
} /* insert_card */
+EXPORT_SYMBOL(pcmcia_insert_card);
-/*======================================================================
- OS-specific module glue goes here
-
-======================================================================*/
-/* in alpha order */
-EXPORT_SYMBOL(pcmcia_eject_card);
-EXPORT_SYMBOL(pcmcia_get_card_services_info);
-EXPORT_SYMBOL(pcmcia_get_mem_page);
-EXPORT_SYMBOL(pcmcia_insert_card);
-EXPORT_SYMBOL(pcmcia_map_mem_page);
-EXPORT_SYMBOL(pcmcia_modify_configuration);
-EXPORT_SYMBOL(pcmcia_release_configuration);
-EXPORT_SYMBOL(pcmcia_release_io);
-EXPORT_SYMBOL(pcmcia_release_irq);
-EXPORT_SYMBOL(pcmcia_release_window);
-EXPORT_SYMBOL(pcmcia_replace_cis);
-EXPORT_SYMBOL(pcmcia_request_configuration);
-EXPORT_SYMBOL(pcmcia_request_io);
-EXPORT_SYMBOL(pcmcia_request_irq);
-EXPORT_SYMBOL(pcmcia_request_window);
-EXPORT_SYMBOL(pcmcia_resume_card);
-EXPORT_SYMBOL(pcmcia_suspend_card);
+static int pcmcia_socket_hotplug(struct class_device *dev, char **envp,
+ int num_envp, char *buffer, int buffer_size)
+{
+ struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
+ int i = 0, length = 0;
+
+ if (add_hotplug_env_var(envp, num_envp, &i, buffer, buffer_size,
+ &length, "SOCKET_NO=%u", s->sock))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
+ return 0;
+}
+
+
+static struct completion pcmcia_unload;
+
+static void pcmcia_release_socket_class(struct class *data)
+{
+ complete(&pcmcia_unload);
+}
-EXPORT_SYMBOL(dead_socket);
-EXPORT_SYMBOL(pcmcia_parse_events);
struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
+ .hotplug = pcmcia_socket_hotplug,
.release = pcmcia_release_socket,
+ .class_release = pcmcia_release_socket_class,
};
EXPORT_SYMBOL(pcmcia_socket_class);
@@ -1903,9 +929,8 @@ EXPORT_SYMBOL(pcmcia_socket_class);
static int __init init_pcmcia_cs(void)
{
int ret;
- printk(KERN_INFO "%s\n", release);
- printk(KERN_INFO " %s\n", options);
+ init_completion(&pcmcia_unload);
ret = class_register(&pcmcia_socket_class);
if (ret)
return (ret);
@@ -1914,13 +939,12 @@ static int __init init_pcmcia_cs(void)
static void __exit exit_pcmcia_cs(void)
{
- printk(KERN_INFO "unloading Kernel Card Services\n");
- class_interface_unregister(&pccard_sysfs_interface);
- class_unregister(&pcmcia_socket_class);
+ class_interface_unregister(&pccard_sysfs_interface);
+ class_unregister(&pcmcia_socket_class);
+
+ wait_for_completion(&pcmcia_unload);
}
subsys_initcall(init_pcmcia_cs);
module_exit(exit_pcmcia_cs);
-/*====================================================================*/
-
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 7933a7db49d3..6bbfbd0e02a5 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -99,23 +99,11 @@ static inline void cs_socket_put(struct pcmcia_socket *skt)
}
}
-#define CHECK_HANDLE(h) \
- (((h) == NULL) || ((h)->client_magic != CLIENT_MAGIC))
-
#define CHECK_SOCKET(s) \
(((s) >= sockets) || (socket_table[s]->ops == NULL))
-#define SOCKET(h) (h->Socket)
-#define CONFIG(h) (&SOCKET(h)->config[(h)->Function])
-
-#define CHECK_REGION(r) \
- (((r) == NULL) || ((r)->region_magic != REGION_MAGIC))
-
-#define CHECK_ERASEQ(q) \
- (((q) == NULL) || ((q)->eraseq_magic != ERASEQ_MAGIC))
-
-#define EVENT(h, e, p) \
- ((h)->event_handler((e), (p), &(h)->event_callback_args))
+#define SOCKET(h) (h->socket)
+#define CONFIG(h) (&SOCKET(h)->config[(h)->func])
/* In cardbus.c */
int cb_alloc(struct pcmcia_socket *s);
@@ -123,9 +111,9 @@ void cb_free(struct pcmcia_socket *s);
int read_cb_mem(struct pcmcia_socket *s, int space, u_int addr, u_int len, void *ptr);
/* In cistpl.c */
-int read_cis_mem(struct pcmcia_socket *s, int attr,
+int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr,
u_int addr, u_int len, void *ptr);
-void write_cis_mem(struct pcmcia_socket *s, int attr,
+void pcmcia_write_cis_mem(struct pcmcia_socket *s, int attr,
u_int addr, u_int len, void *ptr);
void release_cis_mem(struct pcmcia_socket *s);
void destroy_cis_cache(struct pcmcia_socket *s);
@@ -134,13 +122,12 @@ int pccard_read_tuple(struct pcmcia_socket *s, unsigned int function, cisdata_t
/* In rsrc_mgr */
void pcmcia_validate_mem(struct pcmcia_socket *s);
-struct resource *find_io_region(unsigned long base, int num, unsigned long align,
+struct resource *pcmcia_find_io_region(unsigned long base, int num, unsigned long align,
struct pcmcia_socket *s);
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s);
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
int low, struct pcmcia_socket *s);
-int adjust_resource_info(client_handle_t handle, adjust_t *adj);
void release_resource_db(struct pcmcia_socket *s);
/* In socket_sysfs.c */
@@ -159,7 +146,7 @@ int pccard_access_configuration_register(struct pcmcia_socket *s, unsigned int f
struct pcmcia_callback{
struct module *owner;
int (*event) (struct pcmcia_socket *s, event_t event, int priority);
- int (*resources_done) (struct pcmcia_socket *s);
+ void (*requery) (struct pcmcia_socket *s);
};
int pccard_register_pcmcia(struct pcmcia_socket *s, struct pcmcia_callback *c);
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 569e55feecfd..3e3c6f12bbe6 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -10,44 +10,29 @@
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* (C) 1999 David A. Hinds
- * (C) 2003 - 2004 Dominik Brodowski
+ * (C) 2003 - 2005 Dominik Brodowski
*/
#include <linux/config.h>
+#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/fcntl.h>
-#include <linux/sched.h>
-#include <linux/smp_lock.h>
-#include <linux/timer.h>
-#include <linux/ioctl.h>
-#include <linux/proc_fs.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
#include <linux/list.h>
#include <linux/delay.h>
-#include <linux/kref.h>
#include <linux/workqueue.h>
-
-#include <asm/atomic.h>
+#include <linux/crc32.h>
+#include <linux/firmware.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
-#include <pcmcia/bulkmem.h>
#include <pcmcia/cistpl.h>
#include <pcmcia/ds.h>
#include <pcmcia/ss.h>
#include "cs_internal.h"
+#include "ds_internal.h"
/*====================================================================*/
@@ -70,49 +55,9 @@ module_param_named(pc_debug, ds_pc_debug, int, 0644);
#define ds_dbg(lvl, fmt, arg...) do { } while (0)
#endif
-/*====================================================================*/
+spinlock_t pcmcia_dev_list_lock;
-/* Device user information */
-#define MAX_EVENTS 32
-#define USER_MAGIC 0x7ea4
-#define CHECK_USER(u) \
- (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
-typedef struct user_info_t {
- u_int user_magic;
- int event_head, event_tail;
- event_t event[MAX_EVENTS];
- struct user_info_t *next;
- struct pcmcia_bus_socket *socket;
-} user_info_t;
-
-/* Socket state information */
-struct pcmcia_bus_socket {
- struct kref refcount;
- struct pcmcia_callback callback;
- int state;
- user_info_t *user;
- wait_queue_head_t queue;
- struct pcmcia_socket *parent;
-
- /* the PCMCIA devices connected to this socket (normally one, more
- * for multifunction devices: */
- struct list_head devices_list;
- u8 device_count; /* the number of devices, used
- * only internally and subject
- * to incorrectness and change */
-};
-static spinlock_t pcmcia_dev_list_lock;
-
-#define DS_SOCKET_PRESENT 0x01
-#define DS_SOCKET_BUSY 0x02
-#define DS_SOCKET_REMOVAL_PENDING 0x10
-#define DS_SOCKET_DEAD 0x80
-
-/*====================================================================*/
-
-static int major_dev = -1;
-
-static int unbind_request(struct pcmcia_bus_socket *s);
+static int unbind_request(struct pcmcia_socket *s);
/*====================================================================*/
@@ -213,17 +158,15 @@ static const lookup_t service_table[] = {
};
-int pcmcia_report_error(client_handle_t handle, error_info_t *err)
+static int pcmcia_report_error(struct pcmcia_device *p_dev, error_info_t *err)
{
int i;
char *serv;
- if (CHECK_HANDLE(handle))
+ if (!p_dev)
printk(KERN_NOTICE);
- else {
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
+ else
printk(KERN_NOTICE "%s: ", p_dev->dev.bus_id);
- }
for (i = 0; i < ARRAY_SIZE(service_table); i++)
if (service_table[i].key == err->func)
@@ -243,42 +186,117 @@ int pcmcia_report_error(client_handle_t handle, error_info_t *err)
return CS_SUCCESS;
} /* report_error */
-EXPORT_SYMBOL(pcmcia_report_error);
/* end of code which was in cs.c before */
/*======================================================================*/
-void cs_error(client_handle_t handle, int func, int ret)
+void cs_error(struct pcmcia_device *p_dev, int func, int ret)
{
error_info_t err = { func, ret };
- pcmcia_report_error(handle, &err);
+ pcmcia_report_error(p_dev, &err);
}
EXPORT_SYMBOL(cs_error);
-/*======================================================================*/
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info);
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr);
-static void pcmcia_release_bus_socket(struct kref *refcount)
+static void pcmcia_check_driver(struct pcmcia_driver *p_drv)
{
- struct pcmcia_bus_socket *s = container_of(refcount, struct pcmcia_bus_socket, refcount);
- pcmcia_put_socket(s->parent);
- kfree(s);
+ struct pcmcia_device_id *did = p_drv->id_table;
+ unsigned int i;
+ u32 hash;
+
+ if (!p_drv->attach || !p_drv->event || !p_drv->detach)
+ printk(KERN_DEBUG "pcmcia: %s does misses a callback function",
+ p_drv->drv.name);
+
+ while (did && did->match_flags) {
+ for (i=0; i<4; i++) {
+ if (!did->prod_id[i])
+ continue;
+
+ hash = crc32(0, did->prod_id[i], strlen(did->prod_id[i]));
+ if (hash == did->prod_id_hash[i])
+ continue;
+
+ printk(KERN_DEBUG "pcmcia: %s: invalid hash for "
+ "product string \"%s\": is 0x%x, should "
+ "be 0x%x\n", p_drv->drv.name, did->prod_id[i],
+ did->prod_id_hash[i], hash);
+ printk(KERN_DEBUG "pcmcia: see "
+ "Documentation/pcmcia/devicetable.txt for "
+ "details\n");
+ }
+ did++;
+ }
+
+ return;
}
-static void pcmcia_put_bus_socket(struct pcmcia_bus_socket *s)
+
+#ifdef CONFIG_PCMCIA_LOAD_CIS
+
+/**
+ * pcmcia_load_firmware - load CIS from userspace if device-provided is broken
+ * @dev - the pcmcia device which needs a CIS override
+ * @filename - requested filename in /lib/firmware/cis/
+ *
+ * This uses the in-kernel firmware loading mechanism to use a "fake CIS" if
+ * the one provided by the card is broken. The firmware files reside in
+ * /lib/firmware/cis/ in userspace.
+ */
+static int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
{
- kref_put(&s->refcount, pcmcia_release_bus_socket);
+ struct pcmcia_socket *s = dev->socket;
+ const struct firmware *fw;
+ char path[20];
+ int ret=-ENOMEM;
+ cisdump_t *cis;
+
+ if (!filename)
+ return -EINVAL;
+
+ ds_dbg(1, "trying to load firmware %s\n", filename);
+
+ if (strlen(filename) > 14)
+ return -EINVAL;
+
+ snprintf(path, 20, "%s", filename);
+
+ if (request_firmware(&fw, path, &dev->dev) == 0) {
+ if (fw->size >= CISTPL_MAX_CIS_SIZE)
+ goto release;
+
+ cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+ if (!cis)
+ goto release;
+
+ memset(cis, 0, sizeof(cisdump_t));
+
+ cis->Length = fw->size + 1;
+ memcpy(cis->Data, fw->data, fw->size);
+
+ if (!pcmcia_replace_cis(s, cis))
+ ret = 0;
+ }
+ release:
+ release_firmware(fw);
+
+ return (ret);
}
-static struct pcmcia_bus_socket *pcmcia_get_bus_socket(struct pcmcia_bus_socket *s)
+#else /* !CONFIG_PCMCIA_LOAD_CIS */
+
+static inline int pcmcia_load_firmware(struct pcmcia_device *dev, char * filename)
{
- kref_get(&s->refcount);
- return (s);
+ return -ENODEV;
}
+#endif
+
+
+/*======================================================================*/
+
+
/**
* pcmcia_register_driver - register a PCMCIA driver with the bus core
*
@@ -292,6 +310,8 @@ int pcmcia_register_driver(struct pcmcia_driver *driver)
if (!driver)
return -EINVAL;
+ pcmcia_check_driver(driver);
+
/* initialize common fields */
driver->drv.bus = &pcmcia_bus_type;
driver->drv.owner = driver->owner;
@@ -311,42 +331,10 @@ void pcmcia_unregister_driver(struct pcmcia_driver *driver)
}
EXPORT_SYMBOL(pcmcia_unregister_driver);
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *proc_pccard = NULL;
-
-static int proc_read_drivers_callback(struct device_driver *driver, void *d)
-{
- char **p = d;
- struct pcmcia_driver *p_drv = container_of(driver,
- struct pcmcia_driver, drv);
-
- *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
-#ifdef CONFIG_MODULE_UNLOAD
- (p_drv->owner) ? module_refcount(p_drv->owner) : 1
-#else
- 1
-#endif
- );
- d = (void *) p;
-
- return 0;
-}
-
-static int proc_read_drivers(char *buf, char **start, off_t pos,
- int count, int *eof, void *data)
-{
- char *p = buf;
-
- bus_for_each_drv(&pcmcia_bus_type, NULL,
- (void *) &p, proc_read_drivers_callback);
-
- return (p - buf);
-}
-#endif
/* pcmcia_device handling */
-static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
+struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
{
struct device *tmp_dev;
tmp_dev = get_device(&p_dev->dev);
@@ -355,7 +343,7 @@ static struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev)
return to_pcmcia_dev(tmp_dev);
}
-static void pcmcia_put_dev(struct pcmcia_device *p_dev)
+void pcmcia_put_dev(struct pcmcia_device *p_dev)
{
if (p_dev)
put_device(&p_dev->dev);
@@ -365,7 +353,7 @@ static void pcmcia_release_dev(struct device *dev)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
ds_dbg(1, "releasing dev %p\n", p_dev);
- pcmcia_put_bus_socket(p_dev->socket->pcmcia);
+ pcmcia_put_socket(p_dev->socket);
kfree(p_dev);
}
@@ -390,7 +378,7 @@ static int pcmcia_device_probe(struct device * dev)
if (p_drv->attach) {
p_dev->instance = p_drv->attach();
- if ((!p_dev->instance) || (p_dev->client.state & CLIENT_UNBOUND)) {
+ if ((!p_dev->instance) || (p_dev->state & CLIENT_UNBOUND)) {
printk(KERN_NOTICE "ds: unable to create instance "
"of '%s'!\n", p_drv->drv.name);
ret = -EINVAL;
@@ -500,42 +488,45 @@ static int pcmcia_device_query(struct pcmcia_device *p_dev)
*/
static DECLARE_MUTEX(device_add_lock);
-static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, unsigned int function)
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function)
{
struct pcmcia_device *p_dev;
unsigned long flags;
- s = pcmcia_get_bus_socket(s);
+ s = pcmcia_get_socket(s);
if (!s)
return NULL;
down(&device_add_lock);
+ /* max of 2 devices per card */
+ if (s->device_count == 2)
+ goto err_put;
+
p_dev = kmalloc(sizeof(struct pcmcia_device), GFP_KERNEL);
if (!p_dev)
goto err_put;
memset(p_dev, 0, sizeof(struct pcmcia_device));
- p_dev->socket = s->parent;
+ p_dev->socket = s;
p_dev->device_no = (s->device_count++);
p_dev->func = function;
p_dev->dev.bus = &pcmcia_bus_type;
- p_dev->dev.parent = s->parent->dev.dev;
+ p_dev->dev.parent = s->dev.dev;
p_dev->dev.release = pcmcia_release_dev;
sprintf (p_dev->dev.bus_id, "%d.%d", p_dev->socket->sock, p_dev->device_no);
/* compat */
- p_dev->client.client_magic = CLIENT_MAGIC;
- p_dev->client.Socket = s->parent;
- p_dev->client.Function = function;
- p_dev->client.state = CLIENT_UNBOUND;
+ p_dev->state = CLIENT_UNBOUND;
/* Add to the list in pcmcia_bus_socket */
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_add_tail(&p_dev->socket_device_list, &s->devices_list);
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ pcmcia_device_query(p_dev);
+
if (device_register(&p_dev->dev)) {
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
list_del(&p_dev->socket_device_list);
@@ -553,7 +544,7 @@ static struct pcmcia_device * pcmcia_device_add(struct pcmcia_bus_socket *s, uns
s->device_count--;
err_put:
up(&device_add_lock);
- pcmcia_put_bus_socket(s);
+ pcmcia_put_socket(s);
return NULL;
}
@@ -581,26 +572,253 @@ static int pcmcia_card_add(struct pcmcia_socket *s)
else
no_funcs = 1;
- /* this doesn't handle multifunction devices on one pcmcia function
- * yet. */
for (i=0; i < no_funcs; i++)
- pcmcia_device_add(s->pcmcia, i);
+ pcmcia_device_add(s, i);
return (ret);
}
+static void pcmcia_delayed_add_pseudo_device(void *data)
+{
+ struct pcmcia_socket *s = data;
+ pcmcia_device_add(s, 0);
+ s->pcmcia_state.device_add_pending = 0;
+}
+
+static inline void pcmcia_add_pseudo_device(struct pcmcia_socket *s)
+{
+ if (!s->pcmcia_state.device_add_pending) {
+ schedule_work(&s->device_add);
+ s->pcmcia_state.device_add_pending = 1;
+ }
+ return;
+}
+
+static int pcmcia_requery(struct device *dev, void * _data)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ if (!p_dev->dev.driver)
+ pcmcia_device_query(p_dev);
+
+ return 0;
+}
+
+static void pcmcia_bus_rescan(struct pcmcia_socket *skt)
+{
+ int no_devices=0;
+ unsigned long flags;
+
+ /* must be called with skt_sem held */
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ if (list_empty(&skt->devices_list))
+ no_devices=1;
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ /* if no devices were added for this socket yet because of
+ * missing resource information or other trouble, we need to
+ * do this now. */
+ if (no_devices) {
+ int ret = pcmcia_card_add(skt);
+ if (ret)
+ return;
+ }
+
+ /* some device information might have changed because of a CIS
+ * update or because we can finally read it correctly... so
+ * determine it again, overwriting old values if necessary. */
+ bus_for_each_dev(&pcmcia_bus_type, NULL, NULL, pcmcia_requery);
+
+ /* we re-scan all devices, not just the ones connected to this
+ * socket. This does not matter, though. */
+ bus_rescan_devices(&pcmcia_bus_type);
+}
+
+static inline int pcmcia_devmatch(struct pcmcia_device *dev,
+ struct pcmcia_device_id *did)
+{
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID) {
+ if ((!dev->has_manf_id) || (dev->manf_id != did->manf_id))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID) {
+ if ((!dev->has_card_id) || (dev->card_id != did->card_id))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION) {
+ if (dev->func != did->function)
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1) {
+ if (!dev->prod_id[0])
+ return 0;
+ if (strcmp(did->prod_id[0], dev->prod_id[0]))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2) {
+ if (!dev->prod_id[1])
+ return 0;
+ if (strcmp(did->prod_id[1], dev->prod_id[1]))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3) {
+ if (!dev->prod_id[2])
+ return 0;
+ if (strcmp(did->prod_id[2], dev->prod_id[2]))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4) {
+ if (!dev->prod_id[3])
+ return 0;
+ if (strcmp(did->prod_id[3], dev->prod_id[3]))
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO) {
+ /* handle pseudo multifunction devices:
+ * there are at most two pseudo multifunction devices.
+ * if we're matching against the first, schedule a
+ * call which will then check whether there are two
+ * pseudo devices, and if not, add the second one.
+ */
+ if (dev->device_no == 0)
+ pcmcia_add_pseudo_device(dev->socket);
+
+ if (dev->device_no != did->device_no)
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID) {
+ if ((!dev->has_func_id) || (dev->func_id != did->func_id))
+ return 0;
+
+ /* if this is a pseudo-multi-function device,
+ * we need explicit matches */
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO)
+ return 0;
+ if (dev->device_no)
+ return 0;
+
+ /* also, FUNC_ID matching needs to be activated by userspace
+ * after it has re-checked that there is no possible module
+ * with a prod_id/manf_id/card_id match.
+ */
+ if (!dev->allow_func_id_match)
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_FAKE_CIS) {
+ if (!dev->socket->fake_cis)
+ pcmcia_load_firmware(dev, did->cisfile);
+
+ if (!dev->socket->fake_cis)
+ return 0;
+ }
+
+ if (did->match_flags & PCMCIA_DEV_ID_MATCH_ANONYMOUS) {
+ int i;
+ for (i=0; i<4; i++)
+ if (dev->prod_id[i])
+ return 0;
+ if (dev->has_manf_id || dev->has_card_id || dev->has_func_id)
+ return 0;
+ }
+
+ dev->dev.driver_data = (void *) did;
+
+ return 1;
+}
+
+
static int pcmcia_bus_match(struct device * dev, struct device_driver * drv) {
struct pcmcia_device * p_dev = to_pcmcia_dev(dev);
struct pcmcia_driver * p_drv = to_pcmcia_drv(drv);
+ struct pcmcia_device_id *did = p_drv->id_table;
/* matching by cardmgr */
if (p_dev->cardmgr == p_drv)
return 1;
+ while (did && did->match_flags) {
+ if (pcmcia_devmatch(p_dev, did))
+ return 1;
+ did++;
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_HOTPLUG
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ struct pcmcia_device *p_dev;
+ int i, length = 0;
+ u32 hash[4] = { 0, 0, 0, 0};
+
+ if (!dev)
+ return -ENODEV;
+
+ p_dev = to_pcmcia_dev(dev);
+
+ /* calculate hashes */
+ for (i=0; i<4; i++) {
+ if (!p_dev->prod_id[i])
+ continue;
+ hash[i] = crc32(0, p_dev->prod_id[i], strlen(p_dev->prod_id[i]));
+ }
+
+ i = 0;
+
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "SOCKET_NO=%u",
+ p_dev->socket->sock))
+ return -ENOMEM;
+
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "DEVICE_NO=%02X",
+ p_dev->device_no))
+ return -ENOMEM;
+
+ if (add_hotplug_env_var(envp, num_envp, &i,
+ buffer, buffer_size, &length,
+ "MODALIAS=pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ "pa%08Xpb%08Xpc%08Xpd%08X",
+ p_dev->has_manf_id ? p_dev->manf_id : 0,
+ p_dev->has_card_id ? p_dev->card_id : 0,
+ p_dev->has_func_id ? p_dev->func_id : 0,
+ p_dev->func,
+ p_dev->device_no,
+ hash[0],
+ hash[1],
+ hash[2],
+ hash[3]))
+ return -ENOMEM;
+
+ envp[i] = NULL;
+
return 0;
}
+#else
+
+static int pcmcia_bus_hotplug(struct device *dev, char **envp, int num_envp,
+ char *buffer, int buffer_size)
+{
+ return -ENODEV;
+}
+
+#endif
+
/************************ per-device sysfs output ***************************/
#define pcmcia_device_attr(field, test, format) \
@@ -626,6 +844,43 @@ pcmcia_device_stringattr(prod_id2, prod_id[1]);
pcmcia_device_stringattr(prod_id3, prod_id[2]);
pcmcia_device_stringattr(prod_id4, prod_id[3]);
+static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ int i;
+ u32 hash[4] = { 0, 0, 0, 0};
+
+ /* calculate hashes */
+ for (i=0; i<4; i++) {
+ if (!p_dev->prod_id[i])
+ continue;
+ hash[i] = crc32(0,p_dev->prod_id[i],strlen(p_dev->prod_id[i]));
+ }
+ return sprintf(buf, "pcmcia:m%04Xc%04Xf%02Xfn%02Xpfn%02X"
+ "pa%08Xpb%08Xpc%08Xpd%08X\n",
+ p_dev->has_manf_id ? p_dev->manf_id : 0,
+ p_dev->has_card_id ? p_dev->card_id : 0,
+ p_dev->has_func_id ? p_dev->func_id : 0,
+ p_dev->func, p_dev->device_no,
+ hash[0], hash[1], hash[2], hash[3]);
+}
+
+static ssize_t pcmcia_store_allow_func_id_match(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ if (!count)
+ return -EINVAL;
+
+ down(&p_dev->socket->skt_sem);
+ p_dev->allow_func_id_match = 1;
+ up(&p_dev->socket->skt_sem);
+
+ bus_rescan_devices(&pcmcia_bus_type);
+
+ return count;
+}
+
static struct device_attribute pcmcia_dev_attrs[] = {
__ATTR(function, 0444, func_show, NULL),
__ATTR_RO(func_id),
@@ -635,46 +890,14 @@ static struct device_attribute pcmcia_dev_attrs[] = {
__ATTR_RO(prod_id2),
__ATTR_RO(prod_id3),
__ATTR_RO(prod_id4),
+ __ATTR_RO(modalias),
+ __ATTR(allow_func_id_match, 0200, NULL, pcmcia_store_allow_func_id_match),
__ATTR_NULL,
};
/*======================================================================
- These manage a ring buffer of events pending for one user process
-
-======================================================================*/
-
-static int queue_empty(user_info_t *user)
-{
- return (user->event_head == user->event_tail);
-}
-
-static event_t get_queued_event(user_info_t *user)
-{
- user->event_tail = (user->event_tail+1) % MAX_EVENTS;
- return user->event[user->event_tail];
-}
-
-static void queue_event(user_info_t *user, event_t event)
-{
- user->event_head = (user->event_head+1) % MAX_EVENTS;
- if (user->event_head == user->event_tail)
- user->event_tail = (user->event_tail+1) % MAX_EVENTS;
- user->event[user->event_head] = event;
-}
-
-static void handle_event(struct pcmcia_bus_socket *s, event_t event)
-{
- user_info_t *user;
- for (user = s->user; user; user = user->next)
- queue_event(user, event);
- wake_up_interruptible(&s->queue);
-}
-
-
-/*======================================================================
-
The card status event handler.
======================================================================*/
@@ -688,6 +911,7 @@ struct send_event_data {
static int send_event_callback(struct device *dev, void * _data)
{
struct pcmcia_device *p_dev = to_pcmcia_dev(dev);
+ struct pcmcia_driver *p_drv;
struct send_event_data *data = _data;
/* we get called for all sockets, but may only pass the event
@@ -695,32 +919,29 @@ static int send_event_callback(struct device *dev, void * _data)
if (p_dev->socket != data->skt)
return 0;
- if (p_dev->client.state & (CLIENT_UNBOUND|CLIENT_STALE))
+ p_drv = to_pcmcia_drv(p_dev->dev.driver);
+ if (!p_drv)
return 0;
- if (p_dev->client.EventMask & data->event)
- return EVENT(&p_dev->client, data->event, data->priority);
+ if (p_dev->state & (CLIENT_UNBOUND|CLIENT_STALE))
+ return 0;
+
+ if (p_drv->event)
+ return p_drv->event(data->event, data->priority,
+ &p_dev->event_callback_args);
return 0;
}
static int send_event(struct pcmcia_socket *s, event_t event, int priority)
{
- int ret = 0;
struct send_event_data private;
- struct pcmcia_bus_socket *skt = pcmcia_get_bus_socket(s->pcmcia);
-
- if (!skt)
- return 0;
private.skt = s;
private.event = event;
private.priority = priority;
- ret = bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
-
- pcmcia_put_bus_socket(skt);
- return ret;
+ return bus_for_each_dev(&pcmcia_bus_type, NULL, &private, send_event_callback);
} /* send_event */
@@ -731,25 +952,25 @@ static int send_event(struct pcmcia_socket *s, event_t event, int priority)
static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
{
- struct pcmcia_bus_socket *s = skt->pcmcia;
+ struct pcmcia_socket *s = pcmcia_get_socket(skt);
int ret = 0;
ds_dbg(1, "ds_event(0x%06x, %d, 0x%p)\n",
- event, priority, s);
+ event, priority, skt);
switch (event) {
case CS_EVENT_CARD_REMOVAL:
- s->state &= ~DS_SOCKET_PRESENT;
+ s->pcmcia_state.present = 0;
send_event(skt, event, priority);
- unbind_request(s);
- handle_event(s, event);
+ unbind_request(skt);
+ handle_event(skt, event);
break;
case CS_EVENT_CARD_INSERTION:
- s->state |= DS_SOCKET_PRESENT;
+ s->pcmcia_state.present = 1;
pcmcia_card_add(skt);
- handle_event(s, event);
+ handle_event(skt, event);
break;
case CS_EVENT_EJECTION_REQUEST:
@@ -757,138 +978,23 @@ static int ds_event(struct pcmcia_socket *skt, event_t event, int priority)
break;
default:
- handle_event(s, event);
+ handle_event(skt, event);
send_event(skt, event, priority);
break;
}
+ pcmcia_put_socket(s);
+
return 0;
} /* ds_event */
-/*======================================================================
-
- bind_request() and bind_device() are merged by now. Register_client()
- is called right at the end of bind_request(), during the driver's
- ->attach() call. Individual descriptions:
-
- bind_request() connects a socket to a particular client driver.
- It looks up the specified device ID in the list of registered
- drivers, binds it to the socket, and tries to create an instance
- of the device. unbind_request() deletes a driver instance.
-
- Bind_device() associates a device driver with a particular socket.
- It is normally called by Driver Services after it has identified
- a newly inserted card. An instance of that driver will then be
- eligible to register as a client of this socket.
-
- Register_client() uses the dev_info_t handle to match the
- caller with a socket. The driver must have already been bound
- to a socket with bind_device() -- in fact, bind_device()
- allocates the client structure that will be used.
-======================================================================*/
-
-static int bind_request(struct pcmcia_bus_socket *s, bind_info_t *bind_info)
-{
- struct pcmcia_driver *p_drv;
- struct pcmcia_device *p_dev;
- int ret = 0;
- unsigned long flags;
-
- s = pcmcia_get_bus_socket(s);
- if (!s)
- return -EINVAL;
-
- ds_dbg(2, "bind_request(%d, '%s')\n", s->parent->sock,
- (char *)bind_info->dev_info);
-
- p_drv = get_pcmcia_driver(&bind_info->dev_info);
- if (!p_drv) {
- ret = -EINVAL;
- goto err_put;
- }
-
- if (!try_module_get(p_drv->owner)) {
- ret = -EINVAL;
- goto err_put_driver;
- }
-
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if (p_dev->func == bind_info->function) {
- if ((p_dev->dev.driver == &p_drv->drv)) {
- if (p_dev->cardmgr) {
- /* if there's already a device
- * registered, and it was registered
- * by userspace before, we need to
- * return the "instance". */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- bind_info->instance = p_dev->instance;
- ret = -EBUSY;
- goto err_put_module;
- } else {
- /* the correct driver managed to bind
- * itself magically to the correct
- * device. */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- p_dev->cardmgr = p_drv;
- ret = 0;
- goto err_put_module;
- }
- } else if (!p_dev->dev.driver) {
- /* there's already a device available where
- * no device has been bound to yet. So we don't
- * need to register a device! */
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- goto rescan;
- }
- }
- }
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
- p_dev = pcmcia_device_add(s, bind_info->function);
- if (!p_dev) {
- ret = -EIO;
- goto err_put_module;
- }
-
-rescan:
- p_dev->cardmgr = p_drv;
-
- pcmcia_device_query(p_dev);
-
- /*
- * Prevent this racing with a card insertion.
- */
- down(&s->parent->skt_sem);
- bus_rescan_devices(&pcmcia_bus_type);
- up(&s->parent->skt_sem);
-
- /* check whether the driver indeed matched. I don't care if this
- * is racy or not, because it can only happen on cardmgr access
- * paths...
- */
- if (!(p_dev->dev.driver == &p_drv->drv))
- p_dev->cardmgr = NULL;
-
- err_put_module:
- module_put(p_drv->owner);
- err_put_driver:
- put_driver(&p_drv->drv);
- err_put:
- pcmcia_put_bus_socket(s);
-
- return (ret);
-} /* bind_request */
-
-
-int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
+int pcmcia_register_client(struct pcmcia_device **handle, client_reg_t *req)
{
- client_t *client = NULL;
- struct pcmcia_socket *s;
- struct pcmcia_bus_socket *skt = NULL;
+ struct pcmcia_socket *s = NULL;
struct pcmcia_device *p_dev = NULL;
+ struct pcmcia_driver *p_drv = NULL;
/* Look for unbound client with matching dev_info */
down_read(&pcmcia_socket_list_rwsem);
@@ -898,56 +1004,45 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
if (s->state & SOCKET_CARDBUS)
continue;
- skt = s->pcmcia;
- if (!skt)
- continue;
- skt = pcmcia_get_bus_socket(skt);
- if (!skt)
+ s = pcmcia_get_socket(s);
+ if (!s)
continue;
spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(p_dev, &skt->devices_list, socket_device_list) {
- struct pcmcia_driver *p_drv;
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
p_dev = pcmcia_get_dev(p_dev);
if (!p_dev)
continue;
- if (!(p_dev->client.state & CLIENT_UNBOUND) ||
+ if (!(p_dev->state & CLIENT_UNBOUND) ||
(!p_dev->dev.driver)) {
pcmcia_put_dev(p_dev);
continue;
}
p_drv = to_pcmcia_drv(p_dev->dev.driver);
if (!strncmp(p_drv->drv.name, (char *)req->dev_info, DEV_NAME_LEN)) {
- client = &p_dev->client;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
goto found;
}
pcmcia_put_dev(p_dev);
}
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- pcmcia_put_bus_socket(skt);
+ pcmcia_put_socket(s);
}
found:
up_read(&pcmcia_socket_list_rwsem);
- if (!p_dev || !client)
+ if (!p_dev)
return -ENODEV;
- pcmcia_put_bus_socket(skt); /* safe, as we already hold a reference from bind_device */
+ pcmcia_put_socket(s); /* safe, as we already hold a reference from bind_device */
- *handle = client;
- client->state &= ~CLIENT_UNBOUND;
- client->Socket = s;
- client->EventMask = req->EventMask;
- client->event_handler = req->event_handler;
- client->event_callback_args = req->event_callback_args;
- client->event_callback_args.client_handle = client;
+ *handle = p_dev;
+ p_dev->state &= ~CLIENT_UNBOUND;
+ p_dev->event_callback_args = req->event_callback_args;
+ p_dev->event_callback_args.client_handle = p_dev;
- if (s->state & SOCKET_CARDBUS)
- client->state |= CLIENT_CARDBUS;
- if ((!(s->state & SOCKET_CARDBUS)) && (s->functions == 0) &&
- (client->Function != BIND_FN_ALL)) {
+ if (!s->functions) {
cistpl_longlink_mfc_t mfc;
- if (pccard_read_tuple(s, client->Function, CISTPL_LONGLINK_MFC, &mfc)
+ if (pccard_read_tuple(s, p_dev->func, CISTPL_LONGLINK_MFC, &mfc)
== CS_SUCCESS)
s->functions = mfc.nfn;
else
@@ -960,13 +1055,13 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
}
ds_dbg(1, "register_client(): client 0x%p, dev %s\n",
- client, p_dev->dev.bus_id);
- if (client->EventMask & CS_EVENT_REGISTRATION_COMPLETE)
- EVENT(client, CS_EVENT_REGISTRATION_COMPLETE, CS_EVENT_PRI_LOW);
+ p_dev, p_dev->dev.bus_id);
if ((s->state & (SOCKET_PRESENT|SOCKET_CARDBUS)) == SOCKET_PRESENT) {
- if (client->EventMask & CS_EVENT_CARD_INSERTION)
- EVENT(client, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+ if (p_drv->event)
+ p_drv->event(CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW,
+ &p_dev->event_callback_args);
+
}
return CS_SUCCESS;
@@ -978,106 +1073,15 @@ int pcmcia_register_client(client_handle_t *handle, client_reg_t *req)
EXPORT_SYMBOL(pcmcia_register_client);
-/*====================================================================*/
-
-extern struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s);
-
-static int get_device_info(struct pcmcia_bus_socket *s, bind_info_t *bind_info, int first)
-{
- dev_node_t *node;
- struct pcmcia_device *p_dev;
- unsigned long flags;
- int ret = 0;
-
-#ifdef CONFIG_CARDBUS
- /*
- * Some unbelievably ugly code to associate the PCI cardbus
- * device and its driver with the PCMCIA "bind" information.
- */
- {
- struct pci_bus *bus;
-
- bus = pcmcia_lookup_bus(s->parent);
- if (bus) {
- struct list_head *list;
- struct pci_dev *dev = NULL;
-
- list = bus->devices.next;
- while (list != &bus->devices) {
- struct pci_dev *pdev = pci_dev_b(list);
- list = list->next;
-
- if (first) {
- dev = pdev;
- break;
- }
-
- /* Try to handle "next" here some way? */
- }
- if (dev && dev->driver) {
- strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
- bind_info->major = 0;
- bind_info->minor = 0;
- bind_info->next = NULL;
- return 0;
- }
- }
- }
-#endif
-
- spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
- list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
- if (p_dev->func == bind_info->function) {
- p_dev = pcmcia_get_dev(p_dev);
- if (!p_dev)
- continue;
- goto found;
- }
- }
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
- return -ENODEV;
-
- found:
- spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
-
- if ((!p_dev->instance) ||
- (p_dev->instance->state & DEV_CONFIG_PENDING)) {
- ret = -EAGAIN;
- goto err_put;
- }
-
- if (first)
- node = p_dev->instance->dev;
- else
- for (node = p_dev->instance->dev; node; node = node->next)
- if (node == bind_info->next)
- break;
- if (!node) {
- ret = -ENODEV;
- goto err_put;
- }
-
- strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
- bind_info->major = node->major;
- bind_info->minor = node->minor;
- bind_info->next = node->next;
-
- err_put:
- pcmcia_put_dev(p_dev);
- return (ret);
-} /* get_device_info */
-
-/*====================================================================*/
-
/* unbind _all_ devices attached to a given pcmcia_bus_socket. The
* drivers have been called with EVENT_CARD_REMOVAL before.
*/
-static int unbind_request(struct pcmcia_bus_socket *s)
+static int unbind_request(struct pcmcia_socket *s)
{
struct pcmcia_device *p_dev;
unsigned long flags;
- ds_dbg(2, "unbind_request(%d)\n", s->parent->sock);
+ ds_dbg(2, "unbind_request(%d)\n", s->sock);
s->device_count = 0;
@@ -1090,7 +1094,7 @@ static int unbind_request(struct pcmcia_bus_socket *s)
}
p_dev = list_entry((&s->devices_list)->next, struct pcmcia_device, socket_device_list);
list_del(&p_dev->socket_device_list);
- p_dev->client.state |= CLIENT_STALE;
+ p_dev->state |= CLIENT_STALE;
spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
device_unregister(&p_dev->dev);
@@ -1099,31 +1103,25 @@ static int unbind_request(struct pcmcia_bus_socket *s)
return 0;
} /* unbind_request */
-int pcmcia_deregister_client(client_handle_t handle)
+int pcmcia_deregister_client(struct pcmcia_device *p_dev)
{
struct pcmcia_socket *s;
int i;
- struct pcmcia_device *p_dev = handle_to_pdev(handle);
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
+ s = p_dev->socket;
+ ds_dbg(1, "deregister_client(%p)\n", p_dev);
- s = SOCKET(handle);
- ds_dbg(1, "deregister_client(%p)\n", handle);
-
- if (handle->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
+ if (p_dev->state & (CLIENT_IRQ_REQ|CLIENT_IO_REQ|CLIENT_CONFIG_LOCKED))
goto warn_out;
for (i = 0; i < MAX_WIN; i++)
- if (handle->state & CLIENT_WIN_REQ(i))
+ if (p_dev->state & CLIENT_WIN_REQ(i))
goto warn_out;
- if (handle->state & CLIENT_STALE) {
- handle->client_magic = 0;
- handle->state &= ~CLIENT_STALE;
+ if (p_dev->state & CLIENT_STALE) {
+ p_dev->state &= ~CLIENT_STALE;
pcmcia_put_dev(p_dev);
} else {
- handle->state = CLIENT_UNBOUND;
- handle->event_handler = NULL;
+ p_dev->state = CLIENT_UNBOUND;
}
return CS_SUCCESS;
@@ -1133,433 +1131,58 @@ int pcmcia_deregister_client(client_handle_t handle)
} /* deregister_client */
EXPORT_SYMBOL(pcmcia_deregister_client);
-
-/*======================================================================
-
- The user-mode PC Card device interface
-
-======================================================================*/
-
-static int ds_open(struct inode *inode, struct file *file)
-{
- socket_t i = iminor(inode);
- struct pcmcia_bus_socket *s;
- user_info_t *user;
-
- ds_dbg(0, "ds_open(socket %d)\n", i);
-
- s = get_socket_info_by_nr(i);
- if (!s)
- return -ENODEV;
- s = pcmcia_get_bus_socket(s);
- if (!s)
- return -ENODEV;
-
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
- if (s->state & DS_SOCKET_BUSY) {
- pcmcia_put_bus_socket(s);
- return -EBUSY;
- }
- else
- s->state |= DS_SOCKET_BUSY;
- }
-
- user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
- if (!user) {
- pcmcia_put_bus_socket(s);
- return -ENOMEM;
- }
- user->event_tail = user->event_head = 0;
- user->next = s->user;
- user->user_magic = USER_MAGIC;
- user->socket = s;
- s->user = user;
- file->private_data = user;
-
- if (s->state & DS_SOCKET_PRESENT)
- queue_event(user, CS_EVENT_CARD_INSERTION);
- return 0;
-} /* ds_open */
-
-/*====================================================================*/
-
-static int ds_release(struct inode *inode, struct file *file)
-{
- struct pcmcia_bus_socket *s;
- user_info_t *user, **link;
-
- ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
-
- user = file->private_data;
- if (CHECK_USER(user))
- goto out;
-
- s = user->socket;
-
- /* Unlink user data structure */
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
- s->state &= ~DS_SOCKET_BUSY;
- }
- file->private_data = NULL;
- for (link = &s->user; *link; link = &(*link)->next)
- if (*link == user) break;
- if (link == NULL)
- goto out;
- *link = user->next;
- user->user_magic = 0;
- kfree(user);
- pcmcia_put_bus_socket(s);
-out:
- return 0;
-} /* ds_release */
-
-/*====================================================================*/
-
-static ssize_t ds_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct pcmcia_bus_socket *s;
- user_info_t *user;
- int ret;
-
- ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
-
- if (count < 4)
- return -EINVAL;
-
- user = file->private_data;
- if (CHECK_USER(user))
- return -EIO;
-
- s = user->socket;
- if (s->state & DS_SOCKET_DEAD)
- return -EIO;
-
- ret = wait_event_interruptible(s->queue, !queue_empty(user));
- if (ret == 0)
- ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
-
- return ret;
-} /* ds_read */
-
-/*====================================================================*/
-
-static ssize_t ds_write(struct file *file, const char __user *buf,
- size_t count, loff_t *ppos)
-{
- ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
-
- if (count != 4)
- return -EINVAL;
- if ((file->f_flags & O_ACCMODE) == O_RDONLY)
- return -EBADF;
-
- return -EIO;
-} /* ds_write */
-
-/*====================================================================*/
-
-/* No kernel lock - fine */
-static u_int ds_poll(struct file *file, poll_table *wait)
-{
- struct pcmcia_bus_socket *s;
- user_info_t *user;
-
- ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
-
- user = file->private_data;
- if (CHECK_USER(user))
- return POLLERR;
- s = user->socket;
- /*
- * We don't check for a dead socket here since that
- * will send cardmgr into an endless spin.
- */
- poll_wait(file, &s->queue, wait);
- if (!queue_empty(user))
- return POLLIN | POLLRDNORM;
- return 0;
-} /* ds_poll */
-
-/*====================================================================*/
-
-extern int pcmcia_adjust_resource_info(adjust_t *adj);
-
-static int ds_ioctl(struct inode * inode, struct file * file,
- u_int cmd, u_long arg)
-{
- struct pcmcia_bus_socket *s;
- void __user *uarg = (char __user *)arg;
- u_int size;
- int ret, err;
- ds_ioctl_arg_t *buf;
- user_info_t *user;
-
- ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
-
- user = file->private_data;
- if (CHECK_USER(user))
- return -EIO;
-
- s = user->socket;
- if (s->state & DS_SOCKET_DEAD)
- return -EIO;
-
- size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
- if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
-
- /* Permission check */
- if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- if (cmd & IOC_IN) {
- if (!access_ok(VERIFY_READ, uarg, size)) {
- ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
- return -EFAULT;
- }
- }
- if (cmd & IOC_OUT) {
- if (!access_ok(VERIFY_WRITE, uarg, size)) {
- ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
- return -EFAULT;
- }
- }
- buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- err = ret = 0;
-
- if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
-
- switch (cmd) {
- case DS_ADJUST_RESOURCE_INFO:
- ret = pcmcia_adjust_resource_info(&buf->adjust);
- break;
- case DS_GET_CARD_SERVICES_INFO:
- ret = pcmcia_get_card_services_info(&buf->servinfo);
- break;
- case DS_GET_CONFIGURATION_INFO:
- if (buf->config.Function &&
- (buf->config.Function >= s->parent->functions))
- ret = CS_BAD_ARGS;
- else
- ret = pccard_get_configuration_info(s->parent,
- buf->config.Function, &buf->config);
- break;
- case DS_GET_FIRST_TUPLE:
- down(&s->parent->skt_sem);
- pcmcia_validate_mem(s->parent);
- up(&s->parent->skt_sem);
- ret = pccard_get_first_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
- break;
- case DS_GET_NEXT_TUPLE:
- ret = pccard_get_next_tuple(s->parent, BIND_FN_ALL, &buf->tuple);
- break;
- case DS_GET_TUPLE_DATA:
- buf->tuple.TupleData = buf->tuple_parse.data;
- buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
- ret = pccard_get_tuple_data(s->parent, &buf->tuple);
- break;
- case DS_PARSE_TUPLE:
- buf->tuple.TupleData = buf->tuple_parse.data;
- ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
- break;
- case DS_RESET_CARD:
- ret = pccard_reset_card(s->parent);
- break;
- case DS_GET_STATUS:
- if (buf->status.Function &&
- (buf->status.Function >= s->parent->functions))
- ret = CS_BAD_ARGS;
- else
- ret = pccard_get_status(s->parent, buf->status.Function, &buf->status);
- break;
- case DS_VALIDATE_CIS:
- down(&s->parent->skt_sem);
- pcmcia_validate_mem(s->parent);
- up(&s->parent->skt_sem);
- ret = pccard_validate_cis(s->parent, BIND_FN_ALL, &buf->cisinfo);
- break;
- case DS_SUSPEND_CARD:
- ret = pcmcia_suspend_card(s->parent);
- break;
- case DS_RESUME_CARD:
- ret = pcmcia_resume_card(s->parent);
- break;
- case DS_EJECT_CARD:
- err = pcmcia_eject_card(s->parent);
- break;
- case DS_INSERT_CARD:
- err = pcmcia_insert_card(s->parent);
- break;
- case DS_ACCESS_CONFIGURATION_REGISTER:
- if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- }
- if (buf->conf_reg.Function &&
- (buf->conf_reg.Function >= s->parent->functions))
- ret = CS_BAD_ARGS;
- else
- ret = pccard_access_configuration_register(s->parent,
- buf->conf_reg.Function, &buf->conf_reg);
- break;
- case DS_GET_FIRST_REGION:
- case DS_GET_NEXT_REGION:
- case DS_BIND_MTD:
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- } else {
- static int printed = 0;
- if (!printed) {
- printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
- printk(KERN_WARNING "MTD handling any more.\n");
- printed++;
- }
- }
- err = -EINVAL;
- goto free_out;
- break;
- case DS_GET_FIRST_WINDOW:
- ret = pcmcia_get_window(s->parent, &buf->win_info.handle, 0,
- &buf->win_info.window);
- break;
- case DS_GET_NEXT_WINDOW:
- ret = pcmcia_get_window(s->parent, &buf->win_info.handle,
- buf->win_info.handle->index + 1, &buf->win_info.window);
- break;
- case DS_GET_MEM_PAGE:
- ret = pcmcia_get_mem_page(buf->win_info.handle,
- &buf->win_info.map);
- break;
- case DS_REPLACE_CIS:
- ret = pcmcia_replace_cis(s->parent, &buf->cisdump);
- break;
- case DS_BIND_REQUEST:
- if (!capable(CAP_SYS_ADMIN)) {
- err = -EPERM;
- goto free_out;
- }
- err = bind_request(s, &buf->bind_info);
- break;
- case DS_GET_DEVICE_INFO:
- err = get_device_info(s, &buf->bind_info, 1);
- break;
- case DS_GET_NEXT_DEVICE:
- err = get_device_info(s, &buf->bind_info, 0);
- break;
- case DS_UNBIND_REQUEST:
- err = 0;
- break;
- default:
- err = -EINVAL;
- }
-
- if ((err == 0) && (ret != CS_SUCCESS)) {
- ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
- switch (ret) {
- case CS_BAD_SOCKET: case CS_NO_CARD:
- err = -ENODEV; break;
- case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
- case CS_BAD_TUPLE:
- err = -EINVAL; break;
- case CS_IN_USE:
- err = -EBUSY; break;
- case CS_OUT_OF_RESOURCE:
- err = -ENOSPC; break;
- case CS_NO_MORE_ITEMS:
- err = -ENODATA; break;
- case CS_UNSUPPORTED_FUNCTION:
- err = -ENOSYS; break;
- default:
- err = -EIO; break;
- }
- }
-
- if (cmd & IOC_OUT) {
- if (__copy_to_user(uarg, (char *)buf, size))
- err = -EFAULT;
- }
-
-free_out:
- kfree(buf);
- return err;
-} /* ds_ioctl */
-
-/*====================================================================*/
-
-static struct file_operations ds_fops = {
- .owner = THIS_MODULE,
- .open = ds_open,
- .release = ds_release,
- .ioctl = ds_ioctl,
- .read = ds_read,
- .write = ds_write,
- .poll = ds_poll,
+static struct pcmcia_callback pcmcia_bus_callback = {
+ .owner = THIS_MODULE,
+ .event = ds_event,
+ .requery = pcmcia_bus_rescan,
};
static int __devinit pcmcia_bus_add_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
- struct pcmcia_bus_socket *s;
int ret;
- s = kmalloc(sizeof(struct pcmcia_bus_socket), GFP_KERNEL);
- if(!s)
- return -ENOMEM;
- memset(s, 0, sizeof(struct pcmcia_bus_socket));
-
- /* get reference to parent socket */
- s->parent = pcmcia_get_socket(socket);
- if (!s->parent) {
+ socket = pcmcia_get_socket(socket);
+ if (!socket) {
printk(KERN_ERR "PCMCIA obtaining reference to socket %p failed\n", socket);
- kfree (s);
return -ENODEV;
}
- kref_init(&s->refcount);
-
/*
* 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..
*/
msleep(250);
- init_waitqueue_head(&s->queue);
- INIT_LIST_HEAD(&s->devices_list);
-
- /* Set up hotline to Card Services */
- s->callback.owner = THIS_MODULE;
- s->callback.event = &ds_event;
- s->callback.resources_done = &pcmcia_card_add;
- socket->pcmcia = s;
+#ifdef CONFIG_PCMCIA_IOCTL
+ init_waitqueue_head(&socket->queue);
+#endif
+ INIT_LIST_HEAD(&socket->devices_list);
+ INIT_WORK(&socket->device_add, pcmcia_delayed_add_pseudo_device, socket);
+ memset(&socket->pcmcia_state, 0, sizeof(u8));
+ socket->device_count = 0;
- ret = pccard_register_pcmcia(socket, &s->callback);
+ ret = pccard_register_pcmcia(socket, &pcmcia_bus_callback);
if (ret) {
printk(KERN_ERR "PCMCIA registration PCCard core failed for socket %p\n", socket);
- pcmcia_put_bus_socket(s);
- socket->pcmcia = NULL;
+ pcmcia_put_socket(socket);
return (ret);
}
return 0;
}
-
static void pcmcia_bus_remove_socket(struct class_device *class_dev)
{
struct pcmcia_socket *socket = class_get_devdata(class_dev);
- if (!socket || !socket->pcmcia)
+ if (!socket)
return;
+ socket->pcmcia_state.dead = 1;
pccard_register_pcmcia(socket, NULL);
- socket->pcmcia->state |= DS_SOCKET_DEAD;
- pcmcia_put_bus_socket(socket->pcmcia);
- socket->pcmcia = NULL;
+ pcmcia_put_socket(socket);
return;
}
@@ -1575,34 +1198,20 @@ static struct class_interface pcmcia_bus_interface = {
struct bus_type pcmcia_bus_type = {
.name = "pcmcia",
+ .hotplug = pcmcia_bus_hotplug,
.match = pcmcia_bus_match,
.dev_attrs = pcmcia_dev_attrs,
};
-EXPORT_SYMBOL(pcmcia_bus_type);
static int __init init_pcmcia_bus(void)
{
- int i;
-
spin_lock_init(&pcmcia_dev_list_lock);
bus_register(&pcmcia_bus_type);
class_interface_register(&pcmcia_bus_interface);
- /* Set up character device for user mode clients */
- i = register_chrdev(0, "pcmcia", &ds_fops);
- if (i < 0)
- printk(KERN_NOTICE "unable to find a free device # for "
- "Driver Services (error=%d)\n", i);
- else
- major_dev = i;
-
-#ifdef CONFIG_PROC_FS
- proc_pccard = proc_mkdir("pccard", proc_bus);
- if (proc_pccard)
- create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
-#endif
+ pcmcia_setup_ioctl();
return 0;
}
@@ -1612,48 +1221,13 @@ fs_initcall(init_pcmcia_bus); /* one level after subsys_initcall so that
static void __exit exit_pcmcia_bus(void)
{
- class_interface_unregister(&pcmcia_bus_interface);
+ pcmcia_cleanup_ioctl();
-#ifdef CONFIG_PROC_FS
- if (proc_pccard) {
- remove_proc_entry("drivers", proc_pccard);
- remove_proc_entry("pccard", proc_bus);
- }
-#endif
- if (major_dev != -1)
- unregister_chrdev(major_dev, "pcmcia");
+ class_interface_unregister(&pcmcia_bus_interface);
bus_unregister(&pcmcia_bus_type);
}
module_exit(exit_pcmcia_bus);
-
-/* helpers for backwards-compatible functions */
-
-static struct pcmcia_bus_socket * get_socket_info_by_nr(unsigned int nr)
-{
- struct pcmcia_socket * s = pcmcia_get_socket_by_nr(nr);
- if (s && s->pcmcia)
- return s->pcmcia;
- else
- return NULL;
-}
-
-/* backwards-compatible accessing of driver --- by name! */
-
-static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
-{
- struct device_driver *drv;
- struct pcmcia_driver *p_drv;
-
- drv = driver_find((char *) dev_info, &pcmcia_bus_type);
- if (!drv)
- return NULL;
-
- p_drv = container_of(drv, struct pcmcia_driver, drv);
-
- return (p_drv);
-}
-
MODULE_ALIAS("ds");
diff --git a/drivers/pcmcia/ds_internal.h b/drivers/pcmcia/ds_internal.h
new file mode 100644
index 000000000000..d359bd25a51c
--- /dev/null
+++ b/drivers/pcmcia/ds_internal.h
@@ -0,0 +1,21 @@
+/* ds_internal.h - internal header for 16-bit PCMCIA devices management */
+
+extern spinlock_t pcmcia_dev_list_lock;
+extern struct bus_type pcmcia_bus_type;
+
+extern struct pcmcia_device * pcmcia_get_dev(struct pcmcia_device *p_dev);
+extern void pcmcia_put_dev(struct pcmcia_device *p_dev);
+
+struct pcmcia_device * pcmcia_device_add(struct pcmcia_socket *s, unsigned int function);
+
+#ifdef CONFIG_PCMCIA_IOCTL
+extern void __init pcmcia_setup_ioctl(void);
+extern void __exit pcmcia_cleanup_ioctl(void);
+extern void handle_event(struct pcmcia_socket *s, event_t event);
+extern int handle_request(struct pcmcia_socket *s, event_t event);
+#else
+static inline void __init pcmcia_setup_ioctl(void) { return; }
+static inline void __init pcmcia_cleanup_ioctl(void) { return; }
+static inline void handle_event(struct pcmcia_socket *s, event_t event) { return; }
+static inline int handle_request(struct pcmcia_socket *s, event_t event) { return CS_SUCCESS; }
+#endif
diff --git a/drivers/pcmcia/hd64465_ss.c b/drivers/pcmcia/hd64465_ss.c
index 5ab55ae0ac36..316f8bcc878b 100644
--- a/drivers/pcmcia/hd64465_ss.c
+++ b/drivers/pcmcia/hd64465_ss.c
@@ -43,7 +43,6 @@
#include <asm/hd64465/hd64465.h>
#include <asm/hd64465/io.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
diff --git a/drivers/pcmcia/i82365.c b/drivers/pcmcia/i82365.c
index 90a335a5d9fa..a713015e8228 100644
--- a/drivers/pcmcia/i82365.c
+++ b/drivers/pcmcia/i82365.c
@@ -53,7 +53,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -669,11 +668,13 @@ static int __init is_alive(u_short sock)
if ((stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
(i365_get(sock, I365_INTCTL) & I365_PC_IOCARD) &&
(i365_get(sock, I365_ADDRWIN) & I365_ENA_IO(0)) &&
- (check_region(start, stop-start+1) != 0) &&
- ((start & 0xfeef) != 0x02e8))
- return 1;
- else
- return 0;
+ ((start & 0xfeef) != 0x02e8)) {
+ if (!request_region(start, stop-start+1, "i82365"))
+ return 1;
+ release_region(start, stop-start+1);
+ }
+
+ return 0;
}
/*====================================================================*/
@@ -696,8 +697,6 @@ static void __init add_pcic(int ns, int type)
struct i82365_socket *t = &socket[sockets-ns];
base = sockets-ns;
- if (t->ioaddr > 0) request_region(t->ioaddr, 2, "i82365");
-
if (base == 0) printk("\n");
printk(KERN_INFO " %s", pcic[type].name);
printk(" ISA-to-PCMCIA at port %#lx ofs 0x%02x",
@@ -803,7 +802,7 @@ static void __init isa_probe(void)
}
#endif
- if (check_region(i365_base, 2) != 0) {
+ if (!request_region(i365_base, 2, "i82365")) {
if (sockets == 0)
printk("port conflict at %#lx\n", i365_base);
return;
@@ -1441,6 +1440,7 @@ static void __exit exit_i82365(void)
i365_set(i, I365_CSCINT, 0);
release_region(socket[i].ioaddr, 2);
}
+ release_region(i365_base, 2);
#ifdef CONFIG_PNP
if (i82365_pnpdev)
pnp_disable_dev(i82365_pnpdev);
diff --git a/drivers/pcmcia/m32r_cfc.c b/drivers/pcmcia/m32r_cfc.c
index b1111c6bf062..65f3ee3d4d3c 100644
--- a/drivers/pcmcia/m32r_cfc.c
+++ b/drivers/pcmcia/m32r_cfc.c
@@ -29,7 +29,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/m32r_pcc.c b/drivers/pcmcia/m32r_pcc.c
index c0997c4714f0..7b14d7efd68c 100644
--- a/drivers/pcmcia/m32r_pcc.c
+++ b/drivers/pcmcia/m32r_pcc.c
@@ -30,7 +30,6 @@
#include <asm/system.h>
#include <asm/addrspace.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
diff --git a/drivers/pcmcia/pcmcia_compat.c b/drivers/pcmcia/pcmcia_compat.c
index 68b80084f83f..ebb161c4f819 100644
--- a/drivers/pcmcia/pcmcia_compat.c
+++ b/drivers/pcmcia/pcmcia_compat.c
@@ -18,7 +18,6 @@
#include <linux/init.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/bulkmem.h>
@@ -28,98 +27,39 @@
#include "cs_internal.h"
-int pcmcia_get_first_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_first_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_first_tuple(s, handle->Function, tuple);
+ return pccard_get_first_tuple(p_dev->socket, p_dev->func, tuple);
}
EXPORT_SYMBOL(pcmcia_get_first_tuple);
-int pcmcia_get_next_tuple(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_next_tuple(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_next_tuple(s, handle->Function, tuple);
+ return pccard_get_next_tuple(p_dev->socket, p_dev->func, tuple);
}
EXPORT_SYMBOL(pcmcia_get_next_tuple);
-int pcmcia_get_tuple_data(client_handle_t handle, tuple_t *tuple)
+int pcmcia_get_tuple_data(struct pcmcia_device *p_dev, tuple_t *tuple)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_tuple_data(s, tuple);
+ return pccard_get_tuple_data(p_dev->socket, tuple);
}
EXPORT_SYMBOL(pcmcia_get_tuple_data);
-int pcmcia_parse_tuple(client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+int pcmcia_parse_tuple(struct pcmcia_device *p_dev, tuple_t *tuple, cisparse_t *parse)
{
return pccard_parse_tuple(tuple, parse);
}
EXPORT_SYMBOL(pcmcia_parse_tuple);
-int pcmcia_validate_cis(client_handle_t handle, cisinfo_t *info)
+int pcmcia_validate_cis(struct pcmcia_device *p_dev, cisinfo_t *info)
{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_validate_cis(s, handle->Function, info);
+ return pccard_validate_cis(p_dev->socket, p_dev->func, info);
}
EXPORT_SYMBOL(pcmcia_validate_cis);
-int pcmcia_get_configuration_info(client_handle_t handle,
- config_info_t *config)
-{
- struct pcmcia_socket *s;
-
- if ((CHECK_HANDLE(handle)) || !config)
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- if (!s)
- return CS_BAD_HANDLE;
- return pccard_get_configuration_info(s, handle->Function, config);
-}
-EXPORT_SYMBOL(pcmcia_get_configuration_info);
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req)
{
- struct pcmcia_socket *skt;
-
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- skt = SOCKET(handle);
- if (!skt)
- return CS_BAD_HANDLE;
-
- return pccard_reset_card(skt);
+ return pccard_reset_card(p_dev->socket);
}
EXPORT_SYMBOL(pcmcia_reset_card);
-
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
-{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_get_status(s, handle->Function, status);
-}
-EXPORT_SYMBOL(pcmcia_get_status);
-
-int pcmcia_access_configuration_register(client_handle_t handle,
- conf_reg_t *reg)
-{
- struct pcmcia_socket *s;
- if (CHECK_HANDLE(handle))
- return CS_BAD_HANDLE;
- s = SOCKET(handle);
- return pccard_access_configuration_register(s, handle->Function, reg);
-}
-EXPORT_SYMBOL(pcmcia_access_configuration_register);
-
diff --git a/drivers/pcmcia/pcmcia_ioctl.c b/drivers/pcmcia/pcmcia_ioctl.c
new file mode 100644
index 000000000000..39ba6406fd54
--- /dev/null
+++ b/drivers/pcmcia/pcmcia_ioctl.c
@@ -0,0 +1,759 @@
+/*
+ * pcmcia_ioctl.c -- ioctl interface for cardmgr and cardctl
+ *
+ * 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.
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * (C) 1999 David A. Hinds
+ * (C) 2003 - 2004 Dominik Brodowski
+ */
+
+/*
+ * This file will go away soon.
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/major.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+#include <linux/pci.h>
+#include <linux/workqueue.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ss.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+static int major_dev = -1;
+
+
+/* Device user information */
+#define MAX_EVENTS 32
+#define USER_MAGIC 0x7ea4
+#define CHECK_USER(u) \
+ (((u) == NULL) || ((u)->user_magic != USER_MAGIC))
+
+typedef struct user_info_t {
+ u_int user_magic;
+ int event_head, event_tail;
+ event_t event[MAX_EVENTS];
+ struct user_info_t *next;
+ struct pcmcia_socket *socket;
+} user_info_t;
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt) ((skt)->dev.class_id)
+
+#define ds_dbg(lvl, fmt, arg...) do { \
+ if (ds_pc_debug >= lvl) \
+ printk(KERN_DEBUG "ds: " fmt , ## arg); \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+
+/* backwards-compatible accessing of driver --- by name! */
+
+static struct pcmcia_driver * get_pcmcia_driver (dev_info_t *dev_info)
+{
+ struct device_driver *drv;
+ struct pcmcia_driver *p_drv;
+
+ drv = driver_find((char *) dev_info, &pcmcia_bus_type);
+ if (!drv)
+ return NULL;
+
+ p_drv = container_of(drv, struct pcmcia_driver, drv);
+
+ return (p_drv);
+}
+
+
+#ifdef CONFIG_PROC_FS
+static struct proc_dir_entry *proc_pccard = NULL;
+
+static int proc_read_drivers_callback(struct device_driver *driver, void *d)
+{
+ char **p = d;
+ struct pcmcia_driver *p_drv = container_of(driver,
+ struct pcmcia_driver, drv);
+
+ *p += sprintf(*p, "%-24.24s 1 %d\n", p_drv->drv.name,
+#ifdef CONFIG_MODULE_UNLOAD
+ (p_drv->owner) ? module_refcount(p_drv->owner) : 1
+#else
+ 1
+#endif
+ );
+ d = (void *) p;
+
+ return 0;
+}
+
+static int proc_read_drivers(char *buf, char **start, off_t pos,
+ int count, int *eof, void *data)
+{
+ char *p = buf;
+
+ bus_for_each_drv(&pcmcia_bus_type, NULL,
+ (void *) &p, proc_read_drivers_callback);
+
+ return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+ These manage a ring buffer of events pending for one user process
+
+======================================================================*/
+
+
+static int queue_empty(user_info_t *user)
+{
+ return (user->event_head == user->event_tail);
+}
+
+static event_t get_queued_event(user_info_t *user)
+{
+ user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+ return user->event[user->event_tail];
+}
+
+static void queue_event(user_info_t *user, event_t event)
+{
+ user->event_head = (user->event_head+1) % MAX_EVENTS;
+ if (user->event_head == user->event_tail)
+ user->event_tail = (user->event_tail+1) % MAX_EVENTS;
+ user->event[user->event_head] = event;
+}
+
+void handle_event(struct pcmcia_socket *s, event_t event)
+{
+ user_info_t *user;
+ for (user = s->user; user; user = user->next)
+ queue_event(user, event);
+ wake_up_interruptible(&s->queue);
+}
+
+
+/*======================================================================
+
+ bind_request() and bind_device() are merged by now. Register_client()
+ is called right at the end of bind_request(), during the driver's
+ ->attach() call. Individual descriptions:
+
+ bind_request() connects a socket to a particular client driver.
+ It looks up the specified device ID in the list of registered
+ drivers, binds it to the socket, and tries to create an instance
+ of the device. unbind_request() deletes a driver instance.
+
+ Bind_device() associates a device driver with a particular socket.
+ It is normally called by Driver Services after it has identified
+ a newly inserted card. An instance of that driver will then be
+ eligible to register as a client of this socket.
+
+ Register_client() uses the dev_info_t handle to match the
+ caller with a socket. The driver must have already been bound
+ to a socket with bind_device() -- in fact, bind_device()
+ allocates the client structure that will be used.
+
+======================================================================*/
+
+static int bind_request(struct pcmcia_socket *s, bind_info_t *bind_info)
+{
+ struct pcmcia_driver *p_drv;
+ struct pcmcia_device *p_dev;
+ int ret = 0;
+ unsigned long flags;
+
+ s = pcmcia_get_socket(s);
+ if (!s)
+ return -EINVAL;
+
+ ds_dbg(2, "bind_request(%d, '%s')\n", s->sock,
+ (char *)bind_info->dev_info);
+
+ p_drv = get_pcmcia_driver(&bind_info->dev_info);
+ if (!p_drv) {
+ ret = -EINVAL;
+ goto err_put;
+ }
+
+ if (!try_module_get(p_drv->owner)) {
+ ret = -EINVAL;
+ goto err_put_driver;
+ }
+
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+ if (p_dev->func == bind_info->function) {
+ if ((p_dev->dev.driver == &p_drv->drv)) {
+ if (p_dev->cardmgr) {
+ /* if there's already a device
+ * registered, and it was registered
+ * by userspace before, we need to
+ * return the "instance". */
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ bind_info->instance = p_dev->instance;
+ ret = -EBUSY;
+ goto err_put_module;
+ } else {
+ /* the correct driver managed to bind
+ * itself magically to the correct
+ * device. */
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ p_dev->cardmgr = p_drv;
+ ret = 0;
+ goto err_put_module;
+ }
+ } else if (!p_dev->dev.driver) {
+ /* there's already a device available where
+ * no device has been bound to yet. So we don't
+ * need to register a device! */
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ goto rescan;
+ }
+ }
+ }
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ p_dev = pcmcia_device_add(s, bind_info->function);
+ if (!p_dev) {
+ ret = -EIO;
+ goto err_put_module;
+ }
+
+rescan:
+ p_dev->cardmgr = p_drv;
+
+ /* if a driver is already running, we can abort */
+ if (p_dev->dev.driver)
+ goto err_put_module;
+
+ /*
+ * Prevent this racing with a card insertion.
+ */
+ down(&s->skt_sem);
+ bus_rescan_devices(&pcmcia_bus_type);
+ up(&s->skt_sem);
+
+ /* check whether the driver indeed matched. I don't care if this
+ * is racy or not, because it can only happen on cardmgr access
+ * paths...
+ */
+ if (!(p_dev->dev.driver == &p_drv->drv))
+ p_dev->cardmgr = NULL;
+
+ err_put_module:
+ module_put(p_drv->owner);
+ err_put_driver:
+ put_driver(&p_drv->drv);
+ err_put:
+ pcmcia_put_socket(s);
+
+ return (ret);
+} /* bind_request */
+
+#ifdef CONFIG_CARDBUS
+
+static struct pci_bus *pcmcia_lookup_bus(struct pcmcia_socket *s)
+{
+ if (!s || !(s->state & SOCKET_CARDBUS))
+ return NULL;
+
+ return s->cb_dev->subordinate;
+}
+#endif
+
+static int get_device_info(struct pcmcia_socket *s, bind_info_t *bind_info, int first)
+{
+ dev_node_t *node;
+ struct pcmcia_device *p_dev;
+ unsigned long flags;
+ int ret = 0;
+
+#ifdef CONFIG_CARDBUS
+ /*
+ * Some unbelievably ugly code to associate the PCI cardbus
+ * device and its driver with the PCMCIA "bind" information.
+ */
+ {
+ struct pci_bus *bus;
+
+ bus = pcmcia_lookup_bus(s);
+ if (bus) {
+ struct list_head *list;
+ struct pci_dev *dev = NULL;
+
+ list = bus->devices.next;
+ while (list != &bus->devices) {
+ struct pci_dev *pdev = pci_dev_b(list);
+ list = list->next;
+
+ if (first) {
+ dev = pdev;
+ break;
+ }
+
+ /* Try to handle "next" here some way? */
+ }
+ if (dev && dev->driver) {
+ strlcpy(bind_info->name, dev->driver->name, DEV_NAME_LEN);
+ bind_info->major = 0;
+ bind_info->minor = 0;
+ bind_info->next = NULL;
+ return 0;
+ }
+ }
+ }
+#endif
+
+ spin_lock_irqsave(&pcmcia_dev_list_lock, flags);
+ list_for_each_entry(p_dev, &s->devices_list, socket_device_list) {
+ if (p_dev->func == bind_info->function) {
+ p_dev = pcmcia_get_dev(p_dev);
+ if (!p_dev)
+ continue;
+ goto found;
+ }
+ }
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+ return -ENODEV;
+
+ found:
+ spin_unlock_irqrestore(&pcmcia_dev_list_lock, flags);
+
+ if ((!p_dev->instance) ||
+ (p_dev->instance->state & DEV_CONFIG_PENDING)) {
+ ret = -EAGAIN;
+ goto err_put;
+ }
+
+ if (first)
+ node = p_dev->instance->dev;
+ else
+ for (node = p_dev->instance->dev; node; node = node->next)
+ if (node == bind_info->next)
+ break;
+ if (!node) {
+ ret = -ENODEV;
+ goto err_put;
+ }
+
+ strlcpy(bind_info->name, node->dev_name, DEV_NAME_LEN);
+ bind_info->major = node->major;
+ bind_info->minor = node->minor;
+ bind_info->next = node->next;
+
+ err_put:
+ pcmcia_put_dev(p_dev);
+ return (ret);
+} /* get_device_info */
+
+
+static int ds_open(struct inode *inode, struct file *file)
+{
+ socket_t i = iminor(inode);
+ struct pcmcia_socket *s;
+ user_info_t *user;
+
+ ds_dbg(0, "ds_open(socket %d)\n", i);
+
+ s = pcmcia_get_socket_by_nr(i);
+ if (!s)
+ return -ENODEV;
+ s = pcmcia_get_socket(s);
+ if (!s)
+ return -ENODEV;
+
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if (s->pcmcia_state.busy) {
+ pcmcia_put_socket(s);
+ return -EBUSY;
+ }
+ else
+ s->pcmcia_state.busy = 1;
+ }
+
+ user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+ if (!user) {
+ pcmcia_put_socket(s);
+ return -ENOMEM;
+ }
+ user->event_tail = user->event_head = 0;
+ user->next = s->user;
+ user->user_magic = USER_MAGIC;
+ user->socket = s;
+ s->user = user;
+ file->private_data = user;
+
+ if (s->pcmcia_state.present)
+ queue_event(user, CS_EVENT_CARD_INSERTION);
+ return 0;
+} /* ds_open */
+
+/*====================================================================*/
+
+static int ds_release(struct inode *inode, struct file *file)
+{
+ struct pcmcia_socket *s;
+ user_info_t *user, **link;
+
+ ds_dbg(0, "ds_release(socket %d)\n", iminor(inode));
+
+ user = file->private_data;
+ if (CHECK_USER(user))
+ goto out;
+
+ s = user->socket;
+
+ /* Unlink user data structure */
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ s->pcmcia_state.busy = 0;
+ }
+ file->private_data = NULL;
+ for (link = &s->user; *link; link = &(*link)->next)
+ if (*link == user) break;
+ if (link == NULL)
+ goto out;
+ *link = user->next;
+ user->user_magic = 0;
+ kfree(user);
+ pcmcia_put_socket(s);
+out:
+ return 0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct pcmcia_socket *s;
+ user_info_t *user;
+ int ret;
+
+ ds_dbg(2, "ds_read(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+ if (count < 4)
+ return -EINVAL;
+
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return -EIO;
+
+ s = user->socket;
+ if (s->pcmcia_state.dead)
+ return -EIO;
+
+ ret = wait_event_interruptible(s->queue, !queue_empty(user));
+ if (ret == 0)
+ ret = put_user(get_queued_event(user), (int __user *)buf) ? -EFAULT : 4;
+
+ return ret;
+} /* ds_read */
+
+/*====================================================================*/
+
+static ssize_t ds_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ ds_dbg(2, "ds_write(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+ if (count != 4)
+ return -EINVAL;
+ if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+ return -EBADF;
+
+ return -EIO;
+} /* ds_write */
+
+/*====================================================================*/
+
+/* No kernel lock - fine */
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+ struct pcmcia_socket *s;
+ user_info_t *user;
+
+ ds_dbg(2, "ds_poll(socket %d)\n", iminor(file->f_dentry->d_inode));
+
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return POLLERR;
+ s = user->socket;
+ /*
+ * We don't check for a dead socket here since that
+ * will send cardmgr into an endless spin.
+ */
+ poll_wait(file, &s->queue, wait);
+ if (!queue_empty(user))
+ return POLLIN | POLLRDNORM;
+ return 0;
+} /* ds_poll */
+
+/*====================================================================*/
+
+extern int pcmcia_adjust_resource_info(adjust_t *adj);
+
+static int ds_ioctl(struct inode * inode, struct file * file,
+ u_int cmd, u_long arg)
+{
+ struct pcmcia_socket *s;
+ void __user *uarg = (char __user *)arg;
+ u_int size;
+ int ret, err;
+ ds_ioctl_arg_t *buf;
+ user_info_t *user;
+
+ ds_dbg(2, "ds_ioctl(socket %d, %#x, %#lx)\n", iminor(inode), cmd, arg);
+
+ user = file->private_data;
+ if (CHECK_USER(user))
+ return -EIO;
+
+ s = user->socket;
+ if (s->pcmcia_state.dead)
+ return -EIO;
+
+ size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+ if (size > sizeof(ds_ioctl_arg_t)) return -EINVAL;
+
+ /* Permission check */
+ if (!(cmd & IOC_OUT) && !capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (cmd & IOC_IN) {
+ if (!access_ok(VERIFY_READ, uarg, size)) {
+ ds_dbg(3, "ds_ioctl(): verify_read = %d\n", -EFAULT);
+ return -EFAULT;
+ }
+ }
+ if (cmd & IOC_OUT) {
+ if (!access_ok(VERIFY_WRITE, uarg, size)) {
+ ds_dbg(3, "ds_ioctl(): verify_write = %d\n", -EFAULT);
+ return -EFAULT;
+ }
+ }
+ buf = kmalloc(sizeof(ds_ioctl_arg_t), GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ err = ret = 0;
+
+ if (cmd & IOC_IN) __copy_from_user((char *)buf, uarg, size);
+
+ switch (cmd) {
+ case DS_ADJUST_RESOURCE_INFO:
+ ret = pcmcia_adjust_resource_info(&buf->adjust);
+ break;
+ case DS_GET_CONFIGURATION_INFO:
+ if (buf->config.Function &&
+ (buf->config.Function >= s->functions))
+ ret = CS_BAD_ARGS;
+ else
+ ret = pccard_get_configuration_info(s,
+ buf->config.Function, &buf->config);
+ break;
+ case DS_GET_FIRST_TUPLE:
+ down(&s->skt_sem);
+ pcmcia_validate_mem(s);
+ up(&s->skt_sem);
+ ret = pccard_get_first_tuple(s, BIND_FN_ALL, &buf->tuple);
+ break;
+ case DS_GET_NEXT_TUPLE:
+ ret = pccard_get_next_tuple(s, BIND_FN_ALL, &buf->tuple);
+ break;
+ case DS_GET_TUPLE_DATA:
+ buf->tuple.TupleData = buf->tuple_parse.data;
+ buf->tuple.TupleDataMax = sizeof(buf->tuple_parse.data);
+ ret = pccard_get_tuple_data(s, &buf->tuple);
+ break;
+ case DS_PARSE_TUPLE:
+ buf->tuple.TupleData = buf->tuple_parse.data;
+ ret = pccard_parse_tuple(&buf->tuple, &buf->tuple_parse.parse);
+ break;
+ case DS_RESET_CARD:
+ ret = pccard_reset_card(s);
+ break;
+ case DS_GET_STATUS:
+ if (buf->status.Function &&
+ (buf->status.Function >= s->functions))
+ ret = CS_BAD_ARGS;
+ else
+ ret = pccard_get_status(s, buf->status.Function, &buf->status);
+ break;
+ case DS_VALIDATE_CIS:
+ down(&s->skt_sem);
+ pcmcia_validate_mem(s);
+ up(&s->skt_sem);
+ ret = pccard_validate_cis(s, BIND_FN_ALL, &buf->cisinfo);
+ break;
+ case DS_SUSPEND_CARD:
+ ret = pcmcia_suspend_card(s);
+ break;
+ case DS_RESUME_CARD:
+ ret = pcmcia_resume_card(s);
+ break;
+ case DS_EJECT_CARD:
+ err = pcmcia_eject_card(s);
+ break;
+ case DS_INSERT_CARD:
+ err = pcmcia_insert_card(s);
+ break;
+ case DS_ACCESS_CONFIGURATION_REGISTER:
+ if ((buf->conf_reg.Action == CS_WRITE) && !capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto free_out;
+ }
+ if (buf->conf_reg.Function &&
+ (buf->conf_reg.Function >= s->functions))
+ ret = CS_BAD_ARGS;
+ else
+ ret = pccard_access_configuration_register(s,
+ buf->conf_reg.Function, &buf->conf_reg);
+ break;
+ case DS_GET_FIRST_REGION:
+ case DS_GET_NEXT_REGION:
+ case DS_BIND_MTD:
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto free_out;
+ } else {
+ static int printed = 0;
+ if (!printed) {
+ printk(KERN_WARNING "2.6. kernels use pcmciamtd instead of memory_cs.c and do not require special\n");
+ printk(KERN_WARNING "MTD handling any more.\n");
+ printed++;
+ }
+ }
+ err = -EINVAL;
+ goto free_out;
+ break;
+ case DS_GET_FIRST_WINDOW:
+ ret = pcmcia_get_window(s, &buf->win_info.handle, 0,
+ &buf->win_info.window);
+ break;
+ case DS_GET_NEXT_WINDOW:
+ ret = pcmcia_get_window(s, &buf->win_info.handle,
+ buf->win_info.handle->index + 1, &buf->win_info.window);
+ break;
+ case DS_GET_MEM_PAGE:
+ ret = pcmcia_get_mem_page(buf->win_info.handle,
+ &buf->win_info.map);
+ break;
+ case DS_REPLACE_CIS:
+ ret = pcmcia_replace_cis(s, &buf->cisdump);
+ break;
+ case DS_BIND_REQUEST:
+ if (!capable(CAP_SYS_ADMIN)) {
+ err = -EPERM;
+ goto free_out;
+ }
+ err = bind_request(s, &buf->bind_info);
+ break;
+ case DS_GET_DEVICE_INFO:
+ err = get_device_info(s, &buf->bind_info, 1);
+ break;
+ case DS_GET_NEXT_DEVICE:
+ err = get_device_info(s, &buf->bind_info, 0);
+ break;
+ case DS_UNBIND_REQUEST:
+ err = 0;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ if ((err == 0) && (ret != CS_SUCCESS)) {
+ ds_dbg(2, "ds_ioctl: ret = %d\n", ret);
+ switch (ret) {
+ case CS_BAD_SOCKET: case CS_NO_CARD:
+ err = -ENODEV; break;
+ case CS_BAD_ARGS: case CS_BAD_ATTRIBUTE: case CS_BAD_IRQ:
+ case CS_BAD_TUPLE:
+ err = -EINVAL; break;
+ case CS_IN_USE:
+ err = -EBUSY; break;
+ case CS_OUT_OF_RESOURCE:
+ err = -ENOSPC; break;
+ case CS_NO_MORE_ITEMS:
+ err = -ENODATA; break;
+ case CS_UNSUPPORTED_FUNCTION:
+ err = -ENOSYS; break;
+ default:
+ err = -EIO; break;
+ }
+ }
+
+ if (cmd & IOC_OUT) {
+ if (__copy_to_user(uarg, (char *)buf, size))
+ err = -EFAULT;
+ }
+
+free_out:
+ kfree(buf);
+ return err;
+} /* ds_ioctl */
+
+/*====================================================================*/
+
+static struct file_operations ds_fops = {
+ .owner = THIS_MODULE,
+ .open = ds_open,
+ .release = ds_release,
+ .ioctl = ds_ioctl,
+ .read = ds_read,
+ .write = ds_write,
+ .poll = ds_poll,
+};
+
+void __init pcmcia_setup_ioctl(void) {
+ int i;
+
+ /* Set up character device for user mode clients */
+ i = register_chrdev(0, "pcmcia", &ds_fops);
+ if (i < 0)
+ printk(KERN_NOTICE "unable to find a free device # for "
+ "Driver Services (error=%d)\n", i);
+ else
+ major_dev = i;
+
+#ifdef CONFIG_PROC_FS
+ proc_pccard = proc_mkdir("pccard", proc_bus);
+ if (proc_pccard)
+ create_proc_read_entry("drivers",0,proc_pccard,proc_read_drivers,NULL);
+#endif
+}
+
+
+void __exit pcmcia_cleanup_ioctl(void) {
+#ifdef CONFIG_PROC_FS
+ if (proc_pccard) {
+ remove_proc_entry("drivers", proc_pccard);
+ remove_proc_entry("pccard", proc_bus);
+ }
+#endif
+ if (major_dev != -1)
+ unregister_chrdev(major_dev, "pcmcia");
+}
diff --git a/drivers/pcmcia/pcmcia_resource.c b/drivers/pcmcia/pcmcia_resource.c
new file mode 100644
index 000000000000..184f4f88b2a0
--- /dev/null
+++ b/drivers/pcmcia/pcmcia_resource.c
@@ -0,0 +1,943 @@
+/*
+ * PCMCIA 16-bit resource management functions
+ *
+ * The initial developer of the original code is David A. Hinds
+ * <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
+ * are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
+ *
+ * Copyright (C) 1999 David A. Hinds
+ * Copyright (C) 2004-2005 Dominik Brodowski
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/device.h>
+
+#define IN_CARD_SERVICES
+#include <pcmcia/cs_types.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "cs_internal.h"
+#include "ds_internal.h"
+
+
+/* Access speed for IO windows */
+static int io_speed = 0;
+module_param(io_speed, int, 0444);
+
+
+#ifdef CONFIG_PCMCIA_PROBE
+/* mask of IRQs already reserved by other cards, we should avoid using them */
+static u8 pcmcia_used_irq[NR_IRQS];
+#endif
+
+
+#ifdef DEBUG
+extern int ds_pc_debug;
+#define cs_socket_name(skt) ((skt)->dev.class_id)
+
+#define ds_dbg(skt, lvl, fmt, arg...) do { \
+ if (ds_pc_debug >= lvl) \
+ printk(KERN_DEBUG "pcmcia_resource: %s: " fmt, \
+ cs_socket_name(skt) , ## arg); \
+} while (0)
+#else
+#define ds_dbg(lvl, fmt, arg...) do { } while (0)
+#endif
+
+
+
+/** alloc_io_space
+ *
+ * Special stuff for managing IO windows, because they are scarce
+ */
+
+static int alloc_io_space(struct pcmcia_socket *s, u_int attr, ioaddr_t *base,
+ ioaddr_t num, u_int lines)
+{
+ int i;
+ kio_addr_t try, align;
+
+ align = (*base) ? (lines ? 1<<lines : 0) : 1;
+ if (align && (align < num)) {
+ if (*base) {
+ ds_dbg(s, 0, "odd IO request: num %#x align %#lx\n",
+ num, align);
+ align = 0;
+ } else
+ while (align && (align < num)) align <<= 1;
+ }
+ if (*base & ~(align-1)) {
+ ds_dbg(s, 0, "odd IO request: base %#x align %#lx\n",
+ *base, align);
+ align = 0;
+ }
+ if ((s->features & SS_CAP_STATIC_MAP) && s->io_offset) {
+ *base = s->io_offset | (*base & 0x0fff);
+ s->io[0].Attributes = attr;
+ return 0;
+ }
+ /* Check for an already-allocated window that must conflict with
+ * what was asked for. It is a hack because it does not catch all
+ * potential conflicts, just the most obvious ones.
+ */
+ for (i = 0; i < MAX_IO_WIN; i++)
+ if ((s->io[i].NumPorts != 0) &&
+ ((s->io[i].BasePort & (align-1)) == *base))
+ return 1;
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (s->io[i].NumPorts == 0) {
+ s->io[i].res = pcmcia_find_io_region(*base, num, align, s);
+ if (s->io[i].res) {
+ s->io[i].Attributes = attr;
+ s->io[i].BasePort = *base = s->io[i].res->start;
+ s->io[i].NumPorts = s->io[i].InUse = num;
+ break;
+ } else
+ return 1;
+ } else if (s->io[i].Attributes != attr)
+ continue;
+ /* Try to extend top of window */
+ try = s->io[i].BasePort + s->io[i].NumPorts;
+ if ((*base == 0) || (*base == try))
+ if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start,
+ s->io[i].res->end + num, s) == 0) {
+ *base = try;
+ s->io[i].NumPorts += num;
+ s->io[i].InUse += num;
+ break;
+ }
+ /* Try to extend bottom of window */
+ try = s->io[i].BasePort - num;
+ if ((*base == 0) || (*base == try))
+ if (pcmcia_adjust_io_region(s->io[i].res, s->io[i].res->start - num,
+ s->io[i].res->end, s) == 0) {
+ s->io[i].BasePort = *base = try;
+ s->io[i].NumPorts += num;
+ s->io[i].InUse += num;
+ break;
+ }
+ }
+ return (i == MAX_IO_WIN);
+} /* alloc_io_space */
+
+
+static void release_io_space(struct pcmcia_socket *s, ioaddr_t base,
+ ioaddr_t num)
+{
+ int i;
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if ((s->io[i].BasePort <= base) &&
+ (s->io[i].BasePort+s->io[i].NumPorts >= base+num)) {
+ s->io[i].InUse -= num;
+ /* Free the window if no one else is using it */
+ if (s->io[i].InUse == 0) {
+ s->io[i].NumPorts = 0;
+ release_resource(s->io[i].res);
+ kfree(s->io[i].res);
+ s->io[i].res = NULL;
+ }
+ }
+ }
+} /* release_io_space */
+
+
+/** pccard_access_configuration_register
+ *
+ * Access_configuration_register() reads and writes configuration
+ * registers in attribute memory. Memory window 0 is reserved for
+ * this and the tuple reading services.
+ */
+
+int pccard_access_configuration_register(struct pcmcia_socket *s,
+ unsigned int function,
+ conf_reg_t *reg)
+{
+ config_t *c;
+ int addr;
+ u_char val;
+
+ if (!s || !s->config)
+ return CS_NO_CARD;
+
+ c = &s->config[function];
+
+ if (c == NULL)
+ return CS_NO_CARD;
+
+ if (!(c->state & CONFIG_LOCKED))
+ return CS_CONFIGURATION_LOCKED;
+
+ addr = (c->ConfigBase + reg->Offset) >> 1;
+
+ switch (reg->Action) {
+ case CS_READ:
+ pcmcia_read_cis_mem(s, 1, addr, 1, &val);
+ reg->Value = val;
+ break;
+ case CS_WRITE:
+ val = reg->Value;
+ pcmcia_write_cis_mem(s, 1, addr, 1, &val);
+ break;
+ default:
+ return CS_BAD_ARGS;
+ break;
+ }
+ return CS_SUCCESS;
+} /* pccard_access_configuration_register */
+
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev,
+ conf_reg_t *reg)
+{
+ return pccard_access_configuration_register(p_dev->socket,
+ p_dev->func, reg);
+}
+EXPORT_SYMBOL(pcmcia_access_configuration_register);
+
+
+
+int pccard_get_configuration_info(struct pcmcia_socket *s,
+ unsigned int function,
+ config_info_t *config)
+{
+ config_t *c;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ config->Function = function;
+
+#ifdef CONFIG_CARDBUS
+ if (s->state & SOCKET_CARDBUS) {
+ memset(config, 0, sizeof(config_info_t));
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ config->Option = s->cb_dev->subordinate->number;
+ if (s->state & SOCKET_CARDBUS_CONFIG) {
+ config->Attributes = CONF_VALID_CLIENT;
+ config->IntType = INT_CARDBUS;
+ config->AssignedIRQ = s->irq.AssignedIRQ;
+ if (config->AssignedIRQ)
+ config->Attributes |= CONF_ENABLE_IRQ;
+ config->BasePort1 = s->io[0].BasePort;
+ config->NumPorts1 = s->io[0].NumPorts;
+ }
+ return CS_SUCCESS;
+ }
+#endif
+
+ c = (s->config != NULL) ? &s->config[function] : NULL;
+
+ if ((c == NULL) || !(c->state & CONFIG_LOCKED)) {
+ config->Attributes = 0;
+ config->Vcc = s->socket.Vcc;
+ config->Vpp1 = config->Vpp2 = s->socket.Vpp;
+ return CS_SUCCESS;
+ }
+
+ /* !!! This is a hack !!! */
+ memcpy(&config->Attributes, &c->Attributes, sizeof(config_t));
+ config->Attributes |= CONF_VALID_CLIENT;
+ config->CardValues = c->CardValues;
+ config->IRQAttributes = c->irq.Attributes;
+ config->AssignedIRQ = s->irq.AssignedIRQ;
+ config->BasePort1 = c->io.BasePort1;
+ config->NumPorts1 = c->io.NumPorts1;
+ config->Attributes1 = c->io.Attributes1;
+ config->BasePort2 = c->io.BasePort2;
+ config->NumPorts2 = c->io.NumPorts2;
+ config->Attributes2 = c->io.Attributes2;
+ config->IOAddrLines = c->io.IOAddrLines;
+
+ return CS_SUCCESS;
+} /* pccard_get_configuration_info */
+
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev,
+ config_info_t *config)
+{
+ return pccard_get_configuration_info(p_dev->socket, p_dev->func,
+ config);
+}
+EXPORT_SYMBOL(pcmcia_get_configuration_info);
+
+
+/** pcmcia_get_window
+ */
+int pcmcia_get_window(struct pcmcia_socket *s, window_handle_t *handle,
+ int idx, win_req_t *req)
+{
+ window_t *win;
+ int w;
+
+ if (!s || !(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ for (w = idx; w < MAX_WIN; w++)
+ if (s->state & SOCKET_WIN_REQ(w))
+ break;
+ if (w == MAX_WIN)
+ return CS_NO_MORE_ITEMS;
+ win = &s->win[w];
+ req->Base = win->ctl.res->start;
+ req->Size = win->ctl.res->end - win->ctl.res->start + 1;
+ req->AccessSpeed = win->ctl.speed;
+ req->Attributes = 0;
+ if (win->ctl.flags & MAP_ATTRIB)
+ req->Attributes |= WIN_MEMORY_TYPE_AM;
+ if (win->ctl.flags & MAP_ACTIVE)
+ req->Attributes |= WIN_ENABLE;
+ if (win->ctl.flags & MAP_16BIT)
+ req->Attributes |= WIN_DATA_WIDTH_16;
+ if (win->ctl.flags & MAP_USE_WAIT)
+ req->Attributes |= WIN_USE_WAIT;
+ *handle = win;
+ return CS_SUCCESS;
+} /* pcmcia_get_window */
+EXPORT_SYMBOL(pcmcia_get_window);
+
+
+/** pccard_get_status
+ *
+ * Get the current socket state bits. We don't support the latched
+ * SocketState yet: I haven't seen any point for it.
+ */
+
+int pccard_get_status(struct pcmcia_socket *s, unsigned int function,
+ cs_status_t *status)
+{
+ config_t *c;
+ int val;
+
+ s->ops->get_status(s, &val);
+ status->CardState = status->SocketState = 0;
+ status->CardState |= (val & SS_DETECT) ? CS_EVENT_CARD_DETECT : 0;
+ status->CardState |= (val & SS_CARDBUS) ? CS_EVENT_CB_DETECT : 0;
+ status->CardState |= (val & SS_3VCARD) ? CS_EVENT_3VCARD : 0;
+ status->CardState |= (val & SS_XVCARD) ? CS_EVENT_XVCARD : 0;
+ if (s->state & SOCKET_SUSPEND)
+ status->CardState |= CS_EVENT_PM_SUSPEND;
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ c = (s->config != NULL) ? &s->config[function] : NULL;
+ if ((c != NULL) && (c->state & CONFIG_LOCKED) &&
+ (c->IntType & (INT_MEMORY_AND_IO | INT_ZOOMED_VIDEO))) {
+ u_char reg;
+ if (c->Present & PRESENT_PIN_REPLACE) {
+ pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_PRR)>>1, 1, &reg);
+ status->CardState |=
+ (reg & PRR_WP_STATUS) ? CS_EVENT_WRITE_PROTECT : 0;
+ status->CardState |=
+ (reg & PRR_READY_STATUS) ? CS_EVENT_READY_CHANGE : 0;
+ status->CardState |=
+ (reg & PRR_BVD2_STATUS) ? CS_EVENT_BATTERY_LOW : 0;
+ status->CardState |=
+ (reg & PRR_BVD1_STATUS) ? CS_EVENT_BATTERY_DEAD : 0;
+ } else {
+ /* No PRR? Then assume we're always ready */
+ status->CardState |= CS_EVENT_READY_CHANGE;
+ }
+ if (c->Present & PRESENT_EXT_STATUS) {
+ pcmcia_read_cis_mem(s, 1, (c->ConfigBase+CISREG_ESR)>>1, 1, &reg);
+ status->CardState |=
+ (reg & ESR_REQ_ATTN) ? CS_EVENT_REQUEST_ATTENTION : 0;
+ }
+ return CS_SUCCESS;
+ }
+ status->CardState |=
+ (val & SS_WRPROT) ? CS_EVENT_WRITE_PROTECT : 0;
+ status->CardState |=
+ (val & SS_BATDEAD) ? CS_EVENT_BATTERY_DEAD : 0;
+ status->CardState |=
+ (val & SS_BATWARN) ? CS_EVENT_BATTERY_LOW : 0;
+ status->CardState |=
+ (val & SS_READY) ? CS_EVENT_READY_CHANGE : 0;
+ return CS_SUCCESS;
+} /* pccard_get_status */
+
+int pcmcia_get_status(client_handle_t handle, cs_status_t *status)
+{
+ struct pcmcia_socket *s;
+ s = SOCKET(handle);
+ return pccard_get_status(s, handle->func, status);
+}
+EXPORT_SYMBOL(pcmcia_get_status);
+
+
+
+/** pcmcia_get_mem_page
+ *
+ * Change the card address of an already open memory window.
+ */
+int pcmcia_get_mem_page(window_handle_t win, memreq_t *req)
+{
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ req->Page = 0;
+ req->CardOffset = win->ctl.card_start;
+ return CS_SUCCESS;
+} /* pcmcia_get_mem_page */
+EXPORT_SYMBOL(pcmcia_get_mem_page);
+
+
+int pcmcia_map_mem_page(window_handle_t win, memreq_t *req)
+{
+ struct pcmcia_socket *s;
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ if (req->Page != 0)
+ return CS_BAD_PAGE;
+ s = win->sock;
+ win->ctl.card_start = req->CardOffset;
+ if (s->ops->set_mem_map(s, &win->ctl) != 0)
+ return CS_BAD_OFFSET;
+ return CS_SUCCESS;
+} /* pcmcia_map_mem_page */
+EXPORT_SYMBOL(pcmcia_map_mem_page);
+
+
+/** pcmcia_modify_configuration
+ *
+ * Modify a locked socket configuration
+ */
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev,
+ modconf_t *mod)
+{
+ struct pcmcia_socket *s;
+ config_t *c;
+
+ s = p_dev->socket;
+ c = CONFIG(p_dev);
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (!(c->state & CONFIG_LOCKED))
+ return CS_CONFIGURATION_LOCKED;
+
+ if (mod->Attributes & CONF_IRQ_CHANGE_VALID) {
+ if (mod->Attributes & CONF_ENABLE_IRQ) {
+ c->Attributes |= CONF_ENABLE_IRQ;
+ s->socket.io_irq = s->irq.AssignedIRQ;
+ } else {
+ c->Attributes &= ~CONF_ENABLE_IRQ;
+ s->socket.io_irq = 0;
+ }
+ s->ops->set_socket(s, &s->socket);
+ }
+
+ if (mod->Attributes & CONF_VCC_CHANGE_VALID)
+ return CS_BAD_VCC;
+
+ /* We only allow changing Vpp1 and Vpp2 to the same value */
+ if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) &&
+ (mod->Attributes & CONF_VPP2_CHANGE_VALID)) {
+ if (mod->Vpp1 != mod->Vpp2)
+ return CS_BAD_VPP;
+ c->Vpp1 = c->Vpp2 = s->socket.Vpp = mod->Vpp1;
+ if (s->ops->set_socket(s, &s->socket))
+ return CS_BAD_VPP;
+ } else if ((mod->Attributes & CONF_VPP1_CHANGE_VALID) ||
+ (mod->Attributes & CONF_VPP2_CHANGE_VALID))
+ return CS_BAD_VPP;
+
+ return CS_SUCCESS;
+} /* modify_configuration */
+EXPORT_SYMBOL(pcmcia_modify_configuration);
+
+
+int pcmcia_release_configuration(struct pcmcia_device *p_dev)
+{
+ pccard_io_map io = { 0, 0, 0, 0, 1 };
+ struct pcmcia_socket *s = p_dev->socket;
+ int i;
+
+ if (!(p_dev->state & CLIENT_CONFIG_LOCKED))
+ return CS_BAD_HANDLE;
+ p_dev->state &= ~CLIENT_CONFIG_LOCKED;
+
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
+ if (--(s->lock_count) == 0) {
+ s->socket.flags = SS_OUTPUT_ENA; /* Is this correct? */
+ s->socket.Vpp = 0;
+ s->socket.io_irq = 0;
+ s->ops->set_socket(s, &s->socket);
+ }
+ if (c->state & CONFIG_IO_REQ)
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (s->io[i].NumPorts == 0)
+ continue;
+ s->io[i].Config--;
+ if (s->io[i].Config != 0)
+ continue;
+ io.map = i;
+ s->ops->set_io_map(s, &io);
+ }
+ c->state &= ~CONFIG_LOCKED;
+ }
+
+ return CS_SUCCESS;
+} /* pcmcia_release_configuration */
+EXPORT_SYMBOL(pcmcia_release_configuration);
+
+
+/** pcmcia_release_io
+ *
+ * Release_io() releases the I/O ranges allocated by a client. This
+ * may be invoked some time after a card ejection has already dumped
+ * the actual socket configuration, so if the client is "stale", we
+ * don't bother checking the port ranges against the current socket
+ * values.
+ */
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req)
+{
+ struct pcmcia_socket *s = p_dev->socket;
+
+ if (!(p_dev->state & CLIENT_IO_REQ))
+ return CS_BAD_HANDLE;
+ p_dev->state &= ~CLIENT_IO_REQ;
+
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if ((c->io.BasePort1 != req->BasePort1) ||
+ (c->io.NumPorts1 != req->NumPorts1) ||
+ (c->io.BasePort2 != req->BasePort2) ||
+ (c->io.NumPorts2 != req->NumPorts2))
+ return CS_BAD_ARGS;
+ c->state &= ~CONFIG_IO_REQ;
+ }
+
+ release_io_space(s, req->BasePort1, req->NumPorts1);
+ if (req->NumPorts2)
+ release_io_space(s, req->BasePort2, req->NumPorts2);
+
+ return CS_SUCCESS;
+} /* pcmcia_release_io */
+EXPORT_SYMBOL(pcmcia_release_io);
+
+
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req)
+{
+ struct pcmcia_socket *s = p_dev->socket;
+ if (!(p_dev->state & CLIENT_IRQ_REQ))
+ return CS_BAD_HANDLE;
+ p_dev->state &= ~CLIENT_IRQ_REQ;
+
+ if (!(p_dev->state & CLIENT_STALE)) {
+ config_t *c = CONFIG(p_dev);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->irq.Attributes != req->Attributes)
+ return CS_BAD_ATTRIBUTE;
+ if (s->irq.AssignedIRQ != req->AssignedIRQ)
+ return CS_BAD_IRQ;
+ if (--s->irq.Config == 0) {
+ c->state &= ~CONFIG_IRQ_REQ;
+ s->irq.AssignedIRQ = 0;
+ }
+ }
+
+ if (req->Attributes & IRQ_HANDLE_PRESENT) {
+ free_irq(req->AssignedIRQ, req->Instance);
+ }
+
+#ifdef CONFIG_PCMCIA_PROBE
+ pcmcia_used_irq[req->AssignedIRQ]--;
+#endif
+
+ return CS_SUCCESS;
+} /* pcmcia_release_irq */
+EXPORT_SYMBOL(pcmcia_release_irq);
+
+
+int pcmcia_release_window(window_handle_t win)
+{
+ struct pcmcia_socket *s;
+
+ if ((win == NULL) || (win->magic != WINDOW_MAGIC))
+ return CS_BAD_HANDLE;
+ s = win->sock;
+ if (!(win->handle->state & CLIENT_WIN_REQ(win->index)))
+ return CS_BAD_HANDLE;
+
+ /* Shut down memory window */
+ win->ctl.flags &= ~MAP_ACTIVE;
+ s->ops->set_mem_map(s, &win->ctl);
+ s->state &= ~SOCKET_WIN_REQ(win->index);
+
+ /* Release system memory */
+ if (win->ctl.res) {
+ release_resource(win->ctl.res);
+ kfree(win->ctl.res);
+ win->ctl.res = NULL;
+ }
+ win->handle->state &= ~CLIENT_WIN_REQ(win->index);
+
+ win->magic = 0;
+
+ return CS_SUCCESS;
+} /* pcmcia_release_window */
+EXPORT_SYMBOL(pcmcia_release_window);
+
+
+int pcmcia_request_configuration(struct pcmcia_device *p_dev,
+ config_req_t *req)
+{
+ int i;
+ u_int base;
+ struct pcmcia_socket *s = p_dev->socket;
+ config_t *c;
+ pccard_io_map iomap;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ if (req->IntType & INT_CARDBUS)
+ return CS_UNSUPPORTED_MODE;
+ c = CONFIG(p_dev);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+
+ /* Do power control. We don't allow changes in Vcc. */
+ if (s->socket.Vcc != req->Vcc)
+ return CS_BAD_VCC;
+ if (req->Vpp1 != req->Vpp2)
+ return CS_BAD_VPP;
+ s->socket.Vpp = req->Vpp1;
+ if (s->ops->set_socket(s, &s->socket))
+ return CS_BAD_VPP;
+
+ c->Vcc = req->Vcc; c->Vpp1 = c->Vpp2 = req->Vpp1;
+
+ /* Pick memory or I/O card, DMA mode, interrupt */
+ c->IntType = req->IntType;
+ c->Attributes = req->Attributes;
+ if (req->IntType & INT_MEMORY_AND_IO)
+ s->socket.flags |= SS_IOCARD;
+ if (req->IntType & INT_ZOOMED_VIDEO)
+ s->socket.flags |= SS_ZVCARD | SS_IOCARD;
+ if (req->Attributes & CONF_ENABLE_DMA)
+ s->socket.flags |= SS_DMA_MODE;
+ if (req->Attributes & CONF_ENABLE_SPKR)
+ s->socket.flags |= SS_SPKR_ENA;
+ if (req->Attributes & CONF_ENABLE_IRQ)
+ s->socket.io_irq = s->irq.AssignedIRQ;
+ else
+ s->socket.io_irq = 0;
+ s->ops->set_socket(s, &s->socket);
+ s->lock_count++;
+
+ /* Set up CIS configuration registers */
+ base = c->ConfigBase = req->ConfigBase;
+ c->Present = c->CardValues = req->Present;
+ if (req->Present & PRESENT_COPY) {
+ c->Copy = req->Copy;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_SCR)>>1, 1, &c->Copy);
+ }
+ if (req->Present & PRESENT_OPTION) {
+ if (s->functions == 1) {
+ c->Option = req->ConfigIndex & COR_CONFIG_MASK;
+ } else {
+ c->Option = req->ConfigIndex & COR_MFC_CONFIG_MASK;
+ c->Option |= COR_FUNC_ENA|COR_IREQ_ENA;
+ if (req->Present & PRESENT_IOBASE_0)
+ c->Option |= COR_ADDR_DECODE;
+ }
+ if (c->state & CONFIG_IRQ_REQ)
+ if (!(c->irq.Attributes & IRQ_FORCED_PULSE))
+ c->Option |= COR_LEVEL_REQ;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_COR)>>1, 1, &c->Option);
+ mdelay(40);
+ }
+ if (req->Present & PRESENT_STATUS) {
+ c->Status = req->Status;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_CCSR)>>1, 1, &c->Status);
+ }
+ if (req->Present & PRESENT_PIN_REPLACE) {
+ c->Pin = req->Pin;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_PRR)>>1, 1, &c->Pin);
+ }
+ if (req->Present & PRESENT_EXT_STATUS) {
+ c->ExtStatus = req->ExtStatus;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_ESR)>>1, 1, &c->ExtStatus);
+ }
+ if (req->Present & PRESENT_IOBASE_0) {
+ u_char b = c->io.BasePort1 & 0xff;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_0)>>1, 1, &b);
+ b = (c->io.BasePort1 >> 8) & 0xff;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_IOBASE_1)>>1, 1, &b);
+ }
+ if (req->Present & PRESENT_IOSIZE) {
+ u_char b = c->io.NumPorts1 + c->io.NumPorts2 - 1;
+ pcmcia_write_cis_mem(s, 1, (base + CISREG_IOSIZE)>>1, 1, &b);
+ }
+
+ /* Configure I/O windows */
+ if (c->state & CONFIG_IO_REQ) {
+ iomap.speed = io_speed;
+ for (i = 0; i < MAX_IO_WIN; i++)
+ if (s->io[i].NumPorts != 0) {
+ iomap.map = i;
+ iomap.flags = MAP_ACTIVE;
+ switch (s->io[i].Attributes & IO_DATA_PATH_WIDTH) {
+ case IO_DATA_PATH_WIDTH_16:
+ iomap.flags |= MAP_16BIT; break;
+ case IO_DATA_PATH_WIDTH_AUTO:
+ iomap.flags |= MAP_AUTOSZ; break;
+ default:
+ break;
+ }
+ iomap.start = s->io[i].BasePort;
+ iomap.stop = iomap.start + s->io[i].NumPorts - 1;
+ s->ops->set_io_map(s, &iomap);
+ s->io[i].Config++;
+ }
+ }
+
+ c->state |= CONFIG_LOCKED;
+ p_dev->state |= CLIENT_CONFIG_LOCKED;
+ return CS_SUCCESS;
+} /* pcmcia_request_configuration */
+EXPORT_SYMBOL(pcmcia_request_configuration);
+
+
+/** pcmcia_request_io
+ *
+ * Request_io() reserves ranges of port addresses for a socket.
+ * I have not implemented range sharing or alias addressing.
+ */
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req)
+{
+ struct pcmcia_socket *s = p_dev->socket;
+ config_t *c;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+
+ if (!req)
+ return CS_UNSUPPORTED_MODE;
+ c = CONFIG(p_dev);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->state & CONFIG_IO_REQ)
+ return CS_IN_USE;
+ if (req->Attributes1 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS))
+ return CS_BAD_ATTRIBUTE;
+ if ((req->NumPorts2 > 0) &&
+ (req->Attributes2 & (IO_SHARED | IO_FORCE_ALIAS_ACCESS)))
+ return CS_BAD_ATTRIBUTE;
+
+ if (alloc_io_space(s, req->Attributes1, &req->BasePort1,
+ req->NumPorts1, req->IOAddrLines))
+ return CS_IN_USE;
+
+ if (req->NumPorts2) {
+ if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+ req->NumPorts2, req->IOAddrLines)) {
+ release_io_space(s, req->BasePort1, req->NumPorts1);
+ return CS_IN_USE;
+ }
+ }
+
+ c->io = *req;
+ c->state |= CONFIG_IO_REQ;
+ p_dev->state |= CLIENT_IO_REQ;
+ return CS_SUCCESS;
+} /* pcmcia_request_io */
+EXPORT_SYMBOL(pcmcia_request_io);
+
+
+/** pcmcia_request_irq
+ *
+ * Request_irq() reserves an irq for this client.
+ *
+ * Also, since Linux only reserves irq's when they are actually
+ * hooked, we don't guarantee that an irq will still be available
+ * when the configuration is locked. Now that I think about it,
+ * there might be a way to fix this using a dummy handler.
+ */
+
+#ifdef CONFIG_PCMCIA_PROBE
+static irqreturn_t test_action(int cpl, void *dev_id, struct pt_regs *regs)
+{
+ return IRQ_NONE;
+}
+#endif
+
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req)
+{
+ struct pcmcia_socket *s = p_dev->socket;
+ config_t *c;
+ int ret = CS_IN_USE, irq = 0;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ c = CONFIG(p_dev);
+ if (c->state & CONFIG_LOCKED)
+ return CS_CONFIGURATION_LOCKED;
+ if (c->state & CONFIG_IRQ_REQ)
+ return CS_IN_USE;
+
+#ifdef CONFIG_PCMCIA_PROBE
+ if (s->irq.AssignedIRQ != 0) {
+ /* If the interrupt is already assigned, it must be the same */
+ irq = s->irq.AssignedIRQ;
+ } else {
+ int try;
+ u32 mask = s->irq_mask;
+ void *data = NULL;
+
+ for (try = 0; try < 64; try++) {
+ irq = try % 32;
+
+ /* marked as available by driver, and not blocked by userspace? */
+ if (!((mask >> irq) & 1))
+ continue;
+
+ /* avoid an IRQ which is already used by a PCMCIA card */
+ if ((try < 32) && pcmcia_used_irq[irq])
+ continue;
+
+ /* register the correct driver, if possible, of check whether
+ * registering a dummy handle works, i.e. if the IRQ isn't
+ * marked as used by the kernel resource management core */
+ ret = request_irq(irq,
+ (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Handler : test_action,
+ ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+ (s->functions > 1) ||
+ (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+ p_dev->dev.bus_id,
+ (req->Attributes & IRQ_HANDLE_PRESENT) ? req->Instance : data);
+ if (!ret) {
+ if (!(req->Attributes & IRQ_HANDLE_PRESENT))
+ free_irq(irq, data);
+ break;
+ }
+ }
+ }
+#endif
+ if (ret) {
+ if (!s->pci_irq)
+ return ret;
+ irq = s->pci_irq;
+ }
+
+ if (ret && req->Attributes & IRQ_HANDLE_PRESENT) {
+ if (request_irq(irq, req->Handler,
+ ((req->Attributes & IRQ_TYPE_DYNAMIC_SHARING) ||
+ (s->functions > 1) ||
+ (irq == s->pci_irq)) ? SA_SHIRQ : 0,
+ p_dev->dev.bus_id, req->Instance))
+ return CS_IN_USE;
+ }
+
+ c->irq.Attributes = req->Attributes;
+ s->irq.AssignedIRQ = req->AssignedIRQ = irq;
+ s->irq.Config++;
+
+ c->state |= CONFIG_IRQ_REQ;
+ p_dev->state |= CLIENT_IRQ_REQ;
+
+#ifdef CONFIG_PCMCIA_PROBE
+ pcmcia_used_irq[irq]++;
+#endif
+
+ return CS_SUCCESS;
+} /* pcmcia_request_irq */
+EXPORT_SYMBOL(pcmcia_request_irq);
+
+
+/** pcmcia_request_window
+ *
+ * Request_window() establishes a mapping between card memory space
+ * and system memory space.
+ */
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh)
+{
+ struct pcmcia_socket *s = (*p_dev)->socket;
+ window_t *win;
+ u_long align;
+ int w;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return CS_NO_CARD;
+ if (req->Attributes & (WIN_PAGED | WIN_SHARED))
+ return CS_BAD_ATTRIBUTE;
+
+ /* Window size defaults to smallest available */
+ if (req->Size == 0)
+ req->Size = s->map_size;
+ align = (((s->features & SS_CAP_MEM_ALIGN) ||
+ (req->Attributes & WIN_STRICT_ALIGN)) ?
+ req->Size : s->map_size);
+ if (req->Size & (s->map_size-1))
+ return CS_BAD_SIZE;
+ if ((req->Base && (s->features & SS_CAP_STATIC_MAP)) ||
+ (req->Base & (align-1)))
+ return CS_BAD_BASE;
+ if (req->Base)
+ align = 0;
+
+ /* Allocate system memory window */
+ for (w = 0; w < MAX_WIN; w++)
+ if (!(s->state & SOCKET_WIN_REQ(w))) break;
+ if (w == MAX_WIN)
+ return CS_OUT_OF_RESOURCE;
+
+ win = &s->win[w];
+ win->magic = WINDOW_MAGIC;
+ win->index = w;
+ win->handle = *p_dev;
+ win->sock = s;
+
+ if (!(s->features & SS_CAP_STATIC_MAP)) {
+ win->ctl.res = pcmcia_find_mem_region(req->Base, req->Size, align,
+ (req->Attributes & WIN_MAP_BELOW_1MB), s);
+ if (!win->ctl.res)
+ return CS_IN_USE;
+ }
+ (*p_dev)->state |= CLIENT_WIN_REQ(w);
+
+ /* Configure the socket controller */
+ win->ctl.map = w+1;
+ win->ctl.flags = 0;
+ win->ctl.speed = req->AccessSpeed;
+ if (req->Attributes & WIN_MEMORY_TYPE)
+ win->ctl.flags |= MAP_ATTRIB;
+ if (req->Attributes & WIN_ENABLE)
+ win->ctl.flags |= MAP_ACTIVE;
+ if (req->Attributes & WIN_DATA_WIDTH_16)
+ win->ctl.flags |= MAP_16BIT;
+ if (req->Attributes & WIN_USE_WAIT)
+ win->ctl.flags |= MAP_USE_WAIT;
+ win->ctl.card_start = 0;
+ if (s->ops->set_mem_map(s, &win->ctl) != 0)
+ return CS_BAD_ARGS;
+ s->state |= SOCKET_WIN_REQ(w);
+
+ /* Return window handle */
+ 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;
+} /* pcmcia_request_window */
+EXPORT_SYMBOL(pcmcia_request_window);
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index b6843f8d300d..0668384ebc8b 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -72,7 +72,7 @@ int pcmcia_adjust_resource_info(adjust_t *adj)
/* you can't use the old interface if the new
* one was used before */
spin_lock_irqsave(&s->lock, flags);
- if ((s->resource_setup_done) &&
+ if ((s->resource_setup_new) &&
!(s->resource_setup_old)) {
spin_unlock_irqrestore(&s->lock, flags);
continue;
@@ -105,29 +105,32 @@ void pcmcia_validate_mem(struct pcmcia_socket *s)
}
EXPORT_SYMBOL(pcmcia_validate_mem);
-int adjust_io_region(struct resource *res, unsigned long r_start,
+int pcmcia_adjust_io_region(struct resource *res, unsigned long r_start,
unsigned long r_end, struct pcmcia_socket *s)
{
if (s->resource_ops->adjust_io_region)
return s->resource_ops->adjust_io_region(res, r_start, r_end, s);
return -ENOMEM;
}
+EXPORT_SYMBOL(pcmcia_adjust_io_region);
-struct resource *find_io_region(unsigned long base, int num,
+struct resource *pcmcia_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
if (s->resource_ops->find_io)
return s->resource_ops->find_io(base, num, align, s);
return NULL;
}
+EXPORT_SYMBOL(pcmcia_find_io_region);
-struct resource *find_mem_region(u_long base, u_long num, u_long align,
+struct resource *pcmcia_find_mem_region(u_long base, u_long num, u_long align,
int low, struct pcmcia_socket *s)
{
if (s->resource_ops->find_mem)
return s->resource_ops->find_mem(base, num, align, low, s);
return NULL;
}
+EXPORT_SYMBOL(pcmcia_find_mem_region);
void release_resource_db(struct pcmcia_socket *s)
{
diff --git a/drivers/pcmcia/rsrc_nonstatic.c b/drivers/pcmcia/rsrc_nonstatic.c
index 5876bab7c14c..c42455d20eb6 100644
--- a/drivers/pcmcia/rsrc_nonstatic.c
+++ b/drivers/pcmcia/rsrc_nonstatic.c
@@ -372,6 +372,9 @@ static int do_mem_probe(u_long base, u_long num, struct pcmcia_socket *s)
base, base+num-1);
bad = fail = 0;
step = (num < 0x20000) ? 0x2000 : ((num>>4) & ~0x1fff);
+ /* don't allow too large steps */
+ if (step > 0x800000)
+ step = 0x800000;
/* cis_readable wants to map 2x map_size */
if (step < 2 * s->map_size)
step = 2 * s->map_size;
@@ -465,8 +468,7 @@ static void validate_mem(struct pcmcia_socket *s, unsigned int probe_mask)
for (m = s_data->mem_db.next; m != &s_data->mem_db; m = mm.next) {
mm = *m;
- if (do_mem_probe(mm.base, mm.num, s))
- break;
+ do_mem_probe(mm.base, mm.num, s);
}
}
@@ -601,7 +603,7 @@ static int nonstatic_adjust_io_region(struct resource *res, unsigned long r_star
======================================================================*/
-struct resource *nonstatic_find_io_region(unsigned long base, int num,
+static struct resource *nonstatic_find_io_region(unsigned long base, int num,
unsigned long align, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_IO, s->dev.class_id);
@@ -635,8 +637,8 @@ struct resource *nonstatic_find_io_region(unsigned long base, int num,
return res;
}
-struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long align,
- int low, struct pcmcia_socket *s)
+static struct resource * nonstatic_find_mem_region(u_long base, u_long num,
+ u_long align, int low, struct pcmcia_socket *s)
{
struct resource *res = make_resource(0, num, IORESOURCE_MEM, s->dev.class_id);
struct socket_data *s_data = s->resource_data;
@@ -683,27 +685,23 @@ struct resource * nonstatic_find_mem_region(u_long base, u_long num, u_long alig
}
-static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_memory(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{
- u_long base, num;
struct socket_data *data = s->resource_data;
- int ret;
-
- base = adj->resource.memory.Base;
- num = adj->resource.memory.Size;
- if ((num == 0) || (base+num-1 < base))
- return CS_BAD_SIZE;
+ unsigned long size = end - start + 1;
+ int ret = 0;
- ret = CS_SUCCESS;
+ if (end <= start)
+ return -EINVAL;
down(&rsrc_sem);
- switch (adj->Action) {
+ switch (action) {
case ADD_MANAGED_RESOURCE:
- ret = add_interval(&data->mem_db, base, num);
+ ret = add_interval(&data->mem_db, start, size);
break;
case REMOVE_MANAGED_RESOURCE:
- ret = sub_interval(&data->mem_db, base, num);
- if (ret == CS_SUCCESS) {
+ ret = sub_interval(&data->mem_db, start, size);
+ if (!ret) {
struct pcmcia_socket *socket;
down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list)
@@ -712,7 +710,7 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
}
break;
default:
- ret = CS_UNSUPPORTED_FUNCTION;
+ ret = -EINVAL;
}
up(&rsrc_sem);
@@ -720,36 +718,35 @@ static int adjust_memory(struct pcmcia_socket *s, adjust_t *adj)
}
-static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
+static int adjust_io(struct pcmcia_socket *s, unsigned int action, unsigned long start, unsigned long end)
{
struct socket_data *data = s->resource_data;
- kio_addr_t base, num;
- int ret = CS_SUCCESS;
+ unsigned long size = end - start + 1;
+ int ret = 0;
- base = adj->resource.io.BasePort;
- num = adj->resource.io.NumPorts;
- if ((base < 0) || (base > 0xffff))
- return CS_BAD_BASE;
- if ((num <= 0) || (base+num > 0x10000) || (base+num <= base))
- return CS_BAD_SIZE;
+ if (end <= start)
+ return -EINVAL;
+
+ if (end > IO_SPACE_LIMIT)
+ return -EINVAL;
down(&rsrc_sem);
- switch (adj->Action) {
+ switch (action) {
case ADD_MANAGED_RESOURCE:
- if (add_interval(&data->io_db, base, num) != 0) {
- ret = CS_IN_USE;
+ if (add_interval(&data->io_db, start, size) != 0) {
+ ret = -EBUSY;
break;
}
#ifdef CONFIG_PCMCIA_PROBE
if (probe_io)
- do_io_probe(s, base, num);
+ do_io_probe(s, start, size);
#endif
break;
case REMOVE_MANAGED_RESOURCE:
- sub_interval(&data->io_db, base, num);
+ sub_interval(&data->io_db, start, size);
break;
default:
- ret = CS_UNSUPPORTED_FUNCTION;
+ ret = -EINVAL;
break;
}
up(&rsrc_sem);
@@ -760,15 +757,82 @@ static int adjust_io(struct pcmcia_socket *s, adjust_t *adj)
static int nonstatic_adjust_resource_info(struct pcmcia_socket *s, adjust_t *adj)
{
+ unsigned long end;
+
switch (adj->Resource) {
case RES_MEMORY_RANGE:
- return adjust_memory(s, adj);
+ end = adj->resource.memory.Base + adj->resource.memory.Size - 1;
+ return adjust_memory(s, adj->Action, adj->resource.memory.Base, end);
case RES_IO_RANGE:
- return adjust_io(s, adj);
+ end = adj->resource.io.BasePort + adj->resource.io.NumPorts - 1;
+ return adjust_io(s, adj->Action, adj->resource.io.BasePort, end);
}
return CS_UNSUPPORTED_FUNCTION;
}
+#ifdef CONFIG_PCI
+static int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+ struct resource *res;
+ int i, done = 0;
+
+ if (!s->cb_dev || !s->cb_dev->bus)
+ return -ENODEV;
+
+#if defined(CONFIG_X86) || defined(CONFIG_X86_64)
+ /* If this is the root bus, the risk of hitting
+ * some strange system devices which aren't protected
+ * by either ACPI resource tables or properly requested
+ * resources is too big. Therefore, don't do auto-adding
+ * of resources at the moment.
+ */
+ if (s->cb_dev->bus->number == 0)
+ return -EINVAL;
+#endif
+
+ for (i=0; i < PCI_BUS_NUM_RESOURCES; i++) {
+ res = s->cb_dev->bus->resource[i];
+ if (!res)
+ continue;
+
+ if (res->flags & IORESOURCE_IO) {
+ if (res == &ioport_resource)
+ continue;
+ printk(KERN_INFO "pcmcia: parent PCI bridge I/O window: 0x%lx - 0x%lx\n",
+ res->start, res->end);
+ if (!adjust_io(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+ done |= IORESOURCE_IO;
+
+ }
+
+ if (res->flags & IORESOURCE_MEM) {
+ if (res == &iomem_resource)
+ continue;
+ printk(KERN_INFO "pcmcia: parent PCI bridge Memory window: 0x%lx - 0x%lx\n",
+ res->start, res->end);
+ if (!adjust_memory(s, ADD_MANAGED_RESOURCE, res->start, res->end))
+ done |= IORESOURCE_MEM;
+ }
+ }
+
+ /* if we got at least one of IO, and one of MEM, we can be glad and
+ * activate the PCMCIA subsystem */
+ if (done & (IORESOURCE_MEM | IORESOURCE_IO))
+ s->resource_setup_done = 1;
+
+ return 0;
+}
+
+#else
+
+static inline int nonstatic_autoadd_resources(struct pcmcia_socket *s)
+{
+ return -ENODEV;
+}
+
+#endif
+
+
static int nonstatic_init(struct pcmcia_socket *s)
{
struct socket_data *data;
@@ -783,6 +847,8 @@ static int nonstatic_init(struct pcmcia_socket *s)
s->resource_data = (void *) data;
+ nonstatic_autoadd_resources(s);
+
return 0;
}
@@ -845,17 +911,16 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
{
struct pcmcia_socket *s = class_get_devdata(class_dev);
unsigned long start_addr, end_addr;
- unsigned int add = 1;
- adjust_t adj;
+ unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
if (ret != 2) {
ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
- add = 0;
+ add = REMOVE_MANAGED_RESOURCE;
if (ret != 2) {
ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
- add = 1;
+ add = ADD_MANAGED_RESOURCE;
if (ret != 2)
return -EINVAL;
}
@@ -863,12 +928,9 @@ static ssize_t store_io_db(struct class_device *class_dev, const char *buf, size
if (end_addr <= start_addr)
return -EINVAL;
- adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
- adj.Resource = RES_IO_RANGE;
- adj.resource.io.BasePort = start_addr;
- adj.resource.io.NumPorts = end_addr - start_addr + 1;
-
- ret = adjust_io(s, &adj);
+ ret = adjust_io(s, add, start_addr, end_addr);
+ if (!ret)
+ s->resource_setup_new = 1;
return ret ? ret : count;
}
@@ -901,17 +963,16 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
{
struct pcmcia_socket *s = class_get_devdata(class_dev);
unsigned long start_addr, end_addr;
- unsigned int add = 1;
- adjust_t adj;
+ unsigned int add = ADD_MANAGED_RESOURCE;
ssize_t ret = 0;
ret = sscanf (buf, "+ 0x%lx - 0x%lx", &start_addr, &end_addr);
if (ret != 2) {
ret = sscanf (buf, "- 0x%lx - 0x%lx", &start_addr, &end_addr);
- add = 0;
+ add = REMOVE_MANAGED_RESOURCE;
if (ret != 2) {
ret = sscanf (buf, "0x%lx - 0x%lx", &start_addr, &end_addr);
- add = 1;
+ add = ADD_MANAGED_RESOURCE;
if (ret != 2)
return -EINVAL;
}
@@ -919,12 +980,9 @@ static ssize_t store_mem_db(struct class_device *class_dev, const char *buf, siz
if (end_addr <= start_addr)
return -EINVAL;
- adj.Action = add ? ADD_MANAGED_RESOURCE : REMOVE_MANAGED_RESOURCE;
- adj.Resource = RES_MEMORY_RANGE;
- adj.resource.memory.Base = start_addr;
- adj.resource.memory.Size = end_addr - start_addr + 1;
-
- ret = adjust_memory(s, &adj);
+ ret = adjust_memory(s, add, start_addr, end_addr);
+ if (!ret)
+ s->resource_setup_new = 1;
return ret ? ret : count;
}
diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
index f1bb79153021..e98bb3d80e7c 100644
--- a/drivers/pcmcia/sa1100_generic.c
+++ b/drivers/pcmcia/sa1100_generic.c
@@ -34,7 +34,6 @@
#include <linux/init.h>
#include <linux/config.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/soc_common.h b/drivers/pcmcia/soc_common.h
index 700a155fbc78..6f14126889b3 100644
--- a/drivers/pcmcia/soc_common.h
+++ b/drivers/pcmcia/soc_common.h
@@ -11,7 +11,6 @@
/* include the world */
#include <linux/cpufreq.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/socket_sysfs.c b/drivers/pcmcia/socket_sysfs.c
index 8eed03938214..1040a6c1a8a4 100644
--- a/drivers/pcmcia/socket_sysfs.c
+++ b/drivers/pcmcia/socket_sysfs.c
@@ -29,7 +29,6 @@
#include <asm/irq.h>
#define IN_CARD_SERVICES
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -163,28 +162,164 @@ static ssize_t pccard_store_resource(struct class_device *dev, const char *buf,
return -EINVAL;
spin_lock_irqsave(&s->lock, flags);
- if (!s->resource_setup_done) {
+ if (!s->resource_setup_done)
s->resource_setup_done = 1;
- spin_unlock_irqrestore(&s->lock, flags);
+ spin_unlock_irqrestore(&s->lock, flags);
+
+ down(&s->skt_sem);
+ if ((s->callback) &&
+ (s->state & SOCKET_PRESENT) &&
+ !(s->state & SOCKET_CARDBUS)) {
+ if (try_module_get(s->callback->owner)) {
+ s->callback->requery(s);
+ module_put(s->callback->owner);
+ }
+ }
+ up(&s->skt_sem);
+
+ return count;
+}
+static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
+
+
+static ssize_t pccard_extract_cis(struct pcmcia_socket *s, char *buf, loff_t off, size_t count)
+{
+ tuple_t tuple;
+ int status, i;
+ loff_t pointer = 0;
+ ssize_t ret = 0;
+ u_char *tuplebuffer;
+ u_char *tempbuffer;
+
+ tuplebuffer = kmalloc(sizeof(u_char) * 256, GFP_KERNEL);
+ if (!tuplebuffer)
+ return -ENOMEM;
+
+ tempbuffer = kmalloc(sizeof(u_char) * 258, GFP_KERNEL);
+ if (!tempbuffer) {
+ ret = -ENOMEM;
+ goto free_tuple;
+ }
+
+ memset(&tuple, 0, sizeof(tuple_t));
+
+ tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+ tuple.TupleOffset = 0;
+
+ status = pccard_get_first_tuple(s, BIND_FN_ALL, &tuple);
+ while (!status) {
+ tuple.TupleData = tuplebuffer;
+ tuple.TupleDataMax = 255;
+ memset(tuplebuffer, 0, sizeof(u_char) * 255);
+ status = pccard_get_tuple_data(s, &tuple);
+ if (status)
+ break;
+
+ if (off < (pointer + 2 + tuple.TupleDataLen)) {
+ tempbuffer[0] = tuple.TupleCode & 0xff;
+ tempbuffer[1] = tuple.TupleLink & 0xff;
+ for (i = 0; i < tuple.TupleDataLen; i++)
+ tempbuffer[i + 2] = tuplebuffer[i] & 0xff;
+
+ for (i = 0; i < (2 + tuple.TupleDataLen); i++) {
+ if (((i + pointer) >= off) &&
+ (i + pointer) < (off + count)) {
+ buf[ret] = tempbuffer[i];
+ ret++;
+ }
+ }
+ }
+
+ pointer += 2 + tuple.TupleDataLen;
+
+ if (pointer >= (off + count))
+ break;
+
+ if (tuple.TupleCode == CISTPL_END)
+ break;
+ status = pccard_get_next_tuple(s, BIND_FN_ALL, &tuple);
+ }
+
+ kfree(tempbuffer);
+ free_tuple:
+ kfree(tuplebuffer);
+
+ return (ret);
+}
+
+static ssize_t pccard_show_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ unsigned int size = 0x200;
+
+ if (off >= size)
+ count = 0;
+ else {
+ struct pcmcia_socket *s;
+ cisinfo_t cisinfo;
+
+ if (off + count > size)
+ count = size - off;
+
+ s = to_socket(container_of(kobj, struct class_device, kobj));
+
+ if (!(s->state & SOCKET_PRESENT))
+ return -ENODEV;
+ if (pccard_validate_cis(s, BIND_FN_ALL, &cisinfo))
+ return -EIO;
+ if (!cisinfo.Chains)
+ return -ENODATA;
+
+ count = pccard_extract_cis(s, buf, off, count);
+ }
+
+ return (count);
+}
+
+static ssize_t pccard_store_cis(struct kobject *kobj, char *buf, loff_t off, size_t count)
+{
+ struct pcmcia_socket *s = to_socket(container_of(kobj, struct class_device, kobj));
+ cisdump_t *cis;
+ ssize_t ret = count;
+
+ if (off)
+ return -EINVAL;
+
+ if (count >= 0x200)
+ return -EINVAL;
+
+ if (!(s->state & SOCKET_PRESENT))
+ return -ENODEV;
+
+ cis = kmalloc(sizeof(cisdump_t), GFP_KERNEL);
+ if (!cis)
+ return -ENOMEM;
+ memset(cis, 0, sizeof(cisdump_t));
+
+ cis->Length = count + 1;
+ memcpy(cis->Data, buf, count);
+
+ if (pcmcia_replace_cis(s, cis))
+ ret = -EIO;
+
+ kfree(cis);
+
+ if (!ret) {
down(&s->skt_sem);
- if ((s->callback) &&
- (s->state & SOCKET_PRESENT) &&
+ if ((s->callback) && (s->state & SOCKET_PRESENT) &&
!(s->state & SOCKET_CARDBUS)) {
if (try_module_get(s->callback->owner)) {
- s->callback->resources_done(s);
+ s->callback->requery(s);
module_put(s->callback->owner);
}
}
up(&s->skt_sem);
-
- return count;
}
- spin_unlock_irqrestore(&s->lock, flags);
- return count;
+
+ return (ret);
}
-static CLASS_DEVICE_ATTR(available_resources_setup_done, 0600, pccard_show_resource, pccard_store_resource);
static struct class_device_attribute *pccard_socket_attributes[] = {
@@ -199,6 +334,13 @@ static struct class_device_attribute *pccard_socket_attributes[] = {
NULL,
};
+static struct bin_attribute pccard_cis_attr = {
+ .attr = { .name = "cis", .mode = S_IRUGO | S_IWUSR, .owner = THIS_MODULE},
+ .size = 0x200,
+ .read = pccard_show_cis,
+ .write = pccard_store_cis,
+};
+
static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
{
struct class_device_attribute **attr;
@@ -209,6 +351,8 @@ static int __devinit pccard_sysfs_add_socket(struct class_device *class_dev)
if (ret)
break;
}
+ if (!ret)
+ ret = sysfs_create_bin_file(&class_dev->kobj, &pccard_cis_attr);
return ret;
}
@@ -217,6 +361,7 @@ static void __devexit pccard_sysfs_remove_socket(struct class_device *class_dev)
{
struct class_device_attribute **attr;
+ sysfs_remove_bin_file(&class_dev->kobj, &pccard_cis_attr);
for (attr = pccard_socket_attributes; *attr; attr++)
class_device_remove_file(class_dev, *attr);
}
diff --git a/drivers/pcmcia/tcic.c b/drivers/pcmcia/tcic.c
index aacbbb5f055d..d5a61eae6119 100644
--- a/drivers/pcmcia/tcic.c
+++ b/drivers/pcmcia/tcic.c
@@ -50,7 +50,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/ss.h>
diff --git a/drivers/pcmcia/ti113x.h b/drivers/pcmcia/ti113x.h
index c7ba99871aca..fbe233e19ceb 100644
--- a/drivers/pcmcia/ti113x.h
+++ b/drivers/pcmcia/ti113x.h
@@ -154,8 +154,6 @@
#define ENE_TEST_C9 0xc9 /* 8bit */
#define ENE_TEST_C9_TLTENABLE 0x02
-#ifdef CONFIG_CARDBUS
-
/*
* Texas Instruments CardBus controller overrides.
*/
@@ -843,7 +841,5 @@ static int ti1250_override(struct yenta_socket *socket)
return ti12xx_override(socket);
}
-#endif /* CONFIG_CARDBUS */
-
#endif /* _LINUX_TI113X_H */
diff --git a/drivers/pcmcia/yenta_socket.c b/drivers/pcmcia/yenta_socket.c
index bee05362fd24..6837491f021c 100644
--- a/drivers/pcmcia/yenta_socket.c
+++ b/drivers/pcmcia/yenta_socket.c
@@ -18,7 +18,6 @@
#include <linux/delay.h>
#include <linux/module.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
@@ -528,60 +527,29 @@ static int yenta_sock_suspend(struct pcmcia_socket *sock)
* Use an adaptive allocation for the memory resource,
* sometimes the memory behind pci bridges is limited:
* 1/8 of the size of the io window of the parent.
- * max 4 MB, min 16 kB.
+ * max 4 MB, min 16 kB. We try very hard to not get below
+ * the "ACC" values, though.
*/
#define BRIDGE_MEM_MAX 4*1024*1024
+#define BRIDGE_MEM_ACC 128*1024
#define BRIDGE_MEM_MIN 16*1024
-#define BRIDGE_IO_MAX 256
+#define BRIDGE_IO_MAX 512
+#define BRIDGE_IO_ACC 256
#define BRIDGE_IO_MIN 32
#ifndef PCIBIOS_MIN_CARDBUS_IO
#define PCIBIOS_MIN_CARDBUS_IO PCIBIOS_MIN_IO
#endif
-static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type)
+static int yenta_search_one_res(struct resource *root, struct resource *res,
+ u32 min)
{
- struct pci_bus *bus;
- struct resource *root, *res;
- u32 start, end;
- u32 align, size, min;
- unsigned offset;
- unsigned mask;
-
- /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
- mask = ~0xfff;
- if (type & IORESOURCE_IO)
- mask = ~3;
-
- offset = 0x1c + 8*nr;
- bus = socket->dev->subordinate;
- res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
- res->name = bus->name;
- res->flags = type;
- res->start = 0;
- res->end = 0;
- root = pci_find_parent_resource(socket->dev, res);
-
- if (!root)
- return;
+ u32 align, size, start, end;
- start = config_readl(socket, offset) & mask;
- end = config_readl(socket, offset+4) | ~mask;
- if (start && end > start && !override_bios) {
- res->start = start;
- res->end = end;
- if (request_resource(root, res) == 0)
- return;
- printk(KERN_INFO "yenta %s: Preassigned resource %d busy, reconfiguring...\n",
- pci_name(socket->dev), nr);
- res->start = res->end = 0;
- }
-
- if (type & IORESOURCE_IO) {
+ if (res->flags & IORESOURCE_IO) {
align = 1024;
size = BRIDGE_IO_MAX;
- min = BRIDGE_IO_MIN;
start = PCIBIOS_MIN_CARDBUS_IO;
end = ~0U;
} else {
@@ -596,26 +564,107 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
i++;
size = 1 << i;
}
- if (size < BRIDGE_MEM_MIN)
- size = BRIDGE_MEM_MIN;
- min = BRIDGE_MEM_MIN;
+ if (size < min)
+ size = min;
align = size;
start = PCIBIOS_MIN_MEM;
end = ~0U;
}
-
+
do {
- if (allocate_resource(root, res, size, start, end, align, NULL, NULL)==0) {
- config_writel(socket, offset, res->start);
- config_writel(socket, offset+4, res->end);
- return;
+ if (allocate_resource(root, res, size, start, end, align,
+ NULL, NULL)==0) {
+ return 1;
}
size = size/2;
align = size;
} while (size >= min);
+
+ return 0;
+}
+
+
+static int yenta_search_res(struct yenta_socket *socket, struct resource *res,
+ u32 min)
+{
+ int i;
+ for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
+ struct resource * root = socket->dev->bus->resource[i];
+ if (!root)
+ continue;
+
+ if ((res->flags ^ root->flags) &
+ (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH))
+ continue; /* Wrong type */
+
+ if (yenta_search_one_res(root, res, min))
+ return 1;
+ }
+ return 0;
+}
+
+static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned type, int addr_start, int addr_end)
+{
+ struct pci_bus *bus;
+ struct resource *root, *res;
+ u32 start, end;
+ unsigned mask;
+
+ res = socket->dev->resource + PCI_BRIDGE_RESOURCES + nr;
+ /* Already allocated? */
+ if (res->parent)
+ return;
+
+ /* The granularity of the memory limit is 4kB, on IO it's 4 bytes */
+ mask = ~0xfff;
+ if (type & IORESOURCE_IO)
+ mask = ~3;
+
+ bus = socket->dev->subordinate;
+ res->name = bus->name;
+ res->flags = type;
+
+ start = config_readl(socket, addr_start) & mask;
+ end = config_readl(socket, addr_end) | ~mask;
+ if (start && end > start && !override_bios) {
+ res->start = start;
+ res->end = end;
+ root = pci_find_parent_resource(socket->dev, res);
+ if (root && (request_resource(root, res) == 0))
+ return;
+ printk(KERN_INFO "yenta %s: Preassigned resource %d busy or not available, reconfiguring...\n",
+ pci_name(socket->dev), nr);
+ }
+
+ if (type & IORESOURCE_IO) {
+ if ((yenta_search_res(socket, res, BRIDGE_IO_MAX)) ||
+ (yenta_search_res(socket, res, BRIDGE_IO_ACC)) ||
+ (yenta_search_res(socket, res, BRIDGE_IO_MIN))) {
+ config_writel(socket, addr_start, res->start);
+ config_writel(socket, addr_end, res->end);
+ }
+ } else {
+ if (type & IORESOURCE_PREFETCH) {
+ if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
+ (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
+ (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) {
+ config_writel(socket, addr_start, res->start);
+ config_writel(socket, addr_end, res->end);
+ }
+ /* Approximating prefetchable by non-prefetchable */
+ res->flags = IORESOURCE_MEM;
+ }
+ if ((yenta_search_res(socket, res, BRIDGE_MEM_MAX)) ||
+ (yenta_search_res(socket, res, BRIDGE_MEM_ACC)) ||
+ (yenta_search_res(socket, res, BRIDGE_MEM_MIN))) {
+ config_writel(socket, addr_start, res->start);
+ config_writel(socket, addr_end, res->end);
+ }
+ }
+
printk(KERN_INFO "yenta %s: no resource of type %x available, trying to continue...\n",
- pci_name(socket->dev), type);
- res->start = res->end = 0;
+ pci_name(socket->dev), type);
+ res->start = res->end = res->flags = 0;
}
/*
@@ -623,10 +672,14 @@ static void yenta_allocate_res(struct yenta_socket *socket, int nr, unsigned typ
*/
static void yenta_allocate_resources(struct yenta_socket *socket)
{
- yenta_allocate_res(socket, 0, IORESOURCE_MEM|IORESOURCE_PREFETCH);
- yenta_allocate_res(socket, 1, IORESOURCE_MEM);
- yenta_allocate_res(socket, 2, IORESOURCE_IO);
- yenta_allocate_res(socket, 3, IORESOURCE_IO); /* PCI isn't clever enough to use this one yet */
+ yenta_allocate_res(socket, 0, IORESOURCE_IO,
+ PCI_CB_IO_BASE_0, PCI_CB_IO_LIMIT_0);
+ yenta_allocate_res(socket, 1, IORESOURCE_IO,
+ PCI_CB_IO_BASE_1, PCI_CB_IO_LIMIT_1);
+ yenta_allocate_res(socket, 2, IORESOURCE_MEM|IORESOURCE_PREFETCH,
+ PCI_CB_MEMORY_BASE_0, PCI_CB_MEMORY_LIMIT_0);
+ yenta_allocate_res(socket, 3, IORESOURCE_MEM,
+ PCI_CB_MEMORY_BASE_1, PCI_CB_MEMORY_LIMIT_1);
}
@@ -865,14 +918,11 @@ static int yenta_probe_cb_irq(struct yenta_socket *socket)
*/
static void yenta_get_socket_capabilities(struct yenta_socket *socket, u32 isa_irq_mask)
{
- socket->socket.features |= SS_CAP_PAGE_REGS | SS_CAP_PCCARD | SS_CAP_CARDBUS;
- socket->socket.map_size = 0x1000;
socket->socket.pci_irq = socket->cb_irq;
if (isa_probe)
socket->socket.irq_mask = yenta_probe_irq(socket, isa_irq_mask);
else
socket->socket.irq_mask = 0;
- socket->socket.cb_dev = socket->dev;
printk(KERN_INFO "Yenta: ISA IRQ mask 0x%04x, PCI irq %d\n",
socket->socket.irq_mask, socket->cb_irq);
@@ -938,6 +988,9 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
socket->socket.dev.dev = &dev->dev;
socket->socket.driver_data = socket;
socket->socket.owner = THIS_MODULE;
+ socket->socket.features = SS_CAP_PAGE_REGS | SS_CAP_PCCARD;
+ socket->socket.map_size = 0x1000;
+ socket->socket.cb_dev = dev;
/* prepare struct yenta_socket */
socket->dev = dev;
@@ -1008,6 +1061,10 @@ static int __devinit yenta_probe (struct pci_dev *dev, const struct pci_device_i
socket->poll_timer.data = (unsigned long)socket;
socket->poll_timer.expires = jiffies + HZ;
add_timer(&socket->poll_timer);
+ printk(KERN_INFO "Yenta: no PCI IRQ, CardBus support disabled for this socket.\n"
+ KERN_INFO "Yenta: check your BIOS CardBus, BIOS IRQ or ACPI settings.\n");
+ } else {
+ socket->socket.features |= SS_CAP_CARDBUS;
}
/* Figure out what the dang thing can do for the PCMCIA layer... */
@@ -1048,6 +1105,7 @@ static int yenta_dev_suspend (struct pci_dev *dev, pm_message_t state)
pci_save_state(dev);
pci_read_config_dword(dev, 16*4, &socket->saved_state[0]);
pci_read_config_dword(dev, 17*4, &socket->saved_state[1]);
+ pci_disable_device(dev);
/*
* Some laptops (IBM T22) do not like us putting the Cardbus
@@ -1071,6 +1129,8 @@ static int yenta_dev_resume (struct pci_dev *dev)
pci_restore_state(dev);
pci_write_config_dword(dev, 16*4, socket->saved_state[0]);
pci_write_config_dword(dev, 17*4, socket->saved_state[1]);
+ pci_enable_device(dev);
+ pci_set_master(dev);
if (socket->type && socket->type->restore_state)
socket->type->restore_state(socket);
diff --git a/drivers/pnp/card.c b/drivers/pnp/card.c
index 3252662958d3..add12f7c489a 100644
--- a/drivers/pnp/card.c
+++ b/drivers/pnp/card.c
@@ -259,7 +259,6 @@ int pnp_add_card_device(struct pnp_card * card, struct pnp_dev * dev)
/**
* pnp_remove_card_device- removes a device from the specified card
- * @card: pointer to the card to remove from
* @dev: pointer to the device to remove
*/
@@ -274,7 +273,7 @@ void pnp_remove_card_device(struct pnp_dev * dev)
/**
* pnp_request_card_device - Searches for a PnP device under the specified card
- * @lcard: pointer to the card link, cannot be NULL
+ * @clink: pointer to the card link, cannot be NULL
* @id: pointer to a PnP ID structure that explains the rules for finding the device
* @from: Starting place to search from. If NULL it will start from the begining.
*/
diff --git a/drivers/pnp/manager.c b/drivers/pnp/manager.c
index 65ecef738537..6c510c19ad7d 100644
--- a/drivers/pnp/manager.c
+++ b/drivers/pnp/manager.c
@@ -390,6 +390,7 @@ fail:
* pnp_manual_config_dev - Disables Auto Config and Manually sets the resource table
* @dev: pointer to the desired device
* @res: pointer to the new resource config
+ * @mode: 0 or PNP_CONFIG_FORCE
*
* This function can be used by drivers that want to manually set thier resources.
*/
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index dd61e09029b1..75575f6c349c 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -160,7 +160,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
acpi_register_gsi(res->data.irq.interrupts[0],
res->data.irq.edge_level,
res->data.irq.active_high_low));
- pcibios_penalize_isa_irq(res->data.irq.interrupts[0]);
+ pcibios_penalize_isa_irq(res->data.irq.interrupts[0], 1);
}
break;
@@ -171,7 +171,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
acpi_register_gsi(res->data.extended_irq.interrupts[0],
res->data.extended_irq.edge_level,
res->data.extended_irq.active_high_low));
- pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0]);
+ pcibios_penalize_isa_irq(res->data.extended_irq.interrupts[0], 1);
}
break;
case ACPI_RSTYPE_DMA:
@@ -444,6 +444,7 @@ pnpacpi_parse_fixed_mem32_option(struct pnp_option *option,
struct acpipnp_parse_option_s {
struct pnp_option *option;
+ struct pnp_option *option_independent;
struct pnp_dev *dev;
};
@@ -507,7 +508,14 @@ static acpi_status pnpacpi_option_resource(struct acpi_resource *res,
parse_data->option = option;
break;
case ACPI_RSTYPE_END_DPF:
- return AE_CTRL_TERMINATE;
+ /*only one EndDependentFn is allowed*/
+ if (!parse_data->option_independent) {
+ pnp_warn("PnPACPI: more than one EndDependentFn");
+ return AE_ERROR;
+ }
+ parse_data->option = parse_data->option_independent;
+ parse_data->option_independent = NULL;
+ break;
default:
pnp_warn("PnPACPI: unknown resource type %d", res->id);
return AE_ERROR;
@@ -525,6 +533,7 @@ acpi_status pnpacpi_parse_resource_option_data(acpi_handle handle,
parse_data.option = pnp_register_independent_option(dev);
if (!parse_data.option)
return AE_ERROR;
+ parse_data.option_independent = parse_data.option;
parse_data.dev = dev;
status = acpi_walk_resources(handle, METHOD_NAME__PRS,
pnpacpi_option_resource, &parse_data);
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index e939c93a931c..778a324028f4 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -182,7 +182,7 @@ static int pnp_dock_thread(void * unused)
msleep_interruptible(2000);
if(signal_pending(current)) {
- if (try_to_freeze(PF_FREEZE))
+ if (try_to_freeze())
continue;
break;
}
diff --git a/drivers/pnp/pnpbios/rsparser.c b/drivers/pnp/pnpbios/rsparser.c
index 79bce7b75740..9001b6f0204d 100644
--- a/drivers/pnp/pnpbios/rsparser.c
+++ b/drivers/pnp/pnpbios/rsparser.c
@@ -64,7 +64,7 @@ pnpbios_parse_allocated_irqresource(struct pnp_resource_table * res, int irq)
}
res->irq_resource[i].start =
res->irq_resource[i].end = (unsigned long) irq;
- pcibios_penalize_isa_irq(irq);
+ pcibios_penalize_isa_irq(irq, 1);
}
}
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 2d1322dd7e19..887ad8939349 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -102,7 +102,7 @@ int pnp_register_irq_resource(struct pnp_option *option, struct pnp_irq *data)
for (i = 0; i < 16; i++)
if (test_bit(i, data->map))
- pcibios_penalize_isa_irq(i);
+ pcibios_penalize_isa_irq(i, 0);
}
#endif
return 0;
diff --git a/drivers/s390/Kconfig b/drivers/s390/Kconfig
index 96413c2cd1ad..a86a650f3d6d 100644
--- a/drivers/s390/Kconfig
+++ b/drivers/s390/Kconfig
@@ -187,6 +187,13 @@ config VMLOGRDR
*SYMPTOM.
This driver depends on the IUCV support driver.
+config VMCP
+ tristate "Support for the z/VM CP interface (VM only)"
+ help
+ Select this option if you want to be able to interact with the control
+ program on z/VM
+
+
config MONREADER
tristate "API for reading z/VM monitor service records"
depends on IUCV
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index ceeb3cf64a16..6527ff6f4706 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -176,7 +176,7 @@ dasd_state_known_to_basic(struct dasd_device * device)
return rc;
/* register 'device' debug area, used for all DBF_DEV_XXX calls */
- device->debug_area = debug_register(device->cdev->dev.bus_id, 0, 2,
+ device->debug_area = debug_register(device->cdev->dev.bus_id, 1, 2,
8 * sizeof (long));
debug_register_view(device->debug_area, &debug_sprintf_view);
debug_set_level(device->debug_area, DBF_EMERG);
@@ -1952,26 +1952,24 @@ dasd_generic_notify(struct ccw_device *cdev, int event)
* Automatically online either all dasd devices (dasd_autodetect) or
* all devices specified with dasd= parameters.
*/
+static int
+__dasd_auto_online(struct device *dev, void *data)
+{
+ struct ccw_device *cdev;
+
+ cdev = to_ccwdev(dev);
+ if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
+ ccw_device_set_online(cdev);
+ return 0;
+}
+
void
dasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver)
{
struct device_driver *drv;
- struct device *d, *dev;
- struct ccw_device *cdev;
drv = get_driver(&dasd_discipline_driver->driver);
- down_read(&drv->bus->subsys.rwsem);
- dev = NULL;
- list_for_each_entry(d, &drv->devices, driver_list) {
- dev = get_device(d);
- if (!dev)
- continue;
- cdev = to_ccwdev(dev);
- if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0)
- ccw_device_set_online(cdev);
- put_device(dev);
- }
- up_read(&drv->bus->subsys.rwsem);
+ driver_for_each_device(drv, NULL, NULL, __dasd_auto_online);
put_driver(drv);
}
@@ -1983,7 +1981,7 @@ dasd_init(void)
init_waitqueue_head(&dasd_init_waitq);
/* register 'common' DASD debug area, used for all DBF_XXX calls */
- dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long));
+ dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long));
if (dasd_debug_area == NULL) {
rc = -ENOMEM;
goto failed;
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index d7f19745911f..43c34f8c5e68 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -9,13 +9,14 @@
*
* /proc interface for the dasd driver.
*
- * $Revision: 1.31 $
+ * $Revision: 1.32 $
*/
#include <linux/config.h>
#include <linux/ctype.h>
#include <linux/seq_file.h>
#include <linux/vmalloc.h>
+#include <linux/proc_fs.h>
#include <asm/debug.h>
#include <asm/uaccess.h>
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index 16ab8d363ac6..4fde41188996 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -35,14 +35,17 @@
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 int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
+ unsigned long *data);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
static int dcssblk_major;
static struct block_device_operations dcssblk_devops = {
- .owner = THIS_MODULE,
- .open = dcssblk_open,
- .release = dcssblk_release,
+ .owner = THIS_MODULE,
+ .open = dcssblk_open,
+ .release = dcssblk_release,
+ .direct_access = dcssblk_direct_access,
};
static ssize_t dcssblk_add_store(struct device * dev, struct device_attribute *attr, const char * buf,
@@ -641,6 +644,20 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
/* Request beyond end of DCSS segment. */
goto fail;
}
+ /* verify data transfer direction */
+ if (dev_info->is_shared) {
+ switch (dev_info->segment_type) {
+ case SEG_TYPE_SR:
+ case SEG_TYPE_ER:
+ case SEG_TYPE_SC:
+ /* cannot write to these segments */
+ if (bio_data_dir(bio) == WRITE) {
+ PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);
+ goto fail;
+ }
+ }
+ }
+
index = (bio->bi_sector >> 3);
bio_for_each_segment(bvec, bio, i) {
page_addr = (unsigned long)
@@ -661,7 +678,26 @@ dcssblk_make_request(request_queue_t *q, struct bio *bio)
bio_endio(bio, bytes_done, 0);
return 0;
fail:
- bio_io_error(bio, bytes_done);
+ bio_io_error(bio, bio->bi_size);
+ return 0;
+}
+
+static int
+dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
+ unsigned long *data)
+{
+ struct dcssblk_dev_info *dev_info;
+ unsigned long pgoff;
+
+ dev_info = bdev->bd_disk->private_data;
+ if (!dev_info)
+ return -ENODEV;
+ if (secnum % (PAGE_SIZE/512))
+ return -EINVAL;
+ pgoff = secnum / (PAGE_SIZE / 512);
+ if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
+ return -ERANGE;
+ *data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);
return 0;
}
@@ -682,7 +718,7 @@ dcssblk_check_params(void)
buf[j-i] = dcssblk_segments[j];
}
buf[j-i] = '\0';
- rc = dcssblk_add_store(dcssblk_root_dev, buf, j-i);
+ rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);
if ((rc >= 0) && (dcssblk_segments[j] == '(')) {
for (k = 0; buf[k] != '\0'; k++)
buf[k] = toupper(buf[k]);
@@ -692,7 +728,7 @@ dcssblk_check_params(void)
up_read(&dcssblk_devices_sem);
if (dev_info)
dcssblk_shared_store(&dev_info->dev,
- "0\n", 2);
+ NULL, "0\n", 2);
}
}
while ((dcssblk_segments[j] != ',') &&
diff --git a/drivers/s390/char/Makefile b/drivers/s390/char/Makefile
index 14e8cce9f862..6377a96735df 100644
--- a/drivers/s390/char/Makefile
+++ b/drivers/s390/char/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o
obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o
obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o
+obj-$(CONFIG_VMCP) += vmcp.o
tape-$(CONFIG_S390_TAPE_BLOCK) += tape_block.o
tape-$(CONFIG_PROC_FS) += tape_proc.o
diff --git a/drivers/s390/char/con3215.c b/drivers/s390/char/con3215.c
index 022f17bff731..f11a67fda40e 100644
--- a/drivers/s390/char/con3215.c
+++ b/drivers/s390/char/con3215.c
@@ -860,8 +860,8 @@ con3215_init(void)
/* Set the console mode for VM */
if (MACHINE_IS_VM) {
- cpcmd("TERM CONMODE 3215", NULL, 0);
- cpcmd("TERM AUTOCR OFF", NULL, 0);
+ cpcmd("TERM CONMODE 3215", NULL, 0, NULL);
+ cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
}
/* allocate 3215 request structures */
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index d52fb57a6b19..fc7a213e591f 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -591,8 +591,8 @@ con3270_init(void)
/* Set the console mode for VM */
if (MACHINE_IS_VM) {
- cpcmd("TERM CONMODE 3270", 0, 0);
- cpcmd("TERM AUTOCR OFF", 0, 0);
+ cpcmd("TERM CONMODE 3270", NULL, 0, NULL);
+ cpcmd("TERM AUTOCR OFF", NULL, 0, NULL);
}
cdev = ccw_device_probe_console();
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 480ec87976fb..20be88e91fa1 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -1351,13 +1351,13 @@ tape_34xx_init (void)
{
int rc;
- TAPE_DBF_AREA = debug_register ( "tape_34xx", 1, 2, 4*sizeof(long));
+ TAPE_DBF_AREA = debug_register ( "tape_34xx", 2, 2, 4*sizeof(long));
debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
#ifdef DBF_LIKE_HELL
debug_set_level(TAPE_DBF_AREA, 6);
#endif
- DBF_EVENT(3, "34xx init: $Revision: 1.21 $\n");
+ DBF_EVENT(3, "34xx init: $Revision: 1.23 $\n");
/* Register driver for 3480/3490 tapes. */
rc = ccw_driver_register(&tape_34xx_driver);
if (rc)
@@ -1378,7 +1378,7 @@ tape_34xx_exit(void)
MODULE_DEVICE_TABLE(ccw, tape_34xx_ids);
MODULE_AUTHOR("(C) 2001-2002 IBM Deutschland Entwicklung GmbH");
MODULE_DESCRIPTION("Linux on zSeries channel attached 3480 tape "
- "device driver ($Revision: 1.21 $)");
+ "device driver ($Revision: 1.23 $)");
MODULE_LICENSE("GPL");
module_init(tape_34xx_init);
diff --git a/drivers/s390/char/tape_core.c b/drivers/s390/char/tape_core.c
index b4df4a515b12..0597aa0e27ee 100644
--- a/drivers/s390/char/tape_core.c
+++ b/drivers/s390/char/tape_core.c
@@ -1186,7 +1186,7 @@ tape_mtop(struct tape_device *device, int mt_op, int mt_count)
static int
tape_init (void)
{
- TAPE_DBF_AREA = debug_register ( "tape", 1, 2, 4*sizeof(long));
+ TAPE_DBF_AREA = debug_register ( "tape", 2, 2, 4*sizeof(long));
debug_register_view(TAPE_DBF_AREA, &debug_sprintf_view);
#ifdef DBF_LIKE_HELL
debug_set_level(TAPE_DBF_AREA, 6);
diff --git a/drivers/s390/char/tape_proc.c b/drivers/s390/char/tape_proc.c
index 801d17cca34e..5fec0a10cc3d 100644
--- a/drivers/s390/char/tape_proc.c
+++ b/drivers/s390/char/tape_proc.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/vmalloc.h>
#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
#define TAPE_DBF_AREA tape_core_dbf
diff --git a/drivers/s390/char/vmcp.c b/drivers/s390/char/vmcp.c
new file mode 100644
index 000000000000..7f11a608a633
--- /dev/null
+++ b/drivers/s390/char/vmcp.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2004,2005 IBM Corporation
+ * Interface implementation for communication with the v/VM control program
+ * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ *
+ *
+ * z/VMs CP offers the possibility to issue commands via the diagnose code 8
+ * this driver implements a character device that issues these commands and
+ * returns the answer of CP.
+
+ * The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS
+ */
+
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <asm/cpcmd.h>
+#include <asm/debug.h>
+#include <asm/uaccess.h>
+#include "vmcp.h"
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Christian Borntraeger <cborntra@de.ibm.com>");
+MODULE_DESCRIPTION("z/VM CP interface");
+
+static debug_info_t *vmcp_debug;
+
+static int vmcp_open(struct inode *inode, struct file *file)
+{
+ struct vmcp_session *session;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ session = kmalloc(sizeof(*session), GFP_KERNEL);
+ if (!session)
+ return -ENOMEM;
+ session->bufsize = PAGE_SIZE;
+ session->response = NULL;
+ session->resp_size = 0;
+ init_MUTEX(&session->mutex);
+ file->private_data = session;
+ return nonseekable_open(inode, file);
+}
+
+static int vmcp_release(struct inode *inode, struct file *file)
+{
+ struct vmcp_session *session;
+
+ session = (struct vmcp_session *)file->private_data;
+ file->private_data = NULL;
+ free_pages((unsigned long)session->response, get_order(session->bufsize));
+ kfree(session);
+ return 0;
+}
+
+static ssize_t
+vmcp_read(struct file *file, char __user * buff, size_t count, loff_t * ppos)
+{
+ size_t tocopy;
+ struct vmcp_session *session;
+
+ session = (struct vmcp_session *)file->private_data;
+ if (down_interruptible(&session->mutex))
+ return -ERESTARTSYS;
+ if (!session->response) {
+ up(&session->mutex);
+ return 0;
+ }
+ if (*ppos > session->resp_size) {
+ up(&session->mutex);
+ return 0;
+ }
+ tocopy = min(session->resp_size - (size_t) (*ppos), count);
+ tocopy = min(tocopy,session->bufsize - (size_t) (*ppos));
+
+ if (copy_to_user(buff, session->response + (*ppos), tocopy)) {
+ up(&session->mutex);
+ return -EFAULT;
+ }
+ up(&session->mutex);
+ *ppos += tocopy;
+ return tocopy;
+}
+
+static ssize_t
+vmcp_write(struct file *file, const char __user * buff, size_t count,
+ loff_t * ppos)
+{
+ char *cmd;
+ struct vmcp_session *session;
+
+ if (count > 240)
+ return -EINVAL;
+ cmd = kmalloc(count + 1, GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+ if (copy_from_user(cmd, buff, count)) {
+ kfree(cmd);
+ return -EFAULT;
+ }
+ cmd[count] = '\0';
+ session = (struct vmcp_session *)file->private_data;
+ if (down_interruptible(&session->mutex))
+ return -ERESTARTSYS;
+ if (!session->response)
+ session->response = (char *)__get_free_pages(GFP_KERNEL
+ | __GFP_REPEAT | GFP_DMA,
+ get_order(session->bufsize));
+ if (!session->response) {
+ up(&session->mutex);
+ kfree(cmd);
+ return -ENOMEM;
+ }
+ debug_text_event(vmcp_debug, 1, cmd);
+ session->resp_size = cpcmd(cmd, session->response,
+ session->bufsize,
+ &session->resp_code);
+ up(&session->mutex);
+ kfree(cmd);
+ *ppos = 0; /* reset the file pointer after a command */
+ return count;
+}
+
+
+/*
+ * These ioctls are available, as the semantics of the diagnose 8 call
+ * does not fit very well into a Linux call. Diagnose X'08' is described in
+ * CP Programming Services SC24-6084-00
+ *
+ * VMCP_GETCODE: gives the CP return code back to user space
+ * VMCP_SETBUF: sets the response buffer for the next write call. diagnose 8
+ * expects adjacent pages in real storage and to make matters worse, we
+ * dont know the size of the response. Therefore we default to PAGESIZE and
+ * let userspace to change the response size, if userspace expects a bigger
+ * response
+ */
+static long vmcp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct vmcp_session *session;
+ int temp;
+
+ session = (struct vmcp_session *)file->private_data;
+ if (down_interruptible(&session->mutex))
+ return -ERESTARTSYS;
+ switch (cmd) {
+ case VMCP_GETCODE:
+ temp = session->resp_code;
+ up(&session->mutex);
+ return put_user(temp, (int __user *)arg);
+ case VMCP_SETBUF:
+ free_pages((unsigned long)session->response,
+ get_order(session->bufsize));
+ session->response=NULL;
+ temp = get_user(session->bufsize, (int __user *)arg);
+ if (get_order(session->bufsize) > 8) {
+ session->bufsize = PAGE_SIZE;
+ temp = -EINVAL;
+ }
+ up(&session->mutex);
+ return temp;
+ case VMCP_GETSIZE:
+ temp = session->resp_size;
+ up(&session->mutex);
+ return put_user(temp, (int __user *)arg);
+ default:
+ up(&session->mutex);
+ return -ENOIOCTLCMD;
+ }
+}
+
+static struct file_operations vmcp_fops = {
+ .owner = THIS_MODULE,
+ .open = &vmcp_open,
+ .release = &vmcp_release,
+ .read = &vmcp_read,
+ .llseek = &no_llseek,
+ .write = &vmcp_write,
+ .unlocked_ioctl = &vmcp_ioctl,
+ .compat_ioctl = &vmcp_ioctl
+};
+
+static struct miscdevice vmcp_dev = {
+ .name = "vmcp",
+ .minor = MISC_DYNAMIC_MINOR,
+ .fops = &vmcp_fops,
+};
+
+static int __init vmcp_init(void)
+{
+ int ret;
+
+ if (!MACHINE_IS_VM) {
+ printk(KERN_WARNING
+ "z/VM CP interface is only available under z/VM\n");
+ return -ENODEV;
+ }
+ ret = misc_register(&vmcp_dev);
+ if (!ret)
+ printk(KERN_INFO "z/VM CP interface loaded\n");
+ else
+ printk(KERN_WARNING
+ "z/VM CP interface not loaded. Could not register misc device.\n");
+ vmcp_debug = debug_register("vmcp", 1, 1, 240);
+ debug_register_view(vmcp_debug, &debug_hex_ascii_view);
+ return ret;
+}
+
+static void __exit vmcp_exit(void)
+{
+ WARN_ON(misc_deregister(&vmcp_dev) != 0);
+ debug_unregister(vmcp_debug);
+ printk(KERN_INFO "z/VM CP interface unloaded.\n");
+}
+
+module_init(vmcp_init);
+module_exit(vmcp_exit);
diff --git a/drivers/s390/char/vmcp.h b/drivers/s390/char/vmcp.h
new file mode 100644
index 000000000000..87389e730465
--- /dev/null
+++ b/drivers/s390/char/vmcp.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004, 2005 IBM Corporation
+ * Interface implementation for communication with the v/VM control program
+ * Version 1.0
+ * Author(s): Christian Borntraeger <cborntra@de.ibm.com>
+ *
+ *
+ * z/VMs CP offers the possibility to issue commands via the diagnose code 8
+ * this driver implements a character device that issues these commands and
+ * returns the answer of CP.
+ *
+ * The idea of this driver is based on cpint from Neale Ferguson
+ */
+
+#include <asm/semaphore.h>
+#include <linux/ioctl.h>
+
+#define VMCP_GETCODE _IOR(0x10, 1, int)
+#define VMCP_SETBUF _IOW(0x10, 2, int)
+#define VMCP_GETSIZE _IOR(0x10, 3, int)
+
+struct vmcp_session {
+ unsigned int bufsize;
+ char *response;
+ int resp_size;
+ int resp_code;
+ /* As we use copy_from/to_user, which might *
+ * sleep and cannot use a spinlock */
+ struct semaphore mutex;
+};
diff --git a/drivers/s390/char/vmlogrdr.c b/drivers/s390/char/vmlogrdr.c
index f7717327d15e..491f00c032e8 100644
--- a/drivers/s390/char/vmlogrdr.c
+++ b/drivers/s390/char/vmlogrdr.c
@@ -236,7 +236,7 @@ vmlogrdr_get_recording_class_AB(void) {
int len,i;
printk (KERN_DEBUG "vmlogrdr: query command: %s\n", cp_command);
- cpcmd(cp_command, cp_response, sizeof(cp_response));
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
printk (KERN_DEBUG "vmlogrdr: response: %s", cp_response);
len = strnlen(cp_response,sizeof(cp_response));
// now the parsing
@@ -288,7 +288,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
printk (KERN_DEBUG "vmlogrdr: recording command: %s\n",
cp_command);
- cpcmd(cp_command, cp_response, sizeof(cp_response));
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
printk (KERN_DEBUG "vmlogrdr: recording response: %s",
cp_response);
}
@@ -301,7 +301,7 @@ vmlogrdr_recording(struct vmlogrdr_priv_t * logptr, int action, int purge) {
qid_string);
printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
- cpcmd(cp_command, cp_response, sizeof(cp_response));
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
printk (KERN_DEBUG "vmlogrdr: recording response: %s",
cp_response);
/* The recording command will usually answer with 'Command complete'
@@ -607,7 +607,7 @@ vmlogrdr_purge_store(struct device * dev, struct device_attribute *attr, const c
priv->recording_name);
printk (KERN_DEBUG "vmlogrdr: recording command: %s\n", cp_command);
- cpcmd(cp_command, cp_response, sizeof(cp_response));
+ cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);
printk (KERN_DEBUG "vmlogrdr: recording response: %s",
cp_response);
@@ -682,7 +682,7 @@ vmlogrdr_recording_status_show(struct device_driver *driver, char *buf) {
char cp_command[] = "QUERY RECORDING ";
int len;
- cpcmd(cp_command, buf, 4096);
+ cpcmd(cp_command, buf, 4096, NULL);
len = strlen(buf);
return len;
}
diff --git a/drivers/s390/cio/ccwgroup.c b/drivers/s390/cio/ccwgroup.c
index 306525acb9f8..91ea8e4777f3 100644
--- a/drivers/s390/cio/ccwgroup.c
+++ b/drivers/s390/cio/ccwgroup.c
@@ -403,34 +403,22 @@ ccwgroup_driver_register (struct ccwgroup_driver *cdriver)
return driver_register(&cdriver->driver);
}
-static inline struct device *
-__get_next_ccwgroup_device(struct device_driver *drv)
+static int
+__ccwgroup_driver_unregister_device(struct device *dev, void *data)
{
- struct device *dev, *d;
-
- down_read(&drv->bus->subsys.rwsem);
- dev = NULL;
- list_for_each_entry(d, &drv->devices, driver_list) {
- dev = get_device(d);
- if (dev)
- break;
- }
- up_read(&drv->bus->subsys.rwsem);
- return dev;
+ __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
+ device_unregister(dev);
+ put_device(dev);
+ return 0;
}
void
ccwgroup_driver_unregister (struct ccwgroup_driver *cdriver)
{
- struct device *dev;
-
/* We don't want ccwgroup devices to live longer than their driver. */
get_driver(&cdriver->driver);
- while ((dev = __get_next_ccwgroup_device(&cdriver->driver))) {
- __ccwgroup_remove_symlinks(to_ccwgroupdev(dev));
- device_unregister(dev);
- put_device(dev);
- };
+ driver_for_each_device(&cdriver->driver, NULL, NULL,
+ __ccwgroup_driver_unregister_device);
put_driver(&cdriver->driver);
driver_unregister(&cdriver->driver);
}
@@ -449,7 +437,7 @@ __ccwgroup_get_gdev_by_cdev(struct ccw_device *cdev)
if (cdev->dev.driver_data) {
gdev = (struct ccwgroup_device *)cdev->dev.driver_data;
if (get_device(&gdev->dev)) {
- if (!list_empty(&gdev->dev.node))
+ if (klist_node_attached(&gdev->dev.knode_bus))
return gdev;
put_device(&gdev->dev);
}
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 1d9b3f18d8de..ea813bdce1d6 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -1,7 +1,7 @@
/*
* drivers/s390/cio/cio.c
* S/390 common I/O routines -- low level i/o calls
- * $Revision: 1.133 $
+ * $Revision: 1.134 $
*
* Copyright (C) 1999-2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
@@ -63,17 +63,17 @@ __setup ("cio_msg=", cio_setup);
static int __init
cio_debug_init (void)
{
- cio_debug_msg_id = debug_register ("cio_msg", 4, 4, 16*sizeof (long));
+ cio_debug_msg_id = debug_register ("cio_msg", 16, 4, 16*sizeof (long));
if (!cio_debug_msg_id)
goto out_unregister;
debug_register_view (cio_debug_msg_id, &debug_sprintf_view);
debug_set_level (cio_debug_msg_id, 2);
- cio_debug_trace_id = debug_register ("cio_trace", 4, 4, 8);
+ cio_debug_trace_id = debug_register ("cio_trace", 16, 4, 8);
if (!cio_debug_trace_id)
goto out_unregister;
debug_register_view (cio_debug_trace_id, &debug_hex_ascii_view);
debug_set_level (cio_debug_trace_id, 2);
- cio_debug_crw_id = debug_register ("cio_crw", 2, 4, 16*sizeof (long));
+ cio_debug_crw_id = debug_register ("cio_crw", 4, 4, 16*sizeof (long));
if (!cio_debug_crw_id)
goto out_unregister;
debug_register_view (cio_debug_crw_id, &debug_sprintf_view);
diff --git a/drivers/s390/cio/css.c b/drivers/s390/cio/css.c
index 87bd70eeabed..555119cacc27 100644
--- a/drivers/s390/cio/css.c
+++ b/drivers/s390/cio/css.c
@@ -128,34 +128,28 @@ css_probe_device(int irq)
return ret;
}
+static int
+check_subchannel(struct device * dev, void * data)
+{
+ struct subchannel *sch;
+ int irq = (unsigned long)data;
+
+ sch = to_subchannel(dev);
+ return (sch->irq == irq);
+}
+
struct subchannel *
get_subchannel_by_schid(int irq)
{
- struct subchannel *sch;
- struct list_head *entry;
struct device *dev;
- if (!get_bus(&css_bus_type))
- return NULL;
- down_read(&css_bus_type.subsys.rwsem);
- sch = NULL;
- list_for_each(entry, &css_bus_type.devices.list) {
- dev = get_device(container_of(entry,
- struct device, bus_list));
- if (!dev)
- continue;
- sch = to_subchannel(dev);
- if (sch->irq == irq)
- break;
- put_device(dev);
- sch = NULL;
- }
- up_read(&css_bus_type.subsys.rwsem);
- put_bus(&css_bus_type);
+ dev = bus_find_device(&css_bus_type, NULL,
+ (void *)(unsigned long)irq, check_subchannel);
- return sch;
+ return dev ? to_subchannel(dev) : NULL;
}
+
static inline int
css_get_subchannel_status(struct subchannel *sch, int schid)
{
diff --git a/drivers/s390/cio/device.c b/drivers/s390/cio/device.c
index 809e1108a06e..14c76f5e4177 100644
--- a/drivers/s390/cio/device.c
+++ b/drivers/s390/cio/device.c
@@ -514,36 +514,39 @@ ccw_device_register(struct ccw_device *cdev)
return ret;
}
+struct match_data {
+ unsigned int devno;
+ struct ccw_device * sibling;
+};
+
+static int
+match_devno(struct device * dev, void * data)
+{
+ struct match_data * d = (struct match_data *)data;
+ struct ccw_device * cdev;
+
+ cdev = to_ccwdev(dev);
+ if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
+ (cdev->private->devno == d->devno) &&
+ (cdev != d->sibling)) {
+ cdev->private->state = DEV_STATE_NOT_OPER;
+ return 1;
+ }
+ return 0;
+}
+
static struct ccw_device *
get_disc_ccwdev_by_devno(unsigned int devno, struct ccw_device *sibling)
{
- struct ccw_device *cdev;
- struct list_head *entry;
struct device *dev;
+ struct match_data data = {
+ .devno = devno,
+ .sibling = sibling,
+ };
- if (!get_bus(&ccw_bus_type))
- return NULL;
- down_read(&ccw_bus_type.subsys.rwsem);
- cdev = NULL;
- list_for_each(entry, &ccw_bus_type.devices.list) {
- dev = get_device(container_of(entry,
- struct device, bus_list));
- if (!dev)
- continue;
- cdev = to_ccwdev(dev);
- if ((cdev->private->state == DEV_STATE_DISCONNECTED) &&
- (cdev->private->devno == devno) &&
- (cdev != sibling)) {
- cdev->private->state = DEV_STATE_NOT_OPER;
- break;
- }
- put_device(dev);
- cdev = NULL;
- }
- up_read(&ccw_bus_type.subsys.rwsem);
- put_bus(&ccw_bus_type);
+ dev = bus_find_device(&css_bus_type, NULL, &data, match_devno);
- return cdev;
+ return dev ? to_ccwdev(dev) : NULL;
}
static void
@@ -647,7 +650,7 @@ io_subchannel_register(void *data)
cdev = (struct ccw_device *) data;
sch = to_subchannel(cdev->dev.parent);
- if (!list_empty(&sch->dev.children)) {
+ if (klist_node_attached(&cdev->dev.knode_parent)) {
bus_rescan_devices(&ccw_bus_type);
goto out;
}
@@ -1019,30 +1022,29 @@ ccw_device_probe_console(void)
/*
* get ccw_device matching the busid, but only if owned by cdrv
*/
+static int
+__ccwdev_check_busid(struct device *dev, void *id)
+{
+ char *bus_id;
+
+ bus_id = (char *)id;
+
+ return (strncmp(bus_id, dev->bus_id, BUS_ID_SIZE) == 0);
+}
+
+
struct ccw_device *
get_ccwdev_by_busid(struct ccw_driver *cdrv, const char *bus_id)
{
- struct device *d, *dev;
+ struct device *dev;
struct device_driver *drv;
drv = get_driver(&cdrv->driver);
if (!drv)
- return 0;
-
- down_read(&drv->bus->subsys.rwsem);
-
- dev = NULL;
- list_for_each_entry(d, &drv->devices, driver_list) {
- dev = get_device(d);
+ return NULL;
- if (dev && !strncmp(bus_id, dev->bus_id, BUS_ID_SIZE))
- break;
- else if (dev) {
- put_device(dev);
- dev = NULL;
- }
- }
- up_read(&drv->bus->subsys.rwsem);
+ dev = driver_find_device(drv, NULL, (void *)bus_id,
+ __ccwdev_check_busid);
put_driver(drv);
return dev ? to_ccwdev(dev) : 0;
diff --git a/drivers/s390/cio/qdio.c b/drivers/s390/cio/qdio.c
index bbe9f45d1438..82194c4eadfb 100644
--- a/drivers/s390/cio/qdio.c
+++ b/drivers/s390/cio/qdio.c
@@ -56,7 +56,7 @@
#include "ioasm.h"
#include "chsc.h"
-#define VERSION_QDIO_C "$Revision: 1.98 $"
+#define VERSION_QDIO_C "$Revision: 1.101 $"
/****************** MODULE PARAMETER VARIABLES ********************/
MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
@@ -3342,7 +3342,7 @@ static int
qdio_register_dbf_views(void)
{
qdio_dbf_setup=debug_register(QDIO_DBF_SETUP_NAME,
- QDIO_DBF_SETUP_INDEX,
+ QDIO_DBF_SETUP_PAGES,
QDIO_DBF_SETUP_NR_AREAS,
QDIO_DBF_SETUP_LEN);
if (!qdio_dbf_setup)
@@ -3351,7 +3351,7 @@ qdio_register_dbf_views(void)
debug_set_level(qdio_dbf_setup,QDIO_DBF_SETUP_LEVEL);
qdio_dbf_sbal=debug_register(QDIO_DBF_SBAL_NAME,
- QDIO_DBF_SBAL_INDEX,
+ QDIO_DBF_SBAL_PAGES,
QDIO_DBF_SBAL_NR_AREAS,
QDIO_DBF_SBAL_LEN);
if (!qdio_dbf_sbal)
@@ -3361,7 +3361,7 @@ qdio_register_dbf_views(void)
debug_set_level(qdio_dbf_sbal,QDIO_DBF_SBAL_LEVEL);
qdio_dbf_sense=debug_register(QDIO_DBF_SENSE_NAME,
- QDIO_DBF_SENSE_INDEX,
+ QDIO_DBF_SENSE_PAGES,
QDIO_DBF_SENSE_NR_AREAS,
QDIO_DBF_SENSE_LEN);
if (!qdio_dbf_sense)
@@ -3371,7 +3371,7 @@ qdio_register_dbf_views(void)
debug_set_level(qdio_dbf_sense,QDIO_DBF_SENSE_LEVEL);
qdio_dbf_trace=debug_register(QDIO_DBF_TRACE_NAME,
- QDIO_DBF_TRACE_INDEX,
+ QDIO_DBF_TRACE_PAGES,
QDIO_DBF_TRACE_NR_AREAS,
QDIO_DBF_TRACE_LEN);
if (!qdio_dbf_trace)
@@ -3382,7 +3382,7 @@ qdio_register_dbf_views(void)
#ifdef CONFIG_QDIO_DEBUG
qdio_dbf_slsb_out=debug_register(QDIO_DBF_SLSB_OUT_NAME,
- QDIO_DBF_SLSB_OUT_INDEX,
+ QDIO_DBF_SLSB_OUT_PAGES,
QDIO_DBF_SLSB_OUT_NR_AREAS,
QDIO_DBF_SLSB_OUT_LEN);
if (!qdio_dbf_slsb_out)
@@ -3391,7 +3391,7 @@ qdio_register_dbf_views(void)
debug_set_level(qdio_dbf_slsb_out,QDIO_DBF_SLSB_OUT_LEVEL);
qdio_dbf_slsb_in=debug_register(QDIO_DBF_SLSB_IN_NAME,
- QDIO_DBF_SLSB_IN_INDEX,
+ QDIO_DBF_SLSB_IN_PAGES,
QDIO_DBF_SLSB_IN_NR_AREAS,
QDIO_DBF_SLSB_IN_LEN);
if (!qdio_dbf_slsb_in)
diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h
index b6daadac4e8b..6b8aa6a852be 100644
--- a/drivers/s390/cio/qdio.h
+++ b/drivers/s390/cio/qdio.h
@@ -3,7 +3,7 @@
#include <asm/page.h>
-#define VERSION_CIO_QDIO_H "$Revision: 1.32 $"
+#define VERSION_CIO_QDIO_H "$Revision: 1.33 $"
#ifdef CONFIG_QDIO_DEBUG
#define QDIO_VERBOSE_LEVEL 9
@@ -132,7 +132,7 @@ enum qdio_irq_states {
#define QDIO_DBF_SETUP_NAME "qdio_setup"
#define QDIO_DBF_SETUP_LEN 8
-#define QDIO_DBF_SETUP_INDEX 2
+#define QDIO_DBF_SETUP_PAGES 4
#define QDIO_DBF_SETUP_NR_AREAS 1
#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SETUP_LEVEL 6
@@ -142,7 +142,7 @@ enum qdio_irq_states {
#define QDIO_DBF_SBAL_NAME "qdio_labs" /* sbal */
#define QDIO_DBF_SBAL_LEN 256
-#define QDIO_DBF_SBAL_INDEX 2
+#define QDIO_DBF_SBAL_PAGES 4
#define QDIO_DBF_SBAL_NR_AREAS 2
#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SBAL_LEVEL 6
@@ -154,16 +154,16 @@ enum qdio_irq_states {
#define QDIO_DBF_TRACE_LEN 8
#define QDIO_DBF_TRACE_NR_AREAS 2
#ifdef CONFIG_QDIO_DEBUG
-#define QDIO_DBF_TRACE_INDEX 4
+#define QDIO_DBF_TRACE_PAGES 16
#define QDIO_DBF_TRACE_LEVEL 4 /* -------- could be even more verbose here */
#else /* CONFIG_QDIO_DEBUG */
-#define QDIO_DBF_TRACE_INDEX 2
+#define QDIO_DBF_TRACE_PAGES 4
#define QDIO_DBF_TRACE_LEVEL 2
#endif /* CONFIG_QDIO_DEBUG */
#define QDIO_DBF_SENSE_NAME "qdio_sense"
#define QDIO_DBF_SENSE_LEN 64
-#define QDIO_DBF_SENSE_INDEX 1
+#define QDIO_DBF_SENSE_PAGES 2
#define QDIO_DBF_SENSE_NR_AREAS 1
#ifdef CONFIG_QDIO_DEBUG
#define QDIO_DBF_SENSE_LEVEL 6
@@ -176,13 +176,13 @@ enum qdio_irq_states {
#define QDIO_DBF_SLSB_OUT_NAME "qdio_slsb_out"
#define QDIO_DBF_SLSB_OUT_LEN QDIO_MAX_BUFFERS_PER_Q
-#define QDIO_DBF_SLSB_OUT_INDEX 8
+#define QDIO_DBF_SLSB_OUT_PAGES 256
#define QDIO_DBF_SLSB_OUT_NR_AREAS 1
#define QDIO_DBF_SLSB_OUT_LEVEL 6
#define QDIO_DBF_SLSB_IN_NAME "qdio_slsb_in"
#define QDIO_DBF_SLSB_IN_LEN QDIO_MAX_BUFFERS_PER_Q
-#define QDIO_DBF_SLSB_IN_INDEX 8
+#define QDIO_DBF_SLSB_IN_PAGES 256
#define QDIO_DBF_SLSB_IN_NR_AREAS 1
#define QDIO_DBF_SLSB_IN_LEVEL 6
#endif /* CONFIG_QDIO_DEBUG */
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index a99927d54ebb..24c0af49c25c 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -146,8 +146,8 @@ claw_unregister_debug_facility(void)
static int
claw_register_debug_facility(void)
{
- claw_dbf_setup = debug_register("claw_setup", 1, 1, 8);
- claw_dbf_trace = debug_register("claw_trace", 1, 2, 8);
+ claw_dbf_setup = debug_register("claw_setup", 2, 1, 8);
+ claw_dbf_trace = debug_register("claw_trace", 2, 2, 8);
if (claw_dbf_setup == NULL || claw_dbf_trace == NULL) {
printk(KERN_WARNING "Not enough memory for debug facility.\n");
claw_unregister_debug_facility();
@@ -428,7 +428,7 @@ claw_pack_skb(struct claw_privbk *privptr)
new_skb = NULL; /* assume no dice */
pkt_cnt = 0;
CLAW_DBF_TEXT(4,trace,"PackSKBe");
- if (skb_queue_len(&p_ch->collect_queue) > 0) {
+ if (!skb_queue_empty(&p_ch->collect_queue)) {
/* some data */
held_skb = skb_dequeue(&p_ch->collect_queue);
if (p_env->packing != DO_PACKED)
@@ -1254,7 +1254,7 @@ claw_write_next ( struct chbk * p_ch )
privptr = (struct claw_privbk *) dev->priv;
claw_free_wrt_buf( dev );
if ((privptr->write_free_count > 0) &&
- (skb_queue_len(&p_ch->collect_queue) > 0)) {
+ !skb_queue_empty(&p_ch->collect_queue)) {
pk_skb = claw_pack_skb(privptr);
while (pk_skb != NULL) {
rc = claw_hw_tx( pk_skb, dev,1);
diff --git a/drivers/s390/net/ctcdbug.c b/drivers/s390/net/ctcdbug.c
index 2c86bfa11b2f..0e2a8bb93032 100644
--- a/drivers/s390/net/ctcdbug.c
+++ b/drivers/s390/net/ctcdbug.c
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.4 $)
+ * linux/drivers/s390/net/ctcdbug.c ($Revision: 1.6 $)
*
* CTC / ESCON network driver - s390 dbf exploit.
*
@@ -9,7 +9,7 @@
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
- * $Revision: 1.4 $ $Date: 2004/08/04 10:11:59 $
+ * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,15 +51,15 @@ int
ctc_register_dbf_views(void)
{
ctc_dbf_setup = debug_register(CTC_DBF_SETUP_NAME,
- CTC_DBF_SETUP_INDEX,
+ CTC_DBF_SETUP_PAGES,
CTC_DBF_SETUP_NR_AREAS,
CTC_DBF_SETUP_LEN);
ctc_dbf_data = debug_register(CTC_DBF_DATA_NAME,
- CTC_DBF_DATA_INDEX,
+ CTC_DBF_DATA_PAGES,
CTC_DBF_DATA_NR_AREAS,
CTC_DBF_DATA_LEN);
ctc_dbf_trace = debug_register(CTC_DBF_TRACE_NAME,
- CTC_DBF_TRACE_INDEX,
+ CTC_DBF_TRACE_PAGES,
CTC_DBF_TRACE_NR_AREAS,
CTC_DBF_TRACE_LEN);
diff --git a/drivers/s390/net/ctcdbug.h b/drivers/s390/net/ctcdbug.h
index 7fe2ebd1792d..7d6afa1627c3 100644
--- a/drivers/s390/net/ctcdbug.h
+++ b/drivers/s390/net/ctcdbug.h
@@ -1,6 +1,6 @@
/*
*
- * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.5 $)
+ * linux/drivers/s390/net/ctcdbug.h ($Revision: 1.6 $)
*
* CTC / ESCON network driver - s390 dbf exploit.
*
@@ -9,7 +9,7 @@
* Author(s): Original Code written by
* Peter Tiedemann (ptiedem@de.ibm.com)
*
- * $Revision: 1.5 $ $Date: 2005/02/27 19:46:44 $
+ * $Revision: 1.6 $ $Date: 2005/05/11 08:10:17 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,19 +35,19 @@
*/
#define CTC_DBF_SETUP_NAME "ctc_setup"
#define CTC_DBF_SETUP_LEN 16
-#define CTC_DBF_SETUP_INDEX 3
+#define CTC_DBF_SETUP_PAGES 8
#define CTC_DBF_SETUP_NR_AREAS 1
#define CTC_DBF_SETUP_LEVEL 3
#define CTC_DBF_DATA_NAME "ctc_data"
#define CTC_DBF_DATA_LEN 128
-#define CTC_DBF_DATA_INDEX 3
+#define CTC_DBF_DATA_PAGES 8
#define CTC_DBF_DATA_NR_AREAS 1
#define CTC_DBF_DATA_LEVEL 3
#define CTC_DBF_TRACE_NAME "ctc_trace"
#define CTC_DBF_TRACE_LEN 16
-#define CTC_DBF_TRACE_INDEX 2
+#define CTC_DBF_TRACE_PAGES 4
#define CTC_DBF_TRACE_NR_AREAS 2
#define CTC_DBF_TRACE_LEVEL 3
diff --git a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c
index 3080393e823d..968f2c113efe 100644
--- a/drivers/s390/net/ctctty.c
+++ b/drivers/s390/net/ctctty.c
@@ -156,7 +156,7 @@ ctc_tty_readmodem(ctc_tty_info *info)
skb_queue_head(&info->rx_queue, skb);
else {
kfree_skb(skb);
- ret = skb_queue_len(&info->rx_queue);
+ ret = !skb_queue_empty(&info->rx_queue);
}
}
}
@@ -530,7 +530,7 @@ ctc_tty_write(struct tty_struct *tty, const u_char * buf, int count)
total += c;
count -= c;
}
- if (skb_queue_len(&info->tx_queue)) {
+ if (!skb_queue_empty(&info->tx_queue)) {
info->lsr &= ~UART_LSR_TEMT;
tasklet_schedule(&info->tasklet);
}
@@ -594,7 +594,7 @@ ctc_tty_flush_chars(struct tty_struct *tty)
return;
if (ctc_tty_paranoia_check(info, tty->name, "ctc_tty_flush_chars"))
return;
- if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+ if (tty->stopped || tty->hw_stopped || skb_queue_empty(&info->tx_queue))
return;
tasklet_schedule(&info->tasklet);
}
diff --git a/drivers/s390/net/iucv.h b/drivers/s390/net/iucv.h
index 198330217eff..0c4644d3d2f3 100644
--- a/drivers/s390/net/iucv.h
+++ b/drivers/s390/net/iucv.h
@@ -37,19 +37,19 @@
*/
#define IUCV_DBF_SETUP_NAME "iucv_setup"
#define IUCV_DBF_SETUP_LEN 32
-#define IUCV_DBF_SETUP_INDEX 1
+#define IUCV_DBF_SETUP_PAGES 2
#define IUCV_DBF_SETUP_NR_AREAS 1
#define IUCV_DBF_SETUP_LEVEL 3
#define IUCV_DBF_DATA_NAME "iucv_data"
#define IUCV_DBF_DATA_LEN 128
-#define IUCV_DBF_DATA_INDEX 1
+#define IUCV_DBF_DATA_PAGES 2
#define IUCV_DBF_DATA_NR_AREAS 1
#define IUCV_DBF_DATA_LEVEL 2
#define IUCV_DBF_TRACE_NAME "iucv_trace"
#define IUCV_DBF_TRACE_LEN 16
-#define IUCV_DBF_TRACE_INDEX 2
+#define IUCV_DBF_TRACE_PAGES 4
#define IUCV_DBF_TRACE_NR_AREAS 1
#define IUCV_DBF_TRACE_LEVEL 3
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index ab086242d305..46f34ba93ac5 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -11,7 +11,7 @@
* Frank Pavlic (pavlic@de.ibm.com) and
* Martin Schwidefsky <schwidefsky@de.ibm.com>
*
- * $Revision: 1.98 $ $Date: 2005/04/18 13:41:29 $
+ * $Revision: 1.99 $ $Date: 2005/05/11 08:10:17 $
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,7 +59,7 @@
/**
* initialization string for output
*/
-#define VERSION_LCS_C "$Revision: 1.98 $"
+#define VERSION_LCS_C "$Revision: 1.99 $"
static char version[] __initdata = "LCS driver ("VERSION_LCS_C "/" VERSION_LCS_H ")";
static char debug_buffer[255];
@@ -93,8 +93,8 @@ lcs_unregister_debug_facility(void)
static int
lcs_register_debug_facility(void)
{
- lcs_dbf_setup = debug_register("lcs_setup", 1, 1, 8);
- lcs_dbf_trace = debug_register("lcs_trace", 1, 2, 8);
+ lcs_dbf_setup = debug_register("lcs_setup", 2, 1, 8);
+ lcs_dbf_trace = debug_register("lcs_trace", 2, 2, 8);
if (lcs_dbf_setup == NULL || lcs_dbf_trace == NULL) {
PRINT_ERR("Not enough memory for debug facility.\n");
lcs_unregister_debug_facility();
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 3fd4fb754b2d..69425a7a6e98 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -1,5 +1,5 @@
/*
- * $Id: netiucv.c,v 1.63 2004/07/27 13:36:05 mschwide Exp $
+ * $Id: netiucv.c,v 1.66 2005/05/11 08:10:17 holzheu Exp $
*
* IUCV network driver
*
@@ -30,7 +30,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * RELEASE-TAG: IUCV network driver $Revision: 1.63 $
+ * RELEASE-TAG: IUCV network driver $Revision: 1.66 $
*
*/
@@ -391,15 +391,15 @@ static int
iucv_register_dbf_views(void)
{
iucv_dbf_setup = debug_register(IUCV_DBF_SETUP_NAME,
- IUCV_DBF_SETUP_INDEX,
+ IUCV_DBF_SETUP_PAGES,
IUCV_DBF_SETUP_NR_AREAS,
IUCV_DBF_SETUP_LEN);
iucv_dbf_data = debug_register(IUCV_DBF_DATA_NAME,
- IUCV_DBF_DATA_INDEX,
+ IUCV_DBF_DATA_PAGES,
IUCV_DBF_DATA_NR_AREAS,
IUCV_DBF_DATA_LEN);
iucv_dbf_trace = debug_register(IUCV_DBF_TRACE_NAME,
- IUCV_DBF_TRACE_INDEX,
+ IUCV_DBF_TRACE_PAGES,
IUCV_DBF_TRACE_NR_AREAS,
IUCV_DBF_TRACE_LEN);
@@ -2076,7 +2076,7 @@ DRIVER_ATTR(remove, 0200, NULL, remove_write);
static void
netiucv_banner(void)
{
- char vbuf[] = "$Revision: 1.63 $";
+ char vbuf[] = "$Revision: 1.66 $";
char *version = vbuf;
if ((version = strchr(version, ':'))) {
diff --git a/drivers/s390/net/qeth.h b/drivers/s390/net/qeth.h
index a755b57db46b..008e0a5d2eb3 100644
--- a/drivers/s390/net/qeth.h
+++ b/drivers/s390/net/qeth.h
@@ -42,44 +42,44 @@
*/
#define QETH_DBF_SETUP_NAME "qeth_setup"
#define QETH_DBF_SETUP_LEN 8
-#define QETH_DBF_SETUP_INDEX 3
+#define QETH_DBF_SETUP_PAGES 8
#define QETH_DBF_SETUP_NR_AREAS 1
#define QETH_DBF_SETUP_LEVEL 5
#define QETH_DBF_MISC_NAME "qeth_misc"
#define QETH_DBF_MISC_LEN 128
-#define QETH_DBF_MISC_INDEX 1
+#define QETH_DBF_MISC_PAGES 2
#define QETH_DBF_MISC_NR_AREAS 1
#define QETH_DBF_MISC_LEVEL 2
#define QETH_DBF_DATA_NAME "qeth_data"
#define QETH_DBF_DATA_LEN 96
-#define QETH_DBF_DATA_INDEX 3
+#define QETH_DBF_DATA_PAGES 8
#define QETH_DBF_DATA_NR_AREAS 1
#define QETH_DBF_DATA_LEVEL 2
#define QETH_DBF_CONTROL_NAME "qeth_control"
#define QETH_DBF_CONTROL_LEN 256
-#define QETH_DBF_CONTROL_INDEX 3
+#define QETH_DBF_CONTROL_PAGES 8
#define QETH_DBF_CONTROL_NR_AREAS 2
#define QETH_DBF_CONTROL_LEVEL 5
#define QETH_DBF_TRACE_NAME "qeth_trace"
#define QETH_DBF_TRACE_LEN 8
-#define QETH_DBF_TRACE_INDEX 2
+#define QETH_DBF_TRACE_PAGES 4
#define QETH_DBF_TRACE_NR_AREAS 2
#define QETH_DBF_TRACE_LEVEL 3
extern debug_info_t *qeth_dbf_trace;
#define QETH_DBF_SENSE_NAME "qeth_sense"
#define QETH_DBF_SENSE_LEN 64
-#define QETH_DBF_SENSE_INDEX 1
+#define QETH_DBF_SENSE_PAGES 2
#define QETH_DBF_SENSE_NR_AREAS 1
#define QETH_DBF_SENSE_LEVEL 2
#define QETH_DBF_QERR_NAME "qeth_qerr"
#define QETH_DBF_QERR_LEN 8
-#define QETH_DBF_QERR_INDEX 1
+#define QETH_DBF_QERR_PAGES 2
#define QETH_DBF_QERR_NR_AREAS 2
#define QETH_DBF_QERR_LEVEL 2
diff --git a/drivers/s390/net/qeth_main.c b/drivers/s390/net/qeth_main.c
index 208127a5033a..8f4d2999af8e 100644
--- a/drivers/s390/net/qeth_main.c
+++ b/drivers/s390/net/qeth_main.c
@@ -2210,7 +2210,7 @@ no_mem:
return NULL;
}
-static inline unsigned short
+static inline __be16
qeth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct qeth_card *card;
@@ -7639,31 +7639,31 @@ static int
qeth_register_dbf_views(void)
{
qeth_dbf_setup = debug_register(QETH_DBF_SETUP_NAME,
- QETH_DBF_SETUP_INDEX,
+ QETH_DBF_SETUP_PAGES,
QETH_DBF_SETUP_NR_AREAS,
QETH_DBF_SETUP_LEN);
qeth_dbf_misc = debug_register(QETH_DBF_MISC_NAME,
- QETH_DBF_MISC_INDEX,
+ QETH_DBF_MISC_PAGES,
QETH_DBF_MISC_NR_AREAS,
QETH_DBF_MISC_LEN);
qeth_dbf_data = debug_register(QETH_DBF_DATA_NAME,
- QETH_DBF_DATA_INDEX,
+ QETH_DBF_DATA_PAGES,
QETH_DBF_DATA_NR_AREAS,
QETH_DBF_DATA_LEN);
qeth_dbf_control = debug_register(QETH_DBF_CONTROL_NAME,
- QETH_DBF_CONTROL_INDEX,
+ QETH_DBF_CONTROL_PAGES,
QETH_DBF_CONTROL_NR_AREAS,
QETH_DBF_CONTROL_LEN);
qeth_dbf_sense = debug_register(QETH_DBF_SENSE_NAME,
- QETH_DBF_SENSE_INDEX,
+ QETH_DBF_SENSE_PAGES,
QETH_DBF_SENSE_NR_AREAS,
QETH_DBF_SENSE_LEN);
qeth_dbf_qerr = debug_register(QETH_DBF_QERR_NAME,
- QETH_DBF_QERR_INDEX,
+ QETH_DBF_QERR_PAGES,
QETH_DBF_QERR_NR_AREAS,
QETH_DBF_QERR_LEN);
qeth_dbf_trace = debug_register(QETH_DBF_TRACE_NAME,
- QETH_DBF_TRACE_INDEX,
+ QETH_DBF_TRACE_PAGES,
QETH_DBF_TRACE_NR_AREAS,
QETH_DBF_TRACE_LEN);
diff --git a/drivers/s390/net/smsgiucv.c b/drivers/s390/net/smsgiucv.c
index 1e3f7f3c662f..d6469baa7e16 100644
--- a/drivers/s390/net/smsgiucv.c
+++ b/drivers/s390/net/smsgiucv.c
@@ -138,7 +138,7 @@ static void __exit
smsg_exit(void)
{
if (smsg_handle > 0) {
- cpcmd("SET SMSG OFF", 0, 0);
+ cpcmd("SET SMSG OFF", NULL, 0, NULL);
iucv_sever(smsg_pathid, 0);
iucv_unregister_program(smsg_handle);
driver_unregister(&smsg_driver);
@@ -177,7 +177,7 @@ smsg_init(void)
smsg_handle = 0;
return -EIO;
}
- cpcmd("SET SMSG IUCV", 0, 0);
+ cpcmd("SET SMSG IUCV", NULL, 0, NULL);
return 0;
}
diff --git a/drivers/s390/s390mach.c b/drivers/s390/s390mach.c
index ffa996c8a908..5bb255e02acc 100644
--- a/drivers/s390/s390mach.c
+++ b/drivers/s390/s390mach.c
@@ -31,14 +31,14 @@ extern void css_reiterate_subchannels(void);
extern struct workqueue_struct *slow_path_wq;
extern struct work_struct slow_path_work;
-static void
+static NORET_TYPE void
s390_handle_damage(char *msg)
{
- printk(KERN_EMERG "%s\n", msg);
#ifdef CONFIG_SMP
smp_send_stop();
#endif
disabled_wait((unsigned long) __builtin_return_address(0));
+ for(;;);
}
/*
@@ -122,40 +122,39 @@ repeat:
return 0;
}
+struct mcck_struct {
+ int kill_task;
+ int channel_report;
+ int warning;
+ unsigned long long mcck_code;
+};
+
+static DEFINE_PER_CPU(struct mcck_struct, cpu_mcck);
+
/*
- * machine check handler.
+ * Main machine check handler function. Will be called with interrupts enabled
+ * or disabled and machine checks enabled or disabled.
*/
void
-s390_do_machine_check(void)
+s390_handle_mcck(void)
{
- struct mci *mci;
-
- mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+ unsigned long flags;
+ struct mcck_struct mcck;
- if (mci->sd) /* system damage */
- s390_handle_damage("received system damage machine check\n");
+ /*
+ * Disable machine checks and get the current state of accumulated
+ * machine checks. Afterwards delete the old state and enable machine
+ * checks again.
+ */
+ local_irq_save(flags);
+ local_mcck_disable();
+ mcck = __get_cpu_var(cpu_mcck);
+ memset(&__get_cpu_var(cpu_mcck), 0, sizeof(struct mcck_struct));
+ clear_thread_flag(TIF_MCCK_PENDING);
+ local_mcck_enable();
+ local_irq_restore(flags);
- if (mci->pd) /* instruction processing damage */
- s390_handle_damage("received instruction processing "
- "damage machine check\n");
-
- if (mci->se) /* storage error uncorrected */
- s390_handle_damage("received storage error uncorrected "
- "machine check\n");
-
- if (mci->sc) /* storage error corrected */
- printk(KERN_WARNING
- "received storage error corrected machine check\n");
-
- if (mci->ke) /* storage key-error uncorrected */
- s390_handle_damage("received storage key-error uncorrected "
- "machine check\n");
-
- if (mci->ds && mci->fa) /* storage degradation */
- s390_handle_damage("received storage degradation machine "
- "check\n");
-
- if (mci->cp) /* channel report word pending */
+ if (mcck.channel_report)
up(&m_sem);
#ifdef CONFIG_MACHCHK_WARNING
@@ -168,7 +167,7 @@ s390_do_machine_check(void)
* On VM we only get one interrupt per virtally presented machinecheck.
* Though one suffices, we may get one interrupt per (virtual) processor.
*/
- if (mci->w) { /* WARNING pending ? */
+ if (mcck.warning) { /* WARNING pending ? */
static int mchchk_wng_posted = 0;
/*
* Use single machine clear, as we cannot handle smp right now
@@ -178,6 +177,261 @@ s390_do_machine_check(void)
kill_proc(1, SIGPWR, 1);
}
#endif
+
+ if (mcck.kill_task) {
+ local_irq_enable();
+ printk(KERN_EMERG "mcck: Terminating task because of machine "
+ "malfunction (code 0x%016llx).\n", mcck.mcck_code);
+ printk(KERN_EMERG "mcck: task: %s, pid: %d.\n",
+ current->comm, current->pid);
+ do_exit(SIGSEGV);
+ }
+}
+
+/*
+ * returns 0 if all registers could be validated
+ * returns 1 otherwise
+ */
+static int
+s390_revalidate_registers(struct mci *mci)
+{
+ int kill_task;
+ u64 tmpclock;
+ u64 zero;
+ void *fpt_save_area, *fpt_creg_save_area;
+
+ kill_task = 0;
+ zero = 0;
+ /* General purpose registers */
+ if (!mci->gr)
+ /*
+ * General purpose registers couldn't be restored and have
+ * unknown contents. Process needs to be terminated.
+ */
+ kill_task = 1;
+
+ /* Revalidate floating point registers */
+ if (!mci->fp)
+ /*
+ * Floating point registers can't be restored and
+ * therefore the process needs to be terminated.
+ */
+ kill_task = 1;
+
+#ifndef __s390x__
+ asm volatile("ld 0,0(%0)\n"
+ "ld 2,8(%0)\n"
+ "ld 4,16(%0)\n"
+ "ld 6,24(%0)"
+ : : "a" (&S390_lowcore.floating_pt_save_area));
+#endif
+
+ if (MACHINE_HAS_IEEE) {
+#ifdef __s390x__
+ fpt_save_area = &S390_lowcore.floating_pt_save_area;
+ fpt_creg_save_area = &S390_lowcore.fpt_creg_save_area;
+#else
+ fpt_save_area = (void *) S390_lowcore.extended_save_area_addr;
+ fpt_creg_save_area = fpt_save_area+128;
+#endif
+ /* Floating point control register */
+ if (!mci->fc) {
+ /*
+ * Floating point control register can't be restored.
+ * Task will be terminated.
+ */
+ asm volatile ("lfpc 0(%0)" : : "a" (&zero));
+ kill_task = 1;
+
+ }
+ else
+ asm volatile (
+ "lfpc 0(%0)"
+ : : "a" (fpt_creg_save_area));
+
+ asm volatile("ld 0,0(%0)\n"
+ "ld 1,8(%0)\n"
+ "ld 2,16(%0)\n"
+ "ld 3,24(%0)\n"
+ "ld 4,32(%0)\n"
+ "ld 5,40(%0)\n"
+ "ld 6,48(%0)\n"
+ "ld 7,56(%0)\n"
+ "ld 8,64(%0)\n"
+ "ld 9,72(%0)\n"
+ "ld 10,80(%0)\n"
+ "ld 11,88(%0)\n"
+ "ld 12,96(%0)\n"
+ "ld 13,104(%0)\n"
+ "ld 14,112(%0)\n"
+ "ld 15,120(%0)\n"
+ : : "a" (fpt_save_area));
+ }
+
+ /* Revalidate access registers */
+ asm volatile("lam 0,15,0(%0)"
+ : : "a" (&S390_lowcore.access_regs_save_area));
+ if (!mci->ar)
+ /*
+ * Access registers have unknown contents.
+ * Terminating task.
+ */
+ kill_task = 1;
+
+ /* Revalidate control registers */
+ if (!mci->cr)
+ /*
+ * Control registers have unknown contents.
+ * Can't recover and therefore stopping machine.
+ */
+ s390_handle_damage("invalid control registers.");
+ else
+#ifdef __s390x__
+ asm volatile("lctlg 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
+#else
+ asm volatile("lctl 0,15,0(%0)"
+ : : "a" (&S390_lowcore.cregs_save_area));
+#endif
+
+ /*
+ * We don't even try to revalidate the TOD register, since we simply
+ * can't write something sensible into that register.
+ */
+
+#ifdef __s390x__
+ /*
+ * See if we can revalidate the TOD programmable register with its
+ * old contents (should be zero) otherwise set it to zero.
+ */
+ if (!mci->pr)
+ asm volatile("sr 0,0\n"
+ "sckpf"
+ : : : "0", "cc");
+ else
+ asm volatile(
+ "l 0,0(%0)\n"
+ "sckpf"
+ : : "a" (&S390_lowcore.tod_progreg_save_area) : "0", "cc");
+#endif
+
+ /* Revalidate clock comparator register */
+ asm volatile ("stck 0(%1)\n"
+ "sckc 0(%1)"
+ : "=m" (tmpclock) : "a" (&(tmpclock)) : "cc", "memory");
+
+ /* Check if old PSW is valid */
+ if (!mci->wp)
+ /*
+ * Can't tell if we come from user or kernel mode
+ * -> stopping machine.
+ */
+ s390_handle_damage("old psw invalid.");
+
+ if (!mci->ms || !mci->pm || !mci->ia)
+ kill_task = 1;
+
+ return kill_task;
+}
+
+/*
+ * machine check handler.
+ */
+void
+s390_do_machine_check(struct pt_regs *regs)
+{
+ struct mci *mci;
+ struct mcck_struct *mcck;
+ int umode;
+
+ mci = (struct mci *) &S390_lowcore.mcck_interruption_code;
+ mcck = &__get_cpu_var(cpu_mcck);
+ umode = user_mode(regs);
+
+ if (mci->sd)
+ /* System damage -> stopping machine */
+ s390_handle_damage("received system damage machine check.");
+
+ if (mci->pd) {
+ if (mci->b) {
+ /* Processing backup -> verify if we can survive this */
+ u64 z_mcic, o_mcic, t_mcic;
+#ifdef __s390x__
+ z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<29);
+ o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+ 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+ 1ULL<<30 | 1ULL<<21 | 1ULL<<20 | 1ULL<<17 |
+ 1ULL<<16);
+#else
+ z_mcic = (1ULL<<63 | 1ULL<<59 | 1ULL<<57 | 1ULL<<50 |
+ 1ULL<<29);
+ o_mcic = (1ULL<<43 | 1ULL<<42 | 1ULL<<41 | 1ULL<<40 |
+ 1ULL<<36 | 1ULL<<35 | 1ULL<<34 | 1ULL<<32 |
+ 1ULL<<30 | 1ULL<<20 | 1ULL<<17 | 1ULL<<16);
+#endif
+ t_mcic = *(u64 *)mci;
+
+ if (((t_mcic & z_mcic) != 0) ||
+ ((t_mcic & o_mcic) != o_mcic)) {
+ s390_handle_damage("processing backup machine "
+ "check with damage.");
+ }
+ if (!umode)
+ s390_handle_damage("processing backup machine "
+ "check in kernel mode.");
+ mcck->kill_task = 1;
+ mcck->mcck_code = *(unsigned long long *) mci;
+ }
+ else {
+ /* Processing damage -> stopping machine */
+ s390_handle_damage("received instruction processing "
+ "damage machine check.");
+ }
+ }
+ if (s390_revalidate_registers(mci)) {
+ if (umode) {
+ /*
+ * Couldn't restore all register contents while in
+ * user mode -> mark task for termination.
+ */
+ mcck->kill_task = 1;
+ mcck->mcck_code = *(unsigned long long *) mci;
+ set_thread_flag(TIF_MCCK_PENDING);
+ }
+ else
+ /*
+ * Couldn't restore all register contents while in
+ * kernel mode -> stopping machine.
+ */
+ s390_handle_damage("unable to revalidate registers.");
+ }
+
+ if (mci->se)
+ /* Storage error uncorrected */
+ s390_handle_damage("received storage error uncorrected "
+ "machine check.");
+
+ if (mci->ke)
+ /* Storage key-error uncorrected */
+ s390_handle_damage("received storage key-error uncorrected "
+ "machine check.");
+
+ if (mci->ds && mci->fa)
+ /* Storage degradation */
+ s390_handle_damage("received storage degradation machine "
+ "check.");
+
+ if (mci->cp) {
+ /* Channel report word pending */
+ mcck->channel_report = 1;
+ set_thread_flag(TIF_MCCK_PENDING);
+ }
+
+ if (mci->w) {
+ /* Warning pending */
+ mcck->warning = 1;
+ set_thread_flag(TIF_MCCK_PENDING);
+ }
}
/*
@@ -189,9 +443,8 @@ static int
machine_check_init(void)
{
init_MUTEX_LOCKED(&m_sem);
- ctl_clear_bit(14, 25); /* disable damage MCH */
- ctl_set_bit(14, 26); /* enable degradation MCH */
- ctl_set_bit(14, 27); /* enable system recovery MCH */
+ ctl_clear_bit(14, 25); /* disable external damage MCH */
+ ctl_set_bit(14, 27); /* enable system recovery MCH */
#ifdef CONFIG_MACHCHK_WARNING
ctl_set_bit(14, 24); /* enable warning MCH */
#endif
diff --git a/drivers/s390/s390mach.h b/drivers/s390/s390mach.h
index 7e26f0f1b0dc..4eaa70179182 100644
--- a/drivers/s390/s390mach.h
+++ b/drivers/s390/s390mach.h
@@ -16,20 +16,45 @@ struct mci {
__u32 sd : 1; /* 00 system damage */
__u32 pd : 1; /* 01 instruction-processing damage */
__u32 sr : 1; /* 02 system recovery */
- __u32 to_be_defined_1 : 4; /* 03-06 */
+ __u32 to_be_defined_1 : 1; /* 03 */
+ __u32 cd : 1; /* 04 timing-facility damage */
+ __u32 ed : 1; /* 05 external damage */
+ __u32 to_be_defined_2 : 1; /* 06 */
__u32 dg : 1; /* 07 degradation */
__u32 w : 1; /* 08 warning pending */
__u32 cp : 1; /* 09 channel-report pending */
- __u32 to_be_defined_2 : 6; /* 10-15 */
+ __u32 sp : 1; /* 10 service-processor damage */
+ __u32 ck : 1; /* 11 channel-subsystem damage */
+ __u32 to_be_defined_3 : 2; /* 12-13 */
+ __u32 b : 1; /* 14 backed up */
+ __u32 to_be_defined_4 : 1; /* 15 */
__u32 se : 1; /* 16 storage error uncorrected */
__u32 sc : 1; /* 17 storage error corrected */
__u32 ke : 1; /* 18 storage-key error uncorrected */
__u32 ds : 1; /* 19 storage degradation */
- __u32 to_be_defined_3 : 4; /* 20-23 */
+ __u32 wp : 1; /* 20 psw mwp validity */
+ __u32 ms : 1; /* 21 psw mask and key validity */
+ __u32 pm : 1; /* 22 psw program mask and cc validity */
+ __u32 ia : 1; /* 23 psw instruction address validity */
__u32 fa : 1; /* 24 failing storage address validity */
- __u32 to_be_defined_4 : 7; /* 25-31 */
+ __u32 to_be_defined_5 : 1; /* 25 */
+ __u32 ec : 1; /* 26 external damage code validity */
+ __u32 fp : 1; /* 27 floating point register validity */
+ __u32 gr : 1; /* 28 general register validity */
+ __u32 cr : 1; /* 29 control register validity */
+ __u32 to_be_defined_6 : 1; /* 30 */
+ __u32 st : 1; /* 31 storage logical validity */
__u32 ie : 1; /* 32 indirect storage error */
- __u32 to_be_defined_5 : 31; /* 33-63 */
+ __u32 ar : 1; /* 33 access register validity */
+ __u32 da : 1; /* 34 delayed access exception */
+ __u32 to_be_defined_7 : 7; /* 35-41 */
+ __u32 pr : 1; /* 42 tod programmable register validity */
+ __u32 fc : 1; /* 43 fp control register validity */
+ __u32 ap : 1; /* 44 ancillary report */
+ __u32 to_be_defined_8 : 1; /* 45 */
+ __u32 ct : 1; /* 46 cpu timer validity */
+ __u32 cc : 1; /* 47 clock comparator validity */
+ __u32 to_be_defined_9 : 16; /* 47-63 */
};
/*
diff --git a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
index 8f0f46907a81..87302fb14885 100644
--- a/drivers/sbus/char/bpp.c
+++ b/drivers/sbus/char/bpp.c
@@ -79,10 +79,6 @@ struct inst {
unsigned char run_length;
unsigned char repeat_byte;
-
- /* These members manage timeouts for programmed delays */
- wait_queue_head_t wait_queue;
- struct timer_list timer_list;
};
static struct inst instances[BPP_NO];
@@ -297,16 +293,10 @@ static unsigned short get_pins(unsigned minor)
#endif /* __sparc__ */
-static void bpp_wake_up(unsigned long val)
-{ wake_up(&instances[val].wait_queue); }
-
static void snooze(unsigned long snooze_time, unsigned minor)
{
- init_timer(&instances[minor].timer_list);
- instances[minor].timer_list.expires = jiffies + snooze_time + 1;
- instances[minor].timer_list.data = minor;
- add_timer(&instances[minor].timer_list);
- sleep_on (&instances[minor].wait_queue);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(snooze_time + 1);
}
static int wait_for(unsigned short set, unsigned short clr,
@@ -880,11 +870,8 @@ static void probeLptPort(unsigned idx)
instances[idx].enhanced = 0;
instances[idx].direction = 0;
instances[idx].mode = COMPATIBILITY;
- instances[idx].wait_queue = 0;
instances[idx].run_length = 0;
instances[idx].run_flag = 0;
- init_timer(&instances[idx].timer_list);
- instances[idx].timer_list.function = bpp_wake_up;
if (!request_region(lpAddr,3, dev_name)) return;
/*
@@ -977,11 +964,8 @@ static void probeLptPort(unsigned idx)
instances[idx].enhanced = 0;
instances[idx].direction = 0;
instances[idx].mode = COMPATIBILITY;
- init_waitqueue_head(&instances[idx].wait_queue);
instances[idx].run_length = 0;
instances[idx].run_flag = 0;
- init_timer(&instances[idx].timer_list);
- instances[idx].timer_list.function = bpp_wake_up;
if (!rp) return;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 34dbc37a79d4..bc6e4627c7a1 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -1916,9 +1916,9 @@ static void __twa_shutdown(TW_Device_Extension *tw_dev)
} /* End __twa_shutdown() */
/* Wrapper for __twa_shutdown */
-static void twa_shutdown(struct device *dev)
+static void twa_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
__twa_shutdown(tw_dev);
@@ -2140,9 +2140,7 @@ static struct pci_driver twa_driver = {
.id_table = twa_pci_tbl,
.probe = twa_probe,
.remove = twa_remove,
- .driver = {
- .shutdown = twa_shutdown
- }
+ .shutdown = twa_shutdown
};
/* This function is called on driver initialization */
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index b6dc576da430..973c51fb0fe2 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -2264,9 +2264,9 @@ static void __tw_shutdown(TW_Device_Extension *tw_dev)
} /* End __tw_shutdown() */
/* Wrapper for __tw_shutdown */
-static void tw_shutdown(struct device *dev)
+static void tw_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
__tw_shutdown(tw_dev);
@@ -2451,9 +2451,7 @@ static struct pci_driver tw_driver = {
.id_table = tw_pci_tbl,
.probe = tw_probe,
.remove = tw_remove,
- .driver = {
- .shutdown = tw_shutdown
- }
+ .shutdown = tw_shutdown,
};
/* This function is called on driver initialization */
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
index 1fef92d55dee..390cd67c57c0 100644
--- a/drivers/scsi/aacraid/commctrl.c
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -469,7 +469,7 @@ static int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
goto cleanup;
}
- user_srbcmd = kmalloc(GFP_KERNEL, fibsize);
+ user_srbcmd = kmalloc(fibsize, GFP_KERNEL);
if (!user_srbcmd) {
dprintk((KERN_DEBUG"aacraid: Could not make a copy of the srb\n"));
rcode = -ENOMEM;
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
index 9a547ca9c864..c5623694d10f 100644
--- a/drivers/scsi/ahci.c
+++ b/drivers/scsi/ahci.c
@@ -304,26 +304,19 @@ static int ahci_port_start(struct ata_port *ap)
struct device *dev = ap->host_set->dev;
struct ahci_host_priv *hpriv = ap->host_set->private_data;
struct ahci_port_priv *pp;
- int rc;
void *mem, *mmio = ap->host_set->mmio_base;
void *port_mmio = ahci_port_base(mmio, ap->port_no);
dma_addr_t mem_dma;
- rc = ata_port_start(ap);
- if (rc)
- return rc;
-
pp = kmalloc(sizeof(*pp), GFP_KERNEL);
- if (!pp) {
- rc = -ENOMEM;
- goto err_out;
- }
+ if (!pp)
+ return -ENOMEM;
memset(pp, 0, sizeof(*pp));
mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
if (!mem) {
- rc = -ENOMEM;
- goto err_out_kfree;
+ kfree(pp);
+ return -ENOMEM;
}
memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
@@ -373,12 +366,6 @@ static int ahci_port_start(struct ata_port *ap)
readl(port_mmio + PORT_CMD); /* flush */
return 0;
-
-err_out_kfree:
- kfree(pp);
-err_out:
- ata_port_stop(ap);
- return rc;
}
@@ -404,7 +391,6 @@ static void ahci_port_stop(struct ata_port *ap)
dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
pp->cmd_slot, pp->cmd_slot_dma);
kfree(pp);
- ata_port_stop(ap);
}
static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index a699c30b2662..bbe346bd3cb8 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -34,7 +34,6 @@
#define ADDR32 (0)
-#include <linux/version.h>
#include <linux/module.h>
MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
@@ -1811,9 +1810,9 @@ static int adpt_system_info(void __user *buffer)
memset(&si, 0, sizeof(si));
si.osType = OS_LINUX;
- si.osMajorVersion = (u8) (LINUX_VERSION_CODE >> 16);
- si.osMinorVersion = (u8) (LINUX_VERSION_CODE >> 8 & 0x0ff);
- si.osRevision = (u8) (LINUX_VERSION_CODE & 0x0ff);
+ si.osMajorVersion = 0;
+ si.osMinorVersion = 0;
+ si.osRevision = 0;
si.busType = SI_PCI_BUS;
si.processorFamily = DPTI_sig.dsProcessorFamily;
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index 9821783c0164..489194af43d0 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -20,15 +20,7 @@
#ifndef _DPT_H
#define _DPT_H
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,00)
-#define MAX_TO_IOP_MESSAGES (210)
-#else
#define MAX_TO_IOP_MESSAGES (255)
-#endif
#define MAX_FROM_IOP_MESSAGES (255)
@@ -321,10 +313,6 @@ static int adpt_close(struct inode *inode, struct file *file);
static void adpt_delay(int millisec);
#endif
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-static struct pci_dev* adpt_pci_find_device(uint vendor, struct pci_dev* from);
-#endif
-
#if defined __ia64__
static void adpt_ia64_info(sysInfo_S* si);
#endif
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index ba347576d99b..d7a38b6713f9 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -56,7 +56,7 @@ static struct class shost_class = {
* @shost: pointer to struct Scsi_Host
* recovery: recovery requested to run.
**/
-void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
+static void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
{
struct scsi_device *sdev;
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
index f7ddc9f1ba41..2094d4811d61 100644
--- a/drivers/scsi/initio.c
+++ b/drivers/scsi/initio.c
@@ -223,7 +223,7 @@ static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
static int int_tul_busfree(HCS * pCurHcb);
-int int_tul_scsi_rst(HCS * pCurHcb);
+static int int_tul_scsi_rst(HCS * pCurHcb);
static int int_tul_bad_seq(HCS * pCurHcb);
static int int_tul_resel(HCS * pCurHcb);
static int tul_sync_done(HCS * pCurHcb);
@@ -240,9 +240,8 @@ static int tul_se2_rd_all(WORD CurBase);
static void tul_se2_update_all(WORD CurBase); /* setup default pattern */
static void tul_read_eeprom(WORD CurBase);
- /* ---- EXTERNAL VARIABLES ---- */
-HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
/* ---- INTERNAL VARIABLES ---- */
+static HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
/*NVRAM nvram, *nvramp = &nvram; */
@@ -381,7 +380,7 @@ void tul_se2_wait(void)
******************************************************************/
-void tul_se2_instr(WORD CurBase, UCHAR instr)
+static void tul_se2_instr(WORD CurBase, UCHAR instr)
{
int i;
UCHAR b;
@@ -437,7 +436,7 @@ void tul_se2_ew_ds(WORD CurBase)
Input :address of Serial E2PROM
Output :value stored in Serial E2PROM
*******************************************************************/
-USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+static USHORT tul_se2_rd(WORD CurBase, ULONG adr)
{
UCHAR instr, readByte;
USHORT readWord;
@@ -468,7 +467,7 @@ USHORT tul_se2_rd(WORD CurBase, ULONG adr)
/******************************************************************
Input: new value in Serial E2PROM, address of Serial E2PROM
*******************************************************************/
-void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+static void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
{
UCHAR readByte;
UCHAR instr;
@@ -584,8 +583,8 @@ void tul_read_eeprom(WORD CurBase)
TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
} /* read_eeprom */
-int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
- BYTE bBus, BYTE bDevice)
+static int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
+ BYTE bBus, BYTE bDevice)
{
int i, j;
@@ -616,7 +615,7 @@ int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
return 1;
}
-void init_i91uAdapter_table(void)
+static void init_i91uAdapter_table(void)
{
int i;
@@ -630,7 +629,7 @@ void init_i91uAdapter_table(void)
return;
}
-void tul_stop_bm(HCS * pCurHcb)
+static void tul_stop_bm(HCS * pCurHcb)
{
if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) { /* if DMA xfer is pending, abort DMA xfer */
@@ -642,7 +641,7 @@ void tul_stop_bm(HCS * pCurHcb)
}
/***************************************************************************/
-void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
+static void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
{
pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE; /* Supply base address */
pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS; /* Supply BIOS address */
@@ -651,7 +650,7 @@ void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
}
/***************************************************************************/
-int tul_reset_scsi(HCS * pCurHcb, int seconds)
+static int tul_reset_scsi(HCS * pCurHcb, int seconds)
{
TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
@@ -670,7 +669,8 @@ int tul_reset_scsi(HCS * pCurHcb, int seconds)
}
/***************************************************************************/
-int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds)
+static int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb,
+ BYTE * pbBiosAdr, int seconds)
{
int i;
BYTE *pwFlags;
@@ -788,7 +788,7 @@ int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int
}
/***************************************************************************/
-SCB *tul_alloc_scb(HCS * hcsp)
+static SCB *tul_alloc_scb(HCS * hcsp)
{
SCB *pTmpScb;
ULONG flags;
@@ -807,7 +807,7 @@ SCB *tul_alloc_scb(HCS * hcsp)
}
/***************************************************************************/
-void tul_release_scb(HCS * hcsp, SCB * scbp)
+static void tul_release_scb(HCS * hcsp, SCB * scbp)
{
ULONG flags;
@@ -829,7 +829,7 @@ void tul_release_scb(HCS * hcsp, SCB * scbp)
}
/***************************************************************************/
-void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
{
#if DEBUG_QUEUE
@@ -847,7 +847,7 @@ void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
}
/***************************************************************************/
-void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
{
#if DEBUG_QUEUE
@@ -863,7 +863,7 @@ void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
}
/***************************************************************************/
-SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+static SCB *tul_find_first_pend_scb(HCS * pCurHcb)
{
SCB *pFirstPend;
@@ -894,24 +894,7 @@ SCB *tul_find_first_pend_scb(HCS * pCurHcb)
return (pFirstPend);
}
/***************************************************************************/
-SCB *tul_pop_pend_scb(HCS * pCurHcb)
-{
- SCB *pTmpScb;
-
- if ((pTmpScb = pCurHcb->HCS_FirstPend) != NULL) {
- if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
- pCurHcb->HCS_LastPend = NULL;
- pTmpScb->SCB_NxtScb = NULL;
- }
-#if DEBUG_QUEUE
- printk("Pop pend SCB %lx; ", (ULONG) pTmpScb);
-#endif
- return (pTmpScb);
-}
-
-
-/***************************************************************************/
-void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
{
SCB *pTmpScb, *pPrevScb;
@@ -939,7 +922,7 @@ void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
return;
}
/***************************************************************************/
-void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
{
#if DEBUG_QUEUE
@@ -961,7 +944,7 @@ void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
}
/***************************************************************************/
-SCB *tul_pop_busy_scb(HCS * pCurHcb)
+static SCB *tul_pop_busy_scb(HCS * pCurHcb)
{
SCB *pTmpScb;
@@ -982,7 +965,7 @@ SCB *tul_pop_busy_scb(HCS * pCurHcb)
}
/***************************************************************************/
-void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
{
SCB *pTmpScb, *pPrevScb;
@@ -1037,7 +1020,7 @@ SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
}
/***************************************************************************/
-void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+static void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
{
#if DEBUG_QUEUE
@@ -1073,7 +1056,7 @@ SCB *tul_find_done_scb(HCS * pCurHcb)
}
/***************************************************************************/
-int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+static int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
{
ULONG flags;
SCB *pTmpScb, *pPrevScb;
@@ -1163,7 +1146,7 @@ int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
}
/***************************************************************************/
-int tul_bad_seq(HCS * pCurHcb)
+static int tul_bad_seq(HCS * pCurHcb)
{
SCB *pCurScb;
@@ -1182,9 +1165,11 @@ int tul_bad_seq(HCS * pCurHcb)
return (tul_post_scsi_rst(pCurHcb));
}
+#if 0
+
/************************************************************************/
-int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
- unsigned int target, unsigned int ResetFlags)
+static int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
+ unsigned int target, unsigned int ResetFlags)
{
ULONG flags;
SCB *pScb;
@@ -1255,7 +1240,7 @@ int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
return SCSI_RESET_PENDING;
}
-int tul_reset_scsi_bus(HCS * pCurHcb)
+static int tul_reset_scsi_bus(HCS * pCurHcb)
{
ULONG flags;
@@ -1284,8 +1269,10 @@ int tul_reset_scsi_bus(HCS * pCurHcb)
return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
}
+#endif /* 0 */
+
/************************************************************************/
-void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+static void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
{
ULONG flags;
@@ -1318,7 +1305,7 @@ void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
}
/***************************************************************************/
-int tul_isr(HCS * pCurHcb)
+static int tul_isr(HCS * pCurHcb)
{
/* Enter critical section */
@@ -2108,7 +2095,7 @@ int int_tul_busfree(HCS * pCurHcb)
/***************************************************************************/
/* scsi bus reset */
-int int_tul_scsi_rst(HCS * pCurHcb)
+static int int_tul_scsi_rst(HCS * pCurHcb)
{
SCB *pCurScb;
int i;
@@ -2214,7 +2201,7 @@ int int_tul_resel(HCS * pCurHcb)
/***************************************************************************/
-int int_tul_bad_seq(HCS * pCurHcb)
+static int int_tul_bad_seq(HCS * pCurHcb)
{ /* target wrong phase */
SCB *pCurScb;
int i;
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
index df3ed7c1cee3..3efb1184fc39 100644
--- a/drivers/scsi/initio.h
+++ b/drivers/scsi/initio.h
@@ -719,21 +719,3 @@ typedef struct _HCSinfo {
#define SCSI_RESET_HOST_RESET 0x200
#define SCSI_RESET_ACTION 0xff
-extern void init_i91uAdapter_table(void);
-extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
-extern int tul_ReturnNumberOfAdapters(void);
-extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index);
-extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time);
-extern SCB *tul_alloc_scb(HCS * pHCB);
-extern int tul_abort_srb(HCS * pHCB, struct scsi_cmnd * pSRB);
-extern void tul_exec_scb(HCS * pHCB, SCB * pSCB);
-extern void tul_release_scb(HCS * pHCB, SCB * pSCB);
-extern void tul_stop_bm(HCS * pHCB);
-extern int tul_reset_scsi(HCS * pCurHcb, int seconds);
-extern int tul_isr(HCS * pHCB);
-extern int tul_reset(HCS * pHCB, struct scsi_cmnd * pSRB, unsigned char target);
-extern int tul_reset_scsi_bus(HCS * pCurHcb);
-extern int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
- unsigned int target, unsigned int ResetFlags);
- /* ---- EXTERNAL VARIABLES ---- */
-extern HCS tul_hcs[];
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 80d022625c82..babd48363402 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -6012,7 +6012,7 @@ static int __devinit ipr_probe(struct pci_dev *pdev,
/**
* ipr_shutdown - Shutdown handler.
- * @dev: device struct
+ * @pdev: pci device struct
*
* This function is invoked upon system shutdown/reboot. It will issue
* an adapter shutdown to the adapter to flush the write cache.
@@ -6020,9 +6020,9 @@ static int __devinit ipr_probe(struct pci_dev *pdev,
* Return value:
* none
**/
-static void ipr_shutdown(struct device *dev)
+static void ipr_shutdown(struct pci_dev *pdev)
{
- struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev));
+ struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
unsigned long lock_flags = 0;
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
@@ -6068,9 +6068,7 @@ static struct pci_driver ipr_driver = {
.id_table = ipr_pci_table,
.probe = ipr_probe,
.remove = ipr_remove,
- .driver = {
- .shutdown = ipr_shutdown,
- },
+ .shutdown = ipr_shutdown,
};
/**
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 36b401fee1f1..cb535fa185b9 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1408,7 +1408,9 @@ void __sata_phy_reset(struct ata_port *ap)
if (ap->flags & ATA_FLAG_SATA_RESET) {
/* issue phy wake/reset */
scr_write_flush(ap, SCR_CONTROL, 0x301);
- udelay(400); /* FIXME: a guess */
+ /* Couldn't find anything in SATA I/II specs, but
+ * AHCI-1.1 10.4.2 says at least 1 ms. */
+ mdelay(1);
}
scr_write_flush(ap, SCR_CONTROL, 0x300); /* phy wake/clear reset */
@@ -1920,6 +1922,7 @@ static const char * ata_dma_blacklist [] = {
"HITACHI CDR-8335",
"HITACHI CDR-8435",
"Toshiba CD-ROM XM-6202B",
+ "TOSHIBA CD-ROM XM-1702BC",
"CD-532E-A",
"E-IDE CD-ROM CR-840",
"CD-ROM Drive/F5A",
@@ -1927,7 +1930,6 @@ static const char * ata_dma_blacklist [] = {
"SAMSUNG CD-ROM SC-148C",
"SAMSUNG CD-ROM SC",
"SanDisk SDP3B-64",
- "SAMSUNG CD-ROM SN-124",
"ATAPI CD-ROM DRIVE 40X MAXIMUM",
"_NEC DV5800A",
};
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
index 7a4adc4c8f09..794fb559efb0 100644
--- a/drivers/scsi/libata-scsi.c
+++ b/drivers/scsi/libata-scsi.c
@@ -1176,8 +1176,12 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
n_sectors = ata_id_u32(args->id, 60);
n_sectors--; /* ATA TotalUserSectors - 1 */
- tmp = n_sectors; /* note: truncates, if lba48 */
if (args->cmd->cmnd[0] == READ_CAPACITY) {
+ if( n_sectors >= 0xffffffffULL )
+ tmp = 0xffffffff ; /* Return max count on overflow */
+ else
+ tmp = n_sectors ;
+
/* sector count, 32-bit */
rbuf[0] = tmp >> (8 * 3);
rbuf[1] = tmp >> (8 * 2);
@@ -1191,10 +1195,12 @@ unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
} else {
/* sector count, 64-bit */
- rbuf[2] = n_sectors >> (8 * 7);
- rbuf[3] = n_sectors >> (8 * 6);
- rbuf[4] = n_sectors >> (8 * 5);
- rbuf[5] = n_sectors >> (8 * 4);
+ tmp = n_sectors >> (8 * 4);
+ rbuf[2] = tmp >> (8 * 3);
+ rbuf[3] = tmp >> (8 * 2);
+ rbuf[4] = tmp >> (8 * 1);
+ rbuf[5] = tmp;
+ tmp = n_sectors;
rbuf[6] = tmp >> (8 * 3);
rbuf[7] = tmp >> (8 * 2);
rbuf[8] = tmp >> (8 * 1);
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
index edd47d1f0b17..932dcf0366eb 100644
--- a/drivers/scsi/mac53c94.c
+++ b/drivers/scsi/mac53c94.c
@@ -424,7 +424,7 @@ static struct scsi_host_template mac53c94_template = {
.use_clustering = DISABLE_CLUSTERING,
};
-static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match)
+static int mac53c94_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *node = macio_get_of_node(mdev);
struct pci_dev *pdev = macio_get_pci_dev(mdev);
@@ -544,15 +544,14 @@ static int mac53c94_remove(struct macio_dev *mdev)
}
-static struct of_match mac53c94_match[] =
+static struct of_device_id mac53c94_match[] =
{
{
.name = "53c94",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{},
};
+MODULE_DEVICE_TABLE (of, mac53c94_match);
static struct macio_driver mac53c94_driver =
{
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index ec81532eb845..a70cdf31311c 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -5036,9 +5036,9 @@ megaraid_remove_one(struct pci_dev *pdev)
}
static void
-megaraid_shutdown(struct device *dev)
+megaraid_shutdown(struct pci_dev *pdev)
{
- struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+ struct Scsi_Host *host = pci_get_drvdata(pdev);
adapter_t *adapter = (adapter_t *)host->hostdata;
__megaraid_shutdown(adapter);
@@ -5070,9 +5070,7 @@ static struct pci_driver megaraid_pci_driver = {
.id_table = megaraid_pci_tbl,
.probe = megaraid_probe_one,
.remove = __devexit_p(megaraid_remove_one),
- .driver = {
- .shutdown = megaraid_shutdown,
- },
+ .shutdown = megaraid_shutdown,
};
static int __init megaraid_init(void)
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
index b05737ae5eff..ff1933298da6 100644
--- a/drivers/scsi/mesh.c
+++ b/drivers/scsi/mesh.c
@@ -1847,7 +1847,7 @@ static struct scsi_host_template mesh_template = {
.use_clustering = DISABLE_CLUSTERING,
};
-static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
+static int mesh_probe(struct macio_dev *mdev, const struct of_device_id *match)
{
struct device_node *mesh = macio_get_of_node(mdev);
struct pci_dev* pdev = macio_get_pci_dev(mdev);
@@ -2012,20 +2012,18 @@ static int mesh_remove(struct macio_dev *mdev)
}
-static struct of_match mesh_match[] =
+static struct of_device_id mesh_match[] =
{
{
.name = "mesh",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
- .name = OF_ANY_MATCH,
.type = "scsi",
.compatible = "chrp,mesh0"
},
{},
};
+MODULE_DEVICE_TABLE (of, mesh_match);
static struct macio_driver mesh_driver =
{
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
index e60b4c0a8427..7c5306499832 100644
--- a/drivers/scsi/pcmcia/aha152x_stub.c
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -50,7 +50,6 @@
#include <scsi/scsi_host.h>
#include "aha152x.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -134,11 +133,6 @@ static dev_link_t *aha152x_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &aha152x_event;
- client_reg.EventMask =
- CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -318,13 +312,25 @@ static int aha152x_event(event_t event, int priority,
return 0;
}
+static struct pcmcia_device_id aha152x_ids[] = {
+ PCMCIA_DEVICE_PROD_ID123("New Media", "SCSI", "Bus Toaster", 0xcdf7e4cc, 0x35f26476, 0xa8851d6e),
+ PCMCIA_DEVICE_PROD_ID123("NOTEWORTHY", "SCSI", "Bus Toaster", 0xad89c6e8, 0x35f26476, 0xa8851d6e),
+ PCMCIA_DEVICE_PROD_ID12("Adaptec, Inc.", "APA-1460 SCSI Host Adapter", 0x24ba9738, 0x3a3c3d20),
+ PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "Multimedia Sound/SCSI", 0x085a850b, 0x80a6535c),
+ PCMCIA_DEVICE_PROD_ID12("NOTEWORTHY", "NWCOMB02 SCSI/AUDIO COMBO CARD", 0xad89c6e8, 0x5f9a615b),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, aha152x_ids);
+
static struct pcmcia_driver aha152x_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "aha152x_cs",
},
.attach = aha152x_attach,
+ .event = aha152x_event,
.detach = aha152x_detach,
+ .id_table = aha152x_ids,
};
static int __init init_aha152x_cs(void)
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
index 3df7bc72e354..db8f5cd85ffe 100644
--- a/drivers/scsi/pcmcia/fdomain_stub.c
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -47,7 +47,6 @@
#include <scsi/scsi_host.h>
#include "fdomain.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -120,11 +119,6 @@ static dev_link_t *fdomain_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &fdomain_event;
- client_reg.EventMask =
- CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -299,13 +293,24 @@ static int fdomain_event(event_t event, int priority,
return 0;
} /* fdomain_event */
+
+static struct pcmcia_device_id fdomain_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("IBM Corp.", "SCSI PCMCIA Card", 0xe3736c88, 0x859cad20),
+ PCMCIA_DEVICE_PROD_ID1("SCSI PCMCIA Adapter Card", 0x8dacb57e),
+ PCMCIA_DEVICE_PROD_ID12(" SIMPLE TECHNOLOGY Corporation", "SCSI PCMCIA Credit Card Controller", 0x182bdafe, 0xc80d106f),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, fdomain_ids);
+
static struct pcmcia_driver fdomain_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "fdomain_cs",
},
.attach = fdomain_attach,
+ .event = fdomain_event,
.detach = fdomain_detach,
+ .id_table = fdomain_ids,
};
static int __init init_fdomain_cs(void)
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 3dddb323e718..3cd3b40b1a4c 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -51,7 +51,6 @@
#include <scsi/scsi.h>
#include <scsi/scsi_ioctl.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -1642,11 +1641,6 @@ static dev_link_t *nsp_cs_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME ;
- client_reg.event_handler = &nsp_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -2125,13 +2119,27 @@ static int nsp_cs_event(event_t event,
* module entry point
*====================================================================*/
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+static struct pcmcia_device_id nsp_cs_ids[] = {
+ PCMCIA_DEVICE_PROD_ID123("IO DATA", "CBSC16 ", "1", 0x547e66dc, 0x0d63a3fd, 0x51de003a),
+ PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-001", "1", 0x534c02bc, 0x52008408, 0x51de003a),
+ PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-002", "1", 0x534c02bc, 0xcb09d5b2, 0x51de003a),
+ PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-003", "1", 0x534c02bc, 0xbc0ee524, 0x51de003a),
+ PCMCIA_DEVICE_PROD_ID123("KME ", "SCSI-CARD-004", "1", 0x534c02bc, 0x226a7087, 0x51de003a),
+ PCMCIA_DEVICE_PROD_ID123("WBT", "NinjaSCSI-3", "R1.0", 0xc7ba805f, 0xfdc7c97d, 0x6973710e),
+ PCMCIA_DEVICE_PROD_ID123("WORKBIT", "UltraNinja-16", "1", 0x28191418, 0xb70f4b09, 0x51de003a),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, nsp_cs_ids);
+
static struct pcmcia_driver nsp_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "nsp_cs",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "nsp_cs",
},
- .attach = nsp_cs_attach,
- .detach = nsp_cs_detach,
+ .attach = nsp_cs_attach,
+ .event = nsp_cs_event,
+ .detach = nsp_cs_detach,
+ .id_table = nsp_cs_ids,
};
#endif
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
index a0175f5d11cd..7a516f35834e 100644
--- a/drivers/scsi/pcmcia/qlogic_stub.c
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -49,7 +49,6 @@
#include <scsi/scsi_host.h>
#include "../qlogicfas408.h"
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -194,8 +193,6 @@ static dev_link_t *qlogic_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &qlogic_event;
- client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -395,6 +392,27 @@ static int qlogic_event(event_t event, int priority, event_callback_args_t * arg
return 0;
} /* qlogic_event */
+static struct pcmcia_device_id qlogic_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("EIger Labs", "PCMCIA-to-SCSI Adapter", 0x88395fa7, 0x33b7a5e6),
+ PCMCIA_DEVICE_PROD_ID12("EPSON", "SCSI-2 PC Card SC200", 0xd361772f, 0x299d1751),
+ PCMCIA_DEVICE_PROD_ID12("MACNICA", "MIRACLE SCSI-II mPS110", 0x20841b68, 0xab3c3b6d),
+ PCMCIA_DEVICE_PROD_ID12("MIDORI ELECTRONICS ", "CN-SC43", 0x6534382a, 0xd67eee79),
+ PCMCIA_DEVICE_PROD_ID12("NEC", "PC-9801N-J03R", 0x18df0ba0, 0x24662e8a),
+ PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC003", 0x82375a27, 0xf68e5bf7),
+ PCMCIA_DEVICE_PROD_ID12("KME ", "KXLC004", 0x82375a27, 0x68eace54),
+ PCMCIA_DEVICE_PROD_ID12("KME", "KXLC101", 0x3faee676, 0x194250ec),
+ PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05", 0xd77b2930, 0xa85b2735),
+ PCMCIA_DEVICE_PROD_ID12("QLOGIC CORPORATION", "pc05 rev 1.10", 0xd77b2930, 0x70f8b5f8),
+ PCMCIA_DEVICE_PROD_ID123("KME", "KXLC002", "00", 0x3faee676, 0x81896b61, 0xf99f065f),
+ PCMCIA_DEVICE_PROD_ID12("RATOC System Inc.", "SCSI2 CARD 37", 0x85c10e17, 0x1a2640c1),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200A PC CARD SCSI", 0xb4585a1a, 0xa6f06ebe),
+ PCMCIA_DEVICE_PROD_ID12("TOSHIBA", "SCSC200B PC CARD SCSI-10", 0xb4585a1a, 0x0a88dea0),
+ /* these conflict with other cards! */
+ /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+ /* PCMCIA_DEVICE_PROD_ID123("MACNICA", "MIRACLE SCSI", "mPS100", 0x20841b68, 0xf8dedaeb, 0x89f7fafb), */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, qlogic_ids);
static struct pcmcia_driver qlogic_cs_driver = {
.owner = THIS_MODULE,
@@ -402,7 +420,9 @@ static struct pcmcia_driver qlogic_cs_driver = {
.name = "qlogic_cs",
},
.attach = qlogic_attach,
+ .event = qlogic_event,
.detach = qlogic_detach,
+ .id_table = qlogic_ids,
};
static int __init init_qlogic_cs(void)
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
index 1667da9508b4..b4b3a1a8a0c7 100644
--- a/drivers/scsi/pcmcia/sym53c500_cs.c
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -979,10 +979,6 @@ SYM53C500_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.event_handler = &SYM53C500_event;
- client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -999,13 +995,23 @@ MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
MODULE_LICENSE("GPL");
+static struct pcmcia_device_id sym53c500_ids[] = {
+ PCMCIA_DEVICE_PROD_ID12("BASICS by New Media Corporation", "SCSI Sym53C500", 0x23c78a9d, 0x0099e7f7),
+ PCMCIA_DEVICE_PROD_ID12("New Media Corporation", "SCSI Bus Toaster Sym53C500", 0x085a850b, 0x45432eb8),
+ PCMCIA_DEVICE_PROD_ID2("SCSI9000", 0x21648f44),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sym53c500_ids);
+
static struct pcmcia_driver sym53c500_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "sym53c500_cs",
},
.attach = SYM53C500_attach,
+ .event = SYM53C500_event,
.detach = SYM53C500_detach,
+ .id_table = sym53c500_ids,
};
static int __init
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 5578ae9a9e45..1cb5f7d4f278 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -68,6 +68,8 @@
#include "scsi_priv.h"
#include "scsi_logging.h"
+static void scsi_done(struct scsi_cmnd *cmd);
+static int scsi_retry_command(struct scsi_cmnd *cmd);
/*
* Definitions and constants.
@@ -741,7 +743,7 @@ static DEFINE_PER_CPU(struct list_head, scsi_done_q);
*
* This function is interrupt context safe.
*/
-void scsi_done(struct scsi_cmnd *cmd)
+static void scsi_done(struct scsi_cmnd *cmd)
{
/*
* We don't have to worry about this one timing out any more.
@@ -836,7 +838,7 @@ static void scsi_softirq(struct softirq_action *h)
* level drivers should not become re-entrant as a result of
* this.
*/
-int scsi_retry_command(struct scsi_cmnd *cmd)
+static int scsi_retry_command(struct scsi_cmnd *cmd)
{
/*
* Restore the SCSI command state.
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index e0208886b45e..322b5a41a36f 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -1783,7 +1783,7 @@ static void __exit scsi_debug_exit(void)
device_initcall(scsi_debug_init);
module_exit(scsi_debug_exit);
-void pseudo_0_release(struct device * dev)
+static void pseudo_0_release(struct device * dev)
{
if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f996499fa9d..10506f9cd0c9 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -44,7 +44,7 @@ struct scsi_host_sg_pool {
#endif
#define SP(x) { x, "sgpool-" #x }
-struct scsi_host_sg_pool scsi_sg_pools[] = {
+static struct scsi_host_sg_pool scsi_sg_pools[] = {
SP(8),
SP(16),
SP(32),
@@ -632,7 +632,7 @@ static void scsi_free_sgtable(struct scatterlist *sgl, int index)
{
struct scsi_host_sg_pool *sgp;
- BUG_ON(index > SG_MEMPOOL_NR);
+ BUG_ON(index >= SG_MEMPOOL_NR);
sgp = scsi_sg_pools + index;
mempool_free(sgl, sgp->pool);
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index c01580df4476..96d4f745975c 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -61,8 +61,6 @@ extern void scsi_exit_hosts(void);
extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
-extern void scsi_done(struct scsi_cmnd *cmd);
-extern int scsi_retry_command(struct scsi_cmnd *cmd);
extern int scsi_insert_special_req(struct scsi_request *sreq, int);
extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
struct scsi_request *sreq);
@@ -136,7 +134,6 @@ extern void scsi_exit_sysctl(void);
#endif /* CONFIG_SYSCTL */
/* scsi_sysfs.c */
-extern void scsi_device_dev_release(struct device *);
extern int scsi_sysfs_add_sdev(struct scsi_device *);
extern int scsi_sysfs_add_host(struct Scsi_Host *);
extern int scsi_sysfs_register(void);
@@ -145,7 +142,6 @@ extern void scsi_sysfs_device_initialize(struct scsi_device *);
extern int scsi_sysfs_target_initialize(struct scsi_device *);
extern struct scsi_transport_template blank_transport_template;
-extern struct class sdev_class;
extern struct bus_type scsi_bus_type;
/*
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 93b41100a6d8..beed7fbe1cbe 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -150,7 +150,7 @@ static void scsi_device_cls_release(struct class_device *class_dev)
put_device(&sdev->sdev_gendev);
}
-void scsi_device_dev_release(struct device *dev)
+static void scsi_device_dev_release(struct device *dev)
{
struct scsi_device *sdev;
struct device *parent;
@@ -185,7 +185,7 @@ void scsi_device_dev_release(struct device *dev)
put_device(parent);
}
-struct class sdev_class = {
+static struct class sdev_class = {
.name = "scsi_device",
.release = scsi_device_cls_release,
};
diff --git a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c
index db92a0ceda79..d27fb4c881d2 100644
--- a/drivers/serial/68328serial.c
+++ b/drivers/serial/68328serial.c
@@ -992,18 +992,17 @@ static int get_lsr_info(struct m68k_serial * info, unsigned int *value)
/*
* This routine sends a break character out the serial port.
*/
-static void send_break( struct m68k_serial * info, int duration)
+static void send_break(struct m68k_serial * info, unsigned int duration)
{
m68328_uart *uart = &uart_addr[info->line];
unsigned long flags;
if (!info->port)
return;
- set_current_state(TASK_INTERRUPTIBLE);
save_flags(flags);
cli();
#ifdef USE_INTS
uart->utx.w |= UTX_SEND_BREAK;
- schedule_timeout(duration);
+ msleep_interruptible(duration);
uart->utx.w &= ~UTX_SEND_BREAK;
#endif
restore_flags(flags);
@@ -1033,14 +1032,14 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
return retval;
tty_wait_until_sent(tty, 0);
if (!arg)
- send_break(info, HZ/4); /* 1/4 second */
+ send_break(info, 250); /* 1/4 second */
return 0;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ send_break(info, arg ? arg*(100) : 250);
return 0;
case TIOCGSOFTCAR:
error = put_user(C_CLOCAL(tty) ? 1 : 0,
@@ -1498,23 +1497,6 @@ rs68328_init(void)
return 0;
}
-
-
-/*
- * register_serial and unregister_serial allows for serial ports to be
- * configured at run-time, to support PCMCIA modems.
- */
-/* SPARC: Unused at this time, just here to make things link. */
-int register_serial(struct serial_struct *req)
-{
- return -1;
-}
-
-void unregister_serial(int line)
-{
- return;
-}
-
module_init(rs68328_init);
diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c
index f148022b6b4e..b116122e569a 100644
--- a/drivers/serial/68360serial.c
+++ b/drivers/serial/68360serial.c
@@ -1394,14 +1394,13 @@ static void end_break(ser_info_t *info)
/*
* This routine sends a break character out the serial port.
*/
-static void send_break(ser_info_t *info, int duration)
+static void send_break(ser_info_t *info, unsigned int duration)
{
- set_current_state(TASK_INTERRUPTIBLE);
#ifdef SERIAL_DEBUG_SEND_BREAK
printk("rs_send_break(%d) jiff=%lu...", duration, jiffies);
#endif
begin_break(info);
- schedule_timeout(duration);
+ msleep_interruptible(duration);
end_break(info);
#ifdef SERIAL_DEBUG_SEND_BREAK
printk("done jiffies=%lu\n", jiffies);
@@ -1436,7 +1435,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
if (signal_pending(current))
return -EINTR;
if (!arg) {
- send_break(info, HZ/4); /* 1/4 second */
+ send_break(info, 250); /* 1/4 second */
if (signal_pending(current))
return -EINTR;
}
@@ -1448,7 +1447,7 @@ static int rs_360_ioctl(struct tty_struct *tty, struct file * file,
tty_wait_until_sent(tty, 0);
if (signal_pending(current))
return -EINTR;
- send_break(info, arg ? arg*(HZ/10) : HZ/4);
+ send_break(info, arg ? arg*100 : 250);
if (signal_pending(current))
return -EINTR;
return 0;
diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 30e8beb71430..7e8fc7c1d4cc 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -77,23 +77,9 @@ static unsigned int share_irqs = SERIAL8250_SHARE_IRQS;
*/
#define is_real_interrupt(irq) ((irq) != 0)
-/*
- * This converts from our new CONFIG_ symbols to the symbols
- * that asm/serial.h expects. You _NEED_ to comment out the
- * linux/config.h include contained inside asm/serial.h for
- * this to work.
- */
-#undef CONFIG_SERIAL_MANY_PORTS
-#undef CONFIG_SERIAL_DETECT_IRQ
-#undef CONFIG_SERIAL_MULTIPORT
-#undef CONFIG_HUB6
-
#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
#define CONFIG_SERIAL_DETECT_IRQ 1
#endif
-#ifdef CONFIG_SERIAL_8250_MULTIPORT
-#define CONFIG_SERIAL_MULTIPORT 1
-#endif
#ifdef CONFIG_SERIAL_8250_MANY_PORTS
#define CONFIG_SERIAL_MANY_PORTS 1
#endif
@@ -119,7 +105,7 @@ static struct old_serial_port old_serial_port[] = {
SERIAL_PORT_DFNS /* defined in asm/serial.h */
};
-#define UART_NR (ARRAY_SIZE(old_serial_port) + CONFIG_SERIAL_8250_NR_UARTS)
+#define UART_NR CONFIG_SERIAL_8250_NR_UARTS
#ifdef CONFIG_SERIAL_8250_RSA
@@ -132,9 +118,9 @@ struct uart_8250_port {
struct uart_port port;
struct timer_list timer; /* "no irq" timer */
struct list_head list; /* ports on this IRQ */
- unsigned int capabilities; /* port capabilities */
+ unsigned short capabilities; /* port capabilities */
+ unsigned short bugs; /* port bugs */
unsigned int tx_loadsz; /* transmit fifo load size */
- unsigned short rev;
unsigned char acr;
unsigned char ier;
unsigned char lcr;
@@ -560,7 +546,14 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
if (id1 == 0x16 && id2 == 0xC9 &&
(id3 == 0x50 || id3 == 0x52 || id3 == 0x54)) {
up->port.type = PORT_16C950;
- up->rev = rev | (id3 << 8);
+
+ /*
+ * Enable work around for the Oxford Semiconductor 952 rev B
+ * chip which causes it to seriously miscalculate baud rates
+ * when DLL is 0.
+ */
+ if (id3 == 0x52 && rev == 0x01)
+ up->bugs |= UART_BUG_QUOT;
return;
}
@@ -577,8 +570,6 @@ static void autoconfig_has_efr(struct uart_8250_port *up)
id2 = id1 >> 8;
if (id2 == 0x10 || id2 == 0x12 || id2 == 0x14) {
- if (id2 == 0x10)
- up->rev = id1 & 255;
up->port.type = PORT_16850;
return;
}
@@ -809,6 +800,7 @@ static void autoconfig(struct uart_8250_port *up, unsigned int probeflags)
// save_flags(flags); cli();
up->capabilities = 0;
+ up->bugs = 0;
if (!(up->port.flags & UPF_BUGGY_UART)) {
/*
@@ -1001,26 +993,31 @@ static void autoconfig_irq(struct uart_8250_port *up)
up->port.irq = (irq > 0) ? irq : 0;
}
+static inline void __stop_tx(struct uart_8250_port *p)
+{
+ if (p->ier & UART_IER_THRI) {
+ p->ier &= ~UART_IER_THRI;
+ serial_out(p, UART_IER, p->ier);
+ }
+}
+
static void serial8250_stop_tx(struct uart_port *port, unsigned int tty_stop)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
- if (up->ier & UART_IER_THRI) {
- up->ier &= ~UART_IER_THRI;
- serial_out(up, UART_IER, up->ier);
- }
+ __stop_tx(up);
/*
- * We only do this from uart_stop - if we run out of
- * characters to send, we don't want to prevent the
- * FIFO from emptying.
+ * We really want to stop the transmitter from sending.
*/
- if (up->port.type == PORT_16C950 && tty_stop) {
+ if (up->port.type == PORT_16C950) {
up->acr |= UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
}
+static void transmit_chars(struct uart_8250_port *up);
+
static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
@@ -1028,11 +1025,20 @@ static void serial8250_start_tx(struct uart_port *port, unsigned int tty_start)
if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_out(up, UART_IER, up->ier);
+
+ if (up->bugs & UART_BUG_TXEN) {
+ unsigned char lsr, iir;
+ lsr = serial_in(up, UART_LSR);
+ iir = serial_in(up, UART_IIR);
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT)
+ transmit_chars(up);
+ }
}
+
/*
- * We only do this from uart_start
+ * Re-enable the transmitter if we disabled it.
*/
- if (tty_start && up->port.type == PORT_16C950) {
+ if (up->port.type == PORT_16C950 && up->acr & UART_ACR_TXDIS) {
up->acr &= ~UART_ACR_TXDIS;
serial_icr_write(up, UART_ACR, up->acr);
}
@@ -1153,7 +1159,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
return;
}
if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
- serial8250_stop_tx(&up->port, 0);
+ __stop_tx(up);
return;
}
@@ -1172,7 +1178,7 @@ static _INLINE_ void transmit_chars(struct uart_8250_port *up)
DEBUG_INTR("THRE...");
if (uart_circ_empty(xmit))
- serial8250_stop_tx(&up->port, 0);
+ __stop_tx(up);
}
static _INLINE_ void check_modem_status(struct uart_8250_port *up)
@@ -1374,13 +1380,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
- unsigned long flags;
unsigned char status;
unsigned int ret;
- spin_lock_irqsave(&up->port.lock, flags);
status = serial_in(up, UART_MSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
if (status & UART_MSR_DCD)
@@ -1433,6 +1436,7 @@ static int serial8250_startup(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
unsigned long flags;
+ unsigned char lsr, iir;
int retval;
up->capabilities = uart_config[up->port.type].flags;
@@ -1536,6 +1540,26 @@ static int serial8250_startup(struct uart_port *port)
up->port.mctrl |= TIOCM_OUT2;
serial8250_set_mctrl(&up->port, up->port.mctrl);
+
+ /*
+ * Do a quick test to see if we receive an
+ * interrupt when we enable the TX irq.
+ */
+ serial_outp(up, UART_IER, UART_IER_THRI);
+ lsr = serial_in(up, UART_LSR);
+ iir = serial_in(up, UART_IIR);
+ serial_outp(up, UART_IER, 0);
+
+ if (lsr & UART_LSR_TEMT && iir & UART_IIR_NO_INT) {
+ if (!(up->bugs & UART_BUG_TXEN)) {
+ up->bugs |= UART_BUG_TXEN;
+ pr_debug("ttyS%d - enabling bad tx status workarounds\n",
+ port->line);
+ }
+ } else {
+ up->bugs &= ~UART_BUG_TXEN;
+ }
+
spin_unlock_irqrestore(&up->port.lock, flags);
/*
@@ -1645,22 +1669,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
switch (termios->c_cflag & CSIZE) {
case CS5:
- cval = 0x00;
+ cval = UART_LCR_WLEN5;
break;
case CS6:
- cval = 0x01;
+ cval = UART_LCR_WLEN6;
break;
case CS7:
- cval = 0x02;
+ cval = UART_LCR_WLEN7;
break;
default:
case CS8:
- cval = 0x03;
+ cval = UART_LCR_WLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
- cval |= 0x04;
+ cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
@@ -1677,12 +1701,9 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
quot = serial8250_get_divisor(port, baud);
/*
- * Work around a bug in the Oxford Semiconductor 952 rev B
- * chip which causes it to seriously miscalculate baud rates
- * when DLL is 0.
+ * Oxford Semi 952 rev B workaround
*/
- if ((quot & 0xff) == 0 && up->port.type == PORT_16C950 &&
- up->rev == 0x5201)
+ if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
quot ++;
if (up->capabilities & UART_CAP_FIFO && up->port.fifosize > 1) {
@@ -2040,7 +2061,8 @@ static void __init serial8250_isa_init_ports(void)
up->port.ops = &serial8250_pops;
}
- for (i = 0, up = serial8250_ports; i < ARRAY_SIZE(old_serial_port);
+ for (i = 0, up = serial8250_ports;
+ i < ARRAY_SIZE(old_serial_port) && i < UART_NR;
i++, up++) {
up->port.iobase = old_serial_port[i].port;
up->port.irq = irq_canonicalize(old_serial_port[i].irq);
@@ -2289,10 +2311,11 @@ static int __devinit serial8250_probe(struct device *dev)
{
struct plat_serial8250_port *p = dev->platform_data;
struct uart_port port;
+ int ret, i;
memset(&port, 0, sizeof(struct uart_port));
- for (; p && p->flags != 0; p++) {
+ for (i = 0; p && p->flags != 0; p++, i++) {
port.iobase = p->iobase;
port.membase = p->membase;
port.irq = p->irq;
@@ -2301,10 +2324,16 @@ static int __devinit serial8250_probe(struct device *dev)
port.iotype = p->iotype;
port.flags = p->flags;
port.mapbase = p->mapbase;
+ port.hub6 = p->hub6;
port.dev = dev;
if (share_irqs)
port.flags |= UPF_SHARE_IRQ;
- serial8250_register_port(&port);
+ ret = serial8250_register_port(&port);
+ if (ret < 0) {
+ dev_err(dev, "unable to register port at index %d "
+ "(IO%lx MEM%lx IRQ%d): %d\n", i,
+ p->iobase, p->mapbase, p->irq, ret);
+ }
}
return 0;
}
diff --git a/drivers/serial/8250.h b/drivers/serial/8250.h
index 4f3d62f222f4..9225c82faeb8 100644
--- a/drivers/serial/8250.h
+++ b/drivers/serial/8250.h
@@ -51,6 +51,9 @@ struct serial8250_config {
#define UART_CAP_AFE (1 << 11) /* MCR-based hw flow control */
#define UART_CAP_UUE (1 << 12) /* UART needs IER bit 6 set (Xscale) */
+#define UART_BUG_QUOT (1 << 0) /* UART has buggy quot LSB */
+#define UART_BUG_TXEN (1 << 1) /* UART has buggy TX IIR status */
+
#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
#define _INLINE_ inline
#else
diff --git a/drivers/serial/8250_accent.c b/drivers/serial/8250_accent.c
new file mode 100644
index 000000000000..1f2c276063ef
--- /dev/null
+++ b/drivers/serial/8250_accent.c
@@ -0,0 +1,47 @@
+/*
+ * linux/drivers/serial/8250_accent.c
+ *
+ * Copyright (C) 2005 Russell King.
+ * Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ }
+
+static struct plat_serial8250_port accent_data[] = {
+ PORT(0x330, 4),
+ PORT(0x338, 4),
+ { },
+};
+
+static struct platform_device accent_device = {
+ .name = "serial8250",
+ .id = 2,
+ .dev = {
+ .platform_data = accent_data,
+ },
+};
+
+static int __init accent_init(void)
+{
+ return platform_device_register(&accent_device);
+}
+
+module_init(accent_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Accent Async cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_boca.c b/drivers/serial/8250_boca.c
new file mode 100644
index 000000000000..465c9ea1e7a3
--- /dev/null
+++ b/drivers/serial/8250_boca.c
@@ -0,0 +1,61 @@
+/*
+ * linux/drivers/serial/8250_boca.c
+ *
+ * Copyright (C) 2005 Russell King.
+ * Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ }
+
+static struct plat_serial8250_port boca_data[] = {
+ PORT(0x100, 12),
+ PORT(0x108, 12),
+ PORT(0x110, 12),
+ PORT(0x118, 12),
+ PORT(0x120, 12),
+ PORT(0x128, 12),
+ PORT(0x130, 12),
+ PORT(0x138, 12),
+ PORT(0x140, 12),
+ PORT(0x148, 12),
+ PORT(0x150, 12),
+ PORT(0x158, 12),
+ PORT(0x160, 12),
+ PORT(0x168, 12),
+ PORT(0x170, 12),
+ PORT(0x178, 12),
+ { },
+};
+
+static struct platform_device boca_device = {
+ .name = "serial8250",
+ .id = 3,
+ .dev = {
+ .platform_data = boca_data,
+ },
+};
+
+static int __init boca_init(void)
+{
+ return platform_device_register(&boca_device);
+}
+
+module_init(boca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Boca cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_fourport.c b/drivers/serial/8250_fourport.c
new file mode 100644
index 000000000000..e9b4d908ef42
--- /dev/null
+++ b/drivers/serial/8250_fourport.c
@@ -0,0 +1,53 @@
+/*
+ * linux/drivers/serial/8250_fourport.c
+ *
+ * Copyright (C) 2005 Russell King.
+ * Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = UPF_BOOT_AUTOCONF | UPF_FOURPORT, \
+ }
+
+static struct plat_serial8250_port fourport_data[] = {
+ PORT(0x1a0, 9),
+ PORT(0x1a8, 9),
+ PORT(0x1b0, 9),
+ PORT(0x1b8, 9),
+ PORT(0x2a0, 5),
+ PORT(0x2a8, 5),
+ PORT(0x2b0, 5),
+ PORT(0x2b8, 5),
+ { },
+};
+
+static struct platform_device fourport_device = {
+ .name = "serial8250",
+ .id = 1,
+ .dev = {
+ .platform_data = fourport_data,
+ },
+};
+
+static int __init fourport_init(void)
+{
+ return platform_device_register(&fourport_device);
+}
+
+module_init(fourport_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for AST Fourport cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_hub6.c b/drivers/serial/8250_hub6.c
new file mode 100644
index 000000000000..77f396f84b4c
--- /dev/null
+++ b/drivers/serial/8250_hub6.c
@@ -0,0 +1,58 @@
+/*
+ * linux/drivers/serial/8250_hub6.c
+ *
+ * Copyright (C) 2005 Russell King.
+ * Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serial_8250.h>
+
+#define HUB6(card,port) \
+ { \
+ .iobase = 0x302, \
+ .irq = 3, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_HUB6, \
+ .flags = UPF_BOOT_AUTOCONF, \
+ .hub6 = (card) << 6 | (port) << 3 | 1, \
+ }
+
+static struct plat_serial8250_port hub6_data[] = {
+ HUB6(0,0),
+ HUB6(0,1),
+ HUB6(0,2),
+ HUB6(0,3),
+ HUB6(0,4),
+ HUB6(0,5),
+ HUB6(1,0),
+ HUB6(1,1),
+ HUB6(1,2),
+ HUB6(1,3),
+ HUB6(1,4),
+ HUB6(1,5),
+ { },
+};
+
+static struct platform_device hub6_device = {
+ .name = "serial8250",
+ .id = 4,
+ .dev = {
+ .platform_data = hub6_data,
+ },
+};
+
+static int __init hub6_init(void)
+{
+ return platform_device_register(&hub6_device);
+}
+
+module_init(hub6_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for Hub6 cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/8250_mca.c b/drivers/serial/8250_mca.c
new file mode 100644
index 000000000000..f0c40d68b8c1
--- /dev/null
+++ b/drivers/serial/8250_mca.c
@@ -0,0 +1,64 @@
+/*
+ * linux/drivers/serial/8250_mca.c
+ *
+ * Copyright (C) 2005 Russell King.
+ * Data taken from include/asm-i386/serial.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/serial_8250.h>
+
+/*
+ * FIXME: Should we be doing AUTO_IRQ here?
+ */
+#ifdef CONFIG_SERIAL_8250_DETECT_IRQ
+#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_AUTO_IRQ
+#else
+#define MCA_FLAGS UPF_BOOT_AUTOCONF | UPF_SKIP_TEST
+#endif
+
+#define PORT(_base,_irq) \
+ { \
+ .iobase = _base, \
+ .irq = _irq, \
+ .uartclk = 1843200, \
+ .iotype = UPIO_PORT, \
+ .flags = MCA_FLAGS, \
+ }
+
+static struct plat_serial8250_port mca_data[] = {
+ PORT(0x3220, 3),
+ PORT(0x3228, 3),
+ PORT(0x4220, 3),
+ PORT(0x4228, 3),
+ PORT(0x5220, 3),
+ PORT(0x5228, 3),
+ { },
+};
+
+static struct platform_device mca_device = {
+ .name = "serial8250",
+ .id = 5,
+ .dev = {
+ .platform_data = mca_data,
+ },
+};
+
+static int __init mca_init(void)
+{
+ if (!MCA_bus)
+ return -ENODEV;
+ return platform_device_register(&mca_device);
+}
+
+module_init(mca_init);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("8250 serial probe module for MCA ports");
+MODULE_LICENSE("GPL");
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 25fcef2c42de..e0d0a470ddfc 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -86,14 +86,14 @@ config SERIAL_8250_ACPI
namespace, say Y here. If unsure, say N.
config SERIAL_8250_NR_UARTS
- int "Maximum number of non-legacy 8250/16550 serial ports"
+ int "Maximum number of 8250/16550 serial ports"
depends on SERIAL_8250
default "4"
- ---help---
- Set this to the number of non-legacy serial ports you want
- the driver to support. This includes any ports discovered
- via ACPI or PCI enumeration and any ports that may be added
- at run-time via hot-plug.
+ help
+ Set this to the number of serial ports you want the driver
+ to support. This includes any ports discovered via ACPI or
+ PCI enumeration and any ports that may be added at run-time
+ via hot-plug, or any ISA multi-port serial cards.
config SERIAL_8250_EXTENDED
bool "Extended 8250/16550 serial driver options"
@@ -141,31 +141,74 @@ config SERIAL_8250_DETECT_IRQ
If unsure, say N.
-config SERIAL_8250_MULTIPORT
- bool "Support special multiport boards"
- depends on SERIAL_8250_EXTENDED
- help
- Some multiport serial ports have special ports which are used to
- signal when there are any serial ports on the board which need
- servicing. Say Y here to enable the serial driver to take advantage
- of those special I/O ports.
-
config SERIAL_8250_RSA
bool "Support RSA serial ports"
depends on SERIAL_8250_EXTENDED
help
::: To be written :::
-comment "Non-8250 serial port support"
+#
+# Multi-port serial cards
+#
+
+config SERIAL_8250_FOURPORT
+ tristate "Support Fourport cards"
+ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+ help
+ Say Y here if you have an AST FourPort serial board.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_fourport.
+
+config SERIAL_8250_ACCENT
+ tristate "Support Accent cards"
+ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+ help
+ Say Y here if you have an Accent Async serial board.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_accent.
+
+
+config SERIAL_8250_BOCA
+ tristate "Support Boca cards"
+ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+ help
+ Say Y here if you have a Boca serial board. Please read the Boca
+ mini-HOWTO, avaialble from <http://www.tldp.org/docs.html#howto>
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_boca.
+
+
+config SERIAL_8250_HUB6
+ tristate "Support Hub6 cards"
+ depends on SERIAL_8250 != n && ISA && SERIAL_8250_MANY_PORTS
+ help
+ Say Y here if you have a HUB6 serial board.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_hub6.
+
+config SERIAL_8250_MCA
+ tristate "Support 8250-type ports on MCA buses"
+ depends on SERIAL_8250 != n && MCA
+ help
+ Say Y here if you have a MCA serial ports.
+
+ To compile this driver as a module, choose M here: the module
+ will be called 8250_mca.
config SERIAL_8250_ACORN
tristate "Acorn expansion card serial port support"
- depends on ARM && ARCH_ACORN && SERIAL_8250
+ depends on ARCH_ACORN && SERIAL_8250
help
If you have an Atomwide Serial card or Serial Port card for an Acorn
system, say Y to this option. The driver can handle 1, 2, or 3 port
cards. If unsure, say N.
+comment "Non-8250 serial port support"
+
config SERIAL_AMBA_PL010
tristate "ARM AMBA PL010 serial port support"
depends on ARM_AMBA
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 8f1cdde7dbed..65bd4381685e 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -17,6 +17,11 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
+obj-$(CONFIG_SERIAL_8250_FOURPORT) += 8250_fourport.o
+obj-$(CONFIG_SERIAL_8250_ACCENT) += 8250_accent.o
+obj-$(CONFIG_SERIAL_8250_BOCA) += 8250_boca.o
+obj-$(CONFIG_SERIAL_8250_HUB6) += 8250_hub6.o
+obj-$(CONFIG_SERIAL_8250_MCA) += 8250_mca.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
diff --git a/drivers/serial/au1x00_uart.c b/drivers/serial/au1x00_uart.c
index b6d3d5034940..6104aeef1243 100644
--- a/drivers/serial/au1x00_uart.c
+++ b/drivers/serial/au1x00_uart.c
@@ -556,13 +556,10 @@ static unsigned int serial8250_tx_empty(struct uart_port *port)
static unsigned int serial8250_get_mctrl(struct uart_port *port)
{
struct uart_8250_port *up = (struct uart_8250_port *)port;
- unsigned long flags;
unsigned char status;
unsigned int ret;
- spin_lock_irqsave(&up->port.lock, flags);
status = serial_in(up, UART_MSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
if (status & UART_MSR_DCD)
@@ -773,22 +770,22 @@ serial8250_set_termios(struct uart_port *port, struct termios *termios,
switch (termios->c_cflag & CSIZE) {
case CS5:
- cval = 0x00;
+ cval = UART_LCR_WLEN5;
break;
case CS6:
- cval = 0x01;
+ cval = UART_LCR_WLEN6;
break;
case CS7:
- cval = 0x02;
+ cval = UART_LCR_WLEN7;
break;
default:
case CS8:
- cval = 0x03;
+ cval = UART_LCR_WLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
- cval |= 0x04;
+ cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
diff --git a/drivers/serial/cpm_uart/cpm_uart_cpm1.c b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
index de26cf7b003c..7911912f50c7 100644
--- a/drivers/serial/cpm_uart/cpm_uart_cpm1.c
+++ b/drivers/serial/cpm_uart/cpm_uart_cpm1.c
@@ -94,12 +94,42 @@ void smc1_lineif(struct uart_cpm_port *pinfo)
((immap_t *)IMAP_ADDR)->im_ioport.iop_paodr &= ~iobits;
}
+#ifdef CONFIG_MPC885ADS
+ /* Enable SMC1 transceivers */
+ {
+ volatile uint __iomem *bcsr1 = ioremap(BCSR1, 4);
+ uint tmp;
+
+ tmp = in_be32(bcsr1);
+ tmp &= ~BCSR1_RS232EN_1;
+ out_be32(bcsr1, tmp);
+ iounmap(bcsr1);
+ }
+#endif
+
pinfo->brg = 1;
}
void smc2_lineif(struct uart_cpm_port *pinfo)
{
- /* XXX SMC2: insert port configuration here */
+#ifdef CONFIG_MPC885ADS
+ volatile cpm8xx_t *cp = cpmp;
+ volatile uint __iomem *bcsr1;
+ uint tmp;
+
+ cp->cp_pepar |= 0x00000c00;
+ cp->cp_pedir &= ~0x00000c00;
+ cp->cp_peso &= ~0x00000400;
+ cp->cp_peso |= 0x00000800;
+
+ /* Enable SMC2 transceivers */
+ bcsr1 = ioremap(BCSR1, 4);
+ tmp = in_be32(bcsr1);
+ tmp &= ~BCSR1_RS232EN_2;
+ out_be32(bcsr1, tmp);
+ iounmap(bcsr1);
+#endif
+
pinfo->brg = 2;
}
diff --git a/drivers/serial/icom.h b/drivers/serial/icom.h
index 23dc0f7ddf8b..798f1ef23712 100644
--- a/drivers/serial/icom.h
+++ b/drivers/serial/icom.h
@@ -286,5 +286,3 @@ struct lookup_int_table {
u32 __iomem *global_int_mask;
unsigned long processor_id;
};
-
-#define MSECS_TO_JIFFIES(ms) (((ms)*HZ+999)/1000)
diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c
index 3ea46c069f6f..ea5bf4d4daa3 100644
--- a/drivers/serial/ip22zilog.c
+++ b/drivers/serial/ip22zilog.c
@@ -518,27 +518,28 @@ static irqreturn_t ip22zilog_interrupt(int irq, void *dev_id, struct pt_regs *re
static __inline__ unsigned char ip22zilog_read_channel_status(struct uart_port *port)
{
struct zilog_channel *channel;
- unsigned long flags;
unsigned char status;
- spin_lock_irqsave(&port->lock, flags);
-
channel = ZILOG_CHANNEL_FROM_PORT(port);
status = readb(&channel->control);
ZSDELAY();
- spin_unlock_irqrestore(&port->lock, flags);
-
return status;
}
/* The port lock is not held. */
static unsigned int ip22zilog_tx_empty(struct uart_port *port)
{
+ unsigned long flags;
unsigned char status;
unsigned int ret;
+ spin_lock_irqsave(&port->lock, flags);
+
status = ip22zilog_read_channel_status(port);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
if (status & Tx_BUF_EMP)
ret = TIOCSER_TEMT;
else
@@ -547,7 +548,7 @@ static unsigned int ip22zilog_tx_empty(struct uart_port *port)
return ret;
}
-/* The port lock is not held. */
+/* The port lock is held and interrupts are disabled. */
static unsigned int ip22zilog_get_mctrl(struct uart_port *port)
{
unsigned char status;
diff --git a/drivers/serial/m32r_sio.c b/drivers/serial/m32r_sio.c
index 08d61f13edc6..0301feacbde4 100644
--- a/drivers/serial/m32r_sio.c
+++ b/drivers/serial/m32r_sio.c
@@ -724,22 +724,22 @@ static void m32r_sio_set_termios(struct uart_port *port,
switch (termios->c_cflag & CSIZE) {
case CS5:
- cval = 0x00;
+ cval = UART_LCR_WLEN5;
break;
case CS6:
- cval = 0x01;
+ cval = UART_LCR_WLEN6;
break;
case CS7:
- cval = 0x02;
+ cval = UART_LCR_WLEN7;
break;
default:
case CS8:
- cval = 0x03;
+ cval = UART_LCR_WLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
- cval |= 0x04;
+ cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
diff --git a/drivers/serial/mpsc.c b/drivers/serial/mpsc.c
index a8314aee2ab8..e43276c6a954 100644
--- a/drivers/serial/mpsc.c
+++ b/drivers/serial/mpsc.c
@@ -67,7 +67,11 @@
static struct mpsc_port_info mpsc_ports[MPSC_NUM_CTLRS];
static struct mpsc_shared_regs mpsc_shared_regs;
+static struct uart_driver mpsc_reg;
+static void mpsc_start_rx(struct mpsc_port_info *pi);
+static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
+static void mpsc_release_port(struct uart_port *port);
/*
******************************************************************************
*
@@ -546,7 +550,6 @@ static int
mpsc_alloc_ring_mem(struct mpsc_port_info *pi)
{
int rc = 0;
- static void mpsc_free_ring_mem(struct mpsc_port_info *pi);
pr_debug("mpsc_alloc_ring_mem[%d]: Allocating ring mem\n",
pi->port.line);
@@ -745,7 +748,6 @@ mpsc_rx_intr(struct mpsc_port_info *pi, struct pt_regs *regs)
int rc = 0;
u8 *bp;
char flag = TTY_NORMAL;
- static void mpsc_start_rx(struct mpsc_port_info *pi);
pr_debug("mpsc_rx_intr[%d]: Handling Rx intr\n", pi->port.line);
@@ -1056,12 +1058,9 @@ mpsc_get_mctrl(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
u32 mflags, status;
- ulong iflags;
- spin_lock_irqsave(&pi->port.lock, iflags);
status = (pi->mirror_regs) ? pi->MPSC_CHR_10_m :
readl(pi->mpsc_base + MPSC_CHR_10);
- spin_unlock_irqrestore(&pi->port.lock, iflags);
mflags = 0;
if (status & 0x1)
@@ -1178,7 +1177,6 @@ static void
mpsc_shutdown(struct uart_port *port)
{
struct mpsc_port_info *pi = (struct mpsc_port_info *)port;
- static void mpsc_release_port(struct uart_port *port);
pr_debug("mpsc_shutdown[%d]: Shutting down MPSC\n", port->line);
@@ -1448,7 +1446,6 @@ mpsc_console_setup(struct console *co, char *options)
return uart_set_options(&pi->port, co, baud, parity, bits, flow);
}
-extern struct uart_driver mpsc_reg;
static struct console mpsc_console = {
.name = MPSC_DEV_NAME,
.write = mpsc_console_write,
diff --git a/drivers/serial/pmac_zilog.c b/drivers/serial/pmac_zilog.c
index 85abd8a045e0..7db2f37532cf 100644
--- a/drivers/serial/pmac_zilog.c
+++ b/drivers/serial/pmac_zilog.c
@@ -604,7 +604,7 @@ static void pmz_set_mctrl(struct uart_port *port, unsigned int mctrl)
/*
* Get Modem Control bits (only the input ones, the core will
* or that with a cached value of the control ones)
- * The port lock is not held.
+ * The port lock is held and interrupts are disabled.
*/
static unsigned int pmz_get_mctrl(struct uart_port *port)
{
@@ -615,7 +615,7 @@ static unsigned int pmz_get_mctrl(struct uart_port *port)
if (ZS_IS_ASLEEP(uap) || uap->node == NULL)
return 0;
- status = pmz_peek_status(to_pmz(port));
+ status = read_zsreg(uap, R0);
ret = 0;
if (status & DCD)
@@ -1545,7 +1545,7 @@ static void pmz_dispose_port(struct uart_pmac_port *uap)
/*
* Called upon match with an escc node in the devive-tree.
*/
-static int pmz_attach(struct macio_dev *mdev, const struct of_match *match)
+static int pmz_attach(struct macio_dev *mdev, const struct of_device_id *match)
{
int i;
@@ -1850,20 +1850,17 @@ err_out:
return rc;
}
-static struct of_match pmz_match[] =
+static struct of_device_id pmz_match[] =
{
{
.name = "ch-a",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{
.name = "ch-b",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH
},
{},
};
+MODULE_DEVICE_TABLE (of, pmz_match);
static struct macio_driver pmz_driver =
{
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c
index 9dc151d8fa61..461c81c93207 100644
--- a/drivers/serial/pxa.c
+++ b/drivers/serial/pxa.c
@@ -274,14 +274,11 @@ static unsigned int serial_pxa_tx_empty(struct uart_port *port)
static unsigned int serial_pxa_get_mctrl(struct uart_port *port)
{
struct uart_pxa_port *up = (struct uart_pxa_port *)port;
- unsigned long flags;
unsigned char status;
unsigned int ret;
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
- spin_lock_irqsave(&up->port.lock, flags);
status = serial_in(up, UART_MSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
if (status & UART_MSR_DCD)
@@ -455,22 +452,22 @@ serial_pxa_set_termios(struct uart_port *port, struct termios *termios,
switch (termios->c_cflag & CSIZE) {
case CS5:
- cval = 0x00;
+ cval = UART_LCR_WLEN5;
break;
case CS6:
- cval = 0x01;
+ cval = UART_LCR_WLEN6;
break;
case CS7:
- cval = 0x02;
+ cval = UART_LCR_WLEN7;
break;
default:
case CS8:
- cval = 0x03;
+ cval = UART_LCR_WLEN8;
break;
}
if (termios->c_cflag & CSTOPB)
- cval |= 0x04;
+ cval |= UART_LCR_STOP;
if (termios->c_cflag & PARENB)
cval |= UART_LCR_PARITY;
if (!(termios->c_cflag & PARODD))
diff --git a/drivers/serial/s3c2410.c b/drivers/serial/s3c2410.c
index 2a9f7ade2c9d..7365d4b50b95 100644
--- a/drivers/serial/s3c2410.c
+++ b/drivers/serial/s3c2410.c
@@ -198,7 +198,7 @@ static inline struct s3c24xx_uart_port *to_ourport(struct uart_port *port)
/* translate a port to the device name */
-static inline char *s3c24xx_serial_portname(struct uart_port *port)
+static inline const char *s3c24xx_serial_portname(struct uart_port *port)
{
return to_platform_device(port->dev)->name;
}
@@ -522,14 +522,11 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
static int s3c24xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
- unsigned long flags;
int ret;
dbg("s3c24xx_serial_startup: port=%p (%08lx,%p)\n",
port->mapbase, port->membase);
- local_irq_save(flags);
-
rx_enabled(port) = 1;
ret = request_irq(RX_IRQ(port),
@@ -563,12 +560,10 @@ static int s3c24xx_serial_startup(struct uart_port *port)
/* the port reset code should have done the correct
* register setup for the port controls */
- local_irq_restore(flags);
return ret;
err:
s3c24xx_serial_shutdown(port);
- local_irq_restore(flags);
return ret;
}
@@ -903,7 +898,7 @@ static void s3c24xx_serial_release_port(struct uart_port *port)
static int s3c24xx_serial_request_port(struct uart_port *port)
{
- char *name = s3c24xx_serial_portname(port);
+ const char *name = s3c24xx_serial_portname(port);
return request_mem_region(port->mapbase, MAP_SIZE, name) ? 0 : -EBUSY;
}
diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c
index 36b1ae083fb7..54699c3a00ab 100644
--- a/drivers/serial/serial_core.c
+++ b/drivers/serial/serial_core.c
@@ -182,6 +182,13 @@ static int uart_startup(struct uart_state *state, int init_hw)
uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR);
}
+ if (info->flags & UIF_CTS_FLOW) {
+ spin_lock_irq(&port->lock);
+ if (!(port->ops->get_mctrl(port) & TIOCM_CTS))
+ info->tty->hw_stopped = 1;
+ spin_unlock_irq(&port->lock);
+ }
+
info->flags |= UIF_INITIALIZED;
clear_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -828,7 +835,10 @@ static int uart_tiocmget(struct tty_struct *tty, struct file *file)
if ((!file || !tty_hung_up_p(file)) &&
!(tty->flags & (1 << TTY_IO_ERROR))) {
result = port->mctrl;
+
+ spin_lock_irq(&port->lock);
result |= port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
}
up(&state->sem);
@@ -1131,6 +1141,16 @@ static void uart_set_termios(struct tty_struct *tty, struct termios *old_termios
spin_unlock_irqrestore(&state->port->lock, flags);
}
+ /* Handle turning on CRTSCTS */
+ if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
+ spin_lock_irqsave(&state->port->lock, flags);
+ if (!(state->port->ops->get_mctrl(state->port) & TIOCM_CTS)) {
+ tty->hw_stopped = 1;
+ state->port->ops->stop_tx(state->port, 0);
+ }
+ spin_unlock_irqrestore(&state->port->lock, flags);
+ }
+
#if 0
/*
* No need to wake up processes in open wait, since they
@@ -1369,6 +1389,7 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
DECLARE_WAITQUEUE(wait, current);
struct uart_info *info = state->info;
struct uart_port *port = state->port;
+ unsigned int mctrl;
info->blocked_open++;
state->count--;
@@ -1416,7 +1437,10 @@ uart_block_til_ready(struct file *filp, struct uart_state *state)
* and wait for the carrier to indicate that the
* modem is ready for us.
*/
- if (port->ops->get_mctrl(port) & TIOCM_CAR)
+ spin_lock_irq(&port->lock);
+ mctrl = port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
+ if (mctrl & TIOCM_CAR)
break;
up(&state->sem);
@@ -1618,7 +1642,9 @@ static int uart_line_info(char *buf, struct uart_driver *drv, int i)
if(capable(CAP_SYS_ADMIN))
{
+ spin_lock_irq(&port->lock);
status = port->ops->get_mctrl(port);
+ spin_unlock_irq(&port->lock);
ret += sprintf(buf + ret, " tx:%d rx:%d",
port->icount.tx, port->icount.rx);
@@ -1782,6 +1808,12 @@ uart_set_options(struct uart_port *port, struct console *co,
struct termios termios;
int i;
+ /*
+ * Ensure that the serial console lock is initialised
+ * early.
+ */
+ spin_lock_init(&port->lock);
+
memset(&termios, 0, sizeof(struct termios));
termios.c_cflag = CREAD | HUPCL | CLOCAL;
@@ -2170,10 +2202,16 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *port)
state->port = port;
- spin_lock_init(&port->lock);
port->cons = drv->cons;
port->info = state->info;
+ /*
+ * If this port is a console, then the spinlock is already
+ * initialised.
+ */
+ if (!uart_console(port))
+ spin_lock_init(&port->lock);
+
uart_configure_port(drv, state, port);
/*
diff --git a/drivers/serial/serial_cs.c b/drivers/serial/serial_cs.c
index 0d7b65f93e8d..de0136cc5938 100644
--- a/drivers/serial/serial_cs.c
+++ b/drivers/serial/serial_cs.c
@@ -45,7 +45,6 @@
#include <asm/io.h>
#include <asm/system.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -232,11 +231,6 @@ static dev_link_t *serial_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &serial_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -772,13 +766,120 @@ serial_event(event_t event, int priority, event_callback_args_t * args)
return 0;
}
+static struct pcmcia_device_id serial_ids[] = {
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0057, 0x0021),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0089, 0x110a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0104, 0x000a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0xea15),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0109, 0x0501),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0138, 0x110a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0140, 0x000a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0x3341),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0143, 0xc0ab),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x016c, 0x0081),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x021b, 0x0101),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x08a1, 0xc0ab),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0d0a),
+ PCMCIA_PFC_DEVICE_MANF_CARD(1, 0x0105, 0x0e0a),
+ PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x04cd2988, 0x46a52d63),
+ PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM", 0xf510db04, 0x0143b773, 0x46a52d63),
+ PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "EM1144T", "PCMCIA MODEM", 0xf510db04, 0x856d66c8, 0xbd6c43ef),
+ PCMCIA_PFC_DEVICE_PROD_ID123(1, "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM", 0xf510db04, 0x52d21e1e, 0xbd6c43ef),
+ PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM28", 0x2e3ee845, 0x0ea978ea),
+ PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM33", 0x2e3ee845, 0x80609023),
+ PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "CEM56", 0x2e3ee845, 0xa650c32a),
+ PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "REM10", 0x2e3ee845, 0x76df1d29),
+ PCMCIA_PFC_DEVICE_PROD_ID13(1, "Xircom", "XEM5600", 0x2e3ee845, 0xf1403719),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "AnyCom", "Fast Ethernet ", 0x578ba6e7, 0x02d92d1e),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "D-Link", "DME336T", 0x1a424a1c, 0xb23897ff),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Gateway 2000", "XJEM3336", 0xdd9989be, 0x662c394c),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Grey Cell", "GCS3000", 0x2a151fac, 0x48b932ae),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)", 0x0733cc81, 0xb3765033),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "LINKSYS", "PCMLM336", 0xf7cb0b07, 0x7a821b58),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "MEGAHERTZ", "XJEM1144/CCEM1144", 0xf510db04, 0x52d21e1e),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Ositech", "Trumpcard", 0x0c2f80cd, 0x0573c29f),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "ComboCard", 0xdcfe12d3, 0xcd8906cc),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "PCMCIAs", "LanModem", 0xdcfe12d3, 0xc67c648f),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "TDK", "GlobalNetworker 3410/3412", 0x1eae9475, 0xd9a93bed),
+ PCMCIA_PFC_DEVICE_PROD_ID12(1, "Xircom", "CreditCard Ethernet", 0x2e3ee845, 0xc0e778c2),
+ PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0104, 0x0070),
+ PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0101, 0x0562),
+ PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0104, 0x0070),
+ PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x016c, 0x0020),
+ PCMCIA_MFC_DEVICE_PROD_ID123(1, "APEX DATA", "MULTICARD", "ETHERNET-MODEM", 0x11c2da09, 0x7289dc5d, 0xaad95e1f),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away 28.8 PC Card ", 0xb569a6e5, 0x5bd4ff2c),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "Home and Away Credit Card Adapter", 0xb569a6e5, 0x4bdf15c3),
+ PCMCIA_MFC_DEVICE_PROD_ID12(1, "IBM", "w95 Home and Away Credit Card ", 0xb569a6e5, 0xae911c15),
+ PCMCIA_MFC_DEVICE_PROD_ID1(1, "Motorola MARQUIS", 0xf03e4e77),
+ PCMCIA_MFC_DEVICE_PROD_ID2(1, "FAX/Modem/Ethernet Combo Card ", 0x1ed59302),
+ PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0301),
+ PCMCIA_DEVICE_MANF_CARD(0x0101, 0x0039),
+ PCMCIA_DEVICE_MANF_CARD(0x0104, 0x0006),
+ PCMCIA_DEVICE_MANF_CARD(0x0105, 0x410a),
+ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d50),
+ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d51),
+ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d52),
+ PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0d53),
+ PCMCIA_DEVICE_MANF_CARD(0x010b, 0xd180),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x000e),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x001b),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0025),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0045),
+ PCMCIA_DEVICE_MANF_CARD(0x0137, 0x0052),
+ PCMCIA_DEVICE_PROD_ID134("ADV", "TECH", "COMpad-32/85", 0x67459937, 0x916d02ba, 0x8fbe92ae),
+ PCMCIA_DEVICE_PROD_ID124("GATEWAY2000", "CC3144", "PCMCIA MODEM", 0x506bccae, 0xcb3685f1, 0xbd6c43ef),
+ PCMCIA_DEVICE_PROD_ID14("MEGAHERTZ", "PCMCIA MODEM", 0xf510db04, 0xbd6c43ef),
+ PCMCIA_DEVICE_PROD_ID124("TOSHIBA", "T144PF", "PCMCIA MODEM", 0xb4585a1a, 0x7271409c, 0xbd6c43ef),
+ PCMCIA_DEVICE_PROD_ID123("FUJITSU", "FC14F ", "MBH10213", 0x6ee5a3d8, 0x30ead12b, 0xb00f05a0),
+ PCMCIA_DEVICE_PROD_ID13("MEGAHERTZ", "V.34 PCMCIA MODEM", 0xf510db04, 0xbb2cce4a),
+ PCMCIA_DEVICE_PROD_ID12("Brain Boxes", "Bluetooth PC Card", 0xee138382, 0xd4ce9b02),
+ PCMCIA_DEVICE_PROD_ID12("CIRRUS LOGIC", "FAX MODEM", 0xe625f451, 0xcecd6dfa),
+ PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 28800 FAX/DATA MODEM", 0xa3a3062c, 0x8cbd7c76),
+ PCMCIA_DEVICE_PROD_ID12("COMPAQ", "PCMCIA 33600 FAX/DATA MODEM", 0xa3a3062c, 0x5a00ce95),
+ PCMCIA_DEVICE_PROD_ID12("Computerboards, Inc.", "PCM-COM422", 0xd0b78f51, 0x7e2d49ed),
+ PCMCIA_DEVICE_PROD_ID12("Dr. Neuhaus", "FURY CARD 14K4", 0x76942813, 0x8b96ce65),
+ PCMCIA_DEVICE_PROD_ID12("Intelligent", "ANGIA FAX/MODEM", 0xb496e65e, 0xf31602a6),
+ PCMCIA_DEVICE_PROD_ID12("Intel", "MODEM 2400", 0x816cc815, 0x23539b80),
+ PCMCIA_DEVICE_PROD_ID12("IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card", 0x3bd2d898, 0x92abc92f),
+ PCMCIA_DEVICE_PROD_ID12("MACRONIX", "FAX/MODEM", 0x668388b3, 0x3f9bdf2f),
+ PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT1432LT", 0x5f73be51, 0x0b3e2383),
+ PCMCIA_DEVICE_PROD_ID12("Multi-Tech", "MT2834LT", 0x5f73be51, 0x4cd7c09e),
+ PCMCIA_DEVICE_PROD_ID12("OEM ", "C288MX ", 0xb572d360, 0xd2385b7a),
+ PCMCIA_DEVICE_PROD_ID12("PCMCIA ", "C336MX ", 0x99bcafe9, 0xaa25bcab),
+ PCMCIA_DEVICE_PROD_ID12("Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card", 0xc4420b35, 0x92abc92f),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "EN2218-LAN/MODEM", 0x281f1c5d, 0x570f348e, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "PCMCIA", "UE2218-LAN/MODEM", 0x281f1c5d, 0x6fdcacee, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet", 0xf5f025c2, 0x338e8155, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "Psion Dacom", "Gold Card V34 Ethernet GSM", 0xf5f025c2, 0x4ae85d35, "PCMLM28.cis"),
+ PCMCIA_PFC_DEVICE_CIS_PROD_ID12(1, "LINKSYS", "PCMLM28", 0xf7cb0b07, 0x66881874, "PCMLM28.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID12(1, "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION", 0x8fdf8f89, 0xdd5ed9e8, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_PROD_ID4(1, "NSC MF LAN/Modem", 0x58fc6056, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0556, "3CCFEM556.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0175, 0x0000, "DP83903.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x0035, "3CXEM556.cis"),
+ PCMCIA_MFC_DEVICE_CIS_MANF_CARD(1, 0x0101, 0x003d, "3CXEM556.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("MultiTech", "PCMCIA 56K DataFax", 0x842047ee, 0xc2efcf03, "MT5634ZLX.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID12("ADVANTECH", "COMpad-32/85B-4", 0x96913a85, 0xcec8f102, "COMpad4.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID123("ADVANTECH", "COMpad-32/85", "1.0", 0x96913a85, 0x8fbe92ae, 0x0877b627, "COMpad2.cis"),
+ PCMCIA_DEVICE_CIS_PROD_ID2("RS-COM 2P", 0xad20b156, "RS-COM-2P.cis"),
+ /* too generic */
+ /* PCMCIA_MFC_DEVICE_MANF_CARD(0, 0x0160, 0x0002), */
+ /* PCMCIA_MFC_DEVICE_MANF_CARD(1, 0x0160, 0x0002), */
+ PCMCIA_DEVICE_FUNC_ID(2),
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, serial_ids);
+
static struct pcmcia_driver serial_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "serial_cs",
},
.attach = serial_attach,
+ .event = serial_event,
.detach = serial_detach,
+ .id_table = serial_ids,
};
static int __init init_serial_cs(void)
diff --git a/drivers/serial/serial_txx9.c b/drivers/serial/serial_txx9.c
index 3f1051a4a13f..d085030df70b 100644
--- a/drivers/serial/serial_txx9.c
+++ b/drivers/serial/serial_txx9.c
@@ -442,13 +442,10 @@ static unsigned int serial_txx9_tx_empty(struct uart_port *port)
static unsigned int serial_txx9_get_mctrl(struct uart_port *port)
{
struct uart_txx9_port *up = (struct uart_txx9_port *)port;
- unsigned long flags;
unsigned int ret;
- spin_lock_irqsave(&up->port.lock, flags);
ret = ((sio_in(up, TXX9_SIFLCR) & TXX9_SIFLCR_RTSSC) ? 0 : TIOCM_RTS)
| ((sio_in(up, TXX9_SICISR) & TXX9_SICISR_CTSS) ? 0 : TIOCM_CTS);
- spin_unlock_irqrestore(&up->port.lock, flags);
return ret;
}
diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c
index 10e2990a40d4..8d198880756a 100644
--- a/drivers/serial/sunsab.c
+++ b/drivers/serial/sunsab.c
@@ -426,18 +426,15 @@ static void sunsab_set_mctrl(struct uart_port *port, unsigned int mctrl)
sunsab_tx_idle(up);
}
-/* port->lock is not held. */
+/* port->lock is held by caller and interrupts are disabled. */
static unsigned int sunsab_get_mctrl(struct uart_port *port)
{
struct uart_sunsab_port *up = (struct uart_sunsab_port *) port;
- unsigned long flags;
unsigned char val;
unsigned int result;
result = 0;
- spin_lock_irqsave(&up->port.lock, flags);
-
val = readb(&up->regs->r.pvr);
result |= (val & up->pvr_dsr_bit) ? 0 : TIOCM_DSR;
@@ -447,8 +444,6 @@ static unsigned int sunsab_get_mctrl(struct uart_port *port)
val = readb(&up->regs->r.star);
result |= (val & SAB82532_STAR_CTS) ? TIOCM_CTS : 0;
- spin_unlock_irqrestore(&up->port.lock, flags);
-
return result;
}
diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c
index ddc97c905e14..d57a3553aea3 100644
--- a/drivers/serial/sunsu.c
+++ b/drivers/serial/sunsu.c
@@ -572,13 +572,10 @@ static unsigned int sunsu_tx_empty(struct uart_port *port)
static unsigned int sunsu_get_mctrl(struct uart_port *port)
{
struct uart_sunsu_port *up = (struct uart_sunsu_port *) port;
- unsigned long flags;
unsigned char status;
unsigned int ret;
- spin_lock_irqsave(&up->port.lock, flags);
status = serial_in(up, UART_MSR);
- spin_unlock_irqrestore(&up->port.lock, flags);
ret = 0;
if (status & UART_MSR_DCD)
diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c
index 5c4231ae295b..bff42a7b89d0 100644
--- a/drivers/serial/sunzilog.c
+++ b/drivers/serial/sunzilog.c
@@ -610,27 +610,28 @@ static irqreturn_t sunzilog_interrupt(int irq, void *dev_id, struct pt_regs *reg
static __inline__ unsigned char sunzilog_read_channel_status(struct uart_port *port)
{
struct zilog_channel __iomem *channel;
- unsigned long flags;
unsigned char status;
- spin_lock_irqsave(&port->lock, flags);
-
channel = ZILOG_CHANNEL_FROM_PORT(port);
status = sbus_readb(&channel->control);
ZSDELAY();
- spin_unlock_irqrestore(&port->lock, flags);
-
return status;
}
/* The port lock is not held. */
static unsigned int sunzilog_tx_empty(struct uart_port *port)
{
+ unsigned long flags;
unsigned char status;
unsigned int ret;
+ spin_lock_irqsave(&port->lock, flags);
+
status = sunzilog_read_channel_status(port);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
if (status & Tx_BUF_EMP)
ret = TIOCSER_TEMT;
else
@@ -639,7 +640,7 @@ static unsigned int sunzilog_tx_empty(struct uart_port *port)
return ret;
}
-/* The port lock is not held. */
+/* The port lock is held and interrupts are disabled. */
static unsigned int sunzilog_get_mctrl(struct uart_port *port)
{
unsigned char status;
@@ -1071,7 +1072,7 @@ static void __init sunzilog_alloc_tables(void)
*/
static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
{
- unsigned long mapped_addr;
+ void __iomem *mapped_addr;
unsigned int sun4u_ino;
struct sbus_bus *sbus = NULL;
struct sbus_dev *sdev = NULL;
@@ -1111,9 +1112,9 @@ static struct zilog_layout __iomem * __init get_zs_sun4u(int chip, int zsnode)
apply_fhc_ranges(central_bus->child,
&zsregs[0], 1);
apply_central_ranges(central_bus, &zsregs[0], 1);
- mapped_addr =
- (((u64)zsregs[0].which_io)<<32UL) |
- ((u64)zsregs[0].phys_addr);
+ mapped_addr = (void __iomem *)
+ ((((u64)zsregs[0].which_io)<<32UL) |
+ ((u64)zsregs[0].phys_addr));
}
if (zilog_irq == -1) {
diff --git a/drivers/telephony/ixj.c b/drivers/telephony/ixj.c
index d5863b8b56ee..f2c9fa423d40 100644
--- a/drivers/telephony/ixj.c
+++ b/drivers/telephony/ixj.c
@@ -329,10 +329,8 @@ static IXJ *ixj_alloc()
static void ixj_fsk_free(IXJ *j)
{
- if(j->fskdata != NULL) {
- kfree(j->fskdata);
- j->fskdata = NULL;
- }
+ kfree(j->fskdata);
+ j->fskdata = NULL;
}
static void ixj_fsk_alloc(IXJ *j)
@@ -3867,13 +3865,11 @@ static int set_rec_codec(IXJ *j, int rate)
j->rec_mode = 7;
break;
default:
+ kfree(j->read_buffer);
j->rec_frame_size = 0;
j->rec_mode = -1;
- if (j->read_buffer) {
- kfree(j->read_buffer);
- j->read_buffer = NULL;
- j->read_buffer_size = 0;
- }
+ j->read_buffer = NULL;
+ j->read_buffer_size = 0;
retval = 1;
break;
}
@@ -3991,14 +3987,12 @@ static int ixj_record_start(IXJ *j)
static void ixj_record_stop(IXJ *j)
{
- if(ixjdebug & 0x0002)
+ if (ixjdebug & 0x0002)
printk("IXJ %d Stopping Record Codec %d at %ld\n", j->board, j->rec_codec, jiffies);
- if (j->read_buffer) {
- kfree(j->read_buffer);
- j->read_buffer = NULL;
- j->read_buffer_size = 0;
- }
+ kfree(j->read_buffer);
+ j->read_buffer = NULL;
+ j->read_buffer_size = 0;
if (j->rec_mode > -1) {
ixj_WriteDSPCommand(0x5120, j);
j->rec_mode = -1;
@@ -4449,13 +4443,11 @@ static int set_play_codec(IXJ *j, int rate)
j->play_mode = 5;
break;
default:
+ kfree(j->write_buffer);
j->play_frame_size = 0;
j->play_mode = -1;
- if (j->write_buffer) {
- kfree(j->write_buffer);
- j->write_buffer = NULL;
- j->write_buffer_size = 0;
- }
+ j->write_buffer = NULL;
+ j->write_buffer_size = 0;
retval = 1;
break;
}
@@ -4578,14 +4570,12 @@ static int ixj_play_start(IXJ *j)
static void ixj_play_stop(IXJ *j)
{
- if(ixjdebug & 0x0002)
+ if (ixjdebug & 0x0002)
printk("IXJ %d Stopping Play Codec %d at %ld\n", j->board, j->play_codec, jiffies);
- if (j->write_buffer) {
- kfree(j->write_buffer);
- j->write_buffer = NULL;
- j->write_buffer_size = 0;
- }
+ kfree(j->write_buffer);
+ j->write_buffer = NULL;
+ j->write_buffer_size = 0;
if (j->play_mode > -1) {
ixj_WriteDSPCommand(0x5221, j); /* Stop playback and flush buffers. 8022 reference page 9-40 */
@@ -5810,9 +5800,7 @@ static void ixj_cpt_stop(IXJ *j)
ixj_play_tone(j, 0);
j->tone_state = j->tone_cadence_state = 0;
if (j->cadence_t) {
- if (j->cadence_t->ce) {
- kfree(j->cadence_t->ce);
- }
+ kfree(j->cadence_t->ce);
kfree(j->cadence_t);
j->cadence_t = NULL;
}
@@ -7497,10 +7485,8 @@ static void cleanup(void)
printk(KERN_INFO "IXJ: Releasing XILINX address for /dev/phone%d\n", cnt);
release_region(j->XILINXbase, 4);
}
- if (j->read_buffer)
- kfree(j->read_buffer);
- if (j->write_buffer)
- kfree(j->write_buffer);
+ kfree(j->read_buffer);
+ kfree(j->write_buffer);
if (j->dev)
pnp_device_detach(j->dev);
if (ixjdebug & 0x0002)
diff --git a/drivers/telephony/ixj_pcmcia.c b/drivers/telephony/ixj_pcmcia.c
index e1ef0d7ee8d1..57c0c6e3fbed 100644
--- a/drivers/telephony/ixj_pcmcia.c
+++ b/drivers/telephony/ixj_pcmcia.c
@@ -9,7 +9,6 @@
#include <linux/errno.h> /* error codes */
#include <linux/slab.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -69,11 +68,6 @@ static dev_link_t *ixj_attach(void)
link->next = dev_list;
dev_list = link;
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &ixj_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -295,13 +289,21 @@ static int ixj_event(event_t event, int priority, event_callback_args_t * args)
return 0;
}
+static struct pcmcia_device_id ixj_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x0257, 0x0600),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, ixj_ids);
+
static struct pcmcia_driver ixj_driver = {
.owner = THIS_MODULE,
.drv = {
.name = "ixj_cs",
},
.attach = ixj_attach,
+ .event = ixj_event,
.detach = ixj_detach,
+ .id_table = ixj_ids,
};
static int __init ixj_pcmcia_init(void)
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index a61d4433a989..df014c2a7c54 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_MON) += mon/
obj-$(CONFIG_USB_EHCI_HCD) += host/
+obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
@@ -31,6 +32,7 @@ obj-$(CONFIG_USB_MOUSE) += input/
obj-$(CONFIG_USB_MTOUCH) += input/
obj-$(CONFIG_USB_POWERMATE) += input/
obj-$(CONFIG_USB_WACOM) += input/
+obj-$(CONFIG_USB_ACECAD) += input/
obj-$(CONFIG_USB_XPAD) += input/
obj-$(CONFIG_USB_DABUSB) += media/
@@ -63,12 +65,14 @@ obj-$(CONFIG_USB_EMI26) += misc/
obj-$(CONFIG_USB_EMI62) += misc/
obj-$(CONFIG_USB_IDMOUSE) += misc/
obj-$(CONFIG_USB_LCD) += misc/
+obj-$(CONFIG_USB_LD) += misc/
obj-$(CONFIG_USB_LED) += misc/
obj-$(CONFIG_USB_LEGOTOWER) += misc/
obj-$(CONFIG_USB_RIO500) += misc/
obj-$(CONFIG_USB_TEST) += misc/
obj-$(CONFIG_USB_USS720) += misc/
obj-$(CONFIG_USB_PHIDGETSERVO) += misc/
+obj-$(CONFIG_USB_SISUSBVGA) += misc/
obj-$(CONFIG_USB_ATM) += atm/
obj-$(CONFIG_USB_SPEEDTOUCH) += atm/
diff --git a/drivers/usb/atm/Kconfig b/drivers/usb/atm/Kconfig
index 0d9f5379b8cf..f429862e0974 100644
--- a/drivers/usb/atm/Kconfig
+++ b/drivers/usb/atm/Kconfig
@@ -1,30 +1,60 @@
#
-# USB ATM driver configuration
+# USB/ATM DSL configuration
#
-comment "USB ATM/DSL drivers"
+
+menu "USB DSL modem support"
depends on USB
config USB_ATM
- tristate "Generic USB ATM/DSL core I/O support"
+ tristate "USB DSL modem support"
depends on USB && ATM
select CRC32
default n
help
- This provides a library which is used for packet I/O by USB DSL
- modems, such as the SpeedTouch driver below.
+ Say Y here if you want to connect a USB Digital Subscriber Line (DSL)
+ modem to your computer's USB port. You will then need to choose your
+ modem from the list below.
To compile this driver as a module, choose M here: the
- module will be called usb_atm.
+ module will be called usbatm.
config USB_SPEEDTOUCH
- tristate "Alcatel Speedtouch USB support"
- depends on USB && ATM
- select USB_ATM
+ tristate "Speedtouch USB support"
+ depends on USB_ATM
+ select FW_LOADER
help
- Say Y here if you have an Alcatel SpeedTouch USB or SpeedTouch 330
+ Say Y here if you have an SpeedTouch USB or SpeedTouch 330
modem. In order to use your modem you will need to install the
two parts of the firmware, extracted by the user space tools; see
<http://www.linux-usb.org/SpeedTouch/> for details.
To compile this driver as a module, choose M here: the
module will be called speedtch.
+
+config USB_CXACRU
+ tristate "Conexant AccessRunner USB support"
+ depends on USB_ATM
+ select FW_LOADER
+ help
+ Say Y here if you have an ADSL USB modem based on the Conexant
+ AccessRunner chipset. In order to use your modem you will need to
+ install the firmware, extracted by the user space tools; see
+ <http://accessrunner.sourceforge.net/> for details.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cxacru.
+
+config USB_XUSBATM
+ tristate "Other USB DSL modem support"
+ depends on USB_ATM
+ help
+ Say Y here if you have a DSL USB modem not explicitly supported by
+ another USB DSL drivers. In order to use your modem you will need to
+ pass the vendor ID, product ID, and endpoint numbers for transmission
+ and reception as module parameters. You may need to initialize the
+ the modem using a user space utility (a firmware loader for example).
+
+ To compile this driver as a module, choose M here: the
+ module will be called xusbatm.
+
+endmenu
diff --git a/drivers/usb/atm/Makefile b/drivers/usb/atm/Makefile
index 9213b8b97587..751f297be2ef 100644
--- a/drivers/usb/atm/Makefile
+++ b/drivers/usb/atm/Makefile
@@ -1,7 +1,8 @@
#
-# Makefile for the rest of the USB drivers
-# (the ones that don't fit into any other categories)
+# Makefile for USB ATM/xDSL drivers
#
-obj-$(CONFIG_USB_ATM) += usb_atm.o
+obj-$(CONFIG_USB_CXACRU) += cxacru.o
obj-$(CONFIG_USB_SPEEDTOUCH) += speedtch.o
+obj-$(CONFIG_USB_ATM) += usbatm.o
+obj-$(CONFIG_USB_XUSBATM) += xusbatm.o
diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c
new file mode 100644
index 000000000000..8e184e2641cb
--- /dev/null
+++ b/drivers/usb/atm/cxacru.c
@@ -0,0 +1,878 @@
+/******************************************************************************
+ * cxacru.c - driver for USB ADSL modems based on
+ * Conexant AccessRunner chipset
+ *
+ * Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
+ * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*
+ * Credit is due for Josep Comas, who created the original patch to speedtch.c
+ * to support the different padding used by the AccessRunner (now generalized
+ * into usbatm), and the userspace firmware loading utility.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/device.h> /* FIXME: linux/firmware.h should include it itself */
+#include <linux/firmware.h>
+
+#include "usbatm.h"
+
+#define DRIVER_AUTHOR "Roman Kagan, David Woodhouse, Duncan Sands"
+#define DRIVER_VERSION "0.2"
+#define DRIVER_DESC "Conexant AccessRunner ADSL USB modem driver"
+
+static const char cxacru_driver_name[] = "cxacru";
+
+#define CXACRU_EP_CMD 0x01 /* Bulk/interrupt in/out */
+#define CXACRU_EP_DATA 0x02 /* Bulk in/out */
+
+#define CMD_PACKET_SIZE 64 /* Should be maxpacket(ep)? */
+
+/* Addresses */
+#define PLLFCLK_ADDR 0x00350068
+#define PLLBCLK_ADDR 0x0035006c
+#define SDRAMEN_ADDR 0x00350010
+#define FW_ADDR 0x00801000
+#define BR_ADDR 0x00180600
+#define SIG_ADDR 0x00180500
+#define BR_STACK_ADDR 0x00187f10
+
+/* Values */
+#define SDRAM_ENA 0x1
+
+#define CMD_TIMEOUT 2000 /* msecs */
+#define POLL_INTERVAL 5000 /* msecs */
+
+/* commands for interaction with the modem through the control channel before
+ * firmware is loaded */
+enum cxacru_fw_request {
+ FW_CMD_ERR,
+ FW_GET_VER,
+ FW_READ_MEM,
+ FW_WRITE_MEM,
+ FW_RMW_MEM,
+ FW_CHECKSUM_MEM,
+ FW_GOTO_MEM,
+};
+
+/* commands for interaction with the modem through the control channel once
+ * firmware is loaded */
+enum cxacru_cm_request {
+ CM_REQUEST_UNDEFINED = 0x80,
+ CM_REQUEST_TEST,
+ CM_REQUEST_CHIP_GET_MAC_ADDRESS,
+ CM_REQUEST_CHIP_GET_DP_VERSIONS,
+ CM_REQUEST_CHIP_ADSL_LINE_START,
+ CM_REQUEST_CHIP_ADSL_LINE_STOP,
+ CM_REQUEST_CHIP_ADSL_LINE_GET_STATUS,
+ CM_REQUEST_CHIP_ADSL_LINE_GET_SPEED,
+ CM_REQUEST_CARD_INFO_GET,
+ CM_REQUEST_CARD_DATA_GET,
+ CM_REQUEST_CARD_DATA_SET,
+ CM_REQUEST_COMMAND_HW_IO,
+ CM_REQUEST_INTERFACE_HW_IO,
+ CM_REQUEST_CARD_SERIAL_DATA_PATH_GET,
+ CM_REQUEST_CARD_SERIAL_DATA_PATH_SET,
+ CM_REQUEST_CARD_CONTROLLER_VERSION_GET,
+ CM_REQUEST_CARD_GET_STATUS,
+ CM_REQUEST_CARD_GET_MAC_ADDRESS,
+ CM_REQUEST_CARD_GET_DATA_LINK_STATUS,
+ CM_REQUEST_MAX,
+};
+
+/* reply codes to the commands above */
+enum cxacru_cm_status {
+ CM_STATUS_UNDEFINED,
+ CM_STATUS_SUCCESS,
+ CM_STATUS_ERROR,
+ CM_STATUS_UNSUPPORTED,
+ CM_STATUS_UNIMPLEMENTED,
+ CM_STATUS_PARAMETER_ERROR,
+ CM_STATUS_DBG_LOOPBACK,
+ CM_STATUS_MAX,
+};
+
+/* indices into CARD_INFO_GET return array */
+enum cxacru_info_idx {
+ CXINF_DOWNSTREAM_RATE,
+ CXINF_UPSTREAM_RATE,
+ CXINF_LINK_STATUS,
+ CXINF_LINE_STATUS,
+ CXINF_MAC_ADDRESS_HIGH,
+ CXINF_MAC_ADDRESS_LOW,
+ CXINF_UPSTREAM_SNR_MARGIN,
+ CXINF_DOWNSTREAM_SNR_MARGIN,
+ CXINF_UPSTREAM_ATTENUATION,
+ CXINF_DOWNSTREAM_ATTENUATION,
+ CXINF_TRANSMITTER_POWER,
+ CXINF_UPSTREAM_BITS_PER_FRAME,
+ CXINF_DOWNSTREAM_BITS_PER_FRAME,
+ CXINF_STARTUP_ATTEMPTS,
+ CXINF_UPSTREAM_CRC_ERRORS,
+ CXINF_DOWNSTREAM_CRC_ERRORS,
+ CXINF_UPSTREAM_FEC_ERRORS,
+ CXINF_DOWNSTREAM_FEC_ERRORS,
+ CXINF_UPSTREAM_HEC_ERRORS,
+ CXINF_DOWNSTREAM_HEC_ERRORS,
+ CXINF_LINE_STARTABLE,
+ CXINF_MODULATION,
+ CXINF_ADSL_HEADEND,
+ CXINF_ADSL_HEADEND_ENVIRONMENT,
+ CXINF_CONTROLLER_VERSION,
+ /* dunno what the missing two mean */
+ CXINF_MAX = 0x1c,
+};
+
+struct cxacru_modem_type {
+ u32 pll_f_clk;
+ u32 pll_b_clk;
+ int boot_rom_patch;
+};
+
+struct cxacru_data {
+ struct usbatm_data *usbatm;
+
+ const struct cxacru_modem_type *modem_type;
+
+ int line_status;
+ struct work_struct poll_work;
+
+ /* contol handles */
+ struct semaphore cm_serialize;
+ u8 *rcv_buf;
+ u8 *snd_buf;
+ struct urb *rcv_urb;
+ struct urb *snd_urb;
+ struct completion rcv_done;
+ struct completion snd_done;
+};
+
+/* the following three functions are stolen from drivers/usb/core/message.c */
+static void cxacru_blocking_completion(struct urb *urb, struct pt_regs *regs)
+{
+ complete((struct completion *)urb->context);
+}
+
+static void cxacru_timeout_kill(unsigned long data)
+{
+ usb_unlink_urb((struct urb *) data);
+}
+
+static int cxacru_start_wait_urb(struct urb *urb, struct completion *done,
+ int* actual_length)
+{
+ struct timer_list timer;
+ int status;
+
+ init_timer(&timer);
+ timer.expires = jiffies + msecs_to_jiffies(CMD_TIMEOUT);
+ timer.data = (unsigned long) urb;
+ timer.function = cxacru_timeout_kill;
+ add_timer(&timer);
+ wait_for_completion(done);
+ status = urb->status;
+ if (status == -ECONNRESET)
+ status = -ETIMEDOUT;
+ del_timer_sync(&timer);
+
+ if (actual_length)
+ *actual_length = urb->actual_length;
+ return status;
+}
+
+static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
+ u8 *wdata, int wsize, u8 *rdata, int rsize)
+{
+ int ret, actlen;
+ int offb, offd;
+ const int stride = CMD_PACKET_SIZE - 4;
+ u8 *wbuf = instance->snd_buf;
+ u8 *rbuf = instance->rcv_buf;
+ int wbuflen = ((wsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+ int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
+
+ if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
+ dbg("too big transfer requested");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ down(&instance->cm_serialize);
+
+ /* submit reading urb before the writing one */
+ init_completion(&instance->rcv_done);
+ ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
+ if (ret < 0) {
+ dbg("submitting read urb for cm %#x failed", cm);
+ ret = ret;
+ goto fail;
+ }
+
+ memset(wbuf, 0, wbuflen);
+ /* handle wsize == 0 */
+ wbuf[0] = cm;
+ for (offb = offd = 0; offd < wsize; offd += stride, offb += CMD_PACKET_SIZE) {
+ wbuf[offb] = cm;
+ memcpy(wbuf + offb + 4, wdata + offd, min_t(int, stride, wsize - offd));
+ }
+
+ instance->snd_urb->transfer_buffer_length = wbuflen;
+ init_completion(&instance->snd_done);
+ ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
+ if (ret < 0) {
+ dbg("submitting write urb for cm %#x failed", cm);
+ ret = ret;
+ goto fail;
+ }
+
+ ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
+ if (ret < 0) {
+ dbg("sending cm %#x failed", cm);
+ ret = ret;
+ goto fail;
+ }
+
+ ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
+ if (ret < 0) {
+ dbg("receiving cm %#x failed", cm);
+ ret = ret;
+ goto fail;
+ }
+ if (actlen % CMD_PACKET_SIZE || !actlen) {
+ dbg("response is not a positive multiple of %d: %#x",
+ CMD_PACKET_SIZE, actlen);
+ ret = -EIO;
+ goto fail;
+ }
+
+ /* check the return status and copy the data to the output buffer, if needed */
+ for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
+ if (rbuf[offb] != cm) {
+ dbg("wrong cm %#x in response", rbuf[offb]);
+ ret = -EIO;
+ goto fail;
+ }
+ if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
+ dbg("response failed: %#x", rbuf[offb + 1]);
+ ret = -EIO;
+ goto fail;
+ }
+ if (offd >= rsize)
+ break;
+ memcpy(rdata + offd, rbuf + offb + 4, min_t(int, stride, rsize - offd));
+ offd += stride;
+ }
+
+ ret = offd;
+ dbg("cm %#x", cm);
+fail:
+ up(&instance->cm_serialize);
+ return ret;
+}
+
+static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_request cm,
+ u32 *data, int size)
+{
+ int ret, len;
+ u32 *buf;
+ int offb, offd;
+ const int stride = CMD_PACKET_SIZE / (4 * 2) - 1;
+ int buflen = ((size - 1) / stride + 1 + size * 2) * 4;
+
+ buf = kmalloc(buflen, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = cxacru_cm(instance, cm, NULL, 0, (u8 *) buf, buflen);
+ if (ret < 0)
+ goto cleanup;
+
+ /* len > 0 && len % 4 == 0 guaranteed by cxacru_cm() */
+ len = ret / 4;
+ for (offb = 0; offb < len; ) {
+ int l = le32_to_cpu(buf[offb++]);
+ if (l > stride || l > (len - offb) / 2) {
+ dbg("wrong data length %#x in response", l);
+ ret = -EIO;
+ goto cleanup;
+ }
+ while (l--) {
+ offd = le32_to_cpu(buf[offb++]);
+ if (offd >= size) {
+ dbg("wrong index %#x in response", offd);
+ ret = -EIO;
+ goto cleanup;
+ }
+ data[offd] = le32_to_cpu(buf[offb++]);
+ }
+ }
+
+ ret = 0;
+
+cleanup:
+ kfree(buf);
+ return ret;
+}
+
+static int cxacru_card_status(struct cxacru_data *instance)
+{
+ int ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+ if (ret < 0) { /* firmware not loaded */
+ dbg("cxacru_adsl_start: CARD_GET_STATUS returned %d", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance);
+
+static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
+ struct atm_dev *atm_dev)
+{
+ struct cxacru_data *instance = usbatm_instance->driver_data;
+ struct device *dev = &usbatm_instance->usb_intf->dev;
+ /*
+ struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+ */
+ int ret;
+
+ dbg("cxacru_atm_start");
+
+ /* Read MAC address */
+ ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_MAC_ADDRESS, NULL, 0,
+ atm_dev->esi, sizeof(atm_dev->esi));
+ if (ret < 0) {
+ dev_err(dev, "cxacru_atm_start: CARD_GET_MAC_ADDRESS returned %d\n", ret);
+ return ret;
+ }
+
+ /* start ADSL */
+ ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(dev, "cxacru_atm_start: CHIP_ADSL_LINE_START returned %d\n", ret);
+ return ret;
+ }
+
+ /* Start status polling */
+ cxacru_poll_status(instance);
+ return 0;
+}
+
+static void cxacru_poll_status(struct cxacru_data *instance)
+{
+ u32 buf[CXINF_MAX] = {};
+ struct device *dev = &instance->usbatm->usb_intf->dev;
+ struct atm_dev *atm_dev = instance->usbatm->atm_dev;
+ int ret;
+
+ ret = cxacru_cm_get_array(instance, CM_REQUEST_CARD_INFO_GET, buf, CXINF_MAX);
+ if (ret < 0) {
+ dev_warn(dev, "poll status: error %d\n", ret);
+ goto reschedule;
+ }
+
+ if (instance->line_status == buf[CXINF_LINE_STATUS])
+ goto reschedule;
+
+ instance->line_status = buf[CXINF_LINE_STATUS];
+ switch (instance->line_status) {
+ case 0:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: down\n");
+ break;
+
+ case 1:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: attemtping to activate\n");
+ break;
+
+ case 2:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: training\n");
+ break;
+
+ case 3:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: channel analysis\n");
+ break;
+
+ case 4:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: exchange\n");
+ break;
+
+ case 5:
+ atm_dev->link_rate = buf[CXINF_DOWNSTREAM_RATE] * 1000 / 424;
+ atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+ dev_info(dev, "ADSL line: up (%d kb/s down | %d kb/s up)\n",
+ buf[CXINF_DOWNSTREAM_RATE], buf[CXINF_UPSTREAM_RATE]);
+ break;
+
+ case 6:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: waiting\n");
+ break;
+
+ case 7:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ dev_info(dev, "ADSL line: initializing\n");
+ break;
+
+ default:
+ atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ dev_info(dev, "Unknown line state %02x\n", instance->line_status);
+ break;
+ }
+reschedule:
+ schedule_delayed_work(&instance->poll_work, msecs_to_jiffies(POLL_INTERVAL));
+}
+
+static int cxacru_fw(struct usb_device *usb_dev, enum cxacru_fw_request fw,
+ u8 code1, u8 code2, u32 addr, u8 *data, int size)
+{
+ int ret;
+ u8 *buf;
+ int offd, offb;
+ const int stride = CMD_PACKET_SIZE - 8;
+
+ buf = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ offb = offd = 0;
+ do {
+ int l = min_t(int, stride, size - offd);
+ buf[offb++] = fw;
+ buf[offb++] = l;
+ buf[offb++] = code1;
+ buf[offb++] = code2;
+ *((u32 *) (buf + offb)) = cpu_to_le32(addr);
+ offb += 4;
+ addr += l;
+ if(l)
+ memcpy(buf + offb, data + offd, l);
+ if (l < stride)
+ memset(buf + offb + l, 0, stride - l);
+ offb += stride;
+ offd += stride;
+ if ((offb >= PAGE_SIZE) || (offd >= size)) {
+ ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD),
+ buf, offb, NULL, CMD_TIMEOUT);
+ if (ret < 0) {
+ dbg("sending fw %#x failed", fw);
+ goto cleanup;
+ }
+ offb = 0;
+ }
+ } while(offd < size);
+ dbg("sent fw %#x", fw);
+
+ ret = 0;
+
+cleanup:
+ free_page((unsigned long) buf);
+ return ret;
+}
+
+static void cxacru_upload_firmware(struct cxacru_data *instance,
+ const struct firmware *fw,
+ const struct firmware *bp,
+ const struct firmware *cf)
+{
+ int ret;
+ int off;
+ struct usb_device *usb_dev = instance->usbatm->usb_dev;
+ struct device *dev = &instance->usbatm->usb_intf->dev;
+ u16 signature[] = { usb_dev->descriptor.idVendor, usb_dev->descriptor.idProduct };
+ u32 val;
+
+ dbg("cxacru_upload_firmware");
+
+ /* FirmwarePllFClkValue */
+ val = cpu_to_le32(instance->modem_type->pll_f_clk);
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLFCLK_ADDR, (u8 *) &val, 4);
+ if (ret) {
+ dev_err(dev, "FirmwarePllFClkValue failed: %d\n", ret);
+ return;
+ }
+
+ /* FirmwarePllBClkValue */
+ val = cpu_to_le32(instance->modem_type->pll_b_clk);
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, PLLBCLK_ADDR, (u8 *) &val, 4);
+ if (ret) {
+ dev_err(dev, "FirmwarePllBClkValue failed: %d\n", ret);
+ return;
+ }
+
+ /* Enable SDRAM */
+ val = cpu_to_le32(SDRAM_ENA);
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SDRAMEN_ADDR, (u8 *) &val, 4);
+ if (ret) {
+ dev_err(dev, "Enable SDRAM failed: %d\n", ret);
+ return;
+ }
+
+ /* Firmware */
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
+ if (ret) {
+ dev_err(dev, "Firmware upload failed: %d\n", ret);
+ return;
+ }
+
+ /* Boot ROM patch */
+ if (instance->modem_type->boot_rom_patch) {
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
+ if (ret) {
+ dev_err(dev, "Boot ROM patching failed: %d\n", ret);
+ return;
+ }
+ }
+
+ /* Signature */
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, SIG_ADDR, (u8 *) signature, 4);
+ if (ret) {
+ dev_err(dev, "Signature storing failed: %d\n", ret);
+ return;
+ }
+
+ if (instance->modem_type->boot_rom_patch) {
+ val = cpu_to_le32(BR_ADDR);
+ ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
+ }
+ else {
+ ret = cxacru_fw(usb_dev, FW_GOTO_MEM, 0x0, 0x0, FW_ADDR, NULL, 0);
+ }
+ if (ret) {
+ dev_err(dev, "Passing control to firmware failed: %d\n", ret);
+ return;
+ }
+
+ /* Delay to allow firmware to start up. */
+ msleep_interruptible(1000);
+
+ usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_CMD));
+ usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_CMD));
+ usb_clear_halt(usb_dev, usb_sndbulkpipe(usb_dev, CXACRU_EP_DATA));
+ usb_clear_halt(usb_dev, usb_rcvbulkpipe(usb_dev, CXACRU_EP_DATA));
+
+ ret = cxacru_cm(instance, CM_REQUEST_CARD_GET_STATUS, NULL, 0, NULL, 0);
+ if (ret < 0) {
+ dev_err(dev, "modem failed to initialize: %d\n", ret);
+ return;
+ }
+
+ /* Load config data (le32), doing one packet at a time */
+ if (cf)
+ for (off = 0; off < cf->size / 4; ) {
+ u32 buf[CMD_PACKET_SIZE / 4 - 1];
+ int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
+ buf[0] = cpu_to_le32(len);
+ for (i = 0; i < len; i++, off++) {
+ buf[i * 2 + 1] = cpu_to_le32(off);
+ memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
+ }
+ ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
+ (u8 *) buf, len, NULL, 0);
+ if (ret < 0) {
+ dev_err(dev, "load config data failed: %d\n", ret);
+ return;
+ }
+ }
+
+ msleep_interruptible(4000);
+}
+
+static int cxacru_find_firmware(struct cxacru_data *instance,
+ char* phase, const struct firmware **fw_p)
+{
+ struct device *dev = &instance->usbatm->usb_intf->dev;
+ char buf[16];
+
+ sprintf(buf, "cxacru-%s.bin", phase);
+ dbg("cxacru_find_firmware: looking for %s", buf);
+
+ if (request_firmware(fw_p, buf, dev)) {
+ dev_dbg(dev, "no stage %s firmware found\n", phase);
+ return -ENOENT;
+ }
+
+ dev_info(dev, "found firmware %s\n", buf);
+
+ return 0;
+}
+
+static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
+ struct usb_interface *usb_intf)
+{
+ struct device *dev = &usbatm_instance->usb_intf->dev;
+ const struct firmware *fw, *bp, *cf;
+ struct cxacru_data *instance = usbatm_instance->driver_data;
+
+ int ret = cxacru_find_firmware(instance, "fw", &fw);
+ if (ret) {
+ dev_warn(dev, "firmware (cxacru-fw.bin) unavailable (hotplug misconfiguration?)\n");
+ return ret;
+ }
+
+ if (instance->modem_type->boot_rom_patch) {
+ ret = cxacru_find_firmware(instance, "bp", &bp);
+ if (ret) {
+ dev_warn(dev, "boot ROM patch (cxacru-bp.bin) unavailable (hotplug misconfiguration?)\n");
+ release_firmware(fw);
+ return ret;
+ }
+ }
+
+ if (cxacru_find_firmware(instance, "cf", &cf)) /* optional */
+ cf = NULL;
+
+ cxacru_upload_firmware(instance, fw, bp, cf);
+
+ if (cf)
+ release_firmware(cf);
+ if (instance->modem_type->boot_rom_patch)
+ release_firmware(bp);
+ release_firmware(fw);
+
+ ret = cxacru_card_status(instance);
+ if (ret)
+ dbg("modem initialisation failed");
+ else
+ dbg("done setting up the modem");
+
+ return ret;
+}
+
+static int cxacru_bind(struct usbatm_data *usbatm_instance,
+ struct usb_interface *intf, const struct usb_device_id *id,
+ int *need_heavy_init)
+{
+ struct cxacru_data *instance;
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ int ret;
+
+ /* instance init */
+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+ if (!instance) {
+ dbg("cxacru_bind: no memory for instance data");
+ return -ENOMEM;
+ }
+
+ memset(instance, 0, sizeof(*instance));
+
+ instance->usbatm = usbatm_instance;
+ instance->modem_type = (struct cxacru_modem_type *) id->driver_info;
+
+ instance->rcv_buf = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!instance->rcv_buf) {
+ dbg("cxacru_bind: no memory for rcv_buf");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ instance->snd_buf = (u8 *) __get_free_page(GFP_KERNEL);
+ if (!instance->snd_buf) {
+ dbg("cxacru_bind: no memory for snd_buf");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ instance->rcv_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!instance->rcv_urb) {
+ dbg("cxacru_bind: no memory for rcv_urb");
+ ret = -ENOMEM;
+ goto fail;
+ }
+ instance->snd_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!instance->snd_urb) {
+ dbg("cxacru_bind: no memory for snd_urb");
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ usb_fill_int_urb(instance->rcv_urb,
+ usb_dev, usb_rcvintpipe(usb_dev, CXACRU_EP_CMD),
+ instance->rcv_buf, PAGE_SIZE,
+ cxacru_blocking_completion, &instance->rcv_done, 1);
+ instance->rcv_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+ usb_fill_int_urb(instance->snd_urb,
+ usb_dev, usb_sndintpipe(usb_dev, CXACRU_EP_CMD),
+ instance->snd_buf, PAGE_SIZE,
+ cxacru_blocking_completion, &instance->snd_done, 4);
+ instance->snd_urb->transfer_flags |= URB_ASYNC_UNLINK;
+
+ init_MUTEX(&instance->cm_serialize);
+
+ INIT_WORK(&instance->poll_work, (void *)cxacru_poll_status, instance);
+
+ usbatm_instance->driver_data = instance;
+
+ *need_heavy_init = cxacru_card_status(instance);
+
+ return 0;
+
+ fail:
+ free_page((unsigned long) instance->snd_buf);
+ free_page((unsigned long) instance->rcv_buf);
+ usb_free_urb(instance->snd_urb);
+ usb_free_urb(instance->rcv_urb);
+ kfree(instance);
+
+ return ret;
+}
+
+static void cxacru_unbind(struct usbatm_data *usbatm_instance,
+ struct usb_interface *intf)
+{
+ struct cxacru_data *instance = usbatm_instance->driver_data;
+
+ dbg("cxacru_unbind entered");
+
+ if (!instance) {
+ dbg("cxacru_unbind: NULL instance!");
+ return;
+ }
+
+ while (!cancel_delayed_work(&instance->poll_work))
+ flush_scheduled_work();
+
+ usb_kill_urb(instance->snd_urb);
+ usb_kill_urb(instance->rcv_urb);
+ usb_free_urb(instance->snd_urb);
+ usb_free_urb(instance->rcv_urb);
+
+ free_page((unsigned long) instance->snd_buf);
+ free_page((unsigned long) instance->rcv_buf);
+ kfree(instance);
+
+ usbatm_instance->driver_data = NULL;
+}
+
+static const struct cxacru_modem_type cxacru_cafe = {
+ .pll_f_clk = 0x02d874df,
+ .pll_b_clk = 0x0196a51a,
+ .boot_rom_patch = 1,
+};
+
+static const struct cxacru_modem_type cxacru_cb00 = {
+ .pll_f_clk = 0x5,
+ .pll_b_clk = 0x3,
+ .boot_rom_patch = 0,
+};
+
+static const struct usb_device_id cxacru_usb_ids[] = {
+ { /* V = Conexant P = ADSL modem (Euphrates project) */
+ USB_DEVICE(0x0572, 0xcafe), .driver_info = (unsigned long) &cxacru_cafe
+ },
+ { /* V = Conexant P = ADSL modem (Hasbani project) */
+ USB_DEVICE(0x0572, 0xcb00), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Conexant P = ADSL modem */
+ USB_DEVICE(0x0572, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Conexant P = ADSL modem */
+ USB_DEVICE(0x0572, 0xcb06), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Olitec P = ADSL modem version 2 */
+ USB_DEVICE(0x08e3, 0x0100), .driver_info = (unsigned long) &cxacru_cafe
+ },
+ { /* V = Olitec P = ADSL modem version 3 */
+ USB_DEVICE(0x08e3, 0x0102), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Trust/Amigo Technology Co. P = AMX-CA86U */
+ USB_DEVICE(0x0eb0, 0x3457), .driver_info = (unsigned long) &cxacru_cafe
+ },
+ { /* V = Zoom P = 5510 */
+ USB_DEVICE(0x1803, 0x5510), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Draytek P = Vigor 318 */
+ USB_DEVICE(0x0675, 0x0200), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Zyxel P = 630-C1 aka OMNI ADSL USB (Annex A) */
+ USB_DEVICE(0x0586, 0x330a), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Zyxel P = 630-C3 aka OMNI ADSL USB (Annex B) */
+ USB_DEVICE(0x0586, 0x330b), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Aethra P = Starmodem UM1020 */
+ USB_DEVICE(0x0659, 0x0020), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Aztech Systems P = ? AKA Pirelli AUA-010 */
+ USB_DEVICE(0x0509, 0x0812), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Netopia P = Cayman 3341(Annex A)/3351(Annex B) */
+ USB_DEVICE(0x100d, 0xcb01), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ { /* V = Netopia P = Cayman 3342(Annex A)/3352(Annex B) */
+ USB_DEVICE(0x100d, 0x3342), .driver_info = (unsigned long) &cxacru_cb00
+ },
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, cxacru_usb_ids);
+
+static struct usbatm_driver cxacru_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = cxacru_driver_name,
+ .bind = cxacru_bind,
+ .heavy_init = cxacru_heavy_init,
+ .unbind = cxacru_unbind,
+ .atm_start = cxacru_atm_start,
+ .in = CXACRU_EP_DATA,
+ .out = CXACRU_EP_DATA,
+ .rx_padding = 3,
+ .tx_padding = 11,
+};
+
+static int cxacru_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ return usbatm_usb_probe(intf, id, &cxacru_driver);
+}
+
+static struct usb_driver cxacru_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = cxacru_driver_name,
+ .probe = cxacru_usb_probe,
+ .disconnect = usbatm_usb_disconnect,
+ .id_table = cxacru_usb_ids
+};
+
+static int __init cxacru_init(void)
+{
+ return usb_register(&cxacru_usb_driver);
+}
+
+static void __exit cxacru_cleanup(void)
+{
+ usb_deregister(&cxacru_usb_driver);
+}
+
+module_init(cxacru_init);
+module_exit(cxacru_cleanup);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 2a1697bfd695..d0cbbb7f0385 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -5,6 +5,8 @@
* Copyright (C) 2003, Duncan Sands
* Copyright (C) 2004, David Woodhouse
*
+ * Based on "modem_run.c", copyright (C) 2001, Benoit Papillault
+ *
* 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)
@@ -21,467 +23,191 @@
*
******************************************************************************/
-#include <linux/module.h>
-#include <linux/moduleparam.h>
+#include <asm/page.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/firmware.h>
#include <linux/gfp.h>
+#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/processor.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "usb_atm.h"
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/workqueue.h>
-#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE)
-# define USE_FW_LOADER
-#endif
+#include "usbatm.h"
#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.8"
+#define DRIVER_VERSION "1.9"
#define DRIVER_DESC "Alcatel SpeedTouch USB driver version " DRIVER_VERSION
static const char speedtch_driver_name[] = "speedtch";
-#define SPEEDTOUCH_VENDORID 0x06b9
-#define SPEEDTOUCH_PRODUCTID 0x4061
+#define CTRL_TIMEOUT 2000 /* milliseconds */
+#define DATA_TIMEOUT 2000 /* milliseconds */
-/* Timeout in jiffies */
-#define CTRL_TIMEOUT 2000
-#define DATA_TIMEOUT 2000
+#define OFFSET_7 0 /* size 1 */
+#define OFFSET_b 1 /* size 8 */
+#define OFFSET_d 9 /* size 4 */
+#define OFFSET_e 13 /* size 1 */
+#define OFFSET_f 14 /* size 1 */
+#define TOTAL 15
-#define OFFSET_7 0 /* size 1 */
-#define OFFSET_b 1 /* size 8 */
-#define OFFSET_d 9 /* size 4 */
-#define OFFSET_e 13 /* size 1 */
-#define OFFSET_f 14 /* size 1 */
-#define TOTAL 15
+#define SIZE_7 1
+#define SIZE_b 8
+#define SIZE_d 4
+#define SIZE_e 1
+#define SIZE_f 1
-#define SIZE_7 1
-#define SIZE_b 8
-#define SIZE_d 4
-#define SIZE_e 1
-#define SIZE_f 1
+#define MIN_POLL_DELAY 5000 /* milliseconds */
+#define MAX_POLL_DELAY 60000 /* milliseconds */
-static int dl_512_first = 0;
-static int sw_buffering = 0;
+#define RESUBMIT_DELAY 1000 /* milliseconds */
-module_param(dl_512_first, bool, 0444);
-MODULE_PARM_DESC(dl_512_first, "Read 512 bytes before sending firmware");
+#define DEFAULT_ALTSETTING 1
+#define DEFAULT_DL_512_FIRST 0
+#define DEFAULT_SW_BUFFERING 0
-module_param(sw_buffering, uint, 0444);
-MODULE_PARM_DESC(sw_buffering, "Enable software buffering");
+static int altsetting = DEFAULT_ALTSETTING;
+static int dl_512_first = DEFAULT_DL_512_FIRST;
+static int sw_buffering = DEFAULT_SW_BUFFERING;
-#define UDSL_IOCTL_LINE_UP 1
-#define UDSL_IOCTL_LINE_DOWN 2
+module_param(altsetting, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(altsetting,
+ "Alternative setting for data interface (default: "
+ __MODULE_STRING(DEFAULT_ALTSETTING) ")");
-#define SPEEDTCH_ENDPOINT_INT 0x81
-#define SPEEDTCH_ENDPOINT_DATA 0x07
-#define SPEEDTCH_ENDPOINT_FIRMWARE 0x05
+module_param(dl_512_first, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(dl_512_first,
+ "Read 512 bytes before sending firmware (default: "
+ __MODULE_STRING(DEFAULT_DL_512_FIRST) ")");
-#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
+module_param(sw_buffering, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(sw_buffering,
+ "Enable software buffering (default: "
+ __MODULE_STRING(DEFAULT_SW_BUFFERING) ")");
-static struct usb_device_id speedtch_usb_ids[] = {
- {USB_DEVICE(SPEEDTOUCH_VENDORID, SPEEDTOUCH_PRODUCTID)},
- {}
-};
+#define ENDPOINT_INT 0x81
+#define ENDPOINT_DATA 0x07
+#define ENDPOINT_FIRMWARE 0x05
-MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
+#define hex2int(c) ( (c >= '0') && (c <= '9') ? (c - '0') : ((c & 0xf) + 9) )
struct speedtch_instance_data {
- struct udsl_instance_data u;
+ struct usbatm_data *usbatm;
+
+ struct work_struct status_checker;
+
+ unsigned char last_status;
+
+ int poll_delay; /* milliseconds */
- /* Status */
+ struct timer_list resubmit_timer;
struct urb *int_urb;
unsigned char int_data[16];
- struct work_struct poll_work;
- struct timer_list poll_timer;
-};
-/* USB */
-
-static int speedtch_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id);
-static void speedtch_usb_disconnect(struct usb_interface *intf);
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
- void *user_data);
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs);
-static void speedtch_poll_status(struct speedtch_instance_data *instance);
-static struct usb_driver speedtch_usb_driver = {
- .owner = THIS_MODULE,
- .name = speedtch_driver_name,
- .probe = speedtch_usb_probe,
- .disconnect = speedtch_usb_disconnect,
- .ioctl = speedtch_usb_ioctl,
- .id_table = speedtch_usb_ids,
+ unsigned char scratch_buffer[TOTAL];
};
/***************
** firmware **
***************/
-static void speedtch_got_firmware(struct speedtch_instance_data *instance,
- int got_it)
-{
- int err;
- struct usb_interface *intf;
-
- down(&instance->u.serialize); /* vs self, speedtch_firmware_start */
- if (instance->u.status == UDSL_LOADED_FIRMWARE)
- goto out;
- if (!got_it) {
- instance->u.status = UDSL_NO_FIRMWARE;
- goto out;
- }
- if ((err = usb_set_interface(instance->u.usb_dev, 1, 1)) < 0) {
- dbg("speedtch_got_firmware: usb_set_interface returned %d!", err);
- instance->u.status = UDSL_NO_FIRMWARE;
- goto out;
- }
-
- /* Set up interrupt endpoint */
- intf = usb_ifnum_to_if(instance->u.usb_dev, 0);
- if (intf && !usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) {
-
- instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (instance->int_urb) {
-
- usb_fill_int_urb(instance->int_urb, instance->u.usb_dev,
- usb_rcvintpipe(instance->u.usb_dev, SPEEDTCH_ENDPOINT_INT),
- instance->int_data,
- sizeof(instance->int_data),
- speedtch_handle_int, instance, 50);
- err = usb_submit_urb(instance->int_urb, GFP_KERNEL);
- if (err) {
- /* Doesn't matter; we'll poll anyway */
- dbg("speedtch_got_firmware: Submission of interrupt URB failed %d", err);
- usb_free_urb(instance->int_urb);
- instance->int_urb = NULL;
- usb_driver_release_interface(&speedtch_usb_driver, intf);
- }
- }
- }
- /* Start status polling */
- mod_timer(&instance->poll_timer, jiffies + (1 * HZ));
-
- instance->u.status = UDSL_LOADED_FIRMWARE;
- tasklet_schedule(&instance->u.receive_tasklet);
- out:
- up(&instance->u.serialize);
- wake_up_interruptible(&instance->u.firmware_waiters);
-}
-
-static int speedtch_set_swbuff(struct speedtch_instance_data *instance,
- int state)
+static void speedtch_set_swbuff(struct speedtch_instance_data *instance, int state)
{
- struct usb_device *dev = instance->u.usb_dev;
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct usb_device *usb_dev = usbatm->usb_dev;
int ret;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x32, 0x40, state ? 0x01 : 0x00,
- 0x00, NULL, 0, 100);
- if (ret < 0) {
- printk("Warning: %sabling SW buffering: usb_control_msg returned %d\n",
- state ? "En" : "Dis", ret);
- return ret;
- }
-
- dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
- return 0;
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x32, 0x40, state ? 0x01 : 0x00, 0x00, NULL, 0, CTRL_TIMEOUT);
+ if (ret < 0)
+ usb_warn(usbatm,
+ "%sabling SW buffering: usb_control_msg returned %d\n",
+ state ? "En" : "Dis", ret);
+ else
+ dbg("speedtch_set_swbuff: %sbled SW buffering", state ? "En" : "Dis");
}
static void speedtch_test_sequence(struct speedtch_instance_data *instance)
{
- struct usb_device *dev = instance->u.usb_dev;
- unsigned char buf[10];
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct usb_device *usb_dev = usbatm->usb_dev;
+ unsigned char *buf = instance->scratch_buffer;
int ret;
/* URB 147 */
buf[0] = 0x1c;
buf[1] = 0x50;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x01, 0x40, 0x0b, 0x00, buf, 2, 100);
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x0b, 0x00, buf, 2, CTRL_TIMEOUT);
if (ret < 0)
- printk(KERN_WARNING "%s failed on URB147: %d\n", __func__, ret);
+ usb_warn(usbatm, "%s failed on URB147: %d\n", __func__, ret);
/* URB 148 */
buf[0] = 0x32;
buf[1] = 0x00;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x01, 0x40, 0x02, 0x00, buf, 2, 100);
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x02, 0x00, buf, 2, CTRL_TIMEOUT);
if (ret < 0)
- printk(KERN_WARNING "%s failed on URB148: %d\n", __func__, ret);
+ usb_warn(usbatm, "%s failed on URB148: %d\n", __func__, ret);
/* URB 149 */
buf[0] = 0x01;
buf[1] = 0x00;
buf[2] = 0x01;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x01, 0x40, 0x03, 0x00, buf, 3, 100);
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x03, 0x00, buf, 3, CTRL_TIMEOUT);
if (ret < 0)
- printk(KERN_WARNING "%s failed on URB149: %d\n", __func__, ret);
+ usb_warn(usbatm, "%s failed on URB149: %d\n", __func__, ret);
/* URB 150 */
buf[0] = 0x01;
buf[1] = 0x00;
buf[2] = 0x01;
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x01, 0x40, 0x04, 0x00, buf, 3, 100);
+ ret = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ 0x01, 0x40, 0x04, 0x00, buf, 3, CTRL_TIMEOUT);
if (ret < 0)
- printk(KERN_WARNING "%s failed on URB150: %d\n", __func__, ret);
-}
-
-static int speedtch_start_synchro(struct speedtch_instance_data *instance)
-{
- struct usb_device *dev = instance->u.usb_dev;
- unsigned char buf[2];
- int ret;
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x04, 0x00,
- buf, sizeof(buf), CTRL_TIMEOUT);
- if (ret < 0) {
- printk(KERN_WARNING "SpeedTouch: Failed to start ADSL synchronisation: %d\n", ret);
- return ret;
- }
-
- dbg("speedtch_start_synchro: modem prodded. %d Bytes returned: %02x %02x", ret, buf[0], buf[1]);
- return 0;
-}
-
-static void speedtch_handle_int(struct urb *urb, struct pt_regs *regs)
-{
- struct speedtch_instance_data *instance = urb->context;
- unsigned int count = urb->actual_length;
- int ret;
-
- /* The magic interrupt for "up state" */
- const static unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
- /* The magic interrupt for "down state" */
- const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated; clean up */
- dbg("%s - urb shutting down with status: %d", __func__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __func__, urb->status);
- goto exit;
- }
-
- if (count < 6) {
- dbg("%s - int packet too short", __func__);
- goto exit;
- }
-
- if (!memcmp(up_int, instance->int_data, 6)) {
- del_timer(&instance->poll_timer);
- printk(KERN_NOTICE "DSL line goes up\n");
- } else if (!memcmp(down_int, instance->int_data, 6)) {
- printk(KERN_NOTICE "DSL line goes down\n");
- } else {
- int i;
-
- printk(KERN_DEBUG "Unknown interrupt packet of %d bytes:", count);
- for (i = 0; i < count; i++)
- printk(" %02x", instance->int_data[i]);
- printk("\n");
- }
- schedule_work(&instance->poll_work);
-
- exit:
- rmb();
- if (!instance->int_urb)
- return;
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- err("%s - usb_submit_urb failed with result %d", __func__, ret);
-}
-
-static int speedtch_get_status(struct speedtch_instance_data *instance,
- unsigned char *buf)
-{
- struct usb_device *dev = instance->u.usb_dev;
- int ret;
-
- memset(buf, 0, TOTAL);
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
- CTRL_TIMEOUT);
- if (ret < 0) {
- dbg("MSG 7 failed");
- return ret;
- }
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
- CTRL_TIMEOUT);
- if (ret < 0) {
- dbg("MSG B failed");
- return ret;
- }
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
- CTRL_TIMEOUT);
- if (ret < 0) {
- dbg("MSG D failed");
- return ret;
- }
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
- CTRL_TIMEOUT);
- if (ret < 0) {
- dbg("MSG E failed");
- return ret;
- }
-
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
- CTRL_TIMEOUT);
- if (ret < 0) {
- dbg("MSG F failed");
- return ret;
- }
-
- return 0;
+ usb_warn(usbatm, "%s failed on URB150: %d\n", __func__, ret);
}
-static void speedtch_poll_status(struct speedtch_instance_data *instance)
-{
- unsigned char buf[TOTAL];
- int ret;
-
- ret = speedtch_get_status(instance, buf);
- if (ret) {
- printk(KERN_WARNING
- "SpeedTouch: Error %d fetching device status\n", ret);
- return;
- }
-
- dbg("Line state %02x", buf[OFFSET_7]);
-
- switch (buf[OFFSET_7]) {
- case 0:
- if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
- instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
- printk(KERN_NOTICE "ADSL line is down\n");
- /* It'll never resync again unless we ask it to... */
- speedtch_start_synchro(instance);
- }
- break;
-
- case 0x08:
- if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
- instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
- printk(KERN_NOTICE "ADSL line is blocked?\n");
- }
- break;
-
- case 0x10:
- if (instance->u.atm_dev->signal != ATM_PHY_SIG_LOST) {
- instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
- printk(KERN_NOTICE "ADSL line is synchronising\n");
- }
- break;
-
- case 0x20:
- if (instance->u.atm_dev->signal != ATM_PHY_SIG_FOUND) {
- int down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
- | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
- int up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
- | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);
-
- if (!(down_speed & 0x0000ffff) &&
- !(up_speed & 0x0000ffff)) {
- down_speed >>= 16;
- up_speed >>= 16;
- }
- instance->u.atm_dev->link_rate = down_speed * 1000 / 424;
- instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
-
- printk(KERN_NOTICE
- "ADSL line is up (%d Kib/s down | %d Kib/s up)\n",
- down_speed, up_speed);
- }
- break;
-
- default:
- if (instance->u.atm_dev->signal != ATM_PHY_SIG_UNKNOWN) {
- instance->u.atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
- printk(KERN_NOTICE "Unknown line state %02x\n", buf[OFFSET_7]);
- }
- break;
- }
-}
-
-static void speedtch_timer_poll(unsigned long data)
-{
- struct speedtch_instance_data *instance = (void *)data;
-
- schedule_work(&instance->poll_work);
- mod_timer(&instance->poll_timer, jiffies + (5 * HZ));
-}
-
-#ifdef USE_FW_LOADER
-static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
+static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
const struct firmware *fw1,
const struct firmware *fw2)
{
unsigned char *buffer;
- struct usb_device *usb_dev = instance->u.usb_dev;
+ struct usbatm_data *usbatm = instance->usbatm;
struct usb_interface *intf;
- int actual_length, ret;
+ struct usb_device *usb_dev = usbatm->usb_dev;
+ int actual_length;
+ int ret = 0;
int offset;
- dbg("speedtch_upload_firmware");
-
- if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
- dbg("speedtch_upload_firmware: interface not found!");
- goto fail;
- }
+ usb_dbg(usbatm, "%s entered\n", __func__);
if (!(buffer = (unsigned char *)__get_free_page(GFP_KERNEL))) {
- dbg("speedtch_upload_firmware: no memory for buffer!");
- goto fail;
+ ret = -ENOMEM;
+ usb_dbg(usbatm, "%s: no memory for buffer!\n", __func__);
+ goto out;
}
- /* A user-space firmware loader may already have claimed interface #2 */
- if ((ret =
- usb_driver_claim_interface(&speedtch_usb_driver, intf, NULL)) < 0) {
- dbg("speedtch_upload_firmware: interface in use (%d)!", ret);
- goto fail_free;
+ if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+ ret = -ENODEV;
+ usb_dbg(usbatm, "%s: interface not found!\n", __func__);
+ goto out_free;
}
/* URB 7 */
if (dl_512_first) { /* some modems need a read before writing the firmware */
- ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+ ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
buffer, 0x200, &actual_length, 2000);
if (ret < 0 && ret != -ETIMEDOUT)
- dbg("speedtch_upload_firmware: read BLOCK0 from modem failed (%d)!", ret);
+ usb_dbg(usbatm, "%s: read BLOCK0 from modem failed (%d)!\n", __func__, ret);
else
- dbg("speedtch_upload_firmware: BLOCK0 downloaded (%d bytes)", ret);
+ usb_dbg(usbatm, "%s: BLOCK0 downloaded (%d bytes)\n", __func__, ret);
}
/* URB 8 : both leds are static green */
@@ -489,60 +215,60 @@ static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
int thislen = min_t(int, PAGE_SIZE, fw1->size - offset);
memcpy(buffer, fw1->data + offset, thislen);
- ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+ ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
buffer, thislen, &actual_length, DATA_TIMEOUT);
if (ret < 0) {
- dbg("speedtch_upload_firmware: write BLOCK1 to modem failed (%d)!", ret);
- goto fail_release;
+ usb_dbg(usbatm, "%s: write BLOCK1 to modem failed (%d)!\n", __func__, ret);
+ goto out_free;
}
- dbg("speedtch_upload_firmware: BLOCK1 uploaded (%zu bytes)", fw1->size);
+ usb_dbg(usbatm, "%s: BLOCK1 uploaded (%zu bytes)\n", __func__, fw1->size);
}
/* USB led blinking green, ADSL led off */
/* URB 11 */
- ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+ ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
buffer, 0x200, &actual_length, DATA_TIMEOUT);
if (ret < 0) {
- dbg("speedtch_upload_firmware: read BLOCK2 from modem failed (%d)!", ret);
- goto fail_release;
+ usb_dbg(usbatm, "%s: read BLOCK2 from modem failed (%d)!\n", __func__, ret);
+ goto out_free;
}
- dbg("speedtch_upload_firmware: BLOCK2 downloaded (%d bytes)", actual_length);
+ usb_dbg(usbatm, "%s: BLOCK2 downloaded (%d bytes)\n", __func__, actual_length);
/* URBs 12 to 139 - USB led blinking green, ADSL led off */
for (offset = 0; offset < fw2->size; offset += PAGE_SIZE) {
int thislen = min_t(int, PAGE_SIZE, fw2->size - offset);
memcpy(buffer, fw2->data + offset, thislen);
- ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+ ret = usb_bulk_msg(usb_dev, usb_sndbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
buffer, thislen, &actual_length, DATA_TIMEOUT);
if (ret < 0) {
- dbg("speedtch_upload_firmware: write BLOCK3 to modem failed (%d)!", ret);
- goto fail_release;
+ usb_dbg(usbatm, "%s: write BLOCK3 to modem failed (%d)!\n", __func__, ret);
+ goto out_free;
}
}
- dbg("speedtch_upload_firmware: BLOCK3 uploaded (%zu bytes)", fw2->size);
+ usb_dbg(usbatm, "%s: BLOCK3 uploaded (%zu bytes)\n", __func__, fw2->size);
/* USB led static green, ADSL led static red */
/* URB 142 */
- ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, SPEEDTCH_ENDPOINT_FIRMWARE),
+ ret = usb_bulk_msg(usb_dev, usb_rcvbulkpipe(usb_dev, ENDPOINT_FIRMWARE),
buffer, 0x200, &actual_length, DATA_TIMEOUT);
if (ret < 0) {
- dbg("speedtch_upload_firmware: read BLOCK4 from modem failed (%d)!", ret);
- goto fail_release;
+ usb_dbg(usbatm, "%s: read BLOCK4 from modem failed (%d)!\n", __func__, ret);
+ goto out_free;
}
/* success */
- dbg("speedtch_upload_firmware: BLOCK4 downloaded (%d bytes)", actual_length);
+ usb_dbg(usbatm, "%s: BLOCK4 downloaded (%d bytes)\n", __func__, actual_length);
/* Delay to allow firmware to start up. We can do this here
because we're in our own kernel thread anyway. */
- msleep(1000);
+ msleep_interruptible(1000);
/* Enable software buffering, if requested */
if (sw_buffering)
@@ -551,291 +277,543 @@ static void speedtch_upload_firmware(struct speedtch_instance_data *instance,
/* Magic spell; don't ask us what this does */
speedtch_test_sequence(instance);
- /* Start modem synchronisation */
- if (speedtch_start_synchro(instance))
- dbg("speedtch_start_synchro: failed");
-
- speedtch_got_firmware(instance, 1);
-
- free_page((unsigned long)buffer);
- return;
+ ret = 0;
- fail_release:
- /* Only release interface #2 if uploading failed; we don't release it
- we succeeded. This prevents the userspace tools from trying to load
- the firmware themselves */
- usb_driver_release_interface(&speedtch_usb_driver, intf);
- fail_free:
+out_free:
free_page((unsigned long)buffer);
- fail:
- speedtch_got_firmware(instance, 0);
+out:
+ return ret;
}
-static int speedtch_find_firmware(struct speedtch_instance_data
- *instance, int phase,
+static int speedtch_find_firmware(struct usb_interface *intf, int phase,
const struct firmware **fw_p)
{
- char buf[24];
- const u16 bcdDevice = le16_to_cpu(instance->u.usb_dev->descriptor.bcdDevice);
+ struct device *dev = &intf->dev;
+ const u16 bcdDevice = le16_to_cpu(interface_to_usbdev(intf)->descriptor.bcdDevice);
const u8 major_revision = bcdDevice >> 8;
const u8 minor_revision = bcdDevice & 0xff;
+ char buf[24];
sprintf(buf, "speedtch-%d.bin.%x.%02x", phase, major_revision, minor_revision);
- dbg("speedtch_find_firmware: looking for %s", buf);
+ dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
- if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
+ if (request_firmware(fw_p, buf, dev)) {
sprintf(buf, "speedtch-%d.bin.%x", phase, major_revision);
- dbg("speedtch_find_firmware: looking for %s", buf);
+ dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
- if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
+ if (request_firmware(fw_p, buf, dev)) {
sprintf(buf, "speedtch-%d.bin", phase);
- dbg("speedtch_find_firmware: looking for %s", buf);
+ dev_dbg(dev, "%s: looking for %s\n", __func__, buf);
- if (request_firmware(fw_p, buf, &instance->u.usb_dev->dev)) {
- dev_warn(&instance->u.usb_dev->dev, "no stage %d firmware found!", phase);
+ if (request_firmware(fw_p, buf, dev)) {
+ dev_warn(dev, "no stage %d firmware found!\n", phase);
return -ENOENT;
}
}
}
- dev_info(&instance->u.usb_dev->dev, "found stage %d firmware %s\n", phase, buf);
+ dev_info(dev, "found stage %d firmware %s\n", phase, buf);
return 0;
}
-static int speedtch_load_firmware(void *arg)
+static int speedtch_heavy_init(struct usbatm_data *usbatm, struct usb_interface *intf)
{
const struct firmware *fw1, *fw2;
- struct speedtch_instance_data *instance = arg;
-
- BUG_ON(!instance);
+ struct speedtch_instance_data *instance = usbatm->driver_data;
+ int ret;
- daemonize("firmware/speedtch");
+ if ((ret = speedtch_find_firmware(intf, 1, &fw1)) < 0)
+ return ret;
- if (!speedtch_find_firmware(instance, 1, &fw1)) {
- if (!speedtch_find_firmware(instance, 2, &fw2)) {
- speedtch_upload_firmware(instance, fw1, fw2);
- release_firmware(fw2);
- }
+ if ((ret = speedtch_find_firmware(intf, 2, &fw2)) < 0) {
release_firmware(fw1);
+ return ret;
}
- /* In case we failed, set state back to NO_FIRMWARE so that
- another later attempt may work. Otherwise, we never actually
- manage to recover if, for example, the firmware is on /usr and
- we look for it too early. */
- speedtch_got_firmware(instance, 0);
+ ret = speedtch_upload_firmware(instance, fw1, fw2);
- module_put(THIS_MODULE);
- udsl_put_instance(&instance->u);
- return 0;
+ release_firmware(fw2);
+ release_firmware(fw1);
+
+ return ret;
}
-#endif /* USE_FW_LOADER */
-static void speedtch_firmware_start(struct speedtch_instance_data *instance)
+
+/**********
+** ATM **
+**********/
+
+static int speedtch_read_status(struct speedtch_instance_data *instance)
{
-#ifdef USE_FW_LOADER
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct usb_device *usb_dev = usbatm->usb_dev;
+ unsigned char *buf = instance->scratch_buffer;
int ret;
-#endif
- dbg("speedtch_firmware_start");
+ memset(buf, 0, TOTAL);
- down(&instance->u.serialize); /* vs self, speedtch_got_firmware */
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x07, 0x00, buf + OFFSET_7, SIZE_7,
+ CTRL_TIMEOUT);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: MSG 7 failed\n", __func__);
+ return ret;
+ }
- if (instance->u.status >= UDSL_LOADING_FIRMWARE) {
- up(&instance->u.serialize);
- return;
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x0b, 0x00, buf + OFFSET_b, SIZE_b,
+ CTRL_TIMEOUT);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: MSG B failed\n", __func__);
+ return ret;
}
- instance->u.status = UDSL_LOADING_FIRMWARE;
- up(&instance->u.serialize);
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x0d, 0x00, buf + OFFSET_d, SIZE_d,
+ CTRL_TIMEOUT);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: MSG D failed\n", __func__);
+ return ret;
+ }
-#ifdef USE_FW_LOADER
- udsl_get_instance(&instance->u);
- try_module_get(THIS_MODULE);
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x01, 0xc0, 0x0e, 0x00, buf + OFFSET_e, SIZE_e,
+ CTRL_TIMEOUT);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: MSG E failed\n", __func__);
+ return ret;
+ }
- ret = kernel_thread(speedtch_load_firmware, instance,
- CLONE_FS | CLONE_FILES);
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x01, 0xc0, 0x0f, 0x00, buf + OFFSET_f, SIZE_f,
+ CTRL_TIMEOUT);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: MSG F failed\n", __func__);
+ return ret;
+ }
- if (ret >= 0)
- return; /* OK */
+ return 0;
+}
- dbg("speedtch_firmware_start: kernel_thread failed (%d)!", ret);
+static int speedtch_start_synchro(struct speedtch_instance_data *instance)
+{
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct usb_device *usb_dev = usbatm->usb_dev;
+ unsigned char *buf = instance->scratch_buffer;
+ int ret;
- module_put(THIS_MODULE);
- udsl_put_instance(&instance->u);
- /* Just pretend it never happened... hope modem_run happens */
-#endif /* USE_FW_LOADER */
+ atm_dbg(usbatm, "%s entered\n", __func__);
- speedtch_got_firmware(instance, 0);
-}
+ memset(buf, 0, 2);
-static int speedtch_firmware_wait(struct udsl_instance_data *instance)
-{
- speedtch_firmware_start((void *)instance);
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x04, 0x00,
+ buf, 2, CTRL_TIMEOUT);
- if (wait_event_interruptible(instance->firmware_waiters, instance->status != UDSL_LOADING_FIRMWARE) < 0)
- return -ERESTARTSYS;
+ if (ret < 0)
+ atm_warn(usbatm, "failed to start ADSL synchronisation: %d\n", ret);
+ else
+ atm_dbg(usbatm, "%s: modem prodded. %d bytes returned: %02x %02x\n",
+ __func__, ret, buf[0], buf[1]);
- return (instance->status == UDSL_LOADED_FIRMWARE) ? 0 : -EAGAIN;
+ return ret;
}
-/**********
-** USB **
-**********/
-
-static int speedtch_usb_ioctl(struct usb_interface *intf, unsigned int code,
- void *user_data)
+static void speedtch_check_status(struct speedtch_instance_data *instance)
{
- struct speedtch_instance_data *instance = usb_get_intfdata(intf);
+ struct usbatm_data *usbatm = instance->usbatm;
+ struct atm_dev *atm_dev = usbatm->atm_dev;
+ unsigned char *buf = instance->scratch_buffer;
+ int down_speed, up_speed, ret;
+ unsigned char status;
- dbg("speedtch_usb_ioctl entered");
+ atm_dbg(usbatm, "%s entered\n", __func__);
- if (!instance) {
- dbg("speedtch_usb_ioctl: NULL instance!");
- return -ENODEV;
+ ret = speedtch_read_status(instance);
+ if (ret < 0) {
+ atm_warn(usbatm, "error %d fetching device status\n", ret);
+ instance->poll_delay = min(2 * instance->poll_delay, MAX_POLL_DELAY);
+ return;
}
- switch (code) {
- case UDSL_IOCTL_LINE_UP:
- instance->u.atm_dev->signal = ATM_PHY_SIG_FOUND;
- speedtch_got_firmware(instance, 1);
- return (instance->u.status == UDSL_LOADED_FIRMWARE) ? 0 : -EIO;
- case UDSL_IOCTL_LINE_DOWN:
- instance->u.atm_dev->signal = ATM_PHY_SIG_LOST;
- return 0;
- default:
- return -ENOTTY;
+ instance->poll_delay = max(instance->poll_delay / 2, MIN_POLL_DELAY);
+
+ status = buf[OFFSET_7];
+
+ atm_dbg(usbatm, "%s: line state %02x\n", __func__, status);
+
+ if ((status != instance->last_status) || !status) {
+ switch (status) {
+ case 0:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ if (instance->last_status)
+ atm_info(usbatm, "ADSL line is down\n");
+ /* It may never resync again unless we ask it to... */
+ ret = speedtch_start_synchro(instance);
+ break;
+
+ case 0x08:
+ atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_info(usbatm, "ADSL line is blocked?\n");
+ break;
+
+ case 0x10:
+ atm_dev->signal = ATM_PHY_SIG_LOST;
+ atm_info(usbatm, "ADSL line is synchronising\n");
+ break;
+
+ case 0x20:
+ down_speed = buf[OFFSET_b] | (buf[OFFSET_b + 1] << 8)
+ | (buf[OFFSET_b + 2] << 16) | (buf[OFFSET_b + 3] << 24);
+ up_speed = buf[OFFSET_b + 4] | (buf[OFFSET_b + 5] << 8)
+ | (buf[OFFSET_b + 6] << 16) | (buf[OFFSET_b + 7] << 24);
+
+ if (!(down_speed & 0x0000ffff) && !(up_speed & 0x0000ffff)) {
+ down_speed >>= 16;
+ up_speed >>= 16;
+ }
+
+ atm_dev->link_rate = down_speed * 1000 / 424;
+ atm_dev->signal = ATM_PHY_SIG_FOUND;
+
+ atm_info(usbatm,
+ "ADSL line is up (%d kb/s down | %d kb/s up)\n",
+ down_speed, up_speed);
+ break;
+
+ default:
+ atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+ atm_info(usbatm, "Unknown line state %02x\n", status);
+ break;
+ }
+
+ instance->last_status = status;
}
}
-static int speedtch_usb_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
+static void speedtch_status_poll(unsigned long data)
{
- struct usb_device *dev = interface_to_usbdev(intf);
- int ifnum = intf->altsetting->desc.bInterfaceNumber;
- struct speedtch_instance_data *instance;
- unsigned char mac_str[13];
- int ret, i;
- char buf7[SIZE_7];
+ struct speedtch_instance_data *instance = (void *)data;
- dbg("speedtch_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",
- le16_to_cpu(dev->descriptor.idVendor),
- le16_to_cpu(dev->descriptor.idProduct), ifnum);
+ schedule_work(&instance->status_checker);
- if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
- (ifnum != 1))
- return -ENODEV;
+ /* The following check is racy, but the race is harmless */
+ if (instance->poll_delay < MAX_POLL_DELAY)
+ mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(instance->poll_delay));
+ else
+ atm_warn(instance->usbatm, "Too many failures - disabling line status polling\n");
+}
- dbg("speedtch_usb_probe: device accepted");
+static void speedtch_resubmit_int(unsigned long data)
+{
+ struct speedtch_instance_data *instance = (void *)data;
+ struct urb *int_urb = instance->int_urb;
+ int ret;
- /* instance init */
- instance = kmalloc(sizeof(*instance), GFP_KERNEL);
- if (!instance) {
- dbg("speedtch_usb_probe: no memory for instance data!");
- return -ENOMEM;
+ atm_dbg(instance->usbatm, "%s entered\n", __func__);
+
+ if (int_urb) {
+ ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+ if (!ret)
+ schedule_work(&instance->status_checker);
+ else {
+ atm_dbg(instance->usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+ mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
+ }
}
+}
- memset(instance, 0, sizeof(struct speedtch_instance_data));
+static void speedtch_handle_int(struct urb *int_urb, struct pt_regs *regs)
+{
+ struct speedtch_instance_data *instance = int_urb->context;
+ struct usbatm_data *usbatm = instance->usbatm;
+ unsigned int count = int_urb->actual_length;
+ int ret = int_urb->status;
- if ((ret = usb_set_interface(dev, 0, 0)) < 0)
- goto fail;
+ /* The magic interrupt for "up state" */
+ const static unsigned char up_int[6] = { 0xa1, 0x00, 0x01, 0x00, 0x00, 0x00 };
+ /* The magic interrupt for "down state" */
+ const static unsigned char down_int[6] = { 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00 };
- if ((ret = usb_set_interface(dev, 2, 0)) < 0)
+ atm_dbg(usbatm, "%s entered\n", __func__);
+
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: nonzero urb status %d!\n", __func__, ret);
goto fail;
+ }
- instance->u.data_endpoint = SPEEDTCH_ENDPOINT_DATA;
- instance->u.firmware_wait = speedtch_firmware_wait;
- instance->u.driver_name = speedtch_driver_name;
+ if ((count == 6) && !memcmp(up_int, instance->int_data, 6)) {
+ del_timer(&instance->status_checker.timer);
+ atm_info(usbatm, "DSL line goes up\n");
+ } else if ((count == 6) && !memcmp(down_int, instance->int_data, 6)) {
+ atm_info(usbatm, "DSL line goes down\n");
+ } else {
+ int i;
- ret = udsl_instance_setup(dev, &instance->u);
- if (ret)
+ atm_dbg(usbatm, "%s: unknown interrupt packet of length %d:", __func__, count);
+ for (i = 0; i < count; i++)
+ printk(" %02x", instance->int_data[i]);
+ printk("\n");
goto fail;
+ }
+
+ if ((int_urb = instance->int_urb)) {
+ ret = usb_submit_urb(int_urb, GFP_ATOMIC);
+ schedule_work(&instance->status_checker);
+ if (ret < 0) {
+ atm_dbg(usbatm, "%s: usb_submit_urb failed with result %d\n", __func__, ret);
+ goto fail;
+ }
+ }
+
+ return;
+
+fail:
+ if ((int_urb = instance->int_urb))
+ mod_timer(&instance->resubmit_timer, jiffies + msecs_to_jiffies(RESUBMIT_DELAY));
+}
- init_timer(&instance->poll_timer);
- instance->poll_timer.function = speedtch_timer_poll;
- instance->poll_timer.data = (unsigned long)instance;
+static int speedtch_atm_start(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
+{
+ struct usb_device *usb_dev = usbatm->usb_dev;
+ struct speedtch_instance_data *instance = usbatm->driver_data;
+ int i, ret;
+ unsigned char mac_str[13];
- INIT_WORK(&instance->poll_work, (void *)speedtch_poll_status, instance);
+ atm_dbg(usbatm, "%s entered\n", __func__);
- /* set MAC address, it is stored in the serial number */
- memset(instance->u.atm_dev->esi, 0, sizeof(instance->u.atm_dev->esi));
- if (usb_string(dev, dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
+ if ((ret = usb_set_interface(usb_dev, 1, altsetting)) < 0) {
+ atm_dbg(usbatm, "%s: usb_set_interface returned %d!\n", __func__, ret);
+ return ret;
+ }
+
+ /* Set MAC address, it is stored in the serial number */
+ memset(atm_dev->esi, 0, sizeof(atm_dev->esi));
+ if (usb_string(usb_dev, usb_dev->descriptor.iSerialNumber, mac_str, sizeof(mac_str)) == 12) {
for (i = 0; i < 6; i++)
- instance->u.atm_dev->esi[i] =
- (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
+ atm_dev->esi[i] = (hex2int(mac_str[i * 2]) * 16) + (hex2int(mac_str[i * 2 + 1]));
}
- /* First check whether the modem already seems to be alive */
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x12, 0xc0, 0x07, 0x00, buf7, SIZE_7, 500);
+ /* Start modem synchronisation */
+ ret = speedtch_start_synchro(instance);
- if (ret == SIZE_7) {
- dbg("firmware appears to be already loaded");
- speedtch_got_firmware(instance, 1);
- speedtch_poll_status(instance);
- } else {
- speedtch_firmware_start(instance);
+ /* Set up interrupt endpoint */
+ if (instance->int_urb) {
+ ret = usb_submit_urb(instance->int_urb, GFP_KERNEL);
+ if (ret < 0) {
+ /* Doesn't matter; we'll poll anyway */
+ atm_dbg(usbatm, "%s: submission of interrupt URB failed (%d)!\n", __func__, ret);
+ usb_free_urb(instance->int_urb);
+ instance->int_urb = NULL;
+ }
}
- usb_set_intfdata(intf, instance);
+ /* Start status polling */
+ mod_timer(&instance->status_checker.timer, jiffies + msecs_to_jiffies(1000));
return 0;
+}
- fail:
- kfree(instance);
+static void speedtch_atm_stop(struct usbatm_data *usbatm, struct atm_dev *atm_dev)
+{
+ struct speedtch_instance_data *instance = usbatm->driver_data;
+ struct urb *int_urb = instance->int_urb;
+
+ atm_dbg(usbatm, "%s entered\n", __func__);
+
+ del_timer_sync(&instance->status_checker.timer);
+
+ /*
+ * Since resubmit_timer and int_urb can schedule themselves and
+ * each other, shutting them down correctly takes some care
+ */
+ instance->int_urb = NULL; /* signal shutdown */
+ mb();
+ usb_kill_urb(int_urb);
+ del_timer_sync(&instance->resubmit_timer);
+ /*
+ * At this point, speedtch_handle_int and speedtch_resubmit_int
+ * can run or be running, but instance->int_urb == NULL means that
+ * they will not reschedule
+ */
+ usb_kill_urb(int_urb);
+ del_timer_sync(&instance->resubmit_timer);
+ usb_free_urb(int_urb);
- return -ENOMEM;
+ flush_scheduled_work();
}
-static void speedtch_usb_disconnect(struct usb_interface *intf)
+
+/**********
+** USB **
+**********/
+
+static struct usb_device_id speedtch_usb_ids[] = {
+ {USB_DEVICE(0x06b9, 0x4061)},
+ {}
+};
+
+MODULE_DEVICE_TABLE(usb, speedtch_usb_ids);
+
+static int speedtch_usb_probe(struct usb_interface *, const struct usb_device_id *);
+
+static struct usb_driver speedtch_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = speedtch_driver_name,
+ .probe = speedtch_usb_probe,
+ .disconnect = usbatm_usb_disconnect,
+ .id_table = speedtch_usb_ids
+};
+
+static void speedtch_release_interfaces(struct usb_device *usb_dev, int num_interfaces) {
+ struct usb_interface *cur_intf;
+ int i;
+
+ for(i = 0; i < num_interfaces; i++)
+ if ((cur_intf = usb_ifnum_to_if(usb_dev, i))) {
+ usb_set_intfdata(cur_intf, NULL);
+ usb_driver_release_interface(&speedtch_usb_driver, cur_intf);
+ }
+}
+
+static int speedtch_bind(struct usbatm_data *usbatm,
+ struct usb_interface *intf,
+ const struct usb_device_id *id,
+ int *need_heavy_init)
{
- struct speedtch_instance_data *instance = usb_get_intfdata(intf);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct usb_interface *cur_intf;
+ struct speedtch_instance_data *instance;
+ int ifnum = intf->altsetting->desc.bInterfaceNumber;
+ int num_interfaces = usb_dev->actconfig->desc.bNumInterfaces;
+ int i, ret;
- dbg("speedtch_usb_disconnect entered");
+ usb_dbg(usbatm, "%s entered\n", __func__);
- if (!instance) {
- dbg("speedtch_usb_disconnect: NULL instance!");
- return;
+ if (usb_dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) {
+ usb_dbg(usbatm, "%s: wrong device class %d\n", __func__, usb_dev->descriptor.bDeviceClass);
+ return -ENODEV;
}
-/*QQ need to handle disconnects on interface #2 while uploading firmware */
-/*QQ and what about interface #1? */
+ /* claim all interfaces */
- if (instance->int_urb) {
- struct urb *int_urb = instance->int_urb;
- instance->int_urb = NULL;
- wmb();
- usb_unlink_urb(int_urb);
- usb_free_urb(int_urb);
+ for (i=0; i < num_interfaces; i++) {
+ cur_intf = usb_ifnum_to_if(usb_dev, i);
+
+ if ((i != ifnum) && cur_intf) {
+ ret = usb_driver_claim_interface(&speedtch_usb_driver, cur_intf, usbatm);
+
+ if (ret < 0) {
+ usb_dbg(usbatm, "%s: failed to claim interface %d (%d)\n", __func__, i, ret);
+ speedtch_release_interfaces(usb_dev, i);
+ return ret;
+ }
+ }
}
- instance->int_data[0] = 1;
- del_timer_sync(&instance->poll_timer);
- wmb();
- flush_scheduled_work();
+ instance = kmalloc(sizeof(*instance), GFP_KERNEL);
+
+ if (!instance) {
+ usb_dbg(usbatm, "%s: no memory for instance data!\n", __func__);
+ ret = -ENOMEM;
+ goto fail_release;
+ }
+
+ memset(instance, 0, sizeof(struct speedtch_instance_data));
+
+ instance->usbatm = usbatm;
+
+ INIT_WORK(&instance->status_checker, (void *)speedtch_check_status, instance);
+
+ instance->status_checker.timer.function = speedtch_status_poll;
+ instance->status_checker.timer.data = (unsigned long)instance;
+ instance->last_status = 0xff;
+ instance->poll_delay = MIN_POLL_DELAY;
+
+ init_timer(&instance->resubmit_timer);
+ instance->resubmit_timer.function = speedtch_resubmit_int;
+ instance->resubmit_timer.data = (unsigned long)instance;
- udsl_instance_disconnect(&instance->u);
+ instance->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- /* clean up */
- usb_set_intfdata(intf, NULL);
- udsl_put_instance(&instance->u);
+ if (instance->int_urb)
+ usb_fill_int_urb(instance->int_urb, usb_dev,
+ usb_rcvintpipe(usb_dev, ENDPOINT_INT),
+ instance->int_data, sizeof(instance->int_data),
+ speedtch_handle_int, instance, 50);
+ else
+ usb_dbg(usbatm, "%s: no memory for interrupt urb!\n", __func__);
+
+ /* check whether the modem already seems to be alive */
+ ret = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ 0x12, 0xc0, 0x07, 0x00,
+ instance->scratch_buffer + OFFSET_7, SIZE_7, 500);
+
+ *need_heavy_init = (ret != SIZE_7);
+
+ usb_dbg(usbatm, "%s: firmware %s loaded\n", __func__, need_heavy_init ? "not" : "already");
+
+ if (*need_heavy_init)
+ if ((ret = usb_reset_device(usb_dev)) < 0)
+ goto fail_free;
+
+ usbatm->driver_data = instance;
+
+ return 0;
+
+fail_free:
+ usb_free_urb(instance->int_urb);
+ kfree(instance);
+fail_release:
+ speedtch_release_interfaces(usb_dev, num_interfaces);
+ return ret;
+}
+
+static void speedtch_unbind(struct usbatm_data *usbatm, struct usb_interface *intf)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct speedtch_instance_data *instance = usbatm->driver_data;
+
+ usb_dbg(usbatm, "%s entered\n", __func__);
+
+ speedtch_release_interfaces(usb_dev, usb_dev->actconfig->desc.bNumInterfaces);
+ usb_free_urb(instance->int_urb);
+ kfree(instance);
}
+
/***********
** init **
***********/
+static struct usbatm_driver speedtch_usbatm_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = speedtch_driver_name,
+ .bind = speedtch_bind,
+ .heavy_init = speedtch_heavy_init,
+ .unbind = speedtch_unbind,
+ .atm_start = speedtch_atm_start,
+ .atm_stop = speedtch_atm_stop,
+ .in = ENDPOINT_DATA,
+ .out = ENDPOINT_DATA
+};
+
+static int speedtch_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ return usbatm_usb_probe(intf, id, &speedtch_usbatm_driver);
+}
+
static int __init speedtch_usb_init(void)
{
- dbg("speedtch_usb_init: driver version " DRIVER_VERSION);
+ dbg("%s: driver version %s", __func__, DRIVER_VERSION);
return usb_register(&speedtch_usb_driver);
}
static void __exit speedtch_usb_cleanup(void)
{
- dbg("speedtch_usb_cleanup entered");
+ dbg("%s", __func__);
usb_deregister(&speedtch_usb_driver);
}
diff --git a/drivers/usb/atm/usb_atm.c b/drivers/usb/atm/usb_atm.c
deleted file mode 100644
index a4cd4476d49a..000000000000
--- a/drivers/usb/atm/usb_atm.c
+++ /dev/null
@@ -1,1188 +0,0 @@
-/******************************************************************************
- * usb_atm.c - Generic USB xDSL driver core
- *
- * Copyright (C) 2001, Alcatel
- * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- * Copyright (C) 2004, David Woodhouse
- *
- * 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.
- *
- ******************************************************************************/
-
-/*
- * Written by Johan Verrept, maintained by Duncan Sands (duncan.sands@free.fr)
- *
- * 1.7+: - See the check-in logs
- *
- * 1.6: - No longer opens a connection if the firmware is not loaded
- * - Added support for the speedtouch 330
- * - Removed the limit on the number of devices
- * - Module now autoloads on device plugin
- * - Merged relevant parts of sarlib
- * - Replaced the kernel thread with a tasklet
- * - New packet transmission code
- * - Changed proc file contents
- * - Fixed all known SMP races
- * - Many fixes and cleanups
- * - Various fixes by Oliver Neukum (oliver@neukum.name)
- *
- * 1.5A: - Version for inclusion in 2.5 series kernel
- * - Modifications by Richard Purdie (rpurdie@rpsys.net)
- * - made compatible with kernel 2.5.6 onwards by changing
- * udsl_usb_send_data_context->urb to a pointer and adding code
- * to alloc and free it
- * - remove_wait_queue() added to udsl_atm_processqueue_thread()
- *
- * 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
- * (reported by stephen.robinson@zen.co.uk)
- *
- * 1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave()
- * - unlink all active send urbs of a vcc that is being closed.
- *
- * 1.3.1: - added the version number
- *
- * 1.3: - Added multiple send urb support
- * - fixed memory leak and vcc->tx_inuse starvation bug
- * when not enough memory left in vcc.
- *
- * 1.2: - Fixed race condition in udsl_usb_send_data()
- * 1.1: - Turned off packet debugging
- *
- */
-
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/slab.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <asm/uaccess.h>
-#include <linux/smp_lock.h>
-#include <linux/interrupt.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <linux/crc32.h>
-#include <linux/init.h>
-#include <linux/firmware.h>
-
-#include "usb_atm.h"
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len);
-#define PACKETDEBUG(arg...) udsl_print_packet (arg)
-#define vdbg(arg...) dbg (arg)
-#else
-#define PACKETDEBUG(arg...)
-#define vdbg(arg...)
-#endif
-
-#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
-#define DRIVER_VERSION "1.8"
-#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
-
-static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
-static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
-static unsigned int num_rcv_bufs = UDSL_DEFAULT_RCV_BUFS;
-static unsigned int num_snd_bufs = UDSL_DEFAULT_SND_BUFS;
-static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
-static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
-
-module_param(num_rcv_urbs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_urbs,
- "Number of urbs used for reception (range: 0-"
- __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
-
-module_param(num_snd_urbs, uint, 0444);
-MODULE_PARM_DESC(num_snd_urbs,
- "Number of urbs used for transmission (range: 0-"
- __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
-
-module_param(num_rcv_bufs, uint, 0444);
-MODULE_PARM_DESC(num_rcv_bufs,
- "Number of buffers used for reception (range: 0-"
- __MODULE_STRING(UDSL_MAX_RCV_BUFS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_RCV_BUFS) ")");
-
-module_param(num_snd_bufs, uint, 0444);
-MODULE_PARM_DESC(num_snd_bufs,
- "Number of buffers used for transmission (range: 0-"
- __MODULE_STRING(UDSL_MAX_SND_BUFS) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_SND_BUFS) ")");
-
-module_param(rcv_buf_size, uint, 0444);
-MODULE_PARM_DESC(rcv_buf_size,
- "Size of the buffers used for reception (range: 0-"
- __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
-
-module_param(snd_buf_size, uint, 0444);
-MODULE_PARM_DESC(snd_buf_size,
- "Size of the buffers used for transmission (range: 0-"
- __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
- __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
-
-/* ATM */
-
-static void udsl_atm_dev_close(struct atm_dev *dev);
-static int udsl_atm_open(struct atm_vcc *vcc);
-static void udsl_atm_close(struct atm_vcc *vcc);
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
-
-static struct atmdev_ops udsl_atm_devops = {
- .dev_close = udsl_atm_dev_close,
- .open = udsl_atm_open,
- .close = udsl_atm_close,
- .ioctl = udsl_atm_ioctl,
- .send = udsl_atm_send,
- .proc_read = udsl_atm_proc_read,
- .owner = THIS_MODULE,
-};
-
-/***********
-** misc **
-***********/
-
-static inline void udsl_pop(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- if (vcc->pop)
- vcc->pop(vcc, skb);
- else
- dev_kfree_skb(skb);
-}
-
-/*************
-** decode **
-*************/
-
-static inline struct udsl_vcc_data *udsl_find_vcc(struct udsl_instance_data *instance,
- short vpi, int vci)
-{
- struct udsl_vcc_data *vcc;
-
- list_for_each_entry(vcc, &instance->vcc_list, list)
- if ((vcc->vci == vci) && (vcc->vpi == vpi))
- return vcc;
- return NULL;
-}
-
-static void udsl_extract_cells(struct udsl_instance_data *instance,
- unsigned char *source, unsigned int howmany)
-{
- struct udsl_vcc_data *cached_vcc = NULL;
- struct atm_vcc *vcc;
- struct sk_buff *sarb;
- struct udsl_vcc_data *vcc_data;
- int cached_vci = 0;
- unsigned int i;
- int pti;
- int vci;
- short cached_vpi = 0;
- short vpi;
-
- for (i = 0; i < howmany;
- i++, source += ATM_CELL_SIZE + instance->rcv_padding) {
- vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
- vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
- pti = (source[3] & 0x2) != 0;
-
- vdbg("udsl_extract_cells: vpi %hd, vci %d, pti %d", vpi, vci, pti);
-
- if (cached_vcc && (vci == cached_vci) && (vpi == cached_vpi))
- vcc_data = cached_vcc;
- else if ((vcc_data = udsl_find_vcc(instance, vpi, vci))) {
- cached_vcc = vcc_data;
- cached_vpi = vpi;
- cached_vci = vci;
- } else {
- dbg("udsl_extract_cells: unknown vpi/vci (%hd/%d)!", vpi, vci);
- continue;
- }
-
- vcc = vcc_data->vcc;
- sarb = vcc_data->sarb;
-
- if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
- dbg("udsl_extract_cells: buffer overrun (sarb->len %u, vcc: 0x%p)!", sarb->len, vcc);
- /* discard cells already received */
- skb_trim(sarb, 0);
- }
-
- memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
- __skb_put(sarb, ATM_CELL_PAYLOAD);
-
- if (pti) {
- struct sk_buff *skb;
- unsigned int length;
- unsigned int pdu_length;
-
- length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
-
- /* guard against overflow */
- if (length > ATM_MAX_AAL5_PDU) {
- dbg("udsl_extract_cells: bogus length %u (vcc: 0x%p)!", length, vcc);
- atomic_inc(&vcc->stats->rx_err);
- goto out;
- }
-
- pdu_length = UDSL_NUM_CELLS(length) * ATM_CELL_PAYLOAD;
-
- if (sarb->len < pdu_length) {
- dbg("udsl_extract_cells: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!", pdu_length, sarb->len, vcc);
- atomic_inc(&vcc->stats->rx_err);
- goto out;
- }
-
- if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
- dbg("udsl_extract_cells: packet failed crc check (vcc: 0x%p)!", vcc);
- atomic_inc(&vcc->stats->rx_err);
- goto out;
- }
-
- vdbg("udsl_extract_cells: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", length, pdu_length, vcc);
-
- if (!(skb = dev_alloc_skb(length))) {
- dbg("udsl_extract_cells: no memory for skb (length: %u)!", length);
- atomic_inc(&vcc->stats->rx_drop);
- goto out;
- }
-
- vdbg("udsl_extract_cells: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", skb, skb->truesize);
-
- if (!atm_charge(vcc, skb->truesize)) {
- dbg("udsl_extract_cells: failed atm_charge (skb->truesize: %u)!", skb->truesize);
- dev_kfree_skb(skb);
- goto out; /* atm_charge increments rx_drop */
- }
-
- memcpy(skb->data, sarb->tail - pdu_length, length);
- __skb_put(skb, length);
-
- vdbg("udsl_extract_cells: sending skb 0x%p, skb->len %u, skb->truesize %u", skb, skb->len, skb->truesize);
-
- PACKETDEBUG(skb->data, skb->len);
-
- vcc->push(vcc, skb);
-
- atomic_inc(&vcc->stats->rx);
- out:
- skb_trim(sarb, 0);
- }
- }
-}
-
-/*************
-** encode **
-*************/
-
-static inline void udsl_fill_cell_header(unsigned char *target, struct atm_vcc *vcc)
-{
- target[0] = vcc->vpi >> 4;
- target[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
- target[2] = vcc->vci >> 4;
- target[3] = vcc->vci << 4;
- target[4] = 0xec;
-}
-
-static const unsigned char zeros[ATM_CELL_PAYLOAD];
-
-static void udsl_groom_skb(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct udsl_control *ctrl = UDSL_SKB(skb);
- unsigned int zero_padding;
- u32 crc;
-
- ctrl->atm_data.vcc = vcc;
-
- ctrl->num_cells = UDSL_NUM_CELLS(skb->len);
- ctrl->num_entire = skb->len / ATM_CELL_PAYLOAD;
-
- zero_padding = ctrl->num_cells * ATM_CELL_PAYLOAD - skb->len - ATM_AAL5_TRAILER;
-
- if (ctrl->num_entire + 1 < ctrl->num_cells)
- ctrl->pdu_padding = zero_padding - (ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
- else
- ctrl->pdu_padding = zero_padding;
-
- ctrl->aal5_trailer[0] = 0; /* UU = 0 */
- ctrl->aal5_trailer[1] = 0; /* CPI = 0 */
- ctrl->aal5_trailer[2] = skb->len >> 8;
- ctrl->aal5_trailer[3] = skb->len;
-
- crc = crc32_be(~0, skb->data, skb->len);
- crc = crc32_be(crc, zeros, zero_padding);
- crc = crc32_be(crc, ctrl->aal5_trailer, 4);
- crc = ~crc;
-
- ctrl->aal5_trailer[4] = crc >> 24;
- ctrl->aal5_trailer[5] = crc >> 16;
- ctrl->aal5_trailer[6] = crc >> 8;
- ctrl->aal5_trailer[7] = crc;
-}
-
-static unsigned int udsl_write_cells(struct udsl_instance_data *instance,
- unsigned int howmany, struct sk_buff *skb,
- unsigned char **target_p)
-{
- struct udsl_control *ctrl = UDSL_SKB(skb);
- unsigned char *target = *target_p;
- unsigned int nc, ne, i;
-
- vdbg("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
-
- nc = ctrl->num_cells;
- ne = min(howmany, ctrl->num_entire);
-
- for (i = 0; i < ne; i++) {
- udsl_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memcpy(target, skb->data, ATM_CELL_PAYLOAD);
- target += ATM_CELL_PAYLOAD;
- if (instance->snd_padding) {
- memset(target, 0, instance->snd_padding);
- target += instance->snd_padding;
- }
- __skb_pull(skb, ATM_CELL_PAYLOAD);
- }
-
- ctrl->num_entire -= ne;
-
- if (!(ctrl->num_cells -= ne) || !(howmany -= ne))
- goto out;
-
- udsl_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memcpy(target, skb->data, skb->len);
- target += skb->len;
- __skb_pull(skb, skb->len);
- memset(target, 0, ctrl->pdu_padding);
- target += ctrl->pdu_padding;
-
- if (--ctrl->num_cells) {
- if (!--howmany) {
- ctrl->pdu_padding = ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
- goto out;
- }
-
- if (instance->snd_padding) {
- memset(target, 0, instance->snd_padding);
- target += instance->snd_padding;
- }
- udsl_fill_cell_header(target, ctrl->atm_data.vcc);
- target += ATM_CELL_HEADER;
- memset(target, 0, ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER);
- target += ATM_CELL_PAYLOAD - ATM_AAL5_TRAILER;
-
- --ctrl->num_cells;
- UDSL_ASSERT(!ctrl->num_cells);
- }
-
- memcpy(target, ctrl->aal5_trailer, ATM_AAL5_TRAILER);
- target += ATM_AAL5_TRAILER;
- /* set pti bit in last cell */
- *(target + 3 - ATM_CELL_SIZE) |= 0x2;
- if (instance->snd_padding) {
- memset(target, 0, instance->snd_padding);
- target += instance->snd_padding;
- }
- out:
- *target_p = target;
- return nc - ctrl->num_cells;
-}
-
-/**************
-** receive **
-**************/
-
-static void udsl_complete_receive(struct urb *urb, struct pt_regs *regs)
-{
- struct udsl_receive_buffer *buf;
- struct udsl_instance_data *instance;
- struct udsl_receiver *rcv;
- unsigned long flags;
-
- if (!urb || !(rcv = urb->context)) {
- dbg("udsl_complete_receive: bad urb!");
- return;
- }
-
- instance = rcv->instance;
- buf = rcv->buffer;
-
- buf->filled_cells = urb->actual_length / (ATM_CELL_SIZE + instance->rcv_padding);
-
- vdbg("udsl_complete_receive: urb 0x%p, status %d, actual_length %d, filled_cells %u, rcv 0x%p, buf 0x%p", urb, urb->status, urb->actual_length, buf->filled_cells, rcv, buf);
-
- UDSL_ASSERT(buf->filled_cells <= rcv_buf_size);
-
- /* may not be in_interrupt() */
- spin_lock_irqsave(&instance->receive_lock, flags);
- list_add(&rcv->list, &instance->spare_receivers);
- list_add_tail(&buf->list, &instance->filled_receive_buffers);
- if (likely(!urb->status))
- tasklet_schedule(&instance->receive_tasklet);
- spin_unlock_irqrestore(&instance->receive_lock, flags);
-}
-
-static void udsl_process_receive(unsigned long data)
-{
- struct udsl_receive_buffer *buf;
- struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
- struct udsl_receiver *rcv;
- int err;
-
- made_progress:
- while (!list_empty(&instance->spare_receive_buffers)) {
- spin_lock_irq(&instance->receive_lock);
- if (list_empty(&instance->spare_receivers)) {
- spin_unlock_irq(&instance->receive_lock);
- break;
- }
- rcv = list_entry(instance->spare_receivers.next,
- struct udsl_receiver, list);
- list_del(&rcv->list);
- spin_unlock_irq(&instance->receive_lock);
-
- buf = list_entry(instance->spare_receive_buffers.next,
- struct udsl_receive_buffer, list);
- list_del(&buf->list);
-
- rcv->buffer = buf;
-
- usb_fill_bulk_urb(rcv->urb, instance->usb_dev,
- usb_rcvbulkpipe(instance->usb_dev, instance->data_endpoint),
- buf->base,
- rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
- udsl_complete_receive, rcv);
-
- vdbg("udsl_process_receive: sending urb 0x%p, rcv 0x%p, buf 0x%p",
- rcv->urb, rcv, buf);
-
- if ((err = usb_submit_urb(rcv->urb, GFP_ATOMIC)) < 0) {
- dbg("udsl_process_receive: urb submission failed (%d)!", err);
- list_add(&buf->list, &instance->spare_receive_buffers);
- spin_lock_irq(&instance->receive_lock);
- list_add(&rcv->list, &instance->spare_receivers);
- spin_unlock_irq(&instance->receive_lock);
- break;
- }
- }
-
- spin_lock_irq(&instance->receive_lock);
- if (list_empty(&instance->filled_receive_buffers)) {
- spin_unlock_irq(&instance->receive_lock);
- return; /* done - no more buffers */
- }
- buf = list_entry(instance->filled_receive_buffers.next,
- struct udsl_receive_buffer, list);
- list_del(&buf->list);
- spin_unlock_irq(&instance->receive_lock);
-
- vdbg("udsl_process_receive: processing buf 0x%p", buf);
- udsl_extract_cells(instance, buf->base, buf->filled_cells);
- list_add(&buf->list, &instance->spare_receive_buffers);
- goto made_progress;
-}
-
-/***********
-** send **
-***********/
-
-static void udsl_complete_send(struct urb *urb, struct pt_regs *regs)
-{
- struct udsl_instance_data *instance;
- struct udsl_sender *snd;
- unsigned long flags;
-
- if (!urb || !(snd = urb->context) || !(instance = snd->instance)) {
- dbg("udsl_complete_send: bad urb!");
- return;
- }
-
- vdbg("udsl_complete_send: urb 0x%p, status %d, snd 0x%p, buf 0x%p", urb,
- urb->status, snd, snd->buffer);
-
- /* may not be in_interrupt() */
- spin_lock_irqsave(&instance->send_lock, flags);
- list_add(&snd->list, &instance->spare_senders);
- list_add(&snd->buffer->list, &instance->spare_send_buffers);
- tasklet_schedule(&instance->send_tasklet);
- spin_unlock_irqrestore(&instance->send_lock, flags);
-}
-
-static void udsl_process_send(unsigned long data)
-{
- struct udsl_send_buffer *buf;
- struct udsl_instance_data *instance = (struct udsl_instance_data *)data;
- struct sk_buff *skb;
- struct udsl_sender *snd;
- int err;
- unsigned int num_written;
-
- made_progress:
- spin_lock_irq(&instance->send_lock);
- while (!list_empty(&instance->spare_senders)) {
- if (!list_empty(&instance->filled_send_buffers)) {
- buf = list_entry(instance->filled_send_buffers.next,
- struct udsl_send_buffer, list);
- list_del(&buf->list);
- } else if ((buf = instance->current_buffer)) {
- instance->current_buffer = NULL;
- } else /* all buffers empty */
- break;
-
- snd = list_entry(instance->spare_senders.next,
- struct udsl_sender, list);
- list_del(&snd->list);
- spin_unlock_irq(&instance->send_lock);
-
- snd->buffer = buf;
- usb_fill_bulk_urb(snd->urb, instance->usb_dev,
- usb_sndbulkpipe(instance->usb_dev, instance->data_endpoint),
- buf->base,
- (snd_buf_size - buf->free_cells) * (ATM_CELL_SIZE + instance->snd_padding),
- udsl_complete_send, snd);
-
- vdbg("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p",
- snd->urb, snd_buf_size - buf->free_cells, snd, buf);
-
- if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
- dbg("udsl_process_send: urb submission failed (%d)!", err);
- spin_lock_irq(&instance->send_lock);
- list_add(&snd->list, &instance->spare_senders);
- spin_unlock_irq(&instance->send_lock);
- list_add(&buf->list, &instance->filled_send_buffers);
- return; /* bail out */
- }
-
- spin_lock_irq(&instance->send_lock);
- } /* while */
- spin_unlock_irq(&instance->send_lock);
-
- if (!instance->current_skb)
- instance->current_skb = skb_dequeue(&instance->sndqueue);
- if (!instance->current_skb)
- return; /* done - no more skbs */
-
- skb = instance->current_skb;
-
- if (!(buf = instance->current_buffer)) {
- spin_lock_irq(&instance->send_lock);
- if (list_empty(&instance->spare_send_buffers)) {
- instance->current_buffer = NULL;
- spin_unlock_irq(&instance->send_lock);
- return; /* done - no more buffers */
- }
- buf = list_entry(instance->spare_send_buffers.next,
- struct udsl_send_buffer, list);
- list_del(&buf->list);
- spin_unlock_irq(&instance->send_lock);
-
- buf->free_start = buf->base;
- buf->free_cells = snd_buf_size;
-
- instance->current_buffer = buf;
- }
-
- num_written = udsl_write_cells(instance, buf->free_cells, skb, &buf->free_start);
-
- vdbg("udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p",
- num_written, skb, buf);
-
- if (!(buf->free_cells -= num_written)) {
- list_add_tail(&buf->list, &instance->filled_send_buffers);
- instance->current_buffer = NULL;
- }
-
- vdbg("udsl_process_send: buffer contains %d cells, %d left",
- snd_buf_size - buf->free_cells, buf->free_cells);
-
- if (!UDSL_SKB(skb)->num_cells) {
- struct atm_vcc *vcc = UDSL_SKB(skb)->atm_data.vcc;
-
- udsl_pop(vcc, skb);
- instance->current_skb = NULL;
-
- atomic_inc(&vcc->stats->tx);
- }
-
- goto made_progress;
-}
-
-static void udsl_cancel_send(struct udsl_instance_data *instance,
- struct atm_vcc *vcc)
-{
- struct sk_buff *skb, *n;
-
- dbg("udsl_cancel_send entered");
- spin_lock_irq(&instance->sndqueue.lock);
- for (skb = instance->sndqueue.next, n = skb->next;
- skb != (struct sk_buff *)&instance->sndqueue;
- skb = n, n = skb->next)
- if (UDSL_SKB(skb)->atm_data.vcc == vcc) {
- dbg("udsl_cancel_send: popping skb 0x%p", skb);
- __skb_unlink(skb, &instance->sndqueue);
- udsl_pop(vcc, skb);
- }
- spin_unlock_irq(&instance->sndqueue.lock);
-
- tasklet_disable(&instance->send_tasklet);
- if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm_data.vcc == vcc)) {
- dbg("udsl_cancel_send: popping current skb (0x%p)", skb);
- instance->current_skb = NULL;
- udsl_pop(vcc, skb);
- }
- tasklet_enable(&instance->send_tasklet);
- dbg("udsl_cancel_send done");
-}
-
-static int udsl_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
-{
- struct udsl_instance_data *instance = vcc->dev->dev_data;
- int err;
-
- vdbg("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
-
- if (!instance) {
- dbg("udsl_atm_send: NULL data!");
- err = -ENODEV;
- goto fail;
- }
-
- if (vcc->qos.aal != ATM_AAL5) {
- dbg("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal);
- err = -EINVAL;
- goto fail;
- }
-
- if (skb->len > ATM_MAX_AAL5_PDU) {
- dbg("udsl_atm_send: packet too long (%d vs %d)!", skb->len,
- ATM_MAX_AAL5_PDU);
- err = -EINVAL;
- goto fail;
- }
-
- PACKETDEBUG(skb->data, skb->len);
-
- udsl_groom_skb(vcc, skb);
- skb_queue_tail(&instance->sndqueue, skb);
- tasklet_schedule(&instance->send_tasklet);
-
- return 0;
-
- fail:
- udsl_pop(vcc, skb);
- return err;
-}
-
-/********************
-** bean counting **
-********************/
-
-static void udsl_destroy_instance(struct kref *kref)
-{
- struct udsl_instance_data *instance =
- container_of(kref, struct udsl_instance_data, refcount);
-
- tasklet_kill(&instance->receive_tasklet);
- tasklet_kill(&instance->send_tasklet);
- usb_put_dev(instance->usb_dev);
- kfree(instance);
-}
-
-void udsl_get_instance(struct udsl_instance_data *instance)
-{
- kref_get(&instance->refcount);
-}
-
-void udsl_put_instance(struct udsl_instance_data *instance)
-{
- kref_put(&instance->refcount, udsl_destroy_instance);
-}
-
-/**********
-** ATM **
-**********/
-
-static void udsl_atm_dev_close(struct atm_dev *dev)
-{
- struct udsl_instance_data *instance = dev->dev_data;
-
- dev->dev_data = NULL;
- udsl_put_instance(instance);
-}
-
-static int udsl_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
-{
- struct udsl_instance_data *instance = atm_dev->dev_data;
- int left = *pos;
-
- if (!instance) {
- dbg("udsl_atm_proc_read: NULL instance!");
- return -ENODEV;
- }
-
- if (!left--)
- return sprintf(page, "%s\n", instance->description);
-
- if (!left--)
- return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
- atm_dev->esi[0], atm_dev->esi[1],
- atm_dev->esi[2], atm_dev->esi[3],
- atm_dev->esi[4], atm_dev->esi[5]);
-
- if (!left--)
- return sprintf(page,
- "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
- atomic_read(&atm_dev->stats.aal5.tx),
- atomic_read(&atm_dev->stats.aal5.tx_err),
- atomic_read(&atm_dev->stats.aal5.rx),
- atomic_read(&atm_dev->stats.aal5.rx_err),
- atomic_read(&atm_dev->stats.aal5.rx_drop));
-
- if (!left--) {
- switch (atm_dev->signal) {
- case ATM_PHY_SIG_FOUND:
- sprintf(page, "Line up");
- break;
- case ATM_PHY_SIG_LOST:
- sprintf(page, "Line down");
- break;
- default:
- sprintf(page, "Line state unknown");
- break;
- }
-
- if (instance->usb_dev->state == USB_STATE_NOTATTACHED)
- strcat(page, ", disconnected\n");
- else {
- if (instance->status == UDSL_LOADED_FIRMWARE)
- strcat(page, ", firmware loaded\n");
- else if (instance->status == UDSL_LOADING_FIRMWARE)
- strcat(page, ", firmware loading\n");
- else
- strcat(page, ", no firmware\n");
- }
-
- return strlen(page);
- }
-
- return 0;
-}
-
-static int udsl_atm_open(struct atm_vcc *vcc)
-{
- struct udsl_instance_data *instance = vcc->dev->dev_data;
- struct udsl_vcc_data *new;
- unsigned int max_pdu;
- int vci = vcc->vci;
- short vpi = vcc->vpi;
- int err;
-
- dbg("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
-
- if (!instance) {
- dbg("udsl_atm_open: NULL data!");
- return -ENODEV;
- }
-
- /* only support AAL5 */
- if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
- || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
- dbg("udsl_atm_open: unsupported ATM type %d!", vcc->qos.aal);
- return -EINVAL;
- }
-
- if (instance->firmware_wait &&
- (err = instance->firmware_wait(instance)) < 0) {
- dbg("udsl_atm_open: firmware not loaded (%d)!", err);
- return err;
- }
-
- down(&instance->serialize); /* vs self, udsl_atm_close */
-
- if (udsl_find_vcc(instance, vpi, vci)) {
- dbg("udsl_atm_open: %hd/%d already in use!", vpi, vci);
- up(&instance->serialize);
- return -EADDRINUSE;
- }
-
- if (!(new = kmalloc(sizeof(struct udsl_vcc_data), GFP_KERNEL))) {
- dbg("udsl_atm_open: no memory for vcc_data!");
- up(&instance->serialize);
- return -ENOMEM;
- }
-
- memset(new, 0, sizeof(struct udsl_vcc_data));
- new->vcc = vcc;
- new->vpi = vpi;
- new->vci = vci;
-
- /* udsl_extract_cells requires at least one cell */
- max_pdu = max(1, UDSL_NUM_CELLS(vcc->qos.rxtp.max_sdu)) * ATM_CELL_PAYLOAD;
- if (!(new->sarb = alloc_skb(max_pdu, GFP_KERNEL))) {
- dbg("udsl_atm_open: no memory for SAR buffer!");
- kfree(new);
- up(&instance->serialize);
- return -ENOMEM;
- }
-
- vcc->dev_data = new;
-
- tasklet_disable(&instance->receive_tasklet);
- list_add(&new->list, &instance->vcc_list);
- tasklet_enable(&instance->receive_tasklet);
-
- set_bit(ATM_VF_ADDR, &vcc->flags);
- set_bit(ATM_VF_PARTIAL, &vcc->flags);
- set_bit(ATM_VF_READY, &vcc->flags);
-
- up(&instance->serialize);
-
- tasklet_schedule(&instance->receive_tasklet);
-
- dbg("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, max_pdu);
-
- return 0;
-}
-
-static void udsl_atm_close(struct atm_vcc *vcc)
-{
- struct udsl_instance_data *instance = vcc->dev->dev_data;
- struct udsl_vcc_data *vcc_data = vcc->dev_data;
-
- dbg("udsl_atm_close called");
-
- if (!instance || !vcc_data) {
- dbg("udsl_atm_close: NULL data!");
- return;
- }
-
- dbg("udsl_atm_close: deallocating vcc 0x%p with vpi %d vci %d",
- vcc_data, vcc_data->vpi, vcc_data->vci);
-
- udsl_cancel_send(instance, vcc);
-
- down(&instance->serialize); /* vs self, udsl_atm_open */
-
- tasklet_disable(&instance->receive_tasklet);
- list_del(&vcc_data->list);
- tasklet_enable(&instance->receive_tasklet);
-
- kfree_skb(vcc_data->sarb);
- vcc_data->sarb = NULL;
-
- kfree(vcc_data);
- vcc->dev_data = NULL;
-
- vcc->vpi = ATM_VPI_UNSPEC;
- vcc->vci = ATM_VCI_UNSPEC;
- clear_bit(ATM_VF_READY, &vcc->flags);
- clear_bit(ATM_VF_PARTIAL, &vcc->flags);
- clear_bit(ATM_VF_ADDR, &vcc->flags);
-
- up(&instance->serialize);
-
- dbg("udsl_atm_close successful");
-}
-
-static int udsl_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
- void __user * arg)
-{
- switch (cmd) {
- case ATM_QUERYLOOP:
- return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-/**********
-** USB **
-**********/
-
-int udsl_instance_setup(struct usb_device *dev,
- struct udsl_instance_data *instance)
-{
- char *buf;
- int i, length;
-
- kref_init(&instance->refcount); /* one for USB */
- udsl_get_instance(instance); /* one for ATM */
-
- init_MUTEX(&instance->serialize);
-
- instance->usb_dev = dev;
-
- INIT_LIST_HEAD(&instance->vcc_list);
-
- instance->status = UDSL_NO_FIRMWARE;
- init_waitqueue_head(&instance->firmware_waiters);
-
- spin_lock_init(&instance->receive_lock);
- INIT_LIST_HEAD(&instance->spare_receivers);
- INIT_LIST_HEAD(&instance->filled_receive_buffers);
-
- tasklet_init(&instance->receive_tasklet, udsl_process_receive, (unsigned long)instance);
- INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
- skb_queue_head_init(&instance->sndqueue);
-
- spin_lock_init(&instance->send_lock);
- INIT_LIST_HEAD(&instance->spare_senders);
- INIT_LIST_HEAD(&instance->spare_send_buffers);
-
- tasklet_init(&instance->send_tasklet, udsl_process_send,
- (unsigned long)instance);
- INIT_LIST_HEAD(&instance->filled_send_buffers);
-
- /* receive init */
- for (i = 0; i < num_rcv_urbs; i++) {
- struct udsl_receiver *rcv = &(instance->receivers[i]);
-
- if (!(rcv->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dbg("udsl_usb_probe: no memory for receive urb %d!", i);
- goto fail;
- }
-
- rcv->instance = instance;
-
- list_add(&rcv->list, &instance->spare_receivers);
- }
-
- for (i = 0; i < num_rcv_bufs; i++) {
- struct udsl_receive_buffer *buf =
- &(instance->receive_buffers[i]);
-
- buf->base = kmalloc(rcv_buf_size * (ATM_CELL_SIZE + instance->rcv_padding),
- GFP_KERNEL);
- if (!buf->base) {
- dbg("udsl_usb_probe: no memory for receive buffer %d!", i);
- goto fail;
- }
-
- list_add(&buf->list, &instance->spare_receive_buffers);
- }
-
- /* send init */
- for (i = 0; i < num_snd_urbs; i++) {
- struct udsl_sender *snd = &(instance->senders[i]);
-
- if (!(snd->urb = usb_alloc_urb(0, GFP_KERNEL))) {
- dbg("udsl_usb_probe: no memory for send urb %d!", i);
- goto fail;
- }
-
- snd->instance = instance;
-
- list_add(&snd->list, &instance->spare_senders);
- }
-
- for (i = 0; i < num_snd_bufs; i++) {
- struct udsl_send_buffer *buf = &(instance->send_buffers[i]);
-
- buf->base = kmalloc(snd_buf_size * (ATM_CELL_SIZE + instance->snd_padding),
- GFP_KERNEL);
- if (!buf->base) {
- dbg("udsl_usb_probe: no memory for send buffer %d!", i);
- goto fail;
- }
-
- list_add(&buf->list, &instance->spare_send_buffers);
- }
-
- /* ATM init */
- instance->atm_dev = atm_dev_register(instance->driver_name,
- &udsl_atm_devops, -1, NULL);
- if (!instance->atm_dev) {
- dbg("udsl_usb_probe: failed to register ATM device!");
- goto fail;
- }
-
- instance->atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
- instance->atm_dev->ci_range.vci_bits = ATM_CI_MAX;
- instance->atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
-
- /* temp init ATM device, set to 128kbit */
- instance->atm_dev->link_rate = 128 * 1000 / 424;
-
- /* device description */
- buf = instance->description;
- length = sizeof(instance->description);
-
- if ((i = usb_string(dev, dev->descriptor.iProduct, buf, length)) < 0)
- goto finish;
-
- buf += i;
- length -= i;
-
- i = scnprintf(buf, length, " (");
- buf += i;
- length -= i;
-
- if (length <= 0 || (i = usb_make_path(dev, buf, length)) < 0)
- goto finish;
-
- buf += i;
- length -= i;
-
- snprintf(buf, length, ")");
-
- finish:
- /* ready for ATM callbacks */
- wmb();
- instance->atm_dev->dev_data = instance;
-
- usb_get_dev(dev);
-
- return 0;
-
- fail:
- for (i = 0; i < num_snd_bufs; i++)
- kfree(instance->send_buffers[i].base);
-
- for (i = 0; i < num_snd_urbs; i++)
- usb_free_urb(instance->senders[i].urb);
-
- for (i = 0; i < num_rcv_bufs; i++)
- kfree(instance->receive_buffers[i].base);
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_free_urb(instance->receivers[i].urb);
-
- return -ENOMEM;
-}
-
-void udsl_instance_disconnect(struct udsl_instance_data *instance)
-{
- int i;
-
- dbg("udsl_instance_disconnect entered");
-
- if (!instance) {
- dbg("udsl_instance_disconnect: NULL instance!");
- return;
- }
-
- /* receive finalize */
- tasklet_disable(&instance->receive_tasklet);
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_kill_urb(instance->receivers[i].urb);
-
- /* no need to take the spinlock */
- INIT_LIST_HEAD(&instance->filled_receive_buffers);
- INIT_LIST_HEAD(&instance->spare_receive_buffers);
-
- tasklet_enable(&instance->receive_tasklet);
-
- for (i = 0; i < num_rcv_urbs; i++)
- usb_free_urb(instance->receivers[i].urb);
-
- for (i = 0; i < num_rcv_bufs; i++)
- kfree(instance->receive_buffers[i].base);
-
- /* send finalize */
- tasklet_disable(&instance->send_tasklet);
-
- for (i = 0; i < num_snd_urbs; i++)
- usb_kill_urb(instance->senders[i].urb);
-
- /* no need to take the spinlock */
- INIT_LIST_HEAD(&instance->spare_senders);
- INIT_LIST_HEAD(&instance->spare_send_buffers);
- instance->current_buffer = NULL;
-
- tasklet_enable(&instance->send_tasklet);
-
- for (i = 0; i < num_snd_urbs; i++)
- usb_free_urb(instance->senders[i].urb);
-
- for (i = 0; i < num_snd_bufs; i++)
- kfree(instance->send_buffers[i].base);
-
- /* ATM finalize */
- shutdown_atm_dev(instance->atm_dev);
-}
-
-EXPORT_SYMBOL_GPL(udsl_get_instance);
-EXPORT_SYMBOL_GPL(udsl_put_instance);
-EXPORT_SYMBOL_GPL(udsl_instance_setup);
-EXPORT_SYMBOL_GPL(udsl_instance_disconnect);
-
-/***********
-** init **
-***********/
-
-static int __init udsl_usb_init(void)
-{
- dbg("udsl_usb_init: driver version " DRIVER_VERSION);
-
- if (sizeof(struct udsl_control) > sizeof(((struct sk_buff *) 0)->cb)) {
- printk(KERN_ERR __FILE__ ": unusable with this kernel!\n");
- return -EIO;
- }
-
- if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
- || (num_snd_urbs > UDSL_MAX_SND_URBS)
- || (num_rcv_bufs > UDSL_MAX_RCV_BUFS)
- || (num_snd_bufs > UDSL_MAX_SND_BUFS)
- || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
- || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
- return -EINVAL;
-
- return 0;
-}
-
-static void __exit udsl_usb_exit(void)
-{
-}
-
-module_init(udsl_usb_init);
-module_exit(udsl_usb_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
-/************
-** debug **
-************/
-
-#ifdef VERBOSE_DEBUG
-static int udsl_print_packet(const unsigned char *data, int len)
-{
- unsigned char buffer[256];
- int i = 0, j = 0;
-
- for (i = 0; i < len;) {
- buffer[0] = '\0';
- sprintf(buffer, "%.3d :", i);
- for (j = 0; (j < 16) && (i < len); j++, i++) {
- sprintf(buffer, "%s %2.2x", buffer, data[i]);
- }
- dbg("%s", buffer);
- }
- return i;
-}
-#endif
diff --git a/drivers/usb/atm/usb_atm.h b/drivers/usb/atm/usb_atm.h
deleted file mode 100644
index cf8c53283530..000000000000
--- a/drivers/usb/atm/usb_atm.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/******************************************************************************
- * usb_atm.h - Generic USB xDSL driver core
- *
- * Copyright (C) 2001, Alcatel
- * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
- * Copyright (C) 2004, David Woodhouse
- *
- * 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 <linux/config.h>
-#include <linux/list.h>
-#include <linux/kref.h>
-#include <linux/atm.h>
-#include <linux/atmdev.h>
-#include <asm/semaphore.h>
-
-/*
-#define DEBUG
-#define VERBOSE_DEBUG
-*/
-
-#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
-# define DEBUG
-#endif
-
-#include <linux/usb.h>
-
-#ifdef DEBUG
-#define UDSL_ASSERT(x) BUG_ON(!(x))
-#else
-#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '" #x "' at line %d", __LINE__); } while(0)
-#endif
-
-#define UDSL_MAX_RCV_URBS 4
-#define UDSL_MAX_SND_URBS 4
-#define UDSL_MAX_RCV_BUFS 8
-#define UDSL_MAX_SND_BUFS 8
-#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
-#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
-#define UDSL_DEFAULT_RCV_URBS 2
-#define UDSL_DEFAULT_SND_URBS 2
-#define UDSL_DEFAULT_RCV_BUFS 4
-#define UDSL_DEFAULT_SND_BUFS 4
-#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
-#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
-
-#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
-#define UDSL_NUM_CELLS(x) (((x) + ATM_AAL5_TRAILER + ATM_CELL_PAYLOAD - 1) / ATM_CELL_PAYLOAD)
-
-/* receive */
-
-struct udsl_receive_buffer {
- struct list_head list;
- unsigned char *base;
- unsigned int filled_cells;
-};
-
-struct udsl_receiver {
- struct list_head list;
- struct udsl_receive_buffer *buffer;
- struct urb *urb;
- struct udsl_instance_data *instance;
-};
-
-struct udsl_vcc_data {
- /* vpi/vci lookup */
- struct list_head list;
- short vpi;
- int vci;
- struct atm_vcc *vcc;
-
- /* raw cell reassembly */
- struct sk_buff *sarb;
-};
-
-/* send */
-
-struct udsl_send_buffer {
- struct list_head list;
- unsigned char *base;
- unsigned char *free_start;
- unsigned int free_cells;
-};
-
-struct udsl_sender {
- struct list_head list;
- struct udsl_send_buffer *buffer;
- struct urb *urb;
- struct udsl_instance_data *instance;
-};
-
-struct udsl_control {
- struct atm_skb_data atm_data;
- unsigned int num_cells;
- unsigned int num_entire;
- unsigned int pdu_padding;
- unsigned char aal5_trailer[ATM_AAL5_TRAILER];
-};
-
-#define UDSL_SKB(x) ((struct udsl_control *)(x)->cb)
-
-/* main driver data */
-
-enum udsl_status {
- UDSL_NO_FIRMWARE,
- UDSL_LOADING_FIRMWARE,
- UDSL_LOADED_FIRMWARE
-};
-
-struct udsl_instance_data {
- struct kref refcount;
- struct semaphore serialize;
-
- /* USB device part */
- struct usb_device *usb_dev;
- char description[64];
- int data_endpoint;
- int snd_padding;
- int rcv_padding;
- const char *driver_name;
-
- /* ATM device part */
- struct atm_dev *atm_dev;
- struct list_head vcc_list;
-
- /* firmware */
- int (*firmware_wait) (struct udsl_instance_data *);
- enum udsl_status status;
- wait_queue_head_t firmware_waiters;
-
- /* receive */
- struct udsl_receiver receivers[UDSL_MAX_RCV_URBS];
- struct udsl_receive_buffer receive_buffers[UDSL_MAX_RCV_BUFS];
-
- spinlock_t receive_lock;
- struct list_head spare_receivers;
- struct list_head filled_receive_buffers;
-
- struct tasklet_struct receive_tasklet;
- struct list_head spare_receive_buffers;
-
- /* send */
- struct udsl_sender senders[UDSL_MAX_SND_URBS];
- struct udsl_send_buffer send_buffers[UDSL_MAX_SND_BUFS];
-
- struct sk_buff_head sndqueue;
-
- spinlock_t send_lock;
- struct list_head spare_senders;
- struct list_head spare_send_buffers;
-
- struct tasklet_struct send_tasklet;
- struct sk_buff *current_skb; /* being emptied */
- struct udsl_send_buffer *current_buffer; /* being filled */
- struct list_head filled_send_buffers;
-};
-
-extern int udsl_instance_setup(struct usb_device *dev,
- struct udsl_instance_data *instance);
-extern void udsl_instance_disconnect(struct udsl_instance_data *instance);
-extern void udsl_get_instance(struct udsl_instance_data *instance);
-extern void udsl_put_instance(struct udsl_instance_data *instance);
diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c
new file mode 100644
index 000000000000..bb1db1959854
--- /dev/null
+++ b/drivers/usb/atm/usbatm.c
@@ -0,0 +1,1230 @@
+/******************************************************************************
+ * usbatm.c - Generic USB xDSL driver core
+ *
+ * Copyright (C) 2001, Alcatel
+ * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ * Copyright (C) 2004, David Woodhouse, Roman Kagan
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*
+ * Written by Johan Verrept, Duncan Sands (duncan.sands@free.fr) and David Woodhouse
+ *
+ * 1.7+: - See the check-in logs
+ *
+ * 1.6: - No longer opens a connection if the firmware is not loaded
+ * - Added support for the speedtouch 330
+ * - Removed the limit on the number of devices
+ * - Module now autoloads on device plugin
+ * - Merged relevant parts of sarlib
+ * - Replaced the kernel thread with a tasklet
+ * - New packet transmission code
+ * - Changed proc file contents
+ * - Fixed all known SMP races
+ * - Many fixes and cleanups
+ * - Various fixes by Oliver Neukum (oliver@neukum.name)
+ *
+ * 1.5A: - Version for inclusion in 2.5 series kernel
+ * - Modifications by Richard Purdie (rpurdie@rpsys.net)
+ * - made compatible with kernel 2.5.6 onwards by changing
+ * usbatm_usb_send_data_context->urb to a pointer and adding code
+ * to alloc and free it
+ * - remove_wait_queue() added to usbatm_atm_processqueue_thread()
+ *
+ * 1.5: - fixed memory leak when atmsar_decode_aal5 returned NULL.
+ * (reported by stephen.robinson@zen.co.uk)
+ *
+ * 1.4: - changed the spin_lock() under interrupt to spin_lock_irqsave()
+ * - unlink all active send urbs of a vcc that is being closed.
+ *
+ * 1.3.1: - added the version number
+ *
+ * 1.3: - Added multiple send urb support
+ * - fixed memory leak and vcc->tx_inuse starvation bug
+ * when not enough memory left in vcc.
+ *
+ * 1.2: - Fixed race condition in usbatm_usb_send_data()
+ * 1.1: - Turned off packet debugging
+ *
+ */
+
+#include "usbatm.h"
+
+#include <asm/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/stat.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len);
+#define PACKETDEBUG(arg...) usbatm_print_packet (arg)
+#define vdbg(arg...) dbg (arg)
+#else
+#define PACKETDEBUG(arg...)
+#define vdbg(arg...)
+#endif
+
+#define DRIVER_AUTHOR "Johan Verrept, Duncan Sands <duncan.sands@free.fr>"
+#define DRIVER_VERSION "1.9"
+#define DRIVER_DESC "Generic USB ATM/DSL I/O, version " DRIVER_VERSION
+
+static const char usbatm_driver_name[] = "usbatm";
+
+#define UDSL_MAX_RCV_URBS 16
+#define UDSL_MAX_SND_URBS 16
+#define UDSL_MAX_RCV_BUF_SIZE 1024 /* ATM cells */
+#define UDSL_MAX_SND_BUF_SIZE 1024 /* ATM cells */
+#define UDSL_DEFAULT_RCV_URBS 4
+#define UDSL_DEFAULT_SND_URBS 4
+#define UDSL_DEFAULT_RCV_BUF_SIZE 64 /* ATM cells */
+#define UDSL_DEFAULT_SND_BUF_SIZE 64 /* ATM cells */
+
+#define ATM_CELL_HEADER (ATM_CELL_SIZE - ATM_CELL_PAYLOAD)
+
+#define THROTTLE_MSECS 100 /* delay to recover processing after urb submission fails */
+
+static unsigned int num_rcv_urbs = UDSL_DEFAULT_RCV_URBS;
+static unsigned int num_snd_urbs = UDSL_DEFAULT_SND_URBS;
+static unsigned int rcv_buf_size = UDSL_DEFAULT_RCV_BUF_SIZE;
+static unsigned int snd_buf_size = UDSL_DEFAULT_SND_BUF_SIZE;
+
+module_param(num_rcv_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_rcv_urbs,
+ "Number of urbs used for reception (range: 0-"
+ __MODULE_STRING(UDSL_MAX_RCV_URBS) ", default: "
+ __MODULE_STRING(UDSL_DEFAULT_RCV_URBS) ")");
+
+module_param(num_snd_urbs, uint, S_IRUGO);
+MODULE_PARM_DESC(num_snd_urbs,
+ "Number of urbs used for transmission (range: 0-"
+ __MODULE_STRING(UDSL_MAX_SND_URBS) ", default: "
+ __MODULE_STRING(UDSL_DEFAULT_SND_URBS) ")");
+
+module_param(rcv_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(rcv_buf_size,
+ "Size of the buffers used for reception in ATM cells (range: 1-"
+ __MODULE_STRING(UDSL_MAX_RCV_BUF_SIZE) ", default: "
+ __MODULE_STRING(UDSL_DEFAULT_RCV_BUF_SIZE) ")");
+
+module_param(snd_buf_size, uint, S_IRUGO);
+MODULE_PARM_DESC(snd_buf_size,
+ "Size of the buffers used for transmission in ATM cells (range: 1-"
+ __MODULE_STRING(UDSL_MAX_SND_BUF_SIZE) ", default: "
+ __MODULE_STRING(UDSL_DEFAULT_SND_BUF_SIZE) ")");
+
+
+/* receive */
+
+struct usbatm_vcc_data {
+ /* vpi/vci lookup */
+ struct list_head list;
+ short vpi;
+ int vci;
+ struct atm_vcc *vcc;
+
+ /* raw cell reassembly */
+ struct sk_buff *sarb;
+};
+
+
+/* send */
+
+struct usbatm_control {
+ struct atm_skb_data atm;
+ u32 len;
+ u32 crc;
+};
+
+#define UDSL_SKB(x) ((struct usbatm_control *)(x)->cb)
+
+
+/* ATM */
+
+static void usbatm_atm_dev_close(struct atm_dev *dev);
+static int usbatm_atm_open(struct atm_vcc *vcc);
+static void usbatm_atm_close(struct atm_vcc *vcc);
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd, void __user * arg);
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb);
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page);
+
+static struct atmdev_ops usbatm_atm_devops = {
+ .dev_close = usbatm_atm_dev_close,
+ .open = usbatm_atm_open,
+ .close = usbatm_atm_close,
+ .ioctl = usbatm_atm_ioctl,
+ .send = usbatm_atm_send,
+ .proc_read = usbatm_atm_proc_read,
+ .owner = THIS_MODULE,
+};
+
+
+/***********
+** misc **
+***********/
+
+static inline unsigned int usbatm_pdu_length(unsigned int length)
+{
+ length += ATM_CELL_PAYLOAD - 1 + ATM_AAL5_TRAILER;
+ return length - length % ATM_CELL_PAYLOAD;
+}
+
+static inline void usbatm_pop(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+ if (vcc->pop)
+ vcc->pop(vcc, skb);
+ else
+ dev_kfree_skb(skb);
+}
+
+
+/***********
+** urbs **
+************/
+
+static inline struct urb *usbatm_pop_urb(struct usbatm_channel *channel)
+{
+ struct urb *urb;
+
+ spin_lock_irq(&channel->lock);
+ if (list_empty(&channel->list)) {
+ spin_unlock_irq(&channel->lock);
+ return NULL;
+ }
+
+ urb = list_entry(channel->list.next, struct urb, urb_list);
+ list_del(&urb->urb_list);
+ spin_unlock_irq(&channel->lock);
+
+ return urb;
+}
+
+static inline int usbatm_submit_urb(struct urb *urb)
+{
+ struct usbatm_channel *channel = urb->context;
+ int ret;
+
+ vdbg("%s: submitting urb 0x%p, size %u",
+ __func__, urb, urb->transfer_buffer_length);
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret) {
+ atm_dbg(channel->usbatm, "%s: urb 0x%p submission failed (%d)!\n",
+ __func__, urb, ret);
+
+ /* consider all errors transient and return the buffer back to the queue */
+ urb->status = -EAGAIN;
+ spin_lock_irq(&channel->lock);
+
+ /* must add to the front when sending; doesn't matter when receiving */
+ list_add(&urb->urb_list, &channel->list);
+
+ spin_unlock_irq(&channel->lock);
+
+ /* make sure the channel doesn't stall */
+ mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+ }
+
+ return ret;
+}
+
+static void usbatm_complete(struct urb *urb, struct pt_regs *regs)
+{
+ struct usbatm_channel *channel = urb->context;
+ unsigned long flags;
+
+ vdbg("%s: urb 0x%p, status %d, actual_length %d",
+ __func__, urb, urb->status, urb->actual_length);
+
+ /* usually in_interrupt(), but not always */
+ spin_lock_irqsave(&channel->lock, flags);
+
+ /* must add to the back when receiving; doesn't matter when sending */
+ list_add_tail(&urb->urb_list, &channel->list);
+
+ spin_unlock_irqrestore(&channel->lock, flags);
+
+ if (unlikely(urb->status))
+ /* throttle processing in case of an error */
+ mod_timer(&channel->delay, jiffies + msecs_to_jiffies(THROTTLE_MSECS));
+ else
+ tasklet_schedule(&channel->tasklet);
+}
+
+
+/*************
+** decode **
+*************/
+
+static inline struct usbatm_vcc_data *usbatm_find_vcc(struct usbatm_data *instance,
+ short vpi, int vci)
+{
+ struct usbatm_vcc_data *vcc;
+
+ list_for_each_entry(vcc, &instance->vcc_list, list)
+ if ((vcc->vci == vci) && (vcc->vpi == vpi))
+ return vcc;
+ return NULL;
+}
+
+static void usbatm_extract_cells(struct usbatm_data *instance,
+ unsigned char *source, unsigned int avail_data)
+{
+ struct usbatm_vcc_data *cached_vcc = NULL;
+ struct atm_vcc *vcc;
+ struct sk_buff *sarb;
+ unsigned int stride = instance->rx_channel.stride;
+ int vci, cached_vci = 0;
+ short vpi, cached_vpi = 0;
+ u8 pti;
+
+ for (; avail_data >= stride; avail_data -= stride, source += stride) {
+ vpi = ((source[0] & 0x0f) << 4) | (source[1] >> 4);
+ vci = ((source[1] & 0x0f) << 12) | (source[2] << 4) | (source[3] >> 4);
+ pti = ((source[3] & 0xe) >> 1);
+
+ vdbg("%s: vpi %hd, vci %d, pti %d", __func__, vpi, vci, pti);
+
+ if ((vci != cached_vci) || (vpi != cached_vpi)) {
+ cached_vpi = vpi;
+ cached_vci = vci;
+
+ cached_vcc = usbatm_find_vcc(instance, vpi, vci);
+
+ if (!cached_vcc)
+ atm_dbg(instance, "%s: unknown vpi/vci (%hd/%d)!\n", __func__, vpi, vci);
+ }
+
+ if (!cached_vcc)
+ continue;
+
+ vcc = cached_vcc->vcc;
+
+ /* OAM F5 end-to-end */
+ if (pti == ATM_PTI_E2EF5) {
+ atm_warn(instance, "%s: OAM not supported (vpi %d, vci %d)!\n", __func__, vpi, vci);
+ atomic_inc(&vcc->stats->rx_err);
+ continue;
+ }
+
+ sarb = cached_vcc->sarb;
+
+ if (sarb->tail + ATM_CELL_PAYLOAD > sarb->end) {
+ atm_dbg(instance, "%s: buffer overrun (sarb->len %u, vcc: 0x%p)!\n",
+ __func__, sarb->len, vcc);
+ /* discard cells already received */
+ skb_trim(sarb, 0);
+ UDSL_ASSERT(sarb->tail + ATM_CELL_PAYLOAD <= sarb->end);
+ }
+
+ memcpy(sarb->tail, source + ATM_CELL_HEADER, ATM_CELL_PAYLOAD);
+ __skb_put(sarb, ATM_CELL_PAYLOAD);
+
+ if (pti & 1) {
+ struct sk_buff *skb;
+ unsigned int length;
+ unsigned int pdu_length;
+
+ length = (source[ATM_CELL_SIZE - 6] << 8) + source[ATM_CELL_SIZE - 5];
+
+ /* guard against overflow */
+ if (length > ATM_MAX_AAL5_PDU) {
+ atm_dbg(instance, "%s: bogus length %u (vcc: 0x%p)!\n",
+ __func__, length, vcc);
+ atomic_inc(&vcc->stats->rx_err);
+ goto out;
+ }
+
+ pdu_length = usbatm_pdu_length(length);
+
+ if (sarb->len < pdu_length) {
+ atm_dbg(instance, "%s: bogus pdu_length %u (sarb->len: %u, vcc: 0x%p)!\n",
+ __func__, pdu_length, sarb->len, vcc);
+ atomic_inc(&vcc->stats->rx_err);
+ goto out;
+ }
+
+ if (crc32_be(~0, sarb->tail - pdu_length, pdu_length) != 0xc704dd7b) {
+ atm_dbg(instance, "%s: packet failed crc check (vcc: 0x%p)!\n",
+ __func__, vcc);
+ atomic_inc(&vcc->stats->rx_err);
+ goto out;
+ }
+
+ vdbg("%s: got packet (length: %u, pdu_length: %u, vcc: 0x%p)", __func__, length, pdu_length, vcc);
+
+ if (!(skb = dev_alloc_skb(length))) {
+ atm_dbg(instance, "%s: no memory for skb (length: %u)!\n", __func__, length);
+ atomic_inc(&vcc->stats->rx_drop);
+ goto out;
+ }
+
+ vdbg("%s: allocated new sk_buff (skb: 0x%p, skb->truesize: %u)", __func__, skb, skb->truesize);
+
+ if (!atm_charge(vcc, skb->truesize)) {
+ atm_dbg(instance, "%s: failed atm_charge (skb->truesize: %u)!\n", __func__, skb->truesize);
+ dev_kfree_skb(skb);
+ goto out; /* atm_charge increments rx_drop */
+ }
+
+ memcpy(skb->data, sarb->tail - pdu_length, length);
+ __skb_put(skb, length);
+
+ vdbg("%s: sending skb 0x%p, skb->len %u, skb->truesize %u",
+ __func__, skb, skb->len, skb->truesize);
+
+ PACKETDEBUG(skb->data, skb->len);
+
+ vcc->push(vcc, skb);
+
+ atomic_inc(&vcc->stats->rx);
+ out:
+ skb_trim(sarb, 0);
+ }
+ }
+}
+
+
+/*************
+** encode **
+*************/
+
+static unsigned int usbatm_write_cells(struct usbatm_data *instance,
+ struct sk_buff *skb,
+ u8 *target, unsigned int avail_space)
+{
+ struct usbatm_control *ctrl = UDSL_SKB(skb);
+ struct atm_vcc *vcc = ctrl->atm.vcc;
+ unsigned int num_written;
+ unsigned int stride = instance->tx_channel.stride;
+
+ vdbg("%s: skb->len=%d, avail_space=%u", __func__, skb->len, avail_space);
+ UDSL_ASSERT(!(avail_space % stride));
+
+ for (num_written = 0; num_written < avail_space && ctrl->len;
+ num_written += stride, target += stride) {
+ unsigned int data_len = min_t(unsigned int, skb->len, ATM_CELL_PAYLOAD);
+ unsigned int left = ATM_CELL_PAYLOAD - data_len;
+ u8 *ptr = target;
+
+ ptr[0] = vcc->vpi >> 4;
+ ptr[1] = (vcc->vpi << 4) | (vcc->vci >> 12);
+ ptr[2] = vcc->vci >> 4;
+ ptr[3] = vcc->vci << 4;
+ ptr[4] = 0xec;
+ ptr += ATM_CELL_HEADER;
+
+ memcpy(ptr, skb->data, data_len);
+ ptr += data_len;
+ __skb_pull(skb, data_len);
+
+ if(!left)
+ continue;
+
+ memset(ptr, 0, left);
+
+ if (left >= ATM_AAL5_TRAILER) { /* trailer will go in this cell */
+ u8 *trailer = target + ATM_CELL_SIZE - ATM_AAL5_TRAILER;
+ /* trailer[0] = 0; UU = 0 */
+ /* trailer[1] = 0; CPI = 0 */
+ trailer[2] = ctrl->len >> 8;
+ trailer[3] = ctrl->len;
+
+ ctrl->crc = ~ crc32_be(ctrl->crc, ptr, left - 4);
+
+ trailer[4] = ctrl->crc >> 24;
+ trailer[5] = ctrl->crc >> 16;
+ trailer[6] = ctrl->crc >> 8;
+ trailer[7] = ctrl->crc;
+
+ target[3] |= 0x2; /* adjust PTI */
+
+ ctrl->len = 0; /* tag this skb finished */
+ }
+ else
+ ctrl->crc = crc32_be(ctrl->crc, ptr, left);
+ }
+
+ return num_written;
+}
+
+
+/**************
+** receive **
+**************/
+
+static void usbatm_rx_process(unsigned long data)
+{
+ struct usbatm_data *instance = (struct usbatm_data *)data;
+ struct urb *urb;
+
+ while ((urb = usbatm_pop_urb(&instance->rx_channel))) {
+ vdbg("%s: processing urb 0x%p", __func__, urb);
+
+ if (usb_pipeisoc(urb->pipe)) {
+ int i;
+ for (i = 0; i < urb->number_of_packets; i++)
+ if (!urb->iso_frame_desc[i].status)
+ usbatm_extract_cells(instance,
+ (u8 *)urb->transfer_buffer + urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+ else
+ if (!urb->status)
+ usbatm_extract_cells(instance, urb->transfer_buffer, urb->actual_length);
+
+ if (usbatm_submit_urb(urb))
+ return;
+ }
+}
+
+
+/***********
+** send **
+***********/
+
+static void usbatm_tx_process(unsigned long data)
+{
+ struct usbatm_data *instance = (struct usbatm_data *)data;
+ struct sk_buff *skb = instance->current_skb;
+ struct urb *urb = NULL;
+ const unsigned int buf_size = instance->tx_channel.buf_size;
+ unsigned int num_written = 0;
+ u8 *buffer = NULL;
+
+ if (!skb)
+ skb = skb_dequeue(&instance->sndqueue);
+
+ while (skb) {
+ if (!urb) {
+ urb = usbatm_pop_urb(&instance->tx_channel);
+ if (!urb)
+ break; /* no more senders */
+ buffer = urb->transfer_buffer;
+ num_written = (urb->status == -EAGAIN) ?
+ urb->transfer_buffer_length : 0;
+ }
+
+ num_written += usbatm_write_cells(instance, skb,
+ buffer + num_written,
+ buf_size - num_written);
+
+ vdbg("%s: wrote %u bytes from skb 0x%p to urb 0x%p",
+ __func__, num_written, skb, urb);
+
+ if (!UDSL_SKB(skb)->len) {
+ struct atm_vcc *vcc = UDSL_SKB(skb)->atm.vcc;
+
+ usbatm_pop(vcc, skb);
+ atomic_inc(&vcc->stats->tx);
+
+ skb = skb_dequeue(&instance->sndqueue);
+ }
+
+ if (num_written == buf_size || (!skb && num_written)) {
+ urb->transfer_buffer_length = num_written;
+
+ if (usbatm_submit_urb(urb))
+ break;
+ urb = NULL;
+ }
+ }
+
+ instance->current_skb = skb;
+}
+
+static void usbatm_cancel_send(struct usbatm_data *instance,
+ struct atm_vcc *vcc)
+{
+ struct sk_buff *skb, *n;
+
+ atm_dbg(instance, "%s entered\n", __func__);
+ spin_lock_irq(&instance->sndqueue.lock);
+ for (skb = instance->sndqueue.next, n = skb->next;
+ skb != (struct sk_buff *)&instance->sndqueue;
+ skb = n, n = skb->next)
+ if (UDSL_SKB(skb)->atm.vcc == vcc) {
+ atm_dbg(instance, "%s: popping skb 0x%p\n", __func__, skb);
+ __skb_unlink(skb, &instance->sndqueue);
+ usbatm_pop(vcc, skb);
+ }
+ spin_unlock_irq(&instance->sndqueue.lock);
+
+ tasklet_disable(&instance->tx_channel.tasklet);
+ if ((skb = instance->current_skb) && (UDSL_SKB(skb)->atm.vcc == vcc)) {
+ atm_dbg(instance, "%s: popping current skb (0x%p)\n", __func__, skb);
+ instance->current_skb = NULL;
+ usbatm_pop(vcc, skb);
+ }
+ tasklet_enable(&instance->tx_channel.tasklet);
+ atm_dbg(instance, "%s done\n", __func__);
+}
+
+static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+ struct usbatm_data *instance = vcc->dev->dev_data;
+ struct usbatm_control *ctrl = UDSL_SKB(skb);
+ int err;
+
+ vdbg("%s called (skb 0x%p, len %u)", __func__, skb, skb->len);
+
+ if (!instance) {
+ dbg("%s: NULL data!", __func__);
+ err = -ENODEV;
+ goto fail;
+ }
+
+ if (vcc->qos.aal != ATM_AAL5) {
+ atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+ err = -EINVAL;
+ goto fail;
+ }
+
+ if (skb->len > ATM_MAX_AAL5_PDU) {
+ atm_dbg(instance, "%s: packet too long (%d vs %d)!\n",
+ __func__, skb->len, ATM_MAX_AAL5_PDU);
+ err = -EINVAL;
+ goto fail;
+ }
+
+ PACKETDEBUG(skb->data, skb->len);
+
+ /* initialize the control block */
+ ctrl->atm.vcc = vcc;
+ ctrl->len = skb->len;
+ ctrl->crc = crc32_be(~0, skb->data, skb->len);
+
+ skb_queue_tail(&instance->sndqueue, skb);
+ tasklet_schedule(&instance->tx_channel.tasklet);
+
+ return 0;
+
+ fail:
+ usbatm_pop(vcc, skb);
+ return err;
+}
+
+
+/********************
+** bean counting **
+********************/
+
+static void usbatm_destroy_instance(struct kref *kref)
+{
+ struct usbatm_data *instance = container_of(kref, struct usbatm_data, refcount);
+
+ dbg("%s", __func__);
+
+ tasklet_kill(&instance->rx_channel.tasklet);
+ tasklet_kill(&instance->tx_channel.tasklet);
+ usb_put_dev(instance->usb_dev);
+ kfree(instance);
+}
+
+void usbatm_get_instance(struct usbatm_data *instance)
+{
+ dbg("%s", __func__);
+
+ kref_get(&instance->refcount);
+}
+
+void usbatm_put_instance(struct usbatm_data *instance)
+{
+ dbg("%s", __func__);
+
+ kref_put(&instance->refcount, usbatm_destroy_instance);
+}
+
+
+/**********
+** ATM **
+**********/
+
+static void usbatm_atm_dev_close(struct atm_dev *dev)
+{
+ struct usbatm_data *instance = dev->dev_data;
+
+ dbg("%s", __func__);
+
+ if (!instance)
+ return;
+
+ dev->dev_data = NULL;
+ usbatm_put_instance(instance); /* taken in usbatm_atm_init */
+}
+
+static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *page)
+{
+ struct usbatm_data *instance = atm_dev->dev_data;
+ int left = *pos;
+
+ if (!instance) {
+ dbg("%s: NULL instance!", __func__);
+ return -ENODEV;
+ }
+
+ if (!left--)
+ return sprintf(page, "%s\n", instance->description);
+
+ if (!left--)
+ return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ atm_dev->esi[0], atm_dev->esi[1],
+ atm_dev->esi[2], atm_dev->esi[3],
+ atm_dev->esi[4], atm_dev->esi[5]);
+
+ if (!left--)
+ return sprintf(page,
+ "AAL5: tx %d ( %d err ), rx %d ( %d err, %d drop )\n",
+ atomic_read(&atm_dev->stats.aal5.tx),
+ atomic_read(&atm_dev->stats.aal5.tx_err),
+ atomic_read(&atm_dev->stats.aal5.rx),
+ atomic_read(&atm_dev->stats.aal5.rx_err),
+ atomic_read(&atm_dev->stats.aal5.rx_drop));
+
+ if (!left--)
+ switch (atm_dev->signal) {
+ case ATM_PHY_SIG_FOUND:
+ return sprintf(page, "Line up\n");
+ case ATM_PHY_SIG_LOST:
+ return sprintf(page, "Line down\n");
+ default:
+ return sprintf(page, "Line state unknown\n");
+ }
+
+ return 0;
+}
+
+static int usbatm_atm_open(struct atm_vcc *vcc)
+{
+ struct usbatm_data *instance = vcc->dev->dev_data;
+ struct usbatm_vcc_data *new = NULL;
+ int ret;
+ int vci = vcc->vci;
+ short vpi = vcc->vpi;
+
+ if (!instance) {
+ dbg("%s: NULL data!", __func__);
+ return -ENODEV;
+ }
+
+ atm_dbg(instance, "%s: vpi %hd, vci %d\n", __func__, vpi, vci);
+
+ /* only support AAL5 */
+ if ((vcc->qos.aal != ATM_AAL5) || (vcc->qos.rxtp.max_sdu < 0)
+ || (vcc->qos.rxtp.max_sdu > ATM_MAX_AAL5_PDU)) {
+ atm_dbg(instance, "%s: unsupported ATM type %d!\n", __func__, vcc->qos.aal);
+ return -EINVAL;
+ }
+
+ down(&instance->serialize); /* vs self, usbatm_atm_close */
+
+ if (usbatm_find_vcc(instance, vpi, vci)) {
+ atm_dbg(instance, "%s: %hd/%d already in use!\n", __func__, vpi, vci);
+ ret = -EADDRINUSE;
+ goto fail;
+ }
+
+ if (!(new = kmalloc(sizeof(struct usbatm_vcc_data), GFP_KERNEL))) {
+ atm_dbg(instance, "%s: no memory for vcc_data!\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ memset(new, 0, sizeof(struct usbatm_vcc_data));
+ new->vcc = vcc;
+ new->vpi = vpi;
+ new->vci = vci;
+
+ new->sarb = alloc_skb(usbatm_pdu_length(vcc->qos.rxtp.max_sdu), GFP_KERNEL);
+ if (!new->sarb) {
+ atm_dbg(instance, "%s: no memory for SAR buffer!\n", __func__);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ vcc->dev_data = new;
+
+ tasklet_disable(&instance->rx_channel.tasklet);
+ list_add(&new->list, &instance->vcc_list);
+ tasklet_enable(&instance->rx_channel.tasklet);
+
+ set_bit(ATM_VF_ADDR, &vcc->flags);
+ set_bit(ATM_VF_PARTIAL, &vcc->flags);
+ set_bit(ATM_VF_READY, &vcc->flags);
+
+ up(&instance->serialize);
+
+ atm_dbg(instance, "%s: allocated vcc data 0x%p\n", __func__, new);
+
+ return 0;
+
+fail:
+ kfree(new);
+ up(&instance->serialize);
+ return ret;
+}
+
+static void usbatm_atm_close(struct atm_vcc *vcc)
+{
+ struct usbatm_data *instance = vcc->dev->dev_data;
+ struct usbatm_vcc_data *vcc_data = vcc->dev_data;
+
+ if (!instance || !vcc_data) {
+ dbg("%s: NULL data!", __func__);
+ return;
+ }
+
+ atm_dbg(instance, "%s entered\n", __func__);
+
+ atm_dbg(instance, "%s: deallocating vcc 0x%p with vpi %d vci %d\n",
+ __func__, vcc_data, vcc_data->vpi, vcc_data->vci);
+
+ usbatm_cancel_send(instance, vcc);
+
+ down(&instance->serialize); /* vs self, usbatm_atm_open */
+
+ tasklet_disable(&instance->rx_channel.tasklet);
+ list_del(&vcc_data->list);
+ tasklet_enable(&instance->rx_channel.tasklet);
+
+ kfree_skb(vcc_data->sarb);
+ vcc_data->sarb = NULL;
+
+ kfree(vcc_data);
+ vcc->dev_data = NULL;
+
+ vcc->vpi = ATM_VPI_UNSPEC;
+ vcc->vci = ATM_VCI_UNSPEC;
+ clear_bit(ATM_VF_READY, &vcc->flags);
+ clear_bit(ATM_VF_PARTIAL, &vcc->flags);
+ clear_bit(ATM_VF_ADDR, &vcc->flags);
+
+ up(&instance->serialize);
+
+ atm_dbg(instance, "%s successful\n", __func__);
+}
+
+static int usbatm_atm_ioctl(struct atm_dev *dev, unsigned int cmd,
+ void __user * arg)
+{
+ switch (cmd) {
+ case ATM_QUERYLOOP:
+ return put_user(ATM_LM_NONE, (int __user *)arg) ? -EFAULT : 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+static int usbatm_atm_init(struct usbatm_data *instance)
+{
+ struct atm_dev *atm_dev;
+ int ret, i;
+
+ /* ATM init */
+ atm_dev = atm_dev_register(instance->driver_name, &usbatm_atm_devops, -1, NULL);
+ if (!atm_dev) {
+ usb_dbg(instance, "%s: failed to register ATM device!\n", __func__);
+ return -1;
+ }
+
+ instance->atm_dev = atm_dev;
+
+ atm_dev->ci_range.vpi_bits = ATM_CI_MAX;
+ atm_dev->ci_range.vci_bits = ATM_CI_MAX;
+ atm_dev->signal = ATM_PHY_SIG_UNKNOWN;
+
+ /* temp init ATM device, set to 128kbit */
+ atm_dev->link_rate = 128 * 1000 / 424;
+
+ if (instance->driver->atm_start && ((ret = instance->driver->atm_start(instance, atm_dev)) < 0)) {
+ atm_dbg(instance, "%s: atm_start failed: %d!\n", __func__, ret);
+ goto fail;
+ }
+
+ /* ready for ATM callbacks */
+ usbatm_get_instance(instance); /* dropped in usbatm_atm_dev_close */
+ mb();
+ atm_dev->dev_data = instance;
+
+ /* submit all rx URBs */
+ for (i = 0; i < num_rcv_urbs; i++)
+ usbatm_submit_urb(instance->urbs[i]);
+
+ return 0;
+
+ fail:
+ instance->atm_dev = NULL;
+ shutdown_atm_dev(atm_dev); /* usbatm_atm_dev_close will eventually be called */
+ return ret;
+}
+
+
+/**********
+** USB **
+**********/
+
+static int usbatm_do_heavy_init(void *arg)
+{
+ struct usbatm_data *instance = arg;
+ int ret;
+
+ daemonize(instance->driver->driver_name);
+ allow_signal(SIGTERM);
+
+ complete(&instance->thread_started);
+
+ ret = instance->driver->heavy_init(instance, instance->usb_intf);
+
+ if (!ret)
+ ret = usbatm_atm_init(instance);
+
+ down(&instance->serialize);
+ instance->thread_pid = -1;
+ up(&instance->serialize);
+
+ complete_and_exit(&instance->thread_exited, ret);
+}
+
+static int usbatm_heavy_init(struct usbatm_data *instance)
+{
+ int ret = kernel_thread(usbatm_do_heavy_init, instance, CLONE_KERNEL);
+
+ if (ret < 0) {
+ usb_dbg(instance, "%s: failed to create kernel_thread (%d)!\n", __func__, ret);
+ return ret;
+ }
+
+ down(&instance->serialize);
+ instance->thread_pid = ret;
+ up(&instance->serialize);
+
+ wait_for_completion(&instance->thread_started);
+
+ return 0;
+}
+
+static void usbatm_tasklet_schedule(unsigned long data)
+{
+ tasklet_schedule((struct tasklet_struct *) data);
+}
+
+static inline void usbatm_init_channel(struct usbatm_channel *channel)
+{
+ spin_lock_init(&channel->lock);
+ INIT_LIST_HEAD(&channel->list);
+ channel->delay.function = usbatm_tasklet_schedule;
+ channel->delay.data = (unsigned long) &channel->tasklet;
+ init_timer(&channel->delay);
+}
+
+int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+ struct usbatm_driver *driver)
+{
+ struct device *dev = &intf->dev;
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct usbatm_data *instance;
+ char *buf;
+ int error = -ENOMEM;
+ int i, length;
+ int need_heavy;
+
+ dev_dbg(dev, "%s: trying driver %s with vendor=0x%x, product=0x%x, ifnum %d\n",
+ __func__, driver->driver_name,
+ le16_to_cpu(usb_dev->descriptor.idVendor),
+ le16_to_cpu(usb_dev->descriptor.idProduct),
+ intf->altsetting->desc.bInterfaceNumber);
+
+ /* instance init */
+ instance = kcalloc(1, sizeof(*instance) + sizeof(struct urb *) * (num_rcv_urbs + num_snd_urbs), GFP_KERNEL);
+ if (!instance) {
+ dev_dbg(dev, "%s: no memory for instance data!\n", __func__);
+ return -ENOMEM;
+ }
+
+ /* public fields */
+
+ instance->driver = driver;
+ snprintf(instance->driver_name, sizeof(instance->driver_name), driver->driver_name);
+
+ instance->usb_dev = usb_dev;
+ instance->usb_intf = intf;
+
+ buf = instance->description;
+ length = sizeof(instance->description);
+
+ if ((i = usb_string(usb_dev, usb_dev->descriptor.iProduct, buf, length)) < 0)
+ goto bind;
+
+ buf += i;
+ length -= i;
+
+ i = scnprintf(buf, length, " (");
+ buf += i;
+ length -= i;
+
+ if (length <= 0 || (i = usb_make_path(usb_dev, buf, length)) < 0)
+ goto bind;
+
+ buf += i;
+ length -= i;
+
+ snprintf(buf, length, ")");
+
+ bind:
+ need_heavy = 1;
+ if (driver->bind && (error = driver->bind(instance, intf, id, &need_heavy)) < 0) {
+ dev_dbg(dev, "%s: bind failed: %d!\n", __func__, error);
+ goto fail_free;
+ }
+
+ /* private fields */
+
+ kref_init(&instance->refcount); /* dropped in usbatm_usb_disconnect */
+ init_MUTEX(&instance->serialize);
+
+ instance->thread_pid = -1;
+ init_completion(&instance->thread_started);
+ init_completion(&instance->thread_exited);
+
+ INIT_LIST_HEAD(&instance->vcc_list);
+
+ usbatm_init_channel(&instance->rx_channel);
+ usbatm_init_channel(&instance->tx_channel);
+ tasklet_init(&instance->rx_channel.tasklet, usbatm_rx_process, (unsigned long)instance);
+ tasklet_init(&instance->tx_channel.tasklet, usbatm_tx_process, (unsigned long)instance);
+ instance->rx_channel.endpoint = usb_rcvbulkpipe(usb_dev, driver->in);
+ instance->tx_channel.endpoint = usb_sndbulkpipe(usb_dev, driver->out);
+ instance->rx_channel.stride = ATM_CELL_SIZE + driver->rx_padding;
+ instance->tx_channel.stride = ATM_CELL_SIZE + driver->tx_padding;
+ instance->rx_channel.buf_size = rcv_buf_size * instance->rx_channel.stride;
+ instance->tx_channel.buf_size = snd_buf_size * instance->tx_channel.stride;
+ instance->rx_channel.usbatm = instance->tx_channel.usbatm = instance;
+
+ skb_queue_head_init(&instance->sndqueue);
+
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ struct urb *urb;
+ u8 *buffer;
+ unsigned int iso_packets = 0, iso_size = 0;
+ struct usbatm_channel *channel = i < num_rcv_urbs ?
+ &instance->rx_channel : &instance->tx_channel;
+
+ if (usb_pipeisoc(channel->endpoint)) {
+ /* don't expect iso out endpoints */
+ iso_size = usb_maxpacket(instance->usb_dev, channel->endpoint, 0);
+ iso_size -= iso_size % channel->stride; /* alignment */
+ BUG_ON(!iso_size);
+ iso_packets = (channel->buf_size - 1) / iso_size + 1;
+ }
+
+ urb = usb_alloc_urb(iso_packets, GFP_KERNEL);
+ if (!urb) {
+ dev_dbg(dev, "%s: no memory for urb %d!\n", __func__, i);
+ goto fail_unbind;
+ }
+
+ instance->urbs[i] = urb;
+
+ buffer = kmalloc(channel->buf_size, GFP_KERNEL);
+ if (!buffer) {
+ dev_dbg(dev, "%s: no memory for buffer %d!\n", __func__, i);
+ goto fail_unbind;
+ }
+ memset(buffer, 0, channel->buf_size);
+
+ usb_fill_bulk_urb(urb, instance->usb_dev, channel->endpoint,
+ buffer, channel->buf_size, usbatm_complete, channel);
+ if (iso_packets) {
+ int j;
+ urb->interval = 1;
+ urb->transfer_flags = URB_ISO_ASAP;
+ urb->number_of_packets = iso_packets;
+ for (j = 0; j < iso_packets; j++) {
+ urb->iso_frame_desc[j].offset = iso_size * j;
+ urb->iso_frame_desc[j].length = min_t(int, iso_size,
+ channel->buf_size - urb->iso_frame_desc[j].offset);
+ }
+ }
+
+ /* put all tx URBs on the list of spares */
+ if (i >= num_rcv_urbs)
+ list_add_tail(&urb->urb_list, &channel->list);
+
+ vdbg("%s: alloced buffer 0x%p buf size %u urb 0x%p",
+ __func__, urb->transfer_buffer, urb->transfer_buffer_length, urb);
+ }
+
+ if (need_heavy && driver->heavy_init) {
+ error = usbatm_heavy_init(instance);
+ } else {
+ complete(&instance->thread_exited); /* pretend that heavy_init was run */
+ error = usbatm_atm_init(instance);
+ }
+
+ if (error < 0)
+ goto fail_unbind;
+
+ usb_get_dev(usb_dev);
+ usb_set_intfdata(intf, instance);
+
+ return 0;
+
+ fail_unbind:
+ if (instance->driver->unbind)
+ instance->driver->unbind(instance, intf);
+ fail_free:
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ if (instance->urbs[i])
+ kfree(instance->urbs[i]->transfer_buffer);
+ usb_free_urb(instance->urbs[i]);
+ }
+
+ kfree (instance);
+
+ return error;
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_probe);
+
+void usbatm_usb_disconnect(struct usb_interface *intf)
+{
+ struct device *dev = &intf->dev;
+ struct usbatm_data *instance = usb_get_intfdata(intf);
+ int i;
+
+ dev_dbg(dev, "%s entered\n", __func__);
+
+ if (!instance) {
+ dev_dbg(dev, "%s: NULL instance!\n", __func__);
+ return;
+ }
+
+ usb_set_intfdata(intf, NULL);
+
+ down(&instance->serialize);
+ if (instance->thread_pid >= 0)
+ kill_proc(instance->thread_pid, SIGTERM, 1);
+ up(&instance->serialize);
+
+ wait_for_completion(&instance->thread_exited);
+
+ tasklet_disable(&instance->rx_channel.tasklet);
+ tasklet_disable(&instance->tx_channel.tasklet);
+
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++)
+ usb_kill_urb(instance->urbs[i]);
+
+ del_timer_sync(&instance->rx_channel.delay);
+ del_timer_sync(&instance->tx_channel.delay);
+
+ if (instance->atm_dev && instance->driver->atm_stop)
+ instance->driver->atm_stop(instance, instance->atm_dev);
+
+ if (instance->driver->unbind)
+ instance->driver->unbind(instance, intf);
+
+ instance->driver_data = NULL;
+
+ /* turn usbatm_[rt]x_process into noop */
+ /* no need to take the spinlock */
+ INIT_LIST_HEAD(&instance->rx_channel.list);
+ INIT_LIST_HEAD(&instance->tx_channel.list);
+
+ tasklet_enable(&instance->rx_channel.tasklet);
+ tasklet_enable(&instance->tx_channel.tasklet);
+
+ for (i = 0; i < num_rcv_urbs + num_snd_urbs; i++) {
+ kfree(instance->urbs[i]->transfer_buffer);
+ usb_free_urb(instance->urbs[i]);
+ }
+
+ /* ATM finalize */
+ if (instance->atm_dev)
+ shutdown_atm_dev(instance->atm_dev);
+
+ usbatm_put_instance(instance); /* taken in usbatm_usb_probe */
+}
+EXPORT_SYMBOL_GPL(usbatm_usb_disconnect);
+
+
+/***********
+** init **
+***********/
+
+static int __init usbatm_usb_init(void)
+{
+ dbg("%s: driver version %s", __func__, DRIVER_VERSION);
+
+ if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
+ printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
+ return -EIO;
+ }
+
+ if ((num_rcv_urbs > UDSL_MAX_RCV_URBS)
+ || (num_snd_urbs > UDSL_MAX_SND_URBS)
+ || (rcv_buf_size < 1)
+ || (rcv_buf_size > UDSL_MAX_RCV_BUF_SIZE)
+ || (snd_buf_size < 1)
+ || (snd_buf_size > UDSL_MAX_SND_BUF_SIZE))
+ return -EINVAL;
+
+ return 0;
+}
+module_init(usbatm_usb_init);
+
+static void __exit usbatm_usb_exit(void)
+{
+ dbg("%s", __func__);
+}
+module_exit(usbatm_usb_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRIVER_VERSION);
+
+/************
+** debug **
+************/
+
+#ifdef VERBOSE_DEBUG
+static int usbatm_print_packet(const unsigned char *data, int len)
+{
+ unsigned char buffer[256];
+ int i = 0, j = 0;
+
+ for (i = 0; i < len;) {
+ buffer[0] = '\0';
+ sprintf(buffer, "%.3d :", i);
+ for (j = 0; (j < 16) && (i < len); j++, i++) {
+ sprintf(buffer, "%s %2.2x", buffer, data[i]);
+ }
+ dbg("%s", buffer);
+ }
+ return i;
+}
+#endif
diff --git a/drivers/usb/atm/usbatm.h b/drivers/usb/atm/usbatm.h
new file mode 100644
index 000000000000..936646457935
--- /dev/null
+++ b/drivers/usb/atm/usbatm.h
@@ -0,0 +1,184 @@
+/******************************************************************************
+ * usbatm.h - Generic USB xDSL driver core
+ *
+ * Copyright (C) 2001, Alcatel
+ * Copyright (C) 2003, Duncan Sands, SolNegro, Josep Comas
+ * Copyright (C) 2004, David Woodhouse
+ *
+ * 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 _USBATM_H_
+#define _USBATM_H_
+
+#include <linux/config.h>
+
+/*
+#define DEBUG
+#define VERBOSE_DEBUG
+*/
+
+#if !defined (DEBUG) && defined (CONFIG_USB_DEBUG)
+# define DEBUG
+#endif
+
+#include <asm/semaphore.h>
+#include <linux/atm.h>
+#include <linux/atmdev.h>
+#include <linux/completion.h>
+#include <linux/device.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/stringify.h>
+#include <linux/usb.h>
+
+#ifdef DEBUG
+#define UDSL_ASSERT(x) BUG_ON(!(x))
+#else
+#define UDSL_ASSERT(x) do { if (!(x)) warn("failed assertion '%s' at line %d", __stringify(x), __LINE__); } while(0)
+#endif
+
+#define usb_err(instance, format, arg...) \
+ dev_err(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_info(instance, format, arg...) \
+ dev_info(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_warn(instance, format, arg...) \
+ dev_warn(&(instance)->usb_intf->dev , format , ## arg)
+#define usb_dbg(instance, format, arg...) \
+ dev_dbg(&(instance)->usb_intf->dev , format , ## arg)
+
+/* FIXME: move to dev_* once ATM is driver model aware */
+#define atm_printk(level, instance, format, arg...) \
+ printk(level "ATM dev %d: " format , \
+ (instance)->atm_dev->number , ## arg)
+
+#define atm_err(instance, format, arg...) \
+ atm_printk(KERN_ERR, instance , format , ## arg)
+#define atm_info(instance, format, arg...) \
+ atm_printk(KERN_INFO, instance , format , ## arg)
+#define atm_warn(instance, format, arg...) \
+ atm_printk(KERN_WARNING, instance , format , ## arg)
+#ifdef DEBUG
+#define atm_dbg(instance, format, arg...) \
+ atm_printk(KERN_DEBUG, instance , format , ## arg)
+#else
+#define atm_dbg(instance, format, arg...) \
+ do {} while (0)
+#endif
+
+
+/* mini driver */
+
+struct usbatm_data;
+
+/*
+* Assuming all methods exist and succeed, they are called in this order:
+*
+* bind, heavy_init, atm_start, ..., atm_stop, unbind
+*/
+
+struct usbatm_driver {
+ struct module *owner;
+
+ const char *driver_name;
+
+ /*
+ * init device ... can sleep, or cause probe() failure. Drivers with a heavy_init
+ * method can avoid having it called by setting need_heavy_init to zero.
+ */
+ int (*bind) (struct usbatm_data *, struct usb_interface *,
+ const struct usb_device_id *id, int *need_heavy_init);
+
+ /* additional device initialization that is too slow to be done in probe() */
+ int (*heavy_init) (struct usbatm_data *, struct usb_interface *);
+
+ /* cleanup device ... can sleep, but can't fail */
+ void (*unbind) (struct usbatm_data *, struct usb_interface *);
+
+ /* init ATM device ... can sleep, or cause ATM initialization failure */
+ int (*atm_start) (struct usbatm_data *, struct atm_dev *);
+
+ /* cleanup ATM device ... can sleep, but can't fail */
+ void (*atm_stop) (struct usbatm_data *, struct atm_dev *);
+
+ int in; /* rx endpoint */
+ int out; /* tx endpoint */
+
+ unsigned rx_padding;
+ unsigned tx_padding;
+};
+
+extern int usbatm_usb_probe(struct usb_interface *intf, const struct usb_device_id *id,
+ struct usbatm_driver *driver);
+extern void usbatm_usb_disconnect(struct usb_interface *intf);
+
+
+struct usbatm_channel {
+ int endpoint; /* usb pipe */
+ unsigned int stride; /* ATM cell size + padding */
+ unsigned int buf_size; /* urb buffer size */
+ spinlock_t lock;
+ struct list_head list;
+ struct tasklet_struct tasklet;
+ struct timer_list delay;
+ struct usbatm_data *usbatm;
+};
+
+/* main driver data */
+
+struct usbatm_data {
+ /******************
+ * public fields *
+ ******************/
+
+ /* mini driver */
+ struct usbatm_driver *driver;
+ void *driver_data;
+ char driver_name[16];
+
+ /* USB device */
+ struct usb_device *usb_dev;
+ struct usb_interface *usb_intf;
+ char description[64];
+
+ /* ATM device */
+ struct atm_dev *atm_dev;
+
+ /********************************
+ * private fields - do not use *
+ ********************************/
+
+ struct kref refcount;
+ struct semaphore serialize;
+
+ /* heavy init */
+ int thread_pid;
+ struct completion thread_started;
+ struct completion thread_exited;
+
+ /* ATM device */
+ struct list_head vcc_list;
+
+ struct usbatm_channel rx_channel;
+ struct usbatm_channel tx_channel;
+
+ struct sk_buff_head sndqueue;
+ struct sk_buff *current_skb; /* being emptied */
+
+ struct urb *urbs[0];
+};
+
+#endif /* _USBATM_H_ */
diff --git a/drivers/usb/atm/xusbatm.c b/drivers/usb/atm/xusbatm.c
new file mode 100644
index 000000000000..7fe7fb484d10
--- /dev/null
+++ b/drivers/usb/atm/xusbatm.c
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * xusbatm.c - dumb usbatm-based driver for modems initialized in userspace
+ *
+ * Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
+ *
+ * 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 <linux/module.h>
+#include <linux/netdevice.h> /* FIXME: required by linux/etherdevice.h */
+#include <linux/etherdevice.h> /* for random_ether_addr() */
+
+#include "usbatm.h"
+
+
+#define XUSBATM_DRIVERS_MAX 8
+
+#define XUSBATM_PARM(name, type, parmtype, desc) \
+ static type name[XUSBATM_DRIVERS_MAX]; \
+ static int num_##name; \
+ module_param_array(name, parmtype, &num_##name, 0444); \
+ MODULE_PARM_DESC(name, desc)
+
+XUSBATM_PARM(vendor, unsigned short, ushort, "USB device vendor");
+XUSBATM_PARM(product, unsigned short, ushort, "USB device product");
+
+XUSBATM_PARM(rx_endpoint, unsigned char, byte, "rx endpoint number");
+XUSBATM_PARM(tx_endpoint, unsigned char, byte, "tx endpoint number");
+XUSBATM_PARM(rx_padding, unsigned char, byte, "rx padding (default 0)");
+XUSBATM_PARM(tx_padding, unsigned char, byte, "tx padding (default 0)");
+
+static const char xusbatm_driver_name[] = "xusbatm";
+
+static struct usbatm_driver xusbatm_drivers[XUSBATM_DRIVERS_MAX];
+static struct usb_device_id xusbatm_usb_ids[XUSBATM_DRIVERS_MAX + 1];
+static struct usb_driver xusbatm_usb_driver;
+
+static int usb_intf_has_ep(const struct usb_interface *intf, u8 ep)
+{
+ int i, j;
+
+ for (i = 0; i < intf->num_altsetting; i++) {
+ struct usb_host_interface *alt = intf->altsetting;
+ for (j = 0; j < alt->desc.bNumEndpoints; j++)
+ if ((alt->endpoint[i].desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) == ep)
+ return 1;
+ }
+ return 0;
+}
+
+static int xusbatm_bind(struct usbatm_data *usbatm_instance,
+ struct usb_interface *intf, const struct usb_device_id *id,
+ int *need_heavy_init)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ int drv_ix = id - xusbatm_usb_ids;
+ int rx_ep_present = usb_intf_has_ep(intf, rx_endpoint[drv_ix]);
+ int tx_ep_present = usb_intf_has_ep(intf, tx_endpoint[drv_ix]);
+ u8 searched_ep = rx_ep_present ? tx_endpoint[drv_ix] : rx_endpoint[drv_ix];
+ int i, ret;
+
+ usb_dbg(usbatm_instance, "%s: binding driver %d: vendor %#x product %#x"
+ " rx: ep %#x padd %d tx: ep %#x padd %d\n",
+ __func__, drv_ix, vendor[drv_ix], product[drv_ix],
+ rx_endpoint[drv_ix], rx_padding[drv_ix],
+ tx_endpoint[drv_ix], tx_padding[drv_ix]);
+
+ if (!rx_ep_present && !tx_ep_present) {
+ usb_dbg(usbatm_instance, "%s: intf #%d has neither rx (%#x) nor tx (%#x) endpoint\n",
+ __func__, intf->altsetting->desc.bInterfaceNumber,
+ rx_endpoint[drv_ix], tx_endpoint[drv_ix]);
+ return -ENODEV;
+ }
+
+ if (rx_ep_present && tx_ep_present)
+ return 0;
+
+ for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+
+ if (cur_if != intf && usb_intf_has_ep(cur_if, searched_ep)) {
+ ret = usb_driver_claim_interface(&xusbatm_usb_driver,
+ cur_if, usbatm_instance);
+ if (!ret)
+ usb_err(usbatm_instance, "%s: failed to claim interface #%d (%d)\n",
+ __func__, cur_if->altsetting->desc.bInterfaceNumber, ret);
+ return ret;
+ }
+ }
+
+ usb_err(usbatm_instance, "%s: no interface has endpoint %#x\n",
+ __func__, searched_ep);
+ return -ENODEV;
+}
+
+static void xusbatm_unbind(struct usbatm_data *usbatm_instance,
+ struct usb_interface *intf)
+{
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ int i;
+ usb_dbg(usbatm_instance, "%s entered\n", __func__);
+
+ for(i = 0; i < usb_dev->actconfig->desc.bNumInterfaces; i++) {
+ struct usb_interface *cur_if = usb_dev->actconfig->interface[i];
+ usb_set_intfdata(cur_if, NULL);
+ usb_driver_release_interface(&xusbatm_usb_driver, cur_if);
+ }
+}
+
+static int xusbatm_atm_start(struct usbatm_data *usbatm_instance,
+ struct atm_dev *atm_dev)
+{
+ atm_dbg(usbatm_instance, "%s entered\n", __func__);
+
+ /* use random MAC as we've no way to get it from the device */
+ random_ether_addr(atm_dev->esi);
+
+ return 0;
+}
+
+
+static int xusbatm_usb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return usbatm_usb_probe(intf, id,
+ xusbatm_drivers + (id - xusbatm_usb_ids));
+}
+
+static struct usb_driver xusbatm_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = xusbatm_driver_name,
+ .probe = xusbatm_usb_probe,
+ .disconnect = usbatm_usb_disconnect,
+ .id_table = xusbatm_usb_ids
+};
+
+static int __init xusbatm_init(void)
+{
+ int i;
+
+ dbg("xusbatm_init");
+
+ if (!num_vendor ||
+ num_vendor != num_product ||
+ num_vendor != num_rx_endpoint ||
+ num_vendor != num_tx_endpoint) {
+ warn("malformed module parameters");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < num_vendor; i++) {
+ xusbatm_usb_ids[i].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+ xusbatm_usb_ids[i].idVendor = vendor[i];
+ xusbatm_usb_ids[i].idProduct = product[i];
+
+
+ xusbatm_drivers[i].owner = THIS_MODULE;
+ xusbatm_drivers[i].driver_name = xusbatm_driver_name;
+ xusbatm_drivers[i].bind = xusbatm_bind;
+ xusbatm_drivers[i].unbind = xusbatm_unbind;
+ xusbatm_drivers[i].atm_start = xusbatm_atm_start;
+ xusbatm_drivers[i].in = rx_endpoint[i];
+ xusbatm_drivers[i].out = tx_endpoint[i];
+ xusbatm_drivers[i].rx_padding = rx_padding[i];
+ xusbatm_drivers[i].tx_padding = tx_padding[i];
+ }
+
+ return usb_register(&xusbatm_usb_driver);
+}
+module_init(xusbatm_init);
+
+static void __exit xusbatm_exit(void)
+{
+ dbg("xusbatm_exit entered");
+
+ usb_deregister(&xusbatm_usb_driver);
+}
+module_exit(xusbatm_exit);
+
+MODULE_AUTHOR("Roman Kagan, Duncan Sands");
+MODULE_DESCRIPTION("Driver for USB ADSL modems initialized in userspace");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 6d1f9b6aecff..adff5a77e31f 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -106,6 +106,111 @@ static int acm_ctrl_msg(struct acm *acm, int request, int value, void *buf, int
acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)
/*
+ * Write buffer management.
+ * All of these assume proper locks taken by the caller.
+ */
+
+static int acm_wb_alloc(struct acm *acm)
+{
+ int i, wbn;
+ struct acm_wb *wb;
+
+ wbn = acm->write_current;
+ i = 0;
+ for (;;) {
+ wb = &acm->wb[wbn];
+ if (!wb->use) {
+ wb->use = 1;
+ return wbn;
+ }
+ wbn = (wbn + 1) % ACM_NWB;
+ if (++i >= ACM_NWB)
+ return -1;
+ }
+}
+
+static void acm_wb_free(struct acm *acm, int wbn)
+{
+ acm->wb[wbn].use = 0;
+}
+
+static int acm_wb_is_avail(struct acm *acm)
+{
+ int i, n;
+
+ n = 0;
+ for (i = 0; i < ACM_NWB; i++) {
+ if (!acm->wb[i].use)
+ n++;
+ }
+ return n;
+}
+
+static inline int acm_wb_is_used(struct acm *acm, int wbn)
+{
+ return acm->wb[wbn].use;
+}
+
+/*
+ * Finish write.
+ */
+static void acm_write_done(struct acm *acm)
+{
+ unsigned long flags;
+ int wbn;
+
+ spin_lock_irqsave(&acm->write_lock, flags);
+ acm->write_ready = 1;
+ wbn = acm->write_current;
+ acm_wb_free(acm, wbn);
+ acm->write_current = (wbn + 1) % ACM_NWB;
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+}
+
+/*
+ * Poke write.
+ */
+static int acm_write_start(struct acm *acm)
+{
+ unsigned long flags;
+ int wbn;
+ struct acm_wb *wb;
+ int rc;
+
+ spin_lock_irqsave(&acm->write_lock, flags);
+ if (!acm->dev) {
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ return -ENODEV;
+ }
+
+ if (!acm->write_ready) {
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ return 0; /* A white lie */
+ }
+
+ wbn = acm->write_current;
+ if (!acm_wb_is_used(acm, wbn)) {
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ return 0;
+ }
+ wb = &acm->wb[wbn];
+
+ acm->write_ready = 0;
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+
+ acm->writeurb->transfer_buffer = wb->buf;
+ acm->writeurb->transfer_dma = wb->dmah;
+ acm->writeurb->transfer_buffer_length = wb->len;
+ acm->writeurb->dev = acm->dev;
+
+ if ((rc = usb_submit_urb(acm->writeurb, GFP_ATOMIC)) < 0) {
+ dbg("usb_submit_urb(write bulk) failed: %d", rc);
+ acm_write_done(acm);
+ }
+ return rc;
+}
+
+/*
* Interrupt handlers for various ACM device responses
*/
@@ -237,17 +342,13 @@ static void acm_rx_tasklet(unsigned long _acm)
static void acm_write_bulk(struct urb *urb, struct pt_regs *regs)
{
struct acm *acm = (struct acm *)urb->context;
- dbg("Entering acm_write_bulk with status %d\n", urb->status);
-
- if (!ACM_READY(acm))
- goto out;
- if (urb->status)
- dbg("nonzero write bulk status received: %d", urb->status);
+ dbg("Entering acm_write_bulk with status %d\n", urb->status);
- schedule_work(&acm->work);
-out:
- acm->ready_for_write = 1;
+ acm_write_done(acm);
+ acm_write_start(acm);
+ if (ACM_READY(acm))
+ schedule_work(&acm->work);
}
static void acm_softint(void *private)
@@ -321,6 +422,17 @@ bail_out:
return -EIO;
}
+static void acm_tty_unregister(struct acm *acm)
+{
+ tty_unregister_device(acm_tty_driver, acm->minor);
+ usb_put_intf(acm->control);
+ acm_table[acm->minor] = NULL;
+ usb_free_urb(acm->ctrlurb);
+ usb_free_urb(acm->readurb);
+ usb_free_urb(acm->writeurb);
+ kfree(acm);
+}
+
static void acm_tty_close(struct tty_struct *tty, struct file *filp)
{
struct acm *acm = tty->driver_data;
@@ -335,14 +447,8 @@ static void acm_tty_close(struct tty_struct *tty, struct file *filp)
usb_kill_urb(acm->ctrlurb);
usb_kill_urb(acm->writeurb);
usb_kill_urb(acm->readurb);
- } else {
- tty_unregister_device(acm_tty_driver, acm->minor);
- acm_table[acm->minor] = NULL;
- usb_free_urb(acm->ctrlurb);
- usb_free_urb(acm->readurb);
- usb_free_urb(acm->writeurb);
- kfree(acm);
- }
+ } else
+ acm_tty_unregister(acm);
}
up(&open_sem);
}
@@ -351,32 +457,33 @@ static int acm_tty_write(struct tty_struct *tty, const unsigned char *buf, int c
{
struct acm *acm = tty->driver_data;
int stat;
+ unsigned long flags;
+ int wbn;
+ struct acm_wb *wb;
+
dbg("Entering acm_tty_write to write %d bytes,\n", count);
if (!ACM_READY(acm))
return -EINVAL;
- if (!acm->ready_for_write)
- return 0;
if (!count)
return 0;
- count = (count > acm->writesize) ? acm->writesize : count;
+ spin_lock_irqsave(&acm->write_lock, flags);
+ if ((wbn = acm_wb_alloc(acm)) < 0) {
+ spin_unlock_irqrestore(&acm->write_lock, flags);
+ acm_write_start(acm);
+ return 0;
+ }
+ wb = &acm->wb[wbn];
+ count = (count > acm->writesize) ? acm->writesize : count;
dbg("Get %d bytes...", count);
- memcpy(acm->write_buffer, buf, count);
- dbg(" Successfully copied.\n");
+ memcpy(wb->buf, buf, count);
+ wb->len = count;
+ spin_unlock_irqrestore(&acm->write_lock, flags);
- acm->writeurb->transfer_buffer_length = count;
- acm->writeurb->dev = acm->dev;
-
- acm->ready_for_write = 0;
- stat = usb_submit_urb(acm->writeurb, GFP_ATOMIC);
- if (stat < 0) {
- dbg("usb_submit_urb(write bulk) failed");
- acm->ready_for_write = 1;
+ if ((stat = acm_write_start(acm)) < 0)
return stat;
- }
-
return count;
}
@@ -385,7 +492,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
- return !acm->ready_for_write ? 0 : acm->writesize;
+ /*
+ * Do not let the line discipline to know that we have a reserve,
+ * or it might get too enthusiastic.
+ */
+ return (acm->write_ready && acm_wb_is_avail(acm)) ? acm->writesize : 0;
}
static int acm_tty_chars_in_buffer(struct tty_struct *tty)
@@ -393,7 +504,10 @@ static int acm_tty_chars_in_buffer(struct tty_struct *tty)
struct acm *acm = tty->driver_data;
if (!ACM_READY(acm))
return -EINVAL;
- return !acm->ready_for_write ? acm->writeurb->transfer_buffer_length : 0;
+ /*
+ * This is inaccurate (overcounts), but it works.
+ */
+ return (ACM_NWB - acm_wb_is_avail(acm)) * acm->writesize;
}
static void acm_tty_throttle(struct tty_struct *tty)
@@ -526,6 +640,39 @@ static void acm_tty_set_termios(struct tty_struct *tty, struct termios *termios_
* USB probe and disconnect routines.
*/
+/* Little helper: write buffers free */
+static void acm_write_buffers_free(struct acm *acm)
+{
+ int i;
+ struct acm_wb *wb;
+
+ for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+ usb_buffer_free(acm->dev, acm->writesize, wb->buf, wb->dmah);
+ }
+}
+
+/* Little helper: write buffers allocate */
+static int acm_write_buffers_alloc(struct acm *acm)
+{
+ int i;
+ struct acm_wb *wb;
+
+ for (wb = &acm->wb[0], i = 0; i < ACM_NWB; i++, wb++) {
+ wb->buf = usb_buffer_alloc(acm->dev, acm->writesize, GFP_KERNEL,
+ &wb->dmah);
+ if (!wb->buf) {
+ while (i != 0) {
+ --i;
+ --wb;
+ usb_buffer_free(acm->dev, acm->writesize,
+ wb->buf, wb->dmah);
+ }
+ return -ENOMEM;
+ }
+ }
+ return 0;
+}
+
static int acm_probe (struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -700,7 +847,8 @@ skip_normal_probe:
acm->bh.data = (unsigned long) acm;
INIT_WORK(&acm->work, acm_softint, acm);
spin_lock_init(&acm->throttle_lock);
- acm->ready_for_write = 1;
+ spin_lock_init(&acm->write_lock);
+ acm->write_ready = 1;
buf = usb_buffer_alloc(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
if (!buf) {
@@ -716,12 +864,10 @@ skip_normal_probe:
}
acm->read_buffer = buf;
- buf = usb_buffer_alloc(usb_dev, acm->writesize, GFP_KERNEL, &acm->write_dma);
- if (!buf) {
+ if (acm_write_buffers_alloc(acm) < 0) {
dev_dbg(&intf->dev, "out of memory (write buffer alloc)\n");
goto alloc_fail4;
}
- acm->write_buffer = buf;
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
if (!acm->ctrlurb) {
@@ -750,9 +896,9 @@ skip_normal_probe:
acm->readurb->transfer_dma = acm->read_dma;
usb_fill_bulk_urb(acm->writeurb, usb_dev, usb_sndbulkpipe(usb_dev, epwrite->bEndpointAddress),
- acm->write_buffer, acm->writesize, acm_write_bulk, acm);
+ NULL, acm->writesize, acm_write_bulk, acm);
acm->writeurb->transfer_flags |= URB_NO_FSBR | URB_NO_TRANSFER_DMA_MAP;
- acm->writeurb->transfer_dma = acm->write_dma;
+ /* acm->writeurb->transfer_dma = 0; */
dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);
@@ -764,7 +910,8 @@ skip_normal_probe:
usb_driver_claim_interface(&acm_driver, data_interface, acm);
- tty_register_device(acm_tty_driver, minor, &intf->dev);
+ usb_get_intf(control_interface);
+ tty_register_device(acm_tty_driver, minor, &control_interface->dev);
acm_table[minor] = acm;
usb_set_intfdata (intf, acm);
@@ -775,7 +922,7 @@ alloc_fail7:
alloc_fail6:
usb_free_urb(acm->ctrlurb);
alloc_fail5:
- usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+ acm_write_buffers_free(acm);
alloc_fail4:
usb_buffer_free(usb_dev, readsize, acm->read_buffer, acm->read_dma);
alloc_fail3:
@@ -806,19 +953,14 @@ static void acm_disconnect(struct usb_interface *intf)
flush_scheduled_work(); /* wait for acm_softint */
- usb_buffer_free(usb_dev, acm->writesize, acm->write_buffer, acm->write_dma);
+ acm_write_buffers_free(acm);
usb_buffer_free(usb_dev, acm->readsize, acm->read_buffer, acm->read_dma);
usb_buffer_free(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
usb_driver_release_interface(&acm_driver, acm->data);
if (!acm->used) {
- tty_unregister_device(acm_tty_driver, acm->minor);
- acm_table[acm->minor] = NULL;
- usb_free_urb(acm->ctrlurb);
- usb_free_urb(acm->readurb);
- usb_free_urb(acm->writeurb);
- kfree(acm);
+ acm_tty_unregister(acm);
up(&open_sem);
return;
}
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index 9009114e311b..963a5dfd2096 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -51,14 +51,34 @@
* Internal driver structures.
*/
+/*
+ * The only reason to have several buffers is to accomodate assumptions
+ * in line disciplines. They ask for empty space amount, receive our URB size,
+ * and proceed to issue several 1-character writes, assuming they will fit.
+ * The very first write takes a complete URB. Fortunately, this only happens
+ * when processing onlcr, so we only need 2 buffers.
+ */
+#define ACM_NWB 2
+struct acm_wb {
+ unsigned char *buf;
+ dma_addr_t dmah;
+ int len;
+ int use;
+};
+
struct acm {
struct usb_device *dev; /* the corresponding usb device */
struct usb_interface *control; /* control interface */
struct usb_interface *data; /* data interface */
struct tty_struct *tty; /* the corresponding tty */
struct urb *ctrlurb, *readurb, *writeurb; /* urbs */
- u8 *ctrl_buffer, *read_buffer, *write_buffer; /* buffers of urbs */
- dma_addr_t ctrl_dma, read_dma, write_dma; /* dma handles of buffers */
+ u8 *ctrl_buffer, *read_buffer; /* buffers of urbs */
+ dma_addr_t ctrl_dma, read_dma; /* dma handles of buffers */
+ struct acm_wb wb[ACM_NWB];
+ int write_current; /* current write buffer */
+ int write_used; /* number of non-empty write buffers */
+ int write_ready; /* write urb is not running */
+ spinlock_t write_lock;
struct usb_cdc_line_coding line; /* bits, stop, parity */
struct work_struct work; /* work queue entry for line discipline waking up */
struct tasklet_struct bh; /* rx processing */
@@ -71,7 +91,6 @@ struct acm {
unsigned int minor; /* acm minor number */
unsigned char throttle; /* throttled by tty layer */
unsigned char clocal; /* termios CLOCAL */
- unsigned char ready_for_write; /* write urb can be used */
unsigned char resubmit_to_unthrottle; /* throtteling has disabled the read urb */
unsigned int ctrl_caps; /* control capabilities from the class specific header */
};
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index bba22e97ea0f..7ce43fb8118a 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -379,6 +379,8 @@ static int usblp_open(struct inode *inode, struct file *file)
usblp->writeurb->transfer_buffer_length = 0;
usblp->wcomplete = 1; /* we begin writeable */
usblp->rcomplete = 0;
+ usblp->writeurb->status = 0;
+ usblp->readurb->status = 0;
if (usblp->bidir) {
usblp->readcount = 0;
@@ -751,6 +753,7 @@ static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count,
schedule();
} else {
set_current_state(TASK_RUNNING);
+ down(&usblp->sem);
break;
}
down (&usblp->sem);
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index b7827df21f48..fc15b4acc8af 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -106,7 +106,7 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
void *hcd_buffer_alloc (
struct usb_bus *bus,
size_t size,
- int mem_flags,
+ unsigned mem_flags,
dma_addr_t *dma
)
{
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 6bfab4bcaa9e..787c27a63c51 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -784,16 +784,16 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
for (i = 0; i < actconfig->desc.bNumInterfaces; ++i) {
if (usb_interface_claimed(actconfig->interface[i])) {
dev_warn (&ps->dev->dev,
- "usbfs: interface %d claimed "
+ "usbfs: interface %d claimed by %s "
"while '%s' sets config #%d\n",
actconfig->interface[i]
->cur_altsetting
->desc.bInterfaceNumber,
+ actconfig->interface[i]
+ ->dev.driver->name,
current->comm, u);
-#if 0 /* FIXME: enable in 2.6.10 or so */
status = -EBUSY;
break;
-#endif
}
}
}
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 71b4a8d66318..fc056062c960 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -380,6 +380,7 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
usb_hc_died (hcd);
}
+ pci_enable_device(dev);
return retval;
}
EXPORT_SYMBOL (usb_hcd_pci_resume);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 0da23732e807..8616356f55e8 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -519,119 +519,120 @@ error:
/*-------------------------------------------------------------------------*/
/*
- * Root Hub interrupt transfers are synthesized with a timer.
- * Completions are called in_interrupt() but not in_irq().
+ * Root Hub interrupt transfers are polled using a timer if the
+ * driver requests it; otherwise the driver is responsible for
+ * calling usb_hcd_poll_rh_status() when an event occurs.
*
- * Note: some root hubs (including common UHCI based designs) can't
- * correctly issue port change IRQs. They're the ones that _need_ a
- * timer; most other root hubs don't. Some systems could save a
- * lot of battery power by eliminating these root hub timer IRQs.
+ * Completions are called in_interrupt(), but they may or may not
+ * be in_irq().
*/
+void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
+{
+ struct urb *urb;
+ int length;
+ unsigned long flags;
+ char buffer[4]; /* Any root hubs with > 31 ports? */
-static void rh_report_status (unsigned long ptr);
+ if (!hcd->uses_new_polling && !hcd->status_urb)
+ return;
-static int rh_status_urb (struct usb_hcd *hcd, struct urb *urb)
-{
- int len = 1 + (urb->dev->maxchild / 8);
+ length = hcd->driver->hub_status_data(hcd, buffer);
+ if (length > 0) {
- /* rh_timer protected by hcd_data_lock */
- if (hcd->rh_timer.data || urb->transfer_buffer_length < len) {
- dev_dbg (hcd->self.controller,
- "not queuing rh status urb, stat %d\n",
- urb->status);
- return -EINVAL;
+ /* try to complete the status urb */
+ local_irq_save (flags);
+ spin_lock(&hcd_root_hub_lock);
+ urb = hcd->status_urb;
+ if (urb) {
+ spin_lock(&urb->lock);
+ if (urb->status == -EINPROGRESS) {
+ hcd->poll_pending = 0;
+ hcd->status_urb = NULL;
+ urb->status = 0;
+ urb->hcpriv = NULL;
+ urb->actual_length = length;
+ memcpy(urb->transfer_buffer, buffer, length);
+ } else /* urb has been unlinked */
+ length = 0;
+ spin_unlock(&urb->lock);
+ } else
+ length = 0;
+ spin_unlock(&hcd_root_hub_lock);
+
+ /* local irqs are always blocked in completions */
+ if (length > 0)
+ usb_hcd_giveback_urb (hcd, urb, NULL);
+ else
+ hcd->poll_pending = 1;
+ local_irq_restore (flags);
}
- init_timer (&hcd->rh_timer);
- hcd->rh_timer.function = rh_report_status;
- hcd->rh_timer.data = (unsigned long) urb;
- /* USB 2.0 spec says 256msec; this is close enough */
- hcd->rh_timer.expires = jiffies + HZ/4;
- add_timer (&hcd->rh_timer);
- urb->hcpriv = hcd; /* nonzero to indicate it's queued */
- return 0;
+ /* The USB 2.0 spec says 256 ms. This is close enough and won't
+ * exceed that limit if HZ is 100. */
+ if (hcd->uses_new_polling ? hcd->poll_rh :
+ (length == 0 && hcd->status_urb != NULL))
+ mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
}
+EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
/* timer callback */
+static void rh_timer_func (unsigned long _hcd)
+{
+ usb_hcd_poll_rh_status((struct usb_hcd *) _hcd);
+}
-static void rh_report_status (unsigned long ptr)
+/*-------------------------------------------------------------------------*/
+
+static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
{
- struct urb *urb;
- struct usb_hcd *hcd;
- int length = 0;
+ int retval;
unsigned long flags;
+ int len = 1 + (urb->dev->maxchild / 8);
- urb = (struct urb *) ptr;
- local_irq_save (flags);
- spin_lock (&urb->lock);
+ spin_lock_irqsave (&hcd_root_hub_lock, flags);
+ if (urb->status != -EINPROGRESS) /* already unlinked */
+ retval = urb->status;
+ else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+ dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
+ retval = -EINVAL;
+ } else {
+ hcd->status_urb = urb;
+ urb->hcpriv = hcd; /* indicate it's queued */
- /* do nothing if the urb's been unlinked */
- if (!urb->dev
- || urb->status != -EINPROGRESS
- || (hcd = urb->dev->bus->hcpriv) == NULL) {
- spin_unlock (&urb->lock);
- local_irq_restore (flags);
- return;
- }
+ if (!hcd->uses_new_polling)
+ mod_timer (&hcd->rh_timer, jiffies +
+ msecs_to_jiffies(250));
- /* complete the status urb, or retrigger the timer */
- spin_lock (&hcd_data_lock);
- if (urb->dev->state == USB_STATE_CONFIGURED) {
- length = hcd->driver->hub_status_data (
- hcd, urb->transfer_buffer);
- if (length > 0) {
- hcd->rh_timer.data = 0;
- urb->actual_length = length;
- urb->status = 0;
- urb->hcpriv = NULL;
- } else
- mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+ /* If a status change has already occurred, report it ASAP */
+ else if (hcd->poll_pending)
+ mod_timer (&hcd->rh_timer, jiffies);
+ retval = 0;
}
- spin_unlock (&hcd_data_lock);
- spin_unlock (&urb->lock);
-
- /* local irqs are always blocked in completions */
- if (length > 0)
- usb_hcd_giveback_urb (hcd, urb, NULL);
- local_irq_restore (flags);
+ spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
+ return retval;
}
-/*-------------------------------------------------------------------------*/
-
static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
{
- if (usb_pipeint (urb->pipe)) {
- int retval;
- unsigned long flags;
-
- spin_lock_irqsave (&hcd_data_lock, flags);
- retval = rh_status_urb (hcd, urb);
- spin_unlock_irqrestore (&hcd_data_lock, flags);
- return retval;
- }
+ if (usb_pipeint (urb->pipe))
+ return rh_queue_status (hcd, urb);
if (usb_pipecontrol (urb->pipe))
return rh_call_control (hcd, urb);
- else
- return -EINVAL;
+ return -EINVAL;
}
/*-------------------------------------------------------------------------*/
+/* Asynchronous unlinks of root-hub control URBs are legal, but they
+ * don't do anything. Status URB unlinks must be made in process context
+ * with interrupts enabled.
+ */
static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
- unsigned long flags;
+ if (usb_pipeendpoint(urb->pipe) == 0) { /* Control URB */
+ if (in_interrupt())
+ return 0; /* nothing to do */
- /* note: always a synchronous unlink */
- if ((unsigned long) urb == hcd->rh_timer.data) {
- del_timer_sync (&hcd->rh_timer);
- hcd->rh_timer.data = 0;
-
- local_irq_save (flags);
- urb->hcpriv = NULL;
- usb_hcd_giveback_urb (hcd, urb, NULL);
- local_irq_restore (flags);
-
- } else if (usb_pipeendpoint(urb->pipe) == 0) {
spin_lock_irq(&urb->lock); /* from usb_kill_urb */
++urb->reject;
spin_unlock_irq(&urb->lock);
@@ -642,8 +643,22 @@ static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
spin_lock_irq(&urb->lock);
--urb->reject;
spin_unlock_irq(&urb->lock);
- } else
- return -EINVAL;
+
+ } else { /* Status URB */
+ if (!hcd->uses_new_polling)
+ del_timer_sync (&hcd->rh_timer);
+ local_irq_disable ();
+ spin_lock (&hcd_root_hub_lock);
+ if (urb == hcd->status_urb) {
+ hcd->status_urb = NULL;
+ urb->hcpriv = NULL;
+ } else
+ urb = NULL; /* wasn't fully queued */
+ spin_unlock (&hcd_root_hub_lock);
+ if (urb)
+ usb_hcd_giveback_urb (hcd, urb, NULL);
+ local_irq_enable ();
+ }
return 0;
}
@@ -817,30 +832,22 @@ static void usb_deregister_bus (struct usb_bus *bus)
}
/**
- * usb_hcd_register_root_hub - called by HCD to register its root hub
+ * register_root_hub - called by usb_add_hcd() to register a root hub
* @usb_dev: the usb root hub device to be registered.
* @hcd: host controller for this root hub
*
- * The USB host controller calls this function to register the root hub
- * properly with the USB subsystem. It sets up the device properly in
- * the device tree and stores the root_hub pointer in the bus structure,
- * then calls usb_new_device() to register the usb device. It also
- * assigns the root hub's USB address (always 1).
+ * This function registers the root hub with the USB subsystem. It sets up
+ * the device properly in the device tree and stores the root_hub pointer
+ * in the bus structure, then calls usb_new_device() to register the usb
+ * device. It also assigns the root hub's USB address (always 1).
*/
-int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
+static int register_root_hub (struct usb_device *usb_dev,
+ struct usb_hcd *hcd)
{
struct device *parent_dev = hcd->self.controller;
const int devnum = 1;
int retval;
- /* hcd->driver->start() reported can_wakeup, probably with
- * assistance from board's boot firmware.
- * NOTE: normal devices won't enable wakeup by default.
- */
- if (hcd->can_wakeup)
- dev_dbg (parent_dev, "supports USB remote wakeup\n");
- hcd->remote_wakeup = hcd->can_wakeup;
-
usb_dev->devnum = devnum;
usb_dev->bus->devnum_next = devnum + 1;
memset (&usb_dev->bus->devmap.devicemap, 0,
@@ -883,7 +890,16 @@ int usb_hcd_register_root_hub (struct usb_device *usb_dev, struct usb_hcd *hcd)
return retval;
}
-EXPORT_SYMBOL_GPL(usb_hcd_register_root_hub);
+
+void usb_enable_root_hub_irq (struct usb_bus *bus)
+{
+ struct usb_hcd *hcd;
+
+ hcd = container_of (bus, struct usb_hcd, self);
+ if (hcd->driver->hub_irq_enable && !hcd->poll_rh &&
+ hcd->state != HC_STATE_HALT)
+ hcd->driver->hub_irq_enable (hcd);
+}
/*-------------------------------------------------------------------------*/
@@ -1096,7 +1112,7 @@ static void urb_unlink (struct urb *urb)
* expects usb_submit_urb() to have sanity checked and conditioned all
* inputs in the urb
*/
-static int hcd_submit_urb (struct urb *urb, int mem_flags)
+static int hcd_submit_urb (struct urb *urb, unsigned mem_flags)
{
int status;
struct usb_hcd *hcd = urb->dev->bus->hcpriv;
@@ -1348,7 +1364,8 @@ hcd_endpoint_disable (struct usb_device *udev, struct usb_host_endpoint *ep)
hcd = udev->bus->hcpriv;
- WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
+ WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT &&
+ udev->state != USB_STATE_NOTATTACHED);
local_irq_disable ();
@@ -1612,6 +1629,8 @@ void usb_hc_died (struct usb_hcd *hcd)
spin_lock_irqsave (&hcd_root_hub_lock, flags);
if (hcd->rh_registered) {
+ hcd->poll_rh = 0;
+ del_timer(&hcd->rh_timer);
/* make khubd clean up old urbs and devices */
usb_set_device_state (hcd->self.root_hub,
@@ -1665,6 +1684,8 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
hcd->self.bus_name = bus_name;
init_timer(&hcd->rh_timer);
+ hcd->rh_timer.function = rh_timer_func;
+ hcd->rh_timer.data = (unsigned long) hcd;
hcd->driver = driver;
hcd->product_desc = (driver->product_desc) ? driver->product_desc :
@@ -1694,7 +1715,8 @@ EXPORT_SYMBOL (usb_put_hcd);
int usb_add_hcd(struct usb_hcd *hcd,
unsigned int irqnum, unsigned long irqflags)
{
- int retval;
+ int retval;
+ struct usb_device *rhdev;
dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
@@ -1710,7 +1732,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
}
if ((retval = usb_register_bus(&hcd->self)) < 0)
- goto err1;
+ goto err_register_bus;
if (hcd->driver->irq) {
char buf[8], *bufp = buf;
@@ -1727,7 +1749,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
hcd->irq_descr, hcd)) != 0) {
dev_err(hcd->self.controller,
"request interrupt %s failed\n", bufp);
- goto err2;
+ goto err_request_irq;
}
hcd->irq = irqnum;
dev_info(hcd->self.controller, "irq %s, %s 0x%08llx\n", bufp,
@@ -1743,19 +1765,55 @@ int usb_add_hcd(struct usb_hcd *hcd,
(unsigned long long)hcd->rsrc_start);
}
+ /* Allocate the root hub before calling hcd->driver->start(),
+ * but don't register it until afterward so that the hardware
+ * is running.
+ */
+ if ((rhdev = usb_alloc_dev(NULL, &hcd->self, 0)) == NULL) {
+ dev_err(hcd->self.controller, "unable to allocate root hub\n");
+ retval = -ENOMEM;
+ goto err_allocate_root_hub;
+ }
+ rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
+ USB_SPEED_FULL;
+
+ /* Although in principle hcd->driver->start() might need to use rhdev,
+ * none of the current drivers do.
+ */
if ((retval = hcd->driver->start(hcd)) < 0) {
dev_err(hcd->self.controller, "startup error %d\n", retval);
- goto err3;
+ goto err_hcd_driver_start;
}
+ /* hcd->driver->start() reported can_wakeup, probably with
+ * assistance from board's boot firmware.
+ * NOTE: normal devices won't enable wakeup by default.
+ */
+ if (hcd->can_wakeup)
+ dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+ hcd->remote_wakeup = hcd->can_wakeup;
+
+ if ((retval = register_root_hub(rhdev, hcd)) != 0)
+ goto err_register_root_hub;
+
+ if (hcd->uses_new_polling && hcd->poll_rh)
+ usb_hcd_poll_rh_status(hcd);
return retval;
- err3:
+ err_register_root_hub:
+ hcd->driver->stop(hcd);
+
+ err_hcd_driver_start:
+ usb_put_dev(rhdev);
+
+ err_allocate_root_hub:
if (hcd->irq >= 0)
free_irq(irqnum, hcd);
- err2:
+
+ err_request_irq:
usb_deregister_bus(&hcd->self);
- err1:
+
+ err_register_bus:
hcd_buffer_destroy(hcd);
return retval;
}
@@ -1782,6 +1840,9 @@ void usb_remove_hcd(struct usb_hcd *hcd)
spin_unlock_irq (&hcd_root_hub_lock);
usb_disconnect(&hcd->self.root_hub);
+ hcd->poll_rh = 0;
+ del_timer_sync(&hcd->rh_timer);
+
hcd->driver->stop(hcd);
hcd->state = HC_STATE_HALT;
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 325a51656c3f..67db4a999b93 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -65,7 +65,8 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
const char *product_desc; /* product/vendor string */
char irq_descr[24]; /* driver + bus # */
- struct timer_list rh_timer; /* drives root hub */
+ struct timer_list rh_timer; /* drives root-hub polling */
+ struct urb *status_urb; /* the current status urb */
/*
* hardware info/state
@@ -76,10 +77,17 @@ struct usb_hcd { /* usb_bus.hcpriv points to this */
unsigned remote_wakeup:1;/* sw should use wakeup? */
unsigned rh_registered:1;/* is root hub registered? */
+ /* The next flag is a stopgap, to be removed when all the HCDs
+ * support the new root-hub polling mechanism. */
+ unsigned uses_new_polling:1;
+ unsigned poll_rh:1; /* poll for rh status? */
+ unsigned poll_pending:1; /* status has changed? */
+
int irq; /* irq allocated */
void __iomem *regs; /* device memory/io */
u64 rsrc_start; /* memory/io resource start */
u64 rsrc_len; /* memory/io resource length */
+ unsigned power_budget; /* in mA, 0 = no limit */
#define HCD_BUFFER_POOLS 4
struct dma_pool *pool [HCD_BUFFER_POOLS];
@@ -134,12 +142,12 @@ struct hcd_timeout { /* timeouts we allocate */
struct usb_operations {
int (*get_frame_number) (struct usb_device *usb_dev);
- int (*submit_urb) (struct urb *urb, int mem_flags);
+ int (*submit_urb) (struct urb *urb, unsigned mem_flags);
int (*unlink_urb) (struct urb *urb, int status);
/* allocate dma-consistent buffer for URB_DMA_NOMAPPING */
void *(*buffer_alloc)(struct usb_bus *bus, size_t size,
- int mem_flags,
+ unsigned mem_flags,
dma_addr_t *dma);
void (*buffer_free)(struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
@@ -192,7 +200,7 @@ struct hc_driver {
int (*urb_enqueue) (struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
- int mem_flags);
+ unsigned mem_flags);
int (*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
/* hw synch, freeing endpoint resources that urb_dequeue can't */
@@ -207,6 +215,8 @@ struct hc_driver {
int (*hub_suspend)(struct usb_hcd *);
int (*hub_resume)(struct usb_hcd *);
int (*start_port_reset)(struct usb_hcd *, unsigned port_num);
+ void (*hub_irq_enable)(struct usb_hcd *);
+ /* Needed only if port-change IRQs are level-triggered */
};
extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb, struct pt_regs *regs);
@@ -237,13 +247,15 @@ int hcd_buffer_create (struct usb_hcd *hcd);
void hcd_buffer_destroy (struct usb_hcd *hcd);
void *hcd_buffer_alloc (struct usb_bus *bus, size_t size,
- int mem_flags, dma_addr_t *dma);
+ unsigned mem_flags, dma_addr_t *dma);
void hcd_buffer_free (struct usb_bus *bus, size_t size,
void *addr, dma_addr_t dma);
/* generic bus glue, needed for host controllers that don't use PCI */
extern irqreturn_t usb_hcd_irq (int irq, void *__hcd, struct pt_regs *r);
+
extern void usb_hc_died (struct usb_hcd *hcd);
+extern void usb_hcd_poll_rh_status(struct usb_hcd *hcd);
/* -------------------------------------------------------------------------- */
@@ -341,9 +353,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
-extern int usb_hcd_register_root_hub (struct usb_device *usb_dev,
- struct usb_hcd *hcd);
-
extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
extern void usb_set_device_state(struct usb_device *udev,
@@ -360,6 +369,8 @@ extern wait_queue_head_t usb_kill_urb_queue;
extern struct usb_bus *usb_bus_get (struct usb_bus *bus);
extern void usb_bus_put (struct usb_bus *bus);
+extern void usb_enable_root_hub_irq (struct usb_bus *bus);
+
extern int usb_find_interface_driver (struct usb_device *dev,
struct usb_interface *interface);
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index d2d648ee8640..c3e46d24a37e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -26,6 +26,7 @@
#include <linux/ioctl.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
+#include <linux/kthread.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
@@ -47,8 +48,7 @@ static LIST_HEAD(hub_event_list); /* List of hubs needing servicing */
/* Wakes up khubd */
static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
-static pid_t khubd_pid = 0; /* PID of khubd */
-static DECLARE_COMPLETION(khubd_exited);
+static struct task_struct *khubd_task;
/* cycle leds on hubs that aren't blinking for attention */
static int blinkenlights = 0;
@@ -643,15 +643,21 @@ static int hub_configure(struct usb_hub *hub,
message = "can't get hub status";
goto fail;
}
- cpu_to_le16s(&hubstatus);
- if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
+ le16_to_cpus(&hubstatus);
+ if (hdev == hdev->bus->root_hub) {
+ struct usb_hcd *hcd =
+ container_of(hdev->bus, struct usb_hcd, self);
+
+ hub->power_budget = min(500u, hcd->power_budget) / 2;
+ } else if ((hubstatus & (1 << USB_DEVICE_SELF_POWERED)) == 0) {
dev_dbg(hub_dev, "hub controller current requirement: %dmA\n",
hub->descriptor->bHubContrCurrent);
hub->power_budget = (501 - hub->descriptor->bHubContrCurrent)
/ 2;
+ }
+ if (hub->power_budget)
dev_dbg(hub_dev, "%dmA bus power budget for children\n",
hub->power_budget * 2);
- }
ret = hub_hub_status(hub, &hubstatus, &hubchange);
@@ -1727,7 +1733,7 @@ static int finish_port_resume(struct usb_device *udev)
struct usb_driver *driver;
intf = udev->actconfig->interface[i];
- if (intf->dev.power.power_state == PMSG_SUSPEND)
+ if (intf->dev.power.power_state == PMSG_ON)
continue;
if (!intf->dev.driver) {
/* FIXME maybe force to alt 0 */
@@ -2787,6 +2793,11 @@ static void hub_events(void)
hub->activating = 0;
+ /* If this is a root hub, tell the HCD it's okay to
+ * re-enable port-change interrupts now. */
+ if (!hdev->parent)
+ usb_enable_root_hub_irq(hdev->bus);
+
loop:
usb_unlock_device(hdev);
usb_put_intf(intf);
@@ -2796,23 +2807,16 @@ loop:
static int hub_thread(void *__unused)
{
- /*
- * This thread doesn't need any user-level access,
- * so get rid of all our resources
- */
-
- daemonize("khubd");
- allow_signal(SIGKILL);
-
- /* Send me a signal to get me die (for debugging) */
do {
hub_events();
- wait_event_interruptible(khubd_wait, !list_empty(&hub_event_list));
- try_to_freeze(PF_FREEZE);
- } while (!signal_pending(current));
+ wait_event_interruptible(khubd_wait,
+ !list_empty(&hub_event_list) ||
+ kthread_should_stop());
+ try_to_freeze();
+ } while (!kthread_should_stop() || !list_empty(&hub_event_list));
- pr_debug ("%s: khubd exiting\n", usbcore_name);
- complete_and_exit(&khubd_exited, 0);
+ pr_debug("%s: khubd exiting\n", usbcore_name);
+ return 0;
}
static struct usb_device_id hub_id_table [] = {
@@ -2838,20 +2842,15 @@ static struct usb_driver hub_driver = {
int usb_hub_init(void)
{
- pid_t pid;
-
if (usb_register(&hub_driver) < 0) {
printk(KERN_ERR "%s: can't register hub driver\n",
usbcore_name);
return -1;
}
- pid = kernel_thread(hub_thread, NULL, CLONE_KERNEL);
- if (pid >= 0) {
- khubd_pid = pid;
-
+ khubd_task = kthread_run(hub_thread, NULL, "khubd");
+ if (!IS_ERR(khubd_task))
return 0;
- }
/* Fall through if kernel_thread failed */
usb_deregister(&hub_driver);
@@ -2862,12 +2861,7 @@ int usb_hub_init(void)
void usb_hub_cleanup(void)
{
- int ret;
-
- /* Kill the thread */
- ret = kill_proc(khubd_pid, SIGKILL, 1);
-
- wait_for_completion(&khubd_exited);
+ kthread_stop(khubd_task);
/*
* Hub resources are freed for us by usb_deregister. It calls
@@ -2879,7 +2873,6 @@ void usb_hub_cleanup(void)
usb_deregister(&hub_driver);
} /* usb_hub_cleanup() */
-
static int config_descriptors_changed(struct usb_device *udev)
{
unsigned index;
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index d114b847d56f..53bf5649621e 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -224,15 +224,4 @@ struct usb_hub {
struct work_struct leds;
};
-/* use this for low-powered root hubs */
-static inline void
-hub_set_power_budget (struct usb_device *hubdev, unsigned mA)
-{
- struct usb_hub *hub;
-
- hub = (struct usb_hub *)
- usb_get_intfdata (hubdev->actconfig->interface[0]);
- hub->power_budget = min(mA,(unsigned)500)/2;
-}
-
#endif /* __LINUX_HUB_H */
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f50aaf25c98e..a428ef479bd7 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -320,7 +320,7 @@ int usb_sg_init (
struct scatterlist *sg,
int nents,
size_t length,
- int mem_flags
+ unsigned mem_flags
)
{
int i;
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 740cb4c668df..00297f113849 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -196,6 +196,7 @@ usb_descriptor_attr (bDeviceClass, "%02x\n")
usb_descriptor_attr (bDeviceSubClass, "%02x\n")
usb_descriptor_attr (bDeviceProtocol, "%02x\n")
usb_descriptor_attr (bNumConfigurations, "%d\n")
+usb_descriptor_attr (bMaxPacketSize0, "%d\n")
static struct attribute *dev_attrs[] = {
/* current configuration's attributes */
@@ -211,6 +212,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_bDeviceSubClass.attr,
&dev_attr_bDeviceProtocol.attr,
&dev_attr_bNumConfigurations.attr,
+ &dev_attr_bMaxPacketSize0.attr,
&dev_attr_speed.attr,
&dev_attr_devnum.attr,
&dev_attr_version.attr,
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 0faf18d511de..c0feee25ff0a 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -60,7 +60,7 @@ void usb_init_urb(struct urb *urb)
*
* The driver must call usb_free_urb() when it is finished with the urb.
*/
-struct urb *usb_alloc_urb(int iso_packets, int mem_flags)
+struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags)
{
struct urb *urb;
@@ -224,7 +224,7 @@ struct urb * usb_get_urb(struct urb *urb)
* GFP_NOIO, unless b) or c) apply
*
*/
-int usb_submit_urb(struct urb *urb, int mem_flags)
+int usb_submit_urb(struct urb *urb, unsigned mem_flags)
{
int pipe, temp, max;
struct usb_device *dev;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index a3c42203213a..99c85d2f92da 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1129,7 +1129,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
void *usb_buffer_alloc (
struct usb_device *dev,
size_t size,
- int mem_flags,
+ unsigned mem_flags,
dma_addr_t *dma
)
{
@@ -1532,6 +1532,9 @@ EXPORT_SYMBOL(usb_register);
EXPORT_SYMBOL(usb_deregister);
EXPORT_SYMBOL(usb_disabled);
+EXPORT_SYMBOL_GPL(usb_get_intf);
+EXPORT_SYMBOL_GPL(usb_put_intf);
+
EXPORT_SYMBOL(usb_alloc_dev);
EXPORT_SYMBOL(usb_put_dev);
EXPORT_SYMBOL(usb_get_dev);
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 3b24f9f2c234..ff075a53c8d6 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -53,6 +53,9 @@ config USB_GADGET_DEBUG_FILES
driver on a new board. Enable these files by choosing "Y"
here. If in doubt, or to conserve kernel memory, say "N".
+config USB_GADGET_SELECTED
+ boolean
+
#
# USB Peripheral Controller Support
#
@@ -85,6 +88,7 @@ config USB_NET2280
tristate
depends on USB_GADGET_NET2280
default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_GADGET_PXA2XX
boolean "PXA 25x or IXP 4xx"
@@ -105,6 +109,7 @@ config USB_PXA2XX
tristate
depends on USB_GADGET_PXA2XX
default USB_GADGET
+ select USB_GADGET_SELECTED
# if there's only one gadget driver, using only two bulk endpoints,
# don't waste memory for the other endpoints
@@ -134,6 +139,7 @@ config USB_GOKU
tristate
depends on USB_GADGET_GOKU
default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_GADGET_LH7A40X
@@ -146,6 +152,7 @@ config USB_LH7A40X
tristate
depends on USB_GADGET_LH7A40X
default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_GADGET_OMAP
@@ -167,6 +174,7 @@ config USB_OMAP
tristate
depends on USB_GADGET_OMAP
default USB_GADGET
+ select USB_GADGET_SELECTED
config USB_OTG
boolean "OTG Support"
@@ -207,6 +215,7 @@ config USB_DUMMY_HCD
tristate
depends on USB_GADGET_DUMMY_HCD
default USB_GADGET
+ select USB_GADGET_SELECTED
# NOTE: Please keep dummy_hcd LAST so that "real hardware" appears
# first and will be selected by default.
@@ -226,7 +235,7 @@ config USB_GADGET_DUALSPEED
#
choice
tristate "USB Gadget Drivers"
- depends on USB_GADGET
+ depends on USB_GADGET && USB_GADGET_SELECTED
default USB_ETH
help
A Linux "Gadget Driver" talks to the USB Peripheral Controller
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c039d2fbe7ab..583db7c38cf1 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -65,7 +65,7 @@
#define DRIVER_DESC "USB Host+Gadget Emulator"
-#define DRIVER_VERSION "17 Dec 2004"
+#define DRIVER_VERSION "02 May 2005"
static const char driver_name [] = "dummy_hcd";
static const char driver_desc [] = "USB Host+Gadget Emulator";
@@ -141,6 +141,8 @@ static const char *const ep_name [] = {
};
#define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *))
+/*-------------------------------------------------------------------------*/
+
#define FIFO_SIZE 64
struct urbp {
@@ -148,6 +150,13 @@ struct urbp {
struct list_head urbp_list;
};
+
+enum dummy_rh_state {
+ DUMMY_RH_RESET,
+ DUMMY_RH_SUSPENDED,
+ DUMMY_RH_RUNNING
+};
+
struct dummy {
spinlock_t lock;
@@ -161,12 +170,18 @@ struct dummy {
struct dummy_request fifo_req;
u8 fifo_buf [FIFO_SIZE];
u16 devstatus;
+ unsigned udc_suspended:1;
+ unsigned pullup:1;
+ unsigned active:1;
+ unsigned old_active:1;
/*
* MASTER/HOST side support
*/
+ enum dummy_rh_state rh_state;
struct timer_list timer;
u32 port_status;
+ u32 old_status;
unsigned resuming:1;
unsigned long re_timeout;
@@ -189,6 +204,11 @@ static inline struct device *dummy_dev (struct dummy *dum)
return dummy_to_hcd(dum)->self.controller;
}
+static inline struct device *udc_dev (struct dummy *dum)
+{
+ return dum->gadget.dev.parent;
+}
+
static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
{
return container_of (ep->gadget, struct dummy, gadget);
@@ -208,16 +228,98 @@ static struct dummy *the_controller;
/*-------------------------------------------------------------------------*/
-/*
- * This "hardware" may look a bit odd in diagnostics since it's got both
- * host and device sides; and it binds different drivers to each side.
- */
-static struct platform_device the_pdev;
+/* SLAVE/GADGET SIDE UTILITY ROUTINES */
-static struct device_driver dummy_driver = {
- .name = (char *) driver_name,
- .bus = &platform_bus_type,
-};
+/* called with spinlock held */
+static void nuke (struct dummy *dum, struct dummy_ep *ep)
+{
+ while (!list_empty (&ep->queue)) {
+ struct dummy_request *req;
+
+ req = list_entry (ep->queue.next, struct dummy_request, queue);
+ list_del_init (&req->queue);
+ req->req.status = -ESHUTDOWN;
+
+ spin_unlock (&dum->lock);
+ req->req.complete (&ep->ep, &req->req);
+ spin_lock (&dum->lock);
+ }
+}
+
+/* caller must hold lock */
+static void
+stop_activity (struct dummy *dum)
+{
+ struct dummy_ep *ep;
+
+ /* prevent any more requests */
+ dum->address = 0;
+
+ /* The timer is left running so that outstanding URBs can fail */
+
+ /* nuke any pending requests first, so driver i/o is quiesced */
+ list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
+ nuke (dum, ep);
+
+ /* driver now does any non-usb quiescing necessary */
+}
+
+/* caller must hold lock */
+static void
+set_link_state (struct dummy *dum)
+{
+ dum->active = 0;
+ if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
+ dum->port_status = 0;
+
+ /* UDC suspend must cause a disconnect */
+ else if (!dum->pullup || dum->udc_suspended) {
+ dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
+ USB_PORT_STAT_ENABLE |
+ USB_PORT_STAT_LOW_SPEED |
+ USB_PORT_STAT_HIGH_SPEED |
+ USB_PORT_STAT_SUSPEND);
+ if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
+ dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+ } else {
+ dum->port_status |= USB_PORT_STAT_CONNECTION;
+ if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
+ dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+ if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
+ dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+ else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+ dum->rh_state != DUMMY_RH_SUSPENDED)
+ dum->active = 1;
+ }
+
+ if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
+ dum->resuming = 0;
+
+ if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+ (dum->port_status & USB_PORT_STAT_RESET) != 0) {
+ if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+ (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
+ dum->driver) {
+ stop_activity (dum);
+ spin_unlock (&dum->lock);
+ dum->driver->disconnect (&dum->gadget);
+ spin_lock (&dum->lock);
+ }
+ } else if (dum->active != dum->old_active) {
+ if (dum->old_active && dum->driver->suspend) {
+ spin_unlock (&dum->lock);
+ dum->driver->suspend (&dum->gadget);
+ spin_lock (&dum->lock);
+ } else if (!dum->old_active && dum->driver->resume) {
+ spin_unlock (&dum->lock);
+ dum->driver->resume (&dum->gadget);
+ spin_lock (&dum->lock);
+ }
+ }
+
+ dum->old_status = dum->port_status;
+ dum->old_active = dum->active;
+}
/*-------------------------------------------------------------------------*/
@@ -324,7 +426,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
_ep->maxpacket = max;
ep->desc = desc;
- dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+ dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
_ep->name,
desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
@@ -345,22 +447,6 @@ done:
return retval;
}
-/* called with spinlock held */
-static void nuke (struct dummy *dum, struct dummy_ep *ep)
-{
- while (!list_empty (&ep->queue)) {
- struct dummy_request *req;
-
- req = list_entry (ep->queue.next, struct dummy_request, queue);
- list_del_init (&req->queue);
- req->req.status = -ESHUTDOWN;
-
- spin_unlock (&dum->lock);
- req->req.complete (&ep->ep, &req->req);
- spin_lock (&dum->lock);
- }
-}
-
static int dummy_disable (struct usb_ep *_ep)
{
struct dummy_ep *ep;
@@ -379,12 +465,12 @@ static int dummy_disable (struct usb_ep *_ep)
nuke (dum, ep);
spin_unlock_irqrestore (&dum->lock, flags);
- dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name);
+ dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
return retval;
}
static struct usb_request *
-dummy_alloc_request (struct usb_ep *_ep, int mem_flags)
+dummy_alloc_request (struct usb_ep *_ep, unsigned mem_flags)
{
struct dummy_ep *ep;
struct dummy_request *req;
@@ -421,7 +507,7 @@ dummy_alloc_buffer (
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
- int mem_flags
+ unsigned mem_flags
) {
char *retval;
struct dummy_ep *ep;
@@ -454,7 +540,8 @@ fifo_complete (struct usb_ep *ep, struct usb_request *req)
}
static int
-dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags)
+dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
+ unsigned mem_flags)
{
struct dummy_ep *ep;
struct dummy_request *req;
@@ -474,7 +561,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags)
return -ESHUTDOWN;
#if 0
- dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+ dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
ep, _req, _ep->name, _req->length, _req->buf);
#endif
@@ -537,7 +624,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
spin_unlock_irqrestore (&dum->lock, flags);
if (retval == 0) {
- dev_dbg (dummy_dev(dum),
+ dev_dbg (udc_dev(dum),
"dequeued req %p from %s, len %d buf %p\n",
req, _ep->name, _req->length, _req->buf);
_req->complete (_ep, _req);
@@ -601,13 +688,21 @@ static int dummy_wakeup (struct usb_gadget *_gadget)
struct dummy *dum;
dum = gadget_to_dummy (_gadget);
- if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0
- || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)))
+ if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE)
+ | (1 << USB_DEVICE_REMOTE_WAKEUP))))
return -EINVAL;
+ if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+ return -ENOLINK;
+ if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+ dum->rh_state != DUMMY_RH_SUSPENDED)
+ return -EIO;
+
+ /* FIXME: What if the root hub is suspended but the port isn't? */
/* hub notices our request, issues downstream resume, etc */
dum->resuming = 1;
- dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
+ dum->re_timeout = jiffies + msecs_to_jiffies(20);
+ mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
return 0;
}
@@ -623,10 +718,26 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
return 0;
}
+static int dummy_pullup (struct usb_gadget *_gadget, int value)
+{
+ struct dummy *dum;
+ unsigned long flags;
+
+ dum = gadget_to_dummy (_gadget);
+ spin_lock_irqsave (&dum->lock, flags);
+ dum->pullup = (value != 0);
+ set_link_state (dum);
+ spin_unlock_irqrestore (&dum->lock, flags);
+
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+ return 0;
+}
+
static const struct usb_gadget_ops dummy_ops = {
.get_frame = dummy_g_get_frame,
.wakeup = dummy_wakeup,
.set_selfpowered = dummy_set_selfpowered,
+ .pullup = dummy_pullup,
};
/*-------------------------------------------------------------------------*/
@@ -641,7 +752,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf)
return 0;
return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
}
-DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
/*-------------------------------------------------------------------------*/
@@ -659,38 +770,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
* for each driver that registers: just add to a big root hub.
*/
-static void
-dummy_udc_release (struct device *dev)
-{
-}
-
-static void
-dummy_pdev_release (struct device *dev)
-{
-}
-
-static int
-dummy_register_udc (struct dummy *dum)
-{
- int rc;
-
- strcpy (dum->gadget.dev.bus_id, "udc");
- dum->gadget.dev.parent = dummy_dev(dum);
- dum->gadget.dev.release = dummy_udc_release;
-
- rc = device_register (&dum->gadget.dev);
- if (rc == 0)
- device_create_file (&dum->gadget.dev, &dev_attr_function);
- return rc;
-}
-
-static void
-dummy_unregister_udc (struct dummy *dum)
-{
- device_remove_file (&dum->gadget.dev, &dev_attr_function);
- device_unregister (&dum->gadget.dev);
-}
-
int
usb_gadget_register_driver (struct usb_gadget_driver *driver)
{
@@ -709,12 +788,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
* SLAVE side init ... the layer above hardware, which
* can't enumerate without help from the driver we're binding.
*/
- dum->gadget.name = gadget_name;
- dum->gadget.ops = &dummy_ops;
- dum->gadget.is_dualspeed = 1;
dum->devstatus = 0;
- dum->resuming = 0;
INIT_LIST_HEAD (&dum->gadget.ep_list);
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
@@ -740,7 +815,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
dum->driver = driver;
dum->gadget.dev.driver = &driver->driver;
- dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n",
+ dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
if ((retval = driver->bind (&dum->gadget)) != 0) {
dum->driver = NULL;
@@ -748,42 +823,21 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
return retval;
}
- // FIXME: Check these calls for errors and re-order
driver->driver.bus = dum->gadget.dev.parent->bus;
driver_register (&driver->driver);
-
device_bind_driver (&dum->gadget.dev);
/* khubd will enumerate this in a while */
- dum->port_status |= USB_PORT_STAT_CONNECTION
- | (1 << USB_PORT_FEAT_C_CONNECTION);
+ spin_lock_irq (&dum->lock);
+ dum->pullup = 1;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
EXPORT_SYMBOL (usb_gadget_register_driver);
-/* caller must hold lock */
-static void
-stop_activity (struct dummy *dum, struct usb_gadget_driver *driver)
-{
- struct dummy_ep *ep;
-
- /* prevent any more requests */
- dum->address = 0;
-
- /* The timer is left running so that outstanding URBs can fail */
-
- /* nuke any pending requests first, so driver i/o is quiesced */
- list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
- nuke (dum, ep);
-
- /* driver now does any non-usb quiescing necessary */
- if (driver) {
- spin_unlock (&dum->lock);
- driver->disconnect (&dum->gadget);
- spin_lock (&dum->lock);
- }
-}
-
int
usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
{
@@ -795,35 +849,138 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
if (!driver || driver != dum->driver)
return -EINVAL;
- dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n",
+ dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
driver->driver.name);
spin_lock_irqsave (&dum->lock, flags);
- stop_activity (dum, driver);
- dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE |
- USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
- dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION);
+ dum->pullup = 0;
+ set_link_state (dum);
spin_unlock_irqrestore (&dum->lock, flags);
driver->unbind (&dum->gadget);
dum->driver = NULL;
device_release_driver (&dum->gadget.dev);
-
driver_unregister (&driver->driver);
+ spin_lock_irqsave (&dum->lock, flags);
+ dum->pullup = 0;
+ set_link_state (dum);
+ spin_unlock_irqrestore (&dum->lock, flags);
+
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
return 0;
}
EXPORT_SYMBOL (usb_gadget_unregister_driver);
#undef is_enabled
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
{
return -ENOSYS;
}
EXPORT_SYMBOL (net2280_set_fifo_mode);
+
+/* The gadget structure is stored inside the hcd structure and will be
+ * released along with it. */
+static void
+dummy_gadget_release (struct device *dev)
+{
+#if 0 /* usb_bus_put isn't EXPORTed! */
+ struct dummy *dum = gadget_dev_to_dummy (dev);
+
+ usb_bus_put (&dummy_to_hcd (dum)->self);
+#endif
+}
+
+static int dummy_udc_probe (struct device *dev)
+{
+ struct dummy *dum = the_controller;
+ int rc;
+
+ dum->gadget.name = gadget_name;
+ dum->gadget.ops = &dummy_ops;
+ dum->gadget.is_dualspeed = 1;
+
+ /* maybe claim OTG support, though we won't complete HNP */
+ dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
+
+ strcpy (dum->gadget.dev.bus_id, "gadget");
+ dum->gadget.dev.parent = dev;
+ dum->gadget.dev.release = dummy_gadget_release;
+ rc = device_register (&dum->gadget.dev);
+ if (rc < 0)
+ return rc;
+
+#if 0 /* usb_bus_get isn't EXPORTed! */
+ usb_bus_get (&dummy_to_hcd (dum)->self);
+#endif
+
+ dev_set_drvdata (dev, dum);
+ device_create_file (&dum->gadget.dev, &dev_attr_function);
+ return rc;
+}
+
+static int dummy_udc_remove (struct device *dev)
+{
+ struct dummy *dum = dev_get_drvdata (dev);
+
+ dev_set_drvdata (dev, NULL);
+ device_remove_file (&dum->gadget.dev, &dev_attr_function);
+ device_unregister (&dum->gadget.dev);
+ return 0;
+}
+
+static int dummy_udc_suspend (struct device *dev, pm_message_t state,
+ u32 level)
+{
+ struct dummy *dum = dev_get_drvdata(dev);
+
+ if (level != SUSPEND_DISABLE)
+ return 0;
+
+ dev_dbg (dev, "%s\n", __FUNCTION__);
+ spin_lock_irq (&dum->lock);
+ dum->udc_suspended = 1;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+
+ dev->power.power_state = state;
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+ return 0;
+}
+
+static int dummy_udc_resume (struct device *dev, u32 level)
+{
+ struct dummy *dum = dev_get_drvdata(dev);
+
+ if (level != RESUME_ENABLE)
+ return 0;
+
+ dev_dbg (dev, "%s\n", __FUNCTION__);
+ spin_lock_irq (&dum->lock);
+ dum->udc_suspended = 0;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+
+ dev->power.power_state = PMSG_ON;
+ usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+ return 0;
+}
+
+static struct device_driver dummy_udc_driver = {
+ .name = (char *) gadget_name,
+ .bus = &platform_bus_type,
+ .probe = dummy_udc_probe,
+ .remove = dummy_udc_remove,
+ .suspend = dummy_udc_suspend,
+ .resume = dummy_udc_resume,
+};
+
/*-------------------------------------------------------------------------*/
/* MASTER/HOST SIDE DRIVER
@@ -842,7 +999,7 @@ static int dummy_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
) {
struct dummy *dum;
struct urbp *urbp;
@@ -880,7 +1037,16 @@ static int dummy_urb_enqueue (
static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
{
- /* giveback happens automatically in timer callback */
+ struct dummy *dum;
+ unsigned long flags;
+
+ /* giveback happens automatically in timer callback,
+ * so make sure the callback happens */
+ dum = hcd_to_dummy (hcd);
+ spin_lock_irqsave (&dum->lock, flags);
+ if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+ mod_timer (&dum->timer, jiffies);
+ spin_unlock_irqrestore (&dum->lock, flags);
return 0;
}
@@ -1025,7 +1191,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
/* high bandwidth mode */
tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
- tmp = le16_to_cpu (tmp);
tmp = (tmp >> 11) & 0x03;
tmp *= 8 /* applies to entire frame */;
limit += limit * tmp;
@@ -1123,7 +1288,8 @@ restart:
if (urb->status != -EINPROGRESS) {
/* likely it was just unlinked */
goto return_urb;
- }
+ } else if (dum->rh_state != DUMMY_RH_RUNNING)
+ continue;
type = usb_pipetype (urb->pipe);
/* used up this frame's non-periodic bandwidth?
@@ -1168,12 +1334,14 @@ restart:
struct usb_ctrlrequest setup;
int value = 1;
struct dummy_ep *ep2;
+ unsigned w_index;
+ unsigned w_value;
setup = *(struct usb_ctrlrequest*) urb->setup_packet;
- le16_to_cpus (&setup.wIndex);
- le16_to_cpus (&setup.wValue);
- le16_to_cpus (&setup.wLength);
- if (setup.wLength != urb->transfer_buffer_length) {
+ w_index = le16_to_cpu(setup.wIndex);
+ w_value = le16_to_cpu(setup.wValue);
+ if (le16_to_cpu(setup.wLength) !=
+ urb->transfer_buffer_length) {
maybe_set_status (urb, -EOVERFLOW);
goto return_urb;
}
@@ -1182,7 +1350,7 @@ restart:
list_for_each_entry (req, &ep->queue, queue) {
list_del_init (&req->queue);
req->req.status = -EOVERFLOW;
- dev_dbg (dummy_dev(dum), "stale req = %p\n",
+ dev_dbg (udc_dev(dum), "stale req = %p\n",
req);
spin_unlock (&dum->lock);
@@ -1203,31 +1371,40 @@ restart:
case USB_REQ_SET_ADDRESS:
if (setup.bRequestType != Dev_Request)
break;
- dum->address = setup.wValue;
+ dum->address = w_value;
maybe_set_status (urb, 0);
- dev_dbg (dummy_dev(dum), "set_address = %d\n",
- setup.wValue);
+ dev_dbg (udc_dev(dum), "set_address = %d\n",
+ w_value);
value = 0;
break;
case USB_REQ_SET_FEATURE:
if (setup.bRequestType == Dev_Request) {
value = 0;
- switch (setup.wValue) {
+ switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
break;
+ case USB_DEVICE_B_HNP_ENABLE:
+ dum->gadget.b_hnp_enable = 1;
+ break;
+ case USB_DEVICE_A_HNP_SUPPORT:
+ dum->gadget.a_hnp_support = 1;
+ break;
+ case USB_DEVICE_A_ALT_HNP_SUPPORT:
+ dum->gadget.a_alt_hnp_support
+ = 1;
+ break;
default:
value = -EOPNOTSUPP;
}
if (value == 0) {
dum->devstatus |=
- (1 << setup.wValue);
+ (1 << w_value);
maybe_set_status (urb, 0);
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
- ep2 = find_endpoint (dum,
- setup.wIndex);
+ ep2 = find_endpoint (dum, w_index);
if (!ep2) {
value = -EOPNOTSUPP;
break;
@@ -1239,7 +1416,7 @@ restart:
break;
case USB_REQ_CLEAR_FEATURE:
if (setup.bRequestType == Dev_Request) {
- switch (setup.wValue) {
+ switch (w_value) {
case USB_DEVICE_REMOTE_WAKEUP:
dum->devstatus &= ~(1 <<
USB_DEVICE_REMOTE_WAKEUP);
@@ -1252,8 +1429,7 @@ restart:
}
} else if (setup.bRequestType == Ep_Request) {
// endpoint halt
- ep2 = find_endpoint (dum,
- setup.wIndex);
+ ep2 = find_endpoint (dum, w_index);
if (!ep2) {
value = -EOPNOTSUPP;
break;
@@ -1279,7 +1455,7 @@ restart:
if (urb->transfer_buffer_length > 0) {
if (setup.bRequestType ==
Ep_InRequest) {
- ep2 = find_endpoint (dum, setup.wIndex);
+ ep2 = find_endpoint (dum, w_index);
if (!ep2) {
value = -EOPNOTSUPP;
break;
@@ -1321,7 +1497,7 @@ restart:
if (value < 0) {
if (value != -EOPNOTSUPP)
- dev_dbg (dummy_dev(dum),
+ dev_dbg (udc_dev(dum),
"setup --> %d\n",
value);
maybe_set_status (urb, -EPIPE);
@@ -1377,12 +1553,12 @@ return_urb:
goto restart;
}
- /* want a 1 msec delay here */
- if (!list_empty (&dum->urbp_list))
- mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
- else {
+ if (list_empty (&dum->urbp_list)) {
usb_put_dev (dum->udev);
dum->udev = NULL;
+ } else if (dum->rh_state == DUMMY_RH_RUNNING) {
+ /* want a 1 msec delay here */
+ mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
}
spin_unlock_irqrestore (&dum->lock, flags);
@@ -1391,29 +1567,39 @@ return_urb:
/*-------------------------------------------------------------------------*/
#define PORT_C_MASK \
- ((1 << USB_PORT_FEAT_C_CONNECTION) \
- | (1 << USB_PORT_FEAT_C_ENABLE) \
- | (1 << USB_PORT_FEAT_C_SUSPEND) \
- | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \
- | (1 << USB_PORT_FEAT_C_RESET))
+ ((USB_PORT_STAT_C_CONNECTION \
+ | USB_PORT_STAT_C_ENABLE \
+ | USB_PORT_STAT_C_SUSPEND \
+ | USB_PORT_STAT_C_OVERCURRENT \
+ | USB_PORT_STAT_C_RESET) << 16)
static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
{
struct dummy *dum;
unsigned long flags;
- int retval;
+ int retval = 0;
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
- if (!(dum->port_status & PORT_C_MASK))
- retval = 0;
- else {
+ if (hcd->state != HC_STATE_RUNNING)
+ goto done;
+
+ if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
+ dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+ dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+ set_link_state (dum);
+ }
+
+ if ((dum->port_status & PORT_C_MASK) != 0) {
*buf = (1 << 1);
dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
- dum->port_status);
+ dum->port_status);
retval = 1;
+ if (dum->rh_state == DUMMY_RH_SUSPENDED)
+ usb_hcd_resume_root_hub (hcd);
}
+done:
spin_unlock_irqrestore (&dum->lock, flags);
return retval;
}
@@ -1424,7 +1610,8 @@ hub_descriptor (struct usb_hub_descriptor *desc)
memset (desc, 0, sizeof *desc);
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
- desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001);
+ desc->wHubCharacteristics = (__force __u16)
+ (__constant_cpu_to_le16 (0x0001));
desc->bNbrPorts = 1;
desc->bitmap [0] = 0xff;
desc->bitmap [1] = 0xff;
@@ -1442,6 +1629,9 @@ static int dummy_hub_control (
int retval = 0;
unsigned long flags;
+ if (hcd->state != HC_STATE_RUNNING)
+ return -ETIMEDOUT;
+
dum = hcd_to_dummy (hcd);
spin_lock_irqsave (&dum->lock, flags);
switch (typeReq) {
@@ -1450,27 +1640,27 @@ static int dummy_hub_control (
case ClearPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) {
+ if (dum->port_status & USB_PORT_STAT_SUSPEND) {
/* 20msec resume signaling */
dum->resuming = 1;
dum->re_timeout = jiffies +
- msecs_to_jiffies(20);
+ msecs_to_jiffies(20);
}
break;
case USB_PORT_FEAT_POWER:
- dum->port_status = 0;
- dum->resuming = 0;
- stop_activity(dum, dum->driver);
- break;
+ if (dum->port_status & USB_PORT_STAT_POWER)
+ dev_dbg (dummy_dev(dum), "power-off\n");
+ /* FALLS THROUGH */
default:
dum->port_status &= ~(1 << wValue);
+ set_link_state (dum);
}
break;
case GetHubDescriptor:
hub_descriptor ((struct usb_hub_descriptor *) buf);
break;
case GetHubStatus:
- *(u32 *) buf = __constant_cpu_to_le32 (0);
+ *(__le32 *) buf = __constant_cpu_to_le32 (0);
break;
case GetPortStatus:
if (wIndex != 1)
@@ -1479,23 +1669,16 @@ static int dummy_hub_control (
/* whoever resets or resumes must GetPortStatus to
* complete it!!
*/
- if (dum->resuming && time_after (jiffies, dum->re_timeout)) {
- dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND);
- dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND);
- dum->resuming = 0;
- dum->re_timeout = 0;
- if (dum->driver && dum->driver->resume) {
- spin_unlock (&dum->lock);
- dum->driver->resume (&dum->gadget);
- spin_lock (&dum->lock);
- }
+ if (dum->resuming &&
+ time_after_eq (jiffies, dum->re_timeout)) {
+ dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+ dum->port_status &= ~USB_PORT_STAT_SUSPEND;
}
- if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0
- && time_after (jiffies, dum->re_timeout)) {
- dum->port_status |= (1 << USB_PORT_FEAT_C_RESET);
- dum->port_status &= ~(1 << USB_PORT_FEAT_RESET);
- dum->re_timeout = 0;
- if (dum->driver) {
+ if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
+ time_after_eq (jiffies, dum->re_timeout)) {
+ dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
+ dum->port_status &= ~USB_PORT_STAT_RESET;
+ if (dum->pullup) {
dum->port_status |= USB_PORT_STAT_ENABLE;
/* give it the best speed we agree on */
dum->gadget.speed = dum->driver->speed;
@@ -1516,8 +1699,9 @@ static int dummy_hub_control (
}
}
}
- ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
- ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+ set_link_state (dum);
+ ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
+ ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
break;
case SetHubFeature:
retval = -EPIPE;
@@ -1525,36 +1709,37 @@ static int dummy_hub_control (
case SetPortFeature:
switch (wValue) {
case USB_PORT_FEAT_SUSPEND:
- if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))
- == 0) {
- dum->port_status |=
- (1 << USB_PORT_FEAT_SUSPEND);
- if (dum->driver && dum->driver->suspend) {
- spin_unlock (&dum->lock);
- dum->driver->suspend (&dum->gadget);
- spin_lock (&dum->lock);
- }
+ if (dum->active) {
+ dum->port_status |= USB_PORT_STAT_SUSPEND;
+
+ /* HNP would happen here; for now we
+ * assume b_bus_req is always true.
+ */
+ set_link_state (dum);
+ if (((1 << USB_DEVICE_B_HNP_ENABLE)
+ & dum->devstatus) != 0)
+ dev_dbg (dummy_dev(dum),
+ "no HNP yet!\n");
}
break;
+ case USB_PORT_FEAT_POWER:
+ dum->port_status |= USB_PORT_STAT_POWER;
+ set_link_state (dum);
+ break;
case USB_PORT_FEAT_RESET:
- /* if it's already running, disconnect first */
- if (dum->port_status & USB_PORT_STAT_ENABLE) {
- dum->port_status &= ~(USB_PORT_STAT_ENABLE
- | USB_PORT_STAT_LOW_SPEED
- | USB_PORT_STAT_HIGH_SPEED);
- if (dum->driver) {
- dev_dbg (dummy_dev(dum),
- "disconnect\n");
- stop_activity (dum, dum->driver);
- }
-
- /* FIXME test that code path! */
- }
+ /* if it's already enabled, disable */
+ dum->port_status &= ~(USB_PORT_STAT_ENABLE
+ | USB_PORT_STAT_LOW_SPEED
+ | USB_PORT_STAT_HIGH_SPEED);
+ dum->devstatus = 0;
/* 50msec reset signaling */
dum->re_timeout = jiffies + msecs_to_jiffies(50);
- /* FALLTHROUGH */
+ /* FALLS THROUGH */
default:
- dum->port_status |= (1 << wValue);
+ if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
+ dum->port_status |= (1 << wValue);
+ set_link_state (dum);
+ }
}
break;
@@ -1567,9 +1752,35 @@ static int dummy_hub_control (
retval = -EPIPE;
}
spin_unlock_irqrestore (&dum->lock, flags);
+
+ if ((dum->port_status & PORT_C_MASK) != 0)
+ usb_hcd_poll_rh_status (hcd);
return retval;
}
+static int dummy_hub_suspend (struct usb_hcd *hcd)
+{
+ struct dummy *dum = hcd_to_dummy (hcd);
+
+ spin_lock_irq (&dum->lock);
+ dum->rh_state = DUMMY_RH_SUSPENDED;
+ set_link_state (dum);
+ spin_unlock_irq (&dum->lock);
+ return 0;
+}
+
+static int dummy_hub_resume (struct usb_hcd *hcd)
+{
+ struct dummy *dum = hcd_to_dummy (hcd);
+
+ spin_lock_irq (&dum->lock);
+ dum->rh_state = DUMMY_RH_RUNNING;
+ set_link_state (dum);
+ if (!list_empty(&dum->urbp_list))
+ mod_timer (&dum->timer, jiffies);
+ spin_unlock_irq (&dum->lock);
+ return 0;
+}
/*-------------------------------------------------------------------------*/
@@ -1625,8 +1836,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
static int dummy_start (struct usb_hcd *hcd)
{
struct dummy *dum;
- struct usb_device *root;
- int retval;
dum = hcd_to_dummy (hcd);
@@ -1639,38 +1848,22 @@ static int dummy_start (struct usb_hcd *hcd)
init_timer (&dum->timer);
dum->timer.function = dummy_timer;
dum->timer.data = (unsigned long) dum;
+ dum->rh_state = DUMMY_RH_RUNNING;
INIT_LIST_HEAD (&dum->urbp_list);
- root = usb_alloc_dev (NULL, &hcd->self, 0);
- if (!root)
- return -ENOMEM;
-
- /* root hub enters addressed state... */
- hcd->state = HC_STATE_RUNNING;
- root->speed = USB_SPEED_HIGH;
-
- /* ...then configured, so khubd sees us. */
- if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) {
- goto err1;
- }
-
/* only show a low-power port: just 8mA */
- hub_set_power_budget (root, 8);
+ hcd->power_budget = 8;
+ hcd->state = HC_STATE_RUNNING;
+ hcd->uses_new_polling = 1;
- if ((retval = dummy_register_udc (dum)) != 0)
- goto err2;
+#ifdef CONFIG_USB_OTG
+ hcd->self.otg_port = 1;
+#endif
/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
device_create_file (dummy_dev(dum), &dev_attr_urbs);
return 0;
-
- err2:
- usb_disconnect (&hcd->self.root_hub);
- err1:
- usb_put_dev (root);
- hcd->state = HC_STATE_QUIESCING;
- return retval;
}
static void dummy_stop (struct usb_hcd *hcd)
@@ -1680,10 +1873,7 @@ static void dummy_stop (struct usb_hcd *hcd)
dum = hcd_to_dummy (hcd);
device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-
usb_gadget_unregister_driver (dum->driver);
- dummy_unregister_udc (dum);
-
dev_info (dummy_dev(dum), "stopped\n");
}
@@ -1711,9 +1901,11 @@ static const struct hc_driver dummy_hcd = {
.hub_status_data = dummy_hub_status,
.hub_control = dummy_hub_control,
+ .hub_suspend = dummy_hub_suspend,
+ .hub_resume = dummy_hub_resume,
};
-static int dummy_probe (struct device *dev)
+static int dummy_hcd_probe (struct device *dev)
{
struct usb_hcd *hcd;
int retval;
@@ -1733,7 +1925,7 @@ static int dummy_probe (struct device *dev)
return retval;
}
-static void dummy_remove (struct device *dev)
+static int dummy_hcd_remove (struct device *dev)
{
struct usb_hcd *hcd;
@@ -1741,53 +1933,127 @@ static void dummy_remove (struct device *dev)
usb_remove_hcd (hcd);
usb_put_hcd (hcd);
the_controller = NULL;
+ return 0;
}
-/*-------------------------------------------------------------------------*/
-
-static int dummy_pdev_detect (void)
+static int dummy_hcd_suspend (struct device *dev, pm_message_t state,
+ u32 level)
{
- int retval;
+ struct usb_hcd *hcd;
- retval = driver_register (&dummy_driver);
- if (retval < 0)
- return retval;
+ if (level != SUSPEND_DISABLE)
+ return 0;
+
+ dev_dbg (dev, "%s\n", __FUNCTION__);
+ hcd = dev_get_drvdata (dev);
- the_pdev.name = "hc";
- the_pdev.dev.driver = &dummy_driver;
- the_pdev.dev.release = dummy_pdev_release;
+#ifndef CONFIG_USB_SUSPEND
+ /* Otherwise this would never happen */
+ usb_lock_device (hcd->self.root_hub);
+ dummy_hub_suspend (hcd);
+ usb_unlock_device (hcd->self.root_hub);
+#endif
- retval = platform_device_register (&the_pdev);
- if (retval < 0)
- driver_unregister (&dummy_driver);
- return retval;
+ hcd->state = HC_STATE_SUSPENDED;
+ return 0;
}
-static void dummy_pdev_remove (void)
+static int dummy_hcd_resume (struct device *dev, u32 level)
{
- platform_device_unregister (&the_pdev);
- driver_unregister (&dummy_driver);
+ struct usb_hcd *hcd;
+
+ if (level != RESUME_ENABLE)
+ return 0;
+
+ dev_dbg (dev, "%s\n", __FUNCTION__);
+ hcd = dev_get_drvdata (dev);
+ hcd->state = HC_STATE_RUNNING;
+
+#ifndef CONFIG_USB_SUSPEND
+ /* Otherwise this would never happen */
+ usb_lock_device (hcd->self.root_hub);
+ dummy_hub_resume (hcd);
+ usb_unlock_device (hcd->self.root_hub);
+#endif
+
+ usb_hcd_poll_rh_status (hcd);
+ return 0;
}
+static struct device_driver dummy_hcd_driver = {
+ .name = (char *) driver_name,
+ .bus = &platform_bus_type,
+ .probe = dummy_hcd_probe,
+ .remove = dummy_hcd_remove,
+ .suspend = dummy_hcd_suspend,
+ .resume = dummy_hcd_resume,
+};
+
/*-------------------------------------------------------------------------*/
+/* These don't need to do anything because the pdev structures are
+ * statically allocated. */
+static void
+dummy_udc_release (struct device *dev) {}
+
+static void
+dummy_hcd_release (struct device *dev) {}
+
+static struct platform_device the_udc_pdev = {
+ .name = (char *) gadget_name,
+ .id = -1,
+ .dev = {
+ .release = dummy_udc_release,
+ },
+};
+
+static struct platform_device the_hcd_pdev = {
+ .name = (char *) driver_name,
+ .id = -1,
+ .dev = {
+ .release = dummy_hcd_release,
+ },
+};
+
static int __init init (void)
{
int retval;
if (usb_disabled ())
return -ENODEV;
- if ((retval = dummy_pdev_detect ()) != 0)
+
+ retval = driver_register (&dummy_hcd_driver);
+ if (retval < 0)
return retval;
- if ((retval = dummy_probe (&the_pdev.dev)) != 0)
- dummy_pdev_remove ();
+
+ retval = driver_register (&dummy_udc_driver);
+ if (retval < 0)
+ goto err_register_udc_driver;
+
+ retval = platform_device_register (&the_hcd_pdev);
+ if (retval < 0)
+ goto err_register_hcd;
+
+ retval = platform_device_register (&the_udc_pdev);
+ if (retval < 0)
+ goto err_register_udc;
+ return retval;
+
+err_register_udc:
+ platform_device_unregister (&the_hcd_pdev);
+err_register_hcd:
+ driver_unregister (&dummy_udc_driver);
+err_register_udc_driver:
+ driver_unregister (&dummy_hcd_driver);
return retval;
}
module_init (init);
static void __exit cleanup (void)
{
- dummy_remove (&the_pdev.dev);
- dummy_pdev_remove ();
+ platform_device_unregister (&the_udc_pdev);
+ platform_device_unregister (&the_hcd_pdev);
+ driver_unregister (&dummy_udc_driver);
+ driver_unregister (&dummy_hcd_driver);
}
module_exit (cleanup);
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index 3f783cbdc7c3..8509e955007d 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -84,18 +84,19 @@
*/
#define DRIVER_DESC "Ethernet Gadget"
-#define DRIVER_VERSION "Equinox 2004"
+#define DRIVER_VERSION "May Day 2005"
static const char shortname [] = "ether";
static const char driver_desc [] = DRIVER_DESC;
#define RX_EXTRA 20 /* guard against rx overflows */
-#ifdef CONFIG_USB_ETH_RNDIS
#include "rndis.h"
-#else
-#define rndis_init() 0
-#define rndis_exit() do{}while(0)
+
+#ifndef CONFIG_USB_ETH_RNDIS
+#define rndis_uninit(x) do{}while(0)
+#define rndis_deregister(c) do{}while(0)
+#define rndis_exit() do{}while(0)
#endif
/* CDC and RNDIS support the same host-chosen outgoing packet filters. */
@@ -140,9 +141,6 @@ struct eth_dev {
* It also ASSUMES a self-powered device, without remote wakeup,
* although remote wakeup support would make sense.
*/
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
-static const char *EP_STATUS_NAME;
/*-------------------------------------------------------------------------*/
@@ -312,6 +310,7 @@ static inline int rndis_active(struct eth_dev *dev)
#define FS_BPS (19 * 64 * 1 * 1000 * 8)
#ifdef CONFIG_USB_GADGET_DUALSPEED
+#define DEVSPEED USB_SPEED_HIGH
static unsigned qmult = 5;
module_param (qmult, uint, S_IRUGO|S_IWUSR);
@@ -330,6 +329,8 @@ static inline int BITRATE(struct usb_gadget *g)
}
#else /* full speed (low speed doesn't do bulk) */
+#define DEVSPEED USB_SPEED_FULL
+
#define qlen(gadget) DEFAULT_QLEN
static inline int BITRATE(struct usb_gadget *g)
@@ -395,7 +396,8 @@ static inline int BITRATE(struct usb_gadget *g)
#define STRING_SUBSET 8
#define STRING_RNDIS 9
-#define USB_BUFSIZ 256 /* holds our biggest descriptor */
+/* holds our biggest descriptor (or RNDIS response) */
+#define USB_BUFSIZ 256
/*
* This device advertises one configuration, eth_config, unless RNDIS
@@ -538,7 +540,7 @@ static const struct usb_cdc_call_mgmt_descriptor call_mgmt_descriptor = {
.bDataInterface = 0x01,
};
-static struct usb_cdc_acm_descriptor acm_descriptor = {
+static const struct usb_cdc_acm_descriptor acm_descriptor = {
.bLength = sizeof acm_descriptor,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ACM_TYPE,
@@ -846,7 +848,7 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
#else
/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+#define ep_desc(g,hs,fs) (((void)(g)), (fs))
static inline void __init hs_subset_descriptors(void)
{
@@ -943,13 +945,36 @@ config_buf (enum usb_device_speed speed,
/*-------------------------------------------------------------------------*/
-static void eth_start (struct eth_dev *dev, int gfp_flags);
-static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags);
+static void eth_start (struct eth_dev *dev, unsigned gfp_flags);
+static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags);
-#ifdef DEV_CONFIG_CDC
-static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
+static int
+set_ether_config (struct eth_dev *dev, unsigned gfp_flags)
{
- const struct usb_endpoint_descriptor *d;
+ int result = 0;
+ struct usb_gadget *gadget = dev->gadget;
+
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+ /* status endpoint used for RNDIS and (optionally) CDC */
+ if (!subset_active(dev) && dev->status_ep) {
+ dev->status = ep_desc (gadget, &hs_status_desc,
+ &fs_status_desc);
+ dev->status_ep->driver_data = dev;
+
+ result = usb_ep_enable (dev->status_ep, dev->status);
+ if (result != 0) {
+ DEBUG (dev, "enable %s --> %d\n",
+ dev->status_ep->name, result);
+ goto done;
+ }
+ }
+#endif
+
+ dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+ dev->in_ep->driver_data = dev;
+
+ dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+ dev->out_ep->driver_data = dev;
/* With CDC, the host isn't allowed to use these two data
* endpoints in the default altsetting for the interface.
@@ -959,135 +984,33 @@ static inline int ether_alt_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
* a side effect of setting a packet filter. Deactivation is
* from REMOTE_NDIS_HALT_MSG, reset from REMOTE_NDIS_RESET_MSG.
*/
-
- /* one endpoint writes data back IN to the host */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
- ep->driver_data = dev;
- dev->in = d;
-
- /* one endpoint just reads OUT packets */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
- ep->driver_data = dev;
- dev->out = d;
-
- /* optional status/notification endpoint */
- } else if (EP_STATUS_NAME &&
- strcmp (ep->name, EP_STATUS_NAME) == 0) {
- int result;
-
- d = ep_desc (dev->gadget, &hs_status_desc, &fs_status_desc);
- result = usb_ep_enable (ep, d);
- if (result < 0)
- return result;
-
- ep->driver_data = dev;
- dev->status = d;
- }
- return 0;
-}
-#endif
-
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
-static inline int ether_ep_setup (struct eth_dev *dev, struct usb_ep *ep)
-{
- int result;
- const struct usb_endpoint_descriptor *d;
-
- /* CDC subset is simpler: if the device is there,
- * it's live with rx and tx endpoints.
- *
- * Do this as a shortcut for RNDIS too.
- */
-
- /* one endpoint writes data back IN to the host */
- if (strcmp (ep->name, EP_IN_NAME) == 0) {
- d = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
- result = usb_ep_enable (ep, d);
- if (result < 0)
- return result;
-
- ep->driver_data = dev;
- dev->in = d;
-
- /* one endpoint just reads OUT packets */
- } else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
- d = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
- result = usb_ep_enable (ep, d);
- if (result < 0)
- return result;
-
- ep->driver_data = dev;
- dev->out = d;
- }
-
- return 0;
-}
-#endif
-
-static int
-set_ether_config (struct eth_dev *dev, int gfp_flags)
-{
- int result = 0;
- struct usb_ep *ep;
- struct usb_gadget *gadget = dev->gadget;
-
- gadget_for_each_ep (ep, gadget) {
-#ifdef DEV_CONFIG_CDC
- if (!dev->rndis && dev->cdc) {
- result = ether_alt_ep_setup (dev, ep);
- if (result == 0)
- continue;
+ if (!cdc_active(dev)) {
+ result = usb_ep_enable (dev->in_ep, dev->in);
+ if (result != 0) {
+ DEBUG(dev, "enable %s --> %d\n",
+ dev->in_ep->name, result);
+ goto done;
}
-#endif
-
-#ifdef CONFIG_USB_ETH_RNDIS
- if (dev->rndis && strcmp (ep->name, EP_STATUS_NAME) == 0) {
- const struct usb_endpoint_descriptor *d;
- d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
- result = usb_ep_enable (ep, d);
- if (result == 0) {
- ep->driver_data = dev;
- dev->status = d;
- continue;
- }
- } else
-#endif
- {
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
- result = ether_ep_setup (dev, ep);
- if (result == 0)
- continue;
-#endif
+ result = usb_ep_enable (dev->out_ep, dev->out);
+ if (result != 0) {
+ DEBUG (dev, "enable %s --> %d\n",
+ dev->in_ep->name, result);
+ goto done;
}
-
- /* stop on error */
- ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
- break;
}
- if (!result && (!dev->in_ep || !dev->out_ep))
- result = -ENODEV;
+done:
if (result == 0)
result = alloc_requests (dev, qlen (gadget), gfp_flags);
/* on error, disable any endpoints */
if (result < 0) {
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (dev->status)
+ if (!subset_active(dev))
(void) usb_ep_disable (dev->status_ep);
-#endif
dev->status = NULL;
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
- if (dev->rndis || !dev->cdc) {
- if (dev->in)
- (void) usb_ep_disable (dev->in_ep);
- if (dev->out)
- (void) usb_ep_disable (dev->out_ep);
- }
-#endif
+ (void) usb_ep_disable (dev->in_ep);
+ (void) usb_ep_disable (dev->out_ep);
dev->in = NULL;
dev->out = NULL;
} else
@@ -1095,8 +1018,7 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
/* activate non-CDC configs right away
* this isn't strictly according to the RNDIS spec
*/
-#if defined(DEV_CONFIG_SUBSET) || defined(CONFIG_USB_ETH_RNDIS)
- if (dev->rndis || !dev->cdc) {
+ if (!cdc_active (dev)) {
netif_carrier_on (dev->net);
if (netif_running (dev->net)) {
spin_unlock (&dev->lock);
@@ -1104,7 +1026,6 @@ set_ether_config (struct eth_dev *dev, int gfp_flags)
spin_lock (&dev->lock);
}
}
-#endif
if (result == 0)
DEBUG (dev, "qlen %d\n", qlen (gadget));
@@ -1124,6 +1045,7 @@ static void eth_reset_config (struct eth_dev *dev)
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
+ rndis_uninit(dev->rndis_config);
/* disable endpoints, forcing (synchronous) completion of
* pending i/o. then free the requests.
@@ -1150,6 +1072,8 @@ static void eth_reset_config (struct eth_dev *dev)
if (dev->status) {
usb_ep_disable (dev->status_ep);
}
+ dev->rndis = 0;
+ dev->cdc_filter = 0;
dev->config = 0;
}
@@ -1157,14 +1081,11 @@ static void eth_reset_config (struct eth_dev *dev)
* that returns config descriptors, and altsetting code.
*/
static int
-eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
+eth_set_config (struct eth_dev *dev, unsigned number, unsigned gfp_flags)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
- if (number == dev->config)
- return 0;
-
if (gadget_is_sa1100 (gadget)
&& dev->config
&& atomic_read (&dev->tx_qlen) != 0) {
@@ -1174,12 +1095,8 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
}
eth_reset_config (dev);
- /* default: pass all packets, no multicast filtering */
- dev->cdc_filter = DEFAULT_FILTER;
-
switch (number) {
case DEV_CONFIG_VALUE:
- dev->rndis = 0;
result = set_ether_config (dev, gfp_flags);
break;
#ifdef CONFIG_USB_ETH_RNDIS
@@ -1218,9 +1135,9 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
dev->config = number;
INFO (dev, "%s speed config #%d: %d mA, %s, using %s\n",
speed, number, power, driver_desc,
- dev->rndis
+ rndis_active(dev)
? "RNDIS"
- : (dev->cdc
+ : (cdc_active(dev)
? "CDC Ethernet"
: "CDC Ethernet Subset"));
}
@@ -1231,6 +1148,13 @@ eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
#ifdef DEV_CONFIG_CDC
+/* The interrupt endpoint is used in CDC networking models (Ethernet, ATM)
+ * only to notify the host about link status changes (which we support) or
+ * report completion of some encapsulated command (as used in RNDIS). Since
+ * we want this CDC Ethernet code to be vendor-neutral, we don't use that
+ * command mechanism; and only one status request is ever queued.
+ */
+
static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
{
struct usb_cdc_notification *event = req->buf;
@@ -1259,7 +1183,7 @@ static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
} else if (value != -ECONNRESET)
DEBUG (dev, "event %02x --> %d\n",
event->bNotificationType, value);
- event->bmRequestType = 0xff;
+ req->context = NULL;
}
static void issue_start_status (struct eth_dev *dev)
@@ -1276,6 +1200,8 @@ static void issue_start_status (struct eth_dev *dev)
* a "cancel the whole queue" primitive since any
* unlink-one primitive has way too many error modes.
* here, we "know" toggle is already clear...
+ *
+ * FIXME iff req->context != null just dequeue it
*/
usb_ep_disable (dev->status_ep);
usb_ep_enable (dev->status_ep, dev->status);
@@ -1292,6 +1218,8 @@ static void issue_start_status (struct eth_dev *dev)
req->length = sizeof *event;
req->complete = eth_status_complete;
+ req->context = dev;
+
value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
if (value < 0)
DEBUG (dev, "status buf queue --> %d\n", value);
@@ -1351,9 +1279,9 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct eth_dev *dev = get_gadget_data (gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
- u16 wIndex = (__force u16) ctrl->wIndex;
- u16 wValue = (__force u16) ctrl->wValue;
- u16 wLength = (__force u16) ctrl->wLength;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
/* descriptors just go into the pre-allocated ep0 buffer,
* while config change events may enable network traffic.
@@ -1424,7 +1352,7 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
|| !dev->config
|| wIndex > 1)
break;
- if (!dev->cdc && wIndex != 0)
+ if (!cdc_active(dev) && wIndex != 0)
break;
spin_lock (&dev->lock);
@@ -1456,9 +1384,11 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
/* CDC requires the data transfers not be done from
* the default interface setting ... also, setting
- * the non-default interface clears filters etc.
+ * the non-default interface resets filters etc.
*/
if (wValue == 1) {
+ if (!cdc_active (dev))
+ break;
usb_ep_enable (dev->in_ep, dev->in);
usb_ep_enable (dev->out_ep, dev->out);
dev->cdc_filter = DEFAULT_FILTER;
@@ -1492,11 +1422,11 @@ done_set_intf:
|| !dev->config
|| wIndex > 1)
break;
- if (!(dev->cdc || dev->rndis) && wIndex != 0)
+ if (!(cdc_active(dev) || rndis_active(dev)) && wIndex != 0)
break;
/* for CDC, iff carrier is on, data interface is active. */
- if (dev->rndis || wIndex != 1)
+ if (rndis_active(dev) || wIndex != 1)
*(u8 *)req->buf = 0;
else
*(u8 *)req->buf = netif_carrier_ok (dev->net) ? 1 : 0;
@@ -1509,8 +1439,7 @@ done_set_intf:
* wValue = packet filter bitmap
*/
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
- || !dev->cdc
- || dev->rndis
+ || !cdc_active(dev)
|| wLength != 0
|| wIndex > 1)
break;
@@ -1534,7 +1463,7 @@ done_set_intf:
*/
case USB_CDC_SEND_ENCAPSULATED_COMMAND:
if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
- || !dev->rndis
+ || !rndis_active(dev)
|| wLength > USB_BUFSIZ
|| wValue
|| rndis_control_intf.bInterfaceNumber
@@ -1549,7 +1478,7 @@ done_set_intf:
case USB_CDC_GET_ENCAPSULATED_RESPONSE:
if ((USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE)
== ctrl->bRequestType
- && dev->rndis
+ && rndis_active(dev)
// && wLength >= 0x0400
&& !wValue
&& rndis_control_intf.bInterfaceNumber
@@ -1669,7 +1598,7 @@ static void defer_kevent (struct eth_dev *dev, int flag)
static void rx_complete (struct usb_ep *ep, struct usb_request *req);
static int
-rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
+rx_submit (struct eth_dev *dev, struct usb_request *req, unsigned gfp_flags)
{
struct sk_buff *skb;
int retval = -ENOMEM;
@@ -1688,10 +1617,8 @@ rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
*/
size = (sizeof (struct ethhdr) + dev->net->mtu + RX_EXTRA);
size += dev->out_ep->maxpacket - 1;
-#ifdef CONFIG_USB_ETH_RNDIS
- if (dev->rndis)
+ if (rndis_active(dev))
size += sizeof (struct rndis_packet_msg_type);
-#endif
size -= size % dev->out_ep->maxpacket;
if ((skb = alloc_skb (size + NET_IP_ALIGN, gfp_flags)) == 0) {
@@ -1735,11 +1662,9 @@ static void rx_complete (struct usb_ep *ep, struct usb_request *req)
/* normal completion */
case 0:
skb_put (skb, req->actual);
-#ifdef CONFIG_USB_ETH_RNDIS
/* we know MaxPacketsPerTransfer == 1 here */
- if (dev->rndis)
+ if (rndis_active(dev))
status = rndis_rm_hdr (skb);
-#endif
if (status < 0
|| ETH_HLEN > skb->len
|| skb->len > ETH_FRAME_LEN) {
@@ -1799,7 +1724,7 @@ clean:
}
static int prealloc (struct list_head *list, struct usb_ep *ep,
- unsigned n, int gfp_flags)
+ unsigned n, unsigned gfp_flags)
{
unsigned i;
struct usb_request *req;
@@ -1838,7 +1763,7 @@ extra:
return 0;
}
-static int alloc_requests (struct eth_dev *dev, unsigned n, int gfp_flags)
+static int alloc_requests (struct eth_dev *dev, unsigned n, unsigned gfp_flags)
{
int status;
@@ -1854,13 +1779,11 @@ fail:
return status;
}
-static void rx_fill (struct eth_dev *dev, int gfp_flags)
+static void rx_fill (struct eth_dev *dev, unsigned gfp_flags)
{
struct usb_request *req;
unsigned long flags;
- clear_bit (WORK_RX_MEMORY, &dev->todo);
-
/* fill unused rxq slots with some skb */
spin_lock_irqsave (&dev->lock, flags);
while (!list_empty (&dev->rx_reqs)) {
@@ -1883,11 +1806,9 @@ static void eth_work (void *_dev)
{
struct eth_dev *dev = _dev;
- if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
+ if (test_and_clear_bit (WORK_RX_MEMORY, &dev->todo)) {
if (netif_running (dev->net))
rx_fill (dev, GFP_KERNEL);
- else
- clear_bit (WORK_RX_MEMORY, &dev->todo);
}
if (dev->todo)
@@ -1971,8 +1892,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
* or the hardware can't use skb buffers.
* or there's not enough space for any RNDIS headers we need
*/
-#ifdef CONFIG_USB_ETH_RNDIS
- if (dev->rndis) {
+ if (rndis_active(dev)) {
struct sk_buff *skb_rndis;
skb_rndis = skb_realloc_headroom (skb,
@@ -1985,7 +1905,6 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
rndis_add_hdr (skb);
length = skb->len;
}
-#endif
req->buf = skb->data;
req->context = skb;
req->complete = tx_complete;
@@ -2018,9 +1937,7 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
}
if (retval) {
-#ifdef CONFIG_USB_ETH_RNDIS
drop:
-#endif
dev->stats.tx_dropped++;
dev_kfree_skb_any (skb);
spin_lock_irqsave (&dev->lock, flags);
@@ -2036,27 +1953,31 @@ drop:
#ifdef CONFIG_USB_ETH_RNDIS
-static void rndis_send_media_state (struct eth_dev *dev, int connect)
-{
- if (!dev)
- return;
-
- if (connect) {
- if (rndis_signal_connect (dev->rndis_config))
- return;
- } else {
- if (rndis_signal_disconnect (dev->rndis_config))
- return;
- }
-}
+/* The interrupt endpoint is used in RNDIS to notify the host when messages
+ * other than data packets are available ... notably the REMOTE_NDIS_*_CMPLT
+ * messages, but also REMOTE_NDIS_INDICATE_STATUS_MSG and potentially even
+ * REMOTE_NDIS_KEEPALIVE_MSG.
+ *
+ * The RNDIS control queue is processed by GET_ENCAPSULATED_RESPONSE, and
+ * normally just one notification will be queued.
+ */
+
+static struct usb_request *eth_req_alloc (struct usb_ep *, unsigned, unsigned);
+static void eth_req_free (struct usb_ep *ep, struct usb_request *req);
static void
rndis_control_ack_complete (struct usb_ep *ep, struct usb_request *req)
{
+ struct eth_dev *dev = ep->driver_data;
+
if (req->status || req->actual != req->length)
- DEBUG ((struct eth_dev *) ep->driver_data,
+ DEBUG (dev,
"rndis control ack complete --> %d, %d/%d\n",
req->status, req->actual, req->length);
+ req->context = NULL;
+
+ if (req != dev->stat_req)
+ eth_req_free(ep, req);
}
static int rndis_control_ack (struct net_device *net)
@@ -2071,11 +1992,19 @@ static int rndis_control_ack (struct net_device *net)
return -ENODEV;
}
+ /* in case queue length > 1 */
+ if (resp->context) {
+ resp = eth_req_alloc (dev->status_ep, 8, GFP_ATOMIC);
+ if (!resp)
+ return -ENOMEM;
+ }
+
/* Send RNDIS RESPONSE_AVAILABLE notification;
* USB_CDC_NOTIFY_RESPONSE_AVAILABLE should work too
*/
resp->length = 8;
resp->complete = rndis_control_ack_complete;
+ resp->context = dev;
*((__le32 *) resp->buf) = __constant_cpu_to_le32 (1);
*((__le32 *) resp->buf + 1) = __constant_cpu_to_le32 (0);
@@ -2089,9 +2018,13 @@ static int rndis_control_ack (struct net_device *net)
return 0;
}
+#else
+
+#define rndis_control_ack NULL
+
#endif /* RNDIS */
-static void eth_start (struct eth_dev *dev, int gfp_flags)
+static void eth_start (struct eth_dev *dev, unsigned gfp_flags)
{
DEBUG (dev, "%s\n", __FUNCTION__);
@@ -2101,14 +2034,12 @@ static void eth_start (struct eth_dev *dev, int gfp_flags)
/* and open the tx floodgates */
atomic_set (&dev->tx_qlen, 0);
netif_wake_queue (dev->net);
-#ifdef CONFIG_USB_ETH_RNDIS
- if (dev->rndis) {
+ if (rndis_active(dev)) {
rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3,
BITRATE(dev->gadget)/100);
- rndis_send_media_state (dev, 1);
+ (void) rndis_signal_connect (dev->rndis_config);
}
-#endif
}
static int eth_open (struct net_device *net)
@@ -2149,28 +2080,27 @@ static int eth_stop (struct net_device *net)
}
}
-#ifdef CONFIG_USB_ETH_RNDIS
- if (dev->rndis) {
+ if (rndis_active(dev)) {
rndis_set_param_medium (dev->rndis_config,
NDIS_MEDIUM_802_3, 0);
- rndis_send_media_state (dev, 0);
+ (void) rndis_signal_disconnect (dev->rndis_config);
}
-#endif
return 0;
}
/*-------------------------------------------------------------------------*/
-static struct usb_request *eth_req_alloc (struct usb_ep *ep, unsigned size)
+static struct usb_request *
+eth_req_alloc (struct usb_ep *ep, unsigned size, unsigned gfp_flags)
{
struct usb_request *req;
- req = usb_ep_alloc_request (ep, GFP_KERNEL);
+ req = usb_ep_alloc_request (ep, gfp_flags);
if (!req)
return NULL;
- req->buf = kmalloc (size, GFP_KERNEL);
+ req->buf = kmalloc (size, gfp_flags);
if (!req->buf) {
usb_ep_free_request (ep, req);
req = NULL;
@@ -2192,10 +2122,8 @@ eth_unbind (struct usb_gadget *gadget)
struct eth_dev *dev = get_gadget_data (gadget);
DEBUG (dev, "unbind\n");
-#ifdef CONFIG_USB_ETH_RNDIS
rndis_deregister (dev->rndis_config);
rndis_exit ();
-#endif
/* we've already been disconnected ... no i/o is active */
if (dev->req) {
@@ -2368,13 +2296,11 @@ autoconf_fail:
gadget->name);
return -ENODEV;
}
- EP_IN_NAME = in_ep->name;
in_ep->driver_data = in_ep; /* claim */
out_ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
if (!out_ep)
goto autoconf_fail;
- EP_OUT_NAME = out_ep->name;
out_ep->driver_data = out_ep; /* claim */
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
@@ -2384,7 +2310,6 @@ autoconf_fail:
if (cdc || rndis) {
status_ep = usb_ep_autoconfig (gadget, &fs_status_desc);
if (status_ep) {
- EP_STATUS_NAME = status_ep->name;
status_ep->driver_data = status_ep; /* claim */
} else if (rndis) {
dev_err (&gadget->dev,
@@ -2426,7 +2351,7 @@ autoconf_fail:
hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
- if (EP_STATUS_NAME)
+ if (status_ep)
hs_status_desc.bEndpointAddress =
fs_status_desc.bEndpointAddress;
#endif
@@ -2499,20 +2424,23 @@ autoconf_fail:
SET_ETHTOOL_OPS(net, &ops);
/* preallocate control message data and buffer */
- dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ);
+ dev->req = eth_req_alloc (gadget->ep0, USB_BUFSIZ, GFP_KERNEL);
if (!dev->req)
goto fail;
dev->req->complete = eth_setup_complete;
/* ... and maybe likewise for status transfer */
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
if (dev->status_ep) {
dev->stat_req = eth_req_alloc (dev->status_ep,
- STATUS_BYTECOUNT);
+ STATUS_BYTECOUNT, GFP_KERNEL);
if (!dev->stat_req) {
eth_req_free (gadget->ep0, dev->req);
goto fail;
}
+ dev->stat_req->context = NULL;
}
+#endif
/* finish hookup to lower layer ... */
dev->gadget = gadget;
@@ -2526,16 +2454,16 @@ autoconf_fail:
netif_stop_queue (dev->net);
netif_carrier_off (dev->net);
- // SET_NETDEV_DEV (dev->net, &gadget->dev);
+ SET_NETDEV_DEV (dev->net, &gadget->dev);
status = register_netdev (dev->net);
if (status < 0)
goto fail1;
INFO (dev, "%s, version: " DRIVER_VERSION "\n", driver_desc);
INFO (dev, "using %s, OUT %s IN %s%s%s\n", gadget->name,
- EP_OUT_NAME, EP_IN_NAME,
- EP_STATUS_NAME ? " STATUS " : "",
- EP_STATUS_NAME ? EP_STATUS_NAME : ""
+ out_ep->name, in_ep->name,
+ status_ep ? " STATUS " : "",
+ status_ep ? status_ep->name : ""
);
INFO (dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
net->dev_addr [0], net->dev_addr [1],
@@ -2548,7 +2476,6 @@ autoconf_fail:
dev->host_mac [2], dev->host_mac [3],
dev->host_mac [4], dev->host_mac [5]);
-#ifdef CONFIG_USB_ETH_RNDIS
if (rndis) {
u32 vendorID = 0;
@@ -2565,7 +2492,7 @@ fail0:
/* these set up a lot of the OIDs that RNDIS needs */
rndis_set_host_mac (dev->rndis_config, dev->host_mac);
if (rndis_set_param_dev (dev->rndis_config, dev->net,
- &dev->stats))
+ &dev->stats, &dev->cdc_filter))
goto fail0;
if (rndis_set_param_vendor (dev->rndis_config, vendorID,
manufacturer))
@@ -2576,7 +2503,6 @@ fail0:
goto fail0;
INFO (dev, "RNDIS ready\n");
}
-#endif
return status;
@@ -2610,11 +2536,8 @@ eth_resume (struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static struct usb_gadget_driver eth_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
- .speed = USB_SPEED_HIGH,
-#else
- .speed = USB_SPEED_FULL,
-#endif
+ .speed = DEVSPEED,
+
.function = (char *) driver_desc,
.bind = eth_bind,
.unbind = eth_unbind,
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 037a7f163822..4f57085619b4 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -81,6 +81,10 @@
* removable Default false, boolean for removable media
* luns=N Default N = number of filenames, number of
* LUNs to support
+ * stall Default determined according to the type of
+ * USB device controller (usually true),
+ * boolean to permit the driver to halt
+ * bulk endpoints
* 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;
@@ -91,14 +95,10 @@
* buflen=N Default N=16384, buffer size used (will be
* rounded down to a multiple of
* PAGE_CACHE_SIZE)
- * stall Default determined according to the type of
- * USB device controller (usually true),
- * boolean to permit the driver to halt
- * bulk endpoints
*
* 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.
+ * "removable", "luns", and "stall" 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<n> subdirectory of the
@@ -342,14 +342,15 @@ static struct {
int num_ros;
unsigned int nluns;
+ int removable;
+ int can_stall;
+
char *transport_parm;
char *protocol_parm;
- int removable;
unsigned short vendor;
unsigned short product;
unsigned short release;
unsigned int buflen;
- int can_stall;
int transport_type;
char *transport_name;
@@ -360,11 +361,11 @@ static struct {
.transport_parm = "BBB",
.protocol_parm = "SCSI",
.removable = 0,
+ .can_stall = 1,
.vendor = DRIVER_VENDOR_ID,
.product = DRIVER_PRODUCT_ID,
.release = 0xffff, // Use controller chip type
.buflen = 16384,
- .can_stall = 1,
};
@@ -380,6 +381,9 @@ MODULE_PARM_DESC(luns, "number of LUNs");
module_param_named(removable, mod_data.removable, bool, S_IRUGO);
MODULE_PARM_DESC(removable, "true to simulate removable media");
+module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
+MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
+
/* In the non-TEST version, only the module parameters listed above
* are available. */
@@ -404,9 +408,6 @@ MODULE_PARM_DESC(release, "USB release number");
module_param_named(buflen, mod_data.buflen, uint, S_IRUGO);
MODULE_PARM_DESC(buflen, "I/O buffer size");
-module_param_named(stall, mod_data.can_stall, bool, S_IRUGO);
-MODULE_PARM_DESC(stall, "false to prevent bulk stalls");
-
#endif /* CONFIG_USB_FILE_STORAGE_TEST */
@@ -818,7 +819,7 @@ static void inline put_be32(u8 *buf, u32 val)
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
- buf[3] = val;
+ buf[3] = val & 0xff;
}
@@ -1276,8 +1277,8 @@ static int class_setup_req(struct fsg_dev *fsg,
{
struct usb_request *req = fsg->ep0req;
int value = -EOPNOTSUPP;
- u16 w_index = ctrl->wIndex;
- u16 w_length = ctrl->wLength;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
if (!fsg->config)
return value;
@@ -1312,7 +1313,7 @@ static int class_setup_req(struct fsg_dev *fsg,
}
VDBG(fsg, "get max LUN\n");
*(u8 *) req->buf = fsg->nluns - 1;
- value = min(w_length, (u16) 1);
+ value = 1;
break;
}
}
@@ -1344,7 +1345,7 @@ static int class_setup_req(struct fsg_dev *fsg,
"unknown class-specific control req "
"%02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
- ctrl->wValue, w_index, w_length);
+ le16_to_cpu(ctrl->wValue), w_index, w_length);
return value;
}
@@ -1358,9 +1359,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
{
struct usb_request *req = fsg->ep0req;
int value = -EOPNOTSUPP;
- u16 w_index = ctrl->wIndex;
- u16 w_value = ctrl->wValue;
- u16 w_length = ctrl->wLength;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
/* Usually this just stores reply data in the pre-allocated ep0 buffer,
* but config change events will also reconfigure hardware. */
@@ -1374,7 +1374,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
case USB_DT_DEVICE:
VDBG(fsg, "get device descriptor\n");
- value = min(w_length, (u16) sizeof device_desc);
+ value = sizeof device_desc;
memcpy(req->buf, &device_desc, value);
break;
#ifdef CONFIG_USB_GADGET_DUALSPEED
@@ -1382,7 +1382,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
VDBG(fsg, "get device qualifier\n");
if (!fsg->gadget->is_dualspeed)
break;
- value = min(w_length, (u16) sizeof dev_qualifier);
+ value = sizeof dev_qualifier;
memcpy(req->buf, &dev_qualifier, value);
break;
@@ -1401,8 +1401,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
req->buf,
w_value >> 8,
w_value & 0xff);
- if (value >= 0)
- value = min(w_length, (u16) value);
break;
case USB_DT_STRING:
@@ -1411,8 +1409,6 @@ static int standard_setup_req(struct fsg_dev *fsg,
/* wIndex == language code */
value = usb_gadget_get_string(&stringtab,
w_value & 0xff, req->buf);
- if (value >= 0)
- value = min(w_length, (u16) value);
break;
}
break;
@@ -1438,7 +1434,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
break;
VDBG(fsg, "get configuration\n");
*(u8 *) req->buf = fsg->config;
- value = min(w_length, (u16) 1);
+ value = 1;
break;
case USB_REQ_SET_INTERFACE:
@@ -1466,14 +1462,14 @@ static int standard_setup_req(struct fsg_dev *fsg,
}
VDBG(fsg, "get interface\n");
*(u8 *) req->buf = 0;
- value = min(w_length, (u16) 1);
+ value = 1;
break;
default:
VDBG(fsg,
"unknown control req %02x.%02x v%04x i%04x l%u\n",
ctrl->bRequestType, ctrl->bRequest,
- w_value, w_index, w_length);
+ w_value, w_index, le16_to_cpu(ctrl->wLength));
}
return value;
@@ -1485,6 +1481,7 @@ static int fsg_setup(struct usb_gadget *gadget,
{
struct fsg_dev *fsg = get_gadget_data(gadget);
int rc;
+ int w_length = le16_to_cpu(ctrl->wLength);
++fsg->ep0_req_tag; // Record arrival of a new request
fsg->ep0req->context = NULL;
@@ -1498,9 +1495,9 @@ static int fsg_setup(struct usb_gadget *gadget,
/* Respond with data/status or defer until later? */
if (rc >= 0 && rc != DELAYED_STATUS) {
+ rc = min(rc, w_length);
fsg->ep0req->length = rc;
- fsg->ep0req->zero = (rc < ctrl->wLength &&
- (rc % gadget->ep0->maxpacket) == 0);
+ fsg->ep0req->zero = rc < w_length;
fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ?
"ep0-in" : "ep0-out");
rc = ep0_queue(fsg);
@@ -1554,8 +1551,7 @@ static int sleep_thread(struct fsg_dev *fsg)
rc = wait_event_interruptible(fsg->thread_wqh,
fsg->thread_wakeup_needed);
fsg->thread_wakeup_needed = 0;
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
return (rc ? -EINTR : 0);
}
@@ -2661,7 +2657,7 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
}
}
- /* Check that the LUN values are oonsistent */
+ /* Check that the LUN values are consistent */
if (transport_is_bbb()) {
if (fsg->lun != lun)
DBG(fsg, "using LUN %d from CBW, "
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 005db7cca292..eaab26f4ed37 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -70,7 +70,7 @@ MODULE_LICENSE("GPL");
* seem to behave quite as expected. Used by default.
*
* OUT dma documents design problems handling the common "short packet"
- * transfer termination policy; it couldn't enabled by default, even
+ * transfer termination policy; it couldn't be enabled by default, even
* if the OUT-dma abort problems had a resolution.
*/
static unsigned use_dma = 1;
@@ -269,7 +269,7 @@ static int goku_ep_disable(struct usb_ep *_ep)
/*-------------------------------------------------------------------------*/
static struct usb_request *
-goku_alloc_request(struct usb_ep *_ep, int gfp_flags)
+goku_alloc_request(struct usb_ep *_ep, unsigned gfp_flags)
{
struct goku_request *req;
@@ -313,7 +313,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
#if defined(CONFIG_X86)
#define USE_KMALLOC
-#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
#define USE_KMALLOC
#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -327,7 +327,7 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
*/
static void *
goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, int gfp_flags)
+ dma_addr_t *dma, unsigned gfp_flags)
{
void *retval;
struct goku_ep *ep;
@@ -789,7 +789,7 @@ finished:
/*-------------------------------------------------------------------------*/
static int
-goku_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+goku_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags)
{
struct goku_request *req;
struct goku_ep *ep;
@@ -1524,9 +1524,12 @@ static void ep0_setup(struct goku_udc *dev)
/* read SETUP packet and enter DATA stage */
ctrl.bRequestType = readl(&regs->bRequestType);
ctrl.bRequest = readl(&regs->bRequest);
- ctrl.wValue = (readl(&regs->wValueH) << 8) | readl(&regs->wValueL);
- ctrl.wIndex = (readl(&regs->wIndexH) << 8) | readl(&regs->wIndexL);
- ctrl.wLength = (readl(&regs->wLengthH) << 8) | readl(&regs->wLengthL);
+ ctrl.wValue = cpu_to_le16((readl(&regs->wValueH) << 8)
+ | readl(&regs->wValueL));
+ ctrl.wIndex = cpu_to_le16((readl(&regs->wIndexH) << 8)
+ | readl(&regs->wIndexL));
+ ctrl.wLength = cpu_to_le16((readl(&regs->wLengthH) << 8)
+ | readl(&regs->wLengthL));
writel(0, &regs->SetupRecv);
nuke(&dev->ep[0], 0);
@@ -1548,18 +1551,20 @@ static void ep0_setup(struct goku_udc *dev)
case USB_REQ_CLEAR_FEATURE:
switch (ctrl.bRequestType) {
case USB_RECIP_ENDPOINT:
- tmp = ctrl.wIndex & 0x0f;
+ tmp = le16_to_cpu(ctrl.wIndex) & 0x0f;
/* active endpoint */
if (tmp > 3 || (!dev->ep[tmp].desc && tmp != 0))
goto stall;
- if (ctrl.wIndex & USB_DIR_IN) {
+ if (ctrl.wIndex & __constant_cpu_to_le16(
+ USB_DIR_IN)) {
if (!dev->ep[tmp].is_in)
goto stall;
} else {
if (dev->ep[tmp].is_in)
goto stall;
}
- if (ctrl.wValue != USB_ENDPOINT_HALT)
+ if (ctrl.wValue != __constant_cpu_to_le16(
+ USB_ENDPOINT_HALT))
goto stall;
if (tmp)
goku_clear_halt(&dev->ep[tmp]);
@@ -1571,7 +1576,7 @@ succeed:
return;
case USB_RECIP_DEVICE:
/* device remote wakeup: always clear */
- if (ctrl.wValue != 1)
+ if (ctrl.wValue != __constant_cpu_to_le16(1))
goto stall;
VDBG(dev, "clear dev remote wakeup\n");
goto succeed;
@@ -1589,14 +1594,15 @@ succeed:
#ifdef USB_TRACE
VDBG(dev, "SETUP %02x.%02x v%04x i%04x l%04x\n",
ctrl.bRequestType, ctrl.bRequest,
- ctrl.wValue, ctrl.wIndex, ctrl.wLength);
+ le16_to_cpu(ctrl.wValue), le16_to_cpu(ctrl.wIndex),
+ le16_to_cpu(ctrl.wLength));
#endif
/* hw wants to know when we're configured (or not) */
dev->req_config = (ctrl.bRequest == USB_REQ_SET_CONFIGURATION
&& ctrl.bRequestType == USB_RECIP_DEVICE);
if (unlikely(dev->req_config))
- dev->configured = (ctrl.wValue != 0);
+ dev->configured = (ctrl.wValue != __constant_cpu_to_le16(0));
/* delegate everything to the gadget driver.
* it may respond after this irq handler returns.
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 1e5e6ddef787..020815397a49 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -417,8 +417,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
goto free1;
value = ep_io (data, kbuf, len);
- VDEBUG (data->dev, "%s read %d OUT, status %d\n",
- data->name, len, value);
+ VDEBUG (data->dev, "%s read %zu OUT, status %d\n",
+ data->name, len, (int) value);
if (value >= 0 && copy_to_user (buf, kbuf, value))
value = -EFAULT;
@@ -465,8 +465,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
}
value = ep_io (data, kbuf, len);
- VDEBUG (data->dev, "%s write %d IN, status %d\n",
- data->name, len, value);
+ VDEBUG (data->dev, "%s write %zu IN, status %d\n",
+ data->name, len, (int) value);
free1:
up (&data->lock);
kfree (kbuf);
@@ -1318,8 +1318,8 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
struct usb_gadgetfs_event *event;
- u16 w_value = ctrl->wValue;
- u16 w_length = ctrl->wLength;
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
spin_lock (&dev->lock);
dev->setup_abort = 0;
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index df75ab65a5ec..4842577789c9 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -1106,7 +1106,7 @@ static int lh7a40x_ep_disable(struct usb_ep *_ep)
}
static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep,
- int gfp_flags)
+ unsigned gfp_flags)
{
struct lh7a40x_request *req;
@@ -1134,7 +1134,7 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
}
static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
- dma_addr_t * dma, int gfp_flags)
+ dma_addr_t * dma, unsigned gfp_flags)
{
char *retval;
@@ -1158,7 +1158,7 @@ static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
* NOTE: Sets INDEX register
*/
static int lh7a40x_queue(struct usb_ep *_ep, struct usb_request *_req,
- int gfp_flags)
+ unsigned gfp_flags)
{
struct lh7a40x_request *req;
struct lh7a40x_ep *ep;
diff --git a/drivers/usb/gadget/ndis.h b/drivers/usb/gadget/ndis.h
index c553bbf68cab..09e3ee4eeae1 100644
--- a/drivers/usb/gadget/ndis.h
+++ b/drivers/usb/gadget/ndis.h
@@ -47,17 +47,17 @@ struct NDIS_PM_WAKE_UP_CAPABILITIES {
#define NDIS_DEVICE_WAKE_ON_MAGIC_PACKET_ENABLE 0x00000004
struct NDIS_PNP_CAPABILITIES {
- u32 Flags;
+ __le32 Flags;
struct NDIS_PM_WAKE_UP_CAPABILITIES WakeUpCapabilities;
};
struct NDIS_PM_PACKET_PATTERN {
- u32 Priority;
- u32 Reserved;
- u32 MaskSize;
- u32 PatternOffset;
- u32 PatternSize;
- u32 PatternFlags;
+ __le32 Priority;
+ __le32 Reserved;
+ __le32 MaskSize;
+ __le32 PatternOffset;
+ __le32 PatternSize;
+ __le32 PatternFlags;
};
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index e47e398daeb5..477fab2e74d1 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -376,7 +376,7 @@ static int net2280_disable (struct usb_ep *_ep)
/*-------------------------------------------------------------------------*/
static struct usb_request *
-net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
+net2280_alloc_request (struct usb_ep *_ep, unsigned gfp_flags)
{
struct net2280_ep *ep;
struct net2280_request *req;
@@ -448,7 +448,7 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
#elif defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
#define USE_KMALLOC
-#elif defined(CONFIG_MIPS) && !defined(CONFIG_NONCOHERENT_IO)
+#elif defined(CONFIG_MIPS) && !defined(CONFIG_DMA_NONCOHERENT)
#define USE_KMALLOC
/* FIXME there are other cases, including an x86-64 one ... */
@@ -463,7 +463,7 @@ net2280_alloc_buffer (
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
- int gfp_flags
+ unsigned gfp_flags
)
{
void *retval;
@@ -897,7 +897,7 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status)
/*-------------------------------------------------------------------------*/
static int
-net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+net2280_queue (struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags)
{
struct net2280_request *req;
struct net2280_ep *ep;
@@ -1113,7 +1113,7 @@ static void restart_dma (struct net2280_ep *ep)
if (ep->in_fifo_validate)
dmactl |= (1 << DMA_FIFO_VALIDATE);
list_for_each_entry (entry, &ep->queue, queue) {
- u32 dmacount;
+ __le32 dmacount;
if (entry == req)
continue;
@@ -1238,7 +1238,7 @@ static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
&ep->dma->dmadesc);
if (req->td->dmacount & dma_done_ie)
writel (readl (&ep->dma->dmacount)
- | dma_done_ie,
+ | le32_to_cpu(dma_done_ie),
&ep->dma->dmacount);
} else {
struct net2280_request *prev;
@@ -1490,7 +1490,7 @@ show_registers (struct device *_dev, struct device_attribute *attr, char *buf)
unsigned long flags;
int i;
u32 t1, t2;
- char *s;
+ const char *s;
dev = dev_get_drvdata (_dev);
next = buf;
@@ -1779,6 +1779,9 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
}
+/* just declare this in any driver that really need it */
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
/**
* net2280_set_fifo_mode - change allocation of fifo buffers
* @gadget: access to the net2280 device that will be updated
@@ -2382,9 +2385,9 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
cpu_to_le32s (&u.raw [0]);
cpu_to_le32s (&u.raw [1]);
- le16_to_cpus (&u.r.wValue);
- le16_to_cpus (&u.r.wIndex);
- le16_to_cpus (&u.r.wLength);
+#define w_value le16_to_cpup (&u.r.wValue)
+#define w_index le16_to_cpup (&u.r.wIndex)
+#define w_length le16_to_cpup (&u.r.wLength)
/* ack the irq */
writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
@@ -2413,25 +2416,25 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
switch (u.r.bRequest) {
case USB_REQ_GET_STATUS: {
struct net2280_ep *e;
- u16 status;
+ __le32 status;
/* hw handles device and interface status */
if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
goto delegate;
- if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
- || u.r.wLength > 2)
+ if ((e = get_ep_by_addr (dev, w_index)) == 0
+ || w_length > 2)
goto do_stall;
if (readl (&e->regs->ep_rsp)
& (1 << SET_ENDPOINT_HALT))
- status = __constant_cpu_to_le16 (1);
+ status = __constant_cpu_to_le32 (1);
else
- status = __constant_cpu_to_le16 (0);
+ status = __constant_cpu_to_le32 (0);
/* don't bother with a request object! */
writel (0, &dev->epregs [0].ep_irqenb);
- set_fifo_bytecount (ep, u.r.wLength);
- writel (status, &dev->epregs [0].ep_data);
+ set_fifo_bytecount (ep, w_length);
+ writel ((__force u32)status, &dev->epregs [0].ep_data);
allow_status (ep);
VDEBUG (dev, "%s stat %02x\n", ep->ep.name, status);
goto next_endpoints;
@@ -2443,10 +2446,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device features */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT
- || u.r.wLength != 0)
+ if (w_value != USB_ENDPOINT_HALT
+ || w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
clear_halt (e);
allow_status (ep);
@@ -2460,10 +2463,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
/* hw handles device features */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT
- || u.r.wLength != 0)
+ if (w_value != USB_ENDPOINT_HALT
+ || w_length != 0)
goto do_stall;
- if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+ if ((e = get_ep_by_addr (dev, w_index)) == 0)
goto do_stall;
set_halt (e);
allow_status (ep);
@@ -2473,10 +2476,10 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
break;
default:
delegate:
- VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+ VDEBUG (dev, "setup %02x.%02x v%04x i%04x l%04x"
"ep_cfg %08x\n",
u.r.bRequestType, u.r.bRequest,
- u.r.wValue, u.r.wIndex,
+ w_value, w_index, w_length,
readl (&ep->regs->ep_cfg));
spin_unlock (&dev->lock);
tmp = dev->driver->setup (&dev->gadget, &u.r);
@@ -2497,6 +2500,10 @@ do_stall:
*/
}
+#undef w_value
+#undef w_index
+#undef w_length
+
next_endpoints:
/* endpoint data irq ? */
scratch = stat & 0x7f;
@@ -2653,7 +2660,7 @@ static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
restart_dma (ep);
else if (ep->is_in && use_dma_chaining) {
struct net2280_request *req;
- u32 dmacount;
+ __le32 dmacount;
/* the descriptor at the head of the chain
* may still have VALID_BIT clear; that's
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 98cbcbc16cc1..ff5533e69560 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -52,7 +52,6 @@
#include <asm/mach-types.h>
#include <asm/arch/dma.h>
-#include <asm/arch/mux.h>
#include <asm/arch/usb.h>
#include "omap_udc.h"
@@ -167,7 +166,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
maxp = le16_to_cpu (desc->wMaxPacketSize);
if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
&& maxp != ep->maxpacket)
- || desc->wMaxPacketSize > ep->maxpacket
+ || le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
|| !desc->wMaxPacketSize) {
DBG("%s, bad %s maxpacket\n", __FUNCTION__, _ep->name);
return -ERANGE;
@@ -214,7 +213,7 @@ static int omap_ep_enable(struct usb_ep *_ep,
ep->has_dma = 0;
ep->lch = -1;
use_ep(ep, UDC_EP_SEL);
- UDC_CTRL_REG = UDC_RESET_EP;
+ UDC_CTRL_REG = udc->clr_halt;
ep->ackwait = 0;
deselect_ep();
@@ -253,7 +252,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
}
spin_lock_irqsave(&ep->udc->lock, flags);
- ep->desc = 0;
+ ep->desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
ep->has_dma = 0;
@@ -270,7 +269,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
/*-------------------------------------------------------------------------*/
static struct usb_request *
-omap_alloc_request(struct usb_ep *ep, int gfp_flags)
+omap_alloc_request(struct usb_ep *ep, unsigned gfp_flags)
{
struct omap_req *req;
@@ -299,7 +298,7 @@ omap_alloc_buffer(
struct usb_ep *_ep,
unsigned bytes,
dma_addr_t *dma,
- int gfp_flags
+ unsigned gfp_flags
)
{
void *retval;
@@ -388,8 +387,8 @@ done(struct omap_ep *ep, struct omap_req *req, int status)
/*-------------------------------------------------------------------------*/
-#define FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
-#define FIFO_UNWRITABLE (UDC_EP_HALTED | FIFO_FULL)
+#define UDC_FIFO_FULL (UDC_NON_ISO_FIFO_FULL | UDC_ISO_FIFO_FULL)
+#define UDC_FIFO_UNWRITABLE (UDC_EP_HALTED | UDC_FIFO_FULL)
#define FIFO_EMPTY (UDC_NON_ISO_FIFO_EMPTY | UDC_ISO_FIFO_EMPTY)
#define FIFO_UNREADABLE (UDC_EP_HALTED | FIFO_EMPTY)
@@ -433,7 +432,7 @@ static int write_fifo(struct omap_ep *ep, struct omap_req *req)
/* PIO-IN isn't double buffered except for iso */
ep_stat = UDC_STAT_FLG_REG;
- if (ep_stat & FIFO_UNWRITABLE)
+ if (ep_stat & UDC_FIFO_UNWRITABLE)
return 0;
count = ep->ep.maxpacket;
@@ -504,7 +503,7 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
if (ep_stat & UDC_EP_HALTED)
break;
- if (ep_stat & FIFO_FULL)
+ if (ep_stat & UDC_FIFO_FULL)
avail = ep->ep.maxpacket;
else {
avail = UDC_RXFSTAT_REG;
@@ -538,6 +537,32 @@ static int read_fifo(struct omap_ep *ep, struct omap_req *req)
/*-------------------------------------------------------------------------*/
+static inline dma_addr_t dma_csac(unsigned lch)
+{
+ dma_addr_t csac;
+
+ /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ csac = omap_readw(OMAP_DMA_CSAC(lch));
+ if (csac == 0)
+ csac = omap_readw(OMAP_DMA_CSAC(lch));
+ return csac;
+}
+
+static inline dma_addr_t dma_cdac(unsigned lch)
+{
+ dma_addr_t cdac;
+
+ /* omap 3.2/3.3 erratum: sometimes 0 is returned if CSAC/CDAC is
+ * read before the DMA controller finished disabling the channel.
+ */
+ cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ if (cdac == 0)
+ cdac = omap_readw(OMAP_DMA_CDAC(lch));
+ return cdac;
+}
+
static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
@@ -548,7 +573,7 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
if (cpu_is_omap15xx())
return 0;
- end = omap_readw(OMAP_DMA_CSAC(ep->lch));
+ end = dma_csac(ep->lch);
if (end == ep->dma_counter)
return 0;
@@ -559,14 +584,14 @@ static u16 dma_src_len(struct omap_ep *ep, dma_addr_t start)
}
#define DMA_DEST_LAST(x) (cpu_is_omap15xx() \
- ? OMAP_DMA_CSAC(x) /* really: CPC */ \
- : OMAP_DMA_CDAC(x))
+ ? omap_readw(OMAP_DMA_CSAC(x)) /* really: CPC */ \
+ : dma_cdac(x))
static u16 dma_dest_len(struct omap_ep *ep, dma_addr_t start)
{
dma_addr_t end;
- end = omap_readw(DMA_DEST_LAST(ep->lch));
+ end = DMA_DEST_LAST(ep->lch);
if (end == ep->dma_counter)
return 0;
@@ -593,7 +618,7 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
: OMAP_DMA_SYNC_ELEMENT;
/* measure length in either bytes or packets */
- if ((cpu_is_omap16xx() && length <= (UDC_TXN_TSC + 1))
+ if ((cpu_is_omap16xx() && length <= UDC_TXN_TSC)
|| (cpu_is_omap15xx() && length < ep->maxpacket)) {
txdma_ctrl = UDC_TXN_EOT | length;
omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S8,
@@ -602,15 +627,15 @@ static void next_in_dma(struct omap_ep *ep, struct omap_req *req)
length = min(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, sync_mode);
+ omap_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+ ep->ep.maxpacket >> 1, length, sync_mode);
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);
- ep->dma_counter = omap_readw(OMAP_DMA_CSAC(ep->lch));
+ ep->dma_counter = dma_csac(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;
@@ -650,12 +675,12 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
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_set_dma_transfer_params(ep->lch, OMAP_DMA_DATA_TYPE_S16,
+ ep->ep.maxpacket >> 1, 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);
- ep->dma_counter = omap_readw(DMA_DEST_LAST(ep->lch));
+ ep->dma_counter = DMA_DEST_LAST(ep->lch);
UDC_RXDMA_REG(ep->dma_channel) = UDC_RXN_STOP | (packets - 1);
UDC_DMA_IRQ_EN_REG |= UDC_RX_EOT_IE(ep->dma_channel);
@@ -763,7 +788,7 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
reg = UDC_TXDMA_CFG_REG;
else
reg = UDC_RXDMA_CFG_REG;
- reg |= 1 << 12; /* "pulse" activated */
+ reg |= UDC_DMA_REQ; /* "pulse" activated */
ep->dma_channel = 0;
ep->lch = -1;
@@ -787,6 +812,11 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_TXDMA_CFG_REG = reg;
+ /* EMIFF */
+ omap_set_dma_src_burst_mode(ep->lch,
+ OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_src_data_pack(ep->lch, 1);
+ /* TIPB */
omap_set_dma_dest_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
@@ -797,10 +827,15 @@ static void dma_channel_claim(struct omap_ep *ep, unsigned channel)
ep->ep.name, dma_error, ep, &ep->lch);
if (status == 0) {
UDC_RXDMA_CFG_REG = reg;
+ /* TIPB */
omap_set_dma_src_params(ep->lch,
OMAP_DMA_PORT_TIPB,
OMAP_DMA_AMODE_CONSTANT,
(unsigned long) io_v2p((u32)&UDC_DATA_DMA_REG));
+ /* EMIFF */
+ omap_set_dma_dest_burst_mode(ep->lch,
+ OMAP_DMA_DATA_BURST_4);
+ omap_set_dma_dest_data_pack(ep->lch, 1);
}
}
if (status)
@@ -856,7 +891,7 @@ static void dma_channel_release(struct omap_ep *ep)
if (!list_empty(&ep->queue))
req = container_of(ep->queue.next, struct omap_req, queue);
else
- req = 0;
+ req = NULL;
active = ((1 << 7) & omap_readl(OMAP_DMA_CCR(ep->lch))) != 0;
@@ -865,9 +900,13 @@ static void dma_channel_release(struct omap_ep *ep)
(ep->bEndpointAddress & USB_DIR_IN) ? 't' : 'r',
ep->dma_channel - 1, req);
+ /* NOTE: re-setting RX_REQ/TX_REQ because of a chip bug (before
+ * OMAP 1710 ES2.0) where reading the DMA_CFG can clear them.
+ */
+
/* wait till current packet DMA finishes, and fifo empties */
if (ep->bEndpointAddress & USB_DIR_IN) {
- UDC_TXDMA_CFG_REG &= ~mask;
+ UDC_TXDMA_CFG_REG = (UDC_TXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
if (req) {
finish_in_dma(ep, req, -ECONNRESET);
@@ -880,7 +919,7 @@ static void dma_channel_release(struct omap_ep *ep)
while (UDC_TXDMA_CFG_REG & mask)
udelay(10);
} else {
- UDC_RXDMA_CFG_REG &= ~mask;
+ UDC_RXDMA_CFG_REG = (UDC_RXDMA_CFG_REG & ~mask) | UDC_DMA_REQ;
/* dma empties the fifo */
while (UDC_RXDMA_CFG_REG & mask)
@@ -898,7 +937,7 @@ static void dma_channel_release(struct omap_ep *ep)
/*-------------------------------------------------------------------------*/
static int
-omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags)
{
struct omap_ep *ep = container_of(_ep, struct omap_ep, ep);
struct omap_req *req = container_of(_req, struct omap_req, req);
@@ -997,18 +1036,19 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
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);
+ /* STATUS for zero length DATA stages is
+ * always an IN ... even for IN transfers,
+ * a wierd case which seem to stall OMAP.
+ */
+ 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->ep0_in ? 0 : UDC_EP_DIR;
+ UDC_EP_NUM_REG = UDC_EP_DIR;
/* cleanup */
udc->ep0_pending = 0;
done(ep, req, 0);
- req = 0;
+ req = NULL;
/* non-empty DATA stage */
} else if (is_in) {
@@ -1029,7 +1069,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
(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;
+ req = NULL;
deselect_ep();
if (!is_in) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1041,7 +1081,7 @@ omap_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
irq_wait:
/* irq handler advances the queue */
- if (req != 0)
+ if (req != NULL)
list_add_tail(&req->queue, &ep->queue);
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1140,7 +1180,7 @@ static int omap_ep_set_halt(struct usb_ep *_ep, int value)
dma_channel_claim(ep, channel);
} else {
use_ep(ep, 0);
- UDC_CTRL_REG = UDC_RESET_EP;
+ UDC_CTRL_REG = ep->udc->clr_halt;
ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
@@ -1238,6 +1278,8 @@ static int can_pullup(struct omap_udc *udc)
static void pullup_enable(struct omap_udc *udc)
{
+ udc->gadget.dev.parent->power.power_state = PMSG_ON;
+ udc->gadget.dev.power.power_state = PMSG_ON;
UDC_SYSCON1_REG |= UDC_PULLUP_EN;
#ifndef CONFIG_USB_OTG
if (!cpu_is_omap15xx())
@@ -1382,7 +1424,7 @@ static void update_otg(struct omap_udc *udc)
static void ep0_irq(struct omap_udc *udc, u16 irq_src)
{
struct omap_ep *ep0 = &udc->ep[0];
- struct omap_req *req = 0;
+ struct omap_req *req = NULL;
ep0->irqs++;
@@ -1438,7 +1480,7 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
if (req)
done(ep0, req, 0);
}
- req = 0;
+ req = NULL;
} else if (stat & UDC_STALL) {
UDC_CTRL_REG = UDC_CLR_HALT;
UDC_EP_NUM_REG = UDC_EP_DIR;
@@ -1511,9 +1553,10 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
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);
+
+#define w_value le16_to_cpup (&u.r.wValue)
+#define w_index le16_to_cpup (&u.r.wIndex)
+#define w_length le16_to_cpup (&u.r.wLength)
/* Delegate almost all control requests to the gadget driver,
* except for a handful of ch9 status/feature requests that
@@ -1529,11 +1572,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* udc needs to know when ep != 0 is valid */
if (u.r.bRequestType != USB_RECIP_DEVICE)
goto delegate;
- if (u.r.wLength != 0)
+ if (w_length != 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);
+ udc->ep0_reset_config = (w_value == 0);
+ VDBG("set config %d\n", w_value);
/* update udc NOW since gadget driver may start
* queueing requests immediately; clear config
@@ -1549,23 +1592,28 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* clear endpoint halt */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT
- || u.r.wLength != 0)
+ if (w_value != USB_ENDPOINT_HALT
+ || w_length != 0)
goto do_stall;
- ep = &udc->ep[u.r.wIndex & 0xf];
+ ep = &udc->ep[w_index & 0xf];
if (ep != ep0) {
- if (u.r.wIndex & USB_DIR_IN)
+ if (w_index & 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;
+ UDC_CTRL_REG = udc->clr_halt;
ep->ackwait = 0;
if (!(ep->bEndpointAddress & USB_DIR_IN)) {
UDC_CTRL_REG = UDC_SET_FIFO_EN;
ep->ackwait = 1 + ep->double_buf;
}
+ /* NOTE: assumes the host behaves sanely,
+ * only clearing real halts. Else we may
+ * need to kill pending transfers and then
+ * restart the queue... very messy for DMA!
+ */
}
VDBG("%s halt cleared by host\n", ep->name);
goto ep0out_status_stage;
@@ -1573,11 +1621,11 @@ static void ep0_irq(struct omap_udc *udc, u16 irq_src)
/* set endpoint halt */
if (u.r.bRequestType != USB_RECIP_ENDPOINT)
goto delegate;
- if (u.r.wValue != USB_ENDPOINT_HALT
- || u.r.wLength != 0)
+ if (w_value != USB_ENDPOINT_HALT
+ || w_length != 0)
goto do_stall;
- ep = &udc->ep[u.r.wIndex & 0xf];
- if (u.r.wIndex & USB_DIR_IN)
+ ep = &udc->ep[w_index & 0xf];
+ if (w_index & USB_DIR_IN)
ep += 16;
if (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
|| ep == ep0 || !ep->desc)
@@ -1615,13 +1663,13 @@ ep0out_status_stage:
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);
+ VDBG("GET_STATUS, interface %d\n", w_index);
/* next, status stage */
break;
default:
delegate:
/* activate the ep0out fifo right away */
- if (!udc->ep0_in && u.r.wLength) {
+ if (!udc->ep0_in && w_length) {
UDC_EP_NUM_REG = 0;
UDC_CTRL_REG = UDC_SET_FIFO_EN;
}
@@ -1632,7 +1680,11 @@ delegate:
*/
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);
+ w_value, w_index, w_length);
+
+#undef w_value
+#undef w_index
+#undef w_length
/* The gadget driver may return an error here,
* causing an immediate protocol stall.
@@ -2013,7 +2065,7 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
udc->softconnect = 1;
/* hook up the driver */
- driver->driver.bus = 0;
+ driver->driver.bus = NULL;
udc->driver = driver;
udc->gadget.dev.driver = &driver->driver;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -2021,8 +2073,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
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;
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
goto done;
}
DBG("bound to driver %s\n", driver->driver.name);
@@ -2035,8 +2087,8 @@ int usb_gadget_register_driver (struct usb_gadget_driver *driver)
if (status < 0) {
ERR("can't bind to transceiver\n");
driver->unbind (&udc->gadget);
- udc->gadget.dev.driver = 0;
- udc->driver = 0;
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
goto done;
}
} else {
@@ -2071,7 +2123,7 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
- (void) otg_set_peripheral(udc->transceiver, 0);
+ (void) otg_set_peripheral(udc->transceiver, NULL);
else
pullup_disable(udc);
@@ -2080,9 +2132,8 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
spin_unlock_irqrestore(&udc->lock, flags);
driver->unbind(&udc->gadget);
- udc->gadget.dev.driver = 0;
- udc->driver = 0;
-
+ udc->gadget.dev.driver = NULL;
+ udc->driver = NULL;
DBG("unregistered driver '%s'\n", driver->driver.name);
return status;
@@ -2178,14 +2229,14 @@ static int proc_otg_show(struct seq_file *s)
tmp = OTG_REV_REG;
trans = USB_TRANSCEIVER_CTRL_REG;
- seq_printf(s, "OTG rev %d.%d, transceiver_ctrl %03x\n",
+ seq_printf(s, "\nOTG rev %d.%d, transceiver_ctrl %05x\n",
tmp >> 4, tmp & 0xf, trans);
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), trans & CONF_USB2_UNI_R),
trx_mode(USB1_TRX_MODE(tmp), trans & CONF_USB1_UNI_R),
- (USB0_TRX_MODE(tmp) == 0)
+ (USB0_TRX_MODE(tmp) == 0 && !cpu_is_omap1710())
? "internal"
: trx_mode(USB0_TRX_MODE(tmp), 1),
(tmp & OTG_IDLE_EN) ? " !otg" : "",
@@ -2235,6 +2286,7 @@ static int proc_otg_show(struct seq_file *s)
seq_printf(s, "otg_outctrl %04x" "\n", tmp);
tmp = OTG_TEST_REG;
seq_printf(s, "otg_test %04x" "\n", tmp);
+ return 0;
}
static int proc_udc_show(struct seq_file *s, void *_)
@@ -2378,7 +2430,7 @@ static int proc_udc_show(struct seq_file *s, void *_)
static int proc_udc_open(struct inode *inode, struct file *file)
{
- return single_open(file, proc_udc_show, 0);
+ return single_open(file, proc_udc_show, NULL);
}
static struct file_operations proc_ops = {
@@ -2399,7 +2451,7 @@ static void create_proc_file(void)
static void remove_proc_file(void)
{
- remove_proc_entry(proc_filename, 0);
+ remove_proc_entry(proc_filename, NULL);
}
#else
@@ -2414,6 +2466,10 @@ static inline void remove_proc_file(void) {}
/* 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.
+ *
+ * NOTE: as of OMAP 1710 ES2.0, writing a new endpoint config when
+ * UDC_SYSCON_1_REG.CFG_LOCK is set can now work. We won't use that
+ * capability yet though.
*/
static unsigned __init
omap_ep_setup(char *name, u8 addr, u8 type,
@@ -2505,7 +2561,7 @@ static void omap_udc_release(struct device *dev)
{
complete(udc->done);
kfree (udc);
- udc = 0;
+ udc = NULL;
}
static int __init
@@ -2577,23 +2633,33 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
case 1:
OMAP_BULK_EP("ep1in", USB_DIR_IN | 1);
OMAP_BULK_EP("ep2out", USB_DIR_OUT | 2);
+ OMAP_INT_EP("ep9in", USB_DIR_IN | 9, 16);
+
OMAP_BULK_EP("ep3in", USB_DIR_IN | 3);
OMAP_BULK_EP("ep4out", USB_DIR_OUT | 4);
+ OMAP_INT_EP("ep10in", USB_DIR_IN | 10, 16);
OMAP_BULK_EP("ep5in", USB_DIR_IN | 5);
OMAP_BULK_EP("ep5out", USB_DIR_OUT | 5);
+ OMAP_INT_EP("ep11in", USB_DIR_IN | 11, 16);
+
OMAP_BULK_EP("ep6in", USB_DIR_IN | 6);
OMAP_BULK_EP("ep6out", USB_DIR_OUT | 6);
+ OMAP_INT_EP("ep12in", USB_DIR_IN | 12, 16);
OMAP_BULK_EP("ep7in", USB_DIR_IN | 7);
OMAP_BULK_EP("ep7out", USB_DIR_OUT | 7);
+ OMAP_INT_EP("ep13in", USB_DIR_IN | 13, 16);
+ OMAP_INT_EP("ep13out", USB_DIR_OUT | 13, 16);
+
OMAP_BULK_EP("ep8in", USB_DIR_IN | 8);
OMAP_BULK_EP("ep8out", USB_DIR_OUT | 8);
+ OMAP_INT_EP("ep14in", USB_DIR_IN | 14, 16);
+ OMAP_INT_EP("ep14out", USB_DIR_OUT | 14, 16);
+
+ OMAP_BULK_EP("ep15in", USB_DIR_IN | 15);
+ OMAP_BULK_EP("ep15out", USB_DIR_OUT | 15);
- 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
@@ -2640,8 +2706,8 @@ 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 otg_transceiver *xceiv = NULL;
+ const char *type = NULL;
struct omap_usb_config *config = dev->platform_data;
/* NOTE: "knows" the order of the resources! */
@@ -2676,54 +2742,78 @@ static int __init omap_udc_probe(struct device *dev)
FUNC_MUX_CTRL_0_REG = tmp;
}
} else {
+ /* The transceiver may package some GPIO logic or handle
+ * loopback and/or transceiverless setup; if we find one,
+ * use it. Except for OTG, we don't _need_ to talk to one;
+ * but not having one probably means no VBUS detection.
+ */
+ xceiv = otg_get_transceiver();
+ if (xceiv)
+ type = xceiv->label;
+ else if (config->otg) {
+ DBG("OTG requires external transceiver!\n");
+ goto cleanup0;
+ }
+
hmc = HMC_1610;
switch (hmc) {
+ case 0: /* POWERUP DEFAULT == 0 */
+ case 4:
+ case 12:
+ case 20:
+ if (!cpu_is_omap1710()) {
+ type = "integrated";
+ break;
+ }
+ /* FALL THROUGH */
case 3:
case 11:
case 16:
case 19:
case 25:
- xceiv = otg_get_transceiver();
if (!xceiv) {
DBG("external transceiver not registered!\n");
- if (config->otg)
- goto cleanup0;
- type = "(unknown external)";
- } else
- type = xceiv->label;
- break;
- case 0: /* POWERUP DEFAULT == 0 */
- case 4:
- case 12:
- case 20:
- type = "INTEGRATED";
+ type = "unknown";
+ }
break;
case 21: /* internal loopback */
- type = "(loopback)";
+ type = "loopback";
break;
case 14: /* transceiverless */
- type = "(none)";
+ if (cpu_is_omap1710())
+ goto bad_on_1710;
+ /* FALL THROUGH */
+ case 13:
+ case 15:
+ type = "no";
break;
default:
+bad_on_1710:
ERR("unrecognized UDC HMC mode %d\n", hmc);
- return -ENODEV;
+ goto cleanup0;
}
}
- INFO("hmc mode %d, transceiver %s\n", hmc, type);
+ INFO("hmc mode %d, %s transceiver\n", hmc, type);
/* a "gadget" abstracts/virtualizes the controller */
status = omap_udc_setup(odev, xceiv);
if (status) {
goto cleanup0;
}
- xceiv = 0;
+ xceiv = NULL;
// "udc" is now valid
pullup_disable(udc);
#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
udc->gadget.is_otg = (config->otg != 0);
#endif
+ /* starting with omap1710 es2.0, clear toggle is a separate bit */
+ if (UDC_REV_REG >= 0x61)
+ udc->clr_halt = UDC_RESET_EP | UDC_CLRDATA_TOGGLE;
+ else
+ udc->clr_halt = UDC_RESET_EP;
+
/* 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);
@@ -2765,7 +2855,7 @@ cleanup2:
cleanup1:
kfree (udc);
- udc = 0;
+ udc = NULL;
cleanup0:
if (xceiv)
@@ -2788,7 +2878,7 @@ static int __exit omap_udc_remove(struct device *dev)
pullup_disable(udc);
if (udc->transceiver) {
put_device(udc->transceiver->dev);
- udc->transceiver = 0;
+ udc->transceiver = NULL;
}
UDC_SYSCON1_REG = 0;
@@ -2809,13 +2899,33 @@ static int __exit omap_udc_remove(struct device *dev)
return 0;
}
-static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
+/* suspend/resume/wakeup from sysfs (echo > power/state) or when the
+ * system is forced into deep sleep
+ *
+ * REVISIT we should probably reject suspend requests when there's a host
+ * session active, rather than disconnecting, at least on boards that can
+ * report VBUS irqs (UDC_DEVSTAT_REG.UDC_ATT). And in any case, we need to
+ * make host resumes and VBUS detection trigger OMAP wakeup events; that
+ * may involve talking to an external transceiver (e.g. isp1301).
+ */
+
+static int omap_udc_suspend(struct device *dev, pm_message_t message, u32 level)
{
- if (level != 0)
+ u32 devstat;
+
+ if (level != SUSPEND_POWER_DOWN)
return 0;
+ devstat = UDC_DEVSTAT_REG;
+
+ /* we're requesting 48 MHz clock if the pullup is enabled
+ * (== we're attached to the host) and we're not suspended,
+ * which would prevent entry to deep sleep...
+ */
+ if ((devstat & UDC_ATT) != 0 && (devstat & UDC_SUS) == 0) {
+ WARN("session active; suspend requires disconnect\n");
+ omap_pullup(&udc->gadget, 0);
+ }
- DBG("suspend, state %d\n", state);
- omap_pullup(&udc->gadget, 0);
udc->gadget.dev.power.power_state = PMSG_SUSPEND;
udc->gadget.dev.parent->power.power_state = PMSG_SUSPEND;
return 0;
@@ -2823,12 +2933,10 @@ static int omap_udc_suspend(struct device *dev, pm_message_t state, u32 level)
static int omap_udc_resume(struct device *dev, u32 level)
{
- if (level != 0)
+ if (level != RESUME_POWER_ON)
return 0;
DBG("resume + wakeup/SRP\n");
- udc->gadget.dev.parent->power.power_state = PMSG_ON;
- udc->gadget.dev.power.power_state = PMSG_ON;
omap_pullup(&udc->gadget, 1);
/* maybe the host would enumerate us if we nudged it */
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index c9e68541622c..652ee4627344 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -20,6 +20,7 @@
#define UDC_CTRL_REG UDC_REG(0x0C) /* Endpoint control */
# define UDC_CLR_HALT (1 << 7)
# define UDC_SET_HALT (1 << 6)
+# define UDC_CLRDATA_TOGGLE (1 << 3)
# define UDC_SET_FIFO_EN (1 << 2)
# define UDC_CLR_EP (1 << 1)
# define UDC_RESET_EP (1 << 0)
@@ -99,6 +100,7 @@
/* 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_DMA_REQ (1 << 12)
#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 */
@@ -162,6 +164,7 @@ struct omap_udc {
spinlock_t lock;
struct omap_ep ep[32];
u16 devstat;
+ u16 clr_halt;
struct otg_transceiver *transceiver;
struct list_head iso;
unsigned softconnect:1;
@@ -171,7 +174,6 @@ struct omap_udc {
unsigned ep0_set_config:1;
unsigned ep0_reset_config:1;
unsigned ep0_setup:1;
-
struct completion *done;
};
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b8b4524ed746..1507738337c4 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -1,6 +1,6 @@
/*
* linux/drivers/usb/gadget/pxa2xx_udc.c
- * Intel PXA2xx and IXP4xx on-chip full speed USB device controllers
+ * Intel PXA25x and IXP4xx on-chip full speed USB device controllers
*
* Copyright (C) 2002 Intrinsyc, Inc. (Frank Becker)
* Copyright (C) 2003 Robert Schwebel, Pengutronix
@@ -63,7 +63,7 @@
/*
- * This driver handles the USB Device Controller (UDC) in Intel's PXA 2xx
+ * This driver handles the USB Device Controller (UDC) in Intel's PXA 25x
* series processors. The UDC for the IXP 4xx series is very similar.
* There are fifteen endpoints, in addition to ep0.
*
@@ -79,8 +79,8 @@
* pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
*/
-#define DRIVER_VERSION "14-Dec-2003"
-#define DRIVER_DESC "PXA 2xx USB Device Controller driver"
+#define DRIVER_VERSION "4-May-2005"
+#define DRIVER_DESC "PXA 25x USB Device Controller driver"
static const char driver_name [] = "pxa2xx_udc";
@@ -290,6 +290,7 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
static int pxa2xx_ep_disable (struct usb_ep *_ep)
{
struct pxa2xx_ep *ep;
+ unsigned long flags;
ep = container_of (_ep, struct pxa2xx_ep, ep);
if (!_ep || !ep->desc) {
@@ -297,6 +298,8 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
_ep ? ep->ep.name : NULL);
return -EINVAL;
}
+ local_irq_save(flags);
+
nuke (ep, -ESHUTDOWN);
#ifdef USE_DMA
@@ -313,6 +316,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
ep->desc = NULL;
ep->stopped = 1;
+ local_irq_restore(flags);
DBG(DBG_VERBOSE, "%s disabled\n", _ep->name);
return 0;
}
@@ -328,7 +332,7 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
* pxa2xx_ep_alloc_request - allocate a request data structure
*/
static struct usb_request *
-pxa2xx_ep_alloc_request (struct usb_ep *_ep, int gfp_flags)
+pxa2xx_ep_alloc_request (struct usb_ep *_ep, unsigned gfp_flags)
{
struct pxa2xx_request *req;
@@ -363,7 +367,7 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
*/
static void *
pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
- dma_addr_t *dma, int gfp_flags)
+ dma_addr_t *dma, unsigned gfp_flags)
{
char *retval;
@@ -870,7 +874,7 @@ done:
/*-------------------------------------------------------------------------*/
static int
-pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, unsigned gfp_flags)
{
struct pxa2xx_request *req;
struct pxa2xx_ep *ep;
@@ -971,10 +975,10 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
kick_dma(ep, req);
#endif
/* can the FIFO can satisfy the request immediately? */
- } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
- && (*ep->reg_udccs & UDCCS_BI_TFS) != 0
- && write_fifo(ep, req)) {
- req = NULL;
+ } else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+ if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
+ && write_fifo(ep, req))
+ req = NULL;
} else if ((*ep->reg_udccs & UDCCS_BO_RFS) != 0
&& read_fifo(ep, req)) {
req = NULL;
@@ -1290,7 +1294,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
"%s version: %s\nGadget driver: %s\nHost %s\n\n",
driver_name, DRIVER_VERSION SIZE_STR DMASTR,
dev->driver ? dev->driver->driver.name : "(none)",
- is_usb_connected() ? "full speed" : "disconnected");
+ is_vbus_present() ? "full speed" : "disconnected");
size -= t;
next += t;
@@ -1339,7 +1343,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
next += t;
}
- if (!is_usb_connected() || !dev->driver)
+ if (!is_vbus_present() || !dev->driver)
goto done;
t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
@@ -1454,7 +1458,7 @@ static void udc_disable(struct pxa2xx_udc *dev)
UFNRH = UFNRH_SIM;
/* if hardware supports it, disconnect from usb */
- make_usb_disappear();
+ pullup_off();
udc_clear_mask_UDCCR(UDCCR_UDE);
@@ -1567,7 +1571,7 @@ static void udc_enable (struct pxa2xx_udc *dev)
UICR0 &= ~UICR0_IM0;
/* if hardware supports it, pullup D+ and wait for reset */
- let_usb_appear();
+ pullup_on();
}
@@ -2052,10 +2056,10 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
if (unlikely(udccr & UDCCR_SUSIR)) {
udc_ack_int_UDCCR(UDCCR_SUSIR);
handled = 1;
- DBG(DBG_VERBOSE, "USB suspend%s\n", is_usb_connected()
+ DBG(DBG_VERBOSE, "USB suspend%s\n", is_vbus_present()
? "" : "+disconnect");
- if (!is_usb_connected())
+ if (!is_vbus_present())
stop_activity(dev, dev->driver);
else if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
@@ -2073,7 +2077,7 @@ pxa2xx_udc_irq(int irq, void *_dev, struct pt_regs *r)
if (dev->gadget.speed != USB_SPEED_UNKNOWN
&& dev->driver
&& dev->driver->resume
- && is_usb_connected())
+ && is_vbus_present())
dev->driver->resume(&dev->gadget);
}
@@ -2509,7 +2513,7 @@ static int __init pxa2xx_udc_probe(struct device *_dev)
udc_disable(dev);
udc_reinit(dev);
- dev->vbus = is_usb_connected();
+ dev->vbus = is_vbus_present();
/* irq setup after old hardware state is cleaned up */
retval = request_irq(IRQ_USB, pxa2xx_udc_irq,
@@ -2555,6 +2559,12 @@ lubbock_fail0:
return 0;
}
+
+static void pxa2xx_udc_shutdown(struct device *_dev)
+{
+ pullup_off();
+}
+
static int __exit pxa2xx_udc_remove(struct device *_dev)
{
struct pxa2xx_udc *dev = dev_get_drvdata(_dev);
@@ -2624,6 +2634,7 @@ static struct device_driver udc_driver = {
.name = "pxa2xx-udc",
.bus = &platform_bus_type,
.probe = pxa2xx_udc_probe,
+ .shutdown = pxa2xx_udc_shutdown,
.remove = __exit_p(pxa2xx_udc_remove),
.suspend = pxa2xx_udc_suspend,
.resume = pxa2xx_udc_resume,
diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
index 1f3a7d999da7..d0bc396a85d5 100644
--- a/drivers/usb/gadget/pxa2xx_udc.h
+++ b/drivers/usb/gadget/pxa2xx_udc.h
@@ -177,23 +177,23 @@ struct pxa2xx_udc {
static struct pxa2xx_udc *the_controller;
-/* one GPIO should be used to detect host disconnect */
-static inline int is_usb_connected(void)
+/* one GPIO should be used to detect VBUS from the host */
+static inline int is_vbus_present(void)
{
if (!the_controller->mach->udc_is_connected)
return 1;
return the_controller->mach->udc_is_connected();
}
-/* one GPIO should force the host to see this device (or not) */
-static inline void make_usb_disappear(void)
+/* one GPIO should control a D+ pullup, so host sees this device (or not) */
+static inline void pullup_off(void)
{
if (!the_controller->mach->udc_command)
return;
the_controller->mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
}
-static inline void let_usb_appear(void)
+static inline void pullup_on(void)
{
if (!the_controller->mach->udc_command)
return;
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index 7457268d5f28..06b6eba925b5 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -41,6 +41,7 @@
#undef RNDIS_PM
+#undef RNDIS_WAKEUP
#undef VERBOSE
#include "rndis.h"
@@ -60,7 +61,7 @@
} while (0)
static int rndis_debug = 0;
-module_param (rndis_debug, bool, 0);
+module_param (rndis_debug, int, 0);
MODULE_PARM_DESC (rndis_debug, "enable debugging");
#else
@@ -78,22 +79,103 @@ static rndis_params rndis_per_dev_params [RNDIS_MAX_CONFIGS];
static const __le32 rndis_driver_version = __constant_cpu_to_le32 (1);
/* Function Prototypes */
-static int rndis_init_response (int configNr, rndis_init_msg_type *buf);
-static int rndis_query_response (int configNr, rndis_query_msg_type *buf);
-static int rndis_set_response (int configNr, rndis_set_msg_type *buf);
-static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf);
-static int rndis_keepalive_response (int configNr,
- rndis_keepalive_msg_type *buf);
-
static rndis_resp_t *rndis_add_response (int configNr, u32 length);
+/* supported OIDs */
+static const u32 oid_supported_list [] =
+{
+ /* the general stuff */
+ OID_GEN_SUPPORTED_LIST,
+ OID_GEN_HARDWARE_STATUS,
+ OID_GEN_MEDIA_SUPPORTED,
+ OID_GEN_MEDIA_IN_USE,
+ OID_GEN_MAXIMUM_FRAME_SIZE,
+ OID_GEN_LINK_SPEED,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_MEDIA_CONNECT_STATUS,
+ OID_GEN_PHYSICAL_MEDIUM,
+#if 0
+ OID_GEN_RNDIS_CONFIG_PARAMETER,
+#endif
+
+ /* the statistical stuff */
+ OID_GEN_XMIT_OK,
+ OID_GEN_RCV_OK,
+ OID_GEN_XMIT_ERROR,
+ OID_GEN_RCV_ERROR,
+ OID_GEN_RCV_NO_BUFFER,
+#ifdef RNDIS_OPTIONAL_STATS
+ OID_GEN_DIRECTED_BYTES_XMIT,
+ OID_GEN_DIRECTED_FRAMES_XMIT,
+ OID_GEN_MULTICAST_BYTES_XMIT,
+ OID_GEN_MULTICAST_FRAMES_XMIT,
+ OID_GEN_BROADCAST_BYTES_XMIT,
+ OID_GEN_BROADCAST_FRAMES_XMIT,
+ OID_GEN_DIRECTED_BYTES_RCV,
+ OID_GEN_DIRECTED_FRAMES_RCV,
+ OID_GEN_MULTICAST_BYTES_RCV,
+ OID_GEN_MULTICAST_FRAMES_RCV,
+ OID_GEN_BROADCAST_BYTES_RCV,
+ OID_GEN_BROADCAST_FRAMES_RCV,
+ OID_GEN_RCV_CRC_ERROR,
+ OID_GEN_TRANSMIT_QUEUE_LENGTH,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+ /* mandatory 802.3 */
+ /* the general stuff */
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAC_OPTIONS,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+
+ /* the statistical stuff */
+ OID_802_3_RCV_ERROR_ALIGNMENT,
+ OID_802_3_XMIT_ONE_COLLISION,
+ OID_802_3_XMIT_MORE_COLLISIONS,
+#ifdef RNDIS_OPTIONAL_STATS
+ OID_802_3_XMIT_DEFERRED,
+ OID_802_3_XMIT_MAX_COLLISIONS,
+ OID_802_3_RCV_OVERRUN,
+ OID_802_3_XMIT_UNDERRUN,
+ OID_802_3_XMIT_HEARTBEAT_FAILURE,
+ OID_802_3_XMIT_TIMES_CRS_LOST,
+ OID_802_3_XMIT_LATE_COLLISIONS,
+#endif /* RNDIS_OPTIONAL_STATS */
+
+#ifdef RNDIS_PM
+ /* PM and wakeup are mandatory for USB: */
+
+ /* power management */
+ OID_PNP_CAPABILITIES,
+ OID_PNP_QUERY_POWER,
+ OID_PNP_SET_POWER,
+
+#ifdef RNDIS_WAKEUP
+ /* wake up host */
+ OID_PNP_ENABLE_WAKE_UP,
+ OID_PNP_ADD_WAKE_UP_PATTERN,
+ OID_PNP_REMOVE_WAKE_UP_PATTERN,
+#endif /* RNDIS_WAKEUP */
+#endif /* RNDIS_PM */
+};
+
+
/* NDIS Functions */
-static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
+static int
+gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
+ rndis_resp_t *r)
{
int retval = -ENOTSUPP;
- u32 length = 0;
- __le32 *tmp;
+ u32 length = 4; /* usually */
+ __le32 *outbuf;
int i, count;
rndis_query_cmplt_type *resp;
@@ -101,7 +183,22 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
resp = (rndis_query_cmplt_type *) r->buf;
if (!resp) return -ENOMEM;
-
+
+ if (buf_len && rndis_debug > 1) {
+ DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+ for (i = 0; i < buf_len; i += 16) {
+ DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ le32_to_cpup((__le32 *)&buf[i]),
+ le32_to_cpup((__le32 *)&buf[i + 4]),
+ le32_to_cpup((__le32 *)&buf[i + 8]),
+ le32_to_cpup((__le32 *)&buf[i + 12]));
+ }
+ }
+
+ /* response goes here, right after the header */
+ outbuf = (__le32 *) &resp[1];
+ resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
+
switch (OID) {
/* general oids (table 4-1) */
@@ -111,42 +208,36 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
length = sizeof (oid_supported_list);
count = length / sizeof (u32);
- tmp = (__le32 *) ((u8 *)resp + 24);
for (i = 0; i < count; i++)
- tmp[i] = cpu_to_le32 (oid_supported_list[i]);
+ outbuf[i] = cpu_to_le32 (oid_supported_list[i]);
retval = 0;
break;
/* mandatory */
case OID_GEN_HARDWARE_STATUS:
DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
- length = 4;
/* Bogus question!
* Hardware must be ready to receive high level protocols.
* BTW:
* reddite ergo quae sunt Caesaris Caesari
* et quae sunt Dei Deo!
*/
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_SUPPORTED:
DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr].medium);
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_IN_USE:
DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
- length = 4;
/* one medium, one transport... (maybe you do it better) */
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr].medium);
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
retval = 0;
break;
@@ -154,25 +245,21 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_MAXIMUM_FRAME_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
/* mandatory */
case OID_GEN_LINK_SPEED:
-// DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
- length = 4;
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].media_state
- == NDIS_MEDIA_STATE_DISCONNECTED)
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ == NDIS_MEDIA_STATE_DISCONNECTED)
+ *outbuf = __constant_cpu_to_le32 (0);
else
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].speed);
retval = 0;
break;
@@ -181,8 +268,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_TRANSMIT_BLOCK_SIZE:
DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
}
@@ -192,8 +278,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_RECEIVE_BLOCK_SIZE:
DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].dev->mtu);
retval = 0;
}
@@ -202,8 +287,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_GEN_VENDOR_ID:
DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].vendorID);
retval = 0;
break;
@@ -212,51 +296,44 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_VENDOR_DESCRIPTION:
DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
length = strlen (rndis_per_dev_params [configNr].vendorDescr);
- memcpy ((u8 *) resp + 24,
+ memcpy (outbuf,
rndis_per_dev_params [configNr].vendorDescr, length);
retval = 0;
break;
case OID_GEN_VENDOR_DRIVER_VERSION:
DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
- length = 4;
/* Created as LE */
- *((__le32 *) resp + 6) = rndis_driver_version;
+ *outbuf = rndis_driver_version;
retval = 0;
break;
/* mandatory */
case OID_GEN_CURRENT_PACKET_FILTER:
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params[configNr].filter);
+ *outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
retval = 0;
break;
/* mandatory */
case OID_GEN_MAXIMUM_TOTAL_SIZE:
DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = __constant_cpu_to_le32(
- RNDIS_MAX_TOTAL_SIZE);
+ *outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
retval = 0;
break;
/* mandatory */
case OID_GEN_MEDIA_CONNECT_STATUS:
- DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.media_state);
retval = 0;
break;
case OID_GEN_PHYSICAL_MEDIUM:
DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -266,8 +343,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
*/
case OID_GEN_MAC_OPTIONS: /* from WinME */
DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = __constant_cpu_to_le32(
+ *outbuf = __constant_cpu_to_le32(
NDIS_MAC_OPTION_RECEIVE_SERIALIZED
| NDIS_MAC_OPTION_FULL_DUPLEX);
retval = 0;
@@ -277,62 +353,49 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_GEN_XMIT_OK:
- DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->tx_packets -
rndis_per_dev_params [configNr].stats->tx_errors -
rndis_per_dev_params [configNr].stats->tx_dropped);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_OK:
- DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
rndis_per_dev_params [configNr].stats->rx_packets -
rndis_per_dev_params [configNr].stats->rx_errors -
rndis_per_dev_params [configNr].stats->rx_dropped);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
/* mandatory */
case OID_GEN_XMIT_ERROR:
- DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_errors);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
/* mandatory */
case OID_GEN_RCV_ERROR:
- DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+ if (rndis_debug > 1)
+ DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_errors);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
@@ -340,13 +403,9 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_GEN_RCV_NO_BUFFER:
DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_dropped);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
@@ -359,8 +418,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
* divided by weight of Alpha Centauri
*/
if (rndis_per_dev_params [configNr].stats) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
(rndis_per_dev_params [configNr]
.stats->tx_packets -
rndis_per_dev_params [configNr]
@@ -369,9 +427,6 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
.stats->tx_dropped)
* 123);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
@@ -379,8 +434,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
/* dito */
if (rndis_per_dev_params [configNr].stats) {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
+ *outbuf = cpu_to_le32 (
(rndis_per_dev_params [configNr]
.stats->tx_packets -
rndis_per_dev_params [configNr]
@@ -389,144 +443,105 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
.stats->tx_dropped)
/ 123);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_MULTICAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast*1234);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42*255);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_XMIT:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->tx_packets/42);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_DIRECTED_BYTES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_DIRECTED_FRAMES_RCV:
DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
case OID_GEN_MULTICAST_BYTES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast * 1111);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_MULTICAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->multicast);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_BROADCAST_BYTES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42*255);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_BROADCAST_FRAMES_RCV:
DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_packets/42);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_RCV_CRC_ERROR:
DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].stats) {
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_crc_errors);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
case OID_GEN_TRANSMIT_QUEUE_LENGTH:
DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
#endif /* RNDIS_OPTIONAL_STATS */
@@ -538,13 +553,10 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
- memcpy ((u8 *) resp + 24,
+ memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
- } else {
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
- retval = 0;
}
break;
@@ -553,7 +565,7 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
if (rndis_per_dev_params [configNr].dev) {
length = ETH_ALEN;
- memcpy ((u8 *) resp + 24,
+ memcpy (outbuf,
rndis_per_dev_params [configNr].host_mac,
length);
retval = 0;
@@ -563,18 +575,16 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_MULTICAST_LIST:
DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
- length = 4;
/* Multicast base address only */
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0xE0000000);
+ *outbuf = __constant_cpu_to_le32 (0xE0000000);
retval = 0;
break;
/* mandatory */
case OID_802_3_MAXIMUM_LIST_SIZE:
DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
- length = 4;
/* Multicast base address only */
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (1);
+ *outbuf = __constant_cpu_to_le32 (1);
retval = 0;
break;
@@ -587,11 +597,8 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_RCV_ERROR_ALIGNMENT:
DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
- if (rndis_per_dev_params [configNr].stats)
- {
- length = 4;
- *((__le32 *) resp + 6) = cpu_to_le32 (
- rndis_per_dev_params [configNr]
+ if (rndis_per_dev_params [configNr].stats) {
+ *outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
.stats->rx_frame_errors);
retval = 0;
}
@@ -600,16 +607,14 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
/* mandatory */
case OID_802_3_XMIT_ONE_COLLISION:
DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
/* mandatory */
case OID_802_3_XMIT_MORE_COLLISIONS:
DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
- length = 4;
- *((__le32 *) resp + 6) = __constant_cpu_to_le32 (0);
+ *outbuf = __constant_cpu_to_le32 (0);
retval = 0;
break;
@@ -655,27 +660,18 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
case OID_PNP_CAPABILITIES:
DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
- /* just PM, and remote wakeup on link status change
- * (not magic packet or pattern match)
- */
+ /* for now, no wakeup capabilities */
length = sizeof (struct NDIS_PNP_CAPABILITIES);
- memset (resp, 0, length);
- {
- struct NDIS_PNP_CAPABILITIES *caps = (void *) resp;
-
- caps->Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
- caps->WakeUpCapabilities.MinLinkChangeWakeUp
- = NdisDeviceStateD3;
-
- /* FIXME then use usb_gadget_wakeup(), and
- * set USB_CONFIG_ATT_WAKEUP in config desc
- */
- }
+ memset(outbuf, 0, length);
retval = 0;
break;
case OID_PNP_QUERY_POWER:
- DEBUG("%s: OID_PNP_QUERY_POWER\n", __FUNCTION__);
- /* sure, handle any power state that maps to USB suspend */
+ DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+ le32_to_cpup((__le32 *) buf) - 1);
+ /* only suspend is a real power state, and
+ * it can't be entered by OID_PNP_SET_POWER...
+ */
+ length = 0;
retval = 0;
break;
#endif
@@ -684,11 +680,12 @@ static int gen_ndis_query_resp (int configNr, u32 OID, rndis_resp_t *r)
printk (KERN_WARNING "%s: query unknown OID 0x%08X\n",
__FUNCTION__, OID);
}
+ if (retval < 0)
+ length = 0;
- resp->InformationBufferOffset = __constant_cpu_to_le32 (16);
resp->InformationBufferLength = cpu_to_le32 (length);
- resp->MessageLength = cpu_to_le32 (24 + length);
- r->length = 24 + length;
+ r->length = length + sizeof *resp;
+ resp->MessageLength = cpu_to_le32 (r->length);
return retval;
}
@@ -705,45 +702,40 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
if (!resp)
return -ENOMEM;
- DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
- for (i = 0; i < buf_len; i += 16) {
- DEBUG ("%03d: "
- " %02x %02x %02x %02x"
- " %02x %02x %02x %02x"
- " %02x %02x %02x %02x"
- " %02x %02x %02x %02x"
- "\n",
- i,
- buf[i], buf [i+1],
- buf[i+2], buf[i+3],
- buf[i+4], buf [i+5],
- buf[i+6], buf[i+7],
- buf[i+8], buf [i+9],
- buf[i+10], buf[i+11],
- buf[i+12], buf [i+13],
- buf[i+14], buf[i+15]);
+ if (buf_len && rndis_debug > 1) {
+ DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+ for (i = 0; i < buf_len; i += 16) {
+ DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+ le32_to_cpup((__le32 *)&buf[i]),
+ le32_to_cpup((__le32 *)&buf[i + 4]),
+ le32_to_cpup((__le32 *)&buf[i + 8]),
+ le32_to_cpup((__le32 *)&buf[i + 12]));
+ }
}
+ params = &rndis_per_dev_params [configNr];
switch (OID) {
case OID_GEN_CURRENT_PACKET_FILTER:
- params = &rndis_per_dev_params [configNr];
- retval = 0;
- /* FIXME use these NDIS_PACKET_TYPE_* bitflags to
- * set the cdc_filter; it's not RNDIS-specific
+ /* these NDIS_PACKET_TYPE_* bitflags are shared with
+ * cdc_filter; it's not RNDIS-specific
* NDIS_PACKET_TYPE_x == USB_CDC_PACKET_TYPE_x for x in:
* PROMISCUOUS, DIRECTED,
* MULTICAST, ALL_MULTICAST, BROADCAST
*/
- params->filter = le32_to_cpup((__le32 *)buf);
+ *params->filter = (u16) le32_to_cpup((__le32 *)buf);
DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
- __FUNCTION__, params->filter);
+ __FUNCTION__, *params->filter);
/* this call has a significant side effect: it's
* what makes the packet flow start and stop, like
* activating the CDC Ethernet altsetting.
*/
- if (params->filter) {
+#ifdef RNDIS_PM
+update_linkstate:
+#endif
+ retval = 0;
+ if (*params->filter) {
params->state = RNDIS_DATA_INITIALIZED;
netif_carrier_on(params->dev);
if (netif_running(params->dev))
@@ -776,21 +768,34 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
#ifdef RNDIS_PM
case OID_PNP_SET_POWER:
- DEBUG ("OID_PNP_SET_POWER\n");
- /* sure, handle any power state that maps to USB suspend */
- retval = 0;
- break;
-
- case OID_PNP_ENABLE_WAKE_UP:
- /* always-connected ... */
- DEBUG ("OID_PNP_ENABLE_WAKE_UP\n");
- retval = 0;
+ /* The only real power state is USB suspend, and RNDIS requests
+ * can't enter it; this one isn't really about power. After
+ * resuming, Windows forces a reset, and then SET_POWER D0.
+ * FIXME ... then things go batty; Windows wedges itself.
+ */
+ i = le32_to_cpup((__force __le32 *)buf);
+ DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+ switch (i) {
+ case NdisDeviceStateD0:
+ *params->filter = params->saved_filter;
+ goto update_linkstate;
+ case NdisDeviceStateD3:
+ case NdisDeviceStateD2:
+ case NdisDeviceStateD1:
+ params->saved_filter = *params->filter;
+ retval = 0;
+ break;
+ }
break;
- // no PM resume patterns supported (specified where?)
- // so OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN always fails
+#ifdef RNDIS_WAKEUP
+ // no wakeup support advertised, so wakeup OIDs always fail:
+ // - OID_PNP_ENABLE_WAKE_UP
+ // - OID_PNP_{ADD,REMOVE}_WAKE_UP_PATTERN
#endif
+#endif /* RNDIS_PM */
+
default:
printk (KERN_WARNING "%s: set unknown OID 0x%08X, size %d\n",
__FUNCTION__, OID, buf_len);
@@ -811,13 +816,10 @@ static int rndis_init_response (int configNr, rndis_init_msg_type *buf)
if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
r = rndis_add_response (configNr, sizeof (rndis_init_cmplt_type));
-
- if (!r) return -ENOMEM;
-
+ if (!r)
+ return -ENOMEM;
resp = (rndis_init_cmplt_type *) r->buf;
- if (!resp) return -ENOMEM;
-
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_INITIALIZE_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (52);
@@ -857,20 +859,22 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
* oid_supported_list is the largest answer
*/
r = rndis_add_response (configNr, sizeof (oid_supported_list));
-
- if (!r) return -ENOMEM;
+ if (!r)
+ return -ENOMEM;
resp = (rndis_query_cmplt_type *) r->buf;
- if (!resp) return -ENOMEM;
-
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_QUERY_CMPLT);
- resp->MessageLength = __constant_cpu_to_le32 (24);
resp->RequestID = buf->RequestID; /* Still LE in msg buffer */
-
- if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID), r)) {
+
+ if (gen_ndis_query_resp (configNr, le32_to_cpu (buf->OID),
+ le32_to_cpu(buf->InformationBufferOffset)
+ + 8 + (u8 *) buf,
+ le32_to_cpu(buf->InformationBufferLength),
+ r)) {
/* OID not supported */
resp->Status = __constant_cpu_to_le32 (
RNDIS_STATUS_NOT_SUPPORTED);
+ resp->MessageLength = __constant_cpu_to_le32 (sizeof *resp);
resp->InformationBufferLength = __constant_cpu_to_le32 (0);
resp->InformationBufferOffset = __constant_cpu_to_le32 (0);
} else
@@ -889,10 +893,9 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_set_cmplt_type));
-
- if (!r) return -ENOMEM;
+ if (!r)
+ return -ENOMEM;
resp = (rndis_set_cmplt_type *) r->buf;
- if (!resp) return -ENOMEM;
BufLength = le32_to_cpu (buf->InformationBufferLength);
BufOffset = le32_to_cpu (buf->InformationBufferOffset);
@@ -930,10 +933,9 @@ static int rndis_reset_response (int configNr, rndis_reset_msg_type *buf)
rndis_resp_t *r;
r = rndis_add_response (configNr, sizeof (rndis_reset_cmplt_type));
-
- if (!r) return -ENOMEM;
+ if (!r)
+ return -ENOMEM;
resp = (rndis_reset_cmplt_type *) r->buf;
- if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_RESET_CMPLT);
resp->MessageLength = __constant_cpu_to_le32 (16);
@@ -957,8 +959,9 @@ static int rndis_keepalive_response (int configNr,
/* host "should" check only in RNDIS_DATA_INITIALIZED state */
r = rndis_add_response (configNr, sizeof (rndis_keepalive_cmplt_type));
+ if (!r)
+ return -ENOMEM;
resp = (rndis_keepalive_cmplt_type *) r->buf;
- if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_KEEPALIVE_CMPLT);
@@ -987,10 +990,9 @@ static int rndis_indicate_status_msg (int configNr, u32 status)
r = rndis_add_response (configNr,
sizeof (rndis_indicate_status_msg_type));
- if (!r) return -ENOMEM;
-
+ if (!r)
+ return -ENOMEM;
resp = (rndis_indicate_status_msg_type *) r->buf;
- if (!resp) return -ENOMEM;
resp->MessageType = __constant_cpu_to_le32 (
REMOTE_NDIS_INDICATE_STATUS_MSG);
@@ -1021,6 +1023,21 @@ int rndis_signal_disconnect (int configNr)
RNDIS_STATUS_MEDIA_DISCONNECT);
}
+void rndis_uninit (int configNr)
+{
+ u8 *buf;
+ u32 length;
+
+ if (configNr >= RNDIS_MAX_CONFIGS)
+ return;
+ rndis_per_dev_params [configNr].used = 0;
+ rndis_per_dev_params [configNr].state = RNDIS_UNINITIALIZED;
+
+ /* drain the response queue */
+ while ((buf = rndis_get_next_response(configNr, &length)))
+ rndis_free_response(configNr, buf);
+}
+
void rndis_set_host_mac (int configNr, const u8 *addr)
{
rndis_per_dev_params [configNr].host_mac = addr;
@@ -1046,9 +1063,13 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
return -ENOTSUPP;
params = &rndis_per_dev_params [configNr];
+ /* NOTE: RNDIS is *EXTREMELY* chatty ... Windows constantly polls for
+ * rx/tx statistics and link status, in addition to KEEPALIVE traffic
+ * and normal HC level polling to see if there's any IN traffic.
+ */
+
/* For USB: responses may take up to 10 seconds */
- switch (MsgType)
- {
+ switch (MsgType) {
case REMOTE_NDIS_INITIALIZE_MSG:
DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
__FUNCTION__ );
@@ -1082,10 +1103,9 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
case REMOTE_NDIS_KEEPALIVE_MSG:
/* For USB: host does this every 5 seconds */
-#ifdef VERBOSE
- DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
- __FUNCTION__ );
-#endif
+ if (rndis_debug > 1)
+ DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
+ __FUNCTION__ );
return rndis_keepalive_response (configNr,
(rndis_keepalive_msg_type *)
buf);
@@ -1152,7 +1172,8 @@ void rndis_deregister (int configNr)
}
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
- struct net_device_stats *stats)
+ struct net_device_stats *stats,
+ u16 *cdc_filter)
{
DEBUG("%s:\n", __FUNCTION__ );
if (!dev || !stats) return -1;
@@ -1160,6 +1181,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
rndis_per_dev_params [configNr].dev = dev;
rndis_per_dev_params [configNr].stats = stats;
+ rndis_per_dev_params [configNr].filter = cdc_filter;
return 0;
}
@@ -1178,7 +1200,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
{
- DEBUG("%s:\n", __FUNCTION__ );
+ DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
if (configNr >= RNDIS_MAX_CONFIGS) return -1;
rndis_per_dev_params [configNr].medium = medium;
@@ -1242,6 +1264,7 @@ static rndis_resp_t *rndis_add_response (int configNr, u32 length)
{
rndis_resp_t *r;
+ /* NOTE: this gets copied into ether.c USB_BUFSIZ bytes ... */
r = kmalloc (sizeof (rndis_resp_t) + length, GFP_ATOMIC);
if (!r) return NULL;
diff --git a/drivers/usb/gadget/rndis.h b/drivers/usb/gadget/rndis.h
index 2b5b55df3cfd..95b4c6326100 100644
--- a/drivers/usb/gadget/rndis.h
+++ b/drivers/usb/gadget/rndis.h
@@ -69,90 +69,6 @@
#define OID_PNP_ENABLE_WAKE_UP 0xFD010106
-/* supported OIDs */
-static const u32 oid_supported_list [] =
-{
- /* the general stuff */
- OID_GEN_SUPPORTED_LIST,
- OID_GEN_HARDWARE_STATUS,
- OID_GEN_MEDIA_SUPPORTED,
- OID_GEN_MEDIA_IN_USE,
- OID_GEN_MAXIMUM_FRAME_SIZE,
- OID_GEN_LINK_SPEED,
- OID_GEN_TRANSMIT_BLOCK_SIZE,
- OID_GEN_RECEIVE_BLOCK_SIZE,
- OID_GEN_VENDOR_ID,
- OID_GEN_VENDOR_DESCRIPTION,
- OID_GEN_VENDOR_DRIVER_VERSION,
- OID_GEN_CURRENT_PACKET_FILTER,
- OID_GEN_MAXIMUM_TOTAL_SIZE,
- OID_GEN_MEDIA_CONNECT_STATUS,
- OID_GEN_PHYSICAL_MEDIUM,
-#if 0
- OID_GEN_RNDIS_CONFIG_PARAMETER,
-#endif
-
- /* the statistical stuff */
- OID_GEN_XMIT_OK,
- OID_GEN_RCV_OK,
- OID_GEN_XMIT_ERROR,
- OID_GEN_RCV_ERROR,
- OID_GEN_RCV_NO_BUFFER,
-#ifdef RNDIS_OPTIONAL_STATS
- OID_GEN_DIRECTED_BYTES_XMIT,
- OID_GEN_DIRECTED_FRAMES_XMIT,
- OID_GEN_MULTICAST_BYTES_XMIT,
- OID_GEN_MULTICAST_FRAMES_XMIT,
- OID_GEN_BROADCAST_BYTES_XMIT,
- OID_GEN_BROADCAST_FRAMES_XMIT,
- OID_GEN_DIRECTED_BYTES_RCV,
- OID_GEN_DIRECTED_FRAMES_RCV,
- OID_GEN_MULTICAST_BYTES_RCV,
- OID_GEN_MULTICAST_FRAMES_RCV,
- OID_GEN_BROADCAST_BYTES_RCV,
- OID_GEN_BROADCAST_FRAMES_RCV,
- OID_GEN_RCV_CRC_ERROR,
- OID_GEN_TRANSMIT_QUEUE_LENGTH,
-#endif /* RNDIS_OPTIONAL_STATS */
-
- /* mandatory 802.3 */
- /* the general stuff */
- OID_802_3_PERMANENT_ADDRESS,
- OID_802_3_CURRENT_ADDRESS,
- OID_802_3_MULTICAST_LIST,
- OID_802_3_MAC_OPTIONS,
- OID_802_3_MAXIMUM_LIST_SIZE,
-
- /* the statistical stuff */
- OID_802_3_RCV_ERROR_ALIGNMENT,
- OID_802_3_XMIT_ONE_COLLISION,
- OID_802_3_XMIT_MORE_COLLISIONS,
-#ifdef RNDIS_OPTIONAL_STATS
- OID_802_3_XMIT_DEFERRED,
- OID_802_3_XMIT_MAX_COLLISIONS,
- OID_802_3_RCV_OVERRUN,
- OID_802_3_XMIT_UNDERRUN,
- OID_802_3_XMIT_HEARTBEAT_FAILURE,
- OID_802_3_XMIT_TIMES_CRS_LOST,
- OID_802_3_XMIT_LATE_COLLISIONS,
-#endif /* RNDIS_OPTIONAL_STATS */
-
-#ifdef RNDIS_PM
- /* PM and wakeup are mandatory for USB: */
-
- /* power management */
- OID_PNP_CAPABILITIES,
- OID_PNP_QUERY_POWER,
- OID_PNP_SET_POWER,
-
- /* wake up host */
- OID_PNP_ENABLE_WAKE_UP,
- OID_PNP_ADD_WAKE_UP_PATTERN,
- OID_PNP_REMOVE_WAKE_UP_PATTERN,
-#endif
-};
-
-
typedef struct rndis_init_msg_type
{
__le32 MessageType;
@@ -309,15 +225,18 @@ typedef struct rndis_resp_t
typedef struct rndis_params
{
u8 confignr;
- int used;
+ u8 used;
+ u16 saved_filter;
enum rndis_state state;
- u32 filter;
u32 medium;
u32 speed;
u32 media_state;
+
const u8 *host_mac;
+ u16 *filter;
struct net_device *dev;
struct net_device_stats *stats;
+
u32 vendorID;
const char *vendorDescr;
int (*ack) (struct net_device *);
@@ -329,7 +248,8 @@ int rndis_msg_parser (u8 configNr, u8 *buf);
int rndis_register (int (*rndis_control_ack) (struct net_device *));
void rndis_deregister (int configNr);
int rndis_set_param_dev (u8 configNr, struct net_device *dev,
- struct net_device_stats *stats);
+ struct net_device_stats *stats,
+ u16 *cdc_filter);
int rndis_set_param_vendor (u8 configNr, u32 vendorID,
const char *vendorDescr);
int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed);
@@ -338,6 +258,7 @@ int rndis_rm_hdr (struct sk_buff *skb);
u8 *rndis_get_next_response (int configNr, u32 *length);
void rndis_free_response (int configNr, u8 *buf);
+void rndis_uninit (int configNr);
int rndis_signal_connect (int configNr);
int rndis_signal_disconnect (int configNr);
int rndis_state (int configNr);
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 4d591c764e38..9e4f1c6935a5 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -300,18 +300,18 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
u8 type, unsigned int index, int is_otg);
static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
- int kmalloc_flags);
+ unsigned kmalloc_flags);
static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len,
- int kmalloc_flags);
+ unsigned kmalloc_flags);
static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req);
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags);
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags);
static void gs_free_ports(struct gs_dev *dev);
/* circular buffer */
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags);
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags);
static void gs_buf_free(struct gs_buf *gb);
static void gs_buf_clear(struct gs_buf *gb);
static unsigned int gs_buf_data_avail(struct gs_buf *gb);
@@ -1607,9 +1607,9 @@ static int gs_setup(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
- u16 wIndex = ctrl->wIndex;
- u16 wValue = ctrl->wValue;
- u16 wLength = ctrl->wLength;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequestType & USB_TYPE_MASK) {
case USB_TYPE_STANDARD:
@@ -1651,9 +1651,9 @@ static int gs_setup_standard(struct usb_gadget *gadget,
int ret = -EOPNOTSUPP;
struct gs_dev *dev = get_gadget_data(gadget);
struct usb_request *req = dev->dev_ctrl_req;
- u16 wIndex = ctrl->wIndex;
- u16 wValue = ctrl->wValue;
- u16 wLength = ctrl->wLength;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequest) {
case USB_REQ_GET_DESCRIPTOR:
@@ -1782,9 +1782,9 @@ static int gs_setup_class(struct usb_gadget *gadget,
struct gs_dev *dev = get_gadget_data(gadget);
struct gs_port *port = dev->dev_port[0]; /* ACM only has one port */
struct usb_request *req = dev->dev_ctrl_req;
- u16 wIndex = ctrl->wIndex;
- u16 wValue = ctrl->wValue;
- u16 wLength = ctrl->wLength;
+ u16 wIndex = le16_to_cpu(ctrl->wIndex);
+ u16 wValue = le16_to_cpu(ctrl->wValue);
+ u16 wLength = le16_to_cpu(ctrl->wLength);
switch (ctrl->bRequest) {
case USB_CDC_REQ_SET_LINE_CODING:
@@ -2119,7 +2119,8 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
* Allocate a usb_request and its buffer. Returns a pointer to the
* usb_request or NULL if there is an error.
*/
-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len, int kmalloc_flags)
+static struct usb_request *
+gs_alloc_req(struct usb_ep *ep, unsigned int len, unsigned kmalloc_flags)
{
struct usb_request *req;
@@ -2159,7 +2160,8 @@ static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
* Allocates a request and its buffer, using the given
* endpoint, buffer len, and kmalloc flags.
*/
-static struct gs_req_entry *gs_alloc_req_entry(struct usb_ep *ep, unsigned len, int kmalloc_flags)
+static struct gs_req_entry *
+gs_alloc_req_entry(struct usb_ep *ep, unsigned len, unsigned kmalloc_flags)
{
struct gs_req_entry *req;
@@ -2200,7 +2202,7 @@ static void gs_free_req_entry(struct usb_ep *ep, struct gs_req_entry *req)
*
* The device lock is normally held when calling this function.
*/
-static int gs_alloc_ports(struct gs_dev *dev, int kmalloc_flags)
+static int gs_alloc_ports(struct gs_dev *dev, unsigned kmalloc_flags)
{
int i;
struct gs_port *port;
@@ -2282,7 +2284,7 @@ static void gs_free_ports(struct gs_dev *dev)
*
* Allocate a circular buffer and all associated memory.
*/
-static struct gs_buf *gs_buf_alloc(unsigned int size, int kmalloc_flags)
+static struct gs_buf *gs_buf_alloc(unsigned int size, unsigned kmalloc_flags)
{
struct gs_buf *gb;
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 6e49432071a1..bb9b2d94eed5 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -612,7 +612,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
}
static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
+source_sink_start_ep (struct usb_ep *ep, unsigned gfp_flags)
{
struct usb_request *req;
int status;
@@ -640,7 +640,7 @@ source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
}
static int
-set_source_sink_config (struct zero_dev *dev, int gfp_flags)
+set_source_sink_config (struct zero_dev *dev, unsigned gfp_flags)
{
int result = 0;
struct usb_ep *ep;
@@ -744,7 +744,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
}
static int
-set_loopback_config (struct zero_dev *dev, int gfp_flags)
+set_loopback_config (struct zero_dev *dev, unsigned gfp_flags)
{
int result = 0;
struct usb_ep *ep;
@@ -845,7 +845,7 @@ static void zero_reset_config (struct zero_dev *dev)
* by limiting configuration choices (like the pxa2xx).
*/
static int
-zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
+zero_set_config (struct zero_dev *dev, unsigned number, unsigned gfp_flags)
{
int result = 0;
struct usb_gadget *gadget = dev->gadget;
@@ -919,9 +919,9 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
struct zero_dev *dev = get_gadget_data (gadget);
struct usb_request *req = dev->req;
int value = -EOPNOTSUPP;
- u16 w_index = ctrl->wIndex;
- u16 w_value = ctrl->wValue;
- u16 w_length = ctrl->wLength;
+ u16 w_index = le16_to_cpu(ctrl->wIndex);
+ u16 w_value = le16_to_cpu(ctrl->wValue);
+ u16 w_length = le16_to_cpu(ctrl->wLength);
/* usually this stores reply data in the pre-allocated ep0 buffer,
* but config change events will reconfigure hardware.
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 19e598c9641f..ed1899d307db 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -49,6 +49,19 @@ config USB_EHCI_ROOT_HUB_TT
This supports the EHCI implementation from TransDimension Inc.
+config USB_ISP116X_HCD
+ tristate "ISP116X HCD support"
+ depends on USB
+ default N
+ ---help---
+ The ISP1160 and ISP1161 chips are USB host controllers. Enable this
+ option if your board has this chip. If unsure, say N.
+
+ This driver does not support isochronous transfers.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp116x-hcd.
+
config USB_OHCI_HCD
tristate "OHCI HCD support"
depends on USB && USB_ARCH_HAS_OHCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 5dbd3e7a27c7..350d14fc1cc9 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -4,6 +4,7 @@
#
obj-$(CONFIG_USB_EHCI_HCD) += ehci-hcd.o
+obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 2ff11d53567b..50cb01831075 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -254,7 +254,7 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
}
return scnprintf (buf, len,
- "%s%sport %d status %06x%s%s sig=%s %s%s%s%s%s%s%s%s%s",
+ "%s%sport %d status %06x%s%s sig=%s%s%s%s%s%s%s%s%s%s",
label, label [0] ? " " : "", port, status,
(status & PORT_POWER) ? " POWER" : "",
(status & PORT_OWNER) ? " OWNER" : "",
@@ -644,9 +644,11 @@ show_registers (struct class_device *class_dev, char *buf)
if (bus->controller->power.power_state) {
size = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+ "%s\n"
"SUSPENDED (no register access)\n",
hcd->self.controller->bus->name,
- hcd->self.controller->bus_id);
+ hcd->self.controller->bus_id,
+ hcd->product_desc);
goto done;
}
@@ -654,13 +656,53 @@ show_registers (struct class_device *class_dev, char *buf)
i = HC_VERSION(readl (&ehci->caps->hc_capbase));
temp = scnprintf (next, size,
"bus %s, device %s (driver " DRIVER_VERSION ")\n"
+ "%s\n"
"EHCI %x.%02x, hcd state %d\n",
hcd->self.controller->bus->name,
hcd->self.controller->bus_id,
+ hcd->product_desc,
i >> 8, i & 0x0ff, hcd->state);
size -= temp;
next += temp;
+#ifdef CONFIG_PCI
+ /* EHCI 0.96 and later may have "extended capabilities" */
+ if (hcd->self.controller->bus == &pci_bus_type) {
+ struct pci_dev *pdev;
+ u32 offset, cap, cap2;
+ unsigned count = 256/4;
+
+ pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+ offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+ while (offset && count--) {
+ pci_read_config_dword (pdev, offset, &cap);
+ switch (cap & 0xff) {
+ case 1:
+ temp = scnprintf (next, size,
+ "ownership %08x%s%s\n", cap,
+ (cap & (1 << 24)) ? " linux" : "",
+ (cap & (1 << 16)) ? " firmware" : "");
+ size -= temp;
+ next += temp;
+
+ offset += 4;
+ pci_read_config_dword (pdev, offset, &cap2);
+ temp = scnprintf (next, size,
+ "SMI sts/enable 0x%08x\n", cap2);
+ size -= temp;
+ next += temp;
+ break;
+ case 0: /* illegal reserved capability */
+ cap = 0;
+ /* FALLTHROUGH */
+ default: /* unknown */
+ break;
+ }
+ temp = (cap >> 8) & 0xff;
+ }
+ }
+#endif
+
// FIXME interpret both types of params
i = readl (&ehci->caps->hcs_params);
temp = scnprintf (next, size, "structural params 0x%08x\n", i);
@@ -696,12 +738,19 @@ show_registers (struct class_device *class_dev, char *buf)
size -= temp;
next += temp;
- for (i = 0; i < HCS_N_PORTS (ehci->hcs_params); i++) {
- temp = dbg_port_buf (scratch, sizeof scratch, label, i + 1,
- readl (&ehci->regs->port_status [i]));
+ for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
+ temp = dbg_port_buf (scratch, sizeof scratch, label, i,
+ readl (&ehci->regs->port_status [i - 1]));
temp = scnprintf (next, size, fmt, temp, scratch);
size -= temp;
next += temp;
+ if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
+ temp = scnprintf (next, size,
+ " debug control %08x\n",
+ readl (&ehci->debug->control));
+ size -= temp;
+ next += temp;
+ }
}
if (ehci->reclaim) {
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index bc69bd7acebe..149b13fc0a71 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -304,30 +304,31 @@ static void ehci_watchdog (unsigned long param)
*/
static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
{
+ struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+
+ /* always say Linux will own the hardware */
+ pci_write_config_byte(pdev, where + 3, 1);
+
+ /* maybe wait a while for BIOS to respond */
if (cap & (1 << 16)) {
int msec = 5000;
- struct pci_dev *pdev =
- to_pci_dev(ehci_to_hcd(ehci)->self.controller);
- /* request handoff to OS */
- cap |= 1 << 24;
- pci_write_config_dword(pdev, where, cap);
-
- /* and wait a while for it to happen */
do {
msleep(10);
msec -= 10;
pci_read_config_dword(pdev, where, &cap);
} while ((cap & (1 << 16)) && msec);
if (cap & (1 << 16)) {
- ehci_err (ehci, "BIOS handoff failed (%d, %04x)\n",
+ ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
where, cap);
// some BIOS versions seem buggy...
// return 1;
ehci_warn (ehci, "continuing after BIOS bug...\n");
- return 0;
- }
- ehci_dbg (ehci, "BIOS handoff succeeded\n");
+ /* disable all SMIs, and clear "BIOS owns" flag */
+ pci_write_config_dword(pdev, where + 4, 0);
+ pci_write_config_byte(pdev, where + 2, 0);
+ } else
+ ehci_dbg(ehci, "BIOS handoff succeeded\n");
}
return 0;
}
@@ -492,8 +493,6 @@ static int ehci_start (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
u32 temp;
- struct usb_device *udev;
- struct usb_bus *bus;
int retval;
u32 hcc_params;
u8 sbrn = 0;
@@ -588,8 +587,8 @@ static int ehci_start (struct usb_hcd *hcd)
writel (0, &ehci->regs->segment);
#if 0
// this is deeply broken on almost all architectures
- if (!pci_set_dma_mask (to_pci_dev(hcd->self.controller), 0xffffffffffffffffULL))
- ehci_info (ehci, "enabled 64bit PCI DMA\n");
+ if (!dma_set_mask (hcd->self.controller, DMA_64BIT_MASK))
+ ehci_info (ehci, "enabled 64bit DMA\n");
#endif
}
@@ -631,17 +630,6 @@ static int ehci_start (struct usb_hcd *hcd)
/* set async sleep time = 10 us ... ? */
- /* wire up the root hub */
- bus = hcd_to_bus (hcd);
- udev = first ? usb_alloc_dev (NULL, bus, 0) : bus->root_hub;
- if (!udev) {
-done2:
- ehci_mem_cleanup (ehci);
- return -ENOMEM;
- }
- udev->speed = USB_SPEED_HIGH;
- udev->state = first ? USB_STATE_ATTACHED : USB_STATE_CONFIGURED;
-
/*
* Start, enabling full USB 2.0 functionality ... usb 1.1 devices
* are explicitly handed to companion controller(s), so no TT is
@@ -664,24 +652,6 @@ done2:
first ? "initialized" : "restarted",
temp >> 8, temp & 0xff, DRIVER_VERSION);
- /*
- * From here on, khubd concurrently accesses the root
- * hub; drivers will be talking to enumerated devices.
- * (On restart paths, khubd already knows about the root
- * hub and could find work as soon as we wrote FLAG_CF.)
- *
- * Before this point the HC was idle/ready. After, khubd
- * and device drivers may start it running.
- */
- if (first && usb_hcd_register_root_hub (udev, hcd) != 0) {
- if (hcd->state == HC_STATE_RUNNING)
- ehci_quiesce (ehci);
- ehci_reset (ehci);
- usb_put_dev (udev);
- retval = -ENODEV;
- goto done2;
- }
-
writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
if (first)
@@ -990,7 +960,7 @@ static int ehci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
) {
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
struct list_head qtd_list;
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index d7b4f7939ded..36cc1f2218d5 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 by 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
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 7df9b9af54f6..d74b2d68a50e 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001-2002 by David Brownell
+ * Copyright (C) 2001-2004 by 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
@@ -898,7 +898,7 @@ submit_async (
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
- int mem_flags
+ unsigned mem_flags
) {
struct ehci_qtd *qtd;
int epnum;
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 2fa1ffee5ff3..9af4f64532a9 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -588,7 +588,7 @@ static int intr_submit (
struct usb_host_endpoint *ep,
struct urb *urb,
struct list_head *qtd_list,
- int mem_flags
+ unsigned mem_flags
) {
unsigned epnum;
unsigned long flags;
@@ -633,13 +633,12 @@ done:
/* ehci_iso_stream ops work with both ITD and SITD */
static struct ehci_iso_stream *
-iso_stream_alloc (int mem_flags)
+iso_stream_alloc (unsigned mem_flags)
{
struct ehci_iso_stream *stream;
- stream = kmalloc(sizeof *stream, mem_flags);
+ stream = kcalloc(1, sizeof *stream, mem_flags);
if (likely (stream != NULL)) {
- memset (stream, 0, sizeof(*stream));
INIT_LIST_HEAD(&stream->td_list);
INIT_LIST_HEAD(&stream->free_list);
stream->next_uframe = -1;
@@ -847,7 +846,7 @@ iso_stream_find (struct ehci_hcd *ehci, struct urb *urb)
/* ehci_iso_sched ops can be ITD-only or SITD-only */
static struct ehci_iso_sched *
-iso_sched_alloc (unsigned packets, int mem_flags)
+iso_sched_alloc (unsigned packets, unsigned mem_flags)
{
struct ehci_iso_sched *iso_sched;
int size = sizeof *iso_sched;
@@ -894,7 +893,7 @@ itd_sched_init (
trans |= length << 16;
uframe->transaction = cpu_to_le32 (trans);
- /* might need to cross a buffer page within a td */
+ /* might need to cross a buffer page within a uframe */
uframe->bufp = (buf & ~(u64)0x0fff);
buf += length;
if (unlikely ((uframe->bufp != (buf & ~(u64)0x0fff))))
@@ -920,7 +919,7 @@ itd_urb_transaction (
struct ehci_iso_stream *stream,
struct ehci_hcd *ehci,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
)
{
struct ehci_itd *itd;
@@ -1194,6 +1193,7 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
{
int i;
+ /* it's been recently zeroed */
itd->hw_next = EHCI_LIST_END;
itd->hw_bufp [0] = stream->buf0;
itd->hw_bufp [1] = stream->buf1;
@@ -1210,8 +1210,7 @@ itd_patch (
struct ehci_itd *itd,
struct ehci_iso_sched *iso_sched,
unsigned index,
- u16 uframe,
- int first
+ u16 uframe
)
{
struct ehci_iso_packet *uf = &iso_sched->packet [index];
@@ -1228,7 +1227,7 @@ itd_patch (
itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
/* iso_frame_desc[].offset must be strictly increasing */
- if (unlikely (!first && uf->cross)) {
+ if (unlikely (uf->cross)) {
u64 bufp = uf->bufp + 4096;
itd->pg = ++pg;
itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
@@ -1257,7 +1256,7 @@ itd_link_urb (
struct ehci_iso_stream *stream
)
{
- int packet, first = 1;
+ int packet;
unsigned next_uframe, uframe, frame;
struct ehci_iso_sched *iso_sched = urb->hcpriv;
struct ehci_itd *itd;
@@ -1290,7 +1289,6 @@ itd_link_urb (
list_move_tail (&itd->itd_list, &stream->td_list);
itd->stream = iso_stream_get (stream);
itd->urb = usb_get_urb (urb);
- first = 1;
itd_init (stream, itd);
}
@@ -1298,8 +1296,7 @@ itd_link_urb (
frame = next_uframe >> 3;
itd->usecs [uframe] = stream->usecs;
- itd_patch (itd, iso_sched, packet, uframe, first);
- first = 0;
+ itd_patch (itd, iso_sched, packet, uframe);
next_uframe += stream->interval;
stream->depth += stream->interval;
@@ -1415,7 +1412,8 @@ itd_complete (
/*-------------------------------------------------------------------------*/
-static int itd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
+ unsigned mem_flags)
{
int status = -EINVAL;
unsigned long flags;
@@ -1526,7 +1524,7 @@ sitd_urb_transaction (
struct ehci_iso_stream *stream,
struct ehci_hcd *ehci,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
)
{
struct ehci_sitd *sitd;
@@ -1775,7 +1773,8 @@ sitd_complete (
}
-static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+ unsigned mem_flags)
{
int status = -EINVAL;
unsigned long flags;
@@ -1825,7 +1824,8 @@ done:
#else
static inline int
-sitd_submit (struct ehci_hcd *ehci, struct urb *urb, int mem_flags)
+sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
+ unsigned mem_flags)
{
ehci_dbg (ehci, "split iso support is disabled\n");
return -ENOSYS;
diff --git a/drivers/usb/host/hc_crisv10.c b/drivers/usb/host/hc_crisv10.c
index d9883d774d3a..81f8f6b7fdce 100644
--- a/drivers/usb/host/hc_crisv10.c
+++ b/drivers/usb/host/hc_crisv10.c
@@ -463,7 +463,8 @@ static void etrax_usb_free_epid(int epid);
static int etrax_remove_from_sb_list(struct urb *urb);
-static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma);
+static void* etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size,
+ unsigned mem_flags, dma_addr_t *dma);
static void etrax_usb_buffer_free(struct usb_bus *bus, size_t size, void *addr, dma_addr_t dma);
static void etrax_usb_add_to_bulk_sb_list(struct urb *urb, int epid);
@@ -476,7 +477,7 @@ static int etrax_usb_submit_ctrl_urb(struct urb *urb);
static int etrax_usb_submit_intr_urb(struct urb *urb);
static int etrax_usb_submit_isoc_urb(struct urb *urb);
-static int etrax_usb_submit_urb(struct urb *urb, int mem_flags);
+static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags);
static int etrax_usb_unlink_urb(struct urb *urb, int status);
static int etrax_usb_get_frame_number(struct usb_device *usb_dev);
@@ -1262,7 +1263,7 @@ static int etrax_usb_allocate_epid(void)
return -1;
}
-static int etrax_usb_submit_urb(struct urb *urb, int mem_flags)
+static int etrax_usb_submit_urb(struct urb *urb, unsigned mem_flags)
{
etrax_hc_t *hc;
int ret = -EINVAL;
@@ -4277,7 +4278,8 @@ etrax_usb_bulk_eot_timer_func(unsigned long dummy)
}
static void*
-etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size, int mem_flags, dma_addr_t *dma)
+etrax_usb_buffer_alloc(struct usb_bus* bus, size_t size,
+ unsigned mem_flags, dma_addr_t *dma)
{
return kmalloc(size, mem_flags);
}
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
new file mode 100644
index 000000000000..50b1970fe6b6
--- /dev/null
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -0,0 +1,1871 @@
+/*
+ * ISP116x HCD (Host Controller Driver) for USB.
+ *
+ * Derived from the SL811 HCD, rewritten for ISP116x.
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ *
+ * Portions:
+ * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Copyright (C) 2004 David Brownell
+ *
+ * Periodic scheduling is based on Roman's OHCI code
+ * Copyright (C) 1999 Roman Weissgaerber
+ *
+ */
+
+/*
+ * The driver basically works. A number of people have used it with a range
+ * of devices.
+ *
+ * The driver passes all usbtests 1-14.
+ *
+ * Suspending/resuming of root hub via sysfs works. Remote wakeup works too.
+ * And suspending/resuming of platform device works too. Suspend/resume
+ * via HCD operations vector is not implemented.
+ *
+ * Iso transfer support is not implemented. Adding this would include
+ * implementing recovery from the failure to service the processed ITL
+ * fifo ram in time, which will involve chip reset.
+ *
+ * TODO:
+ + More testing of suspend/resume.
+*/
+
+/*
+ ISP116x chips require certain delays between accesses to its
+ registers. The following timing options exist.
+
+ 1. Configure your memory controller (the best)
+ 2. Implement platform-specific delay function possibly
+ combined with configuring the memory controller; see
+ include/linux/usb-isp116x.h for more info. Some broken
+ memory controllers line LH7A400 SMC need this. Also,
+ uncomment for that to work the following
+ USE_PLATFORM_DELAY macro.
+ 3. Use ndelay (easiest, poorest). For that, uncomment
+ the following USE_NDELAY macro.
+*/
+#define USE_PLATFORM_DELAY
+//#define USE_NDELAY
+
+//#define DEBUG
+//#define VERBOSE
+/* Transfer descriptors. See dump_ptd() for printout format */
+//#define PTD_TRACE
+/* enqueuing/finishing log of urbs */
+//#define URB_TRACE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/usb_isp116x.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#ifndef DEBUG
+# define STUB_DEBUG_FILE
+#endif
+
+#include "../core/hcd.h"
+#include "isp116x.h"
+
+#define DRIVER_VERSION "08 Apr 2005"
+#define DRIVER_DESC "ISP116x USB Host Controller Driver"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+static const char hcd_name[] = "isp116x-hcd";
+
+/*-----------------------------------------------------------------*/
+
+/*
+ Write len bytes to fifo, pad till 32-bit boundary
+ */
+static void write_ptddata_to_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+ u8 *dp = (u8 *) buf;
+ u16 *dp2 = (u16 *) buf;
+ u16 w;
+ int quot = len % 4;
+
+ if ((unsigned long)dp2 & 1) {
+ /* not aligned */
+ for (; len > 1; len -= 2) {
+ w = *dp++;
+ w |= *dp++ << 8;
+ isp116x_raw_write_data16(isp116x, w);
+ }
+ if (len)
+ isp116x_write_data16(isp116x, (u16) * dp);
+ } else {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ isp116x_raw_write_data16(isp116x, *dp2++);
+ if (len)
+ isp116x_write_data16(isp116x, 0xff & *((u8 *) dp2));
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_raw_write_data16(isp116x, 0);
+}
+
+/*
+ Read len bytes from fifo and then read till 32-bit boundary.
+ */
+static void read_ptddata_from_fifo(struct isp116x *isp116x, void *buf, int len)
+{
+ u8 *dp = (u8 *) buf;
+ u16 *dp2 = (u16 *) buf;
+ u16 w;
+ int quot = len % 4;
+
+ if ((unsigned long)dp2 & 1) {
+ /* not aligned */
+ for (; len > 1; len -= 2) {
+ w = isp116x_raw_read_data16(isp116x);
+ *dp++ = w & 0xff;
+ *dp++ = (w >> 8) & 0xff;
+ }
+ if (len)
+ *dp = 0xff & isp116x_read_data16(isp116x);
+ } else {
+ /* aligned */
+ for (; len > 1; len -= 2)
+ *dp2++ = isp116x_raw_read_data16(isp116x);
+ if (len)
+ *(u8 *) dp2 = 0xff & isp116x_read_data16(isp116x);
+ }
+ if (quot == 1 || quot == 2)
+ isp116x_raw_read_data16(isp116x);
+}
+
+/*
+ Write ptd's and data for scheduled transfers into
+ the fifo ram. Fifo must be empty and ready.
+*/
+static void pack_fifo(struct isp116x *isp116x)
+{
+ struct isp116x_ep *ep;
+ struct ptd *ptd;
+ int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+ ? isp116x->atl_bufshrt : isp116x->atl_buflen;
+ int ptd_count = 0;
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ isp116x_write_addr(isp116x, HCATLPORT | ISP116x_WRITE_OFFSET);
+ for (ep = isp116x->atl_active; ep; ep = ep->active) {
+ ++ptd_count;
+ ptd = &ep->ptd;
+ dump_ptd(ptd);
+ dump_ptd_out_data(ptd, ep->data);
+ isp116x_write_data16(isp116x, ptd->count);
+ isp116x_write_data16(isp116x, ptd->mps);
+ isp116x_write_data16(isp116x, ptd->len);
+ isp116x_write_data16(isp116x, ptd->faddr);
+ buflen -= sizeof(struct ptd);
+ /* Skip writing data for last IN PTD */
+ if (ep->active || (isp116x->atl_last_dir != PTD_DIR_IN)) {
+ write_ptddata_to_fifo(isp116x, ep->data, ep->length);
+ buflen -= ALIGN(ep->length, 4);
+ }
+ }
+ BUG_ON(buflen);
+}
+
+/*
+ Read the processed ptd's and data from fifo ram back to
+ URBs' buffers. Fifo must be full and done
+*/
+static void unpack_fifo(struct isp116x *isp116x)
+{
+ struct isp116x_ep *ep;
+ struct ptd *ptd;
+ int buflen = isp116x->atl_last_dir == PTD_DIR_IN
+ ? isp116x->atl_buflen : isp116x->atl_bufshrt;
+
+ isp116x_write_reg16(isp116x, HCuPINT, HCuPINT_AIIEOT);
+ isp116x_write_reg16(isp116x, HCXFERCTR, buflen);
+ isp116x_write_addr(isp116x, HCATLPORT);
+ for (ep = isp116x->atl_active; ep; ep = ep->active) {
+ ptd = &ep->ptd;
+ ptd->count = isp116x_read_data16(isp116x);
+ ptd->mps = isp116x_read_data16(isp116x);
+ ptd->len = isp116x_read_data16(isp116x);
+ ptd->faddr = isp116x_read_data16(isp116x);
+ buflen -= sizeof(struct ptd);
+ /* Skip reading data for last Setup or Out PTD */
+ if (ep->active || (isp116x->atl_last_dir == PTD_DIR_IN)) {
+ read_ptddata_from_fifo(isp116x, ep->data, ep->length);
+ buflen -= ALIGN(ep->length, 4);
+ }
+ dump_ptd(ptd);
+ dump_ptd_in_data(ptd, ep->data);
+ }
+ BUG_ON(buflen);
+}
+
+/*---------------------------------------------------------------*/
+
+/*
+ Set up PTD's.
+*/
+static void preproc_atl_queue(struct isp116x *isp116x)
+{
+ struct isp116x_ep *ep;
+ struct urb *urb;
+ struct ptd *ptd;
+ u16 toggle = 0, dir = PTD_DIR_SETUP, len;
+
+ for (ep = isp116x->atl_active; ep; ep = ep->active) {
+ BUG_ON(list_empty(&ep->hep->urb_list));
+ urb = container_of(ep->hep->urb_list.next,
+ struct urb, urb_list);
+ ptd = &ep->ptd;
+ len = ep->length;
+ spin_lock(&urb->lock);
+ ep->data = (unsigned char *)urb->transfer_buffer
+ + urb->actual_length;
+
+ switch (ep->nextpid) {
+ case USB_PID_IN:
+ toggle = usb_gettoggle(urb->dev, ep->epnum, 0);
+ dir = PTD_DIR_IN;
+ break;
+ case USB_PID_OUT:
+ toggle = usb_gettoggle(urb->dev, ep->epnum, 1);
+ dir = PTD_DIR_OUT;
+ break;
+ case USB_PID_SETUP:
+ len = sizeof(struct usb_ctrlrequest);
+ ep->data = urb->setup_packet;
+ break;
+ case USB_PID_ACK:
+ toggle = 1;
+ len = 0;
+ dir = (urb->transfer_buffer_length
+ && usb_pipein(urb->pipe))
+ ? PTD_DIR_OUT : PTD_DIR_IN;
+ break;
+ default:
+ ERR("%s %d: ep->nextpid %d\n", __func__, __LINE__,
+ ep->nextpid);
+ BUG();
+ }
+
+ ptd->count = PTD_CC_MSK | PTD_ACTIVE_MSK | PTD_TOGGLE(toggle);
+ ptd->mps = PTD_MPS(ep->maxpacket)
+ | PTD_SPD(urb->dev->speed == USB_SPEED_LOW)
+ | PTD_EP(ep->epnum);
+ ptd->len = PTD_LEN(len) | PTD_DIR(dir);
+ ptd->faddr = PTD_FA(usb_pipedevice(urb->pipe));
+ spin_unlock(&urb->lock);
+ if (!ep->active) {
+ ptd->mps |= PTD_LAST_MSK;
+ isp116x->atl_last_dir = dir;
+ }
+ isp116x->atl_bufshrt = sizeof(struct ptd) + isp116x->atl_buflen;
+ isp116x->atl_buflen = isp116x->atl_bufshrt + ALIGN(len, 4);
+ }
+}
+
+/*
+ Analyze transfer results, handle partial transfers and errors
+*/
+static void postproc_atl_queue(struct isp116x *isp116x)
+{
+ struct isp116x_ep *ep;
+ struct urb *urb;
+ struct usb_device *udev;
+ struct ptd *ptd;
+ int short_not_ok;
+ u8 cc;
+
+ for (ep = isp116x->atl_active; ep; ep = ep->active) {
+ BUG_ON(list_empty(&ep->hep->urb_list));
+ urb =
+ container_of(ep->hep->urb_list.next, struct urb, urb_list);
+ udev = urb->dev;
+ ptd = &ep->ptd;
+ cc = PTD_GET_CC(ptd);
+
+ spin_lock(&urb->lock);
+ short_not_ok = 1;
+
+ /* Data underrun is special. For allowed underrun
+ we clear the error and continue as normal. For
+ forbidden underrun we finish the DATA stage
+ immediately while for control transfer,
+ we do a STATUS stage. */
+ if (cc == TD_DATAUNDERRUN) {
+ if (!(urb->transfer_flags & URB_SHORT_NOT_OK)) {
+ DBG("Allowed data underrun\n");
+ cc = TD_CC_NOERROR;
+ short_not_ok = 0;
+ } else {
+ ep->error_count = 1;
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_ACK;
+ else
+ usb_settoggle(udev, ep->epnum,
+ ep->nextpid ==
+ USB_PID_OUT,
+ PTD_GET_TOGGLE(ptd) ^ 1);
+ urb->status = cc_to_error[TD_DATAUNDERRUN];
+ spin_unlock(&urb->lock);
+ continue;
+ }
+ }
+ /* Keep underrun error through the STATUS stage */
+ if (urb->status == cc_to_error[TD_DATAUNDERRUN])
+ cc = TD_DATAUNDERRUN;
+
+ if (cc != TD_CC_NOERROR && cc != TD_NOTACCESSED
+ && (++ep->error_count >= 3 || cc == TD_CC_STALL
+ || cc == TD_DATAOVERRUN)) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = cc_to_error[cc];
+ if (ep->nextpid == USB_PID_ACK)
+ ep->nextpid = 0;
+ spin_unlock(&urb->lock);
+ continue;
+ }
+ /* According to usb spec, zero-length Int transfer signals
+ finishing of the urb. Hey, does this apply only
+ for IN endpoints? */
+ if (usb_pipeint(urb->pipe) && !PTD_GET_LEN(ptd)) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ spin_unlock(&urb->lock);
+ continue;
+ }
+
+ /* Relax after previously failed, but later succeeded
+ or correctly NAK'ed retransmission attempt */
+ if (ep->error_count
+ && (cc == TD_CC_NOERROR || cc == TD_NOTACCESSED))
+ ep->error_count = 0;
+
+ /* Take into account idiosyncracies of the isp116x chip
+ regarding toggle bit for failed transfers */
+ if (ep->nextpid == USB_PID_OUT)
+ usb_settoggle(udev, ep->epnum, 1, PTD_GET_TOGGLE(ptd)
+ ^ (ep->error_count > 0));
+ else if (ep->nextpid == USB_PID_IN)
+ usb_settoggle(udev, ep->epnum, 0, PTD_GET_TOGGLE(ptd)
+ ^ (ep->error_count > 0));
+
+ switch (ep->nextpid) {
+ case USB_PID_IN:
+ case USB_PID_OUT:
+ urb->actual_length += PTD_GET_COUNT(ptd);
+ if (PTD_GET_ACTIVE(ptd)
+ || (cc != TD_CC_NOERROR && cc < 0x0E))
+ break;
+ if (urb->transfer_buffer_length != urb->actual_length) {
+ if (short_not_ok)
+ break;
+ } else {
+ if (urb->transfer_flags & URB_ZERO_PACKET
+ && ep->nextpid == USB_PID_OUT
+ && !(PTD_GET_COUNT(ptd) % ep->maxpacket)) {
+ DBG("Zero packet requested\n");
+ break;
+ }
+ }
+ /* All data for this URB is transferred, let's finish */
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_ACK;
+ else if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ break;
+ case USB_PID_SETUP:
+ if (PTD_GET_ACTIVE(ptd)
+ || (cc != TD_CC_NOERROR && cc < 0x0E))
+ break;
+ if (urb->transfer_buffer_length == urb->actual_length)
+ ep->nextpid = USB_PID_ACK;
+ else if (usb_pipeout(urb->pipe)) {
+ usb_settoggle(udev, 0, 1, 1);
+ ep->nextpid = USB_PID_OUT;
+ } else {
+ usb_settoggle(udev, 0, 0, 1);
+ ep->nextpid = USB_PID_IN;
+ }
+ break;
+ case USB_PID_ACK:
+ if (PTD_GET_ACTIVE(ptd)
+ || (cc != TD_CC_NOERROR && cc < 0x0E))
+ break;
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ ep->nextpid = 0;
+ break;
+ default:
+ BUG_ON(1);
+ }
+ spin_unlock(&urb->lock);
+ }
+}
+
+/*
+ Take done or failed requests out of schedule. Give back
+ processed urbs.
+*/
+static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
+ struct urb *urb, struct pt_regs *regs)
+__releases(isp116x->lock) __acquires(isp116x->lock)
+{
+ unsigned i;
+
+ urb->hcpriv = NULL;
+ ep->error_count = 0;
+
+ if (usb_pipecontrol(urb->pipe))
+ ep->nextpid = USB_PID_SETUP;
+
+ urb_dbg(urb, "Finish");
+
+ spin_unlock(&isp116x->lock);
+ usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, regs);
+ spin_lock(&isp116x->lock);
+
+ /* take idle endpoints out of the schedule */
+ if (!list_empty(&ep->hep->urb_list))
+ return;
+
+ /* async deschedule */
+ if (!list_empty(&ep->schedule)) {
+ list_del_init(&ep->schedule);
+ return;
+ }
+
+ /* periodic deschedule */
+ DBG("deschedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+ struct isp116x_ep *temp;
+ struct isp116x_ep **prev = &isp116x->periodic[i];
+
+ while (*prev && ((temp = *prev) != ep))
+ prev = &temp->next;
+ if (*prev)
+ *prev = ep->next;
+ isp116x->load[i] -= ep->load;
+ }
+ ep->branch = PERIODIC_SIZE;
+ isp116x_to_hcd(isp116x)->self.bandwidth_allocated -=
+ ep->load / ep->period;
+
+ /* switch irq type? */
+ if (!--isp116x->periodic_count) {
+ isp116x->irqenb &= ~HCuPINT_SOF;
+ isp116x->irqenb |= HCuPINT_ATL;
+ }
+}
+
+/*
+ Scan transfer lists, schedule transfers, send data off
+ to chip.
+ */
+static void start_atl_transfers(struct isp116x *isp116x)
+{
+ struct isp116x_ep *last_ep = NULL, *ep;
+ struct urb *urb;
+ u16 load = 0;
+ int len, index, speed, byte_time;
+
+ if (atomic_read(&isp116x->atl_finishing))
+ return;
+
+ if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state))
+ return;
+
+ /* FIFO not empty? */
+ if (isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_FULL)
+ return;
+
+ isp116x->atl_active = NULL;
+ isp116x->atl_buflen = isp116x->atl_bufshrt = 0;
+
+ /* Schedule int transfers */
+ if (isp116x->periodic_count) {
+ isp116x->fmindex = index =
+ (isp116x->fmindex + 1) & (PERIODIC_SIZE - 1);
+ if ((load = isp116x->load[index])) {
+ /* Bring all int transfers for this frame
+ into the active queue */
+ isp116x->atl_active = last_ep =
+ isp116x->periodic[index];
+ while (last_ep->next)
+ last_ep = (last_ep->active = last_ep->next);
+ last_ep->active = NULL;
+ }
+ }
+
+ /* Schedule control/bulk transfers */
+ list_for_each_entry(ep, &isp116x->async, schedule) {
+ urb = container_of(ep->hep->urb_list.next,
+ struct urb, urb_list);
+ speed = urb->dev->speed;
+ byte_time = speed == USB_SPEED_LOW
+ ? BYTE_TIME_LOWSPEED : BYTE_TIME_FULLSPEED;
+
+ if (ep->nextpid == USB_PID_SETUP) {
+ len = sizeof(struct usb_ctrlrequest);
+ } else if (ep->nextpid == USB_PID_ACK) {
+ len = 0;
+ } else {
+ /* Find current free length ... */
+ len = (MAX_LOAD_LIMIT - load) / byte_time;
+
+ /* ... then limit it to configured max size ... */
+ len = min(len, speed == USB_SPEED_LOW ?
+ MAX_TRANSFER_SIZE_LOWSPEED :
+ MAX_TRANSFER_SIZE_FULLSPEED);
+
+ /* ... and finally cut to the multiple of MaxPacketSize,
+ or to the real length if there's enough room. */
+ if (len <
+ (urb->transfer_buffer_length -
+ urb->actual_length)) {
+ len -= len % ep->maxpacket;
+ if (!len)
+ continue;
+ } else
+ len = urb->transfer_buffer_length -
+ urb->actual_length;
+ BUG_ON(len < 0);
+ }
+
+ load += len * byte_time;
+ if (load > MAX_LOAD_LIMIT)
+ break;
+
+ ep->active = NULL;
+ ep->length = len;
+ if (last_ep)
+ last_ep->active = ep;
+ else
+ isp116x->atl_active = ep;
+ last_ep = ep;
+ }
+
+ /* Avoid starving of endpoints */
+ if ((&isp116x->async)->next != (&isp116x->async)->prev)
+ list_move(&isp116x->async, (&isp116x->async)->next);
+
+ if (isp116x->atl_active) {
+ preproc_atl_queue(isp116x);
+ pack_fifo(isp116x);
+ }
+}
+
+/*
+ Finish the processed transfers
+*/
+static void finish_atl_transfers(struct isp116x *isp116x, struct pt_regs *regs)
+{
+ struct isp116x_ep *ep;
+ struct urb *urb;
+
+ if (!isp116x->atl_active)
+ return;
+ /* Fifo not ready? */
+ if (!(isp116x_read_reg16(isp116x, HCBUFSTAT) & HCBUFSTAT_ATL_DONE))
+ return;
+
+ atomic_inc(&isp116x->atl_finishing);
+ unpack_fifo(isp116x);
+ postproc_atl_queue(isp116x);
+ for (ep = isp116x->atl_active; ep; ep = ep->active) {
+ urb =
+ container_of(ep->hep->urb_list.next, struct urb, urb_list);
+ /* USB_PID_ACK check here avoids finishing of
+ control transfers, for which TD_DATAUNDERRUN
+ occured, while URB_SHORT_NOT_OK was set */
+ if (urb && urb->status != -EINPROGRESS
+ && ep->nextpid != USB_PID_ACK)
+ finish_request(isp116x, ep, urb, regs);
+ }
+ atomic_dec(&isp116x->atl_finishing);
+}
+
+static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ u16 irqstat;
+ irqreturn_t ret = IRQ_NONE;
+
+ spin_lock(&isp116x->lock);
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+ irqstat = isp116x_read_reg16(isp116x, HCuPINT);
+ isp116x_write_reg16(isp116x, HCuPINT, irqstat);
+
+ if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+ ret = IRQ_HANDLED;
+ finish_atl_transfers(isp116x, regs);
+ }
+
+ if (irqstat & HCuPINT_OPR) {
+ u32 intstat = isp116x_read_reg32(isp116x, HCINTSTAT);
+ isp116x_write_reg32(isp116x, HCINTSTAT, intstat);
+ if (intstat & HCINT_UE) {
+ ERR("Unrecoverable error\n");
+ /* What should we do here? Reset? */
+ }
+ if (intstat & HCINT_RHSC) {
+ isp116x->rhstatus =
+ isp116x_read_reg32(isp116x, HCRHSTATUS);
+ isp116x->rhport[0] =
+ isp116x_read_reg32(isp116x, HCRHPORT1);
+ isp116x->rhport[1] =
+ isp116x_read_reg32(isp116x, HCRHPORT2);
+ }
+ if (intstat & HCINT_RD) {
+ DBG("---- remote wakeup\n");
+ schedule_work(&isp116x->rh_resume);
+ ret = IRQ_HANDLED;
+ }
+ irqstat &= ~HCuPINT_OPR;
+ ret = IRQ_HANDLED;
+ }
+
+ if (irqstat & (HCuPINT_ATL | HCuPINT_SOF)) {
+ start_atl_transfers(isp116x);
+ }
+
+ isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+ spin_unlock(&isp116x->lock);
+ return ret;
+}
+
+/*-----------------------------------------------------------------*/
+
+/* usb 1.1 says max 90% of a frame is available for periodic transfers.
+ * this driver doesn't promise that much since it's got to handle an
+ * IRQ per packet; irq handling latencies also use up that time.
+ */
+
+/* out of 1000 us */
+#define MAX_PERIODIC_LOAD 600
+static int balance(struct isp116x *isp116x, u16 period, u16 load)
+{
+ int i, branch = -ENOSPC;
+
+ /* search for the least loaded schedule branch of that period
+ which has enough bandwidth left unreserved. */
+ for (i = 0; i < period; i++) {
+ if (branch < 0 || isp116x->load[branch] > isp116x->load[i]) {
+ int j;
+
+ for (j = i; j < PERIODIC_SIZE; j += period) {
+ if ((isp116x->load[j] + load)
+ > MAX_PERIODIC_LOAD)
+ break;
+ }
+ if (j < PERIODIC_SIZE)
+ continue;
+ branch = i;
+ }
+ }
+ return branch;
+}
+
+/* NB! ALL the code above this point runs with isp116x->lock
+ held, irqs off
+*/
+
+/*-----------------------------------------------------------------*/
+
+static int isp116x_urb_enqueue(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep, struct urb *urb,
+ unsigned mem_flags)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ struct usb_device *udev = urb->dev;
+ unsigned int pipe = urb->pipe;
+ int is_out = !usb_pipein(pipe);
+ int type = usb_pipetype(pipe);
+ int epnum = usb_pipeendpoint(pipe);
+ struct isp116x_ep *ep = NULL;
+ unsigned long flags;
+ int i;
+ int ret = 0;
+
+ urb_dbg(urb, "Enqueue");
+
+ if (type == PIPE_ISOCHRONOUS) {
+ ERR("Isochronous transfers not supported\n");
+ urb_dbg(urb, "Refused to enqueue");
+ return -ENXIO;
+ }
+ /* avoid all allocations within spinlocks: request or endpoint */
+ if (!hep->hcpriv) {
+ ep = kcalloc(1, sizeof *ep, mem_flags);
+ if (!ep)
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+ if (!HC_IS_RUNNING(hcd->state)) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ if (hep->hcpriv)
+ ep = hep->hcpriv;
+ else {
+ INIT_LIST_HEAD(&ep->schedule);
+ ep->udev = usb_get_dev(udev);
+ ep->epnum = epnum;
+ ep->maxpacket = usb_maxpacket(udev, urb->pipe, is_out);
+ usb_settoggle(udev, epnum, is_out, 0);
+
+ if (type == PIPE_CONTROL) {
+ ep->nextpid = USB_PID_SETUP;
+ } else if (is_out) {
+ ep->nextpid = USB_PID_OUT;
+ } else {
+ ep->nextpid = USB_PID_IN;
+ }
+
+ if (urb->interval) {
+ /*
+ With INT URBs submitted, the driver works with SOF
+ interrupt enabled and ATL interrupt disabled. After
+ the PTDs are written to fifo ram, the chip starts
+ fifo processing and usb transfers after the next
+ SOF and continues until the transfers are finished
+ (succeeded or failed) or the frame ends. Therefore,
+ the transfers occur only in every second frame,
+ while fifo reading/writing and data processing
+ occur in every other second frame. */
+ if (urb->interval < 2)
+ urb->interval = 2;
+ if (urb->interval > 2 * PERIODIC_SIZE)
+ urb->interval = 2 * PERIODIC_SIZE;
+ ep->period = urb->interval >> 1;
+ ep->branch = PERIODIC_SIZE;
+ ep->load = usb_calc_bus_time(udev->speed,
+ !is_out,
+ (type == PIPE_ISOCHRONOUS),
+ usb_maxpacket(udev, pipe,
+ is_out)) /
+ 1000;
+ }
+ hep->hcpriv = ep;
+ ep->hep = hep;
+ }
+
+ /* maybe put endpoint into schedule */
+ switch (type) {
+ case PIPE_CONTROL:
+ case PIPE_BULK:
+ if (list_empty(&ep->schedule))
+ list_add_tail(&ep->schedule, &isp116x->async);
+ break;
+ case PIPE_INTERRUPT:
+ urb->interval = ep->period;
+ ep->length = min((int)ep->maxpacket,
+ urb->transfer_buffer_length);
+
+ /* urb submitted for already existing endpoint */
+ if (ep->branch < PERIODIC_SIZE)
+ break;
+
+ ret = ep->branch = balance(isp116x, ep->period, ep->load);
+ if (ret < 0)
+ goto fail;
+ ret = 0;
+
+ urb->start_frame = (isp116x->fmindex & (PERIODIC_SIZE - 1))
+ + ep->branch;
+
+ /* sort each schedule branch by period (slow before fast)
+ to share the faster parts of the tree without needing
+ dummy/placeholder nodes */
+ DBG("schedule qh%d/%p branch %d\n", ep->period, ep, ep->branch);
+ for (i = ep->branch; i < PERIODIC_SIZE; i += ep->period) {
+ struct isp116x_ep **prev = &isp116x->periodic[i];
+ struct isp116x_ep *here = *prev;
+
+ while (here && ep != here) {
+ if (ep->period > here->period)
+ break;
+ prev = &here->next;
+ here = *prev;
+ }
+ if (ep != here) {
+ ep->next = here;
+ *prev = ep;
+ }
+ isp116x->load[i] += ep->load;
+ }
+ hcd->self.bandwidth_allocated += ep->load / ep->period;
+
+ /* switch over to SOFint */
+ if (!isp116x->periodic_count++) {
+ isp116x->irqenb &= ~HCuPINT_ATL;
+ isp116x->irqenb |= HCuPINT_SOF;
+ isp116x_write_reg16(isp116x, HCuPINTENB,
+ isp116x->irqenb);
+ }
+ }
+
+ /* in case of unlink-during-submit */
+ spin_lock(&urb->lock);
+ if (urb->status != -EINPROGRESS) {
+ spin_unlock(&urb->lock);
+ finish_request(isp116x, ep, urb, NULL);
+ ret = 0;
+ goto fail;
+ }
+ urb->hcpriv = hep;
+ spin_unlock(&urb->lock);
+ start_atl_transfers(isp116x);
+
+ fail:
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return ret;
+}
+
+/*
+ Dequeue URBs.
+*/
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ struct usb_host_endpoint *hep;
+ struct isp116x_ep *ep, *ep_act;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+ hep = urb->hcpriv;
+ /* URB already unlinked (or never linked)? */
+ if (!hep) {
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return 0;
+ }
+ ep = hep->hcpriv;
+ WARN_ON(hep != ep->hep);
+
+ /* In front of queue? */
+ if (ep->hep->urb_list.next == &urb->urb_list)
+ /* active? */
+ for (ep_act = isp116x->atl_active; ep_act;
+ ep_act = ep_act->active)
+ if (ep_act == ep) {
+ VDBG("dequeue, urb %p active; wait for irq\n",
+ urb);
+ urb = NULL;
+ break;
+ }
+
+ if (urb)
+ finish_request(isp116x, ep, urb, NULL);
+
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return 0;
+}
+
+static void isp116x_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *hep)
+{
+ int i;
+ struct isp116x_ep *ep = hep->hcpriv;;
+
+ if (!ep)
+ return;
+
+ /* assume we'd just wait for the irq */
+ for (i = 0; i < 100 && !list_empty(&hep->urb_list); i++)
+ msleep(3);
+ if (!list_empty(&hep->urb_list))
+ WARN("ep %p not empty?\n", ep);
+
+ usb_put_dev(ep->udev);
+ kfree(ep);
+ hep->hcpriv = NULL;
+}
+
+static int isp116x_get_frame(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ u32 fmnum;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+ fmnum = isp116x_read_reg32(isp116x, HCFMNUM);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return (int)fmnum;
+}
+
+/*----------------------------------------------------------------*/
+
+/*
+ Adapted from ohci-hub.c. Currently we don't support autosuspend.
+*/
+static int isp116x_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ int ports, i, changed = 0;
+
+ if (!HC_IS_RUNNING(hcd->state))
+ return -ESHUTDOWN;
+
+ ports = isp116x->rhdesca & RH_A_NDP;
+
+ /* init status */
+ if (isp116x->rhstatus & (RH_HS_LPSC | RH_HS_OCIC))
+ buf[0] = changed = 1;
+ else
+ buf[0] = 0;
+
+ for (i = 0; i < ports; i++) {
+ u32 status = isp116x->rhport[i];
+
+ if (status & (RH_PS_CSC | RH_PS_PESC | RH_PS_PSSC
+ | RH_PS_OCIC | RH_PS_PRSC)) {
+ changed = 1;
+ buf[0] |= 1 << (i + 1);
+ continue;
+ }
+ }
+ return changed;
+}
+
+static void isp116x_hub_descriptor(struct isp116x *isp116x,
+ struct usb_hub_descriptor *desc)
+{
+ u32 reg = isp116x->rhdesca;
+
+ desc->bDescriptorType = 0x29;
+ desc->bDescLength = 9;
+ desc->bHubContrCurrent = 0;
+ desc->bNbrPorts = (u8) (reg & 0x3);
+ /* Power switching, device type, overcurrent. */
+ desc->wHubCharacteristics =
+ (__force __u16) cpu_to_le16((u16) ((reg >> 8) & 0x1f));
+ desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
+ /* two bitmaps: ports removable, and legacy PortPwrCtrlMask */
+ desc->bitmap[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
+ desc->bitmap[1] = ~0;
+}
+
+/* Perform reset of a given port.
+ It would be great to just start the reset and let the
+ USB core to clear the reset in due time. However,
+ root hub ports should be reset for at least 50 ms, while
+ our chip stays in reset for about 10 ms. I.e., we must
+ repeatedly reset it ourself here.
+*/
+static inline void root_port_reset(struct isp116x *isp116x, unsigned port)
+{
+ u32 tmp;
+ unsigned long flags, t;
+
+ /* Root hub reset should be 50 ms, but some devices
+ want it even longer. */
+ t = jiffies + msecs_to_jiffies(100);
+
+ while (time_before(jiffies, t)) {
+ spin_lock_irqsave(&isp116x->lock, flags);
+ /* spin until any current reset finishes */
+ for (;;) {
+ tmp = isp116x_read_reg32(isp116x, port ?
+ HCRHPORT2 : HCRHPORT1);
+ if (!(tmp & RH_PS_PRS))
+ break;
+ udelay(500);
+ }
+ /* Don't reset a disconnected port */
+ if (!(tmp & RH_PS_CCS)) {
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ break;
+ }
+ /* Reset lasts 10ms (claims datasheet) */
+ isp116x_write_reg32(isp116x, port ? HCRHPORT2 :
+ HCRHPORT1, (RH_PS_PRS));
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ msleep(10);
+ }
+}
+
+/* Adapted from ohci-hub.c */
+static int isp116x_hub_control(struct usb_hcd *hcd,
+ u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ int ret = 0;
+ unsigned long flags;
+ int ports = isp116x->rhdesca & RH_A_NDP;
+ u32 tmp = 0;
+
+ switch (typeReq) {
+ case ClearHubFeature:
+ DBG("ClearHubFeature: ");
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ DBG("C_HUB_OVER_CURRENT\n");
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_OCIC);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ case C_HUB_LOCAL_POWER:
+ DBG("C_HUB_LOCAL_POWER\n");
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetHubFeature:
+ DBG("SetHubFeature: ");
+ switch (wValue) {
+ case C_HUB_OVER_CURRENT:
+ case C_HUB_LOCAL_POWER:
+ DBG("C_HUB_OVER_CURRENT or C_HUB_LOCAL_POWER\n");
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case GetHubDescriptor:
+ DBG("GetHubDescriptor\n");
+ isp116x_hub_descriptor(isp116x,
+ (struct usb_hub_descriptor *)buf);
+ break;
+ case GetHubStatus:
+ DBG("GetHubStatus\n");
+ *(__le32 *) buf = 0;
+ break;
+ case GetPortStatus:
+ DBG("GetPortStatus\n");
+ if (!wIndex || wIndex > ports)
+ goto error;
+ tmp = isp116x->rhport[--wIndex];
+ *(__le32 *) buf = cpu_to_le32(tmp);
+ DBG("GetPortStatus: port[%d] %08x\n", wIndex + 1, tmp);
+ break;
+ case ClearPortFeature:
+ DBG("ClearPortFeature: ");
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ DBG("USB_PORT_FEAT_ENABLE\n");
+ tmp = RH_PS_CCS;
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ DBG("USB_PORT_FEAT_C_ENABLE\n");
+ tmp = RH_PS_PESC;
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ DBG("USB_PORT_FEAT_SUSPEND\n");
+ tmp = RH_PS_POCI;
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ DBG("USB_PORT_FEAT_C_SUSPEND\n");
+ tmp = RH_PS_PSSC;
+ break;
+ case USB_PORT_FEAT_POWER:
+ DBG("USB_PORT_FEAT_POWER\n");
+ tmp = RH_PS_LSDA;
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ DBG("USB_PORT_FEAT_C_CONNECTION\n");
+ tmp = RH_PS_CSC;
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ DBG("USB_PORT_FEAT_C_OVER_CURRENT\n");
+ tmp = RH_PS_OCIC;
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ DBG("USB_PORT_FEAT_C_RESET\n");
+ tmp = RH_PS_PRSC;
+ break;
+ default:
+ goto error;
+ }
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg32(isp116x, wIndex
+ ? HCRHPORT2 : HCRHPORT1, tmp);
+ isp116x->rhport[wIndex] =
+ isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ break;
+ case SetPortFeature:
+ DBG("SetPortFeature: ");
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ switch (wValue) {
+ case USB_PORT_FEAT_SUSPEND:
+ DBG("USB_PORT_FEAT_SUSPEND\n");
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg32(isp116x, wIndex
+ ? HCRHPORT2 : HCRHPORT1, RH_PS_PSS);
+ break;
+ case USB_PORT_FEAT_POWER:
+ DBG("USB_PORT_FEAT_POWER\n");
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg32(isp116x, wIndex
+ ? HCRHPORT2 : HCRHPORT1, RH_PS_PPS);
+ break;
+ case USB_PORT_FEAT_RESET:
+ DBG("USB_PORT_FEAT_RESET\n");
+ root_port_reset(isp116x, wIndex);
+ spin_lock_irqsave(&isp116x->lock, flags);
+ break;
+ default:
+ goto error;
+ }
+ isp116x->rhport[wIndex] =
+ isp116x_read_reg32(isp116x, wIndex ? HCRHPORT2 : HCRHPORT1);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ break;
+
+ default:
+ error:
+ /* "protocol stall" on error */
+ DBG("PROTOCOL STALL\n");
+ ret = -EPIPE;
+ }
+ return ret;
+}
+
+#ifdef CONFIG_PM
+
+static int isp116x_hub_suspend(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ unsigned long flags;
+ u32 val;
+ int ret = 0;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+
+ val = isp116x_read_reg32(isp116x, HCCONTROL);
+ switch (val & HCCONTROL_HCFS) {
+ case HCCONTROL_USB_OPER:
+ hcd->state = HC_STATE_QUIESCING;
+ val &= (~HCCONTROL_HCFS & ~HCCONTROL_RWE);
+ val |= HCCONTROL_USB_SUSPEND;
+ if (hcd->remote_wakeup)
+ val |= HCCONTROL_RWE;
+ /* Wait for usb transfers to finish */
+ mdelay(2);
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
+ hcd->state = HC_STATE_SUSPENDED;
+ /* Wait for devices to suspend */
+ mdelay(5);
+ case HCCONTROL_USB_SUSPEND:
+ break;
+ case HCCONTROL_USB_RESUME:
+ isp116x_write_reg32(isp116x, HCCONTROL,
+ (val & ~HCCONTROL_HCFS) |
+ HCCONTROL_USB_RESET);
+ case HCCONTROL_USB_RESET:
+ ret = -EBUSY;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return ret;
+}
+
+static int isp116x_hub_resume(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ u32 val;
+ int ret = -EINPROGRESS;
+
+ msleep(5);
+ spin_lock_irq(&isp116x->lock);
+
+ val = isp116x_read_reg32(isp116x, HCCONTROL);
+ switch (val & HCCONTROL_HCFS) {
+ case HCCONTROL_USB_SUSPEND:
+ val &= ~HCCONTROL_HCFS;
+ val |= HCCONTROL_USB_RESUME;
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
+ case HCCONTROL_USB_RESUME:
+ break;
+ case HCCONTROL_USB_OPER:
+ /* Without setting power_state here the
+ SUSPENDED state won't be removed from
+ sysfs/usbN/power.state as a response to remote
+ wakeup. Maybe in the future. */
+ hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+ ret = 0;
+ break;
+ default:
+ ret = -EBUSY;
+ }
+
+ if (ret != -EINPROGRESS) {
+ spin_unlock_irq(&isp116x->lock);
+ return ret;
+ }
+
+ val = isp116x->rhdesca & RH_A_NDP;
+ while (val--) {
+ u32 stat =
+ isp116x_read_reg32(isp116x, val ? HCRHPORT2 : HCRHPORT1);
+ /* force global, not selective, resume */
+ if (!(stat & RH_PS_PSS))
+ continue;
+ DBG("%s: Resuming port %d\n", __func__, val);
+ isp116x_write_reg32(isp116x, RH_PS_POCI, val
+ ? HCRHPORT2 : HCRHPORT1);
+ }
+ spin_unlock_irq(&isp116x->lock);
+
+ hcd->state = HC_STATE_RESUMING;
+ mdelay(20);
+
+ /* Go operational */
+ spin_lock_irq(&isp116x->lock);
+ val = isp116x_read_reg32(isp116x, HCCONTROL);
+ isp116x_write_reg32(isp116x, HCCONTROL,
+ (val & ~HCCONTROL_HCFS) | HCCONTROL_USB_OPER);
+ spin_unlock_irq(&isp116x->lock);
+ /* see analogous comment above */
+ hcd->self.root_hub->dev.power.power_state = PMSG_ON;
+ hcd->state = HC_STATE_RUNNING;
+
+ return 0;
+}
+
+static void isp116x_rh_resume(void *_hcd)
+{
+ struct usb_hcd *hcd = _hcd;
+
+ usb_resume_device(hcd->self.root_hub);
+}
+
+#else
+
+#define isp116x_hub_suspend NULL
+#define isp116x_hub_resume NULL
+
+static void isp116x_rh_resume(void *_hcd)
+{
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+#ifdef STUB_DEBUG_FILE
+
+static inline void create_debug_file(struct isp116x *isp116x)
+{
+}
+
+static inline void remove_debug_file(struct isp116x *isp116x)
+{
+}
+
+#else
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_irq(struct seq_file *s, char *label, u16 mask)
+{
+ seq_printf(s, "%s %04x%s%s%s%s%s%s\n", label, mask,
+ mask & HCuPINT_CLKRDY ? " clkrdy" : "",
+ mask & HCuPINT_SUSP ? " susp" : "",
+ mask & HCuPINT_OPR ? " opr" : "",
+ mask & HCuPINT_AIIEOT ? " eot" : "",
+ mask & HCuPINT_ATL ? " atl" : "",
+ mask & HCuPINT_SOF ? " sof" : "");
+}
+
+static void dump_int(struct seq_file *s, char *label, u32 mask)
+{
+ seq_printf(s, "%s %08x%s%s%s%s%s%s%s\n", label, mask,
+ mask & HCINT_MIE ? " MIE" : "",
+ mask & HCINT_RHSC ? " rhsc" : "",
+ mask & HCINT_FNO ? " fno" : "",
+ mask & HCINT_UE ? " ue" : "",
+ mask & HCINT_RD ? " rd" : "",
+ mask & HCINT_SF ? " sof" : "", mask & HCINT_SO ? " so" : "");
+}
+
+static int proc_isp116x_show(struct seq_file *s, void *unused)
+{
+ struct isp116x *isp116x = s->private;
+ struct isp116x_ep *ep;
+ struct urb *urb;
+ unsigned i;
+ char *str;
+
+ seq_printf(s, "%s\n%s version %s\n",
+ isp116x_to_hcd(isp116x)->product_desc, hcd_name,
+ DRIVER_VERSION);
+
+ if (HC_IS_SUSPENDED(isp116x_to_hcd(isp116x)->state)) {
+ seq_printf(s, "HCD is suspended\n");
+ return 0;
+ }
+ if (!HC_IS_RUNNING(isp116x_to_hcd(isp116x)->state)) {
+ seq_printf(s, "HCD not running\n");
+ return 0;
+ }
+
+ spin_lock_irq(&isp116x->lock);
+
+ dump_irq(s, "hc_irq_enable", isp116x_read_reg16(isp116x, HCuPINTENB));
+ dump_irq(s, "hc_irq_status", isp116x_read_reg16(isp116x, HCuPINT));
+ dump_int(s, "hc_int_enable", isp116x_read_reg32(isp116x, HCINTENB));
+ dump_int(s, "hc_int_status", isp116x_read_reg32(isp116x, HCINTSTAT));
+
+ list_for_each_entry(ep, &isp116x->async, schedule) {
+
+ switch (ep->nextpid) {
+ case USB_PID_IN:
+ str = "in";
+ break;
+ case USB_PID_OUT:
+ str = "out";
+ break;
+ case USB_PID_SETUP:
+ str = "setup";
+ break;
+ case USB_PID_ACK:
+ str = "status";
+ break;
+ default:
+ str = "?";
+ break;
+ };
+ seq_printf(s, "%p, ep%d%s, maxpacket %d:\n", ep,
+ ep->epnum, str, ep->maxpacket);
+ list_for_each_entry(urb, &ep->hep->urb_list, urb_list) {
+ seq_printf(s, " urb%p, %d/%d\n", urb,
+ urb->actual_length,
+ urb->transfer_buffer_length);
+ }
+ }
+ if (!list_empty(&isp116x->async))
+ seq_printf(s, "\n");
+
+ seq_printf(s, "periodic size= %d\n", PERIODIC_SIZE);
+
+ for (i = 0; i < PERIODIC_SIZE; i++) {
+ ep = isp116x->periodic[i];
+ if (!ep)
+ continue;
+ seq_printf(s, "%2d [%3d]:\n", i, isp116x->load[i]);
+
+ /* DUMB: prints shared entries multiple times */
+ do {
+ seq_printf(s, " %d/%p (%sdev%d ep%d%s max %d)\n",
+ ep->period, ep,
+ (ep->udev->speed ==
+ USB_SPEED_FULL) ? "" : "ls ",
+ ep->udev->devnum, ep->epnum,
+ (ep->epnum ==
+ 0) ? "" : ((ep->nextpid ==
+ USB_PID_IN) ? "in" : "out"),
+ ep->maxpacket);
+ ep = ep->next;
+ } while (ep);
+ }
+ spin_unlock_irq(&isp116x->lock);
+ seq_printf(s, "\n");
+
+ return 0;
+}
+
+static int proc_isp116x_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, proc_isp116x_show, PDE(inode)->data);
+}
+
+static struct file_operations proc_ops = {
+ .open = proc_isp116x_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/* expect just one isp116x per system */
+static const char proc_filename[] = "driver/isp116x";
+
+static void create_debug_file(struct isp116x *isp116x)
+{
+ struct proc_dir_entry *pde;
+
+ pde = create_proc_entry(proc_filename, 0, NULL);
+ if (pde == NULL)
+ return;
+
+ pde->proc_fops = &proc_ops;
+ pde->data = isp116x;
+ isp116x->pde = pde;
+}
+
+static void remove_debug_file(struct isp116x *isp116x)
+{
+ if (isp116x->pde)
+ remove_proc_entry(proc_filename, NULL);
+}
+
+#endif
+
+/*-----------------------------------------------------------------*/
+
+/*
+ Software reset - can be called from any contect.
+*/
+static int isp116x_sw_reset(struct isp116x *isp116x)
+{
+ int retries = 15;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg16(isp116x, HCSWRES, HCSWRES_MAGIC);
+ isp116x_write_reg32(isp116x, HCCMDSTAT, HCCMDSTAT_HCR);
+ while (--retries) {
+ /* It usually resets within 1 ms */
+ mdelay(1);
+ if (!(isp116x_read_reg32(isp116x, HCCMDSTAT) & HCCMDSTAT_HCR))
+ break;
+ }
+ if (!retries) {
+ ERR("Software reset timeout\n");
+ ret = -ETIME;
+ }
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return ret;
+}
+
+/*
+ Reset. Tries to perform platform-specific hardware
+ reset first; falls back to software reset.
+*/
+static int isp116x_reset(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ unsigned long t;
+ u16 clkrdy = 0;
+ int ret = 0, timeout = 15 /* ms */ ;
+
+ if (isp116x->board && isp116x->board->reset) {
+ /* Hardware reset */
+ isp116x->board->reset(hcd->self.controller, 1);
+ msleep(10);
+ if (isp116x->board->clock)
+ isp116x->board->clock(hcd->self.controller, 1);
+ msleep(1);
+ isp116x->board->reset(hcd->self.controller, 0);
+ } else
+ ret = isp116x_sw_reset(isp116x);
+
+ if (ret)
+ return ret;
+
+ t = jiffies + msecs_to_jiffies(timeout);
+ while (time_before_eq(jiffies, t)) {
+ msleep(4);
+ spin_lock_irq(&isp116x->lock);
+ clkrdy = isp116x_read_reg16(isp116x, HCuPINT) & HCuPINT_CLKRDY;
+ spin_unlock_irq(&isp116x->lock);
+ if (clkrdy)
+ break;
+ }
+ if (!clkrdy) {
+ ERR("Clock not ready after 20ms\n");
+ /* After sw_reset the clock won't report to be ready, if
+ H_WAKEUP pin is high. */
+ if (!isp116x->board || !isp116x->board->reset)
+ ERR("The driver does not support hardware wakeup.\n");
+ ERR("Please make sure that the H_WAKEUP pin "
+ "is pulled low!\n");
+ ret = -ENODEV;
+ }
+ return ret;
+}
+
+static void isp116x_stop(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ /* Switch off ports' power, some devices don't come up
+ after next 'insmod' without this */
+ val = isp116x_read_reg32(isp116x, HCRHDESCA);
+ val &= ~(RH_A_NPS | RH_A_PSM);
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x_write_reg32(isp116x, HCRHSTATUS, RH_HS_LPS);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+
+ /* Put the chip into reset state */
+ if (isp116x->board && isp116x->board->reset)
+ isp116x->board->reset(hcd->self.controller, 0);
+ else
+ isp116x_sw_reset(isp116x);
+
+ /* Stop the clock */
+ if (isp116x->board && isp116x->board->clock)
+ isp116x->board->clock(hcd->self.controller, 0);
+}
+
+/*
+ Configure the chip. The chip must be successfully reset by now.
+*/
+static int isp116x_start(struct usb_hcd *hcd)
+{
+ struct isp116x *isp116x = hcd_to_isp116x(hcd);
+ struct isp116x_platform_data *board = isp116x->board;
+ u32 val;
+ unsigned long flags;
+
+ spin_lock_irqsave(&isp116x->lock, flags);
+
+ /* clear interrupt status and disable all interrupt sources */
+ isp116x_write_reg16(isp116x, HCuPINT, 0xff);
+ isp116x_write_reg16(isp116x, HCuPINTENB, 0);
+
+ val = isp116x_read_reg16(isp116x, HCCHIPID);
+ if ((val & HCCHIPID_MASK) != HCCHIPID_MAGIC) {
+ ERR("Invalid chip ID %04x\n", val);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return -ENODEV;
+ }
+
+ isp116x_write_reg16(isp116x, HCITLBUFLEN, ISP116x_ITL_BUFSIZE);
+ isp116x_write_reg16(isp116x, HCATLBUFLEN, ISP116x_ATL_BUFSIZE);
+
+ /* ----- HW conf */
+ val = HCHWCFG_INT_ENABLE | HCHWCFG_DBWIDTH(1);
+ if (board->sel15Kres)
+ val |= HCHWCFG_15KRSEL;
+ /* Remote wakeup won't work without working clock */
+ if (board->clknotstop || board->remote_wakeup_enable)
+ val |= HCHWCFG_CLKNOTSTOP;
+ if (board->oc_enable)
+ val |= HCHWCFG_ANALOG_OC;
+ if (board->int_act_high)
+ val |= HCHWCFG_INT_POL;
+ if (board->int_edge_triggered)
+ val |= HCHWCFG_INT_TRIGGER;
+ isp116x_write_reg16(isp116x, HCHWCFG, val);
+
+ /* ----- Root hub conf */
+ val = 0;
+ /* AN10003_1.pdf recommends NPS to be always 1 */
+ if (board->no_power_switching)
+ val |= RH_A_NPS;
+ if (board->power_switching_mode)
+ val |= RH_A_PSM;
+ if (board->potpg)
+ val |= (board->potpg << 24) & RH_A_POTPGT;
+ else
+ val |= (25 << 24) & RH_A_POTPGT;
+ isp116x_write_reg32(isp116x, HCRHDESCA, val);
+ isp116x->rhdesca = isp116x_read_reg32(isp116x, HCRHDESCA);
+
+ val = RH_B_PPCM;
+ isp116x_write_reg32(isp116x, HCRHDESCB, val);
+ isp116x->rhdescb = isp116x_read_reg32(isp116x, HCRHDESCB);
+
+ val = 0;
+ if (board->remote_wakeup_enable) {
+ hcd->can_wakeup = 1;
+ val |= RH_HS_DRWE;
+ }
+ isp116x_write_reg32(isp116x, HCRHSTATUS, val);
+ isp116x->rhstatus = isp116x_read_reg32(isp116x, HCRHSTATUS);
+
+ isp116x_write_reg32(isp116x, HCFMINTVL, 0x27782edf);
+
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Set up interrupts */
+ isp116x->intenb = HCINT_MIE | HCINT_RHSC | HCINT_UE;
+ if (board->remote_wakeup_enable)
+ isp116x->intenb |= HCINT_RD;
+ isp116x->irqenb = HCuPINT_ATL | HCuPINT_OPR; /* | HCuPINT_SUSP; */
+ isp116x_write_reg32(isp116x, HCINTENB, isp116x->intenb);
+ isp116x_write_reg16(isp116x, HCuPINTENB, isp116x->irqenb);
+
+ /* Go operational */
+ val = HCCONTROL_USB_OPER;
+ /* Remote wakeup connected - NOT SUPPORTED */
+ /* if (board->remote_wakeup_connected)
+ val |= HCCONTROL_RWC; */
+ if (board->remote_wakeup_enable)
+ val |= HCCONTROL_RWE;
+ isp116x_write_reg32(isp116x, HCCONTROL, val);
+
+ /* Disable ports to avoid race in device enumeration */
+ isp116x_write_reg32(isp116x, HCRHPORT1, RH_PS_CCS);
+ isp116x_write_reg32(isp116x, HCRHPORT2, RH_PS_CCS);
+
+ isp116x_show_regs(isp116x);
+ spin_unlock_irqrestore(&isp116x->lock, flags);
+ return 0;
+}
+
+/*-----------------------------------------------------------------*/
+
+static struct hc_driver isp116x_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "ISP116x Host Controller",
+ .hcd_priv_size = sizeof(struct isp116x),
+
+ .irq = isp116x_irq,
+ .flags = HCD_USB11,
+
+ .reset = isp116x_reset,
+ .start = isp116x_start,
+ .stop = isp116x_stop,
+
+ .urb_enqueue = isp116x_urb_enqueue,
+ .urb_dequeue = isp116x_urb_dequeue,
+ .endpoint_disable = isp116x_endpoint_disable,
+
+ .get_frame_number = isp116x_get_frame,
+
+ .hub_status_data = isp116x_hub_status_data,
+ .hub_control = isp116x_hub_control,
+ .hub_suspend = isp116x_hub_suspend,
+ .hub_resume = isp116x_hub_resume,
+};
+
+/*----------------------------------------------------------------*/
+
+static int __init_or_module isp116x_remove(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct isp116x *isp116x;
+ struct platform_device *pdev;
+ struct resource *res;
+
+ if(!hcd)
+ return 0;
+ isp116x = hcd_to_isp116x(hcd);
+ pdev = container_of(dev, struct platform_device, dev);
+ remove_debug_file(isp116x);
+ usb_remove_hcd(hcd);
+
+ iounmap(isp116x->data_reg);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ release_mem_region(res->start, 2);
+ iounmap(isp116x->addr_reg);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ release_mem_region(res->start, 2);
+
+ usb_put_hcd(hcd);
+ return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+
+static int __init isp116x_probe(struct device *dev)
+{
+ struct usb_hcd *hcd;
+ struct isp116x *isp116x;
+ struct platform_device *pdev;
+ struct resource *addr, *data;
+ void __iomem *addr_reg;
+ void __iomem *data_reg;
+ int irq;
+ int ret = 0;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ if (pdev->num_resources < 3) {
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ data = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ addr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ irq = platform_get_irq(pdev, 0);
+ if (!addr || !data || irq < 0) {
+ ret = -ENODEV;
+ goto err1;
+ }
+
+ if (dev->dma_mask) {
+ DBG("DMA not supported\n");
+ ret = -EINVAL;
+ goto err1;
+ }
+
+ if (!request_mem_region(addr->start, 2, hcd_name)) {
+ ret = -EBUSY;
+ goto err1;
+ }
+ addr_reg = ioremap(addr->start, resource_len(addr));
+ if (addr_reg == NULL) {
+ ret = -ENOMEM;
+ goto err2;
+ }
+ if (!request_mem_region(data->start, 2, hcd_name)) {
+ ret = -EBUSY;
+ goto err3;
+ }
+ data_reg = ioremap(data->start, resource_len(data));
+ if (data_reg == NULL) {
+ ret = -ENOMEM;
+ goto err4;
+ }
+
+ /* allocate and initialize hcd */
+ hcd = usb_create_hcd(&isp116x_hc_driver, dev, dev->bus_id);
+ if (!hcd) {
+ ret = -ENOMEM;
+ goto err5;
+ }
+ /* this rsrc_start is bogus */
+ hcd->rsrc_start = addr->start;
+ isp116x = hcd_to_isp116x(hcd);
+ isp116x->data_reg = data_reg;
+ isp116x->addr_reg = addr_reg;
+ spin_lock_init(&isp116x->lock);
+ INIT_LIST_HEAD(&isp116x->async);
+ INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
+ isp116x->board = dev->platform_data;
+
+ if (!isp116x->board) {
+ ERR("Platform data structure not initialized\n");
+ ret = -ENODEV;
+ goto err6;
+ }
+ if (isp116x_check_platform_delay(isp116x)) {
+ ERR("USE_PLATFORM_DELAY defined, but delay function not "
+ "implemented.\n");
+ ERR("See comments in drivers/usb/host/isp116x-hcd.c\n");
+ ret = -ENODEV;
+ goto err6;
+ }
+
+ ret = usb_add_hcd(hcd, irq, SA_INTERRUPT);
+ if (ret != 0)
+ goto err6;
+
+ create_debug_file(isp116x);
+ return 0;
+
+ err6:
+ usb_put_hcd(hcd);
+ err5:
+ iounmap(data_reg);
+ err4:
+ release_mem_region(data->start, 2);
+ err3:
+ iounmap(addr_reg);
+ err2:
+ release_mem_region(addr->start, 2);
+ err1:
+ ERR("init error, %d\n", ret);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+/*
+ Suspend of platform device
+*/
+static int isp116x_suspend(struct device *dev, pm_message_t state, u32 phase)
+{
+ int ret = 0;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ VDBG("%s: state %x, phase %x\n", __func__, state, phase);
+
+ if (phase != SUSPEND_DISABLE && phase != SUSPEND_POWER_DOWN)
+ return 0;
+
+ ret = usb_suspend_device(hcd->self.root_hub, state);
+ if (!ret) {
+ dev->power.power_state = state;
+ INFO("%s suspended\n", hcd_name);
+ } else
+ ERR("%s suspend failed\n", hcd_name);
+
+ return ret;
+}
+
+/*
+ Resume platform device
+*/
+static int isp116x_resume(struct device *dev, u32 phase)
+{
+ int ret = 0;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ VDBG("%s: state %x, phase %x\n", __func__, dev->power.power_state,
+ phase);
+ if (phase != RESUME_POWER_ON)
+ return 0;
+
+ ret = usb_resume_device(hcd->self.root_hub);
+ if (!ret) {
+ dev->power.power_state = PMSG_ON;
+ VDBG("%s resumed\n", (char *)hcd_name);
+ }
+ return ret;
+}
+
+#else
+
+#define isp116x_suspend NULL
+#define isp116x_resume NULL
+
+#endif
+
+static struct device_driver isp116x_driver = {
+ .name = (char *)hcd_name,
+ .bus = &platform_bus_type,
+ .probe = isp116x_probe,
+ .remove = isp116x_remove,
+ .suspend = isp116x_suspend,
+ .resume = isp116x_resume,
+};
+
+/*-----------------------------------------------------------------*/
+
+static int __init isp116x_init(void)
+{
+ if (usb_disabled())
+ return -ENODEV;
+
+ INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
+ return driver_register(&isp116x_driver);
+}
+
+module_init(isp116x_init);
+
+static void __exit isp116x_cleanup(void)
+{
+ driver_unregister(&isp116x_driver);
+}
+
+module_exit(isp116x_cleanup);
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
new file mode 100644
index 000000000000..58873470dcf5
--- /dev/null
+++ b/drivers/usb/host/isp116x.h
@@ -0,0 +1,583 @@
+/*
+ * ISP116x register declarations and HCD data structures
+ *
+ * Copyright (C) 2005 Olav Kongas <ok@artecdesign.ee>
+ * Portions:
+ * Copyright (C) 2004 Lothar Wassmann
+ * Copyright (C) 2004 Psion Teklogix
+ * Copyright (C) 2004 David Brownell
+ */
+
+/* us of 1ms frame */
+#define MAX_LOAD_LIMIT 850
+
+/* Full speed: max # of bytes to transfer for a single urb
+ at a time must be < 1024 && must be multiple of 64.
+ 832 allows transfering 4kiB within 5 frames. */
+#define MAX_TRANSFER_SIZE_FULLSPEED 832
+
+/* Low speed: there is no reason to schedule in very big
+ chunks; often the requested long transfers are for
+ string descriptors containing short strings. */
+#define MAX_TRANSFER_SIZE_LOWSPEED 64
+
+/* Bytetime (us), a rough indication of how much time it
+ would take to transfer a byte of useful data over USB */
+#define BYTE_TIME_FULLSPEED 1
+#define BYTE_TIME_LOWSPEED 20
+
+/* Buffer sizes */
+#define ISP116x_BUF_SIZE 4096
+#define ISP116x_ITL_BUFSIZE 0
+#define ISP116x_ATL_BUFSIZE ((ISP116x_BUF_SIZE) - 2*(ISP116x_ITL_BUFSIZE))
+
+#define ISP116x_WRITE_OFFSET 0x80
+
+/*------------ ISP116x registers/bits ------------*/
+#define HCREVISION 0x00
+#define HCCONTROL 0x01
+#define HCCONTROL_HCFS (3 << 6) /* host controller
+ functional state */
+#define HCCONTROL_USB_RESET (0 << 6)
+#define HCCONTROL_USB_RESUME (1 << 6)
+#define HCCONTROL_USB_OPER (2 << 6)
+#define HCCONTROL_USB_SUSPEND (3 << 6)
+#define HCCONTROL_RWC (1 << 9) /* remote wakeup connected */
+#define HCCONTROL_RWE (1 << 10) /* remote wakeup enable */
+#define HCCMDSTAT 0x02
+#define HCCMDSTAT_HCR (1 << 0) /* host controller reset */
+#define HCCMDSTAT_SOC (3 << 16) /* scheduling overrun count */
+#define HCINTSTAT 0x03
+#define HCINT_SO (1 << 0) /* scheduling overrun */
+#define HCINT_WDH (1 << 1) /* writeback of done_head */
+#define HCINT_SF (1 << 2) /* start frame */
+#define HCINT_RD (1 << 3) /* resume detect */
+#define HCINT_UE (1 << 4) /* unrecoverable error */
+#define HCINT_FNO (1 << 5) /* frame number overflow */
+#define HCINT_RHSC (1 << 6) /* root hub status change */
+#define HCINT_OC (1 << 30) /* ownership change */
+#define HCINT_MIE (1 << 31) /* master interrupt enable */
+#define HCINTENB 0x04
+#define HCINTDIS 0x05
+#define HCFMINTVL 0x0d
+#define HCFMREM 0x0e
+#define HCFMNUM 0x0f
+#define HCLSTHRESH 0x11
+#define HCRHDESCA 0x12
+#define RH_A_NDP (0x3 << 0) /* # downstream ports */
+#define RH_A_PSM (1 << 8) /* power switching mode */
+#define RH_A_NPS (1 << 9) /* no power switching */
+#define RH_A_DT (1 << 10) /* device type (mbz) */
+#define RH_A_OCPM (1 << 11) /* overcurrent protection
+ mode */
+#define RH_A_NOCP (1 << 12) /* no overcurrent protection */
+#define RH_A_POTPGT (0xff << 24) /* power on -> power good
+ time */
+#define HCRHDESCB 0x13
+#define RH_B_DR (0xffff << 0) /* device removable flags */
+#define RH_B_PPCM (0xffff << 16) /* port power control mask */
+#define HCRHSTATUS 0x14
+#define RH_HS_LPS (1 << 0) /* local power status */
+#define RH_HS_OCI (1 << 1) /* over current indicator */
+#define RH_HS_DRWE (1 << 15) /* device remote wakeup
+ enable */
+#define RH_HS_LPSC (1 << 16) /* local power status change */
+#define RH_HS_OCIC (1 << 17) /* over current indicator
+ change */
+#define RH_HS_CRWE (1 << 31) /* clear remote wakeup
+ enable */
+#define HCRHPORT1 0x15
+#define RH_PS_CCS (1 << 0) /* current connect status */
+#define RH_PS_PES (1 << 1) /* port enable status */
+#define RH_PS_PSS (1 << 2) /* port suspend status */
+#define RH_PS_POCI (1 << 3) /* port over current
+ indicator */
+#define RH_PS_PRS (1 << 4) /* port reset status */
+#define RH_PS_PPS (1 << 8) /* port power status */
+#define RH_PS_LSDA (1 << 9) /* low speed device attached */
+#define RH_PS_CSC (1 << 16) /* connect status change */
+#define RH_PS_PESC (1 << 17) /* port enable status change */
+#define RH_PS_PSSC (1 << 18) /* port suspend status
+ change */
+#define RH_PS_OCIC (1 << 19) /* over current indicator
+ change */
+#define RH_PS_PRSC (1 << 20) /* port reset status change */
+#define HCRHPORT_CLRMASK (0x1f << 16)
+#define HCRHPORT2 0x16
+#define HCHWCFG 0x20
+#define HCHWCFG_15KRSEL (1 << 12)
+#define HCHWCFG_CLKNOTSTOP (1 << 11)
+#define HCHWCFG_ANALOG_OC (1 << 10)
+#define HCHWCFG_DACK_MODE (1 << 8)
+#define HCHWCFG_EOT_POL (1 << 7)
+#define HCHWCFG_DACK_POL (1 << 6)
+#define HCHWCFG_DREQ_POL (1 << 5)
+#define HCHWCFG_DBWIDTH_MASK (0x03 << 3)
+#define HCHWCFG_DBWIDTH(n) (((n) << 3) & HCHWCFG_DBWIDTH_MASK)
+#define HCHWCFG_INT_POL (1 << 2)
+#define HCHWCFG_INT_TRIGGER (1 << 1)
+#define HCHWCFG_INT_ENABLE (1 << 0)
+#define HCDMACFG 0x21
+#define HCDMACFG_BURST_LEN_MASK (0x03 << 5)
+#define HCDMACFG_BURST_LEN(n) (((n) << 5) & HCDMACFG_BURST_LEN_MASK)
+#define HCDMACFG_BURST_LEN_1 HCDMACFG_BURST_LEN(0)
+#define HCDMACFG_BURST_LEN_4 HCDMACFG_BURST_LEN(1)
+#define HCDMACFG_BURST_LEN_8 HCDMACFG_BURST_LEN(2)
+#define HCDMACFG_DMA_ENABLE (1 << 4)
+#define HCDMACFG_BUF_TYPE_MASK (0x07 << 1)
+#define HCDMACFG_CTR_SEL (1 << 2)
+#define HCDMACFG_ITLATL_SEL (1 << 1)
+#define HCDMACFG_DMA_RW_SELECT (1 << 0)
+#define HCXFERCTR 0x22
+#define HCuPINT 0x24
+#define HCuPINT_SOF (1 << 0)
+#define HCuPINT_ATL (1 << 1)
+#define HCuPINT_AIIEOT (1 << 2)
+#define HCuPINT_OPR (1 << 4)
+#define HCuPINT_SUSP (1 << 5)
+#define HCuPINT_CLKRDY (1 << 6)
+#define HCuPINTENB 0x25
+#define HCCHIPID 0x27
+#define HCCHIPID_MASK 0xff00
+#define HCCHIPID_MAGIC 0x6100
+#define HCSCRATCH 0x28
+#define HCSWRES 0x29
+#define HCSWRES_MAGIC 0x00f6
+#define HCITLBUFLEN 0x2a
+#define HCATLBUFLEN 0x2b
+#define HCBUFSTAT 0x2c
+#define HCBUFSTAT_ITL0_FULL (1 << 0)
+#define HCBUFSTAT_ITL1_FULL (1 << 1)
+#define HCBUFSTAT_ATL_FULL (1 << 2)
+#define HCBUFSTAT_ITL0_DONE (1 << 3)
+#define HCBUFSTAT_ITL1_DONE (1 << 4)
+#define HCBUFSTAT_ATL_DONE (1 << 5)
+#define HCRDITL0LEN 0x2d
+#define HCRDITL1LEN 0x2e
+#define HCITLPORT 0x40
+#define HCATLPORT 0x41
+
+/* Philips transfer descriptor */
+struct ptd {
+ u16 count;
+#define PTD_COUNT_MSK (0x3ff << 0)
+#define PTD_TOGGLE_MSK (1 << 10)
+#define PTD_ACTIVE_MSK (1 << 11)
+#define PTD_CC_MSK (0xf << 12)
+ u16 mps;
+#define PTD_MPS_MSK (0x3ff << 0)
+#define PTD_SPD_MSK (1 << 10)
+#define PTD_LAST_MSK (1 << 11)
+#define PTD_EP_MSK (0xf << 12)
+ u16 len;
+#define PTD_LEN_MSK (0x3ff << 0)
+#define PTD_DIR_MSK (3 << 10)
+#define PTD_DIR_SETUP (0)
+#define PTD_DIR_OUT (1)
+#define PTD_DIR_IN (2)
+#define PTD_B5_5_MSK (1 << 13)
+ u16 faddr;
+#define PTD_FA_MSK (0x7f << 0)
+#define PTD_FMT_MSK (1 << 7)
+} __attribute__ ((packed, aligned(2)));
+
+/* PTD accessor macros. */
+#define PTD_GET_COUNT(p) (((p)->count & PTD_COUNT_MSK) >> 0)
+#define PTD_COUNT(v) (((v) << 0) & PTD_COUNT_MSK)
+#define PTD_GET_TOGGLE(p) (((p)->count & PTD_TOGGLE_MSK) >> 10)
+#define PTD_TOGGLE(v) (((v) << 10) & PTD_TOGGLE_MSK)
+#define PTD_GET_ACTIVE(p) (((p)->count & PTD_ACTIVE_MSK) >> 11)
+#define PTD_ACTIVE(v) (((v) << 11) & PTD_ACTIVE_MSK)
+#define PTD_GET_CC(p) (((p)->count & PTD_CC_MSK) >> 12)
+#define PTD_CC(v) (((v) << 12) & PTD_CC_MSK)
+#define PTD_GET_MPS(p) (((p)->mps & PTD_MPS_MSK) >> 0)
+#define PTD_MPS(v) (((v) << 0) & PTD_MPS_MSK)
+#define PTD_GET_SPD(p) (((p)->mps & PTD_SPD_MSK) >> 10)
+#define PTD_SPD(v) (((v) << 10) & PTD_SPD_MSK)
+#define PTD_GET_LAST(p) (((p)->mps & PTD_LAST_MSK) >> 11)
+#define PTD_LAST(v) (((v) << 11) & PTD_LAST_MSK)
+#define PTD_GET_EP(p) (((p)->mps & PTD_EP_MSK) >> 12)
+#define PTD_EP(v) (((v) << 12) & PTD_EP_MSK)
+#define PTD_GET_LEN(p) (((p)->len & PTD_LEN_MSK) >> 0)
+#define PTD_LEN(v) (((v) << 0) & PTD_LEN_MSK)
+#define PTD_GET_DIR(p) (((p)->len & PTD_DIR_MSK) >> 10)
+#define PTD_DIR(v) (((v) << 10) & PTD_DIR_MSK)
+#define PTD_GET_B5_5(p) (((p)->len & PTD_B5_5_MSK) >> 13)
+#define PTD_B5_5(v) (((v) << 13) & PTD_B5_5_MSK)
+#define PTD_GET_FA(p) (((p)->faddr & PTD_FA_MSK) >> 0)
+#define PTD_FA(v) (((v) << 0) & PTD_FA_MSK)
+#define PTD_GET_FMT(p) (((p)->faddr & PTD_FMT_MSK) >> 7)
+#define PTD_FMT(v) (((v) << 7) & PTD_FMT_MSK)
+
+/* Hardware transfer status codes -- CC from ptd->count */
+#define TD_CC_NOERROR 0x00
+#define TD_CC_CRC 0x01
+#define TD_CC_BITSTUFFING 0x02
+#define TD_CC_DATATOGGLEM 0x03
+#define TD_CC_STALL 0x04
+#define TD_DEVNOTRESP 0x05
+#define TD_PIDCHECKFAIL 0x06
+#define TD_UNEXPECTEDPID 0x07
+#define TD_DATAOVERRUN 0x08
+#define TD_DATAUNDERRUN 0x09
+ /* 0x0A, 0x0B reserved for hardware */
+#define TD_BUFFEROVERRUN 0x0C
+#define TD_BUFFERUNDERRUN 0x0D
+ /* 0x0E, 0x0F reserved for HCD */
+#define TD_NOTACCESSED 0x0F
+
+/* map PTD status codes (CC) to errno values */
+static const int cc_to_error[16] = {
+ /* No Error */ 0,
+ /* CRC Error */ -EILSEQ,
+ /* Bit Stuff */ -EPROTO,
+ /* Data Togg */ -EILSEQ,
+ /* Stall */ -EPIPE,
+ /* DevNotResp */ -ETIMEDOUT,
+ /* PIDCheck */ -EPROTO,
+ /* UnExpPID */ -EPROTO,
+ /* DataOver */ -EOVERFLOW,
+ /* DataUnder */ -EREMOTEIO,
+ /* (for hw) */ -EIO,
+ /* (for hw) */ -EIO,
+ /* BufferOver */ -ECOMM,
+ /* BuffUnder */ -ENOSR,
+ /* (for HCD) */ -EALREADY,
+ /* (for HCD) */ -EALREADY
+};
+
+/*--------------------------------------------------------------*/
+
+#define LOG2_PERIODIC_SIZE 5 /* arbitrary; this matches OHCI */
+#define PERIODIC_SIZE (1 << LOG2_PERIODIC_SIZE)
+
+struct isp116x {
+ spinlock_t lock;
+ struct work_struct rh_resume;
+
+ void __iomem *addr_reg;
+ void __iomem *data_reg;
+
+ struct isp116x_platform_data *board;
+
+ struct proc_dir_entry *pde;
+ unsigned long stat1, stat2, stat4, stat8, stat16;
+
+ /* HC registers */
+ u32 intenb; /* "OHCI" interrupts */
+ u16 irqenb; /* uP interrupts */
+
+ /* Root hub registers */
+ u32 rhdesca;
+ u32 rhdescb;
+ u32 rhstatus;
+ u32 rhport[2];
+
+ /* async schedule: control, bulk */
+ struct list_head async;
+
+ /* periodic schedule: int */
+ u16 load[PERIODIC_SIZE];
+ struct isp116x_ep *periodic[PERIODIC_SIZE];
+ unsigned periodic_count;
+ u16 fmindex;
+
+ /* Schedule for the current frame */
+ struct isp116x_ep *atl_active;
+ int atl_buflen;
+ int atl_bufshrt;
+ int atl_last_dir;
+ atomic_t atl_finishing;
+};
+
+static inline struct isp116x *hcd_to_isp116x(struct usb_hcd *hcd)
+{
+ return (struct isp116x *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *isp116x_to_hcd(struct isp116x *isp116x)
+{
+ return container_of((void *)isp116x, struct usb_hcd, hcd_priv);
+}
+
+struct isp116x_ep {
+ struct usb_host_endpoint *hep;
+ struct usb_device *udev;
+ struct ptd ptd;
+
+ u8 maxpacket;
+ u8 epnum;
+ u8 nextpid;
+ u16 error_count;
+ u16 length; /* of current packet */
+ unsigned char *data; /* to databuf */
+ /* queue of active EP's (the ones scheduled for the
+ current frame) */
+ struct isp116x_ep *active;
+
+ /* periodic schedule */
+ u16 period;
+ u16 branch;
+ u16 load;
+ struct isp116x_ep *next;
+
+ /* async schedule */
+ struct list_head schedule;
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef DEBUG
+#define DBG(stuff...) printk(KERN_DEBUG "116x: " 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 "116x: " stuff)
+#define WARN(stuff...) printk(KERN_WARNING "116x: " stuff)
+#define INFO(stuff...) printk(KERN_INFO "116x: " stuff)
+
+/* ------------------------------------------------- */
+
+#if defined(USE_PLATFORM_DELAY)
+#if defined(USE_NDELAY)
+#error USE_PLATFORM_DELAY and USE_NDELAY simultaneously defined.
+#endif
+#define isp116x_delay(h,d) (h)->board->delay( \
+ isp116x_to_hcd(h)->self.controller,d)
+#define isp116x_check_platform_delay(h) ((h)->board->delay == NULL)
+#elif defined(USE_NDELAY)
+#define isp116x_delay(h,d) ndelay(d)
+#define isp116x_check_platform_delay(h) 0
+#else
+#define isp116x_delay(h,d) do{}while(0)
+#define isp116x_check_platform_delay(h) 0
+#endif
+
+#if defined(DEBUG)
+#define IRQ_TEST() BUG_ON(!irqs_disabled())
+#else
+#define IRQ_TEST() do{}while(0)
+#endif
+
+static inline void isp116x_write_addr(struct isp116x *isp116x, unsigned reg)
+{
+ IRQ_TEST();
+ writew(reg & 0xff, isp116x->addr_reg);
+ isp116x_delay(isp116x, 300);
+}
+
+static inline void isp116x_write_data16(struct isp116x *isp116x, u16 val)
+{
+ writew(val, isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+}
+
+static inline void isp116x_raw_write_data16(struct isp116x *isp116x, u16 val)
+{
+ __raw_writew(val, isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+}
+
+static inline u16 isp116x_read_data16(struct isp116x *isp116x)
+{
+ u16 val;
+
+ val = readw(isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+ return val;
+}
+
+static inline u16 isp116x_raw_read_data16(struct isp116x *isp116x)
+{
+ u16 val;
+
+ val = __raw_readw(isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+ return val;
+}
+
+static inline void isp116x_write_data32(struct isp116x *isp116x, u32 val)
+{
+ writew(val & 0xffff, isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+ writew(val >> 16, isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+}
+
+static inline u32 isp116x_read_data32(struct isp116x *isp116x)
+{
+ u32 val;
+
+ val = (u32) readw(isp116x->data_reg);
+ isp116x_delay(isp116x, 150);
+ val |= ((u32) readw(isp116x->data_reg)) << 16;
+ isp116x_delay(isp116x, 150);
+ return val;
+}
+
+/* Let's keep register access functions out of line. Hint:
+ we wait at least 150 ns at every access.
+*/
+static u16 isp116x_read_reg16(struct isp116x *isp116x, unsigned reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_read_data16(isp116x);
+}
+
+static u32 isp116x_read_reg32(struct isp116x *isp116x, unsigned reg)
+{
+ isp116x_write_addr(isp116x, reg);
+ return isp116x_read_data32(isp116x);
+}
+
+static void isp116x_write_reg16(struct isp116x *isp116x, unsigned reg,
+ unsigned val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_write_data16(isp116x, (u16) (val & 0xffff));
+}
+
+static void isp116x_write_reg32(struct isp116x *isp116x, unsigned reg,
+ unsigned val)
+{
+ isp116x_write_addr(isp116x, reg | ISP116x_WRITE_OFFSET);
+ isp116x_write_data32(isp116x, (u32) val);
+}
+
+#define isp116x_show_reg(d,r) { \
+ if ((r) < 0x20) { \
+ DBG("%-12s[%02x]: %08x\n", #r, \
+ r, isp116x_read_reg32(d, r)); \
+ } else { \
+ DBG("%-12s[%02x]: %04x\n", #r, \
+ r, isp116x_read_reg16(d, r)); \
+ } \
+}
+
+static inline void isp116x_show_regs(struct isp116x *isp116x)
+{
+ isp116x_show_reg(isp116x, HCREVISION);
+ isp116x_show_reg(isp116x, HCCONTROL);
+ isp116x_show_reg(isp116x, HCCMDSTAT);
+ isp116x_show_reg(isp116x, HCINTSTAT);
+ isp116x_show_reg(isp116x, HCINTENB);
+ isp116x_show_reg(isp116x, HCFMINTVL);
+ isp116x_show_reg(isp116x, HCFMREM);
+ isp116x_show_reg(isp116x, HCFMNUM);
+ isp116x_show_reg(isp116x, HCLSTHRESH);
+ isp116x_show_reg(isp116x, HCRHDESCA);
+ isp116x_show_reg(isp116x, HCRHDESCB);
+ isp116x_show_reg(isp116x, HCRHSTATUS);
+ isp116x_show_reg(isp116x, HCRHPORT1);
+ isp116x_show_reg(isp116x, HCRHPORT2);
+ isp116x_show_reg(isp116x, HCHWCFG);
+ isp116x_show_reg(isp116x, HCDMACFG);
+ isp116x_show_reg(isp116x, HCXFERCTR);
+ isp116x_show_reg(isp116x, HCuPINT);
+ isp116x_show_reg(isp116x, HCuPINTENB);
+ isp116x_show_reg(isp116x, HCCHIPID);
+ isp116x_show_reg(isp116x, HCSCRATCH);
+ isp116x_show_reg(isp116x, HCITLBUFLEN);
+ isp116x_show_reg(isp116x, HCATLBUFLEN);
+ isp116x_show_reg(isp116x, HCBUFSTAT);
+ isp116x_show_reg(isp116x, HCRDITL0LEN);
+ isp116x_show_reg(isp116x, HCRDITL1LEN);
+}
+
+#if defined(URB_TRACE)
+
+#define PIPETYPE(pipe) ({ char *__s; \
+ if (usb_pipecontrol(pipe)) __s = "ctrl"; \
+ else if (usb_pipeint(pipe)) __s = "int"; \
+ else if (usb_pipebulk(pipe)) __s = "bulk"; \
+ else __s = "iso"; \
+ __s;})
+#define PIPEDIR(pipe) ({ usb_pipein(pipe) ? "in" : "out"; })
+#define URB_NOTSHORT(urb) ({ (urb)->transfer_flags & URB_SHORT_NOT_OK ? \
+ "short_not_ok" : ""; })
+
+/* print debug info about the URB */
+static void urb_dbg(struct urb *urb, char *msg)
+{
+ unsigned int pipe;
+
+ if (!urb) {
+ DBG("%s: zero urb\n", msg);
+ return;
+ }
+ pipe = urb->pipe;
+ DBG("%s: FA %d ep%d%s %s: len %d/%d %s\n", msg,
+ usb_pipedevice(pipe), usb_pipeendpoint(pipe),
+ PIPEDIR(pipe), PIPETYPE(pipe),
+ urb->transfer_buffer_length, urb->actual_length, URB_NOTSHORT(urb));
+}
+
+#else
+
+#define urb_dbg(urb,msg) do{}while(0)
+
+#endif /* ! defined(URB_TRACE) */
+
+#if defined(PTD_TRACE)
+
+#define PTD_DIR_STR(ptd) ({char __c; \
+ switch(PTD_GET_DIR(ptd)){ \
+ case 0: __c = 's'; break; \
+ case 1: __c = 'o'; break; \
+ default: __c = 'i'; break; \
+ }; __c;})
+
+/*
+ Dump PTD info. The code documents the format
+ perfectly, right :)
+*/
+static inline void dump_ptd(struct ptd *ptd)
+{
+ printk("td: %x %d%c%d %d,%d,%d %x %x%x%x\n",
+ PTD_GET_CC(ptd), PTD_GET_FA(ptd),
+ PTD_DIR_STR(ptd), PTD_GET_EP(ptd),
+ PTD_GET_COUNT(ptd), PTD_GET_LEN(ptd), PTD_GET_MPS(ptd),
+ PTD_GET_TOGGLE(ptd), PTD_GET_ACTIVE(ptd),
+ PTD_GET_SPD(ptd), PTD_GET_LAST(ptd));
+}
+
+static inline void dump_ptd_out_data(struct ptd *ptd, u8 * buf)
+{
+ int k;
+
+ if (PTD_GET_DIR(ptd) != PTD_DIR_IN && PTD_GET_LEN(ptd)) {
+ printk("-> ");
+ for (k = 0; k < PTD_GET_LEN(ptd); ++k)
+ printk("%02x ", ((u8 *) buf)[k]);
+ printk("\n");
+ }
+}
+
+static inline void dump_ptd_in_data(struct ptd *ptd, u8 * buf)
+{
+ int k;
+
+ if (PTD_GET_DIR(ptd) == PTD_DIR_IN && PTD_GET_COUNT(ptd)) {
+ printk("<- ");
+ for (k = 0; k < PTD_GET_COUNT(ptd); ++k)
+ printk("%02x ", ((u8 *) buf)[k]);
+ printk("\n");
+ }
+ if (PTD_GET_LAST(ptd))
+ printk("-\n");
+}
+
+#else
+
+#define dump_ptd(ptd) do{}while(0)
+#define dump_ptd_in_data(ptd,buf) do{}while(0)
+#define dump_ptd_out_data(ptd,buf) do{}while(0)
+
+#endif /* ! defined(PTD_TRACE) */
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 1e27f10c1592..68decab280dd 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -95,12 +95,11 @@
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/list.h>
-#include <linux/interrupt.h> /* for in_interrupt () */
#include <linux/usb.h>
#include <linux/usb_otg.h>
-#include "../core/hcd.h"
#include <linux/dma-mapping.h>
-#include <linux/dmapool.h> /* needed by ohci-mem.c when no PCI */
+#include <linux/dmapool.h>
+#include <linux/reboot.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -108,8 +107,9 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
+#include "../core/hcd.h"
-#define DRIVER_VERSION "2004 Nov 08"
+#define DRIVER_VERSION "2005 April 22"
#define DRIVER_AUTHOR "Roman Weissgaerber, David Brownell"
#define DRIVER_DESC "USB 1.1 'Open' Host Controller (OHCI) Driver"
@@ -141,6 +141,7 @@ static const char hcd_name [] = "ohci_hcd";
static void ohci_dump (struct ohci_hcd *ohci, int verbose);
static int ohci_init (struct ohci_hcd *ohci);
static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_reboot (struct notifier_block *, unsigned long , void *);
#include "ohci-hub.c"
#include "ohci-dbg.c"
@@ -179,7 +180,7 @@ static int ohci_urb_enqueue (
struct usb_hcd *hcd,
struct usb_host_endpoint *ep,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
) {
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
struct ed *ed;
@@ -420,6 +421,23 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
}
+/* reboot notifier forcibly disables IRQs and DMA, helping kexec and
+ * other cases where the next software may expect clean state from the
+ * "firmware". this is bus-neutral, unlike shutdown() methods.
+ */
+static int
+ohci_reboot (struct notifier_block *block, unsigned long code, void *null)
+{
+ struct ohci_hcd *ohci;
+
+ ohci = container_of (block, struct ohci_hcd, reboot_notifier);
+ ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+ ohci_usb_reset (ohci);
+ /* flush the writes */
+ (void) ohci_readl (ohci, &ohci->regs->control);
+ return 0;
+}
+
/*-------------------------------------------------------------------------*
* HC functions
*-------------------------------------------------------------------------*/
@@ -487,13 +505,10 @@ static int ohci_init (struct ohci_hcd *ohci)
/* Start an OHCI controller, set the BUS operational
* resets USB and controller
* enable interrupts
- * connect the virtual root hub
*/
static int ohci_run (struct ohci_hcd *ohci)
{
u32 mask, temp;
- struct usb_device *udev;
- struct usb_bus *bus;
int first = ohci->fminterval == 0;
disable (ohci);
@@ -654,37 +669,15 @@ retry:
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((temp >> 23) & 0x1fe);
- bus = &ohci_to_hcd(ohci)->self;
ohci_to_hcd(ohci)->state = HC_STATE_RUNNING;
ohci_dump (ohci, 1);
- udev = bus->root_hub;
- if (udev) {
- return 0;
- }
-
- /* connect the virtual root hub */
- udev = usb_alloc_dev (NULL, bus, 0);
- if (!udev) {
- disable (ohci);
- ohci->hc_control &= ~OHCI_CTRL_HCFS;
- ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
- return -ENOMEM;
- }
-
- udev->speed = USB_SPEED_FULL;
- if (usb_hcd_register_root_hub (udev, ohci_to_hcd(ohci)) != 0) {
- usb_put_dev (udev);
- disable (ohci);
- ohci->hc_control &= ~OHCI_CTRL_HCFS;
- ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
- return -ENODEV;
+ if (ohci_to_hcd(ohci)->self.root_hub == NULL) {
+ register_reboot_notifier (&ohci->reboot_notifier);
+ create_debug_files (ohci);
}
- if (ohci->power_budget)
- hub_set_power_budget(udev, ohci->power_budget);
- create_debug_files (ohci);
return 0;
}
@@ -781,6 +774,7 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
remove_debug_files (ohci);
+ unregister_reboot_notifier (&ohci->reboot_notifier);
ohci_mem_cleanup (ohci);
if (ohci->hcca) {
dma_free_coherent (hcd->self.controller,
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index e2fc4129dfc6..83ca4549a50e 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -419,10 +419,11 @@ ohci_hub_descriptor (
/* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
rh = roothub_b (ohci);
+ memset(desc->bitmap, 0xff, sizeof(desc->bitmap));
desc->bitmap [0] = rh & RH_B_DR;
if (ports > 7) {
desc->bitmap [1] = (rh & RH_B_DR) >> 8;
- desc->bitmap [2] = desc->bitmap [3] = 0xff;
+ desc->bitmap [2] = 0xff;
} else
desc->bitmap [1] = 0xff;
}
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index e55682b4919d..fd3c4d3714bd 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -29,6 +29,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
spin_lock_init (&ohci->lock);
INIT_LIST_HEAD (&ohci->pending);
INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
+ ohci->reboot_notifier.notifier_call = ohci_reboot;
}
/*-------------------------------------------------------------------------*/
@@ -83,7 +84,7 @@ dma_to_td (struct ohci_hcd *hc, dma_addr_t td_dma)
/* TDs ... */
static struct td *
-td_alloc (struct ohci_hcd *hc, int mem_flags)
+td_alloc (struct ohci_hcd *hc, unsigned mem_flags)
{
dma_addr_t dma;
struct td *td;
@@ -117,7 +118,7 @@ td_free (struct ohci_hcd *hc, struct td *td)
/* EDs ... */
static struct ed *
-ed_alloc (struct ohci_hcd *hc, int mem_flags)
+ed_alloc (struct ohci_hcd *hc, unsigned mem_flags)
{
dma_addr_t dma;
struct ed *ed;
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 8aab5907afe9..5cde76faab93 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -181,7 +181,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
if (config->otg) {
ohci_to_hcd(ohci)->self.otg_port = config->otg;
/* default/minimum OTG power budget: 8 mA */
- ohci->power_budget = 8;
+ ohci_to_hcd(ohci)->power_budget = 8;
}
/* boards can use OTG transceivers in non-OTG modes */
@@ -230,7 +230,7 @@ static int omap_start_hc(struct ohci_hcd *ohci, struct platform_device *pdev)
/* TPS2045 switch for internal transceiver (port 1) */
if (machine_is_omap_osk()) {
- ohci->power_budget = 250;
+ ohci_to_hcd(ohci)->power_budget = 250;
rh &= ~RH_A_NOCP;
@@ -456,34 +456,22 @@ static int ohci_hcd_omap_drv_remove(struct device *dev)
#ifdef CONFIG_PM
-/* states match PCI usage, always suspending the root hub except that
- * 4 ~= D3cold (ACPI D3) with clock off (resume sees reset).
- *
- * FIXME: above comment is not right, and code is wrong, too :-(.
- */
-
-static int ohci_omap_suspend(struct device *dev, pm_message_t state, u32 level)
+static int ohci_omap_suspend(struct device *dev, pm_message_t message, u32 level)
{
struct ohci_hcd *ohci = hcd_to_ohci(dev_get_drvdata(dev));
int status = -EINVAL;
if (level != SUSPEND_POWER_DOWN)
return 0;
- if (state <= dev->power.power_state)
- return 0;
- dev_dbg(dev, "suspend to %d\n", state);
down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
status = ohci_hub_suspend(ohci_to_hcd(ohci));
if (status == 0) {
- if (state >= 4) {
- omap_ohci_clock_power(0);
- ohci_to_hcd(ohci)->self.root_hub->state =
- USB_STATE_SUSPENDED;
- state = 4;
- }
+ omap_ohci_clock_power(0);
+ ohci_to_hcd(ohci)->self.root_hub->state =
+ USB_STATE_SUSPENDED;
ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
- dev->power.power_state = state;
+ dev->power.power_state = PMSG_SUSPEND;
}
up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
return status;
@@ -497,29 +485,20 @@ static int ohci_omap_resume(struct device *dev, u32 level)
if (level != RESUME_POWER_ON)
return 0;
- switch (dev->power.power_state) {
- case 0:
- break;
- case 4:
- if (time_before(jiffies, ohci->next_statechange))
- msleep(5);
- ohci->next_statechange = jiffies;
- omap_ohci_clock_power(1);
- /* FALLTHROUGH */
- default:
- dev_dbg(dev, "resume from %d\n", dev->power.power_state);
+ if (time_before(jiffies, ohci->next_statechange))
+ msleep(5);
+ ohci->next_statechange = jiffies;
+ omap_ohci_clock_power(1);
#ifdef CONFIG_USB_SUSPEND
- /* get extra cleanup even if remote wakeup isn't in use */
- status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub);
+ /* get extra cleanup even if remote wakeup isn't in use */
+ status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub);
#else
- down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
- status = ohci_hub_resume(ohci_to_hcd(ohci));
- up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+ down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
+ status = ohci_hub_resume(ohci_to_hcd(ohci));
+ up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
#endif
- if (status == 0)
- dev->power.power_state = 0;
- break;
- }
+ if (status == 0)
+ dev->power.power_state = PMSG_ON;
return status;
}
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 57fd07d00549..eede6be098d2 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -14,14 +14,11 @@
* This file is licenced under the GPL.
*/
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
#include <asm/machdep.h>
#include <asm/pmac_feature.h>
#include <asm/pci-bridge.h>
#include <asm/prom.h>
-#ifndef CONFIG_PM
-# define CONFIG_PM
-#endif
#endif
#ifndef CONFIG_PCI
@@ -132,7 +129,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
/* let things settle down a bit */
msleep (100);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
if (_machine == _MACH_Pmac) {
struct device_node *of_node;
@@ -141,7 +138,7 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
return 0;
}
@@ -151,7 +148,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
int retval = 0;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PPC_PMAC
if (_machine == _MACH_Pmac) {
struct device_node *of_node;
@@ -160,7 +157,7 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
if (of_node)
pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PPC_PMAC */
/* resume root hub */
if (time_before (jiffies, ohci->next_statechange))
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 22e1ac138ac0..71cdd2262860 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -371,7 +371,6 @@ struct ohci_hcd {
* other external transceivers should be software-transparent
*/
struct otg_transceiver *transceiver;
- unsigned power_budget;
/*
* memory management for queue data structures
@@ -390,6 +389,7 @@ struct ohci_hcd {
u32 fminterval; /* saved register */
struct work_struct rh_resume;
+ struct notifier_block reboot_notifier;
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 99d43f758ad0..7a890a65f55d 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -815,7 +815,7 @@ static int sl811h_urb_enqueue(
struct usb_hcd *hcd,
struct usb_host_endpoint *hep,
struct urb *urb,
- int mem_flags
+ unsigned mem_flags
) {
struct sl811 *sl811 = hcd_to_sl811(hcd);
struct usb_device *udev = urb->dev;
@@ -1563,29 +1563,15 @@ static int
sl811h_start(struct usb_hcd *hcd)
{
struct sl811 *sl811 = hcd_to_sl811(hcd);
- struct usb_device *udev;
/* chip has been reset, VBUS power is off */
-
- udev = usb_alloc_dev(NULL, &hcd->self, 0);
- if (!udev)
- return -ENOMEM;
-
- udev->speed = USB_SPEED_FULL;
hcd->state = HC_STATE_RUNNING;
- if (sl811->board)
+ if (sl811->board) {
hcd->can_wakeup = sl811->board->can_wakeup;
-
- if (usb_hcd_register_root_hub(udev, hcd) != 0) {
- usb_put_dev(udev);
- sl811h_stop(hcd);
- return -ENODEV;
+ hcd->power_budget = sl811->board->power * 2;
}
- if (sl811->board && sl811->board->power)
- hub_set_power_budget(udev, sl811->board->power * 2);
-
/* enable power and interupts */
port_power(sl811, 1);
diff --git a/drivers/usb/host/sl811_cs.c b/drivers/usb/host/sl811_cs.c
index 6e173265095c..38aebe361ca1 100644
--- a/drivers/usb/host/sl811_cs.c
+++ b/drivers/usb/host/sl811_cs.c
@@ -20,7 +20,6 @@
#include <linux/timer.h>
#include <linux/ioport.h>
-#include <pcmcia/version.h>
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/cistpl.h>
@@ -68,13 +67,6 @@ static const char driver_name[DEV_NAME_LEN] = "sl811_cs";
static dev_link_t *dev_list = NULL;
-static int irq_list[4] = { -1 };
-static int irq_list_count;
-
-module_param_array(irq_list, int, &irq_list_count, 0444);
-
-INT_MODULE_PARM(irq_mask, 0xdeb8);
-
typedef struct local_info_t {
dev_link_t link;
dev_node_t node;
@@ -373,7 +365,7 @@ static dev_link_t *sl811_cs_attach(void)
local_info_t *local;
dev_link_t *link;
client_reg_t client_reg;
- int ret, i;
+ int ret;
local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
if (!local)
@@ -385,11 +377,6 @@ static dev_link_t *sl811_cs_attach(void)
/* Initialize */
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
- if (irq_list[0] == -1)
- link->irq.IRQInfo2 = irq_mask;
- else
- for (i = 0; i < irq_list_count; i++)
- link->irq.IRQInfo2 |= 1 << irq_list[i];
link->irq.Handler = NULL;
link->conf.Attributes = 0;
@@ -401,11 +388,6 @@ static dev_link_t *sl811_cs_attach(void)
dev_list = link;
client_reg.dev_info = (dev_info_t *) &driver_name;
client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
- CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
- CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
- client_reg.event_handler = &sl811_cs_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
ret = pcmcia_register_client(&link->handle, &client_reg);
@@ -418,13 +400,21 @@ static dev_link_t *sl811_cs_attach(void)
return link;
}
+static struct pcmcia_device_id sl811_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0xc015, 0x0001), /* RATOC USB HOST CF+ Card */
+ PCMCIA_DEVICE_NULL,
+};
+MODULE_DEVICE_TABLE(pcmcia, sl811_ids);
+
static struct pcmcia_driver sl811_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = (char *)driver_name,
},
.attach = sl811_cs_attach,
+ .event = sl811_cs_event,
.detach = sl811_cs_detach,
+ .id_table = sl811_ids,
};
/*====================================================================*/
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 24c73c5a3435..4538a98b6f9d 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -237,6 +237,37 @@ static int uhci_show_sc(int port, unsigned short status, char *buf, int len)
return out - buf;
}
+static int uhci_show_root_hub_state(struct uhci_hcd *uhci, char *buf, int len)
+{
+ char *out = buf;
+ char *rh_state;
+
+ /* Try to make sure there's enough memory */
+ if (len < 60)
+ return 0;
+
+ switch (uhci->rh_state) {
+ case UHCI_RH_RESET:
+ rh_state = "reset"; break;
+ case UHCI_RH_SUSPENDED:
+ rh_state = "suspended"; break;
+ case UHCI_RH_AUTO_STOPPED:
+ rh_state = "auto-stopped"; break;
+ case UHCI_RH_RESUMING:
+ rh_state = "resuming"; break;
+ case UHCI_RH_SUSPENDING:
+ rh_state = "suspending"; break;
+ case UHCI_RH_RUNNING:
+ rh_state = "running"; break;
+ case UHCI_RH_RUNNING_NODEVS:
+ rh_state = "running, no devs"; break;
+ default:
+ rh_state = "?"; break;
+ }
+ out += sprintf(out, "Root-hub state: %s\n", rh_state);
+ return out - buf;
+}
+
static int uhci_show_status(struct uhci_hcd *uhci, char *buf, int len)
{
char *out = buf;
@@ -408,6 +439,7 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
spin_lock_irqsave(&uhci->lock, flags);
+ out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
out += sprintf(out, "HC status\n");
out += uhci_show_status(uhci, out, len - (out - buf));
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 49bd83ee0c75..0d5d2545bf07 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -13,18 +13,13 @@
* (C) Copyright 2000 Yggdrasil Computing, Inc. (port of new PCI interface
* support from usb-ohci.c by Adam Richter, adam@yggdrasil.com).
* (C) Copyright 1999 Gregory P. Smith (from usb-ohci.c)
- * (C) Copyright 2004 Alan Stern, stern@rowland.harvard.edu
+ * (C) Copyright 2004-2005 Alan Stern, stern@rowland.harvard.edu
*
* Intel documents this fairly well, and as far as I know there
* are no royalties or anything like that, but even so there are
* people who decided that they want to do the same thing in a
* completely different way.
*
- * WARNING! The USB documentation is downright evil. Most of it
- * is just crap, written by a committee. You're better off ignoring
- * most of it, the important stuff is:
- * - the low-level protocol (fairly simple but lots of small details)
- * - working around the horridness of the rest
*/
#include <linux/config.h>
@@ -64,7 +59,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v2.2"
+#define DRIVER_VERSION "v2.3"
#define DRIVER_AUTHOR "Linus 'Frodo Rabbit' Torvalds, Johannes Erdfelt, \
Randy Dunlap, Georg Acher, Deti Fliegl, Thomas Sailer, Roman Weissgaerber, \
Alan Stern"
@@ -89,8 +84,9 @@ static char *errbuf;
static kmem_cache_t *uhci_up_cachep; /* urb_priv */
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
+static void wakeup_rh(struct uhci_hcd *uhci);
static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
-static void hc_state_transitions(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */
#define IDLE_TIMEOUT msecs_to_jiffies(50)
@@ -101,308 +97,352 @@ static void hc_state_transitions(struct uhci_hcd *uhci);
/* to make sure it doesn't hog all of the bandwidth */
#define DEPTH_INTERVAL 5
+static inline void restart_timer(struct uhci_hcd *uhci)
+{
+ mod_timer(&uhci->stall_timer, jiffies + msecs_to_jiffies(100));
+}
+
#include "uhci-hub.c"
#include "uhci-debug.c"
#include "uhci-q.c"
-static int init_stall_timer(struct usb_hcd *hcd);
-
-static void stall_callback(unsigned long ptr)
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+static void reset_hc(struct uhci_hcd *uhci)
{
- struct usb_hcd *hcd = (struct usb_hcd *)ptr;
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- struct urb_priv *up;
- unsigned long flags;
+ int port;
- spin_lock_irqsave(&uhci->lock, flags);
- uhci_scan_schedule(uhci, NULL);
-
- list_for_each_entry(up, &uhci->urb_list, urb_list) {
- struct urb *u = up->urb;
-
- spin_lock(&u->lock);
-
- /* Check if the FSBR timed out */
- if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
- uhci_fsbr_timeout(uhci, u);
+ /* Turn off PIRQ enable and SMI enable. (This also turns off the
+ * BIOS's USB Legacy Support.) Turn off all the R/WC bits too.
+ */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+ USBLEGSUP_RWC);
- spin_unlock(&u->lock);
- }
+ /* Reset the HC - this will force us to get a
+ * new notification of any already connected
+ * ports due to the virtual disconnect that it
+ * implies.
+ */
+ outw(USBCMD_HCRESET, uhci->io_addr + USBCMD);
+ mb();
+ udelay(5);
+ if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET)
+ dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
- /* Really disable FSBR */
- if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
- uhci->fsbrtimeout = 0;
- uhci->skel_term_qh->link = UHCI_PTR_TERM;
- }
+ /* Just to be safe, disable interrupt requests and
+ * make sure the controller is stopped.
+ */
+ outw(0, uhci->io_addr + USBINTR);
+ outw(0, uhci->io_addr + USBCMD);
- /* Poll for and perform state transitions */
- hc_state_transitions(uhci);
- if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED))
- uhci_check_ports(uhci);
+ /* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
+ * bits in the port status and control registers.
+ * We have to clear them by hand.
+ */
+ for (port = 0; port < uhci->rh_numports; ++port)
+ outw(0, uhci->io_addr + USBPORTSC1 + (port * 2));
- init_stall_timer(hcd);
- spin_unlock_irqrestore(&uhci->lock, flags);
+ uhci->port_c_suspend = uhci->suspended_ports =
+ uhci->resuming_ports = 0;
+ uhci->rh_state = UHCI_RH_RESET;
+ uhci->is_stopped = UHCI_IS_STOPPED;
+ uhci_to_hcd(uhci)->state = HC_STATE_HALT;
+ uhci_to_hcd(uhci)->poll_rh = 0;
}
-static int init_stall_timer(struct usb_hcd *hcd)
+/*
+ * Last rites for a defunct/nonfunctional controller
+ * or one we don't want to use any more.
+ */
+static void hc_died(struct uhci_hcd *uhci)
{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
-
- init_timer(&uhci->stall_timer);
- uhci->stall_timer.function = stall_callback;
- uhci->stall_timer.data = (unsigned long)hcd;
- uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
- add_timer(&uhci->stall_timer);
-
- return 0;
+ reset_hc(uhci);
+ uhci->hc_inaccessible = 1;
+ del_timer(&uhci->stall_timer);
}
-static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed. In either case we can't be sure of its previous state.
+ */
+static void check_and_reset_hc(struct uhci_hcd *uhci)
{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned long io_addr = uhci->io_addr;
- unsigned short status;
+ u16 legsup;
+ unsigned int cmd, intr;
/*
- * Read the interrupt status, and write it back to clear the
- * interrupt cause. Contrary to the UHCI specification, the
- * "HC Halted" status bit is persistent: it is RO, not R/WC.
+ * When restarting a suspended controller, we expect all the
+ * settings to be the same as we left them:
+ *
+ * PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
+ * Controller is stopped and configured with EGSM set;
+ * No interrupts enabled except possibly Resume Detect.
+ *
+ * If any of these conditions are violated we do a complete reset.
*/
- status = inw(io_addr + USBSTS);
- if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
- return IRQ_NONE;
- outw(status, io_addr + USBSTS); /* Clear it */
-
- if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
- if (status & USBSTS_HSE)
- dev_err(uhci_dev(uhci), "host system error, "
- "PCI problems?\n");
- if (status & USBSTS_HCPE)
- dev_err(uhci_dev(uhci), "host controller process "
- "error, something bad happened!\n");
- if ((status & USBSTS_HCH) && uhci->state > 0) {
- dev_err(uhci_dev(uhci), "host controller halted, "
- "very bad!\n");
- /* FIXME: Reset the controller, fix the offending TD */
- }
+ pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup);
+ if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) {
+ dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n",
+ __FUNCTION__, legsup);
+ goto reset_needed;
}
- if (status & USBSTS_RD)
- uhci->resume_detect = 1;
+ cmd = inw(uhci->io_addr + USBCMD);
+ if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
+ dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
+ __FUNCTION__, cmd);
+ goto reset_needed;
+ }
- spin_lock(&uhci->lock);
- uhci_scan_schedule(uhci, regs);
- spin_unlock(&uhci->lock);
+ intr = inw(uhci->io_addr + USBINTR);
+ if (intr & (~USBINTR_RESUME)) {
+ dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
+ __FUNCTION__, intr);
+ goto reset_needed;
+ }
+ return;
- return IRQ_HANDLED;
+reset_needed:
+ dev_dbg(uhci_dev(uhci), "Performing full reset\n");
+ reset_hc(uhci);
}
-static void reset_hc(struct uhci_hcd *uhci)
+/*
+ * Store the basic register settings needed by the controller.
+ */
+static void configure_hc(struct uhci_hcd *uhci)
{
- unsigned long io_addr = uhci->io_addr;
+ /* Set the frame length to the default: 1 ms exactly */
+ outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
- /* Turn off PIRQ, SMI, and all interrupts. This also turns off
- * the BIOS's USB Legacy Support.
- */
- pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
- outw(0, uhci->io_addr + USBINTR);
+ /* Store the frame list base address */
+ outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
- /* Global reset for 50ms */
- uhci->state = UHCI_RESET;
- outw(USBCMD_GRESET, io_addr + USBCMD);
- msleep(50);
- outw(0, io_addr + USBCMD);
+ /* Set the current frame number */
+ outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
- /* Another 10ms delay */
- msleep(10);
- uhci->resume_detect = 0;
- uhci->is_stopped = UHCI_IS_STOPPED;
+ /* Mark controller as running before we enable interrupts */
+ uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+ mb();
+
+ /* Enable PIRQ */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+ USBLEGSUP_DEFAULT);
}
-static void suspend_hc(struct uhci_hcd *uhci)
+
+static int resume_detect_interrupts_are_broken(struct uhci_hcd *uhci)
{
- unsigned long io_addr = uhci->io_addr;
+ int port;
- dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
- uhci->state = UHCI_SUSPENDED;
- uhci->resume_detect = 0;
- outw(USBCMD_EGSM, io_addr + USBCMD);
+ switch (to_pci_dev(uhci_dev(uhci))->vendor) {
+ default:
+ break;
- /* FIXME: Wait for the controller to actually stop */
- uhci_get_current_frame_number(uhci);
- uhci->is_stopped = UHCI_IS_STOPPED;
+ case PCI_VENDOR_ID_GENESYS:
+ /* Genesys Logic's GL880S controllers don't generate
+ * resume-detect interrupts.
+ */
+ return 1;
- uhci_scan_schedule(uhci, NULL);
+ case PCI_VENDOR_ID_INTEL:
+ /* Some of Intel's USB controllers have a bug that causes
+ * resume-detect interrupts if any port has an over-current
+ * condition. To make matters worse, some motherboards
+ * hardwire unused USB ports' over-current inputs active!
+ * To prevent problems, we will not enable resume-detect
+ * interrupts if any ports are OC.
+ */
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if (inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ USBPORTSC_OC)
+ return 1;
+ }
+ break;
+ }
+ return 0;
}
-static void wakeup_hc(struct uhci_hcd *uhci)
+static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state)
+__releases(uhci->lock)
+__acquires(uhci->lock)
{
- unsigned long io_addr = uhci->io_addr;
+ int auto_stop;
+ int int_enable;
- switch (uhci->state) {
- case UHCI_SUSPENDED: /* Start the resume */
- dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
-
- /* Global resume for >= 20ms */
- outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
- uhci->state = UHCI_RESUMING_1;
- uhci->state_end = jiffies + msecs_to_jiffies(20);
- uhci->is_stopped = 0;
- break;
+ auto_stop = (new_state == UHCI_RH_AUTO_STOPPED);
+ dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+ (auto_stop ? " (auto-stop)" : ""));
- case UHCI_RESUMING_1: /* End global resume */
- uhci->state = UHCI_RESUMING_2;
- outw(0, io_addr + USBCMD);
- /* Falls through */
-
- case UHCI_RESUMING_2: /* Wait for EOP to be sent */
- if (inw(io_addr + USBCMD) & USBCMD_FGR)
- break;
-
- /* Run for at least 1 second, and
- * mark it configured with a 64-byte max packet */
- uhci->state = UHCI_RUNNING_GRACE;
- uhci->state_end = jiffies + HZ;
- outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP,
- io_addr + USBCMD);
- break;
+ /* If we get a suspend request when we're already auto-stopped
+ * then there's nothing to do.
+ */
+ if (uhci->rh_state == UHCI_RH_AUTO_STOPPED) {
+ uhci->rh_state = new_state;
+ return;
+ }
- case UHCI_RUNNING_GRACE: /* Now allowed to suspend */
- uhci->state = UHCI_RUNNING;
- break;
+ /* Enable resume-detect interrupts if they work.
+ * Then enter Global Suspend mode, still configured.
+ */
+ int_enable = (resume_detect_interrupts_are_broken(uhci) ?
+ 0 : USBINTR_RESUME);
+ outw(int_enable, uhci->io_addr + USBINTR);
+ outw(USBCMD_EGSM | USBCMD_CF, uhci->io_addr + USBCMD);
+ mb();
+ udelay(5);
- default:
- break;
+ /* If we're auto-stopping then no devices have been attached
+ * for a while, so there shouldn't be any active URBs and the
+ * controller should stop after a few microseconds. Otherwise
+ * we will give the controller one frame to stop.
+ */
+ if (!auto_stop && !(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
+ uhci->rh_state = UHCI_RH_SUSPENDING;
+ spin_unlock_irq(&uhci->lock);
+ msleep(1);
+ spin_lock_irq(&uhci->lock);
+ if (uhci->hc_inaccessible) /* Died */
+ return;
}
-}
+ if (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH))
+ dev_warn(uhci_dev(uhci), "Controller not stopped yet!\n");
-static int ports_active(struct uhci_hcd *uhci)
-{
- unsigned long io_addr = uhci->io_addr;
- int connection = 0;
- int i;
+ uhci_get_current_frame_number(uhci);
+ smp_wmb();
- for (i = 0; i < uhci->rh_numports; i++)
- connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS);
+ uhci->rh_state = new_state;
+ uhci->is_stopped = UHCI_IS_STOPPED;
+ del_timer(&uhci->stall_timer);
+ uhci_to_hcd(uhci)->poll_rh = !int_enable;
- return connection;
+ uhci_scan_schedule(uhci, NULL);
}
-static int suspend_allowed(struct uhci_hcd *uhci)
+static void start_rh(struct uhci_hcd *uhci)
{
- unsigned long io_addr = uhci->io_addr;
- int i;
-
- if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
- return 1;
+ uhci->is_stopped = 0;
+ smp_wmb();
- /* Some of Intel's USB controllers have a bug that causes false
- * resume indications if any port has an over current condition.
- * To prevent problems, we will not allow a global suspend if
- * any ports are OC.
- *
- * Some motherboards using Intel's chipsets (but not using all
- * the USB ports) appear to hardwire the over current inputs active
- * to disable the USB ports.
+ /* Mark it configured and running with a 64-byte max packet.
+ * All interrupts are enabled, even though RESUME won't do anything.
*/
-
- /* check for over current condition on any port */
- for (i = 0; i < uhci->rh_numports; i++) {
- if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC)
- return 0;
- }
-
- return 1;
+ outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, uhci->io_addr + USBCMD);
+ outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
+ uhci->io_addr + USBINTR);
+ mb();
+ uhci->rh_state = UHCI_RH_RUNNING;
+ uhci_to_hcd(uhci)->poll_rh = 1;
+ restart_timer(uhci);
}
-static void hc_state_transitions(struct uhci_hcd *uhci)
+static void wakeup_rh(struct uhci_hcd *uhci)
+__releases(uhci->lock)
+__acquires(uhci->lock)
{
- switch (uhci->state) {
- case UHCI_RUNNING:
+ dev_dbg(uhci_dev(uhci), "%s%s\n", __FUNCTION__,
+ uhci->rh_state == UHCI_RH_AUTO_STOPPED ?
+ " (auto-start)" : "");
- /* global suspend if nothing connected for 1 second */
- if (!ports_active(uhci) && suspend_allowed(uhci)) {
- uhci->state = UHCI_SUSPENDING_GRACE;
- uhci->state_end = jiffies + HZ;
- }
- break;
-
- case UHCI_SUSPENDING_GRACE:
- if (ports_active(uhci))
- uhci->state = UHCI_RUNNING;
- else if (time_after_eq(jiffies, uhci->state_end))
- suspend_hc(uhci);
- break;
-
- case UHCI_SUSPENDED:
-
- /* wakeup if requested by a device */
- if (uhci->resume_detect)
- wakeup_hc(uhci);
- break;
+ /* If we are auto-stopped then no devices are attached so there's
+ * no need for wakeup signals. Otherwise we send Global Resume
+ * for 20 ms.
+ */
+ if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ uhci->rh_state = UHCI_RH_RESUMING;
+ outw(USBCMD_FGR | USBCMD_EGSM | USBCMD_CF,
+ uhci->io_addr + USBCMD);
+ spin_unlock_irq(&uhci->lock);
+ msleep(20);
+ spin_lock_irq(&uhci->lock);
+ if (uhci->hc_inaccessible) /* Died */
+ return;
+
+ /* End Global Resume and wait for EOP to be sent */
+ outw(USBCMD_CF, uhci->io_addr + USBCMD);
+ mb();
+ udelay(4);
+ if (inw(uhci->io_addr + USBCMD) & USBCMD_FGR)
+ dev_warn(uhci_dev(uhci), "FGR not stopped yet!\n");
+ }
- case UHCI_RESUMING_1:
- case UHCI_RESUMING_2:
- case UHCI_RUNNING_GRACE:
- if (time_after_eq(jiffies, uhci->state_end))
- wakeup_hc(uhci);
- break;
+ start_rh(uhci);
- default:
- break;
- }
+ /* Restart root hub polling */
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer, jiffies);
}
-/*
- * Store the current frame number in uhci->frame_number if the controller
- * is runnning
- */
-static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+static void stall_callback(unsigned long _uhci)
{
+ struct uhci_hcd *uhci = (struct uhci_hcd *) _uhci;
+ unsigned long flags;
+
+ spin_lock_irqsave(&uhci->lock, flags);
+ uhci_scan_schedule(uhci, NULL);
+ check_fsbr(uhci);
+
if (!uhci->is_stopped)
- uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
+ restart_timer(uhci);
+ spin_unlock_irqrestore(&uhci->lock, flags);
}
-static int start_hc(struct uhci_hcd *uhci)
+static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
- unsigned long io_addr = uhci->io_addr;
- int timeout = 10;
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned short status;
+ unsigned long flags;
/*
- * Reset the HC - this will force us to get a
- * new notification of any already connected
- * ports due to the virtual disconnect that it
- * implies.
+ * Read the interrupt status, and write it back to clear the
+ * interrupt cause. Contrary to the UHCI specification, the
+ * "HC Halted" status bit is persistent: it is RO, not R/WC.
*/
- outw(USBCMD_HCRESET, io_addr + USBCMD);
- while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
- if (--timeout < 0) {
- dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n");
- return -ETIMEDOUT;
+ status = inw(uhci->io_addr + USBSTS);
+ if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */
+ return IRQ_NONE;
+ outw(status, uhci->io_addr + USBSTS); /* Clear it */
+
+ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) {
+ if (status & USBSTS_HSE)
+ dev_err(uhci_dev(uhci), "host system error, "
+ "PCI problems?\n");
+ if (status & USBSTS_HCPE)
+ dev_err(uhci_dev(uhci), "host controller process "
+ "error, something bad happened!\n");
+ if (status & USBSTS_HCH) {
+ spin_lock_irqsave(&uhci->lock, flags);
+ if (uhci->rh_state >= UHCI_RH_RUNNING) {
+ dev_err(uhci_dev(uhci),
+ "host controller halted, "
+ "very bad!\n");
+ hc_died(uhci);
+ spin_unlock_irqrestore(&uhci->lock, flags);
+ return IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&uhci->lock, flags);
}
- msleep(1);
}
- /* Mark controller as running before we enable interrupts */
- uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
-
- /* Turn on PIRQ and all interrupts */
- pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
- USBLEGSUP_DEFAULT);
- outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
- io_addr + USBINTR);
+ if (status & USBSTS_RD)
+ usb_hcd_poll_rh_status(hcd);
- /* Start at frame 0 */
- outw(0, io_addr + USBFRNUM);
- outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD);
+ spin_lock_irqsave(&uhci->lock, flags);
+ uhci_scan_schedule(uhci, regs);
+ spin_unlock_irqrestore(&uhci->lock, flags);
- /* Run and mark it configured with a 64-byte max packet */
- uhci->state = UHCI_RUNNING_GRACE;
- uhci->state_end = jiffies + HZ;
- outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD);
- uhci->is_stopped = 0;
+ return IRQ_HANDLED;
+}
- return 0;
+/*
+ * Store the current frame number in uhci->frame_number if the controller
+ * is runnning
+ */
+static void uhci_get_current_frame_number(struct uhci_hcd *uhci)
+{
+ if (!uhci->is_stopped)
+ uhci->frame_number = inw(uhci->io_addr + USBFRNUM);
}
/*
@@ -448,16 +488,58 @@ static void release_uhci(struct uhci_hcd *uhci)
static int uhci_reset(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned io_size = (unsigned) hcd->rsrc_len;
+ int port;
uhci->io_addr = (unsigned long) hcd->rsrc_start;
- /* Kick BIOS off this hardware and reset, so we won't get
- * interrupts from any previous setup.
+ /* The UHCI spec says devices must have 2 ports, and goes on to say
+ * they may have more but gives no way to determine how many there
+ * are. However according to the UHCI spec, Bit 7 of the port
+ * status and control register is always set to 1. So we try to
+ * use this to our advantage. Another common failure mode when
+ * a nonexistent register is addressed is to return all ones, so
+ * we test for that also.
*/
- reset_hc(uhci);
+ for (port = 0; port < (io_size - USBPORTSC1) / 2; port++) {
+ unsigned int portstatus;
+
+ portstatus = inw(uhci->io_addr + USBPORTSC1 + (port * 2));
+ if (!(portstatus & 0x0080) || portstatus == 0xffff)
+ break;
+ }
+ if (debug)
+ dev_info(uhci_dev(uhci), "detected %d ports\n", port);
+
+ /* Anything greater than 7 is weird so we'll ignore it. */
+ if (port > UHCI_RH_MAXCHILD) {
+ dev_info(uhci_dev(uhci), "port count misdetected? "
+ "forcing to 2 ports\n");
+ port = 2;
+ }
+ uhci->rh_numports = port;
+
+ /* Kick BIOS off this hardware and reset if the controller
+ * isn't already safely quiescent.
+ */
+ check_and_reset_hc(uhci);
return 0;
}
+/* Make sure the controller is quiescent and that we're not using it
+ * any more. This is mainly for the benefit of programs which, like kexec,
+ * expect the hardware to be idle: not doing DMA or generating IRQs.
+ *
+ * This routine may be called in a damaged or failing kernel. Hence we
+ * do not acquire the spinlock before shutting down the controller.
+ */
+static void uhci_shutdown(struct pci_dev *pdev)
+{
+ struct usb_hcd *hcd = (struct usb_hcd *) pci_get_drvdata(pdev);
+
+ hc_died(hcd_to_uhci(hcd));
+}
+
/*
* Allocate a frame list, and then setup the skeleton
*
@@ -478,17 +560,20 @@ static int uhci_start(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int retval = -EBUSY;
- int i, port;
- unsigned io_size;
+ int i;
dma_addr_t dma_handle;
- struct usb_device *udev;
struct dentry *dentry;
- io_size = (unsigned) hcd->rsrc_len;
+ hcd->uses_new_polling = 1;
+ if (pci_find_capability(to_pci_dev(uhci_dev(uhci)), PCI_CAP_ID_PM))
+ hcd->can_wakeup = 1; /* Assume it supports PME# */
- dentry = debugfs_create_file(hcd->self.bus_name, S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci, &uhci_debug_operations);
+ dentry = debugfs_create_file(hcd->self.bus_name,
+ S_IFREG|S_IRUGO|S_IWUSR, uhci_debugfs_root, uhci,
+ &uhci_debug_operations);
if (!dentry) {
- dev_err(uhci_dev(uhci), "couldn't create uhci debugfs entry\n");
+ dev_err(uhci_dev(uhci),
+ "couldn't create uhci debugfs entry\n");
retval = -ENOMEM;
goto err_create_debug_entry;
}
@@ -510,6 +595,10 @@ static int uhci_start(struct usb_hcd *hcd)
init_waitqueue_head(&uhci->waitqh);
+ init_timer(&uhci->stall_timer);
+ uhci->stall_timer.function = stall_callback;
+ uhci->stall_timer.data = (unsigned long) uhci;
+
uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
&dma_handle, 0);
if (!uhci->fl) {
@@ -536,46 +625,14 @@ static int uhci_start(struct usb_hcd *hcd)
goto err_create_qh_pool;
}
- /* Initialize the root hub */
-
- /* UHCI specs says devices must have 2 ports, but goes on to say */
- /* they may have more but give no way to determine how many they */
- /* have. However, according to the UHCI spec, Bit 7 is always set */
- /* to 1. So we try to use this to our advantage */
- for (port = 0; port < (io_size - 0x10) / 2; port++) {
- unsigned int portstatus;
-
- portstatus = inw(uhci->io_addr + 0x10 + (port * 2));
- if (!(portstatus & 0x0080))
- break;
- }
- if (debug)
- dev_info(uhci_dev(uhci), "detected %d ports\n", port);
-
- /* This is experimental so anything less than 2 or greater than 8 is */
- /* something weird and we'll ignore it */
- if (port < 2 || port > UHCI_RH_MAXCHILD) {
- dev_info(uhci_dev(uhci), "port count misdetected? "
- "forcing to 2 ports\n");
- port = 2;
- }
-
- uhci->rh_numports = port;
-
- udev = usb_alloc_dev(NULL, &hcd->self, 0);
- if (!udev) {
- dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
- goto err_alloc_root_hub;
- }
-
- uhci->term_td = uhci_alloc_td(uhci, udev);
+ uhci->term_td = uhci_alloc_td(uhci);
if (!uhci->term_td) {
dev_err(uhci_dev(uhci), "unable to allocate terminating TD\n");
goto err_alloc_term_td;
}
for (i = 0; i < UHCI_NUM_SKELQH; i++) {
- uhci->skelqh[i] = uhci_alloc_qh(uhci, udev);
+ uhci->skelqh[i] = uhci_alloc_qh(uhci);
if (!uhci->skelqh[i]) {
dev_err(uhci_dev(uhci), "unable to allocate QH\n");
goto err_alloc_skelqh;
@@ -641,32 +698,17 @@ static int uhci_start(struct usb_hcd *hcd)
/*
* Some architectures require a full mb() to enforce completion of
- * the memory writes above before the I/O transfers in start_hc().
+ * the memory writes above before the I/O transfers in configure_hc().
*/
mb();
- if ((retval = start_hc(uhci)) != 0)
- goto err_alloc_skelqh;
-
- init_stall_timer(hcd);
-
- udev->speed = USB_SPEED_FULL;
-
- if (usb_hcd_register_root_hub(udev, hcd) != 0) {
- dev_err(uhci_dev(uhci), "unable to start root hub\n");
- retval = -ENOMEM;
- goto err_start_root_hub;
- }
+ configure_hc(uhci);
+ start_rh(uhci);
return 0;
/*
* error exits:
*/
-err_start_root_hub:
- reset_hc(uhci);
-
- del_timer_sync(&uhci->stall_timer);
-
err_alloc_skelqh:
for (i = 0; i < UHCI_NUM_SKELQH; i++)
if (uhci->skelqh[i]) {
@@ -678,9 +720,6 @@ err_alloc_skelqh:
uhci->term_td = NULL;
err_alloc_term_td:
- usb_put_dev(udev);
-
-err_alloc_root_hub:
dma_pool_destroy(uhci->qh_pool);
uhci->qh_pool = NULL;
@@ -705,73 +744,114 @@ static void uhci_stop(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- del_timer_sync(&uhci->stall_timer);
- reset_hc(uhci);
-
spin_lock_irq(&uhci->lock);
+ reset_hc(uhci);
uhci_scan_schedule(uhci, NULL);
spin_unlock_irq(&uhci->lock);
-
+
+ del_timer_sync(&uhci->stall_timer);
release_uhci(uhci);
}
#ifdef CONFIG_PM
+static int uhci_rh_suspend(struct usb_hcd *hcd)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+
+ spin_lock_irq(&uhci->lock);
+ if (!uhci->hc_inaccessible) /* Not dead */
+ suspend_rh(uhci, UHCI_RH_SUSPENDED);
+ spin_unlock_irq(&uhci->lock);
+ return 0;
+}
+
+static int uhci_rh_resume(struct usb_hcd *hcd)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ int rc = 0;
+
+ spin_lock_irq(&uhci->lock);
+ if (uhci->hc_inaccessible) {
+ if (uhci->rh_state == UHCI_RH_SUSPENDED) {
+ dev_warn(uhci_dev(uhci), "HC isn't running!\n");
+ rc = -ENODEV;
+ }
+ /* Otherwise the HC is dead */
+ } else
+ wakeup_rh(uhci);
+ spin_unlock_irq(&uhci->lock);
+ return rc;
+}
+
static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ int rc = 0;
+
+ dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
spin_lock_irq(&uhci->lock);
+ if (uhci->hc_inaccessible) /* Dead or already suspended */
+ goto done;
- /* Don't try to suspend broken motherboards, reset instead */
- if (suspend_allowed(uhci))
- suspend_hc(uhci);
- else {
- spin_unlock_irq(&uhci->lock);
- reset_hc(uhci);
- spin_lock_irq(&uhci->lock);
- uhci_scan_schedule(uhci, NULL);
- }
+#ifndef CONFIG_USB_SUSPEND
+ /* Otherwise this would never happen */
+ suspend_rh(uhci, UHCI_RH_SUSPENDED);
+#endif
+
+ if (uhci->rh_state > UHCI_RH_SUSPENDED) {
+ dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
+ hcd->state = HC_STATE_RUNNING;
+ rc = -EBUSY;
+ goto done;
+ };
+ /* All PCI host controllers are required to disable IRQ generation
+ * at the source, so we must turn off PIRQ.
+ */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+ uhci->hc_inaccessible = 1;
+
+ /* FIXME: Enable non-PME# remote wakeup? */
+
+done:
spin_unlock_irq(&uhci->lock);
- return 0;
+ if (rc == 0)
+ del_timer_sync(&hcd->rh_timer);
+ return rc;
}
static int uhci_resume(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int rc;
- pci_set_master(to_pci_dev(uhci_dev(uhci)));
+ dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
+ if (uhci->rh_state == UHCI_RH_RESET) /* Dead */
+ return 0;
spin_lock_irq(&uhci->lock);
- if (uhci->state == UHCI_SUSPENDED) {
+ /* FIXME: Disable non-PME# remote wakeup? */
- /*
- * Some systems don't maintain the UHCI register values
- * during a PM suspend/resume cycle, so reinitialize
- * the Frame Number, Framelist Base Address, Interrupt
- * Enable, and Legacy Support registers.
- */
- pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
- 0);
- outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
- outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
- outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
- USBINTR_SP, uhci->io_addr + USBINTR);
- uhci->resume_detect = 1;
- pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
- USBLEGSUP_DEFAULT);
- } else {
- spin_unlock_irq(&uhci->lock);
- reset_hc(uhci);
- if ((rc = start_hc(uhci)) != 0)
- return rc;
- spin_lock_irq(&uhci->lock);
- }
- hcd->state = HC_STATE_RUNNING;
+ uhci->hc_inaccessible = 0;
+
+ /* The BIOS may have changed the controller settings during a
+ * system wakeup. Check it and reconfigure to avoid problems.
+ */
+ check_and_reset_hc(uhci);
+ configure_hc(uhci);
+
+#ifndef CONFIG_USB_SUSPEND
+ /* Otherwise this would never happen */
+ wakeup_rh(uhci);
+#endif
+ if (uhci->rh_state == UHCI_RH_RESET)
+ suspend_rh(uhci, UHCI_RH_SUSPENDED);
spin_unlock_irq(&uhci->lock);
+
+ if (hcd->poll_rh)
+ usb_hcd_poll_rh_status(hcd);
return 0;
}
#endif
@@ -788,13 +868,15 @@ static void uhci_hcd_endpoint_disable(struct usb_hcd *hcd,
static int uhci_hcd_get_frame_number(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- int frame_number;
unsigned long flags;
+ int is_stopped;
+ int frame_number;
/* Minimize latency by avoiding the spinlock */
local_irq_save(flags);
- rmb();
- frame_number = (uhci->is_stopped ? uhci->frame_number :
+ is_stopped = uhci->is_stopped;
+ smp_rmb();
+ frame_number = (is_stopped ? uhci->frame_number :
inw(uhci->io_addr + USBFRNUM));
local_irq_restore(flags);
return frame_number;
@@ -817,6 +899,8 @@ static const struct hc_driver uhci_driver = {
#ifdef CONFIG_PM
.suspend = uhci_suspend,
.resume = uhci_resume,
+ .hub_suspend = uhci_rh_suspend,
+ .hub_resume = uhci_rh_resume,
#endif
.stop = uhci_stop,
@@ -845,6 +929,7 @@ static struct pci_driver uhci_pci_driver = {
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
+ .shutdown = uhci_shutdown,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 02255d69e1fe..bf9c5f9b508b 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -41,6 +41,7 @@
#define USBFRNUM 6
#define USBFLBASEADD 8
#define USBSOF 12
+#define USBSOF_DEFAULT 64 /* Frame length is exactly 1 ms */
/* USB port status and control registers */
#define USBPORTSC1 16
@@ -66,6 +67,8 @@
/* Legacy support register */
#define USBLEGSUP 0xc0
#define USBLEGSUP_DEFAULT 0x2000 /* only PIRQ enable set */
+#define USBLEGSUP_RWC 0x8f00 /* the R/WC bits */
+#define USBLEGSUP_RO 0x5040 /* R/O and reserved bits */
#define UHCI_NULL_DATA_SIZE 0x7FF /* for UHCI controller TD */
@@ -111,7 +114,6 @@ struct uhci_qh {
/* Software fields */
dma_addr_t dma_handle;
- struct usb_device *dev;
struct urb_priv *urbp;
struct list_head list; /* P: uhci->frame_list_lock */
@@ -203,7 +205,6 @@ struct uhci_td {
/* Software fields */
dma_addr_t dma_handle;
- struct usb_device *dev;
struct urb *urb;
struct list_head list; /* P: urb->lock */
@@ -314,26 +315,32 @@ static inline int __interval_to_skel(int interval)
}
/*
- * Device states for the host controller.
+ * States for the root hub.
*
* To prevent "bouncing" in the presence of electrical noise,
- * we insist on a 1-second "grace" period, before switching to
- * the RUNNING or SUSPENDED states, during which the state is
- * not allowed to change.
- *
- * The resume process is divided into substates in order to avoid
- * potentially length delays during the timer handler.
- *
- * States in which the host controller is halted must have values <= 0.
+ * when there are no devices attached we delay for 1 second in the
+ * RUNNING_NODEVS state before switching to the AUTO_STOPPED state.
+ *
+ * (Note that the AUTO_STOPPED state won't be necessary once the hub
+ * driver learns to autosuspend.)
*/
-enum uhci_state {
- UHCI_RESET,
- UHCI_RUNNING_GRACE, /* Before RUNNING */
- UHCI_RUNNING, /* The normal state */
- UHCI_SUSPENDING_GRACE, /* Before SUSPENDED */
- UHCI_SUSPENDED = -10, /* When no devices are attached */
- UHCI_RESUMING_1,
- UHCI_RESUMING_2
+enum uhci_rh_state {
+ /* In the following states the HC must be halted.
+ * These two must come first */
+ UHCI_RH_RESET,
+ UHCI_RH_SUSPENDED,
+
+ UHCI_RH_AUTO_STOPPED,
+ UHCI_RH_RESUMING,
+
+ /* In this state the HC changes from running to halted,
+ * so it can legally appear either way. */
+ UHCI_RH_SUSPENDING,
+
+ /* In the following states it's an error if the HC is halted.
+ * These two must come last */
+ UHCI_RH_RUNNING, /* The normal state */
+ UHCI_RH_RUNNING_NODEVS, /* Running with no devices attached */
};
/*
@@ -363,15 +370,16 @@ struct uhci_hcd {
int fsbr; /* Full-speed bandwidth reclamation */
unsigned long fsbrtimeout; /* FSBR delay */
- enum uhci_state state; /* FIXME: needs a spinlock */
- unsigned long state_end; /* Time of next transition */
+ enum uhci_rh_state rh_state;
+ unsigned long auto_stop_time; /* When to AUTO_STOP */
+
unsigned int frame_number; /* As of last check */
unsigned int is_stopped;
#define UHCI_IS_STOPPED 9999 /* Larger than a frame # */
unsigned int scan_in_progress:1; /* Schedule scan is running */
unsigned int need_rescan:1; /* Redo the schedule scan */
- unsigned int resume_detect:1; /* Need a Global Resume */
+ unsigned int hc_inaccessible:1; /* HC is suspended or dead */
/* Support for port suspend/resume/reset */
unsigned long port_c_suspend; /* Bit-arrays of ports */
@@ -451,4 +459,11 @@ struct urb_priv {
* #2 urb->lock
*/
+
+/* Some special IDs */
+
+#define PCI_VENDOR_ID_GENESYS 0x17a0
+#define PCI_DEVICE_ID_GL880S_UHCI 0x8083
+#define PCI_DEVICE_ID_GL880S_EHCI 0x8084
+
#endif
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 4c45ba8390f8..4eace2b19ddb 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -33,9 +33,24 @@ static __u8 root_hub_hub_des[] =
/* status change bits: nonzero writes will clear */
#define RWC_BITS (USBPORTSC_OCC | USBPORTSC_PEC | USBPORTSC_CSC)
-static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+/* A port that either is connected or has a changed-bit set will prevent
+ * us from AUTO_STOPPING.
+ */
+static int any_ports_active(struct uhci_hcd *uhci)
+{
+ int port;
+
+ for (port = 0; port < uhci->rh_numports; ++port) {
+ if ((inw(uhci->io_addr + USBPORTSC1 + port * 2) &
+ (USBPORTSC_CCS | RWC_BITS)) ||
+ test_bit(port, &uhci->port_c_suspend))
+ return 1;
+ }
+ return 0;
+}
+
+static inline int get_hub_status_data(struct uhci_hcd *uhci, char *buf)
{
- struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int port;
*buf = 0;
@@ -44,8 +59,6 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
test_bit(port, &uhci->port_c_suspend))
*buf |= (1 << (port + 1));
}
- if (*buf && uhci->state == UHCI_SUSPENDED)
- uhci->resume_detect = 1;
return !!*buf;
}
@@ -115,6 +128,11 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
set_bit(port, &uhci->resuming_ports);
uhci->ports_timeout = jiffies +
msecs_to_jiffies(20);
+
+ /* Make sure we see the port again
+ * after the resuming period is over. */
+ mod_timer(&uhci_to_hcd(uhci)->rh_timer,
+ uhci->ports_timeout);
} else if (time_after_eq(jiffies,
uhci->ports_timeout)) {
uhci_finish_suspend(uhci, port, port_addr);
@@ -123,6 +141,60 @@ static void uhci_check_ports(struct uhci_hcd *uhci)
}
}
+static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct uhci_hcd *uhci = hcd_to_uhci(hcd);
+ unsigned long flags;
+ int status;
+
+ spin_lock_irqsave(&uhci->lock, flags);
+ if (uhci->hc_inaccessible) {
+ status = 0;
+ goto done;
+ }
+
+ uhci_check_ports(uhci);
+ status = get_hub_status_data(uhci, buf);
+
+ switch (uhci->rh_state) {
+ case UHCI_RH_SUSPENDING:
+ case UHCI_RH_SUSPENDED:
+ /* if port change, ask to be resumed */
+ if (status)
+ usb_hcd_resume_root_hub(hcd);
+ break;
+
+ case UHCI_RH_AUTO_STOPPED:
+ /* if port change, auto start */
+ if (status)
+ wakeup_rh(uhci);
+ break;
+
+ case UHCI_RH_RUNNING:
+ /* are any devices attached? */
+ if (!any_ports_active(uhci)) {
+ uhci->rh_state = UHCI_RH_RUNNING_NODEVS;
+ uhci->auto_stop_time = jiffies + HZ;
+ }
+ break;
+
+ case UHCI_RH_RUNNING_NODEVS:
+ /* auto-stop if nothing connected for 1 second */
+ if (any_ports_active(uhci))
+ uhci->rh_state = UHCI_RH_RUNNING;
+ else if (time_after_eq(jiffies, uhci->auto_stop_time))
+ suspend_rh(uhci, UHCI_RH_AUTO_STOPPED);
+ break;
+
+ default:
+ break;
+ }
+
+done:
+ spin_unlock_irqrestore(&uhci->lock, flags);
+ return status;
+}
+
/* size of returned buffer is part of USB spec */
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
@@ -134,6 +206,9 @@ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wPortChange, wPortStatus;
unsigned long flags;
+ if (uhci->hc_inaccessible)
+ return -ETIMEDOUT;
+
spin_lock_irqsave(&uhci->lock, flags);
switch (typeReq) {
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 2a7c19501f24..bbb36cd6ed61 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -32,6 +32,8 @@ static void uhci_free_pending_tds(struct uhci_hcd *uhci);
*/
static inline void uhci_set_next_interrupt(struct uhci_hcd *uhci)
{
+ if (uhci->is_stopped)
+ mod_timer(&uhci->stall_timer, jiffies);
uhci->term_td->status |= cpu_to_le32(TD_CTRL_IOC);
}
@@ -46,7 +48,7 @@ static inline void uhci_moveto_complete(struct uhci_hcd *uhci,
list_move_tail(&urbp->urb_list, &uhci->complete_list);
}
-static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci)
{
dma_addr_t dma_handle;
struct uhci_td *td;
@@ -61,14 +63,11 @@ static struct uhci_td *uhci_alloc_td(struct uhci_hcd *uhci, struct usb_device *d
td->buffer = 0;
td->frame = -1;
- td->dev = dev;
INIT_LIST_HEAD(&td->list);
INIT_LIST_HEAD(&td->remove_list);
INIT_LIST_HEAD(&td->fl_list);
- usb_get_dev(dev);
-
return td;
}
@@ -168,13 +167,10 @@ static void uhci_free_td(struct uhci_hcd *uhci, struct uhci_td *td)
if (!list_empty(&td->fl_list))
dev_warn(uhci_dev(uhci), "td %p still in fl_list!\n", td);
- if (td->dev)
- usb_put_dev(td->dev);
-
dma_pool_free(uhci->td_pool, td, td->dma_handle);
}
-static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *dev)
+static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci)
{
dma_addr_t dma_handle;
struct uhci_qh *qh;
@@ -188,14 +184,11 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci, struct usb_device *d
qh->element = UHCI_PTR_TERM;
qh->link = UHCI_PTR_TERM;
- qh->dev = dev;
qh->urbp = NULL;
INIT_LIST_HEAD(&qh->list);
INIT_LIST_HEAD(&qh->remove_list);
- usb_get_dev(dev);
-
return qh;
}
@@ -206,9 +199,6 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
if (!list_empty(&qh->remove_list))
dev_warn(uhci_dev(uhci), "qh %p still in remove_list!\n", qh);
- if (qh->dev)
- usb_put_dev(qh->dev);
-
dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
}
@@ -597,7 +587,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
/*
* Build the TD for the control request setup packet
*/
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -626,7 +616,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
if (pktsze > maxsze)
pktsze = maxsze;
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -644,7 +634,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
/*
* Build the final TD for control status
*/
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -666,7 +656,7 @@ static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct ur
uhci_fill_td(td, status | TD_CTRL_IOC,
destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);
- qh = uhci_alloc_qh(uhci, urb->dev);
+ qh = uhci_alloc_qh(uhci);
if (!qh)
return -ENOMEM;
@@ -865,7 +855,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
status &= ~TD_CTRL_SPD;
}
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -891,7 +881,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
*/
if (usb_pipeout(urb->pipe) && (urb->transfer_flags & URB_ZERO_PACKET) &&
!len && urb->transfer_buffer_length) {
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -913,7 +903,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb
* flag setting. */
td->status |= cpu_to_le32(TD_CTRL_IOC);
- qh = uhci_alloc_qh(uhci, urb->dev);
+ qh = uhci_alloc_qh(uhci);
if (!qh)
return -ENOMEM;
@@ -1096,7 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
if (!urb->iso_frame_desc[i].length)
continue;
- td = uhci_alloc_td(uhci, urb->dev);
+ td = uhci_alloc_td(uhci);
if (!td)
return -ENOMEM;
@@ -1174,7 +1164,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 usb_host_endpoint *ep,
- struct urb *urb, int mem_flags)
+ struct urb *urb, unsigned mem_flags)
{
int ret;
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@@ -1497,6 +1487,7 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
rescan:
uhci->need_rescan = 0;
+ uhci_clear_next_interrupt(uhci);
uhci_get_current_frame_number(uhci);
if (uhci->frame_number + uhci->is_stopped != uhci->qh_remove_age)
@@ -1537,3 +1528,26 @@ static void uhci_scan_schedule(struct uhci_hcd *uhci, struct pt_regs *regs)
/* Wake up anyone waiting for an URB to complete */
wake_up_all(&uhci->waitqh);
}
+
+static void check_fsbr(struct uhci_hcd *uhci)
+{
+ struct urb_priv *up;
+
+ list_for_each_entry(up, &uhci->urb_list, urb_list) {
+ struct urb *u = up->urb;
+
+ spin_lock(&u->lock);
+
+ /* Check if the FSBR timed out */
+ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT))
+ uhci_fsbr_timeout(uhci, u);
+
+ spin_unlock(&u->lock);
+ }
+
+ /* Really disable FSBR */
+ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) {
+ uhci->fsbrtimeout = 0;
+ uhci->skel_term_qh->link = UHCI_PTR_TERM;
+ }
+}
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index d28e7eab6f98..298e4a25e3d3 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -151,6 +151,18 @@ config USB_WACOM
To compile this driver as a module, choose M here: the
module will be called wacom.
+config USB_ACECAD
+ tristate "Acecad Flair tablet support"
+ depends on USB && INPUT
+ help
+ Say Y here if you want to use the USB version of the Acecad Flair
+ tablet. Make sure to say Y to "Mouse support"
+ (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+ (CONFIG_INPUT_EVDEV) as well.
+
+ To compile this driver as a module, choose M here: the
+ module will be called acecad.
+
config USB_KBTAB
tristate "KB Gear JamStudio tablet support"
depends on USB && INPUT
@@ -190,6 +202,18 @@ config USB_MTOUCH
To compile this driver as a module, choose M here: the
module will be called mtouchusb.
+config USB_ITMTOUCH
+ tristate "ITM Touch USB Touchscreen Driver"
+ depends on USB && INPUT
+ ---help---
+ Say Y here if you want to use a ITM Touch USB
+ Touchscreen controller.
+
+ This touchscreen is used in LG 1510SF monitors.
+
+ To compile this driver as a module, choose M here: the
+ module will be called itmtouch.
+
config USB_EGALAX
tristate "eGalax TouchKit USB Touchscreen Driver"
depends on USB && INPUT
@@ -235,3 +259,16 @@ config USB_ATI_REMOTE
To compile this driver as a module, choose M here: the module will be
called ati_remote.
+config USB_KEYSPAN_REMOTE
+ tristate "Keyspan DMR USB remote control (EXPERIMENTAL)"
+ depends on USB && INPUT && EXPERIMENTAL
+ ---help---
+ Say Y here if you want to use a Keyspan DMR USB remote control.
+ Currently only the UIA-11 type of receiver has been tested. The tag
+ on the receiver that connects to the USB port should have a P/N that
+ will tell you what type of DMR you have. The UIA-10 type is not
+ supported at this time. This driver maps all buttons to keypress
+ events.
+
+ To compile this driver as a module, choose M here: the module will
+ be called keyspan_remote.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index 6bcedd16b0a1..f1547be632d4 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -31,9 +31,12 @@ obj-$(CONFIG_USB_ATI_REMOTE) += ati_remote.o
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
obj-$(CONFIG_USB_KBTAB) += kbtab.o
+obj-$(CONFIG_USB_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_USB_MOUSE) += usbmouse.o
obj-$(CONFIG_USB_MTOUCH) += mtouchusb.o
+obj-$(CONFIG_USB_ITMTOUCH) += itmtouch.o
obj-$(CONFIG_USB_EGALAX) += touchkitusb.o
obj-$(CONFIG_USB_POWERMATE) += powermate.o
obj-$(CONFIG_USB_WACOM) += wacom.o
+obj-$(CONFIG_USB_ACECAD) += acecad.o
obj-$(CONFIG_USB_XPAD) += xpad.o
diff --git a/drivers/usb/input/acecad.c b/drivers/usb/input/acecad.c
new file mode 100644
index 000000000000..ebcf7c955800
--- /dev/null
+++ b/drivers/usb/input/acecad.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2001-2005 Edouard TISSERANT <edouard.tisserant@wanadoo.fr>
+ * Copyright (c) 2004-2005 Stephane VOLTZ <svoltz@numericable.fr>
+ *
+ * USB Acecad "Acecad Flair" tablet support
+ *
+ * Changelog:
+ * v3.2 - Added sysfs 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 <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION "v3.2"
+#define DRIVER_DESC "USB Acecad Flair tablet driver"
+#define DRIVER_LICENSE "GPL"
+#define DRIVER_AUTHOR "Edouard TISSERANT <edouard.tisserant@wanadoo.fr>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
+
+#define USB_VENDOR_ID_ACECAD 0x0460
+#define USB_DEVICE_ID_FLAIR 0x0004
+#define USB_DEVICE_ID_302 0x0008
+
+struct usb_acecad {
+ char name[128];
+ char phys[64];
+ struct usb_device *usbdev;
+ struct input_dev dev;
+ struct urb *irq;
+
+ signed char *data;
+ dma_addr_t data_dma;
+};
+
+static void usb_acecad_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_acecad *acecad = urb->context;
+ unsigned char *data = acecad->data;
+ struct input_dev *dev = &acecad->dev;
+ int prox, status;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ goto resubmit;
+ }
+
+ prox = (data[0] & 0x04) >> 2;
+ input_report_key(dev, BTN_TOOL_PEN, prox);
+
+ if (prox) {
+ int x = data[1] | (data[2] << 8);
+ int y = data[3] | (data[4] << 8);
+ /*Pressure should compute the same way for flair and 302*/
+ int pressure = data[5] | ((int)data[6] << 8);
+ int touch = data[0] & 0x01;
+ int stylus = (data[0] & 0x10) >> 4;
+ int stylus2 = (data[0] & 0x20) >> 5;
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ input_report_abs(dev, ABS_PRESSURE, pressure);
+ input_report_key(dev, BTN_TOUCH, touch);
+ input_report_key(dev, BTN_STYLUS, stylus);
+ input_report_key(dev, BTN_STYLUS2, stylus2);
+ }
+
+ /* event termination */
+ input_sync(dev);
+
+resubmit:
+ status = usb_submit_urb (urb, GFP_ATOMIC);
+ if (status)
+ err ("can't resubmit intr, %s-%s/input0, status %d",
+ acecad->usbdev->bus->bus_name, acecad->usbdev->devpath, status);
+}
+
+static int usb_acecad_open(struct input_dev *dev)
+{
+ struct usb_acecad *acecad = dev->private;
+
+ acecad->irq->dev = acecad->usbdev;
+ if (usb_submit_urb(acecad->irq, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void usb_acecad_close(struct input_dev *dev)
+{
+ struct usb_acecad *acecad = dev->private;
+
+ usb_kill_urb(acecad->irq);
+}
+
+static int usb_acecad_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_acecad *acecad;
+ int pipe, maxp;
+ char path[64];
+
+ if (interface->desc.bNumEndpoints != 1)
+ return -ENODEV;
+
+ endpoint = &interface->endpoint[0].desc;
+
+ if (!(endpoint->bEndpointAddress & 0x80))
+ return -ENODEV;
+
+ if ((endpoint->bmAttributes & 3) != 3)
+ return -ENODEV;
+
+ pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ acecad = kcalloc(1, sizeof(struct usb_acecad), GFP_KERNEL);
+ if (!acecad)
+ return -ENOMEM;
+
+ acecad->data = usb_buffer_alloc(dev, 8, SLAB_KERNEL, &acecad->data_dma);
+ if (!acecad->data)
+ goto fail1;
+
+ acecad->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!acecad->irq)
+ goto fail2;
+
+ if (dev->manufacturer)
+ strlcpy(acecad->name, dev->manufacturer, sizeof(acecad->name));
+
+ if (dev->product) {
+ if (dev->manufacturer)
+ strlcat(acecad->name, " ", sizeof(acecad->name));
+ strlcat(acecad->name, dev->product, sizeof(acecad->name));
+ }
+
+ usb_make_path(dev, path, sizeof(path));
+ snprintf(acecad->phys, sizeof(acecad->phys), "%s/input0", path);
+
+ acecad->usbdev = dev;
+
+ acecad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ acecad->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ acecad->dev.keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
+ acecad->dev.keybit[LONG(BTN_DIGI)] = BIT(BTN_TOOL_PEN) |BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2);
+
+ switch (id->driver_info) {
+ case 0:
+ acecad->dev.absmax[ABS_X] = 5000;
+ acecad->dev.absmax[ABS_Y] = 3750;
+ acecad->dev.absmax[ABS_PRESSURE] = 512;
+ if (!strlen(acecad->name))
+ snprintf(acecad->name, sizeof(acecad->name),
+ "USB Acecad Flair Tablet %04x:%04x",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ break;
+ case 1:
+ acecad->dev.absmax[ABS_X] = 3000;
+ acecad->dev.absmax[ABS_Y] = 2250;
+ acecad->dev.absmax[ABS_PRESSURE] = 1024;
+ if (!strlen(acecad->name))
+ snprintf(acecad->name, sizeof(acecad->name),
+ "USB Acecad 302 Tablet %04x:%04x",
+ dev->descriptor.idVendor, dev->descriptor.idProduct);
+ break;
+ }
+
+ acecad->dev.absfuzz[ABS_X] = 4;
+ acecad->dev.absfuzz[ABS_Y] = 4;
+
+ acecad->dev.private = acecad;
+ acecad->dev.open = usb_acecad_open;
+ acecad->dev.close = usb_acecad_close;
+
+ acecad->dev.name = acecad->name;
+ acecad->dev.phys = acecad->phys;
+ acecad->dev.id.bustype = BUS_USB;
+ acecad->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
+ acecad->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
+ acecad->dev.id.version = le16_to_cpu(dev->descriptor.bcdDevice);
+ acecad->dev.dev = &intf->dev;
+
+ usb_fill_int_urb(acecad->irq, dev, pipe,
+ acecad->data, maxp > 8 ? 8 : maxp,
+ usb_acecad_irq, acecad, endpoint->bInterval);
+ acecad->irq->transfer_dma = acecad->data_dma;
+ acecad->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ input_register_device(&acecad->dev);
+
+ printk(KERN_INFO "input: %s with packet size %d on %s\n",
+ acecad->name, maxp, path);
+
+ usb_set_intfdata(intf, acecad);
+
+ return 0;
+
+ fail2: usb_buffer_free(dev, 8, acecad->data, acecad->data_dma);
+ fail1: kfree(acecad);
+ return -ENOMEM;
+}
+
+static void usb_acecad_disconnect(struct usb_interface *intf)
+{
+ struct usb_acecad *acecad = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+ if (acecad) {
+ usb_kill_urb(acecad->irq);
+ input_unregister_device(&acecad->dev);
+ usb_free_urb(acecad->irq);
+ usb_buffer_free(interface_to_usbdev(intf), 10, acecad->data, acecad->data_dma);
+ kfree(acecad);
+ }
+}
+
+static struct usb_device_id usb_acecad_id_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_FLAIR), .driver_info = 0 },
+ { USB_DEVICE(USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_302), .driver_info = 1 },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, usb_acecad_id_table);
+
+static struct usb_driver usb_acecad_driver = {
+ .owner = THIS_MODULE,
+ .name = "usb_acecad",
+ .probe = usb_acecad_probe,
+ .disconnect = usb_acecad_disconnect,
+ .id_table = usb_acecad_id_table,
+};
+
+static int __init usb_acecad_init(void)
+{
+ int result = usb_register(&usb_acecad_driver);
+ if (result == 0)
+ info(DRIVER_VERSION ":" DRIVER_DESC);
+ return result;
+}
+
+static void __exit usb_acecad_exit(void)
+{
+ usb_deregister(&usb_acecad_driver);
+}
+
+module_init(usb_acecad_init);
+module_exit(usb_acecad_exit);
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index e991f7ed7330..6bb0f25e8e93 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -1,7 +1,7 @@
/*
* Native support for the Aiptek HyperPen USB Tablets
* (4000U/5000U/6000U/8000U/12000U)
- *
+ *
* Copyright (c) 2001 Chris Atenasio <chris@crud.net>
* Copyright (c) 2002-2004 Bryan W. Headley <bwheadley@earthlink.net>
*
@@ -31,7 +31,7 @@
* - Added support for the sysfs interface, deprecating the
* procfs interface for 2.5.x kernel. Also added support for
* Wheel command. Bryan W. Headley July-15-2003.
- * v1.2 - Reworked jitter timer as a kernel thread.
+ * v1.2 - Reworked jitter timer as a kernel thread.
* Bryan W. Headley November-28-2003/Jan-10-2004.
* v1.3 - Repaired issue of kernel thread going nuts on single-processor
* machines, introduced programmableDelay as a command line
@@ -49,10 +49,10 @@
* NOTE:
* This kernel driver is augmented by the "Aiptek" XFree86 input
* driver for your X server, as well as the Gaiptek GUI Front-end
- * "Tablet Manager".
- * These three products are highly interactive with one another,
+ * "Tablet Manager".
+ * These three products are highly interactive with one another,
* so therefore it's easier to document them all as one subsystem.
- * Please visit the project's "home page", located at,
+ * Please visit the project's "home page", located at,
* http://aiptektablet.sourceforge.net.
*
* This program is free software; you can redistribute it and/or modify
@@ -156,7 +156,7 @@
* Command/Data Description Return Bytes Return Value
* 0x10/0x00 SwitchToMouse 0
* 0x10/0x01 SwitchToTablet 0
- * 0x18/0x04 SetResolution 0
+ * 0x18/0x04 SetResolution 0
* 0x12/0xFF AutoGainOn 0
* 0x17/0x00 FilterOn 0
* 0x01/0x00 GetXExtension 2 MaxX
@@ -247,7 +247,7 @@
#define AIPTEK_DIAGNOSTIC_SENDING_ABSOLUTE_IN_RELATIVE 2
#define AIPTEK_DIAGNOSTIC_TOOL_DISALLOWED 3
- /* Time to wait (in ms) to help mask hand jittering
+ /* Time to wait (in ms) to help mask hand jittering
* when pressing the stylus buttons.
*/
#define AIPTEK_JITTER_DELAY_DEFAULT 50
@@ -324,7 +324,6 @@ struct aiptek {
struct aiptek_settings curSetting; /* tablet's current programmable */
struct aiptek_settings newSetting; /* ... and new param settings */
unsigned int ifnum; /* interface number for IO */
- int openCount; /* module use counter */
int diagnostic; /* tablet diagnostic codes */
unsigned long eventCount; /* event count */
int inDelay; /* jitter: in jitter delay? */
@@ -791,7 +790,7 @@ exit:
* specific Aiptek model numbers, because there has been overlaps,
* use, and reuse of id's in existing models. Certain models have
* been known to use more than one ID, indicative perhaps of
- * manufacturing revisions. In any event, we consider these
+ * manufacturing revisions. In any event, we consider these
* IDs to not be model-specific nor unique.
*/
static const struct usb_device_id aiptek_ids[] = {
@@ -814,15 +813,9 @@ static int aiptek_open(struct input_dev *inputdev)
{
struct aiptek *aiptek = inputdev->private;
- if (aiptek->openCount++ > 0) {
- return 0;
- }
-
aiptek->urb->dev = aiptek->usbdev;
- if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) {
- aiptek->openCount--;
+ if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0)
return -EIO;
- }
return 0;
}
@@ -834,13 +827,11 @@ static void aiptek_close(struct input_dev *inputdev)
{
struct aiptek *aiptek = inputdev->private;
- if (--aiptek->openCount == 0) {
- usb_kill_urb(aiptek->urb);
- }
+ usb_kill_urb(aiptek->urb);
}
/***********************************************************************
- * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
+ * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x,
* where they were known as usb_set_report and usb_get_report.
*/
static int
@@ -2252,7 +2243,6 @@ static void aiptek_disconnect(struct usb_interface *intf)
AIPTEK_PACKET_LENGTH,
aiptek->data, aiptek->data_dma);
kfree(aiptek);
- aiptek = NULL;
}
}
diff --git a/drivers/usb/input/ati_remote.c b/drivers/usb/input/ati_remote.c
index 860df26323b1..654ac454744d 100644
--- a/drivers/usb/input/ati_remote.c
+++ b/drivers/usb/input/ati_remote.c
@@ -1,15 +1,15 @@
-/*
+/*
* USB ATI Remote support
*
* Version 2.2.0 Copyright (c) 2004 Torrey Hoffman <thoffman@arnor.net>
* Version 2.1.1 Copyright (c) 2002 Vladimir Dergachev
*
* This 2.2.0 version is a rewrite / cleanup of the 2.1.1 driver, including
- * porting to the 2.6 kernel interfaces, along with other modification
+ * porting to the 2.6 kernel interfaces, along with other modification
* to better match the style of the existing usb/input drivers. However, the
* protocol and hardware handling is essentially unchanged from 2.1.1.
- *
- * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
+ *
+ * The 2.1.1 driver was derived from the usbati_remote and usbkbd drivers by
* Vojtech Pavlik.
*
* Changes:
@@ -23,64 +23,64 @@
* Added support for the "Lola" remote contributed by:
* Seth Cohn <sethcohn@yahoo.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
+ * 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
- *
- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Hardware & software notes
*
- * These remote controls are distributed by ATI as part of their
- * "All-In-Wonder" video card packages. The receiver self-identifies as a
+ * These remote controls are distributed by ATI as part of their
+ * "All-In-Wonder" video card packages. The receiver self-identifies as a
* "USB Receiver" with manufacturer "X10 Wireless Technology Inc".
*
- * The "Lola" remote is available from X10. See:
+ * The "Lola" remote is available from X10. See:
* http://www.x10.com/products/lola_sg1.htm
* The Lola is similar to the ATI remote but has no mouse support, and slightly
* different keys.
*
- * It is possible to use multiple receivers and remotes on multiple computers
+ * It is possible to use multiple receivers and remotes on multiple computers
* simultaneously by configuring them to use specific channels.
- *
- * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
- * Actually, it may even support more, at least in some revisions of the
+ *
+ * The RF protocol used by the remote supports 16 distinct channels, 1 to 16.
+ * Actually, it may even support more, at least in some revisions of the
* hardware.
*
* Each remote can be configured to transmit on one channel as follows:
- * - Press and hold the "hand icon" button.
- * - When the red LED starts to blink, let go of the "hand icon" button.
- * - When it stops blinking, input the channel code as two digits, from 01
+ * - Press and hold the "hand icon" button.
+ * - When the red LED starts to blink, let go of the "hand icon" button.
+ * - When it stops blinking, input the channel code as two digits, from 01
* to 16, and press the hand icon again.
- *
+ *
* The timing can be a little tricky. Try loading the module with debug=1
* to have the kernel print out messages about the remote control number
* and mask. Note: debugging prints remote numbers as zero-based hexadecimal.
*
* The driver has a "channel_mask" parameter. This bitmask specifies which
- * channels will be ignored by the module. To mask out channels, just add
+ * channels will be ignored by the module. To mask out channels, just add
* all the 2^channel_number values together.
*
* For instance, set channel_mask = 2^4 = 16 (binary 10000) to make ati_remote
- * ignore signals coming from remote controls transmitting on channel 4, but
+ * ignore signals coming from remote controls transmitting on channel 4, but
* accept all other channels.
*
- * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
+ * Or, set channel_mask = 65533, (0xFFFD), and all channels except 1 will be
* ignored.
*
- * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
+ * The default is 0 (respond to all channels). Bit 0 and bits 17-32 of this
* parameter are unused.
*
*/
@@ -99,13 +99,13 @@
/*
* Module and Version Information, Module Parameters
*/
-
-#define ATI_REMOTE_VENDOR_ID 0x0bc7
-#define ATI_REMOTE_PRODUCT_ID 0x004
-#define LOLA_REMOTE_PRODUCT_ID 0x002
+
+#define ATI_REMOTE_VENDOR_ID 0x0bc7
+#define ATI_REMOTE_PRODUCT_ID 0x004
+#define LOLA_REMOTE_PRODUCT_ID 0x002
#define MEDION_REMOTE_PRODUCT_ID 0x006
-#define DRIVER_VERSION "2.2.1"
+#define DRIVER_VERSION "2.2.1"
#define DRIVER_AUTHOR "Torrey Hoffman <thoffman@arnor.net>"
#define DRIVER_DESC "ATI/X10 RF USB Remote Control"
@@ -113,18 +113,18 @@
#define DATA_BUFSIZE 63 /* size of URB data buffers */
#define ATI_INPUTNUM 1 /* Which input device to register as */
-static unsigned long channel_mask = 0;
+static unsigned long channel_mask;
module_param(channel_mask, ulong, 0444);
MODULE_PARM_DESC(channel_mask, "Bitmask of remote control channels to ignore");
-static int debug = 0;
+static int debug;
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)
#undef err
#define err(format, arg...) printk(KERN_ERR format , ## arg)
-
+
static struct usb_device_id ati_remote_table[] = {
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, ATI_REMOTE_PRODUCT_ID) },
{ USB_DEVICE(ATI_REMOTE_VENDOR_ID, LOLA_REMOTE_PRODUCT_ID) },
@@ -148,7 +148,7 @@ static char init2[] = { 0x01, 0x00, 0x20, 0x14, 0x20, 0x20, 0x20 };
/* Acceleration curve for directional control pad */
static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
-/* Duplicate event filtering time.
+/* Duplicate event filtering time.
* Sequential, identical KIND_FILTERED inputs with less than
* FILTER_TIME jiffies between them are considered as repeat
* events. The hardware generates 5 events for the first keypress
@@ -161,10 +161,10 @@ static char accel[] = { 1, 2, 4, 6, 9, 13, 20 };
static DECLARE_MUTEX(disconnect_sem);
struct ati_remote {
- struct input_dev idev;
+ struct input_dev idev;
struct usb_device *udev;
struct usb_interface *interface;
-
+
struct urb *irq_urb;
struct urb *out_urb;
struct usb_endpoint_descriptor *endpoint_in;
@@ -174,13 +174,11 @@ struct ati_remote {
dma_addr_t inbuf_dma;
dma_addr_t outbuf_dma;
- int open; /* open counter */
-
unsigned char old_data[2]; /* Detect duplicate events */
unsigned long old_jiffies;
unsigned long acc_jiffies; /* handle acceleration */
unsigned int repeat_count;
-
+
char name[NAME_BUFSIZE];
char phys[NAME_BUFSIZE];
@@ -206,14 +204,14 @@ static struct
int type;
unsigned int code;
int value;
-} ati_remote_tbl[] =
+} ati_remote_tbl[] =
{
/* Directional control pad axes */
{KIND_ACCEL, 0x35, 0x70, EV_REL, REL_X, -1}, /* left */
{KIND_ACCEL, 0x36, 0x71, EV_REL, REL_X, 1}, /* right */
{KIND_ACCEL, 0x37, 0x72, EV_REL, REL_Y, -1}, /* up */
{KIND_ACCEL, 0x38, 0x73, EV_REL, REL_Y, 1}, /* down */
- /* Directional control pad diagonals */
+ /* Directional control pad diagonals */
{KIND_LU, 0x39, 0x74, EV_REL, 0, 0}, /* left up */
{KIND_RU, 0x3a, 0x75, EV_REL, 0, 0}, /* right up */
{KIND_LD, 0x3c, 0x77, EV_REL, 0, 0}, /* left down */
@@ -225,7 +223,7 @@ static struct
{KIND_LITERAL, 0x41, 0x7c, EV_KEY, BTN_RIGHT, 1},/* right btn down */
{KIND_LITERAL, 0x42, 0x7d, EV_KEY, BTN_RIGHT, 0},/* right btn up */
- /* Artificial "doubleclick" events are generated by the hardware.
+ /* Artificial "doubleclick" events are generated by the hardware.
* They are mapped to the "side" and "extra" mouse buttons here. */
{KIND_FILTERED, 0x3f, 0x7a, EV_KEY, BTN_SIDE, 1}, /* left dblclick */
{KIND_FILTERED, 0x43, 0x7e, EV_KEY, BTN_EXTRA, 1},/* right dblclick */
@@ -273,15 +271,15 @@ static struct
{KIND_FILTERED, 0xea, 0x25, EV_KEY, KEY_PLAY, 1}, /* ( >) */
{KIND_FILTERED, 0xe9, 0x24, EV_KEY, KEY_REWIND, 1}, /* (<<) */
{KIND_FILTERED, 0xeb, 0x26, EV_KEY, KEY_FORWARD, 1}, /* (>>) */
- {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */
+ {KIND_FILTERED, 0xed, 0x28, EV_KEY, KEY_STOP, 1}, /* ([]) */
{KIND_FILTERED, 0xee, 0x29, EV_KEY, KEY_PAUSE, 1}, /* ('') */
{KIND_FILTERED, 0xf0, 0x2b, EV_KEY, KEY_PREVIOUS, 1}, /* (<-) */
{KIND_FILTERED, 0xef, 0x2a, EV_KEY, KEY_NEXT, 1}, /* (>+) */
{KIND_FILTERED, 0xf2, 0x2D, EV_KEY, KEY_INFO, 1}, /* PLAYING */
{KIND_FILTERED, 0xf3, 0x2E, EV_KEY, KEY_HOME, 1}, /* TOP */
{KIND_FILTERED, 0xf4, 0x2F, EV_KEY, KEY_END, 1}, /* END */
- {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */
-
+ {KIND_FILTERED, 0xf5, 0x30, EV_KEY, KEY_SELECT, 1}, /* SELECT */
+
{KIND_END, 0x00, 0x00, EV_MAX + 1, 0, 0}
};
@@ -315,7 +313,7 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
if ((len == 1) && (data[0] != (unsigned char)0xff) && (data[0] != 0x00))
warn("Weird byte 0x%02x", data[0]);
else if (len == 4)
- warn("Weird key %02x %02x %02x %02x",
+ warn("Weird key %02x %02x %02x %02x",
data[0], data[1], data[2], data[3]);
else
warn("Weird data, len=%d %02x %02x %02x %02x %02x %02x ...",
@@ -328,25 +326,16 @@ static void ati_remote_dump(unsigned char *data, unsigned int len)
static int ati_remote_open(struct input_dev *inputdev)
{
struct ati_remote *ati_remote = inputdev->private;
- int retval = 0;
-
- down(&disconnect_sem);
-
- if (ati_remote->open++)
- goto exit;
/* On first open, submit the read urb which was set up previously. */
ati_remote->irq_urb->dev = ati_remote->udev;
if (usb_submit_urb(ati_remote->irq_urb, GFP_KERNEL)) {
- dev_err(&ati_remote->interface->dev,
+ dev_err(&ati_remote->interface->dev,
"%s: usb_submit_urb failed!\n", __FUNCTION__);
- ati_remote->open--;
- retval = -EIO;
+ return -EIO;
}
-exit:
- up(&disconnect_sem);
- return retval;
+ return 0;
}
/*
@@ -355,9 +344,8 @@ exit:
static void ati_remote_close(struct input_dev *inputdev)
{
struct ati_remote *ati_remote = inputdev->private;
-
- if (!--ati_remote->open)
- usb_kill_urb(ati_remote->irq_urb);
+
+ usb_kill_urb(ati_remote->irq_urb);
}
/*
@@ -366,13 +354,13 @@ static void ati_remote_close(struct input_dev *inputdev)
static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
{
struct ati_remote *ati_remote = urb->context;
-
+
if (urb->status) {
dev_dbg(&ati_remote->interface->dev, "%s: status %d\n",
__FUNCTION__, urb->status);
return;
}
-
+
ati_remote->send_flags |= SEND_FLAG_COMPLETE;
wmb();
wake_up(&ati_remote->wait);
@@ -380,16 +368,16 @@ static void ati_remote_irq_out(struct urb *urb, struct pt_regs *regs)
/*
* ati_remote_sendpacket
- *
+ *
* Used to send device initialization strings
*/
static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigned char *data)
{
int retval = 0;
-
+
/* Set up out_urb */
memcpy(ati_remote->out_urb->transfer_buffer + 1, data, LO(cmd));
- ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
+ ((char *) ati_remote->out_urb->transfer_buffer)[0] = HI(cmd);
ati_remote->out_urb->transfer_buffer_length = LO(cmd) + 1;
ati_remote->out_urb->dev = ati_remote->udev;
@@ -397,17 +385,17 @@ static int ati_remote_sendpacket(struct ati_remote *ati_remote, u16 cmd, unsigne
retval = usb_submit_urb(ati_remote->out_urb, GFP_ATOMIC);
if (retval) {
- dev_dbg(&ati_remote->interface->dev,
+ dev_dbg(&ati_remote->interface->dev,
"sendpacket: usb_submit_urb failed: %d\n", retval);
return retval;
}
wait_event_timeout(ati_remote->wait,
((ati_remote->out_urb->status != -EINPROGRESS) ||
- (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
+ (ati_remote->send_flags & SEND_FLAG_COMPLETE)),
HZ);
usb_kill_urb(ati_remote->out_urb);
-
+
return retval;
}
@@ -419,15 +407,15 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
int i;
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++) {
- /*
- * Decide if the table entry matches the remote input.
+ /*
+ * Decide if the table entry matches the remote input.
*/
if ((((ati_remote_tbl[i].data1 & 0x0f) == (d1 & 0x0f))) &&
- ((((ati_remote_tbl[i].data1 >> 4) -
- (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
+ ((((ati_remote_tbl[i].data1 >> 4) -
+ (d1 >> 4) + rem) & 0x0f) == 0x0f) &&
(ati_remote_tbl[i].data2 == d2))
return i;
-
+
}
return -1;
}
@@ -435,16 +423,16 @@ static int ati_remote_event_lookup(int rem, unsigned char d1, unsigned char d2)
/*
* ati_remote_report_input
*/
-static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
+static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
{
struct ati_remote *ati_remote = urb->context;
unsigned char *data= ati_remote->inbuf;
- struct input_dev *dev = &ati_remote->idev;
+ struct input_dev *dev = &ati_remote->idev;
int index, acc;
int remote_num;
-
+
/* Deal with strange looking inputs */
- if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
+ if ( (urb->actual_length != 4) || (data[0] != 0x14) ||
((data[3] & 0x0f) != 0x00) ) {
ati_remote_dump(data, urb->actual_length);
return;
@@ -453,7 +441,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/* Mask unwanted remote channels. */
/* note: remote_num is 0-based, channel 1 on remote == 0 here */
remote_num = (data[3] >> 4) & 0x0f;
- if (channel_mask & (1 << (remote_num + 1))) {
+ if (channel_mask & (1 << (remote_num + 1))) {
dbginfo(&ati_remote->interface->dev,
"Masked input from channel 0x%02x: data %02x,%02x, mask= 0x%02lx\n",
remote_num, data[1], data[2], channel_mask);
@@ -463,37 +451,36 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
/* Look up event code index in translation table */
index = ati_remote_event_lookup(remote_num, data[1], data[2]);
if (index < 0) {
- dev_warn(&ati_remote->interface->dev,
- "Unknown input from channel 0x%02x: data %02x,%02x\n",
+ dev_warn(&ati_remote->interface->dev,
+ "Unknown input from channel 0x%02x: data %02x,%02x\n",
remote_num, data[1], data[2]);
return;
- }
- dbginfo(&ati_remote->interface->dev,
+ }
+ dbginfo(&ati_remote->interface->dev,
"channel 0x%02x; data %02x,%02x; index %d; keycode %d\n",
remote_num, data[1], data[2], index, ati_remote_tbl[index].code);
-
+
if (ati_remote_tbl[index].kind == KIND_LITERAL) {
input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
ati_remote_tbl[index].code,
ati_remote_tbl[index].value);
input_sync(dev);
-
+
ati_remote->old_jiffies = jiffies;
return;
}
-
+
if (ati_remote_tbl[index].kind == KIND_FILTERED) {
/* Filter duplicate events which happen "too close" together. */
- if ((ati_remote->old_data[0] == data[1]) &&
- (ati_remote->old_data[1] == data[2]) &&
- ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
+ if ((ati_remote->old_data[0] == data[1]) &&
+ (ati_remote->old_data[1] == data[2]) &&
+ ((ati_remote->old_jiffies + FILTER_TIME) > jiffies)) {
ati_remote->repeat_count++;
- }
- else {
+ } else {
ati_remote->repeat_count = 0;
}
-
+
ati_remote->old_data[0] = data[1];
ati_remote->old_data[1] = data[2];
ati_remote->old_jiffies = jiffies;
@@ -501,7 +488,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
if ((ati_remote->repeat_count > 0)
&& (ati_remote->repeat_count < 5))
return;
-
+
input_regs(dev, regs);
input_event(dev, ati_remote_tbl[index].type,
@@ -511,13 +498,13 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
input_sync(dev);
return;
- }
-
- /*
+ }
+
+ /*
* Other event kinds are from the directional control pad, and have an
* acceleration factor applied to them. Without this acceleration, the
* control pad is mostly unusable.
- *
+ *
* If elapsed time since last event is > 1/4 second, user "stopped",
* so reset acceleration. Otherwise, user is probably holding the control
* pad down, so we increase acceleration, ramping up over two seconds to
@@ -559,7 +546,7 @@ static void ati_remote_input_report(struct urb *urb, struct pt_regs *regs)
input_report_rel(dev, REL_Y, acc);
break;
default:
- dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
+ dev_dbg(&ati_remote->interface->dev, "ati_remote kind=%d\n",
ati_remote_tbl[index].kind);
}
input_sync(dev);
@@ -586,12 +573,12 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
case -ESHUTDOWN:
dev_dbg(&ati_remote->interface->dev, "%s: urb error status, unlink? \n",
__FUNCTION__);
- return;
+ return;
default: /* error */
- dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
+ dev_dbg(&ati_remote->interface->dev, "%s: Nonzero urb status %d\n",
__FUNCTION__, urb->status);
}
-
+
retval = usb_submit_urb(urb, SLAB_ATOMIC);
if (retval)
dev_err(&ati_remote->interface->dev, "%s: usb_submit_urb()=%d\n",
@@ -603,8 +590,6 @@ static void ati_remote_irq_in(struct urb *urb, struct pt_regs *regs)
*/
static void ati_remote_delete(struct ati_remote *ati_remote)
{
- if (!ati_remote) return;
-
if (ati_remote->irq_urb)
usb_kill_urb(ati_remote->irq_urb);
@@ -614,16 +599,16 @@ static void ati_remote_delete(struct ati_remote *ati_remote)
input_unregister_device(&ati_remote->idev);
if (ati_remote->inbuf)
- usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->inbuf, ati_remote->inbuf_dma);
-
+
if (ati_remote->outbuf)
- usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
+ usb_buffer_free(ati_remote->udev, DATA_BUFSIZE,
ati_remote->outbuf, ati_remote->outbuf_dma);
-
+
if (ati_remote->irq_urb)
usb_free_urb(ati_remote->irq_urb);
-
+
if (ati_remote->out_urb)
usb_free_urb(ati_remote->out_urb);
@@ -636,51 +621,52 @@ static void ati_remote_input_init(struct ati_remote *ati_remote)
int i;
idev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
- idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
+ idev->keybit[LONG(BTN_MOUSE)] = ( BIT(BTN_LEFT) | BIT(BTN_RIGHT) |
BIT(BTN_SIDE) | BIT(BTN_EXTRA) );
idev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
for (i = 0; ati_remote_tbl[i].kind != KIND_END; i++)
if (ati_remote_tbl[i].type == EV_KEY)
set_bit(ati_remote_tbl[i].code, idev->keybit);
-
+
idev->private = ati_remote;
idev->open = ati_remote_open;
idev->close = ati_remote_close;
-
+
idev->name = ati_remote->name;
idev->phys = ati_remote->phys;
-
- idev->id.bustype = BUS_USB;
+
+ idev->id.bustype = BUS_USB;
idev->id.vendor = le16_to_cpu(ati_remote->udev->descriptor.idVendor);
idev->id.product = le16_to_cpu(ati_remote->udev->descriptor.idProduct);
idev->id.version = le16_to_cpu(ati_remote->udev->descriptor.bcdDevice);
+ idev->dev = &(ati_remote->udev->dev);
}
static int ati_remote_initialize(struct ati_remote *ati_remote)
{
struct usb_device *udev = ati_remote->udev;
int pipe, maxp;
-
+
init_waitqueue_head(&ati_remote->wait);
/* Set up irq_urb */
pipe = usb_rcvintpipe(udev, ati_remote->endpoint_in->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
-
- usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
- maxp, ati_remote_irq_in, ati_remote,
+
+ usb_fill_int_urb(ati_remote->irq_urb, udev, pipe, ati_remote->inbuf,
+ maxp, ati_remote_irq_in, ati_remote,
ati_remote->endpoint_in->bInterval);
ati_remote->irq_urb->transfer_dma = ati_remote->inbuf_dma;
ati_remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
+
/* Set up out_urb */
pipe = usb_sndintpipe(udev, ati_remote->endpoint_out->bEndpointAddress);
maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
maxp = (maxp > DATA_BUFSIZE) ? DATA_BUFSIZE : maxp;
- usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
- maxp, ati_remote_irq_out, ati_remote,
+ usb_fill_int_urb(ati_remote->out_urb, udev, pipe, ati_remote->outbuf,
+ maxp, ati_remote_irq_out, ati_remote,
ati_remote->endpoint_out->bInterval);
ati_remote->out_urb->transfer_dma = ati_remote->outbuf_dma;
ati_remote->out_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
@@ -688,11 +674,11 @@ static int ati_remote_initialize(struct ati_remote *ati_remote)
/* send initialization strings */
if ((ati_remote_sendpacket(ati_remote, 0x8004, init1)) ||
(ati_remote_sendpacket(ati_remote, 0x8007, init2))) {
- dev_err(&ati_remote->interface->dev,
+ dev_err(&ati_remote->interface->dev,
"Initializing ati_remote hardware failed.\n");
return 1;
}
-
+
return 0;
}
@@ -769,7 +755,7 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
if (!strlen(ati_remote->name))
sprintf(ati_remote->name, DRIVER_DESC "(%04x,%04x)",
- le16_to_cpu(ati_remote->udev->descriptor.idVendor),
+ le16_to_cpu(ati_remote->udev->descriptor.idVendor),
le16_to_cpu(ati_remote->udev->descriptor.idProduct));
/* Device Hardware Initialization - fills in ati_remote->idev from udev. */
@@ -781,11 +767,11 @@ static int ati_remote_probe(struct usb_interface *interface, const struct usb_de
ati_remote_input_init(ati_remote);
input_register_device(&ati_remote->idev);
- dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
+ dev_info(&ati_remote->interface->dev, "Input registered: %s on %s\n",
ati_remote->name, path);
usb_set_intfdata(interface, ati_remote);
-
+
error:
if (retval)
ati_remote_delete(ati_remote);
@@ -800,18 +786,14 @@ static void ati_remote_disconnect(struct usb_interface *interface)
{
struct ati_remote *ati_remote;
- down(&disconnect_sem);
-
ati_remote = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
if (!ati_remote) {
warn("%s - null device?\n", __FUNCTION__);
return;
}
-
- ati_remote_delete(ati_remote);
- up(&disconnect_sem);
+ ati_remote_delete(ati_remote);
}
/*
@@ -820,7 +802,7 @@ static void ati_remote_disconnect(struct usb_interface *interface)
static int __init ati_remote_init(void)
{
int result;
-
+
result = usb_register(&ati_remote_driver);
if (result)
err("usb_register error #%d\n", result);
@@ -838,8 +820,8 @@ static void __exit ati_remote_exit(void)
usb_deregister(&ati_remote_driver);
}
-/*
- * module specification
+/*
+ * module specification
*/
module_init(ati_remote_init);
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 740dec1f521d..2350e7a5ad70 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -232,7 +232,7 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
report->size += parser->global.report_size * parser->global.report_count;
if (!parser->local.usage_index) /* Ignore padding fields */
- return 0;
+ return 0;
usages = max_t(int, parser->local.usage_index, parser->global.report_count);
@@ -765,7 +765,7 @@ 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((__le64*)report)) >> offset) & ((1 << n) - 1);
+ return (le64_to_cpu(get_unaligned((__le64*)report)) >> offset) & ((1ULL << n) - 1);
}
static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
@@ -1233,6 +1233,13 @@ int hid_wait_io(struct hid_device *hid)
return 0;
}
+static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
+{
+ return usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, (idle << 8) | report,
+ ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
+}
+
static int hid_get_class_descriptor(struct usb_device *dev, int ifnum,
unsigned char type, void *buf, int size)
{
@@ -1301,10 +1308,6 @@ void hid_init_reports(struct hid_device *hid)
if (err)
warn("timeout initializing reports\n");
-
- usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0),
- HID_REQ_SET_IDLE, USB_TYPE_CLASS | USB_RECIP_INTERFACE, 0,
- hid->ifnum, NULL, 0, USB_CTRL_SET_TIMEOUT);
}
#define USB_VENDOR_ID_WACOM 0x056a
@@ -1318,6 +1321,10 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_WACOM_INTUOS3 0x00B0
#define USB_DEVICE_ID_WACOM_CINTIQ 0x003F
+#define USB_VENDOR_ID_ACECAD 0x0460
+#define USB_DEVICE_ID_ACECAD_FLAIR 0x0004
+#define USB_DEVICE_ID_ACECAD_302 0x0008
+
#define USB_VENDOR_ID_KBGEAR 0x084e
#define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001
@@ -1421,6 +1428,19 @@ void hid_init_reports(struct hid_device *hid)
#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+#define USB_VENDOR_ID_LD 0x0f11
+#define USB_DEVICE_ID_CASSY 0x1000
+#define USB_DEVICE_ID_POCKETCASSY 0x1010
+#define USB_DEVICE_ID_MOBILECASSY 0x1020
+#define USB_DEVICE_ID_JWM 0x1080
+#define USB_DEVICE_ID_DMMP 0x1081
+#define USB_DEVICE_ID_UMIP 0x1090
+#define USB_DEVICE_ID_VIDEOCOM 0x1200
+#define USB_DEVICE_ID_COM3LAB 0x2000
+#define USB_DEVICE_ID_TELEPORT 0x2010
+#define USB_DEVICE_ID_NETWORKANALYSER 0x2020
+#define USB_DEVICE_ID_POWERCONTROL 0x2030
+
/*
* Alphabetically sorted blacklist by quirk type.
@@ -1456,6 +1476,17 @@ static struct hid_blacklist {
{ 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_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1024LS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_IGNORE },
@@ -1502,6 +1533,9 @@ static struct hid_blacklist {
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_FLAIR, HID_QUIRK_IGNORE },
+ { USB_VENDOR_ID_ACECAD, USB_DEVICE_ID_ACECAD_302, HID_QUIRK_IGNORE },
+
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
@@ -1590,6 +1624,8 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
return NULL;
}
+ hid_set_idle(dev, interface->desc.bInterfaceNumber, 0, 0);
+
if ((n = hid_get_class_descriptor(dev, interface->desc.bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) {
dbg("reading report descriptor failed");
kfree(rdesc);
@@ -1635,7 +1671,7 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
/* Change the polling interval of mice. */
if (hid->collection->usage == HID_GD_MOUSE && hid_mousepoll_interval > 0)
interval = hid_mousepoll_interval;
-
+
if (endpoint->bEndpointAddress & USB_DIR_IN) {
if (hid->urbin)
continue;
diff --git a/drivers/usb/input/hid-debug.h b/drivers/usb/input/hid-debug.h
index 2b91705740a7..52437e5e2e78 100644
--- a/drivers/usb/input/hid-debug.h
+++ b/drivers/usb/input/hid-debug.h
@@ -67,7 +67,7 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0x44, "Vbry"},
{0, 0x45, "Vbrz"},
{0, 0x46, "Vno"},
- {0, 0x80, "SystemControl"},
+ {0, 0x80, "SystemControl"},
{0, 0x81, "SystemPowerDown"},
{0, 0x82, "SystemSleep"},
{0, 0x83, "SystemWakeUp"},
@@ -347,7 +347,7 @@ __inline__ static void tab(int n) {
static void hid_dump_field(struct hid_field *field, int n) {
int j;
-
+
if (field->physical) {
tab(n);
printk("Physical(");
@@ -408,7 +408,7 @@ static void hid_dump_field(struct hid_field *field, int n) {
printk("%s", units[sys][i]);
if(nibble != 1) {
/* This is a _signed_ nibble(!) */
-
+
int val = nibble & 0x7;
if(nibble & 0x08)
val = -((0x7 & ~val) +1);
@@ -443,7 +443,7 @@ static void __attribute__((unused)) hid_dump_device(struct hid_device *device) {
struct list_head *list;
unsigned i,k;
static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
-
+
for (i = 0; i < HID_REPORT_TYPES; i++) {
report_enum = device->report_enum + i;
list = report_enum->report_list.next;
@@ -664,8 +664,8 @@ static char *keys[KEY_MAX + 1] = {
static char *relatives[REL_MAX + 1] = {
[REL_X] = "X", [REL_Y] = "Y",
[REL_Z] = "Z", [REL_HWHEEL] = "HWheel",
- [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel",
- [REL_MISC] = "Misc",
+ [REL_DIAL] = "Dial", [REL_WHEEL] = "Wheel",
+ [REL_MISC] = "Misc",
};
static char *absolutes[ABS_MAX + 1] = {
@@ -690,9 +690,9 @@ static char *misc[MSC_MAX + 1] = {
};
static char *leds[LED_MAX + 1] = {
- [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
+ [LED_NUML] = "NumLock", [LED_CAPSL] = "CapsLock",
[LED_SCROLLL] = "ScrollLock", [LED_COMPOSE] = "Compose",
- [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
+ [LED_KANA] = "Kana", [LED_SLEEP] = "Sleep",
[LED_SUSPEND] = "Suspend", [LED_MUTE] = "Mute",
[LED_MISC] = "Misc",
};
diff --git a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
index 5553c3553e9d..9ac1e9095334 100644
--- a/drivers/usb/input/hid-input.c
+++ b/drivers/usb/input/hid-input.c
@@ -164,7 +164,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_GD_X: case HID_GD_Y: case HID_GD_Z:
case HID_GD_RX: case HID_GD_RY: case HID_GD_RZ:
case HID_GD_SLIDER: case HID_GD_DIAL: case HID_GD_WHEEL:
- if (field->flags & HID_MAIN_ITEM_RELATIVE)
+ if (field->flags & HID_MAIN_ITEM_RELATIVE)
map_rel(usage->hid & 0xf);
else
map_abs(usage->hid & 0xf);
@@ -297,7 +297,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case HID_UP_MSVENDOR:
goto ignore;
-
+
case HID_UP_PID:
set_bit(EV_FF, input->evbit);
@@ -349,7 +349,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
if ((device->quirks & (HID_QUIRK_2WHEEL_MOUSE_HACK_7 | HID_QUIRK_2WHEEL_MOUSE_HACK_5)) &&
- (usage->type == EV_REL) && (usage->code == REL_WHEEL))
+ (usage->type == EV_REL) && (usage->code == REL_WHEEL))
set_bit(REL_HWHEEL, bit);
if (((device->quirks & HID_QUIRK_2WHEEL_MOUSE_HACK_5) && (usage->hid == 0x00090005))
@@ -365,11 +365,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
a = field->logical_minimum = 0;
b = field->logical_maximum = 255;
}
-
+
if (field->application == HID_GD_GAMEPAD || field->application == HID_GD_JOYSTICK)
input_set_abs_params(input, usage->code, a, b, (b - a) >> 8, (b - a) >> 4);
else input_set_abs_params(input, usage->code, a, b, 0, 0);
-
+
}
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
@@ -420,7 +420,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
- if (usage->hat_min < usage->hat_max || usage->hat_dir) {
+ if (usage->hat_min < usage->hat_max || usage->hat_dir) {
int hat_dir = usage->hat_dir;
if (!hat_dir)
hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1;
@@ -551,7 +551,7 @@ int hidinput_connect(struct hid_device *hid)
for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type == HID_COLLECTION_APPLICATION ||
hid->collection[i].type == HID_COLLECTION_PHYSICAL)
- if (IS_INPUT_APPLICATION(hid->collection[i].usage))
+ if (IS_INPUT_APPLICATION(hid->collection[i].usage))
break;
if (i == hid->maxcollection)
@@ -592,7 +592,7 @@ int hidinput_connect(struct hid_device *hid)
for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
-
+
if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
diff --git a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
index 0d7404bab92f..0c4c77aa31ea 100644
--- a/drivers/usb/input/hid-lgff.c
+++ b/drivers/usb/input/hid-lgff.c
@@ -94,7 +94,7 @@ struct lgff_device {
isn't really necessary */
unsigned long flags[1]; /* Contains various information about the
- state of the driver for this device */
+ state of the driver for this device */
struct timer_list timer;
};
@@ -234,7 +234,7 @@ static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report)
kfree(ret);
return NULL;
}
- memset(ret->field[0]->value, 0, sizeof(s32[8]));
+ memset(ret->field[0]->value, 0, sizeof(s32[8]));
return ret;
}
@@ -295,11 +295,11 @@ static int hid_lgff_event(struct hid_device *hid, struct input_dev* input,
unsigned long flags;
if (type != EV_FF) return -EINVAL;
- if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
+ if (!LGFF_CHECK_OWNERSHIP(code, lgff)) return -EACCES;
if (value < 0) return -EINVAL;
spin_lock_irqsave(&lgff->lock, flags);
-
+
if (value > 0) {
if (test_bit(EFFECT_STARTED, effect->flags)) {
spin_unlock_irqrestore(&lgff->lock, flags);
@@ -345,7 +345,7 @@ static int hid_lgff_flush(struct input_dev *dev, struct file *file)
and perform ioctls on the same fd all at the same time */
if ( current->pid == lgff->effects[i].owner
&& test_bit(EFFECT_USED, lgff->effects[i].flags)) {
-
+
if (hid_lgff_erase(dev, i))
warn("erase effect %d failed", i);
}
@@ -378,7 +378,7 @@ static int hid_lgff_upload_effect(struct input_dev* input,
struct lgff_effect new;
int id;
unsigned long flags;
-
+
dbg("ioctl rumble");
if (!test_bit(effect->type, input->ffbit)) return -EINVAL;
@@ -441,7 +441,7 @@ static void hid_lgff_timer(unsigned long timer_data)
spin_lock_irqsave(&lgff->lock, flags);
- for (i=0; i<LGFF_EFFECTS; ++i) {
+ for (i=0; i<LGFF_EFFECTS; ++i) {
struct lgff_effect* effect = lgff->effects +i;
if (test_bit(EFFECT_PLAYING, effect->flags)) {
@@ -491,7 +491,7 @@ static void hid_lgff_timer(unsigned long timer_data)
set_bit(EFFECT_PLAYING, lgff->effects[i].flags);
}
}
- }
+ }
#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff
@@ -524,5 +524,5 @@ static void hid_lgff_timer(unsigned long timer_data)
add_timer(&lgff->timer);
}
- spin_unlock_irqrestore(&lgff->lock, flags);
+ spin_unlock_irqrestore(&lgff->lock, flags);
}
diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h
index 6d9329c698d9..c1b6b69bc4a4 100644
--- a/drivers/usb/input/hid.h
+++ b/drivers/usb/input/hid.h
@@ -118,7 +118,7 @@ struct hid_item {
#define HID_MAIN_ITEM_CONSTANT 0x001
#define HID_MAIN_ITEM_VARIABLE 0x002
#define HID_MAIN_ITEM_RELATIVE 0x004
-#define HID_MAIN_ITEM_WRAP 0x008
+#define HID_MAIN_ITEM_WRAP 0x008
#define HID_MAIN_ITEM_NONLINEAR 0x010
#define HID_MAIN_ITEM_NO_PREFERRED 0x020
#define HID_MAIN_ITEM_NULL_STATE 0x040
@@ -172,14 +172,14 @@ struct hid_item {
#define HID_USAGE_PAGE 0xffff0000
#define HID_UP_UNDEFINED 0x00000000
-#define HID_UP_GENDESK 0x00010000
-#define HID_UP_KEYBOARD 0x00070000
-#define HID_UP_LED 0x00080000
-#define HID_UP_BUTTON 0x00090000
-#define HID_UP_ORDINAL 0x000a0000
+#define HID_UP_GENDESK 0x00010000
+#define HID_UP_KEYBOARD 0x00070000
+#define HID_UP_LED 0x00080000
+#define HID_UP_BUTTON 0x00090000
+#define HID_UP_ORDINAL 0x000a0000
#define HID_UP_CONSUMER 0x000c0000
-#define HID_UP_DIGITIZER 0x000d0000
-#define HID_UP_PID 0x000f0000
+#define HID_UP_DIGITIZER 0x000d0000
+#define HID_UP_PID 0x000f0000
#define HID_UP_HPVENDOR 0xff7f0000
#define HID_UP_MSVENDOR 0xff000000
@@ -406,7 +406,7 @@ struct hid_device { /* device report descriptor */
dma_addr_t outbuf_dma; /* Output buffer dma */
spinlock_t outlock; /* Output fifo spinlock */
- unsigned claimed; /* Claimed by hidinput, hiddev? */
+ unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
struct list_head inputs; /* The list of inputs */
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index 96b7c9067951..4c13331b5f41 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -95,7 +95,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
return NULL;
rinfo->report_id = ((struct hid_report *) list)->id;
break;
-
+
case HID_REPORT_ID_NEXT:
list = (struct list_head *)
report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
@@ -106,7 +106,7 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
return NULL;
rinfo->report_id = ((struct hid_report *) list)->id;
break;
-
+
default:
return NULL;
}
@@ -158,7 +158,7 @@ static void hiddev_send_event(struct hid_device *hid,
if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) {
list->buffer[list->head] = *uref;
- list->head = (list->head + 1) &
+ list->head = (list->head + 1) &
(HIDDEV_BUFFER_SIZE - 1);
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
@@ -179,9 +179,9 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field,
unsigned type = field->report_type;
struct hiddev_usage_ref uref;
- uref.report_type =
+ uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
- ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+ ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
uref.report_id = field->report->id;
uref.field_index = field->index;
@@ -199,9 +199,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
struct hiddev_usage_ref uref;
memset(&uref, 0, sizeof(uref));
- uref.report_type =
+ uref.report_type =
(type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT :
- ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
+ ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT :
((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0));
uref.report_id = report->id;
uref.field_index = HID_FIELD_INDEX_NONE;
@@ -236,7 +236,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
*listptr = (*listptr)->next;
if (!--list->hiddev->open) {
- if (list->hiddev->exist)
+ if (list->hiddev->exist)
hid_close(list->hiddev->hid);
else
kfree(list->hiddev);
@@ -303,7 +303,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
if (list->head == list->tail) {
add_wait_queue(&list->hiddev->wait, &wait);
set_current_state(TASK_INTERRUPTIBLE);
-
+
while (list->head == list->tail) {
if (file->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
@@ -317,7 +317,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
retval = -EIO;
break;
}
-
+
schedule();
}
@@ -329,7 +329,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun
return retval;
- while (list->head != list->tail &&
+ while (list->head != list->tail &&
retval + event_size <= count) {
if ((list->flags & HIDDEV_FLAG_UREF) == 0) {
if (list->buffer[list->tail].field_index !=
@@ -405,10 +405,10 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -EINVAL;
for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type ==
+ if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && arg-- == 0)
break;
-
+
if (i == hid->maxcollection)
return -EINVAL;
@@ -562,7 +562,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
if (!uref_multi)
return -ENOMEM;
uref = &uref_multi->uref;
- if (copy_from_user(uref, user_arg, sizeof(*uref)))
+ if (copy_from_user(uref, user_arg, sizeof(*uref)))
goto fault;
rinfo.report_type = uref->report_type;
@@ -595,7 +595,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return -ENOMEM;
uref = &uref_multi->uref;
if (cmd == HIDIOCGUSAGES || cmd == HIDIOCSUSAGES) {
- if (copy_from_user(uref_multi, user_arg,
+ if (copy_from_user(uref_multi, user_arg,
sizeof(*uref_multi)))
goto fault;
} else {
@@ -603,7 +603,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
goto fault;
}
- if (cmd != HIDIOCGUSAGE &&
+ if (cmd != HIDIOCGUSAGE &&
cmd != HIDIOCGUSAGES &&
uref->report_type == HID_REPORT_TYPE_INPUT)
goto inval;
@@ -651,16 +651,16 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
return field->usage[uref->usage_index].collection_index;
case HIDIOCGUSAGES:
for (i = 0; i < uref_multi->num_values; i++)
- uref_multi->values[i] =
+ uref_multi->values[i] =
field->value[uref->usage_index + i];
- if (copy_to_user(user_arg, uref_multi,
+ if (copy_to_user(user_arg, uref_multi,
sizeof(*uref_multi)))
goto fault;
goto goodreturn;
case HIDIOCSUSAGES:
for (i = 0; i < uref_multi->num_values; i++)
- field->value[uref->usage_index + i] =
- uref_multi->values[i];
+ field->value[uref->usage_index + i] =
+ uref_multi->values[i];
goto goodreturn;
}
@@ -670,7 +670,7 @@ goodreturn:
fault:
kfree(uref_multi);
return -EFAULT;
-inval:
+inval:
kfree(uref_multi);
return -EINVAL;
@@ -734,7 +734,7 @@ static struct usb_class_driver hiddev_class = {
.name = "usb/hid/hiddev%d",
.fops = &hiddev_fops,
.mode = S_IFCHR | S_IRUGO | S_IWUSR,
- .minor_base = HIDDEV_MINOR_BASE,
+ .minor_base = HIDDEV_MINOR_BASE,
};
/*
@@ -747,7 +747,7 @@ int hiddev_connect(struct hid_device *hid)
int retval;
for (i = 0; i < hid->maxcollection; i++)
- if (hid->collection[i].type ==
+ if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION &&
!IS_INPUT_APPLICATION(hid->collection[i].usage))
break;
@@ -755,11 +755,11 @@ int hiddev_connect(struct hid_device *hid)
if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
return -1;
- if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+ if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
return -1;
memset(hiddev, 0, sizeof(struct hiddev));
- retval = usb_register_dev(hid->intf, &hiddev_class);
+ retval = usb_register_dev(hid->intf, &hiddev_class);
if (retval) {
err("Not able to get a minor for this device.");
kfree(hiddev);
@@ -768,12 +768,12 @@ int hiddev_connect(struct hid_device *hid)
init_waitqueue_head(&hiddev->wait);
- hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
+ hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev;
hiddev->hid = hid;
hiddev->exist = 1;
- hid->minor = hid->intf->minor;
+ hid->minor = hid->intf->minor;
hid->hiddev = hiddev;
return 0;
@@ -818,7 +818,7 @@ void hiddev_disconnect(struct hid_device *hid)
/* We never attach in this manner, and rely on HID to connect us. This
* is why there is no disconnect routine defined in the usb_driver either.
*/
-static int hiddev_usbd_probe(struct usb_interface *intf,
+static int hiddev_usbd_probe(struct usb_interface *intf,
const struct usb_device_id *hiddev_info)
{
return -ENODEV;
diff --git a/drivers/usb/input/itmtouch.c b/drivers/usb/input/itmtouch.c
new file mode 100644
index 000000000000..47dec6a1b344
--- /dev/null
+++ b/drivers/usb/input/itmtouch.c
@@ -0,0 +1,268 @@
+/******************************************************************************
+ * itmtouch.c -- Driver for ITM touchscreen panel
+ *
+ * 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.
+ *
+ * Based upon original work by Chris Collins <xfire-itmtouch@xware.cx>.
+ *
+ * Kudos to ITM for providing me with the datasheet for the panel,
+ * even though it was a day later than I had finished writing this
+ * driver.
+ *
+ * It has meant that I've been able to correct my interpretation of the
+ * protocol packets however.
+ *
+ * CC -- 2003/9/29
+ *
+ * History
+ * 1.0 & 1.1 2003 (CC) vojtech@suse.cz
+ * Original version for 2.4.x kernels
+ *
+ * 1.2 02/03/2005 (HCE) hc@mivu.no
+ * Complete rewrite to support Linux 2.6.10, thanks to mtouchusb.c for hints.
+ * Unfortunately no calibration support at this time.
+ *
+ * 1.2.1 09/03/2005 (HCE) hc@mivu.no
+ * Code cleanup and adjusting syntax to start matching kernel standards
+ *
+ *****************************************************************************/
+
+#include <linux/config.h>
+
+#ifdef CONFIG_USB_DEBUG
+ #define DEBUG
+#else
+ #undef DEBUG
+#endif
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/usb.h>
+
+/* only an 8 byte buffer necessary for a single packet */
+#define ITM_BUFSIZE 8
+#define PATH_SIZE 64
+
+#define USB_VENDOR_ID_ITMINC 0x0403
+#define USB_PRODUCT_ID_TOUCHPANEL 0xf9e9
+
+#define DRIVER_AUTHOR "Hans-Christian Egtvedt <hc@mivu.no>"
+#define DRIVER_VERSION "v1.2.1"
+#define DRIVER_DESC "USB ITM Inc Touch Panel Driver"
+#define DRIVER_LICENSE "GPL"
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE( DRIVER_LICENSE );
+
+struct itmtouch_dev {
+ struct usb_device *usbdev; /* usb device */
+ struct input_dev inputdev; /* input device */
+ struct urb *readurb; /* urb */
+ char rbuf[ITM_BUFSIZE]; /* data */
+ int users;
+ char name[128];
+ char phys[64];
+};
+
+static struct usb_device_id itmtouch_ids [] = {
+ { USB_DEVICE(USB_VENDOR_ID_ITMINC, USB_PRODUCT_ID_TOUCHPANEL) },
+ { }
+};
+
+static void itmtouch_irq(struct urb *urb, struct pt_regs *regs)
+{
+ struct itmtouch_dev * itmtouch = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ struct input_dev *dev = &itmtouch->inputdev;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ETIMEDOUT:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+ return;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ input_regs(dev, regs);
+
+ /* if pressure has been released, then don't report X/Y */
+ if (data[7] & 0x20) {
+ input_report_abs(dev, ABS_X, (data[0] & 0x1F) << 7 | (data[3] & 0x7F));
+ input_report_abs(dev, ABS_Y, (data[1] & 0x1F) << 7 | (data[4] & 0x7F));
+ }
+
+ input_report_abs(dev, ABS_PRESSURE, (data[2] & 1) << 7 | (data[5] & 0x7F));
+ input_report_key(dev, BTN_TOUCH, ~data[7] & 0x20);
+ input_sync(dev);
+
+exit:
+ retval = usb_submit_urb (urb, GFP_ATOMIC);
+ if (retval)
+ printk(KERN_ERR "%s - usb_submit_urb failed with result: %d",
+ __FUNCTION__, retval);
+}
+
+static int itmtouch_open(struct input_dev *input)
+{
+ struct itmtouch_dev *itmtouch = input->private;
+
+ itmtouch->readurb->dev = itmtouch->usbdev;
+
+ if (usb_submit_urb(itmtouch->readurb, GFP_KERNEL))
+ return -EIO;
+
+ return 0;
+}
+
+static void itmtouch_close(struct input_dev *input)
+{
+ struct itmtouch_dev *itmtouch = input->private;
+
+ usb_kill_urb(itmtouch->readurb);
+}
+
+static int itmtouch_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct itmtouch_dev *itmtouch;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ unsigned int pipe;
+ unsigned int maxp;
+ char path[PATH_SIZE];
+
+ interface = intf->cur_altsetting;
+ endpoint = &interface->endpoint[0].desc;
+
+ if (!(itmtouch = kcalloc(1, sizeof(struct itmtouch_dev), GFP_KERNEL))) {
+ err("%s - Out of memory.", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ itmtouch->usbdev = udev;
+
+ itmtouch->inputdev.private = itmtouch;
+ itmtouch->inputdev.open = itmtouch_open;
+ itmtouch->inputdev.close = itmtouch_close;
+
+ usb_make_path(udev, path, PATH_SIZE);
+
+ itmtouch->inputdev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ itmtouch->inputdev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE);
+ itmtouch->inputdev.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+ itmtouch->inputdev.name = itmtouch->name;
+ itmtouch->inputdev.phys = itmtouch->phys;
+ itmtouch->inputdev.id.bustype = BUS_USB;
+ itmtouch->inputdev.id.vendor = udev->descriptor.idVendor;
+ itmtouch->inputdev.id.product = udev->descriptor.idProduct;
+ itmtouch->inputdev.id.version = udev->descriptor.bcdDevice;
+ itmtouch->inputdev.dev = &intf->dev;
+
+ if (!strlen(itmtouch->name))
+ sprintf(itmtouch->name, "USB ITM touchscreen");
+
+ /* device limits */
+ /* as specified by the ITM datasheet, X and Y are 12bit,
+ * Z (pressure) is 8 bit. However, the fields are defined up
+ * to 14 bits for future possible expansion.
+ */
+ input_set_abs_params(&itmtouch->inputdev, ABS_X, 0, 0x0FFF, 2, 0);
+ input_set_abs_params(&itmtouch->inputdev, ABS_Y, 0, 0x0FFF, 2, 0);
+ input_set_abs_params(&itmtouch->inputdev, ABS_PRESSURE, 0, 0xFF, 2, 0);
+
+ /* initialise the URB so we can read from the transport stream */
+ pipe = usb_rcvintpipe(itmtouch->usbdev, endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
+
+ if (maxp > ITM_BUFSIZE)
+ maxp = ITM_BUFSIZE;
+
+ itmtouch->readurb = usb_alloc_urb(0, GFP_KERNEL);
+
+ if (!itmtouch->readurb) {
+ dbg("%s - usb_alloc_urb failed: itmtouch->readurb", __FUNCTION__);
+ kfree(itmtouch);
+ return -ENOMEM;
+ }
+
+ usb_fill_int_urb(itmtouch->readurb, itmtouch->usbdev, pipe, itmtouch->rbuf,
+ maxp, itmtouch_irq, itmtouch, endpoint->bInterval);
+
+ input_register_device(&itmtouch->inputdev);
+
+ printk(KERN_INFO "itmtouch: %s registered on %s\n", itmtouch->name, path);
+ usb_set_intfdata(intf, itmtouch);
+
+ return 0;
+}
+
+static void itmtouch_disconnect(struct usb_interface *intf)
+{
+ struct itmtouch_dev *itmtouch = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (itmtouch) {
+ input_unregister_device(&itmtouch->inputdev);
+ usb_kill_urb(itmtouch->readurb);
+ usb_free_urb(itmtouch->readurb);
+ kfree(itmtouch);
+ }
+}
+
+MODULE_DEVICE_TABLE(usb, itmtouch_ids);
+
+static struct usb_driver itmtouch_driver = {
+ .owner = THIS_MODULE,
+ .name = "itmtouch",
+ .probe = itmtouch_probe,
+ .disconnect = itmtouch_disconnect,
+ .id_table = itmtouch_ids,
+};
+
+static int __init itmtouch_init(void)
+{
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ info(DRIVER_AUTHOR);
+ return usb_register(&itmtouch_driver);
+}
+
+static void __exit itmtouch_exit(void)
+{
+ usb_deregister(&itmtouch_driver);
+}
+
+module_init(itmtouch_init);
+module_exit(itmtouch_exit);
diff --git a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c
index a68c5b4e7b37..d2f0f90a9bcd 100644
--- a/drivers/usb/input/kbtab.c
+++ b/drivers/usb/input/kbtab.c
@@ -36,7 +36,6 @@ struct kbtab {
struct input_dev dev;
struct usb_device *usbdev;
struct urb *irq;
- int open;
int x, y;
int button;
int pressure;
@@ -79,12 +78,12 @@ static void kbtab_irq(struct urb *urb, struct pt_regs *regs)
/*input_report_key(dev, BTN_TOUCH , data[0] & 0x01);*/
input_report_key(dev, BTN_RIGHT, data[0] & 0x02);
- if( -1 == kb_pressure_click){
+ if (-1 == kb_pressure_click) {
input_report_abs(dev, ABS_PRESSURE, kbtab->pressure);
} else {
input_report_key(dev, BTN_LEFT, (kbtab->pressure > kb_pressure_click) ? 1 : 0);
};
-
+
input_sync(dev);
exit:
@@ -105,14 +104,9 @@ static int kbtab_open(struct input_dev *dev)
{
struct kbtab *kbtab = dev->private;
- if (kbtab->open++)
- return 0;
-
kbtab->irq->dev = kbtab->usbdev;
- if (usb_submit_urb(kbtab->irq, GFP_KERNEL)) {
- kbtab->open--;
+ if (usb_submit_urb(kbtab->irq, GFP_KERNEL))
return -EIO;
- }
return 0;
}
@@ -121,8 +115,7 @@ static void kbtab_close(struct input_dev *dev)
{
struct kbtab *kbtab = dev->private;
- if (!--kbtab->open)
- usb_kill_urb(kbtab->irq);
+ usb_kill_urb(kbtab->irq);
}
static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -161,7 +154,7 @@ static int kbtab_probe(struct usb_interface *intf, const struct usb_device_id *i
kbtab->dev.absmax[ABS_X] = 0x2000;
kbtab->dev.absmax[ABS_Y] = 0x1750;
kbtab->dev.absmax[ABS_PRESSURE] = 0xff;
-
+
kbtab->dev.absfuzz[ABS_X] = 4;
kbtab->dev.absfuzz[ABS_Y] = 4;
diff --git a/drivers/usb/input/keyspan_remote.c b/drivers/usb/input/keyspan_remote.c
new file mode 100644
index 000000000000..67dc93685203
--- /dev/null
+++ b/drivers/usb/input/keyspan_remote.c
@@ -0,0 +1,633 @@
+/*
+ * keyspan_remote: USB driver for the Keyspan DMR
+ *
+ * Copyright (C) 2005 Zymeta Corporation - Michael Downey (downey@zymeta.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 has been put together with the support of Innosys, Inc.
+ * and Keyspan, Inc the manufacturers of the Keyspan USB DMR product.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#define DRIVER_VERSION "v0.1"
+#define DRIVER_AUTHOR "Michael Downey <downey@zymeta.com>"
+#define DRIVER_DESC "Driver for the USB Keyspan remote control."
+#define DRIVER_LICENSE "GPL"
+
+/* Parameters that can be passed to the driver. */
+static int debug;
+module_param(debug, int, 0444);
+MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
+
+/* Vendor and product ids */
+#define USB_KEYSPAN_VENDOR_ID 0x06CD
+#define USB_KEYSPAN_PRODUCT_UIA11 0x0202
+
+/* Defines for converting the data from the remote. */
+#define ZERO 0x18
+#define ZERO_MASK 0x1F /* 5 bits for a 0 */
+#define ONE 0x3C
+#define ONE_MASK 0x3F /* 6 bits for a 1 */
+#define SYNC 0x3F80
+#define SYNC_MASK 0x3FFF /* 14 bits for a SYNC sequence */
+#define STOP 0x00
+#define STOP_MASK 0x1F /* 5 bits for the STOP sequence */
+#define GAP 0xFF
+
+#define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */
+
+/* table of devices that work with this driver */
+static struct usb_device_id keyspan_table[] = {
+ { USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
+ { } /* Terminating entry */
+};
+
+/* Structure to store all the real stuff that a remote sends to us. */
+struct keyspan_message {
+ u16 system;
+ u8 button;
+ u8 toggle;
+};
+
+/* Structure used for all the bit testing magic needed to be done. */
+struct bit_tester {
+ u32 tester;
+ int len;
+ int pos;
+ int bits_left;
+ u8 buffer[32];
+};
+
+/* Structure to hold all of our driver specific stuff */
+struct usb_keyspan {
+ char name[128];
+ char phys[64];
+ struct usb_device* udev;
+ struct input_dev input;
+ struct usb_interface* interface;
+ struct usb_endpoint_descriptor* in_endpoint;
+ struct urb* irq_urb;
+ int open;
+ dma_addr_t in_dma;
+ unsigned char* in_buffer;
+
+ /* variables used to parse messages from remote. */
+ struct bit_tester data;
+ int stage;
+ int toggle;
+};
+
+/*
+ * Table that maps the 31 possible keycodes to input keys.
+ * Currently there are 15 and 17 button models so RESERVED codes
+ * are blank areas in the mapping.
+ */
+static int keyspan_key_table[] = {
+ KEY_RESERVED, /* 0 is just a place holder. */
+ KEY_RESERVED,
+ KEY_STOP,
+ KEY_PLAYCD,
+ KEY_RESERVED,
+ KEY_PREVIOUSSONG,
+ KEY_REWIND,
+ KEY_FORWARD,
+ KEY_NEXTSONG,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_PAUSE,
+ KEY_VOLUMEUP,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_VOLUMEDOWN,
+ KEY_RESERVED,
+ KEY_UP,
+ KEY_RESERVED,
+ KEY_MUTE,
+ KEY_LEFT,
+ KEY_ENTER,
+ KEY_RIGHT,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_DOWN,
+ KEY_RESERVED,
+ KEY_KPASTERISK,
+ KEY_RESERVED,
+ KEY_MENU
+};
+
+static struct usb_driver keyspan_driver;
+
+/*
+ * Debug routine that prints out what we've received from the remote.
+ */
+static void keyspan_print(struct usb_keyspan* dev) /*unsigned char* data)*/
+{
+ char codes[4*RECV_SIZE];
+ int i;
+
+ for (i = 0; i < RECV_SIZE; i++) {
+ snprintf(codes+i*3, 4, "%02x ", dev->in_buffer[i]);
+ }
+
+ dev_info(&dev->udev->dev, "%s\n", codes);
+}
+
+/*
+ * Routine that manages the bit_tester structure. It makes sure that there are
+ * at least bits_needed bits loaded into the tester.
+ */
+static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
+{
+ if (dev->data.bits_left >= bits_needed)
+ return(0);
+
+ /*
+ * Somehow we've missed the last message. The message will be repeated
+ * though so it's not too big a deal
+ */
+ if (dev->data.pos >= dev->data.len) {
+ dev_dbg(&dev->udev, "%s - Error ran out of data. pos: %d, len: %d\n",
+ __FUNCTION__, dev->data.pos, dev->data.len);
+ return(-1);
+ }
+
+ /* Load as much as we can into the tester. */
+ while ((dev->data.bits_left + 7 < (sizeof(dev->data.tester) * 8)) &&
+ (dev->data.pos < dev->data.len)) {
+ dev->data.tester += (dev->data.buffer[dev->data.pos++] << dev->data.bits_left);
+ dev->data.bits_left += 8;
+ }
+
+ return(0);
+}
+
+/*
+ * Routine that handles all the logic needed to parse out the message from the remote.
+ */
+static void keyspan_check_data(struct usb_keyspan *remote, struct pt_regs *regs)
+{
+ int i;
+ int found = 0;
+ struct keyspan_message message;
+
+ switch(remote->stage) {
+ case 0:
+ /*
+ * In stage 0 we want to find the start of a message. The remote sends a 0xFF as filler.
+ * So the first byte that isn't a FF should be the start of a new message.
+ */
+ for (i = 0; i < RECV_SIZE && remote->in_buffer[i] == GAP; ++i);
+
+ if (i < RECV_SIZE) {
+ memcpy(remote->data.buffer, remote->in_buffer, RECV_SIZE);
+ remote->data.len = RECV_SIZE;
+ remote->data.pos = 0;
+ remote->data.tester = 0;
+ remote->data.bits_left = 0;
+ remote->stage = 1;
+ }
+ break;
+
+ case 1:
+ /*
+ * Stage 1 we should have 16 bytes and should be able to detect a
+ * SYNC. The SYNC is 14 bits, 7 0's and then 7 1's.
+ */
+ memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+ remote->data.len += RECV_SIZE;
+
+ found = 0;
+ while ((remote->data.bits_left >= 14 || remote->data.pos < remote->data.len) && !found) {
+ for (i = 0; i < 8; ++i) {
+ if (keyspan_load_tester(remote, 14) != 0) {
+ remote->stage = 0;
+ return;
+ }
+
+ if ((remote->data.tester & SYNC_MASK) == SYNC) {
+ remote->data.tester = remote->data.tester >> 14;
+ remote->data.bits_left -= 14;
+ found = 1;
+ break;
+ } else {
+ remote->data.tester = remote->data.tester >> 1;
+ --remote->data.bits_left;
+ }
+ }
+ }
+
+ if (!found) {
+ remote->stage = 0;
+ remote->data.len = 0;
+ } else {
+ remote->stage = 2;
+ }
+ break;
+
+ case 2:
+ /*
+ * Stage 2 we should have 24 bytes which will be enough for a full
+ * message. We need to parse out the system code, button code,
+ * toggle code, and stop.
+ */
+ memcpy(remote->data.buffer + remote->data.len, remote->in_buffer, RECV_SIZE);
+ remote->data.len += RECV_SIZE;
+
+ message.system = 0;
+ for (i = 0; i < 9; i++) {
+ keyspan_load_tester(remote, 6);
+
+ if ((remote->data.tester & ZERO_MASK) == ZERO) {
+ message.system = message.system << 1;
+ remote->data.tester = remote->data.tester >> 5;
+ remote->data.bits_left -= 5;
+ } else if ((remote->data.tester & ONE_MASK) == ONE) {
+ message.system = (message.system << 1) + 1;
+ remote->data.tester = remote->data.tester >> 6;
+ remote->data.bits_left -= 6;
+ } else {
+ err("%s - Unknown sequence found in system data.\n", __FUNCTION__);
+ remote->stage = 0;
+ return;
+ }
+ }
+
+ message.button = 0;
+ for (i = 0; i < 5; i++) {
+ keyspan_load_tester(remote, 6);
+
+ if ((remote->data.tester & ZERO_MASK) == ZERO) {
+ message.button = message.button << 1;
+ remote->data.tester = remote->data.tester >> 5;
+ remote->data.bits_left -= 5;
+ } else if ((remote->data.tester & ONE_MASK) == ONE) {
+ message.button = (message.button << 1) + 1;
+ remote->data.tester = remote->data.tester >> 6;
+ remote->data.bits_left -= 6;
+ } else {
+ err("%s - Unknown sequence found in button data.\n", __FUNCTION__);
+ remote->stage = 0;
+ return;
+ }
+ }
+
+ keyspan_load_tester(remote, 6);
+ if ((remote->data.tester & ZERO_MASK) == ZERO) {
+ message.toggle = 0;
+ remote->data.tester = remote->data.tester >> 5;
+ remote->data.bits_left -= 5;
+ } else if ((remote->data.tester & ONE_MASK) == ONE) {
+ message.toggle = 1;
+ remote->data.tester = remote->data.tester >> 6;
+ remote->data.bits_left -= 6;
+ } else {
+ err("%s - Error in message, invalid toggle.\n", __FUNCTION__);
+ }
+
+ keyspan_load_tester(remote, 5);
+ if ((remote->data.tester & STOP_MASK) == STOP) {
+ remote->data.tester = remote->data.tester >> 5;
+ remote->data.bits_left -= 5;
+ } else {
+ err("Bad message recieved, no stop bit found.\n");
+ }
+
+ dev_dbg(&remote->udev,
+ "%s found valid message: system: %d, button: %d, toggle: %d\n",
+ __FUNCTION__, message.system, message.button, message.toggle);
+
+ if (message.toggle != remote->toggle) {
+ input_regs(&remote->input, regs);
+ input_report_key(&remote->input, keyspan_key_table[message.button], 1);
+ input_report_key(&remote->input, keyspan_key_table[message.button], 0);
+ input_sync(&remote->input);
+ remote->toggle = message.toggle;
+ }
+
+ remote->stage = 0;
+ break;
+ }
+}
+
+/*
+ * Routine for sending all the initialization messages to the remote.
+ */
+static int keyspan_setup(struct usb_device* dev)
+{
+ int retval = 0;
+
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x11, 0x40, 0x5601, 0x0, NULL, 0, 0);
+ if (retval) {
+ dev_dbg(&dev->dev, "%s - failed to set bit rate due to error: %d\n",
+ __FUNCTION__, retval);
+ return(retval);
+ }
+
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x44, 0x40, 0x0, 0x0, NULL, 0, 0);
+ if (retval) {
+ dev_dbg(&dev->dev, "%s - failed to set resume sensitivity due to error: %d\n",
+ __FUNCTION__, retval);
+ return(retval);
+ }
+
+ retval = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x22, 0x40, 0x0, 0x0, NULL, 0, 0);
+ if (retval) {
+ dev_dbg(&dev->dev, "%s - failed to turn receive on due to error: %d\n",
+ __FUNCTION__, retval);
+ return(retval);
+ }
+
+ dev_dbg(&dev->dev, "%s - Setup complete.\n", __FUNCTION__);
+ return(retval);
+}
+
+/*
+ * Routine used to handle a new message that has come in.
+ */
+static void keyspan_irq_recv(struct urb *urb, struct pt_regs *regs)
+{
+ struct usb_keyspan *dev = urb->context;
+ int retval;
+
+ /* Check our status in case we need to bail out early. */
+ switch (urb->status) {
+ case 0:
+ break;
+
+ /* Device went away so don't keep trying to read from it. */
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+
+ default:
+ goto resubmit;
+ break;
+ }
+
+ if (debug)
+ keyspan_print(dev);
+
+ keyspan_check_data(dev, regs);
+
+resubmit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ err ("%s - usb_submit_urb failed with result: %d", __FUNCTION__, retval);
+}
+
+static int keyspan_open(struct input_dev *dev)
+{
+ struct usb_keyspan *remote = dev->private;
+
+ if (remote->open++)
+ return 0;
+
+ remote->irq_urb->dev = remote->udev;
+ if (usb_submit_urb(remote->irq_urb, GFP_KERNEL)) {
+ remote->open--;
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void keyspan_close(struct input_dev *dev)
+{
+ struct usb_keyspan *remote = dev->private;
+
+ if (!--remote->open)
+ usb_kill_urb(remote->irq_urb);
+}
+
+/*
+ * Routine that sets up the driver to handle a specific USB device detected on the bus.
+ */
+static int keyspan_probe(struct usb_interface *interface, const struct usb_device_id *id)
+{
+ int i;
+ int retval = -ENOMEM;
+ char path[64];
+ char *buf;
+ struct usb_keyspan *remote = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = usb_get_dev(interface_to_usbdev(interface));
+
+ /* See if the offered device matches what we can accept */
+ if ((udev->descriptor.idVendor != USB_KEYSPAN_VENDOR_ID) ||
+ (udev->descriptor.idProduct != USB_KEYSPAN_PRODUCT_UIA11) )
+ return -ENODEV;
+
+ /* allocate memory for our device state and initialize it */
+ remote = kmalloc(sizeof(*remote), GFP_KERNEL);
+ if (remote == NULL) {
+ err("Out of memory\n");
+ goto error;
+ }
+ memset(remote, 0x00, sizeof(*remote));
+
+ remote->udev = udev;
+ remote->interface = interface;
+ remote->toggle = -1; /* Set to -1 so we will always not match the toggle from the first remote message. */
+
+ /* set up the endpoint information */
+ /* use only the first in interrupt endpoint */
+ iface_desc = interface->cur_altsetting;
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (!remote->in_endpoint &&
+ (endpoint->bEndpointAddress & USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ /* we found our interrupt in endpoint */
+ remote->in_endpoint = endpoint;
+
+ remote->in_buffer = usb_buffer_alloc(remote->udev, RECV_SIZE, SLAB_ATOMIC, &remote->in_dma);
+ if (!remote->in_buffer) {
+ retval = -ENOMEM;
+ goto error;
+ }
+ }
+ }
+
+ if (!remote->in_endpoint) {
+ err("Could not find interrupt input endpoint.\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ remote->irq_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!remote->irq_urb) {
+ err("Failed to allocate urb.\n");
+ retval = -ENOMEM;
+ goto error;
+ }
+
+ retval = keyspan_setup(remote->udev);
+ if (retval) {
+ err("Failed to setup device.\n");
+ retval = -ENODEV;
+ goto error;
+ }
+
+ /*
+ * Setup the input system with the bits we are going to be reporting
+ */
+ remote->input.evbit[0] = BIT(EV_KEY); /* We will only report KEY events. */
+ for (i = 0; i < 32; ++i) {
+ if (keyspan_key_table[i] != KEY_RESERVED) {
+ set_bit(keyspan_key_table[i], remote->input.keybit);
+ }
+ }
+
+ remote->input.private = remote;
+ remote->input.open = keyspan_open;
+ remote->input.close = keyspan_close;
+
+ usb_make_path(remote->udev, path, 64);
+ sprintf(remote->phys, "%s/input0", path);
+
+ remote->input.name = remote->name;
+ remote->input.phys = remote->phys;
+ remote->input.id.bustype = BUS_USB;
+ remote->input.id.vendor = le16_to_cpu(remote->udev->descriptor.idVendor);
+ remote->input.id.product = le16_to_cpu(remote->udev->descriptor.idProduct);
+ remote->input.id.version = le16_to_cpu(remote->udev->descriptor.bcdDevice);
+
+ if (!(buf = kmalloc(63, GFP_KERNEL))) {
+ usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+ kfree(remote);
+ return -ENOMEM;
+ }
+
+ if (remote->udev->descriptor.iManufacturer &&
+ usb_string(remote->udev, remote->udev->descriptor.iManufacturer, buf, 63) > 0)
+ strcat(remote->name, buf);
+
+ if (remote->udev->descriptor.iProduct &&
+ usb_string(remote->udev, remote->udev->descriptor.iProduct, buf, 63) > 0)
+ sprintf(remote->name, "%s %s", remote->name, buf);
+
+ if (!strlen(remote->name))
+ sprintf(remote->name, "USB Keyspan Remote %04x:%04x",
+ remote->input.id.vendor, remote->input.id.product);
+
+ kfree(buf);
+
+ /*
+ * Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
+ */
+ usb_fill_int_urb(remote->irq_urb,
+ remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
+ remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
+ remote->in_endpoint->bInterval);
+ remote->irq_urb->transfer_dma = remote->in_dma;
+ remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ /* we can register the device now, as it is ready */
+ input_register_device(&remote->input);
+
+ /* save our data pointer in this interface device */
+ usb_set_intfdata(interface, remote);
+
+ /* let the user know what node this device is now attached to */
+ info("connected: %s on %s", remote->name, path);
+ return 0;
+
+error:
+ /*
+ * In case of error we need to clean up any allocated buffers
+ */
+ if (remote->irq_urb)
+ usb_free_urb(remote->irq_urb);
+
+ if (remote->in_buffer)
+ usb_buffer_free(remote->udev, RECV_SIZE, remote->in_buffer, remote->in_dma);
+
+ if (remote)
+ kfree(remote);
+
+ return retval;
+}
+
+/*
+ * Routine called when a device is disconnected from the USB.
+ */
+static void keyspan_disconnect(struct usb_interface *interface)
+{
+ struct usb_keyspan *remote;
+
+ /* prevent keyspan_open() from racing keyspan_disconnect() */
+ lock_kernel();
+
+ remote = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
+
+ if (remote) { /* We have a valid driver structure so clean up everything we allocated. */
+ input_unregister_device(&remote->input);
+ usb_kill_urb(remote->irq_urb);
+ usb_free_urb(remote->irq_urb);
+ usb_buffer_free(interface_to_usbdev(interface), RECV_SIZE, remote->in_buffer, remote->in_dma);
+ kfree(remote);
+ }
+
+ unlock_kernel();
+
+ info("USB Keyspan now disconnected");
+}
+
+/*
+ * Standard driver set up sections
+ */
+static struct usb_driver keyspan_driver =
+{
+ .owner = THIS_MODULE,
+ .name = "keyspan_remote",
+ .probe = keyspan_probe,
+ .disconnect = keyspan_disconnect,
+ .id_table = keyspan_table
+};
+
+static int __init usb_keyspan_init(void)
+{
+ int result;
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&keyspan_driver);
+ if (result)
+ err("usb_register failed. Error number %d\n", result);
+
+ return result;
+}
+
+static void __exit usb_keyspan_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&keyspan_driver);
+}
+
+module_init(usb_keyspan_init);
+module_exit(usb_keyspan_exit);
+
+MODULE_DEVICE_TABLE(usb, keyspan_table);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE(DRIVER_LICENSE);
diff --git a/drivers/usb/input/mtouchusb.c b/drivers/usb/input/mtouchusb.c
index ab1a2a30ce7c..09b5cc7c66de 100644
--- a/drivers/usb/input/mtouchusb.c
+++ b/drivers/usb/input/mtouchusb.c
@@ -42,9 +42,9 @@
#include <linux/config.h>
#ifdef CONFIG_USB_DEBUG
- #define DEBUG
+ #define DEBUG
#else
- #undef DEBUG
+ #undef DEBUG
#endif
#include <linux/kernel.h>
@@ -93,275 +93,255 @@ module_param(raw_coordinates, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(raw_coordinates, "report raw coordinate values (y, default) or hardware-calibrated coordinate values (n)");
struct mtouch_usb {
- unsigned char *data;
- dma_addr_t data_dma;
- struct urb *irq;
- struct usb_device *udev;
- struct input_dev input;
- int open;
- char name[128];
- char phys[64];
+ unsigned char *data;
+ dma_addr_t data_dma;
+ struct urb *irq;
+ struct usb_device *udev;
+ struct input_dev input;
+ char name[128];
+ char phys[64];
};
-static struct usb_device_id mtouchusb_devices [] = {
- { USB_DEVICE(0x0596, 0x0001) },
- { }
+static struct usb_device_id mtouchusb_devices[] = {
+ { USB_DEVICE(0x0596, 0x0001) },
+ { }
};
static void mtouchusb_irq(struct urb *urb, struct pt_regs *regs)
{
- struct mtouch_usb *mtouch = urb->context;
- int retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ETIMEDOUT:
- /* this urb is timing out */
- dbg("%s - urb timed out - was the device unplugged?",
- __FUNCTION__);
- return;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __FUNCTION__, urb->status);
- goto exit;
- }
-
- input_regs(&mtouch->input, regs);
- input_report_key(&mtouch->input, BTN_TOUCH,
- MTOUCHUSB_GET_TOUCHED(mtouch->data));
- input_report_abs(&mtouch->input, ABS_X,
- MTOUCHUSB_GET_XC(mtouch->data));
- input_report_abs(&mtouch->input, ABS_Y,
+ struct mtouch_usb *mtouch = urb->context;
+ int retval;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ETIMEDOUT:
+ /* this urb is timing out */
+ dbg("%s - urb timed out - was the device unplugged?",
+ __FUNCTION__);
+ return;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d",
+ __FUNCTION__, urb->status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d",
+ __FUNCTION__, urb->status);
+ goto exit;
+ }
+
+ input_regs(&mtouch->input, regs);
+ input_report_key(&mtouch->input, BTN_TOUCH,
+ MTOUCHUSB_GET_TOUCHED(mtouch->data));
+ input_report_abs(&mtouch->input, ABS_X, MTOUCHUSB_GET_XC(mtouch->data));
+ input_report_abs(&mtouch->input, ABS_Y,
(raw_coordinates ? MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC)
- - MTOUCHUSB_GET_YC(mtouch->data));
- input_sync(&mtouch->input);
+ - MTOUCHUSB_GET_YC(mtouch->data));
+ input_sync(&mtouch->input);
exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result: %d",
- __FUNCTION__, retval);
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ err("%s - usb_submit_urb failed with result: %d",
+ __FUNCTION__, retval);
}
-static int mtouchusb_open (struct input_dev *input)
+static int mtouchusb_open(struct input_dev *input)
{
- struct mtouch_usb *mtouch = input->private;
+ struct mtouch_usb *mtouch = input->private;
- if (mtouch->open++)
- return 0;
+ mtouch->irq->dev = mtouch->udev;
- mtouch->irq->dev = mtouch->udev;
+ if (usb_submit_urb(mtouch->irq, GFP_ATOMIC))
+ return -EIO;
- if (usb_submit_urb (mtouch->irq, GFP_ATOMIC)) {
- mtouch->open--;
- return -EIO;
- }
-
- return 0;
+ return 0;
}
-static void mtouchusb_close (struct input_dev *input)
+static void mtouchusb_close(struct input_dev *input)
{
- struct mtouch_usb *mtouch = input->private;
+ struct mtouch_usb *mtouch = input->private;
- if (!--mtouch->open)
- usb_kill_urb (mtouch->irq);
+ usb_kill_urb(mtouch->irq);
}
static int mtouchusb_alloc_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
- dbg("%s - called", __FUNCTION__);
+ dbg("%s - called", __FUNCTION__);
- mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
- SLAB_ATOMIC, &mtouch->data_dma);
+ mtouch->data = usb_buffer_alloc(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+ SLAB_ATOMIC, &mtouch->data_dma);
- if (!mtouch->data)
- return -1;
+ if (!mtouch->data)
+ return -1;
- return 0;
+ return 0;
}
static void mtouchusb_free_buffers(struct usb_device *udev, struct mtouch_usb *mtouch)
{
- dbg("%s - called", __FUNCTION__);
+ dbg("%s - called", __FUNCTION__);
- if (mtouch->data)
- usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
- mtouch->data, mtouch->data_dma);
+ if (mtouch->data)
+ usb_buffer_free(udev, MTOUCHUSB_REPORT_DATA_SIZE,
+ mtouch->data, mtouch->data_dma);
}
static int mtouchusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
- struct mtouch_usb *mtouch;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- struct usb_device *udev = interface_to_usbdev (intf);
- char path[64];
- int nRet;
-
- dbg("%s - called", __FUNCTION__);
-
- dbg("%s - setting interface", __FUNCTION__);
- interface = intf->cur_altsetting;
-
- dbg("%s - setting endpoint", __FUNCTION__);
- endpoint = &interface->endpoint[0].desc;
-
- if (!(mtouch = kmalloc (sizeof (struct mtouch_usb), GFP_KERNEL))) {
- err("%s - Out of memory.", __FUNCTION__);
- return -ENOMEM;
- }
-
- memset(mtouch, 0, sizeof(struct mtouch_usb));
- mtouch->udev = udev;
-
- dbg("%s - allocating buffers", __FUNCTION__);
- if (mtouchusb_alloc_buffers(udev, mtouch)) {
- mtouchusb_free_buffers(udev, mtouch);
- kfree(mtouch);
- return -ENOMEM;
- }
-
- mtouch->input.private = mtouch;
- mtouch->input.open = mtouchusb_open;
- mtouch->input.close = mtouchusb_close;
-
- usb_make_path(udev, path, 64);
- sprintf(mtouch->phys, "%s/input0", path);
-
- mtouch->input.name = mtouch->name;
- mtouch->input.phys = mtouch->phys;
- mtouch->input.id.bustype = BUS_USB;
- mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
- mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
- mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
- mtouch->input.dev = &intf->dev;
-
- mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
- mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
-
- /* Used to Scale Compensated Data and Flip Y */
- mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
- mtouch->input.absmax[ABS_X] = raw_coordinates ? \
- MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
- mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
- mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
- mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
- mtouch->input.absmax[ABS_Y] = raw_coordinates ? \
- MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
- mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
- mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
+ struct mtouch_usb *mtouch;
+ struct usb_host_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct usb_device *udev = interface_to_usbdev(intf);
+ char path[64];
+ int nRet;
+
+ dbg("%s - called", __FUNCTION__);
+
+ dbg("%s - setting interface", __FUNCTION__);
+ interface = intf->cur_altsetting;
+
+ dbg("%s - setting endpoint", __FUNCTION__);
+ endpoint = &interface->endpoint[0].desc;
+
+ if (!(mtouch = kmalloc(sizeof(struct mtouch_usb), GFP_KERNEL))) {
+ err("%s - Out of memory.", __FUNCTION__);
+ return -ENOMEM;
+ }
+
+ memset(mtouch, 0, sizeof(struct mtouch_usb));
+ mtouch->udev = udev;
+
+ dbg("%s - allocating buffers", __FUNCTION__);
+ if (mtouchusb_alloc_buffers(udev, mtouch)) {
+ mtouchusb_free_buffers(udev, mtouch);
+ kfree(mtouch);
+ return -ENOMEM;
+ }
+
+ mtouch->input.private = mtouch;
+ mtouch->input.open = mtouchusb_open;
+ mtouch->input.close = mtouchusb_close;
+
+ usb_make_path(udev, path, 64);
+ sprintf(mtouch->phys, "%s/input0", path);
+
+ mtouch->input.name = mtouch->name;
+ mtouch->input.phys = mtouch->phys;
+ mtouch->input.id.bustype = BUS_USB;
+ mtouch->input.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
+ mtouch->input.id.product = le16_to_cpu(udev->descriptor.idProduct);
+ mtouch->input.id.version = le16_to_cpu(udev->descriptor.bcdDevice);
+ mtouch->input.dev = &intf->dev;
+
+ mtouch->input.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ mtouch->input.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+ mtouch->input.keybit[LONG(BTN_TOUCH)] = BIT(BTN_TOUCH);
+
+ /* Used to Scale Compensated Data and Flip Y */
+ mtouch->input.absmin[ABS_X] = MTOUCHUSB_MIN_XC;
+ mtouch->input.absmax[ABS_X] = raw_coordinates ?
+ MTOUCHUSB_MAX_RAW_XC : MTOUCHUSB_MAX_CALIB_XC;
+ mtouch->input.absfuzz[ABS_X] = MTOUCHUSB_XC_FUZZ;
+ mtouch->input.absflat[ABS_X] = MTOUCHUSB_XC_FLAT;
+ mtouch->input.absmin[ABS_Y] = MTOUCHUSB_MIN_YC;
+ mtouch->input.absmax[ABS_Y] = raw_coordinates ?
+ MTOUCHUSB_MAX_RAW_YC : MTOUCHUSB_MAX_CALIB_YC;
+ mtouch->input.absfuzz[ABS_Y] = MTOUCHUSB_YC_FUZZ;
+ mtouch->input.absflat[ABS_Y] = MTOUCHUSB_YC_FLAT;
if (udev->manufacturer)
strcat(mtouch->name, udev->manufacturer);
if (udev->product)
sprintf(mtouch->name, "%s %s", mtouch->name, udev->product);
- if (!strlen(mtouch->name))
- sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
- mtouch->input.id.vendor, mtouch->input.id.product);
-
- nRet = usb_control_msg(mtouch->udev,
- usb_rcvctrlpipe(udev, 0),
- MTOUCHUSB_RESET,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1,
- 0,
- NULL,
- 0,
- USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
- __FUNCTION__, nRet);
-
- dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
- mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
- if (!mtouch->irq) {
- dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
- mtouchusb_free_buffers(udev, mtouch);
- kfree(mtouch);
- return -ENOMEM;
- }
-
- dbg("%s - usb_fill_int_urb", __FUNCTION__);
- usb_fill_int_urb(mtouch->irq,
- mtouch->udev,
- usb_rcvintpipe(mtouch->udev, 0x81),
- mtouch->data,
- MTOUCHUSB_REPORT_DATA_SIZE,
- mtouchusb_irq,
- mtouch,
- endpoint->bInterval);
-
- dbg("%s - input_register_device", __FUNCTION__);
- input_register_device(&mtouch->input);
-
- nRet = usb_control_msg(mtouch->udev,
- usb_rcvctrlpipe(udev, 0),
- MTOUCHUSB_ASYNC_REPORT,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 1,
- 1,
- NULL,
- 0,
- USB_CTRL_SET_TIMEOUT);
- dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
- __FUNCTION__, nRet);
-
- printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
- usb_set_intfdata(intf, mtouch);
-
- return 0;
+ if (!strlen(mtouch->name))
+ sprintf(mtouch->name, "USB Touchscreen %04x:%04x",
+ mtouch->input.id.vendor, mtouch->input.id.product);
+
+ nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+ MTOUCHUSB_RESET,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, 0, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("%s - usb_control_msg - MTOUCHUSB_RESET - bytes|err: %d",
+ __FUNCTION__, nRet);
+
+ dbg("%s - usb_alloc_urb: mtouch->irq", __FUNCTION__);
+ mtouch->irq = usb_alloc_urb(0, GFP_KERNEL);
+ if (!mtouch->irq) {
+ dbg("%s - usb_alloc_urb failed: mtouch->irq", __FUNCTION__);
+ mtouchusb_free_buffers(udev, mtouch);
+ kfree(mtouch);
+ return -ENOMEM;
+ }
+
+ dbg("%s - usb_fill_int_urb", __FUNCTION__);
+ usb_fill_int_urb(mtouch->irq, mtouch->udev,
+ usb_rcvintpipe(mtouch->udev, 0x81),
+ mtouch->data, MTOUCHUSB_REPORT_DATA_SIZE,
+ mtouchusb_irq, mtouch, endpoint->bInterval);
+
+ dbg("%s - input_register_device", __FUNCTION__);
+ input_register_device(&mtouch->input);
+
+ nRet = usb_control_msg(mtouch->udev, usb_rcvctrlpipe(udev, 0),
+ MTOUCHUSB_ASYNC_REPORT,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 1, 1, NULL, 0, USB_CTRL_SET_TIMEOUT);
+ dbg("%s - usb_control_msg - MTOUCHUSB_ASYNC_REPORT - bytes|err: %d",
+ __FUNCTION__, nRet);
+
+ printk(KERN_INFO "input: %s on %s\n", mtouch->name, path);
+ usb_set_intfdata(intf, mtouch);
+
+ return 0;
}
static void mtouchusb_disconnect(struct usb_interface *intf)
{
- struct mtouch_usb *mtouch = usb_get_intfdata (intf);
-
- dbg("%s - called", __FUNCTION__);
- usb_set_intfdata(intf, NULL);
- if (mtouch) {
- dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
- usb_kill_urb(mtouch->irq);
- input_unregister_device(&mtouch->input);
- usb_free_urb(mtouch->irq);
- mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
- kfree(mtouch);
- }
+ struct mtouch_usb *mtouch = usb_get_intfdata(intf);
+
+ dbg("%s - called", __FUNCTION__);
+ usb_set_intfdata(intf, NULL);
+ if (mtouch) {
+ dbg("%s - mtouch is initialized, cleaning up", __FUNCTION__);
+ usb_kill_urb(mtouch->irq);
+ input_unregister_device(&mtouch->input);
+ usb_free_urb(mtouch->irq);
+ mtouchusb_free_buffers(interface_to_usbdev(intf), mtouch);
+ kfree(mtouch);
+ }
}
-MODULE_DEVICE_TABLE (usb, mtouchusb_devices);
+MODULE_DEVICE_TABLE(usb, mtouchusb_devices);
static struct usb_driver mtouchusb_driver = {
- .owner = THIS_MODULE,
- .name = "mtouchusb",
- .probe = mtouchusb_probe,
- .disconnect = mtouchusb_disconnect,
- .id_table = mtouchusb_devices,
+ .owner = THIS_MODULE,
+ .name = "mtouchusb",
+ .probe = mtouchusb_probe,
+ .disconnect = mtouchusb_disconnect,
+ .id_table = mtouchusb_devices,
};
-static int __init mtouchusb_init(void) {
- dbg("%s - called", __FUNCTION__);
- return usb_register(&mtouchusb_driver);
+static int __init mtouchusb_init(void)
+{
+ dbg("%s - called", __FUNCTION__);
+ return usb_register(&mtouchusb_driver);
}
-static void __exit mtouchusb_cleanup(void) {
- dbg("%s - called", __FUNCTION__);
- usb_deregister(&mtouchusb_driver);
+static void __exit mtouchusb_cleanup(void)
+{
+ dbg("%s - called", __FUNCTION__);
+ usb_deregister(&mtouchusb_driver);
}
module_init(mtouchusb_init);
module_exit(mtouchusb_cleanup);
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c
index 7fa2f9b9fb69..3975b309d55f 100644
--- a/drivers/usb/input/powermate.c
+++ b/drivers/usb/input/powermate.c
@@ -10,7 +10,7 @@
* back to the host when polled by the USB controller.
*
* Testing with the knob I have has shown that it measures approximately 94 "clicks"
- * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
+ * for one full rotation. Testing with my High Speed Rotation Actuator (ok, it was
* a variable speed cordless electric drill) has shown that the device can measure
* speeds of up to 7 clicks either clockwise or anticlockwise between pollings from
* the host. If it counts more than 7 clicks before it is polled, it will wrap back
@@ -120,9 +120,9 @@ exit:
/* Decide if we need to issue a control message and do so. Must be called with pm->lock taken */
static void powermate_sync_state(struct powermate_device *pm)
{
- if (pm->requires_update == 0)
+ if (pm->requires_update == 0)
return; /* no updates are required */
- if (pm->config->status == -EINPROGRESS)
+ if (pm->config->status == -EINPROGRESS)
return; /* an update is already in progress; it'll issue this update when it completes */
if (pm->requires_update & UPDATE_PULSE_ASLEEP){
@@ -142,7 +142,7 @@ static void powermate_sync_state(struct powermate_device *pm)
2: multiply the speed
the argument only has an effect for operations 0 and 2, and ranges between
1 (least effect) to 255 (maximum effect).
-
+
thus, several states are equivalent and are coalesced into one state.
we map this onto a range from 0 to 510, with:
@@ -151,7 +151,7 @@ static void powermate_sync_state(struct powermate_device *pm)
256 -- 510 -- use multiple (510 = fastest).
Only values of 'arg' quite close to 255 are particularly useful/spectacular.
- */
+ */
if (pm->pulse_speed < 255){
op = 0; // divide
arg = 255 - pm->pulse_speed;
@@ -199,14 +199,14 @@ static void powermate_config_complete(struct urb *urb, struct pt_regs *regs)
if (urb->status)
printk(KERN_ERR "powermate: config urb returned %d\n", urb->status);
-
+
spin_lock_irqsave(&pm->lock, flags);
powermate_sync_state(pm);
spin_unlock_irqrestore(&pm->lock, flags);
}
/* Set the LED up as described and begin the sync with the hardware if required */
-static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
+static void powermate_pulse_led(struct powermate_device *pm, int static_brightness, int pulse_speed,
int pulse_table, int pulse_asleep, int pulse_awake)
{
unsigned long flags;
@@ -229,7 +229,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
/* mark state updates which are required */
if (static_brightness != pm->static_brightness){
pm->static_brightness = static_brightness;
- pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
+ pm->requires_update |= UPDATE_STATIC_BRIGHTNESS;
}
if (pulse_asleep != pm->pulse_asleep){
pm->pulse_asleep = pulse_asleep;
@@ -246,7 +246,7 @@ static void powermate_pulse_led(struct powermate_device *pm, int static_brightne
}
powermate_sync_state(pm);
-
+
spin_unlock_irqrestore(&pm->lock, flags);
}
@@ -257,19 +257,19 @@ static int powermate_input_event(struct input_dev *dev, unsigned int type, unsig
struct powermate_device *pm = dev->private;
if (type == EV_MSC && code == MSC_PULSELED){
- /*
+ /*
bits 0- 7: 8 bits: LED brightness
bits 8-16: 9 bits: pulsing speed modifier (0 ... 510); 0-254 = slower, 255 = standard, 256-510 = faster.
bits 17-18: 2 bits: pulse table (0, 1, 2 valid)
bit 19: 1 bit : pulse whilst asleep?
bit 20: 1 bit : pulse constantly?
- */
+ */
int static_brightness = command & 0xFF; // bits 0-7
int pulse_speed = (command >> 8) & 0x1FF; // bits 8-16
int pulse_table = (command >> 17) & 0x3; // bits 17-18
int pulse_asleep = (command >> 19) & 0x1; // bit 19
int pulse_awake = (command >> 20) & 0x1; // bit 20
-
+
powermate_pulse_led(pm, static_brightness, pulse_speed, pulse_table, pulse_asleep, pulse_awake);
}
@@ -378,7 +378,7 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
switch (le16_to_cpu(udev->descriptor.idProduct)) {
case POWERMATE_PRODUCT_NEW: pm->input.name = pm_name_powermate; break;
case POWERMATE_PRODUCT_OLD: pm->input.name = pm_name_soundknob; break;
- default:
+ default:
pm->input.name = pm_name_soundknob;
printk(KERN_WARNING "powermate: unknown product id %04x\n",
le16_to_cpu(udev->descriptor.idProduct));
@@ -402,11 +402,11 @@ static int powermate_probe(struct usb_interface *intf, const struct usb_device_i
usb_make_path(udev, path, 64);
snprintf(pm->phys, 64, "%s/input0", path);
printk(KERN_INFO "input: %s on %s\n", pm->input.name, pm->input.phys);
-
+
/* force an update of everything */
pm->requires_update = UPDATE_PULSE_ASLEEP | UPDATE_PULSE_AWAKE | UPDATE_PULSE_MODE | UPDATE_STATIC_BRIGHTNESS;
powermate_pulse_led(pm, 0x80, 255, 0, 1, 0); // set default pulse parameters
-
+
usb_set_intfdata(intf, pm);
return 0;
}
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index a71f1bbd0a17..386595ee21c0 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -69,7 +69,6 @@ struct touchkit_usb {
struct urb *irq;
struct usb_device *udev;
struct input_dev input;
- int open;
char name[128];
char phys[64];
};
@@ -134,15 +133,10 @@ static int touchkit_open(struct input_dev *input)
{
struct touchkit_usb *touchkit = input->private;
- if (touchkit->open++)
- return 0;
-
touchkit->irq->dev = touchkit->udev;
- if (usb_submit_urb(touchkit->irq, GFP_ATOMIC)) {
- touchkit->open--;
+ if (usb_submit_urb(touchkit->irq, GFP_ATOMIC))
return -EIO;
- }
return 0;
}
@@ -151,8 +145,7 @@ static void touchkit_close(struct input_dev *input)
{
struct touchkit_usb *touchkit = input->private;
- if (!--touchkit->open)
- usb_kill_urb(touchkit->irq);
+ usb_kill_urb(touchkit->irq);
}
static int touchkit_alloc_buffers(struct usb_device *udev,
diff --git a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
index 7038fb9d1ced..f35db1974c42 100644
--- a/drivers/usb/input/usbkbd.c
+++ b/drivers/usb/input/usbkbd.c
@@ -9,18 +9,18 @@
/*
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -72,7 +72,6 @@ struct usb_kbd {
unsigned char newleds;
char name[128];
char phys[64];
- int open;
unsigned char *new;
struct usb_ctrlrequest *cr;
@@ -166,7 +165,7 @@ static void usb_kbd_led(struct urb *urb, struct pt_regs *regs)
if (urb->status)
warn("led urb status %d received", urb->status);
-
+
if (*(kbd->leds) == kbd->newleds)
return;
@@ -180,14 +179,9 @@ static int usb_kbd_open(struct input_dev *dev)
{
struct usb_kbd *kbd = dev->private;
- if (kbd->open++)
- return 0;
-
kbd->irq->dev = kbd->usbdev;
- if (usb_submit_urb(kbd->irq, GFP_KERNEL)) {
- kbd->open--;
+ if (usb_submit_urb(kbd->irq, GFP_KERNEL))
return -EIO;
- }
return 0;
}
@@ -196,8 +190,7 @@ static void usb_kbd_close(struct input_dev *dev)
{
struct usb_kbd *kbd = dev->private;
- if (!--kbd->open)
- usb_kill_urb(kbd->irq);
+ usb_kill_urb(kbd->irq);
}
static int usb_kbd_alloc_mem(struct usb_device *dev, struct usb_kbd *kbd)
@@ -230,7 +223,7 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
}
-static int usb_kbd_probe(struct usb_interface *iface,
+static int usb_kbd_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
struct usb_device * dev = interface_to_usbdev(iface);
@@ -272,7 +265,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
for (i = 0; i < 255; i++)
set_bit(usb_kbd_keycode[i], kbd->dev.keybit);
clear_bit(0, kbd->dev.keybit);
-
+
kbd->dev.private = kbd;
kbd->dev.event = usb_kbd_event;
kbd->dev.open = usb_kbd_open;
@@ -294,7 +287,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
sprintf(kbd->phys, "%s/input0", path);
kbd->dev.name = kbd->name;
- kbd->dev.phys = kbd->phys;
+ kbd->dev.phys = kbd->phys;
kbd->dev.id.bustype = BUS_USB;
kbd->dev.id.vendor = le16_to_cpu(dev->descriptor.idVendor);
kbd->dev.id.product = le16_to_cpu(dev->descriptor.idProduct);
@@ -329,7 +322,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
static void usb_kbd_disconnect(struct usb_interface *intf)
{
struct usb_kbd *kbd = usb_get_intfdata (intf);
-
+
usb_set_intfdata(intf, NULL);
if (kbd) {
usb_kill_urb(kbd->irq);
diff --git a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c
index 01155bbddd43..1ec41b5effe6 100644
--- a/drivers/usb/input/usbmouse.c
+++ b/drivers/usb/input/usbmouse.c
@@ -9,18 +9,18 @@
/*
* 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 <vojtech@ucw.cz>, or by paper mail:
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
@@ -51,7 +51,6 @@ struct usb_mouse {
struct usb_device *usbdev;
struct input_dev dev;
struct urb *irq;
- int open;
signed char *data;
dma_addr_t data_dma;
@@ -101,14 +100,9 @@ static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;
- if (mouse->open++)
- return 0;
-
mouse->irq->dev = mouse->usbdev;
- if (usb_submit_urb(mouse->irq, GFP_KERNEL)) {
- mouse->open--;
+ if (usb_submit_urb(mouse->irq, GFP_KERNEL))
return -EIO;
- }
return 0;
}
@@ -117,8 +111,7 @@ static void usb_mouse_close(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;
- if (!--mouse->open)
- usb_kill_urb(mouse->irq);
+ usb_kill_urb(mouse->irq);
}
static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_id * id)
@@ -132,19 +125,19 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
interface = intf->cur_altsetting;
- if (interface->desc.bNumEndpoints != 1)
+ if (interface->desc.bNumEndpoints != 1)
return -ENODEV;
endpoint = &interface->endpoint[0].desc;
- if (!(endpoint->bEndpointAddress & 0x80))
+ if (!(endpoint->bEndpointAddress & 0x80))
return -ENODEV;
- if ((endpoint->bmAttributes & 3) != 3)
+ if ((endpoint->bmAttributes & 3) != 3)
return -ENODEV;
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
- if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
+ if (!(mouse = kmalloc(sizeof(struct usb_mouse), GFP_KERNEL)))
return -ENOMEM;
memset(mouse, 0, sizeof(struct usb_mouse));
@@ -209,7 +202,7 @@ static int usb_mouse_probe(struct usb_interface * intf, const struct usb_device_
static void usb_mouse_disconnect(struct usb_interface *intf)
{
struct usb_mouse *mouse = usb_get_intfdata (intf);
-
+
usb_set_intfdata(intf, NULL);
if (mouse) {
usb_kill_urb(mouse->irq);
@@ -238,7 +231,7 @@ static struct usb_driver usb_mouse_driver = {
static int __init usb_mouse_init(void)
{
int retval = usb_register(&usb_mouse_driver);
- if (retval == 0)
+ if (retval == 0)
info(DRIVER_VERSION ":" DRIVER_DESC);
return retval;
}
diff --git a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c
index fec04dda088e..f6b34af66b3d 100644
--- a/drivers/usb/input/wacom.c
+++ b/drivers/usb/input/wacom.c
@@ -9,7 +9,7 @@
* Copyright (c) 2000 Daniel Egger <egger@suse.de>
* Copyright (c) 2001 Frederic Lepied <flepied@mandrakesoft.com>
* Copyright (c) 2004 Panagiotis Issaris <panagiotis.issaris@mech.kuleuven.ac.be>
- * Copyright (c) 2002-2004 Ping Cheng <pingc@wacom.com>
+ * Copyright (c) 2002-2005 Ping Cheng <pingc@wacom.com>
*
* ChangeLog:
* v0.1 (vp) - Initial release
@@ -18,7 +18,7 @@
* v0.4 (sm) - Support for more Intuos models, menustrip
* relative mode, proximity.
* v0.5 (vp) - Big cleanup, nifty features removed,
- * they belong in userspace
+ * they belong in userspace
* v1.8 (vp) - Submit URB only when operating, moved to CVS,
* use input_report_key instead of report_btn and
* other cleanups
@@ -51,6 +51,9 @@
* - Cleanups here and there
* v1.30.1 (pi) - Added Graphire3 support
* v1.40 (pc) - Add support for several new devices, fix eraser reporting, ...
+ * v1.43 (pc) - Added support for Cintiq 21UX
+ - Fixed a Graphire bug
+ - Merged wacom_intuos3_irq into wacom_intuos_irq
*/
/*
@@ -72,7 +75,7 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.40"
+#define DRIVER_VERSION "v1.43"
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>"
#define DRIVER_DESC "USB Wacom Graphire and Wacom Intuos tablet driver"
#define DRIVER_LICENSE "GPL"
@@ -83,6 +86,16 @@ MODULE_LICENSE(DRIVER_LICENSE);
#define USB_VENDOR_ID_WACOM 0x056a
+enum {
+ PENPARTNER = 0,
+ GRAPHIRE,
+ PL,
+ INTUOS,
+ INTUOS3,
+ CINTIQ,
+ MAX_TYPE
+};
+
struct wacom_features {
char *name;
int pktlen;
@@ -102,7 +115,6 @@ struct wacom {
struct urb *irq;
struct wacom_features *features;
int tool[2];
- int open;
__u32 serial[2];
char phys[32];
};
@@ -149,7 +161,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
prox = data[1] & 0x40;
input_regs(dev, regs);
-
+
if (prox) {
pressure = (signed char)((data[7] << 1) | ((data[4] >> 2) & 1));
@@ -166,8 +178,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
if (!wacom->tool[0]) {
/* Going into proximity select tool */
wacom->tool[1] = (data[4] & 0x20)? BTN_TOOL_RUBBER : BTN_TOOL_PEN;
- }
- else {
+ } else {
/* was entered with stylus2 pressed */
if (wacom->tool[1] == BTN_TOOL_RUBBER && !(data[4] & 0x20) ) {
/* report out proximity for previous tool */
@@ -182,16 +193,15 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
wacom->tool[1] = BTN_TOOL_PEN;
}
input_report_key(dev, wacom->tool[1], prox); /* report in proximity for tool */
- input_report_abs(dev, ABS_X, data[3] | ((__u32)data[2] << 7) | ((__u32)(data[1] & 0x03) << 14));
- input_report_abs(dev, ABS_Y, data[6] | ((__u32)data[5] << 7) | ((__u32)(data[4] & 0x03) << 14));
+ input_report_abs(dev, ABS_X, data[3] | (data[2] << 7) | ((data[1] & 0x03) << 14));
+ input_report_abs(dev, ABS_Y, data[6] | (data[5] << 7) | ((data[4] & 0x03) << 14));
input_report_abs(dev, ABS_PRESSURE, pressure);
input_report_key(dev, BTN_TOUCH, data[4] & 0x08);
input_report_key(dev, BTN_STYLUS, data[4] & 0x10);
/* Only allow the stylus2 button to be reported for the pen tool. */
input_report_key(dev, BTN_STYLUS2, (wacom->tool[1] == BTN_TOOL_PEN) && (data[4] & 0x20));
- }
- else {
+ } else {
/* report proximity-out of a (valid) tool */
if (wacom->tool[1] != BTN_TOOL_RUBBER) {
/* Unknown tool selected default to pen tool */
@@ -203,7 +213,7 @@ static void wacom_pl_irq(struct urb *urb, struct pt_regs *regs)
wacom->tool[0] = prox; /* Save proximity state */
input_sync(dev);
-exit:
+ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
@@ -232,20 +242,16 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- if (data[0] != 2)
- {
+ if (data[0] != 2) {
printk(KERN_INFO "wacom_ptu_irq: received unknown report #%d\n", data[0]);
goto exit;
}
input_regs(dev, regs);
- if (data[1] & 0x04)
- {
+ if (data[1] & 0x04) {
input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x20);
input_report_key(dev, BTN_TOUCH, data[1] & 0x08);
- }
- else
- {
+ } else {
input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x20);
input_report_key(dev, BTN_TOUCH, data[1] & 0x01);
}
@@ -257,7 +263,7 @@ static void wacom_ptu_irq(struct urb *urb, struct pt_regs *regs)
input_sync(dev);
-exit:
+ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
@@ -300,7 +306,7 @@ static void wacom_penpartner_irq(struct urb *urb, struct pt_regs *regs)
input_report_key(dev, BTN_STYLUS, (data[5] & 0x40));
input_sync(dev);
-exit:
+ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
@@ -340,47 +346,47 @@ static void wacom_graphire_irq(struct urb *urb, struct pt_regs *regs)
input_regs(dev, regs);
- switch ((data[1] >> 5) & 3) {
+ if (data[1] & 0x10) { /* in prox */
- case 0: /* Pen */
- input_report_key(dev, BTN_TOOL_PEN, data[1] & 0x80);
- break;
+ switch ((data[1] >> 5) & 3) {
- case 1: /* Rubber */
- input_report_key(dev, BTN_TOOL_RUBBER, data[1] & 0x80);
- break;
-
- case 2: /* Mouse with wheel */
- input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
- input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
- /* fall through */
+ case 0: /* Pen */
+ wacom->tool[0] = BTN_TOOL_PEN;
+ break;
- case 3: /* Mouse without wheel */
- input_report_key(dev, BTN_TOOL_MOUSE, data[7] > 24);
- input_report_key(dev, BTN_LEFT, data[1] & 0x01);
- input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
- input_report_abs(dev, ABS_DISTANCE, data[7]);
+ case 1: /* Rubber */
+ wacom->tool[0] = BTN_TOOL_RUBBER;
+ break;
- input_report_abs(dev, ABS_X, x);
- input_report_abs(dev, ABS_Y, y);
+ case 2: /* Mouse with wheel */
+ input_report_key(dev, BTN_MIDDLE, data[1] & 0x04);
+ input_report_rel(dev, REL_WHEEL, (signed char) data[6]);
+ /* fall through */
- input_sync(dev);
- goto exit;
+ case 3: /* Mouse without wheel */
+ wacom->tool[0] = BTN_TOOL_MOUSE;
+ input_report_key(dev, BTN_LEFT, data[1] & 0x01);
+ input_report_key(dev, BTN_RIGHT, data[1] & 0x02);
+ input_report_abs(dev, ABS_DISTANCE, data[7]);
+ break;
+ }
}
if (data[1] & 0x80) {
input_report_abs(dev, ABS_X, x);
input_report_abs(dev, ABS_Y, y);
}
+ if (wacom->tool[0] != BTN_TOOL_MOUSE) {
+ 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);
+ }
- 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);
-
+ input_report_key(dev, wacom->tool[0], data[1] & 0x10);
input_sync(dev);
-exit:
+ exit:
retval = usb_submit_urb (urb, GFP_ATOMIC);
if (retval)
err ("%s - usb_submit_urb failed with result %d",
@@ -398,14 +404,13 @@ static int wacom_intuos_inout(struct urb *urb)
idx = data[1] & 0x01;
/* Enter report */
- if ((data[1] & 0xfc) == 0xc0)
- {
+ if ((data[1] & 0xfc) == 0xc0) {
/* serial number of the tool */
- wacom->serial[idx] = ((__u32)(data[3] & 0x0f) << 28) +
- ((__u32)data[4] << 20) + ((__u32)data[5] << 12) +
- ((__u32)data[6] << 4) + (data[7] >> 4);
+ wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
+ (data[4] << 20) + (data[5] << 12) +
+ (data[6] << 4) + (data[7] >> 4);
- switch (((__u32)data[2] << 4) | (data[3] >> 4)) {
+ switch ((data[2] << 4) | (data[3] >> 4)) {
case 0x812: /* Inking pen */
case 0x801: /* Intuos3 Inking pen */
case 0x012:
@@ -449,7 +454,7 @@ static int wacom_intuos_inout(struct urb *urb)
case 0x112:
case 0x913: /* Intuos3 Airbrush */
wacom->tool[idx] = BTN_TOOL_AIRBRUSH;
- break; /* Airbrush */
+ break;
default: /* Unknown tool */
wacom->tool[idx] = BTN_TOOL_PEN;
}
@@ -478,9 +483,8 @@ static void wacom_intuos_general(struct urb *urb)
unsigned int t;
/* general pen packet */
- if ((data[1] & 0xb8) == 0xa0)
- {
- t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
+ if ((data[1] & 0xb8) == 0xa0) {
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
input_report_abs(dev, ABS_PRESSURE, t);
input_report_abs(dev, ABS_TILT_X,
((data[7] << 1) & 0x7e) | (data[8] >> 7));
@@ -491,10 +495,9 @@ static void wacom_intuos_general(struct urb *urb)
}
/* airbrush second packet */
- if ((data[1] & 0xbc) == 0xb4)
- {
+ if ((data[1] & 0xbc) == 0xb4) {
input_report_abs(dev, ABS_WHEEL,
- ((__u32)data[6] << 2) | ((data[7] >> 6) & 3));
+ (data[6] << 2) | ((data[7] >> 6) & 3));
input_report_abs(dev, ABS_TILT_X,
((data[7] << 1) & 0x7e) | (data[8] >> 7));
input_report_abs(dev, ABS_TILT_Y, data[8] & 0x7f);
@@ -526,7 +529,7 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
goto exit;
}
- if (data[0] != 2 && data[0] != 5 && data[0] != 6) {
+ if (data[0] != 2 && data[0] != 5 && data[0] != 6 && data[0] != 12) {
dbg("wacom_intuos_irq: received unknown report #%d", data[0]);
goto exit;
}
@@ -536,107 +539,10 @@ static void wacom_intuos_irq(struct urb *urb, struct pt_regs *regs)
/* tool number */
idx = data[1] & 0x01;
- /* process in/out prox events */
- if (wacom_intuos_inout(urb)) goto exit;
-
- 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]);
-
- /* process general packets */
- wacom_intuos_general(urb);
-
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) { /* 4D mouse or Lens cursor packets */
-
- if (data[1] & 0x02) { /* Rotation packet */
-
- t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
- input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ? ((t - 1) / 2) : -t / 2);
-
- } else {
-
- if ((data[1] & 0x10) == 0) { /* 4D mouse packets */
-
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
-
- input_report_key(dev, BTN_SIDE, data[8] & 0x20);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
- t = ((__u32)data[6] << 2) | ((data[7] >> 6) & 3);
- input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
-
- } else {
- if (wacom->tool[idx] == BTN_TOOL_MOUSE) { /* 2D mouse packets */
- input_report_key(dev, BTN_LEFT, data[8] & 0x04);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
- input_report_rel(dev, REL_WHEEL,
- (-(__u32)(data[8] & 0x01) + (__u32)((data[8] & 0x02) >> 1)));
- }
- else { /* Lens cursor packets */
- input_report_key(dev, BTN_LEFT, data[8] & 0x01);
- input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
- input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
- input_report_key(dev, BTN_SIDE, data[8] & 0x10);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
- }
- }
- }
- }
-
- input_report_key(dev, wacom->tool[idx], 1);
- input_event(dev, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
- input_sync(dev);
-
-exit:
- retval = usb_submit_urb (urb, GFP_ATOMIC);
- if (retval)
- err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, retval);
-}
-
-static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
-{
- struct wacom *wacom = urb->context;
- unsigned char *data = wacom->data;
- struct input_dev *dev = &wacom->dev;
- unsigned int t;
- int idx, retval;
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
- goto exit;
- }
-
- /* check for valid report */
- if (data[0] != 2 && data[0] != 5 && data[0] != 12)
- {
- printk(KERN_INFO "wacom_intuos3_irq: received unknown report #%d\n", data[0]);
- goto exit;
- }
-
- input_regs(dev, regs);
-
- /* tool index is always 0 here since there is no dual input tool */
- idx = data[1] & 0x01;
-
/* pad packets. Works as a second tool and is always in prox */
- if (data[0] == 12)
- {
+ if (data[0] == 12) {
/* initiate the pad as a device */
- if (wacom->tool[1] != BTN_TOOL_FINGER)
- {
+ if (wacom->tool[1] != BTN_TOOL_FINGER) {
wacom->tool[1] = BTN_TOOL_FINGER;
input_report_key(dev, wacom->tool[1], 1);
}
@@ -656,37 +562,78 @@ static void wacom_intuos3_irq(struct urb *urb, struct pt_regs *regs)
}
/* process in/out prox events */
- if (wacom_intuos_inout(urb)) goto exit;
+ if (wacom_intuos_inout(urb))
+ goto exit;
- input_report_abs(dev, ABS_X, ((__u32)data[2] << 9) | ((__u32)data[3] << 1) | ((data[9] >> 1) & 1));
- input_report_abs(dev, ABS_Y, ((__u32)data[4] << 9) | ((__u32)data[5] << 1) | (data[9] & 1));
- input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+ /* Cintiq doesn't send data when RDY bit isn't set */
+ if ((wacom->features->type == CINTIQ) && !(data[1] & 0x40))
+ return;
+
+ if (wacom->features->type >= INTUOS3) {
+ input_report_abs(dev, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
+ input_report_abs(dev, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
+ input_report_abs(dev, ABS_DISTANCE, ((data[9] >> 2) & 0x3f));
+ } else {
+ 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] >> 3) & 0x1f));
+ }
/* process general packets */
wacom_intuos_general(urb);
- if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0)
- {
- /* Marker pen rotation packet. Reported as wheel due to valuator limitation */
- if (data[1] & 0x02)
- {
- t = ((__u32)data[6] << 3) | ((data[7] >> 5) & 7);
- t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
- ((t-1) / 2 + 450)) : (450 - t / 2) ;
- input_report_abs(dev, ABS_WHEEL, t);
- }
+ /* 4D mouse, 2D mouse, marker pen rotation, or Lens cursor packets */
+ if ((data[1] & 0xbc) == 0xa8 || (data[1] & 0xbe) == 0xb0) {
+
+ if (data[1] & 0x02) {
+ /* Rotation packet */
+ if (wacom->features->type >= INTUOS3) {
+ /* I3 marker pen rotation reported as wheel
+ * due to valuator limitation
+ */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ t = (data[7] & 0x20) ? ((t > 900) ? ((t-1) / 2 - 1350) :
+ ((t-1) / 2 + 450)) : (450 - t / 2) ;
+ input_report_abs(dev, ABS_WHEEL, t);
+ } else {
+ /* 4D mouse rotation packet */
+ t = (data[6] << 3) | ((data[7] >> 5) & 7);
+ input_report_abs(dev, ABS_RZ, (data[7] & 0x20) ?
+ ((t - 1) / 2) : -t / 2);
+ }
- /* 2D mouse packets */
- if (wacom->tool[idx] == BTN_TOOL_MOUSE)
- {
+ } else if (!(data[1] & 0x10) && wacom->features->type < INTUOS3) {
+ /* 4D mouse packet */
+ input_report_key(dev, BTN_LEFT, data[8] & 0x01);
+ input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
+
+ input_report_key(dev, BTN_SIDE, data[8] & 0x20);
+ input_report_key(dev, BTN_EXTRA, data[8] & 0x10);
+ t = (data[6] << 2) | ((data[7] >> 6) & 3);
+ input_report_abs(dev, ABS_THROTTLE, (data[8] & 0x08) ? -t : t);
+
+ } else if (wacom->tool[idx] == BTN_TOOL_MOUSE) {
+ /* 2D mouse packet */
input_report_key(dev, BTN_LEFT, data[8] & 0x04);
input_report_key(dev, BTN_MIDDLE, data[8] & 0x08);
input_report_key(dev, BTN_RIGHT, data[8] & 0x10);
- input_report_key(dev, BTN_SIDE, data[8] & 0x40);
- input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
- /* mouse wheel is positive when rolled backwards */
- input_report_rel(dev, REL_WHEEL, ((__u32)((data[8] & 0x02) >> 1)
- - (__u32)(data[8] & 0x01)));
+ input_report_rel(dev, REL_WHEEL, ((data[8] & 0x02) >> 1)
+ - (data[8] & 0x01));
+
+ /* I3 2D mouse side buttons */
+ if (wacom->features->type == INTUOS3) {
+ input_report_key(dev, BTN_SIDE, data[8] & 0x40);
+ input_report_key(dev, BTN_EXTRA, data[8] & 0x20);
+ }
+
+ } else if (wacom->features->type < INTUOS3) {
+ /* Lens cursor packets */
+ input_report_key(dev, BTN_LEFT, data[8] & 0x01);
+ input_report_key(dev, BTN_MIDDLE, data[8] & 0x02);
+ input_report_key(dev, BTN_RIGHT, data[8] & 0x04);
+ input_report_key(dev, BTN_SIDE, data[8] & 0x10);
+ input_report_key(dev, BTN_EXTRA, data[8] & 0x08);
}
}
@@ -702,35 +649,36 @@ exit:
}
static struct wacom_features wacom_features[] = {
- { "Wacom Penpartner", 7, 5040, 3780, 255, 32, 0, wacom_penpartner_irq },
- { "Wacom Graphire", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Graphire3", 8, 10208, 7424, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom PL400", 8, 5408, 4056, 255, 32, 3, wacom_pl_irq },
- { "Wacom PL500", 8, 6144, 4608, 255, 32, 3, wacom_pl_irq },
- { "Wacom PL600", 8, 6126, 4604, 255, 32, 3, wacom_pl_irq },
- { "Wacom PL600SX", 8, 6260, 5016, 255, 32, 3, wacom_pl_irq },
- { "Wacom PL550", 8, 6144, 4608, 511, 32, 3, wacom_pl_irq },
- { "Wacom PL800", 8, 7220, 5780, 511, 32, 3, wacom_pl_irq },
- { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, 2, wacom_intuos_irq },
- { "Wacom Volito", 8, 5104, 3712, 511, 32, 1, wacom_graphire_irq },
- { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, 3, wacom_ptu_irq },
- { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, 4, wacom_intuos3_irq },
- { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, 4, wacom_intuos3_irq },
- { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, 4, wacom_intuos3_irq },
- { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, 2, wacom_intuos_irq },
- { }
+ { "Wacom Penpartner", 7, 5040, 3780, 255, 32, PENPARTNER, wacom_penpartner_irq },
+ { "Wacom Graphire", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Graphire2 4x5", 8, 10206, 7422, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Graphire2 5x7", 8, 13918, 10206, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Graphire3", 8, 10208, 7424, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Graphire3 6x8", 8, 16704, 12064, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Intuos 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom PL400", 8, 5408, 4056, 255, 32, PL, wacom_pl_irq },
+ { "Wacom PL500", 8, 6144, 4608, 255, 32, PL, wacom_pl_irq },
+ { "Wacom PL600", 8, 6126, 4604, 255, 32, PL, wacom_pl_irq },
+ { "Wacom PL600SX", 8, 6260, 5016, 255, 32, PL, wacom_pl_irq },
+ { "Wacom PL550", 8, 6144, 4608, 511, 32, PL, wacom_pl_irq },
+ { "Wacom PL800", 8, 7220, 5780, 511, 32, PL, wacom_pl_irq },
+ { "Wacom Intuos2 4x5", 10, 12700, 10600, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos2 9x12", 10, 30480, 24060, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos2 12x12", 10, 30480, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Intuos2 12x18", 10, 45720, 31680, 1023, 15, INTUOS, wacom_intuos_irq },
+ { "Wacom Volito", 8, 5104, 3712, 511, 32, GRAPHIRE, wacom_graphire_irq },
+ { "Wacom Cintiq Partner",8, 20480, 15360, 511, 32, PL, wacom_ptu_irq },
+ { "Wacom Intuos3 4x5", 10, 25400, 20320, 1023, 15, INTUOS3, wacom_intuos_irq },
+ { "Wacom Intuos3 6x8", 10, 40640, 30480, 1023, 15, INTUOS3, wacom_intuos_irq },
+ { "Wacom Intuos3 9x12", 10, 60960, 45720, 1023, 15, INTUOS3, wacom_intuos_irq },
+ { "Wacom Cintiq 21UX", 10, 87200, 65600, 1023, 15, CINTIQ, wacom_intuos_irq },
+ { "Wacom Intuos2 6x8", 10, 20320, 16240, 1023, 15, INTUOS, wacom_intuos_irq },
+ { }
};
static struct usb_device_id wacom_ids[] = {
@@ -761,6 +709,7 @@ static struct usb_device_id wacom_ids[] = {
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB0) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB1) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0xB2) },
+ { USB_DEVICE(USB_VENDOR_ID_WACOM, 0x3F) },
{ USB_DEVICE(USB_VENDOR_ID_WACOM, 0x47) },
{ }
};
@@ -771,14 +720,9 @@ static int wacom_open(struct input_dev *dev)
{
struct wacom *wacom = dev->private;
- if (wacom->open++)
- return 0;
-
wacom->irq->dev = wacom->usbdev;
- if (usb_submit_urb(wacom->irq, GFP_KERNEL)) {
- wacom->open--;
+ if (usb_submit_urb(wacom->irq, GFP_KERNEL))
return -EIO;
- }
return 0;
}
@@ -787,8 +731,7 @@ static void wacom_close(struct input_dev *dev)
{
struct wacom *wacom = dev->private;
- if (!--wacom->open)
- usb_kill_urb(wacom->irq);
+ usb_kill_urb(wacom->irq);
}
static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -823,32 +766,33 @@ static int wacom_probe(struct usb_interface *intf, const struct usb_device_id *i
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_PEN) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS);
switch (wacom->features->type) {
- case 1:
+ case GRAPHIRE:
wacom->dev.evbit[0] |= BIT(EV_REL);
wacom->dev.relbit[0] |= BIT(REL_WHEEL);
wacom->dev.absbit[0] |= BIT(ABS_DISTANCE);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_STYLUS2);
break;
- case 4: /* new functions for Intuos3 */
+ case INTUOS3:
+ case CINTIQ:
wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_FINGER);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_0) | BIT(BTN_1) | BIT(BTN_2) | BIT(BTN_3) | BIT(BTN_4) | BIT(BTN_5) | BIT(BTN_6) | BIT(BTN_7);
wacom->dev.absbit[0] |= BIT(ABS_RX) | BIT(ABS_RY);
/* fall through */
- case 2:
+ case INTUOS:
wacom->dev.evbit[0] |= BIT(EV_MSC) | BIT(EV_REL);
wacom->dev.mscbit[0] |= BIT(MSC_SERIAL);
wacom->dev.relbit[0] |= BIT(REL_WHEEL);
wacom->dev.keybit[LONG(BTN_LEFT)] |= BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE) | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_BRUSH)
| BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_LENS) | BIT(BTN_STYLUS2);
wacom->dev.absbit[0] |= BIT(ABS_DISTANCE) | BIT(ABS_WHEEL) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_RZ) | BIT(ABS_THROTTLE);
break;
- case 3:
- wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
+ case PL:
+ wacom->dev.keybit[LONG(BTN_DIGI)] |= BIT(BTN_STYLUS2) | BIT(BTN_TOOL_RUBBER);
break;
}
diff --git a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
index d65edb22e545..a7fa1b17dcfe 100644
--- a/drivers/usb/input/xpad.c
+++ b/drivers/usb/input/xpad.c
@@ -104,13 +104,12 @@ MODULE_DEVICE_TABLE (usb, xpad_table);
struct usb_xpad {
struct input_dev dev; /* input device interface */
struct usb_device *udev; /* usb device */
-
+
struct urb *irq_in; /* urb for interrupt in report */
unsigned char *idata; /* input data */
dma_addr_t idata_dma;
-
+
char phys[65]; /* physical device path */
- int open_count; /* reference count */
};
/*
@@ -128,35 +127,35 @@ static void xpad_process_packet(struct usb_xpad *xpad, u16 cmd, unsigned char *d
struct input_dev *dev = &xpad->dev;
input_regs(dev, regs);
-
+
/* left stick */
input_report_abs(dev, ABS_X, (__s16) (((__s16)data[13] << 8) | data[12]));
input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[15] << 8) | data[14]));
-
+
/* right stick */
input_report_abs(dev, ABS_RX, (__s16) (((__s16)data[17] << 8) | data[16]));
input_report_abs(dev, ABS_RY, (__s16) (((__s16)data[19] << 8) | data[18]));
-
+
/* triggers left/right */
input_report_abs(dev, ABS_Z, data[10]);
input_report_abs(dev, ABS_RZ, data[11]);
-
+
/* digital pad */
input_report_abs(dev, ABS_HAT0X, !!(data[2] & 0x08) - !!(data[2] & 0x04));
input_report_abs(dev, ABS_HAT0Y, !!(data[2] & 0x02) - !!(data[2] & 0x01));
-
+
/* start/back buttons and stick press left/right */
input_report_key(dev, BTN_START, (data[2] & 0x10) >> 4);
input_report_key(dev, BTN_BACK, (data[2] & 0x20) >> 5);
input_report_key(dev, BTN_THUMBL, (data[2] & 0x40) >> 6);
input_report_key(dev, BTN_THUMBR, data[2] >> 7);
-
+
/* "analog" buttons A, B, X, Y */
input_report_key(dev, BTN_A, data[4]);
input_report_key(dev, BTN_B, data[5]);
input_report_key(dev, BTN_X, data[6]);
input_report_key(dev, BTN_Y, data[7]);
-
+
/* "analog" buttons black, white */
input_report_key(dev, BTN_C, data[8]);
input_report_key(dev, BTN_Z, data[9]);
@@ -168,7 +167,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
{
struct usb_xpad *xpad = urb->context;
int retval;
-
+
switch (urb->status) {
case 0:
/* success */
@@ -183,7 +182,7 @@ static void xpad_irq_in(struct urb *urb, struct pt_regs *regs)
dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
goto exit;
}
-
+
xpad_process_packet(xpad, 0, xpad->idata, regs);
exit:
@@ -196,25 +195,19 @@ exit:
static int xpad_open (struct input_dev *dev)
{
struct usb_xpad *xpad = dev->private;
-
- if (xpad->open_count++)
- return 0;
-
+
xpad->irq_in->dev = xpad->udev;
- if (usb_submit_urb(xpad->irq_in, GFP_KERNEL)) {
- xpad->open_count--;
+ if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO;
- }
-
+
return 0;
}
static void xpad_close (struct input_dev *dev)
{
struct usb_xpad *xpad = dev->private;
-
- if (!--xpad->open_count)
- usb_kill_urb(xpad->irq_in);
+
+ usb_kill_urb(xpad->irq_in);
}
static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id)
@@ -224,19 +217,19 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
struct usb_endpoint_descriptor *ep_irq_in;
char path[64];
int i;
-
+
for (i = 0; xpad_device[i].idVendor; i++) {
if ((le16_to_cpu(udev->descriptor.idVendor) == xpad_device[i].idVendor) &&
(le16_to_cpu(udev->descriptor.idProduct) == xpad_device[i].idProduct))
break;
}
-
+
if ((xpad = kmalloc (sizeof(struct usb_xpad), GFP_KERNEL)) == NULL) {
err("cannot allocate memory for new pad");
return -ENOMEM;
}
memset(xpad, 0, sizeof(struct usb_xpad));
-
+
xpad->idata = usb_buffer_alloc(udev, XPAD_PKT_LEN,
SLAB_ATOMIC, &xpad->idata_dma);
if (!xpad->idata) {
@@ -251,18 +244,18 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
kfree(xpad);
return -ENOMEM;
}
-
+
ep_irq_in = &intf->cur_altsetting->endpoint[0].desc;
-
+
usb_fill_int_urb(xpad->irq_in, udev,
usb_rcvintpipe(udev, ep_irq_in->bEndpointAddress),
xpad->idata, XPAD_PKT_LEN, xpad_irq_in,
xpad, ep_irq_in->bInterval);
xpad->irq_in->transfer_dma = xpad->idata_dma;
xpad->irq_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
-
+
xpad->udev = udev;
-
+
xpad->dev.id.bustype = BUS_USB;
xpad->dev.id.vendor = le16_to_cpu(udev->descriptor.idVendor);
xpad->dev.id.product = le16_to_cpu(udev->descriptor.idProduct);
@@ -273,21 +266,21 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
xpad->dev.phys = xpad->phys;
xpad->dev.open = xpad_open;
xpad->dev.close = xpad_close;
-
+
usb_make_path(udev, path, 64);
snprintf(xpad->phys, 64, "%s/input0", path);
-
+
xpad->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
+
for (i = 0; xpad_btn[i] >= 0; i++)
set_bit(xpad_btn[i], xpad->dev.keybit);
-
+
for (i = 0; xpad_abs[i] >= 0; i++) {
-
+
signed short t = xpad_abs[i];
-
+
set_bit(t, xpad->dev.absbit);
-
+
switch (t) {
case ABS_X:
case ABS_Y:
@@ -310,11 +303,11 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
break;
}
}
-
+
input_register_device(&xpad->dev);
-
+
printk(KERN_INFO "input: %s on %s", xpad->dev.name, path);
-
+
usb_set_intfdata(intf, xpad);
return 0;
}
@@ -322,7 +315,7 @@ static int xpad_probe(struct usb_interface *intf, const struct usb_device_id *id
static void xpad_disconnect(struct usb_interface *intf)
{
struct usb_xpad *xpad = usb_get_intfdata (intf);
-
+
usb_set_intfdata(intf, NULL);
if (xpad) {
usb_kill_urb(xpad->irq_in);
diff --git a/drivers/usb/media/Makefile b/drivers/usb/media/Makefile
index 2b76df7005fe..d83adffa925f 100644
--- a/drivers/usb/media/Makefile
+++ b/drivers/usb/media/Makefile
@@ -2,7 +2,7 @@
# Makefile for USB Media drivers
#
-sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
+sn9c102-objs := sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
obj-$(CONFIG_USB_DABUSB) += dabusb.o
obj-$(CONFIG_USB_DSBR) += dsbr100.o
diff --git a/drivers/usb/media/sn9c102.h b/drivers/usb/media/sn9c102.h
index 8b8a4c8743f8..e5cea0e2eb57 100644
--- a/drivers/usb/media/sn9c102.h
+++ b/drivers/usb/media/sn9c102.h
@@ -56,7 +56,7 @@
#define SN9C102_MODULE_AUTHOR "(C) 2004-2005 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE "GPL"
-#define SN9C102_MODULE_VERSION "1:1.24"
+#define SN9C102_MODULE_VERSION "1:1.24a"
#define SN9C102_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 24)
enum sn9c102_bridge {
diff --git a/drivers/usb/media/sn9c102_core.c b/drivers/usb/media/sn9c102_core.c
index 31d57400d5be..cf8cfbabefde 100644
--- a/drivers/usb/media/sn9c102_core.c
+++ b/drivers/usb/media/sn9c102_core.c
@@ -429,7 +429,7 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam,
}
-static int
+int
sn9c102_i2c_try_write(struct sn9c102_device* cam,
struct sn9c102_sensor* sensor, u8 address, u8 value)
{
diff --git a/drivers/usb/media/sn9c102_ov7630.c b/drivers/usb/media/sn9c102_ov7630.c
new file mode 100644
index 000000000000..d27c5aedeaf8
--- /dev/null
+++ b/drivers/usb/media/sn9c102_ov7630.c
@@ -0,0 +1,394 @@
+/***************************************************************************
+ * Plug-in for OV7630 image sensor connected to the SN9C10x PC Camera *
+ * Controllers *
+ * *
+ * Copyright (C) 2005 by Luca Risolia <luca.risolia@studio.unibo.it> *
+ * *
+ * 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 "sn9c102_sensor.h"
+
+
+static struct sn9c102_sensor ov7630;
+
+
+static int ov7630_init(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ err += sn9c102_write_reg(cam, 0x00, 0x14);
+ err += sn9c102_write_reg(cam, 0x60, 0x17);
+ err += sn9c102_write_reg(cam, 0x0f, 0x18);
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+ err += sn9c102_i2c_write(cam, 0x12, 0x8d);
+ err += sn9c102_i2c_write(cam, 0x11, 0x00);
+ err += sn9c102_i2c_write(cam, 0x15, 0x34);
+ err += sn9c102_i2c_write(cam, 0x16, 0x03);
+ err += sn9c102_i2c_write(cam, 0x17, 0x1c);
+ err += sn9c102_i2c_write(cam, 0x18, 0xbd);
+ err += sn9c102_i2c_write(cam, 0x19, 0x06);
+ err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
+ err += sn9c102_i2c_write(cam, 0x1b, 0x04);
+ err += sn9c102_i2c_write(cam, 0x20, 0x44);
+ err += sn9c102_i2c_write(cam, 0x23, 0xee);
+ err += sn9c102_i2c_write(cam, 0x26, 0xa0);
+ err += sn9c102_i2c_write(cam, 0x27, 0x9a);
+ err += sn9c102_i2c_write(cam, 0x28, 0x20);
+ err += sn9c102_i2c_write(cam, 0x29, 0x30);
+ err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
+ err += sn9c102_i2c_write(cam, 0x30, 0x24);
+ err += sn9c102_i2c_write(cam, 0x32, 0x86);
+ err += sn9c102_i2c_write(cam, 0x60, 0xa9);
+ err += sn9c102_i2c_write(cam, 0x61, 0x42);
+ err += sn9c102_i2c_write(cam, 0x65, 0x00);
+ err += sn9c102_i2c_write(cam, 0x69, 0x38);
+ err += sn9c102_i2c_write(cam, 0x6f, 0x88);
+ err += sn9c102_i2c_write(cam, 0x70, 0x0b);
+ err += sn9c102_i2c_write(cam, 0x71, 0x00);
+ err += sn9c102_i2c_write(cam, 0x74, 0x21);
+ err += sn9c102_i2c_write(cam, 0x7d, 0xf7);
+
+ return err;
+}
+
+
+static int ov7630_set_ctrl(struct sn9c102_device* cam,
+ const struct v4l2_control* ctrl)
+{
+ int err = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ err += sn9c102_i2c_write(cam, 0x10, ctrl->value >> 2);
+ err += sn9c102_i2c_write(cam, 0x76, ctrl->value & 0x03);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
+ break;
+ case V4L2_CID_GAIN:
+ err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
+ break;
+ case V4L2_CID_CONTRAST:
+ err += ctrl->value ? sn9c102_i2c_write(cam, 0x05,
+ (ctrl->value-1) | 0x20)
+ : sn9c102_i2c_write(cam, 0x05, 0x00);
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ err += sn9c102_i2c_write(cam, 0x06, ctrl->value);
+ break;
+ case V4L2_CID_SATURATION:
+ err += sn9c102_i2c_write(cam, 0x03, ctrl->value << 4);
+ break;
+ case V4L2_CID_HUE:
+ err += ctrl->value ? sn9c102_i2c_write(cam, 0x04,
+ (ctrl->value-1) | 0x20)
+ : sn9c102_i2c_write(cam, 0x04, 0x00);
+ break;
+ case V4L2_CID_DO_WHITE_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
+ break;
+ case V4L2_CID_WHITENESS:
+ err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
+ break;
+ case V4L2_CID_VFLIP:
+ err += sn9c102_i2c_write(cam, 0x75, 0x0e | (ctrl->value << 7));
+ break;
+ case V4L2_CID_BLACK_LEVEL:
+ err += sn9c102_i2c_write(cam, 0x25, ctrl->value);
+ break;
+ case SN9C102_V4L2_CID_BRIGHT_LEVEL:
+ err += sn9c102_i2c_write(cam, 0x24, ctrl->value);
+ break;
+ case SN9C102_V4L2_CID_GAMMA:
+ err += sn9c102_i2c_write(cam, 0x14, (ctrl->value << 2) | 0x80);
+ break;
+ case SN9C102_V4L2_CID_BAND_FILTER:
+ err += sn9c102_i2c_write(cam, 0x2d, ctrl->value << 2);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return err ? -EIO : 0;
+}
+
+
+static int ov7630_set_crop(struct sn9c102_device* cam,
+ const struct v4l2_rect* rect)
+{
+ struct sn9c102_sensor* s = &ov7630;
+ int err = 0;
+ u8 v_start = (u8)(rect->top - s->cropcap.bounds.top) + 1;
+
+ err += sn9c102_write_reg(cam, v_start, 0x13);
+
+ return err;
+}
+
+
+static int ov7630_set_pix_format(struct sn9c102_device* cam,
+ const struct v4l2_pix_format* pix)
+{
+ int err = 0;
+
+ if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
+ err += sn9c102_write_reg(cam, 0x20, 0x19);
+ else
+ err += sn9c102_write_reg(cam, 0x50, 0x19);
+
+ return err;
+}
+
+
+static struct sn9c102_sensor ov7630 = {
+ .name = "OV7630",
+ .maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
+ .sysfs_ops = SN9C102_I2C_WRITE,
+ .frequency = SN9C102_I2C_100KHZ,
+ .interface = SN9C102_I2C_2WIRES,
+ .i2c_slave_id = 0x21,
+ .init = &ov7630_init,
+ .qctrl = {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "global gain",
+ .minimum = 0x00,
+ .maximum = 0x3f,
+ .step = 0x01,
+ .default_value = 0x14,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "hue",
+ .minimum = 0x00,
+ .maximum = 0x1f+1,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "saturation",
+ .minimum = 0x00,
+ .maximum = 0x0f,
+ .step = 0x01,
+ .default_value = 0x08,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "contrast",
+ .minimum = 0x00,
+ .maximum = 0x1f+1,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x000,
+ .maximum = 0x3ff,
+ .step = 0x001,
+ .default_value = 0x83<<2,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = 0x3a,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = 0x77,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "brightness",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x01,
+ .default_value = 0xa0,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_DO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "white balance background: blue",
+ .minimum = 0x00,
+ .maximum = 0x3f,
+ .step = 0x01,
+ .default_value = 0x20,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_WHITENESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "white balance background: red",
+ .minimum = 0x00,
+ .maximum = 0x3f,
+ .step = 0x01,
+ .default_value = 0x20,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x01,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain & exposure mode",
+ .minimum = 0x00,
+ .maximum = 0x03,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x01,
+ .flags = 0,
+ },
+ {
+ .id = V4L2_CID_BLACK_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "black pixel ratio",
+ .minimum = 0x01,
+ .maximum = 0x9a,
+ .step = 0x01,
+ .default_value = 0x8a,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_BRIGHT_LEVEL,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "bright pixel ratio",
+ .minimum = 0x01,
+ .maximum = 0x9a,
+ .step = 0x01,
+ .default_value = 0x10,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_BAND_FILTER,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "band filter",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ {
+ .id = SN9C102_V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "rgb gamma",
+ .minimum = 0x00,
+ .maximum = 0x01,
+ .step = 0x01,
+ .default_value = 0x00,
+ .flags = 0,
+ },
+ },
+ .set_ctrl = &ov7630_set_ctrl,
+ .cropcap = {
+ .bounds = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ .defrect = {
+ .left = 0,
+ .top = 0,
+ .width = 640,
+ .height = 480,
+ },
+ },
+ .set_crop = &ov7630_set_crop,
+ .pix_format = {
+ .width = 640,
+ .height = 480,
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .priv = 8,
+ },
+ .set_pix_format = &ov7630_set_pix_format
+};
+
+
+int sn9c102_probe_ov7630(struct sn9c102_device* cam)
+{
+ int err = 0;
+
+ sn9c102_attach_sensor(cam, &ov7630);
+
+ if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
+ le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c)
+ return -ENODEV;
+
+ err += sn9c102_write_reg(cam, 0x01, 0x01);
+ err += sn9c102_write_reg(cam, 0x00, 0x01);
+ err += sn9c102_write_reg(cam, 0x28, 0x17);
+
+ if (err)
+ return -EIO;
+
+ err += sn9c102_i2c_write(cam, 0x0b, 0);
+ if (err)
+ return -ENODEV;
+
+ return 0;
+}
diff --git a/drivers/usb/media/sn9c102_sensor.h b/drivers/usb/media/sn9c102_sensor.h
index 6a7adebcb4bf..a45166c3488c 100644
--- a/drivers/usb/media/sn9c102_sensor.h
+++ b/drivers/usb/media/sn9c102_sensor.h
@@ -64,6 +64,7 @@ struct sn9c102_sensor;
*/
extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
+extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
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);
@@ -80,6 +81,7 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
+ &sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
NULL, \
@@ -103,7 +105,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \
{ USB_DEVICE(0x0c45, 0x6029), }, /* PAS106B */ \
{ USB_DEVICE(0x0c45, 0x602a), }, /* HV7131D */ \
{ USB_DEVICE(0x0c45, 0x602b), }, /* MI-0343 */ \
- { USB_DEVICE(0x0c45, 0x602c), }, /* OV7620 */ \
+ { USB_DEVICE(0x0c45, 0x602c), }, /* OV7630 */ \
+ { USB_DEVICE(0x0c45, 0x602d), }, \
{ USB_DEVICE(0x0c45, 0x6030), }, /* MI03x */ \
{ USB_DEVICE(0x0c45, 0x6080), }, \
{ USB_DEVICE(0x0c45, 0x6082), }, /* MI0343 and MI0360 */ \
@@ -145,6 +148,8 @@ static const struct usb_device_id sn9c102_id_table[] = { \
*/
/* The "try" I2C I/O versions are used when probing the sensor */
+extern int sn9c102_i2c_try_write(struct sn9c102_device*,struct sn9c102_sensor*,
+ u8 address, u8 value);
extern int sn9c102_i2c_try_read(struct sn9c102_device*,struct sn9c102_sensor*,
u8 address);
@@ -201,6 +206,8 @@ enum sn9c102_i2c_interface {
SN9C102_I2C_3WIRES,
};
+#define SN9C102_MAX_CTRLS V4L2_CID_LASTP1-V4L2_CID_BASE+10
+
struct sn9c102_sensor {
char name[32], /* sensor name */
maintainer[64]; /* name of the mantainer <email> */
@@ -243,7 +250,7 @@ struct sn9c102_sensor {
sensor according to the default configuration structures below.
*/
- struct v4l2_queryctrl qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE];
+ struct v4l2_queryctrl qctrl[SN9C102_MAX_CTRLS];
/*
Optional list of default controls, defined as indicated in the
V4L2 API. Menu type controls are not handled by this interface.
@@ -356,7 +363,7 @@ struct sn9c102_sensor {
core module to store successfully updated values of the above
settings, for rollbacks..etc..in case of errors during atomic I/O
*/
- struct v4l2_queryctrl _qctrl[V4L2_CID_LASTP1-V4L2_CID_BASE];
+ struct v4l2_queryctrl _qctrl[SN9C102_MAX_CTRLS];
struct v4l2_rect _rect;
};
@@ -367,5 +374,8 @@ struct sn9c102_sensor {
#define SN9C102_V4L2_CID_GREEN_BALANCE V4L2_CID_PRIVATE_BASE + 1
#define SN9C102_V4L2_CID_RESET_LEVEL V4L2_CID_PRIVATE_BASE + 2
#define SN9C102_V4L2_CID_PIXEL_BIAS_VOLTAGE V4L2_CID_PRIVATE_BASE + 3
+#define SN9C102_V4L2_CID_GAMMA V4L2_CID_PRIVATE_BASE + 4
+#define SN9C102_V4L2_CID_BAND_FILTER V4L2_CID_PRIVATE_BASE + 5
+#define SN9C102_V4L2_CID_BRIGHT_LEVEL V4L2_CID_PRIVATE_BASE + 6
#endif /* _SN9C102_SENSOR_H_ */
diff --git a/drivers/usb/media/sn9c102_tas5110c1b.c b/drivers/usb/media/sn9c102_tas5110c1b.c
index 690d62192273..8775999b5aff 100644
--- a/drivers/usb/media/sn9c102_tas5110c1b.c
+++ b/drivers/usb/media/sn9c102_tas5110c1b.c
@@ -24,8 +24,6 @@
static struct sn9c102_sensor tas5110c1b;
-static struct v4l2_control tas5110c1b_gain;
-
static int tas5110c1b_init(struct sn9c102_device* cam)
{
@@ -46,21 +44,6 @@ static int tas5110c1b_init(struct sn9c102_device* cam)
}
-static int tas5110c1b_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- ctrl->value = tas5110c1b_gain.value;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
@@ -68,8 +51,7 @@ static int tas5110c1b_set_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_GAIN:
- if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
- tas5110c1b_gain.value = ctrl->value;
+ err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
break;
default:
return -EINVAL;
@@ -147,7 +129,6 @@ static struct sn9c102_sensor tas5110c1b = {
.height = 288,
},
},
- .get_ctrl = &tas5110c1b_get_ctrl,
.set_crop = &tas5110c1b_set_crop,
.pix_format = {
.width = 352,
diff --git a/drivers/usb/media/sn9c102_tas5130d1b.c b/drivers/usb/media/sn9c102_tas5130d1b.c
index b378e941bbe8..927eafdd8c73 100644
--- a/drivers/usb/media/sn9c102_tas5130d1b.c
+++ b/drivers/usb/media/sn9c102_tas5130d1b.c
@@ -24,8 +24,6 @@
static struct sn9c102_sensor tas5130d1b;
-static struct v4l2_control tas5130d1b_gain, tas5130d1b_exposure;
-
static int tas5130d1b_init(struct sn9c102_device* cam)
{
@@ -44,24 +42,6 @@ static int tas5130d1b_init(struct sn9c102_device* cam)
}
-static int tas5130d1b_get_ctrl(struct sn9c102_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_GAIN:
- ctrl->value = tas5130d1b_gain.value;
- break;
- case V4L2_CID_EXPOSURE:
- ctrl->value = tas5130d1b_exposure.value;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-
static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
@@ -69,12 +49,10 @@ static int tas5130d1b_set_ctrl(struct sn9c102_device* cam,
switch (ctrl->id) {
case V4L2_CID_GAIN:
- if (!(err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value)))
- tas5130d1b_gain.value = ctrl->value;
+ err += sn9c102_i2c_write(cam, 0x20, 0xf6 - ctrl->value);
break;
case V4L2_CID_EXPOSURE:
- if (!(err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value)))
- tas5130d1b_exposure.value = ctrl->value;
+ err += sn9c102_i2c_write(cam, 0x40, 0x47 - ctrl->value);
break;
default:
return -EINVAL;
@@ -147,7 +125,6 @@ static struct sn9c102_sensor tas5130d1b = {
.flags = 0,
},
},
- .get_ctrl = &tas5130d1b_get_ctrl,
.set_ctrl = &tas5130d1b_set_ctrl,
.cropcap = {
.bounds = {
diff --git a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c
index ae455c8e3702..7398a7f19c1e 100644
--- a/drivers/usb/media/stv680.c
+++ b/drivers/usb/media/stv680.c
@@ -1375,9 +1375,13 @@ static int stv680_probe (struct usb_interface *intf, const struct usb_device_id
(le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
camera_name = "STV0680";
PDEBUG (0, "STV(i): STV0680 camera found.");
+ } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
+ camera_name = "Creative WebCam Go Mini";
+ PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
} else {
- PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 values.");
- PDEBUG (0, "STV(e): Check that the STV0680 camera is connected to the computer.");
+ PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
+ PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
retval = -ENODEV;
goto error;
}
diff --git a/drivers/usb/media/stv680.h b/drivers/usb/media/stv680.h
index 7e0e314dcf12..445940612603 100644
--- a/drivers/usb/media/stv680.h
+++ b/drivers/usb/media/stv680.h
@@ -41,12 +41,17 @@
#define USB_PENCAM_VENDOR_ID 0x0553
#define USB_PENCAM_PRODUCT_ID 0x0202
+
+#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e
+#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007
+
#define PENCAM_TIMEOUT 1000
/* fmt 4 */
#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
static struct usb_device_id device_table[] = {
{USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
+ {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
{}
};
MODULE_DEVICE_TABLE (usb, device_table);
diff --git a/drivers/usb/misc/Kconfig b/drivers/usb/misc/Kconfig
index 3a896954b3a9..6649531fa824 100644
--- a/drivers/usb/misc/Kconfig
+++ b/drivers/usb/misc/Kconfig
@@ -139,6 +139,16 @@ config USB_IDMOUSE
source "drivers/usb/misc/sisusbvga/Kconfig"
+config USB_LD
+ tristate "USB LD driver"
+ depends on USB && EXPERIMENTAL
+ help
+ This driver is for generic USB devices that use interrupt transfers,
+ like LD Didactic's USB devices.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ldusb.
+
config USB_TEST
tristate "USB testing driver (DEVELOPMENT)"
depends on USB && USB_DEVICEFS && EXPERIMENTAL
diff --git a/drivers/usb/misc/Makefile b/drivers/usb/misc/Makefile
index 4a3814cbd48d..862e40a83689 100644
--- a/drivers/usb/misc/Makefile
+++ b/drivers/usb/misc/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_USB_EMI26) += emi26.o
obj-$(CONFIG_USB_EMI62) += emi62.o
obj-$(CONFIG_USB_IDMOUSE) += idmouse.o
obj-$(CONFIG_USB_LCD) += usblcd.o
+obj-$(CONFIG_USB_LD) += ldusb.o
obj-$(CONFIG_USB_LED) += usbled.o
obj-$(CONFIG_USB_LEGOTOWER) += legousbtower.o
obj-$(CONFIG_USB_PHIDGETKIT) += phidgetkit.o
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index ce030d1f1c1f..733acc213726 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -1,4 +1,4 @@
-/* Siemens ID Mouse driver v0.5
+/* Siemens ID Mouse driver v0.6
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -11,6 +11,9 @@
Derived from the USB Skeleton driver 1.1,
Copyright (C) 2003 Greg Kroah-Hartman (greg@kroah.com)
+ Additional information provided by Martin Reising
+ <Martin.Reising@natural-computing.de>
+
*/
#include <linux/config.h>
@@ -25,29 +28,44 @@
#include <asm/uaccess.h>
#include <linux/usb.h>
+/* image constants */
#define WIDTH 225
-#define HEIGHT 288
-#define HEADER "P5 225 288 255 "
+#define HEIGHT 289
+#define HEADER "P5 225 289 255 "
#define IMGSIZE ((WIDTH * HEIGHT) + sizeof(HEADER)-1)
-/* Version Information */
-#define DRIVER_VERSION "0.5"
+/* version information */
+#define DRIVER_VERSION "0.6"
#define DRIVER_SHORT "idmouse"
#define DRIVER_AUTHOR "Florian 'Floe' Echtler <echtler@fs.tum.de>"
#define DRIVER_DESC "Siemens ID Mouse FingerTIP Sensor Driver"
-/* Siemens ID Mouse */
-#define USB_IDMOUSE_VENDOR_ID 0x0681
-#define USB_IDMOUSE_PRODUCT_ID 0x0005
-
-/* we still need a minor number */
+/* minor number for misc USB devices */
#define USB_IDMOUSE_MINOR_BASE 132
+/* vendor and device IDs */
+#define ID_SIEMENS 0x0681
+#define ID_IDMOUSE 0x0005
+#define ID_CHERRY 0x0010
+
+/* device ID table */
static struct usb_device_id idmouse_table[] = {
- {USB_DEVICE(USB_IDMOUSE_VENDOR_ID, USB_IDMOUSE_PRODUCT_ID)},
- {} /* null entry at the end */
+ {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
+ {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board */
+ {} /* terminating null entry */
};
+/* sensor commands */
+#define FTIP_RESET 0x20
+#define FTIP_ACQUIRE 0x21
+#define FTIP_RELEASE 0x22
+#define FTIP_BLINK 0x23 /* LSB of value = blink pulse width */
+#define FTIP_SCROLL 0x24
+
+#define ftip_command(dev, command, value, index) \
+ usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0), command, \
+ USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT, value, index, NULL, 0, 1000)
+
MODULE_DEVICE_TABLE(usb, idmouse_table);
/* structure to hold all of our device specific stuff */
@@ -57,7 +75,8 @@ struct usb_idmouse {
struct usb_interface *interface; /* the interface for this device */
unsigned char *bulk_in_buffer; /* the buffer to receive data */
- size_t bulk_in_size; /* the size of the receive buffer */
+ size_t bulk_in_size; /* the maximum bulk packet size */
+ size_t orig_bi_size; /* same as above, but reported by the device */
__u8 bulk_in_endpointAddr; /* the address of the bulk in endpoint */
int open; /* if the port is open or not */
@@ -103,7 +122,7 @@ static struct usb_driver idmouse_driver = {
.id_table = idmouse_table,
};
-// prevent races between open() and disconnect()
+/* prevent races between open() and disconnect() */
static DECLARE_MUTEX(disconnect_sem);
static int idmouse_create_image(struct usb_idmouse *dev)
@@ -112,42 +131,34 @@ static int idmouse_create_image(struct usb_idmouse *dev)
int bulk_read = 0;
int result = 0;
- if (dev->bulk_in_size < sizeof(HEADER))
- return -ENOMEM;
-
- memcpy(dev->bulk_in_buffer,HEADER,sizeof(HEADER)-1);
+ memcpy(dev->bulk_in_buffer, HEADER, sizeof(HEADER)-1);
bytes_read += sizeof(HEADER)-1;
- /* Dump the setup packets. Yes, they are uncommented, simply
- because they were sniffed under Windows using SnoopyPro.
- I _guess_ that 0x22 is a kind of reset command and 0x21
- means init..
- */
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
- if (result < 0)
- return result;
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+ /* reset the device and set a fast blink rate */
+ result = ftip_command(dev, FTIP_RELEASE, 0, 0);
if (result < 0)
- return result;
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
+ goto reset;
+ result = ftip_command(dev, FTIP_BLINK, 1, 0);
if (result < 0)
- return result;
+ goto reset;
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x21, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+ /* initialize the sensor - sending this command twice */
+ /* significantly reduces the rate of failed reads */
+ result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
if (result < 0)
- return result;
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0001, 0x0002, NULL, 0, 1000);
+ goto reset;
+ result = ftip_command(dev, FTIP_ACQUIRE, 0, 0);
if (result < 0)
- return result;
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x20, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
+ goto reset;
+
+ /* start the readout - sending this command twice */
+ /* presumably enables the high dynamic range mode */
+ result = ftip_command(dev, FTIP_RESET, 0, 0);
if (result < 0)
- return result;
+ goto reset;
+ result = ftip_command(dev, FTIP_RESET, 0, 0);
+ if (result < 0)
+ goto reset;
/* loop over a blocking bulk read to get data from the device */
while (bytes_read < IMGSIZE) {
@@ -155,22 +166,40 @@ static int idmouse_create_image(struct usb_idmouse *dev)
usb_rcvbulkpipe (dev->udev, dev->bulk_in_endpointAddr),
dev->bulk_in_buffer + bytes_read,
dev->bulk_in_size, &bulk_read, 5000);
- if (result < 0)
- return result;
- if (signal_pending(current))
- return -EINTR;
+ if (result < 0) {
+ /* Maybe this error was caused by the increased packet size? */
+ /* Reset to the original value and tell userspace to retry. */
+ if (dev->bulk_in_size != dev->orig_bi_size) {
+ dev->bulk_in_size = dev->orig_bi_size;
+ result = -EAGAIN;
+ }
+ break;
+ }
+ if (signal_pending(current)) {
+ result = -EINTR;
+ break;
+ }
bytes_read += bulk_read;
}
/* reset the device */
- result = usb_control_msg (dev->udev, usb_sndctrlpipe (dev->udev, 0),
- 0x22, 0x42, 0x0000, 0x0002, NULL, 0, 1000);
- if (result < 0)
- return result;
+reset:
+ ftip_command(dev, FTIP_RELEASE, 0, 0);
+
+ /* check for valid image */
+ /* right border should be black (0x00) */
+ for (bytes_read = sizeof(HEADER)-1 + WIDTH-1; bytes_read < IMGSIZE; bytes_read += WIDTH)
+ if (dev->bulk_in_buffer[bytes_read] != 0x00)
+ return -EAGAIN;
- /* should be IMGSIZE == 64815 */
+ /* lower border should be white (0xFF) */
+ for (bytes_read = IMGSIZE-WIDTH; bytes_read < IMGSIZE-1; bytes_read++)
+ if (dev->bulk_in_buffer[bytes_read] != 0xFF)
+ return -EAGAIN;
+
+ /* should be IMGSIZE == 65040 */
dbg("read %d bytes fingerprint data", bytes_read);
- return 0;
+ return result;
}
static inline void idmouse_delete(struct usb_idmouse *dev)
@@ -282,10 +311,10 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
dev = (struct usb_idmouse *) file->private_data;
- // lock this object
+ /* lock this object */
down (&dev->sem);
- // verify that the device wasn't unplugged
+ /* verify that the device wasn't unplugged */
if (!dev->present) {
up (&dev->sem);
return -ENODEV;
@@ -296,8 +325,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
return 0;
}
- if (count > IMGSIZE - *ppos)
- count = IMGSIZE - *ppos;
+ count = min ((loff_t)count, IMGSIZE - (*ppos));
if (copy_to_user (buffer, dev->bulk_in_buffer + *ppos, count)) {
result = -EFAULT;
@@ -306,7 +334,7 @@ static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count
*ppos += count;
}
- // unlock the device
+ /* unlock the device */
up(&dev->sem);
return result;
}
@@ -318,7 +346,6 @@ static int idmouse_probe(struct usb_interface *interface,
struct usb_idmouse *dev = NULL;
struct usb_host_interface *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- size_t buffer_size;
int result;
/* check if we have gotten the data or the hid interface */
@@ -344,11 +371,11 @@ static int idmouse_probe(struct usb_interface *interface,
USB_ENDPOINT_XFER_BULK)) {
/* we found a bulk in endpoint */
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- dev->bulk_in_size = buffer_size;
+ dev->orig_bi_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ dev->bulk_in_size = 0x200; /* works _much_ faster */
dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;
dev->bulk_in_buffer =
- kmalloc(IMGSIZE + buffer_size, GFP_KERNEL);
+ kmalloc(IMGSIZE + dev->bulk_in_size, GFP_KERNEL);
if (!dev->bulk_in_buffer) {
err("Unable to allocate input buffer.");
diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c
new file mode 100644
index 000000000000..66ec88354b93
--- /dev/null
+++ b/drivers/usb/misc/ldusb.c
@@ -0,0 +1,794 @@
+/**
+ * Generic USB driver for report based interrupt in/out devices
+ * like LD Didactic's USB devices. LD Didactic's USB devices are
+ * HID devices which do not use HID report definitons (they use
+ * raw interrupt in and our reports only for communication).
+ *
+ * This driver uses a ring buffer for time critical reading of
+ * interrupt in reports and provides read and write methods for
+ * raw interrupt reports (similar to the Windows HID driver).
+ * Devices based on the book USB COMPLETE by Jan Axelson may need
+ * such a compatibility to the Windows HID driver.
+ *
+ * Copyright (C) 2005 Michael Hund <mhund@ld-didactic.de>
+ *
+ * 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.
+ *
+ * Derived from Lego USB Tower driver
+ * Copyright (C) 2003 David Glance <advidgsf@sourceforge.net>
+ * 2001-2004 Juergen Stuber <starblue@users.sourceforge.net>
+ *
+ * V0.1 (mh) Initial version
+ * V0.11 (mh) Added raw support for HID 1.0 devices (no interrupt out endpoint)
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include <asm/uaccess.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+
+/* Define these values to match your devices */
+#define USB_VENDOR_ID_LD 0x0f11 /* USB Vendor ID of LD Didactic GmbH */
+#define USB_DEVICE_ID_CASSY 0x1000 /* USB Product ID for all CASSY-S modules */
+#define USB_DEVICE_ID_POCKETCASSY 0x1010 /* USB Product ID for Pocket-CASSY */
+#define USB_DEVICE_ID_MOBILECASSY 0x1020 /* USB Product ID for Mobile-CASSY */
+#define USB_DEVICE_ID_JWM 0x1080 /* USB Product ID for Joule and Wattmeter */
+#define USB_DEVICE_ID_DMMP 0x1081 /* USB Product ID for Digital Multimeter P (reserved) */
+#define USB_DEVICE_ID_UMIP 0x1090 /* USB Product ID for UMI P */
+#define USB_DEVICE_ID_VIDEOCOM 0x1200 /* USB Product ID for VideoCom */
+#define USB_DEVICE_ID_COM3LAB 0x2000 /* USB Product ID for COM3LAB */
+#define USB_DEVICE_ID_TELEPORT 0x2010 /* USB Product ID for Terminal Adapter */
+#define USB_DEVICE_ID_NETWORKANALYSER 0x2020 /* USB Product ID for Network Analyser */
+#define USB_DEVICE_ID_POWERCONTROL 0x2030 /* USB Product ID for Controlling device for Power Electronics */
+
+#define USB_VENDOR_ID_VERNIER 0x08f7
+#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001
+#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002
+#define USB_DEVICE_ID_VERNIER_SKIP 0x0003
+#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004
+
+
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+#define USB_LD_MINOR_BASE 0
+#else
+#define USB_LD_MINOR_BASE 176
+#endif
+
+/* table of devices that work with this driver */
+static struct usb_device_id ld_usb_table [] = {
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_CASSY) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POCKETCASSY) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_MOBILECASSY) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_JWM) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_DMMP) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_UMIP) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_VIDEOCOM) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_COM3LAB) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_TELEPORT) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_NETWORKANALYSER) },
+ { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_POWERCONTROL) },
+ { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
+ { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
+ { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
+ { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, ld_usb_table);
+MODULE_VERSION("V0.11");
+MODULE_AUTHOR("Michael Hund <mhund@ld-didactic.de>");
+MODULE_DESCRIPTION("LD USB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("LD USB Devices");
+
+#ifdef CONFIG_USB_DEBUG
+ static int debug = 1;
+#else
+ static int debug = 0;
+#endif
+
+/* Use our own dbg macro */
+#define dbg_info(dev, format, arg...) do { if (debug) dev_info(dev , format , ## arg); } while (0)
+
+/* Module parameters */
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* All interrupt in transfers are collected in a ring buffer to
+ * avoid racing conditions and get better performance of the driver.
+ */
+static int ring_buffer_size = 128;
+module_param(ring_buffer_size, int, 0);
+MODULE_PARM_DESC(ring_buffer_size, "Read ring buffer size in reports");
+
+/* The write_buffer can contain more than one interrupt out transfer.
+ */
+static int write_buffer_size = 10;
+module_param(write_buffer_size, int, 0);
+MODULE_PARM_DESC(write_buffer_size, "Write buffer size in reports");
+
+/* As of kernel version 2.6.4 ehci-hcd uses an
+ * "only one interrupt transfer per frame" shortcut
+ * to simplify the scheduling of periodic transfers.
+ * This conflicts with our standard 1ms intervals for in and out URBs.
+ * We use default intervals of 2ms for in and 2ms for out transfers,
+ * which should be fast enough.
+ * Increase the interval to allow more devices that do interrupt transfers,
+ * or set to 1 to use the standard interval from the endpoint descriptors.
+ */
+static int min_interrupt_in_interval = 2;
+module_param(min_interrupt_in_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_in_interval, "Minimum interrupt in interval in ms");
+
+static int min_interrupt_out_interval = 2;
+module_param(min_interrupt_out_interval, int, 0);
+MODULE_PARM_DESC(min_interrupt_out_interval, "Minimum interrupt out interval in ms");
+
+/* Structure to hold all of our device specific stuff */
+struct ld_usb {
+ struct semaphore sem; /* locks this structure */
+ struct usb_interface* intf; /* save off the usb interface pointer */
+
+ int open_count; /* number of times this port has been opened */
+
+ char* ring_buffer;
+ unsigned int ring_head;
+ unsigned int ring_tail;
+
+ wait_queue_head_t read_wait;
+ wait_queue_head_t write_wait;
+
+ char* interrupt_in_buffer;
+ struct usb_endpoint_descriptor* interrupt_in_endpoint;
+ struct urb* interrupt_in_urb;
+ int interrupt_in_interval;
+ size_t interrupt_in_endpoint_size;
+ int interrupt_in_running;
+ int interrupt_in_done;
+
+ char* interrupt_out_buffer;
+ struct usb_endpoint_descriptor* interrupt_out_endpoint;
+ struct urb* interrupt_out_urb;
+ int interrupt_out_interval;
+ size_t interrupt_out_endpoint_size;
+ int interrupt_out_busy;
+};
+
+/* prevent races between open() and disconnect() */
+static DECLARE_MUTEX(disconnect_sem);
+
+static struct usb_driver ld_usb_driver;
+
+/**
+ * ld_usb_abort_transfers
+ * aborts transfers and frees associated data structures
+ */
+static void ld_usb_abort_transfers(struct ld_usb *dev)
+{
+ /* shutdown transfer */
+ if (dev->interrupt_in_running) {
+ dev->interrupt_in_running = 0;
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_in_urb);
+ }
+ if (dev->interrupt_out_busy)
+ if (dev->intf)
+ usb_kill_urb(dev->interrupt_out_urb);
+}
+
+/**
+ * ld_usb_delete
+ */
+static void ld_usb_delete(struct ld_usb *dev)
+{
+ ld_usb_abort_transfers(dev);
+
+ /* free data structures */
+ usb_free_urb(dev->interrupt_in_urb);
+ usb_free_urb(dev->interrupt_out_urb);
+ kfree(dev->ring_buffer);
+ kfree(dev->interrupt_in_buffer);
+ kfree(dev->interrupt_out_buffer);
+ kfree(dev);
+}
+
+/**
+ * ld_usb_interrupt_in_callback
+ */
+static void ld_usb_interrupt_in_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct ld_usb *dev = urb->context;
+ size_t *actual_buffer;
+ unsigned int next_ring_head;
+ int retval;
+
+ if (urb->status) {
+ if (urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN) {
+ goto exit;
+ } else {
+ dbg_info(&dev->intf->dev, "%s: nonzero status received: %d\n",
+ __FUNCTION__, urb->status);
+ goto resubmit; /* maybe we can recover */
+ }
+ }
+
+ if (urb->actual_length > 0) {
+ next_ring_head = (dev->ring_head+1) % ring_buffer_size;
+ if (next_ring_head != dev->ring_tail) {
+ actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_head*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
+ /* actual_buffer gets urb->actual_length + interrupt_in_buffer */
+ *actual_buffer = urb->actual_length;
+ memcpy(actual_buffer+1, dev->interrupt_in_buffer, urb->actual_length);
+ dev->ring_head = next_ring_head;
+ dbg_info(&dev->intf->dev, "%s: received %d bytes\n",
+ __FUNCTION__, urb->actual_length);
+ } else
+ dev_warn(&dev->intf->dev,
+ "Ring buffer overflow, %d bytes dropped\n",
+ urb->actual_length);
+ }
+
+resubmit:
+ /* resubmit if we're still running */
+ if (dev->interrupt_in_running && dev->intf) {
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&dev->intf->dev,
+ "usb_submit_urb failed (%d)\n", retval);
+ }
+
+exit:
+ dev->interrupt_in_done = 1;
+ wake_up_interruptible(&dev->read_wait);
+}
+
+/**
+ * ld_usb_interrupt_out_callback
+ */
+static void ld_usb_interrupt_out_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct ld_usb *dev = urb->context;
+
+ /* sync/async unlink faults aren't errors */
+ if (urb->status && !(urb->status == -ENOENT ||
+ urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN))
+ dbg_info(&dev->intf->dev,
+ "%s - nonzero write interrupt status received: %d\n",
+ __FUNCTION__, urb->status);
+
+ dev->interrupt_out_busy = 0;
+ wake_up_interruptible(&dev->write_wait);
+}
+
+/**
+ * ld_usb_open
+ */
+static int ld_usb_open(struct inode *inode, struct file *file)
+{
+ struct ld_usb *dev;
+ int subminor;
+ int retval = 0;
+ struct usb_interface *interface;
+
+ nonseekable_open(inode, file);
+ subminor = iminor(inode);
+
+ down(&disconnect_sem);
+
+ interface = usb_find_interface(&ld_usb_driver, subminor);
+
+ if (!interface) {
+ err("%s - error, can't find device for minor %d\n",
+ __FUNCTION__, subminor);
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ dev = usb_get_intfdata(interface);
+
+ if (!dev) {
+ retval = -ENODEV;
+ goto unlock_disconnect_exit;
+ }
+
+ /* lock this device */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto unlock_disconnect_exit;
+ }
+
+ /* allow opening only once */
+ if (dev->open_count) {
+ retval = -EBUSY;
+ goto unlock_exit;
+ }
+ dev->open_count = 1;
+
+ /* initialize in direction */
+ dev->ring_head = 0;
+ dev->ring_tail = 0;
+ usb_fill_int_urb(dev->interrupt_in_urb,
+ interface_to_usbdev(interface),
+ usb_rcvintpipe(interface_to_usbdev(interface),
+ dev->interrupt_in_endpoint->bEndpointAddress),
+ dev->interrupt_in_buffer,
+ dev->interrupt_in_endpoint_size,
+ ld_usb_interrupt_in_callback,
+ dev,
+ dev->interrupt_in_interval);
+
+ dev->interrupt_in_running = 1;
+ dev->interrupt_in_done = 0;
+
+ retval = usb_submit_urb(dev->interrupt_in_urb, GFP_KERNEL);
+ if (retval) {
+ dev_err(&interface->dev, "Couldn't submit interrupt_in_urb %d\n", retval);
+ dev->interrupt_in_running = 0;
+ dev->open_count = 0;
+ goto unlock_exit;
+ }
+
+ /* save device in the file's private structure */
+ file->private_data = dev;
+
+unlock_exit:
+ up(&dev->sem);
+
+unlock_disconnect_exit:
+ up(&disconnect_sem);
+
+ return retval;
+}
+
+/**
+ * ld_usb_release
+ */
+static int ld_usb_release(struct inode *inode, struct file *file)
+{
+ struct ld_usb *dev;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ if (dev == NULL) {
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ if (dev->open_count != 1) {
+ retval = -ENODEV;
+ goto unlock_exit;
+ }
+ if (dev->intf == NULL) {
+ /* the device was unplugged before the file was released */
+ up(&dev->sem);
+ /* unlock here as ld_usb_delete frees dev */
+ ld_usb_delete(dev);
+ goto exit;
+ }
+
+ /* wait until write transfer is finished */
+ if (dev->interrupt_out_busy)
+ wait_event_interruptible_timeout(dev->write_wait, !dev->interrupt_out_busy, 2 * HZ);
+ ld_usb_abort_transfers(dev);
+ dev->open_count = 0;
+
+unlock_exit:
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * ld_usb_poll
+ */
+static unsigned int ld_usb_poll(struct file *file, poll_table *wait)
+{
+ struct ld_usb *dev;
+ unsigned int mask = 0;
+
+ dev = file->private_data;
+
+ poll_wait(file, &dev->read_wait, wait);
+ poll_wait(file, &dev->write_wait, wait);
+
+ if (dev->ring_head != dev->ring_tail)
+ mask |= POLLIN | POLLRDNORM;
+ if (!dev->interrupt_out_busy)
+ mask |= POLLOUT | POLLWRNORM;
+
+ return mask;
+}
+
+/**
+ * ld_usb_read
+ */
+static ssize_t ld_usb_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *ppos)
+{
+ struct ld_usb *dev;
+ size_t *actual_buffer;
+ size_t bytes_to_read;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to read */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ /* wait for data */
+ if (dev->ring_head == dev->ring_tail) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible(dev->read_wait, dev->interrupt_in_done);
+ if (retval < 0)
+ goto unlock_exit;
+ }
+
+ /* actual_buffer contains actual_length + interrupt_in_buffer */
+ actual_buffer = (size_t*)(dev->ring_buffer + dev->ring_tail*(sizeof(size_t)+dev->interrupt_in_endpoint_size));
+ bytes_to_read = min(count, *actual_buffer);
+ if (bytes_to_read < *actual_buffer)
+ dev_warn(&dev->intf->dev, "Read buffer overflow, %d bytes dropped\n",
+ *actual_buffer-bytes_to_read);
+
+ /* copy one interrupt_in_buffer from ring_buffer into userspace */
+ if (copy_to_user(buffer, actual_buffer+1, bytes_to_read)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+ dev->ring_tail = (dev->ring_tail+1) % ring_buffer_size;
+
+ retval = bytes_to_read;
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/**
+ * ld_usb_write
+ */
+static ssize_t ld_usb_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ struct ld_usb *dev;
+ size_t bytes_to_write;
+ int retval = 0;
+
+ dev = file->private_data;
+
+ /* verify that we actually have some data to write */
+ if (count == 0)
+ goto exit;
+
+ /* lock this object */
+ if (down_interruptible(&dev->sem)) {
+ retval = -ERESTARTSYS;
+ goto exit;
+ }
+
+ /* verify that the device wasn't unplugged */
+ if (dev->intf == NULL) {
+ retval = -ENODEV;
+ err("No device or device unplugged %d\n", retval);
+ goto unlock_exit;
+ }
+
+ /* wait until previous transfer is finished */
+ if (dev->interrupt_out_busy) {
+ if (file->f_flags & O_NONBLOCK) {
+ retval = -EAGAIN;
+ goto unlock_exit;
+ }
+ retval = wait_event_interruptible(dev->write_wait, !dev->interrupt_out_busy);
+ if (retval < 0) {
+ goto unlock_exit;
+ }
+ }
+
+ /* write the data into interrupt_out_buffer from userspace */
+ bytes_to_write = min(count, write_buffer_size*dev->interrupt_out_endpoint_size);
+ if (bytes_to_write < count)
+ dev_warn(&dev->intf->dev, "Write buffer overflow, %d bytes dropped\n",count-bytes_to_write);
+ dbg_info(&dev->intf->dev, "%s: count = %d, bytes_to_write = %d\n", __FUNCTION__, count, bytes_to_write);
+
+ if (copy_from_user(dev->interrupt_out_buffer, buffer, bytes_to_write)) {
+ retval = -EFAULT;
+ goto unlock_exit;
+ }
+
+ if (dev->interrupt_out_endpoint == NULL) {
+ /* try HID_REQ_SET_REPORT=9 on control_endpoint instead of interrupt_out_endpoint */
+ retval = usb_control_msg(interface_to_usbdev(dev->intf),
+ usb_sndctrlpipe(interface_to_usbdev(dev->intf), 0),
+ 9,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ 1 << 8, 0,
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ USB_CTRL_SET_TIMEOUT * HZ);
+ if (retval < 0)
+ err("Couldn't submit HID_REQ_SET_REPORT %d\n", retval);
+ goto unlock_exit;
+ }
+
+ /* send off the urb */
+ usb_fill_int_urb(dev->interrupt_out_urb,
+ interface_to_usbdev(dev->intf),
+ usb_sndintpipe(interface_to_usbdev(dev->intf),
+ dev->interrupt_out_endpoint->bEndpointAddress),
+ dev->interrupt_out_buffer,
+ bytes_to_write,
+ ld_usb_interrupt_out_callback,
+ dev,
+ dev->interrupt_out_interval);
+
+ dev->interrupt_out_busy = 1;
+ wmb();
+
+ retval = usb_submit_urb(dev->interrupt_out_urb, GFP_KERNEL);
+ if (retval) {
+ dev->interrupt_out_busy = 0;
+ err("Couldn't submit interrupt_out_urb %d\n", retval);
+ goto unlock_exit;
+ }
+ retval = bytes_to_write;
+
+unlock_exit:
+ /* unlock the device */
+ up(&dev->sem);
+
+exit:
+ return retval;
+}
+
+/* file operations needed when we register this driver */
+static struct file_operations ld_usb_fops = {
+ .owner = THIS_MODULE,
+ .read = ld_usb_read,
+ .write = ld_usb_write,
+ .open = ld_usb_open,
+ .release = ld_usb_release,
+ .poll = ld_usb_poll,
+};
+
+/*
+ * 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 ld_usb_class = {
+ .name = "ldusb%d",
+ .fops = &ld_usb_fops,
+ .minor_base = USB_LD_MINOR_BASE,
+};
+
+/**
+ * ld_usb_probe
+ *
+ * Called by the usb core when a new device is connected that it thinks
+ * this driver might be interested in.
+ */
+static int ld_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct ld_usb *dev = NULL;
+ struct usb_host_interface *iface_desc;
+ struct usb_endpoint_descriptor *endpoint;
+ char *buffer;
+ int i;
+ int retval = -ENOMEM;
+
+ /* allocate memory for our device state and intialize it */
+
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ dev_err(&intf->dev, "Out of memory\n");
+ goto exit;
+ }
+ memset(dev, 0x00, sizeof(*dev));
+ init_MUTEX(&dev->sem);
+ dev->intf = intf;
+ init_waitqueue_head(&dev->read_wait);
+ init_waitqueue_head(&dev->write_wait);
+
+ /* workaround for early firmware versions on fast computers */
+ if ((le16_to_cpu(udev->descriptor.idVendor) == USB_VENDOR_ID_LD) &&
+ ((le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_CASSY) ||
+ (le16_to_cpu(udev->descriptor.idProduct) == USB_DEVICE_ID_COM3LAB)) &&
+ (le16_to_cpu(udev->descriptor.bcdDevice) <= 0x103)) {
+ buffer = kmalloc(256, GFP_KERNEL);
+ /* usb_string makes SETUP+STALL to leave always ControlReadLoop */
+ usb_string(udev, 255, buffer, 256);
+ kfree(buffer);
+ }
+
+ iface_desc = intf->cur_altsetting;
+
+ /* set up the endpoint information */
+ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+ endpoint = &iface_desc->endpoint[i].desc;
+
+ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ dev->interrupt_in_endpoint = endpoint;
+ }
+
+ if (((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) &&
+ ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)) {
+ dev->interrupt_out_endpoint = endpoint;
+ }
+ }
+ if (dev->interrupt_in_endpoint == NULL) {
+ dev_err(&intf->dev, "Interrupt in endpoint not found\n");
+ goto error;
+ }
+ if (dev->interrupt_out_endpoint == NULL)
+ dev_warn(&intf->dev, "Interrupt out endpoint not found (using control endpoint instead)\n");
+
+ dev->interrupt_in_endpoint_size = le16_to_cpu(dev->interrupt_in_endpoint->wMaxPacketSize);
+ dev->ring_buffer = kmalloc(ring_buffer_size*(sizeof(size_t)+dev->interrupt_in_endpoint_size), GFP_KERNEL);
+ if (!dev->ring_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate ring_buffer\n");
+ goto error;
+ }
+ dev->interrupt_in_buffer = kmalloc(dev->interrupt_in_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_in_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_buffer\n");
+ goto error;
+ }
+ dev->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_in_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_in_urb\n");
+ goto error;
+ }
+ dev->interrupt_out_endpoint_size = dev->interrupt_out_endpoint ? le16_to_cpu(dev->interrupt_out_endpoint->wMaxPacketSize) :
+ udev->descriptor.bMaxPacketSize0;
+ dev->interrupt_out_buffer = kmalloc(write_buffer_size*dev->interrupt_out_endpoint_size, GFP_KERNEL);
+ if (!dev->interrupt_out_buffer) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_buffer\n");
+ goto error;
+ }
+ dev->interrupt_out_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->interrupt_out_urb) {
+ dev_err(&intf->dev, "Couldn't allocate interrupt_out_urb\n");
+ goto error;
+ }
+ dev->interrupt_in_interval = min_interrupt_in_interval > dev->interrupt_in_endpoint->bInterval ? min_interrupt_in_interval : dev->interrupt_in_endpoint->bInterval;
+ if (dev->interrupt_out_endpoint)
+ dev->interrupt_out_interval = min_interrupt_out_interval > dev->interrupt_out_endpoint->bInterval ? min_interrupt_out_interval : dev->interrupt_out_endpoint->bInterval;
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(intf, dev);
+
+ retval = usb_register_dev(intf, &ld_usb_class);
+ if (retval) {
+ /* something prevented us from registering this driver */
+ dev_err(&intf->dev, "Not able to get a minor for this device.\n");
+ usb_set_intfdata(intf, NULL);
+ goto error;
+ }
+
+ /* let the user know what node this device is now attached to */
+ dev_info(&intf->dev, "LD USB Device #%d now attached to major %d minor %d\n",
+ (intf->minor - USB_LD_MINOR_BASE), USB_MAJOR, intf->minor);
+
+exit:
+ return retval;
+
+error:
+ ld_usb_delete(dev);
+
+ return retval;
+}
+
+/**
+ * ld_usb_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ */
+static void ld_usb_disconnect(struct usb_interface *intf)
+{
+ struct ld_usb *dev;
+ int minor;
+
+ down(&disconnect_sem);
+
+ dev = usb_get_intfdata(intf);
+ usb_set_intfdata(intf, NULL);
+
+ down(&dev->sem);
+
+ minor = intf->minor;
+
+ /* give back our minor */
+ usb_deregister_dev(intf, &ld_usb_class);
+
+ /* if the device is not opened, then we clean up right now */
+ if (!dev->open_count) {
+ up(&dev->sem);
+ ld_usb_delete(dev);
+ } else {
+ dev->intf = NULL;
+ up(&dev->sem);
+ }
+
+ up(&disconnect_sem);
+
+ dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
+ (minor - USB_LD_MINOR_BASE));
+}
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver ld_usb_driver = {
+ .owner = THIS_MODULE,
+ .name = "ldusb",
+ .probe = ld_usb_probe,
+ .disconnect = ld_usb_disconnect,
+ .id_table = ld_usb_table,
+};
+
+/**
+ * ld_usb_init
+ */
+static int __init ld_usb_init(void)
+{
+ int retval;
+
+ /* register this driver with the USB subsystem */
+ retval = usb_register(&ld_usb_driver);
+ if (retval)
+ err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
+
+ return retval;
+}
+
+/**
+ * ld_usb_exit
+ */
+static void __exit ld_usb_exit(void)
+{
+ /* deregister this driver with the USB subsystem */
+ usb_deregister(&ld_usb_driver);
+}
+
+module_init(ld_usb_init);
+module_exit(ld_usb_exit);
+
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 3104f28f6aa8..cda7249a90b2 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -461,7 +461,7 @@ static int perform_sglist (
static unsigned realworld = 1;
module_param (realworld, uint, 0);
-MODULE_PARM_DESC (realworld, "clear to demand stricter ch9 compliance");
+MODULE_PARM_DESC (realworld, "clear to demand stricter spec compliance");
static int get_altsetting (struct usbtest_dev *dev)
{
@@ -604,9 +604,8 @@ static int ch9_postconfig (struct usbtest_dev *dev)
USB_DIR_IN | USB_RECIP_DEVICE,
0, 0, dev->buf, 1, USB_CTRL_GET_TIMEOUT);
if (retval != 1 || dev->buf [0] != expected) {
- dev_dbg (&iface->dev,
- "get config --> %d (%d)\n", retval,
- expected);
+ dev_dbg (&iface->dev, "get config --> %d %d (1 %d)\n",
+ retval, dev->buf[0], expected);
return (retval < 0) ? retval : -EDOM;
}
}
@@ -1243,7 +1242,7 @@ static int ctrl_out (struct usbtest_dev *dev,
char *what = "?";
struct usb_device *udev;
- if (length > 0xffff || vary >= length)
+ if (length < 1 || length > 0xffff || vary >= length)
return -EINVAL;
buf = kmalloc(length, SLAB_KERNEL);
@@ -1266,6 +1265,11 @@ static int ctrl_out (struct usbtest_dev *dev,
0, 0, buf, len, USB_CTRL_SET_TIMEOUT);
if (retval != len) {
what = "write";
+ if (retval >= 0) {
+ INFO(dev, "ctrl_out, wlen %d (expected %d)\n",
+ retval, len);
+ retval = -EBADMSG;
+ }
break;
}
@@ -1275,6 +1279,11 @@ static int ctrl_out (struct usbtest_dev *dev,
0, 0, buf, len, USB_CTRL_GET_TIMEOUT);
if (retval != len) {
what = "read";
+ if (retval >= 0) {
+ INFO(dev, "ctrl_out, rlen %d (expected %d)\n",
+ retval, len);
+ retval = -EBADMSG;
+ }
break;
}
@@ -1293,8 +1302,13 @@ static int ctrl_out (struct usbtest_dev *dev,
}
len += vary;
+
+ /* [real world] the "zero bytes IN" case isn't really used.
+ * hardware can easily trip up in this wierd case, since its
+ * status stage is IN, not OUT like other ep0in transfers.
+ */
if (len > length)
- len = 0;
+ len = realworld ? 1 : 0;
}
if (retval < 0)
@@ -1519,6 +1533,11 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
if (down_interruptible (&dev->sem))
return -ERESTARTSYS;
+ if (intf->dev.power.power_state != PMSG_ON) {
+ up (&dev->sem);
+ return -EHOSTUNREACH;
+ }
+
/* some devices, like ez-usb default devices, need a non-default
* altsetting to have any active endpoints. some tests change
* altsettings; force a default so most tests don't need to check.
@@ -1762,8 +1781,10 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
case 14:
if (!dev->info->ctrl_out)
break;
- dev_dbg (&intf->dev, "TEST 14: %d ep0out, 0..%d vary %d\n",
- param->iterations, param->length, param->vary);
+ dev_dbg (&intf->dev, "TEST 14: %d ep0out, %d..%d vary %d\n",
+ param->iterations,
+ realworld ? 1 : 0, param->length,
+ param->vary);
retval = ctrl_out (dev, param->iterations,
param->length, param->vary);
break;
@@ -1927,6 +1948,27 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
return 0;
}
+static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
+{
+ struct usbtest_dev *dev = usb_get_intfdata (intf);
+
+ down (&dev->sem);
+ intf->dev.power.power_state = PMSG_SUSPEND;
+ up (&dev->sem);
+ return 0;
+}
+
+static int usbtest_resume (struct usb_interface *intf)
+{
+ struct usbtest_dev *dev = usb_get_intfdata (intf);
+
+ down (&dev->sem);
+ intf->dev.power.power_state = PMSG_ON;
+ up (&dev->sem);
+ return 0;
+}
+
+
static void usbtest_disconnect (struct usb_interface *intf)
{
struct usbtest_dev *dev = usb_get_intfdata (intf);
@@ -2115,6 +2157,8 @@ static struct usb_driver usbtest_driver = {
.probe = usbtest_probe,
.ioctl = usbtest_ioctl,
.disconnect = usbtest_disconnect,
+ .suspend = usbtest_suspend,
+ .resume = usbtest_resume,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 755a4570477f..26266b30028e 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -19,11 +19,16 @@
#define DATA_MAX 32
/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_MAX 8
+
+/*
* This limit exists to prevent OOMs when the user process stops reading.
*/
#define EVENT_MAX 25
-#define PRINTF_DFL 120
+#define PRINTF_DFL 130
struct mon_event_text {
struct list_head e_link;
@@ -33,7 +38,9 @@ struct mon_event_text {
unsigned int tstamp;
int length; /* Depends on type: xfer length or act length */
int status;
+ char setup_flag;
char data_flag;
+ unsigned char setup[SETUP_MAX];
unsigned char data[DATA_MAX];
};
@@ -64,6 +71,22 @@ static void mon_text_dtor(void *, kmem_cache_t *, unsigned long);
* This is called with the whole mon_bus locked, so no additional lock.
*/
+static inline char mon_text_get_setup(struct mon_event_text *ep,
+ struct urb *urb, char ev_type)
+{
+
+ if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+ return '-';
+
+ if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+ return 'D';
+ if (urb->setup_packet == NULL)
+ return 'Z'; /* '0' would be not as pretty. */
+
+ memcpy(ep->setup, urb->setup_packet, SETUP_MAX);
+ return 0;
+}
+
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
int len, char ev_type)
{
@@ -90,7 +113,6 @@ static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
/*
* Bulk is easy to shortcut reliably.
- * XXX Control needs setup packet taken.
* XXX Other pipe types need consideration. Currently, we overdo it
* and collect garbage for them: better more than less.
*/
@@ -144,6 +166,7 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
/* Collecting status makes debugging sense for submits, too */
ep->status = urb->status;
+ ep->setup_flag = mon_text_get_setup(ep, urb, ev_type);
ep->data_flag = mon_text_get_data(ep, urb, ep->length, ev_type);
rp->nevents++;
@@ -299,10 +322,25 @@ static ssize_t mon_text_read(struct file *file, char __user *buf,
default: /* PIPE_BULK */ utype = 'B';
}
cnt += snprintf(pbuf + cnt, limit - cnt,
- "%lx %u %c %c%c:%03u:%02u %d %d",
+ "%lx %u %c %c%c:%03u:%02u",
ep->id, ep->tstamp, ep->type,
- utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe),
- ep->status, ep->length);
+ utype, udir, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+
+ if (ep->setup_flag == 0) { /* Setup packet is present and captured */
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " s %02x %02x %04x %04x %04x",
+ ep->setup[0],
+ ep->setup[1],
+ (ep->setup[3] << 8) | ep->setup[2],
+ (ep->setup[5] << 8) | ep->setup[4],
+ (ep->setup[7] << 8) | ep->setup[6]);
+ } else if (ep->setup_flag != '-') { /* Unable to capture setup packet */
+ cnt += snprintf(pbuf + cnt, limit - cnt,
+ " %c __ __ ____ ____ ____", ep->setup_flag);
+ } else { /* No setup for this kind of URB */
+ cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->status);
+ }
+ cnt += snprintf(pbuf + cnt, limit - cnt, " %d", ep->length);
if ((data_len = ep->length) > 0) {
if (ep->data_flag == 0) {
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fd6ff4cb2c62..7ffa99b9760f 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -477,7 +477,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
}
static void kaweth_usb_receive(struct urb *, struct pt_regs *regs);
-static int kaweth_resubmit_rx_urb(struct kaweth_device *, int);
+static int kaweth_resubmit_rx_urb(struct kaweth_device *, unsigned);
/****************************************************************
int_callback
@@ -550,7 +550,7 @@ static void kaweth_resubmit_tl(void *d)
* kaweth_resubmit_rx_urb
****************************************************************/
static int kaweth_resubmit_rx_urb(struct kaweth_device *kaweth,
- int mem_flags)
+ unsigned mem_flags)
{
int result;
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index d976790312aa..5f4496d8dbac 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1166,7 +1166,7 @@ static void pegasus_set_multicast(struct net_device *net)
pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
if (netif_msg_link(pegasus))
pr_info("%s: Promiscuous mode enabled.\n", net->name);
- } else if ((net->mc_count > multicast_filter_limit) ||
+ } else if (net->mc_count ||
(net->flags & IFF_ALLMULTI)) {
pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index 13ccedef5c7e..b98f2a833442 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -249,6 +249,8 @@ PEGASUS_DEV( "Kingston KNU101TX Ethernet", VENDOR_KINGSTON, 0x000a,
DEFAULT_GPIO_RESET)
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x4002,
DEFAULT_GPIO_RESET )
+PEGASUS_DEV( "LANEED USB Ethernet LD-USBL/TX", VENDOR_LANEED, 0x4005,
+ DEFAULT_GPIO_RESET | PEGASUS_II)
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/TX", VENDOR_LANEED, 0x400b,
DEFAULT_GPIO_RESET | PEGASUS_II )
PEGASUS_DEV( "LANEED USB Ethernet LD-USB/T", VENDOR_LANEED, 0xabc1,
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index 8fb223385f2f..626b016addff 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -667,7 +667,7 @@ static void rtl8150_set_multicast(struct net_device *netdev)
if (netdev->flags & IFF_PROMISC) {
dev->rx_creg |= cpu_to_le16(0x0001);
info("%s: promiscuous mode", netdev->name);
- } else if ((netdev->mc_count > multicast_filter_limit) ||
+ } else if (netdev->mc_count ||
(netdev->flags & IFF_ALLMULTI)) {
dev->rx_creg &= cpu_to_le16(0xfffe);
dev->rx_creg |= cpu_to_le16(0x0002);
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index 4cbb408af727..576f3b852fce 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -1429,7 +1429,7 @@ static int generic_cdc_bind (struct usbnet *dev, struct usb_interface *intf)
info->ether = (void *) buf;
if (info->ether->bLength != sizeof *info->ether) {
dev_dbg (&intf->dev, "CDC ether len %u\n",
- info->u->bLength);
+ info->ether->bLength);
goto bad_desc;
}
dev->net->mtu = le16_to_cpup (
@@ -3227,9 +3227,9 @@ static int usbnet_stop (struct net_device *net)
temp = unlink_urbs (dev, &dev->txq) + unlink_urbs (dev, &dev->rxq);
// maybe wait for deletions to finish.
- while (skb_queue_len (&dev->rxq)
- && skb_queue_len (&dev->txq)
- && skb_queue_len (&dev->done)) {
+ while (!skb_queue_empty(&dev->rxq) &&
+ !skb_queue_empty(&dev->txq) &&
+ !skb_queue_empty(&dev->done)) {
msleep(UNLINK_TIMEOUT_MS);
if (netif_msg_ifdown (dev))
devdbg (dev, "waited for %d urb completions", temp);
diff --git a/drivers/usb/net/zd1201.c b/drivers/usb/net/zd1201.c
index 341ae5f732dd..3b387b005739 100644
--- a/drivers/usb/net/zd1201.c
+++ b/drivers/usb/net/zd1201.c
@@ -1884,12 +1884,53 @@ static void zd1201_disconnect(struct usb_interface *interface)
kfree(zd);
}
+#ifdef CONFIG_PM
+
+static int zd1201_suspend(struct usb_interface *interface,
+ pm_message_t message)
+{
+ struct zd1201 *zd = usb_get_intfdata(interface);
+
+ netif_device_detach(zd->dev);
+
+ zd->was_enabled = zd->mac_enabled;
+
+ if (zd->was_enabled)
+ return zd1201_disable(zd);
+ else
+ return 0;
+}
+
+static int zd1201_resume(struct usb_interface *interface)
+{
+ struct zd1201 *zd = usb_get_intfdata(interface);
+
+ if (!zd || !zd->dev)
+ return -ENODEV;
+
+ netif_device_attach(zd->dev);
+
+ if (zd->was_enabled)
+ return zd1201_enable(zd);
+ else
+ return 0;
+}
+
+#else
+
+#define zd1201_suspend NULL
+#define zd1201_resume NULL
+
+#endif
+
static struct usb_driver zd1201_usb = {
.owner = THIS_MODULE,
.name = "zd1201",
.probe = zd1201_probe,
.disconnect = zd1201_disconnect,
.id_table = zd1201_table,
+ .suspend = zd1201_suspend,
+ .resume = zd1201_resume,
};
static int __init zd1201_init(void)
diff --git a/drivers/usb/net/zd1201.h b/drivers/usb/net/zd1201.h
index 1627c71e8052..235f0ee34b24 100644
--- a/drivers/usb/net/zd1201.h
+++ b/drivers/usb/net/zd1201.h
@@ -46,6 +46,7 @@ struct zd1201 {
char essid[IW_ESSID_MAX_SIZE+1];
int essidlen;
int mac_enabled;
+ int was_enabled;
int monitor;
int encode_enabled;
int encode_restricted;
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 46a204cd40e1..b5b431067b08 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -213,10 +213,14 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
spin_lock_irqsave(&priv->lock, flags);
@@ -224,6 +228,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
/* To much data for buffer. Reset buffer. */
priv->wrfilled=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return (0);
}
@@ -268,6 +273,7 @@ static int cyberjack_write (struct usb_serial_port *port, const unsigned char *b
priv->wrfilled=0;
priv->wrsent=0;
spin_unlock_irqrestore(&priv->lock, flags);
+ port->write_urb_busy = 0;
return 0;
}
@@ -412,7 +418,8 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
struct cyberjack_private *priv = usb_get_serial_port_data(port);
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
@@ -424,12 +431,6 @@ static void cyberjack_write_bulk_callback (struct urb *urb, struct pt_regs *regs
if( priv->wrfilled ) {
int length, blksize, result;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg("%s - already writing", __FUNCTION__);
- spin_unlock(&priv->lock);
- return;
- }
-
dbg("%s - transmitting data (frame n)", __FUNCTION__);
length = ((priv->wrfilled - priv->wrsent) > port->bulk_out_size) ?
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index d882fa3ad19a..0b03ddab53d9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -264,16 +264,26 @@
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.4.2"
+#define DRIVER_VERSION "v1.4.3"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Bill Ryder <bryder@sgi.com>, Kuba Ober <kuba@mareimbrium.org>"
#define DRIVER_DESC "USB FTDI Serial Converters Driver"
static int debug;
-static struct usb_device_id id_table_sio [] = {
- { USB_DEVICE(FTDI_VID, FTDI_SIO_PID) },
- { USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { } /* Terminating entry */
+/* struct ftdi_sio_quirk is used by devices requiring special attention. */
+struct ftdi_sio_quirk {
+ void (*setup)(struct usb_serial *); /* Special settings during startup. */
+};
+
+static void ftdi_USB_UIRT_setup (struct usb_serial *serial);
+static void ftdi_HE_TIRA1_setup (struct usb_serial *serial);
+
+static struct ftdi_sio_quirk ftdi_USB_UIRT_quirk = {
+ .setup = ftdi_USB_UIRT_setup,
+};
+
+static struct ftdi_sio_quirk ftdi_HE_TIRA1_quirk = {
+ .setup = ftdi_HE_TIRA1_setup,
};
/*
@@ -288,237 +298,11 @@ static struct usb_device_id id_table_sio [] = {
* the bcdDevice value is used to differentiate FT232BM and FT245BM from
* the earlier FT8U232AM and FT8U232BM. For now, include all known VID/PID
* combinations in both tables.
- * FIXME: perhaps bcdDevice can also identify 12MHz devices, but I don't know
- * if those ever went into mass production. [Ian Abbott]
+ * FIXME: perhaps bcdDevice can also identify 12MHz FT8U232AM devices,
+ * but I don't know if those ever went into mass production. [Ian Abbott]
*/
-static struct usb_device_id id_table_8U232AM [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0, 0x3ff) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_IOBOARD_PID) },
- { USB_DEVICE(INTERBIOMETRICS_VID, INTERBIOMETRICS_MINI_IOBOARD_PID) },
- { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0, 0x3ff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0, 0x3ff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0, 0x3ff) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_FT232BM [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_IRTRANS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_8U232AM_ALT_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RELAIS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_632_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_634_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_547_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_633_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_631_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_635_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_640_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_XF_642_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_VNHCPCUSB_D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_DSS20_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PIEGROUP_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2101_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2102_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2103_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2104_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2201_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2202_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2203_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2401_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2402_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2403_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2801_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2802_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_7_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(SEALEVEL_VID, SEALEVEL_2803_8_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(IDTECH_VID, IDTECH_IDT1221U_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(OCT_VID, OCT_US101_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_1, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_R2X0, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_3, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, PROTEGO_SPECIAL_4, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UO100_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ELV_UM100_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
- { USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
- { USB_DEVICE_VER(FTDI_VID, INSIDE_ACCESSO, 0x400, 0xffff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_VALUECAN_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(INTREPID_VID, INTREPID_NEOVI_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FALCOM_VID, FALCOM_TWIST_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_SUUNTO_SPORTS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_RM_CANVIEW_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USOTL4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USTL4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(BANDB_VID, BANDB_USO9ML2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, EVER_ECO_PRO_CDS, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_USB_UIRT [] = {
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
- { } /* Terminating entry */
-};
-
-
-static struct usb_device_id id_table_HE_TIRA1 [] = {
- { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
- { } /* Terminating entry */
-};
-
-
-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) },
@@ -540,14 +324,14 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_DSS20_PID) },
{ USB_DEVICE(FTDI_NF_RIC_VID, FTDI_NF_RIC_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_VNHCPCUSB_D_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_3_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_4_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_5_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_MTXORB_6_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_0_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_1_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_2_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_3_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_4_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_5_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_MTXORB_6_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_PERLE_ULTRAPORT_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_PIEGROUP_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2101_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2102_PID) },
@@ -597,35 +381,37 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_HE_TIRA1_PID, 0x400, 0xffff) },
- { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_HE_TIRA1_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_HE_TIRA1_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_USB_UIRT_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_USB_UIRT_quirk },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_1) },
{ USB_DEVICE(FTDI_VID, PROTEGO_R2X0) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_3) },
{ USB_DEVICE(FTDI_VID, PROTEGO_SPECIAL_4) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E808_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E809_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E80F_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E888_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E889_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88A_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88B_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88C_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88D_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88E_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_GUDEADS_E88F_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E808_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E809_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80A_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80B_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80D_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80E_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E80F_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E888_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E889_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88A_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88B_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88C_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88D_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88E_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_GUDEADS_E88F_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UO100_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
- { USB_DEVICE_VER(FTDI_VID, LINX_SDMUSBQSS_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_MASTERDEVEL2_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_0_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_1_PID, 0x400, 0xffff) },
- { USB_DEVICE_VER(FTDI_VID, LINX_FUTURE_2_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, LINX_SDMUSBQSS_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_MASTERDEVEL2_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_0_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_1_PID) },
+ { USB_DEVICE(FTDI_VID, LINX_FUTURE_2_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU20_0_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_CCSICDU40_1_PID) },
{ USB_DEVICE(FTDI_VID, INSIDE_ACCESSO) },
@@ -642,7 +428,7 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
{ USB_DEVICE(MOBILITY_VID, MOBILITY_USB_SERIAL_PID) },
- { USB_DEVICE_VER(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID, 0x400, 0xffff) },
+ { USB_DEVICE(FTDI_VID, FTDI_ACTIVE_ROBOTS_PID) },
{ } /* Terminating entry */
};
@@ -705,12 +491,8 @@ struct ftdi_private {
ASYNC_SPD_CUST | ASYNC_SPD_SHI | ASYNC_SPD_WARP )
/* function prototypes for a FTDI serial converter */
-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 int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id);
+static int ftdi_sio_attach (struct usb_serial *serial);
static void ftdi_shutdown (struct usb_serial *serial);
static int ftdi_open (struct usb_serial_port *port, struct file *filp);
static void ftdi_close (struct usb_serial_port *port, struct file *filp);
@@ -733,14 +515,16 @@ static unsigned short int ftdi_232am_baud_to_divisor (int baud);
static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
static __u32 ftdi_232bm_baud_to_divisor (int baud);
-static struct usb_serial_device_type ftdi_SIO_device = {
+static struct usb_serial_device_type ftdi_sio_device = {
.owner = THIS_MODULE,
- .name = "FTDI SIO",
- .id_table = id_table_sio,
+ .name = "FTDI USB Serial Device",
+ .short_name = "ftdi_sio",
+ .id_table = id_table_combined,
.num_interrupt_in = 0,
.num_bulk_in = 1,
.num_bulk_out = 1,
.num_ports = 1,
+ .probe = ftdi_sio_probe,
.open = ftdi_open,
.close = ftdi_close,
.throttle = ftdi_throttle,
@@ -755,143 +539,10 @@ static struct usb_serial_device_type ftdi_SIO_device = {
.ioctl = ftdi_ioctl,
.set_termios = ftdi_set_termios,
.break_ctl = ftdi_break_ctl,
- .attach = ftdi_SIO_startup,
+ .attach = ftdi_sio_attach,
.shutdown = ftdi_shutdown,
};
-static struct usb_serial_device_type ftdi_8U232AM_device = {
- .owner = THIS_MODULE,
- .name = "FTDI 8U232AM Compatible",
- .id_table = id_table_8U232AM,
- .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_8U232AM_startup,
- .shutdown = ftdi_shutdown,
-};
-
-static struct usb_serial_device_type ftdi_FT232BM_device = {
- .owner = THIS_MODULE,
- .name = "FTDI FT232BM Compatible",
- .id_table = id_table_FT232BM,
- .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_FT232BM_startup,
- .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",
- .id_table = id_table_USB_UIRT,
- .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_USB_UIRT_startup,
- .shutdown = ftdi_shutdown,
-};
-
-/* The TIRA1 is based on a FT232BM which requires a fixed baud rate of 100000
- * and which requires RTS-CTS to be enabled. */
-static struct usb_serial_device_type ftdi_HE_TIRA1_device = {
- .owner = THIS_MODULE,
- .name = "Home-Electronics TIRA-1 IR Transceiver",
- .id_table = id_table_HE_TIRA1,
- .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_HE_TIRA1_startup,
- .shutdown = ftdi_shutdown,
-};
-
-
#define WDR_TIMEOUT 5000 /* default urb timeout */
@@ -1212,6 +863,59 @@ check_and_exit:
} /* set_serial_info */
+/* Determine type of FTDI chip based on USB config and descriptor. */
+static void ftdi_determine_type(struct usb_serial_port *port)
+{
+ struct ftdi_private *priv = usb_get_serial_port_data(port);
+ struct usb_serial *serial = port->serial;
+ struct usb_device *udev = serial->dev;
+ unsigned version;
+ unsigned interfaces;
+
+ /* Assume it is not the original SIO device for now. */
+ priv->baud_base = 48000000 / 16;
+ priv->write_offset = 0;
+
+ version = le16_to_cpu(udev->descriptor.bcdDevice);
+ interfaces = udev->actconfig->desc.bNumInterfaces;
+ dbg("%s: bcdDevice = 0x%x, bNumInterfaces = %u", __FUNCTION__,
+ version, interfaces);
+ if (interfaces > 1) {
+ int inter;
+
+ /* Multiple interfaces. Assume FT2232C. */
+ priv->chip_type = FT2232C;
+ /* Determine interface code. */
+ inter = serial->interface->altsetting->desc.bInterfaceNumber;
+ if (inter == 0) {
+ priv->interface = PIT_SIOA;
+ } else {
+ priv->interface = PIT_SIOB;
+ }
+ /* BM-type devices have a bug where bcdDevice gets set
+ * to 0x200 when iSerialNumber is 0. */
+ if (version < 0x500) {
+ dbg("%s: something fishy - bcdDevice too low for multi-interface device",
+ __FUNCTION__);
+ }
+ } else if (version < 0x200) {
+ /* Old device. Assume its the original SIO. */
+ priv->chip_type = SIO;
+ priv->baud_base = 12000000 / 16;
+ priv->write_offset = 1;
+ } else if (version < 0x400) {
+ /* Assume its an FT8U232AM (or FT8U245AM) */
+ /* (It might be a BM because of the iSerialNumber bug,
+ * but it will still work as an AM device.) */
+ priv->chip_type = FT8U232AM;
+ } else {
+ /* Assume its an FT232BM (or FT245BM) */
+ priv->chip_type = FT232BM;
+ }
+ info("Detected %s", ftdi_chip_name[priv->chip_type]);
+}
+
+
/*
* ***************************************************************************
* Sysfs Attribute
@@ -1355,12 +1059,20 @@ static void remove_sysfs_attrs(struct usb_serial *serial)
* ***************************************************************************
*/
-/* Common startup subroutine */
-/* Called from ftdi_SIO_startup, etc. */
-static int ftdi_common_startup (struct usb_serial *serial)
+/* Probe function to check for special devices */
+static int ftdi_sio_probe (struct usb_serial *serial, const struct usb_device_id *id)
+{
+ usb_set_serial_data(serial, (void *)id->driver_info);
+
+ return (0);
+}
+
+/* attach subroutine */
+static int ftdi_sio_attach (struct usb_serial *serial)
{
struct usb_serial_port *port = serial->port[0];
struct ftdi_private *priv;
+ struct ftdi_sio_quirk *quirk;
dbg("%s",__FUNCTION__);
@@ -1400,150 +1112,49 @@ static int ftdi_common_startup (struct usb_serial *serial)
port->bulk_out_buffer = NULL;
usb_set_serial_port_data(serial->port[0], priv);
-
- return (0);
-}
-
-
-/* Startup for the SIO chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_SIO_startup (struct usb_serial *serial)
-{
- struct ftdi_private *priv;
- int err;
-
- dbg("%s",__FUNCTION__);
-
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
- }
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = SIO;
- priv->baud_base = 12000000 / 16;
- priv->write_offset = 1;
-
- return (0);
-}
-
-/* Startup for the 8U232AM chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_8U232AM_startup (struct usb_serial *serial)
-{ /* ftdi_8U232AM_startup */
- struct ftdi_private *priv;
- int err;
-
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
- }
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT8U232AM;
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FTDI supports 0.125, 0.25 and 0.5 divisor fractions! */
-
+ ftdi_determine_type (serial->port[0]);
create_sysfs_attrs(serial);
-
- return (0);
-} /* ftdi_8U232AM_startup */
-/* Startup for the FT232BM chip */
-/* Called from usbserial:serial_probe */
-static int ftdi_FT232BM_startup (struct usb_serial *serial)
-{ /* ftdi_FT232BM_startup */
- struct ftdi_private *priv;
- int err;
-
- dbg("%s",__FUNCTION__);
- err = ftdi_common_startup(serial);
- if (err){
- return (err);
+ /* Check for device requiring special set up. */
+ quirk = (struct ftdi_sio_quirk *)usb_get_serial_data(serial);
+ if (quirk && quirk->setup) {
+ quirk->setup(serial);
}
-
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT232BM;
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FT232BM supports multiple of 0.125 divisor fractions! */
- create_sysfs_attrs(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);
- }
+} /* ftdi_sio_attach */
- priv = usb_get_serial_port_data(serial->port[0]);
- priv->chip_type = FT2232C;
- inter = serial->interface->altsetting->desc.bInterfaceNumber;
- if (inter) {
- priv->interface = PIT_SIOB;
- }
- else {
- priv->interface = PIT_SIOA;
- }
- priv->baud_base = 48000000 / 2; /* Would be / 16, but FT2232C supports multiple of 0.125 divisor fractions! */
-
- create_sysfs_attrs(serial);
-
- return (0);
-} /* ftdi_FT2232C_startup */
-
-/* Startup for the USB-UIRT device, which requires hardwired baudrate (38400 gets mapped to 312500) */
+/* Setup 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)
-{ /* ftdi_USB_UIRT_startup */
+static void ftdi_USB_UIRT_setup (struct usb_serial *serial)
+{
struct ftdi_private *priv;
- int err;
dbg("%s",__FUNCTION__);
- err = ftdi_8U232AM_startup(serial);
- if (err){
- return (err);
- }
priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 77;
priv->force_baud = B38400;
-
- return (0);
-} /* ftdi_USB_UIRT_startup */
+} /* ftdi_USB_UIRT_setup */
-/* Startup for the HE-TIRA1 device, which requires hardwired
- * baudrate (38400 gets mapped to 100000) */
-static int ftdi_HE_TIRA1_startup (struct usb_serial *serial)
-{ /* ftdi_HE_TIRA1_startup */
+/* Setup for the HE-TIRA1 device, which requires hardwired
+ * baudrate (38400 gets mapped to 100000) and RTS-CTS enabled. */
+static void ftdi_HE_TIRA1_setup (struct usb_serial *serial)
+{
struct ftdi_private *priv;
- int err;
dbg("%s",__FUNCTION__);
- err = ftdi_FT232BM_startup(serial);
- if (err){
- return (err);
- }
priv = usb_get_serial_port_data(serial->port[0]);
priv->flags |= ASYNC_SPD_CUST;
priv->custom_divisor = 240;
priv->force_baud = B38400;
priv->force_rtscts = 1;
-
- return (0);
-} /* ftdi_HE_TIRA1_startup */
+} /* ftdi_HE_TIRA1_setup */
/* ftdi_shutdown is called from usbserial:usb_serial_disconnect
@@ -2367,60 +1978,11 @@ static int ftdi_ioctl (struct usb_serial_port *port, struct file * file, unsigne
{
struct ftdi_private *priv = usb_get_serial_port_data(port);
- int ret, mask;
-
dbg("%s cmd 0x%04x", __FUNCTION__, cmd);
/* Based on code from acm.c and others */
switch (cmd) {
- case TIOCMBIS: /* turns on (Sets) the lines as specified by the mask */
- dbg("%s TIOCMBIS", __FUNCTION__);
- if (get_user(mask, (unsigned long __user *) arg))
- return -EFAULT;
- if (mask & TIOCM_DTR){
- if ((ret = set_dtr(port, HIGH)) < 0) {
- err("Urb to set DTR failed");
- return(ret);
- }
- }
- if (mask & TIOCM_RTS) {
- if ((ret = set_rts(port, HIGH)) < 0){
- err("Urb to set RTS failed");
- return(ret);
- }
- }
- return(0);
- break;
-
- case TIOCMBIC: /* turns off (Clears) the lines as specified by the mask */
- dbg("%s TIOCMBIC", __FUNCTION__);
- if (get_user(mask, (unsigned long __user *) arg))
- return -EFAULT;
- if (mask & TIOCM_DTR){
- if ((ret = set_dtr(port, LOW)) < 0){
- err("Urb to unset DTR failed");
- return(ret);
- }
- }
- if (mask & TIOCM_RTS) {
- if ((ret = set_rts(port, LOW)) < 0){
- err("Urb to unset RTS failed");
- return(ret);
- }
- }
- return(0);
- break;
-
- /*
- * I had originally implemented TCSET{A,S}{,F,W} and
- * TCGET{A,S} here separately, however when testing I
- * found that the higher layers actually do the termios
- * conversions themselves and pass the call onto
- * ftdi_sio_set_termios.
- *
- */
-
case TIOCGSERIAL: /* gets serial port data */
return get_serial_info(port, (struct serial_struct __user *) arg);
@@ -2516,24 +2078,9 @@ static int __init ftdi_init (void)
int retval;
dbg("%s", __FUNCTION__);
- retval = usb_serial_register(&ftdi_SIO_device);
- if (retval)
- goto failed_SIO_register;
- retval = usb_serial_register(&ftdi_8U232AM_device);
- if (retval)
- goto failed_8U232AM_register;
- 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;
- retval = usb_serial_register(&ftdi_HE_TIRA1_device);
+ retval = usb_serial_register(&ftdi_sio_device);
if (retval)
- goto failed_HE_TIRA1_register;
+ goto failed_sio_register;
retval = usb_register(&ftdi_driver);
if (retval)
goto failed_usb_register;
@@ -2541,18 +2088,8 @@ static int __init ftdi_init (void)
info(DRIVER_VERSION ":" DRIVER_DESC);
return 0;
failed_usb_register:
- usb_serial_deregister(&ftdi_HE_TIRA1_device);
-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);
-failed_8U232AM_register:
- usb_serial_deregister(&ftdi_SIO_device);
-failed_SIO_register:
+ usb_serial_deregister(&ftdi_sio_device);
+failed_sio_register:
return retval;
}
@@ -2563,12 +2100,7 @@ static void __exit ftdi_exit (void)
dbg("%s", __FUNCTION__);
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);
+ usb_serial_deregister (&ftdi_sio_device);
}
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 99214aa3cd19..ddde5fb13f6b 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -174,10 +174,14 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
/* only do something if we have a bulk out endpoint */
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS) {
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
@@ -195,17 +199,20 @@ int usb_serial_generic_write(struct usb_serial_port *port, const unsigned char *
usb_serial_generic_write_bulk_callback), port);
/* send the data out the bulk port */
+ port->write_urb_busy = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ /* don't have to grab the lock here, as we will retry if != 0 */
+ port->write_urb_busy = 0;
+ } else
result = count;
return result;
}
/* no bulk out, so return 0 bytes written */
- return (0);
+ return 0;
}
int usb_serial_generic_write_room (struct usb_serial_port *port)
@@ -214,9 +221,9 @@ int usb_serial_generic_write_room (struct usb_serial_port *port)
int room = 0;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
if (serial->num_bulk_out) {
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size;
}
@@ -232,7 +239,7 @@ int usb_serial_generic_chars_in_buffer (struct usb_serial_port *port)
dbg("%s - port %d", __FUNCTION__, port->number);
if (serial->num_bulk_out) {
- if (port->write_urb->status == -EINPROGRESS)
+ if (port->write_urb_busy)
chars = port->write_urb->transfer_buffer_length;
}
@@ -291,6 +298,7 @@ void usb_serial_generic_write_bulk_callback (struct urb *urb, struct pt_regs *re
dbg("%s - port %d", __FUNCTION__, port->number);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 3bd69c4ef24b..c05c2a2a0f31 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -818,11 +818,6 @@ static void ipaq_write_gather(struct usb_serial_port *port)
struct ipaq_packet *pkt, *tmp;
struct urb *urb = port->write_urb;
- if (urb->status == -EINPROGRESS) {
- /* Should never happen */
- err("%s - flushing while urb is active !", __FUNCTION__);
- return;
- }
room = URBDATA_SIZE;
list_for_each_entry_safe(pkt, tmp, &priv->queue, list) {
count = min(room, (int)(pkt->len - pkt->written));
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 11105d74f461..85e242459c27 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -399,16 +399,21 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
dbg("%s - write request of 0 bytes", __FUNCTION__);
return 0;
}
-
- /* Racy and broken, FIXME properly! */
- if (port->write_urb->status == -EINPROGRESS)
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
+ }
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = min(count, port->bulk_out_size);
memcpy(port->bulk_out_buffer, buf, count);
dbg("%s count now:%d", __FUNCTION__, count);
-
+
usb_fill_bulk_urb(port->write_urb, dev,
usb_sndbulkpipe(dev, port->bulk_out_endpointAddress),
port->write_urb->transfer_buffer,
@@ -418,6 +423,7 @@ static int ipw_write(struct usb_serial_port *port, const unsigned char *buf, int
ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (ret != 0) {
+ port->write_urb_busy = 0;
dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, ret);
return ret;
}
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 59f234df5f89..937b2fdd7171 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -341,10 +341,14 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
if (count == 0)
return 0;
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
transfer_buffer = port->write_urb->transfer_buffer;
transfer_size = min(count, port->bulk_out_size - 1);
@@ -374,9 +378,10 @@ static int ir_write (struct usb_serial_port *port, const unsigned char *buf, int
port->write_urb->transfer_flags = URB_ZERO_PACKET;
result = usb_submit_urb (port->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result);
- else
+ } else
result = transfer_size;
return result;
@@ -387,7 +392,8 @@ static void ir_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
dbg("%s - port %d", __FUNCTION__, port->number);
-
+
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 7fd0aa9eccf6..635c384cb15a 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -520,9 +520,13 @@ static int keyspan_pda_write(struct usb_serial_port *port,
the TX urb is in-flight (wait until it completes)
the device is full (wait until it says there is room)
*/
- if (port->write_urb->status == -EINPROGRESS || priv->tx_throttled ) {
- return( 0 );
+ spin_lock(&port->lock);
+ if (port->write_urb_busy || priv->tx_throttled) {
+ spin_unlock(&port->lock);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
/* At this point the URB is in our control, nobody else can submit it
again (the only sudden transition was the one from EINPROGRESS to
@@ -570,7 +574,7 @@ static int keyspan_pda_write(struct usb_serial_port *port,
memcpy (port->write_urb->transfer_buffer, buf, count);
/* send the data out the bulk port */
port->write_urb->transfer_buffer_length = count;
-
+
priv->tx_room -= count;
port->write_urb->dev = port->serial->dev;
@@ -593,6 +597,8 @@ static int keyspan_pda_write(struct usb_serial_port *port,
rc = count;
exit:
+ if (rc < 0)
+ port->write_urb_busy = 0;
return rc;
}
@@ -602,6 +608,7 @@ static void keyspan_pda_write_bulk_callback (struct urb *urb, struct pt_regs *re
struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
struct keyspan_pda_private *priv;
+ port->write_urb_busy = 0;
priv = usb_get_serial_port_data(port);
/* queue up a wakeup at scheduler time */
@@ -626,12 +633,12 @@ static int keyspan_pda_write_room (struct usb_serial_port *port)
static int keyspan_pda_chars_in_buffer (struct usb_serial_port *port)
{
struct keyspan_pda_private *priv;
-
+
priv = usb_get_serial_port_data(port);
-
+
/* when throttled, return at least WAKEUP_CHARS to tell select() (via
n_tty.c:normal_poll() ) that we're not writeable. */
- if( port->write_urb->status == -EINPROGRESS || priv->tx_throttled )
+ if (port->write_urb_busy || priv->tx_throttled)
return 256;
return 0;
}
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index b5f2c06d4f3e..6a99ae192df1 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -254,10 +254,15 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
dbg("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (wport->write_urb->status == -EINPROGRESS) {
+
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
dbg("%s - already writing", __FUNCTION__);
- return (0);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
@@ -275,9 +280,10 @@ static int omninet_write (struct usb_serial_port *port, const unsigned char *buf
wport->write_urb->dev = serial->dev;
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
- if (result)
+ if (result) {
+ port->write_urb_busy = 0;
err("%s - failed submitting write urb, error %d", __FUNCTION__, result);
- else
+ } else
result = count;
return result;
@@ -291,7 +297,7 @@ static int omninet_write_room (struct usb_serial_port *port)
int room = 0; // Default: no room
- if (wport->write_urb->status != -EINPROGRESS)
+ if (wport->write_urb_busy)
room = wport->bulk_out_size - OMNINET_HEADERLEN;
// dbg("omninet_write_room returns %d", room);
@@ -306,6 +312,7 @@ static void omninet_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
// dbg("omninet_write_bulk_callback, port %0x\n", port);
+ port->write_urb_busy = 0;
if (urb->status) {
dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
return;
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 0e85ed6c6c19..96a17568cbf1 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -299,10 +299,14 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
dbg ("%s - write request of 0 bytes", __FUNCTION__);
return (0);
}
- if (port->write_urb->status == -EINPROGRESS) {
- dbg ("%s - already writing", __FUNCTION__);
- return (0);
+ spin_lock(&port->lock);
+ if (port->write_urb_busy) {
+ spin_unlock(&port->lock);
+ dbg("%s - already writing", __FUNCTION__);
+ return 0;
}
+ port->write_urb_busy = 1;
+ spin_unlock(&port->lock);
packet_length = port->bulk_out_size; // get max packetsize
@@ -354,6 +358,7 @@ static int safe_write (struct usb_serial_port *port, const unsigned char *buf, i
#endif
port->write_urb->dev = port->serial->dev;
if ((result = usb_submit_urb (port->write_urb, GFP_KERNEL))) {
+ port->write_urb_busy = 0;
err ("%s - failed submitting write urb, error %d", __FUNCTION__, result);
return 0;
}
@@ -368,7 +373,7 @@ static int safe_write_room (struct usb_serial_port *port)
dbg ("%s", __FUNCTION__);
- if (port->write_urb->status != -EINPROGRESS)
+ if (port->write_urb_busy)
room = port->bulk_out_size - (safe ? 2 : 0);
if (room) {
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 5da76dd8fb28..0267b26dde18 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1047,6 +1047,7 @@ int usb_serial_probe(struct usb_interface *interface,
memset(port, 0x00, sizeof(struct usb_serial_port));
port->number = i + serial->minor;
port->serial = serial;
+ spin_lock_init(&port->lock);
INIT_WORK(&port->work, usb_serial_port_softint, port);
serial->port[i] = port;
}
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index d1f0c4057fa6..57f92f054c75 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -69,6 +69,7 @@
* usb_serial_port: structure for the specific ports of a device.
* @serial: pointer back to the struct usb_serial owner of this port.
* @tty: pointer to the corresponding tty for this port.
+ * @lock: spinlock to grab when updating portions of this structure.
* @number: the number of the port (the minor number).
* @interrupt_in_buffer: pointer to the interrupt in buffer for this port.
* @interrupt_in_urb: pointer to the interrupt in struct urb for this port.
@@ -98,6 +99,7 @@
struct usb_serial_port {
struct usb_serial * serial;
struct tty_struct * tty;
+ spinlock_t lock;
unsigned char number;
unsigned char * interrupt_in_buffer;
@@ -117,6 +119,7 @@ struct usb_serial_port {
unsigned char * bulk_out_buffer;
int bulk_out_size;
struct urb * write_urb;
+ int write_urb_busy;
__u8 bulk_out_endpointAddress;
wait_queue_head_t write_wait;
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e43eddc3d44b..af294bb68c35 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -155,6 +155,15 @@ static int slave_configure(struct scsi_device *sdev)
* If this device makes that mistake, tell the sd driver. */
if (us->flags & US_FL_FIX_CAPACITY)
sdev->fix_capacity = 1;
+
+ /* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
+ * Hardware Error) when any low-level error occurs,
+ * recoverable or not. Setting this flag tells the SCSI
+ * midlayer to retry such commands, which frequently will
+ * succeed and fix the error. The worst this can lead to
+ * is an occasional series of retries that will all fail. */
+ sdev->retry_hwerror = 1;
+
} else {
/* Non-disk-type devices don't need to blacklist any pages
@@ -255,50 +264,23 @@ static int device_reset(struct scsi_cmnd *srb)
/* lock the device pointers and do the reset */
down(&(us->dev_semaphore));
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- result = FAILED;
- US_DEBUGP("No reset during disconnect\n");
- } else
- result = us->transport_reset(us);
+ result = us->transport_reset(us);
up(&(us->dev_semaphore));
- return result;
+ return result < 0 ? FAILED : SUCCESS;
}
-/* This resets the device's USB port. */
-/* It refuses to work if there's more than one interface in
- * the device, so that other users are not affected. */
+/* Simulate a SCSI bus reset by resetting the device's USB port. */
/* This is always called with scsi_lock(host) held */
static int bus_reset(struct scsi_cmnd *srb)
{
struct us_data *us = host_to_us(srb->device->host);
- int result, rc;
+ int result;
US_DEBUGP("%s called\n", __FUNCTION__);
- /* The USB subsystem doesn't handle synchronisation between
- * a device's several drivers. Therefore we reset only devices
- * with just one interface, which we of course own. */
-
down(&(us->dev_semaphore));
- if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
- result = -EIO;
- US_DEBUGP("No reset during disconnect\n");
- } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
- result = -EBUSY;
- US_DEBUGP("Refusing to reset a multi-interface device\n");
- } else {
- rc = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
- if (rc < 0) {
- US_DEBUGP("unable to lock device for reset: %d\n", rc);
- result = rc;
- } else {
- result = usb_reset_device(us->pusb_dev);
- if (rc)
- usb_unlock_device(us->pusb_dev);
- US_DEBUGP("usb_reset_device returns %d\n", result);
- }
- }
+ result = usb_stor_port_reset(us);
up(&(us->dev_semaphore));
/* lock the host for the return */
@@ -320,6 +302,14 @@ void usb_stor_report_device_reset(struct us_data *us)
}
}
+/* Report a driver-initiated bus reset to the SCSI layer.
+ * Calling this for a SCSI-initiated reset is unnecessary but harmless.
+ * The caller must own the SCSI host lock. */
+void usb_stor_report_bus_reset(struct us_data *us)
+{
+ scsi_report_bus_reset(us_to_host(us), 0);
+}
+
/***********************************************************************
* /proc/scsi/ functions
***********************************************************************/
diff --git a/drivers/usb/storage/scsiglue.h b/drivers/usb/storage/scsiglue.h
index d0a49af026c4..737e4fa6045f 100644
--- a/drivers/usb/storage/scsiglue.h
+++ b/drivers/usb/storage/scsiglue.h
@@ -42,6 +42,7 @@
#define _SCSIGLUE_H_
extern void usb_stor_report_device_reset(struct us_data *us);
+extern void usb_stor_report_bus_reset(struct us_data *us);
extern unsigned char usb_stor_sense_invalidCDB[18];
extern struct scsi_host_template usb_stor_host_template;
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 9743e289cd3b..e6b1c6cf07f2 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -266,8 +266,9 @@ int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
NULL, 0, 3*HZ);
/* reset the endpoint toggle */
- usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
- usb_pipeout(pipe), 0);
+ if (result >= 0)
+ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
+ usb_pipeout(pipe), 0);
US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
return result;
@@ -540,15 +541,15 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
*/
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- command was aborted\n");
- goto Handle_Abort;
+ srb->result = DID_ABORT << 16;
+ goto Handle_Errors;
}
/* if there is a transport error, reset and don't auto-sense */
if (result == USB_STOR_TRANSPORT_ERROR) {
US_DEBUGP("-- transport indicates error, resetting\n");
- us->transport_reset(us);
srb->result = DID_ERROR << 16;
- return;
+ goto Handle_Errors;
}
/* if the transport provided its own sense data, don't auto-sense */
@@ -668,7 +669,8 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
if (test_bit(US_FLIDX_TIMED_OUT, &us->flags)) {
US_DEBUGP("-- auto-sense aborted\n");
- goto Handle_Abort;
+ srb->result = DID_ABORT << 16;
+ goto Handle_Errors;
}
if (temp_result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("-- auto-sense failure\n");
@@ -677,9 +679,9 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
* multi-target device, since failure of an
* auto-sense is perfectly valid
*/
- if (!(us->flags & US_FL_SCM_MULT_TARG))
- us->transport_reset(us);
srb->result = DID_ERROR << 16;
+ if (!(us->flags & US_FL_SCM_MULT_TARG))
+ goto Handle_Errors;
return;
}
@@ -720,12 +722,28 @@ void usb_stor_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
return;
- /* abort processing: the bulk-only transport requires a reset
- * following an abort */
- Handle_Abort:
- srb->result = DID_ABORT << 16;
- if (us->protocol == US_PR_BULK)
+ /* Error and abort processing: try to resynchronize with the device
+ * by issuing a port reset. If that fails, try a class-specific
+ * device reset. */
+ Handle_Errors:
+
+ /* Let the SCSI layer know we are doing a reset, set the
+ * RESETTING bit, and clear the ABORTING bit so that the reset
+ * may proceed. */
+ scsi_lock(us_to_host(us));
+ usb_stor_report_bus_reset(us);
+ set_bit(US_FLIDX_RESETTING, &us->flags);
+ clear_bit(US_FLIDX_ABORTING, &us->flags);
+ scsi_unlock(us_to_host(us));
+
+ result = usb_stor_port_reset(us);
+ if (result < 0) {
+ scsi_lock(us_to_host(us));
+ usb_stor_report_device_reset(us);
+ scsi_unlock(us_to_host(us));
us->transport_reset(us);
+ }
+ clear_bit(US_FLIDX_RESETTING, &us->flags);
}
/* Stop the current URB transfer */
@@ -1124,7 +1142,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
* It's handy that every transport mechanism uses the control endpoint for
* resets.
*
- * Basically, we send a reset with a 20-second timeout, so we don't get
+ * Basically, we send a reset with a 5-second timeout, so we don't get
* jammed attempting to do the reset.
*/
static int usb_stor_reset_common(struct us_data *us,
@@ -1133,28 +1151,18 @@ static int usb_stor_reset_common(struct us_data *us,
{
int result;
int result2;
- int rc = FAILED;
- /* Let the SCSI layer know we are doing a reset, set the
- * RESETTING bit, and clear the ABORTING bit so that the reset
- * may proceed.
- */
- scsi_lock(us_to_host(us));
- usb_stor_report_device_reset(us);
- set_bit(US_FLIDX_RESETTING, &us->flags);
- clear_bit(US_FLIDX_ABORTING, &us->flags);
- scsi_unlock(us_to_host(us));
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+ US_DEBUGP("No reset during disconnect\n");
+ return -EIO;
+ }
- /* A 20-second timeout may seem rather long, but a LaCie
- * StudioDrive USB2 device takes 16+ seconds to get going
- * following a powerup or USB attach event.
- */
result = usb_stor_control_msg(us, us->send_ctrl_pipe,
request, requesttype, value, index, data, size,
- 20*HZ);
+ 5*HZ);
if (result < 0) {
US_DEBUGP("Soft reset failed: %d\n", result);
- goto Done;
+ return result;
}
/* Give the device some time to recover from the reset,
@@ -1164,7 +1172,7 @@ static int usb_stor_reset_common(struct us_data *us,
HZ*6);
if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
US_DEBUGP("Reset interrupted by disconnect\n");
- goto Done;
+ return -EIO;
}
US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n");
@@ -1173,17 +1181,14 @@ static int usb_stor_reset_common(struct us_data *us,
US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n");
result2 = usb_stor_clear_halt(us, us->send_bulk_pipe);
- /* return a result code based on the result of the control message */
- if (result < 0 || result2 < 0) {
+ /* return a result code based on the result of the clear-halts */
+ if (result >= 0)
+ result = result2;
+ if (result < 0)
US_DEBUGP("Soft reset failed\n");
- goto Done;
- }
- US_DEBUGP("Soft reset done\n");
- rc = SUCCESS;
-
- Done:
- clear_bit(US_FLIDX_RESETTING, &us->flags);
- return rc;
+ else
+ US_DEBUGP("Soft reset done\n");
+ return result;
}
/* This issues a CB[I] Reset to the device in question
@@ -1213,3 +1218,32 @@ int usb_stor_Bulk_reset(struct us_data *us)
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, us->ifnum, NULL, 0);
}
+
+/* Issue a USB port reset to the device. But don't do anything if
+ * there's more than one interface in the device, so that other users
+ * are not affected. */
+int usb_stor_port_reset(struct us_data *us)
+{
+ int result, rc;
+
+ if (test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+ result = -EIO;
+ US_DEBUGP("No reset during disconnect\n");
+ } else if (us->pusb_dev->actconfig->desc.bNumInterfaces != 1) {
+ result = -EBUSY;
+ US_DEBUGP("Refusing to reset a multi-interface device\n");
+ } else {
+ result = rc =
+ usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
+ if (result < 0) {
+ US_DEBUGP("unable to lock device for reset: %d\n",
+ result);
+ } else {
+ result = usb_reset_device(us->pusb_dev);
+ if (rc)
+ usb_unlock_device(us->pusb_dev);
+ US_DEBUGP("usb_reset_device returns %d\n", result);
+ }
+ }
+ return result;
+}
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index e25f8d8fc741..8d9e0663f8fe 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -171,4 +171,5 @@ extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe,
extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
void *buf, unsigned int length, int use_sg, int *residual);
+extern int usb_stor_port_reset(struct us_data *us);
#endif
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 9fcc7bd1fbe4..bd0ab3039bdd 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -697,7 +697,7 @@ UNUSUAL_DEV( 0x07af, 0x0004, 0x0100, 0x0133,
UNUSUAL_DEV( 0x07af, 0x0005, 0x0100, 0x0100,
"Microtech",
"USB-SCSI-HD50",
- US_SC_SCSI, US_PR_BULK, usb_stor_euscsi_init,
+ US_SC_DEVICE, US_PR_DEVICE, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
#ifdef CONFIG_USB_STORAGE_DPCM
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 35c1ca6b5a8e..77e7fc258aa2 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -847,10 +847,8 @@ retry:
wait_event_interruptible_timeout(us->delay_wait,
test_bit(US_FLIDX_DISCONNECTING, &us->flags),
delay_use * HZ);
- if (current->flags & PF_FREEZE) {
- refrigerator(PF_FREEZE);
+ if (try_to_freeze())
goto retry;
- }
}
/* If the device is still connected, perform the scanning */
diff --git a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c
index 9789115980a5..7bc1d44d8814 100644
--- a/drivers/video/aty/aty128fb.c
+++ b/drivers/video/aty/aty128fb.c
@@ -350,10 +350,8 @@ static int default_vmode __initdata = VMODE_1024_768_60;
static int default_cmode __initdata = CMODE_8;
#endif
-#ifdef CONFIG_PMAC_PBOOK
static int default_crt_on __initdata = 0;
static int default_lcd_on __initdata = 1;
-#endif
#ifdef CONFIG_MTRR
static int mtrr = 1;
@@ -1249,7 +1247,6 @@ static int aty128_crtc_to_var(const struct aty128_crtc *crtc,
return 0;
}
-#ifdef CONFIG_PMAC_PBOOK
static void aty128_set_crt_enable(struct aty128fb_par *par, int on)
{
if (on) {
@@ -1284,7 +1281,6 @@ static void aty128_set_lcd_enable(struct aty128fb_par *par, int on)
aty_st_le32(LVDS_GEN_CNTL, reg);
}
}
-#endif /* CONFIG_PMAC_PBOOK */
static void aty128_set_pll(struct aty128_pll *pll, const struct aty128fb_par *par)
{
@@ -1491,12 +1487,10 @@ static int aty128fb_set_par(struct fb_info *info)
info->fix.visual = par->crtc.bpp == 8 ? FB_VISUAL_PSEUDOCOLOR
: FB_VISUAL_DIRECTCOLOR;
-#ifdef CONFIG_PMAC_PBOOK
if (par->chip_gen == rage_M3) {
aty128_set_crt_enable(par, par->crt_on);
aty128_set_lcd_enable(par, par->lcd_on);
}
-#endif
if (par->accel_flags & FB_ACCELF_TEXT)
aty128_init_engine(par);
@@ -1652,7 +1646,6 @@ static int __init aty128fb_setup(char *options)
return 0;
while ((this_opt = strsep(&options, ",")) != NULL) {
-#ifdef CONFIG_PMAC_PBOOK
if (!strncmp(this_opt, "lcd:", 4)) {
default_lcd_on = simple_strtoul(this_opt+4, NULL, 0);
continue;
@@ -1660,7 +1653,6 @@ static int __init aty128fb_setup(char *options)
default_crt_on = simple_strtoul(this_opt+4, NULL, 0);
continue;
}
-#endif
#ifdef CONFIG_MTRR
if(!strncmp(this_opt, "nomtrr", 6)) {
mtrr = 0;
@@ -1752,10 +1744,8 @@ static int __init aty128_init(struct pci_dev *pdev, const struct pci_device_id *
info->fbops = &aty128fb_ops;
info->flags = FBINFO_FLAG_DEFAULT;
-#ifdef CONFIG_PMAC_PBOOK
par->lcd_on = default_lcd_on;
par->crt_on = default_crt_on;
-#endif
var = default_var;
#ifdef CONFIG_PPC_PMAC
@@ -2035,12 +2025,10 @@ static int aty128fb_blank(int blank, struct fb_info *fb)
aty_st_8(CRTC_EXT_CNTL+1, state);
-#ifdef CONFIG_PMAC_PBOOK
if (par->chip_gen == rage_M3) {
aty128_set_crt_enable(par, par->crt_on && !blank);
aty128_set_lcd_enable(par, par->lcd_on && !blank);
}
-#endif
#ifdef CONFIG_PMAC_BACKLIGHT
if ((_machine == _MACH_Pmac) && !blank)
set_backlight_enable(1);
@@ -2124,7 +2112,6 @@ static int aty128fb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg, struct fb_info *info)
{
-#ifdef CONFIG_PMAC_PBOOK
struct aty128fb_par *par = info->par;
u32 value;
int rc;
@@ -2149,7 +2136,6 @@ static int aty128fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
value = (par->crt_on << 1) | par->lcd_on;
return put_user(value, (__u32 __user *)arg);
}
-#endif
return -EINVAL;
}
diff --git a/drivers/video/au1100fb.c b/drivers/video/au1100fb.c
index cacd88cc84ab..b6fe30c3ad62 100644
--- a/drivers/video/au1100fb.c
+++ b/drivers/video/au1100fb.c
@@ -111,15 +111,15 @@ static int au1100fb_ioctl(struct inode *inode, struct file *file, u_int cmd,
void au1100_nocursor(struct display *p, int mode, int xx, int yy){};
static struct fb_ops au1100fb_ops = {
- owner: THIS_MODULE,
- fb_get_fix: fbgen_get_fix,
- fb_get_var: fbgen_get_var,
- fb_set_var: fbgen_set_var,
- fb_get_cmap: fbgen_get_cmap,
- fb_set_cmap: fbgen_set_cmap,
- fb_pan_display: fbgen_pan_display,
- fb_ioctl: au1100fb_ioctl,
- fb_mmap: au1100fb_mmap,
+ .owner = THIS_MODULE,
+ .fb_get_fix = fbgen_get_fix,
+ .fb_get_var = fbgen_get_var,
+ .fb_set_var = fbgen_set_var,
+ .fb_get_cmap = fbgen_get_cmap,
+ .fb_set_cmap = fbgen_set_cmap,
+ .fb_pan_display = fbgen_pan_display,
+ .fb_ioctl = au1100fb_ioctl,
+ .fb_mmap = au1100fb_mmap,
};
static void au1100_detect(void)
diff --git a/drivers/video/chipsfb.c b/drivers/video/chipsfb.c
index 95e72550d43f..e75a965ec760 100644
--- a/drivers/video/chipsfb.c
+++ b/drivers/video/chipsfb.c
@@ -28,22 +28,17 @@
#include <linux/fb.h>
#include <linux/init.h>
#include <linux/pci.h>
+#include <linux/console.h>
#include <asm/io.h>
#ifdef CONFIG_PMAC_BACKLIGHT
#include <asm/backlight.h>
#endif
-#ifdef CONFIG_PMAC_PBOOK
-#include <linux/adb.h>
-#include <linux/pmu.h>
-#endif
/*
* Since we access the display with inb/outb to fixed port numbers,
* we can only handle one 6555x chip. -- paulus
*/
-static struct fb_info chipsfb_info;
-
#define write_ind(num, val, ap, dp) do { \
outb((num), (ap)); outb((val), (dp)); \
} while (0)
@@ -74,14 +69,6 @@ static struct fb_info chipsfb_info;
inb(0x3da); read_ind(num, var, 0x3c0, 0x3c1); \
} while (0)
-#ifdef CONFIG_PMAC_PBOOK
-static unsigned char *save_framebuffer;
-int chips_sleep_notify(struct pmu_sleep_notifier *self, int when);
-static struct pmu_sleep_notifier chips_sleep_notifier = {
- chips_sleep_notify, SLEEP_LEVEL_VIDEO,
-};
-#endif
-
/*
* Exported functions
*/
@@ -356,6 +343,8 @@ static struct fb_var_screeninfo chipsfb_var __initdata = {
static void __init init_chips(struct fb_info *p, unsigned long addr)
{
+ memset(p->screen_base, 0, 0x100000);
+
p->fix = chipsfb_fix;
p->fix.smem_start = addr;
@@ -366,34 +355,41 @@ static void __init init_chips(struct fb_info *p, unsigned long addr)
fb_alloc_cmap(&p->cmap, 256, 0);
- if (register_framebuffer(p) < 0) {
- printk(KERN_ERR "C&T 65550 framebuffer failed to register\n");
- return;
- }
-
- printk(KERN_INFO "fb%d: Chips 65550 frame buffer (%dK RAM detected)\n",
- p->node, p->fix.smem_len / 1024);
-
chips_hw_init();
}
static int __devinit
chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
{
- struct fb_info *p = &chipsfb_info;
+ struct fb_info *p;
unsigned long addr, size;
unsigned short cmd;
+ int rc = -ENODEV;
+
+ if (pci_enable_device(dp) < 0) {
+ dev_err(&dp->dev, "Cannot enable PCI device\n");
+ goto err_out;
+ }
if ((dp->resource[0].flags & IORESOURCE_MEM) == 0)
- return -ENODEV;
+ goto err_disable;
addr = pci_resource_start(dp, 0);
size = pci_resource_len(dp, 0);
if (addr == 0)
- return -ENODEV;
- if (p->screen_base != 0)
- return -EBUSY;
- if (!request_mem_region(addr, size, "chipsfb"))
- return -EBUSY;
+ goto err_disable;
+
+ p = framebuffer_alloc(0, &dp->dev);
+ if (p == NULL) {
+ dev_err(&dp->dev, "Cannot allocate framebuffer structure\n");
+ rc = -ENOMEM;
+ goto err_disable;
+ }
+
+ if (pci_request_region(dp, 0, "chipsfb") != 0) {
+ dev_err(&dp->dev, "Cannot request framebuffer\n");
+ rc = -EBUSY;
+ goto err_release_fb;
+ }
#ifdef __BIG_ENDIAN
addr += 0x800000; // Use big-endian aperture
@@ -411,37 +407,89 @@ chipsfb_pci_init(struct pci_dev *dp, const struct pci_device_id *ent)
set_backlight_enable(1);
#endif /* CONFIG_PMAC_BACKLIGHT */
+#ifdef CONFIG_PPC
p->screen_base = __ioremap(addr, 0x200000, _PAGE_NO_CACHE);
+#else
+ p->screen_base = ioremap(addr, 0x200000);
+#endif
if (p->screen_base == NULL) {
- release_mem_region(addr, size);
- return -ENOMEM;
+ dev_err(&dp->dev, "Cannot map framebuffer\n");
+ rc = -ENOMEM;
+ goto err_release_pci;
}
+
+ pci_set_drvdata(dp, p);
p->device = &dp->dev;
+
init_chips(p, addr);
-#ifdef CONFIG_PMAC_PBOOK
- pmu_register_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+ if (register_framebuffer(p) < 0) {
+ dev_err(&dp->dev,"C&T 65550 framebuffer failed to register\n");
+ goto err_unmap;
+ }
+
+ dev_info(&dp->dev,"fb%d: Chips 65550 frame buffer"
+ " (%dK RAM detected)\n",
+ p->node, p->fix.smem_len / 1024);
- pci_set_drvdata(dp, p);
return 0;
+
+ err_unmap:
+ iounmap(p->screen_base);
+ err_release_pci:
+ pci_release_region(dp, 0);
+ err_release_fb:
+ framebuffer_release(p);
+ err_disable:
+ err_out:
+ return rc;
}
static void __devexit chipsfb_remove(struct pci_dev *dp)
{
struct fb_info *p = pci_get_drvdata(dp);
- if (p != &chipsfb_info || p->screen_base == NULL)
+ if (p->screen_base == NULL)
return;
unregister_framebuffer(p);
iounmap(p->screen_base);
p->screen_base = NULL;
- release_mem_region(pci_resource_start(dp, 0), pci_resource_len(dp, 0));
+ pci_release_region(dp, 0);
+}
+
+#ifdef CONFIG_PM
+static int chipsfb_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+ struct fb_info *p = pci_get_drvdata(pdev);
+
+ if (state == pdev->dev.power.power_state)
+ return 0;
+ if (state != PM_SUSPEND_MEM)
+ goto done;
+
+ acquire_console_sem();
+ chipsfb_blank(1, p);
+ fb_set_suspend(p, 1);
+ release_console_sem();
+ done:
+ pdev->dev.power.power_state = state;
+ return 0;
+}
+
+static int chipsfb_pci_resume(struct pci_dev *pdev)
+{
+ struct fb_info *p = pci_get_drvdata(pdev);
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier(&chips_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+ acquire_console_sem();
+ fb_set_suspend(p, 0);
+ chipsfb_blank(0, p);
+ release_console_sem();
+
+ pdev->dev.power.power_state = PMSG_ON;
+ return 0;
}
+#endif /* CONFIG_PM */
+
static struct pci_device_id chipsfb_pci_tbl[] = {
{ PCI_VENDOR_ID_CT, PCI_DEVICE_ID_CT_65550, PCI_ANY_ID, PCI_ANY_ID },
@@ -455,6 +503,10 @@ static struct pci_driver chipsfb_driver = {
.id_table = chipsfb_pci_tbl,
.probe = chipsfb_pci_init,
.remove = __devexit_p(chipsfb_remove),
+#ifdef CONFIG_PM
+ .suspend = chipsfb_pci_suspend,
+ .resume = chipsfb_pci_resume,
+#endif
};
int __init chips_init(void)
@@ -472,48 +524,4 @@ static void __exit chipsfb_exit(void)
pci_unregister_driver(&chipsfb_driver);
}
-#ifdef CONFIG_PMAC_PBOOK
-/*
- * Save the contents of the frame buffer when we go to sleep,
- * and restore it when we wake up again.
- */
-int
-chips_sleep_notify(struct pmu_sleep_notifier *self, int when)
-{
- struct fb_info *p = &chipsfb_info;
- int nb = p->var.yres * p->fix.line_length;
-
- if (p->screen_base == NULL)
- return PBOOK_SLEEP_OK;
-
- switch (when) {
- case PBOOK_SLEEP_REQUEST:
- save_framebuffer = vmalloc(nb);
- if (save_framebuffer == NULL)
- return PBOOK_SLEEP_REFUSE;
- break;
- case PBOOK_SLEEP_REJECT:
- if (save_framebuffer) {
- vfree(save_framebuffer);
- save_framebuffer = NULL;
- }
- break;
- case PBOOK_SLEEP_NOW:
- chipsfb_blank(1, p);
- if (save_framebuffer)
- memcpy(save_framebuffer, p->screen_base, nb);
- break;
- case PBOOK_WAKE:
- if (save_framebuffer) {
- memcpy(p->screen_base, save_framebuffer, nb);
- vfree(save_framebuffer);
- save_framebuffer = NULL;
- }
- chipsfb_blank(0, p);
- break;
- }
- return PBOOK_SLEEP_OK;
-}
-#endif /* CONFIG_PMAC_PBOOK */
-
MODULE_LICENSE("GPL");
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index e4b91a4b936c..cbff98337aa6 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -156,7 +156,6 @@ config FONT_6x11
config FONT_7x14
bool "console 7x14 font (not supported by all drivers)" if FONTS
depends on FRAMEBUFFER_CONSOLE
- default y if !SPARC32 && !SPARC64 && !FONTS
help
Console font with characters just a bit smaller than the default.
If the standard 8x16 font is a little too big for you, say Y.
@@ -197,8 +196,8 @@ config FONT_SUN12x22
standard font is unreadable for you, say Y, otherwise say N.
config FONT_10x18
- bool "console 10x18 font (not supported by all drivers)"
- depends on FONTS
+ bool "console 10x18 font (not supported by all drivers)" if FONTS
+ depends on FRAMEBUFFER_CONSOLE
help
This is a high resolution console font for machines with very
big letters. It fits between the sun 12x22 and the normal 8x16 font.
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index b209adbd508a..9dd0fbccf994 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -142,7 +142,6 @@ static int fbcon_set_origin(struct vc_data *);
#define CURSOR_DRAW_DELAY (1)
/* # VBL ints between cursor state changes */
-#define ARM_CURSOR_BLINK_RATE (10)
#define ATARI_CURSOR_BLINK_RATE (42)
#define MAC_CURSOR_BLINK_RATE (32)
#define DEFAULT_CURSOR_BLINK_RATE (20)
@@ -288,7 +287,7 @@ static void fb_flashcursor(void *private)
release_console_sem();
}
-#if (defined(__arm__) && defined(IRQ_VSYNCPULSE)) || defined(CONFIG_ATARI) || defined(CONFIG_MAC)
+#if defined(CONFIG_ATARI) || defined(CONFIG_MAC)
static int cursor_blink_rate;
static irqreturn_t fb_vbl_handler(int irq, void *dev_id, struct pt_regs *fp)
{
@@ -878,11 +877,6 @@ static const char *fbcon_startup(void)
}
#endif /* CONFIG_MAC */
-#if defined(__arm__) && defined(IRQ_VSYNCPULSE)
- cursor_blink_rate = ARM_CURSOR_BLINK_RATE;
- irqres = request_irq(IRQ_VSYNCPULSE, fb_vbl_handler, SA_SHIRQ,
- "framebuffer vbl", info);
-#endif
/* Initialize the work queue. If the driver provides its
* own work queue this means it will use something besides
* default timer to flash the cursor. */
diff --git a/drivers/video/fbsysfs.c b/drivers/video/fbsysfs.c
index 277d733c6d00..ddc9443254d9 100644
--- a/drivers/video/fbsysfs.c
+++ b/drivers/video/fbsysfs.c
@@ -228,8 +228,6 @@ static ssize_t store_virtual(struct class_device *class_device,
if (last - buf >= count)
return -EINVAL;
var.yres_virtual = simple_strtoul(last, &last, 0);
- printk(KERN_ERR "fb: xres %d yres %d\n", var.xres_virtual,
- var.yres_virtual);
if ((err = activate(fb_info, &var)))
return err;
@@ -258,7 +256,7 @@ static ssize_t show_cmap(struct class_device *class_device, char *buf)
unsigned int offset = 0, i;
if (!fb_info->cmap.red || !fb_info->cmap.blue ||
- fb_info->cmap.green || fb_info->cmap.transp)
+ !fb_info->cmap.green || !fb_info->cmap.transp)
return -EINVAL;
for (i = 0; i < fb_info->cmap.len; i++) {
diff --git a/drivers/video/logo/Kconfig b/drivers/video/logo/Kconfig
index 6ba10e3aceff..3e9ccf370ab2 100644
--- a/drivers/video/logo/Kconfig
+++ b/drivers/video/logo/Kconfig
@@ -63,5 +63,10 @@ config LOGO_SUPERH_CLUT224
depends on LOGO && SUPERH
default y
+config LOGO_M32R_CLUT224
+ bool "224-color M32R Linux logo"
+ depends on LOGO && M32R
+ default y
+
endmenu
diff --git a/drivers/video/logo/Makefile b/drivers/video/logo/Makefile
index b0d995020bd1..d0244c04af5a 100644
--- a/drivers/video/logo/Makefile
+++ b/drivers/video/logo/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_LOGO_SUN_CLUT224) += logo_sun_clut224.o
obj-$(CONFIG_LOGO_SUPERH_MONO) += logo_superh_mono.o
obj-$(CONFIG_LOGO_SUPERH_VGA16) += logo_superh_vga16.o
obj-$(CONFIG_LOGO_SUPERH_CLUT224) += logo_superh_clut224.o
+obj-$(CONFIG_LOGO_M32R_CLUT224) += logo_m32r_clut224.o
# How to generate logo's
diff --git a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
index 77b622075001..788fa812c871 100644
--- a/drivers/video/logo/logo.c
+++ b/drivers/video/logo/logo.c
@@ -33,6 +33,7 @@ extern const struct linux_logo logo_sun_clut224;
extern const struct linux_logo logo_superh_mono;
extern const struct linux_logo logo_superh_vga16;
extern const struct linux_logo logo_superh_clut224;
+extern const struct linux_logo logo_m32r_clut224;
const struct linux_logo *fb_find_logo(int depth)
@@ -97,6 +98,10 @@ const struct linux_logo *fb_find_logo(int depth)
/* SuperH Linux logo */
logo = &logo_superh_clut224;
#endif
+#ifdef CONFIG_LOGO_M32R_CLUT224
+ /* M32R Linux logo */
+ logo = &logo_m32r_clut224;
+#endif
}
return logo;
}
diff --git a/drivers/video/logo/logo_m32r_clut224.ppm b/drivers/video/logo/logo_m32r_clut224.ppm
new file mode 100644
index 000000000000..8b2983c5a0bd
--- /dev/null
+++ b/drivers/video/logo/logo_m32r_clut224.ppm
@@ -0,0 +1,1292 @@
+P3
+# CREATOR: The GIMP's PNM Filter Version 1.0
+#
+# Note: how to convert ppm to pnm(ascii).
+# $ convert -posterize 224 m32r.ppm - | pnm2asc -f5 >logo_m32r_clut224.ppm
+#
+# convert - imagemagick: /usr/bin/convert
+# pnm2asc - pnm to ascii-pnm format converter
+# http://www.is.aist.go.jp/etlcdb/util/p2a.htm#English
+
+80 80
+255
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 43 43 43 75 75 75 27 27 27 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 59 59 59 123 123 123 67 67 67 27 27 27
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 10 6 3 59 59 59 80 80 80 43 43 43 27 27 27
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 19 19 19 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 10 6 3 10 6 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 10 6 3 11 11 11 11 11 11 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 27 27 27 10 6 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 19 19 19 2 2 3 2 2 3 51 51 51 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 123 123 123 196 196 196 115 115 115 2 2 3
+ 2 2 3 2 2 3 2 2 3 75 75 75 141 141 140
+ 172 172 172 196 196 196 190 189 188 2 2 3 11 11 11
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 27 27 27 164 164 164 228 228 228 221 221 220 10 6 3
+ 2 2 3 2 2 3 2 2 3 172 172 172 245 245 245
+ 254 254 252 254 254 252 221 221 220 35 35 35 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 164 164 164 228 228 228 35 35 35 236 236 236 236 236 236
+ 2 2 3 11 11 11 2 2 3 254 254 252 245 245 245
+ 2 2 3 75 75 75 245 245 245 245 245 245 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 212 212 212 2 2 3 51 51 51 11 11 11 245 245 245
+ 27 27 27 80 80 80 10 6 3 254 254 252 2 2 3
+ 2 2 3 91 91 91 19 19 19 254 254 252 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 196 196 196 10 6 3 2 2 3 11 11 11 107 107 107
+ 49 35 5 57 42 11 31 22 3 236 236 236 2 2 3
+ 2 2 3 2 2 3 2 2 3 254 254 252 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 107 107 107 221 221 220 2 2 3 64 43 7 194 148 10
+ 236 188 10 225 180 10 170 126 10 236 188 10 94 86 67
+ 2 2 3 2 2 3 204 204 204 236 236 236 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 228 228 228 182 126 10 218 164 9 236 188 10
+ 236 188 10 237 204 14 236 205 40 246 214 48 246 214 48
+ 245 189 11 209 156 9 196 196 196 11 11 11 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 165 114 10 207 148 7 229 172 9 236 180 10
+ 236 196 11 237 204 14 242 218 43 246 218 75 246 218 19
+ 246 213 13 246 218 19 244 205 11 218 164 9 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 164 109 5 192 133 7 224 165 9 236 180 10 236 188 10
+ 236 196 11 241 212 42 246 218 75 246 218 19 246 218 19
+ 246 218 19 236 196 11 150 114 10 229 172 9 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 165 114 10 201 142 7 229 172 9 242 182 11 236 188 10
+ 237 204 14 245 213 67 246 218 19 246 213 13 246 213 13
+ 154 119 10 207 148 7 218 164 9 216 156 8 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 120 78 3 225 180 10 245 189 11 236 205 40
+ 241 212 42 241 212 17 237 204 14 148 107 9 182 126 10
+ 216 156 8 218 164 9 207 148 7 82 70 43 2 2 3
+ 2 2 3 123 123 123 35 35 35 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 10 6 3 180 180 180 156 102 5 135 88 5 142 106 7
+ 126 98 11 165 114 10 185 132 9 207 148 7 215 150 13
+ 199 140 8 188 148 71 196 196 196 190 189 188 2 2 3
+ 2 2 3 11 11 11 132 132 132 75 75 75 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 10 6 3 190 189 188 190 189 188 151 97 5 192 133 7
+ 207 148 7 206 142 8 199 140 8 180 121 7 180 132 31
+ 190 189 188 190 189 188 212 212 212 212 212 212 107 107 107
+ 2 2 3 2 2 3 99 99 99 51 51 51 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 190 189 188 190 189 188 190 189 188 136 95 7
+ 151 97 5 151 97 5 151 97 5 183 156 91 190 189 188
+ 190 189 188 228 228 228 254 254 252 254 254 252 221 221 220
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 10 6 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 75 75 75 245 245 245 196 196 196 190 189 188 190 189 188
+ 190 189 188 196 196 196 190 189 188 190 189 188 204 204 204
+ 236 236 236 254 254 252 254 254 252 254 254 252 254 254 252
+ 35 35 35 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 27 27 27 2 2 3
+ 245 245 245 254 254 252 245 245 245 190 189 188 190 189 188
+ 190 189 188 190 189 188 190 189 188 212 212 212 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 10 6 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 132 132 132
+ 254 254 252 254 254 252 254 254 252 236 236 236 196 196 196
+ 190 189 188 204 204 204 245 245 245 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 80 80 80 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 212 212 212 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 2 2 3 2 2 3 204 204 204 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 236 236 236 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 11 11 11 164 164 164 212 212 212
+ 236 236 236 245 245 245 254 254 252 236 236 236 221 221 220
+ 221 221 220 228 228 228 245 245 245 245 245 245 245 245 245
+ 236 236 236 221 221 220 212 212 212 204 204 204 204 204 204
+ 196 196 196 204 204 204 59 59 59 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 27 27 27 172 172 172 212 212 212
+ 236 236 236 254 254 252 254 254 252 254 254 252 228 228 228
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 221 221 220 204 204 204 196 196 196
+ 196 196 196 196 196 196 228 228 228 19 19 19 2 2 3
+ 80 80 80 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 164 164 164 236 236 236 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 236 236 236 212 212 212 196 196 196 245 245 245 2 2 3
+ 2 2 3 11 11 11 51 51 51 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 86 86 83
+ 2 2 3 27 27 27 236 236 236 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 212 212 212 196 196 196 91 91 91
+ 2 2 3 2 2 3 2 2 3 11 11 11 2 2 3
+ 2 2 3 2 2 3 2 2 3 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 2 2 3 2 2 3
+ 2 2 3 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 221 221 220 245 245 245
+ 2 2 3 11 11 11 43 43 43 19 19 19 10 6 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 2 2 3 80 80 80 2 2 3
+ 2 2 3 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 43 43 43 27 27 27 80 80 80 19 19 19 80 80 80
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 2 2 3 2 2 3 2 2 3
+ 245 245 245 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 254 254 252 254 254 252 236 236 236 17 11 233
+ 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 11 11 11 11 11 11 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 2 2 3 67 67 67 2 2 3 19 19 19
+ 254 254 252 254 254 252 245 245 245 17 11 233 245 245 245
+ 254 254 252 254 254 252 17 11 233 228 228 228 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233
+ 17 11 233 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 10 6 3 11 11 11 2 2 3 228 228 228
+ 254 254 252 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 17 11 233 17 11 233 17 11 233 245 245 245
+ 254 254 252 254 254 252 17 11 233 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 27 27 27 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 2 2 3 2 2 3 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 17 11 233 254 254 252
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 254 254 252 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 19 19 19 2 2 3 2 2 3 254 254 252
+ 254 254 252 254 254 252 17 11 233 245 245 245 17 11 233
+ 17 11 233 245 245 245 254 254 252 17 11 233 254 254 252
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 2 2 3
+ 2 2 3 19 19 19 2 2 3 19 19 19 254 254 252
+ 254 254 252 245 245 245 17 11 233 254 254 252 17 11 233
+ 17 11 233 254 254 252 254 254 252 17 11 233 254 254 252
+ 254 254 252 254 254 252 17 11 233 17 11 233 254 254 252
+ 17 11 233 17 11 233 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 43 43 43 2 2 3 43 43 43 254 254 252
+ 245 245 245 254 254 252 17 11 233 254 254 252 17 11 233
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 17 11 233 17 11 233 17 11 233 254 254 252 17 11 233
+ 17 11 233 17 11 233 17 11 233 17 11 233 17 11 233
+ 245 245 245 254 254 252 17 11 233 254 254 252 254 254 252
+ 245 245 245 2 2 3 2 2 3 2 2 3 11 11 11
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 75 75 75 2 2 3 99 99 99 254 254 252
+ 254 254 252 254 254 252 17 11 233 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 17 11 233 245 245 245 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 17 11 233 17 11 233
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 2 2 3 75 75 75
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 2 2 3
+ 2 2 3 2 2 3 11 11 11 107 107 107 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 245 245 245 236 236 236 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 2 2 3 11 11 11 19 19 19
+ 11 11 11 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 2 2 3 11 11 11
+ 140 102 3 11 11 11 10 6 3 67 67 67 254 254 252
+ 245 245 245 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 2 2 3 43 43 43 2 2 3 2 2 3
+ 2 2 3 11 11 11 67 67 67 11 11 11 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 185 132 9 242 182 11
+ 245 189 11 245 189 11 49 35 5 2 2 3 228 228 228
+ 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 228 228 228 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 245 238 222 232 189 94
+ 226 186 99 43 43 43 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 59 59 59 2 2 3
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 216 156 8 236 180 22
+ 245 189 11 245 189 11 245 189 11 49 35 5 11 11 11
+ 212 212 212 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 245 245 245 254 254 252 254 254 252 229 172 9 246 218 19
+ 246 218 19 41 27 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 19 19 19 27 27 27 196 154 14
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 199 140 8 229 172 9 242 182 11
+ 245 189 11 245 189 11 245 189 11 244 196 10 2 2 3
+ 2 2 3 115 115 115 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 228 228 228 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 224 165 9 245 189 11
+ 236 196 11 19 19 19 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 11 11 11 236 196 11
+ 244 205 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 182 126 10 209 156 9 215 150 13
+ 193 140 10 207 148 24 216 156 8 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 209 156 9
+ 2 2 3 2 2 3 43 43 43 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 236 236 236 216 156 8 245 189 11
+ 229 172 9 64 43 7 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 207 148 7 236 188 10
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 121 7 216 156 8 242 182 11 236 180 10
+ 229 172 9 242 182 11 242 182 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 237 204 14
+ 170 126 10 2 2 3 2 2 3 11 11 11 236 236 236
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 204 204 204 196 196 196 216 156 8 236 180 10
+ 224 165 9 182 126 10 73 48 6 2 2 3 2 2 3
+ 2 2 3 41 27 3 199 140 8 229 172 9 236 180 10
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 185 132 9 229 172 9 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 226 188 11 2 2 3 2 2 3 2 2 3 11 11 11
+ 245 245 245 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 196 196 196 196 196 196 215 150 13 236 180 10
+ 229 172 9 201 142 7 185 132 9 180 121 7 173 120 10
+ 180 121 7 192 133 7 229 172 9 242 182 11 245 189 11
+ 245 189 11 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 126 47 224 165 9 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 236 188 10 193 140 10 2 2 3 2 2 3 2 2 3
+ 2 2 3 212 212 212 254 254 252 245 245 245 245 245 245
+ 254 254 252 254 254 252 254 254 252 245 245 245 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 204 204 204 196 196 196 199 140 8 229 172 9
+ 236 180 10 218 164 9 215 150 13 207 148 7 207 148 7
+ 216 156 8 229 172 9 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 185 132 9 216 156 8 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 196 11 19 19 19 2 2 3 2 2 3
+ 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 245 245 245 254 254 252 254 254 252
+ 245 245 245 221 221 220 196 196 196 185 132 9 229 172 9
+ 242 182 11 229 172 9 224 165 9 218 164 9 224 165 9
+ 229 172 9 236 180 10 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 180 22 242 182 11 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 236 180 22 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 236 188 10 225 180 10 2 2 3 2 2 3
+ 2 2 3 11 11 11 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 221 221 220 19 19 19 185 132 9 224 165 9
+ 245 189 11 245 189 11 242 182 11 236 180 10 236 180 10
+ 242 182 11 242 182 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 196 154 14
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 207 148 7 236 180 22 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 237 204 14 135 88 5 2 2 3
+ 27 27 27 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 245 245 245 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 67 67 67 19 13 3 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 236 180 22 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 245 189 11 242 182 11
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 236 188 10 226 188 11 104 83 48
+ 254 254 252 254 254 252 254 254 252 254 254 252 245 245 245
+ 254 254 252 254 254 252 245 245 245 254 254 252 245 245 245
+ 254 254 252 245 245 245 254 254 252 254 254 252 254 254 252
+ 2 2 3 2 2 3 56 38 5 185 132 9 229 172 9
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 229 172 9 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 182 126 10 215 150 13 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 245 189 11 236 196 11 216 156 8
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 245 245 245 2 2 3
+ 2 2 3 2 2 3 75 54 3 182 126 10 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 229 172 9
+ 207 148 24 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 192 133 7 229 172 9 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 242 182 11 225 180 10 224 165 9
+ 107 69 5 245 245 245 254 254 252 254 254 252 254 254 252
+ 254 254 252 254 254 252 254 254 252 254 254 252 254 254 252
+ 254 254 252 236 236 236 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 91 67 9 182 126 10 229 172 9
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 242 182 11 216 156 8 180 126 47
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 206 142 8 224 165 9 245 189 11 242 182 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 242 182 11 242 182 11 216 156 8
+ 156 102 5 19 13 3 43 43 43 196 196 196 254 254 252
+ 245 245 245 254 254 252 254 254 252 204 204 204 51 51 51
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 95 62 5 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 242 182 11 245 189 11 245 189 11
+ 236 180 22 216 156 8 206 142 8 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 192 133 7 215 150 13 229 172 9 229 172 9
+ 236 180 10 236 180 22 242 182 11 242 182 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 245 189 11 245 189 11 229 172 9 216 156 8
+ 156 102 5 83 54 6 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 115 73 3 185 132 9 229 172 9
+ 242 182 11 245 189 11 245 189 11 245 189 11 245 189 11
+ 245 189 11 242 182 11 229 172 9 229 172 9 216 156 8
+ 180 121 7 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 180 121 7 182 126 10 192 133 7 199 140 8
+ 207 148 7 215 150 13 216 156 8 224 165 9 229 172 9
+ 236 180 22 245 189 11 242 182 11 245 189 11 242 182 11
+ 245 189 11 245 189 11 242 182 11 229 172 9 199 140 8
+ 151 97 5 101 67 7 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 115 73 3 180 121 7 216 156 8
+ 236 180 22 242 182 11 245 189 11 245 189 11 242 182 11
+ 236 180 10 224 165 9 215 150 13 206 142 8 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 156 102 5 164 109 5 172 114 5 180 121 7 180 121 7
+ 192 133 7 201 142 7 216 156 8 224 165 9 236 180 22
+ 245 189 11 242 182 11 229 172 9 201 142 7 172 114 5
+ 125 83 5 83 54 6 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 2 2 3 2 2 3 2 2 3
+ 2 2 3 2 2 3 91 58 5 156 102 5 192 133 7
+ 216 156 8 229 172 9 236 180 10 236 180 10 229 172 9
+ 215 150 13 199 140 8 164 109 5 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 120 78 3 132 82 3
+ 151 97 5 157 106 7 180 121 7 185 132 9 193 140 10
+ 207 148 7 207 148 7 192 133 7 172 114 5 132 82 3
+ 101 67 7 41 27 3 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 73 48 6 143 90 3 180 121 7
+ 192 133 7 207 148 7 207 148 7 201 142 7 185 132 9
+ 173 120 10 136 95 7 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 91 58 5 125 83 5 135 88 5
+ 144 95 7 151 97 5 132 82 3 115 73 3 95 62 5
+ 64 43 7 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 64 43 7 91 58 5 151 97 5
+ 157 106 7 172 114 5 172 114 5 164 109 5 151 97 5
+ 85 59 6 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 73 48 6
+ 91 58 5 95 62 5 95 62 5 91 58 5 56 38 5
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 83 54 6
+ 107 69 5 132 82 3 125 83 5 101 67 7 71 47 31
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
+ 215 150 13 215 150 13 215 150 13 215 150 13 215 150 13
diff --git a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c
index 76fd3a519b8a..a18dd024fc86 100644
--- a/drivers/video/matrox/matroxfb_misc.c
+++ b/drivers/video/matrox/matroxfb_misc.c
@@ -197,10 +197,7 @@ int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) {
DBG(__FUNCTION__)
hw->SEQ[0] = 0x00;
- if (fwidth == 9)
- hw->SEQ[1] = 0x00;
- else
- hw->SEQ[1] = 0x01; /* or 0x09 */
+ hw->SEQ[1] = 0x01; /* or 0x09 */
hw->SEQ[2] = 0x0F; /* bitplanes */
hw->SEQ[3] = 0x00;
hw->SEQ[4] = 0x0E;
diff --git a/drivers/video/platinumfb.c b/drivers/video/platinumfb.c
index 3dd1de1539d2..b00887e9851c 100644
--- a/drivers/video/platinumfb.c
+++ b/drivers/video/platinumfb.c
@@ -523,7 +523,7 @@ int __init platinumfb_setup(char *options)
#define invalidate_cache(addr)
#endif
-static int __devinit platinumfb_probe(struct of_device* odev, const struct of_match *match)
+static int __devinit platinumfb_probe(struct of_device* odev, const struct of_device_id *match)
{
struct device_node *dp = odev->node;
struct fb_info *info;
@@ -647,12 +647,10 @@ static int __devexit platinumfb_remove(struct of_device* odev)
return 0;
}
-static struct of_match platinumfb_match[] =
+static struct of_device_id platinumfb_match[] =
{
{
.name = "platinum",
- .type = OF_ANY_MATCH,
- .compatible = OF_ANY_MATCH,
},
{},
};
diff --git a/drivers/video/pxafb.c b/drivers/video/pxafb.c
index 815fbc8317fc..16e37a535d85 100644
--- a/drivers/video/pxafb.c
+++ b/drivers/video/pxafb.c
@@ -43,6 +43,7 @@
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
+#include <asm/div64.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/bitfield.h>
#include <asm/arch/pxafb.h>
@@ -460,7 +461,7 @@ static inline unsigned int get_pcd(unsigned int pixclock)
* speeds */
pcd = (unsigned long long)get_lcdclk_frequency_10khz() * pixclock;
- pcd /= 100000000 * 2;
+ do_div(pcd, 100000000 * 2);
/* no need for this, since we should subtract 1 anyway. they cancel */
/* pcd += 1; */ /* make up for integer math truncations */
return (unsigned int)pcd;
diff --git a/drivers/video/s1d13xxxfb.c b/drivers/video/s1d13xxxfb.c
index 789de13f461f..3848be2b9d2d 100644
--- a/drivers/video/s1d13xxxfb.c
+++ b/drivers/video/s1d13xxxfb.c
@@ -67,12 +67,18 @@ static struct fb_fix_screeninfo __devinitdata s1d13xxxfb_fix = {
static inline u8
s1d13xxxfb_readreg(struct s1d13xxxfb_par *par, u16 regno)
{
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
return readb(par->regs + regno);
}
static inline void
s1d13xxxfb_writereg(struct s1d13xxxfb_par *par, u16 regno, u8 value)
{
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ regno=((regno & 1) ? (regno & ~1L) : (regno + 1));
+#endif
writeb(value, par->regs + regno);
}
@@ -259,7 +265,11 @@ s1d13xxxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
dbg("s1d13xxxfb_setcolreg: pseudo %d, val %08x\n",
regno, pseudo_val);
+#if defined(CONFIG_PLAT_MAPPI)
+ ((u32 *)info->pseudo_palette)[regno] = cpu_to_le16(pseudo_val);
+#else
((u32 *)info->pseudo_palette)[regno] = pseudo_val;
+#endif
break;
case FB_VISUAL_PSEUDOCOLOR:
diff --git a/drivers/video/savage/savagefb_driver.c b/drivers/video/savage/savagefb_driver.c
index 8fadcdae6f42..f4633d1891f1 100644
--- a/drivers/video/savage/savagefb_driver.c
+++ b/drivers/video/savage/savagefb_driver.c
@@ -2113,7 +2113,7 @@ static int savagefb_suspend (struct pci_dev* dev, pm_message_t state)
printk(KERN_DEBUG "state: %u\n", state);
acquire_console_sem();
- fb_set_suspend(info, state);
+ fb_set_suspend(info, pci_choose_state(dev, state));
savage_disable_mmio(par);
release_console_sem();
diff --git a/drivers/video/vesafb.c b/drivers/video/vesafb.c
index f3069b01e248..9ed1a931dd31 100644
--- a/drivers/video/vesafb.c
+++ b/drivers/video/vesafb.c
@@ -389,10 +389,11 @@ static int __init vesafb_probe(struct device *device)
unsigned int temp_size = size_total;
/* Find the largest power-of-two */
while (temp_size & (temp_size - 1))
- temp_size &= (temp_size - 1);
-
- /* Try and find a power of two to add */
- while (temp_size && mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
+ temp_size &= (temp_size - 1);
+
+ /* Try and find a power of two to add */
+ while (temp_size > PAGE_SIZE &&
+ mtrr_add(vesafb_fix.smem_start, temp_size, MTRR_TYPE_WRCOMB, 1)==-EINVAL) {
temp_size >>= 1;
}
}
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index b460927ec32a..8a9c42822502 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -516,6 +516,7 @@ static void w1_slave_found(unsigned long data, u64 rn)
struct w1_reg_num *tmp;
int family_found = 0;
struct w1_master *dev;
+ u64 rn_le = cpu_to_le64(rn);
dev = w1_search_master(data);
if (!dev) {
@@ -544,10 +545,8 @@ static void w1_slave_found(unsigned long data, u64 rn)
slave_count++;
}
- rn = cpu_to_le64(rn);
-
if (slave_count == dev->slave_count &&
- rn && ((le64_to_cpu(rn) >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn, 7)) {
+ rn && ((rn >> 56) & 0xff) == w1_calc_crc8((u8 *)&rn_le, 7)) {
w1_attach_slave_device(dev, tmp);
}
@@ -646,7 +645,7 @@ static int w1_control(void *data)
while (!control_needs_exit || have_to_wait) {
have_to_wait = 0;
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
msleep_interruptible(w1_timeout * 1000);
if (signal_pending(current))
@@ -725,7 +724,7 @@ int w1_process(void *data)
allow_signal(SIGTERM);
while (!test_bit(W1_MASTER_NEED_EXIT, &dev->flags)) {
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
msleep_interruptible(w1_timeout * 1000);
if (signal_pending(current))
diff --git a/fs/Kconfig b/fs/Kconfig
index a7c0cc3203cb..5d0c4be43dba 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -29,6 +29,7 @@ config EXT2_FS_XATTR
config EXT2_FS_POSIX_ACL
bool "Ext2 POSIX Access Control Lists"
depends on EXT2_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -50,6 +51,23 @@ config EXT2_FS_SECURITY
If you are not using a security module that requires using
extended attributes for file security labels, say N.
+config EXT2_FS_XIP
+ bool "Ext2 execute in place support"
+ depends on EXT2_FS
+ help
+ Execute in place can be used on memory-backed block devices. If you
+ enable this option, you can select to mount block devices which are
+ capable of this feature without using the page cache.
+
+ If you do not use a block device that is capable of using this,
+ or if unsure, say N.
+
+config FS_XIP
+# execute in place
+ bool
+ depends on EXT2_FS_XIP
+ default y
+
config EXT3_FS
tristate "Ext3 journalling file system support"
help
@@ -97,6 +115,7 @@ config EXT3_FS_XATTR
config EXT3_FS_POSIX_ACL
bool "Ext3 POSIX Access Control Lists"
depends on EXT3_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -224,6 +243,7 @@ config REISERFS_FS_XATTR
config REISERFS_FS_POSIX_ACL
bool "ReiserFS POSIX Access Control Lists"
depends on REISERFS_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -257,6 +277,7 @@ config JFS_FS
config JFS_POSIX_ACL
bool "JFS POSIX Access Control Lists"
depends on JFS_FS
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -301,8 +322,7 @@ config FS_POSIX_ACL
# Never use this symbol for ifdefs.
#
bool
- depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFSD_V4
- default y
+ default n
source "fs/xfs/Kconfig"
@@ -339,6 +359,19 @@ config ROMFS_FS
If you don't know whether you need it, then you don't need it:
answer N.
+config INOTIFY
+ bool "Inotify file change notification support"
+ default y
+ ---help---
+ Say Y here to enable inotify support and the /dev/inotify character
+ device. Inotify is a file change notification system and a
+ replacement for dnotify. Inotify fixes numerous shortcomings in
+ dnotify and introduces several new features. It allows monitoring
+ of both files and directories via a single open fd. Multiple file
+ events are supported.
+
+ If unsure, say Y.
+
config QUOTA
bool "Quota support"
help
@@ -717,6 +750,12 @@ config PROC_KCORE
bool "/proc/kcore support" if !ARM
depends on PROC_FS && MMU
+config PROC_VMCORE
+ bool "/proc/vmcore support (EXPERIMENTAL)"
+ depends on PROC_FS && EMBEDDED && EXPERIMENTAL && CRASH_DUMP
+ help
+ Exports the dump image of crashed kernel in ELF format.
+
config SYSFS
bool "sysfs file system support" if EMBEDDED
default y
@@ -1013,26 +1052,18 @@ config JFFS2_FS_DEBUG
If reporting bugs, please try to have available a full dump of the
messages at debug level 1 while the misbehaviour was occurring.
-config JFFS2_FS_NAND
- bool "JFFS2 support for NAND flash"
+config JFFS2_FS_WRITEBUFFER
+ bool "JFFS2 write-buffering support"
depends on JFFS2_FS
- default n
+ default y
help
- This enables the support for NAND flash in JFFS2. NAND is a newer
- type of flash chip design than the traditional NOR flash, with
- higher density but a handful of characteristics which make it more
- interesting for the file system to use.
-
- Say 'N' unless you have NAND flash.
+ This enables the write-buffering support in JFFS2.
-config JFFS2_FS_NOR_ECC
- bool "JFFS2 support for ECC'd NOR flash (EXPERIMENTAL)"
- depends on JFFS2_FS && EXPERIMENTAL
- default n
- help
- This enables the experimental support for NOR flash with transparent
- ECC for JFFS2. This type of flash chip is not common, however it is
- available from ST Microelectronics.
+ This functionality is required to support JFFS2 on the following
+ types of flash devices:
+ - NAND flash
+ - NOR flash with transparent ECC
+ - DataFlash
config JFFS2_COMPRESSION_OPTIONS
bool "Advanced compression options for JFFS2"
@@ -1413,6 +1444,9 @@ config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL
select NFSD_TCP
+ select CRYPTO_MD5
+ select CRYPTO
+ select FS_POSIX_ACL
help
If you would like to include the NFSv4 server as well as the NFSv2
and NFSv3 servers, say Y here. This feature is experimental, and
diff --git a/fs/Makefile b/fs/Makefile
index fc92e59e9faf..cf95eb894fd5 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -10,7 +10,9 @@ obj-y := open.o read_write.o file_table.o buffer.o bio.o super.o \
ioctl.o readdir.o select.o fifo.o locks.o dcache.o inode.o \
attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
seq_file.o xattr.o libfs.o fs-writeback.o mpage.o direct-io.o \
+ ioprio.o
+obj-$(CONFIG_INOTIFY) += inotify.o
obj-$(CONFIG_EPOLL) += eventpoll.o
obj-$(CONFIG_COMPAT) += compat.o
diff --git a/fs/afs/kafsasyncd.c b/fs/afs/kafsasyncd.c
index 6fc88ae8ad94..7ac07d0d47b9 100644
--- a/fs/afs/kafsasyncd.c
+++ b/fs/afs/kafsasyncd.c
@@ -116,7 +116,7 @@ static int kafsasyncd(void *arg)
remove_wait_queue(&kafsasyncd_sleepq, &myself);
set_current_state(TASK_RUNNING);
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
/* discard pending signals */
afs_discard_my_signals();
diff --git a/fs/afs/kafstimod.c b/fs/afs/kafstimod.c
index 86e710dd057e..65bc05ab8182 100644
--- a/fs/afs/kafstimod.c
+++ b/fs/afs/kafstimod.c
@@ -91,7 +91,7 @@ static int kafstimod(void *arg)
complete_and_exit(&kafstimod_dead, 0);
}
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
/* discard pending signals */
afs_discard_my_signals();
diff --git a/fs/aio.c b/fs/aio.c
index 7afa222f6802..06d7d4390fe7 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -58,6 +58,7 @@ static DEFINE_SPINLOCK(fput_lock);
static LIST_HEAD(fput_head);
static void aio_kick_handler(void *);
+static void aio_queue_work(struct kioctx *);
/* aio_setup
* Creates the slab caches used by the aio routines, panic on
@@ -747,6 +748,14 @@ out:
* has already been kicked */
if (kiocbIsKicked(iocb)) {
__queue_kicked_iocb(iocb);
+
+ /*
+ * __queue_kicked_iocb will always return 1 here, because
+ * iocb->ki_run_list is empty at this point so it should
+ * be safe to unconditionally queue the context into the
+ * work queue.
+ */
+ aio_queue_work(ctx);
}
}
return ret;
diff --git a/fs/attr.c b/fs/attr.c
index c3c76fe78346..b1796fb9e524 100644
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -10,7 +10,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/smp_lock.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/fcntl.h>
#include <linux/quotaops.h>
#include <linux/security.h>
@@ -107,31 +107,8 @@ int inode_setattr(struct inode * inode, struct iattr * attr)
out:
return error;
}
-
EXPORT_SYMBOL(inode_setattr);
-int setattr_mask(unsigned int ia_valid)
-{
- unsigned long dn_mask = 0;
-
- if (ia_valid & ATTR_UID)
- dn_mask |= DN_ATTRIB;
- if (ia_valid & ATTR_GID)
- dn_mask |= DN_ATTRIB;
- if (ia_valid & ATTR_SIZE)
- dn_mask |= DN_MODIFY;
- /* both times implies a utime(s) call */
- if ((ia_valid & (ATTR_ATIME|ATTR_MTIME)) == (ATTR_ATIME|ATTR_MTIME))
- dn_mask |= DN_ATTRIB;
- else if (ia_valid & ATTR_ATIME)
- dn_mask |= DN_ACCESS;
- else if (ia_valid & ATTR_MTIME)
- dn_mask |= DN_MODIFY;
- if (ia_valid & ATTR_MODE)
- dn_mask |= DN_ATTRIB;
- return dn_mask;
-}
-
int notify_change(struct dentry * dentry, struct iattr * attr)
{
struct inode *inode = dentry->d_inode;
@@ -197,11 +174,9 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
if (ia_valid & ATTR_SIZE)
up_write(&dentry->d_inode->i_alloc_sem);
- if (!error) {
- unsigned long dn_mask = setattr_mask(ia_valid);
- if (dn_mask)
- dnotify_parent(dentry, dn_mask);
- }
+ if (!error)
+ fsnotify_change(dentry, ia_valid);
+
return error;
}
diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c
index fa2348dcd671..3df86285a1c7 100644
--- a/fs/autofs4/waitq.c
+++ b/fs/autofs4/waitq.c
@@ -231,8 +231,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
int type = (notify == NFY_MOUNT ?
autofs_ptype_missing : autofs_ptype_expire_multi);
- DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
- (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify));
+ DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
+ (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
/* autofs4_notify_daemon() may block */
autofs4_notify_daemon(sbi, wq, type);
diff --git a/fs/bio.c b/fs/bio.c
index 3a1472acc361..ca8f7a850fe3 100644
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -52,7 +52,7 @@ struct biovec_slab {
*/
#define BV(x) { .nr_vecs = x, .name = "biovec-"__stringify(x) }
-static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] = {
+static struct biovec_slab bvec_slabs[BIOVEC_NR_POOLS] __read_mostly = {
BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES),
};
#undef BV
diff --git a/fs/buffer.c b/fs/buffer.c
index 13e5938a64f6..6a25d7df89b1 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -278,7 +278,7 @@ EXPORT_SYMBOL(thaw_bdev);
*/
static void do_sync(unsigned long wait)
{
- wakeup_bdflush(0);
+ wakeup_pdflush(0);
sync_inodes(0); /* All mappings, inodes and their blockdevs */
DQUOT_SYNC(NULL);
sync_supers(); /* Write the superblocks */
@@ -497,7 +497,7 @@ static void free_more_memory(void)
struct zone **zones;
pg_data_t *pgdat;
- wakeup_bdflush(1024);
+ wakeup_pdflush(1024);
yield();
for_each_pgdat(pgdat) {
@@ -513,8 +513,8 @@ static void free_more_memory(void)
*/
static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
{
- static DEFINE_SPINLOCK(page_uptodate_lock);
unsigned long flags;
+ struct buffer_head *first;
struct buffer_head *tmp;
struct page *page;
int page_uptodate = 1;
@@ -536,7 +536,9 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
* two buffer heads end IO at almost the same time and both
* decide that the page is now completely done.
*/
- spin_lock_irqsave(&page_uptodate_lock, flags);
+ first = page_buffers(page);
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
clear_buffer_async_read(bh);
unlock_buffer(bh);
tmp = bh;
@@ -549,7 +551,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
}
tmp = tmp->b_this_page;
} while (tmp != bh);
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
/*
* If none of the buffers had errors and they are all
@@ -561,7 +564,8 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)
return;
still_busy:
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
return;
}
@@ -572,8 +576,8 @@ still_busy:
void end_buffer_async_write(struct buffer_head *bh, int uptodate)
{
char b[BDEVNAME_SIZE];
- static DEFINE_SPINLOCK(page_uptodate_lock);
unsigned long flags;
+ struct buffer_head *first;
struct buffer_head *tmp;
struct page *page;
@@ -594,7 +598,10 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
SetPageError(page);
}
- spin_lock_irqsave(&page_uptodate_lock, flags);
+ first = page_buffers(page);
+ local_irq_save(flags);
+ bit_spin_lock(BH_Uptodate_Lock, &first->b_state);
+
clear_buffer_async_write(bh);
unlock_buffer(bh);
tmp = bh->b_this_page;
@@ -605,12 +612,14 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)
}
tmp = tmp->b_this_page;
}
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
end_page_writeback(page);
return;
still_busy:
- spin_unlock_irqrestore(&page_uptodate_lock, flags);
+ bit_spin_unlock(BH_Uptodate_Lock, &first->b_state);
+ local_irq_restore(flags);
return;
}
diff --git a/fs/char_dev.c b/fs/char_dev.c
index e82aac9cc2f5..3b1b1eefdbb0 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -150,7 +150,7 @@ __unregister_chrdev_region(unsigned major, unsigned baseminor, int minorct)
struct char_device_struct *cd = NULL, **cp;
int i = major_to_index(major);
- up(&chrdevs_lock);
+ down(&chrdevs_lock);
for (cp = &chrdevs[i]; *cp; cp = &(*cp)->next)
if ((*cp)->major == major &&
(*cp)->baseminor == baseminor &&
@@ -277,8 +277,9 @@ static struct kobject *cdev_get(struct cdev *p)
void cdev_put(struct cdev *p)
{
if (p) {
+ struct module *owner = p->owner;
kobject_put(&p->kobj);
- module_put(p->owner);
+ module_put(owner);
}
}
diff --git a/fs/compat.c b/fs/compat.c
index 728cd8365384..6b06b6bae35e 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -37,7 +37,7 @@
#include <linux/ctype.h>
#include <linux/module.h>
#include <linux/dirent.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/highuid.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -1307,9 +1307,13 @@ static ssize_t compat_do_readv_writev(int type, struct file *file,
out:
if (iov != iovstack)
kfree(iov);
- if ((ret + (type == READ)) > 0)
- dnotify_parent(file->f_dentry,
- (type == READ) ? DN_ACCESS : DN_MODIFY);
+ if ((ret + (type == READ)) > 0) {
+ struct dentry *dentry = file->f_dentry;
+ if (type == READ)
+ fsnotify_access(dentry);
+ else
+ fsnotify_modify(dentry);
+ }
return ret;
}
diff --git a/fs/dcookies.c b/fs/dcookies.c
index 581aac959cd3..02aa0ddc582a 100644
--- a/fs/dcookies.c
+++ b/fs/dcookies.c
@@ -94,12 +94,10 @@ static struct dcookie_struct * alloc_dcookie(struct dentry * dentry,
if (!dcs)
return NULL;
- atomic_inc(&dentry->d_count);
- atomic_inc(&vfsmnt->mnt_count);
dentry->d_cookie = dcs;
- dcs->dentry = dentry;
- dcs->vfsmnt = vfsmnt;
+ dcs->dentry = dget(dentry);
+ dcs->vfsmnt = mntget(vfsmnt);
hash_dcookie(dcs);
return dcs;
diff --git a/fs/direct-io.c b/fs/direct-io.c
index 1d55e7e67342..0d06097bc995 100644
--- a/fs/direct-io.c
+++ b/fs/direct-io.c
@@ -215,7 +215,7 @@ static struct page *dio_get_page(struct dio *dio)
static void dio_complete(struct dio *dio, loff_t offset, ssize_t bytes)
{
if (dio->end_io && dio->result)
- dio->end_io(dio->inode, offset, bytes, dio->map_bh.b_private);
+ dio->end_io(dio->iocb, offset, bytes, dio->map_bh.b_private);
if (dio->lock_type == DIO_LOCKING)
up_read(&dio->inode->i_alloc_sem);
}
diff --git a/fs/dquot.c b/fs/dquot.c
index 37212b039a4a..b9732335bcdc 100644
--- a/fs/dquot.c
+++ b/fs/dquot.c
@@ -409,13 +409,10 @@ out_dqlock:
* for this sb+type at all. */
static void invalidate_dquots(struct super_block *sb, int type)
{
- struct dquot *dquot;
- struct list_head *head;
+ struct dquot *dquot, *tmp;
spin_lock(&dq_list_lock);
- for (head = inuse_list.next; head != &inuse_list;) {
- dquot = list_entry(head, struct dquot, dq_inuse);
- head = head->next;
+ list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) {
if (dquot->dq_sb != sb)
continue;
if (dquot->dq_type != type)
diff --git a/fs/exec.c b/fs/exec.c
index 48871917d363..222ab1c572d8 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -642,6 +642,18 @@ static inline int de_thread(struct task_struct *tsk)
count = 2;
if (thread_group_leader(current))
count = 1;
+ else {
+ /*
+ * The SIGALRM timer survives the exec, but needs to point
+ * at us as the new group leader now. We have a race with
+ * a timer firing now getting the old leader, so we need to
+ * synchronize with any firing (by calling del_timer_sync)
+ * before we can safely let the old group leader die.
+ */
+ sig->real_timer.data = (unsigned long)current;
+ if (del_timer_sync(&sig->real_timer))
+ add_timer(&sig->real_timer);
+ }
while (atomic_read(&sig->count) > count) {
sig->group_exit_task = current;
sig->notify_count = count;
diff --git a/fs/ext2/Makefile b/fs/ext2/Makefile
index ee240a14e70f..c5d02da73bc3 100644
--- a/fs/ext2/Makefile
+++ b/fs/ext2/Makefile
@@ -10,3 +10,4 @@ ext2-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
ext2-$(CONFIG_EXT2_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
ext2-$(CONFIG_EXT2_FS_POSIX_ACL) += acl.o
ext2-$(CONFIG_EXT2_FS_SECURITY) += xattr_security.o
+ext2-$(CONFIG_EXT2_FS_XIP) += xip.o
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index 8f0fd726c3f1..e977f8566d14 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -2,6 +2,15 @@
#include <linux/ext2_fs.h>
/*
+ * ext2 mount options
+ */
+struct ext2_mount_options {
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+};
+
+/*
* second extended file system inode data in memory
*/
struct ext2_inode_info {
@@ -147,9 +156,11 @@ extern struct file_operations ext2_dir_operations;
/* file.c */
extern struct inode_operations ext2_file_inode_operations;
extern struct file_operations ext2_file_operations;
+extern struct file_operations ext2_xip_file_operations;
/* inode.c */
extern struct address_space_operations ext2_aops;
+extern struct address_space_operations ext2_aops_xip;
extern struct address_space_operations ext2_nobh_aops;
/* namei.c */
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index f5e86141ec54..a484412fc782 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -55,6 +55,20 @@ struct file_operations ext2_file_operations = {
.sendfile = generic_file_sendfile,
};
+#ifdef CONFIG_EXT2_FS_XIP
+struct file_operations ext2_xip_file_operations = {
+ .llseek = generic_file_llseek,
+ .read = xip_file_read,
+ .write = xip_file_write,
+ .ioctl = ext2_ioctl,
+ .mmap = xip_file_mmap,
+ .open = generic_file_open,
+ .release = ext2_release_file,
+ .fsync = ext2_sync_file,
+ .sendfile = xip_file_sendfile,
+};
+#endif
+
struct inode_operations ext2_file_inode_operations = {
.truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c
index a50d9db4b6e4..53dceb0c6593 100644
--- a/fs/ext2/inode.c
+++ b/fs/ext2/inode.c
@@ -33,6 +33,7 @@
#include <linux/mpage.h>
#include "ext2.h"
#include "acl.h"
+#include "xip.h"
MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
@@ -594,6 +595,16 @@ out:
if (err)
goto cleanup;
+ if (ext2_use_xip(inode->i_sb)) {
+ /*
+ * we need to clear the block
+ */
+ err = ext2_clear_xip_target (inode,
+ le32_to_cpu(chain[depth-1].key));
+ if (err)
+ goto cleanup;
+ }
+
if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)
goto changed;
@@ -691,6 +702,11 @@ struct address_space_operations ext2_aops = {
.writepages = ext2_writepages,
};
+struct address_space_operations ext2_aops_xip = {
+ .bmap = ext2_bmap,
+ .get_xip_page = ext2_get_xip_page,
+};
+
struct address_space_operations ext2_nobh_aops = {
.readpage = ext2_readpage,
.readpages = ext2_readpages,
@@ -910,7 +926,9 @@ void ext2_truncate (struct inode * inode)
iblock = (inode->i_size + blocksize-1)
>> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
- if (test_opt(inode->i_sb, NOBH))
+ if (mapping_is_xip(inode->i_mapping))
+ xip_truncate_page(inode->i_mapping, inode->i_size);
+ else if (test_opt(inode->i_sb, NOBH))
nobh_truncate_page(inode->i_mapping, inode->i_size);
else
block_truncate_page(inode->i_mapping,
@@ -1110,11 +1128,16 @@ void ext2_read_inode (struct inode * inode)
if (S_ISREG(inode->i_mode)) {
inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- if (test_opt(inode->i_sb, NOBH))
+ if (ext2_use_xip(inode->i_sb)) {
+ inode->i_mapping->a_ops = &ext2_aops_xip;
+ inode->i_fop = &ext2_xip_file_operations;
+ } else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
- else
+ inode->i_fop = &ext2_file_operations;
+ } else {
inode->i_mapping->a_ops = &ext2_aops;
+ inode->i_fop = &ext2_file_operations;
+ }
} else if (S_ISDIR(inode->i_mode)) {
inode->i_op = &ext2_dir_inode_operations;
inode->i_fop = &ext2_dir_operations;
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index 3176b3d3ffa8..c5513953c825 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -34,6 +34,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
+#include "xip.h"
/*
* Couple of helper functions - make the code slightly cleaner.
@@ -127,11 +128,16 @@ static int ext2_create (struct inode * dir, struct dentry * dentry, int mode, st
int err = PTR_ERR(inode);
if (!IS_ERR(inode)) {
inode->i_op = &ext2_file_inode_operations;
- inode->i_fop = &ext2_file_operations;
- if (test_opt(inode->i_sb, NOBH))
+ if (ext2_use_xip(inode->i_sb)) {
+ inode->i_mapping->a_ops = &ext2_aops_xip;
+ inode->i_fop = &ext2_xip_file_operations;
+ } else if (test_opt(inode->i_sb, NOBH)) {
inode->i_mapping->a_ops = &ext2_nobh_aops;
- else
+ inode->i_fop = &ext2_file_operations;
+ } else {
inode->i_mapping->a_ops = &ext2_aops;
+ inode->i_fop = &ext2_file_operations;
+ }
mark_inode_dirty(inode);
err = ext2_add_nondir(dentry, inode);
}
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 661c3d98d946..dcfe331dc4c4 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -31,6 +31,7 @@
#include "ext2.h"
#include "xattr.h"
#include "acl.h"
+#include "xip.h"
static void ext2_sync_super(struct super_block *sb,
struct ext2_super_block *es);
@@ -257,7 +258,7 @@ enum {
Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
Opt_nouid32, Opt_check, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh,
- Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
+ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip,
Opt_ignore, Opt_err,
};
@@ -286,6 +287,7 @@ static match_table_t tokens = {
{Opt_nouser_xattr, "nouser_xattr"},
{Opt_acl, "acl"},
{Opt_noacl, "noacl"},
+ {Opt_xip, "xip"},
{Opt_ignore, "grpquota"},
{Opt_ignore, "noquota"},
{Opt_ignore, "quota"},
@@ -397,6 +399,13 @@ static int parse_options (char * options,
printk("EXT2 (no)acl options not supported\n");
break;
#endif
+ case Opt_xip:
+#ifdef CONFIG_EXT2_FS_XIP
+ set_opt (sbi->s_mount_opt, XIP);
+#else
+ printk("EXT2 xip option not supported\n");
+#endif
+ break;
case Opt_ignore:
break;
default:
@@ -640,6 +649,9 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ?
MS_POSIXACL : 0);
+ ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset
+ EXT2_MOUNT_XIP if not */
+
if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV &&
(EXT2_HAS_COMPAT_FEATURE(sb, ~0U) ||
EXT2_HAS_RO_COMPAT_FEATURE(sb, ~0U) ||
@@ -668,6 +680,13 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size);
+ if ((ext2_use_xip(sb)) && ((blocksize != PAGE_SIZE) ||
+ (sb->s_blocksize != blocksize))) {
+ if (!silent)
+ printk("XIP: Unsupported blocksize\n");
+ goto failed_mount;
+ }
+
/* If the blocksize doesn't match, re-read the thing.. */
if (sb->s_blocksize != blocksize) {
brelse(bh);
@@ -916,17 +935,34 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
{
struct ext2_sb_info * sbi = EXT2_SB(sb);
struct ext2_super_block * es;
+ unsigned long old_mount_opt = sbi->s_mount_opt;
+ struct ext2_mount_options old_opts;
+ unsigned long old_sb_flags;
+ int err;
+
+ /* Store the old options */
+ old_sb_flags = sb->s_flags;
+ old_opts.s_mount_opt = sbi->s_mount_opt;
+ old_opts.s_resuid = sbi->s_resuid;
+ old_opts.s_resgid = sbi->s_resgid;
/*
* Allow the "check" option to be passed as a remount option.
*/
- if (!parse_options (data, sbi))
- return -EINVAL;
+ if (!parse_options (data, sbi)) {
+ err = -EINVAL;
+ goto restore_opts;
+ }
sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
es = sbi->s_es;
+ if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) !=
+ (old_mount_opt & EXT2_MOUNT_XIP)) &&
+ invalidate_inodes(sb))
+ ext2_warning(sb, __FUNCTION__, "busy inodes while remounting "\
+ "xip remain in cache (no functional problem)");
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
return 0;
if (*flags & MS_RDONLY) {
@@ -946,7 +982,8 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
printk("EXT2-fs: %s: couldn't remount RDWR because of "
"unsupported optional features (%x).\n",
sb->s_id, le32_to_cpu(ret));
- return -EROFS;
+ err = -EROFS;
+ goto restore_opts;
}
/*
* Mounting a RDONLY partition read-write, so reread and
@@ -959,6 +996,12 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
}
ext2_sync_super(sb, es);
return 0;
+restore_opts:
+ sbi->s_mount_opt = old_opts.s_mount_opt;
+ sbi->s_resuid = old_opts.s_resuid;
+ sbi->s_resgid = old_opts.s_resgid;
+ sb->s_flags = old_sb_flags;
+ return err;
}
static int ext2_statfs (struct super_block * sb, struct kstatfs * buf)
diff --git a/fs/ext2/xip.c b/fs/ext2/xip.c
new file mode 100644
index 000000000000..d44431d1a338
--- /dev/null
+++ b/fs/ext2/xip.c
@@ -0,0 +1,80 @@
+/*
+ * linux/fs/ext2/xip.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte (cotte@de.ibm.com)
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/buffer_head.h>
+#include <linux/ext2_fs_sb.h>
+#include <linux/ext2_fs.h>
+#include "ext2.h"
+#include "xip.h"
+
+static inline int
+__inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) {
+ BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
+ return inode->i_sb->s_bdev->bd_disk->fops
+ ->direct_access(inode->i_sb->s_bdev,sector,data);
+}
+
+int
+ext2_clear_xip_target(struct inode *inode, int block) {
+ sector_t sector = block*(PAGE_SIZE/512);
+ unsigned long data;
+ int rc;
+
+ rc = __inode_direct_access(inode, sector, &data);
+ if (rc)
+ return rc;
+ clear_page((void*)data);
+ return 0;
+}
+
+void ext2_xip_verify_sb(struct super_block *sb)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(sb);
+
+ if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) {
+ if ((sb->s_bdev == NULL) ||
+ sb->s_bdev->bd_disk == NULL ||
+ sb->s_bdev->bd_disk->fops == NULL ||
+ sb->s_bdev->bd_disk->fops->direct_access == NULL) {
+ sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
+ ext2_warning(sb, __FUNCTION__,
+ "ignoring xip option - not supported by bdev");
+ }
+ }
+}
+
+struct page*
+ext2_get_xip_page(struct address_space *mapping, sector_t blockno,
+ int create)
+{
+ int rc;
+ unsigned long data;
+ struct buffer_head tmp;
+
+ tmp.b_state = 0;
+ tmp.b_blocknr = 0;
+ rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp,
+ create);
+ if (rc)
+ return ERR_PTR(rc);
+ if (tmp.b_blocknr == 0) {
+ /* SPARSE block */
+ BUG_ON(create);
+ return ERR_PTR(-ENODATA);
+ }
+
+ rc = __inode_direct_access
+ (mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data);
+ if (rc)
+ return ERR_PTR(rc);
+
+ SetPageUptodate(virt_to_page(data));
+ return virt_to_page(data);
+}
diff --git a/fs/ext2/xip.h b/fs/ext2/xip.h
new file mode 100644
index 000000000000..aa85331d6c56
--- /dev/null
+++ b/fs/ext2/xip.h
@@ -0,0 +1,25 @@
+/*
+ * linux/fs/ext2/xip.h
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte (cotte@de.ibm.com)
+ */
+
+#ifdef CONFIG_EXT2_FS_XIP
+extern void ext2_xip_verify_sb (struct super_block *);
+extern int ext2_clear_xip_target (struct inode *, int);
+
+static inline int ext2_use_xip (struct super_block *sb)
+{
+ struct ext2_sb_info *sbi = EXT2_SB(sb);
+ return (sbi->s_mount_opt & EXT2_MOUNT_XIP);
+}
+struct page* ext2_get_xip_page (struct address_space *, sector_t, int);
+#define mapping_is_xip(map) unlikely(map->a_ops->get_xip_page)
+#else
+#define mapping_is_xip(map) 0
+#define ext2_xip_verify_sb(sb) do { } while (0)
+#define ext2_use_xip(sb) 0
+#define ext2_clear_xip_target(inode, chain) 0
+#define ext2_get_xip_page NULL
+#endif
diff --git a/fs/ext3/acl.c b/fs/ext3/acl.c
index 133f5aa581bb..3ac38266fc9e 100644
--- a/fs/ext3/acl.c
+++ b/fs/ext3/acl.c
@@ -393,7 +393,8 @@ ext3_acl_chmod(struct inode *inode)
int retries = 0;
retry:
- handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode,
+ EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
ext3_std_error(inode->i_sb, error);
@@ -503,7 +504,7 @@ ext3_xattr_set_acl(struct inode *inode, int type, const void *value,
acl = NULL;
retry:
- handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
error = ext3_set_acl(handle, inode, type, acl);
diff --git a/fs/ext3/balloc.c b/fs/ext3/balloc.c
index ccd632fcc6d8..e463dca008e4 100644
--- a/fs/ext3/balloc.c
+++ b/fs/ext3/balloc.c
@@ -749,24 +749,24 @@ fail_access:
* to find a free region that is of my size and has not
* been reserved.
*
- * on succeed, it returns the reservation window to be appended to.
- * failed, return NULL.
*/
-static struct ext3_reserve_window_node *find_next_reservable_window(
+static int find_next_reservable_window(
struct ext3_reserve_window_node *search_head,
- unsigned long size, int *start_block,
+ struct ext3_reserve_window_node *my_rsv,
+ struct super_block * sb, int start_block,
int last_block)
{
struct rb_node *next;
struct ext3_reserve_window_node *rsv, *prev;
int cur;
+ int size = my_rsv->rsv_goal_size;
/* TODO: make the start of the reservation window byte-aligned */
/* cur = *start_block & ~7;*/
- cur = *start_block;
+ cur = start_block;
rsv = search_head;
if (!rsv)
- return NULL;
+ return -1;
while (1) {
if (cur <= rsv->rsv_end)
@@ -782,11 +782,11 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
* space with expected-size (or more)...
*/
if (cur > last_block)
- return NULL; /* fail */
+ return -1; /* fail */
prev = rsv;
next = rb_next(&rsv->rsv_node);
- rsv = list_entry(next, struct ext3_reserve_window_node, rsv_node);
+ rsv = list_entry(next,struct ext3_reserve_window_node,rsv_node);
/*
* Reached the last reservation, we can just append to the
@@ -813,8 +813,25 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
* return the reservation window that we could append to.
* succeed.
*/
- *start_block = cur;
- return prev;
+
+ if ((prev != my_rsv) && (!rsv_is_empty(&my_rsv->rsv_window)))
+ rsv_window_remove(sb, my_rsv);
+
+ /*
+ * Let's book the whole avaliable window for now. We will check the
+ * disk bitmap later and then, if there are free blocks then we adjust
+ * the window size if it's larger than requested.
+ * Otherwise, we will remove this node from the tree next time
+ * call find_next_reservable_window.
+ */
+ my_rsv->rsv_start = cur;
+ my_rsv->rsv_end = cur + size - 1;
+ my_rsv->rsv_alloc_hit = 0;
+
+ if (prev != my_rsv)
+ ext3_rsv_window_add(sb, my_rsv);
+
+ return 0;
}
/**
@@ -852,6 +869,7 @@ static struct ext3_reserve_window_node *find_next_reservable_window(
* @sb: the super block
* @group: the group we are trying to allocate in
* @bitmap_bh: the block group block bitmap
+ *
*/
static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
int goal, struct super_block *sb,
@@ -860,10 +878,10 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
struct ext3_reserve_window_node *search_head;
int group_first_block, group_end_block, start_block;
int first_free_block;
- int reservable_space_start;
- struct ext3_reserve_window_node *prev_rsv;
struct rb_root *fs_rsv_root = &EXT3_SB(sb)->s_rsv_window_root;
unsigned long size;
+ int ret;
+ spinlock_t *rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
group_first_block = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) +
group * EXT3_BLOCKS_PER_GROUP(sb);
@@ -875,6 +893,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
start_block = goal + group_first_block;
size = my_rsv->rsv_goal_size;
+
if (!rsv_is_empty(&my_rsv->rsv_window)) {
/*
* if the old reservation is cross group boundary
@@ -908,6 +927,8 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
my_rsv->rsv_goal_size= size;
}
}
+
+ spin_lock(rsv_lock);
/*
* shift the search start to the window near the goal block
*/
@@ -921,11 +942,16 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
* need to check the bitmap after we found a reservable window.
*/
retry:
- prev_rsv = find_next_reservable_window(search_head, size,
- &start_block, group_end_block);
- if (prev_rsv == NULL)
- goto failed;
- reservable_space_start = start_block;
+ ret = find_next_reservable_window(search_head, my_rsv, sb,
+ start_block, group_end_block);
+
+ if (ret == -1) {
+ if (!rsv_is_empty(&my_rsv->rsv_window))
+ rsv_window_remove(sb, my_rsv);
+ spin_unlock(rsv_lock);
+ return -1;
+ }
+
/*
* On success, find_next_reservable_window() returns the
* reservation window where there is a reservable space after it.
@@ -937,8 +963,9 @@ retry:
* block. Search start from the start block of the reservable space
* we just found.
*/
+ spin_unlock(rsv_lock);
first_free_block = bitmap_search_next_usable_block(
- reservable_space_start - group_first_block,
+ my_rsv->rsv_start - group_first_block,
bitmap_bh, group_end_block - group_first_block + 1);
if (first_free_block < 0) {
@@ -946,54 +973,29 @@ retry:
* no free block left on the bitmap, no point
* to reserve the space. return failed.
*/
- goto failed;
+ spin_lock(rsv_lock);
+ if (!rsv_is_empty(&my_rsv->rsv_window))
+ rsv_window_remove(sb, my_rsv);
+ spin_unlock(rsv_lock);
+ return -1; /* failed */
}
+
start_block = first_free_block + group_first_block;
/*
* check if the first free block is within the
- * free space we just found
+ * free space we just reserved
*/
- if ((start_block >= reservable_space_start) &&
- (start_block < reservable_space_start + size))
- goto found_rsv_window;
+ if (start_block >= my_rsv->rsv_start && start_block < my_rsv->rsv_end)
+ return 0; /* success */
/*
* if the first free bit we found is out of the reservable space
- * this means there is no free block on the reservable space
- * we should continue search for next reservable space,
+ * continue search for next reservable space,
* start from where the free block is,
* we also shift the list head to where we stopped last time
*/
- search_head = prev_rsv;
+ search_head = my_rsv;
+ spin_lock(rsv_lock);
goto retry;
-
-found_rsv_window:
- /*
- * great! the reservable space contains some free blocks.
- * if the search returns that we should add the new
- * window just next to where the old window, we don't
- * need to remove the old window first then add it to the
- * same place, just update the new start and new end.
- */
- if (my_rsv != prev_rsv) {
- if (!rsv_is_empty(&my_rsv->rsv_window))
- rsv_window_remove(sb, my_rsv);
- }
- my_rsv->rsv_start = reservable_space_start;
- my_rsv->rsv_end = my_rsv->rsv_start + size - 1;
- my_rsv->rsv_alloc_hit = 0;
- if (my_rsv != prev_rsv) {
- ext3_rsv_window_add(sb, my_rsv);
- }
- return 0; /* succeed */
-failed:
- /*
- * failed to find a new reservation window in the current
- * group, remove the current(stale) reservation window
- * if there is any
- */
- if (!rsv_is_empty(&my_rsv->rsv_window))
- rsv_window_remove(sb, my_rsv);
- return -1; /* failed */
}
/*
@@ -1023,7 +1025,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
int goal, struct ext3_reserve_window_node * my_rsv,
int *errp)
{
- spinlock_t *rsv_lock;
unsigned long group_first_block;
int ret = 0;
int fatal;
@@ -1052,7 +1053,6 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal, NULL);
goto out;
}
- rsv_lock = &EXT3_SB(sb)->s_rsv_window_lock;
/*
* goal is a group relative block number (if there is a goal)
* 0 < goal < EXT3_BLOCKS_PER_GROUP(sb)
@@ -1078,30 +1078,21 @@ ext3_try_to_allocate_with_rsv(struct super_block *sb, handle_t *handle,
* then we could go to allocate from the reservation window directly.
*/
while (1) {
- struct ext3_reserve_window rsv_copy;
-
- rsv_copy._rsv_start = my_rsv->rsv_start;
- rsv_copy._rsv_end = my_rsv->rsv_end;
-
- if (rsv_is_empty(&rsv_copy) || (ret < 0) ||
- !goal_in_my_reservation(&rsv_copy, goal, group, sb)) {
- spin_lock(rsv_lock);
+ if (rsv_is_empty(&my_rsv->rsv_window) || (ret < 0) ||
+ !goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb)) {
ret = alloc_new_reservation(my_rsv, goal, sb,
group, bitmap_bh);
- rsv_copy._rsv_start = my_rsv->rsv_start;
- rsv_copy._rsv_end = my_rsv->rsv_end;
- spin_unlock(rsv_lock);
if (ret < 0)
break; /* failed */
- if (!goal_in_my_reservation(&rsv_copy, goal, group, sb))
+ if (!goal_in_my_reservation(&my_rsv->rsv_window, goal, group, sb))
goal = -1;
}
- if ((rsv_copy._rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
- || (rsv_copy._rsv_end < group_first_block))
+ if ((my_rsv->rsv_start >= group_first_block + EXT3_BLOCKS_PER_GROUP(sb))
+ || (my_rsv->rsv_end < group_first_block))
BUG();
ret = ext3_try_to_allocate(sb, handle, group, bitmap_bh, goal,
- &rsv_copy);
+ &my_rsv->rsv_window);
if (ret >= 0) {
my_rsv->rsv_alloc_hit++;
break; /* succeed */
diff --git a/fs/ext3/file.c b/fs/ext3/file.c
index 5ad8cf0292df..98e78345ead9 100644
--- a/fs/ext3/file.c
+++ b/fs/ext3/file.c
@@ -36,7 +36,11 @@ static int ext3_release_file (struct inode * inode, struct file * filp)
/* if we are the last writer on the inode, drop the block reservation */
if ((filp->f_mode & FMODE_WRITE) &&
(atomic_read(&inode->i_writecount) == 1))
+ {
+ down(&EXT3_I(inode)->truncate_sem);
ext3_discard_reservation(inode);
+ up(&EXT3_I(inode)->truncate_sem);
+ }
if (is_dx(inode) && filp->private_data)
ext3_htree_free_dir_info(filp->private_data);
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c
index 0d5fa73b18dc..9989fdcf4d5a 100644
--- a/fs/ext3/inode.c
+++ b/fs/ext3/inode.c
@@ -128,7 +128,7 @@ static unsigned long blocks_for_truncate(struct inode *inode)
if (needed > EXT3_MAX_TRANS_DATA)
needed = EXT3_MAX_TRANS_DATA;
- return EXT3_DATA_TRANS_BLOCKS + needed;
+ return EXT3_DATA_TRANS_BLOCKS(inode->i_sb) + needed;
}
/*
@@ -2663,7 +2663,7 @@ static int ext3_do_update_inode(handle_t *handle,
} else for (block = 0; block < EXT3_N_BLOCKS; block++)
raw_inode->i_block[block] = ei->i_data[block];
- if (EXT3_INODE_SIZE(inode->i_sb) > EXT3_GOOD_OLD_INODE_SIZE)
+ if (ei->i_extra_isize)
raw_inode->i_extra_isize = cpu_to_le16(ei->i_extra_isize);
BUFFER_TRACE(bh, "call ext3_journal_dirty_metadata");
@@ -2763,7 +2763,8 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
/* (user+group)*(old+new) structure, inode write (sb,
* inode block, ? - but truncate inode update has it) */
- handle = ext3_journal_start(inode, 4*EXT3_QUOTA_INIT_BLOCKS+3);
+ handle = ext3_journal_start(inode, 2*(EXT3_QUOTA_INIT_BLOCKS(inode->i_sb)+
+ EXT3_QUOTA_DEL_BLOCKS(inode->i_sb))+3);
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
goto err_out;
@@ -2861,7 +2862,7 @@ static int ext3_writepage_trans_blocks(struct inode *inode)
#ifdef CONFIG_QUOTA
/* We know that structure was already allocated during DQUOT_INIT so
* we will be updating only the data blocks + inodes */
- ret += 2*EXT3_QUOTA_TRANS_BLOCKS;
+ ret += 2*EXT3_QUOTA_TRANS_BLOCKS(inode->i_sb);
#endif
return ret;
diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 60e44e6dd7a6..50378d8ff84b 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -1645,9 +1645,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode,
int err, retries = 0;
retry:
- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- 2*EXT3_QUOTA_INIT_BLOCKS);
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -1679,9 +1679,9 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry,
return -EINVAL;
retry:
- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- 2*EXT3_QUOTA_INIT_BLOCKS);
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -1715,9 +1715,9 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
return -EMLINK;
retry:
- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
- 2*EXT3_QUOTA_INIT_BLOCKS);
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2006,7 +2006,7 @@ static int ext3_rmdir (struct inode * dir, struct dentry *dentry)
/* Initialize quotas before so that eventual writes go in
* separate transaction */
DQUOT_INIT(dentry->d_inode);
- handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+ handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2065,7 +2065,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
/* Initialize quotas before so that eventual writes go
* in separate transaction */
DQUOT_INIT(dentry->d_inode);
- handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS);
+ handle = ext3_journal_start(dir, EXT3_DELETE_TRANS_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2120,9 +2120,9 @@ static int ext3_symlink (struct inode * dir,
return -ENAMETOOLONG;
retry:
- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
- 2*EXT3_QUOTA_INIT_BLOCKS);
+ 2*EXT3_QUOTA_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2174,7 +2174,7 @@ static int ext3_link (struct dentry * old_dentry,
return -EMLINK;
retry:
- handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS);
if (IS_ERR(handle))
return PTR_ERR(handle);
@@ -2216,7 +2216,8 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
* in separate transaction */
if (new_dentry->d_inode)
DQUOT_INIT(new_dentry->d_inode);
- handle = ext3_journal_start(old_dir, 2 * EXT3_DATA_TRANS_BLOCKS +
+ handle = ext3_journal_start(old_dir, 2 *
+ EXT3_DATA_TRANS_BLOCKS(old_dir->i_sb) +
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 2);
if (IS_ERR(handle))
return PTR_ERR(handle);
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index 9630fbfdc24a..3c3c6e399fb3 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -589,7 +589,7 @@ enum {
Opt_commit, Opt_journal_update, Opt_journal_inum,
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
- Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0,
+ Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
Opt_ignore, Opt_barrier, Opt_err, Opt_resize,
};
@@ -634,10 +634,10 @@ static match_table_t tokens = {
{Opt_grpjquota, "grpjquota=%s"},
{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
- {Opt_ignore, "grpquota"},
- {Opt_ignore, "noquota"},
- {Opt_ignore, "quota"},
- {Opt_ignore, "usrquota"},
+ {Opt_quota, "grpquota"},
+ {Opt_noquota, "noquota"},
+ {Opt_quota, "quota"},
+ {Opt_quota, "usrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_err, NULL},
{Opt_resize, "resize"},
@@ -876,6 +876,7 @@ set_qf_name:
sbi->s_qf_names[qtype] = NULL;
return 0;
}
+ set_opt(sbi->s_mount_opt, QUOTA);
break;
case Opt_offusrjquota:
qtype = USRQUOTA;
@@ -889,7 +890,10 @@ clear_qf_name:
"quota turned on.\n");
return 0;
}
- kfree(sbi->s_qf_names[qtype]);
+ /*
+ * The space will be released later when all options
+ * are confirmed to be correct
+ */
sbi->s_qf_names[qtype] = NULL;
break;
case Opt_jqfmt_vfsold:
@@ -898,6 +902,17 @@ clear_qf_name:
case Opt_jqfmt_vfsv0:
sbi->s_jquota_fmt = QFMT_VFS_V0;
break;
+ case Opt_quota:
+ set_opt(sbi->s_mount_opt, QUOTA);
+ break;
+ case Opt_noquota:
+ if (sb_any_quota_enabled(sb)) {
+ printk(KERN_ERR "EXT3-fs: Cannot change quota "
+ "options when quota turned on.\n");
+ return 0;
+ }
+ clear_opt(sbi->s_mount_opt, QUOTA);
+ break;
#else
case Opt_usrjquota:
case Opt_grpjquota:
@@ -909,6 +924,9 @@ clear_qf_name:
"EXT3-fs: journalled quota options not "
"supported.\n");
break;
+ case Opt_quota:
+ case Opt_noquota:
+ break;
#endif
case Opt_abort:
set_opt(sbi->s_mount_opt, ABORT);
@@ -924,12 +942,13 @@ clear_qf_name:
case Opt_ignore:
break;
case Opt_resize:
- if (!n_blocks_count) {
+ if (!is_remount) {
printk("EXT3-fs: resize option only available "
"for remount\n");
return 0;
}
- match_int(&args[0], &option);
+ if (match_int(&args[0], &option) != 0)
+ return 0;
*n_blocks_count = option;
break;
case Opt_nobh:
@@ -2093,14 +2112,33 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
{
struct ext3_super_block * es;
struct ext3_sb_info *sbi = EXT3_SB(sb);
- unsigned long tmp;
unsigned long n_blocks_count = 0;
+ unsigned long old_sb_flags;
+ struct ext3_mount_options old_opts;
+ int err;
+#ifdef CONFIG_QUOTA
+ int i;
+#endif
+
+ /* Store the original options */
+ old_sb_flags = sb->s_flags;
+ old_opts.s_mount_opt = sbi->s_mount_opt;
+ old_opts.s_resuid = sbi->s_resuid;
+ old_opts.s_resgid = sbi->s_resgid;
+ old_opts.s_commit_interval = sbi->s_commit_interval;
+#ifdef CONFIG_QUOTA
+ old_opts.s_jquota_fmt = sbi->s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++)
+ old_opts.s_qf_names[i] = sbi->s_qf_names[i];
+#endif
/*
* Allow the "check" option to be passed as a remount option.
*/
- if (!parse_options(data, sb, &tmp, &n_blocks_count, 1))
- return -EINVAL;
+ if (!parse_options(data, sb, NULL, &n_blocks_count, 1)) {
+ err = -EINVAL;
+ goto restore_opts;
+ }
if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
ext3_abort(sb, __FUNCTION__, "Abort forced by user");
@@ -2114,8 +2152,10 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
if ((*flags & MS_RDONLY) != (sb->s_flags & MS_RDONLY) ||
n_blocks_count > le32_to_cpu(es->s_blocks_count)) {
- if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
- return -EROFS;
+ if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) {
+ err = -EROFS;
+ goto restore_opts;
+ }
if (*flags & MS_RDONLY) {
/*
@@ -2142,7 +2182,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
"remount RDWR because of unsupported "
"optional features (%x).\n",
sb->s_id, le32_to_cpu(ret));
- return -EROFS;
+ err = -EROFS;
+ goto restore_opts;
}
/*
* Mounting a RDONLY partition read-write, so reread
@@ -2152,13 +2193,38 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
*/
ext3_clear_journal_err(sb, es);
sbi->s_mount_state = le16_to_cpu(es->s_state);
- if ((ret = ext3_group_extend(sb, es, n_blocks_count)))
- return ret;
+ if ((ret = ext3_group_extend(sb, es, n_blocks_count))) {
+ err = ret;
+ goto restore_opts;
+ }
if (!ext3_setup_super (sb, es, 0))
sb->s_flags &= ~MS_RDONLY;
}
}
+#ifdef CONFIG_QUOTA
+ /* Release old quota file names */
+ for (i = 0; i < MAXQUOTAS; i++)
+ if (old_opts.s_qf_names[i] &&
+ old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+ kfree(old_opts.s_qf_names[i]);
+#endif
return 0;
+restore_opts:
+ sb->s_flags = old_sb_flags;
+ sbi->s_mount_opt = old_opts.s_mount_opt;
+ sbi->s_resuid = old_opts.s_resuid;
+ sbi->s_resgid = old_opts.s_resgid;
+ sbi->s_commit_interval = old_opts.s_commit_interval;
+#ifdef CONFIG_QUOTA
+ sbi->s_jquota_fmt = old_opts.s_jquota_fmt;
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sbi->s_qf_names[i] &&
+ old_opts.s_qf_names[i] != sbi->s_qf_names[i])
+ kfree(sbi->s_qf_names[i]);
+ sbi->s_qf_names[i] = old_opts.s_qf_names[i];
+ }
+#endif
+ return err;
}
static int ext3_statfs (struct super_block * sb, struct kstatfs * buf)
@@ -2238,7 +2304,7 @@ static int ext3_dquot_initialize(struct inode *inode, int type)
int ret, err;
/* We may create quota structure so we need to reserve enough blocks */
- handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+ handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS(inode->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
ret = dquot_initialize(inode, type);
@@ -2254,7 +2320,7 @@ static int ext3_dquot_drop(struct inode *inode)
int ret, err;
/* We may delete quota structure so we need to reserve enough blocks */
- handle = ext3_journal_start(inode, 2*EXT3_QUOTA_INIT_BLOCKS);
+ handle = ext3_journal_start(inode, 2*EXT3_QUOTA_DEL_BLOCKS(inode->i_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
ret = dquot_drop(inode);
@@ -2272,7 +2338,7 @@ static int ext3_write_dquot(struct dquot *dquot)
inode = dquot_to_inode(dquot);
handle = ext3_journal_start(inode,
- EXT3_QUOTA_TRANS_BLOCKS);
+ EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
ret = dquot_commit(dquot);
@@ -2288,7 +2354,7 @@ static int ext3_acquire_dquot(struct dquot *dquot)
handle_t *handle;
handle = ext3_journal_start(dquot_to_inode(dquot),
- EXT3_QUOTA_INIT_BLOCKS);
+ EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
ret = dquot_acquire(dquot);
@@ -2304,7 +2370,7 @@ static int ext3_release_dquot(struct dquot *dquot)
handle_t *handle;
handle = ext3_journal_start(dquot_to_inode(dquot),
- EXT3_QUOTA_INIT_BLOCKS);
+ EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb));
if (IS_ERR(handle))
return PTR_ERR(handle);
ret = dquot_release(dquot);
@@ -2361,6 +2427,8 @@ static int ext3_quota_on(struct super_block *sb, int type, int format_id,
int err;
struct nameidata nd;
+ if (!test_opt(sb, QUOTA))
+ return -EINVAL;
/* Not journalling quota? */
if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] &&
!EXT3_SB(sb)->s_qf_names[GRPQUOTA])
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c
index 4cbc6d0212d3..3f9dfa643b19 100644
--- a/fs/ext3/xattr.c
+++ b/fs/ext3/xattr.c
@@ -1044,7 +1044,7 @@ ext3_xattr_set(struct inode *inode, int name_index, const char *name,
int error, retries = 0;
retry:
- handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS);
+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
if (IS_ERR(handle)) {
error = PTR_ERR(handle);
} else {
diff --git a/fs/fat/cache.c b/fs/fat/cache.c
index 7c52e465a619..77c24fcf712a 100644
--- a/fs/fat/cache.c
+++ b/fs/fat/cache.c
@@ -56,7 +56,7 @@ int __init fat_cache_init(void)
return 0;
}
-void __exit fat_cache_destroy(void)
+void fat_cache_destroy(void)
{
if (kmem_cache_destroy(fat_cache_cachep))
printk(KERN_INFO "fat_cache: not all structures were freed\n");
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 8ccee8415488..96ae85b67eba 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1327,16 +1327,25 @@ out_fail:
EXPORT_SYMBOL(fat_fill_super);
int __init fat_cache_init(void);
-void __exit fat_cache_destroy(void);
+void fat_cache_destroy(void);
static int __init init_fat_fs(void)
{
- int ret;
+ int err;
- ret = fat_cache_init();
- if (ret < 0)
- return ret;
- return fat_init_inodecache();
+ err = fat_cache_init();
+ if (err)
+ return err;
+
+ err = fat_init_inodecache();
+ if (err)
+ goto failed;
+
+ return 0;
+
+failed:
+ fat_cache_destroy();
+ return err;
}
static void __exit exit_fat_fs(void)
diff --git a/fs/file_table.c b/fs/file_table.c
index fa7849fae134..1d3de78e6bc9 100644
--- a/fs/file_table.c
+++ b/fs/file_table.c
@@ -16,6 +16,7 @@
#include <linux/eventpoll.h>
#include <linux/mount.h>
#include <linux/cdev.h>
+#include <linux/fsnotify.h>
/* sysctl tunables... */
struct files_stat_struct files_stat = {
@@ -126,6 +127,8 @@ void fastcall __fput(struct file *file)
struct inode *inode = dentry->d_inode;
might_sleep();
+
+ fsnotify_close(file);
/*
* The function eventpoll_release() should be the first called
* in the file cleanup chain.
diff --git a/fs/freevxfs/vxfs.h b/fs/freevxfs/vxfs.h
index 8da0252642a4..583bd78086d8 100644
--- a/fs/freevxfs/vxfs.h
+++ b/fs/freevxfs/vxfs.h
@@ -37,7 +37,6 @@
* superblocks of the Veritas Filesystem.
*/
#include <linux/types.h>
-#include "vxfs_kcompat.h"
/*
diff --git a/fs/freevxfs/vxfs_bmap.c b/fs/freevxfs/vxfs_bmap.c
index bc4b57da306a..d3f6b2835bc8 100644
--- a/fs/freevxfs/vxfs_bmap.c
+++ b/fs/freevxfs/vxfs_bmap.c
@@ -101,7 +101,7 @@ vxfs_bmap_ext4(struct inode *ip, long bn)
return 0;
fail_size:
- printk("vxfs: indirect extent to big!\n");
+ printk("vxfs: indirect extent too big!\n");
fail_buf:
return 0;
}
diff --git a/fs/freevxfs/vxfs_fshead.c b/fs/freevxfs/vxfs_fshead.c
index 05b19f70bf97..6dee109aeea4 100644
--- a/fs/freevxfs/vxfs_fshead.c
+++ b/fs/freevxfs/vxfs_fshead.c
@@ -78,17 +78,18 @@ vxfs_getfsh(struct inode *ip, int which)
struct buffer_head *bp;
bp = vxfs_bread(ip, which);
- if (buffer_mapped(bp)) {
+ if (bp) {
struct vxfs_fsh *fhp;
- if (!(fhp = kmalloc(sizeof(*fhp), SLAB_KERNEL)))
- return NULL;
+ if (!(fhp = kmalloc(sizeof(*fhp), GFP_KERNEL)))
+ goto out;
memcpy(fhp, bp->b_data, sizeof(*fhp));
- brelse(bp);
+ put_bh(bp);
return (fhp);
}
-
+out:
+ brelse(bp);
return NULL;
}
diff --git a/fs/freevxfs/vxfs_kcompat.h b/fs/freevxfs/vxfs_kcompat.h
deleted file mode 100644
index 342a4cc860f4..000000000000
--- a/fs/freevxfs/vxfs_kcompat.h
+++ /dev/null
@@ -1,49 +0,0 @@
-#ifndef _VXFS_KCOMPAT_H
-#define _VXFS_KCOMPAT_H
-
-#include <linux/version.h>
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
-
-#include <linux/blkdev.h>
-
-typedef long sector_t;
-
-/* From include/linux/fs.h (Linux 2.5.2-pre3) */
-static inline struct buffer_head * sb_bread(struct super_block *sb, int block)
-{
- return bread(sb->s_dev, block, sb->s_blocksize);
-}
-
-/* Dito. */
-static inline void map_bh(struct buffer_head *bh, struct super_block *sb, int block)
-{
- bh->b_state |= 1 << BH_Mapped;
- bh->b_dev = sb->s_dev;
- bh->b_blocknr = block;
-}
-
-/* From fs/block_dev.c (Linux 2.5.2-pre2) */
-static inline int sb_set_blocksize(struct super_block *sb, int size)
-{
- int bits;
- if (set_blocksize(sb->s_dev, size) < 0)
- return 0;
- sb->s_blocksize = size;
- for (bits = 9, size >>= 9; size >>= 1; bits++)
- ;
- sb->s_blocksize_bits = bits;
- return sb->s_blocksize;
-}
-
-/* Dito. */
-static inline int sb_min_blocksize(struct super_block *sb, int size)
-{
- int minsize = get_hardsect_size(sb->s_dev);
- if (size < minsize)
- size = minsize;
- return sb_set_blocksize(sb, size);
-}
-
-#endif /* Kernel 2.4 */
-#endif /* _VXFS_KCOMPAT_H */
diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c
index 506ae251d2c0..554eb455722c 100644
--- a/fs/freevxfs/vxfs_lookup.c
+++ b/fs/freevxfs/vxfs_lookup.c
@@ -61,13 +61,13 @@ struct file_operations vxfs_dir_operations = {
};
-static __inline__ u_long
+static inline u_long
dir_pages(struct inode *inode)
{
return (inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
}
-static __inline__ u_long
+static inline u_long
dir_blocks(struct inode *ip)
{
u_long bsize = ip->i_sb->s_blocksize;
@@ -79,7 +79,7 @@ dir_blocks(struct inode *ip)
*
* len <= VXFS_NAMELEN and de != NULL are guaranteed by caller.
*/
-static __inline__ int
+static inline int
vxfs_match(int len, const char * const name, struct vxfs_direct *de)
{
if (len != de->d_namelen)
@@ -89,7 +89,7 @@ vxfs_match(int len, const char * const name, struct vxfs_direct *de)
return !memcmp(name, de->d_name, len);
}
-static __inline__ struct vxfs_direct *
+static inline struct vxfs_direct *
vxfs_next_entry(struct vxfs_direct *de)
{
return ((struct vxfs_direct *)((char*)de + de->d_reclen));
diff --git a/fs/freevxfs/vxfs_olt.c b/fs/freevxfs/vxfs_olt.c
index 7a204e31aad9..133476201d84 100644
--- a/fs/freevxfs/vxfs_olt.c
+++ b/fs/freevxfs/vxfs_olt.c
@@ -38,7 +38,7 @@
#include "vxfs_olt.h"
-static __inline__ void
+static inline void
vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
{
if (infp->vsi_fshino)
@@ -46,7 +46,7 @@ vxfs_get_fshead(struct vxfs_oltfshead *fshp, struct vxfs_sb_info *infp)
infp->vsi_fshino = fshp->olt_fsino[0];
}
-static __inline__ void
+static inline void
vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
{
if (infp->vsi_iext)
@@ -54,7 +54,7 @@ vxfs_get_ilist(struct vxfs_oltilist *ilistp, struct vxfs_sb_info *infp)
infp->vsi_iext = ilistp->olt_iext[0];
}
-static __inline__ u_long
+static inline u_long
vxfs_oblock(struct super_block *sbp, daddr_t block, u_long bsize)
{
if (sbp->s_blocksize % bsize)
@@ -104,8 +104,8 @@ vxfs_read_olt(struct super_block *sbp, u_long bsize)
goto fail;
}
- oaddr = (char *)bp->b_data + op->olt_size;
- eaddr = (char *)bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
+ oaddr = bp->b_data + op->olt_size;
+ eaddr = bp->b_data + (infp->vsi_oltsize * sbp->s_blocksize);
while (oaddr < eaddr) {
struct vxfs_oltcommon *ocp =
diff --git a/fs/freevxfs/vxfs_subr.c b/fs/freevxfs/vxfs_subr.c
index 5e305612054a..50aae77651b2 100644
--- a/fs/freevxfs/vxfs_subr.c
+++ b/fs/freevxfs/vxfs_subr.c
@@ -36,7 +36,6 @@
#include <linux/slab.h>
#include <linux/pagemap.h>
-#include "vxfs_kcompat.h"
#include "vxfs_extern.h"
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c
index 0ae2c7b8182a..27f66d3e8a04 100644
--- a/fs/freevxfs/vxfs_super.c
+++ b/fs/freevxfs/vxfs_super.c
@@ -155,12 +155,11 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
sbp->s_flags |= MS_RDONLY;
- infp = kmalloc(sizeof(*infp), GFP_KERNEL);
+ infp = kcalloc(1, sizeof(*infp), GFP_KERNEL);
if (!infp) {
printk(KERN_WARNING "vxfs: unable to allocate incore superblock\n");
return -ENOMEM;
}
- memset(infp, 0, sizeof(*infp));
bsize = sb_min_blocksize(sbp, BLOCK_SIZE);
if (!bsize) {
@@ -196,7 +195,7 @@ static int vxfs_fill_super(struct super_block *sbp, void *dp, int silent)
#endif
sbp->s_magic = rsbp->vs_magic;
- sbp->s_fs_info = (void *)infp;
+ sbp->s_fs_info = infp;
infp->vsi_raw = rsbp;
infp->vsi_bp = bp;
@@ -263,7 +262,7 @@ vxfs_init(void)
sizeof(struct vxfs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT, NULL, NULL);
if (vxfs_inode_cachep)
- return (register_filesystem(&vxfs_fs_type));
+ return register_filesystem(&vxfs_fs_type);
return -ENOMEM;
}
diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c
index f8e0cbd0cb60..6f553e17c375 100644
--- a/fs/hppfs/hppfs_kern.c
+++ b/fs/hppfs/hppfs_kern.c
@@ -4,6 +4,7 @@
*/
#include <linux/fs.h>
+#include <linux/file.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
@@ -491,7 +492,7 @@ static int hppfs_open(struct inode *inode, struct file *file)
fd = open_host_sock(host_file, &filter);
if(fd > 0){
data->contents = hppfs_get_data(fd, filter,
- &data->proc_file,
+ data->proc_file,
file, &data->len);
if(!IS_ERR(data->contents))
data->host_fd = fd;
@@ -543,7 +544,7 @@ static int hppfs_dir_open(struct inode *inode, struct file *file)
static loff_t hppfs_llseek(struct file *file, loff_t off, int where)
{
struct hppfs_private *data = file->private_data;
- struct file *proc_file = &data->proc_file;
+ struct file *proc_file = data->proc_file;
loff_t (*llseek)(struct file *, loff_t, int);
loff_t ret;
@@ -586,7 +587,7 @@ static int hppfs_filldir(void *d, const char *name, int size,
static int hppfs_readdir(struct file *file, void *ent, filldir_t filldir)
{
struct hppfs_private *data = file->private_data;
- struct file *proc_file = &data->proc_file;
+ struct file *proc_file = data->proc_file;
int (*readdir)(struct file *, void *, filldir_t);
struct hppfs_dirent dirent = ((struct hppfs_dirent)
{ .vfs_dirent = ent,
diff --git a/fs/inode.c b/fs/inode.c
index 1f9a3a2b89bc..96364fae0844 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -21,6 +21,7 @@
#include <linux/pagemap.h>
#include <linux/cdev.h>
#include <linux/bootmem.h>
+#include <linux/inotify.h>
/*
* This is needed for the following functions:
@@ -202,6 +203,10 @@ void inode_init_once(struct inode *inode)
INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear);
spin_lock_init(&inode->i_lock);
i_size_ordered_init(inode);
+#ifdef CONFIG_INOTIFY
+ INIT_LIST_HEAD(&inode->inotify_watches);
+ sema_init(&inode->inotify_sem, 1);
+#endif
}
EXPORT_SYMBOL(inode_init_once);
@@ -282,6 +287,13 @@ static void dispose_list(struct list_head *head)
if (inode->i_data.nrpages)
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
+
+ spin_lock(&inode_lock);
+ hlist_del_init(&inode->i_hash);
+ list_del_init(&inode->i_sb_list);
+ spin_unlock(&inode_lock);
+
+ wake_up_inode(inode);
destroy_inode(inode);
nr_disposed++;
}
@@ -317,8 +329,6 @@ static int invalidate_list(struct list_head *head, struct list_head *dispose)
inode = list_entry(tmp, struct inode, i_sb_list);
invalidate_inode_buffers(inode);
if (!atomic_read(&inode->i_count)) {
- hlist_del_init(&inode->i_hash);
- list_del(&inode->i_sb_list);
list_move(&inode->i_list, dispose);
inode->i_state |= I_FREEING;
count++;
@@ -346,6 +356,7 @@ int invalidate_inodes(struct super_block * sb)
down(&iprune_sem);
spin_lock(&inode_lock);
+ inotify_unmount_inodes(&sb->s_inodes);
busy = invalidate_list(&sb->s_inodes, &throw_away);
spin_unlock(&inode_lock);
@@ -439,8 +450,6 @@ static void prune_icache(int nr_to_scan)
if (!can_unuse(inode))
continue;
}
- hlist_del_init(&inode->i_hash);
- list_del_init(&inode->i_sb_list);
list_move(&inode->i_list, &freeable);
inode->i_state |= I_FREEING;
nr_pruned++;
@@ -1052,7 +1061,7 @@ static void generic_forget_inode(struct inode *inode)
* inode when the usage count drops to zero, and
* i_nlink is zero.
*/
-static void generic_drop_inode(struct inode *inode)
+void generic_drop_inode(struct inode *inode)
{
if (!inode->i_nlink)
generic_delete_inode(inode);
@@ -1060,6 +1069,8 @@ static void generic_drop_inode(struct inode *inode)
generic_forget_inode(inode);
}
+EXPORT_SYMBOL_GPL(generic_drop_inode);
+
/*
* Called when we're dropping the last reference
* to an inode.
@@ -1242,29 +1253,21 @@ int inode_wait(void *word)
}
/*
- * If we try to find an inode in the inode hash while it is being deleted, we
- * have to wait until the filesystem completes its deletion before reporting
- * that it isn't found. This is because iget will immediately call
- * ->read_inode, and we want to be sure that evidence of the deletion is found
- * by ->read_inode.
+ * If we try to find an inode in the inode hash while it is being
+ * deleted, we have to wait until the filesystem completes its
+ * deletion before reporting that it isn't found. This function waits
+ * until the deletion _might_ have completed. Callers are responsible
+ * to recheck inode state.
+ *
+ * It doesn't matter if I_LOCK is not set initially, a call to
+ * wake_up_inode() after removing from the hash list will DTRT.
+ *
* This is called with inode_lock held.
*/
static void __wait_on_freeing_inode(struct inode *inode)
{
wait_queue_head_t *wq;
DEFINE_WAIT_BIT(wait, &inode->i_state, __I_LOCK);
-
- /*
- * I_FREEING and I_CLEAR are cleared in process context under
- * inode_lock, so we have to give the tasks who would clear them
- * a chance to run and acquire inode_lock.
- */
- if (!(inode->i_state & I_LOCK)) {
- spin_unlock(&inode_lock);
- yield();
- spin_lock(&inode_lock);
- return;
- }
wq = bit_waitqueue(&inode->i_state, __I_LOCK);
prepare_to_wait(wq, &wait.wait, TASK_UNINTERRUPTIBLE);
spin_unlock(&inode_lock);
diff --git a/fs/inotify.c b/fs/inotify.c
new file mode 100644
index 000000000000..e423bfe0c86f
--- /dev/null
+++ b/fs/inotify.c
@@ -0,0 +1,999 @@
+/*
+ * fs/inotify.c - inode-based file event notifications
+ *
+ * Authors:
+ * John McCutchan <ttb@tentacle.dhs.org>
+ * Robert Love <rml@novell.com>
+ *
+ * Copyright (C) 2005 John McCutchan
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/poll.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/writeback.h>
+#include <linux/inotify.h>
+
+#include <asm/ioctls.h>
+
+static atomic_t inotify_cookie;
+
+static kmem_cache_t *watch_cachep;
+static kmem_cache_t *event_cachep;
+
+static struct vfsmount *inotify_mnt;
+
+/* These are configurable via /proc/sys/inotify */
+int inotify_max_user_devices;
+int inotify_max_user_watches;
+int inotify_max_queued_events;
+
+/*
+ * Lock ordering:
+ *
+ * dentry->d_lock (used to keep d_move() away from dentry->d_parent)
+ * iprune_sem (synchronize shrink_icache_memory())
+ * inode_lock (protects the super_block->s_inodes list)
+ * inode->inotify_sem (protects inode->inotify_watches and watches->i_list)
+ * inotify_dev->sem (protects inotify_device and watches->d_list)
+ */
+
+/*
+ * Lifetimes of the three main data structures--inotify_device, inode, and
+ * inotify_watch--are managed by reference count.
+ *
+ * inotify_device: Lifetime is from open until release. Additional references
+ * can bump the count via get_inotify_dev() and drop the count via
+ * put_inotify_dev().
+ *
+ * inotify_watch: Lifetime is from create_watch() to destory_watch().
+ * Additional references can bump the count via get_inotify_watch() and drop
+ * the count via put_inotify_watch().
+ *
+ * inode: Pinned so long as the inode is associated with a watch, from
+ * create_watch() to put_inotify_watch().
+ */
+
+/*
+ * struct inotify_device - represents an open instance of an inotify device
+ *
+ * This structure is protected by the semaphore 'sem'.
+ */
+struct inotify_device {
+ wait_queue_head_t wq; /* wait queue for i/o */
+ struct idr idr; /* idr mapping wd -> watch */
+ struct semaphore sem; /* protects this bad boy */
+ struct list_head events; /* list of queued events */
+ struct list_head watches; /* list of watches */
+ atomic_t count; /* reference count */
+ struct user_struct *user; /* user who opened this dev */
+ unsigned int queue_size; /* size of the queue (bytes) */
+ unsigned int event_count; /* number of pending events */
+ unsigned int max_events; /* maximum number of events */
+};
+
+/*
+ * struct inotify_kernel_event - An inotify event, originating from a watch and
+ * queued for user-space. A list of these is attached to each instance of the
+ * device. In read(), this list is walked and all events that can fit in the
+ * buffer are returned.
+ *
+ * Protected by dev->sem of the device in which we are queued.
+ */
+struct inotify_kernel_event {
+ struct inotify_event event; /* the user-space event */
+ struct list_head list; /* entry in inotify_device's list */
+ char *name; /* filename, if any */
+};
+
+/*
+ * struct inotify_watch - represents a watch request on a specific inode
+ *
+ * d_list is protected by dev->sem of the associated watch->dev.
+ * i_list and mask are protected by inode->inotify_sem of the associated inode.
+ * dev, inode, and wd are never written to once the watch is created.
+ */
+struct inotify_watch {
+ struct list_head d_list; /* entry in inotify_device's list */
+ struct list_head i_list; /* entry in inode's list */
+ atomic_t count; /* reference count */
+ struct inotify_device *dev; /* associated device */
+ struct inode *inode; /* associated inode */
+ s32 wd; /* watch descriptor */
+ u32 mask; /* event mask for this watch */
+};
+
+static inline void get_inotify_dev(struct inotify_device *dev)
+{
+ atomic_inc(&dev->count);
+}
+
+static inline void put_inotify_dev(struct inotify_device *dev)
+{
+ if (atomic_dec_and_test(&dev->count)) {
+ atomic_dec(&dev->user->inotify_devs);
+ free_uid(dev->user);
+ kfree(dev);
+ }
+}
+
+static inline void get_inotify_watch(struct inotify_watch *watch)
+{
+ atomic_inc(&watch->count);
+}
+
+/*
+ * put_inotify_watch - decrements the ref count on a given watch. cleans up
+ * the watch and its references if the count reaches zero.
+ */
+static inline void put_inotify_watch(struct inotify_watch *watch)
+{
+ if (atomic_dec_and_test(&watch->count)) {
+ put_inotify_dev(watch->dev);
+ iput(watch->inode);
+ kmem_cache_free(watch_cachep, watch);
+ }
+}
+
+/*
+ * kernel_event - create a new kernel event with the given parameters
+ *
+ * This function can sleep.
+ */
+static struct inotify_kernel_event * kernel_event(s32 wd, u32 mask, u32 cookie,
+ const char *name)
+{
+ struct inotify_kernel_event *kevent;
+
+ kevent = kmem_cache_alloc(event_cachep, GFP_KERNEL);
+ if (unlikely(!kevent))
+ return NULL;
+
+ /* we hand this out to user-space, so zero it just in case */
+ memset(&kevent->event, 0, sizeof(struct inotify_event));
+
+ kevent->event.wd = wd;
+ kevent->event.mask = mask;
+ kevent->event.cookie = cookie;
+
+ INIT_LIST_HEAD(&kevent->list);
+
+ if (name) {
+ size_t len, rem, event_size = sizeof(struct inotify_event);
+
+ /*
+ * We need to pad the filename so as to properly align an
+ * array of inotify_event structures. Because the structure is
+ * small and the common case is a small filename, we just round
+ * up to the next multiple of the structure's sizeof. This is
+ * simple and safe for all architectures.
+ */
+ len = strlen(name) + 1;
+ rem = event_size - len;
+ if (len > event_size) {
+ rem = event_size - (len % event_size);
+ if (len % event_size == 0)
+ rem = 0;
+ }
+
+ kevent->name = kmalloc(len + rem, GFP_KERNEL);
+ if (unlikely(!kevent->name)) {
+ kmem_cache_free(event_cachep, kevent);
+ return NULL;
+ }
+ memcpy(kevent->name, name, len);
+ if (rem)
+ memset(kevent->name + len, 0, rem);
+ kevent->event.len = len + rem;
+ } else {
+ kevent->event.len = 0;
+ kevent->name = NULL;
+ }
+
+ return kevent;
+}
+
+/*
+ * inotify_dev_get_event - return the next event in the given dev's queue
+ *
+ * Caller must hold dev->sem.
+ */
+static inline struct inotify_kernel_event *
+inotify_dev_get_event(struct inotify_device *dev)
+{
+ return list_entry(dev->events.next, struct inotify_kernel_event, list);
+}
+
+/*
+ * inotify_dev_queue_event - add a new event to the given device
+ *
+ * Caller must hold dev->sem. Can sleep (calls kernel_event()).
+ */
+static void inotify_dev_queue_event(struct inotify_device *dev,
+ struct inotify_watch *watch, u32 mask,
+ u32 cookie, const char *name)
+{
+ struct inotify_kernel_event *kevent, *last;
+
+ /* coalescing: drop this event if it is a dupe of the previous */
+ last = inotify_dev_get_event(dev);
+ if (last && last->event.mask == mask && last->event.wd == watch->wd &&
+ last->event.cookie == cookie) {
+ const char *lastname = last->name;
+
+ if (!name && !lastname)
+ return;
+ if (name && lastname && !strcmp(lastname, name))
+ return;
+ }
+
+ /* the queue overflowed and we already sent the Q_OVERFLOW event */
+ if (unlikely(dev->event_count > dev->max_events))
+ return;
+
+ /* if the queue overflows, we need to notify user space */
+ if (unlikely(dev->event_count == dev->max_events))
+ kevent = kernel_event(-1, IN_Q_OVERFLOW, cookie, NULL);
+ else
+ kevent = kernel_event(watch->wd, mask, cookie, name);
+
+ if (unlikely(!kevent))
+ return;
+
+ /* queue the event and wake up anyone waiting */
+ dev->event_count++;
+ dev->queue_size += sizeof(struct inotify_event) + kevent->event.len;
+ list_add_tail(&kevent->list, &dev->events);
+ wake_up_interruptible(&dev->wq);
+}
+
+/*
+ * remove_kevent - cleans up and ultimately frees the given kevent
+ *
+ * Caller must hold dev->sem.
+ */
+static void remove_kevent(struct inotify_device *dev,
+ struct inotify_kernel_event *kevent)
+{
+ list_del(&kevent->list);
+
+ dev->event_count--;
+ dev->queue_size -= sizeof(struct inotify_event) + kevent->event.len;
+
+ kfree(kevent->name);
+ kmem_cache_free(event_cachep, kevent);
+}
+
+/*
+ * inotify_dev_event_dequeue - destroy an event on the given device
+ *
+ * Caller must hold dev->sem.
+ */
+static void inotify_dev_event_dequeue(struct inotify_device *dev)
+{
+ if (!list_empty(&dev->events)) {
+ struct inotify_kernel_event *kevent;
+ kevent = inotify_dev_get_event(dev);
+ remove_kevent(dev, kevent);
+ }
+}
+
+/*
+ * inotify_dev_get_wd - returns the next WD for use by the given dev
+ *
+ * Callers must hold dev->sem. This function can sleep.
+ */
+static int inotify_dev_get_wd(struct inotify_device *dev,
+ struct inotify_watch *watch)
+{
+ int ret;
+
+ do {
+ if (unlikely(!idr_pre_get(&dev->idr, GFP_KERNEL)))
+ return -ENOSPC;
+ ret = idr_get_new(&dev->idr, watch, &watch->wd);
+ } while (ret == -EAGAIN);
+
+ return ret;
+}
+
+/*
+ * find_inode - resolve a user-given path to a specific inode and return a nd
+ */
+static int find_inode(const char __user *dirname, struct nameidata *nd)
+{
+ int error;
+
+ error = __user_walk(dirname, LOOKUP_FOLLOW, nd);
+ if (error)
+ return error;
+ /* you can only watch an inode if you have read permissions on it */
+ error = permission(nd->dentry->d_inode, MAY_READ, NULL);
+ if (error)
+ path_release (nd);
+ return error;
+}
+
+/*
+ * create_watch - creates a watch on the given device.
+ *
+ * Callers must hold dev->sem. Calls inotify_dev_get_wd() so may sleep.
+ * Both 'dev' and 'inode' (by way of nameidata) need to be pinned.
+ */
+static struct inotify_watch *create_watch(struct inotify_device *dev,
+ u32 mask, struct inode *inode)
+{
+ struct inotify_watch *watch;
+ int ret;
+
+ if (atomic_read(&dev->user->inotify_watches) >= inotify_max_user_watches)
+ return ERR_PTR(-ENOSPC);
+
+ watch = kmem_cache_alloc(watch_cachep, GFP_KERNEL);
+ if (unlikely(!watch))
+ return ERR_PTR(-ENOMEM);
+
+ ret = inotify_dev_get_wd(dev, watch);
+ if (unlikely(ret)) {
+ kmem_cache_free(watch_cachep, watch);
+ return ERR_PTR(ret);
+ }
+
+ watch->mask = mask;
+ atomic_set(&watch->count, 0);
+ INIT_LIST_HEAD(&watch->d_list);
+ INIT_LIST_HEAD(&watch->i_list);
+
+ /* save a reference to device and bump the count to make it official */
+ get_inotify_dev(dev);
+ watch->dev = dev;
+
+ /*
+ * Save a reference to the inode and bump the ref count to make it
+ * official. We hold a reference to nameidata, which makes this safe.
+ */
+ watch->inode = igrab(inode);
+
+ /* bump our own count, corresponding to our entry in dev->watches */
+ get_inotify_watch(watch);
+
+ atomic_inc(&dev->user->inotify_watches);
+
+ return watch;
+}
+
+/*
+ * inotify_find_dev - find the watch associated with the given inode and dev
+ *
+ * Callers must hold inode->inotify_sem.
+ */
+static struct inotify_watch *inode_find_dev(struct inode *inode,
+ struct inotify_device *dev)
+{
+ struct inotify_watch *watch;
+
+ list_for_each_entry(watch, &inode->inotify_watches, i_list) {
+ if (watch->dev == dev)
+ return watch;
+ }
+
+ return NULL;
+}
+
+/*
+ * remove_watch_no_event - remove_watch() without the IN_IGNORED event.
+ */
+static void remove_watch_no_event(struct inotify_watch *watch,
+ struct inotify_device *dev)
+{
+ list_del(&watch->i_list);
+ list_del(&watch->d_list);
+
+ atomic_dec(&dev->user->inotify_watches);
+ idr_remove(&dev->idr, watch->wd);
+ put_inotify_watch(watch);
+}
+
+/*
+ * remove_watch - Remove a watch from both the device and the inode. Sends
+ * the IN_IGNORED event to the given device signifying that the inode is no
+ * longer watched.
+ *
+ * Callers must hold both inode->inotify_sem and dev->sem. We drop a
+ * reference to the inode before returning.
+ *
+ * The inode is not iput() so as to remain atomic. If the inode needs to be
+ * iput(), the call returns one. Otherwise, it returns zero.
+ */
+static void remove_watch(struct inotify_watch *watch,struct inotify_device *dev)
+{
+ inotify_dev_queue_event(dev, watch, IN_IGNORED, 0, NULL);
+ remove_watch_no_event(watch, dev);
+}
+
+/*
+ * inotify_inode_watched - returns nonzero if there are watches on this inode
+ * and zero otherwise. We call this lockless, we do not care if we race.
+ */
+static inline int inotify_inode_watched(struct inode *inode)
+{
+ return !list_empty(&inode->inotify_watches);
+}
+
+/* Kernel API */
+
+/**
+ * inotify_inode_queue_event - queue an event to all watches on this inode
+ * @inode: inode event is originating from
+ * @mask: event mask describing this event
+ * @cookie: cookie for synchronization, or zero
+ * @name: filename, if any
+ */
+void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie,
+ const char *name)
+{
+ struct inotify_watch *watch, *next;
+
+ if (!inotify_inode_watched(inode))
+ return;
+
+ down(&inode->inotify_sem);
+ list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
+ u32 watch_mask = watch->mask;
+ if (watch_mask & mask) {
+ struct inotify_device *dev = watch->dev;
+ get_inotify_watch(watch);
+ down(&dev->sem);
+ inotify_dev_queue_event(dev, watch, mask, cookie, name);
+ if (watch_mask & IN_ONESHOT)
+ remove_watch_no_event(watch, dev);
+ up(&dev->sem);
+ put_inotify_watch(watch);
+ }
+ }
+ up(&inode->inotify_sem);
+}
+EXPORT_SYMBOL_GPL(inotify_inode_queue_event);
+
+/**
+ * inotify_dentry_parent_queue_event - queue an event to a dentry's parent
+ * @dentry: the dentry in question, we queue against this dentry's parent
+ * @mask: event mask describing this event
+ * @cookie: cookie for synchronization, or zero
+ * @name: filename, if any
+ */
+void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask,
+ u32 cookie, const char *name)
+{
+ struct dentry *parent;
+ struct inode *inode;
+
+ spin_lock(&dentry->d_lock);
+ parent = dentry->d_parent;
+ inode = parent->d_inode;
+
+ if (inotify_inode_watched(inode)) {
+ dget(parent);
+ spin_unlock(&dentry->d_lock);
+ inotify_inode_queue_event(inode, mask, cookie, name);
+ dput(parent);
+ } else
+ spin_unlock(&dentry->d_lock);
+}
+EXPORT_SYMBOL_GPL(inotify_dentry_parent_queue_event);
+
+/**
+ * inotify_get_cookie - return a unique cookie for use in synchronizing events.
+ */
+u32 inotify_get_cookie(void)
+{
+ return atomic_inc_return(&inotify_cookie);
+}
+EXPORT_SYMBOL_GPL(inotify_get_cookie);
+
+/**
+ * inotify_unmount_inodes - an sb is unmounting. handle any watched inodes.
+ * @list: list of inodes being unmounted (sb->s_inodes)
+ *
+ * Called with inode_lock held, protecting the unmounting super block's list
+ * of inodes, and with iprune_sem held, keeping shrink_icache_memory() at bay.
+ * We temporarily drop inode_lock, however, and CAN block.
+ */
+void inotify_unmount_inodes(struct list_head *list)
+{
+ struct inode *inode, *next_i, *need_iput = NULL;
+
+ list_for_each_entry_safe(inode, next_i, list, i_sb_list) {
+ struct inotify_watch *watch, *next_w;
+ struct inode *need_iput_tmp;
+ struct list_head *watches;
+
+ /*
+ * If i_count is zero, the inode cannot have any watches and
+ * doing an __iget/iput with MS_ACTIVE clear would actually
+ * evict all inodes with zero i_count from icache which is
+ * unnecessarily violent and may in fact be illegal to do.
+ */
+ if (!atomic_read(&inode->i_count))
+ continue;
+
+ /*
+ * We cannot __iget() an inode in state I_CLEAR, I_FREEING, or
+ * I_WILL_FREE which is fine because by that point the inode
+ * cannot have any associated watches.
+ */
+ if (inode->i_state & (I_CLEAR | I_FREEING | I_WILL_FREE))
+ continue;
+
+ need_iput_tmp = need_iput;
+ need_iput = NULL;
+ /* In case the remove_watch() drops a reference. */
+ if (inode != need_iput_tmp)
+ __iget(inode);
+ else
+ need_iput_tmp = NULL;
+ /* In case the dropping of a reference would nuke next_i. */
+ if ((&next_i->i_sb_list != list) &&
+ atomic_read(&next_i->i_count) &&
+ !(next_i->i_state & (I_CLEAR | I_FREEING |
+ I_WILL_FREE))) {
+ __iget(next_i);
+ need_iput = next_i;
+ }
+
+ /*
+ * We can safely drop inode_lock here because we hold
+ * references on both inode and next_i. Also no new inodes
+ * will be added since the umount has begun. Finally,
+ * iprune_sem keeps shrink_icache_memory() away.
+ */
+ spin_unlock(&inode_lock);
+
+ if (need_iput_tmp)
+ iput(need_iput_tmp);
+
+ /* for each watch, send IN_UNMOUNT and then remove it */
+ down(&inode->inotify_sem);
+ watches = &inode->inotify_watches;
+ list_for_each_entry_safe(watch, next_w, watches, i_list) {
+ struct inotify_device *dev = watch->dev;
+ down(&dev->sem);
+ inotify_dev_queue_event(dev, watch, IN_UNMOUNT,0,NULL);
+ remove_watch(watch, dev);
+ up(&dev->sem);
+ }
+ up(&inode->inotify_sem);
+ iput(inode);
+
+ spin_lock(&inode_lock);
+ }
+}
+EXPORT_SYMBOL_GPL(inotify_unmount_inodes);
+
+/**
+ * inotify_inode_is_dead - an inode has been deleted, cleanup any watches
+ * @inode: inode that is about to be removed
+ */
+void inotify_inode_is_dead(struct inode *inode)
+{
+ struct inotify_watch *watch, *next;
+
+ down(&inode->inotify_sem);
+ list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) {
+ struct inotify_device *dev = watch->dev;
+ down(&dev->sem);
+ remove_watch(watch, dev);
+ up(&dev->sem);
+ }
+ up(&inode->inotify_sem);
+}
+EXPORT_SYMBOL_GPL(inotify_inode_is_dead);
+
+/* Device Interface */
+
+static unsigned int inotify_poll(struct file *file, poll_table *wait)
+{
+ struct inotify_device *dev = file->private_data;
+ int ret = 0;
+
+ poll_wait(file, &dev->wq, wait);
+ down(&dev->sem);
+ if (!list_empty(&dev->events))
+ ret = POLLIN | POLLRDNORM;
+ up(&dev->sem);
+
+ return ret;
+}
+
+static ssize_t inotify_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ size_t event_size = sizeof (struct inotify_event);
+ struct inotify_device *dev;
+ char __user *start;
+ int ret;
+ DEFINE_WAIT(wait);
+
+ start = buf;
+ dev = file->private_data;
+
+ while (1) {
+ int events;
+
+ prepare_to_wait(&dev->wq, &wait, TASK_INTERRUPTIBLE);
+
+ down(&dev->sem);
+ events = !list_empty(&dev->events);
+ up(&dev->sem);
+ if (events) {
+ ret = 0;
+ break;
+ }
+
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
+
+ if (signal_pending(current)) {
+ ret = -EINTR;
+ break;
+ }
+
+ schedule();
+ }
+
+ finish_wait(&dev->wq, &wait);
+ if (ret)
+ return ret;
+
+ down(&dev->sem);
+ while (1) {
+ struct inotify_kernel_event *kevent;
+
+ ret = buf - start;
+ if (list_empty(&dev->events))
+ break;
+
+ kevent = inotify_dev_get_event(dev);
+ if (event_size + kevent->event.len > count)
+ break;
+
+ if (copy_to_user(buf, &kevent->event, event_size)) {
+ ret = -EFAULT;
+ break;
+ }
+ buf += event_size;
+ count -= event_size;
+
+ if (kevent->name) {
+ if (copy_to_user(buf, kevent->name, kevent->event.len)){
+ ret = -EFAULT;
+ break;
+ }
+ buf += kevent->event.len;
+ count -= kevent->event.len;
+ }
+
+ remove_kevent(dev, kevent);
+ }
+ up(&dev->sem);
+
+ return ret;
+}
+
+static int inotify_release(struct inode *ignored, struct file *file)
+{
+ struct inotify_device *dev = file->private_data;
+
+ /*
+ * Destroy all of the watches on this device. Unfortunately, not very
+ * pretty. We cannot do a simple iteration over the list, because we
+ * do not know the inode until we iterate to the watch. But we need to
+ * hold inode->inotify_sem before dev->sem. The following works.
+ */
+ while (1) {
+ struct inotify_watch *watch;
+ struct list_head *watches;
+ struct inode *inode;
+
+ down(&dev->sem);
+ watches = &dev->watches;
+ if (list_empty(watches)) {
+ up(&dev->sem);
+ break;
+ }
+ watch = list_entry(watches->next, struct inotify_watch, d_list);
+ get_inotify_watch(watch);
+ up(&dev->sem);
+
+ inode = watch->inode;
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+ remove_watch_no_event(watch, dev);
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+ put_inotify_watch(watch);
+ }
+
+ /* destroy all of the events on this device */
+ down(&dev->sem);
+ while (!list_empty(&dev->events))
+ inotify_dev_event_dequeue(dev);
+ up(&dev->sem);
+
+ /* free this device: the put matching the get in inotify_open() */
+ put_inotify_dev(dev);
+
+ return 0;
+}
+
+/*
+ * inotify_ignore - handle the INOTIFY_IGNORE ioctl, asking that a given wd be
+ * removed from the device.
+ *
+ * Can sleep.
+ */
+static int inotify_ignore(struct inotify_device *dev, s32 wd)
+{
+ struct inotify_watch *watch;
+ struct inode *inode;
+
+ down(&dev->sem);
+ watch = idr_find(&dev->idr, wd);
+ if (unlikely(!watch)) {
+ up(&dev->sem);
+ return -EINVAL;
+ }
+ get_inotify_watch(watch);
+ inode = watch->inode;
+ up(&dev->sem);
+
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+
+ /* make sure that we did not race */
+ watch = idr_find(&dev->idr, wd);
+ if (likely(watch))
+ remove_watch(watch, dev);
+
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+ put_inotify_watch(watch);
+
+ return 0;
+}
+
+static long inotify_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct inotify_device *dev;
+ void __user *p;
+ int ret = -ENOTTY;
+
+ dev = file->private_data;
+ p = (void __user *) arg;
+
+ switch (cmd) {
+ case FIONREAD:
+ ret = put_user(dev->queue_size, (int __user *) p);
+ break;
+ }
+
+ return ret;
+}
+
+static struct file_operations inotify_fops = {
+ .poll = inotify_poll,
+ .read = inotify_read,
+ .release = inotify_release,
+ .unlocked_ioctl = inotify_ioctl,
+ .compat_ioctl = inotify_ioctl,
+};
+
+asmlinkage long sys_inotify_init(void)
+{
+ struct inotify_device *dev;
+ struct user_struct *user;
+ int ret = -ENOTTY;
+ int fd;
+ struct file *filp;
+
+ fd = get_unused_fd();
+ if (fd < 0) {
+ ret = fd;
+ goto out;
+ }
+
+ filp = get_empty_filp();
+ if (!filp) {
+ put_unused_fd(fd);
+ ret = -ENFILE;
+ goto out;
+ }
+ filp->f_op = &inotify_fops;
+ filp->f_vfsmnt = mntget(inotify_mnt);
+ filp->f_dentry = dget(inotify_mnt->mnt_root);
+ filp->f_mapping = filp->f_dentry->d_inode->i_mapping;
+ filp->f_mode = FMODE_READ;
+ filp->f_flags = O_RDONLY;
+
+ user = get_uid(current->user);
+
+ if (unlikely(atomic_read(&user->inotify_devs) >= inotify_max_user_devices)) {
+ ret = -EMFILE;
+ goto out_err;
+ }
+
+ dev = kmalloc(sizeof(struct inotify_device), GFP_KERNEL);
+ if (unlikely(!dev)) {
+ ret = -ENOMEM;
+ goto out_err;
+ }
+
+ idr_init(&dev->idr);
+ INIT_LIST_HEAD(&dev->events);
+ INIT_LIST_HEAD(&dev->watches);
+ init_waitqueue_head(&dev->wq);
+ sema_init(&dev->sem, 1);
+ dev->event_count = 0;
+ dev->queue_size = 0;
+ dev->max_events = inotify_max_queued_events;
+ dev->user = user;
+ atomic_set(&dev->count, 0);
+
+ get_inotify_dev(dev);
+ atomic_inc(&user->inotify_devs);
+
+ filp->private_data = dev;
+ fd_install (fd, filp);
+ return fd;
+out_err:
+ put_unused_fd (fd);
+ put_filp (filp);
+ free_uid(user);
+out:
+ return ret;
+}
+
+asmlinkage long sys_inotify_add_watch(int fd, const char *path, u32 mask)
+{
+ struct inotify_watch *watch, *old;
+ struct inode *inode;
+ struct inotify_device *dev;
+ struct nameidata nd;
+ struct file *filp;
+ int ret;
+
+ filp = fget(fd);
+ if (!filp)
+ return -EBADF;
+
+ dev = filp->private_data;
+
+ ret = find_inode ((const char __user*)path, &nd);
+ if (ret)
+ goto fput_and_out;
+
+ /* Held in place by reference in nd */
+ inode = nd.dentry->d_inode;
+
+ down(&inode->inotify_sem);
+ down(&dev->sem);
+
+ /* don't let user-space set invalid bits: we don't want flags set */
+ mask &= IN_ALL_EVENTS;
+ if (!mask) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /*
+ * Handle the case of re-adding a watch on an (inode,dev) pair that we
+ * are already watching. We just update the mask and return its wd.
+ */
+ old = inode_find_dev(inode, dev);
+ if (unlikely(old)) {
+ old->mask = mask;
+ ret = old->wd;
+ goto out;
+ }
+
+ watch = create_watch(dev, mask, inode);
+ if (unlikely(IS_ERR(watch))) {
+ ret = PTR_ERR(watch);
+ goto out;
+ }
+
+ /* Add the watch to the device's and the inode's list */
+ list_add(&watch->d_list, &dev->watches);
+ list_add(&watch->i_list, &inode->inotify_watches);
+ ret = watch->wd;
+out:
+ path_release (&nd);
+ up(&dev->sem);
+ up(&inode->inotify_sem);
+fput_and_out:
+ fput(filp);
+ return ret;
+}
+
+asmlinkage long sys_inotify_rm_watch(int fd, u32 wd)
+{
+ struct file *filp;
+ struct inotify_device *dev;
+ int ret;
+
+ filp = fget(fd);
+ if (!filp)
+ return -EBADF;
+ dev = filp->private_data;
+ ret = inotify_ignore (dev, wd);
+ fput(filp);
+ return ret;
+}
+
+static struct super_block *
+inotify_get_sb(struct file_system_type *fs_type, int flags,
+ const char *dev_name, void *data)
+{
+ return get_sb_pseudo(fs_type, "inotify", NULL, 0xBAD1DEA);
+}
+
+static struct file_system_type inotify_fs_type = {
+ .name = "inotifyfs",
+ .get_sb = inotify_get_sb,
+ .kill_sb = kill_anon_super,
+};
+
+/*
+ * inotify_init - Our initialization function. Note that we cannnot return
+ * error because we have compiled-in VFS hooks. So an (unlikely) failure here
+ * must result in panic().
+ */
+static int __init inotify_init(void)
+{
+ register_filesystem(&inotify_fs_type);
+ inotify_mnt = kern_mount(&inotify_fs_type);
+
+ inotify_max_queued_events = 8192;
+ inotify_max_user_devices = 128;
+ inotify_max_user_watches = 8192;
+
+ atomic_set(&inotify_cookie, 0);
+
+ watch_cachep = kmem_cache_create("inotify_watch_cache",
+ sizeof(struct inotify_watch),
+ 0, SLAB_PANIC, NULL, NULL);
+ event_cachep = kmem_cache_create("inotify_event_cache",
+ sizeof(struct inotify_kernel_event),
+ 0, SLAB_PANIC, NULL, NULL);
+
+ printk(KERN_INFO "inotify syscall\n");
+
+ return 0;
+}
+
+module_init(inotify_init);
diff --git a/fs/ioprio.c b/fs/ioprio.c
new file mode 100644
index 000000000000..97e1f088ba00
--- /dev/null
+++ b/fs/ioprio.c
@@ -0,0 +1,172 @@
+/*
+ * fs/ioprio.c
+ *
+ * Copyright (C) 2004 Jens Axboe <axboe@suse.de>
+ *
+ * Helper functions for setting/querying io priorities of processes. The
+ * system calls closely mimmick getpriority/setpriority, see the man page for
+ * those. The prio argument is a composite of prio class and prio data, where
+ * the data argument has meaning within that class. The standard scheduling
+ * classes have 8 distinct prio levels, with 0 being the highest prio and 7
+ * being the lowest.
+ *
+ * IOW, setting BE scheduling class with prio 2 is done ala:
+ *
+ * unsigned int prio = (IOPRIO_CLASS_BE << IOPRIO_CLASS_SHIFT) | 2;
+ *
+ * ioprio_set(PRIO_PROCESS, pid, prio);
+ *
+ * See also Documentation/block/ioprio.txt
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/ioprio.h>
+#include <linux/blkdev.h>
+
+static int set_task_ioprio(struct task_struct *task, int ioprio)
+{
+ struct io_context *ioc;
+
+ if (task->uid != current->euid &&
+ task->uid != current->uid && !capable(CAP_SYS_NICE))
+ return -EPERM;
+
+ task_lock(task);
+
+ task->ioprio = ioprio;
+
+ ioc = task->io_context;
+ if (ioc && ioc->set_ioprio)
+ ioc->set_ioprio(ioc, ioprio);
+
+ task_unlock(task);
+ return 0;
+}
+
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio)
+{
+ int class = IOPRIO_PRIO_CLASS(ioprio);
+ int data = IOPRIO_PRIO_DATA(ioprio);
+ struct task_struct *p, *g;
+ struct user_struct *user;
+ int ret;
+
+ switch (class) {
+ case IOPRIO_CLASS_RT:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ /* fall through, rt has prio field too */
+ case IOPRIO_CLASS_BE:
+ if (data >= IOPRIO_BE_NR || data < 0)
+ return -EINVAL;
+
+ break;
+ case IOPRIO_CLASS_IDLE:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = -ESRCH;
+ read_lock_irq(&tasklist_lock);
+ switch (which) {
+ case IOPRIO_WHO_PROCESS:
+ if (!who)
+ p = current;
+ else
+ p = find_task_by_pid(who);
+ if (p)
+ ret = set_task_ioprio(p, ioprio);
+ break;
+ case IOPRIO_WHO_PGRP:
+ if (!who)
+ who = process_group(current);
+ do_each_task_pid(who, PIDTYPE_PGID, p) {
+ ret = set_task_ioprio(p, ioprio);
+ if (ret)
+ break;
+ } while_each_task_pid(who, PIDTYPE_PGID, p);
+ break;
+ case IOPRIO_WHO_USER:
+ if (!who)
+ user = current->user;
+ else
+ user = find_user(who);
+
+ if (!user)
+ break;
+
+ do_each_thread(g, p) {
+ if (p->uid != who)
+ continue;
+ ret = set_task_ioprio(p, ioprio);
+ if (ret)
+ break;
+ } while_each_thread(g, p);
+
+ if (who)
+ free_uid(user);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ read_unlock_irq(&tasklist_lock);
+ return ret;
+}
+
+asmlinkage long sys_ioprio_get(int which, int who)
+{
+ struct task_struct *g, *p;
+ struct user_struct *user;
+ int ret = -ESRCH;
+
+ read_lock_irq(&tasklist_lock);
+ switch (which) {
+ case IOPRIO_WHO_PROCESS:
+ if (!who)
+ p = current;
+ else
+ p = find_task_by_pid(who);
+ if (p)
+ ret = p->ioprio;
+ break;
+ case IOPRIO_WHO_PGRP:
+ if (!who)
+ who = process_group(current);
+ do_each_task_pid(who, PIDTYPE_PGID, p) {
+ if (ret == -ESRCH)
+ ret = p->ioprio;
+ else
+ ret = ioprio_best(ret, p->ioprio);
+ } while_each_task_pid(who, PIDTYPE_PGID, p);
+ break;
+ case IOPRIO_WHO_USER:
+ if (!who)
+ user = current->user;
+ else
+ user = find_user(who);
+
+ if (!user)
+ break;
+
+ do_each_thread(g, p) {
+ if (p->uid != user->uid)
+ continue;
+ if (ret == -ESRCH)
+ ret = p->ioprio;
+ else
+ ret = ioprio_best(ret, p->ioprio);
+ } while_each_thread(g, p);
+
+ if (who)
+ free_uid(user);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ read_unlock_irq(&tasklist_lock);
+ return ret;
+}
+
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index 1e6f2e2ad4a3..5e7b43949517 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -167,7 +167,7 @@ loop:
}
wake_up(&journal->j_wait_done_commit);
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
/*
* The simpler the better. Flushing journal isn't a
* good idea, because that depends on threads that may
@@ -175,7 +175,7 @@ loop:
*/
jbd_debug(1, "Now suspending kjournald\n");
spin_unlock(&journal->j_state_lock);
- refrigerator(PF_FREEZE);
+ refrigerator();
spin_lock(&journal->j_state_lock);
} else {
/*
diff --git a/fs/jffs/intrep.c b/fs/jffs/intrep.c
index 8cc6893fc56c..fc589ddd0762 100644
--- a/fs/jffs/intrep.c
+++ b/fs/jffs/intrep.c
@@ -175,8 +175,64 @@ jffs_hexdump(struct mtd_info *mtd, loff_t pos, int size)
}
}
+/* Print the contents of a node. */
+static void
+jffs_print_node(struct jffs_node *n)
+{
+ D(printk("jffs_node: 0x%p\n", n));
+ D(printk("{\n"));
+ D(printk(" 0x%08x, /* version */\n", n->version));
+ D(printk(" 0x%08x, /* data_offset */\n", n->data_offset));
+ D(printk(" 0x%08x, /* data_size */\n", n->data_size));
+ D(printk(" 0x%08x, /* removed_size */\n", n->removed_size));
+ D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset));
+ D(printk(" 0x%02x, /* name_size */\n", n->name_size));
+ D(printk(" 0x%p, /* fm, fm->offset: %u */\n",
+ n->fm, (n->fm ? n->fm->offset : 0)));
+ D(printk(" 0x%p, /* version_prev */\n", n->version_prev));
+ D(printk(" 0x%p, /* version_next */\n", n->version_next));
+ D(printk(" 0x%p, /* range_prev */\n", n->range_prev));
+ D(printk(" 0x%p, /* range_next */\n", n->range_next));
+ D(printk("}\n"));
+}
+
#endif
+/* Print the contents of a raw inode. */
+static void
+jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
+{
+ D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino));
+ D(printk("{\n"));
+ D(printk(" 0x%08x, /* magic */\n", raw_inode->magic));
+ D(printk(" 0x%08x, /* ino */\n", raw_inode->ino));
+ D(printk(" 0x%08x, /* pino */\n", raw_inode->pino));
+ D(printk(" 0x%08x, /* version */\n", raw_inode->version));
+ D(printk(" 0x%08x, /* mode */\n", raw_inode->mode));
+ D(printk(" 0x%04x, /* uid */\n", raw_inode->uid));
+ D(printk(" 0x%04x, /* gid */\n", raw_inode->gid));
+ D(printk(" 0x%08x, /* atime */\n", raw_inode->atime));
+ D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime));
+ D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime));
+ D(printk(" 0x%08x, /* offset */\n", raw_inode->offset));
+ D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize));
+ D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize));
+ D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize));
+ D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink));
+ D(printk(" 0x%02x, /* spare */\n",
+ raw_inode->spare));
+ D(printk(" %u, /* rename */\n",
+ raw_inode->rename));
+ D(printk(" %u, /* deleted */\n",
+ raw_inode->deleted));
+ D(printk(" 0x%02x, /* accurate */\n",
+ raw_inode->accurate));
+ D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum));
+ D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum));
+ D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum));
+ D(printk("}\n"));
+}
+
#define flash_safe_acquire(arg)
#define flash_safe_release(arg)
@@ -2507,64 +2563,6 @@ jffs_update_file(struct jffs_file *f, struct jffs_node *node)
return 0;
}
-/* Print the contents of a node. */
-void
-jffs_print_node(struct jffs_node *n)
-{
- D(printk("jffs_node: 0x%p\n", n));
- D(printk("{\n"));
- D(printk(" 0x%08x, /* version */\n", n->version));
- D(printk(" 0x%08x, /* data_offset */\n", n->data_offset));
- D(printk(" 0x%08x, /* data_size */\n", n->data_size));
- D(printk(" 0x%08x, /* removed_size */\n", n->removed_size));
- D(printk(" 0x%08x, /* fm_offset */\n", n->fm_offset));
- D(printk(" 0x%02x, /* name_size */\n", n->name_size));
- D(printk(" 0x%p, /* fm, fm->offset: %u */\n",
- n->fm, (n->fm ? n->fm->offset : 0)));
- D(printk(" 0x%p, /* version_prev */\n", n->version_prev));
- D(printk(" 0x%p, /* version_next */\n", n->version_next));
- D(printk(" 0x%p, /* range_prev */\n", n->range_prev));
- D(printk(" 0x%p, /* range_next */\n", n->range_next));
- D(printk("}\n"));
-}
-
-
-/* Print the contents of a raw inode. */
-void
-jffs_print_raw_inode(struct jffs_raw_inode *raw_inode)
-{
- D(printk("jffs_raw_inode: inode number: %u\n", raw_inode->ino));
- D(printk("{\n"));
- D(printk(" 0x%08x, /* magic */\n", raw_inode->magic));
- D(printk(" 0x%08x, /* ino */\n", raw_inode->ino));
- D(printk(" 0x%08x, /* pino */\n", raw_inode->pino));
- D(printk(" 0x%08x, /* version */\n", raw_inode->version));
- D(printk(" 0x%08x, /* mode */\n", raw_inode->mode));
- D(printk(" 0x%04x, /* uid */\n", raw_inode->uid));
- D(printk(" 0x%04x, /* gid */\n", raw_inode->gid));
- D(printk(" 0x%08x, /* atime */\n", raw_inode->atime));
- D(printk(" 0x%08x, /* mtime */\n", raw_inode->mtime));
- D(printk(" 0x%08x, /* ctime */\n", raw_inode->ctime));
- D(printk(" 0x%08x, /* offset */\n", raw_inode->offset));
- D(printk(" 0x%08x, /* dsize */\n", raw_inode->dsize));
- D(printk(" 0x%08x, /* rsize */\n", raw_inode->rsize));
- D(printk(" 0x%02x, /* nsize */\n", raw_inode->nsize));
- D(printk(" 0x%02x, /* nlink */\n", raw_inode->nlink));
- D(printk(" 0x%02x, /* spare */\n",
- raw_inode->spare));
- D(printk(" %u, /* rename */\n",
- raw_inode->rename));
- D(printk(" %u, /* deleted */\n",
- raw_inode->deleted));
- D(printk(" 0x%02x, /* accurate */\n",
- raw_inode->accurate));
- D(printk(" 0x%08x, /* dchksum */\n", raw_inode->dchksum));
- D(printk(" 0x%04x, /* nchksum */\n", raw_inode->nchksum));
- D(printk(" 0x%04x, /* chksum */\n", raw_inode->chksum));
- D(printk("}\n"));
-}
-
-
/* Print the contents of a file. */
#if 0
int
diff --git a/fs/jffs/intrep.h b/fs/jffs/intrep.h
index 4ae97b17911c..5c7abe0e2695 100644
--- a/fs/jffs/intrep.h
+++ b/fs/jffs/intrep.h
@@ -49,8 +49,6 @@ int jffs_garbage_collect_thread(void *c);
void jffs_garbage_collect_trigger(struct jffs_control *c);
/* For debugging purposes. */
-void jffs_print_node(struct jffs_node *n);
-void jffs_print_raw_inode(struct jffs_raw_inode *raw_inode);
#if 0
int jffs_print_file(struct jffs_file *f);
#endif /* 0 */
diff --git a/fs/jffs/jffs_fm.c b/fs/jffs/jffs_fm.c
index 0cab8da49d3c..053e3a98a276 100644
--- a/fs/jffs/jffs_fm.c
+++ b/fs/jffs/jffs_fm.c
@@ -31,6 +31,60 @@ static void jffs_free_fm(struct jffs_fm *n);
extern kmem_cache_t *fm_cache;
extern kmem_cache_t *node_cache;
+#if CONFIG_JFFS_FS_VERBOSE > 0
+void
+jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
+{
+ D(printk("struct jffs_fmcontrol: 0x%p\n", fmc));
+ D(printk("{\n"));
+ D(printk(" %u, /* flash_size */\n", fmc->flash_size));
+ D(printk(" %u, /* used_size */\n", fmc->used_size));
+ D(printk(" %u, /* dirty_size */\n", fmc->dirty_size));
+ D(printk(" %u, /* free_size */\n", fmc->free_size));
+ D(printk(" %u, /* sector_size */\n", fmc->sector_size));
+ D(printk(" %u, /* min_free_size */\n", fmc->min_free_size));
+ D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size));
+ D(printk(" 0x%p, /* mtd */\n", fmc->mtd));
+ D(printk(" 0x%p, /* head */ "
+ "(head->offset = 0x%08x)\n",
+ fmc->head, (fmc->head ? fmc->head->offset : 0)));
+ D(printk(" 0x%p, /* tail */ "
+ "(tail->offset + tail->size = 0x%08x)\n",
+ fmc->tail,
+ (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0)));
+ D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra));
+ D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra));
+ D(printk("}\n"));
+}
+#endif /* CONFIG_JFFS_FS_VERBOSE > 0 */
+
+#if CONFIG_JFFS_FS_VERBOSE > 2
+static void
+jffs_print_fm(struct jffs_fm *fm)
+{
+ D(printk("struct jffs_fm: 0x%p\n", fm));
+ D(printk("{\n"));
+ D(printk(" 0x%08x, /* offset */\n", fm->offset));
+ D(printk(" %u, /* size */\n", fm->size));
+ D(printk(" 0x%p, /* prev */\n", fm->prev));
+ D(printk(" 0x%p, /* next */\n", fm->next));
+ D(printk(" 0x%p, /* nodes */\n", fm->nodes));
+ D(printk("}\n"));
+}
+#endif /* CONFIG_JFFS_FS_VERBOSE > 2 */
+
+#if 0
+void
+jffs_print_node_ref(struct jffs_node_ref *ref)
+{
+ D(printk("struct jffs_node_ref: 0x%p\n", ref));
+ D(printk("{\n"));
+ D(printk(" 0x%p, /* node */\n", ref->node));
+ D(printk(" 0x%p, /* next */\n", ref->next));
+ D(printk("}\n"));
+}
+#endif /* 0 */
+
/* This function creates a new shiny flash memory control structure. */
struct jffs_fmcontrol *
jffs_build_begin(struct jffs_control *c, int unit)
@@ -742,54 +796,3 @@ int jffs_get_node_inuse(void)
{
return no_jffs_node;
}
-
-void
-jffs_print_fmcontrol(struct jffs_fmcontrol *fmc)
-{
- D(printk("struct jffs_fmcontrol: 0x%p\n", fmc));
- D(printk("{\n"));
- D(printk(" %u, /* flash_size */\n", fmc->flash_size));
- D(printk(" %u, /* used_size */\n", fmc->used_size));
- D(printk(" %u, /* dirty_size */\n", fmc->dirty_size));
- D(printk(" %u, /* free_size */\n", fmc->free_size));
- D(printk(" %u, /* sector_size */\n", fmc->sector_size));
- D(printk(" %u, /* min_free_size */\n", fmc->min_free_size));
- D(printk(" %u, /* max_chunk_size */\n", fmc->max_chunk_size));
- D(printk(" 0x%p, /* mtd */\n", fmc->mtd));
- D(printk(" 0x%p, /* head */ "
- "(head->offset = 0x%08x)\n",
- fmc->head, (fmc->head ? fmc->head->offset : 0)));
- D(printk(" 0x%p, /* tail */ "
- "(tail->offset + tail->size = 0x%08x)\n",
- fmc->tail,
- (fmc->tail ? fmc->tail->offset + fmc->tail->size : 0)));
- D(printk(" 0x%p, /* head_extra */\n", fmc->head_extra));
- D(printk(" 0x%p, /* tail_extra */\n", fmc->tail_extra));
- D(printk("}\n"));
-}
-
-void
-jffs_print_fm(struct jffs_fm *fm)
-{
- D(printk("struct jffs_fm: 0x%p\n", fm));
- D(printk("{\n"));
- D(printk(" 0x%08x, /* offset */\n", fm->offset));
- D(printk(" %u, /* size */\n", fm->size));
- D(printk(" 0x%p, /* prev */\n", fm->prev));
- D(printk(" 0x%p, /* next */\n", fm->next));
- D(printk(" 0x%p, /* nodes */\n", fm->nodes));
- D(printk("}\n"));
-}
-
-#if 0
-void
-jffs_print_node_ref(struct jffs_node_ref *ref)
-{
- D(printk("struct jffs_node_ref: 0x%p\n", ref));
- D(printk("{\n"));
- D(printk(" 0x%p, /* node */\n", ref->node));
- D(printk(" 0x%p, /* next */\n", ref->next));
- D(printk("}\n"));
-}
-#endif /* 0 */
-
diff --git a/fs/jffs/jffs_fm.h b/fs/jffs/jffs_fm.h
index bc291c431822..f64151e74122 100644
--- a/fs/jffs/jffs_fm.h
+++ b/fs/jffs/jffs_fm.h
@@ -139,8 +139,9 @@ int jffs_add_node(struct jffs_node *node);
void jffs_fmfree_partly(struct jffs_fmcontrol *fmc, struct jffs_fm *fm,
__u32 size);
+#if CONFIG_JFFS_FS_VERBOSE > 0
void jffs_print_fmcontrol(struct jffs_fmcontrol *fmc);
-void jffs_print_fm(struct jffs_fm *fm);
+#endif
#if 0
void jffs_print_node_ref(struct jffs_node_ref *ref);
#endif /* 0 */
diff --git a/fs/jffs2/Makefile b/fs/jffs2/Makefile
index e3c38ccf9c7d..f1afe681ecd6 100644
--- a/fs/jffs2/Makefile
+++ b/fs/jffs2/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the Linux Journalling Flash File System v2 (JFFS2)
#
-# $Id: Makefile.common,v 1.7 2004/11/03 12:57:38 jwboyer Exp $
+# $Id: Makefile.common,v 1.9 2005/02/09 09:23:53 pavlov Exp $
#
obj-$(CONFIG_JFFS2_FS) += jffs2.o
@@ -11,8 +11,7 @@ jffs2-y += read.o nodemgmt.o readinode.o write.o scan.o gc.o
jffs2-y += symlink.o build.o erase.o background.o fs.o writev.o
jffs2-y += super.o
-jffs2-$(CONFIG_JFFS2_FS_NAND) += wbuf.o
-jffs2-$(CONFIG_JFFS2_FS_NOR_ECC) += wbuf.o
+jffs2-$(CONFIG_JFFS2_FS_WRITEBUFFER) += wbuf.o
jffs2-$(CONFIG_JFFS2_RUBIN) += compr_rubin.o
jffs2-$(CONFIG_JFFS2_RTIME) += compr_rtime.o
jffs2-$(CONFIG_JFFS2_ZLIB) += compr_zlib.o
diff --git a/fs/jffs2/README.Locking b/fs/jffs2/README.Locking
index 49771cf8513a..b7943439b6ec 100644
--- a/fs/jffs2/README.Locking
+++ b/fs/jffs2/README.Locking
@@ -1,4 +1,4 @@
- $Id: README.Locking,v 1.9 2004/11/20 10:35:40 dwmw2 Exp $
+ $Id: README.Locking,v 1.12 2005/04/13 13:22:35 dwmw2 Exp $
JFFS2 LOCKING DOCUMENTATION
---------------------------
@@ -108,6 +108,10 @@ in-core jffs2_inode_cache objects (each inode in JFFS2 has the
correspondent jffs2_inode_cache object). So, the inocache_lock
has to be locked while walking the c->inocache_list hash buckets.
+This spinlock also covers allocation of new inode numbers, which is
+currently just '++->highest_ino++', but might one day get more complicated
+if we need to deal with wrapping after 4 milliard inode numbers are used.
+
Note, the f->sem guarantees that the correspondent jffs2_inode_cache
will not be removed. So, it is allowed to access it without locking
the inocache_lock spinlock.
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 1be6de27dd81..0f224384f176 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: background.c,v 1.50 2004/11/16 20:36:10 dwmw2 Exp $
+ * $Id: background.c,v 1.54 2005/05/20 21:37:12 gleixner Exp $
*
*/
@@ -37,7 +37,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
if (c->gc_task)
BUG();
- init_MUTEX_LOCKED(&c->gc_thread_start);
+ init_completion(&c->gc_thread_start);
init_completion(&c->gc_thread_exit);
pid = kernel_thread(jffs2_garbage_collect_thread, c, CLONE_FS|CLONE_FILES);
@@ -48,7 +48,7 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
} else {
/* Wait for it... */
D1(printk(KERN_DEBUG "JFFS2: Garbage collect thread is pid %d\n", pid));
- down(&c->gc_thread_start);
+ wait_for_completion(&c->gc_thread_start);
}
return ret;
@@ -56,13 +56,16 @@ int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
{
+ int wait = 0;
spin_lock(&c->erase_completion_lock);
if (c->gc_task) {
D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid));
send_sig(SIGKILL, c->gc_task, 1);
+ wait = 1;
}
spin_unlock(&c->erase_completion_lock);
- wait_for_completion(&c->gc_thread_exit);
+ if (wait)
+ wait_for_completion(&c->gc_thread_exit);
}
static int jffs2_garbage_collect_thread(void *_c)
@@ -75,7 +78,7 @@ static int jffs2_garbage_collect_thread(void *_c)
allow_signal(SIGCONT);
c->gc_task = current;
- up(&c->gc_thread_start);
+ complete(&c->gc_thread_start);
set_user_nice(current, 10);
@@ -92,7 +95,7 @@ static int jffs2_garbage_collect_thread(void *_c)
schedule();
}
- if (try_to_freeze(0))
+ if (try_to_freeze())
continue;
cond_resched();
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
index a01dd5fdbb95..3dd5394921c9 100644
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: build.c,v 1.69 2004/12/16 20:22:18 dmarlin Exp $
+ * $Id: build.c,v 1.70 2005/02/28 08:21:05 dedekind Exp $
*
*/
@@ -97,14 +97,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
/* First, scan the medium and build all the inode caches with
lists of physical nodes */
- c->flags |= JFFS2_SB_FLAG_MOUNTING;
+ c->flags |= JFFS2_SB_FLAG_SCANNING;
ret = jffs2_scan_medium(c);
+ c->flags &= ~JFFS2_SB_FLAG_SCANNING;
if (ret)
goto exit;
D1(printk(KERN_DEBUG "Scanned flash completely\n"));
D2(jffs2_dump_block_lists(c));
+ c->flags |= JFFS2_SB_FLAG_BUILDING;
/* Now scan the directory tree, increasing nlink according to every dirent found. */
for_each_inode(i, c, ic) {
D1(printk(KERN_DEBUG "Pass 1: ino #%u\n", ic->ino));
@@ -116,7 +118,6 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
cond_resched();
}
}
- c->flags &= ~JFFS2_SB_FLAG_MOUNTING;
D1(printk(KERN_DEBUG "Pass 1 complete\n"));
@@ -164,6 +165,8 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
ic->scan_dents = NULL;
cond_resched();
}
+ c->flags &= ~JFFS2_SB_FLAG_BUILDING;
+
D1(printk(KERN_DEBUG "Pass 3 complete\n"));
D2(jffs2_dump_block_lists(c));
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c
index 078a30e406b5..83f7e0788fd0 100644
--- a/fs/jffs2/compr_zlib.c
+++ b/fs/jffs2/compr_zlib.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: compr_zlib.c,v 1.29 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: compr_zlib.c,v 1.31 2005/05/20 19:30:06 gleixner Exp $
*
*/
@@ -17,10 +17,10 @@
#include <linux/config.h>
#include <linux/kernel.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/zlib.h>
#include <linux/zutil.h>
-#include <asm/semaphore.h>
#include "nodelist.h"
#include "compr.h"
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 757306fa3ff4..3ca0d25eef1d 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: dir.c,v 1.84 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: dir.c,v 1.86 2005/07/06 12:13:09 dwmw2 Exp $
*
*/
@@ -22,16 +22,6 @@
#include <linux/time.h>
#include "nodelist.h"
-/* Urgh. Please tell me there's a nicer way of doing these. */
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
-typedef int mknod_arg_t;
-#define NAMEI_COMPAT(x) ((void *)x)
-#else
-typedef dev_t mknod_arg_t;
-#define NAMEI_COMPAT(x) (x)
-#endif
-
static int jffs2_readdir (struct file *, void *, filldir_t);
static int jffs2_create (struct inode *,struct dentry *,int,
@@ -43,7 +33,7 @@ static int jffs2_unlink (struct inode *,struct dentry *);
static int jffs2_symlink (struct inode *,struct dentry *,const char *);
static int jffs2_mkdir (struct inode *,struct dentry *,int);
static int jffs2_rmdir (struct inode *,struct dentry *);
-static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t);
+static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t);
static int jffs2_rename (struct inode *, struct dentry *,
struct inode *, struct dentry *);
@@ -58,8 +48,8 @@ struct file_operations jffs2_dir_operations =
struct inode_operations jffs2_dir_inode_operations =
{
- .create = NAMEI_COMPAT(jffs2_create),
- .lookup = NAMEI_COMPAT(jffs2_lookup),
+ .create = jffs2_create,
+ .lookup = jffs2_lookup,
.link = jffs2_link,
.unlink = jffs2_unlink,
.symlink = jffs2_symlink,
@@ -296,11 +286,11 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
struct jffs2_full_dirent *fd;
int namelen;
uint32_t alloclen, phys_ofs;
- int ret;
+ int ret, targetlen = strlen(target);
/* FIXME: If you care. We'd need to use frags for the target
if it grows much more than this */
- if (strlen(target) > 254)
+ if (targetlen > 254)
return -EINVAL;
ri = jffs2_alloc_raw_inode();
@@ -314,7 +304,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
* Just the node will do for now, though
*/
namelen = dentry->d_name.len;
- ret = jffs2_reserve_space(c, sizeof(*ri) + strlen(target), &phys_ofs, &alloclen, ALLOC_NORMAL);
+ ret = jffs2_reserve_space(c, sizeof(*ri) + targetlen, &phys_ofs, &alloclen, ALLOC_NORMAL);
if (ret) {
jffs2_free_raw_inode(ri);
@@ -333,16 +323,16 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
f = JFFS2_INODE_INFO(inode);
- inode->i_size = strlen(target);
+ inode->i_size = targetlen;
ri->isize = ri->dsize = ri->csize = cpu_to_je32(inode->i_size);
ri->totlen = cpu_to_je32(sizeof(*ri) + inode->i_size);
ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4));
ri->compr = JFFS2_COMPR_NONE;
- ri->data_crc = cpu_to_je32(crc32(0, target, strlen(target)));
+ ri->data_crc = cpu_to_je32(crc32(0, target, targetlen));
ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
- fn = jffs2_write_dnode(c, f, ri, target, strlen(target), phys_ofs, ALLOC_NORMAL);
+ fn = jffs2_write_dnode(c, f, ri, target, targetlen, phys_ofs, ALLOC_NORMAL);
jffs2_free_raw_inode(ri);
@@ -353,6 +343,20 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
jffs2_clear_inode(inode);
return PTR_ERR(fn);
}
+
+ /* We use f->dents field to store the target path. */
+ f->dents = kmalloc(targetlen + 1, GFP_KERNEL);
+ if (!f->dents) {
+ printk(KERN_WARNING "Can't allocate %d bytes of memory\n", targetlen + 1);
+ up(&f->sem);
+ jffs2_complete_reservation(c);
+ jffs2_clear_inode(inode);
+ return -ENOMEM;
+ }
+
+ memcpy(f->dents, target, targetlen + 1);
+ D1(printk(KERN_DEBUG "jffs2_symlink: symlink's target '%s' cached\n", (char *)f->dents));
+
/* No data here. Only a metadata node, which will be
obsoleted by the first data write
*/
@@ -564,7 +568,7 @@ static int jffs2_rmdir (struct inode *dir_i, struct dentry *dentry)
return ret;
}
-static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev)
+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev)
{
struct jffs2_inode_info *f, *dir_f;
struct jffs2_sb_info *c;
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c
index 41451e8bf361..6a4c0a3685da 100644
--- a/fs/jffs2/erase.c
+++ b/fs/jffs2/erase.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: erase.c,v 1.66 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $
*
*/
@@ -48,6 +48,7 @@ static void jffs2_erase_block(struct jffs2_sb_info *c,
#else /* Linux */
struct erase_info *instr;
+ D1(printk(KERN_DEBUG "jffs2_erase_block(): erase block %#x (range %#x-%#x)\n", jeb->offset, jeb->offset, jeb->offset + c->sector_size));
instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL);
if (!instr) {
printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n");
@@ -233,7 +234,7 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
continue;
}
- if (((*prev)->flash_offset & ~(c->sector_size -1)) == jeb->offset) {
+ if (SECTOR_ADDR((*prev)->flash_offset) == jeb->offset) {
/* It's in the block we're erasing */
struct jffs2_raw_node_ref *this;
@@ -277,11 +278,8 @@ static inline void jffs2_remove_node_refs_from_ino_list(struct jffs2_sb_info *c,
printk("\n");
});
- if (ic->nodes == (void *)ic) {
- D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+ if (ic->nodes == (void *)ic && ic->nlink == 0)
jffs2_del_ino_cache(c, ic);
- jffs2_free_inode_cache(ic);
- }
}
static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
@@ -310,7 +308,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
int ret;
uint32_t bad_offset;
- if (!jffs2_cleanmarker_oob(c)) {
+ if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
marker_ref = jffs2_alloc_raw_node_ref();
if (!marker_ref) {
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
@@ -335,7 +333,8 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
bad_offset = ofs;
- ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
+ ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
+
if (ret) {
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
goto bad;
@@ -351,7 +350,7 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
bad_offset += i;
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
bad:
- if (!jffs2_cleanmarker_oob(c))
+ if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
jffs2_free_raw_node_ref(marker_ref);
kfree(ebuf);
bad2:
@@ -387,6 +386,13 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
jeb->used_size = 0;
jeb->dirty_size = 0;
jeb->wasted_size = 0;
+ } else if (c->cleanmarker_size == 0) {
+ jeb->first_node = jeb->last_node = NULL;
+
+ jeb->free_size = c->sector_size;
+ jeb->used_size = 0;
+ jeb->dirty_size = 0;
+ jeb->wasted_size = 0;
} else {
struct kvec vecs[1];
struct jffs2_unknown_node marker = {
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 771a554701d6..bd9ed9b0247b 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -7,11 +7,10 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: file.c,v 1.99 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: file.c,v 1.102 2005/07/06 12:13:09 dwmw2 Exp $
*
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/fs.h>
@@ -51,9 +50,7 @@ struct file_operations jffs2_file_operations =
.ioctl = jffs2_ioctl,
.mmap = generic_file_readonly_mmap,
.fsync = jffs2_fsync,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,29)
.sendfile = generic_file_sendfile
-#endif
};
/* jffs2_file_inode_operations */
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c
index 30ab233fe423..5687c3f42002 100644
--- a/fs/jffs2/fs.c
+++ b/fs/jffs2/fs.c
@@ -7,11 +7,10 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: fs.c,v 1.51 2004/11/28 12:19:37 dedekind Exp $
+ * $Id: fs.c,v 1.56 2005/07/06 12:13:09 dwmw2 Exp $
*
*/
-#include <linux/version.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -450,11 +449,15 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
c = JFFS2_SB_INFO(sb);
-#ifndef CONFIG_JFFS2_FS_NAND
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
if (c->mtd->type == MTD_NANDFLASH) {
printk(KERN_ERR "jffs2: Cannot operate on NAND flash unless jffs2 NAND support is compiled in.\n");
return -EINVAL;
}
+ if (c->mtd->type == MTD_DATAFLASH) {
+ printk(KERN_ERR "jffs2: Cannot operate on DataFlash unless jffs2 DataFlash support is compiled in.\n");
+ return -EINVAL;
+ }
#endif
c->flash_size = c->mtd->size;
@@ -522,9 +525,7 @@ int jffs2_do_fill_super(struct super_block *sb, void *data, int silent)
if (!sb->s_root)
goto out_root_i;
-#if LINUX_VERSION_CODE >= 0x20403
sb->s_maxbytes = 0xFFFFFFFF;
-#endif
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = JFFS2_SUPER_MAGIC;
@@ -661,6 +662,14 @@ static int jffs2_flash_setup(struct jffs2_sb_info *c) {
if (ret)
return ret;
}
+
+ /* and Dataflash */
+ if (jffs2_dataflash(c)) {
+ ret = jffs2_dataflash_setup(c);
+ if (ret)
+ return ret;
+ }
+
return ret;
}
@@ -674,4 +683,9 @@ void jffs2_flash_cleanup(struct jffs2_sb_info *c) {
if (jffs2_nor_ecc(c)) {
jffs2_nor_ecc_flash_cleanup(c);
}
+
+ /* and DataFlash */
+ if (jffs2_dataflash(c)) {
+ jffs2_dataflash_cleanup(c);
+ }
}
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c
index 87ec74ff5930..7086cd634503 100644
--- a/fs/jffs2/gc.c
+++ b/fs/jffs2/gc.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: gc.c,v 1.144 2004/12/21 11:18:50 dwmw2 Exp $
+ * $Id: gc.c,v 1.148 2005/04/09 10:47:00 dedekind Exp $
*
*/
@@ -50,6 +50,7 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
put the clever wear-levelling algorithms. Eventually. */
/* We possibly want to favour the dirtier blocks more when the
number of free blocks is low. */
+again:
if (!list_empty(&c->bad_used_list) && c->nr_free_blocks > c->resv_blocks_gcbad) {
D1(printk(KERN_DEBUG "Picking block from bad_used_list to GC next\n"));
nextlist = &c->bad_used_list;
@@ -79,6 +80,13 @@ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c)
D1(printk(KERN_DEBUG "Picking block from erasable_list to GC next (clean_list and {very_,}dirty_list were empty)\n"));
nextlist = &c->erasable_list;
+ } else if (!list_empty(&c->erasable_pending_wbuf_list)) {
+ /* There are blocks are wating for the wbuf sync */
+ D1(printk(KERN_DEBUG "Synching wbuf in order to reuse erasable_pending_wbuf_list blocks\n"));
+ spin_unlock(&c->erase_completion_lock);
+ jffs2_flush_wbuf_pad(c);
+ spin_lock(&c->erase_completion_lock);
+ goto again;
} else {
/* Eep. All were empty */
D1(printk(KERN_NOTICE "jffs2: No clean, dirty _or_ erasable blocks to GC from! Where are they all?\n"));
@@ -661,9 +669,10 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
{
struct jffs2_full_dnode *new_fn;
struct jffs2_raw_inode ri;
+ struct jffs2_node_frag *last_frag;
jint16_t dev;
char *mdata = NULL, mdatalen = 0;
- uint32_t alloclen, phys_ofs;
+ uint32_t alloclen, phys_ofs, ilen;
int ret;
if (S_ISBLK(JFFS2_F_I_MODE(f)) ||
@@ -699,6 +708,14 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
goto out;
}
+ last_frag = frag_last(&f->fragtree);
+ if (last_frag)
+ /* Fetch the inode length from the fragtree rather then
+ * from i_size since i_size may have not been updated yet */
+ ilen = last_frag->ofs + last_frag->size;
+ else
+ ilen = JFFS2_F_I_SIZE(f);
+
memset(&ri, 0, sizeof(ri));
ri.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri.nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -710,7 +727,7 @@ static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_
ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
- ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
+ ri.isize = cpu_to_je32(ilen);
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
@@ -816,8 +833,7 @@ static int jffs2_garbage_collect_deletion_dirent(struct jffs2_sb_info *c, struct
/* Doesn't matter if there's one in the same erase block. We're going to
delete it too at the same time. */
- if ((raw->flash_offset & ~(c->sector_size-1)) ==
- (fd->raw->flash_offset & ~(c->sector_size-1)))
+ if (SECTOR_ADDR(raw->flash_offset) == SECTOR_ADDR(fd->raw->flash_offset))
continue;
D1(printk(KERN_DEBUG "Check potential deletion dirent at %08x\n", ref_offset(raw)));
@@ -891,7 +907,7 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
struct jffs2_raw_inode ri;
struct jffs2_node_frag *frag;
struct jffs2_full_dnode *new_fn;
- uint32_t alloclen, phys_ofs;
+ uint32_t alloclen, phys_ofs, ilen;
int ret;
D1(printk(KERN_DEBUG "Writing replacement hole node for ino #%u from offset 0x%x to 0x%x\n",
@@ -951,10 +967,19 @@ static int jffs2_garbage_collect_hole(struct jffs2_sb_info *c, struct jffs2_eras
ri.csize = cpu_to_je32(0);
ri.compr = JFFS2_COMPR_ZERO;
}
+
+ frag = frag_last(&f->fragtree);
+ if (frag)
+ /* Fetch the inode length from the fragtree rather then
+ * from i_size since i_size may have not been updated yet */
+ ilen = frag->ofs + frag->size;
+ else
+ ilen = JFFS2_F_I_SIZE(f);
+
ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f));
ri.uid = cpu_to_je16(JFFS2_F_I_UID(f));
ri.gid = cpu_to_je16(JFFS2_F_I_GID(f));
- ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f));
+ ri.isize = cpu_to_je32(ilen);
ri.atime = cpu_to_je32(JFFS2_F_I_ATIME(f));
ri.ctime = cpu_to_je32(JFFS2_F_I_CTIME(f));
ri.mtime = cpu_to_je32(JFFS2_F_I_MTIME(f));
@@ -1161,7 +1186,7 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_era
D1(printk(KERN_DEBUG "Expanded dnode to write from (0x%x-0x%x) to (0x%x-0x%x)\n",
orig_start, orig_end, start, end));
- BUG_ON(end > JFFS2_F_I_SIZE(f));
+ D1(BUG_ON(end > frag_last(&f->fragtree)->ofs + frag_last(&f->fragtree)->size));
BUG_ON(end < orig_end);
BUG_ON(start > orig_start);
}
diff --git a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c
index cd6a8bd13e0b..c7bbdeec93a6 100644
--- a/fs/jffs2/nodelist.c
+++ b/fs/jffs2/nodelist.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.c,v 1.90 2004/12/08 17:59:20 dwmw2 Exp $
+ * $Id: nodelist.c,v 1.97 2005/07/06 15:18:41 dwmw2 Exp $
*
*/
@@ -58,27 +58,60 @@ void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new
/* Put a new tmp_dnode_info into the list, keeping the list in
order of increasing version
*/
-static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct jffs2_tmp_dnode_info **list)
+
+static void jffs2_add_tn_to_list(struct jffs2_tmp_dnode_info *tn, struct rb_root *list)
{
- struct jffs2_tmp_dnode_info **prev = list;
-
- while ((*prev) && (*prev)->version < tn->version) {
- prev = &((*prev)->next);
- }
- tn->next = (*prev);
- *prev = tn;
+ struct rb_node **p = &list->rb_node;
+ struct rb_node * parent = NULL;
+ struct jffs2_tmp_dnode_info *this;
+
+ while (*p) {
+ parent = *p;
+ this = rb_entry(parent, struct jffs2_tmp_dnode_info, rb);
+
+ /* There may actually be a collision here, but it doesn't
+ actually matter. As long as the two nodes with the same
+ version are together, it's all fine. */
+ if (tn->version < this->version)
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ rb_link_node(&tn->rb, parent, p);
+ rb_insert_color(&tn->rb, list);
}
-static void jffs2_free_tmp_dnode_info_list(struct jffs2_tmp_dnode_info *tn)
+static void jffs2_free_tmp_dnode_info_list(struct rb_root *list)
{
- struct jffs2_tmp_dnode_info *next;
+ struct rb_node *this;
+ struct jffs2_tmp_dnode_info *tn;
+
+ this = list->rb_node;
+
+ /* Now at bottom of tree */
+ while (this) {
+ if (this->rb_left)
+ this = this->rb_left;
+ else if (this->rb_right)
+ this = this->rb_right;
+ else {
+ tn = rb_entry(this, struct jffs2_tmp_dnode_info, rb);
+ jffs2_free_full_dnode(tn->fn);
+ jffs2_free_tmp_dnode_info(tn);
+
+ this = this->rb_parent;
+ if (!this)
+ break;
- while (tn) {
- next = tn;
- tn = tn->next;
- jffs2_free_full_dnode(next->fn);
- jffs2_free_tmp_dnode_info(next);
+ if (this->rb_left == &tn->rb)
+ this->rb_left = NULL;
+ else if (this->rb_right == &tn->rb)
+ this->rb_right = NULL;
+ else BUG();
+ }
}
+ list->rb_node = NULL;
}
static void jffs2_free_full_dirent_list(struct jffs2_full_dirent *fd)
@@ -108,12 +141,13 @@ static struct jffs2_raw_node_ref *jffs2_first_valid_node(struct jffs2_raw_node_r
with this ino, returning the former in order of version */
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
+ struct rb_root *tnp, struct jffs2_full_dirent **fdp,
uint32_t *highest_version, uint32_t *latest_mctime,
uint32_t *mctime_ver)
{
struct jffs2_raw_node_ref *ref, *valid_ref;
- struct jffs2_tmp_dnode_info *tn, *ret_tn = NULL;
+ struct jffs2_tmp_dnode_info *tn;
+ struct rb_root ret_tn = RB_ROOT;
struct jffs2_full_dirent *fd, *ret_fd = NULL;
union jffs2_node_union node;
size_t retlen;
@@ -127,7 +161,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
valid_ref = jffs2_first_valid_node(f->inocache->nodes);
- if (!valid_ref)
+ if (!valid_ref && (f->inocache->ino != 1))
printk(KERN_WARNING "Eep. No valid nodes for ino #%u\n", f->inocache->ino);
while (valid_ref) {
@@ -450,7 +484,7 @@ int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
return 0;
free_out:
- jffs2_free_tmp_dnode_info_list(ret_tn);
+ jffs2_free_tmp_dnode_info_list(&ret_tn);
jffs2_free_full_dirent_list(ret_fd);
return err;
}
@@ -489,9 +523,13 @@ struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t
void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new)
{
struct jffs2_inode_cache **prev;
- D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+
spin_lock(&c->inocache_lock);
-
+ if (!new->ino)
+ new->ino = ++c->highest_ino;
+
+ D2(printk(KERN_DEBUG "jffs2_add_ino_cache: Add %p (ino #%u)\n", new, new->ino));
+
prev = &c->inocache_list[new->ino % INOCACHE_HASHSIZE];
while ((*prev) && (*prev)->ino < new->ino) {
@@ -506,7 +544,7 @@ void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new
void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
{
struct jffs2_inode_cache **prev;
- D2(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
+ D1(printk(KERN_DEBUG "jffs2_del_ino_cache: Del %p (ino #%u)\n", old, old->ino));
spin_lock(&c->inocache_lock);
prev = &c->inocache_list[old->ino % INOCACHE_HASHSIZE];
@@ -518,6 +556,14 @@ void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old)
*prev = old->next;
}
+ /* Free it now unless it's in READING or CLEARING state, which
+ are the transitions upon read_inode() and clear_inode(). The
+ rest of the time we know nobody else is looking at it, and
+ if it's held by read_inode() or clear_inode() they'll free it
+ for themselves. */
+ if (old->state != INO_STATE_READING && old->state != INO_STATE_CLEARING)
+ jffs2_free_inode_cache(old);
+
spin_unlock(&c->inocache_lock);
}
@@ -530,7 +576,6 @@ void jffs2_free_ino_caches(struct jffs2_sb_info *c)
this = c->inocache_list[i];
while (this) {
next = this->next;
- D2(printk(KERN_DEBUG "jffs2_free_ino_caches: Freeing ino #%u at %p\n", this->ino, this));
jffs2_free_inode_cache(this);
this = next;
}
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h
index a4864d05ea92..b34c397909ef 100644
--- a/fs/jffs2/nodelist.h
+++ b/fs/jffs2/nodelist.h
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodelist.h,v 1.126 2004/11/19 15:06:29 dedekind Exp $
+ * $Id: nodelist.h,v 1.131 2005/07/05 21:03:07 dwmw2 Exp $
*
*/
@@ -135,6 +135,7 @@ struct jffs2_inode_cache {
#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */
#define INO_STATE_GC 4 /* GCing a 'pristine' node */
#define INO_STATE_READING 5 /* In read_inode() */
+#define INO_STATE_CLEARING 6 /* In clear_inode() */
#define INOCACHE_HASHSIZE 128
@@ -160,7 +161,7 @@ struct jffs2_full_dnode
*/
struct jffs2_tmp_dnode_info
{
- struct jffs2_tmp_dnode_info *next;
+ struct rb_node rb;
struct jffs2_full_dnode *fn;
uint32_t version;
};
@@ -362,6 +363,18 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
node = node->rb_left;
return rb_entry(node, struct jffs2_node_frag, rb);
}
+
+static inline struct jffs2_node_frag *frag_last(struct rb_root *root)
+{
+ struct rb_node *node = root->rb_node;
+
+ if (!node)
+ return NULL;
+ while(node->rb_right)
+ node = node->rb_right;
+ return rb_entry(node, struct jffs2_node_frag, rb);
+}
+
#define rb_parent(rb) ((rb)->rb_parent)
#define frag_next(frag) rb_entry(rb_next(&(frag)->rb), struct jffs2_node_frag, rb)
#define frag_prev(frag) rb_entry(rb_prev(&(frag)->rb), struct jffs2_node_frag, rb)
@@ -374,7 +387,7 @@ static inline struct jffs2_node_frag *frag_first(struct rb_root *root)
D2(void jffs2_print_frag_list(struct jffs2_inode_info *f));
void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list);
int jffs2_get_inode_nodes(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
- struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp,
+ struct rb_root *tnp, struct jffs2_full_dirent **fdp,
uint32_t *highest_version, uint32_t *latest_mctime,
uint32_t *mctime_ver);
void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state);
@@ -462,7 +475,7 @@ int jffs2_do_mount_fs(struct jffs2_sb_info *c);
/* erase.c */
void jffs2_erase_pending_blocks(struct jffs2_sb_info *c, int count);
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
/* wbuf.c */
int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
diff --git a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c
index 2651135bdf42..c1d8b5ed9ab9 100644
--- a/fs/jffs2/nodemgmt.c
+++ b/fs/jffs2/nodemgmt.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: nodemgmt.c,v 1.115 2004/11/22 11:07:21 dwmw2 Exp $
+ * $Id: nodemgmt.c,v 1.122 2005/05/06 09:30:27 dedekind Exp $
*
*/
@@ -75,7 +75,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size;
if (dirty < c->nospc_dirty_size) {
if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
- printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n");
+ D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on dirty space to GC, but it's a deletion. Allowing...\n"));
break;
}
D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < nospc_dirty_size 0x%08x, returning -ENOSPC\n",
@@ -98,7 +98,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize, uint32_t *ofs
avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size;
if ( (avail / c->sector_size) <= blocksneeded) {
if (prio == ALLOC_DELETION && c->nr_free_blocks + c->nr_erasing_blocks >= c->resv_blocks_deletion) {
- printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n");
+ D1(printk(KERN_NOTICE "jffs2_reserve_space(): Low on possibly available space, but it's a deletion. Allowing...\n"));
break;
}
@@ -308,7 +308,10 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len));
#if 1
- if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) {
+ /* we could get some obsolete nodes after nextblock was refiled
+ in wbuf.c */
+ if ((c->nextblock || !ref_obsolete(new))
+ &&(jeb != c->nextblock || ref_offset(new) != jeb->offset + (c->sector_size - jeb->free_size))) {
printk(KERN_WARNING "argh. node added in wrong place\n");
jffs2_free_raw_node_ref(new);
return -EINVAL;
@@ -332,7 +335,7 @@ int jffs2_add_physical_node_ref(struct jffs2_sb_info *c, struct jffs2_raw_node_r
c->used_size += len;
}
- if (!jeb->free_size && !jeb->dirty_size) {
+ if (!jeb->free_size && !jeb->dirty_size && !ISDIRTY(jeb->wasted_size)) {
/* If it lives on the dirty_list, jffs2_reserve_space will put it there */
D1(printk(KERN_DEBUG "Adding full erase block at 0x%08x to clean_list (free 0x%08x, dirty 0x%08x, used 0x%08x\n",
jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size));
@@ -400,7 +403,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
jeb = &c->blocks[blocknr];
if (jffs2_can_mark_obsolete(c) && !jffs2_is_readonly(c) &&
- !(c->flags & JFFS2_SB_FLAG_MOUNTING)) {
+ !(c->flags & (JFFS2_SB_FLAG_SCANNING | JFFS2_SB_FLAG_BUILDING))) {
/* Hm. This may confuse static lock analysis. If any of the above
three conditions is false, we're going to return from this
function without actually obliterating any nodes or freeing
@@ -434,7 +437,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
// Take care, that wasted size is taken into concern
if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref_totlen(c, jeb, ref))) && jeb != c->nextblock) {
- D1(printk("Dirtying\n"));
+ D1(printk(KERN_DEBUG "Dirtying\n"));
addedsize = ref_totlen(c, jeb, ref);
jeb->dirty_size += ref_totlen(c, jeb, ref);
c->dirty_size += ref_totlen(c, jeb, ref);
@@ -456,7 +459,7 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
}
}
} else {
- D1(printk("Wasting\n"));
+ D1(printk(KERN_DEBUG "Wasting\n"));
addedsize = 0;
jeb->wasted_size += ref_totlen(c, jeb, ref);
c->wasted_size += ref_totlen(c, jeb, ref);
@@ -467,8 +470,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
D1(ACCT_PARANOIA_CHECK(jeb));
- if (c->flags & JFFS2_SB_FLAG_MOUNTING) {
- /* Mount in progress. Don't muck about with the block
+ if (c->flags & JFFS2_SB_FLAG_SCANNING) {
+ /* Flash scanning is in progress. Don't muck about with the block
lists because they're not ready yet, and don't actually
obliterate nodes that look obsolete. If they weren't
marked obsolete on the flash at the time they _became_
@@ -527,7 +530,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
spin_unlock(&c->erase_completion_lock);
- if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c)) {
+ if (!jffs2_can_mark_obsolete(c) || jffs2_is_readonly(c) ||
+ (c->flags & JFFS2_SB_FLAG_BUILDING)) {
/* We didn't lock the erase_free_sem */
return;
}
@@ -590,11 +594,8 @@ void jffs2_mark_node_obsolete(struct jffs2_sb_info *c, struct jffs2_raw_node_ref
*p = ref->next_in_ino;
ref->next_in_ino = NULL;
- if (ic->nodes == (void *)ic) {
- D1(printk(KERN_DEBUG "inocache for ino #%u is all gone now. Freeing\n", ic->ino));
+ if (ic->nodes == (void *)ic && ic->nlink == 0)
jffs2_del_ino_cache(c, ic);
- jffs2_free_inode_cache(ic);
- }
spin_unlock(&c->erase_completion_lock);
}
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h
index 03b0acc37b73..7bf72e012c94 100644
--- a/fs/jffs2/os-linux.h
+++ b/fs/jffs2/os-linux.h
@@ -7,41 +7,24 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: os-linux.h,v 1.51 2004/11/16 20:36:11 dwmw2 Exp $
+ * $Id: os-linux.h,v 1.57 2005/07/06 12:13:09 dwmw2 Exp $
*
*/
#ifndef __JFFS2_OS_LINUX_H__
#define __JFFS2_OS_LINUX_H__
-#include <linux/version.h>
/* JFFS2 uses Linux mode bits natively -- no need for conversion */
#define os_to_jffs2_mode(x) (x)
#define jffs2_to_os_mode(x) (x)
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,73)
-#define kstatfs statfs
-#endif
-
struct kstatfs;
struct kvec;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
#define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode))
#define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode)
#define JFFS2_SB_INFO(sb) (sb->s_fs_info)
#define OFNI_BS_2SFFJ(c) ((struct super_block *)c->os_priv)
-#elif defined(JFFS2_OUT_OF_KERNEL)
-#define JFFS2_INODE_INFO(i) ((struct jffs2_inode_info *) &(i)->u)
-#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-#define JFFS2_SB_INFO(sb) ((struct jffs2_sb_info *) &(sb)->u)
-#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-#else
-#define JFFS2_INODE_INFO(i) (&i->u.jffs2_i)
-#define OFNI_EDONI_2SFFJ(f) ((struct inode *) ( ((char *)f) - ((char *)(&((struct inode *)NULL)->u)) ) )
-#define JFFS2_SB_INFO(sb) (&sb->u.jffs2_sb)
-#define OFNI_BS_2SFFJ(c) ((struct super_block *) ( ((char *)c) - ((char *)(&((struct super_block *)NULL)->u)) ) )
-#endif
#define JFFS2_F_I_SIZE(f) (OFNI_EDONI_2SFFJ(f)->i_size)
@@ -49,28 +32,14 @@ struct kvec;
#define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid)
#define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid)
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1)
#define JFFS2_F_I_RDEV_MIN(f) (iminor(OFNI_EDONI_2SFFJ(f)))
#define JFFS2_F_I_RDEV_MAJ(f) (imajor(OFNI_EDONI_2SFFJ(f)))
-#else
-#define JFFS2_F_I_RDEV_MIN(f) (MINOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-#define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev)))
-#endif
-/* Urgh. The things we do to keep the 2.4 build working */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47)
#define ITIME(sec) ((struct timespec){sec, 0})
#define I_SEC(tv) ((tv).tv_sec)
#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec)
#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec)
#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec)
-#else
-#define ITIME(x) (x)
-#define I_SEC(x) (x)
-#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime)
-#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime)
-#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime)
-#endif
#define sleep_on_spinunlock(wq, s) \
do { \
@@ -84,23 +53,21 @@ struct kvec;
static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
{
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)
f->highest_version = 0;
f->fragtree = RB_ROOT;
f->metadata = NULL;
f->dents = NULL;
f->flags = 0;
f->usercompr = 0;
-#else
- memset(f, 0, sizeof(*f));
- init_MUTEX_LOCKED(&f->sem);
-#endif
}
+
#define jffs2_is_readonly(c) (OFNI_BS_2SFFJ(c)->s_flags & MS_RDONLY)
-#if (!defined CONFIG_JFFS2_FS_NAND && !defined CONFIG_JFFS2_FS_NOR_ECC)
+#ifndef CONFIG_JFFS2_FS_WRITEBUFFER
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) & ~(c->sector_size-1)) )
#define jffs2_can_mark_obsolete(c) (1)
+#define jffs2_is_writebuffered(c) (0)
#define jffs2_cleanmarker_oob(c) (0)
#define jffs2_write_nand_cleanmarker(c,jeb) (-EIO)
@@ -116,11 +83,14 @@ static inline void jffs2_init_inode_info(struct jffs2_inode_info *f)
#define jffs2_wbuf_timeout NULL
#define jffs2_wbuf_process NULL
#define jffs2_nor_ecc(c) (0)
+#define jffs2_dataflash(c) (0)
#define jffs2_nor_ecc_flash_setup(c) (0)
#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
#else /* NAND and/or ECC'd NOR support present */
+#define jffs2_is_writebuffered(c) (c->wbuf != NULL)
+#define SECTOR_ADDR(x) ( ((unsigned long)(x) / (unsigned long)(c->sector_size)) * c->sector_size )
#define jffs2_can_mark_obsolete(c) ((c->mtd->type == MTD_NORFLASH && !(c->mtd->flags & MTD_ECC)) || c->mtd->type == MTD_RAM)
#define jffs2_cleanmarker_oob(c) (c->mtd->type == MTD_NANDFLASH)
@@ -142,16 +112,16 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino);
int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c);
int jffs2_nand_flash_setup(struct jffs2_sb_info *c);
void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c);
-#ifdef CONFIG_JFFS2_FS_NOR_ECC
+
#define jffs2_nor_ecc(c) (c->mtd->type == MTD_NORFLASH && (c->mtd->flags & MTD_ECC))
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c);
void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c);
-#else
-#define jffs2_nor_ecc(c) (0)
-#define jffs2_nor_ecc_flash_setup(c) (0)
-#define jffs2_nor_ecc_flash_cleanup(c) do {} while (0)
-#endif /* NOR ECC */
-#endif /* NAND */
+
+#define jffs2_dataflash(c) (c->mtd->type == MTD_DATAFLASH)
+int jffs2_dataflash_setup(struct jffs2_sb_info *c);
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c);
+
+#endif /* WRITEBUFFER */
/* erase.c */
static inline void jffs2_erase_pending_trigger(struct jffs2_sb_info *c)
diff --git a/fs/jffs2/read.c b/fs/jffs2/read.c
index eb493dc06db7..c7f9068907cf 100644
--- a/fs/jffs2/read.c
+++ b/fs/jffs2/read.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: read.c,v 1.38 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: read.c,v 1.39 2005/03/01 10:34:03 dedekind Exp $
*
*/
@@ -214,33 +214,3 @@ int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
return 0;
}
-/* Core function to read symlink target. */
-char *jffs2_getlink(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
-{
- char *buf;
- int ret;
-
- down(&f->sem);
-
- if (!f->metadata) {
- printk(KERN_NOTICE "No metadata for symlink inode #%u\n", f->inocache->ino);
- up(&f->sem);
- return ERR_PTR(-EINVAL);
- }
- buf = kmalloc(f->metadata->size+1, GFP_USER);
- if (!buf) {
- up(&f->sem);
- return ERR_PTR(-ENOMEM);
- }
- buf[f->metadata->size]=0;
-
- ret = jffs2_read_dnode(c, f, f->metadata, buf, 0, f->metadata->size);
-
- up(&f->sem);
-
- if (ret) {
- kfree(buf);
- return ERR_PTR(ret);
- }
- return buf;
-}
diff --git a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c
index aca4a0b17bcd..081656c1d49e 100644
--- a/fs/jffs2/readinode.c
+++ b/fs/jffs2/readinode.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: readinode.c,v 1.117 2004/11/20 18:06:54 dwmw2 Exp $
+ * $Id: readinode.c,v 1.120 2005/07/05 21:03:07 dwmw2 Exp $
*
*/
@@ -500,7 +500,9 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
struct jffs2_inode_info *f,
struct jffs2_raw_inode *latest_node)
{
- struct jffs2_tmp_dnode_info *tn_list, *tn;
+ struct jffs2_tmp_dnode_info *tn = NULL;
+ struct rb_root tn_list;
+ struct rb_node *rb, *repl_rb;
struct jffs2_full_dirent *fd_list;
struct jffs2_full_dnode *fn = NULL;
uint32_t crc;
@@ -522,9 +524,10 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
}
f->dents = fd_list;
- while (tn_list) {
- tn = tn_list;
+ rb = rb_first(&tn_list);
+ while (rb) {
+ tn = rb_entry(rb, struct jffs2_tmp_dnode_info, rb);
fn = tn->fn;
if (f->metadata) {
@@ -556,7 +559,30 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
mdata_ver = tn->version;
}
next_tn:
- tn_list = tn->next;
+ BUG_ON(rb->rb_left);
+ repl_rb = NULL;
+ if (rb->rb_parent && rb->rb_parent->rb_left == rb) {
+ /* We were then left-hand child of our parent. We need
+ to move our own right-hand child into our place. */
+ repl_rb = rb->rb_right;
+ if (repl_rb)
+ repl_rb->rb_parent = rb->rb_parent;
+ } else
+ repl_rb = NULL;
+
+ rb = rb_next(rb);
+
+ /* Remove the spent tn from the tree; don't bother rebalancing
+ but put our right-hand child in our own place. */
+ if (tn->rb.rb_parent) {
+ if (tn->rb.rb_parent->rb_left == &tn->rb)
+ tn->rb.rb_parent->rb_left = repl_rb;
+ else if (tn->rb.rb_parent->rb_right == &tn->rb)
+ tn->rb.rb_parent->rb_right = repl_rb;
+ else BUG();
+ } else if (tn->rb.rb_right)
+ tn->rb.rb_right->rb_parent = NULL;
+
jffs2_free_tmp_dnode_info(tn);
}
D1(jffs2_sanitycheck_fragtree(f));
@@ -623,6 +649,40 @@ static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c,
case. */
if (!je32_to_cpu(latest_node->isize))
latest_node->isize = latest_node->dsize;
+
+ if (f->inocache->state != INO_STATE_CHECKING) {
+ /* Symlink's inode data is the target path. Read it and
+ * keep in RAM to facilitate quick follow symlink operation.
+ * We use f->dents field to store the target path, which
+ * is somewhat ugly. */
+ f->dents = kmalloc(je32_to_cpu(latest_node->csize) + 1, GFP_KERNEL);
+ if (!f->dents) {
+ printk(KERN_WARNING "Can't allocate %d bytes of memory "
+ "for the symlink target path cache\n",
+ je32_to_cpu(latest_node->csize));
+ up(&f->sem);
+ jffs2_do_clear_inode(c, f);
+ return -ENOMEM;
+ }
+
+ ret = jffs2_flash_read(c, ref_offset(fn->raw) + sizeof(*latest_node),
+ je32_to_cpu(latest_node->csize), &retlen, (char *)f->dents);
+
+ if (ret || retlen != je32_to_cpu(latest_node->csize)) {
+ if (retlen != je32_to_cpu(latest_node->csize))
+ ret = -EIO;
+ kfree(f->dents);
+ f->dents = NULL;
+ up(&f->sem);
+ jffs2_do_clear_inode(c, f);
+ return -ret;
+ }
+
+ ((char *)f->dents)[je32_to_cpu(latest_node->csize)] = '\0';
+ D1(printk(KERN_DEBUG "jffs2_do_read_inode(): symlink's target '%s' cached\n",
+ (char *)f->dents));
+ }
+
/* fall through... */
case S_IFBLK:
@@ -672,6 +732,9 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
down(&f->sem);
deleted = f->inocache && !f->inocache->nlink;
+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
+ jffs2_set_inocache_state(c, f->inocache, INO_STATE_CLEARING);
+
if (f->metadata) {
if (deleted)
jffs2_mark_node_obsolete(c, f->metadata->raw);
@@ -680,16 +743,27 @@ void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f)
jffs2_kill_fragtree(&f->fragtree, deleted?c:NULL);
- fds = f->dents;
+ /* For symlink inodes we us f->dents to store the target path name */
+ if (S_ISLNK(OFNI_EDONI_2SFFJ(f)->i_mode)) {
+ if (f->dents) {
+ kfree(f->dents);
+ f->dents = NULL;
+ }
+ } else {
+ fds = f->dents;
- while(fds) {
- fd = fds;
- fds = fd->next;
- jffs2_free_full_dirent(fd);
+ while(fds) {
+ fd = fds;
+ fds = fd->next;
+ jffs2_free_full_dirent(fd);
+ }
}
- if (f->inocache && f->inocache->state != INO_STATE_CHECKING)
+ if (f->inocache && f->inocache->state != INO_STATE_CHECKING) {
jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT);
+ if (f->inocache->nodes == (void *)f->inocache)
+ jffs2_del_ino_cache(c, f->inocache);
+ }
up(&f->sem);
}
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
index ded53584a897..b63160f83bab 100644
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: scan.c,v 1.115 2004/11/17 12:59:08 dedekind Exp $
+ * $Id: scan.c,v 1.119 2005/02/17 17:51:13 dedekind Exp $
*
*/
#include <linux/kernel.h>
@@ -19,7 +19,7 @@
#include <linux/compiler.h>
#include "nodelist.h"
-#define EMPTY_SCAN_SIZE 1024
+#define DEFAULT_EMPTY_SCAN_SIZE 1024
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \
@@ -68,13 +68,21 @@ static int jffs2_scan_dirent_node(struct jffs2_sb_info *c, struct jffs2_eraseblo
static inline int min_free(struct jffs2_sb_info *c)
{
uint32_t min = 2 * sizeof(struct jffs2_raw_inode);
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
if (!jffs2_can_mark_obsolete(c) && min < c->wbuf_pagesize)
return c->wbuf_pagesize;
#endif
return min;
}
+
+static inline uint32_t EMPTY_SCAN_SIZE(uint32_t sector_size) {
+ if (sector_size < DEFAULT_EMPTY_SCAN_SIZE)
+ return sector_size;
+ else
+ return DEFAULT_EMPTY_SCAN_SIZE;
+}
+
int jffs2_scan_medium(struct jffs2_sb_info *c)
{
int i, ret;
@@ -220,7 +228,7 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
c->dirty_size -= c->nextblock->dirty_size;
c->nextblock->dirty_size = 0;
}
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
if (!jffs2_can_mark_obsolete(c) && c->nextblock && (c->nextblock->free_size & (c->wbuf_pagesize-1))) {
/* If we're going to start writing into a block which already
contains data, and the end of the data isn't page-aligned,
@@ -286,7 +294,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
uint32_t hdr_crc, buf_ofs, buf_len;
int err;
int noise = 0;
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
int cleanmarkerfound = 0;
#endif
@@ -295,7 +303,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
if (jffs2_cleanmarker_oob(c)) {
int ret = jffs2_check_nand_cleanmarker(c, jeb);
D2(printk(KERN_NOTICE "jffs_check_nand_cleanmarker returned %d\n",ret));
@@ -316,7 +324,7 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
if (!buf_size) {
buf_len = c->sector_size;
} else {
- buf_len = EMPTY_SCAN_SIZE;
+ buf_len = EMPTY_SCAN_SIZE(c->sector_size);
err = jffs2_fill_scan_buf(c, buf, buf_ofs, buf_len);
if (err)
return err;
@@ -326,11 +334,11 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
ofs = 0;
/* Scan only 4KiB of 0xFF before declaring it's empty */
- while(ofs < EMPTY_SCAN_SIZE && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
+ while(ofs < EMPTY_SCAN_SIZE(c->sector_size) && *(uint32_t *)(&buf[ofs]) == 0xFFFFFFFF)
ofs += 4;
- if (ofs == EMPTY_SCAN_SIZE) {
-#ifdef CONFIG_JFFS2_FS_NAND
+ if (ofs == EMPTY_SCAN_SIZE(c->sector_size)) {
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
if (jffs2_cleanmarker_oob(c)) {
/* scan oob, take care of cleanmarker */
int ret = jffs2_check_oob_empty(c, jeb, cleanmarkerfound);
@@ -343,7 +351,10 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
}
#endif
D1(printk(KERN_DEBUG "Block at 0x%08x is empty (erased)\n", jeb->offset));
- return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
+ if (c->cleanmarker_size == 0)
+ return BLK_STATE_CLEANMARKER; /* don't bother with re-erase */
+ else
+ return BLK_STATE_ALLFF; /* OK to erase if all blocks are like this */
}
if (ofs) {
D1(printk(KERN_DEBUG "Free space at %08x ends at %08x\n", jeb->offset,
@@ -422,8 +433,8 @@ scan_more:
/* If we're only checking the beginning of a block with a cleanmarker,
bail now */
if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) &&
- c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_in_ino) {
- D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE));
+ c->cleanmarker_size && !jeb->dirty_size && !jeb->first_node->next_phys) {
+ D1(printk(KERN_DEBUG "%d bytes at start of block seems clean... assuming all clean\n", EMPTY_SCAN_SIZE(c->sector_size)));
return BLK_STATE_CLEANMARKER;
}
@@ -618,7 +629,7 @@ scan_more:
}
if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size
- && (!jeb->first_node || !jeb->first_node->next_in_ino) )
+ && (!jeb->first_node || !jeb->first_node->next_phys) )
return BLK_STATE_CLEANMARKER;
/* move blocks with max 4 byte dirty space to cleanlist */
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c
index 6b2a441d2766..2cf14cf8b35a 100644
--- a/fs/jffs2/super.c
+++ b/fs/jffs2/super.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: super.c,v 1.104 2004/11/23 15:37:31 gleixner Exp $
+ * $Id: super.c,v 1.106 2005/05/18 11:37:25 dedekind Exp $
*
*/
@@ -270,8 +270,6 @@ static void jffs2_put_super (struct super_block *sb)
D2(printk(KERN_DEBUG "jffs2: jffs2_put_super()\n"));
- if (!(sb->s_flags & MS_RDONLY))
- jffs2_stop_garbage_collect_thread(c);
down(&c->alloc_sem);
jffs2_flush_wbuf_pad(c);
up(&c->alloc_sem);
@@ -292,6 +290,8 @@ static void jffs2_put_super (struct super_block *sb)
static void jffs2_kill_sb(struct super_block *sb)
{
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
+ if (!(sb->s_flags & MS_RDONLY))
+ jffs2_stop_garbage_collect_thread(c);
generic_shutdown_super(sb);
put_mtd_device(c->mtd);
kfree(c);
@@ -309,7 +309,7 @@ static int __init init_jffs2_fs(void)
int ret;
printk(KERN_INFO "JFFS2 version 2.2."
-#ifdef CONFIG_JFFS2_FS_NAND
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
" (NAND)"
#endif
" (C) 2001-2003 Red Hat, Inc.\n");
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 7b1820d13712..65ab6b001dca 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: symlink.c,v 1.14 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: symlink.c,v 1.16 2005/03/01 10:50:48 dedekind Exp $
*
*/
@@ -19,27 +19,45 @@
#include "nodelist.h"
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
-static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd);
struct inode_operations jffs2_symlink_inode_operations =
{
.readlink = generic_readlink,
.follow_link = jffs2_follow_link,
- .put_link = jffs2_put_link,
.setattr = jffs2_setattr
};
static int jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
{
- unsigned char *buf;
- buf = jffs2_getlink(JFFS2_SB_INFO(dentry->d_inode->i_sb), JFFS2_INODE_INFO(dentry->d_inode));
- nd_set_link(nd, buf);
+ struct jffs2_inode_info *f = JFFS2_INODE_INFO(dentry->d_inode);
+
+ /*
+ * We don't acquire the f->sem mutex here since the only data we
+ * use is f->dents which in case of the symlink inode points to the
+ * symlink's target path.
+ *
+ * 1. If we are here the inode has already built and f->dents has
+ * to point to the target path.
+ * 2. Nobody uses f->dents (if the inode is symlink's inode). The
+ * exception is inode freeing function which frees f->dents. But
+ * it can't be called while we are here and before VFS has
+ * stopped using our f->dents string which we provide by means of
+ * nd_set_link() call.
+ */
+
+ if (!f->dents) {
+ printk(KERN_ERR "jffs2_follow_link(): can't find symlink taerget\n");
+ return -EIO;
+ }
+ D1(printk(KERN_DEBUG "jffs2_follow_link(): target path is '%s'\n", (char *) f->dents));
+
+ nd_set_link(nd, (char *)f->dents);
+
+ /*
+ * We unlock the f->sem mutex but VFS will use the f->dents string. This is safe
+ * since the only way that may cause f->dents to be changed is iput() operation.
+ * But VFS will not use f->dents after iput() has been called.
+ */
return 0;
}
-static void jffs2_put_link(struct dentry *dentry, struct nameidata *nd)
-{
- char *s = nd_get_link(nd);
- if (!IS_ERR(s))
- kfree(s);
-}
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index c8128069ecf0..996d922e503e 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -9,7 +9,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: wbuf.c,v 1.82 2004/11/20 22:08:31 dwmw2 Exp $
+ * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $
*
*/
@@ -83,7 +83,7 @@ static void jffs2_wbuf_dirties_inode(struct jffs2_sb_info *c, uint32_t ino)
struct jffs2_inodirty *new;
/* Mark the superblock dirty so that kupdated will flush... */
- OFNI_BS_2SFFJ(c)->s_dirt = 1;
+ jffs2_erase_pending_trigger(c);
if (jffs2_wbuf_pending_for_ino(c, ino))
return;
@@ -130,7 +130,10 @@ static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c)
}
}
-static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
+#define REFILE_NOTEMPTY 0
+#define REFILE_ANYWAY 1
+
+static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int allow_empty)
{
D1(printk("About to refile bad block at %08x\n", jeb->offset));
@@ -144,7 +147,7 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock
D1(printk("Refiling block at %08x to bad_used_list\n", jeb->offset));
list_add(&jeb->list, &c->bad_used_list);
} else {
- BUG();
+ BUG_ON(allow_empty == REFILE_NOTEMPTY);
/* It has to have had some nodes or we couldn't be here */
D1(printk("Refiling block at %08x to erase_pending_list\n", jeb->offset));
list_add(&jeb->list, &c->erase_pending_list);
@@ -179,7 +182,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
- jffs2_block_refile(c, jeb);
+ jffs2_block_refile(c, jeb, REFILE_NOTEMPTY);
/* Find the first node to be recovered, by skipping over every
node which ends before the wbuf starts, or which is obsolete. */
@@ -264,17 +267,16 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len);
if (ret) {
printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n");
- if (buf)
- kfree(buf);
+ kfree(buf);
return;
}
if (end-start >= c->wbuf_pagesize) {
- /* Need to do another write immediately. This, btw,
- means that we'll be writing from 'buf' and not from
- the wbuf. Since if we're writing from the wbuf there
- won't be more than a wbuf full of data, now will
- there? :) */
-
+ /* Need to do another write immediately, but it's possible
+ that this is just because the wbuf itself is completely
+ full, and there's nothing earlier read back from the
+ flash. Hence 'buf' isn't necessarily what we're writing
+ from. */
+ unsigned char *rewrite_buf = buf?:c->wbuf;
uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize);
D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n",
@@ -292,9 +294,9 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
#endif
if (jffs2_cleanmarker_oob(c))
ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen,
- buf, NULL, c->oobinfo);
+ rewrite_buf, NULL, c->oobinfo);
else
- ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, buf);
+ ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf);
if (ret || retlen != towrite) {
/* Argh. We tried. Really we did. */
@@ -321,10 +323,10 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c)
c->wbuf_len = (end - start) - towrite;
c->wbuf_ofs = ofs + towrite;
- memcpy(c->wbuf, buf + towrite, c->wbuf_len);
+ memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);
/* Don't muck about with c->wbuf_inodes. False positives are harmless. */
-
- kfree(buf);
+ if (buf)
+ kfree(buf);
} else {
/* OK, now we're left with the dregs in whichever buffer we're using */
if (buf) {
@@ -413,9 +415,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
int ret;
size_t retlen;
- /* Nothing to do if not NAND flash. In particular, we shouldn't
+ /* Nothing to do if not write-buffering the flash. In particular, we shouldn't
del_timer() the timer we never initialised. */
- if (jffs2_can_mark_obsolete(c))
+ if (!jffs2_is_writebuffered(c))
return 0;
if (!down_trylock(&c->alloc_sem)) {
@@ -424,7 +426,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
BUG();
}
- if(!c->wbuf || !c->wbuf_len)
+ if (!c->wbuf_len) /* already checked c->wbuf above */
return 0;
/* claim remaining space on the page
@@ -433,7 +435,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
if we have a switch to next page, we will not have
enough remaining space for this.
*/
- if (pad) {
+ if (pad && !jffs2_dataflash(c)) {
c->wbuf_len = PAD(c->wbuf_len);
/* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
@@ -484,7 +486,7 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
spin_lock(&c->erase_completion_lock);
/* Adjust free size of the block if we padded. */
- if (pad) {
+ if (pad && !jffs2_dataflash(c)) {
struct jffs2_eraseblock *jeb;
jeb = &c->blocks[c->wbuf_ofs / c->sector_size];
@@ -532,6 +534,9 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));
+ if (!c->wbuf)
+ return 0;
+
down(&c->alloc_sem);
if (!jffs2_wbuf_pending_for_ino(c, ino)) {
D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));
@@ -547,6 +552,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));
down_write(&c->wbuf_sem);
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ /* retry flushing wbuf in case jffs2_wbuf_recover
+ left some data in the wbuf */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
up_write(&c->wbuf_sem);
} else while (old_wbuf_len &&
old_wbuf_ofs == c->wbuf_ofs) {
@@ -561,6 +570,10 @@ int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino)
down(&c->alloc_sem);
down_write(&c->wbuf_sem);
ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
+ /* retry flushing wbuf in case jffs2_wbuf_recover
+ left some data in the wbuf */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);
up_write(&c->wbuf_sem);
break;
}
@@ -578,15 +591,27 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
{
int ret;
+ if (!c->wbuf)
+ return 0;
+
down_write(&c->wbuf_sem);
ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
+ /* retry - maybe wbuf recover left some data in wbuf. */
+ if (ret)
+ ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
up_write(&c->wbuf_sem);
return ret;
}
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
+#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) )
+#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) )
+#else
#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )
#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )
+#endif
+
int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino)
{
struct kvec outvecs[3];
@@ -601,7 +626,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
uint32_t outvec_to = to;
/* If not NAND flash, don't bother */
- if (!c->wbuf)
+ if (!jffs2_is_writebuffered(c))
return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
down_write(&c->wbuf_sem);
@@ -630,7 +655,7 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
erase block. Anything else, and you die.
New block starts at xxx000c (0-b = block header)
*/
- if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {
+ if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
/* It's a write to a new block */
if (c->wbuf_len) {
D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));
@@ -762,9 +787,18 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
/* At this point we have no problem,
- c->wbuf is empty.
+ c->wbuf is empty. However refile nextblock to avoid
+ writing again to same address.
*/
- *retlen = donelen;
+ struct jffs2_eraseblock *jeb;
+
+ spin_lock(&c->erase_completion_lock);
+
+ jeb = &c->blocks[outvec_to / c->sector_size];
+ jffs2_block_refile(c, jeb, REFILE_ANYWAY);
+
+ *retlen = 0;
+ spin_unlock(&c->erase_completion_lock);
goto exit;
}
@@ -819,7 +853,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r
{
struct kvec vecs[1];
- if (jffs2_can_mark_obsolete(c))
+ if (!jffs2_is_writebuffered(c))
return c->mtd->write(c->mtd, ofs, len, retlen, buf);
vecs[0].iov_base = (unsigned char *) buf;
@@ -835,39 +869,38 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re
loff_t orbf = 0, owbf = 0, lwbf = 0;
int ret;
- /* Read flash */
- if (!jffs2_can_mark_obsolete(c)) {
- down_read(&c->wbuf_sem);
-
- if (jffs2_cleanmarker_oob(c))
- ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
- else
- ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
-
- if ( (ret == -EBADMSG) && (*retlen == len) ) {
- printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
- len, ofs);
- /*
- * We have the raw data without ECC correction in the buffer, maybe
- * we are lucky and all data or parts are correct. We check the node.
- * If data are corrupted node check will sort it out.
- * We keep this block, it will fail on write or erase and the we
- * mark it bad. Or should we do that now? But we should give him a chance.
- * Maybe we had a system crash or power loss before the ecc write or
- * a erase was completed.
- * So we return success. :)
- */
- ret = 0;
- }
- } else
+ if (!jffs2_is_writebuffered(c))
return c->mtd->read(c->mtd, ofs, len, retlen, buf);
+ /* Read flash */
+ down_read(&c->wbuf_sem);
+ if (jffs2_cleanmarker_oob(c))
+ ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo);
+ else
+ ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);
+
+ if ( (ret == -EBADMSG) && (*retlen == len) ) {
+ printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n",
+ len, ofs);
+ /*
+ * We have the raw data without ECC correction in the buffer, maybe
+ * we are lucky and all data or parts are correct. We check the node.
+ * If data are corrupted node check will sort it out.
+ * We keep this block, it will fail on write or erase and the we
+ * mark it bad. Or should we do that now? But we should give him a chance.
+ * Maybe we had a system crash or power loss before the ecc write or
+ * a erase was completed.
+ * So we return success. :)
+ */
+ ret = 0;
+ }
+
/* if no writebuffer available or write buffer empty, return */
if (!c->wbuf_pagesize || !c->wbuf_len)
goto exit;
/* if we read in a different block, return */
- if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) )
+ if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))
goto exit;
if (ofs >= c->wbuf_ofs) {
@@ -1161,7 +1194,27 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c)
kfree(c->wbuf);
}
-#ifdef CONFIG_JFFS2_FS_NOR_ECC
+int jffs2_dataflash_setup(struct jffs2_sb_info *c) {
+ c->cleanmarker_size = 0; /* No cleanmarkers needed */
+
+ /* Initialize write buffer */
+ init_rwsem(&c->wbuf_sem);
+ c->wbuf_pagesize = c->sector_size;
+ c->wbuf_ofs = 0xFFFFFFFF;
+
+ c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);
+ if (!c->wbuf)
+ return -ENOMEM;
+
+ printk(KERN_INFO "JFFS2 write-buffering enabled (%i)\n", c->wbuf_pagesize);
+
+ return 0;
+}
+
+void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {
+ kfree(c->wbuf);
+}
+
int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
/* Cleanmarker is actually larger on the flashes */
c->cleanmarker_size = 16;
@@ -1181,4 +1234,3 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) {
void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) {
kfree(c->wbuf);
}
-#endif
diff --git a/fs/jffs2/write.c b/fs/jffs2/write.c
index 80a5db542629..69100615d9ae 100644
--- a/fs/jffs2/write.c
+++ b/fs/jffs2/write.c
@@ -7,7 +7,7 @@
*
* For licensing information, see the file 'LICENCE' in this directory.
*
- * $Id: write.c,v 1.87 2004/11/16 20:36:12 dwmw2 Exp $
+ * $Id: write.c,v 1.92 2005/04/13 13:22:35 dwmw2 Exp $
*
*/
@@ -35,13 +35,12 @@ int jffs2_do_new_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint
f->inocache = ic;
f->inocache->nlink = 1;
f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache;
- f->inocache->ino = ++c->highest_ino;
f->inocache->state = INO_STATE_PRESENT;
- ri->ino = cpu_to_je32(f->inocache->ino);
- D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
jffs2_add_ino_cache(c, f->inocache);
+ D1(printk(KERN_DEBUG "jffs2_do_new_inode(): Assigned ino# %d\n", f->inocache->ino));
+ ri->ino = cpu_to_je32(f->inocache->ino);
ri->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE);
@@ -136,6 +135,15 @@ struct jffs2_full_dnode *jffs2_write_dnode(struct jffs2_sb_info *c, struct jffs2
raw->__totlen = PAD(sizeof(*ri)+datalen);
raw->next_phys = NULL;
+ if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(ri->version) < f->highest_version)) {
+ BUG_ON(!retried);
+ D1(printk(KERN_DEBUG "jffs2_write_dnode : dnode_version %d, "
+ "highest version %d -> updating dnode\n",
+ je32_to_cpu(ri->version), f->highest_version));
+ ri->version = cpu_to_je32(++f->highest_version);
+ ri->node_crc = cpu_to_je32(crc32(0, ri, sizeof(*ri)-8));
+ }
+
ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen,
(alloc_mode==ALLOC_GC)?0:f->inocache->ino);
@@ -280,6 +288,16 @@ struct jffs2_full_dirent *jffs2_write_dirent(struct jffs2_sb_info *c, struct jff
raw->__totlen = PAD(sizeof(*rd)+namelen);
raw->next_phys = NULL;
+ if ((alloc_mode!=ALLOC_GC) && (je32_to_cpu(rd->version) < f->highest_version)) {
+ BUG_ON(!retried);
+ D1(printk(KERN_DEBUG "jffs2_write_dirent : dirent_version %d, "
+ "highest version %d -> updating dirent\n",
+ je32_to_cpu(rd->version), f->highest_version));
+ rd->version = cpu_to_je32(++f->highest_version);
+ fd->version = je32_to_cpu(rd->version);
+ rd->node_crc = cpu_to_je32(crc32(0, rd, sizeof(*rd)-8));
+ }
+
ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen,
(alloc_mode==ALLOC_GC)?0:je32_to_cpu(rd->pino));
if (ret || (retlen != sizeof(*rd) + namelen)) {
@@ -625,20 +643,23 @@ int jffs2_do_unlink(struct jffs2_sb_info *c, struct jffs2_inode_info *dir_f,
down(&dead_f->sem);
- while (dead_f->dents) {
- /* There can be only deleted ones */
- fd = dead_f->dents;
-
- dead_f->dents = fd->next;
-
- if (fd->ino) {
- printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
- dead_f->inocache->ino, fd->name, fd->ino);
- } else {
- D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n", fd->name, dead_f->inocache->ino));
+ if (S_ISDIR(OFNI_EDONI_2SFFJ(dead_f)->i_mode)) {
+ while (dead_f->dents) {
+ /* There can be only deleted ones */
+ fd = dead_f->dents;
+
+ dead_f->dents = fd->next;
+
+ if (fd->ino) {
+ printk(KERN_WARNING "Deleting inode #%u with active dentry \"%s\"->ino #%u\n",
+ dead_f->inocache->ino, fd->name, fd->ino);
+ } else {
+ D1(printk(KERN_DEBUG "Removing deletion dirent for \"%s\" from dir ino #%u\n",
+ fd->name, dead_f->inocache->ino));
+ }
+ jffs2_mark_node_obsolete(c, fd->raw);
+ jffs2_free_full_dirent(fd);
}
- jffs2_mark_node_obsolete(c, fd->raw);
- jffs2_free_full_dirent(fd);
}
dead_f->inocache->nlink--;
diff --git a/fs/jfs/jfs_logmgr.c b/fs/jfs/jfs_logmgr.c
index 7c8387ed4192..79d07624bfe1 100644
--- a/fs/jfs/jfs_logmgr.c
+++ b/fs/jfs/jfs_logmgr.c
@@ -2359,9 +2359,9 @@ int jfsIOWait(void *arg)
lbmStartIO(bp);
spin_lock_irq(&log_redrive_lock);
}
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
spin_unlock_irq(&log_redrive_lock);
- refrigerator(PF_FREEZE);
+ refrigerator();
} else {
add_wait_queue(&jfs_IO_thread_wait, &wq);
set_current_state(TASK_INTERRUPTIBLE);
diff --git a/fs/jfs/jfs_txnmgr.c b/fs/jfs/jfs_txnmgr.c
index 8cbaaff1d5fa..121c981ff453 100644
--- a/fs/jfs/jfs_txnmgr.c
+++ b/fs/jfs/jfs_txnmgr.c
@@ -2788,9 +2788,9 @@ int jfs_lazycommit(void *arg)
/* In case a wakeup came while all threads were active */
jfs_commit_thread_waking = 0;
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
LAZY_UNLOCK(flags);
- refrigerator(PF_FREEZE);
+ refrigerator();
} else {
DECLARE_WAITQUEUE(wq, current);
@@ -2987,9 +2987,9 @@ int jfs_sync(void *arg)
/* Add anon_list2 back to anon_list */
list_splice_init(&TxAnchor.anon_list2, &TxAnchor.anon_list);
- if (current->flags & PF_FREEZE) {
+ if (freezing(current)) {
TXN_UNLOCK();
- refrigerator(PF_FREEZE);
+ refrigerator();
} else {
DECLARE_WAITQUEUE(wq, current);
diff --git a/fs/libfs.c b/fs/libfs.c
index 5025563e7379..58101dff2c66 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -183,6 +183,7 @@ struct file_operations simple_dir_operations = {
.llseek = dcache_dir_lseek,
.read = generic_read_dir,
.readdir = dcache_readdir,
+ .fsync = simple_sync_file,
};
struct inode_operations simple_dir_inode_operations = {
diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c
index fd77ed1d710d..14b3ce87fa29 100644
--- a/fs/lockd/clntproc.c
+++ b/fs/lockd/clntproc.c
@@ -313,7 +313,7 @@ static int nlm_wait_on_grace(wait_queue_head_t *queue)
prepare_to_wait(queue, &wait, TASK_INTERRUPTIBLE);
if (!signalled ()) {
schedule_timeout(NLMCLNT_GRACE_WAIT);
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
if (!signalled ())
status = 0;
}
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index b82e470912e8..6e242556b903 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -191,7 +191,9 @@ lockd(struct svc_rqst *rqstp)
printk(KERN_DEBUG
"lockd: new process, skipping host shutdown\n");
wake_up(&lockd_exit);
-
+
+ flush_signals(current);
+
/* Exit the RPC thread */
svc_exit_thread(rqstp);
diff --git a/fs/locks.c b/fs/locks.c
index a0bc03495bd4..29fa5da6c117 100644
--- a/fs/locks.c
+++ b/fs/locks.c
@@ -1276,7 +1276,7 @@ int fcntl_getlease(struct file *filp)
*/
static int __setlease(struct file *filp, long arg, struct file_lock **flp)
{
- struct file_lock *fl, **before, **my_before = NULL, *lease = *flp;
+ struct file_lock *fl, **before, **my_before = NULL, *lease;
struct dentry *dentry = filp->f_dentry;
struct inode *inode = dentry->d_inode;
int error, rdlease_count = 0, wrlease_count = 0;
@@ -1287,6 +1287,8 @@ static int __setlease(struct file *filp, long arg, struct file_lock **flp)
if (!flp || !(*flp) || !(*flp)->fl_lmops || !(*flp)->fl_lmops->fl_break)
goto out;
+ lease = *flp;
+
error = -EAGAIN;
if ((arg == F_RDLCK) && (atomic_read(&inode->i_writecount) > 0))
goto out;
diff --git a/fs/namei.c b/fs/namei.c
index fa8df81ce8ca..02a824cd3c5c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -21,7 +21,7 @@
#include <linux/namei.h>
#include <linux/quotaops.h>
#include <linux/pagemap.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/smp_lock.h>
#include <linux/personality.h>
#include <linux/security.h>
@@ -314,7 +314,7 @@ void path_release(struct nameidata *nd)
void path_release_on_umount(struct nameidata *nd)
{
dput(nd->dentry);
- _mntput(nd->mnt);
+ mntput_no_expire(nd->mnt);
}
/*
@@ -1312,7 +1312,7 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode,
DQUOT_INIT(dir);
error = dir->i_op->create(dir, dentry, mode, nd);
if (!error) {
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_create(dir, dentry->d_name.name);
security_inode_post_create(dir, dentry, mode);
}
return error;
@@ -1637,7 +1637,7 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
DQUOT_INIT(dir);
error = dir->i_op->mknod(dir, dentry, mode, dev);
if (!error) {
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_create(dir, dentry->d_name.name);
security_inode_post_mknod(dir, dentry, mode, dev);
}
return error;
@@ -1710,7 +1710,7 @@ int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
DQUOT_INIT(dir);
error = dir->i_op->mkdir(dir, dentry, mode);
if (!error) {
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_mkdir(dir, dentry->d_name.name);
security_inode_post_mkdir(dir,dentry, mode);
}
return error;
@@ -1801,7 +1801,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
}
up(&dentry->d_inode->i_sem);
if (!error) {
- inode_dir_notify(dir, DN_DELETE);
+ fsnotify_rmdir(dentry, dentry->d_inode, dir);
d_delete(dentry);
}
dput(dentry);
@@ -1874,9 +1874,10 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
/* We don't d_delete() NFS sillyrenamed files--they still exist. */
if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) {
+ fsnotify_unlink(dentry, dir);
d_delete(dentry);
- inode_dir_notify(dir, DN_DELETE);
}
+
return error;
}
@@ -1950,7 +1951,7 @@ int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, i
DQUOT_INIT(dir);
error = dir->i_op->symlink(dir, dentry, oldname);
if (!error) {
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_create(dir, dentry->d_name.name);
security_inode_post_symlink(dir, dentry, oldname);
}
return error;
@@ -2023,7 +2024,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
error = dir->i_op->link(old_dentry, dir, new_dentry);
up(&old_dentry->d_inode->i_sem);
if (!error) {
- inode_dir_notify(dir, DN_CREATE);
+ fsnotify_create(dir, new_dentry->d_name.name);
security_inode_post_link(old_dentry, dir, new_dentry);
}
return error;
@@ -2187,6 +2188,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
{
int error;
int is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
+ const char *old_name;
if (old_dentry->d_inode == new_dentry->d_inode)
return 0;
@@ -2208,18 +2210,18 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
DQUOT_INIT(old_dir);
DQUOT_INIT(new_dir);
+ old_name = fsnotify_oldname_init(old_dentry->d_name.name);
+
if (is_dir)
error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
else
error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
if (!error) {
- if (old_dir == new_dir)
- inode_dir_notify(old_dir, DN_RENAME);
- else {
- inode_dir_notify(old_dir, DN_DELETE);
- inode_dir_notify(new_dir, DN_CREATE);
- }
+ const char *new_name = old_dentry->d_name.name;
+ fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir);
}
+ fsnotify_oldname_free(old_name);
+
return error;
}
diff --git a/fs/namespace.c b/fs/namespace.c
index 3b93e5d750eb..587eb0d707ee 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -61,7 +61,7 @@ struct vfsmount *alloc_vfsmnt(const char *name)
INIT_LIST_HEAD(&mnt->mnt_child);
INIT_LIST_HEAD(&mnt->mnt_mounts);
INIT_LIST_HEAD(&mnt->mnt_list);
- INIT_LIST_HEAD(&mnt->mnt_fslink);
+ INIT_LIST_HEAD(&mnt->mnt_expire);
if (name) {
int size = strlen(name)+1;
char *newname = kmalloc(size, GFP_KERNEL);
@@ -165,8 +165,8 @@ clone_mnt(struct vfsmount *old, struct dentry *root)
/* stick the duplicate mount on the same expiry list
* as the original if that was on one */
spin_lock(&vfsmount_lock);
- if (!list_empty(&old->mnt_fslink))
- list_add(&mnt->mnt_fslink, &old->mnt_fslink);
+ if (!list_empty(&old->mnt_expire))
+ list_add(&mnt->mnt_expire, &old->mnt_expire);
spin_unlock(&vfsmount_lock);
}
return mnt;
@@ -337,7 +337,7 @@ int may_umount(struct vfsmount *mnt)
EXPORT_SYMBOL(may_umount);
-void umount_tree(struct vfsmount *mnt)
+static void umount_tree(struct vfsmount *mnt)
{
struct vfsmount *p;
LIST_HEAD(kill);
@@ -345,12 +345,13 @@ void umount_tree(struct vfsmount *mnt)
for (p = mnt; p; p = next_mnt(p, mnt)) {
list_del(&p->mnt_list);
list_add(&p->mnt_list, &kill);
+ p->mnt_namespace = NULL;
}
while (!list_empty(&kill)) {
mnt = list_entry(kill.next, struct vfsmount, mnt_list);
list_del_init(&mnt->mnt_list);
- list_del_init(&mnt->mnt_fslink);
+ list_del_init(&mnt->mnt_expire);
if (mnt->mnt_parent == mnt) {
spin_unlock(&vfsmount_lock);
} else {
@@ -644,7 +645,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
if (mnt) {
/* stop bind mounts from expiring */
spin_lock(&vfsmount_lock);
- list_del_init(&mnt->mnt_fslink);
+ list_del_init(&mnt->mnt_expire);
spin_unlock(&vfsmount_lock);
err = graft_tree(mnt, nd);
@@ -743,7 +744,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
/* if the mount is moved, it should no longer be expire
* automatically */
- list_del_init(&old_nd.mnt->mnt_fslink);
+ list_del_init(&old_nd.mnt->mnt_expire);
out2:
spin_unlock(&vfsmount_lock);
out1:
@@ -807,12 +808,13 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
goto unlock;
newmnt->mnt_flags = mnt_flags;
+ newmnt->mnt_namespace = current->namespace;
err = graft_tree(newmnt, nd);
if (err == 0 && fslist) {
/* add to the specified expiration list */
spin_lock(&vfsmount_lock);
- list_add_tail(&newmnt->mnt_fslink, fslist);
+ list_add_tail(&newmnt->mnt_expire, fslist);
spin_unlock(&vfsmount_lock);
}
@@ -824,6 +826,54 @@ unlock:
EXPORT_SYMBOL_GPL(do_add_mount);
+static void expire_mount(struct vfsmount *mnt, struct list_head *mounts)
+{
+ spin_lock(&vfsmount_lock);
+
+ /*
+ * Check if mount is still attached, if not, let whoever holds it deal
+ * with the sucker
+ */
+ if (mnt->mnt_parent == mnt) {
+ spin_unlock(&vfsmount_lock);
+ return;
+ }
+
+ /*
+ * Check that it is still dead: the count should now be 2 - as
+ * contributed by the vfsmount parent and the mntget above
+ */
+ if (atomic_read(&mnt->mnt_count) == 2) {
+ struct nameidata old_nd;
+
+ /* delete from the namespace */
+ list_del_init(&mnt->mnt_list);
+ mnt->mnt_namespace = NULL;
+ detach_mnt(mnt, &old_nd);
+ spin_unlock(&vfsmount_lock);
+ path_release(&old_nd);
+
+ /*
+ * Now lay it to rest if this was the last ref on the superblock
+ */
+ if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
+ /* last instance - try to be smart */
+ lock_kernel();
+ DQUOT_OFF(mnt->mnt_sb);
+ acct_auto_close(mnt->mnt_sb);
+ unlock_kernel();
+ }
+ mntput(mnt);
+ } else {
+ /*
+ * Someone brought it back to life whilst we didn't have any
+ * locks held so return it to the expiration list
+ */
+ list_add_tail(&mnt->mnt_expire, mounts);
+ spin_unlock(&vfsmount_lock);
+ }
+}
+
/*
* process a list of expirable mountpoints with the intent of discarding any
* mountpoints that aren't in use and haven't been touched since last we came
@@ -846,13 +896,13 @@ void mark_mounts_for_expiry(struct list_head *mounts)
* - still marked for expiry (marked on the last call here; marks are
* cleared by mntput())
*/
- list_for_each_entry_safe(mnt, next, mounts, mnt_fslink) {
+ list_for_each_entry_safe(mnt, next, mounts, mnt_expire) {
if (!xchg(&mnt->mnt_expiry_mark, 1) ||
atomic_read(&mnt->mnt_count) != 1)
continue;
mntget(mnt);
- list_move(&mnt->mnt_fslink, &graveyard);
+ list_move(&mnt->mnt_expire, &graveyard);
}
/*
@@ -862,61 +912,19 @@ void mark_mounts_for_expiry(struct list_head *mounts)
* - dispose of the corpse
*/
while (!list_empty(&graveyard)) {
- mnt = list_entry(graveyard.next, struct vfsmount, mnt_fslink);
- list_del_init(&mnt->mnt_fslink);
+ mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire);
+ list_del_init(&mnt->mnt_expire);
/* don't do anything if the namespace is dead - all the
* vfsmounts from it are going away anyway */
namespace = mnt->mnt_namespace;
- if (!namespace || atomic_read(&namespace->count) <= 0)
+ if (!namespace || !namespace->root)
continue;
get_namespace(namespace);
spin_unlock(&vfsmount_lock);
down_write(&namespace->sem);
- spin_lock(&vfsmount_lock);
-
- /* check that it is still dead: the count should now be 2 - as
- * contributed by the vfsmount parent and the mntget above */
- if (atomic_read(&mnt->mnt_count) == 2) {
- struct vfsmount *xdmnt;
- struct dentry *xdentry;
-
- /* delete from the namespace */
- list_del_init(&mnt->mnt_list);
- list_del_init(&mnt->mnt_child);
- list_del_init(&mnt->mnt_hash);
- mnt->mnt_mountpoint->d_mounted--;
-
- xdentry = mnt->mnt_mountpoint;
- mnt->mnt_mountpoint = mnt->mnt_root;
- xdmnt = mnt->mnt_parent;
- mnt->mnt_parent = mnt;
-
- spin_unlock(&vfsmount_lock);
-
- mntput(xdmnt);
- dput(xdentry);
-
- /* now lay it to rest if this was the last ref on the
- * superblock */
- if (atomic_read(&mnt->mnt_sb->s_active) == 1) {
- /* last instance - try to be smart */
- lock_kernel();
- DQUOT_OFF(mnt->mnt_sb);
- acct_auto_close(mnt->mnt_sb);
- unlock_kernel();
- }
-
- mntput(mnt);
- } else {
- /* someone brought it back to life whilst we didn't
- * have any locks held so return it to the expiration
- * list */
- list_add_tail(&mnt->mnt_fslink, mounts);
- spin_unlock(&vfsmount_lock);
- }
-
+ expire_mount(mnt, mounts);
up_write(&namespace->sem);
mntput(mnt);
@@ -1449,16 +1457,12 @@ void __init mnt_init(unsigned long mempages)
void __put_namespace(struct namespace *namespace)
{
- struct vfsmount *mnt;
-
+ struct vfsmount *root = namespace->root;
+ namespace->root = NULL;
+ spin_unlock(&vfsmount_lock);
down_write(&namespace->sem);
spin_lock(&vfsmount_lock);
-
- list_for_each_entry(mnt, &namespace->list, mnt_list) {
- mnt->mnt_namespace = NULL;
- }
-
- umount_tree(namespace->root);
+ umount_tree(root);
spin_unlock(&vfsmount_lock);
up_write(&namespace->sem);
kfree(namespace);
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 2dc2d8693968..a9f7a8ab1d59 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -705,18 +705,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
return;
}
-#ifdef USE_OLD_SLOW_DIRECTORY_LISTING
- for (;;) {
- err = ncp_search_for_file_or_subdir(server, &seq, &entry.i);
- if (err) {
- DPRINTK("ncp_do_readdir: search failed, err=%d\n", err);
- break;
- }
- entry.volume = entry.i.volNumber;
- if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry))
- break;
- }
-#else
/* We MUST NOT use server->buffer_size handshaked with server if we are
using UDP, as for UDP server uses max. buffer size determined by
MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
@@ -754,7 +742,6 @@ ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir,
}
} while (more);
vfree(buf);
-#endif
return;
}
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index e4eb5ed4bee4..c755e1848a42 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -845,46 +845,6 @@ out:
return result;
}
-/* Search for everything */
-int ncp_search_for_file_or_subdir(struct ncp_server *server,
- struct nw_search_sequence *seq,
- struct nw_info_struct *target)
-{
- int result;
-
- ncp_init_request(server);
- ncp_add_byte(server, 3); /* subfunction */
- ncp_add_byte(server, server->name_space[seq->volNumber]);
- ncp_add_byte(server, 0); /* data stream (???) */
- ncp_add_word(server, cpu_to_le16(0x8006)); /* Search attribs */
- ncp_add_dword(server, RIM_ALL); /* return info mask */
- ncp_add_mem(server, seq, 9);
-#ifdef CONFIG_NCPFS_NFS_NS
- if (server->name_space[seq->volNumber] == NW_NS_NFS) {
- ncp_add_byte(server, 0); /* 0 byte pattern */
- } else
-#endif
- {
- ncp_add_byte(server, 2); /* 2 byte pattern */
- ncp_add_byte(server, 0xff); /* following is a wildcard */
- ncp_add_byte(server, '*');
- }
-
- if ((result = ncp_request(server, 87)) != 0)
- goto out;
- memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
- ncp_extract_file_info(ncp_reply_data(server, 10), target);
-
- ncp_unlock_server(server);
-
- result = ncp_obtain_nfs_info(server, target);
- return result;
-
-out:
- ncp_unlock_server(server);
- return result;
-}
-
int ncp_search_for_fileset(struct ncp_server *server,
struct nw_search_sequence *seq,
int* more,
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 05ec2e9d90c6..9e4dc30c2435 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -87,9 +87,6 @@ int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, char *,
int ncp_initialize_search(struct ncp_server *, struct inode *,
struct nw_search_sequence *target);
-int ncp_search_for_file_or_subdir(struct ncp_server *server,
- struct nw_search_sequence *seq,
- struct nw_info_struct *target);
int ncp_search_for_fileset(struct ncp_server *server,
struct nw_search_sequence *seq,
int* more, int* cnt,
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c
index ee3536fc84a3..1b7a3ef2f813 100644
--- a/fs/nfs/nfs3acl.c
+++ b/fs/nfs/nfs3acl.c
@@ -2,7 +2,7 @@
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
-#include <linux/xattr_acl.h>
+#include <linux/posix_acl_xattr.h>
#include <linux/nfsacl.h>
#define NFSDBG_FACILITY NFSDBG_PROC
@@ -53,9 +53,9 @@ ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
struct posix_acl *acl;
int type, error = 0;
- if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
- else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
@@ -82,9 +82,9 @@ int nfs3_setxattr(struct dentry *dentry, const char *name,
struct posix_acl *acl;
int type, error;
- if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
- else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
@@ -103,9 +103,9 @@ int nfs3_removexattr(struct dentry *dentry, const char *name)
struct inode *inode = dentry->d_inode;
int type;
- if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
type = ACL_TYPE_ACCESS;
- else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
type = ACL_TYPE_DEFAULT;
else
return -EOPNOTSUPP;
diff --git a/fs/nfsd/Makefile b/fs/nfsd/Makefile
index 9f043f44c92f..ce341dc76d5e 100644
--- a/fs/nfsd/Makefile
+++ b/fs/nfsd/Makefile
@@ -10,5 +10,5 @@ nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
- nfs4acl.o nfs4callback.o
+ nfs4acl.o nfs4callback.o nfs4recover.o
nfsd-objs := $(nfsd-y)
diff --git a/fs/nfsd/nfs4acl.c b/fs/nfsd/nfs4acl.c
index 11ebf6c4aa54..4a2105552ac4 100644
--- a/fs/nfsd/nfs4acl.c
+++ b/fs/nfsd/nfs4acl.c
@@ -125,7 +125,7 @@ static short ace2type(struct nfs4_ace *);
static int _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *, unsigned int);
static struct posix_acl *_nfsv4_to_posix_one(struct nfs4_acl *, unsigned int);
int nfs4_acl_add_ace(struct nfs4_acl *, u32, u32, u32, int, uid_t);
-int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
+static int nfs4_acl_split(struct nfs4_acl *, struct nfs4_acl *);
struct nfs4_acl *
nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
@@ -775,7 +775,7 @@ out_err:
return pacl;
}
-int
+static int
nfs4_acl_split(struct nfs4_acl *acl, struct nfs4_acl *dacl)
{
struct list_head *h, *n;
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index 634465e9cfc6..583c0710e45e 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -54,7 +54,6 @@
/* declarations */
static void nfs4_cb_null(struct rpc_task *task);
-extern spinlock_t recall_lock;
/* Index of predefined Linux callback client operations */
@@ -329,12 +328,12 @@ out:
.p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \
}
-struct rpc_procinfo nfs4_cb_procedures[] = {
+static struct rpc_procinfo nfs4_cb_procedures[] = {
PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null),
PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall),
};
-struct rpc_version nfs_cb_version4 = {
+static struct rpc_version nfs_cb_version4 = {
.number = 1,
.nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]),
.procs = nfs4_cb_procedures
@@ -348,7 +347,7 @@ static struct rpc_version * nfs_cb_version[] = {
/*
* Use the SETCLIENTID credential
*/
-struct rpc_cred *
+static struct rpc_cred *
nfsd4_lookupcred(struct nfs4_client *clp, int taskflags)
{
struct auth_cred acred;
@@ -387,9 +386,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
char hostname[32];
int status;
- dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d\n",
- cb->cb_parsed, atomic_read(&cb->cb_set));
- if (!cb->cb_parsed || atomic_read(&cb->cb_set))
+ if (atomic_read(&cb->cb_set))
return;
/* Initialize address */
@@ -427,7 +424,7 @@ nfsd4_probe_callback(struct nfs4_client *clp)
* XXX AUTH_UNIX only - need AUTH_GSS....
*/
sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr));
- clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
+ clnt = rpc_new_client(xprt, hostname, program, 1, RPC_AUTH_UNIX);
if (IS_ERR(clnt)) {
dprintk("NFSD: couldn't create callback client\n");
goto out_err;
diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c
index 4ba540841cf6..5605a26efc57 100644
--- a/fs/nfsd/nfs4idmap.c
+++ b/fs/nfsd/nfs4idmap.c
@@ -104,7 +104,7 @@ ent_update(struct ent *new, struct ent *itm)
ent_init(new, itm);
}
-void
+static void
ent_put(struct cache_head *ch, struct cache_detail *cd)
{
if (cache_put(ch, cd)) {
@@ -186,7 +186,7 @@ warn_no_idmapd(struct cache_detail *detail)
static int idtoname_parse(struct cache_detail *, char *, int);
static struct ent *idtoname_lookup(struct ent *, int);
-struct cache_detail idtoname_cache = {
+static struct cache_detail idtoname_cache = {
.hash_size = ENT_HASHMAX,
.hash_table = idtoname_table,
.name = "nfs4.idtoname",
@@ -277,7 +277,7 @@ nametoid_hash(struct ent *ent)
return hash_str(ent->name, ENT_HASHBITS);
}
-void
+static void
nametoid_request(struct cache_detail *cd, struct cache_head *ch, char **bpp,
int *blen)
{
@@ -317,9 +317,9 @@ nametoid_show(struct seq_file *m, struct cache_detail *cd, struct cache_head *h)
}
static struct ent *nametoid_lookup(struct ent *, int);
-int nametoid_parse(struct cache_detail *, char *, int);
+static int nametoid_parse(struct cache_detail *, char *, int);
-struct cache_detail nametoid_cache = {
+static struct cache_detail nametoid_cache = {
.hash_size = ENT_HASHMAX,
.hash_table = nametoid_table,
.name = "nfs4.nametoid",
@@ -330,7 +330,7 @@ struct cache_detail nametoid_cache = {
.warn_no_listener = warn_no_idmapd,
};
-int
+static int
nametoid_parse(struct cache_detail *cd, char *buf, int buflen)
{
struct ent ent, *res;
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index e8158741e8b5..e08edc17c6a0 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -45,6 +45,7 @@
#include <linux/param.h>
#include <linux/major.h>
#include <linux/slab.h>
+#include <linux/file.h>
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
@@ -168,12 +169,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
(int)open->op_fname.len, open->op_fname.data,
open->op_stateowner);
- if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_grace;
-
- if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- return nfserr_no_grace;
-
/* This check required by spec. */
if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
return nfserr_inval;
@@ -198,6 +193,11 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
if (status)
goto out;
switch (open->op_claim_type) {
+ case NFS4_OPEN_CLAIM_DELEGATE_CUR:
+ status = nfserr_inval;
+ if (open->op_create)
+ goto out;
+ /* fall through */
case NFS4_OPEN_CLAIM_NULL:
/*
* (1) set CURRENT_FH to the file being opened,
@@ -220,7 +220,6 @@ nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open
if (status)
goto out;
break;
- case NFS4_OPEN_CLAIM_DELEGATE_CUR:
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
printk("NFSD: unsupported OPEN claim type %d\n",
open->op_claim_type);
@@ -473,26 +472,27 @@ static inline int
nfsd4_read(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_read *read)
{
int status;
- struct file *filp = NULL;
/* no need to check permission - this will be done in nfsd_read() */
+ read->rd_filp = NULL;
if (read->rd_offset >= OFFSET_MAX)
return nfserr_inval;
nfs4_lock_state();
/* check stateid */
if ((status = nfs4_preprocess_stateid_op(current_fh, &read->rd_stateid,
- CHECK_FH | RD_STATE, &filp))) {
+ CHECK_FH | RD_STATE, &read->rd_filp))) {
dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
goto out;
}
+ if (read->rd_filp)
+ get_file(read->rd_filp);
status = nfs_ok;
out:
nfs4_unlock_state();
read->rd_rqstp = rqstp;
read->rd_fhp = current_fh;
- read->rd_filp = filp;
return status;
}
@@ -532,6 +532,8 @@ nfsd4_remove(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_rem
{
int status;
+ if (nfs4_in_grace())
+ return nfserr_grace;
status = nfsd_unlink(rqstp, current_fh, 0, remove->rm_name, remove->rm_namelen);
if (status == nfserr_symlink)
return nfserr_notdir;
@@ -550,6 +552,9 @@ nfsd4_rename(struct svc_rqst *rqstp, struct svc_fh *current_fh,
if (!save_fh->fh_dentry)
return status;
+ if (nfs4_in_grace() && !(save_fh->fh_export->ex_flags
+ & NFSEXP_NOSUBTREECHECK))
+ return nfserr_grace;
status = nfsd_rename(rqstp, save_fh, rename->rn_sname,
rename->rn_snamelen, current_fh,
rename->rn_tname, rename->rn_tnamelen);
@@ -624,6 +629,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
goto out;
}
+ if (filp)
+ get_file(filp);
nfs4_unlock_state();
write->wr_bytes_written = write->wr_buflen;
@@ -635,6 +642,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_writ
status = nfsd_write(rqstp, current_fh, filp, write->wr_offset,
write->wr_vec, write->wr_vlen, write->wr_buflen,
&write->wr_how_written);
+ if (filp)
+ fput(filp);
if (status == nfserr_symlink)
status = nfserr_inval;
@@ -923,6 +932,9 @@ encode_op:
nfs4_put_stateowner(replay_owner);
replay_owner = NULL;
}
+ /* XXX Ugh, we need to get rid of this kind of special case: */
+ if (op->opnum == OP_READ && op->u.read.rd_filp)
+ fput(op->u.read.rd_filp);
}
out:
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
new file mode 100644
index 000000000000..57ed50fe7f85
--- /dev/null
+++ b/fs/nfsd/nfs4recover.c
@@ -0,0 +1,421 @@
+/*
+* linux/fs/nfsd/nfs4recover.c
+*
+* Copyright (c) 2004 The Regents of the University of Michigan.
+* All rights reserved.
+*
+* Andy Adamson <andros@citi.umich.edu>
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions
+* are met:
+*
+* 1. Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* 2. Redistributions in binary form must reproduce the above copyright
+* notice, this list of conditions and the following disclaimer in the
+* documentation and/or other materials provided with the distribution.
+* 3. Neither the name of the University nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* 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 REGENTS OR CONTRIBUTORS 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.
+*
+*/
+
+
+#include <linux/sunrpc/svc.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/nfs4.h>
+#include <linux/nfsd/state.h>
+#include <linux/nfsd/xdr4.h>
+#include <linux/param.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <asm/uaccess.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+
+
+#define NFSDDBG_FACILITY NFSDDBG_PROC
+
+/* Globals */
+static struct nameidata rec_dir;
+static int rec_dir_init = 0;
+
+static void
+nfs4_save_user(uid_t *saveuid, gid_t *savegid)
+{
+ *saveuid = current->fsuid;
+ *savegid = current->fsgid;
+ current->fsuid = 0;
+ current->fsgid = 0;
+}
+
+static void
+nfs4_reset_user(uid_t saveuid, gid_t savegid)
+{
+ current->fsuid = saveuid;
+ current->fsgid = savegid;
+}
+
+static void
+md5_to_hex(char *out, char *md5)
+{
+ int i;
+
+ for (i=0; i<16; i++) {
+ unsigned char c = md5[i];
+
+ *out++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
+ *out++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
+ }
+ *out = '\0';
+}
+
+int
+nfs4_make_rec_clidname(char *dname, struct xdr_netobj *clname)
+{
+ struct xdr_netobj cksum;
+ struct crypto_tfm *tfm;
+ struct scatterlist sg[1];
+ int status = nfserr_resource;
+
+ dprintk("NFSD: nfs4_make_rec_clidname for %.*s\n",
+ clname->len, clname->data);
+ tfm = crypto_alloc_tfm("md5", 0);
+ if (tfm == NULL)
+ goto out;
+ cksum.len = crypto_tfm_alg_digestsize(tfm);
+ cksum.data = kmalloc(cksum.len, GFP_KERNEL);
+ if (cksum.data == NULL)
+ goto out;
+ crypto_digest_init(tfm);
+
+ sg[0].page = virt_to_page(clname->data);
+ sg[0].offset = offset_in_page(clname->data);
+ sg[0].length = clname->len;
+
+ crypto_digest_update(tfm, sg, 1);
+ crypto_digest_final(tfm, cksum.data);
+
+ md5_to_hex(dname, cksum.data);
+
+ kfree(cksum.data);
+ status = nfs_ok;
+out:
+ if (tfm)
+ crypto_free_tfm(tfm);
+ return status;
+}
+
+static void
+nfsd4_sync_rec_dir(void)
+{
+ down(&rec_dir.dentry->d_inode->i_sem);
+ nfsd_sync_dir(rec_dir.dentry);
+ up(&rec_dir.dentry->d_inode->i_sem);
+}
+
+int
+nfsd4_create_clid_dir(struct nfs4_client *clp)
+{
+ char *dname = clp->cl_recdir;
+ struct dentry *dentry;
+ uid_t uid;
+ gid_t gid;
+ int status;
+
+ dprintk("NFSD: nfsd4_create_clid_dir for \"%s\"\n", dname);
+
+ if (!rec_dir_init || clp->cl_firststate)
+ return 0;
+
+ nfs4_save_user(&uid, &gid);
+
+ /* lock the parent */
+ down(&rec_dir.dentry->d_inode->i_sem);
+
+ dentry = lookup_one_len(dname, rec_dir.dentry, HEXDIR_LEN-1);
+ if (IS_ERR(dentry)) {
+ status = PTR_ERR(dentry);
+ goto out_unlock;
+ }
+ status = -EEXIST;
+ if (dentry->d_inode) {
+ dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n");
+ goto out_put;
+ }
+ status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU);
+out_put:
+ dput(dentry);
+out_unlock:
+ up(&rec_dir.dentry->d_inode->i_sem);
+ if (status == 0) {
+ clp->cl_firststate = 1;
+ nfsd4_sync_rec_dir();
+ }
+ nfs4_reset_user(uid, gid);
+ dprintk("NFSD: nfsd4_create_clid_dir returns %d\n", status);
+ return status;
+}
+
+typedef int (recdir_func)(struct dentry *, struct dentry *);
+
+struct dentry_list {
+ struct dentry *dentry;
+ struct list_head list;
+};
+
+struct dentry_list_arg {
+ struct list_head dentries;
+ struct dentry *parent;
+};
+
+static int
+nfsd4_build_dentrylist(void *arg, const char *name, int namlen,
+ loff_t offset, ino_t ino, unsigned int d_type)
+{
+ struct dentry_list_arg *dla = arg;
+ struct list_head *dentries = &dla->dentries;
+ struct dentry *parent = dla->parent;
+ struct dentry *dentry;
+ struct dentry_list *child;
+
+ if (name && isdotent(name, namlen))
+ return nfs_ok;
+ dentry = lookup_one_len(name, parent, namlen);
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+ child = kmalloc(sizeof(*child), GFP_KERNEL);
+ if (child == NULL)
+ return -ENOMEM;
+ child->dentry = dentry;
+ list_add(&child->list, dentries);
+ return 0;
+}
+
+static int
+nfsd4_list_rec_dir(struct dentry *dir, recdir_func *f)
+{
+ struct file *filp;
+ struct dentry_list_arg dla = {
+ .parent = dir,
+ };
+ struct list_head *dentries = &dla.dentries;
+ struct dentry_list *child;
+ uid_t uid;
+ gid_t gid;
+ int status;
+
+ if (!rec_dir_init)
+ return 0;
+
+ nfs4_save_user(&uid, &gid);
+
+ filp = dentry_open(dget(dir), mntget(rec_dir.mnt),
+ O_RDWR);
+ status = PTR_ERR(filp);
+ if (IS_ERR(filp))
+ goto out;
+ INIT_LIST_HEAD(dentries);
+ status = vfs_readdir(filp, nfsd4_build_dentrylist, &dla);
+ fput(filp);
+ while (!list_empty(dentries)) {
+ child = list_entry(dentries->next, struct dentry_list, list);
+ status = f(dir, child->dentry);
+ if (status)
+ goto out;
+ list_del(&child->list);
+ dput(child->dentry);
+ kfree(child);
+ }
+out:
+ while (!list_empty(dentries)) {
+ child = list_entry(dentries->next, struct dentry_list, list);
+ list_del(&child->list);
+ dput(child->dentry);
+ kfree(child);
+ }
+ nfs4_reset_user(uid, gid);
+ return status;
+}
+
+static int
+nfsd4_remove_clid_file(struct dentry *dir, struct dentry *dentry)
+{
+ int status;
+
+ if (!S_ISREG(dir->d_inode->i_mode)) {
+ printk("nfsd4: non-file found in client recovery directory\n");
+ return -EINVAL;
+ }
+ down(&dir->d_inode->i_sem);
+ status = vfs_unlink(dir->d_inode, dentry);
+ up(&dir->d_inode->i_sem);
+ return status;
+}
+
+static int
+nfsd4_clear_clid_dir(struct dentry *dir, struct dentry *dentry)
+{
+ int status;
+
+ /* For now this directory should already be empty, but we empty it of
+ * any regular files anyway, just in case the directory was created by
+ * a kernel from the future.... */
+ nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file);
+ down(&dir->d_inode->i_sem);
+ status = vfs_rmdir(dir->d_inode, dentry);
+ up(&dir->d_inode->i_sem);
+ return status;
+}
+
+static int
+nfsd4_unlink_clid_dir(char *name, int namlen)
+{
+ struct dentry *dentry;
+ int status;
+
+ dprintk("NFSD: nfsd4_unlink_clid_dir. name %.*s\n", namlen, name);
+
+ down(&rec_dir.dentry->d_inode->i_sem);
+ dentry = lookup_one_len(name, rec_dir.dentry, namlen);
+ up(&rec_dir.dentry->d_inode->i_sem);
+ if (IS_ERR(dentry)) {
+ status = PTR_ERR(dentry);
+ return status;
+ }
+ status = -ENOENT;
+ if (!dentry->d_inode)
+ goto out;
+
+ status = nfsd4_clear_clid_dir(rec_dir.dentry, dentry);
+out:
+ dput(dentry);
+ return status;
+}
+
+void
+nfsd4_remove_clid_dir(struct nfs4_client *clp)
+{
+ uid_t uid;
+ gid_t gid;
+ int status;
+
+ if (!rec_dir_init || !clp->cl_firststate)
+ return;
+
+ clp->cl_firststate = 0;
+ nfs4_save_user(&uid, &gid);
+ status = nfsd4_unlink_clid_dir(clp->cl_recdir, HEXDIR_LEN-1);
+ nfs4_reset_user(uid, gid);
+ if (status == 0)
+ nfsd4_sync_rec_dir();
+ if (status)
+ printk("NFSD: Failed to remove expired client state directory"
+ " %.*s\n", HEXDIR_LEN, clp->cl_recdir);
+ return;
+}
+
+static int
+purge_old(struct dentry *parent, struct dentry *child)
+{
+ int status;
+
+ if (nfs4_has_reclaimed_state(child->d_name.name))
+ return nfs_ok;
+
+ status = nfsd4_clear_clid_dir(parent, child);
+ if (status)
+ printk("failed to remove client recovery directory %s\n",
+ child->d_name.name);
+ /* Keep trying, success or failure: */
+ return nfs_ok;
+}
+
+void
+nfsd4_recdir_purge_old(void) {
+ int status;
+
+ if (!rec_dir_init)
+ return;
+ status = nfsd4_list_rec_dir(rec_dir.dentry, purge_old);
+ if (status == 0)
+ nfsd4_sync_rec_dir();
+ if (status)
+ printk("nfsd4: failed to purge old clients from recovery"
+ " directory %s\n", rec_dir.dentry->d_name.name);
+ return;
+}
+
+static int
+load_recdir(struct dentry *parent, struct dentry *child)
+{
+ if (child->d_name.len != HEXDIR_LEN - 1) {
+ printk("nfsd4: illegal name %s in recovery directory\n",
+ child->d_name.name);
+ /* Keep trying; maybe the others are OK: */
+ return nfs_ok;
+ }
+ nfs4_client_to_reclaim(child->d_name.name);
+ return nfs_ok;
+}
+
+int
+nfsd4_recdir_load(void) {
+ int status;
+
+ status = nfsd4_list_rec_dir(rec_dir.dentry, load_recdir);
+ if (status)
+ printk("nfsd4: failed loading clients from recovery"
+ " directory %s\n", rec_dir.dentry->d_name.name);
+ return status;
+}
+
+/*
+ * Hold reference to the recovery directory.
+ */
+
+void
+nfsd4_init_recdir(char *rec_dirname)
+{
+ uid_t uid = 0;
+ gid_t gid = 0;
+ int status;
+
+ printk("NFSD: Using %s as the NFSv4 state recovery directory\n",
+ rec_dirname);
+
+ BUG_ON(rec_dir_init);
+
+ nfs4_save_user(&uid, &gid);
+
+ status = path_lookup(rec_dirname, LOOKUP_FOLLOW, &rec_dir);
+ if (status == -ENOENT)
+ printk("NFSD: recovery directory %s doesn't exist\n",
+ rec_dirname);
+
+ if (!status)
+ rec_dir_init = 1;
+ nfs4_reset_user(uid, gid);
+}
+
+void
+nfsd4_shutdown_recdir(void)
+{
+ if (!rec_dir_init)
+ return;
+ rec_dir_init = 0;
+ path_release(&rec_dir);
+}
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index 75e8b137580c..b83f8fb441e1 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -48,39 +48,32 @@
#include <linux/nfs4.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
+#include <linux/namei.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
/* Globals */
static time_t lease_time = 90; /* default lease time */
-static time_t old_lease_time = 90; /* past incarnation lease time */
-static u32 nfs4_reclaim_init = 0;
-time_t boot_time;
-static time_t grace_end = 0;
+static time_t user_lease_time = 90;
+static time_t boot_time;
+static int in_grace = 1;
static u32 current_clientid = 1;
static u32 current_ownerid = 1;
static u32 current_fileid = 1;
static u32 current_delegid = 1;
static u32 nfs4_init;
-stateid_t zerostateid; /* bits all 0 */
-stateid_t onestateid; /* bits all 1 */
-
-/* debug counters */
-u32 list_add_perfile = 0;
-u32 list_del_perfile = 0;
-u32 add_perclient = 0;
-u32 del_perclient = 0;
-u32 alloc_file = 0;
-u32 free_file = 0;
-u32 vfsopen = 0;
-u32 vfsclose = 0;
-u32 alloc_delegation= 0;
-u32 free_delegation= 0;
+static stateid_t zerostateid; /* bits all 0 */
+static stateid_t onestateid; /* bits all 1 */
+
+#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
+#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
/* forward declarations */
-struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
+static struct nfs4_stateid * find_stateid(stateid_t *stid, int flags);
static struct nfs4_delegation * find_delegation_stateid(struct inode *ino, stateid_t *stid);
static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
+static char user_recovery_dirname[PATH_MAX] = "/var/lib/nfs/v4recovery";
+static void nfs4_set_recdir(char *recdir);
/* Locking:
*
@@ -90,6 +83,11 @@ static void release_stateid_lockowners(struct nfs4_stateid *open_stp);
*/
static DECLARE_MUTEX(client_sema);
+static kmem_cache_t *stateowner_slab = NULL;
+static kmem_cache_t *file_slab = NULL;
+static kmem_cache_t *stateid_slab = NULL;
+static kmem_cache_t *deleg_slab = NULL;
+
void
nfs4_lock_state(void)
{
@@ -118,16 +116,36 @@ opaque_hashval(const void *ptr, int nbytes)
/* forward declarations */
static void release_stateowner(struct nfs4_stateowner *sop);
static void release_stateid(struct nfs4_stateid *stp, int flags);
-static void release_file(struct nfs4_file *fp);
/*
* Delegation state
*/
/* recall_lock protects the del_recall_lru */
-spinlock_t recall_lock;
+static spinlock_t recall_lock = SPIN_LOCK_UNLOCKED;
static struct list_head del_recall_lru;
+static void
+free_nfs4_file(struct kref *kref)
+{
+ struct nfs4_file *fp = container_of(kref, struct nfs4_file, fi_ref);
+ list_del(&fp->fi_hash);
+ iput(fp->fi_inode);
+ kmem_cache_free(file_slab, fp);
+}
+
+static inline void
+put_nfs4_file(struct nfs4_file *fi)
+{
+ kref_put(&fi->fi_ref, free_nfs4_file);
+}
+
+static inline void
+get_nfs4_file(struct nfs4_file *fi)
+{
+ kref_get(&fi->fi_ref);
+}
+
static struct nfs4_delegation *
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_fh *current_fh, u32 type)
{
@@ -136,13 +154,14 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
struct nfs4_callback *cb = &stp->st_stateowner->so_client->cl_callback;
dprintk("NFSD alloc_init_deleg\n");
- if ((dp = kmalloc(sizeof(struct nfs4_delegation),
- GFP_KERNEL)) == NULL)
+ dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
+ if (dp == NULL)
return dp;
- INIT_LIST_HEAD(&dp->dl_del_perfile);
- INIT_LIST_HEAD(&dp->dl_del_perclnt);
+ INIT_LIST_HEAD(&dp->dl_perfile);
+ INIT_LIST_HEAD(&dp->dl_perclnt);
INIT_LIST_HEAD(&dp->dl_recall_lru);
dp->dl_client = clp;
+ get_nfs4_file(fp);
dp->dl_file = fp;
dp->dl_flock = NULL;
get_file(stp->st_vfs_file);
@@ -160,9 +179,8 @@ alloc_init_deleg(struct nfs4_client *clp, struct nfs4_stateid *stp, struct svc_f
current_fh->fh_handle.fh_size);
dp->dl_time = 0;
atomic_set(&dp->dl_count, 1);
- list_add(&dp->dl_del_perfile, &fp->fi_del_perfile);
- list_add(&dp->dl_del_perclnt, &clp->cl_del_perclnt);
- alloc_delegation++;
+ list_add(&dp->dl_perfile, &fp->fi_delegations);
+ list_add(&dp->dl_perclnt, &clp->cl_delegations);
return dp;
}
@@ -171,8 +189,8 @@ nfs4_put_delegation(struct nfs4_delegation *dp)
{
if (atomic_dec_and_test(&dp->dl_count)) {
dprintk("NFSD: freeing dp %p\n",dp);
- kfree(dp);
- free_delegation++;
+ put_nfs4_file(dp->dl_file);
+ kmem_cache_free(deleg_slab, dp);
}
}
@@ -193,15 +211,14 @@ nfs4_close_delegation(struct nfs4_delegation *dp)
if (dp->dl_flock)
setlease(filp, F_UNLCK, &dp->dl_flock);
nfsd_close(filp);
- vfsclose++;
}
/* Called under the state lock. */
static void
unhash_delegation(struct nfs4_delegation *dp)
{
- list_del_init(&dp->dl_del_perfile);
- list_del_init(&dp->dl_del_perclnt);
+ list_del_init(&dp->dl_perfile);
+ list_del_init(&dp->dl_perclnt);
spin_lock(&recall_lock);
list_del_init(&dp->dl_recall_lru);
spin_unlock(&recall_lock);
@@ -220,8 +237,8 @@ unhash_delegation(struct nfs4_delegation *dp)
#define clientid_hashval(id) \
((id) & CLIENT_HASH_MASK)
-#define clientstr_hashval(name, namelen) \
- (opaque_hashval((name), (namelen)) & CLIENT_HASH_MASK)
+#define clientstr_hashval(name) \
+ (opaque_hashval((name), 8) & CLIENT_HASH_MASK)
/*
* reclaim_str_hashtbl[] holds known client info from previous reset/reboot
* used in reboot/reset lease grace period processing
@@ -331,11 +348,11 @@ expire_client(struct nfs4_client *clp)
INIT_LIST_HEAD(&reaplist);
spin_lock(&recall_lock);
- while (!list_empty(&clp->cl_del_perclnt)) {
- dp = list_entry(clp->cl_del_perclnt.next, struct nfs4_delegation, dl_del_perclnt);
+ while (!list_empty(&clp->cl_delegations)) {
+ dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
dprintk("NFSD: expire client. dp %p, fp %p\n", dp,
dp->dl_flock);
- list_del_init(&dp->dl_del_perclnt);
+ list_del_init(&dp->dl_perclnt);
list_move(&dp->dl_recall_lru, &reaplist);
}
spin_unlock(&recall_lock);
@@ -347,26 +364,26 @@ expire_client(struct nfs4_client *clp)
list_del(&clp->cl_idhash);
list_del(&clp->cl_strhash);
list_del(&clp->cl_lru);
- while (!list_empty(&clp->cl_perclient)) {
- sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
+ while (!list_empty(&clp->cl_openowners)) {
+ sop = list_entry(clp->cl_openowners.next, struct nfs4_stateowner, so_perclient);
release_stateowner(sop);
}
put_nfs4_client(clp);
}
static struct nfs4_client *
-create_client(struct xdr_netobj name) {
+create_client(struct xdr_netobj name, char *recdir) {
struct nfs4_client *clp;
if (!(clp = alloc_client(name)))
goto out;
+ memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
atomic_set(&clp->cl_count, 1);
atomic_set(&clp->cl_callback.cb_set, 0);
- clp->cl_callback.cb_parsed = 0;
INIT_LIST_HEAD(&clp->cl_idhash);
INIT_LIST_HEAD(&clp->cl_strhash);
- INIT_LIST_HEAD(&clp->cl_perclient);
- INIT_LIST_HEAD(&clp->cl_del_perclnt);
+ INIT_LIST_HEAD(&clp->cl_openowners);
+ INIT_LIST_HEAD(&clp->cl_delegations);
INIT_LIST_HEAD(&clp->cl_lru);
out:
return clp;
@@ -392,11 +409,9 @@ copy_cred(struct svc_cred *target, struct svc_cred *source) {
get_group_info(target->cr_group_info);
}
-static int
-cmp_name(struct xdr_netobj *n1, struct xdr_netobj *n2) {
- if (!n1 || !n2)
- return 0;
- return((n1->len == n2->len) && !memcmp(n1->data, n2->data, n2->len));
+static inline int
+same_name(const char *n1, const char *n2) {
+ return 0 == memcmp(n1, n2, HEXDIR_LEN);
}
static int
@@ -446,7 +461,7 @@ check_name(struct xdr_netobj name) {
return 1;
}
-void
+static void
add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
{
unsigned int idhashval;
@@ -458,7 +473,7 @@ add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
clp->cl_time = get_seconds();
}
-void
+static void
move_to_confirmed(struct nfs4_client *clp)
{
unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
@@ -468,8 +483,7 @@ move_to_confirmed(struct nfs4_client *clp)
list_del_init(&clp->cl_strhash);
list_del_init(&clp->cl_idhash);
list_add(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
- strhashval = clientstr_hashval(clp->cl_name.data,
- clp->cl_name.len);
+ strhashval = clientstr_hashval(clp->cl_recdir);
list_add(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
renew_client(clp);
}
@@ -500,6 +514,30 @@ find_unconfirmed_client(clientid_t *clid)
return NULL;
}
+static struct nfs4_client *
+find_confirmed_client_by_str(const char *dname, unsigned int hashval)
+{
+ struct nfs4_client *clp;
+
+ list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
+ if (same_name(clp->cl_recdir, dname))
+ return clp;
+ }
+ return NULL;
+}
+
+static struct nfs4_client *
+find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
+{
+ struct nfs4_client *clp;
+
+ list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
+ if (same_name(clp->cl_recdir, dname))
+ return clp;
+ }
+ return NULL;
+}
+
/* a helper function for parse_callback */
static int
parse_octet(unsigned int *lenp, char **addrp)
@@ -534,7 +572,7 @@ parse_octet(unsigned int *lenp, char **addrp)
}
/* parse and set the setclientid ipv4 callback address */
-int
+static int
parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigned short *cbportp)
{
int temp = 0;
@@ -570,7 +608,7 @@ parse_ipv4(unsigned int addr_len, char *addr_val, unsigned int *cbaddrp, unsigne
return 1;
}
-void
+static void
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
{
struct nfs4_callback *cb = &clp->cl_callback;
@@ -584,14 +622,12 @@ gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se)
goto out_err;
cb->cb_prog = se->se_callback_prog;
cb->cb_ident = se->se_callback_ident;
- cb->cb_parsed = 1;
return;
out_err:
printk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
"will not receive delegations\n",
clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- cb->cb_parsed = 0;
return;
}
@@ -638,59 +674,43 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
};
nfs4_verifier clverifier = setclid->se_verf;
unsigned int strhashval;
- struct nfs4_client * conf, * unconf, * new, * clp;
+ struct nfs4_client *conf, *unconf, *new;
int status;
+ char dname[HEXDIR_LEN];
status = nfserr_inval;
if (!check_name(clname))
goto out;
+ status = nfs4_make_rec_clidname(dname, &clname);
+ if (status)
+ goto out;
+
/*
* XXX The Duplicate Request Cache (DRC) has been checked (??)
* We get here on a DRC miss.
*/
- strhashval = clientstr_hashval(clname.data, clname.len);
+ strhashval = clientstr_hashval(dname);
- conf = NULL;
nfs4_lock_state();
- list_for_each_entry(clp, &conf_str_hashtbl[strhashval], cl_strhash) {
- if (!cmp_name(&clp->cl_name, &clname))
- continue;
+ conf = find_confirmed_client_by_str(dname, strhashval);
+ if (conf) {
/*
* CASE 0:
* clname match, confirmed, different principal
* or different ip_address
*/
status = nfserr_clid_inuse;
- if (!cmp_creds(&clp->cl_cred,&rqstp->rq_cred)) {
+ if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred)
+ || conf->cl_addr != ip_addr) {
printk("NFSD: setclientid: string in use by client"
"(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- goto out;
- }
- if (clp->cl_addr != ip_addr) {
- printk("NFSD: setclientid: string in use by client"
- "(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
+ conf->cl_clientid.cl_boot, conf->cl_clientid.cl_id);
goto out;
}
-
- /*
- * cl_name match from a previous SETCLIENTID operation
- * XXX check for additional matches?
- */
- conf = clp;
- break;
- }
- unconf = NULL;
- list_for_each_entry(clp, &unconf_str_hashtbl[strhashval], cl_strhash) {
- if (!cmp_name(&clp->cl_name, &clname))
- continue;
- /* cl_name match from a previous SETCLIENTID operation */
- unconf = clp;
- break;
}
+ unconf = find_unconfirmed_client_by_str(dname, strhashval);
status = nfserr_resource;
if (!conf) {
/*
@@ -699,7 +719,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
*/
if (unconf)
expire_client(unconf);
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new, &clverifier);
new->cl_addr = ip_addr;
@@ -722,12 +743,16 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
* nfs4_client, but with the new callback info and a
* new cl_confirm
*/
- if ((unconf) &&
- cmp_verf(&unconf->cl_verifier, &conf->cl_verifier) &&
- cmp_clid(&unconf->cl_clientid, &conf->cl_clientid)) {
- expire_client(unconf);
+ if (unconf) {
+ /* Note this is removing unconfirmed {*x***},
+ * which is stronger than RFC recommended {vxc**}.
+ * This has the advantage that there is at most
+ * one {*x***} in either list at any time.
+ */
+ expire_client(unconf);
}
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&conf->cl_verifier);
new->cl_addr = ip_addr;
@@ -745,7 +770,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
* using input clverifier, clname, and callback info
* and generate a new cl_clientid and cl_confirm.
*/
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&clverifier);
new->cl_addr = ip_addr;
@@ -771,7 +797,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid)
* new cl_verifier and a new cl_confirm
*/
expire_client(unconf);
- if (!(new = create_client(clname)))
+ new = create_client(clname, dname);
+ if (new == NULL)
goto out;
copy_verf(new,&clverifier);
new->cl_addr = ip_addr;
@@ -807,7 +834,7 @@ int
nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm)
{
u32 ip_addr = rqstp->rq_addr.sin_addr.s_addr;
- struct nfs4_client *clp, *conf = NULL, *unconf = NULL;
+ struct nfs4_client *conf, *unconf;
nfs4_verifier confirm = setclientid_confirm->sc_confirm;
clientid_t * clid = &setclientid_confirm->sc_clientid;
int status;
@@ -820,102 +847,91 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confi
*/
nfs4_lock_state();
- clp = find_confirmed_client(clid);
- if (clp) {
- status = nfserr_inval;
- /*
- * Found a record for this clientid. If the IP addresses
- * don't match, return ERR_INVAL just as if the record had
- * not been found.
- */
- if (clp->cl_addr != ip_addr) {
- printk("NFSD: setclientid: string in use by client"
- "(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- goto out;
- }
- conf = clp;
- }
- clp = find_unconfirmed_client(clid);
- if (clp) {
- status = nfserr_inval;
- if (clp->cl_addr != ip_addr) {
- printk("NFSD: setclientid: string in use by client"
- "(clientid %08x/%08x)\n",
- clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);
- goto out;
- }
- unconf = clp;
- }
- /* CASE 1:
- * unconf record that matches input clientid and input confirm.
- * conf record that matches input clientid.
- * conf and unconf records match names, verifiers
- */
+
+ conf = find_confirmed_client(clid);
+ unconf = find_unconfirmed_client(clid);
+
+ status = nfserr_clid_inuse;
+ if (conf && conf->cl_addr != ip_addr)
+ goto out;
+ if (unconf && unconf->cl_addr != ip_addr)
+ goto out;
+
if ((conf && unconf) &&
(cmp_verf(&unconf->cl_confirm, &confirm)) &&
(cmp_verf(&conf->cl_verifier, &unconf->cl_verifier)) &&
- (cmp_name(&conf->cl_name,&unconf->cl_name)) &&
+ (same_name(conf->cl_recdir,unconf->cl_recdir)) &&
(!cmp_verf(&conf->cl_confirm, &unconf->cl_confirm))) {
+ /* CASE 1:
+ * unconf record that matches input clientid and input confirm.
+ * conf record that matches input clientid.
+ * conf and unconf records match names, verifiers
+ */
if (!cmp_creds(&conf->cl_cred, &unconf->cl_cred))
status = nfserr_clid_inuse;
else {
- expire_client(conf);
- clp = unconf;
- move_to_confirmed(unconf);
+ /* XXX: We just turn off callbacks until we can handle
+ * change request correctly. */
+ atomic_set(&conf->cl_callback.cb_set, 0);
+ gen_confirm(conf);
+ nfsd4_remove_clid_dir(unconf);
+ expire_client(unconf);
status = nfs_ok;
+
}
- goto out;
- }
- /* CASE 2:
- * conf record that matches input clientid.
- * if unconf record that matches input clientid, then unconf->cl_name
- * or unconf->cl_verifier don't match the conf record.
- */
- if ((conf && !unconf) ||
+ } else if ((conf && !unconf) ||
((conf && unconf) &&
(!cmp_verf(&conf->cl_verifier, &unconf->cl_verifier) ||
- !cmp_name(&conf->cl_name, &unconf->cl_name)))) {
- if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred)) {
+ !same_name(conf->cl_recdir, unconf->cl_recdir)))) {
+ /* CASE 2:
+ * conf record that matches input clientid.
+ * if unconf record matches input clientid, then
+ * unconf->cl_name or unconf->cl_verifier don't match the
+ * conf record.
+ */
+ if (!cmp_creds(&conf->cl_cred,&rqstp->rq_cred))
status = nfserr_clid_inuse;
- } else {
- clp = conf;
+ else
status = nfs_ok;
- }
- goto out;
- }
- /* CASE 3:
- * conf record not found.
- * unconf record found.
- * unconf->cl_confirm matches input confirm
- */
- if (!conf && unconf && cmp_verf(&unconf->cl_confirm, &confirm)) {
+ } else if (!conf && unconf
+ && cmp_verf(&unconf->cl_confirm, &confirm)) {
+ /* CASE 3:
+ * conf record not found.
+ * unconf record found.
+ * unconf->cl_confirm matches input confirm
+ */
if (!cmp_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
status = nfserr_clid_inuse;
} else {
- status = nfs_ok;
- clp = unconf;
+ unsigned int hash =
+ clientstr_hashval(unconf->cl_recdir);
+ conf = find_confirmed_client_by_str(unconf->cl_recdir,
+ hash);
+ if (conf) {
+ nfsd4_remove_clid_dir(conf);
+ expire_client(conf);
+ }
move_to_confirmed(unconf);
+ conf = unconf;
+ status = nfs_ok;
}
- goto out;
- }
- /* CASE 4:
- * conf record not found, or if conf, then conf->cl_confirm does not
- * match input confirm.
- * unconf record not found, or if unconf, then unconf->cl_confirm
- * does not match input confirm.
- */
- if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm))) &&
- (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm, &confirm)))) {
+ } else if ((!conf || (conf && !cmp_verf(&conf->cl_confirm, &confirm)))
+ && (!unconf || (unconf && !cmp_verf(&unconf->cl_confirm,
+ &confirm)))) {
+ /* CASE 4:
+ * conf record not found, or if conf, conf->cl_confirm does not
+ * match input confirm.
+ * unconf record not found, or if unconf, unconf->cl_confirm
+ * does not match input confirm.
+ */
status = nfserr_stale_clientid;
- goto out;
+ } else {
+ /* check that we have hit one of the cases...*/
+ status = nfserr_clid_inuse;
}
- /* check that we have hit one of the cases...*/
- status = nfserr_inval;
- goto out;
out:
if (!status)
- nfsd4_probe_callback(clp);
+ nfsd4_probe_callback(conf);
nfs4_unlock_state();
return status;
}
@@ -961,60 +977,65 @@ alloc_init_file(struct inode *ino)
struct nfs4_file *fp;
unsigned int hashval = file_hashval(ino);
- if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
+ fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
+ if (fp) {
+ kref_init(&fp->fi_ref);
INIT_LIST_HEAD(&fp->fi_hash);
- INIT_LIST_HEAD(&fp->fi_perfile);
- INIT_LIST_HEAD(&fp->fi_del_perfile);
+ INIT_LIST_HEAD(&fp->fi_stateids);
+ INIT_LIST_HEAD(&fp->fi_delegations);
list_add(&fp->fi_hash, &file_hashtbl[hashval]);
fp->fi_inode = igrab(ino);
fp->fi_id = current_fileid++;
- alloc_file++;
return fp;
}
return NULL;
}
static void
-release_all_files(void)
+nfsd4_free_slab(kmem_cache_t **slab)
{
- int i;
- struct nfs4_file *fp;
+ int status;
- for (i=0;i<FILE_HASH_SIZE;i++) {
- while (!list_empty(&file_hashtbl[i])) {
- fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
- /* this should never be more than once... */
- if (!list_empty(&fp->fi_perfile) || !list_empty(&fp->fi_del_perfile)) {
- printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
- }
- release_file(fp);
- }
- }
+ if (*slab == NULL)
+ return;
+ status = kmem_cache_destroy(*slab);
+ *slab = NULL;
+ WARN_ON(status);
}
-kmem_cache_t *stateowner_slab = NULL;
+static void
+nfsd4_free_slabs(void)
+{
+ nfsd4_free_slab(&stateowner_slab);
+ nfsd4_free_slab(&file_slab);
+ nfsd4_free_slab(&stateid_slab);
+ nfsd4_free_slab(&deleg_slab);
+}
static int
nfsd4_init_slabs(void)
{
stateowner_slab = kmem_cache_create("nfsd4_stateowners",
sizeof(struct nfs4_stateowner), 0, 0, NULL, NULL);
- if (stateowner_slab == NULL) {
- dprintk("nfsd4: out of memory while initializing nfsv4\n");
- return -ENOMEM;
- }
+ if (stateowner_slab == NULL)
+ goto out_nomem;
+ file_slab = kmem_cache_create("nfsd4_files",
+ sizeof(struct nfs4_file), 0, 0, NULL, NULL);
+ if (file_slab == NULL)
+ goto out_nomem;
+ stateid_slab = kmem_cache_create("nfsd4_stateids",
+ sizeof(struct nfs4_stateid), 0, 0, NULL, NULL);
+ if (stateid_slab == NULL)
+ goto out_nomem;
+ deleg_slab = kmem_cache_create("nfsd4_delegations",
+ sizeof(struct nfs4_delegation), 0, 0, NULL, NULL);
+ if (deleg_slab == NULL)
+ goto out_nomem;
return 0;
-}
-
-static void
-nfsd4_free_slabs(void)
-{
- int status = 0;
-
- if (stateowner_slab)
- status = kmem_cache_destroy(stateowner_slab);
- stateowner_slab = NULL;
- BUG_ON(status);
+out_nomem:
+ nfsd4_free_slabs();
+ dprintk("nfsd4: out of memory while initializing nfsv4\n");
+ return -ENOMEM;
}
void
@@ -1055,14 +1076,13 @@ alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_idhash);
INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_perfilestate);
- INIT_LIST_HEAD(&sop->so_perlockowner); /* not used */
+ INIT_LIST_HEAD(&sop->so_stateids);
+ INIT_LIST_HEAD(&sop->so_perstateid); /* not used */
INIT_LIST_HEAD(&sop->so_close_lru);
sop->so_time = 0;
list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perclient, &clp->cl_perclient);
- add_perclient++;
+ list_add(&sop->so_perclient, &clp->cl_openowners);
sop->so_is_open_owner = 1;
sop->so_id = current_ownerid++;
sop->so_client = clp;
@@ -1080,10 +1100,10 @@ release_stateid_lockowners(struct nfs4_stateid *open_stp)
{
struct nfs4_stateowner *lock_sop;
- while (!list_empty(&open_stp->st_perlockowner)) {
- lock_sop = list_entry(open_stp->st_perlockowner.next,
- struct nfs4_stateowner, so_perlockowner);
- /* list_del(&open_stp->st_perlockowner); */
+ while (!list_empty(&open_stp->st_lockowners)) {
+ lock_sop = list_entry(open_stp->st_lockowners.next,
+ struct nfs4_stateowner, so_perstateid);
+ /* list_del(&open_stp->st_lockowners); */
BUG_ON(lock_sop->so_is_open_owner);
release_stateowner(lock_sop);
}
@@ -1096,14 +1116,12 @@ unhash_stateowner(struct nfs4_stateowner *sop)
list_del(&sop->so_idhash);
list_del(&sop->so_strhash);
- if (sop->so_is_open_owner) {
+ if (sop->so_is_open_owner)
list_del(&sop->so_perclient);
- del_perclient++;
- }
- list_del(&sop->so_perlockowner);
- while (!list_empty(&sop->so_perfilestate)) {
- stp = list_entry(sop->so_perfilestate.next,
- struct nfs4_stateid, st_perfilestate);
+ list_del(&sop->so_perstateid);
+ while (!list_empty(&sop->so_stateids)) {
+ stp = list_entry(sop->so_stateids.next,
+ struct nfs4_stateid, st_perstateowner);
if (sop->so_is_open_owner)
release_stateid(stp, OPEN_STATE);
else
@@ -1125,14 +1143,14 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
INIT_LIST_HEAD(&stp->st_hash);
- INIT_LIST_HEAD(&stp->st_perfilestate);
- INIT_LIST_HEAD(&stp->st_perlockowner);
+ INIT_LIST_HEAD(&stp->st_perstateowner);
+ INIT_LIST_HEAD(&stp->st_lockowners);
INIT_LIST_HEAD(&stp->st_perfile);
list_add(&stp->st_hash, &stateid_hashtbl[hashval]);
- list_add(&stp->st_perfilestate, &sop->so_perfilestate);
- list_add_perfile++;
- list_add(&stp->st_perfile, &fp->fi_perfile);
+ list_add(&stp->st_perstateowner, &sop->so_stateids);
+ list_add(&stp->st_perfile, &fp->fi_stateids);
stp->st_stateowner = sop;
+ get_nfs4_file(fp);
stp->st_file = fp;
stp->st_stateid.si_boot = boot_time;
stp->st_stateid.si_stateownerid = sop->so_id;
@@ -1142,6 +1160,7 @@ init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *
stp->st_deny_bmap = 0;
__set_bit(open->op_share_access, &stp->st_access_bmap);
__set_bit(open->op_share_deny, &stp->st_deny_bmap);
+ stp->st_openstp = NULL;
}
static void
@@ -1150,30 +1169,20 @@ release_stateid(struct nfs4_stateid *stp, int flags)
struct file *filp = stp->st_vfs_file;
list_del(&stp->st_hash);
- list_del_perfile++;
list_del(&stp->st_perfile);
- list_del(&stp->st_perfilestate);
+ list_del(&stp->st_perstateowner);
if (flags & OPEN_STATE) {
release_stateid_lockowners(stp);
stp->st_vfs_file = NULL;
nfsd_close(filp);
- vfsclose++;
} else if (flags & LOCK_STATE)
locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);
- kfree(stp);
+ put_nfs4_file(stp->st_file);
+ kmem_cache_free(stateid_slab, stp);
stp = NULL;
}
static void
-release_file(struct nfs4_file *fp)
-{
- free_file++;
- list_del(&fp->fi_hash);
- iput(fp->fi_inode);
- kfree(fp);
-}
-
-void
move_to_close_lru(struct nfs4_stateowner *sop)
{
dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);
@@ -1183,11 +1192,10 @@ move_to_close_lru(struct nfs4_stateowner *sop)
sop->so_time = get_seconds();
}
-void
+static void
release_state_owner(struct nfs4_stateid *stp, int flag)
{
struct nfs4_stateowner *sop = stp->st_stateowner;
- struct nfs4_file *fp = stp->st_file;
dprintk("NFSD: release_state_owner\n");
release_stateid(stp, flag);
@@ -1196,12 +1204,8 @@ release_state_owner(struct nfs4_stateid *stp, int flag)
* released by the laundromat service after the lease period
* to enable us to handle CLOSE replay
*/
- if (sop->so_confirmed && list_empty(&sop->so_perfilestate))
+ if (sop->so_confirmed && list_empty(&sop->so_stateids))
move_to_close_lru(sop);
- /* unused nfs4_file's are releseed. XXX slab cache? */
- if (list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile)) {
- release_file(fp);
- }
}
static int
@@ -1231,8 +1235,10 @@ find_file(struct inode *ino)
struct nfs4_file *fp;
list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
- if (fp->fi_inode == ino)
+ if (fp->fi_inode == ino) {
+ get_nfs4_file(fp);
return fp;
+ }
}
return NULL;
}
@@ -1240,7 +1246,7 @@ find_file(struct inode *ino)
#define TEST_ACCESS(x) ((x > 0 || x < 4)?1:0)
#define TEST_DENY(x) ((x >= 0 || x < 5)?1:0)
-void
+static void
set_access(unsigned int *access, unsigned long bmap) {
int i;
@@ -1251,7 +1257,7 @@ set_access(unsigned int *access, unsigned long bmap) {
}
}
-void
+static void
set_deny(unsigned int *deny, unsigned long bmap) {
int i;
@@ -1277,25 +1283,30 @@ test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
* Called to check deny when READ with all zero stateid or
* WRITE with all zero or all one stateid
*/
-int
+static int
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_file *fp;
struct nfs4_stateid *stp;
+ int ret;
dprintk("NFSD: nfs4_share_conflict\n");
fp = find_file(ino);
- if (fp) {
+ if (!fp)
+ return nfs_ok;
+ ret = nfserr_locked;
/* Search for conflicting share reservations */
- list_for_each_entry(stp, &fp->fi_perfile, st_perfile) {
- if (test_bit(deny_type, &stp->st_deny_bmap) ||
- test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
- return nfserr_share_denied;
- }
+ list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
+ if (test_bit(deny_type, &stp->st_deny_bmap) ||
+ test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
+ goto out;
}
- return nfs_ok;
+ ret = nfs_ok;
+out:
+ put_nfs4_file(fp);
+ return ret;
}
static inline void
@@ -1427,7 +1438,7 @@ int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
return -EAGAIN;
}
-struct lock_manager_operations nfsd_lease_mng_ops = {
+static struct lock_manager_operations nfsd_lease_mng_ops = {
.fl_break = nfsd_break_deleg_cb,
.fl_release_private = nfsd_release_deleg_cb,
.fl_copy_lock = nfsd_copy_lock_deleg_cb,
@@ -1473,7 +1484,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
if (sop) {
open->op_stateowner = sop;
/* check for replay */
- if (open->op_seqid == sop->so_seqid){
+ if (open->op_seqid == sop->so_seqid - 1){
if (sop->so_replay.rp_buflen)
return NFSERR_REPLAY_ME;
else {
@@ -1488,7 +1499,7 @@ nfsd4_process_open1(struct nfsd4_open *open)
goto renew;
}
} else if (sop->so_confirmed) {
- if (open->op_seqid == sop->so_seqid + 1)
+ if (open->op_seqid == sop->so_seqid)
goto renew;
status = nfserr_bad_seqid;
goto out;
@@ -1521,11 +1532,54 @@ renew:
status = nfs_ok;
renew_client(sop->so_client);
out:
- if (status && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
- status = nfserr_reclaim_bad;
return status;
}
+static inline int
+nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
+{
+ if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
+ return nfserr_openmode;
+ else
+ return nfs_ok;
+}
+
+static struct nfs4_delegation *
+find_delegation_file(struct nfs4_file *fp, stateid_t *stid)
+{
+ struct nfs4_delegation *dp;
+
+ list_for_each_entry(dp, &fp->fi_delegations, dl_perfile) {
+ if (dp->dl_stateid.si_stateownerid == stid->si_stateownerid)
+ return dp;
+ }
+ return NULL;
+}
+
+static int
+nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
+ struct nfs4_delegation **dp)
+{
+ int flags;
+ int status = nfserr_bad_stateid;
+
+ *dp = find_delegation_file(fp, &open->op_delegate_stateid);
+ if (*dp == NULL)
+ goto out;
+ flags = open->op_share_access == NFS4_SHARE_ACCESS_READ ?
+ RD_STATE : WR_STATE;
+ status = nfs4_check_delegmode(*dp, flags);
+ if (status)
+ *dp = NULL;
+out:
+ if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)
+ return nfs_ok;
+ if (status)
+ return status;
+ open->op_stateowner->so_confirmed = 1;
+ return nfs_ok;
+}
+
static int
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_stateid **stpp)
{
@@ -1533,7 +1587,7 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_state
int status = nfserr_share_denied;
struct nfs4_stateowner *sop = open->op_stateowner;
- list_for_each_entry(local, &fp->fi_perfile, st_perfile) {
+ list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
/* ignore lock owners */
if (local->st_stateowner->so_is_open_owner == 0)
continue;
@@ -1549,25 +1603,37 @@ out:
return status;
}
+static inline struct nfs4_stateid *
+nfs4_alloc_stateid(void)
+{
+ return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
+}
+
static int
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_stateid **stpp,
+ struct nfs4_delegation *dp,
struct svc_fh *cur_fh, int flags)
{
struct nfs4_stateid *stp;
- int status;
- stp = kmalloc(sizeof(struct nfs4_stateid), GFP_KERNEL);
+ stp = nfs4_alloc_stateid();
if (stp == NULL)
return nfserr_resource;
- status = nfsd_open(rqstp, cur_fh, S_IFREG, flags, &stp->st_vfs_file);
- if (status) {
- if (status == nfserr_dropit)
- status = nfserr_jukebox;
- kfree(stp);
- return status;
+ if (dp) {
+ get_file(dp->dl_vfs_file);
+ stp->st_vfs_file = dp->dl_vfs_file;
+ } else {
+ int status;
+ status = nfsd_open(rqstp, cur_fh, S_IFREG, flags,
+ &stp->st_vfs_file);
+ if (status) {
+ if (status == nfserr_dropit)
+ status = nfserr_jukebox;
+ kmem_cache_free(stateid_slab, stp);
+ return status;
+ }
}
- vfsopen++;
*stpp = stp;
return 0;
}
@@ -1619,18 +1685,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta
}
-/* decrement seqid on successful reclaim, it will be bumped in encode_open */
static void
-nfs4_set_claim_prev(struct nfsd4_open *open, int *status)
+nfs4_set_claim_prev(struct nfsd4_open *open)
{
- if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS) {
- if (*status)
- *status = nfserr_reclaim_bad;
- else {
- open->op_stateowner->so_confirmed = 1;
- open->op_stateowner->so_seqid--;
- }
- }
+ open->op_stateowner->so_confirmed = 1;
+ open->op_stateowner->so_client->cl_firststate = 1;
}
/*
@@ -1646,14 +1705,30 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
int status, flag = 0;
flag = NFS4_OPEN_DELEGATE_NONE;
- if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL
- || !atomic_read(&cb->cb_set) || !sop->so_confirmed)
- goto out;
-
- if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
- flag = NFS4_OPEN_DELEGATE_WRITE;
- else
- flag = NFS4_OPEN_DELEGATE_READ;
+ open->op_recall = 0;
+ switch (open->op_claim_type) {
+ case NFS4_OPEN_CLAIM_PREVIOUS:
+ if (!atomic_read(&cb->cb_set))
+ open->op_recall = 1;
+ flag = open->op_delegate_type;
+ if (flag == NFS4_OPEN_DELEGATE_NONE)
+ goto out;
+ break;
+ case NFS4_OPEN_CLAIM_NULL:
+ /* Let's not give out any delegations till everyone's
+ * had the chance to reclaim theirs.... */
+ if (nfs4_in_grace())
+ goto out;
+ if (!atomic_read(&cb->cb_set) || !sop->so_confirmed)
+ goto out;
+ if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
+ flag = NFS4_OPEN_DELEGATE_WRITE;
+ else
+ flag = NFS4_OPEN_DELEGATE_READ;
+ break;
+ default:
+ goto out;
+ }
dp = alloc_init_deleg(sop->so_client, stp, fh, flag);
if (dp == NULL) {
@@ -1687,6 +1762,10 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_sta
dp->dl_stateid.si_fileid,
dp->dl_stateid.si_generation);
out:
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
+ && flag == NFS4_OPEN_DELEGATE_NONE
+ && open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
+ printk("NFSD: WARNING: refusing delegation reclaim\n");
open->op_delegate_type = flag;
}
@@ -1699,8 +1778,15 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
struct nfs4_file *fp = NULL;
struct inode *ino = current_fh->fh_dentry->d_inode;
struct nfs4_stateid *stp = NULL;
+ struct nfs4_delegation *dp = NULL;
int status;
+ if (nfs4_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_grace;
+
+ if (!nfs4_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ return nfserr_no_grace;
+
status = nfserr_inval;
if (!TEST_ACCESS(open->op_share_access) || !TEST_DENY(open->op_share_deny))
goto out;
@@ -1713,7 +1799,13 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
if (fp) {
if ((status = nfs4_check_open(fp, open, &stp)))
goto out;
+ status = nfs4_check_deleg(fp, open, &dp);
+ if (status)
+ goto out;
} else {
+ status = nfserr_bad_stateid;
+ if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
+ goto out;
status = nfserr_resource;
fp = alloc_init_file(ino);
if (fp == NULL)
@@ -1729,6 +1821,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
status = nfs4_upgrade_open(rqstp, current_fh, stp, open);
if (status)
goto out;
+ update_stateid(&stp->st_stateid);
} else {
/* Stateid was not found, this is a new OPEN */
int flags = 0;
@@ -1736,7 +1829,8 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
flags = MAY_WRITE;
else
flags = MAY_READ;
- if ((status = nfs4_new_open(rqstp, &stp, current_fh, flags)))
+ status = nfs4_new_open(rqstp, &stp, dp, current_fh, flags);
+ if (status)
goto out;
init_stateid(stp, fp, open);
status = nfsd4_truncate(rqstp, current_fh, open);
@@ -1759,12 +1853,10 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
out:
- /* take the opportunity to clean up unused state */
- if (fp && list_empty(&fp->fi_perfile) && list_empty(&fp->fi_del_perfile))
- release_file(fp);
-
- /* CLAIM_PREVIOUS has different error returns */
- nfs4_set_claim_prev(open, &status);
+ if (fp)
+ put_nfs4_file(fp);
+ if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
+ nfs4_set_claim_prev(open);
/*
* To finish the open response, we just need to set the rflags.
*/
@@ -1775,6 +1867,7 @@ out:
return status;
}
+static struct workqueue_struct *laundry_wq;
static struct work_struct laundromat_work;
static void laundromat_main(void *);
static DECLARE_WORK(laundromat_work, laundromat_main, NULL);
@@ -1800,7 +1893,7 @@ nfsd4_renew(clientid_t *clid)
}
renew_client(clp);
status = nfserr_cb_path_down;
- if (!list_empty(&clp->cl_del_perclnt)
+ if (!list_empty(&clp->cl_delegations)
&& !atomic_read(&clp->cl_callback.cb_set))
goto out;
status = nfs_ok;
@@ -1809,7 +1902,15 @@ out:
return status;
}
-time_t
+static void
+end_grace(void)
+{
+ dprintk("NFSD: end of grace period\n");
+ nfsd4_recdir_purge_old();
+ in_grace = 0;
+}
+
+static time_t
nfs4_laundromat(void)
{
struct nfs4_client *clp;
@@ -1823,6 +1924,8 @@ nfs4_laundromat(void)
nfs4_lock_state();
dprintk("NFSD: laundromat service - starting\n");
+ if (in_grace)
+ end_grace();
list_for_each_safe(pos, next, &client_lru) {
clp = list_entry(pos, struct nfs4_client, cl_lru);
if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
@@ -1833,6 +1936,7 @@ nfs4_laundromat(void)
}
dprintk("NFSD: purging unused client (clientid %08x)\n",
clp->cl_clientid.cl_id);
+ nfsd4_remove_clid_dir(clp);
expire_client(clp);
}
INIT_LIST_HEAD(&reaplist);
@@ -1882,17 +1986,14 @@ laundromat_main(void *not_used)
t = nfs4_laundromat();
dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
- schedule_delayed_work(&laundromat_work, t*HZ);
+ queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
}
-/* search ownerid_hashtbl[] and close_lru for stateid owner
- * (stateid->si_stateownerid)
- */
-struct nfs4_stateowner *
-find_openstateowner_id(u32 st_id, int flags) {
+static struct nfs4_stateowner *
+search_close_lru(u32 st_id, int flags)
+{
struct nfs4_stateowner *local = NULL;
- dprintk("NFSD: find_openstateowner_id %d\n", st_id);
if (flags & CLOSE_STATE) {
list_for_each_entry(local, &close_lru, so_close_lru) {
if (local->so_id == st_id)
@@ -1949,15 +2050,6 @@ out:
}
static inline int
-nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
-{
- if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
- return nfserr_openmode;
- else
- return nfs_ok;
-}
-
-static inline int
check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
{
/* Trying to call delegreturn with a special stateid? Yuch: */
@@ -2067,14 +2159,19 @@ out:
return status;
}
+static inline int
+setlkflg (int type)
+{
+ return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
+ RD_STATE : WR_STATE;
+}
/*
* Checks for sequence id mutating operations.
*/
-int
-nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, clientid_t *lockclid)
+static int
+nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *stateid, int flags, struct nfs4_stateowner **sopp, struct nfs4_stateid **stpp, struct nfsd4_lock *lock)
{
- int status;
struct nfs4_stateid *stp;
struct nfs4_stateowner *sop;
@@ -2082,53 +2179,65 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
"stateid = (%08x/%08x/%08x/%08x)\n", seqid,
stateid->si_boot, stateid->si_stateownerid, stateid->si_fileid,
stateid->si_generation);
-
+
*stpp = NULL;
*sopp = NULL;
- status = nfserr_bad_stateid;
if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) {
printk("NFSD: preprocess_seqid_op: magic stateid!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_stale_stateid;
if (STALE_STATEID(stateid))
- goto out;
+ return nfserr_stale_stateid;
/*
* We return BAD_STATEID if filehandle doesn't match stateid,
* the confirmed flag is incorrecly set, or the generation
* number is incorrect.
- * If there is no entry in the openfile table for this id,
- * we can't always return BAD_STATEID;
- * this might be a retransmitted CLOSE which has arrived after
- * the openfile has been released.
*/
- if (!(stp = find_stateid(stateid, flags)))
- goto no_nfs4_stateid;
-
- status = nfserr_bad_stateid;
+ stp = find_stateid(stateid, flags);
+ if (stp == NULL) {
+ /*
+ * Also, we should make sure this isn't just the result of
+ * a replayed close:
+ */
+ sop = search_close_lru(stateid->si_stateownerid, flags);
+ if (sop == NULL)
+ return nfserr_bad_stateid;
+ *sopp = sop;
+ goto check_replay;
+ }
- /* for new lock stateowners:
- * check that the lock->v.new.open_stateid
- * refers to an open stateowner
- *
- * check that the lockclid (nfs4_lock->v.new.clientid) is the same
- * as the open_stateid->st_stateowner->so_client->clientid
- */
- if (lockclid) {
+ if (lock) {
struct nfs4_stateowner *sop = stp->st_stateowner;
+ clientid_t *lockclid = &lock->v.new.clientid;
struct nfs4_client *clp = sop->so_client;
+ int lkflg = 0;
+ int status;
+
+ lkflg = setlkflg(lock->lk_type);
+
+ if (lock->lk_is_new) {
+ if (!sop->so_is_open_owner)
+ return nfserr_bad_stateid;
+ if (!cmp_clid(&clp->cl_clientid, lockclid))
+ return nfserr_bad_stateid;
+ /* stp is the open stateid */
+ status = nfs4_check_openmode(stp, lkflg);
+ if (status)
+ return status;
+ } else {
+ /* stp is the lock stateid */
+ status = nfs4_check_openmode(stp->st_openstp, lkflg);
+ if (status)
+ return status;
+ }
- if (!sop->so_is_open_owner)
- goto out;
- if (!cmp_clid(&clp->cl_clientid, lockclid))
- goto out;
}
if ((flags & CHECK_FH) && nfs4_check_fh(current_fh, stp)) {
printk("NFSD: preprocess_seqid_op: fh-stateid mismatch!\n");
- goto out;
+ return nfserr_bad_stateid;
}
*stpp = stp;
@@ -2139,63 +2248,41 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei
* For the moment, we ignore the possibility of
* generation number wraparound.
*/
- if (seqid != sop->so_seqid + 1)
+ if (seqid != sop->so_seqid)
goto check_replay;
- if (sop->so_confirmed) {
- if (flags & CONFIRM) {
- printk("NFSD: preprocess_seqid_op: expected unconfirmed stateowner!\n");
- goto out;
- }
+ if (sop->so_confirmed && flags & CONFIRM) {
+ printk("NFSD: preprocess_seqid_op: expected"
+ " unconfirmed stateowner!\n");
+ return nfserr_bad_stateid;
}
- else {
- if (!(flags & CONFIRM)) {
- printk("NFSD: preprocess_seqid_op: stateowner not confirmed yet!\n");
- goto out;
- }
+ if (!sop->so_confirmed && !(flags & CONFIRM)) {
+ printk("NFSD: preprocess_seqid_op: stateowner not"
+ " confirmed yet!\n");
+ return nfserr_bad_stateid;
}
if (stateid->si_generation > stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: future stateid?!\n");
- goto out;
+ return nfserr_bad_stateid;
}
- status = nfserr_old_stateid;
if (stateid->si_generation < stp->st_stateid.si_generation) {
printk("NFSD: preprocess_seqid_op: old stateid!\n");
- goto out;
- }
- /* XXX renew the client lease here */
- status = nfs_ok;
-
-out:
- return status;
-
-no_nfs4_stateid:
-
- /*
- * We determine whether this is a bad stateid or a replay,
- * starting by trying to look up the stateowner.
- * If stateowner is not found - stateid is bad.
- */
- if (!(sop = find_openstateowner_id(stateid->si_stateownerid, flags))) {
- printk("NFSD: preprocess_seqid_op: no stateowner or nfs4_stateid!\n");
- status = nfserr_bad_stateid;
- goto out;
+ return nfserr_old_stateid;
}
- *sopp = sop;
+ renew_client(sop->so_client);
+ return nfs_ok;
check_replay:
- if (seqid == sop->so_seqid) {
+ if (seqid == sop->so_seqid - 1) {
printk("NFSD: preprocess_seqid_op: retransmission?\n");
/* indicate replay to calling function */
- status = NFSERR_REPLAY_ME;
- } else {
- printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid);
-
- *sopp = NULL;
- status = nfserr_bad_seqid;
+ return NFSERR_REPLAY_ME;
}
- goto out;
+ printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d)\n",
+ sop->so_seqid, seqid);
+ *sopp = NULL;
+ return nfserr_bad_seqid;
}
int
@@ -2230,6 +2317,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfs
stp->st_stateid.si_stateownerid,
stp->st_stateid.si_fileid,
stp->st_stateid.si_generation);
+
+ nfsd4_create_clid_dir(sop->so_client);
out:
if (oc->oc_stateowner)
nfs4_get_stateowner(oc->oc_stateowner);
@@ -2387,7 +2476,7 @@ static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head lock_ownerstr_hashtbl[LOCK_HASH_SIZE];
static struct list_head lockstateid_hashtbl[STATEID_HASH_SIZE];
-struct nfs4_stateid *
+static struct nfs4_stateid *
find_stateid(stateid_t *stid, int flags)
{
struct nfs4_stateid *local = NULL;
@@ -2419,25 +2508,19 @@ find_stateid(stateid_t *stid, int flags)
static struct nfs4_delegation *
find_delegation_stateid(struct inode *ino, stateid_t *stid)
{
- struct nfs4_delegation *dp = NULL;
- struct nfs4_file *fp = NULL;
- u32 st_id;
+ struct nfs4_file *fp;
+ struct nfs4_delegation *dl;
dprintk("NFSD:find_delegation_stateid stateid=(%08x/%08x/%08x/%08x)\n",
stid->si_boot, stid->si_stateownerid,
stid->si_fileid, stid->si_generation);
- st_id = stid->si_stateownerid;
fp = find_file(ino);
- if (fp) {
- list_for_each_entry(dp, &fp->fi_del_perfile, dl_del_perfile) {
- if(dp->dl_stateid.si_stateownerid == st_id) {
- dprintk("NFSD: find_delegation dp %p\n",dp);
- return dp;
- }
- }
- }
- return NULL;
+ if (!fp)
+ return NULL;
+ dl = find_delegation_file(fp, stid);
+ put_nfs4_file(fp);
+ return dl;
}
/*
@@ -2457,7 +2540,7 @@ nfs4_transform_lock_offset(struct file_lock *lock)
lock->fl_end = OFFSET_MAX;
}
-int
+static int
nfs4_verify_lock_stateowner(struct nfs4_stateowner *sop, unsigned int hashval)
{
struct nfs4_stateowner *local = NULL;
@@ -2498,22 +2581,6 @@ nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
}
static struct nfs4_stateowner *
-find_lockstateowner(struct xdr_netobj *owner, clientid_t *clid)
-{
- struct nfs4_stateowner *local = NULL;
- int i;
-
- for (i = 0; i < LOCK_HASH_SIZE; i++) {
- list_for_each_entry(local, &lock_ownerid_hashtbl[i], so_idhash) {
- if (!cmp_owner_str(local, owner, clid))
- continue;
- return local;
- }
- }
- return NULL;
-}
-
-static struct nfs4_stateowner *
find_lockstateowner_str(struct inode *inode, clientid_t *clid,
struct xdr_netobj *owner)
{
@@ -2533,7 +2600,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid,
* occured.
*
* strhashval = lock_ownerstr_hashval
- * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode
*/
static struct nfs4_stateowner *
@@ -2548,17 +2614,17 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
INIT_LIST_HEAD(&sop->so_idhash);
INIT_LIST_HEAD(&sop->so_strhash);
INIT_LIST_HEAD(&sop->so_perclient);
- INIT_LIST_HEAD(&sop->so_perfilestate);
- INIT_LIST_HEAD(&sop->so_perlockowner);
+ INIT_LIST_HEAD(&sop->so_stateids);
+ INIT_LIST_HEAD(&sop->so_perstateid);
INIT_LIST_HEAD(&sop->so_close_lru); /* not used */
sop->so_time = 0;
list_add(&sop->so_idhash, &lock_ownerid_hashtbl[idhashval]);
list_add(&sop->so_strhash, &lock_ownerstr_hashtbl[strhashval]);
- list_add(&sop->so_perlockowner, &open_stp->st_perlockowner);
+ list_add(&sop->so_perstateid, &open_stp->st_lockowners);
sop->so_is_open_owner = 0;
sop->so_id = current_ownerid++;
sop->so_client = clp;
- sop->so_seqid = lock->lk_new_lock_seqid - 1;
+ sop->so_seqid = lock->lk_new_lock_seqid;
sop->so_confirmed = 1;
rp = &sop->so_replay;
rp->rp_status = NFSERR_SERVERFAULT;
@@ -2567,24 +2633,24 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str
return sop;
}
-struct nfs4_stateid *
+static struct nfs4_stateid *
alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struct nfs4_stateid *open_stp)
{
struct nfs4_stateid *stp;
unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);
- if ((stp = kmalloc(sizeof(struct nfs4_stateid),
- GFP_KERNEL)) == NULL)
+ stp = nfs4_alloc_stateid();
+ if (stp == NULL)
goto out;
INIT_LIST_HEAD(&stp->st_hash);
INIT_LIST_HEAD(&stp->st_perfile);
- INIT_LIST_HEAD(&stp->st_perfilestate);
- INIT_LIST_HEAD(&stp->st_perlockowner); /* not used */
+ INIT_LIST_HEAD(&stp->st_perstateowner);
+ INIT_LIST_HEAD(&stp->st_lockowners); /* not used */
list_add(&stp->st_hash, &lockstateid_hashtbl[hashval]);
- list_add(&stp->st_perfile, &fp->fi_perfile);
- list_add_perfile++;
- list_add(&stp->st_perfilestate, &sop->so_perfilestate);
+ list_add(&stp->st_perfile, &fp->fi_stateids);
+ list_add(&stp->st_perstateowner, &sop->so_stateids);
stp->st_stateowner = sop;
+ get_nfs4_file(fp);
stp->st_file = fp;
stp->st_stateid.si_boot = boot_time;
stp->st_stateid.si_stateownerid = sop->so_id;
@@ -2593,12 +2659,13 @@ alloc_init_lock_stateid(struct nfs4_stateowner *sop, struct nfs4_file *fp, struc
stp->st_vfs_file = open_stp->st_vfs_file; /* FIXME refcount?? */
stp->st_access_bmap = open_stp->st_access_bmap;
stp->st_deny_bmap = open_stp->st_deny_bmap;
+ stp->st_openstp = open_stp;
out:
return stp;
}
-int
+static int
check_lock_length(u64 offset, u64 length)
{
return ((length == 0) || ((length != ~(u64)0) &&
@@ -2611,7 +2678,7 @@ check_lock_length(u64 offset, u64 length)
int
nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock *lock)
{
- struct nfs4_stateowner *lock_sop = NULL, *open_sop = NULL;
+ struct nfs4_stateowner *open_sop = NULL;
struct nfs4_stateid *lock_stp;
struct file *filp;
struct file_lock file_lock;
@@ -2623,22 +2690,17 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
(long long) lock->lk_offset,
(long long) lock->lk_length);
- if (nfs4_in_grace() && !lock->lk_reclaim)
- return nfserr_grace;
- if (!nfs4_in_grace() && lock->lk_reclaim)
- return nfserr_no_grace;
-
if (check_lock_length(lock->lk_offset, lock->lk_length))
return nfserr_inval;
nfs4_lock_state();
if (lock->lk_is_new) {
- /*
- * Client indicates that this is a new lockowner.
- * Use open owner and open stateid to create lock owner and lock
- * stateid.
- */
+ /*
+ * Client indicates that this is a new lockowner.
+ * Use open owner and open stateid to create lock owner and
+ * lock stateid.
+ */
struct nfs4_stateid *open_stp = NULL;
struct nfs4_file *fp;
@@ -2648,38 +2710,22 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
}
- /* is the new lock seqid presented by the client zero? */
- status = nfserr_bad_seqid;
- if (lock->v.new.lock_seqid != 0)
- goto out;
-
/* validate and update open stateid and open seqid */
status = nfs4_preprocess_seqid_op(current_fh,
lock->lk_new_open_seqid,
&lock->lk_new_open_stateid,
CHECK_FH | OPEN_STATE,
- &open_sop, &open_stp,
- &lock->v.new.clientid);
- if (status) {
- if (lock->lk_reclaim)
- status = nfserr_reclaim_bad;
+ &open_sop, &open_stp, lock);
+ if (status)
goto out;
- }
/* create lockowner and lock stateid */
fp = open_stp->st_file;
strhashval = lock_ownerstr_hashval(fp->fi_inode,
open_sop->so_client->cl_clientid.cl_id,
&lock->v.new.owner);
- /*
- * If we already have this lock owner, the client is in
- * error (or our bookeeping is wrong!)
- * for asking for a 'new lock'.
- */
- status = nfserr_bad_stateid;
- lock_sop = find_lockstateowner(&lock->v.new.owner,
- &lock->v.new.clientid);
- if (lock_sop)
- goto out;
+ /* XXX: Do we need to check for duplicate stateowners on
+ * the same file, or should they just be allowed (and
+ * create new stateids)? */
status = nfserr_resource;
if (!(lock->lk_stateowner = alloc_init_lock_stateowner(strhashval, open_sop->so_client, open_stp, lock)))
goto out;
@@ -2697,7 +2743,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
lock->lk_old_lock_seqid,
&lock->lk_old_lock_stateid,
CHECK_FH | LOCK_STATE,
- &lock->lk_stateowner, &lock_stp, NULL);
+ &lock->lk_stateowner, &lock_stp, lock);
if (status)
goto out;
}
@@ -2709,6 +2755,13 @@ nfsd4_lock(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_lock
goto out;
}
+ status = nfserr_grace;
+ if (nfs4_in_grace() && !lock->lk_reclaim)
+ goto out;
+ status = nfserr_no_grace;
+ if (!nfs4_in_grace() && lock->lk_reclaim)
+ goto out;
+
locks_init_lock(&file_lock);
switch (lock->lk_type) {
case NFS4_READ_LT:
@@ -2775,10 +2828,10 @@ conflicting_lock:
out_destroy_new_stateid:
if (lock->lk_is_new) {
dprintk("NFSD: nfsd4_lock: destroy new stateid!\n");
- /*
- * An error encountered after instantiation of the new
- * stateid has forced us to destroy it.
- */
+ /*
+ * An error encountered after instantiation of the new
+ * stateid has forced us to destroy it.
+ */
if (!seqid_mutating_err(status))
open_sop->so_seqid--;
@@ -2970,8 +3023,11 @@ int
nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *rlockowner)
{
clientid_t *clid = &rlockowner->rl_clientid;
- struct nfs4_stateowner *local = NULL;
+ struct nfs4_stateowner *sop;
+ struct nfs4_stateid *stp;
struct xdr_netobj *owner = &rlockowner->rl_owner;
+ struct list_head matches;
+ int i;
int status;
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
@@ -2987,22 +3043,37 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp, struct nfsd4_release_lockowner *
nfs4_lock_state();
- status = nfs_ok;
- local = find_lockstateowner(owner, clid);
- if (local) {
- struct nfs4_stateid *stp;
-
- /* check for any locks held by any stateid
- * associated with the (lock) stateowner */
- status = nfserr_locks_held;
- list_for_each_entry(stp, &local->so_perfilestate,
- st_perfilestate) {
- if (check_for_locks(stp->st_vfs_file, local))
- goto out;
+ status = nfserr_locks_held;
+ /* XXX: we're doing a linear search through all the lockowners.
+ * Yipes! For now we'll just hope clients aren't really using
+ * release_lockowner much, but eventually we have to fix these
+ * data structures. */
+ INIT_LIST_HEAD(&matches);
+ for (i = 0; i < LOCK_HASH_SIZE; i++) {
+ list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
+ if (!cmp_owner_str(sop, owner, clid))
+ continue;
+ list_for_each_entry(stp, &sop->so_stateids,
+ st_perstateowner) {
+ if (check_for_locks(stp->st_vfs_file, sop))
+ goto out;
+ /* Note: so_perclient unused for lockowners,
+ * so it's OK to fool with here. */
+ list_add(&sop->so_perclient, &matches);
+ }
}
- /* no locks held by (lock) stateowner */
- status = nfs_ok;
- release_stateowner(local);
+ }
+ /* Clients probably won't expect us to return with some (but not all)
+ * of the lockowner state released; so don't release any until all
+ * have been checked. */
+ status = nfs_ok;
+ while (!list_empty(&matches)) {
+ sop = list_entry(matches.next, struct nfs4_stateowner,
+ so_perclient);
+ /* unhash_stateowner deletes so_perclient only
+ * for openowners. */
+ list_del(&sop->so_perclient);
+ release_stateowner(sop);
}
out:
nfs4_unlock_state();
@@ -3010,39 +3081,38 @@ out:
}
static inline struct nfs4_client_reclaim *
-alloc_reclaim(int namelen)
+alloc_reclaim(void)
{
- struct nfs4_client_reclaim *crp = NULL;
+ return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
+}
- crp = kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
- if (!crp)
- return NULL;
- crp->cr_name.data = kmalloc(namelen, GFP_KERNEL);
- if (!crp->cr_name.data) {
- kfree(crp);
- return NULL;
- }
- return crp;
+int
+nfs4_has_reclaimed_state(const char *name)
+{
+ unsigned int strhashval = clientstr_hashval(name);
+ struct nfs4_client *clp;
+
+ clp = find_confirmed_client_by_str(name, strhashval);
+ return clp ? 1 : 0;
}
/*
* failure => all reset bets are off, nfserr_no_grace...
*/
-static int
-nfs4_client_to_reclaim(char *name, int namlen)
+int
+nfs4_client_to_reclaim(const char *name)
{
unsigned int strhashval;
struct nfs4_client_reclaim *crp = NULL;
- dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", namlen, name);
- crp = alloc_reclaim(namlen);
+ dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
+ crp = alloc_reclaim();
if (!crp)
return 0;
- strhashval = clientstr_hashval(name, namlen);
+ strhashval = clientstr_hashval(name);
INIT_LIST_HEAD(&crp->cr_strhash);
list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
- memcpy(crp->cr_name.data, name, namlen);
- crp->cr_name.len = namlen;
+ memcpy(crp->cr_recdir, name, HEXDIR_LEN);
reclaim_str_hashtbl_size++;
return 1;
}
@@ -3053,13 +3123,11 @@ nfs4_release_reclaim(void)
struct nfs4_client_reclaim *crp = NULL;
int i;
- BUG_ON(!nfs4_reclaim_init);
for (i = 0; i < CLIENT_HASH_SIZE; i++) {
while (!list_empty(&reclaim_str_hashtbl[i])) {
crp = list_entry(reclaim_str_hashtbl[i].next,
struct nfs4_client_reclaim, cr_strhash);
list_del(&crp->cr_strhash);
- kfree(crp->cr_name.data);
kfree(crp);
reclaim_str_hashtbl_size--;
}
@@ -3069,7 +3137,7 @@ nfs4_release_reclaim(void)
/*
* called from OPEN, CLAIM_PREVIOUS with a new clientid. */
-struct nfs4_client_reclaim *
+static struct nfs4_client_reclaim *
nfs4_find_reclaim_client(clientid_t *clid)
{
unsigned int strhashval;
@@ -3082,13 +3150,14 @@ nfs4_find_reclaim_client(clientid_t *clid)
if (clp == NULL)
return NULL;
- dprintk("NFSD: nfs4_find_reclaim_client for %.*s\n",
- clp->cl_name.len, clp->cl_name.data);
+ dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
+ clp->cl_name.len, clp->cl_name.data,
+ clp->cl_recdir);
/* find clp->cl_name in reclaim_str_hashtbl */
- strhashval = clientstr_hashval(clp->cl_name.data, clp->cl_name.len);
+ strhashval = clientstr_hashval(clp->cl_recdir);
list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
- if (cmp_name(&crp->cr_name, &clp->cl_name)) {
+ if (same_name(crp->cr_recdir, clp->cl_recdir)) {
return crp;
}
}
@@ -3101,30 +3170,16 @@ nfs4_find_reclaim_client(clientid_t *clid)
int
nfs4_check_open_reclaim(clientid_t *clid)
{
- struct nfs4_client_reclaim *crp;
-
- if ((crp = nfs4_find_reclaim_client(clid)) == NULL)
- return nfserr_reclaim_bad;
- return nfs_ok;
+ return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
}
+/* initialization to perform at module load time: */
-/*
- * Start and stop routines
- */
-
-static void
-__nfs4_state_init(void)
+void
+nfs4_state_init(void)
{
int i;
- time_t grace_time;
- if (!nfs4_reclaim_init) {
- for (i = 0; i < CLIENT_HASH_SIZE; i++)
- INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
- reclaim_str_hashtbl_size = 0;
- nfs4_reclaim_init = 1;
- }
for (i = 0; i < CLIENT_HASH_SIZE; i++) {
INIT_LIST_HEAD(&conf_id_hashtbl[i]);
INIT_LIST_HEAD(&conf_str_hashtbl[i]);
@@ -3146,26 +3201,46 @@ __nfs4_state_init(void)
INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
}
- memset(&zerostateid, 0, sizeof(stateid_t));
memset(&onestateid, ~0, sizeof(stateid_t));
-
INIT_LIST_HEAD(&close_lru);
INIT_LIST_HEAD(&client_lru);
INIT_LIST_HEAD(&del_recall_lru);
- spin_lock_init(&recall_lock);
+ for (i = 0; i < CLIENT_HASH_SIZE; i++)
+ INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
+ reclaim_str_hashtbl_size = 0;
+}
+
+static void
+nfsd4_load_reboot_recovery_data(void)
+{
+ int status;
+
+ nfs4_lock_state();
+ nfsd4_init_recdir(user_recovery_dirname);
+ status = nfsd4_recdir_load();
+ nfs4_unlock_state();
+ if (status)
+ printk("NFSD: Failure reading reboot recovery data\n");
+}
+
+/* initialization to perform when the nfsd service is started: */
+
+static void
+__nfs4_state_start(void)
+{
+ time_t grace_time;
+
boot_time = get_seconds();
- grace_time = max(old_lease_time, lease_time);
- if (reclaim_str_hashtbl_size == 0)
- grace_time = 0;
- if (grace_time)
- printk("NFSD: starting %ld-second grace period\n", grace_time);
- grace_end = boot_time + grace_time;
- INIT_WORK(&laundromat_work,laundromat_main, NULL);
- schedule_delayed_work(&laundromat_work, NFSD_LEASE_TIME*HZ);
+ grace_time = max(user_lease_time, lease_time);
+ lease_time = user_lease_time;
+ in_grace = 1;
+ printk("NFSD: starting %ld-second grace period\n", grace_time);
+ laundry_wq = create_singlethread_workqueue("nfsd4");
+ queue_delayed_work(laundry_wq, &laundromat_work, grace_time*HZ);
}
int
-nfs4_state_init(void)
+nfs4_state_start(void)
{
int status;
@@ -3174,7 +3249,8 @@ nfs4_state_init(void)
status = nfsd4_init_slabs();
if (status)
return status;
- __nfs4_state_init();
+ nfsd4_load_reboot_recovery_data();
+ __nfs4_state_start();
nfs4_init = 1;
return 0;
}
@@ -3182,14 +3258,7 @@ nfs4_state_init(void)
int
nfs4_in_grace(void)
{
- return get_seconds() < grace_end;
-}
-
-void
-set_no_grace(void)
-{
- printk("NFSD: ERROR in reboot recovery. State reclaims will fail.\n");
- grace_end = get_seconds();
+ return in_grace;
}
time_t
@@ -3236,21 +3305,11 @@ __nfs4_state_shutdown(void)
unhash_delegation(dp);
}
- release_all_files();
cancel_delayed_work(&laundromat_work);
- flush_scheduled_work();
+ flush_workqueue(laundry_wq);
+ destroy_workqueue(laundry_wq);
+ nfsd4_shutdown_recdir();
nfs4_init = 0;
- dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n",
- list_add_perfile, list_del_perfile);
- dprintk("NFSD: add_perclient %d del_perclient %d\n",
- add_perclient, del_perclient);
- dprintk("NFSD: alloc_file %d free_file %d\n",
- alloc_file, free_file);
- dprintk("NFSD: vfsopen %d vfsclose %d\n",
- vfsopen, vfsclose);
- dprintk("NFSD: alloc_delegation %d free_delegation %d\n",
- alloc_delegation, free_delegation);
-
}
void
@@ -3263,56 +3322,48 @@ nfs4_state_shutdown(void)
nfs4_unlock_state();
}
+static void
+nfs4_set_recdir(char *recdir)
+{
+ nfs4_lock_state();
+ strcpy(user_recovery_dirname, recdir);
+ nfs4_unlock_state();
+}
+
+/*
+ * Change the NFSv4 recovery directory to recdir.
+ */
+int
+nfs4_reset_recoverydir(char *recdir)
+{
+ int status;
+ struct nameidata nd;
+
+ status = path_lookup(recdir, LOOKUP_FOLLOW, &nd);
+ if (status)
+ return status;
+ status = -ENOTDIR;
+ if (S_ISDIR(nd.dentry->d_inode->i_mode)) {
+ nfs4_set_recdir(recdir);
+ status = 0;
+ }
+ path_release(&nd);
+ return status;
+}
+
/*
* Called when leasetime is changed.
*
- * if nfsd is not started, simply set the global lease.
- *
- * if nfsd(s) are running, lease change requires nfsv4 state to be reset.
- * e.g: boot_time is reset, existing nfs4_client structs are
- * used to fill reclaim_str_hashtbl, then all state (except for the
- * reclaim_str_hashtbl) is re-initialized.
- *
- * if the old lease time is greater than the new lease time, the grace
- * period needs to be set to the old lease time to allow clients to reclaim
- * their state. XXX - we may want to set the grace period == lease time
- * after an initial grace period == old lease time
- *
- * if an error occurs in this process, the new lease is set, but the server
- * will not honor OPEN or LOCK reclaims, and will return nfserr_no_grace
- * which means OPEN/LOCK/READ/WRITE will fail during grace period.
- *
- * clients will attempt to reset all state with SETCLIENTID/CONFIRM, and
- * OPEN and LOCK reclaims.
+ * The only way the protocol gives us to handle on-the-fly lease changes is to
+ * simulate a reboot. Instead of doing that, we just wait till the next time
+ * we start to register any changes in lease time. If the administrator
+ * really wants to change the lease time *now*, they can go ahead and bring
+ * nfsd down and then back up again after changing the lease time.
*/
void
nfs4_reset_lease(time_t leasetime)
{
- struct nfs4_client *clp;
- int i;
-
- printk("NFSD: New leasetime %ld\n",leasetime);
- if (!nfs4_init)
- return;
- nfs4_lock_state();
- old_lease_time = lease_time;
- lease_time = leasetime;
-
- nfs4_release_reclaim();
-
- /* populate reclaim_str_hashtbl with current confirmed nfs4_clientid */
- for (i = 0; i < CLIENT_HASH_SIZE; i++) {
- list_for_each_entry(clp, &conf_id_hashtbl[i], cl_idhash) {
- if (!nfs4_client_to_reclaim(clp->cl_name.data,
- clp->cl_name.len)) {
- nfs4_release_reclaim();
- goto init_state;
- }
- }
- }
-init_state:
- __nfs4_state_shutdown();
- __nfs4_state_init();
- nfs4_unlock_state();
+ lock_kernel();
+ user_lease_time = leasetime;
+ unlock_kernel();
}
-
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index 36a058a112d5..4c4146350236 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -136,7 +136,7 @@ xdr_error: \
} \
} while (0)
-u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
+static u32 *read_buf(struct nfsd4_compoundargs *argp, int nbytes)
{
/* We want more bytes than seem to be available.
* Maybe we need a new page, maybe we have just run out
@@ -190,7 +190,7 @@ defer_free(struct nfsd4_compoundargs *argp,
return 0;
}
-char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
+static char *savemem(struct nfsd4_compoundargs *argp, u32 *p, int nbytes)
{
void *new = NULL;
if (p == argp->tmp) {
@@ -1210,16 +1210,15 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
save = resp->p;
/*
- * Routine for encoding the result of a
- * "seqid-mutating" NFSv4 operation. This is
- * where seqids are incremented, and the
- * replay cache is filled.
+ * Routine for encoding the result of a "seqid-mutating" NFSv4 operation. This
+ * is where sequence id's are incremented, and the replay cache is filled.
+ * Note that we increment sequence id's here, at the last moment, so we're sure
+ * we know whether the error to be returned is a sequence id mutating error.
*/
#define ENCODE_SEQID_OP_TAIL(stateowner) do { \
if (seqid_mutating_err(nfserr) && stateowner) { \
- if (stateowner->so_confirmed) \
- stateowner->so_seqid++; \
+ stateowner->so_seqid++; \
stateowner->so_replay.rp_status = nfserr; \
stateowner->so_replay.rp_buflen = \
(((char *)(resp)->p - (char *)save)); \
@@ -1366,7 +1365,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
if ((buflen -= 4) < 0)
goto out_resource;
- WRITE32( NFS4_FH_NOEXPIRE_WITH_OPEN | NFS4_FH_VOL_RENAME );
+ if (exp->ex_flags & NFSEXP_NOSUBTREECHECK)
+ WRITE32(NFS4_FH_PERSISTENT);
+ else
+ WRITE32(NFS4_FH_PERSISTENT|NFS4_FH_VOL_RENAME);
}
if (bmval0 & FATTR4_WORD0_CHANGE) {
/*
@@ -1969,7 +1971,7 @@ nfsd4_encode_open(struct nfsd4_compoundres *resp, int nfserr, struct nfsd4_open
case NFS4_OPEN_DELEGATE_READ:
RESERVE_SPACE(20 + sizeof(stateid_t));
WRITEMEM(&open->op_delegate_stateid, sizeof(stateid_t));
- WRITE32(0);
+ WRITE32(open->op_recall);
/*
* TODO: ACE's in delegations
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 161afdcb8f7d..841c562991e8 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -51,6 +51,7 @@ enum {
NFSD_Fh,
NFSD_Threads,
NFSD_Leasetime,
+ NFSD_RecoveryDir,
};
/*
@@ -66,6 +67,7 @@ static ssize_t write_getfs(struct file *file, char *buf, size_t size);
static ssize_t write_filehandle(struct file *file, char *buf, size_t size);
static ssize_t write_threads(struct file *file, char *buf, size_t size);
static ssize_t write_leasetime(struct file *file, char *buf, size_t size);
+static ssize_t write_recoverydir(struct file *file, char *buf, size_t size);
static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Svc] = write_svc,
@@ -78,6 +80,7 @@ static ssize_t (*write_op[])(struct file *, char *, size_t) = {
[NFSD_Fh] = write_filehandle,
[NFSD_Threads] = write_threads,
[NFSD_Leasetime] = write_leasetime,
+ [NFSD_RecoveryDir] = write_recoverydir,
};
static ssize_t nfsctl_transaction_write(struct file *file, const char __user *buf, size_t size, loff_t *pos)
@@ -349,6 +352,25 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
return strlen(buf);
}
+static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
+{
+ char *mesg = buf;
+ char *recdir;
+ int len, status;
+
+ if (size > PATH_MAX || buf[size-1] != '\n')
+ return -EINVAL;
+ buf[size-1] = 0;
+
+ recdir = mesg;
+ len = qword_get(&mesg, recdir, size);
+ if (len <= 0)
+ return -EINVAL;
+
+ status = nfs4_reset_recoverydir(recdir);
+ return strlen(buf);
+}
+
/*----------------------------------------------------------------------------*/
/*
* populating the filesystem.
@@ -369,6 +391,7 @@ static int nfsd_fill_super(struct super_block * sb, void * data, int silent)
[NFSD_Threads] = {"threads", &transaction_ops, S_IWUSR|S_IRUSR},
#ifdef CONFIG_NFSD_V4
[NFSD_Leasetime] = {"nfsv4leasetime", &transaction_ops, S_IWUSR|S_IRUSR},
+ [NFSD_RecoveryDir] = {"nfsv4recoverydir", &transaction_ops, S_IWUSR|S_IRUSR},
#endif
/* last one */ {""}
};
@@ -397,9 +420,8 @@ static int __init init_nfsd(void)
nfsd_cache_init(); /* RPC reply cache */
nfsd_export_init(); /* Exports table */
nfsd_lockd_init(); /* lockd->nfsd callbacks */
-#ifdef CONFIG_NFSD_V4
+ nfs4_state_init(); /* NFSv4 locking state */
nfsd_idmap_init(); /* Name to ID mapping */
-#endif /* CONFIG_NFSD_V4 */
if (proc_mkdir("fs/nfs", NULL)) {
struct proc_dir_entry *entry;
entry = create_proc_entry("fs/nfs/exports", 0, NULL);
@@ -426,9 +448,7 @@ static void __exit exit_nfsd(void)
remove_proc_entry("fs/nfs", NULL);
nfsd_stat_shutdown();
nfsd_lockd_shutdown();
-#ifdef CONFIG_NFSD_V4
nfsd_idmap_shutdown();
-#endif /* CONFIG_NFSD_V4 */
unregister_filesystem(&nfsd_fs_type);
}
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 904df604e86b..07b9a065e9da 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -95,7 +95,7 @@ nfsd_svc(unsigned short port, int nrservs)
error = nfsd_racache_init(2*nrservs);
if (error<0)
goto out;
- error = nfs4_state_init();
+ error = nfs4_state_start();
if (error<0)
goto out;
if (!nfsd_serv) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index de340ffd33c3..4f2cd3d27566 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -45,11 +45,10 @@
#endif /* CONFIG_NFSD_V3 */
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
-#include <linux/dnotify.h>
-#include <linux/xattr_acl.h>
+#include <linux/fsnotify.h>
#include <linux/posix_acl.h>
-#ifdef CONFIG_NFSD_V4
#include <linux/posix_acl_xattr.h>
+#ifdef CONFIG_NFSD_V4
#include <linux/xattr.h>
#include <linux/nfs4.h>
#include <linux/nfs4_acl.h>
@@ -734,7 +733,7 @@ nfsd_sync(struct file *filp)
up(&inode->i_sem);
}
-static void
+void
nfsd_sync_dir(struct dentry *dp)
{
nfsd_dosync(NULL, dp, dp->d_inode->i_fop);
@@ -861,7 +860,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_read += err;
*count = err;
err = 0;
- dnotify_parent(file->f_dentry, DN_ACCESS);
+ fsnotify_access(file->f_dentry);
} else
err = nfserrno(err);
out:
@@ -917,7 +916,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
set_fs(oldfs);
if (err >= 0) {
nfsdstats.io_write += cnt;
- dnotify_parent(file->f_dentry, DN_MODIFY);
+ fsnotify_modify(file->f_dentry);
}
/* clear setuid/setgid flag after write */
@@ -1872,10 +1871,10 @@ nfsd_get_posix_acl(struct svc_fh *fhp, int type)
return ERR_PTR(-EOPNOTSUPP);
switch(type) {
case ACL_TYPE_ACCESS:
- name = XATTR_NAME_ACL_ACCESS;
+ name = POSIX_ACL_XATTR_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = XATTR_NAME_ACL_DEFAULT;
+ name = POSIX_ACL_XATTR_DEFAULT;
break;
default:
return ERR_PTR(-EOPNOTSUPP);
@@ -1919,17 +1918,17 @@ nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
return -EOPNOTSUPP;
switch(type) {
case ACL_TYPE_ACCESS:
- name = XATTR_NAME_ACL_ACCESS;
+ name = POSIX_ACL_XATTR_ACCESS;
break;
case ACL_TYPE_DEFAULT:
- name = XATTR_NAME_ACL_DEFAULT;
+ name = POSIX_ACL_XATTR_DEFAULT;
break;
default:
return -EOPNOTSUPP;
}
if (acl && acl->a_count) {
- size = xattr_acl_size(acl->a_count);
+ size = posix_acl_xattr_size(acl->a_count);
value = kmalloc(size, GFP_KERNEL);
if (!value)
return -ENOMEM;
diff --git a/fs/open.c b/fs/open.c
index 8ec63f735918..32bf05e2996d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -10,7 +10,7 @@
#include <linux/file.h>
#include <linux/smp_lock.h>
#include <linux/quotaops.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/tty.h>
@@ -808,7 +808,9 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags)
/* NB: we're sure to have correct a_ops only after f_op->open */
if (f->f_flags & O_DIRECT) {
- if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO) {
+ if (!f->f_mapping->a_ops ||
+ ((!f->f_mapping->a_ops->direct_IO) &&
+ (!f->f_mapping->a_ops->get_xip_page))) {
fput(f);
f = ERR_PTR(-EINVAL);
}
@@ -949,6 +951,7 @@ asmlinkage long sys_open(const char __user * filename, int flags, int mode)
put_unused_fd(fd);
fd = PTR_ERR(f);
} else {
+ fsnotify_open(f->f_dentry);
fd_install(fd, f);
}
}
diff --git a/fs/partitions/Makefile b/fs/partitions/Makefile
index 4c83c17969e1..66d5cc26fafb 100644
--- a/fs/partitions/Makefile
+++ b/fs/partitions/Makefile
@@ -17,4 +17,3 @@ obj-$(CONFIG_SUN_PARTITION) += sun.o
obj-$(CONFIG_ULTRIX_PARTITION) += ultrix.o
obj-$(CONFIG_IBM_PARTITION) += ibm.o
obj-$(CONFIG_EFI_PARTITION) += efi.o
-obj-$(CONFIG_NEC98_PARTITION) += nec98.o msdos.o
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 2cab98a9a621..77e178f13162 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -79,9 +79,6 @@ static int (*check_part[])(struct parsed_partitions *, struct block_device *) =
#ifdef CONFIG_LDM_PARTITION
ldm_partition, /* this must come before msdos */
#endif
-#ifdef CONFIG_NEC98_PARTITION
- nec98_partition, /* must be come before `msdos_partition' */
-#endif
#ifdef CONFIG_MSDOS_PARTITION
msdos_partition,
#endif
diff --git a/fs/partitions/check.h b/fs/partitions/check.h
index 43adcc68e471..17ae8ecd9e8b 100644
--- a/fs/partitions/check.h
+++ b/fs/partitions/check.h
@@ -30,7 +30,3 @@ put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size)
extern int warn_no_part;
-extern void parse_bsd(struct parsed_partitions *state,
- struct block_device *bdev, u32 offset, u32 size,
- int origin, char *flavour, int max_partitions);
-
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c
index 584a27b2bbd5..9935d254186e 100644
--- a/fs/partitions/msdos.c
+++ b/fs/partitions/msdos.c
@@ -202,12 +202,12 @@ parse_solaris_x86(struct parsed_partitions *state, struct block_device *bdev,
#endif
}
-#if defined(CONFIG_BSD_DISKLABEL) || defined(CONFIG_NEC98_PARTITION)
+#if defined(CONFIG_BSD_DISKLABEL)
/*
* Create devices for BSD partitions listed in a disklabel, under a
* dos-like partition. See parse_extended() for more information.
*/
-void
+static void
parse_bsd(struct parsed_partitions *state, struct block_device *bdev,
u32 offset, u32 size, int origin, char *flavour,
int max_partitions)
diff --git a/fs/proc/Makefile b/fs/proc/Makefile
index 738b9b602932..7431d7ba2d09 100644
--- a/fs/proc/Makefile
+++ b/fs/proc/Makefile
@@ -11,4 +11,5 @@ proc-y += inode.o root.o base.o generic.o array.o \
kmsg.o proc_tty.o proc_misc.o
proc-$(CONFIG_PROC_KCORE) += kcore.o
+proc-$(CONFIG_PROC_VMCORE) += vmcore.o
proc-$(CONFIG_PROC_DEVICETREE) += proc_devtree.o
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 94b570ad037d..a3453555a94e 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -44,6 +44,7 @@
#include <linux/jiffies.h>
#include <linux/sysrq.h>
#include <linux/vmalloc.h>
+#include <linux/crash_dump.h>
#include <asm/uaccess.h>
#include <asm/pgtable.h>
#include <asm/io.h>
@@ -618,6 +619,11 @@ void __init proc_misc_init(void)
(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
}
#endif
+#ifdef CONFIG_PROC_VMCORE
+ proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
+ if (proc_vmcore)
+ proc_vmcore->proc_fops = &proc_vmcore_operations;
+#endif
#ifdef CONFIG_MAGIC_SYSRQ
entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL);
if (entry)
diff --git a/fs/proc/vmcore.c b/fs/proc/vmcore.c
new file mode 100644
index 000000000000..3b2e7b69e63a
--- /dev/null
+++ b/fs/proc/vmcore.c
@@ -0,0 +1,669 @@
+/*
+ * fs/proc/vmcore.c Interface for accessing the crash
+ * dump from the system's previous life.
+ * Heavily borrowed from fs/proc/kcore.c
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2004. All rights reserved
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/elf.h>
+#include <linux/elfcore.h>
+#include <linux/proc_fs.h>
+#include <linux/highmem.h>
+#include <linux/bootmem.h>
+#include <linux/init.h>
+#include <linux/crash_dump.h>
+#include <linux/list.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+
+/* List representing chunks of contiguous memory areas and their offsets in
+ * vmcore file.
+ */
+static LIST_HEAD(vmcore_list);
+
+/* Stores the pointer to the buffer containing kernel elf core headers. */
+static char *elfcorebuf;
+static size_t elfcorebuf_sz;
+
+/* Total size of vmcore file. */
+static u64 vmcore_size;
+
+struct proc_dir_entry *proc_vmcore = NULL;
+
+/* Reads a page from the oldmem device from given offset. */
+static ssize_t read_from_oldmem(char *buf, size_t count,
+ loff_t *ppos, int userbuf)
+{
+ unsigned long pfn, offset;
+ size_t nr_bytes;
+ ssize_t read = 0, tmp;
+
+ if (!count)
+ return 0;
+
+ offset = (unsigned long)(*ppos % PAGE_SIZE);
+ pfn = (unsigned long)(*ppos / PAGE_SIZE);
+ if (pfn > saved_max_pfn)
+ return -EINVAL;
+
+ do {
+ if (count > (PAGE_SIZE - offset))
+ nr_bytes = PAGE_SIZE - offset;
+ else
+ nr_bytes = count;
+
+ tmp = copy_oldmem_page(pfn, buf, nr_bytes, offset, userbuf);
+ if (tmp < 0)
+ return tmp;
+ *ppos += nr_bytes;
+ count -= nr_bytes;
+ buf += nr_bytes;
+ read += nr_bytes;
+ ++pfn;
+ offset = 0;
+ } while (count);
+
+ return read;
+}
+
+/* Maps vmcore file offset to respective physical address in memroy. */
+static u64 map_offset_to_paddr(loff_t offset, struct list_head *vc_list,
+ struct vmcore **m_ptr)
+{
+ struct vmcore *m;
+ u64 paddr;
+
+ list_for_each_entry(m, vc_list, list) {
+ u64 start, end;
+ start = m->offset;
+ end = m->offset + m->size - 1;
+ if (offset >= start && offset <= end) {
+ paddr = m->paddr + offset - start;
+ *m_ptr = m;
+ return paddr;
+ }
+ }
+ *m_ptr = NULL;
+ return 0;
+}
+
+/* Read from the ELF header and then the crash dump. On error, negative value is
+ * returned otherwise number of bytes read are returned.
+ */
+static ssize_t read_vmcore(struct file *file, char __user *buffer,
+ size_t buflen, loff_t *fpos)
+{
+ ssize_t acc = 0, tmp;
+ size_t tsz, nr_bytes;
+ u64 start;
+ struct vmcore *curr_m = NULL;
+
+ if (buflen == 0 || *fpos >= vmcore_size)
+ return 0;
+
+ /* trim buflen to not go beyond EOF */
+ if (buflen > vmcore_size - *fpos)
+ buflen = vmcore_size - *fpos;
+
+ /* Read ELF core header */
+ if (*fpos < elfcorebuf_sz) {
+ tsz = elfcorebuf_sz - *fpos;
+ if (buflen < tsz)
+ tsz = buflen;
+ if (copy_to_user(buffer, elfcorebuf + *fpos, tsz))
+ return -EFAULT;
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+
+ /* leave now if filled buffer already */
+ if (buflen == 0)
+ return acc;
+ }
+
+ start = map_offset_to_paddr(*fpos, &vmcore_list, &curr_m);
+ if (!curr_m)
+ return -EINVAL;
+ if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+ tsz = buflen;
+
+ /* Calculate left bytes in current memory segment. */
+ nr_bytes = (curr_m->size - (start - curr_m->paddr));
+ if (tsz > nr_bytes)
+ tsz = nr_bytes;
+
+ while (buflen) {
+ tmp = read_from_oldmem(buffer, tsz, &start, 1);
+ if (tmp < 0)
+ return tmp;
+ buflen -= tsz;
+ *fpos += tsz;
+ buffer += tsz;
+ acc += tsz;
+ if (start >= (curr_m->paddr + curr_m->size)) {
+ if (curr_m->list.next == &vmcore_list)
+ return acc; /*EOF*/
+ curr_m = list_entry(curr_m->list.next,
+ struct vmcore, list);
+ start = curr_m->paddr;
+ }
+ if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen)
+ tsz = buflen;
+ /* Calculate left bytes in current memory segment. */
+ nr_bytes = (curr_m->size - (start - curr_m->paddr));
+ if (tsz > nr_bytes)
+ tsz = nr_bytes;
+ }
+ return acc;
+}
+
+static int open_vmcore(struct inode *inode, struct file *filp)
+{
+ return 0;
+}
+
+struct file_operations proc_vmcore_operations = {
+ .read = read_vmcore,
+ .open = open_vmcore,
+};
+
+static struct vmcore* __init get_new_element(void)
+{
+ struct vmcore *p;
+
+ p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (p)
+ memset(p, 0, sizeof(*p));
+ return p;
+}
+
+static u64 __init get_vmcore_size_elf64(char *elfptr)
+{
+ int i;
+ u64 size;
+ Elf64_Ehdr *ehdr_ptr;
+ Elf64_Phdr *phdr_ptr;
+
+ ehdr_ptr = (Elf64_Ehdr *)elfptr;
+ phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+ size = sizeof(Elf64_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr));
+ for (i = 0; i < ehdr_ptr->e_phnum; i++) {
+ size += phdr_ptr->p_memsz;
+ phdr_ptr++;
+ }
+ return size;
+}
+
+static u64 __init get_vmcore_size_elf32(char *elfptr)
+{
+ int i;
+ u64 size;
+ Elf32_Ehdr *ehdr_ptr;
+ Elf32_Phdr *phdr_ptr;
+
+ ehdr_ptr = (Elf32_Ehdr *)elfptr;
+ phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+ size = sizeof(Elf32_Ehdr) + ((ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr));
+ for (i = 0; i < ehdr_ptr->e_phnum; i++) {
+ size += phdr_ptr->p_memsz;
+ phdr_ptr++;
+ }
+ return size;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf64(char *elfptr, size_t *elfsz,
+ struct list_head *vc_list)
+{
+ int i, nr_ptnote=0, rc=0;
+ char *tmp;
+ Elf64_Ehdr *ehdr_ptr;
+ Elf64_Phdr phdr, *phdr_ptr;
+ Elf64_Nhdr *nhdr_ptr;
+ u64 phdr_sz = 0, note_off;
+
+ ehdr_ptr = (Elf64_Ehdr *)elfptr;
+ phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr));
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ int j;
+ void *notes_section;
+ struct vmcore *new;
+ u64 offset, max_sz, sz, real_sz = 0;
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ nr_ptnote++;
+ max_sz = phdr_ptr->p_memsz;
+ offset = phdr_ptr->p_offset;
+ notes_section = kmalloc(max_sz, GFP_KERNEL);
+ if (!notes_section)
+ return -ENOMEM;
+ rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+ if (rc < 0) {
+ kfree(notes_section);
+ return rc;
+ }
+ nhdr_ptr = notes_section;
+ for (j = 0; j < max_sz; j += sz) {
+ if (nhdr_ptr->n_namesz == 0)
+ break;
+ sz = sizeof(Elf64_Nhdr) +
+ ((nhdr_ptr->n_namesz + 3) & ~3) +
+ ((nhdr_ptr->n_descsz + 3) & ~3);
+ real_sz += sz;
+ nhdr_ptr = (Elf64_Nhdr*)((char*)nhdr_ptr + sz);
+ }
+
+ /* Add this contiguous chunk of notes section to vmcore list.*/
+ new = get_new_element();
+ if (!new) {
+ kfree(notes_section);
+ return -ENOMEM;
+ }
+ new->paddr = phdr_ptr->p_offset;
+ new->size = real_sz;
+ list_add_tail(&new->list, vc_list);
+ phdr_sz += real_sz;
+ kfree(notes_section);
+ }
+
+ /* Prepare merged PT_NOTE program header. */
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = 0;
+ note_off = sizeof(Elf64_Ehdr) +
+ (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf64_Phdr);
+ phdr.p_offset = note_off;
+ phdr.p_vaddr = phdr.p_paddr = 0;
+ phdr.p_filesz = phdr.p_memsz = phdr_sz;
+ phdr.p_align = 0;
+
+ /* Add merged PT_NOTE program header*/
+ tmp = elfptr + sizeof(Elf64_Ehdr);
+ memcpy(tmp, &phdr, sizeof(phdr));
+ tmp += sizeof(phdr);
+
+ /* Remove unwanted PT_NOTE program headers. */
+ i = (nr_ptnote - 1) * sizeof(Elf64_Phdr);
+ *elfsz = *elfsz - i;
+ memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf64_Ehdr)-sizeof(Elf64_Phdr)));
+
+ /* Modify e_phnum to reflect merged headers. */
+ ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+
+ return 0;
+}
+
+/* Merges all the PT_NOTE headers into one. */
+static int __init merge_note_headers_elf32(char *elfptr, size_t *elfsz,
+ struct list_head *vc_list)
+{
+ int i, nr_ptnote=0, rc=0;
+ char *tmp;
+ Elf32_Ehdr *ehdr_ptr;
+ Elf32_Phdr phdr, *phdr_ptr;
+ Elf32_Nhdr *nhdr_ptr;
+ u64 phdr_sz = 0, note_off;
+
+ ehdr_ptr = (Elf32_Ehdr *)elfptr;
+ phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr));
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ int j;
+ void *notes_section;
+ struct vmcore *new;
+ u64 offset, max_sz, sz, real_sz = 0;
+ if (phdr_ptr->p_type != PT_NOTE)
+ continue;
+ nr_ptnote++;
+ max_sz = phdr_ptr->p_memsz;
+ offset = phdr_ptr->p_offset;
+ notes_section = kmalloc(max_sz, GFP_KERNEL);
+ if (!notes_section)
+ return -ENOMEM;
+ rc = read_from_oldmem(notes_section, max_sz, &offset, 0);
+ if (rc < 0) {
+ kfree(notes_section);
+ return rc;
+ }
+ nhdr_ptr = notes_section;
+ for (j = 0; j < max_sz; j += sz) {
+ if (nhdr_ptr->n_namesz == 0)
+ break;
+ sz = sizeof(Elf32_Nhdr) +
+ ((nhdr_ptr->n_namesz + 3) & ~3) +
+ ((nhdr_ptr->n_descsz + 3) & ~3);
+ real_sz += sz;
+ nhdr_ptr = (Elf32_Nhdr*)((char*)nhdr_ptr + sz);
+ }
+
+ /* Add this contiguous chunk of notes section to vmcore list.*/
+ new = get_new_element();
+ if (!new) {
+ kfree(notes_section);
+ return -ENOMEM;
+ }
+ new->paddr = phdr_ptr->p_offset;
+ new->size = real_sz;
+ list_add_tail(&new->list, vc_list);
+ phdr_sz += real_sz;
+ kfree(notes_section);
+ }
+
+ /* Prepare merged PT_NOTE program header. */
+ phdr.p_type = PT_NOTE;
+ phdr.p_flags = 0;
+ note_off = sizeof(Elf32_Ehdr) +
+ (ehdr_ptr->e_phnum - nr_ptnote +1) * sizeof(Elf32_Phdr);
+ phdr.p_offset = note_off;
+ phdr.p_vaddr = phdr.p_paddr = 0;
+ phdr.p_filesz = phdr.p_memsz = phdr_sz;
+ phdr.p_align = 0;
+
+ /* Add merged PT_NOTE program header*/
+ tmp = elfptr + sizeof(Elf32_Ehdr);
+ memcpy(tmp, &phdr, sizeof(phdr));
+ tmp += sizeof(phdr);
+
+ /* Remove unwanted PT_NOTE program headers. */
+ i = (nr_ptnote - 1) * sizeof(Elf32_Phdr);
+ *elfsz = *elfsz - i;
+ memmove(tmp, tmp+i, ((*elfsz)-sizeof(Elf32_Ehdr)-sizeof(Elf32_Phdr)));
+
+ /* Modify e_phnum to reflect merged headers. */
+ ehdr_ptr->e_phnum = ehdr_ptr->e_phnum - nr_ptnote + 1;
+
+ return 0;
+}
+
+/* Add memory chunks represented by program headers to vmcore list. Also update
+ * the new offset fields of exported program headers. */
+static int __init process_ptload_program_headers_elf64(char *elfptr,
+ size_t elfsz,
+ struct list_head *vc_list)
+{
+ int i;
+ Elf64_Ehdr *ehdr_ptr;
+ Elf64_Phdr *phdr_ptr;
+ loff_t vmcore_off;
+ struct vmcore *new;
+
+ ehdr_ptr = (Elf64_Ehdr *)elfptr;
+ phdr_ptr = (Elf64_Phdr*)(elfptr + sizeof(Elf64_Ehdr)); /* PT_NOTE hdr */
+
+ /* First program header is PT_NOTE header. */
+ vmcore_off = sizeof(Elf64_Ehdr) +
+ (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr) +
+ phdr_ptr->p_memsz; /* Note sections */
+
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ if (phdr_ptr->p_type != PT_LOAD)
+ continue;
+
+ /* Add this contiguous chunk of memory to vmcore list.*/
+ new = get_new_element();
+ if (!new)
+ return -ENOMEM;
+ new->paddr = phdr_ptr->p_offset;
+ new->size = phdr_ptr->p_memsz;
+ list_add_tail(&new->list, vc_list);
+
+ /* Update the program header offset. */
+ phdr_ptr->p_offset = vmcore_off;
+ vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+ }
+ return 0;
+}
+
+static int __init process_ptload_program_headers_elf32(char *elfptr,
+ size_t elfsz,
+ struct list_head *vc_list)
+{
+ int i;
+ Elf32_Ehdr *ehdr_ptr;
+ Elf32_Phdr *phdr_ptr;
+ loff_t vmcore_off;
+ struct vmcore *new;
+
+ ehdr_ptr = (Elf32_Ehdr *)elfptr;
+ phdr_ptr = (Elf32_Phdr*)(elfptr + sizeof(Elf32_Ehdr)); /* PT_NOTE hdr */
+
+ /* First program header is PT_NOTE header. */
+ vmcore_off = sizeof(Elf32_Ehdr) +
+ (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr) +
+ phdr_ptr->p_memsz; /* Note sections */
+
+ for (i = 0; i < ehdr_ptr->e_phnum; i++, phdr_ptr++) {
+ if (phdr_ptr->p_type != PT_LOAD)
+ continue;
+
+ /* Add this contiguous chunk of memory to vmcore list.*/
+ new = get_new_element();
+ if (!new)
+ return -ENOMEM;
+ new->paddr = phdr_ptr->p_offset;
+ new->size = phdr_ptr->p_memsz;
+ list_add_tail(&new->list, vc_list);
+
+ /* Update the program header offset */
+ phdr_ptr->p_offset = vmcore_off;
+ vmcore_off = vmcore_off + phdr_ptr->p_memsz;
+ }
+ return 0;
+}
+
+/* Sets offset fields of vmcore elements. */
+static void __init set_vmcore_list_offsets_elf64(char *elfptr,
+ struct list_head *vc_list)
+{
+ loff_t vmcore_off;
+ Elf64_Ehdr *ehdr_ptr;
+ struct vmcore *m;
+
+ ehdr_ptr = (Elf64_Ehdr *)elfptr;
+
+ /* Skip Elf header and program headers. */
+ vmcore_off = sizeof(Elf64_Ehdr) +
+ (ehdr_ptr->e_phnum) * sizeof(Elf64_Phdr);
+
+ list_for_each_entry(m, vc_list, list) {
+ m->offset = vmcore_off;
+ vmcore_off += m->size;
+ }
+}
+
+/* Sets offset fields of vmcore elements. */
+static void __init set_vmcore_list_offsets_elf32(char *elfptr,
+ struct list_head *vc_list)
+{
+ loff_t vmcore_off;
+ Elf32_Ehdr *ehdr_ptr;
+ struct vmcore *m;
+
+ ehdr_ptr = (Elf32_Ehdr *)elfptr;
+
+ /* Skip Elf header and program headers. */
+ vmcore_off = sizeof(Elf32_Ehdr) +
+ (ehdr_ptr->e_phnum) * sizeof(Elf32_Phdr);
+
+ list_for_each_entry(m, vc_list, list) {
+ m->offset = vmcore_off;
+ vmcore_off += m->size;
+ }
+}
+
+static int __init parse_crash_elf64_headers(void)
+{
+ int rc=0;
+ Elf64_Ehdr ehdr;
+ u64 addr;
+
+ addr = elfcorehdr_addr;
+
+ /* Read Elf header */
+ rc = read_from_oldmem((char*)&ehdr, sizeof(Elf64_Ehdr), &addr, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Do some basic Verification. */
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
+ (ehdr.e_type != ET_CORE) ||
+ !elf_check_arch(&ehdr) ||
+ ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
+ ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
+ ehdr.e_version != EV_CURRENT ||
+ ehdr.e_ehsize != sizeof(Elf64_Ehdr) ||
+ ehdr.e_phentsize != sizeof(Elf64_Phdr) ||
+ ehdr.e_phnum == 0) {
+ printk(KERN_WARNING "Warning: Core image elf header is not"
+ "sane\n");
+ return -EINVAL;
+ }
+
+ /* Read in all elf headers. */
+ elfcorebuf_sz = sizeof(Elf64_Ehdr) + ehdr.e_phnum * sizeof(Elf64_Phdr);
+ elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+ if (!elfcorebuf)
+ return -ENOMEM;
+ addr = elfcorehdr_addr;
+ rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
+ if (rc < 0) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+
+ /* Merge all PT_NOTE headers into one. */
+ rc = merge_note_headers_elf64(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+ if (rc) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+ rc = process_ptload_program_headers_elf64(elfcorebuf, elfcorebuf_sz,
+ &vmcore_list);
+ if (rc) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+ set_vmcore_list_offsets_elf64(elfcorebuf, &vmcore_list);
+ return 0;
+}
+
+static int __init parse_crash_elf32_headers(void)
+{
+ int rc=0;
+ Elf32_Ehdr ehdr;
+ u64 addr;
+
+ addr = elfcorehdr_addr;
+
+ /* Read Elf header */
+ rc = read_from_oldmem((char*)&ehdr, sizeof(Elf32_Ehdr), &addr, 0);
+ if (rc < 0)
+ return rc;
+
+ /* Do some basic Verification. */
+ if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
+ (ehdr.e_type != ET_CORE) ||
+ !elf_check_arch(&ehdr) ||
+ ehdr.e_ident[EI_CLASS] != ELFCLASS32||
+ ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
+ ehdr.e_version != EV_CURRENT ||
+ ehdr.e_ehsize != sizeof(Elf32_Ehdr) ||
+ ehdr.e_phentsize != sizeof(Elf32_Phdr) ||
+ ehdr.e_phnum == 0) {
+ printk(KERN_WARNING "Warning: Core image elf header is not"
+ "sane\n");
+ return -EINVAL;
+ }
+
+ /* Read in all elf headers. */
+ elfcorebuf_sz = sizeof(Elf32_Ehdr) + ehdr.e_phnum * sizeof(Elf32_Phdr);
+ elfcorebuf = kmalloc(elfcorebuf_sz, GFP_KERNEL);
+ if (!elfcorebuf)
+ return -ENOMEM;
+ addr = elfcorehdr_addr;
+ rc = read_from_oldmem(elfcorebuf, elfcorebuf_sz, &addr, 0);
+ if (rc < 0) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+
+ /* Merge all PT_NOTE headers into one. */
+ rc = merge_note_headers_elf32(elfcorebuf, &elfcorebuf_sz, &vmcore_list);
+ if (rc) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+ rc = process_ptload_program_headers_elf32(elfcorebuf, elfcorebuf_sz,
+ &vmcore_list);
+ if (rc) {
+ kfree(elfcorebuf);
+ return rc;
+ }
+ set_vmcore_list_offsets_elf32(elfcorebuf, &vmcore_list);
+ return 0;
+}
+
+static int __init parse_crash_elf_headers(void)
+{
+ unsigned char e_ident[EI_NIDENT];
+ u64 addr;
+ int rc=0;
+
+ addr = elfcorehdr_addr;
+ rc = read_from_oldmem(e_ident, EI_NIDENT, &addr, 0);
+ if (rc < 0)
+ return rc;
+ if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
+ printk(KERN_WARNING "Warning: Core image elf header"
+ " not found\n");
+ return -EINVAL;
+ }
+
+ if (e_ident[EI_CLASS] == ELFCLASS64) {
+ rc = parse_crash_elf64_headers();
+ if (rc)
+ return rc;
+
+ /* Determine vmcore size. */
+ vmcore_size = get_vmcore_size_elf64(elfcorebuf);
+ } else if (e_ident[EI_CLASS] == ELFCLASS32) {
+ rc = parse_crash_elf32_headers();
+ if (rc)
+ return rc;
+
+ /* Determine vmcore size. */
+ vmcore_size = get_vmcore_size_elf32(elfcorebuf);
+ } else {
+ printk(KERN_WARNING "Warning: Core image elf header is not"
+ " sane\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/* Init function for vmcore module. */
+static int __init vmcore_init(void)
+{
+ int rc = 0;
+
+ /* If elfcorehdr= has been passed in cmdline, then capture the dump.*/
+ if (!(elfcorehdr_addr < ELFCORE_ADDR_MAX))
+ return rc;
+ rc = parse_crash_elf_headers();
+ if (rc) {
+ printk(KERN_WARNING "Kdump: vmcore not initialized\n");
+ return rc;
+ }
+
+ /* Initialize /proc/vmcore size if proc is already up. */
+ if (proc_vmcore)
+ proc_vmcore->size = vmcore_size;
+ return 0;
+}
+module_init(vmcore_init)
diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c
index cd66147cca04..7a8f5595c26f 100644
--- a/fs/qnx4/dir.c
+++ b/fs/qnx4/dir.c
@@ -61,7 +61,7 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir)
ino = blknum * QNX4_INODES_PER_BLOCK + ix - 1;
else {
le = (struct qnx4_link_info*)de;
- ino = ( le->dl_inode_blk - 1 ) *
+ ino = ( le32_to_cpu(le->dl_inode_blk) - 1 ) *
QNX4_INODES_PER_BLOCK +
le->dl_inode_ndx;
}
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c
index aa92d6b76a9a..b79162a35478 100644
--- a/fs/qnx4/inode.c
+++ b/fs/qnx4/inode.c
@@ -236,7 +236,7 @@ unsigned long qnx4_block_map( struct inode *inode, long iblock )
struct buffer_head *bh = NULL;
struct qnx4_xblk *xblk = NULL;
struct qnx4_inode_entry *qnx4_inode = qnx4_raw_inode(inode);
- qnx4_nxtnt_t nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
+ u16 nxtnt = le16_to_cpu(qnx4_inode->di_num_xtnts);
if ( iblock < le32_to_cpu(qnx4_inode->di_first_xtnt.xtnt_size) ) {
// iblock is in the first extent. This is easy.
@@ -372,7 +372,7 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
printk("qnx4: unable to read the superblock\n");
goto outnobh;
}
- if ( le32_to_cpu( *(__u32*)bh->b_data ) != QNX4_SUPER_MAGIC ) {
+ if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
if (!silent)
printk("qnx4: wrong fsid in superblock.\n");
goto out;
diff --git a/fs/read_write.c b/fs/read_write.c
index 9292f5fa4d62..563abd09b5c8 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -10,7 +10,7 @@
#include <linux/file.h>
#include <linux/uio.h>
#include <linux/smp_lock.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/security.h>
#include <linux/module.h>
#include <linux/syscalls.h>
@@ -252,7 +252,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
else
ret = do_sync_read(file, buf, count, pos);
if (ret > 0) {
- dnotify_parent(file->f_dentry, DN_ACCESS);
+ fsnotify_access(file->f_dentry);
current->rchar += ret;
}
current->syscr++;
@@ -303,7 +303,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_
else
ret = do_sync_write(file, buf, count, pos);
if (ret > 0) {
- dnotify_parent(file->f_dentry, DN_MODIFY);
+ fsnotify_modify(file->f_dentry);
current->wchar += ret;
}
current->syscw++;
@@ -539,9 +539,12 @@ static ssize_t do_readv_writev(int type, struct file *file,
out:
if (iov != iovstack)
kfree(iov);
- if ((ret + (type == READ)) > 0)
- dnotify_parent(file->f_dentry,
- (type == READ) ? DN_ACCESS : DN_MODIFY);
+ if ((ret + (type == READ)) > 0) {
+ if (type == READ)
+ fsnotify_access(file->f_dentry);
+ else
+ fsnotify_modify(file->f_dentry);
+ }
return ret;
Efault:
ret = -EFAULT;
diff --git a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
index 49c479c9454a..909f71e9a30f 100644
--- a/fs/reiserfs/bitmap.c
+++ b/fs/reiserfs/bitmap.c
@@ -46,1125 +46,1221 @@
#define TEST_OPTION(optname, s) \
test_bit(_ALLOC_ ## optname , &SB_ALLOC_OPTS(s))
-static inline void get_bit_address (struct super_block * s,
- b_blocknr_t block, int * bmap_nr, int * offset)
+static inline void get_bit_address(struct super_block *s,
+ b_blocknr_t block, int *bmap_nr, int *offset)
{
- /* It is in the bitmap block number equal to the block
- * number divided by the number of bits in a block. */
- *bmap_nr = block / (s->s_blocksize << 3);
- /* Within that bitmap block it is located at bit offset *offset. */
- *offset = block & ((s->s_blocksize << 3) - 1 );
- return;
+ /* It is in the bitmap block number equal to the block
+ * number divided by the number of bits in a block. */
+ *bmap_nr = block / (s->s_blocksize << 3);
+ /* Within that bitmap block it is located at bit offset *offset. */
+ *offset = block & ((s->s_blocksize << 3) - 1);
+ return;
}
#ifdef CONFIG_REISERFS_CHECK
-int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value)
+int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value)
{
- int i, j;
+ int i, j;
- if (block == 0 || block >= SB_BLOCK_COUNT (s)) {
- reiserfs_warning (s, "vs-4010: is_reusable: block number is out of range %lu (%u)",
- block, SB_BLOCK_COUNT (s));
- return 0;
- }
-
- /* it can't be one of the bitmap blocks */
- for (i = 0; i < SB_BMAP_NR (s); i ++)
- if (block == SB_AP_BITMAP (s)[i].bh->b_blocknr) {
- reiserfs_warning (s, "vs: 4020: is_reusable: "
- "bitmap block %lu(%u) can't be freed or reused",
- block, SB_BMAP_NR (s));
- return 0;
+ if (block == 0 || block >= SB_BLOCK_COUNT(s)) {
+ reiserfs_warning(s,
+ "vs-4010: is_reusable: block number is out of range %lu (%u)",
+ block, SB_BLOCK_COUNT(s));
+ return 0;
}
-
- get_bit_address (s, block, &i, &j);
- if (i >= SB_BMAP_NR (s)) {
- reiserfs_warning (s, "vs-4030: is_reusable: there is no so many bitmap blocks: "
- "block=%lu, bitmap_nr=%d", block, i);
- return 0;
- }
+ /* it can't be one of the bitmap blocks */
+ for (i = 0; i < SB_BMAP_NR(s); i++)
+ if (block == SB_AP_BITMAP(s)[i].bh->b_blocknr) {
+ reiserfs_warning(s, "vs: 4020: is_reusable: "
+ "bitmap block %lu(%u) can't be freed or reused",
+ block, SB_BMAP_NR(s));
+ return 0;
+ }
- if ((bit_value == 0 &&
- reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
- (bit_value == 1 &&
- reiserfs_test_le_bit(j, SB_AP_BITMAP (s)[i].bh->b_data) == 0)) {
- reiserfs_warning (s, "vs-4040: is_reusable: corresponding bit of block %lu does not "
- "match required value (i==%d, j==%d) test_bit==%d",
- block, i, j, reiserfs_test_le_bit (j, SB_AP_BITMAP (s)[i].bh->b_data));
+ get_bit_address(s, block, &i, &j);
- return 0;
- }
+ if (i >= SB_BMAP_NR(s)) {
+ reiserfs_warning(s,
+ "vs-4030: is_reusable: there is no so many bitmap blocks: "
+ "block=%lu, bitmap_nr=%d", block, i);
+ return 0;
+ }
- if (bit_value == 0 && block == SB_ROOT_BLOCK (s)) {
- reiserfs_warning (s, "vs-4050: is_reusable: this is root block (%u), "
- "it must be busy", SB_ROOT_BLOCK (s));
- return 0;
- }
+ if ((bit_value == 0 &&
+ reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data)) ||
+ (bit_value == 1 &&
+ reiserfs_test_le_bit(j, SB_AP_BITMAP(s)[i].bh->b_data) == 0)) {
+ reiserfs_warning(s,
+ "vs-4040: is_reusable: corresponding bit of block %lu does not "
+ "match required value (i==%d, j==%d) test_bit==%d",
+ block, i, j, reiserfs_test_le_bit(j,
+ SB_AP_BITMAP
+ (s)[i].bh->
+ b_data));
+
+ return 0;
+ }
- return 1;
+ if (bit_value == 0 && block == SB_ROOT_BLOCK(s)) {
+ reiserfs_warning(s,
+ "vs-4050: is_reusable: this is root block (%u), "
+ "it must be busy", SB_ROOT_BLOCK(s));
+ return 0;
+ }
+
+ return 1;
}
-#endif /* CONFIG_REISERFS_CHECK */
+#endif /* CONFIG_REISERFS_CHECK */
/* searches in journal structures for a given block number (bmap, off). If block
is found in reiserfs journal it suggests next free block candidate to test. */
-static inline int is_block_in_journal (struct super_block * s, int bmap, int
-off, int *next)
+static inline int is_block_in_journal(struct super_block *s, int bmap, int
+ off, int *next)
{
- b_blocknr_t tmp;
-
- if (reiserfs_in_journal (s, bmap, off, 1, &tmp)) {
- if (tmp) { /* hint supplied */
- *next = tmp;
- PROC_INFO_INC( s, scan_bitmap.in_journal_hint );
- } else {
- (*next) = off + 1; /* inc offset to avoid looping. */
- PROC_INFO_INC( s, scan_bitmap.in_journal_nohint );
+ b_blocknr_t tmp;
+
+ if (reiserfs_in_journal(s, bmap, off, 1, &tmp)) {
+ if (tmp) { /* hint supplied */
+ *next = tmp;
+ PROC_INFO_INC(s, scan_bitmap.in_journal_hint);
+ } else {
+ (*next) = off + 1; /* inc offset to avoid looping. */
+ PROC_INFO_INC(s, scan_bitmap.in_journal_nohint);
+ }
+ PROC_INFO_INC(s, scan_bitmap.retry);
+ return 1;
}
- PROC_INFO_INC( s, scan_bitmap.retry );
- return 1;
- }
- return 0;
+ return 0;
}
/* it searches for a window of zero bits with given minimum and maximum lengths in one bitmap
* block; */
-static int scan_bitmap_block (struct reiserfs_transaction_handle *th,
- int bmap_n, int *beg, int boundary, int min, int max, int unfm)
+static int scan_bitmap_block(struct reiserfs_transaction_handle *th,
+ int bmap_n, int *beg, int boundary, int min,
+ int max, int unfm)
{
- struct super_block *s = th->t_super;
- struct reiserfs_bitmap_info *bi=&SB_AP_BITMAP(s)[bmap_n];
- int end, next;
- int org = *beg;
+ struct super_block *s = th->t_super;
+ struct reiserfs_bitmap_info *bi = &SB_AP_BITMAP(s)[bmap_n];
+ int end, next;
+ int org = *beg;
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- RFALSE(bmap_n >= SB_BMAP_NR (s), "Bitmap %d is out of range (0..%d)",bmap_n, SB_BMAP_NR (s) - 1);
- PROC_INFO_INC( s, scan_bitmap.bmap );
+ RFALSE(bmap_n >= SB_BMAP_NR(s), "Bitmap %d is out of range (0..%d)",
+ bmap_n, SB_BMAP_NR(s) - 1);
+ PROC_INFO_INC(s, scan_bitmap.bmap);
/* this is unclear and lacks comments, explain how journal bitmaps
work here for the reader. Convey a sense of the design here. What
is a window? */
/* - I mean `a window of zero bits' as in description of this function - Zam. */
-
- if ( !bi ) {
- reiserfs_warning (s, "NULL bitmap info pointer for bitmap %d", bmap_n);
- return 0;
- }
- if (buffer_locked (bi->bh)) {
- PROC_INFO_INC( s, scan_bitmap.wait );
- __wait_on_buffer (bi->bh);
- }
-
- while (1) {
- cont:
- if (bi->free_count < min)
- return 0; // No free blocks in this bitmap
-
- /* search for a first zero bit -- beggining of a window */
- *beg = reiserfs_find_next_zero_le_bit
- ((unsigned long*)(bi->bh->b_data), boundary, *beg);
-
- if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
- * cannot contain a zero window of minimum size */
- return 0;
- }
- if (unfm && is_block_in_journal(s,bmap_n, *beg, beg))
- continue;
- /* first zero bit found; we check next bits */
- for (end = *beg + 1;; end ++) {
- if (end >= *beg + max || end >= boundary || reiserfs_test_le_bit (end, bi->bh->b_data)) {
- next = end;
- break;
- }
- /* finding the other end of zero bit window requires looking into journal structures (in
- * case of searching for free blocks for unformatted nodes) */
- if (unfm && is_block_in_journal(s, bmap_n, end, &next))
- break;
+ if (!bi) {
+ reiserfs_warning(s, "NULL bitmap info pointer for bitmap %d",
+ bmap_n);
+ return 0;
+ }
+ if (buffer_locked(bi->bh)) {
+ PROC_INFO_INC(s, scan_bitmap.wait);
+ __wait_on_buffer(bi->bh);
}
- /* now (*beg) points to beginning of zero bits window,
- * (end) points to one bit after the window end */
- if (end - *beg >= min) { /* it seems we have found window of proper size */
- int i;
- reiserfs_prepare_for_journal (s, bi->bh, 1);
- /* try to set all blocks used checking are they still free */
- for (i = *beg; i < end; i++) {
- /* It seems that we should not check in journal again. */
- if (reiserfs_test_and_set_le_bit (i, bi->bh->b_data)) {
- /* bit was set by another process
- * while we slept in prepare_for_journal() */
- PROC_INFO_INC( s, scan_bitmap.stolen );
- if (i >= *beg + min) { /* we can continue with smaller set of allocated blocks,
- * if length of this set is more or equal to `min' */
- end = i;
- break;
- }
- /* otherwise we clear all bit were set ... */
- while (--i >= *beg)
- reiserfs_test_and_clear_le_bit (i, bi->bh->b_data);
- reiserfs_restore_prepared_buffer (s, bi->bh);
- *beg = org;
- /* ... and search again in current block from beginning */
- goto cont;
+ while (1) {
+ cont:
+ if (bi->free_count < min)
+ return 0; // No free blocks in this bitmap
+
+ /* search for a first zero bit -- beggining of a window */
+ *beg = reiserfs_find_next_zero_le_bit
+ ((unsigned long *)(bi->bh->b_data), boundary, *beg);
+
+ if (*beg + min > boundary) { /* search for a zero bit fails or the rest of bitmap block
+ * cannot contain a zero window of minimum size */
+ return 0;
}
- }
- bi->free_count -= (end - *beg);
- journal_mark_dirty (th, s, bi->bh);
- /* free block count calculation */
- reiserfs_prepare_for_journal (s, SB_BUFFER_WITH_SB(s), 1);
- PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
- journal_mark_dirty (th, s, SB_BUFFER_WITH_SB(s));
+ if (unfm && is_block_in_journal(s, bmap_n, *beg, beg))
+ continue;
+ /* first zero bit found; we check next bits */
+ for (end = *beg + 1;; end++) {
+ if (end >= *beg + max || end >= boundary
+ || reiserfs_test_le_bit(end, bi->bh->b_data)) {
+ next = end;
+ break;
+ }
+ /* finding the other end of zero bit window requires looking into journal structures (in
+ * case of searching for free blocks for unformatted nodes) */
+ if (unfm && is_block_in_journal(s, bmap_n, end, &next))
+ break;
+ }
- return end - (*beg);
- } else {
- *beg = next;
+ /* now (*beg) points to beginning of zero bits window,
+ * (end) points to one bit after the window end */
+ if (end - *beg >= min) { /* it seems we have found window of proper size */
+ int i;
+ reiserfs_prepare_for_journal(s, bi->bh, 1);
+ /* try to set all blocks used checking are they still free */
+ for (i = *beg; i < end; i++) {
+ /* It seems that we should not check in journal again. */
+ if (reiserfs_test_and_set_le_bit
+ (i, bi->bh->b_data)) {
+ /* bit was set by another process
+ * while we slept in prepare_for_journal() */
+ PROC_INFO_INC(s, scan_bitmap.stolen);
+ if (i >= *beg + min) { /* we can continue with smaller set of allocated blocks,
+ * if length of this set is more or equal to `min' */
+ end = i;
+ break;
+ }
+ /* otherwise we clear all bit were set ... */
+ while (--i >= *beg)
+ reiserfs_test_and_clear_le_bit
+ (i, bi->bh->b_data);
+ reiserfs_restore_prepared_buffer(s,
+ bi->
+ bh);
+ *beg = org;
+ /* ... and search again in current block from beginning */
+ goto cont;
+ }
+ }
+ bi->free_count -= (end - *beg);
+ journal_mark_dirty(th, s, bi->bh);
+
+ /* free block count calculation */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
+ 1);
+ PUT_SB_FREE_BLOCKS(s, SB_FREE_BLOCKS(s) - (end - *beg));
+ journal_mark_dirty(th, s, SB_BUFFER_WITH_SB(s));
+
+ return end - (*beg);
+ } else {
+ *beg = next;
+ }
}
- }
}
-static int bmap_hash_id(struct super_block *s, u32 id) {
- char * hash_in = NULL;
- unsigned long hash;
- unsigned bm;
-
- if (id <= 2) {
- bm = 1;
- } else {
- hash_in = (char *)(&id);
- hash = keyed_hash(hash_in, 4);
- bm = hash % SB_BMAP_NR(s);
- if (!bm)
- bm = 1;
- }
- /* this can only be true when SB_BMAP_NR = 1 */
- if (bm >= SB_BMAP_NR(s))
- bm = 0;
- return bm;
+static int bmap_hash_id(struct super_block *s, u32 id)
+{
+ char *hash_in = NULL;
+ unsigned long hash;
+ unsigned bm;
+
+ if (id <= 2) {
+ bm = 1;
+ } else {
+ hash_in = (char *)(&id);
+ hash = keyed_hash(hash_in, 4);
+ bm = hash % SB_BMAP_NR(s);
+ if (!bm)
+ bm = 1;
+ }
+ /* this can only be true when SB_BMAP_NR = 1 */
+ if (bm >= SB_BMAP_NR(s))
+ bm = 0;
+ return bm;
}
/*
* hashes the id and then returns > 0 if the block group for the
* corresponding hash is full
*/
-static inline int block_group_used(struct super_block *s, u32 id) {
- int bm;
- bm = bmap_hash_id(s, id);
- if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100) ) {
- return 0;
- }
- return 1;
+static inline int block_group_used(struct super_block *s, u32 id)
+{
+ int bm;
+ bm = bmap_hash_id(s, id);
+ if (SB_AP_BITMAP(s)[bm].free_count > ((s->s_blocksize << 3) * 60 / 100)) {
+ return 0;
+ }
+ return 1;
}
/*
* the packing is returned in disk byte order
*/
-__le32 reiserfs_choose_packing(struct inode *dir)
+__le32 reiserfs_choose_packing(struct inode * dir)
{
- __le32 packing;
- if (TEST_OPTION(packing_groups, dir->i_sb)) {
- u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
- /*
- * some versions of reiserfsck expect packing locality 1 to be
- * special
- */
- if (parent_dir == 1 || block_group_used(dir->i_sb,parent_dir))
- packing = INODE_PKEY(dir)->k_objectid;
- else
- packing = INODE_PKEY(dir)->k_dir_id;
- } else
- packing = INODE_PKEY(dir)->k_objectid;
- return packing;
+ __le32 packing;
+ if (TEST_OPTION(packing_groups, dir->i_sb)) {
+ u32 parent_dir = le32_to_cpu(INODE_PKEY(dir)->k_dir_id);
+ /*
+ * some versions of reiserfsck expect packing locality 1 to be
+ * special
+ */
+ if (parent_dir == 1 || block_group_used(dir->i_sb, parent_dir))
+ packing = INODE_PKEY(dir)->k_objectid;
+ else
+ packing = INODE_PKEY(dir)->k_dir_id;
+ } else
+ packing = INODE_PKEY(dir)->k_objectid;
+ return packing;
}
-
+
/* Tries to find contiguous zero bit window (given size) in given region of
* bitmap and place new blocks there. Returns number of allocated blocks. */
-static int scan_bitmap (struct reiserfs_transaction_handle *th,
- b_blocknr_t *start, b_blocknr_t finish,
- int min, int max, int unfm, unsigned long file_block)
+static int scan_bitmap(struct reiserfs_transaction_handle *th,
+ b_blocknr_t * start, b_blocknr_t finish,
+ int min, int max, int unfm, unsigned long file_block)
{
- int nr_allocated=0;
- struct super_block * s = th->t_super;
- /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
- * - Hans, it is not a block number - Zam. */
-
- int bm, off;
- int end_bm, end_off;
- int off_max = s->s_blocksize << 3;
-
- BUG_ON (!th->t_trans_id);
-
- PROC_INFO_INC( s, scan_bitmap.call );
- if ( SB_FREE_BLOCKS(s) <= 0)
- return 0; // No point in looking for more free blocks
-
- get_bit_address (s, *start, &bm, &off);
- get_bit_address (s, finish, &end_bm, &end_off);
- if (bm > SB_BMAP_NR(s))
- return 0;
- if (end_bm > SB_BMAP_NR(s))
- end_bm = SB_BMAP_NR(s);
-
- /* When the bitmap is more than 10% free, anyone can allocate.
- * When it's less than 10% free, only files that already use the
- * bitmap are allowed. Once we pass 80% full, this restriction
- * is lifted.
- *
- * We do this so that files that grow later still have space close to
- * their original allocation. This improves locality, and presumably
- * performance as a result.
- *
- * This is only an allocation policy and does not make up for getting a
- * bad hint. Decent hinting must be implemented for this to work well.
- */
- if ( TEST_OPTION(skip_busy, s) && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s)/20 ) {
- for (;bm < end_bm; bm++, off = 0) {
- if ( ( off && (!unfm || (file_block != 0))) || SB_AP_BITMAP(s)[bm].free_count > (s->s_blocksize << 3) / 10 )
- nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
- if (nr_allocated)
- goto ret;
- }
- /* we know from above that start is a reasonable number */
- get_bit_address (s, *start, &bm, &off);
- }
-
- for (;bm < end_bm; bm++, off = 0) {
- nr_allocated = scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
- if (nr_allocated)
- goto ret;
- }
-
- nr_allocated = scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
-
- ret:
- *start = bm * off_max + off;
- return nr_allocated;
+ int nr_allocated = 0;
+ struct super_block *s = th->t_super;
+ /* find every bm and bmap and bmap_nr in this file, and change them all to bitmap_blocknr
+ * - Hans, it is not a block number - Zam. */
+
+ int bm, off;
+ int end_bm, end_off;
+ int off_max = s->s_blocksize << 3;
+
+ BUG_ON(!th->t_trans_id);
+
+ PROC_INFO_INC(s, scan_bitmap.call);
+ if (SB_FREE_BLOCKS(s) <= 0)
+ return 0; // No point in looking for more free blocks
+
+ get_bit_address(s, *start, &bm, &off);
+ get_bit_address(s, finish, &end_bm, &end_off);
+ if (bm > SB_BMAP_NR(s))
+ return 0;
+ if (end_bm > SB_BMAP_NR(s))
+ end_bm = SB_BMAP_NR(s);
+
+ /* When the bitmap is more than 10% free, anyone can allocate.
+ * When it's less than 10% free, only files that already use the
+ * bitmap are allowed. Once we pass 80% full, this restriction
+ * is lifted.
+ *
+ * We do this so that files that grow later still have space close to
+ * their original allocation. This improves locality, and presumably
+ * performance as a result.
+ *
+ * This is only an allocation policy and does not make up for getting a
+ * bad hint. Decent hinting must be implemented for this to work well.
+ */
+ if (TEST_OPTION(skip_busy, s)
+ && SB_FREE_BLOCKS(s) > SB_BLOCK_COUNT(s) / 20) {
+ for (; bm < end_bm; bm++, off = 0) {
+ if ((off && (!unfm || (file_block != 0)))
+ || SB_AP_BITMAP(s)[bm].free_count >
+ (s->s_blocksize << 3) / 10)
+ nr_allocated =
+ scan_bitmap_block(th, bm, &off, off_max,
+ min, max, unfm);
+ if (nr_allocated)
+ goto ret;
+ }
+ /* we know from above that start is a reasonable number */
+ get_bit_address(s, *start, &bm, &off);
+ }
+
+ for (; bm < end_bm; bm++, off = 0) {
+ nr_allocated =
+ scan_bitmap_block(th, bm, &off, off_max, min, max, unfm);
+ if (nr_allocated)
+ goto ret;
+ }
+
+ nr_allocated =
+ scan_bitmap_block(th, bm, &off, end_off + 1, min, max, unfm);
+
+ ret:
+ *start = bm * off_max + off;
+ return nr_allocated;
}
-static void _reiserfs_free_block (struct reiserfs_transaction_handle *th,
- struct inode *inode, b_blocknr_t block,
- int for_unformatted)
+static void _reiserfs_free_block(struct reiserfs_transaction_handle *th,
+ struct inode *inode, b_blocknr_t block,
+ int for_unformatted)
{
- struct super_block * s = th->t_super;
- struct reiserfs_super_block * rs;
- struct buffer_head * sbh;
- struct reiserfs_bitmap_info *apbi;
- int nr, offset;
+ struct super_block *s = th->t_super;
+ struct reiserfs_super_block *rs;
+ struct buffer_head *sbh;
+ struct reiserfs_bitmap_info *apbi;
+ int nr, offset;
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- PROC_INFO_INC( s, free_block );
+ PROC_INFO_INC(s, free_block);
- rs = SB_DISK_SUPER_BLOCK (s);
- sbh = SB_BUFFER_WITH_SB (s);
- apbi = SB_AP_BITMAP(s);
+ rs = SB_DISK_SUPER_BLOCK(s);
+ sbh = SB_BUFFER_WITH_SB(s);
+ apbi = SB_AP_BITMAP(s);
- get_bit_address (s, block, &nr, &offset);
+ get_bit_address(s, block, &nr, &offset);
- if (nr >= sb_bmap_nr (rs)) {
- reiserfs_warning (s, "vs-4075: reiserfs_free_block: "
- "block %lu is out of range on %s",
- block, reiserfs_bdevname (s));
- return;
- }
-
- reiserfs_prepare_for_journal(s, apbi[nr].bh, 1 ) ;
-
- /* clear bit for the given block in bit map */
- if (!reiserfs_test_and_clear_le_bit (offset, apbi[nr].bh->b_data)) {
- reiserfs_warning (s, "vs-4080: reiserfs_free_block: "
- "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
- reiserfs_bdevname (s), block);
- }
- apbi[nr].free_count ++;
- journal_mark_dirty (th, s, apbi[nr].bh);
-
- reiserfs_prepare_for_journal(s, sbh, 1) ;
- /* update super block */
- set_sb_free_blocks( rs, sb_free_blocks(rs) + 1 );
-
- journal_mark_dirty (th, s, sbh);
- if (for_unformatted)
- DQUOT_FREE_BLOCK_NODIRTY(inode, 1);
+ if (nr >= sb_bmap_nr(rs)) {
+ reiserfs_warning(s, "vs-4075: reiserfs_free_block: "
+ "block %lu is out of range on %s",
+ block, reiserfs_bdevname(s));
+ return;
+ }
+
+ reiserfs_prepare_for_journal(s, apbi[nr].bh, 1);
+
+ /* clear bit for the given block in bit map */
+ if (!reiserfs_test_and_clear_le_bit(offset, apbi[nr].bh->b_data)) {
+ reiserfs_warning(s, "vs-4080: reiserfs_free_block: "
+ "free_block (%s:%lu)[dev:blocknr]: bit already cleared",
+ reiserfs_bdevname(s), block);
+ }
+ apbi[nr].free_count++;
+ journal_mark_dirty(th, s, apbi[nr].bh);
+
+ reiserfs_prepare_for_journal(s, sbh, 1);
+ /* update super block */
+ set_sb_free_blocks(rs, sb_free_blocks(rs) + 1);
+
+ journal_mark_dirty(th, s, sbh);
+ if (for_unformatted)
+ DQUOT_FREE_BLOCK_NODIRTY(inode, 1);
}
-void reiserfs_free_block (struct reiserfs_transaction_handle *th,
- struct inode *inode, b_blocknr_t block,
- int for_unformatted)
+void reiserfs_free_block(struct reiserfs_transaction_handle *th,
+ struct inode *inode, b_blocknr_t block,
+ int for_unformatted)
{
- struct super_block * s = th->t_super;
+ struct super_block *s = th->t_super;
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
- RFALSE(is_reusable (s, block, 1) == 0, "vs-4071: can not free such block");
- /* mark it before we clear it, just in case */
- journal_mark_freed(th, s, block) ;
- _reiserfs_free_block(th, inode, block, for_unformatted) ;
+ RFALSE(!s, "vs-4061: trying to free block on nonexistent device");
+ RFALSE(is_reusable(s, block, 1) == 0,
+ "vs-4071: can not free such block");
+ /* mark it before we clear it, just in case */
+ journal_mark_freed(th, s, block);
+ _reiserfs_free_block(th, inode, block, for_unformatted);
}
/* preallocated blocks don't need to be run through journal_mark_freed */
-static void reiserfs_free_prealloc_block (struct reiserfs_transaction_handle *th,
- struct inode *inode, b_blocknr_t block) {
- RFALSE(!th->t_super, "vs-4060: trying to free block on nonexistent device");
- RFALSE(is_reusable (th->t_super, block, 1) == 0, "vs-4070: can not free such block");
- BUG_ON (!th->t_trans_id);
- _reiserfs_free_block(th, inode, block, 1) ;
+static void reiserfs_free_prealloc_block(struct reiserfs_transaction_handle *th,
+ struct inode *inode, b_blocknr_t block)
+{
+ RFALSE(!th->t_super,
+ "vs-4060: trying to free block on nonexistent device");
+ RFALSE(is_reusable(th->t_super, block, 1) == 0,
+ "vs-4070: can not free such block");
+ BUG_ON(!th->t_trans_id);
+ _reiserfs_free_block(th, inode, block, 1);
}
-static void __discard_prealloc (struct reiserfs_transaction_handle * th,
- struct reiserfs_inode_info *ei)
+static void __discard_prealloc(struct reiserfs_transaction_handle *th,
+ struct reiserfs_inode_info *ei)
{
- unsigned long save = ei->i_prealloc_block ;
- int dirty = 0;
- struct inode *inode = &ei->vfs_inode;
- BUG_ON (!th->t_trans_id);
+ unsigned long save = ei->i_prealloc_block;
+ int dirty = 0;
+ struct inode *inode = &ei->vfs_inode;
+ BUG_ON(!th->t_trans_id);
#ifdef CONFIG_REISERFS_CHECK
- if (ei->i_prealloc_count < 0)
- reiserfs_warning (th->t_super, "zam-4001:%s: inode has negative prealloc blocks count.", __FUNCTION__ );
+ if (ei->i_prealloc_count < 0)
+ reiserfs_warning(th->t_super,
+ "zam-4001:%s: inode has negative prealloc blocks count.",
+ __FUNCTION__);
#endif
- while (ei->i_prealloc_count > 0) {
- reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
- ei->i_prealloc_block++;
- ei->i_prealloc_count --;
- dirty = 1;
- }
- if (dirty)
- reiserfs_update_sd(th, inode);
- ei->i_prealloc_block = save;
- list_del_init(&(ei->i_prealloc_list));
+ while (ei->i_prealloc_count > 0) {
+ reiserfs_free_prealloc_block(th, inode, ei->i_prealloc_block);
+ ei->i_prealloc_block++;
+ ei->i_prealloc_count--;
+ dirty = 1;
+ }
+ if (dirty)
+ reiserfs_update_sd(th, inode);
+ ei->i_prealloc_block = save;
+ list_del_init(&(ei->i_prealloc_list));
}
/* FIXME: It should be inline function */
-void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
- struct inode *inode)
+void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
+ struct inode *inode)
{
- struct reiserfs_inode_info *ei = REISERFS_I(inode);
- BUG_ON (!th->t_trans_id);
- if (ei->i_prealloc_count)
- __discard_prealloc(th, ei);
+ struct reiserfs_inode_info *ei = REISERFS_I(inode);
+ BUG_ON(!th->t_trans_id);
+ if (ei->i_prealloc_count)
+ __discard_prealloc(th, ei);
}
-void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th)
+void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th)
{
- struct list_head * plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
+ struct list_head *plist = &SB_JOURNAL(th->t_super)->j_prealloc_list;
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- while (!list_empty(plist)) {
- struct reiserfs_inode_info *ei;
- ei = list_entry(plist->next, struct reiserfs_inode_info, i_prealloc_list);
+ while (!list_empty(plist)) {
+ struct reiserfs_inode_info *ei;
+ ei = list_entry(plist->next, struct reiserfs_inode_info,
+ i_prealloc_list);
#ifdef CONFIG_REISERFS_CHECK
- if (!ei->i_prealloc_count) {
- reiserfs_warning (th->t_super, "zam-4001:%s: inode is in prealloc list but has no preallocated blocks.", __FUNCTION__);
- }
+ if (!ei->i_prealloc_count) {
+ reiserfs_warning(th->t_super,
+ "zam-4001:%s: inode is in prealloc list but has no preallocated blocks.",
+ __FUNCTION__);
+ }
#endif
- __discard_prealloc(th, ei);
- }
+ __discard_prealloc(th, ei);
+ }
}
-void reiserfs_init_alloc_options (struct super_block *s)
+void reiserfs_init_alloc_options(struct super_block *s)
{
- set_bit (_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
- set_bit (_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
- set_bit (_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
+ set_bit(_ALLOC_skip_busy, &SB_ALLOC_OPTS(s));
+ set_bit(_ALLOC_dirid_groups, &SB_ALLOC_OPTS(s));
+ set_bit(_ALLOC_packing_groups, &SB_ALLOC_OPTS(s));
}
/* block allocator related options are parsed here */
-int reiserfs_parse_alloc_options(struct super_block * s, char * options)
+int reiserfs_parse_alloc_options(struct super_block *s, char *options)
{
- char * this_char, * value;
-
- REISERFS_SB(s)->s_alloc_options.bits = 0; /* clear default settings */
-
- while ( (this_char = strsep (&options, ":")) != NULL ) {
- if ((value = strchr (this_char, '=')) != NULL)
- *value++ = 0;
-
- if (!strcmp(this_char, "concentrating_formatted_nodes")) {
- int temp;
- SET_OPTION(concentrating_formatted_nodes);
- temp = (value && *value) ? simple_strtoul (value, &value, 0) : 10;
- if (temp <= 0 || temp > 100) {
- REISERFS_SB(s)->s_alloc_options.border = 10;
- } else {
- REISERFS_SB(s)->s_alloc_options.border = 100 / temp;
- }
- continue;
- }
- if (!strcmp(this_char, "displacing_large_files")) {
- SET_OPTION(displacing_large_files);
- REISERFS_SB(s)->s_alloc_options.large_file_size =
- (value && *value) ? simple_strtoul (value, &value, 0) : 16;
- continue;
- }
- if (!strcmp(this_char, "displacing_new_packing_localities")) {
- SET_OPTION(displacing_new_packing_localities);
- continue;
- };
-
- if (!strcmp(this_char, "old_hashed_relocation")) {
- SET_OPTION(old_hashed_relocation);
- continue;
- }
+ char *this_char, *value;
+
+ REISERFS_SB(s)->s_alloc_options.bits = 0; /* clear default settings */
+
+ while ((this_char = strsep(&options, ":")) != NULL) {
+ if ((value = strchr(this_char, '=')) != NULL)
+ *value++ = 0;
+
+ if (!strcmp(this_char, "concentrating_formatted_nodes")) {
+ int temp;
+ SET_OPTION(concentrating_formatted_nodes);
+ temp = (value
+ && *value) ? simple_strtoul(value, &value,
+ 0) : 10;
+ if (temp <= 0 || temp > 100) {
+ REISERFS_SB(s)->s_alloc_options.border = 10;
+ } else {
+ REISERFS_SB(s)->s_alloc_options.border =
+ 100 / temp;
+ }
+ continue;
+ }
+ if (!strcmp(this_char, "displacing_large_files")) {
+ SET_OPTION(displacing_large_files);
+ REISERFS_SB(s)->s_alloc_options.large_file_size =
+ (value
+ && *value) ? simple_strtoul(value, &value, 0) : 16;
+ continue;
+ }
+ if (!strcmp(this_char, "displacing_new_packing_localities")) {
+ SET_OPTION(displacing_new_packing_localities);
+ continue;
+ };
+
+ if (!strcmp(this_char, "old_hashed_relocation")) {
+ SET_OPTION(old_hashed_relocation);
+ continue;
+ }
- if (!strcmp(this_char, "new_hashed_relocation")) {
- SET_OPTION(new_hashed_relocation);
- continue;
- }
+ if (!strcmp(this_char, "new_hashed_relocation")) {
+ SET_OPTION(new_hashed_relocation);
+ continue;
+ }
- if (!strcmp(this_char, "dirid_groups")) {
- SET_OPTION(dirid_groups);
- continue;
- }
- if (!strcmp(this_char, "oid_groups")) {
- SET_OPTION(oid_groups);
- continue;
- }
- if (!strcmp(this_char, "packing_groups")) {
- SET_OPTION(packing_groups);
- continue;
- }
- if (!strcmp(this_char, "hashed_formatted_nodes")) {
- SET_OPTION(hashed_formatted_nodes);
- continue;
- }
+ if (!strcmp(this_char, "dirid_groups")) {
+ SET_OPTION(dirid_groups);
+ continue;
+ }
+ if (!strcmp(this_char, "oid_groups")) {
+ SET_OPTION(oid_groups);
+ continue;
+ }
+ if (!strcmp(this_char, "packing_groups")) {
+ SET_OPTION(packing_groups);
+ continue;
+ }
+ if (!strcmp(this_char, "hashed_formatted_nodes")) {
+ SET_OPTION(hashed_formatted_nodes);
+ continue;
+ }
- if (!strcmp(this_char, "skip_busy")) {
- SET_OPTION(skip_busy);
- continue;
- }
+ if (!strcmp(this_char, "skip_busy")) {
+ SET_OPTION(skip_busy);
+ continue;
+ }
- if (!strcmp(this_char, "hundredth_slices")) {
- SET_OPTION(hundredth_slices);
- continue;
- }
+ if (!strcmp(this_char, "hundredth_slices")) {
+ SET_OPTION(hundredth_slices);
+ continue;
+ }
- if (!strcmp(this_char, "old_way")) {
- SET_OPTION(old_way);
- continue;
- }
+ if (!strcmp(this_char, "old_way")) {
+ SET_OPTION(old_way);
+ continue;
+ }
- if (!strcmp(this_char, "displace_based_on_dirid")) {
- SET_OPTION(displace_based_on_dirid);
- continue;
- }
+ if (!strcmp(this_char, "displace_based_on_dirid")) {
+ SET_OPTION(displace_based_on_dirid);
+ continue;
+ }
- if (!strcmp(this_char, "preallocmin")) {
- REISERFS_SB(s)->s_alloc_options.preallocmin =
- (value && *value) ? simple_strtoul (value, &value, 0) : 4;
- continue;
- }
+ if (!strcmp(this_char, "preallocmin")) {
+ REISERFS_SB(s)->s_alloc_options.preallocmin =
+ (value
+ && *value) ? simple_strtoul(value, &value, 0) : 4;
+ continue;
+ }
+
+ if (!strcmp(this_char, "preallocsize")) {
+ REISERFS_SB(s)->s_alloc_options.preallocsize =
+ (value
+ && *value) ? simple_strtoul(value, &value,
+ 0) :
+ PREALLOCATION_SIZE;
+ continue;
+ }
- if (!strcmp(this_char, "preallocsize")) {
- REISERFS_SB(s)->s_alloc_options.preallocsize =
- (value && *value) ? simple_strtoul (value, &value, 0) : PREALLOCATION_SIZE;
- continue;
+ reiserfs_warning(s, "zam-4001: %s : unknown option - %s",
+ __FUNCTION__, this_char);
+ return 1;
}
- reiserfs_warning (s, "zam-4001: %s : unknown option - %s",
- __FUNCTION__ , this_char);
- return 1;
- }
-
- reiserfs_warning (s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
- return 0;
+ reiserfs_warning(s, "allocator options = [%08x]\n", SB_ALLOC_OPTS(s));
+ return 0;
}
-
-static inline void new_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+
+static inline void new_hashed_relocation(reiserfs_blocknr_hint_t * hint)
{
- char * hash_in;
- if (hint->formatted_node) {
- hash_in = (char*)&hint->key.k_dir_id;
- } else {
- if (!hint->inode) {
- //hint->search_start = hint->beg;
- hash_in = (char*)&hint->key.k_dir_id;
- } else
- if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
- hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
- else
- hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
- }
+ char *hash_in;
+ if (hint->formatted_node) {
+ hash_in = (char *)&hint->key.k_dir_id;
+ } else {
+ if (!hint->inode) {
+ //hint->search_start = hint->beg;
+ hash_in = (char *)&hint->key.k_dir_id;
+ } else
+ if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+ hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+ else
+ hash_in =
+ (char *)(&INODE_PKEY(hint->inode)->k_objectid);
+ }
- hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+ hint->search_start =
+ hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
}
/*
* Relocation based on dirid, hashing them into a given bitmap block
* files. Formatted nodes are unaffected, a seperate policy covers them
*/
-static void
-dirid_groups (reiserfs_blocknr_hint_t *hint)
+static void dirid_groups(reiserfs_blocknr_hint_t * hint)
{
- unsigned long hash;
- __u32 dirid = 0;
- int bm = 0;
- struct super_block *sb = hint->th->t_super;
- if (hint->inode)
- dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
- else if (hint->formatted_node)
- dirid = hint->key.k_dir_id;
-
- if (dirid) {
- bm = bmap_hash_id(sb, dirid);
- hash = bm * (sb->s_blocksize << 3);
- /* give a portion of the block group to metadata */
+ unsigned long hash;
+ __u32 dirid = 0;
+ int bm = 0;
+ struct super_block *sb = hint->th->t_super;
if (hint->inode)
- hash += sb->s_blocksize/2;
- hint->search_start = hash;
- }
+ dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+ else if (hint->formatted_node)
+ dirid = hint->key.k_dir_id;
+
+ if (dirid) {
+ bm = bmap_hash_id(sb, dirid);
+ hash = bm * (sb->s_blocksize << 3);
+ /* give a portion of the block group to metadata */
+ if (hint->inode)
+ hash += sb->s_blocksize / 2;
+ hint->search_start = hash;
+ }
}
/*
* Relocation based on oid, hashing them into a given bitmap block
* files. Formatted nodes are unaffected, a seperate policy covers them
*/
-static void
-oid_groups (reiserfs_blocknr_hint_t *hint)
+static void oid_groups(reiserfs_blocknr_hint_t * hint)
{
- if (hint->inode) {
- unsigned long hash;
- __u32 oid;
- __u32 dirid;
- int bm;
-
- dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
-
- /* keep the root dir and it's first set of subdirs close to
- * the start of the disk
- */
- if (dirid <= 2)
- hash = (hint->inode->i_sb->s_blocksize << 3);
- else {
- oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
- bm = bmap_hash_id(hint->inode->i_sb, oid);
- hash = bm * (hint->inode->i_sb->s_blocksize << 3);
+ if (hint->inode) {
+ unsigned long hash;
+ __u32 oid;
+ __u32 dirid;
+ int bm;
+
+ dirid = le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id);
+
+ /* keep the root dir and it's first set of subdirs close to
+ * the start of the disk
+ */
+ if (dirid <= 2)
+ hash = (hint->inode->i_sb->s_blocksize << 3);
+ else {
+ oid = le32_to_cpu(INODE_PKEY(hint->inode)->k_objectid);
+ bm = bmap_hash_id(hint->inode->i_sb, oid);
+ hash = bm * (hint->inode->i_sb->s_blocksize << 3);
+ }
+ hint->search_start = hash;
}
- hint->search_start = hash;
- }
}
/* returns 1 if it finds an indirect item and gets valid hint info
* from it, otherwise 0
*/
-static int get_left_neighbor(reiserfs_blocknr_hint_t *hint)
+static int get_left_neighbor(reiserfs_blocknr_hint_t * hint)
{
- struct path * path;
- struct buffer_head * bh;
- struct item_head * ih;
- int pos_in_item;
- __le32 * item;
- int ret = 0;
-
- if (!hint->path) /* reiserfs code can call this function w/o pointer to path
+ struct path *path;
+ struct buffer_head *bh;
+ struct item_head *ih;
+ int pos_in_item;
+ __le32 *item;
+ int ret = 0;
+
+ if (!hint->path) /* reiserfs code can call this function w/o pointer to path
* structure supplied; then we rely on supplied search_start */
- return 0;
-
- path = hint->path;
- bh = get_last_bh(path);
- RFALSE( !bh, "green-4002: Illegal path specified to get_left_neighbor");
- ih = get_ih(path);
- pos_in_item = path->pos_in_item;
- item = get_item (path);
-
- hint->search_start = bh->b_blocknr;
-
- if (!hint->formatted_node && is_indirect_le_ih (ih)) {
- /* for indirect item: go to left and look for the first non-hole entry
- in the indirect item */
- if (pos_in_item == I_UNFM_NUM (ih))
- pos_in_item--;
-// pos_in_item = I_UNFM_NUM (ih) - 1;
- while (pos_in_item >= 0) {
- int t=get_block_num(item,pos_in_item);
- if (t) {
- hint->search_start = t;
- ret = 1;
- break;
- }
- pos_in_item --;
+ return 0;
+
+ path = hint->path;
+ bh = get_last_bh(path);
+ RFALSE(!bh, "green-4002: Illegal path specified to get_left_neighbor");
+ ih = get_ih(path);
+ pos_in_item = path->pos_in_item;
+ item = get_item(path);
+
+ hint->search_start = bh->b_blocknr;
+
+ if (!hint->formatted_node && is_indirect_le_ih(ih)) {
+ /* for indirect item: go to left and look for the first non-hole entry
+ in the indirect item */
+ if (pos_in_item == I_UNFM_NUM(ih))
+ pos_in_item--;
+// pos_in_item = I_UNFM_NUM (ih) - 1;
+ while (pos_in_item >= 0) {
+ int t = get_block_num(item, pos_in_item);
+ if (t) {
+ hint->search_start = t;
+ ret = 1;
+ break;
+ }
+ pos_in_item--;
+ }
}
- }
- /* does result value fit into specified region? */
- return ret;
+ /* does result value fit into specified region? */
+ return ret;
}
/* should be, if formatted node, then try to put on first part of the device
specified as number of percent with mount option device, else try to put
on last of device. This is not to say it is good code to do so,
but the effect should be measured. */
-static inline void set_border_in_hint(struct super_block *s, reiserfs_blocknr_hint_t *hint)
+static inline void set_border_in_hint(struct super_block *s,
+ reiserfs_blocknr_hint_t * hint)
{
- b_blocknr_t border = SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
+ b_blocknr_t border =
+ SB_BLOCK_COUNT(s) / REISERFS_SB(s)->s_alloc_options.border;
- if (hint->formatted_node)
- hint->end = border - 1;
- else
- hint->beg = border;
+ if (hint->formatted_node)
+ hint->end = border - 1;
+ else
+ hint->beg = border;
}
-static inline void displace_large_file(reiserfs_blocknr_hint_t *hint)
+static inline void displace_large_file(reiserfs_blocknr_hint_t * hint)
{
- if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
- hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id), 4) % (hint->end - hint->beg);
- else
- hint->search_start = hint->beg + keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid), 4) % (hint->end - hint->beg);
+ if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+ hint->search_start =
+ hint->beg +
+ keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_dir_id),
+ 4) % (hint->end - hint->beg);
+ else
+ hint->search_start =
+ hint->beg +
+ keyed_hash((char *)(&INODE_PKEY(hint->inode)->k_objectid),
+ 4) % (hint->end - hint->beg);
}
-static inline void hash_formatted_node(reiserfs_blocknr_hint_t *hint)
+static inline void hash_formatted_node(reiserfs_blocknr_hint_t * hint)
{
- char * hash_in;
+ char *hash_in;
- if (!hint->inode)
- hash_in = (char*)&hint->key.k_dir_id;
- else if ( TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
- hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
- else
- hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
+ if (!hint->inode)
+ hash_in = (char *)&hint->key.k_dir_id;
+ else if (TEST_OPTION(displace_based_on_dirid, hint->th->t_super))
+ hash_in = (char *)(&INODE_PKEY(hint->inode)->k_dir_id);
+ else
+ hash_in = (char *)(&INODE_PKEY(hint->inode)->k_objectid);
- hint->search_start = hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
+ hint->search_start =
+ hint->beg + keyed_hash(hash_in, 4) % (hint->end - hint->beg);
}
-static inline int this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *hint)
+static inline int
+this_blocknr_allocation_would_make_it_a_large_file(reiserfs_blocknr_hint_t *
+ hint)
{
- return hint->block == REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
+ return hint->block ==
+ REISERFS_SB(hint->th->t_super)->s_alloc_options.large_file_size;
}
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
-static inline void displace_new_packing_locality (reiserfs_blocknr_hint_t *hint)
+static inline void displace_new_packing_locality(reiserfs_blocknr_hint_t * hint)
{
- struct in_core_key * key = &hint->key;
+ struct in_core_key *key = &hint->key;
- hint->th->displace_new_blocks = 0;
- hint->search_start = hint->beg + keyed_hash((char*)(&key->k_objectid),4) % (hint->end - hint->beg);
+ hint->th->displace_new_blocks = 0;
+ hint->search_start =
+ hint->beg + keyed_hash((char *)(&key->k_objectid),
+ 4) % (hint->end - hint->beg);
}
- #endif
+#endif
-static inline int old_hashed_relocation (reiserfs_blocknr_hint_t * hint)
+static inline int old_hashed_relocation(reiserfs_blocknr_hint_t * hint)
{
- b_blocknr_t border;
- u32 hash_in;
-
- if (hint->formatted_node || hint->inode == NULL) {
- return 0;
- }
+ b_blocknr_t border;
+ u32 hash_in;
- hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
- border = hint->beg + (u32) keyed_hash(((char *) (&hash_in)), 4) % (hint->end - hint->beg - 1);
- if (border > hint->search_start)
- hint->search_start = border;
+ if (hint->formatted_node || hint->inode == NULL) {
+ return 0;
+ }
- return 1;
- }
-
-static inline int old_way (reiserfs_blocknr_hint_t * hint)
-{
- b_blocknr_t border;
-
- if (hint->formatted_node || hint->inode == NULL) {
- return 0;
- }
-
- border = hint->beg + le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end - hint->beg);
- if (border > hint->search_start)
- hint->search_start = border;
+ hash_in = le32_to_cpu((INODE_PKEY(hint->inode))->k_dir_id);
+ border =
+ hint->beg + (u32) keyed_hash(((char *)(&hash_in)),
+ 4) % (hint->end - hint->beg - 1);
+ if (border > hint->search_start)
+ hint->search_start = border;
- return 1;
+ return 1;
}
-static inline void hundredth_slices (reiserfs_blocknr_hint_t * hint)
+static inline int old_way(reiserfs_blocknr_hint_t * hint)
{
- struct in_core_key * key = &hint->key;
- b_blocknr_t slice_start;
+ b_blocknr_t border;
+
+ if (hint->formatted_node || hint->inode == NULL) {
+ return 0;
+ }
+
+ border =
+ hint->beg +
+ le32_to_cpu(INODE_PKEY(hint->inode)->k_dir_id) % (hint->end -
+ hint->beg);
+ if (border > hint->search_start)
+ hint->search_start = border;
- slice_start = (keyed_hash((char*)(&key->k_dir_id),4) % 100) * (hint->end / 100);
- if ( slice_start > hint->search_start || slice_start + (hint->end / 100) <= hint->search_start) {
- hint->search_start = slice_start;
- }
+ return 1;
+}
+
+static inline void hundredth_slices(reiserfs_blocknr_hint_t * hint)
+{
+ struct in_core_key *key = &hint->key;
+ b_blocknr_t slice_start;
+
+ slice_start =
+ (keyed_hash((char *)(&key->k_dir_id), 4) % 100) * (hint->end / 100);
+ if (slice_start > hint->search_start
+ || slice_start + (hint->end / 100) <= hint->search_start) {
+ hint->search_start = slice_start;
+ }
}
-
-static void determine_search_start(reiserfs_blocknr_hint_t *hint,
- int amount_needed)
+
+static void determine_search_start(reiserfs_blocknr_hint_t * hint,
+ int amount_needed)
{
- struct super_block *s = hint->th->t_super;
- int unfm_hint;
+ struct super_block *s = hint->th->t_super;
+ int unfm_hint;
- hint->beg = 0;
- hint->end = SB_BLOCK_COUNT(s) - 1;
+ hint->beg = 0;
+ hint->end = SB_BLOCK_COUNT(s) - 1;
- /* This is former border algorithm. Now with tunable border offset */
- if (concentrating_formatted_nodes(s))
- set_border_in_hint(s, hint);
+ /* This is former border algorithm. Now with tunable border offset */
+ if (concentrating_formatted_nodes(s))
+ set_border_in_hint(s, hint);
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- /* whenever we create a new directory, we displace it. At first we will
- hash for location, later we might look for a moderately empty place for
- it */
- if (displacing_new_packing_localities(s)
- && hint->th->displace_new_blocks) {
- displace_new_packing_locality(hint);
-
- /* we do not continue determine_search_start,
- * if new packing locality is being displaced */
- return;
- }
+ /* whenever we create a new directory, we displace it. At first we will
+ hash for location, later we might look for a moderately empty place for
+ it */
+ if (displacing_new_packing_localities(s)
+ && hint->th->displace_new_blocks) {
+ displace_new_packing_locality(hint);
+
+ /* we do not continue determine_search_start,
+ * if new packing locality is being displaced */
+ return;
+ }
#endif
-
- /* all persons should feel encouraged to add more special cases here and
- * test them */
- if (displacing_large_files(s) && !hint->formatted_node
- && this_blocknr_allocation_would_make_it_a_large_file(hint)) {
- displace_large_file(hint);
- return;
- }
-
- /* if none of our special cases is relevant, use the left neighbor in the
- tree order of the new node we are allocating for */
- if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes,s)) {
- hash_formatted_node(hint);
- return;
- }
+ /* all persons should feel encouraged to add more special cases here and
+ * test them */
- unfm_hint = get_left_neighbor(hint);
+ if (displacing_large_files(s) && !hint->formatted_node
+ && this_blocknr_allocation_would_make_it_a_large_file(hint)) {
+ displace_large_file(hint);
+ return;
+ }
- /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
- new blocks are displaced based on directory ID. Also, if suggested search_start
- is less than last preallocated block, we start searching from it, assuming that
- HDD dataflow is faster in forward direction */
- if ( TEST_OPTION(old_way, s)) {
- if (!hint->formatted_node) {
- if ( !reiserfs_hashed_relocation(s))
- old_way(hint);
- else if (!reiserfs_no_unhashed_relocation(s))
- old_hashed_relocation(hint);
+ /* if none of our special cases is relevant, use the left neighbor in the
+ tree order of the new node we are allocating for */
+ if (hint->formatted_node && TEST_OPTION(hashed_formatted_nodes, s)) {
+ hash_formatted_node(hint);
+ return;
+ }
- if ( hint->inode && hint->search_start < REISERFS_I(hint->inode)->i_prealloc_block)
- hint->search_start = REISERFS_I(hint->inode)->i_prealloc_block;
+ unfm_hint = get_left_neighbor(hint);
+
+ /* Mimic old block allocator behaviour, that is if VFS allowed for preallocation,
+ new blocks are displaced based on directory ID. Also, if suggested search_start
+ is less than last preallocated block, we start searching from it, assuming that
+ HDD dataflow is faster in forward direction */
+ if (TEST_OPTION(old_way, s)) {
+ if (!hint->formatted_node) {
+ if (!reiserfs_hashed_relocation(s))
+ old_way(hint);
+ else if (!reiserfs_no_unhashed_relocation(s))
+ old_hashed_relocation(hint);
+
+ if (hint->inode
+ && hint->search_start <
+ REISERFS_I(hint->inode)->i_prealloc_block)
+ hint->search_start =
+ REISERFS_I(hint->inode)->i_prealloc_block;
+ }
+ return;
}
- return;
- }
- /* This is an approach proposed by Hans */
- if ( TEST_OPTION(hundredth_slices, s) && ! (displacing_large_files(s) && !hint->formatted_node)) {
- hundredth_slices(hint);
- return;
- }
-
- /* old_hashed_relocation only works on unformatted */
- if (!unfm_hint && !hint->formatted_node &&
- TEST_OPTION(old_hashed_relocation, s))
- {
- old_hashed_relocation(hint);
- }
- /* new_hashed_relocation works with both formatted/unformatted nodes */
- if ((!unfm_hint || hint->formatted_node) &&
- TEST_OPTION(new_hashed_relocation, s))
- {
- new_hashed_relocation(hint);
- }
- /* dirid grouping works only on unformatted nodes */
- if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups,s))
- {
- dirid_groups(hint);
- }
+ /* This is an approach proposed by Hans */
+ if (TEST_OPTION(hundredth_slices, s)
+ && !(displacing_large_files(s) && !hint->formatted_node)) {
+ hundredth_slices(hint);
+ return;
+ }
+ /* old_hashed_relocation only works on unformatted */
+ if (!unfm_hint && !hint->formatted_node &&
+ TEST_OPTION(old_hashed_relocation, s)) {
+ old_hashed_relocation(hint);
+ }
+ /* new_hashed_relocation works with both formatted/unformatted nodes */
+ if ((!unfm_hint || hint->formatted_node) &&
+ TEST_OPTION(new_hashed_relocation, s)) {
+ new_hashed_relocation(hint);
+ }
+ /* dirid grouping works only on unformatted nodes */
+ if (!unfm_hint && !hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
+ dirid_groups(hint);
+ }
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- if (hint->formatted_node && TEST_OPTION(dirid_groups,s))
- {
- dirid_groups(hint);
- }
+ if (hint->formatted_node && TEST_OPTION(dirid_groups, s)) {
+ dirid_groups(hint);
+ }
#endif
- /* oid grouping works only on unformatted nodes */
- if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups,s))
- {
- oid_groups(hint);
- }
- return;
+ /* oid grouping works only on unformatted nodes */
+ if (!unfm_hint && !hint->formatted_node && TEST_OPTION(oid_groups, s)) {
+ oid_groups(hint);
+ }
+ return;
}
static int determine_prealloc_size(reiserfs_blocknr_hint_t * hint)
{
- /* make minimum size a mount option and benchmark both ways */
- /* we preallocate blocks only for regular files, specific size */
- /* benchmark preallocating always and see what happens */
-
- hint->prealloc_size = 0;
-
- if (!hint->formatted_node && hint->preallocate) {
- if (S_ISREG(hint->inode->i_mode)
- && hint->inode->i_size >= REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocmin * hint->inode->i_sb->s_blocksize)
- hint->prealloc_size = REISERFS_SB(hint->th->t_super)->s_alloc_options.preallocsize - 1;
- }
- return CARRY_ON;
+ /* make minimum size a mount option and benchmark both ways */
+ /* we preallocate blocks only for regular files, specific size */
+ /* benchmark preallocating always and see what happens */
+
+ hint->prealloc_size = 0;
+
+ if (!hint->formatted_node && hint->preallocate) {
+ if (S_ISREG(hint->inode->i_mode)
+ && hint->inode->i_size >=
+ REISERFS_SB(hint->th->t_super)->s_alloc_options.
+ preallocmin * hint->inode->i_sb->s_blocksize)
+ hint->prealloc_size =
+ REISERFS_SB(hint->th->t_super)->s_alloc_options.
+ preallocsize - 1;
+ }
+ return CARRY_ON;
}
/* XXX I know it could be merged with upper-level function;
but may be result function would be too complex. */
-static inline int allocate_without_wrapping_disk (reiserfs_blocknr_hint_t * hint,
- b_blocknr_t * new_blocknrs,
- b_blocknr_t start, b_blocknr_t finish,
- int min,
- int amount_needed, int prealloc_size)
+static inline int allocate_without_wrapping_disk(reiserfs_blocknr_hint_t * hint,
+ b_blocknr_t * new_blocknrs,
+ b_blocknr_t start,
+ b_blocknr_t finish, int min,
+ int amount_needed,
+ int prealloc_size)
{
- int rest = amount_needed;
- int nr_allocated;
-
- while (rest > 0 && start <= finish) {
- nr_allocated = scan_bitmap (hint->th, &start, finish, min,
- rest + prealloc_size, !hint->formatted_node,
- hint->block);
-
- if (nr_allocated == 0) /* no new blocks allocated, return */
- break;
-
- /* fill free_blocknrs array first */
- while (rest > 0 && nr_allocated > 0) {
- * new_blocknrs ++ = start ++;
- rest --; nr_allocated --;
- }
+ int rest = amount_needed;
+ int nr_allocated;
+
+ while (rest > 0 && start <= finish) {
+ nr_allocated = scan_bitmap(hint->th, &start, finish, min,
+ rest + prealloc_size,
+ !hint->formatted_node, hint->block);
+
+ if (nr_allocated == 0) /* no new blocks allocated, return */
+ break;
+
+ /* fill free_blocknrs array first */
+ while (rest > 0 && nr_allocated > 0) {
+ *new_blocknrs++ = start++;
+ rest--;
+ nr_allocated--;
+ }
- /* do we have something to fill prealloc. array also ? */
- if (nr_allocated > 0) {
- /* it means prealloc_size was greater that 0 and we do preallocation */
- list_add(&REISERFS_I(hint->inode)->i_prealloc_list,
- &SB_JOURNAL(hint->th->t_super)->j_prealloc_list);
- REISERFS_I(hint->inode)->i_prealloc_block = start;
- REISERFS_I(hint->inode)->i_prealloc_count = nr_allocated;
- break;
+ /* do we have something to fill prealloc. array also ? */
+ if (nr_allocated > 0) {
+ /* it means prealloc_size was greater that 0 and we do preallocation */
+ list_add(&REISERFS_I(hint->inode)->i_prealloc_list,
+ &SB_JOURNAL(hint->th->t_super)->
+ j_prealloc_list);
+ REISERFS_I(hint->inode)->i_prealloc_block = start;
+ REISERFS_I(hint->inode)->i_prealloc_count =
+ nr_allocated;
+ break;
+ }
}
- }
- return (amount_needed - rest);
+ return (amount_needed - rest);
}
static inline int blocknrs_and_prealloc_arrays_from_search_start
- (reiserfs_blocknr_hint_t *hint, b_blocknr_t *new_blocknrs, int amount_needed)
-{
- struct super_block *s = hint->th->t_super;
- b_blocknr_t start = hint->search_start;
- b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
- int passno = 0;
- int nr_allocated = 0;
- int bigalloc = 0;
-
- determine_prealloc_size(hint);
- if (!hint->formatted_node) {
- int quota_ret;
+ (reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs,
+ int amount_needed) {
+ struct super_block *s = hint->th->t_super;
+ b_blocknr_t start = hint->search_start;
+ b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1;
+ int passno = 0;
+ int nr_allocated = 0;
+ int bigalloc = 0;
+
+ determine_prealloc_size(hint);
+ if (!hint->formatted_node) {
+ int quota_ret;
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: allocating %d blocks id=%u", amount_needed, hint->inode->i_uid);
+ reiserfs_debug(s, REISERFS_DEBUG_CODE,
+ "reiserquota: allocating %d blocks id=%u",
+ amount_needed, hint->inode->i_uid);
#endif
- quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);
- if (quota_ret) /* Quota exceeded? */
- return QUOTA_EXCEEDED;
- if (hint->preallocate && hint->prealloc_size ) {
+ quota_ret =
+ DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed);
+ if (quota_ret) /* Quota exceeded? */
+ return QUOTA_EXCEEDED;
+ if (hint->preallocate && hint->prealloc_size) {
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: allocating (prealloc) %d blocks id=%u", hint->prealloc_size, hint->inode->i_uid);
+ reiserfs_debug(s, REISERFS_DEBUG_CODE,
+ "reiserquota: allocating (prealloc) %d blocks id=%u",
+ hint->prealloc_size, hint->inode->i_uid);
#endif
- quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, hint->prealloc_size);
- if (quota_ret)
- hint->preallocate=hint->prealloc_size=0;
+ quota_ret =
+ DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode,
+ hint->prealloc_size);
+ if (quota_ret)
+ hint->preallocate = hint->prealloc_size = 0;
+ }
+ /* for unformatted nodes, force large allocations */
+ bigalloc = amount_needed;
}
- /* for unformatted nodes, force large allocations */
- bigalloc = amount_needed;
- }
- do {
- /* in bigalloc mode, nr_allocated should stay zero until
- * the entire allocation is filled
- */
- if (unlikely(bigalloc && nr_allocated)) {
- reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
- bigalloc, nr_allocated);
- /* reset things to a sane value */
- bigalloc = amount_needed - nr_allocated;
- }
- /*
- * try pass 0 and pass 1 looking for a nice big
- * contiguous allocation. Then reset and look
- * for anything you can find.
- */
- if (passno == 2 && bigalloc) {
- passno = 0;
- bigalloc = 0;
- }
- switch (passno++) {
- case 0: /* Search from hint->search_start to end of disk */
- start = hint->search_start;
- finish = SB_BLOCK_COUNT(s) - 1;
- break;
- case 1: /* Search from hint->beg to hint->search_start */
- start = hint->beg;
- finish = hint->search_start;
- break;
- case 2: /* Last chance: Search from 0 to hint->beg */
- start = 0;
- finish = hint->beg;
- break;
- default: /* We've tried searching everywhere, not enough space */
- /* Free the blocks */
- if (!hint->formatted_node) {
+ do {
+ /* in bigalloc mode, nr_allocated should stay zero until
+ * the entire allocation is filled
+ */
+ if (unlikely(bigalloc && nr_allocated)) {
+ reiserfs_warning(s, "bigalloc is %d, nr_allocated %d\n",
+ bigalloc, nr_allocated);
+ /* reset things to a sane value */
+ bigalloc = amount_needed - nr_allocated;
+ }
+ /*
+ * try pass 0 and pass 1 looking for a nice big
+ * contiguous allocation. Then reset and look
+ * for anything you can find.
+ */
+ if (passno == 2 && bigalloc) {
+ passno = 0;
+ bigalloc = 0;
+ }
+ switch (passno++) {
+ case 0: /* Search from hint->search_start to end of disk */
+ start = hint->search_start;
+ finish = SB_BLOCK_COUNT(s) - 1;
+ break;
+ case 1: /* Search from hint->beg to hint->search_start */
+ start = hint->beg;
+ finish = hint->search_start;
+ break;
+ case 2: /* Last chance: Search from 0 to hint->beg */
+ start = 0;
+ finish = hint->beg;
+ break;
+ default: /* We've tried searching everywhere, not enough space */
+ /* Free the blocks */
+ if (!hint->formatted_node) {
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: freeing (nospace) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated, hint->inode->i_uid);
+ reiserfs_debug(s, REISERFS_DEBUG_CODE,
+ "reiserquota: freeing (nospace) %d blocks id=%u",
+ amount_needed +
+ hint->prealloc_size -
+ nr_allocated,
+ hint->inode->i_uid);
#endif
- DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated); /* Free not allocated blocks */
- }
- while (nr_allocated --)
- reiserfs_free_block(hint->th, hint->inode, new_blocknrs[nr_allocated], !hint->formatted_node);
-
- return NO_DISK_SPACE;
- }
- } while ((nr_allocated += allocate_without_wrapping_disk (hint,
- new_blocknrs + nr_allocated, start, finish,
- bigalloc ? bigalloc : 1,
- amount_needed - nr_allocated,
- hint->prealloc_size))
- < amount_needed);
- if ( !hint->formatted_node &&
- amount_needed + hint->prealloc_size >
- nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
- /* Some of preallocation blocks were not allocated */
+ DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated); /* Free not allocated blocks */
+ }
+ while (nr_allocated--)
+ reiserfs_free_block(hint->th, hint->inode,
+ new_blocknrs[nr_allocated],
+ !hint->formatted_node);
+
+ return NO_DISK_SPACE;
+ }
+ } while ((nr_allocated += allocate_without_wrapping_disk(hint,
+ new_blocknrs +
+ nr_allocated,
+ start, finish,
+ bigalloc ?
+ bigalloc : 1,
+ amount_needed -
+ nr_allocated,
+ hint->
+ prealloc_size))
+ < amount_needed);
+ if (!hint->formatted_node &&
+ amount_needed + hint->prealloc_size >
+ nr_allocated + REISERFS_I(hint->inode)->i_prealloc_count) {
+ /* Some of preallocation blocks were not allocated */
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (s, REISERFS_DEBUG_CODE, "reiserquota: freeing (failed prealloc) %d blocks id=%u", amount_needed + hint->prealloc_size - nr_allocated - REISERFS_I(hint->inode)->i_prealloc_count, hint->inode->i_uid);
+ reiserfs_debug(s, REISERFS_DEBUG_CODE,
+ "reiserquota: freeing (failed prealloc) %d blocks id=%u",
+ amount_needed + hint->prealloc_size -
+ nr_allocated -
+ REISERFS_I(hint->inode)->i_prealloc_count,
+ hint->inode->i_uid);
#endif
- DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +
- hint->prealloc_size - nr_allocated -
- REISERFS_I(hint->inode)->i_prealloc_count);
- }
+ DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed +
+ hint->prealloc_size - nr_allocated -
+ REISERFS_I(hint->inode)->
+ i_prealloc_count);
+ }
- return CARRY_ON;
+ return CARRY_ON;
}
/* grab new blocknrs from preallocated list */
/* return amount still needed after using them */
-static int use_preallocated_list_if_available (reiserfs_blocknr_hint_t *hint,
- b_blocknr_t *new_blocknrs, int amount_needed)
+static int use_preallocated_list_if_available(reiserfs_blocknr_hint_t * hint,
+ b_blocknr_t * new_blocknrs,
+ int amount_needed)
{
- struct inode * inode = hint->inode;
+ struct inode *inode = hint->inode;
- if (REISERFS_I(inode)->i_prealloc_count > 0) {
- while (amount_needed) {
+ if (REISERFS_I(inode)->i_prealloc_count > 0) {
+ while (amount_needed) {
- *new_blocknrs ++ = REISERFS_I(inode)->i_prealloc_block ++;
- REISERFS_I(inode)->i_prealloc_count --;
+ *new_blocknrs++ = REISERFS_I(inode)->i_prealloc_block++;
+ REISERFS_I(inode)->i_prealloc_count--;
- amount_needed --;
+ amount_needed--;
- if (REISERFS_I(inode)->i_prealloc_count <= 0) {
- list_del(&REISERFS_I(inode)->i_prealloc_list);
- break;
- }
+ if (REISERFS_I(inode)->i_prealloc_count <= 0) {
+ list_del(&REISERFS_I(inode)->i_prealloc_list);
+ break;
+ }
+ }
}
- }
- /* return amount still needed after using preallocated blocks */
- return amount_needed;
+ /* return amount still needed after using preallocated blocks */
+ return amount_needed;
}
-int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *hint,
- b_blocknr_t * new_blocknrs, int amount_needed,
- int reserved_by_us /* Amount of blocks we have
- already reserved */)
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t * hint, b_blocknr_t * new_blocknrs, int amount_needed, int reserved_by_us /* Amount of blocks we have
+ already reserved */ )
{
- int initial_amount_needed = amount_needed;
- int ret;
- struct super_block *s = hint->th->t_super;
-
- /* Check if there is enough space, taking into account reserved space */
- if ( SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks <
- amount_needed - reserved_by_us)
- return NO_DISK_SPACE;
- /* should this be if !hint->inode && hint->preallocate? */
- /* do you mean hint->formatted_node can be removed ? - Zam */
- /* hint->formatted_node cannot be removed because we try to access
- inode information here, and there is often no inode assotiated with
- metadata allocations - green */
-
- if (!hint->formatted_node && hint->preallocate) {
- amount_needed = use_preallocated_list_if_available
+ int initial_amount_needed = amount_needed;
+ int ret;
+ struct super_block *s = hint->th->t_super;
+
+ /* Check if there is enough space, taking into account reserved space */
+ if (SB_FREE_BLOCKS(s) - REISERFS_SB(s)->reserved_blocks <
+ amount_needed - reserved_by_us)
+ return NO_DISK_SPACE;
+ /* should this be if !hint->inode && hint->preallocate? */
+ /* do you mean hint->formatted_node can be removed ? - Zam */
+ /* hint->formatted_node cannot be removed because we try to access
+ inode information here, and there is often no inode assotiated with
+ metadata allocations - green */
+
+ if (!hint->formatted_node && hint->preallocate) {
+ amount_needed = use_preallocated_list_if_available
+ (hint, new_blocknrs, amount_needed);
+ if (amount_needed == 0) /* all blocknrs we need we got from
+ prealloc. list */
+ return CARRY_ON;
+ new_blocknrs += (initial_amount_needed - amount_needed);
+ }
+
+ /* find search start and save it in hint structure */
+ determine_search_start(hint, amount_needed);
+ if (hint->search_start >= SB_BLOCK_COUNT(s))
+ hint->search_start = SB_BLOCK_COUNT(s) - 1;
+
+ /* allocation itself; fill new_blocknrs and preallocation arrays */
+ ret = blocknrs_and_prealloc_arrays_from_search_start
(hint, new_blocknrs, amount_needed);
- if (amount_needed == 0) /* all blocknrs we need we got from
- prealloc. list */
- return CARRY_ON;
- new_blocknrs += (initial_amount_needed - amount_needed);
- }
-
- /* find search start and save it in hint structure */
- determine_search_start(hint, amount_needed);
- if (hint->search_start >= SB_BLOCK_COUNT(s))
- hint->search_start = SB_BLOCK_COUNT(s) - 1;
-
- /* allocation itself; fill new_blocknrs and preallocation arrays */
- ret = blocknrs_and_prealloc_arrays_from_search_start
- (hint, new_blocknrs, amount_needed);
-
- /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
- * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
- * variant) */
-
- if (ret != CARRY_ON) {
- while (amount_needed ++ < initial_amount_needed) {
- reiserfs_free_block(hint->th, hint->inode, *(--new_blocknrs), 1);
+
+ /* we used prealloc. list to fill (partially) new_blocknrs array. If final allocation fails we
+ * need to return blocks back to prealloc. list or just free them. -- Zam (I chose second
+ * variant) */
+
+ if (ret != CARRY_ON) {
+ while (amount_needed++ < initial_amount_needed) {
+ reiserfs_free_block(hint->th, hint->inode,
+ *(--new_blocknrs), 1);
+ }
}
- }
- return ret;
+ return ret;
}
/* These 2 functions are here to provide blocks reservation to the rest of kernel */
/* Reserve @blocks amount of blocks in fs pointed by @sb. Caller must make sure
there are actually this much blocks on the FS available */
-void reiserfs_claim_blocks_to_be_allocated(
- struct super_block *sb, /* super block of
- filesystem where
- blocks should be
- reserved */
- int blocks /* How much to reserve */
- )
+void reiserfs_claim_blocks_to_be_allocated(struct super_block *sb, /* super block of
+ filesystem where
+ blocks should be
+ reserved */
+ int blocks /* How much to reserve */
+ )
{
- /* Fast case, if reservation is zero - exit immediately. */
- if ( !blocks )
- return;
+ /* Fast case, if reservation is zero - exit immediately. */
+ if (!blocks)
+ return;
- spin_lock(&REISERFS_SB(sb)->bitmap_lock);
- REISERFS_SB(sb)->reserved_blocks += blocks;
- spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
+ spin_lock(&REISERFS_SB(sb)->bitmap_lock);
+ REISERFS_SB(sb)->reserved_blocks += blocks;
+ spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
}
/* Unreserve @blocks amount of blocks in fs pointed by @sb */
-void reiserfs_release_claimed_blocks(
- struct super_block *sb, /* super block of
- filesystem where
- blocks should be
- reserved */
- int blocks /* How much to unreserve */
- )
+void reiserfs_release_claimed_blocks(struct super_block *sb, /* super block of
+ filesystem where
+ blocks should be
+ reserved */
+ int blocks /* How much to unreserve */
+ )
{
- /* Fast case, if unreservation is zero - exit immediately. */
- if ( !blocks )
- return;
+ /* Fast case, if unreservation is zero - exit immediately. */
+ if (!blocks)
+ return;
- spin_lock(&REISERFS_SB(sb)->bitmap_lock);
- REISERFS_SB(sb)->reserved_blocks -= blocks;
- spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
- RFALSE( REISERFS_SB(sb)->reserved_blocks < 0, "amount of blocks reserved became zero?");
+ spin_lock(&REISERFS_SB(sb)->bitmap_lock);
+ REISERFS_SB(sb)->reserved_blocks -= blocks;
+ spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
+ RFALSE(REISERFS_SB(sb)->reserved_blocks < 0,
+ "amount of blocks reserved became zero?");
}
/* This function estimates how much pages we will be able to write to FS
used for reiserfs_file_write() purposes for now. */
-int reiserfs_can_fit_pages ( struct super_block *sb /* superblock of filesystem
- to estimate space */ )
+int reiserfs_can_fit_pages(struct super_block *sb /* superblock of filesystem
+ to estimate space */ )
{
int space;
spin_lock(&REISERFS_SB(sb)->bitmap_lock);
- space = (SB_FREE_BLOCKS(sb) - REISERFS_SB(sb)->reserved_blocks) >> ( PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
+ space =
+ (SB_FREE_BLOCKS(sb) -
+ REISERFS_SB(sb)->reserved_blocks) >> (PAGE_CACHE_SHIFT -
+ sb->s_blocksize_bits);
spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
- return space>0?space:0;
+ return space > 0 ? space : 0;
}
diff --git a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
index fbde4b01a325..9dd71e807034 100644
--- a/fs/reiserfs/dir.c
+++ b/fs/reiserfs/dir.c
@@ -12,264 +12,286 @@
#include <linux/buffer_head.h>
#include <asm/uaccess.h>
-extern struct reiserfs_key MIN_KEY;
+extern struct reiserfs_key MIN_KEY;
-static int reiserfs_readdir (struct file *, void *, filldir_t);
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) ;
+static int reiserfs_readdir(struct file *, void *, filldir_t);
+static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
+ int datasync);
struct file_operations reiserfs_dir_operations = {
- .read = generic_read_dir,
- .readdir = reiserfs_readdir,
- .fsync = reiserfs_dir_fsync,
- .ioctl = reiserfs_ioctl,
+ .read = generic_read_dir,
+ .readdir = reiserfs_readdir,
+ .fsync = reiserfs_dir_fsync,
+ .ioctl = reiserfs_ioctl,
};
-static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry, int datasync) {
- struct inode *inode = dentry->d_inode;
- int err;
- reiserfs_write_lock(inode->i_sb);
- err = reiserfs_commit_for_inode(inode) ;
- reiserfs_write_unlock(inode->i_sb) ;
- if (err < 0)
- return err;
- return 0;
+static int reiserfs_dir_fsync(struct file *filp, struct dentry *dentry,
+ int datasync)
+{
+ struct inode *inode = dentry->d_inode;
+ int err;
+ reiserfs_write_lock(inode->i_sb);
+ err = reiserfs_commit_for_inode(inode);
+ reiserfs_write_unlock(inode->i_sb);
+ if (err < 0)
+ return err;
+ return 0;
}
-
#define store_ih(where,what) copy_item_head (where, what)
//
-static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldir)
+static int reiserfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
- struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
- INITIALIZE_PATH (path_to_entry);
- struct buffer_head * bh;
- int item_num, entry_num;
- const struct reiserfs_key * rkey;
- struct item_head * ih, tmp_ih;
- int search_res;
- char * local_buf;
- loff_t next_pos;
- char small_buf[32] ; /* avoid kmalloc if we can */
- struct reiserfs_dir_entry de;
- int ret = 0;
-
- reiserfs_write_lock(inode->i_sb);
-
- reiserfs_check_lock_depth(inode->i_sb, "readdir") ;
-
- /* form key for search the next directory entry using f_pos field of
- file structure */
- make_cpu_key (&pos_key, inode, (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET,
- TYPE_DIRENTRY, 3);
- next_pos = cpu_key_k_offset (&pos_key);
-
- /* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos);*/
-
- path_to_entry.reada = PATH_READA;
- while (1) {
- research:
- /* search the directory item, containing entry with specified key */
- search_res = search_by_entry_key (inode->i_sb, &pos_key, &path_to_entry, &de);
- if (search_res == IO_ERROR) {
- // FIXME: we could just skip part of directory which could
- // not be read
- ret = -EIO;
- goto out;
- }
- entry_num = de.de_entry_num;
- bh = de.de_bh;
- item_num = de.de_item_num;
- ih = de.de_ih;
- store_ih (&tmp_ih, ih);
-
- /* we must have found item, that is item of this directory, */
- RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
- "vs-9000: found item %h does not match to dir we readdir %K",
- ih, &pos_key);
- RFALSE( item_num > B_NR_ITEMS (bh) - 1,
- "vs-9005 item_num == %d, item amount == %d",
- item_num, B_NR_ITEMS (bh));
-
- /* and entry must be not more than number of entries in the item */
- RFALSE( I_ENTRY_COUNT (ih) < entry_num,
- "vs-9010: entry number is too big %d (%d)",
- entry_num, I_ENTRY_COUNT (ih));
-
- if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT (ih)) {
- /* go through all entries in the directory item beginning from the entry, that has been found */
- struct reiserfs_de_head * deh = B_I_DEH (bh, ih) + entry_num;
-
- for (; entry_num < I_ENTRY_COUNT (ih); entry_num ++, deh ++) {
- int d_reclen;
- char * d_name;
- off_t d_off;
- ino_t d_ino;
-
- if (!de_visible (deh))
- /* it is hidden entry */
- continue;
- d_reclen = entry_length (bh, ih, entry_num);
- d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh);
- if (!d_name[d_reclen - 1])
- d_reclen = strlen (d_name);
-
- if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
- /* too big to send back to VFS */
- continue ;
- }
-
- /* Ignore the .reiserfs_priv entry */
- if (reiserfs_xattrs (inode->i_sb) &&
- !old_format_only(inode->i_sb) &&
- filp->f_dentry == inode->i_sb->s_root &&
- REISERFS_SB(inode->i_sb)->priv_root &&
- REISERFS_SB(inode->i_sb)->priv_root->d_inode &&
- deh_objectid(deh) == le32_to_cpu (INODE_PKEY(REISERFS_SB(inode->i_sb)->priv_root->d_inode)->k_objectid)) {
- continue;
- }
-
- d_off = deh_offset (deh);
- filp->f_pos = d_off ;
- d_ino = deh_objectid (deh);
- if (d_reclen <= 32) {
- local_buf = small_buf ;
- } else {
- local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
- if (!local_buf) {
- pathrelse (&path_to_entry);
- ret = -ENOMEM ;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
+ INITIALIZE_PATH(path_to_entry);
+ struct buffer_head *bh;
+ int item_num, entry_num;
+ const struct reiserfs_key *rkey;
+ struct item_head *ih, tmp_ih;
+ int search_res;
+ char *local_buf;
+ loff_t next_pos;
+ char small_buf[32]; /* avoid kmalloc if we can */
+ struct reiserfs_dir_entry de;
+ int ret = 0;
+
+ reiserfs_write_lock(inode->i_sb);
+
+ reiserfs_check_lock_depth(inode->i_sb, "readdir");
+
+ /* form key for search the next directory entry using f_pos field of
+ file structure */
+ make_cpu_key(&pos_key, inode,
+ (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY,
+ 3);
+ next_pos = cpu_key_k_offset(&pos_key);
+
+ /* reiserfs_warning (inode->i_sb, "reiserfs_readdir 1: f_pos = %Ld", filp->f_pos); */
+
+ path_to_entry.reada = PATH_READA;
+ while (1) {
+ research:
+ /* search the directory item, containing entry with specified key */
+ search_res =
+ search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
+ &de);
+ if (search_res == IO_ERROR) {
+ // FIXME: we could just skip part of directory which could
+ // not be read
+ ret = -EIO;
goto out;
- }
- if (item_moved (&tmp_ih, &path_to_entry)) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
- goto research;
- }
- }
- // Note, that we copy name to user space via temporary
- // buffer (local_buf) because filldir will block if
- // user space buffer is swapped out. At that time
- // entry can move to somewhere else
- memcpy (local_buf, d_name, d_reclen);
- if (filldir (dirent, local_buf, d_reclen, d_off, d_ino,
- DT_UNKNOWN) < 0) {
- if (local_buf != small_buf) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
- }
- goto end;
}
- if (local_buf != small_buf) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
+ entry_num = de.de_entry_num;
+ bh = de.de_bh;
+ item_num = de.de_item_num;
+ ih = de.de_ih;
+ store_ih(&tmp_ih, ih);
+
+ /* we must have found item, that is item of this directory, */
+ RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
+ "vs-9000: found item %h does not match to dir we readdir %K",
+ ih, &pos_key);
+ RFALSE(item_num > B_NR_ITEMS(bh) - 1,
+ "vs-9005 item_num == %d, item amount == %d",
+ item_num, B_NR_ITEMS(bh));
+
+ /* and entry must be not more than number of entries in the item */
+ RFALSE(I_ENTRY_COUNT(ih) < entry_num,
+ "vs-9010: entry number is too big %d (%d)",
+ entry_num, I_ENTRY_COUNT(ih));
+
+ if (search_res == POSITION_FOUND
+ || entry_num < I_ENTRY_COUNT(ih)) {
+ /* go through all entries in the directory item beginning from the entry, that has been found */
+ struct reiserfs_de_head *deh =
+ B_I_DEH(bh, ih) + entry_num;
+
+ for (; entry_num < I_ENTRY_COUNT(ih);
+ entry_num++, deh++) {
+ int d_reclen;
+ char *d_name;
+ off_t d_off;
+ ino_t d_ino;
+
+ if (!de_visible(deh))
+ /* it is hidden entry */
+ continue;
+ d_reclen = entry_length(bh, ih, entry_num);
+ d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
+ if (!d_name[d_reclen - 1])
+ d_reclen = strlen(d_name);
+
+ if (d_reclen >
+ REISERFS_MAX_NAME(inode->i_sb->
+ s_blocksize)) {
+ /* too big to send back to VFS */
+ continue;
+ }
+
+ /* Ignore the .reiserfs_priv entry */
+ if (reiserfs_xattrs(inode->i_sb) &&
+ !old_format_only(inode->i_sb) &&
+ filp->f_dentry == inode->i_sb->s_root &&
+ REISERFS_SB(inode->i_sb)->priv_root &&
+ REISERFS_SB(inode->i_sb)->priv_root->d_inode
+ && deh_objectid(deh) ==
+ le32_to_cpu(INODE_PKEY
+ (REISERFS_SB(inode->i_sb)->
+ priv_root->d_inode)->
+ k_objectid)) {
+ continue;
+ }
+
+ d_off = deh_offset(deh);
+ filp->f_pos = d_off;
+ d_ino = deh_objectid(deh);
+ if (d_reclen <= 32) {
+ local_buf = small_buf;
+ } else {
+ local_buf =
+ reiserfs_kmalloc(d_reclen, GFP_NOFS,
+ inode->i_sb);
+ if (!local_buf) {
+ pathrelse(&path_to_entry);
+ ret = -ENOMEM;
+ goto out;
+ }
+ if (item_moved(&tmp_ih, &path_to_entry)) {
+ reiserfs_kfree(local_buf,
+ d_reclen,
+ inode->i_sb);
+ goto research;
+ }
+ }
+ // Note, that we copy name to user space via temporary
+ // buffer (local_buf) because filldir will block if
+ // user space buffer is swapped out. At that time
+ // entry can move to somewhere else
+ memcpy(local_buf, d_name, d_reclen);
+ if (filldir
+ (dirent, local_buf, d_reclen, d_off, d_ino,
+ DT_UNKNOWN) < 0) {
+ if (local_buf != small_buf) {
+ reiserfs_kfree(local_buf,
+ d_reclen,
+ inode->i_sb);
+ }
+ goto end;
+ }
+ if (local_buf != small_buf) {
+ reiserfs_kfree(local_buf, d_reclen,
+ inode->i_sb);
+ }
+ // next entry should be looked for with such offset
+ next_pos = deh_offset(deh) + 1;
+
+ if (item_moved(&tmp_ih, &path_to_entry)) {
+ goto research;
+ }
+ } /* for */
}
- // next entry should be looked for with such offset
- next_pos = deh_offset (deh) + 1;
+ if (item_num != B_NR_ITEMS(bh) - 1)
+ // end of directory has been reached
+ goto end;
+
+ /* item we went through is last item of node. Using right
+ delimiting key check is it directory end */
+ rkey = get_rkey(&path_to_entry, inode->i_sb);
+ if (!comp_le_keys(rkey, &MIN_KEY)) {
+ /* set pos_key to key, that is the smallest and greater
+ that key of the last entry in the item */
+ set_cpu_key_k_offset(&pos_key, next_pos);
+ continue;
+ }
- if (item_moved (&tmp_ih, &path_to_entry)) {
- goto research;
+ if (COMP_SHORT_KEYS(rkey, &pos_key)) {
+ // end of directory has been reached
+ goto end;
}
- } /* for */
- }
-
- if (item_num != B_NR_ITEMS (bh) - 1)
- // end of directory has been reached
- goto end;
-
- /* item we went through is last item of node. Using right
- delimiting key check is it directory end */
- rkey = get_rkey (&path_to_entry, inode->i_sb);
- if (! comp_le_keys (rkey, &MIN_KEY)) {
- /* set pos_key to key, that is the smallest and greater
- that key of the last entry in the item */
- set_cpu_key_k_offset (&pos_key, next_pos);
- continue;
- }
-
- if ( COMP_SHORT_KEYS (rkey, &pos_key)) {
- // end of directory has been reached
- goto end;
- }
-
- /* directory continues in the right neighboring block */
- set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey));
-
- } /* while */
-
-
- end:
- filp->f_pos = next_pos;
- pathrelse (&path_to_entry);
- reiserfs_check_path(&path_to_entry) ;
- out:
- reiserfs_write_unlock(inode->i_sb);
- return ret;
+
+ /* directory continues in the right neighboring block */
+ set_cpu_key_k_offset(&pos_key,
+ le_key_k_offset(KEY_FORMAT_3_5, rkey));
+
+ } /* while */
+
+ end:
+ filp->f_pos = next_pos;
+ pathrelse(&path_to_entry);
+ reiserfs_check_path(&path_to_entry);
+ out:
+ reiserfs_write_unlock(inode->i_sb);
+ return ret;
}
/* compose directory item containing "." and ".." entries (entries are
not aligned to 4 byte boundary) */
/* the last four params are LE */
-void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid,
- __le32 par_dirid, __le32 par_objid)
+void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid)
{
- struct reiserfs_de_head * deh;
-
- memset (body, 0, EMPTY_DIR_SIZE_V1);
- deh = (struct reiserfs_de_head *)body;
-
- /* direntry header of "." */
- put_deh_offset( &(deh[0]), DOT_OFFSET );
- /* these two are from make_le_item_head, and are are LE */
- deh[0].deh_dir_id = dirid;
- deh[0].deh_objectid = objid;
- deh[0].deh_state = 0; /* Endian safe if 0 */
- put_deh_location( &(deh[0]), EMPTY_DIR_SIZE_V1 - strlen( "." ));
- mark_de_visible(&(deh[0]));
-
- /* direntry header of ".." */
- put_deh_offset( &(deh[1]), DOT_DOT_OFFSET);
- /* key of ".." for the root directory */
- /* these two are from the inode, and are are LE */
- deh[1].deh_dir_id = par_dirid;
- deh[1].deh_objectid = par_objid;
- deh[1].deh_state = 0; /* Endian safe if 0 */
- put_deh_location( &(deh[1]), deh_location( &(deh[0]) ) - strlen( ".." ) );
- mark_de_visible(&(deh[1]));
-
- /* copy ".." and "." */
- memcpy (body + deh_location( &(deh[0]) ), ".", 1);
- memcpy (body + deh_location( &(deh[1]) ), "..", 2);
+ struct reiserfs_de_head *deh;
+
+ memset(body, 0, EMPTY_DIR_SIZE_V1);
+ deh = (struct reiserfs_de_head *)body;
+
+ /* direntry header of "." */
+ put_deh_offset(&(deh[0]), DOT_OFFSET);
+ /* these two are from make_le_item_head, and are are LE */
+ deh[0].deh_dir_id = dirid;
+ deh[0].deh_objectid = objid;
+ deh[0].deh_state = 0; /* Endian safe if 0 */
+ put_deh_location(&(deh[0]), EMPTY_DIR_SIZE_V1 - strlen("."));
+ mark_de_visible(&(deh[0]));
+
+ /* direntry header of ".." */
+ put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
+ /* key of ".." for the root directory */
+ /* these two are from the inode, and are are LE */
+ deh[1].deh_dir_id = par_dirid;
+ deh[1].deh_objectid = par_objid;
+ deh[1].deh_state = 0; /* Endian safe if 0 */
+ put_deh_location(&(deh[1]), deh_location(&(deh[0])) - strlen(".."));
+ mark_de_visible(&(deh[1]));
+
+ /* copy ".." and "." */
+ memcpy(body + deh_location(&(deh[0])), ".", 1);
+ memcpy(body + deh_location(&(deh[1])), "..", 2);
}
/* compose directory item containing "." and ".." entries */
-void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
- __le32 par_dirid, __le32 par_objid)
+void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid)
{
- struct reiserfs_de_head * deh;
-
- memset (body, 0, EMPTY_DIR_SIZE);
- deh = (struct reiserfs_de_head *)body;
-
- /* direntry header of "." */
- put_deh_offset( &(deh[0]), DOT_OFFSET );
- /* these two are from make_le_item_head, and are are LE */
- deh[0].deh_dir_id = dirid;
- deh[0].deh_objectid = objid;
- deh[0].deh_state = 0; /* Endian safe if 0 */
- put_deh_location( &(deh[0]), EMPTY_DIR_SIZE - ROUND_UP( strlen( "." ) ) );
- mark_de_visible(&(deh[0]));
-
- /* direntry header of ".." */
- put_deh_offset( &(deh[1]), DOT_DOT_OFFSET );
- /* key of ".." for the root directory */
- /* these two are from the inode, and are are LE */
- deh[1].deh_dir_id = par_dirid;
- deh[1].deh_objectid = par_objid;
- deh[1].deh_state = 0; /* Endian safe if 0 */
- put_deh_location( &(deh[1]), deh_location( &(deh[0])) - ROUND_UP( strlen( ".." ) ) );
- mark_de_visible(&(deh[1]));
-
- /* copy ".." and "." */
- memcpy (body + deh_location( &(deh[0]) ), ".", 1);
- memcpy (body + deh_location( &(deh[1]) ), "..", 2);
+ struct reiserfs_de_head *deh;
+
+ memset(body, 0, EMPTY_DIR_SIZE);
+ deh = (struct reiserfs_de_head *)body;
+
+ /* direntry header of "." */
+ put_deh_offset(&(deh[0]), DOT_OFFSET);
+ /* these two are from make_le_item_head, and are are LE */
+ deh[0].deh_dir_id = dirid;
+ deh[0].deh_objectid = objid;
+ deh[0].deh_state = 0; /* Endian safe if 0 */
+ put_deh_location(&(deh[0]), EMPTY_DIR_SIZE - ROUND_UP(strlen(".")));
+ mark_de_visible(&(deh[0]));
+
+ /* direntry header of ".." */
+ put_deh_offset(&(deh[1]), DOT_DOT_OFFSET);
+ /* key of ".." for the root directory */
+ /* these two are from the inode, and are are LE */
+ deh[1].deh_dir_id = par_dirid;
+ deh[1].deh_objectid = par_objid;
+ deh[1].deh_state = 0; /* Endian safe if 0 */
+ put_deh_location(&(deh[1]),
+ deh_location(&(deh[0])) - ROUND_UP(strlen("..")));
+ mark_de_visible(&(deh[1]));
+
+ /* copy ".." and "." */
+ memcpy(body + deh_location(&(deh[0])), ".", 1);
+ memcpy(body + deh_location(&(deh[1])), "..", 2);
}
diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
index 2118db2896c7..b2264ba3cc56 100644
--- a/fs/reiserfs/do_balan.c
+++ b/fs/reiserfs/do_balan.c
@@ -8,7 +8,6 @@
/* balance the tree according to the analysis made before, */
/* and using buffers obtained after all above. */
-
/**
** balance_leaf_when_delete
** balance_leaf
@@ -24,23 +23,22 @@
#ifdef CONFIG_REISERFS_CHECK
-struct tree_balance * cur_tb = NULL; /* detects whether more than one
- copy of tb exists as a means
- of checking whether schedule
- is interrupting do_balance */
+struct tree_balance *cur_tb = NULL; /* detects whether more than one
+ copy of tb exists as a means
+ of checking whether schedule
+ is interrupting do_balance */
#endif
-inline void do_balance_mark_leaf_dirty (struct tree_balance * tb,
- struct buffer_head * bh, int flag)
+inline void do_balance_mark_leaf_dirty(struct tree_balance *tb,
+ struct buffer_head *bh, int flag)
{
- journal_mark_dirty(tb->transaction_handle,
- tb->transaction_handle->t_super, bh) ;
+ journal_mark_dirty(tb->transaction_handle,
+ tb->transaction_handle->t_super, bh);
}
#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
-
/* summary:
if deleting something ( tb->insert_size[0] < 0 )
return(balance_leaf_when_delete()); (flag d handled here)
@@ -64,8 +62,6 @@ be performed by do_balance.
-Hans */
-
-
/* Balance leaf node in case of delete or cut: insert_size[0] < 0
*
* lnum, rnum can have values >= -1
@@ -73,1384 +69,1933 @@ be performed by do_balance.
* 0 means that nothing should be done with the neighbor
* >0 means to shift entirely or partly the specified number of items to the neighbor
*/
-static int balance_leaf_when_delete (struct tree_balance * tb, int flag)
+static int balance_leaf_when_delete(struct tree_balance *tb, int flag)
{
- struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
- int item_pos = PATH_LAST_POSITION (tb->tb_path);
- int pos_in_item = tb->tb_path->pos_in_item;
- struct buffer_info bi;
- int n;
- struct item_head * ih;
+ struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+ int item_pos = PATH_LAST_POSITION(tb->tb_path);
+ int pos_in_item = tb->tb_path->pos_in_item;
+ struct buffer_info bi;
+ int n;
+ struct item_head *ih;
- RFALSE( tb->FR[0] && B_LEVEL (tb->FR[0]) != DISK_LEAF_NODE_LEVEL + 1,
- "vs- 12000: level: wrong FR %z", tb->FR[0]);
- RFALSE( tb->blknum[0] > 1,
- "PAP-12005: tb->blknum == %d, can not be > 1", tb->blknum[0]);
- RFALSE( ! tb->blknum[0] && ! PATH_H_PPARENT(tb->tb_path, 0),
- "PAP-12010: tree can not be empty");
+ RFALSE(tb->FR[0] && B_LEVEL(tb->FR[0]) != DISK_LEAF_NODE_LEVEL + 1,
+ "vs- 12000: level: wrong FR %z", tb->FR[0]);
+ RFALSE(tb->blknum[0] > 1,
+ "PAP-12005: tb->blknum == %d, can not be > 1", tb->blknum[0]);
+ RFALSE(!tb->blknum[0] && !PATH_H_PPARENT(tb->tb_path, 0),
+ "PAP-12010: tree can not be empty");
- ih = B_N_PITEM_HEAD (tbS0, item_pos);
+ ih = B_N_PITEM_HEAD(tbS0, item_pos);
- /* Delete or truncate the item */
+ /* Delete or truncate the item */
- switch (flag) {
- case M_DELETE: /* delete item in S[0] */
+ switch (flag) {
+ case M_DELETE: /* delete item in S[0] */
+
+ RFALSE(ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
+ "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
+ -tb->insert_size[0], ih);
+
+ bi.tb = tb;
+ bi.bi_bh = tbS0;
+ bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
+ leaf_delete_items(&bi, 0, item_pos, 1, -1);
+
+ if (!item_pos && tb->CFL[0]) {
+ if (B_NR_ITEMS(tbS0)) {
+ replace_key(tb, tb->CFL[0], tb->lkey[0], tbS0,
+ 0);
+ } else {
+ if (!PATH_H_POSITION(tb->tb_path, 1))
+ replace_key(tb, tb->CFL[0], tb->lkey[0],
+ PATH_H_PPARENT(tb->tb_path,
+ 0), 0);
+ }
+ }
- RFALSE( ih_item_len(ih) + IH_SIZE != -tb->insert_size[0],
- "vs-12013: mode Delete, insert size %d, ih to be deleted %h",
- -tb->insert_size [0], ih);
+ RFALSE(!item_pos && !tb->CFL[0],
+ "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0],
+ tb->L[0]);
- bi.tb = tb;
- bi.bi_bh = tbS0;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
- leaf_delete_items (&bi, 0, item_pos, 1, -1);
-
- if ( ! item_pos && tb->CFL[0] ) {
- if ( B_NR_ITEMS(tbS0) ) {
- replace_key(tb, tb->CFL[0],tb->lkey[0],tbS0,0);
- }
- else {
- if ( ! PATH_H_POSITION (tb->tb_path, 1) )
- replace_key(tb, tb->CFL[0],tb->lkey[0],PATH_H_PPARENT(tb->tb_path, 0),0);
- }
- }
-
- RFALSE( ! item_pos && !tb->CFL[0],
- "PAP-12020: tb->CFL[0]==%p, tb->L[0]==%p", tb->CFL[0], tb->L[0]);
-
- break;
-
- case M_CUT: { /* cut item in S[0] */
- bi.tb = tb;
- bi.bi_bh = tbS0;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
- if (is_direntry_le_ih (ih)) {
-
- /* UFS unlink semantics are such that you can only delete one directory entry at a time. */
- /* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */
- tb->insert_size[0] = -1;
- leaf_cut_from_buffer (&bi, item_pos, pos_in_item, -tb->insert_size[0]);
-
- RFALSE( ! item_pos && ! pos_in_item && ! tb->CFL[0],
- "PAP-12030: can not change delimiting key. CFL[0]=%p",
- tb->CFL[0]);
-
- if ( ! item_pos && ! pos_in_item && tb->CFL[0] ) {
- replace_key(tb, tb->CFL[0],tb->lkey[0],tbS0,0);
- }
- } else {
- leaf_cut_from_buffer (&bi, item_pos, pos_in_item, -tb->insert_size[0]);
-
- RFALSE( ! ih_item_len(ih),
- "PAP-12035: cut must leave non-zero dynamic length of item");
- }
- break;
- }
-
- default:
- print_cur_tb ("12040");
- reiserfs_panic (tb->tb_sb, "PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)",
- (flag == M_PASTE) ? "PASTE" : ((flag == M_INSERT) ? "INSERT" : "UNKNOWN"), flag);
- }
-
- /* the rule is that no shifting occurs unless by shifting a node can be freed */
- n = B_NR_ITEMS(tbS0);
- if ( tb->lnum[0] ) /* L[0] takes part in balancing */
- {
- if ( tb->lnum[0] == -1 ) /* L[0] must be joined with S[0] */
- {
- if ( tb->rnum[0] == -1 ) /* R[0] must be also joined with S[0] */
- {
- if ( tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0) )
- {
- /* all contents of all the 3 buffers will be in L[0] */
- if ( PATH_H_POSITION (tb->tb_path, 1) == 0 && 1 < B_NR_ITEMS(tb->FR[0]) )
- replace_key(tb, tb->CFL[0],tb->lkey[0],tb->FR[0],1);
-
- leaf_move_items (LEAF_FROM_S_TO_L, tb, n, -1, NULL);
- leaf_move_items (LEAF_FROM_R_TO_L, tb, B_NR_ITEMS(tb->R[0]), -1, NULL);
-
- reiserfs_invalidate_buffer (tb, tbS0);
- reiserfs_invalidate_buffer (tb, tb->R[0]);
-
- return 0;
+ break;
+
+ case M_CUT:{ /* cut item in S[0] */
+ bi.tb = tb;
+ bi.bi_bh = tbS0;
+ bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
+ if (is_direntry_le_ih(ih)) {
+
+ /* UFS unlink semantics are such that you can only delete one directory entry at a time. */
+ /* when we cut a directory tb->insert_size[0] means number of entries to be cut (always 1) */
+ tb->insert_size[0] = -1;
+ leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
+ -tb->insert_size[0]);
+
+ RFALSE(!item_pos && !pos_in_item && !tb->CFL[0],
+ "PAP-12030: can not change delimiting key. CFL[0]=%p",
+ tb->CFL[0]);
+
+ if (!item_pos && !pos_in_item && tb->CFL[0]) {
+ replace_key(tb, tb->CFL[0], tb->lkey[0],
+ tbS0, 0);
+ }
+ } else {
+ leaf_cut_from_buffer(&bi, item_pos, pos_in_item,
+ -tb->insert_size[0]);
+
+ RFALSE(!ih_item_len(ih),
+ "PAP-12035: cut must leave non-zero dynamic length of item");
+ }
+ break;
}
- /* all contents of all the 3 buffers will be in R[0] */
- leaf_move_items (LEAF_FROM_S_TO_R, tb, n, -1, NULL);
- leaf_move_items (LEAF_FROM_L_TO_R, tb, B_NR_ITEMS(tb->L[0]), -1, NULL);
- /* right_delimiting_key is correct in R[0] */
- replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+ default:
+ print_cur_tb("12040");
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12040: balance_leaf_when_delete: unexpectable mode: %s(%d)",
+ (flag ==
+ M_PASTE) ? "PASTE" : ((flag ==
+ M_INSERT) ? "INSERT" :
+ "UNKNOWN"), flag);
+ }
- reiserfs_invalidate_buffer (tb, tbS0);
- reiserfs_invalidate_buffer (tb, tb->L[0]);
+ /* the rule is that no shifting occurs unless by shifting a node can be freed */
+ n = B_NR_ITEMS(tbS0);
+ if (tb->lnum[0]) { /* L[0] takes part in balancing */
+ if (tb->lnum[0] == -1) { /* L[0] must be joined with S[0] */
+ if (tb->rnum[0] == -1) { /* R[0] must be also joined with S[0] */
+ if (tb->FR[0] == PATH_H_PPARENT(tb->tb_path, 0)) {
+ /* all contents of all the 3 buffers will be in L[0] */
+ if (PATH_H_POSITION(tb->tb_path, 1) == 0
+ && 1 < B_NR_ITEMS(tb->FR[0]))
+ replace_key(tb, tb->CFL[0],
+ tb->lkey[0],
+ tb->FR[0], 1);
+
+ leaf_move_items(LEAF_FROM_S_TO_L, tb, n,
+ -1, NULL);
+ leaf_move_items(LEAF_FROM_R_TO_L, tb,
+ B_NR_ITEMS(tb->R[0]),
+ -1, NULL);
+
+ reiserfs_invalidate_buffer(tb, tbS0);
+ reiserfs_invalidate_buffer(tb,
+ tb->R[0]);
+
+ return 0;
+ }
+ /* all contents of all the 3 buffers will be in R[0] */
+ leaf_move_items(LEAF_FROM_S_TO_R, tb, n, -1,
+ NULL);
+ leaf_move_items(LEAF_FROM_L_TO_R, tb,
+ B_NR_ITEMS(tb->L[0]), -1, NULL);
+
+ /* right_delimiting_key is correct in R[0] */
+ replace_key(tb, tb->CFR[0], tb->rkey[0],
+ tb->R[0], 0);
- return -1;
- }
+ reiserfs_invalidate_buffer(tb, tbS0);
+ reiserfs_invalidate_buffer(tb, tb->L[0]);
- RFALSE( tb->rnum[0] != 0,
- "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
- /* all contents of L[0] and S[0] will be in L[0] */
- leaf_shift_left(tb, n, -1);
+ return -1;
+ }
- reiserfs_invalidate_buffer (tb, tbS0);
+ RFALSE(tb->rnum[0] != 0,
+ "PAP-12045: rnum must be 0 (%d)", tb->rnum[0]);
+ /* all contents of L[0] and S[0] will be in L[0] */
+ leaf_shift_left(tb, n, -1);
- return 0;
+ reiserfs_invalidate_buffer(tb, tbS0);
+
+ return 0;
+ }
+ /* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */
+
+ RFALSE((tb->lnum[0] + tb->rnum[0] < n) ||
+ (tb->lnum[0] + tb->rnum[0] > n + 1),
+ "PAP-12050: rnum(%d) and lnum(%d) and item number(%d) in S[0] are not consistent",
+ tb->rnum[0], tb->lnum[0], n);
+ RFALSE((tb->lnum[0] + tb->rnum[0] == n) &&
+ (tb->lbytes != -1 || tb->rbytes != -1),
+ "PAP-12055: bad rbytes (%d)/lbytes (%d) parameters when items are not split",
+ tb->rbytes, tb->lbytes);
+ RFALSE((tb->lnum[0] + tb->rnum[0] == n + 1) &&
+ (tb->lbytes < 1 || tb->rbytes != -1),
+ "PAP-12060: bad rbytes (%d)/lbytes (%d) parameters when items are split",
+ tb->rbytes, tb->lbytes);
+
+ leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
+ leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
+
+ reiserfs_invalidate_buffer(tb, tbS0);
+
+ return 0;
}
- /* a part of contents of S[0] will be in L[0] and the rest part of S[0] will be in R[0] */
-
- RFALSE( ( tb->lnum[0] + tb->rnum[0] < n ) ||
- ( tb->lnum[0] + tb->rnum[0] > n+1 ),
- "PAP-12050: rnum(%d) and lnum(%d) and item number(%d) in S[0] are not consistent",
- tb->rnum[0], tb->lnum[0], n);
- RFALSE( ( tb->lnum[0] + tb->rnum[0] == n ) &&
- (tb->lbytes != -1 || tb->rbytes != -1),
- "PAP-12055: bad rbytes (%d)/lbytes (%d) parameters when items are not split",
- tb->rbytes, tb->lbytes);
- RFALSE( ( tb->lnum[0] + tb->rnum[0] == n + 1 ) &&
- (tb->lbytes < 1 || tb->rbytes != -1),
- "PAP-12060: bad rbytes (%d)/lbytes (%d) parameters when items are split",
- tb->rbytes, tb->lbytes);
-
- leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
- leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
-
- reiserfs_invalidate_buffer (tb, tbS0);
- return 0;
- }
+ if (tb->rnum[0] == -1) {
+ /* all contents of R[0] and S[0] will be in R[0] */
+ leaf_shift_right(tb, n, -1);
+ reiserfs_invalidate_buffer(tb, tbS0);
+ return 0;
+ }
- if ( tb->rnum[0] == -1 ) {
- /* all contents of R[0] and S[0] will be in R[0] */
- leaf_shift_right(tb, n, -1);
- reiserfs_invalidate_buffer (tb, tbS0);
+ RFALSE(tb->rnum[0],
+ "PAP-12065: bad rnum parameter must be 0 (%d)", tb->rnum[0]);
return 0;
- }
-
- RFALSE( tb->rnum[0],
- "PAP-12065: bad rnum parameter must be 0 (%d)", tb->rnum[0]);
- return 0;
}
-
-static int balance_leaf (struct tree_balance * tb,
- struct item_head * ih, /* item header of inserted item (this is on little endian) */
- const char * body, /* body of inserted item or bytes to paste */
- int flag, /* i - insert, d - delete, c - cut, p - paste
- (see comment to do_balance) */
- struct item_head * insert_key, /* in our processing of one level we sometimes determine what
- must be inserted into the next higher level. This insertion
- consists of a key or two keys and their corresponding
- pointers */
- struct buffer_head ** insert_ptr /* inserted node-ptrs for the next level */
+static int balance_leaf(struct tree_balance *tb, struct item_head *ih, /* item header of inserted item (this is on little endian) */
+ const char *body, /* body of inserted item or bytes to paste */
+ int flag, /* i - insert, d - delete, c - cut, p - paste
+ (see comment to do_balance) */
+ struct item_head *insert_key, /* in our processing of one level we sometimes determine what
+ must be inserted into the next higher level. This insertion
+ consists of a key or two keys and their corresponding
+ pointers */
+ struct buffer_head **insert_ptr /* inserted node-ptrs for the next level */
)
{
- struct buffer_head * tbS0 = PATH_PLAST_BUFFER (tb->tb_path);
- int item_pos = PATH_LAST_POSITION (tb->tb_path); /* index into the array of item headers in S[0]
- of the affected item */
- struct buffer_info bi;
- struct buffer_head *S_new[2]; /* new nodes allocated to hold what could not fit into S */
- int snum[2]; /* number of items that will be placed
- into S_new (includes partially shifted
- items) */
- int sbytes[2]; /* if an item is partially shifted into S_new then
- if it is a directory item
- it is the number of entries from the item that are shifted into S_new
- else
- it is the number of bytes from the item that are shifted into S_new
- */
- int n, i;
- int ret_val;
- int pos_in_item;
- int zeros_num;
-
- PROC_INFO_INC( tb -> tb_sb, balance_at[ 0 ] );
-
- /* Make balance in case insert_size[0] < 0 */
- if ( tb->insert_size[0] < 0 )
- return balance_leaf_when_delete (tb, flag);
-
- zeros_num = 0;
- if (flag == M_INSERT && body == 0)
- zeros_num = ih_item_len( ih );
-
- pos_in_item = tb->tb_path->pos_in_item;
- /* for indirect item pos_in_item is measured in unformatted node
- pointers. Recalculate to bytes */
- if (flag != M_INSERT && is_indirect_le_ih (B_N_PITEM_HEAD (tbS0, item_pos)))
- pos_in_item *= UNFM_P_SIZE;
-
- if ( tb->lnum[0] > 0 ) {
- /* Shift lnum[0] items from S[0] to the left neighbor L[0] */
- if ( item_pos < tb->lnum[0] ) {
- /* new item or it part falls to L[0], shift it too */
- n = B_NR_ITEMS(tb->L[0]);
-
- switch (flag) {
- case M_INSERT: /* insert item into L[0] */
-
- if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) {
- /* part of new item falls into L[0] */
- int new_item_len;
- int version;
-
- ret_val = leaf_shift_left (tb, tb->lnum[0]-1, -1);
-
- /* Calculate item length to insert to S[0] */
- new_item_len = ih_item_len(ih) - tb->lbytes;
- /* Calculate and check item length to insert to L[0] */
- put_ih_item_len(ih, ih_item_len(ih) - new_item_len );
-
- RFALSE( ih_item_len(ih) <= 0,
- "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
- ih_item_len(ih));
-
- /* Insert new item into L[0] */
- bi.tb = tb;
- bi.bi_bh = tb->L[0];
- bi.bi_parent = tb->FL[0];
- bi.bi_position = get_left_neighbor_position (tb, 0);
- leaf_insert_into_buf (&bi, n + item_pos - ret_val, ih, body,
- zeros_num > ih_item_len(ih) ? ih_item_len(ih) : zeros_num);
-
- version = ih_version (ih);
-
- /* Calculate key component, item length and body to insert into S[0] */
- set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + (tb->lbytes << (is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0)) );
-
- put_ih_item_len( ih, new_item_len );
- if ( tb->lbytes > zeros_num ) {
- body += (tb->lbytes - zeros_num);
- zeros_num = 0;
- }
- else
- zeros_num -= tb->lbytes;
-
- RFALSE( ih_item_len(ih) <= 0,
- "PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
- ih_item_len(ih));
- } else {
- /* new item in whole falls into L[0] */
- /* Shift lnum[0]-1 items to L[0] */
- ret_val = leaf_shift_left(tb, tb->lnum[0]-1, tb->lbytes);
- /* Insert new item into L[0] */
- bi.tb = tb;
- bi.bi_bh = tb->L[0];
- bi.bi_parent = tb->FL[0];
- bi.bi_position = get_left_neighbor_position (tb, 0);
- leaf_insert_into_buf (&bi, n + item_pos - ret_val, ih, body, zeros_num);
- tb->insert_size[0] = 0;
- zeros_num = 0;
- }
- break;
-
- case M_PASTE: /* append item in L[0] */
-
- if ( item_pos == tb->lnum[0] - 1 && tb->lbytes != -1 ) {
- /* we must shift the part of the appended item */
- if ( is_direntry_le_ih (B_N_PITEM_HEAD (tbS0, item_pos))) {
-
- RFALSE( zeros_num,
- "PAP-12090: invalid parameter in case of a directory");
- /* directory item */
- if ( tb->lbytes > pos_in_item ) {
- /* new directory entry falls into L[0] */
- struct item_head * pasted;
- int l_pos_in_item = pos_in_item;
-
- /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
- ret_val = leaf_shift_left(tb, tb->lnum[0], tb->lbytes - 1);
- if ( ret_val && ! item_pos ) {
- pasted = B_N_PITEM_HEAD(tb->L[0],B_NR_ITEMS(tb->L[0])-1);
- l_pos_in_item += I_ENTRY_COUNT(pasted) - (tb->lbytes-1);
- }
-
- /* Append given directory entry to directory item */
- bi.tb = tb;
- bi.bi_bh = tb->L[0];
- bi.bi_parent = tb->FL[0];
- bi.bi_position = get_left_neighbor_position (tb, 0);
- leaf_paste_in_buffer (&bi, n + item_pos - ret_val, l_pos_in_item,
- tb->insert_size[0], body, zeros_num);
-
- /* previous string prepared space for pasting new entry, following string pastes this entry */
-
- /* when we have merge directory item, pos_in_item has been changed too */
-
- /* paste new directory entry. 1 is entry number */
- leaf_paste_entries (bi.bi_bh, n + item_pos - ret_val, l_pos_in_item, 1,
- (struct reiserfs_de_head *)body,
- body + DEH_SIZE, tb->insert_size[0]
- );
- tb->insert_size[0] = 0;
- } else {
- /* new directory item doesn't fall into L[0] */
- /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
- leaf_shift_left (tb, tb->lnum[0], tb->lbytes);
- }
- /* Calculate new position to append in item body */
- pos_in_item -= tb->lbytes;
- }
- else {
- /* regular object */
- RFALSE( tb->lbytes <= 0,
- "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
- tb->lbytes);
- RFALSE( pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0, item_pos)),
- "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
- ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)), pos_in_item);
-
- if ( tb->lbytes >= pos_in_item ) {
- /* appended item will be in L[0] in whole */
- int l_n;
-
- /* this bytes number must be appended to the last item of L[h] */
- l_n = tb->lbytes - pos_in_item;
-
- /* Calculate new insert_size[0] */
- tb->insert_size[0] -= l_n;
-
- RFALSE( tb->insert_size[0] <= 0,
- "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
- tb->insert_size[0]);
- ret_val = leaf_shift_left(tb,tb->lnum[0],
- ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)));
- /* Append to body of item in L[0] */
- bi.tb = tb;
- bi.bi_bh = tb->L[0];
- bi.bi_parent = tb->FL[0];
- bi.bi_position = get_left_neighbor_position (tb, 0);
- leaf_paste_in_buffer(
- &bi,n + item_pos - ret_val,
- ih_item_len( B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)),
- l_n,body, zeros_num > l_n ? l_n : zeros_num
- );
- /* 0-th item in S0 can be only of DIRECT type when l_n != 0*/
- {
- int version;
- int temp_l = l_n;
-
- RFALSE (ih_item_len (B_N_PITEM_HEAD (tbS0, 0)),
- "PAP-12106: item length must be 0");
- RFALSE (comp_short_le_keys (B_N_PKEY (tbS0, 0),
- B_N_PKEY (tb->L[0],
- n + item_pos - ret_val)),
- "PAP-12107: items must be of the same file");
- if (is_indirect_le_ih(B_N_PITEM_HEAD (tb->L[0],
- n + item_pos - ret_val))) {
- temp_l = l_n << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
+ struct buffer_head *tbS0 = PATH_PLAST_BUFFER(tb->tb_path);
+ int item_pos = PATH_LAST_POSITION(tb->tb_path); /* index into the array of item headers in S[0]
+ of the affected item */
+ struct buffer_info bi;
+ struct buffer_head *S_new[2]; /* new nodes allocated to hold what could not fit into S */
+ int snum[2]; /* number of items that will be placed
+ into S_new (includes partially shifted
+ items) */
+ int sbytes[2]; /* if an item is partially shifted into S_new then
+ if it is a directory item
+ it is the number of entries from the item that are shifted into S_new
+ else
+ it is the number of bytes from the item that are shifted into S_new
+ */
+ int n, i;
+ int ret_val;
+ int pos_in_item;
+ int zeros_num;
+
+ PROC_INFO_INC(tb->tb_sb, balance_at[0]);
+
+ /* Make balance in case insert_size[0] < 0 */
+ if (tb->insert_size[0] < 0)
+ return balance_leaf_when_delete(tb, flag);
+
+ zeros_num = 0;
+ if (flag == M_INSERT && body == 0)
+ zeros_num = ih_item_len(ih);
+
+ pos_in_item = tb->tb_path->pos_in_item;
+ /* for indirect item pos_in_item is measured in unformatted node
+ pointers. Recalculate to bytes */
+ if (flag != M_INSERT
+ && is_indirect_le_ih(B_N_PITEM_HEAD(tbS0, item_pos)))
+ pos_in_item *= UNFM_P_SIZE;
+
+ if (tb->lnum[0] > 0) {
+ /* Shift lnum[0] items from S[0] to the left neighbor L[0] */
+ if (item_pos < tb->lnum[0]) {
+ /* new item or it part falls to L[0], shift it too */
+ n = B_NR_ITEMS(tb->L[0]);
+
+ switch (flag) {
+ case M_INSERT: /* insert item into L[0] */
+
+ if (item_pos == tb->lnum[0] - 1
+ && tb->lbytes != -1) {
+ /* part of new item falls into L[0] */
+ int new_item_len;
+ int version;
+
+ ret_val =
+ leaf_shift_left(tb, tb->lnum[0] - 1,
+ -1);
+
+ /* Calculate item length to insert to S[0] */
+ new_item_len =
+ ih_item_len(ih) - tb->lbytes;
+ /* Calculate and check item length to insert to L[0] */
+ put_ih_item_len(ih,
+ ih_item_len(ih) -
+ new_item_len);
+
+ RFALSE(ih_item_len(ih) <= 0,
+ "PAP-12080: there is nothing to insert into L[0]: ih_item_len=%d",
+ ih_item_len(ih));
+
+ /* Insert new item into L[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[0];
+ bi.bi_parent = tb->FL[0];
+ bi.bi_position =
+ get_left_neighbor_position(tb, 0);
+ leaf_insert_into_buf(&bi,
+ n + item_pos -
+ ret_val, ih, body,
+ zeros_num >
+ ih_item_len(ih) ?
+ ih_item_len(ih) :
+ zeros_num);
+
+ version = ih_version(ih);
+
+ /* Calculate key component, item length and body to insert into S[0] */
+ set_le_ih_k_offset(ih,
+ le_ih_k_offset(ih) +
+ (tb->
+ lbytes <<
+ (is_indirect_le_ih
+ (ih) ? tb->tb_sb->
+ s_blocksize_bits -
+ UNFM_P_SHIFT :
+ 0)));
+
+ put_ih_item_len(ih, new_item_len);
+ if (tb->lbytes > zeros_num) {
+ body +=
+ (tb->lbytes - zeros_num);
+ zeros_num = 0;
+ } else
+ zeros_num -= tb->lbytes;
+
+ RFALSE(ih_item_len(ih) <= 0,
+ "PAP-12085: there is nothing to insert into S[0]: ih_item_len=%d",
+ ih_item_len(ih));
+ } else {
+ /* new item in whole falls into L[0] */
+ /* Shift lnum[0]-1 items to L[0] */
+ ret_val =
+ leaf_shift_left(tb, tb->lnum[0] - 1,
+ tb->lbytes);
+ /* Insert new item into L[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[0];
+ bi.bi_parent = tb->FL[0];
+ bi.bi_position =
+ get_left_neighbor_position(tb, 0);
+ leaf_insert_into_buf(&bi,
+ n + item_pos -
+ ret_val, ih, body,
+ zeros_num);
+ tb->insert_size[0] = 0;
+ zeros_num = 0;
}
- /* update key of first item in S0 */
- version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
- set_le_key_k_offset (version, B_N_PKEY (tbS0, 0),
- le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + temp_l);
- /* update left delimiting key */
- set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
- le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + temp_l);
- }
-
- /* Calculate new body, position in item and insert_size[0] */
- if ( l_n > zeros_num ) {
- body += (l_n - zeros_num);
- zeros_num = 0;
- }
- else
- zeros_num -= l_n;
- pos_in_item = 0;
-
- RFALSE( comp_short_le_keys
- (B_N_PKEY(tbS0,0),
- B_N_PKEY(tb->L[0],B_NR_ITEMS(tb->L[0])-1)) ||
-
- !op_is_left_mergeable
- (B_N_PKEY (tbS0, 0), tbS0->b_size) ||
- !op_is_left_mergeable
- (B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
- tbS0->b_size),
- "PAP-12120: item must be merge-able with left neighboring item");
- }
- else /* only part of the appended item will be in L[0] */
- {
- /* Calculate position in item for append in S[0] */
- pos_in_item -= tb->lbytes;
-
- RFALSE( pos_in_item <= 0,
- "PAP-12125: no place for paste. pos_in_item=%d", pos_in_item);
-
- /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
- leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
- }
- }
- }
- else /* appended item will be in L[0] in whole */
- {
- struct item_head * pasted;
-
- if ( ! item_pos && op_is_left_mergeable (B_N_PKEY (tbS0, 0), tbS0->b_size) )
- { /* if we paste into first item of S[0] and it is left mergable */
- /* then increment pos_in_item by the size of the last item in L[0] */
- pasted = B_N_PITEM_HEAD(tb->L[0],n-1);
- if ( is_direntry_le_ih (pasted) )
- pos_in_item += ih_entry_count(pasted);
- else
- pos_in_item += ih_item_len(pasted);
+ break;
+
+ case M_PASTE: /* append item in L[0] */
+
+ if (item_pos == tb->lnum[0] - 1
+ && tb->lbytes != -1) {
+ /* we must shift the part of the appended item */
+ if (is_direntry_le_ih
+ (B_N_PITEM_HEAD(tbS0, item_pos))) {
+
+ RFALSE(zeros_num,
+ "PAP-12090: invalid parameter in case of a directory");
+ /* directory item */
+ if (tb->lbytes > pos_in_item) {
+ /* new directory entry falls into L[0] */
+ struct item_head
+ *pasted;
+ int l_pos_in_item =
+ pos_in_item;
+
+ /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 entries from given directory item */
+ ret_val =
+ leaf_shift_left(tb,
+ tb->
+ lnum
+ [0],
+ tb->
+ lbytes
+ -
+ 1);
+ if (ret_val
+ && !item_pos) {
+ pasted =
+ B_N_PITEM_HEAD
+ (tb->L[0],
+ B_NR_ITEMS
+ (tb->
+ L[0]) -
+ 1);
+ l_pos_in_item +=
+ I_ENTRY_COUNT
+ (pasted) -
+ (tb->
+ lbytes -
+ 1);
+ }
+
+ /* Append given directory entry to directory item */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[0];
+ bi.bi_parent =
+ tb->FL[0];
+ bi.bi_position =
+ get_left_neighbor_position
+ (tb, 0);
+ leaf_paste_in_buffer
+ (&bi,
+ n + item_pos -
+ ret_val,
+ l_pos_in_item,
+ tb->insert_size[0],
+ body, zeros_num);
+
+ /* previous string prepared space for pasting new entry, following string pastes this entry */
+
+ /* when we have merge directory item, pos_in_item has been changed too */
+
+ /* paste new directory entry. 1 is entry number */
+ leaf_paste_entries(bi.
+ bi_bh,
+ n +
+ item_pos
+ -
+ ret_val,
+ l_pos_in_item,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)
+ body,
+ body
+ +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ tb->insert_size[0] = 0;
+ } else {
+ /* new directory item doesn't fall into L[0] */
+ /* Shift lnum[0]-1 items in whole. Shift lbytes directory entries from directory item number lnum[0] */
+ leaf_shift_left(tb,
+ tb->
+ lnum[0],
+ tb->
+ lbytes);
+ }
+ /* Calculate new position to append in item body */
+ pos_in_item -= tb->lbytes;
+ } else {
+ /* regular object */
+ RFALSE(tb->lbytes <= 0,
+ "PAP-12095: there is nothing to shift to L[0]. lbytes=%d",
+ tb->lbytes);
+ RFALSE(pos_in_item !=
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0, item_pos)),
+ "PAP-12100: incorrect position to paste: item_len=%d, pos_in_item=%d",
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0, item_pos)),
+ pos_in_item);
+
+ if (tb->lbytes >= pos_in_item) {
+ /* appended item will be in L[0] in whole */
+ int l_n;
+
+ /* this bytes number must be appended to the last item of L[h] */
+ l_n =
+ tb->lbytes -
+ pos_in_item;
+
+ /* Calculate new insert_size[0] */
+ tb->insert_size[0] -=
+ l_n;
+
+ RFALSE(tb->
+ insert_size[0] <=
+ 0,
+ "PAP-12105: there is nothing to paste into L[0]. insert_size=%d",
+ tb->
+ insert_size[0]);
+ ret_val =
+ leaf_shift_left(tb,
+ tb->
+ lnum
+ [0],
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0,
+ item_pos)));
+ /* Append to body of item in L[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[0];
+ bi.bi_parent =
+ tb->FL[0];
+ bi.bi_position =
+ get_left_neighbor_position
+ (tb, 0);
+ leaf_paste_in_buffer
+ (&bi,
+ n + item_pos -
+ ret_val,
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tb->L[0],
+ n + item_pos -
+ ret_val)), l_n,
+ body,
+ zeros_num >
+ l_n ? l_n :
+ zeros_num);
+ /* 0-th item in S0 can be only of DIRECT type when l_n != 0 */
+ {
+ int version;
+ int temp_l =
+ l_n;
+
+ RFALSE
+ (ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0,
+ 0)),
+ "PAP-12106: item length must be 0");
+ RFALSE
+ (comp_short_le_keys
+ (B_N_PKEY
+ (tbS0, 0),
+ B_N_PKEY
+ (tb->L[0],
+ n +
+ item_pos
+ -
+ ret_val)),
+ "PAP-12107: items must be of the same file");
+ if (is_indirect_le_ih(B_N_PITEM_HEAD(tb->L[0], n + item_pos - ret_val))) {
+ temp_l =
+ l_n
+ <<
+ (tb->
+ tb_sb->
+ s_blocksize_bits
+ -
+ UNFM_P_SHIFT);
+ }
+ /* update key of first item in S0 */
+ version =
+ ih_version
+ (B_N_PITEM_HEAD
+ (tbS0, 0));
+ set_le_key_k_offset
+ (version,
+ B_N_PKEY
+ (tbS0, 0),
+ le_key_k_offset
+ (version,
+ B_N_PKEY
+ (tbS0,
+ 0)) +
+ temp_l);
+ /* update left delimiting key */
+ set_le_key_k_offset
+ (version,
+ B_N_PDELIM_KEY
+ (tb->
+ CFL[0],
+ tb->
+ lkey[0]),
+ le_key_k_offset
+ (version,
+ B_N_PDELIM_KEY
+ (tb->
+ CFL[0],
+ tb->
+ lkey[0]))
+ + temp_l);
+ }
+
+ /* Calculate new body, position in item and insert_size[0] */
+ if (l_n > zeros_num) {
+ body +=
+ (l_n -
+ zeros_num);
+ zeros_num = 0;
+ } else
+ zeros_num -=
+ l_n;
+ pos_in_item = 0;
+
+ RFALSE
+ (comp_short_le_keys
+ (B_N_PKEY(tbS0, 0),
+ B_N_PKEY(tb->L[0],
+ B_NR_ITEMS
+ (tb->
+ L[0]) -
+ 1))
+ ||
+ !op_is_left_mergeable
+ (B_N_PKEY(tbS0, 0),
+ tbS0->b_size)
+ ||
+ !op_is_left_mergeable
+ (B_N_PDELIM_KEY
+ (tb->CFL[0],
+ tb->lkey[0]),
+ tbS0->b_size),
+ "PAP-12120: item must be merge-able with left neighboring item");
+ } else { /* only part of the appended item will be in L[0] */
+
+ /* Calculate position in item for append in S[0] */
+ pos_in_item -=
+ tb->lbytes;
+
+ RFALSE(pos_in_item <= 0,
+ "PAP-12125: no place for paste. pos_in_item=%d",
+ pos_in_item);
+
+ /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
+ leaf_shift_left(tb,
+ tb->
+ lnum[0],
+ tb->
+ lbytes);
+ }
+ }
+ } else { /* appended item will be in L[0] in whole */
+
+ struct item_head *pasted;
+
+ if (!item_pos && op_is_left_mergeable(B_N_PKEY(tbS0, 0), tbS0->b_size)) { /* if we paste into first item of S[0] and it is left mergable */
+ /* then increment pos_in_item by the size of the last item in L[0] */
+ pasted =
+ B_N_PITEM_HEAD(tb->L[0],
+ n - 1);
+ if (is_direntry_le_ih(pasted))
+ pos_in_item +=
+ ih_entry_count
+ (pasted);
+ else
+ pos_in_item +=
+ ih_item_len(pasted);
+ }
+
+ /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
+ ret_val =
+ leaf_shift_left(tb, tb->lnum[0],
+ tb->lbytes);
+ /* Append to body of item in L[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[0];
+ bi.bi_parent = tb->FL[0];
+ bi.bi_position =
+ get_left_neighbor_position(tb, 0);
+ leaf_paste_in_buffer(&bi,
+ n + item_pos -
+ ret_val,
+ pos_in_item,
+ tb->insert_size[0],
+ body, zeros_num);
+
+ /* if appended item is directory, paste entry */
+ pasted =
+ B_N_PITEM_HEAD(tb->L[0],
+ n + item_pos -
+ ret_val);
+ if (is_direntry_le_ih(pasted))
+ leaf_paste_entries(bi.bi_bh,
+ n +
+ item_pos -
+ ret_val,
+ pos_in_item,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)body,
+ body +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ /* if appended item is indirect item, put unformatted node into un list */
+ if (is_indirect_le_ih(pasted))
+ set_ih_free_space(pasted, 0);
+ tb->insert_size[0] = 0;
+ zeros_num = 0;
+ }
+ break;
+ default: /* cases d and t */
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)",
+ (flag ==
+ M_DELETE) ? "DELETE" : ((flag ==
+ M_CUT)
+ ? "CUT"
+ :
+ "UNKNOWN"),
+ flag);
}
-
- /* Shift lnum[0] - 1 items in whole. Shift lbytes - 1 byte from item number lnum[0] */
- ret_val = leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
- /* Append to body of item in L[0] */
- bi.tb = tb;
- bi.bi_bh = tb->L[0];
- bi.bi_parent = tb->FL[0];
- bi.bi_position = get_left_neighbor_position (tb, 0);
- leaf_paste_in_buffer (&bi, n + item_pos - ret_val, pos_in_item, tb->insert_size[0],
- body, zeros_num);
-
- /* if appended item is directory, paste entry */
- pasted = B_N_PITEM_HEAD (tb->L[0], n + item_pos - ret_val);
- if (is_direntry_le_ih (pasted))
- leaf_paste_entries (
- bi.bi_bh, n + item_pos - ret_val, pos_in_item, 1,
- (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]
- );
- /* if appended item is indirect item, put unformatted node into un list */
- if (is_indirect_le_ih (pasted))
- set_ih_free_space (pasted, 0);
- tb->insert_size[0] = 0;
- zeros_num = 0;
+ } else {
+ /* new item doesn't fall into L[0] */
+ leaf_shift_left(tb, tb->lnum[0], tb->lbytes);
}
- break;
- default: /* cases d and t */
- reiserfs_panic (tb->tb_sb, "PAP-12130: balance_leaf: lnum > 0: unexpectable mode: %s(%d)",
- (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
- }
- } else {
- /* new item doesn't fall into L[0] */
- leaf_shift_left(tb,tb->lnum[0],tb->lbytes);
}
- } /* tb->lnum[0] > 0 */
- /* Calculate new item position */
- item_pos -= ( tb->lnum[0] - (( tb->lbytes != -1 ) ? 1 : 0));
-
- if ( tb->rnum[0] > 0 ) {
- /* shift rnum[0] items from S[0] to the right neighbor R[0] */
- n = B_NR_ITEMS(tbS0);
- switch ( flag ) {
-
- case M_INSERT: /* insert item */
- if ( n - tb->rnum[0] < item_pos )
- { /* new item or its part falls to R[0] */
- if ( item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1 )
- { /* part of new item falls into R[0] */
- loff_t old_key_comp, old_len, r_zeros_number;
- const char * r_body;
- int version;
- loff_t offset;
-
- leaf_shift_right(tb,tb->rnum[0]-1,-1);
-
- version = ih_version(ih);
- /* Remember key component and item length */
- old_key_comp = le_ih_k_offset( ih );
- old_len = ih_item_len(ih);
-
- /* Calculate key component and item length to insert into R[0] */
- offset = le_ih_k_offset( ih ) + ((old_len - tb->rbytes )<<(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0));
- set_le_ih_k_offset( ih, offset );
- put_ih_item_len( ih, tb->rbytes);
- /* Insert part of the item into R[0] */
- bi.tb = tb;
- bi.bi_bh = tb->R[0];
- bi.bi_parent = tb->FR[0];
- bi.bi_position = get_right_neighbor_position (tb, 0);
- if ( (old_len - tb->rbytes) > zeros_num ) {
- r_zeros_number = 0;
- r_body = body + (old_len - tb->rbytes) - zeros_num;
- }
- else {
- r_body = body;
- r_zeros_number = zeros_num - (old_len - tb->rbytes);
- zeros_num -= r_zeros_number;
- }
-
- leaf_insert_into_buf (&bi, 0, ih, r_body, r_zeros_number);
-
- /* Replace right delimiting key by first key in R[0] */
- replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
-
- /* Calculate key component and item length to insert into S[0] */
- set_le_ih_k_offset( ih, old_key_comp );
- put_ih_item_len( ih, old_len - tb->rbytes );
-
- tb->insert_size[0] -= tb->rbytes;
+ /* tb->lnum[0] > 0 */
+ /* Calculate new item position */
+ item_pos -= (tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0));
+
+ if (tb->rnum[0] > 0) {
+ /* shift rnum[0] items from S[0] to the right neighbor R[0] */
+ n = B_NR_ITEMS(tbS0);
+ switch (flag) {
+
+ case M_INSERT: /* insert item */
+ if (n - tb->rnum[0] < item_pos) { /* new item or its part falls to R[0] */
+ if (item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1) { /* part of new item falls into R[0] */
+ loff_t old_key_comp, old_len,
+ r_zeros_number;
+ const char *r_body;
+ int version;
+ loff_t offset;
+
+ leaf_shift_right(tb, tb->rnum[0] - 1,
+ -1);
+
+ version = ih_version(ih);
+ /* Remember key component and item length */
+ old_key_comp = le_ih_k_offset(ih);
+ old_len = ih_item_len(ih);
+
+ /* Calculate key component and item length to insert into R[0] */
+ offset =
+ le_ih_k_offset(ih) +
+ ((old_len -
+ tb->
+ rbytes) << (is_indirect_le_ih(ih)
+ ? tb->tb_sb->
+ s_blocksize_bits -
+ UNFM_P_SHIFT : 0));
+ set_le_ih_k_offset(ih, offset);
+ put_ih_item_len(ih, tb->rbytes);
+ /* Insert part of the item into R[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->R[0];
+ bi.bi_parent = tb->FR[0];
+ bi.bi_position =
+ get_right_neighbor_position(tb, 0);
+ if ((old_len - tb->rbytes) > zeros_num) {
+ r_zeros_number = 0;
+ r_body =
+ body + (old_len -
+ tb->rbytes) -
+ zeros_num;
+ } else {
+ r_body = body;
+ r_zeros_number =
+ zeros_num - (old_len -
+ tb->rbytes);
+ zeros_num -= r_zeros_number;
+ }
+
+ leaf_insert_into_buf(&bi, 0, ih, r_body,
+ r_zeros_number);
+
+ /* Replace right delimiting key by first key in R[0] */
+ replace_key(tb, tb->CFR[0], tb->rkey[0],
+ tb->R[0], 0);
+
+ /* Calculate key component and item length to insert into S[0] */
+ set_le_ih_k_offset(ih, old_key_comp);
+ put_ih_item_len(ih,
+ old_len - tb->rbytes);
+
+ tb->insert_size[0] -= tb->rbytes;
+
+ } else { /* whole new item falls into R[0] */
+
+ /* Shift rnum[0]-1 items to R[0] */
+ ret_val =
+ leaf_shift_right(tb,
+ tb->rnum[0] - 1,
+ tb->rbytes);
+ /* Insert new item into R[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->R[0];
+ bi.bi_parent = tb->FR[0];
+ bi.bi_position =
+ get_right_neighbor_position(tb, 0);
+ leaf_insert_into_buf(&bi,
+ item_pos - n +
+ tb->rnum[0] - 1,
+ ih, body,
+ zeros_num);
+
+ if (item_pos - n + tb->rnum[0] - 1 == 0) {
+ replace_key(tb, tb->CFR[0],
+ tb->rkey[0],
+ tb->R[0], 0);
+
+ }
+ zeros_num = tb->insert_size[0] = 0;
+ }
+ } else { /* new item or part of it doesn't fall into R[0] */
- }
- else /* whole new item falls into R[0] */
- {
- /* Shift rnum[0]-1 items to R[0] */
- ret_val = leaf_shift_right(tb,tb->rnum[0]-1,tb->rbytes);
- /* Insert new item into R[0] */
- bi.tb = tb;
- bi.bi_bh = tb->R[0];
- bi.bi_parent = tb->FR[0];
- bi.bi_position = get_right_neighbor_position (tb, 0);
- leaf_insert_into_buf (&bi, item_pos - n + tb->rnum[0] - 1, ih, body, zeros_num);
-
- if ( item_pos - n + tb->rnum[0] - 1 == 0 ) {
- replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
-
- }
- zeros_num = tb->insert_size[0] = 0;
- }
- }
- else /* new item or part of it doesn't fall into R[0] */
- {
- leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
- }
- break;
-
- case M_PASTE: /* append item */
-
- if ( n - tb->rnum[0] <= item_pos ) /* pasted item or part of it falls to R[0] */
- {
- if ( item_pos == n - tb->rnum[0] && tb->rbytes != -1 )
- { /* we must shift the part of the appended item */
- if ( is_direntry_le_ih (B_N_PITEM_HEAD(tbS0, item_pos)))
- { /* we append to directory item */
- int entry_count;
-
- RFALSE( zeros_num,
- "PAP-12145: invalid parameter in case of a directory");
- entry_count = I_ENTRY_COUNT(B_N_PITEM_HEAD(tbS0, item_pos));
- if ( entry_count - tb->rbytes < pos_in_item )
- /* new directory entry falls into R[0] */
- {
- int paste_entry_position;
-
- RFALSE( tb->rbytes - 1 >= entry_count ||
- ! tb->insert_size[0],
- "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
- tb->rbytes, entry_count);
- /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
- leaf_shift_right(tb,tb->rnum[0],tb->rbytes - 1);
- /* Paste given directory entry to directory item */
- paste_entry_position = pos_in_item - entry_count + tb->rbytes - 1;
- bi.tb = tb;
- bi.bi_bh = tb->R[0];
- bi.bi_parent = tb->FR[0];
- bi.bi_position = get_right_neighbor_position (tb, 0);
- leaf_paste_in_buffer (&bi, 0, paste_entry_position,
- tb->insert_size[0],body,zeros_num);
- /* paste entry */
- leaf_paste_entries (
- bi.bi_bh, 0, paste_entry_position, 1, (struct reiserfs_de_head *)body,
- body + DEH_SIZE, tb->insert_size[0]
- );
-
- if ( paste_entry_position == 0 ) {
- /* change delimiting keys */
- replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
- }
-
- tb->insert_size[0] = 0;
- pos_in_item++;
- }
- else /* new directory entry doesn't fall into R[0] */
- {
- leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
- }
- }
- else /* regular object */
- {
- int n_shift, n_rem, r_zeros_number;
- const char * r_body;
-
- /* Calculate number of bytes which must be shifted from appended item */
- if ( (n_shift = tb->rbytes - tb->insert_size[0]) < 0 )
- n_shift = 0;
-
- RFALSE(pos_in_item != ih_item_len(B_N_PITEM_HEAD (tbS0, item_pos)),
- "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
- pos_in_item, ih_item_len( B_N_PITEM_HEAD(tbS0,item_pos)));
-
- leaf_shift_right(tb,tb->rnum[0],n_shift);
- /* Calculate number of bytes which must remain in body after appending to R[0] */
- if ( (n_rem = tb->insert_size[0] - tb->rbytes) < 0 )
- n_rem = 0;
-
- {
- int version;
- unsigned long temp_rem = n_rem;
-
- version = ih_version (B_N_PITEM_HEAD (tb->R[0],0));
- if (is_indirect_le_key(version,B_N_PKEY(tb->R[0],0))){
- temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits -
- UNFM_P_SHIFT);
- }
- set_le_key_k_offset (version, B_N_PKEY(tb->R[0],0),
- le_key_k_offset (version, B_N_PKEY(tb->R[0],0)) + temp_rem);
- set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0]),
- le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) + temp_rem);
+ leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
}
+ break;
+
+ case M_PASTE: /* append item */
+
+ if (n - tb->rnum[0] <= item_pos) { /* pasted item or part of it falls to R[0] */
+ if (item_pos == n - tb->rnum[0] && tb->rbytes != -1) { /* we must shift the part of the appended item */
+ if (is_direntry_le_ih(B_N_PITEM_HEAD(tbS0, item_pos))) { /* we append to directory item */
+ int entry_count;
+
+ RFALSE(zeros_num,
+ "PAP-12145: invalid parameter in case of a directory");
+ entry_count =
+ I_ENTRY_COUNT(B_N_PITEM_HEAD
+ (tbS0,
+ item_pos));
+ if (entry_count - tb->rbytes <
+ pos_in_item)
+ /* new directory entry falls into R[0] */
+ {
+ int paste_entry_position;
+
+ RFALSE(tb->rbytes - 1 >=
+ entry_count
+ || !tb->
+ insert_size[0],
+ "PAP-12150: no enough of entries to shift to R[0]: rbytes=%d, entry_count=%d",
+ tb->rbytes,
+ entry_count);
+ /* Shift rnum[0]-1 items in whole. Shift rbytes-1 directory entries from directory item number rnum[0] */
+ leaf_shift_right(tb,
+ tb->
+ rnum
+ [0],
+ tb->
+ rbytes
+ - 1);
+ /* Paste given directory entry to directory item */
+ paste_entry_position =
+ pos_in_item -
+ entry_count +
+ tb->rbytes - 1;
+ bi.tb = tb;
+ bi.bi_bh = tb->R[0];
+ bi.bi_parent =
+ tb->FR[0];
+ bi.bi_position =
+ get_right_neighbor_position
+ (tb, 0);
+ leaf_paste_in_buffer
+ (&bi, 0,
+ paste_entry_position,
+ tb->insert_size[0],
+ body, zeros_num);
+ /* paste entry */
+ leaf_paste_entries(bi.
+ bi_bh,
+ 0,
+ paste_entry_position,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)
+ body,
+ body
+ +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+
+ if (paste_entry_position
+ == 0) {
+ /* change delimiting keys */
+ replace_key(tb,
+ tb->
+ CFR
+ [0],
+ tb->
+ rkey
+ [0],
+ tb->
+ R
+ [0],
+ 0);
+ }
+
+ tb->insert_size[0] = 0;
+ pos_in_item++;
+ } else { /* new directory entry doesn't fall into R[0] */
+
+ leaf_shift_right(tb,
+ tb->
+ rnum
+ [0],
+ tb->
+ rbytes);
+ }
+ } else { /* regular object */
+
+ int n_shift, n_rem,
+ r_zeros_number;
+ const char *r_body;
+
+ /* Calculate number of bytes which must be shifted from appended item */
+ if ((n_shift =
+ tb->rbytes -
+ tb->insert_size[0]) < 0)
+ n_shift = 0;
+
+ RFALSE(pos_in_item !=
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0, item_pos)),
+ "PAP-12155: invalid position to paste. ih_item_len=%d, pos_in_item=%d",
+ pos_in_item,
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0, item_pos)));
+
+ leaf_shift_right(tb,
+ tb->rnum[0],
+ n_shift);
+ /* Calculate number of bytes which must remain in body after appending to R[0] */
+ if ((n_rem =
+ tb->insert_size[0] -
+ tb->rbytes) < 0)
+ n_rem = 0;
+
+ {
+ int version;
+ unsigned long temp_rem =
+ n_rem;
+
+ version =
+ ih_version
+ (B_N_PITEM_HEAD
+ (tb->R[0], 0));
+ if (is_indirect_le_key
+ (version,
+ B_N_PKEY(tb->R[0],
+ 0))) {
+ temp_rem =
+ n_rem <<
+ (tb->tb_sb->
+ s_blocksize_bits
+ -
+ UNFM_P_SHIFT);
+ }
+ set_le_key_k_offset
+ (version,
+ B_N_PKEY(tb->R[0],
+ 0),
+ le_key_k_offset
+ (version,
+ B_N_PKEY(tb->R[0],
+ 0)) +
+ temp_rem);
+ set_le_key_k_offset
+ (version,
+ B_N_PDELIM_KEY(tb->
+ CFR
+ [0],
+ tb->
+ rkey
+ [0]),
+ le_key_k_offset
+ (version,
+ B_N_PDELIM_KEY
+ (tb->CFR[0],
+ tb->rkey[0])) +
+ temp_rem);
+ }
/* k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
- do_balance_mark_internal_dirty (tb, tb->CFR[0], 0);
-
- /* Append part of body into R[0] */
- bi.tb = tb;
- bi.bi_bh = tb->R[0];
- bi.bi_parent = tb->FR[0];
- bi.bi_position = get_right_neighbor_position (tb, 0);
- if ( n_rem > zeros_num ) {
- r_zeros_number = 0;
- r_body = body + n_rem - zeros_num;
- }
- else {
- r_body = body;
- r_zeros_number = zeros_num - n_rem;
- zeros_num -= r_zeros_number;
- }
-
- leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0] - n_rem, r_body, r_zeros_number);
-
- if (is_indirect_le_ih (B_N_PITEM_HEAD(tb->R[0],0))) {
+ do_balance_mark_internal_dirty
+ (tb, tb->CFR[0], 0);
+
+ /* Append part of body into R[0] */
+ bi.tb = tb;
+ bi.bi_bh = tb->R[0];
+ bi.bi_parent = tb->FR[0];
+ bi.bi_position =
+ get_right_neighbor_position
+ (tb, 0);
+ if (n_rem > zeros_num) {
+ r_zeros_number = 0;
+ r_body =
+ body + n_rem -
+ zeros_num;
+ } else {
+ r_body = body;
+ r_zeros_number =
+ zeros_num - n_rem;
+ zeros_num -=
+ r_zeros_number;
+ }
+
+ leaf_paste_in_buffer(&bi, 0,
+ n_shift,
+ tb->
+ insert_size
+ [0] -
+ n_rem,
+ r_body,
+ r_zeros_number);
+
+ if (is_indirect_le_ih
+ (B_N_PITEM_HEAD
+ (tb->R[0], 0))) {
#if 0
- RFALSE( n_rem,
- "PAP-12160: paste more than one unformatted node pointer");
+ RFALSE(n_rem,
+ "PAP-12160: paste more than one unformatted node pointer");
#endif
- set_ih_free_space (B_N_PITEM_HEAD(tb->R[0],0), 0);
- }
- tb->insert_size[0] = n_rem;
- if ( ! n_rem )
- pos_in_item ++;
- }
- }
- else /* pasted item in whole falls into R[0] */
- {
- struct item_head * pasted;
+ set_ih_free_space
+ (B_N_PITEM_HEAD
+ (tb->R[0], 0), 0);
+ }
+ tb->insert_size[0] = n_rem;
+ if (!n_rem)
+ pos_in_item++;
+ }
+ } else { /* pasted item in whole falls into R[0] */
+
+ struct item_head *pasted;
+
+ ret_val =
+ leaf_shift_right(tb, tb->rnum[0],
+ tb->rbytes);
+ /* append item in R[0] */
+ if (pos_in_item >= 0) {
+ bi.tb = tb;
+ bi.bi_bh = tb->R[0];
+ bi.bi_parent = tb->FR[0];
+ bi.bi_position =
+ get_right_neighbor_position
+ (tb, 0);
+ leaf_paste_in_buffer(&bi,
+ item_pos -
+ n +
+ tb->
+ rnum[0],
+ pos_in_item,
+ tb->
+ insert_size
+ [0], body,
+ zeros_num);
+ }
+
+ /* paste new entry, if item is directory item */
+ pasted =
+ B_N_PITEM_HEAD(tb->R[0],
+ item_pos - n +
+ tb->rnum[0]);
+ if (is_direntry_le_ih(pasted)
+ && pos_in_item >= 0) {
+ leaf_paste_entries(bi.bi_bh,
+ item_pos -
+ n +
+ tb->rnum[0],
+ pos_in_item,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)body,
+ body +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ if (!pos_in_item) {
+
+ RFALSE(item_pos - n +
+ tb->rnum[0],
+ "PAP-12165: directory item must be first item of node when pasting is in 0th position");
+
+ /* update delimiting keys */
+ replace_key(tb,
+ tb->CFR[0],
+ tb->rkey[0],
+ tb->R[0],
+ 0);
+ }
+ }
+
+ if (is_indirect_le_ih(pasted))
+ set_ih_free_space(pasted, 0);
+ zeros_num = tb->insert_size[0] = 0;
+ }
+ } else { /* new item doesn't fall into R[0] */
- ret_val = leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
- /* append item in R[0] */
- if ( pos_in_item >= 0 ) {
- bi.tb = tb;
- bi.bi_bh = tb->R[0];
- bi.bi_parent = tb->FR[0];
- bi.bi_position = get_right_neighbor_position (tb, 0);
- leaf_paste_in_buffer(&bi,item_pos - n + tb->rnum[0], pos_in_item,
- tb->insert_size[0],body, zeros_num);
- }
-
- /* paste new entry, if item is directory item */
- pasted = B_N_PITEM_HEAD(tb->R[0], item_pos - n + tb->rnum[0]);
- if (is_direntry_le_ih (pasted) && pos_in_item >= 0 ) {
- leaf_paste_entries (
- bi.bi_bh, item_pos - n + tb->rnum[0], pos_in_item, 1,
- (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]
- );
- if ( ! pos_in_item ) {
-
- RFALSE( item_pos - n + tb->rnum[0],
- "PAP-12165: directory item must be first item of node when pasting is in 0th position");
-
- /* update delimiting keys */
- replace_key(tb, tb->CFR[0],tb->rkey[0],tb->R[0],0);
+ leaf_shift_right(tb, tb->rnum[0], tb->rbytes);
}
- }
-
- if (is_indirect_le_ih (pasted))
- set_ih_free_space (pasted, 0);
- zeros_num = tb->insert_size[0] = 0;
+ break;
+ default: /* cases d and t */
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)",
+ (flag ==
+ M_DELETE) ? "DELETE" : ((flag ==
+ M_CUT) ? "CUT"
+ : "UNKNOWN"),
+ flag);
}
- }
- else /* new item doesn't fall into R[0] */
- {
- leaf_shift_right(tb,tb->rnum[0],tb->rbytes);
- }
- break;
- default: /* cases d and t */
- reiserfs_panic (tb->tb_sb, "PAP-12175: balance_leaf: rnum > 0: unexpectable mode: %s(%d)",
- (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
- }
-
- } /* tb->rnum[0] > 0 */
-
-
- RFALSE( tb->blknum[0] > 3,
- "PAP-12180: blknum can not be %d. It must be <= 3", tb->blknum[0]);
- RFALSE( tb->blknum[0] < 0,
- "PAP-12185: blknum can not be %d. It must be >= 0", tb->blknum[0]);
-
- /* if while adding to a node we discover that it is possible to split
- it in two, and merge the left part into the left neighbor and the
- right part into the right neighbor, eliminating the node */
- if ( tb->blknum[0] == 0 ) { /* node S[0] is empty now */
-
- RFALSE( ! tb->lnum[0] || ! tb->rnum[0],
- "PAP-12190: lnum and rnum must not be zero");
- /* if insertion was done before 0-th position in R[0], right
- delimiting key of the tb->L[0]'s and left delimiting key are
- not set correctly */
- if (tb->CFL[0]) {
- if (!tb->CFR[0])
- reiserfs_panic (tb->tb_sb, "vs-12195: balance_leaf: CFR not initialized");
- copy_key (B_N_PDELIM_KEY (tb->CFL[0], tb->lkey[0]), B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]));
- do_balance_mark_internal_dirty (tb, tb->CFL[0], 0);
- }
-
- reiserfs_invalidate_buffer(tb,tbS0);
- return 0;
- }
-
-
- /* Fill new nodes that appear in place of S[0] */
- /* I am told that this copying is because we need an array to enable
- the looping code. -Hans */
- snum[0] = tb->s1num,
- snum[1] = tb->s2num;
- sbytes[0] = tb->s1bytes;
- sbytes[1] = tb->s2bytes;
- for( i = tb->blknum[0] - 2; i >= 0; i-- ) {
-
- RFALSE( !snum[i], "PAP-12200: snum[%d] == %d. Must be > 0", i, snum[i]);
+ }
- /* here we shift from S to S_new nodes */
+ /* tb->rnum[0] > 0 */
+ RFALSE(tb->blknum[0] > 3,
+ "PAP-12180: blknum can not be %d. It must be <= 3",
+ tb->blknum[0]);
+ RFALSE(tb->blknum[0] < 0,
+ "PAP-12185: blknum can not be %d. It must be >= 0",
+ tb->blknum[0]);
+
+ /* if while adding to a node we discover that it is possible to split
+ it in two, and merge the left part into the left neighbor and the
+ right part into the right neighbor, eliminating the node */
+ if (tb->blknum[0] == 0) { /* node S[0] is empty now */
+
+ RFALSE(!tb->lnum[0] || !tb->rnum[0],
+ "PAP-12190: lnum and rnum must not be zero");
+ /* if insertion was done before 0-th position in R[0], right
+ delimiting key of the tb->L[0]'s and left delimiting key are
+ not set correctly */
+ if (tb->CFL[0]) {
+ if (!tb->CFR[0])
+ reiserfs_panic(tb->tb_sb,
+ "vs-12195: balance_leaf: CFR not initialized");
+ copy_key(B_N_PDELIM_KEY(tb->CFL[0], tb->lkey[0]),
+ B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]));
+ do_balance_mark_internal_dirty(tb, tb->CFL[0], 0);
+ }
- S_new[i] = get_FEB(tb);
+ reiserfs_invalidate_buffer(tb, tbS0);
+ return 0;
+ }
- /* initialized block type and tree level */
- set_blkh_level( B_BLK_HEAD(S_new[i]), DISK_LEAF_NODE_LEVEL );
+ /* Fill new nodes that appear in place of S[0] */
+
+ /* I am told that this copying is because we need an array to enable
+ the looping code. -Hans */
+ snum[0] = tb->s1num, snum[1] = tb->s2num;
+ sbytes[0] = tb->s1bytes;
+ sbytes[1] = tb->s2bytes;
+ for (i = tb->blknum[0] - 2; i >= 0; i--) {
+
+ RFALSE(!snum[i], "PAP-12200: snum[%d] == %d. Must be > 0", i,
+ snum[i]);
+
+ /* here we shift from S to S_new nodes */
+
+ S_new[i] = get_FEB(tb);
+
+ /* initialized block type and tree level */
+ set_blkh_level(B_BLK_HEAD(S_new[i]), DISK_LEAF_NODE_LEVEL);
+
+ n = B_NR_ITEMS(tbS0);
+
+ switch (flag) {
+ case M_INSERT: /* insert item */
+
+ if (n - snum[i] < item_pos) { /* new item or it's part falls to first new node S_new[i] */
+ if (item_pos == n - snum[i] + 1 && sbytes[i] != -1) { /* part of new item falls into S_new[i] */
+ int old_key_comp, old_len,
+ r_zeros_number;
+ const char *r_body;
+ int version;
+
+ /* Move snum[i]-1 items from S[0] to S_new[i] */
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
+ snum[i] - 1, -1,
+ S_new[i]);
+ /* Remember key component and item length */
+ version = ih_version(ih);
+ old_key_comp = le_ih_k_offset(ih);
+ old_len = ih_item_len(ih);
+
+ /* Calculate key component and item length to insert into S_new[i] */
+ set_le_ih_k_offset(ih,
+ le_ih_k_offset(ih) +
+ ((old_len -
+ sbytes[i]) <<
+ (is_indirect_le_ih
+ (ih) ? tb->tb_sb->
+ s_blocksize_bits -
+ UNFM_P_SHIFT :
+ 0)));
+
+ put_ih_item_len(ih, sbytes[i]);
+
+ /* Insert part of the item into S_new[i] before 0-th item */
+ bi.tb = tb;
+ bi.bi_bh = S_new[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+
+ if ((old_len - sbytes[i]) > zeros_num) {
+ r_zeros_number = 0;
+ r_body =
+ body + (old_len -
+ sbytes[i]) -
+ zeros_num;
+ } else {
+ r_body = body;
+ r_zeros_number =
+ zeros_num - (old_len -
+ sbytes[i]);
+ zeros_num -= r_zeros_number;
+ }
+
+ leaf_insert_into_buf(&bi, 0, ih, r_body,
+ r_zeros_number);
+
+ /* Calculate key component and item length to insert into S[i] */
+ set_le_ih_k_offset(ih, old_key_comp);
+ put_ih_item_len(ih,
+ old_len - sbytes[i]);
+ tb->insert_size[0] -= sbytes[i];
+ } else { /* whole new item falls into S_new[i] */
+
+ /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
+ snum[i] - 1, sbytes[i],
+ S_new[i]);
+
+ /* Insert new item into S_new[i] */
+ bi.tb = tb;
+ bi.bi_bh = S_new[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+ leaf_insert_into_buf(&bi,
+ item_pos - n +
+ snum[i] - 1, ih,
+ body, zeros_num);
+
+ zeros_num = tb->insert_size[0] = 0;
+ }
+ }
+ else { /* new item or it part don't falls into S_new[i] */
- n = B_NR_ITEMS(tbS0);
-
- switch (flag) {
- case M_INSERT: /* insert item */
-
- if ( n - snum[i] < item_pos )
- { /* new item or it's part falls to first new node S_new[i]*/
- if ( item_pos == n - snum[i] + 1 && sbytes[i] != -1 )
- { /* part of new item falls into S_new[i] */
- int old_key_comp, old_len, r_zeros_number;
- const char * r_body;
- int version;
-
- /* Move snum[i]-1 items from S[0] to S_new[i] */
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]);
- /* Remember key component and item length */
- version = ih_version (ih);
- old_key_comp = le_ih_k_offset( ih );
- old_len = ih_item_len(ih);
-
- /* Calculate key component and item length to insert into S_new[i] */
- set_le_ih_k_offset( ih,
- le_ih_k_offset(ih) + ((old_len - sbytes[i] )<<(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0)) );
-
- put_ih_item_len( ih, sbytes[i] );
-
- /* Insert part of the item into S_new[i] before 0-th item */
- bi.tb = tb;
- bi.bi_bh = S_new[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
-
- if ( (old_len - sbytes[i]) > zeros_num ) {
- r_zeros_number = 0;
- r_body = body + (old_len - sbytes[i]) - zeros_num;
- }
- else {
- r_body = body;
- r_zeros_number = zeros_num - (old_len - sbytes[i]);
- zeros_num -= r_zeros_number;
- }
-
- leaf_insert_into_buf (&bi, 0, ih, r_body, r_zeros_number);
-
- /* Calculate key component and item length to insert into S[i] */
- set_le_ih_k_offset( ih, old_key_comp );
- put_ih_item_len( ih, old_len - sbytes[i] );
- tb->insert_size[0] -= sbytes[i];
- }
- else /* whole new item falls into S_new[i] */
- {
- /* Shift snum[0] - 1 items to S_new[i] (sbytes[i] of split item) */
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, sbytes[i], S_new[i]);
-
- /* Insert new item into S_new[i] */
- bi.tb = tb;
- bi.bi_bh = S_new[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
- leaf_insert_into_buf (&bi, item_pos - n + snum[i] - 1, ih, body, zeros_num);
-
- zeros_num = tb->insert_size[0] = 0;
- }
- }
-
- else /* new item or it part don't falls into S_new[i] */
- {
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
- }
- break;
-
- case M_PASTE: /* append item */
-
- if ( n - snum[i] <= item_pos ) /* pasted item or part if it falls to S_new[i] */
- {
- if ( item_pos == n - snum[i] && sbytes[i] != -1 )
- { /* we must shift part of the appended item */
- struct item_head * aux_ih;
-
- RFALSE( ih, "PAP-12210: ih must be 0");
-
- if ( is_direntry_le_ih (aux_ih = B_N_PITEM_HEAD(tbS0,item_pos))) {
- /* we append to directory item */
-
- int entry_count;
-
- entry_count = ih_entry_count(aux_ih);
-
- if ( entry_count - sbytes[i] < pos_in_item && pos_in_item <= entry_count ) {
- /* new directory entry falls into S_new[i] */
-
- RFALSE( ! tb->insert_size[0],
- "PAP-12215: insert_size is already 0");
- RFALSE( sbytes[i] - 1 >= entry_count,
- "PAP-12220: there are no so much entries (%d), only %d",
- sbytes[i] - 1, entry_count);
-
- /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i]-1, S_new[i]);
- /* Paste given directory entry to directory item */
- bi.tb = tb;
- bi.bi_bh = S_new[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
- leaf_paste_in_buffer (&bi, 0, pos_in_item - entry_count + sbytes[i] - 1,
- tb->insert_size[0], body,zeros_num);
- /* paste new directory entry */
- leaf_paste_entries (
- bi.bi_bh, 0, pos_in_item - entry_count + sbytes[i] - 1,
- 1, (struct reiserfs_de_head *)body, body + DEH_SIZE,
- tb->insert_size[0]
- );
- tb->insert_size[0] = 0;
- pos_in_item++;
- } else { /* new directory entry doesn't fall into S_new[i] */
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
+ snum[i], sbytes[i], S_new[i]);
}
- }
- else /* regular object */
- {
- int n_shift, n_rem, r_zeros_number;
- const char * r_body;
-
- RFALSE( pos_in_item != ih_item_len(B_N_PITEM_HEAD(tbS0,item_pos)) ||
- tb->insert_size[0] <= 0,
- "PAP-12225: item too short or insert_size <= 0");
-
- /* Calculate number of bytes which must be shifted from appended item */
- n_shift = sbytes[i] - tb->insert_size[0];
- if ( n_shift < 0 )
- n_shift = 0;
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], n_shift, S_new[i]);
-
- /* Calculate number of bytes which must remain in body after append to S_new[i] */
- n_rem = tb->insert_size[0] - sbytes[i];
- if ( n_rem < 0 )
- n_rem = 0;
- /* Append part of body into S_new[0] */
- bi.tb = tb;
- bi.bi_bh = S_new[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
+ break;
+
+ case M_PASTE: /* append item */
+
+ if (n - snum[i] <= item_pos) { /* pasted item or part if it falls to S_new[i] */
+ if (item_pos == n - snum[i] && sbytes[i] != -1) { /* we must shift part of the appended item */
+ struct item_head *aux_ih;
+
+ RFALSE(ih, "PAP-12210: ih must be 0");
+
+ if (is_direntry_le_ih
+ (aux_ih =
+ B_N_PITEM_HEAD(tbS0, item_pos))) {
+ /* we append to directory item */
+
+ int entry_count;
+
+ entry_count =
+ ih_entry_count(aux_ih);
+
+ if (entry_count - sbytes[i] <
+ pos_in_item
+ && pos_in_item <=
+ entry_count) {
+ /* new directory entry falls into S_new[i] */
+
+ RFALSE(!tb->
+ insert_size[0],
+ "PAP-12215: insert_size is already 0");
+ RFALSE(sbytes[i] - 1 >=
+ entry_count,
+ "PAP-12220: there are no so much entries (%d), only %d",
+ sbytes[i] - 1,
+ entry_count);
+
+ /* Shift snum[i]-1 items in whole. Shift sbytes[i] directory entries from directory item number snum[i] */
+ leaf_move_items
+ (LEAF_FROM_S_TO_SNEW,
+ tb, snum[i],
+ sbytes[i] - 1,
+ S_new[i]);
+ /* Paste given directory entry to directory item */
+ bi.tb = tb;
+ bi.bi_bh = S_new[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+ leaf_paste_in_buffer
+ (&bi, 0,
+ pos_in_item -
+ entry_count +
+ sbytes[i] - 1,
+ tb->insert_size[0],
+ body, zeros_num);
+ /* paste new directory entry */
+ leaf_paste_entries(bi.
+ bi_bh,
+ 0,
+ pos_in_item
+ -
+ entry_count
+ +
+ sbytes
+ [i] -
+ 1, 1,
+ (struct
+ reiserfs_de_head
+ *)
+ body,
+ body
+ +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ tb->insert_size[0] = 0;
+ pos_in_item++;
+ } else { /* new directory entry doesn't fall into S_new[i] */
+ leaf_move_items
+ (LEAF_FROM_S_TO_SNEW,
+ tb, snum[i],
+ sbytes[i],
+ S_new[i]);
+ }
+ } else { /* regular object */
+
+ int n_shift, n_rem,
+ r_zeros_number;
+ const char *r_body;
+
+ RFALSE(pos_in_item !=
+ ih_item_len
+ (B_N_PITEM_HEAD
+ (tbS0, item_pos))
+ || tb->insert_size[0] <=
+ 0,
+ "PAP-12225: item too short or insert_size <= 0");
+
+ /* Calculate number of bytes which must be shifted from appended item */
+ n_shift =
+ sbytes[i] -
+ tb->insert_size[0];
+ if (n_shift < 0)
+ n_shift = 0;
+ leaf_move_items
+ (LEAF_FROM_S_TO_SNEW, tb,
+ snum[i], n_shift,
+ S_new[i]);
+
+ /* Calculate number of bytes which must remain in body after append to S_new[i] */
+ n_rem =
+ tb->insert_size[0] -
+ sbytes[i];
+ if (n_rem < 0)
+ n_rem = 0;
+ /* Append part of body into S_new[0] */
+ bi.tb = tb;
+ bi.bi_bh = S_new[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+
+ if (n_rem > zeros_num) {
+ r_zeros_number = 0;
+ r_body =
+ body + n_rem -
+ zeros_num;
+ } else {
+ r_body = body;
+ r_zeros_number =
+ zeros_num - n_rem;
+ zeros_num -=
+ r_zeros_number;
+ }
+
+ leaf_paste_in_buffer(&bi, 0,
+ n_shift,
+ tb->
+ insert_size
+ [0] -
+ n_rem,
+ r_body,
+ r_zeros_number);
+ {
+ struct item_head *tmp;
+
+ tmp =
+ B_N_PITEM_HEAD(S_new
+ [i],
+ 0);
+ if (is_indirect_le_ih
+ (tmp)) {
+ set_ih_free_space
+ (tmp, 0);
+ set_le_ih_k_offset
+ (tmp,
+ le_ih_k_offset
+ (tmp) +
+ (n_rem <<
+ (tb->
+ tb_sb->
+ s_blocksize_bits
+ -
+ UNFM_P_SHIFT)));
+ } else {
+ set_le_ih_k_offset
+ (tmp,
+ le_ih_k_offset
+ (tmp) +
+ n_rem);
+ }
+ }
+
+ tb->insert_size[0] = n_rem;
+ if (!n_rem)
+ pos_in_item++;
+ }
+ } else
+ /* item falls wholly into S_new[i] */
+ {
+ int ret_val;
+ struct item_head *pasted;
- if ( n_rem > zeros_num ) {
- r_zeros_number = 0;
- r_body = body + n_rem - zeros_num;
- }
- else {
- r_body = body;
- r_zeros_number = zeros_num - n_rem;
- zeros_num -= r_zeros_number;
+#ifdef CONFIG_REISERFS_CHECK
+ struct item_head *ih =
+ B_N_PITEM_HEAD(tbS0, item_pos);
+
+ if (!is_direntry_le_ih(ih)
+ && (pos_in_item != ih_item_len(ih)
+ || tb->insert_size[0] <= 0))
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
+#endif /* CONFIG_REISERFS_CHECK */
+
+ ret_val =
+ leaf_move_items(LEAF_FROM_S_TO_SNEW,
+ tb, snum[i],
+ sbytes[i],
+ S_new[i]);
+
+ RFALSE(ret_val,
+ "PAP-12240: unexpected value returned by leaf_move_items (%d)",
+ ret_val);
+
+ /* paste into item */
+ bi.tb = tb;
+ bi.bi_bh = S_new[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+ leaf_paste_in_buffer(&bi,
+ item_pos - n +
+ snum[i],
+ pos_in_item,
+ tb->insert_size[0],
+ body, zeros_num);
+
+ pasted =
+ B_N_PITEM_HEAD(S_new[i],
+ item_pos - n +
+ snum[i]);
+ if (is_direntry_le_ih(pasted)) {
+ leaf_paste_entries(bi.bi_bh,
+ item_pos -
+ n + snum[i],
+ pos_in_item,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)body,
+ body +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ }
+
+ /* if we paste to indirect item update ih_free_space */
+ if (is_indirect_le_ih(pasted))
+ set_ih_free_space(pasted, 0);
+ zeros_num = tb->insert_size[0] = 0;
+ }
}
- leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0]-n_rem, r_body,r_zeros_number);
- {
- struct item_head * tmp;
-
- tmp = B_N_PITEM_HEAD(S_new[i],0);
- if (is_indirect_le_ih (tmp)) {
- set_ih_free_space (tmp, 0);
- set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) +
- (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT)));
- } else {
- set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) +
- n_rem );
- }
- }
+ else { /* pasted item doesn't fall into S_new[i] */
- tb->insert_size[0] = n_rem;
- if ( ! n_rem )
- pos_in_item++;
- }
+ leaf_move_items(LEAF_FROM_S_TO_SNEW, tb,
+ snum[i], sbytes[i], S_new[i]);
+ }
+ break;
+ default: /* cases d and t */
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)",
+ (flag ==
+ M_DELETE) ? "DELETE" : ((flag ==
+ M_CUT) ? "CUT"
+ : "UNKNOWN"),
+ flag);
}
- else
- /* item falls wholly into S_new[i] */
- {
- int ret_val;
- struct item_head * pasted;
-#ifdef CONFIG_REISERFS_CHECK
- struct item_head * ih = B_N_PITEM_HEAD(tbS0,item_pos);
-
- if ( ! is_direntry_le_ih(ih) && (pos_in_item != ih_item_len(ih) ||
- tb->insert_size[0] <= 0) )
- reiserfs_panic (tb->tb_sb, "PAP-12235: balance_leaf: pos_in_item must be equal to ih_item_len");
-#endif /* CONFIG_REISERFS_CHECK */
-
- ret_val = leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
-
- RFALSE( ret_val,
- "PAP-12240: unexpected value returned by leaf_move_items (%d)",
- ret_val);
-
- /* paste into item */
- bi.tb = tb;
- bi.bi_bh = S_new[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
- leaf_paste_in_buffer(&bi, item_pos - n + snum[i], pos_in_item, tb->insert_size[0], body, zeros_num);
-
- pasted = B_N_PITEM_HEAD(S_new[i], item_pos - n + snum[i]);
- if (is_direntry_le_ih (pasted))
- {
- leaf_paste_entries (
- bi.bi_bh, item_pos - n + snum[i], pos_in_item, 1,
- (struct reiserfs_de_head *)body, body + DEH_SIZE, tb->insert_size[0]
- );
- }
-
- /* if we paste to indirect item update ih_free_space */
- if (is_indirect_le_ih (pasted))
- set_ih_free_space (pasted, 0);
- zeros_num = tb->insert_size[0] = 0;
- }
- }
-
- else /* pasted item doesn't fall into S_new[i] */
- {
- leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i], sbytes[i], S_new[i]);
- }
- break;
- default: /* cases d and t */
- reiserfs_panic (tb->tb_sb, "PAP-12245: balance_leaf: blknum > 2: unexpectable mode: %s(%d)",
- (flag == M_DELETE) ? "DELETE" : ((flag == M_CUT) ? "CUT" : "UNKNOWN"), flag);
+ memcpy(insert_key + i, B_N_PKEY(S_new[i], 0), KEY_SIZE);
+ insert_ptr[i] = S_new[i];
+
+ RFALSE(!buffer_journaled(S_new[i])
+ || buffer_journal_dirty(S_new[i])
+ || buffer_dirty(S_new[i]), "PAP-12247: S_new[%d] : (%b)",
+ i, S_new[i]);
}
- memcpy (insert_key + i,B_N_PKEY(S_new[i],0),KEY_SIZE);
- insert_ptr[i] = S_new[i];
-
- RFALSE (!buffer_journaled (S_new [i]) || buffer_journal_dirty (S_new [i]) ||
- buffer_dirty (S_new [i]),
- "PAP-12247: S_new[%d] : (%b)", i, S_new[i]);
- }
-
- /* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the
- affected item which remains in S */
- if ( 0 <= item_pos && item_pos < tb->s0num )
- { /* if we must insert or append into buffer S[0] */
-
- switch (flag)
- {
- case M_INSERT: /* insert item into S[0] */
- bi.tb = tb;
- bi.bi_bh = tbS0;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
- leaf_insert_into_buf (&bi, item_pos, ih, body, zeros_num);
-
- /* If we insert the first key change the delimiting key */
- if( item_pos == 0 ) {
- if (tb->CFL[0]) /* can be 0 in reiserfsck */
- replace_key(tb, tb->CFL[0], tb->lkey[0],tbS0,0);
-
- }
- break;
-
- case M_PASTE: { /* append item in S[0] */
- struct item_head * pasted;
-
- pasted = B_N_PITEM_HEAD (tbS0, item_pos);
- /* when directory, may be new entry already pasted */
- if (is_direntry_le_ih (pasted)) {
- if ( pos_in_item >= 0 &&
- pos_in_item <= ih_entry_count(pasted) ) {
-
- RFALSE( ! tb->insert_size[0],
- "PAP-12260: insert_size is 0 already");
-
- /* prepare space */
- bi.tb = tb;
- bi.bi_bh = tbS0;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
- leaf_paste_in_buffer(&bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_num);
-
- /* paste entry */
- leaf_paste_entries (
- bi.bi_bh, item_pos, pos_in_item, 1, (struct reiserfs_de_head *)body,
- body + DEH_SIZE, tb->insert_size[0]
- );
- if ( ! item_pos && ! pos_in_item ) {
- RFALSE( !tb->CFL[0] || !tb->L[0],
- "PAP-12270: CFL[0]/L[0] must be specified");
- if (tb->CFL[0]) {
- replace_key(tb, tb->CFL[0], tb->lkey[0],tbS0,0);
+ /* if the affected item was not wholly shifted then we perform all necessary operations on that part or whole of the
+ affected item which remains in S */
+ if (0 <= item_pos && item_pos < tb->s0num) { /* if we must insert or append into buffer S[0] */
+
+ switch (flag) {
+ case M_INSERT: /* insert item into S[0] */
+ bi.tb = tb;
+ bi.bi_bh = tbS0;
+ bi.bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ bi.bi_position = PATH_H_POSITION(tb->tb_path, 1);
+ leaf_insert_into_buf(&bi, item_pos, ih, body,
+ zeros_num);
+
+ /* If we insert the first key change the delimiting key */
+ if (item_pos == 0) {
+ if (tb->CFL[0]) /* can be 0 in reiserfsck */
+ replace_key(tb, tb->CFL[0], tb->lkey[0],
+ tbS0, 0);
}
- }
- tb->insert_size[0] = 0;
- }
- } else { /* regular object */
- if ( pos_in_item == ih_item_len(pasted) ) {
-
- RFALSE( tb->insert_size[0] <= 0,
- "PAP-12275: insert size must not be %d",
- tb->insert_size[0]);
- bi.tb = tb;
- bi.bi_bh = tbS0;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, 1);
- leaf_paste_in_buffer (&bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_num);
-
- if (is_indirect_le_ih (pasted)) {
+ break;
+
+ case M_PASTE:{ /* append item in S[0] */
+ struct item_head *pasted;
+
+ pasted = B_N_PITEM_HEAD(tbS0, item_pos);
+ /* when directory, may be new entry already pasted */
+ if (is_direntry_le_ih(pasted)) {
+ if (pos_in_item >= 0 &&
+ pos_in_item <=
+ ih_entry_count(pasted)) {
+
+ RFALSE(!tb->insert_size[0],
+ "PAP-12260: insert_size is 0 already");
+
+ /* prepare space */
+ bi.tb = tb;
+ bi.bi_bh = tbS0;
+ bi.bi_parent =
+ PATH_H_PPARENT(tb->tb_path,
+ 0);
+ bi.bi_position =
+ PATH_H_POSITION(tb->tb_path,
+ 1);
+ leaf_paste_in_buffer(&bi,
+ item_pos,
+ pos_in_item,
+ tb->
+ insert_size
+ [0], body,
+ zeros_num);
+
+ /* paste entry */
+ leaf_paste_entries(bi.bi_bh,
+ item_pos,
+ pos_in_item,
+ 1,
+ (struct
+ reiserfs_de_head
+ *)body,
+ body +
+ DEH_SIZE,
+ tb->
+ insert_size
+ [0]
+ );
+ if (!item_pos && !pos_in_item) {
+ RFALSE(!tb->CFL[0]
+ || !tb->L[0],
+ "PAP-12270: CFL[0]/L[0] must be specified");
+ if (tb->CFL[0]) {
+ replace_key(tb,
+ tb->
+ CFL
+ [0],
+ tb->
+ lkey
+ [0],
+ tbS0,
+ 0);
+
+ }
+ }
+ tb->insert_size[0] = 0;
+ }
+ } else { /* regular object */
+ if (pos_in_item == ih_item_len(pasted)) {
+
+ RFALSE(tb->insert_size[0] <= 0,
+ "PAP-12275: insert size must not be %d",
+ tb->insert_size[0]);
+ bi.tb = tb;
+ bi.bi_bh = tbS0;
+ bi.bi_parent =
+ PATH_H_PPARENT(tb->tb_path,
+ 0);
+ bi.bi_position =
+ PATH_H_POSITION(tb->tb_path,
+ 1);
+ leaf_paste_in_buffer(&bi,
+ item_pos,
+ pos_in_item,
+ tb->
+ insert_size
+ [0], body,
+ zeros_num);
+
+ if (is_indirect_le_ih(pasted)) {
#if 0
- RFALSE( tb->insert_size[0] != UNFM_P_SIZE,
- "PAP-12280: insert_size for indirect item must be %d, not %d",
- UNFM_P_SIZE, tb->insert_size[0]);
+ RFALSE(tb->
+ insert_size[0] !=
+ UNFM_P_SIZE,
+ "PAP-12280: insert_size for indirect item must be %d, not %d",
+ UNFM_P_SIZE,
+ tb->
+ insert_size[0]);
#endif
- set_ih_free_space (pasted, 0);
- }
- tb->insert_size[0] = 0;
- }
-
+ set_ih_free_space
+ (pasted, 0);
+ }
+ tb->insert_size[0] = 0;
+ }
#ifdef CONFIG_REISERFS_CHECK
- else {
- if ( tb->insert_size[0] ) {
- print_cur_tb ("12285");
- reiserfs_panic (tb->tb_sb, "PAP-12285: balance_leaf: insert_size must be 0 (%d)", tb->insert_size[0]);
- }
+ else {
+ if (tb->insert_size[0]) {
+ print_cur_tb("12285");
+ reiserfs_panic(tb->
+ tb_sb,
+ "PAP-12285: balance_leaf: insert_size must be 0 (%d)",
+ tb->
+ insert_size
+ [0]);
+ }
+ }
+#endif /* CONFIG_REISERFS_CHECK */
+
+ }
+ } /* case M_PASTE: */
}
-#endif /* CONFIG_REISERFS_CHECK */
-
- }
- } /* case M_PASTE: */
}
- }
-
#ifdef CONFIG_REISERFS_CHECK
- if ( flag == M_PASTE && tb->insert_size[0] ) {
- print_cur_tb ("12290");
- reiserfs_panic (tb->tb_sb, "PAP-12290: balance_leaf: insert_size is still not 0 (%d)", tb->insert_size[0]);
- }
-#endif /* CONFIG_REISERFS_CHECK */
-
- return 0;
-} /* Leaf level of the tree is balanced (end of balance_leaf) */
-
+ if (flag == M_PASTE && tb->insert_size[0]) {
+ print_cur_tb("12290");
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12290: balance_leaf: insert_size is still not 0 (%d)",
+ tb->insert_size[0]);
+ }
+#endif /* CONFIG_REISERFS_CHECK */
+ return 0;
+} /* Leaf level of the tree is balanced (end of balance_leaf) */
/* Make empty node */
-void make_empty_node (struct buffer_info * bi)
+void make_empty_node(struct buffer_info *bi)
{
- struct block_head * blkh;
+ struct block_head *blkh;
- RFALSE( bi->bi_bh == NULL, "PAP-12295: pointer to the buffer is NULL");
+ RFALSE(bi->bi_bh == NULL, "PAP-12295: pointer to the buffer is NULL");
- blkh = B_BLK_HEAD(bi->bi_bh);
- set_blkh_nr_item( blkh, 0 );
- set_blkh_free_space( blkh, MAX_CHILD_SIZE(bi->bi_bh) );
+ blkh = B_BLK_HEAD(bi->bi_bh);
+ set_blkh_nr_item(blkh, 0);
+ set_blkh_free_space(blkh, MAX_CHILD_SIZE(bi->bi_bh));
- if (bi->bi_parent)
- B_N_CHILD (bi->bi_parent, bi->bi_position)->dc_size = 0; /* Endian safe if 0 */
+ if (bi->bi_parent)
+ B_N_CHILD(bi->bi_parent, bi->bi_position)->dc_size = 0; /* Endian safe if 0 */
}
-
/* Get first empty buffer */
-struct buffer_head * get_FEB (struct tree_balance * tb)
+struct buffer_head *get_FEB(struct tree_balance *tb)
{
- int i;
- struct buffer_head * first_b;
- struct buffer_info bi;
-
- for (i = 0; i < MAX_FEB_SIZE; i ++)
- if (tb->FEB[i] != 0)
- break;
-
- if (i == MAX_FEB_SIZE)
- reiserfs_panic(tb->tb_sb, "vs-12300: get_FEB: FEB list is empty");
-
- bi.tb = tb;
- bi.bi_bh = first_b = tb->FEB[i];
- bi.bi_parent = NULL;
- bi.bi_position = 0;
- make_empty_node (&bi);
- set_buffer_uptodate(first_b);
- tb->FEB[i] = NULL;
- tb->used[i] = first_b;
-
- return(first_b);
-}
+ int i;
+ struct buffer_head *first_b;
+ struct buffer_info bi;
+ for (i = 0; i < MAX_FEB_SIZE; i++)
+ if (tb->FEB[i] != 0)
+ break;
+
+ if (i == MAX_FEB_SIZE)
+ reiserfs_panic(tb->tb_sb,
+ "vs-12300: get_FEB: FEB list is empty");
+
+ bi.tb = tb;
+ bi.bi_bh = first_b = tb->FEB[i];
+ bi.bi_parent = NULL;
+ bi.bi_position = 0;
+ make_empty_node(&bi);
+ set_buffer_uptodate(first_b);
+ tb->FEB[i] = NULL;
+ tb->used[i] = first_b;
+
+ return (first_b);
+}
/* This is now used because reiserfs_free_block has to be able to
** schedule.
*/
-static void store_thrown (struct tree_balance * tb, struct buffer_head * bh)
+static void store_thrown(struct tree_balance *tb, struct buffer_head *bh)
{
- int i;
-
- if (buffer_dirty (bh))
- reiserfs_warning (tb->tb_sb, "store_thrown deals with dirty buffer");
- for (i = 0; i < sizeof (tb->thrown)/sizeof (tb->thrown[0]); i ++)
- if (!tb->thrown[i]) {
- tb->thrown[i] = bh;
- get_bh(bh) ; /* free_thrown puts this */
- return;
- }
- reiserfs_warning (tb->tb_sb, "store_thrown: too many thrown buffers");
+ int i;
+
+ if (buffer_dirty(bh))
+ reiserfs_warning(tb->tb_sb,
+ "store_thrown deals with dirty buffer");
+ for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++)
+ if (!tb->thrown[i]) {
+ tb->thrown[i] = bh;
+ get_bh(bh); /* free_thrown puts this */
+ return;
+ }
+ reiserfs_warning(tb->tb_sb, "store_thrown: too many thrown buffers");
}
-static void free_thrown(struct tree_balance *tb) {
- int i ;
- b_blocknr_t blocknr ;
- for (i = 0; i < sizeof (tb->thrown)/sizeof (tb->thrown[0]); i++) {
- if (tb->thrown[i]) {
- blocknr = tb->thrown[i]->b_blocknr ;
- if (buffer_dirty (tb->thrown[i]))
- reiserfs_warning (tb->tb_sb,
- "free_thrown deals with dirty buffer %d",
- blocknr);
- brelse(tb->thrown[i]) ; /* incremented in store_thrown */
- reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
+static void free_thrown(struct tree_balance *tb)
+{
+ int i;
+ b_blocknr_t blocknr;
+ for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++) {
+ if (tb->thrown[i]) {
+ blocknr = tb->thrown[i]->b_blocknr;
+ if (buffer_dirty(tb->thrown[i]))
+ reiserfs_warning(tb->tb_sb,
+ "free_thrown deals with dirty buffer %d",
+ blocknr);
+ brelse(tb->thrown[i]); /* incremented in store_thrown */
+ reiserfs_free_block(tb->transaction_handle, NULL,
+ blocknr, 0);
+ }
}
- }
}
-void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh)
+void reiserfs_invalidate_buffer(struct tree_balance *tb, struct buffer_head *bh)
{
- struct block_head *blkh;
- blkh = B_BLK_HEAD(bh);
- set_blkh_level( blkh, FREE_LEVEL );
- set_blkh_nr_item( blkh, 0 );
-
- clear_buffer_dirty(bh);
- store_thrown (tb, bh);
+ struct block_head *blkh;
+ blkh = B_BLK_HEAD(bh);
+ set_blkh_level(blkh, FREE_LEVEL);
+ set_blkh_nr_item(blkh, 0);
+
+ clear_buffer_dirty(bh);
+ store_thrown(tb, bh);
}
/* Replace n_dest'th key in buffer dest by n_src'th key of buffer src.*/
-void replace_key (struct tree_balance * tb, struct buffer_head * dest, int n_dest,
- struct buffer_head * src, int n_src)
+void replace_key(struct tree_balance *tb, struct buffer_head *dest, int n_dest,
+ struct buffer_head *src, int n_src)
{
- RFALSE( dest == NULL || src == NULL,
- "vs-12305: source or destination buffer is 0 (src=%p, dest=%p)",
- src, dest);
- RFALSE( ! B_IS_KEYS_LEVEL (dest),
- "vs-12310: invalid level (%z) for destination buffer. dest must be leaf",
- dest);
- RFALSE( n_dest < 0 || n_src < 0,
- "vs-12315: src(%d) or dest(%d) key number < 0", n_src, n_dest);
- RFALSE( n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src),
- "vs-12320: src(%d(%d)) or dest(%d(%d)) key number is too big",
- n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest));
-
- if (B_IS_ITEMS_LEVEL (src))
- /* source buffer contains leaf node */
- memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PITEM_HEAD(src,n_src), KEY_SIZE);
- else
- memcpy (B_N_PDELIM_KEY(dest,n_dest), B_N_PDELIM_KEY(src,n_src), KEY_SIZE);
-
- do_balance_mark_internal_dirty (tb, dest, 0);
+ RFALSE(dest == NULL || src == NULL,
+ "vs-12305: source or destination buffer is 0 (src=%p, dest=%p)",
+ src, dest);
+ RFALSE(!B_IS_KEYS_LEVEL(dest),
+ "vs-12310: invalid level (%z) for destination buffer. dest must be leaf",
+ dest);
+ RFALSE(n_dest < 0 || n_src < 0,
+ "vs-12315: src(%d) or dest(%d) key number < 0", n_src, n_dest);
+ RFALSE(n_dest >= B_NR_ITEMS(dest) || n_src >= B_NR_ITEMS(src),
+ "vs-12320: src(%d(%d)) or dest(%d(%d)) key number is too big",
+ n_src, B_NR_ITEMS(src), n_dest, B_NR_ITEMS(dest));
+
+ if (B_IS_ITEMS_LEVEL(src))
+ /* source buffer contains leaf node */
+ memcpy(B_N_PDELIM_KEY(dest, n_dest), B_N_PITEM_HEAD(src, n_src),
+ KEY_SIZE);
+ else
+ memcpy(B_N_PDELIM_KEY(dest, n_dest), B_N_PDELIM_KEY(src, n_src),
+ KEY_SIZE);
+
+ do_balance_mark_internal_dirty(tb, dest, 0);
}
-
-int get_left_neighbor_position (
- struct tree_balance * tb,
- int h
- )
+int get_left_neighbor_position(struct tree_balance *tb, int h)
{
- int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1);
+ int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
- RFALSE( PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FL[h] == 0,
- "vs-12325: FL[%d](%p) or F[%d](%p) does not exist",
- h, tb->FL[h], h, PATH_H_PPARENT (tb->tb_path, h));
+ RFALSE(PATH_H_PPARENT(tb->tb_path, h) == 0 || tb->FL[h] == 0,
+ "vs-12325: FL[%d](%p) or F[%d](%p) does not exist",
+ h, tb->FL[h], h, PATH_H_PPARENT(tb->tb_path, h));
- if (Sh_position == 0)
- return B_NR_ITEMS (tb->FL[h]);
- else
- return Sh_position - 1;
+ if (Sh_position == 0)
+ return B_NR_ITEMS(tb->FL[h]);
+ else
+ return Sh_position - 1;
}
-
-int get_right_neighbor_position (struct tree_balance * tb, int h)
+int get_right_neighbor_position(struct tree_balance *tb, int h)
{
- int Sh_position = PATH_H_POSITION (tb->tb_path, h + 1);
+ int Sh_position = PATH_H_POSITION(tb->tb_path, h + 1);
- RFALSE( PATH_H_PPARENT (tb->tb_path, h) == 0 || tb->FR[h] == 0,
- "vs-12330: F[%d](%p) or FR[%d](%p) does not exist",
- h, PATH_H_PPARENT (tb->tb_path, h), h, tb->FR[h]);
+ RFALSE(PATH_H_PPARENT(tb->tb_path, h) == 0 || tb->FR[h] == 0,
+ "vs-12330: F[%d](%p) or FR[%d](%p) does not exist",
+ h, PATH_H_PPARENT(tb->tb_path, h), h, tb->FR[h]);
- if (Sh_position == B_NR_ITEMS (PATH_H_PPARENT (tb->tb_path, h)))
- return 0;
- else
- return Sh_position + 1;
+ if (Sh_position == B_NR_ITEMS(PATH_H_PPARENT(tb->tb_path, h)))
+ return 0;
+ else
+ return Sh_position + 1;
}
-
#ifdef CONFIG_REISERFS_CHECK
-int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
-static void check_internal_node (struct super_block * s, struct buffer_head * bh, char * mes)
+int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
+static void check_internal_node(struct super_block *s, struct buffer_head *bh,
+ char *mes)
{
- struct disk_child * dc;
- int i;
-
- RFALSE( !bh, "PAP-12336: bh == 0");
-
- if (!bh || !B_IS_IN_TREE (bh))
- return;
-
- RFALSE( !buffer_dirty (bh) &&
- !(buffer_journaled(bh) || buffer_journal_dirty(bh)),
- "PAP-12337: buffer (%b) must be dirty", bh);
- dc = B_N_CHILD (bh, 0);
-
- for (i = 0; i <= B_NR_ITEMS (bh); i ++, dc ++) {
- if (!is_reusable (s, dc_block_number(dc), 1) ) {
- print_cur_tb (mes);
- reiserfs_panic (s, "PAP-12338: check_internal_node: invalid child pointer %y in %b", dc, bh);
- }
- }
-}
+ struct disk_child *dc;
+ int i;
+ RFALSE(!bh, "PAP-12336: bh == 0");
-static int locked_or_not_in_tree (struct buffer_head * bh, char * which)
-{
- if ( (!buffer_journal_prepared (bh) && buffer_locked (bh)) ||
- !B_IS_IN_TREE (bh) ) {
- reiserfs_warning (NULL, "vs-12339: locked_or_not_in_tree: %s (%b)",
- which, bh);
- return 1;
- }
- return 0;
-}
+ if (!bh || !B_IS_IN_TREE(bh))
+ return;
+ RFALSE(!buffer_dirty(bh) &&
+ !(buffer_journaled(bh) || buffer_journal_dirty(bh)),
+ "PAP-12337: buffer (%b) must be dirty", bh);
+ dc = B_N_CHILD(bh, 0);
-static int check_before_balancing (struct tree_balance * tb)
-{
- int retval = 0;
-
- if ( cur_tb ) {
- reiserfs_panic (tb->tb_sb, "vs-12335: check_before_balancing: "
- "suspect that schedule occurred based on cur_tb not being null at this point in code. "
- "do_balance cannot properly handle schedule occurring while it runs.");
- }
-
- /* double check that buffers that we will modify are unlocked. (fix_nodes should already have
- prepped all of these for us). */
- if ( tb->lnum[0] ) {
- retval |= locked_or_not_in_tree (tb->L[0], "L[0]");
- retval |= locked_or_not_in_tree (tb->FL[0], "FL[0]");
- retval |= locked_or_not_in_tree (tb->CFL[0], "CFL[0]");
- check_leaf (tb->L[0]);
- }
- if ( tb->rnum[0] ) {
- retval |= locked_or_not_in_tree (tb->R[0], "R[0]");
- retval |= locked_or_not_in_tree (tb->FR[0], "FR[0]");
- retval |= locked_or_not_in_tree (tb->CFR[0], "CFR[0]");
- check_leaf (tb->R[0]);
- }
- retval |= locked_or_not_in_tree (PATH_PLAST_BUFFER (tb->tb_path), "S[0]");
- check_leaf (PATH_PLAST_BUFFER (tb->tb_path));
-
- return retval;
+ for (i = 0; i <= B_NR_ITEMS(bh); i++, dc++) {
+ if (!is_reusable(s, dc_block_number(dc), 1)) {
+ print_cur_tb(mes);
+ reiserfs_panic(s,
+ "PAP-12338: check_internal_node: invalid child pointer %y in %b",
+ dc, bh);
+ }
+ }
}
+static int locked_or_not_in_tree(struct buffer_head *bh, char *which)
+{
+ if ((!buffer_journal_prepared(bh) && buffer_locked(bh)) ||
+ !B_IS_IN_TREE(bh)) {
+ reiserfs_warning(NULL,
+ "vs-12339: locked_or_not_in_tree: %s (%b)",
+ which, bh);
+ return 1;
+ }
+ return 0;
+}
-static void check_after_balance_leaf (struct tree_balance * tb)
+static int check_before_balancing(struct tree_balance *tb)
{
- if (tb->lnum[0]) {
- if (B_FREE_SPACE (tb->L[0]) !=
- MAX_CHILD_SIZE (tb->L[0]) - dc_size(B_N_CHILD (tb->FL[0], get_left_neighbor_position (tb, 0)))) {
- print_cur_tb ("12221");
- reiserfs_panic (tb->tb_sb, "PAP-12355: check_after_balance_leaf: shift to left was incorrect");
+ int retval = 0;
+
+ if (cur_tb) {
+ reiserfs_panic(tb->tb_sb, "vs-12335: check_before_balancing: "
+ "suspect that schedule occurred based on cur_tb not being null at this point in code. "
+ "do_balance cannot properly handle schedule occurring while it runs.");
}
- }
- if (tb->rnum[0]) {
- if (B_FREE_SPACE (tb->R[0]) !=
- MAX_CHILD_SIZE (tb->R[0]) - dc_size(B_N_CHILD (tb->FR[0], get_right_neighbor_position (tb, 0)))) {
- print_cur_tb ("12222");
- reiserfs_panic (tb->tb_sb, "PAP-12360: check_after_balance_leaf: shift to right was incorrect");
+
+ /* double check that buffers that we will modify are unlocked. (fix_nodes should already have
+ prepped all of these for us). */
+ if (tb->lnum[0]) {
+ retval |= locked_or_not_in_tree(tb->L[0], "L[0]");
+ retval |= locked_or_not_in_tree(tb->FL[0], "FL[0]");
+ retval |= locked_or_not_in_tree(tb->CFL[0], "CFL[0]");
+ check_leaf(tb->L[0]);
}
- }
- if (PATH_H_PBUFFER(tb->tb_path,1) &&
- (B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) !=
- (MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
- dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1),
- PATH_H_POSITION (tb->tb_path, 1)))) )) {
- int left = B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0));
- int right = (MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)) -
- dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1),
- PATH_H_POSITION (tb->tb_path, 1))));
- print_cur_tb ("12223");
- reiserfs_warning (tb->tb_sb,
- "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
- "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d",
- left,
- MAX_CHILD_SIZE (PATH_H_PBUFFER(tb->tb_path,0)),
- PATH_H_PBUFFER(tb->tb_path,1),
- PATH_H_POSITION (tb->tb_path, 1),
- dc_size(B_N_CHILD (PATH_H_PBUFFER(tb->tb_path,1), PATH_H_POSITION (tb->tb_path, 1 )) ),
- right );
- reiserfs_panic (tb->tb_sb, "PAP-12365: check_after_balance_leaf: S is incorrect");
- }
-}
+ if (tb->rnum[0]) {
+ retval |= locked_or_not_in_tree(tb->R[0], "R[0]");
+ retval |= locked_or_not_in_tree(tb->FR[0], "FR[0]");
+ retval |= locked_or_not_in_tree(tb->CFR[0], "CFR[0]");
+ check_leaf(tb->R[0]);
+ }
+ retval |= locked_or_not_in_tree(PATH_PLAST_BUFFER(tb->tb_path), "S[0]");
+ check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
+ return retval;
+}
-static void check_leaf_level (struct tree_balance * tb)
+static void check_after_balance_leaf(struct tree_balance *tb)
{
- check_leaf (tb->L[0]);
- check_leaf (tb->R[0]);
- check_leaf (PATH_PLAST_BUFFER (tb->tb_path));
+ if (tb->lnum[0]) {
+ if (B_FREE_SPACE(tb->L[0]) !=
+ MAX_CHILD_SIZE(tb->L[0]) -
+ dc_size(B_N_CHILD
+ (tb->FL[0], get_left_neighbor_position(tb, 0)))) {
+ print_cur_tb("12221");
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12355: check_after_balance_leaf: shift to left was incorrect");
+ }
+ }
+ if (tb->rnum[0]) {
+ if (B_FREE_SPACE(tb->R[0]) !=
+ MAX_CHILD_SIZE(tb->R[0]) -
+ dc_size(B_N_CHILD
+ (tb->FR[0], get_right_neighbor_position(tb, 0)))) {
+ print_cur_tb("12222");
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12360: check_after_balance_leaf: shift to right was incorrect");
+ }
+ }
+ if (PATH_H_PBUFFER(tb->tb_path, 1) &&
+ (B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0)) !=
+ (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
+ dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
+ PATH_H_POSITION(tb->tb_path, 1)))))) {
+ int left = B_FREE_SPACE(PATH_H_PBUFFER(tb->tb_path, 0));
+ int right = (MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)) -
+ dc_size(B_N_CHILD(PATH_H_PBUFFER(tb->tb_path, 1),
+ PATH_H_POSITION(tb->tb_path,
+ 1))));
+ print_cur_tb("12223");
+ reiserfs_warning(tb->tb_sb,
+ "B_FREE_SPACE (PATH_H_PBUFFER(tb->tb_path,0)) = %d; "
+ "MAX_CHILD_SIZE (%d) - dc_size( %y, %d ) [%d] = %d",
+ left,
+ MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, 0)),
+ PATH_H_PBUFFER(tb->tb_path, 1),
+ PATH_H_POSITION(tb->tb_path, 1),
+ dc_size(B_N_CHILD
+ (PATH_H_PBUFFER(tb->tb_path, 1),
+ PATH_H_POSITION(tb->tb_path, 1))),
+ right);
+ reiserfs_panic(tb->tb_sb,
+ "PAP-12365: check_after_balance_leaf: S is incorrect");
+ }
}
-static void check_internal_levels (struct tree_balance * tb)
+static void check_leaf_level(struct tree_balance *tb)
{
- int h;
+ check_leaf(tb->L[0]);
+ check_leaf(tb->R[0]);
+ check_leaf(PATH_PLAST_BUFFER(tb->tb_path));
+}
- /* check all internal nodes */
- for (h = 1; tb->insert_size[h]; h ++) {
- check_internal_node (tb->tb_sb, PATH_H_PBUFFER (tb->tb_path, h), "BAD BUFFER ON PATH");
- if (tb->lnum[h])
- check_internal_node (tb->tb_sb, tb->L[h], "BAD L");
- if (tb->rnum[h])
- check_internal_node (tb->tb_sb, tb->R[h], "BAD R");
- }
+static void check_internal_levels(struct tree_balance *tb)
+{
+ int h;
+
+ /* check all internal nodes */
+ for (h = 1; tb->insert_size[h]; h++) {
+ check_internal_node(tb->tb_sb, PATH_H_PBUFFER(tb->tb_path, h),
+ "BAD BUFFER ON PATH");
+ if (tb->lnum[h])
+ check_internal_node(tb->tb_sb, tb->L[h], "BAD L");
+ if (tb->rnum[h])
+ check_internal_node(tb->tb_sb, tb->R[h], "BAD R");
+ }
}
#endif
-
-
-
-
-
/* Now we have all of the buffers that must be used in balancing of
the tree. We rely on the assumption that schedule() will not occur
while do_balance works. ( Only interrupt handlers are acceptable.)
@@ -1484,114 +2029,109 @@ static void check_internal_levels (struct tree_balance * tb)
*/
-static inline void do_balance_starts (struct tree_balance *tb)
+static inline void do_balance_starts(struct tree_balance *tb)
{
- /* use print_cur_tb() to see initial state of struct
- tree_balance */
+ /* use print_cur_tb() to see initial state of struct
+ tree_balance */
- /* store_print_tb (tb); */
+ /* store_print_tb (tb); */
- /* do not delete, just comment it out */
+ /* do not delete, just comment it out */
/* print_tb(flag, PATH_LAST_POSITION(tb->tb_path), tb->tb_path->pos_in_item, tb,
"check");*/
- RFALSE( check_before_balancing (tb), "PAP-12340: locked buffers in TB");
+ RFALSE(check_before_balancing(tb), "PAP-12340: locked buffers in TB");
#ifdef CONFIG_REISERFS_CHECK
- cur_tb = tb;
+ cur_tb = tb;
#endif
}
-
-static inline void do_balance_completed (struct tree_balance * tb)
+static inline void do_balance_completed(struct tree_balance *tb)
{
-
+
#ifdef CONFIG_REISERFS_CHECK
- check_leaf_level (tb);
- check_internal_levels (tb);
- cur_tb = NULL;
+ check_leaf_level(tb);
+ check_internal_levels(tb);
+ cur_tb = NULL;
#endif
- /* reiserfs_free_block is no longer schedule safe. So, we need to
- ** put the buffers we want freed on the thrown list during do_balance,
- ** and then free them now
- */
-
- REISERFS_SB(tb->tb_sb)->s_do_balance ++;
+ /* reiserfs_free_block is no longer schedule safe. So, we need to
+ ** put the buffers we want freed on the thrown list during do_balance,
+ ** and then free them now
+ */
+ REISERFS_SB(tb->tb_sb)->s_do_balance++;
- /* release all nodes hold to perform the balancing */
- unfix_nodes(tb);
+ /* release all nodes hold to perform the balancing */
+ unfix_nodes(tb);
- free_thrown(tb) ;
+ free_thrown(tb);
}
+void do_balance(struct tree_balance *tb, /* tree_balance structure */
+ struct item_head *ih, /* item header of inserted item */
+ const char *body, /* body of inserted item or bytes to paste */
+ int flag)
+{ /* i - insert, d - delete
+ c - cut, p - paste
+
+ Cut means delete part of an item
+ (includes removing an entry from a
+ directory).
+
+ Delete means delete whole item.
+
+ Insert means add a new item into the
+ tree.
+
+ Paste means to append to the end of an
+ existing file or to insert a directory
+ entry. */
+ int child_pos, /* position of a child node in its parent */
+ h; /* level of the tree being processed */
+ struct item_head insert_key[2]; /* in our processing of one level
+ we sometimes determine what
+ must be inserted into the next
+ higher level. This insertion
+ consists of a key or two keys
+ and their corresponding
+ pointers */
+ struct buffer_head *insert_ptr[2]; /* inserted node-ptrs for the next
+ level */
+
+ tb->tb_mode = flag;
+ tb->need_balance_dirty = 0;
+
+ if (FILESYSTEM_CHANGED_TB(tb)) {
+ reiserfs_panic(tb->tb_sb,
+ "clm-6000: do_balance, fs generation has changed\n");
+ }
+ /* if we have no real work to do */
+ if (!tb->insert_size[0]) {
+ reiserfs_warning(tb->tb_sb,
+ "PAP-12350: do_balance: insert_size == 0, mode == %c",
+ flag);
+ unfix_nodes(tb);
+ return;
+ }
+ atomic_inc(&(fs_generation(tb->tb_sb)));
+ do_balance_starts(tb);
-
-
-void do_balance (struct tree_balance * tb, /* tree_balance structure */
- struct item_head * ih, /* item header of inserted item */
- const char * body, /* body of inserted item or bytes to paste */
- int flag) /* i - insert, d - delete
- c - cut, p - paste
-
- Cut means delete part of an item
- (includes removing an entry from a
- directory).
-
- Delete means delete whole item.
-
- Insert means add a new item into the
- tree.
-
- Paste means to append to the end of an
- existing file or to insert a directory
- entry. */
-{
- int child_pos, /* position of a child node in its parent */
- h; /* level of the tree being processed */
- struct item_head insert_key[2]; /* in our processing of one level
- we sometimes determine what
- must be inserted into the next
- higher level. This insertion
- consists of a key or two keys
- and their corresponding
- pointers */
- struct buffer_head *insert_ptr[2]; /* inserted node-ptrs for the next
- level */
-
- tb->tb_mode = flag;
- tb->need_balance_dirty = 0;
-
- if (FILESYSTEM_CHANGED_TB(tb)) {
- reiserfs_panic(tb->tb_sb, "clm-6000: do_balance, fs generation has changed\n") ;
- }
- /* if we have no real work to do */
- if ( ! tb->insert_size[0] ) {
- reiserfs_warning (tb->tb_sb,
- "PAP-12350: do_balance: insert_size == 0, mode == %c",
- flag);
- unfix_nodes(tb);
- return;
- }
-
- atomic_inc (&(fs_generation (tb->tb_sb)));
- do_balance_starts (tb);
-
/* balance leaf returns 0 except if combining L R and S into
one node. see balance_internal() for explanation of this
- line of code.*/
- child_pos = PATH_H_B_ITEM_ORDER (tb->tb_path, 0) +
- balance_leaf (tb, ih, body, flag, insert_key, insert_ptr);
+ line of code. */
+ child_pos = PATH_H_B_ITEM_ORDER(tb->tb_path, 0) +
+ balance_leaf(tb, ih, body, flag, insert_key, insert_ptr);
#ifdef CONFIG_REISERFS_CHECK
- check_after_balance_leaf (tb);
+ check_after_balance_leaf(tb);
#endif
- /* Balance internal level of the tree. */
- for ( h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++ )
- child_pos = balance_internal (tb, h, child_pos, insert_key, insert_ptr);
-
+ /* Balance internal level of the tree. */
+ for (h = 1; h < MAX_HEIGHT && tb->insert_size[h]; h++)
+ child_pos =
+ balance_internal(tb, h, child_pos, insert_key, insert_ptr);
- do_balance_completed (tb);
+ do_balance_completed(tb);
}
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 2230afff1870..c9f178fb494f 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -2,7 +2,6 @@
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
-
#include <linux/time.h>
#include <linux/reiserfs_fs.h>
#include <linux/reiserfs_acl.h>
@@ -31,82 +30,84 @@
** We use reiserfs_truncate_file to pack the tail, since it already has
** all the conditions coded.
*/
-static int reiserfs_file_release (struct inode * inode, struct file * filp)
+static int reiserfs_file_release(struct inode *inode, struct file *filp)
{
- struct reiserfs_transaction_handle th ;
- int err;
- int jbegin_failure = 0;
+ struct reiserfs_transaction_handle th;
+ int err;
+ int jbegin_failure = 0;
- if (!S_ISREG (inode->i_mode))
- BUG ();
+ if (!S_ISREG(inode->i_mode))
+ BUG();
- /* fast out for when nothing needs to be done */
- if ((atomic_read(&inode->i_count) > 1 ||
- !(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) ||
- !tail_has_to_be_packed(inode)) &&
- REISERFS_I(inode)->i_prealloc_count <= 0) {
- return 0;
- }
-
- reiserfs_write_lock(inode->i_sb);
- down (&inode->i_sem);
- /* freeing preallocation only involves relogging blocks that
- * are already in the current transaction. preallocation gets
- * freed at the end of each transaction, so it is impossible for
- * us to log any additional blocks (including quota blocks)
- */
- err = journal_begin(&th, inode->i_sb, 1);
- if (err) {
- /* uh oh, we can't allow the inode to go away while there
- * is still preallocation blocks pending. Try to join the
- * aborted transaction
- */
- jbegin_failure = err;
- err = journal_join_abort(&th, inode->i_sb, 1);
+ /* fast out for when nothing needs to be done */
+ if ((atomic_read(&inode->i_count) > 1 ||
+ !(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) ||
+ !tail_has_to_be_packed(inode)) &&
+ REISERFS_I(inode)->i_prealloc_count <= 0) {
+ return 0;
+ }
+ reiserfs_write_lock(inode->i_sb);
+ down(&inode->i_sem);
+ /* freeing preallocation only involves relogging blocks that
+ * are already in the current transaction. preallocation gets
+ * freed at the end of each transaction, so it is impossible for
+ * us to log any additional blocks (including quota blocks)
+ */
+ err = journal_begin(&th, inode->i_sb, 1);
if (err) {
- /* hmpf, our choices here aren't good. We can pin the inode
- * which will disallow unmount from every happening, we can
- * do nothing, which will corrupt random memory on unmount,
- * or we can forcibly remove the file from the preallocation
- * list, which will leak blocks on disk. Lets pin the inode
- * and let the admin know what is going on.
- */
- igrab(inode);
- reiserfs_warning(inode->i_sb, "pinning inode %lu because the "
- "preallocation can't be freed");
- goto out;
+ /* uh oh, we can't allow the inode to go away while there
+ * is still preallocation blocks pending. Try to join the
+ * aborted transaction
+ */
+ jbegin_failure = err;
+ err = journal_join_abort(&th, inode->i_sb, 1);
+
+ if (err) {
+ /* hmpf, our choices here aren't good. We can pin the inode
+ * which will disallow unmount from every happening, we can
+ * do nothing, which will corrupt random memory on unmount,
+ * or we can forcibly remove the file from the preallocation
+ * list, which will leak blocks on disk. Lets pin the inode
+ * and let the admin know what is going on.
+ */
+ igrab(inode);
+ reiserfs_warning(inode->i_sb,
+ "pinning inode %lu because the "
+ "preallocation can't be freed");
+ goto out;
+ }
}
- }
- reiserfs_update_inode_transaction(inode) ;
+ reiserfs_update_inode_transaction(inode);
#ifdef REISERFS_PREALLOCATE
- reiserfs_discard_prealloc (&th, inode);
+ reiserfs_discard_prealloc(&th, inode);
#endif
- err = journal_end(&th, inode->i_sb, 1);
-
- /* copy back the error code from journal_begin */
- if (!err)
- err = jbegin_failure;
-
- if (!err && atomic_read(&inode->i_count) <= 1 &&
- (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) &&
- tail_has_to_be_packed (inode)) {
- /* if regular file is released by last holder and it has been
- appended (we append by unformatted node only) or its direct
- item(s) had to be converted, then it may have to be
- indirect2direct converted */
- err = reiserfs_truncate_file(inode, 0) ;
- }
-out:
- up (&inode->i_sem);
- reiserfs_write_unlock(inode->i_sb);
- return err;
+ err = journal_end(&th, inode->i_sb, 1);
+
+ /* copy back the error code from journal_begin */
+ if (!err)
+ err = jbegin_failure;
+
+ if (!err && atomic_read(&inode->i_count) <= 1 &&
+ (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) &&
+ tail_has_to_be_packed(inode)) {
+ /* if regular file is released by last holder and it has been
+ appended (we append by unformatted node only) or its direct
+ item(s) had to be converted, then it may have to be
+ indirect2direct converted */
+ err = reiserfs_truncate_file(inode, 0);
+ }
+ out:
+ up(&inode->i_sem);
+ reiserfs_write_unlock(inode->i_sb);
+ return err;
}
-static void reiserfs_vfs_truncate_file(struct inode *inode) {
- reiserfs_truncate_file(inode, 1) ;
+static void reiserfs_vfs_truncate_file(struct inode *inode)
+{
+ reiserfs_truncate_file(inode, 1);
}
/* Sync a reiserfs file. */
@@ -116,26 +117,24 @@ static void reiserfs_vfs_truncate_file(struct inode *inode) {
* be removed...
*/
-static int reiserfs_sync_file(
- struct file * p_s_filp,
- struct dentry * p_s_dentry,
- int datasync
- ) {
- struct inode * p_s_inode = p_s_dentry->d_inode;
- int n_err;
- int barrier_done;
-
- if (!S_ISREG(p_s_inode->i_mode))
- BUG ();
- n_err = sync_mapping_buffers(p_s_inode->i_mapping) ;
- reiserfs_write_lock(p_s_inode->i_sb);
- barrier_done = reiserfs_commit_for_inode(p_s_inode);
- reiserfs_write_unlock(p_s_inode->i_sb);
- if (barrier_done != 1)
- blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
- if (barrier_done < 0)
- return barrier_done;
- return ( n_err < 0 ) ? -EIO : 0;
+static int reiserfs_sync_file(struct file *p_s_filp,
+ struct dentry *p_s_dentry, int datasync)
+{
+ struct inode *p_s_inode = p_s_dentry->d_inode;
+ int n_err;
+ int barrier_done;
+
+ if (!S_ISREG(p_s_inode->i_mode))
+ BUG();
+ n_err = sync_mapping_buffers(p_s_inode->i_mapping);
+ reiserfs_write_lock(p_s_inode->i_sb);
+ barrier_done = reiserfs_commit_for_inode(p_s_inode);
+ reiserfs_write_unlock(p_s_inode->i_sb);
+ if (barrier_done != 1)
+ blkdev_issue_flush(p_s_inode->i_sb->s_bdev, NULL);
+ if (barrier_done < 0)
+ return barrier_done;
+ return (n_err < 0) ? -EIO : 0;
}
/* I really do not want to play with memory shortage right now, so
@@ -147,700 +146,797 @@ static int reiserfs_sync_file(
/* Allocates blocks for a file to fulfil write request.
Maps all unmapped but prepared pages from the list.
Updates metadata with newly allocated blocknumbers as needed */
-static int reiserfs_allocate_blocks_for_region(
- struct reiserfs_transaction_handle *th,
- struct inode *inode, /* Inode we work with */
- loff_t pos, /* Writing position */
- int num_pages, /* number of pages write going
- to touch */
- int write_bytes, /* amount of bytes to write */
- struct page **prepared_pages, /* array of
- prepared pages
- */
- int blocks_to_allocate /* Amount of blocks we
- need to allocate to
- fit the data into file
- */
- )
+static int reiserfs_allocate_blocks_for_region(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode we work with */
+ loff_t pos, /* Writing position */
+ int num_pages, /* number of pages write going
+ to touch */
+ int write_bytes, /* amount of bytes to write */
+ struct page **prepared_pages, /* array of
+ prepared pages
+ */
+ int blocks_to_allocate /* Amount of blocks we
+ need to allocate to
+ fit the data into file
+ */
+ )
{
- struct cpu_key key; // cpu key of item that we are going to deal with
- struct item_head *ih; // pointer to item head that we are going to deal with
- struct buffer_head *bh; // Buffer head that contains items that we are going to deal with
- __le32 * item; // pointer to item we are going to deal with
- INITIALIZE_PATH(path); // path to item, that we are going to deal with.
- b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored.
- reiserfs_blocknr_hint_t hint; // hint structure for block allocator.
- size_t res; // return value of various functions that we call.
- int curr_block; // current block used to keep track of unmapped blocks.
- int i; // loop counter
- int itempos; // position in item
- unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in
- // first page
- unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */
- __u64 hole_size ; // amount of blocks for a file hole, if it needed to be created.
- int modifying_this_item = 0; // Flag for items traversal code to keep track
- // of the fact that we already prepared
- // current block for journal
- int will_prealloc = 0;
- RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?");
-
- /* only preallocate if this is a small write */
- if (REISERFS_I(inode)->i_prealloc_count ||
- (!(write_bytes & (inode->i_sb->s_blocksize -1)) &&
- blocks_to_allocate <
- REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize))
- will_prealloc = REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize;
-
- allocated_blocks = kmalloc((blocks_to_allocate + will_prealloc) *
- sizeof(b_blocknr_t), GFP_NOFS);
-
- /* First we compose a key to point at the writing position, we want to do
- that outside of any locking region. */
- make_cpu_key (&key, inode, pos+1, TYPE_ANY, 3/*key length*/);
-
- /* If we came here, it means we absolutely need to open a transaction,
- since we need to allocate some blocks */
- reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
- res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS); // Wish I know if this number enough
- if (res)
- goto error_exit;
- reiserfs_update_inode_transaction(inode) ;
-
- /* Look for the in-tree position of our write, need path for block allocator */
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- res = -EIO;
- goto error_exit;
- }
-
- /* Allocate blocks */
- /* First fill in "hint" structure for block allocator */
- hint.th = th; // transaction handle.
- hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine.
- hint.inode = inode; // Inode is needed by block allocator too.
- hint.search_start = 0; // We have no hint on where to search free blocks for block allocator.
- hint.key = key.on_disk_key; // on disk key of file.
- hint.block = inode->i_blocks>>(inode->i_sb->s_blocksize_bits-9); // Number of disk blocks this file occupies already.
- hint.formatted_node = 0; // We are allocating blocks for unformatted node.
- hint.preallocate = will_prealloc;
-
- /* Call block allocator to allocate blocks */
- res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
- if ( res != CARRY_ON ) {
- if ( res == NO_DISK_SPACE ) {
- /* We flush the transaction in case of no space. This way some
- blocks might become free */
- SB_JOURNAL(inode->i_sb)->j_must_wait = 1;
- res = restart_transaction(th, inode, &path);
- if (res)
- goto error_exit;
-
- /* We might have scheduled, so search again */
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- res = -EIO;
+ struct cpu_key key; // cpu key of item that we are going to deal with
+ struct item_head *ih; // pointer to item head that we are going to deal with
+ struct buffer_head *bh; // Buffer head that contains items that we are going to deal with
+ __le32 *item; // pointer to item we are going to deal with
+ INITIALIZE_PATH(path); // path to item, that we are going to deal with.
+ b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored.
+ reiserfs_blocknr_hint_t hint; // hint structure for block allocator.
+ size_t res; // return value of various functions that we call.
+ int curr_block; // current block used to keep track of unmapped blocks.
+ int i; // loop counter
+ int itempos; // position in item
+ unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in
+ // first page
+ unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */
+ __u64 hole_size; // amount of blocks for a file hole, if it needed to be created.
+ int modifying_this_item = 0; // Flag for items traversal code to keep track
+ // of the fact that we already prepared
+ // current block for journal
+ int will_prealloc = 0;
+ RFALSE(!blocks_to_allocate,
+ "green-9004: tried to allocate zero blocks?");
+
+ /* only preallocate if this is a small write */
+ if (REISERFS_I(inode)->i_prealloc_count ||
+ (!(write_bytes & (inode->i_sb->s_blocksize - 1)) &&
+ blocks_to_allocate <
+ REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize))
+ will_prealloc =
+ REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize;
+
+ allocated_blocks = kmalloc((blocks_to_allocate + will_prealloc) *
+ sizeof(b_blocknr_t), GFP_NOFS);
+
+ /* First we compose a key to point at the writing position, we want to do
+ that outside of any locking region. */
+ make_cpu_key(&key, inode, pos + 1, TYPE_ANY, 3 /*key length */ );
+
+ /* If we came here, it means we absolutely need to open a transaction,
+ since we need to allocate some blocks */
+ reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
+ res = journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb)); // Wish I know if this number enough
+ if (res)
goto error_exit;
- }
+ reiserfs_update_inode_transaction(inode);
- /* update changed info for hint structure. */
- res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
- if ( res != CARRY_ON ) {
- res = -ENOSPC;
- pathrelse(&path);
+ /* Look for the in-tree position of our write, need path for block allocator */
+ res = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
goto error_exit;
- }
- } else {
- res = -ENOSPC;
- pathrelse(&path);
- goto error_exit;
}
- }
-#ifdef __BIG_ENDIAN
- // Too bad, I have not found any way to convert a given region from
- // cpu format to little endian format
- {
- int i;
- for ( i = 0; i < blocks_to_allocate ; i++)
- allocated_blocks[i]=cpu_to_le32(allocated_blocks[i]);
- }
-#endif
-
- /* Blocks allocating well might have scheduled and tree might have changed,
- let's search the tree again */
- /* find where in the tree our write should go */
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- res = -EIO;
- goto error_exit_free_blocks;
- }
-
- bh = get_last_bh( &path ); // Get a bufferhead for last element in path.
- ih = get_ih( &path ); // Get a pointer to last item head in path.
- item = get_item( &path ); // Get a pointer to last item in path
-
- /* Let's see what we have found */
- if ( res != POSITION_FOUND ) { /* position not found, this means that we
- might need to append file with holes
- first */
- // Since we are writing past the file's end, we need to find out if
- // there is a hole that needs to be inserted before our writing
- // position, and how many blocks it is going to cover (we need to
- // populate pointers to file blocks representing the hole with zeros)
+ /* Allocate blocks */
+ /* First fill in "hint" structure for block allocator */
+ hint.th = th; // transaction handle.
+ hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine.
+ hint.inode = inode; // Inode is needed by block allocator too.
+ hint.search_start = 0; // We have no hint on where to search free blocks for block allocator.
+ hint.key = key.on_disk_key; // on disk key of file.
+ hint.block = inode->i_blocks >> (inode->i_sb->s_blocksize_bits - 9); // Number of disk blocks this file occupies already.
+ hint.formatted_node = 0; // We are allocating blocks for unformatted node.
+ hint.preallocate = will_prealloc;
+
+ /* Call block allocator to allocate blocks */
+ res =
+ reiserfs_allocate_blocknrs(&hint, allocated_blocks,
+ blocks_to_allocate, blocks_to_allocate);
+ if (res != CARRY_ON) {
+ if (res == NO_DISK_SPACE) {
+ /* We flush the transaction in case of no space. This way some
+ blocks might become free */
+ SB_JOURNAL(inode->i_sb)->j_must_wait = 1;
+ res = restart_transaction(th, inode, &path);
+ if (res)
+ goto error_exit;
+
+ /* We might have scheduled, so search again */
+ res =
+ search_for_position_by_key(inode->i_sb, &key,
+ &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
+ goto error_exit;
+ }
+ /* update changed info for hint structure. */
+ res =
+ reiserfs_allocate_blocknrs(&hint, allocated_blocks,
+ blocks_to_allocate,
+ blocks_to_allocate);
+ if (res != CARRY_ON) {
+ res = -ENOSPC;
+ pathrelse(&path);
+ goto error_exit;
+ }
+ } else {
+ res = -ENOSPC;
+ pathrelse(&path);
+ goto error_exit;
+ }
+ }
+#ifdef __BIG_ENDIAN
+ // Too bad, I have not found any way to convert a given region from
+ // cpu format to little endian format
{
- int item_offset = 1;
- /*
- * if ih is stat data, its offset is 0 and we don't want to
- * add 1 to pos in the hole_size calculation
- */
- if (is_statdata_le_ih(ih))
- item_offset = 0;
- hole_size = (pos + item_offset -
- (le_key_k_offset( get_inode_item_key_version(inode),
- &(ih->ih_key)) +
- op_bytes_number(ih, inode->i_sb->s_blocksize))) >>
- inode->i_sb->s_blocksize_bits;
+ int i;
+ for (i = 0; i < blocks_to_allocate; i++)
+ allocated_blocks[i] = cpu_to_le32(allocated_blocks[i]);
}
+#endif
- if ( hole_size > 0 ) {
- int to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE ); // How much data to insert first time.
- /* area filled with zeroes, to supply as list of zero blocknumbers
- We allocate it outside of loop just in case loop would spin for
- several iterations. */
- char *zeros = kmalloc(to_paste*UNFM_P_SIZE, GFP_ATOMIC); // We cannot insert more than MAX_ITEM_LEN bytes anyway.
- if ( !zeros ) {
- res = -ENOMEM;
+ /* Blocks allocating well might have scheduled and tree might have changed,
+ let's search the tree again */
+ /* find where in the tree our write should go */
+ res = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
goto error_exit_free_blocks;
- }
- memset ( zeros, 0, to_paste*UNFM_P_SIZE);
- do {
- to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE );
- if ( is_indirect_le_ih(ih) ) {
- /* Ok, there is existing indirect item already. Need to append it */
- /* Calculate position past inserted item */
- make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
- res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)zeros, UNFM_P_SIZE*to_paste);
- if ( res ) {
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- } else if ( is_statdata_le_ih(ih) ) {
- /* No existing item, create it */
- /* item head for new item */
- struct item_head ins_ih;
-
- /* create a key for our new item */
- make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3);
-
- /* Create new item head for our new item */
- make_le_item_head (&ins_ih, &key, key.version, 1,
- TYPE_INDIRECT, to_paste*UNFM_P_SIZE,
- 0 /* free space */);
-
- /* Find where such item should live in the tree */
- res = search_item (inode->i_sb, &key, &path);
- if ( res != ITEM_NOT_FOUND ) {
- /* item should not exist, otherwise we have error */
- if ( res != -ENOSPC ) {
- reiserfs_warning (inode->i_sb,
- "green-9008: search_by_key (%K) returned %d",
- &key, res);
+ }
+
+ bh = get_last_bh(&path); // Get a bufferhead for last element in path.
+ ih = get_ih(&path); // Get a pointer to last item head in path.
+ item = get_item(&path); // Get a pointer to last item in path
+
+ /* Let's see what we have found */
+ if (res != POSITION_FOUND) { /* position not found, this means that we
+ might need to append file with holes
+ first */
+ // Since we are writing past the file's end, we need to find out if
+ // there is a hole that needs to be inserted before our writing
+ // position, and how many blocks it is going to cover (we need to
+ // populate pointers to file blocks representing the hole with zeros)
+
+ {
+ int item_offset = 1;
+ /*
+ * if ih is stat data, its offset is 0 and we don't want to
+ * add 1 to pos in the hole_size calculation
+ */
+ if (is_statdata_le_ih(ih))
+ item_offset = 0;
+ hole_size = (pos + item_offset -
+ (le_key_k_offset
+ (get_inode_item_key_version(inode),
+ &(ih->ih_key)) + op_bytes_number(ih,
+ inode->
+ i_sb->
+ s_blocksize)))
+ >> inode->i_sb->s_blocksize_bits;
+ }
+
+ if (hole_size > 0) {
+ int to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize) / UNFM_P_SIZE); // How much data to insert first time.
+ /* area filled with zeroes, to supply as list of zero blocknumbers
+ We allocate it outside of loop just in case loop would spin for
+ several iterations. */
+ char *zeros = kmalloc(to_paste * UNFM_P_SIZE, GFP_ATOMIC); // We cannot insert more than MAX_ITEM_LEN bytes anyway.
+ if (!zeros) {
+ res = -ENOMEM;
+ goto error_exit_free_blocks;
}
- res = -EIO;
- kfree(zeros);
- goto error_exit_free_blocks;
- }
- res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)zeros);
- } else {
- reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key);
+ memset(zeros, 0, to_paste * UNFM_P_SIZE);
+ do {
+ to_paste =
+ min_t(__u64, hole_size,
+ MAX_ITEM_LEN(inode->i_sb->
+ s_blocksize) /
+ UNFM_P_SIZE);
+ if (is_indirect_le_ih(ih)) {
+ /* Ok, there is existing indirect item already. Need to append it */
+ /* Calculate position past inserted item */
+ make_cpu_key(&key, inode,
+ le_key_k_offset
+ (get_inode_item_key_version
+ (inode),
+ &(ih->ih_key)) +
+ op_bytes_number(ih,
+ inode->
+ i_sb->
+ s_blocksize),
+ TYPE_INDIRECT, 3);
+ res =
+ reiserfs_paste_into_item(th, &path,
+ &key,
+ inode,
+ (char *)
+ zeros,
+ UNFM_P_SIZE
+ *
+ to_paste);
+ if (res) {
+ kfree(zeros);
+ goto error_exit_free_blocks;
+ }
+ } else if (is_statdata_le_ih(ih)) {
+ /* No existing item, create it */
+ /* item head for new item */
+ struct item_head ins_ih;
+
+ /* create a key for our new item */
+ make_cpu_key(&key, inode, 1,
+ TYPE_INDIRECT, 3);
+
+ /* Create new item head for our new item */
+ make_le_item_head(&ins_ih, &key,
+ key.version, 1,
+ TYPE_INDIRECT,
+ to_paste *
+ UNFM_P_SIZE,
+ 0 /* free space */ );
+
+ /* Find where such item should live in the tree */
+ res =
+ search_item(inode->i_sb, &key,
+ &path);
+ if (res != ITEM_NOT_FOUND) {
+ /* item should not exist, otherwise we have error */
+ if (res != -ENOSPC) {
+ reiserfs_warning(inode->
+ i_sb,
+ "green-9008: search_by_key (%K) returned %d",
+ &key,
+ res);
+ }
+ res = -EIO;
+ kfree(zeros);
+ goto error_exit_free_blocks;
+ }
+ res =
+ reiserfs_insert_item(th, &path,
+ &key, &ins_ih,
+ inode,
+ (char *)zeros);
+ } else {
+ reiserfs_panic(inode->i_sb,
+ "green-9011: Unexpected key type %K\n",
+ &key);
+ }
+ if (res) {
+ kfree(zeros);
+ goto error_exit_free_blocks;
+ }
+ /* Now we want to check if transaction is too full, and if it is
+ we restart it. This will also free the path. */
+ if (journal_transaction_should_end
+ (th, th->t_blocks_allocated)) {
+ res =
+ restart_transaction(th, inode,
+ &path);
+ if (res) {
+ pathrelse(&path);
+ kfree(zeros);
+ goto error_exit;
+ }
+ }
+
+ /* Well, need to recalculate path and stuff */
+ set_cpu_key_k_offset(&key,
+ cpu_key_k_offset(&key) +
+ (to_paste << inode->
+ i_blkbits));
+ res =
+ search_for_position_by_key(inode->i_sb,
+ &key, &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
+ kfree(zeros);
+ goto error_exit_free_blocks;
+ }
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ hole_size -= to_paste;
+ } while (hole_size);
+ kfree(zeros);
}
- if ( res ) {
- kfree(zeros);
- goto error_exit_free_blocks;
+ }
+ // Go through existing indirect items first
+ // replace all zeroes with blocknumbers from list
+ // Note that if no corresponding item was found, by previous search,
+ // it means there are no existing in-tree representation for file area
+ // we are going to overwrite, so there is nothing to scan through for holes.
+ for (curr_block = 0, itempos = path.pos_in_item;
+ curr_block < blocks_to_allocate && res == POSITION_FOUND;) {
+ retry:
+
+ if (itempos >= ih_item_len(ih) / UNFM_P_SIZE) {
+ /* We run out of data in this indirect item, let's look for another
+ one. */
+ /* First if we are already modifying current item, log it */
+ if (modifying_this_item) {
+ journal_mark_dirty(th, inode->i_sb, bh);
+ modifying_this_item = 0;
+ }
+ /* Then set the key to look for a new indirect item (offset of old
+ item is added to old item length */
+ set_cpu_key_k_offset(&key,
+ le_key_k_offset
+ (get_inode_item_key_version(inode),
+ &(ih->ih_key)) +
+ op_bytes_number(ih,
+ inode->i_sb->
+ s_blocksize));
+ /* Search ofor position of new key in the tree. */
+ res =
+ search_for_position_by_key(inode->i_sb, &key,
+ &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
+ goto error_exit_free_blocks;
+ }
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ itempos = path.pos_in_item;
+ continue; // loop to check all kinds of conditions and so on.
}
- /* Now we want to check if transaction is too full, and if it is
- we restart it. This will also free the path. */
- if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
- res = restart_transaction(th, inode, &path);
- if (res) {
- pathrelse (&path);
- kfree(zeros);
- goto error_exit;
- }
- }
-
- /* Well, need to recalculate path and stuff */
- set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + (to_paste << inode->i_blkbits));
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- res = -EIO;
- kfree(zeros);
- goto error_exit_free_blocks;
+ /* Ok, we have correct position in item now, so let's see if it is
+ representing file hole (blocknumber is zero) and fill it if needed */
+ if (!item[itempos]) {
+ /* Ok, a hole. Now we need to check if we already prepared this
+ block to be journaled */
+ while (!modifying_this_item) { // loop until succeed
+ /* Well, this item is not journaled yet, so we must prepare
+ it for journal first, before we can change it */
+ struct item_head tmp_ih; // We copy item head of found item,
+ // here to detect if fs changed under
+ // us while we were preparing for
+ // journal.
+ int fs_gen; // We store fs generation here to find if someone
+ // changes fs under our feet
+
+ copy_item_head(&tmp_ih, ih); // Remember itemhead
+ fs_gen = get_generation(inode->i_sb); // remember fs generation
+ reiserfs_prepare_for_journal(inode->i_sb, bh, 1); // Prepare a buffer within which indirect item is stored for changing.
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ // Sigh, fs was changed under us, we need to look for new
+ // location of item we are working with
+
+ /* unmark prepaerd area as journaled and search for it's
+ new position */
+ reiserfs_restore_prepared_buffer(inode->
+ i_sb,
+ bh);
+ res =
+ search_for_position_by_key(inode->
+ i_sb,
+ &key,
+ &path);
+ if (res == IO_ERROR) {
+ res = -EIO;
+ goto error_exit_free_blocks;
+ }
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ itempos = path.pos_in_item;
+ goto retry;
+ }
+ modifying_this_item = 1;
+ }
+ item[itempos] = allocated_blocks[curr_block]; // Assign new block
+ curr_block++;
}
- bh=get_last_bh(&path);
- ih=get_ih(&path);
- item = get_item(&path);
- hole_size -= to_paste;
- } while ( hole_size );
- kfree(zeros);
+ itempos++;
}
- }
-
- // Go through existing indirect items first
- // replace all zeroes with blocknumbers from list
- // Note that if no corresponding item was found, by previous search,
- // it means there are no existing in-tree representation for file area
- // we are going to overwrite, so there is nothing to scan through for holes.
- for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
-retry:
-
- if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
- /* We run out of data in this indirect item, let's look for another
- one. */
- /* First if we are already modifying current item, log it */
- if ( modifying_this_item ) {
- journal_mark_dirty (th, inode->i_sb, bh);
- modifying_this_item = 0;
- }
- /* Then set the key to look for a new indirect item (offset of old
- item is added to old item length */
- set_cpu_key_k_offset( &key, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize));
- /* Search ofor position of new key in the tree. */
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR) {
- res = -EIO;
- goto error_exit_free_blocks;
- }
- bh=get_last_bh(&path);
- ih=get_ih(&path);
- item = get_item(&path);
- itempos = path.pos_in_item;
- continue; // loop to check all kinds of conditions and so on.
+
+ if (modifying_this_item) { // We need to log last-accessed block, if it
+ // was modified, but not logged yet.
+ journal_mark_dirty(th, inode->i_sb, bh);
}
- /* Ok, we have correct position in item now, so let's see if it is
- representing file hole (blocknumber is zero) and fill it if needed */
- if ( !item[itempos] ) {
- /* Ok, a hole. Now we need to check if we already prepared this
- block to be journaled */
- while ( !modifying_this_item ) { // loop until succeed
- /* Well, this item is not journaled yet, so we must prepare
- it for journal first, before we can change it */
- struct item_head tmp_ih; // We copy item head of found item,
- // here to detect if fs changed under
- // us while we were preparing for
- // journal.
- int fs_gen; // We store fs generation here to find if someone
- // changes fs under our feet
-
- copy_item_head (&tmp_ih, ih); // Remember itemhead
- fs_gen = get_generation (inode->i_sb); // remember fs generation
- reiserfs_prepare_for_journal(inode->i_sb, bh, 1); // Prepare a buffer within which indirect item is stored for changing.
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- // Sigh, fs was changed under us, we need to look for new
- // location of item we are working with
-
- /* unmark prepaerd area as journaled and search for it's
- new position */
- reiserfs_restore_prepared_buffer(inode->i_sb, bh);
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR) {
- res = -EIO;
- goto error_exit_free_blocks;
- }
- bh=get_last_bh(&path);
- ih=get_ih(&path);
- item = get_item(&path);
- itempos = path.pos_in_item;
- goto retry;
+
+ if (curr_block < blocks_to_allocate) {
+ // Oh, well need to append to indirect item, or to create indirect item
+ // if there weren't any
+ if (is_indirect_le_ih(ih)) {
+ // Existing indirect item - append. First calculate key for append
+ // position. We do not need to recalculate path as it should
+ // already point to correct place.
+ make_cpu_key(&key, inode,
+ le_key_k_offset(get_inode_item_key_version
+ (inode),
+ &(ih->ih_key)) +
+ op_bytes_number(ih,
+ inode->i_sb->s_blocksize),
+ TYPE_INDIRECT, 3);
+ res =
+ reiserfs_paste_into_item(th, &path, &key, inode,
+ (char *)(allocated_blocks +
+ curr_block),
+ UNFM_P_SIZE *
+ (blocks_to_allocate -
+ curr_block));
+ if (res) {
+ goto error_exit_free_blocks;
+ }
+ } else if (is_statdata_le_ih(ih)) {
+ // Last found item was statdata. That means we need to create indirect item.
+ struct item_head ins_ih; /* itemhead for new item */
+
+ /* create a key for our new item */
+ make_cpu_key(&key, inode, 1, TYPE_INDIRECT, 3); // Position one,
+ // because that's
+ // where first
+ // indirect item
+ // begins
+ /* Create new item head for our new item */
+ make_le_item_head(&ins_ih, &key, key.version, 1,
+ TYPE_INDIRECT,
+ (blocks_to_allocate -
+ curr_block) * UNFM_P_SIZE,
+ 0 /* free space */ );
+ /* Find where such item should live in the tree */
+ res = search_item(inode->i_sb, &key, &path);
+ if (res != ITEM_NOT_FOUND) {
+ /* Well, if we have found such item already, or some error
+ occured, we need to warn user and return error */
+ if (res != -ENOSPC) {
+ reiserfs_warning(inode->i_sb,
+ "green-9009: search_by_key (%K) "
+ "returned %d", &key,
+ res);
+ }
+ res = -EIO;
+ goto error_exit_free_blocks;
+ }
+ /* Insert item into the tree with the data as its body */
+ res =
+ reiserfs_insert_item(th, &path, &key, &ins_ih,
+ inode,
+ (char *)(allocated_blocks +
+ curr_block));
+ } else {
+ reiserfs_panic(inode->i_sb,
+ "green-9010: unexpected item type for key %K\n",
+ &key);
}
- modifying_this_item = 1;
- }
- item[itempos] = allocated_blocks[curr_block]; // Assign new block
- curr_block++;
}
- itempos++;
- }
-
- if ( modifying_this_item ) { // We need to log last-accessed block, if it
- // was modified, but not logged yet.
- journal_mark_dirty (th, inode->i_sb, bh);
- }
-
- if ( curr_block < blocks_to_allocate ) {
- // Oh, well need to append to indirect item, or to create indirect item
- // if there weren't any
- if ( is_indirect_le_ih(ih) ) {
- // Existing indirect item - append. First calculate key for append
- // position. We do not need to recalculate path as it should
- // already point to correct place.
- make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
- res = reiserfs_paste_into_item( th, &path, &key, inode, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
- if ( res ) {
- goto error_exit_free_blocks;
- }
- } else if (is_statdata_le_ih(ih) ) {
- // Last found item was statdata. That means we need to create indirect item.
- struct item_head ins_ih; /* itemhead for new item */
-
- /* create a key for our new item */
- make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3); // Position one,
- // because that's
- // where first
- // indirect item
- // begins
- /* Create new item head for our new item */
- make_le_item_head (&ins_ih, &key, key.version, 1, TYPE_INDIRECT,
- (blocks_to_allocate-curr_block)*UNFM_P_SIZE,
- 0 /* free space */);
- /* Find where such item should live in the tree */
- res = search_item (inode->i_sb, &key, &path);
- if ( res != ITEM_NOT_FOUND ) {
- /* Well, if we have found such item already, or some error
- occured, we need to warn user and return error */
- if ( res != -ENOSPC ) {
- reiserfs_warning (inode->i_sb,
- "green-9009: search_by_key (%K) "
- "returned %d", &key, res);
+ // the caller is responsible for closing the transaction
+ // unless we return an error, they are also responsible for logging
+ // the inode.
+ //
+ pathrelse(&path);
+ /*
+ * cleanup prellocation from previous writes
+ * if this is a partial block write
+ */
+ if (write_bytes & (inode->i_sb->s_blocksize - 1))
+ reiserfs_discard_prealloc(th, inode);
+ reiserfs_write_unlock(inode->i_sb);
+
+ // go through all the pages/buffers and map the buffers to newly allocated
+ // blocks (so that system knows where to write these pages later).
+ curr_block = 0;
+ for (i = 0; i < num_pages; i++) {
+ struct page *page = prepared_pages[i]; //current page
+ struct buffer_head *head = page_buffers(page); // first buffer for a page
+ int block_start, block_end; // in-page offsets for buffers.
+
+ if (!page_buffers(page))
+ reiserfs_panic(inode->i_sb,
+ "green-9005: No buffers for prepared page???");
+
+ /* For each buffer in page */
+ for (bh = head, block_start = 0; bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+ if (!bh)
+ reiserfs_panic(inode->i_sb,
+ "green-9006: Allocated but absent buffer for a page?");
+ block_end = block_start + inode->i_sb->s_blocksize;
+ if (i == 0 && block_end <= from)
+ /* if this buffer is before requested data to map, skip it */
+ continue;
+ if (i == num_pages - 1 && block_start >= to)
+ /* If this buffer is after requested data to map, abort
+ processing of current page */
+ break;
+
+ if (!buffer_mapped(bh)) { // Ok, unmapped buffer, need to map it
+ map_bh(bh, inode->i_sb,
+ le32_to_cpu(allocated_blocks
+ [curr_block]));
+ curr_block++;
+ set_buffer_new(bh);
+ }
}
- res = -EIO;
- goto error_exit_free_blocks;
- }
- /* Insert item into the tree with the data as its body */
- res = reiserfs_insert_item( th, &path, &key, &ins_ih, inode, (char *)(allocated_blocks+curr_block));
- } else {
- reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key);
- }
- }
-
- // the caller is responsible for closing the transaction
- // unless we return an error, they are also responsible for logging
- // the inode.
- //
- pathrelse(&path);
- /*
- * cleanup prellocation from previous writes
- * if this is a partial block write
- */
- if (write_bytes & (inode->i_sb->s_blocksize -1))
- reiserfs_discard_prealloc(th, inode);
- reiserfs_write_unlock(inode->i_sb);
-
- // go through all the pages/buffers and map the buffers to newly allocated
- // blocks (so that system knows where to write these pages later).
- curr_block = 0;
- for ( i = 0; i < num_pages ; i++ ) {
- struct page *page=prepared_pages[i]; //current page
- struct buffer_head *head = page_buffers(page);// first buffer for a page
- int block_start, block_end; // in-page offsets for buffers.
-
- if (!page_buffers(page))
- reiserfs_panic(inode->i_sb, "green-9005: No buffers for prepared page???");
-
- /* For each buffer in page */
- for(bh = head, block_start = 0; bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page) {
- if (!bh)
- reiserfs_panic(inode->i_sb, "green-9006: Allocated but absent buffer for a page?");
- block_end = block_start+inode->i_sb->s_blocksize;
- if (i == 0 && block_end <= from )
- /* if this buffer is before requested data to map, skip it */
- continue;
- if (i == num_pages - 1 && block_start >= to)
- /* If this buffer is after requested data to map, abort
- processing of current page */
- break;
-
- if ( !buffer_mapped(bh) ) { // Ok, unmapped buffer, need to map it
- map_bh( bh, inode->i_sb, le32_to_cpu(allocated_blocks[curr_block]));
- curr_block++;
- set_buffer_new(bh);
- }
}
- }
- RFALSE( curr_block > blocks_to_allocate, "green-9007: Used too many blocks? weird");
+ RFALSE(curr_block > blocks_to_allocate,
+ "green-9007: Used too many blocks? weird");
- kfree(allocated_blocks);
- return 0;
+ kfree(allocated_blocks);
+ return 0;
// Need to deal with transaction here.
-error_exit_free_blocks:
- pathrelse(&path);
- // free blocks
- for( i = 0; i < blocks_to_allocate; i++ )
- reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]), 1);
-
-error_exit:
- if (th->t_trans_id) {
- int err;
- // update any changes we made to blk count
- reiserfs_update_sd(th, inode);
- err = journal_end(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS);
- if (err)
- res = err;
- }
- reiserfs_write_unlock(inode->i_sb);
- kfree(allocated_blocks);
-
- return res;
+ error_exit_free_blocks:
+ pathrelse(&path);
+ // free blocks
+ for (i = 0; i < blocks_to_allocate; i++)
+ reiserfs_free_block(th, inode, le32_to_cpu(allocated_blocks[i]),
+ 1);
+
+ error_exit:
+ if (th->t_trans_id) {
+ int err;
+ // update any changes we made to blk count
+ reiserfs_update_sd(th, inode);
+ err =
+ journal_end(th, inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT * 3 + 1 +
+ 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb));
+ if (err)
+ res = err;
+ }
+ reiserfs_write_unlock(inode->i_sb);
+ kfree(allocated_blocks);
+
+ return res;
}
/* Unlock pages prepared by reiserfs_prepare_file_region_for_write */
-static void reiserfs_unprepare_pages(struct page **prepared_pages, /* list of locked pages */
- size_t num_pages /* amount of pages */) {
- int i; // loop counter
+static void reiserfs_unprepare_pages(struct page **prepared_pages, /* list of locked pages */
+ size_t num_pages /* amount of pages */ )
+{
+ int i; // loop counter
- for (i=0; i < num_pages ; i++) {
- struct page *page = prepared_pages[i];
+ for (i = 0; i < num_pages; i++) {
+ struct page *page = prepared_pages[i];
- try_to_free_buffers(page);
- unlock_page(page);
- page_cache_release(page);
- }
+ try_to_free_buffers(page);
+ unlock_page(page);
+ page_cache_release(page);
+ }
}
/* This function will copy data from userspace to specified pages within
supplied byte range */
-static int reiserfs_copy_from_user_to_file_region(
- loff_t pos, /* In-file position */
- int num_pages, /* Number of pages affected */
- int write_bytes, /* Amount of bytes to write */
- struct page **prepared_pages, /* pointer to
- array to
- prepared pages
- */
- const char __user *buf /* Pointer to user-supplied
- data*/
- )
+static int reiserfs_copy_from_user_to_file_region(loff_t pos, /* In-file position */
+ int num_pages, /* Number of pages affected */
+ int write_bytes, /* Amount of bytes to write */
+ struct page **prepared_pages, /* pointer to
+ array to
+ prepared pages
+ */
+ const char __user * buf /* Pointer to user-supplied
+ data */
+ )
{
- long page_fault=0; // status of copy_from_user.
- int i; // loop counter.
- int offset; // offset in page
-
- for ( i = 0, offset = (pos & (PAGE_CACHE_SIZE-1)); i < num_pages ; i++,offset=0) {
- size_t count = min_t(size_t,PAGE_CACHE_SIZE-offset,write_bytes); // How much of bytes to write to this page
- struct page *page=prepared_pages[i]; // Current page we process.
-
- fault_in_pages_readable( buf, count);
-
- /* Copy data from userspace to the current page */
- kmap(page);
- page_fault = __copy_from_user(page_address(page)+offset, buf, count); // Copy the data.
- /* Flush processor's dcache for this page */
- flush_dcache_page(page);
- kunmap(page);
- buf+=count;
- write_bytes-=count;
-
- if (page_fault)
- break; // Was there a fault? abort.
- }
-
- return page_fault?-EFAULT:0;
+ long page_fault = 0; // status of copy_from_user.
+ int i; // loop counter.
+ int offset; // offset in page
+
+ for (i = 0, offset = (pos & (PAGE_CACHE_SIZE - 1)); i < num_pages;
+ i++, offset = 0) {
+ size_t count = min_t(size_t, PAGE_CACHE_SIZE - offset, write_bytes); // How much of bytes to write to this page
+ struct page *page = prepared_pages[i]; // Current page we process.
+
+ fault_in_pages_readable(buf, count);
+
+ /* Copy data from userspace to the current page */
+ kmap(page);
+ page_fault = __copy_from_user(page_address(page) + offset, buf, count); // Copy the data.
+ /* Flush processor's dcache for this page */
+ flush_dcache_page(page);
+ kunmap(page);
+ buf += count;
+ write_bytes -= count;
+
+ if (page_fault)
+ break; // Was there a fault? abort.
+ }
+
+ return page_fault ? -EFAULT : 0;
}
/* taken fs/buffer.c:__block_commit_write */
int reiserfs_commit_page(struct inode *inode, struct page *page,
- unsigned from, unsigned to)
+ unsigned from, unsigned to)
{
- unsigned block_start, block_end;
- int partial = 0;
- unsigned blocksize;
- struct buffer_head *bh, *head;
- unsigned long i_size_index = inode->i_size >> PAGE_CACHE_SHIFT;
- int new;
- int logit = reiserfs_file_data_log(inode);
- struct super_block *s = inode->i_sb;
- int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
- struct reiserfs_transaction_handle th;
- int ret = 0;
-
- th.t_trans_id = 0;
- blocksize = 1 << inode->i_blkbits;
-
- if (logit) {
- reiserfs_write_lock(s);
- ret = journal_begin(&th, s, bh_per_page + 1);
- if (ret)
- goto drop_write_lock;
- reiserfs_update_inode_transaction(inode);
- }
- for(bh = head = page_buffers(page), block_start = 0;
- bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page)
- {
-
- new = buffer_new(bh);
- clear_buffer_new(bh);
- block_end = block_start + blocksize;
- if (block_end <= from || block_start >= to) {
- if (!buffer_uptodate(bh))
- partial = 1;
- } else {
- set_buffer_uptodate(bh);
- if (logit) {
- reiserfs_prepare_for_journal(s, bh, 1);
- journal_mark_dirty(&th, s, bh);
- } else if (!buffer_dirty(bh)) {
- mark_buffer_dirty(bh);
- /* do data=ordered on any page past the end
- * of file and any buffer marked BH_New.
- */
- if (reiserfs_data_ordered(inode->i_sb) &&
- (new || page->index >= i_size_index)) {
- reiserfs_add_ordered_list(inode, bh);
- }
- }
+ unsigned block_start, block_end;
+ int partial = 0;
+ unsigned blocksize;
+ struct buffer_head *bh, *head;
+ unsigned long i_size_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ int new;
+ int logit = reiserfs_file_data_log(inode);
+ struct super_block *s = inode->i_sb;
+ int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+ struct reiserfs_transaction_handle th;
+ int ret = 0;
+
+ th.t_trans_id = 0;
+ blocksize = 1 << inode->i_blkbits;
+
+ if (logit) {
+ reiserfs_write_lock(s);
+ ret = journal_begin(&th, s, bh_per_page + 1);
+ if (ret)
+ goto drop_write_lock;
+ reiserfs_update_inode_transaction(inode);
+ }
+ for (bh = head = page_buffers(page), block_start = 0;
+ bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+
+ new = buffer_new(bh);
+ clear_buffer_new(bh);
+ block_end = block_start + blocksize;
+ if (block_end <= from || block_start >= to) {
+ if (!buffer_uptodate(bh))
+ partial = 1;
+ } else {
+ set_buffer_uptodate(bh);
+ if (logit) {
+ reiserfs_prepare_for_journal(s, bh, 1);
+ journal_mark_dirty(&th, s, bh);
+ } else if (!buffer_dirty(bh)) {
+ mark_buffer_dirty(bh);
+ /* do data=ordered on any page past the end
+ * of file and any buffer marked BH_New.
+ */
+ if (reiserfs_data_ordered(inode->i_sb) &&
+ (new || page->index >= i_size_index)) {
+ reiserfs_add_ordered_list(inode, bh);
+ }
+ }
+ }
}
- }
- if (logit) {
- ret = journal_end(&th, s, bh_per_page + 1);
-drop_write_lock:
- reiserfs_write_unlock(s);
- }
- /*
- * If this is a partial write which happened to make all buffers
- * uptodate then we can optimize away a bogus readpage() for
- * the next read(). Here we 'discover' whether the page went
- * uptodate as a result of this (potentially partial) write.
- */
- if (!partial)
- SetPageUptodate(page);
- return ret;
+ if (logit) {
+ ret = journal_end(&th, s, bh_per_page + 1);
+ drop_write_lock:
+ reiserfs_write_unlock(s);
+ }
+ /*
+ * If this is a partial write which happened to make all buffers
+ * uptodate then we can optimize away a bogus readpage() for
+ * the next read(). Here we 'discover' whether the page went
+ * uptodate as a result of this (potentially partial) write.
+ */
+ if (!partial)
+ SetPageUptodate(page);
+ return ret;
}
-
/* Submit pages for write. This was separated from actual file copying
because we might want to allocate block numbers in-between.
This function assumes that caller will adjust file size to correct value. */
-static int reiserfs_submit_file_region_for_write(
- struct reiserfs_transaction_handle *th,
- struct inode *inode,
- loff_t pos, /* Writing position offset */
- size_t num_pages, /* Number of pages to write */
- size_t write_bytes, /* number of bytes to write */
- struct page **prepared_pages /* list of pages */
- )
+static int reiserfs_submit_file_region_for_write(struct reiserfs_transaction_handle *th, struct inode *inode, loff_t pos, /* Writing position offset */
+ size_t num_pages, /* Number of pages to write */
+ size_t write_bytes, /* number of bytes to write */
+ struct page **prepared_pages /* list of pages */
+ )
{
- int status; // return status of block_commit_write.
- int retval = 0; // Return value we are going to return.
- int i; // loop counter
- int offset; // Writing offset in page.
- int orig_write_bytes = write_bytes;
- int sd_update = 0;
-
- for ( i = 0, offset = (pos & (PAGE_CACHE_SIZE-1)); i < num_pages ; i++,offset=0) {
- int count = min_t(int,PAGE_CACHE_SIZE-offset,write_bytes); // How much of bytes to write to this page
- struct page *page=prepared_pages[i]; // Current page we process.
-
- status = reiserfs_commit_page(inode, page, offset, offset+count);
- if ( status )
- retval = status; // To not overcomplicate matters We are going to
- // submit all the pages even if there was error.
- // we only remember error status to report it on
- // exit.
- write_bytes-=count;
- }
- /* now that we've gotten all the ordered buffers marked dirty,
- * we can safely update i_size and close any running transaction
- */
- if ( pos + orig_write_bytes > inode->i_size) {
- inode->i_size = pos + orig_write_bytes; // Set new size
- /* If the file have grown so much that tail packing is no
- * longer possible, reset "need to pack" flag */
- if ( (have_large_tails (inode->i_sb) &&
- inode->i_size > i_block_size (inode)*4) ||
- (have_small_tails (inode->i_sb) &&
- inode->i_size > i_block_size(inode)) )
- REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ;
- else if ( (have_large_tails (inode->i_sb) &&
- inode->i_size < i_block_size (inode)*4) ||
- (have_small_tails (inode->i_sb) &&
- inode->i_size < i_block_size(inode)) )
- REISERFS_I(inode)->i_flags |= i_pack_on_close_mask ;
-
+ int status; // return status of block_commit_write.
+ int retval = 0; // Return value we are going to return.
+ int i; // loop counter
+ int offset; // Writing offset in page.
+ int orig_write_bytes = write_bytes;
+ int sd_update = 0;
+
+ for (i = 0, offset = (pos & (PAGE_CACHE_SIZE - 1)); i < num_pages;
+ i++, offset = 0) {
+ int count = min_t(int, PAGE_CACHE_SIZE - offset, write_bytes); // How much of bytes to write to this page
+ struct page *page = prepared_pages[i]; // Current page we process.
+
+ status =
+ reiserfs_commit_page(inode, page, offset, offset + count);
+ if (status)
+ retval = status; // To not overcomplicate matters We are going to
+ // submit all the pages even if there was error.
+ // we only remember error status to report it on
+ // exit.
+ write_bytes -= count;
+ }
+ /* now that we've gotten all the ordered buffers marked dirty,
+ * we can safely update i_size and close any running transaction
+ */
+ if (pos + orig_write_bytes > inode->i_size) {
+ inode->i_size = pos + orig_write_bytes; // Set new size
+ /* If the file have grown so much that tail packing is no
+ * longer possible, reset "need to pack" flag */
+ if ((have_large_tails(inode->i_sb) &&
+ inode->i_size > i_block_size(inode) * 4) ||
+ (have_small_tails(inode->i_sb) &&
+ inode->i_size > i_block_size(inode)))
+ REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
+ else if ((have_large_tails(inode->i_sb) &&
+ inode->i_size < i_block_size(inode) * 4) ||
+ (have_small_tails(inode->i_sb) &&
+ inode->i_size < i_block_size(inode)))
+ REISERFS_I(inode)->i_flags |= i_pack_on_close_mask;
+
+ if (th->t_trans_id) {
+ reiserfs_write_lock(inode->i_sb);
+ reiserfs_update_sd(th, inode); // And update on-disk metadata
+ reiserfs_write_unlock(inode->i_sb);
+ } else
+ inode->i_sb->s_op->dirty_inode(inode);
+
+ sd_update = 1;
+ }
if (th->t_trans_id) {
- reiserfs_write_lock(inode->i_sb);
- reiserfs_update_sd(th, inode); // And update on-disk metadata
- reiserfs_write_unlock(inode->i_sb);
- } else
- inode->i_sb->s_op->dirty_inode(inode);
+ reiserfs_write_lock(inode->i_sb);
+ if (!sd_update)
+ reiserfs_update_sd(th, inode);
+ status = journal_end(th, th->t_super, th->t_blocks_allocated);
+ if (status)
+ retval = status;
+ reiserfs_write_unlock(inode->i_sb);
+ }
+ th->t_trans_id = 0;
- sd_update = 1;
- }
- if (th->t_trans_id) {
- reiserfs_write_lock(inode->i_sb);
- if (!sd_update)
- reiserfs_update_sd(th, inode);
- status = journal_end(th, th->t_super, th->t_blocks_allocated);
- if (status)
- retval = status;
- reiserfs_write_unlock(inode->i_sb);
- }
- th->t_trans_id = 0;
-
- /*
- * we have to unlock the pages after updating i_size, otherwise
- * we race with writepage
- */
- for ( i = 0; i < num_pages ; i++) {
- struct page *page=prepared_pages[i];
- unlock_page(page);
- mark_page_accessed(page);
- page_cache_release(page);
- }
- return retval;
+ /*
+ * we have to unlock the pages after updating i_size, otherwise
+ * we race with writepage
+ */
+ for (i = 0; i < num_pages; i++) {
+ struct page *page = prepared_pages[i];
+ unlock_page(page);
+ mark_page_accessed(page);
+ page_cache_release(page);
+ }
+ return retval;
}
/* Look if passed writing region is going to touch file's tail
(if it is present). And if it is, convert the tail to unformatted node */
-static int reiserfs_check_for_tail_and_convert( struct inode *inode, /* inode to deal with */
- loff_t pos, /* Writing position */
- int write_bytes /* amount of bytes to write */
- )
+static int reiserfs_check_for_tail_and_convert(struct inode *inode, /* inode to deal with */
+ loff_t pos, /* Writing position */
+ int write_bytes /* amount of bytes to write */
+ )
{
- INITIALIZE_PATH(path); // needed for search_for_position
- struct cpu_key key; // Key that would represent last touched writing byte.
- struct item_head *ih; // item header of found block;
- int res; // Return value of various functions we call.
- int cont_expand_offset; // We will put offset for generic_cont_expand here
- // This can be int just because tails are created
- // only for small files.
-
+ INITIALIZE_PATH(path); // needed for search_for_position
+ struct cpu_key key; // Key that would represent last touched writing byte.
+ struct item_head *ih; // item header of found block;
+ int res; // Return value of various functions we call.
+ int cont_expand_offset; // We will put offset for generic_cont_expand here
+ // This can be int just because tails are created
+ // only for small files.
+
/* this embodies a dependency on a particular tail policy */
- if ( inode->i_size >= inode->i_sb->s_blocksize*4 ) {
- /* such a big files do not have tails, so we won't bother ourselves
- to look for tails, simply return */
- return 0;
- }
-
- reiserfs_write_lock(inode->i_sb);
- /* find the item containing the last byte to be written, or if
- * writing past the end of the file then the last item of the
- * file (and then we check its type). */
- make_cpu_key (&key, inode, pos+write_bytes+1, TYPE_ANY, 3/*key length*/);
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- if ( res == IO_ERROR ) {
- reiserfs_write_unlock(inode->i_sb);
- return -EIO;
- }
- ih = get_ih(&path);
- res = 0;
- if ( is_direct_le_ih(ih) ) {
- /* Ok, closest item is file tail (tails are stored in "direct"
- * items), so we need to unpack it. */
- /* To not overcomplicate matters, we just call generic_cont_expand
- which will in turn call other stuff and finally will boil down to
- reiserfs_get_block() that would do necessary conversion. */
- cont_expand_offset = le_key_k_offset(get_inode_item_key_version(inode), &(ih->ih_key));
- pathrelse(&path);
- res = generic_cont_expand( inode, cont_expand_offset);
- } else
- pathrelse(&path);
+ if (inode->i_size >= inode->i_sb->s_blocksize * 4) {
+ /* such a big files do not have tails, so we won't bother ourselves
+ to look for tails, simply return */
+ return 0;
+ }
- reiserfs_write_unlock(inode->i_sb);
- return res;
+ reiserfs_write_lock(inode->i_sb);
+ /* find the item containing the last byte to be written, or if
+ * writing past the end of the file then the last item of the
+ * file (and then we check its type). */
+ make_cpu_key(&key, inode, pos + write_bytes + 1, TYPE_ANY,
+ 3 /*key length */ );
+ res = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (res == IO_ERROR) {
+ reiserfs_write_unlock(inode->i_sb);
+ return -EIO;
+ }
+ ih = get_ih(&path);
+ res = 0;
+ if (is_direct_le_ih(ih)) {
+ /* Ok, closest item is file tail (tails are stored in "direct"
+ * items), so we need to unpack it. */
+ /* To not overcomplicate matters, we just call generic_cont_expand
+ which will in turn call other stuff and finally will boil down to
+ reiserfs_get_block() that would do necessary conversion. */
+ cont_expand_offset =
+ le_key_k_offset(get_inode_item_key_version(inode),
+ &(ih->ih_key));
+ pathrelse(&path);
+ res = generic_cont_expand(inode, cont_expand_offset);
+ } else
+ pathrelse(&path);
+
+ reiserfs_write_unlock(inode->i_sb);
+ return res;
}
/* This function locks pages starting from @pos for @inode.
@@ -851,275 +947,296 @@ static int reiserfs_check_for_tail_and_convert( struct inode *inode, /* inode to
append), it is zeroed, then.
Returns number of unallocated blocks that should be allocated to cover
new file data.*/
-static int reiserfs_prepare_file_region_for_write(
- struct inode *inode /* Inode of the file */,
- loff_t pos, /* position in the file */
- size_t num_pages, /* number of pages to
- prepare */
- size_t write_bytes, /* Amount of bytes to be
- overwritten from
- @pos */
- struct page **prepared_pages /* pointer to array
- where to store
- prepared pages */
- )
+static int reiserfs_prepare_file_region_for_write(struct inode *inode
+ /* Inode of the file */ ,
+ loff_t pos, /* position in the file */
+ size_t num_pages, /* number of pages to
+ prepare */
+ size_t write_bytes, /* Amount of bytes to be
+ overwritten from
+ @pos */
+ struct page **prepared_pages /* pointer to array
+ where to store
+ prepared pages */
+ )
{
- int res=0; // Return values of different functions we call.
- unsigned long index = pos >> PAGE_CACHE_SHIFT; // Offset in file in pages.
- int from = (pos & (PAGE_CACHE_SIZE - 1)); // Writing offset in first page
- int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1;
- /* offset of last modified byte in last
- page */
- struct address_space *mapping = inode->i_mapping; // Pages are mapped here.
- int i; // Simple counter
- int blocks = 0; /* Return value (blocks that should be allocated) */
- struct buffer_head *bh, *head; // Current bufferhead and first bufferhead
- // of a page.
- unsigned block_start, block_end; // Starting and ending offsets of current
- // buffer in the page.
- struct buffer_head *wait[2], **wait_bh=wait; // Buffers for page, if
- // Page appeared to be not up
- // to date. Note how we have
- // at most 2 buffers, this is
- // because we at most may
- // partially overwrite two
- // buffers for one page. One at // the beginning of write area
- // and one at the end.
- // Everything inthe middle gets // overwritten totally.
-
- struct cpu_key key; // cpu key of item that we are going to deal with
- struct item_head *ih = NULL; // pointer to item head that we are going to deal with
- struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with
- INITIALIZE_PATH(path); // path to item, that we are going to deal with.
- __le32 * item=NULL; // pointer to item we are going to deal with
- int item_pos=-1; /* Position in indirect item */
-
-
- if ( num_pages < 1 ) {
- reiserfs_warning (inode->i_sb,
- "green-9001: reiserfs_prepare_file_region_for_write "
- "called with zero number of pages to process");
- return -EFAULT;
- }
-
- /* We have 2 loops for pages. In first loop we grab and lock the pages, so
- that nobody would touch these until we release the pages. Then
- we'd start to deal with mapping buffers to blocks. */
- for ( i = 0; i < num_pages; i++) {
- prepared_pages[i] = grab_cache_page(mapping, index + i); // locks the page
- if ( !prepared_pages[i]) {
- res = -ENOMEM;
- goto failed_page_grabbing;
- }
- if (!page_has_buffers(prepared_pages[i]))
- create_empty_buffers(prepared_pages[i], inode->i_sb->s_blocksize, 0);
- }
-
- /* Let's count amount of blocks for a case where all the blocks
- overwritten are new (we will substract already allocated blocks later)*/
- if ( num_pages > 2 )
- /* These are full-overwritten pages so we count all the blocks in
- these pages are counted as needed to be allocated */
- blocks = (num_pages - 2) << (PAGE_CACHE_SHIFT - inode->i_blkbits);
-
- /* count blocks needed for first page (possibly partially written) */
- blocks += ((PAGE_CACHE_SIZE - from) >> inode->i_blkbits) +
- !!(from & (inode->i_sb->s_blocksize-1)); /* roundup */
-
- /* Now we account for last page. If last page == first page (we
- overwrite only one page), we substract all the blocks past the
- last writing position in a page out of already calculated number
- of blocks */
- blocks += ((num_pages > 1) << (PAGE_CACHE_SHIFT-inode->i_blkbits)) -
- ((PAGE_CACHE_SIZE - to) >> inode->i_blkbits);
- /* Note how we do not roundup here since partial blocks still
- should be allocated */
-
- /* Now if all the write area lies past the file end, no point in
- maping blocks, since there is none, so we just zero out remaining
- parts of first and last pages in write area (if needed) */
- if ( (pos & ~((loff_t)PAGE_CACHE_SIZE - 1)) > inode->i_size ) {
- if ( from != 0 ) {/* First page needs to be partially zeroed */
- char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
- memset(kaddr, 0, from);
- kunmap_atomic( kaddr, KM_USER0);
- }
- if ( to != PAGE_CACHE_SIZE ) { /* Last page needs to be partially zeroed */
- char *kaddr = kmap_atomic(prepared_pages[num_pages-1], KM_USER0);
- memset(kaddr+to, 0, PAGE_CACHE_SIZE - to);
- kunmap_atomic( kaddr, KM_USER0);
+ int res = 0; // Return values of different functions we call.
+ unsigned long index = pos >> PAGE_CACHE_SHIFT; // Offset in file in pages.
+ int from = (pos & (PAGE_CACHE_SIZE - 1)); // Writing offset in first page
+ int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1;
+ /* offset of last modified byte in last
+ page */
+ struct address_space *mapping = inode->i_mapping; // Pages are mapped here.
+ int i; // Simple counter
+ int blocks = 0; /* Return value (blocks that should be allocated) */
+ struct buffer_head *bh, *head; // Current bufferhead and first bufferhead
+ // of a page.
+ unsigned block_start, block_end; // Starting and ending offsets of current
+ // buffer in the page.
+ struct buffer_head *wait[2], **wait_bh = wait; // Buffers for page, if
+ // Page appeared to be not up
+ // to date. Note how we have
+ // at most 2 buffers, this is
+ // because we at most may
+ // partially overwrite two
+ // buffers for one page. One at // the beginning of write area
+ // and one at the end.
+ // Everything inthe middle gets // overwritten totally.
+
+ struct cpu_key key; // cpu key of item that we are going to deal with
+ struct item_head *ih = NULL; // pointer to item head that we are going to deal with
+ struct buffer_head *itembuf = NULL; // Buffer head that contains items that we are going to deal with
+ INITIALIZE_PATH(path); // path to item, that we are going to deal with.
+ __le32 *item = NULL; // pointer to item we are going to deal with
+ int item_pos = -1; /* Position in indirect item */
+
+ if (num_pages < 1) {
+ reiserfs_warning(inode->i_sb,
+ "green-9001: reiserfs_prepare_file_region_for_write "
+ "called with zero number of pages to process");
+ return -EFAULT;
}
- /* Since all blocks are new - use already calculated value */
- return blocks;
- }
-
- /* Well, since we write somewhere into the middle of a file, there is
- possibility we are writing over some already allocated blocks, so
- let's map these blocks and substract number of such blocks out of blocks
- we need to allocate (calculated above) */
- /* Mask write position to start on blocksize, we do it out of the
- loop for performance reasons */
- pos &= ~((loff_t) inode->i_sb->s_blocksize - 1);
- /* Set cpu key to the starting position in a file (on left block boundary)*/
- make_cpu_key (&key, inode, 1 + ((pos) & ~((loff_t) inode->i_sb->s_blocksize - 1)), TYPE_ANY, 3/*key length*/);
-
- reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key()
- for ( i = 0; i < num_pages ; i++ ) {
-
- head = page_buffers(prepared_pages[i]);
- /* For each buffer in the page */
- for(bh = head, block_start = 0; bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page) {
- if (!bh)
- reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
- /* Find where this buffer ends */
- block_end = block_start+inode->i_sb->s_blocksize;
- if (i == 0 && block_end <= from )
- /* if this buffer is before requested data to map, skip it*/
- continue;
-
- if (i == num_pages - 1 && block_start >= to) {
- /* If this buffer is after requested data to map, abort
- processing of current page */
- break;
+ /* We have 2 loops for pages. In first loop we grab and lock the pages, so
+ that nobody would touch these until we release the pages. Then
+ we'd start to deal with mapping buffers to blocks. */
+ for (i = 0; i < num_pages; i++) {
+ prepared_pages[i] = grab_cache_page(mapping, index + i); // locks the page
+ if (!prepared_pages[i]) {
+ res = -ENOMEM;
+ goto failed_page_grabbing;
}
+ if (!page_has_buffers(prepared_pages[i]))
+ create_empty_buffers(prepared_pages[i],
+ inode->i_sb->s_blocksize, 0);
+ }
- if ( buffer_mapped(bh) && bh->b_blocknr !=0 ) {
- /* This is optimisation for a case where buffer is mapped
- and have blocknumber assigned. In case significant amount
- of such buffers are present, we may avoid some amount
- of search_by_key calls.
- Probably it would be possible to move parts of this code
- out of BKL, but I afraid that would overcomplicate code
- without any noticeable benefit.
- */
- item_pos++;
- /* Update the key */
- set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + inode->i_sb->s_blocksize);
- blocks--; // Decrease the amount of blocks that need to be
- // allocated
- continue; // Go to the next buffer
+ /* Let's count amount of blocks for a case where all the blocks
+ overwritten are new (we will substract already allocated blocks later) */
+ if (num_pages > 2)
+ /* These are full-overwritten pages so we count all the blocks in
+ these pages are counted as needed to be allocated */
+ blocks =
+ (num_pages - 2) << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+ /* count blocks needed for first page (possibly partially written) */
+ blocks += ((PAGE_CACHE_SIZE - from) >> inode->i_blkbits) + !!(from & (inode->i_sb->s_blocksize - 1)); /* roundup */
+
+ /* Now we account for last page. If last page == first page (we
+ overwrite only one page), we substract all the blocks past the
+ last writing position in a page out of already calculated number
+ of blocks */
+ blocks += ((num_pages > 1) << (PAGE_CACHE_SHIFT - inode->i_blkbits)) -
+ ((PAGE_CACHE_SIZE - to) >> inode->i_blkbits);
+ /* Note how we do not roundup here since partial blocks still
+ should be allocated */
+
+ /* Now if all the write area lies past the file end, no point in
+ maping blocks, since there is none, so we just zero out remaining
+ parts of first and last pages in write area (if needed) */
+ if ((pos & ~((loff_t) PAGE_CACHE_SIZE - 1)) > inode->i_size) {
+ if (from != 0) { /* First page needs to be partially zeroed */
+ char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
+ memset(kaddr, 0, from);
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+ if (to != PAGE_CACHE_SIZE) { /* Last page needs to be partially zeroed */
+ char *kaddr =
+ kmap_atomic(prepared_pages[num_pages - 1],
+ KM_USER0);
+ memset(kaddr + to, 0, PAGE_CACHE_SIZE - to);
+ kunmap_atomic(kaddr, KM_USER0);
}
- if ( !itembuf || /* if first iteration */
- item_pos >= ih_item_len(ih)/UNFM_P_SIZE)
- { /* or if we progressed past the
- current unformatted_item */
- /* Try to find next item */
- res = search_for_position_by_key(inode->i_sb, &key, &path);
- /* Abort if no more items */
- if ( res != POSITION_FOUND ) {
- /* make sure later loops don't use this item */
- itembuf = NULL;
- item = NULL;
- break;
+ /* Since all blocks are new - use already calculated value */
+ return blocks;
+ }
+
+ /* Well, since we write somewhere into the middle of a file, there is
+ possibility we are writing over some already allocated blocks, so
+ let's map these blocks and substract number of such blocks out of blocks
+ we need to allocate (calculated above) */
+ /* Mask write position to start on blocksize, we do it out of the
+ loop for performance reasons */
+ pos &= ~((loff_t) inode->i_sb->s_blocksize - 1);
+ /* Set cpu key to the starting position in a file (on left block boundary) */
+ make_cpu_key(&key, inode,
+ 1 + ((pos) & ~((loff_t) inode->i_sb->s_blocksize - 1)),
+ TYPE_ANY, 3 /*key length */ );
+
+ reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key()
+ for (i = 0; i < num_pages; i++) {
+
+ head = page_buffers(prepared_pages[i]);
+ /* For each buffer in the page */
+ for (bh = head, block_start = 0; bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+ if (!bh)
+ reiserfs_panic(inode->i_sb,
+ "green-9002: Allocated but absent buffer for a page?");
+ /* Find where this buffer ends */
+ block_end = block_start + inode->i_sb->s_blocksize;
+ if (i == 0 && block_end <= from)
+ /* if this buffer is before requested data to map, skip it */
+ continue;
+
+ if (i == num_pages - 1 && block_start >= to) {
+ /* If this buffer is after requested data to map, abort
+ processing of current page */
+ break;
}
- /* Update information about current indirect item */
- itembuf = get_last_bh( &path );
- ih = get_ih( &path );
- item = get_item( &path );
- item_pos = path.pos_in_item;
+ if (buffer_mapped(bh) && bh->b_blocknr != 0) {
+ /* This is optimisation for a case where buffer is mapped
+ and have blocknumber assigned. In case significant amount
+ of such buffers are present, we may avoid some amount
+ of search_by_key calls.
+ Probably it would be possible to move parts of this code
+ out of BKL, but I afraid that would overcomplicate code
+ without any noticeable benefit.
+ */
+ item_pos++;
+ /* Update the key */
+ set_cpu_key_k_offset(&key,
+ cpu_key_k_offset(&key) +
+ inode->i_sb->s_blocksize);
+ blocks--; // Decrease the amount of blocks that need to be
+ // allocated
+ continue; // Go to the next buffer
+ }
- RFALSE( !is_indirect_le_ih (ih), "green-9003: indirect item expected");
- }
+ if (!itembuf || /* if first iteration */
+ item_pos >= ih_item_len(ih) / UNFM_P_SIZE) { /* or if we progressed past the
+ current unformatted_item */
+ /* Try to find next item */
+ res =
+ search_for_position_by_key(inode->i_sb,
+ &key, &path);
+ /* Abort if no more items */
+ if (res != POSITION_FOUND) {
+ /* make sure later loops don't use this item */
+ itembuf = NULL;
+ item = NULL;
+ break;
+ }
+
+ /* Update information about current indirect item */
+ itembuf = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ item_pos = path.pos_in_item;
+
+ RFALSE(!is_indirect_le_ih(ih),
+ "green-9003: indirect item expected");
+ }
- /* See if there is some block associated with the file
- at that position, map the buffer to this block */
- if ( get_block_num(item,item_pos) ) {
- map_bh(bh, inode->i_sb, get_block_num(item,item_pos));
- blocks--; // Decrease the amount of blocks that need to be
- // allocated
+ /* See if there is some block associated with the file
+ at that position, map the buffer to this block */
+ if (get_block_num(item, item_pos)) {
+ map_bh(bh, inode->i_sb,
+ get_block_num(item, item_pos));
+ blocks--; // Decrease the amount of blocks that need to be
+ // allocated
+ }
+ item_pos++;
+ /* Update the key */
+ set_cpu_key_k_offset(&key,
+ cpu_key_k_offset(&key) +
+ inode->i_sb->s_blocksize);
}
- item_pos++;
- /* Update the key */
- set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + inode->i_sb->s_blocksize);
}
- }
- pathrelse(&path); // Free the path
- reiserfs_write_unlock(inode->i_sb);
+ pathrelse(&path); // Free the path
+ reiserfs_write_unlock(inode->i_sb);
/* Now zero out unmappend buffers for the first and last pages of
write area or issue read requests if page is mapped. */
/* First page, see if it is not uptodate */
- if ( !PageUptodate(prepared_pages[0]) ) {
- head = page_buffers(prepared_pages[0]);
-
- /* For each buffer in page */
- for(bh = head, block_start = 0; bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page) {
-
- if (!bh)
- reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
- /* Find where this buffer ends */
- block_end = block_start+inode->i_sb->s_blocksize;
- if ( block_end <= from )
- /* if this buffer is before requested data to map, skip it*/
- continue;
- if ( block_start < from ) { /* Aha, our partial buffer */
- if ( buffer_mapped(bh) ) { /* If it is mapped, we need to
- issue READ request for it to
- not loose data */
- ll_rw_block(READ, 1, &bh);
- *wait_bh++=bh;
- } else { /* Not mapped, zero it */
- char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
- memset(kaddr+block_start, 0, from-block_start);
- kunmap_atomic( kaddr, KM_USER0);
- set_buffer_uptodate(bh);
- }
+ if (!PageUptodate(prepared_pages[0])) {
+ head = page_buffers(prepared_pages[0]);
+
+ /* For each buffer in page */
+ for (bh = head, block_start = 0; bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+
+ if (!bh)
+ reiserfs_panic(inode->i_sb,
+ "green-9002: Allocated but absent buffer for a page?");
+ /* Find where this buffer ends */
+ block_end = block_start + inode->i_sb->s_blocksize;
+ if (block_end <= from)
+ /* if this buffer is before requested data to map, skip it */
+ continue;
+ if (block_start < from) { /* Aha, our partial buffer */
+ if (buffer_mapped(bh)) { /* If it is mapped, we need to
+ issue READ request for it to
+ not loose data */
+ ll_rw_block(READ, 1, &bh);
+ *wait_bh++ = bh;
+ } else { /* Not mapped, zero it */
+ char *kaddr =
+ kmap_atomic(prepared_pages[0],
+ KM_USER0);
+ memset(kaddr + block_start, 0,
+ from - block_start);
+ kunmap_atomic(kaddr, KM_USER0);
+ set_buffer_uptodate(bh);
+ }
+ }
}
- }
}
/* Last page, see if it is not uptodate, or if the last page is past the end of the file. */
- if ( !PageUptodate(prepared_pages[num_pages-1]) ||
- ((pos+write_bytes)>>PAGE_CACHE_SHIFT) > (inode->i_size>>PAGE_CACHE_SHIFT) ) {
- head = page_buffers(prepared_pages[num_pages-1]);
-
- /* for each buffer in page */
- for(bh = head, block_start = 0; bh != head || !block_start;
- block_start=block_end, bh = bh->b_this_page) {
-
- if (!bh)
- reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
- /* Find where this buffer ends */
- block_end = block_start+inode->i_sb->s_blocksize;
- if ( block_start >= to )
- /* if this buffer is after requested data to map, skip it*/
- break;
- if ( block_end > to ) { /* Aha, our partial buffer */
- if ( buffer_mapped(bh) ) { /* If it is mapped, we need to
- issue READ request for it to
- not loose data */
- ll_rw_block(READ, 1, &bh);
- *wait_bh++=bh;
- } else { /* Not mapped, zero it */
- char *kaddr = kmap_atomic(prepared_pages[num_pages-1], KM_USER0);
- memset(kaddr+to, 0, block_end-to);
- kunmap_atomic( kaddr, KM_USER0);
- set_buffer_uptodate(bh);
- }
+ if (!PageUptodate(prepared_pages[num_pages - 1]) ||
+ ((pos + write_bytes) >> PAGE_CACHE_SHIFT) >
+ (inode->i_size >> PAGE_CACHE_SHIFT)) {
+ head = page_buffers(prepared_pages[num_pages - 1]);
+
+ /* for each buffer in page */
+ for (bh = head, block_start = 0; bh != head || !block_start;
+ block_start = block_end, bh = bh->b_this_page) {
+
+ if (!bh)
+ reiserfs_panic(inode->i_sb,
+ "green-9002: Allocated but absent buffer for a page?");
+ /* Find where this buffer ends */
+ block_end = block_start + inode->i_sb->s_blocksize;
+ if (block_start >= to)
+ /* if this buffer is after requested data to map, skip it */
+ break;
+ if (block_end > to) { /* Aha, our partial buffer */
+ if (buffer_mapped(bh)) { /* If it is mapped, we need to
+ issue READ request for it to
+ not loose data */
+ ll_rw_block(READ, 1, &bh);
+ *wait_bh++ = bh;
+ } else { /* Not mapped, zero it */
+ char *kaddr =
+ kmap_atomic(prepared_pages
+ [num_pages - 1],
+ KM_USER0);
+ memset(kaddr + to, 0, block_end - to);
+ kunmap_atomic(kaddr, KM_USER0);
+ set_buffer_uptodate(bh);
+ }
+ }
}
- }
}
- /* Wait for read requests we made to happen, if necessary */
- while(wait_bh > wait) {
- wait_on_buffer(*--wait_bh);
- if (!buffer_uptodate(*wait_bh)) {
- res = -EIO;
- goto failed_read;
+ /* Wait for read requests we made to happen, if necessary */
+ while (wait_bh > wait) {
+ wait_on_buffer(*--wait_bh);
+ if (!buffer_uptodate(*wait_bh)) {
+ res = -EIO;
+ goto failed_read;
+ }
}
- }
-
- return blocks;
-failed_page_grabbing:
- num_pages = i;
-failed_read:
- reiserfs_unprepare_pages(prepared_pages, num_pages);
- return res;
+
+ return blocks;
+ failed_page_grabbing:
+ num_pages = i;
+ failed_read:
+ reiserfs_unprepare_pages(prepared_pages, num_pages);
+ return res;
}
/* Write @count bytes at position @ppos in a file indicated by @file
@@ -1148,262 +1265,305 @@ failed_read:
Future Features: providing search_by_key with hints.
*/
-static ssize_t reiserfs_file_write( struct file *file, /* the file we are going to write into */
- const char __user *buf, /* pointer to user supplied data
-(in userspace) */
- size_t count, /* amount of bytes to write */
- loff_t *ppos /* pointer to position in file that we start writing at. Should be updated to
- * new current position before returning. */ )
+static ssize_t reiserfs_file_write(struct file *file, /* the file we are going to write into */
+ const char __user * buf, /* pointer to user supplied data
+ (in userspace) */
+ size_t count, /* amount of bytes to write */
+ loff_t * ppos /* pointer to position in file that we start writing at. Should be updated to
+ * new current position before returning. */
+ )
{
- size_t already_written = 0; // Number of bytes already written to the file.
- loff_t pos; // Current position in the file.
- ssize_t res; // return value of various functions that we call.
- int err = 0;
- struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
- /* To simplify coding at this time, we store
- locked pages in array for now */
- struct page * prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME];
- struct reiserfs_transaction_handle th;
- th.t_trans_id = 0;
-
- if ( file->f_flags & O_DIRECT) { // Direct IO needs treatment
- ssize_t result, after_file_end = 0;
- if ( (*ppos + count >= inode->i_size) || (file->f_flags & O_APPEND) ) {
- /* If we are appending a file, we need to put this savelink in here.
- If we will crash while doing direct io, finish_unfinished will
- cut the garbage from the file end. */
- reiserfs_write_lock(inode->i_sb);
- err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
- if (err) {
- reiserfs_write_unlock (inode->i_sb);
- return err;
- }
- reiserfs_update_inode_transaction(inode);
- add_save_link (&th, inode, 1 /* Truncate */);
- after_file_end = 1;
- err = journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT );
- reiserfs_write_unlock(inode->i_sb);
- if (err)
- return err;
- }
- result = generic_file_write(file, buf, count, ppos);
-
- if ( after_file_end ) { /* Now update i_size and remove the savelink */
- struct reiserfs_transaction_handle th;
- reiserfs_write_lock(inode->i_sb);
- err = journal_begin(&th, inode->i_sb, 1);
- if (err) {
- reiserfs_write_unlock (inode->i_sb);
- return err;
- }
- reiserfs_update_inode_transaction(inode);
- reiserfs_update_sd(&th, inode);
- err = journal_end(&th, inode->i_sb, 1);
- if (err) {
- reiserfs_write_unlock (inode->i_sb);
- return err;
- }
- err = remove_save_link (inode, 1/* truncate */);
- reiserfs_write_unlock(inode->i_sb);
- if (err)
- return err;
- }
-
- return result;
- }
-
- if ( unlikely((ssize_t) count < 0 ))
- return -EINVAL;
-
- if (unlikely(!access_ok(VERIFY_READ, buf, count)))
- return -EFAULT;
-
- down(&inode->i_sem); // locks the entire file for just us
-
- pos = *ppos;
-
- /* Check if we can write to specified region of file, file
- is not overly big and this kind of stuff. Adjust pos and
- count, if needed */
- res = generic_write_checks(file, &pos, &count, 0);
- if (res)
- goto out;
-
- if ( count == 0 )
- goto out;
-
- res = remove_suid(file->f_dentry);
- if (res)
- goto out;
-
- inode_update_time(inode, 1); /* Both mtime and ctime */
-
- // Ok, we are done with all the checks.
+ size_t already_written = 0; // Number of bytes already written to the file.
+ loff_t pos; // Current position in the file.
+ ssize_t res; // return value of various functions that we call.
+ int err = 0;
+ struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
+ /* To simplify coding at this time, we store
+ locked pages in array for now */
+ struct page *prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME];
+ struct reiserfs_transaction_handle th;
+ th.t_trans_id = 0;
+
+ if (file->f_flags & O_DIRECT) { // Direct IO needs treatment
+ ssize_t result, after_file_end = 0;
+ if ((*ppos + count >= inode->i_size)
+ || (file->f_flags & O_APPEND)) {
+ /* If we are appending a file, we need to put this savelink in here.
+ If we will crash while doing direct io, finish_unfinished will
+ cut the garbage from the file end. */
+ reiserfs_write_lock(inode->i_sb);
+ err =
+ journal_begin(&th, inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT);
+ if (err) {
+ reiserfs_write_unlock(inode->i_sb);
+ return err;
+ }
+ reiserfs_update_inode_transaction(inode);
+ add_save_link(&th, inode, 1 /* Truncate */ );
+ after_file_end = 1;
+ err =
+ journal_end(&th, inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT);
+ reiserfs_write_unlock(inode->i_sb);
+ if (err)
+ return err;
+ }
+ result = generic_file_write(file, buf, count, ppos);
+
+ if (after_file_end) { /* Now update i_size and remove the savelink */
+ struct reiserfs_transaction_handle th;
+ reiserfs_write_lock(inode->i_sb);
+ err = journal_begin(&th, inode->i_sb, 1);
+ if (err) {
+ reiserfs_write_unlock(inode->i_sb);
+ return err;
+ }
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_sd(&th, inode);
+ err = journal_end(&th, inode->i_sb, 1);
+ if (err) {
+ reiserfs_write_unlock(inode->i_sb);
+ return err;
+ }
+ err = remove_save_link(inode, 1 /* truncate */ );
+ reiserfs_write_unlock(inode->i_sb);
+ if (err)
+ return err;
+ }
- // Now we should start real work
+ return result;
+ }
- /* If we are going to write past the file's packed tail or if we are going
- to overwrite part of the tail, we need that tail to be converted into
- unformatted node */
- res = reiserfs_check_for_tail_and_convert( inode, pos, count);
- if (res)
- goto out;
+ if (unlikely((ssize_t) count < 0))
+ return -EINVAL;
+
+ if (unlikely(!access_ok(VERIFY_READ, buf, count)))
+ return -EFAULT;
+
+ down(&inode->i_sem); // locks the entire file for just us
+
+ pos = *ppos;
+
+ /* Check if we can write to specified region of file, file
+ is not overly big and this kind of stuff. Adjust pos and
+ count, if needed */
+ res = generic_write_checks(file, &pos, &count, 0);
+ if (res)
+ goto out;
+
+ if (count == 0)
+ goto out;
+
+ res = remove_suid(file->f_dentry);
+ if (res)
+ goto out;
+
+ inode_update_time(inode, 1); /* Both mtime and ctime */
+
+ // Ok, we are done with all the checks.
+
+ // Now we should start real work
+
+ /* If we are going to write past the file's packed tail or if we are going
+ to overwrite part of the tail, we need that tail to be converted into
+ unformatted node */
+ res = reiserfs_check_for_tail_and_convert(inode, pos, count);
+ if (res)
+ goto out;
+
+ while (count > 0) {
+ /* This is the main loop in which we running until some error occures
+ or until we write all of the data. */
+ size_t num_pages; /* amount of pages we are going to write this iteration */
+ size_t write_bytes; /* amount of bytes to write during this iteration */
+ size_t blocks_to_allocate; /* how much blocks we need to allocate for this iteration */
+
+ /* (pos & (PAGE_CACHE_SIZE-1)) is an idiom for offset into a page of pos */
+ num_pages = !!((pos + count) & (PAGE_CACHE_SIZE - 1)) + /* round up partial
+ pages */
+ ((count +
+ (pos & (PAGE_CACHE_SIZE - 1))) >> PAGE_CACHE_SHIFT);
+ /* convert size to amount of
+ pages */
+ reiserfs_write_lock(inode->i_sb);
+ if (num_pages > REISERFS_WRITE_PAGES_AT_A_TIME
+ || num_pages > reiserfs_can_fit_pages(inode->i_sb)) {
+ /* If we were asked to write more data than we want to or if there
+ is not that much space, then we shorten amount of data to write
+ for this iteration. */
+ num_pages =
+ min_t(size_t, REISERFS_WRITE_PAGES_AT_A_TIME,
+ reiserfs_can_fit_pages(inode->i_sb));
+ /* Also we should not forget to set size in bytes accordingly */
+ write_bytes = (num_pages << PAGE_CACHE_SHIFT) -
+ (pos & (PAGE_CACHE_SIZE - 1));
+ /* If position is not on the
+ start of the page, we need
+ to substract the offset
+ within page */
+ } else
+ write_bytes = count;
+
+ /* reserve the blocks to be allocated later, so that later on
+ we still have the space to write the blocks to */
+ reiserfs_claim_blocks_to_be_allocated(inode->i_sb,
+ num_pages <<
+ (PAGE_CACHE_SHIFT -
+ inode->i_blkbits));
+ reiserfs_write_unlock(inode->i_sb);
+
+ if (!num_pages) { /* If we do not have enough space even for a single page... */
+ if (pos >
+ inode->i_size + inode->i_sb->s_blocksize -
+ (pos & (inode->i_sb->s_blocksize - 1))) {
+ res = -ENOSPC;
+ break; // In case we are writing past the end of the last file block, break.
+ }
+ // Otherwise we are possibly overwriting the file, so
+ // let's set write size to be equal or less than blocksize.
+ // This way we get it correctly for file holes.
+ // But overwriting files on absolutelly full volumes would not
+ // be very efficient. Well, people are not supposed to fill
+ // 100% of disk space anyway.
+ write_bytes =
+ min_t(size_t, count,
+ inode->i_sb->s_blocksize -
+ (pos & (inode->i_sb->s_blocksize - 1)));
+ num_pages = 1;
+ // No blocks were claimed before, so do it now.
+ reiserfs_claim_blocks_to_be_allocated(inode->i_sb,
+ 1 <<
+ (PAGE_CACHE_SHIFT
+ -
+ inode->
+ i_blkbits));
+ }
- while ( count > 0) {
- /* This is the main loop in which we running until some error occures
- or until we write all of the data. */
- size_t num_pages;/* amount of pages we are going to write this iteration */
- size_t write_bytes; /* amount of bytes to write during this iteration */
- size_t blocks_to_allocate; /* how much blocks we need to allocate for this iteration */
-
- /* (pos & (PAGE_CACHE_SIZE-1)) is an idiom for offset into a page of pos*/
- num_pages = !!((pos+count) & (PAGE_CACHE_SIZE - 1)) + /* round up partial
- pages */
- ((count + (pos & (PAGE_CACHE_SIZE-1))) >> PAGE_CACHE_SHIFT);
- /* convert size to amount of
- pages */
- reiserfs_write_lock(inode->i_sb);
- if ( num_pages > REISERFS_WRITE_PAGES_AT_A_TIME
- || num_pages > reiserfs_can_fit_pages(inode->i_sb) ) {
- /* If we were asked to write more data than we want to or if there
- is not that much space, then we shorten amount of data to write
- for this iteration. */
- num_pages = min_t(size_t, REISERFS_WRITE_PAGES_AT_A_TIME, reiserfs_can_fit_pages(inode->i_sb));
- /* Also we should not forget to set size in bytes accordingly */
- write_bytes = (num_pages << PAGE_CACHE_SHIFT) -
- (pos & (PAGE_CACHE_SIZE-1));
- /* If position is not on the
- start of the page, we need
- to substract the offset
- within page */
- } else
- write_bytes = count;
+ /* Prepare for writing into the region, read in all the
+ partially overwritten pages, if needed. And lock the pages,
+ so that nobody else can access these until we are done.
+ We get number of actual blocks needed as a result. */
+ blocks_to_allocate =
+ reiserfs_prepare_file_region_for_write(inode, pos,
+ num_pages,
+ write_bytes,
+ prepared_pages);
+ if (blocks_to_allocate < 0) {
+ res = blocks_to_allocate;
+ reiserfs_release_claimed_blocks(inode->i_sb,
+ num_pages <<
+ (PAGE_CACHE_SHIFT -
+ inode->i_blkbits));
+ break;
+ }
- /* reserve the blocks to be allocated later, so that later on
- we still have the space to write the blocks to */
- reiserfs_claim_blocks_to_be_allocated(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
- reiserfs_write_unlock(inode->i_sb);
+ /* First we correct our estimate of how many blocks we need */
+ reiserfs_release_claimed_blocks(inode->i_sb,
+ (num_pages <<
+ (PAGE_CACHE_SHIFT -
+ inode->i_sb->
+ s_blocksize_bits)) -
+ blocks_to_allocate);
+
+ if (blocks_to_allocate > 0) { /*We only allocate blocks if we need to */
+ /* Fill in all the possible holes and append the file if needed */
+ res =
+ reiserfs_allocate_blocks_for_region(&th, inode, pos,
+ num_pages,
+ write_bytes,
+ prepared_pages,
+ blocks_to_allocate);
+ }
- if ( !num_pages ) { /* If we do not have enough space even for a single page... */
- if ( pos > inode->i_size+inode->i_sb->s_blocksize-(pos & (inode->i_sb->s_blocksize-1))) {
- res = -ENOSPC;
- break; // In case we are writing past the end of the last file block, break.
- }
- // Otherwise we are possibly overwriting the file, so
- // let's set write size to be equal or less than blocksize.
- // This way we get it correctly for file holes.
- // But overwriting files on absolutelly full volumes would not
- // be very efficient. Well, people are not supposed to fill
- // 100% of disk space anyway.
- write_bytes = min_t(size_t, count, inode->i_sb->s_blocksize - (pos & (inode->i_sb->s_blocksize - 1)));
- num_pages = 1;
- // No blocks were claimed before, so do it now.
- reiserfs_claim_blocks_to_be_allocated(inode->i_sb, 1 << (PAGE_CACHE_SHIFT - inode->i_blkbits));
- }
+ /* well, we have allocated the blocks, so it is time to free
+ the reservation we made earlier. */
+ reiserfs_release_claimed_blocks(inode->i_sb,
+ blocks_to_allocate);
+ if (res) {
+ reiserfs_unprepare_pages(prepared_pages, num_pages);
+ break;
+ }
- /* Prepare for writing into the region, read in all the
- partially overwritten pages, if needed. And lock the pages,
- so that nobody else can access these until we are done.
- We get number of actual blocks needed as a result.*/
- blocks_to_allocate = reiserfs_prepare_file_region_for_write(inode, pos, num_pages, write_bytes, prepared_pages);
- if ( blocks_to_allocate < 0 ) {
- res = blocks_to_allocate;
- reiserfs_release_claimed_blocks(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
- break;
- }
+/* NOTE that allocating blocks and filling blocks can be done in reverse order
+ and probably we would do that just to get rid of garbage in files after a
+ crash */
- /* First we correct our estimate of how many blocks we need */
- reiserfs_release_claimed_blocks(inode->i_sb, (num_pages << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits)) - blocks_to_allocate );
+ /* Copy data from user-supplied buffer to file's pages */
+ res =
+ reiserfs_copy_from_user_to_file_region(pos, num_pages,
+ write_bytes,
+ prepared_pages, buf);
+ if (res) {
+ reiserfs_unprepare_pages(prepared_pages, num_pages);
+ break;
+ }
- if ( blocks_to_allocate > 0) {/*We only allocate blocks if we need to*/
- /* Fill in all the possible holes and append the file if needed */
- res = reiserfs_allocate_blocks_for_region(&th, inode, pos, num_pages, write_bytes, prepared_pages, blocks_to_allocate);
+ /* Send the pages to disk and unlock them. */
+ res =
+ reiserfs_submit_file_region_for_write(&th, inode, pos,
+ num_pages,
+ write_bytes,
+ prepared_pages);
+ if (res)
+ break;
+
+ already_written += write_bytes;
+ buf += write_bytes;
+ *ppos = pos += write_bytes;
+ count -= write_bytes;
+ balance_dirty_pages_ratelimited(inode->i_mapping);
}
- /* well, we have allocated the blocks, so it is time to free
- the reservation we made earlier. */
- reiserfs_release_claimed_blocks(inode->i_sb, blocks_to_allocate);
- if ( res ) {
- reiserfs_unprepare_pages(prepared_pages, num_pages);
- break;
+ /* this is only true on error */
+ if (th.t_trans_id) {
+ reiserfs_write_lock(inode->i_sb);
+ err = journal_end(&th, th.t_super, th.t_blocks_allocated);
+ reiserfs_write_unlock(inode->i_sb);
+ if (err) {
+ res = err;
+ goto out;
+ }
}
-/* NOTE that allocating blocks and filling blocks can be done in reverse order
- and probably we would do that just to get rid of garbage in files after a
- crash */
+ if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
+ res =
+ generic_osync_inode(inode, file->f_mapping,
+ OSYNC_METADATA | OSYNC_DATA);
- /* Copy data from user-supplied buffer to file's pages */
- res = reiserfs_copy_from_user_to_file_region(pos, num_pages, write_bytes, prepared_pages, buf);
- if ( res ) {
- reiserfs_unprepare_pages(prepared_pages, num_pages);
- break;
- }
+ up(&inode->i_sem);
+ reiserfs_async_progress_wait(inode->i_sb);
+ return (already_written != 0) ? already_written : res;
- /* Send the pages to disk and unlock them. */
- res = reiserfs_submit_file_region_for_write(&th, inode, pos, num_pages,
- write_bytes,prepared_pages);
- if ( res )
- break;
-
- already_written += write_bytes;
- buf += write_bytes;
- *ppos = pos += write_bytes;
- count -= write_bytes;
- balance_dirty_pages_ratelimited(inode->i_mapping);
- }
-
- /* this is only true on error */
- if (th.t_trans_id) {
- reiserfs_write_lock(inode->i_sb);
- err = journal_end(&th, th.t_super, th.t_blocks_allocated);
- reiserfs_write_unlock(inode->i_sb);
- if (err) {
- res = err;
- goto out;
- }
- }
-
- if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
- res = generic_osync_inode(inode, file->f_mapping, OSYNC_METADATA|OSYNC_DATA);
-
- up(&inode->i_sem);
- reiserfs_async_progress_wait(inode->i_sb);
- return (already_written != 0)?already_written:res;
-
-out:
- up(&inode->i_sem); // unlock the file on exit.
- return res;
+ out:
+ up(&inode->i_sem); // unlock the file on exit.
+ return res;
}
-static ssize_t reiserfs_aio_write(struct kiocb *iocb, const char __user *buf,
- size_t count, loff_t pos)
+static ssize_t reiserfs_aio_write(struct kiocb *iocb, const char __user * buf,
+ size_t count, loff_t pos)
{
- return generic_file_aio_write(iocb, buf, count, pos);
+ return generic_file_aio_write(iocb, buf, count, pos);
}
-
-
struct file_operations reiserfs_file_operations = {
- .read = generic_file_read,
- .write = reiserfs_file_write,
- .ioctl = reiserfs_ioctl,
- .mmap = generic_file_mmap,
- .release = reiserfs_file_release,
- .fsync = reiserfs_sync_file,
- .sendfile = generic_file_sendfile,
- .aio_read = generic_file_aio_read,
- .aio_write = reiserfs_aio_write,
+ .read = generic_file_read,
+ .write = reiserfs_file_write,
+ .ioctl = reiserfs_ioctl,
+ .mmap = generic_file_mmap,
+ .release = reiserfs_file_release,
+ .fsync = reiserfs_sync_file,
+ .sendfile = generic_file_sendfile,
+ .aio_read = generic_file_aio_read,
+ .aio_write = reiserfs_aio_write,
};
-
-struct inode_operations reiserfs_file_inode_operations = {
- .truncate = reiserfs_vfs_truncate_file,
- .setattr = reiserfs_setattr,
- .setxattr = reiserfs_setxattr,
- .getxattr = reiserfs_getxattr,
- .listxattr = reiserfs_listxattr,
- .removexattr = reiserfs_removexattr,
- .permission = reiserfs_permission,
+struct inode_operations reiserfs_file_inode_operations = {
+ .truncate = reiserfs_vfs_truncate_file,
+ .setattr = reiserfs_setattr,
+ .setxattr = reiserfs_setxattr,
+ .getxattr = reiserfs_getxattr,
+ .listxattr = reiserfs_listxattr,
+ .removexattr = reiserfs_removexattr,
+ .permission = reiserfs_permission,
};
-
-
diff --git a/fs/reiserfs/fix_node.c b/fs/reiserfs/fix_node.c
index e4f64be9e15b..2706e2adffab 100644
--- a/fs/reiserfs/fix_node.c
+++ b/fs/reiserfs/fix_node.c
@@ -34,14 +34,12 @@
**
**/
-
#include <linux/config.h>
#include <linux/time.h>
#include <linux/string.h>
#include <linux/reiserfs_fs.h>
#include <linux/buffer_head.h>
-
/* To make any changes in the tree we find a node, that contains item
to be changed/deleted or position in the node we insert a new item
to. We call this node S. To do balancing we need to decide what we
@@ -56,490 +54,522 @@
have to have if we do not any shiftings, if we shift to left/right
neighbor or to both. */
-
/* taking item number in virtual node, returns number of item, that it has in source buffer */
-static inline int old_item_num (int new_num, int affected_item_num, int mode)
+static inline int old_item_num(int new_num, int affected_item_num, int mode)
{
- if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num)
- return new_num;
+ if (mode == M_PASTE || mode == M_CUT || new_num < affected_item_num)
+ return new_num;
- if (mode == M_INSERT) {
+ if (mode == M_INSERT) {
- RFALSE( new_num == 0,
- "vs-8005: for INSERT mode and item number of inserted item");
+ RFALSE(new_num == 0,
+ "vs-8005: for INSERT mode and item number of inserted item");
- return new_num - 1;
- }
+ return new_num - 1;
+ }
- RFALSE( mode != M_DELETE,
- "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'", mode);
- /* delete mode */
- return new_num + 1;
+ RFALSE(mode != M_DELETE,
+ "vs-8010: old_item_num: mode must be M_DELETE (mode = \'%c\'",
+ mode);
+ /* delete mode */
+ return new_num + 1;
}
-static void create_virtual_node (struct tree_balance * tb, int h)
+static void create_virtual_node(struct tree_balance *tb, int h)
{
- struct item_head * ih;
- struct virtual_node * vn = tb->tb_vn;
- int new_num;
- struct buffer_head * Sh; /* this comes from tb->S[h] */
+ struct item_head *ih;
+ struct virtual_node *vn = tb->tb_vn;
+ int new_num;
+ struct buffer_head *Sh; /* this comes from tb->S[h] */
- Sh = PATH_H_PBUFFER (tb->tb_path, h);
+ Sh = PATH_H_PBUFFER(tb->tb_path, h);
- /* size of changed node */
- vn->vn_size = MAX_CHILD_SIZE (Sh) - B_FREE_SPACE (Sh) + tb->insert_size[h];
+ /* size of changed node */
+ vn->vn_size =
+ MAX_CHILD_SIZE(Sh) - B_FREE_SPACE(Sh) + tb->insert_size[h];
- /* for internal nodes array if virtual items is not created */
- if (h) {
- vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE);
- return;
- }
-
- /* number of items in virtual node */
- vn->vn_nr_item = B_NR_ITEMS (Sh) + ((vn->vn_mode == M_INSERT)? 1 : 0) - ((vn->vn_mode == M_DELETE)? 1 : 0);
-
- /* first virtual item */
- vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1);
- memset (vn->vn_vi, 0, vn->vn_nr_item * sizeof (struct virtual_item));
- vn->vn_free_ptr += vn->vn_nr_item * sizeof (struct virtual_item);
-
-
- /* first item in the node */
- ih = B_N_PITEM_HEAD (Sh, 0);
-
- /* define the mergeability for 0-th item (if it is not being deleted) */
- if (op_is_left_mergeable (&(ih->ih_key), Sh->b_size) && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num))
- vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE;
-
- /* go through all items those remain in the virtual node (except for the new (inserted) one) */
- for (new_num = 0; new_num < vn->vn_nr_item; new_num ++) {
- int j;
- struct virtual_item * vi = vn->vn_vi + new_num;
- int is_affected = ((new_num != vn->vn_affected_item_num) ? 0 : 1);
-
-
- if (is_affected && vn->vn_mode == M_INSERT)
- continue;
-
- /* get item number in source node */
- j = old_item_num (new_num, vn->vn_affected_item_num, vn->vn_mode);
-
- vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE;
- vi->vi_ih = ih + j;
- vi->vi_item = B_I_PITEM (Sh, ih + j);
- vi->vi_uarea = vn->vn_free_ptr;
-
- // FIXME: there is no check, that item operation did not
- // consume too much memory
- vn->vn_free_ptr += op_create_vi (vn, vi, is_affected, tb->insert_size [0]);
- if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr)
- reiserfs_panic (tb->tb_sb, "vs-8030: create_virtual_node: "
- "virtual node space consumed");
-
- if (!is_affected)
- /* this is not being changed */
- continue;
-
- if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) {
- vn->vn_vi[new_num].vi_item_len += tb->insert_size[0];
- vi->vi_new_data = vn->vn_data; // pointer to data which is going to be pasted
+ /* for internal nodes array if virtual items is not created */
+ if (h) {
+ vn->vn_nr_item = (vn->vn_size - DC_SIZE) / (DC_SIZE + KEY_SIZE);
+ return;
}
- }
-
-
- /* virtual inserted item is not defined yet */
- if (vn->vn_mode == M_INSERT) {
- struct virtual_item * vi = vn->vn_vi + vn->vn_affected_item_num;
-
- RFALSE( vn->vn_ins_ih == 0,
- "vs-8040: item header of inserted item is not specified");
- vi->vi_item_len = tb->insert_size[0];
- vi->vi_ih = vn->vn_ins_ih;
- vi->vi_item = vn->vn_data;
- vi->vi_uarea = vn->vn_free_ptr;
-
- op_create_vi (vn, vi, 0/*not pasted or cut*/, tb->insert_size [0]);
- }
-
- /* set right merge flag we take right delimiting key and check whether it is a mergeable item */
- if (tb->CFR[0]) {
- struct reiserfs_key * key;
-
- key = B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0]);
- if (op_is_left_mergeable (key, Sh->b_size) && (vn->vn_mode != M_DELETE ||
- vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1))
- vn->vn_vi[vn->vn_nr_item-1].vi_type |= VI_TYPE_RIGHT_MERGEABLE;
-#ifdef CONFIG_REISERFS_CHECK
- if (op_is_left_mergeable (key, Sh->b_size) &&
- !(vn->vn_mode != M_DELETE || vn->vn_affected_item_num != B_NR_ITEMS (Sh) - 1) ) {
- /* we delete last item and it could be merged with right neighbor's first item */
- if (!(B_NR_ITEMS (Sh) == 1 && is_direntry_le_ih (B_N_PITEM_HEAD (Sh, 0)) &&
- I_ENTRY_COUNT (B_N_PITEM_HEAD (Sh, 0)) == 1)) {
- /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */
- print_block (Sh, 0, -1, -1);
- reiserfs_panic (tb->tb_sb, "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c",
- key, vn->vn_affected_item_num, vn->vn_mode, M_DELETE);
- } else
- /* we can delete directory item, that has only one directory entry in it */
- ;
+ /* number of items in virtual node */
+ vn->vn_nr_item =
+ B_NR_ITEMS(Sh) + ((vn->vn_mode == M_INSERT) ? 1 : 0) -
+ ((vn->vn_mode == M_DELETE) ? 1 : 0);
+
+ /* first virtual item */
+ vn->vn_vi = (struct virtual_item *)(tb->tb_vn + 1);
+ memset(vn->vn_vi, 0, vn->vn_nr_item * sizeof(struct virtual_item));
+ vn->vn_free_ptr += vn->vn_nr_item * sizeof(struct virtual_item);
+
+ /* first item in the node */
+ ih = B_N_PITEM_HEAD(Sh, 0);
+
+ /* define the mergeability for 0-th item (if it is not being deleted) */
+ if (op_is_left_mergeable(&(ih->ih_key), Sh->b_size)
+ && (vn->vn_mode != M_DELETE || vn->vn_affected_item_num))
+ vn->vn_vi[0].vi_type |= VI_TYPE_LEFT_MERGEABLE;
+
+ /* go through all items those remain in the virtual node (except for the new (inserted) one) */
+ for (new_num = 0; new_num < vn->vn_nr_item; new_num++) {
+ int j;
+ struct virtual_item *vi = vn->vn_vi + new_num;
+ int is_affected =
+ ((new_num != vn->vn_affected_item_num) ? 0 : 1);
+
+ if (is_affected && vn->vn_mode == M_INSERT)
+ continue;
+
+ /* get item number in source node */
+ j = old_item_num(new_num, vn->vn_affected_item_num,
+ vn->vn_mode);
+
+ vi->vi_item_len += ih_item_len(ih + j) + IH_SIZE;
+ vi->vi_ih = ih + j;
+ vi->vi_item = B_I_PITEM(Sh, ih + j);
+ vi->vi_uarea = vn->vn_free_ptr;
+
+ // FIXME: there is no check, that item operation did not
+ // consume too much memory
+ vn->vn_free_ptr +=
+ op_create_vi(vn, vi, is_affected, tb->insert_size[0]);
+ if (tb->vn_buf + tb->vn_buf_size < vn->vn_free_ptr)
+ reiserfs_panic(tb->tb_sb,
+ "vs-8030: create_virtual_node: "
+ "virtual node space consumed");
+
+ if (!is_affected)
+ /* this is not being changed */
+ continue;
+
+ if (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT) {
+ vn->vn_vi[new_num].vi_item_len += tb->insert_size[0];
+ vi->vi_new_data = vn->vn_data; // pointer to data which is going to be pasted
+ }
}
+
+ /* virtual inserted item is not defined yet */
+ if (vn->vn_mode == M_INSERT) {
+ struct virtual_item *vi = vn->vn_vi + vn->vn_affected_item_num;
+
+ RFALSE(vn->vn_ins_ih == 0,
+ "vs-8040: item header of inserted item is not specified");
+ vi->vi_item_len = tb->insert_size[0];
+ vi->vi_ih = vn->vn_ins_ih;
+ vi->vi_item = vn->vn_data;
+ vi->vi_uarea = vn->vn_free_ptr;
+
+ op_create_vi(vn, vi, 0 /*not pasted or cut */ ,
+ tb->insert_size[0]);
+ }
+
+ /* set right merge flag we take right delimiting key and check whether it is a mergeable item */
+ if (tb->CFR[0]) {
+ struct reiserfs_key *key;
+
+ key = B_N_PDELIM_KEY(tb->CFR[0], tb->rkey[0]);
+ if (op_is_left_mergeable(key, Sh->b_size)
+ && (vn->vn_mode != M_DELETE
+ || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1))
+ vn->vn_vi[vn->vn_nr_item - 1].vi_type |=
+ VI_TYPE_RIGHT_MERGEABLE;
+
+#ifdef CONFIG_REISERFS_CHECK
+ if (op_is_left_mergeable(key, Sh->b_size) &&
+ !(vn->vn_mode != M_DELETE
+ || vn->vn_affected_item_num != B_NR_ITEMS(Sh) - 1)) {
+ /* we delete last item and it could be merged with right neighbor's first item */
+ if (!
+ (B_NR_ITEMS(Sh) == 1
+ && is_direntry_le_ih(B_N_PITEM_HEAD(Sh, 0))
+ && I_ENTRY_COUNT(B_N_PITEM_HEAD(Sh, 0)) == 1)) {
+ /* node contains more than 1 item, or item is not directory item, or this item contains more than 1 entry */
+ print_block(Sh, 0, -1, -1);
+ reiserfs_panic(tb->tb_sb,
+ "vs-8045: create_virtual_node: rdkey %k, affected item==%d (mode==%c) Must be %c",
+ key, vn->vn_affected_item_num,
+ vn->vn_mode, M_DELETE);
+ } else
+ /* we can delete directory item, that has only one directory entry in it */
+ ;
+ }
#endif
-
- }
-}
+ }
+}
/* using virtual node check, how many items can be shifted to left
neighbor */
-static void check_left (struct tree_balance * tb, int h, int cur_free)
+static void check_left(struct tree_balance *tb, int h, int cur_free)
{
- int i;
- struct virtual_node * vn = tb->tb_vn;
- struct virtual_item * vi;
- int d_size, ih_size;
+ int i;
+ struct virtual_node *vn = tb->tb_vn;
+ struct virtual_item *vi;
+ int d_size, ih_size;
- RFALSE( cur_free < 0, "vs-8050: cur_free (%d) < 0", cur_free);
+ RFALSE(cur_free < 0, "vs-8050: cur_free (%d) < 0", cur_free);
- /* internal level */
- if (h > 0) {
- tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
- return;
- }
+ /* internal level */
+ if (h > 0) {
+ tb->lnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
+ return;
+ }
- /* leaf level */
+ /* leaf level */
- if (!cur_free || !vn->vn_nr_item) {
- /* no free space or nothing to move */
- tb->lnum[h] = 0;
- tb->lbytes = -1;
- return;
- }
+ if (!cur_free || !vn->vn_nr_item) {
+ /* no free space or nothing to move */
+ tb->lnum[h] = 0;
+ tb->lbytes = -1;
+ return;
+ }
- RFALSE( !PATH_H_PPARENT (tb->tb_path, 0),
- "vs-8055: parent does not exist or invalid");
+ RFALSE(!PATH_H_PPARENT(tb->tb_path, 0),
+ "vs-8055: parent does not exist or invalid");
- vi = vn->vn_vi;
- if ((unsigned int)cur_free >= (vn->vn_size - ((vi->vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) {
- /* all contents of S[0] fits into L[0] */
+ vi = vn->vn_vi;
+ if ((unsigned int)cur_free >=
+ (vn->vn_size -
+ ((vi->vi_type & VI_TYPE_LEFT_MERGEABLE) ? IH_SIZE : 0))) {
+ /* all contents of S[0] fits into L[0] */
- RFALSE( vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE,
- "vs-8055: invalid mode or balance condition failed");
+ RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE,
+ "vs-8055: invalid mode or balance condition failed");
- tb->lnum[0] = vn->vn_nr_item;
- tb->lbytes = -1;
- return;
- }
-
-
- d_size = 0, ih_size = IH_SIZE;
-
- /* first item may be merge with last item in left neighbor */
- if (vi->vi_type & VI_TYPE_LEFT_MERGEABLE)
- d_size = -((int)IH_SIZE), ih_size = 0;
-
- tb->lnum[0] = 0;
- for (i = 0; i < vn->vn_nr_item; i ++, ih_size = IH_SIZE, d_size = 0, vi ++) {
- d_size += vi->vi_item_len;
- if (cur_free >= d_size) {
- /* the item can be shifted entirely */
- cur_free -= d_size;
- tb->lnum[0] ++;
- continue;
+ tb->lnum[0] = vn->vn_nr_item;
+ tb->lbytes = -1;
+ return;
}
-
- /* the item cannot be shifted entirely, try to split it */
- /* check whether L[0] can hold ih and at least one byte of the item body */
- if (cur_free <= ih_size) {
- /* cannot shift even a part of the current item */
- tb->lbytes = -1;
- return;
+
+ d_size = 0, ih_size = IH_SIZE;
+
+ /* first item may be merge with last item in left neighbor */
+ if (vi->vi_type & VI_TYPE_LEFT_MERGEABLE)
+ d_size = -((int)IH_SIZE), ih_size = 0;
+
+ tb->lnum[0] = 0;
+ for (i = 0; i < vn->vn_nr_item;
+ i++, ih_size = IH_SIZE, d_size = 0, vi++) {
+ d_size += vi->vi_item_len;
+ if (cur_free >= d_size) {
+ /* the item can be shifted entirely */
+ cur_free -= d_size;
+ tb->lnum[0]++;
+ continue;
+ }
+
+ /* the item cannot be shifted entirely, try to split it */
+ /* check whether L[0] can hold ih and at least one byte of the item body */
+ if (cur_free <= ih_size) {
+ /* cannot shift even a part of the current item */
+ tb->lbytes = -1;
+ return;
+ }
+ cur_free -= ih_size;
+
+ tb->lbytes = op_check_left(vi, cur_free, 0, 0);
+ if (tb->lbytes != -1)
+ /* count partially shifted item */
+ tb->lnum[0]++;
+
+ break;
}
- cur_free -= ih_size;
-
- tb->lbytes = op_check_left (vi, cur_free, 0, 0);
- if (tb->lbytes != -1)
- /* count partially shifted item */
- tb->lnum[0] ++;
-
- break;
- }
-
- return;
-}
+ return;
+}
/* using virtual node check, how many items can be shifted to right
neighbor */
-static void check_right (struct tree_balance * tb, int h, int cur_free)
+static void check_right(struct tree_balance *tb, int h, int cur_free)
{
- int i;
- struct virtual_node * vn = tb->tb_vn;
- struct virtual_item * vi;
- int d_size, ih_size;
-
- RFALSE( cur_free < 0, "vs-8070: cur_free < 0");
-
- /* internal level */
- if (h > 0) {
- tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
- return;
- }
-
- /* leaf level */
-
- if (!cur_free || !vn->vn_nr_item) {
- /* no free space */
- tb->rnum[h] = 0;
- tb->rbytes = -1;
- return;
- }
-
- RFALSE( !PATH_H_PPARENT (tb->tb_path, 0),
- "vs-8075: parent does not exist or invalid");
-
- vi = vn->vn_vi + vn->vn_nr_item - 1;
- if ((unsigned int)cur_free >= (vn->vn_size - ((vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) {
- /* all contents of S[0] fits into R[0] */
-
- RFALSE( vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE,
- "vs-8080: invalid mode or balance condition failed");
-
- tb->rnum[h] = vn->vn_nr_item;
- tb->rbytes = -1;
- return;
- }
-
- d_size = 0, ih_size = IH_SIZE;
-
- /* last item may be merge with first item in right neighbor */
- if (vi->vi_type & VI_TYPE_RIGHT_MERGEABLE)
- d_size = -(int)IH_SIZE, ih_size = 0;
-
- tb->rnum[0] = 0;
- for (i = vn->vn_nr_item - 1; i >= 0; i --, d_size = 0, ih_size = IH_SIZE, vi --) {
- d_size += vi->vi_item_len;
- if (cur_free >= d_size) {
- /* the item can be shifted entirely */
- cur_free -= d_size;
- tb->rnum[0] ++;
- continue;
+ int i;
+ struct virtual_node *vn = tb->tb_vn;
+ struct virtual_item *vi;
+ int d_size, ih_size;
+
+ RFALSE(cur_free < 0, "vs-8070: cur_free < 0");
+
+ /* internal level */
+ if (h > 0) {
+ tb->rnum[h] = cur_free / (DC_SIZE + KEY_SIZE);
+ return;
}
-
- /* check whether R[0] can hold ih and at least one byte of the item body */
- if ( cur_free <= ih_size ) { /* cannot shift even a part of the current item */
- tb->rbytes = -1;
- return;
+
+ /* leaf level */
+
+ if (!cur_free || !vn->vn_nr_item) {
+ /* no free space */
+ tb->rnum[h] = 0;
+ tb->rbytes = -1;
+ return;
}
-
- /* R[0] can hold the header of the item and at least one byte of its body */
- cur_free -= ih_size; /* cur_free is still > 0 */
-
- tb->rbytes = op_check_right (vi, cur_free);
- if (tb->rbytes != -1)
- /* count partially shifted item */
- tb->rnum[0] ++;
-
- break;
- }
-
- return;
-}
+ RFALSE(!PATH_H_PPARENT(tb->tb_path, 0),
+ "vs-8075: parent does not exist or invalid");
+
+ vi = vn->vn_vi + vn->vn_nr_item - 1;
+ if ((unsigned int)cur_free >=
+ (vn->vn_size -
+ ((vi->vi_type & VI_TYPE_RIGHT_MERGEABLE) ? IH_SIZE : 0))) {
+ /* all contents of S[0] fits into R[0] */
+
+ RFALSE(vn->vn_mode == M_INSERT || vn->vn_mode == M_PASTE,
+ "vs-8080: invalid mode or balance condition failed");
+
+ tb->rnum[h] = vn->vn_nr_item;
+ tb->rbytes = -1;
+ return;
+ }
+
+ d_size = 0, ih_size = IH_SIZE;
+
+ /* last item may be merge with first item in right neighbor */
+ if (vi->vi_type & VI_TYPE_RIGHT_MERGEABLE)
+ d_size = -(int)IH_SIZE, ih_size = 0;
+
+ tb->rnum[0] = 0;
+ for (i = vn->vn_nr_item - 1; i >= 0;
+ i--, d_size = 0, ih_size = IH_SIZE, vi--) {
+ d_size += vi->vi_item_len;
+ if (cur_free >= d_size) {
+ /* the item can be shifted entirely */
+ cur_free -= d_size;
+ tb->rnum[0]++;
+ continue;
+ }
+
+ /* check whether R[0] can hold ih and at least one byte of the item body */
+ if (cur_free <= ih_size) { /* cannot shift even a part of the current item */
+ tb->rbytes = -1;
+ return;
+ }
+
+ /* R[0] can hold the header of the item and at least one byte of its body */
+ cur_free -= ih_size; /* cur_free is still > 0 */
+
+ tb->rbytes = op_check_right(vi, cur_free);
+ if (tb->rbytes != -1)
+ /* count partially shifted item */
+ tb->rnum[0]++;
+
+ break;
+ }
+
+ return;
+}
/*
* from - number of items, which are shifted to left neighbor entirely
* to - number of item, which are shifted to right neighbor entirely
* from_bytes - number of bytes of boundary item (or directory entries) which are shifted to left neighbor
* to_bytes - number of bytes of boundary item (or directory entries) which are shifted to right neighbor */
-static int get_num_ver (int mode, struct tree_balance * tb, int h,
- int from, int from_bytes,
- int to, int to_bytes,
- short * snum012, int flow
- )
+static int get_num_ver(int mode, struct tree_balance *tb, int h,
+ int from, int from_bytes,
+ int to, int to_bytes, short *snum012, int flow)
{
- int i;
- int cur_free;
- // int bytes;
- int units;
- struct virtual_node * vn = tb->tb_vn;
- // struct virtual_item * vi;
-
- int total_node_size, max_node_size, current_item_size;
- int needed_nodes;
- int start_item, /* position of item we start filling node from */
- end_item, /* position of item we finish filling node by */
- start_bytes,/* number of first bytes (entries for directory) of start_item-th item
- we do not include into node that is being filled */
- end_bytes; /* number of last bytes (entries for directory) of end_item-th item
- we do node include into node that is being filled */
- int split_item_positions[2]; /* these are positions in virtual item of
- items, that are split between S[0] and
- S1new and S1new and S2new */
-
- split_item_positions[0] = -1;
- split_item_positions[1] = -1;
-
- /* We only create additional nodes if we are in insert or paste mode
- or we are in replace mode at the internal level. If h is 0 and
- the mode is M_REPLACE then in fix_nodes we change the mode to
- paste or insert before we get here in the code. */
- RFALSE( tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE),
- "vs-8100: insert_size < 0 in overflow");
-
- max_node_size = MAX_CHILD_SIZE (PATH_H_PBUFFER (tb->tb_path, h));
-
- /* snum012 [0-2] - number of items, that lay
- to S[0], first new node and second new node */
- snum012[3] = -1; /* s1bytes */
- snum012[4] = -1; /* s2bytes */
-
- /* internal level */
- if (h > 0) {
- i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE);
- if (i == max_node_size)
- return 1;
- return (i / max_node_size + 1);
- }
-
- /* leaf level */
- needed_nodes = 1;
- total_node_size = 0;
- cur_free = max_node_size;
-
- // start from 'from'-th item
- start_item = from;
- // skip its first 'start_bytes' units
- start_bytes = ((from_bytes != -1) ? from_bytes : 0);
-
- // last included item is the 'end_item'-th one
- end_item = vn->vn_nr_item - to - 1;
- // do not count last 'end_bytes' units of 'end_item'-th item
- end_bytes = (to_bytes != -1) ? to_bytes : 0;
-
- /* go through all item beginning from the start_item-th item and ending by
- the end_item-th item. Do not count first 'start_bytes' units of
- 'start_item'-th item and last 'end_bytes' of 'end_item'-th item */
-
- for (i = start_item; i <= end_item; i ++) {
- struct virtual_item * vi = vn->vn_vi + i;
- int skip_from_end = ((i == end_item) ? end_bytes : 0);
-
- RFALSE( needed_nodes > 3, "vs-8105: too many nodes are needed");
-
- /* get size of current item */
- current_item_size = vi->vi_item_len;
-
- /* do not take in calculation head part (from_bytes) of from-th item */
- current_item_size -= op_part_size (vi, 0/*from start*/, start_bytes);
-
- /* do not take in calculation tail part of last item */
- current_item_size -= op_part_size (vi, 1/*from end*/, skip_from_end);
-
- /* if item fits into current node entierly */
- if (total_node_size + current_item_size <= max_node_size) {
- snum012[needed_nodes - 1] ++;
- total_node_size += current_item_size;
- start_bytes = 0;
- continue;
+ int i;
+ int cur_free;
+ // int bytes;
+ int units;
+ struct virtual_node *vn = tb->tb_vn;
+ // struct virtual_item * vi;
+
+ int total_node_size, max_node_size, current_item_size;
+ int needed_nodes;
+ int start_item, /* position of item we start filling node from */
+ end_item, /* position of item we finish filling node by */
+ start_bytes, /* number of first bytes (entries for directory) of start_item-th item
+ we do not include into node that is being filled */
+ end_bytes; /* number of last bytes (entries for directory) of end_item-th item
+ we do node include into node that is being filled */
+ int split_item_positions[2]; /* these are positions in virtual item of
+ items, that are split between S[0] and
+ S1new and S1new and S2new */
+
+ split_item_positions[0] = -1;
+ split_item_positions[1] = -1;
+
+ /* We only create additional nodes if we are in insert or paste mode
+ or we are in replace mode at the internal level. If h is 0 and
+ the mode is M_REPLACE then in fix_nodes we change the mode to
+ paste or insert before we get here in the code. */
+ RFALSE(tb->insert_size[h] < 0 || (mode != M_INSERT && mode != M_PASTE),
+ "vs-8100: insert_size < 0 in overflow");
+
+ max_node_size = MAX_CHILD_SIZE(PATH_H_PBUFFER(tb->tb_path, h));
+
+ /* snum012 [0-2] - number of items, that lay
+ to S[0], first new node and second new node */
+ snum012[3] = -1; /* s1bytes */
+ snum012[4] = -1; /* s2bytes */
+
+ /* internal level */
+ if (h > 0) {
+ i = ((to - from) * (KEY_SIZE + DC_SIZE) + DC_SIZE);
+ if (i == max_node_size)
+ return 1;
+ return (i / max_node_size + 1);
}
- if (current_item_size > max_node_size) {
- /* virtual item length is longer, than max size of item in
- a node. It is impossible for direct item */
- RFALSE( is_direct_le_ih (vi->vi_ih),
- "vs-8110: "
- "direct item length is %d. It can not be longer than %d",
- current_item_size, max_node_size);
- /* we will try to split it */
- flow = 1;
+ /* leaf level */
+ needed_nodes = 1;
+ total_node_size = 0;
+ cur_free = max_node_size;
+
+ // start from 'from'-th item
+ start_item = from;
+ // skip its first 'start_bytes' units
+ start_bytes = ((from_bytes != -1) ? from_bytes : 0);
+
+ // last included item is the 'end_item'-th one
+ end_item = vn->vn_nr_item - to - 1;
+ // do not count last 'end_bytes' units of 'end_item'-th item
+ end_bytes = (to_bytes != -1) ? to_bytes : 0;
+
+ /* go through all item beginning from the start_item-th item and ending by
+ the end_item-th item. Do not count first 'start_bytes' units of
+ 'start_item'-th item and last 'end_bytes' of 'end_item'-th item */
+
+ for (i = start_item; i <= end_item; i++) {
+ struct virtual_item *vi = vn->vn_vi + i;
+ int skip_from_end = ((i == end_item) ? end_bytes : 0);
+
+ RFALSE(needed_nodes > 3, "vs-8105: too many nodes are needed");
+
+ /* get size of current item */
+ current_item_size = vi->vi_item_len;
+
+ /* do not take in calculation head part (from_bytes) of from-th item */
+ current_item_size -=
+ op_part_size(vi, 0 /*from start */ , start_bytes);
+
+ /* do not take in calculation tail part of last item */
+ current_item_size -=
+ op_part_size(vi, 1 /*from end */ , skip_from_end);
+
+ /* if item fits into current node entierly */
+ if (total_node_size + current_item_size <= max_node_size) {
+ snum012[needed_nodes - 1]++;
+ total_node_size += current_item_size;
+ start_bytes = 0;
+ continue;
+ }
+
+ if (current_item_size > max_node_size) {
+ /* virtual item length is longer, than max size of item in
+ a node. It is impossible for direct item */
+ RFALSE(is_direct_le_ih(vi->vi_ih),
+ "vs-8110: "
+ "direct item length is %d. It can not be longer than %d",
+ current_item_size, max_node_size);
+ /* we will try to split it */
+ flow = 1;
+ }
+
+ if (!flow) {
+ /* as we do not split items, take new node and continue */
+ needed_nodes++;
+ i--;
+ total_node_size = 0;
+ continue;
+ }
+ // calculate number of item units which fit into node being
+ // filled
+ {
+ int free_space;
+
+ free_space = max_node_size - total_node_size - IH_SIZE;
+ units =
+ op_check_left(vi, free_space, start_bytes,
+ skip_from_end);
+ if (units == -1) {
+ /* nothing fits into current node, take new node and continue */
+ needed_nodes++, i--, total_node_size = 0;
+ continue;
+ }
+ }
+
+ /* something fits into the current node */
+ //if (snum012[3] != -1 || needed_nodes != 1)
+ // reiserfs_panic (tb->tb_sb, "vs-8115: get_num_ver: too many nodes required");
+ //snum012[needed_nodes - 1 + 3] = op_unit_num (vi) - start_bytes - units;
+ start_bytes += units;
+ snum012[needed_nodes - 1 + 3] = units;
+
+ if (needed_nodes > 2)
+ reiserfs_warning(tb->tb_sb, "vs-8111: get_num_ver: "
+ "split_item_position is out of boundary");
+ snum012[needed_nodes - 1]++;
+ split_item_positions[needed_nodes - 1] = i;
+ needed_nodes++;
+ /* continue from the same item with start_bytes != -1 */
+ start_item = i;
+ i--;
+ total_node_size = 0;
}
- if (!flow) {
- /* as we do not split items, take new node and continue */
- needed_nodes ++; i --; total_node_size = 0;
- continue;
+ // sum012[4] (if it is not -1) contains number of units of which
+ // are to be in S1new, snum012[3] - to be in S0. They are supposed
+ // to be S1bytes and S2bytes correspondingly, so recalculate
+ if (snum012[4] > 0) {
+ int split_item_num;
+ int bytes_to_r, bytes_to_l;
+ int bytes_to_S1new;
+
+ split_item_num = split_item_positions[1];
+ bytes_to_l =
+ ((from == split_item_num
+ && from_bytes != -1) ? from_bytes : 0);
+ bytes_to_r =
+ ((end_item == split_item_num
+ && end_bytes != -1) ? end_bytes : 0);
+ bytes_to_S1new =
+ ((split_item_positions[0] ==
+ split_item_positions[1]) ? snum012[3] : 0);
+
+ // s2bytes
+ snum012[4] =
+ op_unit_num(&vn->vn_vi[split_item_num]) - snum012[4] -
+ bytes_to_r - bytes_to_l - bytes_to_S1new;
+
+ if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY &&
+ vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT)
+ reiserfs_warning(tb->tb_sb, "vs-8115: get_num_ver: not "
+ "directory or indirect item");
}
- // calculate number of item units which fit into node being
- // filled
- {
- int free_space;
-
- free_space = max_node_size - total_node_size - IH_SIZE;
- units = op_check_left (vi, free_space, start_bytes, skip_from_end);
- if (units == -1) {
- /* nothing fits into current node, take new node and continue */
- needed_nodes ++, i--, total_node_size = 0;
- continue;
- }
+ /* now we know S2bytes, calculate S1bytes */
+ if (snum012[3] > 0) {
+ int split_item_num;
+ int bytes_to_r, bytes_to_l;
+ int bytes_to_S2new;
+
+ split_item_num = split_item_positions[0];
+ bytes_to_l =
+ ((from == split_item_num
+ && from_bytes != -1) ? from_bytes : 0);
+ bytes_to_r =
+ ((end_item == split_item_num
+ && end_bytes != -1) ? end_bytes : 0);
+ bytes_to_S2new =
+ ((split_item_positions[0] == split_item_positions[1]
+ && snum012[4] != -1) ? snum012[4] : 0);
+
+ // s1bytes
+ snum012[3] =
+ op_unit_num(&vn->vn_vi[split_item_num]) - snum012[3] -
+ bytes_to_r - bytes_to_l - bytes_to_S2new;
}
- /* something fits into the current node */
- //if (snum012[3] != -1 || needed_nodes != 1)
- // reiserfs_panic (tb->tb_sb, "vs-8115: get_num_ver: too many nodes required");
- //snum012[needed_nodes - 1 + 3] = op_unit_num (vi) - start_bytes - units;
- start_bytes += units;
- snum012[needed_nodes - 1 + 3] = units;
-
- if (needed_nodes > 2)
- reiserfs_warning (tb->tb_sb, "vs-8111: get_num_ver: "
- "split_item_position is out of boundary");
- snum012[needed_nodes - 1] ++;
- split_item_positions[needed_nodes - 1] = i;
- needed_nodes ++;
- /* continue from the same item with start_bytes != -1 */
- start_item = i;
- i --;
- total_node_size = 0;
- }
-
- // sum012[4] (if it is not -1) contains number of units of which
- // are to be in S1new, snum012[3] - to be in S0. They are supposed
- // to be S1bytes and S2bytes correspondingly, so recalculate
- if (snum012[4] > 0) {
- int split_item_num;
- int bytes_to_r, bytes_to_l;
- int bytes_to_S1new;
-
- split_item_num = split_item_positions[1];
- bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0);
- bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0);
- bytes_to_S1new = ((split_item_positions[0] == split_item_positions[1]) ? snum012[3] : 0);
-
- // s2bytes
- snum012[4] = op_unit_num (&vn->vn_vi[split_item_num]) - snum012[4] - bytes_to_r - bytes_to_l - bytes_to_S1new;
-
- if (vn->vn_vi[split_item_num].vi_index != TYPE_DIRENTRY &&
- vn->vn_vi[split_item_num].vi_index != TYPE_INDIRECT)
- reiserfs_warning (tb->tb_sb, "vs-8115: get_num_ver: not "
- "directory or indirect item");
- }
-
- /* now we know S2bytes, calculate S1bytes */
- if (snum012[3] > 0) {
- int split_item_num;
- int bytes_to_r, bytes_to_l;
- int bytes_to_S2new;
-
- split_item_num = split_item_positions[0];
- bytes_to_l = ((from == split_item_num && from_bytes != -1) ? from_bytes : 0);
- bytes_to_r = ((end_item == split_item_num && end_bytes != -1) ? end_bytes : 0);
- bytes_to_S2new = ((split_item_positions[0] == split_item_positions[1] && snum012[4] != -1) ? snum012[4] : 0);
-
- // s1bytes
- snum012[3] = op_unit_num (&vn->vn_vi[split_item_num]) - snum012[3] - bytes_to_r - bytes_to_l - bytes_to_S2new;
- }
-
- return needed_nodes;
+ return needed_nodes;
}
-
#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance * cur_tb;
+extern struct tree_balance *cur_tb;
#endif
-
/* Set parameters for balancing.
* Performs write of results of analysis of balancing into structure tb,
* where it will later be used by the functions that actually do the balancing.
@@ -557,131 +587,130 @@ extern struct tree_balance * cur_tb;
* s1bytes number of bytes which flow to the first new node when S[0] splits (this number is contained in s012 array)
*/
-static void set_parameters (struct tree_balance * tb, int h, int lnum,
- int rnum, int blk_num, short * s012, int lb, int rb)
+static void set_parameters(struct tree_balance *tb, int h, int lnum,
+ int rnum, int blk_num, short *s012, int lb, int rb)
{
- tb->lnum[h] = lnum;
- tb->rnum[h] = rnum;
- tb->blknum[h] = blk_num;
+ tb->lnum[h] = lnum;
+ tb->rnum[h] = rnum;
+ tb->blknum[h] = blk_num;
- if (h == 0)
- { /* only for leaf level */
- if (s012 != NULL)
- {
- tb->s0num = * s012 ++,
- tb->s1num = * s012 ++,
- tb->s2num = * s012 ++;
- tb->s1bytes = * s012 ++;
- tb->s2bytes = * s012;
+ if (h == 0) { /* only for leaf level */
+ if (s012 != NULL) {
+ tb->s0num = *s012++,
+ tb->s1num = *s012++, tb->s2num = *s012++;
+ tb->s1bytes = *s012++;
+ tb->s2bytes = *s012;
+ }
+ tb->lbytes = lb;
+ tb->rbytes = rb;
}
- tb->lbytes = lb;
- tb->rbytes = rb;
- }
- PROC_INFO_ADD( tb -> tb_sb, lnum[ h ], lnum );
- PROC_INFO_ADD( tb -> tb_sb, rnum[ h ], rnum );
-
- PROC_INFO_ADD( tb -> tb_sb, lbytes[ h ], lb );
- PROC_INFO_ADD( tb -> tb_sb, rbytes[ h ], rb );
-}
-
+ PROC_INFO_ADD(tb->tb_sb, lnum[h], lnum);
+ PROC_INFO_ADD(tb->tb_sb, rnum[h], rnum);
+ PROC_INFO_ADD(tb->tb_sb, lbytes[h], lb);
+ PROC_INFO_ADD(tb->tb_sb, rbytes[h], rb);
+}
/* check, does node disappear if we shift tb->lnum[0] items to left
neighbor and tb->rnum[0] to the right one. */
-static int is_leaf_removable (struct tree_balance * tb)
+static int is_leaf_removable(struct tree_balance *tb)
{
- struct virtual_node * vn = tb->tb_vn;
- int to_left, to_right;
- int size;
- int remain_items;
-
- /* number of items, that will be shifted to left (right) neighbor
- entirely */
- to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0);
- to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0);
- remain_items = vn->vn_nr_item;
-
- /* how many items remain in S[0] after shiftings to neighbors */
- remain_items -= (to_left + to_right);
-
- if (remain_items < 1) {
- /* all content of node can be shifted to neighbors */
- set_parameters (tb, 0, to_left, vn->vn_nr_item - to_left, 0, NULL, -1, -1);
- return 1;
- }
-
- if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1)
- /* S[0] is not removable */
- return 0;
-
- /* check, whether we can divide 1 remaining item between neighbors */
-
- /* get size of remaining item (in item units) */
- size = op_unit_num (&(vn->vn_vi[to_left]));
-
- if (tb->lbytes + tb->rbytes >= size) {
- set_parameters (tb, 0, to_left + 1, to_right + 1, 0, NULL, tb->lbytes, -1);
- return 1;
- }
-
- return 0;
-}
+ struct virtual_node *vn = tb->tb_vn;
+ int to_left, to_right;
+ int size;
+ int remain_items;
+
+ /* number of items, that will be shifted to left (right) neighbor
+ entirely */
+ to_left = tb->lnum[0] - ((tb->lbytes != -1) ? 1 : 0);
+ to_right = tb->rnum[0] - ((tb->rbytes != -1) ? 1 : 0);
+ remain_items = vn->vn_nr_item;
+
+ /* how many items remain in S[0] after shiftings to neighbors */
+ remain_items -= (to_left + to_right);
+
+ if (remain_items < 1) {
+ /* all content of node can be shifted to neighbors */
+ set_parameters(tb, 0, to_left, vn->vn_nr_item - to_left, 0,
+ NULL, -1, -1);
+ return 1;
+ }
+ if (remain_items > 1 || tb->lbytes == -1 || tb->rbytes == -1)
+ /* S[0] is not removable */
+ return 0;
+
+ /* check, whether we can divide 1 remaining item between neighbors */
+
+ /* get size of remaining item (in item units) */
+ size = op_unit_num(&(vn->vn_vi[to_left]));
+
+ if (tb->lbytes + tb->rbytes >= size) {
+ set_parameters(tb, 0, to_left + 1, to_right + 1, 0, NULL,
+ tb->lbytes, -1);
+ return 1;
+ }
+
+ return 0;
+}
/* check whether L, S, R can be joined in one node */
-static int are_leaves_removable (struct tree_balance * tb, int lfree, int rfree)
+static int are_leaves_removable(struct tree_balance *tb, int lfree, int rfree)
{
- struct virtual_node * vn = tb->tb_vn;
- int ih_size;
- struct buffer_head *S0;
-
- S0 = PATH_H_PBUFFER (tb->tb_path, 0);
-
- ih_size = 0;
- if (vn->vn_nr_item) {
- if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE)
- ih_size += IH_SIZE;
-
- if (vn->vn_vi[vn->vn_nr_item-1].vi_type & VI_TYPE_RIGHT_MERGEABLE)
- ih_size += IH_SIZE;
- } else {
- /* there was only one item and it will be deleted */
- struct item_head * ih;
-
- RFALSE( B_NR_ITEMS (S0) != 1,
- "vs-8125: item number must be 1: it is %d", B_NR_ITEMS(S0));
-
- ih = B_N_PITEM_HEAD (S0, 0);
- if (tb->CFR[0] && !comp_short_le_keys (&(ih->ih_key), B_N_PDELIM_KEY (tb->CFR[0], tb->rkey[0])))
- if (is_direntry_le_ih (ih)) {
- /* Directory must be in correct state here: that is
- somewhere at the left side should exist first directory
- item. But the item being deleted can not be that first
- one because its right neighbor is item of the same
- directory. (But first item always gets deleted in last
- turn). So, neighbors of deleted item can be merged, so
- we can save ih_size */
- ih_size = IH_SIZE;
-
- /* we might check that left neighbor exists and is of the
- same directory */
- RFALSE(le_ih_k_offset (ih) == DOT_OFFSET,
- "vs-8130: first directory item can not be removed until directory is not empty");
- }
-
- }
-
- if (MAX_CHILD_SIZE (S0) + vn->vn_size <= rfree + lfree + ih_size) {
- set_parameters (tb, 0, -1, -1, -1, NULL, -1, -1);
- PROC_INFO_INC( tb -> tb_sb, leaves_removable );
- return 1;
- }
- return 0;
-
-}
+ struct virtual_node *vn = tb->tb_vn;
+ int ih_size;
+ struct buffer_head *S0;
+
+ S0 = PATH_H_PBUFFER(tb->tb_path, 0);
+
+ ih_size = 0;
+ if (vn->vn_nr_item) {
+ if (vn->vn_vi[0].vi_type & VI_TYPE_LEFT_MERGEABLE)
+ ih_size += IH_SIZE;
+
+ if (vn->vn_vi[vn->vn_nr_item - 1].
+ vi_type & VI_TYPE_RIGHT_MERGEABLE)
+ ih_size += IH_SIZE;
+ } else {
+ /* there was only one item and it will be deleted */
+ struct item_head *ih;
+
+ RFALSE(B_NR_ITEMS(S0) != 1,
+ "vs-8125: item number must be 1: it is %d",
+ B_NR_ITEMS(S0));
+
+ ih = B_N_PITEM_HEAD(S0, 0);
+ if (tb->CFR[0]
+ && !comp_short_le_keys(&(ih->ih_key),
+ B_N_PDELIM_KEY(tb->CFR[0],
+ tb->rkey[0])))
+ if (is_direntry_le_ih(ih)) {
+ /* Directory must be in correct state here: that is
+ somewhere at the left side should exist first directory
+ item. But the item being deleted can not be that first
+ one because its right neighbor is item of the same
+ directory. (But first item always gets deleted in last
+ turn). So, neighbors of deleted item can be merged, so
+ we can save ih_size */
+ ih_size = IH_SIZE;
+
+ /* we might check that left neighbor exists and is of the
+ same directory */
+ RFALSE(le_ih_k_offset(ih) == DOT_OFFSET,
+ "vs-8130: first directory item can not be removed until directory is not empty");
+ }
+ }
+
+ if (MAX_CHILD_SIZE(S0) + vn->vn_size <= rfree + lfree + ih_size) {
+ set_parameters(tb, 0, -1, -1, -1, NULL, -1, -1);
+ PROC_INFO_INC(tb->tb_sb, leaves_removable);
+ return 1;
+ }
+ return 0;
+}
/* when we do not split item, lnum and rnum are numbers of entire items */
#define SET_PAR_SHIFT_LEFT \
@@ -704,7 +733,6 @@ else \
-1, -1);\
}
-
#define SET_PAR_SHIFT_RIGHT \
if (h)\
{\
@@ -724,214 +752,199 @@ else \
-1, -1);\
}
-
-static void free_buffers_in_tb (
- struct tree_balance * p_s_tb
- ) {
- int n_counter;
-
- decrement_counters_in_path(p_s_tb->tb_path);
-
- for ( n_counter = 0; n_counter < MAX_HEIGHT; n_counter++ ) {
- decrement_bcount(p_s_tb->L[n_counter]);
- p_s_tb->L[n_counter] = NULL;
- decrement_bcount(p_s_tb->R[n_counter]);
- p_s_tb->R[n_counter] = NULL;
- decrement_bcount(p_s_tb->FL[n_counter]);
- p_s_tb->FL[n_counter] = NULL;
- decrement_bcount(p_s_tb->FR[n_counter]);
- p_s_tb->FR[n_counter] = NULL;
- decrement_bcount(p_s_tb->CFL[n_counter]);
- p_s_tb->CFL[n_counter] = NULL;
- decrement_bcount(p_s_tb->CFR[n_counter]);
- p_s_tb->CFR[n_counter] = NULL;
- }
+static void free_buffers_in_tb(struct tree_balance *p_s_tb)
+{
+ int n_counter;
+
+ decrement_counters_in_path(p_s_tb->tb_path);
+
+ for (n_counter = 0; n_counter < MAX_HEIGHT; n_counter++) {
+ decrement_bcount(p_s_tb->L[n_counter]);
+ p_s_tb->L[n_counter] = NULL;
+ decrement_bcount(p_s_tb->R[n_counter]);
+ p_s_tb->R[n_counter] = NULL;
+ decrement_bcount(p_s_tb->FL[n_counter]);
+ p_s_tb->FL[n_counter] = NULL;
+ decrement_bcount(p_s_tb->FR[n_counter]);
+ p_s_tb->FR[n_counter] = NULL;
+ decrement_bcount(p_s_tb->CFL[n_counter]);
+ p_s_tb->CFL[n_counter] = NULL;
+ decrement_bcount(p_s_tb->CFR[n_counter]);
+ p_s_tb->CFR[n_counter] = NULL;
+ }
}
-
/* Get new buffers for storing new nodes that are created while balancing.
* Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked;
* CARRY_ON - schedule didn't occur while the function worked;
* NO_DISK_SPACE - no disk space.
*/
/* The function is NOT SCHEDULE-SAFE! */
-static int get_empty_nodes(
- struct tree_balance * p_s_tb,
- int n_h
- ) {
- struct buffer_head * p_s_new_bh,
- * p_s_Sh = PATH_H_PBUFFER (p_s_tb->tb_path, n_h);
- b_blocknr_t * p_n_blocknr,
- a_n_blocknrs[MAX_AMOUNT_NEEDED] = {0, };
- int n_counter,
- n_number_of_freeblk,
- n_amount_needed,/* number of needed empty blocks */
- n_retval = CARRY_ON;
- struct super_block * p_s_sb = p_s_tb->tb_sb;
-
-
- /* number_of_freeblk is the number of empty blocks which have been
- acquired for use by the balancing algorithm minus the number of
- empty blocks used in the previous levels of the analysis,
- number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs
- after empty blocks are acquired, and the balancing analysis is
- then restarted, amount_needed is the number needed by this level
- (n_h) of the balancing analysis.
-
- Note that for systems with many processes writing, it would be
- more layout optimal to calculate the total number needed by all
- levels and then to run reiserfs_new_blocks to get all of them at once. */
-
- /* Initiate number_of_freeblk to the amount acquired prior to the restart of
- the analysis or 0 if not restarted, then subtract the amount needed
- by all of the levels of the tree below n_h. */
- /* blknum includes S[n_h], so we subtract 1 in this calculation */
- for ( n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum; n_counter < n_h; n_counter++ )
- n_number_of_freeblk -= ( p_s_tb->blknum[n_counter] ) ? (p_s_tb->blknum[n_counter] - 1) : 0;
-
- /* Allocate missing empty blocks. */
- /* if p_s_Sh == 0 then we are getting a new root */
- n_amount_needed = ( p_s_Sh ) ? (p_s_tb->blknum[n_h] - 1) : 1;
- /* Amount_needed = the amount that we need more than the amount that we have. */
- if ( n_amount_needed > n_number_of_freeblk )
- n_amount_needed -= n_number_of_freeblk;
- else /* If we have enough already then there is nothing to do. */
- return CARRY_ON;
-
- /* No need to check quota - is not allocated for blocks used for formatted nodes */
- if (reiserfs_new_form_blocknrs (p_s_tb, a_n_blocknrs,
- n_amount_needed) == NO_DISK_SPACE)
- return NO_DISK_SPACE;
-
- /* for each blocknumber we just got, get a buffer and stick it on FEB */
- for ( p_n_blocknr = a_n_blocknrs, n_counter = 0; n_counter < n_amount_needed;
- p_n_blocknr++, n_counter++ ) {
-
- RFALSE( ! *p_n_blocknr,
- "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
-
- p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr);
- RFALSE (buffer_dirty (p_s_new_bh) ||
- buffer_journaled (p_s_new_bh) ||
- buffer_journal_dirty (p_s_new_bh),
- "PAP-8140: journlaled or dirty buffer %b for the new block",
- p_s_new_bh);
-
- /* Put empty buffers into the array. */
- RFALSE (p_s_tb->FEB[p_s_tb->cur_blknum],
- "PAP-8141: busy slot for new buffer");
-
- set_buffer_journal_new (p_s_new_bh);
- p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
- }
-
- if ( n_retval == CARRY_ON && FILESYSTEM_CHANGED_TB (p_s_tb) )
- n_retval = REPEAT_SEARCH ;
-
- return n_retval;
-}
+static int get_empty_nodes(struct tree_balance *p_s_tb, int n_h)
+{
+ struct buffer_head *p_s_new_bh,
+ *p_s_Sh = PATH_H_PBUFFER(p_s_tb->tb_path, n_h);
+ b_blocknr_t *p_n_blocknr, a_n_blocknrs[MAX_AMOUNT_NEEDED] = { 0, };
+ int n_counter, n_number_of_freeblk, n_amount_needed, /* number of needed empty blocks */
+ n_retval = CARRY_ON;
+ struct super_block *p_s_sb = p_s_tb->tb_sb;
+
+ /* number_of_freeblk is the number of empty blocks which have been
+ acquired for use by the balancing algorithm minus the number of
+ empty blocks used in the previous levels of the analysis,
+ number_of_freeblk = tb->cur_blknum can be non-zero if a schedule occurs
+ after empty blocks are acquired, and the balancing analysis is
+ then restarted, amount_needed is the number needed by this level
+ (n_h) of the balancing analysis.
+
+ Note that for systems with many processes writing, it would be
+ more layout optimal to calculate the total number needed by all
+ levels and then to run reiserfs_new_blocks to get all of them at once. */
+
+ /* Initiate number_of_freeblk to the amount acquired prior to the restart of
+ the analysis or 0 if not restarted, then subtract the amount needed
+ by all of the levels of the tree below n_h. */
+ /* blknum includes S[n_h], so we subtract 1 in this calculation */
+ for (n_counter = 0, n_number_of_freeblk = p_s_tb->cur_blknum;
+ n_counter < n_h; n_counter++)
+ n_number_of_freeblk -=
+ (p_s_tb->blknum[n_counter]) ? (p_s_tb->blknum[n_counter] -
+ 1) : 0;
+
+ /* Allocate missing empty blocks. */
+ /* if p_s_Sh == 0 then we are getting a new root */
+ n_amount_needed = (p_s_Sh) ? (p_s_tb->blknum[n_h] - 1) : 1;
+ /* Amount_needed = the amount that we need more than the amount that we have. */
+ if (n_amount_needed > n_number_of_freeblk)
+ n_amount_needed -= n_number_of_freeblk;
+ else /* If we have enough already then there is nothing to do. */
+ return CARRY_ON;
+
+ /* No need to check quota - is not allocated for blocks used for formatted nodes */
+ if (reiserfs_new_form_blocknrs(p_s_tb, a_n_blocknrs,
+ n_amount_needed) == NO_DISK_SPACE)
+ return NO_DISK_SPACE;
+
+ /* for each blocknumber we just got, get a buffer and stick it on FEB */
+ for (p_n_blocknr = a_n_blocknrs, n_counter = 0;
+ n_counter < n_amount_needed; p_n_blocknr++, n_counter++) {
+
+ RFALSE(!*p_n_blocknr,
+ "PAP-8135: reiserfs_new_blocknrs failed when got new blocks");
+
+ p_s_new_bh = sb_getblk(p_s_sb, *p_n_blocknr);
+ RFALSE(buffer_dirty(p_s_new_bh) ||
+ buffer_journaled(p_s_new_bh) ||
+ buffer_journal_dirty(p_s_new_bh),
+ "PAP-8140: journlaled or dirty buffer %b for the new block",
+ p_s_new_bh);
+
+ /* Put empty buffers into the array. */
+ RFALSE(p_s_tb->FEB[p_s_tb->cur_blknum],
+ "PAP-8141: busy slot for new buffer");
+
+ set_buffer_journal_new(p_s_new_bh);
+ p_s_tb->FEB[p_s_tb->cur_blknum++] = p_s_new_bh;
+ }
+
+ if (n_retval == CARRY_ON && FILESYSTEM_CHANGED_TB(p_s_tb))
+ n_retval = REPEAT_SEARCH;
+ return n_retval;
+}
/* Get free space of the left neighbor, which is stored in the parent
* node of the left neighbor. */
-static int get_lfree (struct tree_balance * tb, int h)
+static int get_lfree(struct tree_balance *tb, int h)
{
- struct buffer_head * l, * f;
- int order;
+ struct buffer_head *l, *f;
+ int order;
- if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (l = tb->FL[h]) == 0)
- return 0;
+ if ((f = PATH_H_PPARENT(tb->tb_path, h)) == 0 || (l = tb->FL[h]) == 0)
+ return 0;
- if (f == l)
- order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) - 1;
- else {
- order = B_NR_ITEMS (l);
- f = l;
- }
+ if (f == l)
+ order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) - 1;
+ else {
+ order = B_NR_ITEMS(l);
+ f = l;
+ }
- return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f,order)));
+ return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order)));
}
-
/* Get free space of the right neighbor,
* which is stored in the parent node of the right neighbor.
*/
-static int get_rfree (struct tree_balance * tb, int h)
+static int get_rfree(struct tree_balance *tb, int h)
{
- struct buffer_head * r, * f;
- int order;
+ struct buffer_head *r, *f;
+ int order;
- if ((f = PATH_H_PPARENT (tb->tb_path, h)) == 0 || (r = tb->FR[h]) == 0)
- return 0;
+ if ((f = PATH_H_PPARENT(tb->tb_path, h)) == 0 || (r = tb->FR[h]) == 0)
+ return 0;
- if (f == r)
- order = PATH_H_B_ITEM_ORDER (tb->tb_path, h) + 1;
- else {
- order = 0;
- f = r;
- }
+ if (f == r)
+ order = PATH_H_B_ITEM_ORDER(tb->tb_path, h) + 1;
+ else {
+ order = 0;
+ f = r;
+ }
- return (MAX_CHILD_SIZE(f) - dc_size( B_N_CHILD(f,order)));
+ return (MAX_CHILD_SIZE(f) - dc_size(B_N_CHILD(f, order)));
}
-
/* Check whether left neighbor is in memory. */
-static int is_left_neighbor_in_cache(
- struct tree_balance * p_s_tb,
- int n_h
- ) {
- struct buffer_head * p_s_father, * left;
- struct super_block * p_s_sb = p_s_tb->tb_sb;
- b_blocknr_t n_left_neighbor_blocknr;
- int n_left_neighbor_position;
-
- if ( ! p_s_tb->FL[n_h] ) /* Father of the left neighbor does not exist. */
- return 0;
-
- /* Calculate father of the node to be balanced. */
- p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1);
-
- RFALSE( ! p_s_father ||
- ! B_IS_IN_TREE (p_s_father) ||
- ! B_IS_IN_TREE (p_s_tb->FL[n_h]) ||
- ! buffer_uptodate (p_s_father) ||
- ! buffer_uptodate (p_s_tb->FL[n_h]),
- "vs-8165: F[h] (%b) or FL[h] (%b) is invalid",
- p_s_father, p_s_tb->FL[n_h]);
-
-
- /* Get position of the pointer to the left neighbor into the left father. */
- n_left_neighbor_position = ( p_s_father == p_s_tb->FL[n_h] ) ?
- p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]);
- /* Get left neighbor block number. */
- n_left_neighbor_blocknr = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position);
- /* Look for the left neighbor in the cache. */
- if ( (left = sb_find_get_block(p_s_sb, n_left_neighbor_blocknr)) ) {
-
- RFALSE( buffer_uptodate (left) && ! B_IS_IN_TREE(left),
- "vs-8170: left neighbor (%b %z) is not in the tree", left, left);
- put_bh(left) ;
- return 1;
- }
-
- return 0;
-}
+static int is_left_neighbor_in_cache(struct tree_balance *p_s_tb, int n_h)
+{
+ struct buffer_head *p_s_father, *left;
+ struct super_block *p_s_sb = p_s_tb->tb_sb;
+ b_blocknr_t n_left_neighbor_blocknr;
+ int n_left_neighbor_position;
+
+ if (!p_s_tb->FL[n_h]) /* Father of the left neighbor does not exist. */
+ return 0;
+
+ /* Calculate father of the node to be balanced. */
+ p_s_father = PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1);
+
+ RFALSE(!p_s_father ||
+ !B_IS_IN_TREE(p_s_father) ||
+ !B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
+ !buffer_uptodate(p_s_father) ||
+ !buffer_uptodate(p_s_tb->FL[n_h]),
+ "vs-8165: F[h] (%b) or FL[h] (%b) is invalid",
+ p_s_father, p_s_tb->FL[n_h]);
+
+ /* Get position of the pointer to the left neighbor into the left father. */
+ n_left_neighbor_position = (p_s_father == p_s_tb->FL[n_h]) ?
+ p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb->FL[n_h]);
+ /* Get left neighbor block number. */
+ n_left_neighbor_blocknr =
+ B_N_CHILD_NUM(p_s_tb->FL[n_h], n_left_neighbor_position);
+ /* Look for the left neighbor in the cache. */
+ if ((left = sb_find_get_block(p_s_sb, n_left_neighbor_blocknr))) {
+
+ RFALSE(buffer_uptodate(left) && !B_IS_IN_TREE(left),
+ "vs-8170: left neighbor (%b %z) is not in the tree",
+ left, left);
+ put_bh(left);
+ return 1;
+ }
+ return 0;
+}
#define LEFT_PARENTS 'l'
#define RIGHT_PARENTS 'r'
-
-static void decrement_key (struct cpu_key * p_s_key)
+static void decrement_key(struct cpu_key *p_s_key)
{
- // call item specific function for this key
- item_ops[cpu_key_k_type (p_s_key)]->decrement_key (p_s_key);
+ // call item specific function for this key
+ item_ops[cpu_key_k_type(p_s_key)]->decrement_key(p_s_key);
}
-
-
-
/* Calculate far left/right parent of the left/right neighbor of the current node, that
* is calculate the left/right (FL[h]/FR[h]) neighbor of the parent F[h].
* Calculate left/right common parent of the current node and L[h]/R[h].
@@ -940,111 +953,121 @@ static void decrement_key (struct cpu_key * p_s_key)
SCHEDULE_OCCURRED - schedule occurred while the function worked;
* CARRY_ON - schedule didn't occur while the function worked;
*/
-static int get_far_parent (struct tree_balance * p_s_tb,
- int n_h,
- struct buffer_head ** pp_s_father,
- struct buffer_head ** pp_s_com_father,
- char c_lr_par)
+static int get_far_parent(struct tree_balance *p_s_tb,
+ int n_h,
+ struct buffer_head **pp_s_father,
+ struct buffer_head **pp_s_com_father, char c_lr_par)
{
- struct buffer_head * p_s_parent;
- INITIALIZE_PATH (s_path_to_neighbor_father);
- struct path * p_s_path = p_s_tb->tb_path;
- struct cpu_key s_lr_father_key;
- int n_counter,
- n_position = INT_MAX,
- n_first_last_position = 0,
- n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h);
-
- /* Starting from F[n_h] go upwards in the tree, and look for the common
- ancestor of F[n_h], and its neighbor l/r, that should be obtained. */
-
- n_counter = n_path_offset;
-
- RFALSE( n_counter < FIRST_PATH_ELEMENT_OFFSET,
- "PAP-8180: invalid path length");
-
-
- for ( ; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter-- ) {
- /* Check whether parent of the current buffer in the path is really parent in the tree. */
- if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1)) )
- return REPEAT_SEARCH;
- /* Check whether position in the parent is correct. */
- if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_counter - 1)) > B_NR_ITEMS(p_s_parent) )
- return REPEAT_SEARCH;
- /* Check whether parent at the path really points to the child. */
- if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
- PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr )
- return REPEAT_SEARCH;
- /* Return delimiting key if position in the parent is not equal to first/last one. */
- if ( c_lr_par == RIGHT_PARENTS )
- n_first_last_position = B_NR_ITEMS (p_s_parent);
- if ( n_position != n_first_last_position ) {
- *pp_s_com_father = p_s_parent;
- get_bh(*pp_s_com_father) ;
- /*(*pp_s_com_father = p_s_parent)->b_count++;*/
- break;
+ struct buffer_head *p_s_parent;
+ INITIALIZE_PATH(s_path_to_neighbor_father);
+ struct path *p_s_path = p_s_tb->tb_path;
+ struct cpu_key s_lr_father_key;
+ int n_counter,
+ n_position = INT_MAX,
+ n_first_last_position = 0,
+ n_path_offset = PATH_H_PATH_OFFSET(p_s_path, n_h);
+
+ /* Starting from F[n_h] go upwards in the tree, and look for the common
+ ancestor of F[n_h], and its neighbor l/r, that should be obtained. */
+
+ n_counter = n_path_offset;
+
+ RFALSE(n_counter < FIRST_PATH_ELEMENT_OFFSET,
+ "PAP-8180: invalid path length");
+
+ for (; n_counter > FIRST_PATH_ELEMENT_OFFSET; n_counter--) {
+ /* Check whether parent of the current buffer in the path is really parent in the tree. */
+ if (!B_IS_IN_TREE
+ (p_s_parent = PATH_OFFSET_PBUFFER(p_s_path, n_counter - 1)))
+ return REPEAT_SEARCH;
+ /* Check whether position in the parent is correct. */
+ if ((n_position =
+ PATH_OFFSET_POSITION(p_s_path,
+ n_counter - 1)) >
+ B_NR_ITEMS(p_s_parent))
+ return REPEAT_SEARCH;
+ /* Check whether parent at the path really points to the child. */
+ if (B_N_CHILD_NUM(p_s_parent, n_position) !=
+ PATH_OFFSET_PBUFFER(p_s_path, n_counter)->b_blocknr)
+ return REPEAT_SEARCH;
+ /* Return delimiting key if position in the parent is not equal to first/last one. */
+ if (c_lr_par == RIGHT_PARENTS)
+ n_first_last_position = B_NR_ITEMS(p_s_parent);
+ if (n_position != n_first_last_position) {
+ *pp_s_com_father = p_s_parent;
+ get_bh(*pp_s_com_father);
+ /*(*pp_s_com_father = p_s_parent)->b_count++; */
+ break;
+ }
}
- }
-
- /* if we are in the root of the tree, then there is no common father */
- if ( n_counter == FIRST_PATH_ELEMENT_OFFSET ) {
- /* Check whether first buffer in the path is the root of the tree. */
- if ( PATH_OFFSET_PBUFFER(p_s_tb->tb_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
- SB_ROOT_BLOCK (p_s_tb->tb_sb) ) {
- *pp_s_father = *pp_s_com_father = NULL;
- return CARRY_ON;
+
+ /* if we are in the root of the tree, then there is no common father */
+ if (n_counter == FIRST_PATH_ELEMENT_OFFSET) {
+ /* Check whether first buffer in the path is the root of the tree. */
+ if (PATH_OFFSET_PBUFFER
+ (p_s_tb->tb_path,
+ FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
+ SB_ROOT_BLOCK(p_s_tb->tb_sb)) {
+ *pp_s_father = *pp_s_com_father = NULL;
+ return CARRY_ON;
+ }
+ return REPEAT_SEARCH;
}
- return REPEAT_SEARCH;
- }
- RFALSE( B_LEVEL (*pp_s_com_father) <= DISK_LEAF_NODE_LEVEL,
- "PAP-8185: (%b %z) level too small",
- *pp_s_com_father, *pp_s_com_father);
+ RFALSE(B_LEVEL(*pp_s_com_father) <= DISK_LEAF_NODE_LEVEL,
+ "PAP-8185: (%b %z) level too small",
+ *pp_s_com_father, *pp_s_com_father);
- /* Check whether the common parent is locked. */
+ /* Check whether the common parent is locked. */
- if ( buffer_locked (*pp_s_com_father) ) {
- __wait_on_buffer(*pp_s_com_father);
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
- decrement_bcount(*pp_s_com_father);
- return REPEAT_SEARCH;
+ if (buffer_locked(*pp_s_com_father)) {
+ __wait_on_buffer(*pp_s_com_father);
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ decrement_bcount(*pp_s_com_father);
+ return REPEAT_SEARCH;
+ }
}
- }
-
- /* So, we got common parent of the current node and its left/right neighbor.
- Now we are geting the parent of the left/right neighbor. */
- /* Form key to get parent of the left/right neighbor. */
- le_key2cpu_key (&s_lr_father_key, B_N_PDELIM_KEY(*pp_s_com_father, ( c_lr_par == LEFT_PARENTS ) ?
- (p_s_tb->lkey[n_h - 1] = n_position - 1) : (p_s_tb->rkey[n_h - 1] = n_position)));
+ /* So, we got common parent of the current node and its left/right neighbor.
+ Now we are geting the parent of the left/right neighbor. */
+ /* Form key to get parent of the left/right neighbor. */
+ le_key2cpu_key(&s_lr_father_key,
+ B_N_PDELIM_KEY(*pp_s_com_father,
+ (c_lr_par ==
+ LEFT_PARENTS) ? (p_s_tb->lkey[n_h - 1] =
+ n_position -
+ 1) : (p_s_tb->rkey[n_h -
+ 1] =
+ n_position)));
- if ( c_lr_par == LEFT_PARENTS )
- decrement_key(&s_lr_father_key);
+ if (c_lr_par == LEFT_PARENTS)
+ decrement_key(&s_lr_father_key);
- if (search_by_key(p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father, n_h + 1) == IO_ERROR)
- // path is released
- return IO_ERROR;
+ if (search_by_key
+ (p_s_tb->tb_sb, &s_lr_father_key, &s_path_to_neighbor_father,
+ n_h + 1) == IO_ERROR)
+ // path is released
+ return IO_ERROR;
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
- decrement_counters_in_path(&s_path_to_neighbor_father);
- decrement_bcount(*pp_s_com_father);
- return REPEAT_SEARCH;
- }
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ decrement_counters_in_path(&s_path_to_neighbor_father);
+ decrement_bcount(*pp_s_com_father);
+ return REPEAT_SEARCH;
+ }
- *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father);
+ *pp_s_father = PATH_PLAST_BUFFER(&s_path_to_neighbor_father);
- RFALSE( B_LEVEL (*pp_s_father) != n_h + 1,
- "PAP-8190: (%b %z) level too small", *pp_s_father, *pp_s_father);
- RFALSE( s_path_to_neighbor_father.path_length < FIRST_PATH_ELEMENT_OFFSET,
- "PAP-8192: path length is too small");
+ RFALSE(B_LEVEL(*pp_s_father) != n_h + 1,
+ "PAP-8190: (%b %z) level too small", *pp_s_father, *pp_s_father);
+ RFALSE(s_path_to_neighbor_father.path_length <
+ FIRST_PATH_ELEMENT_OFFSET, "PAP-8192: path length is too small");
- s_path_to_neighbor_father.path_length--;
- decrement_counters_in_path(&s_path_to_neighbor_father);
- return CARRY_ON;
+ s_path_to_neighbor_father.path_length--;
+ decrement_counters_in_path(&s_path_to_neighbor_father);
+ return CARRY_ON;
}
-
/* Get parents of neighbors of node in the path(S[n_path_offset]) and common parents of
* S[n_path_offset] and L[n_path_offset]/R[n_path_offset]: F[n_path_offset], FL[n_path_offset],
* FR[n_path_offset], CFL[n_path_offset], CFR[n_path_offset].
@@ -1052,122 +1075,127 @@ static int get_far_parent (struct tree_balance * p_s_tb,
* Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked;
* CARRY_ON - schedule didn't occur while the function worked;
*/
-static int get_parents (struct tree_balance * p_s_tb, int n_h)
+static int get_parents(struct tree_balance *p_s_tb, int n_h)
{
- struct path * p_s_path = p_s_tb->tb_path;
- int n_position,
- n_ret_value,
- n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
- struct buffer_head * p_s_curf,
- * p_s_curcf;
-
- /* Current node is the root of the tree or will be root of the tree */
- if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) {
- /* The root can not have parents.
- Release nodes which previously were obtained as parents of the current node neighbors. */
+ struct path *p_s_path = p_s_tb->tb_path;
+ int n_position,
+ n_ret_value,
+ n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
+ struct buffer_head *p_s_curf, *p_s_curcf;
+
+ /* Current node is the root of the tree or will be root of the tree */
+ if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
+ /* The root can not have parents.
+ Release nodes which previously were obtained as parents of the current node neighbors. */
+ decrement_bcount(p_s_tb->FL[n_h]);
+ decrement_bcount(p_s_tb->CFL[n_h]);
+ decrement_bcount(p_s_tb->FR[n_h]);
+ decrement_bcount(p_s_tb->CFR[n_h]);
+ p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] =
+ p_s_tb->CFR[n_h] = NULL;
+ return CARRY_ON;
+ }
+
+ /* Get parent FL[n_path_offset] of L[n_path_offset]. */
+ if ((n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1))) {
+ /* Current node is not the first child of its parent. */
+ /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */
+ p_s_curf = p_s_curcf =
+ PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
+ get_bh(p_s_curf);
+ get_bh(p_s_curf);
+ p_s_tb->lkey[n_h] = n_position - 1;
+ } else {
+ /* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node.
+ Calculate current common parent of L[n_path_offset] and the current node. Note that
+ CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset].
+ Calculate lkey[n_path_offset]. */
+ if ((n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf,
+ &p_s_curcf,
+ LEFT_PARENTS)) != CARRY_ON)
+ return n_ret_value;
+ }
+
decrement_bcount(p_s_tb->FL[n_h]);
+ p_s_tb->FL[n_h] = p_s_curf; /* New initialization of FL[n_h]. */
decrement_bcount(p_s_tb->CFL[n_h]);
- decrement_bcount(p_s_tb->FR[n_h]);
- decrement_bcount(p_s_tb->CFR[n_h]);
- p_s_tb->FL[n_h] = p_s_tb->CFL[n_h] = p_s_tb->FR[n_h] = p_s_tb->CFR[n_h] = NULL;
- return CARRY_ON;
- }
-
- /* Get parent FL[n_path_offset] of L[n_path_offset]. */
- if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) ) {
- /* Current node is not the first child of its parent. */
- /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;*/
- p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
- get_bh(p_s_curf) ;
- get_bh(p_s_curf) ;
- p_s_tb->lkey[n_h] = n_position - 1;
- }
- else {
- /* Calculate current parent of L[n_path_offset], which is the left neighbor of the current node.
- Calculate current common parent of L[n_path_offset] and the current node. Note that
- CFL[n_path_offset] not equal FL[n_path_offset] and CFL[n_path_offset] not equal F[n_path_offset].
- Calculate lkey[n_path_offset]. */
- if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf,
- &p_s_curcf, LEFT_PARENTS)) != CARRY_ON )
- return n_ret_value;
- }
-
- decrement_bcount(p_s_tb->FL[n_h]);
- p_s_tb->FL[n_h] = p_s_curf; /* New initialization of FL[n_h]. */
- decrement_bcount(p_s_tb->CFL[n_h]);
- p_s_tb->CFL[n_h] = p_s_curcf; /* New initialization of CFL[n_h]. */
-
- RFALSE( (p_s_curf && !B_IS_IN_TREE (p_s_curf)) ||
- (p_s_curcf && !B_IS_IN_TREE (p_s_curcf)),
- "PAP-8195: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf);
+ p_s_tb->CFL[n_h] = p_s_curcf; /* New initialization of CFL[n_h]. */
+
+ RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) ||
+ (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)),
+ "PAP-8195: FL (%b) or CFL (%b) is invalid", p_s_curf, p_s_curcf);
/* Get parent FR[n_h] of R[n_h]. */
/* Current node is the last child of F[n_h]. FR[n_h] != F[n_h]. */
- if ( n_position == B_NR_ITEMS (PATH_H_PBUFFER(p_s_path, n_h + 1)) ) {
+ if (n_position == B_NR_ITEMS(PATH_H_PBUFFER(p_s_path, n_h + 1))) {
/* Calculate current parent of R[n_h], which is the right neighbor of F[n_h].
Calculate current common parent of R[n_h] and current node. Note that CFR[n_h]
not equal FR[n_path_offset] and CFR[n_h] not equal F[n_h]. */
- if ( (n_ret_value = get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf, RIGHT_PARENTS)) != CARRY_ON )
- return n_ret_value;
- }
- else {
+ if ((n_ret_value =
+ get_far_parent(p_s_tb, n_h + 1, &p_s_curf, &p_s_curcf,
+ RIGHT_PARENTS)) != CARRY_ON)
+ return n_ret_value;
+ } else {
/* Current node is not the last child of its parent F[n_h]. */
- /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2;*/
- p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
- get_bh(p_s_curf) ;
- get_bh(p_s_curf) ;
- p_s_tb->rkey[n_h] = n_position;
- }
-
- decrement_bcount(p_s_tb->FR[n_h]);
- p_s_tb->FR[n_h] = p_s_curf; /* New initialization of FR[n_path_offset]. */
-
- decrement_bcount(p_s_tb->CFR[n_h]);
- p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */
-
- RFALSE( (p_s_curf && !B_IS_IN_TREE (p_s_curf)) ||
- (p_s_curcf && !B_IS_IN_TREE (p_s_curcf)),
- "PAP-8205: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf);
-
- return CARRY_ON;
-}
+ /*(p_s_curf = p_s_curcf = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1))->b_count += 2; */
+ p_s_curf = p_s_curcf =
+ PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1);
+ get_bh(p_s_curf);
+ get_bh(p_s_curf);
+ p_s_tb->rkey[n_h] = n_position;
+ }
+ decrement_bcount(p_s_tb->FR[n_h]);
+ p_s_tb->FR[n_h] = p_s_curf; /* New initialization of FR[n_path_offset]. */
+
+ decrement_bcount(p_s_tb->CFR[n_h]);
+ p_s_tb->CFR[n_h] = p_s_curcf; /* New initialization of CFR[n_path_offset]. */
+
+ RFALSE((p_s_curf && !B_IS_IN_TREE(p_s_curf)) ||
+ (p_s_curcf && !B_IS_IN_TREE(p_s_curcf)),
+ "PAP-8205: FR (%b) or CFR (%b) is invalid", p_s_curf, p_s_curcf);
+
+ return CARRY_ON;
+}
/* it is possible to remove node as result of shiftings to
neighbors even when we insert or paste item. */
-static inline int can_node_be_removed (int mode, int lfree, int sfree, int rfree, struct tree_balance * tb, int h)
+static inline int can_node_be_removed(int mode, int lfree, int sfree, int rfree,
+ struct tree_balance *tb, int h)
{
- struct buffer_head * Sh = PATH_H_PBUFFER (tb->tb_path, h);
- int levbytes = tb->insert_size[h];
- struct item_head * ih;
- struct reiserfs_key * r_key = NULL;
-
- ih = B_N_PITEM_HEAD (Sh, 0);
- if ( tb->CFR[h] )
- r_key = B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]);
-
- if (
- lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes
- /* shifting may merge items which might save space */
- - (( ! h && op_is_left_mergeable (&(ih->ih_key), Sh->b_size) ) ? IH_SIZE : 0)
- - (( ! h && r_key && op_is_left_mergeable (r_key, Sh->b_size) ) ? IH_SIZE : 0)
- + (( h ) ? KEY_SIZE : 0))
- {
- /* node can not be removed */
- if (sfree >= levbytes ) { /* new item fits into node S[h] without any shifting */
- if ( ! h )
- tb->s0num = B_NR_ITEMS(Sh) + ((mode == M_INSERT ) ? 1 : 0);
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED;
+ struct buffer_head *Sh = PATH_H_PBUFFER(tb->tb_path, h);
+ int levbytes = tb->insert_size[h];
+ struct item_head *ih;
+ struct reiserfs_key *r_key = NULL;
+
+ ih = B_N_PITEM_HEAD(Sh, 0);
+ if (tb->CFR[h])
+ r_key = B_N_PDELIM_KEY(tb->CFR[h], tb->rkey[h]);
+
+ if (lfree + rfree + sfree < MAX_CHILD_SIZE(Sh) + levbytes
+ /* shifting may merge items which might save space */
+ -
+ ((!h
+ && op_is_left_mergeable(&(ih->ih_key), Sh->b_size)) ? IH_SIZE : 0)
+ -
+ ((!h && r_key
+ && op_is_left_mergeable(r_key, Sh->b_size)) ? IH_SIZE : 0)
+ + ((h) ? KEY_SIZE : 0)) {
+ /* node can not be removed */
+ if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */
+ if (!h)
+ tb->s0num =
+ B_NR_ITEMS(Sh) +
+ ((mode == M_INSERT) ? 1 : 0);
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED;
+ }
}
- }
- PROC_INFO_INC( tb -> tb_sb, can_node_be_removed[ h ] );
- return !NO_BALANCING_NEEDED;
+ PROC_INFO_INC(tb->tb_sb, can_node_be_removed[h]);
+ return !NO_BALANCING_NEEDED;
}
-
-
/* Check whether current node S[h] is balanced when increasing its size by
* Inserting or Pasting.
* Calculate parameters for balancing for current level h.
@@ -1182,154 +1210,157 @@ static inline int can_node_be_removed (int mode, int lfree, int sfree, int rfree
* -2 - no disk space.
*/
/* ip means Inserting or Pasting */
-static int ip_check_balance (struct tree_balance * tb, int h)
+static int ip_check_balance(struct tree_balance *tb, int h)
{
- struct virtual_node * vn = tb->tb_vn;
- int levbytes, /* Number of bytes that must be inserted into (value
- is negative if bytes are deleted) buffer which
- contains node being balanced. The mnemonic is
- that the attempted change in node space used level
- is levbytes bytes. */
- n_ret_value;
-
- int lfree, sfree, rfree /* free space in L, S and R */;
-
- /* nver is short for number of vertixes, and lnver is the number if
- we shift to the left, rnver is the number if we shift to the
- right, and lrnver is the number if we shift in both directions.
- The goal is to minimize first the number of vertixes, and second,
- the number of vertixes whose contents are changed by shifting,
- and third the number of uncached vertixes whose contents are
- changed by shifting and must be read from disk. */
- int nver, lnver, rnver, lrnver;
-
- /* used at leaf level only, S0 = S[0] is the node being balanced,
- sInum [ I = 0,1,2 ] is the number of items that will
- remain in node SI after balancing. S1 and S2 are new
- nodes that might be created. */
-
- /* we perform 8 calls to get_num_ver(). For each call we calculate five parameters.
- where 4th parameter is s1bytes and 5th - s2bytes
- */
- short snum012[40] = {0,}; /* s0num, s1num, s2num for 8 cases
- 0,1 - do not shift and do not shift but bottle
- 2 - shift only whole item to left
- 3 - shift to left and bottle as much as possible
- 4,5 - shift to right (whole items and as much as possible
- 6,7 - shift to both directions (whole items and as much as possible)
- */
-
- /* Sh is the node whose balance is currently being checked */
- struct buffer_head * Sh;
-
- Sh = PATH_H_PBUFFER (tb->tb_path, h);
- levbytes = tb->insert_size[h];
-
- /* Calculate balance parameters for creating new root. */
- if ( ! Sh ) {
- if ( ! h )
- reiserfs_panic (tb->tb_sb, "vs-8210: ip_check_balance: S[0] can not be 0");
- switch ( n_ret_value = get_empty_nodes (tb, h) ) {
- case CARRY_ON:
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
-
- case NO_DISK_SPACE:
- case REPEAT_SEARCH:
- return n_ret_value;
- default:
- reiserfs_panic(tb->tb_sb, "vs-8215: ip_check_balance: incorrect return value of get_empty_nodes");
+ struct virtual_node *vn = tb->tb_vn;
+ int levbytes, /* Number of bytes that must be inserted into (value
+ is negative if bytes are deleted) buffer which
+ contains node being balanced. The mnemonic is
+ that the attempted change in node space used level
+ is levbytes bytes. */
+ n_ret_value;
+
+ int lfree, sfree, rfree /* free space in L, S and R */ ;
+
+ /* nver is short for number of vertixes, and lnver is the number if
+ we shift to the left, rnver is the number if we shift to the
+ right, and lrnver is the number if we shift in both directions.
+ The goal is to minimize first the number of vertixes, and second,
+ the number of vertixes whose contents are changed by shifting,
+ and third the number of uncached vertixes whose contents are
+ changed by shifting and must be read from disk. */
+ int nver, lnver, rnver, lrnver;
+
+ /* used at leaf level only, S0 = S[0] is the node being balanced,
+ sInum [ I = 0,1,2 ] is the number of items that will
+ remain in node SI after balancing. S1 and S2 are new
+ nodes that might be created. */
+
+ /* we perform 8 calls to get_num_ver(). For each call we calculate five parameters.
+ where 4th parameter is s1bytes and 5th - s2bytes
+ */
+ short snum012[40] = { 0, }; /* s0num, s1num, s2num for 8 cases
+ 0,1 - do not shift and do not shift but bottle
+ 2 - shift only whole item to left
+ 3 - shift to left and bottle as much as possible
+ 4,5 - shift to right (whole items and as much as possible
+ 6,7 - shift to both directions (whole items and as much as possible)
+ */
+
+ /* Sh is the node whose balance is currently being checked */
+ struct buffer_head *Sh;
+
+ Sh = PATH_H_PBUFFER(tb->tb_path, h);
+ levbytes = tb->insert_size[h];
+
+ /* Calculate balance parameters for creating new root. */
+ if (!Sh) {
+ if (!h)
+ reiserfs_panic(tb->tb_sb,
+ "vs-8210: ip_check_balance: S[0] can not be 0");
+ switch (n_ret_value = get_empty_nodes(tb, h)) {
+ case CARRY_ON:
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
+
+ case NO_DISK_SPACE:
+ case REPEAT_SEARCH:
+ return n_ret_value;
+ default:
+ reiserfs_panic(tb->tb_sb,
+ "vs-8215: ip_check_balance: incorrect return value of get_empty_nodes");
+ }
}
- }
-
- if ( (n_ret_value = get_parents (tb, h)) != CARRY_ON ) /* get parents of S[h] neighbors. */
- return n_ret_value;
-
- sfree = B_FREE_SPACE (Sh);
-
- /* get free space of neighbors */
- rfree = get_rfree (tb, h);
- lfree = get_lfree (tb, h);
-
- if (can_node_be_removed (vn->vn_mode, lfree, sfree, rfree, tb, h) == NO_BALANCING_NEEDED)
- /* and new item fits into node S[h] without any shifting */
- return NO_BALANCING_NEEDED;
-
- create_virtual_node (tb, h);
-
- /*
- determine maximal number of items we can shift to the left neighbor (in tb structure)
- and the maximal number of bytes that can flow to the left neighbor
- from the left most liquid item that cannot be shifted from S[0] entirely (returned value)
- */
- check_left (tb, h, lfree);
-
- /*
- determine maximal number of items we can shift to the right neighbor (in tb structure)
- and the maximal number of bytes that can flow to the right neighbor
- from the right most liquid item that cannot be shifted from S[0] entirely (returned value)
- */
- check_right (tb, h, rfree);
-
-
- /* all contents of internal node S[h] can be moved into its
- neighbors, S[h] will be removed after balancing */
- if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) {
- int to_r;
-
- /* Since we are working on internal nodes, and our internal
- nodes have fixed size entries, then we can balance by the
- number of items rather than the space they consume. In this
- routine we set the left node equal to the right node,
- allowing a difference of less than or equal to 1 child
- pointer. */
- to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 -
- (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
- set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- /* this checks balance condition, that any two neighboring nodes can not fit in one node */
- RFALSE( h &&
- ( tb->lnum[h] >= vn->vn_nr_item + 1 ||
- tb->rnum[h] >= vn->vn_nr_item + 1),
- "vs-8220: tree is not balanced on internal level");
- RFALSE( ! h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) ||
- (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1)) ),
- "vs-8225: tree is not balanced on leaf level");
-
- /* all contents of S[0] can be moved into its neighbors
- S[0] will be removed after balancing. */
- if (!h && is_leaf_removable (tb))
- return CARRY_ON;
+ if ((n_ret_value = get_parents(tb, h)) != CARRY_ON) /* get parents of S[h] neighbors. */
+ return n_ret_value;
- /* why do we perform this check here rather than earlier??
- Answer: we can win 1 node in some cases above. Moreover we
- checked it above, when we checked, that S[0] is not removable
- in principle */
- if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */
- if ( ! h )
- tb->s0num = vn->vn_nr_item;
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED;
- }
+ sfree = B_FREE_SPACE(Sh);
+
+ /* get free space of neighbors */
+ rfree = get_rfree(tb, h);
+ lfree = get_lfree(tb, h);
+
+ if (can_node_be_removed(vn->vn_mode, lfree, sfree, rfree, tb, h) ==
+ NO_BALANCING_NEEDED)
+ /* and new item fits into node S[h] without any shifting */
+ return NO_BALANCING_NEEDED;
+ create_virtual_node(tb, h);
- {
- int lpar, rpar, nset, lset, rset, lrset;
- /*
- * regular overflowing of the node
+ /*
+ determine maximal number of items we can shift to the left neighbor (in tb structure)
+ and the maximal number of bytes that can flow to the left neighbor
+ from the left most liquid item that cannot be shifted from S[0] entirely (returned value)
*/
+ check_left(tb, h, lfree);
- /* get_num_ver works in 2 modes (FLOW & NO_FLOW)
- lpar, rpar - number of items we can shift to left/right neighbor (including splitting item)
- nset, lset, rset, lrset - shows, whether flowing items give better packing
- */
+ /*
+ determine maximal number of items we can shift to the right neighbor (in tb structure)
+ and the maximal number of bytes that can flow to the right neighbor
+ from the right most liquid item that cannot be shifted from S[0] entirely (returned value)
+ */
+ check_right(tb, h, rfree);
+
+ /* all contents of internal node S[h] can be moved into its
+ neighbors, S[h] will be removed after balancing */
+ if (h && (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)) {
+ int to_r;
+
+ /* Since we are working on internal nodes, and our internal
+ nodes have fixed size entries, then we can balance by the
+ number of items rather than the space they consume. In this
+ routine we set the left node equal to the right node,
+ allowing a difference of less than or equal to 1 child
+ pointer. */
+ to_r =
+ ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] +
+ vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 -
+ tb->rnum[h]);
+ set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL,
+ -1, -1);
+ return CARRY_ON;
+ }
+
+ /* this checks balance condition, that any two neighboring nodes can not fit in one node */
+ RFALSE(h &&
+ (tb->lnum[h] >= vn->vn_nr_item + 1 ||
+ tb->rnum[h] >= vn->vn_nr_item + 1),
+ "vs-8220: tree is not balanced on internal level");
+ RFALSE(!h && ((tb->lnum[h] >= vn->vn_nr_item && (tb->lbytes == -1)) ||
+ (tb->rnum[h] >= vn->vn_nr_item && (tb->rbytes == -1))),
+ "vs-8225: tree is not balanced on leaf level");
+
+ /* all contents of S[0] can be moved into its neighbors
+ S[0] will be removed after balancing. */
+ if (!h && is_leaf_removable(tb))
+ return CARRY_ON;
+
+ /* why do we perform this check here rather than earlier??
+ Answer: we can win 1 node in some cases above. Moreover we
+ checked it above, when we checked, that S[0] is not removable
+ in principle */
+ if (sfree >= levbytes) { /* new item fits into node S[h] without any shifting */
+ if (!h)
+ tb->s0num = vn->vn_nr_item;
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED;
+ }
+
+ {
+ int lpar, rpar, nset, lset, rset, lrset;
+ /*
+ * regular overflowing of the node
+ */
+
+ /* get_num_ver works in 2 modes (FLOW & NO_FLOW)
+ lpar, rpar - number of items we can shift to left/right neighbor (including splitting item)
+ nset, lset, rset, lrset - shows, whether flowing items give better packing
+ */
#define FLOW 1
-#define NO_FLOW 0 /* do not any splitting */
+#define NO_FLOW 0 /* do not any splitting */
- /* we choose one the following */
+ /* we choose one the following */
#define NOTHING_SHIFT_NO_FLOW 0
#define NOTHING_SHIFT_FLOW 5
#define LEFT_SHIFT_NO_FLOW 10
@@ -1339,164 +1370,173 @@ static int ip_check_balance (struct tree_balance * tb, int h)
#define LR_SHIFT_NO_FLOW 30
#define LR_SHIFT_FLOW 35
+ lpar = tb->lnum[h];
+ rpar = tb->rnum[h];
+
+ /* calculate number of blocks S[h] must be split into when
+ nothing is shifted to the neighbors,
+ as well as number of items in each part of the split node (s012 numbers),
+ and number of bytes (s1bytes) of the shared drop which flow to S1 if any */
+ nset = NOTHING_SHIFT_NO_FLOW;
+ nver = get_num_ver(vn->vn_mode, tb, h,
+ 0, -1, h ? vn->vn_nr_item : 0, -1,
+ snum012, NO_FLOW);
+
+ if (!h) {
+ int nver1;
+
+ /* note, that in this case we try to bottle between S[0] and S1 (S1 - the first new node) */
+ nver1 = get_num_ver(vn->vn_mode, tb, h,
+ 0, -1, 0, -1,
+ snum012 + NOTHING_SHIFT_FLOW, FLOW);
+ if (nver > nver1)
+ nset = NOTHING_SHIFT_FLOW, nver = nver1;
+ }
- lpar = tb->lnum[h];
- rpar = tb->rnum[h];
-
-
- /* calculate number of blocks S[h] must be split into when
- nothing is shifted to the neighbors,
- as well as number of items in each part of the split node (s012 numbers),
- and number of bytes (s1bytes) of the shared drop which flow to S1 if any */
- nset = NOTHING_SHIFT_NO_FLOW;
- nver = get_num_ver (vn->vn_mode, tb, h,
- 0, -1, h?vn->vn_nr_item:0, -1,
- snum012, NO_FLOW);
-
- if (!h)
- {
- int nver1;
-
- /* note, that in this case we try to bottle between S[0] and S1 (S1 - the first new node) */
- nver1 = get_num_ver (vn->vn_mode, tb, h,
- 0, -1, 0, -1,
- snum012 + NOTHING_SHIFT_FLOW, FLOW);
- if (nver > nver1)
- nset = NOTHING_SHIFT_FLOW, nver = nver1;
- }
-
-
- /* calculate number of blocks S[h] must be split into when
- l_shift_num first items and l_shift_bytes of the right most
- liquid item to be shifted are shifted to the left neighbor,
- as well as number of items in each part of the splitted node (s012 numbers),
- and number of bytes (s1bytes) of the shared drop which flow to S1 if any
- */
- lset = LEFT_SHIFT_NO_FLOW;
- lnver = get_num_ver (vn->vn_mode, tb, h,
- lpar - (( h || tb->lbytes == -1 ) ? 0 : 1), -1, h ? vn->vn_nr_item:0, -1,
- snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW);
- if (!h)
- {
- int lnver1;
-
- lnver1 = get_num_ver (vn->vn_mode, tb, h,
- lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, 0, -1,
- snum012 + LEFT_SHIFT_FLOW, FLOW);
- if (lnver > lnver1)
- lset = LEFT_SHIFT_FLOW, lnver = lnver1;
- }
-
-
- /* calculate number of blocks S[h] must be split into when
- r_shift_num first items and r_shift_bytes of the left most
- liquid item to be shifted are shifted to the right neighbor,
- as well as number of items in each part of the splitted node (s012 numbers),
- and number of bytes (s1bytes) of the shared drop which flow to S1 if any
- */
- rset = RIGHT_SHIFT_NO_FLOW;
- rnver = get_num_ver (vn->vn_mode, tb, h,
- 0, -1, h ? (vn->vn_nr_item-rpar) : (rpar - (( tb->rbytes != -1 ) ? 1 : 0)), -1,
- snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW);
- if (!h)
- {
- int rnver1;
-
- rnver1 = get_num_ver (vn->vn_mode, tb, h,
- 0, -1, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes,
- snum012 + RIGHT_SHIFT_FLOW, FLOW);
-
- if (rnver > rnver1)
- rset = RIGHT_SHIFT_FLOW, rnver = rnver1;
- }
-
-
- /* calculate number of blocks S[h] must be split into when
- items are shifted in both directions,
- as well as number of items in each part of the splitted node (s012 numbers),
- and number of bytes (s1bytes) of the shared drop which flow to S1 if any
- */
- lrset = LR_SHIFT_NO_FLOW;
- lrnver = get_num_ver (vn->vn_mode, tb, h,
- lpar - ((h || tb->lbytes == -1) ? 0 : 1), -1, h ? (vn->vn_nr_item-rpar):(rpar - ((tb->rbytes != -1) ? 1 : 0)), -1,
- snum012 + LR_SHIFT_NO_FLOW, NO_FLOW);
- if (!h)
- {
- int lrnver1;
-
- lrnver1 = get_num_ver (vn->vn_mode, tb, h,
- lpar - ((tb->lbytes != -1) ? 1 : 0), tb->lbytes, (rpar - ((tb->rbytes != -1) ? 1 : 0)), tb->rbytes,
- snum012 + LR_SHIFT_FLOW, FLOW);
- if (lrnver > lrnver1)
- lrset = LR_SHIFT_FLOW, lrnver = lrnver1;
- }
-
-
+ /* calculate number of blocks S[h] must be split into when
+ l_shift_num first items and l_shift_bytes of the right most
+ liquid item to be shifted are shifted to the left neighbor,
+ as well as number of items in each part of the splitted node (s012 numbers),
+ and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+ */
+ lset = LEFT_SHIFT_NO_FLOW;
+ lnver = get_num_ver(vn->vn_mode, tb, h,
+ lpar - ((h || tb->lbytes == -1) ? 0 : 1),
+ -1, h ? vn->vn_nr_item : 0, -1,
+ snum012 + LEFT_SHIFT_NO_FLOW, NO_FLOW);
+ if (!h) {
+ int lnver1;
+
+ lnver1 = get_num_ver(vn->vn_mode, tb, h,
+ lpar -
+ ((tb->lbytes != -1) ? 1 : 0),
+ tb->lbytes, 0, -1,
+ snum012 + LEFT_SHIFT_FLOW, FLOW);
+ if (lnver > lnver1)
+ lset = LEFT_SHIFT_FLOW, lnver = lnver1;
+ }
- /* Our general shifting strategy is:
- 1) to minimized number of new nodes;
- 2) to minimized number of neighbors involved in shifting;
- 3) to minimized number of disk reads; */
+ /* calculate number of blocks S[h] must be split into when
+ r_shift_num first items and r_shift_bytes of the left most
+ liquid item to be shifted are shifted to the right neighbor,
+ as well as number of items in each part of the splitted node (s012 numbers),
+ and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+ */
+ rset = RIGHT_SHIFT_NO_FLOW;
+ rnver = get_num_ver(vn->vn_mode, tb, h,
+ 0, -1,
+ h ? (vn->vn_nr_item - rpar) : (rpar -
+ ((tb->
+ rbytes !=
+ -1) ? 1 :
+ 0)), -1,
+ snum012 + RIGHT_SHIFT_NO_FLOW, NO_FLOW);
+ if (!h) {
+ int rnver1;
+
+ rnver1 = get_num_ver(vn->vn_mode, tb, h,
+ 0, -1,
+ (rpar -
+ ((tb->rbytes != -1) ? 1 : 0)),
+ tb->rbytes,
+ snum012 + RIGHT_SHIFT_FLOW, FLOW);
+
+ if (rnver > rnver1)
+ rset = RIGHT_SHIFT_FLOW, rnver = rnver1;
+ }
- /* we can win TWO or ONE nodes by shifting in both directions */
- if (lrnver < lnver && lrnver < rnver)
- {
- RFALSE( h &&
- (tb->lnum[h] != 1 ||
- tb->rnum[h] != 1 ||
- lrnver != 1 || rnver != 2 || lnver != 2 || h != 1),
- "vs-8230: bad h");
- if (lrset == LR_SHIFT_FLOW)
- set_parameters (tb, h, tb->lnum[h], tb->rnum[h], lrnver, snum012 + lrset,
- tb->lbytes, tb->rbytes);
- else
- set_parameters (tb, h, tb->lnum[h] - ((tb->lbytes == -1) ? 0 : 1),
- tb->rnum[h] - ((tb->rbytes == -1) ? 0 : 1), lrnver, snum012 + lrset, -1, -1);
-
- return CARRY_ON;
- }
+ /* calculate number of blocks S[h] must be split into when
+ items are shifted in both directions,
+ as well as number of items in each part of the splitted node (s012 numbers),
+ and number of bytes (s1bytes) of the shared drop which flow to S1 if any
+ */
+ lrset = LR_SHIFT_NO_FLOW;
+ lrnver = get_num_ver(vn->vn_mode, tb, h,
+ lpar - ((h || tb->lbytes == -1) ? 0 : 1),
+ -1,
+ h ? (vn->vn_nr_item - rpar) : (rpar -
+ ((tb->
+ rbytes !=
+ -1) ? 1 :
+ 0)), -1,
+ snum012 + LR_SHIFT_NO_FLOW, NO_FLOW);
+ if (!h) {
+ int lrnver1;
+
+ lrnver1 = get_num_ver(vn->vn_mode, tb, h,
+ lpar -
+ ((tb->lbytes != -1) ? 1 : 0),
+ tb->lbytes,
+ (rpar -
+ ((tb->rbytes != -1) ? 1 : 0)),
+ tb->rbytes,
+ snum012 + LR_SHIFT_FLOW, FLOW);
+ if (lrnver > lrnver1)
+ lrset = LR_SHIFT_FLOW, lrnver = lrnver1;
+ }
- /* if shifting doesn't lead to better packing then don't shift */
- if (nver == lrnver)
- {
- set_parameters (tb, h, 0, 0, nver, snum012 + nset, -1, -1);
- return CARRY_ON;
- }
+ /* Our general shifting strategy is:
+ 1) to minimized number of new nodes;
+ 2) to minimized number of neighbors involved in shifting;
+ 3) to minimized number of disk reads; */
+
+ /* we can win TWO or ONE nodes by shifting in both directions */
+ if (lrnver < lnver && lrnver < rnver) {
+ RFALSE(h &&
+ (tb->lnum[h] != 1 ||
+ tb->rnum[h] != 1 ||
+ lrnver != 1 || rnver != 2 || lnver != 2
+ || h != 1), "vs-8230: bad h");
+ if (lrset == LR_SHIFT_FLOW)
+ set_parameters(tb, h, tb->lnum[h], tb->rnum[h],
+ lrnver, snum012 + lrset,
+ tb->lbytes, tb->rbytes);
+ else
+ set_parameters(tb, h,
+ tb->lnum[h] -
+ ((tb->lbytes == -1) ? 0 : 1),
+ tb->rnum[h] -
+ ((tb->rbytes == -1) ? 0 : 1),
+ lrnver, snum012 + lrset, -1, -1);
+
+ return CARRY_ON;
+ }
+ /* if shifting doesn't lead to better packing then don't shift */
+ if (nver == lrnver) {
+ set_parameters(tb, h, 0, 0, nver, snum012 + nset, -1,
+ -1);
+ return CARRY_ON;
+ }
- /* now we know that for better packing shifting in only one
- direction either to the left or to the right is required */
+ /* now we know that for better packing shifting in only one
+ direction either to the left or to the right is required */
- /* if shifting to the left is better than shifting to the right */
- if (lnver < rnver)
- {
- SET_PAR_SHIFT_LEFT;
- return CARRY_ON;
- }
+ /* if shifting to the left is better than shifting to the right */
+ if (lnver < rnver) {
+ SET_PAR_SHIFT_LEFT;
+ return CARRY_ON;
+ }
- /* if shifting to the right is better than shifting to the left */
- if (lnver > rnver)
- {
- SET_PAR_SHIFT_RIGHT;
- return CARRY_ON;
- }
+ /* if shifting to the right is better than shifting to the left */
+ if (lnver > rnver) {
+ SET_PAR_SHIFT_RIGHT;
+ return CARRY_ON;
+ }
+ /* now shifting in either direction gives the same number
+ of nodes and we can make use of the cached neighbors */
+ if (is_left_neighbor_in_cache(tb, h)) {
+ SET_PAR_SHIFT_LEFT;
+ return CARRY_ON;
+ }
- /* now shifting in either direction gives the same number
- of nodes and we can make use of the cached neighbors */
- if (is_left_neighbor_in_cache (tb,h))
- {
- SET_PAR_SHIFT_LEFT;
- return CARRY_ON;
+ /* shift to the right independently on whether the right neighbor in cache or not */
+ SET_PAR_SHIFT_RIGHT;
+ return CARRY_ON;
}
-
- /* shift to the right independently on whether the right neighbor in cache or not */
- SET_PAR_SHIFT_RIGHT;
- return CARRY_ON;
- }
}
-
/* Check whether current node S[h] is balanced when Decreasing its size by
* Deleting or Cutting for INTERNAL node of S+tree.
* Calculate parameters for balancing for current level h.
@@ -1513,157 +1553,173 @@ static int ip_check_balance (struct tree_balance * tb, int h)
* Note: Items of internal nodes have fixed size, so the balance condition for
* the internal part of S+tree is as for the B-trees.
*/
-static int dc_check_balance_internal (struct tree_balance * tb, int h)
+static int dc_check_balance_internal(struct tree_balance *tb, int h)
{
- struct virtual_node * vn = tb->tb_vn;
+ struct virtual_node *vn = tb->tb_vn;
- /* Sh is the node whose balance is currently being checked,
- and Fh is its father. */
- struct buffer_head * Sh, * Fh;
- int maxsize,
- n_ret_value;
- int lfree, rfree /* free space in L and R */;
+ /* Sh is the node whose balance is currently being checked,
+ and Fh is its father. */
+ struct buffer_head *Sh, *Fh;
+ int maxsize, n_ret_value;
+ int lfree, rfree /* free space in L and R */ ;
- Sh = PATH_H_PBUFFER (tb->tb_path, h);
- Fh = PATH_H_PPARENT (tb->tb_path, h);
+ Sh = PATH_H_PBUFFER(tb->tb_path, h);
+ Fh = PATH_H_PPARENT(tb->tb_path, h);
- maxsize = MAX_CHILD_SIZE(Sh);
+ maxsize = MAX_CHILD_SIZE(Sh);
/* using tb->insert_size[h], which is negative in this case, create_virtual_node calculates: */
/* new_nr_item = number of items node would have if operation is */
/* performed without balancing (new_nr_item); */
- create_virtual_node (tb, h);
+ create_virtual_node(tb, h);
- if ( ! Fh )
- { /* S[h] is the root. */
- if ( vn->vn_nr_item > 0 )
- {
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
+ if (!Fh) { /* S[h] is the root. */
+ if (vn->vn_nr_item > 0) {
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED; /* no balancing for higher levels needed */
+ }
+ /* new_nr_item == 0.
+ * Current root will be deleted resulting in
+ * decrementing the tree height. */
+ set_parameters(tb, h, 0, 0, 0, NULL, -1, -1);
+ return CARRY_ON;
+ }
+
+ if ((n_ret_value = get_parents(tb, h)) != CARRY_ON)
+ return n_ret_value;
+
+ /* get free space of neighbors */
+ rfree = get_rfree(tb, h);
+ lfree = get_lfree(tb, h);
+
+ /* determine maximal number of items we can fit into neighbors */
+ check_left(tb, h, lfree);
+ check_right(tb, h, rfree);
+
+ if (vn->vn_nr_item >= MIN_NR_KEY(Sh)) { /* Balance condition for the internal node is valid.
+ * In this case we balance only if it leads to better packing. */
+ if (vn->vn_nr_item == MIN_NR_KEY(Sh)) { /* Here we join S[h] with one of its neighbors,
+ * which is impossible with greater values of new_nr_item. */
+ if (tb->lnum[h] >= vn->vn_nr_item + 1) {
+ /* All contents of S[h] can be moved to L[h]. */
+ int n;
+ int order_L;
+
+ order_L =
+ ((n =
+ PATH_H_B_ITEM_ORDER(tb->tb_path,
+ h)) ==
+ 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
+ n = dc_size(B_N_CHILD(tb->FL[h], order_L)) /
+ (DC_SIZE + KEY_SIZE);
+ set_parameters(tb, h, -n - 1, 0, 0, NULL, -1,
+ -1);
+ return CARRY_ON;
+ }
+
+ if (tb->rnum[h] >= vn->vn_nr_item + 1) {
+ /* All contents of S[h] can be moved to R[h]. */
+ int n;
+ int order_R;
+
+ order_R =
+ ((n =
+ PATH_H_B_ITEM_ORDER(tb->tb_path,
+ h)) ==
+ B_NR_ITEMS(Fh)) ? 0 : n + 1;
+ n = dc_size(B_N_CHILD(tb->FR[h], order_R)) /
+ (DC_SIZE + KEY_SIZE);
+ set_parameters(tb, h, 0, -n - 1, 0, NULL, -1,
+ -1);
+ return CARRY_ON;
+ }
+ }
+
+ if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) {
+ /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
+ int to_r;
+
+ to_r =
+ ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] -
+ tb->rnum[h] + vn->vn_nr_item + 1) / 2 -
+ (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
+ set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r,
+ 0, NULL, -1, -1);
+ return CARRY_ON;
+ }
+
+ /* Balancing does not lead to better packing. */
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED;
}
- /* new_nr_item == 0.
- * Current root will be deleted resulting in
- * decrementing the tree height. */
- set_parameters (tb, h, 0, 0, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON )
- return n_ret_value;
-
-
- /* get free space of neighbors */
- rfree = get_rfree (tb, h);
- lfree = get_lfree (tb, h);
-
- /* determine maximal number of items we can fit into neighbors */
- check_left (tb, h, lfree);
- check_right (tb, h, rfree);
-
-
- if ( vn->vn_nr_item >= MIN_NR_KEY(Sh) )
- { /* Balance condition for the internal node is valid.
- * In this case we balance only if it leads to better packing. */
- if ( vn->vn_nr_item == MIN_NR_KEY(Sh) )
- { /* Here we join S[h] with one of its neighbors,
- * which is impossible with greater values of new_nr_item. */
- if ( tb->lnum[h] >= vn->vn_nr_item + 1 )
- {
- /* All contents of S[h] can be moved to L[h]. */
- int n;
- int order_L;
-
- order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
- n = dc_size(B_N_CHILD(tb->FL[h],order_L)) / (DC_SIZE + KEY_SIZE);
- set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- if ( tb->rnum[h] >= vn->vn_nr_item + 1 )
- {
- /* All contents of S[h] can be moved to R[h]. */
- int n;
- int order_R;
-
- order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : n + 1;
- n = dc_size(B_N_CHILD(tb->FR[h],order_R)) / (DC_SIZE + KEY_SIZE);
- set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
- return CARRY_ON;
- }
+
+ /* Current node contain insufficient number of items. Balancing is required. */
+ /* Check whether we can merge S[h] with left neighbor. */
+ if (tb->lnum[h] >= vn->vn_nr_item + 1)
+ if (is_left_neighbor_in_cache(tb, h)
+ || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h]) {
+ int n;
+ int order_L;
+
+ order_L =
+ ((n =
+ PATH_H_B_ITEM_ORDER(tb->tb_path,
+ h)) ==
+ 0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
+ n = dc_size(B_N_CHILD(tb->FL[h], order_L)) / (DC_SIZE +
+ KEY_SIZE);
+ set_parameters(tb, h, -n - 1, 0, 0, NULL, -1, -1);
+ return CARRY_ON;
+ }
+
+ /* Check whether we can merge S[h] with right neighbor. */
+ if (tb->rnum[h] >= vn->vn_nr_item + 1) {
+ int n;
+ int order_R;
+
+ order_R =
+ ((n =
+ PATH_H_B_ITEM_ORDER(tb->tb_path,
+ h)) == B_NR_ITEMS(Fh)) ? 0 : (n + 1);
+ n = dc_size(B_N_CHILD(tb->FR[h], order_R)) / (DC_SIZE +
+ KEY_SIZE);
+ set_parameters(tb, h, 0, -n - 1, 0, NULL, -1, -1);
+ return CARRY_ON;
}
- if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)
- {
- /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
- int to_r;
+ /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
+ if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1) {
+ int to_r;
+
+ to_r =
+ ((MAX_NR_KEY(Sh) << 1) + 2 - tb->lnum[h] - tb->rnum[h] +
+ vn->vn_nr_item + 1) / 2 - (MAX_NR_KEY(Sh) + 1 -
+ tb->rnum[h]);
+ set_parameters(tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL,
+ -1, -1);
+ return CARRY_ON;
+ }
- to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 -
- (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
- set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
- return CARRY_ON;
+ /* For internal nodes try to borrow item from a neighbor */
+ RFALSE(!tb->FL[h] && !tb->FR[h], "vs-8235: trying to borrow for root");
+
+ /* Borrow one or two items from caching neighbor */
+ if (is_left_neighbor_in_cache(tb, h) || !tb->FR[h]) {
+ int from_l;
+
+ from_l =
+ (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item +
+ 1) / 2 - (vn->vn_nr_item + 1);
+ set_parameters(tb, h, -from_l, 0, 1, NULL, -1, -1);
+ return CARRY_ON;
}
- /* Balancing does not lead to better packing. */
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED;
- }
-
- /* Current node contain insufficient number of items. Balancing is required. */
- /* Check whether we can merge S[h] with left neighbor. */
- if (tb->lnum[h] >= vn->vn_nr_item + 1)
- if (is_left_neighbor_in_cache (tb,h) || tb->rnum[h] < vn->vn_nr_item + 1 || !tb->FR[h])
- {
- int n;
- int order_L;
-
- order_L = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==0) ? B_NR_ITEMS(tb->FL[h]) : n - 1;
- n = dc_size(B_N_CHILD(tb->FL[h],order_L)) / (DC_SIZE + KEY_SIZE);
- set_parameters (tb, h, -n-1, 0, 0, NULL, -1, -1);
+ set_parameters(tb, h, 0,
+ -((MAX_NR_KEY(Sh) + 1 - tb->rnum[h] + vn->vn_nr_item +
+ 1) / 2 - (vn->vn_nr_item + 1)), 1, NULL, -1, -1);
return CARRY_ON;
- }
-
- /* Check whether we can merge S[h] with right neighbor. */
- if (tb->rnum[h] >= vn->vn_nr_item + 1)
- {
- int n;
- int order_R;
-
- order_R = ((n=PATH_H_B_ITEM_ORDER(tb->tb_path, h))==B_NR_ITEMS(Fh)) ? 0 : (n + 1);
- n = dc_size(B_N_CHILD(tb->FR[h],order_R)) / (DC_SIZE + KEY_SIZE);
- set_parameters (tb, h, 0, -n-1, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- /* All contents of S[h] can be moved to the neighbors (L[h] & R[h]). */
- if (tb->rnum[h] + tb->lnum[h] >= vn->vn_nr_item + 1)
- {
- int to_r;
-
- to_r = ((MAX_NR_KEY(Sh)<<1)+2-tb->lnum[h]-tb->rnum[h]+vn->vn_nr_item+1)/2 -
- (MAX_NR_KEY(Sh) + 1 - tb->rnum[h]);
- set_parameters (tb, h, vn->vn_nr_item + 1 - to_r, to_r, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- /* For internal nodes try to borrow item from a neighbor */
- RFALSE( !tb->FL[h] && !tb->FR[h], "vs-8235: trying to borrow for root");
-
- /* Borrow one or two items from caching neighbor */
- if (is_left_neighbor_in_cache (tb,h) || !tb->FR[h])
- {
- int from_l;
-
- from_l = (MAX_NR_KEY(Sh) + 1 - tb->lnum[h] + vn->vn_nr_item + 1) / 2 - (vn->vn_nr_item + 1);
- set_parameters (tb, h, -from_l, 0, 1, NULL, -1, -1);
- return CARRY_ON;
- }
-
- set_parameters (tb, h, 0, -((MAX_NR_KEY(Sh)+1-tb->rnum[h]+vn->vn_nr_item+1)/2-(vn->vn_nr_item+1)), 1,
- NULL, -1, -1);
- return CARRY_ON;
}
-
/* Check whether current node S[h] is balanced when Decreasing its size by
* Deleting or Truncating for LEAF node of S+tree.
* Calculate parameters for balancing for current level h.
@@ -1677,90 +1733,86 @@ static int dc_check_balance_internal (struct tree_balance * tb, int h)
* -1 - no balancing for higher levels needed;
* -2 - no disk space.
*/
-static int dc_check_balance_leaf (struct tree_balance * tb, int h)
+static int dc_check_balance_leaf(struct tree_balance *tb, int h)
{
- struct virtual_node * vn = tb->tb_vn;
-
- /* Number of bytes that must be deleted from
- (value is negative if bytes are deleted) buffer which
- contains node being balanced. The mnemonic is that the
- attempted change in node space used level is levbytes bytes. */
- int levbytes;
- /* the maximal item size */
- int maxsize,
- n_ret_value;
- /* S0 is the node whose balance is currently being checked,
- and F0 is its father. */
- struct buffer_head * S0, * F0;
- int lfree, rfree /* free space in L and R */;
-
- S0 = PATH_H_PBUFFER (tb->tb_path, 0);
- F0 = PATH_H_PPARENT (tb->tb_path, 0);
-
- levbytes = tb->insert_size[h];
-
- maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */
-
- if ( ! F0 )
- { /* S[0] is the root now. */
-
- RFALSE( -levbytes >= maxsize - B_FREE_SPACE (S0),
- "vs-8240: attempt to create empty buffer tree");
-
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED;
- }
-
- if ( (n_ret_value = get_parents(tb,h)) != CARRY_ON )
- return n_ret_value;
-
- /* get free space of neighbors */
- rfree = get_rfree (tb, h);
- lfree = get_lfree (tb, h);
-
- create_virtual_node (tb, h);
-
- /* if 3 leaves can be merge to one, set parameters and return */
- if (are_leaves_removable (tb, lfree, rfree))
- return CARRY_ON;
-
- /* determine maximal number of items we can shift to the left/right neighbor
- and the maximal number of bytes that can flow to the left/right neighbor
- from the left/right most liquid item that cannot be shifted from S[0] entirely
- */
- check_left (tb, h, lfree);
- check_right (tb, h, rfree);
-
- /* check whether we can merge S with left neighbor. */
- if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1)
- if (is_left_neighbor_in_cache (tb,h) ||
- ((tb->rnum[0] - ((tb->rbytes == -1) ? 0 : 1)) < vn->vn_nr_item) || /* S can not be merged with R */
- !tb->FR[h]) {
-
- RFALSE( !tb->FL[h], "vs-8245: dc_check_balance_leaf: FL[h] must exist");
-
- /* set parameter to merge S[0] with its left neighbor */
- set_parameters (tb, h, -1, 0, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- /* check whether we can merge S[0] with right neighbor. */
- if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) {
- set_parameters (tb, h, 0, -1, 0, NULL, -1, -1);
- return CARRY_ON;
- }
-
- /* All contents of S[0] can be moved to the neighbors (L[0] & R[0]). Set parameters and return */
- if (is_leaf_removable (tb))
- return CARRY_ON;
-
- /* Balancing is not required. */
- tb->s0num = vn->vn_nr_item;
- set_parameters (tb, h, 0, 0, 1, NULL, -1, -1);
- return NO_BALANCING_NEEDED;
-}
+ struct virtual_node *vn = tb->tb_vn;
+
+ /* Number of bytes that must be deleted from
+ (value is negative if bytes are deleted) buffer which
+ contains node being balanced. The mnemonic is that the
+ attempted change in node space used level is levbytes bytes. */
+ int levbytes;
+ /* the maximal item size */
+ int maxsize, n_ret_value;
+ /* S0 is the node whose balance is currently being checked,
+ and F0 is its father. */
+ struct buffer_head *S0, *F0;
+ int lfree, rfree /* free space in L and R */ ;
+
+ S0 = PATH_H_PBUFFER(tb->tb_path, 0);
+ F0 = PATH_H_PPARENT(tb->tb_path, 0);
+ levbytes = tb->insert_size[h];
+ maxsize = MAX_CHILD_SIZE(S0); /* maximal possible size of an item */
+
+ if (!F0) { /* S[0] is the root now. */
+
+ RFALSE(-levbytes >= maxsize - B_FREE_SPACE(S0),
+ "vs-8240: attempt to create empty buffer tree");
+
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED;
+ }
+
+ if ((n_ret_value = get_parents(tb, h)) != CARRY_ON)
+ return n_ret_value;
+
+ /* get free space of neighbors */
+ rfree = get_rfree(tb, h);
+ lfree = get_lfree(tb, h);
+
+ create_virtual_node(tb, h);
+
+ /* if 3 leaves can be merge to one, set parameters and return */
+ if (are_leaves_removable(tb, lfree, rfree))
+ return CARRY_ON;
+
+ /* determine maximal number of items we can shift to the left/right neighbor
+ and the maximal number of bytes that can flow to the left/right neighbor
+ from the left/right most liquid item that cannot be shifted from S[0] entirely
+ */
+ check_left(tb, h, lfree);
+ check_right(tb, h, rfree);
+
+ /* check whether we can merge S with left neighbor. */
+ if (tb->lnum[0] >= vn->vn_nr_item && tb->lbytes == -1)
+ if (is_left_neighbor_in_cache(tb, h) || ((tb->rnum[0] - ((tb->rbytes == -1) ? 0 : 1)) < vn->vn_nr_item) || /* S can not be merged with R */
+ !tb->FR[h]) {
+
+ RFALSE(!tb->FL[h],
+ "vs-8245: dc_check_balance_leaf: FL[h] must exist");
+
+ /* set parameter to merge S[0] with its left neighbor */
+ set_parameters(tb, h, -1, 0, 0, NULL, -1, -1);
+ return CARRY_ON;
+ }
+
+ /* check whether we can merge S[0] with right neighbor. */
+ if (tb->rnum[0] >= vn->vn_nr_item && tb->rbytes == -1) {
+ set_parameters(tb, h, 0, -1, 0, NULL, -1, -1);
+ return CARRY_ON;
+ }
+
+ /* All contents of S[0] can be moved to the neighbors (L[0] & R[0]). Set parameters and return */
+ if (is_leaf_removable(tb))
+ return CARRY_ON;
+
+ /* Balancing is not required. */
+ tb->s0num = vn->vn_nr_item;
+ set_parameters(tb, h, 0, 0, 1, NULL, -1, -1);
+ return NO_BALANCING_NEEDED;
+}
/* Check whether current node S[h] is balanced when Decreasing its size by
* Deleting or Cutting.
@@ -1775,18 +1827,17 @@ static int dc_check_balance_leaf (struct tree_balance * tb, int h)
* -1 - no balancing for higher levels needed;
* -2 - no disk space.
*/
-static int dc_check_balance (struct tree_balance * tb, int h)
+static int dc_check_balance(struct tree_balance *tb, int h)
{
- RFALSE( ! (PATH_H_PBUFFER (tb->tb_path, h)), "vs-8250: S is not initialized");
+ RFALSE(!(PATH_H_PBUFFER(tb->tb_path, h)),
+ "vs-8250: S is not initialized");
- if ( h )
- return dc_check_balance_internal (tb, h);
- else
- return dc_check_balance_leaf (tb, h);
+ if (h)
+ return dc_check_balance_internal(tb, h);
+ else
+ return dc_check_balance_leaf(tb, h);
}
-
-
/* Check whether current node S[h] is balanced.
* Calculate parameters for balancing for current level h.
* Parameters:
@@ -1805,83 +1856,80 @@ static int dc_check_balance (struct tree_balance * tb, int h)
* -1 - no balancing for higher levels needed;
* -2 - no disk space.
*/
-static int check_balance (int mode,
- struct tree_balance * tb,
- int h,
- int inum,
- int pos_in_item,
- struct item_head * ins_ih,
- const void * data
- )
+static int check_balance(int mode,
+ struct tree_balance *tb,
+ int h,
+ int inum,
+ int pos_in_item,
+ struct item_head *ins_ih, const void *data)
{
- struct virtual_node * vn;
+ struct virtual_node *vn;
- vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf);
- vn->vn_free_ptr = (char *)(tb->tb_vn + 1);
- vn->vn_mode = mode;
- vn->vn_affected_item_num = inum;
- vn->vn_pos_in_item = pos_in_item;
- vn->vn_ins_ih = ins_ih;
- vn->vn_data = data;
+ vn = tb->tb_vn = (struct virtual_node *)(tb->vn_buf);
+ vn->vn_free_ptr = (char *)(tb->tb_vn + 1);
+ vn->vn_mode = mode;
+ vn->vn_affected_item_num = inum;
+ vn->vn_pos_in_item = pos_in_item;
+ vn->vn_ins_ih = ins_ih;
+ vn->vn_data = data;
- RFALSE( mode == M_INSERT && !vn->vn_ins_ih,
- "vs-8255: ins_ih can not be 0 in insert mode");
+ RFALSE(mode == M_INSERT && !vn->vn_ins_ih,
+ "vs-8255: ins_ih can not be 0 in insert mode");
- if ( tb->insert_size[h] > 0 )
- /* Calculate balance parameters when size of node is increasing. */
- return ip_check_balance (tb, h);
+ if (tb->insert_size[h] > 0)
+ /* Calculate balance parameters when size of node is increasing. */
+ return ip_check_balance(tb, h);
- /* Calculate balance parameters when size of node is decreasing. */
- return dc_check_balance (tb, h);
+ /* Calculate balance parameters when size of node is decreasing. */
+ return dc_check_balance(tb, h);
}
+/* Check whether parent at the path is the really parent of the current node.*/
+static int get_direct_parent(struct tree_balance *p_s_tb, int n_h)
+{
+ struct buffer_head *p_s_bh;
+ struct path *p_s_path = p_s_tb->tb_path;
+ int n_position,
+ n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
+
+ /* We are in the root or in the new root. */
+ if (n_path_offset <= FIRST_PATH_ELEMENT_OFFSET) {
+
+ RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1,
+ "PAP-8260: invalid offset in the path");
+
+ if (PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)->
+ b_blocknr == SB_ROOT_BLOCK(p_s_tb->tb_sb)) {
+ /* Root is not changed. */
+ PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL;
+ PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0;
+ return CARRY_ON;
+ }
+ return REPEAT_SEARCH; /* Root is changed and we must recalculate the path. */
+ }
+
+ if (!B_IS_IN_TREE
+ (p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)))
+ return REPEAT_SEARCH; /* Parent in the path is not in the tree. */
+ if ((n_position =
+ PATH_OFFSET_POSITION(p_s_path,
+ n_path_offset - 1)) > B_NR_ITEMS(p_s_bh))
+ return REPEAT_SEARCH;
-/* Check whether parent at the path is the really parent of the current node.*/
-static int get_direct_parent(
- struct tree_balance * p_s_tb,
- int n_h
- ) {
- struct buffer_head * p_s_bh;
- struct path * p_s_path = p_s_tb->tb_path;
- int n_position,
- n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h);
-
- /* We are in the root or in the new root. */
- if ( n_path_offset <= FIRST_PATH_ELEMENT_OFFSET ) {
-
- RFALSE( n_path_offset < FIRST_PATH_ELEMENT_OFFSET - 1,
- "PAP-8260: invalid offset in the path");
-
- if ( PATH_OFFSET_PBUFFER(p_s_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
- SB_ROOT_BLOCK (p_s_tb->tb_sb) ) {
- /* Root is not changed. */
- PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1) = NULL;
- PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1) = 0;
- return CARRY_ON;
+ if (B_N_CHILD_NUM(p_s_bh, n_position) !=
+ PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr)
+ /* Parent in the path is not parent of the current node in the tree. */
+ return REPEAT_SEARCH;
+
+ if (buffer_locked(p_s_bh)) {
+ __wait_on_buffer(p_s_bh);
+ if (FILESYSTEM_CHANGED_TB(p_s_tb))
+ return REPEAT_SEARCH;
}
- return REPEAT_SEARCH; /* Root is changed and we must recalculate the path. */
- }
-
- if ( ! B_IS_IN_TREE(p_s_bh = PATH_OFFSET_PBUFFER(p_s_path, n_path_offset - 1)) )
- return REPEAT_SEARCH; /* Parent in the path is not in the tree. */
-
- if ( (n_position = PATH_OFFSET_POSITION(p_s_path, n_path_offset - 1)) > B_NR_ITEMS(p_s_bh) )
- return REPEAT_SEARCH;
-
- if ( B_N_CHILD_NUM(p_s_bh, n_position) != PATH_OFFSET_PBUFFER(p_s_path, n_path_offset)->b_blocknr )
- /* Parent in the path is not parent of the current node in the tree. */
- return REPEAT_SEARCH;
-
- if ( buffer_locked(p_s_bh) ) {
- __wait_on_buffer(p_s_bh);
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) )
- return REPEAT_SEARCH;
- }
-
- return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node. */
-}
+ return CARRY_ON; /* Parent in the path is unlocked and really parent of the current node. */
+}
/* Using lnum[n_h] and rnum[n_h] we should determine what neighbors
* of S[n_h] we
@@ -1889,356 +1937,401 @@ static int get_direct_parent(
* Returns: SCHEDULE_OCCURRED - schedule occurred while the function worked;
* CARRY_ON - schedule didn't occur while the function worked;
*/
-static int get_neighbors(
- struct tree_balance * p_s_tb,
- int n_h
- ) {
- int n_child_position,
- n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1);
- unsigned long n_son_number;
- struct super_block * p_s_sb = p_s_tb->tb_sb;
- struct buffer_head * p_s_bh;
-
-
- PROC_INFO_INC( p_s_sb, get_neighbors[ n_h ] );
-
- if ( p_s_tb->lnum[n_h] ) {
- /* We need left neighbor to balance S[n_h]. */
- PROC_INFO_INC( p_s_sb, need_l_neighbor[ n_h ] );
- p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
-
- RFALSE( p_s_bh == p_s_tb->FL[n_h] &&
- ! PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset),
- "PAP-8270: invalid position in the parent");
-
- n_child_position = ( p_s_bh == p_s_tb->FL[n_h] ) ? p_s_tb->lkey[n_h] : B_NR_ITEMS (p_s_tb->FL[n_h]);
- n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
- p_s_bh = sb_bread(p_s_sb, n_son_number);
- if (!p_s_bh)
- return IO_ERROR;
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
- decrement_bcount(p_s_bh);
- PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] );
- return REPEAT_SEARCH;
+static int get_neighbors(struct tree_balance *p_s_tb, int n_h)
+{
+ int n_child_position,
+ n_path_offset = PATH_H_PATH_OFFSET(p_s_tb->tb_path, n_h + 1);
+ unsigned long n_son_number;
+ struct super_block *p_s_sb = p_s_tb->tb_sb;
+ struct buffer_head *p_s_bh;
+
+ PROC_INFO_INC(p_s_sb, get_neighbors[n_h]);
+
+ if (p_s_tb->lnum[n_h]) {
+ /* We need left neighbor to balance S[n_h]. */
+ PROC_INFO_INC(p_s_sb, need_l_neighbor[n_h]);
+ p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+
+ RFALSE(p_s_bh == p_s_tb->FL[n_h] &&
+ !PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset),
+ "PAP-8270: invalid position in the parent");
+
+ n_child_position =
+ (p_s_bh ==
+ p_s_tb->FL[n_h]) ? p_s_tb->lkey[n_h] : B_NR_ITEMS(p_s_tb->
+ FL[n_h]);
+ n_son_number = B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position);
+ p_s_bh = sb_bread(p_s_sb, n_son_number);
+ if (!p_s_bh)
+ return IO_ERROR;
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ decrement_bcount(p_s_bh);
+ PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]);
+ return REPEAT_SEARCH;
+ }
+
+ RFALSE(!B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
+ n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
+ B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) !=
+ p_s_bh->b_blocknr, "PAP-8275: invalid parent");
+ RFALSE(!B_IS_IN_TREE(p_s_bh), "PAP-8280: invalid child");
+ RFALSE(!n_h &&
+ B_FREE_SPACE(p_s_bh) !=
+ MAX_CHILD_SIZE(p_s_bh) -
+ dc_size(B_N_CHILD(p_s_tb->FL[0], n_child_position)),
+ "PAP-8290: invalid child size of left neighbor");
+
+ decrement_bcount(p_s_tb->L[n_h]);
+ p_s_tb->L[n_h] = p_s_bh;
}
-
- RFALSE( ! B_IS_IN_TREE(p_s_tb->FL[n_h]) ||
- n_child_position > B_NR_ITEMS(p_s_tb->FL[n_h]) ||
- B_N_CHILD_NUM(p_s_tb->FL[n_h], n_child_position) !=
- p_s_bh->b_blocknr, "PAP-8275: invalid parent");
- RFALSE( ! B_IS_IN_TREE(p_s_bh), "PAP-8280: invalid child");
- RFALSE( ! n_h &&
- B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - dc_size(B_N_CHILD (p_s_tb->FL[0],n_child_position)),
- "PAP-8290: invalid child size of left neighbor");
-
- decrement_bcount(p_s_tb->L[n_h]);
- p_s_tb->L[n_h] = p_s_bh;
- }
-
-
- if ( p_s_tb->rnum[n_h] ) { /* We need right neighbor to balance S[n_path_offset]. */
- PROC_INFO_INC( p_s_sb, need_r_neighbor[ n_h ] );
- p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
-
- RFALSE( p_s_bh == p_s_tb->FR[n_h] &&
- PATH_OFFSET_POSITION(p_s_tb->tb_path, n_path_offset) >= B_NR_ITEMS(p_s_bh),
- "PAP-8295: invalid position in the parent");
-
- n_child_position = ( p_s_bh == p_s_tb->FR[n_h] ) ? p_s_tb->rkey[n_h] + 1 : 0;
- n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
- p_s_bh = sb_bread(p_s_sb, n_son_number);
- if (!p_s_bh)
- return IO_ERROR;
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
- decrement_bcount(p_s_bh);
- PROC_INFO_INC( p_s_sb, get_neighbors_restart[ n_h ] );
- return REPEAT_SEARCH;
+
+ if (p_s_tb->rnum[n_h]) { /* We need right neighbor to balance S[n_path_offset]. */
+ PROC_INFO_INC(p_s_sb, need_r_neighbor[n_h]);
+ p_s_bh = PATH_OFFSET_PBUFFER(p_s_tb->tb_path, n_path_offset);
+
+ RFALSE(p_s_bh == p_s_tb->FR[n_h] &&
+ PATH_OFFSET_POSITION(p_s_tb->tb_path,
+ n_path_offset) >=
+ B_NR_ITEMS(p_s_bh),
+ "PAP-8295: invalid position in the parent");
+
+ n_child_position =
+ (p_s_bh == p_s_tb->FR[n_h]) ? p_s_tb->rkey[n_h] + 1 : 0;
+ n_son_number = B_N_CHILD_NUM(p_s_tb->FR[n_h], n_child_position);
+ p_s_bh = sb_bread(p_s_sb, n_son_number);
+ if (!p_s_bh)
+ return IO_ERROR;
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ decrement_bcount(p_s_bh);
+ PROC_INFO_INC(p_s_sb, get_neighbors_restart[n_h]);
+ return REPEAT_SEARCH;
+ }
+ decrement_bcount(p_s_tb->R[n_h]);
+ p_s_tb->R[n_h] = p_s_bh;
+
+ RFALSE(!n_h
+ && B_FREE_SPACE(p_s_bh) !=
+ MAX_CHILD_SIZE(p_s_bh) -
+ dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position)),
+ "PAP-8300: invalid child size of right neighbor (%d != %d - %d)",
+ B_FREE_SPACE(p_s_bh), MAX_CHILD_SIZE(p_s_bh),
+ dc_size(B_N_CHILD(p_s_tb->FR[0], n_child_position)));
+
}
- decrement_bcount(p_s_tb->R[n_h]);
- p_s_tb->R[n_h] = p_s_bh;
-
- RFALSE( ! n_h && B_FREE_SPACE (p_s_bh) != MAX_CHILD_SIZE (p_s_bh) - dc_size(B_N_CHILD (p_s_tb->FR[0],n_child_position)),
- "PAP-8300: invalid child size of right neighbor (%d != %d - %d)",
- B_FREE_SPACE (p_s_bh), MAX_CHILD_SIZE (p_s_bh),
- dc_size(B_N_CHILD (p_s_tb->FR[0],n_child_position)));
-
- }
- return CARRY_ON;
+ return CARRY_ON;
}
#ifdef CONFIG_REISERFS_CHECK
-void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s)
+void *reiserfs_kmalloc(size_t size, int flags, struct super_block *s)
{
- void * vp;
- static size_t malloced;
-
-
- vp = kmalloc (size, flags);
- if (vp) {
- REISERFS_SB(s)->s_kmallocs += size;
- if (REISERFS_SB(s)->s_kmallocs > malloced + 200000) {
- reiserfs_warning (s,
- "vs-8301: reiserfs_kmalloc: allocated memory %d",
- REISERFS_SB(s)->s_kmallocs);
- malloced = REISERFS_SB(s)->s_kmallocs;
+ void *vp;
+ static size_t malloced;
+
+ vp = kmalloc(size, flags);
+ if (vp) {
+ REISERFS_SB(s)->s_kmallocs += size;
+ if (REISERFS_SB(s)->s_kmallocs > malloced + 200000) {
+ reiserfs_warning(s,
+ "vs-8301: reiserfs_kmalloc: allocated memory %d",
+ REISERFS_SB(s)->s_kmallocs);
+ malloced = REISERFS_SB(s)->s_kmallocs;
+ }
}
- }
- return vp;
+ return vp;
}
-void reiserfs_kfree (const void * vp, size_t size, struct super_block * s)
+void reiserfs_kfree(const void *vp, size_t size, struct super_block *s)
{
- kfree (vp);
-
- REISERFS_SB(s)->s_kmallocs -= size;
- if (REISERFS_SB(s)->s_kmallocs < 0)
- reiserfs_warning (s, "vs-8302: reiserfs_kfree: allocated memory %d",
- REISERFS_SB(s)->s_kmallocs);
+ kfree(vp);
+
+ REISERFS_SB(s)->s_kmallocs -= size;
+ if (REISERFS_SB(s)->s_kmallocs < 0)
+ reiserfs_warning(s,
+ "vs-8302: reiserfs_kfree: allocated memory %d",
+ REISERFS_SB(s)->s_kmallocs);
}
#endif
-
-static int get_virtual_node_size (struct super_block * sb, struct buffer_head * bh)
+static int get_virtual_node_size(struct super_block *sb, struct buffer_head *bh)
{
- int max_num_of_items;
- int max_num_of_entries;
- unsigned long blocksize = sb->s_blocksize;
+ int max_num_of_items;
+ int max_num_of_entries;
+ unsigned long blocksize = sb->s_blocksize;
#define MIN_NAME_LEN 1
- max_num_of_items = (blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN);
- max_num_of_entries = (blocksize - BLKH_SIZE - IH_SIZE) /
- (DEH_SIZE + MIN_NAME_LEN);
+ max_num_of_items = (blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN);
+ max_num_of_entries = (blocksize - BLKH_SIZE - IH_SIZE) /
+ (DEH_SIZE + MIN_NAME_LEN);
- return sizeof(struct virtual_node) +
- max(max_num_of_items * sizeof (struct virtual_item),
- sizeof (struct virtual_item) + sizeof(struct direntry_uarea) +
- (max_num_of_entries - 1) * sizeof (__u16));
+ return sizeof(struct virtual_node) +
+ max(max_num_of_items * sizeof(struct virtual_item),
+ sizeof(struct virtual_item) + sizeof(struct direntry_uarea) +
+ (max_num_of_entries - 1) * sizeof(__u16));
}
-
-
/* maybe we should fail balancing we are going to perform when kmalloc
fails several times. But now it will loop until kmalloc gets
required memory */
-static int get_mem_for_virtual_node (struct tree_balance * tb)
+static int get_mem_for_virtual_node(struct tree_balance *tb)
{
- int check_fs = 0;
- int size;
- char * buf;
-
- size = get_virtual_node_size (tb->tb_sb, PATH_PLAST_BUFFER (tb->tb_path));
-
- if (size > tb->vn_buf_size) {
- /* we have to allocate more memory for virtual node */
- if (tb->vn_buf) {
- /* free memory allocated before */
- reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
- /* this is not needed if kfree is atomic */
- check_fs = 1;
- }
+ int check_fs = 0;
+ int size;
+ char *buf;
+
+ size = get_virtual_node_size(tb->tb_sb, PATH_PLAST_BUFFER(tb->tb_path));
+
+ if (size > tb->vn_buf_size) {
+ /* we have to allocate more memory for virtual node */
+ if (tb->vn_buf) {
+ /* free memory allocated before */
+ reiserfs_kfree(tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
+ /* this is not needed if kfree is atomic */
+ check_fs = 1;
+ }
- /* virtual node requires now more memory */
- tb->vn_buf_size = size;
-
- /* get memory for virtual item */
- buf = reiserfs_kmalloc(size, GFP_ATOMIC | __GFP_NOWARN, tb->tb_sb);
- if ( ! buf ) {
- /* getting memory with GFP_KERNEL priority may involve
- balancing now (due to indirect_to_direct conversion on
- dcache shrinking). So, release path and collected
- resources here */
- free_buffers_in_tb (tb);
- buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb);
- if ( !buf ) {
+ /* virtual node requires now more memory */
+ tb->vn_buf_size = size;
+
+ /* get memory for virtual item */
+ buf =
+ reiserfs_kmalloc(size, GFP_ATOMIC | __GFP_NOWARN,
+ tb->tb_sb);
+ if (!buf) {
+ /* getting memory with GFP_KERNEL priority may involve
+ balancing now (due to indirect_to_direct conversion on
+ dcache shrinking). So, release path and collected
+ resources here */
+ free_buffers_in_tb(tb);
+ buf = reiserfs_kmalloc(size, GFP_NOFS, tb->tb_sb);
+ if (!buf) {
#ifdef CONFIG_REISERFS_CHECK
- reiserfs_warning (tb->tb_sb,
- "vs-8345: get_mem_for_virtual_node: "
- "kmalloc failed. reiserfs kmalloced %d bytes",
- REISERFS_SB(tb->tb_sb)->s_kmallocs);
+ reiserfs_warning(tb->tb_sb,
+ "vs-8345: get_mem_for_virtual_node: "
+ "kmalloc failed. reiserfs kmalloced %d bytes",
+ REISERFS_SB(tb->tb_sb)->
+ s_kmallocs);
#endif
- tb->vn_buf_size = 0;
- }
- tb->vn_buf = buf;
- schedule() ;
- return REPEAT_SEARCH;
- }
+ tb->vn_buf_size = 0;
+ }
+ tb->vn_buf = buf;
+ schedule();
+ return REPEAT_SEARCH;
+ }
- tb->vn_buf = buf;
- }
+ tb->vn_buf = buf;
+ }
- if ( check_fs && FILESYSTEM_CHANGED_TB (tb) )
- return REPEAT_SEARCH;
+ if (check_fs && FILESYSTEM_CHANGED_TB(tb))
+ return REPEAT_SEARCH;
- return CARRY_ON;
+ return CARRY_ON;
}
-
#ifdef CONFIG_REISERFS_CHECK
-static void tb_buffer_sanity_check (struct super_block * p_s_sb,
- struct buffer_head * p_s_bh,
- const char *descr, int level) {
- if (p_s_bh) {
- if (atomic_read (&(p_s_bh->b_count)) <= 0) {
-
- reiserfs_panic (p_s_sb, "jmacd-1: tb_buffer_sanity_check(): negative or zero reference counter for buffer %s[%d] (%b)\n", descr, level, p_s_bh);
- }
-
- if ( ! buffer_uptodate (p_s_bh) ) {
- reiserfs_panic (p_s_sb, "jmacd-2: tb_buffer_sanity_check(): buffer is not up to date %s[%d] (%b)\n", descr, level, p_s_bh);
- }
-
- if ( ! B_IS_IN_TREE (p_s_bh) ) {
- reiserfs_panic (p_s_sb, "jmacd-3: tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n", descr, level, p_s_bh);
- }
-
- if (p_s_bh->b_bdev != p_s_sb->s_bdev) {
- reiserfs_panic (p_s_sb, "jmacd-4: tb_buffer_sanity_check(): buffer has wrong device %s[%d] (%b)\n", descr, level, p_s_bh);
- }
-
- if (p_s_bh->b_size != p_s_sb->s_blocksize) {
- reiserfs_panic (p_s_sb, "jmacd-5: tb_buffer_sanity_check(): buffer has wrong blocksize %s[%d] (%b)\n", descr, level, p_s_bh);
- }
-
- if (p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
- reiserfs_panic (p_s_sb, "jmacd-6: tb_buffer_sanity_check(): buffer block number too high %s[%d] (%b)\n", descr, level, p_s_bh);
- }
- }
-}
-#else
-static void tb_buffer_sanity_check (struct super_block * p_s_sb,
- struct buffer_head * p_s_bh,
- const char *descr, int level)
-{;}
-#endif
-
-static int clear_all_dirty_bits(struct super_block *s,
- struct buffer_head *bh) {
- return reiserfs_prepare_for_journal(s, bh, 0) ;
-}
-
-static int wait_tb_buffers_until_unlocked (struct tree_balance * p_s_tb)
+static void tb_buffer_sanity_check(struct super_block *p_s_sb,
+ struct buffer_head *p_s_bh,
+ const char *descr, int level)
{
- struct buffer_head * locked;
-#ifdef CONFIG_REISERFS_CHECK
- int repeat_counter = 0;
-#endif
- int i;
+ if (p_s_bh) {
+ if (atomic_read(&(p_s_bh->b_count)) <= 0) {
- do {
-
- locked = NULL;
-
- for ( i = p_s_tb->tb_path->path_length; !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i-- ) {
- if ( PATH_OFFSET_PBUFFER (p_s_tb->tb_path, i) ) {
- /* if I understand correctly, we can only be sure the last buffer
- ** in the path is in the tree --clm
- */
-#ifdef CONFIG_REISERFS_CHECK
- if (PATH_PLAST_BUFFER(p_s_tb->tb_path) ==
- PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) {
- tb_buffer_sanity_check (p_s_tb->tb_sb,
- PATH_OFFSET_PBUFFER (p_s_tb->tb_path, i),
- "S",
- p_s_tb->tb_path->path_length - i);
+ reiserfs_panic(p_s_sb,
+ "jmacd-1: tb_buffer_sanity_check(): negative or zero reference counter for buffer %s[%d] (%b)\n",
+ descr, level, p_s_bh);
}
-#endif
- if (!clear_all_dirty_bits(p_s_tb->tb_sb,
- PATH_OFFSET_PBUFFER (p_s_tb->tb_path, i)))
- {
- locked = PATH_OFFSET_PBUFFER (p_s_tb->tb_path, i);
- }
- }
- }
- for ( i = 0; !locked && i < MAX_HEIGHT && p_s_tb->insert_size[i]; i++ ) {
+ if (!buffer_uptodate(p_s_bh)) {
+ reiserfs_panic(p_s_sb,
+ "jmacd-2: tb_buffer_sanity_check(): buffer is not up to date %s[%d] (%b)\n",
+ descr, level, p_s_bh);
+ }
- if (p_s_tb->lnum[i] ) {
+ if (!B_IS_IN_TREE(p_s_bh)) {
+ reiserfs_panic(p_s_sb,
+ "jmacd-3: tb_buffer_sanity_check(): buffer is not in tree %s[%d] (%b)\n",
+ descr, level, p_s_bh);
+ }
- if ( p_s_tb->L[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->L[i], "L", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->L[i]))
- locked = p_s_tb->L[i];
+ if (p_s_bh->b_bdev != p_s_sb->s_bdev) {
+ reiserfs_panic(p_s_sb,
+ "jmacd-4: tb_buffer_sanity_check(): buffer has wrong device %s[%d] (%b)\n",
+ descr, level, p_s_bh);
}
- if ( !locked && p_s_tb->FL[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->FL[i], "FL", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->FL[i]))
- locked = p_s_tb->FL[i];
+ if (p_s_bh->b_size != p_s_sb->s_blocksize) {
+ reiserfs_panic(p_s_sb,
+ "jmacd-5: tb_buffer_sanity_check(): buffer has wrong blocksize %s[%d] (%b)\n",
+ descr, level, p_s_bh);
}
- if ( !locked && p_s_tb->CFL[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->CFL[i], "CFL", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->CFL[i]))
- locked = p_s_tb->CFL[i];
+ if (p_s_bh->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
+ reiserfs_panic(p_s_sb,
+ "jmacd-6: tb_buffer_sanity_check(): buffer block number too high %s[%d] (%b)\n",
+ descr, level, p_s_bh);
}
+ }
+}
+#else
+static void tb_buffer_sanity_check(struct super_block *p_s_sb,
+ struct buffer_head *p_s_bh,
+ const char *descr, int level)
+{;
+}
+#endif
- }
+static int clear_all_dirty_bits(struct super_block *s, struct buffer_head *bh)
+{
+ return reiserfs_prepare_for_journal(s, bh, 0);
+}
- if ( !locked && (p_s_tb->rnum[i]) ) {
+static int wait_tb_buffers_until_unlocked(struct tree_balance *p_s_tb)
+{
+ struct buffer_head *locked;
+#ifdef CONFIG_REISERFS_CHECK
+ int repeat_counter = 0;
+#endif
+ int i;
- if ( p_s_tb->R[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->R[i], "R", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->R[i]))
- locked = p_s_tb->R[i];
- }
+ do {
-
- if ( !locked && p_s_tb->FR[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->FR[i], "FR", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->FR[i]))
- locked = p_s_tb->FR[i];
+ locked = NULL;
+
+ for (i = p_s_tb->tb_path->path_length;
+ !locked && i > ILLEGAL_PATH_ELEMENT_OFFSET; i--) {
+ if (PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) {
+ /* if I understand correctly, we can only be sure the last buffer
+ ** in the path is in the tree --clm
+ */
+#ifdef CONFIG_REISERFS_CHECK
+ if (PATH_PLAST_BUFFER(p_s_tb->tb_path) ==
+ PATH_OFFSET_PBUFFER(p_s_tb->tb_path, i)) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ PATH_OFFSET_PBUFFER
+ (p_s_tb->tb_path,
+ i), "S",
+ p_s_tb->tb_path->
+ path_length - i);
+ }
+#endif
+ if (!clear_all_dirty_bits(p_s_tb->tb_sb,
+ PATH_OFFSET_PBUFFER
+ (p_s_tb->tb_path,
+ i))) {
+ locked =
+ PATH_OFFSET_PBUFFER(p_s_tb->tb_path,
+ i);
+ }
+ }
}
- if ( !locked && p_s_tb->CFR[i] ) {
- tb_buffer_sanity_check (p_s_tb->tb_sb, p_s_tb->CFR[i], "CFR", i);
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->CFR[i]))
- locked = p_s_tb->CFR[i];
+ for (i = 0; !locked && i < MAX_HEIGHT && p_s_tb->insert_size[i];
+ i++) {
+
+ if (p_s_tb->lnum[i]) {
+
+ if (p_s_tb->L[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->L[i],
+ "L", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->L[i]))
+ locked = p_s_tb->L[i];
+ }
+
+ if (!locked && p_s_tb->FL[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->FL[i],
+ "FL", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->FL[i]))
+ locked = p_s_tb->FL[i];
+ }
+
+ if (!locked && p_s_tb->CFL[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->CFL[i],
+ "CFL", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->CFL[i]))
+ locked = p_s_tb->CFL[i];
+ }
+
+ }
+
+ if (!locked && (p_s_tb->rnum[i])) {
+
+ if (p_s_tb->R[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->R[i],
+ "R", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->R[i]))
+ locked = p_s_tb->R[i];
+ }
+
+ if (!locked && p_s_tb->FR[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->FR[i],
+ "FR", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->FR[i]))
+ locked = p_s_tb->FR[i];
+ }
+
+ if (!locked && p_s_tb->CFR[i]) {
+ tb_buffer_sanity_check(p_s_tb->tb_sb,
+ p_s_tb->CFR[i],
+ "CFR", i);
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->CFR[i]))
+ locked = p_s_tb->CFR[i];
+ }
+ }
+ }
+ /* as far as I can tell, this is not required. The FEB list seems
+ ** to be full of newly allocated nodes, which will never be locked,
+ ** dirty, or anything else.
+ ** To be safe, I'm putting in the checks and waits in. For the moment,
+ ** they are needed to keep the code in journal.c from complaining
+ ** about the buffer. That code is inside CONFIG_REISERFS_CHECK as well.
+ ** --clm
+ */
+ for (i = 0; !locked && i < MAX_FEB_SIZE; i++) {
+ if (p_s_tb->FEB[i]) {
+ if (!clear_all_dirty_bits
+ (p_s_tb->tb_sb, p_s_tb->FEB[i]))
+ locked = p_s_tb->FEB[i];
+ }
}
- }
- }
- /* as far as I can tell, this is not required. The FEB list seems
- ** to be full of newly allocated nodes, which will never be locked,
- ** dirty, or anything else.
- ** To be safe, I'm putting in the checks and waits in. For the moment,
- ** they are needed to keep the code in journal.c from complaining
- ** about the buffer. That code is inside CONFIG_REISERFS_CHECK as well.
- ** --clm
- */
- for ( i = 0; !locked && i < MAX_FEB_SIZE; i++ ) {
- if ( p_s_tb->FEB[i] ) {
- if (!clear_all_dirty_bits(p_s_tb->tb_sb, p_s_tb->FEB[i]))
- locked = p_s_tb->FEB[i] ;
- }
- }
- if (locked) {
+ if (locked) {
#ifdef CONFIG_REISERFS_CHECK
- repeat_counter++;
- if ( (repeat_counter % 10000) == 0) {
- reiserfs_warning (p_s_tb->tb_sb,
- "wait_tb_buffers_until_released(): too many "
- "iterations waiting for buffer to unlock "
- "(%b)", locked);
-
- /* Don't loop forever. Try to recover from possible error. */
-
- return ( FILESYSTEM_CHANGED_TB (p_s_tb) ) ? REPEAT_SEARCH : CARRY_ON;
- }
+ repeat_counter++;
+ if ((repeat_counter % 10000) == 0) {
+ reiserfs_warning(p_s_tb->tb_sb,
+ "wait_tb_buffers_until_released(): too many "
+ "iterations waiting for buffer to unlock "
+ "(%b)", locked);
+
+ /* Don't loop forever. Try to recover from possible error. */
+
+ return (FILESYSTEM_CHANGED_TB(p_s_tb)) ?
+ REPEAT_SEARCH : CARRY_ON;
+ }
#endif
- __wait_on_buffer (locked);
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) ) {
- return REPEAT_SEARCH;
- }
- }
+ __wait_on_buffer(locked);
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ return REPEAT_SEARCH;
+ }
+ }
- } while (locked);
+ } while (locked);
- return CARRY_ON;
+ return CARRY_ON;
}
-
/* Prepare for balancing, that is
* get all necessary parents, and neighbors;
* analyze what and where should be moved;
@@ -2267,252 +2360,266 @@ static int wait_tb_buffers_until_unlocked (struct tree_balance * p_s_tb)
* -1 - if no_disk_space
*/
+int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb, struct item_head *p_s_ins_ih, // item head of item being inserted
+ const void *data // inserted item or data to be pasted
+ )
+{
+ int n_ret_value, n_h, n_item_num = PATH_LAST_POSITION(p_s_tb->tb_path);
+ int n_pos_in_item;
-int fix_nodes (int n_op_mode,
- struct tree_balance * p_s_tb,
- struct item_head * p_s_ins_ih, // item head of item being inserted
- const void * data // inserted item or data to be pasted
- ) {
- int n_ret_value,
- n_h,
- n_item_num = PATH_LAST_POSITION(p_s_tb->tb_path);
- int n_pos_in_item;
-
- /* we set wait_tb_buffers_run when we have to restore any dirty bits cleared
- ** during wait_tb_buffers_run
- */
- int wait_tb_buffers_run = 0 ;
- struct buffer_head * p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path);
-
- ++ REISERFS_SB(p_s_tb -> tb_sb) -> s_fix_nodes;
-
- n_pos_in_item = p_s_tb->tb_path->pos_in_item;
-
-
- p_s_tb->fs_gen = get_generation (p_s_tb->tb_sb);
-
- /* we prepare and log the super here so it will already be in the
- ** transaction when do_balance needs to change it.
- ** This way do_balance won't have to schedule when trying to prepare
- ** the super for logging
- */
- reiserfs_prepare_for_journal(p_s_tb->tb_sb,
- SB_BUFFER_WITH_SB(p_s_tb->tb_sb), 1) ;
- journal_mark_dirty(p_s_tb->transaction_handle, p_s_tb->tb_sb,
- SB_BUFFER_WITH_SB(p_s_tb->tb_sb)) ;
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) )
- return REPEAT_SEARCH;
-
- /* if it possible in indirect_to_direct conversion */
- if (buffer_locked (p_s_tbS0)) {
- __wait_on_buffer (p_s_tbS0);
- if ( FILESYSTEM_CHANGED_TB (p_s_tb) )
- return REPEAT_SEARCH;
- }
+ /* we set wait_tb_buffers_run when we have to restore any dirty bits cleared
+ ** during wait_tb_buffers_run
+ */
+ int wait_tb_buffers_run = 0;
+ struct buffer_head *p_s_tbS0 = PATH_PLAST_BUFFER(p_s_tb->tb_path);
-#ifdef CONFIG_REISERFS_CHECK
- if ( cur_tb ) {
- print_cur_tb ("fix_nodes");
- reiserfs_panic(p_s_tb->tb_sb,"PAP-8305: fix_nodes: there is pending do_balance");
- }
-
- if (!buffer_uptodate (p_s_tbS0) || !B_IS_IN_TREE (p_s_tbS0)) {
- reiserfs_panic (p_s_tb->tb_sb, "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate "
- "at the beginning of fix_nodes or not in tree (mode %c)", p_s_tbS0, p_s_tbS0, n_op_mode);
- }
-
- /* Check parameters. */
- switch (n_op_mode) {
- case M_INSERT:
- if ( n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0) )
- reiserfs_panic(p_s_tb->tb_sb,"PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert",
- n_item_num, B_NR_ITEMS(p_s_tbS0));
- break;
- case M_PASTE:
- case M_DELETE:
- case M_CUT:
- if ( n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0) ) {
- print_block (p_s_tbS0, 0, -1, -1);
- reiserfs_panic(p_s_tb->tb_sb,"PAP-8335: fix_nodes: Incorrect item number(%d); mode = %c insert_size = %d\n", n_item_num, n_op_mode, p_s_tb->insert_size[0]);
- }
- break;
- default:
- reiserfs_panic(p_s_tb->tb_sb,"PAP-8340: fix_nodes: Incorrect mode of operation");
- }
-#endif
+ ++REISERFS_SB(p_s_tb->tb_sb)->s_fix_nodes;
+
+ n_pos_in_item = p_s_tb->tb_path->pos_in_item;
+
+ p_s_tb->fs_gen = get_generation(p_s_tb->tb_sb);
- if (get_mem_for_virtual_node (p_s_tb) == REPEAT_SEARCH)
- // FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat
- return REPEAT_SEARCH;
+ /* we prepare and log the super here so it will already be in the
+ ** transaction when do_balance needs to change it.
+ ** This way do_balance won't have to schedule when trying to prepare
+ ** the super for logging
+ */
+ reiserfs_prepare_for_journal(p_s_tb->tb_sb,
+ SB_BUFFER_WITH_SB(p_s_tb->tb_sb), 1);
+ journal_mark_dirty(p_s_tb->transaction_handle, p_s_tb->tb_sb,
+ SB_BUFFER_WITH_SB(p_s_tb->tb_sb));
+ if (FILESYSTEM_CHANGED_TB(p_s_tb))
+ return REPEAT_SEARCH;
+ /* if it possible in indirect_to_direct conversion */
+ if (buffer_locked(p_s_tbS0)) {
+ __wait_on_buffer(p_s_tbS0);
+ if (FILESYSTEM_CHANGED_TB(p_s_tb))
+ return REPEAT_SEARCH;
+ }
+#ifdef CONFIG_REISERFS_CHECK
+ if (cur_tb) {
+ print_cur_tb("fix_nodes");
+ reiserfs_panic(p_s_tb->tb_sb,
+ "PAP-8305: fix_nodes: there is pending do_balance");
+ }
- /* Starting from the leaf level; for all levels n_h of the tree. */
- for ( n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++ ) {
- if ( (n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON ) {
- goto repeat;
+ if (!buffer_uptodate(p_s_tbS0) || !B_IS_IN_TREE(p_s_tbS0)) {
+ reiserfs_panic(p_s_tb->tb_sb,
+ "PAP-8320: fix_nodes: S[0] (%b %z) is not uptodate "
+ "at the beginning of fix_nodes or not in tree (mode %c)",
+ p_s_tbS0, p_s_tbS0, n_op_mode);
}
- if ( (n_ret_value = check_balance (n_op_mode, p_s_tb, n_h, n_item_num,
- n_pos_in_item, p_s_ins_ih, data)) != CARRY_ON ) {
- if ( n_ret_value == NO_BALANCING_NEEDED ) {
- /* No balancing for higher levels needed. */
- if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
- goto repeat;
+ /* Check parameters. */
+ switch (n_op_mode) {
+ case M_INSERT:
+ if (n_item_num <= 0 || n_item_num > B_NR_ITEMS(p_s_tbS0))
+ reiserfs_panic(p_s_tb->tb_sb,
+ "PAP-8330: fix_nodes: Incorrect item number %d (in S0 - %d) in case of insert",
+ n_item_num, B_NR_ITEMS(p_s_tbS0));
+ break;
+ case M_PASTE:
+ case M_DELETE:
+ case M_CUT:
+ if (n_item_num < 0 || n_item_num >= B_NR_ITEMS(p_s_tbS0)) {
+ print_block(p_s_tbS0, 0, -1, -1);
+ reiserfs_panic(p_s_tb->tb_sb,
+ "PAP-8335: fix_nodes: Incorrect item number(%d); mode = %c insert_size = %d\n",
+ n_item_num, n_op_mode,
+ p_s_tb->insert_size[0]);
}
- if ( n_h != MAX_HEIGHT - 1 )
- p_s_tb->insert_size[n_h + 1] = 0;
- /* ok, analysis and resource gathering are complete */
break;
- }
- goto repeat;
+ default:
+ reiserfs_panic(p_s_tb->tb_sb,
+ "PAP-8340: fix_nodes: Incorrect mode of operation");
}
+#endif
- if ( (n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON ) {
- goto repeat;
- }
+ if (get_mem_for_virtual_node(p_s_tb) == REPEAT_SEARCH)
+ // FIXME: maybe -ENOMEM when tb->vn_buf == 0? Now just repeat
+ return REPEAT_SEARCH;
- if ( (n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON ) {
- goto repeat; /* No disk space, or schedule occurred and
- analysis may be invalid and needs to be redone. */
- }
-
- if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h) ) {
- /* We have a positive insert size but no nodes exist on this
- level, this means that we are creating a new root. */
+ /* Starting from the leaf level; for all levels n_h of the tree. */
+ for (n_h = 0; n_h < MAX_HEIGHT && p_s_tb->insert_size[n_h]; n_h++) {
+ if ((n_ret_value = get_direct_parent(p_s_tb, n_h)) != CARRY_ON) {
+ goto repeat;
+ }
- RFALSE( p_s_tb->blknum[n_h] != 1,
- "PAP-8350: creating new empty root");
+ if ((n_ret_value =
+ check_balance(n_op_mode, p_s_tb, n_h, n_item_num,
+ n_pos_in_item, p_s_ins_ih,
+ data)) != CARRY_ON) {
+ if (n_ret_value == NO_BALANCING_NEEDED) {
+ /* No balancing for higher levels needed. */
+ if ((n_ret_value =
+ get_neighbors(p_s_tb, n_h)) != CARRY_ON) {
+ goto repeat;
+ }
+ if (n_h != MAX_HEIGHT - 1)
+ p_s_tb->insert_size[n_h + 1] = 0;
+ /* ok, analysis and resource gathering are complete */
+ break;
+ }
+ goto repeat;
+ }
- if ( n_h < MAX_HEIGHT - 1 )
- p_s_tb->insert_size[n_h + 1] = 0;
- }
- else
- if ( ! PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1) ) {
- if ( p_s_tb->blknum[n_h] > 1 ) {
- /* The tree needs to be grown, so this node S[n_h]
- which is the root node is split into two nodes,
- and a new node (S[n_h+1]) will be created to
- become the root node. */
-
- RFALSE( n_h == MAX_HEIGHT - 1,
- "PAP-8355: attempt to create too high of a tree");
-
- p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) + DC_SIZE;
+ if ((n_ret_value = get_neighbors(p_s_tb, n_h)) != CARRY_ON) {
+ goto repeat;
}
- else
- if ( n_h < MAX_HEIGHT - 1 )
- p_s_tb->insert_size[n_h + 1] = 0;
- }
- else
- p_s_tb->insert_size[n_h + 1] = (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1);
- }
-
- if ((n_ret_value = wait_tb_buffers_until_unlocked (p_s_tb)) == CARRY_ON) {
- if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
- wait_tb_buffers_run = 1 ;
- n_ret_value = REPEAT_SEARCH ;
- goto repeat;
- } else {
- return CARRY_ON;
+
+ if ((n_ret_value = get_empty_nodes(p_s_tb, n_h)) != CARRY_ON) {
+ goto repeat; /* No disk space, or schedule occurred and
+ analysis may be invalid and needs to be redone. */
+ }
+
+ if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h)) {
+ /* We have a positive insert size but no nodes exist on this
+ level, this means that we are creating a new root. */
+
+ RFALSE(p_s_tb->blknum[n_h] != 1,
+ "PAP-8350: creating new empty root");
+
+ if (n_h < MAX_HEIGHT - 1)
+ p_s_tb->insert_size[n_h + 1] = 0;
+ } else if (!PATH_H_PBUFFER(p_s_tb->tb_path, n_h + 1)) {
+ if (p_s_tb->blknum[n_h] > 1) {
+ /* The tree needs to be grown, so this node S[n_h]
+ which is the root node is split into two nodes,
+ and a new node (S[n_h+1]) will be created to
+ become the root node. */
+
+ RFALSE(n_h == MAX_HEIGHT - 1,
+ "PAP-8355: attempt to create too high of a tree");
+
+ p_s_tb->insert_size[n_h + 1] =
+ (DC_SIZE +
+ KEY_SIZE) * (p_s_tb->blknum[n_h] - 1) +
+ DC_SIZE;
+ } else if (n_h < MAX_HEIGHT - 1)
+ p_s_tb->insert_size[n_h + 1] = 0;
+ } else
+ p_s_tb->insert_size[n_h + 1] =
+ (DC_SIZE + KEY_SIZE) * (p_s_tb->blknum[n_h] - 1);
}
- } else {
- wait_tb_buffers_run = 1 ;
- goto repeat;
- }
-
- repeat:
- // fix_nodes was unable to perform its calculation due to
- // filesystem got changed under us, lack of free disk space or i/o
- // failure. If the first is the case - the search will be
- // repeated. For now - free all resources acquired so far except
- // for the new allocated nodes
- {
- int i;
- /* Release path buffers. */
- if (wait_tb_buffers_run) {
- pathrelse_and_restore(p_s_tb->tb_sb, p_s_tb->tb_path) ;
+ if ((n_ret_value = wait_tb_buffers_until_unlocked(p_s_tb)) == CARRY_ON) {
+ if (FILESYSTEM_CHANGED_TB(p_s_tb)) {
+ wait_tb_buffers_run = 1;
+ n_ret_value = REPEAT_SEARCH;
+ goto repeat;
+ } else {
+ return CARRY_ON;
+ }
} else {
- pathrelse (p_s_tb->tb_path);
- }
- /* brelse all resources collected for balancing */
- for ( i = 0; i < MAX_HEIGHT; i++ ) {
- if (wait_tb_buffers_run) {
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->L[i]);
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->R[i]);
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->FL[i]);
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->FR[i]);
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->CFL[i]);
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb, p_s_tb->CFR[i]);
- }
-
- brelse (p_s_tb->L[i]);p_s_tb->L[i] = NULL;
- brelse (p_s_tb->R[i]);p_s_tb->R[i] = NULL;
- brelse (p_s_tb->FL[i]);p_s_tb->FL[i] = NULL;
- brelse (p_s_tb->FR[i]);p_s_tb->FR[i] = NULL;
- brelse (p_s_tb->CFL[i]);p_s_tb->CFL[i] = NULL;
- brelse (p_s_tb->CFR[i]);p_s_tb->CFR[i] = NULL;
+ wait_tb_buffers_run = 1;
+ goto repeat;
}
- if (wait_tb_buffers_run) {
- for ( i = 0; i < MAX_FEB_SIZE; i++ ) {
- if ( p_s_tb->FEB[i] ) {
- reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
- p_s_tb->FEB[i]) ;
+ repeat:
+ // fix_nodes was unable to perform its calculation due to
+ // filesystem got changed under us, lack of free disk space or i/o
+ // failure. If the first is the case - the search will be
+ // repeated. For now - free all resources acquired so far except
+ // for the new allocated nodes
+ {
+ int i;
+
+ /* Release path buffers. */
+ if (wait_tb_buffers_run) {
+ pathrelse_and_restore(p_s_tb->tb_sb, p_s_tb->tb_path);
+ } else {
+ pathrelse(p_s_tb->tb_path);
+ }
+ /* brelse all resources collected for balancing */
+ for (i = 0; i < MAX_HEIGHT; i++) {
+ if (wait_tb_buffers_run) {
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->L[i]);
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->R[i]);
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->FL[i]);
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->FR[i]);
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->
+ CFL[i]);
+ reiserfs_restore_prepared_buffer(p_s_tb->tb_sb,
+ p_s_tb->
+ CFR[i]);
+ }
+
+ brelse(p_s_tb->L[i]);
+ p_s_tb->L[i] = NULL;
+ brelse(p_s_tb->R[i]);
+ p_s_tb->R[i] = NULL;
+ brelse(p_s_tb->FL[i]);
+ p_s_tb->FL[i] = NULL;
+ brelse(p_s_tb->FR[i]);
+ p_s_tb->FR[i] = NULL;
+ brelse(p_s_tb->CFL[i]);
+ p_s_tb->CFL[i] = NULL;
+ brelse(p_s_tb->CFR[i]);
+ p_s_tb->CFR[i] = NULL;
+ }
+
+ if (wait_tb_buffers_run) {
+ for (i = 0; i < MAX_FEB_SIZE; i++) {
+ if (p_s_tb->FEB[i]) {
+ reiserfs_restore_prepared_buffer
+ (p_s_tb->tb_sb, p_s_tb->FEB[i]);
+ }
+ }
}
- }
+ return n_ret_value;
}
- return n_ret_value;
- }
}
-
/* Anatoly will probably forgive me renaming p_s_tb to tb. I just
wanted to make lines shorter */
-void unfix_nodes (struct tree_balance * tb)
+void unfix_nodes(struct tree_balance *tb)
{
- int i;
-
- /* Release path buffers. */
- pathrelse_and_restore (tb->tb_sb, tb->tb_path);
-
- /* brelse all resources collected for balancing */
- for ( i = 0; i < MAX_HEIGHT; i++ ) {
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->L[i]);
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->R[i]);
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->FL[i]);
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->FR[i]);
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->CFL[i]);
- reiserfs_restore_prepared_buffer (tb->tb_sb, tb->CFR[i]);
-
- brelse (tb->L[i]);
- brelse (tb->R[i]);
- brelse (tb->FL[i]);
- brelse (tb->FR[i]);
- brelse (tb->CFL[i]);
- brelse (tb->CFR[i]);
- }
-
- /* deal with list of allocated (used and unused) nodes */
- for ( i = 0; i < MAX_FEB_SIZE; i++ ) {
- if ( tb->FEB[i] ) {
- b_blocknr_t blocknr = tb->FEB[i]->b_blocknr ;
- /* de-allocated block which was not used by balancing and
- bforget about buffer for it */
- brelse (tb->FEB[i]);
- reiserfs_free_block (tb->transaction_handle, NULL, blocknr, 0);
- }
- if (tb->used[i]) {
- /* release used as new nodes including a new root */
- brelse (tb->used[i]);
- }
- }
+ int i;
- if (tb->vn_buf)
- reiserfs_kfree (tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
+ /* Release path buffers. */
+ pathrelse_and_restore(tb->tb_sb, tb->tb_path);
-}
+ /* brelse all resources collected for balancing */
+ for (i = 0; i < MAX_HEIGHT; i++) {
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->L[i]);
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->R[i]);
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FL[i]);
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->FR[i]);
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFL[i]);
+ reiserfs_restore_prepared_buffer(tb->tb_sb, tb->CFR[i]);
+
+ brelse(tb->L[i]);
+ brelse(tb->R[i]);
+ brelse(tb->FL[i]);
+ brelse(tb->FR[i]);
+ brelse(tb->CFL[i]);
+ brelse(tb->CFR[i]);
+ }
+ /* deal with list of allocated (used and unused) nodes */
+ for (i = 0; i < MAX_FEB_SIZE; i++) {
+ if (tb->FEB[i]) {
+ b_blocknr_t blocknr = tb->FEB[i]->b_blocknr;
+ /* de-allocated block which was not used by balancing and
+ bforget about buffer for it */
+ brelse(tb->FEB[i]);
+ reiserfs_free_block(tb->transaction_handle, NULL,
+ blocknr, 0);
+ }
+ if (tb->used[i]) {
+ /* release used as new nodes including a new root */
+ brelse(tb->used[i]);
+ }
+ }
+ if (tb->vn_buf)
+ reiserfs_kfree(tb->vn_buf, tb->vn_buf_size, tb->tb_sb);
+}
diff --git a/fs/reiserfs/hashes.c b/fs/reiserfs/hashes.c
index 08d0508c2d39..37c1306eb9b7 100644
--- a/fs/reiserfs/hashes.c
+++ b/fs/reiserfs/hashes.c
@@ -22,7 +22,6 @@
#include <asm/types.h>
#include <asm/bug.h>
-
#define DELTA 0x9E3779B9
#define FULLROUNDS 10 /* 32 is overkill, 16 is strong crypto */
#define PARTROUNDS 6 /* 6 gets complete mixing */
@@ -48,105 +47,75 @@
h1 += b1; \
} while(0)
-
u32 keyed_hash(const signed char *msg, int len)
{
- u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3};
+ u32 k[] = { 0x9464a485, 0x542e1a94, 0x3e846bff, 0xb75bcfc3 };
u32 h0 = k[0], h1 = k[1];
u32 a, b, c, d;
u32 pad;
int i;
-
- // assert(len >= 0 && len < 256);
- pad = (u32)len | ((u32)len << 8);
+ // assert(len >= 0 && len < 256);
+
+ pad = (u32) len | ((u32) len << 8);
pad |= pad << 16;
- while(len >= 16)
- {
- a = (u32)msg[ 0] |
- (u32)msg[ 1] << 8 |
- (u32)msg[ 2] << 16|
- (u32)msg[ 3] << 24;
- b = (u32)msg[ 4] |
- (u32)msg[ 5] << 8 |
- (u32)msg[ 6] << 16|
- (u32)msg[ 7] << 24;
- c = (u32)msg[ 8] |
- (u32)msg[ 9] << 8 |
- (u32)msg[10] << 16|
- (u32)msg[11] << 24;
- d = (u32)msg[12] |
- (u32)msg[13] << 8 |
- (u32)msg[14] << 16|
- (u32)msg[15] << 24;
-
+ while (len >= 16) {
+ a = (u32) msg[0] |
+ (u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
+ b = (u32) msg[4] |
+ (u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
+ c = (u32) msg[8] |
+ (u32) msg[9] << 8 |
+ (u32) msg[10] << 16 | (u32) msg[11] << 24;
+ d = (u32) msg[12] |
+ (u32) msg[13] << 8 |
+ (u32) msg[14] << 16 | (u32) msg[15] << 24;
+
TEACORE(PARTROUNDS);
len -= 16;
msg += 16;
}
- if (len >= 12)
- {
- a = (u32)msg[ 0] |
- (u32)msg[ 1] << 8 |
- (u32)msg[ 2] << 16|
- (u32)msg[ 3] << 24;
- b = (u32)msg[ 4] |
- (u32)msg[ 5] << 8 |
- (u32)msg[ 6] << 16|
- (u32)msg[ 7] << 24;
- c = (u32)msg[ 8] |
- (u32)msg[ 9] << 8 |
- (u32)msg[10] << 16|
- (u32)msg[11] << 24;
+ if (len >= 12) {
+ a = (u32) msg[0] |
+ (u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
+ b = (u32) msg[4] |
+ (u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
+ c = (u32) msg[8] |
+ (u32) msg[9] << 8 |
+ (u32) msg[10] << 16 | (u32) msg[11] << 24;
d = pad;
- for(i = 12; i < len; i++)
- {
+ for (i = 12; i < len; i++) {
d <<= 8;
d |= msg[i];
}
- }
- else if (len >= 8)
- {
- a = (u32)msg[ 0] |
- (u32)msg[ 1] << 8 |
- (u32)msg[ 2] << 16|
- (u32)msg[ 3] << 24;
- b = (u32)msg[ 4] |
- (u32)msg[ 5] << 8 |
- (u32)msg[ 6] << 16|
- (u32)msg[ 7] << 24;
+ } else if (len >= 8) {
+ a = (u32) msg[0] |
+ (u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
+ b = (u32) msg[4] |
+ (u32) msg[5] << 8 | (u32) msg[6] << 16 | (u32) msg[7] << 24;
c = d = pad;
- for(i = 8; i < len; i++)
- {
+ for (i = 8; i < len; i++) {
c <<= 8;
c |= msg[i];
}
- }
- else if (len >= 4)
- {
- a = (u32)msg[ 0] |
- (u32)msg[ 1] << 8 |
- (u32)msg[ 2] << 16|
- (u32)msg[ 3] << 24;
+ } else if (len >= 4) {
+ a = (u32) msg[0] |
+ (u32) msg[1] << 8 | (u32) msg[2] << 16 | (u32) msg[3] << 24;
b = c = d = pad;
- for(i = 4; i < len; i++)
- {
+ for (i = 4; i < len; i++) {
b <<= 8;
b |= msg[i];
}
- }
- else
- {
+ } else {
a = b = c = d = pad;
- for(i = 0; i < len; i++)
- {
+ for (i = 0; i < len; i++) {
a <<= 8;
a |= msg[i];
}
@@ -155,55 +124,59 @@ u32 keyed_hash(const signed char *msg, int len)
TEACORE(FULLROUNDS);
/* return 0;*/
- return h0^h1;
+ return h0 ^ h1;
}
/* What follows in this file is copyright 2000 by Hans Reiser, and the
* licensing of what follows is governed by reiserfs/README */
-u32 yura_hash (const signed char *msg, int len)
+u32 yura_hash(const signed char *msg, int len)
{
- int j, pow;
- u32 a, c;
- int i;
-
- for (pow=1,i=1; i < len; i++) pow = pow * 10;
-
- if (len == 1)
- a = msg[0]-48;
- else
- a = (msg[0] - 48) * pow;
-
- for (i=1; i < len; i++) {
- c = msg[i] - 48;
- for (pow=1,j=i; j < len-1; j++) pow = pow * 10;
- a = a + c * pow;
- }
-
- for (; i < 40; i++) {
- c = '0' - 48;
- for (pow=1,j=i; j < len-1; j++) pow = pow * 10;
- a = a + c * pow;
- }
-
- for (; i < 256; i++) {
- c = i;
- for (pow=1,j=i; j < len-1; j++) pow = pow * 10;
- a = a + c * pow;
- }
-
- a = a << 7;
- return a;
+ int j, pow;
+ u32 a, c;
+ int i;
+
+ for (pow = 1, i = 1; i < len; i++)
+ pow = pow * 10;
+
+ if (len == 1)
+ a = msg[0] - 48;
+ else
+ a = (msg[0] - 48) * pow;
+
+ for (i = 1; i < len; i++) {
+ c = msg[i] - 48;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ for (; i < 40; i++) {
+ c = '0' - 48;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ for (; i < 256; i++) {
+ c = i;
+ for (pow = 1, j = i; j < len - 1; j++)
+ pow = pow * 10;
+ a = a + c * pow;
+ }
+
+ a = a << 7;
+ return a;
}
-u32 r5_hash (const signed char *msg, int len)
+u32 r5_hash(const signed char *msg, int len)
{
- u32 a=0;
- while(*msg) {
- a += *msg << 4;
- a += *msg >> 4;
- a *= 11;
- msg++;
- }
- return a;
+ u32 a = 0;
+ while (*msg) {
+ a += *msg << 4;
+ a += *msg >> 4;
+ a *= 11;
+ msg++;
+ }
+ return a;
}
diff --git a/fs/reiserfs/ibalance.c b/fs/reiserfs/ibalance.c
index a362125da0d8..6c5a726fd34b 100644
--- a/fs/reiserfs/ibalance.c
+++ b/fs/reiserfs/ibalance.c
@@ -10,13 +10,8 @@
#include <linux/buffer_head.h>
/* this is one and only function that is used outside (do_balance.c) */
-int balance_internal (
- struct tree_balance * ,
- int,
- int,
- struct item_head * ,
- struct buffer_head **
- );
+int balance_internal(struct tree_balance *,
+ int, int, struct item_head *, struct buffer_head **);
/* modes of internal_shift_left, internal_shift_right and internal_insert_childs */
#define INTERNAL_SHIFT_FROM_S_TO_L 0
@@ -27,464 +22,474 @@ int balance_internal (
#define INTERNAL_INSERT_TO_L 5
#define INTERNAL_INSERT_TO_R 6
-static void internal_define_dest_src_infos (
- int shift_mode,
- struct tree_balance * tb,
- int h,
- struct buffer_info * dest_bi,
- struct buffer_info * src_bi,
- int * d_key,
- struct buffer_head ** cf
- )
+static void internal_define_dest_src_infos(int shift_mode,
+ struct tree_balance *tb,
+ int h,
+ struct buffer_info *dest_bi,
+ struct buffer_info *src_bi,
+ int *d_key, struct buffer_head **cf)
{
- memset (dest_bi, 0, sizeof (struct buffer_info));
- memset (src_bi, 0, sizeof (struct buffer_info));
- /* define dest, src, dest parent, dest position */
- switch (shift_mode) {
- case INTERNAL_SHIFT_FROM_S_TO_L: /* used in internal_shift_left */
- src_bi->tb = tb;
- src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
- src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->L[h];
- dest_bi->bi_parent = tb->FL[h];
- dest_bi->bi_position = get_left_neighbor_position (tb, h);
- *d_key = tb->lkey[h];
- *cf = tb->CFL[h];
- break;
- case INTERNAL_SHIFT_FROM_L_TO_S:
- src_bi->tb = tb;
- src_bi->bi_bh = tb->L[h];
- src_bi->bi_parent = tb->FL[h];
- src_bi->bi_position = get_left_neighbor_position (tb, h);
- dest_bi->tb = tb;
- dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
- dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1); /* dest position is analog of dest->b_item_order */
- *d_key = tb->lkey[h];
- *cf = tb->CFL[h];
- break;
-
- case INTERNAL_SHIFT_FROM_R_TO_S: /* used in internal_shift_left */
- src_bi->tb = tb;
- src_bi->bi_bh = tb->R[h];
- src_bi->bi_parent = tb->FR[h];
- src_bi->bi_position = get_right_neighbor_position (tb, h);
- dest_bi->tb = tb;
- dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
- dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
- *d_key = tb->rkey[h];
- *cf = tb->CFR[h];
- break;
-
- case INTERNAL_SHIFT_FROM_S_TO_R:
- src_bi->tb = tb;
- src_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
- src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- src_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->R[h];
- dest_bi->bi_parent = tb->FR[h];
- dest_bi->bi_position = get_right_neighbor_position (tb, h);
- *d_key = tb->rkey[h];
- *cf = tb->CFR[h];
- break;
-
- case INTERNAL_INSERT_TO_L:
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->L[h];
- dest_bi->bi_parent = tb->FL[h];
- dest_bi->bi_position = get_left_neighbor_position (tb, h);
- break;
-
- case INTERNAL_INSERT_TO_S:
- dest_bi->tb = tb;
- dest_bi->bi_bh = PATH_H_PBUFFER (tb->tb_path, h);
- dest_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- dest_bi->bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
- break;
-
- case INTERNAL_INSERT_TO_R:
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->R[h];
- dest_bi->bi_parent = tb->FR[h];
- dest_bi->bi_position = get_right_neighbor_position (tb, h);
- break;
-
- default:
- reiserfs_panic (tb->tb_sb, "internal_define_dest_src_infos: shift type is unknown (%d)", shift_mode);
- }
+ memset(dest_bi, 0, sizeof(struct buffer_info));
+ memset(src_bi, 0, sizeof(struct buffer_info));
+ /* define dest, src, dest parent, dest position */
+ switch (shift_mode) {
+ case INTERNAL_SHIFT_FROM_S_TO_L: /* used in internal_shift_left */
+ src_bi->tb = tb;
+ src_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
+ src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ src_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->L[h];
+ dest_bi->bi_parent = tb->FL[h];
+ dest_bi->bi_position = get_left_neighbor_position(tb, h);
+ *d_key = tb->lkey[h];
+ *cf = tb->CFL[h];
+ break;
+ case INTERNAL_SHIFT_FROM_L_TO_S:
+ src_bi->tb = tb;
+ src_bi->bi_bh = tb->L[h];
+ src_bi->bi_parent = tb->FL[h];
+ src_bi->bi_position = get_left_neighbor_position(tb, h);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
+ dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1); /* dest position is analog of dest->b_item_order */
+ *d_key = tb->lkey[h];
+ *cf = tb->CFL[h];
+ break;
+
+ case INTERNAL_SHIFT_FROM_R_TO_S: /* used in internal_shift_left */
+ src_bi->tb = tb;
+ src_bi->bi_bh = tb->R[h];
+ src_bi->bi_parent = tb->FR[h];
+ src_bi->bi_position = get_right_neighbor_position(tb, h);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
+ dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+ *d_key = tb->rkey[h];
+ *cf = tb->CFR[h];
+ break;
+
+ case INTERNAL_SHIFT_FROM_S_TO_R:
+ src_bi->tb = tb;
+ src_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
+ src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ src_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->R[h];
+ dest_bi->bi_parent = tb->FR[h];
+ dest_bi->bi_position = get_right_neighbor_position(tb, h);
+ *d_key = tb->rkey[h];
+ *cf = tb->CFR[h];
+ break;
+
+ case INTERNAL_INSERT_TO_L:
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->L[h];
+ dest_bi->bi_parent = tb->FL[h];
+ dest_bi->bi_position = get_left_neighbor_position(tb, h);
+ break;
+
+ case INTERNAL_INSERT_TO_S:
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = PATH_H_PBUFFER(tb->tb_path, h);
+ dest_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ dest_bi->bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+ break;
+
+ case INTERNAL_INSERT_TO_R:
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->R[h];
+ dest_bi->bi_parent = tb->FR[h];
+ dest_bi->bi_position = get_right_neighbor_position(tb, h);
+ break;
+
+ default:
+ reiserfs_panic(tb->tb_sb,
+ "internal_define_dest_src_infos: shift type is unknown (%d)",
+ shift_mode);
+ }
}
-
-
/* Insert count node pointers into buffer cur before position to + 1.
* Insert count items into buffer cur before position to.
* Items and node pointers are specified by inserted and bh respectively.
- */
-static void internal_insert_childs (struct buffer_info * cur_bi,
- int to, int count,
- struct item_head * inserted,
- struct buffer_head ** bh
- )
+ */
+static void internal_insert_childs(struct buffer_info *cur_bi,
+ int to, int count,
+ struct item_head *inserted,
+ struct buffer_head **bh)
{
- struct buffer_head * cur = cur_bi->bi_bh;
- struct block_head * blkh;
- int nr;
- struct reiserfs_key * ih;
- struct disk_child new_dc[2];
- struct disk_child * dc;
- int i;
-
- if (count <= 0)
- return;
-
- blkh = B_BLK_HEAD(cur);
- nr = blkh_nr_item(blkh);
-
- RFALSE( count > 2,
- "too many children (%d) are to be inserted", count);
- RFALSE( B_FREE_SPACE (cur) < count * (KEY_SIZE + DC_SIZE),
- "no enough free space (%d), needed %d bytes",
- B_FREE_SPACE (cur), count * (KEY_SIZE + DC_SIZE));
-
- /* prepare space for count disk_child */
- dc = B_N_CHILD(cur,to+1);
-
- memmove (dc + count, dc, (nr+1-(to+1)) * DC_SIZE);
-
- /* copy to_be_insert disk children */
- for (i = 0; i < count; i ++) {
- put_dc_size( &(new_dc[i]), MAX_CHILD_SIZE(bh[i]) - B_FREE_SPACE(bh[i]));
- put_dc_block_number( &(new_dc[i]), bh[i]->b_blocknr );
- }
- memcpy (dc, new_dc, DC_SIZE * count);
-
-
- /* prepare space for count items */
- ih = B_N_PDELIM_KEY (cur, ((to == -1) ? 0 : to));
-
- memmove (ih + count, ih, (nr - to) * KEY_SIZE + (nr + 1 + count) * DC_SIZE);
-
- /* copy item headers (keys) */
- memcpy (ih, inserted, KEY_SIZE);
- if ( count > 1 )
- memcpy (ih + 1, inserted + 1, KEY_SIZE);
-
- /* sizes, item number */
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) + count );
- set_blkh_free_space( blkh,
- blkh_free_space(blkh) - count * (DC_SIZE + KEY_SIZE ) );
-
- do_balance_mark_internal_dirty (cur_bi->tb, cur,0);
-
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (cur);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
-
- if (cur_bi->bi_parent) {
- struct disk_child *t_dc = B_N_CHILD (cur_bi->bi_parent,cur_bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) + (count * (DC_SIZE + KEY_SIZE)));
- do_balance_mark_internal_dirty(cur_bi->tb, cur_bi->bi_parent, 0);
-
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (cur_bi->bi_parent);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- }
+ struct buffer_head *cur = cur_bi->bi_bh;
+ struct block_head *blkh;
+ int nr;
+ struct reiserfs_key *ih;
+ struct disk_child new_dc[2];
+ struct disk_child *dc;
+ int i;
+
+ if (count <= 0)
+ return;
+
+ blkh = B_BLK_HEAD(cur);
+ nr = blkh_nr_item(blkh);
+
+ RFALSE(count > 2, "too many children (%d) are to be inserted", count);
+ RFALSE(B_FREE_SPACE(cur) < count * (KEY_SIZE + DC_SIZE),
+ "no enough free space (%d), needed %d bytes",
+ B_FREE_SPACE(cur), count * (KEY_SIZE + DC_SIZE));
+
+ /* prepare space for count disk_child */
+ dc = B_N_CHILD(cur, to + 1);
+
+ memmove(dc + count, dc, (nr + 1 - (to + 1)) * DC_SIZE);
+
+ /* copy to_be_insert disk children */
+ for (i = 0; i < count; i++) {
+ put_dc_size(&(new_dc[i]),
+ MAX_CHILD_SIZE(bh[i]) - B_FREE_SPACE(bh[i]));
+ put_dc_block_number(&(new_dc[i]), bh[i]->b_blocknr);
+ }
+ memcpy(dc, new_dc, DC_SIZE * count);
+
+ /* prepare space for count items */
+ ih = B_N_PDELIM_KEY(cur, ((to == -1) ? 0 : to));
+
+ memmove(ih + count, ih,
+ (nr - to) * KEY_SIZE + (nr + 1 + count) * DC_SIZE);
+
+ /* copy item headers (keys) */
+ memcpy(ih, inserted, KEY_SIZE);
+ if (count > 1)
+ memcpy(ih + 1, inserted + 1, KEY_SIZE);
+
+ /* sizes, item number */
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) + count);
+ set_blkh_free_space(blkh,
+ blkh_free_space(blkh) - count * (DC_SIZE +
+ KEY_SIZE));
+
+ do_balance_mark_internal_dirty(cur_bi->tb, cur, 0);
+
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(cur);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+
+ if (cur_bi->bi_parent) {
+ struct disk_child *t_dc =
+ B_N_CHILD(cur_bi->bi_parent, cur_bi->bi_position);
+ put_dc_size(t_dc,
+ dc_size(t_dc) + (count * (DC_SIZE + KEY_SIZE)));
+ do_balance_mark_internal_dirty(cur_bi->tb, cur_bi->bi_parent,
+ 0);
+
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(cur_bi->bi_parent);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ }
}
-
/* Delete del_num items and node pointers from buffer cur starting from *
* the first_i'th item and first_p'th pointers respectively. */
-static void internal_delete_pointers_items (
- struct buffer_info * cur_bi,
- int first_p,
- int first_i,
- int del_num
- )
+static void internal_delete_pointers_items(struct buffer_info *cur_bi,
+ int first_p,
+ int first_i, int del_num)
{
- struct buffer_head * cur = cur_bi->bi_bh;
- int nr;
- struct block_head * blkh;
- struct reiserfs_key * key;
- struct disk_child * dc;
-
- RFALSE( cur == NULL, "buffer is 0");
- RFALSE( del_num < 0,
- "negative number of items (%d) can not be deleted", del_num);
- RFALSE( first_p < 0 || first_p + del_num > B_NR_ITEMS (cur) + 1 || first_i < 0,
- "first pointer order (%d) < 0 or "
- "no so many pointers (%d), only (%d) or "
- "first key order %d < 0", first_p,
- first_p + del_num, B_NR_ITEMS (cur) + 1, first_i);
- if ( del_num == 0 )
- return;
-
- blkh = B_BLK_HEAD(cur);
- nr = blkh_nr_item(blkh);
-
- if ( first_p == 0 && del_num == nr + 1 ) {
- RFALSE( first_i != 0, "1st deleted key must have order 0, not %d", first_i);
- make_empty_node (cur_bi);
- return;
- }
-
- RFALSE( first_i + del_num > B_NR_ITEMS (cur),
- "first_i = %d del_num = %d "
- "no so many keys (%d) in the node (%b)(%z)",
- first_i, del_num, first_i + del_num, cur, cur);
-
-
- /* deleting */
- dc = B_N_CHILD (cur, first_p);
-
- memmove (dc, dc + del_num, (nr + 1 - first_p - del_num) * DC_SIZE);
- key = B_N_PDELIM_KEY (cur, first_i);
- memmove (key, key + del_num, (nr - first_i - del_num) * KEY_SIZE + (nr + 1 - del_num) * DC_SIZE);
-
-
- /* sizes, item number */
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) - del_num );
- set_blkh_free_space( blkh,
- blkh_free_space(blkh) + (del_num * (KEY_SIZE + DC_SIZE) ) );
-
- do_balance_mark_internal_dirty (cur_bi->tb, cur, 0);
- /*&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (cur);
- /*&&&&&&&&&&&&&&&&&&&&&&&*/
-
- if (cur_bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD (cur_bi->bi_parent, cur_bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) - (del_num * (KEY_SIZE + DC_SIZE) ) );
-
- do_balance_mark_internal_dirty (cur_bi->tb, cur_bi->bi_parent,0);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (cur_bi->bi_parent);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- }
-}
+ struct buffer_head *cur = cur_bi->bi_bh;
+ int nr;
+ struct block_head *blkh;
+ struct reiserfs_key *key;
+ struct disk_child *dc;
+
+ RFALSE(cur == NULL, "buffer is 0");
+ RFALSE(del_num < 0,
+ "negative number of items (%d) can not be deleted", del_num);
+ RFALSE(first_p < 0 || first_p + del_num > B_NR_ITEMS(cur) + 1
+ || first_i < 0,
+ "first pointer order (%d) < 0 or "
+ "no so many pointers (%d), only (%d) or "
+ "first key order %d < 0", first_p, first_p + del_num,
+ B_NR_ITEMS(cur) + 1, first_i);
+ if (del_num == 0)
+ return;
+
+ blkh = B_BLK_HEAD(cur);
+ nr = blkh_nr_item(blkh);
+
+ if (first_p == 0 && del_num == nr + 1) {
+ RFALSE(first_i != 0,
+ "1st deleted key must have order 0, not %d", first_i);
+ make_empty_node(cur_bi);
+ return;
+ }
+ RFALSE(first_i + del_num > B_NR_ITEMS(cur),
+ "first_i = %d del_num = %d "
+ "no so many keys (%d) in the node (%b)(%z)",
+ first_i, del_num, first_i + del_num, cur, cur);
+
+ /* deleting */
+ dc = B_N_CHILD(cur, first_p);
+
+ memmove(dc, dc + del_num, (nr + 1 - first_p - del_num) * DC_SIZE);
+ key = B_N_PDELIM_KEY(cur, first_i);
+ memmove(key, key + del_num,
+ (nr - first_i - del_num) * KEY_SIZE + (nr + 1 -
+ del_num) * DC_SIZE);
+
+ /* sizes, item number */
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) - del_num);
+ set_blkh_free_space(blkh,
+ blkh_free_space(blkh) +
+ (del_num * (KEY_SIZE + DC_SIZE)));
+
+ do_balance_mark_internal_dirty(cur_bi->tb, cur, 0);
+ /*&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(cur);
+ /*&&&&&&&&&&&&&&&&&&&&&&& */
+
+ if (cur_bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(cur_bi->bi_parent, cur_bi->bi_position);
+ put_dc_size(t_dc,
+ dc_size(t_dc) - (del_num * (KEY_SIZE + DC_SIZE)));
+
+ do_balance_mark_internal_dirty(cur_bi->tb, cur_bi->bi_parent,
+ 0);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(cur_bi->bi_parent);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ }
+}
/* delete n node pointers and items starting from given position */
-static void internal_delete_childs (struct buffer_info * cur_bi,
- int from, int n)
+static void internal_delete_childs(struct buffer_info *cur_bi, int from, int n)
{
- int i_from;
+ int i_from;
- i_from = (from == 0) ? from : from - 1;
+ i_from = (from == 0) ? from : from - 1;
- /* delete n pointers starting from `from' position in CUR;
- delete n keys starting from 'i_from' position in CUR;
- */
- internal_delete_pointers_items (cur_bi, from, i_from, n);
+ /* delete n pointers starting from `from' position in CUR;
+ delete n keys starting from 'i_from' position in CUR;
+ */
+ internal_delete_pointers_items(cur_bi, from, i_from, n);
}
-
/* copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest
* last_first == FIRST_TO_LAST means, that we copy first items from src to tail of dest
* last_first == LAST_TO_FIRST means, that we copy last items from src to head of dest
*/
-static void internal_copy_pointers_items (
- struct buffer_info * dest_bi,
- struct buffer_head * src,
- int last_first, int cpy_num
- )
+static void internal_copy_pointers_items(struct buffer_info *dest_bi,
+ struct buffer_head *src,
+ int last_first, int cpy_num)
{
- /* ATTENTION! Number of node pointers in DEST is equal to number of items in DEST *
- * as delimiting key have already inserted to buffer dest.*/
- struct buffer_head * dest = dest_bi->bi_bh;
- int nr_dest, nr_src;
- int dest_order, src_order;
- struct block_head * blkh;
- struct reiserfs_key * key;
- struct disk_child * dc;
-
- nr_src = B_NR_ITEMS (src);
-
- RFALSE( dest == NULL || src == NULL,
- "src (%p) or dest (%p) buffer is 0", src, dest);
- RFALSE( last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
- "invalid last_first parameter (%d)", last_first);
- RFALSE( nr_src < cpy_num - 1,
- "no so many items (%d) in src (%d)", cpy_num, nr_src);
- RFALSE( cpy_num < 0, "cpy_num less than 0 (%d)", cpy_num);
- RFALSE( cpy_num - 1 + B_NR_ITEMS(dest) > (int)MAX_NR_KEY(dest),
- "cpy_num (%d) + item number in dest (%d) can not be > MAX_NR_KEY(%d)",
- cpy_num, B_NR_ITEMS(dest), MAX_NR_KEY(dest));
-
- if ( cpy_num == 0 )
- return;
+ /* ATTENTION! Number of node pointers in DEST is equal to number of items in DEST *
+ * as delimiting key have already inserted to buffer dest.*/
+ struct buffer_head *dest = dest_bi->bi_bh;
+ int nr_dest, nr_src;
+ int dest_order, src_order;
+ struct block_head *blkh;
+ struct reiserfs_key *key;
+ struct disk_child *dc;
+
+ nr_src = B_NR_ITEMS(src);
+
+ RFALSE(dest == NULL || src == NULL,
+ "src (%p) or dest (%p) buffer is 0", src, dest);
+ RFALSE(last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
+ "invalid last_first parameter (%d)", last_first);
+ RFALSE(nr_src < cpy_num - 1,
+ "no so many items (%d) in src (%d)", cpy_num, nr_src);
+ RFALSE(cpy_num < 0, "cpy_num less than 0 (%d)", cpy_num);
+ RFALSE(cpy_num - 1 + B_NR_ITEMS(dest) > (int)MAX_NR_KEY(dest),
+ "cpy_num (%d) + item number in dest (%d) can not be > MAX_NR_KEY(%d)",
+ cpy_num, B_NR_ITEMS(dest), MAX_NR_KEY(dest));
+
+ if (cpy_num == 0)
+ return;
/* coping */
- blkh = B_BLK_HEAD(dest);
- nr_dest = blkh_nr_item(blkh);
+ blkh = B_BLK_HEAD(dest);
+ nr_dest = blkh_nr_item(blkh);
- /*dest_order = (last_first == LAST_TO_FIRST) ? 0 : nr_dest;*/
- /*src_order = (last_first == LAST_TO_FIRST) ? (nr_src - cpy_num + 1) : 0;*/
- (last_first == LAST_TO_FIRST) ? (dest_order = 0, src_order = nr_src - cpy_num + 1) :
- (dest_order = nr_dest, src_order = 0);
+ /*dest_order = (last_first == LAST_TO_FIRST) ? 0 : nr_dest; */
+ /*src_order = (last_first == LAST_TO_FIRST) ? (nr_src - cpy_num + 1) : 0; */
+ (last_first == LAST_TO_FIRST) ? (dest_order = 0, src_order =
+ nr_src - cpy_num + 1) : (dest_order =
+ nr_dest,
+ src_order =
+ 0);
- /* prepare space for cpy_num pointers */
- dc = B_N_CHILD (dest, dest_order);
+ /* prepare space for cpy_num pointers */
+ dc = B_N_CHILD(dest, dest_order);
- memmove (dc + cpy_num, dc, (nr_dest - dest_order) * DC_SIZE);
+ memmove(dc + cpy_num, dc, (nr_dest - dest_order) * DC_SIZE);
/* insert pointers */
- memcpy (dc, B_N_CHILD (src, src_order), DC_SIZE * cpy_num);
-
-
- /* prepare space for cpy_num - 1 item headers */
- key = B_N_PDELIM_KEY(dest, dest_order);
- memmove (key + cpy_num - 1, key,
- KEY_SIZE * (nr_dest - dest_order) + DC_SIZE * (nr_dest + cpy_num));
-
-
- /* insert headers */
- memcpy (key, B_N_PDELIM_KEY (src, src_order), KEY_SIZE * (cpy_num - 1));
-
- /* sizes, item number */
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) + (cpy_num - 1 ) );
- set_blkh_free_space( blkh,
- blkh_free_space(blkh) - (KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num ) );
-
- do_balance_mark_internal_dirty (dest_bi->tb, dest, 0);
-
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (dest);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
-
- if (dest_bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) + (KEY_SIZE * (cpy_num - 1) + DC_SIZE * cpy_num) );
-
- do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent,0);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (dest_bi->bi_parent);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- }
+ memcpy(dc, B_N_CHILD(src, src_order), DC_SIZE * cpy_num);
+
+ /* prepare space for cpy_num - 1 item headers */
+ key = B_N_PDELIM_KEY(dest, dest_order);
+ memmove(key + cpy_num - 1, key,
+ KEY_SIZE * (nr_dest - dest_order) + DC_SIZE * (nr_dest +
+ cpy_num));
+
+ /* insert headers */
+ memcpy(key, B_N_PDELIM_KEY(src, src_order), KEY_SIZE * (cpy_num - 1));
+
+ /* sizes, item number */
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) + (cpy_num - 1));
+ set_blkh_free_space(blkh,
+ blkh_free_space(blkh) - (KEY_SIZE * (cpy_num - 1) +
+ DC_SIZE * cpy_num));
+
+ do_balance_mark_internal_dirty(dest_bi->tb, dest, 0);
+
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(dest);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+
+ if (dest_bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(dest_bi->bi_parent, dest_bi->bi_position);
+ put_dc_size(t_dc,
+ dc_size(t_dc) + (KEY_SIZE * (cpy_num - 1) +
+ DC_SIZE * cpy_num));
+
+ do_balance_mark_internal_dirty(dest_bi->tb, dest_bi->bi_parent,
+ 0);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(dest_bi->bi_parent);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ }
}
-
/* Copy cpy_num node pointers and cpy_num - 1 items from buffer src to buffer dest.
* Delete cpy_num - del_par items and node pointers from buffer src.
* last_first == FIRST_TO_LAST means, that we copy/delete first items from src.
* last_first == LAST_TO_FIRST means, that we copy/delete last items from src.
*/
-static void internal_move_pointers_items (struct buffer_info * dest_bi,
- struct buffer_info * src_bi,
- int last_first, int cpy_num, int del_par)
+static void internal_move_pointers_items(struct buffer_info *dest_bi,
+ struct buffer_info *src_bi,
+ int last_first, int cpy_num,
+ int del_par)
{
- int first_pointer;
- int first_item;
-
- internal_copy_pointers_items (dest_bi, src_bi->bi_bh, last_first, cpy_num);
-
- if (last_first == FIRST_TO_LAST) { /* shift_left occurs */
- first_pointer = 0;
- first_item = 0;
- /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer,
- for key - with first_item */
- internal_delete_pointers_items (src_bi, first_pointer, first_item, cpy_num - del_par);
- } else { /* shift_right occurs */
- int i, j;
-
- i = ( cpy_num - del_par == ( j = B_NR_ITEMS(src_bi->bi_bh)) + 1 ) ? 0 : j - cpy_num + del_par;
-
- internal_delete_pointers_items (src_bi, j + 1 - cpy_num + del_par, i, cpy_num - del_par);
- }
+ int first_pointer;
+ int first_item;
+
+ internal_copy_pointers_items(dest_bi, src_bi->bi_bh, last_first,
+ cpy_num);
+
+ if (last_first == FIRST_TO_LAST) { /* shift_left occurs */
+ first_pointer = 0;
+ first_item = 0;
+ /* delete cpy_num - del_par pointers and keys starting for pointers with first_pointer,
+ for key - with first_item */
+ internal_delete_pointers_items(src_bi, first_pointer,
+ first_item, cpy_num - del_par);
+ } else { /* shift_right occurs */
+ int i, j;
+
+ i = (cpy_num - del_par ==
+ (j =
+ B_NR_ITEMS(src_bi->bi_bh)) + 1) ? 0 : j - cpy_num +
+ del_par;
+
+ internal_delete_pointers_items(src_bi,
+ j + 1 - cpy_num + del_par, i,
+ cpy_num - del_par);
+ }
}
/* Insert n_src'th key of buffer src before n_dest'th key of buffer dest. */
-static void internal_insert_key (struct buffer_info * dest_bi,
- int dest_position_before, /* insert key before key with n_dest number */
- struct buffer_head * src,
- int src_position)
+static void internal_insert_key(struct buffer_info *dest_bi, int dest_position_before, /* insert key before key with n_dest number */
+ struct buffer_head *src, int src_position)
{
- struct buffer_head * dest = dest_bi->bi_bh;
- int nr;
- struct block_head * blkh;
- struct reiserfs_key * key;
-
- RFALSE( dest == NULL || src == NULL,
- "source(%p) or dest(%p) buffer is 0", src, dest);
- RFALSE( dest_position_before < 0 || src_position < 0,
- "source(%d) or dest(%d) key number less than 0",
- src_position, dest_position_before);
- RFALSE( dest_position_before > B_NR_ITEMS (dest) ||
- src_position >= B_NR_ITEMS(src),
- "invalid position in dest (%d (key number %d)) or in src (%d (key number %d))",
- dest_position_before, B_NR_ITEMS (dest),
- src_position, B_NR_ITEMS(src));
- RFALSE( B_FREE_SPACE (dest) < KEY_SIZE,
- "no enough free space (%d) in dest buffer", B_FREE_SPACE (dest));
-
- blkh = B_BLK_HEAD(dest);
- nr = blkh_nr_item(blkh);
-
- /* prepare space for inserting key */
- key = B_N_PDELIM_KEY (dest, dest_position_before);
- memmove (key + 1, key, (nr - dest_position_before) * KEY_SIZE + (nr + 1) * DC_SIZE);
-
- /* insert key */
- memcpy (key, B_N_PDELIM_KEY(src, src_position), KEY_SIZE);
-
- /* Change dirt, free space, item number fields. */
-
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) + 1 );
- set_blkh_free_space( blkh, blkh_free_space(blkh) - KEY_SIZE );
-
- do_balance_mark_internal_dirty (dest_bi->tb, dest, 0);
-
- if (dest_bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD(dest_bi->bi_parent,dest_bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) + KEY_SIZE );
-
- do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent,0);
- }
+ struct buffer_head *dest = dest_bi->bi_bh;
+ int nr;
+ struct block_head *blkh;
+ struct reiserfs_key *key;
+
+ RFALSE(dest == NULL || src == NULL,
+ "source(%p) or dest(%p) buffer is 0", src, dest);
+ RFALSE(dest_position_before < 0 || src_position < 0,
+ "source(%d) or dest(%d) key number less than 0",
+ src_position, dest_position_before);
+ RFALSE(dest_position_before > B_NR_ITEMS(dest) ||
+ src_position >= B_NR_ITEMS(src),
+ "invalid position in dest (%d (key number %d)) or in src (%d (key number %d))",
+ dest_position_before, B_NR_ITEMS(dest),
+ src_position, B_NR_ITEMS(src));
+ RFALSE(B_FREE_SPACE(dest) < KEY_SIZE,
+ "no enough free space (%d) in dest buffer", B_FREE_SPACE(dest));
+
+ blkh = B_BLK_HEAD(dest);
+ nr = blkh_nr_item(blkh);
+
+ /* prepare space for inserting key */
+ key = B_N_PDELIM_KEY(dest, dest_position_before);
+ memmove(key + 1, key,
+ (nr - dest_position_before) * KEY_SIZE + (nr + 1) * DC_SIZE);
+
+ /* insert key */
+ memcpy(key, B_N_PDELIM_KEY(src, src_position), KEY_SIZE);
+
+ /* Change dirt, free space, item number fields. */
+
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) + 1);
+ set_blkh_free_space(blkh, blkh_free_space(blkh) - KEY_SIZE);
+
+ do_balance_mark_internal_dirty(dest_bi->tb, dest, 0);
+
+ if (dest_bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(dest_bi->bi_parent, dest_bi->bi_position);
+ put_dc_size(t_dc, dc_size(t_dc) + KEY_SIZE);
+
+ do_balance_mark_internal_dirty(dest_bi->tb, dest_bi->bi_parent,
+ 0);
+ }
}
-
-
/* Insert d_key'th (delimiting) key from buffer cfl to tail of dest.
* Copy pointer_amount node pointers and pointer_amount - 1 items from buffer src to buffer dest.
* Replace d_key'th key in buffer cfl.
* Delete pointer_amount items and node pointers from buffer src.
*/
/* this can be invoked both to shift from S to L and from R to S */
-static void internal_shift_left (
- int mode, /* INTERNAL_FROM_S_TO_L | INTERNAL_FROM_R_TO_S */
- struct tree_balance * tb,
- int h,
- int pointer_amount
- )
+static void internal_shift_left(int mode, /* INTERNAL_FROM_S_TO_L | INTERNAL_FROM_R_TO_S */
+ struct tree_balance *tb,
+ int h, int pointer_amount)
{
- struct buffer_info dest_bi, src_bi;
- struct buffer_head * cf;
- int d_key_position;
-
- internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
-
- /*printk("pointer_amount = %d\n",pointer_amount);*/
-
- if (pointer_amount) {
- /* insert delimiting key from common father of dest and src to node dest into position B_NR_ITEM(dest) */
- internal_insert_key (&dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position);
-
- if (B_NR_ITEMS(src_bi.bi_bh) == pointer_amount - 1) {
- if (src_bi.bi_position/*src->b_item_order*/ == 0)
- replace_key (tb, cf, d_key_position, src_bi.bi_parent/*src->b_parent*/, 0);
- } else
- replace_key (tb, cf, d_key_position, src_bi.bi_bh, pointer_amount - 1);
- }
- /* last parameter is del_parameter */
- internal_move_pointers_items (&dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 0);
+ struct buffer_info dest_bi, src_bi;
+ struct buffer_head *cf;
+ int d_key_position;
+
+ internal_define_dest_src_infos(mode, tb, h, &dest_bi, &src_bi,
+ &d_key_position, &cf);
+
+ /*printk("pointer_amount = %d\n",pointer_amount); */
+
+ if (pointer_amount) {
+ /* insert delimiting key from common father of dest and src to node dest into position B_NR_ITEM(dest) */
+ internal_insert_key(&dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf,
+ d_key_position);
+
+ if (B_NR_ITEMS(src_bi.bi_bh) == pointer_amount - 1) {
+ if (src_bi.bi_position /*src->b_item_order */ == 0)
+ replace_key(tb, cf, d_key_position,
+ src_bi.
+ bi_parent /*src->b_parent */ , 0);
+ } else
+ replace_key(tb, cf, d_key_position, src_bi.bi_bh,
+ pointer_amount - 1);
+ }
+ /* last parameter is del_parameter */
+ internal_move_pointers_items(&dest_bi, &src_bi, FIRST_TO_LAST,
+ pointer_amount, 0);
}
@@ -493,67 +498,66 @@ static void internal_shift_left (
* Delete n - 1 items and node pointers from buffer S[h].
*/
/* it always shifts from S[h] to L[h] */
-static void internal_shift1_left (
- struct tree_balance * tb,
- int h,
- int pointer_amount
- )
+static void internal_shift1_left(struct tree_balance *tb,
+ int h, int pointer_amount)
{
- struct buffer_info dest_bi, src_bi;
- struct buffer_head * cf;
- int d_key_position;
+ struct buffer_info dest_bi, src_bi;
+ struct buffer_head *cf;
+ int d_key_position;
- internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
+ internal_define_dest_src_infos(INTERNAL_SHIFT_FROM_S_TO_L, tb, h,
+ &dest_bi, &src_bi, &d_key_position, &cf);
- if ( pointer_amount > 0 ) /* insert lkey[h]-th key from CFL[h] to left neighbor L[h] */
- internal_insert_key (&dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf, d_key_position);
- /* internal_insert_key (tb->L[h], B_NR_ITEM(tb->L[h]), tb->CFL[h], tb->lkey[h]);*/
+ if (pointer_amount > 0) /* insert lkey[h]-th key from CFL[h] to left neighbor L[h] */
+ internal_insert_key(&dest_bi, B_NR_ITEMS(dest_bi.bi_bh), cf,
+ d_key_position);
+ /* internal_insert_key (tb->L[h], B_NR_ITEM(tb->L[h]), tb->CFL[h], tb->lkey[h]); */
- /* last parameter is del_parameter */
- internal_move_pointers_items (&dest_bi, &src_bi, FIRST_TO_LAST, pointer_amount, 1);
- /* internal_move_pointers_items (tb->L[h], tb->S[h], FIRST_TO_LAST, pointer_amount, 1);*/
+ /* last parameter is del_parameter */
+ internal_move_pointers_items(&dest_bi, &src_bi, FIRST_TO_LAST,
+ pointer_amount, 1);
+ /* internal_move_pointers_items (tb->L[h], tb->S[h], FIRST_TO_LAST, pointer_amount, 1); */
}
-
/* Insert d_key'th (delimiting) key from buffer cfr to head of dest.
* Copy n node pointers and n - 1 items from buffer src to buffer dest.
* Replace d_key'th key in buffer cfr.
* Delete n items and node pointers from buffer src.
*/
-static void internal_shift_right (
- int mode, /* INTERNAL_FROM_S_TO_R | INTERNAL_FROM_L_TO_S */
- struct tree_balance * tb,
- int h,
- int pointer_amount
- )
+static void internal_shift_right(int mode, /* INTERNAL_FROM_S_TO_R | INTERNAL_FROM_L_TO_S */
+ struct tree_balance *tb,
+ int h, int pointer_amount)
{
- struct buffer_info dest_bi, src_bi;
- struct buffer_head * cf;
- int d_key_position;
- int nr;
-
-
- internal_define_dest_src_infos (mode, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
-
- nr = B_NR_ITEMS (src_bi.bi_bh);
-
- if (pointer_amount > 0) {
- /* insert delimiting key from common father of dest and src to dest node into position 0 */
- internal_insert_key (&dest_bi, 0, cf, d_key_position);
- if (nr == pointer_amount - 1) {
- RFALSE( src_bi.bi_bh != PATH_H_PBUFFER (tb->tb_path, h)/*tb->S[h]*/ ||
- dest_bi.bi_bh != tb->R[h],
- "src (%p) must be == tb->S[h](%p) when it disappears",
- src_bi.bi_bh, PATH_H_PBUFFER (tb->tb_path, h));
- /* when S[h] disappers replace left delemiting key as well */
- if (tb->CFL[h])
- replace_key (tb, cf, d_key_position, tb->CFL[h], tb->lkey[h]);
- } else
- replace_key (tb, cf, d_key_position, src_bi.bi_bh, nr - pointer_amount);
- }
-
- /* last parameter is del_parameter */
- internal_move_pointers_items (&dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 0);
+ struct buffer_info dest_bi, src_bi;
+ struct buffer_head *cf;
+ int d_key_position;
+ int nr;
+
+ internal_define_dest_src_infos(mode, tb, h, &dest_bi, &src_bi,
+ &d_key_position, &cf);
+
+ nr = B_NR_ITEMS(src_bi.bi_bh);
+
+ if (pointer_amount > 0) {
+ /* insert delimiting key from common father of dest and src to dest node into position 0 */
+ internal_insert_key(&dest_bi, 0, cf, d_key_position);
+ if (nr == pointer_amount - 1) {
+ RFALSE(src_bi.bi_bh != PATH_H_PBUFFER(tb->tb_path, h) /*tb->S[h] */ ||
+ dest_bi.bi_bh != tb->R[h],
+ "src (%p) must be == tb->S[h](%p) when it disappears",
+ src_bi.bi_bh, PATH_H_PBUFFER(tb->tb_path, h));
+ /* when S[h] disappers replace left delemiting key as well */
+ if (tb->CFL[h])
+ replace_key(tb, cf, d_key_position, tb->CFL[h],
+ tb->lkey[h]);
+ } else
+ replace_key(tb, cf, d_key_position, src_bi.bi_bh,
+ nr - pointer_amount);
+ }
+
+ /* last parameter is del_parameter */
+ internal_move_pointers_items(&dest_bi, &src_bi, LAST_TO_FIRST,
+ pointer_amount, 0);
}
/* Insert delimiting key to R[h].
@@ -561,498 +565,526 @@ static void internal_shift_right (
* Delete n - 1 items and node pointers from buffer S[h].
*/
/* it always shift from S[h] to R[h] */
-static void internal_shift1_right (
- struct tree_balance * tb,
- int h,
- int pointer_amount
- )
+static void internal_shift1_right(struct tree_balance *tb,
+ int h, int pointer_amount)
{
- struct buffer_info dest_bi, src_bi;
- struct buffer_head * cf;
- int d_key_position;
-
- internal_define_dest_src_infos (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, &dest_bi, &src_bi, &d_key_position, &cf);
-
- if (pointer_amount > 0) /* insert rkey from CFR[h] to right neighbor R[h] */
- internal_insert_key (&dest_bi, 0, cf, d_key_position);
- /* internal_insert_key (tb->R[h], 0, tb->CFR[h], tb->rkey[h]);*/
-
- /* last parameter is del_parameter */
- internal_move_pointers_items (&dest_bi, &src_bi, LAST_TO_FIRST, pointer_amount, 1);
- /* internal_move_pointers_items (tb->R[h], tb->S[h], LAST_TO_FIRST, pointer_amount, 1);*/
-}
+ struct buffer_info dest_bi, src_bi;
+ struct buffer_head *cf;
+ int d_key_position;
+
+ internal_define_dest_src_infos(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
+ &dest_bi, &src_bi, &d_key_position, &cf);
+
+ if (pointer_amount > 0) /* insert rkey from CFR[h] to right neighbor R[h] */
+ internal_insert_key(&dest_bi, 0, cf, d_key_position);
+ /* internal_insert_key (tb->R[h], 0, tb->CFR[h], tb->rkey[h]); */
+ /* last parameter is del_parameter */
+ internal_move_pointers_items(&dest_bi, &src_bi, LAST_TO_FIRST,
+ pointer_amount, 1);
+ /* internal_move_pointers_items (tb->R[h], tb->S[h], LAST_TO_FIRST, pointer_amount, 1); */
+}
/* Delete insert_num node pointers together with their left items
* and balance current node.*/
-static void balance_internal_when_delete (struct tree_balance * tb,
- int h, int child_pos)
+static void balance_internal_when_delete(struct tree_balance *tb,
+ int h, int child_pos)
{
- int insert_num;
- int n;
- struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h);
- struct buffer_info bi;
-
- insert_num = tb->insert_size[h] / ((int)(DC_SIZE + KEY_SIZE));
-
- /* delete child-node-pointer(s) together with their left item(s) */
- bi.tb = tb;
- bi.bi_bh = tbSh;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
-
- internal_delete_childs (&bi, child_pos, -insert_num);
-
- RFALSE( tb->blknum[h] > 1,
- "tb->blknum[%d]=%d when insert_size < 0", h, tb->blknum[h]);
-
- n = B_NR_ITEMS(tbSh);
-
- if ( tb->lnum[h] == 0 && tb->rnum[h] == 0 ) {
- if ( tb->blknum[h] == 0 ) {
- /* node S[h] (root of the tree) is empty now */
- struct buffer_head *new_root;
-
- RFALSE( n || B_FREE_SPACE (tbSh) != MAX_CHILD_SIZE(tbSh) - DC_SIZE,
- "buffer must have only 0 keys (%d)", n);
- RFALSE( bi.bi_parent, "root has parent (%p)", bi.bi_parent);
-
- /* choose a new root */
- if ( ! tb->L[h-1] || ! B_NR_ITEMS(tb->L[h-1]) )
- new_root = tb->R[h-1];
- else
- new_root = tb->L[h-1];
- /* switch super block's tree root block number to the new value */
- PUT_SB_ROOT_BLOCK( tb->tb_sb, new_root->b_blocknr );
- //REISERFS_SB(tb->tb_sb)->s_rs->s_tree_height --;
- PUT_SB_TREE_HEIGHT( tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) - 1 );
-
- do_balance_mark_sb_dirty (tb, REISERFS_SB(tb->tb_sb)->s_sbh, 1);
- /*&&&&&&&&&&&&&&&&&&&&&&*/
- if (h > 1)
- /* use check_internal if new root is an internal node */
- check_internal (new_root);
- /*&&&&&&&&&&&&&&&&&&&&&&*/
-
- /* do what is needed for buffer thrown from tree */
- reiserfs_invalidate_buffer(tb, tbSh);
- return;
+ int insert_num;
+ int n;
+ struct buffer_head *tbSh = PATH_H_PBUFFER(tb->tb_path, h);
+ struct buffer_info bi;
+
+ insert_num = tb->insert_size[h] / ((int)(DC_SIZE + KEY_SIZE));
+
+ /* delete child-node-pointer(s) together with their left item(s) */
+ bi.tb = tb;
+ bi.bi_bh = tbSh;
+ bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+
+ internal_delete_childs(&bi, child_pos, -insert_num);
+
+ RFALSE(tb->blknum[h] > 1,
+ "tb->blknum[%d]=%d when insert_size < 0", h, tb->blknum[h]);
+
+ n = B_NR_ITEMS(tbSh);
+
+ if (tb->lnum[h] == 0 && tb->rnum[h] == 0) {
+ if (tb->blknum[h] == 0) {
+ /* node S[h] (root of the tree) is empty now */
+ struct buffer_head *new_root;
+
+ RFALSE(n
+ || B_FREE_SPACE(tbSh) !=
+ MAX_CHILD_SIZE(tbSh) - DC_SIZE,
+ "buffer must have only 0 keys (%d)", n);
+ RFALSE(bi.bi_parent, "root has parent (%p)",
+ bi.bi_parent);
+
+ /* choose a new root */
+ if (!tb->L[h - 1] || !B_NR_ITEMS(tb->L[h - 1]))
+ new_root = tb->R[h - 1];
+ else
+ new_root = tb->L[h - 1];
+ /* switch super block's tree root block number to the new value */
+ PUT_SB_ROOT_BLOCK(tb->tb_sb, new_root->b_blocknr);
+ //REISERFS_SB(tb->tb_sb)->s_rs->s_tree_height --;
+ PUT_SB_TREE_HEIGHT(tb->tb_sb,
+ SB_TREE_HEIGHT(tb->tb_sb) - 1);
+
+ do_balance_mark_sb_dirty(tb,
+ REISERFS_SB(tb->tb_sb)->s_sbh,
+ 1);
+ /*&&&&&&&&&&&&&&&&&&&&&& */
+ if (h > 1)
+ /* use check_internal if new root is an internal node */
+ check_internal(new_root);
+ /*&&&&&&&&&&&&&&&&&&&&&& */
+
+ /* do what is needed for buffer thrown from tree */
+ reiserfs_invalidate_buffer(tb, tbSh);
+ return;
+ }
+ return;
+ }
+
+ if (tb->L[h] && tb->lnum[h] == -B_NR_ITEMS(tb->L[h]) - 1) { /* join S[h] with L[h] */
+
+ RFALSE(tb->rnum[h] != 0,
+ "invalid tb->rnum[%d]==%d when joining S[h] with L[h]",
+ h, tb->rnum[h]);
+
+ internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h, n + 1);
+ reiserfs_invalidate_buffer(tb, tbSh);
+
+ return;
+ }
+
+ if (tb->R[h] && tb->rnum[h] == -B_NR_ITEMS(tb->R[h]) - 1) { /* join S[h] with R[h] */
+ RFALSE(tb->lnum[h] != 0,
+ "invalid tb->lnum[%d]==%d when joining S[h] with R[h]",
+ h, tb->lnum[h]);
+
+ internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h, n + 1);
+
+ reiserfs_invalidate_buffer(tb, tbSh);
+ return;
}
- return;
- }
-
- if ( tb->L[h] && tb->lnum[h] == -B_NR_ITEMS(tb->L[h]) - 1 ) { /* join S[h] with L[h] */
-
- RFALSE( tb->rnum[h] != 0,
- "invalid tb->rnum[%d]==%d when joining S[h] with L[h]",
- h, tb->rnum[h]);
-
- internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, n + 1);
- reiserfs_invalidate_buffer(tb, tbSh);
-
- return;
- }
-
- if ( tb->R[h] && tb->rnum[h] == -B_NR_ITEMS(tb->R[h]) - 1 ) { /* join S[h] with R[h] */
- RFALSE( tb->lnum[h] != 0,
- "invalid tb->lnum[%d]==%d when joining S[h] with R[h]",
- h, tb->lnum[h]);
-
- internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, n + 1);
-
- reiserfs_invalidate_buffer(tb,tbSh);
- return;
- }
-
- if ( tb->lnum[h] < 0 ) { /* borrow from left neighbor L[h] */
- RFALSE( tb->rnum[h] != 0,
- "wrong tb->rnum[%d]==%d when borrow from L[h]", h, tb->rnum[h]);
- /*internal_shift_right (tb, h, tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], -tb->lnum[h]);*/
- internal_shift_right (INTERNAL_SHIFT_FROM_L_TO_S, tb, h, -tb->lnum[h]);
- return;
- }
-
- if ( tb->rnum[h] < 0 ) { /* borrow from right neighbor R[h] */
- RFALSE( tb->lnum[h] != 0,
- "invalid tb->lnum[%d]==%d when borrow from R[h]",
- h, tb->lnum[h]);
- internal_shift_left (INTERNAL_SHIFT_FROM_R_TO_S, tb, h, -tb->rnum[h]);/*tb->S[h], tb->CFR[h], tb->rkey[h], tb->R[h], -tb->rnum[h]);*/
- return;
- }
-
- if ( tb->lnum[h] > 0 ) { /* split S[h] into two parts and put them into neighbors */
- RFALSE( tb->rnum[h] == 0 || tb->lnum[h] + tb->rnum[h] != n + 1,
- "invalid tb->lnum[%d]==%d or tb->rnum[%d]==%d when S[h](item number == %d) is split between them",
- h, tb->lnum[h], h, tb->rnum[h], n);
-
- internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);/*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], tb->lnum[h]);*/
- internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]);
-
- reiserfs_invalidate_buffer (tb, tbSh);
-
- return;
- }
- reiserfs_panic (tb->tb_sb, "balance_internal_when_delete: unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
- h, tb->lnum[h], h, tb->rnum[h]);
-}
+ if (tb->lnum[h] < 0) { /* borrow from left neighbor L[h] */
+ RFALSE(tb->rnum[h] != 0,
+ "wrong tb->rnum[%d]==%d when borrow from L[h]", h,
+ tb->rnum[h]);
+ /*internal_shift_right (tb, h, tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], -tb->lnum[h]); */
+ internal_shift_right(INTERNAL_SHIFT_FROM_L_TO_S, tb, h,
+ -tb->lnum[h]);
+ return;
+ }
+
+ if (tb->rnum[h] < 0) { /* borrow from right neighbor R[h] */
+ RFALSE(tb->lnum[h] != 0,
+ "invalid tb->lnum[%d]==%d when borrow from R[h]",
+ h, tb->lnum[h]);
+ internal_shift_left(INTERNAL_SHIFT_FROM_R_TO_S, tb, h, -tb->rnum[h]); /*tb->S[h], tb->CFR[h], tb->rkey[h], tb->R[h], -tb->rnum[h]); */
+ return;
+ }
+
+ if (tb->lnum[h] > 0) { /* split S[h] into two parts and put them into neighbors */
+ RFALSE(tb->rnum[h] == 0 || tb->lnum[h] + tb->rnum[h] != n + 1,
+ "invalid tb->lnum[%d]==%d or tb->rnum[%d]==%d when S[h](item number == %d) is split between them",
+ h, tb->lnum[h], h, tb->rnum[h], n);
+
+ internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]); /*tb->L[h], tb->CFL[h], tb->lkey[h], tb->S[h], tb->lnum[h]); */
+ internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
+ tb->rnum[h]);
+
+ reiserfs_invalidate_buffer(tb, tbSh);
+
+ return;
+ }
+ reiserfs_panic(tb->tb_sb,
+ "balance_internal_when_delete: unexpected tb->lnum[%d]==%d or tb->rnum[%d]==%d",
+ h, tb->lnum[h], h, tb->rnum[h]);
+}
/* Replace delimiting key of buffers L[h] and S[h] by the given key.*/
-static void replace_lkey (
- struct tree_balance * tb,
- int h,
- struct item_head * key
- )
+static void replace_lkey(struct tree_balance *tb, int h, struct item_head *key)
{
- RFALSE( tb->L[h] == NULL || tb->CFL[h] == NULL,
- "L[h](%p) and CFL[h](%p) must exist in replace_lkey",
- tb->L[h], tb->CFL[h]);
+ RFALSE(tb->L[h] == NULL || tb->CFL[h] == NULL,
+ "L[h](%p) and CFL[h](%p) must exist in replace_lkey",
+ tb->L[h], tb->CFL[h]);
- if (B_NR_ITEMS(PATH_H_PBUFFER(tb->tb_path, h)) == 0)
- return;
+ if (B_NR_ITEMS(PATH_H_PBUFFER(tb->tb_path, h)) == 0)
+ return;
- memcpy (B_N_PDELIM_KEY(tb->CFL[h],tb->lkey[h]), key, KEY_SIZE);
+ memcpy(B_N_PDELIM_KEY(tb->CFL[h], tb->lkey[h]), key, KEY_SIZE);
- do_balance_mark_internal_dirty (tb, tb->CFL[h],0);
+ do_balance_mark_internal_dirty(tb, tb->CFL[h], 0);
}
-
/* Replace delimiting key of buffers S[h] and R[h] by the given key.*/
-static void replace_rkey (
- struct tree_balance * tb,
- int h,
- struct item_head * key
- )
+static void replace_rkey(struct tree_balance *tb, int h, struct item_head *key)
{
- RFALSE( tb->R[h] == NULL || tb->CFR[h] == NULL,
- "R[h](%p) and CFR[h](%p) must exist in replace_rkey",
- tb->R[h], tb->CFR[h]);
- RFALSE( B_NR_ITEMS(tb->R[h]) == 0,
- "R[h] can not be empty if it exists (item number=%d)",
- B_NR_ITEMS(tb->R[h]));
+ RFALSE(tb->R[h] == NULL || tb->CFR[h] == NULL,
+ "R[h](%p) and CFR[h](%p) must exist in replace_rkey",
+ tb->R[h], tb->CFR[h]);
+ RFALSE(B_NR_ITEMS(tb->R[h]) == 0,
+ "R[h] can not be empty if it exists (item number=%d)",
+ B_NR_ITEMS(tb->R[h]));
- memcpy (B_N_PDELIM_KEY(tb->CFR[h],tb->rkey[h]), key, KEY_SIZE);
+ memcpy(B_N_PDELIM_KEY(tb->CFR[h], tb->rkey[h]), key, KEY_SIZE);
- do_balance_mark_internal_dirty (tb, tb->CFR[h], 0);
+ do_balance_mark_internal_dirty(tb, tb->CFR[h], 0);
}
-
-int balance_internal (struct tree_balance * tb, /* tree_balance structure */
- int h, /* level of the tree */
- int child_pos,
- struct item_head * insert_key, /* key for insertion on higher level */
- struct buffer_head ** insert_ptr /* node for insertion on higher level*/
+int balance_internal(struct tree_balance *tb, /* tree_balance structure */
+ int h, /* level of the tree */
+ int child_pos, struct item_head *insert_key, /* key for insertion on higher level */
+ struct buffer_head **insert_ptr /* node for insertion on higher level */
)
/* if inserting/pasting
{
- child_pos is the position of the node-pointer in S[h] that *
- pointed to S[h-1] before balancing of the h-1 level; *
+ child_pos is the position of the node-pointer in S[h] that *
+ pointed to S[h-1] before balancing of the h-1 level; *
this means that new pointers and items must be inserted AFTER *
child_pos
}
else
{
- it is the position of the leftmost pointer that must be deleted (together with
- its corresponding key to the left of the pointer)
- as a result of the previous level's balancing.
- }
-*/
+ it is the position of the leftmost pointer that must be deleted (together with
+ its corresponding key to the left of the pointer)
+ as a result of the previous level's balancing.
+ }
+ */
{
- struct buffer_head * tbSh = PATH_H_PBUFFER (tb->tb_path, h);
- struct buffer_info bi;
- int order; /* we return this: it is 0 if there is no S[h], else it is tb->S[h]->b_item_order */
- int insert_num, n, k;
- struct buffer_head * S_new;
- struct item_head new_insert_key;
- struct buffer_head * new_insert_ptr = NULL;
- struct item_head * new_insert_key_addr = insert_key;
-
- RFALSE( h < 1, "h (%d) can not be < 1 on internal level", h);
-
- PROC_INFO_INC( tb -> tb_sb, balance_at[ h ] );
-
- order = ( tbSh ) ? PATH_H_POSITION (tb->tb_path, h + 1)/*tb->S[h]->b_item_order*/ : 0;
-
- /* Using insert_size[h] calculate the number insert_num of items
- that must be inserted to or deleted from S[h]. */
- insert_num = tb->insert_size[h]/((int)(KEY_SIZE + DC_SIZE));
-
- /* Check whether insert_num is proper **/
- RFALSE( insert_num < -2 || insert_num > 2,
- "incorrect number of items inserted to the internal node (%d)",
- insert_num);
- RFALSE( h > 1 && (insert_num > 1 || insert_num < -1),
- "incorrect number of items (%d) inserted to the internal node on a level (h=%d) higher than last internal level",
- insert_num, h);
-
- /* Make balance in case insert_num < 0 */
- if ( insert_num < 0 ) {
- balance_internal_when_delete (tb, h, child_pos);
- return order;
- }
-
- k = 0;
- if ( tb->lnum[h] > 0 ) {
- /* shift lnum[h] items from S[h] to the left neighbor L[h].
- check how many of new items fall into L[h] or CFL[h] after
- shifting */
- n = B_NR_ITEMS (tb->L[h]); /* number of items in L[h] */
- if ( tb->lnum[h] <= child_pos ) {
- /* new items don't fall into L[h] or CFL[h] */
- internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h]);
- /*internal_shift_left (tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,tb->lnum[h]);*/
- child_pos -= tb->lnum[h];
- } else if ( tb->lnum[h] > child_pos + insert_num ) {
- /* all new items fall into L[h] */
- internal_shift_left (INTERNAL_SHIFT_FROM_S_TO_L, tb, h, tb->lnum[h] - insert_num);
- /* internal_shift_left(tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,
- tb->lnum[h]-insert_num);
- */
- /* insert insert_num keys and node-pointers into L[h] */
- bi.tb = tb;
- bi.bi_bh = tb->L[h];
- bi.bi_parent = tb->FL[h];
- bi.bi_position = get_left_neighbor_position (tb, h);
- internal_insert_childs (&bi,/*tb->L[h], tb->S[h-1]->b_next*/ n + child_pos + 1,
- insert_num,insert_key,insert_ptr);
-
- insert_num = 0;
- } else {
- struct disk_child * dc;
-
- /* some items fall into L[h] or CFL[h], but some don't fall */
- internal_shift1_left(tb,h,child_pos+1);
- /* calculate number of new items that fall into L[h] */
- k = tb->lnum[h] - child_pos - 1;
- bi.tb = tb;
- bi.bi_bh = tb->L[h];
- bi.bi_parent = tb->FL[h];
- bi.bi_position = get_left_neighbor_position (tb, h);
- internal_insert_childs (&bi,/*tb->L[h], tb->S[h-1]->b_next,*/ n + child_pos + 1,k,
- insert_key,insert_ptr);
-
- replace_lkey(tb,h,insert_key + k);
-
- /* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */
- dc = B_N_CHILD(tbSh, 0);
- put_dc_size( dc, MAX_CHILD_SIZE(insert_ptr[k]) - B_FREE_SPACE (insert_ptr[k]));
- put_dc_block_number( dc, insert_ptr[k]->b_blocknr );
-
- do_balance_mark_internal_dirty (tb, tbSh, 0);
-
- k++;
- insert_key += k;
- insert_ptr += k;
- insert_num -= k;
- child_pos = 0;
+ struct buffer_head *tbSh = PATH_H_PBUFFER(tb->tb_path, h);
+ struct buffer_info bi;
+ int order; /* we return this: it is 0 if there is no S[h], else it is tb->S[h]->b_item_order */
+ int insert_num, n, k;
+ struct buffer_head *S_new;
+ struct item_head new_insert_key;
+ struct buffer_head *new_insert_ptr = NULL;
+ struct item_head *new_insert_key_addr = insert_key;
+
+ RFALSE(h < 1, "h (%d) can not be < 1 on internal level", h);
+
+ PROC_INFO_INC(tb->tb_sb, balance_at[h]);
+
+ order =
+ (tbSh) ? PATH_H_POSITION(tb->tb_path,
+ h + 1) /*tb->S[h]->b_item_order */ : 0;
+
+ /* Using insert_size[h] calculate the number insert_num of items
+ that must be inserted to or deleted from S[h]. */
+ insert_num = tb->insert_size[h] / ((int)(KEY_SIZE + DC_SIZE));
+
+ /* Check whether insert_num is proper * */
+ RFALSE(insert_num < -2 || insert_num > 2,
+ "incorrect number of items inserted to the internal node (%d)",
+ insert_num);
+ RFALSE(h > 1 && (insert_num > 1 || insert_num < -1),
+ "incorrect number of items (%d) inserted to the internal node on a level (h=%d) higher than last internal level",
+ insert_num, h);
+
+ /* Make balance in case insert_num < 0 */
+ if (insert_num < 0) {
+ balance_internal_when_delete(tb, h, child_pos);
+ return order;
}
- } /* tb->lnum[h] > 0 */
-
- if ( tb->rnum[h] > 0 ) {
- /*shift rnum[h] items from S[h] to the right neighbor R[h]*/
- /* check how many of new items fall into R or CFR after shifting */
- n = B_NR_ITEMS (tbSh); /* number of items in S[h] */
- if ( n - tb->rnum[h] >= child_pos )
- /* new items fall into S[h] */
- /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],tb->rnum[h]);*/
- internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h]);
- else
- if ( n + insert_num - tb->rnum[h] < child_pos )
- {
- /* all new items fall into R[h] */
- /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],
- tb->rnum[h] - insert_num);*/
- internal_shift_right (INTERNAL_SHIFT_FROM_S_TO_R, tb, h, tb->rnum[h] - insert_num);
-
- /* insert insert_num keys and node-pointers into R[h] */
- bi.tb = tb;
- bi.bi_bh = tb->R[h];
- bi.bi_parent = tb->FR[h];
- bi.bi_position = get_right_neighbor_position (tb, h);
- internal_insert_childs (&bi, /*tb->R[h],tb->S[h-1]->b_next*/ child_pos - n - insert_num + tb->rnum[h] - 1,
- insert_num,insert_key,insert_ptr);
- insert_num = 0;
- }
- else
- {
- struct disk_child * dc;
-
- /* one of the items falls into CFR[h] */
- internal_shift1_right(tb,h,n - child_pos + 1);
- /* calculate number of new items that fall into R[h] */
- k = tb->rnum[h] - n + child_pos - 1;
- bi.tb = tb;
- bi.bi_bh = tb->R[h];
- bi.bi_parent = tb->FR[h];
- bi.bi_position = get_right_neighbor_position (tb, h);
- internal_insert_childs (&bi, /*tb->R[h], tb->R[h]->b_child,*/ 0, k, insert_key + 1, insert_ptr + 1);
- replace_rkey(tb,h,insert_key + insert_num - k - 1);
+ k = 0;
+ if (tb->lnum[h] > 0) {
+ /* shift lnum[h] items from S[h] to the left neighbor L[h].
+ check how many of new items fall into L[h] or CFL[h] after
+ shifting */
+ n = B_NR_ITEMS(tb->L[h]); /* number of items in L[h] */
+ if (tb->lnum[h] <= child_pos) {
+ /* new items don't fall into L[h] or CFL[h] */
+ internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h,
+ tb->lnum[h]);
+ /*internal_shift_left (tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,tb->lnum[h]); */
+ child_pos -= tb->lnum[h];
+ } else if (tb->lnum[h] > child_pos + insert_num) {
+ /* all new items fall into L[h] */
+ internal_shift_left(INTERNAL_SHIFT_FROM_S_TO_L, tb, h,
+ tb->lnum[h] - insert_num);
+ /* internal_shift_left(tb->L[h],tb->CFL[h],tb->lkey[h],tbSh,
+ tb->lnum[h]-insert_num);
+ */
+ /* insert insert_num keys and node-pointers into L[h] */
+ bi.tb = tb;
+ bi.bi_bh = tb->L[h];
+ bi.bi_parent = tb->FL[h];
+ bi.bi_position = get_left_neighbor_position(tb, h);
+ internal_insert_childs(&bi,
+ /*tb->L[h], tb->S[h-1]->b_next */
+ n + child_pos + 1,
+ insert_num, insert_key,
+ insert_ptr);
+
+ insert_num = 0;
+ } else {
+ struct disk_child *dc;
+
+ /* some items fall into L[h] or CFL[h], but some don't fall */
+ internal_shift1_left(tb, h, child_pos + 1);
+ /* calculate number of new items that fall into L[h] */
+ k = tb->lnum[h] - child_pos - 1;
+ bi.tb = tb;
+ bi.bi_bh = tb->L[h];
+ bi.bi_parent = tb->FL[h];
+ bi.bi_position = get_left_neighbor_position(tb, h);
+ internal_insert_childs(&bi,
+ /*tb->L[h], tb->S[h-1]->b_next, */
+ n + child_pos + 1, k,
+ insert_key, insert_ptr);
+
+ replace_lkey(tb, h, insert_key + k);
+
+ /* replace the first node-ptr in S[h] by node-ptr to insert_ptr[k] */
+ dc = B_N_CHILD(tbSh, 0);
+ put_dc_size(dc,
+ MAX_CHILD_SIZE(insert_ptr[k]) -
+ B_FREE_SPACE(insert_ptr[k]));
+ put_dc_block_number(dc, insert_ptr[k]->b_blocknr);
+
+ do_balance_mark_internal_dirty(tb, tbSh, 0);
+
+ k++;
+ insert_key += k;
+ insert_ptr += k;
+ insert_num -= k;
+ child_pos = 0;
+ }
+ }
+ /* tb->lnum[h] > 0 */
+ if (tb->rnum[h] > 0) {
+ /*shift rnum[h] items from S[h] to the right neighbor R[h] */
+ /* check how many of new items fall into R or CFR after shifting */
+ n = B_NR_ITEMS(tbSh); /* number of items in S[h] */
+ if (n - tb->rnum[h] >= child_pos)
+ /* new items fall into S[h] */
+ /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],tb->rnum[h]); */
+ internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
+ tb->rnum[h]);
+ else if (n + insert_num - tb->rnum[h] < child_pos) {
+ /* all new items fall into R[h] */
+ /*internal_shift_right(tb,h,tbSh,tb->CFR[h],tb->rkey[h],tb->R[h],
+ tb->rnum[h] - insert_num); */
+ internal_shift_right(INTERNAL_SHIFT_FROM_S_TO_R, tb, h,
+ tb->rnum[h] - insert_num);
+
+ /* insert insert_num keys and node-pointers into R[h] */
+ bi.tb = tb;
+ bi.bi_bh = tb->R[h];
+ bi.bi_parent = tb->FR[h];
+ bi.bi_position = get_right_neighbor_position(tb, h);
+ internal_insert_childs(&bi,
+ /*tb->R[h],tb->S[h-1]->b_next */
+ child_pos - n - insert_num +
+ tb->rnum[h] - 1,
+ insert_num, insert_key,
+ insert_ptr);
+ insert_num = 0;
+ } else {
+ struct disk_child *dc;
+
+ /* one of the items falls into CFR[h] */
+ internal_shift1_right(tb, h, n - child_pos + 1);
+ /* calculate number of new items that fall into R[h] */
+ k = tb->rnum[h] - n + child_pos - 1;
+ bi.tb = tb;
+ bi.bi_bh = tb->R[h];
+ bi.bi_parent = tb->FR[h];
+ bi.bi_position = get_right_neighbor_position(tb, h);
+ internal_insert_childs(&bi,
+ /*tb->R[h], tb->R[h]->b_child, */
+ 0, k, insert_key + 1,
+ insert_ptr + 1);
+
+ replace_rkey(tb, h, insert_key + insert_num - k - 1);
+
+ /* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1] */
+ dc = B_N_CHILD(tb->R[h], 0);
+ put_dc_size(dc,
+ MAX_CHILD_SIZE(insert_ptr
+ [insert_num - k - 1]) -
+ B_FREE_SPACE(insert_ptr
+ [insert_num - k - 1]));
+ put_dc_block_number(dc,
+ insert_ptr[insert_num - k -
+ 1]->b_blocknr);
+
+ do_balance_mark_internal_dirty(tb, tb->R[h], 0);
+
+ insert_num -= (k + 1);
+ }
+ }
- /* replace the first node-ptr in R[h] by node-ptr insert_ptr[insert_num-k-1]*/
- dc = B_N_CHILD(tb->R[h], 0);
- put_dc_size( dc, MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
- B_FREE_SPACE (insert_ptr[insert_num-k-1]));
- put_dc_block_number( dc, insert_ptr[insert_num-k-1]->b_blocknr );
+ /** Fill new node that appears instead of S[h] **/
+ RFALSE(tb->blknum[h] > 2, "blknum can not be > 2 for internal level");
+ RFALSE(tb->blknum[h] < 0, "blknum can not be < 0");
- do_balance_mark_internal_dirty (tb, tb->R[h],0);
+ if (!tb->blknum[h]) { /* node S[h] is empty now */
+ RFALSE(!tbSh, "S[h] is equal NULL");
- insert_num -= (k + 1);
- }
- }
+ /* do what is needed for buffer thrown from tree */
+ reiserfs_invalidate_buffer(tb, tbSh);
+ return order;
+ }
- /** Fill new node that appears instead of S[h] **/
- RFALSE( tb->blknum[h] > 2, "blknum can not be > 2 for internal level");
- RFALSE( tb->blknum[h] < 0, "blknum can not be < 0");
+ if (!tbSh) {
+ /* create new root */
+ struct disk_child *dc;
+ struct buffer_head *tbSh_1 = PATH_H_PBUFFER(tb->tb_path, h - 1);
+ struct block_head *blkh;
- if ( ! tb->blknum[h] )
- { /* node S[h] is empty now */
- RFALSE( ! tbSh, "S[h] is equal NULL");
+ if (tb->blknum[h] != 1)
+ reiserfs_panic(NULL,
+ "balance_internal: One new node required for creating the new root");
+ /* S[h] = empty buffer from the list FEB. */
+ tbSh = get_FEB(tb);
+ blkh = B_BLK_HEAD(tbSh);
+ set_blkh_level(blkh, h + 1);
- /* do what is needed for buffer thrown from tree */
- reiserfs_invalidate_buffer(tb,tbSh);
- return order;
- }
-
- if ( ! tbSh ) {
- /* create new root */
- struct disk_child * dc;
- struct buffer_head * tbSh_1 = PATH_H_PBUFFER (tb->tb_path, h - 1);
- struct block_head * blkh;
-
-
- if ( tb->blknum[h] != 1 )
- reiserfs_panic(NULL, "balance_internal: One new node required for creating the new root");
- /* S[h] = empty buffer from the list FEB. */
- tbSh = get_FEB (tb);
- blkh = B_BLK_HEAD(tbSh);
- set_blkh_level( blkh, h + 1 );
-
- /* Put the unique node-pointer to S[h] that points to S[h-1]. */
-
- dc = B_N_CHILD(tbSh, 0);
- put_dc_block_number( dc, tbSh_1->b_blocknr );
- put_dc_size( dc, (MAX_CHILD_SIZE (tbSh_1) - B_FREE_SPACE (tbSh_1)));
-
- tb->insert_size[h] -= DC_SIZE;
- set_blkh_free_space( blkh, blkh_free_space(blkh) - DC_SIZE );
-
- do_balance_mark_internal_dirty (tb, tbSh, 0);
-
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
- check_internal (tbSh);
- /*&&&&&&&&&&&&&&&&&&&&&&&&*/
-
- /* put new root into path structure */
- PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) = tbSh;
-
- /* Change root in structure super block. */
- PUT_SB_ROOT_BLOCK( tb->tb_sb, tbSh->b_blocknr );
- PUT_SB_TREE_HEIGHT( tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) + 1 );
- do_balance_mark_sb_dirty (tb, REISERFS_SB(tb->tb_sb)->s_sbh, 1);
- }
-
- if ( tb->blknum[h] == 2 ) {
- int snum;
- struct buffer_info dest_bi, src_bi;
+ /* Put the unique node-pointer to S[h] that points to S[h-1]. */
+
+ dc = B_N_CHILD(tbSh, 0);
+ put_dc_block_number(dc, tbSh_1->b_blocknr);
+ put_dc_size(dc,
+ (MAX_CHILD_SIZE(tbSh_1) - B_FREE_SPACE(tbSh_1)));
+
+ tb->insert_size[h] -= DC_SIZE;
+ set_blkh_free_space(blkh, blkh_free_space(blkh) - DC_SIZE);
+ do_balance_mark_internal_dirty(tb, tbSh, 0);
- /* S_new = free buffer from list FEB */
- S_new = get_FEB(tb);
-
- set_blkh_level( B_BLK_HEAD(S_new), h + 1 );
-
- dest_bi.tb = tb;
- dest_bi.bi_bh = S_new;
- dest_bi.bi_parent = NULL;
- dest_bi.bi_position = 0;
- src_bi.tb = tb;
- src_bi.bi_bh = tbSh;
- src_bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- src_bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
-
- n = B_NR_ITEMS (tbSh); /* number of items in S[h] */
- snum = (insert_num + n + 1)/2;
- if ( n - snum >= child_pos ) {
- /* new items don't fall into S_new */
- /* store the delimiting key for the next level */
- /* new_insert_key = (n - snum)'th key in S[h] */
- memcpy (&new_insert_key,B_N_PDELIM_KEY(tbSh,n - snum),
- KEY_SIZE);
- /* last parameter is del_par */
- internal_move_pointers_items (&dest_bi, &src_bi, LAST_TO_FIRST, snum, 0);
- /* internal_move_pointers_items(S_new, tbSh, LAST_TO_FIRST, snum, 0);*/
- } else if ( n + insert_num - snum < child_pos ) {
- /* all new items fall into S_new */
- /* store the delimiting key for the next level */
- /* new_insert_key = (n + insert_item - snum)'th key in S[h] */
- memcpy(&new_insert_key,B_N_PDELIM_KEY(tbSh,n + insert_num - snum),
- KEY_SIZE);
- /* last parameter is del_par */
- internal_move_pointers_items (&dest_bi, &src_bi, LAST_TO_FIRST, snum - insert_num, 0);
- /* internal_move_pointers_items(S_new,tbSh,1,snum - insert_num,0);*/
-
- /* insert insert_num keys and node-pointers into S_new */
- internal_insert_childs (&dest_bi, /*S_new,tb->S[h-1]->b_next,*/child_pos - n - insert_num + snum - 1,
- insert_num,insert_key,insert_ptr);
-
- insert_num = 0;
- } else {
- struct disk_child * dc;
-
- /* some items fall into S_new, but some don't fall */
- /* last parameter is del_par */
- internal_move_pointers_items (&dest_bi, &src_bi, LAST_TO_FIRST, n - child_pos + 1, 1);
- /* internal_move_pointers_items(S_new,tbSh,1,n - child_pos + 1,1);*/
- /* calculate number of new items that fall into S_new */
- k = snum - n + child_pos - 1;
-
- internal_insert_childs (&dest_bi, /*S_new,*/ 0, k, insert_key + 1, insert_ptr+1);
-
- /* new_insert_key = insert_key[insert_num - k - 1] */
- memcpy(&new_insert_key,insert_key + insert_num - k - 1,
- KEY_SIZE);
- /* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */
-
- dc = B_N_CHILD(S_new,0);
- put_dc_size( dc, (MAX_CHILD_SIZE(insert_ptr[insert_num-k-1]) -
- B_FREE_SPACE(insert_ptr[insert_num-k-1])) );
- put_dc_block_number( dc, insert_ptr[insert_num-k-1]->b_blocknr );
-
- do_balance_mark_internal_dirty (tb, S_new,0);
-
- insert_num -= (k + 1);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+ check_internal(tbSh);
+ /*&&&&&&&&&&&&&&&&&&&&&&&& */
+
+ /* put new root into path structure */
+ PATH_OFFSET_PBUFFER(tb->tb_path, ILLEGAL_PATH_ELEMENT_OFFSET) =
+ tbSh;
+
+ /* Change root in structure super block. */
+ PUT_SB_ROOT_BLOCK(tb->tb_sb, tbSh->b_blocknr);
+ PUT_SB_TREE_HEIGHT(tb->tb_sb, SB_TREE_HEIGHT(tb->tb_sb) + 1);
+ do_balance_mark_sb_dirty(tb, REISERFS_SB(tb->tb_sb)->s_sbh, 1);
}
- /* new_insert_ptr = node_pointer to S_new */
- new_insert_ptr = S_new;
-
- RFALSE (!buffer_journaled(S_new) || buffer_journal_dirty(S_new) ||
- buffer_dirty (S_new),
- "cm-00001: bad S_new (%b)", S_new);
-
- // S_new is released in unfix_nodes
- }
-
- n = B_NR_ITEMS (tbSh); /*number of items in S[h] */
-
- if ( 0 <= child_pos && child_pos <= n && insert_num > 0 ) {
- bi.tb = tb;
- bi.bi_bh = tbSh;
- bi.bi_parent = PATH_H_PPARENT (tb->tb_path, h);
- bi.bi_position = PATH_H_POSITION (tb->tb_path, h + 1);
- internal_insert_childs (
- &bi,/*tbSh,*/
- /* ( tb->S[h-1]->b_parent == tb->S[h] ) ? tb->S[h-1]->b_next : tb->S[h]->b_child->b_next,*/
- child_pos,insert_num,insert_key,insert_ptr
- );
+
+ if (tb->blknum[h] == 2) {
+ int snum;
+ struct buffer_info dest_bi, src_bi;
+
+ /* S_new = free buffer from list FEB */
+ S_new = get_FEB(tb);
+
+ set_blkh_level(B_BLK_HEAD(S_new), h + 1);
+
+ dest_bi.tb = tb;
+ dest_bi.bi_bh = S_new;
+ dest_bi.bi_parent = NULL;
+ dest_bi.bi_position = 0;
+ src_bi.tb = tb;
+ src_bi.bi_bh = tbSh;
+ src_bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ src_bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+
+ n = B_NR_ITEMS(tbSh); /* number of items in S[h] */
+ snum = (insert_num + n + 1) / 2;
+ if (n - snum >= child_pos) {
+ /* new items don't fall into S_new */
+ /* store the delimiting key for the next level */
+ /* new_insert_key = (n - snum)'th key in S[h] */
+ memcpy(&new_insert_key, B_N_PDELIM_KEY(tbSh, n - snum),
+ KEY_SIZE);
+ /* last parameter is del_par */
+ internal_move_pointers_items(&dest_bi, &src_bi,
+ LAST_TO_FIRST, snum, 0);
+ /* internal_move_pointers_items(S_new, tbSh, LAST_TO_FIRST, snum, 0); */
+ } else if (n + insert_num - snum < child_pos) {
+ /* all new items fall into S_new */
+ /* store the delimiting key for the next level */
+ /* new_insert_key = (n + insert_item - snum)'th key in S[h] */
+ memcpy(&new_insert_key,
+ B_N_PDELIM_KEY(tbSh, n + insert_num - snum),
+ KEY_SIZE);
+ /* last parameter is del_par */
+ internal_move_pointers_items(&dest_bi, &src_bi,
+ LAST_TO_FIRST,
+ snum - insert_num, 0);
+ /* internal_move_pointers_items(S_new,tbSh,1,snum - insert_num,0); */
+
+ /* insert insert_num keys and node-pointers into S_new */
+ internal_insert_childs(&dest_bi,
+ /*S_new,tb->S[h-1]->b_next, */
+ child_pos - n - insert_num +
+ snum - 1,
+ insert_num, insert_key,
+ insert_ptr);
+
+ insert_num = 0;
+ } else {
+ struct disk_child *dc;
+
+ /* some items fall into S_new, but some don't fall */
+ /* last parameter is del_par */
+ internal_move_pointers_items(&dest_bi, &src_bi,
+ LAST_TO_FIRST,
+ n - child_pos + 1, 1);
+ /* internal_move_pointers_items(S_new,tbSh,1,n - child_pos + 1,1); */
+ /* calculate number of new items that fall into S_new */
+ k = snum - n + child_pos - 1;
+
+ internal_insert_childs(&dest_bi, /*S_new, */ 0, k,
+ insert_key + 1, insert_ptr + 1);
+
+ /* new_insert_key = insert_key[insert_num - k - 1] */
+ memcpy(&new_insert_key, insert_key + insert_num - k - 1,
+ KEY_SIZE);
+ /* replace first node-ptr in S_new by node-ptr to insert_ptr[insert_num-k-1] */
+
+ dc = B_N_CHILD(S_new, 0);
+ put_dc_size(dc,
+ (MAX_CHILD_SIZE
+ (insert_ptr[insert_num - k - 1]) -
+ B_FREE_SPACE(insert_ptr
+ [insert_num - k - 1])));
+ put_dc_block_number(dc,
+ insert_ptr[insert_num - k -
+ 1]->b_blocknr);
+
+ do_balance_mark_internal_dirty(tb, S_new, 0);
+
+ insert_num -= (k + 1);
+ }
+ /* new_insert_ptr = node_pointer to S_new */
+ new_insert_ptr = S_new;
+
+ RFALSE(!buffer_journaled(S_new) || buffer_journal_dirty(S_new)
+ || buffer_dirty(S_new), "cm-00001: bad S_new (%b)",
+ S_new);
+
+ // S_new is released in unfix_nodes
}
+ n = B_NR_ITEMS(tbSh); /*number of items in S[h] */
- memcpy (new_insert_key_addr,&new_insert_key,KEY_SIZE);
+ if (0 <= child_pos && child_pos <= n && insert_num > 0) {
+ bi.tb = tb;
+ bi.bi_bh = tbSh;
+ bi.bi_parent = PATH_H_PPARENT(tb->tb_path, h);
+ bi.bi_position = PATH_H_POSITION(tb->tb_path, h + 1);
+ internal_insert_childs(&bi, /*tbSh, */
+ /* ( tb->S[h-1]->b_parent == tb->S[h] ) ? tb->S[h-1]->b_next : tb->S[h]->b_child->b_next, */
+ child_pos, insert_num, insert_key,
+ insert_ptr);
+ }
+
+ memcpy(new_insert_key_addr, &new_insert_key, KEY_SIZE);
insert_ptr[0] = new_insert_ptr;
return order;
- }
-
-
-
+}
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
index 2711dff1b7b4..1aaf2c7d44e6 100644
--- a/fs/reiserfs/inode.c
+++ b/fs/reiserfs/inode.c
@@ -18,107 +18,109 @@
#include <linux/writeback.h>
#include <linux/quotaops.h>
-extern int reiserfs_default_io_size; /* default io size devuned in super.c */
+extern int reiserfs_default_io_size; /* default io size devuned in super.c */
static int reiserfs_commit_write(struct file *f, struct page *page,
- unsigned from, unsigned to);
+ unsigned from, unsigned to);
static int reiserfs_prepare_write(struct file *f, struct page *page,
unsigned from, unsigned to);
-void reiserfs_delete_inode (struct inode * inode)
+void reiserfs_delete_inode(struct inode *inode)
{
- /* We need blocks for transaction + (user+group) quota update (possibly delete) */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * REISERFS_QUOTA_INIT_BLOCKS;
- struct reiserfs_transaction_handle th ;
-
- reiserfs_write_lock(inode->i_sb);
+ /* We need blocks for transaction + (user+group) quota update (possibly delete) */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 2 +
+ 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb);
+ struct reiserfs_transaction_handle th;
- /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
- if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
- down (&inode->i_sem);
+ reiserfs_write_lock(inode->i_sb);
- reiserfs_delete_xattrs (inode);
+ /* The = 0 happens when we abort creating a new inode for some reason like lack of space.. */
+ if (!(inode->i_state & I_NEW) && INODE_PKEY(inode)->k_objectid != 0) { /* also handles bad_inode case */
+ down(&inode->i_sem);
- if (journal_begin(&th, inode->i_sb, jbegin_count)) {
- up (&inode->i_sem);
- goto out;
- }
- reiserfs_update_inode_transaction(inode) ;
+ reiserfs_delete_xattrs(inode);
- if (reiserfs_delete_object (&th, inode)) {
- up (&inode->i_sem);
- goto out;
- }
+ if (journal_begin(&th, inode->i_sb, jbegin_count)) {
+ up(&inode->i_sem);
+ goto out;
+ }
+ reiserfs_update_inode_transaction(inode);
- /* Do quota update inside a transaction for journaled quotas. We must do that
- * after delete_object so that quota updates go into the same transaction as
- * stat data deletion */
- DQUOT_FREE_INODE(inode);
+ if (reiserfs_delete_object(&th, inode)) {
+ up(&inode->i_sem);
+ goto out;
+ }
- if (journal_end(&th, inode->i_sb, jbegin_count)) {
- up (&inode->i_sem);
- goto out;
- }
+ /* Do quota update inside a transaction for journaled quotas. We must do that
+ * after delete_object so that quota updates go into the same transaction as
+ * stat data deletion */
+ DQUOT_FREE_INODE(inode);
+
+ if (journal_end(&th, inode->i_sb, jbegin_count)) {
+ up(&inode->i_sem);
+ goto out;
+ }
- up (&inode->i_sem);
+ up(&inode->i_sem);
- /* all items of file are deleted, so we can remove "save" link */
- remove_save_link (inode, 0/* not truncate */); /* we can't do anything
- * about an error here */
- } else {
- /* no object items are in the tree */
- ;
- }
-out:
- clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */
- inode->i_blocks = 0;
- reiserfs_write_unlock(inode->i_sb);
+ /* all items of file are deleted, so we can remove "save" link */
+ remove_save_link(inode, 0 /* not truncate */ ); /* we can't do anything
+ * about an error here */
+ } else {
+ /* no object items are in the tree */
+ ;
+ }
+ out:
+ clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */
+ inode->i_blocks = 0;
+ reiserfs_write_unlock(inode->i_sb);
}
-static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid,
- loff_t offset, int type, int length )
+static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid,
+ __u32 objectid, loff_t offset, int type, int length)
{
- key->version = version;
+ key->version = version;
- key->on_disk_key.k_dir_id = dirid;
- key->on_disk_key.k_objectid = objectid;
- set_cpu_key_k_offset (key, offset);
- set_cpu_key_k_type (key, type);
- key->key_length = length;
+ key->on_disk_key.k_dir_id = dirid;
+ key->on_disk_key.k_objectid = objectid;
+ set_cpu_key_k_offset(key, offset);
+ set_cpu_key_k_type(key, type);
+ key->key_length = length;
}
-
/* take base of inode_key (it comes from inode always) (dirid, objectid) and version from an inode, set
offset and type of key */
-void make_cpu_key (struct cpu_key * key, struct inode * inode, loff_t offset,
- int type, int length )
+void make_cpu_key(struct cpu_key *key, struct inode *inode, loff_t offset,
+ int type, int length)
{
- _make_cpu_key (key, get_inode_item_key_version (inode), le32_to_cpu (INODE_PKEY (inode)->k_dir_id),
- le32_to_cpu (INODE_PKEY (inode)->k_objectid),
- offset, type, length);
+ _make_cpu_key(key, get_inode_item_key_version(inode),
+ le32_to_cpu(INODE_PKEY(inode)->k_dir_id),
+ le32_to_cpu(INODE_PKEY(inode)->k_objectid), offset, type,
+ length);
}
-
//
// when key is 0, do not set version and short key
//
-inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key,
- int version,
- loff_t offset, int type, int length,
- int entry_count/*or ih_free_space*/)
+inline void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
+ int version,
+ loff_t offset, int type, int length,
+ int entry_count /*or ih_free_space */ )
{
- if (key) {
- ih->ih_key.k_dir_id = cpu_to_le32 (key->on_disk_key.k_dir_id);
- ih->ih_key.k_objectid = cpu_to_le32 (key->on_disk_key.k_objectid);
- }
- put_ih_version( ih, version );
- set_le_ih_k_offset (ih, offset);
- set_le_ih_k_type (ih, type);
- put_ih_item_len( ih, length );
- /* set_ih_free_space (ih, 0);*/
- // for directory items it is entry count, for directs and stat
- // datas - 0xffff, for indirects - 0
- put_ih_entry_count( ih, entry_count );
+ if (key) {
+ ih->ih_key.k_dir_id = cpu_to_le32(key->on_disk_key.k_dir_id);
+ ih->ih_key.k_objectid =
+ cpu_to_le32(key->on_disk_key.k_objectid);
+ }
+ put_ih_version(ih, version);
+ set_le_ih_k_offset(ih, offset);
+ set_le_ih_k_type(ih, type);
+ put_ih_item_len(ih, length);
+ /* set_ih_free_space (ih, 0); */
+ // for directory items it is entry count, for directs and stat
+ // datas - 0xffff, for indirects - 0
+ put_ih_entry_count(ih, entry_count);
}
//
@@ -153,84 +155,84 @@ inline void make_le_item_head (struct item_head * ih, const struct cpu_key * key
** to be unmapped, so that block_prepare_write will correctly call
** reiserfs_get_block to convert the tail into an unformatted node
*/
-static inline void fix_tail_page_for_writing(struct page *page) {
- struct buffer_head *head, *next, *bh ;
-
- if (page && page_has_buffers(page)) {
- head = page_buffers(page) ;
- bh = head ;
- do {
- next = bh->b_this_page ;
- if (buffer_mapped(bh) && bh->b_blocknr == 0) {
- reiserfs_unmap_buffer(bh) ;
- }
- bh = next ;
- } while (bh != head) ;
- }
+static inline void fix_tail_page_for_writing(struct page *page)
+{
+ struct buffer_head *head, *next, *bh;
+
+ if (page && page_has_buffers(page)) {
+ head = page_buffers(page);
+ bh = head;
+ do {
+ next = bh->b_this_page;
+ if (buffer_mapped(bh) && bh->b_blocknr == 0) {
+ reiserfs_unmap_buffer(bh);
+ }
+ bh = next;
+ } while (bh != head);
+ }
}
/* reiserfs_get_block does not need to allocate a block only if it has been
done already or non-hole position has been found in the indirect item */
-static inline int allocation_needed (int retval, b_blocknr_t allocated,
- struct item_head * ih,
- __le32 * item, int pos_in_item)
+static inline int allocation_needed(int retval, b_blocknr_t allocated,
+ struct item_head *ih,
+ __le32 * item, int pos_in_item)
{
- if (allocated)
- return 0;
- if (retval == POSITION_FOUND && is_indirect_le_ih (ih) &&
- get_block_num(item, pos_in_item))
- return 0;
- return 1;
+ if (allocated)
+ return 0;
+ if (retval == POSITION_FOUND && is_indirect_le_ih(ih) &&
+ get_block_num(item, pos_in_item))
+ return 0;
+ return 1;
}
-static inline int indirect_item_found (int retval, struct item_head * ih)
+static inline int indirect_item_found(int retval, struct item_head *ih)
{
- return (retval == POSITION_FOUND) && is_indirect_le_ih (ih);
+ return (retval == POSITION_FOUND) && is_indirect_le_ih(ih);
}
-
-static inline void set_block_dev_mapped (struct buffer_head * bh,
- b_blocknr_t block, struct inode * inode)
+static inline void set_block_dev_mapped(struct buffer_head *bh,
+ b_blocknr_t block, struct inode *inode)
{
map_bh(bh, inode->i_sb, block);
}
-
//
// files which were created in the earlier version can not be longer,
// than 2 gb
//
-static int file_capable (struct inode * inode, long block)
+static int file_capable(struct inode *inode, long block)
{
- if (get_inode_item_key_version (inode) != KEY_FORMAT_3_5 || // it is new file.
- block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb
- return 1;
+ if (get_inode_item_key_version(inode) != KEY_FORMAT_3_5 || // it is new file.
+ block < (1 << (31 - inode->i_sb->s_blocksize_bits))) // old file, but 'block' is inside of 2gb
+ return 1;
- return 0;
+ return 0;
}
/*static*/ int restart_transaction(struct reiserfs_transaction_handle *th,
- struct inode *inode, struct path *path) {
- struct super_block *s = th->t_super ;
- int len = th->t_blocks_allocated ;
- int err;
-
- BUG_ON (!th->t_trans_id);
- BUG_ON (!th->t_refcount);
-
- /* we cannot restart while nested */
- if (th->t_refcount > 1) {
- return 0 ;
- }
- pathrelse(path) ;
- reiserfs_update_sd(th, inode) ;
- err = journal_end(th, s, len) ;
- if (!err) {
- err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6) ;
- if (!err)
- reiserfs_update_inode_transaction(inode) ;
- }
- return err;
+ struct inode *inode, struct path *path)
+{
+ struct super_block *s = th->t_super;
+ int len = th->t_blocks_allocated;
+ int err;
+
+ BUG_ON(!th->t_trans_id);
+ BUG_ON(!th->t_refcount);
+
+ /* we cannot restart while nested */
+ if (th->t_refcount > 1) {
+ return 0;
+ }
+ pathrelse(path);
+ reiserfs_update_sd(th, inode);
+ err = journal_end(th, s, len);
+ if (!err) {
+ err = journal_begin(th, s, JOURNAL_PER_BALANCE_CNT * 6);
+ if (!err)
+ reiserfs_update_inode_transaction(inode);
+ }
+ return err;
}
// it is called by get_block when create == 0. Returns block number
@@ -241,181 +243,192 @@ static int file_capable (struct inode * inode, long block)
// Please improve the english/clarity in the comment above, as it is
// hard to understand.
-static int _get_block_create_0 (struct inode * inode, long block,
- struct buffer_head * bh_result,
- int args)
+static int _get_block_create_0(struct inode *inode, long block,
+ struct buffer_head *bh_result, int args)
{
- INITIALIZE_PATH (path);
- struct cpu_key key;
- struct buffer_head * bh;
- struct item_head * ih, tmp_ih;
- int fs_gen ;
- int blocknr;
- char * p = NULL;
- int chars;
- int ret ;
- int done = 0 ;
- unsigned long offset ;
-
- // prepare the key to look for the 'block'-th block of file
- make_cpu_key (&key, inode,
- (loff_t)block * inode->i_sb->s_blocksize + 1, TYPE_ANY, 3);
-
-research:
- if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND) {
- pathrelse (&path);
- if (p)
- kunmap(bh_result->b_page) ;
- // We do not return -ENOENT if there is a hole but page is uptodate, because it means
- // That there is some MMAPED data associated with it that is yet to be written to disk.
- if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) {
- return -ENOENT ;
- }
- return 0 ;
- }
-
- //
- bh = get_last_bh (&path);
- ih = get_ih (&path);
- if (is_indirect_le_ih (ih)) {
- __le32 * ind_item = (__le32 *)B_I_PITEM (bh, ih);
-
- /* FIXME: here we could cache indirect item or part of it in
- the inode to avoid search_by_key in case of subsequent
- access to file */
- blocknr = get_block_num(ind_item, path.pos_in_item) ;
- ret = 0 ;
- if (blocknr) {
- map_bh(bh_result, inode->i_sb, blocknr);
- if (path.pos_in_item == ((ih_item_len(ih) / UNFM_P_SIZE) - 1)) {
- set_buffer_boundary(bh_result);
- }
- } else
- // We do not return -ENOENT if there is a hole but page is uptodate, because it means
- // That there is some MMAPED data associated with it that is yet to be written to disk.
- if ((args & GET_BLOCK_NO_HOLE) && !PageUptodate(bh_result->b_page) ) {
- ret = -ENOENT ;
- }
-
- pathrelse (&path);
- if (p)
- kunmap(bh_result->b_page) ;
- return ret ;
- }
-
- // requested data are in direct item(s)
- if (!(args & GET_BLOCK_READ_DIRECT)) {
- // we are called by bmap. FIXME: we can not map block of file
- // when it is stored in direct item(s)
- pathrelse (&path);
- if (p)
- kunmap(bh_result->b_page) ;
- return -ENOENT;
- }
-
- /* if we've got a direct item, and the buffer or page was uptodate,
- ** we don't want to pull data off disk again. skip to the
- ** end, where we map the buffer and return
- */
- if (buffer_uptodate(bh_result)) {
- goto finished ;
- } else
- /*
- ** grab_tail_page can trigger calls to reiserfs_get_block on up to date
- ** pages without any buffers. If the page is up to date, we don't want
- ** read old data off disk. Set the up to date bit on the buffer instead
- ** and jump to the end
- */
- if (!bh_result->b_page || PageUptodate(bh_result->b_page)) {
+ INITIALIZE_PATH(path);
+ struct cpu_key key;
+ struct buffer_head *bh;
+ struct item_head *ih, tmp_ih;
+ int fs_gen;
+ int blocknr;
+ char *p = NULL;
+ int chars;
+ int ret;
+ int result;
+ int done = 0;
+ unsigned long offset;
+
+ // prepare the key to look for the 'block'-th block of file
+ make_cpu_key(&key, inode,
+ (loff_t) block * inode->i_sb->s_blocksize + 1, TYPE_ANY,
+ 3);
+
+ research:
+ result = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (result != POSITION_FOUND) {
+ pathrelse(&path);
+ if (p)
+ kunmap(bh_result->b_page);
+ if (result == IO_ERROR)
+ return -EIO;
+ // We do not return -ENOENT if there is a hole but page is uptodate, because it means
+ // That there is some MMAPED data associated with it that is yet to be written to disk.
+ if ((args & GET_BLOCK_NO_HOLE)
+ && !PageUptodate(bh_result->b_page)) {
+ return -ENOENT;
+ }
+ return 0;
+ }
+ //
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ if (is_indirect_le_ih(ih)) {
+ __le32 *ind_item = (__le32 *) B_I_PITEM(bh, ih);
+
+ /* FIXME: here we could cache indirect item or part of it in
+ the inode to avoid search_by_key in case of subsequent
+ access to file */
+ blocknr = get_block_num(ind_item, path.pos_in_item);
+ ret = 0;
+ if (blocknr) {
+ map_bh(bh_result, inode->i_sb, blocknr);
+ if (path.pos_in_item ==
+ ((ih_item_len(ih) / UNFM_P_SIZE) - 1)) {
+ set_buffer_boundary(bh_result);
+ }
+ } else
+ // We do not return -ENOENT if there is a hole but page is uptodate, because it means
+ // That there is some MMAPED data associated with it that is yet to be written to disk.
+ if ((args & GET_BLOCK_NO_HOLE)
+ && !PageUptodate(bh_result->b_page)) {
+ ret = -ENOENT;
+ }
+
+ pathrelse(&path);
+ if (p)
+ kunmap(bh_result->b_page);
+ return ret;
+ }
+ // requested data are in direct item(s)
+ if (!(args & GET_BLOCK_READ_DIRECT)) {
+ // we are called by bmap. FIXME: we can not map block of file
+ // when it is stored in direct item(s)
+ pathrelse(&path);
+ if (p)
+ kunmap(bh_result->b_page);
+ return -ENOENT;
+ }
+
+ /* if we've got a direct item, and the buffer or page was uptodate,
+ ** we don't want to pull data off disk again. skip to the
+ ** end, where we map the buffer and return
+ */
+ if (buffer_uptodate(bh_result)) {
+ goto finished;
+ } else
+ /*
+ ** grab_tail_page can trigger calls to reiserfs_get_block on up to date
+ ** pages without any buffers. If the page is up to date, we don't want
+ ** read old data off disk. Set the up to date bit on the buffer instead
+ ** and jump to the end
+ */
+ if (!bh_result->b_page || PageUptodate(bh_result->b_page)) {
set_buffer_uptodate(bh_result);
- goto finished ;
- }
-
- // read file tail into part of page
- offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1) ;
- fs_gen = get_generation(inode->i_sb) ;
- copy_item_head (&tmp_ih, ih);
-
- /* we only want to kmap if we are reading the tail into the page.
- ** this is not the common case, so we don't kmap until we are
- ** sure we need to. But, this means the item might move if
- ** kmap schedules
- */
- if (!p) {
- p = (char *)kmap(bh_result->b_page) ;
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- goto research;
- }
- }
- p += offset ;
- memset (p, 0, inode->i_sb->s_blocksize);
- do {
- if (!is_direct_le_ih (ih)) {
- BUG ();
- }
- /* make sure we don't read more bytes than actually exist in
- ** the file. This can happen in odd cases where i_size isn't
- ** correct, and when direct item padding results in a few
- ** extra bytes at the end of the direct item
- */
- if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size)
- break ;
- if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) {
- chars = inode->i_size - (le_ih_k_offset(ih) - 1) - path.pos_in_item;
- done = 1 ;
- } else {
- chars = ih_item_len(ih) - path.pos_in_item;
- }
- memcpy (p, B_I_PITEM (bh, ih) + path.pos_in_item, chars);
-
- if (done)
- break ;
-
- p += chars;
-
- if (PATH_LAST_POSITION (&path) != (B_NR_ITEMS (bh) - 1))
- // we done, if read direct item is not the last item of
- // node FIXME: we could try to check right delimiting key
- // to see whether direct item continues in the right
- // neighbor or rely on i_size
- break;
-
- // update key to look for the next piece
- set_cpu_key_k_offset (&key, cpu_key_k_offset (&key) + chars);
- if (search_for_position_by_key (inode->i_sb, &key, &path) != POSITION_FOUND)
- // we read something from tail, even if now we got IO_ERROR
- break;
- bh = get_last_bh (&path);
- ih = get_ih (&path);
- } while (1);
-
- flush_dcache_page(bh_result->b_page) ;
- kunmap(bh_result->b_page) ;
-
-finished:
- pathrelse (&path);
- /* this buffer has valid data, but isn't valid for io. mapping it to
- * block #0 tells the rest of reiserfs it just has a tail in it
- */
- map_bh(bh_result, inode->i_sb, 0);
- set_buffer_uptodate (bh_result);
- return 0;
-}
+ goto finished;
+ }
+ // read file tail into part of page
+ offset = (cpu_key_k_offset(&key) - 1) & (PAGE_CACHE_SIZE - 1);
+ fs_gen = get_generation(inode->i_sb);
+ copy_item_head(&tmp_ih, ih);
+
+ /* we only want to kmap if we are reading the tail into the page.
+ ** this is not the common case, so we don't kmap until we are
+ ** sure we need to. But, this means the item might move if
+ ** kmap schedules
+ */
+ if (!p) {
+ p = (char *)kmap(bh_result->b_page);
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ goto research;
+ }
+ }
+ p += offset;
+ memset(p, 0, inode->i_sb->s_blocksize);
+ do {
+ if (!is_direct_le_ih(ih)) {
+ BUG();
+ }
+ /* make sure we don't read more bytes than actually exist in
+ ** the file. This can happen in odd cases where i_size isn't
+ ** correct, and when direct item padding results in a few
+ ** extra bytes at the end of the direct item
+ */
+ if ((le_ih_k_offset(ih) + path.pos_in_item) > inode->i_size)
+ break;
+ if ((le_ih_k_offset(ih) - 1 + ih_item_len(ih)) > inode->i_size) {
+ chars =
+ inode->i_size - (le_ih_k_offset(ih) - 1) -
+ path.pos_in_item;
+ done = 1;
+ } else {
+ chars = ih_item_len(ih) - path.pos_in_item;
+ }
+ memcpy(p, B_I_PITEM(bh, ih) + path.pos_in_item, chars);
+
+ if (done)
+ break;
+
+ p += chars;
+ if (PATH_LAST_POSITION(&path) != (B_NR_ITEMS(bh) - 1))
+ // we done, if read direct item is not the last item of
+ // node FIXME: we could try to check right delimiting key
+ // to see whether direct item continues in the right
+ // neighbor or rely on i_size
+ break;
+
+ // update key to look for the next piece
+ set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + chars);
+ result = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (result != POSITION_FOUND)
+ // i/o error most likely
+ break;
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ } while (1);
+
+ flush_dcache_page(bh_result->b_page);
+ kunmap(bh_result->b_page);
+
+ finished:
+ pathrelse(&path);
+
+ if (result == IO_ERROR)
+ return -EIO;
+
+ /* this buffer has valid data, but isn't valid for io. mapping it to
+ * block #0 tells the rest of reiserfs it just has a tail in it
+ */
+ map_bh(bh_result, inode->i_sb, 0);
+ set_buffer_uptodate(bh_result);
+ return 0;
+}
// this is called to create file map. So, _get_block_create_0 will not
// read direct item
-static int reiserfs_bmap (struct inode * inode, sector_t block,
- struct buffer_head * bh_result, int create)
+static int reiserfs_bmap(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
{
- if (!file_capable (inode, block))
- return -EFBIG;
-
- reiserfs_write_lock(inode->i_sb);
- /* do not read the direct item */
- _get_block_create_0 (inode, block, bh_result, 0) ;
- reiserfs_write_unlock(inode->i_sb);
- return 0;
+ if (!file_capable(inode, block))
+ return -EFBIG;
+
+ reiserfs_write_lock(inode->i_sb);
+ /* do not read the direct item */
+ _get_block_create_0(inode, block, bh_result, 0);
+ reiserfs_write_unlock(inode->i_sb);
+ return 0;
}
/* special version of get_block that is only used by grab_tail_page right
@@ -435,9 +448,11 @@ static int reiserfs_bmap (struct inode * inode, sector_t block,
** don't want to send create == GET_BLOCK_NO_HOLE to reiserfs_get_block,
** don't use this function.
*/
-static int reiserfs_get_block_create_0 (struct inode * inode, sector_t block,
- struct buffer_head * bh_result, int create) {
- return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE) ;
+static int reiserfs_get_block_create_0(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result,
+ int create)
+{
+ return reiserfs_get_block(inode, block, bh_result, GET_BLOCK_NO_HOLE);
}
/* This is special helper for reiserfs_get_block in case we are executing
@@ -448,43 +463,42 @@ static int reiserfs_get_blocks_direct_io(struct inode *inode,
struct buffer_head *bh_result,
int create)
{
- int ret ;
-
- bh_result->b_page = NULL;
-
- /* We set the b_size before reiserfs_get_block call since it is
- referenced in convert_tail_for_hole() that may be called from
- reiserfs_get_block() */
- bh_result->b_size = (1 << inode->i_blkbits);
-
- ret = reiserfs_get_block(inode, iblock, bh_result,
- create | GET_BLOCK_NO_DANGLE) ;
- if (ret)
- goto out;
-
- /* don't allow direct io onto tail pages */
- if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
- /* make sure future calls to the direct io funcs for this offset
- ** in the file fail by unmapping the buffer
- */
- clear_buffer_mapped(bh_result);
- ret = -EINVAL ;
- }
- /* Possible unpacked tail. Flush the data before pages have
- disappeared */
- if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
- int err;
- lock_kernel();
- err = reiserfs_commit_for_inode(inode);
- REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
- unlock_kernel();
- if (err < 0)
- ret = err;
- }
-out:
- return ret ;
-}
+ int ret;
+
+ bh_result->b_page = NULL;
+
+ /* We set the b_size before reiserfs_get_block call since it is
+ referenced in convert_tail_for_hole() that may be called from
+ reiserfs_get_block() */
+ bh_result->b_size = (1 << inode->i_blkbits);
+
+ ret = reiserfs_get_block(inode, iblock, bh_result,
+ create | GET_BLOCK_NO_DANGLE);
+ if (ret)
+ goto out;
+ /* don't allow direct io onto tail pages */
+ if (buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
+ /* make sure future calls to the direct io funcs for this offset
+ ** in the file fail by unmapping the buffer
+ */
+ clear_buffer_mapped(bh_result);
+ ret = -EINVAL;
+ }
+ /* Possible unpacked tail. Flush the data before pages have
+ disappeared */
+ if (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) {
+ int err;
+ lock_kernel();
+ err = reiserfs_commit_for_inode(inode);
+ REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
+ unlock_kernel();
+ if (err < 0)
+ ret = err;
+ }
+ out:
+ return ret;
+}
/*
** helper function for when reiserfs_get_block is called for a hole
@@ -496,490 +510,547 @@ out:
** you should not be in a transaction, or have any paths held when you
** call this.
*/
-static int convert_tail_for_hole(struct inode *inode,
- struct buffer_head *bh_result,
- loff_t tail_offset) {
- unsigned long index ;
- unsigned long tail_end ;
- unsigned long tail_start ;
- struct page * tail_page ;
- struct page * hole_page = bh_result->b_page ;
- int retval = 0 ;
-
- if ((tail_offset & (bh_result->b_size - 1)) != 1)
- return -EIO ;
-
- /* always try to read until the end of the block */
- tail_start = tail_offset & (PAGE_CACHE_SIZE - 1) ;
- tail_end = (tail_start | (bh_result->b_size - 1)) + 1 ;
-
- index = tail_offset >> PAGE_CACHE_SHIFT ;
- /* hole_page can be zero in case of direct_io, we are sure
- that we cannot get here if we write with O_DIRECT into
- tail page */
- if (!hole_page || index != hole_page->index) {
- tail_page = grab_cache_page(inode->i_mapping, index) ;
- retval = -ENOMEM;
- if (!tail_page) {
- goto out ;
- }
- } else {
- tail_page = hole_page ;
- }
-
- /* we don't have to make sure the conversion did not happen while
- ** we were locking the page because anyone that could convert
- ** must first take i_sem.
- **
- ** We must fix the tail page for writing because it might have buffers
- ** that are mapped, but have a block number of 0. This indicates tail
- ** data that has been read directly into the page, and block_prepare_write
- ** won't trigger a get_block in this case.
- */
- fix_tail_page_for_writing(tail_page) ;
- retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end);
- if (retval)
- goto unlock ;
-
- /* tail conversion might change the data in the page */
- flush_dcache_page(tail_page) ;
-
- retval = reiserfs_commit_write(NULL, tail_page, tail_start, tail_end) ;
-
-unlock:
- if (tail_page != hole_page) {
- unlock_page(tail_page) ;
- page_cache_release(tail_page) ;
- }
-out:
- return retval ;
+static int convert_tail_for_hole(struct inode *inode,
+ struct buffer_head *bh_result,
+ loff_t tail_offset)
+{
+ unsigned long index;
+ unsigned long tail_end;
+ unsigned long tail_start;
+ struct page *tail_page;
+ struct page *hole_page = bh_result->b_page;
+ int retval = 0;
+
+ if ((tail_offset & (bh_result->b_size - 1)) != 1)
+ return -EIO;
+
+ /* always try to read until the end of the block */
+ tail_start = tail_offset & (PAGE_CACHE_SIZE - 1);
+ tail_end = (tail_start | (bh_result->b_size - 1)) + 1;
+
+ index = tail_offset >> PAGE_CACHE_SHIFT;
+ /* hole_page can be zero in case of direct_io, we are sure
+ that we cannot get here if we write with O_DIRECT into
+ tail page */
+ if (!hole_page || index != hole_page->index) {
+ tail_page = grab_cache_page(inode->i_mapping, index);
+ retval = -ENOMEM;
+ if (!tail_page) {
+ goto out;
+ }
+ } else {
+ tail_page = hole_page;
+ }
+
+ /* we don't have to make sure the conversion did not happen while
+ ** we were locking the page because anyone that could convert
+ ** must first take i_sem.
+ **
+ ** We must fix the tail page for writing because it might have buffers
+ ** that are mapped, but have a block number of 0. This indicates tail
+ ** data that has been read directly into the page, and block_prepare_write
+ ** won't trigger a get_block in this case.
+ */
+ fix_tail_page_for_writing(tail_page);
+ retval = reiserfs_prepare_write(NULL, tail_page, tail_start, tail_end);
+ if (retval)
+ goto unlock;
+
+ /* tail conversion might change the data in the page */
+ flush_dcache_page(tail_page);
+
+ retval = reiserfs_commit_write(NULL, tail_page, tail_start, tail_end);
+
+ unlock:
+ if (tail_page != hole_page) {
+ unlock_page(tail_page);
+ page_cache_release(tail_page);
+ }
+ out:
+ return retval;
}
static inline int _allocate_block(struct reiserfs_transaction_handle *th,
- long block,
- struct inode *inode,
- b_blocknr_t *allocated_block_nr,
- struct path * path,
- int flags) {
- BUG_ON (!th->t_trans_id);
-
+ long block,
+ struct inode *inode,
+ b_blocknr_t * allocated_block_nr,
+ struct path *path, int flags)
+{
+ BUG_ON(!th->t_trans_id);
+
#ifdef REISERFS_PREALLOCATE
- if (!(flags & GET_BLOCK_NO_ISEM)) {
- return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr, path, block);
- }
+ if (!(flags & GET_BLOCK_NO_ISEM)) {
+ return reiserfs_new_unf_blocknrs2(th, inode, allocated_block_nr,
+ path, block);
+ }
#endif
- return reiserfs_new_unf_blocknrs (th, inode, allocated_block_nr, path, block);
+ return reiserfs_new_unf_blocknrs(th, inode, allocated_block_nr, path,
+ block);
}
-int reiserfs_get_block (struct inode * inode, sector_t block,
- struct buffer_head * bh_result, int create)
+int reiserfs_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create)
{
- int repeat, retval = 0;
- b_blocknr_t allocated_block_nr = 0;// b_blocknr_t is (unsigned) 32 bit int
- INITIALIZE_PATH(path);
- int pos_in_item;
- struct cpu_key key;
- struct buffer_head * bh, * unbh = NULL;
- struct item_head * ih, tmp_ih;
- __le32 * item;
- int done;
- int fs_gen;
- struct reiserfs_transaction_handle *th = NULL;
- /* space reserved in transaction batch:
- . 3 balancings in direct->indirect conversion
- . 1 block involved into reiserfs_update_sd()
- XXX in practically impossible worst case direct2indirect()
- can incur (much) more than 3 balancings.
- quota update for user, group */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 1 + 2 * REISERFS_QUOTA_TRANS_BLOCKS;
- int version;
- int dangle = 1;
- loff_t new_offset = (((loff_t)block) << inode->i_sb->s_blocksize_bits) + 1 ;
-
- /* bad.... */
- reiserfs_write_lock(inode->i_sb);
- version = get_inode_item_key_version (inode);
-
- if (block < 0) {
- reiserfs_write_unlock(inode->i_sb);
- return -EIO;
- }
+ int repeat, retval = 0;
+ b_blocknr_t allocated_block_nr = 0; // b_blocknr_t is (unsigned) 32 bit int
+ INITIALIZE_PATH(path);
+ int pos_in_item;
+ struct cpu_key key;
+ struct buffer_head *bh, *unbh = NULL;
+ struct item_head *ih, tmp_ih;
+ __le32 *item;
+ int done;
+ int fs_gen;
+ struct reiserfs_transaction_handle *th = NULL;
+ /* space reserved in transaction batch:
+ . 3 balancings in direct->indirect conversion
+ . 1 block involved into reiserfs_update_sd()
+ XXX in practically impossible worst case direct2indirect()
+ can incur (much) more than 3 balancings.
+ quota update for user, group */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 + 1 +
+ 2 * REISERFS_QUOTA_TRANS_BLOCKS(inode->i_sb);
+ int version;
+ int dangle = 1;
+ loff_t new_offset =
+ (((loff_t) block) << inode->i_sb->s_blocksize_bits) + 1;
+
+ /* bad.... */
+ reiserfs_write_lock(inode->i_sb);
+ version = get_inode_item_key_version(inode);
- if (!file_capable (inode, block)) {
- reiserfs_write_unlock(inode->i_sb);
- return -EFBIG;
- }
-
- /* if !create, we aren't changing the FS, so we don't need to
- ** log anything, so we don't need to start a transaction
- */
- if (!(create & GET_BLOCK_CREATE)) {
- int ret ;
- /* find number of block-th logical block of the file */
- ret = _get_block_create_0 (inode, block, bh_result,
- create | GET_BLOCK_READ_DIRECT) ;
- reiserfs_write_unlock(inode->i_sb);
- return ret;
- }
- /*
- * if we're already in a transaction, make sure to close
- * any new transactions we start in this func
- */
- if ((create & GET_BLOCK_NO_DANGLE) ||
- reiserfs_transaction_running(inode->i_sb))
- dangle = 0;
-
- /* If file is of such a size, that it might have a tail and tails are enabled
- ** we should mark it as possibly needing tail packing on close
- */
- if ( (have_large_tails (inode->i_sb) && inode->i_size < i_block_size (inode)*4) ||
- (have_small_tails (inode->i_sb) && inode->i_size < i_block_size(inode)) )
- REISERFS_I(inode)->i_flags |= i_pack_on_close_mask ;
-
- /* set the key of the first byte in the 'block'-th block of file */
- make_cpu_key (&key, inode, new_offset,
- TYPE_ANY, 3/*key length*/);
- if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) {
-start_trans:
- th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count);
- if (!th) {
- retval = -ENOMEM;
- goto failure;
- }
- reiserfs_update_inode_transaction(inode) ;
- }
- research:
-
- retval = search_for_position_by_key (inode->i_sb, &key, &path);
- if (retval == IO_ERROR) {
- retval = -EIO;
- goto failure;
- }
-
- bh = get_last_bh (&path);
- ih = get_ih (&path);
- item = get_item (&path);
- pos_in_item = path.pos_in_item;
-
- fs_gen = get_generation (inode->i_sb);
- copy_item_head (&tmp_ih, ih);
-
- if (allocation_needed (retval, allocated_block_nr, ih, item, pos_in_item)) {
- /* we have to allocate block for the unformatted node */
- if (!th) {
- pathrelse(&path) ;
- goto start_trans;
- }
-
- repeat = _allocate_block(th, block, inode, &allocated_block_nr, &path, create);
-
- if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) {
- /* restart the transaction to give the journal a chance to free
- ** some blocks. releases the path, so we have to go back to
- ** research if we succeed on the second try
- */
- SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1;
- retval = restart_transaction(th, inode, &path) ;
- if (retval)
- goto failure;
- repeat = _allocate_block(th, block, inode, &allocated_block_nr, NULL, create);
-
- if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
- goto research ;
- }
- if (repeat == QUOTA_EXCEEDED)
- retval = -EDQUOT;
- else
- retval = -ENOSPC;
- goto failure;
- }
-
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- goto research;
- }
- }
-
- if (indirect_item_found (retval, ih)) {
- b_blocknr_t unfm_ptr;
- /* 'block'-th block is in the file already (there is
- corresponding cell in some indirect item). But it may be
- zero unformatted node pointer (hole) */
- unfm_ptr = get_block_num (item, pos_in_item);
- if (unfm_ptr == 0) {
- /* use allocated block to plug the hole */
- reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ;
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- reiserfs_restore_prepared_buffer(inode->i_sb, bh) ;
- goto research;
- }
- set_buffer_new(bh_result);
- if (buffer_dirty(bh_result) && reiserfs_data_ordered(inode->i_sb))
- reiserfs_add_ordered_list(inode, bh_result);
- put_block_num(item, pos_in_item, allocated_block_nr) ;
- unfm_ptr = allocated_block_nr;
- journal_mark_dirty (th, inode->i_sb, bh);
- reiserfs_update_sd(th, inode) ;
- }
- set_block_dev_mapped(bh_result, unfm_ptr, inode);
- pathrelse (&path);
- retval = 0;
- if (!dangle && th)
- retval = reiserfs_end_persistent_transaction(th);
+ if (block < 0) {
+ reiserfs_write_unlock(inode->i_sb);
+ return -EIO;
+ }
- reiserfs_write_unlock(inode->i_sb);
-
- /* the item was found, so new blocks were not added to the file
- ** there is no need to make sure the inode is updated with this
- ** transaction
- */
- return retval;
- }
-
- if (!th) {
- pathrelse(&path) ;
- goto start_trans;
- }
-
- /* desired position is not found or is in the direct item. We have
- to append file with holes up to 'block'-th block converting
- direct items to indirect one if necessary */
- done = 0;
- do {
- if (is_statdata_le_ih (ih)) {
- __le32 unp = 0;
- struct cpu_key tmp_key;
-
- /* indirect item has to be inserted */
- make_le_item_head (&tmp_ih, &key, version, 1, TYPE_INDIRECT,
- UNFM_P_SIZE, 0/* free_space */);
-
- if (cpu_key_k_offset (&key) == 1) {
- /* we are going to add 'block'-th block to the file. Use
- allocated block for that */
- unp = cpu_to_le32 (allocated_block_nr);
- set_block_dev_mapped (bh_result, allocated_block_nr, inode);
- set_buffer_new(bh_result);
- done = 1;
- }
- tmp_key = key; // ;)
- set_cpu_key_k_offset (&tmp_key, 1);
- PATH_LAST_POSITION(&path) ++;
-
- retval = reiserfs_insert_item (th, &path, &tmp_key, &tmp_ih, inode, (char *)&unp);
- if (retval) {
- reiserfs_free_block (th, inode, allocated_block_nr, 1);
- goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST
- }
- //mark_tail_converted (inode);
- } else if (is_direct_le_ih (ih)) {
- /* direct item has to be converted */
- loff_t tail_offset;
-
- tail_offset = ((le_ih_k_offset (ih) - 1) & ~(inode->i_sb->s_blocksize - 1)) + 1;
- if (tail_offset == cpu_key_k_offset (&key)) {
- /* direct item we just found fits into block we have
- to map. Convert it into unformatted node: use
- bh_result for the conversion */
- set_block_dev_mapped (bh_result, allocated_block_nr, inode);
- unbh = bh_result;
- done = 1;
- } else {
- /* we have to padd file tail stored in direct item(s)
- up to block size and convert it to unformatted
- node. FIXME: this should also get into page cache */
-
- pathrelse(&path) ;
- /*
- * ugly, but we can only end the transaction if
- * we aren't nested
- */
- BUG_ON (!th->t_refcount);
- if (th->t_refcount == 1) {
- retval = reiserfs_end_persistent_transaction(th);
- th = NULL;
- if (retval)
+ if (!file_capable(inode, block)) {
+ reiserfs_write_unlock(inode->i_sb);
+ return -EFBIG;
+ }
+
+ /* if !create, we aren't changing the FS, so we don't need to
+ ** log anything, so we don't need to start a transaction
+ */
+ if (!(create & GET_BLOCK_CREATE)) {
+ int ret;
+ /* find number of block-th logical block of the file */
+ ret = _get_block_create_0(inode, block, bh_result,
+ create | GET_BLOCK_READ_DIRECT);
+ reiserfs_write_unlock(inode->i_sb);
+ return ret;
+ }
+ /*
+ * if we're already in a transaction, make sure to close
+ * any new transactions we start in this func
+ */
+ if ((create & GET_BLOCK_NO_DANGLE) ||
+ reiserfs_transaction_running(inode->i_sb))
+ dangle = 0;
+
+ /* If file is of such a size, that it might have a tail and tails are enabled
+ ** we should mark it as possibly needing tail packing on close
+ */
+ if ((have_large_tails(inode->i_sb)
+ && inode->i_size < i_block_size(inode) * 4)
+ || (have_small_tails(inode->i_sb)
+ && inode->i_size < i_block_size(inode)))
+ REISERFS_I(inode)->i_flags |= i_pack_on_close_mask;
+
+ /* set the key of the first byte in the 'block'-th block of file */
+ make_cpu_key(&key, inode, new_offset, TYPE_ANY, 3 /*key length */ );
+ if ((new_offset + inode->i_sb->s_blocksize - 1) > inode->i_size) {
+ start_trans:
+ th = reiserfs_persistent_transaction(inode->i_sb, jbegin_count);
+ if (!th) {
+ retval = -ENOMEM;
goto failure;
}
+ reiserfs_update_inode_transaction(inode);
+ }
+ research:
- retval = convert_tail_for_hole(inode, bh_result, tail_offset) ;
- if (retval) {
- if ( retval != -ENOSPC )
- reiserfs_warning (inode->i_sb, "clm-6004: convert tail failed inode %lu, error %d", inode->i_ino, retval) ;
- if (allocated_block_nr) {
- /* the bitmap, the super, and the stat data == 3 */
- if (!th)
- th = reiserfs_persistent_transaction(inode->i_sb,3);
- if (th)
- reiserfs_free_block (th,inode,allocated_block_nr,1);
- }
- goto failure ;
- }
- goto research ;
- }
- retval = direct2indirect (th, inode, &path, unbh, tail_offset);
- if (retval) {
- reiserfs_unmap_buffer(unbh);
- reiserfs_free_block (th, inode, allocated_block_nr, 1);
- goto failure;
- }
- /* it is important the set_buffer_uptodate is done after
- ** the direct2indirect. The buffer might contain valid
- ** data newer than the data on disk (read by readpage, changed,
- ** and then sent here by writepage). direct2indirect needs
- ** to know if unbh was already up to date, so it can decide
- ** if the data in unbh needs to be replaced with data from
- ** the disk
- */
- set_buffer_uptodate (unbh);
-
- /* unbh->b_page == NULL in case of DIRECT_IO request, this means
- buffer will disappear shortly, so it should not be added to
- */
- if ( unbh->b_page ) {
- /* we've converted the tail, so we must
- ** flush unbh before the transaction commits
- */
- reiserfs_add_tail_list(inode, unbh) ;
-
- /* mark it dirty now to prevent commit_write from adding
- ** this buffer to the inode's dirty buffer list
- */
- /*
- * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty().
- * It's still atomic, but it sets the page dirty too,
- * which makes it eligible for writeback at any time by the
- * VM (which was also the case with __mark_buffer_dirty())
- */
- mark_buffer_dirty(unbh) ;
- }
- } else {
- /* append indirect item with holes if needed, when appending
- pointer to 'block'-th block use block, which is already
- allocated */
- struct cpu_key tmp_key;
- unp_t unf_single=0; // We use this in case we need to allocate only
- // one block which is a fastpath
- unp_t *un;
- __u64 max_to_insert=MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE;
- __u64 blocks_needed;
-
- RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE,
- "vs-804: invalid position for append");
- /* indirect item has to be appended, set up key of that position */
- make_cpu_key (&tmp_key, inode,
- le_key_k_offset (version, &(ih->ih_key)) + op_bytes_number (ih, inode->i_sb->s_blocksize),
- //pos_in_item * inode->i_sb->s_blocksize,
- TYPE_INDIRECT, 3);// key type is unimportant
-
- blocks_needed = 1 + ((cpu_key_k_offset (&key) - cpu_key_k_offset (&tmp_key)) >> inode->i_sb->s_blocksize_bits);
- RFALSE( blocks_needed < 0, "green-805: invalid offset");
-
- if ( blocks_needed == 1 ) {
- un = &unf_single;
- } else {
- un=kmalloc( min(blocks_needed,max_to_insert)*UNFM_P_SIZE,
- GFP_ATOMIC); // We need to avoid scheduling.
- if ( !un) {
- un = &unf_single;
- blocks_needed = 1;
- max_to_insert = 0;
- } else
- memset(un, 0, UNFM_P_SIZE * min(blocks_needed,max_to_insert));
- }
- if ( blocks_needed <= max_to_insert) {
- /* we are going to add target block to the file. Use allocated
- block for that */
- un[blocks_needed-1] = cpu_to_le32 (allocated_block_nr);
- set_block_dev_mapped (bh_result, allocated_block_nr, inode);
- set_buffer_new(bh_result);
- done = 1;
- } else {
- /* paste hole to the indirect item */
- /* If kmalloc failed, max_to_insert becomes zero and it means we
- only have space for one block */
- blocks_needed=max_to_insert?max_to_insert:1;
- }
- retval = reiserfs_paste_into_item (th, &path, &tmp_key, inode, (char *)un, UNFM_P_SIZE * blocks_needed);
-
- if (blocks_needed != 1)
- kfree(un);
-
- if (retval) {
- reiserfs_free_block (th, inode, allocated_block_nr, 1);
- goto failure;
- }
- if (!done) {
- /* We need to mark new file size in case this function will be
- interrupted/aborted later on. And we may do this only for
- holes. */
- inode->i_size += inode->i_sb->s_blocksize * blocks_needed;
- }
- }
-
- if (done == 1)
- break;
-
- /* this loop could log more blocks than we had originally asked
- ** for. So, we have to allow the transaction to end if it is
- ** too big or too full. Update the inode so things are
- ** consistent if we crash before the function returns
- **
- ** release the path so that anybody waiting on the path before
- ** ending their transaction will be able to continue.
- */
- if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
- retval = restart_transaction(th, inode, &path) ;
- if (retval)
- goto failure;
- }
- /* inserting indirect pointers for a hole can take a
- ** long time. reschedule if needed
- */
- cond_resched();
-
- retval = search_for_position_by_key (inode->i_sb, &key, &path);
+ retval = search_for_position_by_key(inode->i_sb, &key, &path);
if (retval == IO_ERROR) {
- retval = -EIO;
- goto failure;
- }
- if (retval == POSITION_FOUND) {
- reiserfs_warning (inode->i_sb, "vs-825: reiserfs_get_block: "
- "%K should not be found", &key);
- retval = -EEXIST;
- if (allocated_block_nr)
- reiserfs_free_block (th, inode, allocated_block_nr, 1);
- pathrelse(&path) ;
- goto failure;
- }
- bh = get_last_bh (&path);
- ih = get_ih (&path);
- item = get_item (&path);
+ retval = -EIO;
+ goto failure;
+ }
+
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
pos_in_item = path.pos_in_item;
- } while (1);
+ fs_gen = get_generation(inode->i_sb);
+ copy_item_head(&tmp_ih, ih);
+
+ if (allocation_needed
+ (retval, allocated_block_nr, ih, item, pos_in_item)) {
+ /* we have to allocate block for the unformatted node */
+ if (!th) {
+ pathrelse(&path);
+ goto start_trans;
+ }
+
+ repeat =
+ _allocate_block(th, block, inode, &allocated_block_nr,
+ &path, create);
+
+ if (repeat == NO_DISK_SPACE || repeat == QUOTA_EXCEEDED) {
+ /* restart the transaction to give the journal a chance to free
+ ** some blocks. releases the path, so we have to go back to
+ ** research if we succeed on the second try
+ */
+ SB_JOURNAL(inode->i_sb)->j_next_async_flush = 1;
+ retval = restart_transaction(th, inode, &path);
+ if (retval)
+ goto failure;
+ repeat =
+ _allocate_block(th, block, inode,
+ &allocated_block_nr, NULL, create);
+
+ if (repeat != NO_DISK_SPACE && repeat != QUOTA_EXCEEDED) {
+ goto research;
+ }
+ if (repeat == QUOTA_EXCEEDED)
+ retval = -EDQUOT;
+ else
+ retval = -ENOSPC;
+ goto failure;
+ }
+
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ goto research;
+ }
+ }
+
+ if (indirect_item_found(retval, ih)) {
+ b_blocknr_t unfm_ptr;
+ /* 'block'-th block is in the file already (there is
+ corresponding cell in some indirect item). But it may be
+ zero unformatted node pointer (hole) */
+ unfm_ptr = get_block_num(item, pos_in_item);
+ if (unfm_ptr == 0) {
+ /* use allocated block to plug the hole */
+ reiserfs_prepare_for_journal(inode->i_sb, bh, 1);
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ reiserfs_restore_prepared_buffer(inode->i_sb,
+ bh);
+ goto research;
+ }
+ set_buffer_new(bh_result);
+ if (buffer_dirty(bh_result)
+ && reiserfs_data_ordered(inode->i_sb))
+ reiserfs_add_ordered_list(inode, bh_result);
+ put_block_num(item, pos_in_item, allocated_block_nr);
+ unfm_ptr = allocated_block_nr;
+ journal_mark_dirty(th, inode->i_sb, bh);
+ reiserfs_update_sd(th, inode);
+ }
+ set_block_dev_mapped(bh_result, unfm_ptr, inode);
+ pathrelse(&path);
+ retval = 0;
+ if (!dangle && th)
+ retval = reiserfs_end_persistent_transaction(th);
+
+ reiserfs_write_unlock(inode->i_sb);
+
+ /* the item was found, so new blocks were not added to the file
+ ** there is no need to make sure the inode is updated with this
+ ** transaction
+ */
+ return retval;
+ }
+
+ if (!th) {
+ pathrelse(&path);
+ goto start_trans;
+ }
+
+ /* desired position is not found or is in the direct item. We have
+ to append file with holes up to 'block'-th block converting
+ direct items to indirect one if necessary */
+ done = 0;
+ do {
+ if (is_statdata_le_ih(ih)) {
+ __le32 unp = 0;
+ struct cpu_key tmp_key;
+
+ /* indirect item has to be inserted */
+ make_le_item_head(&tmp_ih, &key, version, 1,
+ TYPE_INDIRECT, UNFM_P_SIZE,
+ 0 /* free_space */ );
+
+ if (cpu_key_k_offset(&key) == 1) {
+ /* we are going to add 'block'-th block to the file. Use
+ allocated block for that */
+ unp = cpu_to_le32(allocated_block_nr);
+ set_block_dev_mapped(bh_result,
+ allocated_block_nr, inode);
+ set_buffer_new(bh_result);
+ done = 1;
+ }
+ tmp_key = key; // ;)
+ set_cpu_key_k_offset(&tmp_key, 1);
+ PATH_LAST_POSITION(&path)++;
+
+ retval =
+ reiserfs_insert_item(th, &path, &tmp_key, &tmp_ih,
+ inode, (char *)&unp);
+ if (retval) {
+ reiserfs_free_block(th, inode,
+ allocated_block_nr, 1);
+ goto failure; // retval == -ENOSPC, -EDQUOT or -EIO or -EEXIST
+ }
+ //mark_tail_converted (inode);
+ } else if (is_direct_le_ih(ih)) {
+ /* direct item has to be converted */
+ loff_t tail_offset;
+
+ tail_offset =
+ ((le_ih_k_offset(ih) -
+ 1) & ~(inode->i_sb->s_blocksize - 1)) + 1;
+ if (tail_offset == cpu_key_k_offset(&key)) {
+ /* direct item we just found fits into block we have
+ to map. Convert it into unformatted node: use
+ bh_result for the conversion */
+ set_block_dev_mapped(bh_result,
+ allocated_block_nr, inode);
+ unbh = bh_result;
+ done = 1;
+ } else {
+ /* we have to padd file tail stored in direct item(s)
+ up to block size and convert it to unformatted
+ node. FIXME: this should also get into page cache */
+
+ pathrelse(&path);
+ /*
+ * ugly, but we can only end the transaction if
+ * we aren't nested
+ */
+ BUG_ON(!th->t_refcount);
+ if (th->t_refcount == 1) {
+ retval =
+ reiserfs_end_persistent_transaction
+ (th);
+ th = NULL;
+ if (retval)
+ goto failure;
+ }
+
+ retval =
+ convert_tail_for_hole(inode, bh_result,
+ tail_offset);
+ if (retval) {
+ if (retval != -ENOSPC)
+ reiserfs_warning(inode->i_sb,
+ "clm-6004: convert tail failed inode %lu, error %d",
+ inode->i_ino,
+ retval);
+ if (allocated_block_nr) {
+ /* the bitmap, the super, and the stat data == 3 */
+ if (!th)
+ th = reiserfs_persistent_transaction(inode->i_sb, 3);
+ if (th)
+ reiserfs_free_block(th,
+ inode,
+ allocated_block_nr,
+ 1);
+ }
+ goto failure;
+ }
+ goto research;
+ }
+ retval =
+ direct2indirect(th, inode, &path, unbh,
+ tail_offset);
+ if (retval) {
+ reiserfs_unmap_buffer(unbh);
+ reiserfs_free_block(th, inode,
+ allocated_block_nr, 1);
+ goto failure;
+ }
+ /* it is important the set_buffer_uptodate is done after
+ ** the direct2indirect. The buffer might contain valid
+ ** data newer than the data on disk (read by readpage, changed,
+ ** and then sent here by writepage). direct2indirect needs
+ ** to know if unbh was already up to date, so it can decide
+ ** if the data in unbh needs to be replaced with data from
+ ** the disk
+ */
+ set_buffer_uptodate(unbh);
+
+ /* unbh->b_page == NULL in case of DIRECT_IO request, this means
+ buffer will disappear shortly, so it should not be added to
+ */
+ if (unbh->b_page) {
+ /* we've converted the tail, so we must
+ ** flush unbh before the transaction commits
+ */
+ reiserfs_add_tail_list(inode, unbh);
+
+ /* mark it dirty now to prevent commit_write from adding
+ ** this buffer to the inode's dirty buffer list
+ */
+ /*
+ * AKPM: changed __mark_buffer_dirty to mark_buffer_dirty().
+ * It's still atomic, but it sets the page dirty too,
+ * which makes it eligible for writeback at any time by the
+ * VM (which was also the case with __mark_buffer_dirty())
+ */
+ mark_buffer_dirty(unbh);
+ }
+ } else {
+ /* append indirect item with holes if needed, when appending
+ pointer to 'block'-th block use block, which is already
+ allocated */
+ struct cpu_key tmp_key;
+ unp_t unf_single = 0; // We use this in case we need to allocate only
+ // one block which is a fastpath
+ unp_t *un;
+ __u64 max_to_insert =
+ MAX_ITEM_LEN(inode->i_sb->s_blocksize) /
+ UNFM_P_SIZE;
+ __u64 blocks_needed;
+
+ RFALSE(pos_in_item != ih_item_len(ih) / UNFM_P_SIZE,
+ "vs-804: invalid position for append");
+ /* indirect item has to be appended, set up key of that position */
+ make_cpu_key(&tmp_key, inode,
+ le_key_k_offset(version,
+ &(ih->ih_key)) +
+ op_bytes_number(ih,
+ inode->i_sb->s_blocksize),
+ //pos_in_item * inode->i_sb->s_blocksize,
+ TYPE_INDIRECT, 3); // key type is unimportant
+
+ blocks_needed =
+ 1 +
+ ((cpu_key_k_offset(&key) -
+ cpu_key_k_offset(&tmp_key)) >> inode->i_sb->
+ s_blocksize_bits);
+ RFALSE(blocks_needed < 0, "green-805: invalid offset");
+
+ if (blocks_needed == 1) {
+ un = &unf_single;
+ } else {
+ un = kmalloc(min(blocks_needed, max_to_insert) * UNFM_P_SIZE, GFP_ATOMIC); // We need to avoid scheduling.
+ if (!un) {
+ un = &unf_single;
+ blocks_needed = 1;
+ max_to_insert = 0;
+ } else
+ memset(un, 0,
+ UNFM_P_SIZE * min(blocks_needed,
+ max_to_insert));
+ }
+ if (blocks_needed <= max_to_insert) {
+ /* we are going to add target block to the file. Use allocated
+ block for that */
+ un[blocks_needed - 1] =
+ cpu_to_le32(allocated_block_nr);
+ set_block_dev_mapped(bh_result,
+ allocated_block_nr, inode);
+ set_buffer_new(bh_result);
+ done = 1;
+ } else {
+ /* paste hole to the indirect item */
+ /* If kmalloc failed, max_to_insert becomes zero and it means we
+ only have space for one block */
+ blocks_needed =
+ max_to_insert ? max_to_insert : 1;
+ }
+ retval =
+ reiserfs_paste_into_item(th, &path, &tmp_key, inode,
+ (char *)un,
+ UNFM_P_SIZE *
+ blocks_needed);
+
+ if (blocks_needed != 1)
+ kfree(un);
+
+ if (retval) {
+ reiserfs_free_block(th, inode,
+ allocated_block_nr, 1);
+ goto failure;
+ }
+ if (!done) {
+ /* We need to mark new file size in case this function will be
+ interrupted/aborted later on. And we may do this only for
+ holes. */
+ inode->i_size +=
+ inode->i_sb->s_blocksize * blocks_needed;
+ }
+ }
- retval = 0;
+ if (done == 1)
+ break;
- failure:
- if (th && (!dangle || (retval && !th->t_trans_id))) {
- int err;
- if (th->t_trans_id)
- reiserfs_update_sd(th, inode);
- err = reiserfs_end_persistent_transaction(th);
- if (err)
- retval = err;
- }
+ /* this loop could log more blocks than we had originally asked
+ ** for. So, we have to allow the transaction to end if it is
+ ** too big or too full. Update the inode so things are
+ ** consistent if we crash before the function returns
+ **
+ ** release the path so that anybody waiting on the path before
+ ** ending their transaction will be able to continue.
+ */
+ if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
+ retval = restart_transaction(th, inode, &path);
+ if (retval)
+ goto failure;
+ }
+ /* inserting indirect pointers for a hole can take a
+ ** long time. reschedule if needed
+ */
+ cond_resched();
+
+ retval = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (retval == IO_ERROR) {
+ retval = -EIO;
+ goto failure;
+ }
+ if (retval == POSITION_FOUND) {
+ reiserfs_warning(inode->i_sb,
+ "vs-825: reiserfs_get_block: "
+ "%K should not be found", &key);
+ retval = -EEXIST;
+ if (allocated_block_nr)
+ reiserfs_free_block(th, inode,
+ allocated_block_nr, 1);
+ pathrelse(&path);
+ goto failure;
+ }
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ pos_in_item = path.pos_in_item;
+ } while (1);
- reiserfs_write_unlock(inode->i_sb);
- reiserfs_check_path(&path) ;
- return retval;
+ retval = 0;
+
+ failure:
+ if (th && (!dangle || (retval && !th->t_trans_id))) {
+ int err;
+ if (th->t_trans_id)
+ reiserfs_update_sd(th, inode);
+ err = reiserfs_end_persistent_transaction(th);
+ if (err)
+ retval = err;
+ }
+
+ reiserfs_write_unlock(inode->i_sb);
+ reiserfs_check_path(&path);
+ return retval;
}
static int
reiserfs_readpages(struct file *file, struct address_space *mapping,
- struct list_head *pages, unsigned nr_pages)
+ struct list_head *pages, unsigned nr_pages)
{
- return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block);
+ return mpage_readpages(mapping, pages, nr_pages, reiserfs_get_block);
}
/* Compute real number of used bytes by file
@@ -987,51 +1058,56 @@ reiserfs_readpages(struct file *file, struct address_space *mapping,
*/
static int real_space_diff(struct inode *inode, int sd_size)
{
- int bytes;
- loff_t blocksize = inode->i_sb->s_blocksize ;
-
- if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode))
- return sd_size ;
-
- /* End of file is also in full block with indirect reference, so round
- ** up to the next block.
- **
- ** there is just no way to know if the tail is actually packed
- ** on the file, so we have to assume it isn't. When we pack the
- ** tail, we add 4 bytes to pretend there really is an unformatted
- ** node pointer
- */
- bytes = ((inode->i_size + (blocksize-1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE + sd_size;
- return bytes ;
+ int bytes;
+ loff_t blocksize = inode->i_sb->s_blocksize;
+
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode))
+ return sd_size;
+
+ /* End of file is also in full block with indirect reference, so round
+ ** up to the next block.
+ **
+ ** there is just no way to know if the tail is actually packed
+ ** on the file, so we have to assume it isn't. When we pack the
+ ** tail, we add 4 bytes to pretend there really is an unformatted
+ ** node pointer
+ */
+ bytes =
+ ((inode->i_size +
+ (blocksize - 1)) >> inode->i_sb->s_blocksize_bits) * UNFM_P_SIZE +
+ sd_size;
+ return bytes;
}
static inline loff_t to_real_used_space(struct inode *inode, ulong blocks,
- int sd_size)
+ int sd_size)
{
- if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
- return inode->i_size + (loff_t)(real_space_diff(inode, sd_size)) ;
- }
- return ((loff_t)real_space_diff(inode, sd_size)) + (((loff_t)blocks) << 9);
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+ return inode->i_size +
+ (loff_t) (real_space_diff(inode, sd_size));
+ }
+ return ((loff_t) real_space_diff(inode, sd_size)) +
+ (((loff_t) blocks) << 9);
}
/* Compute number of blocks used by file in ReiserFS counting */
static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size)
{
- loff_t bytes = inode_get_bytes(inode) ;
- loff_t real_space = real_space_diff(inode, sd_size) ;
-
- /* keeps fsck and non-quota versions of reiserfs happy */
- if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
- bytes += (loff_t)511 ;
- }
-
- /* files from before the quota patch might i_blocks such that
- ** bytes < real_space. Deal with that here to prevent it from
- ** going negative.
- */
- if (bytes < real_space)
- return 0 ;
- return (bytes - real_space) >> 9;
+ loff_t bytes = inode_get_bytes(inode);
+ loff_t real_space = real_space_diff(inode, sd_size);
+
+ /* keeps fsck and non-quota versions of reiserfs happy */
+ if (S_ISLNK(inode->i_mode) || S_ISDIR(inode->i_mode)) {
+ bytes += (loff_t) 511;
+ }
+
+ /* files from before the quota patch might i_blocks such that
+ ** bytes < real_space. Deal with that here to prevent it from
+ ** going negative.
+ */
+ if (bytes < real_space)
+ return 0;
+ return (bytes - real_space) >> 9;
}
//
@@ -1042,263 +1118,269 @@ static inline ulong to_fake_used_blocks(struct inode *inode, int sd_size)
//
// called by read_locked_inode
-static void init_inode (struct inode * inode, struct path * path)
+static void init_inode(struct inode *inode, struct path *path)
{
- struct buffer_head * bh;
- struct item_head * ih;
- __u32 rdev;
- //int version = ITEM_VERSION_1;
-
- bh = PATH_PLAST_BUFFER (path);
- ih = PATH_PITEM_HEAD (path);
-
-
- copy_key (INODE_PKEY (inode), &(ih->ih_key));
- inode->i_blksize = reiserfs_default_io_size;
-
- INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));
- REISERFS_I(inode)->i_flags = 0;
- REISERFS_I(inode)->i_prealloc_block = 0;
- REISERFS_I(inode)->i_prealloc_count = 0;
- REISERFS_I(inode)->i_trans_id = 0;
- REISERFS_I(inode)->i_jl = NULL;
- REISERFS_I(inode)->i_acl_access = NULL;
- REISERFS_I(inode)->i_acl_default = NULL;
- init_rwsem (&REISERFS_I(inode)->xattr_sem);
-
- if (stat_data_v1 (ih)) {
- struct stat_data_v1 * sd = (struct stat_data_v1 *)B_I_PITEM (bh, ih);
- unsigned long blocks;
-
- set_inode_item_key_version (inode, KEY_FORMAT_3_5);
- set_inode_sd_version (inode, STAT_DATA_V1);
- inode->i_mode = sd_v1_mode(sd);
- inode->i_nlink = sd_v1_nlink(sd);
- inode->i_uid = sd_v1_uid(sd);
- inode->i_gid = sd_v1_gid(sd);
- inode->i_size = sd_v1_size(sd);
- inode->i_atime.tv_sec = sd_v1_atime(sd);
- inode->i_mtime.tv_sec = sd_v1_mtime(sd);
- inode->i_ctime.tv_sec = sd_v1_ctime(sd);
- inode->i_atime.tv_nsec = 0;
- inode->i_ctime.tv_nsec = 0;
- inode->i_mtime.tv_nsec = 0;
-
- inode->i_blocks = sd_v1_blocks(sd);
- inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
- blocks = (inode->i_size + 511) >> 9;
- blocks = _ROUND_UP (blocks, inode->i_sb->s_blocksize >> 9);
- if (inode->i_blocks > blocks) {
- // there was a bug in <=3.5.23 when i_blocks could take negative
- // values. Starting from 3.5.17 this value could even be stored in
- // stat data. For such files we set i_blocks based on file
- // size. Just 2 notes: this can be wrong for sparce files. On-disk value will be
- // only updated if file's inode will ever change
- inode->i_blocks = blocks;
- }
-
- rdev = sd_v1_rdev(sd);
- REISERFS_I(inode)->i_first_direct_byte = sd_v1_first_direct_byte(sd);
- /* an early bug in the quota code can give us an odd number for the
- ** block count. This is incorrect, fix it here.
- */
- if (inode->i_blocks & 1) {
- inode->i_blocks++ ;
- }
- inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
- SD_V1_SIZE));
- /* nopack is initially zero for v1 objects. For v2 objects,
- nopack is initialised from sd_attrs */
- REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
- } else {
- // new stat data found, but object may have old items
- // (directories and symlinks)
- struct stat_data * sd = (struct stat_data *)B_I_PITEM (bh, ih);
-
- inode->i_mode = sd_v2_mode(sd);
- inode->i_nlink = sd_v2_nlink(sd);
- inode->i_uid = sd_v2_uid(sd);
- inode->i_size = sd_v2_size(sd);
- inode->i_gid = sd_v2_gid(sd);
- inode->i_mtime.tv_sec = sd_v2_mtime(sd);
- inode->i_atime.tv_sec = sd_v2_atime(sd);
- inode->i_ctime.tv_sec = sd_v2_ctime(sd);
- inode->i_ctime.tv_nsec = 0;
- inode->i_mtime.tv_nsec = 0;
- inode->i_atime.tv_nsec = 0;
- inode->i_blocks = sd_v2_blocks(sd);
- rdev = sd_v2_rdev(sd);
- if( S_ISCHR( inode -> i_mode ) || S_ISBLK( inode -> i_mode ) )
- inode->i_generation = le32_to_cpu (INODE_PKEY (inode)->k_dir_id);
- else
- inode->i_generation = sd_v2_generation(sd);
+ struct buffer_head *bh;
+ struct item_head *ih;
+ __u32 rdev;
+ //int version = ITEM_VERSION_1;
+
+ bh = PATH_PLAST_BUFFER(path);
+ ih = PATH_PITEM_HEAD(path);
+
+ copy_key(INODE_PKEY(inode), &(ih->ih_key));
+ inode->i_blksize = reiserfs_default_io_size;
+
+ INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list));
+ REISERFS_I(inode)->i_flags = 0;
+ REISERFS_I(inode)->i_prealloc_block = 0;
+ REISERFS_I(inode)->i_prealloc_count = 0;
+ REISERFS_I(inode)->i_trans_id = 0;
+ REISERFS_I(inode)->i_jl = NULL;
+ REISERFS_I(inode)->i_acl_access = NULL;
+ REISERFS_I(inode)->i_acl_default = NULL;
+ init_rwsem(&REISERFS_I(inode)->xattr_sem);
+
+ if (stat_data_v1(ih)) {
+ struct stat_data_v1 *sd =
+ (struct stat_data_v1 *)B_I_PITEM(bh, ih);
+ unsigned long blocks;
+
+ set_inode_item_key_version(inode, KEY_FORMAT_3_5);
+ set_inode_sd_version(inode, STAT_DATA_V1);
+ inode->i_mode = sd_v1_mode(sd);
+ inode->i_nlink = sd_v1_nlink(sd);
+ inode->i_uid = sd_v1_uid(sd);
+ inode->i_gid = sd_v1_gid(sd);
+ inode->i_size = sd_v1_size(sd);
+ inode->i_atime.tv_sec = sd_v1_atime(sd);
+ inode->i_mtime.tv_sec = sd_v1_mtime(sd);
+ inode->i_ctime.tv_sec = sd_v1_ctime(sd);
+ inode->i_atime.tv_nsec = 0;
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_mtime.tv_nsec = 0;
+
+ inode->i_blocks = sd_v1_blocks(sd);
+ inode->i_generation = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
+ blocks = (inode->i_size + 511) >> 9;
+ blocks = _ROUND_UP(blocks, inode->i_sb->s_blocksize >> 9);
+ if (inode->i_blocks > blocks) {
+ // there was a bug in <=3.5.23 when i_blocks could take negative
+ // values. Starting from 3.5.17 this value could even be stored in
+ // stat data. For such files we set i_blocks based on file
+ // size. Just 2 notes: this can be wrong for sparce files. On-disk value will be
+ // only updated if file's inode will ever change
+ inode->i_blocks = blocks;
+ }
- if (S_ISDIR (inode->i_mode) || S_ISLNK (inode->i_mode))
- set_inode_item_key_version (inode, KEY_FORMAT_3_5);
- else
- set_inode_item_key_version (inode, KEY_FORMAT_3_6);
- REISERFS_I(inode)->i_first_direct_byte = 0;
- set_inode_sd_version (inode, STAT_DATA_V2);
- inode_set_bytes(inode, to_real_used_space(inode, inode->i_blocks,
- SD_V2_SIZE));
- /* read persistent inode attributes from sd and initalise
- generic inode flags from them */
- REISERFS_I(inode)->i_attrs = sd_v2_attrs( sd );
- sd_attrs_to_i_attrs( sd_v2_attrs( sd ), inode );
- }
-
- pathrelse (path);
- if (S_ISREG (inode->i_mode)) {
- inode->i_op = &reiserfs_file_inode_operations;
- inode->i_fop = &reiserfs_file_operations;
- inode->i_mapping->a_ops = &reiserfs_address_space_operations ;
- } else if (S_ISDIR (inode->i_mode)) {
- inode->i_op = &reiserfs_dir_inode_operations;
- inode->i_fop = &reiserfs_dir_operations;
- } else if (S_ISLNK (inode->i_mode)) {
- inode->i_op = &reiserfs_symlink_inode_operations;
- inode->i_mapping->a_ops = &reiserfs_address_space_operations;
- } else {
- inode->i_blocks = 0;
- inode->i_op = &reiserfs_special_inode_operations;
- init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
- }
-}
+ rdev = sd_v1_rdev(sd);
+ REISERFS_I(inode)->i_first_direct_byte =
+ sd_v1_first_direct_byte(sd);
+ /* an early bug in the quota code can give us an odd number for the
+ ** block count. This is incorrect, fix it here.
+ */
+ if (inode->i_blocks & 1) {
+ inode->i_blocks++;
+ }
+ inode_set_bytes(inode,
+ to_real_used_space(inode, inode->i_blocks,
+ SD_V1_SIZE));
+ /* nopack is initially zero for v1 objects. For v2 objects,
+ nopack is initialised from sd_attrs */
+ REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
+ } else {
+ // new stat data found, but object may have old items
+ // (directories and symlinks)
+ struct stat_data *sd = (struct stat_data *)B_I_PITEM(bh, ih);
+
+ inode->i_mode = sd_v2_mode(sd);
+ inode->i_nlink = sd_v2_nlink(sd);
+ inode->i_uid = sd_v2_uid(sd);
+ inode->i_size = sd_v2_size(sd);
+ inode->i_gid = sd_v2_gid(sd);
+ inode->i_mtime.tv_sec = sd_v2_mtime(sd);
+ inode->i_atime.tv_sec = sd_v2_atime(sd);
+ inode->i_ctime.tv_sec = sd_v2_ctime(sd);
+ inode->i_ctime.tv_nsec = 0;
+ inode->i_mtime.tv_nsec = 0;
+ inode->i_atime.tv_nsec = 0;
+ inode->i_blocks = sd_v2_blocks(sd);
+ rdev = sd_v2_rdev(sd);
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ inode->i_generation =
+ le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
+ else
+ inode->i_generation = sd_v2_generation(sd);
+ if (S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))
+ set_inode_item_key_version(inode, KEY_FORMAT_3_5);
+ else
+ set_inode_item_key_version(inode, KEY_FORMAT_3_6);
+ REISERFS_I(inode)->i_first_direct_byte = 0;
+ set_inode_sd_version(inode, STAT_DATA_V2);
+ inode_set_bytes(inode,
+ to_real_used_space(inode, inode->i_blocks,
+ SD_V2_SIZE));
+ /* read persistent inode attributes from sd and initalise
+ generic inode flags from them */
+ REISERFS_I(inode)->i_attrs = sd_v2_attrs(sd);
+ sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode);
+ }
+
+ pathrelse(path);
+ if (S_ISREG(inode->i_mode)) {
+ inode->i_op = &reiserfs_file_inode_operations;
+ inode->i_fop = &reiserfs_file_operations;
+ inode->i_mapping->a_ops = &reiserfs_address_space_operations;
+ } else if (S_ISDIR(inode->i_mode)) {
+ inode->i_op = &reiserfs_dir_inode_operations;
+ inode->i_fop = &reiserfs_dir_operations;
+ } else if (S_ISLNK(inode->i_mode)) {
+ inode->i_op = &reiserfs_symlink_inode_operations;
+ inode->i_mapping->a_ops = &reiserfs_address_space_operations;
+ } else {
+ inode->i_blocks = 0;
+ inode->i_op = &reiserfs_special_inode_operations;
+ init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
+ }
+}
// update new stat data with inode fields
-static void inode2sd (void * sd, struct inode * inode, loff_t size)
+static void inode2sd(void *sd, struct inode *inode, loff_t size)
{
- struct stat_data * sd_v2 = (struct stat_data *)sd;
- __u16 flags;
-
- set_sd_v2_mode(sd_v2, inode->i_mode );
- set_sd_v2_nlink(sd_v2, inode->i_nlink );
- set_sd_v2_uid(sd_v2, inode->i_uid );
- set_sd_v2_size(sd_v2, size );
- set_sd_v2_gid(sd_v2, inode->i_gid );
- set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec );
- set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec );
- set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec );
- set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE));
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));
- else
- set_sd_v2_generation(sd_v2, inode->i_generation);
- flags = REISERFS_I(inode)->i_attrs;
- i_attrs_to_sd_attrs( inode, &flags );
- set_sd_v2_attrs( sd_v2, flags );
+ struct stat_data *sd_v2 = (struct stat_data *)sd;
+ __u16 flags;
+
+ set_sd_v2_mode(sd_v2, inode->i_mode);
+ set_sd_v2_nlink(sd_v2, inode->i_nlink);
+ set_sd_v2_uid(sd_v2, inode->i_uid);
+ set_sd_v2_size(sd_v2, size);
+ set_sd_v2_gid(sd_v2, inode->i_gid);
+ set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec);
+ set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec);
+ set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec);
+ set_sd_v2_blocks(sd_v2, to_fake_used_blocks(inode, SD_V2_SIZE));
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ set_sd_v2_rdev(sd_v2, new_encode_dev(inode->i_rdev));
+ else
+ set_sd_v2_generation(sd_v2, inode->i_generation);
+ flags = REISERFS_I(inode)->i_attrs;
+ i_attrs_to_sd_attrs(inode, &flags);
+ set_sd_v2_attrs(sd_v2, flags);
}
-
// used to copy inode's fields to old stat data
-static void inode2sd_v1 (void * sd, struct inode * inode, loff_t size)
+static void inode2sd_v1(void *sd, struct inode *inode, loff_t size)
{
- struct stat_data_v1 * sd_v1 = (struct stat_data_v1 *)sd;
-
- set_sd_v1_mode(sd_v1, inode->i_mode );
- set_sd_v1_uid(sd_v1, inode->i_uid );
- set_sd_v1_gid(sd_v1, inode->i_gid );
- set_sd_v1_nlink(sd_v1, inode->i_nlink );
- set_sd_v1_size(sd_v1, size );
- set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec );
- set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec );
- set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec );
-
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev));
- else
- set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE));
-
- // Sigh. i_first_direct_byte is back
- set_sd_v1_first_direct_byte(sd_v1, REISERFS_I(inode)->i_first_direct_byte);
-}
+ struct stat_data_v1 *sd_v1 = (struct stat_data_v1 *)sd;
+
+ set_sd_v1_mode(sd_v1, inode->i_mode);
+ set_sd_v1_uid(sd_v1, inode->i_uid);
+ set_sd_v1_gid(sd_v1, inode->i_gid);
+ set_sd_v1_nlink(sd_v1, inode->i_nlink);
+ set_sd_v1_size(sd_v1, size);
+ set_sd_v1_atime(sd_v1, inode->i_atime.tv_sec);
+ set_sd_v1_ctime(sd_v1, inode->i_ctime.tv_sec);
+ set_sd_v1_mtime(sd_v1, inode->i_mtime.tv_sec);
+
+ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ set_sd_v1_rdev(sd_v1, new_encode_dev(inode->i_rdev));
+ else
+ set_sd_v1_blocks(sd_v1, to_fake_used_blocks(inode, SD_V1_SIZE));
+ // Sigh. i_first_direct_byte is back
+ set_sd_v1_first_direct_byte(sd_v1,
+ REISERFS_I(inode)->i_first_direct_byte);
+}
/* NOTE, you must prepare the buffer head before sending it here,
** and then log it after the call
*/
-static void update_stat_data (struct path * path, struct inode * inode,
- loff_t size)
+static void update_stat_data(struct path *path, struct inode *inode,
+ loff_t size)
{
- struct buffer_head * bh;
- struct item_head * ih;
-
- bh = PATH_PLAST_BUFFER (path);
- ih = PATH_PITEM_HEAD (path);
-
- if (!is_statdata_le_ih (ih))
- reiserfs_panic (inode->i_sb, "vs-13065: update_stat_data: key %k, found item %h",
- INODE_PKEY (inode), ih);
-
- if (stat_data_v1 (ih)) {
- // path points to old stat data
- inode2sd_v1 (B_I_PITEM (bh, ih), inode, size);
- } else {
- inode2sd (B_I_PITEM (bh, ih), inode, size);
- }
-
- return;
-}
+ struct buffer_head *bh;
+ struct item_head *ih;
+
+ bh = PATH_PLAST_BUFFER(path);
+ ih = PATH_PITEM_HEAD(path);
+
+ if (!is_statdata_le_ih(ih))
+ reiserfs_panic(inode->i_sb,
+ "vs-13065: update_stat_data: key %k, found item %h",
+ INODE_PKEY(inode), ih);
+
+ if (stat_data_v1(ih)) {
+ // path points to old stat data
+ inode2sd_v1(B_I_PITEM(bh, ih), inode, size);
+ } else {
+ inode2sd(B_I_PITEM(bh, ih), inode, size);
+ }
+ return;
+}
-void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
- struct inode * inode, loff_t size)
+void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
+ struct inode *inode, loff_t size)
{
- struct cpu_key key;
- INITIALIZE_PATH(path);
- struct buffer_head *bh ;
- int fs_gen ;
- struct item_head *ih, tmp_ih ;
- int retval;
-
- BUG_ON (!th->t_trans_id);
-
- make_cpu_key (&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3);//key type is unimportant
-
- for(;;) {
- int pos;
- /* look for the object's stat data */
- retval = search_item (inode->i_sb, &key, &path);
- if (retval == IO_ERROR) {
- reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: "
- "i/o failure occurred trying to update %K stat data",
- &key);
- return;
- }
- if (retval == ITEM_NOT_FOUND) {
- pos = PATH_LAST_POSITION (&path);
- pathrelse(&path) ;
- if (inode->i_nlink == 0) {
- /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found");*/
- return;
- }
- reiserfs_warning (inode->i_sb, "vs-13060: reiserfs_update_sd: "
- "stat data of object %k (nlink == %d) not found (pos %d)",
- INODE_PKEY (inode), inode->i_nlink, pos);
- reiserfs_check_path(&path) ;
- return;
- }
-
- /* sigh, prepare_for_journal might schedule. When it schedules the
- ** FS might change. We have to detect that, and loop back to the
- ** search if the stat data item has moved
- */
- bh = get_last_bh(&path) ;
- ih = get_ih(&path) ;
- copy_item_head (&tmp_ih, ih);
- fs_gen = get_generation (inode->i_sb);
- reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ;
- if (fs_changed (fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) {
- reiserfs_restore_prepared_buffer(inode->i_sb, bh) ;
- continue ; /* Stat_data item has been moved after scheduling. */
- }
- break;
- }
- update_stat_data (&path, inode, size);
- journal_mark_dirty(th, th->t_super, bh) ;
- pathrelse (&path);
- return;
+ struct cpu_key key;
+ INITIALIZE_PATH(path);
+ struct buffer_head *bh;
+ int fs_gen;
+ struct item_head *ih, tmp_ih;
+ int retval;
+
+ BUG_ON(!th->t_trans_id);
+
+ make_cpu_key(&key, inode, SD_OFFSET, TYPE_STAT_DATA, 3); //key type is unimportant
+
+ for (;;) {
+ int pos;
+ /* look for the object's stat data */
+ retval = search_item(inode->i_sb, &key, &path);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(inode->i_sb,
+ "vs-13050: reiserfs_update_sd: "
+ "i/o failure occurred trying to update %K stat data",
+ &key);
+ return;
+ }
+ if (retval == ITEM_NOT_FOUND) {
+ pos = PATH_LAST_POSITION(&path);
+ pathrelse(&path);
+ if (inode->i_nlink == 0) {
+ /*reiserfs_warning (inode->i_sb, "vs-13050: reiserfs_update_sd: i_nlink == 0, stat data not found"); */
+ return;
+ }
+ reiserfs_warning(inode->i_sb,
+ "vs-13060: reiserfs_update_sd: "
+ "stat data of object %k (nlink == %d) not found (pos %d)",
+ INODE_PKEY(inode), inode->i_nlink,
+ pos);
+ reiserfs_check_path(&path);
+ return;
+ }
+
+ /* sigh, prepare_for_journal might schedule. When it schedules the
+ ** FS might change. We have to detect that, and loop back to the
+ ** search if the stat data item has moved
+ */
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ copy_item_head(&tmp_ih, ih);
+ fs_gen = get_generation(inode->i_sb);
+ reiserfs_prepare_for_journal(inode->i_sb, bh, 1);
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ reiserfs_restore_prepared_buffer(inode->i_sb, bh);
+ continue; /* Stat_data item has been moved after scheduling. */
+ }
+ break;
+ }
+ update_stat_data(&path, inode, size);
+ journal_mark_dirty(th, th->t_super, bh);
+ pathrelse(&path);
+ return;
}
/* reiserfs_read_locked_inode is called to read the inode off disk, and it
@@ -1307,9 +1389,10 @@ void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
** corresponding iput might try to delete whatever object the inode last
** represented.
*/
-static void reiserfs_make_bad_inode(struct inode *inode) {
- memset(INODE_PKEY(inode), 0, KEY_SIZE);
- make_bad_inode(inode);
+static void reiserfs_make_bad_inode(struct inode *inode)
+{
+ memset(INODE_PKEY(inode), 0, KEY_SIZE);
+ make_bad_inode(inode);
}
//
@@ -1317,77 +1400,79 @@ static void reiserfs_make_bad_inode(struct inode *inode) {
// evolved as the prototype did
//
-int reiserfs_init_locked_inode (struct inode * inode, void *p)
+int reiserfs_init_locked_inode(struct inode *inode, void *p)
{
- struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p ;
- inode->i_ino = args->objectid;
- INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid);
- return 0;
+ struct reiserfs_iget_args *args = (struct reiserfs_iget_args *)p;
+ inode->i_ino = args->objectid;
+ INODE_PKEY(inode)->k_dir_id = cpu_to_le32(args->dirid);
+ return 0;
}
/* looks for stat data in the tree, and fills up the fields of in-core
inode stat data fields */
-void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args *args)
+void reiserfs_read_locked_inode(struct inode *inode,
+ struct reiserfs_iget_args *args)
{
- INITIALIZE_PATH (path_to_sd);
- struct cpu_key key;
- unsigned long dirino;
- int retval;
-
- dirino = args->dirid ;
-
- /* set version 1, version 2 could be used too, because stat data
- key is the same in both versions */
- key.version = KEY_FORMAT_3_5;
- key.on_disk_key.k_dir_id = dirino;
- key.on_disk_key.k_objectid = inode->i_ino;
- key.on_disk_key.k_offset = 0;
- key.on_disk_key.k_type = 0;
-
- /* look for the object's stat data */
- retval = search_item (inode->i_sb, &key, &path_to_sd);
- if (retval == IO_ERROR) {
- reiserfs_warning (inode->i_sb, "vs-13070: reiserfs_read_locked_inode: "
- "i/o failure occurred trying to find stat data of %K",
- &key);
- reiserfs_make_bad_inode(inode) ;
- return;
- }
- if (retval != ITEM_FOUND) {
- /* a stale NFS handle can trigger this without it being an error */
- pathrelse (&path_to_sd);
- reiserfs_make_bad_inode(inode) ;
- inode->i_nlink = 0;
- return;
- }
-
- init_inode (inode, &path_to_sd);
-
- /* It is possible that knfsd is trying to access inode of a file
- that is being removed from the disk by some other thread. As we
- update sd on unlink all that is required is to check for nlink
- here. This bug was first found by Sizif when debugging
- SquidNG/Butterfly, forgotten, and found again after Philippe
- Gramoulle <philippe.gramoulle@mmania.com> reproduced it.
-
- More logical fix would require changes in fs/inode.c:iput() to
- remove inode from hash-table _after_ fs cleaned disk stuff up and
- in iget() to return NULL if I_FREEING inode is found in
- hash-table. */
- /* Currently there is one place where it's ok to meet inode with
- nlink==0: processing of open-unlinked and half-truncated files
- during mount (fs/reiserfs/super.c:finish_unfinished()). */
- if( ( inode -> i_nlink == 0 ) &&
- ! REISERFS_SB(inode -> i_sb) -> s_is_unlinked_ok ) {
- reiserfs_warning (inode->i_sb,
- "vs-13075: reiserfs_read_locked_inode: "
- "dead inode read from disk %K. "
- "This is likely to be race with knfsd. Ignore",
- &key );
- reiserfs_make_bad_inode( inode );
- }
-
- reiserfs_check_path(&path_to_sd) ; /* init inode should be relsing */
+ INITIALIZE_PATH(path_to_sd);
+ struct cpu_key key;
+ unsigned long dirino;
+ int retval;
+
+ dirino = args->dirid;
+
+ /* set version 1, version 2 could be used too, because stat data
+ key is the same in both versions */
+ key.version = KEY_FORMAT_3_5;
+ key.on_disk_key.k_dir_id = dirino;
+ key.on_disk_key.k_objectid = inode->i_ino;
+ key.on_disk_key.k_offset = 0;
+ key.on_disk_key.k_type = 0;
+
+ /* look for the object's stat data */
+ retval = search_item(inode->i_sb, &key, &path_to_sd);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(inode->i_sb,
+ "vs-13070: reiserfs_read_locked_inode: "
+ "i/o failure occurred trying to find stat data of %K",
+ &key);
+ reiserfs_make_bad_inode(inode);
+ return;
+ }
+ if (retval != ITEM_FOUND) {
+ /* a stale NFS handle can trigger this without it being an error */
+ pathrelse(&path_to_sd);
+ reiserfs_make_bad_inode(inode);
+ inode->i_nlink = 0;
+ return;
+ }
+
+ init_inode(inode, &path_to_sd);
+
+ /* It is possible that knfsd is trying to access inode of a file
+ that is being removed from the disk by some other thread. As we
+ update sd on unlink all that is required is to check for nlink
+ here. This bug was first found by Sizif when debugging
+ SquidNG/Butterfly, forgotten, and found again after Philippe
+ Gramoulle <philippe.gramoulle@mmania.com> reproduced it.
+
+ More logical fix would require changes in fs/inode.c:iput() to
+ remove inode from hash-table _after_ fs cleaned disk stuff up and
+ in iget() to return NULL if I_FREEING inode is found in
+ hash-table. */
+ /* Currently there is one place where it's ok to meet inode with
+ nlink==0: processing of open-unlinked and half-truncated files
+ during mount (fs/reiserfs/super.c:finish_unfinished()). */
+ if ((inode->i_nlink == 0) &&
+ !REISERFS_SB(inode->i_sb)->s_is_unlinked_ok) {
+ reiserfs_warning(inode->i_sb,
+ "vs-13075: reiserfs_read_locked_inode: "
+ "dead inode read from disk %K. "
+ "This is likely to be race with knfsd. Ignore",
+ &key);
+ reiserfs_make_bad_inode(inode);
+ }
+
+ reiserfs_check_path(&path_to_sd); /* init inode should be relsing */
}
@@ -1403,140 +1488,148 @@ void reiserfs_read_locked_inode (struct inode * inode, struct reiserfs_iget_args
* inode numbers (objectids) are distinguished by parent directory ids.
*
*/
-int reiserfs_find_actor( struct inode *inode, void *opaque )
+int reiserfs_find_actor(struct inode *inode, void *opaque)
{
- struct reiserfs_iget_args *args;
+ struct reiserfs_iget_args *args;
- args = opaque;
- /* args is already in CPU order */
- return (inode->i_ino == args->objectid) &&
- (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid);
+ args = opaque;
+ /* args is already in CPU order */
+ return (inode->i_ino == args->objectid) &&
+ (le32_to_cpu(INODE_PKEY(inode)->k_dir_id) == args->dirid);
}
-struct inode * reiserfs_iget (struct super_block * s, const struct cpu_key * key)
+struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key)
{
- struct inode * inode;
- struct reiserfs_iget_args args ;
-
- args.objectid = key->on_disk_key.k_objectid ;
- args.dirid = key->on_disk_key.k_dir_id ;
- inode = iget5_locked (s, key->on_disk_key.k_objectid,
- reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
- if (!inode)
- return ERR_PTR(-ENOMEM) ;
-
- if (inode->i_state & I_NEW) {
- reiserfs_read_locked_inode(inode, &args);
- unlock_new_inode(inode);
- }
-
- if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
- /* either due to i/o error or a stale NFS handle */
- iput (inode);
- inode = NULL;
- }
- return inode;
+ struct inode *inode;
+ struct reiserfs_iget_args args;
+
+ args.objectid = key->on_disk_key.k_objectid;
+ args.dirid = key->on_disk_key.k_dir_id;
+ inode = iget5_locked(s, key->on_disk_key.k_objectid,
+ reiserfs_find_actor, reiserfs_init_locked_inode,
+ (void *)(&args));
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ if (inode->i_state & I_NEW) {
+ reiserfs_read_locked_inode(inode, &args);
+ unlock_new_inode(inode);
+ }
+
+ if (comp_short_keys(INODE_PKEY(inode), key) || is_bad_inode(inode)) {
+ /* either due to i/o error or a stale NFS handle */
+ iput(inode);
+ inode = NULL;
+ }
+ return inode;
}
struct dentry *reiserfs_get_dentry(struct super_block *sb, void *vobjp)
{
- __u32 *data = vobjp;
- struct cpu_key key ;
- struct dentry *result;
- struct inode *inode;
-
- key.on_disk_key.k_objectid = data[0] ;
- key.on_disk_key.k_dir_id = data[1] ;
- reiserfs_write_lock(sb);
- inode = reiserfs_iget(sb, &key) ;
- if (inode && !IS_ERR(inode) && data[2] != 0 &&
- data[2] != inode->i_generation) {
- iput(inode) ;
- inode = NULL ;
- }
- reiserfs_write_unlock(sb);
- if (!inode)
- inode = ERR_PTR(-ESTALE);
- if (IS_ERR(inode))
- return ERR_PTR(PTR_ERR(inode));
- result = d_alloc_anon(inode);
- if (!result) {
- iput(inode);
- return ERR_PTR(-ENOMEM);
- }
- return result;
+ __u32 *data = vobjp;
+ struct cpu_key key;
+ struct dentry *result;
+ struct inode *inode;
+
+ key.on_disk_key.k_objectid = data[0];
+ key.on_disk_key.k_dir_id = data[1];
+ reiserfs_write_lock(sb);
+ inode = reiserfs_iget(sb, &key);
+ if (inode && !IS_ERR(inode) && data[2] != 0 &&
+ data[2] != inode->i_generation) {
+ iput(inode);
+ inode = NULL;
+ }
+ reiserfs_write_unlock(sb);
+ if (!inode)
+ inode = ERR_PTR(-ESTALE);
+ if (IS_ERR(inode))
+ return ERR_PTR(PTR_ERR(inode));
+ result = d_alloc_anon(inode);
+ if (!result) {
+ iput(inode);
+ return ERR_PTR(-ENOMEM);
+ }
+ return result;
}
-struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 *data,
- int len, int fhtype,
- int (*acceptable)(void *contect, struct dentry *de),
- void *context) {
- __u32 obj[3], parent[3];
-
- /* fhtype happens to reflect the number of u32s encoded.
- * due to a bug in earlier code, fhtype might indicate there
- * are more u32s then actually fitted.
- * so if fhtype seems to be more than len, reduce fhtype.
- * Valid types are:
- * 2 - objectid + dir_id - legacy support
- * 3 - objectid + dir_id + generation
- * 4 - objectid + dir_id + objectid and dirid of parent - legacy
- * 5 - objectid + dir_id + generation + objectid and dirid of parent
- * 6 - as above plus generation of directory
- * 6 does not fit in NFSv2 handles
- */
- if (fhtype > len) {
- if (fhtype != 6 || len != 5)
- reiserfs_warning (sb, "nfsd/reiserfs, fhtype=%d, len=%d - odd",
- fhtype, len);
- fhtype = 5;
- }
-
- obj[0] = data[0];
- obj[1] = data[1];
- if (fhtype == 3 || fhtype >= 5)
- obj[2] = data[2];
- else obj[2] = 0; /* generation number */
-
- if (fhtype >= 4) {
- parent[0] = data[fhtype>=5?3:2] ;
- parent[1] = data[fhtype>=5?4:3] ;
- if (fhtype == 6)
- parent[2] = data[5];
- else parent[2] = 0;
- }
- return sb->s_export_op->find_exported_dentry(sb, obj, fhtype < 4 ? NULL : parent,
- acceptable, context);
-}
+struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data,
+ int len, int fhtype,
+ int (*acceptable) (void *contect,
+ struct dentry * de),
+ void *context)
+{
+ __u32 obj[3], parent[3];
+
+ /* fhtype happens to reflect the number of u32s encoded.
+ * due to a bug in earlier code, fhtype might indicate there
+ * are more u32s then actually fitted.
+ * so if fhtype seems to be more than len, reduce fhtype.
+ * Valid types are:
+ * 2 - objectid + dir_id - legacy support
+ * 3 - objectid + dir_id + generation
+ * 4 - objectid + dir_id + objectid and dirid of parent - legacy
+ * 5 - objectid + dir_id + generation + objectid and dirid of parent
+ * 6 - as above plus generation of directory
+ * 6 does not fit in NFSv2 handles
+ */
+ if (fhtype > len) {
+ if (fhtype != 6 || len != 5)
+ reiserfs_warning(sb,
+ "nfsd/reiserfs, fhtype=%d, len=%d - odd",
+ fhtype, len);
+ fhtype = 5;
+ }
-int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_parent) {
- struct inode *inode = dentry->d_inode ;
- int maxlen = *lenp;
-
- if (maxlen < 3)
- return 255 ;
-
- data[0] = inode->i_ino ;
- data[1] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
- data[2] = inode->i_generation ;
- *lenp = 3 ;
- /* no room for directory info? return what we've stored so far */
- if (maxlen < 5 || ! need_parent)
- return 3 ;
-
- spin_lock(&dentry->d_lock);
- inode = dentry->d_parent->d_inode ;
- data[3] = inode->i_ino ;
- data[4] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
- *lenp = 5 ;
- if (maxlen >= 6) {
- data[5] = inode->i_generation ;
- *lenp = 6 ;
- }
- spin_unlock(&dentry->d_lock);
- return *lenp ;
+ obj[0] = data[0];
+ obj[1] = data[1];
+ if (fhtype == 3 || fhtype >= 5)
+ obj[2] = data[2];
+ else
+ obj[2] = 0; /* generation number */
+
+ if (fhtype >= 4) {
+ parent[0] = data[fhtype >= 5 ? 3 : 2];
+ parent[1] = data[fhtype >= 5 ? 4 : 3];
+ if (fhtype == 6)
+ parent[2] = data[5];
+ else
+ parent[2] = 0;
+ }
+ return sb->s_export_op->find_exported_dentry(sb, obj,
+ fhtype < 4 ? NULL : parent,
+ acceptable, context);
}
+int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
+ int need_parent)
+{
+ struct inode *inode = dentry->d_inode;
+ int maxlen = *lenp;
+
+ if (maxlen < 3)
+ return 255;
+
+ data[0] = inode->i_ino;
+ data[1] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
+ data[2] = inode->i_generation;
+ *lenp = 3;
+ /* no room for directory info? return what we've stored so far */
+ if (maxlen < 5 || !need_parent)
+ return 3;
+
+ spin_lock(&dentry->d_lock);
+ inode = dentry->d_parent->d_inode;
+ data[3] = inode->i_ino;
+ data[4] = le32_to_cpu(INODE_PKEY(inode)->k_dir_id);
+ *lenp = 5;
+ if (maxlen >= 6) {
+ data[5] = inode->i_generation;
+ *lenp = 6;
+ }
+ spin_unlock(&dentry->d_lock);
+ return *lenp;
+}
/* looks for stat data, then copies fields to it, marks the buffer
containing stat data as dirty */
@@ -1545,120 +1638,127 @@ int reiserfs_encode_fh(struct dentry *dentry, __u32 *data, int *lenp, int need_p
** to properly mark inodes for datasync and such, but only actually
** does something when called for a synchronous update.
*/
-int reiserfs_write_inode (struct inode * inode, int do_sync) {
- struct reiserfs_transaction_handle th ;
- int jbegin_count = 1 ;
-
- if (inode->i_sb->s_flags & MS_RDONLY)
- return -EROFS;
- /* memory pressure can sometimes initiate write_inode calls with sync == 1,
- ** these cases are just when the system needs ram, not when the
- ** inode needs to reach disk for safety, and they can safely be
- ** ignored because the altered inode has already been logged.
- */
- if (do_sync && !(current->flags & PF_MEMALLOC)) {
- reiserfs_write_lock(inode->i_sb);
- if (!journal_begin(&th, inode->i_sb, jbegin_count)) {
- reiserfs_update_sd (&th, inode);
- journal_end_sync(&th, inode->i_sb, jbegin_count) ;
- }
- reiserfs_write_unlock(inode->i_sb);
- }
- return 0;
+int reiserfs_write_inode(struct inode *inode, int do_sync)
+{
+ struct reiserfs_transaction_handle th;
+ int jbegin_count = 1;
+
+ if (inode->i_sb->s_flags & MS_RDONLY)
+ return -EROFS;
+ /* memory pressure can sometimes initiate write_inode calls with sync == 1,
+ ** these cases are just when the system needs ram, not when the
+ ** inode needs to reach disk for safety, and they can safely be
+ ** ignored because the altered inode has already been logged.
+ */
+ if (do_sync && !(current->flags & PF_MEMALLOC)) {
+ reiserfs_write_lock(inode->i_sb);
+ if (!journal_begin(&th, inode->i_sb, jbegin_count)) {
+ reiserfs_update_sd(&th, inode);
+ journal_end_sync(&th, inode->i_sb, jbegin_count);
+ }
+ reiserfs_write_unlock(inode->i_sb);
+ }
+ return 0;
}
/* stat data of new object is inserted already, this inserts the item
containing "." and ".." entries */
-static int reiserfs_new_directory (struct reiserfs_transaction_handle *th,
- struct inode *inode,
- struct item_head * ih, struct path * path,
- struct inode * dir)
+static int reiserfs_new_directory(struct reiserfs_transaction_handle *th,
+ struct inode *inode,
+ struct item_head *ih, struct path *path,
+ struct inode *dir)
{
- struct super_block * sb = th->t_super;
- char empty_dir [EMPTY_DIR_SIZE];
- char * body = empty_dir;
- struct cpu_key key;
- int retval;
-
- BUG_ON (!th->t_trans_id);
-
- _make_cpu_key (&key, KEY_FORMAT_3_5, le32_to_cpu (ih->ih_key.k_dir_id),
- le32_to_cpu (ih->ih_key.k_objectid), DOT_OFFSET, TYPE_DIRENTRY, 3/*key length*/);
-
- /* compose item head for new item. Directories consist of items of
- old type (ITEM_VERSION_1). Do not set key (second arg is 0), it
- is done by reiserfs_new_inode */
- if (old_format_only (sb)) {
- make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
-
- make_empty_dir_item_v1 (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
- INODE_PKEY (dir)->k_dir_id,
- INODE_PKEY (dir)->k_objectid );
- } else {
- make_le_item_head (ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET, TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
-
- make_empty_dir_item (body, ih->ih_key.k_dir_id, ih->ih_key.k_objectid,
- INODE_PKEY (dir)->k_dir_id,
- INODE_PKEY (dir)->k_objectid );
- }
-
- /* look for place in the tree for new item */
- retval = search_item (sb, &key, path);
- if (retval == IO_ERROR) {
- reiserfs_warning (sb, "vs-13080: reiserfs_new_directory: "
- "i/o failure occurred creating new directory");
- return -EIO;
- }
- if (retval == ITEM_FOUND) {
- pathrelse (path);
- reiserfs_warning (sb, "vs-13070: reiserfs_new_directory: "
- "object with this key exists (%k)", &(ih->ih_key));
- return -EEXIST;
- }
-
- /* insert item, that is empty directory item */
- return reiserfs_insert_item (th, path, &key, ih, inode, body);
-}
+ struct super_block *sb = th->t_super;
+ char empty_dir[EMPTY_DIR_SIZE];
+ char *body = empty_dir;
+ struct cpu_key key;
+ int retval;
+
+ BUG_ON(!th->t_trans_id);
+
+ _make_cpu_key(&key, KEY_FORMAT_3_5, le32_to_cpu(ih->ih_key.k_dir_id),
+ le32_to_cpu(ih->ih_key.k_objectid), DOT_OFFSET,
+ TYPE_DIRENTRY, 3 /*key length */ );
+
+ /* compose item head for new item. Directories consist of items of
+ old type (ITEM_VERSION_1). Do not set key (second arg is 0), it
+ is done by reiserfs_new_inode */
+ if (old_format_only(sb)) {
+ make_le_item_head(ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET,
+ TYPE_DIRENTRY, EMPTY_DIR_SIZE_V1, 2);
+
+ make_empty_dir_item_v1(body, ih->ih_key.k_dir_id,
+ ih->ih_key.k_objectid,
+ INODE_PKEY(dir)->k_dir_id,
+ INODE_PKEY(dir)->k_objectid);
+ } else {
+ make_le_item_head(ih, NULL, KEY_FORMAT_3_5, DOT_OFFSET,
+ TYPE_DIRENTRY, EMPTY_DIR_SIZE, 2);
+
+ make_empty_dir_item(body, ih->ih_key.k_dir_id,
+ ih->ih_key.k_objectid,
+ INODE_PKEY(dir)->k_dir_id,
+ INODE_PKEY(dir)->k_objectid);
+ }
+
+ /* look for place in the tree for new item */
+ retval = search_item(sb, &key, path);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(sb, "vs-13080: reiserfs_new_directory: "
+ "i/o failure occurred creating new directory");
+ return -EIO;
+ }
+ if (retval == ITEM_FOUND) {
+ pathrelse(path);
+ reiserfs_warning(sb, "vs-13070: reiserfs_new_directory: "
+ "object with this key exists (%k)",
+ &(ih->ih_key));
+ return -EEXIST;
+ }
+ /* insert item, that is empty directory item */
+ return reiserfs_insert_item(th, path, &key, ih, inode, body);
+}
/* stat data of object has been inserted, this inserts the item
containing the body of symlink */
-static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
- struct inode *inode, /* Inode of symlink */
- struct item_head * ih,
- struct path * path, const char * symname, int item_len)
+static int reiserfs_new_symlink(struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode of symlink */
+ struct item_head *ih,
+ struct path *path, const char *symname,
+ int item_len)
{
- struct super_block * sb = th->t_super;
- struct cpu_key key;
- int retval;
-
- BUG_ON (!th->t_trans_id);
-
- _make_cpu_key (&key, KEY_FORMAT_3_5,
- le32_to_cpu (ih->ih_key.k_dir_id),
- le32_to_cpu (ih->ih_key.k_objectid),
- 1, TYPE_DIRECT, 3/*key length*/);
-
- make_le_item_head (ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len, 0/*free_space*/);
-
- /* look for place in the tree for new item */
- retval = search_item (sb, &key, path);
- if (retval == IO_ERROR) {
- reiserfs_warning (sb, "vs-13080: reiserfs_new_symlinik: "
- "i/o failure occurred creating new symlink");
- return -EIO;
- }
- if (retval == ITEM_FOUND) {
- pathrelse (path);
- reiserfs_warning (sb, "vs-13080: reiserfs_new_symlink: "
- "object with this key exists (%k)", &(ih->ih_key));
- return -EEXIST;
- }
-
- /* insert item, that is body of symlink */
- return reiserfs_insert_item (th, path, &key, ih, inode, symname);
-}
+ struct super_block *sb = th->t_super;
+ struct cpu_key key;
+ int retval;
+
+ BUG_ON(!th->t_trans_id);
+
+ _make_cpu_key(&key, KEY_FORMAT_3_5,
+ le32_to_cpu(ih->ih_key.k_dir_id),
+ le32_to_cpu(ih->ih_key.k_objectid),
+ 1, TYPE_DIRECT, 3 /*key length */ );
+
+ make_le_item_head(ih, NULL, KEY_FORMAT_3_5, 1, TYPE_DIRECT, item_len,
+ 0 /*free_space */ );
+
+ /* look for place in the tree for new item */
+ retval = search_item(sb, &key, path);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(sb, "vs-13080: reiserfs_new_symlinik: "
+ "i/o failure occurred creating new symlink");
+ return -EIO;
+ }
+ if (retval == ITEM_FOUND) {
+ pathrelse(path);
+ reiserfs_warning(sb, "vs-13080: reiserfs_new_symlink: "
+ "object with this key exists (%k)",
+ &(ih->ih_key));
+ return -EEXIST;
+ }
+ /* insert item, that is body of symlink */
+ return reiserfs_insert_item(th, path, &key, ih, inode, symname);
+}
/* inserts the stat data into the tree, and then calls
reiserfs_new_directory (to insert ".", ".." item if new object is
@@ -1669,213 +1769,219 @@ static int reiserfs_new_symlink (struct reiserfs_transaction_handle *th,
non-zero due to an error, we have to drop the quota previously allocated
for the fresh inode. This can only be done outside a transaction, so
if we return non-zero, we also end the transaction. */
-int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
- struct inode * dir, int mode,
- const char * symname,
- /* 0 for regular, EMTRY_DIR_SIZE for dirs,
- strlen (symname) for symlinks)*/
- loff_t i_size, struct dentry *dentry,
- struct inode *inode)
+int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
+ struct inode *dir, int mode, const char *symname,
+ /* 0 for regular, EMTRY_DIR_SIZE for dirs,
+ strlen (symname) for symlinks) */
+ loff_t i_size, struct dentry *dentry,
+ struct inode *inode)
{
- struct super_block * sb;
- INITIALIZE_PATH (path_to_key);
- struct cpu_key key;
- struct item_head ih;
- struct stat_data sd;
- int retval;
- int err;
-
- BUG_ON (!th->t_trans_id);
-
- if (DQUOT_ALLOC_INODE(inode)) {
- err = -EDQUOT;
- goto out_end_trans;
- }
- if (!dir || !dir->i_nlink) {
- err = -EPERM;
- goto out_bad_inode;
- }
-
- sb = dir->i_sb;
-
- /* item head of new item */
- ih.ih_key.k_dir_id = reiserfs_choose_packing(dir);
- ih.ih_key.k_objectid = cpu_to_le32 (reiserfs_get_unused_objectid (th));
- if (!ih.ih_key.k_objectid) {
- err = -ENOMEM;
- goto out_bad_inode ;
- }
- if (old_format_only (sb))
- /* not a perfect generation count, as object ids can be reused, but
- ** this is as good as reiserfs can do right now.
- ** note that the private part of inode isn't filled in yet, we have
- ** to use the directory.
- */
- inode->i_generation = le32_to_cpu (INODE_PKEY (dir)->k_objectid);
- else
+ struct super_block *sb;
+ INITIALIZE_PATH(path_to_key);
+ struct cpu_key key;
+ struct item_head ih;
+ struct stat_data sd;
+ int retval;
+ int err;
+
+ BUG_ON(!th->t_trans_id);
+
+ if (DQUOT_ALLOC_INODE(inode)) {
+ err = -EDQUOT;
+ goto out_end_trans;
+ }
+ if (!dir || !dir->i_nlink) {
+ err = -EPERM;
+ goto out_bad_inode;
+ }
+
+ sb = dir->i_sb;
+
+ /* item head of new item */
+ ih.ih_key.k_dir_id = reiserfs_choose_packing(dir);
+ ih.ih_key.k_objectid = cpu_to_le32(reiserfs_get_unused_objectid(th));
+ if (!ih.ih_key.k_objectid) {
+ err = -ENOMEM;
+ goto out_bad_inode;
+ }
+ if (old_format_only(sb))
+ /* not a perfect generation count, as object ids can be reused, but
+ ** this is as good as reiserfs can do right now.
+ ** note that the private part of inode isn't filled in yet, we have
+ ** to use the directory.
+ */
+ inode->i_generation = le32_to_cpu(INODE_PKEY(dir)->k_objectid);
+ else
#if defined( USE_INODE_GENERATION_COUNTER )
- inode->i_generation = le32_to_cpu(REISERFS_SB(sb)->s_rs->s_inode_generation);
+ inode->i_generation =
+ le32_to_cpu(REISERFS_SB(sb)->s_rs->s_inode_generation);
#else
- inode->i_generation = ++event;
+ inode->i_generation = ++event;
#endif
- /* fill stat data */
- inode->i_nlink = (S_ISDIR (mode) ? 2 : 1);
-
- /* uid and gid must already be set by the caller for quota init */
-
- /* symlink cannot be immutable or append only, right? */
- if( S_ISLNK( inode -> i_mode ) )
- inode -> i_flags &= ~ ( S_IMMUTABLE | S_APPEND );
-
- inode->i_mtime = inode->i_atime = inode->i_ctime =
- CURRENT_TIME_SEC;
- inode->i_size = i_size;
- inode->i_blocks = 0;
- inode->i_bytes = 0;
- REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 :
- U32_MAX/*NO_BYTES_IN_DIRECT_ITEM*/;
-
- INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));
- REISERFS_I(inode)->i_flags = 0;
- REISERFS_I(inode)->i_prealloc_block = 0;
- REISERFS_I(inode)->i_prealloc_count = 0;
- REISERFS_I(inode)->i_trans_id = 0;
- REISERFS_I(inode)->i_jl = NULL;
- REISERFS_I(inode)->i_attrs =
- REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
- sd_attrs_to_i_attrs( REISERFS_I(inode) -> i_attrs, inode );
- REISERFS_I(inode)->i_acl_access = NULL;
- REISERFS_I(inode)->i_acl_default = NULL;
- init_rwsem (&REISERFS_I(inode)->xattr_sem);
-
- if (old_format_only (sb))
- make_le_item_head (&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET, TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
- else
- make_le_item_head (&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET, TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
-
- /* key to search for correct place for new stat data */
- _make_cpu_key (&key, KEY_FORMAT_3_6, le32_to_cpu (ih.ih_key.k_dir_id),
- le32_to_cpu (ih.ih_key.k_objectid), SD_OFFSET, TYPE_STAT_DATA, 3/*key length*/);
-
- /* find proper place for inserting of stat data */
- retval = search_item (sb, &key, &path_to_key);
- if (retval == IO_ERROR) {
- err = -EIO;
- goto out_bad_inode;
- }
- if (retval == ITEM_FOUND) {
- pathrelse (&path_to_key);
- err = -EEXIST;
- goto out_bad_inode;
- }
- if (old_format_only (sb)) {
- if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
- pathrelse (&path_to_key);
- /* i_uid or i_gid is too big to be stored in stat data v3.5 */
- err = -EINVAL;
- goto out_bad_inode;
- }
- inode2sd_v1 (&sd, inode, inode->i_size);
- } else {
- inode2sd (&sd, inode, inode->i_size);
- }
- // these do not go to on-disk stat data
- inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
- inode->i_blksize = reiserfs_default_io_size;
-
- // store in in-core inode the key of stat data and version all
- // object items will have (directory items will have old offset
- // format, other new objects will consist of new items)
- memcpy (INODE_PKEY (inode), &(ih.ih_key), KEY_SIZE);
- if (old_format_only (sb) || S_ISDIR(mode) || S_ISLNK(mode))
- set_inode_item_key_version (inode, KEY_FORMAT_3_5);
- else
- set_inode_item_key_version (inode, KEY_FORMAT_3_6);
- if (old_format_only (sb))
- set_inode_sd_version (inode, STAT_DATA_V1);
- else
- set_inode_sd_version (inode, STAT_DATA_V2);
-
- /* insert the stat data into the tree */
+ /* fill stat data */
+ inode->i_nlink = (S_ISDIR(mode) ? 2 : 1);
+
+ /* uid and gid must already be set by the caller for quota init */
+
+ /* symlink cannot be immutable or append only, right? */
+ if (S_ISLNK(inode->i_mode))
+ inode->i_flags &= ~(S_IMMUTABLE | S_APPEND);
+
+ inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
+ inode->i_size = i_size;
+ inode->i_blocks = 0;
+ inode->i_bytes = 0;
+ REISERFS_I(inode)->i_first_direct_byte = S_ISLNK(mode) ? 1 :
+ U32_MAX /*NO_BYTES_IN_DIRECT_ITEM */ ;
+
+ INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list));
+ REISERFS_I(inode)->i_flags = 0;
+ REISERFS_I(inode)->i_prealloc_block = 0;
+ REISERFS_I(inode)->i_prealloc_count = 0;
+ REISERFS_I(inode)->i_trans_id = 0;
+ REISERFS_I(inode)->i_jl = NULL;
+ REISERFS_I(inode)->i_attrs =
+ REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK;
+ sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode);
+ REISERFS_I(inode)->i_acl_access = NULL;
+ REISERFS_I(inode)->i_acl_default = NULL;
+ init_rwsem(&REISERFS_I(inode)->xattr_sem);
+
+ if (old_format_only(sb))
+ make_le_item_head(&ih, NULL, KEY_FORMAT_3_5, SD_OFFSET,
+ TYPE_STAT_DATA, SD_V1_SIZE, MAX_US_INT);
+ else
+ make_le_item_head(&ih, NULL, KEY_FORMAT_3_6, SD_OFFSET,
+ TYPE_STAT_DATA, SD_SIZE, MAX_US_INT);
+
+ /* key to search for correct place for new stat data */
+ _make_cpu_key(&key, KEY_FORMAT_3_6, le32_to_cpu(ih.ih_key.k_dir_id),
+ le32_to_cpu(ih.ih_key.k_objectid), SD_OFFSET,
+ TYPE_STAT_DATA, 3 /*key length */ );
+
+ /* find proper place for inserting of stat data */
+ retval = search_item(sb, &key, &path_to_key);
+ if (retval == IO_ERROR) {
+ err = -EIO;
+ goto out_bad_inode;
+ }
+ if (retval == ITEM_FOUND) {
+ pathrelse(&path_to_key);
+ err = -EEXIST;
+ goto out_bad_inode;
+ }
+ if (old_format_only(sb)) {
+ if (inode->i_uid & ~0xffff || inode->i_gid & ~0xffff) {
+ pathrelse(&path_to_key);
+ /* i_uid or i_gid is too big to be stored in stat data v3.5 */
+ err = -EINVAL;
+ goto out_bad_inode;
+ }
+ inode2sd_v1(&sd, inode, inode->i_size);
+ } else {
+ inode2sd(&sd, inode, inode->i_size);
+ }
+ // these do not go to on-disk stat data
+ inode->i_ino = le32_to_cpu(ih.ih_key.k_objectid);
+ inode->i_blksize = reiserfs_default_io_size;
+
+ // store in in-core inode the key of stat data and version all
+ // object items will have (directory items will have old offset
+ // format, other new objects will consist of new items)
+ memcpy(INODE_PKEY(inode), &(ih.ih_key), KEY_SIZE);
+ if (old_format_only(sb) || S_ISDIR(mode) || S_ISLNK(mode))
+ set_inode_item_key_version(inode, KEY_FORMAT_3_5);
+ else
+ set_inode_item_key_version(inode, KEY_FORMAT_3_6);
+ if (old_format_only(sb))
+ set_inode_sd_version(inode, STAT_DATA_V1);
+ else
+ set_inode_sd_version(inode, STAT_DATA_V2);
+
+ /* insert the stat data into the tree */
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- if (REISERFS_I(dir)->new_packing_locality)
- th->displace_new_blocks = 1;
+ if (REISERFS_I(dir)->new_packing_locality)
+ th->displace_new_blocks = 1;
#endif
- retval = reiserfs_insert_item (th, &path_to_key, &key, &ih, inode, (char *)(&sd));
- if (retval) {
- err = retval;
- reiserfs_check_path(&path_to_key) ;
- goto out_bad_inode;
- }
-
+ retval =
+ reiserfs_insert_item(th, &path_to_key, &key, &ih, inode,
+ (char *)(&sd));
+ if (retval) {
+ err = retval;
+ reiserfs_check_path(&path_to_key);
+ goto out_bad_inode;
+ }
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- if (!th->displace_new_blocks)
- REISERFS_I(dir)->new_packing_locality = 0;
+ if (!th->displace_new_blocks)
+ REISERFS_I(dir)->new_packing_locality = 0;
#endif
- if (S_ISDIR(mode)) {
- /* insert item with "." and ".." */
- retval = reiserfs_new_directory (th, inode, &ih, &path_to_key, dir);
- }
-
- if (S_ISLNK(mode)) {
- /* insert body of symlink */
- if (!old_format_only (sb))
- i_size = ROUND_UP(i_size);
- retval = reiserfs_new_symlink (th, inode, &ih, &path_to_key, symname, i_size);
- }
- if (retval) {
- err = retval;
- reiserfs_check_path(&path_to_key) ;
- journal_end(th, th->t_super, th->t_blocks_allocated);
- goto out_inserted_sd;
- }
-
- /* XXX CHECK THIS */
- if (reiserfs_posixacl (inode->i_sb)) {
- retval = reiserfs_inherit_default_acl (dir, dentry, inode);
- if (retval) {
- err = retval;
- reiserfs_check_path(&path_to_key) ;
- journal_end(th, th->t_super, th->t_blocks_allocated);
- goto out_inserted_sd;
- }
- } else if (inode->i_sb->s_flags & MS_POSIXACL) {
- reiserfs_warning (inode->i_sb, "ACLs aren't enabled in the fs, "
- "but vfs thinks they are!");
- } else if (is_reiserfs_priv_object (dir)) {
- reiserfs_mark_inode_private (inode);
- }
-
- insert_inode_hash (inode);
- reiserfs_update_sd(th, inode);
- reiserfs_check_path(&path_to_key) ;
-
- return 0;
+ if (S_ISDIR(mode)) {
+ /* insert item with "." and ".." */
+ retval =
+ reiserfs_new_directory(th, inode, &ih, &path_to_key, dir);
+ }
+
+ if (S_ISLNK(mode)) {
+ /* insert body of symlink */
+ if (!old_format_only(sb))
+ i_size = ROUND_UP(i_size);
+ retval =
+ reiserfs_new_symlink(th, inode, &ih, &path_to_key, symname,
+ i_size);
+ }
+ if (retval) {
+ err = retval;
+ reiserfs_check_path(&path_to_key);
+ journal_end(th, th->t_super, th->t_blocks_allocated);
+ goto out_inserted_sd;
+ }
+
+ /* XXX CHECK THIS */
+ if (reiserfs_posixacl(inode->i_sb)) {
+ retval = reiserfs_inherit_default_acl(dir, dentry, inode);
+ if (retval) {
+ err = retval;
+ reiserfs_check_path(&path_to_key);
+ journal_end(th, th->t_super, th->t_blocks_allocated);
+ goto out_inserted_sd;
+ }
+ } else if (inode->i_sb->s_flags & MS_POSIXACL) {
+ reiserfs_warning(inode->i_sb, "ACLs aren't enabled in the fs, "
+ "but vfs thinks they are!");
+ } else if (is_reiserfs_priv_object(dir)) {
+ reiserfs_mark_inode_private(inode);
+ }
+
+ insert_inode_hash(inode);
+ reiserfs_update_sd(th, inode);
+ reiserfs_check_path(&path_to_key);
+
+ return 0;
/* it looks like you can easily compress these two goto targets into
* one. Keeping it like this doesn't actually hurt anything, and they
* are place holders for what the quota code actually needs.
*/
-out_bad_inode:
- /* Invalidate the object, nothing was inserted yet */
- INODE_PKEY(inode)->k_objectid = 0;
-
- /* Quota change must be inside a transaction for journaling */
- DQUOT_FREE_INODE(inode);
-
-out_end_trans:
- journal_end(th, th->t_super, th->t_blocks_allocated) ;
- /* Drop can be outside and it needs more credits so it's better to have it outside */
- DQUOT_DROP(inode);
- inode->i_flags |= S_NOQUOTA;
- make_bad_inode(inode);
-
-out_inserted_sd:
- inode->i_nlink = 0;
- th->t_trans_id = 0; /* so the caller can't use this handle later */
- iput(inode);
- return err;
+ out_bad_inode:
+ /* Invalidate the object, nothing was inserted yet */
+ INODE_PKEY(inode)->k_objectid = 0;
+
+ /* Quota change must be inside a transaction for journaling */
+ DQUOT_FREE_INODE(inode);
+
+ out_end_trans:
+ journal_end(th, th->t_super, th->t_blocks_allocated);
+ /* Drop can be outside and it needs more credits so it's better to have it outside */
+ DQUOT_DROP(inode);
+ inode->i_flags |= S_NOQUOTA;
+ make_bad_inode(inode);
+
+ out_inserted_sd:
+ inode->i_nlink = 0;
+ th->t_trans_id = 0; /* so the caller can't use this handle later */
+ iput(inode);
+ return err;
}
/*
@@ -1891,77 +1997,78 @@ out_inserted_sd:
**
** on failure, nonzero is returned, page_result and bh_result are untouched.
*/
-static int grab_tail_page(struct inode *p_s_inode,
- struct page **page_result,
- struct buffer_head **bh_result) {
-
- /* we want the page with the last byte in the file,
- ** not the page that will hold the next byte for appending
- */
- unsigned long index = (p_s_inode->i_size-1) >> PAGE_CACHE_SHIFT ;
- unsigned long pos = 0 ;
- unsigned long start = 0 ;
- unsigned long blocksize = p_s_inode->i_sb->s_blocksize ;
- unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1) ;
- struct buffer_head *bh ;
- struct buffer_head *head ;
- struct page * page ;
- int error ;
-
- /* we know that we are only called with inode->i_size > 0.
- ** we also know that a file tail can never be as big as a block
- ** If i_size % blocksize == 0, our file is currently block aligned
- ** and it won't need converting or zeroing after a truncate.
- */
- if ((offset & (blocksize - 1)) == 0) {
- return -ENOENT ;
- }
- page = grab_cache_page(p_s_inode->i_mapping, index) ;
- error = -ENOMEM ;
- if (!page) {
- goto out ;
- }
- /* start within the page of the last block in the file */
- start = (offset / blocksize) * blocksize ;
-
- error = block_prepare_write(page, start, offset,
- reiserfs_get_block_create_0) ;
- if (error)
- goto unlock ;
-
- head = page_buffers(page) ;
- bh = head;
- do {
- if (pos >= start) {
- break ;
- }
- bh = bh->b_this_page ;
- pos += blocksize ;
- } while(bh != head) ;
-
- if (!buffer_uptodate(bh)) {
- /* note, this should never happen, prepare_write should
- ** be taking care of this for us. If the buffer isn't up to date,
- ** I've screwed up the code to find the buffer, or the code to
- ** call prepare_write
- */
- reiserfs_warning (p_s_inode->i_sb,
- "clm-6000: error reading block %lu on dev %s",
- bh->b_blocknr,
- reiserfs_bdevname (p_s_inode->i_sb)) ;
- error = -EIO ;
- goto unlock ;
- }
- *bh_result = bh ;
- *page_result = page ;
-
-out:
- return error ;
-
-unlock:
- unlock_page(page) ;
- page_cache_release(page) ;
- return error ;
+static int grab_tail_page(struct inode *p_s_inode,
+ struct page **page_result,
+ struct buffer_head **bh_result)
+{
+
+ /* we want the page with the last byte in the file,
+ ** not the page that will hold the next byte for appending
+ */
+ unsigned long index = (p_s_inode->i_size - 1) >> PAGE_CACHE_SHIFT;
+ unsigned long pos = 0;
+ unsigned long start = 0;
+ unsigned long blocksize = p_s_inode->i_sb->s_blocksize;
+ unsigned long offset = (p_s_inode->i_size) & (PAGE_CACHE_SIZE - 1);
+ struct buffer_head *bh;
+ struct buffer_head *head;
+ struct page *page;
+ int error;
+
+ /* we know that we are only called with inode->i_size > 0.
+ ** we also know that a file tail can never be as big as a block
+ ** If i_size % blocksize == 0, our file is currently block aligned
+ ** and it won't need converting or zeroing after a truncate.
+ */
+ if ((offset & (blocksize - 1)) == 0) {
+ return -ENOENT;
+ }
+ page = grab_cache_page(p_s_inode->i_mapping, index);
+ error = -ENOMEM;
+ if (!page) {
+ goto out;
+ }
+ /* start within the page of the last block in the file */
+ start = (offset / blocksize) * blocksize;
+
+ error = block_prepare_write(page, start, offset,
+ reiserfs_get_block_create_0);
+ if (error)
+ goto unlock;
+
+ head = page_buffers(page);
+ bh = head;
+ do {
+ if (pos >= start) {
+ break;
+ }
+ bh = bh->b_this_page;
+ pos += blocksize;
+ } while (bh != head);
+
+ if (!buffer_uptodate(bh)) {
+ /* note, this should never happen, prepare_write should
+ ** be taking care of this for us. If the buffer isn't up to date,
+ ** I've screwed up the code to find the buffer, or the code to
+ ** call prepare_write
+ */
+ reiserfs_warning(p_s_inode->i_sb,
+ "clm-6000: error reading block %lu on dev %s",
+ bh->b_blocknr,
+ reiserfs_bdevname(p_s_inode->i_sb));
+ error = -EIO;
+ goto unlock;
+ }
+ *bh_result = bh;
+ *page_result = page;
+
+ out:
+ return error;
+
+ unlock:
+ unlock_page(page);
+ page_cache_release(page);
+ return error;
}
/*
@@ -1970,235 +2077,247 @@ unlock:
**
** some code taken from block_truncate_page
*/
-int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps) {
- struct reiserfs_transaction_handle th ;
- /* we want the offset for the first byte after the end of the file */
- unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1) ;
- unsigned blocksize = p_s_inode->i_sb->s_blocksize ;
- unsigned length ;
- struct page *page = NULL ;
- int error ;
- struct buffer_head *bh = NULL ;
-
- reiserfs_write_lock(p_s_inode->i_sb);
-
- if (p_s_inode->i_size > 0) {
- if ((error = grab_tail_page(p_s_inode, &page, &bh))) {
- // -ENOENT means we truncated past the end of the file,
- // and get_block_create_0 could not find a block to read in,
- // which is ok.
- if (error != -ENOENT)
- reiserfs_warning (p_s_inode->i_sb,
- "clm-6001: grab_tail_page failed %d",
- error);
- page = NULL ;
- bh = NULL ;
- }
- }
-
- /* so, if page != NULL, we have a buffer head for the offset at
- ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0,
- ** then we have an unformatted node. Otherwise, we have a direct item,
- ** and no zeroing is required on disk. We zero after the truncate,
- ** because the truncate might pack the item anyway
- ** (it will unmap bh if it packs).
- */
- /* it is enough to reserve space in transaction for 2 balancings:
- one for "save" link adding and another for the first
- cut_from_item. 1 is for update_sd */
- error = journal_begin (&th, p_s_inode->i_sb,
- JOURNAL_PER_BALANCE_CNT * 2 + 1);
- if (error)
- goto out;
- reiserfs_update_inode_transaction(p_s_inode) ;
- if (update_timestamps)
- /* we are doing real truncate: if the system crashes before the last
- transaction of truncating gets committed - on reboot the file
- either appears truncated properly or not truncated at all */
- add_save_link (&th, p_s_inode, 1);
- error = reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
- if (error)
- goto out;
- error = journal_end (&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
- if (error)
- goto out;
-
- if (update_timestamps) {
- error = remove_save_link (p_s_inode, 1/* truncate */);
- if (error)
- goto out;
- }
-
- if (page) {
- length = offset & (blocksize - 1) ;
- /* if we are not on a block boundary */
- if (length) {
- char *kaddr;
-
- length = blocksize - length ;
- kaddr = kmap_atomic(page, KM_USER0) ;
- memset(kaddr + offset, 0, length) ;
- flush_dcache_page(page) ;
- kunmap_atomic(kaddr, KM_USER0) ;
- if (buffer_mapped(bh) && bh->b_blocknr != 0) {
- mark_buffer_dirty(bh) ;
- }
- }
- unlock_page(page) ;
- page_cache_release(page) ;
- }
-
- reiserfs_write_unlock(p_s_inode->i_sb);
- return 0;
-out:
- if (page) {
- unlock_page (page);
- page_cache_release (page);
- }
- reiserfs_write_unlock(p_s_inode->i_sb);
- return error;
-}
+int reiserfs_truncate_file(struct inode *p_s_inode, int update_timestamps)
+{
+ struct reiserfs_transaction_handle th;
+ /* we want the offset for the first byte after the end of the file */
+ unsigned long offset = p_s_inode->i_size & (PAGE_CACHE_SIZE - 1);
+ unsigned blocksize = p_s_inode->i_sb->s_blocksize;
+ unsigned length;
+ struct page *page = NULL;
+ int error;
+ struct buffer_head *bh = NULL;
+
+ reiserfs_write_lock(p_s_inode->i_sb);
+
+ if (p_s_inode->i_size > 0) {
+ if ((error = grab_tail_page(p_s_inode, &page, &bh))) {
+ // -ENOENT means we truncated past the end of the file,
+ // and get_block_create_0 could not find a block to read in,
+ // which is ok.
+ if (error != -ENOENT)
+ reiserfs_warning(p_s_inode->i_sb,
+ "clm-6001: grab_tail_page failed %d",
+ error);
+ page = NULL;
+ bh = NULL;
+ }
+ }
-static int map_block_for_writepage(struct inode *inode,
- struct buffer_head *bh_result,
- unsigned long block) {
- struct reiserfs_transaction_handle th ;
- int fs_gen ;
- struct item_head tmp_ih ;
- struct item_head *ih ;
- struct buffer_head *bh ;
- __le32 *item ;
- struct cpu_key key ;
- INITIALIZE_PATH(path) ;
- int pos_in_item ;
- int jbegin_count = JOURNAL_PER_BALANCE_CNT ;
- loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1 ;
- int retval ;
- int use_get_block = 0 ;
- int bytes_copied = 0 ;
- int copy_size ;
- int trans_running = 0;
-
- /* catch places below that try to log something without starting a trans */
- th.t_trans_id = 0;
-
- if (!buffer_uptodate(bh_result)) {
- return -EIO;
- }
-
- kmap(bh_result->b_page) ;
-start_over:
- reiserfs_write_lock(inode->i_sb);
- make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3) ;
-
-research:
- retval = search_for_position_by_key(inode->i_sb, &key, &path) ;
- if (retval != POSITION_FOUND) {
- use_get_block = 1;
- goto out ;
- }
-
- bh = get_last_bh(&path) ;
- ih = get_ih(&path) ;
- item = get_item(&path) ;
- pos_in_item = path.pos_in_item ;
-
- /* we've found an unformatted node */
- if (indirect_item_found(retval, ih)) {
- if (bytes_copied > 0) {
- reiserfs_warning (inode->i_sb, "clm-6002: bytes_copied %d",
- bytes_copied) ;
- }
- if (!get_block_num(item, pos_in_item)) {
- /* crap, we are writing to a hole */
- use_get_block = 1;
- goto out ;
- }
- set_block_dev_mapped(bh_result, get_block_num(item,pos_in_item),inode);
- } else if (is_direct_le_ih(ih)) {
- char *p ;
- p = page_address(bh_result->b_page) ;
- p += (byte_offset -1) & (PAGE_CACHE_SIZE - 1) ;
- copy_size = ih_item_len(ih) - pos_in_item;
-
- fs_gen = get_generation(inode->i_sb) ;
- copy_item_head(&tmp_ih, ih) ;
-
- if (!trans_running) {
- /* vs-3050 is gone, no need to drop the path */
- retval = journal_begin(&th, inode->i_sb, jbegin_count) ;
- if (retval)
- goto out;
- reiserfs_update_inode_transaction(inode) ;
- trans_running = 1;
- if (fs_changed(fs_gen, inode->i_sb) && item_moved(&tmp_ih, &path)) {
- reiserfs_restore_prepared_buffer(inode->i_sb, bh) ;
- goto research;
- }
- }
-
- reiserfs_prepare_for_journal(inode->i_sb, bh, 1) ;
-
- if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
- reiserfs_restore_prepared_buffer(inode->i_sb, bh) ;
- goto research;
- }
-
- memcpy( B_I_PITEM(bh, ih) + pos_in_item, p + bytes_copied, copy_size) ;
-
- journal_mark_dirty(&th, inode->i_sb, bh) ;
- bytes_copied += copy_size ;
- set_block_dev_mapped(bh_result, 0, inode);
-
- /* are there still bytes left? */
- if (bytes_copied < bh_result->b_size &&
- (byte_offset + bytes_copied) < inode->i_size) {
- set_cpu_key_k_offset(&key, cpu_key_k_offset(&key) + copy_size) ;
- goto research ;
- }
- } else {
- reiserfs_warning (inode->i_sb,
- "clm-6003: bad item inode %lu, device %s",
- inode->i_ino, reiserfs_bdevname (inode->i_sb)) ;
- retval = -EIO ;
- goto out ;
- }
- retval = 0 ;
-
-out:
- pathrelse(&path) ;
- if (trans_running) {
- int err = journal_end(&th, inode->i_sb, jbegin_count) ;
- if (err)
- retval = err;
- trans_running = 0;
- }
- reiserfs_write_unlock(inode->i_sb);
-
- /* this is where we fill in holes in the file. */
- if (use_get_block) {
- retval = reiserfs_get_block(inode, block, bh_result,
- GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM |
- GET_BLOCK_NO_DANGLE);
- if (!retval) {
- if (!buffer_mapped(bh_result) || bh_result->b_blocknr == 0) {
- /* get_block failed to find a mapped unformatted node. */
- use_get_block = 0 ;
- goto start_over ;
- }
- }
- }
- kunmap(bh_result->b_page) ;
-
- if (!retval && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
- /* we've copied data from the page into the direct item, so the
- * buffer in the page is now clean, mark it to reflect that.
+ /* so, if page != NULL, we have a buffer head for the offset at
+ ** the end of the file. if the bh is mapped, and bh->b_blocknr != 0,
+ ** then we have an unformatted node. Otherwise, we have a direct item,
+ ** and no zeroing is required on disk. We zero after the truncate,
+ ** because the truncate might pack the item anyway
+ ** (it will unmap bh if it packs).
*/
- lock_buffer(bh_result);
- clear_buffer_dirty(bh_result);
- unlock_buffer(bh_result);
- }
- return retval ;
+ /* it is enough to reserve space in transaction for 2 balancings:
+ one for "save" link adding and another for the first
+ cut_from_item. 1 is for update_sd */
+ error = journal_begin(&th, p_s_inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT * 2 + 1);
+ if (error)
+ goto out;
+ reiserfs_update_inode_transaction(p_s_inode);
+ if (update_timestamps)
+ /* we are doing real truncate: if the system crashes before the last
+ transaction of truncating gets committed - on reboot the file
+ either appears truncated properly or not truncated at all */
+ add_save_link(&th, p_s_inode, 1);
+ error = reiserfs_do_truncate(&th, p_s_inode, page, update_timestamps);
+ if (error)
+ goto out;
+ error =
+ journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1);
+ if (error)
+ goto out;
+
+ if (update_timestamps) {
+ error = remove_save_link(p_s_inode, 1 /* truncate */ );
+ if (error)
+ goto out;
+ }
+
+ if (page) {
+ length = offset & (blocksize - 1);
+ /* if we are not on a block boundary */
+ if (length) {
+ char *kaddr;
+
+ length = blocksize - length;
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
+ if (buffer_mapped(bh) && bh->b_blocknr != 0) {
+ mark_buffer_dirty(bh);
+ }
+ }
+ unlock_page(page);
+ page_cache_release(page);
+ }
+
+ reiserfs_write_unlock(p_s_inode->i_sb);
+ return 0;
+ out:
+ if (page) {
+ unlock_page(page);
+ page_cache_release(page);
+ }
+ reiserfs_write_unlock(p_s_inode->i_sb);
+ return error;
+}
+
+static int map_block_for_writepage(struct inode *inode,
+ struct buffer_head *bh_result,
+ unsigned long block)
+{
+ struct reiserfs_transaction_handle th;
+ int fs_gen;
+ struct item_head tmp_ih;
+ struct item_head *ih;
+ struct buffer_head *bh;
+ __le32 *item;
+ struct cpu_key key;
+ INITIALIZE_PATH(path);
+ int pos_in_item;
+ int jbegin_count = JOURNAL_PER_BALANCE_CNT;
+ loff_t byte_offset = (block << inode->i_sb->s_blocksize_bits) + 1;
+ int retval;
+ int use_get_block = 0;
+ int bytes_copied = 0;
+ int copy_size;
+ int trans_running = 0;
+
+ /* catch places below that try to log something without starting a trans */
+ th.t_trans_id = 0;
+
+ if (!buffer_uptodate(bh_result)) {
+ return -EIO;
+ }
+
+ kmap(bh_result->b_page);
+ start_over:
+ reiserfs_write_lock(inode->i_sb);
+ make_cpu_key(&key, inode, byte_offset, TYPE_ANY, 3);
+
+ research:
+ retval = search_for_position_by_key(inode->i_sb, &key, &path);
+ if (retval != POSITION_FOUND) {
+ use_get_block = 1;
+ goto out;
+ }
+
+ bh = get_last_bh(&path);
+ ih = get_ih(&path);
+ item = get_item(&path);
+ pos_in_item = path.pos_in_item;
+
+ /* we've found an unformatted node */
+ if (indirect_item_found(retval, ih)) {
+ if (bytes_copied > 0) {
+ reiserfs_warning(inode->i_sb,
+ "clm-6002: bytes_copied %d",
+ bytes_copied);
+ }
+ if (!get_block_num(item, pos_in_item)) {
+ /* crap, we are writing to a hole */
+ use_get_block = 1;
+ goto out;
+ }
+ set_block_dev_mapped(bh_result,
+ get_block_num(item, pos_in_item), inode);
+ } else if (is_direct_le_ih(ih)) {
+ char *p;
+ p = page_address(bh_result->b_page);
+ p += (byte_offset - 1) & (PAGE_CACHE_SIZE - 1);
+ copy_size = ih_item_len(ih) - pos_in_item;
+
+ fs_gen = get_generation(inode->i_sb);
+ copy_item_head(&tmp_ih, ih);
+
+ if (!trans_running) {
+ /* vs-3050 is gone, no need to drop the path */
+ retval = journal_begin(&th, inode->i_sb, jbegin_count);
+ if (retval)
+ goto out;
+ reiserfs_update_inode_transaction(inode);
+ trans_running = 1;
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ reiserfs_restore_prepared_buffer(inode->i_sb,
+ bh);
+ goto research;
+ }
+ }
+
+ reiserfs_prepare_for_journal(inode->i_sb, bh, 1);
+
+ if (fs_changed(fs_gen, inode->i_sb)
+ && item_moved(&tmp_ih, &path)) {
+ reiserfs_restore_prepared_buffer(inode->i_sb, bh);
+ goto research;
+ }
+
+ memcpy(B_I_PITEM(bh, ih) + pos_in_item, p + bytes_copied,
+ copy_size);
+
+ journal_mark_dirty(&th, inode->i_sb, bh);
+ bytes_copied += copy_size;
+ set_block_dev_mapped(bh_result, 0, inode);
+
+ /* are there still bytes left? */
+ if (bytes_copied < bh_result->b_size &&
+ (byte_offset + bytes_copied) < inode->i_size) {
+ set_cpu_key_k_offset(&key,
+ cpu_key_k_offset(&key) +
+ copy_size);
+ goto research;
+ }
+ } else {
+ reiserfs_warning(inode->i_sb,
+ "clm-6003: bad item inode %lu, device %s",
+ inode->i_ino, reiserfs_bdevname(inode->i_sb));
+ retval = -EIO;
+ goto out;
+ }
+ retval = 0;
+
+ out:
+ pathrelse(&path);
+ if (trans_running) {
+ int err = journal_end(&th, inode->i_sb, jbegin_count);
+ if (err)
+ retval = err;
+ trans_running = 0;
+ }
+ reiserfs_write_unlock(inode->i_sb);
+
+ /* this is where we fill in holes in the file. */
+ if (use_get_block) {
+ retval = reiserfs_get_block(inode, block, bh_result,
+ GET_BLOCK_CREATE | GET_BLOCK_NO_ISEM
+ | GET_BLOCK_NO_DANGLE);
+ if (!retval) {
+ if (!buffer_mapped(bh_result)
+ || bh_result->b_blocknr == 0) {
+ /* get_block failed to find a mapped unformatted node. */
+ use_get_block = 0;
+ goto start_over;
+ }
+ }
+ }
+ kunmap(bh_result->b_page);
+
+ if (!retval && buffer_mapped(bh_result) && bh_result->b_blocknr == 0) {
+ /* we've copied data from the page into the direct item, so the
+ * buffer in the page is now clean, mark it to reflect that.
+ */
+ lock_buffer(bh_result);
+ clear_buffer_dirty(bh_result);
+ unlock_buffer(bh_result);
+ }
+ return retval;
}
/*
@@ -2206,383 +2325,390 @@ out:
* start/recovery path as __block_write_full_page, along with special
* code to handle reiserfs tails.
*/
-static int reiserfs_write_full_page(struct page *page, struct writeback_control *wbc) {
- struct inode *inode = page->mapping->host ;
- unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT ;
- int error = 0;
- unsigned long block ;
- struct buffer_head *head, *bh;
- int partial = 0 ;
- int nr = 0;
- int checked = PageChecked(page);
- struct reiserfs_transaction_handle th;
- struct super_block *s = inode->i_sb;
- int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
- th.t_trans_id = 0;
-
- /* The page dirty bit is cleared before writepage is called, which
- * means we have to tell create_empty_buffers to make dirty buffers
- * The page really should be up to date at this point, so tossing
- * in the BH_Uptodate is just a sanity check.
- */
- if (!page_has_buffers(page)) {
- create_empty_buffers(page, s->s_blocksize,
- (1 << BH_Dirty) | (1 << BH_Uptodate));
- }
- head = page_buffers(page) ;
-
- /* last page in the file, zero out any contents past the
- ** last byte in the file
- */
- if (page->index >= end_index) {
- char *kaddr;
- unsigned last_offset;
-
- last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1) ;
- /* no file contents in this page */
- if (page->index >= end_index + 1 || !last_offset) {
- unlock_page(page);
- return 0;
- }
- kaddr = kmap_atomic(page, KM_USER0);
- memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE-last_offset) ;
- flush_dcache_page(page) ;
- kunmap_atomic(kaddr, KM_USER0) ;
- }
- bh = head ;
- block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits) ;
- /* first map all the buffers, logging any direct items we find */
- do {
- if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
- (buffer_mapped(bh) && bh->b_blocknr == 0))) {
- /* not mapped yet, or it points to a direct item, search
- * the btree for the mapping info, and log any direct
- * items found
- */
- if ((error = map_block_for_writepage(inode, bh, block))) {
- goto fail ;
- }
- }
- bh = bh->b_this_page;
- block++;
- } while(bh != head) ;
-
- /*
- * we start the transaction after map_block_for_writepage,
- * because it can create holes in the file (an unbounded operation).
- * starting it here, we can make a reliable estimate for how many
- * blocks we're going to log
- */
- if (checked) {
- ClearPageChecked(page);
- reiserfs_write_lock(s);
- error = journal_begin(&th, s, bh_per_page + 1);
- if (error) {
- reiserfs_write_unlock(s);
- goto fail;
- }
- reiserfs_update_inode_transaction(inode);
- }
- /* now go through and lock any dirty buffers on the page */
- do {
- get_bh(bh);
- if (!buffer_mapped(bh))
- continue;
- if (buffer_mapped(bh) && bh->b_blocknr == 0)
- continue;
+static int reiserfs_write_full_page(struct page *page,
+ struct writeback_control *wbc)
+{
+ struct inode *inode = page->mapping->host;
+ unsigned long end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+ int error = 0;
+ unsigned long block;
+ struct buffer_head *head, *bh;
+ int partial = 0;
+ int nr = 0;
+ int checked = PageChecked(page);
+ struct reiserfs_transaction_handle th;
+ struct super_block *s = inode->i_sb;
+ int bh_per_page = PAGE_CACHE_SIZE / s->s_blocksize;
+ th.t_trans_id = 0;
+
+ /* The page dirty bit is cleared before writepage is called, which
+ * means we have to tell create_empty_buffers to make dirty buffers
+ * The page really should be up to date at this point, so tossing
+ * in the BH_Uptodate is just a sanity check.
+ */
+ if (!page_has_buffers(page)) {
+ create_empty_buffers(page, s->s_blocksize,
+ (1 << BH_Dirty) | (1 << BH_Uptodate));
+ }
+ head = page_buffers(page);
- if (checked) {
- reiserfs_prepare_for_journal(s, bh, 1);
- journal_mark_dirty(&th, s, bh);
- continue;
+ /* last page in the file, zero out any contents past the
+ ** last byte in the file
+ */
+ if (page->index >= end_index) {
+ char *kaddr;
+ unsigned last_offset;
+
+ last_offset = inode->i_size & (PAGE_CACHE_SIZE - 1);
+ /* no file contents in this page */
+ if (page->index >= end_index + 1 || !last_offset) {
+ unlock_page(page);
+ return 0;
+ }
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + last_offset, 0, PAGE_CACHE_SIZE - last_offset);
+ flush_dcache_page(page);
+ kunmap_atomic(kaddr, KM_USER0);
}
- /* from this point on, we know the buffer is mapped to a
- * real block and not a direct item
+ bh = head;
+ block = page->index << (PAGE_CACHE_SHIFT - s->s_blocksize_bits);
+ /* first map all the buffers, logging any direct items we find */
+ do {
+ if ((checked || buffer_dirty(bh)) && (!buffer_mapped(bh) ||
+ (buffer_mapped(bh)
+ && bh->b_blocknr ==
+ 0))) {
+ /* not mapped yet, or it points to a direct item, search
+ * the btree for the mapping info, and log any direct
+ * items found
+ */
+ if ((error = map_block_for_writepage(inode, bh, block))) {
+ goto fail;
+ }
+ }
+ bh = bh->b_this_page;
+ block++;
+ } while (bh != head);
+
+ /*
+ * we start the transaction after map_block_for_writepage,
+ * because it can create holes in the file (an unbounded operation).
+ * starting it here, we can make a reliable estimate for how many
+ * blocks we're going to log
*/
- if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
- lock_buffer(bh);
- } else {
- if (test_set_buffer_locked(bh)) {
- redirty_page_for_writepage(wbc, page);
- continue;
- }
+ if (checked) {
+ ClearPageChecked(page);
+ reiserfs_write_lock(s);
+ error = journal_begin(&th, s, bh_per_page + 1);
+ if (error) {
+ reiserfs_write_unlock(s);
+ goto fail;
+ }
+ reiserfs_update_inode_transaction(inode);
}
- if (test_clear_buffer_dirty(bh)) {
- mark_buffer_async_write(bh);
- } else {
- unlock_buffer(bh);
+ /* now go through and lock any dirty buffers on the page */
+ do {
+ get_bh(bh);
+ if (!buffer_mapped(bh))
+ continue;
+ if (buffer_mapped(bh) && bh->b_blocknr == 0)
+ continue;
+
+ if (checked) {
+ reiserfs_prepare_for_journal(s, bh, 1);
+ journal_mark_dirty(&th, s, bh);
+ continue;
+ }
+ /* from this point on, we know the buffer is mapped to a
+ * real block and not a direct item
+ */
+ if (wbc->sync_mode != WB_SYNC_NONE || !wbc->nonblocking) {
+ lock_buffer(bh);
+ } else {
+ if (test_set_buffer_locked(bh)) {
+ redirty_page_for_writepage(wbc, page);
+ continue;
+ }
+ }
+ if (test_clear_buffer_dirty(bh)) {
+ mark_buffer_async_write(bh);
+ } else {
+ unlock_buffer(bh);
+ }
+ } while ((bh = bh->b_this_page) != head);
+
+ if (checked) {
+ error = journal_end(&th, s, bh_per_page + 1);
+ reiserfs_write_unlock(s);
+ if (error)
+ goto fail;
}
- } while((bh = bh->b_this_page) != head);
+ BUG_ON(PageWriteback(page));
+ set_page_writeback(page);
+ unlock_page(page);
- if (checked) {
- error = journal_end(&th, s, bh_per_page + 1);
- reiserfs_write_unlock(s);
- if (error)
- goto fail;
- }
- BUG_ON(PageWriteback(page));
- set_page_writeback(page);
- unlock_page(page);
-
- /*
- * since any buffer might be the only dirty buffer on the page,
- * the first submit_bh can bring the page out of writeback.
- * be careful with the buffers.
- */
- do {
- struct buffer_head *next = bh->b_this_page;
- if (buffer_async_write(bh)) {
- submit_bh(WRITE, bh);
- nr++;
- }
- put_bh(bh);
- bh = next;
- } while(bh != head);
-
- error = 0;
-done:
- if (nr == 0) {
- /*
- * if this page only had a direct item, it is very possible for
- * no io to be required without there being an error. Or,
- * someone else could have locked them and sent them down the
- * pipe without locking the page
+ /*
+ * since any buffer might be the only dirty buffer on the page,
+ * the first submit_bh can bring the page out of writeback.
+ * be careful with the buffers.
*/
- bh = head ;
do {
- if (!buffer_uptodate(bh)) {
- partial = 1;
- break;
- }
- bh = bh->b_this_page;
- } while(bh != head);
- if (!partial)
- SetPageUptodate(page);
- end_page_writeback(page);
- }
- return error;
-
-fail:
- /* catches various errors, we need to make sure any valid dirty blocks
- * get to the media. The page is currently locked and not marked for
- * writeback
- */
- ClearPageUptodate(page);
- bh = head;
- do {
- get_bh(bh);
- if (buffer_mapped(bh) && buffer_dirty(bh) && bh->b_blocknr) {
- lock_buffer(bh);
- mark_buffer_async_write(bh);
- } else {
- /*
- * clear any dirty bits that might have come from getting
- * attached to a dirty page
- */
- clear_buffer_dirty(bh);
- }
- bh = bh->b_this_page;
- } while(bh != head);
- SetPageError(page);
- BUG_ON(PageWriteback(page));
- set_page_writeback(page);
- unlock_page(page);
- do {
- struct buffer_head *next = bh->b_this_page;
- if (buffer_async_write(bh)) {
- clear_buffer_dirty(bh);
- submit_bh(WRITE, bh);
- nr++;
- }
- put_bh(bh);
- bh = next;
- } while(bh != head);
- goto done;
-}
+ struct buffer_head *next = bh->b_this_page;
+ if (buffer_async_write(bh)) {
+ submit_bh(WRITE, bh);
+ nr++;
+ }
+ put_bh(bh);
+ bh = next;
+ } while (bh != head);
+ error = 0;
+ done:
+ if (nr == 0) {
+ /*
+ * if this page only had a direct item, it is very possible for
+ * no io to be required without there being an error. Or,
+ * someone else could have locked them and sent them down the
+ * pipe without locking the page
+ */
+ bh = head;
+ do {
+ if (!buffer_uptodate(bh)) {
+ partial = 1;
+ break;
+ }
+ bh = bh->b_this_page;
+ } while (bh != head);
+ if (!partial)
+ SetPageUptodate(page);
+ end_page_writeback(page);
+ }
+ return error;
-static int reiserfs_readpage (struct file *f, struct page * page)
-{
- return block_read_full_page (page, reiserfs_get_block);
+ fail:
+ /* catches various errors, we need to make sure any valid dirty blocks
+ * get to the media. The page is currently locked and not marked for
+ * writeback
+ */
+ ClearPageUptodate(page);
+ bh = head;
+ do {
+ get_bh(bh);
+ if (buffer_mapped(bh) && buffer_dirty(bh) && bh->b_blocknr) {
+ lock_buffer(bh);
+ mark_buffer_async_write(bh);
+ } else {
+ /*
+ * clear any dirty bits that might have come from getting
+ * attached to a dirty page
+ */
+ clear_buffer_dirty(bh);
+ }
+ bh = bh->b_this_page;
+ } while (bh != head);
+ SetPageError(page);
+ BUG_ON(PageWriteback(page));
+ set_page_writeback(page);
+ unlock_page(page);
+ do {
+ struct buffer_head *next = bh->b_this_page;
+ if (buffer_async_write(bh)) {
+ clear_buffer_dirty(bh);
+ submit_bh(WRITE, bh);
+ nr++;
+ }
+ put_bh(bh);
+ bh = next;
+ } while (bh != head);
+ goto done;
}
+static int reiserfs_readpage(struct file *f, struct page *page)
+{
+ return block_read_full_page(page, reiserfs_get_block);
+}
-static int reiserfs_writepage (struct page * page, struct writeback_control *wbc)
+static int reiserfs_writepage(struct page *page, struct writeback_control *wbc)
{
- struct inode *inode = page->mapping->host ;
- reiserfs_wait_on_write_block(inode->i_sb) ;
- return reiserfs_write_full_page(page, wbc) ;
+ struct inode *inode = page->mapping->host;
+ reiserfs_wait_on_write_block(inode->i_sb);
+ return reiserfs_write_full_page(page, wbc);
}
static int reiserfs_prepare_write(struct file *f, struct page *page,
- unsigned from, unsigned to) {
- struct inode *inode = page->mapping->host ;
- int ret;
- int old_ref = 0;
-
- reiserfs_wait_on_write_block(inode->i_sb) ;
- fix_tail_page_for_writing(page) ;
- if (reiserfs_transaction_running(inode->i_sb)) {
- struct reiserfs_transaction_handle *th;
- th = (struct reiserfs_transaction_handle *)current->journal_info;
- BUG_ON (!th->t_refcount);
- BUG_ON (!th->t_trans_id);
- old_ref = th->t_refcount;
- th->t_refcount++;
- }
-
- ret = block_prepare_write(page, from, to, reiserfs_get_block) ;
- if (ret && reiserfs_transaction_running(inode->i_sb)) {
- struct reiserfs_transaction_handle *th = current->journal_info;
- /* this gets a little ugly. If reiserfs_get_block returned an
- * error and left a transacstion running, we've got to close it,
- * and we've got to free handle if it was a persistent transaction.
- *
- * But, if we had nested into an existing transaction, we need
- * to just drop the ref count on the handle.
- *
- * If old_ref == 0, the transaction is from reiserfs_get_block,
- * and it was a persistent trans. Otherwise, it was nested above.
- */
- if (th->t_refcount > old_ref) {
- if (old_ref)
- th->t_refcount--;
- else {
- int err;
- reiserfs_write_lock(inode->i_sb);
- err = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
- if (err)
- ret = err;
- }
+ unsigned from, unsigned to)
+{
+ struct inode *inode = page->mapping->host;
+ int ret;
+ int old_ref = 0;
+
+ reiserfs_wait_on_write_block(inode->i_sb);
+ fix_tail_page_for_writing(page);
+ if (reiserfs_transaction_running(inode->i_sb)) {
+ struct reiserfs_transaction_handle *th;
+ th = (struct reiserfs_transaction_handle *)current->
+ journal_info;
+ BUG_ON(!th->t_refcount);
+ BUG_ON(!th->t_trans_id);
+ old_ref = th->t_refcount;
+ th->t_refcount++;
}
- }
- return ret;
-}
+ ret = block_prepare_write(page, from, to, reiserfs_get_block);
+ if (ret && reiserfs_transaction_running(inode->i_sb)) {
+ struct reiserfs_transaction_handle *th = current->journal_info;
+ /* this gets a little ugly. If reiserfs_get_block returned an
+ * error and left a transacstion running, we've got to close it,
+ * and we've got to free handle if it was a persistent transaction.
+ *
+ * But, if we had nested into an existing transaction, we need
+ * to just drop the ref count on the handle.
+ *
+ * If old_ref == 0, the transaction is from reiserfs_get_block,
+ * and it was a persistent trans. Otherwise, it was nested above.
+ */
+ if (th->t_refcount > old_ref) {
+ if (old_ref)
+ th->t_refcount--;
+ else {
+ int err;
+ reiserfs_write_lock(inode->i_sb);
+ err = reiserfs_end_persistent_transaction(th);
+ reiserfs_write_unlock(inode->i_sb);
+ if (err)
+ ret = err;
+ }
+ }
+ }
+ return ret;
+}
-static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block) {
- return generic_block_bmap(as, block, reiserfs_bmap) ;
+static sector_t reiserfs_aop_bmap(struct address_space *as, sector_t block)
+{
+ return generic_block_bmap(as, block, reiserfs_bmap);
}
-static int reiserfs_commit_write(struct file *f, struct page *page,
- unsigned from, unsigned to) {
- struct inode *inode = page->mapping->host ;
- loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
- int ret = 0;
- int update_sd = 0;
- struct reiserfs_transaction_handle *th = NULL;
-
- reiserfs_wait_on_write_block(inode->i_sb) ;
- if (reiserfs_transaction_running(inode->i_sb)) {
- th = current->journal_info;
- }
- reiserfs_commit_page(inode, page, from, to);
-
- /* generic_commit_write does this for us, but does not update the
- ** transaction tracking stuff when the size changes. So, we have
- ** to do the i_size updates here.
- */
- if (pos > inode->i_size) {
- struct reiserfs_transaction_handle myth ;
- reiserfs_write_lock(inode->i_sb);
- /* If the file have grown beyond the border where it
- can have a tail, unmark it as needing a tail
- packing */
- if ( (have_large_tails (inode->i_sb) && inode->i_size > i_block_size (inode)*4) ||
- (have_small_tails (inode->i_sb) && inode->i_size > i_block_size(inode)) )
- REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask ;
-
- ret = journal_begin(&myth, inode->i_sb, 1) ;
- if (ret) {
- reiserfs_write_unlock(inode->i_sb);
- goto journal_error;
- }
- reiserfs_update_inode_transaction(inode) ;
- inode->i_size = pos ;
- reiserfs_update_sd(&myth, inode) ;
- update_sd = 1;
- ret = journal_end(&myth, inode->i_sb, 1) ;
- reiserfs_write_unlock(inode->i_sb);
- if (ret)
- goto journal_error;
- }
- if (th) {
- reiserfs_write_lock(inode->i_sb);
- if (!update_sd)
- reiserfs_update_sd(th, inode) ;
- ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
- if (ret)
- goto out;
- }
-
- /* we test for O_SYNC here so we can commit the transaction
- ** for any packed tails the file might have had
- */
- if (f && (f->f_flags & O_SYNC)) {
- reiserfs_write_lock(inode->i_sb);
- ret = reiserfs_commit_for_inode(inode) ;
- reiserfs_write_unlock(inode->i_sb);
- }
-out:
- return ret ;
+static int reiserfs_commit_write(struct file *f, struct page *page,
+ unsigned from, unsigned to)
+{
+ struct inode *inode = page->mapping->host;
+ loff_t pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to;
+ int ret = 0;
+ int update_sd = 0;
+ struct reiserfs_transaction_handle *th = NULL;
+
+ reiserfs_wait_on_write_block(inode->i_sb);
+ if (reiserfs_transaction_running(inode->i_sb)) {
+ th = current->journal_info;
+ }
+ reiserfs_commit_page(inode, page, from, to);
-journal_error:
- if (th) {
- reiserfs_write_lock(inode->i_sb);
- if (!update_sd)
- reiserfs_update_sd(th, inode) ;
- ret = reiserfs_end_persistent_transaction(th);
- reiserfs_write_unlock(inode->i_sb);
- }
+ /* generic_commit_write does this for us, but does not update the
+ ** transaction tracking stuff when the size changes. So, we have
+ ** to do the i_size updates here.
+ */
+ if (pos > inode->i_size) {
+ struct reiserfs_transaction_handle myth;
+ reiserfs_write_lock(inode->i_sb);
+ /* If the file have grown beyond the border where it
+ can have a tail, unmark it as needing a tail
+ packing */
+ if ((have_large_tails(inode->i_sb)
+ && inode->i_size > i_block_size(inode) * 4)
+ || (have_small_tails(inode->i_sb)
+ && inode->i_size > i_block_size(inode)))
+ REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask;
+
+ ret = journal_begin(&myth, inode->i_sb, 1);
+ if (ret) {
+ reiserfs_write_unlock(inode->i_sb);
+ goto journal_error;
+ }
+ reiserfs_update_inode_transaction(inode);
+ inode->i_size = pos;
+ reiserfs_update_sd(&myth, inode);
+ update_sd = 1;
+ ret = journal_end(&myth, inode->i_sb, 1);
+ reiserfs_write_unlock(inode->i_sb);
+ if (ret)
+ goto journal_error;
+ }
+ if (th) {
+ reiserfs_write_lock(inode->i_sb);
+ if (!update_sd)
+ reiserfs_update_sd(th, inode);
+ ret = reiserfs_end_persistent_transaction(th);
+ reiserfs_write_unlock(inode->i_sb);
+ if (ret)
+ goto out;
+ }
+
+ /* we test for O_SYNC here so we can commit the transaction
+ ** for any packed tails the file might have had
+ */
+ if (f && (f->f_flags & O_SYNC)) {
+ reiserfs_write_lock(inode->i_sb);
+ ret = reiserfs_commit_for_inode(inode);
+ reiserfs_write_unlock(inode->i_sb);
+ }
+ out:
+ return ret;
- return ret;
+ journal_error:
+ if (th) {
+ reiserfs_write_lock(inode->i_sb);
+ if (!update_sd)
+ reiserfs_update_sd(th, inode);
+ ret = reiserfs_end_persistent_transaction(th);
+ reiserfs_write_unlock(inode->i_sb);
+ }
+
+ return ret;
}
-void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode )
+void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode)
{
- if( reiserfs_attrs( inode -> i_sb ) ) {
- if( sd_attrs & REISERFS_SYNC_FL )
- inode -> i_flags |= S_SYNC;
+ if (reiserfs_attrs(inode->i_sb)) {
+ if (sd_attrs & REISERFS_SYNC_FL)
+ inode->i_flags |= S_SYNC;
else
- inode -> i_flags &= ~S_SYNC;
- if( sd_attrs & REISERFS_IMMUTABLE_FL )
- inode -> i_flags |= S_IMMUTABLE;
+ inode->i_flags &= ~S_SYNC;
+ if (sd_attrs & REISERFS_IMMUTABLE_FL)
+ inode->i_flags |= S_IMMUTABLE;
else
- inode -> i_flags &= ~S_IMMUTABLE;
- if( sd_attrs & REISERFS_APPEND_FL )
- inode -> i_flags |= S_APPEND;
+ inode->i_flags &= ~S_IMMUTABLE;
+ if (sd_attrs & REISERFS_APPEND_FL)
+ inode->i_flags |= S_APPEND;
else
- inode -> i_flags &= ~S_APPEND;
- if( sd_attrs & REISERFS_NOATIME_FL )
- inode -> i_flags |= S_NOATIME;
+ inode->i_flags &= ~S_APPEND;
+ if (sd_attrs & REISERFS_NOATIME_FL)
+ inode->i_flags |= S_NOATIME;
else
- inode -> i_flags &= ~S_NOATIME;
- if( sd_attrs & REISERFS_NOTAIL_FL )
+ inode->i_flags &= ~S_NOATIME;
+ if (sd_attrs & REISERFS_NOTAIL_FL)
REISERFS_I(inode)->i_flags |= i_nopack_mask;
else
REISERFS_I(inode)->i_flags &= ~i_nopack_mask;
}
}
-void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
+void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs)
{
- if( reiserfs_attrs( inode -> i_sb ) ) {
- if( inode -> i_flags & S_IMMUTABLE )
+ if (reiserfs_attrs(inode->i_sb)) {
+ if (inode->i_flags & S_IMMUTABLE)
*sd_attrs |= REISERFS_IMMUTABLE_FL;
else
*sd_attrs &= ~REISERFS_IMMUTABLE_FL;
- if( inode -> i_flags & S_SYNC )
+ if (inode->i_flags & S_SYNC)
*sd_attrs |= REISERFS_SYNC_FL;
else
*sd_attrs &= ~REISERFS_SYNC_FL;
- if( inode -> i_flags & S_NOATIME )
+ if (inode->i_flags & S_NOATIME)
*sd_attrs |= REISERFS_NOATIME_FL;
else
*sd_attrs &= ~REISERFS_NOATIME_FL;
- if( REISERFS_I(inode)->i_flags & i_nopack_mask )
+ if (REISERFS_I(inode)->i_flags & i_nopack_mask)
*sd_attrs |= REISERFS_NOTAIL_FL;
else
*sd_attrs &= ~REISERFS_NOTAIL_FL;
@@ -2594,106 +2720,107 @@ void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs )
*/
static int invalidatepage_can_drop(struct inode *inode, struct buffer_head *bh)
{
- int ret = 1 ;
- struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ;
-
- spin_lock(&j->j_dirty_buffers_lock) ;
- if (!buffer_mapped(bh)) {
- goto free_jh;
- }
- /* the page is locked, and the only places that log a data buffer
- * also lock the page.
- */
- if (reiserfs_file_data_log(inode)) {
- /*
- * very conservative, leave the buffer pinned if
- * anyone might need it.
- */
- if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
- ret = 0 ;
- }
- } else
- if (buffer_dirty(bh) || buffer_locked(bh)) {
- struct reiserfs_journal_list *jl;
- struct reiserfs_jh *jh = bh->b_private;
-
- /* why is this safe?
- * reiserfs_setattr updates i_size in the on disk
- * stat data before allowing vmtruncate to be called.
- *
- * If buffer was put onto the ordered list for this
- * transaction, we know for sure either this transaction
- * or an older one already has updated i_size on disk,
- * and this ordered data won't be referenced in the file
- * if we crash.
- *
- * if the buffer was put onto the ordered list for an older
- * transaction, we need to leave it around
+ int ret = 1;
+ struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb);
+
+ spin_lock(&j->j_dirty_buffers_lock);
+ if (!buffer_mapped(bh)) {
+ goto free_jh;
+ }
+ /* the page is locked, and the only places that log a data buffer
+ * also lock the page.
*/
- if (jh && (jl = jh->jl) && jl != SB_JOURNAL(inode->i_sb)->j_current_jl)
- ret = 0;
- }
-free_jh:
- if (ret && bh->b_private) {
- reiserfs_free_jh(bh);
- }
- spin_unlock(&j->j_dirty_buffers_lock) ;
- return ret ;
+ if (reiserfs_file_data_log(inode)) {
+ /*
+ * very conservative, leave the buffer pinned if
+ * anyone might need it.
+ */
+ if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
+ ret = 0;
+ }
+ } else if (buffer_dirty(bh) || buffer_locked(bh)) {
+ struct reiserfs_journal_list *jl;
+ struct reiserfs_jh *jh = bh->b_private;
+
+ /* why is this safe?
+ * reiserfs_setattr updates i_size in the on disk
+ * stat data before allowing vmtruncate to be called.
+ *
+ * If buffer was put onto the ordered list for this
+ * transaction, we know for sure either this transaction
+ * or an older one already has updated i_size on disk,
+ * and this ordered data won't be referenced in the file
+ * if we crash.
+ *
+ * if the buffer was put onto the ordered list for an older
+ * transaction, we need to leave it around
+ */
+ if (jh && (jl = jh->jl)
+ && jl != SB_JOURNAL(inode->i_sb)->j_current_jl)
+ ret = 0;
+ }
+ free_jh:
+ if (ret && bh->b_private) {
+ reiserfs_free_jh(bh);
+ }
+ spin_unlock(&j->j_dirty_buffers_lock);
+ return ret;
}
/* clm -- taken from fs/buffer.c:block_invalidate_page */
static int reiserfs_invalidatepage(struct page *page, unsigned long offset)
{
- struct buffer_head *head, *bh, *next;
- struct inode *inode = page->mapping->host;
- unsigned int curr_off = 0;
- int ret = 1;
+ struct buffer_head *head, *bh, *next;
+ struct inode *inode = page->mapping->host;
+ unsigned int curr_off = 0;
+ int ret = 1;
- BUG_ON(!PageLocked(page));
+ BUG_ON(!PageLocked(page));
- if (offset == 0)
- ClearPageChecked(page);
+ if (offset == 0)
+ ClearPageChecked(page);
- if (!page_has_buffers(page))
- goto out;
+ if (!page_has_buffers(page))
+ goto out;
+
+ head = page_buffers(page);
+ bh = head;
+ do {
+ unsigned int next_off = curr_off + bh->b_size;
+ next = bh->b_this_page;
- head = page_buffers(page);
- bh = head;
- do {
- unsigned int next_off = curr_off + bh->b_size;
- next = bh->b_this_page;
+ /*
+ * is this block fully invalidated?
+ */
+ if (offset <= curr_off) {
+ if (invalidatepage_can_drop(inode, bh))
+ reiserfs_unmap_buffer(bh);
+ else
+ ret = 0;
+ }
+ curr_off = next_off;
+ bh = next;
+ } while (bh != head);
/*
- * is this block fully invalidated?
+ * We release buffers only if the entire page is being invalidated.
+ * The get_block cached value has been unconditionally invalidated,
+ * so real IO is not possible anymore.
*/
- if (offset <= curr_off) {
- if (invalidatepage_can_drop(inode, bh))
- reiserfs_unmap_buffer(bh);
- else
- ret = 0;
- }
- curr_off = next_off;
- bh = next;
- } while (bh != head);
-
- /*
- * We release buffers only if the entire page is being invalidated.
- * The get_block cached value has been unconditionally invalidated,
- * so real IO is not possible anymore.
- */
- if (!offset && ret)
- ret = try_to_release_page(page, 0);
-out:
- return ret;
+ if (!offset && ret)
+ ret = try_to_release_page(page, 0);
+ out:
+ return ret;
}
-static int reiserfs_set_page_dirty(struct page *page) {
- struct inode *inode = page->mapping->host;
- if (reiserfs_file_data_log(inode)) {
- SetPageChecked(page);
- return __set_page_dirty_nobuffers(page);
- }
- return __set_page_dirty_buffers(page);
+static int reiserfs_set_page_dirty(struct page *page)
+{
+ struct inode *inode = page->mapping->host;
+ if (reiserfs_file_data_log(inode)) {
+ SetPageChecked(page);
+ return __set_page_dirty_nobuffers(page);
+ }
+ return __set_page_dirty_buffers(page);
}
/*
@@ -2707,140 +2834,152 @@ static int reiserfs_set_page_dirty(struct page *page) {
*/
static int reiserfs_releasepage(struct page *page, int unused_gfp_flags)
{
- struct inode *inode = page->mapping->host ;
- struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb) ;
- struct buffer_head *head ;
- struct buffer_head *bh ;
- int ret = 1 ;
-
- WARN_ON(PageChecked(page));
- spin_lock(&j->j_dirty_buffers_lock) ;
- head = page_buffers(page) ;
- bh = head ;
- do {
- if (bh->b_private) {
- if (!buffer_dirty(bh) && !buffer_locked(bh)) {
- reiserfs_free_jh(bh);
- } else {
- ret = 0 ;
- break ;
- }
- }
- bh = bh->b_this_page ;
- } while (bh != head) ;
- if (ret)
- ret = try_to_free_buffers(page) ;
- spin_unlock(&j->j_dirty_buffers_lock) ;
- return ret ;
+ struct inode *inode = page->mapping->host;
+ struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb);
+ struct buffer_head *head;
+ struct buffer_head *bh;
+ int ret = 1;
+
+ WARN_ON(PageChecked(page));
+ spin_lock(&j->j_dirty_buffers_lock);
+ head = page_buffers(page);
+ bh = head;
+ do {
+ if (bh->b_private) {
+ if (!buffer_dirty(bh) && !buffer_locked(bh)) {
+ reiserfs_free_jh(bh);
+ } else {
+ ret = 0;
+ break;
+ }
+ }
+ bh = bh->b_this_page;
+ } while (bh != head);
+ if (ret)
+ ret = try_to_free_buffers(page);
+ spin_unlock(&j->j_dirty_buffers_lock);
+ return ret;
}
/* We thank Mingming Cao for helping us understand in great detail what
to do in this section of the code. */
static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb,
- const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+ const struct iovec *iov, loff_t offset,
+ unsigned long nr_segs)
{
- struct file *file = iocb->ki_filp;
- struct inode *inode = file->f_mapping->host;
+ struct file *file = iocb->ki_filp;
+ struct inode *inode = file->f_mapping->host;
- return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
- offset, nr_segs, reiserfs_get_blocks_direct_io, NULL);
+ return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
+ offset, nr_segs,
+ reiserfs_get_blocks_direct_io, NULL);
}
-int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) {
- struct inode *inode = dentry->d_inode ;
- int error ;
- unsigned int ia_valid = attr->ia_valid;
- reiserfs_write_lock(inode->i_sb);
- if (attr->ia_valid & ATTR_SIZE) {
- /* version 2 items will be caught by the s_maxbytes check
- ** done for us in vmtruncate
- */
- if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
- attr->ia_size > MAX_NON_LFS) {
- error = -EFBIG ;
- goto out;
- }
- /* fill in hole pointers in the expanding truncate case. */
- if (attr->ia_size > inode->i_size) {
- error = generic_cont_expand(inode, attr->ia_size) ;
- if (REISERFS_I(inode)->i_prealloc_count > 0) {
- int err;
- struct reiserfs_transaction_handle th ;
- /* we're changing at most 2 bitmaps, inode + super */
- err = journal_begin(&th, inode->i_sb, 4) ;
- if (!err) {
- reiserfs_discard_prealloc (&th, inode);
- err = journal_end(&th, inode->i_sb, 4) ;
+int reiserfs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+ struct inode *inode = dentry->d_inode;
+ int error;
+ unsigned int ia_valid = attr->ia_valid;
+ reiserfs_write_lock(inode->i_sb);
+ if (attr->ia_valid & ATTR_SIZE) {
+ /* version 2 items will be caught by the s_maxbytes check
+ ** done for us in vmtruncate
+ */
+ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5 &&
+ attr->ia_size > MAX_NON_LFS) {
+ error = -EFBIG;
+ goto out;
+ }
+ /* fill in hole pointers in the expanding truncate case. */
+ if (attr->ia_size > inode->i_size) {
+ error = generic_cont_expand(inode, attr->ia_size);
+ if (REISERFS_I(inode)->i_prealloc_count > 0) {
+ int err;
+ struct reiserfs_transaction_handle th;
+ /* we're changing at most 2 bitmaps, inode + super */
+ err = journal_begin(&th, inode->i_sb, 4);
+ if (!err) {
+ reiserfs_discard_prealloc(&th, inode);
+ err = journal_end(&th, inode->i_sb, 4);
+ }
+ if (err)
+ error = err;
+ }
+ if (error)
+ goto out;
}
- if (err)
- error = err;
- }
- if (error)
- goto out;
}
- }
- if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
- ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
- (get_inode_sd_version (inode) == STAT_DATA_V1)) {
+ if ((((attr->ia_valid & ATTR_UID) && (attr->ia_uid & ~0xffff)) ||
+ ((attr->ia_valid & ATTR_GID) && (attr->ia_gid & ~0xffff))) &&
+ (get_inode_sd_version(inode) == STAT_DATA_V1)) {
/* stat data of format v3.5 has 16 bit uid and gid */
- error = -EINVAL;
- goto out;
+ error = -EINVAL;
+ goto out;
}
- error = inode_change_ok(inode, attr) ;
- if (!error) {
- if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
- (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
- error = reiserfs_chown_xattrs (inode, attr);
-
- if (!error) {
- struct reiserfs_transaction_handle th;
-
- /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
- journal_begin(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
- error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
- if (error) {
- journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
- goto out;
- }
- /* Update corresponding info in inode so that everything is in
- * one transaction */
- if (attr->ia_valid & ATTR_UID)
- inode->i_uid = attr->ia_uid;
- if (attr->ia_valid & ATTR_GID)
- inode->i_gid = attr->ia_gid;
- mark_inode_dirty(inode);
- journal_end(&th, inode->i_sb, 4*REISERFS_QUOTA_INIT_BLOCKS+2);
+ error = inode_change_ok(inode, attr);
+ if (!error) {
+ if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
+ (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) {
+ error = reiserfs_chown_xattrs(inode, attr);
+
+ if (!error) {
+ struct reiserfs_transaction_handle th;
+ int jbegin_count =
+ 2 *
+ (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) +
+ REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) +
+ 2;
+
+ /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */
+ error =
+ journal_begin(&th, inode->i_sb,
+ jbegin_count);
+ if (error)
+ goto out;
+ error =
+ DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
+ if (error) {
+ journal_end(&th, inode->i_sb,
+ jbegin_count);
+ goto out;
+ }
+ /* Update corresponding info in inode so that everything is in
+ * one transaction */
+ if (attr->ia_valid & ATTR_UID)
+ inode->i_uid = attr->ia_uid;
+ if (attr->ia_valid & ATTR_GID)
+ inode->i_gid = attr->ia_gid;
+ mark_inode_dirty(inode);
+ error =
+ journal_end(&th, inode->i_sb, jbegin_count);
+ }
}
- }
- if (!error)
- error = inode_setattr(inode, attr) ;
- }
-
+ if (!error)
+ error = inode_setattr(inode, attr);
+ }
- if (!error && reiserfs_posixacl (inode->i_sb)) {
- if (attr->ia_valid & ATTR_MODE)
- error = reiserfs_acl_chmod (inode);
- }
+ if (!error && reiserfs_posixacl(inode->i_sb)) {
+ if (attr->ia_valid & ATTR_MODE)
+ error = reiserfs_acl_chmod(inode);
+ }
-out:
- reiserfs_write_unlock(inode->i_sb);
- return error ;
+ out:
+ reiserfs_write_unlock(inode->i_sb);
+ return error;
}
-
-
struct address_space_operations reiserfs_address_space_operations = {
- .writepage = reiserfs_writepage,
- .readpage = reiserfs_readpage,
- .readpages = reiserfs_readpages,
- .releasepage = reiserfs_releasepage,
- .invalidatepage = reiserfs_invalidatepage,
- .sync_page = block_sync_page,
- .prepare_write = reiserfs_prepare_write,
- .commit_write = reiserfs_commit_write,
- .bmap = reiserfs_aop_bmap,
- .direct_IO = reiserfs_direct_IO,
- .set_page_dirty = reiserfs_set_page_dirty,
-} ;
+ .writepage = reiserfs_writepage,
+ .readpage = reiserfs_readpage,
+ .readpages = reiserfs_readpages,
+ .releasepage = reiserfs_releasepage,
+ .invalidatepage = reiserfs_invalidatepage,
+ .sync_page = block_sync_page,
+ .prepare_write = reiserfs_prepare_write,
+ .commit_write = reiserfs_commit_write,
+ .bmap = reiserfs_aop_bmap,
+ .direct_IO = reiserfs_direct_IO,
+ .set_page_dirty = reiserfs_set_page_dirty,
+};
diff --git a/fs/reiserfs/ioctl.c b/fs/reiserfs/ioctl.c
index 94dc42475a04..81fc00285f60 100644
--- a/fs/reiserfs/ioctl.c
+++ b/fs/reiserfs/ioctl.c
@@ -9,7 +9,7 @@
#include <linux/pagemap.h>
#include <linux/smp_lock.h>
-static int reiserfs_unpack (struct inode * inode, struct file * filp);
+static int reiserfs_unpack(struct inode *inode, struct file *filp);
/*
** reiserfs_ioctl - handler for ioctl for inode
@@ -19,63 +19,72 @@ static int reiserfs_unpack (struct inode * inode, struct file * filp);
** 2) REISERFS_IOC_[GS]ETFLAGS, REISERFS_IOC_[GS]ETVERSION
** 3) That's all for a while ...
*/
-int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
- unsigned long arg)
+int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
unsigned int flags;
switch (cmd) {
- case REISERFS_IOC_UNPACK:
- if( S_ISREG( inode -> i_mode ) ) {
- if (arg)
- return reiserfs_unpack (inode, filp);
+ case REISERFS_IOC_UNPACK:
+ if (S_ISREG(inode->i_mode)) {
+ if (arg)
+ return reiserfs_unpack(inode, filp);
else
return 0;
} else
return -ENOTTY;
- /* following two cases are taken from fs/ext2/ioctl.c by Remy
- Card (card@masi.ibp.fr) */
+ /* following two cases are taken from fs/ext2/ioctl.c by Remy
+ Card (card@masi.ibp.fr) */
case REISERFS_IOC_GETFLAGS:
- flags = REISERFS_I(inode) -> i_attrs;
- i_attrs_to_sd_attrs( inode, ( __u16 * ) &flags );
- return put_user(flags, (int __user *) arg);
- case REISERFS_IOC_SETFLAGS: {
- if (IS_RDONLY(inode))
- return -EROFS;
+ if (!reiserfs_attrs(inode->i_sb))
+ return -ENOTTY;
- if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
- return -EPERM;
+ flags = REISERFS_I(inode)->i_attrs;
+ i_attrs_to_sd_attrs(inode, (__u16 *) & flags);
+ return put_user(flags, (int __user *)arg);
+ case REISERFS_IOC_SETFLAGS:{
+ if (!reiserfs_attrs(inode->i_sb))
+ return -ENOTTY;
- if (get_user(flags, (int __user *) arg))
- return -EFAULT;
+ if (IS_RDONLY(inode))
+ return -EROFS;
- if ( ( ( flags ^ REISERFS_I(inode) -> i_attrs) & ( REISERFS_IMMUTABLE_FL | REISERFS_APPEND_FL)) &&
- !capable( CAP_LINUX_IMMUTABLE ) )
- return -EPERM;
-
- if( ( flags & REISERFS_NOTAIL_FL ) &&
- S_ISREG( inode -> i_mode ) ) {
+ if ((current->fsuid != inode->i_uid)
+ && !capable(CAP_FOWNER))
+ return -EPERM;
+
+ if (get_user(flags, (int __user *)arg))
+ return -EFAULT;
+
+ if (((flags ^ REISERFS_I(inode)->
+ i_attrs) & (REISERFS_IMMUTABLE_FL |
+ REISERFS_APPEND_FL))
+ && !capable(CAP_LINUX_IMMUTABLE))
+ return -EPERM;
+
+ if ((flags & REISERFS_NOTAIL_FL) &&
+ S_ISREG(inode->i_mode)) {
int result;
- result = reiserfs_unpack( inode, filp );
- if( result )
+ result = reiserfs_unpack(inode, filp);
+ if (result)
return result;
+ }
+ sd_attrs_to_i_attrs(flags, inode);
+ REISERFS_I(inode)->i_attrs = flags;
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+ return 0;
}
- sd_attrs_to_i_attrs( flags, inode );
- REISERFS_I(inode) -> i_attrs = flags;
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty(inode);
- return 0;
- }
case REISERFS_IOC_GETVERSION:
- return put_user(inode->i_generation, (int __user *) arg);
+ return put_user(inode->i_generation, (int __user *)arg);
case REISERFS_IOC_SETVERSION:
if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
return -EPERM;
if (IS_RDONLY(inode))
return -EROFS;
- if (get_user(inode->i_generation, (int __user *) arg))
- return -EFAULT;
+ if (get_user(inode->i_generation, (int __user *)arg))
+ return -EFAULT;
inode->i_ctime = CURRENT_TIME_SEC;
mark_inode_dirty(inode);
return 0;
@@ -89,63 +98,65 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
** Function try to convert tail from direct item into indirect.
** It set up nopack attribute in the REISERFS_I(inode)->nopack
*/
-static int reiserfs_unpack (struct inode * inode, struct file * filp)
+static int reiserfs_unpack(struct inode *inode, struct file *filp)
{
- int retval = 0;
- int index ;
- struct page *page ;
- struct address_space *mapping ;
- unsigned long write_from ;
- unsigned long blocksize = inode->i_sb->s_blocksize ;
-
- if (inode->i_size == 0) {
- REISERFS_I(inode)->i_flags |= i_nopack_mask;
- return 0 ;
- }
- /* ioctl already done */
- if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
- return 0 ;
- }
- reiserfs_write_lock(inode->i_sb);
-
- /* we need to make sure nobody is changing the file size beneath
- ** us
- */
- down(&inode->i_sem) ;
-
- write_from = inode->i_size & (blocksize - 1) ;
- /* if we are on a block boundary, we are already unpacked. */
- if ( write_from == 0) {
+ int retval = 0;
+ int index;
+ struct page *page;
+ struct address_space *mapping;
+ unsigned long write_from;
+ unsigned long blocksize = inode->i_sb->s_blocksize;
+
+ if (inode->i_size == 0) {
+ REISERFS_I(inode)->i_flags |= i_nopack_mask;
+ return 0;
+ }
+ /* ioctl already done */
+ if (REISERFS_I(inode)->i_flags & i_nopack_mask) {
+ return 0;
+ }
+ reiserfs_write_lock(inode->i_sb);
+
+ /* we need to make sure nobody is changing the file size beneath
+ ** us
+ */
+ down(&inode->i_sem);
+
+ write_from = inode->i_size & (blocksize - 1);
+ /* if we are on a block boundary, we are already unpacked. */
+ if (write_from == 0) {
+ REISERFS_I(inode)->i_flags |= i_nopack_mask;
+ goto out;
+ }
+
+ /* we unpack by finding the page with the tail, and calling
+ ** reiserfs_prepare_write on that page. This will force a
+ ** reiserfs_get_block to unpack the tail for us.
+ */
+ index = inode->i_size >> PAGE_CACHE_SHIFT;
+ mapping = inode->i_mapping;
+ page = grab_cache_page(mapping, index);
+ retval = -ENOMEM;
+ if (!page) {
+ goto out;
+ }
+ retval =
+ mapping->a_ops->prepare_write(NULL, page, write_from, write_from);
+ if (retval)
+ goto out_unlock;
+
+ /* conversion can change page contents, must flush */
+ flush_dcache_page(page);
+ retval =
+ mapping->a_ops->commit_write(NULL, page, write_from, write_from);
REISERFS_I(inode)->i_flags |= i_nopack_mask;
- goto out ;
- }
-
- /* we unpack by finding the page with the tail, and calling
- ** reiserfs_prepare_write on that page. This will force a
- ** reiserfs_get_block to unpack the tail for us.
- */
- index = inode->i_size >> PAGE_CACHE_SHIFT ;
- mapping = inode->i_mapping ;
- page = grab_cache_page(mapping, index) ;
- retval = -ENOMEM;
- if (!page) {
- goto out ;
- }
- retval = mapping->a_ops->prepare_write(NULL, page, write_from, write_from) ;
- if (retval)
- goto out_unlock ;
-
- /* conversion can change page contents, must flush */
- flush_dcache_page(page) ;
- retval = mapping->a_ops->commit_write(NULL, page, write_from, write_from) ;
- REISERFS_I(inode)->i_flags |= i_nopack_mask;
-
-out_unlock:
- unlock_page(page) ;
- page_cache_release(page) ;
-
-out:
- up(&inode->i_sem) ;
- reiserfs_write_unlock(inode->i_sb);
- return retval;
+
+ out_unlock:
+ unlock_page(page);
+ page_cache_release(page);
+
+ out:
+ up(&inode->i_sem);
+ reiserfs_write_unlock(inode->i_sb);
+ return retval;
}
diff --git a/fs/reiserfs/item_ops.c b/fs/reiserfs/item_ops.c
index 0ce33db1acdf..e237cd668e5b 100644
--- a/fs/reiserfs/item_ops.c
+++ b/fs/reiserfs/item_ops.c
@@ -14,776 +14,741 @@
//////////////////////////////////////////////////////////////////////////////
// stat data functions
//
-static int sd_bytes_number (struct item_head * ih, int block_size)
+static int sd_bytes_number(struct item_head *ih, int block_size)
{
- return 0;
+ return 0;
}
-static void sd_decrement_key (struct cpu_key * key)
+static void sd_decrement_key(struct cpu_key *key)
{
- key->on_disk_key.k_objectid --;
- set_cpu_key_k_type (key, TYPE_ANY);
- set_cpu_key_k_offset(key, (loff_t)(-1));
+ key->on_disk_key.k_objectid--;
+ set_cpu_key_k_type(key, TYPE_ANY);
+ set_cpu_key_k_offset(key, (loff_t) (-1));
}
-static int sd_is_left_mergeable (struct reiserfs_key * key, unsigned long bsize)
+static int sd_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize)
{
- return 0;
+ return 0;
}
-
-
-static char * print_time (time_t t)
+static char *print_time(time_t t)
{
- static char timebuf[256];
+ static char timebuf[256];
- sprintf (timebuf, "%ld", t);
- return timebuf;
+ sprintf(timebuf, "%ld", t);
+ return timebuf;
}
-
-static void sd_print_item (struct item_head * ih, char * item)
+static void sd_print_item(struct item_head *ih, char *item)
{
- printk ("\tmode | size | nlinks | first direct | mtime\n");
- if (stat_data_v1 (ih)) {
- struct stat_data_v1 * sd = (struct stat_data_v1 *)item;
+ printk("\tmode | size | nlinks | first direct | mtime\n");
+ if (stat_data_v1(ih)) {
+ struct stat_data_v1 *sd = (struct stat_data_v1 *)item;
- printk ("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd),
- sd_v1_size(sd), sd_v1_nlink(sd), sd_v1_first_direct_byte(sd),
- print_time( sd_v1_mtime(sd) ) );
- } else {
- struct stat_data * sd = (struct stat_data *)item;
+ printk("\t0%-6o | %6u | %2u | %d | %s\n", sd_v1_mode(sd),
+ sd_v1_size(sd), sd_v1_nlink(sd),
+ sd_v1_first_direct_byte(sd),
+ print_time(sd_v1_mtime(sd)));
+ } else {
+ struct stat_data *sd = (struct stat_data *)item;
- printk ("\t0%-6o | %6Lu | %2u | %d | %s\n", sd_v2_mode(sd),
- (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
- sd_v2_rdev(sd), print_time(sd_v2_mtime(sd)));
- }
+ printk("\t0%-6o | %6Lu | %2u | %d | %s\n", sd_v2_mode(sd),
+ (unsigned long long)sd_v2_size(sd), sd_v2_nlink(sd),
+ sd_v2_rdev(sd), print_time(sd_v2_mtime(sd)));
+ }
}
-static void sd_check_item (struct item_head * ih, char * item)
+static void sd_check_item(struct item_head *ih, char *item)
{
- // FIXME: type something here!
+ // FIXME: type something here!
}
-
-static int sd_create_vi (struct virtual_node * vn,
- struct virtual_item * vi,
- int is_affected,
- int insert_size)
+static int sd_create_vi(struct virtual_node *vn,
+ struct virtual_item *vi,
+ int is_affected, int insert_size)
{
- vi->vi_index = TYPE_STAT_DATA;
- //vi->vi_type |= VI_TYPE_STAT_DATA;// not needed?
- return 0;
+ vi->vi_index = TYPE_STAT_DATA;
+ //vi->vi_type |= VI_TYPE_STAT_DATA;// not needed?
+ return 0;
}
-
-static int sd_check_left (struct virtual_item * vi, int free,
- int start_skip, int end_skip)
+static int sd_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
{
- if (start_skip || end_skip)
- BUG ();
- return -1;
+ if (start_skip || end_skip)
+ BUG();
+ return -1;
}
-
-static int sd_check_right (struct virtual_item * vi, int free)
+static int sd_check_right(struct virtual_item *vi, int free)
{
- return -1;
+ return -1;
}
-static int sd_part_size (struct virtual_item * vi, int first, int count)
+static int sd_part_size(struct virtual_item *vi, int first, int count)
{
- if (count)
- BUG ();
- return 0;
+ if (count)
+ BUG();
+ return 0;
}
-static int sd_unit_num (struct virtual_item * vi)
+static int sd_unit_num(struct virtual_item *vi)
{
- return vi->vi_item_len - IH_SIZE;
+ return vi->vi_item_len - IH_SIZE;
}
-
-static void sd_print_vi (struct virtual_item * vi)
+static void sd_print_vi(struct virtual_item *vi)
{
- reiserfs_warning (NULL, "STATDATA, index %d, type 0x%x, %h",
- vi->vi_index, vi->vi_type, vi->vi_ih);
+ reiserfs_warning(NULL, "STATDATA, index %d, type 0x%x, %h",
+ vi->vi_index, vi->vi_type, vi->vi_ih);
}
static struct item_operations stat_data_ops = {
- .bytes_number = sd_bytes_number,
- .decrement_key = sd_decrement_key,
- .is_left_mergeable = sd_is_left_mergeable,
- .print_item = sd_print_item,
- .check_item = sd_check_item,
-
- .create_vi = sd_create_vi,
- .check_left = sd_check_left,
- .check_right = sd_check_right,
- .part_size = sd_part_size,
- .unit_num = sd_unit_num,
- .print_vi = sd_print_vi
+ .bytes_number = sd_bytes_number,
+ .decrement_key = sd_decrement_key,
+ .is_left_mergeable = sd_is_left_mergeable,
+ .print_item = sd_print_item,
+ .check_item = sd_check_item,
+
+ .create_vi = sd_create_vi,
+ .check_left = sd_check_left,
+ .check_right = sd_check_right,
+ .part_size = sd_part_size,
+ .unit_num = sd_unit_num,
+ .print_vi = sd_print_vi
};
-
-
//////////////////////////////////////////////////////////////////////////////
// direct item functions
//
-static int direct_bytes_number (struct item_head * ih, int block_size)
+static int direct_bytes_number(struct item_head *ih, int block_size)
{
- return ih_item_len(ih);
+ return ih_item_len(ih);
}
-
// FIXME: this should probably switch to indirect as well
-static void direct_decrement_key (struct cpu_key * key)
+static void direct_decrement_key(struct cpu_key *key)
{
- cpu_key_k_offset_dec (key);
- if (cpu_key_k_offset (key) == 0)
- set_cpu_key_k_type (key, TYPE_STAT_DATA);
+ cpu_key_k_offset_dec(key);
+ if (cpu_key_k_offset(key) == 0)
+ set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
-
-static int direct_is_left_mergeable (struct reiserfs_key * key, unsigned long bsize)
+static int direct_is_left_mergeable(struct reiserfs_key *key,
+ unsigned long bsize)
{
- int version = le_key_version (key);
- return ((le_key_k_offset (version, key) & (bsize - 1)) != 1);
+ int version = le_key_version(key);
+ return ((le_key_k_offset(version, key) & (bsize - 1)) != 1);
}
-
-static void direct_print_item (struct item_head * ih, char * item)
+static void direct_print_item(struct item_head *ih, char *item)
{
- int j = 0;
+ int j = 0;
// return;
- printk ("\"");
- while (j < ih_item_len(ih))
- printk ("%c", item[j++]);
- printk ("\"\n");
+ printk("\"");
+ while (j < ih_item_len(ih))
+ printk("%c", item[j++]);
+ printk("\"\n");
}
-
-static void direct_check_item (struct item_head * ih, char * item)
+static void direct_check_item(struct item_head *ih, char *item)
{
- // FIXME: type something here!
+ // FIXME: type something here!
}
-
-static int direct_create_vi (struct virtual_node * vn,
- struct virtual_item * vi,
- int is_affected,
- int insert_size)
+static int direct_create_vi(struct virtual_node *vn,
+ struct virtual_item *vi,
+ int is_affected, int insert_size)
{
- vi->vi_index = TYPE_DIRECT;
- //vi->vi_type |= VI_TYPE_DIRECT;
- return 0;
+ vi->vi_index = TYPE_DIRECT;
+ //vi->vi_type |= VI_TYPE_DIRECT;
+ return 0;
}
-static int direct_check_left (struct virtual_item * vi, int free,
- int start_skip, int end_skip)
+static int direct_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
{
- int bytes;
+ int bytes;
- bytes = free - free % 8;
- return bytes ?: -1;
+ bytes = free - free % 8;
+ return bytes ? : -1;
}
-
-static int direct_check_right (struct virtual_item * vi, int free)
+static int direct_check_right(struct virtual_item *vi, int free)
{
- return direct_check_left (vi, free, 0, 0);
+ return direct_check_left(vi, free, 0, 0);
}
-static int direct_part_size (struct virtual_item * vi, int first, int count)
+static int direct_part_size(struct virtual_item *vi, int first, int count)
{
- return count;
+ return count;
}
-
-static int direct_unit_num (struct virtual_item * vi)
+static int direct_unit_num(struct virtual_item *vi)
{
- return vi->vi_item_len - IH_SIZE;
+ return vi->vi_item_len - IH_SIZE;
}
-
-static void direct_print_vi (struct virtual_item * vi)
+static void direct_print_vi(struct virtual_item *vi)
{
- reiserfs_warning (NULL, "DIRECT, index %d, type 0x%x, %h",
- vi->vi_index, vi->vi_type, vi->vi_ih);
+ reiserfs_warning(NULL, "DIRECT, index %d, type 0x%x, %h",
+ vi->vi_index, vi->vi_type, vi->vi_ih);
}
static struct item_operations direct_ops = {
- .bytes_number = direct_bytes_number,
- .decrement_key = direct_decrement_key,
- .is_left_mergeable = direct_is_left_mergeable,
- .print_item = direct_print_item,
- .check_item = direct_check_item,
-
- .create_vi = direct_create_vi,
- .check_left = direct_check_left,
- .check_right = direct_check_right,
- .part_size = direct_part_size,
- .unit_num = direct_unit_num,
- .print_vi = direct_print_vi
+ .bytes_number = direct_bytes_number,
+ .decrement_key = direct_decrement_key,
+ .is_left_mergeable = direct_is_left_mergeable,
+ .print_item = direct_print_item,
+ .check_item = direct_check_item,
+
+ .create_vi = direct_create_vi,
+ .check_left = direct_check_left,
+ .check_right = direct_check_right,
+ .part_size = direct_part_size,
+ .unit_num = direct_unit_num,
+ .print_vi = direct_print_vi
};
-
-
//////////////////////////////////////////////////////////////////////////////
// indirect item functions
//
-static int indirect_bytes_number (struct item_head * ih, int block_size)
+static int indirect_bytes_number(struct item_head *ih, int block_size)
{
- return ih_item_len(ih) / UNFM_P_SIZE * block_size; //- get_ih_free_space (ih);
+ return ih_item_len(ih) / UNFM_P_SIZE * block_size; //- get_ih_free_space (ih);
}
-
// decrease offset, if it becomes 0, change type to stat data
-static void indirect_decrement_key (struct cpu_key * key)
+static void indirect_decrement_key(struct cpu_key *key)
{
- cpu_key_k_offset_dec (key);
- if (cpu_key_k_offset (key) == 0)
- set_cpu_key_k_type (key, TYPE_STAT_DATA);
+ cpu_key_k_offset_dec(key);
+ if (cpu_key_k_offset(key) == 0)
+ set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
-
// if it is not first item of the body, then it is mergeable
-static int indirect_is_left_mergeable (struct reiserfs_key * key, unsigned long bsize)
+static int indirect_is_left_mergeable(struct reiserfs_key *key,
+ unsigned long bsize)
{
- int version = le_key_version (key);
- return (le_key_k_offset (version, key) != 1);
+ int version = le_key_version(key);
+ return (le_key_k_offset(version, key) != 1);
}
-
// printing of indirect item
-static void start_new_sequence (__u32 * start, int * len, __u32 new)
+static void start_new_sequence(__u32 * start, int *len, __u32 new)
{
- *start = new;
- *len = 1;
+ *start = new;
+ *len = 1;
}
-
-static int sequence_finished (__u32 start, int * len, __u32 new)
+static int sequence_finished(__u32 start, int *len, __u32 new)
{
- if (start == INT_MAX)
- return 1;
+ if (start == INT_MAX)
+ return 1;
- if (start == 0 && new == 0) {
- (*len) ++;
- return 0;
- }
- if (start != 0 && (start + *len) == new) {
- (*len) ++;
- return 0;
- }
- return 1;
+ if (start == 0 && new == 0) {
+ (*len)++;
+ return 0;
+ }
+ if (start != 0 && (start + *len) == new) {
+ (*len)++;
+ return 0;
+ }
+ return 1;
}
-static void print_sequence (__u32 start, int len)
+static void print_sequence(__u32 start, int len)
{
- if (start == INT_MAX)
- return;
+ if (start == INT_MAX)
+ return;
- if (len == 1)
- printk (" %d", start);
- else
- printk (" %d(%d)", start, len);
+ if (len == 1)
+ printk(" %d", start);
+ else
+ printk(" %d(%d)", start, len);
}
-
-static void indirect_print_item (struct item_head * ih, char * item)
+static void indirect_print_item(struct item_head *ih, char *item)
{
- int j;
- __le32 * unp;
- __u32 prev = INT_MAX;
- int num;
+ int j;
+ __le32 *unp;
+ __u32 prev = INT_MAX;
+ int num;
- unp = (__le32 *)item;
+ unp = (__le32 *) item;
- if (ih_item_len(ih) % UNFM_P_SIZE)
- reiserfs_warning (NULL, "indirect_print_item: invalid item len");
+ if (ih_item_len(ih) % UNFM_P_SIZE)
+ reiserfs_warning(NULL, "indirect_print_item: invalid item len");
- printk ("%d pointers\n[ ", (int)I_UNFM_NUM (ih));
- for (j = 0; j < I_UNFM_NUM (ih); j ++) {
- if (sequence_finished (prev, &num, get_block_num(unp, j))) {
- print_sequence (prev, num);
- start_new_sequence (&prev, &num, get_block_num(unp, j));
+ printk("%d pointers\n[ ", (int)I_UNFM_NUM(ih));
+ for (j = 0; j < I_UNFM_NUM(ih); j++) {
+ if (sequence_finished(prev, &num, get_block_num(unp, j))) {
+ print_sequence(prev, num);
+ start_new_sequence(&prev, &num, get_block_num(unp, j));
+ }
}
- }
- print_sequence (prev, num);
- printk ("]\n");
+ print_sequence(prev, num);
+ printk("]\n");
}
-static void indirect_check_item (struct item_head * ih, char * item)
+static void indirect_check_item(struct item_head *ih, char *item)
{
- // FIXME: type something here!
+ // FIXME: type something here!
}
-
-static int indirect_create_vi (struct virtual_node * vn,
- struct virtual_item * vi,
- int is_affected,
- int insert_size)
+static int indirect_create_vi(struct virtual_node *vn,
+ struct virtual_item *vi,
+ int is_affected, int insert_size)
{
- vi->vi_index = TYPE_INDIRECT;
- //vi->vi_type |= VI_TYPE_INDIRECT;
- return 0;
+ vi->vi_index = TYPE_INDIRECT;
+ //vi->vi_type |= VI_TYPE_INDIRECT;
+ return 0;
}
-static int indirect_check_left (struct virtual_item * vi, int free,
- int start_skip, int end_skip)
+static int indirect_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
{
- int bytes;
+ int bytes;
- bytes = free - free % UNFM_P_SIZE;
- return bytes ?: -1;
+ bytes = free - free % UNFM_P_SIZE;
+ return bytes ? : -1;
}
-
-static int indirect_check_right (struct virtual_item * vi, int free)
+static int indirect_check_right(struct virtual_item *vi, int free)
{
- return indirect_check_left (vi, free, 0, 0);
+ return indirect_check_left(vi, free, 0, 0);
}
-
-
// return size in bytes of 'units' units. If first == 0 - calculate from the head (left), otherwise - from tail (right)
-static int indirect_part_size (struct virtual_item * vi, int first, int units)
+static int indirect_part_size(struct virtual_item *vi, int first, int units)
{
- // unit of indirect item is byte (yet)
- return units;
+ // unit of indirect item is byte (yet)
+ return units;
}
-static int indirect_unit_num (struct virtual_item * vi)
+static int indirect_unit_num(struct virtual_item *vi)
{
- // unit of indirect item is byte (yet)
- return vi->vi_item_len - IH_SIZE;
+ // unit of indirect item is byte (yet)
+ return vi->vi_item_len - IH_SIZE;
}
-static void indirect_print_vi (struct virtual_item * vi)
+static void indirect_print_vi(struct virtual_item *vi)
{
- reiserfs_warning (NULL, "INDIRECT, index %d, type 0x%x, %h",
- vi->vi_index, vi->vi_type, vi->vi_ih);
+ reiserfs_warning(NULL, "INDIRECT, index %d, type 0x%x, %h",
+ vi->vi_index, vi->vi_type, vi->vi_ih);
}
static struct item_operations indirect_ops = {
- .bytes_number = indirect_bytes_number,
- .decrement_key = indirect_decrement_key,
- .is_left_mergeable = indirect_is_left_mergeable,
- .print_item = indirect_print_item,
- .check_item = indirect_check_item,
-
- .create_vi = indirect_create_vi,
- .check_left = indirect_check_left,
- .check_right = indirect_check_right,
- .part_size = indirect_part_size,
- .unit_num = indirect_unit_num,
- .print_vi = indirect_print_vi
+ .bytes_number = indirect_bytes_number,
+ .decrement_key = indirect_decrement_key,
+ .is_left_mergeable = indirect_is_left_mergeable,
+ .print_item = indirect_print_item,
+ .check_item = indirect_check_item,
+
+ .create_vi = indirect_create_vi,
+ .check_left = indirect_check_left,
+ .check_right = indirect_check_right,
+ .part_size = indirect_part_size,
+ .unit_num = indirect_unit_num,
+ .print_vi = indirect_print_vi
};
-
//////////////////////////////////////////////////////////////////////////////
// direntry functions
//
-
-static int direntry_bytes_number (struct item_head * ih, int block_size)
+static int direntry_bytes_number(struct item_head *ih, int block_size)
{
- reiserfs_warning (NULL, "vs-16090: direntry_bytes_number: "
- "bytes number is asked for direntry");
- return 0;
-}
-
-static void direntry_decrement_key (struct cpu_key * key)
-{
- cpu_key_k_offset_dec (key);
- if (cpu_key_k_offset (key) == 0)
- set_cpu_key_k_type (key, TYPE_STAT_DATA);
+ reiserfs_warning(NULL, "vs-16090: direntry_bytes_number: "
+ "bytes number is asked for direntry");
+ return 0;
}
-
-static int direntry_is_left_mergeable (struct reiserfs_key * key, unsigned long bsize)
+static void direntry_decrement_key(struct cpu_key *key)
{
- if (le32_to_cpu (key->u.k_offset_v1.k_offset) == DOT_OFFSET)
- return 0;
- return 1;
-
+ cpu_key_k_offset_dec(key);
+ if (cpu_key_k_offset(key) == 0)
+ set_cpu_key_k_type(key, TYPE_STAT_DATA);
}
-
-static void direntry_print_item (struct item_head * ih, char * item)
+static int direntry_is_left_mergeable(struct reiserfs_key *key,
+ unsigned long bsize)
{
- int i;
- int namelen;
- struct reiserfs_de_head * deh;
- char * name;
- static char namebuf [80];
-
-
- printk ("\n # %-15s%-30s%-15s%-15s%-15s\n", "Name", "Key of pointed object", "Hash", "Gen number", "Status");
+ if (le32_to_cpu(key->u.k_offset_v1.k_offset) == DOT_OFFSET)
+ return 0;
+ return 1;
- deh = (struct reiserfs_de_head *)item;
+}
- for (i = 0; i < I_ENTRY_COUNT (ih); i ++, deh ++) {
- namelen = (i ? (deh_location(deh - 1)) : ih_item_len(ih)) - deh_location(deh);
- name = item + deh_location(deh);
- if (name[namelen-1] == 0)
- namelen = strlen (name);
- namebuf[0] = '"';
- if (namelen > sizeof (namebuf) - 3) {
- strncpy (namebuf + 1, name, sizeof (namebuf) - 3);
- namebuf[sizeof (namebuf) - 2] = '"';
- namebuf[sizeof (namebuf) - 1] = 0;
- } else {
- memcpy (namebuf + 1, name, namelen);
- namebuf[namelen + 1] = '"';
- namebuf[namelen + 2] = 0;
+static void direntry_print_item(struct item_head *ih, char *item)
+{
+ int i;
+ int namelen;
+ struct reiserfs_de_head *deh;
+ char *name;
+ static char namebuf[80];
+
+ printk("\n # %-15s%-30s%-15s%-15s%-15s\n", "Name",
+ "Key of pointed object", "Hash", "Gen number", "Status");
+
+ deh = (struct reiserfs_de_head *)item;
+
+ for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) {
+ namelen =
+ (i ? (deh_location(deh - 1)) : ih_item_len(ih)) -
+ deh_location(deh);
+ name = item + deh_location(deh);
+ if (name[namelen - 1] == 0)
+ namelen = strlen(name);
+ namebuf[0] = '"';
+ if (namelen > sizeof(namebuf) - 3) {
+ strncpy(namebuf + 1, name, sizeof(namebuf) - 3);
+ namebuf[sizeof(namebuf) - 2] = '"';
+ namebuf[sizeof(namebuf) - 1] = 0;
+ } else {
+ memcpy(namebuf + 1, name, namelen);
+ namebuf[namelen + 1] = '"';
+ namebuf[namelen + 2] = 0;
+ }
+
+ printk("%d: %-15s%-15d%-15d%-15Ld%-15Ld(%s)\n",
+ i, namebuf,
+ deh_dir_id(deh), deh_objectid(deh),
+ GET_HASH_VALUE(deh_offset(deh)),
+ GET_GENERATION_NUMBER((deh_offset(deh))),
+ (de_hidden(deh)) ? "HIDDEN" : "VISIBLE");
}
-
- printk ("%d: %-15s%-15d%-15d%-15Ld%-15Ld(%s)\n",
- i, namebuf,
- deh_dir_id(deh), deh_objectid(deh),
- GET_HASH_VALUE (deh_offset (deh)), GET_GENERATION_NUMBER ((deh_offset (deh))),
- (de_hidden (deh)) ? "HIDDEN" : "VISIBLE");
- }
}
-
-static void direntry_check_item (struct item_head * ih, char * item)
+static void direntry_check_item(struct item_head *ih, char *item)
{
- int i;
- struct reiserfs_de_head * deh;
+ int i;
+ struct reiserfs_de_head *deh;
- // FIXME: type something here!
- deh = (struct reiserfs_de_head *)item;
- for (i = 0; i < I_ENTRY_COUNT (ih); i ++, deh ++) {
- ;
- }
+ // FIXME: type something here!
+ deh = (struct reiserfs_de_head *)item;
+ for (i = 0; i < I_ENTRY_COUNT(ih); i++, deh++) {
+ ;
+ }
}
-
-
#define DIRENTRY_VI_FIRST_DIRENTRY_ITEM 1
/*
* function returns old entry number in directory item in real node
* using new entry number in virtual item in virtual node */
-static inline int old_entry_num (int is_affected, int virtual_entry_num, int pos_in_item, int mode)
+static inline int old_entry_num(int is_affected, int virtual_entry_num,
+ int pos_in_item, int mode)
{
- if ( mode == M_INSERT || mode == M_DELETE)
- return virtual_entry_num;
-
- if (!is_affected)
- /* cut or paste is applied to another item */
- return virtual_entry_num;
-
- if (virtual_entry_num < pos_in_item)
- return virtual_entry_num;
+ if (mode == M_INSERT || mode == M_DELETE)
+ return virtual_entry_num;
- if (mode == M_CUT)
- return virtual_entry_num + 1;
+ if (!is_affected)
+ /* cut or paste is applied to another item */
+ return virtual_entry_num;
- RFALSE( mode != M_PASTE || virtual_entry_num == 0,
- "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'", mode);
-
- return virtual_entry_num - 1;
-}
+ if (virtual_entry_num < pos_in_item)
+ return virtual_entry_num;
+ if (mode == M_CUT)
+ return virtual_entry_num + 1;
+ RFALSE(mode != M_PASTE || virtual_entry_num == 0,
+ "vs-8015: old_entry_num: mode must be M_PASTE (mode = \'%c\'",
+ mode);
+ return virtual_entry_num - 1;
+}
/* Create an array of sizes of directory entries for virtual
item. Return space used by an item. FIXME: no control over
consuming of space used by this item handler */
-static int direntry_create_vi (struct virtual_node * vn,
- struct virtual_item * vi,
- int is_affected,
- int insert_size)
-{
- struct direntry_uarea * dir_u = vi->vi_uarea;
- int i, j;
- int size = sizeof (struct direntry_uarea);
- struct reiserfs_de_head * deh;
-
- vi->vi_index = TYPE_DIRENTRY;
-
- if (!(vi->vi_ih) || !vi->vi_item)
- BUG ();
-
-
- dir_u->flags = 0;
- if (le_ih_k_offset (vi->vi_ih) == DOT_OFFSET)
- dir_u->flags |= DIRENTRY_VI_FIRST_DIRENTRY_ITEM;
-
- deh = (struct reiserfs_de_head *)(vi->vi_item);
-
-
- /* virtual directory item have this amount of entry after */
- dir_u->entry_count = ih_entry_count (vi->vi_ih) +
- ((is_affected) ? ((vn->vn_mode == M_CUT) ? -1 :
- (vn->vn_mode == M_PASTE ? 1 : 0)) : 0);
-
- for (i = 0; i < dir_u->entry_count; i ++) {
- j = old_entry_num (is_affected, i, vn->vn_pos_in_item, vn->vn_mode);
- dir_u->entry_sizes[i] = (j ? deh_location( &(deh[j - 1]) ) :
- ih_item_len (vi->vi_ih)) -
- deh_location( &(deh[j])) + DEH_SIZE;
- }
-
- size += (dir_u->entry_count * sizeof (short));
-
- /* set size of pasted entry */
- if (is_affected && vn->vn_mode == M_PASTE)
- dir_u->entry_sizes[vn->vn_pos_in_item] = insert_size;
+static int direntry_create_vi(struct virtual_node *vn,
+ struct virtual_item *vi,
+ int is_affected, int insert_size)
+{
+ struct direntry_uarea *dir_u = vi->vi_uarea;
+ int i, j;
+ int size = sizeof(struct direntry_uarea);
+ struct reiserfs_de_head *deh;
+ vi->vi_index = TYPE_DIRENTRY;
+
+ if (!(vi->vi_ih) || !vi->vi_item)
+ BUG();
+
+ dir_u->flags = 0;
+ if (le_ih_k_offset(vi->vi_ih) == DOT_OFFSET)
+ dir_u->flags |= DIRENTRY_VI_FIRST_DIRENTRY_ITEM;
+
+ deh = (struct reiserfs_de_head *)(vi->vi_item);
+
+ /* virtual directory item have this amount of entry after */
+ dir_u->entry_count = ih_entry_count(vi->vi_ih) +
+ ((is_affected) ? ((vn->vn_mode == M_CUT) ? -1 :
+ (vn->vn_mode == M_PASTE ? 1 : 0)) : 0);
+
+ for (i = 0; i < dir_u->entry_count; i++) {
+ j = old_entry_num(is_affected, i, vn->vn_pos_in_item,
+ vn->vn_mode);
+ dir_u->entry_sizes[i] =
+ (j ? deh_location(&(deh[j - 1])) : ih_item_len(vi->vi_ih)) -
+ deh_location(&(deh[j])) + DEH_SIZE;
+ }
+
+ size += (dir_u->entry_count * sizeof(short));
+
+ /* set size of pasted entry */
+ if (is_affected && vn->vn_mode == M_PASTE)
+ dir_u->entry_sizes[vn->vn_pos_in_item] = insert_size;
#ifdef CONFIG_REISERFS_CHECK
- /* compare total size of entries with item length */
- {
- int k, l;
-
- l = 0;
- for (k = 0; k < dir_u->entry_count; k ++)
- l += dir_u->entry_sizes[k];
-
- if (l + IH_SIZE != vi->vi_item_len +
- ((is_affected && (vn->vn_mode == M_PASTE || vn->vn_mode == M_CUT)) ? insert_size : 0) ) {
- reiserfs_panic (NULL, "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item",
- vn->vn_mode, insert_size);
+ /* compare total size of entries with item length */
+ {
+ int k, l;
+
+ l = 0;
+ for (k = 0; k < dir_u->entry_count; k++)
+ l += dir_u->entry_sizes[k];
+
+ if (l + IH_SIZE != vi->vi_item_len +
+ ((is_affected
+ && (vn->vn_mode == M_PASTE
+ || vn->vn_mode == M_CUT)) ? insert_size : 0)) {
+ reiserfs_panic(NULL,
+ "vs-8025: set_entry_sizes: (mode==%c, insert_size==%d), invalid length of directory item",
+ vn->vn_mode, insert_size);
+ }
}
- }
#endif
- return size;
-
+ return size;
}
-
//
// return number of entries which may fit into specified amount of
// free space, or -1 if free space is not enough even for 1 entry
//
-static int direntry_check_left (struct virtual_item * vi, int free,
- int start_skip, int end_skip)
+static int direntry_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
{
- int i;
- int entries = 0;
- struct direntry_uarea * dir_u = vi->vi_uarea;
+ int i;
+ int entries = 0;
+ struct direntry_uarea *dir_u = vi->vi_uarea;
- for (i = start_skip; i < dir_u->entry_count - end_skip; i ++) {
- if (dir_u->entry_sizes[i] > free)
- /* i-th entry doesn't fit into the remaining free space */
- break;
-
- free -= dir_u->entry_sizes[i];
- entries ++;
- }
+ for (i = start_skip; i < dir_u->entry_count - end_skip; i++) {
+ if (dir_u->entry_sizes[i] > free)
+ /* i-th entry doesn't fit into the remaining free space */
+ break;
- if (entries == dir_u->entry_count) {
- reiserfs_panic (NULL, "free space %d, entry_count %d\n", free, dir_u->entry_count);
- }
+ free -= dir_u->entry_sizes[i];
+ entries++;
+ }
- /* "." and ".." can not be separated from each other */
- if (start_skip == 0 && (dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM) && entries < 2)
- entries = 0;
-
- return entries ?: -1;
-}
+ if (entries == dir_u->entry_count) {
+ reiserfs_panic(NULL, "free space %d, entry_count %d\n", free,
+ dir_u->entry_count);
+ }
+ /* "." and ".." can not be separated from each other */
+ if (start_skip == 0 && (dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
+ && entries < 2)
+ entries = 0;
-static int direntry_check_right (struct virtual_item * vi, int free)
+ return entries ? : -1;
+}
+
+static int direntry_check_right(struct virtual_item *vi, int free)
{
- int i;
- int entries = 0;
- struct direntry_uarea * dir_u = vi->vi_uarea;
-
- for (i = dir_u->entry_count - 1; i >= 0; i --) {
- if (dir_u->entry_sizes[i] > free)
- /* i-th entry doesn't fit into the remaining free space */
- break;
-
- free -= dir_u->entry_sizes[i];
- entries ++;
- }
- if (entries == dir_u->entry_count)
- BUG ();
+ int i;
+ int entries = 0;
+ struct direntry_uarea *dir_u = vi->vi_uarea;
- /* "." and ".." can not be separated from each other */
- if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM) && entries > dir_u->entry_count - 2)
- entries = dir_u->entry_count - 2;
+ for (i = dir_u->entry_count - 1; i >= 0; i--) {
+ if (dir_u->entry_sizes[i] > free)
+ /* i-th entry doesn't fit into the remaining free space */
+ break;
- return entries ?: -1;
-}
+ free -= dir_u->entry_sizes[i];
+ entries++;
+ }
+ if (entries == dir_u->entry_count)
+ BUG();
+ /* "." and ".." can not be separated from each other */
+ if ((dir_u->flags & DIRENTRY_VI_FIRST_DIRENTRY_ITEM)
+ && entries > dir_u->entry_count - 2)
+ entries = dir_u->entry_count - 2;
+
+ return entries ? : -1;
+}
/* sum of entry sizes between from-th and to-th entries including both edges */
-static int direntry_part_size (struct virtual_item * vi, int first, int count)
+static int direntry_part_size(struct virtual_item *vi, int first, int count)
{
- int i, retval;
- int from, to;
- struct direntry_uarea * dir_u = vi->vi_uarea;
-
- retval = 0;
- if (first == 0)
- from = 0;
- else
- from = dir_u->entry_count - count;
- to = from + count - 1;
+ int i, retval;
+ int from, to;
+ struct direntry_uarea *dir_u = vi->vi_uarea;
- for (i = from; i <= to; i ++)
- retval += dir_u->entry_sizes[i];
+ retval = 0;
+ if (first == 0)
+ from = 0;
+ else
+ from = dir_u->entry_count - count;
+ to = from + count - 1;
- return retval;
-}
+ for (i = from; i <= to; i++)
+ retval += dir_u->entry_sizes[i];
-static int direntry_unit_num (struct virtual_item * vi)
-{
- struct direntry_uarea * dir_u = vi->vi_uarea;
-
- return dir_u->entry_count;
+ return retval;
}
+static int direntry_unit_num(struct virtual_item *vi)
+{
+ struct direntry_uarea *dir_u = vi->vi_uarea;
+ return dir_u->entry_count;
+}
-static void direntry_print_vi (struct virtual_item * vi)
+static void direntry_print_vi(struct virtual_item *vi)
{
- int i;
- struct direntry_uarea * dir_u = vi->vi_uarea;
+ int i;
+ struct direntry_uarea *dir_u = vi->vi_uarea;
- reiserfs_warning (NULL, "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
- vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags);
- printk ("%d entries: ", dir_u->entry_count);
- for (i = 0; i < dir_u->entry_count; i ++)
- printk ("%d ", dir_u->entry_sizes[i]);
- printk ("\n");
+ reiserfs_warning(NULL, "DIRENTRY, index %d, type 0x%x, %h, flags 0x%x",
+ vi->vi_index, vi->vi_type, vi->vi_ih, dir_u->flags);
+ printk("%d entries: ", dir_u->entry_count);
+ for (i = 0; i < dir_u->entry_count; i++)
+ printk("%d ", dir_u->entry_sizes[i]);
+ printk("\n");
}
static struct item_operations direntry_ops = {
- .bytes_number = direntry_bytes_number,
- .decrement_key = direntry_decrement_key,
- .is_left_mergeable = direntry_is_left_mergeable,
- .print_item = direntry_print_item,
- .check_item = direntry_check_item,
-
- .create_vi = direntry_create_vi,
- .check_left = direntry_check_left,
- .check_right = direntry_check_right,
- .part_size = direntry_part_size,
- .unit_num = direntry_unit_num,
- .print_vi = direntry_print_vi
+ .bytes_number = direntry_bytes_number,
+ .decrement_key = direntry_decrement_key,
+ .is_left_mergeable = direntry_is_left_mergeable,
+ .print_item = direntry_print_item,
+ .check_item = direntry_check_item,
+
+ .create_vi = direntry_create_vi,
+ .check_left = direntry_check_left,
+ .check_right = direntry_check_right,
+ .part_size = direntry_part_size,
+ .unit_num = direntry_unit_num,
+ .print_vi = direntry_print_vi
};
-
//////////////////////////////////////////////////////////////////////////////
// Error catching functions to catch errors caused by incorrect item types.
//
-static int errcatch_bytes_number (struct item_head * ih, int block_size)
+static int errcatch_bytes_number(struct item_head *ih, int block_size)
{
- reiserfs_warning (NULL, "green-16001: Invalid item type observed, run fsck ASAP");
- return 0;
+ reiserfs_warning(NULL,
+ "green-16001: Invalid item type observed, run fsck ASAP");
+ return 0;
}
-static void errcatch_decrement_key (struct cpu_key * key)
+static void errcatch_decrement_key(struct cpu_key *key)
{
- reiserfs_warning (NULL, "green-16002: Invalid item type observed, run fsck ASAP");
+ reiserfs_warning(NULL,
+ "green-16002: Invalid item type observed, run fsck ASAP");
}
-
-static int errcatch_is_left_mergeable (struct reiserfs_key * key, unsigned long bsize)
+static int errcatch_is_left_mergeable(struct reiserfs_key *key,
+ unsigned long bsize)
{
- reiserfs_warning (NULL, "green-16003: Invalid item type observed, run fsck ASAP");
- return 0;
+ reiserfs_warning(NULL,
+ "green-16003: Invalid item type observed, run fsck ASAP");
+ return 0;
}
-
-static void errcatch_print_item (struct item_head * ih, char * item)
+static void errcatch_print_item(struct item_head *ih, char *item)
{
- reiserfs_warning (NULL, "green-16004: Invalid item type observed, run fsck ASAP");
+ reiserfs_warning(NULL,
+ "green-16004: Invalid item type observed, run fsck ASAP");
}
-
-static void errcatch_check_item (struct item_head * ih, char * item)
+static void errcatch_check_item(struct item_head *ih, char *item)
{
- reiserfs_warning (NULL, "green-16005: Invalid item type observed, run fsck ASAP");
+ reiserfs_warning(NULL,
+ "green-16005: Invalid item type observed, run fsck ASAP");
}
-static int errcatch_create_vi (struct virtual_node * vn,
- struct virtual_item * vi,
- int is_affected,
- int insert_size)
+static int errcatch_create_vi(struct virtual_node *vn,
+ struct virtual_item *vi,
+ int is_affected, int insert_size)
{
- reiserfs_warning (NULL, "green-16006: Invalid item type observed, run fsck ASAP");
- return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where
- // this operation is called from is of return type void.
+ reiserfs_warning(NULL,
+ "green-16006: Invalid item type observed, run fsck ASAP");
+ return 0; // We might return -1 here as well, but it won't help as create_virtual_node() from where
+ // this operation is called from is of return type void.
}
-static int errcatch_check_left (struct virtual_item * vi, int free,
- int start_skip, int end_skip)
+static int errcatch_check_left(struct virtual_item *vi, int free,
+ int start_skip, int end_skip)
{
- reiserfs_warning (NULL, "green-16007: Invalid item type observed, run fsck ASAP");
- return -1;
+ reiserfs_warning(NULL,
+ "green-16007: Invalid item type observed, run fsck ASAP");
+ return -1;
}
-
-static int errcatch_check_right (struct virtual_item * vi, int free)
+static int errcatch_check_right(struct virtual_item *vi, int free)
{
- reiserfs_warning (NULL, "green-16008: Invalid item type observed, run fsck ASAP");
- return -1;
+ reiserfs_warning(NULL,
+ "green-16008: Invalid item type observed, run fsck ASAP");
+ return -1;
}
-static int errcatch_part_size (struct virtual_item * vi, int first, int count)
+static int errcatch_part_size(struct virtual_item *vi, int first, int count)
{
- reiserfs_warning (NULL, "green-16009: Invalid item type observed, run fsck ASAP");
- return 0;
+ reiserfs_warning(NULL,
+ "green-16009: Invalid item type observed, run fsck ASAP");
+ return 0;
}
-static int errcatch_unit_num (struct virtual_item * vi)
+static int errcatch_unit_num(struct virtual_item *vi)
{
- reiserfs_warning (NULL, "green-16010: Invalid item type observed, run fsck ASAP");
- return 0;
+ reiserfs_warning(NULL,
+ "green-16010: Invalid item type observed, run fsck ASAP");
+ return 0;
}
-static void errcatch_print_vi (struct virtual_item * vi)
+static void errcatch_print_vi(struct virtual_item *vi)
{
- reiserfs_warning (NULL, "green-16011: Invalid item type observed, run fsck ASAP");
+ reiserfs_warning(NULL,
+ "green-16011: Invalid item type observed, run fsck ASAP");
}
static struct item_operations errcatch_ops = {
- errcatch_bytes_number,
- errcatch_decrement_key,
- errcatch_is_left_mergeable,
- errcatch_print_item,
- errcatch_check_item,
-
- errcatch_create_vi,
- errcatch_check_left,
- errcatch_check_right,
- errcatch_part_size,
- errcatch_unit_num,
- errcatch_print_vi
+ errcatch_bytes_number,
+ errcatch_decrement_key,
+ errcatch_is_left_mergeable,
+ errcatch_print_item,
+ errcatch_check_item,
+
+ errcatch_create_vi,
+ errcatch_check_left,
+ errcatch_check_right,
+ errcatch_part_size,
+ errcatch_unit_num,
+ errcatch_print_vi
};
-
-
//////////////////////////////////////////////////////////////////////////////
//
//
#if ! (TYPE_STAT_DATA == 0 && TYPE_INDIRECT == 1 && TYPE_DIRECT == 2 && TYPE_DIRENTRY == 3)
- do not compile
+#error Item types must use disk-format assigned values.
#endif
-struct item_operations * item_ops [TYPE_ANY + 1] = {
- &stat_data_ops,
- &indirect_ops,
- &direct_ops,
- &direntry_ops,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &errcatch_ops /* This is to catch errors with invalid type (15th entry for TYPE_ANY) */
+struct item_operations *item_ops[TYPE_ANY + 1] = {
+ &stat_data_ops,
+ &indirect_ops,
+ &direct_ops,
+ &direntry_ops,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &errcatch_ops /* This is to catch errors with invalid type (15th entry for TYPE_ANY) */
};
-
-
-
-
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c
index 3072cfdee959..c66c27ec4100 100644
--- a/fs/reiserfs/journal.c
+++ b/fs/reiserfs/journal.c
@@ -55,7 +55,6 @@
#include <linux/writeback.h>
#include <linux/blkdev.h>
-
/* gets a struct reiserfs_journal_list * from a list head */
#define JOURNAL_LIST_ENTRY(h) (list_entry((h), struct reiserfs_journal_list, \
j_list))
@@ -69,55 +68,61 @@ static int reiserfs_mounted_fs_count;
static struct workqueue_struct *commit_wq;
-#define JOURNAL_TRANS_HALF 1018 /* must be correct to keep the desc and commit
- structs at 4k */
-#define BUFNR 64 /*read ahead */
+#define JOURNAL_TRANS_HALF 1018 /* must be correct to keep the desc and commit
+ structs at 4k */
+#define BUFNR 64 /*read ahead */
/* cnode stat bits. Move these into reiserfs_fs.h */
#define BLOCK_FREED 2 /* this block was freed, and can't be written. */
-#define BLOCK_FREED_HOLDER 3 /* this block was freed during this transaction, and can't be written */
+#define BLOCK_FREED_HOLDER 3 /* this block was freed during this transaction, and can't be written */
#define BLOCK_NEEDS_FLUSH 4 /* used in flush_journal_list */
#define BLOCK_DIRTIED 5
-
/* journal list state bits */
#define LIST_TOUCHED 1
#define LIST_DIRTY 2
-#define LIST_COMMIT_PENDING 4 /* someone will commit this list */
+#define LIST_COMMIT_PENDING 4 /* someone will commit this list */
/* flags for do_journal_end */
#define FLUSH_ALL 1 /* flush commit and real blocks */
#define COMMIT_NOW 2 /* end and commit this transaction */
-#define WAIT 4 /* wait for the log blocks to hit the disk*/
-
-static int do_journal_end(struct reiserfs_transaction_handle *,struct super_block *,unsigned long nblocks,int flags) ;
-static int flush_journal_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
-static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) ;
-static int can_dirty(struct reiserfs_journal_cnode *cn) ;
-static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks);
-static int release_journal_dev( struct super_block *super,
- struct reiserfs_journal *journal );
+#define WAIT 4 /* wait for the log blocks to hit the disk */
+
+static int do_journal_end(struct reiserfs_transaction_handle *,
+ struct super_block *, unsigned long nblocks,
+ int flags);
+static int flush_journal_list(struct super_block *s,
+ struct reiserfs_journal_list *jl, int flushall);
+static int flush_commit_list(struct super_block *s,
+ struct reiserfs_journal_list *jl, int flushall);
+static int can_dirty(struct reiserfs_journal_cnode *cn);
+static int journal_join(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks);
+static int release_journal_dev(struct super_block *super,
+ struct reiserfs_journal *journal);
static int dirty_one_transaction(struct super_block *s,
- struct reiserfs_journal_list *jl);
+ struct reiserfs_journal_list *jl);
static void flush_async_commits(void *p);
static void queue_log_writer(struct super_block *s);
/* values for join in do_journal_begin_r */
enum {
- JBEGIN_REG = 0, /* regular journal begin */
- JBEGIN_JOIN = 1, /* join the running transaction if at all possible */
- JBEGIN_ABORT = 2, /* called from cleanup code, ignores aborted flag */
+ JBEGIN_REG = 0, /* regular journal begin */
+ JBEGIN_JOIN = 1, /* join the running transaction if at all possible */
+ JBEGIN_ABORT = 2, /* called from cleanup code, ignores aborted flag */
};
static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
- struct super_block * p_s_sb,
- unsigned long nblocks,int join);
+ struct super_block *p_s_sb,
+ unsigned long nblocks, int join);
-static void init_journal_hash(struct super_block *p_s_sb) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- memset(journal->j_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
+static void init_journal_hash(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ memset(journal->j_hash_table, 0,
+ JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *));
}
/*
@@ -125,149 +130,159 @@ static void init_journal_hash(struct super_block *p_s_sb) {
** make schedule happen after I've freed a block. Look at remove_from_transaction and journal_mark_freed for
** more details.
*/
-static int reiserfs_clean_and_file_buffer(struct buffer_head *bh) {
- if (bh) {
- clear_buffer_dirty(bh);
- clear_buffer_journal_test(bh);
- }
- return 0 ;
+static int reiserfs_clean_and_file_buffer(struct buffer_head *bh)
+{
+ if (bh) {
+ clear_buffer_dirty(bh);
+ clear_buffer_journal_test(bh);
+ }
+ return 0;
}
static void disable_barrier(struct super_block *s)
{
- REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);
- printk("reiserfs: disabling flush barriers on %s\n", reiserfs_bdevname(s));
-}
-
-static struct reiserfs_bitmap_node *
-allocate_bitmap_node(struct super_block *p_s_sb) {
- struct reiserfs_bitmap_node *bn ;
- static int id;
-
- bn = reiserfs_kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS, p_s_sb) ;
- if (!bn) {
- return NULL ;
- }
- bn->data = reiserfs_kmalloc(p_s_sb->s_blocksize, GFP_NOFS, p_s_sb) ;
- if (!bn->data) {
- reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
- return NULL ;
- }
- bn->id = id++ ;
- memset(bn->data, 0, p_s_sb->s_blocksize) ;
- INIT_LIST_HEAD(&bn->list) ;
- return bn ;
-}
-
-static struct reiserfs_bitmap_node *
-get_bitmap_node(struct super_block *p_s_sb) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_bitmap_node *bn = NULL;
- struct list_head *entry = journal->j_bitmap_nodes.next ;
-
- journal->j_used_bitmap_nodes++ ;
-repeat:
-
- if(entry != &journal->j_bitmap_nodes) {
- bn = list_entry(entry, struct reiserfs_bitmap_node, list) ;
- list_del(entry) ;
- memset(bn->data, 0, p_s_sb->s_blocksize) ;
- journal->j_free_bitmap_nodes-- ;
- return bn ;
- }
- bn = allocate_bitmap_node(p_s_sb) ;
- if (!bn) {
- yield();
- goto repeat ;
- }
- return bn ;
+ REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_BARRIER_FLUSH);
+ printk("reiserfs: disabling flush barriers on %s\n",
+ reiserfs_bdevname(s));
+}
+
+static struct reiserfs_bitmap_node *allocate_bitmap_node(struct super_block
+ *p_s_sb)
+{
+ struct reiserfs_bitmap_node *bn;
+ static int id;
+
+ bn = reiserfs_kmalloc(sizeof(struct reiserfs_bitmap_node), GFP_NOFS,
+ p_s_sb);
+ if (!bn) {
+ return NULL;
+ }
+ bn->data = reiserfs_kmalloc(p_s_sb->s_blocksize, GFP_NOFS, p_s_sb);
+ if (!bn->data) {
+ reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb);
+ return NULL;
+ }
+ bn->id = id++;
+ memset(bn->data, 0, p_s_sb->s_blocksize);
+ INIT_LIST_HEAD(&bn->list);
+ return bn;
+}
+
+static struct reiserfs_bitmap_node *get_bitmap_node(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_bitmap_node *bn = NULL;
+ struct list_head *entry = journal->j_bitmap_nodes.next;
+
+ journal->j_used_bitmap_nodes++;
+ repeat:
+
+ if (entry != &journal->j_bitmap_nodes) {
+ bn = list_entry(entry, struct reiserfs_bitmap_node, list);
+ list_del(entry);
+ memset(bn->data, 0, p_s_sb->s_blocksize);
+ journal->j_free_bitmap_nodes--;
+ return bn;
+ }
+ bn = allocate_bitmap_node(p_s_sb);
+ if (!bn) {
+ yield();
+ goto repeat;
+ }
+ return bn;
}
static inline void free_bitmap_node(struct super_block *p_s_sb,
- struct reiserfs_bitmap_node *bn) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- journal->j_used_bitmap_nodes-- ;
- if (journal->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) {
- reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;
- reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
- } else {
- list_add(&bn->list, &journal->j_bitmap_nodes) ;
- journal->j_free_bitmap_nodes++ ;
- }
-}
-
-static void allocate_bitmap_nodes(struct super_block *p_s_sb) {
- int i ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_bitmap_node *bn = NULL ;
- for (i = 0 ; i < REISERFS_MIN_BITMAP_NODES ; i++) {
- bn = allocate_bitmap_node(p_s_sb) ;
- if (bn) {
- list_add(&bn->list, &journal->j_bitmap_nodes) ;
- journal->j_free_bitmap_nodes++ ;
- } else {
- break ; // this is ok, we'll try again when more are needed
- }
- }
+ struct reiserfs_bitmap_node *bn)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ journal->j_used_bitmap_nodes--;
+ if (journal->j_free_bitmap_nodes > REISERFS_MAX_BITMAP_NODES) {
+ reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb);
+ reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb);
+ } else {
+ list_add(&bn->list, &journal->j_bitmap_nodes);
+ journal->j_free_bitmap_nodes++;
+ }
+}
+
+static void allocate_bitmap_nodes(struct super_block *p_s_sb)
+{
+ int i;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_bitmap_node *bn = NULL;
+ for (i = 0; i < REISERFS_MIN_BITMAP_NODES; i++) {
+ bn = allocate_bitmap_node(p_s_sb);
+ if (bn) {
+ list_add(&bn->list, &journal->j_bitmap_nodes);
+ journal->j_free_bitmap_nodes++;
+ } else {
+ break; // this is ok, we'll try again when more are needed
+ }
+ }
}
static int set_bit_in_list_bitmap(struct super_block *p_s_sb, int block,
- struct reiserfs_list_bitmap *jb) {
- int bmap_nr = block / (p_s_sb->s_blocksize << 3) ;
- int bit_nr = block % (p_s_sb->s_blocksize << 3) ;
+ struct reiserfs_list_bitmap *jb)
+{
+ int bmap_nr = block / (p_s_sb->s_blocksize << 3);
+ int bit_nr = block % (p_s_sb->s_blocksize << 3);
- if (!jb->bitmaps[bmap_nr]) {
- jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb) ;
- }
- set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data) ;
- return 0 ;
+ if (!jb->bitmaps[bmap_nr]) {
+ jb->bitmaps[bmap_nr] = get_bitmap_node(p_s_sb);
+ }
+ set_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data);
+ return 0;
}
static void cleanup_bitmap_list(struct super_block *p_s_sb,
- struct reiserfs_list_bitmap *jb) {
- int i;
- if (jb->bitmaps == NULL)
- return;
-
- for (i = 0 ; i < SB_BMAP_NR(p_s_sb) ; i++) {
- if (jb->bitmaps[i]) {
- free_bitmap_node(p_s_sb, jb->bitmaps[i]) ;
- jb->bitmaps[i] = NULL ;
- }
- }
+ struct reiserfs_list_bitmap *jb)
+{
+ int i;
+ if (jb->bitmaps == NULL)
+ return;
+
+ for (i = 0; i < SB_BMAP_NR(p_s_sb); i++) {
+ if (jb->bitmaps[i]) {
+ free_bitmap_node(p_s_sb, jb->bitmaps[i]);
+ jb->bitmaps[i] = NULL;
+ }
+ }
}
/*
** only call this on FS unmount.
*/
static int free_list_bitmaps(struct super_block *p_s_sb,
- struct reiserfs_list_bitmap *jb_array) {
- int i ;
- struct reiserfs_list_bitmap *jb ;
- for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
- jb = jb_array + i ;
- jb->journal_list = NULL ;
- cleanup_bitmap_list(p_s_sb, jb) ;
- vfree(jb->bitmaps) ;
- jb->bitmaps = NULL ;
- }
- return 0;
-}
-
-static int free_bitmap_nodes(struct super_block *p_s_sb) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct list_head *next = journal->j_bitmap_nodes.next ;
- struct reiserfs_bitmap_node *bn ;
-
- while(next != &journal->j_bitmap_nodes) {
- bn = list_entry(next, struct reiserfs_bitmap_node, list) ;
- list_del(next) ;
- reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb) ;
- reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb) ;
- next = journal->j_bitmap_nodes.next ;
- journal->j_free_bitmap_nodes-- ;
- }
-
- return 0 ;
+ struct reiserfs_list_bitmap *jb_array)
+{
+ int i;
+ struct reiserfs_list_bitmap *jb;
+ for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
+ jb = jb_array + i;
+ jb->journal_list = NULL;
+ cleanup_bitmap_list(p_s_sb, jb);
+ vfree(jb->bitmaps);
+ jb->bitmaps = NULL;
+ }
+ return 0;
+}
+
+static int free_bitmap_nodes(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct list_head *next = journal->j_bitmap_nodes.next;
+ struct reiserfs_bitmap_node *bn;
+
+ while (next != &journal->j_bitmap_nodes) {
+ bn = list_entry(next, struct reiserfs_bitmap_node, list);
+ list_del(next);
+ reiserfs_kfree(bn->data, p_s_sb->s_blocksize, p_s_sb);
+ reiserfs_kfree(bn, sizeof(struct reiserfs_bitmap_node), p_s_sb);
+ next = journal->j_bitmap_nodes.next;
+ journal->j_free_bitmap_nodes--;
+ }
+
+ return 0;
}
/*
@@ -275,59 +290,65 @@ static int free_bitmap_nodes(struct super_block *p_s_sb) {
** jb_array is the array to be filled in.
*/
int reiserfs_allocate_list_bitmaps(struct super_block *p_s_sb,
- struct reiserfs_list_bitmap *jb_array,
- int bmap_nr) {
- int i ;
- int failed = 0 ;
- struct reiserfs_list_bitmap *jb ;
- int mem = bmap_nr * sizeof(struct reiserfs_bitmap_node *) ;
-
- for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
- jb = jb_array + i ;
- jb->journal_list = NULL ;
- jb->bitmaps = vmalloc( mem ) ;
- if (!jb->bitmaps) {
- reiserfs_warning(p_s_sb, "clm-2000, unable to allocate bitmaps for journal lists") ;
- failed = 1;
- break ;
- }
- memset(jb->bitmaps, 0, mem) ;
- }
- if (failed) {
- free_list_bitmaps(p_s_sb, jb_array) ;
- return -1 ;
- }
- return 0 ;
+ struct reiserfs_list_bitmap *jb_array,
+ int bmap_nr)
+{
+ int i;
+ int failed = 0;
+ struct reiserfs_list_bitmap *jb;
+ int mem = bmap_nr * sizeof(struct reiserfs_bitmap_node *);
+
+ for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
+ jb = jb_array + i;
+ jb->journal_list = NULL;
+ jb->bitmaps = vmalloc(mem);
+ if (!jb->bitmaps) {
+ reiserfs_warning(p_s_sb,
+ "clm-2000, unable to allocate bitmaps for journal lists");
+ failed = 1;
+ break;
+ }
+ memset(jb->bitmaps, 0, mem);
+ }
+ if (failed) {
+ free_list_bitmaps(p_s_sb, jb_array);
+ return -1;
+ }
+ return 0;
}
/*
** find an available list bitmap. If you can't find one, flush a commit list
** and try again
*/
-static struct reiserfs_list_bitmap *
-get_list_bitmap(struct super_block *p_s_sb, struct reiserfs_journal_list *jl) {
- int i,j ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_list_bitmap *jb = NULL ;
-
- for (j = 0 ; j < (JOURNAL_NUM_BITMAPS * 3) ; j++) {
- i = journal->j_list_bitmap_index ;
- journal->j_list_bitmap_index = (i + 1) % JOURNAL_NUM_BITMAPS ;
- jb = journal->j_list_bitmap + i ;
- if (journal->j_list_bitmap[i].journal_list) {
- flush_commit_list(p_s_sb, journal->j_list_bitmap[i].journal_list, 1) ;
- if (!journal->j_list_bitmap[i].journal_list) {
- break ;
- }
- } else {
- break ;
- }
- }
- if (jb->journal_list) { /* double check to make sure if flushed correctly */
- return NULL ;
- }
- jb->journal_list = jl ;
- return jb ;
+static struct reiserfs_list_bitmap *get_list_bitmap(struct super_block *p_s_sb,
+ struct reiserfs_journal_list
+ *jl)
+{
+ int i, j;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_list_bitmap *jb = NULL;
+
+ for (j = 0; j < (JOURNAL_NUM_BITMAPS * 3); j++) {
+ i = journal->j_list_bitmap_index;
+ journal->j_list_bitmap_index = (i + 1) % JOURNAL_NUM_BITMAPS;
+ jb = journal->j_list_bitmap + i;
+ if (journal->j_list_bitmap[i].journal_list) {
+ flush_commit_list(p_s_sb,
+ journal->j_list_bitmap[i].
+ journal_list, 1);
+ if (!journal->j_list_bitmap[i].journal_list) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ if (jb->journal_list) { /* double check to make sure if flushed correctly */
+ return NULL;
+ }
+ jb->journal_list = jl;
+ return jb;
}
/*
@@ -335,104 +356,114 @@ get_list_bitmap(struct super_block *p_s_sb, struct reiserfs_journal_list *jl) {
** Uses the cnode->next and cnode->prev pointers
** returns NULL on failure
*/
-static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes) {
- struct reiserfs_journal_cnode *head ;
- int i ;
- if (num_cnodes <= 0) {
- return NULL ;
- }
- head = vmalloc(num_cnodes * sizeof(struct reiserfs_journal_cnode)) ;
- if (!head) {
- return NULL ;
- }
- memset(head, 0, num_cnodes * sizeof(struct reiserfs_journal_cnode)) ;
- head[0].prev = NULL ;
- head[0].next = head + 1 ;
- for (i = 1 ; i < num_cnodes; i++) {
- head[i].prev = head + (i - 1) ;
- head[i].next = head + (i + 1) ; /* if last one, overwrite it after the if */
- }
- head[num_cnodes -1].next = NULL ;
- return head ;
+static struct reiserfs_journal_cnode *allocate_cnodes(int num_cnodes)
+{
+ struct reiserfs_journal_cnode *head;
+ int i;
+ if (num_cnodes <= 0) {
+ return NULL;
+ }
+ head = vmalloc(num_cnodes * sizeof(struct reiserfs_journal_cnode));
+ if (!head) {
+ return NULL;
+ }
+ memset(head, 0, num_cnodes * sizeof(struct reiserfs_journal_cnode));
+ head[0].prev = NULL;
+ head[0].next = head + 1;
+ for (i = 1; i < num_cnodes; i++) {
+ head[i].prev = head + (i - 1);
+ head[i].next = head + (i + 1); /* if last one, overwrite it after the if */
+ }
+ head[num_cnodes - 1].next = NULL;
+ return head;
}
/*
** pulls a cnode off the free list, or returns NULL on failure
*/
-static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb) {
- struct reiserfs_journal_cnode *cn ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
-
- reiserfs_check_lock_depth(p_s_sb, "get_cnode") ;
-
- if (journal->j_cnode_free <= 0) {
- return NULL ;
- }
- journal->j_cnode_used++ ;
- journal->j_cnode_free-- ;
- cn = journal->j_cnode_free_list ;
- if (!cn) {
- return cn ;
- }
- if (cn->next) {
- cn->next->prev = NULL ;
- }
- journal->j_cnode_free_list = cn->next ;
- memset(cn, 0, sizeof(struct reiserfs_journal_cnode)) ;
- return cn ;
+static struct reiserfs_journal_cnode *get_cnode(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal_cnode *cn;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+
+ reiserfs_check_lock_depth(p_s_sb, "get_cnode");
+
+ if (journal->j_cnode_free <= 0) {
+ return NULL;
+ }
+ journal->j_cnode_used++;
+ journal->j_cnode_free--;
+ cn = journal->j_cnode_free_list;
+ if (!cn) {
+ return cn;
+ }
+ if (cn->next) {
+ cn->next->prev = NULL;
+ }
+ journal->j_cnode_free_list = cn->next;
+ memset(cn, 0, sizeof(struct reiserfs_journal_cnode));
+ return cn;
}
/*
** returns a cnode to the free list
*/
-static void free_cnode(struct super_block *p_s_sb, struct reiserfs_journal_cnode *cn) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
+static void free_cnode(struct super_block *p_s_sb,
+ struct reiserfs_journal_cnode *cn)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
- reiserfs_check_lock_depth(p_s_sb, "free_cnode") ;
+ reiserfs_check_lock_depth(p_s_sb, "free_cnode");
- journal->j_cnode_used-- ;
- journal->j_cnode_free++ ;
- /* memset(cn, 0, sizeof(struct reiserfs_journal_cnode)) ; */
- cn->next = journal->j_cnode_free_list ;
- if (journal->j_cnode_free_list) {
- journal->j_cnode_free_list->prev = cn ;
- }
- cn->prev = NULL ; /* not needed with the memset, but I might kill the memset, and forget to do this */
- journal->j_cnode_free_list = cn ;
+ journal->j_cnode_used--;
+ journal->j_cnode_free++;
+ /* memset(cn, 0, sizeof(struct reiserfs_journal_cnode)) ; */
+ cn->next = journal->j_cnode_free_list;
+ if (journal->j_cnode_free_list) {
+ journal->j_cnode_free_list->prev = cn;
+ }
+ cn->prev = NULL; /* not needed with the memset, but I might kill the memset, and forget to do this */
+ journal->j_cnode_free_list = cn;
}
-static void clear_prepared_bits(struct buffer_head *bh) {
- clear_buffer_journal_prepared (bh);
- clear_buffer_journal_restore_dirty (bh);
+static void clear_prepared_bits(struct buffer_head *bh)
+{
+ clear_buffer_journal_prepared(bh);
+ clear_buffer_journal_restore_dirty(bh);
}
/* utility function to force a BUG if it is called without the big
** kernel lock held. caller is the string printed just before calling BUG()
*/
-void reiserfs_check_lock_depth(struct super_block *sb, char *caller) {
+void reiserfs_check_lock_depth(struct super_block *sb, char *caller)
+{
#ifdef CONFIG_SMP
- if (current->lock_depth < 0) {
- reiserfs_panic (sb, "%s called without kernel lock held", caller) ;
- }
+ if (current->lock_depth < 0) {
+ reiserfs_panic(sb, "%s called without kernel lock held",
+ caller);
+ }
#else
- ;
+ ;
#endif
}
/* return a cnode with same dev, block number and size in table, or null if not found */
-static inline struct reiserfs_journal_cnode *
-get_journal_hash_dev(struct super_block *sb,
- struct reiserfs_journal_cnode **table,
- long bl)
+static inline struct reiserfs_journal_cnode *get_journal_hash_dev(struct
+ super_block
+ *sb,
+ struct
+ reiserfs_journal_cnode
+ **table,
+ long bl)
{
- struct reiserfs_journal_cnode *cn ;
- cn = journal_hash(table, sb, bl) ;
- while(cn) {
- if (cn->blocknr == bl && cn->sb == sb)
- return cn ;
- cn = cn->hnext ;
- }
- return (struct reiserfs_journal_cnode *)0 ;
+ struct reiserfs_journal_cnode *cn;
+ cn = journal_hash(table, sb, bl);
+ while (cn) {
+ if (cn->blocknr == bl && cn->sb == sb)
+ return cn;
+ cn = cn->hnext;
+ }
+ return (struct reiserfs_journal_cnode *)0;
}
/*
@@ -454,91 +485,103 @@ get_journal_hash_dev(struct super_block *sb,
**
*/
int reiserfs_in_journal(struct super_block *p_s_sb,
- int bmap_nr, int bit_nr, int search_all,
- b_blocknr_t *next_zero_bit) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_cnode *cn ;
- struct reiserfs_list_bitmap *jb ;
- int i ;
- unsigned long bl;
-
- *next_zero_bit = 0 ; /* always start this at zero. */
-
- PROC_INFO_INC( p_s_sb, journal.in_journal );
- /* If we aren't doing a search_all, this is a metablock, and it will be logged before use.
- ** if we crash before the transaction that freed it commits, this transaction won't
- ** have committed either, and the block will never be written
- */
- if (search_all) {
- for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
- PROC_INFO_INC( p_s_sb, journal.in_journal_bitmap );
- jb = journal->j_list_bitmap + i ;
- if (jb->journal_list && jb->bitmaps[bmap_nr] &&
- test_bit(bit_nr, (unsigned long *)jb->bitmaps[bmap_nr]->data)) {
- *next_zero_bit = find_next_zero_bit((unsigned long *)
- (jb->bitmaps[bmap_nr]->data),
- p_s_sb->s_blocksize << 3, bit_nr+1) ;
- return 1 ;
- }
- }
- }
-
- bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
- /* is it in any old transactions? */
- if (search_all && (cn = get_journal_hash_dev(p_s_sb, journal->j_list_hash_table, bl))) {
- return 1;
- }
-
- /* is it in the current transaction. This should never happen */
- if ((cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, bl))) {
- BUG();
- return 1;
- }
-
- PROC_INFO_INC( p_s_sb, journal.in_journal_reusable );
- /* safe for reuse */
- return 0 ;
+ int bmap_nr, int bit_nr, int search_all,
+ b_blocknr_t * next_zero_bit)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_cnode *cn;
+ struct reiserfs_list_bitmap *jb;
+ int i;
+ unsigned long bl;
+
+ *next_zero_bit = 0; /* always start this at zero. */
+
+ PROC_INFO_INC(p_s_sb, journal.in_journal);
+ /* If we aren't doing a search_all, this is a metablock, and it will be logged before use.
+ ** if we crash before the transaction that freed it commits, this transaction won't
+ ** have committed either, and the block will never be written
+ */
+ if (search_all) {
+ for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
+ PROC_INFO_INC(p_s_sb, journal.in_journal_bitmap);
+ jb = journal->j_list_bitmap + i;
+ if (jb->journal_list && jb->bitmaps[bmap_nr] &&
+ test_bit(bit_nr,
+ (unsigned long *)jb->bitmaps[bmap_nr]->
+ data)) {
+ *next_zero_bit =
+ find_next_zero_bit((unsigned long *)
+ (jb->bitmaps[bmap_nr]->
+ data),
+ p_s_sb->s_blocksize << 3,
+ bit_nr + 1);
+ return 1;
+ }
+ }
+ }
+
+ bl = bmap_nr * (p_s_sb->s_blocksize << 3) + bit_nr;
+ /* is it in any old transactions? */
+ if (search_all
+ && (cn =
+ get_journal_hash_dev(p_s_sb, journal->j_list_hash_table, bl))) {
+ return 1;
+ }
+
+ /* is it in the current transaction. This should never happen */
+ if ((cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, bl))) {
+ BUG();
+ return 1;
+ }
+
+ PROC_INFO_INC(p_s_sb, journal.in_journal_reusable);
+ /* safe for reuse */
+ return 0;
}
/* insert cn into table
*/
-static inline void insert_journal_hash(struct reiserfs_journal_cnode **table, struct reiserfs_journal_cnode *cn) {
- struct reiserfs_journal_cnode *cn_orig ;
+static inline void insert_journal_hash(struct reiserfs_journal_cnode **table,
+ struct reiserfs_journal_cnode *cn)
+{
+ struct reiserfs_journal_cnode *cn_orig;
- cn_orig = journal_hash(table, cn->sb, cn->blocknr) ;
- cn->hnext = cn_orig ;
- cn->hprev = NULL ;
- if (cn_orig) {
- cn_orig->hprev = cn ;
- }
- journal_hash(table, cn->sb, cn->blocknr) = cn ;
+ cn_orig = journal_hash(table, cn->sb, cn->blocknr);
+ cn->hnext = cn_orig;
+ cn->hprev = NULL;
+ if (cn_orig) {
+ cn_orig->hprev = cn;
+ }
+ journal_hash(table, cn->sb, cn->blocknr) = cn;
}
/* lock the current transaction */
-inline static void lock_journal(struct super_block *p_s_sb) {
- PROC_INFO_INC( p_s_sb, journal.lock_journal );
- down(&SB_JOURNAL(p_s_sb)->j_lock);
+inline static void lock_journal(struct super_block *p_s_sb)
+{
+ PROC_INFO_INC(p_s_sb, journal.lock_journal);
+ down(&SB_JOURNAL(p_s_sb)->j_lock);
}
/* unlock the current transaction */
-inline static void unlock_journal(struct super_block *p_s_sb) {
- up(&SB_JOURNAL(p_s_sb)->j_lock);
+inline static void unlock_journal(struct super_block *p_s_sb)
+{
+ up(&SB_JOURNAL(p_s_sb)->j_lock);
}
static inline void get_journal_list(struct reiserfs_journal_list *jl)
{
- jl->j_refcount++;
+ jl->j_refcount++;
}
static inline void put_journal_list(struct super_block *s,
- struct reiserfs_journal_list *jl)
+ struct reiserfs_journal_list *jl)
{
- if (jl->j_refcount < 1) {
- reiserfs_panic (s, "trans id %lu, refcount at %d", jl->j_trans_id,
- jl->j_refcount);
- }
- if (--jl->j_refcount == 0)
- reiserfs_kfree(jl, sizeof(struct reiserfs_journal_list), s);
+ if (jl->j_refcount < 1) {
+ reiserfs_panic(s, "trans id %lu, refcount at %d",
+ jl->j_trans_id, jl->j_refcount);
+ }
+ if (--jl->j_refcount == 0)
+ reiserfs_kfree(jl, sizeof(struct reiserfs_journal_list), s);
}
/*
@@ -546,354 +589,375 @@ static inline void put_journal_list(struct super_block *s,
** it gets called by flush_commit_list, and cleans up any data stored about blocks freed during a
** transaction.
*/
-static void cleanup_freed_for_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl) {
+static void cleanup_freed_for_journal_list(struct super_block *p_s_sb,
+ struct reiserfs_journal_list *jl)
+{
- struct reiserfs_list_bitmap *jb = jl->j_list_bitmap ;
- if (jb) {
- cleanup_bitmap_list(p_s_sb, jb) ;
- }
- jl->j_list_bitmap->journal_list = NULL ;
- jl->j_list_bitmap = NULL ;
+ struct reiserfs_list_bitmap *jb = jl->j_list_bitmap;
+ if (jb) {
+ cleanup_bitmap_list(p_s_sb, jb);
+ }
+ jl->j_list_bitmap->journal_list = NULL;
+ jl->j_list_bitmap = NULL;
}
static int journal_list_still_alive(struct super_block *s,
- unsigned long trans_id)
-{
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- struct list_head *entry = &journal->j_journal_list;
- struct reiserfs_journal_list *jl;
-
- if (!list_empty(entry)) {
- jl = JOURNAL_LIST_ENTRY(entry->next);
- if (jl->j_trans_id <= trans_id) {
- return 1;
- }
- }
- return 0;
-}
-
-static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate) {
- char b[BDEVNAME_SIZE];
-
- if (buffer_journaled(bh)) {
- reiserfs_warning(NULL, "clm-2084: pinned buffer %lu:%s sent to disk",
- bh->b_blocknr, bdevname(bh->b_bdev, b)) ;
- }
- if (uptodate)
- set_buffer_uptodate(bh) ;
- else
- clear_buffer_uptodate(bh) ;
- unlock_buffer(bh) ;
- put_bh(bh) ;
-}
-
-static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate) {
- if (uptodate)
- set_buffer_uptodate(bh) ;
- else
- clear_buffer_uptodate(bh) ;
- unlock_buffer(bh) ;
- put_bh(bh) ;
-}
-
-static void submit_logged_buffer(struct buffer_head *bh) {
- get_bh(bh) ;
- bh->b_end_io = reiserfs_end_buffer_io_sync ;
- clear_buffer_journal_new (bh);
- clear_buffer_dirty(bh) ;
- if (!test_clear_buffer_journal_test (bh))
- BUG();
- if (!buffer_uptodate(bh))
- BUG();
- submit_bh(WRITE, bh) ;
-}
-
-static void submit_ordered_buffer(struct buffer_head *bh) {
- get_bh(bh) ;
- bh->b_end_io = reiserfs_end_ordered_io;
- clear_buffer_dirty(bh) ;
- if (!buffer_uptodate(bh))
- BUG();
- submit_bh(WRITE, bh) ;
-}
-
-static int submit_barrier_buffer(struct buffer_head *bh) {
- get_bh(bh) ;
- bh->b_end_io = reiserfs_end_ordered_io;
- clear_buffer_dirty(bh) ;
- if (!buffer_uptodate(bh))
- BUG();
- return submit_bh(WRITE_BARRIER, bh) ;
+ unsigned long trans_id)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ struct list_head *entry = &journal->j_journal_list;
+ struct reiserfs_journal_list *jl;
+
+ if (!list_empty(entry)) {
+ jl = JOURNAL_LIST_ENTRY(entry->next);
+ if (jl->j_trans_id <= trans_id) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void reiserfs_end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+{
+ char b[BDEVNAME_SIZE];
+
+ if (buffer_journaled(bh)) {
+ reiserfs_warning(NULL,
+ "clm-2084: pinned buffer %lu:%s sent to disk",
+ bh->b_blocknr, bdevname(bh->b_bdev, b));
+ }
+ if (uptodate)
+ set_buffer_uptodate(bh);
+ else
+ clear_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ put_bh(bh);
+}
+
+static void reiserfs_end_ordered_io(struct buffer_head *bh, int uptodate)
+{
+ if (uptodate)
+ set_buffer_uptodate(bh);
+ else
+ clear_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ put_bh(bh);
+}
+
+static void submit_logged_buffer(struct buffer_head *bh)
+{
+ get_bh(bh);
+ bh->b_end_io = reiserfs_end_buffer_io_sync;
+ clear_buffer_journal_new(bh);
+ clear_buffer_dirty(bh);
+ if (!test_clear_buffer_journal_test(bh))
+ BUG();
+ if (!buffer_uptodate(bh))
+ BUG();
+ submit_bh(WRITE, bh);
+}
+
+static void submit_ordered_buffer(struct buffer_head *bh)
+{
+ get_bh(bh);
+ bh->b_end_io = reiserfs_end_ordered_io;
+ clear_buffer_dirty(bh);
+ if (!buffer_uptodate(bh))
+ BUG();
+ submit_bh(WRITE, bh);
+}
+
+static int submit_barrier_buffer(struct buffer_head *bh)
+{
+ get_bh(bh);
+ bh->b_end_io = reiserfs_end_ordered_io;
+ clear_buffer_dirty(bh);
+ if (!buffer_uptodate(bh))
+ BUG();
+ return submit_bh(WRITE_BARRIER, bh);
}
static void check_barrier_completion(struct super_block *s,
- struct buffer_head *bh) {
- if (buffer_eopnotsupp(bh)) {
- clear_buffer_eopnotsupp(bh);
- disable_barrier(s);
- set_buffer_uptodate(bh);
- set_buffer_dirty(bh);
- sync_dirty_buffer(bh);
- }
+ struct buffer_head *bh)
+{
+ if (buffer_eopnotsupp(bh)) {
+ clear_buffer_eopnotsupp(bh);
+ disable_barrier(s);
+ set_buffer_uptodate(bh);
+ set_buffer_dirty(bh);
+ sync_dirty_buffer(bh);
+ }
}
#define CHUNK_SIZE 32
struct buffer_chunk {
- struct buffer_head *bh[CHUNK_SIZE];
- int nr;
+ struct buffer_head *bh[CHUNK_SIZE];
+ int nr;
};
-static void write_chunk(struct buffer_chunk *chunk) {
- int i;
- for (i = 0; i < chunk->nr ; i++) {
- submit_logged_buffer(chunk->bh[i]) ;
- }
- chunk->nr = 0;
+static void write_chunk(struct buffer_chunk *chunk)
+{
+ int i;
+ get_fs_excl();
+ for (i = 0; i < chunk->nr; i++) {
+ submit_logged_buffer(chunk->bh[i]);
+ }
+ chunk->nr = 0;
+ put_fs_excl();
}
-static void write_ordered_chunk(struct buffer_chunk *chunk) {
- int i;
- for (i = 0; i < chunk->nr ; i++) {
- submit_ordered_buffer(chunk->bh[i]) ;
- }
- chunk->nr = 0;
+static void write_ordered_chunk(struct buffer_chunk *chunk)
+{
+ int i;
+ get_fs_excl();
+ for (i = 0; i < chunk->nr; i++) {
+ submit_ordered_buffer(chunk->bh[i]);
+ }
+ chunk->nr = 0;
+ put_fs_excl();
}
static int add_to_chunk(struct buffer_chunk *chunk, struct buffer_head *bh,
- spinlock_t *lock,
- void (fn)(struct buffer_chunk *))
+ spinlock_t * lock, void (fn) (struct buffer_chunk *))
{
- int ret = 0;
- if (chunk->nr >= CHUNK_SIZE)
- BUG();
- chunk->bh[chunk->nr++] = bh;
- if (chunk->nr >= CHUNK_SIZE) {
- ret = 1;
- if (lock)
- spin_unlock(lock);
- fn(chunk);
- if (lock)
- spin_lock(lock);
- }
- return ret;
+ int ret = 0;
+ if (chunk->nr >= CHUNK_SIZE)
+ BUG();
+ chunk->bh[chunk->nr++] = bh;
+ if (chunk->nr >= CHUNK_SIZE) {
+ ret = 1;
+ if (lock)
+ spin_unlock(lock);
+ fn(chunk);
+ if (lock)
+ spin_lock(lock);
+ }
+ return ret;
}
-
static atomic_t nr_reiserfs_jh = ATOMIC_INIT(0);
-static struct reiserfs_jh *alloc_jh(void) {
- struct reiserfs_jh *jh;
- while(1) {
- jh = kmalloc(sizeof(*jh), GFP_NOFS);
- if (jh) {
- atomic_inc(&nr_reiserfs_jh);
- return jh;
+static struct reiserfs_jh *alloc_jh(void)
+{
+ struct reiserfs_jh *jh;
+ while (1) {
+ jh = kmalloc(sizeof(*jh), GFP_NOFS);
+ if (jh) {
+ atomic_inc(&nr_reiserfs_jh);
+ return jh;
+ }
+ yield();
}
- yield();
- }
}
/*
* we want to free the jh when the buffer has been written
* and waited on
*/
-void reiserfs_free_jh(struct buffer_head *bh) {
- struct reiserfs_jh *jh;
-
- jh = bh->b_private;
- if (jh) {
- bh->b_private = NULL;
- jh->bh = NULL;
- list_del_init(&jh->list);
- kfree(jh);
- if (atomic_read(&nr_reiserfs_jh) <= 0)
- BUG();
- atomic_dec(&nr_reiserfs_jh);
- put_bh(bh);
- }
+void reiserfs_free_jh(struct buffer_head *bh)
+{
+ struct reiserfs_jh *jh;
+
+ jh = bh->b_private;
+ if (jh) {
+ bh->b_private = NULL;
+ jh->bh = NULL;
+ list_del_init(&jh->list);
+ kfree(jh);
+ if (atomic_read(&nr_reiserfs_jh) <= 0)
+ BUG();
+ atomic_dec(&nr_reiserfs_jh);
+ put_bh(bh);
+ }
}
static inline int __add_jh(struct reiserfs_journal *j, struct buffer_head *bh,
- int tail)
+ int tail)
{
- struct reiserfs_jh *jh;
+ struct reiserfs_jh *jh;
- if (bh->b_private) {
- spin_lock(&j->j_dirty_buffers_lock);
- if (!bh->b_private) {
- spin_unlock(&j->j_dirty_buffers_lock);
- goto no_jh;
+ if (bh->b_private) {
+ spin_lock(&j->j_dirty_buffers_lock);
+ if (!bh->b_private) {
+ spin_unlock(&j->j_dirty_buffers_lock);
+ goto no_jh;
+ }
+ jh = bh->b_private;
+ list_del_init(&jh->list);
+ } else {
+ no_jh:
+ get_bh(bh);
+ jh = alloc_jh();
+ spin_lock(&j->j_dirty_buffers_lock);
+ /* buffer must be locked for __add_jh, should be able to have
+ * two adds at the same time
+ */
+ if (bh->b_private)
+ BUG();
+ jh->bh = bh;
+ bh->b_private = jh;
}
- jh = bh->b_private;
- list_del_init(&jh->list);
- } else {
-no_jh:
- get_bh(bh);
- jh = alloc_jh();
- spin_lock(&j->j_dirty_buffers_lock);
- /* buffer must be locked for __add_jh, should be able to have
- * two adds at the same time
- */
- if (bh->b_private)
- BUG();
- jh->bh = bh;
- bh->b_private = jh;
- }
- jh->jl = j->j_current_jl;
- if (tail)
- list_add_tail(&jh->list, &jh->jl->j_tail_bh_list);
- else {
- list_add_tail(&jh->list, &jh->jl->j_bh_list);
- }
- spin_unlock(&j->j_dirty_buffers_lock);
- return 0;
+ jh->jl = j->j_current_jl;
+ if (tail)
+ list_add_tail(&jh->list, &jh->jl->j_tail_bh_list);
+ else {
+ list_add_tail(&jh->list, &jh->jl->j_bh_list);
+ }
+ spin_unlock(&j->j_dirty_buffers_lock);
+ return 0;
}
-int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh) {
- return __add_jh(SB_JOURNAL(inode->i_sb), bh, 1);
+int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh)
+{
+ return __add_jh(SB_JOURNAL(inode->i_sb), bh, 1);
}
-int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh) {
- return __add_jh(SB_JOURNAL(inode->i_sb), bh, 0);
+int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh)
+{
+ return __add_jh(SB_JOURNAL(inode->i_sb), bh, 0);
}
#define JH_ENTRY(l) list_entry((l), struct reiserfs_jh, list)
-static int write_ordered_buffers(spinlock_t *lock,
+static int write_ordered_buffers(spinlock_t * lock,
struct reiserfs_journal *j,
- struct reiserfs_journal_list *jl,
+ struct reiserfs_journal_list *jl,
struct list_head *list)
{
- struct buffer_head *bh;
- struct reiserfs_jh *jh;
- int ret = j->j_errno;
- struct buffer_chunk chunk;
- struct list_head tmp;
- INIT_LIST_HEAD(&tmp);
-
- chunk.nr = 0;
- spin_lock(lock);
- while(!list_empty(list)) {
- jh = JH_ENTRY(list->next);
- bh = jh->bh;
- get_bh(bh);
- if (test_set_buffer_locked(bh)) {
- if (!buffer_dirty(bh)) {
- list_del_init(&jh->list);
- list_add(&jh->list, &tmp);
- goto loop_next;
- }
- spin_unlock(lock);
- if (chunk.nr)
+ struct buffer_head *bh;
+ struct reiserfs_jh *jh;
+ int ret = j->j_errno;
+ struct buffer_chunk chunk;
+ struct list_head tmp;
+ INIT_LIST_HEAD(&tmp);
+
+ chunk.nr = 0;
+ spin_lock(lock);
+ while (!list_empty(list)) {
+ jh = JH_ENTRY(list->next);
+ bh = jh->bh;
+ get_bh(bh);
+ if (test_set_buffer_locked(bh)) {
+ if (!buffer_dirty(bh)) {
+ list_del_init(&jh->list);
+ list_add(&jh->list, &tmp);
+ goto loop_next;
+ }
+ spin_unlock(lock);
+ if (chunk.nr)
+ write_ordered_chunk(&chunk);
+ wait_on_buffer(bh);
+ cond_resched();
+ spin_lock(lock);
+ goto loop_next;
+ }
+ if (buffer_dirty(bh)) {
+ list_del_init(&jh->list);
+ list_add(&jh->list, &tmp);
+ add_to_chunk(&chunk, bh, lock, write_ordered_chunk);
+ } else {
+ reiserfs_free_jh(bh);
+ unlock_buffer(bh);
+ }
+ loop_next:
+ put_bh(bh);
+ cond_resched_lock(lock);
+ }
+ if (chunk.nr) {
+ spin_unlock(lock);
write_ordered_chunk(&chunk);
- wait_on_buffer(bh);
- cond_resched();
- spin_lock(lock);
- goto loop_next;
- }
- if (buffer_dirty(bh)) {
- list_del_init(&jh->list);
- list_add(&jh->list, &tmp);
- add_to_chunk(&chunk, bh, lock, write_ordered_chunk);
- } else {
- reiserfs_free_jh(bh);
- unlock_buffer(bh);
+ spin_lock(lock);
}
-loop_next:
- put_bh(bh);
- cond_resched_lock(lock);
- }
- if (chunk.nr) {
- spin_unlock(lock);
- write_ordered_chunk(&chunk);
- spin_lock(lock);
- }
- while(!list_empty(&tmp)) {
- jh = JH_ENTRY(tmp.prev);
- bh = jh->bh;
- get_bh(bh);
- reiserfs_free_jh(bh);
-
- if (buffer_locked(bh)) {
- spin_unlock(lock);
- wait_on_buffer(bh);
- spin_lock(lock);
+ while (!list_empty(&tmp)) {
+ jh = JH_ENTRY(tmp.prev);
+ bh = jh->bh;
+ get_bh(bh);
+ reiserfs_free_jh(bh);
+
+ if (buffer_locked(bh)) {
+ spin_unlock(lock);
+ wait_on_buffer(bh);
+ spin_lock(lock);
+ }
+ if (!buffer_uptodate(bh)) {
+ ret = -EIO;
+ }
+ put_bh(bh);
+ cond_resched_lock(lock);
}
- if (!buffer_uptodate(bh)) {
- ret = -EIO;
- }
- put_bh(bh);
- cond_resched_lock(lock);
- }
- spin_unlock(lock);
- return ret;
-}
-
-static int flush_older_commits(struct super_block *s, struct reiserfs_journal_list *jl) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- struct reiserfs_journal_list *other_jl;
- struct reiserfs_journal_list *first_jl;
- struct list_head *entry;
- unsigned long trans_id = jl->j_trans_id;
- unsigned long other_trans_id;
- unsigned long first_trans_id;
-
-find_first:
- /*
- * first we walk backwards to find the oldest uncommitted transation
- */
- first_jl = jl;
- entry = jl->j_list.prev;
- while(1) {
- other_jl = JOURNAL_LIST_ENTRY(entry);
- if (entry == &journal->j_journal_list ||
- atomic_read(&other_jl->j_older_commits_done))
- break;
-
- first_jl = other_jl;
- entry = other_jl->j_list.prev;
- }
-
- /* if we didn't find any older uncommitted transactions, return now */
- if (first_jl == jl) {
- return 0;
- }
-
- first_trans_id = first_jl->j_trans_id;
+ spin_unlock(lock);
+ return ret;
+}
- entry = &first_jl->j_list;
- while(1) {
- other_jl = JOURNAL_LIST_ENTRY(entry);
- other_trans_id = other_jl->j_trans_id;
+static int flush_older_commits(struct super_block *s,
+ struct reiserfs_journal_list *jl)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ struct reiserfs_journal_list *other_jl;
+ struct reiserfs_journal_list *first_jl;
+ struct list_head *entry;
+ unsigned long trans_id = jl->j_trans_id;
+ unsigned long other_trans_id;
+ unsigned long first_trans_id;
+
+ find_first:
+ /*
+ * first we walk backwards to find the oldest uncommitted transation
+ */
+ first_jl = jl;
+ entry = jl->j_list.prev;
+ while (1) {
+ other_jl = JOURNAL_LIST_ENTRY(entry);
+ if (entry == &journal->j_journal_list ||
+ atomic_read(&other_jl->j_older_commits_done))
+ break;
- if (other_trans_id < trans_id) {
- if (atomic_read(&other_jl->j_commit_left) != 0) {
- flush_commit_list(s, other_jl, 0);
+ first_jl = other_jl;
+ entry = other_jl->j_list.prev;
+ }
- /* list we were called with is gone, return */
- if (!journal_list_still_alive(s, trans_id))
- return 1;
+ /* if we didn't find any older uncommitted transactions, return now */
+ if (first_jl == jl) {
+ return 0;
+ }
- /* the one we just flushed is gone, this means all
- * older lists are also gone, so first_jl is no longer
- * valid either. Go back to the beginning.
- */
- if (!journal_list_still_alive(s, other_trans_id)) {
- goto find_first;
+ first_trans_id = first_jl->j_trans_id;
+
+ entry = &first_jl->j_list;
+ while (1) {
+ other_jl = JOURNAL_LIST_ENTRY(entry);
+ other_trans_id = other_jl->j_trans_id;
+
+ if (other_trans_id < trans_id) {
+ if (atomic_read(&other_jl->j_commit_left) != 0) {
+ flush_commit_list(s, other_jl, 0);
+
+ /* list we were called with is gone, return */
+ if (!journal_list_still_alive(s, trans_id))
+ return 1;
+
+ /* the one we just flushed is gone, this means all
+ * older lists are also gone, so first_jl is no longer
+ * valid either. Go back to the beginning.
+ */
+ if (!journal_list_still_alive
+ (s, other_trans_id)) {
+ goto find_first;
+ }
+ }
+ entry = entry->next;
+ if (entry == &journal->j_journal_list)
+ return 0;
+ } else {
+ return 0;
}
- }
- entry = entry->next;
- if (entry == &journal->j_journal_list)
- return 0;
- } else {
- return 0;
}
- }
- return 0;
+ return 0;
}
-int reiserfs_async_progress_wait(struct super_block *s) {
- DEFINE_WAIT(wait);
- struct reiserfs_journal *j = SB_JOURNAL(s);
- if (atomic_read(&j->j_async_throttle))
- blk_congestion_wait(WRITE, HZ/10);
- return 0;
+int reiserfs_async_progress_wait(struct super_block *s)
+{
+ DEFINE_WAIT(wait);
+ struct reiserfs_journal *j = SB_JOURNAL(s);
+ if (atomic_read(&j->j_async_throttle))
+ blk_congestion_wait(WRITE, HZ / 10);
+ return 0;
}
/*
@@ -903,209 +967,225 @@ int reiserfs_async_progress_wait(struct super_block *s) {
** Before the commit block can by written, every other log block must be safely on disk
**
*/
-static int flush_commit_list(struct super_block *s, struct reiserfs_journal_list *jl, int flushall) {
- int i;
- int bn ;
- struct buffer_head *tbh = NULL ;
- unsigned long trans_id = jl->j_trans_id;
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- int barrier = 0;
- int retval = 0;
-
- reiserfs_check_lock_depth(s, "flush_commit_list") ;
-
- if (atomic_read(&jl->j_older_commits_done)) {
- return 0 ;
- }
-
- /* before we can put our commit blocks on disk, we have to make sure everyone older than
- ** us is on disk too
- */
- BUG_ON (jl->j_len <= 0);
- BUG_ON (trans_id == journal->j_trans_id);
-
- get_journal_list(jl);
- if (flushall) {
- if (flush_older_commits(s, jl) == 1) {
- /* list disappeared during flush_older_commits. return */
- goto put_jl;
- }
- }
-
- /* make sure nobody is trying to flush this one at the same time */
- down(&jl->j_commit_lock);
- if (!journal_list_still_alive(s, trans_id)) {
- up(&jl->j_commit_lock);
- goto put_jl;
- }
- BUG_ON (jl->j_trans_id == 0);
-
- /* this commit is done, exit */
- if (atomic_read(&(jl->j_commit_left)) <= 0) {
- if (flushall) {
- atomic_set(&(jl->j_older_commits_done), 1) ;
- }
- up(&jl->j_commit_lock);
- goto put_jl;
- }
-
- if (!list_empty(&jl->j_bh_list)) {
- unlock_kernel();
- write_ordered_buffers(&journal->j_dirty_buffers_lock,
- journal, jl, &jl->j_bh_list);
- lock_kernel();
- }
- BUG_ON (!list_empty(&jl->j_bh_list));
- /*
- * for the description block and all the log blocks, submit any buffers
- * that haven't already reached the disk
- */
- atomic_inc(&journal->j_async_throttle);
- for (i = 0 ; i < (jl->j_len + 1) ; i++) {
- bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start+i) %
- SB_ONDISK_JOURNAL_SIZE(s);
- tbh = journal_find_get_block(s, bn) ;
- if (buffer_dirty(tbh)) /* redundant, ll_rw_block() checks */
- ll_rw_block(WRITE, 1, &tbh) ;
- put_bh(tbh) ;
- }
- atomic_dec(&journal->j_async_throttle);
-
- /* wait on everything written so far before writing the commit
- * if we are in barrier mode, send the commit down now
- */
- barrier = reiserfs_barrier_flush(s);
- if (barrier) {
- int ret;
- lock_buffer(jl->j_commit_bh);
- ret = submit_barrier_buffer(jl->j_commit_bh);
- if (ret == -EOPNOTSUPP) {
- set_buffer_uptodate(jl->j_commit_bh);
- disable_barrier(s);
- barrier = 0;
- }
- }
- for (i = 0 ; i < (jl->j_len + 1) ; i++) {
- bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
- (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s) ;
- tbh = journal_find_get_block(s, bn) ;
- wait_on_buffer(tbh) ;
- // since we're using ll_rw_blk above, it might have skipped over
- // a locked buffer. Double check here
- //
- if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
- sync_dirty_buffer(tbh);
- if (unlikely (!buffer_uptodate(tbh))) {
+static int flush_commit_list(struct super_block *s,
+ struct reiserfs_journal_list *jl, int flushall)
+{
+ int i;
+ int bn;
+ struct buffer_head *tbh = NULL;
+ unsigned long trans_id = jl->j_trans_id;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ int barrier = 0;
+ int retval = 0;
+
+ reiserfs_check_lock_depth(s, "flush_commit_list");
+
+ if (atomic_read(&jl->j_older_commits_done)) {
+ return 0;
+ }
+
+ get_fs_excl();
+
+ /* before we can put our commit blocks on disk, we have to make sure everyone older than
+ ** us is on disk too
+ */
+ BUG_ON(jl->j_len <= 0);
+ BUG_ON(trans_id == journal->j_trans_id);
+
+ get_journal_list(jl);
+ if (flushall) {
+ if (flush_older_commits(s, jl) == 1) {
+ /* list disappeared during flush_older_commits. return */
+ goto put_jl;
+ }
+ }
+
+ /* make sure nobody is trying to flush this one at the same time */
+ down(&jl->j_commit_lock);
+ if (!journal_list_still_alive(s, trans_id)) {
+ up(&jl->j_commit_lock);
+ goto put_jl;
+ }
+ BUG_ON(jl->j_trans_id == 0);
+
+ /* this commit is done, exit */
+ if (atomic_read(&(jl->j_commit_left)) <= 0) {
+ if (flushall) {
+ atomic_set(&(jl->j_older_commits_done), 1);
+ }
+ up(&jl->j_commit_lock);
+ goto put_jl;
+ }
+
+ if (!list_empty(&jl->j_bh_list)) {
+ unlock_kernel();
+ write_ordered_buffers(&journal->j_dirty_buffers_lock,
+ journal, jl, &jl->j_bh_list);
+ lock_kernel();
+ }
+ BUG_ON(!list_empty(&jl->j_bh_list));
+ /*
+ * for the description block and all the log blocks, submit any buffers
+ * that haven't already reached the disk
+ */
+ atomic_inc(&journal->j_async_throttle);
+ for (i = 0; i < (jl->j_len + 1); i++) {
+ bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) + (jl->j_start + i) %
+ SB_ONDISK_JOURNAL_SIZE(s);
+ tbh = journal_find_get_block(s, bn);
+ if (buffer_dirty(tbh)) /* redundant, ll_rw_block() checks */
+ ll_rw_block(WRITE, 1, &tbh);
+ put_bh(tbh);
+ }
+ atomic_dec(&journal->j_async_throttle);
+
+ /* wait on everything written so far before writing the commit
+ * if we are in barrier mode, send the commit down now
+ */
+ barrier = reiserfs_barrier_flush(s);
+ if (barrier) {
+ int ret;
+ lock_buffer(jl->j_commit_bh);
+ ret = submit_barrier_buffer(jl->j_commit_bh);
+ if (ret == -EOPNOTSUPP) {
+ set_buffer_uptodate(jl->j_commit_bh);
+ disable_barrier(s);
+ barrier = 0;
+ }
+ }
+ for (i = 0; i < (jl->j_len + 1); i++) {
+ bn = SB_ONDISK_JOURNAL_1st_BLOCK(s) +
+ (jl->j_start + i) % SB_ONDISK_JOURNAL_SIZE(s);
+ tbh = journal_find_get_block(s, bn);
+ wait_on_buffer(tbh);
+ // since we're using ll_rw_blk above, it might have skipped over
+ // a locked buffer. Double check here
+ //
+ if (buffer_dirty(tbh)) /* redundant, sync_dirty_buffer() checks */
+ sync_dirty_buffer(tbh);
+ if (unlikely(!buffer_uptodate(tbh))) {
#ifdef CONFIG_REISERFS_CHECK
- reiserfs_warning(s, "journal-601, buffer write failed") ;
+ reiserfs_warning(s, "journal-601, buffer write failed");
#endif
- retval = -EIO;
- }
- put_bh(tbh) ; /* once for journal_find_get_block */
- put_bh(tbh) ; /* once due to original getblk in do_journal_end */
- atomic_dec(&(jl->j_commit_left)) ;
- }
-
- BUG_ON (atomic_read(&(jl->j_commit_left)) != 1);
-
- if (!barrier) {
- if (buffer_dirty(jl->j_commit_bh))
- BUG();
- mark_buffer_dirty(jl->j_commit_bh) ;
- sync_dirty_buffer(jl->j_commit_bh) ;
- } else
- wait_on_buffer(jl->j_commit_bh);
-
- check_barrier_completion(s, jl->j_commit_bh);
-
- /* If there was a write error in the journal - we can't commit this
- * transaction - it will be invalid and, if successful, will just end
- * up propogating the write error out to the filesystem. */
- if (unlikely (!buffer_uptodate(jl->j_commit_bh))) {
+ retval = -EIO;
+ }
+ put_bh(tbh); /* once for journal_find_get_block */
+ put_bh(tbh); /* once due to original getblk in do_journal_end */
+ atomic_dec(&(jl->j_commit_left));
+ }
+
+ BUG_ON(atomic_read(&(jl->j_commit_left)) != 1);
+
+ if (!barrier) {
+ if (buffer_dirty(jl->j_commit_bh))
+ BUG();
+ mark_buffer_dirty(jl->j_commit_bh);
+ sync_dirty_buffer(jl->j_commit_bh);
+ } else
+ wait_on_buffer(jl->j_commit_bh);
+
+ check_barrier_completion(s, jl->j_commit_bh);
+
+ /* If there was a write error in the journal - we can't commit this
+ * transaction - it will be invalid and, if successful, will just end
+ * up propogating the write error out to the filesystem. */
+ if (unlikely(!buffer_uptodate(jl->j_commit_bh))) {
#ifdef CONFIG_REISERFS_CHECK
- reiserfs_warning(s, "journal-615: buffer write failed") ;
+ reiserfs_warning(s, "journal-615: buffer write failed");
#endif
- retval = -EIO;
- }
- bforget(jl->j_commit_bh) ;
- if (journal->j_last_commit_id != 0 &&
- (jl->j_trans_id - journal->j_last_commit_id) != 1) {
- reiserfs_warning(s, "clm-2200: last commit %lu, current %lu",
- journal->j_last_commit_id,
- jl->j_trans_id);
- }
- journal->j_last_commit_id = jl->j_trans_id;
-
- /* now, every commit block is on the disk. It is safe to allow blocks freed during this transaction to be reallocated */
- cleanup_freed_for_journal_list(s, jl) ;
-
- retval = retval ? retval : journal->j_errno;
-
- /* mark the metadata dirty */
- if (!retval)
- dirty_one_transaction(s, jl);
- atomic_dec(&(jl->j_commit_left)) ;
-
- if (flushall) {
- atomic_set(&(jl->j_older_commits_done), 1) ;
- }
- up(&jl->j_commit_lock);
-put_jl:
- put_journal_list(s, jl);
-
- if (retval)
- reiserfs_abort (s, retval, "Journal write error in %s", __FUNCTION__);
- return retval;
+ retval = -EIO;
+ }
+ bforget(jl->j_commit_bh);
+ if (journal->j_last_commit_id != 0 &&
+ (jl->j_trans_id - journal->j_last_commit_id) != 1) {
+ reiserfs_warning(s, "clm-2200: last commit %lu, current %lu",
+ journal->j_last_commit_id, jl->j_trans_id);
+ }
+ journal->j_last_commit_id = jl->j_trans_id;
+
+ /* now, every commit block is on the disk. It is safe to allow blocks freed during this transaction to be reallocated */
+ cleanup_freed_for_journal_list(s, jl);
+
+ retval = retval ? retval : journal->j_errno;
+
+ /* mark the metadata dirty */
+ if (!retval)
+ dirty_one_transaction(s, jl);
+ atomic_dec(&(jl->j_commit_left));
+
+ if (flushall) {
+ atomic_set(&(jl->j_older_commits_done), 1);
+ }
+ up(&jl->j_commit_lock);
+ put_jl:
+ put_journal_list(s, jl);
+
+ if (retval)
+ reiserfs_abort(s, retval, "Journal write error in %s",
+ __FUNCTION__);
+ put_fs_excl();
+ return retval;
}
/*
** flush_journal_list frequently needs to find a newer transaction for a given block. This does that, or
** returns NULL if it can't find anything
*/
-static struct reiserfs_journal_list *find_newer_jl_for_cn(struct reiserfs_journal_cnode *cn) {
- struct super_block *sb = cn->sb;
- b_blocknr_t blocknr = cn->blocknr ;
+static struct reiserfs_journal_list *find_newer_jl_for_cn(struct
+ reiserfs_journal_cnode
+ *cn)
+{
+ struct super_block *sb = cn->sb;
+ b_blocknr_t blocknr = cn->blocknr;
- cn = cn->hprev ;
- while(cn) {
- if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist) {
- return cn->jlist ;
- }
- cn = cn->hprev ;
- }
- return NULL ;
+ cn = cn->hprev;
+ while (cn) {
+ if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist) {
+ return cn->jlist;
+ }
+ cn = cn->hprev;
+ }
+ return NULL;
}
-static void remove_journal_hash(struct super_block *, struct reiserfs_journal_cnode **,
-struct reiserfs_journal_list *, unsigned long, int);
+static void remove_journal_hash(struct super_block *,
+ struct reiserfs_journal_cnode **,
+ struct reiserfs_journal_list *, unsigned long,
+ int);
/*
** once all the real blocks have been flushed, it is safe to remove them from the
** journal list for this transaction. Aside from freeing the cnode, this also allows the
** block to be reallocated for data blocks if it had been deleted.
*/
-static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reiserfs_journal_list *jl, int debug) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_cnode *cn, *last ;
- cn = jl->j_realblock ;
-
- /* which is better, to lock once around the whole loop, or
- ** to lock for each call to remove_journal_hash?
- */
- while(cn) {
- if (cn->blocknr != 0) {
- if (debug) {
- reiserfs_warning (p_s_sb, "block %u, bh is %d, state %ld", cn->blocknr,
- cn->bh ? 1: 0, cn->state) ;
- }
- cn->state = 0 ;
- remove_journal_hash(p_s_sb, journal->j_list_hash_table, jl, cn->blocknr, 1) ;
- }
- last = cn ;
- cn = cn->next ;
- free_cnode(p_s_sb, last) ;
- }
- jl->j_realblock = NULL ;
+static void remove_all_from_journal_list(struct super_block *p_s_sb,
+ struct reiserfs_journal_list *jl,
+ int debug)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_cnode *cn, *last;
+ cn = jl->j_realblock;
+
+ /* which is better, to lock once around the whole loop, or
+ ** to lock for each call to remove_journal_hash?
+ */
+ while (cn) {
+ if (cn->blocknr != 0) {
+ if (debug) {
+ reiserfs_warning(p_s_sb,
+ "block %u, bh is %d, state %ld",
+ cn->blocknr, cn->bh ? 1 : 0,
+ cn->state);
+ }
+ cn->state = 0;
+ remove_journal_hash(p_s_sb, journal->j_list_hash_table,
+ jl, cn->blocknr, 1);
+ }
+ last = cn;
+ cn = cn->next;
+ free_cnode(p_s_sb, last);
+ }
+ jl->j_realblock = NULL;
}
/*
@@ -1115,98 +1195,107 @@ static void remove_all_from_journal_list(struct super_block *p_s_sb, struct reis
** called by flush_journal_list, before it calls remove_all_from_journal_list
**
*/
-static int _update_journal_header_block(struct super_block *p_s_sb, unsigned long offset, unsigned long trans_id) {
- struct reiserfs_journal_header *jh ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
+static int _update_journal_header_block(struct super_block *p_s_sb,
+ unsigned long offset,
+ unsigned long trans_id)
+{
+ struct reiserfs_journal_header *jh;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
- if (reiserfs_is_journal_aborted (journal))
- return -EIO;
+ if (reiserfs_is_journal_aborted(journal))
+ return -EIO;
- if (trans_id >= journal->j_last_flush_trans_id) {
- if (buffer_locked((journal->j_header_bh))) {
- wait_on_buffer((journal->j_header_bh)) ;
- if (unlikely (!buffer_uptodate(journal->j_header_bh))) {
+ if (trans_id >= journal->j_last_flush_trans_id) {
+ if (buffer_locked((journal->j_header_bh))) {
+ wait_on_buffer((journal->j_header_bh));
+ if (unlikely(!buffer_uptodate(journal->j_header_bh))) {
#ifdef CONFIG_REISERFS_CHECK
- reiserfs_warning (p_s_sb, "journal-699: buffer write failed") ;
+ reiserfs_warning(p_s_sb,
+ "journal-699: buffer write failed");
#endif
- return -EIO;
- }
- }
- journal->j_last_flush_trans_id = trans_id ;
- journal->j_first_unflushed_offset = offset ;
- jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data) ;
- jh->j_last_flush_trans_id = cpu_to_le32(trans_id) ;
- jh->j_first_unflushed_offset = cpu_to_le32(offset) ;
- jh->j_mount_id = cpu_to_le32(journal->j_mount_id) ;
-
- if (reiserfs_barrier_flush(p_s_sb)) {
- int ret;
- lock_buffer(journal->j_header_bh);
- ret = submit_barrier_buffer(journal->j_header_bh);
- if (ret == -EOPNOTSUPP) {
- set_buffer_uptodate(journal->j_header_bh);
- disable_barrier(p_s_sb);
- goto sync;
- }
- wait_on_buffer(journal->j_header_bh);
- check_barrier_completion(p_s_sb, journal->j_header_bh);
- } else {
-sync:
- set_buffer_dirty(journal->j_header_bh) ;
- sync_dirty_buffer(journal->j_header_bh) ;
- }
- if (!buffer_uptodate(journal->j_header_bh)) {
- reiserfs_warning (p_s_sb, "journal-837: IO error during journal replay");
- return -EIO ;
- }
- }
- return 0 ;
-}
-
-static int update_journal_header_block(struct super_block *p_s_sb,
- unsigned long offset,
- unsigned long trans_id) {
- return _update_journal_header_block(p_s_sb, offset, trans_id);
+ return -EIO;
+ }
+ }
+ journal->j_last_flush_trans_id = trans_id;
+ journal->j_first_unflushed_offset = offset;
+ jh = (struct reiserfs_journal_header *)(journal->j_header_bh->
+ b_data);
+ jh->j_last_flush_trans_id = cpu_to_le32(trans_id);
+ jh->j_first_unflushed_offset = cpu_to_le32(offset);
+ jh->j_mount_id = cpu_to_le32(journal->j_mount_id);
+
+ if (reiserfs_barrier_flush(p_s_sb)) {
+ int ret;
+ lock_buffer(journal->j_header_bh);
+ ret = submit_barrier_buffer(journal->j_header_bh);
+ if (ret == -EOPNOTSUPP) {
+ set_buffer_uptodate(journal->j_header_bh);
+ disable_barrier(p_s_sb);
+ goto sync;
+ }
+ wait_on_buffer(journal->j_header_bh);
+ check_barrier_completion(p_s_sb, journal->j_header_bh);
+ } else {
+ sync:
+ set_buffer_dirty(journal->j_header_bh);
+ sync_dirty_buffer(journal->j_header_bh);
+ }
+ if (!buffer_uptodate(journal->j_header_bh)) {
+ reiserfs_warning(p_s_sb,
+ "journal-837: IO error during journal replay");
+ return -EIO;
+ }
+ }
+ return 0;
}
+
+static int update_journal_header_block(struct super_block *p_s_sb,
+ unsigned long offset,
+ unsigned long trans_id)
+{
+ return _update_journal_header_block(p_s_sb, offset, trans_id);
+}
+
/*
** flush any and all journal lists older than you are
** can only be called from flush_journal_list
*/
static int flush_older_journal_lists(struct super_block *p_s_sb,
- struct reiserfs_journal_list *jl)
-{
- struct list_head *entry;
- struct reiserfs_journal_list *other_jl ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- unsigned long trans_id = jl->j_trans_id;
-
- /* we know we are the only ones flushing things, no extra race
- * protection is required.
- */
-restart:
- entry = journal->j_journal_list.next;
- /* Did we wrap? */
- if (entry == &journal->j_journal_list)
- return 0;
- other_jl = JOURNAL_LIST_ENTRY(entry);
- if (other_jl->j_trans_id < trans_id) {
- BUG_ON (other_jl->j_refcount <= 0);
- /* do not flush all */
- flush_journal_list(p_s_sb, other_jl, 0) ;
-
- /* other_jl is now deleted from the list */
- goto restart;
- }
- return 0 ;
+ struct reiserfs_journal_list *jl)
+{
+ struct list_head *entry;
+ struct reiserfs_journal_list *other_jl;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ unsigned long trans_id = jl->j_trans_id;
+
+ /* we know we are the only ones flushing things, no extra race
+ * protection is required.
+ */
+ restart:
+ entry = journal->j_journal_list.next;
+ /* Did we wrap? */
+ if (entry == &journal->j_journal_list)
+ return 0;
+ other_jl = JOURNAL_LIST_ENTRY(entry);
+ if (other_jl->j_trans_id < trans_id) {
+ BUG_ON(other_jl->j_refcount <= 0);
+ /* do not flush all */
+ flush_journal_list(p_s_sb, other_jl, 0);
+
+ /* other_jl is now deleted from the list */
+ goto restart;
+ }
+ return 0;
}
static void del_from_work_list(struct super_block *s,
- struct reiserfs_journal_list *jl) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- if (!list_empty(&jl->j_working_list)) {
- list_del_init(&jl->j_working_list);
- journal->j_num_work_lists--;
- }
+ struct reiserfs_journal_list *jl)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ if (!list_empty(&jl->j_working_list)) {
+ list_del_init(&jl->j_working_list);
+ journal->j_num_work_lists--;
+ }
}
/* flush a journal list, both commit and real blocks
@@ -1218,383 +1307,407 @@ static void del_from_work_list(struct super_block *s,
** and the journal is locked. That means it can only be called from
** do_journal_end, or by journal_release
*/
-static int flush_journal_list(struct super_block *s,
- struct reiserfs_journal_list *jl, int flushall) {
- struct reiserfs_journal_list *pjl ;
- struct reiserfs_journal_cnode *cn, *last ;
- int count ;
- int was_jwait = 0 ;
- int was_dirty = 0 ;
- struct buffer_head *saved_bh ;
- unsigned long j_len_saved = jl->j_len ;
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- int err = 0;
-
- BUG_ON (j_len_saved <= 0);
-
- if (atomic_read(&journal->j_wcount) != 0) {
- reiserfs_warning(s, "clm-2048: flush_journal_list called with wcount %d",
- atomic_read(&journal->j_wcount)) ;
- }
- BUG_ON (jl->j_trans_id == 0);
-
- /* if flushall == 0, the lock is already held */
- if (flushall) {
- down(&journal->j_flush_sem);
- } else if (!down_trylock(&journal->j_flush_sem)) {
- BUG();
- }
-
- count = 0 ;
- if (j_len_saved > journal->j_trans_max) {
- reiserfs_panic(s, "journal-715: flush_journal_list, length is %lu, trans id %lu\n", j_len_saved, jl->j_trans_id);
- return 0 ;
- }
-
- /* if all the work is already done, get out of here */
- if (atomic_read(&(jl->j_nonzerolen)) <= 0 &&
- atomic_read(&(jl->j_commit_left)) <= 0) {
- goto flush_older_and_return ;
- }
-
- /* start by putting the commit list on disk. This will also flush
- ** the commit lists of any olders transactions
- */
- flush_commit_list(s, jl, 1) ;
-
- if (!(jl->j_state & LIST_DIRTY) && !reiserfs_is_journal_aborted (journal))
- BUG();
-
- /* are we done now? */
- if (atomic_read(&(jl->j_nonzerolen)) <= 0 &&
- atomic_read(&(jl->j_commit_left)) <= 0) {
- goto flush_older_and_return ;
- }
-
- /* loop through each cnode, see if we need to write it,
- ** or wait on a more recent transaction, or just ignore it
- */
- if (atomic_read(&(journal->j_wcount)) != 0) {
- reiserfs_panic(s, "journal-844: panic journal list is flushing, wcount is not 0\n") ;
- }
- cn = jl->j_realblock ;
- while(cn) {
- was_jwait = 0 ;
- was_dirty = 0 ;
- saved_bh = NULL ;
- /* blocknr of 0 is no longer in the hash, ignore it */
- if (cn->blocknr == 0) {
- goto free_cnode ;
- }
-
- /* This transaction failed commit. Don't write out to the disk */
- if (!(jl->j_state & LIST_DIRTY))
- goto free_cnode;
-
- pjl = find_newer_jl_for_cn(cn) ;
- /* the order is important here. We check pjl to make sure we
- ** don't clear BH_JDirty_wait if we aren't the one writing this
- ** block to disk
- */
- if (!pjl && cn->bh) {
- saved_bh = cn->bh ;
-
- /* we do this to make sure nobody releases the buffer while
- ** we are working with it
- */
- get_bh(saved_bh) ;
-
- if (buffer_journal_dirty(saved_bh)) {
- BUG_ON (!can_dirty (cn));
- was_jwait = 1 ;
- was_dirty = 1 ;
- } else if (can_dirty(cn)) {
- /* everything with !pjl && jwait should be writable */
- BUG();
- }
- }
-
- /* if someone has this block in a newer transaction, just make
- ** sure they are commited, and don't try writing it to disk
- */
- if (pjl) {
- if (atomic_read(&pjl->j_commit_left))
- flush_commit_list(s, pjl, 1) ;
- goto free_cnode ;
- }
-
- /* bh == NULL when the block got to disk on its own, OR,
- ** the block got freed in a future transaction
- */
- if (saved_bh == NULL) {
- goto free_cnode ;
- }
-
- /* this should never happen. kupdate_one_transaction has this list
- ** locked while it works, so we should never see a buffer here that
- ** is not marked JDirty_wait
- */
- if ((!was_jwait) && !buffer_locked(saved_bh)) {
- reiserfs_warning (s, "journal-813: BAD! buffer %llu %cdirty %cjwait, "
- "not in a newer tranasction",
- (unsigned long long)saved_bh->b_blocknr,
- was_dirty ? ' ' : '!', was_jwait ? ' ' : '!') ;
- }
- if (was_dirty) {
- /* we inc again because saved_bh gets decremented at free_cnode */
- get_bh(saved_bh) ;
- set_bit(BLOCK_NEEDS_FLUSH, &cn->state) ;
- lock_buffer(saved_bh);
- BUG_ON (cn->blocknr != saved_bh->b_blocknr);
- if (buffer_dirty(saved_bh))
- submit_logged_buffer(saved_bh) ;
- else
- unlock_buffer(saved_bh);
- count++ ;
- } else {
- reiserfs_warning (s, "clm-2082: Unable to flush buffer %llu in %s",
- (unsigned long long)saved_bh->b_blocknr, __FUNCTION__);
- }
-free_cnode:
- last = cn ;
- cn = cn->next ;
- if (saved_bh) {
- /* we incremented this to keep others from taking the buffer head away */
- put_bh(saved_bh) ;
- if (atomic_read(&(saved_bh->b_count)) < 0) {
- reiserfs_warning (s, "journal-945: saved_bh->b_count < 0");
- }
- }
- }
- if (count > 0) {
- cn = jl->j_realblock ;
- while(cn) {
- if (test_bit(BLOCK_NEEDS_FLUSH, &cn->state)) {
- if (!cn->bh) {
- reiserfs_panic(s, "journal-1011: cn->bh is NULL\n") ;
- }
- wait_on_buffer(cn->bh) ;
- if (!cn->bh) {
- reiserfs_panic(s, "journal-1012: cn->bh is NULL\n") ;
- }
- if (unlikely (!buffer_uptodate(cn->bh))) {
+static int flush_journal_list(struct super_block *s,
+ struct reiserfs_journal_list *jl, int flushall)
+{
+ struct reiserfs_journal_list *pjl;
+ struct reiserfs_journal_cnode *cn, *last;
+ int count;
+ int was_jwait = 0;
+ int was_dirty = 0;
+ struct buffer_head *saved_bh;
+ unsigned long j_len_saved = jl->j_len;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ int err = 0;
+
+ BUG_ON(j_len_saved <= 0);
+
+ if (atomic_read(&journal->j_wcount) != 0) {
+ reiserfs_warning(s,
+ "clm-2048: flush_journal_list called with wcount %d",
+ atomic_read(&journal->j_wcount));
+ }
+ BUG_ON(jl->j_trans_id == 0);
+
+ /* if flushall == 0, the lock is already held */
+ if (flushall) {
+ down(&journal->j_flush_sem);
+ } else if (!down_trylock(&journal->j_flush_sem)) {
+ BUG();
+ }
+
+ count = 0;
+ if (j_len_saved > journal->j_trans_max) {
+ reiserfs_panic(s,
+ "journal-715: flush_journal_list, length is %lu, trans id %lu\n",
+ j_len_saved, jl->j_trans_id);
+ return 0;
+ }
+
+ get_fs_excl();
+
+ /* if all the work is already done, get out of here */
+ if (atomic_read(&(jl->j_nonzerolen)) <= 0 &&
+ atomic_read(&(jl->j_commit_left)) <= 0) {
+ goto flush_older_and_return;
+ }
+
+ /* start by putting the commit list on disk. This will also flush
+ ** the commit lists of any olders transactions
+ */
+ flush_commit_list(s, jl, 1);
+
+ if (!(jl->j_state & LIST_DIRTY)
+ && !reiserfs_is_journal_aborted(journal))
+ BUG();
+
+ /* are we done now? */
+ if (atomic_read(&(jl->j_nonzerolen)) <= 0 &&
+ atomic_read(&(jl->j_commit_left)) <= 0) {
+ goto flush_older_and_return;
+ }
+
+ /* loop through each cnode, see if we need to write it,
+ ** or wait on a more recent transaction, or just ignore it
+ */
+ if (atomic_read(&(journal->j_wcount)) != 0) {
+ reiserfs_panic(s,
+ "journal-844: panic journal list is flushing, wcount is not 0\n");
+ }
+ cn = jl->j_realblock;
+ while (cn) {
+ was_jwait = 0;
+ was_dirty = 0;
+ saved_bh = NULL;
+ /* blocknr of 0 is no longer in the hash, ignore it */
+ if (cn->blocknr == 0) {
+ goto free_cnode;
+ }
+
+ /* This transaction failed commit. Don't write out to the disk */
+ if (!(jl->j_state & LIST_DIRTY))
+ goto free_cnode;
+
+ pjl = find_newer_jl_for_cn(cn);
+ /* the order is important here. We check pjl to make sure we
+ ** don't clear BH_JDirty_wait if we aren't the one writing this
+ ** block to disk
+ */
+ if (!pjl && cn->bh) {
+ saved_bh = cn->bh;
+
+ /* we do this to make sure nobody releases the buffer while
+ ** we are working with it
+ */
+ get_bh(saved_bh);
+
+ if (buffer_journal_dirty(saved_bh)) {
+ BUG_ON(!can_dirty(cn));
+ was_jwait = 1;
+ was_dirty = 1;
+ } else if (can_dirty(cn)) {
+ /* everything with !pjl && jwait should be writable */
+ BUG();
+ }
+ }
+
+ /* if someone has this block in a newer transaction, just make
+ ** sure they are commited, and don't try writing it to disk
+ */
+ if (pjl) {
+ if (atomic_read(&pjl->j_commit_left))
+ flush_commit_list(s, pjl, 1);
+ goto free_cnode;
+ }
+
+ /* bh == NULL when the block got to disk on its own, OR,
+ ** the block got freed in a future transaction
+ */
+ if (saved_bh == NULL) {
+ goto free_cnode;
+ }
+
+ /* this should never happen. kupdate_one_transaction has this list
+ ** locked while it works, so we should never see a buffer here that
+ ** is not marked JDirty_wait
+ */
+ if ((!was_jwait) && !buffer_locked(saved_bh)) {
+ reiserfs_warning(s,
+ "journal-813: BAD! buffer %llu %cdirty %cjwait, "
+ "not in a newer tranasction",
+ (unsigned long long)saved_bh->
+ b_blocknr, was_dirty ? ' ' : '!',
+ was_jwait ? ' ' : '!');
+ }
+ if (was_dirty) {
+ /* we inc again because saved_bh gets decremented at free_cnode */
+ get_bh(saved_bh);
+ set_bit(BLOCK_NEEDS_FLUSH, &cn->state);
+ lock_buffer(saved_bh);
+ BUG_ON(cn->blocknr != saved_bh->b_blocknr);
+ if (buffer_dirty(saved_bh))
+ submit_logged_buffer(saved_bh);
+ else
+ unlock_buffer(saved_bh);
+ count++;
+ } else {
+ reiserfs_warning(s,
+ "clm-2082: Unable to flush buffer %llu in %s",
+ (unsigned long long)saved_bh->
+ b_blocknr, __FUNCTION__);
+ }
+ free_cnode:
+ last = cn;
+ cn = cn->next;
+ if (saved_bh) {
+ /* we incremented this to keep others from taking the buffer head away */
+ put_bh(saved_bh);
+ if (atomic_read(&(saved_bh->b_count)) < 0) {
+ reiserfs_warning(s,
+ "journal-945: saved_bh->b_count < 0");
+ }
+ }
+ }
+ if (count > 0) {
+ cn = jl->j_realblock;
+ while (cn) {
+ if (test_bit(BLOCK_NEEDS_FLUSH, &cn->state)) {
+ if (!cn->bh) {
+ reiserfs_panic(s,
+ "journal-1011: cn->bh is NULL\n");
+ }
+ wait_on_buffer(cn->bh);
+ if (!cn->bh) {
+ reiserfs_panic(s,
+ "journal-1012: cn->bh is NULL\n");
+ }
+ if (unlikely(!buffer_uptodate(cn->bh))) {
#ifdef CONFIG_REISERFS_CHECK
- reiserfs_warning(s, "journal-949: buffer write failed\n") ;
+ reiserfs_warning(s,
+ "journal-949: buffer write failed\n");
#endif
- err = -EIO;
- }
- /* note, we must clear the JDirty_wait bit after the up to date
- ** check, otherwise we race against our flushpage routine
- */
- BUG_ON (!test_clear_buffer_journal_dirty (cn->bh));
-
- /* undo the inc from journal_mark_dirty */
- put_bh(cn->bh) ;
- brelse(cn->bh) ;
- }
- cn = cn->next ;
- }
- }
-
- if (err)
- reiserfs_abort (s, -EIO, "Write error while pushing transaction to disk in %s", __FUNCTION__);
-flush_older_and_return:
-
-
- /* before we can update the journal header block, we _must_ flush all
- ** real blocks from all older transactions to disk. This is because
- ** once the header block is updated, this transaction will not be
- ** replayed after a crash
- */
- if (flushall) {
- flush_older_journal_lists(s, jl);
- }
-
- err = journal->j_errno;
- /* before we can remove everything from the hash tables for this
- ** transaction, we must make sure it can never be replayed
- **
- ** since we are only called from do_journal_end, we know for sure there
- ** are no allocations going on while we are flushing journal lists. So,
- ** we only need to update the journal header block for the last list
- ** being flushed
- */
- if (!err && flushall) {
- err = update_journal_header_block(s, (jl->j_start + jl->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(s), jl->j_trans_id) ;
- if (err)
- reiserfs_abort (s, -EIO, "Write error while updating journal header in %s", __FUNCTION__);
- }
- remove_all_from_journal_list(s, jl, 0) ;
- list_del_init(&jl->j_list);
- journal->j_num_lists--;
- del_from_work_list(s, jl);
-
- if (journal->j_last_flush_id != 0 &&
- (jl->j_trans_id - journal->j_last_flush_id) != 1) {
- reiserfs_warning(s, "clm-2201: last flush %lu, current %lu",
- journal->j_last_flush_id,
- jl->j_trans_id);
- }
- journal->j_last_flush_id = jl->j_trans_id;
-
- /* not strictly required since we are freeing the list, but it should
- * help find code using dead lists later on
- */
- jl->j_len = 0 ;
- atomic_set(&(jl->j_nonzerolen), 0) ;
- jl->j_start = 0 ;
- jl->j_realblock = NULL ;
- jl->j_commit_bh = NULL ;
- jl->j_trans_id = 0 ;
- jl->j_state = 0;
- put_journal_list(s, jl);
- if (flushall)
- up(&journal->j_flush_sem);
- return err ;
-}
+ err = -EIO;
+ }
+ /* note, we must clear the JDirty_wait bit after the up to date
+ ** check, otherwise we race against our flushpage routine
+ */
+ BUG_ON(!test_clear_buffer_journal_dirty
+ (cn->bh));
+
+ /* undo the inc from journal_mark_dirty */
+ put_bh(cn->bh);
+ brelse(cn->bh);
+ }
+ cn = cn->next;
+ }
+ }
+
+ if (err)
+ reiserfs_abort(s, -EIO,
+ "Write error while pushing transaction to disk in %s",
+ __FUNCTION__);
+ flush_older_and_return:
+
+ /* before we can update the journal header block, we _must_ flush all
+ ** real blocks from all older transactions to disk. This is because
+ ** once the header block is updated, this transaction will not be
+ ** replayed after a crash
+ */
+ if (flushall) {
+ flush_older_journal_lists(s, jl);
+ }
+
+ err = journal->j_errno;
+ /* before we can remove everything from the hash tables for this
+ ** transaction, we must make sure it can never be replayed
+ **
+ ** since we are only called from do_journal_end, we know for sure there
+ ** are no allocations going on while we are flushing journal lists. So,
+ ** we only need to update the journal header block for the last list
+ ** being flushed
+ */
+ if (!err && flushall) {
+ err =
+ update_journal_header_block(s,
+ (jl->j_start + jl->j_len +
+ 2) % SB_ONDISK_JOURNAL_SIZE(s),
+ jl->j_trans_id);
+ if (err)
+ reiserfs_abort(s, -EIO,
+ "Write error while updating journal header in %s",
+ __FUNCTION__);
+ }
+ remove_all_from_journal_list(s, jl, 0);
+ list_del_init(&jl->j_list);
+ journal->j_num_lists--;
+ del_from_work_list(s, jl);
+
+ if (journal->j_last_flush_id != 0 &&
+ (jl->j_trans_id - journal->j_last_flush_id) != 1) {
+ reiserfs_warning(s, "clm-2201: last flush %lu, current %lu",
+ journal->j_last_flush_id, jl->j_trans_id);
+ }
+ journal->j_last_flush_id = jl->j_trans_id;
+
+ /* not strictly required since we are freeing the list, but it should
+ * help find code using dead lists later on
+ */
+ jl->j_len = 0;
+ atomic_set(&(jl->j_nonzerolen), 0);
+ jl->j_start = 0;
+ jl->j_realblock = NULL;
+ jl->j_commit_bh = NULL;
+ jl->j_trans_id = 0;
+ jl->j_state = 0;
+ put_journal_list(s, jl);
+ if (flushall)
+ up(&journal->j_flush_sem);
+ put_fs_excl();
+ return err;
+}
static int write_one_transaction(struct super_block *s,
- struct reiserfs_journal_list *jl,
+ struct reiserfs_journal_list *jl,
struct buffer_chunk *chunk)
{
- struct reiserfs_journal_cnode *cn;
- int ret = 0 ;
-
- jl->j_state |= LIST_TOUCHED;
- del_from_work_list(s, jl);
- if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0) {
- return 0;
- }
-
- cn = jl->j_realblock ;
- while(cn) {
- /* if the blocknr == 0, this has been cleared from the hash,
- ** skip it
- */
- if (cn->blocknr == 0) {
- goto next ;
- }
- if (cn->bh && can_dirty(cn) && buffer_dirty(cn->bh)) {
- struct buffer_head *tmp_bh;
- /* we can race against journal_mark_freed when we try
- * to lock_buffer(cn->bh), so we have to inc the buffer
- * count, and recheck things after locking
- */
- tmp_bh = cn->bh;
- get_bh(tmp_bh);
- lock_buffer(tmp_bh);
- if (cn->bh && can_dirty(cn) && buffer_dirty(tmp_bh)) {
- if (!buffer_journal_dirty(tmp_bh) ||
- buffer_journal_prepared(tmp_bh))
- BUG();
- add_to_chunk(chunk, tmp_bh, NULL, write_chunk);
- ret++;
- } else {
- /* note, cn->bh might be null now */
- unlock_buffer(tmp_bh);
- }
- put_bh(tmp_bh);
- }
-next:
- cn = cn->next ;
- cond_resched();
- }
- return ret ;
+ struct reiserfs_journal_cnode *cn;
+ int ret = 0;
+
+ jl->j_state |= LIST_TOUCHED;
+ del_from_work_list(s, jl);
+ if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0) {
+ return 0;
+ }
+
+ cn = jl->j_realblock;
+ while (cn) {
+ /* if the blocknr == 0, this has been cleared from the hash,
+ ** skip it
+ */
+ if (cn->blocknr == 0) {
+ goto next;
+ }
+ if (cn->bh && can_dirty(cn) && buffer_dirty(cn->bh)) {
+ struct buffer_head *tmp_bh;
+ /* we can race against journal_mark_freed when we try
+ * to lock_buffer(cn->bh), so we have to inc the buffer
+ * count, and recheck things after locking
+ */
+ tmp_bh = cn->bh;
+ get_bh(tmp_bh);
+ lock_buffer(tmp_bh);
+ if (cn->bh && can_dirty(cn) && buffer_dirty(tmp_bh)) {
+ if (!buffer_journal_dirty(tmp_bh) ||
+ buffer_journal_prepared(tmp_bh))
+ BUG();
+ add_to_chunk(chunk, tmp_bh, NULL, write_chunk);
+ ret++;
+ } else {
+ /* note, cn->bh might be null now */
+ unlock_buffer(tmp_bh);
+ }
+ put_bh(tmp_bh);
+ }
+ next:
+ cn = cn->next;
+ cond_resched();
+ }
+ return ret;
}
/* used by flush_commit_list */
static int dirty_one_transaction(struct super_block *s,
- struct reiserfs_journal_list *jl)
-{
- struct reiserfs_journal_cnode *cn;
- struct reiserfs_journal_list *pjl;
- int ret = 0 ;
-
- jl->j_state |= LIST_DIRTY;
- cn = jl->j_realblock ;
- while(cn) {
- /* look for a more recent transaction that logged this
- ** buffer. Only the most recent transaction with a buffer in
- ** it is allowed to send that buffer to disk
- */
- pjl = find_newer_jl_for_cn(cn) ;
- if (!pjl && cn->blocknr && cn->bh && buffer_journal_dirty(cn->bh))
- {
- BUG_ON (!can_dirty(cn));
- /* if the buffer is prepared, it will either be logged
- * or restored. If restored, we need to make sure
- * it actually gets marked dirty
- */
- clear_buffer_journal_new (cn->bh);
- if (buffer_journal_prepared (cn->bh)) {
- set_buffer_journal_restore_dirty (cn->bh);
- } else {
- set_buffer_journal_test (cn->bh);
- mark_buffer_dirty(cn->bh);
- }
- }
- cn = cn->next ;
- }
- return ret ;
+ struct reiserfs_journal_list *jl)
+{
+ struct reiserfs_journal_cnode *cn;
+ struct reiserfs_journal_list *pjl;
+ int ret = 0;
+
+ jl->j_state |= LIST_DIRTY;
+ cn = jl->j_realblock;
+ while (cn) {
+ /* look for a more recent transaction that logged this
+ ** buffer. Only the most recent transaction with a buffer in
+ ** it is allowed to send that buffer to disk
+ */
+ pjl = find_newer_jl_for_cn(cn);
+ if (!pjl && cn->blocknr && cn->bh
+ && buffer_journal_dirty(cn->bh)) {
+ BUG_ON(!can_dirty(cn));
+ /* if the buffer is prepared, it will either be logged
+ * or restored. If restored, we need to make sure
+ * it actually gets marked dirty
+ */
+ clear_buffer_journal_new(cn->bh);
+ if (buffer_journal_prepared(cn->bh)) {
+ set_buffer_journal_restore_dirty(cn->bh);
+ } else {
+ set_buffer_journal_test(cn->bh);
+ mark_buffer_dirty(cn->bh);
+ }
+ }
+ cn = cn->next;
+ }
+ return ret;
}
static int kupdate_transactions(struct super_block *s,
- struct reiserfs_journal_list *jl,
- struct reiserfs_journal_list **next_jl,
- unsigned long *next_trans_id,
- int num_blocks,
- int num_trans) {
- int ret = 0;
- int written = 0 ;
- int transactions_flushed = 0;
- unsigned long orig_trans_id = jl->j_trans_id;
- struct buffer_chunk chunk;
- struct list_head *entry;
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- chunk.nr = 0;
-
- down(&journal->j_flush_sem);
- if (!journal_list_still_alive(s, orig_trans_id)) {
- goto done;
- }
-
- /* we've got j_flush_sem held, nobody is going to delete any
- * of these lists out from underneath us
- */
- while((num_trans && transactions_flushed < num_trans) ||
- (!num_trans && written < num_blocks)) {
-
- if (jl->j_len == 0 || (jl->j_state & LIST_TOUCHED) ||
- atomic_read(&jl->j_commit_left) || !(jl->j_state & LIST_DIRTY))
- {
- del_from_work_list(s, jl);
- break;
- }
- ret = write_one_transaction(s, jl, &chunk);
-
- if (ret < 0)
- goto done;
- transactions_flushed++;
- written += ret;
- entry = jl->j_list.next;
-
- /* did we wrap? */
- if (entry == &journal->j_journal_list) {
- break;
- }
- jl = JOURNAL_LIST_ENTRY(entry);
-
- /* don't bother with older transactions */
- if (jl->j_trans_id <= orig_trans_id)
- break;
- }
- if (chunk.nr) {
- write_chunk(&chunk);
- }
-
-done:
- up(&journal->j_flush_sem);
- return ret;
+ struct reiserfs_journal_list *jl,
+ struct reiserfs_journal_list **next_jl,
+ unsigned long *next_trans_id,
+ int num_blocks, int num_trans)
+{
+ int ret = 0;
+ int written = 0;
+ int transactions_flushed = 0;
+ unsigned long orig_trans_id = jl->j_trans_id;
+ struct buffer_chunk chunk;
+ struct list_head *entry;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ chunk.nr = 0;
+
+ down(&journal->j_flush_sem);
+ if (!journal_list_still_alive(s, orig_trans_id)) {
+ goto done;
+ }
+
+ /* we've got j_flush_sem held, nobody is going to delete any
+ * of these lists out from underneath us
+ */
+ while ((num_trans && transactions_flushed < num_trans) ||
+ (!num_trans && written < num_blocks)) {
+
+ if (jl->j_len == 0 || (jl->j_state & LIST_TOUCHED) ||
+ atomic_read(&jl->j_commit_left)
+ || !(jl->j_state & LIST_DIRTY)) {
+ del_from_work_list(s, jl);
+ break;
+ }
+ ret = write_one_transaction(s, jl, &chunk);
+
+ if (ret < 0)
+ goto done;
+ transactions_flushed++;
+ written += ret;
+ entry = jl->j_list.next;
+
+ /* did we wrap? */
+ if (entry == &journal->j_journal_list) {
+ break;
+ }
+ jl = JOURNAL_LIST_ENTRY(entry);
+
+ /* don't bother with older transactions */
+ if (jl->j_trans_id <= orig_trans_id)
+ break;
+ }
+ if (chunk.nr) {
+ write_chunk(&chunk);
+ }
+
+ done:
+ up(&journal->j_flush_sem);
+ return ret;
}
/* for o_sync and fsync heavy applications, they tend to use
@@ -1607,47 +1720,48 @@ done:
** list updates the header block
*/
static int flush_used_journal_lists(struct super_block *s,
- struct reiserfs_journal_list *jl) {
- unsigned long len = 0;
- unsigned long cur_len;
- int ret;
- int i;
- int limit = 256;
- struct reiserfs_journal_list *tjl;
- struct reiserfs_journal_list *flush_jl;
- unsigned long trans_id;
- struct reiserfs_journal *journal = SB_JOURNAL (s);
-
- flush_jl = tjl = jl;
-
- /* in data logging mode, try harder to flush a lot of blocks */
- if (reiserfs_data_log(s))
- limit = 1024;
- /* flush for 256 transactions or limit blocks, whichever comes first */
- for(i = 0 ; i < 256 && len < limit ; i++) {
- if (atomic_read(&tjl->j_commit_left) ||
- tjl->j_trans_id < jl->j_trans_id) {
- break;
- }
- cur_len = atomic_read(&tjl->j_nonzerolen);
- if (cur_len > 0) {
- tjl->j_state &= ~LIST_TOUCHED;
- }
- len += cur_len;
- flush_jl = tjl;
- if (tjl->j_list.next == &journal->j_journal_list)
- break;
- tjl = JOURNAL_LIST_ENTRY(tjl->j_list.next);
- }
- /* try to find a group of blocks we can flush across all the
- ** transactions, but only bother if we've actually spanned
- ** across multiple lists
- */
- if (flush_jl != jl) {
- ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i);
- }
- flush_journal_list(s, flush_jl, 1);
- return 0;
+ struct reiserfs_journal_list *jl)
+{
+ unsigned long len = 0;
+ unsigned long cur_len;
+ int ret;
+ int i;
+ int limit = 256;
+ struct reiserfs_journal_list *tjl;
+ struct reiserfs_journal_list *flush_jl;
+ unsigned long trans_id;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+
+ flush_jl = tjl = jl;
+
+ /* in data logging mode, try harder to flush a lot of blocks */
+ if (reiserfs_data_log(s))
+ limit = 1024;
+ /* flush for 256 transactions or limit blocks, whichever comes first */
+ for (i = 0; i < 256 && len < limit; i++) {
+ if (atomic_read(&tjl->j_commit_left) ||
+ tjl->j_trans_id < jl->j_trans_id) {
+ break;
+ }
+ cur_len = atomic_read(&tjl->j_nonzerolen);
+ if (cur_len > 0) {
+ tjl->j_state &= ~LIST_TOUCHED;
+ }
+ len += cur_len;
+ flush_jl = tjl;
+ if (tjl->j_list.next == &journal->j_journal_list)
+ break;
+ tjl = JOURNAL_LIST_ENTRY(tjl->j_list.next);
+ }
+ /* try to find a group of blocks we can flush across all the
+ ** transactions, but only bother if we've actually spanned
+ ** across multiple lists
+ */
+ if (flush_jl != jl) {
+ ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i);
+ }
+ flush_journal_list(s, flush_jl, 1);
+ return 0;
}
/*
@@ -1655,207 +1769,248 @@ static int flush_used_journal_lists(struct super_block *s,
** only touchs the hnext and hprev pointers.
*/
void remove_journal_hash(struct super_block *sb,
- struct reiserfs_journal_cnode **table,
- struct reiserfs_journal_list *jl,
- unsigned long block, int remove_freed)
-{
- struct reiserfs_journal_cnode *cur ;
- struct reiserfs_journal_cnode **head ;
-
- head= &(journal_hash(table, sb, block)) ;
- if (!head) {
- return ;
- }
- cur = *head ;
- while(cur) {
- if (cur->blocknr == block && cur->sb == sb && (jl == NULL || jl == cur->jlist) &&
- (!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) {
- if (cur->hnext) {
- cur->hnext->hprev = cur->hprev ;
- }
- if (cur->hprev) {
- cur->hprev->hnext = cur->hnext ;
- } else {
- *head = cur->hnext ;
- }
- cur->blocknr = 0 ;
- cur->sb = NULL ;
- cur->state = 0 ;
- if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */
- atomic_dec(&(cur->jlist->j_nonzerolen)) ;
- cur->bh = NULL ;
- cur->jlist = NULL ;
- }
- cur = cur->hnext ;
- }
-}
-
-static void free_journal_ram(struct super_block *p_s_sb) {
- struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
- reiserfs_kfree(journal->j_current_jl,
- sizeof(struct reiserfs_journal_list), p_s_sb);
- journal->j_num_lists--;
-
- vfree(journal->j_cnode_free_orig) ;
- free_list_bitmaps(p_s_sb, journal->j_list_bitmap) ;
- free_bitmap_nodes(p_s_sb) ; /* must be after free_list_bitmaps */
- if (journal->j_header_bh) {
- brelse(journal->j_header_bh) ;
- }
- /* j_header_bh is on the journal dev, make sure not to release the journal
- * dev until we brelse j_header_bh
- */
- release_journal_dev(p_s_sb, journal);
- vfree(journal) ;
+ struct reiserfs_journal_cnode **table,
+ struct reiserfs_journal_list *jl,
+ unsigned long block, int remove_freed)
+{
+ struct reiserfs_journal_cnode *cur;
+ struct reiserfs_journal_cnode **head;
+
+ head = &(journal_hash(table, sb, block));
+ if (!head) {
+ return;
+ }
+ cur = *head;
+ while (cur) {
+ if (cur->blocknr == block && cur->sb == sb
+ && (jl == NULL || jl == cur->jlist)
+ && (!test_bit(BLOCK_FREED, &cur->state) || remove_freed)) {
+ if (cur->hnext) {
+ cur->hnext->hprev = cur->hprev;
+ }
+ if (cur->hprev) {
+ cur->hprev->hnext = cur->hnext;
+ } else {
+ *head = cur->hnext;
+ }
+ cur->blocknr = 0;
+ cur->sb = NULL;
+ cur->state = 0;
+ if (cur->bh && cur->jlist) /* anybody who clears the cur->bh will also dec the nonzerolen */
+ atomic_dec(&(cur->jlist->j_nonzerolen));
+ cur->bh = NULL;
+ cur->jlist = NULL;
+ }
+ cur = cur->hnext;
+ }
+}
+
+static void free_journal_ram(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ reiserfs_kfree(journal->j_current_jl,
+ sizeof(struct reiserfs_journal_list), p_s_sb);
+ journal->j_num_lists--;
+
+ vfree(journal->j_cnode_free_orig);
+ free_list_bitmaps(p_s_sb, journal->j_list_bitmap);
+ free_bitmap_nodes(p_s_sb); /* must be after free_list_bitmaps */
+ if (journal->j_header_bh) {
+ brelse(journal->j_header_bh);
+ }
+ /* j_header_bh is on the journal dev, make sure not to release the journal
+ * dev until we brelse j_header_bh
+ */
+ release_journal_dev(p_s_sb, journal);
+ vfree(journal);
}
/*
** call on unmount. Only set error to 1 if you haven't made your way out
** of read_super() yet. Any other caller must keep error at 0.
*/
-static int do_journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, int error) {
- struct reiserfs_transaction_handle myth ;
- int flushed = 0;
- struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
-
- /* we only want to flush out transactions if we were called with error == 0
- */
- if (!error && !(p_s_sb->s_flags & MS_RDONLY)) {
- /* end the current trans */
- BUG_ON (!th->t_trans_id);
- do_journal_end(th, p_s_sb,10, FLUSH_ALL) ;
-
- /* make sure something gets logged to force our way into the flush code */
- if (!journal_join(&myth, p_s_sb, 1)) {
- reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
- journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
- do_journal_end(&myth, p_s_sb,1, FLUSH_ALL) ;
- flushed = 1;
- }
- }
-
- /* this also catches errors during the do_journal_end above */
- if (!error && reiserfs_is_journal_aborted(journal)) {
- memset(&myth, 0, sizeof(myth));
- if (!journal_join_abort(&myth, p_s_sb, 1)) {
- reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
- journal_mark_dirty(&myth, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
- do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL) ;
- }
- }
-
- reiserfs_mounted_fs_count-- ;
- /* wait for all commits to finish */
- cancel_delayed_work(&SB_JOURNAL(p_s_sb)->j_work);
- flush_workqueue(commit_wq);
- if (!reiserfs_mounted_fs_count) {
- destroy_workqueue(commit_wq);
- commit_wq = NULL;
- }
-
- free_journal_ram(p_s_sb) ;
-
- return 0 ;
+static int do_journal_release(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, int error)
+{
+ struct reiserfs_transaction_handle myth;
+ int flushed = 0;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+
+ /* we only want to flush out transactions if we were called with error == 0
+ */
+ if (!error && !(p_s_sb->s_flags & MS_RDONLY)) {
+ /* end the current trans */
+ BUG_ON(!th->t_trans_id);
+ do_journal_end(th, p_s_sb, 10, FLUSH_ALL);
+
+ /* make sure something gets logged to force our way into the flush code */
+ if (!journal_join(&myth, p_s_sb, 1)) {
+ reiserfs_prepare_for_journal(p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+ journal_mark_dirty(&myth, p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb));
+ do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL);
+ flushed = 1;
+ }
+ }
+
+ /* this also catches errors during the do_journal_end above */
+ if (!error && reiserfs_is_journal_aborted(journal)) {
+ memset(&myth, 0, sizeof(myth));
+ if (!journal_join_abort(&myth, p_s_sb, 1)) {
+ reiserfs_prepare_for_journal(p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+ journal_mark_dirty(&myth, p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb));
+ do_journal_end(&myth, p_s_sb, 1, FLUSH_ALL);
+ }
+ }
+
+ reiserfs_mounted_fs_count--;
+ /* wait for all commits to finish */
+ cancel_delayed_work(&SB_JOURNAL(p_s_sb)->j_work);
+ flush_workqueue(commit_wq);
+ if (!reiserfs_mounted_fs_count) {
+ destroy_workqueue(commit_wq);
+ commit_wq = NULL;
+ }
+
+ free_journal_ram(p_s_sb);
+
+ return 0;
}
/*
** call on unmount. flush all journal trans, release all alloc'd ram
*/
-int journal_release(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb) {
- return do_journal_release(th, p_s_sb, 0) ;
+int journal_release(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb)
+{
+ return do_journal_release(th, p_s_sb, 0);
}
+
/*
** only call from an error condition inside reiserfs_read_super!
*/
-int journal_release_error(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb) {
- return do_journal_release(th, p_s_sb, 1) ;
+int journal_release_error(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb)
+{
+ return do_journal_release(th, p_s_sb, 1);
}
/* compares description block with commit block. returns 1 if they differ, 0 if they are the same */
-static int journal_compare_desc_commit(struct super_block *p_s_sb, struct reiserfs_journal_desc *desc,
- struct reiserfs_journal_commit *commit) {
- if (get_commit_trans_id (commit) != get_desc_trans_id (desc) ||
- get_commit_trans_len (commit) != get_desc_trans_len (desc) ||
- get_commit_trans_len (commit) > SB_JOURNAL(p_s_sb)->j_trans_max ||
- get_commit_trans_len (commit) <= 0
- ) {
- return 1 ;
- }
- return 0 ;
+static int journal_compare_desc_commit(struct super_block *p_s_sb,
+ struct reiserfs_journal_desc *desc,
+ struct reiserfs_journal_commit *commit)
+{
+ if (get_commit_trans_id(commit) != get_desc_trans_id(desc) ||
+ get_commit_trans_len(commit) != get_desc_trans_len(desc) ||
+ get_commit_trans_len(commit) > SB_JOURNAL(p_s_sb)->j_trans_max ||
+ get_commit_trans_len(commit) <= 0) {
+ return 1;
+ }
+ return 0;
}
+
/* returns 0 if it did not find a description block
** returns -1 if it found a corrupt commit block
** returns 1 if both desc and commit were valid
*/
-static int journal_transaction_is_valid(struct super_block *p_s_sb, struct buffer_head *d_bh, unsigned long *oldest_invalid_trans_id, unsigned long *newest_mount_id) {
- struct reiserfs_journal_desc *desc ;
- struct reiserfs_journal_commit *commit ;
- struct buffer_head *c_bh ;
- unsigned long offset ;
-
- if (!d_bh)
- return 0 ;
-
- desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
- if (get_desc_trans_len(desc) > 0 && !memcmp(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8)) {
- if (oldest_invalid_trans_id && *oldest_invalid_trans_id && get_desc_trans_id(desc) > *oldest_invalid_trans_id) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-986: transaction "
- "is valid returning because trans_id %d is greater than "
- "oldest_invalid %lu", get_desc_trans_id(desc),
- *oldest_invalid_trans_id);
- return 0 ;
- }
- if (newest_mount_id && *newest_mount_id > get_desc_mount_id (desc)) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1087: transaction "
- "is valid returning because mount_id %d is less than "
- "newest_mount_id %lu", get_desc_mount_id (desc),
- *newest_mount_id) ;
- return -1 ;
- }
- if ( get_desc_trans_len(desc) > SB_JOURNAL(p_s_sb)->j_trans_max ) {
- reiserfs_warning(p_s_sb, "journal-2018: Bad transaction length %d encountered, ignoring transaction", get_desc_trans_len(desc));
- return -1 ;
- }
- offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
-
- /* ok, we have a journal description block, lets see if the transaction was valid */
- c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- if (!c_bh)
- return 0 ;
- commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
- if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
- "journal_transaction_is_valid, commit offset %ld had bad "
- "time %d or length %d",
- c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- get_commit_trans_id (commit),
- get_commit_trans_len(commit));
- brelse(c_bh) ;
- if (oldest_invalid_trans_id) {
- *oldest_invalid_trans_id = get_desc_trans_id(desc) ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: "
- "transaction_is_valid setting oldest invalid trans_id "
- "to %d", get_desc_trans_id(desc)) ;
- }
- return -1;
- }
- brelse(c_bh) ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid "
- "transaction start offset %llu, len %d id %d",
- d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- get_desc_trans_len(desc), get_desc_trans_id(desc)) ;
- return 1 ;
- } else {
- return 0 ;
- }
-}
-
-static void brelse_array(struct buffer_head **heads, int num) {
- int i ;
- for (i = 0 ; i < num ; i++) {
- brelse(heads[i]) ;
- }
+static int journal_transaction_is_valid(struct super_block *p_s_sb,
+ struct buffer_head *d_bh,
+ unsigned long *oldest_invalid_trans_id,
+ unsigned long *newest_mount_id)
+{
+ struct reiserfs_journal_desc *desc;
+ struct reiserfs_journal_commit *commit;
+ struct buffer_head *c_bh;
+ unsigned long offset;
+
+ if (!d_bh)
+ return 0;
+
+ desc = (struct reiserfs_journal_desc *)d_bh->b_data;
+ if (get_desc_trans_len(desc) > 0
+ && !memcmp(get_journal_desc_magic(d_bh), JOURNAL_DESC_MAGIC, 8)) {
+ if (oldest_invalid_trans_id && *oldest_invalid_trans_id
+ && get_desc_trans_id(desc) > *oldest_invalid_trans_id) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-986: transaction "
+ "is valid returning because trans_id %d is greater than "
+ "oldest_invalid %lu",
+ get_desc_trans_id(desc),
+ *oldest_invalid_trans_id);
+ return 0;
+ }
+ if (newest_mount_id
+ && *newest_mount_id > get_desc_mount_id(desc)) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1087: transaction "
+ "is valid returning because mount_id %d is less than "
+ "newest_mount_id %lu",
+ get_desc_mount_id(desc),
+ *newest_mount_id);
+ return -1;
+ }
+ if (get_desc_trans_len(desc) > SB_JOURNAL(p_s_sb)->j_trans_max) {
+ reiserfs_warning(p_s_sb,
+ "journal-2018: Bad transaction length %d encountered, ignoring transaction",
+ get_desc_trans_len(desc));
+ return -1;
+ }
+ offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+
+ /* ok, we have a journal description block, lets see if the transaction was valid */
+ c_bh =
+ journal_bread(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ ((offset + get_desc_trans_len(desc) +
+ 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+ if (!c_bh)
+ return 0;
+ commit = (struct reiserfs_journal_commit *)c_bh->b_data;
+ if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal_transaction_is_valid, commit offset %ld had bad "
+ "time %d or length %d",
+ c_bh->b_blocknr -
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ get_commit_trans_id(commit),
+ get_commit_trans_len(commit));
+ brelse(c_bh);
+ if (oldest_invalid_trans_id) {
+ *oldest_invalid_trans_id =
+ get_desc_trans_id(desc);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1004: "
+ "transaction_is_valid setting oldest invalid trans_id "
+ "to %d",
+ get_desc_trans_id(desc));
+ }
+ return -1;
+ }
+ brelse(c_bh);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1006: found valid "
+ "transaction start offset %llu, len %d id %d",
+ d_bh->b_blocknr -
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ get_desc_trans_len(desc),
+ get_desc_trans_id(desc));
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static void brelse_array(struct buffer_head **heads, int num)
+{
+ int i;
+ for (i = 0; i < num; i++) {
+ brelse(heads[i]);
+ }
}
/*
@@ -1863,149 +2018,202 @@ static void brelse_array(struct buffer_head **heads, int num) {
** this either reads in a replays a transaction, or returns because the transaction
** is invalid, or too old.
*/
-static int journal_read_transaction(struct super_block *p_s_sb, unsigned long cur_dblock, unsigned long oldest_start,
- unsigned long oldest_trans_id, unsigned long newest_mount_id) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_desc *desc ;
- struct reiserfs_journal_commit *commit ;
- unsigned long trans_id = 0 ;
- struct buffer_head *c_bh ;
- struct buffer_head *d_bh ;
- struct buffer_head **log_blocks = NULL ;
- struct buffer_head **real_blocks = NULL ;
- unsigned long trans_offset ;
- int i;
- int trans_half;
-
- d_bh = journal_bread(p_s_sb, cur_dblock) ;
- if (!d_bh)
- return 1 ;
- desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
- trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: "
- "journal_read_transaction, offset %llu, len %d mount_id %d",
- d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- get_desc_trans_len(desc), get_desc_mount_id(desc)) ;
- if (get_desc_trans_id(desc) < oldest_trans_id) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: "
- "journal_read_trans skipping because %lu is too old",
- cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ;
- brelse(d_bh) ;
- return 1 ;
- }
- if (get_desc_mount_id(desc) != newest_mount_id) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: "
- "journal_read_trans skipping because %d is != "
- "newest_mount_id %lu", get_desc_mount_id(desc),
- newest_mount_id) ;
- brelse(d_bh) ;
- return 1 ;
- }
- c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((trans_offset + get_desc_trans_len(desc) + 1) %
- SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- if (!c_bh) {
- brelse(d_bh) ;
- return 1 ;
- }
- commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
- if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal_read_transaction, "
- "commit offset %llu had bad time %d or length %d",
- c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- get_commit_trans_id(commit), get_commit_trans_len(commit));
- brelse(c_bh) ;
- brelse(d_bh) ;
- return 1;
- }
- trans_id = get_desc_trans_id(desc) ;
- /* now we know we've got a good transaction, and it was inside the valid time ranges */
- log_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ;
- real_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ;
- if (!log_blocks || !real_blocks) {
- brelse(c_bh) ;
- brelse(d_bh) ;
- reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_warning(p_s_sb, "journal-1169: kmalloc failed, unable to mount FS") ;
- return -1 ;
- }
- /* get all the buffer heads */
- trans_half = journal_trans_half (p_s_sb->s_blocksize) ;
- for(i = 0 ; i < get_desc_trans_len(desc) ; i++) {
- log_blocks[i] = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
- if (i < trans_half) {
- real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ;
- } else {
- real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - trans_half])) ;
- }
- if ( real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb) ) {
- reiserfs_warning(p_s_sb, "journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem");
- goto abort_replay;
- }
- /* make sure we don't try to replay onto log or reserved area */
- if (is_block_in_log_or_reserved_area(p_s_sb, real_blocks[i]->b_blocknr)) {
- reiserfs_warning(p_s_sb, "journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block") ;
-abort_replay:
- brelse_array(log_blocks, i) ;
- brelse_array(real_blocks, i) ;
- brelse(c_bh) ;
- brelse(d_bh) ;
- reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- return -1 ;
- }
- }
- /* read in the log blocks, memcpy to the corresponding real block */
- ll_rw_block(READ, get_desc_trans_len(desc), log_blocks) ;
- for (i = 0 ; i < get_desc_trans_len(desc) ; i++) {
- wait_on_buffer(log_blocks[i]) ;
- if (!buffer_uptodate(log_blocks[i])) {
- reiserfs_warning(p_s_sb, "journal-1212: REPLAY FAILURE fsck required! buffer write failed") ;
- brelse_array(log_blocks + i, get_desc_trans_len(desc) - i) ;
- brelse_array(real_blocks, get_desc_trans_len(desc)) ;
- brelse(c_bh) ;
- brelse(d_bh) ;
- reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- return -1 ;
- }
- memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ;
- set_buffer_uptodate(real_blocks[i]) ;
- brelse(log_blocks[i]) ;
- }
- /* flush out the real blocks */
- for (i = 0 ; i < get_desc_trans_len(desc) ; i++) {
- set_buffer_dirty(real_blocks[i]) ;
- ll_rw_block(WRITE, 1, real_blocks + i) ;
- }
- for (i = 0 ; i < get_desc_trans_len(desc) ; i++) {
- wait_on_buffer(real_blocks[i]) ;
- if (!buffer_uptodate(real_blocks[i])) {
- reiserfs_warning(p_s_sb, "journal-1226: REPLAY FAILURE, fsck required! buffer write failed") ;
- brelse_array(real_blocks + i, get_desc_trans_len(desc) - i) ;
- brelse(c_bh) ;
- brelse(d_bh) ;
- reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ;
- return -1 ;
- }
- brelse(real_blocks[i]) ;
- }
- cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + get_desc_trans_len(desc) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal "
- "start to offset %ld",
- cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ;
-
- /* init starting values for the first transaction, in case this is the last transaction to be replayed. */
- journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
- journal->j_last_flush_trans_id = trans_id ;
- journal->j_trans_id = trans_id + 1;
- brelse(c_bh) ;
- brelse(d_bh) ;
- reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
- reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ;
- return 0 ;
+static int journal_read_transaction(struct super_block *p_s_sb,
+ unsigned long cur_dblock,
+ unsigned long oldest_start,
+ unsigned long oldest_trans_id,
+ unsigned long newest_mount_id)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_desc *desc;
+ struct reiserfs_journal_commit *commit;
+ unsigned long trans_id = 0;
+ struct buffer_head *c_bh;
+ struct buffer_head *d_bh;
+ struct buffer_head **log_blocks = NULL;
+ struct buffer_head **real_blocks = NULL;
+ unsigned long trans_offset;
+ int i;
+ int trans_half;
+
+ d_bh = journal_bread(p_s_sb, cur_dblock);
+ if (!d_bh)
+ return 1;
+ desc = (struct reiserfs_journal_desc *)d_bh->b_data;
+ trans_offset = d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: "
+ "journal_read_transaction, offset %llu, len %d mount_id %d",
+ d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ get_desc_trans_len(desc), get_desc_mount_id(desc));
+ if (get_desc_trans_id(desc) < oldest_trans_id) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: "
+ "journal_read_trans skipping because %lu is too old",
+ cur_dblock -
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb));
+ brelse(d_bh);
+ return 1;
+ }
+ if (get_desc_mount_id(desc) != newest_mount_id) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: "
+ "journal_read_trans skipping because %d is != "
+ "newest_mount_id %lu", get_desc_mount_id(desc),
+ newest_mount_id);
+ brelse(d_bh);
+ return 1;
+ }
+ c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ ((trans_offset + get_desc_trans_len(desc) + 1) %
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+ if (!c_bh) {
+ brelse(d_bh);
+ return 1;
+ }
+ commit = (struct reiserfs_journal_commit *)c_bh->b_data;
+ if (journal_compare_desc_commit(p_s_sb, desc, commit)) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal_read_transaction, "
+ "commit offset %llu had bad time %d or length %d",
+ c_bh->b_blocknr -
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ get_commit_trans_id(commit),
+ get_commit_trans_len(commit));
+ brelse(c_bh);
+ brelse(d_bh);
+ return 1;
+ }
+ trans_id = get_desc_trans_id(desc);
+ /* now we know we've got a good transaction, and it was inside the valid time ranges */
+ log_blocks =
+ reiserfs_kmalloc(get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), GFP_NOFS, p_s_sb);
+ real_blocks =
+ reiserfs_kmalloc(get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), GFP_NOFS, p_s_sb);
+ if (!log_blocks || !real_blocks) {
+ brelse(c_bh);
+ brelse(d_bh);
+ reiserfs_kfree(log_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ reiserfs_kfree(real_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ reiserfs_warning(p_s_sb,
+ "journal-1169: kmalloc failed, unable to mount FS");
+ return -1;
+ }
+ /* get all the buffer heads */
+ trans_half = journal_trans_half(p_s_sb->s_blocksize);
+ for (i = 0; i < get_desc_trans_len(desc); i++) {
+ log_blocks[i] =
+ journal_getblk(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ (trans_offset + 1 +
+ i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+ if (i < trans_half) {
+ real_blocks[i] =
+ sb_getblk(p_s_sb,
+ le32_to_cpu(desc->j_realblock[i]));
+ } else {
+ real_blocks[i] =
+ sb_getblk(p_s_sb,
+ le32_to_cpu(commit->
+ j_realblock[i - trans_half]));
+ }
+ if (real_blocks[i]->b_blocknr > SB_BLOCK_COUNT(p_s_sb)) {
+ reiserfs_warning(p_s_sb,
+ "journal-1207: REPLAY FAILURE fsck required! Block to replay is outside of filesystem");
+ goto abort_replay;
+ }
+ /* make sure we don't try to replay onto log or reserved area */
+ if (is_block_in_log_or_reserved_area
+ (p_s_sb, real_blocks[i]->b_blocknr)) {
+ reiserfs_warning(p_s_sb,
+ "journal-1204: REPLAY FAILURE fsck required! Trying to replay onto a log block");
+ abort_replay:
+ brelse_array(log_blocks, i);
+ brelse_array(real_blocks, i);
+ brelse(c_bh);
+ brelse(d_bh);
+ reiserfs_kfree(log_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ reiserfs_kfree(real_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ return -1;
+ }
+ }
+ /* read in the log blocks, memcpy to the corresponding real block */
+ ll_rw_block(READ, get_desc_trans_len(desc), log_blocks);
+ for (i = 0; i < get_desc_trans_len(desc); i++) {
+ wait_on_buffer(log_blocks[i]);
+ if (!buffer_uptodate(log_blocks[i])) {
+ reiserfs_warning(p_s_sb,
+ "journal-1212: REPLAY FAILURE fsck required! buffer write failed");
+ brelse_array(log_blocks + i,
+ get_desc_trans_len(desc) - i);
+ brelse_array(real_blocks, get_desc_trans_len(desc));
+ brelse(c_bh);
+ brelse(d_bh);
+ reiserfs_kfree(log_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ reiserfs_kfree(real_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ return -1;
+ }
+ memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data,
+ real_blocks[i]->b_size);
+ set_buffer_uptodate(real_blocks[i]);
+ brelse(log_blocks[i]);
+ }
+ /* flush out the real blocks */
+ for (i = 0; i < get_desc_trans_len(desc); i++) {
+ set_buffer_dirty(real_blocks[i]);
+ ll_rw_block(WRITE, 1, real_blocks + i);
+ }
+ for (i = 0; i < get_desc_trans_len(desc); i++) {
+ wait_on_buffer(real_blocks[i]);
+ if (!buffer_uptodate(real_blocks[i])) {
+ reiserfs_warning(p_s_sb,
+ "journal-1226: REPLAY FAILURE, fsck required! buffer write failed");
+ brelse_array(real_blocks + i,
+ get_desc_trans_len(desc) - i);
+ brelse(c_bh);
+ brelse(d_bh);
+ reiserfs_kfree(log_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ reiserfs_kfree(real_blocks,
+ get_desc_trans_len(desc) *
+ sizeof(struct buffer_head *), p_s_sb);
+ return -1;
+ }
+ brelse(real_blocks[i]);
+ }
+ cur_dblock =
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ ((trans_offset + get_desc_trans_len(desc) +
+ 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1095: setting journal " "start to offset %ld",
+ cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb));
+
+ /* init starting values for the first transaction, in case this is the last transaction to be replayed. */
+ journal->j_start = cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+ journal->j_last_flush_trans_id = trans_id;
+ journal->j_trans_id = trans_id + 1;
+ brelse(c_bh);
+ brelse(d_bh);
+ reiserfs_kfree(log_blocks,
+ le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *),
+ p_s_sb);
+ reiserfs_kfree(real_blocks,
+ le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *),
+ p_s_sb);
+ return 0;
}
/* This function reads blocks starting from block and to max_block of bufsize
@@ -2014,39 +2222,39 @@ abort_replay:
Right now it is only used from journal code. But later we might use it
from other places.
Note: Do not use journal_getblk/sb_getblk functions here! */
-static struct buffer_head * reiserfs_breada (struct block_device *dev, int block, int bufsize,
- unsigned int max_block)
+static struct buffer_head *reiserfs_breada(struct block_device *dev, int block,
+ int bufsize, unsigned int max_block)
{
- struct buffer_head * bhlist[BUFNR];
+ struct buffer_head *bhlist[BUFNR];
unsigned int blocks = BUFNR;
- struct buffer_head * bh;
+ struct buffer_head *bh;
int i, j;
-
- bh = __getblk (dev, block, bufsize );
- if (buffer_uptodate (bh))
- return (bh);
-
+
+ bh = __getblk(dev, block, bufsize);
+ if (buffer_uptodate(bh))
+ return (bh);
+
if (block + BUFNR > max_block) {
blocks = max_block - block;
}
bhlist[0] = bh;
j = 1;
for (i = 1; i < blocks; i++) {
- bh = __getblk (dev, block + i, bufsize);
- if (buffer_uptodate (bh)) {
- brelse (bh);
+ bh = __getblk(dev, block + i, bufsize);
+ if (buffer_uptodate(bh)) {
+ brelse(bh);
break;
- }
- else bhlist[j++] = bh;
+ } else
+ bhlist[j++] = bh;
}
- ll_rw_block (READ, j, bhlist);
- for(i = 1; i < j; i++)
- brelse (bhlist[i]);
+ ll_rw_block(READ, j, bhlist);
+ for (i = 1; i < j; i++)
+ brelse(bhlist[i]);
bh = bhlist[0];
- wait_on_buffer (bh);
- if (buffer_uptodate (bh))
+ wait_on_buffer(bh);
+ if (buffer_uptodate(bh))
return bh;
- brelse (bh);
+ brelse(bh);
return NULL;
}
@@ -2059,218 +2267,250 @@ static struct buffer_head * reiserfs_breada (struct block_device *dev, int block
**
** On exit, it sets things up so the first transaction will work correctly.
*/
-static int journal_read(struct super_block *p_s_sb) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_desc *desc ;
- unsigned long oldest_trans_id = 0;
- unsigned long oldest_invalid_trans_id = 0 ;
- time_t start ;
- unsigned long oldest_start = 0;
- unsigned long cur_dblock = 0 ;
- unsigned long newest_mount_id = 9 ;
- struct buffer_head *d_bh ;
- struct reiserfs_journal_header *jh ;
- int valid_journal_header = 0 ;
- int replay_count = 0 ;
- int continue_replay = 1 ;
- int ret ;
- char b[BDEVNAME_SIZE];
-
- cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) ;
- reiserfs_info (p_s_sb, "checking transaction log (%s)\n",
- bdevname(journal->j_dev_bd, b));
- start = get_seconds();
-
- /* step 1, read in the journal header block. Check the transaction it says
- ** is the first unflushed, and if that transaction is not valid,
- ** replay is done
- */
- journal->j_header_bh = journal_bread(p_s_sb,
- SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- SB_ONDISK_JOURNAL_SIZE(p_s_sb));
- if (!journal->j_header_bh) {
- return 1 ;
- }
- jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data) ;
- if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 &&
- le32_to_cpu(jh->j_first_unflushed_offset) < SB_ONDISK_JOURNAL_SIZE(p_s_sb) &&
- le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
- oldest_start = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- le32_to_cpu(jh->j_first_unflushed_offset) ;
- oldest_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1;
- newest_mount_id = le32_to_cpu(jh->j_mount_id);
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1153: found in "
- "header: first_unflushed_offset %d, last_flushed_trans_id "
- "%lu", le32_to_cpu(jh->j_first_unflushed_offset),
- le32_to_cpu(jh->j_last_flush_trans_id)) ;
- valid_journal_header = 1 ;
-
- /* now, we try to read the first unflushed offset. If it is not valid,
- ** there is nothing more we can do, and it makes no sense to read
- ** through the whole log.
- */
- d_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + le32_to_cpu(jh->j_first_unflushed_offset)) ;
- ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL) ;
- if (!ret) {
- continue_replay = 0 ;
- }
- brelse(d_bh) ;
- goto start_log_replay;
- }
-
- if (continue_replay && bdev_read_only(p_s_sb->s_bdev)) {
- reiserfs_warning (p_s_sb,
- "clm-2076: device is readonly, unable to replay log") ;
- return -1 ;
- }
-
- /* ok, there are transactions that need to be replayed. start with the first log block, find
- ** all the valid transactions, and pick out the oldest.
- */
- while(continue_replay && cur_dblock < (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb))) {
- /* Note that it is required for blocksize of primary fs device and journal
- device to be the same */
- d_bh = reiserfs_breada(journal->j_dev_bd, cur_dblock, p_s_sb->s_blocksize,
- SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ;
- ret = journal_transaction_is_valid(p_s_sb, d_bh, &oldest_invalid_trans_id, &newest_mount_id) ;
- if (ret == 1) {
- desc = (struct reiserfs_journal_desc *)d_bh->b_data ;
- if (oldest_start == 0) { /* init all oldest_ values */
- oldest_trans_id = get_desc_trans_id(desc) ;
- oldest_start = d_bh->b_blocknr ;
- newest_mount_id = get_desc_mount_id(desc) ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1179: Setting "
- "oldest_start to offset %llu, trans_id %lu",
- oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- oldest_trans_id) ;
- } else if (oldest_trans_id > get_desc_trans_id(desc)) {
- /* one we just read was older */
- oldest_trans_id = get_desc_trans_id(desc) ;
- oldest_start = d_bh->b_blocknr ;
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting "
- "oldest_start to offset %lu, trans_id %lu",
- oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- oldest_trans_id) ;
- }
- if (newest_mount_id < get_desc_mount_id(desc)) {
- newest_mount_id = get_desc_mount_id(desc) ;
+static int journal_read(struct super_block *p_s_sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_desc *desc;
+ unsigned long oldest_trans_id = 0;
+ unsigned long oldest_invalid_trans_id = 0;
+ time_t start;
+ unsigned long oldest_start = 0;
+ unsigned long cur_dblock = 0;
+ unsigned long newest_mount_id = 9;
+ struct buffer_head *d_bh;
+ struct reiserfs_journal_header *jh;
+ int valid_journal_header = 0;
+ int replay_count = 0;
+ int continue_replay = 1;
+ int ret;
+ char b[BDEVNAME_SIZE];
+
+ cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb);
+ reiserfs_info(p_s_sb, "checking transaction log (%s)\n",
+ bdevname(journal->j_dev_bd, b));
+ start = get_seconds();
+
+ /* step 1, read in the journal header block. Check the transaction it says
+ ** is the first unflushed, and if that transaction is not valid,
+ ** replay is done
+ */
+ journal->j_header_bh = journal_bread(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)
+ + SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+ if (!journal->j_header_bh) {
+ return 1;
+ }
+ jh = (struct reiserfs_journal_header *)(journal->j_header_bh->b_data);
+ if (le32_to_cpu(jh->j_first_unflushed_offset) >= 0 &&
+ le32_to_cpu(jh->j_first_unflushed_offset) <
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)
+ && le32_to_cpu(jh->j_last_flush_trans_id) > 0) {
+ oldest_start =
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ le32_to_cpu(jh->j_first_unflushed_offset);
+ oldest_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1;
+ newest_mount_id = le32_to_cpu(jh->j_mount_id);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1153: found in "
+ "header: first_unflushed_offset %d, last_flushed_trans_id "
+ "%lu", le32_to_cpu(jh->j_first_unflushed_offset),
+ le32_to_cpu(jh->j_last_flush_trans_id));
+ valid_journal_header = 1;
+
+ /* now, we try to read the first unflushed offset. If it is not valid,
+ ** there is nothing more we can do, and it makes no sense to read
+ ** through the whole log.
+ */
+ d_bh =
+ journal_bread(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ le32_to_cpu(jh->j_first_unflushed_offset));
+ ret = journal_transaction_is_valid(p_s_sb, d_bh, NULL, NULL);
+ if (!ret) {
+ continue_replay = 0;
+ }
+ brelse(d_bh);
+ goto start_log_replay;
+ }
+
+ if (continue_replay && bdev_read_only(p_s_sb->s_bdev)) {
+ reiserfs_warning(p_s_sb,
+ "clm-2076: device is readonly, unable to replay log");
+ return -1;
+ }
+
+ /* ok, there are transactions that need to be replayed. start with the first log block, find
+ ** all the valid transactions, and pick out the oldest.
+ */
+ while (continue_replay
+ && cur_dblock <
+ (SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb))) {
+ /* Note that it is required for blocksize of primary fs device and journal
+ device to be the same */
+ d_bh =
+ reiserfs_breada(journal->j_dev_bd, cur_dblock,
+ p_s_sb->s_blocksize,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+ ret =
+ journal_transaction_is_valid(p_s_sb, d_bh,
+ &oldest_invalid_trans_id,
+ &newest_mount_id);
+ if (ret == 1) {
+ desc = (struct reiserfs_journal_desc *)d_bh->b_data;
+ if (oldest_start == 0) { /* init all oldest_ values */
+ oldest_trans_id = get_desc_trans_id(desc);
+ oldest_start = d_bh->b_blocknr;
+ newest_mount_id = get_desc_mount_id(desc);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1179: Setting "
+ "oldest_start to offset %llu, trans_id %lu",
+ oldest_start -
+ SB_ONDISK_JOURNAL_1st_BLOCK
+ (p_s_sb), oldest_trans_id);
+ } else if (oldest_trans_id > get_desc_trans_id(desc)) {
+ /* one we just read was older */
+ oldest_trans_id = get_desc_trans_id(desc);
+ oldest_start = d_bh->b_blocknr;
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1180: Resetting "
+ "oldest_start to offset %lu, trans_id %lu",
+ oldest_start -
+ SB_ONDISK_JOURNAL_1st_BLOCK
+ (p_s_sb), oldest_trans_id);
+ }
+ if (newest_mount_id < get_desc_mount_id(desc)) {
+ newest_mount_id = get_desc_mount_id(desc);
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1299: Setting "
+ "newest_mount_id to %d",
+ get_desc_mount_id(desc));
+ }
+ cur_dblock += get_desc_trans_len(desc) + 2;
+ } else {
+ cur_dblock++;
+ }
+ brelse(d_bh);
+ }
+
+ start_log_replay:
+ cur_dblock = oldest_start;
+ if (oldest_trans_id) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1206: Starting replay "
+ "from offset %llu, trans_id %lu",
+ cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ oldest_trans_id);
+
+ }
+ replay_count = 0;
+ while (continue_replay && oldest_trans_id > 0) {
+ ret =
+ journal_read_transaction(p_s_sb, cur_dblock, oldest_start,
+ oldest_trans_id, newest_mount_id);
+ if (ret < 0) {
+ return ret;
+ } else if (ret != 0) {
+ break;
+ }
+ cur_dblock =
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start;
+ replay_count++;
+ if (cur_dblock == oldest_start)
+ break;
+ }
+
+ if (oldest_trans_id == 0) {
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "journal-1225: No valid " "transactions found");
+ }
+ /* j_start does not get set correctly if we don't replay any transactions.
+ ** if we had a valid journal_header, set j_start to the first unflushed transaction value,
+ ** copy the trans_id from the header
+ */
+ if (valid_journal_header && replay_count == 0) {
+ journal->j_start = le32_to_cpu(jh->j_first_unflushed_offset);
+ journal->j_trans_id =
+ le32_to_cpu(jh->j_last_flush_trans_id) + 1;
+ journal->j_last_flush_trans_id =
+ le32_to_cpu(jh->j_last_flush_trans_id);
+ journal->j_mount_id = le32_to_cpu(jh->j_mount_id) + 1;
+ } else {
+ journal->j_mount_id = newest_mount_id + 1;
+ }
reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting "
- "newest_mount_id to %d", get_desc_mount_id(desc));
- }
- cur_dblock += get_desc_trans_len(desc) + 2 ;
- } else {
- cur_dblock++ ;
- }
- brelse(d_bh) ;
- }
-
-start_log_replay:
- cur_dblock = oldest_start ;
- if (oldest_trans_id) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1206: Starting replay "
- "from offset %llu, trans_id %lu",
- cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- oldest_trans_id) ;
-
- }
- replay_count = 0 ;
- while(continue_replay && oldest_trans_id > 0) {
- ret = journal_read_transaction(p_s_sb, cur_dblock, oldest_start, oldest_trans_id, newest_mount_id) ;
- if (ret < 0) {
- return ret ;
- } else if (ret != 0) {
- break ;
- }
- cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start ;
- replay_count++ ;
- if (cur_dblock == oldest_start)
- break;
- }
-
- if (oldest_trans_id == 0) {
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1225: No valid "
- "transactions found") ;
- }
- /* j_start does not get set correctly if we don't replay any transactions.
- ** if we had a valid journal_header, set j_start to the first unflushed transaction value,
- ** copy the trans_id from the header
- */
- if (valid_journal_header && replay_count == 0) {
- journal->j_start = le32_to_cpu(jh->j_first_unflushed_offset) ;
- journal->j_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) + 1;
- journal->j_last_flush_trans_id = le32_to_cpu(jh->j_last_flush_trans_id) ;
- journal->j_mount_id = le32_to_cpu(jh->j_mount_id) + 1;
- } else {
- journal->j_mount_id = newest_mount_id + 1 ;
- }
- reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting "
- "newest_mount_id to %lu", journal->j_mount_id) ;
- journal->j_first_unflushed_offset = journal->j_start ;
- if (replay_count > 0) {
- reiserfs_info (p_s_sb, "replayed %d transactions in %lu seconds\n",
- replay_count, get_seconds() - start) ;
- }
- if (!bdev_read_only(p_s_sb->s_bdev) &&
- _update_journal_header_block(p_s_sb, journal->j_start,
- journal->j_last_flush_trans_id))
- {
- /* replay failed, caller must call free_journal_ram and abort
- ** the mount
- */
- return -1 ;
- }
- return 0 ;
+ "newest_mount_id to %lu", journal->j_mount_id);
+ journal->j_first_unflushed_offset = journal->j_start;
+ if (replay_count > 0) {
+ reiserfs_info(p_s_sb,
+ "replayed %d transactions in %lu seconds\n",
+ replay_count, get_seconds() - start);
+ }
+ if (!bdev_read_only(p_s_sb->s_bdev) &&
+ _update_journal_header_block(p_s_sb, journal->j_start,
+ journal->j_last_flush_trans_id)) {
+ /* replay failed, caller must call free_journal_ram and abort
+ ** the mount
+ */
+ return -1;
+ }
+ return 0;
}
static struct reiserfs_journal_list *alloc_journal_list(struct super_block *s)
{
- struct reiserfs_journal_list *jl;
-retry:
- jl = reiserfs_kmalloc(sizeof(struct reiserfs_journal_list), GFP_NOFS, s);
- if (!jl) {
- yield();
- goto retry;
- }
- memset(jl, 0, sizeof(*jl));
- INIT_LIST_HEAD(&jl->j_list);
- INIT_LIST_HEAD(&jl->j_working_list);
- INIT_LIST_HEAD(&jl->j_tail_bh_list);
- INIT_LIST_HEAD(&jl->j_bh_list);
- sema_init(&jl->j_commit_lock, 1);
- SB_JOURNAL(s)->j_num_lists++;
- get_journal_list(jl);
- return jl;
-}
-
-static void journal_list_init(struct super_block *p_s_sb) {
- SB_JOURNAL(p_s_sb)->j_current_jl = alloc_journal_list(p_s_sb);
-}
-
-static int release_journal_dev( struct super_block *super,
- struct reiserfs_journal *journal )
-{
- int result;
-
- result = 0;
-
- if( journal -> j_dev_file != NULL ) {
- result = filp_close( journal -> j_dev_file, NULL );
- journal -> j_dev_file = NULL;
- journal -> j_dev_bd = NULL;
- } else if( journal -> j_dev_bd != NULL ) {
- result = blkdev_put( journal -> j_dev_bd );
- journal -> j_dev_bd = NULL;
- }
-
- if( result != 0 ) {
- reiserfs_warning(super, "sh-457: release_journal_dev: Cannot release journal device: %i", result );
- }
- return result;
-}
-
-static int journal_init_dev( struct super_block *super,
- struct reiserfs_journal *journal,
- const char *jdev_name )
+ struct reiserfs_journal_list *jl;
+ retry:
+ jl = reiserfs_kmalloc(sizeof(struct reiserfs_journal_list), GFP_NOFS,
+ s);
+ if (!jl) {
+ yield();
+ goto retry;
+ }
+ memset(jl, 0, sizeof(*jl));
+ INIT_LIST_HEAD(&jl->j_list);
+ INIT_LIST_HEAD(&jl->j_working_list);
+ INIT_LIST_HEAD(&jl->j_tail_bh_list);
+ INIT_LIST_HEAD(&jl->j_bh_list);
+ sema_init(&jl->j_commit_lock, 1);
+ SB_JOURNAL(s)->j_num_lists++;
+ get_journal_list(jl);
+ return jl;
+}
+
+static void journal_list_init(struct super_block *p_s_sb)
+{
+ SB_JOURNAL(p_s_sb)->j_current_jl = alloc_journal_list(p_s_sb);
+}
+
+static int release_journal_dev(struct super_block *super,
+ struct reiserfs_journal *journal)
+{
+ int result;
+
+ result = 0;
+
+ if (journal->j_dev_file != NULL) {
+ result = filp_close(journal->j_dev_file, NULL);
+ journal->j_dev_file = NULL;
+ journal->j_dev_bd = NULL;
+ } else if (journal->j_dev_bd != NULL) {
+ result = blkdev_put(journal->j_dev_bd);
+ journal->j_dev_bd = NULL;
+ }
+
+ if (result != 0) {
+ reiserfs_warning(super,
+ "sh-457: release_journal_dev: Cannot release journal device: %i",
+ result);
+ }
+ return result;
+}
+
+static int journal_init_dev(struct super_block *super,
+ struct reiserfs_journal *journal,
+ const char *jdev_name)
{
int result;
dev_t jdev;
@@ -2279,50 +2519,51 @@ static int journal_init_dev( struct super_block *super,
result = 0;
- journal -> j_dev_bd = NULL;
- journal -> j_dev_file = NULL;
- jdev = SB_ONDISK_JOURNAL_DEVICE( super ) ?
- new_decode_dev(SB_ONDISK_JOURNAL_DEVICE(super)) : super->s_dev;
+ journal->j_dev_bd = NULL;
+ journal->j_dev_file = NULL;
+ jdev = SB_ONDISK_JOURNAL_DEVICE(super) ?
+ new_decode_dev(SB_ONDISK_JOURNAL_DEVICE(super)) : super->s_dev;
if (bdev_read_only(super->s_bdev))
- blkdev_mode = FMODE_READ;
+ blkdev_mode = FMODE_READ;
/* there is no "jdev" option and journal is on separate device */
- if( ( !jdev_name || !jdev_name[ 0 ] ) ) {
+ if ((!jdev_name || !jdev_name[0])) {
journal->j_dev_bd = open_by_devnum(jdev, blkdev_mode);
if (IS_ERR(journal->j_dev_bd)) {
result = PTR_ERR(journal->j_dev_bd);
journal->j_dev_bd = NULL;
- reiserfs_warning (super, "sh-458: journal_init_dev: "
- "cannot init journal device '%s': %i",
- __bdevname(jdev, b), result );
+ reiserfs_warning(super, "sh-458: journal_init_dev: "
+ "cannot init journal device '%s': %i",
+ __bdevname(jdev, b), result);
return result;
} else if (jdev != super->s_dev)
set_blocksize(journal->j_dev_bd, super->s_blocksize);
return 0;
}
- journal -> j_dev_file = filp_open( jdev_name, 0, 0 );
- if( !IS_ERR( journal -> j_dev_file ) ) {
+ journal->j_dev_file = filp_open(jdev_name, 0, 0);
+ if (!IS_ERR(journal->j_dev_file)) {
struct inode *jdev_inode = journal->j_dev_file->f_mapping->host;
- if( !S_ISBLK( jdev_inode -> i_mode ) ) {
+ if (!S_ISBLK(jdev_inode->i_mode)) {
reiserfs_warning(super, "journal_init_dev: '%s' is "
- "not a block device", jdev_name );
+ "not a block device", jdev_name);
result = -ENOTBLK;
- release_journal_dev( super, journal );
- } else {
+ release_journal_dev(super, journal);
+ } else {
/* ok */
journal->j_dev_bd = I_BDEV(jdev_inode);
set_blocksize(journal->j_dev_bd, super->s_blocksize);
- reiserfs_info(super, "journal_init_dev: journal device: %s\n",
+ reiserfs_info(super,
+ "journal_init_dev: journal device: %s\n",
bdevname(journal->j_dev_bd, b));
}
} else {
- result = PTR_ERR( journal -> j_dev_file );
- journal -> j_dev_file = NULL;
- reiserfs_warning (super,
- "journal_init_dev: Cannot open '%s': %i",
- jdev_name, result );
+ result = PTR_ERR(journal->j_dev_file);
+ journal->j_dev_file = NULL;
+ reiserfs_warning(super,
+ "journal_init_dev: Cannot open '%s': %i",
+ jdev_name, result);
}
return result;
}
@@ -2330,193 +2571,214 @@ static int journal_init_dev( struct super_block *super,
/*
** must be called once on fs mount. calls journal_read for you
*/
-int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_format, unsigned int commit_max_age) {
- int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2 ;
- struct buffer_head *bhjh;
- struct reiserfs_super_block * rs;
- struct reiserfs_journal_header *jh;
- struct reiserfs_journal *journal;
- struct reiserfs_journal_list *jl;
- char b[BDEVNAME_SIZE];
-
- journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof (struct reiserfs_journal)) ;
- if (!journal) {
- reiserfs_warning (p_s_sb, "journal-1256: unable to get memory for journal structure") ;
- return 1 ;
- }
- memset(journal, 0, sizeof(struct reiserfs_journal)) ;
- INIT_LIST_HEAD(&journal->j_bitmap_nodes) ;
- INIT_LIST_HEAD (&journal->j_prealloc_list);
- INIT_LIST_HEAD(&journal->j_working_list);
- INIT_LIST_HEAD(&journal->j_journal_list);
- journal->j_persistent_trans = 0;
- if (reiserfs_allocate_list_bitmaps(p_s_sb,
- journal->j_list_bitmap,
- SB_BMAP_NR(p_s_sb)))
- goto free_and_return ;
- allocate_bitmap_nodes(p_s_sb) ;
-
- /* reserved for journal area support */
- SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ?
- REISERFS_OLD_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize +
- SB_BMAP_NR(p_s_sb) + 1 :
- REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2);
-
- /* Sanity check to see is the standard journal fitting withing first bitmap
- (actual for small blocksizes) */
- if ( !SB_ONDISK_JOURNAL_DEVICE( p_s_sb ) &&
- (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8) ) {
- reiserfs_warning (p_s_sb, "journal-1393: journal does not fit for area "
- "addressed by first of bitmap blocks. It starts at "
- "%u and its size is %u. Block size %ld",
- SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb),
- SB_ONDISK_JOURNAL_SIZE(p_s_sb), p_s_sb->s_blocksize);
- goto free_and_return;
- }
-
- if( journal_init_dev( p_s_sb, journal, j_dev_name ) != 0 ) {
- reiserfs_warning (p_s_sb, "sh-462: unable to initialize jornal device");
- goto free_and_return;
- }
-
- rs = SB_DISK_SUPER_BLOCK(p_s_sb);
-
- /* read journal header */
- bhjh = journal_bread(p_s_sb,
- SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb));
- if (!bhjh) {
- reiserfs_warning (p_s_sb, "sh-459: unable to read journal header");
- goto free_and_return;
- }
- jh = (struct reiserfs_journal_header *)(bhjh->b_data);
-
- /* make sure that journal matches to the super block */
- if (is_reiserfs_jr(rs) && (le32_to_cpu(jh->jh_journal.jp_journal_magic) != sb_jp_journal_magic(rs))) {
- reiserfs_warning (p_s_sb, "sh-460: journal header magic %x "
- "(device %s) does not match to magic found in super "
- "block %x",
- jh->jh_journal.jp_journal_magic,
- bdevname( journal->j_dev_bd, b),
- sb_jp_journal_magic(rs));
- brelse (bhjh);
- goto free_and_return;
- }
-
- journal->j_trans_max = le32_to_cpu (jh->jh_journal.jp_journal_trans_max);
- journal->j_max_batch = le32_to_cpu (jh->jh_journal.jp_journal_max_batch);
- journal->j_max_commit_age = le32_to_cpu (jh->jh_journal.jp_journal_max_commit_age);
- journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
-
- if (journal->j_trans_max) {
- /* make sure these parameters are available, assign it if they are not */
- __u32 initial = journal->j_trans_max;
- __u32 ratio = 1;
-
- if (p_s_sb->s_blocksize < 4096)
- ratio = 4096 / p_s_sb->s_blocksize;
-
- if (SB_ONDISK_JOURNAL_SIZE(p_s_sb)/journal->j_trans_max < JOURNAL_MIN_RATIO)
- journal->j_trans_max = SB_ONDISK_JOURNAL_SIZE(p_s_sb) / JOURNAL_MIN_RATIO;
- if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio)
- journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT / ratio;
- if (journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio)
- journal->j_trans_max = JOURNAL_TRANS_MIN_DEFAULT / ratio;
-
- if (journal->j_trans_max != initial)
- reiserfs_warning (p_s_sb, "sh-461: journal_init: wrong transaction max size (%u). Changed to %u",
- initial, journal->j_trans_max);
-
- journal->j_max_batch = journal->j_trans_max*
- JOURNAL_MAX_BATCH_DEFAULT/JOURNAL_TRANS_MAX_DEFAULT;
- }
-
- if (!journal->j_trans_max) {
- /*we have the file system was created by old version of mkreiserfs
- so this field contains zero value */
- journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT ;
- journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT ;
- journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE ;
-
- /* for blocksize >= 4096 - max transaction size is 1024. For block size < 4096
- trans max size is decreased proportionally */
- if (p_s_sb->s_blocksize < 4096) {
- journal->j_trans_max /= (4096 / p_s_sb->s_blocksize) ;
- journal->j_max_batch = (journal->j_trans_max) * 9 / 10 ;
- }
- }
-
- journal->j_default_max_commit_age = journal->j_max_commit_age;
-
- if (commit_max_age != 0) {
- journal->j_max_commit_age = commit_max_age;
- journal->j_max_trans_age = commit_max_age;
- }
-
- reiserfs_info (p_s_sb, "journal params: device %s, size %u, "
- "journal first block %u, max trans len %u, max batch %u, "
- "max commit age %u, max trans age %u\n",
- bdevname( journal->j_dev_bd, b),
- SB_ONDISK_JOURNAL_SIZE(p_s_sb),
- SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
- journal->j_trans_max,
- journal->j_max_batch,
- journal->j_max_commit_age,
- journal->j_max_trans_age);
-
- brelse (bhjh);
-
- journal->j_list_bitmap_index = 0 ;
- journal_list_init(p_s_sb) ;
-
- memset(journal->j_list_hash_table, 0, JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *)) ;
-
- INIT_LIST_HEAD(&journal->j_dirty_buffers) ;
- spin_lock_init(&journal->j_dirty_buffers_lock) ;
-
- journal->j_start = 0 ;
- journal->j_len = 0 ;
- journal->j_len_alloc = 0 ;
- atomic_set(&(journal->j_wcount), 0) ;
- atomic_set(&(journal->j_async_throttle), 0) ;
- journal->j_bcount = 0 ;
- journal->j_trans_start_time = 0 ;
- journal->j_last = NULL ;
- journal->j_first = NULL ;
- init_waitqueue_head(&(journal->j_join_wait)) ;
- sema_init(&journal->j_lock, 1);
- sema_init(&journal->j_flush_sem, 1);
-
- journal->j_trans_id = 10 ;
- journal->j_mount_id = 10 ;
- journal->j_state = 0 ;
- atomic_set(&(journal->j_jlock), 0) ;
- journal->j_cnode_free_list = allocate_cnodes(num_cnodes) ;
- journal->j_cnode_free_orig = journal->j_cnode_free_list ;
- journal->j_cnode_free = journal->j_cnode_free_list ? num_cnodes : 0 ;
- journal->j_cnode_used = 0 ;
- journal->j_must_wait = 0 ;
-
- init_journal_hash(p_s_sb) ;
- jl = journal->j_current_jl;
- jl->j_list_bitmap = get_list_bitmap(p_s_sb, jl);
- if (!jl->j_list_bitmap) {
- reiserfs_warning(p_s_sb, "journal-2005, get_list_bitmap failed for journal list 0") ;
- goto free_and_return;
- }
- if (journal_read(p_s_sb) < 0) {
- reiserfs_warning(p_s_sb, "Replay Failure, unable to mount") ;
- goto free_and_return;
- }
-
- reiserfs_mounted_fs_count++ ;
- if (reiserfs_mounted_fs_count <= 1)
- commit_wq = create_workqueue("reiserfs");
-
- INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb);
- return 0 ;
-free_and_return:
- free_journal_ram(p_s_sb);
- return 1;
+int journal_init(struct super_block *p_s_sb, const char *j_dev_name,
+ int old_format, unsigned int commit_max_age)
+{
+ int num_cnodes = SB_ONDISK_JOURNAL_SIZE(p_s_sb) * 2;
+ struct buffer_head *bhjh;
+ struct reiserfs_super_block *rs;
+ struct reiserfs_journal_header *jh;
+ struct reiserfs_journal *journal;
+ struct reiserfs_journal_list *jl;
+ char b[BDEVNAME_SIZE];
+
+ journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof(struct reiserfs_journal));
+ if (!journal) {
+ reiserfs_warning(p_s_sb,
+ "journal-1256: unable to get memory for journal structure");
+ return 1;
+ }
+ memset(journal, 0, sizeof(struct reiserfs_journal));
+ INIT_LIST_HEAD(&journal->j_bitmap_nodes);
+ INIT_LIST_HEAD(&journal->j_prealloc_list);
+ INIT_LIST_HEAD(&journal->j_working_list);
+ INIT_LIST_HEAD(&journal->j_journal_list);
+ journal->j_persistent_trans = 0;
+ if (reiserfs_allocate_list_bitmaps(p_s_sb,
+ journal->j_list_bitmap,
+ SB_BMAP_NR(p_s_sb)))
+ goto free_and_return;
+ allocate_bitmap_nodes(p_s_sb);
+
+ /* reserved for journal area support */
+ SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) = (old_format ?
+ REISERFS_OLD_DISK_OFFSET_IN_BYTES
+ / p_s_sb->s_blocksize +
+ SB_BMAP_NR(p_s_sb) +
+ 1 :
+ REISERFS_DISK_OFFSET_IN_BYTES /
+ p_s_sb->s_blocksize + 2);
+
+ /* Sanity check to see is the standard journal fitting withing first bitmap
+ (actual for small blocksizes) */
+ if (!SB_ONDISK_JOURNAL_DEVICE(p_s_sb) &&
+ (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) +
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8)) {
+ reiserfs_warning(p_s_sb,
+ "journal-1393: journal does not fit for area "
+ "addressed by first of bitmap blocks. It starts at "
+ "%u and its size is %u. Block size %ld",
+ SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb),
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb),
+ p_s_sb->s_blocksize);
+ goto free_and_return;
+ }
+
+ if (journal_init_dev(p_s_sb, journal, j_dev_name) != 0) {
+ reiserfs_warning(p_s_sb,
+ "sh-462: unable to initialize jornal device");
+ goto free_and_return;
+ }
+
+ rs = SB_DISK_SUPER_BLOCK(p_s_sb);
+
+ /* read journal header */
+ bhjh = journal_bread(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb));
+ if (!bhjh) {
+ reiserfs_warning(p_s_sb,
+ "sh-459: unable to read journal header");
+ goto free_and_return;
+ }
+ jh = (struct reiserfs_journal_header *)(bhjh->b_data);
+
+ /* make sure that journal matches to the super block */
+ if (is_reiserfs_jr(rs)
+ && (le32_to_cpu(jh->jh_journal.jp_journal_magic) !=
+ sb_jp_journal_magic(rs))) {
+ reiserfs_warning(p_s_sb,
+ "sh-460: journal header magic %x "
+ "(device %s) does not match to magic found in super "
+ "block %x", jh->jh_journal.jp_journal_magic,
+ bdevname(journal->j_dev_bd, b),
+ sb_jp_journal_magic(rs));
+ brelse(bhjh);
+ goto free_and_return;
+ }
+
+ journal->j_trans_max = le32_to_cpu(jh->jh_journal.jp_journal_trans_max);
+ journal->j_max_batch = le32_to_cpu(jh->jh_journal.jp_journal_max_batch);
+ journal->j_max_commit_age =
+ le32_to_cpu(jh->jh_journal.jp_journal_max_commit_age);
+ journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
+
+ if (journal->j_trans_max) {
+ /* make sure these parameters are available, assign it if they are not */
+ __u32 initial = journal->j_trans_max;
+ __u32 ratio = 1;
+
+ if (p_s_sb->s_blocksize < 4096)
+ ratio = 4096 / p_s_sb->s_blocksize;
+
+ if (SB_ONDISK_JOURNAL_SIZE(p_s_sb) / journal->j_trans_max <
+ JOURNAL_MIN_RATIO)
+ journal->j_trans_max =
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb) / JOURNAL_MIN_RATIO;
+ if (journal->j_trans_max > JOURNAL_TRANS_MAX_DEFAULT / ratio)
+ journal->j_trans_max =
+ JOURNAL_TRANS_MAX_DEFAULT / ratio;
+ if (journal->j_trans_max < JOURNAL_TRANS_MIN_DEFAULT / ratio)
+ journal->j_trans_max =
+ JOURNAL_TRANS_MIN_DEFAULT / ratio;
+
+ if (journal->j_trans_max != initial)
+ reiserfs_warning(p_s_sb,
+ "sh-461: journal_init: wrong transaction max size (%u). Changed to %u",
+ initial, journal->j_trans_max);
+
+ journal->j_max_batch = journal->j_trans_max *
+ JOURNAL_MAX_BATCH_DEFAULT / JOURNAL_TRANS_MAX_DEFAULT;
+ }
+
+ if (!journal->j_trans_max) {
+ /*we have the file system was created by old version of mkreiserfs
+ so this field contains zero value */
+ journal->j_trans_max = JOURNAL_TRANS_MAX_DEFAULT;
+ journal->j_max_batch = JOURNAL_MAX_BATCH_DEFAULT;
+ journal->j_max_commit_age = JOURNAL_MAX_COMMIT_AGE;
+
+ /* for blocksize >= 4096 - max transaction size is 1024. For block size < 4096
+ trans max size is decreased proportionally */
+ if (p_s_sb->s_blocksize < 4096) {
+ journal->j_trans_max /= (4096 / p_s_sb->s_blocksize);
+ journal->j_max_batch = (journal->j_trans_max) * 9 / 10;
+ }
+ }
+
+ journal->j_default_max_commit_age = journal->j_max_commit_age;
+
+ if (commit_max_age != 0) {
+ journal->j_max_commit_age = commit_max_age;
+ journal->j_max_trans_age = commit_max_age;
+ }
+
+ reiserfs_info(p_s_sb, "journal params: device %s, size %u, "
+ "journal first block %u, max trans len %u, max batch %u, "
+ "max commit age %u, max trans age %u\n",
+ bdevname(journal->j_dev_bd, b),
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb),
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb),
+ journal->j_trans_max,
+ journal->j_max_batch,
+ journal->j_max_commit_age, journal->j_max_trans_age);
+
+ brelse(bhjh);
+
+ journal->j_list_bitmap_index = 0;
+ journal_list_init(p_s_sb);
+
+ memset(journal->j_list_hash_table, 0,
+ JOURNAL_HASH_SIZE * sizeof(struct reiserfs_journal_cnode *));
+
+ INIT_LIST_HEAD(&journal->j_dirty_buffers);
+ spin_lock_init(&journal->j_dirty_buffers_lock);
+
+ journal->j_start = 0;
+ journal->j_len = 0;
+ journal->j_len_alloc = 0;
+ atomic_set(&(journal->j_wcount), 0);
+ atomic_set(&(journal->j_async_throttle), 0);
+ journal->j_bcount = 0;
+ journal->j_trans_start_time = 0;
+ journal->j_last = NULL;
+ journal->j_first = NULL;
+ init_waitqueue_head(&(journal->j_join_wait));
+ sema_init(&journal->j_lock, 1);
+ sema_init(&journal->j_flush_sem, 1);
+
+ journal->j_trans_id = 10;
+ journal->j_mount_id = 10;
+ journal->j_state = 0;
+ atomic_set(&(journal->j_jlock), 0);
+ journal->j_cnode_free_list = allocate_cnodes(num_cnodes);
+ journal->j_cnode_free_orig = journal->j_cnode_free_list;
+ journal->j_cnode_free = journal->j_cnode_free_list ? num_cnodes : 0;
+ journal->j_cnode_used = 0;
+ journal->j_must_wait = 0;
+
+ init_journal_hash(p_s_sb);
+ jl = journal->j_current_jl;
+ jl->j_list_bitmap = get_list_bitmap(p_s_sb, jl);
+ if (!jl->j_list_bitmap) {
+ reiserfs_warning(p_s_sb,
+ "journal-2005, get_list_bitmap failed for journal list 0");
+ goto free_and_return;
+ }
+ if (journal_read(p_s_sb) < 0) {
+ reiserfs_warning(p_s_sb, "Replay Failure, unable to mount");
+ goto free_and_return;
+ }
+
+ reiserfs_mounted_fs_count++;
+ if (reiserfs_mounted_fs_count <= 1)
+ commit_wq = create_workqueue("reiserfs");
+
+ INIT_WORK(&journal->j_work, flush_async_commits, p_s_sb);
+ return 0;
+ free_and_return:
+ free_journal_ram(p_s_sb);
+ return 1;
}
/*
@@ -2524,96 +2786,102 @@ free_and_return:
** be used by delete to make sure they don't write more than can fit inside a single
** transaction
*/
-int journal_transaction_should_end(struct reiserfs_transaction_handle *th, int new_alloc) {
- struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
- time_t now = get_seconds() ;
- /* cannot restart while nested */
- BUG_ON (!th->t_trans_id);
- if (th->t_refcount > 1)
- return 0 ;
- if ( journal->j_must_wait > 0 ||
- (journal->j_len_alloc + new_alloc) >= journal->j_max_batch ||
- atomic_read(&(journal->j_jlock)) ||
- (now - journal->j_trans_start_time) > journal->j_max_trans_age ||
- journal->j_cnode_free < (journal->j_trans_max * 3)) {
- return 1 ;
- }
- return 0 ;
+int journal_transaction_should_end(struct reiserfs_transaction_handle *th,
+ int new_alloc)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(th->t_super);
+ time_t now = get_seconds();
+ /* cannot restart while nested */
+ BUG_ON(!th->t_trans_id);
+ if (th->t_refcount > 1)
+ return 0;
+ if (journal->j_must_wait > 0 ||
+ (journal->j_len_alloc + new_alloc) >= journal->j_max_batch ||
+ atomic_read(&(journal->j_jlock)) ||
+ (now - journal->j_trans_start_time) > journal->j_max_trans_age ||
+ journal->j_cnode_free < (journal->j_trans_max * 3)) {
+ return 1;
+ }
+ return 0;
}
/* this must be called inside a transaction, and requires the
** kernel_lock to be held
*/
-void reiserfs_block_writes(struct reiserfs_transaction_handle *th) {
- struct reiserfs_journal *journal = SB_JOURNAL (th->t_super);
- BUG_ON (!th->t_trans_id);
- journal->j_must_wait = 1 ;
- set_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
- return ;
+void reiserfs_block_writes(struct reiserfs_transaction_handle *th)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(th->t_super);
+ BUG_ON(!th->t_trans_id);
+ journal->j_must_wait = 1;
+ set_bit(J_WRITERS_BLOCKED, &journal->j_state);
+ return;
}
/* this must be called without a transaction started, and does not
** require BKL
*/
-void reiserfs_allow_writes(struct super_block *s) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- clear_bit(J_WRITERS_BLOCKED, &journal->j_state) ;
- wake_up(&journal->j_join_wait) ;
+void reiserfs_allow_writes(struct super_block *s)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ clear_bit(J_WRITERS_BLOCKED, &journal->j_state);
+ wake_up(&journal->j_join_wait);
}
/* this must be called without a transaction started, and does not
** require BKL
*/
-void reiserfs_wait_on_write_block(struct super_block *s) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- wait_event(journal->j_join_wait,
- !test_bit(J_WRITERS_BLOCKED, &journal->j_state)) ;
-}
-
-static void queue_log_writer(struct super_block *s) {
- wait_queue_t wait;
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- set_bit(J_WRITERS_QUEUED, &journal->j_state);
-
- /*
- * we don't want to use wait_event here because
- * we only want to wait once.
- */
- init_waitqueue_entry(&wait, current);
- add_wait_queue(&journal->j_join_wait, &wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
- schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(&journal->j_join_wait, &wait);
-}
-
-static void wake_queued_writers(struct super_block *s) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- if (test_and_clear_bit(J_WRITERS_QUEUED, &journal->j_state))
- wake_up(&journal->j_join_wait);
-}
-
-static void let_transaction_grow(struct super_block *sb,
- unsigned long trans_id)
-{
- struct reiserfs_journal *journal = SB_JOURNAL (sb);
- unsigned long bcount = journal->j_bcount;
- while(1) {
+void reiserfs_wait_on_write_block(struct super_block *s)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ wait_event(journal->j_join_wait,
+ !test_bit(J_WRITERS_BLOCKED, &journal->j_state));
+}
+
+static void queue_log_writer(struct super_block *s)
+{
+ wait_queue_t wait;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ set_bit(J_WRITERS_QUEUED, &journal->j_state);
+
+ /*
+ * we don't want to use wait_event here because
+ * we only want to wait once.
+ */
+ init_waitqueue_entry(&wait, current);
+ add_wait_queue(&journal->j_join_wait, &wait);
set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- journal->j_current_jl->j_state |= LIST_COMMIT_PENDING;
- while ((atomic_read(&journal->j_wcount) > 0 ||
- atomic_read(&journal->j_jlock)) &&
- journal->j_trans_id == trans_id) {
- queue_log_writer(sb);
+ if (test_bit(J_WRITERS_QUEUED, &journal->j_state))
+ schedule();
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&journal->j_join_wait, &wait);
+}
+
+static void wake_queued_writers(struct super_block *s)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ if (test_and_clear_bit(J_WRITERS_QUEUED, &journal->j_state))
+ wake_up(&journal->j_join_wait);
+}
+
+static void let_transaction_grow(struct super_block *sb, unsigned long trans_id)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(sb);
+ unsigned long bcount = journal->j_bcount;
+ while (1) {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(1);
+ journal->j_current_jl->j_state |= LIST_COMMIT_PENDING;
+ while ((atomic_read(&journal->j_wcount) > 0 ||
+ atomic_read(&journal->j_jlock)) &&
+ journal->j_trans_id == trans_id) {
+ queue_log_writer(sb);
+ }
+ if (journal->j_trans_id != trans_id)
+ break;
+ if (bcount == journal->j_bcount)
+ break;
+ bcount = journal->j_bcount;
}
- if (journal->j_trans_id != trans_id)
- break;
- if (bcount == journal->j_bcount)
- break;
- bcount = journal->j_bcount;
- }
}
/* join == true if you must join an existing transaction.
@@ -2622,221 +2890,244 @@ static void let_transaction_grow(struct super_block *sb,
** this will block until the transaction is joinable. send the number of blocks you
** expect to use in nblocks.
*/
-static int do_journal_begin_r(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb,unsigned long nblocks,int join) {
- time_t now = get_seconds() ;
- int old_trans_id ;
- struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
- struct reiserfs_transaction_handle myth;
- int sched_count = 0;
- int retval;
-
- reiserfs_check_lock_depth(p_s_sb, "journal_begin") ;
-
- PROC_INFO_INC( p_s_sb, journal.journal_being );
- /* set here for journal_join */
- th->t_refcount = 1;
- th->t_super = p_s_sb ;
-
-relock:
- lock_journal(p_s_sb) ;
- if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted (journal)) {
- unlock_journal (p_s_sb);
- retval = journal->j_errno;
- goto out_fail;
- }
- journal->j_bcount++;
-
- if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
- unlock_journal(p_s_sb) ;
- reiserfs_wait_on_write_block(p_s_sb) ;
- PROC_INFO_INC( p_s_sb, journal.journal_relock_writers );
- goto relock ;
- }
- now = get_seconds();
-
- /* if there is no room in the journal OR
- ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning
- ** we don't sleep if there aren't other writers
- */
-
- if ( (!join && journal->j_must_wait > 0) ||
- ( !join && (journal->j_len_alloc + nblocks + 2) >= journal->j_max_batch) ||
- (!join && atomic_read(&journal->j_wcount) > 0 && journal->j_trans_start_time > 0 &&
- (now - journal->j_trans_start_time) > journal->j_max_trans_age) ||
- (!join && atomic_read(&journal->j_jlock)) ||
- (!join && journal->j_cnode_free < (journal->j_trans_max * 3))) {
-
- old_trans_id = journal->j_trans_id;
- unlock_journal(p_s_sb) ; /* allow others to finish this transaction */
-
- if (!join && (journal->j_len_alloc + nblocks + 2) >=
- journal->j_max_batch &&
- ((journal->j_len + nblocks + 2) * 100) < (journal->j_len_alloc * 75))
- {
- if (atomic_read(&journal->j_wcount) > 10) {
- sched_count++;
- queue_log_writer(p_s_sb);
- goto relock;
- }
- }
- /* don't mess with joining the transaction if all we have to do is
- * wait for someone else to do a commit
- */
- if (atomic_read(&journal->j_jlock)) {
- while (journal->j_trans_id == old_trans_id &&
- atomic_read(&journal->j_jlock)) {
- queue_log_writer(p_s_sb);
- }
- goto relock;
- }
- retval = journal_join(&myth, p_s_sb, 1) ;
- if (retval)
- goto out_fail;
-
- /* someone might have ended the transaction while we joined */
- if (old_trans_id != journal->j_trans_id) {
- retval = do_journal_end(&myth, p_s_sb, 1, 0) ;
- } else {
- retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW) ;
- }
-
- if (retval)
- goto out_fail;
-
- PROC_INFO_INC( p_s_sb, journal.journal_relock_wcount );
- goto relock ;
- }
- /* we are the first writer, set trans_id */
- if (journal->j_trans_start_time == 0) {
- journal->j_trans_start_time = get_seconds();
- }
- atomic_inc(&(journal->j_wcount)) ;
- journal->j_len_alloc += nblocks ;
- th->t_blocks_logged = 0 ;
- th->t_blocks_allocated = nblocks ;
- th->t_trans_id = journal->j_trans_id ;
- unlock_journal(p_s_sb) ;
- INIT_LIST_HEAD (&th->t_list);
- return 0 ;
-
-out_fail:
- memset (th, 0, sizeof (*th));
- /* Re-set th->t_super, so we can properly keep track of how many
- * persistent transactions there are. We need to do this so if this
- * call is part of a failed restart_transaction, we can free it later */
- th->t_super = p_s_sb;
- return retval;
-}
-
-struct reiserfs_transaction_handle *
-reiserfs_persistent_transaction(struct super_block *s, int nblocks) {
- int ret ;
- struct reiserfs_transaction_handle *th ;
-
- /* if we're nesting into an existing transaction. It will be
- ** persistent on its own
- */
- if (reiserfs_transaction_running(s)) {
- th = current->journal_info ;
- th->t_refcount++ ;
- if (th->t_refcount < 2) {
- BUG() ;
- }
- return th ;
- }
- th = reiserfs_kmalloc(sizeof(struct reiserfs_transaction_handle), GFP_NOFS, s) ;
- if (!th)
- return NULL;
- ret = journal_begin(th, s, nblocks) ;
- if (ret) {
- reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
- return NULL;
- }
-
- SB_JOURNAL(s)->j_persistent_trans++;
- return th ;
-}
-
-int
-reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th) {
- struct super_block *s = th->t_super;
- int ret = 0;
- if (th->t_trans_id)
- ret = journal_end(th, th->t_super, th->t_blocks_allocated);
- else
- ret = -EIO;
- if (th->t_refcount == 0) {
- SB_JOURNAL(s)->j_persistent_trans--;
- reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle), s) ;
- }
- return ret;
-}
-
-static int journal_join(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
- struct reiserfs_transaction_handle *cur_th = current->journal_info;
-
- /* this keeps do_journal_end from NULLing out the current->journal_info
- ** pointer
- */
- th->t_handle_save = cur_th ;
- if (cur_th && cur_th->t_refcount > 1) {
- BUG() ;
- }
- return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN) ;
-}
-
-int journal_join_abort(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
- struct reiserfs_transaction_handle *cur_th = current->journal_info;
-
- /* this keeps do_journal_end from NULLing out the current->journal_info
- ** pointer
- */
- th->t_handle_save = cur_th ;
- if (cur_th && cur_th->t_refcount > 1) {
- BUG() ;
- }
- return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT) ;
-}
-
-int journal_begin(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb, unsigned long nblocks) {
- struct reiserfs_transaction_handle *cur_th = current->journal_info ;
- int ret ;
-
- th->t_handle_save = NULL ;
- if (cur_th) {
- /* we are nesting into the current transaction */
- if (cur_th->t_super == p_s_sb) {
- BUG_ON (!cur_th->t_refcount);
- cur_th->t_refcount++ ;
- memcpy(th, cur_th, sizeof(*th));
- if (th->t_refcount <= 1)
- reiserfs_warning (p_s_sb, "BAD: refcount <= 1, but journal_info != 0");
- return 0;
+static int do_journal_begin_r(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks,
+ int join)
+{
+ time_t now = get_seconds();
+ int old_trans_id;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_transaction_handle myth;
+ int sched_count = 0;
+ int retval;
+
+ reiserfs_check_lock_depth(p_s_sb, "journal_begin");
+ if (nblocks > journal->j_trans_max)
+ BUG();
+
+ PROC_INFO_INC(p_s_sb, journal.journal_being);
+ /* set here for journal_join */
+ th->t_refcount = 1;
+ th->t_super = p_s_sb;
+
+ relock:
+ lock_journal(p_s_sb);
+ if (join != JBEGIN_ABORT && reiserfs_is_journal_aborted(journal)) {
+ unlock_journal(p_s_sb);
+ retval = journal->j_errno;
+ goto out_fail;
+ }
+ journal->j_bcount++;
+
+ if (test_bit(J_WRITERS_BLOCKED, &journal->j_state)) {
+ unlock_journal(p_s_sb);
+ reiserfs_wait_on_write_block(p_s_sb);
+ PROC_INFO_INC(p_s_sb, journal.journal_relock_writers);
+ goto relock;
+ }
+ now = get_seconds();
+
+ /* if there is no room in the journal OR
+ ** if this transaction is too old, and we weren't called joinable, wait for it to finish before beginning
+ ** we don't sleep if there aren't other writers
+ */
+
+ if ((!join && journal->j_must_wait > 0) ||
+ (!join
+ && (journal->j_len_alloc + nblocks + 2) >= journal->j_max_batch)
+ || (!join && atomic_read(&journal->j_wcount) > 0
+ && journal->j_trans_start_time > 0
+ && (now - journal->j_trans_start_time) >
+ journal->j_max_trans_age) || (!join
+ && atomic_read(&journal->j_jlock))
+ || (!join && journal->j_cnode_free < (journal->j_trans_max * 3))) {
+
+ old_trans_id = journal->j_trans_id;
+ unlock_journal(p_s_sb); /* allow others to finish this transaction */
+
+ if (!join && (journal->j_len_alloc + nblocks + 2) >=
+ journal->j_max_batch &&
+ ((journal->j_len + nblocks + 2) * 100) <
+ (journal->j_len_alloc * 75)) {
+ if (atomic_read(&journal->j_wcount) > 10) {
+ sched_count++;
+ queue_log_writer(p_s_sb);
+ goto relock;
+ }
+ }
+ /* don't mess with joining the transaction if all we have to do is
+ * wait for someone else to do a commit
+ */
+ if (atomic_read(&journal->j_jlock)) {
+ while (journal->j_trans_id == old_trans_id &&
+ atomic_read(&journal->j_jlock)) {
+ queue_log_writer(p_s_sb);
+ }
+ goto relock;
+ }
+ retval = journal_join(&myth, p_s_sb, 1);
+ if (retval)
+ goto out_fail;
+
+ /* someone might have ended the transaction while we joined */
+ if (old_trans_id != journal->j_trans_id) {
+ retval = do_journal_end(&myth, p_s_sb, 1, 0);
+ } else {
+ retval = do_journal_end(&myth, p_s_sb, 1, COMMIT_NOW);
+ }
+
+ if (retval)
+ goto out_fail;
+
+ PROC_INFO_INC(p_s_sb, journal.journal_relock_wcount);
+ goto relock;
+ }
+ /* we are the first writer, set trans_id */
+ if (journal->j_trans_start_time == 0) {
+ journal->j_trans_start_time = get_seconds();
+ }
+ atomic_inc(&(journal->j_wcount));
+ journal->j_len_alloc += nblocks;
+ th->t_blocks_logged = 0;
+ th->t_blocks_allocated = nblocks;
+ th->t_trans_id = journal->j_trans_id;
+ unlock_journal(p_s_sb);
+ INIT_LIST_HEAD(&th->t_list);
+ get_fs_excl();
+ return 0;
+
+ out_fail:
+ memset(th, 0, sizeof(*th));
+ /* Re-set th->t_super, so we can properly keep track of how many
+ * persistent transactions there are. We need to do this so if this
+ * call is part of a failed restart_transaction, we can free it later */
+ th->t_super = p_s_sb;
+ return retval;
+}
+
+struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
+ super_block
+ *s,
+ int nblocks)
+{
+ int ret;
+ struct reiserfs_transaction_handle *th;
+
+ /* if we're nesting into an existing transaction. It will be
+ ** persistent on its own
+ */
+ if (reiserfs_transaction_running(s)) {
+ th = current->journal_info;
+ th->t_refcount++;
+ if (th->t_refcount < 2) {
+ BUG();
+ }
+ return th;
+ }
+ th = reiserfs_kmalloc(sizeof(struct reiserfs_transaction_handle),
+ GFP_NOFS, s);
+ if (!th)
+ return NULL;
+ ret = journal_begin(th, s, nblocks);
+ if (ret) {
+ reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle),
+ s);
+ return NULL;
+ }
+
+ SB_JOURNAL(s)->j_persistent_trans++;
+ return th;
+}
+
+int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *th)
+{
+ struct super_block *s = th->t_super;
+ int ret = 0;
+ if (th->t_trans_id)
+ ret = journal_end(th, th->t_super, th->t_blocks_allocated);
+ else
+ ret = -EIO;
+ if (th->t_refcount == 0) {
+ SB_JOURNAL(s)->j_persistent_trans--;
+ reiserfs_kfree(th, sizeof(struct reiserfs_transaction_handle),
+ s);
+ }
+ return ret;
+}
+
+static int journal_join(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks)
+{
+ struct reiserfs_transaction_handle *cur_th = current->journal_info;
+
+ /* this keeps do_journal_end from NULLing out the current->journal_info
+ ** pointer
+ */
+ th->t_handle_save = cur_th;
+ if (cur_th && cur_th->t_refcount > 1) {
+ BUG();
+ }
+ return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_JOIN);
+}
+
+int journal_join_abort(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks)
+{
+ struct reiserfs_transaction_handle *cur_th = current->journal_info;
+
+ /* this keeps do_journal_end from NULLing out the current->journal_info
+ ** pointer
+ */
+ th->t_handle_save = cur_th;
+ if (cur_th && cur_th->t_refcount > 1) {
+ BUG();
+ }
+ return do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_ABORT);
+}
+
+int journal_begin(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks)
+{
+ struct reiserfs_transaction_handle *cur_th = current->journal_info;
+ int ret;
+
+ th->t_handle_save = NULL;
+ if (cur_th) {
+ /* we are nesting into the current transaction */
+ if (cur_th->t_super == p_s_sb) {
+ BUG_ON(!cur_th->t_refcount);
+ cur_th->t_refcount++;
+ memcpy(th, cur_th, sizeof(*th));
+ if (th->t_refcount <= 1)
+ reiserfs_warning(p_s_sb,
+ "BAD: refcount <= 1, but journal_info != 0");
+ return 0;
+ } else {
+ /* we've ended up with a handle from a different filesystem.
+ ** save it and restore on journal_end. This should never
+ ** really happen...
+ */
+ reiserfs_warning(p_s_sb,
+ "clm-2100: nesting info a different FS");
+ th->t_handle_save = current->journal_info;
+ current->journal_info = th;
+ }
} else {
- /* we've ended up with a handle from a different filesystem.
- ** save it and restore on journal_end. This should never
- ** really happen...
- */
- reiserfs_warning(p_s_sb, "clm-2100: nesting info a different FS") ;
- th->t_handle_save = current->journal_info ;
- current->journal_info = th;
- }
- } else {
- current->journal_info = th;
- }
- ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG) ;
- if (current->journal_info != th)
- BUG() ;
+ current->journal_info = th;
+ }
+ ret = do_journal_begin_r(th, p_s_sb, nblocks, JBEGIN_REG);
+ if (current->journal_info != th)
+ BUG();
- /* I guess this boils down to being the reciprocal of clm-2100 above.
- * If do_journal_begin_r fails, we need to put it back, since journal_end
- * won't be called to do it. */
- if (ret)
- current->journal_info = th->t_handle_save;
- else
- BUG_ON (!th->t_refcount);
+ /* I guess this boils down to being the reciprocal of clm-2100 above.
+ * If do_journal_begin_r fails, we need to put it back, since journal_end
+ * won't be called to do it. */
+ if (ret)
+ current->journal_info = th->t_handle_save;
+ else
+ BUG_ON(!th->t_refcount);
- return ret ;
+ return ret;
}
/*
@@ -2848,129 +3139,140 @@ int journal_begin(struct reiserfs_transaction_handle *th, struct super_block *
**
** if j_len, is bigger than j_len_alloc, it pushes j_len_alloc to 10 + j_len.
*/
-int journal_mark_dirty(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, struct buffer_head *bh) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_cnode *cn = NULL;
- int count_already_incd = 0 ;
- int prepared = 0 ;
- BUG_ON (!th->t_trans_id);
-
- PROC_INFO_INC( p_s_sb, journal.mark_dirty );
- if (th->t_trans_id != journal->j_trans_id) {
- reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n",
- th->t_trans_id, journal->j_trans_id);
- }
-
- p_s_sb->s_dirt = 1;
-
- prepared = test_clear_buffer_journal_prepared (bh);
- clear_buffer_journal_restore_dirty (bh);
- /* already in this transaction, we are done */
- if (buffer_journaled(bh)) {
- PROC_INFO_INC( p_s_sb, journal.mark_dirty_already );
- return 0 ;
- }
-
- /* this must be turned into a panic instead of a warning. We can't allow
- ** a dirty or journal_dirty or locked buffer to be logged, as some changes
- ** could get to disk too early. NOT GOOD.
- */
- if (!prepared || buffer_dirty(bh)) {
- reiserfs_warning (p_s_sb, "journal-1777: buffer %llu bad state "
- "%cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT",
- (unsigned long long)bh->b_blocknr, prepared ? ' ' : '!',
- buffer_locked(bh) ? ' ' : '!',
- buffer_dirty(bh) ? ' ' : '!',
- buffer_journal_dirty(bh) ? ' ' : '!') ;
- }
-
- if (atomic_read(&(journal->j_wcount)) <= 0) {
- reiserfs_warning (p_s_sb, "journal-1409: journal_mark_dirty returning because j_wcount was %d", atomic_read(&(journal->j_wcount))) ;
- return 1 ;
- }
- /* this error means I've screwed up, and we've overflowed the transaction.
- ** Nothing can be done here, except make the FS readonly or panic.
- */
- if (journal->j_len >= journal->j_trans_max) {
- reiserfs_panic(th->t_super, "journal-1413: journal_mark_dirty: j_len (%lu) is too big\n", journal->j_len) ;
- }
-
- if (buffer_journal_dirty(bh)) {
- count_already_incd = 1 ;
- PROC_INFO_INC( p_s_sb, journal.mark_dirty_notjournal );
- clear_buffer_journal_dirty (bh);
- }
-
- if (journal->j_len > journal->j_len_alloc) {
- journal->j_len_alloc = journal->j_len + JOURNAL_PER_BALANCE_CNT ;
- }
-
- set_buffer_journaled (bh);
-
- /* now put this guy on the end */
- if (!cn) {
- cn = get_cnode(p_s_sb) ;
- if (!cn) {
- reiserfs_panic(p_s_sb, "get_cnode failed!\n");
- }
-
- if (th->t_blocks_logged == th->t_blocks_allocated) {
- th->t_blocks_allocated += JOURNAL_PER_BALANCE_CNT ;
- journal->j_len_alloc += JOURNAL_PER_BALANCE_CNT ;
- }
- th->t_blocks_logged++ ;
- journal->j_len++ ;
-
- cn->bh = bh ;
- cn->blocknr = bh->b_blocknr ;
- cn->sb = p_s_sb;
- cn->jlist = NULL ;
- insert_journal_hash(journal->j_hash_table, cn) ;
- if (!count_already_incd) {
- get_bh(bh) ;
- }
- }
- cn->next = NULL ;
- cn->prev = journal->j_last ;
- cn->bh = bh ;
- if (journal->j_last) {
- journal->j_last->next = cn ;
- journal->j_last = cn ;
- } else {
- journal->j_first = cn ;
- journal->j_last = cn ;
- }
- return 0 ;
-}
-
-int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
- if (!current->journal_info && th->t_refcount > 1)
- reiserfs_warning (p_s_sb, "REISER-NESTING: th NULL, refcount %d",
- th->t_refcount);
-
- if (!th->t_trans_id) {
- WARN_ON (1);
- return -EIO;
- }
-
- th->t_refcount--;
- if (th->t_refcount > 0) {
- struct reiserfs_transaction_handle *cur_th = current->journal_info ;
-
- /* we aren't allowed to close a nested transaction on a different
- ** filesystem from the one in the task struct
- */
- if (cur_th->t_super != th->t_super)
- BUG() ;
-
- if (th != cur_th) {
- memcpy(current->journal_info, th, sizeof(*th));
- th->t_trans_id = 0;
- }
- return 0;
- } else {
- return do_journal_end(th, p_s_sb, nblocks, 0) ;
- }
+int journal_mark_dirty(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, struct buffer_head *bh)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_cnode *cn = NULL;
+ int count_already_incd = 0;
+ int prepared = 0;
+ BUG_ON(!th->t_trans_id);
+
+ PROC_INFO_INC(p_s_sb, journal.mark_dirty);
+ if (th->t_trans_id != journal->j_trans_id) {
+ reiserfs_panic(th->t_super,
+ "journal-1577: handle trans id %ld != current trans id %ld\n",
+ th->t_trans_id, journal->j_trans_id);
+ }
+
+ p_s_sb->s_dirt = 1;
+
+ prepared = test_clear_buffer_journal_prepared(bh);
+ clear_buffer_journal_restore_dirty(bh);
+ /* already in this transaction, we are done */
+ if (buffer_journaled(bh)) {
+ PROC_INFO_INC(p_s_sb, journal.mark_dirty_already);
+ return 0;
+ }
+
+ /* this must be turned into a panic instead of a warning. We can't allow
+ ** a dirty or journal_dirty or locked buffer to be logged, as some changes
+ ** could get to disk too early. NOT GOOD.
+ */
+ if (!prepared || buffer_dirty(bh)) {
+ reiserfs_warning(p_s_sb, "journal-1777: buffer %llu bad state "
+ "%cPREPARED %cLOCKED %cDIRTY %cJDIRTY_WAIT",
+ (unsigned long long)bh->b_blocknr,
+ prepared ? ' ' : '!',
+ buffer_locked(bh) ? ' ' : '!',
+ buffer_dirty(bh) ? ' ' : '!',
+ buffer_journal_dirty(bh) ? ' ' : '!');
+ }
+
+ if (atomic_read(&(journal->j_wcount)) <= 0) {
+ reiserfs_warning(p_s_sb,
+ "journal-1409: journal_mark_dirty returning because j_wcount was %d",
+ atomic_read(&(journal->j_wcount)));
+ return 1;
+ }
+ /* this error means I've screwed up, and we've overflowed the transaction.
+ ** Nothing can be done here, except make the FS readonly or panic.
+ */
+ if (journal->j_len >= journal->j_trans_max) {
+ reiserfs_panic(th->t_super,
+ "journal-1413: journal_mark_dirty: j_len (%lu) is too big\n",
+ journal->j_len);
+ }
+
+ if (buffer_journal_dirty(bh)) {
+ count_already_incd = 1;
+ PROC_INFO_INC(p_s_sb, journal.mark_dirty_notjournal);
+ clear_buffer_journal_dirty(bh);
+ }
+
+ if (journal->j_len > journal->j_len_alloc) {
+ journal->j_len_alloc = journal->j_len + JOURNAL_PER_BALANCE_CNT;
+ }
+
+ set_buffer_journaled(bh);
+
+ /* now put this guy on the end */
+ if (!cn) {
+ cn = get_cnode(p_s_sb);
+ if (!cn) {
+ reiserfs_panic(p_s_sb, "get_cnode failed!\n");
+ }
+
+ if (th->t_blocks_logged == th->t_blocks_allocated) {
+ th->t_blocks_allocated += JOURNAL_PER_BALANCE_CNT;
+ journal->j_len_alloc += JOURNAL_PER_BALANCE_CNT;
+ }
+ th->t_blocks_logged++;
+ journal->j_len++;
+
+ cn->bh = bh;
+ cn->blocknr = bh->b_blocknr;
+ cn->sb = p_s_sb;
+ cn->jlist = NULL;
+ insert_journal_hash(journal->j_hash_table, cn);
+ if (!count_already_incd) {
+ get_bh(bh);
+ }
+ }
+ cn->next = NULL;
+ cn->prev = journal->j_last;
+ cn->bh = bh;
+ if (journal->j_last) {
+ journal->j_last->next = cn;
+ journal->j_last = cn;
+ } else {
+ journal->j_first = cn;
+ journal->j_last = cn;
+ }
+ return 0;
+}
+
+int journal_end(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks)
+{
+ if (!current->journal_info && th->t_refcount > 1)
+ reiserfs_warning(p_s_sb, "REISER-NESTING: th NULL, refcount %d",
+ th->t_refcount);
+
+ if (!th->t_trans_id) {
+ WARN_ON(1);
+ return -EIO;
+ }
+
+ th->t_refcount--;
+ if (th->t_refcount > 0) {
+ struct reiserfs_transaction_handle *cur_th =
+ current->journal_info;
+
+ /* we aren't allowed to close a nested transaction on a different
+ ** filesystem from the one in the task struct
+ */
+ if (cur_th->t_super != th->t_super)
+ BUG();
+
+ if (th != cur_th) {
+ memcpy(current->journal_info, th, sizeof(*th));
+ th->t_trans_id = 0;
+ }
+ return 0;
+ } else {
+ return do_journal_end(th, p_s_sb, nblocks, 0);
+ }
}
/* removes from the current transaction, relsing and descrementing any counters.
@@ -2980,47 +3282,51 @@ int journal_end(struct reiserfs_transaction_handle *th, struct super_block *p_s_
**
** returns 1 if it cleaned and relsed the buffer. 0 otherwise
*/
-static int remove_from_transaction(struct super_block *p_s_sb, b_blocknr_t blocknr, int already_cleaned) {
- struct buffer_head *bh ;
- struct reiserfs_journal_cnode *cn ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- int ret = 0;
-
- cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr) ;
- if (!cn || !cn->bh) {
- return ret ;
- }
- bh = cn->bh ;
- if (cn->prev) {
- cn->prev->next = cn->next ;
- }
- if (cn->next) {
- cn->next->prev = cn->prev ;
- }
- if (cn == journal->j_first) {
- journal->j_first = cn->next ;
- }
- if (cn == journal->j_last) {
- journal->j_last = cn->prev ;
- }
- if (bh)
- remove_journal_hash(p_s_sb, journal->j_hash_table, NULL, bh->b_blocknr, 0) ;
- clear_buffer_journaled (bh); /* don't log this one */
-
- if (!already_cleaned) {
- clear_buffer_journal_dirty (bh);
- clear_buffer_dirty(bh);
- clear_buffer_journal_test (bh);
- put_bh(bh) ;
- if (atomic_read(&(bh->b_count)) < 0) {
- reiserfs_warning (p_s_sb, "journal-1752: remove from trans, b_count < 0");
- }
- ret = 1 ;
- }
- journal->j_len-- ;
- journal->j_len_alloc-- ;
- free_cnode(p_s_sb, cn) ;
- return ret ;
+static int remove_from_transaction(struct super_block *p_s_sb,
+ b_blocknr_t blocknr, int already_cleaned)
+{
+ struct buffer_head *bh;
+ struct reiserfs_journal_cnode *cn;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ int ret = 0;
+
+ cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
+ if (!cn || !cn->bh) {
+ return ret;
+ }
+ bh = cn->bh;
+ if (cn->prev) {
+ cn->prev->next = cn->next;
+ }
+ if (cn->next) {
+ cn->next->prev = cn->prev;
+ }
+ if (cn == journal->j_first) {
+ journal->j_first = cn->next;
+ }
+ if (cn == journal->j_last) {
+ journal->j_last = cn->prev;
+ }
+ if (bh)
+ remove_journal_hash(p_s_sb, journal->j_hash_table, NULL,
+ bh->b_blocknr, 0);
+ clear_buffer_journaled(bh); /* don't log this one */
+
+ if (!already_cleaned) {
+ clear_buffer_journal_dirty(bh);
+ clear_buffer_dirty(bh);
+ clear_buffer_journal_test(bh);
+ put_bh(bh);
+ if (atomic_read(&(bh->b_count)) < 0) {
+ reiserfs_warning(p_s_sb,
+ "journal-1752: remove from trans, b_count < 0");
+ }
+ ret = 1;
+ }
+ journal->j_len--;
+ journal->j_len_alloc--;
+ free_cnode(p_s_sb, cn);
+ return ret;
}
/*
@@ -3033,120 +3339,129 @@ static int remove_from_transaction(struct super_block *p_s_sb, b_blocknr_t block
** blocks for a given transaction on disk
**
*/
-static int can_dirty(struct reiserfs_journal_cnode *cn) {
- struct super_block *sb = cn->sb;
- b_blocknr_t blocknr = cn->blocknr ;
- struct reiserfs_journal_cnode *cur = cn->hprev ;
- int can_dirty = 1 ;
-
- /* first test hprev. These are all newer than cn, so any node here
- ** with the same block number and dev means this node can't be sent
- ** to disk right now.
- */
- while(cur && can_dirty) {
- if (cur->jlist && cur->bh && cur->blocknr && cur->sb == sb &&
- cur->blocknr == blocknr) {
- can_dirty = 0 ;
- }
- cur = cur->hprev ;
- }
- /* then test hnext. These are all older than cn. As long as they
- ** are committed to the log, it is safe to write cn to disk
- */
- cur = cn->hnext ;
- while(cur && can_dirty) {
- if (cur->jlist && cur->jlist->j_len > 0 &&
- atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh &&
- cur->blocknr && cur->sb == sb && cur->blocknr == blocknr) {
- can_dirty = 0 ;
- }
- cur = cur->hnext ;
- }
- return can_dirty ;
+static int can_dirty(struct reiserfs_journal_cnode *cn)
+{
+ struct super_block *sb = cn->sb;
+ b_blocknr_t blocknr = cn->blocknr;
+ struct reiserfs_journal_cnode *cur = cn->hprev;
+ int can_dirty = 1;
+
+ /* first test hprev. These are all newer than cn, so any node here
+ ** with the same block number and dev means this node can't be sent
+ ** to disk right now.
+ */
+ while (cur && can_dirty) {
+ if (cur->jlist && cur->bh && cur->blocknr && cur->sb == sb &&
+ cur->blocknr == blocknr) {
+ can_dirty = 0;
+ }
+ cur = cur->hprev;
+ }
+ /* then test hnext. These are all older than cn. As long as they
+ ** are committed to the log, it is safe to write cn to disk
+ */
+ cur = cn->hnext;
+ while (cur && can_dirty) {
+ if (cur->jlist && cur->jlist->j_len > 0 &&
+ atomic_read(&(cur->jlist->j_commit_left)) > 0 && cur->bh &&
+ cur->blocknr && cur->sb == sb && cur->blocknr == blocknr) {
+ can_dirty = 0;
+ }
+ cur = cur->hnext;
+ }
+ return can_dirty;
}
/* syncs the commit blocks, but does not force the real buffers to disk
** will wait until the current transaction is done/commited before returning
*/
-int journal_end_sync(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, unsigned long nblocks) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
+int journal_end_sync(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
- BUG_ON (!th->t_trans_id);
- /* you can sync while nested, very, very bad */
- if (th->t_refcount > 1) {
- BUG() ;
- }
- if (journal->j_len == 0) {
- reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
- journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
- }
- return do_journal_end(th, p_s_sb, nblocks, COMMIT_NOW | WAIT) ;
+ BUG_ON(!th->t_trans_id);
+ /* you can sync while nested, very, very bad */
+ if (th->t_refcount > 1) {
+ BUG();
+ }
+ if (journal->j_len == 0) {
+ reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+ journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb));
+ }
+ return do_journal_end(th, p_s_sb, nblocks, COMMIT_NOW | WAIT);
}
/*
** writeback the pending async commits to disk
*/
-static void flush_async_commits(void *p) {
- struct super_block *p_s_sb = p;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_list *jl;
- struct list_head *entry;
-
- lock_kernel();
- if (!list_empty(&journal->j_journal_list)) {
- /* last entry is the youngest, commit it and you get everything */
- entry = journal->j_journal_list.prev;
- jl = JOURNAL_LIST_ENTRY(entry);
- flush_commit_list(p_s_sb, jl, 1);
- }
- unlock_kernel();
- /*
- * this is a little racey, but there's no harm in missing
- * the filemap_fdata_write
- */
- if (!atomic_read(&journal->j_async_throttle) && !reiserfs_is_journal_aborted (journal)) {
- atomic_inc(&journal->j_async_throttle);
- filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
- atomic_dec(&journal->j_async_throttle);
- }
+static void flush_async_commits(void *p)
+{
+ struct super_block *p_s_sb = p;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_list *jl;
+ struct list_head *entry;
+
+ lock_kernel();
+ if (!list_empty(&journal->j_journal_list)) {
+ /* last entry is the youngest, commit it and you get everything */
+ entry = journal->j_journal_list.prev;
+ jl = JOURNAL_LIST_ENTRY(entry);
+ flush_commit_list(p_s_sb, jl, 1);
+ }
+ unlock_kernel();
+ /*
+ * this is a little racey, but there's no harm in missing
+ * the filemap_fdata_write
+ */
+ if (!atomic_read(&journal->j_async_throttle)
+ && !reiserfs_is_journal_aborted(journal)) {
+ atomic_inc(&journal->j_async_throttle);
+ filemap_fdatawrite(p_s_sb->s_bdev->bd_inode->i_mapping);
+ atomic_dec(&journal->j_async_throttle);
+ }
}
/*
** flushes any old transactions to disk
** ends the current transaction if it is too old
*/
-int reiserfs_flush_old_commits(struct super_block *p_s_sb) {
- time_t now ;
- struct reiserfs_transaction_handle th ;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
-
- now = get_seconds();
- /* safety check so we don't flush while we are replaying the log during
- * mount
- */
- if (list_empty(&journal->j_journal_list)) {
- return 0 ;
- }
-
- /* check the current transaction. If there are no writers, and it is
- * too old, finish it, and force the commit blocks to disk
- */
- if (atomic_read(&journal->j_wcount) <= 0 &&
- journal->j_trans_start_time > 0 &&
- journal->j_len > 0 &&
- (now - journal->j_trans_start_time) > journal->j_max_trans_age)
- {
- if (!journal_join(&th, p_s_sb, 1)) {
- reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
- journal_mark_dirty(&th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
-
- /* we're only being called from kreiserfsd, it makes no sense to do
- ** an async commit so that kreiserfsd can do it later
- */
- do_journal_end(&th, p_s_sb,1, COMMIT_NOW | WAIT) ;
- }
- }
- return p_s_sb->s_dirt;
+int reiserfs_flush_old_commits(struct super_block *p_s_sb)
+{
+ time_t now;
+ struct reiserfs_transaction_handle th;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+
+ now = get_seconds();
+ /* safety check so we don't flush while we are replaying the log during
+ * mount
+ */
+ if (list_empty(&journal->j_journal_list)) {
+ return 0;
+ }
+
+ /* check the current transaction. If there are no writers, and it is
+ * too old, finish it, and force the commit blocks to disk
+ */
+ if (atomic_read(&journal->j_wcount) <= 0 &&
+ journal->j_trans_start_time > 0 &&
+ journal->j_len > 0 &&
+ (now - journal->j_trans_start_time) > journal->j_max_trans_age) {
+ if (!journal_join(&th, p_s_sb, 1)) {
+ reiserfs_prepare_for_journal(p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+ journal_mark_dirty(&th, p_s_sb,
+ SB_BUFFER_WITH_SB(p_s_sb));
+
+ /* we're only being called from kreiserfsd, it makes no sense to do
+ ** an async commit so that kreiserfsd can do it later
+ */
+ do_journal_end(&th, p_s_sb, 1, COMMIT_NOW | WAIT);
+ }
+ }
+ return p_s_sb->s_dirt;
}
/*
@@ -3160,101 +3475,108 @@ int reiserfs_flush_old_commits(struct super_block *p_s_sb) {
**
** Note, we can't allow the journal_end to proceed while there are still writers in the log.
*/
-static int check_journal_end(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb,
- unsigned long nblocks, int flags) {
-
- time_t now ;
- int flush = flags & FLUSH_ALL ;
- int commit_now = flags & COMMIT_NOW ;
- int wait_on_commit = flags & WAIT ;
- struct reiserfs_journal_list *jl;
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
-
- BUG_ON (!th->t_trans_id);
-
- if (th->t_trans_id != journal->j_trans_id) {
- reiserfs_panic(th->t_super, "journal-1577: handle trans id %ld != current trans id %ld\n",
- th->t_trans_id, journal->j_trans_id);
- }
-
- journal->j_len_alloc -= (th->t_blocks_allocated - th->t_blocks_logged) ;
- if (atomic_read(&(journal->j_wcount)) > 0) { /* <= 0 is allowed. unmounting might not call begin */
- atomic_dec(&(journal->j_wcount)) ;
- }
-
- /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released
- ** will be dealt with by next transaction that actually writes something, but should be taken
- ** care of in this trans
- */
- if (journal->j_len == 0) {
- BUG();
- }
- /* if wcount > 0, and we are called to with flush or commit_now,
- ** we wait on j_join_wait. We will wake up when the last writer has
- ** finished the transaction, and started it on its way to the disk.
- ** Then, we flush the commit or journal list, and just return 0
- ** because the rest of journal end was already done for this transaction.
- */
- if (atomic_read(&(journal->j_wcount)) > 0) {
- if (flush || commit_now) {
- unsigned trans_id ;
-
- jl = journal->j_current_jl;
- trans_id = jl->j_trans_id;
- if (wait_on_commit)
- jl->j_state |= LIST_COMMIT_PENDING;
- atomic_set(&(journal->j_jlock), 1) ;
- if (flush) {
- journal->j_next_full_flush = 1 ;
- }
- unlock_journal(p_s_sb) ;
-
- /* sleep while the current transaction is still j_jlocked */
- while(journal->j_trans_id == trans_id) {
- if (atomic_read(&journal->j_jlock)) {
- queue_log_writer(p_s_sb);
- } else {
- lock_journal(p_s_sb);
- if (journal->j_trans_id == trans_id) {
- atomic_set(&(journal->j_jlock), 1) ;
- }
- unlock_journal(p_s_sb);
- }
- }
- if (journal->j_trans_id == trans_id) {
- BUG();
- }
- if (commit_now && journal_list_still_alive(p_s_sb, trans_id) &&
- wait_on_commit)
- {
- flush_commit_list(p_s_sb, jl, 1) ;
- }
- return 0 ;
- }
- unlock_journal(p_s_sb) ;
- return 0 ;
- }
-
- /* deal with old transactions where we are the last writers */
- now = get_seconds();
- if ((now - journal->j_trans_start_time) > journal->j_max_trans_age) {
- commit_now = 1 ;
- journal->j_next_async_flush = 1 ;
- }
- /* don't batch when someone is waiting on j_join_wait */
- /* don't batch when syncing the commit or flushing the whole trans */
- if (!(journal->j_must_wait > 0) && !(atomic_read(&(journal->j_jlock))) && !flush && !commit_now &&
- (journal->j_len < journal->j_max_batch) &&
- journal->j_len_alloc < journal->j_max_batch && journal->j_cnode_free > (journal->j_trans_max * 3)) {
- journal->j_bcount++ ;
- unlock_journal(p_s_sb) ;
- return 0 ;
- }
-
- if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
- reiserfs_panic(p_s_sb, "journal-003: journal_end: j_start (%ld) is too high\n", journal->j_start) ;
- }
- return 1 ;
+static int check_journal_end(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks,
+ int flags)
+{
+
+ time_t now;
+ int flush = flags & FLUSH_ALL;
+ int commit_now = flags & COMMIT_NOW;
+ int wait_on_commit = flags & WAIT;
+ struct reiserfs_journal_list *jl;
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+
+ BUG_ON(!th->t_trans_id);
+
+ if (th->t_trans_id != journal->j_trans_id) {
+ reiserfs_panic(th->t_super,
+ "journal-1577: handle trans id %ld != current trans id %ld\n",
+ th->t_trans_id, journal->j_trans_id);
+ }
+
+ journal->j_len_alloc -= (th->t_blocks_allocated - th->t_blocks_logged);
+ if (atomic_read(&(journal->j_wcount)) > 0) { /* <= 0 is allowed. unmounting might not call begin */
+ atomic_dec(&(journal->j_wcount));
+ }
+
+ /* BUG, deal with case where j_len is 0, but people previously freed blocks need to be released
+ ** will be dealt with by next transaction that actually writes something, but should be taken
+ ** care of in this trans
+ */
+ if (journal->j_len == 0) {
+ BUG();
+ }
+ /* if wcount > 0, and we are called to with flush or commit_now,
+ ** we wait on j_join_wait. We will wake up when the last writer has
+ ** finished the transaction, and started it on its way to the disk.
+ ** Then, we flush the commit or journal list, and just return 0
+ ** because the rest of journal end was already done for this transaction.
+ */
+ if (atomic_read(&(journal->j_wcount)) > 0) {
+ if (flush || commit_now) {
+ unsigned trans_id;
+
+ jl = journal->j_current_jl;
+ trans_id = jl->j_trans_id;
+ if (wait_on_commit)
+ jl->j_state |= LIST_COMMIT_PENDING;
+ atomic_set(&(journal->j_jlock), 1);
+ if (flush) {
+ journal->j_next_full_flush = 1;
+ }
+ unlock_journal(p_s_sb);
+
+ /* sleep while the current transaction is still j_jlocked */
+ while (journal->j_trans_id == trans_id) {
+ if (atomic_read(&journal->j_jlock)) {
+ queue_log_writer(p_s_sb);
+ } else {
+ lock_journal(p_s_sb);
+ if (journal->j_trans_id == trans_id) {
+ atomic_set(&(journal->j_jlock),
+ 1);
+ }
+ unlock_journal(p_s_sb);
+ }
+ }
+ if (journal->j_trans_id == trans_id) {
+ BUG();
+ }
+ if (commit_now
+ && journal_list_still_alive(p_s_sb, trans_id)
+ && wait_on_commit) {
+ flush_commit_list(p_s_sb, jl, 1);
+ }
+ return 0;
+ }
+ unlock_journal(p_s_sb);
+ return 0;
+ }
+
+ /* deal with old transactions where we are the last writers */
+ now = get_seconds();
+ if ((now - journal->j_trans_start_time) > journal->j_max_trans_age) {
+ commit_now = 1;
+ journal->j_next_async_flush = 1;
+ }
+ /* don't batch when someone is waiting on j_join_wait */
+ /* don't batch when syncing the commit or flushing the whole trans */
+ if (!(journal->j_must_wait > 0) && !(atomic_read(&(journal->j_jlock)))
+ && !flush && !commit_now && (journal->j_len < journal->j_max_batch)
+ && journal->j_len_alloc < journal->j_max_batch
+ && journal->j_cnode_free > (journal->j_trans_max * 3)) {
+ journal->j_bcount++;
+ unlock_journal(p_s_sb);
+ return 0;
+ }
+
+ if (journal->j_start > SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+ reiserfs_panic(p_s_sb,
+ "journal-003: journal_end: j_start (%ld) is too high\n",
+ journal->j_start);
+ }
+ return 1;
}
/*
@@ -3271,83 +3593,95 @@ static int check_journal_end(struct reiserfs_transaction_handle *th, struct supe
**
** Then remove it from the current transaction, decrementing any counters and filing it on the clean list.
*/
-int journal_mark_freed(struct reiserfs_transaction_handle *th, struct super_block *p_s_sb, b_blocknr_t blocknr) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_cnode *cn = NULL ;
- struct buffer_head *bh = NULL ;
- struct reiserfs_list_bitmap *jb = NULL ;
- int cleaned = 0 ;
- BUG_ON (!th->t_trans_id);
-
- cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
- if (cn && cn->bh) {
- bh = cn->bh ;
- get_bh(bh) ;
- }
- /* if it is journal new, we just remove it from this transaction */
- if (bh && buffer_journal_new(bh)) {
- clear_buffer_journal_new (bh);
- clear_prepared_bits(bh) ;
- reiserfs_clean_and_file_buffer(bh) ;
- cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
- } else {
- /* set the bit for this block in the journal bitmap for this transaction */
- jb = journal->j_current_jl->j_list_bitmap;
- if (!jb) {
- reiserfs_panic(p_s_sb, "journal-1702: journal_mark_freed, journal_list_bitmap is NULL\n") ;
- }
- set_bit_in_list_bitmap(p_s_sb, blocknr, jb) ;
-
- /* Note, the entire while loop is not allowed to schedule. */
-
- if (bh) {
- clear_prepared_bits(bh) ;
- reiserfs_clean_and_file_buffer(bh) ;
- }
- cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned) ;
-
- /* find all older transactions with this block, make sure they don't try to write it out */
- cn = get_journal_hash_dev(p_s_sb,journal->j_list_hash_table, blocknr) ;
- while (cn) {
- if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
- set_bit(BLOCK_FREED, &cn->state) ;
- if (cn->bh) {
- if (!cleaned) {
- /* remove_from_transaction will brelse the buffer if it was
- ** in the current trans
- */
- clear_buffer_journal_dirty (cn->bh);
- clear_buffer_dirty(cn->bh);
- clear_buffer_journal_test(cn->bh);
- cleaned = 1 ;
- put_bh(cn->bh) ;
- if (atomic_read(&(cn->bh->b_count)) < 0) {
- reiserfs_warning (p_s_sb, "journal-2138: cn->bh->b_count < 0");
- }
- }
- if (cn->jlist) { /* since we are clearing the bh, we MUST dec nonzerolen */
- atomic_dec(&(cn->jlist->j_nonzerolen)) ;
- }
- cn->bh = NULL ;
- }
- }
- cn = cn->hnext ;
- }
- }
-
- if (bh) {
- put_bh(bh) ; /* get_hash grabs the buffer */
- if (atomic_read(&(bh->b_count)) < 0) {
- reiserfs_warning (p_s_sb, "journal-2165: bh->b_count < 0");
- }
- }
- return 0 ;
-}
-
-void reiserfs_update_inode_transaction(struct inode *inode) {
- struct reiserfs_journal *journal = SB_JOURNAL (inode->i_sb);
- REISERFS_I(inode)->i_jl = journal->j_current_jl;
- REISERFS_I(inode)->i_trans_id = journal->j_trans_id ;
+int journal_mark_freed(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, b_blocknr_t blocknr)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_cnode *cn = NULL;
+ struct buffer_head *bh = NULL;
+ struct reiserfs_list_bitmap *jb = NULL;
+ int cleaned = 0;
+ BUG_ON(!th->t_trans_id);
+
+ cn = get_journal_hash_dev(p_s_sb, journal->j_hash_table, blocknr);
+ if (cn && cn->bh) {
+ bh = cn->bh;
+ get_bh(bh);
+ }
+ /* if it is journal new, we just remove it from this transaction */
+ if (bh && buffer_journal_new(bh)) {
+ clear_buffer_journal_new(bh);
+ clear_prepared_bits(bh);
+ reiserfs_clean_and_file_buffer(bh);
+ cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned);
+ } else {
+ /* set the bit for this block in the journal bitmap for this transaction */
+ jb = journal->j_current_jl->j_list_bitmap;
+ if (!jb) {
+ reiserfs_panic(p_s_sb,
+ "journal-1702: journal_mark_freed, journal_list_bitmap is NULL\n");
+ }
+ set_bit_in_list_bitmap(p_s_sb, blocknr, jb);
+
+ /* Note, the entire while loop is not allowed to schedule. */
+
+ if (bh) {
+ clear_prepared_bits(bh);
+ reiserfs_clean_and_file_buffer(bh);
+ }
+ cleaned = remove_from_transaction(p_s_sb, blocknr, cleaned);
+
+ /* find all older transactions with this block, make sure they don't try to write it out */
+ cn = get_journal_hash_dev(p_s_sb, journal->j_list_hash_table,
+ blocknr);
+ while (cn) {
+ if (p_s_sb == cn->sb && blocknr == cn->blocknr) {
+ set_bit(BLOCK_FREED, &cn->state);
+ if (cn->bh) {
+ if (!cleaned) {
+ /* remove_from_transaction will brelse the buffer if it was
+ ** in the current trans
+ */
+ clear_buffer_journal_dirty(cn->
+ bh);
+ clear_buffer_dirty(cn->bh);
+ clear_buffer_journal_test(cn->
+ bh);
+ cleaned = 1;
+ put_bh(cn->bh);
+ if (atomic_read
+ (&(cn->bh->b_count)) < 0) {
+ reiserfs_warning(p_s_sb,
+ "journal-2138: cn->bh->b_count < 0");
+ }
+ }
+ if (cn->jlist) { /* since we are clearing the bh, we MUST dec nonzerolen */
+ atomic_dec(&
+ (cn->jlist->
+ j_nonzerolen));
+ }
+ cn->bh = NULL;
+ }
+ }
+ cn = cn->hnext;
+ }
+ }
+
+ if (bh) {
+ put_bh(bh); /* get_hash grabs the buffer */
+ if (atomic_read(&(bh->b_count)) < 0) {
+ reiserfs_warning(p_s_sb,
+ "journal-2165: bh->b_count < 0");
+ }
+ }
+ return 0;
+}
+
+void reiserfs_update_inode_transaction(struct inode *inode)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(inode->i_sb);
+ REISERFS_I(inode)->i_jl = journal->j_current_jl;
+ REISERFS_I(inode)->i_trans_id = journal->j_trans_id;
}
/*
@@ -3355,99 +3689,102 @@ void reiserfs_update_inode_transaction(struct inode *inode) {
* if a transaction was actually committed and the barrier was done
*/
static int __commit_trans_jl(struct inode *inode, unsigned long id,
- struct reiserfs_journal_list *jl)
+ struct reiserfs_journal_list *jl)
{
- struct reiserfs_transaction_handle th ;
- struct super_block *sb = inode->i_sb ;
- struct reiserfs_journal *journal = SB_JOURNAL (sb);
- int ret = 0;
+ struct reiserfs_transaction_handle th;
+ struct super_block *sb = inode->i_sb;
+ struct reiserfs_journal *journal = SB_JOURNAL(sb);
+ int ret = 0;
+
+ /* is it from the current transaction, or from an unknown transaction? */
+ if (id == journal->j_trans_id) {
+ jl = journal->j_current_jl;
+ /* try to let other writers come in and grow this transaction */
+ let_transaction_grow(sb, id);
+ if (journal->j_trans_id != id) {
+ goto flush_commit_only;
+ }
- /* is it from the current transaction, or from an unknown transaction? */
- if (id == journal->j_trans_id) {
- jl = journal->j_current_jl;
- /* try to let other writers come in and grow this transaction */
- let_transaction_grow(sb, id);
- if (journal->j_trans_id != id) {
- goto flush_commit_only;
- }
+ ret = journal_begin(&th, sb, 1);
+ if (ret)
+ return ret;
+
+ /* someone might have ended this transaction while we joined */
+ if (journal->j_trans_id != id) {
+ reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb),
+ 1);
+ journal_mark_dirty(&th, sb, SB_BUFFER_WITH_SB(sb));
+ ret = journal_end(&th, sb, 1);
+ goto flush_commit_only;
+ }
- ret = journal_begin(&th, sb, 1) ;
- if (ret)
- return ret;
+ ret = journal_end_sync(&th, sb, 1);
+ if (!ret)
+ ret = 1;
- /* someone might have ended this transaction while we joined */
- if (journal->j_trans_id != id) {
- reiserfs_prepare_for_journal(sb, SB_BUFFER_WITH_SB(sb), 1) ;
- journal_mark_dirty(&th, sb, SB_BUFFER_WITH_SB(sb)) ;
- ret = journal_end(&th, sb, 1) ;
- goto flush_commit_only;
+ } else {
+ /* this gets tricky, we have to make sure the journal list in
+ * the inode still exists. We know the list is still around
+ * if we've got a larger transaction id than the oldest list
+ */
+ flush_commit_only:
+ if (journal_list_still_alive(inode->i_sb, id)) {
+ /*
+ * we only set ret to 1 when we know for sure
+ * the barrier hasn't been started yet on the commit
+ * block.
+ */
+ if (atomic_read(&jl->j_commit_left) > 1)
+ ret = 1;
+ flush_commit_list(sb, jl, 1);
+ if (journal->j_errno)
+ ret = journal->j_errno;
+ }
}
+ /* otherwise the list is gone, and long since committed */
+ return ret;
+}
- ret = journal_end_sync(&th, sb, 1) ;
- if (!ret)
- ret = 1;
+int reiserfs_commit_for_inode(struct inode *inode)
+{
+ unsigned long id = REISERFS_I(inode)->i_trans_id;
+ struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
- } else {
- /* this gets tricky, we have to make sure the journal list in
- * the inode still exists. We know the list is still around
- * if we've got a larger transaction id than the oldest list
+ /* for the whole inode, assume unset id means it was
+ * changed in the current transaction. More conservative
*/
-flush_commit_only:
- if (journal_list_still_alive(inode->i_sb, id)) {
- /*
- * we only set ret to 1 when we know for sure
- * the barrier hasn't been started yet on the commit
- * block.
- */
- if (atomic_read(&jl->j_commit_left) > 1)
- ret = 1;
- flush_commit_list(sb, jl, 1) ;
- if (journal->j_errno)
- ret = journal->j_errno;
- }
- }
- /* otherwise the list is gone, and long since committed */
- return ret;
-}
-
-int reiserfs_commit_for_inode(struct inode *inode) {
- unsigned long id = REISERFS_I(inode)->i_trans_id;
- struct reiserfs_journal_list *jl = REISERFS_I(inode)->i_jl;
-
- /* for the whole inode, assume unset id means it was
- * changed in the current transaction. More conservative
- */
- if (!id || !jl) {
- reiserfs_update_inode_transaction(inode) ;
- id = REISERFS_I(inode)->i_trans_id;
- /* jl will be updated in __commit_trans_jl */
- }
-
- return __commit_trans_jl(inode, id, jl);
-}
-
-void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb,
- struct buffer_head *bh) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- PROC_INFO_INC( p_s_sb, journal.restore_prepared );
- if (!bh) {
- return ;
- }
- if (test_clear_buffer_journal_restore_dirty (bh) &&
- buffer_journal_dirty(bh)) {
- struct reiserfs_journal_cnode *cn;
- cn = get_journal_hash_dev(p_s_sb,
- journal->j_list_hash_table,
- bh->b_blocknr);
- if (cn && can_dirty(cn)) {
- set_buffer_journal_test (bh);
- mark_buffer_dirty(bh);
- }
- }
- clear_buffer_journal_prepared (bh);
-}
-
-extern struct tree_balance *cur_tb ;
+ if (!id || !jl) {
+ reiserfs_update_inode_transaction(inode);
+ id = REISERFS_I(inode)->i_trans_id;
+ /* jl will be updated in __commit_trans_jl */
+ }
+
+ return __commit_trans_jl(inode, id, jl);
+}
+
+void reiserfs_restore_prepared_buffer(struct super_block *p_s_sb,
+ struct buffer_head *bh)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ PROC_INFO_INC(p_s_sb, journal.restore_prepared);
+ if (!bh) {
+ return;
+ }
+ if (test_clear_buffer_journal_restore_dirty(bh) &&
+ buffer_journal_dirty(bh)) {
+ struct reiserfs_journal_cnode *cn;
+ cn = get_journal_hash_dev(p_s_sb,
+ journal->j_list_hash_table,
+ bh->b_blocknr);
+ if (cn && can_dirty(cn)) {
+ set_buffer_journal_test(bh);
+ mark_buffer_dirty(bh);
+ }
+ }
+ clear_buffer_journal_prepared(bh);
+}
+
+extern struct tree_balance *cur_tb;
/*
** before we can change a metadata block, we have to make sure it won't
** be written to disk while we are altering it. So, we must:
@@ -3456,39 +3793,41 @@ extern struct tree_balance *cur_tb ;
**
*/
int reiserfs_prepare_for_journal(struct super_block *p_s_sb,
- struct buffer_head *bh, int wait) {
- PROC_INFO_INC( p_s_sb, journal.prepare );
-
- if (test_set_buffer_locked(bh)) {
- if (!wait)
- return 0;
- lock_buffer(bh);
- }
- set_buffer_journal_prepared (bh);
- if (test_clear_buffer_dirty(bh) && buffer_journal_dirty(bh)) {
- clear_buffer_journal_test (bh);
- set_buffer_journal_restore_dirty (bh);
- }
- unlock_buffer(bh);
- return 1;
-}
-
-static void flush_old_journal_lists(struct super_block *s) {
- struct reiserfs_journal *journal = SB_JOURNAL (s);
- struct reiserfs_journal_list *jl;
- struct list_head *entry;
- time_t now = get_seconds();
-
- while(!list_empty(&journal->j_journal_list)) {
- entry = journal->j_journal_list.next;
- jl = JOURNAL_LIST_ENTRY(entry);
- /* this check should always be run, to send old lists to disk */
- if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4))) {
- flush_used_journal_lists(s, jl);
- } else {
- break;
+ struct buffer_head *bh, int wait)
+{
+ PROC_INFO_INC(p_s_sb, journal.prepare);
+
+ if (test_set_buffer_locked(bh)) {
+ if (!wait)
+ return 0;
+ lock_buffer(bh);
+ }
+ set_buffer_journal_prepared(bh);
+ if (test_clear_buffer_dirty(bh) && buffer_journal_dirty(bh)) {
+ clear_buffer_journal_test(bh);
+ set_buffer_journal_restore_dirty(bh);
+ }
+ unlock_buffer(bh);
+ return 1;
+}
+
+static void flush_old_journal_lists(struct super_block *s)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ struct reiserfs_journal_list *jl;
+ struct list_head *entry;
+ time_t now = get_seconds();
+
+ while (!list_empty(&journal->j_journal_list)) {
+ entry = journal->j_journal_list.next;
+ jl = JOURNAL_LIST_ENTRY(entry);
+ /* this check should always be run, to send old lists to disk */
+ if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4))) {
+ flush_used_journal_lists(s, jl);
+ } else {
+ break;
+ }
}
- }
}
/*
@@ -3501,374 +3840,390 @@ static void flush_old_journal_lists(struct super_block *s) {
** If the journal is aborted, we just clean up. Things like flushing
** journal lists, etc just won't happen.
*/
-static int do_journal_end(struct reiserfs_transaction_handle *th, struct super_block * p_s_sb, unsigned long nblocks,
- int flags) {
- struct reiserfs_journal *journal = SB_JOURNAL (p_s_sb);
- struct reiserfs_journal_cnode *cn, *next, *jl_cn;
- struct reiserfs_journal_cnode *last_cn = NULL;
- struct reiserfs_journal_desc *desc ;
- struct reiserfs_journal_commit *commit ;
- struct buffer_head *c_bh ; /* commit bh */
- struct buffer_head *d_bh ; /* desc bh */
- int cur_write_start = 0 ; /* start index of current log write */
- int old_start ;
- int i ;
- int flush = flags & FLUSH_ALL ;
- int wait_on_commit = flags & WAIT ;
- struct reiserfs_journal_list *jl, *temp_jl;
- struct list_head *entry, *safe;
- unsigned long jindex;
- unsigned long commit_trans_id;
- int trans_half;
-
- BUG_ON (th->t_refcount > 1);
- BUG_ON (!th->t_trans_id);
-
- current->journal_info = th->t_handle_save;
- reiserfs_check_lock_depth(p_s_sb, "journal end");
- if (journal->j_len == 0) {
- reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb), 1) ;
- journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb)) ;
- }
-
- lock_journal(p_s_sb) ;
- if (journal->j_next_full_flush) {
- flags |= FLUSH_ALL ;
- flush = 1 ;
- }
- if (journal->j_next_async_flush) {
- flags |= COMMIT_NOW | WAIT;
- wait_on_commit = 1;
- }
-
- /* check_journal_end locks the journal, and unlocks if it does not return 1
- ** it tells us if we should continue with the journal_end, or just return
- */
- if (!check_journal_end(th, p_s_sb, nblocks, flags)) {
- p_s_sb->s_dirt = 1;
- wake_queued_writers(p_s_sb);
- reiserfs_async_progress_wait(p_s_sb);
- goto out ;
- }
-
- /* check_journal_end might set these, check again */
- if (journal->j_next_full_flush) {
- flush = 1 ;
- }
-
- /*
- ** j must wait means we have to flush the log blocks, and the real blocks for
- ** this transaction
- */
- if (journal->j_must_wait > 0) {
- flush = 1 ;
- }
+static int do_journal_end(struct reiserfs_transaction_handle *th,
+ struct super_block *p_s_sb, unsigned long nblocks,
+ int flags)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(p_s_sb);
+ struct reiserfs_journal_cnode *cn, *next, *jl_cn;
+ struct reiserfs_journal_cnode *last_cn = NULL;
+ struct reiserfs_journal_desc *desc;
+ struct reiserfs_journal_commit *commit;
+ struct buffer_head *c_bh; /* commit bh */
+ struct buffer_head *d_bh; /* desc bh */
+ int cur_write_start = 0; /* start index of current log write */
+ int old_start;
+ int i;
+ int flush = flags & FLUSH_ALL;
+ int wait_on_commit = flags & WAIT;
+ struct reiserfs_journal_list *jl, *temp_jl;
+ struct list_head *entry, *safe;
+ unsigned long jindex;
+ unsigned long commit_trans_id;
+ int trans_half;
+
+ BUG_ON(th->t_refcount > 1);
+ BUG_ON(!th->t_trans_id);
+
+ put_fs_excl();
+ current->journal_info = th->t_handle_save;
+ reiserfs_check_lock_depth(p_s_sb, "journal end");
+ if (journal->j_len == 0) {
+ reiserfs_prepare_for_journal(p_s_sb, SB_BUFFER_WITH_SB(p_s_sb),
+ 1);
+ journal_mark_dirty(th, p_s_sb, SB_BUFFER_WITH_SB(p_s_sb));
+ }
+ lock_journal(p_s_sb);
+ if (journal->j_next_full_flush) {
+ flags |= FLUSH_ALL;
+ flush = 1;
+ }
+ if (journal->j_next_async_flush) {
+ flags |= COMMIT_NOW | WAIT;
+ wait_on_commit = 1;
+ }
+
+ /* check_journal_end locks the journal, and unlocks if it does not return 1
+ ** it tells us if we should continue with the journal_end, or just return
+ */
+ if (!check_journal_end(th, p_s_sb, nblocks, flags)) {
+ p_s_sb->s_dirt = 1;
+ wake_queued_writers(p_s_sb);
+ reiserfs_async_progress_wait(p_s_sb);
+ goto out;
+ }
+
+ /* check_journal_end might set these, check again */
+ if (journal->j_next_full_flush) {
+ flush = 1;
+ }
+
+ /*
+ ** j must wait means we have to flush the log blocks, and the real blocks for
+ ** this transaction
+ */
+ if (journal->j_must_wait > 0) {
+ flush = 1;
+ }
#ifdef REISERFS_PREALLOCATE
- /* quota ops might need to nest, setup the journal_info pointer for them */
- current->journal_info = th ;
- reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into
- * the transaction */
- current->journal_info = th->t_handle_save ;
+ /* quota ops might need to nest, setup the journal_info pointer for them */
+ current->journal_info = th;
+ reiserfs_discard_all_prealloc(th); /* it should not involve new blocks into
+ * the transaction */
+ current->journal_info = th->t_handle_save;
#endif
-
- /* setup description block */
- d_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + journal->j_start) ;
- set_buffer_uptodate(d_bh);
- desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ;
- memset(d_bh->b_data, 0, d_bh->b_size) ;
- memcpy(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8) ;
- set_desc_trans_id(desc, journal->j_trans_id) ;
-
- /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */
- c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((journal->j_start + journal->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- commit = (struct reiserfs_journal_commit *)c_bh->b_data ;
- memset(c_bh->b_data, 0, c_bh->b_size) ;
- set_commit_trans_id(commit, journal->j_trans_id) ;
- set_buffer_uptodate(c_bh) ;
-
- /* init this journal list */
- jl = journal->j_current_jl;
-
- /* we lock the commit before doing anything because
- * we want to make sure nobody tries to run flush_commit_list until
- * the new transaction is fully setup, and we've already flushed the
- * ordered bh list
- */
- down(&jl->j_commit_lock);
-
- /* save the transaction id in case we need to commit it later */
- commit_trans_id = jl->j_trans_id;
-
- atomic_set(&jl->j_older_commits_done, 0) ;
- jl->j_trans_id = journal->j_trans_id ;
- jl->j_timestamp = journal->j_trans_start_time ;
- jl->j_commit_bh = c_bh ;
- jl->j_start = journal->j_start ;
- jl->j_len = journal->j_len ;
- atomic_set(&jl->j_nonzerolen, journal->j_len) ;
- atomic_set(&jl->j_commit_left, journal->j_len + 2);
- jl->j_realblock = NULL ;
-
- /* The ENTIRE FOR LOOP MUST not cause schedule to occur.
- ** for each real block, add it to the journal list hash,
- ** copy into real block index array in the commit or desc block
- */
- trans_half = journal_trans_half(p_s_sb->s_blocksize);
- for (i = 0, cn = journal->j_first ; cn ; cn = cn->next, i++) {
- if (buffer_journaled (cn->bh)) {
- jl_cn = get_cnode(p_s_sb) ;
- if (!jl_cn) {
- reiserfs_panic(p_s_sb, "journal-1676, get_cnode returned NULL\n") ;
- }
- if (i == 0) {
- jl->j_realblock = jl_cn ;
- }
- jl_cn->prev = last_cn ;
- jl_cn->next = NULL ;
- if (last_cn) {
- last_cn->next = jl_cn ;
- }
- last_cn = jl_cn ;
- /* make sure the block we are trying to log is not a block
- of journal or reserved area */
-
- if (is_block_in_log_or_reserved_area(p_s_sb, cn->bh->b_blocknr)) {
- reiserfs_panic(p_s_sb, "journal-2332: Trying to log block %lu, which is a log block\n", cn->bh->b_blocknr) ;
- }
- jl_cn->blocknr = cn->bh->b_blocknr ;
- jl_cn->state = 0 ;
- jl_cn->sb = p_s_sb;
- jl_cn->bh = cn->bh ;
- jl_cn->jlist = jl;
- insert_journal_hash(journal->j_list_hash_table, jl_cn) ;
- if (i < trans_half) {
- desc->j_realblock[i] = cpu_to_le32(cn->bh->b_blocknr) ;
- } else {
- commit->j_realblock[i - trans_half] = cpu_to_le32(cn->bh->b_blocknr) ;
- }
- } else {
- i-- ;
- }
- }
- set_desc_trans_len(desc, journal->j_len) ;
- set_desc_mount_id(desc, journal->j_mount_id) ;
- set_desc_trans_id(desc, journal->j_trans_id) ;
- set_commit_trans_len(commit, journal->j_len);
-
- /* special check in case all buffers in the journal were marked for not logging */
- if (journal->j_len == 0) {
- BUG();
- }
-
- /* we're about to dirty all the log blocks, mark the description block
- * dirty now too. Don't mark the commit block dirty until all the
- * others are on disk
- */
- mark_buffer_dirty(d_bh);
-
- /* first data block is j_start + 1, so add one to cur_write_start wherever you use it */
- cur_write_start = journal->j_start ;
- cn = journal->j_first ;
- jindex = 1 ; /* start at one so we don't get the desc again */
- while(cn) {
- clear_buffer_journal_new (cn->bh);
- /* copy all the real blocks into log area. dirty log blocks */
- if (buffer_journaled (cn->bh)) {
- struct buffer_head *tmp_bh ;
- char *addr;
- struct page *page;
- tmp_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
- ((cur_write_start + jindex) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ;
- set_buffer_uptodate(tmp_bh);
- page = cn->bh->b_page;
- addr = kmap(page);
- memcpy(tmp_bh->b_data, addr + offset_in_page(cn->bh->b_data),
- cn->bh->b_size);
- kunmap(page);
- mark_buffer_dirty(tmp_bh);
- jindex++ ;
- set_buffer_journal_dirty (cn->bh);
- clear_buffer_journaled (cn->bh);
- } else {
- /* JDirty cleared sometime during transaction. don't log this one */
- reiserfs_warning(p_s_sb, "journal-2048: do_journal_end: BAD, buffer in journal hash, but not JDirty!") ;
- brelse(cn->bh) ;
- }
- next = cn->next ;
- free_cnode(p_s_sb, cn) ;
- cn = next ;
- cond_resched();
- }
-
- /* we are done with both the c_bh and d_bh, but
- ** c_bh must be written after all other commit blocks,
- ** so we dirty/relse c_bh in flush_commit_list, with commit_left <= 1.
- */
-
- journal->j_current_jl = alloc_journal_list(p_s_sb);
-
- /* now it is safe to insert this transaction on the main list */
- list_add_tail(&jl->j_list, &journal->j_journal_list);
- list_add_tail(&jl->j_working_list, &journal->j_working_list);
- journal->j_num_work_lists++;
-
- /* reset journal values for the next transaction */
- old_start = journal->j_start ;
- journal->j_start = (journal->j_start + journal->j_len + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb);
- atomic_set(&(journal->j_wcount), 0) ;
- journal->j_bcount = 0 ;
- journal->j_last = NULL ;
- journal->j_first = NULL ;
- journal->j_len = 0 ;
- journal->j_trans_start_time = 0 ;
- journal->j_trans_id++ ;
- journal->j_current_jl->j_trans_id = journal->j_trans_id;
- journal->j_must_wait = 0 ;
- journal->j_len_alloc = 0 ;
- journal->j_next_full_flush = 0 ;
- journal->j_next_async_flush = 0 ;
- init_journal_hash(p_s_sb) ;
-
- // make sure reiserfs_add_jh sees the new current_jl before we
- // write out the tails
- smp_mb();
-
- /* tail conversion targets have to hit the disk before we end the
- * transaction. Otherwise a later transaction might repack the tail
- * before this transaction commits, leaving the data block unflushed and
- * clean, if we crash before the later transaction commits, the data block
- * is lost.
- */
- if (!list_empty(&jl->j_tail_bh_list)) {
- unlock_kernel();
- write_ordered_buffers(&journal->j_dirty_buffers_lock,
- journal, jl, &jl->j_tail_bh_list);
- lock_kernel();
- }
- if (!list_empty(&jl->j_tail_bh_list))
- BUG();
- up(&jl->j_commit_lock);
-
- /* honor the flush wishes from the caller, simple commits can
- ** be done outside the journal lock, they are done below
- **
- ** if we don't flush the commit list right now, we put it into
- ** the work queue so the people waiting on the async progress work
- ** queue don't wait for this proc to flush journal lists and such.
- */
- if (flush) {
- flush_commit_list(p_s_sb, jl, 1) ;
- flush_journal_list(p_s_sb, jl, 1) ;
- } else if (!(jl->j_state & LIST_COMMIT_PENDING))
- queue_delayed_work(commit_wq, &journal->j_work, HZ/10);
-
-
- /* if the next transaction has any chance of wrapping, flush
- ** transactions that might get overwritten. If any journal lists are very
- ** old flush them as well.
- */
-first_jl:
- list_for_each_safe(entry, safe, &journal->j_journal_list) {
- temp_jl = JOURNAL_LIST_ENTRY(entry);
- if (journal->j_start <= temp_jl->j_start) {
- if ((journal->j_start + journal->j_trans_max + 1) >=
- temp_jl->j_start)
- {
- flush_used_journal_lists(p_s_sb, temp_jl);
- goto first_jl;
- } else if ((journal->j_start +
- journal->j_trans_max + 1) <
- SB_ONDISK_JOURNAL_SIZE(p_s_sb))
- {
- /* if we don't cross into the next transaction and we don't
- * wrap, there is no way we can overlap any later transactions
- * break now
- */
- break;
- }
- } else if ((journal->j_start +
- journal->j_trans_max + 1) >
- SB_ONDISK_JOURNAL_SIZE(p_s_sb))
- {
- if (((journal->j_start + journal->j_trans_max + 1) %
- SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >= temp_jl->j_start)
- {
- flush_used_journal_lists(p_s_sb, temp_jl);
- goto first_jl;
- } else {
- /* we don't overlap anything from out start to the end of the
- * log, and our wrapped portion doesn't overlap anything at
- * the start of the log. We can break
- */
- break;
- }
- }
- }
- flush_old_journal_lists(p_s_sb);
-
- journal->j_current_jl->j_list_bitmap = get_list_bitmap(p_s_sb, journal->j_current_jl) ;
-
- if (!(journal->j_current_jl->j_list_bitmap)) {
- reiserfs_panic(p_s_sb, "journal-1996: do_journal_end, could not get a list bitmap\n") ;
- }
-
- atomic_set(&(journal->j_jlock), 0) ;
- unlock_journal(p_s_sb) ;
- /* wake up any body waiting to join. */
- clear_bit(J_WRITERS_QUEUED, &journal->j_state);
- wake_up(&(journal->j_join_wait)) ;
-
- if (!flush && wait_on_commit &&
- journal_list_still_alive(p_s_sb, commit_trans_id)) {
- flush_commit_list(p_s_sb, jl, 1) ;
- }
-out:
- reiserfs_check_lock_depth(p_s_sb, "journal end2");
-
- memset (th, 0, sizeof (*th));
- /* Re-set th->t_super, so we can properly keep track of how many
- * persistent transactions there are. We need to do this so if this
- * call is part of a failed restart_transaction, we can free it later */
- th->t_super = p_s_sb;
-
- return journal->j_errno;
-}
-
-static void
-__reiserfs_journal_abort_hard (struct super_block *sb)
-{
- struct reiserfs_journal *journal = SB_JOURNAL (sb);
- if (test_bit (J_ABORTED, &journal->j_state))
- return;
-
- printk (KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n",
- reiserfs_bdevname (sb));
-
- sb->s_flags |= MS_RDONLY;
- set_bit (J_ABORTED, &journal->j_state);
+
+ /* setup description block */
+ d_bh =
+ journal_getblk(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ journal->j_start);
+ set_buffer_uptodate(d_bh);
+ desc = (struct reiserfs_journal_desc *)(d_bh)->b_data;
+ memset(d_bh->b_data, 0, d_bh->b_size);
+ memcpy(get_journal_desc_magic(d_bh), JOURNAL_DESC_MAGIC, 8);
+ set_desc_trans_id(desc, journal->j_trans_id);
+
+ /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */
+ c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ ((journal->j_start + journal->j_len +
+ 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+ commit = (struct reiserfs_journal_commit *)c_bh->b_data;
+ memset(c_bh->b_data, 0, c_bh->b_size);
+ set_commit_trans_id(commit, journal->j_trans_id);
+ set_buffer_uptodate(c_bh);
+
+ /* init this journal list */
+ jl = journal->j_current_jl;
+
+ /* we lock the commit before doing anything because
+ * we want to make sure nobody tries to run flush_commit_list until
+ * the new transaction is fully setup, and we've already flushed the
+ * ordered bh list
+ */
+ down(&jl->j_commit_lock);
+
+ /* save the transaction id in case we need to commit it later */
+ commit_trans_id = jl->j_trans_id;
+
+ atomic_set(&jl->j_older_commits_done, 0);
+ jl->j_trans_id = journal->j_trans_id;
+ jl->j_timestamp = journal->j_trans_start_time;
+ jl->j_commit_bh = c_bh;
+ jl->j_start = journal->j_start;
+ jl->j_len = journal->j_len;
+ atomic_set(&jl->j_nonzerolen, journal->j_len);
+ atomic_set(&jl->j_commit_left, journal->j_len + 2);
+ jl->j_realblock = NULL;
+
+ /* The ENTIRE FOR LOOP MUST not cause schedule to occur.
+ ** for each real block, add it to the journal list hash,
+ ** copy into real block index array in the commit or desc block
+ */
+ trans_half = journal_trans_half(p_s_sb->s_blocksize);
+ for (i = 0, cn = journal->j_first; cn; cn = cn->next, i++) {
+ if (buffer_journaled(cn->bh)) {
+ jl_cn = get_cnode(p_s_sb);
+ if (!jl_cn) {
+ reiserfs_panic(p_s_sb,
+ "journal-1676, get_cnode returned NULL\n");
+ }
+ if (i == 0) {
+ jl->j_realblock = jl_cn;
+ }
+ jl_cn->prev = last_cn;
+ jl_cn->next = NULL;
+ if (last_cn) {
+ last_cn->next = jl_cn;
+ }
+ last_cn = jl_cn;
+ /* make sure the block we are trying to log is not a block
+ of journal or reserved area */
+
+ if (is_block_in_log_or_reserved_area
+ (p_s_sb, cn->bh->b_blocknr)) {
+ reiserfs_panic(p_s_sb,
+ "journal-2332: Trying to log block %lu, which is a log block\n",
+ cn->bh->b_blocknr);
+ }
+ jl_cn->blocknr = cn->bh->b_blocknr;
+ jl_cn->state = 0;
+ jl_cn->sb = p_s_sb;
+ jl_cn->bh = cn->bh;
+ jl_cn->jlist = jl;
+ insert_journal_hash(journal->j_list_hash_table, jl_cn);
+ if (i < trans_half) {
+ desc->j_realblock[i] =
+ cpu_to_le32(cn->bh->b_blocknr);
+ } else {
+ commit->j_realblock[i - trans_half] =
+ cpu_to_le32(cn->bh->b_blocknr);
+ }
+ } else {
+ i--;
+ }
+ }
+ set_desc_trans_len(desc, journal->j_len);
+ set_desc_mount_id(desc, journal->j_mount_id);
+ set_desc_trans_id(desc, journal->j_trans_id);
+ set_commit_trans_len(commit, journal->j_len);
+
+ /* special check in case all buffers in the journal were marked for not logging */
+ if (journal->j_len == 0) {
+ BUG();
+ }
+
+ /* we're about to dirty all the log blocks, mark the description block
+ * dirty now too. Don't mark the commit block dirty until all the
+ * others are on disk
+ */
+ mark_buffer_dirty(d_bh);
+
+ /* first data block is j_start + 1, so add one to cur_write_start wherever you use it */
+ cur_write_start = journal->j_start;
+ cn = journal->j_first;
+ jindex = 1; /* start at one so we don't get the desc again */
+ while (cn) {
+ clear_buffer_journal_new(cn->bh);
+ /* copy all the real blocks into log area. dirty log blocks */
+ if (buffer_journaled(cn->bh)) {
+ struct buffer_head *tmp_bh;
+ char *addr;
+ struct page *page;
+ tmp_bh =
+ journal_getblk(p_s_sb,
+ SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) +
+ ((cur_write_start +
+ jindex) %
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)));
+ set_buffer_uptodate(tmp_bh);
+ page = cn->bh->b_page;
+ addr = kmap(page);
+ memcpy(tmp_bh->b_data,
+ addr + offset_in_page(cn->bh->b_data),
+ cn->bh->b_size);
+ kunmap(page);
+ mark_buffer_dirty(tmp_bh);
+ jindex++;
+ set_buffer_journal_dirty(cn->bh);
+ clear_buffer_journaled(cn->bh);
+ } else {
+ /* JDirty cleared sometime during transaction. don't log this one */
+ reiserfs_warning(p_s_sb,
+ "journal-2048: do_journal_end: BAD, buffer in journal hash, but not JDirty!");
+ brelse(cn->bh);
+ }
+ next = cn->next;
+ free_cnode(p_s_sb, cn);
+ cn = next;
+ cond_resched();
+ }
+
+ /* we are done with both the c_bh and d_bh, but
+ ** c_bh must be written after all other commit blocks,
+ ** so we dirty/relse c_bh in flush_commit_list, with commit_left <= 1.
+ */
+
+ journal->j_current_jl = alloc_journal_list(p_s_sb);
+
+ /* now it is safe to insert this transaction on the main list */
+ list_add_tail(&jl->j_list, &journal->j_journal_list);
+ list_add_tail(&jl->j_working_list, &journal->j_working_list);
+ journal->j_num_work_lists++;
+
+ /* reset journal values for the next transaction */
+ old_start = journal->j_start;
+ journal->j_start =
+ (journal->j_start + journal->j_len +
+ 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb);
+ atomic_set(&(journal->j_wcount), 0);
+ journal->j_bcount = 0;
+ journal->j_last = NULL;
+ journal->j_first = NULL;
+ journal->j_len = 0;
+ journal->j_trans_start_time = 0;
+ journal->j_trans_id++;
+ journal->j_current_jl->j_trans_id = journal->j_trans_id;
+ journal->j_must_wait = 0;
+ journal->j_len_alloc = 0;
+ journal->j_next_full_flush = 0;
+ journal->j_next_async_flush = 0;
+ init_journal_hash(p_s_sb);
+
+ // make sure reiserfs_add_jh sees the new current_jl before we
+ // write out the tails
+ smp_mb();
+
+ /* tail conversion targets have to hit the disk before we end the
+ * transaction. Otherwise a later transaction might repack the tail
+ * before this transaction commits, leaving the data block unflushed and
+ * clean, if we crash before the later transaction commits, the data block
+ * is lost.
+ */
+ if (!list_empty(&jl->j_tail_bh_list)) {
+ unlock_kernel();
+ write_ordered_buffers(&journal->j_dirty_buffers_lock,
+ journal, jl, &jl->j_tail_bh_list);
+ lock_kernel();
+ }
+ if (!list_empty(&jl->j_tail_bh_list))
+ BUG();
+ up(&jl->j_commit_lock);
+
+ /* honor the flush wishes from the caller, simple commits can
+ ** be done outside the journal lock, they are done below
+ **
+ ** if we don't flush the commit list right now, we put it into
+ ** the work queue so the people waiting on the async progress work
+ ** queue don't wait for this proc to flush journal lists and such.
+ */
+ if (flush) {
+ flush_commit_list(p_s_sb, jl, 1);
+ flush_journal_list(p_s_sb, jl, 1);
+ } else if (!(jl->j_state & LIST_COMMIT_PENDING))
+ queue_delayed_work(commit_wq, &journal->j_work, HZ / 10);
+
+ /* if the next transaction has any chance of wrapping, flush
+ ** transactions that might get overwritten. If any journal lists are very
+ ** old flush them as well.
+ */
+ first_jl:
+ list_for_each_safe(entry, safe, &journal->j_journal_list) {
+ temp_jl = JOURNAL_LIST_ENTRY(entry);
+ if (journal->j_start <= temp_jl->j_start) {
+ if ((journal->j_start + journal->j_trans_max + 1) >=
+ temp_jl->j_start) {
+ flush_used_journal_lists(p_s_sb, temp_jl);
+ goto first_jl;
+ } else if ((journal->j_start +
+ journal->j_trans_max + 1) <
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+ /* if we don't cross into the next transaction and we don't
+ * wrap, there is no way we can overlap any later transactions
+ * break now
+ */
+ break;
+ }
+ } else if ((journal->j_start +
+ journal->j_trans_max + 1) >
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)) {
+ if (((journal->j_start + journal->j_trans_max + 1) %
+ SB_ONDISK_JOURNAL_SIZE(p_s_sb)) >=
+ temp_jl->j_start) {
+ flush_used_journal_lists(p_s_sb, temp_jl);
+ goto first_jl;
+ } else {
+ /* we don't overlap anything from out start to the end of the
+ * log, and our wrapped portion doesn't overlap anything at
+ * the start of the log. We can break
+ */
+ break;
+ }
+ }
+ }
+ flush_old_journal_lists(p_s_sb);
+
+ journal->j_current_jl->j_list_bitmap =
+ get_list_bitmap(p_s_sb, journal->j_current_jl);
+
+ if (!(journal->j_current_jl->j_list_bitmap)) {
+ reiserfs_panic(p_s_sb,
+ "journal-1996: do_journal_end, could not get a list bitmap\n");
+ }
+
+ atomic_set(&(journal->j_jlock), 0);
+ unlock_journal(p_s_sb);
+ /* wake up any body waiting to join. */
+ clear_bit(J_WRITERS_QUEUED, &journal->j_state);
+ wake_up(&(journal->j_join_wait));
+
+ if (!flush && wait_on_commit &&
+ journal_list_still_alive(p_s_sb, commit_trans_id)) {
+ flush_commit_list(p_s_sb, jl, 1);
+ }
+ out:
+ reiserfs_check_lock_depth(p_s_sb, "journal end2");
+
+ memset(th, 0, sizeof(*th));
+ /* Re-set th->t_super, so we can properly keep track of how many
+ * persistent transactions there are. We need to do this so if this
+ * call is part of a failed restart_transaction, we can free it later */
+ th->t_super = p_s_sb;
+
+ return journal->j_errno;
+}
+
+static void __reiserfs_journal_abort_hard(struct super_block *sb)
+{
+ struct reiserfs_journal *journal = SB_JOURNAL(sb);
+ if (test_bit(J_ABORTED, &journal->j_state))
+ return;
+
+ printk(KERN_CRIT "REISERFS: Aborting journal for filesystem on %s\n",
+ reiserfs_bdevname(sb));
+
+ sb->s_flags |= MS_RDONLY;
+ set_bit(J_ABORTED, &journal->j_state);
#ifdef CONFIG_REISERFS_CHECK
- dump_stack();
+ dump_stack();
#endif
}
-static void
-__reiserfs_journal_abort_soft (struct super_block *sb, int errno)
+static void __reiserfs_journal_abort_soft(struct super_block *sb, int errno)
{
- struct reiserfs_journal *journal = SB_JOURNAL (sb);
- if (test_bit (J_ABORTED, &journal->j_state))
- return;
+ struct reiserfs_journal *journal = SB_JOURNAL(sb);
+ if (test_bit(J_ABORTED, &journal->j_state))
+ return;
- if (!journal->j_errno)
- journal->j_errno = errno;
+ if (!journal->j_errno)
+ journal->j_errno = errno;
- __reiserfs_journal_abort_hard (sb);
+ __reiserfs_journal_abort_hard(sb);
}
-void
-reiserfs_journal_abort (struct super_block *sb, int errno)
+void reiserfs_journal_abort(struct super_block *sb, int errno)
{
- return __reiserfs_journal_abort_soft (sb, errno);
+ return __reiserfs_journal_abort_soft(sb, errno);
}
diff --git a/fs/reiserfs/lbalance.c b/fs/reiserfs/lbalance.c
index 2406608fc5cd..2533c1f64aba 100644
--- a/fs/reiserfs/lbalance.c
+++ b/fs/reiserfs/lbalance.c
@@ -21,648 +21,709 @@
leaf_paste_entries
*/
-
/* copy copy_count entries from source directory item to dest buffer (creating new item if needed) */
-static void leaf_copy_dir_entries (struct buffer_info * dest_bi, struct buffer_head * source,
- int last_first, int item_num, int from, int copy_count)
+static void leaf_copy_dir_entries(struct buffer_info *dest_bi,
+ struct buffer_head *source, int last_first,
+ int item_num, int from, int copy_count)
{
- struct buffer_head * dest = dest_bi->bi_bh;
- int item_num_in_dest; /* either the number of target item,
- or if we must create a new item,
- the number of the item we will
- create it next to */
- struct item_head * ih;
- struct reiserfs_de_head * deh;
- int copy_records_len; /* length of all records in item to be copied */
- char * records;
-
- ih = B_N_PITEM_HEAD (source, item_num);
-
- RFALSE( !is_direntry_le_ih (ih), "vs-10000: item must be directory item");
-
- /* length of all record to be copied and first byte of the last of them */
- deh = B_I_DEH (source, ih);
- if (copy_count) {
- copy_records_len = (from ? deh_location( &(deh[from - 1]) ) :
- ih_item_len(ih)) - deh_location( &(deh[from + copy_count - 1]));
- records = source->b_data + ih_location(ih) +
- deh_location( &(deh[from + copy_count - 1]));
- } else {
- copy_records_len = 0;
- records = NULL;
- }
-
- /* when copy last to first, dest buffer can contain 0 items */
- item_num_in_dest = (last_first == LAST_TO_FIRST) ? (( B_NR_ITEMS(dest) ) ? 0 : -1) : (B_NR_ITEMS(dest) - 1);
-
- /* if there are no items in dest or the first/last item in dest is not item of the same directory */
- if ( (item_num_in_dest == - 1) ||
- (last_first == FIRST_TO_LAST && le_ih_k_offset (ih) == DOT_OFFSET) ||
- (last_first == LAST_TO_FIRST && comp_short_le_keys/*COMP_SHORT_KEYS*/ (&ih->ih_key, B_N_PKEY (dest, item_num_in_dest)))) {
- /* create new item in dest */
- struct item_head new_ih;
-
- /* form item header */
- memcpy (&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
- put_ih_version( &new_ih, KEY_FORMAT_3_5 );
- /* calculate item len */
- put_ih_item_len( &new_ih, DEH_SIZE * copy_count + copy_records_len );
- put_ih_entry_count( &new_ih, 0 );
-
- if (last_first == LAST_TO_FIRST) {
- /* form key by the following way */
- if (from < I_ENTRY_COUNT(ih)) {
- set_le_ih_k_offset( &new_ih, deh_offset( &(deh[from]) ) );
- /*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE);*/
- } else {
- /* no entries will be copied to this item in this function */
- set_le_ih_k_offset (&new_ih, U32_MAX);
- /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
- }
- set_le_key_k_type (KEY_FORMAT_3_5, &(new_ih.ih_key), TYPE_DIRENTRY);
+ struct buffer_head *dest = dest_bi->bi_bh;
+ int item_num_in_dest; /* either the number of target item,
+ or if we must create a new item,
+ the number of the item we will
+ create it next to */
+ struct item_head *ih;
+ struct reiserfs_de_head *deh;
+ int copy_records_len; /* length of all records in item to be copied */
+ char *records;
+
+ ih = B_N_PITEM_HEAD(source, item_num);
+
+ RFALSE(!is_direntry_le_ih(ih), "vs-10000: item must be directory item");
+
+ /* length of all record to be copied and first byte of the last of them */
+ deh = B_I_DEH(source, ih);
+ if (copy_count) {
+ copy_records_len = (from ? deh_location(&(deh[from - 1])) :
+ ih_item_len(ih)) -
+ deh_location(&(deh[from + copy_count - 1]));
+ records =
+ source->b_data + ih_location(ih) +
+ deh_location(&(deh[from + copy_count - 1]));
+ } else {
+ copy_records_len = 0;
+ records = NULL;
+ }
+
+ /* when copy last to first, dest buffer can contain 0 items */
+ item_num_in_dest =
+ (last_first ==
+ LAST_TO_FIRST) ? ((B_NR_ITEMS(dest)) ? 0 : -1) : (B_NR_ITEMS(dest)
+ - 1);
+
+ /* if there are no items in dest or the first/last item in dest is not item of the same directory */
+ if ((item_num_in_dest == -1) ||
+ (last_first == FIRST_TO_LAST && le_ih_k_offset(ih) == DOT_OFFSET) ||
+ (last_first == LAST_TO_FIRST
+ && comp_short_le_keys /*COMP_SHORT_KEYS */ (&ih->ih_key,
+ B_N_PKEY(dest,
+ item_num_in_dest))))
+ {
+ /* create new item in dest */
+ struct item_head new_ih;
+
+ /* form item header */
+ memcpy(&new_ih.ih_key, &ih->ih_key, KEY_SIZE);
+ put_ih_version(&new_ih, KEY_FORMAT_3_5);
+ /* calculate item len */
+ put_ih_item_len(&new_ih,
+ DEH_SIZE * copy_count + copy_records_len);
+ put_ih_entry_count(&new_ih, 0);
+
+ if (last_first == LAST_TO_FIRST) {
+ /* form key by the following way */
+ if (from < I_ENTRY_COUNT(ih)) {
+ set_le_ih_k_offset(&new_ih,
+ deh_offset(&(deh[from])));
+ /*memcpy (&new_ih.ih_key.k_offset, &deh[from].deh_offset, SHORT_KEY_SIZE); */
+ } else {
+ /* no entries will be copied to this item in this function */
+ set_le_ih_k_offset(&new_ih, U32_MAX);
+ /* this item is not yet valid, but we want I_IS_DIRECTORY_ITEM to return 1 for it, so we -1 */
+ }
+ set_le_key_k_type(KEY_FORMAT_3_5, &(new_ih.ih_key),
+ TYPE_DIRENTRY);
+ }
+
+ /* insert item into dest buffer */
+ leaf_insert_into_buf(dest_bi,
+ (last_first ==
+ LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest),
+ &new_ih, NULL, 0);
+ } else {
+ /* prepare space for entries */
+ leaf_paste_in_buffer(dest_bi,
+ (last_first ==
+ FIRST_TO_LAST) ? (B_NR_ITEMS(dest) -
+ 1) : 0, MAX_US_INT,
+ DEH_SIZE * copy_count + copy_records_len,
+ records, 0);
}
-
- /* insert item into dest buffer */
- leaf_insert_into_buf (dest_bi, (last_first == LAST_TO_FIRST) ? 0 : B_NR_ITEMS(dest), &new_ih, NULL, 0);
- } else {
- /* prepare space for entries */
- leaf_paste_in_buffer (dest_bi, (last_first==FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0, MAX_US_INT,
- DEH_SIZE * copy_count + copy_records_len, records, 0
- );
- }
-
- item_num_in_dest = (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest)-1) : 0;
-
- leaf_paste_entries (dest_bi->bi_bh, item_num_in_dest,
- (last_first == FIRST_TO_LAST) ? I_ENTRY_COUNT(B_N_PITEM_HEAD (dest, item_num_in_dest)) : 0,
- copy_count, deh + from, records,
- DEH_SIZE * copy_count + copy_records_len
- );
-}
+ item_num_in_dest =
+ (last_first == FIRST_TO_LAST) ? (B_NR_ITEMS(dest) - 1) : 0;
+
+ leaf_paste_entries(dest_bi->bi_bh, item_num_in_dest,
+ (last_first ==
+ FIRST_TO_LAST) ? I_ENTRY_COUNT(B_N_PITEM_HEAD(dest,
+ item_num_in_dest))
+ : 0, copy_count, deh + from, records,
+ DEH_SIZE * copy_count + copy_records_len);
+}
/* Copy the first (if last_first == FIRST_TO_LAST) or last (last_first == LAST_TO_FIRST) item or
part of it or nothing (see the return 0 below) from SOURCE to the end
(if last_first) or beginning (!last_first) of the DEST */
/* returns 1 if anything was copied, else 0 */
-static int leaf_copy_boundary_item (struct buffer_info * dest_bi, struct buffer_head * src, int last_first,
- int bytes_or_entries)
+static int leaf_copy_boundary_item(struct buffer_info *dest_bi,
+ struct buffer_head *src, int last_first,
+ int bytes_or_entries)
{
- struct buffer_head * dest = dest_bi->bi_bh;
- int dest_nr_item, src_nr_item; /* number of items in the source and destination buffers */
- struct item_head * ih;
- struct item_head * dih;
-
- dest_nr_item = B_NR_ITEMS(dest);
-
- if ( last_first == FIRST_TO_LAST ) {
- /* if ( DEST is empty or first item of SOURCE and last item of DEST are the items of different objects
- or of different types ) then there is no need to treat this item differently from the other items
- that we copy, so we return */
- ih = B_N_PITEM_HEAD (src, 0);
- dih = B_N_PITEM_HEAD (dest, dest_nr_item - 1);
- if (!dest_nr_item || (!op_is_left_mergeable (&(ih->ih_key), src->b_size)))
- /* there is nothing to merge */
- return 0;
-
- RFALSE( ! ih_item_len(ih), "vs-10010: item can not have empty length");
-
- if ( is_direntry_le_ih (ih) ) {
- if ( bytes_or_entries == -1 )
- /* copy all entries to dest */
- bytes_or_entries = ih_entry_count(ih);
- leaf_copy_dir_entries (dest_bi, src, FIRST_TO_LAST, 0, 0, bytes_or_entries);
- return 1;
- }
-
- /* copy part of the body of the first item of SOURCE to the end of the body of the last item of the DEST
- part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header
- */
- if ( bytes_or_entries == -1 )
- bytes_or_entries = ih_item_len(ih);
+ struct buffer_head *dest = dest_bi->bi_bh;
+ int dest_nr_item, src_nr_item; /* number of items in the source and destination buffers */
+ struct item_head *ih;
+ struct item_head *dih;
+
+ dest_nr_item = B_NR_ITEMS(dest);
+
+ if (last_first == FIRST_TO_LAST) {
+ /* if ( DEST is empty or first item of SOURCE and last item of DEST are the items of different objects
+ or of different types ) then there is no need to treat this item differently from the other items
+ that we copy, so we return */
+ ih = B_N_PITEM_HEAD(src, 0);
+ dih = B_N_PITEM_HEAD(dest, dest_nr_item - 1);
+ if (!dest_nr_item
+ || (!op_is_left_mergeable(&(ih->ih_key), src->b_size)))
+ /* there is nothing to merge */
+ return 0;
+
+ RFALSE(!ih_item_len(ih),
+ "vs-10010: item can not have empty length");
+
+ if (is_direntry_le_ih(ih)) {
+ if (bytes_or_entries == -1)
+ /* copy all entries to dest */
+ bytes_or_entries = ih_entry_count(ih);
+ leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST, 0, 0,
+ bytes_or_entries);
+ return 1;
+ }
+
+ /* copy part of the body of the first item of SOURCE to the end of the body of the last item of the DEST
+ part defined by 'bytes_or_entries'; if bytes_or_entries == -1 copy whole body; don't create new item header
+ */
+ if (bytes_or_entries == -1)
+ bytes_or_entries = ih_item_len(ih);
#ifdef CONFIG_REISERFS_CHECK
- else {
- if (bytes_or_entries == ih_item_len(ih) && is_indirect_le_ih(ih))
- if (get_ih_free_space (ih))
- reiserfs_panic (NULL, "vs-10020: leaf_copy_boundary_item: "
- "last unformatted node must be filled entirely (%h)",
- ih);
- }
+ else {
+ if (bytes_or_entries == ih_item_len(ih)
+ && is_indirect_le_ih(ih))
+ if (get_ih_free_space(ih))
+ reiserfs_panic(NULL,
+ "vs-10020: leaf_copy_boundary_item: "
+ "last unformatted node must be filled entirely (%h)",
+ ih);
+ }
#endif
-
- /* merge first item (or its part) of src buffer with the last
- item of dest buffer. Both are of the same file */
- leaf_paste_in_buffer (dest_bi,
- dest_nr_item - 1, ih_item_len(dih), bytes_or_entries, B_I_PITEM(src,ih), 0
- );
-
- if (is_indirect_le_ih (dih)) {
- RFALSE( get_ih_free_space (dih),
- "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zerto free space",
- ih);
- if (bytes_or_entries == ih_item_len(ih))
- set_ih_free_space (dih, get_ih_free_space (ih));
- }
-
- return 1;
- }
-
-
- /* copy boundary item to right (last_first == LAST_TO_FIRST) */
-
- /* ( DEST is empty or last item of SOURCE and first item of DEST
- are the items of different object or of different types )
- */
- src_nr_item = B_NR_ITEMS (src);
- ih = B_N_PITEM_HEAD (src, src_nr_item - 1);
- dih = B_N_PITEM_HEAD (dest, 0);
-
- if (!dest_nr_item || !op_is_left_mergeable (&(dih->ih_key), src->b_size))
- return 0;
-
- if ( is_direntry_le_ih (ih)) {
- if ( bytes_or_entries == -1 )
- /* bytes_or_entries = entries number in last item body of SOURCE */
- bytes_or_entries = ih_entry_count(ih);
-
- leaf_copy_dir_entries (dest_bi, src, LAST_TO_FIRST, src_nr_item - 1, ih_entry_count(ih) - bytes_or_entries, bytes_or_entries);
- return 1;
- }
-
- /* copy part of the body of the last item of SOURCE to the begin of the body of the first item of the DEST;
- part defined by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body; change first item key of the DEST;
- don't create new item header
- */
-
- RFALSE( is_indirect_le_ih(ih) && get_ih_free_space (ih),
- "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
- ih);
-
- if ( bytes_or_entries == -1 ) {
- /* bytes_or_entries = length of last item body of SOURCE */
- bytes_or_entries = ih_item_len(ih);
-
- RFALSE( le_ih_k_offset (dih) !=
- le_ih_k_offset (ih) + op_bytes_number (ih, src->b_size),
- "vs-10050: items %h and %h do not match", ih, dih);
-
- /* change first item key of the DEST */
- set_le_ih_k_offset (dih, le_ih_k_offset (ih));
-
- /* item becomes non-mergeable */
- /* or mergeable if left item was */
- set_le_ih_k_type (dih, le_ih_k_type (ih));
- } else {
- /* merge to right only part of item */
- RFALSE( ih_item_len(ih) <= bytes_or_entries,
- "vs-10060: no so much bytes %lu (needed %lu)",
- ( unsigned long )ih_item_len(ih), ( unsigned long )bytes_or_entries);
-
- /* change first item key of the DEST */
- if ( is_direct_le_ih (dih) ) {
- RFALSE( le_ih_k_offset (dih) <= (unsigned long)bytes_or_entries,
- "vs-10070: dih %h, bytes_or_entries(%d)", dih, bytes_or_entries);
- set_le_ih_k_offset (dih, le_ih_k_offset (dih) - bytes_or_entries);
- } else {
- RFALSE( le_ih_k_offset (dih) <=
- (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
- "vs-10080: dih %h, bytes_or_entries(%d)",
- dih, (bytes_or_entries/UNFM_P_SIZE)*dest->b_size);
- set_le_ih_k_offset (dih, le_ih_k_offset (dih) - ((bytes_or_entries / UNFM_P_SIZE) * dest->b_size));
- }
- }
-
- leaf_paste_in_buffer (dest_bi, 0, 0, bytes_or_entries, B_I_PITEM(src,ih) + ih_item_len(ih) - bytes_or_entries, 0);
- return 1;
-}
+ /* merge first item (or its part) of src buffer with the last
+ item of dest buffer. Both are of the same file */
+ leaf_paste_in_buffer(dest_bi,
+ dest_nr_item - 1, ih_item_len(dih),
+ bytes_or_entries, B_I_PITEM(src, ih), 0);
+
+ if (is_indirect_le_ih(dih)) {
+ RFALSE(get_ih_free_space(dih),
+ "vs-10030: merge to left: last unformatted node of non-last indirect item %h must have zerto free space",
+ ih);
+ if (bytes_or_entries == ih_item_len(ih))
+ set_ih_free_space(dih, get_ih_free_space(ih));
+ }
+
+ return 1;
+ }
+
+ /* copy boundary item to right (last_first == LAST_TO_FIRST) */
+
+ /* ( DEST is empty or last item of SOURCE and first item of DEST
+ are the items of different object or of different types )
+ */
+ src_nr_item = B_NR_ITEMS(src);
+ ih = B_N_PITEM_HEAD(src, src_nr_item - 1);
+ dih = B_N_PITEM_HEAD(dest, 0);
+
+ if (!dest_nr_item || !op_is_left_mergeable(&(dih->ih_key), src->b_size))
+ return 0;
+
+ if (is_direntry_le_ih(ih)) {
+ if (bytes_or_entries == -1)
+ /* bytes_or_entries = entries number in last item body of SOURCE */
+ bytes_or_entries = ih_entry_count(ih);
+
+ leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
+ src_nr_item - 1,
+ ih_entry_count(ih) - bytes_or_entries,
+ bytes_or_entries);
+ return 1;
+ }
+
+ /* copy part of the body of the last item of SOURCE to the begin of the body of the first item of the DEST;
+ part defined by 'bytes_or_entries'; if byte_or_entriess == -1 copy whole body; change first item key of the DEST;
+ don't create new item header
+ */
+
+ RFALSE(is_indirect_le_ih(ih) && get_ih_free_space(ih),
+ "vs-10040: merge to right: last unformatted node of non-last indirect item must be filled entirely (%h)",
+ ih);
+
+ if (bytes_or_entries == -1) {
+ /* bytes_or_entries = length of last item body of SOURCE */
+ bytes_or_entries = ih_item_len(ih);
+
+ RFALSE(le_ih_k_offset(dih) !=
+ le_ih_k_offset(ih) + op_bytes_number(ih, src->b_size),
+ "vs-10050: items %h and %h do not match", ih, dih);
+
+ /* change first item key of the DEST */
+ set_le_ih_k_offset(dih, le_ih_k_offset(ih));
+
+ /* item becomes non-mergeable */
+ /* or mergeable if left item was */
+ set_le_ih_k_type(dih, le_ih_k_type(ih));
+ } else {
+ /* merge to right only part of item */
+ RFALSE(ih_item_len(ih) <= bytes_or_entries,
+ "vs-10060: no so much bytes %lu (needed %lu)",
+ (unsigned long)ih_item_len(ih),
+ (unsigned long)bytes_or_entries);
+
+ /* change first item key of the DEST */
+ if (is_direct_le_ih(dih)) {
+ RFALSE(le_ih_k_offset(dih) <=
+ (unsigned long)bytes_or_entries,
+ "vs-10070: dih %h, bytes_or_entries(%d)", dih,
+ bytes_or_entries);
+ set_le_ih_k_offset(dih,
+ le_ih_k_offset(dih) -
+ bytes_or_entries);
+ } else {
+ RFALSE(le_ih_k_offset(dih) <=
+ (bytes_or_entries / UNFM_P_SIZE) * dest->b_size,
+ "vs-10080: dih %h, bytes_or_entries(%d)",
+ dih,
+ (bytes_or_entries / UNFM_P_SIZE) * dest->b_size);
+ set_le_ih_k_offset(dih,
+ le_ih_k_offset(dih) -
+ ((bytes_or_entries / UNFM_P_SIZE) *
+ dest->b_size));
+ }
+ }
+
+ leaf_paste_in_buffer(dest_bi, 0, 0, bytes_or_entries,
+ B_I_PITEM(src,
+ ih) + ih_item_len(ih) - bytes_or_entries,
+ 0);
+ return 1;
+}
/* copy cpy_mun items from buffer src to buffer dest
* last_first == FIRST_TO_LAST means, that we copy cpy_num items beginning from first-th item in src to tail of dest
* last_first == LAST_TO_FIRST means, that we copy cpy_num items beginning from first-th item in src to head of dest
*/
-static void leaf_copy_items_entirely (struct buffer_info * dest_bi, struct buffer_head * src, int last_first,
- int first, int cpy_num)
+static void leaf_copy_items_entirely(struct buffer_info *dest_bi,
+ struct buffer_head *src, int last_first,
+ int first, int cpy_num)
{
- struct buffer_head * dest;
- int nr, free_space;
- int dest_before;
- int last_loc, last_inserted_loc, location;
- int i, j;
- struct block_head * blkh;
- struct item_head * ih;
-
- RFALSE( last_first != LAST_TO_FIRST && last_first != FIRST_TO_LAST,
- "vs-10090: bad last_first parameter %d", last_first);
- RFALSE( B_NR_ITEMS (src) - first < cpy_num,
- "vs-10100: too few items in source %d, required %d from %d",
- B_NR_ITEMS(src), cpy_num, first);
- RFALSE( cpy_num < 0, "vs-10110: can not copy negative amount of items");
- RFALSE( ! dest_bi, "vs-10120: can not copy negative amount of items");
-
- dest = dest_bi->bi_bh;
-
- RFALSE( ! dest, "vs-10130: can not copy negative amount of items");
-
- if (cpy_num == 0)
- return;
-
- blkh = B_BLK_HEAD(dest);
- nr = blkh_nr_item( blkh );
- free_space = blkh_free_space(blkh);
-
- /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */
- dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
-
- /* location of head of first new item */
- ih = B_N_PITEM_HEAD (dest, dest_before);
-
- RFALSE( blkh_free_space(blkh) < cpy_num * IH_SIZE,
- "vs-10140: not enough free space for headers %d (needed %d)",
- B_FREE_SPACE (dest), cpy_num * IH_SIZE);
-
- /* prepare space for headers */
- memmove (ih + cpy_num, ih, (nr-dest_before) * IH_SIZE);
-
- /* copy item headers */
- memcpy (ih, B_N_PITEM_HEAD (src, first), cpy_num * IH_SIZE);
-
- free_space -= (IH_SIZE * cpy_num);
- set_blkh_free_space( blkh, free_space );
-
- /* location of unmovable item */
- j = location = (dest_before == 0) ? dest->b_size : ih_location(ih-1);
- for (i = dest_before; i < nr + cpy_num; i ++) {
- location -= ih_item_len( ih + i - dest_before );
- put_ih_location( ih + i - dest_before, location );
- }
-
- /* prepare space for items */
- last_loc = ih_location( &(ih[nr+cpy_num-1-dest_before]) );
- last_inserted_loc = ih_location( &(ih[cpy_num-1]) );
-
- /* check free space */
- RFALSE( free_space < j - last_inserted_loc,
- "vs-10150: not enough free space for items %d (needed %d)",
- free_space, j - last_inserted_loc);
-
- memmove (dest->b_data + last_loc,
- dest->b_data + last_loc + j - last_inserted_loc,
- last_inserted_loc - last_loc);
-
- /* copy items */
- memcpy (dest->b_data + last_inserted_loc, B_N_PITEM(src,(first + cpy_num - 1)),
- j - last_inserted_loc);
-
- /* sizes, item number */
- set_blkh_nr_item( blkh, nr + cpy_num );
- set_blkh_free_space( blkh, free_space - (j - last_inserted_loc) );
-
- do_balance_mark_leaf_dirty (dest_bi->tb, dest, 0);
-
- if (dest_bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD (dest_bi->bi_parent, dest_bi->bi_position);
- RFALSE( dc_block_number(t_dc) != dest->b_blocknr,
- "vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
- ( long unsigned ) dest->b_blocknr,
- ( long unsigned ) dc_block_number(t_dc));
- put_dc_size( t_dc, dc_size(t_dc) + (j - last_inserted_loc + IH_SIZE * cpy_num ) );
-
- do_balance_mark_internal_dirty (dest_bi->tb, dest_bi->bi_parent, 0);
- }
-}
+ struct buffer_head *dest;
+ int nr, free_space;
+ int dest_before;
+ int last_loc, last_inserted_loc, location;
+ int i, j;
+ struct block_head *blkh;
+ struct item_head *ih;
+
+ RFALSE(last_first != LAST_TO_FIRST && last_first != FIRST_TO_LAST,
+ "vs-10090: bad last_first parameter %d", last_first);
+ RFALSE(B_NR_ITEMS(src) - first < cpy_num,
+ "vs-10100: too few items in source %d, required %d from %d",
+ B_NR_ITEMS(src), cpy_num, first);
+ RFALSE(cpy_num < 0, "vs-10110: can not copy negative amount of items");
+ RFALSE(!dest_bi, "vs-10120: can not copy negative amount of items");
+
+ dest = dest_bi->bi_bh;
+
+ RFALSE(!dest, "vs-10130: can not copy negative amount of items");
+
+ if (cpy_num == 0)
+ return;
+
+ blkh = B_BLK_HEAD(dest);
+ nr = blkh_nr_item(blkh);
+ free_space = blkh_free_space(blkh);
+
+ /* we will insert items before 0-th or nr-th item in dest buffer. It depends of last_first parameter */
+ dest_before = (last_first == LAST_TO_FIRST) ? 0 : nr;
+
+ /* location of head of first new item */
+ ih = B_N_PITEM_HEAD(dest, dest_before);
+
+ RFALSE(blkh_free_space(blkh) < cpy_num * IH_SIZE,
+ "vs-10140: not enough free space for headers %d (needed %d)",
+ B_FREE_SPACE(dest), cpy_num * IH_SIZE);
+
+ /* prepare space for headers */
+ memmove(ih + cpy_num, ih, (nr - dest_before) * IH_SIZE);
+ /* copy item headers */
+ memcpy(ih, B_N_PITEM_HEAD(src, first), cpy_num * IH_SIZE);
+
+ free_space -= (IH_SIZE * cpy_num);
+ set_blkh_free_space(blkh, free_space);
+
+ /* location of unmovable item */
+ j = location = (dest_before == 0) ? dest->b_size : ih_location(ih - 1);
+ for (i = dest_before; i < nr + cpy_num; i++) {
+ location -= ih_item_len(ih + i - dest_before);
+ put_ih_location(ih + i - dest_before, location);
+ }
+
+ /* prepare space for items */
+ last_loc = ih_location(&(ih[nr + cpy_num - 1 - dest_before]));
+ last_inserted_loc = ih_location(&(ih[cpy_num - 1]));
+
+ /* check free space */
+ RFALSE(free_space < j - last_inserted_loc,
+ "vs-10150: not enough free space for items %d (needed %d)",
+ free_space, j - last_inserted_loc);
+
+ memmove(dest->b_data + last_loc,
+ dest->b_data + last_loc + j - last_inserted_loc,
+ last_inserted_loc - last_loc);
+
+ /* copy items */
+ memcpy(dest->b_data + last_inserted_loc,
+ B_N_PITEM(src, (first + cpy_num - 1)), j - last_inserted_loc);
+
+ /* sizes, item number */
+ set_blkh_nr_item(blkh, nr + cpy_num);
+ set_blkh_free_space(blkh, free_space - (j - last_inserted_loc));
+
+ do_balance_mark_leaf_dirty(dest_bi->tb, dest, 0);
+
+ if (dest_bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(dest_bi->bi_parent, dest_bi->bi_position);
+ RFALSE(dc_block_number(t_dc) != dest->b_blocknr,
+ "vs-10160: block number in bh does not match to field in disk_child structure %lu and %lu",
+ (long unsigned)dest->b_blocknr,
+ (long unsigned)dc_block_number(t_dc));
+ put_dc_size(t_dc,
+ dc_size(t_dc) + (j - last_inserted_loc +
+ IH_SIZE * cpy_num));
+
+ do_balance_mark_internal_dirty(dest_bi->tb, dest_bi->bi_parent,
+ 0);
+ }
+}
/* This function splits the (liquid) item into two items (useful when
shifting part of an item into another node.) */
-static void leaf_item_bottle (struct buffer_info * dest_bi, struct buffer_head * src, int last_first,
- int item_num, int cpy_bytes)
+static void leaf_item_bottle(struct buffer_info *dest_bi,
+ struct buffer_head *src, int last_first,
+ int item_num, int cpy_bytes)
{
- struct buffer_head * dest = dest_bi->bi_bh;
- struct item_head * ih;
-
- RFALSE( cpy_bytes == -1, "vs-10170: bytes == - 1 means: do not split item");
-
- if ( last_first == FIRST_TO_LAST ) {
- /* if ( if item in position item_num in buffer SOURCE is directory item ) */
- if (is_direntry_le_ih (ih = B_N_PITEM_HEAD(src,item_num)))
- leaf_copy_dir_entries (dest_bi, src, FIRST_TO_LAST, item_num, 0, cpy_bytes);
- else {
- struct item_head n_ih;
-
- /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST
- part defined by 'cpy_bytes'; create new item header; change old item_header (????);
- n_ih = new item_header;
- */
- memcpy (&n_ih, ih, IH_SIZE);
- put_ih_item_len( &n_ih, cpy_bytes );
- if (is_indirect_le_ih (ih)) {
- RFALSE( cpy_bytes == ih_item_len(ih) && get_ih_free_space(ih),
- "vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
- ( long unsigned ) get_ih_free_space (ih));
- set_ih_free_space (&n_ih, 0);
- }
-
- RFALSE( op_is_left_mergeable (&(ih->ih_key), src->b_size),
- "vs-10190: bad mergeability of item %h", ih);
- n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
- leaf_insert_into_buf (dest_bi, B_NR_ITEMS(dest), &n_ih, B_N_PITEM (src, item_num), 0);
+ struct buffer_head *dest = dest_bi->bi_bh;
+ struct item_head *ih;
+
+ RFALSE(cpy_bytes == -1,
+ "vs-10170: bytes == - 1 means: do not split item");
+
+ if (last_first == FIRST_TO_LAST) {
+ /* if ( if item in position item_num in buffer SOURCE is directory item ) */
+ if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num)))
+ leaf_copy_dir_entries(dest_bi, src, FIRST_TO_LAST,
+ item_num, 0, cpy_bytes);
+ else {
+ struct item_head n_ih;
+
+ /* copy part of the body of the item number 'item_num' of SOURCE to the end of the DEST
+ part defined by 'cpy_bytes'; create new item header; change old item_header (????);
+ n_ih = new item_header;
+ */
+ memcpy(&n_ih, ih, IH_SIZE);
+ put_ih_item_len(&n_ih, cpy_bytes);
+ if (is_indirect_le_ih(ih)) {
+ RFALSE(cpy_bytes == ih_item_len(ih)
+ && get_ih_free_space(ih),
+ "vs-10180: when whole indirect item is bottle to left neighbor, it must have free_space==0 (not %lu)",
+ (long unsigned)get_ih_free_space(ih));
+ set_ih_free_space(&n_ih, 0);
+ }
+
+ RFALSE(op_is_left_mergeable(&(ih->ih_key), src->b_size),
+ "vs-10190: bad mergeability of item %h", ih);
+ n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
+ leaf_insert_into_buf(dest_bi, B_NR_ITEMS(dest), &n_ih,
+ B_N_PITEM(src, item_num), 0);
+ }
+ } else {
+ /* if ( if item in position item_num in buffer SOURCE is directory item ) */
+ if (is_direntry_le_ih(ih = B_N_PITEM_HEAD(src, item_num)))
+ leaf_copy_dir_entries(dest_bi, src, LAST_TO_FIRST,
+ item_num,
+ I_ENTRY_COUNT(ih) - cpy_bytes,
+ cpy_bytes);
+ else {
+ struct item_head n_ih;
+
+ /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST
+ part defined by 'cpy_bytes'; create new item header;
+ n_ih = new item_header;
+ */
+ memcpy(&n_ih, ih, SHORT_KEY_SIZE);
+
+ n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
+
+ if (is_direct_le_ih(ih)) {
+ set_le_ih_k_offset(&n_ih,
+ le_ih_k_offset(ih) +
+ ih_item_len(ih) - cpy_bytes);
+ set_le_ih_k_type(&n_ih, TYPE_DIRECT);
+ set_ih_free_space(&n_ih, MAX_US_INT);
+ } else {
+ /* indirect item */
+ RFALSE(!cpy_bytes && get_ih_free_space(ih),
+ "vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
+ set_le_ih_k_offset(&n_ih,
+ le_ih_k_offset(ih) +
+ (ih_item_len(ih) -
+ cpy_bytes) / UNFM_P_SIZE *
+ dest->b_size);
+ set_le_ih_k_type(&n_ih, TYPE_INDIRECT);
+ set_ih_free_space(&n_ih, get_ih_free_space(ih));
+ }
+
+ /* set item length */
+ put_ih_item_len(&n_ih, cpy_bytes);
+
+ n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
+
+ leaf_insert_into_buf(dest_bi, 0, &n_ih,
+ B_N_PITEM(src,
+ item_num) +
+ ih_item_len(ih) - cpy_bytes, 0);
+ }
}
- } else {
- /* if ( if item in position item_num in buffer SOURCE is directory item ) */
- if (is_direntry_le_ih(ih = B_N_PITEM_HEAD (src, item_num)))
- leaf_copy_dir_entries (dest_bi, src, LAST_TO_FIRST, item_num, I_ENTRY_COUNT(ih) - cpy_bytes, cpy_bytes);
- else {
- struct item_head n_ih;
-
- /* copy part of the body of the item number 'item_num' of SOURCE to the begin of the DEST
- part defined by 'cpy_bytes'; create new item header;
- n_ih = new item_header;
- */
- memcpy (&n_ih, ih, SHORT_KEY_SIZE);
-
- n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
-
- if (is_direct_le_ih (ih)) {
- set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + ih_item_len(ih) - cpy_bytes);
- set_le_ih_k_type (&n_ih, TYPE_DIRECT);
- set_ih_free_space (&n_ih, MAX_US_INT);
- } else {
- /* indirect item */
- RFALSE( !cpy_bytes && get_ih_free_space (ih),
- "vs-10200: ih->ih_free_space must be 0 when indirect item will be appended");
- set_le_ih_k_offset (&n_ih, le_ih_k_offset (ih) + (ih_item_len(ih) - cpy_bytes) / UNFM_P_SIZE * dest->b_size);
- set_le_ih_k_type (&n_ih, TYPE_INDIRECT);
- set_ih_free_space (&n_ih, get_ih_free_space (ih));
- }
-
- /* set item length */
- put_ih_item_len( &n_ih, cpy_bytes );
-
- n_ih.ih_version = ih->ih_version; /* JDM Endian safe, both le */
-
- leaf_insert_into_buf (dest_bi, 0, &n_ih, B_N_PITEM(src,item_num) + ih_item_len(ih) - cpy_bytes, 0);
- }
- }
}
-
/* If cpy_bytes equals minus one than copy cpy_num whole items from SOURCE to DEST.
If cpy_bytes not equal to minus one than copy cpy_num-1 whole items from SOURCE to DEST.
From last item copy cpy_num bytes for regular item and cpy_num directory entries for
directory item. */
-static int leaf_copy_items (struct buffer_info * dest_bi, struct buffer_head * src, int last_first, int cpy_num,
- int cpy_bytes)
+static int leaf_copy_items(struct buffer_info *dest_bi, struct buffer_head *src,
+ int last_first, int cpy_num, int cpy_bytes)
{
- struct buffer_head * dest;
- int pos, i, src_nr_item, bytes;
-
- dest = dest_bi->bi_bh;
- RFALSE( !dest || !src, "vs-10210: !dest || !src");
- RFALSE( last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
- "vs-10220:last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST");
- RFALSE( B_NR_ITEMS(src) < cpy_num,
- "vs-10230: No enough items: %d, req. %d", B_NR_ITEMS(src), cpy_num);
- RFALSE( cpy_num < 0,"vs-10240: cpy_num < 0 (%d)", cpy_num);
-
- if ( cpy_num == 0 )
- return 0;
-
- if ( last_first == FIRST_TO_LAST ) {
- /* copy items to left */
- pos = 0;
- if ( cpy_num == 1 )
- bytes = cpy_bytes;
- else
- bytes = -1;
-
- /* copy the first item or it part or nothing to the end of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes)) */
- i = leaf_copy_boundary_item (dest_bi, src, FIRST_TO_LAST, bytes);
- cpy_num -= i;
- if ( cpy_num == 0 )
- return i;
- pos += i;
- if ( cpy_bytes == -1 )
- /* copy first cpy_num items starting from position 'pos' of SOURCE to end of DEST */
- leaf_copy_items_entirely (dest_bi, src, FIRST_TO_LAST, pos, cpy_num);
- else {
- /* copy first cpy_num-1 items starting from position 'pos-1' of the SOURCE to the end of the DEST */
- leaf_copy_items_entirely (dest_bi, src, FIRST_TO_LAST, pos, cpy_num-1);
-
- /* copy part of the item which number is cpy_num+pos-1 to the end of the DEST */
- leaf_item_bottle (dest_bi, src, FIRST_TO_LAST, cpy_num+pos-1, cpy_bytes);
- }
- } else {
- /* copy items to right */
- src_nr_item = B_NR_ITEMS (src);
- if ( cpy_num == 1 )
- bytes = cpy_bytes;
- else
- bytes = -1;
-
- /* copy the last item or it part or nothing to the begin of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes)); */
- i = leaf_copy_boundary_item (dest_bi, src, LAST_TO_FIRST, bytes);
-
- cpy_num -= i;
- if ( cpy_num == 0 )
- return i;
-
- pos = src_nr_item - cpy_num - i;
- if ( cpy_bytes == -1 ) {
- /* starting from position 'pos' copy last cpy_num items of SOURCE to begin of DEST */
- leaf_copy_items_entirely (dest_bi, src, LAST_TO_FIRST, pos, cpy_num);
- } else {
- /* copy last cpy_num-1 items starting from position 'pos+1' of the SOURCE to the begin of the DEST; */
- leaf_copy_items_entirely (dest_bi, src, LAST_TO_FIRST, pos+1, cpy_num-1);
-
- /* copy part of the item which number is pos to the begin of the DEST */
- leaf_item_bottle (dest_bi, src, LAST_TO_FIRST, pos, cpy_bytes);
- }
- }
- return i;
+ struct buffer_head *dest;
+ int pos, i, src_nr_item, bytes;
+
+ dest = dest_bi->bi_bh;
+ RFALSE(!dest || !src, "vs-10210: !dest || !src");
+ RFALSE(last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST,
+ "vs-10220:last_first != FIRST_TO_LAST && last_first != LAST_TO_FIRST");
+ RFALSE(B_NR_ITEMS(src) < cpy_num,
+ "vs-10230: No enough items: %d, req. %d", B_NR_ITEMS(src),
+ cpy_num);
+ RFALSE(cpy_num < 0, "vs-10240: cpy_num < 0 (%d)", cpy_num);
+
+ if (cpy_num == 0)
+ return 0;
+
+ if (last_first == FIRST_TO_LAST) {
+ /* copy items to left */
+ pos = 0;
+ if (cpy_num == 1)
+ bytes = cpy_bytes;
+ else
+ bytes = -1;
+
+ /* copy the first item or it part or nothing to the end of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,0,bytes)) */
+ i = leaf_copy_boundary_item(dest_bi, src, FIRST_TO_LAST, bytes);
+ cpy_num -= i;
+ if (cpy_num == 0)
+ return i;
+ pos += i;
+ if (cpy_bytes == -1)
+ /* copy first cpy_num items starting from position 'pos' of SOURCE to end of DEST */
+ leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
+ pos, cpy_num);
+ else {
+ /* copy first cpy_num-1 items starting from position 'pos-1' of the SOURCE to the end of the DEST */
+ leaf_copy_items_entirely(dest_bi, src, FIRST_TO_LAST,
+ pos, cpy_num - 1);
+
+ /* copy part of the item which number is cpy_num+pos-1 to the end of the DEST */
+ leaf_item_bottle(dest_bi, src, FIRST_TO_LAST,
+ cpy_num + pos - 1, cpy_bytes);
+ }
+ } else {
+ /* copy items to right */
+ src_nr_item = B_NR_ITEMS(src);
+ if (cpy_num == 1)
+ bytes = cpy_bytes;
+ else
+ bytes = -1;
+
+ /* copy the last item or it part or nothing to the begin of the DEST (i = leaf_copy_boundary_item(DEST,SOURCE,1,bytes)); */
+ i = leaf_copy_boundary_item(dest_bi, src, LAST_TO_FIRST, bytes);
+
+ cpy_num -= i;
+ if (cpy_num == 0)
+ return i;
+
+ pos = src_nr_item - cpy_num - i;
+ if (cpy_bytes == -1) {
+ /* starting from position 'pos' copy last cpy_num items of SOURCE to begin of DEST */
+ leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
+ pos, cpy_num);
+ } else {
+ /* copy last cpy_num-1 items starting from position 'pos+1' of the SOURCE to the begin of the DEST; */
+ leaf_copy_items_entirely(dest_bi, src, LAST_TO_FIRST,
+ pos + 1, cpy_num - 1);
+
+ /* copy part of the item which number is pos to the begin of the DEST */
+ leaf_item_bottle(dest_bi, src, LAST_TO_FIRST, pos,
+ cpy_bytes);
+ }
+ }
+ return i;
}
-
/* there are types of coping: from S[0] to L[0], from S[0] to R[0],
from R[0] to L[0]. for each of these we have to define parent and
positions of destination and source buffers */
-static void leaf_define_dest_src_infos (int shift_mode, struct tree_balance * tb, struct buffer_info * dest_bi,
- struct buffer_info * src_bi, int * first_last,
- struct buffer_head * Snew)
+static void leaf_define_dest_src_infos(int shift_mode, struct tree_balance *tb,
+ struct buffer_info *dest_bi,
+ struct buffer_info *src_bi,
+ int *first_last,
+ struct buffer_head *Snew)
{
- memset (dest_bi, 0, sizeof (struct buffer_info));
- memset (src_bi, 0, sizeof (struct buffer_info));
-
- /* define dest, src, dest parent, dest position */
- switch (shift_mode) {
- case LEAF_FROM_S_TO_L: /* it is used in leaf_shift_left */
- src_bi->tb = tb;
- src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
- src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0); /* src->b_item_order */
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->L[0];
- dest_bi->bi_parent = tb->FL[0];
- dest_bi->bi_position = get_left_neighbor_position (tb, 0);
- *first_last = FIRST_TO_LAST;
- break;
-
- case LEAF_FROM_S_TO_R: /* it is used in leaf_shift_right */
- src_bi->tb = tb;
- src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
- src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->R[0];
- dest_bi->bi_parent = tb->FR[0];
- dest_bi->bi_position = get_right_neighbor_position (tb, 0);
- *first_last = LAST_TO_FIRST;
- break;
-
- case LEAF_FROM_R_TO_L: /* it is used in balance_leaf_when_delete */
- src_bi->tb = tb;
- src_bi->bi_bh = tb->R[0];
- src_bi->bi_parent = tb->FR[0];
- src_bi->bi_position = get_right_neighbor_position (tb, 0);
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->L[0];
- dest_bi->bi_parent = tb->FL[0];
- dest_bi->bi_position = get_left_neighbor_position (tb, 0);
- *first_last = FIRST_TO_LAST;
- break;
-
- case LEAF_FROM_L_TO_R: /* it is used in balance_leaf_when_delete */
- src_bi->tb = tb;
- src_bi->bi_bh = tb->L[0];
- src_bi->bi_parent = tb->FL[0];
- src_bi->bi_position = get_left_neighbor_position (tb, 0);
- dest_bi->tb = tb;
- dest_bi->bi_bh = tb->R[0];
- dest_bi->bi_parent = tb->FR[0];
- dest_bi->bi_position = get_right_neighbor_position (tb, 0);
- *first_last = LAST_TO_FIRST;
- break;
-
- case LEAF_FROM_S_TO_SNEW:
- src_bi->tb = tb;
- src_bi->bi_bh = PATH_PLAST_BUFFER (tb->tb_path);
- src_bi->bi_parent = PATH_H_PPARENT (tb->tb_path, 0);
- src_bi->bi_position = PATH_H_B_ITEM_ORDER (tb->tb_path, 0);
- dest_bi->tb = tb;
- dest_bi->bi_bh = Snew;
- dest_bi->bi_parent = NULL;
- dest_bi->bi_position = 0;
- *first_last = LAST_TO_FIRST;
- break;
-
- default:
- reiserfs_panic (NULL, "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)", shift_mode);
- }
- RFALSE( src_bi->bi_bh == 0 || dest_bi->bi_bh == 0,
- "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
- shift_mode, src_bi->bi_bh, dest_bi->bi_bh);
+ memset(dest_bi, 0, sizeof(struct buffer_info));
+ memset(src_bi, 0, sizeof(struct buffer_info));
+
+ /* define dest, src, dest parent, dest position */
+ switch (shift_mode) {
+ case LEAF_FROM_S_TO_L: /* it is used in leaf_shift_left */
+ src_bi->tb = tb;
+ src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
+ src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0); /* src->b_item_order */
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->L[0];
+ dest_bi->bi_parent = tb->FL[0];
+ dest_bi->bi_position = get_left_neighbor_position(tb, 0);
+ *first_last = FIRST_TO_LAST;
+ break;
+
+ case LEAF_FROM_S_TO_R: /* it is used in leaf_shift_right */
+ src_bi->tb = tb;
+ src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
+ src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->R[0];
+ dest_bi->bi_parent = tb->FR[0];
+ dest_bi->bi_position = get_right_neighbor_position(tb, 0);
+ *first_last = LAST_TO_FIRST;
+ break;
+
+ case LEAF_FROM_R_TO_L: /* it is used in balance_leaf_when_delete */
+ src_bi->tb = tb;
+ src_bi->bi_bh = tb->R[0];
+ src_bi->bi_parent = tb->FR[0];
+ src_bi->bi_position = get_right_neighbor_position(tb, 0);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->L[0];
+ dest_bi->bi_parent = tb->FL[0];
+ dest_bi->bi_position = get_left_neighbor_position(tb, 0);
+ *first_last = FIRST_TO_LAST;
+ break;
+
+ case LEAF_FROM_L_TO_R: /* it is used in balance_leaf_when_delete */
+ src_bi->tb = tb;
+ src_bi->bi_bh = tb->L[0];
+ src_bi->bi_parent = tb->FL[0];
+ src_bi->bi_position = get_left_neighbor_position(tb, 0);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = tb->R[0];
+ dest_bi->bi_parent = tb->FR[0];
+ dest_bi->bi_position = get_right_neighbor_position(tb, 0);
+ *first_last = LAST_TO_FIRST;
+ break;
+
+ case LEAF_FROM_S_TO_SNEW:
+ src_bi->tb = tb;
+ src_bi->bi_bh = PATH_PLAST_BUFFER(tb->tb_path);
+ src_bi->bi_parent = PATH_H_PPARENT(tb->tb_path, 0);
+ src_bi->bi_position = PATH_H_B_ITEM_ORDER(tb->tb_path, 0);
+ dest_bi->tb = tb;
+ dest_bi->bi_bh = Snew;
+ dest_bi->bi_parent = NULL;
+ dest_bi->bi_position = 0;
+ *first_last = LAST_TO_FIRST;
+ break;
+
+ default:
+ reiserfs_panic(NULL,
+ "vs-10250: leaf_define_dest_src_infos: shift type is unknown (%d)",
+ shift_mode);
+ }
+ RFALSE(src_bi->bi_bh == 0 || dest_bi->bi_bh == 0,
+ "vs-10260: mode==%d, source (%p) or dest (%p) buffer is initialized incorrectly",
+ shift_mode, src_bi->bi_bh, dest_bi->bi_bh);
}
-
-
-
/* copy mov_num items and mov_bytes of the (mov_num-1)th item to
neighbor. Delete them from source */
-int leaf_move_items (int shift_mode, struct tree_balance * tb, int mov_num, int mov_bytes, struct buffer_head * Snew)
+int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
+ int mov_bytes, struct buffer_head *Snew)
{
- int ret_value;
- struct buffer_info dest_bi, src_bi;
- int first_last;
+ int ret_value;
+ struct buffer_info dest_bi, src_bi;
+ int first_last;
- leaf_define_dest_src_infos (shift_mode, tb, &dest_bi, &src_bi, &first_last, Snew);
+ leaf_define_dest_src_infos(shift_mode, tb, &dest_bi, &src_bi,
+ &first_last, Snew);
- ret_value = leaf_copy_items (&dest_bi, src_bi.bi_bh, first_last, mov_num, mov_bytes);
+ ret_value =
+ leaf_copy_items(&dest_bi, src_bi.bi_bh, first_last, mov_num,
+ mov_bytes);
- leaf_delete_items (&src_bi, first_last, (first_last == FIRST_TO_LAST) ? 0 : (B_NR_ITEMS(src_bi.bi_bh) - mov_num), mov_num, mov_bytes);
+ leaf_delete_items(&src_bi, first_last,
+ (first_last ==
+ FIRST_TO_LAST) ? 0 : (B_NR_ITEMS(src_bi.bi_bh) -
+ mov_num), mov_num, mov_bytes);
-
- return ret_value;
+ return ret_value;
}
-
/* Shift shift_num items (and shift_bytes of last shifted item if shift_bytes != -1)
from S[0] to L[0] and replace the delimiting key */
-int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes)
+int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes)
{
- struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path);
- int i;
+ struct buffer_head *S0 = PATH_PLAST_BUFFER(tb->tb_path);
+ int i;
- /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */
- i = leaf_move_items (LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, NULL);
+ /* move shift_num (and shift_bytes bytes) items from S[0] to left neighbor L[0] */
+ i = leaf_move_items(LEAF_FROM_S_TO_L, tb, shift_num, shift_bytes, NULL);
- if ( shift_num ) {
- if (B_NR_ITEMS (S0) == 0) { /* number of items in S[0] == 0 */
+ if (shift_num) {
+ if (B_NR_ITEMS(S0) == 0) { /* number of items in S[0] == 0 */
- RFALSE( shift_bytes != -1,
- "vs-10270: S0 is empty now, but shift_bytes != -1 (%d)",
- shift_bytes);
+ RFALSE(shift_bytes != -1,
+ "vs-10270: S0 is empty now, but shift_bytes != -1 (%d)",
+ shift_bytes);
#ifdef CONFIG_REISERFS_CHECK
- if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) {
- print_cur_tb ("vs-10275");
- reiserfs_panic (tb->tb_sb, "vs-10275: leaf_shift_left: balance condition corrupted (%c)", tb->tb_mode);
- }
+ if (tb->tb_mode == M_PASTE || tb->tb_mode == M_INSERT) {
+ print_cur_tb("vs-10275");
+ reiserfs_panic(tb->tb_sb,
+ "vs-10275: leaf_shift_left: balance condition corrupted (%c)",
+ tb->tb_mode);
+ }
#endif
- if (PATH_H_POSITION (tb->tb_path, 1) == 0)
- replace_key (tb, tb->CFL[0], tb->lkey[0], PATH_H_PPARENT (tb->tb_path, 0), 0);
-
- } else {
- /* replace lkey in CFL[0] by 0-th key from S[0]; */
- replace_key (tb, tb->CFL[0], tb->lkey[0], S0, 0);
-
- RFALSE( (shift_bytes != -1 &&
- !(is_direntry_le_ih (B_N_PITEM_HEAD (S0, 0))
- && !I_ENTRY_COUNT (B_N_PITEM_HEAD (S0, 0)))) &&
- (!op_is_left_mergeable (B_N_PKEY (S0, 0), S0->b_size)),
- "vs-10280: item must be mergeable");
- }
- }
-
- return i;
-}
-
-
-
+ if (PATH_H_POSITION(tb->tb_path, 1) == 0)
+ replace_key(tb, tb->CFL[0], tb->lkey[0],
+ PATH_H_PPARENT(tb->tb_path, 0), 0);
+
+ } else {
+ /* replace lkey in CFL[0] by 0-th key from S[0]; */
+ replace_key(tb, tb->CFL[0], tb->lkey[0], S0, 0);
+
+ RFALSE((shift_bytes != -1 &&
+ !(is_direntry_le_ih(B_N_PITEM_HEAD(S0, 0))
+ && !I_ENTRY_COUNT(B_N_PITEM_HEAD(S0, 0)))) &&
+ (!op_is_left_mergeable
+ (B_N_PKEY(S0, 0), S0->b_size)),
+ "vs-10280: item must be mergeable");
+ }
+ }
+ return i;
+}
/* CLEANING STOPPED HERE */
-
-
-
/* Shift shift_num (shift_bytes) items from S[0] to the right neighbor, and replace the delimiting key */
-int leaf_shift_right(
- struct tree_balance * tb,
- int shift_num,
- int shift_bytes
- )
+int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes)
{
- // struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path);
- int ret_value;
+ // struct buffer_head * S0 = PATH_PLAST_BUFFER (tb->tb_path);
+ int ret_value;
- /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */
- ret_value = leaf_move_items (LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, NULL);
+ /* move shift_num (and shift_bytes) items from S[0] to right neighbor R[0] */
+ ret_value =
+ leaf_move_items(LEAF_FROM_S_TO_R, tb, shift_num, shift_bytes, NULL);
- /* replace rkey in CFR[0] by the 0-th key from R[0] */
- if (shift_num) {
- replace_key (tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
+ /* replace rkey in CFR[0] by the 0-th key from R[0] */
+ if (shift_num) {
+ replace_key(tb, tb->CFR[0], tb->rkey[0], tb->R[0], 0);
- }
+ }
- return ret_value;
+ return ret_value;
}
-
-
-static void leaf_delete_items_entirely (struct buffer_info * bi,
- int first, int del_num);
+static void leaf_delete_items_entirely(struct buffer_info *bi,
+ int first, int del_num);
/* If del_bytes == -1, starting from position 'first' delete del_num items in whole in buffer CUR.
If not.
If last_first == 0. Starting from position 'first' delete del_num-1 items in whole. Delete part of body of
@@ -670,287 +731,292 @@ static void leaf_delete_items_entirely (struct buffer_info * bi,
If last_first == 1. Starting from position 'first+1' delete del_num-1 items in whole. Delete part of body of
the last item . Part defined by del_bytes. Don't delete last item header.
*/
-void leaf_delete_items (struct buffer_info * cur_bi, int last_first,
- int first, int del_num, int del_bytes)
+void leaf_delete_items(struct buffer_info *cur_bi, int last_first,
+ int first, int del_num, int del_bytes)
{
- struct buffer_head * bh;
- int item_amount = B_NR_ITEMS (bh = cur_bi->bi_bh);
-
- RFALSE( !bh, "10155: bh is not defined");
- RFALSE( del_num < 0, "10160: del_num can not be < 0. del_num==%d", del_num);
- RFALSE( first < 0 || first + del_num > item_amount,
- "10165: invalid number of first item to be deleted (%d) or "
- "no so much items (%d) to delete (only %d)",
- first, first + del_num, item_amount);
-
- if ( del_num == 0 )
- return;
-
- if ( first == 0 && del_num == item_amount && del_bytes == -1 ) {
- make_empty_node (cur_bi);
- do_balance_mark_leaf_dirty (cur_bi->tb, bh, 0);
- return;
- }
-
- if ( del_bytes == -1 )
- /* delete del_num items beginning from item in position first */
- leaf_delete_items_entirely (cur_bi, first, del_num);
- else {
- if ( last_first == FIRST_TO_LAST ) {
- /* delete del_num-1 items beginning from item in position first */
- leaf_delete_items_entirely (cur_bi, first, del_num-1);
-
- /* delete the part of the first item of the bh
- do not delete item header
- */
- leaf_cut_from_buffer (cur_bi, 0, 0, del_bytes);
- } else {
- struct item_head * ih;
- int len;
-
- /* delete del_num-1 items beginning from item in position first+1 */
- leaf_delete_items_entirely (cur_bi, first+1, del_num-1);
-
- if (is_direntry_le_ih (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh)-1))) /* the last item is directory */
- /* len = numbers of directory entries in this item */
- len = ih_entry_count(ih);
- else
- /* len = body len of item */
- len = ih_item_len(ih);
-
- /* delete the part of the last item of the bh
- do not delete item header
- */
- leaf_cut_from_buffer (cur_bi, B_NR_ITEMS(bh)-1, len - del_bytes, del_bytes);
+ struct buffer_head *bh;
+ int item_amount = B_NR_ITEMS(bh = cur_bi->bi_bh);
+
+ RFALSE(!bh, "10155: bh is not defined");
+ RFALSE(del_num < 0, "10160: del_num can not be < 0. del_num==%d",
+ del_num);
+ RFALSE(first < 0
+ || first + del_num > item_amount,
+ "10165: invalid number of first item to be deleted (%d) or "
+ "no so much items (%d) to delete (only %d)", first,
+ first + del_num, item_amount);
+
+ if (del_num == 0)
+ return;
+
+ if (first == 0 && del_num == item_amount && del_bytes == -1) {
+ make_empty_node(cur_bi);
+ do_balance_mark_leaf_dirty(cur_bi->tb, bh, 0);
+ return;
}
- }
-}
+ if (del_bytes == -1)
+ /* delete del_num items beginning from item in position first */
+ leaf_delete_items_entirely(cur_bi, first, del_num);
+ else {
+ if (last_first == FIRST_TO_LAST) {
+ /* delete del_num-1 items beginning from item in position first */
+ leaf_delete_items_entirely(cur_bi, first, del_num - 1);
+
+ /* delete the part of the first item of the bh
+ do not delete item header
+ */
+ leaf_cut_from_buffer(cur_bi, 0, 0, del_bytes);
+ } else {
+ struct item_head *ih;
+ int len;
+
+ /* delete del_num-1 items beginning from item in position first+1 */
+ leaf_delete_items_entirely(cur_bi, first + 1,
+ del_num - 1);
+
+ if (is_direntry_le_ih
+ (ih = B_N_PITEM_HEAD(bh, B_NR_ITEMS(bh) - 1)))
+ /* the last item is directory */
+ /* len = numbers of directory entries in this item */
+ len = ih_entry_count(ih);
+ else
+ /* len = body len of item */
+ len = ih_item_len(ih);
+
+ /* delete the part of the last item of the bh
+ do not delete item header
+ */
+ leaf_cut_from_buffer(cur_bi, B_NR_ITEMS(bh) - 1,
+ len - del_bytes, del_bytes);
+ }
+ }
+}
/* insert item into the leaf node in position before */
-void leaf_insert_into_buf (struct buffer_info * bi, int before,
- struct item_head * inserted_item_ih,
- const char * inserted_item_body,
- int zeros_number)
+void leaf_insert_into_buf(struct buffer_info *bi, int before,
+ struct item_head *inserted_item_ih,
+ const char *inserted_item_body, int zeros_number)
{
- struct buffer_head * bh = bi->bi_bh;
- int nr, free_space;
- struct block_head * blkh;
- struct item_head * ih;
- int i;
- int last_loc, unmoved_loc;
- char * to;
-
-
- blkh = B_BLK_HEAD(bh);
- nr = blkh_nr_item(blkh);
- free_space = blkh_free_space( blkh );
-
- /* check free space */
- RFALSE( free_space < ih_item_len(inserted_item_ih) + IH_SIZE,
- "vs-10170: not enough free space in block %z, new item %h",
- bh, inserted_item_ih);
- RFALSE( zeros_number > ih_item_len(inserted_item_ih),
- "vs-10172: zero number == %d, item length == %d",
- zeros_number, ih_item_len(inserted_item_ih));
-
-
- /* get item new item must be inserted before */
- ih = B_N_PITEM_HEAD (bh, before);
-
- /* prepare space for the body of new item */
- last_loc = nr ? ih_location( &(ih[nr - before - 1]) ) : bh->b_size;
- unmoved_loc = before ? ih_location( ih-1 ) : bh->b_size;
-
-
- memmove (bh->b_data + last_loc - ih_item_len(inserted_item_ih),
- bh->b_data + last_loc, unmoved_loc - last_loc);
-
- to = bh->b_data + unmoved_loc - ih_item_len(inserted_item_ih);
- memset (to, 0, zeros_number);
- to += zeros_number;
-
- /* copy body to prepared space */
- if (inserted_item_body)
- memmove (to, inserted_item_body, ih_item_len(inserted_item_ih) - zeros_number);
- else
- memset(to, '\0', ih_item_len(inserted_item_ih) - zeros_number);
-
- /* insert item header */
- memmove (ih + 1, ih, IH_SIZE * (nr - before));
- memmove (ih, inserted_item_ih, IH_SIZE);
-
- /* change locations */
- for (i = before; i < nr + 1; i ++)
- {
- unmoved_loc -= ih_item_len( &(ih[i-before]));
- put_ih_location( &(ih[i-before]), unmoved_loc );
- }
-
- /* sizes, free space, item number */
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) + 1 );
- set_blkh_free_space( blkh,
- free_space - (IH_SIZE + ih_item_len(inserted_item_ih ) ) );
- do_balance_mark_leaf_dirty (bi->tb, bh, 1);
-
- if (bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) + (IH_SIZE + ih_item_len(inserted_item_ih)));
- do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
- }
-}
+ struct buffer_head *bh = bi->bi_bh;
+ int nr, free_space;
+ struct block_head *blkh;
+ struct item_head *ih;
+ int i;
+ int last_loc, unmoved_loc;
+ char *to;
+
+ blkh = B_BLK_HEAD(bh);
+ nr = blkh_nr_item(blkh);
+ free_space = blkh_free_space(blkh);
+
+ /* check free space */
+ RFALSE(free_space < ih_item_len(inserted_item_ih) + IH_SIZE,
+ "vs-10170: not enough free space in block %z, new item %h",
+ bh, inserted_item_ih);
+ RFALSE(zeros_number > ih_item_len(inserted_item_ih),
+ "vs-10172: zero number == %d, item length == %d",
+ zeros_number, ih_item_len(inserted_item_ih));
+
+ /* get item new item must be inserted before */
+ ih = B_N_PITEM_HEAD(bh, before);
+
+ /* prepare space for the body of new item */
+ last_loc = nr ? ih_location(&(ih[nr - before - 1])) : bh->b_size;
+ unmoved_loc = before ? ih_location(ih - 1) : bh->b_size;
+
+ memmove(bh->b_data + last_loc - ih_item_len(inserted_item_ih),
+ bh->b_data + last_loc, unmoved_loc - last_loc);
+
+ to = bh->b_data + unmoved_loc - ih_item_len(inserted_item_ih);
+ memset(to, 0, zeros_number);
+ to += zeros_number;
+
+ /* copy body to prepared space */
+ if (inserted_item_body)
+ memmove(to, inserted_item_body,
+ ih_item_len(inserted_item_ih) - zeros_number);
+ else
+ memset(to, '\0', ih_item_len(inserted_item_ih) - zeros_number);
+
+ /* insert item header */
+ memmove(ih + 1, ih, IH_SIZE * (nr - before));
+ memmove(ih, inserted_item_ih, IH_SIZE);
+
+ /* change locations */
+ for (i = before; i < nr + 1; i++) {
+ unmoved_loc -= ih_item_len(&(ih[i - before]));
+ put_ih_location(&(ih[i - before]), unmoved_loc);
+ }
+ /* sizes, free space, item number */
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) + 1);
+ set_blkh_free_space(blkh,
+ free_space - (IH_SIZE +
+ ih_item_len(inserted_item_ih)));
+ do_balance_mark_leaf_dirty(bi->tb, bh, 1);
+
+ if (bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
+ put_dc_size(t_dc,
+ dc_size(t_dc) + (IH_SIZE +
+ ih_item_len(inserted_item_ih)));
+ do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
+ }
+}
/* paste paste_size bytes to affected_item_num-th item.
When item is a directory, this only prepare space for new entries */
-void leaf_paste_in_buffer (struct buffer_info * bi, int affected_item_num,
- int pos_in_item, int paste_size,
- const char * body,
- int zeros_number)
+void leaf_paste_in_buffer(struct buffer_info *bi, int affected_item_num,
+ int pos_in_item, int paste_size,
+ const char *body, int zeros_number)
{
- struct buffer_head * bh = bi->bi_bh;
- int nr, free_space;
- struct block_head * blkh;
- struct item_head * ih;
- int i;
- int last_loc, unmoved_loc;
-
- blkh = B_BLK_HEAD(bh);
- nr = blkh_nr_item(blkh);
- free_space = blkh_free_space(blkh);
-
-
- /* check free space */
- RFALSE( free_space < paste_size,
- "vs-10175: not enough free space: needed %d, available %d",
- paste_size, free_space);
+ struct buffer_head *bh = bi->bi_bh;
+ int nr, free_space;
+ struct block_head *blkh;
+ struct item_head *ih;
+ int i;
+ int last_loc, unmoved_loc;
+
+ blkh = B_BLK_HEAD(bh);
+ nr = blkh_nr_item(blkh);
+ free_space = blkh_free_space(blkh);
+
+ /* check free space */
+ RFALSE(free_space < paste_size,
+ "vs-10175: not enough free space: needed %d, available %d",
+ paste_size, free_space);
#ifdef CONFIG_REISERFS_CHECK
- if (zeros_number > paste_size) {
- print_cur_tb ("10177");
- reiserfs_panic ( NULL, "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d",
- zeros_number, paste_size);
- }
-#endif /* CONFIG_REISERFS_CHECK */
-
-
- /* item to be appended */
- ih = B_N_PITEM_HEAD(bh, affected_item_num);
-
- last_loc = ih_location( &(ih[nr - affected_item_num - 1]) );
- unmoved_loc = affected_item_num ? ih_location( ih-1 ) : bh->b_size;
-
- /* prepare space */
- memmove (bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
- unmoved_loc - last_loc);
-
-
- /* change locations */
- for (i = affected_item_num; i < nr; i ++)
- put_ih_location( &(ih[i-affected_item_num]),
- ih_location( &(ih[i-affected_item_num])) - paste_size );
-
- if ( body ) {
- if (!is_direntry_le_ih (ih)) {
- if (!pos_in_item) {
- /* shift data to right */
- memmove (bh->b_data + ih_location(ih) + paste_size,
- bh->b_data + ih_location(ih), ih_item_len(ih));
- /* paste data in the head of item */
- memset (bh->b_data + ih_location(ih), 0, zeros_number);
- memcpy (bh->b_data + ih_location(ih) + zeros_number, body, paste_size - zeros_number);
- } else {
- memset (bh->b_data + unmoved_loc - paste_size, 0, zeros_number);
- memcpy (bh->b_data + unmoved_loc - paste_size + zeros_number, body, paste_size - zeros_number);
- }
+ if (zeros_number > paste_size) {
+ print_cur_tb("10177");
+ reiserfs_panic(NULL,
+ "vs-10177: leaf_paste_in_buffer: ero number == %d, paste_size == %d",
+ zeros_number, paste_size);
+ }
+#endif /* CONFIG_REISERFS_CHECK */
+
+ /* item to be appended */
+ ih = B_N_PITEM_HEAD(bh, affected_item_num);
+
+ last_loc = ih_location(&(ih[nr - affected_item_num - 1]));
+ unmoved_loc = affected_item_num ? ih_location(ih - 1) : bh->b_size;
+
+ /* prepare space */
+ memmove(bh->b_data + last_loc - paste_size, bh->b_data + last_loc,
+ unmoved_loc - last_loc);
+
+ /* change locations */
+ for (i = affected_item_num; i < nr; i++)
+ put_ih_location(&(ih[i - affected_item_num]),
+ ih_location(&(ih[i - affected_item_num])) -
+ paste_size);
+
+ if (body) {
+ if (!is_direntry_le_ih(ih)) {
+ if (!pos_in_item) {
+ /* shift data to right */
+ memmove(bh->b_data + ih_location(ih) +
+ paste_size,
+ bh->b_data + ih_location(ih),
+ ih_item_len(ih));
+ /* paste data in the head of item */
+ memset(bh->b_data + ih_location(ih), 0,
+ zeros_number);
+ memcpy(bh->b_data + ih_location(ih) +
+ zeros_number, body,
+ paste_size - zeros_number);
+ } else {
+ memset(bh->b_data + unmoved_loc - paste_size, 0,
+ zeros_number);
+ memcpy(bh->b_data + unmoved_loc - paste_size +
+ zeros_number, body,
+ paste_size - zeros_number);
+ }
+ }
+ } else
+ memset(bh->b_data + unmoved_loc - paste_size, '\0', paste_size);
+
+ put_ih_item_len(ih, ih_item_len(ih) + paste_size);
+
+ /* change free space */
+ set_blkh_free_space(blkh, free_space - paste_size);
+
+ do_balance_mark_leaf_dirty(bi->tb, bh, 0);
+
+ if (bi->bi_parent) {
+ struct disk_child *t_dc =
+ B_N_CHILD(bi->bi_parent, bi->bi_position);
+ put_dc_size(t_dc, dc_size(t_dc) + paste_size);
+ do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
}
- }
- else
- memset(bh->b_data + unmoved_loc - paste_size, '\0', paste_size);
-
- put_ih_item_len( ih, ih_item_len(ih) + paste_size );
-
- /* change free space */
- set_blkh_free_space( blkh, free_space - paste_size );
-
- do_balance_mark_leaf_dirty (bi->tb, bh, 0);
-
- if (bi->bi_parent) {
- struct disk_child *t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) + paste_size );
- do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
- }
}
-
/* cuts DEL_COUNT entries beginning from FROM-th entry. Directory item
does not have free space, so it moves DEHs and remaining records as
necessary. Return value is size of removed part of directory item
in bytes. */
-static int leaf_cut_entries (
- struct buffer_head * bh,
- struct item_head * ih,
- int from,
- int del_count
- )
+static int leaf_cut_entries(struct buffer_head *bh,
+ struct item_head *ih, int from, int del_count)
{
- char * item;
- struct reiserfs_de_head * deh;
- int prev_record_offset; /* offset of record, that is (from-1)th */
- char * prev_record; /* */
- int cut_records_len; /* length of all removed records */
- int i;
-
-
- /* make sure, that item is directory and there are enough entries to
- remove */
- RFALSE( !is_direntry_le_ih (ih), "10180: item is not directory item");
- RFALSE( I_ENTRY_COUNT(ih) < from + del_count,
- "10185: item contains not enough entries: entry_cout = %d, from = %d, to delete = %d",
- I_ENTRY_COUNT(ih), from, del_count);
-
- if (del_count == 0)
- return 0;
-
- /* first byte of item */
- item = bh->b_data + ih_location(ih);
-
- /* entry head array */
- deh = B_I_DEH (bh, ih);
-
- /* first byte of remaining entries, those are BEFORE cut entries
- (prev_record) and length of all removed records (cut_records_len) */
- prev_record_offset = (from ? deh_location( &(deh[from - 1])) : ih_item_len(ih));
- cut_records_len = prev_record_offset/*from_record*/ -
- deh_location( &(deh[from + del_count - 1]));
- prev_record = item + prev_record_offset;
-
-
- /* adjust locations of remaining entries */
- for (i = I_ENTRY_COUNT(ih) - 1; i > from + del_count - 1; i --)
- put_deh_location( &(deh[i]),
- deh_location( &deh[i] ) - (DEH_SIZE * del_count ) );
-
- for (i = 0; i < from; i ++)
- put_deh_location( &(deh[i]),
- deh_location( &deh[i] ) - (DEH_SIZE * del_count + cut_records_len) );
-
- put_ih_entry_count( ih, ih_entry_count(ih) - del_count );
-
- /* shift entry head array and entries those are AFTER removed entries */
- memmove ((char *)(deh + from),
- deh + from + del_count,
- prev_record - cut_records_len - (char *)(deh + from + del_count));
-
- /* shift records, those are BEFORE removed entries */
- memmove (prev_record - cut_records_len - DEH_SIZE * del_count,
- prev_record, item + ih_item_len(ih) - prev_record);
-
- return DEH_SIZE * del_count + cut_records_len;
+ char *item;
+ struct reiserfs_de_head *deh;
+ int prev_record_offset; /* offset of record, that is (from-1)th */
+ char *prev_record; /* */
+ int cut_records_len; /* length of all removed records */
+ int i;
+
+ /* make sure, that item is directory and there are enough entries to
+ remove */
+ RFALSE(!is_direntry_le_ih(ih), "10180: item is not directory item");
+ RFALSE(I_ENTRY_COUNT(ih) < from + del_count,
+ "10185: item contains not enough entries: entry_cout = %d, from = %d, to delete = %d",
+ I_ENTRY_COUNT(ih), from, del_count);
+
+ if (del_count == 0)
+ return 0;
+
+ /* first byte of item */
+ item = bh->b_data + ih_location(ih);
+
+ /* entry head array */
+ deh = B_I_DEH(bh, ih);
+
+ /* first byte of remaining entries, those are BEFORE cut entries
+ (prev_record) and length of all removed records (cut_records_len) */
+ prev_record_offset =
+ (from ? deh_location(&(deh[from - 1])) : ih_item_len(ih));
+ cut_records_len = prev_record_offset /*from_record */ -
+ deh_location(&(deh[from + del_count - 1]));
+ prev_record = item + prev_record_offset;
+
+ /* adjust locations of remaining entries */
+ for (i = I_ENTRY_COUNT(ih) - 1; i > from + del_count - 1; i--)
+ put_deh_location(&(deh[i]),
+ deh_location(&deh[i]) -
+ (DEH_SIZE * del_count));
+
+ for (i = 0; i < from; i++)
+ put_deh_location(&(deh[i]),
+ deh_location(&deh[i]) - (DEH_SIZE * del_count +
+ cut_records_len));
+
+ put_ih_entry_count(ih, ih_entry_count(ih) - del_count);
+
+ /* shift entry head array and entries those are AFTER removed entries */
+ memmove((char *)(deh + from),
+ deh + from + del_count,
+ prev_record - cut_records_len - (char *)(deh + from +
+ del_count));
+
+ /* shift records, those are BEFORE removed entries */
+ memmove(prev_record - cut_records_len - DEH_SIZE * del_count,
+ prev_record, item + ih_item_len(ih) - prev_record);
+
+ return DEH_SIZE * del_count + cut_records_len;
}
-
/* when cut item is part of regular file
pos_in_item - first byte that must be cut
cut_size - number of bytes to be cut beginning from pos_in_item
@@ -959,264 +1025,278 @@ static int leaf_cut_entries (
pos_in_item - number of first deleted entry
cut_size - count of deleted entries
*/
-void leaf_cut_from_buffer (struct buffer_info * bi, int cut_item_num,
- int pos_in_item, int cut_size)
+void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
+ int pos_in_item, int cut_size)
{
- int nr;
- struct buffer_head * bh = bi->bi_bh;
- struct block_head * blkh;
- struct item_head * ih;
- int last_loc, unmoved_loc;
- int i;
-
- blkh = B_BLK_HEAD(bh);
- nr = blkh_nr_item(blkh);
-
- /* item head of truncated item */
- ih = B_N_PITEM_HEAD (bh, cut_item_num);
-
- if (is_direntry_le_ih (ih)) {
- /* first cut entry ()*/
- cut_size = leaf_cut_entries (bh, ih, pos_in_item, cut_size);
- if (pos_in_item == 0) {
- /* change key */
- RFALSE( cut_item_num,
- "when 0-th enrty of item is cut, that item must be first in the node, not %d-th", cut_item_num);
- /* change item key by key of first entry in the item */
- set_le_ih_k_offset (ih, deh_offset(B_I_DEH (bh, ih)));
- /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE);*/
- }
- } else {
- /* item is direct or indirect */
- RFALSE( is_statdata_le_ih (ih), "10195: item is stat data");
- RFALSE( pos_in_item && pos_in_item + cut_size != ih_item_len(ih),
- "10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
- ( long unsigned ) pos_in_item, ( long unsigned ) cut_size,
- ( long unsigned ) ih_item_len (ih));
-
- /* shift item body to left if cut is from the head of item */
- if (pos_in_item == 0) {
- memmove( bh->b_data + ih_location(ih),
- bh->b_data + ih_location(ih) + cut_size,
- ih_item_len(ih) - cut_size);
-
- /* change key of item */
- if (is_direct_le_ih (ih))
- set_le_ih_k_offset (ih, le_ih_k_offset (ih) + cut_size);
- else {
- set_le_ih_k_offset (ih, le_ih_k_offset (ih) + (cut_size / UNFM_P_SIZE) * bh->b_size);
- RFALSE( ih_item_len(ih) == cut_size && get_ih_free_space (ih),
- "10205: invalid ih_free_space (%h)", ih);
- }
- }
- }
-
-
- /* location of the last item */
- last_loc = ih_location( &(ih[nr - cut_item_num - 1]) );
-
- /* location of the item, which is remaining at the same place */
- unmoved_loc = cut_item_num ? ih_location(ih-1) : bh->b_size;
-
-
- /* shift */
- memmove (bh->b_data + last_loc + cut_size, bh->b_data + last_loc,
- unmoved_loc - last_loc - cut_size);
-
- /* change item length */
- put_ih_item_len( ih, ih_item_len(ih) - cut_size );
-
- if (is_indirect_le_ih (ih)) {
- if (pos_in_item)
- set_ih_free_space (ih, 0);
- }
-
- /* change locations */
- for (i = cut_item_num; i < nr; i ++)
- put_ih_location( &(ih[i-cut_item_num]), ih_location( &ih[i-cut_item_num]) + cut_size );
-
- /* size, free space */
- set_blkh_free_space( blkh, blkh_free_space(blkh) + cut_size );
-
- do_balance_mark_leaf_dirty (bi->tb, bh, 0);
-
- if (bi->bi_parent) {
- struct disk_child *t_dc;
- t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) - cut_size );
- do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
- }
-}
+ int nr;
+ struct buffer_head *bh = bi->bi_bh;
+ struct block_head *blkh;
+ struct item_head *ih;
+ int last_loc, unmoved_loc;
+ int i;
+
+ blkh = B_BLK_HEAD(bh);
+ nr = blkh_nr_item(blkh);
+
+ /* item head of truncated item */
+ ih = B_N_PITEM_HEAD(bh, cut_item_num);
+
+ if (is_direntry_le_ih(ih)) {
+ /* first cut entry () */
+ cut_size = leaf_cut_entries(bh, ih, pos_in_item, cut_size);
+ if (pos_in_item == 0) {
+ /* change key */
+ RFALSE(cut_item_num,
+ "when 0-th enrty of item is cut, that item must be first in the node, not %d-th",
+ cut_item_num);
+ /* change item key by key of first entry in the item */
+ set_le_ih_k_offset(ih, deh_offset(B_I_DEH(bh, ih)));
+ /*memcpy (&ih->ih_key.k_offset, &(B_I_DEH (bh, ih)->deh_offset), SHORT_KEY_SIZE); */
+ }
+ } else {
+ /* item is direct or indirect */
+ RFALSE(is_statdata_le_ih(ih), "10195: item is stat data");
+ RFALSE(pos_in_item && pos_in_item + cut_size != ih_item_len(ih),
+ "10200: invalid offset (%lu) or trunc_size (%lu) or ih_item_len (%lu)",
+ (long unsigned)pos_in_item, (long unsigned)cut_size,
+ (long unsigned)ih_item_len(ih));
+
+ /* shift item body to left if cut is from the head of item */
+ if (pos_in_item == 0) {
+ memmove(bh->b_data + ih_location(ih),
+ bh->b_data + ih_location(ih) + cut_size,
+ ih_item_len(ih) - cut_size);
+
+ /* change key of item */
+ if (is_direct_le_ih(ih))
+ set_le_ih_k_offset(ih,
+ le_ih_k_offset(ih) +
+ cut_size);
+ else {
+ set_le_ih_k_offset(ih,
+ le_ih_k_offset(ih) +
+ (cut_size / UNFM_P_SIZE) *
+ bh->b_size);
+ RFALSE(ih_item_len(ih) == cut_size
+ && get_ih_free_space(ih),
+ "10205: invalid ih_free_space (%h)", ih);
+ }
+ }
+ }
+
+ /* location of the last item */
+ last_loc = ih_location(&(ih[nr - cut_item_num - 1]));
+
+ /* location of the item, which is remaining at the same place */
+ unmoved_loc = cut_item_num ? ih_location(ih - 1) : bh->b_size;
+
+ /* shift */
+ memmove(bh->b_data + last_loc + cut_size, bh->b_data + last_loc,
+ unmoved_loc - last_loc - cut_size);
+
+ /* change item length */
+ put_ih_item_len(ih, ih_item_len(ih) - cut_size);
+ if (is_indirect_le_ih(ih)) {
+ if (pos_in_item)
+ set_ih_free_space(ih, 0);
+ }
+
+ /* change locations */
+ for (i = cut_item_num; i < nr; i++)
+ put_ih_location(&(ih[i - cut_item_num]),
+ ih_location(&ih[i - cut_item_num]) + cut_size);
+
+ /* size, free space */
+ set_blkh_free_space(blkh, blkh_free_space(blkh) + cut_size);
+
+ do_balance_mark_leaf_dirty(bi->tb, bh, 0);
+
+ if (bi->bi_parent) {
+ struct disk_child *t_dc;
+ t_dc = B_N_CHILD(bi->bi_parent, bi->bi_position);
+ put_dc_size(t_dc, dc_size(t_dc) - cut_size);
+ do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
+ }
+}
/* delete del_num items from buffer starting from the first'th item */
-static void leaf_delete_items_entirely (struct buffer_info * bi,
- int first, int del_num)
+static void leaf_delete_items_entirely(struct buffer_info *bi,
+ int first, int del_num)
{
- struct buffer_head * bh = bi->bi_bh;
- int nr;
- int i, j;
- int last_loc, last_removed_loc;
- struct block_head * blkh;
- struct item_head * ih;
-
- RFALSE( bh == NULL, "10210: buffer is 0");
- RFALSE( del_num < 0, "10215: del_num less than 0 (%d)", del_num);
-
- if (del_num == 0)
- return;
-
- blkh = B_BLK_HEAD(bh);
- nr = blkh_nr_item(blkh);
-
- RFALSE( first < 0 || first + del_num > nr,
- "10220: first=%d, number=%d, there is %d items", first, del_num, nr);
-
- if (first == 0 && del_num == nr) {
- /* this does not work */
- make_empty_node (bi);
-
- do_balance_mark_leaf_dirty (bi->tb, bh, 0);
- return;
- }
-
- ih = B_N_PITEM_HEAD (bh, first);
-
- /* location of unmovable item */
- j = (first == 0) ? bh->b_size : ih_location(ih-1);
-
- /* delete items */
- last_loc = ih_location( &(ih[nr-1-first]) );
- last_removed_loc = ih_location( &(ih[del_num-1]) );
-
- memmove (bh->b_data + last_loc + j - last_removed_loc,
- bh->b_data + last_loc, last_removed_loc - last_loc);
-
- /* delete item headers */
- memmove (ih, ih + del_num, (nr - first - del_num) * IH_SIZE);
-
- /* change item location */
- for (i = first; i < nr - del_num; i ++)
- put_ih_location( &(ih[i-first]), ih_location( &(ih[i-first]) ) + (j - last_removed_loc) );
-
- /* sizes, item number */
- set_blkh_nr_item( blkh, blkh_nr_item(blkh) - del_num );
- set_blkh_free_space( blkh, blkh_free_space(blkh) + (j - last_removed_loc + IH_SIZE * del_num) );
-
- do_balance_mark_leaf_dirty (bi->tb, bh, 0);
-
- if (bi->bi_parent) {
- struct disk_child *t_dc = B_N_CHILD (bi->bi_parent, bi->bi_position);
- put_dc_size( t_dc, dc_size(t_dc) -
- (j - last_removed_loc + IH_SIZE * del_num));
- do_balance_mark_internal_dirty (bi->tb, bi->bi_parent, 0);
- }
-}
+ struct buffer_head *bh = bi->bi_bh;
+ int nr;
+ int i, j;
+ int last_loc, last_removed_loc;
+ struct block_head *blkh;
+ struct item_head *ih;
+
+ RFALSE(bh == NULL, "10210: buffer is 0");
+ RFALSE(del_num < 0, "10215: del_num less than 0 (%d)", del_num);
+
+ if (del_num == 0)
+ return;
+
+ blkh = B_BLK_HEAD(bh);
+ nr = blkh_nr_item(blkh);
+ RFALSE(first < 0 || first + del_num > nr,
+ "10220: first=%d, number=%d, there is %d items", first, del_num,
+ nr);
+
+ if (first == 0 && del_num == nr) {
+ /* this does not work */
+ make_empty_node(bi);
+
+ do_balance_mark_leaf_dirty(bi->tb, bh, 0);
+ return;
+ }
+ ih = B_N_PITEM_HEAD(bh, first);
+ /* location of unmovable item */
+ j = (first == 0) ? bh->b_size : ih_location(ih - 1);
+ /* delete items */
+ last_loc = ih_location(&(ih[nr - 1 - first]));
+ last_removed_loc = ih_location(&(ih[del_num - 1]));
+
+ memmove(bh->b_data + last_loc + j - last_removed_loc,
+ bh->b_data + last_loc, last_removed_loc - last_loc);
+
+ /* delete item headers */
+ memmove(ih, ih + del_num, (nr - first - del_num) * IH_SIZE);
+
+ /* change item location */
+ for (i = first; i < nr - del_num; i++)
+ put_ih_location(&(ih[i - first]),
+ ih_location(&(ih[i - first])) + (j -
+ last_removed_loc));
+
+ /* sizes, item number */
+ set_blkh_nr_item(blkh, blkh_nr_item(blkh) - del_num);
+ set_blkh_free_space(blkh,
+ blkh_free_space(blkh) + (j - last_removed_loc +
+ IH_SIZE * del_num));
+
+ do_balance_mark_leaf_dirty(bi->tb, bh, 0);
+
+ if (bi->bi_parent) {
+ struct disk_child *t_dc =
+ B_N_CHILD(bi->bi_parent, bi->bi_position);
+ put_dc_size(t_dc,
+ dc_size(t_dc) - (j - last_removed_loc +
+ IH_SIZE * del_num));
+ do_balance_mark_internal_dirty(bi->tb, bi->bi_parent, 0);
+ }
+}
/* paste new_entry_count entries (new_dehs, records) into position before to item_num-th item */
-void leaf_paste_entries (
- struct buffer_head * bh,
+void leaf_paste_entries(struct buffer_head *bh,
int item_num,
int before,
int new_entry_count,
- struct reiserfs_de_head * new_dehs,
- const char * records,
- int paste_size
- )
+ struct reiserfs_de_head *new_dehs,
+ const char *records, int paste_size)
{
- struct item_head * ih;
- char * item;
- struct reiserfs_de_head * deh;
- char * insert_point;
- int i, old_entry_num;
-
- if (new_entry_count == 0)
- return;
-
- ih = B_N_PITEM_HEAD(bh, item_num);
-
- /* make sure, that item is directory, and there are enough records in it */
- RFALSE( !is_direntry_le_ih (ih), "10225: item is not directory item");
- RFALSE( I_ENTRY_COUNT (ih) < before,
- "10230: there are no entry we paste entries before. entry_count = %d, before = %d",
- I_ENTRY_COUNT (ih), before);
-
-
- /* first byte of dest item */
- item = bh->b_data + ih_location(ih);
-
- /* entry head array */
- deh = B_I_DEH (bh, ih);
-
- /* new records will be pasted at this point */
- insert_point = item + (before ? deh_location( &(deh[before - 1])) : (ih_item_len(ih) - paste_size));
-
- /* adjust locations of records that will be AFTER new records */
- for (i = I_ENTRY_COUNT(ih) - 1; i >= before; i --)
- put_deh_location( &(deh[i]),
- deh_location(&(deh[i])) + (DEH_SIZE * new_entry_count ));
-
- /* adjust locations of records that will be BEFORE new records */
- for (i = 0; i < before; i ++)
- put_deh_location( &(deh[i]), deh_location(&(deh[i])) + paste_size );
-
- old_entry_num = I_ENTRY_COUNT(ih);
- put_ih_entry_count( ih, ih_entry_count(ih) + new_entry_count );
-
- /* prepare space for pasted records */
- memmove (insert_point + paste_size, insert_point, item + (ih_item_len(ih) - paste_size) - insert_point);
-
- /* copy new records */
- memcpy (insert_point + DEH_SIZE * new_entry_count, records,
- paste_size - DEH_SIZE * new_entry_count);
-
- /* prepare space for new entry heads */
- deh += before;
- memmove ((char *)(deh + new_entry_count), deh, insert_point - (char *)deh);
-
- /* copy new entry heads */
- deh = (struct reiserfs_de_head *)((char *)deh);
- memcpy (deh, new_dehs, DEH_SIZE * new_entry_count);
-
- /* set locations of new records */
- for (i = 0; i < new_entry_count; i ++)
- {
- put_deh_location( &(deh[i]),
- deh_location( &(deh[i] )) +
- (- deh_location( &(new_dehs[new_entry_count - 1])) +
- insert_point + DEH_SIZE * new_entry_count - item));
- }
-
-
- /* change item key if necessary (when we paste before 0-th entry */
- if (!before)
- {
- set_le_ih_k_offset (ih, deh_offset(new_dehs));
+ struct item_head *ih;
+ char *item;
+ struct reiserfs_de_head *deh;
+ char *insert_point;
+ int i, old_entry_num;
+
+ if (new_entry_count == 0)
+ return;
+
+ ih = B_N_PITEM_HEAD(bh, item_num);
+
+ /* make sure, that item is directory, and there are enough records in it */
+ RFALSE(!is_direntry_le_ih(ih), "10225: item is not directory item");
+ RFALSE(I_ENTRY_COUNT(ih) < before,
+ "10230: there are no entry we paste entries before. entry_count = %d, before = %d",
+ I_ENTRY_COUNT(ih), before);
+
+ /* first byte of dest item */
+ item = bh->b_data + ih_location(ih);
+
+ /* entry head array */
+ deh = B_I_DEH(bh, ih);
+
+ /* new records will be pasted at this point */
+ insert_point =
+ item +
+ (before ? deh_location(&(deh[before - 1]))
+ : (ih_item_len(ih) - paste_size));
+
+ /* adjust locations of records that will be AFTER new records */
+ for (i = I_ENTRY_COUNT(ih) - 1; i >= before; i--)
+ put_deh_location(&(deh[i]),
+ deh_location(&(deh[i])) +
+ (DEH_SIZE * new_entry_count));
+
+ /* adjust locations of records that will be BEFORE new records */
+ for (i = 0; i < before; i++)
+ put_deh_location(&(deh[i]),
+ deh_location(&(deh[i])) + paste_size);
+
+ old_entry_num = I_ENTRY_COUNT(ih);
+ put_ih_entry_count(ih, ih_entry_count(ih) + new_entry_count);
+
+ /* prepare space for pasted records */
+ memmove(insert_point + paste_size, insert_point,
+ item + (ih_item_len(ih) - paste_size) - insert_point);
+
+ /* copy new records */
+ memcpy(insert_point + DEH_SIZE * new_entry_count, records,
+ paste_size - DEH_SIZE * new_entry_count);
+
+ /* prepare space for new entry heads */
+ deh += before;
+ memmove((char *)(deh + new_entry_count), deh,
+ insert_point - (char *)deh);
+
+ /* copy new entry heads */
+ deh = (struct reiserfs_de_head *)((char *)deh);
+ memcpy(deh, new_dehs, DEH_SIZE * new_entry_count);
+
+ /* set locations of new records */
+ for (i = 0; i < new_entry_count; i++) {
+ put_deh_location(&(deh[i]),
+ deh_location(&(deh[i])) +
+ (-deh_location
+ (&(new_dehs[new_entry_count - 1])) +
+ insert_point + DEH_SIZE * new_entry_count -
+ item));
+ }
+
+ /* change item key if necessary (when we paste before 0-th entry */
+ if (!before) {
+ set_le_ih_k_offset(ih, deh_offset(new_dehs));
/* memcpy (&ih->ih_key.k_offset,
&new_dehs->deh_offset, SHORT_KEY_SIZE);*/
- }
-
+ }
#ifdef CONFIG_REISERFS_CHECK
- {
- int prev, next;
- /* check record locations */
- deh = B_I_DEH (bh, ih);
- for (i = 0; i < I_ENTRY_COUNT(ih); i ++) {
- next = (i < I_ENTRY_COUNT(ih) - 1) ? deh_location( &(deh[i + 1])) : 0;
- prev = (i != 0) ? deh_location( &(deh[i - 1]) ) : 0;
-
- if (prev && prev <= deh_location( &(deh[i])))
- reiserfs_warning (NULL, "vs-10240: leaf_paste_entries: directory item (%h) corrupted (prev %a, cur(%d) %a)",
- ih, deh + i - 1, i, deh + i);
- if (next && next >= deh_location( &(deh[i])))
- reiserfs_warning (NULL, "vs-10250: leaf_paste_entries: directory item (%h) corrupted (cur(%d) %a, next %a)",
- ih, i, deh + i, deh + i + 1);
- }
- }
+ {
+ int prev, next;
+ /* check record locations */
+ deh = B_I_DEH(bh, ih);
+ for (i = 0; i < I_ENTRY_COUNT(ih); i++) {
+ next =
+ (i <
+ I_ENTRY_COUNT(ih) -
+ 1) ? deh_location(&(deh[i + 1])) : 0;
+ prev = (i != 0) ? deh_location(&(deh[i - 1])) : 0;
+
+ if (prev && prev <= deh_location(&(deh[i])))
+ reiserfs_warning(NULL,
+ "vs-10240: leaf_paste_entries: directory item (%h) corrupted (prev %a, cur(%d) %a)",
+ ih, deh + i - 1, i, deh + i);
+ if (next && next >= deh_location(&(deh[i])))
+ reiserfs_warning(NULL,
+ "vs-10250: leaf_paste_entries: directory item (%h) corrupted (cur(%d) %a, next %a)",
+ ih, i, deh + i, deh + i + 1);
+ }
+ }
#endif
}
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 7d4dc5f5aa8b..a20bbc1642dc 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -25,86 +25,85 @@
// directory item contains array of entry headers. This performs
// binary search through that array
-static int bin_search_in_dir_item (struct reiserfs_dir_entry * de, loff_t off)
+static int bin_search_in_dir_item(struct reiserfs_dir_entry *de, loff_t off)
{
- struct item_head * ih = de->de_ih;
- struct reiserfs_de_head * deh = de->de_deh;
- int rbound, lbound, j;
-
- lbound = 0;
- rbound = I_ENTRY_COUNT (ih) - 1;
-
- for (j = (rbound + lbound) / 2; lbound <= rbound; j = (rbound + lbound) / 2) {
- if (off < deh_offset (deh + j)) {
- rbound = j - 1;
- continue;
+ struct item_head *ih = de->de_ih;
+ struct reiserfs_de_head *deh = de->de_deh;
+ int rbound, lbound, j;
+
+ lbound = 0;
+ rbound = I_ENTRY_COUNT(ih) - 1;
+
+ for (j = (rbound + lbound) / 2; lbound <= rbound;
+ j = (rbound + lbound) / 2) {
+ if (off < deh_offset(deh + j)) {
+ rbound = j - 1;
+ continue;
+ }
+ if (off > deh_offset(deh + j)) {
+ lbound = j + 1;
+ continue;
+ }
+ // this is not name found, but matched third key component
+ de->de_entry_num = j;
+ return NAME_FOUND;
}
- if (off > deh_offset (deh + j)) {
- lbound = j + 1;
- continue;
- }
- // this is not name found, but matched third key component
- de->de_entry_num = j;
- return NAME_FOUND;
- }
- de->de_entry_num = lbound;
- return NAME_NOT_FOUND;
+ de->de_entry_num = lbound;
+ return NAME_NOT_FOUND;
}
-
// comment? maybe something like set de to point to what the path points to?
-static inline void set_de_item_location (struct reiserfs_dir_entry * de, struct path * path)
+static inline void set_de_item_location(struct reiserfs_dir_entry *de,
+ struct path *path)
{
- de->de_bh = get_last_bh (path);
- de->de_ih = get_ih (path);
- de->de_deh = B_I_DEH (de->de_bh, de->de_ih);
- de->de_item_num = PATH_LAST_POSITION (path);
-}
-
+ de->de_bh = get_last_bh(path);
+ de->de_ih = get_ih(path);
+ de->de_deh = B_I_DEH(de->de_bh, de->de_ih);
+ de->de_item_num = PATH_LAST_POSITION(path);
+}
// de_bh, de_ih, de_deh (points to first element of array), de_item_num is set
-inline void set_de_name_and_namelen (struct reiserfs_dir_entry * de)
+inline void set_de_name_and_namelen(struct reiserfs_dir_entry *de)
{
- struct reiserfs_de_head * deh = de->de_deh + de->de_entry_num;
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
- if (de->de_entry_num >= ih_entry_count (de->de_ih))
- BUG ();
+ if (de->de_entry_num >= ih_entry_count(de->de_ih))
+ BUG();
- de->de_entrylen = entry_length (de->de_bh, de->de_ih, de->de_entry_num);
- de->de_namelen = de->de_entrylen - (de_with_sd (deh) ? SD_SIZE : 0);
- de->de_name = B_I_PITEM (de->de_bh, de->de_ih) + deh_location(deh);
- if (de->de_name[de->de_namelen - 1] == 0)
- de->de_namelen = strlen (de->de_name);
+ de->de_entrylen = entry_length(de->de_bh, de->de_ih, de->de_entry_num);
+ de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0);
+ de->de_name = B_I_PITEM(de->de_bh, de->de_ih) + deh_location(deh);
+ if (de->de_name[de->de_namelen - 1] == 0)
+ de->de_namelen = strlen(de->de_name);
}
-
// what entry points to
-static inline void set_de_object_key (struct reiserfs_dir_entry * de)
+static inline void set_de_object_key(struct reiserfs_dir_entry *de)
{
- if (de->de_entry_num >= ih_entry_count (de->de_ih))
- BUG ();
- de->de_dir_id = deh_dir_id( &(de->de_deh[de->de_entry_num]));
- de->de_objectid = deh_objectid( &(de->de_deh[de->de_entry_num]));
+ if (de->de_entry_num >= ih_entry_count(de->de_ih))
+ BUG();
+ de->de_dir_id = deh_dir_id(&(de->de_deh[de->de_entry_num]));
+ de->de_objectid = deh_objectid(&(de->de_deh[de->de_entry_num]));
}
-
-static inline void store_de_entry_key (struct reiserfs_dir_entry * de)
+static inline void store_de_entry_key(struct reiserfs_dir_entry *de)
{
- struct reiserfs_de_head * deh = de->de_deh + de->de_entry_num;
-
- if (de->de_entry_num >= ih_entry_count (de->de_ih))
- BUG ();
-
- /* store key of the found entry */
- de->de_entry_key.version = KEY_FORMAT_3_5;
- de->de_entry_key.on_disk_key.k_dir_id = le32_to_cpu (de->de_ih->ih_key.k_dir_id);
- de->de_entry_key.on_disk_key.k_objectid = le32_to_cpu (de->de_ih->ih_key.k_objectid);
- set_cpu_key_k_offset (&(de->de_entry_key), deh_offset (deh));
- set_cpu_key_k_type (&(de->de_entry_key), TYPE_DIRENTRY);
+ struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num;
+
+ if (de->de_entry_num >= ih_entry_count(de->de_ih))
+ BUG();
+
+ /* store key of the found entry */
+ de->de_entry_key.version = KEY_FORMAT_3_5;
+ de->de_entry_key.on_disk_key.k_dir_id =
+ le32_to_cpu(de->de_ih->ih_key.k_dir_id);
+ de->de_entry_key.on_disk_key.k_objectid =
+ le32_to_cpu(de->de_ih->ih_key.k_objectid);
+ set_cpu_key_k_offset(&(de->de_entry_key), deh_offset(deh));
+ set_cpu_key_k_type(&(de->de_entry_key), TYPE_DIRENTRY);
}
-
/* We assign a key to each directory item, and place multiple entries
in a single directory item. A directory item has a key equal to the
key of the first directory entry in it.
@@ -117,58 +116,60 @@ entry position in the item
*/
/* The function is NOT SCHEDULE-SAFE! */
-int search_by_entry_key (struct super_block * sb, const struct cpu_key * key,
- struct path * path, struct reiserfs_dir_entry * de)
+int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
+ struct path *path, struct reiserfs_dir_entry *de)
{
- int retval;
-
- retval = search_item (sb, key, path);
- switch (retval) {
- case ITEM_NOT_FOUND:
- if (!PATH_LAST_POSITION (path)) {
- reiserfs_warning (sb, "vs-7000: search_by_entry_key: search_by_key returned item position == 0");
- pathrelse(path) ;
- return IO_ERROR ;
+ int retval;
+
+ retval = search_item(sb, key, path);
+ switch (retval) {
+ case ITEM_NOT_FOUND:
+ if (!PATH_LAST_POSITION(path)) {
+ reiserfs_warning(sb,
+ "vs-7000: search_by_entry_key: search_by_key returned item position == 0");
+ pathrelse(path);
+ return IO_ERROR;
+ }
+ PATH_LAST_POSITION(path)--;
+
+ case ITEM_FOUND:
+ break;
+
+ case IO_ERROR:
+ return retval;
+
+ default:
+ pathrelse(path);
+ reiserfs_warning(sb,
+ "vs-7002: search_by_entry_key: no path to here");
+ return IO_ERROR;
}
- PATH_LAST_POSITION (path) --;
-
- case ITEM_FOUND:
- break;
-
- case IO_ERROR:
- return retval;
- default:
- pathrelse (path);
- reiserfs_warning (sb, "vs-7002: search_by_entry_key: no path to here");
- return IO_ERROR;
- }
-
- set_de_item_location (de, path);
+ set_de_item_location(de, path);
#ifdef CONFIG_REISERFS_CHECK
- if (!is_direntry_le_ih (de->de_ih) ||
- COMP_SHORT_KEYS (&(de->de_ih->ih_key), key)) {
- print_block (de->de_bh, 0, -1, -1);
- reiserfs_panic (sb, "vs-7005: search_by_entry_key: found item %h is not directory item or "
- "does not belong to the same directory as key %K", de->de_ih, key);
- }
-#endif /* CONFIG_REISERFS_CHECK */
-
- /* binary search in directory item by third componen t of the
- key. sets de->de_entry_num of de */
- retval = bin_search_in_dir_item (de, cpu_key_k_offset (key));
- path->pos_in_item = de->de_entry_num;
- if (retval != NAME_NOT_FOUND) {
- // ugly, but rename needs de_bh, de_deh, de_name, de_namelen, de_objectid set
- set_de_name_and_namelen (de);
- set_de_object_key (de);
- }
- return retval;
+ if (!is_direntry_le_ih(de->de_ih) ||
+ COMP_SHORT_KEYS(&(de->de_ih->ih_key), key)) {
+ print_block(de->de_bh, 0, -1, -1);
+ reiserfs_panic(sb,
+ "vs-7005: search_by_entry_key: found item %h is not directory item or "
+ "does not belong to the same directory as key %K",
+ de->de_ih, key);
+ }
+#endif /* CONFIG_REISERFS_CHECK */
+
+ /* binary search in directory item by third componen t of the
+ key. sets de->de_entry_num of de */
+ retval = bin_search_in_dir_item(de, cpu_key_k_offset(key));
+ path->pos_in_item = de->de_entry_num;
+ if (retval != NAME_NOT_FOUND) {
+ // ugly, but rename needs de_bh, de_deh, de_name, de_namelen, de_objectid set
+ set_de_name_and_namelen(de);
+ set_de_object_key(de);
+ }
+ return retval;
}
-
-
/* Keyed 32-bit hash function using TEA in a Davis-Meyer function */
/* The third component is hashed, and you can choose from more than
@@ -176,197 +177,210 @@ int search_by_entry_key (struct super_block * sb, const struct cpu_key * key,
but are thought about. This function should be moved to hashes.c
Jedi, please do so. -Hans */
-static __u32 get_third_component (struct super_block * s,
- const char * name, int len)
+static __u32 get_third_component(struct super_block *s,
+ const char *name, int len)
{
- __u32 res;
-
- if (!len || (len == 1 && name[0] == '.'))
- return DOT_OFFSET;
- if (len == 2 && name[0] == '.' && name[1] == '.')
- return DOT_DOT_OFFSET;
-
- res = REISERFS_SB(s)->s_hash_function (name, len);
-
- // take bits from 7-th to 30-th including both bounds
- res = GET_HASH_VALUE(res);
- if (res == 0)
- // needed to have no names before "." and ".." those have hash
- // value == 0 and generation conters 1 and 2 accordingly
- res = 128;
- return res + MAX_GENERATION_NUMBER;
+ __u32 res;
+
+ if (!len || (len == 1 && name[0] == '.'))
+ return DOT_OFFSET;
+ if (len == 2 && name[0] == '.' && name[1] == '.')
+ return DOT_DOT_OFFSET;
+
+ res = REISERFS_SB(s)->s_hash_function(name, len);
+
+ // take bits from 7-th to 30-th including both bounds
+ res = GET_HASH_VALUE(res);
+ if (res == 0)
+ // needed to have no names before "." and ".." those have hash
+ // value == 0 and generation conters 1 and 2 accordingly
+ res = 128;
+ return res + MAX_GENERATION_NUMBER;
}
-
-static int reiserfs_match (struct reiserfs_dir_entry * de,
- const char * name, int namelen)
+static int reiserfs_match(struct reiserfs_dir_entry *de,
+ const char *name, int namelen)
{
- int retval = NAME_NOT_FOUND;
+ int retval = NAME_NOT_FOUND;
- if ((namelen == de->de_namelen) &&
- !memcmp(de->de_name, name, de->de_namelen))
- retval = (de_visible (de->de_deh + de->de_entry_num) ? NAME_FOUND : NAME_FOUND_INVISIBLE);
+ if ((namelen == de->de_namelen) &&
+ !memcmp(de->de_name, name, de->de_namelen))
+ retval =
+ (de_visible(de->de_deh + de->de_entry_num) ? NAME_FOUND :
+ NAME_FOUND_INVISIBLE);
- return retval;
+ return retval;
}
-
/* de's de_bh, de_ih, de_deh, de_item_num, de_entry_num are set already */
/* used when hash collisions exist */
-
-static int linear_search_in_dir_item (struct cpu_key * key, struct reiserfs_dir_entry * de,
- const char * name, int namelen)
+static int linear_search_in_dir_item(struct cpu_key *key,
+ struct reiserfs_dir_entry *de,
+ const char *name, int namelen)
{
- struct reiserfs_de_head * deh = de->de_deh;
- int retval;
- int i;
+ struct reiserfs_de_head *deh = de->de_deh;
+ int retval;
+ int i;
- i = de->de_entry_num;
+ i = de->de_entry_num;
- if (i == I_ENTRY_COUNT (de->de_ih) ||
- GET_HASH_VALUE (deh_offset (deh + i)) != GET_HASH_VALUE (cpu_key_k_offset (key))) {
- i --;
- }
+ if (i == I_ENTRY_COUNT(de->de_ih) ||
+ GET_HASH_VALUE(deh_offset(deh + i)) !=
+ GET_HASH_VALUE(cpu_key_k_offset(key))) {
+ i--;
+ }
- RFALSE( de->de_deh != B_I_DEH (de->de_bh, de->de_ih),
- "vs-7010: array of entry headers not found");
+ RFALSE(de->de_deh != B_I_DEH(de->de_bh, de->de_ih),
+ "vs-7010: array of entry headers not found");
- deh += i;
+ deh += i;
- for (; i >= 0; i --, deh --) {
- if (GET_HASH_VALUE (deh_offset (deh)) !=
- GET_HASH_VALUE (cpu_key_k_offset (key))) {
- // hash value does not match, no need to check whole name
- return NAME_NOT_FOUND;
- }
-
- /* mark, that this generation number is used */
- if (de->de_gen_number_bit_string)
- set_bit (GET_GENERATION_NUMBER (deh_offset (deh)), (unsigned long *)de->de_gen_number_bit_string);
+ for (; i >= 0; i--, deh--) {
+ if (GET_HASH_VALUE(deh_offset(deh)) !=
+ GET_HASH_VALUE(cpu_key_k_offset(key))) {
+ // hash value does not match, no need to check whole name
+ return NAME_NOT_FOUND;
+ }
+
+ /* mark, that this generation number is used */
+ if (de->de_gen_number_bit_string)
+ set_bit(GET_GENERATION_NUMBER(deh_offset(deh)),
+ (unsigned long *)de->de_gen_number_bit_string);
- // calculate pointer to name and namelen
- de->de_entry_num = i;
- set_de_name_and_namelen (de);
+ // calculate pointer to name and namelen
+ de->de_entry_num = i;
+ set_de_name_and_namelen(de);
- if ((retval = reiserfs_match (de, name, namelen)) != NAME_NOT_FOUND) {
- // de's de_name, de_namelen, de_recordlen are set. Fill the rest:
+ if ((retval =
+ reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) {
+ // de's de_name, de_namelen, de_recordlen are set. Fill the rest:
- // key of pointed object
- set_de_object_key (de);
+ // key of pointed object
+ set_de_object_key(de);
- store_de_entry_key (de);
+ store_de_entry_key(de);
- // retval can be NAME_FOUND or NAME_FOUND_INVISIBLE
- return retval;
+ // retval can be NAME_FOUND or NAME_FOUND_INVISIBLE
+ return retval;
+ }
}
- }
-
- if (GET_GENERATION_NUMBER (le_ih_k_offset (de->de_ih)) == 0)
- /* we have reached left most entry in the node. In common we
- have to go to the left neighbor, but if generation counter
- is 0 already, we know for sure, that there is no name with
- the same hash value */
- // FIXME: this work correctly only because hash value can not
- // be 0. Btw, in case of Yura's hash it is probably possible,
- // so, this is a bug
- return NAME_NOT_FOUND;
- RFALSE( de->de_item_num,
- "vs-7015: two diritems of the same directory in one node?");
+ if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0)
+ /* we have reached left most entry in the node. In common we
+ have to go to the left neighbor, but if generation counter
+ is 0 already, we know for sure, that there is no name with
+ the same hash value */
+ // FIXME: this work correctly only because hash value can not
+ // be 0. Btw, in case of Yura's hash it is probably possible,
+ // so, this is a bug
+ return NAME_NOT_FOUND;
- return GOTO_PREVIOUS_ITEM;
-}
+ RFALSE(de->de_item_num,
+ "vs-7015: two diritems of the same directory in one node?");
+ return GOTO_PREVIOUS_ITEM;
+}
// may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND
// FIXME: should add something like IOERROR
-static int reiserfs_find_entry (struct inode * dir, const char * name, int namelen,
- struct path * path_to_entry, struct reiserfs_dir_entry * de)
+static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen,
+ struct path *path_to_entry,
+ struct reiserfs_dir_entry *de)
{
- struct cpu_key key_to_search;
- int retval;
-
-
- if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
- return NAME_NOT_FOUND;
-
- /* we will search for this key in the tree */
- make_cpu_key (&key_to_search, dir,
- get_third_component (dir->i_sb, name, namelen), TYPE_DIRENTRY, 3);
-
- while (1) {
- retval = search_by_entry_key (dir->i_sb, &key_to_search, path_to_entry, de);
- if (retval == IO_ERROR) {
- reiserfs_warning (dir->i_sb, "zam-7001: io error in %s",
- __FUNCTION__);
- return IO_ERROR;
- }
-
- /* compare names for all entries having given hash value */
- retval = linear_search_in_dir_item (&key_to_search, de, name, namelen);
- if (retval != GOTO_PREVIOUS_ITEM) {
- /* there is no need to scan directory anymore. Given entry found or does not exist */
- path_to_entry->pos_in_item = de->de_entry_num;
- return retval;
- }
-
- /* there is left neighboring item of this directory and given entry can be there */
- set_cpu_key_k_offset (&key_to_search, le_ih_k_offset (de->de_ih) - 1);
- pathrelse (path_to_entry);
-
- } /* while (1) */
+ struct cpu_key key_to_search;
+ int retval;
+
+ if (namelen > REISERFS_MAX_NAME(dir->i_sb->s_blocksize))
+ return NAME_NOT_FOUND;
+
+ /* we will search for this key in the tree */
+ make_cpu_key(&key_to_search, dir,
+ get_third_component(dir->i_sb, name, namelen),
+ TYPE_DIRENTRY, 3);
+
+ while (1) {
+ retval =
+ search_by_entry_key(dir->i_sb, &key_to_search,
+ path_to_entry, de);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(dir->i_sb, "zam-7001: io error in %s",
+ __FUNCTION__);
+ return IO_ERROR;
+ }
+
+ /* compare names for all entries having given hash value */
+ retval =
+ linear_search_in_dir_item(&key_to_search, de, name,
+ namelen);
+ if (retval != GOTO_PREVIOUS_ITEM) {
+ /* there is no need to scan directory anymore. Given entry found or does not exist */
+ path_to_entry->pos_in_item = de->de_entry_num;
+ return retval;
+ }
+
+ /* there is left neighboring item of this directory and given entry can be there */
+ set_cpu_key_k_offset(&key_to_search,
+ le_ih_k_offset(de->de_ih) - 1);
+ pathrelse(path_to_entry);
+
+ } /* while (1) */
}
-
-static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dentry, struct nameidata *nd)
+static struct dentry *reiserfs_lookup(struct inode *dir, struct dentry *dentry,
+ struct nameidata *nd)
{
- int retval;
- struct inode * inode = NULL;
- struct reiserfs_dir_entry de;
- INITIALIZE_PATH (path_to_entry);
-
- if (REISERFS_MAX_NAME (dir->i_sb->s_blocksize) < dentry->d_name.len)
- return ERR_PTR(-ENAMETOOLONG);
-
- reiserfs_write_lock(dir->i_sb);
- de.de_gen_number_bit_string = NULL;
- retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path_to_entry, &de);
- pathrelse (&path_to_entry);
- if (retval == NAME_FOUND) {
- /* Hide the .reiserfs_priv directory */
- if (reiserfs_xattrs (dir->i_sb) &&
- !old_format_only(dir->i_sb) &&
- REISERFS_SB(dir->i_sb)->priv_root &&
- REISERFS_SB(dir->i_sb)->priv_root->d_inode &&
- de.de_objectid == le32_to_cpu (INODE_PKEY(REISERFS_SB(dir->i_sb)->priv_root->d_inode)->k_objectid)) {
- reiserfs_write_unlock (dir->i_sb);
- return ERR_PTR (-EACCES);
+ int retval;
+ struct inode *inode = NULL;
+ struct reiserfs_dir_entry de;
+ INITIALIZE_PATH(path_to_entry);
+
+ if (REISERFS_MAX_NAME(dir->i_sb->s_blocksize) < dentry->d_name.len)
+ return ERR_PTR(-ENAMETOOLONG);
+
+ reiserfs_write_lock(dir->i_sb);
+ de.de_gen_number_bit_string = NULL;
+ retval =
+ reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
+ &path_to_entry, &de);
+ pathrelse(&path_to_entry);
+ if (retval == NAME_FOUND) {
+ /* Hide the .reiserfs_priv directory */
+ if (reiserfs_xattrs(dir->i_sb) &&
+ !old_format_only(dir->i_sb) &&
+ REISERFS_SB(dir->i_sb)->priv_root &&
+ REISERFS_SB(dir->i_sb)->priv_root->d_inode &&
+ de.de_objectid ==
+ le32_to_cpu(INODE_PKEY
+ (REISERFS_SB(dir->i_sb)->priv_root->d_inode)->
+ k_objectid)) {
+ reiserfs_write_unlock(dir->i_sb);
+ return ERR_PTR(-EACCES);
+ }
+
+ inode =
+ reiserfs_iget(dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
+ if (!inode || IS_ERR(inode)) {
+ reiserfs_write_unlock(dir->i_sb);
+ return ERR_PTR(-EACCES);
+ }
+
+ /* Propogate the priv_object flag so we know we're in the priv tree */
+ if (is_reiserfs_priv_object(dir))
+ reiserfs_mark_inode_private(inode);
+ }
+ reiserfs_write_unlock(dir->i_sb);
+ if (retval == IO_ERROR) {
+ return ERR_PTR(-EIO);
}
- inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
- if (!inode || IS_ERR(inode)) {
- reiserfs_write_unlock(dir->i_sb);
- return ERR_PTR(-EACCES);
- }
-
- /* Propogate the priv_object flag so we know we're in the priv tree */
- if (is_reiserfs_priv_object (dir))
- reiserfs_mark_inode_private (inode);
- }
- reiserfs_write_unlock(dir->i_sb);
- if ( retval == IO_ERROR ) {
- return ERR_PTR(-EIO);
- }
-
- if (inode)
- return d_splice_alias(inode, dentry);
-
- d_add(dentry, inode);
- return NULL;
-}
+ if (inode)
+ return d_splice_alias(inode, dentry);
+ d_add(dentry, inode);
+ return NULL;
+}
/*
** looks up the dentry of the parent directory for child.
@@ -374,40 +388,38 @@ static struct dentry * reiserfs_lookup (struct inode * dir, struct dentry * dent
*/
struct dentry *reiserfs_get_parent(struct dentry *child)
{
- int retval;
- struct inode * inode = NULL;
- struct reiserfs_dir_entry de;
- INITIALIZE_PATH (path_to_entry);
- struct dentry *parent;
- struct inode *dir = child->d_inode ;
-
-
- if (dir->i_nlink == 0) {
- return ERR_PTR(-ENOENT);
- }
- de.de_gen_number_bit_string = NULL;
-
- reiserfs_write_lock(dir->i_sb);
- retval = reiserfs_find_entry (dir, "..", 2, &path_to_entry, &de);
- pathrelse (&path_to_entry);
- if (retval != NAME_FOUND) {
+ int retval;
+ struct inode *inode = NULL;
+ struct reiserfs_dir_entry de;
+ INITIALIZE_PATH(path_to_entry);
+ struct dentry *parent;
+ struct inode *dir = child->d_inode;
+
+ if (dir->i_nlink == 0) {
+ return ERR_PTR(-ENOENT);
+ }
+ de.de_gen_number_bit_string = NULL;
+
+ reiserfs_write_lock(dir->i_sb);
+ retval = reiserfs_find_entry(dir, "..", 2, &path_to_entry, &de);
+ pathrelse(&path_to_entry);
+ if (retval != NAME_FOUND) {
+ reiserfs_write_unlock(dir->i_sb);
+ return ERR_PTR(-ENOENT);
+ }
+ inode = reiserfs_iget(dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
reiserfs_write_unlock(dir->i_sb);
- return ERR_PTR(-ENOENT);
- }
- inode = reiserfs_iget (dir->i_sb, (struct cpu_key *)&(de.de_dir_id));
- reiserfs_write_unlock(dir->i_sb);
-
- if (!inode || IS_ERR(inode)) {
- return ERR_PTR(-EACCES);
- }
- parent = d_alloc_anon(inode);
- if (!parent) {
- iput(inode);
- parent = ERR_PTR(-ENOMEM);
- }
- return parent;
-}
+ if (!inode || IS_ERR(inode)) {
+ return ERR_PTR(-EACCES);
+ }
+ parent = d_alloc_anon(inode);
+ if (!parent) {
+ iput(inode);
+ parent = ERR_PTR(-ENOMEM);
+ }
+ return parent;
+}
/* add entry to the directory (entry can be hidden).
@@ -415,132 +427,143 @@ insert definition of when hidden directories are used here -Hans
Does not mark dir inode dirty, do it after successesfull call to it */
-static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct inode * dir,
- const char * name, int namelen, struct inode * inode,
- int visible)
+static int reiserfs_add_entry(struct reiserfs_transaction_handle *th,
+ struct inode *dir, const char *name, int namelen,
+ struct inode *inode, int visible)
{
- struct cpu_key entry_key;
- struct reiserfs_de_head * deh;
- INITIALIZE_PATH (path);
- struct reiserfs_dir_entry de;
- int bit_string [MAX_GENERATION_NUMBER / (sizeof(int) * 8) + 1];
- int gen_number;
- char small_buf[32+DEH_SIZE] ; /* 48 bytes now and we avoid kmalloc
- if we create file with short name */
- char * buffer;
- int buflen, paste_size;
- int retval;
-
- BUG_ON (!th->t_trans_id);
-
- /* cannot allow items to be added into a busy deleted directory */
- if (!namelen)
- return -EINVAL;
-
- if (namelen > REISERFS_MAX_NAME (dir->i_sb->s_blocksize))
- return -ENAMETOOLONG;
-
- /* each entry has unique key. compose it */
- make_cpu_key (&entry_key, dir,
- get_third_component (dir->i_sb, name, namelen), TYPE_DIRENTRY, 3);
-
- /* get memory for composing the entry */
- buflen = DEH_SIZE + ROUND_UP (namelen);
- if (buflen > sizeof (small_buf)) {
- buffer = reiserfs_kmalloc (buflen, GFP_NOFS, dir->i_sb);
- if (buffer == 0)
- return -ENOMEM;
- } else
- buffer = small_buf;
-
- paste_size = (get_inode_sd_version (dir) == STAT_DATA_V1) ? (DEH_SIZE + namelen) : buflen;
-
- /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
- deh = (struct reiserfs_de_head *)buffer;
- deh->deh_location = 0; /* JDM Endian safe if 0 */
- put_deh_offset( deh, cpu_key_k_offset( &entry_key ) );
- deh->deh_state = 0; /* JDM Endian safe if 0 */
- /* put key (ino analog) to de */
- deh->deh_dir_id = INODE_PKEY (inode)->k_dir_id; /* safe: k_dir_id is le */
- deh->deh_objectid = INODE_PKEY (inode)->k_objectid; /* safe: k_objectid is le */
-
- /* copy name */
- memcpy ((char *)(deh + 1), name, namelen);
- /* padd by 0s to the 4 byte boundary */
- padd_item ((char *)(deh + 1), ROUND_UP (namelen), namelen);
-
- /* entry is ready to be pasted into tree, set 'visibility' and 'stat data in entry' attributes */
- mark_de_without_sd (deh);
- visible ? mark_de_visible (deh) : mark_de_hidden (deh);
-
- /* find the proper place for the new entry */
- memset (bit_string, 0, sizeof (bit_string));
- de.de_gen_number_bit_string = (char *)bit_string;
- retval = reiserfs_find_entry (dir, name, namelen, &path, &de);
- if( retval != NAME_NOT_FOUND ) {
- if (buffer != small_buf)
- reiserfs_kfree (buffer, buflen, dir->i_sb);
- pathrelse (&path);
+ struct cpu_key entry_key;
+ struct reiserfs_de_head *deh;
+ INITIALIZE_PATH(path);
+ struct reiserfs_dir_entry de;
+ int bit_string[MAX_GENERATION_NUMBER / (sizeof(int) * 8) + 1];
+ int gen_number;
+ char small_buf[32 + DEH_SIZE]; /* 48 bytes now and we avoid kmalloc
+ if we create file with short name */
+ char *buffer;
+ int buflen, paste_size;
+ int retval;
+
+ BUG_ON(!th->t_trans_id);
+
+ /* cannot allow items to be added into a busy deleted directory */
+ if (!namelen)
+ return -EINVAL;
+
+ if (namelen > REISERFS_MAX_NAME(dir->i_sb->s_blocksize))
+ return -ENAMETOOLONG;
+
+ /* each entry has unique key. compose it */
+ make_cpu_key(&entry_key, dir,
+ get_third_component(dir->i_sb, name, namelen),
+ TYPE_DIRENTRY, 3);
+
+ /* get memory for composing the entry */
+ buflen = DEH_SIZE + ROUND_UP(namelen);
+ if (buflen > sizeof(small_buf)) {
+ buffer = reiserfs_kmalloc(buflen, GFP_NOFS, dir->i_sb);
+ if (buffer == 0)
+ return -ENOMEM;
+ } else
+ buffer = small_buf;
+
+ paste_size =
+ (get_inode_sd_version(dir) ==
+ STAT_DATA_V1) ? (DEH_SIZE + namelen) : buflen;
+
+ /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */
+ deh = (struct reiserfs_de_head *)buffer;
+ deh->deh_location = 0; /* JDM Endian safe if 0 */
+ put_deh_offset(deh, cpu_key_k_offset(&entry_key));
+ deh->deh_state = 0; /* JDM Endian safe if 0 */
+ /* put key (ino analog) to de */
+ deh->deh_dir_id = INODE_PKEY(inode)->k_dir_id; /* safe: k_dir_id is le */
+ deh->deh_objectid = INODE_PKEY(inode)->k_objectid; /* safe: k_objectid is le */
+
+ /* copy name */
+ memcpy((char *)(deh + 1), name, namelen);
+ /* padd by 0s to the 4 byte boundary */
+ padd_item((char *)(deh + 1), ROUND_UP(namelen), namelen);
+
+ /* entry is ready to be pasted into tree, set 'visibility' and 'stat data in entry' attributes */
+ mark_de_without_sd(deh);
+ visible ? mark_de_visible(deh) : mark_de_hidden(deh);
+
+ /* find the proper place for the new entry */
+ memset(bit_string, 0, sizeof(bit_string));
+ de.de_gen_number_bit_string = (char *)bit_string;
+ retval = reiserfs_find_entry(dir, name, namelen, &path, &de);
+ if (retval != NAME_NOT_FOUND) {
+ if (buffer != small_buf)
+ reiserfs_kfree(buffer, buflen, dir->i_sb);
+ pathrelse(&path);
+
+ if (retval == IO_ERROR) {
+ return -EIO;
+ }
+
+ if (retval != NAME_FOUND) {
+ reiserfs_warning(dir->i_sb,
+ "zam-7002:%s: \"reiserfs_find_entry\" "
+ "has returned unexpected value (%d)",
+ __FUNCTION__, retval);
+ }
+
+ return -EEXIST;
+ }
- if ( retval == IO_ERROR ) {
- return -EIO;
+ gen_number =
+ find_first_zero_bit((unsigned long *)bit_string,
+ MAX_GENERATION_NUMBER + 1);
+ if (gen_number > MAX_GENERATION_NUMBER) {
+ /* there is no free generation number */
+ reiserfs_warning(dir->i_sb,
+ "reiserfs_add_entry: Congratulations! we have got hash function screwed up");
+ if (buffer != small_buf)
+ reiserfs_kfree(buffer, buflen, dir->i_sb);
+ pathrelse(&path);
+ return -EBUSY;
+ }
+ /* adjust offset of directory enrty */
+ put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number));
+ set_cpu_key_k_offset(&entry_key, deh_offset(deh));
+
+ /* update max-hash-collisions counter in reiserfs_sb_info */
+ PROC_INFO_MAX(th->t_super, max_hash_collisions, gen_number);
+
+ if (gen_number != 0) { /* we need to re-search for the insertion point */
+ if (search_by_entry_key(dir->i_sb, &entry_key, &path, &de) !=
+ NAME_NOT_FOUND) {
+ reiserfs_warning(dir->i_sb,
+ "vs-7032: reiserfs_add_entry: "
+ "entry with this key (%K) already exists",
+ &entry_key);
+
+ if (buffer != small_buf)
+ reiserfs_kfree(buffer, buflen, dir->i_sb);
+ pathrelse(&path);
+ return -EBUSY;
+ }
}
- if (retval != NAME_FOUND) {
- reiserfs_warning (dir->i_sb, "zam-7002:%s: \"reiserfs_find_entry\" "
- "has returned unexpected value (%d)",
- __FUNCTION__, retval);
- }
-
- return -EEXIST;
- }
-
- gen_number = find_first_zero_bit ((unsigned long *)bit_string, MAX_GENERATION_NUMBER + 1);
- if (gen_number > MAX_GENERATION_NUMBER) {
- /* there is no free generation number */
- reiserfs_warning (dir->i_sb, "reiserfs_add_entry: Congratulations! we have got hash function screwed up");
- if (buffer != small_buf)
- reiserfs_kfree (buffer, buflen, dir->i_sb);
- pathrelse (&path);
- return -EBUSY;
- }
- /* adjust offset of directory enrty */
- put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number));
- set_cpu_key_k_offset (&entry_key, deh_offset(deh));
-
- /* update max-hash-collisions counter in reiserfs_sb_info */
- PROC_INFO_MAX( th -> t_super, max_hash_collisions, gen_number );
-
- if (gen_number != 0) { /* we need to re-search for the insertion point */
- if (search_by_entry_key (dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) {
- reiserfs_warning (dir->i_sb, "vs-7032: reiserfs_add_entry: "
- "entry with this key (%K) already exists",
- &entry_key);
-
- if (buffer != small_buf)
- reiserfs_kfree (buffer, buflen, dir->i_sb);
- pathrelse (&path);
- return -EBUSY;
+ /* perform the insertion of the entry that we have prepared */
+ retval =
+ reiserfs_paste_into_item(th, &path, &entry_key, dir, buffer,
+ paste_size);
+ if (buffer != small_buf)
+ reiserfs_kfree(buffer, buflen, dir->i_sb);
+ if (retval) {
+ reiserfs_check_path(&path);
+ return retval;
}
- }
-
- /* perform the insertion of the entry that we have prepared */
- retval = reiserfs_paste_into_item (th, &path, &entry_key, dir, buffer, paste_size);
- if (buffer != small_buf)
- reiserfs_kfree (buffer, buflen, dir->i_sb);
- if (retval) {
- reiserfs_check_path(&path) ;
- return retval;
- }
- dir->i_size += paste_size;
- dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
- if (!S_ISDIR (inode->i_mode) && visible)
- // reiserfs_mkdir or reiserfs_rename will do that by itself
- reiserfs_update_sd (th, dir);
+ dir->i_size += paste_size;
+ dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
+ if (!S_ISDIR(inode->i_mode) && visible)
+ // reiserfs_mkdir or reiserfs_rename will do that by itself
+ reiserfs_update_sd(th, dir);
- reiserfs_check_path(&path) ;
- return 0;
+ reiserfs_check_path(&path);
+ return 0;
}
/* quota utility function, call if you've had to abort after calling
@@ -548,12 +571,13 @@ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct in
** This should only be called on inodes that do not have stat data
** inserted into the tree yet.
*/
-static int drop_new_inode(struct inode *inode) {
- DQUOT_DROP(inode);
- make_bad_inode(inode) ;
- inode->i_flags |= S_NOQUOTA;
- iput(inode) ;
- return 0 ;
+static int drop_new_inode(struct inode *inode)
+{
+ DQUOT_DROP(inode);
+ make_bad_inode(inode);
+ inode->i_flags |= S_NOQUOTA;
+ iput(inode);
+ return 0;
}
/* utility function that does setup for reiserfs_new_inode.
@@ -561,902 +585,968 @@ static int drop_new_inode(struct inode *inode) {
** outside of a transaction, so we had to pull some bits of
** reiserfs_new_inode out into this func.
*/
-static int new_inode_init(struct inode *inode, struct inode *dir, int mode) {
-
- /* the quota init calls have to know who to charge the quota to, so
- ** we have to set uid and gid here
- */
- inode->i_uid = current->fsuid;
- inode->i_mode = mode;
-
- if (dir->i_mode & S_ISGID) {
- inode->i_gid = dir->i_gid;
- if (S_ISDIR(mode))
- inode->i_mode |= S_ISGID;
- } else {
- inode->i_gid = current->fsgid;
- }
- DQUOT_INIT(inode);
- return 0 ;
+static int new_inode_init(struct inode *inode, struct inode *dir, int mode)
+{
+
+ /* the quota init calls have to know who to charge the quota to, so
+ ** we have to set uid and gid here
+ */
+ inode->i_uid = current->fsuid;
+ inode->i_mode = mode;
+
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ inode->i_mode |= S_ISGID;
+ } else {
+ inode->i_gid = current->fsgid;
+ }
+ DQUOT_INIT(inode);
+ return 0;
}
-static int reiserfs_create (struct inode * dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
+static int reiserfs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
{
- int retval;
- struct inode * inode;
- /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
- struct reiserfs_transaction_handle th ;
- int locked;
-
- if (!(inode = new_inode(dir->i_sb))) {
- return -ENOMEM ;
- }
- new_inode_init(inode, dir, mode);
-
- locked = reiserfs_cache_default_acl (dir);
-
- reiserfs_write_lock(dir->i_sb);
-
- if (locked)
- reiserfs_write_lock_xattrs (dir->i_sb);
-
- retval = journal_begin(&th, dir->i_sb, jbegin_count);
- if (retval) {
- drop_new_inode (inode);
- goto out_failed;
- }
-
- retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
- if (retval)
- goto out_failed;
-
- if (locked) {
- reiserfs_write_unlock_xattrs (dir->i_sb);
- locked = 0;
- }
-
- inode->i_op = &reiserfs_file_inode_operations;
- inode->i_fop = &reiserfs_file_operations;
- inode->i_mapping->a_ops = &reiserfs_address_space_operations ;
-
- retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
- inode, 1/*visible*/);
- if (retval) {
- int err;
- inode->i_nlink--;
- reiserfs_update_sd (&th, inode);
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- if (err)
- retval = err;
- iput (inode);
- goto out_failed;
- }
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
-
- d_instantiate(dentry, inode);
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
-
-out_failed:
- if (locked)
- reiserfs_write_unlock_xattrs (dir->i_sb);
- reiserfs_write_unlock(dir->i_sb);
- return retval;
-}
+ int retval;
+ struct inode *inode;
+ /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 2 +
+ 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
+ REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
+ struct reiserfs_transaction_handle th;
+ int locked;
+
+ if (!(inode = new_inode(dir->i_sb))) {
+ return -ENOMEM;
+ }
+ new_inode_init(inode, dir, mode);
+ locked = reiserfs_cache_default_acl(dir);
-static int reiserfs_mknod (struct inode * dir, struct dentry *dentry, int mode, dev_t rdev)
-{
- int retval;
- struct inode * inode;
- struct reiserfs_transaction_handle th ;
- /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
- int locked;
+ reiserfs_write_lock(dir->i_sb);
- if (!new_valid_dev(rdev))
- return -EINVAL;
+ if (locked)
+ reiserfs_write_lock_xattrs(dir->i_sb);
+
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval) {
+ drop_new_inode(inode);
+ goto out_failed;
+ }
+
+ retval =
+ reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
+ inode);
+ if (retval)
+ goto out_failed;
+
+ if (locked) {
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ locked = 0;
+ }
+
+ inode->i_op = &reiserfs_file_inode_operations;
+ inode->i_fop = &reiserfs_file_operations;
+ inode->i_mapping->a_ops = &reiserfs_address_space_operations;
+
+ retval =
+ reiserfs_add_entry(&th, dir, dentry->d_name.name,
+ dentry->d_name.len, inode, 1 /*visible */ );
+ if (retval) {
+ int err;
+ inode->i_nlink--;
+ reiserfs_update_sd(&th, inode);
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ if (err)
+ retval = err;
+ iput(inode);
+ goto out_failed;
+ }
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
- if (!(inode = new_inode(dir->i_sb))) {
- return -ENOMEM ;
- }
- new_inode_init(inode, dir, mode);
+ d_instantiate(dentry, inode);
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
- locked = reiserfs_cache_default_acl (dir);
+ out_failed:
+ if (locked)
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
+}
- reiserfs_write_lock(dir->i_sb);
+static int reiserfs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+ dev_t rdev)
+{
+ int retval;
+ struct inode *inode;
+ struct reiserfs_transaction_handle th;
+ /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 +
+ 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
+ REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
+ int locked;
+
+ if (!new_valid_dev(rdev))
+ return -EINVAL;
+
+ if (!(inode = new_inode(dir->i_sb))) {
+ return -ENOMEM;
+ }
+ new_inode_init(inode, dir, mode);
- if (locked)
- reiserfs_write_lock_xattrs (dir->i_sb);
+ locked = reiserfs_cache_default_acl(dir);
- retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
- if (retval) {
- drop_new_inode (inode);
- goto out_failed;
- }
+ reiserfs_write_lock(dir->i_sb);
- retval = reiserfs_new_inode (&th, dir, mode, NULL, 0/*i_size*/, dentry, inode);
- if (retval) {
- goto out_failed;
- }
+ if (locked)
+ reiserfs_write_lock_xattrs(dir->i_sb);
- if (locked) {
- reiserfs_write_unlock_xattrs (dir->i_sb);
- locked = 0;
- }
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval) {
+ drop_new_inode(inode);
+ goto out_failed;
+ }
+ retval =
+ reiserfs_new_inode(&th, dir, mode, NULL, 0 /*i_size */ , dentry,
+ inode);
+ if (retval) {
+ goto out_failed;
+ }
- inode->i_op = &reiserfs_special_inode_operations;
- init_special_inode(inode, inode->i_mode, rdev) ;
+ if (locked) {
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ locked = 0;
+ }
- //FIXME: needed for block and char devices only
- reiserfs_update_sd (&th, inode);
+ inode->i_op = &reiserfs_special_inode_operations;
+ init_special_inode(inode, inode->i_mode, rdev);
+
+ //FIXME: needed for block and char devices only
+ reiserfs_update_sd(&th, inode);
+
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
+
+ retval =
+ reiserfs_add_entry(&th, dir, dentry->d_name.name,
+ dentry->d_name.len, inode, 1 /*visible */ );
+ if (retval) {
+ int err;
+ inode->i_nlink--;
+ reiserfs_update_sd(&th, inode);
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ if (err)
+ retval = err;
+ iput(inode);
+ goto out_failed;
+ }
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
+ d_instantiate(dentry, inode);
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
- retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
- inode, 1/*visible*/);
- if (retval) {
- int err;
- inode->i_nlink--;
- reiserfs_update_sd (&th, inode);
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- if (err)
- retval = err;
- iput (inode);
- goto out_failed;
- }
-
- d_instantiate(dentry, inode);
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
-
-out_failed:
- if (locked)
- reiserfs_write_unlock_xattrs (dir->i_sb);
- reiserfs_write_unlock(dir->i_sb);
- return retval;
+ out_failed:
+ if (locked)
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
}
-
-static int reiserfs_mkdir (struct inode * dir, struct dentry *dentry, int mode)
+static int reiserfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
- int retval;
- struct inode * inode;
- struct reiserfs_transaction_handle th ;
- /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
- int locked;
+ int retval;
+ struct inode *inode;
+ struct reiserfs_transaction_handle th;
+ /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 +
+ 2 * (REISERFS_QUOTA_INIT_BLOCKS(dir->i_sb) +
+ REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb));
+ int locked;
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */
- REISERFS_I(dir)->new_packing_locality = 1;
+ /* set flag that new packing locality created and new blocks for the content * of that directory are not displaced yet */
+ REISERFS_I(dir)->new_packing_locality = 1;
#endif
- mode = S_IFDIR | mode;
- if (!(inode = new_inode(dir->i_sb))) {
- return -ENOMEM ;
- }
- new_inode_init(inode, dir, mode);
-
- locked = reiserfs_cache_default_acl (dir);
-
- reiserfs_write_lock(dir->i_sb);
- if (locked)
- reiserfs_write_lock_xattrs (dir->i_sb);
-
- retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
- if (retval) {
- drop_new_inode (inode);
- goto out_failed;
- }
-
-
- /* inc the link count now, so another writer doesn't overflow it while
- ** we sleep later on.
- */
- INC_DIR_INODE_NLINK(dir)
-
- retval = reiserfs_new_inode (&th, dir, mode, NULL/*symlink*/,
- old_format_only (dir->i_sb) ?
- EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
- dentry, inode);
- if (retval) {
- dir->i_nlink-- ;
- goto out_failed;
- }
-
- if (locked) {
- reiserfs_write_unlock_xattrs (dir->i_sb);
- locked = 0;
- }
-
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
-
- inode->i_op = &reiserfs_dir_inode_operations;
- inode->i_fop = &reiserfs_dir_operations;
-
- // note, _this_ add_entry will not update dir's stat data
- retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
- inode, 1/*visible*/);
- if (retval) {
- int err;
- inode->i_nlink = 0;
- DEC_DIR_INODE_NLINK(dir);
- reiserfs_update_sd (&th, inode);
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- if (err)
- retval = err;
- iput (inode);
- goto out_failed;
- }
-
- // the above add_entry did not update dir's stat data
- reiserfs_update_sd (&th, dir);
-
- d_instantiate(dentry, inode);
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
-out_failed:
- if (locked)
- reiserfs_write_unlock_xattrs (dir->i_sb);
- reiserfs_write_unlock(dir->i_sb);
- return retval;
-}
+ mode = S_IFDIR | mode;
+ if (!(inode = new_inode(dir->i_sb))) {
+ return -ENOMEM;
+ }
+ new_inode_init(inode, dir, mode);
+
+ locked = reiserfs_cache_default_acl(dir);
+
+ reiserfs_write_lock(dir->i_sb);
+ if (locked)
+ reiserfs_write_lock_xattrs(dir->i_sb);
+
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval) {
+ drop_new_inode(inode);
+ goto out_failed;
+ }
-static inline int reiserfs_empty_dir(struct inode *inode) {
- /* we can cheat because an old format dir cannot have
- ** EMPTY_DIR_SIZE, and a new format dir cannot have
- ** EMPTY_DIR_SIZE_V1. So, if the inode is either size,
- ** regardless of disk format version, the directory is empty.
- */
- if (inode->i_size != EMPTY_DIR_SIZE &&
- inode->i_size != EMPTY_DIR_SIZE_V1) {
- return 0 ;
- }
- return 1 ;
+ /* inc the link count now, so another writer doesn't overflow it while
+ ** we sleep later on.
+ */
+ INC_DIR_INODE_NLINK(dir)
+
+ retval = reiserfs_new_inode(&th, dir, mode, NULL /*symlink */ ,
+ old_format_only(dir->i_sb) ?
+ EMPTY_DIR_SIZE_V1 : EMPTY_DIR_SIZE,
+ dentry, inode);
+ if (retval) {
+ dir->i_nlink--;
+ goto out_failed;
+ }
+
+ if (locked) {
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ locked = 0;
+ }
+
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
+
+ inode->i_op = &reiserfs_dir_inode_operations;
+ inode->i_fop = &reiserfs_dir_operations;
+
+ // note, _this_ add_entry will not update dir's stat data
+ retval =
+ reiserfs_add_entry(&th, dir, dentry->d_name.name,
+ dentry->d_name.len, inode, 1 /*visible */ );
+ if (retval) {
+ int err;
+ inode->i_nlink = 0;
+ DEC_DIR_INODE_NLINK(dir);
+ reiserfs_update_sd(&th, inode);
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ if (err)
+ retval = err;
+ iput(inode);
+ goto out_failed;
+ }
+ // the above add_entry did not update dir's stat data
+ reiserfs_update_sd(&th, dir);
+
+ d_instantiate(dentry, inode);
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
+ out_failed:
+ if (locked)
+ reiserfs_write_unlock_xattrs(dir->i_sb);
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
}
-static int reiserfs_rmdir (struct inode * dir, struct dentry *dentry)
+static inline int reiserfs_empty_dir(struct inode *inode)
{
- int retval, err;
- struct inode * inode;
- struct reiserfs_transaction_handle th ;
- int jbegin_count;
- INITIALIZE_PATH (path);
- struct reiserfs_dir_entry de;
-
-
- /* we will be doing 2 balancings and update 2 stat data, we change quotas
- * of the owner of the directory and of the owner of the parent directory */
- jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
-
- reiserfs_write_lock(dir->i_sb);
- retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
- if (retval)
- goto out_rmdir;
-
- de.de_gen_number_bit_string = NULL;
- if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
- retval = -ENOENT;
- goto end_rmdir;
- } else if ( retval == IO_ERROR) {
- retval = -EIO;
- goto end_rmdir;
- }
-
- inode = dentry->d_inode;
-
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
-
- if (de.de_objectid != inode->i_ino) {
- // FIXME: compare key of an object and a key found in the
- // entry
- retval = -EIO;
- goto end_rmdir;
- }
- if (!reiserfs_empty_dir(inode)) {
- retval = -ENOTEMPTY;
- goto end_rmdir;
- }
-
- /* cut entry from dir directory */
- retval = reiserfs_cut_from_item (&th, &path, &(de.de_entry_key), dir,
- NULL, /* page */
- 0/*new file size - not used here*/);
- if (retval < 0)
- goto end_rmdir;
-
- if ( inode->i_nlink != 2 && inode->i_nlink != 1 )
- reiserfs_warning (inode->i_sb, "%s: empty directory has nlink "
- "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
-
- inode->i_nlink = 0;
- inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
- reiserfs_update_sd (&th, inode);
-
- DEC_DIR_INODE_NLINK(dir)
- dir->i_size -= (DEH_SIZE + de.de_entrylen);
- reiserfs_update_sd (&th, dir);
-
- /* prevent empty directory from getting lost */
- add_save_link (&th, inode, 0/* not truncate */);
-
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_check_path(&path) ;
-out_rmdir:
- reiserfs_write_unlock(dir->i_sb);
- return retval;
-
- end_rmdir:
- /* we must release path, because we did not call
- reiserfs_cut_from_item, or reiserfs_cut_from_item does not
- release path if operation was not complete */
- pathrelse (&path);
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_write_unlock(dir->i_sb);
- return err ? err : retval;
+ /* we can cheat because an old format dir cannot have
+ ** EMPTY_DIR_SIZE, and a new format dir cannot have
+ ** EMPTY_DIR_SIZE_V1. So, if the inode is either size,
+ ** regardless of disk format version, the directory is empty.
+ */
+ if (inode->i_size != EMPTY_DIR_SIZE &&
+ inode->i_size != EMPTY_DIR_SIZE_V1) {
+ return 0;
+ }
+ return 1;
}
-static int reiserfs_unlink (struct inode * dir, struct dentry *dentry)
+static int reiserfs_rmdir(struct inode *dir, struct dentry *dentry)
{
- int retval, err;
- struct inode * inode;
- struct reiserfs_dir_entry de;
- INITIALIZE_PATH (path);
- struct reiserfs_transaction_handle th ;
- int jbegin_count;
- unsigned long savelink;
-
- inode = dentry->d_inode;
-
- /* in this transaction we can be doing at max two balancings and update
- two stat datas, we change quotas of the owner of the directory and of
- the owner of the parent directory */
- jbegin_count = JOURNAL_PER_BALANCE_CNT * 2 + 2 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
-
- reiserfs_write_lock(dir->i_sb);
- retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
- if (retval)
- goto out_unlink;
-
- de.de_gen_number_bit_string = NULL;
- if ( (retval = reiserfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &path, &de)) == NAME_NOT_FOUND) {
- retval = -ENOENT;
- goto end_unlink;
- } else if (retval == IO_ERROR) {
- retval = -EIO;
- goto end_unlink;
- }
-
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
-
- if (de.de_objectid != inode->i_ino) {
- // FIXME: compare key of an object and a key found in the
- // entry
- retval = -EIO;
- goto end_unlink;
- }
-
- if (!inode->i_nlink) {
- reiserfs_warning (inode->i_sb, "%s: deleting nonexistent file "
- "(%s:%lu), %d", __FUNCTION__,
- reiserfs_bdevname (inode->i_sb), inode->i_ino,
- inode->i_nlink);
- inode->i_nlink = 1;
- }
-
- inode->i_nlink--;
-
- /*
- * we schedule before doing the add_save_link call, save the link
- * count so we don't race
- */
- savelink = inode->i_nlink;
-
-
- retval = reiserfs_cut_from_item (&th, &path, &(de.de_entry_key), dir, NULL, 0);
- if (retval < 0) {
- inode->i_nlink++;
- goto end_unlink;
- }
- inode->i_ctime = CURRENT_TIME_SEC;
- reiserfs_update_sd (&th, inode);
-
- dir->i_size -= (de.de_entrylen + DEH_SIZE);
- dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
- reiserfs_update_sd (&th, dir);
-
- if (!savelink)
- /* prevent file from getting lost */
- add_save_link (&th, inode, 0/* not truncate */);
-
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_check_path(&path) ;
- reiserfs_write_unlock(dir->i_sb);
- return retval;
-
- end_unlink:
- pathrelse (&path);
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_check_path(&path) ;
- if (err)
- retval = err;
-out_unlink:
- reiserfs_write_unlock(dir->i_sb);
- return retval;
+ int retval, err;
+ struct inode *inode;
+ struct reiserfs_transaction_handle th;
+ int jbegin_count;
+ INITIALIZE_PATH(path);
+ struct reiserfs_dir_entry de;
+
+ /* we will be doing 2 balancings and update 2 stat data, we change quotas
+ * of the owner of the directory and of the owner of the parent directory.
+ * The quota structure is possibly deleted only on last iput => outside
+ * of this transaction */
+ jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 2 + 2 +
+ 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
+
+ reiserfs_write_lock(dir->i_sb);
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval)
+ goto out_rmdir;
+
+ de.de_gen_number_bit_string = NULL;
+ if ((retval =
+ reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
+ &path, &de)) == NAME_NOT_FOUND) {
+ retval = -ENOENT;
+ goto end_rmdir;
+ } else if (retval == IO_ERROR) {
+ retval = -EIO;
+ goto end_rmdir;
+ }
+
+ inode = dentry->d_inode;
+
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
+
+ if (de.de_objectid != inode->i_ino) {
+ // FIXME: compare key of an object and a key found in the
+ // entry
+ retval = -EIO;
+ goto end_rmdir;
+ }
+ if (!reiserfs_empty_dir(inode)) {
+ retval = -ENOTEMPTY;
+ goto end_rmdir;
+ }
+
+ /* cut entry from dir directory */
+ retval = reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL, /* page */
+ 0 /*new file size - not used here */ );
+ if (retval < 0)
+ goto end_rmdir;
+
+ if (inode->i_nlink != 2 && inode->i_nlink != 1)
+ reiserfs_warning(inode->i_sb, "%s: empty directory has nlink "
+ "!= 2 (%d)", __FUNCTION__, inode->i_nlink);
+
+ inode->i_nlink = 0;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ reiserfs_update_sd(&th, inode);
+
+ DEC_DIR_INODE_NLINK(dir)
+ dir->i_size -= (DEH_SIZE + de.de_entrylen);
+ reiserfs_update_sd(&th, dir);
+
+ /* prevent empty directory from getting lost */
+ add_save_link(&th, inode, 0 /* not truncate */ );
+
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_check_path(&path);
+ out_rmdir:
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
+
+ end_rmdir:
+ /* we must release path, because we did not call
+ reiserfs_cut_from_item, or reiserfs_cut_from_item does not
+ release path if operation was not complete */
+ pathrelse(&path);
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(dir->i_sb);
+ return err ? err : retval;
}
-static int reiserfs_symlink (struct inode * parent_dir,
- struct dentry * dentry, const char * symname)
+static int reiserfs_unlink(struct inode *dir, struct dentry *dentry)
{
- int retval;
- struct inode * inode;
- char * name;
- int item_len;
- struct reiserfs_transaction_handle th ;
- int mode = S_IFLNK | S_IRWXUGO;
- /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * (REISERFS_QUOTA_INIT_BLOCKS+REISERFS_QUOTA_TRANS_BLOCKS);
-
- if (!(inode = new_inode(parent_dir->i_sb))) {
- return -ENOMEM ;
- }
- new_inode_init(inode, parent_dir, mode);
-
- reiserfs_write_lock(parent_dir->i_sb);
- item_len = ROUND_UP (strlen (symname));
- if (item_len > MAX_DIRECT_ITEM_LEN (parent_dir->i_sb->s_blocksize)) {
- retval = -ENAMETOOLONG;
- drop_new_inode(inode);
- goto out_failed;
- }
-
- name = reiserfs_kmalloc (item_len, GFP_NOFS, parent_dir->i_sb);
- if (!name) {
- drop_new_inode(inode);
- retval = -ENOMEM;
- goto out_failed;
- }
- memcpy (name, symname, strlen (symname));
- padd_item (name, item_len, strlen (symname));
-
- /* We would inherit the default ACL here, but symlinks don't get ACLs */
-
- retval = journal_begin(&th, parent_dir->i_sb, jbegin_count) ;
- if (retval) {
- drop_new_inode (inode);
- reiserfs_kfree (name, item_len, parent_dir->i_sb);
- goto out_failed;
- }
-
- retval = reiserfs_new_inode (&th, parent_dir, mode, name, strlen (symname),
- dentry, inode);
- reiserfs_kfree (name, item_len, parent_dir->i_sb);
- if (retval) { /* reiserfs_new_inode iputs for us */
- goto out_failed;
- }
-
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(parent_dir) ;
-
- inode->i_op = &reiserfs_symlink_inode_operations;
- inode->i_mapping->a_ops = &reiserfs_address_space_operations;
-
- // must be sure this inode is written with this transaction
- //
- //reiserfs_update_sd (&th, inode, READ_BLOCKS);
-
- retval = reiserfs_add_entry (&th, parent_dir, dentry->d_name.name,
- dentry->d_name.len, inode, 1/*visible*/);
- if (retval) {
- int err;
+ int retval, err;
+ struct inode *inode;
+ struct reiserfs_dir_entry de;
+ INITIALIZE_PATH(path);
+ struct reiserfs_transaction_handle th;
+ int jbegin_count;
+ unsigned long savelink;
+
+ inode = dentry->d_inode;
+
+ /* in this transaction we can be doing at max two balancings and update
+ * two stat datas, we change quotas of the owner of the directory and of
+ * the owner of the parent directory. The quota structure is possibly
+ * deleted only on iput => outside of this transaction */
+ jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 2 + 2 +
+ 4 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
+
+ reiserfs_write_lock(dir->i_sb);
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval)
+ goto out_unlink;
+
+ de.de_gen_number_bit_string = NULL;
+ if ((retval =
+ reiserfs_find_entry(dir, dentry->d_name.name, dentry->d_name.len,
+ &path, &de)) == NAME_NOT_FOUND) {
+ retval = -ENOENT;
+ goto end_unlink;
+ } else if (retval == IO_ERROR) {
+ retval = -EIO;
+ goto end_unlink;
+ }
+
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
+
+ if (de.de_objectid != inode->i_ino) {
+ // FIXME: compare key of an object and a key found in the
+ // entry
+ retval = -EIO;
+ goto end_unlink;
+ }
+
+ if (!inode->i_nlink) {
+ reiserfs_warning(inode->i_sb, "%s: deleting nonexistent file "
+ "(%s:%lu), %d", __FUNCTION__,
+ reiserfs_bdevname(inode->i_sb), inode->i_ino,
+ inode->i_nlink);
+ inode->i_nlink = 1;
+ }
+
inode->i_nlink--;
- reiserfs_update_sd (&th, inode);
- err = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
+
+ /*
+ * we schedule before doing the add_save_link call, save the link
+ * count so we don't race
+ */
+ savelink = inode->i_nlink;
+
+ retval =
+ reiserfs_cut_from_item(&th, &path, &(de.de_entry_key), dir, NULL,
+ 0);
+ if (retval < 0) {
+ inode->i_nlink++;
+ goto end_unlink;
+ }
+ inode->i_ctime = CURRENT_TIME_SEC;
+ reiserfs_update_sd(&th, inode);
+
+ dir->i_size -= (de.de_entrylen + DEH_SIZE);
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME_SEC;
+ reiserfs_update_sd(&th, dir);
+
+ if (!savelink)
+ /* prevent file from getting lost */
+ add_save_link(&th, inode, 0 /* not truncate */ );
+
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_check_path(&path);
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
+
+ end_unlink:
+ pathrelse(&path);
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_check_path(&path);
if (err)
- retval = err;
- iput (inode);
- goto out_failed;
- }
-
- d_instantiate(dentry, inode);
- retval = journal_end(&th, parent_dir->i_sb, jbegin_count) ;
-out_failed:
- reiserfs_write_unlock(parent_dir->i_sb);
- return retval;
+ retval = err;
+ out_unlink:
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
}
-static int reiserfs_link (struct dentry * old_dentry, struct inode * dir, struct dentry * dentry)
+static int reiserfs_symlink(struct inode *parent_dir,
+ struct dentry *dentry, const char *symname)
{
- int retval;
- struct inode *inode = old_dentry->d_inode;
- struct reiserfs_transaction_handle th ;
- /* We need blocks for transaction + update of quotas for the owners of the directory */
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 2 * REISERFS_QUOTA_TRANS_BLOCKS;
-
- reiserfs_write_lock(dir->i_sb);
- if (inode->i_nlink >= REISERFS_LINK_MAX) {
- //FIXME: sd_nlink is 32 bit for new files
- reiserfs_write_unlock(dir->i_sb);
- return -EMLINK;
- }
- if (inode->i_nlink == 0) {
- reiserfs_write_unlock(dir->i_sb);
- return -ENOENT;
- }
-
- /* inc before scheduling so reiserfs_unlink knows we are here */
- inode->i_nlink++;
-
- retval = journal_begin(&th, dir->i_sb, jbegin_count) ;
- if (retval) {
- inode->i_nlink--;
- reiserfs_write_unlock (dir->i_sb);
- return retval;
- }
-
- /* create new entry */
- retval = reiserfs_add_entry (&th, dir, dentry->d_name.name, dentry->d_name.len,
- inode, 1/*visible*/);
-
- reiserfs_update_inode_transaction(inode) ;
- reiserfs_update_inode_transaction(dir) ;
-
- if (retval) {
- int err;
- inode->i_nlink--;
- err = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_write_unlock(dir->i_sb);
- return err ? err : retval;
- }
+ int retval;
+ struct inode *inode;
+ char *name;
+ int item_len;
+ struct reiserfs_transaction_handle th;
+ int mode = S_IFLNK | S_IRWXUGO;
+ /* We need blocks for transaction + (user+group)*(quotas for new inode + update of quota for directory owner) */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 +
+ 2 * (REISERFS_QUOTA_INIT_BLOCKS(parent_dir->i_sb) +
+ REISERFS_QUOTA_TRANS_BLOCKS(parent_dir->i_sb));
+
+ if (!(inode = new_inode(parent_dir->i_sb))) {
+ return -ENOMEM;
+ }
+ new_inode_init(inode, parent_dir, mode);
+
+ reiserfs_write_lock(parent_dir->i_sb);
+ item_len = ROUND_UP(strlen(symname));
+ if (item_len > MAX_DIRECT_ITEM_LEN(parent_dir->i_sb->s_blocksize)) {
+ retval = -ENAMETOOLONG;
+ drop_new_inode(inode);
+ goto out_failed;
+ }
+
+ name = reiserfs_kmalloc(item_len, GFP_NOFS, parent_dir->i_sb);
+ if (!name) {
+ drop_new_inode(inode);
+ retval = -ENOMEM;
+ goto out_failed;
+ }
+ memcpy(name, symname, strlen(symname));
+ padd_item(name, item_len, strlen(symname));
+
+ /* We would inherit the default ACL here, but symlinks don't get ACLs */
+
+ retval = journal_begin(&th, parent_dir->i_sb, jbegin_count);
+ if (retval) {
+ drop_new_inode(inode);
+ reiserfs_kfree(name, item_len, parent_dir->i_sb);
+ goto out_failed;
+ }
+
+ retval =
+ reiserfs_new_inode(&th, parent_dir, mode, name, strlen(symname),
+ dentry, inode);
+ reiserfs_kfree(name, item_len, parent_dir->i_sb);
+ if (retval) { /* reiserfs_new_inode iputs for us */
+ goto out_failed;
+ }
- inode->i_ctime = CURRENT_TIME_SEC;
- reiserfs_update_sd (&th, inode);
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(parent_dir);
+
+ inode->i_op = &reiserfs_symlink_inode_operations;
+ inode->i_mapping->a_ops = &reiserfs_address_space_operations;
+
+ // must be sure this inode is written with this transaction
+ //
+ //reiserfs_update_sd (&th, inode, READ_BLOCKS);
+
+ retval = reiserfs_add_entry(&th, parent_dir, dentry->d_name.name,
+ dentry->d_name.len, inode, 1 /*visible */ );
+ if (retval) {
+ int err;
+ inode->i_nlink--;
+ reiserfs_update_sd(&th, inode);
+ err = journal_end(&th, parent_dir->i_sb, jbegin_count);
+ if (err)
+ retval = err;
+ iput(inode);
+ goto out_failed;
+ }
- atomic_inc(&inode->i_count) ;
- d_instantiate(dentry, inode);
- retval = journal_end(&th, dir->i_sb, jbegin_count) ;
- reiserfs_write_unlock(dir->i_sb);
- return retval;
+ d_instantiate(dentry, inode);
+ retval = journal_end(&th, parent_dir->i_sb, jbegin_count);
+ out_failed:
+ reiserfs_write_unlock(parent_dir->i_sb);
+ return retval;
}
+static int reiserfs_link(struct dentry *old_dentry, struct inode *dir,
+ struct dentry *dentry)
+{
+ int retval;
+ struct inode *inode = old_dentry->d_inode;
+ struct reiserfs_transaction_handle th;
+ /* We need blocks for transaction + update of quotas for the owners of the directory */
+ int jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 +
+ 2 * REISERFS_QUOTA_TRANS_BLOCKS(dir->i_sb);
+
+ reiserfs_write_lock(dir->i_sb);
+ if (inode->i_nlink >= REISERFS_LINK_MAX) {
+ //FIXME: sd_nlink is 32 bit for new files
+ reiserfs_write_unlock(dir->i_sb);
+ return -EMLINK;
+ }
+ if (inode->i_nlink == 0) {
+ reiserfs_write_unlock(dir->i_sb);
+ return -ENOENT;
+ }
+
+ /* inc before scheduling so reiserfs_unlink knows we are here */
+ inode->i_nlink++;
+
+ retval = journal_begin(&th, dir->i_sb, jbegin_count);
+ if (retval) {
+ inode->i_nlink--;
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
+ }
+
+ /* create new entry */
+ retval =
+ reiserfs_add_entry(&th, dir, dentry->d_name.name,
+ dentry->d_name.len, inode, 1 /*visible */ );
+
+ reiserfs_update_inode_transaction(inode);
+ reiserfs_update_inode_transaction(dir);
+
+ if (retval) {
+ int err;
+ inode->i_nlink--;
+ err = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(dir->i_sb);
+ return err ? err : retval;
+ }
+
+ inode->i_ctime = CURRENT_TIME_SEC;
+ reiserfs_update_sd(&th, inode);
+
+ atomic_inc(&inode->i_count);
+ d_instantiate(dentry, inode);
+ retval = journal_end(&th, dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(dir->i_sb);
+ return retval;
+}
// de contains information pointing to an entry which
-static int de_still_valid (const char * name, int len, struct reiserfs_dir_entry * de)
+static int de_still_valid(const char *name, int len,
+ struct reiserfs_dir_entry *de)
{
- struct reiserfs_dir_entry tmp = *de;
-
- // recalculate pointer to name and name length
- set_de_name_and_namelen (&tmp);
- // FIXME: could check more
- if (tmp.de_namelen != len || memcmp (name, de->de_name, len))
- return 0;
- return 1;
+ struct reiserfs_dir_entry tmp = *de;
+
+ // recalculate pointer to name and name length
+ set_de_name_and_namelen(&tmp);
+ // FIXME: could check more
+ if (tmp.de_namelen != len || memcmp(name, de->de_name, len))
+ return 0;
+ return 1;
}
-
-static int entry_points_to_object (const char * name, int len, struct reiserfs_dir_entry * de, struct inode * inode)
+static int entry_points_to_object(const char *name, int len,
+ struct reiserfs_dir_entry *de,
+ struct inode *inode)
{
- if (!de_still_valid (name, len, de))
- return 0;
-
- if (inode) {
- if (!de_visible (de->de_deh + de->de_entry_num))
- reiserfs_panic (NULL, "vs-7042: entry_points_to_object: entry must be visible");
- return (de->de_objectid == inode->i_ino) ? 1 : 0;
- }
+ if (!de_still_valid(name, len, de))
+ return 0;
+
+ if (inode) {
+ if (!de_visible(de->de_deh + de->de_entry_num))
+ reiserfs_panic(NULL,
+ "vs-7042: entry_points_to_object: entry must be visible");
+ return (de->de_objectid == inode->i_ino) ? 1 : 0;
+ }
- /* this must be added hidden entry */
- if (de_visible (de->de_deh + de->de_entry_num))
- reiserfs_panic (NULL, "vs-7043: entry_points_to_object: entry must be visible");
+ /* this must be added hidden entry */
+ if (de_visible(de->de_deh + de->de_entry_num))
+ reiserfs_panic(NULL,
+ "vs-7043: entry_points_to_object: entry must be visible");
- return 1;
+ return 1;
}
-
/* sets key of objectid the entry has to point to */
-static void set_ino_in_dir_entry (struct reiserfs_dir_entry * de, struct reiserfs_key * key)
+static void set_ino_in_dir_entry(struct reiserfs_dir_entry *de,
+ struct reiserfs_key *key)
{
- /* JDM These operations are endian safe - both are le */
- de->de_deh[de->de_entry_num].deh_dir_id = key->k_dir_id;
- de->de_deh[de->de_entry_num].deh_objectid = key->k_objectid;
+ /* JDM These operations are endian safe - both are le */
+ de->de_deh[de->de_entry_num].deh_dir_id = key->k_dir_id;
+ de->de_deh[de->de_entry_num].deh_objectid = key->k_objectid;
}
-
/*
* process, that is going to call fix_nodes/do_balance must hold only
* one path. If it holds 2 or more, it can get into endless waiting in
* get_empty_nodes or its clones
*/
-static int reiserfs_rename (struct inode * old_dir, struct dentry *old_dentry,
- struct inode * new_dir, struct dentry *new_dentry)
+static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
{
- int retval;
- INITIALIZE_PATH (old_entry_path);
- INITIALIZE_PATH (new_entry_path);
- INITIALIZE_PATH (dot_dot_entry_path);
- struct item_head new_entry_ih, old_entry_ih, dot_dot_ih ;
- struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
- struct inode * old_inode, * new_dentry_inode;
- struct reiserfs_transaction_handle th ;
- int jbegin_count ;
- umode_t old_inode_mode;
- unsigned long savelink = 1;
- struct timespec ctime;
-
- /* three balancings: (1) old name removal, (2) new name insertion
- and (3) maybe "save" link insertion
- stat data updates: (1) old directory,
- (2) new directory and (3) maybe old object stat data (when it is
- directory) and (4) maybe stat data of object to which new entry
- pointed initially and (5) maybe block containing ".." of
- renamed directory
- quota updates: two parent directories */
- jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 5 + 4 * REISERFS_QUOTA_TRANS_BLOCKS;
-
- old_inode = old_dentry->d_inode;
- new_dentry_inode = new_dentry->d_inode;
-
- // make sure, that oldname still exists and points to an object we
- // are going to rename
- old_de.de_gen_number_bit_string = NULL;
- reiserfs_write_lock(old_dir->i_sb);
- retval = reiserfs_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len,
- &old_entry_path, &old_de);
- pathrelse (&old_entry_path);
- if (retval == IO_ERROR) {
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
- }
-
- if (retval != NAME_FOUND || old_de.de_objectid != old_inode->i_ino) {
- reiserfs_write_unlock(old_dir->i_sb);
- return -ENOENT;
- }
-
- old_inode_mode = old_inode->i_mode;
- if (S_ISDIR(old_inode_mode)) {
- // make sure, that directory being renamed has correct ".."
- // and that its new parent directory has not too many links
- // already
-
- if (new_dentry_inode) {
- if (!reiserfs_empty_dir(new_dentry_inode)) {
+ int retval;
+ INITIALIZE_PATH(old_entry_path);
+ INITIALIZE_PATH(new_entry_path);
+ INITIALIZE_PATH(dot_dot_entry_path);
+ struct item_head new_entry_ih, old_entry_ih, dot_dot_ih;
+ struct reiserfs_dir_entry old_de, new_de, dot_dot_de;
+ struct inode *old_inode, *new_dentry_inode;
+ struct reiserfs_transaction_handle th;
+ int jbegin_count;
+ umode_t old_inode_mode;
+ unsigned long savelink = 1;
+ struct timespec ctime;
+
+ /* three balancings: (1) old name removal, (2) new name insertion
+ and (3) maybe "save" link insertion
+ stat data updates: (1) old directory,
+ (2) new directory and (3) maybe old object stat data (when it is
+ directory) and (4) maybe stat data of object to which new entry
+ pointed initially and (5) maybe block containing ".." of
+ renamed directory
+ quota updates: two parent directories */
+ jbegin_count =
+ JOURNAL_PER_BALANCE_CNT * 3 + 5 +
+ 4 * REISERFS_QUOTA_TRANS_BLOCKS(old_dir->i_sb);
+
+ old_inode = old_dentry->d_inode;
+ new_dentry_inode = new_dentry->d_inode;
+
+ // make sure, that oldname still exists and points to an object we
+ // are going to rename
+ old_de.de_gen_number_bit_string = NULL;
+ reiserfs_write_lock(old_dir->i_sb);
+ retval =
+ reiserfs_find_entry(old_dir, old_dentry->d_name.name,
+ old_dentry->d_name.len, &old_entry_path,
+ &old_de);
+ pathrelse(&old_entry_path);
+ if (retval == IO_ERROR) {
reiserfs_write_unlock(old_dir->i_sb);
- return -ENOTEMPTY;
- }
+ return -EIO;
}
-
- /* directory is renamed, its parent directory will be changed,
- ** so find ".." entry
- */
- dot_dot_de.de_gen_number_bit_string = NULL;
- retval = reiserfs_find_entry (old_inode, "..", 2, &dot_dot_entry_path, &dot_dot_de);
- pathrelse (&dot_dot_entry_path);
- if (retval != NAME_FOUND) {
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
+
+ if (retval != NAME_FOUND || old_de.de_objectid != old_inode->i_ino) {
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -ENOENT;
}
- /* inode number of .. must equal old_dir->i_ino */
- if (dot_dot_de.de_objectid != old_dir->i_ino) {
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
+ old_inode_mode = old_inode->i_mode;
+ if (S_ISDIR(old_inode_mode)) {
+ // make sure, that directory being renamed has correct ".."
+ // and that its new parent directory has not too many links
+ // already
+
+ if (new_dentry_inode) {
+ if (!reiserfs_empty_dir(new_dentry_inode)) {
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -ENOTEMPTY;
+ }
+ }
+
+ /* directory is renamed, its parent directory will be changed,
+ ** so find ".." entry
+ */
+ dot_dot_de.de_gen_number_bit_string = NULL;
+ retval =
+ reiserfs_find_entry(old_inode, "..", 2, &dot_dot_entry_path,
+ &dot_dot_de);
+ pathrelse(&dot_dot_entry_path);
+ if (retval != NAME_FOUND) {
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -EIO;
+ }
+
+ /* inode number of .. must equal old_dir->i_ino */
+ if (dot_dot_de.de_objectid != old_dir->i_ino) {
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -EIO;
+ }
}
- }
-
- retval = journal_begin(&th, old_dir->i_sb, jbegin_count) ;
- if (retval) {
- reiserfs_write_unlock (old_dir->i_sb);
- return retval;
- }
-
- /* add new entry (or find the existing one) */
- retval = reiserfs_add_entry (&th, new_dir, new_dentry->d_name.name, new_dentry->d_name.len,
- old_inode, 0);
- if (retval == -EEXIST) {
- if (!new_dentry_inode) {
- reiserfs_panic (old_dir->i_sb,
- "vs-7050: new entry is found, new inode == 0\n");
+
+ retval = journal_begin(&th, old_dir->i_sb, jbegin_count);
+ if (retval) {
+ reiserfs_write_unlock(old_dir->i_sb);
+ return retval;
}
- } else if (retval) {
- int err = journal_end(&th, old_dir->i_sb, jbegin_count) ;
- reiserfs_write_unlock(old_dir->i_sb);
- return err ? err : retval;
- }
-
- reiserfs_update_inode_transaction(old_dir) ;
- reiserfs_update_inode_transaction(new_dir) ;
-
- /* this makes it so an fsync on an open fd for the old name will
- ** commit the rename operation
- */
- reiserfs_update_inode_transaction(old_inode) ;
-
- if (new_dentry_inode)
- reiserfs_update_inode_transaction(new_dentry_inode) ;
-
- while (1) {
- // look for old name using corresponding entry key (found by reiserfs_find_entry)
- if ((retval = search_by_entry_key (new_dir->i_sb, &old_de.de_entry_key,
- &old_entry_path, &old_de)) != NAME_FOUND) {
- pathrelse(&old_entry_path);
- journal_end(&th, old_dir->i_sb, jbegin_count);
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
+
+ /* add new entry (or find the existing one) */
+ retval =
+ reiserfs_add_entry(&th, new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, old_inode, 0);
+ if (retval == -EEXIST) {
+ if (!new_dentry_inode) {
+ reiserfs_panic(old_dir->i_sb,
+ "vs-7050: new entry is found, new inode == 0\n");
+ }
+ } else if (retval) {
+ int err = journal_end(&th, old_dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(old_dir->i_sb);
+ return err ? err : retval;
}
- copy_item_head(&old_entry_ih, get_ih(&old_entry_path)) ;
-
- reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1) ;
-
- // look for new name by reiserfs_find_entry
- new_de.de_gen_number_bit_string = NULL;
- retval = reiserfs_find_entry (new_dir, new_dentry->d_name.name, new_dentry->d_name.len,
- &new_entry_path, &new_de);
- // reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from
- // reiserfs_add_entry above, and we'll catch any i/o errors before we get here.
- if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND) {
- pathrelse(&new_entry_path);
- pathrelse(&old_entry_path);
- journal_end(&th, old_dir->i_sb, jbegin_count);
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
+ reiserfs_update_inode_transaction(old_dir);
+ reiserfs_update_inode_transaction(new_dir);
+
+ /* this makes it so an fsync on an open fd for the old name will
+ ** commit the rename operation
+ */
+ reiserfs_update_inode_transaction(old_inode);
+
+ if (new_dentry_inode)
+ reiserfs_update_inode_transaction(new_dentry_inode);
+
+ while (1) {
+ // look for old name using corresponding entry key (found by reiserfs_find_entry)
+ if ((retval =
+ search_by_entry_key(new_dir->i_sb, &old_de.de_entry_key,
+ &old_entry_path,
+ &old_de)) != NAME_FOUND) {
+ pathrelse(&old_entry_path);
+ journal_end(&th, old_dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -EIO;
+ }
+
+ copy_item_head(&old_entry_ih, get_ih(&old_entry_path));
+
+ reiserfs_prepare_for_journal(old_inode->i_sb, old_de.de_bh, 1);
+
+ // look for new name by reiserfs_find_entry
+ new_de.de_gen_number_bit_string = NULL;
+ retval =
+ reiserfs_find_entry(new_dir, new_dentry->d_name.name,
+ new_dentry->d_name.len, &new_entry_path,
+ &new_de);
+ // reiserfs_add_entry should not return IO_ERROR, because it is called with essentially same parameters from
+ // reiserfs_add_entry above, and we'll catch any i/o errors before we get here.
+ if (retval != NAME_FOUND_INVISIBLE && retval != NAME_FOUND) {
+ pathrelse(&new_entry_path);
+ pathrelse(&old_entry_path);
+ journal_end(&th, old_dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -EIO;
+ }
+
+ copy_item_head(&new_entry_ih, get_ih(&new_entry_path));
+
+ reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1);
+
+ if (S_ISDIR(old_inode->i_mode)) {
+ if ((retval =
+ search_by_entry_key(new_dir->i_sb,
+ &dot_dot_de.de_entry_key,
+ &dot_dot_entry_path,
+ &dot_dot_de)) != NAME_FOUND) {
+ pathrelse(&dot_dot_entry_path);
+ pathrelse(&new_entry_path);
+ pathrelse(&old_entry_path);
+ journal_end(&th, old_dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(old_dir->i_sb);
+ return -EIO;
+ }
+ copy_item_head(&dot_dot_ih,
+ get_ih(&dot_dot_entry_path));
+ // node containing ".." gets into transaction
+ reiserfs_prepare_for_journal(old_inode->i_sb,
+ dot_dot_de.de_bh, 1);
+ }
+ /* we should check seals here, not do
+ this stuff, yes? Then, having
+ gathered everything into RAM we
+ should lock the buffers, yes? -Hans */
+ /* probably. our rename needs to hold more
+ ** than one path at once. The seals would
+ ** have to be written to deal with multi-path
+ ** issues -chris
+ */
+ /* sanity checking before doing the rename - avoid races many
+ ** of the above checks could have scheduled. We have to be
+ ** sure our items haven't been shifted by another process.
+ */
+ if (item_moved(&new_entry_ih, &new_entry_path) ||
+ !entry_points_to_object(new_dentry->d_name.name,
+ new_dentry->d_name.len,
+ &new_de, new_dentry_inode) ||
+ item_moved(&old_entry_ih, &old_entry_path) ||
+ !entry_points_to_object(old_dentry->d_name.name,
+ old_dentry->d_name.len,
+ &old_de, old_inode)) {
+ reiserfs_restore_prepared_buffer(old_inode->i_sb,
+ new_de.de_bh);
+ reiserfs_restore_prepared_buffer(old_inode->i_sb,
+ old_de.de_bh);
+ if (S_ISDIR(old_inode_mode))
+ reiserfs_restore_prepared_buffer(old_inode->
+ i_sb,
+ dot_dot_de.
+ de_bh);
+ continue;
+ }
+ if (S_ISDIR(old_inode_mode)) {
+ if (item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
+ !entry_points_to_object("..", 2, &dot_dot_de,
+ old_dir)) {
+ reiserfs_restore_prepared_buffer(old_inode->
+ i_sb,
+ old_de.de_bh);
+ reiserfs_restore_prepared_buffer(old_inode->
+ i_sb,
+ new_de.de_bh);
+ reiserfs_restore_prepared_buffer(old_inode->
+ i_sb,
+ dot_dot_de.
+ de_bh);
+ continue;
+ }
+ }
+
+ RFALSE(S_ISDIR(old_inode_mode) &&
+ !buffer_journal_prepared(dot_dot_de.de_bh), "");
+
+ break;
}
- copy_item_head(&new_entry_ih, get_ih(&new_entry_path)) ;
+ /* ok, all the changes can be done in one fell swoop when we
+ have claimed all the buffers needed. */
- reiserfs_prepare_for_journal(old_inode->i_sb, new_de.de_bh, 1) ;
+ mark_de_visible(new_de.de_deh + new_de.de_entry_num);
+ set_ino_in_dir_entry(&new_de, INODE_PKEY(old_inode));
+ journal_mark_dirty(&th, old_dir->i_sb, new_de.de_bh);
- if (S_ISDIR(old_inode->i_mode)) {
- if ((retval = search_by_entry_key (new_dir->i_sb, &dot_dot_de.de_entry_key,
- &dot_dot_entry_path, &dot_dot_de)) != NAME_FOUND) {
- pathrelse(&dot_dot_entry_path);
- pathrelse(&new_entry_path);
- pathrelse(&old_entry_path);
- journal_end(&th, old_dir->i_sb, jbegin_count);
- reiserfs_write_unlock(old_dir->i_sb);
- return -EIO;
- }
- copy_item_head(&dot_dot_ih, get_ih(&dot_dot_entry_path)) ;
- // node containing ".." gets into transaction
- reiserfs_prepare_for_journal(old_inode->i_sb, dot_dot_de.de_bh, 1) ;
- }
- /* we should check seals here, not do
- this stuff, yes? Then, having
- gathered everything into RAM we
- should lock the buffers, yes? -Hans */
- /* probably. our rename needs to hold more
- ** than one path at once. The seals would
- ** have to be written to deal with multi-path
- ** issues -chris
- */
- /* sanity checking before doing the rename - avoid races many
- ** of the above checks could have scheduled. We have to be
- ** sure our items haven't been shifted by another process.
- */
- if (item_moved(&new_entry_ih, &new_entry_path) ||
- !entry_points_to_object(new_dentry->d_name.name,
- new_dentry->d_name.len,
- &new_de, new_dentry_inode) ||
- item_moved(&old_entry_ih, &old_entry_path) ||
- !entry_points_to_object (old_dentry->d_name.name,
- old_dentry->d_name.len,
- &old_de, old_inode)) {
- reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
- reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
- if (S_ISDIR(old_inode_mode))
- reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
- continue;
+ mark_de_hidden(old_de.de_deh + old_de.de_entry_num);
+ journal_mark_dirty(&th, old_dir->i_sb, old_de.de_bh);
+ ctime = CURRENT_TIME_SEC;
+ old_dir->i_ctime = old_dir->i_mtime = ctime;
+ new_dir->i_ctime = new_dir->i_mtime = ctime;
+ /* thanks to Alex Adriaanse <alex_a@caltech.edu> for patch which adds ctime update of
+ renamed object */
+ old_inode->i_ctime = ctime;
+
+ if (new_dentry_inode) {
+ // adjust link number of the victim
+ if (S_ISDIR(new_dentry_inode->i_mode)) {
+ new_dentry_inode->i_nlink = 0;
+ } else {
+ new_dentry_inode->i_nlink--;
+ }
+ new_dentry_inode->i_ctime = ctime;
+ savelink = new_dentry_inode->i_nlink;
}
+
if (S_ISDIR(old_inode_mode)) {
- if ( item_moved(&dot_dot_ih, &dot_dot_entry_path) ||
- !entry_points_to_object ( "..", 2, &dot_dot_de, old_dir) ) {
- reiserfs_restore_prepared_buffer (old_inode->i_sb, old_de.de_bh);
- reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
- reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
- continue;
- }
+ // adjust ".." of renamed directory
+ set_ino_in_dir_entry(&dot_dot_de, INODE_PKEY(new_dir));
+ journal_mark_dirty(&th, new_dir->i_sb, dot_dot_de.de_bh);
+
+ if (!new_dentry_inode)
+ /* there (in new_dir) was no directory, so it got new link
+ (".." of renamed directory) */
+ INC_DIR_INODE_NLINK(new_dir);
+
+ /* old directory lost one link - ".. " of renamed directory */
+ DEC_DIR_INODE_NLINK(old_dir);
}
+ // looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
+ pathrelse(&new_entry_path);
+ pathrelse(&dot_dot_entry_path);
- RFALSE( S_ISDIR(old_inode_mode) &&
- !buffer_journal_prepared(dot_dot_de.de_bh), "" );
-
- break;
- }
-
- /* ok, all the changes can be done in one fell swoop when we
- have claimed all the buffers needed.*/
-
- mark_de_visible (new_de.de_deh + new_de.de_entry_num);
- set_ino_in_dir_entry (&new_de, INODE_PKEY (old_inode));
- journal_mark_dirty (&th, old_dir->i_sb, new_de.de_bh);
-
- mark_de_hidden (old_de.de_deh + old_de.de_entry_num);
- journal_mark_dirty (&th, old_dir->i_sb, old_de.de_bh);
- ctime = CURRENT_TIME_SEC;
- old_dir->i_ctime = old_dir->i_mtime = ctime;
- new_dir->i_ctime = new_dir->i_mtime = ctime;
- /* thanks to Alex Adriaanse <alex_a@caltech.edu> for patch which adds ctime update of
- renamed object */
- old_inode->i_ctime = ctime;
-
- if (new_dentry_inode) {
- // adjust link number of the victim
- if (S_ISDIR(new_dentry_inode->i_mode)) {
- new_dentry_inode->i_nlink = 0;
- } else {
- new_dentry_inode->i_nlink--;
+ // FIXME: this reiserfs_cut_from_item's return value may screw up
+ // anybody, but it will panic if will not be able to find the
+ // entry. This needs one more clean up
+ if (reiserfs_cut_from_item
+ (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL,
+ 0) < 0)
+ reiserfs_warning(old_dir->i_sb,
+ "vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?");
+
+ old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
+
+ reiserfs_update_sd(&th, old_dir);
+ reiserfs_update_sd(&th, new_dir);
+ reiserfs_update_sd(&th, old_inode);
+
+ if (new_dentry_inode) {
+ if (savelink == 0)
+ add_save_link(&th, new_dentry_inode,
+ 0 /* not truncate */ );
+ reiserfs_update_sd(&th, new_dentry_inode);
}
- new_dentry_inode->i_ctime = ctime;
- savelink = new_dentry_inode->i_nlink;
- }
-
- if (S_ISDIR(old_inode_mode)) {
- // adjust ".." of renamed directory
- set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
- journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
-
- if (!new_dentry_inode)
- /* there (in new_dir) was no directory, so it got new link
- (".." of renamed directory) */
- INC_DIR_INODE_NLINK(new_dir);
-
- /* old directory lost one link - ".. " of renamed directory */
- DEC_DIR_INODE_NLINK(old_dir);
- }
-
- // looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
- pathrelse (&new_entry_path);
- pathrelse (&dot_dot_entry_path);
-
- // FIXME: this reiserfs_cut_from_item's return value may screw up
- // anybody, but it will panic if will not be able to find the
- // entry. This needs one more clean up
- if (reiserfs_cut_from_item (&th, &old_entry_path, &(old_de.de_entry_key), old_dir, NULL, 0) < 0)
- reiserfs_warning (old_dir->i_sb, "vs-7060: reiserfs_rename: couldn't not cut old name. Fsck later?");
-
- old_dir->i_size -= DEH_SIZE + old_de.de_entrylen;
-
- reiserfs_update_sd (&th, old_dir);
- reiserfs_update_sd (&th, new_dir);
- reiserfs_update_sd (&th, old_inode);
-
- if (new_dentry_inode) {
- if (savelink == 0)
- add_save_link (&th, new_dentry_inode, 0/* not truncate */);
- reiserfs_update_sd (&th, new_dentry_inode);
- }
-
- retval = journal_end(&th, old_dir->i_sb, jbegin_count) ;
- reiserfs_write_unlock(old_dir->i_sb);
- return retval;
+
+ retval = journal_end(&th, old_dir->i_sb, jbegin_count);
+ reiserfs_write_unlock(old_dir->i_sb);
+ return retval;
}
/*
* directories can handle most operations...
*/
struct inode_operations reiserfs_dir_inode_operations = {
- //&reiserfs_dir_operations, /* default_file_ops */
- .create = reiserfs_create,
- .lookup = reiserfs_lookup,
- .link = reiserfs_link,
- .unlink = reiserfs_unlink,
- .symlink = reiserfs_symlink,
- .mkdir = reiserfs_mkdir,
- .rmdir = reiserfs_rmdir,
- .mknod = reiserfs_mknod,
- .rename = reiserfs_rename,
- .setattr = reiserfs_setattr,
- .setxattr = reiserfs_setxattr,
- .getxattr = reiserfs_getxattr,
- .listxattr = reiserfs_listxattr,
- .removexattr = reiserfs_removexattr,
- .permission = reiserfs_permission,
+ //&reiserfs_dir_operations, /* default_file_ops */
+ .create = reiserfs_create,
+ .lookup = reiserfs_lookup,
+ .link = reiserfs_link,
+ .unlink = reiserfs_unlink,
+ .symlink = reiserfs_symlink,
+ .mkdir = reiserfs_mkdir,
+ .rmdir = reiserfs_rmdir,
+ .mknod = reiserfs_mknod,
+ .rename = reiserfs_rename,
+ .setattr = reiserfs_setattr,
+ .setxattr = reiserfs_setxattr,
+ .getxattr = reiserfs_getxattr,
+ .listxattr = reiserfs_listxattr,
+ .removexattr = reiserfs_removexattr,
+ .permission = reiserfs_permission,
};
/*
@@ -1464,28 +1554,27 @@ struct inode_operations reiserfs_dir_inode_operations = {
* stuff added
*/
struct inode_operations reiserfs_symlink_inode_operations = {
- .readlink = generic_readlink,
- .follow_link = page_follow_link_light,
- .put_link = page_put_link,
- .setattr = reiserfs_setattr,
- .setxattr = reiserfs_setxattr,
- .getxattr = reiserfs_getxattr,
- .listxattr = reiserfs_listxattr,
- .removexattr = reiserfs_removexattr,
- .permission = reiserfs_permission,
+ .readlink = generic_readlink,
+ .follow_link = page_follow_link_light,
+ .put_link = page_put_link,
+ .setattr = reiserfs_setattr,
+ .setxattr = reiserfs_setxattr,
+ .getxattr = reiserfs_getxattr,
+ .listxattr = reiserfs_listxattr,
+ .removexattr = reiserfs_removexattr,
+ .permission = reiserfs_permission,
};
-
/*
* special file operations.. just xattr/acl stuff
*/
struct inode_operations reiserfs_special_inode_operations = {
- .setattr = reiserfs_setattr,
- .setxattr = reiserfs_setxattr,
- .getxattr = reiserfs_getxattr,
- .listxattr = reiserfs_listxattr,
- .removexattr = reiserfs_removexattr,
- .permission = reiserfs_permission,
+ .setattr = reiserfs_setattr,
+ .setxattr = reiserfs_setxattr,
+ .getxattr = reiserfs_getxattr,
+ .listxattr = reiserfs_listxattr,
+ .removexattr = reiserfs_removexattr,
+ .permission = reiserfs_permission,
};
diff --git a/fs/reiserfs/objectid.c b/fs/reiserfs/objectid.c
index bfe8e25ef293..f62590aa9c95 100644
--- a/fs/reiserfs/objectid.c
+++ b/fs/reiserfs/objectid.c
@@ -14,24 +14,24 @@
(__le32 *)((struct reiserfs_super_block_v1 *)(rs) + 1) :\
(__le32 *)((rs) + 1))
-
#ifdef CONFIG_REISERFS_CHECK
-static void check_objectid_map (struct super_block * s, __le32 * map)
+static void check_objectid_map(struct super_block *s, __le32 * map)
{
- if (le32_to_cpu (map[0]) != 1)
- reiserfs_panic (s, "vs-15010: check_objectid_map: map corrupted: %lx",
- ( long unsigned int ) le32_to_cpu (map[0]));
+ if (le32_to_cpu(map[0]) != 1)
+ reiserfs_panic(s,
+ "vs-15010: check_objectid_map: map corrupted: %lx",
+ (long unsigned int)le32_to_cpu(map[0]));
- // FIXME: add something else here
+ // FIXME: add something else here
}
#else
-static void check_objectid_map (struct super_block * s, __le32 * map)
-{;}
+static void check_objectid_map(struct super_block *s, __le32 * map)
+{;
+}
#endif
-
/* When we allocate objectids we allocate the first unused objectid.
Each sequence of objectids in use (the odd sequences) is followed
by a sequence of objectids not in use (the even sequences). We
@@ -46,161 +46,162 @@ static void check_objectid_map (struct super_block * s, __le32 * map)
interesting optimizations of layout could result from complicating
objectid assignment, but we have deferred making them for now. */
-
/* get unique object identifier */
-__u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th)
+__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th)
{
- struct super_block * s = th->t_super;
- struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
- __le32 * map = objectid_map (s, rs);
- __u32 unused_objectid;
-
- BUG_ON (!th->t_trans_id);
+ struct super_block *s = th->t_super;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
+ __le32 *map = objectid_map(s, rs);
+ __u32 unused_objectid;
+
+ BUG_ON(!th->t_trans_id);
+
+ check_objectid_map(s, map);
+
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+ /* comment needed -Hans */
+ unused_objectid = le32_to_cpu(map[1]);
+ if (unused_objectid == U32_MAX) {
+ reiserfs_warning(s, "%s: no more object ids", __FUNCTION__);
+ reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s));
+ return 0;
+ }
- check_objectid_map (s, map);
+ /* This incrementation allocates the first unused objectid. That
+ is to say, the first entry on the objectid map is the first
+ unused objectid, and by incrementing it we use it. See below
+ where we check to see if we eliminated a sequence of unused
+ objectids.... */
+ map[1] = cpu_to_le32(unused_objectid + 1);
+
+ /* Now we check to see if we eliminated the last remaining member of
+ the first even sequence (and can eliminate the sequence by
+ eliminating its last objectid from oids), and can collapse the
+ first two odd sequences into one sequence. If so, then the net
+ result is to eliminate a pair of objectids from oids. We do this
+ by shifting the entire map to the left. */
+ if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
+ memmove(map + 1, map + 3,
+ (sb_oid_cursize(rs) - 3) * sizeof(__u32));
+ set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
+ }
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
- /* comment needed -Hans */
- unused_objectid = le32_to_cpu (map[1]);
- if (unused_objectid == U32_MAX) {
- reiserfs_warning (s, "%s: no more object ids", __FUNCTION__);
- reiserfs_restore_prepared_buffer(s, SB_BUFFER_WITH_SB(s)) ;
- return 0;
- }
-
- /* This incrementation allocates the first unused objectid. That
- is to say, the first entry on the objectid map is the first
- unused objectid, and by incrementing it we use it. See below
- where we check to see if we eliminated a sequence of unused
- objectids.... */
- map[1] = cpu_to_le32 (unused_objectid + 1);
-
- /* Now we check to see if we eliminated the last remaining member of
- the first even sequence (and can eliminate the sequence by
- eliminating its last objectid from oids), and can collapse the
- first two odd sequences into one sequence. If so, then the net
- result is to eliminate a pair of objectids from oids. We do this
- by shifting the entire map to the left. */
- if (sb_oid_cursize(rs) > 2 && map[1] == map[2]) {
- memmove (map + 1, map + 3, (sb_oid_cursize(rs) - 3) * sizeof(__u32));
- set_sb_oid_cursize( rs, sb_oid_cursize(rs) - 2 );
- }
-
- journal_mark_dirty(th, s, SB_BUFFER_WITH_SB (s));
- return unused_objectid;
+ journal_mark_dirty(th, s, SB_BUFFER_WITH_SB(s));
+ return unused_objectid;
}
-
/* makes object identifier unused */
-void reiserfs_release_objectid (struct reiserfs_transaction_handle *th,
- __u32 objectid_to_release)
+void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
+ __u32 objectid_to_release)
{
- struct super_block * s = th->t_super;
- struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
- __le32 * map = objectid_map (s, rs);
- int i = 0;
-
- BUG_ON (!th->t_trans_id);
- //return;
- check_objectid_map (s, map);
-
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
- journal_mark_dirty(th, s, SB_BUFFER_WITH_SB (s));
-
- /* start at the beginning of the objectid map (i = 0) and go to
- the end of it (i = disk_sb->s_oid_cursize). Linear search is
- what we use, though it is possible that binary search would be
- more efficient after performing lots of deletions (which is
- when oids is large.) We only check even i's. */
- while (i < sb_oid_cursize(rs)) {
- if (objectid_to_release == le32_to_cpu (map[i])) {
- /* This incrementation unallocates the objectid. */
- //map[i]++;
- map[i] = cpu_to_le32 (le32_to_cpu (map[i]) + 1);
-
- /* Did we unallocate the last member of an odd sequence, and can shrink oids? */
- if (map[i] == map[i+1]) {
- /* shrink objectid map */
- memmove (map + i, map + i + 2,
- (sb_oid_cursize(rs) - i - 2) * sizeof (__u32));
- //disk_sb->s_oid_cursize -= 2;
- set_sb_oid_cursize( rs, sb_oid_cursize(rs) - 2 );
-
- RFALSE( sb_oid_cursize(rs) < 2 ||
- sb_oid_cursize(rs) > sb_oid_maxsize(rs),
- "vs-15005: objectid map corrupted cur_size == %d (max == %d)",
- sb_oid_cursize(rs), sb_oid_maxsize(rs));
- }
- return;
+ struct super_block *s = th->t_super;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
+ __le32 *map = objectid_map(s, rs);
+ int i = 0;
+
+ BUG_ON(!th->t_trans_id);
+ //return;
+ check_objectid_map(s, map);
+
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+ journal_mark_dirty(th, s, SB_BUFFER_WITH_SB(s));
+
+ /* start at the beginning of the objectid map (i = 0) and go to
+ the end of it (i = disk_sb->s_oid_cursize). Linear search is
+ what we use, though it is possible that binary search would be
+ more efficient after performing lots of deletions (which is
+ when oids is large.) We only check even i's. */
+ while (i < sb_oid_cursize(rs)) {
+ if (objectid_to_release == le32_to_cpu(map[i])) {
+ /* This incrementation unallocates the objectid. */
+ //map[i]++;
+ map[i] = cpu_to_le32(le32_to_cpu(map[i]) + 1);
+
+ /* Did we unallocate the last member of an odd sequence, and can shrink oids? */
+ if (map[i] == map[i + 1]) {
+ /* shrink objectid map */
+ memmove(map + i, map + i + 2,
+ (sb_oid_cursize(rs) - i -
+ 2) * sizeof(__u32));
+ //disk_sb->s_oid_cursize -= 2;
+ set_sb_oid_cursize(rs, sb_oid_cursize(rs) - 2);
+
+ RFALSE(sb_oid_cursize(rs) < 2 ||
+ sb_oid_cursize(rs) > sb_oid_maxsize(rs),
+ "vs-15005: objectid map corrupted cur_size == %d (max == %d)",
+ sb_oid_cursize(rs), sb_oid_maxsize(rs));
+ }
+ return;
+ }
+
+ if (objectid_to_release > le32_to_cpu(map[i]) &&
+ objectid_to_release < le32_to_cpu(map[i + 1])) {
+ /* size of objectid map is not changed */
+ if (objectid_to_release + 1 == le32_to_cpu(map[i + 1])) {
+ //objectid_map[i+1]--;
+ map[i + 1] =
+ cpu_to_le32(le32_to_cpu(map[i + 1]) - 1);
+ return;
+ }
+
+ /* JDM comparing two little-endian values for equality -- safe */
+ if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
+ /* objectid map must be expanded, but there is no space */
+ PROC_INFO_INC(s, leaked_oid);
+ return;
+ }
+
+ /* expand the objectid map */
+ memmove(map + i + 3, map + i + 1,
+ (sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
+ map[i + 1] = cpu_to_le32(objectid_to_release);
+ map[i + 2] = cpu_to_le32(objectid_to_release + 1);
+ set_sb_oid_cursize(rs, sb_oid_cursize(rs) + 2);
+ return;
+ }
+ i += 2;
}
- if (objectid_to_release > le32_to_cpu (map[i]) &&
- objectid_to_release < le32_to_cpu (map[i + 1])) {
- /* size of objectid map is not changed */
- if (objectid_to_release + 1 == le32_to_cpu (map[i + 1])) {
- //objectid_map[i+1]--;
- map[i + 1] = cpu_to_le32 (le32_to_cpu (map[i + 1]) - 1);
- return;
- }
-
- /* JDM comparing two little-endian values for equality -- safe */
- if (sb_oid_cursize(rs) == sb_oid_maxsize(rs)) {
- /* objectid map must be expanded, but there is no space */
- PROC_INFO_INC( s, leaked_oid );
- return;
- }
+ reiserfs_warning(s,
+ "vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)",
+ (long unsigned)objectid_to_release);
+}
- /* expand the objectid map*/
- memmove (map + i + 3, map + i + 1,
- (sb_oid_cursize(rs) - i - 1) * sizeof(__u32));
- map[i + 1] = cpu_to_le32 (objectid_to_release);
- map[i + 2] = cpu_to_le32 (objectid_to_release + 1);
- set_sb_oid_cursize( rs, sb_oid_cursize(rs) + 2 );
- return;
+int reiserfs_convert_objectid_map_v1(struct super_block *s)
+{
+ struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK(s);
+ int cur_size = sb_oid_cursize(disk_sb);
+ int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2;
+ int old_max = sb_oid_maxsize(disk_sb);
+ struct reiserfs_super_block_v1 *disk_sb_v1;
+ __le32 *objectid_map, *new_objectid_map;
+ int i;
+
+ disk_sb_v1 =
+ (struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
+ objectid_map = (__le32 *) (disk_sb_v1 + 1);
+ new_objectid_map = (__le32 *) (disk_sb + 1);
+
+ if (cur_size > new_size) {
+ /* mark everyone used that was listed as free at the end of the objectid
+ ** map
+ */
+ objectid_map[new_size - 1] = objectid_map[cur_size - 1];
+ set_sb_oid_cursize(disk_sb, new_size);
+ }
+ /* move the smaller objectid map past the end of the new super */
+ for (i = new_size - 1; i >= 0; i--) {
+ objectid_map[i + (old_max - new_size)] = objectid_map[i];
}
- i += 2;
- }
- reiserfs_warning (s, "vs-15011: reiserfs_release_objectid: tried to free free object id (%lu)",
- ( long unsigned ) objectid_to_release);
-}
+ /* set the max size so we don't overflow later */
+ set_sb_oid_maxsize(disk_sb, new_size);
+ /* Zero out label and generate random UUID */
+ memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label));
+ generate_random_uuid(disk_sb->s_uuid);
-int reiserfs_convert_objectid_map_v1(struct super_block *s) {
- struct reiserfs_super_block *disk_sb = SB_DISK_SUPER_BLOCK (s);
- int cur_size = sb_oid_cursize(disk_sb);
- int new_size = (s->s_blocksize - SB_SIZE) / sizeof(__u32) / 2 * 2 ;
- int old_max = sb_oid_maxsize(disk_sb);
- struct reiserfs_super_block_v1 *disk_sb_v1 ;
- __le32 *objectid_map, *new_objectid_map ;
- int i ;
-
- disk_sb_v1=(struct reiserfs_super_block_v1 *)(SB_BUFFER_WITH_SB(s)->b_data);
- objectid_map = (__le32 *)(disk_sb_v1 + 1) ;
- new_objectid_map = (__le32 *)(disk_sb + 1) ;
-
- if (cur_size > new_size) {
- /* mark everyone used that was listed as free at the end of the objectid
- ** map
- */
- objectid_map[new_size - 1] = objectid_map[cur_size - 1] ;
- set_sb_oid_cursize(disk_sb,new_size) ;
- }
- /* move the smaller objectid map past the end of the new super */
- for (i = new_size - 1 ; i >= 0 ; i--) {
- objectid_map[i + (old_max - new_size)] = objectid_map[i] ;
- }
-
-
- /* set the max size so we don't overflow later */
- set_sb_oid_maxsize(disk_sb,new_size) ;
-
- /* Zero out label and generate random UUID */
- memset(disk_sb->s_label, 0, sizeof(disk_sb->s_label)) ;
- generate_random_uuid(disk_sb->s_uuid);
-
- /* finally, zero out the unused chunk of the new super */
- memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused)) ;
- return 0 ;
+ /* finally, zero out the unused chunk of the new super */
+ memset(disk_sb->s_unused, 0, sizeof(disk_sb->s_unused));
+ return 0;
}
-
diff --git a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
index 16fdca1d4bd7..d55e164bd5c2 100644
--- a/fs/reiserfs/prints.c
+++ b/fs/reiserfs/prints.c
@@ -15,168 +15,166 @@ static char error_buf[1024];
static char fmt_buf[1024];
static char off_buf[80];
-
-static char * reiserfs_cpu_offset (struct cpu_key * key)
+static char *reiserfs_cpu_offset(struct cpu_key *key)
{
- if (cpu_key_k_type(key) == TYPE_DIRENTRY)
- sprintf (off_buf, "%Lu(%Lu)",
- (unsigned long long)GET_HASH_VALUE (cpu_key_k_offset (key)),
- (unsigned long long)GET_GENERATION_NUMBER (cpu_key_k_offset (key)));
- else
- sprintf (off_buf, "0x%Lx", (unsigned long long)cpu_key_k_offset (key));
- return off_buf;
+ if (cpu_key_k_type(key) == TYPE_DIRENTRY)
+ sprintf(off_buf, "%Lu(%Lu)",
+ (unsigned long long)
+ GET_HASH_VALUE(cpu_key_k_offset(key)),
+ (unsigned long long)
+ GET_GENERATION_NUMBER(cpu_key_k_offset(key)));
+ else
+ sprintf(off_buf, "0x%Lx",
+ (unsigned long long)cpu_key_k_offset(key));
+ return off_buf;
}
-
-static char * le_offset (struct reiserfs_key * key)
+static char *le_offset(struct reiserfs_key *key)
{
- int version;
+ int version;
- version = le_key_version (key);
- if (le_key_k_type (version, key) == TYPE_DIRENTRY)
- sprintf (off_buf, "%Lu(%Lu)",
- (unsigned long long)GET_HASH_VALUE (le_key_k_offset (version, key)),
- (unsigned long long)GET_GENERATION_NUMBER (le_key_k_offset (version, key)));
- else
- sprintf (off_buf, "0x%Lx", (unsigned long long)le_key_k_offset (version, key));
- return off_buf;
+ version = le_key_version(key);
+ if (le_key_k_type(version, key) == TYPE_DIRENTRY)
+ sprintf(off_buf, "%Lu(%Lu)",
+ (unsigned long long)
+ GET_HASH_VALUE(le_key_k_offset(version, key)),
+ (unsigned long long)
+ GET_GENERATION_NUMBER(le_key_k_offset(version, key)));
+ else
+ sprintf(off_buf, "0x%Lx",
+ (unsigned long long)le_key_k_offset(version, key));
+ return off_buf;
}
-
-static char * cpu_type (struct cpu_key * key)
+static char *cpu_type(struct cpu_key *key)
{
- if (cpu_key_k_type (key) == TYPE_STAT_DATA)
- return "SD";
- if (cpu_key_k_type (key) == TYPE_DIRENTRY)
- return "DIR";
- if (cpu_key_k_type (key) == TYPE_DIRECT)
- return "DIRECT";
- if (cpu_key_k_type (key) == TYPE_INDIRECT)
- return "IND";
- return "UNKNOWN";
+ if (cpu_key_k_type(key) == TYPE_STAT_DATA)
+ return "SD";
+ if (cpu_key_k_type(key) == TYPE_DIRENTRY)
+ return "DIR";
+ if (cpu_key_k_type(key) == TYPE_DIRECT)
+ return "DIRECT";
+ if (cpu_key_k_type(key) == TYPE_INDIRECT)
+ return "IND";
+ return "UNKNOWN";
}
-
-static char * le_type (struct reiserfs_key * key)
+static char *le_type(struct reiserfs_key *key)
{
- int version;
-
- version = le_key_version (key);
+ int version;
- if (le_key_k_type (version, key) == TYPE_STAT_DATA)
- return "SD";
- if (le_key_k_type (version, key) == TYPE_DIRENTRY)
- return "DIR";
- if (le_key_k_type (version, key) == TYPE_DIRECT)
- return "DIRECT";
- if (le_key_k_type (version, key) == TYPE_INDIRECT)
- return "IND";
- return "UNKNOWN";
-}
+ version = le_key_version(key);
+ if (le_key_k_type(version, key) == TYPE_STAT_DATA)
+ return "SD";
+ if (le_key_k_type(version, key) == TYPE_DIRENTRY)
+ return "DIR";
+ if (le_key_k_type(version, key) == TYPE_DIRECT)
+ return "DIRECT";
+ if (le_key_k_type(version, key) == TYPE_INDIRECT)
+ return "IND";
+ return "UNKNOWN";
+}
/* %k */
-static void sprintf_le_key (char * buf, struct reiserfs_key * key)
+static void sprintf_le_key(char *buf, struct reiserfs_key *key)
{
- if (key)
- sprintf (buf, "[%d %d %s %s]", le32_to_cpu (key->k_dir_id),
- le32_to_cpu (key->k_objectid), le_offset (key), le_type (key));
- else
- sprintf (buf, "[NULL]");
+ if (key)
+ sprintf(buf, "[%d %d %s %s]", le32_to_cpu(key->k_dir_id),
+ le32_to_cpu(key->k_objectid), le_offset(key),
+ le_type(key));
+ else
+ sprintf(buf, "[NULL]");
}
-
/* %K */
-static void sprintf_cpu_key (char * buf, struct cpu_key * key)
+static void sprintf_cpu_key(char *buf, struct cpu_key *key)
{
- if (key)
- sprintf (buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
- key->on_disk_key.k_objectid, reiserfs_cpu_offset (key),
- cpu_type (key));
- else
- sprintf (buf, "[NULL]");
+ if (key)
+ sprintf(buf, "[%d %d %s %s]", key->on_disk_key.k_dir_id,
+ key->on_disk_key.k_objectid, reiserfs_cpu_offset(key),
+ cpu_type(key));
+ else
+ sprintf(buf, "[NULL]");
}
-static void sprintf_de_head( char *buf, struct reiserfs_de_head *deh )
+static void sprintf_de_head(char *buf, struct reiserfs_de_head *deh)
{
- if( deh )
- sprintf( buf, "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]", deh_offset(deh), deh_dir_id(deh),
- deh_objectid(deh), deh_location(deh), deh_state(deh) );
- else
- sprintf( buf, "[NULL]" );
+ if (deh)
+ sprintf(buf,
+ "[offset=%d dir_id=%d objectid=%d location=%d state=%04x]",
+ deh_offset(deh), deh_dir_id(deh), deh_objectid(deh),
+ deh_location(deh), deh_state(deh));
+ else
+ sprintf(buf, "[NULL]");
}
-static void sprintf_item_head (char * buf, struct item_head * ih)
+static void sprintf_item_head(char *buf, struct item_head *ih)
{
- if (ih) {
- strcpy (buf, (ih_version (ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
- sprintf_le_key (buf + strlen (buf), &(ih->ih_key));
- sprintf (buf + strlen (buf), ", item_len %d, item_location %d, "
- "free_space(entry_count) %d",
- ih_item_len(ih), ih_location(ih), ih_free_space (ih));
- } else
- sprintf (buf, "[NULL]");
+ if (ih) {
+ strcpy(buf,
+ (ih_version(ih) == KEY_FORMAT_3_6) ? "*3.6* " : "*3.5*");
+ sprintf_le_key(buf + strlen(buf), &(ih->ih_key));
+ sprintf(buf + strlen(buf), ", item_len %d, item_location %d, "
+ "free_space(entry_count) %d",
+ ih_item_len(ih), ih_location(ih), ih_free_space(ih));
+ } else
+ sprintf(buf, "[NULL]");
}
-
-static void sprintf_direntry (char * buf, struct reiserfs_dir_entry * de)
+static void sprintf_direntry(char *buf, struct reiserfs_dir_entry *de)
{
- char name[20];
+ char name[20];
- memcpy (name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
- name [de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
- sprintf (buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid);
+ memcpy(name, de->de_name, de->de_namelen > 19 ? 19 : de->de_namelen);
+ name[de->de_namelen > 19 ? 19 : de->de_namelen] = 0;
+ sprintf(buf, "\"%s\"==>[%d %d]", name, de->de_dir_id, de->de_objectid);
}
-
-static void sprintf_block_head (char * buf, struct buffer_head * bh)
+static void sprintf_block_head(char *buf, struct buffer_head *bh)
{
- sprintf (buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
- B_LEVEL (bh), B_NR_ITEMS (bh), B_FREE_SPACE (bh));
+ sprintf(buf, "level=%d, nr_items=%d, free_space=%d rdkey ",
+ B_LEVEL(bh), B_NR_ITEMS(bh), B_FREE_SPACE(bh));
}
-
-static void sprintf_buffer_head (char * buf, struct buffer_head * bh)
+static void sprintf_buffer_head(char *buf, struct buffer_head *bh)
{
- char b[BDEVNAME_SIZE];
+ char b[BDEVNAME_SIZE];
- sprintf (buf, "dev %s, size %d, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
- bdevname (bh->b_bdev, b), bh->b_size,
- (unsigned long long)bh->b_blocknr,
- atomic_read (&(bh->b_count)),
- bh->b_state, bh->b_page,
- buffer_uptodate (bh) ? "UPTODATE" : "!UPTODATE",
- buffer_dirty (bh) ? "DIRTY" : "CLEAN",
- buffer_locked (bh) ? "LOCKED" : "UNLOCKED");
+ sprintf(buf,
+ "dev %s, size %d, blocknr %llu, count %d, state 0x%lx, page %p, (%s, %s, %s)",
+ bdevname(bh->b_bdev, b), bh->b_size,
+ (unsigned long long)bh->b_blocknr, atomic_read(&(bh->b_count)),
+ bh->b_state, bh->b_page,
+ buffer_uptodate(bh) ? "UPTODATE" : "!UPTODATE",
+ buffer_dirty(bh) ? "DIRTY" : "CLEAN",
+ buffer_locked(bh) ? "LOCKED" : "UNLOCKED");
}
-
-static void sprintf_disk_child (char * buf, struct disk_child * dc)
+static void sprintf_disk_child(char *buf, struct disk_child *dc)
{
- sprintf (buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc), dc_size(dc));
+ sprintf(buf, "[dc_number=%d, dc_size=%u]", dc_block_number(dc),
+ dc_size(dc));
}
-
-static char * is_there_reiserfs_struct (char * fmt, int * what, int * skip)
+static char *is_there_reiserfs_struct(char *fmt, int *what, int *skip)
{
- char * k = fmt;
+ char *k = fmt;
- *skip = 0;
-
- while ((k = strchr (k, '%')) != NULL)
- {
- if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
- k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a' ) {
- *what = k[1];
- break;
- }
- (*skip) ++;
- k ++;
- }
- return k;
-}
+ *skip = 0;
+ while ((k = strchr(k, '%')) != NULL) {
+ if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
+ k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a') {
+ *what = k[1];
+ break;
+ }
+ (*skip)++;
+ k++;
+ }
+ return k;
+}
/* debugging reiserfs we used to print out a lot of different
variables, like keys, item headers, buffer heads etc. Values of
@@ -191,61 +189,64 @@ static char * is_there_reiserfs_struct (char * fmt, int * what, int * skip)
key->k_offset, key->k_uniqueness);
*/
-
-static void
-prepare_error_buf( const char *fmt, va_list args )
-{
- char * fmt1 = fmt_buf;
- char * k;
- char * p = error_buf;
- int i, j, what, skip;
-
- strcpy (fmt1, fmt);
-
- while( (k = is_there_reiserfs_struct( fmt1, &what, &skip )) != NULL )
- {
- *k = 0;
-
- p += vsprintf (p, fmt1, args);
-
- for (i = 0; i < skip; i ++)
- j = va_arg (args, int);
-
- switch (what) {
- case 'k':
- sprintf_le_key (p, va_arg(args, struct reiserfs_key *));
- break;
- case 'K':
- sprintf_cpu_key (p, va_arg(args, struct cpu_key *));
- break;
- case 'h':
- sprintf_item_head (p, va_arg(args, struct item_head *));
- break;
- case 't':
- sprintf_direntry (p, va_arg(args, struct reiserfs_dir_entry *));
- break;
- case 'y':
- sprintf_disk_child (p, va_arg(args, struct disk_child *));
- break;
- case 'z':
- sprintf_block_head (p, va_arg(args, struct buffer_head *));
- break;
- case 'b':
- sprintf_buffer_head (p, va_arg(args, struct buffer_head *));
- break;
- case 'a':
- sprintf_de_head (p, va_arg(args, struct reiserfs_de_head *));
- break;
- }
-
- p += strlen (p);
- fmt1 = k + 2;
- }
- vsprintf (p, fmt1, args);
+static void prepare_error_buf(const char *fmt, va_list args)
+{
+ char *fmt1 = fmt_buf;
+ char *k;
+ char *p = error_buf;
+ int i, j, what, skip;
+
+ strcpy(fmt1, fmt);
+
+ while ((k = is_there_reiserfs_struct(fmt1, &what, &skip)) != NULL) {
+ *k = 0;
+
+ p += vsprintf(p, fmt1, args);
+
+ for (i = 0; i < skip; i++)
+ j = va_arg(args, int);
+
+ switch (what) {
+ case 'k':
+ sprintf_le_key(p, va_arg(args, struct reiserfs_key *));
+ break;
+ case 'K':
+ sprintf_cpu_key(p, va_arg(args, struct cpu_key *));
+ break;
+ case 'h':
+ sprintf_item_head(p, va_arg(args, struct item_head *));
+ break;
+ case 't':
+ sprintf_direntry(p,
+ va_arg(args,
+ struct reiserfs_dir_entry *));
+ break;
+ case 'y':
+ sprintf_disk_child(p,
+ va_arg(args, struct disk_child *));
+ break;
+ case 'z':
+ sprintf_block_head(p,
+ va_arg(args, struct buffer_head *));
+ break;
+ case 'b':
+ sprintf_buffer_head(p,
+ va_arg(args, struct buffer_head *));
+ break;
+ case 'a':
+ sprintf_de_head(p,
+ va_arg(args,
+ struct reiserfs_de_head *));
+ break;
+ }
+
+ p += strlen(p);
+ fmt1 = k + 2;
+ }
+ vsprintf(p, fmt1, args);
}
-
/* in addition to usual conversion specifiers this accepts reiserfs
specific conversion specifiers:
%k to print little endian key,
@@ -264,43 +265,43 @@ prepare_error_buf( const char *fmt, va_list args )
va_end( args );\
}
-void reiserfs_warning (struct super_block *sb, const char * fmt, ...)
+void reiserfs_warning(struct super_block *sb, const char *fmt, ...)
{
- do_reiserfs_warning(fmt);
- if (sb)
- printk (KERN_WARNING "ReiserFS: %s: warning: %s\n",
- reiserfs_bdevname (sb), error_buf);
- else
- printk (KERN_WARNING "ReiserFS: warning: %s\n", error_buf);
+ do_reiserfs_warning(fmt);
+ if (sb)
+ printk(KERN_WARNING "ReiserFS: %s: warning: %s\n",
+ reiserfs_bdevname(sb), error_buf);
+ else
+ printk(KERN_WARNING "ReiserFS: warning: %s\n", error_buf);
}
/* No newline.. reiserfs_info calls can be followed by printk's */
-void reiserfs_info (struct super_block *sb, const char * fmt, ...)
+void reiserfs_info(struct super_block *sb, const char *fmt, ...)
{
- do_reiserfs_warning(fmt);
- if (sb)
- printk (KERN_NOTICE "ReiserFS: %s: %s",
- reiserfs_bdevname (sb), error_buf);
- else
- printk (KERN_NOTICE "ReiserFS: %s", error_buf);
+ do_reiserfs_warning(fmt);
+ if (sb)
+ printk(KERN_NOTICE "ReiserFS: %s: %s",
+ reiserfs_bdevname(sb), error_buf);
+ else
+ printk(KERN_NOTICE "ReiserFS: %s", error_buf);
}
/* No newline.. reiserfs_printk calls can be followed by printk's */
-static void reiserfs_printk (const char * fmt, ...)
+static void reiserfs_printk(const char *fmt, ...)
{
- do_reiserfs_warning(fmt);
- printk (error_buf);
+ do_reiserfs_warning(fmt);
+ printk(error_buf);
}
-void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...)
+void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...)
{
#ifdef CONFIG_REISERFS_CHECK
- do_reiserfs_warning(fmt);
- if (s)
- printk (KERN_DEBUG "ReiserFS: %s: %s\n",
- reiserfs_bdevname (s), error_buf);
- else
- printk (KERN_DEBUG "ReiserFS: %s\n", error_buf);
+ do_reiserfs_warning(fmt);
+ if (s)
+ printk(KERN_DEBUG "ReiserFS: %s: %s\n",
+ reiserfs_bdevname(s), error_buf);
+ else
+ printk(KERN_DEBUG "ReiserFS: %s\n", error_buf);
#endif
}
@@ -349,379 +350,403 @@ void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...)
. */
-
#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance * cur_tb;
+extern struct tree_balance *cur_tb;
#endif
-void reiserfs_panic (struct super_block * sb, const char * fmt, ...)
+void reiserfs_panic(struct super_block *sb, const char *fmt, ...)
{
- do_reiserfs_warning(fmt);
- printk (KERN_EMERG "REISERFS: panic (device %s): %s\n",
- reiserfs_bdevname (sb), error_buf);
- BUG ();
+ do_reiserfs_warning(fmt);
+ printk(KERN_EMERG "REISERFS: panic (device %s): %s\n",
+ reiserfs_bdevname(sb), error_buf);
+ BUG();
- /* this is not actually called, but makes reiserfs_panic() "noreturn" */
- panic ("REISERFS: panic (device %s): %s\n",
- reiserfs_bdevname (sb), error_buf);
+ /* this is not actually called, but makes reiserfs_panic() "noreturn" */
+ panic("REISERFS: panic (device %s): %s\n",
+ reiserfs_bdevname(sb), error_buf);
}
-void
-reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...)
+void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...)
{
- do_reiserfs_warning (fmt);
+ do_reiserfs_warning(fmt);
- if (reiserfs_error_panic (sb)) {
- panic (KERN_CRIT "REISERFS: panic (device %s): %s\n",
- reiserfs_bdevname (sb), error_buf);
- }
+ if (reiserfs_error_panic(sb)) {
+ panic(KERN_CRIT "REISERFS: panic (device %s): %s\n",
+ reiserfs_bdevname(sb), error_buf);
+ }
- if (sb->s_flags & MS_RDONLY)
- return;
+ if (sb->s_flags & MS_RDONLY)
+ return;
- printk (KERN_CRIT "REISERFS: abort (device %s): %s\n",
- reiserfs_bdevname (sb), error_buf);
+ printk(KERN_CRIT "REISERFS: abort (device %s): %s\n",
+ reiserfs_bdevname(sb), error_buf);
- sb->s_flags |= MS_RDONLY;
- reiserfs_journal_abort (sb, errno);
+ sb->s_flags |= MS_RDONLY;
+ reiserfs_journal_abort(sb, errno);
}
/* this prints internal nodes (4 keys/items in line) (dc_number,
dc_size)[k_dirid, k_objectid, k_offset, k_uniqueness](dc_number,
dc_size)...*/
-static int print_internal (struct buffer_head * bh, int first, int last)
+static int print_internal(struct buffer_head *bh, int first, int last)
{
- struct reiserfs_key * key;
- struct disk_child * dc;
- int i;
- int from, to;
-
- if (!B_IS_KEYS_LEVEL (bh))
- return 1;
-
- check_internal (bh);
-
- if (first == -1) {
- from = 0;
- to = B_NR_ITEMS (bh);
- } else {
- from = first;
- to = last < B_NR_ITEMS (bh) ? last : B_NR_ITEMS (bh);
- }
-
- reiserfs_printk ("INTERNAL NODE (%ld) contains %z\n", bh->b_blocknr, bh);
-
- dc = B_N_CHILD (bh, from);
- reiserfs_printk ("PTR %d: %y ", from, dc);
-
- for (i = from, key = B_N_PDELIM_KEY (bh, from), dc ++; i < to; i ++, key ++, dc ++) {
- reiserfs_printk ("KEY %d: %k PTR %d: %y ", i, key, i + 1, dc);
- if (i && i % 4 == 0)
- printk ("\n");
- }
- printk ("\n");
- return 0;
-}
+ struct reiserfs_key *key;
+ struct disk_child *dc;
+ int i;
+ int from, to;
+ if (!B_IS_KEYS_LEVEL(bh))
+ return 1;
+ check_internal(bh);
+ if (first == -1) {
+ from = 0;
+ to = B_NR_ITEMS(bh);
+ } else {
+ from = first;
+ to = last < B_NR_ITEMS(bh) ? last : B_NR_ITEMS(bh);
+ }
+ reiserfs_printk("INTERNAL NODE (%ld) contains %z\n", bh->b_blocknr, bh);
-static int print_leaf (struct buffer_head * bh, int print_mode, int first, int last)
-{
- struct block_head * blkh;
- struct item_head * ih;
- int i, nr;
- int from, to;
+ dc = B_N_CHILD(bh, from);
+ reiserfs_printk("PTR %d: %y ", from, dc);
- if (!B_IS_ITEMS_LEVEL (bh))
- return 1;
+ for (i = from, key = B_N_PDELIM_KEY(bh, from), dc++; i < to;
+ i++, key++, dc++) {
+ reiserfs_printk("KEY %d: %k PTR %d: %y ", i, key, i + 1, dc);
+ if (i && i % 4 == 0)
+ printk("\n");
+ }
+ printk("\n");
+ return 0;
+}
- check_leaf (bh);
+static int print_leaf(struct buffer_head *bh, int print_mode, int first,
+ int last)
+{
+ struct block_head *blkh;
+ struct item_head *ih;
+ int i, nr;
+ int from, to;
- blkh = B_BLK_HEAD (bh);
- ih = B_N_PITEM_HEAD (bh,0);
- nr = blkh_nr_item(blkh);
+ if (!B_IS_ITEMS_LEVEL(bh))
+ return 1;
- printk ("\n===================================================================\n");
- reiserfs_printk ("LEAF NODE (%ld) contains %z\n", bh->b_blocknr, bh);
+ check_leaf(bh);
- if (!(print_mode & PRINT_LEAF_ITEMS)) {
- reiserfs_printk ("FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
- &(ih->ih_key), &((ih + nr - 1)->ih_key));
- return 0;
- }
+ blkh = B_BLK_HEAD(bh);
+ ih = B_N_PITEM_HEAD(bh, 0);
+ nr = blkh_nr_item(blkh);
- if (first < 0 || first > nr - 1)
- from = 0;
- else
- from = first;
+ printk
+ ("\n===================================================================\n");
+ reiserfs_printk("LEAF NODE (%ld) contains %z\n", bh->b_blocknr, bh);
- if (last < 0 || last > nr )
- to = nr;
- else
- to = last;
+ if (!(print_mode & PRINT_LEAF_ITEMS)) {
+ reiserfs_printk("FIRST ITEM_KEY: %k, LAST ITEM KEY: %k\n",
+ &(ih->ih_key), &((ih + nr - 1)->ih_key));
+ return 0;
+ }
- ih += from;
- printk ("-------------------------------------------------------------------------------\n");
- printk ("|##| type | key | ilen | free_space | version | loc |\n");
- for (i = from; i < to; i++, ih ++) {
- printk ("-------------------------------------------------------------------------------\n");
- reiserfs_printk ("|%2d| %h |\n", i, ih);
- if (print_mode & PRINT_LEAF_ITEMS)
- op_print_item (ih, B_I_PITEM (bh, ih));
- }
+ if (first < 0 || first > nr - 1)
+ from = 0;
+ else
+ from = first;
+
+ if (last < 0 || last > nr)
+ to = nr;
+ else
+ to = last;
+
+ ih += from;
+ printk
+ ("-------------------------------------------------------------------------------\n");
+ printk
+ ("|##| type | key | ilen | free_space | version | loc |\n");
+ for (i = from; i < to; i++, ih++) {
+ printk
+ ("-------------------------------------------------------------------------------\n");
+ reiserfs_printk("|%2d| %h |\n", i, ih);
+ if (print_mode & PRINT_LEAF_ITEMS)
+ op_print_item(ih, B_I_PITEM(bh, ih));
+ }
- printk ("===================================================================\n");
+ printk
+ ("===================================================================\n");
- return 0;
+ return 0;
}
-char * reiserfs_hashname(int code)
+char *reiserfs_hashname(int code)
{
- if ( code == YURA_HASH)
- return "rupasov";
- if ( code == TEA_HASH)
- return "tea";
- if ( code == R5_HASH)
- return "r5";
+ if (code == YURA_HASH)
+ return "rupasov";
+ if (code == TEA_HASH)
+ return "tea";
+ if (code == R5_HASH)
+ return "r5";
- return "unknown";
+ return "unknown";
}
/* return 1 if this is not super block */
-static int print_super_block (struct buffer_head * bh)
-{
- struct reiserfs_super_block * rs = (struct reiserfs_super_block *)(bh->b_data);
- int skipped, data_blocks;
- char *version;
- char b[BDEVNAME_SIZE];
-
- if (is_reiserfs_3_5(rs)) {
- version = "3.5";
- } else if (is_reiserfs_3_6(rs)) {
- version = "3.6";
- } else if (is_reiserfs_jr(rs)) {
- version = ((sb_version(rs) == REISERFS_VERSION_2) ?
- "3.6" : "3.5");
- } else {
- return 1;
- }
-
- printk ("%s\'s super block is in block %llu\n", bdevname (bh->b_bdev, b),
- (unsigned long long)bh->b_blocknr);
- printk ("Reiserfs version %s\n", version );
- printk ("Block count %u\n", sb_block_count(rs));
- printk ("Blocksize %d\n", sb_blocksize(rs));
- printk ("Free blocks %u\n", sb_free_blocks(rs));
- // FIXME: this would be confusing if
- // someone stores reiserfs super block in some data block ;)
+static int print_super_block(struct buffer_head *bh)
+{
+ struct reiserfs_super_block *rs =
+ (struct reiserfs_super_block *)(bh->b_data);
+ int skipped, data_blocks;
+ char *version;
+ char b[BDEVNAME_SIZE];
+
+ if (is_reiserfs_3_5(rs)) {
+ version = "3.5";
+ } else if (is_reiserfs_3_6(rs)) {
+ version = "3.6";
+ } else if (is_reiserfs_jr(rs)) {
+ version = ((sb_version(rs) == REISERFS_VERSION_2) ?
+ "3.6" : "3.5");
+ } else {
+ return 1;
+ }
+
+ printk("%s\'s super block is in block %llu\n", bdevname(bh->b_bdev, b),
+ (unsigned long long)bh->b_blocknr);
+ printk("Reiserfs version %s\n", version);
+ printk("Block count %u\n", sb_block_count(rs));
+ printk("Blocksize %d\n", sb_blocksize(rs));
+ printk("Free blocks %u\n", sb_free_blocks(rs));
+ // FIXME: this would be confusing if
+ // someone stores reiserfs super block in some data block ;)
// skipped = (bh->b_blocknr * bh->b_size) / sb_blocksize(rs);
- skipped = bh->b_blocknr;
- data_blocks = sb_block_count(rs) - skipped - 1 - sb_bmap_nr(rs) -
- (!is_reiserfs_jr(rs) ? sb_jp_journal_size(rs) + 1 : sb_reserved_for_journal(rs)) -
- sb_free_blocks(rs);
- printk ("Busy blocks (skipped %d, bitmaps - %d, journal (or reserved) blocks - %d\n"
- "1 super block, %d data blocks\n",
- skipped, sb_bmap_nr(rs), (!is_reiserfs_jr(rs) ? (sb_jp_journal_size(rs) + 1) :
- sb_reserved_for_journal(rs)) , data_blocks);
- printk ("Root block %u\n", sb_root_block(rs));
- printk ("Journal block (first) %d\n", sb_jp_journal_1st_block(rs));
- printk ("Journal dev %d\n", sb_jp_journal_dev(rs));
- printk ("Journal orig size %d\n", sb_jp_journal_size(rs));
- printk ("FS state %d\n", sb_fs_state(rs));
- printk ("Hash function \"%s\"\n",
- reiserfs_hashname(sb_hash_function_code(rs)));
-
- printk ("Tree height %d\n", sb_tree_height(rs));
- return 0;
+ skipped = bh->b_blocknr;
+ data_blocks = sb_block_count(rs) - skipped - 1 - sb_bmap_nr(rs) -
+ (!is_reiserfs_jr(rs) ? sb_jp_journal_size(rs) +
+ 1 : sb_reserved_for_journal(rs)) - sb_free_blocks(rs);
+ printk
+ ("Busy blocks (skipped %d, bitmaps - %d, journal (or reserved) blocks - %d\n"
+ "1 super block, %d data blocks\n", skipped, sb_bmap_nr(rs),
+ (!is_reiserfs_jr(rs) ? (sb_jp_journal_size(rs) + 1) :
+ sb_reserved_for_journal(rs)), data_blocks);
+ printk("Root block %u\n", sb_root_block(rs));
+ printk("Journal block (first) %d\n", sb_jp_journal_1st_block(rs));
+ printk("Journal dev %d\n", sb_jp_journal_dev(rs));
+ printk("Journal orig size %d\n", sb_jp_journal_size(rs));
+ printk("FS state %d\n", sb_fs_state(rs));
+ printk("Hash function \"%s\"\n",
+ reiserfs_hashname(sb_hash_function_code(rs)));
+
+ printk("Tree height %d\n", sb_tree_height(rs));
+ return 0;
}
-static int print_desc_block (struct buffer_head * bh)
+static int print_desc_block(struct buffer_head *bh)
{
- struct reiserfs_journal_desc * desc;
+ struct reiserfs_journal_desc *desc;
- if (memcmp(get_journal_desc_magic (bh), JOURNAL_DESC_MAGIC, 8))
- return 1;
+ if (memcmp(get_journal_desc_magic(bh), JOURNAL_DESC_MAGIC, 8))
+ return 1;
- desc = (struct reiserfs_journal_desc *)(bh->b_data);
- printk ("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)",
- (unsigned long long)bh->b_blocknr, get_desc_trans_id (desc), get_desc_mount_id (desc),
- get_desc_trans_len (desc));
+ desc = (struct reiserfs_journal_desc *)(bh->b_data);
+ printk("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)",
+ (unsigned long long)bh->b_blocknr, get_desc_trans_id(desc),
+ get_desc_mount_id(desc), get_desc_trans_len(desc));
- return 0;
+ return 0;
}
-
-void print_block (struct buffer_head * bh, ...)//int print_mode, int first, int last)
+void print_block(struct buffer_head *bh, ...) //int print_mode, int first, int last)
{
- va_list args;
- int mode, first, last;
+ va_list args;
+ int mode, first, last;
- va_start (args, bh);
+ va_start(args, bh);
- if ( ! bh ) {
- printk("print_block: buffer is NULL\n");
- return;
- }
+ if (!bh) {
+ printk("print_block: buffer is NULL\n");
+ return;
+ }
- mode = va_arg (args, int);
- first = va_arg (args, int);
- last = va_arg (args, int);
- if (print_leaf (bh, mode, first, last))
- if (print_internal (bh, first, last))
- if (print_super_block (bh))
- if (print_desc_block (bh))
- printk ("Block %llu contains unformatted data\n", (unsigned long long)bh->b_blocknr);
+ mode = va_arg(args, int);
+ first = va_arg(args, int);
+ last = va_arg(args, int);
+ if (print_leaf(bh, mode, first, last))
+ if (print_internal(bh, first, last))
+ if (print_super_block(bh))
+ if (print_desc_block(bh))
+ printk
+ ("Block %llu contains unformatted data\n",
+ (unsigned long long)bh->b_blocknr);
}
-
-
static char print_tb_buf[2048];
/* this stores initial state of tree balance in the print_tb_buf */
-void store_print_tb (struct tree_balance * tb)
-{
- int h = 0;
- int i;
- struct buffer_head * tbSh, * tbFh;
-
- if (!tb)
- return;
-
- sprintf (print_tb_buf, "\n"
- "BALANCING %d\n"
- "MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n"
- "=====================================================================\n"
- "* h * S * L * R * F * FL * FR * CFL * CFR *\n",
- REISERFS_SB(tb->tb_sb)->s_do_balance,
- tb->tb_mode, PATH_LAST_POSITION (tb->tb_path), tb->tb_path->pos_in_item);
-
- for (h = 0; h < sizeof(tb->insert_size) / sizeof (tb->insert_size[0]); h ++) {
- if (PATH_H_PATH_OFFSET (tb->tb_path, h) <= tb->tb_path->path_length &&
- PATH_H_PATH_OFFSET (tb->tb_path, h) > ILLEGAL_PATH_ELEMENT_OFFSET) {
- tbSh = PATH_H_PBUFFER (tb->tb_path, h);
- tbFh = PATH_H_PPARENT (tb->tb_path, h);
- } else {
- tbSh = NULL;
- tbFh = NULL;
+void store_print_tb(struct tree_balance *tb)
+{
+ int h = 0;
+ int i;
+ struct buffer_head *tbSh, *tbFh;
+
+ if (!tb)
+ return;
+
+ sprintf(print_tb_buf, "\n"
+ "BALANCING %d\n"
+ "MODE=%c, ITEM_POS=%d POS_IN_ITEM=%d\n"
+ "=====================================================================\n"
+ "* h * S * L * R * F * FL * FR * CFL * CFR *\n",
+ REISERFS_SB(tb->tb_sb)->s_do_balance,
+ tb->tb_mode, PATH_LAST_POSITION(tb->tb_path),
+ tb->tb_path->pos_in_item);
+
+ for (h = 0; h < sizeof(tb->insert_size) / sizeof(tb->insert_size[0]);
+ h++) {
+ if (PATH_H_PATH_OFFSET(tb->tb_path, h) <=
+ tb->tb_path->path_length
+ && PATH_H_PATH_OFFSET(tb->tb_path,
+ h) > ILLEGAL_PATH_ELEMENT_OFFSET) {
+ tbSh = PATH_H_PBUFFER(tb->tb_path, h);
+ tbFh = PATH_H_PPARENT(tb->tb_path, h);
+ } else {
+ tbSh = NULL;
+ tbFh = NULL;
+ }
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "* %d * %3lld(%2d) * %3lld(%2d) * %3lld(%2d) * %5lld * %5lld * %5lld * %5lld * %5lld *\n",
+ h,
+ (tbSh) ? (long long)(tbSh->b_blocknr) : (-1LL),
+ (tbSh) ? atomic_read(&(tbSh->b_count)) : -1,
+ (tb->L[h]) ? (long long)(tb->L[h]->b_blocknr) : (-1LL),
+ (tb->L[h]) ? atomic_read(&(tb->L[h]->b_count)) : -1,
+ (tb->R[h]) ? (long long)(tb->R[h]->b_blocknr) : (-1LL),
+ (tb->R[h]) ? atomic_read(&(tb->R[h]->b_count)) : -1,
+ (tbFh) ? (long long)(tbFh->b_blocknr) : (-1LL),
+ (tb->FL[h]) ? (long long)(tb->FL[h]->
+ b_blocknr) : (-1LL),
+ (tb->FR[h]) ? (long long)(tb->FR[h]->
+ b_blocknr) : (-1LL),
+ (tb->CFL[h]) ? (long long)(tb->CFL[h]->
+ b_blocknr) : (-1LL),
+ (tb->CFR[h]) ? (long long)(tb->CFR[h]->
+ b_blocknr) : (-1LL));
}
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "* %d * %3lld(%2d) * %3lld(%2d) * %3lld(%2d) * %5lld * %5lld * %5lld * %5lld * %5lld *\n",
- h,
- (tbSh) ? (long long)(tbSh->b_blocknr):(-1LL),
- (tbSh) ? atomic_read (&(tbSh->b_count)) : -1,
- (tb->L[h]) ? (long long)(tb->L[h]->b_blocknr):(-1LL),
- (tb->L[h]) ? atomic_read (&(tb->L[h]->b_count)) : -1,
- (tb->R[h]) ? (long long)(tb->R[h]->b_blocknr):(-1LL),
- (tb->R[h]) ? atomic_read (&(tb->R[h]->b_count)) : -1,
- (tbFh) ? (long long)(tbFh->b_blocknr):(-1LL),
- (tb->FL[h]) ? (long long)(tb->FL[h]->b_blocknr):(-1LL),
- (tb->FR[h]) ? (long long)(tb->FR[h]->b_blocknr):(-1LL),
- (tb->CFL[h]) ? (long long)(tb->CFL[h]->b_blocknr):(-1LL),
- (tb->CFR[h]) ? (long long)(tb->CFR[h]->b_blocknr):(-1LL));
- }
-
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "=====================================================================\n"
- "* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n"
- "* 0 * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n",
- tb->insert_size[0], tb->lnum[0], tb->lbytes, tb->rnum[0],tb->rbytes, tb->blknum[0],
- tb->s0num, tb->s1num,tb->s1bytes, tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[0], tb->rkey[0]);
-
- /* this prints balance parameters for non-leaf levels */
- h = 0;
- do {
- h++;
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "* %d * %4d * %2d * * %2d * * %2d *\n",
- h, tb->insert_size[h], tb->lnum[h], tb->rnum[h], tb->blknum[h]);
- } while (tb->insert_size[h]);
-
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "=====================================================================\n"
- "FEB list: ");
-
- /* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */
- h = 0;
- for (i = 0; i < sizeof (tb->FEB) / sizeof (tb->FEB[0]); i ++)
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "%p (%llu %d)%s", tb->FEB[i], tb->FEB[i] ? (unsigned long long)tb->FEB[i]->b_blocknr : 0ULL,
- tb->FEB[i] ? atomic_read (&(tb->FEB[i]->b_count)) : 0,
- (i == sizeof (tb->FEB) / sizeof (tb->FEB[0]) - 1) ? "\n" : ", ");
-
- sprintf (print_tb_buf + strlen (print_tb_buf),
- "======================== the end ====================================\n");
-}
-
-void print_cur_tb (char * mes)
-{
- printk ("%s\n%s", mes, print_tb_buf);
-}
-
-static void check_leaf_block_head (struct buffer_head * bh)
-{
- struct block_head * blkh;
- int nr;
-
- blkh = B_BLK_HEAD (bh);
- nr = blkh_nr_item(blkh);
- if ( nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
- reiserfs_panic (NULL, "vs-6010: check_leaf_block_head: invalid item number %z", bh);
- if ( blkh_free_space(blkh) >
- bh->b_size - BLKH_SIZE - IH_SIZE * nr )
- reiserfs_panic (NULL, "vs-6020: check_leaf_block_head: invalid free space %z", bh);
-
-}
-static void check_internal_block_head (struct buffer_head * bh)
-{
- struct block_head * blkh;
-
- blkh = B_BLK_HEAD (bh);
- if (!(B_LEVEL (bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL (bh) <= MAX_HEIGHT))
- reiserfs_panic (NULL, "vs-6025: check_internal_block_head: invalid level %z", bh);
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "=====================================================================\n"
+ "* h * size * ln * lb * rn * rb * blkn * s0 * s1 * s1b * s2 * s2b * curb * lk * rk *\n"
+ "* 0 * %4d * %2d * %2d * %2d * %2d * %4d * %2d * %2d * %3d * %2d * %3d * %4d * %2d * %2d *\n",
+ tb->insert_size[0], tb->lnum[0], tb->lbytes, tb->rnum[0],
+ tb->rbytes, tb->blknum[0], tb->s0num, tb->s1num, tb->s1bytes,
+ tb->s2num, tb->s2bytes, tb->cur_blknum, tb->lkey[0],
+ tb->rkey[0]);
+
+ /* this prints balance parameters for non-leaf levels */
+ h = 0;
+ do {
+ h++;
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "* %d * %4d * %2d * * %2d * * %2d *\n",
+ h, tb->insert_size[h], tb->lnum[h], tb->rnum[h],
+ tb->blknum[h]);
+ } while (tb->insert_size[h]);
- if (B_NR_ITEMS (bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
- reiserfs_panic (NULL, "vs-6030: check_internal_block_head: invalid item number %z", bh);
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "=====================================================================\n"
+ "FEB list: ");
- if (B_FREE_SPACE (bh) !=
- bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS (bh) - DC_SIZE * (B_NR_ITEMS (bh) + 1))
- reiserfs_panic (NULL, "vs-6040: check_internal_block_head: invalid free space %z", bh);
+ /* print FEB list (list of buffers in form (bh (b_blocknr, b_count), that will be used for new nodes) */
+ h = 0;
+ for (i = 0; i < sizeof(tb->FEB) / sizeof(tb->FEB[0]); i++)
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "%p (%llu %d)%s", tb->FEB[i],
+ tb->FEB[i] ? (unsigned long long)tb->FEB[i]->
+ b_blocknr : 0ULL,
+ tb->FEB[i] ? atomic_read(&(tb->FEB[i]->b_count)) : 0,
+ (i ==
+ sizeof(tb->FEB) / sizeof(tb->FEB[0]) -
+ 1) ? "\n" : ", ");
+ sprintf(print_tb_buf + strlen(print_tb_buf),
+ "======================== the end ====================================\n");
}
+void print_cur_tb(char *mes)
+{
+ printk("%s\n%s", mes, print_tb_buf);
+}
-void check_leaf (struct buffer_head * bh)
+static void check_leaf_block_head(struct buffer_head *bh)
{
- int i;
- struct item_head * ih;
+ struct block_head *blkh;
+ int nr;
+
+ blkh = B_BLK_HEAD(bh);
+ nr = blkh_nr_item(blkh);
+ if (nr > (bh->b_size - BLKH_SIZE) / IH_SIZE)
+ reiserfs_panic(NULL,
+ "vs-6010: check_leaf_block_head: invalid item number %z",
+ bh);
+ if (blkh_free_space(blkh) > bh->b_size - BLKH_SIZE - IH_SIZE * nr)
+ reiserfs_panic(NULL,
+ "vs-6020: check_leaf_block_head: invalid free space %z",
+ bh);
- if (!bh)
- return;
- check_leaf_block_head (bh);
- for (i = 0, ih = B_N_PITEM_HEAD (bh, 0); i < B_NR_ITEMS (bh); i ++, ih ++)
- op_check_item (ih, B_I_PITEM (bh, ih));
}
+static void check_internal_block_head(struct buffer_head *bh)
+{
+ struct block_head *blkh;
+
+ blkh = B_BLK_HEAD(bh);
+ if (!(B_LEVEL(bh) > DISK_LEAF_NODE_LEVEL && B_LEVEL(bh) <= MAX_HEIGHT))
+ reiserfs_panic(NULL,
+ "vs-6025: check_internal_block_head: invalid level %z",
+ bh);
+
+ if (B_NR_ITEMS(bh) > (bh->b_size - BLKH_SIZE) / IH_SIZE)
+ reiserfs_panic(NULL,
+ "vs-6030: check_internal_block_head: invalid item number %z",
+ bh);
+
+ if (B_FREE_SPACE(bh) !=
+ bh->b_size - BLKH_SIZE - KEY_SIZE * B_NR_ITEMS(bh) -
+ DC_SIZE * (B_NR_ITEMS(bh) + 1))
+ reiserfs_panic(NULL,
+ "vs-6040: check_internal_block_head: invalid free space %z",
+ bh);
+
+}
-void check_internal (struct buffer_head * bh)
+void check_leaf(struct buffer_head *bh)
{
- if (!bh)
- return;
- check_internal_block_head (bh);
+ int i;
+ struct item_head *ih;
+
+ if (!bh)
+ return;
+ check_leaf_block_head(bh);
+ for (i = 0, ih = B_N_PITEM_HEAD(bh, 0); i < B_NR_ITEMS(bh); i++, ih++)
+ op_check_item(ih, B_I_PITEM(bh, ih));
}
+void check_internal(struct buffer_head *bh)
+{
+ if (!bh)
+ return;
+ check_internal_block_head(bh);
+}
-void print_statistics (struct super_block * s)
+void print_statistics(struct super_block *s)
{
- /*
- printk ("reiserfs_put_super: session statistics: balances %d, fix_nodes %d, \
-bmap with search %d, without %d, dir2ind %d, ind2dir %d\n",
- REISERFS_SB(s)->s_do_balance, REISERFS_SB(s)->s_fix_nodes,
- REISERFS_SB(s)->s_bmaps, REISERFS_SB(s)->s_bmaps_without_search,
- REISERFS_SB(s)->s_direct2indirect, REISERFS_SB(s)->s_indirect2direct);
- */
+ /*
+ printk ("reiserfs_put_super: session statistics: balances %d, fix_nodes %d, \
+ bmap with search %d, without %d, dir2ind %d, ind2dir %d\n",
+ REISERFS_SB(s)->s_do_balance, REISERFS_SB(s)->s_fix_nodes,
+ REISERFS_SB(s)->s_bmaps, REISERFS_SB(s)->s_bmaps_without_search,
+ REISERFS_SB(s)->s_direct2indirect, REISERFS_SB(s)->s_indirect2direct);
+ */
}
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index e242ebc7f6f6..fc2f43c75df4 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -33,28 +33,27 @@
static int show_version(struct seq_file *m, struct super_block *sb)
{
char *format;
-
- if ( REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6) ) {
+
+ if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_6)) {
format = "3.6";
- } else if ( REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_5) ) {
+ } else if (REISERFS_SB(sb)->s_properties & (1 << REISERFS_3_5)) {
format = "3.5";
} else {
format = "unknown";
}
- seq_printf(m, "%s format\twith checks %s\n",
- format,
+ seq_printf(m, "%s format\twith checks %s\n", format,
#if defined( CONFIG_REISERFS_CHECK )
- "on"
+ "on"
#else
- "off"
+ "off"
#endif
- );
+ );
return 0;
}
-int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
- int count, int *eof, void *data )
+int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
+ int count, int *eof, void *data)
{
*start = buffer;
*eof = 1;
@@ -79,87 +78,68 @@ int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
#define DJF( x ) le32_to_cpu( rs -> x )
#define DJV( x ) le32_to_cpu( s_v1 -> x )
-#define DJP( x ) le32_to_cpu( jp -> x )
+#define DJP( x ) le32_to_cpu( jp -> x )
#define JF( x ) ( r -> s_journal -> x )
static int show_super(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
-
- seq_printf(m, "state: \t%s\n"
- "mount options: \t%s%s%s%s%s%s%s%s%s%s%s\n"
- "gen. counter: \t%i\n"
- "s_kmallocs: \t%i\n"
- "s_disk_reads: \t%i\n"
- "s_disk_writes: \t%i\n"
- "s_fix_nodes: \t%i\n"
- "s_do_balance: \t%i\n"
- "s_unneeded_left_neighbor: \t%i\n"
- "s_good_search_by_key_reada: \t%i\n"
- "s_bmaps: \t%i\n"
- "s_bmaps_without_search: \t%i\n"
- "s_direct2indirect: \t%i\n"
- "s_indirect2direct: \t%i\n"
- "\n"
- "max_hash_collisions: \t%i\n"
-
- "breads: \t%lu\n"
- "bread_misses: \t%lu\n"
-
- "search_by_key: \t%lu\n"
- "search_by_key_fs_changed: \t%lu\n"
- "search_by_key_restarted: \t%lu\n"
-
- "insert_item_restarted: \t%lu\n"
- "paste_into_item_restarted: \t%lu\n"
- "cut_from_item_restarted: \t%lu\n"
- "delete_solid_item_restarted: \t%lu\n"
- "delete_item_restarted: \t%lu\n"
-
- "leaked_oid: \t%lu\n"
- "leaves_removable: \t%lu\n",
-
- SF( s_mount_state ) == REISERFS_VALID_FS ?
- "REISERFS_VALID_FS" : "REISERFS_ERROR_FS",
- reiserfs_r5_hash( sb ) ? "FORCE_R5 " : "",
- reiserfs_rupasov_hash( sb ) ? "FORCE_RUPASOV " : "",
- reiserfs_tea_hash( sb ) ? "FORCE_TEA " : "",
- reiserfs_hash_detect( sb ) ? "DETECT_HASH " : "",
- reiserfs_no_border( sb ) ? "NO_BORDER " : "BORDER ",
- reiserfs_no_unhashed_relocation( sb ) ? "NO_UNHASHED_RELOCATION " : "",
- reiserfs_hashed_relocation( sb ) ? "UNHASHED_RELOCATION " : "",
- reiserfs_test4( sb ) ? "TEST4 " : "",
- have_large_tails( sb ) ? "TAILS " : have_small_tails(sb)?"SMALL_TAILS ":"NO_TAILS ",
- replay_only( sb ) ? "REPLAY_ONLY " : "",
- convert_reiserfs( sb ) ? "CONV " : "",
-
- atomic_read( &r -> s_generation_counter ),
- SF( s_kmallocs ),
- SF( s_disk_reads ),
- SF( s_disk_writes ),
- SF( s_fix_nodes ),
- SF( s_do_balance ),
- SF( s_unneeded_left_neighbor ),
- SF( s_good_search_by_key_reada ),
- SF( s_bmaps ),
- SF( s_bmaps_without_search ),
- SF( s_direct2indirect ),
- SF( s_indirect2direct ),
- SFP( max_hash_collisions ),
- SFP( breads ),
- SFP( bread_miss ),
- SFP( search_by_key ),
- SFP( search_by_key_fs_changed ),
- SFP( search_by_key_restarted ),
-
- SFP( insert_item_restarted ),
- SFP( paste_into_item_restarted ),
- SFP( cut_from_item_restarted ),
- SFP( delete_solid_item_restarted ),
- SFP( delete_item_restarted ),
-
- SFP( leaked_oid ),
- SFP( leaves_removable ) );
+
+ seq_printf(m, "state: \t%s\n"
+ "mount options: \t%s%s%s%s%s%s%s%s%s%s%s\n"
+ "gen. counter: \t%i\n"
+ "s_kmallocs: \t%i\n"
+ "s_disk_reads: \t%i\n"
+ "s_disk_writes: \t%i\n"
+ "s_fix_nodes: \t%i\n"
+ "s_do_balance: \t%i\n"
+ "s_unneeded_left_neighbor: \t%i\n"
+ "s_good_search_by_key_reada: \t%i\n"
+ "s_bmaps: \t%i\n"
+ "s_bmaps_without_search: \t%i\n"
+ "s_direct2indirect: \t%i\n"
+ "s_indirect2direct: \t%i\n"
+ "\n"
+ "max_hash_collisions: \t%i\n"
+ "breads: \t%lu\n"
+ "bread_misses: \t%lu\n"
+ "search_by_key: \t%lu\n"
+ "search_by_key_fs_changed: \t%lu\n"
+ "search_by_key_restarted: \t%lu\n"
+ "insert_item_restarted: \t%lu\n"
+ "paste_into_item_restarted: \t%lu\n"
+ "cut_from_item_restarted: \t%lu\n"
+ "delete_solid_item_restarted: \t%lu\n"
+ "delete_item_restarted: \t%lu\n"
+ "leaked_oid: \t%lu\n"
+ "leaves_removable: \t%lu\n",
+ SF(s_mount_state) == REISERFS_VALID_FS ?
+ "REISERFS_VALID_FS" : "REISERFS_ERROR_FS",
+ reiserfs_r5_hash(sb) ? "FORCE_R5 " : "",
+ reiserfs_rupasov_hash(sb) ? "FORCE_RUPASOV " : "",
+ reiserfs_tea_hash(sb) ? "FORCE_TEA " : "",
+ reiserfs_hash_detect(sb) ? "DETECT_HASH " : "",
+ reiserfs_no_border(sb) ? "NO_BORDER " : "BORDER ",
+ reiserfs_no_unhashed_relocation(sb) ?
+ "NO_UNHASHED_RELOCATION " : "",
+ reiserfs_hashed_relocation(sb) ? "UNHASHED_RELOCATION " : "",
+ reiserfs_test4(sb) ? "TEST4 " : "",
+ have_large_tails(sb) ? "TAILS " : have_small_tails(sb) ?
+ "SMALL_TAILS " : "NO_TAILS ",
+ replay_only(sb) ? "REPLAY_ONLY " : "",
+ convert_reiserfs(sb) ? "CONV " : "",
+ atomic_read(&r->s_generation_counter), SF(s_kmallocs),
+ SF(s_disk_reads), SF(s_disk_writes), SF(s_fix_nodes),
+ SF(s_do_balance), SF(s_unneeded_left_neighbor),
+ SF(s_good_search_by_key_reada), SF(s_bmaps),
+ SF(s_bmaps_without_search), SF(s_direct2indirect),
+ SF(s_indirect2direct), SFP(max_hash_collisions), SFP(breads),
+ SFP(bread_miss), SFP(search_by_key),
+ SFP(search_by_key_fs_changed), SFP(search_by_key_restarted),
+ SFP(insert_item_restarted), SFP(paste_into_item_restarted),
+ SFP(cut_from_item_restarted),
+ SFP(delete_solid_item_restarted), SFP(delete_item_restarted),
+ SFP(leaked_oid), SFP(leaves_removable));
return 0;
}
@@ -169,61 +149,55 @@ static int show_per_level(struct seq_file *m, struct super_block *sb)
struct reiserfs_sb_info *r = REISERFS_SB(sb);
int level;
- seq_printf(m, "level\t"
- " balances"
- " [sbk: reads"
- " fs_changed"
- " restarted]"
- " free space"
- " items"
- " can_remove"
- " lnum"
- " rnum"
- " lbytes"
- " rbytes"
- " get_neig"
- " get_neig_res"
- " need_l_neig"
- " need_r_neig"
- "\n"
-
- );
-
- for( level = 0 ; level < MAX_HEIGHT ; ++ level ) {
- seq_printf(m, "%i\t"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12li"
- " %12li"
- " %12li"
- " %12li"
- " %12lu"
- " %12lu"
- " %12lu"
- " %12lu"
- "\n",
- level,
- SFPL( balance_at ),
- SFPL( sbk_read_at ),
- SFPL( sbk_fs_changed ),
- SFPL( sbk_restarted ),
- SFPL( free_at ),
- SFPL( items_at ),
- SFPL( can_node_be_removed ),
- SFPL( lnum ),
- SFPL( rnum ),
- SFPL( lbytes ),
- SFPL( rbytes ),
- SFPL( get_neighbors ),
- SFPL( get_neighbors_restart ),
- SFPL( need_l_neighbor ),
- SFPL( need_r_neighbor )
- );
+ seq_printf(m, "level\t"
+ " balances"
+ " [sbk: reads"
+ " fs_changed"
+ " restarted]"
+ " free space"
+ " items"
+ " can_remove"
+ " lnum"
+ " rnum"
+ " lbytes"
+ " rbytes"
+ " get_neig"
+ " get_neig_res" " need_l_neig" " need_r_neig" "\n");
+
+ for (level = 0; level < MAX_HEIGHT; ++level) {
+ seq_printf(m, "%i\t"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12li"
+ " %12li"
+ " %12li"
+ " %12li"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ " %12lu"
+ "\n",
+ level,
+ SFPL(balance_at),
+ SFPL(sbk_read_at),
+ SFPL(sbk_fs_changed),
+ SFPL(sbk_restarted),
+ SFPL(free_at),
+ SFPL(items_at),
+ SFPL(can_node_be_removed),
+ SFPL(lnum),
+ SFPL(rnum),
+ SFPL(lbytes),
+ SFPL(rbytes),
+ SFPL(get_neighbors),
+ SFPL(get_neighbors_restart),
+ SFPL(need_l_neighbor), SFPL(need_r_neighbor)
+ );
}
return 0;
}
@@ -232,31 +206,30 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
- seq_printf(m, "free_block: %lu\n"
- " scan_bitmap:"
- " wait"
- " bmap"
- " retry"
- " stolen"
- " journal_hint"
- "journal_nohint"
- "\n"
- " %14lu"
- " %14lu"
- " %14lu"
- " %14lu"
- " %14lu"
- " %14lu"
- " %14lu"
- "\n",
- SFP( free_block ),
- SFPF( call ),
- SFPF( wait ),
- SFPF( bmap ),
- SFPF( retry ),
- SFPF( stolen ),
- SFPF( in_journal_hint ),
- SFPF( in_journal_nohint ) );
+ seq_printf(m, "free_block: %lu\n"
+ " scan_bitmap:"
+ " wait"
+ " bmap"
+ " retry"
+ " stolen"
+ " journal_hint"
+ "journal_nohint"
+ "\n"
+ " %14lu"
+ " %14lu"
+ " %14lu"
+ " %14lu"
+ " %14lu"
+ " %14lu"
+ " %14lu"
+ "\n",
+ SFP(free_block),
+ SFPF(call),
+ SFPF(wait),
+ SFPF(bmap),
+ SFPF(retry),
+ SFPF(stolen),
+ SFPF(in_journal_hint), SFPF(in_journal_nohint));
return 0;
}
@@ -264,46 +237,42 @@ static int show_bitmap(struct seq_file *m, struct super_block *sb)
static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
- struct reiserfs_super_block *rs = sb_info -> s_rs;
- int hash_code = DFL( s_hash_function_code );
- __u32 flags = DJF( s_flags );
-
- seq_printf(m, "block_count: \t%i\n"
- "free_blocks: \t%i\n"
- "root_block: \t%i\n"
- "blocksize: \t%i\n"
- "oid_maxsize: \t%i\n"
- "oid_cursize: \t%i\n"
- "umount_state: \t%i\n"
- "magic: \t%10.10s\n"
- "fs_state: \t%i\n"
- "hash: \t%s\n"
- "tree_height: \t%i\n"
- "bmap_nr: \t%i\n"
- "version: \t%i\n"
- "flags: \t%x[%s]\n"
- "reserved_for_journal: \t%i\n",
-
- DFL( s_block_count ),
- DFL( s_free_blocks ),
- DFL( s_root_block ),
- DF( s_blocksize ),
- DF( s_oid_maxsize ),
- DF( s_oid_cursize ),
- DF( s_umount_state ),
- rs -> s_v1.s_magic,
- DF( s_fs_state ),
- hash_code == TEA_HASH ? "tea" :
- ( hash_code == YURA_HASH ) ? "rupasov" :
- ( hash_code == R5_HASH ) ? "r5" :
- ( hash_code == UNSET_HASH ) ? "unset" : "unknown",
- DF( s_tree_height ),
- DF( s_bmap_nr ),
- DF( s_version ),
- flags,
- ( flags & reiserfs_attrs_cleared )
- ? "attrs_cleared" : "",
- DF (s_reserved_for_journal));
+ struct reiserfs_super_block *rs = sb_info->s_rs;
+ int hash_code = DFL(s_hash_function_code);
+ __u32 flags = DJF(s_flags);
+
+ seq_printf(m, "block_count: \t%i\n"
+ "free_blocks: \t%i\n"
+ "root_block: \t%i\n"
+ "blocksize: \t%i\n"
+ "oid_maxsize: \t%i\n"
+ "oid_cursize: \t%i\n"
+ "umount_state: \t%i\n"
+ "magic: \t%10.10s\n"
+ "fs_state: \t%i\n"
+ "hash: \t%s\n"
+ "tree_height: \t%i\n"
+ "bmap_nr: \t%i\n"
+ "version: \t%i\n"
+ "flags: \t%x[%s]\n"
+ "reserved_for_journal: \t%i\n",
+ DFL(s_block_count),
+ DFL(s_free_blocks),
+ DFL(s_root_block),
+ DF(s_blocksize),
+ DF(s_oid_maxsize),
+ DF(s_oid_cursize),
+ DF(s_umount_state),
+ rs->s_v1.s_magic,
+ DF(s_fs_state),
+ hash_code == TEA_HASH ? "tea" :
+ (hash_code == YURA_HASH) ? "rupasov" :
+ (hash_code == R5_HASH) ? "r5" :
+ (hash_code == UNSET_HASH) ? "unset" : "unknown",
+ DF(s_tree_height),
+ DF(s_bmap_nr),
+ DF(s_version), flags, (flags & reiserfs_attrs_cleared)
+ ? "attrs_cleared" : "", DF(s_reserved_for_journal));
return 0;
}
@@ -311,131 +280,122 @@ static int show_on_disk_super(struct seq_file *m, struct super_block *sb)
static int show_oidmap(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *sb_info = REISERFS_SB(sb);
- struct reiserfs_super_block *rs = sb_info -> s_rs;
- unsigned int mapsize = le16_to_cpu( rs -> s_v1.s_oid_cursize );
+ struct reiserfs_super_block *rs = sb_info->s_rs;
+ unsigned int mapsize = le16_to_cpu(rs->s_v1.s_oid_cursize);
unsigned long total_used = 0;
int i;
- for( i = 0 ; i < mapsize ; ++i ) {
+ for (i = 0; i < mapsize; ++i) {
__u32 right;
- right = ( i == mapsize - 1 ) ? MAX_KEY_OBJECTID : MAP( i + 1 );
+ right = (i == mapsize - 1) ? MAX_KEY_OBJECTID : MAP(i + 1);
seq_printf(m, "%s: [ %x .. %x )\n",
- ( i & 1 ) ? "free" : "used", MAP( i ), right );
- if( ! ( i & 1 ) ) {
- total_used += right - MAP( i );
+ (i & 1) ? "free" : "used", MAP(i), right);
+ if (!(i & 1)) {
+ total_used += right - MAP(i);
}
}
#if defined( REISERFS_USE_OIDMAPF )
- if( sb_info -> oidmap.use_file && ( sb_info -> oidmap.mapf != NULL ) ) {
+ if (sb_info->oidmap.use_file && (sb_info->oidmap.mapf != NULL)) {
loff_t size = sb_info->oidmap.mapf->f_dentry->d_inode->i_size;
- total_used += size / sizeof( reiserfs_oidinterval_d_t );
+ total_used += size / sizeof(reiserfs_oidinterval_d_t);
}
#endif
- seq_printf(m, "total: \t%i [%i/%i] used: %lu [exact]\n",
- mapsize,
- mapsize, le16_to_cpu( rs -> s_v1.s_oid_maxsize ),
- total_used);
+ seq_printf(m, "total: \t%i [%i/%i] used: %lu [exact]\n",
+ mapsize,
+ mapsize, le16_to_cpu(rs->s_v1.s_oid_maxsize), total_used);
return 0;
}
static int show_journal(struct seq_file *m, struct super_block *sb)
{
struct reiserfs_sb_info *r = REISERFS_SB(sb);
- struct reiserfs_super_block *rs = r -> s_rs;
+ struct reiserfs_super_block *rs = r->s_rs;
struct journal_params *jp = &rs->s_v1.s_journal;
char b[BDEVNAME_SIZE];
-
-
- seq_printf(m, /* on-disk fields */
- "jp_journal_1st_block: \t%i\n"
- "jp_journal_dev: \t%s[%x]\n"
- "jp_journal_size: \t%i\n"
- "jp_journal_trans_max: \t%i\n"
- "jp_journal_magic: \t%i\n"
- "jp_journal_max_batch: \t%i\n"
- "jp_journal_max_commit_age: \t%i\n"
- "jp_journal_max_trans_age: \t%i\n"
- /* incore fields */
- "j_1st_reserved_block: \t%i\n"
- "j_state: \t%li\n"
- "j_trans_id: \t%lu\n"
- "j_mount_id: \t%lu\n"
- "j_start: \t%lu\n"
- "j_len: \t%lu\n"
- "j_len_alloc: \t%lu\n"
- "j_wcount: \t%i\n"
- "j_bcount: \t%lu\n"
- "j_first_unflushed_offset: \t%lu\n"
- "j_last_flush_trans_id: \t%lu\n"
- "j_trans_start_time: \t%li\n"
- "j_list_bitmap_index: \t%i\n"
- "j_must_wait: \t%i\n"
- "j_next_full_flush: \t%i\n"
- "j_next_async_flush: \t%i\n"
- "j_cnode_used: \t%i\n"
- "j_cnode_free: \t%i\n"
- "\n"
- /* reiserfs_proc_info_data_t.journal fields */
- "in_journal: \t%12lu\n"
- "in_journal_bitmap: \t%12lu\n"
- "in_journal_reusable: \t%12lu\n"
- "lock_journal: \t%12lu\n"
- "lock_journal_wait: \t%12lu\n"
- "journal_begin: \t%12lu\n"
- "journal_relock_writers: \t%12lu\n"
- "journal_relock_wcount: \t%12lu\n"
- "mark_dirty: \t%12lu\n"
- "mark_dirty_already: \t%12lu\n"
- "mark_dirty_notjournal: \t%12lu\n"
- "restore_prepared: \t%12lu\n"
- "prepare: \t%12lu\n"
- "prepare_retry: \t%12lu\n",
-
- DJP( jp_journal_1st_block ),
- bdevname(SB_JOURNAL(sb)->j_dev_bd, b),
- DJP( jp_journal_dev ),
- DJP( jp_journal_size ),
- DJP( jp_journal_trans_max ),
- DJP( jp_journal_magic ),
- DJP( jp_journal_max_batch ),
- SB_JOURNAL(sb)->j_max_commit_age,
- DJP( jp_journal_max_trans_age ),
-
- JF( j_1st_reserved_block ),
- JF( j_state ),
- JF( j_trans_id ),
- JF( j_mount_id ),
- JF( j_start ),
- JF( j_len ),
- JF( j_len_alloc ),
- atomic_read( & r -> s_journal -> j_wcount ),
- JF( j_bcount ),
- JF( j_first_unflushed_offset ),
- JF( j_last_flush_trans_id ),
- JF( j_trans_start_time ),
- JF( j_list_bitmap_index ),
- JF( j_must_wait ),
- JF( j_next_full_flush ),
- JF( j_next_async_flush ),
- JF( j_cnode_used ),
- JF( j_cnode_free ),
-
- SFPJ( in_journal ),
- SFPJ( in_journal_bitmap ),
- SFPJ( in_journal_reusable ),
- SFPJ( lock_journal ),
- SFPJ( lock_journal_wait ),
- SFPJ( journal_being ),
- SFPJ( journal_relock_writers ),
- SFPJ( journal_relock_wcount ),
- SFPJ( mark_dirty ),
- SFPJ( mark_dirty_already ),
- SFPJ( mark_dirty_notjournal ),
- SFPJ( restore_prepared ),
- SFPJ( prepare ),
- SFPJ( prepare_retry )
- );
+
+ seq_printf(m, /* on-disk fields */
+ "jp_journal_1st_block: \t%i\n"
+ "jp_journal_dev: \t%s[%x]\n"
+ "jp_journal_size: \t%i\n"
+ "jp_journal_trans_max: \t%i\n"
+ "jp_journal_magic: \t%i\n"
+ "jp_journal_max_batch: \t%i\n"
+ "jp_journal_max_commit_age: \t%i\n"
+ "jp_journal_max_trans_age: \t%i\n"
+ /* incore fields */
+ "j_1st_reserved_block: \t%i\n"
+ "j_state: \t%li\n"
+ "j_trans_id: \t%lu\n"
+ "j_mount_id: \t%lu\n"
+ "j_start: \t%lu\n"
+ "j_len: \t%lu\n"
+ "j_len_alloc: \t%lu\n"
+ "j_wcount: \t%i\n"
+ "j_bcount: \t%lu\n"
+ "j_first_unflushed_offset: \t%lu\n"
+ "j_last_flush_trans_id: \t%lu\n"
+ "j_trans_start_time: \t%li\n"
+ "j_list_bitmap_index: \t%i\n"
+ "j_must_wait: \t%i\n"
+ "j_next_full_flush: \t%i\n"
+ "j_next_async_flush: \t%i\n"
+ "j_cnode_used: \t%i\n" "j_cnode_free: \t%i\n" "\n"
+ /* reiserfs_proc_info_data_t.journal fields */
+ "in_journal: \t%12lu\n"
+ "in_journal_bitmap: \t%12lu\n"
+ "in_journal_reusable: \t%12lu\n"
+ "lock_journal: \t%12lu\n"
+ "lock_journal_wait: \t%12lu\n"
+ "journal_begin: \t%12lu\n"
+ "journal_relock_writers: \t%12lu\n"
+ "journal_relock_wcount: \t%12lu\n"
+ "mark_dirty: \t%12lu\n"
+ "mark_dirty_already: \t%12lu\n"
+ "mark_dirty_notjournal: \t%12lu\n"
+ "restore_prepared: \t%12lu\n"
+ "prepare: \t%12lu\n"
+ "prepare_retry: \t%12lu\n",
+ DJP(jp_journal_1st_block),
+ bdevname(SB_JOURNAL(sb)->j_dev_bd, b),
+ DJP(jp_journal_dev),
+ DJP(jp_journal_size),
+ DJP(jp_journal_trans_max),
+ DJP(jp_journal_magic),
+ DJP(jp_journal_max_batch),
+ SB_JOURNAL(sb)->j_max_commit_age,
+ DJP(jp_journal_max_trans_age),
+ JF(j_1st_reserved_block),
+ JF(j_state),
+ JF(j_trans_id),
+ JF(j_mount_id),
+ JF(j_start),
+ JF(j_len),
+ JF(j_len_alloc),
+ atomic_read(&r->s_journal->j_wcount),
+ JF(j_bcount),
+ JF(j_first_unflushed_offset),
+ JF(j_last_flush_trans_id),
+ JF(j_trans_start_time),
+ JF(j_list_bitmap_index),
+ JF(j_must_wait),
+ JF(j_next_full_flush),
+ JF(j_next_async_flush),
+ JF(j_cnode_used),
+ JF(j_cnode_free),
+ SFPJ(in_journal),
+ SFPJ(in_journal_bitmap),
+ SFPJ(in_journal_reusable),
+ SFPJ(lock_journal),
+ SFPJ(lock_journal_wait),
+ SFPJ(journal_being),
+ SFPJ(journal_relock_writers),
+ SFPJ(journal_relock_wcount),
+ SFPJ(mark_dirty),
+ SFPJ(mark_dirty_already),
+ SFPJ(mark_dirty_notjournal),
+ SFPJ(restore_prepared), SFPJ(prepare), SFPJ(prepare_retry)
+ );
return 0;
}
@@ -450,7 +410,7 @@ static int set_sb(struct super_block *sb, void *data)
return -ENOENT;
}
-static void *r_start(struct seq_file *m, loff_t *pos)
+static void *r_start(struct seq_file *m, loff_t * pos)
{
struct proc_dir_entry *de = m->private;
struct super_block *s = de->parent->data;
@@ -472,7 +432,7 @@ static void *r_start(struct seq_file *m, loff_t *pos)
return s;
}
-static void *r_next(struct seq_file *m, void *v, loff_t *pos)
+static void *r_next(struct seq_file *m, void *v, loff_t * pos)
{
++*pos;
if (v)
@@ -489,7 +449,7 @@ static void r_stop(struct seq_file *m, void *v)
static int r_show(struct seq_file *m, void *v)
{
struct proc_dir_entry *de = m->private;
- int (*show)(struct seq_file *, struct super_block *) = de->data;
+ int (*show) (struct seq_file *, struct super_block *) = de->data;
return show(m, v);
}
@@ -512,17 +472,17 @@ static int r_open(struct inode *inode, struct file *file)
}
static struct file_operations r_file_operations = {
- .open = r_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
+ .open = r_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
};
static struct proc_dir_entry *proc_info_root = NULL;
static const char proc_info_root_name[] = "fs/reiserfs";
static void add_file(struct super_block *sb, char *name,
- int (*func)(struct seq_file *, struct super_block *))
+ int (*func) (struct seq_file *, struct super_block *))
{
struct proc_dir_entry *de;
de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
@@ -532,11 +492,12 @@ static void add_file(struct super_block *sb, char *name,
}
}
-int reiserfs_proc_info_init( struct super_block *sb )
+int reiserfs_proc_info_init(struct super_block *sb)
{
- spin_lock_init( & __PINFO( sb ).lock );
- REISERFS_SB(sb)->procdir = proc_mkdir(reiserfs_bdevname (sb), proc_info_root);
- if( REISERFS_SB(sb)->procdir ) {
+ spin_lock_init(&__PINFO(sb).lock);
+ REISERFS_SB(sb)->procdir =
+ proc_mkdir(reiserfs_bdevname(sb), proc_info_root);
+ if (REISERFS_SB(sb)->procdir) {
REISERFS_SB(sb)->procdir->owner = THIS_MODULE;
REISERFS_SB(sb)->procdir->data = sb;
add_file(sb, "version", show_version);
@@ -549,11 +510,11 @@ int reiserfs_proc_info_init( struct super_block *sb )
return 0;
}
reiserfs_warning(sb, "reiserfs: cannot create /proc/%s/%s",
- proc_info_root_name, reiserfs_bdevname (sb) );
+ proc_info_root_name, reiserfs_bdevname(sb));
return 1;
}
-int reiserfs_proc_info_done( struct super_block *sb )
+int reiserfs_proc_info_done(struct super_block *sb)
{
struct proc_dir_entry *de = REISERFS_SB(sb)->procdir;
if (de) {
@@ -565,48 +526,48 @@ int reiserfs_proc_info_done( struct super_block *sb )
remove_proc_entry("super", de);
remove_proc_entry("version", de);
}
- spin_lock( & __PINFO( sb ).lock );
- __PINFO( sb ).exiting = 1;
- spin_unlock( & __PINFO( sb ).lock );
- if ( proc_info_root ) {
- remove_proc_entry( reiserfs_bdevname (sb), proc_info_root );
+ spin_lock(&__PINFO(sb).lock);
+ __PINFO(sb).exiting = 1;
+ spin_unlock(&__PINFO(sb).lock);
+ if (proc_info_root) {
+ remove_proc_entry(reiserfs_bdevname(sb), proc_info_root);
REISERFS_SB(sb)->procdir = NULL;
}
return 0;
}
-struct proc_dir_entry *reiserfs_proc_register_global( char *name,
- read_proc_t *func )
+struct proc_dir_entry *reiserfs_proc_register_global(char *name,
+ read_proc_t * func)
{
- return ( proc_info_root ) ? create_proc_read_entry( name, 0,
- proc_info_root,
- func, NULL ) : NULL;
+ return (proc_info_root) ? create_proc_read_entry(name, 0,
+ proc_info_root,
+ func, NULL) : NULL;
}
-void reiserfs_proc_unregister_global( const char *name )
+void reiserfs_proc_unregister_global(const char *name)
{
- remove_proc_entry( name, proc_info_root );
+ remove_proc_entry(name, proc_info_root);
}
-int reiserfs_proc_info_global_init( void )
+int reiserfs_proc_info_global_init(void)
{
- if( proc_info_root == NULL ) {
+ if (proc_info_root == NULL) {
proc_info_root = proc_mkdir(proc_info_root_name, NULL);
- if( proc_info_root ) {
- proc_info_root -> owner = THIS_MODULE;
+ if (proc_info_root) {
+ proc_info_root->owner = THIS_MODULE;
} else {
- reiserfs_warning (NULL,
- "reiserfs: cannot create /proc/%s",
- proc_info_root_name );
+ reiserfs_warning(NULL,
+ "reiserfs: cannot create /proc/%s",
+ proc_info_root_name);
return 1;
}
}
return 0;
}
-int reiserfs_proc_info_global_done( void )
+int reiserfs_proc_info_global_done(void)
{
- if ( proc_info_root != NULL ) {
+ if (proc_info_root != NULL) {
proc_info_root = NULL;
remove_proc_entry(proc_info_root_name, NULL);
}
@@ -616,22 +577,40 @@ int reiserfs_proc_info_global_done( void )
/* REISERFS_PROC_INFO */
#else
-int reiserfs_proc_info_init( struct super_block *sb ) { return 0; }
-int reiserfs_proc_info_done( struct super_block *sb ) { return 0; }
+int reiserfs_proc_info_init(struct super_block *sb)
+{
+ return 0;
+}
+int reiserfs_proc_info_done(struct super_block *sb)
+{
+ return 0;
+}
-struct proc_dir_entry *reiserfs_proc_register_global( char *name,
- read_proc_t *func )
-{ return NULL; }
+struct proc_dir_entry *reiserfs_proc_register_global(char *name,
+ read_proc_t * func)
+{
+ return NULL;
+}
-void reiserfs_proc_unregister_global( const char *name ) {;}
+void reiserfs_proc_unregister_global(const char *name)
+{;
+}
-int reiserfs_proc_info_global_init( void ) { return 0; }
-int reiserfs_proc_info_global_done( void ) { return 0; }
+int reiserfs_proc_info_global_init(void)
+{
+ return 0;
+}
+int reiserfs_proc_info_global_done(void)
+{
+ return 0;
+}
-int reiserfs_global_version_in_proc( char *buffer, char **start,
- off_t offset,
- int count, int *eof, void *data )
-{ return 0; }
+int reiserfs_global_version_in_proc(char *buffer, char **start,
+ off_t offset,
+ int count, int *eof, void *data)
+{
+ return 0;
+}
/* REISERFS_PROC_INFO */
#endif
diff --git a/fs/reiserfs/resize.c b/fs/reiserfs/resize.c
index 170012078b76..39cc7f47f5dc 100644
--- a/fs/reiserfs/resize.c
+++ b/fs/reiserfs/resize.c
@@ -1,7 +1,7 @@
/*
* Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README
*/
-
+
/*
* Written by Alexander Zarochentcev.
*
@@ -17,23 +17,23 @@
#include <linux/reiserfs_fs_sb.h>
#include <linux/buffer_head.h>
-int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
+int reiserfs_resize(struct super_block *s, unsigned long block_count_new)
{
- int err = 0;
- struct reiserfs_super_block * sb;
- struct reiserfs_bitmap_info *bitmap;
+ int err = 0;
+ struct reiserfs_super_block *sb;
+ struct reiserfs_bitmap_info *bitmap;
struct reiserfs_bitmap_info *old_bitmap = SB_AP_BITMAP(s);
- struct buffer_head * bh;
+ struct buffer_head *bh;
struct reiserfs_transaction_handle th;
unsigned int bmap_nr_new, bmap_nr;
unsigned int block_r_new, block_r;
-
- struct reiserfs_list_bitmap * jb;
+
+ struct reiserfs_list_bitmap *jb;
struct reiserfs_list_bitmap jbitmap[JOURNAL_NUM_BITMAPS];
-
+
unsigned long int block_count, free_blocks;
int i;
- int copy_size ;
+ int copy_size;
sb = SB_DISK_SUPER_BLOCK(s);
@@ -47,136 +47,145 @@ int reiserfs_resize (struct super_block * s, unsigned long block_count_new)
if (!bh) {
printk("reiserfs_resize: can\'t read last block\n");
return -EINVAL;
- }
+ }
bforget(bh);
/* old disk layout detection; those partitions can be mounted, but
* cannot be resized */
- if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
- != REISERFS_DISK_OFFSET_IN_BYTES ) {
- printk("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
+ if (SB_BUFFER_WITH_SB(s)->b_blocknr * SB_BUFFER_WITH_SB(s)->b_size
+ != REISERFS_DISK_OFFSET_IN_BYTES) {
+ printk
+ ("reiserfs_resize: unable to resize a reiserfs without distributed bitmap (fs version < 3.5.12)\n");
return -ENOTSUPP;
}
-
+
/* count used bits in last bitmap block */
- block_r = SB_BLOCK_COUNT(s) -
- (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8;
-
+ block_r = SB_BLOCK_COUNT(s) - (SB_BMAP_NR(s) - 1) * s->s_blocksize * 8;
+
/* count bitmap blocks in new fs */
- bmap_nr_new = block_count_new / ( s->s_blocksize * 8 );
+ bmap_nr_new = block_count_new / (s->s_blocksize * 8);
block_r_new = block_count_new - bmap_nr_new * s->s_blocksize * 8;
- if (block_r_new)
+ if (block_r_new)
bmap_nr_new++;
else
block_r_new = s->s_blocksize * 8;
/* save old values */
block_count = SB_BLOCK_COUNT(s);
- bmap_nr = SB_BMAP_NR(s);
+ bmap_nr = SB_BMAP_NR(s);
/* resizing of reiserfs bitmaps (journal and real), if needed */
- if (bmap_nr_new > bmap_nr) {
- /* reallocate journal bitmaps */
- if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
- printk("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
- unlock_super(s) ;
- return -ENOMEM ;
- }
- /* the new journal bitmaps are zero filled, now we copy in the bitmap
- ** node pointers from the old journal bitmap structs, and then
- ** transfer the new data structures into the journal struct.
- **
- ** using the copy_size var below allows this code to work for
- ** both shrinking and expanding the FS.
- */
- copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr ;
- copy_size = copy_size * sizeof(struct reiserfs_list_bitmap_node *) ;
- for (i = 0 ; i < JOURNAL_NUM_BITMAPS ; i++) {
- struct reiserfs_bitmap_node **node_tmp ;
- jb = SB_JOURNAL(s)->j_list_bitmap + i ;
- memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size) ;
-
- /* just in case vfree schedules on us, copy the new
- ** pointer into the journal struct before freeing the
- ** old one
- */
- node_tmp = jb->bitmaps ;
- jb->bitmaps = jbitmap[i].bitmaps ;
- vfree(node_tmp) ;
- }
-
- /* allocate additional bitmap blocks, reallocate array of bitmap
- * block pointers */
- bitmap = vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
- if (!bitmap) {
- /* Journal bitmaps are still supersized, but the memory isn't
- * leaked, so I guess it's ok */
- printk("reiserfs_resize: unable to allocate memory.\n");
- return -ENOMEM;
- }
- memset (bitmap, 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
- for (i = 0; i < bmap_nr; i++)
- bitmap[i] = old_bitmap[i];
-
- /* This doesn't go through the journal, but it doesn't have to.
- * The changes are still atomic: We're synced up when the journal
- * transaction begins, and the new bitmaps don't matter if the
- * transaction fails. */
- for (i = bmap_nr; i < bmap_nr_new; i++) {
- bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
- memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
- reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
-
- set_buffer_uptodate(bitmap[i].bh);
- mark_buffer_dirty(bitmap[i].bh) ;
- sync_dirty_buffer(bitmap[i].bh);
- // update bitmap_info stuff
- bitmap[i].first_zero_hint=1;
- bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
- }
- /* free old bitmap blocks array */
- SB_AP_BITMAP(s) = bitmap;
- vfree (old_bitmap);
+ if (bmap_nr_new > bmap_nr) {
+ /* reallocate journal bitmaps */
+ if (reiserfs_allocate_list_bitmaps(s, jbitmap, bmap_nr_new) < 0) {
+ printk
+ ("reiserfs_resize: unable to allocate memory for journal bitmaps\n");
+ unlock_super(s);
+ return -ENOMEM;
+ }
+ /* the new journal bitmaps are zero filled, now we copy in the bitmap
+ ** node pointers from the old journal bitmap structs, and then
+ ** transfer the new data structures into the journal struct.
+ **
+ ** using the copy_size var below allows this code to work for
+ ** both shrinking and expanding the FS.
+ */
+ copy_size = bmap_nr_new < bmap_nr ? bmap_nr_new : bmap_nr;
+ copy_size =
+ copy_size * sizeof(struct reiserfs_list_bitmap_node *);
+ for (i = 0; i < JOURNAL_NUM_BITMAPS; i++) {
+ struct reiserfs_bitmap_node **node_tmp;
+ jb = SB_JOURNAL(s)->j_list_bitmap + i;
+ memcpy(jbitmap[i].bitmaps, jb->bitmaps, copy_size);
+
+ /* just in case vfree schedules on us, copy the new
+ ** pointer into the journal struct before freeing the
+ ** old one
+ */
+ node_tmp = jb->bitmaps;
+ jb->bitmaps = jbitmap[i].bitmaps;
+ vfree(node_tmp);
+ }
+
+ /* allocate additional bitmap blocks, reallocate array of bitmap
+ * block pointers */
+ bitmap =
+ vmalloc(sizeof(struct reiserfs_bitmap_info) * bmap_nr_new);
+ if (!bitmap) {
+ /* Journal bitmaps are still supersized, but the memory isn't
+ * leaked, so I guess it's ok */
+ printk("reiserfs_resize: unable to allocate memory.\n");
+ return -ENOMEM;
+ }
+ memset(bitmap, 0,
+ sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
+ for (i = 0; i < bmap_nr; i++)
+ bitmap[i] = old_bitmap[i];
+
+ /* This doesn't go through the journal, but it doesn't have to.
+ * The changes are still atomic: We're synced up when the journal
+ * transaction begins, and the new bitmaps don't matter if the
+ * transaction fails. */
+ for (i = bmap_nr; i < bmap_nr_new; i++) {
+ bitmap[i].bh = sb_getblk(s, i * s->s_blocksize * 8);
+ memset(bitmap[i].bh->b_data, 0, sb_blocksize(sb));
+ reiserfs_test_and_set_le_bit(0, bitmap[i].bh->b_data);
+
+ set_buffer_uptodate(bitmap[i].bh);
+ mark_buffer_dirty(bitmap[i].bh);
+ sync_dirty_buffer(bitmap[i].bh);
+ // update bitmap_info stuff
+ bitmap[i].first_zero_hint = 1;
+ bitmap[i].free_count = sb_blocksize(sb) * 8 - 1;
+ }
+ /* free old bitmap blocks array */
+ SB_AP_BITMAP(s) = bitmap;
+ vfree(old_bitmap);
}
-
+
/* begin transaction, if there was an error, it's fine. Yes, we have
* incorrect bitmaps now, but none of it is ever going to touch the
* disk anyway. */
err = journal_begin(&th, s, 10);
if (err)
- return err;
+ return err;
/* correct last bitmap blocks in old and new disk layout */
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr - 1].bh, 1);
for (i = block_r; i < s->s_blocksize * 8; i++)
- reiserfs_test_and_clear_le_bit(i,
- SB_AP_BITMAP(s)[bmap_nr - 1].bh->b_data);
+ reiserfs_test_and_clear_le_bit(i,
+ SB_AP_BITMAP(s)[bmap_nr -
+ 1].bh->b_data);
SB_AP_BITMAP(s)[bmap_nr - 1].free_count += s->s_blocksize * 8 - block_r;
- if ( !SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
- SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
+ if (!SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint)
+ SB_AP_BITMAP(s)[bmap_nr - 1].first_zero_hint = block_r;
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr - 1].bh);
reiserfs_prepare_for_journal(s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh, 1);
for (i = block_r_new; i < s->s_blocksize * 8; i++)
- reiserfs_test_and_set_le_bit(i,
- SB_AP_BITMAP(s)[bmap_nr_new - 1].bh->b_data);
+ reiserfs_test_and_set_le_bit(i,
+ SB_AP_BITMAP(s)[bmap_nr_new -
+ 1].bh->b_data);
journal_mark_dirty(&th, s, SB_AP_BITMAP(s)[bmap_nr_new - 1].bh);
-
- SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -= s->s_blocksize * 8 - block_r_new;
+
+ SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count -=
+ s->s_blocksize * 8 - block_r_new;
/* Extreme case where last bitmap is the only valid block in itself. */
- if ( !SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count )
- SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
- /* update super */
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
+ if (!SB_AP_BITMAP(s)[bmap_nr_new - 1].free_count)
+ SB_AP_BITMAP(s)[bmap_nr_new - 1].first_zero_hint = 0;
+ /* update super */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
free_blocks = SB_FREE_BLOCKS(s);
- PUT_SB_FREE_BLOCKS(s, free_blocks + (block_count_new - block_count - (bmap_nr_new - bmap_nr)));
+ PUT_SB_FREE_BLOCKS(s,
+ free_blocks + (block_count_new - block_count -
+ (bmap_nr_new - bmap_nr)));
PUT_SB_BLOCK_COUNT(s, block_count_new);
PUT_SB_BMAP_NR(s, bmap_nr_new);
s->s_dirt = 1;
journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
-
+
SB_JOURNAL(s)->j_must_wait = 1;
return journal_end(&th, s, 10);
}
diff --git a/fs/reiserfs/stree.c b/fs/reiserfs/stree.c
index c47f8fd31a2d..e2d08d7bcffc 100644
--- a/fs/reiserfs/stree.c
+++ b/fs/reiserfs/stree.c
@@ -59,46 +59,45 @@
#include <linux/quotaops.h>
/* Does the buffer contain a disk block which is in the tree. */
-inline int B_IS_IN_TREE (const struct buffer_head * p_s_bh)
+inline int B_IS_IN_TREE(const struct buffer_head *p_s_bh)
{
- RFALSE( B_LEVEL (p_s_bh) > MAX_HEIGHT,
- "PAP-1010: block (%b) has too big level (%z)", p_s_bh, p_s_bh);
+ RFALSE(B_LEVEL(p_s_bh) > MAX_HEIGHT,
+ "PAP-1010: block (%b) has too big level (%z)", p_s_bh, p_s_bh);
- return ( B_LEVEL (p_s_bh) != FREE_LEVEL );
+ return (B_LEVEL(p_s_bh) != FREE_LEVEL);
}
//
// to gets item head in le form
//
-inline void copy_item_head(struct item_head * p_v_to,
- const struct item_head * p_v_from)
+inline void copy_item_head(struct item_head *p_v_to,
+ const struct item_head *p_v_from)
{
- memcpy (p_v_to, p_v_from, IH_SIZE);
+ memcpy(p_v_to, p_v_from, IH_SIZE);
}
-
/* k1 is pointer to on-disk structure which is stored in little-endian
form. k2 is pointer to cpu variable. For key of items of the same
object this returns 0.
Returns: -1 if key1 < key2
0 if key1 == key2
1 if key1 > key2 */
-inline int comp_short_keys (const struct reiserfs_key * le_key,
- const struct cpu_key * cpu_key)
+inline int comp_short_keys(const struct reiserfs_key *le_key,
+ const struct cpu_key *cpu_key)
{
- __u32 n;
- n = le32_to_cpu(le_key->k_dir_id);
- if (n < cpu_key->on_disk_key.k_dir_id)
- return -1;
- if (n > cpu_key->on_disk_key.k_dir_id)
- return 1;
- n = le32_to_cpu(le_key->k_objectid);
- if (n < cpu_key->on_disk_key.k_objectid)
- return -1;
- if (n > cpu_key->on_disk_key.k_objectid)
- return 1;
- return 0;
+ __u32 n;
+ n = le32_to_cpu(le_key->k_dir_id);
+ if (n < cpu_key->on_disk_key.k_dir_id)
+ return -1;
+ if (n > cpu_key->on_disk_key.k_dir_id)
+ return 1;
+ n = le32_to_cpu(le_key->k_objectid);
+ if (n < cpu_key->on_disk_key.k_objectid)
+ return -1;
+ if (n > cpu_key->on_disk_key.k_objectid)
+ return 1;
+ return 0;
}
/* k1 is pointer to on-disk structure which is stored in little-endian
@@ -106,68 +105,72 @@ inline int comp_short_keys (const struct reiserfs_key * le_key,
Compare keys using all 4 key fields.
Returns: -1 if key1 < key2 0
if key1 = key2 1 if key1 > key2 */
-static inline int comp_keys (const struct reiserfs_key * le_key, const struct cpu_key * cpu_key)
+static inline int comp_keys(const struct reiserfs_key *le_key,
+ const struct cpu_key *cpu_key)
{
- int retval;
-
- retval = comp_short_keys (le_key, cpu_key);
- if (retval)
- return retval;
- if (le_key_k_offset (le_key_version(le_key), le_key) < cpu_key_k_offset (cpu_key))
- return -1;
- if (le_key_k_offset (le_key_version(le_key), le_key) > cpu_key_k_offset (cpu_key))
- return 1;
-
- if (cpu_key->key_length == 3)
- return 0;
-
- /* this part is needed only when tail conversion is in progress */
- if (le_key_k_type (le_key_version(le_key), le_key) < cpu_key_k_type (cpu_key))
- return -1;
+ int retval;
+
+ retval = comp_short_keys(le_key, cpu_key);
+ if (retval)
+ return retval;
+ if (le_key_k_offset(le_key_version(le_key), le_key) <
+ cpu_key_k_offset(cpu_key))
+ return -1;
+ if (le_key_k_offset(le_key_version(le_key), le_key) >
+ cpu_key_k_offset(cpu_key))
+ return 1;
+
+ if (cpu_key->key_length == 3)
+ return 0;
+
+ /* this part is needed only when tail conversion is in progress */
+ if (le_key_k_type(le_key_version(le_key), le_key) <
+ cpu_key_k_type(cpu_key))
+ return -1;
+
+ if (le_key_k_type(le_key_version(le_key), le_key) >
+ cpu_key_k_type(cpu_key))
+ return 1;
- if (le_key_k_type (le_key_version(le_key), le_key) > cpu_key_k_type (cpu_key))
- return 1;
-
- return 0;
+ return 0;
}
-
-inline int comp_short_le_keys (const struct reiserfs_key * key1, const struct reiserfs_key * key2)
+inline int comp_short_le_keys(const struct reiserfs_key *key1,
+ const struct reiserfs_key *key2)
{
- __u32 * p_s_1_u32, * p_s_2_u32;
- int n_key_length = REISERFS_SHORT_KEY_LEN;
-
- p_s_1_u32 = (__u32 *)key1;
- p_s_2_u32 = (__u32 *)key2;
- for( ; n_key_length--; ++p_s_1_u32, ++p_s_2_u32 ) {
- if ( le32_to_cpu (*p_s_1_u32) < le32_to_cpu (*p_s_2_u32) )
- return -1;
- if ( le32_to_cpu (*p_s_1_u32) > le32_to_cpu (*p_s_2_u32) )
- return 1;
- }
- return 0;
+ __u32 *p_s_1_u32, *p_s_2_u32;
+ int n_key_length = REISERFS_SHORT_KEY_LEN;
+
+ p_s_1_u32 = (__u32 *) key1;
+ p_s_2_u32 = (__u32 *) key2;
+ for (; n_key_length--; ++p_s_1_u32, ++p_s_2_u32) {
+ if (le32_to_cpu(*p_s_1_u32) < le32_to_cpu(*p_s_2_u32))
+ return -1;
+ if (le32_to_cpu(*p_s_1_u32) > le32_to_cpu(*p_s_2_u32))
+ return 1;
+ }
+ return 0;
}
-inline void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from)
+inline void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from)
{
- int version;
- to->on_disk_key.k_dir_id = le32_to_cpu (from->k_dir_id);
- to->on_disk_key.k_objectid = le32_to_cpu (from->k_objectid);
-
- // find out version of the key
- version = le_key_version (from);
- to->version = version;
- to->on_disk_key.k_offset = le_key_k_offset(version, from);
- to->on_disk_key.k_type = le_key_k_type(version, from);
+ int version;
+ to->on_disk_key.k_dir_id = le32_to_cpu(from->k_dir_id);
+ to->on_disk_key.k_objectid = le32_to_cpu(from->k_objectid);
+
+ // find out version of the key
+ version = le_key_version(from);
+ to->version = version;
+ to->on_disk_key.k_offset = le_key_k_offset(version, from);
+ to->on_disk_key.k_type = le_key_k_type(version, from);
}
-
-
// this does not say which one is bigger, it only returns 1 if keys
// are not equal, 0 otherwise
-inline int comp_le_keys (const struct reiserfs_key * k1, const struct reiserfs_key * k2)
+inline int comp_le_keys(const struct reiserfs_key *k1,
+ const struct reiserfs_key *k2)
{
- return memcmp (k1, k2, sizeof (struct reiserfs_key));
+ return memcmp(k1, k2, sizeof(struct reiserfs_key));
}
/**************************************************************************
@@ -184,373 +187,396 @@ inline int comp_le_keys (const struct reiserfs_key * k1, const struct reiserfs_k
there are no possible items, and we have not found it. With each examination we
cut the number of possible items it could be by one more than half rounded down,
or we find it. */
-static inline int bin_search (
- const void * p_v_key, /* Key to search for. */
- const void * p_v_base,/* First item in the array. */
- int p_n_num, /* Number of items in the array. */
- int p_n_width, /* Item size in the array.
- searched. Lest the reader be
- confused, note that this is crafted
- as a general function, and when it
- is applied specifically to the array
- of item headers in a node, p_n_width
- is actually the item header size not
- the item size. */
- int * p_n_pos /* Number of the searched for element. */
- ) {
- int n_rbound, n_lbound, n_j;
-
- for ( n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0))/2; n_lbound <= n_rbound; n_j = (n_rbound + n_lbound)/2 )
- switch( comp_keys((struct reiserfs_key *)((char * )p_v_base + n_j * p_n_width), (struct cpu_key *)p_v_key) ) {
- case -1: n_lbound = n_j + 1; continue;
- case 1: n_rbound = n_j - 1; continue;
- case 0: *p_n_pos = n_j; return ITEM_FOUND; /* Key found in the array. */
- }
-
- /* bin_search did not find given key, it returns position of key,
- that is minimal and greater than the given one. */
- *p_n_pos = n_lbound;
- return ITEM_NOT_FOUND;
+static inline int bin_search(const void *p_v_key, /* Key to search for. */
+ const void *p_v_base, /* First item in the array. */
+ int p_n_num, /* Number of items in the array. */
+ int p_n_width, /* Item size in the array.
+ searched. Lest the reader be
+ confused, note that this is crafted
+ as a general function, and when it
+ is applied specifically to the array
+ of item headers in a node, p_n_width
+ is actually the item header size not
+ the item size. */
+ int *p_n_pos /* Number of the searched for element. */
+ )
+{
+ int n_rbound, n_lbound, n_j;
+
+ for (n_j = ((n_rbound = p_n_num - 1) + (n_lbound = 0)) / 2;
+ n_lbound <= n_rbound; n_j = (n_rbound + n_lbound) / 2)
+ switch (comp_keys
+ ((struct reiserfs_key *)((char *)p_v_base +
+ n_j * p_n_width),
+ (struct cpu_key *)p_v_key)) {
+ case -1:
+ n_lbound = n_j + 1;
+ continue;
+ case 1:
+ n_rbound = n_j - 1;
+ continue;
+ case 0:
+ *p_n_pos = n_j;
+ return ITEM_FOUND; /* Key found in the array. */
+ }
+
+ /* bin_search did not find given key, it returns position of key,
+ that is minimal and greater than the given one. */
+ *p_n_pos = n_lbound;
+ return ITEM_NOT_FOUND;
}
#ifdef CONFIG_REISERFS_CHECK
-extern struct tree_balance * cur_tb;
+extern struct tree_balance *cur_tb;
#endif
-
-
/* Minimal possible key. It is never in the tree. */
-const struct reiserfs_key MIN_KEY = {0, 0, {{0, 0},}};
+const struct reiserfs_key MIN_KEY = { 0, 0, {{0, 0},} };
/* Maximal possible key. It is never in the tree. */
-const struct reiserfs_key MAX_KEY = {
+static const struct reiserfs_key MAX_KEY = {
__constant_cpu_to_le32(0xffffffff),
__constant_cpu_to_le32(0xffffffff),
{{__constant_cpu_to_le32(0xffffffff),
- __constant_cpu_to_le32(0xffffffff)},}
+ __constant_cpu_to_le32(0xffffffff)},}
};
-
/* Get delimiting key of the buffer by looking for it in the buffers in the path, starting from the bottom
of the path, and going upwards. We must check the path's validity at each step. If the key is not in
the path, there is no delimiting key in the tree (buffer is first or last buffer in tree), and in this
case we return a special key, either MIN_KEY or MAX_KEY. */
-static inline const struct reiserfs_key * get_lkey (
- const struct path * p_s_chk_path,
- const struct super_block * p_s_sb
- ) {
- int n_position, n_path_offset = p_s_chk_path->path_length;
- struct buffer_head * p_s_parent;
-
- RFALSE( n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
- "PAP-5010: invalid offset in the path");
-
- /* While not higher in path than first element. */
- while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {
-
- RFALSE( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
- "PAP-5020: parent is not uptodate");
-
- /* Parent at the path is not in the tree now. */
- if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
- return &MAX_KEY;
- /* Check whether position in the parent is correct. */
- if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
- return &MAX_KEY;
- /* Check whether parent at the path really points to the child. */
- if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
- PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )
- return &MAX_KEY;
- /* Return delimiting key if position in the parent is not equal to zero. */
- if ( n_position )
- return B_N_PDELIM_KEY(p_s_parent, n_position - 1);
- }
- /* Return MIN_KEY if we are in the root of the buffer tree. */
- if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
- SB_ROOT_BLOCK (p_s_sb) )
- return &MIN_KEY;
- return &MAX_KEY;
+static inline const struct reiserfs_key *get_lkey(const struct path
+ *p_s_chk_path,
+ const struct super_block
+ *p_s_sb)
+{
+ int n_position, n_path_offset = p_s_chk_path->path_length;
+ struct buffer_head *p_s_parent;
+
+ RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
+ "PAP-5010: invalid offset in the path");
+
+ /* While not higher in path than first element. */
+ while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+
+ RFALSE(!buffer_uptodate
+ (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
+ "PAP-5020: parent is not uptodate");
+
+ /* Parent at the path is not in the tree now. */
+ if (!B_IS_IN_TREE
+ (p_s_parent =
+ PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+ return &MAX_KEY;
+ /* Check whether position in the parent is correct. */
+ if ((n_position =
+ PATH_OFFSET_POSITION(p_s_chk_path,
+ n_path_offset)) >
+ B_NR_ITEMS(p_s_parent))
+ return &MAX_KEY;
+ /* Check whether parent at the path really points to the child. */
+ if (B_N_CHILD_NUM(p_s_parent, n_position) !=
+ PATH_OFFSET_PBUFFER(p_s_chk_path,
+ n_path_offset + 1)->b_blocknr)
+ return &MAX_KEY;
+ /* Return delimiting key if position in the parent is not equal to zero. */
+ if (n_position)
+ return B_N_PDELIM_KEY(p_s_parent, n_position - 1);
+ }
+ /* Return MIN_KEY if we are in the root of the buffer tree. */
+ if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->
+ b_blocknr == SB_ROOT_BLOCK(p_s_sb))
+ return &MIN_KEY;
+ return &MAX_KEY;
}
-
/* Get delimiting key of the buffer at the path and its right neighbor. */
-inline const struct reiserfs_key * get_rkey (
- const struct path * p_s_chk_path,
- const struct super_block * p_s_sb
- ) {
- int n_position,
- n_path_offset = p_s_chk_path->path_length;
- struct buffer_head * p_s_parent;
-
- RFALSE( n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
- "PAP-5030: invalid offset in the path");
-
- while ( n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET ) {
-
- RFALSE( ! buffer_uptodate(PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
- "PAP-5040: parent is not uptodate");
-
- /* Parent at the path is not in the tree now. */
- if ( ! B_IS_IN_TREE(p_s_parent = PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)) )
- return &MIN_KEY;
- /* Check whether position in the parent is correct. */
- if ( (n_position = PATH_OFFSET_POSITION(p_s_chk_path, n_path_offset)) > B_NR_ITEMS(p_s_parent) )
- return &MIN_KEY;
- /* Check whether parent at the path really points to the child. */
- if ( B_N_CHILD_NUM(p_s_parent, n_position) !=
- PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset + 1)->b_blocknr )
- return &MIN_KEY;
- /* Return delimiting key if position in the parent is not the last one. */
- if ( n_position != B_NR_ITEMS(p_s_parent) )
- return B_N_PDELIM_KEY(p_s_parent, n_position);
- }
- /* Return MAX_KEY if we are in the root of the buffer tree. */
- if ( PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->b_blocknr ==
- SB_ROOT_BLOCK (p_s_sb) )
- return &MAX_KEY;
- return &MIN_KEY;
+inline const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+ const struct super_block *p_s_sb)
+{
+ int n_position, n_path_offset = p_s_chk_path->path_length;
+ struct buffer_head *p_s_parent;
+
+ RFALSE(n_path_offset < FIRST_PATH_ELEMENT_OFFSET,
+ "PAP-5030: invalid offset in the path");
+
+ while (n_path_offset-- > FIRST_PATH_ELEMENT_OFFSET) {
+
+ RFALSE(!buffer_uptodate
+ (PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)),
+ "PAP-5040: parent is not uptodate");
+
+ /* Parent at the path is not in the tree now. */
+ if (!B_IS_IN_TREE
+ (p_s_parent =
+ PATH_OFFSET_PBUFFER(p_s_chk_path, n_path_offset)))
+ return &MIN_KEY;
+ /* Check whether position in the parent is correct. */
+ if ((n_position =
+ PATH_OFFSET_POSITION(p_s_chk_path,
+ n_path_offset)) >
+ B_NR_ITEMS(p_s_parent))
+ return &MIN_KEY;
+ /* Check whether parent at the path really points to the child. */
+ if (B_N_CHILD_NUM(p_s_parent, n_position) !=
+ PATH_OFFSET_PBUFFER(p_s_chk_path,
+ n_path_offset + 1)->b_blocknr)
+ return &MIN_KEY;
+ /* Return delimiting key if position in the parent is not the last one. */
+ if (n_position != B_NR_ITEMS(p_s_parent))
+ return B_N_PDELIM_KEY(p_s_parent, n_position);
+ }
+ /* Return MAX_KEY if we are in the root of the buffer tree. */
+ if (PATH_OFFSET_PBUFFER(p_s_chk_path, FIRST_PATH_ELEMENT_OFFSET)->
+ b_blocknr == SB_ROOT_BLOCK(p_s_sb))
+ return &MAX_KEY;
+ return &MIN_KEY;
}
-
/* Check whether a key is contained in the tree rooted from a buffer at a path. */
/* This works by looking at the left and right delimiting keys for the buffer in the last path_element in
the path. These delimiting keys are stored at least one level above that buffer in the tree. If the
buffer is the first or last node in the tree order then one of the delimiting keys may be absent, and in
this case get_lkey and get_rkey return a special key which is MIN_KEY or MAX_KEY. */
-static inline int key_in_buffer (
- struct path * p_s_chk_path, /* Path which should be checked. */
- const struct cpu_key * p_s_key, /* Key which should be checked. */
- struct super_block * p_s_sb /* Super block pointer. */
- ) {
-
- RFALSE( ! p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET ||
- p_s_chk_path->path_length > MAX_HEIGHT,
- "PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d)",
- p_s_key, p_s_chk_path->path_length);
- RFALSE( !PATH_PLAST_BUFFER(p_s_chk_path)->b_bdev,
- "PAP-5060: device must not be NODEV");
-
- if ( comp_keys(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1 )
- /* left delimiting key is bigger, that the key we look for */
- return 0;
- // if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
- if ( comp_keys(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1 )
- /* p_s_key must be less than right delimitiing key */
- return 0;
- return 1;
-}
-
+static inline int key_in_buffer(struct path *p_s_chk_path, /* Path which should be checked. */
+ const struct cpu_key *p_s_key, /* Key which should be checked. */
+ struct super_block *p_s_sb /* Super block pointer. */
+ )
+{
-inline void decrement_bcount(
- struct buffer_head * p_s_bh
- ) {
- if ( p_s_bh ) {
- if ( atomic_read (&(p_s_bh->b_count)) ) {
- put_bh(p_s_bh) ;
- return;
- }
- reiserfs_panic(NULL, "PAP-5070: decrement_bcount: trying to free free buffer %b", p_s_bh);
- }
+ RFALSE(!p_s_key || p_s_chk_path->path_length < FIRST_PATH_ELEMENT_OFFSET
+ || p_s_chk_path->path_length > MAX_HEIGHT,
+ "PAP-5050: pointer to the key(%p) is NULL or invalid path length(%d)",
+ p_s_key, p_s_chk_path->path_length);
+ RFALSE(!PATH_PLAST_BUFFER(p_s_chk_path)->b_bdev,
+ "PAP-5060: device must not be NODEV");
+
+ if (comp_keys(get_lkey(p_s_chk_path, p_s_sb), p_s_key) == 1)
+ /* left delimiting key is bigger, that the key we look for */
+ return 0;
+ // if ( comp_keys(p_s_key, get_rkey(p_s_chk_path, p_s_sb)) != -1 )
+ if (comp_keys(get_rkey(p_s_chk_path, p_s_sb), p_s_key) != 1)
+ /* p_s_key must be less than right delimitiing key */
+ return 0;
+ return 1;
}
+inline void decrement_bcount(struct buffer_head *p_s_bh)
+{
+ if (p_s_bh) {
+ if (atomic_read(&(p_s_bh->b_count))) {
+ put_bh(p_s_bh);
+ return;
+ }
+ reiserfs_panic(NULL,
+ "PAP-5070: decrement_bcount: trying to free free buffer %b",
+ p_s_bh);
+ }
+}
/* Decrement b_count field of the all buffers in the path. */
-void decrement_counters_in_path (
- struct path * p_s_search_path
- ) {
- int n_path_offset = p_s_search_path->path_length;
-
- RFALSE( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ||
- n_path_offset > EXTENDED_MAX_HEIGHT - 1,
- "PAP-5080: invalid path offset of %d", n_path_offset);
-
- while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
- struct buffer_head * bh;
-
- bh = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--);
- decrement_bcount (bh);
- }
- p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
-}
+void decrement_counters_in_path(struct path *p_s_search_path)
+{
+ int n_path_offset = p_s_search_path->path_length;
+
+ RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET ||
+ n_path_offset > EXTENDED_MAX_HEIGHT - 1,
+ "PAP-5080: invalid path offset of %d", n_path_offset);
+ while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
+ struct buffer_head *bh;
-int reiserfs_check_path(struct path *p) {
- RFALSE( p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
- "path not properly relsed") ;
- return 0 ;
+ bh = PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--);
+ decrement_bcount(bh);
+ }
+ p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
}
+int reiserfs_check_path(struct path *p)
+{
+ RFALSE(p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET,
+ "path not properly relsed");
+ return 0;
+}
/* Release all buffers in the path. Restore dirty bits clean
** when preparing the buffer for the log
**
** only called from fix_nodes()
*/
-void pathrelse_and_restore (
- struct super_block *s,
- struct path * p_s_search_path
- ) {
- int n_path_offset = p_s_search_path->path_length;
-
- RFALSE( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
- "clm-4000: invalid path offset");
-
- while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET ) {
- reiserfs_restore_prepared_buffer(s, PATH_OFFSET_PBUFFER(p_s_search_path,
- n_path_offset));
- brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
- }
- p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path)
+{
+ int n_path_offset = p_s_search_path->path_length;
+
+ RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
+ "clm-4000: invalid path offset");
+
+ while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET) {
+ reiserfs_restore_prepared_buffer(s,
+ PATH_OFFSET_PBUFFER
+ (p_s_search_path,
+ n_path_offset));
+ brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
+ }
+ p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
}
/* Release all buffers in the path. */
-void pathrelse (
- struct path * p_s_search_path
- ) {
- int n_path_offset = p_s_search_path->path_length;
-
- RFALSE( n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
- "PAP-5090: invalid path offset");
-
- while ( n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET )
- brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
-
- p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
-}
+void pathrelse(struct path *p_s_search_path)
+{
+ int n_path_offset = p_s_search_path->path_length;
+ RFALSE(n_path_offset < ILLEGAL_PATH_ELEMENT_OFFSET,
+ "PAP-5090: invalid path offset");
+ while (n_path_offset > ILLEGAL_PATH_ELEMENT_OFFSET)
+ brelse(PATH_OFFSET_PBUFFER(p_s_search_path, n_path_offset--));
-static int is_leaf (char * buf, int blocksize, struct buffer_head * bh)
-{
- struct block_head * blkh;
- struct item_head * ih;
- int used_space;
- int prev_location;
- int i;
- int nr;
-
- blkh = (struct block_head *)buf;
- if ( blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
- reiserfs_warning (NULL, "is_leaf: this should be caught earlier");
- return 0;
- }
+ p_s_search_path->path_length = ILLEGAL_PATH_ELEMENT_OFFSET;
+}
- nr = blkh_nr_item(blkh);
- if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
- /* item number is too big or too small */
- reiserfs_warning (NULL, "is_leaf: nr_item seems wrong: %z", bh);
- return 0;
- }
- ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
- used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location (ih));
- if (used_space != blocksize - blkh_free_space(blkh)) {
- /* free space does not match to calculated amount of use space */
- reiserfs_warning (NULL, "is_leaf: free space seems wrong: %z", bh);
- return 0;
- }
-
- // FIXME: it is_leaf will hit performance too much - we may have
- // return 1 here
-
- /* check tables of item heads */
- ih = (struct item_head *)(buf + BLKH_SIZE);
- prev_location = blocksize;
- for (i = 0; i < nr; i ++, ih ++) {
- if ( le_ih_k_type(ih) == TYPE_ANY) {
- reiserfs_warning (NULL, "is_leaf: wrong item type for item %h",ih);
- return 0;
+static int is_leaf(char *buf, int blocksize, struct buffer_head *bh)
+{
+ struct block_head *blkh;
+ struct item_head *ih;
+ int used_space;
+ int prev_location;
+ int i;
+ int nr;
+
+ blkh = (struct block_head *)buf;
+ if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) {
+ reiserfs_warning(NULL,
+ "is_leaf: this should be caught earlier");
+ return 0;
}
- if (ih_location (ih) >= blocksize || ih_location (ih) < IH_SIZE * nr) {
- reiserfs_warning (NULL, "is_leaf: item location seems wrong: %h", ih);
- return 0;
+
+ nr = blkh_nr_item(blkh);
+ if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) {
+ /* item number is too big or too small */
+ reiserfs_warning(NULL, "is_leaf: nr_item seems wrong: %z", bh);
+ return 0;
}
- if (ih_item_len (ih) < 1 || ih_item_len (ih) > MAX_ITEM_LEN (blocksize)) {
- reiserfs_warning (NULL, "is_leaf: item length seems wrong: %h", ih);
- return 0;
+ ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1;
+ used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih));
+ if (used_space != blocksize - blkh_free_space(blkh)) {
+ /* free space does not match to calculated amount of use space */
+ reiserfs_warning(NULL, "is_leaf: free space seems wrong: %z",
+ bh);
+ return 0;
}
- if (prev_location - ih_location (ih) != ih_item_len (ih)) {
- reiserfs_warning (NULL, "is_leaf: item location seems wrong (second one): %h", ih);
- return 0;
+ // FIXME: it is_leaf will hit performance too much - we may have
+ // return 1 here
+
+ /* check tables of item heads */
+ ih = (struct item_head *)(buf + BLKH_SIZE);
+ prev_location = blocksize;
+ for (i = 0; i < nr; i++, ih++) {
+ if (le_ih_k_type(ih) == TYPE_ANY) {
+ reiserfs_warning(NULL,
+ "is_leaf: wrong item type for item %h",
+ ih);
+ return 0;
+ }
+ if (ih_location(ih) >= blocksize
+ || ih_location(ih) < IH_SIZE * nr) {
+ reiserfs_warning(NULL,
+ "is_leaf: item location seems wrong: %h",
+ ih);
+ return 0;
+ }
+ if (ih_item_len(ih) < 1
+ || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) {
+ reiserfs_warning(NULL,
+ "is_leaf: item length seems wrong: %h",
+ ih);
+ return 0;
+ }
+ if (prev_location - ih_location(ih) != ih_item_len(ih)) {
+ reiserfs_warning(NULL,
+ "is_leaf: item location seems wrong (second one): %h",
+ ih);
+ return 0;
+ }
+ prev_location = ih_location(ih);
}
- prev_location = ih_location (ih);
- }
- // one may imagine much more checks
- return 1;
+ // one may imagine much more checks
+ return 1;
}
-
/* returns 1 if buf looks like an internal node, 0 otherwise */
-static int is_internal (char * buf, int blocksize, struct buffer_head * bh)
+static int is_internal(char *buf, int blocksize, struct buffer_head *bh)
{
- struct block_head * blkh;
- int nr;
- int used_space;
-
- blkh = (struct block_head *)buf;
- nr = blkh_level(blkh);
- if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
- /* this level is not possible for internal nodes */
- reiserfs_warning (NULL, "is_internal: this should be caught earlier");
- return 0;
- }
-
- nr = blkh_nr_item(blkh);
- if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
- /* for internal which is not root we might check min number of keys */
- reiserfs_warning (NULL, "is_internal: number of key seems wrong: %z", bh);
- return 0;
- }
+ struct block_head *blkh;
+ int nr;
+ int used_space;
+
+ blkh = (struct block_head *)buf;
+ nr = blkh_level(blkh);
+ if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) {
+ /* this level is not possible for internal nodes */
+ reiserfs_warning(NULL,
+ "is_internal: this should be caught earlier");
+ return 0;
+ }
- used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
- if (used_space != blocksize - blkh_free_space(blkh)) {
- reiserfs_warning (NULL, "is_internal: free space seems wrong: %z", bh);
- return 0;
- }
+ nr = blkh_nr_item(blkh);
+ if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) {
+ /* for internal which is not root we might check min number of keys */
+ reiserfs_warning(NULL,
+ "is_internal: number of key seems wrong: %z",
+ bh);
+ return 0;
+ }
- // one may imagine much more checks
- return 1;
+ used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1);
+ if (used_space != blocksize - blkh_free_space(blkh)) {
+ reiserfs_warning(NULL,
+ "is_internal: free space seems wrong: %z", bh);
+ return 0;
+ }
+ // one may imagine much more checks
+ return 1;
}
-
// make sure that bh contains formatted node of reiserfs tree of
// 'level'-th level
-static int is_tree_node (struct buffer_head * bh, int level)
+static int is_tree_node(struct buffer_head *bh, int level)
{
- if (B_LEVEL (bh) != level) {
- reiserfs_warning (NULL, "is_tree_node: node level %d does not match to the expected one %d",
- B_LEVEL (bh), level);
- return 0;
- }
- if (level == DISK_LEAF_NODE_LEVEL)
- return is_leaf (bh->b_data, bh->b_size, bh);
+ if (B_LEVEL(bh) != level) {
+ reiserfs_warning(NULL,
+ "is_tree_node: node level %d does not match to the expected one %d",
+ B_LEVEL(bh), level);
+ return 0;
+ }
+ if (level == DISK_LEAF_NODE_LEVEL)
+ return is_leaf(bh->b_data, bh->b_size, bh);
- return is_internal (bh->b_data, bh->b_size, bh);
+ return is_internal(bh->b_data, bh->b_size, bh);
}
-
-
#define SEARCH_BY_KEY_READA 16
/* The function is NOT SCHEDULE-SAFE! */
-static void search_by_key_reada (struct super_block * s,
- struct buffer_head **bh,
- unsigned long *b, int num)
+static void search_by_key_reada(struct super_block *s,
+ struct buffer_head **bh,
+ unsigned long *b, int num)
{
- int i,j;
-
- for (i = 0 ; i < num ; i++) {
- bh[i] = sb_getblk (s, b[i]);
- }
- for (j = 0 ; j < i ; j++) {
- /*
- * note, this needs attention if we are getting rid of the BKL
- * you have to make sure the prepared bit isn't set on this buffer
- */
- if (!buffer_uptodate(bh[j]))
- ll_rw_block(READA, 1, bh + j);
- brelse(bh[j]);
- }
+ int i, j;
+
+ for (i = 0; i < num; i++) {
+ bh[i] = sb_getblk(s, b[i]);
+ }
+ for (j = 0; j < i; j++) {
+ /*
+ * note, this needs attention if we are getting rid of the BKL
+ * you have to make sure the prepared bit isn't set on this buffer
+ */
+ if (!buffer_uptodate(bh[j]))
+ ll_rw_block(READA, 1, bh + j);
+ brelse(bh[j]);
+ }
}
/**************************************************************************
@@ -576,194 +602,200 @@ static void search_by_key_reada (struct super_block * s,
correctness of the top of the path but need not be checked for the
correctness of the bottom of the path */
/* The function is NOT SCHEDULE-SAFE! */
-int search_by_key (struct super_block * p_s_sb,
- const struct cpu_key * p_s_key, /* Key to search. */
- struct path * p_s_search_path, /* This structure was
- allocated and initialized
- by the calling
- function. It is filled up
- by this function. */
- int n_stop_level /* How far down the tree to search. To
- stop at leaf level - set to
- DISK_LEAF_NODE_LEVEL */
- ) {
- int n_block_number;
- int expected_level;
- struct buffer_head * p_s_bh;
- struct path_element * p_s_last_element;
- int n_node_level, n_retval;
- int right_neighbor_of_leaf_node;
- int fs_gen;
- struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
- unsigned long reada_blocks[SEARCH_BY_KEY_READA];
- int reada_count = 0;
+int search_by_key(struct super_block *p_s_sb, const struct cpu_key *p_s_key, /* Key to search. */
+ struct path *p_s_search_path, /* This structure was
+ allocated and initialized
+ by the calling
+ function. It is filled up
+ by this function. */
+ int n_stop_level /* How far down the tree to search. To
+ stop at leaf level - set to
+ DISK_LEAF_NODE_LEVEL */
+ )
+{
+ int n_block_number;
+ int expected_level;
+ struct buffer_head *p_s_bh;
+ struct path_element *p_s_last_element;
+ int n_node_level, n_retval;
+ int right_neighbor_of_leaf_node;
+ int fs_gen;
+ struct buffer_head *reada_bh[SEARCH_BY_KEY_READA];
+ unsigned long reada_blocks[SEARCH_BY_KEY_READA];
+ int reada_count = 0;
#ifdef CONFIG_REISERFS_CHECK
- int n_repeat_counter = 0;
+ int n_repeat_counter = 0;
#endif
-
- PROC_INFO_INC( p_s_sb, search_by_key );
-
- /* As we add each node to a path we increase its count. This means that
- we must be careful to release all nodes in a path before we either
- discard the path struct or re-use the path struct, as we do here. */
- decrement_counters_in_path(p_s_search_path);
+ PROC_INFO_INC(p_s_sb, search_by_key);
+
+ /* As we add each node to a path we increase its count. This means that
+ we must be careful to release all nodes in a path before we either
+ discard the path struct or re-use the path struct, as we do here. */
- right_neighbor_of_leaf_node = 0;
+ decrement_counters_in_path(p_s_search_path);
- /* With each iteration of this loop we search through the items in the
- current node, and calculate the next current node(next path element)
- for the next iteration of this loop.. */
- n_block_number = SB_ROOT_BLOCK (p_s_sb);
- expected_level = -1;
- while ( 1 ) {
+ right_neighbor_of_leaf_node = 0;
+
+ /* With each iteration of this loop we search through the items in the
+ current node, and calculate the next current node(next path element)
+ for the next iteration of this loop.. */
+ n_block_number = SB_ROOT_BLOCK(p_s_sb);
+ expected_level = -1;
+ while (1) {
#ifdef CONFIG_REISERFS_CHECK
- if ( !(++n_repeat_counter % 50000) )
- reiserfs_warning (p_s_sb, "PAP-5100: search_by_key: %s:"
- "there were %d iterations of while loop "
- "looking for key %K",
- current->comm, n_repeat_counter, p_s_key);
+ if (!(++n_repeat_counter % 50000))
+ reiserfs_warning(p_s_sb, "PAP-5100: search_by_key: %s:"
+ "there were %d iterations of while loop "
+ "looking for key %K",
+ current->comm, n_repeat_counter,
+ p_s_key);
#endif
- /* prep path to have another element added to it. */
- p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length);
- fs_gen = get_generation (p_s_sb);
-
- /* Read the next tree node, and set the last element in the path to
- have a pointer to it. */
- if ((p_s_bh = p_s_last_element->pe_buffer =
- sb_getblk(p_s_sb, n_block_number)) ) {
- if (!buffer_uptodate(p_s_bh) && reada_count > 1) {
- search_by_key_reada (p_s_sb, reada_bh,
- reada_blocks, reada_count);
- }
- ll_rw_block(READ, 1, &p_s_bh);
- wait_on_buffer(p_s_bh);
- if (!buffer_uptodate(p_s_bh))
- goto io_error;
- } else {
-io_error:
- p_s_search_path->path_length --;
- pathrelse(p_s_search_path);
- return IO_ERROR;
- }
- reada_count = 0;
- if (expected_level == -1)
- expected_level = SB_TREE_HEIGHT (p_s_sb);
- expected_level --;
-
- /* It is possible that schedule occurred. We must check whether the key
- to search is still in the tree rooted from the current buffer. If
- not then repeat search from the root. */
- if ( fs_changed (fs_gen, p_s_sb) &&
- (!B_IS_IN_TREE (p_s_bh) ||
- B_LEVEL(p_s_bh) != expected_level ||
- !key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) {
- PROC_INFO_INC( p_s_sb, search_by_key_fs_changed );
- PROC_INFO_INC( p_s_sb, search_by_key_restarted );
- PROC_INFO_INC( p_s_sb, sbk_restarted[ expected_level - 1 ] );
- decrement_counters_in_path(p_s_search_path);
-
- /* Get the root block number so that we can repeat the search
- starting from the root. */
- n_block_number = SB_ROOT_BLOCK (p_s_sb);
- expected_level = -1;
- right_neighbor_of_leaf_node = 0;
-
- /* repeat search from the root */
- continue;
- }
+ /* prep path to have another element added to it. */
+ p_s_last_element =
+ PATH_OFFSET_PELEMENT(p_s_search_path,
+ ++p_s_search_path->path_length);
+ fs_gen = get_generation(p_s_sb);
+
+ /* Read the next tree node, and set the last element in the path to
+ have a pointer to it. */
+ if ((p_s_bh = p_s_last_element->pe_buffer =
+ sb_getblk(p_s_sb, n_block_number))) {
+ if (!buffer_uptodate(p_s_bh) && reada_count > 1) {
+ search_by_key_reada(p_s_sb, reada_bh,
+ reada_blocks, reada_count);
+ }
+ ll_rw_block(READ, 1, &p_s_bh);
+ wait_on_buffer(p_s_bh);
+ if (!buffer_uptodate(p_s_bh))
+ goto io_error;
+ } else {
+ io_error:
+ p_s_search_path->path_length--;
+ pathrelse(p_s_search_path);
+ return IO_ERROR;
+ }
+ reada_count = 0;
+ if (expected_level == -1)
+ expected_level = SB_TREE_HEIGHT(p_s_sb);
+ expected_level--;
+
+ /* It is possible that schedule occurred. We must check whether the key
+ to search is still in the tree rooted from the current buffer. If
+ not then repeat search from the root. */
+ if (fs_changed(fs_gen, p_s_sb) &&
+ (!B_IS_IN_TREE(p_s_bh) ||
+ B_LEVEL(p_s_bh) != expected_level ||
+ !key_in_buffer(p_s_search_path, p_s_key, p_s_sb))) {
+ PROC_INFO_INC(p_s_sb, search_by_key_fs_changed);
+ PROC_INFO_INC(p_s_sb, search_by_key_restarted);
+ PROC_INFO_INC(p_s_sb,
+ sbk_restarted[expected_level - 1]);
+ decrement_counters_in_path(p_s_search_path);
+
+ /* Get the root block number so that we can repeat the search
+ starting from the root. */
+ n_block_number = SB_ROOT_BLOCK(p_s_sb);
+ expected_level = -1;
+ right_neighbor_of_leaf_node = 0;
+
+ /* repeat search from the root */
+ continue;
+ }
- /* only check that the key is in the buffer if p_s_key is not
- equal to the MAX_KEY. Latter case is only possible in
- "finish_unfinished()" processing during mount. */
- RFALSE( comp_keys( &MAX_KEY, p_s_key ) &&
- ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
- "PAP-5130: key is not in the buffer");
+ /* only check that the key is in the buffer if p_s_key is not
+ equal to the MAX_KEY. Latter case is only possible in
+ "finish_unfinished()" processing during mount. */
+ RFALSE(comp_keys(&MAX_KEY, p_s_key) &&
+ !key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
+ "PAP-5130: key is not in the buffer");
#ifdef CONFIG_REISERFS_CHECK
- if ( cur_tb ) {
- print_cur_tb ("5140");
- reiserfs_panic(p_s_sb, "PAP-5140: search_by_key: schedule occurred in do_balance!");
- }
+ if (cur_tb) {
+ print_cur_tb("5140");
+ reiserfs_panic(p_s_sb,
+ "PAP-5140: search_by_key: schedule occurred in do_balance!");
+ }
#endif
- // make sure, that the node contents look like a node of
- // certain level
- if (!is_tree_node (p_s_bh, expected_level)) {
- reiserfs_warning (p_s_sb, "vs-5150: search_by_key: "
- "invalid format found in block %ld. Fsck?",
- p_s_bh->b_blocknr);
- pathrelse (p_s_search_path);
- return IO_ERROR;
- }
-
- /* ok, we have acquired next formatted node in the tree */
- n_node_level = B_LEVEL (p_s_bh);
-
- PROC_INFO_BH_STAT( p_s_sb, p_s_bh, n_node_level - 1 );
-
- RFALSE( n_node_level < n_stop_level,
- "vs-5152: tree level (%d) is less than stop level (%d)",
- n_node_level, n_stop_level);
-
- n_retval = bin_search( p_s_key, B_N_PITEM_HEAD(p_s_bh, 0),
- B_NR_ITEMS(p_s_bh),
- ( n_node_level == DISK_LEAF_NODE_LEVEL ) ? IH_SIZE : KEY_SIZE,
- &(p_s_last_element->pe_position));
- if (n_node_level == n_stop_level) {
- return n_retval;
- }
+ // make sure, that the node contents look like a node of
+ // certain level
+ if (!is_tree_node(p_s_bh, expected_level)) {
+ reiserfs_warning(p_s_sb, "vs-5150: search_by_key: "
+ "invalid format found in block %ld. Fsck?",
+ p_s_bh->b_blocknr);
+ pathrelse(p_s_search_path);
+ return IO_ERROR;
+ }
- /* we are not in the stop level */
- if (n_retval == ITEM_FOUND)
- /* item has been found, so we choose the pointer which is to the right of the found one */
- p_s_last_element->pe_position++;
+ /* ok, we have acquired next formatted node in the tree */
+ n_node_level = B_LEVEL(p_s_bh);
- /* if item was not found we choose the position which is to
- the left of the found item. This requires no code,
- bin_search did it already.*/
+ PROC_INFO_BH_STAT(p_s_sb, p_s_bh, n_node_level - 1);
- /* So we have chosen a position in the current node which is
- an internal node. Now we calculate child block number by
- position in the node. */
- n_block_number = B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
+ RFALSE(n_node_level < n_stop_level,
+ "vs-5152: tree level (%d) is less than stop level (%d)",
+ n_node_level, n_stop_level);
- /* if we are going to read leaf nodes, try for read ahead as well */
- if ((p_s_search_path->reada & PATH_READA) &&
- n_node_level == DISK_LEAF_NODE_LEVEL + 1)
- {
- int pos = p_s_last_element->pe_position;
- int limit = B_NR_ITEMS(p_s_bh);
- struct reiserfs_key *le_key;
-
- if (p_s_search_path->reada & PATH_READA_BACK)
- limit = 0;
- while(reada_count < SEARCH_BY_KEY_READA) {
- if (pos == limit)
- break;
- reada_blocks[reada_count++] = B_N_CHILD_NUM(p_s_bh, pos);
- if (p_s_search_path->reada & PATH_READA_BACK)
- pos--;
- else
- pos++;
+ n_retval = bin_search(p_s_key, B_N_PITEM_HEAD(p_s_bh, 0),
+ B_NR_ITEMS(p_s_bh),
+ (n_node_level ==
+ DISK_LEAF_NODE_LEVEL) ? IH_SIZE :
+ KEY_SIZE,
+ &(p_s_last_element->pe_position));
+ if (n_node_level == n_stop_level) {
+ return n_retval;
+ }
- /*
- * check to make sure we're in the same object
- */
- le_key = B_N_PDELIM_KEY(p_s_bh, pos);
- if (le32_to_cpu(le_key->k_objectid) !=
- p_s_key->on_disk_key.k_objectid)
- {
- break;
+ /* we are not in the stop level */
+ if (n_retval == ITEM_FOUND)
+ /* item has been found, so we choose the pointer which is to the right of the found one */
+ p_s_last_element->pe_position++;
+
+ /* if item was not found we choose the position which is to
+ the left of the found item. This requires no code,
+ bin_search did it already. */
+
+ /* So we have chosen a position in the current node which is
+ an internal node. Now we calculate child block number by
+ position in the node. */
+ n_block_number =
+ B_N_CHILD_NUM(p_s_bh, p_s_last_element->pe_position);
+
+ /* if we are going to read leaf nodes, try for read ahead as well */
+ if ((p_s_search_path->reada & PATH_READA) &&
+ n_node_level == DISK_LEAF_NODE_LEVEL + 1) {
+ int pos = p_s_last_element->pe_position;
+ int limit = B_NR_ITEMS(p_s_bh);
+ struct reiserfs_key *le_key;
+
+ if (p_s_search_path->reada & PATH_READA_BACK)
+ limit = 0;
+ while (reada_count < SEARCH_BY_KEY_READA) {
+ if (pos == limit)
+ break;
+ reada_blocks[reada_count++] =
+ B_N_CHILD_NUM(p_s_bh, pos);
+ if (p_s_search_path->reada & PATH_READA_BACK)
+ pos--;
+ else
+ pos++;
+
+ /*
+ * check to make sure we're in the same object
+ */
+ le_key = B_N_PDELIM_KEY(p_s_bh, pos);
+ if (le32_to_cpu(le_key->k_objectid) !=
+ p_s_key->on_disk_key.k_objectid) {
+ break;
+ }
+ }
}
- }
- }
- }
+ }
}
-
/* Form the path to an item and position in this item which contains
file byte defined by p_s_key. If there is no such item
corresponding to the key, we point the path to the item with
@@ -780,94 +812,97 @@ io_error:
units of directory entries. */
/* The function is NOT SCHEDULE-SAFE! */
-int search_for_position_by_key (struct super_block * p_s_sb, /* Pointer to the super block. */
- const struct cpu_key * p_cpu_key, /* Key to search (cpu variable) */
- struct path * p_s_search_path /* Filled up by this function. */
- ) {
- struct item_head * p_le_ih; /* pointer to on-disk structure */
- int n_blk_size;
- loff_t item_offset, offset;
- struct reiserfs_dir_entry de;
- int retval;
-
- /* If searching for directory entry. */
- if ( is_direntry_cpu_key (p_cpu_key) )
- return search_by_entry_key (p_s_sb, p_cpu_key, p_s_search_path, &de);
-
- /* If not searching for directory entry. */
-
- /* If item is found. */
- retval = search_item (p_s_sb, p_cpu_key, p_s_search_path);
- if (retval == IO_ERROR)
- return retval;
- if ( retval == ITEM_FOUND ) {
-
- RFALSE( ! ih_item_len(
- B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path),
- PATH_LAST_POSITION(p_s_search_path))),
- "PAP-5165: item length equals zero");
+int search_for_position_by_key(struct super_block *p_s_sb, /* Pointer to the super block. */
+ const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */
+ struct path *p_s_search_path /* Filled up by this function. */
+ )
+{
+ struct item_head *p_le_ih; /* pointer to on-disk structure */
+ int n_blk_size;
+ loff_t item_offset, offset;
+ struct reiserfs_dir_entry de;
+ int retval;
+
+ /* If searching for directory entry. */
+ if (is_direntry_cpu_key(p_cpu_key))
+ return search_by_entry_key(p_s_sb, p_cpu_key, p_s_search_path,
+ &de);
+
+ /* If not searching for directory entry. */
+
+ /* If item is found. */
+ retval = search_item(p_s_sb, p_cpu_key, p_s_search_path);
+ if (retval == IO_ERROR)
+ return retval;
+ if (retval == ITEM_FOUND) {
- pos_in_item(p_s_search_path) = 0;
- return POSITION_FOUND;
- }
+ RFALSE(!ih_item_len
+ (B_N_PITEM_HEAD
+ (PATH_PLAST_BUFFER(p_s_search_path),
+ PATH_LAST_POSITION(p_s_search_path))),
+ "PAP-5165: item length equals zero");
- RFALSE( ! PATH_LAST_POSITION(p_s_search_path),
- "PAP-5170: position equals zero");
+ pos_in_item(p_s_search_path) = 0;
+ return POSITION_FOUND;
+ }
- /* Item is not found. Set path to the previous item. */
- p_le_ih = B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path), --PATH_LAST_POSITION(p_s_search_path));
- n_blk_size = p_s_sb->s_blocksize;
+ RFALSE(!PATH_LAST_POSITION(p_s_search_path),
+ "PAP-5170: position equals zero");
- if (comp_short_keys (&(p_le_ih->ih_key), p_cpu_key)) {
- return FILE_NOT_FOUND;
- }
+ /* Item is not found. Set path to the previous item. */
+ p_le_ih =
+ B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path),
+ --PATH_LAST_POSITION(p_s_search_path));
+ n_blk_size = p_s_sb->s_blocksize;
- // FIXME: quite ugly this far
+ if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) {
+ return FILE_NOT_FOUND;
+ }
+ // FIXME: quite ugly this far
- item_offset = le_ih_k_offset (p_le_ih);
- offset = cpu_key_k_offset (p_cpu_key);
+ item_offset = le_ih_k_offset(p_le_ih);
+ offset = cpu_key_k_offset(p_cpu_key);
- /* Needed byte is contained in the item pointed to by the path.*/
- if (item_offset <= offset &&
- item_offset + op_bytes_number (p_le_ih, n_blk_size) > offset) {
- pos_in_item (p_s_search_path) = offset - item_offset;
- if ( is_indirect_le_ih(p_le_ih) ) {
- pos_in_item (p_s_search_path) /= n_blk_size;
+ /* Needed byte is contained in the item pointed to by the path. */
+ if (item_offset <= offset &&
+ item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) {
+ pos_in_item(p_s_search_path) = offset - item_offset;
+ if (is_indirect_le_ih(p_le_ih)) {
+ pos_in_item(p_s_search_path) /= n_blk_size;
+ }
+ return POSITION_FOUND;
}
- return POSITION_FOUND;
- }
-
- /* Needed byte is not contained in the item pointed to by the
- path. Set pos_in_item out of the item. */
- if ( is_indirect_le_ih (p_le_ih) )
- pos_in_item (p_s_search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE;
- else
- pos_in_item (p_s_search_path) = ih_item_len( p_le_ih );
-
- return POSITION_NOT_FOUND;
-}
+ /* Needed byte is not contained in the item pointed to by the
+ path. Set pos_in_item out of the item. */
+ if (is_indirect_le_ih(p_le_ih))
+ pos_in_item(p_s_search_path) =
+ ih_item_len(p_le_ih) / UNFM_P_SIZE;
+ else
+ pos_in_item(p_s_search_path) = ih_item_len(p_le_ih);
+
+ return POSITION_NOT_FOUND;
+}
/* Compare given item and item pointed to by the path. */
-int comp_items (const struct item_head * stored_ih, const struct path * p_s_path)
+int comp_items(const struct item_head *stored_ih, const struct path *p_s_path)
{
- struct buffer_head * p_s_bh;
- struct item_head * ih;
+ struct buffer_head *p_s_bh;
+ struct item_head *ih;
- /* Last buffer at the path is not in the tree. */
- if ( ! B_IS_IN_TREE(p_s_bh = PATH_PLAST_BUFFER(p_s_path)) )
- return 1;
+ /* Last buffer at the path is not in the tree. */
+ if (!B_IS_IN_TREE(p_s_bh = PATH_PLAST_BUFFER(p_s_path)))
+ return 1;
- /* Last path position is invalid. */
- if ( PATH_LAST_POSITION(p_s_path) >= B_NR_ITEMS(p_s_bh) )
- return 1;
+ /* Last path position is invalid. */
+ if (PATH_LAST_POSITION(p_s_path) >= B_NR_ITEMS(p_s_bh))
+ return 1;
- /* we need only to know, whether it is the same item */
- ih = get_ih (p_s_path);
- return memcmp (stored_ih, ih, IH_SIZE);
+ /* we need only to know, whether it is the same item */
+ ih = get_ih(p_s_path);
+ return memcmp(stored_ih, ih, IH_SIZE);
}
-
/* unformatted nodes are not logged anymore, ever. This is safe
** now
*/
@@ -876,461 +911,466 @@ int comp_items (const struct item_head * stored_ih, const struct path * p_s_path
// block can not be forgotten as it is in I/O or held by someone
#define block_in_use(bh) (buffer_locked(bh) || (held_by_others(bh)))
-
-
// prepare for delete or cut of direct item
-static inline int prepare_for_direct_item (struct path * path,
- struct item_head * le_ih,
- struct inode * inode,
- loff_t new_file_length,
- int * cut_size)
+static inline int prepare_for_direct_item(struct path *path,
+ struct item_head *le_ih,
+ struct inode *inode,
+ loff_t new_file_length, int *cut_size)
{
- loff_t round_len;
-
-
- if ( new_file_length == max_reiserfs_offset (inode) ) {
- /* item has to be deleted */
- *cut_size = -(IH_SIZE + ih_item_len(le_ih));
- return M_DELETE;
- }
-
- // new file gets truncated
- if (get_inode_item_key_version (inode) == KEY_FORMAT_3_6) {
- //
- round_len = ROUND_UP (new_file_length);
- /* this was n_new_file_length < le_ih ... */
- if ( round_len < le_ih_k_offset (le_ih) ) {
- *cut_size = -(IH_SIZE + ih_item_len(le_ih));
- return M_DELETE; /* Delete this item. */
+ loff_t round_len;
+
+ if (new_file_length == max_reiserfs_offset(inode)) {
+ /* item has to be deleted */
+ *cut_size = -(IH_SIZE + ih_item_len(le_ih));
+ return M_DELETE;
+ }
+ // new file gets truncated
+ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_6) {
+ //
+ round_len = ROUND_UP(new_file_length);
+ /* this was n_new_file_length < le_ih ... */
+ if (round_len < le_ih_k_offset(le_ih)) {
+ *cut_size = -(IH_SIZE + ih_item_len(le_ih));
+ return M_DELETE; /* Delete this item. */
+ }
+ /* Calculate first position and size for cutting from item. */
+ pos_in_item(path) = round_len - (le_ih_k_offset(le_ih) - 1);
+ *cut_size = -(ih_item_len(le_ih) - pos_in_item(path));
+
+ return M_CUT; /* Cut from this item. */
+ }
+
+ // old file: items may have any length
+
+ if (new_file_length < le_ih_k_offset(le_ih)) {
+ *cut_size = -(IH_SIZE + ih_item_len(le_ih));
+ return M_DELETE; /* Delete this item. */
}
/* Calculate first position and size for cutting from item. */
- pos_in_item (path) = round_len - (le_ih_k_offset (le_ih) - 1);
- *cut_size = -(ih_item_len(le_ih) - pos_in_item(path));
-
- return M_CUT; /* Cut from this item. */
- }
-
-
- // old file: items may have any length
-
- if ( new_file_length < le_ih_k_offset (le_ih) ) {
- *cut_size = -(IH_SIZE + ih_item_len(le_ih));
- return M_DELETE; /* Delete this item. */
- }
- /* Calculate first position and size for cutting from item. */
- *cut_size = -(ih_item_len(le_ih) -
- (pos_in_item (path) = new_file_length + 1 - le_ih_k_offset (le_ih)));
- return M_CUT; /* Cut from this item. */
+ *cut_size = -(ih_item_len(le_ih) -
+ (pos_in_item(path) =
+ new_file_length + 1 - le_ih_k_offset(le_ih)));
+ return M_CUT; /* Cut from this item. */
}
-
-static inline int prepare_for_direntry_item (struct path * path,
- struct item_head * le_ih,
- struct inode * inode,
- loff_t new_file_length,
- int * cut_size)
+static inline int prepare_for_direntry_item(struct path *path,
+ struct item_head *le_ih,
+ struct inode *inode,
+ loff_t new_file_length,
+ int *cut_size)
{
- if (le_ih_k_offset (le_ih) == DOT_OFFSET &&
- new_file_length == max_reiserfs_offset (inode)) {
- RFALSE( ih_entry_count (le_ih) != 2,
- "PAP-5220: incorrect empty directory item (%h)", le_ih);
- *cut_size = -(IH_SIZE + ih_item_len(le_ih));
- return M_DELETE; /* Delete the directory item containing "." and ".." entry. */
- }
-
- if ( ih_entry_count (le_ih) == 1 ) {
- /* Delete the directory item such as there is one record only
- in this item*/
- *cut_size = -(IH_SIZE + ih_item_len(le_ih));
- return M_DELETE;
- }
-
- /* Cut one record from the directory item. */
- *cut_size = -(DEH_SIZE + entry_length (get_last_bh (path), le_ih, pos_in_item (path)));
- return M_CUT;
-}
+ if (le_ih_k_offset(le_ih) == DOT_OFFSET &&
+ new_file_length == max_reiserfs_offset(inode)) {
+ RFALSE(ih_entry_count(le_ih) != 2,
+ "PAP-5220: incorrect empty directory item (%h)", le_ih);
+ *cut_size = -(IH_SIZE + ih_item_len(le_ih));
+ return M_DELETE; /* Delete the directory item containing "." and ".." entry. */
+ }
+ if (ih_entry_count(le_ih) == 1) {
+ /* Delete the directory item such as there is one record only
+ in this item */
+ *cut_size = -(IH_SIZE + ih_item_len(le_ih));
+ return M_DELETE;
+ }
+
+ /* Cut one record from the directory item. */
+ *cut_size =
+ -(DEH_SIZE +
+ entry_length(get_last_bh(path), le_ih, pos_in_item(path)));
+ return M_CUT;
+}
/* If the path points to a directory or direct item, calculate mode and the size cut, for balance.
If the path points to an indirect item, remove some number of its unformatted nodes.
In case of file truncate calculate whether this item must be deleted/truncated or last
unformatted node of this item will be converted to a direct item.
This function returns a determination of what balance mode the calling function should employ. */
-static char prepare_for_delete_or_cut(
- struct reiserfs_transaction_handle *th,
- struct inode * inode,
- struct path * p_s_path,
- const struct cpu_key * p_s_item_key,
- int * p_n_removed, /* Number of unformatted nodes which were removed
- from end of the file. */
- int * p_n_cut_size,
- unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */
- ) {
- struct super_block * p_s_sb = inode->i_sb;
- struct item_head * p_le_ih = PATH_PITEM_HEAD(p_s_path);
- struct buffer_head * p_s_bh = PATH_PLAST_BUFFER(p_s_path);
-
- BUG_ON (!th->t_trans_id);
-
- /* Stat_data item. */
- if ( is_statdata_le_ih (p_le_ih) ) {
-
- RFALSE( n_new_file_length != max_reiserfs_offset (inode),
- "PAP-5210: mode must be M_DELETE");
-
- *p_n_cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
- return M_DELETE;
- }
-
-
- /* Directory item. */
- if ( is_direntry_le_ih (p_le_ih) )
- return prepare_for_direntry_item (p_s_path, p_le_ih, inode, n_new_file_length, p_n_cut_size);
-
- /* Direct item. */
- if ( is_direct_le_ih (p_le_ih) )
- return prepare_for_direct_item (p_s_path, p_le_ih, inode, n_new_file_length, p_n_cut_size);
-
-
- /* Case of an indirect item. */
- {
- int n_unfm_number, /* Number of the item unformatted nodes. */
- n_counter,
- n_blk_size;
- __le32 * p_n_unfm_pointer; /* Pointer to the unformatted node number. */
- __u32 tmp;
- struct item_head s_ih; /* Item header. */
- char c_mode; /* Returned mode of the balance. */
- int need_research;
+static char prepare_for_delete_or_cut(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *p_s_path, const struct cpu_key *p_s_item_key, int *p_n_removed, /* Number of unformatted nodes which were removed
+ from end of the file. */
+ int *p_n_cut_size, unsigned long long n_new_file_length /* MAX_KEY_OFFSET in case of delete. */
+ )
+{
+ struct super_block *p_s_sb = inode->i_sb;
+ struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_path);
+ struct buffer_head *p_s_bh = PATH_PLAST_BUFFER(p_s_path);
+ BUG_ON(!th->t_trans_id);
- n_blk_size = p_s_sb->s_blocksize;
+ /* Stat_data item. */
+ if (is_statdata_le_ih(p_le_ih)) {
- /* Search for the needed object indirect item until there are no unformatted nodes to be removed. */
- do {
- need_research = 0;
- p_s_bh = PATH_PLAST_BUFFER(p_s_path);
- /* Copy indirect item header to a temp variable. */
- copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
- /* Calculate number of unformatted nodes in this item. */
- n_unfm_number = I_UNFM_NUM(&s_ih);
-
- RFALSE( ! is_indirect_le_ih(&s_ih) || ! n_unfm_number ||
- pos_in_item (p_s_path) + 1 != n_unfm_number,
- "PAP-5240: invalid item %h "
- "n_unfm_number = %d *p_n_pos_in_item = %d",
- &s_ih, n_unfm_number, pos_in_item (p_s_path));
-
- /* Calculate balance mode and position in the item to remove unformatted nodes. */
- if ( n_new_file_length == max_reiserfs_offset (inode) ) {/* Case of delete. */
- pos_in_item (p_s_path) = 0;
- *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
- c_mode = M_DELETE;
- }
- else { /* Case of truncate. */
- if ( n_new_file_length < le_ih_k_offset (&s_ih) ) {
- pos_in_item (p_s_path) = 0;
- *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
- c_mode = M_DELETE; /* Delete this item. */
- }
- else {
- /* indirect item must be truncated starting from *p_n_pos_in_item-th position */
- pos_in_item (p_s_path) = (n_new_file_length + n_blk_size - le_ih_k_offset (&s_ih) ) >> p_s_sb->s_blocksize_bits;
-
- RFALSE( pos_in_item (p_s_path) > n_unfm_number,
- "PAP-5250: invalid position in the item");
-
- /* Either convert last unformatted node of indirect item to direct item or increase
- its free space. */
- if ( pos_in_item (p_s_path) == n_unfm_number ) {
- *p_n_cut_size = 0; /* Nothing to cut. */
- return M_CONVERT; /* Maybe convert last unformatted node to the direct item. */
- }
- /* Calculate size to cut. */
- *p_n_cut_size = -(ih_item_len(&s_ih) - pos_in_item(p_s_path) * UNFM_P_SIZE);
-
- c_mode = M_CUT; /* Cut from this indirect item. */
- }
- }
-
- RFALSE( n_unfm_number <= pos_in_item (p_s_path),
- "PAP-5260: invalid position in the indirect item");
-
- /* pointers to be cut */
- n_unfm_number -= pos_in_item (p_s_path);
- /* Set pointer to the last unformatted node pointer that is to be cut. */
- p_n_unfm_pointer = (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1 - *p_n_removed;
-
-
- /* We go through the unformatted nodes pointers of the indirect
- item and look for the unformatted nodes in the cache. If we
- found some of them we free it, zero corresponding indirect item
- entry and log buffer containing that indirect item. For this we
- need to prepare last path element for logging. If some
- unformatted node has b_count > 1 we must not free this
- unformatted node since it is in use. */
- reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
- // note: path could be changed, first line in for loop takes care
- // of it
-
- for (n_counter = *p_n_removed;
- n_counter < n_unfm_number; n_counter++, p_n_unfm_pointer-- ) {
-
- cond_resched();
- if (item_moved (&s_ih, p_s_path)) {
- need_research = 1 ;
- break;
- }
- RFALSE( p_n_unfm_pointer < (__le32 *)B_I_PITEM(p_s_bh, &s_ih) ||
- p_n_unfm_pointer > (__le32 *)B_I_PITEM(p_s_bh, &s_ih) + I_UNFM_NUM(&s_ih) - 1,
- "vs-5265: pointer out of range");
+ RFALSE(n_new_file_length != max_reiserfs_offset(inode),
+ "PAP-5210: mode must be M_DELETE");
- /* Hole, nothing to remove. */
- if ( ! get_block_num(p_n_unfm_pointer,0) ) {
- (*p_n_removed)++;
- continue;
- }
+ *p_n_cut_size = -(IH_SIZE + ih_item_len(p_le_ih));
+ return M_DELETE;
+ }
- (*p_n_removed)++;
+ /* Directory item. */
+ if (is_direntry_le_ih(p_le_ih))
+ return prepare_for_direntry_item(p_s_path, p_le_ih, inode,
+ n_new_file_length,
+ p_n_cut_size);
- tmp = get_block_num(p_n_unfm_pointer,0);
- put_block_num(p_n_unfm_pointer, 0, 0);
- journal_mark_dirty (th, p_s_sb, p_s_bh);
- reiserfs_free_block(th, inode, tmp, 1);
- if ( item_moved (&s_ih, p_s_path) ) {
- need_research = 1;
- break ;
- }
- }
-
- /* a trick. If the buffer has been logged, this
- ** will do nothing. If we've broken the loop without
- ** logging it, it will restore the buffer
- **
- */
- reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
-
- /* This loop can be optimized. */
- } while ( (*p_n_removed < n_unfm_number || need_research) &&
- search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_FOUND );
-
- RFALSE( *p_n_removed < n_unfm_number,
- "PAP-5310: indirect item is not found");
- RFALSE( item_moved (&s_ih, p_s_path),
- "after while, comp failed, retry") ;
-
- if (c_mode == M_CUT)
- pos_in_item (p_s_path) *= UNFM_P_SIZE;
- return c_mode;
- }
+ /* Direct item. */
+ if (is_direct_le_ih(p_le_ih))
+ return prepare_for_direct_item(p_s_path, p_le_ih, inode,
+ n_new_file_length, p_n_cut_size);
+
+ /* Case of an indirect item. */
+ {
+ int n_unfm_number, /* Number of the item unformatted nodes. */
+ n_counter, n_blk_size;
+ __le32 *p_n_unfm_pointer; /* Pointer to the unformatted node number. */
+ __u32 tmp;
+ struct item_head s_ih; /* Item header. */
+ char c_mode; /* Returned mode of the balance. */
+ int need_research;
+
+ n_blk_size = p_s_sb->s_blocksize;
+
+ /* Search for the needed object indirect item until there are no unformatted nodes to be removed. */
+ do {
+ need_research = 0;
+ p_s_bh = PATH_PLAST_BUFFER(p_s_path);
+ /* Copy indirect item header to a temp variable. */
+ copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+ /* Calculate number of unformatted nodes in this item. */
+ n_unfm_number = I_UNFM_NUM(&s_ih);
+
+ RFALSE(!is_indirect_le_ih(&s_ih) || !n_unfm_number ||
+ pos_in_item(p_s_path) + 1 != n_unfm_number,
+ "PAP-5240: invalid item %h "
+ "n_unfm_number = %d *p_n_pos_in_item = %d",
+ &s_ih, n_unfm_number, pos_in_item(p_s_path));
+
+ /* Calculate balance mode and position in the item to remove unformatted nodes. */
+ if (n_new_file_length == max_reiserfs_offset(inode)) { /* Case of delete. */
+ pos_in_item(p_s_path) = 0;
+ *p_n_cut_size = -(IH_SIZE + ih_item_len(&s_ih));
+ c_mode = M_DELETE;
+ } else { /* Case of truncate. */
+ if (n_new_file_length < le_ih_k_offset(&s_ih)) {
+ pos_in_item(p_s_path) = 0;
+ *p_n_cut_size =
+ -(IH_SIZE + ih_item_len(&s_ih));
+ c_mode = M_DELETE; /* Delete this item. */
+ } else {
+ /* indirect item must be truncated starting from *p_n_pos_in_item-th position */
+ pos_in_item(p_s_path) =
+ (n_new_file_length + n_blk_size -
+ le_ih_k_offset(&s_ih)) >> p_s_sb->
+ s_blocksize_bits;
+
+ RFALSE(pos_in_item(p_s_path) >
+ n_unfm_number,
+ "PAP-5250: invalid position in the item");
+
+ /* Either convert last unformatted node of indirect item to direct item or increase
+ its free space. */
+ if (pos_in_item(p_s_path) ==
+ n_unfm_number) {
+ *p_n_cut_size = 0; /* Nothing to cut. */
+ return M_CONVERT; /* Maybe convert last unformatted node to the direct item. */
+ }
+ /* Calculate size to cut. */
+ *p_n_cut_size =
+ -(ih_item_len(&s_ih) -
+ pos_in_item(p_s_path) *
+ UNFM_P_SIZE);
+
+ c_mode = M_CUT; /* Cut from this indirect item. */
+ }
+ }
+
+ RFALSE(n_unfm_number <= pos_in_item(p_s_path),
+ "PAP-5260: invalid position in the indirect item");
+
+ /* pointers to be cut */
+ n_unfm_number -= pos_in_item(p_s_path);
+ /* Set pointer to the last unformatted node pointer that is to be cut. */
+ p_n_unfm_pointer =
+ (__le32 *) B_I_PITEM(p_s_bh,
+ &s_ih) + I_UNFM_NUM(&s_ih) -
+ 1 - *p_n_removed;
+
+ /* We go through the unformatted nodes pointers of the indirect
+ item and look for the unformatted nodes in the cache. If we
+ found some of them we free it, zero corresponding indirect item
+ entry and log buffer containing that indirect item. For this we
+ need to prepare last path element for logging. If some
+ unformatted node has b_count > 1 we must not free this
+ unformatted node since it is in use. */
+ reiserfs_prepare_for_journal(p_s_sb, p_s_bh, 1);
+ // note: path could be changed, first line in for loop takes care
+ // of it
+
+ for (n_counter = *p_n_removed;
+ n_counter < n_unfm_number;
+ n_counter++, p_n_unfm_pointer--) {
+
+ cond_resched();
+ if (item_moved(&s_ih, p_s_path)) {
+ need_research = 1;
+ break;
+ }
+ RFALSE(p_n_unfm_pointer <
+ (__le32 *) B_I_PITEM(p_s_bh, &s_ih)
+ || p_n_unfm_pointer >
+ (__le32 *) B_I_PITEM(p_s_bh,
+ &s_ih) +
+ I_UNFM_NUM(&s_ih) - 1,
+ "vs-5265: pointer out of range");
+
+ /* Hole, nothing to remove. */
+ if (!get_block_num(p_n_unfm_pointer, 0)) {
+ (*p_n_removed)++;
+ continue;
+ }
+
+ (*p_n_removed)++;
+
+ tmp = get_block_num(p_n_unfm_pointer, 0);
+ put_block_num(p_n_unfm_pointer, 0, 0);
+ journal_mark_dirty(th, p_s_sb, p_s_bh);
+ reiserfs_free_block(th, inode, tmp, 1);
+ if (item_moved(&s_ih, p_s_path)) {
+ need_research = 1;
+ break;
+ }
+ }
+
+ /* a trick. If the buffer has been logged, this
+ ** will do nothing. If we've broken the loop without
+ ** logging it, it will restore the buffer
+ **
+ */
+ reiserfs_restore_prepared_buffer(p_s_sb, p_s_bh);
+
+ /* This loop can be optimized. */
+ } while ((*p_n_removed < n_unfm_number || need_research) &&
+ search_for_position_by_key(p_s_sb, p_s_item_key,
+ p_s_path) ==
+ POSITION_FOUND);
+
+ RFALSE(*p_n_removed < n_unfm_number,
+ "PAP-5310: indirect item is not found");
+ RFALSE(item_moved(&s_ih, p_s_path),
+ "after while, comp failed, retry");
+
+ if (c_mode == M_CUT)
+ pos_in_item(p_s_path) *= UNFM_P_SIZE;
+ return c_mode;
+ }
}
/* Calculate number of bytes which will be deleted or cut during balance */
-static int calc_deleted_bytes_number(
- struct tree_balance * p_s_tb,
- char c_mode
- ) {
- int n_del_size;
- struct item_head * p_le_ih = PATH_PITEM_HEAD(p_s_tb->tb_path);
-
- if ( is_statdata_le_ih (p_le_ih) )
- return 0;
+static int calc_deleted_bytes_number(struct tree_balance *p_s_tb, char c_mode)
+{
+ int n_del_size;
+ struct item_head *p_le_ih = PATH_PITEM_HEAD(p_s_tb->tb_path);
+
+ if (is_statdata_le_ih(p_le_ih))
+ return 0;
+
+ n_del_size =
+ (c_mode ==
+ M_DELETE) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
+ if (is_direntry_le_ih(p_le_ih)) {
+ // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */
+ // we can't use EMPTY_DIR_SIZE, as old format dirs have a different
+ // empty size. ick. FIXME, is this right?
+ //
+ return n_del_size;
+ }
- n_del_size = ( c_mode == M_DELETE ) ? ih_item_len(p_le_ih) : -p_s_tb->insert_size[0];
- if ( is_direntry_le_ih (p_le_ih) ) {
- // return EMPTY_DIR_SIZE; /* We delete emty directoris only. */
- // we can't use EMPTY_DIR_SIZE, as old format dirs have a different
- // empty size. ick. FIXME, is this right?
- //
- return n_del_size ;
- }
-
- if ( is_indirect_le_ih (p_le_ih) )
- n_del_size = (n_del_size/UNFM_P_SIZE)*
- (PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_size);// - get_ih_free_space (p_le_ih);
- return n_del_size;
+ if (is_indirect_le_ih(p_le_ih))
+ n_del_size = (n_del_size / UNFM_P_SIZE) * (PATH_PLAST_BUFFER(p_s_tb->tb_path)->b_size); // - get_ih_free_space (p_le_ih);
+ return n_del_size;
}
-static void init_tb_struct(
- struct reiserfs_transaction_handle *th,
- struct tree_balance * p_s_tb,
- struct super_block * p_s_sb,
- struct path * p_s_path,
- int n_size
- ) {
-
- BUG_ON (!th->t_trans_id);
-
- memset (p_s_tb,'\0',sizeof(struct tree_balance));
- p_s_tb->transaction_handle = th ;
- p_s_tb->tb_sb = p_s_sb;
- p_s_tb->tb_path = p_s_path;
- PATH_OFFSET_PBUFFER(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
- PATH_OFFSET_POSITION(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
- p_s_tb->insert_size[0] = n_size;
-}
+static void init_tb_struct(struct reiserfs_transaction_handle *th,
+ struct tree_balance *p_s_tb,
+ struct super_block *p_s_sb,
+ struct path *p_s_path, int n_size)
+{
+ BUG_ON(!th->t_trans_id);
+ memset(p_s_tb, '\0', sizeof(struct tree_balance));
+ p_s_tb->transaction_handle = th;
+ p_s_tb->tb_sb = p_s_sb;
+ p_s_tb->tb_path = p_s_path;
+ PATH_OFFSET_PBUFFER(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = NULL;
+ PATH_OFFSET_POSITION(p_s_path, ILLEGAL_PATH_ELEMENT_OFFSET) = 0;
+ p_s_tb->insert_size[0] = n_size;
+}
-void padd_item (char * item, int total_length, int length)
+void padd_item(char *item, int total_length, int length)
{
- int i;
+ int i;
- for (i = total_length; i > length; )
- item [--i] = 0;
+ for (i = total_length; i > length;)
+ item[--i] = 0;
}
#ifdef REISERQUOTA_DEBUG
char key2type(struct reiserfs_key *ih)
{
- if (is_direntry_le_key(2, ih))
- return 'd';
- if (is_direct_le_key(2, ih))
- return 'D';
- if (is_indirect_le_key(2, ih))
- return 'i';
- if (is_statdata_le_key(2, ih))
- return 's';
- return 'u';
+ if (is_direntry_le_key(2, ih))
+ return 'd';
+ if (is_direct_le_key(2, ih))
+ return 'D';
+ if (is_indirect_le_key(2, ih))
+ return 'i';
+ if (is_statdata_le_key(2, ih))
+ return 's';
+ return 'u';
}
char head2type(struct item_head *ih)
{
- if (is_direntry_le_ih(ih))
- return 'd';
- if (is_direct_le_ih(ih))
- return 'D';
- if (is_indirect_le_ih(ih))
- return 'i';
- if (is_statdata_le_ih(ih))
- return 's';
- return 'u';
+ if (is_direntry_le_ih(ih))
+ return 'd';
+ if (is_direct_le_ih(ih))
+ return 'D';
+ if (is_indirect_le_ih(ih))
+ return 'i';
+ if (is_statdata_le_ih(ih))
+ return 's';
+ return 'u';
}
#endif
/* Delete object item. */
-int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
- struct path * p_s_path, /* Path to the deleted item. */
- const struct cpu_key * p_s_item_key, /* Key to search for the deleted item. */
- struct inode * p_s_inode,/* inode is here just to update i_blocks and quotas */
- struct buffer_head * p_s_un_bh) /* NULL or unformatted node pointer. */
-{
- struct super_block * p_s_sb = p_s_inode->i_sb;
- struct tree_balance s_del_balance;
- struct item_head s_ih;
- struct item_head *q_ih;
- int quota_cut_bytes;
- int n_ret_value,
- n_del_size,
- n_removed;
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the deleted item. */
+ const struct cpu_key *p_s_item_key, /* Key to search for the deleted item. */
+ struct inode *p_s_inode, /* inode is here just to update i_blocks and quotas */
+ struct buffer_head *p_s_un_bh)
+{ /* NULL or unformatted node pointer. */
+ struct super_block *p_s_sb = p_s_inode->i_sb;
+ struct tree_balance s_del_balance;
+ struct item_head s_ih;
+ struct item_head *q_ih;
+ int quota_cut_bytes;
+ int n_ret_value, n_del_size, n_removed;
#ifdef CONFIG_REISERFS_CHECK
- char c_mode;
- int n_iter = 0;
+ char c_mode;
+ int n_iter = 0;
#endif
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path, 0/*size is unknown*/);
+ init_tb_struct(th, &s_del_balance, p_s_sb, p_s_path,
+ 0 /*size is unknown */ );
- while ( 1 ) {
- n_removed = 0;
+ while (1) {
+ n_removed = 0;
#ifdef CONFIG_REISERFS_CHECK
- n_iter++;
- c_mode =
+ n_iter++;
+ c_mode =
#endif
- prepare_for_delete_or_cut(th, p_s_inode, p_s_path, p_s_item_key, &n_removed, &n_del_size, max_reiserfs_offset (p_s_inode));
-
- RFALSE( c_mode != M_DELETE, "PAP-5320: mode must be M_DELETE");
-
- copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
- s_del_balance.insert_size[0] = n_del_size;
-
- n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL);
- if ( n_ret_value != REPEAT_SEARCH )
- break;
-
- PROC_INFO_INC( p_s_sb, delete_item_restarted );
+ prepare_for_delete_or_cut(th, p_s_inode, p_s_path,
+ p_s_item_key, &n_removed,
+ &n_del_size,
+ max_reiserfs_offset(p_s_inode));
+
+ RFALSE(c_mode != M_DELETE, "PAP-5320: mode must be M_DELETE");
+
+ copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+ s_del_balance.insert_size[0] = n_del_size;
+
+ n_ret_value = fix_nodes(M_DELETE, &s_del_balance, NULL, NULL);
+ if (n_ret_value != REPEAT_SEARCH)
+ break;
+
+ PROC_INFO_INC(p_s_sb, delete_item_restarted);
+
+ // file system changed, repeat search
+ n_ret_value =
+ search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
+ if (n_ret_value == IO_ERROR)
+ break;
+ if (n_ret_value == FILE_NOT_FOUND) {
+ reiserfs_warning(p_s_sb,
+ "vs-5340: reiserfs_delete_item: "
+ "no items of the file %K found",
+ p_s_item_key);
+ break;
+ }
+ } /* while (1) */
- // file system changed, repeat search
- n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
- if (n_ret_value == IO_ERROR)
- break;
- if (n_ret_value == FILE_NOT_FOUND) {
- reiserfs_warning (p_s_sb, "vs-5340: reiserfs_delete_item: "
- "no items of the file %K found", p_s_item_key);
- break;
+ if (n_ret_value != CARRY_ON) {
+ unfix_nodes(&s_del_balance);
+ return 0;
+ }
+ // reiserfs_delete_item returns item length when success
+ n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
+ q_ih = get_ih(p_s_path);
+ quota_cut_bytes = ih_item_len(q_ih);
+
+ /* hack so the quota code doesn't have to guess if the file
+ ** has a tail. On tail insert, we allocate quota for 1 unformatted node.
+ ** We test the offset because the tail might have been
+ ** split into multiple items, and we only want to decrement for
+ ** the unfm node once
+ */
+ if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(q_ih)) {
+ if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) {
+ quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
+ } else {
+ quota_cut_bytes = 0;
+ }
}
- } /* while (1) */
- if ( n_ret_value != CARRY_ON ) {
- unfix_nodes(&s_del_balance);
- return 0;
- }
-
- // reiserfs_delete_item returns item length when success
- n_ret_value = calc_deleted_bytes_number(&s_del_balance, M_DELETE);
- q_ih = get_ih(p_s_path) ;
- quota_cut_bytes = ih_item_len(q_ih) ;
-
- /* hack so the quota code doesn't have to guess if the file
- ** has a tail. On tail insert, we allocate quota for 1 unformatted node.
- ** We test the offset because the tail might have been
- ** split into multiple items, and we only want to decrement for
- ** the unfm node once
- */
- if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(q_ih)) {
- if ((le_ih_k_offset(q_ih) & (p_s_sb->s_blocksize - 1)) == 1) {
- quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
- } else {
- quota_cut_bytes = 0 ;
+ if (p_s_un_bh) {
+ int off;
+ char *data;
+
+ /* We are in direct2indirect conversion, so move tail contents
+ to the unformatted node */
+ /* note, we do the copy before preparing the buffer because we
+ ** don't care about the contents of the unformatted node yet.
+ ** the only thing we really care about is the direct item's data
+ ** is in the unformatted node.
+ **
+ ** Otherwise, we would have to call reiserfs_prepare_for_journal on
+ ** the unformatted node, which might schedule, meaning we'd have to
+ ** loop all the way back up to the start of the while loop.
+ **
+ ** The unformatted node must be dirtied later on. We can't be
+ ** sure here if the entire tail has been deleted yet.
+ **
+ ** p_s_un_bh is from the page cache (all unformatted nodes are
+ ** from the page cache) and might be a highmem page. So, we
+ ** can't use p_s_un_bh->b_data.
+ ** -clm
+ */
+
+ data = kmap_atomic(p_s_un_bh->b_page, KM_USER0);
+ off = ((le_ih_k_offset(&s_ih) - 1) & (PAGE_CACHE_SIZE - 1));
+ memcpy(data + off,
+ B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih),
+ n_ret_value);
+ kunmap_atomic(data, KM_USER0);
}
- }
-
- if ( p_s_un_bh ) {
- int off;
- char *data ;
-
- /* We are in direct2indirect conversion, so move tail contents
- to the unformatted node */
- /* note, we do the copy before preparing the buffer because we
- ** don't care about the contents of the unformatted node yet.
- ** the only thing we really care about is the direct item's data
- ** is in the unformatted node.
- **
- ** Otherwise, we would have to call reiserfs_prepare_for_journal on
- ** the unformatted node, which might schedule, meaning we'd have to
- ** loop all the way back up to the start of the while loop.
- **
- ** The unformatted node must be dirtied later on. We can't be
- ** sure here if the entire tail has been deleted yet.
- **
- ** p_s_un_bh is from the page cache (all unformatted nodes are
- ** from the page cache) and might be a highmem page. So, we
- ** can't use p_s_un_bh->b_data.
- ** -clm
- */
-
- data = kmap_atomic(p_s_un_bh->b_page, KM_USER0);
- off = ((le_ih_k_offset (&s_ih) - 1) & (PAGE_CACHE_SIZE - 1));
- memcpy(data + off,
- B_I_PITEM(PATH_PLAST_BUFFER(p_s_path), &s_ih), n_ret_value);
- kunmap_atomic(data, KM_USER0);
- }
- /* Perform balancing after all resources have been collected at once. */
- do_balance(&s_del_balance, NULL, NULL, M_DELETE);
+ /* Perform balancing after all resources have been collected at once. */
+ do_balance(&s_del_balance, NULL, NULL, M_DELETE);
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (p_s_sb, REISERFS_DEBUG_CODE, "reiserquota delete_item(): freeing %u, id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih));
+ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE,
+ "reiserquota delete_item(): freeing %u, id=%u type=%c",
+ quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih));
#endif
- DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
+ DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
- /* Return deleted body length */
- return n_ret_value;
+ /* Return deleted body length */
+ return n_ret_value;
}
-
/* Summary Of Mechanisms For Handling Collisions Between Processes:
deletion of the body of the object is performed by iput(), with the
@@ -1347,727 +1387,804 @@ int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
- Hans
*/
-
/* this deletes item which never gets split */
-void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
- struct inode *inode,
- struct reiserfs_key * key)
+void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
+ struct inode *inode, struct reiserfs_key *key)
{
- struct tree_balance tb;
- INITIALIZE_PATH (path);
- int item_len = 0;
- int tb_init = 0 ;
- struct cpu_key cpu_key;
- int retval;
- int quota_cut_bytes = 0;
-
- BUG_ON (!th->t_trans_id);
-
- le_key2cpu_key (&cpu_key, key);
-
- while (1) {
- retval = search_item (th->t_super, &cpu_key, &path);
- if (retval == IO_ERROR) {
- reiserfs_warning (th->t_super,
- "vs-5350: reiserfs_delete_solid_item: "
- "i/o failure occurred trying to delete %K",
- &cpu_key);
- break;
- }
- if (retval != ITEM_FOUND) {
- pathrelse (&path);
- // No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir
- if ( !( (unsigned long long) GET_HASH_VALUE (le_key_k_offset (le_key_version (key), key)) == 0 && \
- (unsigned long long) GET_GENERATION_NUMBER (le_key_k_offset (le_key_version (key), key)) == 1 ) )
- reiserfs_warning (th->t_super, "vs-5355: reiserfs_delete_solid_item: %k not found", key);
- break;
- }
- if (!tb_init) {
- tb_init = 1 ;
- item_len = ih_item_len( PATH_PITEM_HEAD(&path) );
- init_tb_struct (th, &tb, th->t_super, &path, - (IH_SIZE + item_len));
- }
- quota_cut_bytes = ih_item_len(PATH_PITEM_HEAD(&path)) ;
+ struct tree_balance tb;
+ INITIALIZE_PATH(path);
+ int item_len = 0;
+ int tb_init = 0;
+ struct cpu_key cpu_key;
+ int retval;
+ int quota_cut_bytes = 0;
+
+ BUG_ON(!th->t_trans_id);
+
+ le_key2cpu_key(&cpu_key, key);
+
+ while (1) {
+ retval = search_item(th->t_super, &cpu_key, &path);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(th->t_super,
+ "vs-5350: reiserfs_delete_solid_item: "
+ "i/o failure occurred trying to delete %K",
+ &cpu_key);
+ break;
+ }
+ if (retval != ITEM_FOUND) {
+ pathrelse(&path);
+ // No need for a warning, if there is just no free space to insert '..' item into the newly-created subdir
+ if (!
+ ((unsigned long long)
+ GET_HASH_VALUE(le_key_k_offset
+ (le_key_version(key), key)) == 0
+ && (unsigned long long)
+ GET_GENERATION_NUMBER(le_key_k_offset
+ (le_key_version(key),
+ key)) == 1))
+ reiserfs_warning(th->t_super,
+ "vs-5355: reiserfs_delete_solid_item: %k not found",
+ key);
+ break;
+ }
+ if (!tb_init) {
+ tb_init = 1;
+ item_len = ih_item_len(PATH_PITEM_HEAD(&path));
+ init_tb_struct(th, &tb, th->t_super, &path,
+ -(IH_SIZE + item_len));
+ }
+ quota_cut_bytes = ih_item_len(PATH_PITEM_HEAD(&path));
- retval = fix_nodes (M_DELETE, &tb, NULL, NULL);
- if (retval == REPEAT_SEARCH) {
- PROC_INFO_INC( th -> t_super, delete_solid_item_restarted );
- continue;
- }
+ retval = fix_nodes(M_DELETE, &tb, NULL, NULL);
+ if (retval == REPEAT_SEARCH) {
+ PROC_INFO_INC(th->t_super, delete_solid_item_restarted);
+ continue;
+ }
- if (retval == CARRY_ON) {
- do_balance (&tb, NULL, NULL, M_DELETE);
- if (inode) { /* Should we count quota for item? (we don't count quotas for save-links) */
+ if (retval == CARRY_ON) {
+ do_balance(&tb, NULL, NULL, M_DELETE);
+ if (inode) { /* Should we count quota for item? (we don't count quotas for save-links) */
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (th->t_super, REISERFS_DEBUG_CODE, "reiserquota delete_solid_item(): freeing %u id=%u type=%c", quota_cut_bytes, inode->i_uid, key2type(key));
+ reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
+ "reiserquota delete_solid_item(): freeing %u id=%u type=%c",
+ quota_cut_bytes, inode->i_uid,
+ key2type(key));
#endif
- DQUOT_FREE_SPACE_NODIRTY(inode, quota_cut_bytes);
- }
- break;
+ DQUOT_FREE_SPACE_NODIRTY(inode,
+ quota_cut_bytes);
+ }
+ break;
+ }
+ // IO_ERROR, NO_DISK_SPACE, etc
+ reiserfs_warning(th->t_super,
+ "vs-5360: reiserfs_delete_solid_item: "
+ "could not delete %K due to fix_nodes failure",
+ &cpu_key);
+ unfix_nodes(&tb);
+ break;
}
- // IO_ERROR, NO_DISK_SPACE, etc
- reiserfs_warning (th->t_super, "vs-5360: reiserfs_delete_solid_item: "
- "could not delete %K due to fix_nodes failure", &cpu_key);
- unfix_nodes (&tb);
- break;
- }
-
- reiserfs_check_path(&path) ;
+ reiserfs_check_path(&path);
}
-
-int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * inode)
+int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
+ struct inode *inode)
{
- int err;
- inode->i_size = 0;
- BUG_ON (!th->t_trans_id);
-
- /* for directory this deletes item containing "." and ".." */
- err = reiserfs_do_truncate (th, inode, NULL, 0/*no timestamp updates*/);
- if (err)
- return err;
-
+ int err;
+ inode->i_size = 0;
+ BUG_ON(!th->t_trans_id);
+
+ /* for directory this deletes item containing "." and ".." */
+ err =
+ reiserfs_do_truncate(th, inode, NULL, 0 /*no timestamp updates */ );
+ if (err)
+ return err;
+
#if defined( USE_INODE_GENERATION_COUNTER )
- if( !old_format_only ( th -> t_super ) )
- {
- __le32 *inode_generation;
-
- inode_generation =
- &REISERFS_SB(th -> t_super) -> s_rs -> s_inode_generation;
- *inode_generation = cpu_to_le32( le32_to_cpu( *inode_generation ) + 1 );
- }
+ if (!old_format_only(th->t_super)) {
+ __le32 *inode_generation;
+
+ inode_generation =
+ &REISERFS_SB(th->t_super)->s_rs->s_inode_generation;
+ *inode_generation =
+ cpu_to_le32(le32_to_cpu(*inode_generation) + 1);
+ }
/* USE_INODE_GENERATION_COUNTER */
#endif
- reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
+ reiserfs_delete_solid_item(th, inode, INODE_PKEY(inode));
- return err;
+ return err;
}
-static void
-unmap_buffers(struct page *page, loff_t pos) {
- struct buffer_head *bh ;
- struct buffer_head *head ;
- struct buffer_head *next ;
- unsigned long tail_index ;
- unsigned long cur_index ;
-
- if (page) {
- if (page_has_buffers(page)) {
- tail_index = pos & (PAGE_CACHE_SIZE - 1) ;
- cur_index = 0 ;
- head = page_buffers(page) ;
- bh = head ;
- do {
- next = bh->b_this_page ;
-
- /* we want to unmap the buffers that contain the tail, and
- ** all the buffers after it (since the tail must be at the
- ** end of the file). We don't want to unmap file data
- ** before the tail, since it might be dirty and waiting to
- ** reach disk
- */
- cur_index += bh->b_size ;
- if (cur_index > tail_index) {
- reiserfs_unmap_buffer(bh) ;
+static void unmap_buffers(struct page *page, loff_t pos)
+{
+ struct buffer_head *bh;
+ struct buffer_head *head;
+ struct buffer_head *next;
+ unsigned long tail_index;
+ unsigned long cur_index;
+
+ if (page) {
+ if (page_has_buffers(page)) {
+ tail_index = pos & (PAGE_CACHE_SIZE - 1);
+ cur_index = 0;
+ head = page_buffers(page);
+ bh = head;
+ do {
+ next = bh->b_this_page;
+
+ /* we want to unmap the buffers that contain the tail, and
+ ** all the buffers after it (since the tail must be at the
+ ** end of the file). We don't want to unmap file data
+ ** before the tail, since it might be dirty and waiting to
+ ** reach disk
+ */
+ cur_index += bh->b_size;
+ if (cur_index > tail_index) {
+ reiserfs_unmap_buffer(bh);
+ }
+ bh = next;
+ } while (bh != head);
+ if (PAGE_SIZE == bh->b_size) {
+ clear_page_dirty(page);
+ }
}
- bh = next ;
- } while (bh != head) ;
- if ( PAGE_SIZE == bh->b_size ) {
- clear_page_dirty(page);
- }
}
- }
}
-static int maybe_indirect_to_direct (struct reiserfs_transaction_handle *th,
- struct inode * p_s_inode,
- struct page *page,
- struct path * p_s_path,
- const struct cpu_key * p_s_item_key,
- loff_t n_new_file_size,
- char * p_c_mode
- ) {
- struct super_block * p_s_sb = p_s_inode->i_sb;
- int n_block_size = p_s_sb->s_blocksize;
- int cut_bytes;
- BUG_ON (!th->t_trans_id);
-
- if (n_new_file_size != p_s_inode->i_size)
- BUG ();
-
- /* the page being sent in could be NULL if there was an i/o error
- ** reading in the last block. The user will hit problems trying to
- ** read the file, but for now we just skip the indirect2direct
- */
- if (atomic_read(&p_s_inode->i_count) > 1 ||
- !tail_has_to_be_packed (p_s_inode) ||
- !page || (REISERFS_I(p_s_inode)->i_flags & i_nopack_mask)) {
- // leave tail in an unformatted node
- *p_c_mode = M_SKIP_BALANCING;
- cut_bytes = n_block_size - (n_new_file_size & (n_block_size - 1));
- pathrelse(p_s_path);
- return cut_bytes;
- }
- /* Permorm the conversion to a direct_item. */
- /*return indirect_to_direct (p_s_inode, p_s_path, p_s_item_key, n_new_file_size, p_c_mode);*/
- return indirect2direct (th, p_s_inode, page, p_s_path, p_s_item_key, n_new_file_size, p_c_mode);
-}
+static int maybe_indirect_to_direct(struct reiserfs_transaction_handle *th,
+ struct inode *p_s_inode,
+ struct page *page,
+ struct path *p_s_path,
+ const struct cpu_key *p_s_item_key,
+ loff_t n_new_file_size, char *p_c_mode)
+{
+ struct super_block *p_s_sb = p_s_inode->i_sb;
+ int n_block_size = p_s_sb->s_blocksize;
+ int cut_bytes;
+ BUG_ON(!th->t_trans_id);
+
+ if (n_new_file_size != p_s_inode->i_size)
+ BUG();
+ /* the page being sent in could be NULL if there was an i/o error
+ ** reading in the last block. The user will hit problems trying to
+ ** read the file, but for now we just skip the indirect2direct
+ */
+ if (atomic_read(&p_s_inode->i_count) > 1 ||
+ !tail_has_to_be_packed(p_s_inode) ||
+ !page || (REISERFS_I(p_s_inode)->i_flags & i_nopack_mask)) {
+ // leave tail in an unformatted node
+ *p_c_mode = M_SKIP_BALANCING;
+ cut_bytes =
+ n_block_size - (n_new_file_size & (n_block_size - 1));
+ pathrelse(p_s_path);
+ return cut_bytes;
+ }
+ /* Permorm the conversion to a direct_item. */
+ /*return indirect_to_direct (p_s_inode, p_s_path, p_s_item_key, n_new_file_size, p_c_mode); */
+ return indirect2direct(th, p_s_inode, page, p_s_path, p_s_item_key,
+ n_new_file_size, p_c_mode);
+}
/* we did indirect_to_direct conversion. And we have inserted direct
item successesfully, but there were no disk space to cut unfm
pointer being converted. Therefore we have to delete inserted
direct item(s) */
-static void indirect_to_direct_roll_back (struct reiserfs_transaction_handle *th, struct inode * inode, struct path * path)
+static void indirect_to_direct_roll_back(struct reiserfs_transaction_handle *th,
+ struct inode *inode, struct path *path)
{
- struct cpu_key tail_key;
- int tail_len;
- int removed;
- BUG_ON (!th->t_trans_id);
-
- make_cpu_key (&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4);// !!!!
- tail_key.key_length = 4;
-
- tail_len = (cpu_key_k_offset (&tail_key) & (inode->i_sb->s_blocksize - 1)) - 1;
- while (tail_len) {
- /* look for the last byte of the tail */
- if (search_for_position_by_key (inode->i_sb, &tail_key, path) == POSITION_NOT_FOUND)
- reiserfs_panic (inode->i_sb, "vs-5615: indirect_to_direct_roll_back: found invalid item");
- RFALSE( path->pos_in_item != ih_item_len(PATH_PITEM_HEAD (path)) - 1,
- "vs-5616: appended bytes found");
- PATH_LAST_POSITION (path) --;
-
- removed = reiserfs_delete_item (th, path, &tail_key, inode, NULL/*unbh not needed*/);
- RFALSE( removed <= 0 || removed > tail_len,
- "vs-5617: there was tail %d bytes, removed item length %d bytes",
- tail_len, removed);
- tail_len -= removed;
- set_cpu_key_k_offset (&tail_key, cpu_key_k_offset (&tail_key) - removed);
- }
- reiserfs_warning (inode->i_sb, "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space");
- //mark_file_without_tail (inode);
- mark_inode_dirty (inode);
+ struct cpu_key tail_key;
+ int tail_len;
+ int removed;
+ BUG_ON(!th->t_trans_id);
+
+ make_cpu_key(&tail_key, inode, inode->i_size + 1, TYPE_DIRECT, 4); // !!!!
+ tail_key.key_length = 4;
+
+ tail_len =
+ (cpu_key_k_offset(&tail_key) & (inode->i_sb->s_blocksize - 1)) - 1;
+ while (tail_len) {
+ /* look for the last byte of the tail */
+ if (search_for_position_by_key(inode->i_sb, &tail_key, path) ==
+ POSITION_NOT_FOUND)
+ reiserfs_panic(inode->i_sb,
+ "vs-5615: indirect_to_direct_roll_back: found invalid item");
+ RFALSE(path->pos_in_item !=
+ ih_item_len(PATH_PITEM_HEAD(path)) - 1,
+ "vs-5616: appended bytes found");
+ PATH_LAST_POSITION(path)--;
+
+ removed =
+ reiserfs_delete_item(th, path, &tail_key, inode,
+ NULL /*unbh not needed */ );
+ RFALSE(removed <= 0
+ || removed > tail_len,
+ "vs-5617: there was tail %d bytes, removed item length %d bytes",
+ tail_len, removed);
+ tail_len -= removed;
+ set_cpu_key_k_offset(&tail_key,
+ cpu_key_k_offset(&tail_key) - removed);
+ }
+ reiserfs_warning(inode->i_sb,
+ "indirect_to_direct_roll_back: indirect_to_direct conversion has been rolled back due to lack of disk space");
+ //mark_file_without_tail (inode);
+ mark_inode_dirty(inode);
}
-
/* (Truncate or cut entry) or delete object item. Returns < 0 on failure */
-int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
- struct path * p_s_path,
- struct cpu_key * p_s_item_key,
- struct inode * p_s_inode,
- struct page *page,
- loff_t n_new_file_size)
+int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
+ struct path *p_s_path,
+ struct cpu_key *p_s_item_key,
+ struct inode *p_s_inode,
+ struct page *page, loff_t n_new_file_size)
{
- struct super_block * p_s_sb = p_s_inode->i_sb;
- /* Every function which is going to call do_balance must first
- create a tree_balance structure. Then it must fill up this
- structure by using the init_tb_struct and fix_nodes functions.
- After that we can make tree balancing. */
- struct tree_balance s_cut_balance;
- struct item_head *p_le_ih;
- int n_cut_size = 0, /* Amount to be cut. */
- n_ret_value = CARRY_ON,
- n_removed = 0, /* Number of the removed unformatted nodes. */
- n_is_inode_locked = 0;
- char c_mode; /* Mode of the balance. */
- int retval2 = -1;
- int quota_cut_bytes;
- loff_t tail_pos = 0;
-
- BUG_ON (!th->t_trans_id);
-
- init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path, n_cut_size);
-
-
- /* Repeat this loop until we either cut the item without needing
- to balance, or we fix_nodes without schedule occurring */
- while ( 1 ) {
- /* Determine the balance mode, position of the first byte to
- be cut, and size to be cut. In case of the indirect item
- free unformatted nodes which are pointed to by the cut
- pointers. */
-
- c_mode = prepare_for_delete_or_cut(th, p_s_inode, p_s_path, p_s_item_key, &n_removed,
- &n_cut_size, n_new_file_size);
- if ( c_mode == M_CONVERT ) {
- /* convert last unformatted node to direct item or leave
- tail in the unformatted node */
- RFALSE( n_ret_value != CARRY_ON, "PAP-5570: can not convert twice");
-
- n_ret_value = maybe_indirect_to_direct (th, p_s_inode, page, p_s_path, p_s_item_key,
- n_new_file_size, &c_mode);
- if ( c_mode == M_SKIP_BALANCING )
- /* tail has been left in the unformatted node */
- return n_ret_value;
-
- n_is_inode_locked = 1;
-
- /* removing of last unformatted node will change value we
- have to return to truncate. Save it */
- retval2 = n_ret_value;
- /*retval2 = p_s_sb->s_blocksize - (n_new_file_size & (p_s_sb->s_blocksize - 1));*/
-
- /* So, we have performed the first part of the conversion:
- inserting the new direct item. Now we are removing the
- last unformatted node pointer. Set key to search for
- it. */
- set_cpu_key_k_type (p_s_item_key, TYPE_INDIRECT);
- p_s_item_key->key_length = 4;
- n_new_file_size -= (n_new_file_size & (p_s_sb->s_blocksize - 1));
- tail_pos = n_new_file_size;
- set_cpu_key_k_offset (p_s_item_key, n_new_file_size + 1);
- if ( search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND ){
- print_block (PATH_PLAST_BUFFER (p_s_path), 3, PATH_LAST_POSITION (p_s_path) - 1, PATH_LAST_POSITION (p_s_path) + 1);
- reiserfs_panic(p_s_sb, "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)", p_s_item_key);
- }
- continue;
- }
- if (n_cut_size == 0) {
- pathrelse (p_s_path);
- return 0;
- }
+ struct super_block *p_s_sb = p_s_inode->i_sb;
+ /* Every function which is going to call do_balance must first
+ create a tree_balance structure. Then it must fill up this
+ structure by using the init_tb_struct and fix_nodes functions.
+ After that we can make tree balancing. */
+ struct tree_balance s_cut_balance;
+ struct item_head *p_le_ih;
+ int n_cut_size = 0, /* Amount to be cut. */
+ n_ret_value = CARRY_ON, n_removed = 0, /* Number of the removed unformatted nodes. */
+ n_is_inode_locked = 0;
+ char c_mode; /* Mode of the balance. */
+ int retval2 = -1;
+ int quota_cut_bytes;
+ loff_t tail_pos = 0;
+
+ BUG_ON(!th->t_trans_id);
+
+ init_tb_struct(th, &s_cut_balance, p_s_inode->i_sb, p_s_path,
+ n_cut_size);
+
+ /* Repeat this loop until we either cut the item without needing
+ to balance, or we fix_nodes without schedule occurring */
+ while (1) {
+ /* Determine the balance mode, position of the first byte to
+ be cut, and size to be cut. In case of the indirect item
+ free unformatted nodes which are pointed to by the cut
+ pointers. */
+
+ c_mode =
+ prepare_for_delete_or_cut(th, p_s_inode, p_s_path,
+ p_s_item_key, &n_removed,
+ &n_cut_size, n_new_file_size);
+ if (c_mode == M_CONVERT) {
+ /* convert last unformatted node to direct item or leave
+ tail in the unformatted node */
+ RFALSE(n_ret_value != CARRY_ON,
+ "PAP-5570: can not convert twice");
+
+ n_ret_value =
+ maybe_indirect_to_direct(th, p_s_inode, page,
+ p_s_path, p_s_item_key,
+ n_new_file_size, &c_mode);
+ if (c_mode == M_SKIP_BALANCING)
+ /* tail has been left in the unformatted node */
+ return n_ret_value;
+
+ n_is_inode_locked = 1;
+
+ /* removing of last unformatted node will change value we
+ have to return to truncate. Save it */
+ retval2 = n_ret_value;
+ /*retval2 = p_s_sb->s_blocksize - (n_new_file_size & (p_s_sb->s_blocksize - 1)); */
+
+ /* So, we have performed the first part of the conversion:
+ inserting the new direct item. Now we are removing the
+ last unformatted node pointer. Set key to search for
+ it. */
+ set_cpu_key_k_type(p_s_item_key, TYPE_INDIRECT);
+ p_s_item_key->key_length = 4;
+ n_new_file_size -=
+ (n_new_file_size & (p_s_sb->s_blocksize - 1));
+ tail_pos = n_new_file_size;
+ set_cpu_key_k_offset(p_s_item_key, n_new_file_size + 1);
+ if (search_for_position_by_key
+ (p_s_sb, p_s_item_key,
+ p_s_path) == POSITION_NOT_FOUND) {
+ print_block(PATH_PLAST_BUFFER(p_s_path), 3,
+ PATH_LAST_POSITION(p_s_path) - 1,
+ PATH_LAST_POSITION(p_s_path) + 1);
+ reiserfs_panic(p_s_sb,
+ "PAP-5580: reiserfs_cut_from_item: item to convert does not exist (%K)",
+ p_s_item_key);
+ }
+ continue;
+ }
+ if (n_cut_size == 0) {
+ pathrelse(p_s_path);
+ return 0;
+ }
+
+ s_cut_balance.insert_size[0] = n_cut_size;
+
+ n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL);
+ if (n_ret_value != REPEAT_SEARCH)
+ break;
+
+ PROC_INFO_INC(p_s_sb, cut_from_item_restarted);
+
+ n_ret_value =
+ search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
+ if (n_ret_value == POSITION_FOUND)
+ continue;
- s_cut_balance.insert_size[0] = n_cut_size;
-
- n_ret_value = fix_nodes(c_mode, &s_cut_balance, NULL, NULL);
- if ( n_ret_value != REPEAT_SEARCH )
- break;
-
- PROC_INFO_INC( p_s_sb, cut_from_item_restarted );
-
- n_ret_value = search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path);
- if (n_ret_value == POSITION_FOUND)
- continue;
-
- reiserfs_warning (p_s_sb, "PAP-5610: reiserfs_cut_from_item: item %K not found", p_s_item_key);
- unfix_nodes (&s_cut_balance);
- return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT;
- } /* while */
-
- // check fix_nodes results (IO_ERROR or NO_DISK_SPACE)
- if ( n_ret_value != CARRY_ON ) {
- if ( n_is_inode_locked ) {
- // FIXME: this seems to be not needed: we are always able
- // to cut item
- indirect_to_direct_roll_back (th, p_s_inode, p_s_path);
+ reiserfs_warning(p_s_sb,
+ "PAP-5610: reiserfs_cut_from_item: item %K not found",
+ p_s_item_key);
+ unfix_nodes(&s_cut_balance);
+ return (n_ret_value == IO_ERROR) ? -EIO : -ENOENT;
+ } /* while */
+
+ // check fix_nodes results (IO_ERROR or NO_DISK_SPACE)
+ if (n_ret_value != CARRY_ON) {
+ if (n_is_inode_locked) {
+ // FIXME: this seems to be not needed: we are always able
+ // to cut item
+ indirect_to_direct_roll_back(th, p_s_inode, p_s_path);
+ }
+ if (n_ret_value == NO_DISK_SPACE)
+ reiserfs_warning(p_s_sb, "NO_DISK_SPACE");
+ unfix_nodes(&s_cut_balance);
+ return -EIO;
}
- if (n_ret_value == NO_DISK_SPACE)
- reiserfs_warning (p_s_sb, "NO_DISK_SPACE");
- unfix_nodes (&s_cut_balance);
- return -EIO;
- }
-
- /* go ahead and perform balancing */
-
- RFALSE( c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode");
-
- /* Calculate number of bytes that need to be cut from the item. */
- quota_cut_bytes = ( c_mode == M_DELETE ) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.insert_size[0];
- if (retval2 == -1)
- n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);
- else
- n_ret_value = retval2;
-
-
- /* For direct items, we only change the quota when deleting the last
- ** item.
- */
- p_le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
- if (!S_ISLNK (p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) {
- if (c_mode == M_DELETE &&
- (le_ih_k_offset (p_le_ih) & (p_s_sb->s_blocksize - 1)) == 1 ) {
- // FIXME: this is to keep 3.5 happy
- REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
- quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE ;
- } else {
- quota_cut_bytes = 0 ;
+
+ /* go ahead and perform balancing */
+
+ RFALSE(c_mode == M_PASTE || c_mode == M_INSERT, "invalid mode");
+
+ /* Calculate number of bytes that need to be cut from the item. */
+ quota_cut_bytes =
+ (c_mode ==
+ M_DELETE) ? ih_item_len(get_ih(p_s_path)) : -s_cut_balance.
+ insert_size[0];
+ if (retval2 == -1)
+ n_ret_value = calc_deleted_bytes_number(&s_cut_balance, c_mode);
+ else
+ n_ret_value = retval2;
+
+ /* For direct items, we only change the quota when deleting the last
+ ** item.
+ */
+ p_le_ih = PATH_PITEM_HEAD(s_cut_balance.tb_path);
+ if (!S_ISLNK(p_s_inode->i_mode) && is_direct_le_ih(p_le_ih)) {
+ if (c_mode == M_DELETE &&
+ (le_ih_k_offset(p_le_ih) & (p_s_sb->s_blocksize - 1)) ==
+ 1) {
+ // FIXME: this is to keep 3.5 happy
+ REISERFS_I(p_s_inode)->i_first_direct_byte = U32_MAX;
+ quota_cut_bytes = p_s_sb->s_blocksize + UNFM_P_SIZE;
+ } else {
+ quota_cut_bytes = 0;
+ }
}
- }
#ifdef CONFIG_REISERFS_CHECK
- if (n_is_inode_locked) {
- struct item_head * le_ih = PATH_PITEM_HEAD (s_cut_balance.tb_path);
- /* we are going to complete indirect2direct conversion. Make
- sure, that we exactly remove last unformatted node pointer
- of the item */
- if (!is_indirect_le_ih (le_ih))
- reiserfs_panic (p_s_sb, "vs-5652: reiserfs_cut_from_item: "
- "item must be indirect %h", le_ih);
-
- if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
- reiserfs_panic (p_s_sb, "vs-5653: reiserfs_cut_from_item: "
- "completing indirect2direct conversion indirect item %h "
- "being deleted must be of 4 byte long", le_ih);
-
- if (c_mode == M_CUT && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) {
- reiserfs_panic (p_s_sb, "vs-5654: reiserfs_cut_from_item: "
- "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)",
- le_ih, s_cut_balance.insert_size[0]);
+ if (n_is_inode_locked) {
+ struct item_head *le_ih =
+ PATH_PITEM_HEAD(s_cut_balance.tb_path);
+ /* we are going to complete indirect2direct conversion. Make
+ sure, that we exactly remove last unformatted node pointer
+ of the item */
+ if (!is_indirect_le_ih(le_ih))
+ reiserfs_panic(p_s_sb,
+ "vs-5652: reiserfs_cut_from_item: "
+ "item must be indirect %h", le_ih);
+
+ if (c_mode == M_DELETE && ih_item_len(le_ih) != UNFM_P_SIZE)
+ reiserfs_panic(p_s_sb,
+ "vs-5653: reiserfs_cut_from_item: "
+ "completing indirect2direct conversion indirect item %h "
+ "being deleted must be of 4 byte long",
+ le_ih);
+
+ if (c_mode == M_CUT
+ && s_cut_balance.insert_size[0] != -UNFM_P_SIZE) {
+ reiserfs_panic(p_s_sb,
+ "vs-5654: reiserfs_cut_from_item: "
+ "can not complete indirect2direct conversion of %h (CUT, insert_size==%d)",
+ le_ih, s_cut_balance.insert_size[0]);
+ }
+ /* it would be useful to make sure, that right neighboring
+ item is direct item of this file */
}
- /* it would be useful to make sure, that right neighboring
- item is direct item of this file */
- }
#endif
-
- do_balance(&s_cut_balance, NULL, NULL, c_mode);
- if ( n_is_inode_locked ) {
- /* we've done an indirect->direct conversion. when the data block
- ** was freed, it was removed from the list of blocks that must
- ** be flushed before the transaction commits, make sure to
- ** unmap and invalidate it
- */
- unmap_buffers(page, tail_pos);
- REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask ;
- }
+
+ do_balance(&s_cut_balance, NULL, NULL, c_mode);
+ if (n_is_inode_locked) {
+ /* we've done an indirect->direct conversion. when the data block
+ ** was freed, it was removed from the list of blocks that must
+ ** be flushed before the transaction commits, make sure to
+ ** unmap and invalidate it
+ */
+ unmap_buffers(page, tail_pos);
+ REISERFS_I(p_s_inode)->i_flags &= ~i_pack_on_close_mask;
+ }
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (p_s_inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota cut_from_item(): freeing %u id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, '?');
+ reiserfs_debug(p_s_inode->i_sb, REISERFS_DEBUG_CODE,
+ "reiserquota cut_from_item(): freeing %u id=%u type=%c",
+ quota_cut_bytes, p_s_inode->i_uid, '?');
#endif
- DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
- return n_ret_value;
+ DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes);
+ return n_ret_value;
}
-static void truncate_directory (struct reiserfs_transaction_handle *th, struct inode * inode)
+static void truncate_directory(struct reiserfs_transaction_handle *th,
+ struct inode *inode)
{
- BUG_ON (!th->t_trans_id);
- if (inode->i_nlink)
- reiserfs_warning (inode->i_sb,
- "vs-5655: truncate_directory: link count != 0");
-
- set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), DOT_OFFSET);
- set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_DIRENTRY);
- reiserfs_delete_solid_item (th, inode, INODE_PKEY (inode));
- reiserfs_update_sd(th, inode) ;
- set_le_key_k_offset (KEY_FORMAT_3_5, INODE_PKEY (inode), SD_OFFSET);
- set_le_key_k_type (KEY_FORMAT_3_5, INODE_PKEY (inode), TYPE_STAT_DATA);
+ BUG_ON(!th->t_trans_id);
+ if (inode->i_nlink)
+ reiserfs_warning(inode->i_sb,
+ "vs-5655: truncate_directory: link count != 0");
+
+ set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), DOT_OFFSET);
+ set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_DIRENTRY);
+ reiserfs_delete_solid_item(th, inode, INODE_PKEY(inode));
+ reiserfs_update_sd(th, inode);
+ set_le_key_k_offset(KEY_FORMAT_3_5, INODE_PKEY(inode), SD_OFFSET);
+ set_le_key_k_type(KEY_FORMAT_3_5, INODE_PKEY(inode), TYPE_STAT_DATA);
}
+/* Truncate file to the new size. Note, this must be called with a transaction
+ already started */
+int reiserfs_do_truncate(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, /* ->i_size contains new
+ size */
+ struct page *page, /* up to date for last block */
+ int update_timestamps /* when it is called by
+ file_release to convert
+ the tail - no timestamps
+ should be updated */
+ )
+{
+ INITIALIZE_PATH(s_search_path); /* Path to the current object item. */
+ struct item_head *p_le_ih; /* Pointer to an item header. */
+ struct cpu_key s_item_key; /* Key to search for a previous file item. */
+ loff_t n_file_size, /* Old file size. */
+ n_new_file_size; /* New file size. */
+ int n_deleted; /* Number of deleted or truncated bytes. */
+ int retval;
+ int err = 0;
+
+ BUG_ON(!th->t_trans_id);
+ if (!
+ (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode)
+ || S_ISLNK(p_s_inode->i_mode)))
+ return 0;
+
+ if (S_ISDIR(p_s_inode->i_mode)) {
+ // deletion of directory - no need to update timestamps
+ truncate_directory(th, p_s_inode);
+ return 0;
+ }
+ /* Get new file size. */
+ n_new_file_size = p_s_inode->i_size;
+ // FIXME: note, that key type is unimportant here
+ make_cpu_key(&s_item_key, p_s_inode, max_reiserfs_offset(p_s_inode),
+ TYPE_DIRECT, 3);
-/* Truncate file to the new size. Note, this must be called with a transaction
- already started */
-int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
- struct inode * p_s_inode, /* ->i_size contains new
- size */
- struct page *page, /* up to date for last block */
- int update_timestamps /* when it is called by
- file_release to convert
- the tail - no timestamps
- should be updated */
- ) {
- INITIALIZE_PATH (s_search_path); /* Path to the current object item. */
- struct item_head * p_le_ih; /* Pointer to an item header. */
- struct cpu_key s_item_key; /* Key to search for a previous file item. */
- loff_t n_file_size, /* Old file size. */
- n_new_file_size;/* New file size. */
- int n_deleted; /* Number of deleted or truncated bytes. */
- int retval;
- int err = 0;
-
- BUG_ON (!th->t_trans_id);
- if ( ! (S_ISREG(p_s_inode->i_mode) || S_ISDIR(p_s_inode->i_mode) || S_ISLNK(p_s_inode->i_mode)) )
- return 0;
+ retval =
+ search_for_position_by_key(p_s_inode->i_sb, &s_item_key,
+ &s_search_path);
+ if (retval == IO_ERROR) {
+ reiserfs_warning(p_s_inode->i_sb,
+ "vs-5657: reiserfs_do_truncate: "
+ "i/o failure occurred trying to truncate %K",
+ &s_item_key);
+ err = -EIO;
+ goto out;
+ }
+ if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
+ reiserfs_warning(p_s_inode->i_sb,
+ "PAP-5660: reiserfs_do_truncate: "
+ "wrong result %d of search for %K", retval,
+ &s_item_key);
+
+ err = -EIO;
+ goto out;
+ }
- if (S_ISDIR(p_s_inode->i_mode)) {
- // deletion of directory - no need to update timestamps
- truncate_directory (th, p_s_inode);
- return 0;
- }
-
- /* Get new file size. */
- n_new_file_size = p_s_inode->i_size;
-
- // FIXME: note, that key type is unimportant here
- make_cpu_key (&s_item_key, p_s_inode, max_reiserfs_offset (p_s_inode), TYPE_DIRECT, 3);
-
- retval = search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path);
- if (retval == IO_ERROR) {
- reiserfs_warning (p_s_inode->i_sb, "vs-5657: reiserfs_do_truncate: "
- "i/o failure occurred trying to truncate %K", &s_item_key);
- err = -EIO;
- goto out;
- }
- if (retval == POSITION_FOUND || retval == FILE_NOT_FOUND) {
- reiserfs_warning (p_s_inode->i_sb, "PAP-5660: reiserfs_do_truncate: "
- "wrong result %d of search for %K", retval, &s_item_key);
-
- err = -EIO;
- goto out;
- }
-
- s_search_path.pos_in_item --;
-
- /* Get real file size (total length of all file items) */
- p_le_ih = PATH_PITEM_HEAD(&s_search_path);
- if ( is_statdata_le_ih (p_le_ih) )
- n_file_size = 0;
- else {
- loff_t offset = le_ih_k_offset (p_le_ih);
- int bytes = op_bytes_number (p_le_ih,p_s_inode->i_sb->s_blocksize);
-
- /* this may mismatch with real file size: if last direct item
- had no padding zeros and last unformatted node had no free
- space, this file would have this file size */
- n_file_size = offset + bytes - 1;
- }
- /*
- * are we doing a full truncate or delete, if so
- * kick in the reada code
- */
- if (n_new_file_size == 0)
- s_search_path.reada = PATH_READA | PATH_READA_BACK;
-
- if ( n_file_size == 0 || n_file_size < n_new_file_size ) {
- goto update_and_out ;
- }
-
- /* Update key to search for the last file item. */
- set_cpu_key_k_offset (&s_item_key, n_file_size);
-
- do {
- /* Cut or delete file item. */
- n_deleted = reiserfs_cut_from_item(th, &s_search_path, &s_item_key, p_s_inode, page, n_new_file_size);
- if (n_deleted < 0) {
- reiserfs_warning (p_s_inode->i_sb, "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");
- reiserfs_check_path(&s_search_path) ;
- return 0;
+ s_search_path.pos_in_item--;
+
+ /* Get real file size (total length of all file items) */
+ p_le_ih = PATH_PITEM_HEAD(&s_search_path);
+ if (is_statdata_le_ih(p_le_ih))
+ n_file_size = 0;
+ else {
+ loff_t offset = le_ih_k_offset(p_le_ih);
+ int bytes =
+ op_bytes_number(p_le_ih, p_s_inode->i_sb->s_blocksize);
+
+ /* this may mismatch with real file size: if last direct item
+ had no padding zeros and last unformatted node had no free
+ space, this file would have this file size */
+ n_file_size = offset + bytes - 1;
+ }
+ /*
+ * are we doing a full truncate or delete, if so
+ * kick in the reada code
+ */
+ if (n_new_file_size == 0)
+ s_search_path.reada = PATH_READA | PATH_READA_BACK;
+
+ if (n_file_size == 0 || n_file_size < n_new_file_size) {
+ goto update_and_out;
}
- RFALSE( n_deleted > n_file_size,
- "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K",
- n_deleted, n_file_size, &s_item_key);
+ /* Update key to search for the last file item. */
+ set_cpu_key_k_offset(&s_item_key, n_file_size);
+
+ do {
+ /* Cut or delete file item. */
+ n_deleted =
+ reiserfs_cut_from_item(th, &s_search_path, &s_item_key,
+ p_s_inode, page, n_new_file_size);
+ if (n_deleted < 0) {
+ reiserfs_warning(p_s_inode->i_sb,
+ "vs-5665: reiserfs_do_truncate: reiserfs_cut_from_item failed");
+ reiserfs_check_path(&s_search_path);
+ return 0;
+ }
- /* Change key to search the last file item. */
- n_file_size -= n_deleted;
+ RFALSE(n_deleted > n_file_size,
+ "PAP-5670: reiserfs_cut_from_item: too many bytes deleted: deleted %d, file_size %lu, item_key %K",
+ n_deleted, n_file_size, &s_item_key);
- set_cpu_key_k_offset (&s_item_key, n_file_size);
+ /* Change key to search the last file item. */
+ n_file_size -= n_deleted;
- /* While there are bytes to truncate and previous file item is presented in the tree. */
+ set_cpu_key_k_offset(&s_item_key, n_file_size);
- /*
- ** This loop could take a really long time, and could log
- ** many more blocks than a transaction can hold. So, we do a polite
- ** journal end here, and if the transaction needs ending, we make
- ** sure the file is consistent before ending the current trans
- ** and starting a new one
- */
- if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
- int orig_len_alloc = th->t_blocks_allocated ;
- decrement_counters_in_path(&s_search_path) ;
-
- if (update_timestamps) {
- p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
- }
- reiserfs_update_sd(th, p_s_inode) ;
-
- err = journal_end(th, p_s_inode->i_sb, orig_len_alloc) ;
- if (err)
- goto out;
- err = journal_begin (th, p_s_inode->i_sb,
- JOURNAL_PER_BALANCE_CNT * 6);
- if (err)
- goto out;
- reiserfs_update_inode_transaction(p_s_inode) ;
+ /* While there are bytes to truncate and previous file item is presented in the tree. */
+
+ /*
+ ** This loop could take a really long time, and could log
+ ** many more blocks than a transaction can hold. So, we do a polite
+ ** journal end here, and if the transaction needs ending, we make
+ ** sure the file is consistent before ending the current trans
+ ** and starting a new one
+ */
+ if (journal_transaction_should_end(th, th->t_blocks_allocated)) {
+ int orig_len_alloc = th->t_blocks_allocated;
+ decrement_counters_in_path(&s_search_path);
+
+ if (update_timestamps) {
+ p_s_inode->i_mtime = p_s_inode->i_ctime =
+ CURRENT_TIME_SEC;
+ }
+ reiserfs_update_sd(th, p_s_inode);
+
+ err = journal_end(th, p_s_inode->i_sb, orig_len_alloc);
+ if (err)
+ goto out;
+ err = journal_begin(th, p_s_inode->i_sb,
+ JOURNAL_PER_BALANCE_CNT * 6);
+ if (err)
+ goto out;
+ reiserfs_update_inode_transaction(p_s_inode);
+ }
+ } while (n_file_size > ROUND_UP(n_new_file_size) &&
+ search_for_position_by_key(p_s_inode->i_sb, &s_item_key,
+ &s_search_path) == POSITION_FOUND);
+
+ RFALSE(n_file_size > ROUND_UP(n_new_file_size),
+ "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d",
+ n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid);
+
+ update_and_out:
+ if (update_timestamps) {
+ // this is truncate, not file closing
+ p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
}
- } while ( n_file_size > ROUND_UP (n_new_file_size) &&
- search_for_position_by_key(p_s_inode->i_sb, &s_item_key, &s_search_path) == POSITION_FOUND ) ;
-
- RFALSE( n_file_size > ROUND_UP (n_new_file_size),
- "PAP-5680: truncate did not finish: new_file_size %Ld, current %Ld, oid %d",
- n_new_file_size, n_file_size, s_item_key.on_disk_key.k_objectid);
-
-update_and_out:
- if (update_timestamps) {
- // this is truncate, not file closing
- p_s_inode->i_mtime = p_s_inode->i_ctime = CURRENT_TIME_SEC;
- }
- reiserfs_update_sd (th, p_s_inode);
-
-out:
- pathrelse(&s_search_path) ;
- return err;
-}
+ reiserfs_update_sd(th, p_s_inode);
+ out:
+ pathrelse(&s_search_path);
+ return err;
+}
#ifdef CONFIG_REISERFS_CHECK
// this makes sure, that we __append__, not overwrite or add holes
-static void check_research_for_paste (struct path * path,
- const struct cpu_key * p_s_key)
+static void check_research_for_paste(struct path *path,
+ const struct cpu_key *p_s_key)
{
- struct item_head * found_ih = get_ih (path);
-
- if (is_direct_le_ih (found_ih)) {
- if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) !=
- cpu_key_k_offset (p_s_key) ||
- op_bytes_number (found_ih, get_last_bh (path)->b_size) != pos_in_item (path))
- reiserfs_panic (NULL, "PAP-5720: check_research_for_paste: "
- "found direct item %h or position (%d) does not match to key %K",
- found_ih, pos_in_item (path), p_s_key);
- }
- if (is_indirect_le_ih (found_ih)) {
- if (le_ih_k_offset (found_ih) + op_bytes_number (found_ih, get_last_bh (path)->b_size) != cpu_key_k_offset (p_s_key) ||
- I_UNFM_NUM (found_ih) != pos_in_item (path) ||
- get_ih_free_space (found_ih) != 0)
- reiserfs_panic (NULL, "PAP-5730: check_research_for_paste: "
- "found indirect item (%h) or position (%d) does not match to key (%K)",
- found_ih, pos_in_item (path), p_s_key);
- }
+ struct item_head *found_ih = get_ih(path);
+
+ if (is_direct_le_ih(found_ih)) {
+ if (le_ih_k_offset(found_ih) +
+ op_bytes_number(found_ih,
+ get_last_bh(path)->b_size) !=
+ cpu_key_k_offset(p_s_key)
+ || op_bytes_number(found_ih,
+ get_last_bh(path)->b_size) !=
+ pos_in_item(path))
+ reiserfs_panic(NULL,
+ "PAP-5720: check_research_for_paste: "
+ "found direct item %h or position (%d) does not match to key %K",
+ found_ih, pos_in_item(path), p_s_key);
+ }
+ if (is_indirect_le_ih(found_ih)) {
+ if (le_ih_k_offset(found_ih) +
+ op_bytes_number(found_ih,
+ get_last_bh(path)->b_size) !=
+ cpu_key_k_offset(p_s_key)
+ || I_UNFM_NUM(found_ih) != pos_in_item(path)
+ || get_ih_free_space(found_ih) != 0)
+ reiserfs_panic(NULL,
+ "PAP-5730: check_research_for_paste: "
+ "found indirect item (%h) or position (%d) does not match to key (%K)",
+ found_ih, pos_in_item(path), p_s_key);
+ }
}
-#endif /* config reiserfs check */
-
+#endif /* config reiserfs check */
/* Paste bytes to the existing item. Returns bytes number pasted into the item. */
-int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
- struct path * p_s_search_path, /* Path to the pasted item. */
- const struct cpu_key * p_s_key, /* Key to search for the needed item.*/
- struct inode * inode, /* Inode item belongs to */
- const char * p_c_body, /* Pointer to the bytes to paste. */
- int n_pasted_size) /* Size of pasted bytes. */
-{
- struct tree_balance s_paste_balance;
- int retval;
- int fs_gen;
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th, struct path *p_s_search_path, /* Path to the pasted item. */
+ const struct cpu_key *p_s_key, /* Key to search for the needed item. */
+ struct inode *inode, /* Inode item belongs to */
+ const char *p_c_body, /* Pointer to the bytes to paste. */
+ int n_pasted_size)
+{ /* Size of pasted bytes. */
+ struct tree_balance s_paste_balance;
+ int retval;
+ int fs_gen;
+
+ BUG_ON(!th->t_trans_id);
- BUG_ON (!th->t_trans_id);
-
- fs_gen = get_generation(inode->i_sb) ;
+ fs_gen = get_generation(inode->i_sb);
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): allocating %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
+ reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
+ "reiserquota paste_into_item(): allocating %u id=%u type=%c",
+ n_pasted_size, inode->i_uid,
+ key2type(&(p_s_key->on_disk_key)));
#endif
- if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) {
- pathrelse(p_s_search_path);
- return -EDQUOT;
- }
- init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size);
+ if (DQUOT_ALLOC_SPACE_NODIRTY(inode, n_pasted_size)) {
+ pathrelse(p_s_search_path);
+ return -EDQUOT;
+ }
+ init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path,
+ n_pasted_size);
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- s_paste_balance.key = p_s_key->on_disk_key;
+ s_paste_balance.key = p_s_key->on_disk_key;
#endif
- /* DQUOT_* can schedule, must check before the fix_nodes */
- if (fs_changed(fs_gen, inode->i_sb)) {
- goto search_again;
- }
-
- while ((retval = fix_nodes(M_PASTE, &s_paste_balance, NULL, p_c_body)) ==
-REPEAT_SEARCH ) {
-search_again:
- /* file system changed while we were in the fix_nodes */
- PROC_INFO_INC( th -> t_super, paste_into_item_restarted );
- retval = search_for_position_by_key (th->t_super, p_s_key, p_s_search_path);
- if (retval == IO_ERROR) {
- retval = -EIO ;
- goto error_out ;
+ /* DQUOT_* can schedule, must check before the fix_nodes */
+ if (fs_changed(fs_gen, inode->i_sb)) {
+ goto search_again;
}
- if (retval == POSITION_FOUND) {
- reiserfs_warning (inode->i_sb, "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists", p_s_key);
- retval = -EEXIST ;
- goto error_out ;
- }
-
+
+ while ((retval =
+ fix_nodes(M_PASTE, &s_paste_balance, NULL,
+ p_c_body)) == REPEAT_SEARCH) {
+ search_again:
+ /* file system changed while we were in the fix_nodes */
+ PROC_INFO_INC(th->t_super, paste_into_item_restarted);
+ retval =
+ search_for_position_by_key(th->t_super, p_s_key,
+ p_s_search_path);
+ if (retval == IO_ERROR) {
+ retval = -EIO;
+ goto error_out;
+ }
+ if (retval == POSITION_FOUND) {
+ reiserfs_warning(inode->i_sb,
+ "PAP-5710: reiserfs_paste_into_item: entry or pasted byte (%K) exists",
+ p_s_key);
+ retval = -EEXIST;
+ goto error_out;
+ }
#ifdef CONFIG_REISERFS_CHECK
- check_research_for_paste (p_s_search_path, p_s_key);
+ check_research_for_paste(p_s_search_path, p_s_key);
#endif
- }
+ }
- /* Perform balancing after all resources are collected by fix_nodes, and
- accessing them will not risk triggering schedule. */
- if ( retval == CARRY_ON ) {
- do_balance(&s_paste_balance, NULL/*ih*/, p_c_body, M_PASTE);
- return 0;
- }
- retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
-error_out:
- /* this also releases the path */
- unfix_nodes(&s_paste_balance);
+ /* Perform balancing after all resources are collected by fix_nodes, and
+ accessing them will not risk triggering schedule. */
+ if (retval == CARRY_ON) {
+ do_balance(&s_paste_balance, NULL /*ih */ , p_c_body, M_PASTE);
+ return 0;
+ }
+ retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+ error_out:
+ /* this also releases the path */
+ unfix_nodes(&s_paste_balance);
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota paste_into_item(): freeing %u id=%u type=%c", n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key)));
+ reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
+ "reiserquota paste_into_item(): freeing %u id=%u type=%c",
+ n_pasted_size, inode->i_uid,
+ key2type(&(p_s_key->on_disk_key)));
#endif
- DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size);
- return retval ;
+ DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size);
+ return retval;
}
-
/* Insert new item into the buffer at the path. */
-int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
- struct path * p_s_path, /* Path to the inserteded item. */
- const struct cpu_key * key,
- struct item_head * p_s_ih, /* Pointer to the item header to insert.*/
- struct inode * inode,
- const char * p_c_body) /* Pointer to the bytes to insert. */
-{
- struct tree_balance s_ins_balance;
- int retval;
- int fs_gen = 0 ;
- int quota_bytes = 0 ;
-
- BUG_ON (!th->t_trans_id);
-
- if (inode) { /* Do we count quotas for item? */
- fs_gen = get_generation(inode->i_sb);
- quota_bytes = ih_item_len(p_s_ih);
-
- /* hack so the quota code doesn't have to guess if the file has
- ** a tail, links are always tails, so there's no guessing needed
- */
- if (!S_ISLNK (inode->i_mode) && is_direct_le_ih(p_s_ih)) {
- quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE ;
- }
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th, struct path *p_s_path, /* Path to the inserteded item. */
+ const struct cpu_key *key, struct item_head *p_s_ih, /* Pointer to the item header to insert. */
+ struct inode *inode, const char *p_c_body)
+{ /* Pointer to the bytes to insert. */
+ struct tree_balance s_ins_balance;
+ int retval;
+ int fs_gen = 0;
+ int quota_bytes = 0;
+
+ BUG_ON(!th->t_trans_id);
+
+ if (inode) { /* Do we count quotas for item? */
+ fs_gen = get_generation(inode->i_sb);
+ quota_bytes = ih_item_len(p_s_ih);
+
+ /* hack so the quota code doesn't have to guess if the file has
+ ** a tail, links are always tails, so there's no guessing needed
+ */
+ if (!S_ISLNK(inode->i_mode) && is_direct_le_ih(p_s_ih)) {
+ quota_bytes = inode->i_sb->s_blocksize + UNFM_P_SIZE;
+ }
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (inode->i_sb, REISERFS_DEBUG_CODE, "reiserquota insert_item(): allocating %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih));
+ reiserfs_debug(inode->i_sb, REISERFS_DEBUG_CODE,
+ "reiserquota insert_item(): allocating %u id=%u type=%c",
+ quota_bytes, inode->i_uid, head2type(p_s_ih));
#endif
- /* We can't dirty inode here. It would be immediately written but
- * appropriate stat item isn't inserted yet... */
- if (DQUOT_ALLOC_SPACE_NODIRTY(inode, quota_bytes)) {
- pathrelse(p_s_path);
- return -EDQUOT;
+ /* We can't dirty inode here. It would be immediately written but
+ * appropriate stat item isn't inserted yet... */
+ if (DQUOT_ALLOC_SPACE_NODIRTY(inode, quota_bytes)) {
+ pathrelse(p_s_path);
+ return -EDQUOT;
+ }
}
- }
- init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih));
+ init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path,
+ IH_SIZE + ih_item_len(p_s_ih));
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- s_ins_balance.key = key->on_disk_key;
+ s_ins_balance.key = key->on_disk_key;
#endif
- /* DQUOT_* can schedule, must check to be sure calling fix_nodes is safe */
- if (inode && fs_changed(fs_gen, inode->i_sb)) {
- goto search_again;
- }
-
- while ( (retval = fix_nodes(M_INSERT, &s_ins_balance, p_s_ih, p_c_body)) == REPEAT_SEARCH) {
-search_again:
- /* file system changed while we were in the fix_nodes */
- PROC_INFO_INC( th -> t_super, insert_item_restarted );
- retval = search_item (th->t_super, key, p_s_path);
- if (retval == IO_ERROR) {
- retval = -EIO;
- goto error_out ;
+ /* DQUOT_* can schedule, must check to be sure calling fix_nodes is safe */
+ if (inode && fs_changed(fs_gen, inode->i_sb)) {
+ goto search_again;
}
- if (retval == ITEM_FOUND) {
- reiserfs_warning (th->t_super, "PAP-5760: reiserfs_insert_item: "
- "key %K already exists in the tree", key);
- retval = -EEXIST ;
- goto error_out;
+
+ while ((retval =
+ fix_nodes(M_INSERT, &s_ins_balance, p_s_ih,
+ p_c_body)) == REPEAT_SEARCH) {
+ search_again:
+ /* file system changed while we were in the fix_nodes */
+ PROC_INFO_INC(th->t_super, insert_item_restarted);
+ retval = search_item(th->t_super, key, p_s_path);
+ if (retval == IO_ERROR) {
+ retval = -EIO;
+ goto error_out;
+ }
+ if (retval == ITEM_FOUND) {
+ reiserfs_warning(th->t_super,
+ "PAP-5760: reiserfs_insert_item: "
+ "key %K already exists in the tree",
+ key);
+ retval = -EEXIST;
+ goto error_out;
+ }
}
- }
- /* make balancing after all resources will be collected at a time */
- if ( retval == CARRY_ON ) {
- do_balance (&s_ins_balance, p_s_ih, p_c_body, M_INSERT);
- return 0;
- }
+ /* make balancing after all resources will be collected at a time */
+ if (retval == CARRY_ON) {
+ do_balance(&s_ins_balance, p_s_ih, p_c_body, M_INSERT);
+ return 0;
+ }
- retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
-error_out:
- /* also releases the path */
- unfix_nodes(&s_ins_balance);
+ retval = (retval == NO_DISK_SPACE) ? -ENOSPC : -EIO;
+ error_out:
+ /* also releases the path */
+ unfix_nodes(&s_ins_balance);
#ifdef REISERQUOTA_DEBUG
- reiserfs_debug (th->t_super, REISERFS_DEBUG_CODE, "reiserquota insert_item(): freeing %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih));
+ reiserfs_debug(th->t_super, REISERFS_DEBUG_CODE,
+ "reiserquota insert_item(): freeing %u id=%u type=%c",
+ quota_bytes, inode->i_uid, head2type(p_s_ih));
#endif
- if (inode)
- DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes) ;
- return retval;
+ if (inode)
+ DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes);
+ return retval;
}
-
-
-
-
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index aae0779ed5b4..6951c35755be 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -35,83 +35,81 @@ static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;
static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;
static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;
-int is_reiserfs_3_5 (struct reiserfs_super_block * rs)
+int is_reiserfs_3_5(struct reiserfs_super_block *rs)
{
- return !strncmp (rs->s_v1.s_magic, reiserfs_3_5_magic_string,
- strlen (reiserfs_3_5_magic_string));
+ return !strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string,
+ strlen(reiserfs_3_5_magic_string));
}
-
-int is_reiserfs_3_6 (struct reiserfs_super_block * rs)
+int is_reiserfs_3_6(struct reiserfs_super_block *rs)
{
- return !strncmp (rs->s_v1.s_magic, reiserfs_3_6_magic_string,
- strlen (reiserfs_3_6_magic_string));
+ return !strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string,
+ strlen(reiserfs_3_6_magic_string));
}
-
-int is_reiserfs_jr (struct reiserfs_super_block * rs)
+int is_reiserfs_jr(struct reiserfs_super_block *rs)
{
- return !strncmp (rs->s_v1.s_magic, reiserfs_jr_magic_string,
- strlen (reiserfs_jr_magic_string));
+ return !strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string,
+ strlen(reiserfs_jr_magic_string));
}
-
-static int is_any_reiserfs_magic_string (struct reiserfs_super_block * rs)
+static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs)
{
- return (is_reiserfs_3_5 (rs) || is_reiserfs_3_6 (rs) ||
- is_reiserfs_jr (rs));
+ return (is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) ||
+ is_reiserfs_jr(rs));
}
-static int reiserfs_remount (struct super_block * s, int * flags, char * data);
-static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf);
+static int reiserfs_remount(struct super_block *s, int *flags, char *data);
+static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf);
-static int reiserfs_sync_fs (struct super_block * s, int wait)
+static int reiserfs_sync_fs(struct super_block *s, int wait)
{
- if (!(s->s_flags & MS_RDONLY)) {
- struct reiserfs_transaction_handle th;
- reiserfs_write_lock(s);
- if (!journal_begin(&th, s, 1))
- if (!journal_end_sync(&th, s, 1))
- reiserfs_flush_old_commits(s);
- s->s_dirt = 0; /* Even if it's not true.
- * We'll loop forever in sync_supers otherwise */
- reiserfs_write_unlock(s);
- } else {
- s->s_dirt = 0;
- }
- return 0;
+ if (!(s->s_flags & MS_RDONLY)) {
+ struct reiserfs_transaction_handle th;
+ reiserfs_write_lock(s);
+ if (!journal_begin(&th, s, 1))
+ if (!journal_end_sync(&th, s, 1))
+ reiserfs_flush_old_commits(s);
+ s->s_dirt = 0; /* Even if it's not true.
+ * We'll loop forever in sync_supers otherwise */
+ reiserfs_write_unlock(s);
+ } else {
+ s->s_dirt = 0;
+ }
+ return 0;
}
static void reiserfs_write_super(struct super_block *s)
{
- reiserfs_sync_fs(s, 1);
+ reiserfs_sync_fs(s, 1);
}
-static void reiserfs_write_super_lockfs (struct super_block * s)
+static void reiserfs_write_super_lockfs(struct super_block *s)
{
- struct reiserfs_transaction_handle th ;
- reiserfs_write_lock(s);
- if (!(s->s_flags & MS_RDONLY)) {
- int err = journal_begin(&th, s, 1) ;
- if (err) {
- reiserfs_block_writes(&th) ;
- } else {
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
- journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
- reiserfs_block_writes(&th) ;
- journal_end_sync(&th, s, 1) ;
- }
- }
- s->s_dirt = 0;
- reiserfs_write_unlock(s);
+ struct reiserfs_transaction_handle th;
+ reiserfs_write_lock(s);
+ if (!(s->s_flags & MS_RDONLY)) {
+ int err = journal_begin(&th, s, 1);
+ if (err) {
+ reiserfs_block_writes(&th);
+ } else {
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
+ 1);
+ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
+ reiserfs_block_writes(&th);
+ journal_end_sync(&th, s, 1);
+ }
+ }
+ s->s_dirt = 0;
+ reiserfs_write_unlock(s);
}
-static void reiserfs_unlockfs(struct super_block *s) {
- reiserfs_allow_writes(s) ;
+static void reiserfs_unlockfs(struct super_block *s)
+{
+ reiserfs_allow_writes(s);
}
-extern const struct in_core_key MAX_IN_CORE_KEY;
-
+extern const struct in_core_key MAX_IN_CORE_KEY;
/* this is used to delete "save link" when there are no items of a
file it points to. It can either happen if unlink is completed but
@@ -120,364 +118,387 @@ extern const struct in_core_key MAX_IN_CORE_KEY;
protecting unlink is bigger that a key lf "save link" which
protects truncate), so there left no items to make truncate
completion on */
-static int remove_save_link_only (struct super_block * s, struct reiserfs_key * key, int oid_free)
+static int remove_save_link_only(struct super_block *s,
+ struct reiserfs_key *key, int oid_free)
{
- struct reiserfs_transaction_handle th;
- int err;
-
- /* we are going to do one balancing */
- err = journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT);
- if (err)
- return err;
-
- reiserfs_delete_solid_item (&th, NULL, key);
- if (oid_free)
- /* removals are protected by direct items */
- reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid));
-
- return journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);
+ struct reiserfs_transaction_handle th;
+ int err;
+
+ /* we are going to do one balancing */
+ err = journal_begin(&th, s, JOURNAL_PER_BALANCE_CNT);
+ if (err)
+ return err;
+
+ reiserfs_delete_solid_item(&th, NULL, key);
+ if (oid_free)
+ /* removals are protected by direct items */
+ reiserfs_release_objectid(&th, le32_to_cpu(key->k_objectid));
+
+ return journal_end(&th, s, JOURNAL_PER_BALANCE_CNT);
}
-
+
#ifdef CONFIG_QUOTA
static int reiserfs_quota_on_mount(struct super_block *, int);
#endif
-
+
/* look for uncompleted unlinks and truncates and complete them */
-static int finish_unfinished (struct super_block * s)
+static int finish_unfinished(struct super_block *s)
{
- INITIALIZE_PATH (path);
- struct cpu_key max_cpu_key, obj_key;
- struct reiserfs_key save_link_key;
- int retval = 0;
- struct item_head * ih;
- struct buffer_head * bh;
- int item_pos;
- char * item;
- int done;
- struct inode * inode;
- int truncate;
+ INITIALIZE_PATH(path);
+ struct cpu_key max_cpu_key, obj_key;
+ struct reiserfs_key save_link_key;
+ int retval = 0;
+ struct item_head *ih;
+ struct buffer_head *bh;
+ int item_pos;
+ char *item;
+ int done;
+ struct inode *inode;
+ int truncate;
#ifdef CONFIG_QUOTA
- int i;
- int ms_active_set;
+ int i;
+ int ms_active_set;
#endif
-
-
- /* compose key to look for "save" links */
- max_cpu_key.version = KEY_FORMAT_3_5;
- max_cpu_key.on_disk_key.k_dir_id = ~0U;
- max_cpu_key.on_disk_key.k_objectid = ~0U;
- set_cpu_key_k_offset (&max_cpu_key, ~0U);
- max_cpu_key.key_length = 3;
+
+ /* compose key to look for "save" links */
+ max_cpu_key.version = KEY_FORMAT_3_5;
+ max_cpu_key.on_disk_key.k_dir_id = ~0U;
+ max_cpu_key.on_disk_key.k_objectid = ~0U;
+ set_cpu_key_k_offset(&max_cpu_key, ~0U);
+ max_cpu_key.key_length = 3;
#ifdef CONFIG_QUOTA
- /* Needed for iput() to work correctly and not trash data */
- if (s->s_flags & MS_ACTIVE) {
- ms_active_set = 0;
- } else {
- ms_active_set = 1;
- s->s_flags |= MS_ACTIVE;
- }
- /* Turn on quotas so that they are updated correctly */
- for (i = 0; i < MAXQUOTAS; i++) {
- if (REISERFS_SB(s)->s_qf_names[i]) {
- int ret = reiserfs_quota_on_mount(s, i);
- if (ret < 0)
- reiserfs_warning(s, "reiserfs: cannot turn on journalled quota: error %d", ret);
- }
- }
+ /* Needed for iput() to work correctly and not trash data */
+ if (s->s_flags & MS_ACTIVE) {
+ ms_active_set = 0;
+ } else {
+ ms_active_set = 1;
+ s->s_flags |= MS_ACTIVE;
+ }
+ /* Turn on quotas so that they are updated correctly */
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (REISERFS_SB(s)->s_qf_names[i]) {
+ int ret = reiserfs_quota_on_mount(s, i);
+ if (ret < 0)
+ reiserfs_warning(s,
+ "reiserfs: cannot turn on journalled quota: error %d",
+ ret);
+ }
+ }
#endif
-
- done = 0;
- REISERFS_SB(s)->s_is_unlinked_ok = 1;
- while (!retval) {
- retval = search_item (s, &max_cpu_key, &path);
- if (retval != ITEM_NOT_FOUND) {
- reiserfs_warning (s, "vs-2140: finish_unfinished: search_by_key returned %d",
- retval);
- break;
- }
-
- bh = get_last_bh (&path);
- item_pos = get_item_pos (&path);
- if (item_pos != B_NR_ITEMS (bh)) {
- reiserfs_warning (s, "vs-2060: finish_unfinished: wrong position found");
- break;
- }
- item_pos --;
- ih = B_N_PITEM_HEAD (bh, item_pos);
-
- if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
- /* there are no "save" links anymore */
- break;
-
- save_link_key = ih->ih_key;
- if (is_indirect_le_ih (ih))
- truncate = 1;
- else
- truncate = 0;
-
- /* reiserfs_iget needs k_dirid and k_objectid only */
- item = B_I_PITEM (bh, ih);
- obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__le32 *)item);
- obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid);
- obj_key.on_disk_key.k_offset = 0;
- obj_key.on_disk_key.k_type = 0;
-
- pathrelse (&path);
-
- inode = reiserfs_iget (s, &obj_key);
- if (!inode) {
- /* the unlink almost completed, it just did not manage to remove
- "save" link and release objectid */
- reiserfs_warning (s, "vs-2180: finish_unfinished: iget failed for %K",
- &obj_key);
- retval = remove_save_link_only (s, &save_link_key, 1);
- continue;
- }
-
- if (!truncate && inode->i_nlink) {
- /* file is not unlinked */
- reiserfs_warning (s, "vs-2185: finish_unfinished: file %K is not unlinked",
- &obj_key);
- retval = remove_save_link_only (s, &save_link_key, 0);
- continue;
- }
- DQUOT_INIT(inode);
-
- if (truncate && S_ISDIR (inode->i_mode) ) {
- /* We got a truncate request for a dir which is impossible.
- The only imaginable way is to execute unfinished truncate request
- then boot into old kernel, remove the file and create dir with
- the same key. */
- reiserfs_warning(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY (inode));
- retval = remove_save_link_only (s, &save_link_key, 0);
- truncate = 0;
- iput (inode);
- continue;
- }
-
- if (truncate) {
- REISERFS_I(inode) -> i_flags |= i_link_saved_truncate_mask;
- /* not completed truncate found. New size was committed together
- with "save" link */
- reiserfs_info (s, "Truncating %k to %Ld ..",
- INODE_PKEY (inode), inode->i_size);
- reiserfs_truncate_file (inode, 0/*don't update modification time*/);
- retval = remove_save_link (inode, truncate);
- } else {
- REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask;
- /* not completed unlink (rmdir) found */
- reiserfs_info (s, "Removing %k..", INODE_PKEY (inode));
- /* removal gets completed in iput */
- retval = 0;
- }
-
- iput (inode);
- printk ("done\n");
- done ++;
- }
- REISERFS_SB(s)->s_is_unlinked_ok = 0;
-
+
+ done = 0;
+ REISERFS_SB(s)->s_is_unlinked_ok = 1;
+ while (!retval) {
+ retval = search_item(s, &max_cpu_key, &path);
+ if (retval != ITEM_NOT_FOUND) {
+ reiserfs_warning(s,
+ "vs-2140: finish_unfinished: search_by_key returned %d",
+ retval);
+ break;
+ }
+
+ bh = get_last_bh(&path);
+ item_pos = get_item_pos(&path);
+ if (item_pos != B_NR_ITEMS(bh)) {
+ reiserfs_warning(s,
+ "vs-2060: finish_unfinished: wrong position found");
+ break;
+ }
+ item_pos--;
+ ih = B_N_PITEM_HEAD(bh, item_pos);
+
+ if (le32_to_cpu(ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID)
+ /* there are no "save" links anymore */
+ break;
+
+ save_link_key = ih->ih_key;
+ if (is_indirect_le_ih(ih))
+ truncate = 1;
+ else
+ truncate = 0;
+
+ /* reiserfs_iget needs k_dirid and k_objectid only */
+ item = B_I_PITEM(bh, ih);
+ obj_key.on_disk_key.k_dir_id = le32_to_cpu(*(__le32 *) item);
+ obj_key.on_disk_key.k_objectid =
+ le32_to_cpu(ih->ih_key.k_objectid);
+ obj_key.on_disk_key.k_offset = 0;
+ obj_key.on_disk_key.k_type = 0;
+
+ pathrelse(&path);
+
+ inode = reiserfs_iget(s, &obj_key);
+ if (!inode) {
+ /* the unlink almost completed, it just did not manage to remove
+ "save" link and release objectid */
+ reiserfs_warning(s,
+ "vs-2180: finish_unfinished: iget failed for %K",
+ &obj_key);
+ retval = remove_save_link_only(s, &save_link_key, 1);
+ continue;
+ }
+
+ if (!truncate && inode->i_nlink) {
+ /* file is not unlinked */
+ reiserfs_warning(s,
+ "vs-2185: finish_unfinished: file %K is not unlinked",
+ &obj_key);
+ retval = remove_save_link_only(s, &save_link_key, 0);
+ continue;
+ }
+ DQUOT_INIT(inode);
+
+ if (truncate && S_ISDIR(inode->i_mode)) {
+ /* We got a truncate request for a dir which is impossible.
+ The only imaginable way is to execute unfinished truncate request
+ then boot into old kernel, remove the file and create dir with
+ the same key. */
+ reiserfs_warning(s,
+ "green-2101: impossible truncate on a directory %k. Please report",
+ INODE_PKEY(inode));
+ retval = remove_save_link_only(s, &save_link_key, 0);
+ truncate = 0;
+ iput(inode);
+ continue;
+ }
+
+ if (truncate) {
+ REISERFS_I(inode)->i_flags |=
+ i_link_saved_truncate_mask;
+ /* not completed truncate found. New size was committed together
+ with "save" link */
+ reiserfs_info(s, "Truncating %k to %Ld ..",
+ INODE_PKEY(inode), inode->i_size);
+ reiserfs_truncate_file(inode,
+ 0
+ /*don't update modification time */
+ );
+ retval = remove_save_link(inode, truncate);
+ } else {
+ REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
+ /* not completed unlink (rmdir) found */
+ reiserfs_info(s, "Removing %k..", INODE_PKEY(inode));
+ /* removal gets completed in iput */
+ retval = 0;
+ }
+
+ iput(inode);
+ printk("done\n");
+ done++;
+ }
+ REISERFS_SB(s)->s_is_unlinked_ok = 0;
+
#ifdef CONFIG_QUOTA
- /* Turn quotas off */
- for (i = 0; i < MAXQUOTAS; i++) {
- if (sb_dqopt(s)->files[i])
- vfs_quota_off_mount(s, i);
- }
- if (ms_active_set)
- /* Restore the flag back */
- s->s_flags &= ~MS_ACTIVE;
+ /* Turn quotas off */
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (sb_dqopt(s)->files[i])
+ vfs_quota_off_mount(s, i);
+ }
+ if (ms_active_set)
+ /* Restore the flag back */
+ s->s_flags &= ~MS_ACTIVE;
#endif
- pathrelse (&path);
- if (done)
- reiserfs_info (s, "There were %d uncompleted unlinks/truncates. "
- "Completed\n", done);
- return retval;
+ pathrelse(&path);
+ if (done)
+ reiserfs_info(s, "There were %d uncompleted unlinks/truncates. "
+ "Completed\n", done);
+ return retval;
}
-
+
/* to protect file being unlinked from getting lost we "safe" link files
being unlinked. This link will be deleted in the same transaction with last
item of file. mounting the filesytem we scan all these links and remove
files which almost got lost */
-void add_save_link (struct reiserfs_transaction_handle * th,
- struct inode * inode, int truncate)
+void add_save_link(struct reiserfs_transaction_handle *th,
+ struct inode *inode, int truncate)
{
- INITIALIZE_PATH (path);
- int retval;
- struct cpu_key key;
- struct item_head ih;
- __le32 link;
-
- BUG_ON (!th->t_trans_id);
-
- /* file can only get one "save link" of each kind */
- RFALSE( truncate &&
- ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ),
- "saved link already exists for truncated inode %lx",
- ( long ) inode -> i_ino );
- RFALSE( !truncate &&
- ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ),
- "saved link already exists for unlinked inode %lx",
- ( long ) inode -> i_ino );
-
- /* setup key of "save" link */
- key.version = KEY_FORMAT_3_5;
- key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
- key.on_disk_key.k_objectid = inode->i_ino;
- if (!truncate) {
- /* unlink, rmdir, rename */
- set_cpu_key_k_offset (&key, 1 + inode->i_sb->s_blocksize);
- set_cpu_key_k_type (&key, TYPE_DIRECT);
-
- /* item head of "safe" link */
- make_le_item_head (&ih, &key, key.version, 1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
- 4/*length*/, 0xffff/*free space*/);
- } else {
- /* truncate */
- if (S_ISDIR (inode->i_mode))
- reiserfs_warning(inode->i_sb, "green-2102: Adding a truncate savelink for a directory %k! Please report", INODE_PKEY(inode));
- set_cpu_key_k_offset (&key, 1);
- set_cpu_key_k_type (&key, TYPE_INDIRECT);
-
- /* item head of "safe" link */
- make_le_item_head (&ih, &key, key.version, 1, TYPE_INDIRECT,
- 4/*length*/, 0/*free space*/);
- }
- key.key_length = 3;
-
- /* look for its place in the tree */
- retval = search_item (inode->i_sb, &key, &path);
- if (retval != ITEM_NOT_FOUND) {
- if ( retval != -ENOSPC )
- reiserfs_warning (inode->i_sb, "vs-2100: add_save_link:"
- "search_by_key (%K) returned %d", &key, retval);
- pathrelse (&path);
- return;
- }
-
- /* body of "save" link */
- link = INODE_PKEY (inode)->k_dir_id;
-
- /* put "save" link inot tree, don't charge quota to anyone */
- retval = reiserfs_insert_item (th, &path, &key, &ih, NULL, (char *)&link);
- if (retval) {
- if (retval != -ENOSPC)
- reiserfs_warning (inode->i_sb, "vs-2120: add_save_link: insert_item returned %d",
- retval);
- } else {
- if( truncate )
- REISERFS_I(inode) -> i_flags |= i_link_saved_truncate_mask;
- else
- REISERFS_I(inode) -> i_flags |= i_link_saved_unlink_mask;
- }
-}
+ INITIALIZE_PATH(path);
+ int retval;
+ struct cpu_key key;
+ struct item_head ih;
+ __le32 link;
+
+ BUG_ON(!th->t_trans_id);
+
+ /* file can only get one "save link" of each kind */
+ RFALSE(truncate &&
+ (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask),
+ "saved link already exists for truncated inode %lx",
+ (long)inode->i_ino);
+ RFALSE(!truncate &&
+ (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask),
+ "saved link already exists for unlinked inode %lx",
+ (long)inode->i_ino);
+
+ /* setup key of "save" link */
+ key.version = KEY_FORMAT_3_5;
+ key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID;
+ key.on_disk_key.k_objectid = inode->i_ino;
+ if (!truncate) {
+ /* unlink, rmdir, rename */
+ set_cpu_key_k_offset(&key, 1 + inode->i_sb->s_blocksize);
+ set_cpu_key_k_type(&key, TYPE_DIRECT);
+
+ /* item head of "safe" link */
+ make_le_item_head(&ih, &key, key.version,
+ 1 + inode->i_sb->s_blocksize, TYPE_DIRECT,
+ 4 /*length */ , 0xffff /*free space */ );
+ } else {
+ /* truncate */
+ if (S_ISDIR(inode->i_mode))
+ reiserfs_warning(inode->i_sb,
+ "green-2102: Adding a truncate savelink for a directory %k! Please report",
+ INODE_PKEY(inode));
+ set_cpu_key_k_offset(&key, 1);
+ set_cpu_key_k_type(&key, TYPE_INDIRECT);
+
+ /* item head of "safe" link */
+ make_le_item_head(&ih, &key, key.version, 1, TYPE_INDIRECT,
+ 4 /*length */ , 0 /*free space */ );
+ }
+ key.key_length = 3;
+
+ /* look for its place in the tree */
+ retval = search_item(inode->i_sb, &key, &path);
+ if (retval != ITEM_NOT_FOUND) {
+ if (retval != -ENOSPC)
+ reiserfs_warning(inode->i_sb, "vs-2100: add_save_link:"
+ "search_by_key (%K) returned %d", &key,
+ retval);
+ pathrelse(&path);
+ return;
+ }
+ /* body of "save" link */
+ link = INODE_PKEY(inode)->k_dir_id;
+
+ /* put "save" link inot tree, don't charge quota to anyone */
+ retval =
+ reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link);
+ if (retval) {
+ if (retval != -ENOSPC)
+ reiserfs_warning(inode->i_sb,
+ "vs-2120: add_save_link: insert_item returned %d",
+ retval);
+ } else {
+ if (truncate)
+ REISERFS_I(inode)->i_flags |=
+ i_link_saved_truncate_mask;
+ else
+ REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask;
+ }
+}
/* this opens transaction unlike add_save_link */
-int remove_save_link (struct inode * inode, int truncate)
+int remove_save_link(struct inode *inode, int truncate)
{
- struct reiserfs_transaction_handle th;
- struct reiserfs_key key;
- int err;
-
- /* we are going to do one balancing only */
- err = journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
- if (err)
- return err;
-
- /* setup key of "save" link */
- key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID);
- key.k_objectid = INODE_PKEY (inode)->k_objectid;
- if (!truncate) {
- /* unlink, rmdir, rename */
- set_le_key_k_offset (KEY_FORMAT_3_5, &key,
- 1 + inode->i_sb->s_blocksize);
- set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_DIRECT);
- } else {
- /* truncate */
- set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1);
- set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
- }
-
- if( ( truncate &&
- ( REISERFS_I(inode) -> i_flags & i_link_saved_truncate_mask ) ) ||
- ( !truncate &&
- ( REISERFS_I(inode) -> i_flags & i_link_saved_unlink_mask ) ) )
- /* don't take quota bytes from anywhere */
- reiserfs_delete_solid_item (&th, NULL, &key);
- if (!truncate) {
- reiserfs_release_objectid (&th, inode->i_ino);
- REISERFS_I(inode) -> i_flags &= ~i_link_saved_unlink_mask;
- } else
- REISERFS_I(inode) -> i_flags &= ~i_link_saved_truncate_mask;
-
- return journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
-}
+ struct reiserfs_transaction_handle th;
+ struct reiserfs_key key;
+ int err;
+
+ /* we are going to do one balancing only */
+ err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+ if (err)
+ return err;
+
+ /* setup key of "save" link */
+ key.k_dir_id = cpu_to_le32(MAX_KEY_OBJECTID);
+ key.k_objectid = INODE_PKEY(inode)->k_objectid;
+ if (!truncate) {
+ /* unlink, rmdir, rename */
+ set_le_key_k_offset(KEY_FORMAT_3_5, &key,
+ 1 + inode->i_sb->s_blocksize);
+ set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_DIRECT);
+ } else {
+ /* truncate */
+ set_le_key_k_offset(KEY_FORMAT_3_5, &key, 1);
+ set_le_key_k_type(KEY_FORMAT_3_5, &key, TYPE_INDIRECT);
+ }
+ if ((truncate &&
+ (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask)) ||
+ (!truncate &&
+ (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask)))
+ /* don't take quota bytes from anywhere */
+ reiserfs_delete_solid_item(&th, NULL, &key);
+ if (!truncate) {
+ reiserfs_release_objectid(&th, inode->i_ino);
+ REISERFS_I(inode)->i_flags &= ~i_link_saved_unlink_mask;
+ } else
+ REISERFS_I(inode)->i_flags &= ~i_link_saved_truncate_mask;
+
+ return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);
+}
-static void reiserfs_put_super (struct super_block * s)
+static void reiserfs_put_super(struct super_block *s)
{
- int i;
- struct reiserfs_transaction_handle th ;
- th.t_trans_id = 0;
-
- if (REISERFS_SB(s)->xattr_root) {
- d_invalidate (REISERFS_SB(s)->xattr_root);
- dput (REISERFS_SB(s)->xattr_root);
- }
-
- if (REISERFS_SB(s)->priv_root) {
- d_invalidate (REISERFS_SB(s)->priv_root);
- dput (REISERFS_SB(s)->priv_root);
- }
-
- /* change file system state to current state if it was mounted with read-write permissions */
- if (!(s->s_flags & MS_RDONLY)) {
- if (!journal_begin(&th, s, 10)) {
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
- set_sb_umount_state( SB_DISK_SUPER_BLOCK(s), REISERFS_SB(s)->s_mount_state );
- journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
- }
- }
-
- /* note, journal_release checks for readonly mount, and can decide not
- ** to do a journal_end
- */
- journal_release(&th, s) ;
-
- for (i = 0; i < SB_BMAP_NR (s); i ++)
- brelse (SB_AP_BITMAP (s)[i].bh);
-
- vfree (SB_AP_BITMAP (s));
-
- brelse (SB_BUFFER_WITH_SB (s));
-
- print_statistics (s);
-
- if (REISERFS_SB(s)->s_kmallocs != 0) {
- reiserfs_warning (s, "vs-2004: reiserfs_put_super: allocated memory left %d",
- REISERFS_SB(s)->s_kmallocs);
- }
-
- if (REISERFS_SB(s)->reserved_blocks != 0) {
- reiserfs_warning (s, "green-2005: reiserfs_put_super: reserved blocks left %d",
- REISERFS_SB(s)->reserved_blocks);
- }
-
- reiserfs_proc_info_done( s );
-
- kfree(s->s_fs_info);
- s->s_fs_info = NULL;
-
- return;
+ int i;
+ struct reiserfs_transaction_handle th;
+ th.t_trans_id = 0;
+
+ if (REISERFS_SB(s)->xattr_root) {
+ d_invalidate(REISERFS_SB(s)->xattr_root);
+ dput(REISERFS_SB(s)->xattr_root);
+ }
+
+ if (REISERFS_SB(s)->priv_root) {
+ d_invalidate(REISERFS_SB(s)->priv_root);
+ dput(REISERFS_SB(s)->priv_root);
+ }
+
+ /* change file system state to current state if it was mounted with read-write permissions */
+ if (!(s->s_flags & MS_RDONLY)) {
+ if (!journal_begin(&th, s, 10)) {
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s),
+ 1);
+ set_sb_umount_state(SB_DISK_SUPER_BLOCK(s),
+ REISERFS_SB(s)->s_mount_state);
+ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
+ }
+ }
+
+ /* note, journal_release checks for readonly mount, and can decide not
+ ** to do a journal_end
+ */
+ journal_release(&th, s);
+
+ for (i = 0; i < SB_BMAP_NR(s); i++)
+ brelse(SB_AP_BITMAP(s)[i].bh);
+
+ vfree(SB_AP_BITMAP(s));
+
+ brelse(SB_BUFFER_WITH_SB(s));
+
+ print_statistics(s);
+
+ if (REISERFS_SB(s)->s_kmallocs != 0) {
+ reiserfs_warning(s,
+ "vs-2004: reiserfs_put_super: allocated memory left %d",
+ REISERFS_SB(s)->s_kmallocs);
+ }
+
+ if (REISERFS_SB(s)->reserved_blocks != 0) {
+ reiserfs_warning(s,
+ "green-2005: reiserfs_put_super: reserved blocks left %d",
+ REISERFS_SB(s)->reserved_blocks);
+ }
+
+ reiserfs_proc_info_done(s);
+
+ kfree(s->s_fs_info);
+ s->s_fs_info = NULL;
+
+ return;
}
-static kmem_cache_t * reiserfs_inode_cachep;
+static kmem_cache_t *reiserfs_inode_cachep;
static struct inode *reiserfs_alloc_inode(struct super_block *sb)
{
struct reiserfs_inode_info *ei;
- ei = (struct reiserfs_inode_info *)kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
+ ei = (struct reiserfs_inode_info *)
+ kmem_cache_alloc(reiserfs_inode_cachep, SLAB_KERNEL);
if (!ei)
return NULL;
return &ei->vfs_inode;
@@ -488,25 +509,26 @@ static void reiserfs_destroy_inode(struct inode *inode)
kmem_cache_free(reiserfs_inode_cachep, REISERFS_I(inode));
}
-static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
+static void init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
{
- struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *) foo;
+ struct reiserfs_inode_info *ei = (struct reiserfs_inode_info *)foo;
- if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
SLAB_CTOR_CONSTRUCTOR) {
- INIT_LIST_HEAD(&ei->i_prealloc_list) ;
+ INIT_LIST_HEAD(&ei->i_prealloc_list);
inode_init_once(&ei->vfs_inode);
ei->i_acl_access = NULL;
ei->i_acl_default = NULL;
}
}
-
+
static int init_inodecache(void)
{
reiserfs_inode_cachep = kmem_cache_create("reiser_inode_cache",
- sizeof(struct reiserfs_inode_info),
- 0, SLAB_RECLAIM_ACCOUNT,
- init_once, NULL);
+ sizeof(struct
+ reiserfs_inode_info),
+ 0, SLAB_RECLAIM_ACCOUNT,
+ init_once, NULL);
if (reiserfs_inode_cachep == NULL)
return -ENOMEM;
return 0;
@@ -515,72 +537,76 @@ static int init_inodecache(void)
static void destroy_inodecache(void)
{
if (kmem_cache_destroy(reiserfs_inode_cachep))
- reiserfs_warning (NULL, "reiserfs_inode_cache: not all structures were freed");
+ reiserfs_warning(NULL,
+ "reiserfs_inode_cache: not all structures were freed");
}
/* we don't mark inodes dirty, we just log them */
-static void reiserfs_dirty_inode (struct inode * inode) {
- struct reiserfs_transaction_handle th ;
-
- int err = 0;
- if (inode->i_sb->s_flags & MS_RDONLY) {
- reiserfs_warning(inode->i_sb, "clm-6006: writing inode %lu on readonly FS",
- inode->i_ino) ;
- return ;
- }
- reiserfs_write_lock(inode->i_sb);
-
- /* this is really only used for atime updates, so they don't have
- ** to be included in O_SYNC or fsync
- */
- err = journal_begin(&th, inode->i_sb, 1) ;
- if (err) {
- reiserfs_write_unlock (inode->i_sb);
- return;
- }
- reiserfs_update_sd (&th, inode);
- journal_end(&th, inode->i_sb, 1) ;
- reiserfs_write_unlock(inode->i_sb);
+static void reiserfs_dirty_inode(struct inode *inode)
+{
+ struct reiserfs_transaction_handle th;
+
+ int err = 0;
+ if (inode->i_sb->s_flags & MS_RDONLY) {
+ reiserfs_warning(inode->i_sb,
+ "clm-6006: writing inode %lu on readonly FS",
+ inode->i_ino);
+ return;
+ }
+ reiserfs_write_lock(inode->i_sb);
+
+ /* this is really only used for atime updates, so they don't have
+ ** to be included in O_SYNC or fsync
+ */
+ err = journal_begin(&th, inode->i_sb, 1);
+ if (err) {
+ reiserfs_write_unlock(inode->i_sb);
+ return;
+ }
+ reiserfs_update_sd(&th, inode);
+ journal_end(&th, inode->i_sb, 1);
+ reiserfs_write_unlock(inode->i_sb);
}
-static void reiserfs_clear_inode (struct inode *inode)
+static void reiserfs_clear_inode(struct inode *inode)
{
- struct posix_acl *acl;
+ struct posix_acl *acl;
- acl = REISERFS_I(inode)->i_acl_access;
- if (acl && !IS_ERR (acl))
- posix_acl_release (acl);
- REISERFS_I(inode)->i_acl_access = NULL;
+ acl = REISERFS_I(inode)->i_acl_access;
+ if (acl && !IS_ERR(acl))
+ posix_acl_release(acl);
+ REISERFS_I(inode)->i_acl_access = NULL;
- acl = REISERFS_I(inode)->i_acl_default;
- if (acl && !IS_ERR (acl))
- posix_acl_release (acl);
- REISERFS_I(inode)->i_acl_default = NULL;
+ acl = REISERFS_I(inode)->i_acl_default;
+ if (acl && !IS_ERR(acl))
+ posix_acl_release(acl);
+ REISERFS_I(inode)->i_acl_default = NULL;
}
#ifdef CONFIG_QUOTA
-static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, size_t, loff_t);
-static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t, loff_t);
+static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
+ size_t, loff_t);
+static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t,
+ loff_t);
#endif
-static struct super_operations reiserfs_sops =
-{
- .alloc_inode = reiserfs_alloc_inode,
- .destroy_inode = reiserfs_destroy_inode,
- .write_inode = reiserfs_write_inode,
- .dirty_inode = reiserfs_dirty_inode,
- .delete_inode = reiserfs_delete_inode,
- .clear_inode = reiserfs_clear_inode,
- .put_super = reiserfs_put_super,
- .write_super = reiserfs_write_super,
- .sync_fs = reiserfs_sync_fs,
- .write_super_lockfs = reiserfs_write_super_lockfs,
- .unlockfs = reiserfs_unlockfs,
- .statfs = reiserfs_statfs,
- .remount_fs = reiserfs_remount,
+static struct super_operations reiserfs_sops = {
+ .alloc_inode = reiserfs_alloc_inode,
+ .destroy_inode = reiserfs_destroy_inode,
+ .write_inode = reiserfs_write_inode,
+ .dirty_inode = reiserfs_dirty_inode,
+ .delete_inode = reiserfs_delete_inode,
+ .clear_inode = reiserfs_clear_inode,
+ .put_super = reiserfs_put_super,
+ .write_super = reiserfs_write_super,
+ .sync_fs = reiserfs_sync_fs,
+ .write_super_lockfs = reiserfs_write_super_lockfs,
+ .unlockfs = reiserfs_unlockfs,
+ .statfs = reiserfs_statfs,
+ .remount_fs = reiserfs_remount,
#ifdef CONFIG_QUOTA
- .quota_read = reiserfs_quota_read,
- .quota_write = reiserfs_quota_write,
+ .quota_read = reiserfs_quota_read,
+ .quota_write = reiserfs_quota_write,
#endif
};
@@ -596,50 +622,48 @@ static int reiserfs_mark_dquot_dirty(struct dquot *);
static int reiserfs_write_info(struct super_block *, int);
static int reiserfs_quota_on(struct super_block *, int, int, char *);
-static struct dquot_operations reiserfs_quota_operations =
-{
- .initialize = reiserfs_dquot_initialize,
- .drop = reiserfs_dquot_drop,
- .alloc_space = dquot_alloc_space,
- .alloc_inode = dquot_alloc_inode,
- .free_space = dquot_free_space,
- .free_inode = dquot_free_inode,
- .transfer = dquot_transfer,
- .write_dquot = reiserfs_write_dquot,
- .acquire_dquot = reiserfs_acquire_dquot,
- .release_dquot = reiserfs_release_dquot,
- .mark_dirty = reiserfs_mark_dquot_dirty,
- .write_info = reiserfs_write_info,
+static struct dquot_operations reiserfs_quota_operations = {
+ .initialize = reiserfs_dquot_initialize,
+ .drop = reiserfs_dquot_drop,
+ .alloc_space = dquot_alloc_space,
+ .alloc_inode = dquot_alloc_inode,
+ .free_space = dquot_free_space,
+ .free_inode = dquot_free_inode,
+ .transfer = dquot_transfer,
+ .write_dquot = reiserfs_write_dquot,
+ .acquire_dquot = reiserfs_acquire_dquot,
+ .release_dquot = reiserfs_release_dquot,
+ .mark_dirty = reiserfs_mark_dquot_dirty,
+ .write_info = reiserfs_write_info,
};
-static struct quotactl_ops reiserfs_qctl_operations =
-{
- .quota_on = reiserfs_quota_on,
- .quota_off = vfs_quota_off,
- .quota_sync = vfs_quota_sync,
- .get_info = vfs_get_dqinfo,
- .set_info = vfs_set_dqinfo,
- .get_dqblk = vfs_get_dqblk,
- .set_dqblk = vfs_set_dqblk,
+static struct quotactl_ops reiserfs_qctl_operations = {
+ .quota_on = reiserfs_quota_on,
+ .quota_off = vfs_quota_off,
+ .quota_sync = vfs_quota_sync,
+ .get_info = vfs_get_dqinfo,
+ .set_info = vfs_set_dqinfo,
+ .get_dqblk = vfs_get_dqblk,
+ .set_dqblk = vfs_set_dqblk,
};
#endif
static struct export_operations reiserfs_export_ops = {
- .encode_fh = reiserfs_encode_fh,
- .decode_fh = reiserfs_decode_fh,
- .get_parent = reiserfs_get_parent,
- .get_dentry = reiserfs_get_dentry,
-} ;
+ .encode_fh = reiserfs_encode_fh,
+ .decode_fh = reiserfs_decode_fh,
+ .get_parent = reiserfs_get_parent,
+ .get_dentry = reiserfs_get_dentry,
+};
/* this struct is used in reiserfs_getopt () for containing the value for those
mount options that have values rather than being toggles. */
typedef struct {
- char * value;
- int setmask; /* bitmask which is to set on mount_options bitmask when this
- value is found, 0 is no bits are to be changed. */
- int clrmask; /* bitmask which is to clear on mount_options bitmask when this
- value is found, 0 is no bits are to be changed. This is
- applied BEFORE setmask */
+ char *value;
+ int setmask; /* bitmask which is to set on mount_options bitmask when this
+ value is found, 0 is no bits are to be changed. */
+ int clrmask; /* bitmask which is to clear on mount_options bitmask when this
+ value is found, 0 is no bits are to be changed. This is
+ applied BEFORE setmask */
} arg_desc_t;
/* Set this bit in arg_required to allow empty arguments */
@@ -648,67 +672,70 @@ typedef struct {
/* this struct is used in reiserfs_getopt() for describing the set of reiserfs
mount options */
typedef struct {
- char * option_name;
- int arg_required; /* 0 if argument is not required, not 0 otherwise */
- const arg_desc_t * values; /* list of values accepted by an option */
- int setmask; /* bitmask which is to set on mount_options bitmask when this
- value is found, 0 is no bits are to be changed. */
- int clrmask; /* bitmask which is to clear on mount_options bitmask when this
- value is found, 0 is no bits are to be changed. This is
- applied BEFORE setmask */
+ char *option_name;
+ int arg_required; /* 0 if argument is not required, not 0 otherwise */
+ const arg_desc_t *values; /* list of values accepted by an option */
+ int setmask; /* bitmask which is to set on mount_options bitmask when this
+ value is found, 0 is no bits are to be changed. */
+ int clrmask; /* bitmask which is to clear on mount_options bitmask when this
+ value is found, 0 is no bits are to be changed. This is
+ applied BEFORE setmask */
} opt_desc_t;
/* possible values for -o data= */
static const arg_desc_t logging_mode[] = {
- {"ordered", 1<<REISERFS_DATA_ORDERED, (1<<REISERFS_DATA_LOG|1<<REISERFS_DATA_WRITEBACK)},
- {"journal", 1<<REISERFS_DATA_LOG, (1<<REISERFS_DATA_ORDERED|1<<REISERFS_DATA_WRITEBACK)},
- {"writeback", 1<<REISERFS_DATA_WRITEBACK, (1<<REISERFS_DATA_ORDERED|1<<REISERFS_DATA_LOG)},
- {NULL, 0}
+ {"ordered", 1 << REISERFS_DATA_ORDERED,
+ (1 << REISERFS_DATA_LOG | 1 << REISERFS_DATA_WRITEBACK)},
+ {"journal", 1 << REISERFS_DATA_LOG,
+ (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_WRITEBACK)},
+ {"writeback", 1 << REISERFS_DATA_WRITEBACK,
+ (1 << REISERFS_DATA_ORDERED | 1 << REISERFS_DATA_LOG)},
+ {NULL, 0}
};
/* possible values for -o barrier= */
static const arg_desc_t barrier_mode[] = {
- {"none", 1<<REISERFS_BARRIER_NONE, 1<<REISERFS_BARRIER_FLUSH},
- {"flush", 1<<REISERFS_BARRIER_FLUSH, 1<<REISERFS_BARRIER_NONE},
- {NULL, 0}
+ {"none", 1 << REISERFS_BARRIER_NONE, 1 << REISERFS_BARRIER_FLUSH},
+ {"flush", 1 << REISERFS_BARRIER_FLUSH, 1 << REISERFS_BARRIER_NONE},
+ {NULL, 0}
};
/* possible values for "-o block-allocator=" and bits which are to be set in
s_mount_opt of reiserfs specific part of in-core super block */
static const arg_desc_t balloc[] = {
- {"noborder", 1<<REISERFS_NO_BORDER, 0},
- {"border", 0, 1<<REISERFS_NO_BORDER},
- {"no_unhashed_relocation", 1<<REISERFS_NO_UNHASHED_RELOCATION, 0},
- {"hashed_relocation", 1<<REISERFS_HASHED_RELOCATION, 0},
- {"test4", 1<<REISERFS_TEST4, 0},
- {"notest4", 0, 1<<REISERFS_TEST4},
- {NULL, 0, 0}
+ {"noborder", 1 << REISERFS_NO_BORDER, 0},
+ {"border", 0, 1 << REISERFS_NO_BORDER},
+ {"no_unhashed_relocation", 1 << REISERFS_NO_UNHASHED_RELOCATION, 0},
+ {"hashed_relocation", 1 << REISERFS_HASHED_RELOCATION, 0},
+ {"test4", 1 << REISERFS_TEST4, 0},
+ {"notest4", 0, 1 << REISERFS_TEST4},
+ {NULL, 0, 0}
};
static const arg_desc_t tails[] = {
- {"on", 1<<REISERFS_LARGETAIL, 1<<REISERFS_SMALLTAIL},
- {"off", 0, (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)},
- {"small", 1<<REISERFS_SMALLTAIL, 1<<REISERFS_LARGETAIL},
- {NULL, 0, 0}
+ {"on", 1 << REISERFS_LARGETAIL, 1 << REISERFS_SMALLTAIL},
+ {"off", 0, (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
+ {"small", 1 << REISERFS_SMALLTAIL, 1 << REISERFS_LARGETAIL},
+ {NULL, 0, 0}
};
static const arg_desc_t error_actions[] = {
- {"panic", 1 << REISERFS_ERROR_PANIC,
- (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
- {"ro-remount", 1 << REISERFS_ERROR_RO,
- (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
+ {"panic", 1 << REISERFS_ERROR_PANIC,
+ (1 << REISERFS_ERROR_RO | 1 << REISERFS_ERROR_CONTINUE)},
+ {"ro-remount", 1 << REISERFS_ERROR_RO,
+ (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_CONTINUE)},
#ifdef REISERFS_JOURNAL_ERROR_ALLOWS_NO_LOG
- {"continue", 1 << REISERFS_ERROR_CONTINUE,
- (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
+ {"continue", 1 << REISERFS_ERROR_CONTINUE,
+ (1 << REISERFS_ERROR_PANIC | 1 << REISERFS_ERROR_RO)},
#endif
- {NULL, 0, 0},
+ {NULL, 0, 0},
};
-int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
- There might be broken applications that are
- confused by this. Use nolargeio mount option
- to get usual i/o size = PAGE_SIZE.
- */
+int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
+ There might be broken applications that are
+ confused by this. Use nolargeio mount option
+ to get usual i/o size = PAGE_SIZE.
+ */
/* proceed only one option from a list *cur - string containing of mount options
opts - array of options which are accepted
@@ -716,476 +743,530 @@ int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 12
in the input - pointer to the argument is stored here
bit_flags - if option requires to set a certain bit - it is set here
return -1 if unknown option is found, opt->arg_required otherwise */
-static int reiserfs_getopt ( struct super_block * s, char ** cur, opt_desc_t * opts, char ** opt_arg,
- unsigned long * bit_flags)
+static int reiserfs_getopt(struct super_block *s, char **cur, opt_desc_t * opts,
+ char **opt_arg, unsigned long *bit_flags)
{
- char * p;
- /* foo=bar,
- ^ ^ ^
- | | +-- option_end
- | +-- arg_start
- +-- option_start
- */
- const opt_desc_t * opt;
- const arg_desc_t * arg;
-
-
- p = *cur;
-
- /* assume argument cannot contain commas */
- *cur = strchr (p, ',');
- if (*cur) {
- *(*cur) = '\0';
- (*cur) ++;
- }
-
- if ( !strncmp (p, "alloc=", 6) ) {
- /* Ugly special case, probably we should redo options parser so that
- it can understand several arguments for some options, also so that
- it can fill several bitfields with option values. */
- if ( reiserfs_parse_alloc_options( s, p + 6) ) {
- return -1;
- } else {
- return 0;
- }
- }
-
-
- /* for every option in the list */
- for (opt = opts; opt->option_name; opt ++) {
- if (!strncmp (p, opt->option_name, strlen (opt->option_name))) {
- if (bit_flags) {
- if (opt->clrmask == (1 << REISERFS_UNSUPPORTED_OPT))
- reiserfs_warning (s, "%s not supported.", p);
- else
- *bit_flags &= ~opt->clrmask;
- if (opt->setmask == (1 << REISERFS_UNSUPPORTED_OPT))
- reiserfs_warning (s, "%s not supported.", p);
- else
- *bit_flags |= opt->setmask;
- }
- break;
- }
- }
- if (!opt->option_name) {
- reiserfs_warning (s, "unknown mount option \"%s\"", p);
- return -1;
- }
-
- p += strlen (opt->option_name);
- switch (*p) {
- case '=':
- if (!opt->arg_required) {
- reiserfs_warning (s, "the option \"%s\" does not require an argument",
- opt->option_name);
- return -1;
- }
- break;
-
- case 0:
- if (opt->arg_required) {
- reiserfs_warning (s, "the option \"%s\" requires an argument", opt->option_name);
- return -1;
- }
- break;
- default:
- reiserfs_warning (s, "head of option \"%s\" is only correct", opt->option_name);
- return -1;
- }
-
- /* move to the argument, or to next option if argument is not required */
- p ++;
-
- if ( opt->arg_required && !(opt->arg_required & (1<<REISERFS_OPT_ALLOWEMPTY)) && !strlen (p) ) {
- /* this catches "option=," if not allowed */
- reiserfs_warning (s, "empty argument for \"%s\"", opt->option_name);
+ char *p;
+ /* foo=bar,
+ ^ ^ ^
+ | | +-- option_end
+ | +-- arg_start
+ +-- option_start
+ */
+ const opt_desc_t *opt;
+ const arg_desc_t *arg;
+
+ p = *cur;
+
+ /* assume argument cannot contain commas */
+ *cur = strchr(p, ',');
+ if (*cur) {
+ *(*cur) = '\0';
+ (*cur)++;
+ }
+
+ if (!strncmp(p, "alloc=", 6)) {
+ /* Ugly special case, probably we should redo options parser so that
+ it can understand several arguments for some options, also so that
+ it can fill several bitfields with option values. */
+ if (reiserfs_parse_alloc_options(s, p + 6)) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ /* for every option in the list */
+ for (opt = opts; opt->option_name; opt++) {
+ if (!strncmp(p, opt->option_name, strlen(opt->option_name))) {
+ if (bit_flags) {
+ if (opt->clrmask ==
+ (1 << REISERFS_UNSUPPORTED_OPT))
+ reiserfs_warning(s, "%s not supported.",
+ p);
+ else
+ *bit_flags &= ~opt->clrmask;
+ if (opt->setmask ==
+ (1 << REISERFS_UNSUPPORTED_OPT))
+ reiserfs_warning(s, "%s not supported.",
+ p);
+ else
+ *bit_flags |= opt->setmask;
+ }
+ break;
+ }
+ }
+ if (!opt->option_name) {
+ reiserfs_warning(s, "unknown mount option \"%s\"", p);
+ return -1;
+ }
+
+ p += strlen(opt->option_name);
+ switch (*p) {
+ case '=':
+ if (!opt->arg_required) {
+ reiserfs_warning(s,
+ "the option \"%s\" does not require an argument",
+ opt->option_name);
+ return -1;
+ }
+ break;
+
+ case 0:
+ if (opt->arg_required) {
+ reiserfs_warning(s,
+ "the option \"%s\" requires an argument",
+ opt->option_name);
+ return -1;
+ }
+ break;
+ default:
+ reiserfs_warning(s, "head of option \"%s\" is only correct",
+ opt->option_name);
+ return -1;
+ }
+
+ /* move to the argument, or to next option if argument is not required */
+ p++;
+
+ if (opt->arg_required
+ && !(opt->arg_required & (1 << REISERFS_OPT_ALLOWEMPTY))
+ && !strlen(p)) {
+ /* this catches "option=," if not allowed */
+ reiserfs_warning(s, "empty argument for \"%s\"",
+ opt->option_name);
+ return -1;
+ }
+
+ if (!opt->values) {
+ /* *=NULLopt_arg contains pointer to argument */
+ *opt_arg = p;
+ return opt->arg_required & ~(1 << REISERFS_OPT_ALLOWEMPTY);
+ }
+
+ /* values possible for this option are listed in opt->values */
+ for (arg = opt->values; arg->value; arg++) {
+ if (!strcmp(p, arg->value)) {
+ if (bit_flags) {
+ *bit_flags &= ~arg->clrmask;
+ *bit_flags |= arg->setmask;
+ }
+ return opt->arg_required;
+ }
+ }
+
+ reiserfs_warning(s, "bad value \"%s\" for option \"%s\"", p,
+ opt->option_name);
return -1;
- }
-
- if (!opt->values) {
- /* *=NULLopt_arg contains pointer to argument */
- *opt_arg = p;
- return opt->arg_required & ~(1<<REISERFS_OPT_ALLOWEMPTY);
- }
-
- /* values possible for this option are listed in opt->values */
- for (arg = opt->values; arg->value; arg ++) {
- if (!strcmp (p, arg->value)) {
- if (bit_flags) {
- *bit_flags &= ~arg->clrmask;
- *bit_flags |= arg->setmask;
- }
- return opt->arg_required;
- }
- }
-
- reiserfs_warning (s, "bad value \"%s\" for option \"%s\"", p, opt->option_name);
- return -1;
}
/* returns 0 if something is wrong in option string, 1 - otherwise */
-static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */
- unsigned long * mount_options,
- /* after the parsing phase, contains the
- collection of bitflags defining what
- mount options were selected. */
- unsigned long * blocks, /* strtol-ed from NNN of resize=NNN */
- char ** jdev_name,
- unsigned int * commit_max_age)
+static int reiserfs_parse_options(struct super_block *s, char *options, /* string given via mount's -o */
+ unsigned long *mount_options,
+ /* after the parsing phase, contains the
+ collection of bitflags defining what
+ mount options were selected. */
+ unsigned long *blocks, /* strtol-ed from NNN of resize=NNN */
+ char **jdev_name,
+ unsigned int *commit_max_age)
{
- int c;
- char * arg = NULL;
- char * pos;
- opt_desc_t opts[] = {
- /* Compatibility stuff, so that -o notail for old setups still work */
- {"tails", .arg_required = 't', .values = tails},
- {"notail", .clrmask = (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)},
- {"conv", .setmask = 1<<REISERFS_CONVERT},
- {"attrs", .setmask = 1<<REISERFS_ATTRS},
- {"noattrs", .clrmask = 1<<REISERFS_ATTRS},
+ int c;
+ char *arg = NULL;
+ char *pos;
+ opt_desc_t opts[] = {
+ /* Compatibility stuff, so that -o notail for old setups still work */
+ {"tails",.arg_required = 't',.values = tails},
+ {"notail",.clrmask =
+ (1 << REISERFS_LARGETAIL) | (1 << REISERFS_SMALLTAIL)},
+ {"conv",.setmask = 1 << REISERFS_CONVERT},
+ {"attrs",.setmask = 1 << REISERFS_ATTRS},
+ {"noattrs",.clrmask = 1 << REISERFS_ATTRS},
#ifdef CONFIG_REISERFS_FS_XATTR
- {"user_xattr", .setmask = 1<<REISERFS_XATTRS_USER},
- {"nouser_xattr",.clrmask = 1<<REISERFS_XATTRS_USER},
+ {"user_xattr",.setmask = 1 << REISERFS_XATTRS_USER},
+ {"nouser_xattr",.clrmask = 1 << REISERFS_XATTRS_USER},
#else
- {"user_xattr", .setmask = 1<<REISERFS_UNSUPPORTED_OPT},
- {"nouser_xattr",.clrmask = 1<<REISERFS_UNSUPPORTED_OPT},
+ {"user_xattr",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
+ {"nouser_xattr",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
#endif
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
- {"acl", .setmask = 1<<REISERFS_POSIXACL},
- {"noacl", .clrmask = 1<<REISERFS_POSIXACL},
+ {"acl",.setmask = 1 << REISERFS_POSIXACL},
+ {"noacl",.clrmask = 1 << REISERFS_POSIXACL},
#else
- {"acl", .setmask = 1<<REISERFS_UNSUPPORTED_OPT},
- {"noacl", .clrmask = 1<<REISERFS_UNSUPPORTED_OPT},
+ {"acl",.setmask = 1 << REISERFS_UNSUPPORTED_OPT},
+ {"noacl",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT},
#endif
- {"nolog",}, /* This is unsupported */
- {"replayonly", .setmask = 1<<REPLAYONLY},
- {"block-allocator", .arg_required = 'a', .values = balloc},
- {"data", .arg_required = 'd', .values = logging_mode},
- {"barrier", .arg_required = 'b', .values = barrier_mode},
- {"resize", .arg_required = 'r', .values = NULL},
- {"jdev", .arg_required = 'j', .values = NULL},
- {"nolargeio", .arg_required = 'w', .values = NULL},
- {"commit", .arg_required = 'c', .values = NULL},
- {"usrquota",},
- {"grpquota",},
- {"errors", .arg_required = 'e', .values = error_actions},
- {"usrjquota", .arg_required = 'u'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL},
- {"grpjquota", .arg_required = 'g'|(1<<REISERFS_OPT_ALLOWEMPTY), .values = NULL},
- {"jqfmt", .arg_required = 'f', .values = NULL},
- {NULL,}
- };
-
- *blocks = 0;
- if (!options || !*options)
- /* use default configuration: create tails, journaling on, no
- conversion to newest format */
- return 1;
-
- for (pos = options; pos; ) {
- c = reiserfs_getopt (s, &pos, opts, &arg, mount_options);
- if (c == -1)
- /* wrong option is given */
- return 0;
-
- if (c == 'r') {
- char * p;
-
- p = NULL;
- /* "resize=NNN" or "resize=auto" */
-
- if (!strcmp(arg, "auto")) {
- /* From JFS code, to auto-get the size.*/
- *blocks = s->s_bdev->bd_inode->i_size >> s->s_blocksize_bits;
- } else {
- *blocks = simple_strtoul (arg, &p, 0);
- if (*p != '\0') {
- /* NNN does not look like a number */
- reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
+ {"nolog",}, /* This is unsupported */
+ {"replayonly",.setmask = 1 << REPLAYONLY},
+ {"block-allocator",.arg_required = 'a',.values = balloc},
+ {"data",.arg_required = 'd',.values = logging_mode},
+ {"barrier",.arg_required = 'b',.values = barrier_mode},
+ {"resize",.arg_required = 'r',.values = NULL},
+ {"jdev",.arg_required = 'j',.values = NULL},
+ {"nolargeio",.arg_required = 'w',.values = NULL},
+ {"commit",.arg_required = 'c',.values = NULL},
+ {"usrquota",.setmask = 1 << REISERFS_QUOTA},
+ {"grpquota",.setmask = 1 << REISERFS_QUOTA},
+ {"noquota",.clrmask = 1 << REISERFS_QUOTA},
+ {"errors",.arg_required = 'e',.values = error_actions},
+ {"usrjquota",.arg_required =
+ 'u' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
+ {"grpjquota",.arg_required =
+ 'g' | (1 << REISERFS_OPT_ALLOWEMPTY),.values = NULL},
+ {"jqfmt",.arg_required = 'f',.values = NULL},
+ {NULL,}
+ };
+
+ *blocks = 0;
+ if (!options || !*options)
+ /* use default configuration: create tails, journaling on, no
+ conversion to newest format */
+ return 1;
+
+ for (pos = options; pos;) {
+ c = reiserfs_getopt(s, &pos, opts, &arg, mount_options);
+ if (c == -1)
+ /* wrong option is given */
return 0;
- }
- }
- }
- if ( c == 'c' ) {
- char *p = NULL;
- unsigned long val = simple_strtoul (arg, &p, 0);
- /* commit=NNN (time in seconds) */
- if ( *p != '\0' || val >= (unsigned int)-1) {
- reiserfs_warning (s, "reiserfs_parse_options: bad value %s", arg);
- return 0;
+ if (c == 'r') {
+ char *p;
+
+ p = NULL;
+ /* "resize=NNN" or "resize=auto" */
+
+ if (!strcmp(arg, "auto")) {
+ /* From JFS code, to auto-get the size. */
+ *blocks =
+ s->s_bdev->bd_inode->i_size >> s->
+ s_blocksize_bits;
+ } else {
+ *blocks = simple_strtoul(arg, &p, 0);
+ if (*p != '\0') {
+ /* NNN does not look like a number */
+ reiserfs_warning(s,
+ "reiserfs_parse_options: bad value %s",
+ arg);
+ return 0;
+ }
+ }
}
- *commit_max_age = (unsigned int)val;
- }
- if ( c == 'w' ) {
- char *p=NULL;
- int val = simple_strtoul (arg, &p, 0);
-
- if ( *p != '\0') {
- reiserfs_warning (s, "reiserfs_parse_options: non-numeric value %s for nolargeio option", arg);
- return 0;
+ if (c == 'c') {
+ char *p = NULL;
+ unsigned long val = simple_strtoul(arg, &p, 0);
+ /* commit=NNN (time in seconds) */
+ if (*p != '\0' || val >= (unsigned int)-1) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: bad value %s",
+ arg);
+ return 0;
+ }
+ *commit_max_age = (unsigned int)val;
}
- if ( val )
- reiserfs_default_io_size = PAGE_SIZE;
- else
- reiserfs_default_io_size = 128 * 1024;
- }
- if (c == 'j') {
- if (arg && *arg && jdev_name) {
- if ( *jdev_name ) { //Hm, already assigned?
- reiserfs_warning (s, "reiserfs_parse_options: journal device was already specified to be %s", *jdev_name);
- return 0;
+ if (c == 'w') {
+ char *p = NULL;
+ int val = simple_strtoul(arg, &p, 0);
+
+ if (*p != '\0') {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: non-numeric value %s for nolargeio option",
+ arg);
+ return 0;
+ }
+ if (val)
+ reiserfs_default_io_size = PAGE_SIZE;
+ else
+ reiserfs_default_io_size = 128 * 1024;
}
- *jdev_name = arg;
- }
- }
-#ifdef CONFIG_QUOTA
- if (c == 'u' || c == 'g') {
- int qtype = c == 'u' ? USRQUOTA : GRPQUOTA;
-
- if (sb_any_quota_enabled(s)) {
- reiserfs_warning(s, "reiserfs_parse_options: cannot change journalled quota options when quota turned on.");
- return 0;
- }
- if (*arg) { /* Some filename specified? */
- if (REISERFS_SB(s)->s_qf_names[qtype] && strcmp(REISERFS_SB(s)->s_qf_names[qtype], arg)) {
- reiserfs_warning(s, "reiserfs_parse_options: %s quota file already specified.", QTYPE2NAME(qtype));
- return 0;
+ if (c == 'j') {
+ if (arg && *arg && jdev_name) {
+ if (*jdev_name) { //Hm, already assigned?
+ reiserfs_warning(s,
+ "reiserfs_parse_options: journal device was already specified to be %s",
+ *jdev_name);
+ return 0;
+ }
+ *jdev_name = arg;
+ }
}
- if (strchr(arg, '/')) {
- reiserfs_warning(s, "reiserfs_parse_options: quotafile must be on filesystem root.");
- return 0;
+#ifdef CONFIG_QUOTA
+ if (c == 'u' || c == 'g') {
+ int qtype = c == 'u' ? USRQUOTA : GRPQUOTA;
+
+ if (sb_any_quota_enabled(s)) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: cannot change journalled quota options when quota turned on.");
+ return 0;
+ }
+ if (*arg) { /* Some filename specified? */
+ if (REISERFS_SB(s)->s_qf_names[qtype]
+ && strcmp(REISERFS_SB(s)->s_qf_names[qtype],
+ arg)) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: %s quota file already specified.",
+ QTYPE2NAME(qtype));
+ return 0;
+ }
+ if (strchr(arg, '/')) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: quotafile must be on filesystem root.");
+ return 0;
+ }
+ REISERFS_SB(s)->s_qf_names[qtype] =
+ kmalloc(strlen(arg) + 1, GFP_KERNEL);
+ if (!REISERFS_SB(s)->s_qf_names[qtype]) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: not enough memory for storing quotafile name.");
+ return 0;
+ }
+ strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg);
+ *mount_options |= 1 << REISERFS_QUOTA;
+ } else {
+ if (REISERFS_SB(s)->s_qf_names[qtype]) {
+ kfree(REISERFS_SB(s)->
+ s_qf_names[qtype]);
+ REISERFS_SB(s)->s_qf_names[qtype] =
+ NULL;
+ }
+ }
}
- REISERFS_SB(s)->s_qf_names[qtype] = kmalloc(strlen(arg)+1, GFP_KERNEL);
- if (!REISERFS_SB(s)->s_qf_names[qtype]) {
- reiserfs_warning(s, "reiserfs_parse_options: not enough memory for storing quotafile name.");
- return 0;
+ if (c == 'f') {
+ if (!strcmp(arg, "vfsold"))
+ REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD;
+ else if (!strcmp(arg, "vfsv0"))
+ REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0;
+ else {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: unknown quota format specified.");
+ return 0;
+ }
}
- strcpy(REISERFS_SB(s)->s_qf_names[qtype], arg);
- }
- else {
- if (REISERFS_SB(s)->s_qf_names[qtype]) {
- kfree(REISERFS_SB(s)->s_qf_names[qtype]);
- REISERFS_SB(s)->s_qf_names[qtype] = NULL;
+#else
+ if (c == 'u' || c == 'g' || c == 'f') {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: journalled quota options not supported.");
+ return 0;
}
- }
- }
- if (c == 'f') {
- if (!strcmp(arg, "vfsold"))
- REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_OLD;
- else if (!strcmp(arg, "vfsv0"))
- REISERFS_SB(s)->s_jquota_fmt = QFMT_VFS_V0;
- else {
- reiserfs_warning(s, "reiserfs_parse_options: unknown quota format specified.");
+#endif
+ }
+
+#ifdef CONFIG_QUOTA
+ if (!REISERFS_SB(s)->s_jquota_fmt
+ && (REISERFS_SB(s)->s_qf_names[USRQUOTA]
+ || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: journalled quota format not specified.");
return 0;
- }
}
-#else
- if (c == 'u' || c == 'g' || c == 'f') {
- reiserfs_warning(s, "reiserfs_parse_options: journalled quota options not supported.");
- return 0;
+ /* This checking is not precise wrt the quota type but for our purposes it is sufficient */
+ if (!(*mount_options & (1 << REISERFS_QUOTA))
+ && sb_any_quota_enabled(s)) {
+ reiserfs_warning(s,
+ "reiserfs_parse_options: quota options must be present when quota is turned on.");
+ return 0;
}
#endif
- }
-
-#ifdef CONFIG_QUOTA
- if (!REISERFS_SB(s)->s_jquota_fmt && (REISERFS_SB(s)->s_qf_names[USRQUOTA] || REISERFS_SB(s)->s_qf_names[GRPQUOTA])) {
- reiserfs_warning(s, "reiserfs_parse_options: journalled quota format not specified.");
- return 0;
- }
-#endif
- return 1;
+
+ return 1;
}
-static void switch_data_mode(struct super_block *s, unsigned long mode) {
- REISERFS_SB(s)->s_mount_opt &= ~((1 << REISERFS_DATA_LOG) |
- (1 << REISERFS_DATA_ORDERED) |
- (1 << REISERFS_DATA_WRITEBACK));
- REISERFS_SB(s)->s_mount_opt |= (1 << mode);
+static void switch_data_mode(struct super_block *s, unsigned long mode)
+{
+ REISERFS_SB(s)->s_mount_opt &= ~((1 << REISERFS_DATA_LOG) |
+ (1 << REISERFS_DATA_ORDERED) |
+ (1 << REISERFS_DATA_WRITEBACK));
+ REISERFS_SB(s)->s_mount_opt |= (1 << mode);
}
static void handle_data_mode(struct super_block *s, unsigned long mount_options)
{
- if (mount_options & (1 << REISERFS_DATA_LOG)) {
- if (!reiserfs_data_log(s)) {
- switch_data_mode(s, REISERFS_DATA_LOG);
- reiserfs_info (s, "switching to journaled data mode\n");
- }
- } else if (mount_options & (1 << REISERFS_DATA_ORDERED)) {
- if (!reiserfs_data_ordered(s)) {
- switch_data_mode(s, REISERFS_DATA_ORDERED);
- reiserfs_info (s, "switching to ordered data mode\n");
- }
- } else if (mount_options & (1 << REISERFS_DATA_WRITEBACK)) {
- if (!reiserfs_data_writeback(s)) {
- switch_data_mode(s, REISERFS_DATA_WRITEBACK);
- reiserfs_info (s, "switching to writeback data mode\n");
- }
- }
+ if (mount_options & (1 << REISERFS_DATA_LOG)) {
+ if (!reiserfs_data_log(s)) {
+ switch_data_mode(s, REISERFS_DATA_LOG);
+ reiserfs_info(s, "switching to journaled data mode\n");
+ }
+ } else if (mount_options & (1 << REISERFS_DATA_ORDERED)) {
+ if (!reiserfs_data_ordered(s)) {
+ switch_data_mode(s, REISERFS_DATA_ORDERED);
+ reiserfs_info(s, "switching to ordered data mode\n");
+ }
+ } else if (mount_options & (1 << REISERFS_DATA_WRITEBACK)) {
+ if (!reiserfs_data_writeback(s)) {
+ switch_data_mode(s, REISERFS_DATA_WRITEBACK);
+ reiserfs_info(s, "switching to writeback data mode\n");
+ }
+ }
}
-static void handle_barrier_mode(struct super_block *s, unsigned long bits) {
- int flush = (1 << REISERFS_BARRIER_FLUSH);
- int none = (1 << REISERFS_BARRIER_NONE);
- int all_barrier = flush | none;
-
- if (bits & all_barrier) {
- REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
- if (bits & flush) {
- REISERFS_SB(s)->s_mount_opt |= flush;
- printk("reiserfs: enabling write barrier flush mode\n");
- } else if (bits & none) {
- REISERFS_SB(s)->s_mount_opt |= none;
- printk("reiserfs: write barriers turned off\n");
- }
- }
+static void handle_barrier_mode(struct super_block *s, unsigned long bits)
+{
+ int flush = (1 << REISERFS_BARRIER_FLUSH);
+ int none = (1 << REISERFS_BARRIER_NONE);
+ int all_barrier = flush | none;
+
+ if (bits & all_barrier) {
+ REISERFS_SB(s)->s_mount_opt &= ~all_barrier;
+ if (bits & flush) {
+ REISERFS_SB(s)->s_mount_opt |= flush;
+ printk("reiserfs: enabling write barrier flush mode\n");
+ } else if (bits & none) {
+ REISERFS_SB(s)->s_mount_opt |= none;
+ printk("reiserfs: write barriers turned off\n");
+ }
+ }
}
-static void handle_attrs( struct super_block *s )
+static void handle_attrs(struct super_block *s)
{
- struct reiserfs_super_block * rs;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
- if( reiserfs_attrs( s ) ) {
- rs = SB_DISK_SUPER_BLOCK (s);
- if( old_format_only(s) ) {
- reiserfs_warning(s, "reiserfs: cannot support attributes on 3.5.x disk format" );
- REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
+ if (reiserfs_attrs(s)) {
+ if (old_format_only(s)) {
+ reiserfs_warning(s,
+ "reiserfs: cannot support attributes on 3.5.x disk format");
+ REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
return;
}
- if( !( le32_to_cpu( rs -> s_flags ) & reiserfs_attrs_cleared ) ) {
- reiserfs_warning(s, "reiserfs: cannot support attributes until flag is set in super-block" );
- REISERFS_SB(s) -> s_mount_opt &= ~ ( 1 << REISERFS_ATTRS );
+ if (!(le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared)) {
+ reiserfs_warning(s,
+ "reiserfs: cannot support attributes until flag is set in super-block");
+ REISERFS_SB(s)->s_mount_opt &= ~(1 << REISERFS_ATTRS);
}
+ } else if (le32_to_cpu(rs->s_flags) & reiserfs_attrs_cleared) {
+ REISERFS_SB(s)->s_mount_opt |= REISERFS_ATTRS;
}
}
-static int reiserfs_remount (struct super_block * s, int * mount_flags, char * arg)
+static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
{
- struct reiserfs_super_block * rs;
- struct reiserfs_transaction_handle th ;
- unsigned long blocks;
- unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
- unsigned long safe_mask = 0;
- unsigned int commit_max_age = (unsigned int)-1;
- struct reiserfs_journal *journal = SB_JOURNAL(s);
- int err;
+ struct reiserfs_super_block *rs;
+ struct reiserfs_transaction_handle th;
+ unsigned long blocks;
+ unsigned long mount_options = REISERFS_SB(s)->s_mount_opt;
+ unsigned long safe_mask = 0;
+ unsigned int commit_max_age = (unsigned int)-1;
+ struct reiserfs_journal *journal = SB_JOURNAL(s);
+ int err;
#ifdef CONFIG_QUOTA
- int i;
+ int i;
#endif
- rs = SB_DISK_SUPER_BLOCK (s);
+ rs = SB_DISK_SUPER_BLOCK(s);
- if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL, &commit_max_age)) {
+ if (!reiserfs_parse_options
+ (s, arg, &mount_options, &blocks, NULL, &commit_max_age)) {
#ifdef CONFIG_QUOTA
- for (i = 0; i < MAXQUOTAS; i++)
- if (REISERFS_SB(s)->s_qf_names[i]) {
- kfree(REISERFS_SB(s)->s_qf_names[i]);
- REISERFS_SB(s)->s_qf_names[i] = NULL;
- }
+ for (i = 0; i < MAXQUOTAS; i++)
+ if (REISERFS_SB(s)->s_qf_names[i]) {
+ kfree(REISERFS_SB(s)->s_qf_names[i]);
+ REISERFS_SB(s)->s_qf_names[i] = NULL;
+ }
#endif
- return -EINVAL;
- }
-
- handle_attrs(s);
-
- /* Add options that are safe here */
- safe_mask |= 1 << REISERFS_SMALLTAIL;
- safe_mask |= 1 << REISERFS_LARGETAIL;
- safe_mask |= 1 << REISERFS_NO_BORDER;
- safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION;
- safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
- safe_mask |= 1 << REISERFS_TEST4;
- safe_mask |= 1 << REISERFS_ATTRS;
- safe_mask |= 1 << REISERFS_XATTRS_USER;
- safe_mask |= 1 << REISERFS_POSIXACL;
- safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
- safe_mask |= 1 << REISERFS_BARRIER_NONE;
- safe_mask |= 1 << REISERFS_ERROR_RO;
- safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
- safe_mask |= 1 << REISERFS_ERROR_PANIC;
-
- /* Update the bitmask, taking care to keep
- * the bits we're not allowed to change here */
- REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask);
-
- if(commit_max_age != 0 && commit_max_age != (unsigned int)-1) {
- journal->j_max_commit_age = commit_max_age;
- journal->j_max_trans_age = commit_max_age;
- }
- else if(commit_max_age == 0)
- {
- /* 0 means restore defaults. */
- journal->j_max_commit_age = journal->j_default_max_commit_age;
- journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
- }
-
- if(blocks) {
- int rc = reiserfs_resize(s, blocks);
- if (rc != 0)
- return rc;
- }
-
- if (*mount_flags & MS_RDONLY) {
- reiserfs_xattr_init (s, *mount_flags);
- /* remount read-only */
- if (s->s_flags & MS_RDONLY)
- /* it is read-only already */
- return 0;
- /* try to remount file system with read-only permissions */
- if (sb_umount_state(rs) == REISERFS_VALID_FS || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
- return 0;
- }
-
- err = journal_begin(&th, s, 10) ;
- if (err)
- return err;
-
- /* Mounting a rw partition read-only. */
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
- set_sb_umount_state( rs, REISERFS_SB(s)->s_mount_state );
- journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
- } else {
- /* remount read-write */
- if (!(s->s_flags & MS_RDONLY)) {
- reiserfs_xattr_init (s, *mount_flags);
- return 0; /* We are read-write already */
- }
-
- if (reiserfs_is_journal_aborted (journal))
- return journal->j_errno;
-
- handle_data_mode(s, mount_options);
- handle_barrier_mode(s, mount_options);
- REISERFS_SB(s)->s_mount_state = sb_umount_state(rs) ;
- s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */
- err = journal_begin(&th, s, 10) ;
- if (err)
- return err;
-
- /* Mount a partition which is read-only, read-write */
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
- REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
- s->s_flags &= ~MS_RDONLY;
- set_sb_umount_state( rs, REISERFS_ERROR_FS );
- /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
- journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
- REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS ;
- }
- /* this will force a full flush of all journal lists */
- SB_JOURNAL(s)->j_must_wait = 1 ;
- err = journal_end(&th, s, 10) ;
- if (err)
- return err;
- s->s_dirt = 0;
-
- if (!( *mount_flags & MS_RDONLY ) ) {
- finish_unfinished( s );
- reiserfs_xattr_init (s, *mount_flags);
- }
-
- return 0;
+ return -EINVAL;
+ }
+
+ handle_attrs(s);
+
+ /* Add options that are safe here */
+ safe_mask |= 1 << REISERFS_SMALLTAIL;
+ safe_mask |= 1 << REISERFS_LARGETAIL;
+ safe_mask |= 1 << REISERFS_NO_BORDER;
+ safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION;
+ safe_mask |= 1 << REISERFS_HASHED_RELOCATION;
+ safe_mask |= 1 << REISERFS_TEST4;
+ safe_mask |= 1 << REISERFS_ATTRS;
+ safe_mask |= 1 << REISERFS_XATTRS_USER;
+ safe_mask |= 1 << REISERFS_POSIXACL;
+ safe_mask |= 1 << REISERFS_BARRIER_FLUSH;
+ safe_mask |= 1 << REISERFS_BARRIER_NONE;
+ safe_mask |= 1 << REISERFS_ERROR_RO;
+ safe_mask |= 1 << REISERFS_ERROR_CONTINUE;
+ safe_mask |= 1 << REISERFS_ERROR_PANIC;
+ safe_mask |= 1 << REISERFS_QUOTA;
+
+ /* Update the bitmask, taking care to keep
+ * the bits we're not allowed to change here */
+ REISERFS_SB(s)->s_mount_opt =
+ (REISERFS_SB(s)->
+ s_mount_opt & ~safe_mask) | (mount_options & safe_mask);
+
+ if (commit_max_age != 0 && commit_max_age != (unsigned int)-1) {
+ journal->j_max_commit_age = commit_max_age;
+ journal->j_max_trans_age = commit_max_age;
+ } else if (commit_max_age == 0) {
+ /* 0 means restore defaults. */
+ journal->j_max_commit_age = journal->j_default_max_commit_age;
+ journal->j_max_trans_age = JOURNAL_MAX_TRANS_AGE;
+ }
+
+ if (blocks) {
+ int rc = reiserfs_resize(s, blocks);
+ if (rc != 0)
+ return rc;
+ }
+
+ if (*mount_flags & MS_RDONLY) {
+ reiserfs_xattr_init(s, *mount_flags);
+ /* remount read-only */
+ if (s->s_flags & MS_RDONLY)
+ /* it is read-only already */
+ return 0;
+ /* try to remount file system with read-only permissions */
+ if (sb_umount_state(rs) == REISERFS_VALID_FS
+ || REISERFS_SB(s)->s_mount_state != REISERFS_VALID_FS) {
+ return 0;
+ }
+
+ err = journal_begin(&th, s, 10);
+ if (err)
+ return err;
+
+ /* Mounting a rw partition read-only. */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+ set_sb_umount_state(rs, REISERFS_SB(s)->s_mount_state);
+ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
+ } else {
+ /* remount read-write */
+ if (!(s->s_flags & MS_RDONLY)) {
+ reiserfs_xattr_init(s, *mount_flags);
+ return 0; /* We are read-write already */
+ }
+
+ if (reiserfs_is_journal_aborted(journal))
+ return journal->j_errno;
+
+ handle_data_mode(s, mount_options);
+ handle_barrier_mode(s, mount_options);
+ REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
+ s->s_flags &= ~MS_RDONLY; /* now it is safe to call journal_begin */
+ err = journal_begin(&th, s, 10);
+ if (err)
+ return err;
+
+ /* Mount a partition which is read-only, read-write */
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+ REISERFS_SB(s)->s_mount_state = sb_umount_state(rs);
+ s->s_flags &= ~MS_RDONLY;
+ set_sb_umount_state(rs, REISERFS_ERROR_FS);
+ /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */
+ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
+ REISERFS_SB(s)->s_mount_state = REISERFS_VALID_FS;
+ }
+ /* this will force a full flush of all journal lists */
+ SB_JOURNAL(s)->j_must_wait = 1;
+ err = journal_end(&th, s, 10);
+ if (err)
+ return err;
+ s->s_dirt = 0;
+
+ if (!(*mount_flags & MS_RDONLY)) {
+ finish_unfinished(s);
+ reiserfs_xattr_init(s, *mount_flags);
+ }
+
+ return 0;
}
/* load_bitmap_info_data - Sets up the reiserfs_bitmap_info structure from disk.
@@ -1204,731 +1285,829 @@ static int reiserfs_remount (struct super_block * s, int * mount_flags, char * a
* free blocks at all.
*/
-static void load_bitmap_info_data (struct super_block *sb,
- struct reiserfs_bitmap_info *bi)
+static void load_bitmap_info_data(struct super_block *sb,
+ struct reiserfs_bitmap_info *bi)
{
- unsigned long *cur = (unsigned long *)bi->bh->b_data;
-
- while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
-
- /* No need to scan if all 0's or all 1's.
- * Since we're only counting 0's, we can simply ignore all 1's */
- if (*cur == 0) {
- if (bi->first_zero_hint == 0) {
- bi->first_zero_hint = ((char *)cur - bi->bh->b_data) << 3;
- }
- bi->free_count += sizeof(unsigned long)*8;
- } else if (*cur != ~0L) {
- int b;
- for (b = 0; b < sizeof(unsigned long)*8; b++) {
- if (!reiserfs_test_le_bit (b, cur)) {
- bi->free_count ++;
- if (bi->first_zero_hint == 0)
- bi->first_zero_hint =
- (((char *)cur - bi->bh->b_data) << 3) + b;
- }
+ unsigned long *cur = (unsigned long *)bi->bh->b_data;
+
+ while ((char *)cur < (bi->bh->b_data + sb->s_blocksize)) {
+
+ /* No need to scan if all 0's or all 1's.
+ * Since we're only counting 0's, we can simply ignore all 1's */
+ if (*cur == 0) {
+ if (bi->first_zero_hint == 0) {
+ bi->first_zero_hint =
+ ((char *)cur - bi->bh->b_data) << 3;
+ }
+ bi->free_count += sizeof(unsigned long) * 8;
+ } else if (*cur != ~0L) {
+ int b;
+ for (b = 0; b < sizeof(unsigned long) * 8; b++) {
+ if (!reiserfs_test_le_bit(b, cur)) {
+ bi->free_count++;
+ if (bi->first_zero_hint == 0)
+ bi->first_zero_hint =
+ (((char *)cur -
+ bi->bh->b_data) << 3) + b;
+ }
+ }
}
- }
- cur ++;
- }
+ cur++;
+ }
#ifdef CONFIG_REISERFS_CHECK
// This outputs a lot of unneded info on big FSes
// reiserfs_warning ("bitmap loaded from block %d: %d free blocks",
-// bi->bh->b_blocknr, bi->free_count);
+// bi->bh->b_blocknr, bi->free_count);
#endif
}
-
-static int read_bitmaps (struct super_block * s)
+
+static int read_bitmaps(struct super_block *s)
{
- int i, bmap_nr;
+ int i, bmap_nr;
+
+ SB_AP_BITMAP(s) =
+ vmalloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
+ if (SB_AP_BITMAP(s) == 0)
+ return 1;
+ memset(SB_AP_BITMAP(s), 0,
+ sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
+ for (i = 0, bmap_nr =
+ REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
+ i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) {
+ SB_AP_BITMAP(s)[i].bh = sb_getblk(s, bmap_nr);
+ if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
+ ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);
+ }
+ for (i = 0; i < SB_BMAP_NR(s); i++) {
+ wait_on_buffer(SB_AP_BITMAP(s)[i].bh);
+ if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
+ reiserfs_warning(s, "sh-2029: reiserfs read_bitmaps: "
+ "bitmap block (#%lu) reading failed",
+ SB_AP_BITMAP(s)[i].bh->b_blocknr);
+ for (i = 0; i < SB_BMAP_NR(s); i++)
+ brelse(SB_AP_BITMAP(s)[i].bh);
+ vfree(SB_AP_BITMAP(s));
+ SB_AP_BITMAP(s) = NULL;
+ return 1;
+ }
+ load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
+ }
+ return 0;
+}
- SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
- if (SB_AP_BITMAP (s) == 0)
- return 1;
- memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_bitmap_info) * SB_BMAP_NR(s));
- for (i = 0, bmap_nr = REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize + 1;
- i < SB_BMAP_NR(s); i++, bmap_nr = s->s_blocksize * 8 * i) {
- SB_AP_BITMAP (s)[i].bh = sb_getblk(s, bmap_nr);
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh))
- ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);
- }
- for (i = 0; i < SB_BMAP_NR(s); i++) {
- wait_on_buffer(SB_AP_BITMAP (s)[i].bh);
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
- reiserfs_warning(s,"sh-2029: reiserfs read_bitmaps: "
- "bitmap block (#%lu) reading failed",
- SB_AP_BITMAP(s)[i].bh->b_blocknr);
- for (i = 0; i < SB_BMAP_NR(s); i++)
- brelse(SB_AP_BITMAP(s)[i].bh);
- vfree(SB_AP_BITMAP(s));
- SB_AP_BITMAP(s) = NULL;
- return 1;
+static int read_old_bitmaps(struct super_block *s)
+{
+ int i;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
+ int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */
+
+ /* read true bitmap */
+ SB_AP_BITMAP(s) =
+ vmalloc(sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
+ if (SB_AP_BITMAP(s) == 0)
+ return 1;
+
+ memset(SB_AP_BITMAP(s), 0,
+ sizeof(struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
+
+ for (i = 0; i < sb_bmap_nr(rs); i++) {
+ SB_AP_BITMAP(s)[i].bh = sb_bread(s, bmp1 + i);
+ if (!SB_AP_BITMAP(s)[i].bh)
+ return 1;
+ load_bitmap_info_data(s, SB_AP_BITMAP(s) + i);
}
- load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
- }
- return 0;
+
+ return 0;
}
-static int read_old_bitmaps (struct super_block * s)
+static int read_super_block(struct super_block *s, int offset)
{
- int i ;
- struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK(s);
- int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */
+ struct buffer_head *bh;
+ struct reiserfs_super_block *rs;
+ int fs_blocksize;
- /* read true bitmap */
- SB_AP_BITMAP (s) = vmalloc (sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
- if (SB_AP_BITMAP (s) == 0)
- return 1;
+ bh = sb_bread(s, offset / s->s_blocksize);
+ if (!bh) {
+ reiserfs_warning(s, "sh-2006: read_super_block: "
+ "bread failed (dev %s, block %lu, size %lu)",
+ reiserfs_bdevname(s), offset / s->s_blocksize,
+ s->s_blocksize);
+ return 1;
+ }
- memset (SB_AP_BITMAP (s), 0, sizeof (struct reiserfs_buffer_info *) * sb_bmap_nr(rs));
+ rs = (struct reiserfs_super_block *)bh->b_data;
+ if (!is_any_reiserfs_magic_string(rs)) {
+ brelse(bh);
+ return 1;
+ }
+ //
+ // ok, reiserfs signature (old or new) found in at the given offset
+ //
+ fs_blocksize = sb_blocksize(rs);
+ brelse(bh);
+ sb_set_blocksize(s, fs_blocksize);
- for (i = 0; i < sb_bmap_nr(rs); i ++) {
- SB_AP_BITMAP (s)[i].bh = sb_bread (s, bmp1 + i);
- if (!SB_AP_BITMAP (s)[i].bh)
- return 1;
- load_bitmap_info_data (s, SB_AP_BITMAP (s) + i);
- }
+ bh = sb_bread(s, offset / s->s_blocksize);
+ if (!bh) {
+ reiserfs_warning(s, "sh-2007: read_super_block: "
+ "bread failed (dev %s, block %lu, size %lu)\n",
+ reiserfs_bdevname(s), offset / s->s_blocksize,
+ s->s_blocksize);
+ return 1;
+ }
- return 0;
-}
+ rs = (struct reiserfs_super_block *)bh->b_data;
+ if (sb_blocksize(rs) != s->s_blocksize) {
+ reiserfs_warning(s, "sh-2011: read_super_block: "
+ "can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n",
+ reiserfs_bdevname(s),
+ (unsigned long long)bh->b_blocknr,
+ s->s_blocksize);
+ brelse(bh);
+ return 1;
+ }
-static int read_super_block (struct super_block * s, int offset)
-{
- struct buffer_head * bh;
- struct reiserfs_super_block * rs;
- int fs_blocksize;
-
-
- bh = sb_bread (s, offset / s->s_blocksize);
- if (!bh) {
- reiserfs_warning (s, "sh-2006: read_super_block: "
- "bread failed (dev %s, block %lu, size %lu)",
- reiserfs_bdevname (s), offset / s->s_blocksize, s->s_blocksize);
- return 1;
- }
-
- rs = (struct reiserfs_super_block *)bh->b_data;
- if (!is_any_reiserfs_magic_string (rs)) {
- brelse (bh);
- return 1;
- }
-
- //
- // ok, reiserfs signature (old or new) found in at the given offset
- //
- fs_blocksize = sb_blocksize(rs);
- brelse (bh);
- sb_set_blocksize (s, fs_blocksize);
-
- bh = sb_bread (s, offset / s->s_blocksize);
- if (!bh) {
- reiserfs_warning (s, "sh-2007: read_super_block: "
- "bread failed (dev %s, block %lu, size %lu)\n",
- reiserfs_bdevname (s), offset / s->s_blocksize, s->s_blocksize);
- return 1;
- }
-
- rs = (struct reiserfs_super_block *)bh->b_data;
- if (sb_blocksize(rs) != s->s_blocksize) {
- reiserfs_warning (s, "sh-2011: read_super_block: "
- "can't find a reiserfs filesystem on (dev %s, block %Lu, size %lu)\n",
- reiserfs_bdevname (s), (unsigned long long)bh->b_blocknr, s->s_blocksize);
- brelse (bh);
- return 1;
- }
-
- if ( rs->s_v1.s_root_block == cpu_to_le32(-1) ) {
- brelse(bh) ;
- reiserfs_warning (s, "Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
- "reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
- "get newer reiserfsprogs package");
- return 1;
- }
-
- SB_BUFFER_WITH_SB (s) = bh;
- SB_DISK_SUPER_BLOCK (s) = rs;
-
- if (is_reiserfs_jr (rs)) {
- /* magic is of non-standard journal filesystem, look at s_version to
- find which format is in use */
- if (sb_version(rs) == REISERFS_VERSION_2)
- reiserfs_warning (s, "read_super_block: found reiserfs format \"3.6\""
- " with non-standard journal");
- else if (sb_version(rs) == REISERFS_VERSION_1)
- reiserfs_warning (s, "read_super_block: found reiserfs format \"3.5\""
- " with non-standard journal");
- else {
- reiserfs_warning (s, "sh-2012: read_super_block: found unknown "
- "format \"%u\" of reiserfs with non-standard magic",
- sb_version(rs));
- return 1;
+ if (rs->s_v1.s_root_block == cpu_to_le32(-1)) {
+ brelse(bh);
+ reiserfs_warning(s,
+ "Unfinished reiserfsck --rebuild-tree run detected. Please run\n"
+ "reiserfsck --rebuild-tree and wait for a completion. If that fails\n"
+ "get newer reiserfsprogs package");
+ return 1;
}
- }
- else
- /* s_version of standard format may contain incorrect information,
- so we just look at the magic string */
- reiserfs_info (s, "found reiserfs format \"%s\" with standard journal\n",
- is_reiserfs_3_5 (rs) ? "3.5" : "3.6");
- s->s_op = &reiserfs_sops;
- s->s_export_op = &reiserfs_export_ops;
+ SB_BUFFER_WITH_SB(s) = bh;
+ SB_DISK_SUPER_BLOCK(s) = rs;
+
+ if (is_reiserfs_jr(rs)) {
+ /* magic is of non-standard journal filesystem, look at s_version to
+ find which format is in use */
+ if (sb_version(rs) == REISERFS_VERSION_2)
+ reiserfs_warning(s,
+ "read_super_block: found reiserfs format \"3.6\""
+ " with non-standard journal");
+ else if (sb_version(rs) == REISERFS_VERSION_1)
+ reiserfs_warning(s,
+ "read_super_block: found reiserfs format \"3.5\""
+ " with non-standard journal");
+ else {
+ reiserfs_warning(s,
+ "sh-2012: read_super_block: found unknown "
+ "format \"%u\" of reiserfs with non-standard magic",
+ sb_version(rs));
+ return 1;
+ }
+ } else
+ /* s_version of standard format may contain incorrect information,
+ so we just look at the magic string */
+ reiserfs_info(s,
+ "found reiserfs format \"%s\" with standard journal\n",
+ is_reiserfs_3_5(rs) ? "3.5" : "3.6");
+
+ s->s_op = &reiserfs_sops;
+ s->s_export_op = &reiserfs_export_ops;
#ifdef CONFIG_QUOTA
- s->s_qcop = &reiserfs_qctl_operations;
- s->dq_op = &reiserfs_quota_operations;
+ s->s_qcop = &reiserfs_qctl_operations;
+ s->dq_op = &reiserfs_quota_operations;
#endif
- /* new format is limited by the 32 bit wide i_blocks field, want to
- ** be one full block below that.
- */
- s->s_maxbytes = (512LL << 32) - s->s_blocksize ;
- return 0;
+ /* new format is limited by the 32 bit wide i_blocks field, want to
+ ** be one full block below that.
+ */
+ s->s_maxbytes = (512LL << 32) - s->s_blocksize;
+ return 0;
}
-
-
/* after journal replay, reread all bitmap and super blocks */
-static int reread_meta_blocks(struct super_block *s) {
- int i ;
- ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))) ;
- wait_on_buffer(SB_BUFFER_WITH_SB(s)) ;
- if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
- reiserfs_warning (s, "reread_meta_blocks, error reading the super") ;
- return 1 ;
- }
-
- for (i = 0; i < SB_BMAP_NR(s) ; i++) {
- ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh)) ;
- wait_on_buffer(SB_AP_BITMAP(s)[i].bh) ;
- if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
- reiserfs_warning (s, "reread_meta_blocks, error reading bitmap block number %d at %llu",
- i, (unsigned long long)SB_AP_BITMAP(s)[i].bh->b_blocknr) ;
- return 1 ;
- }
- }
- return 0 ;
+static int reread_meta_blocks(struct super_block *s)
+{
+ int i;
+ ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s)));
+ wait_on_buffer(SB_BUFFER_WITH_SB(s));
+ if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) {
+ reiserfs_warning(s,
+ "reread_meta_blocks, error reading the super");
+ return 1;
+ }
-}
+ for (i = 0; i < SB_BMAP_NR(s); i++) {
+ ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i].bh));
+ wait_on_buffer(SB_AP_BITMAP(s)[i].bh);
+ if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) {
+ reiserfs_warning(s,
+ "reread_meta_blocks, error reading bitmap block number %d at %llu",
+ i,
+ (unsigned long long)SB_AP_BITMAP(s)[i].
+ bh->b_blocknr);
+ return 1;
+ }
+ }
+ return 0;
+}
/////////////////////////////////////////////////////
// hash detection stuff
-
// if root directory is empty - we set default - Yura's - hash and
// warn about it
// FIXME: we look for only one name in a directory. If tea and yura
// bith have the same value - we ask user to send report to the
// mailing list
-static __u32 find_hash_out (struct super_block * s)
+static __u32 find_hash_out(struct super_block *s)
{
- int retval;
- struct inode * inode;
- struct cpu_key key;
- INITIALIZE_PATH (path);
- struct reiserfs_dir_entry de;
- __u32 hash = DEFAULT_HASH;
-
- inode = s->s_root->d_inode;
-
- do { // Some serious "goto"-hater was there ;)
- u32 teahash, r5hash, yurahash;
-
- make_cpu_key (&key, inode, ~0, TYPE_DIRENTRY, 3);
- retval = search_by_entry_key (s, &key, &path, &de);
- if (retval == IO_ERROR) {
- pathrelse (&path);
- return UNSET_HASH ;
- }
- if (retval == NAME_NOT_FOUND)
- de.de_entry_num --;
- set_de_name_and_namelen (&de);
- if (deh_offset( &(de.de_deh[de.de_entry_num]) ) == DOT_DOT_OFFSET) {
- /* allow override in this case */
- if (reiserfs_rupasov_hash(s)) {
- hash = YURA_HASH ;
- }
- reiserfs_warning(s,"FS seems to be empty, autodetect "
- "is using the default hash");
- break;
- }
- r5hash=GET_HASH_VALUE (r5_hash (de.de_name, de.de_namelen));
- teahash=GET_HASH_VALUE (keyed_hash (de.de_name, de.de_namelen));
- yurahash=GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen));
- if ( ( (teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) ) ||
- ( (teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ||
- ( (r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))) ) ) {
- reiserfs_warning(s,"Unable to automatically detect hash function. "
- "Please mount with -o hash={tea,rupasov,r5}",
- reiserfs_bdevname (s));
- hash = UNSET_HASH;
- break;
- }
- if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == yurahash)
- hash = YURA_HASH;
- else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == teahash)
- hash = TEA_HASH;
- else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])) ) == r5hash)
- hash = R5_HASH;
- else {
- reiserfs_warning (s,"Unrecognised hash function");
- hash = UNSET_HASH;
- }
- } while (0);
-
- pathrelse (&path);
- return hash;
+ int retval;
+ struct inode *inode;
+ struct cpu_key key;
+ INITIALIZE_PATH(path);
+ struct reiserfs_dir_entry de;
+ __u32 hash = DEFAULT_HASH;
+
+ inode = s->s_root->d_inode;
+
+ do { // Some serious "goto"-hater was there ;)
+ u32 teahash, r5hash, yurahash;
+
+ make_cpu_key(&key, inode, ~0, TYPE_DIRENTRY, 3);
+ retval = search_by_entry_key(s, &key, &path, &de);
+ if (retval == IO_ERROR) {
+ pathrelse(&path);
+ return UNSET_HASH;
+ }
+ if (retval == NAME_NOT_FOUND)
+ de.de_entry_num--;
+ set_de_name_and_namelen(&de);
+ if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) {
+ /* allow override in this case */
+ if (reiserfs_rupasov_hash(s)) {
+ hash = YURA_HASH;
+ }
+ reiserfs_warning(s, "FS seems to be empty, autodetect "
+ "is using the default hash");
+ break;
+ }
+ r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen));
+ teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen));
+ yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen));
+ if (((teahash == r5hash)
+ &&
+ (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num])))
+ == r5hash)) || ((teahash == yurahash)
+ && (yurahash ==
+ GET_HASH_VALUE(deh_offset
+ (&
+ (de.
+ de_deh[de.
+ de_entry_num])))))
+ || ((r5hash == yurahash)
+ && (yurahash ==
+ GET_HASH_VALUE(deh_offset
+ (&(de.de_deh[de.de_entry_num])))))) {
+ reiserfs_warning(s,
+ "Unable to automatically detect hash function. "
+ "Please mount with -o hash={tea,rupasov,r5}",
+ reiserfs_bdevname(s));
+ hash = UNSET_HASH;
+ break;
+ }
+ if (GET_HASH_VALUE(deh_offset(&(de.de_deh[de.de_entry_num]))) ==
+ yurahash)
+ hash = YURA_HASH;
+ else if (GET_HASH_VALUE
+ (deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash)
+ hash = TEA_HASH;
+ else if (GET_HASH_VALUE
+ (deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)
+ hash = R5_HASH;
+ else {
+ reiserfs_warning(s, "Unrecognised hash function");
+ hash = UNSET_HASH;
+ }
+ } while (0);
+
+ pathrelse(&path);
+ return hash;
}
// finds out which hash names are sorted with
-static int what_hash (struct super_block * s)
+static int what_hash(struct super_block *s)
{
- __u32 code;
-
- code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s));
-
- /* reiserfs_hash_detect() == true if any of the hash mount options
- ** were used. We must check them to make sure the user isn't
- ** using a bad hash value
- */
- if (code == UNSET_HASH || reiserfs_hash_detect(s))
- code = find_hash_out (s);
-
- if (code != UNSET_HASH && reiserfs_hash_detect(s)) {
- /* detection has found the hash, and we must check against the
- ** mount options
- */
- if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
- reiserfs_warning (s, "Error, %s hash detected, "
- "unable to force rupasov hash", reiserfs_hashname(code)) ;
- code = UNSET_HASH ;
- } else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
- reiserfs_warning (s, "Error, %s hash detected, "
- "unable to force tea hash", reiserfs_hashname(code)) ;
- code = UNSET_HASH ;
- } else if (reiserfs_r5_hash(s) && code != R5_HASH) {
- reiserfs_warning (s, "Error, %s hash detected, "
- "unable to force r5 hash", reiserfs_hashname(code)) ;
- code = UNSET_HASH ;
- }
- } else {
- /* find_hash_out was not called or could not determine the hash */
- if (reiserfs_rupasov_hash(s)) {
- code = YURA_HASH ;
- } else if (reiserfs_tea_hash(s)) {
- code = TEA_HASH ;
- } else if (reiserfs_r5_hash(s)) {
- code = R5_HASH ;
- }
- }
-
- /* if we are mounted RW, and we have a new valid hash code, update
- ** the super
- */
- if (code != UNSET_HASH &&
- !(s->s_flags & MS_RDONLY) &&
- code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
- set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
- }
- return code;
+ __u32 code;
+
+ code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(s));
+
+ /* reiserfs_hash_detect() == true if any of the hash mount options
+ ** were used. We must check them to make sure the user isn't
+ ** using a bad hash value
+ */
+ if (code == UNSET_HASH || reiserfs_hash_detect(s))
+ code = find_hash_out(s);
+
+ if (code != UNSET_HASH && reiserfs_hash_detect(s)) {
+ /* detection has found the hash, and we must check against the
+ ** mount options
+ */
+ if (reiserfs_rupasov_hash(s) && code != YURA_HASH) {
+ reiserfs_warning(s, "Error, %s hash detected, "
+ "unable to force rupasov hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ } else if (reiserfs_tea_hash(s) && code != TEA_HASH) {
+ reiserfs_warning(s, "Error, %s hash detected, "
+ "unable to force tea hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ } else if (reiserfs_r5_hash(s) && code != R5_HASH) {
+ reiserfs_warning(s, "Error, %s hash detected, "
+ "unable to force r5 hash",
+ reiserfs_hashname(code));
+ code = UNSET_HASH;
+ }
+ } else {
+ /* find_hash_out was not called or could not determine the hash */
+ if (reiserfs_rupasov_hash(s)) {
+ code = YURA_HASH;
+ } else if (reiserfs_tea_hash(s)) {
+ code = TEA_HASH;
+ } else if (reiserfs_r5_hash(s)) {
+ code = R5_HASH;
+ }
+ }
+
+ /* if we are mounted RW, and we have a new valid hash code, update
+ ** the super
+ */
+ if (code != UNSET_HASH &&
+ !(s->s_flags & MS_RDONLY) &&
+ code != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) {
+ set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code);
+ }
+ return code;
}
// return pointer to appropriate function
-static hashf_t hash_function (struct super_block * s)
+static hashf_t hash_function(struct super_block *s)
{
- switch (what_hash (s)) {
- case TEA_HASH:
- reiserfs_info (s, "Using tea hash to sort names\n");
- return keyed_hash;
- case YURA_HASH:
- reiserfs_info (s, "Using rupasov hash to sort names\n");
- return yura_hash;
- case R5_HASH:
- reiserfs_info (s, "Using r5 hash to sort names\n");
- return r5_hash;
- }
- return NULL;
+ switch (what_hash(s)) {
+ case TEA_HASH:
+ reiserfs_info(s, "Using tea hash to sort names\n");
+ return keyed_hash;
+ case YURA_HASH:
+ reiserfs_info(s, "Using rupasov hash to sort names\n");
+ return yura_hash;
+ case R5_HASH:
+ reiserfs_info(s, "Using r5 hash to sort names\n");
+ return r5_hash;
+ }
+ return NULL;
}
// this is used to set up correct value for old partitions
-static int function2code (hashf_t func)
+static int function2code(hashf_t func)
{
- if (func == keyed_hash)
- return TEA_HASH;
- if (func == yura_hash)
- return YURA_HASH;
- if (func == r5_hash)
- return R5_HASH;
+ if (func == keyed_hash)
+ return TEA_HASH;
+ if (func == yura_hash)
+ return YURA_HASH;
+ if (func == r5_hash)
+ return R5_HASH;
- BUG() ; // should never happen
+ BUG(); // should never happen
- return 0;
+ return 0;
}
#define SWARN(silent, s, ...) \
if (!(silent)) \
reiserfs_warning (s, __VA_ARGS__)
-static int reiserfs_fill_super (struct super_block * s, void * data, int silent)
+static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
{
- struct inode *root_inode;
- int j;
- struct reiserfs_transaction_handle th ;
- int old_format = 0;
- unsigned long blocks;
- unsigned int commit_max_age = 0;
- int jinit_done = 0 ;
- struct reiserfs_iget_args args ;
- struct reiserfs_super_block * rs;
- char *jdev_name;
- struct reiserfs_sb_info *sbi;
- int errval = -EINVAL;
-
- sbi = kmalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
- if (!sbi) {
- errval = -ENOMEM;
- goto error;
- }
- s->s_fs_info = sbi;
- memset (sbi, 0, sizeof (struct reiserfs_sb_info));
- /* Set default values for options: non-aggressive tails, RO on errors */
- REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
- REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO);
- /* no preallocation minimum, be smart in
- reiserfs_file_write instead */
- REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
- /* Preallocate by 16 blocks (17-1) at once */
- REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
- /* Initialize the rwsem for xattr dir */
- init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
-
- /* setup default block allocator options */
- reiserfs_init_alloc_options(s);
-
- jdev_name = NULL;
- if (reiserfs_parse_options (s, (char *) data, &(sbi->s_mount_opt), &blocks, &jdev_name, &commit_max_age) == 0) {
- goto error;
- }
-
- if (blocks) {
- SWARN (silent, s, "jmacd-7: reiserfs_fill_super: resize option "
- "for remount only");
- goto error;
- }
-
- /* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
- if (!read_super_block (s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))
- old_format = 1;
- /* try new format (64-th 1k block), which can contain reiserfs super block */
- else if (read_super_block (s, REISERFS_DISK_OFFSET_IN_BYTES)) {
- SWARN(silent, s, "sh-2021: reiserfs_fill_super: can not find reiserfs on %s", reiserfs_bdevname (s));
- goto error;
- }
-
- rs = SB_DISK_SUPER_BLOCK (s);
- /* Let's do basic sanity check to verify that underlying device is not
- smaller than the filesystem. If the check fails then abort and scream,
- because bad stuff will happen otherwise. */
- if ( s->s_bdev && s->s_bdev->bd_inode && i_size_read(s->s_bdev->bd_inode) < sb_block_count(rs)*sb_blocksize(rs)) {
- SWARN (silent, s, "Filesystem on %s cannot be mounted because it is bigger than the device", reiserfs_bdevname(s));
- SWARN(silent, s, "You may need to run fsck or increase size of your LVM partition");
- SWARN(silent, s, "Or may be you forgot to reboot after fdisk when it told you to");
- goto error;
- }
-
- sbi->s_mount_state = SB_REISERFS_STATE(s);
- sbi->s_mount_state = REISERFS_VALID_FS ;
-
- if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) {
- SWARN(silent, s, "jmacd-8: reiserfs_fill_super: unable to read bitmap");
- goto error;
- }
+ struct inode *root_inode;
+ int j;
+ struct reiserfs_transaction_handle th;
+ int old_format = 0;
+ unsigned long blocks;
+ unsigned int commit_max_age = 0;
+ int jinit_done = 0;
+ struct reiserfs_iget_args args;
+ struct reiserfs_super_block *rs;
+ char *jdev_name;
+ struct reiserfs_sb_info *sbi;
+ int errval = -EINVAL;
+
+ sbi = kmalloc(sizeof(struct reiserfs_sb_info), GFP_KERNEL);
+ if (!sbi) {
+ errval = -ENOMEM;
+ goto error;
+ }
+ s->s_fs_info = sbi;
+ memset(sbi, 0, sizeof(struct reiserfs_sb_info));
+ /* Set default values for options: non-aggressive tails, RO on errors */
+ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_SMALLTAIL);
+ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_ERROR_RO);
+ /* no preallocation minimum, be smart in
+ reiserfs_file_write instead */
+ REISERFS_SB(s)->s_alloc_options.preallocmin = 0;
+ /* Preallocate by 16 blocks (17-1) at once */
+ REISERFS_SB(s)->s_alloc_options.preallocsize = 17;
+ /* Initialize the rwsem for xattr dir */
+ init_rwsem(&REISERFS_SB(s)->xattr_dir_sem);
+
+ /* setup default block allocator options */
+ reiserfs_init_alloc_options(s);
+
+ jdev_name = NULL;
+ if (reiserfs_parse_options
+ (s, (char *)data, &(sbi->s_mount_opt), &blocks, &jdev_name,
+ &commit_max_age) == 0) {
+ goto error;
+ }
+
+ if (blocks) {
+ SWARN(silent, s, "jmacd-7: reiserfs_fill_super: resize option "
+ "for remount only");
+ goto error;
+ }
+
+ /* try old format (undistributed bitmap, super block in 8-th 1k block of a device) */
+ if (!read_super_block(s, REISERFS_OLD_DISK_OFFSET_IN_BYTES))
+ old_format = 1;
+ /* try new format (64-th 1k block), which can contain reiserfs super block */
+ else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
+ SWARN(silent, s,
+ "sh-2021: reiserfs_fill_super: can not find reiserfs on %s",
+ reiserfs_bdevname(s));
+ goto error;
+ }
+
+ rs = SB_DISK_SUPER_BLOCK(s);
+ /* Let's do basic sanity check to verify that underlying device is not
+ smaller than the filesystem. If the check fails then abort and scream,
+ because bad stuff will happen otherwise. */
+ if (s->s_bdev && s->s_bdev->bd_inode
+ && i_size_read(s->s_bdev->bd_inode) <
+ sb_block_count(rs) * sb_blocksize(rs)) {
+ SWARN(silent, s,
+ "Filesystem on %s cannot be mounted because it is bigger than the device",
+ reiserfs_bdevname(s));
+ SWARN(silent, s,
+ "You may need to run fsck or increase size of your LVM partition");
+ SWARN(silent, s,
+ "Or may be you forgot to reboot after fdisk when it told you to");
+ goto error;
+ }
+
+ sbi->s_mount_state = SB_REISERFS_STATE(s);
+ sbi->s_mount_state = REISERFS_VALID_FS;
+
+ if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) {
+ SWARN(silent, s,
+ "jmacd-8: reiserfs_fill_super: unable to read bitmap");
+ goto error;
+ }
#ifdef CONFIG_REISERFS_CHECK
- SWARN (silent, s, "CONFIG_REISERFS_CHECK is set ON");
- SWARN (silent, s, "- it is slow mode for debugging.");
+ SWARN(silent, s, "CONFIG_REISERFS_CHECK is set ON");
+ SWARN(silent, s, "- it is slow mode for debugging.");
#endif
- /* make data=ordered the default */
- if (!reiserfs_data_log(s) && !reiserfs_data_ordered(s) &&
- !reiserfs_data_writeback(s))
- {
- REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
- }
-
- if (reiserfs_data_log(s)) {
- reiserfs_info (s, "using journaled data mode\n");
- } else if (reiserfs_data_ordered(s)) {
- reiserfs_info (s, "using ordered data mode\n");
- } else {
- reiserfs_info (s, "using writeback data mode\n");
- }
- if (reiserfs_barrier_flush(s)) {
- printk("reiserfs: using flush barriers\n");
- }
-
- // set_device_ro(s->s_dev, 1) ;
- if( journal_init(s, jdev_name, old_format, commit_max_age) ) {
- SWARN(silent, s, "sh-2022: reiserfs_fill_super: unable to initialize journal space") ;
- goto error ;
- } else {
- jinit_done = 1 ; /* once this is set, journal_release must be called
- ** if we error out of the mount
- */
- }
- if (reread_meta_blocks(s)) {
- SWARN(silent, s, "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init") ;
- goto error ;
- }
-
- if (replay_only (s))
- goto error;
-
- if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
- SWARN(silent, s, "clm-7000: Detected readonly device, marking FS readonly") ;
- s->s_flags |= MS_RDONLY ;
- }
- args.objectid = REISERFS_ROOT_OBJECTID ;
- args.dirid = REISERFS_ROOT_PARENT_OBJECTID ;
- root_inode = iget5_locked (s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor, reiserfs_init_locked_inode, (void *)(&args));
- if (!root_inode) {
- SWARN(silent, s, "jmacd-10: reiserfs_fill_super: get root inode failed");
- goto error;
- }
-
- if (root_inode->i_state & I_NEW) {
- reiserfs_read_locked_inode(root_inode, &args);
- unlock_new_inode(root_inode);
- }
-
- s->s_root = d_alloc_root(root_inode);
- if (!s->s_root) {
- iput(root_inode);
- goto error;
- }
-
- // define and initialize hash function
- sbi->s_hash_function = hash_function (s);
- if (sbi->s_hash_function == NULL) {
- dput(s->s_root) ;
- s->s_root = NULL ;
- goto error ;
- }
-
- if (is_reiserfs_3_5 (rs) || (is_reiserfs_jr (rs) && SB_VERSION (s) == REISERFS_VERSION_1))
- set_bit(REISERFS_3_5, &(sbi->s_properties));
- else
- set_bit(REISERFS_3_6, &(sbi->s_properties));
-
- if (!(s->s_flags & MS_RDONLY)) {
-
- errval = journal_begin(&th, s, 1) ;
- if (errval) {
- dput (s->s_root);
- s->s_root = NULL;
- goto error;
- }
- reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ;
-
- set_sb_umount_state( rs, REISERFS_ERROR_FS );
- set_sb_fs_state (rs, 0);
-
- if (old_format_only(s)) {
- /* filesystem of format 3.5 either with standard or non-standard
- journal */
- if (convert_reiserfs (s)) {
- /* and -o conv is given */
- if(!silent)
- reiserfs_info (s,"converting 3.5 filesystem to the 3.6 format") ;
-
- if (is_reiserfs_3_5 (rs))
- /* put magic string of 3.6 format. 2.2 will not be able to
- mount this filesystem anymore */
- memcpy (rs->s_v1.s_magic, reiserfs_3_6_magic_string,
- sizeof (reiserfs_3_6_magic_string));
-
- set_sb_version(rs,REISERFS_VERSION_2);
- reiserfs_convert_objectid_map_v1(s) ;
- set_bit(REISERFS_3_6, &(sbi->s_properties));
- clear_bit(REISERFS_3_5, &(sbi->s_properties));
- } else if (!silent){
- reiserfs_info (s, "using 3.5.x disk format\n") ;
- }
- }
-
- journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s));
- errval = journal_end(&th, s, 1) ;
- if (errval) {
- dput (s->s_root);
- s->s_root = NULL;
- goto error;
- }
-
- if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
- dput (s->s_root);
- s->s_root = NULL;
- goto error;
- }
-
- /* look for files which were to be removed in previous session */
- finish_unfinished (s);
- } else {
- if ( old_format_only(s) && !silent) {
- reiserfs_info (s, "using 3.5.x disk format\n") ;
- }
-
- if ((errval = reiserfs_xattr_init (s, s->s_flags))) {
- dput (s->s_root);
- s->s_root = NULL;
- goto error;
- }
- }
- // mark hash in super block: it could be unset. overwrite should be ok
- set_sb_hash_function_code( rs, function2code(sbi->s_hash_function ) );
-
- handle_attrs( s );
-
- reiserfs_proc_info_init( s );
-
- init_waitqueue_head (&(sbi->s_wait));
- spin_lock_init(&sbi->bitmap_lock);
-
- return (0);
-
- error:
- if (jinit_done) { /* kill the commit thread, free journal ram */
- journal_release_error(NULL, s) ;
- }
- if (SB_DISK_SUPER_BLOCK (s)) {
- for (j = 0; j < SB_BMAP_NR (s); j ++) {
- if (SB_AP_BITMAP (s))
- brelse (SB_AP_BITMAP (s)[j].bh);
- }
- if (SB_AP_BITMAP (s))
- vfree (SB_AP_BITMAP (s));
- }
- if (SB_BUFFER_WITH_SB (s))
- brelse(SB_BUFFER_WITH_SB (s));
+ /* make data=ordered the default */
+ if (!reiserfs_data_log(s) && !reiserfs_data_ordered(s) &&
+ !reiserfs_data_writeback(s)) {
+ REISERFS_SB(s)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
+ }
+
+ if (reiserfs_data_log(s)) {
+ reiserfs_info(s, "using journaled data mode\n");
+ } else if (reiserfs_data_ordered(s)) {
+ reiserfs_info(s, "using ordered data mode\n");
+ } else {
+ reiserfs_info(s, "using writeback data mode\n");
+ }
+ if (reiserfs_barrier_flush(s)) {
+ printk("reiserfs: using flush barriers\n");
+ }
+ // set_device_ro(s->s_dev, 1) ;
+ if (journal_init(s, jdev_name, old_format, commit_max_age)) {
+ SWARN(silent, s,
+ "sh-2022: reiserfs_fill_super: unable to initialize journal space");
+ goto error;
+ } else {
+ jinit_done = 1; /* once this is set, journal_release must be called
+ ** if we error out of the mount
+ */
+ }
+ if (reread_meta_blocks(s)) {
+ SWARN(silent, s,
+ "jmacd-9: reiserfs_fill_super: unable to reread meta blocks after journal init");
+ goto error;
+ }
+
+ if (replay_only(s))
+ goto error;
+
+ if (bdev_read_only(s->s_bdev) && !(s->s_flags & MS_RDONLY)) {
+ SWARN(silent, s,
+ "clm-7000: Detected readonly device, marking FS readonly");
+ s->s_flags |= MS_RDONLY;
+ }
+ args.objectid = REISERFS_ROOT_OBJECTID;
+ args.dirid = REISERFS_ROOT_PARENT_OBJECTID;
+ root_inode =
+ iget5_locked(s, REISERFS_ROOT_OBJECTID, reiserfs_find_actor,
+ reiserfs_init_locked_inode, (void *)(&args));
+ if (!root_inode) {
+ SWARN(silent, s,
+ "jmacd-10: reiserfs_fill_super: get root inode failed");
+ goto error;
+ }
+
+ if (root_inode->i_state & I_NEW) {
+ reiserfs_read_locked_inode(root_inode, &args);
+ unlock_new_inode(root_inode);
+ }
+
+ s->s_root = d_alloc_root(root_inode);
+ if (!s->s_root) {
+ iput(root_inode);
+ goto error;
+ }
+ // define and initialize hash function
+ sbi->s_hash_function = hash_function(s);
+ if (sbi->s_hash_function == NULL) {
+ dput(s->s_root);
+ s->s_root = NULL;
+ goto error;
+ }
+
+ if (is_reiserfs_3_5(rs)
+ || (is_reiserfs_jr(rs) && SB_VERSION(s) == REISERFS_VERSION_1))
+ set_bit(REISERFS_3_5, &(sbi->s_properties));
+ else
+ set_bit(REISERFS_3_6, &(sbi->s_properties));
+
+ if (!(s->s_flags & MS_RDONLY)) {
+
+ errval = journal_begin(&th, s, 1);
+ if (errval) {
+ dput(s->s_root);
+ s->s_root = NULL;
+ goto error;
+ }
+ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1);
+
+ set_sb_umount_state(rs, REISERFS_ERROR_FS);
+ set_sb_fs_state(rs, 0);
+
+ if (old_format_only(s)) {
+ /* filesystem of format 3.5 either with standard or non-standard
+ journal */
+ if (convert_reiserfs(s)) {
+ /* and -o conv is given */
+ if (!silent)
+ reiserfs_info(s,
+ "converting 3.5 filesystem to the 3.6 format");
+
+ if (is_reiserfs_3_5(rs))
+ /* put magic string of 3.6 format. 2.2 will not be able to
+ mount this filesystem anymore */
+ memcpy(rs->s_v1.s_magic,
+ reiserfs_3_6_magic_string,
+ sizeof
+ (reiserfs_3_6_magic_string));
+
+ set_sb_version(rs, REISERFS_VERSION_2);
+ reiserfs_convert_objectid_map_v1(s);
+ set_bit(REISERFS_3_6, &(sbi->s_properties));
+ clear_bit(REISERFS_3_5, &(sbi->s_properties));
+ } else if (!silent) {
+ reiserfs_info(s, "using 3.5.x disk format\n");
+ }
+ }
+
+ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB(s));
+ errval = journal_end(&th, s, 1);
+ if (errval) {
+ dput(s->s_root);
+ s->s_root = NULL;
+ goto error;
+ }
+
+ if ((errval = reiserfs_xattr_init(s, s->s_flags))) {
+ dput(s->s_root);
+ s->s_root = NULL;
+ goto error;
+ }
+
+ /* look for files which were to be removed in previous session */
+ finish_unfinished(s);
+ } else {
+ if (old_format_only(s) && !silent) {
+ reiserfs_info(s, "using 3.5.x disk format\n");
+ }
+
+ if ((errval = reiserfs_xattr_init(s, s->s_flags))) {
+ dput(s->s_root);
+ s->s_root = NULL;
+ goto error;
+ }
+ }
+ // mark hash in super block: it could be unset. overwrite should be ok
+ set_sb_hash_function_code(rs, function2code(sbi->s_hash_function));
+
+ handle_attrs(s);
+
+ reiserfs_proc_info_init(s);
+
+ init_waitqueue_head(&(sbi->s_wait));
+ spin_lock_init(&sbi->bitmap_lock);
+
+ return (0);
+
+ error:
+ if (jinit_done) { /* kill the commit thread, free journal ram */
+ journal_release_error(NULL, s);
+ }
+ if (SB_DISK_SUPER_BLOCK(s)) {
+ for (j = 0; j < SB_BMAP_NR(s); j++) {
+ if (SB_AP_BITMAP(s))
+ brelse(SB_AP_BITMAP(s)[j].bh);
+ }
+ if (SB_AP_BITMAP(s))
+ vfree(SB_AP_BITMAP(s));
+ }
+ if (SB_BUFFER_WITH_SB(s))
+ brelse(SB_BUFFER_WITH_SB(s));
#ifdef CONFIG_QUOTA
- for (j = 0; j < MAXQUOTAS; j++) {
- if (sbi->s_qf_names[j])
- kfree(sbi->s_qf_names[j]);
- }
+ for (j = 0; j < MAXQUOTAS; j++) {
+ if (sbi->s_qf_names[j])
+ kfree(sbi->s_qf_names[j]);
+ }
#endif
- if (sbi != NULL) {
- kfree(sbi);
- }
+ if (sbi != NULL) {
+ kfree(sbi);
+ }
- s->s_fs_info = NULL;
- return errval;
+ s->s_fs_info = NULL;
+ return errval;
}
-
-static int reiserfs_statfs (struct super_block * s, struct kstatfs * buf)
+static int reiserfs_statfs(struct super_block *s, struct kstatfs *buf)
{
- struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s);
-
- buf->f_namelen = (REISERFS_MAX_NAME (s->s_blocksize));
- buf->f_bfree = sb_free_blocks(rs);
- buf->f_bavail = buf->f_bfree;
- buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
- buf->f_bsize = s->s_blocksize;
- /* changed to accommodate gcc folks.*/
- buf->f_type = REISERFS_SUPER_MAGIC;
- return 0;
+ struct reiserfs_super_block *rs = SB_DISK_SUPER_BLOCK(s);
+
+ buf->f_namelen = (REISERFS_MAX_NAME(s->s_blocksize));
+ buf->f_bfree = sb_free_blocks(rs);
+ buf->f_bavail = buf->f_bfree;
+ buf->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1;
+ buf->f_bsize = s->s_blocksize;
+ /* changed to accommodate gcc folks. */
+ buf->f_type = REISERFS_SUPER_MAGIC;
+ return 0;
}
#ifdef CONFIG_QUOTA
static int reiserfs_dquot_initialize(struct inode *inode, int type)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- /* We may create quota structure so we need to reserve enough blocks */
- reiserfs_write_lock(inode->i_sb);
- journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
- ret = dquot_initialize(inode, type);
- journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
- reiserfs_write_unlock(inode->i_sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ /* We may create quota structure so we need to reserve enough blocks */
+ reiserfs_write_lock(inode->i_sb);
+ ret =
+ journal_begin(&th, inode->i_sb,
+ 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
+ if (ret)
+ goto out;
+ ret = dquot_initialize(inode, type);
+ err =
+ journal_end(&th, inode->i_sb,
+ 2 * REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb));
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(inode->i_sb);
+ return ret;
}
static int reiserfs_dquot_drop(struct inode *inode)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- /* We may delete quota structure so we need to reserve enough blocks */
- reiserfs_write_lock(inode->i_sb);
- journal_begin(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
- ret = dquot_drop(inode);
- journal_end(&th, inode->i_sb, 2*REISERFS_QUOTA_INIT_BLOCKS);
- reiserfs_write_unlock(inode->i_sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ /* We may delete quota structure so we need to reserve enough blocks */
+ reiserfs_write_lock(inode->i_sb);
+ ret =
+ journal_begin(&th, inode->i_sb,
+ 2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
+ if (ret)
+ goto out;
+ ret = dquot_drop(inode);
+ err =
+ journal_end(&th, inode->i_sb,
+ 2 * REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb));
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(inode->i_sb);
+ return ret;
}
static int reiserfs_write_dquot(struct dquot *dquot)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- reiserfs_write_lock(dquot->dq_sb);
- journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS);
- ret = dquot_commit(dquot);
- journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_TRANS_BLOCKS);
- reiserfs_write_unlock(dquot->dq_sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ reiserfs_write_lock(dquot->dq_sb);
+ ret =
+ journal_begin(&th, dquot->dq_sb,
+ REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+ if (ret)
+ goto out;
+ ret = dquot_commit(dquot);
+ err =
+ journal_end(&th, dquot->dq_sb,
+ REISERFS_QUOTA_TRANS_BLOCKS(dquot->dq_sb));
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(dquot->dq_sb);
+ return ret;
}
static int reiserfs_acquire_dquot(struct dquot *dquot)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- reiserfs_write_lock(dquot->dq_sb);
- journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
- ret = dquot_acquire(dquot);
- journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
- reiserfs_write_unlock(dquot->dq_sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ reiserfs_write_lock(dquot->dq_sb);
+ ret =
+ journal_begin(&th, dquot->dq_sb,
+ REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+ if (ret)
+ goto out;
+ ret = dquot_acquire(dquot);
+ err =
+ journal_end(&th, dquot->dq_sb,
+ REISERFS_QUOTA_INIT_BLOCKS(dquot->dq_sb));
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(dquot->dq_sb);
+ return ret;
}
static int reiserfs_release_dquot(struct dquot *dquot)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- reiserfs_write_lock(dquot->dq_sb);
- journal_begin(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
- ret = dquot_release(dquot);
- journal_end(&th, dquot->dq_sb, REISERFS_QUOTA_INIT_BLOCKS);
- reiserfs_write_unlock(dquot->dq_sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ reiserfs_write_lock(dquot->dq_sb);
+ ret =
+ journal_begin(&th, dquot->dq_sb,
+ REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+ if (ret)
+ goto out;
+ ret = dquot_release(dquot);
+ err =
+ journal_end(&th, dquot->dq_sb,
+ REISERFS_QUOTA_DEL_BLOCKS(dquot->dq_sb));
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(dquot->dq_sb);
+ return ret;
}
static int reiserfs_mark_dquot_dirty(struct dquot *dquot)
{
- /* Are we journalling quotas? */
- if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
- REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
- dquot_mark_dquot_dirty(dquot);
- return reiserfs_write_dquot(dquot);
- }
- else
- return dquot_mark_dquot_dirty(dquot);
+ /* Are we journalling quotas? */
+ if (REISERFS_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] ||
+ REISERFS_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) {
+ dquot_mark_dquot_dirty(dquot);
+ return reiserfs_write_dquot(dquot);
+ } else
+ return dquot_mark_dquot_dirty(dquot);
}
static int reiserfs_write_info(struct super_block *sb, int type)
{
- struct reiserfs_transaction_handle th;
- int ret;
-
- /* Data block + inode block */
- reiserfs_write_lock(sb);
- journal_begin(&th, sb, 2);
- ret = dquot_commit_info(sb, type);
- journal_end(&th, sb, 2);
- reiserfs_write_unlock(sb);
- return ret;
+ struct reiserfs_transaction_handle th;
+ int ret, err;
+
+ /* Data block + inode block */
+ reiserfs_write_lock(sb);
+ ret = journal_begin(&th, sb, 2);
+ if (ret)
+ goto out;
+ ret = dquot_commit_info(sb, type);
+ err = journal_end(&th, sb, 2);
+ if (!ret && err)
+ ret = err;
+ out:
+ reiserfs_write_unlock(sb);
+ return ret;
}
/*
@@ -1937,43 +2116,48 @@ static int reiserfs_write_info(struct super_block *sb, int type)
static int reiserfs_quota_on_mount(struct super_block *sb, int type)
{
return vfs_quota_on_mount(sb, REISERFS_SB(sb)->s_qf_names[type],
- REISERFS_SB(sb)->s_jquota_fmt, type);
+ REISERFS_SB(sb)->s_jquota_fmt, type);
}
/*
* Standard function to be called on quota_on
*/
-static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, char *path)
+static int reiserfs_quota_on(struct super_block *sb, int type, int format_id,
+ char *path)
{
- int err;
- struct nameidata nd;
-
- err = path_lookup(path, LOOKUP_FOLLOW, &nd);
- if (err)
- return err;
- /* Quotafile not on the same filesystem? */
- if (nd.mnt->mnt_sb != sb) {
- path_release(&nd);
- return -EXDEV;
- }
- /* We must not pack tails for quota files on reiserfs for quota IO to work */
- if (!REISERFS_I(nd.dentry->d_inode)->i_flags & i_nopack_mask) {
- reiserfs_warning(sb, "reiserfs: Quota file must have tail packing disabled.");
- path_release(&nd);
- return -EINVAL;
- }
- /* Not journalling quota? No more tests needed... */
- if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] &&
- !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) {
+ int err;
+ struct nameidata nd;
+
+ if (!(REISERFS_SB(sb)->s_mount_opt & (1 << REISERFS_QUOTA)))
+ return -EINVAL;
+ err = path_lookup(path, LOOKUP_FOLLOW, &nd);
+ if (err)
+ return err;
+ /* Quotafile not on the same filesystem? */
+ if (nd.mnt->mnt_sb != sb) {
+ path_release(&nd);
+ return -EXDEV;
+ }
+ /* We must not pack tails for quota files on reiserfs for quota IO to work */
+ if (!REISERFS_I(nd.dentry->d_inode)->i_flags & i_nopack_mask) {
+ reiserfs_warning(sb,
+ "reiserfs: Quota file must have tail packing disabled.");
+ path_release(&nd);
+ return -EINVAL;
+ }
+ /* Not journalling quota? No more tests needed... */
+ if (!REISERFS_SB(sb)->s_qf_names[USRQUOTA] &&
+ !REISERFS_SB(sb)->s_qf_names[GRPQUOTA]) {
+ path_release(&nd);
+ return vfs_quota_on(sb, type, format_id, path);
+ }
+ /* Quotafile not of fs root? */
+ if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
+ reiserfs_warning(sb,
+ "reiserfs: Quota file not on filesystem root. "
+ "Journalled quota will not work.");
path_release(&nd);
- return vfs_quota_on(sb, type, format_id, path);
- }
- /* Quotafile not of fs root? */
- if (nd.dentry->d_parent->d_inode != sb->s_root->d_inode)
- reiserfs_warning(sb, "reiserfs: Quota file not on filesystem root. "
- "Journalled quota will not work.");
- path_release(&nd);
- return vfs_quota_on(sb, type, format_id, path);
+ return vfs_quota_on(sb, type, format_id, path);
}
/* Read data from quotafile - avoid pagecache and such because we cannot afford
@@ -1983,42 +2167,44 @@ static int reiserfs_quota_on(struct super_block *sb, int type, int format_id, ch
static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off)
{
- struct inode *inode = sb_dqopt(sb)->files[type];
- unsigned long blk = off >> sb->s_blocksize_bits;
- int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
- size_t toread;
- struct buffer_head tmp_bh, *bh;
- loff_t i_size = i_size_read(inode);
-
- if (off > i_size)
- return 0;
- if (off+len > i_size)
- len = i_size-off;
- toread = len;
- while (toread > 0) {
- tocopy = sb->s_blocksize - offset < toread ? sb->s_blocksize - offset : toread;
- tmp_bh.b_state = 0;
- /* Quota files are without tails so we can safely use this function */
- reiserfs_write_lock(sb);
- err = reiserfs_get_block(inode, blk, &tmp_bh, 0);
- reiserfs_write_unlock(sb);
- if (err)
- return err;
- if (!buffer_mapped(&tmp_bh)) /* A hole? */
- memset(data, 0, tocopy);
- else {
- bh = sb_bread(sb, tmp_bh.b_blocknr);
- if (!bh)
- return -EIO;
- memcpy(data, bh->b_data+offset, tocopy);
- brelse(bh);
- }
- offset = 0;
- toread -= tocopy;
- data += tocopy;
- blk++;
- }
- return len;
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ unsigned long blk = off >> sb->s_blocksize_bits;
+ int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
+ size_t toread;
+ struct buffer_head tmp_bh, *bh;
+ loff_t i_size = i_size_read(inode);
+
+ if (off > i_size)
+ return 0;
+ if (off + len > i_size)
+ len = i_size - off;
+ toread = len;
+ while (toread > 0) {
+ tocopy =
+ sb->s_blocksize - offset <
+ toread ? sb->s_blocksize - offset : toread;
+ tmp_bh.b_state = 0;
+ /* Quota files are without tails so we can safely use this function */
+ reiserfs_write_lock(sb);
+ err = reiserfs_get_block(inode, blk, &tmp_bh, 0);
+ reiserfs_write_unlock(sb);
+ if (err)
+ return err;
+ if (!buffer_mapped(&tmp_bh)) /* A hole? */
+ memset(data, 0, tocopy);
+ else {
+ bh = sb_bread(sb, tmp_bh.b_blocknr);
+ if (!bh)
+ return -EIO;
+ memcpy(data, bh->b_data + offset, tocopy);
+ brelse(bh);
+ }
+ offset = 0;
+ toread -= tocopy;
+ data += tocopy;
+ blk++;
+ }
+ return len;
}
/* Write to quotafile (we know the transaction is already started and has
@@ -2026,117 +2212,116 @@ static ssize_t reiserfs_quota_read(struct super_block *sb, int type, char *data,
static ssize_t reiserfs_quota_write(struct super_block *sb, int type,
const char *data, size_t len, loff_t off)
{
- struct inode *inode = sb_dqopt(sb)->files[type];
- unsigned long blk = off >> sb->s_blocksize_bits;
- int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
- int journal_quota = REISERFS_SB(sb)->s_qf_names[type] != NULL;
- size_t towrite = len;
- struct buffer_head tmp_bh, *bh;
-
- down(&inode->i_sem);
- while (towrite > 0) {
- tocopy = sb->s_blocksize - offset < towrite ?
- sb->s_blocksize - offset : towrite;
- tmp_bh.b_state = 0;
- err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
- if (err)
- goto out;
- if (offset || tocopy != sb->s_blocksize)
- bh = sb_bread(sb, tmp_bh.b_blocknr);
- else
- bh = sb_getblk(sb, tmp_bh.b_blocknr);
- if (!bh) {
- err = -EIO;
- goto out;
- }
- lock_buffer(bh);
- memcpy(bh->b_data+offset, data, tocopy);
- flush_dcache_page(bh->b_page);
- set_buffer_uptodate(bh);
- unlock_buffer(bh);
- reiserfs_prepare_for_journal(sb, bh, 1);
- journal_mark_dirty(current->journal_info, sb, bh);
- if (!journal_quota)
- reiserfs_add_ordered_list(inode, bh);
- brelse(bh);
- offset = 0;
- towrite -= tocopy;
- data += tocopy;
- blk++;
- }
-out:
- if (len == towrite)
- return err;
- if (inode->i_size < off+len-towrite)
- i_size_write(inode, off+len-towrite);
- inode->i_version++;
- inode->i_mtime = inode->i_ctime = CURRENT_TIME;
- mark_inode_dirty(inode);
- up(&inode->i_sem);
- return len - towrite;
+ struct inode *inode = sb_dqopt(sb)->files[type];
+ unsigned long blk = off >> sb->s_blocksize_bits;
+ int err = 0, offset = off & (sb->s_blocksize - 1), tocopy;
+ int journal_quota = REISERFS_SB(sb)->s_qf_names[type] != NULL;
+ size_t towrite = len;
+ struct buffer_head tmp_bh, *bh;
+
+ down(&inode->i_sem);
+ while (towrite > 0) {
+ tocopy = sb->s_blocksize - offset < towrite ?
+ sb->s_blocksize - offset : towrite;
+ tmp_bh.b_state = 0;
+ err = reiserfs_get_block(inode, blk, &tmp_bh, GET_BLOCK_CREATE);
+ if (err)
+ goto out;
+ if (offset || tocopy != sb->s_blocksize)
+ bh = sb_bread(sb, tmp_bh.b_blocknr);
+ else
+ bh = sb_getblk(sb, tmp_bh.b_blocknr);
+ if (!bh) {
+ err = -EIO;
+ goto out;
+ }
+ lock_buffer(bh);
+ memcpy(bh->b_data + offset, data, tocopy);
+ flush_dcache_page(bh->b_page);
+ set_buffer_uptodate(bh);
+ unlock_buffer(bh);
+ reiserfs_prepare_for_journal(sb, bh, 1);
+ journal_mark_dirty(current->journal_info, sb, bh);
+ if (!journal_quota)
+ reiserfs_add_ordered_list(inode, bh);
+ brelse(bh);
+ offset = 0;
+ towrite -= tocopy;
+ data += tocopy;
+ blk++;
+ }
+ out:
+ if (len == towrite)
+ return err;
+ if (inode->i_size < off + len - towrite)
+ i_size_write(inode, off + len - towrite);
+ inode->i_version++;
+ inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ mark_inode_dirty(inode);
+ up(&inode->i_sem);
+ return len - towrite;
}
#endif
-static struct super_block*
-get_super_block (struct file_system_type *fs_type, int flags,
- const char *dev_name, void *data)
+static struct super_block *get_super_block(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
{
return get_sb_bdev(fs_type, flags, dev_name, data, reiserfs_fill_super);
}
-static int __init
-init_reiserfs_fs ( void )
+static int __init init_reiserfs_fs(void)
{
int ret;
- if ((ret = init_inodecache ())) {
+ if ((ret = init_inodecache())) {
return ret;
}
- if ((ret = reiserfs_xattr_register_handlers ()))
- goto failed_reiserfs_xattr_register_handlers;
+ if ((ret = reiserfs_xattr_register_handlers()))
+ goto failed_reiserfs_xattr_register_handlers;
- reiserfs_proc_info_global_init ();
- reiserfs_proc_register_global ("version", reiserfs_global_version_in_proc);
+ reiserfs_proc_info_global_init();
+ reiserfs_proc_register_global("version",
+ reiserfs_global_version_in_proc);
- ret = register_filesystem (& reiserfs_fs_type);
+ ret = register_filesystem(&reiserfs_fs_type);
if (ret == 0) {
return 0;
}
- reiserfs_xattr_unregister_handlers ();
+ reiserfs_xattr_unregister_handlers();
-failed_reiserfs_xattr_register_handlers:
- reiserfs_proc_unregister_global ("version");
- reiserfs_proc_info_global_done ();
- destroy_inodecache ();
+ failed_reiserfs_xattr_register_handlers:
+ reiserfs_proc_unregister_global("version");
+ reiserfs_proc_info_global_done();
+ destroy_inodecache();
return ret;
}
-static void __exit
-exit_reiserfs_fs ( void )
+static void __exit exit_reiserfs_fs(void)
{
- reiserfs_xattr_unregister_handlers ();
- reiserfs_proc_unregister_global ("version");
- reiserfs_proc_info_global_done ();
- unregister_filesystem (& reiserfs_fs_type);
- destroy_inodecache ();
+ reiserfs_xattr_unregister_handlers();
+ reiserfs_proc_unregister_global("version");
+ reiserfs_proc_info_global_done();
+ unregister_filesystem(&reiserfs_fs_type);
+ destroy_inodecache();
}
struct file_system_type reiserfs_fs_type = {
- .owner = THIS_MODULE,
- .name = "reiserfs",
- .get_sb = get_super_block,
- .kill_sb = kill_block_super,
- .fs_flags = FS_REQUIRES_DEV,
+ .owner = THIS_MODULE,
+ .name = "reiserfs",
+ .get_sb = get_super_block,
+ .kill_sb = kill_block_super,
+ .fs_flags = FS_REQUIRES_DEV,
};
-MODULE_DESCRIPTION ("ReiserFS journaled filesystem");
-MODULE_AUTHOR ("Hans Reiser <reiser@namesys.com>");
-MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION("ReiserFS journaled filesystem");
+MODULE_AUTHOR("Hans Reiser <reiser@namesys.com>");
+MODULE_LICENSE("GPL");
-module_init (init_reiserfs_fs);
-module_exit (exit_reiserfs_fs);
+module_init(init_reiserfs_fs);
+module_exit(exit_reiserfs_fs);
diff --git a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
index 6191909d5165..c92e124f628e 100644
--- a/fs/reiserfs/tail_conversion.c
+++ b/fs/reiserfs/tail_conversion.c
@@ -11,156 +11,159 @@
/* access to tail : when one is going to read tail it must make sure, that is not running.
direct2indirect and indirect2direct can not run concurrently */
-
/* Converts direct items to an unformatted node. Panics if file has no
tail. -ENOSPC if no disk space for conversion */
/* path points to first direct item of the file regarless of how many of
them are there */
-int direct2indirect (struct reiserfs_transaction_handle *th, struct inode * inode,
- struct path * path, struct buffer_head * unbh,
- loff_t tail_offset)
+int direct2indirect(struct reiserfs_transaction_handle *th, struct inode *inode,
+ struct path *path, struct buffer_head *unbh,
+ loff_t tail_offset)
{
- struct super_block * sb = inode->i_sb;
- struct buffer_head *up_to_date_bh ;
- struct item_head * p_le_ih = PATH_PITEM_HEAD (path);
- unsigned long total_tail = 0 ;
- struct cpu_key end_key; /* Key to search for the last byte of the
- converted item. */
- struct item_head ind_ih; /* new indirect item to be inserted or
- key of unfm pointer to be pasted */
- int n_blk_size,
- n_retval; /* returned value for reiserfs_insert_item and clones */
- unp_t unfm_ptr; /* Handle on an unformatted node
- that will be inserted in the
- tree. */
-
- BUG_ON (!th->t_trans_id);
-
- REISERFS_SB(sb)->s_direct2indirect ++;
-
- n_blk_size = sb->s_blocksize;
-
- /* and key to search for append or insert pointer to the new
- unformatted node. */
- copy_item_head (&ind_ih, p_le_ih);
- set_le_ih_k_offset (&ind_ih, tail_offset);
- set_le_ih_k_type (&ind_ih, TYPE_INDIRECT);
-
- /* Set the key to search for the place for new unfm pointer */
- make_cpu_key (&end_key, inode, tail_offset, TYPE_INDIRECT, 4);
-
- // FIXME: we could avoid this
- if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND ) {
- reiserfs_warning (sb, "PAP-14030: direct2indirect: "
- "pasted or inserted byte exists in the tree %K. "
- "Use fsck to repair.", &end_key);
- pathrelse(path);
- return -EIO;
- }
-
- p_le_ih = PATH_PITEM_HEAD (path);
-
- unfm_ptr = cpu_to_le32 (unbh->b_blocknr);
-
- if ( is_statdata_le_ih (p_le_ih) ) {
- /* Insert new indirect item. */
- set_ih_free_space (&ind_ih, 0); /* delete at nearest future */
- put_ih_item_len( &ind_ih, UNFM_P_SIZE );
- PATH_LAST_POSITION (path)++;
- n_retval = reiserfs_insert_item (th, path, &end_key, &ind_ih, inode,
+ struct super_block *sb = inode->i_sb;
+ struct buffer_head *up_to_date_bh;
+ struct item_head *p_le_ih = PATH_PITEM_HEAD(path);
+ unsigned long total_tail = 0;
+ struct cpu_key end_key; /* Key to search for the last byte of the
+ converted item. */
+ struct item_head ind_ih; /* new indirect item to be inserted or
+ key of unfm pointer to be pasted */
+ int n_blk_size, n_retval; /* returned value for reiserfs_insert_item and clones */
+ unp_t unfm_ptr; /* Handle on an unformatted node
+ that will be inserted in the
+ tree. */
+
+ BUG_ON(!th->t_trans_id);
+
+ REISERFS_SB(sb)->s_direct2indirect++;
+
+ n_blk_size = sb->s_blocksize;
+
+ /* and key to search for append or insert pointer to the new
+ unformatted node. */
+ copy_item_head(&ind_ih, p_le_ih);
+ set_le_ih_k_offset(&ind_ih, tail_offset);
+ set_le_ih_k_type(&ind_ih, TYPE_INDIRECT);
+
+ /* Set the key to search for the place for new unfm pointer */
+ make_cpu_key(&end_key, inode, tail_offset, TYPE_INDIRECT, 4);
+
+ // FIXME: we could avoid this
+ if (search_for_position_by_key(sb, &end_key, path) == POSITION_FOUND) {
+ reiserfs_warning(sb, "PAP-14030: direct2indirect: "
+ "pasted or inserted byte exists in the tree %K. "
+ "Use fsck to repair.", &end_key);
+ pathrelse(path);
+ return -EIO;
+ }
+
+ p_le_ih = PATH_PITEM_HEAD(path);
+
+ unfm_ptr = cpu_to_le32(unbh->b_blocknr);
+
+ if (is_statdata_le_ih(p_le_ih)) {
+ /* Insert new indirect item. */
+ set_ih_free_space(&ind_ih, 0); /* delete at nearest future */
+ put_ih_item_len(&ind_ih, UNFM_P_SIZE);
+ PATH_LAST_POSITION(path)++;
+ n_retval =
+ reiserfs_insert_item(th, path, &end_key, &ind_ih, inode,
(char *)&unfm_ptr);
- } else {
- /* Paste into last indirect item of an object. */
- n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
- (char *)&unfm_ptr, UNFM_P_SIZE);
- }
- if ( n_retval ) {
- return n_retval;
- }
-
- // note: from here there are two keys which have matching first
- // three key components. They only differ by the fourth one.
-
-
- /* Set the key to search for the direct items of the file */
- make_cpu_key (&end_key, inode, max_reiserfs_offset (inode), TYPE_DIRECT, 4);
-
- /* Move bytes from the direct items to the new unformatted node
- and delete them. */
- while (1) {
- int tail_size;
-
- /* end_key.k_offset is set so, that we will always have found
- last item of the file */
- if ( search_for_position_by_key (sb, &end_key, path) == POSITION_FOUND )
- reiserfs_panic (sb, "PAP-14050: direct2indirect: "
- "direct item (%K) not found", &end_key);
- p_le_ih = PATH_PITEM_HEAD (path);
- RFALSE( !is_direct_le_ih (p_le_ih),
- "vs-14055: direct item expected(%K), found %h",
- &end_key, p_le_ih);
- tail_size = (le_ih_k_offset (p_le_ih) & (n_blk_size - 1))
- + ih_item_len(p_le_ih) - 1;
-
- /* we only send the unbh pointer if the buffer is not up to date.
- ** this avoids overwriting good data from writepage() with old data
- ** from the disk or buffer cache
- ** Special case: unbh->b_page will be NULL if we are coming through
- ** DIRECT_IO handler here.
- */
- if (!unbh->b_page || buffer_uptodate(unbh) || PageUptodate(unbh->b_page)) {
- up_to_date_bh = NULL ;
} else {
- up_to_date_bh = unbh ;
+ /* Paste into last indirect item of an object. */
+ n_retval = reiserfs_paste_into_item(th, path, &end_key, inode,
+ (char *)&unfm_ptr,
+ UNFM_P_SIZE);
}
- n_retval = reiserfs_delete_item (th, path, &end_key, inode,
- up_to_date_bh) ;
-
- total_tail += n_retval ;
- if (tail_size == n_retval)
- // done: file does not have direct items anymore
- break;
-
- }
- /* if we've copied bytes from disk into the page, we need to zero
- ** out the unused part of the block (it was not up to date before)
- */
- if (up_to_date_bh) {
- unsigned pgoff = (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
- char *kaddr=kmap_atomic(up_to_date_bh->b_page, KM_USER0);
- memset(kaddr + pgoff, 0, n_blk_size - total_tail) ;
- kunmap_atomic(kaddr, KM_USER0);
- }
-
- REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
-
- return 0;
-}
+ if (n_retval) {
+ return n_retval;
+ }
+ // note: from here there are two keys which have matching first
+ // three key components. They only differ by the fourth one.
+
+ /* Set the key to search for the direct items of the file */
+ make_cpu_key(&end_key, inode, max_reiserfs_offset(inode), TYPE_DIRECT,
+ 4);
+
+ /* Move bytes from the direct items to the new unformatted node
+ and delete them. */
+ while (1) {
+ int tail_size;
+
+ /* end_key.k_offset is set so, that we will always have found
+ last item of the file */
+ if (search_for_position_by_key(sb, &end_key, path) ==
+ POSITION_FOUND)
+ reiserfs_panic(sb,
+ "PAP-14050: direct2indirect: "
+ "direct item (%K) not found", &end_key);
+ p_le_ih = PATH_PITEM_HEAD(path);
+ RFALSE(!is_direct_le_ih(p_le_ih),
+ "vs-14055: direct item expected(%K), found %h",
+ &end_key, p_le_ih);
+ tail_size = (le_ih_k_offset(p_le_ih) & (n_blk_size - 1))
+ + ih_item_len(p_le_ih) - 1;
+
+ /* we only send the unbh pointer if the buffer is not up to date.
+ ** this avoids overwriting good data from writepage() with old data
+ ** from the disk or buffer cache
+ ** Special case: unbh->b_page will be NULL if we are coming through
+ ** DIRECT_IO handler here.
+ */
+ if (!unbh->b_page || buffer_uptodate(unbh)
+ || PageUptodate(unbh->b_page)) {
+ up_to_date_bh = NULL;
+ } else {
+ up_to_date_bh = unbh;
+ }
+ n_retval = reiserfs_delete_item(th, path, &end_key, inode,
+ up_to_date_bh);
+
+ total_tail += n_retval;
+ if (tail_size == n_retval)
+ // done: file does not have direct items anymore
+ break;
+ }
+ /* if we've copied bytes from disk into the page, we need to zero
+ ** out the unused part of the block (it was not up to date before)
+ */
+ if (up_to_date_bh) {
+ unsigned pgoff =
+ (tail_offset + total_tail - 1) & (PAGE_CACHE_SIZE - 1);
+ char *kaddr = kmap_atomic(up_to_date_bh->b_page, KM_USER0);
+ memset(kaddr + pgoff, 0, n_blk_size - total_tail);
+ kunmap_atomic(kaddr, KM_USER0);
+ }
+
+ REISERFS_I(inode)->i_first_direct_byte = U32_MAX;
+
+ return 0;
+}
/* stolen from fs/buffer.c */
-void reiserfs_unmap_buffer(struct buffer_head *bh) {
- lock_buffer(bh) ;
- if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
- BUG() ;
- }
- clear_buffer_dirty(bh) ;
- /* Remove the buffer from whatever list it belongs to. We are mostly
- interested in removing it from per-sb j_dirty_buffers list, to avoid
- BUG() on attempt to write not mapped buffer */
- if ( (!list_empty(&bh->b_assoc_buffers) || bh->b_private) && bh->b_page) {
- struct inode *inode = bh->b_page->mapping->host;
- struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb);
- spin_lock(&j->j_dirty_buffers_lock);
- list_del_init(&bh->b_assoc_buffers);
- reiserfs_free_jh(bh);
- spin_unlock(&j->j_dirty_buffers_lock);
- }
- clear_buffer_mapped(bh) ;
- clear_buffer_req(bh) ;
- clear_buffer_new(bh);
- bh->b_bdev = NULL;
- unlock_buffer(bh) ;
+void reiserfs_unmap_buffer(struct buffer_head *bh)
+{
+ lock_buffer(bh);
+ if (buffer_journaled(bh) || buffer_journal_dirty(bh)) {
+ BUG();
+ }
+ clear_buffer_dirty(bh);
+ /* Remove the buffer from whatever list it belongs to. We are mostly
+ interested in removing it from per-sb j_dirty_buffers list, to avoid
+ BUG() on attempt to write not mapped buffer */
+ if ((!list_empty(&bh->b_assoc_buffers) || bh->b_private) && bh->b_page) {
+ struct inode *inode = bh->b_page->mapping->host;
+ struct reiserfs_journal *j = SB_JOURNAL(inode->i_sb);
+ spin_lock(&j->j_dirty_buffers_lock);
+ list_del_init(&bh->b_assoc_buffers);
+ reiserfs_free_jh(bh);
+ spin_unlock(&j->j_dirty_buffers_lock);
+ }
+ clear_buffer_mapped(bh);
+ clear_buffer_req(bh);
+ clear_buffer_new(bh);
+ bh->b_bdev = NULL;
+ unlock_buffer(bh);
}
/* this first locks inode (neither reads nor sync are permitted),
@@ -169,108 +172,108 @@ void reiserfs_unmap_buffer(struct buffer_head *bh) {
what we expect from it (number of cut bytes). But when tail remains
in the unformatted node, we set mode to SKIP_BALANCING and unlock
inode */
-int indirect2direct (struct reiserfs_transaction_handle *th,
- struct inode * p_s_inode,
- struct page *page,
- struct path * p_s_path, /* path to the indirect item. */
- const struct cpu_key * p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
- loff_t n_new_file_size, /* New file size. */
- char * p_c_mode)
+int indirect2direct(struct reiserfs_transaction_handle *th, struct inode *p_s_inode, struct page *page, struct path *p_s_path, /* path to the indirect item. */
+ const struct cpu_key *p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
+ loff_t n_new_file_size, /* New file size. */
+ char *p_c_mode)
{
- struct super_block * p_s_sb = p_s_inode->i_sb;
- struct item_head s_ih;
- unsigned long n_block_size = p_s_sb->s_blocksize;
- char * tail;
- int tail_len, round_tail_len;
- loff_t pos, pos1; /* position of first byte of the tail */
- struct cpu_key key;
+ struct super_block *p_s_sb = p_s_inode->i_sb;
+ struct item_head s_ih;
+ unsigned long n_block_size = p_s_sb->s_blocksize;
+ char *tail;
+ int tail_len, round_tail_len;
+ loff_t pos, pos1; /* position of first byte of the tail */
+ struct cpu_key key;
- BUG_ON (!th->t_trans_id);
+ BUG_ON(!th->t_trans_id);
- REISERFS_SB(p_s_sb)->s_indirect2direct ++;
+ REISERFS_SB(p_s_sb)->s_indirect2direct++;
- *p_c_mode = M_SKIP_BALANCING;
+ *p_c_mode = M_SKIP_BALANCING;
- /* store item head path points to. */
- copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path));
-
- tail_len = (n_new_file_size & (n_block_size - 1));
- if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2)
- round_tail_len = ROUND_UP (tail_len);
- else
- round_tail_len = tail_len;
-
- pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
- pos1 = pos;
-
- // we are protected by i_sem. The tail can not disapper, not
- // append can be done either
- // we are in truncate or packing tail in file_release
-
- tail = (char *)kmap(page) ; /* this can schedule */
-
- if (path_changed (&s_ih, p_s_path)) {
- /* re-search indirect item */
- if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND )
- reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: "
- "item to be converted %K does not exist", p_s_item_key);
+ /* store item head path points to. */
copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
+
+ tail_len = (n_new_file_size & (n_block_size - 1));
+ if (get_inode_sd_version(p_s_inode) == STAT_DATA_V2)
+ round_tail_len = ROUND_UP(tail_len);
+ else
+ round_tail_len = tail_len;
+
+ pos =
+ le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE -
+ 1) * p_s_sb->s_blocksize;
+ pos1 = pos;
+
+ // we are protected by i_sem. The tail can not disapper, not
+ // append can be done either
+ // we are in truncate or packing tail in file_release
+
+ tail = (char *)kmap(page); /* this can schedule */
+
+ if (path_changed(&s_ih, p_s_path)) {
+ /* re-search indirect item */
+ if (search_for_position_by_key(p_s_sb, p_s_item_key, p_s_path)
+ == POSITION_NOT_FOUND)
+ reiserfs_panic(p_s_sb,
+ "PAP-5520: indirect2direct: "
+ "item to be converted %K does not exist",
+ p_s_item_key);
+ copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
#ifdef CONFIG_REISERFS_CHECK
- pos = le_ih_k_offset (&s_ih) - 1 +
- (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
- if (pos != pos1)
- reiserfs_panic (p_s_sb, "vs-5530: indirect2direct: "
- "tail position changed while we were reading it");
+ pos = le_ih_k_offset(&s_ih) - 1 +
+ (ih_item_len(&s_ih) / UNFM_P_SIZE -
+ 1) * p_s_sb->s_blocksize;
+ if (pos != pos1)
+ reiserfs_panic(p_s_sb, "vs-5530: indirect2direct: "
+ "tail position changed while we were reading it");
#endif
- }
-
-
- /* Set direct item header to insert. */
- make_le_item_head (&s_ih, NULL, get_inode_item_key_version (p_s_inode), pos1 + 1,
- TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/);
-
- /* we want a pointer to the first byte of the tail in the page.
- ** the page was locked and this part of the page was up to date when
- ** indirect2direct was called, so we know the bytes are still valid
- */
- tail = tail + (pos & (PAGE_CACHE_SIZE - 1)) ;
-
- PATH_LAST_POSITION(p_s_path)++;
-
- key = *p_s_item_key;
- set_cpu_key_k_type (&key, TYPE_DIRECT);
- key.key_length = 4;
- /* Insert tail as new direct item in the tree */
- if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode,
- tail ? tail : NULL) < 0 ) {
- /* No disk memory. So we can not convert last unformatted node
- to the direct item. In this case we used to adjust
- indirect items's ih_free_space. Now ih_free_space is not
- used, it would be ideal to write zeros to corresponding
- unformatted node. For now i_size is considered as guard for
- going out of file size */
- kunmap(page) ;
- return n_block_size - round_tail_len;
- }
- kunmap(page) ;
-
- /* make sure to get the i_blocks changes from reiserfs_insert_item */
- reiserfs_update_sd(th, p_s_inode);
+ }
- // note: we have now the same as in above direct2indirect
- // conversion: there are two keys which have matching first three
- // key components. They only differ by the fouhth one.
+ /* Set direct item header to insert. */
+ make_le_item_head(&s_ih, NULL, get_inode_item_key_version(p_s_inode),
+ pos1 + 1, TYPE_DIRECT, round_tail_len,
+ 0xffff /*ih_free_space */ );
+
+ /* we want a pointer to the first byte of the tail in the page.
+ ** the page was locked and this part of the page was up to date when
+ ** indirect2direct was called, so we know the bytes are still valid
+ */
+ tail = tail + (pos & (PAGE_CACHE_SIZE - 1));
+
+ PATH_LAST_POSITION(p_s_path)++;
+
+ key = *p_s_item_key;
+ set_cpu_key_k_type(&key, TYPE_DIRECT);
+ key.key_length = 4;
+ /* Insert tail as new direct item in the tree */
+ if (reiserfs_insert_item(th, p_s_path, &key, &s_ih, p_s_inode,
+ tail ? tail : NULL) < 0) {
+ /* No disk memory. So we can not convert last unformatted node
+ to the direct item. In this case we used to adjust
+ indirect items's ih_free_space. Now ih_free_space is not
+ used, it would be ideal to write zeros to corresponding
+ unformatted node. For now i_size is considered as guard for
+ going out of file size */
+ kunmap(page);
+ return n_block_size - round_tail_len;
+ }
+ kunmap(page);
- /* We have inserted new direct item and must remove last
- unformatted node. */
- *p_c_mode = M_CUT;
+ /* make sure to get the i_blocks changes from reiserfs_insert_item */
+ reiserfs_update_sd(th, p_s_inode);
- /* we store position of first direct item in the in-core inode */
- //mark_file_with_tail (p_s_inode, pos1 + 1);
- REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
-
- return n_block_size - round_tail_len;
-}
+ // note: we have now the same as in above direct2indirect
+ // conversion: there are two keys which have matching first three
+ // key components. They only differ by the fouhth one.
+ /* We have inserted new direct item and must remove last
+ unformatted node. */
+ *p_c_mode = M_CUT;
+ /* we store position of first direct item in the in-core inode */
+ //mark_file_with_tail (p_s_inode, pos1 + 1);
+ REISERFS_I(p_s_inode)->i_first_direct_byte = pos1 + 1;
+ return n_block_size - round_tail_len;
+}
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 45582fe8b466..e386d3db3051 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -51,67 +51,68 @@
#define PRIVROOT_NAME ".reiserfs_priv"
#define XAROOT_NAME "xattrs"
-static struct reiserfs_xattr_handler *find_xattr_handler_prefix (const char *prefix);
+static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
+ *prefix);
-static struct dentry *
-create_xa_root (struct super_block *sb)
+static struct dentry *create_xa_root(struct super_block *sb)
{
- struct dentry *privroot = dget (REISERFS_SB(sb)->priv_root);
- struct dentry *xaroot;
-
- /* This needs to be created at mount-time */
- if (!privroot)
- return ERR_PTR(-EOPNOTSUPP);
-
- xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));
- if (IS_ERR (xaroot)) {
- goto out;
- } else if (!xaroot->d_inode) {
- int err;
- down (&privroot->d_inode->i_sem);
- err = privroot->d_inode->i_op->mkdir (privroot->d_inode, xaroot, 0700);
- up (&privroot->d_inode->i_sem);
-
- if (err) {
- dput (xaroot);
- dput (privroot);
- return ERR_PTR (err);
- }
- REISERFS_SB(sb)->xattr_root = dget (xaroot);
- }
-
-out:
- dput (privroot);
- return xaroot;
+ struct dentry *privroot = dget(REISERFS_SB(sb)->priv_root);
+ struct dentry *xaroot;
+
+ /* This needs to be created at mount-time */
+ if (!privroot)
+ return ERR_PTR(-EOPNOTSUPP);
+
+ xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
+ if (IS_ERR(xaroot)) {
+ goto out;
+ } else if (!xaroot->d_inode) {
+ int err;
+ down(&privroot->d_inode->i_sem);
+ err =
+ privroot->d_inode->i_op->mkdir(privroot->d_inode, xaroot,
+ 0700);
+ up(&privroot->d_inode->i_sem);
+
+ if (err) {
+ dput(xaroot);
+ dput(privroot);
+ return ERR_PTR(err);
+ }
+ REISERFS_SB(sb)->xattr_root = dget(xaroot);
+ }
+
+ out:
+ dput(privroot);
+ return xaroot;
}
/* This will return a dentry, or error, refering to the xa root directory.
* If the xa root doesn't exist yet, the dentry will be returned without
* an associated inode. This dentry can be used with ->mkdir to create
* the xa directory. */
-static struct dentry *
-__get_xa_root (struct super_block *s)
+static struct dentry *__get_xa_root(struct super_block *s)
{
- struct dentry *privroot = dget (REISERFS_SB(s)->priv_root);
- struct dentry *xaroot = NULL;
-
- if (IS_ERR (privroot) || !privroot)
- return privroot;
-
- xaroot = lookup_one_len (XAROOT_NAME, privroot, strlen (XAROOT_NAME));
- if (IS_ERR (xaroot)) {
- goto out;
- } else if (!xaroot->d_inode) {
- dput (xaroot);
- xaroot = NULL;
- goto out;
- }
-
- REISERFS_SB(s)->xattr_root = dget (xaroot);
-
-out:
- dput (privroot);
- return xaroot;
+ struct dentry *privroot = dget(REISERFS_SB(s)->priv_root);
+ struct dentry *xaroot = NULL;
+
+ if (IS_ERR(privroot) || !privroot)
+ return privroot;
+
+ xaroot = lookup_one_len(XAROOT_NAME, privroot, strlen(XAROOT_NAME));
+ if (IS_ERR(xaroot)) {
+ goto out;
+ } else if (!xaroot->d_inode) {
+ dput(xaroot);
+ xaroot = NULL;
+ goto out;
+ }
+
+ REISERFS_SB(s)->xattr_root = dget(xaroot);
+
+ out:
+ dput(privroot);
+ return xaroot;
}
/* Returns the dentry (or NULL) referring to the root of the extended
@@ -119,147 +120,145 @@ out:
* Otherwise, we attempt to retreive it from disk. It may also return
* a pointer-encoded error.
*/
-static inline struct dentry *
-get_xa_root (struct super_block *s)
+static inline struct dentry *get_xa_root(struct super_block *s)
{
- struct dentry *dentry = dget (REISERFS_SB(s)->xattr_root);
+ struct dentry *dentry = dget(REISERFS_SB(s)->xattr_root);
- if (!dentry)
- dentry = __get_xa_root (s);
+ if (!dentry)
+ dentry = __get_xa_root(s);
- return dentry;
+ return dentry;
}
/* Opens the directory corresponding to the inode's extended attribute store.
* If flags allow, the tree to the directory may be created. If creation is
* prohibited, -ENODATA is returned. */
-static struct dentry *
-open_xa_dir (const struct inode *inode, int flags)
+static struct dentry *open_xa_dir(const struct inode *inode, int flags)
{
- struct dentry *xaroot, *xadir;
- char namebuf[17];
-
- xaroot = get_xa_root (inode->i_sb);
- if (IS_ERR (xaroot)) {
- return xaroot;
- } else if (!xaroot) {
- if (flags == 0 || flags & XATTR_CREATE) {
- xaroot = create_xa_root (inode->i_sb);
- if (IS_ERR (xaroot))
- return xaroot;
- }
- if (!xaroot)
- return ERR_PTR (-ENODATA);
- }
-
- /* ok, we have xaroot open */
-
- snprintf (namebuf, sizeof (namebuf), "%X.%X",
- le32_to_cpu (INODE_PKEY (inode)->k_objectid),
- inode->i_generation);
- xadir = lookup_one_len (namebuf, xaroot, strlen (namebuf));
- if (IS_ERR (xadir)) {
- dput (xaroot);
- return xadir;
- }
-
- if (!xadir->d_inode) {
- int err;
- if (flags == 0 || flags & XATTR_CREATE) {
- /* Although there is nothing else trying to create this directory,
- * another directory with the same hash may be created, so we need
- * to protect against that */
- err = xaroot->d_inode->i_op->mkdir (xaroot->d_inode, xadir, 0700);
- if (err) {
- dput (xaroot);
- dput (xadir);
- return ERR_PTR (err);
- }
- }
- if (!xadir->d_inode) {
- dput (xaroot);
- dput (xadir);
- return ERR_PTR (-ENODATA);
- }
- }
-
- dput (xaroot);
- return xadir;
+ struct dentry *xaroot, *xadir;
+ char namebuf[17];
+
+ xaroot = get_xa_root(inode->i_sb);
+ if (IS_ERR(xaroot)) {
+ return xaroot;
+ } else if (!xaroot) {
+ if (flags == 0 || flags & XATTR_CREATE) {
+ xaroot = create_xa_root(inode->i_sb);
+ if (IS_ERR(xaroot))
+ return xaroot;
+ }
+ if (!xaroot)
+ return ERR_PTR(-ENODATA);
+ }
+
+ /* ok, we have xaroot open */
+
+ snprintf(namebuf, sizeof(namebuf), "%X.%X",
+ le32_to_cpu(INODE_PKEY(inode)->k_objectid),
+ inode->i_generation);
+ xadir = lookup_one_len(namebuf, xaroot, strlen(namebuf));
+ if (IS_ERR(xadir)) {
+ dput(xaroot);
+ return xadir;
+ }
+
+ if (!xadir->d_inode) {
+ int err;
+ if (flags == 0 || flags & XATTR_CREATE) {
+ /* Although there is nothing else trying to create this directory,
+ * another directory with the same hash may be created, so we need
+ * to protect against that */
+ err =
+ xaroot->d_inode->i_op->mkdir(xaroot->d_inode, xadir,
+ 0700);
+ if (err) {
+ dput(xaroot);
+ dput(xadir);
+ return ERR_PTR(err);
+ }
+ }
+ if (!xadir->d_inode) {
+ dput(xaroot);
+ dput(xadir);
+ return ERR_PTR(-ENODATA);
+ }
+ }
+
+ dput(xaroot);
+ return xadir;
}
/* Returns a dentry corresponding to a specific extended attribute file
* for the inode. If flags allow, the file is created. Otherwise, a
* valid or negative dentry, or an error is returned. */
-static struct dentry *
-get_xa_file_dentry (const struct inode *inode, const char *name, int flags)
+static struct dentry *get_xa_file_dentry(const struct inode *inode,
+ const char *name, int flags)
{
- struct dentry *xadir, *xafile;
- int err = 0;
-
- xadir = open_xa_dir (inode, flags);
- if (IS_ERR (xadir)) {
- return ERR_PTR (PTR_ERR (xadir));
- } else if (xadir && !xadir->d_inode) {
- dput (xadir);
- return ERR_PTR (-ENODATA);
- }
-
- xafile = lookup_one_len (name, xadir, strlen (name));
- if (IS_ERR (xafile)) {
- dput (xadir);
- return ERR_PTR (PTR_ERR (xafile));
- }
-
- if (xafile->d_inode) { /* file exists */
- if (flags & XATTR_CREATE) {
- err = -EEXIST;
- dput (xafile);
- goto out;
- }
- } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
- goto out;
- } else {
- /* inode->i_sem is down, so nothing else can try to create
- * the same xattr */
- err = xadir->d_inode->i_op->create (xadir->d_inode, xafile,
- 0700|S_IFREG, NULL);
-
- if (err) {
- dput (xafile);
- goto out;
- }
- }
-
-out:
- dput (xadir);
- if (err)
- xafile = ERR_PTR (err);
- return xafile;
-}
+ struct dentry *xadir, *xafile;
+ int err = 0;
+
+ xadir = open_xa_dir(inode, flags);
+ if (IS_ERR(xadir)) {
+ return ERR_PTR(PTR_ERR(xadir));
+ } else if (xadir && !xadir->d_inode) {
+ dput(xadir);
+ return ERR_PTR(-ENODATA);
+ }
+
+ xafile = lookup_one_len(name, xadir, strlen(name));
+ if (IS_ERR(xafile)) {
+ dput(xadir);
+ return ERR_PTR(PTR_ERR(xafile));
+ }
+
+ if (xafile->d_inode) { /* file exists */
+ if (flags & XATTR_CREATE) {
+ err = -EEXIST;
+ dput(xafile);
+ goto out;
+ }
+ } else if (flags & XATTR_REPLACE || flags & FL_READONLY) {
+ goto out;
+ } else {
+ /* inode->i_sem is down, so nothing else can try to create
+ * the same xattr */
+ err = xadir->d_inode->i_op->create(xadir->d_inode, xafile,
+ 0700 | S_IFREG, NULL);
+
+ if (err) {
+ dput(xafile);
+ goto out;
+ }
+ }
+ out:
+ dput(xadir);
+ if (err)
+ xafile = ERR_PTR(err);
+ return xafile;
+}
/* Opens a file pointer to the attribute associated with inode */
-static struct file *
-open_xa_file (const struct inode *inode, const char *name, int flags)
+static struct file *open_xa_file(const struct inode *inode, const char *name,
+ int flags)
{
- struct dentry *xafile;
- struct file *fp;
-
- xafile = get_xa_file_dentry (inode, name, flags);
- if (IS_ERR (xafile))
- return ERR_PTR (PTR_ERR (xafile));
- else if (!xafile->d_inode) {
- dput (xafile);
- return ERR_PTR (-ENODATA);
- }
+ struct dentry *xafile;
+ struct file *fp;
+
+ xafile = get_xa_file_dentry(inode, name, flags);
+ if (IS_ERR(xafile))
+ return ERR_PTR(PTR_ERR(xafile));
+ else if (!xafile->d_inode) {
+ dput(xafile);
+ return ERR_PTR(-ENODATA);
+ }
- fp = dentry_open (xafile, NULL, O_RDWR);
- /* dentry_open dputs the dentry if it fails */
+ fp = dentry_open(xafile, NULL, O_RDWR);
+ /* dentry_open dputs the dentry if it fails */
- return fp;
+ return fp;
}
-
/*
* this is very similar to fs/reiserfs/dir.c:reiserfs_readdir, but
* we need to drop the path before calling the filldir struct. That
@@ -273,139 +272,146 @@ open_xa_file (const struct inode *inode, const char *name, int flags)
* we're called with i_sem held, so there are no worries about the directory
* changing underneath us.
*/
-static int __xattr_readdir(struct file * filp, void * dirent, filldir_t filldir)
+static int __xattr_readdir(struct file *filp, void *dirent, filldir_t filldir)
{
- struct inode *inode = filp->f_dentry->d_inode;
- struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
- INITIALIZE_PATH (path_to_entry);
- struct buffer_head * bh;
- int entry_num;
- struct item_head * ih, tmp_ih;
- int search_res;
- char * local_buf;
- loff_t next_pos;
- char small_buf[32] ; /* avoid kmalloc if we can */
- struct reiserfs_de_head *deh;
- int d_reclen;
- char * d_name;
- off_t d_off;
- ino_t d_ino;
- struct reiserfs_dir_entry de;
-
-
- /* form key for search the next directory entry using f_pos field of
- file structure */
- next_pos = max_reiserfs_offset(inode);
-
- while (1) {
-research:
- if (next_pos <= DOT_DOT_OFFSET)
- break;
- make_cpu_key (&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);
-
- search_res = search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, &de);
- if (search_res == IO_ERROR) {
- // FIXME: we could just skip part of directory which could
- // not be read
- pathrelse(&path_to_entry);
- return -EIO;
- }
-
- if (search_res == NAME_NOT_FOUND)
- de.de_entry_num--;
+ struct inode *inode = filp->f_dentry->d_inode;
+ struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */
+ INITIALIZE_PATH(path_to_entry);
+ struct buffer_head *bh;
+ int entry_num;
+ struct item_head *ih, tmp_ih;
+ int search_res;
+ char *local_buf;
+ loff_t next_pos;
+ char small_buf[32]; /* avoid kmalloc if we can */
+ struct reiserfs_de_head *deh;
+ int d_reclen;
+ char *d_name;
+ off_t d_off;
+ ino_t d_ino;
+ struct reiserfs_dir_entry de;
+
+ /* form key for search the next directory entry using f_pos field of
+ file structure */
+ next_pos = max_reiserfs_offset(inode);
+
+ while (1) {
+ research:
+ if (next_pos <= DOT_DOT_OFFSET)
+ break;
+ make_cpu_key(&pos_key, inode, next_pos, TYPE_DIRENTRY, 3);
+
+ search_res =
+ search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry,
+ &de);
+ if (search_res == IO_ERROR) {
+ // FIXME: we could just skip part of directory which could
+ // not be read
+ pathrelse(&path_to_entry);
+ return -EIO;
+ }
- set_de_name_and_namelen(&de);
- entry_num = de.de_entry_num;
- deh = &(de.de_deh[entry_num]);
+ if (search_res == NAME_NOT_FOUND)
+ de.de_entry_num--;
- bh = de.de_bh;
- ih = de.de_ih;
+ set_de_name_and_namelen(&de);
+ entry_num = de.de_entry_num;
+ deh = &(de.de_deh[entry_num]);
- if (!is_direntry_le_ih(ih)) {
- reiserfs_warning(inode->i_sb, "not direntry %h", ih);
- break;
- }
- copy_item_head(&tmp_ih, ih);
+ bh = de.de_bh;
+ ih = de.de_ih;
- /* we must have found item, that is item of this directory, */
- RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key),
- "vs-9000: found item %h does not match to dir we readdir %K",
- ih, &pos_key);
+ if (!is_direntry_le_ih(ih)) {
+ reiserfs_warning(inode->i_sb, "not direntry %h", ih);
+ break;
+ }
+ copy_item_head(&tmp_ih, ih);
- if (deh_offset(deh) <= DOT_DOT_OFFSET) {
- break;
- }
+ /* we must have found item, that is item of this directory, */
+ RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key),
+ "vs-9000: found item %h does not match to dir we readdir %K",
+ ih, &pos_key);
- /* look for the previous entry in the directory */
- next_pos = deh_offset (deh) - 1;
+ if (deh_offset(deh) <= DOT_DOT_OFFSET) {
+ break;
+ }
- if (!de_visible (deh))
- /* it is hidden entry */
- continue;
+ /* look for the previous entry in the directory */
+ next_pos = deh_offset(deh) - 1;
- d_reclen = entry_length(bh, ih, entry_num);
- d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh);
- d_off = deh_offset (deh);
- d_ino = deh_objectid (deh);
+ if (!de_visible(deh))
+ /* it is hidden entry */
+ continue;
- if (!d_name[d_reclen - 1])
- d_reclen = strlen (d_name);
+ d_reclen = entry_length(bh, ih, entry_num);
+ d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh);
+ d_off = deh_offset(deh);
+ d_ino = deh_objectid(deh);
- if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)){
- /* too big to send back to VFS */
- continue ;
- }
+ if (!d_name[d_reclen - 1])
+ d_reclen = strlen(d_name);
- /* Ignore the .reiserfs_priv entry */
- if (reiserfs_xattrs (inode->i_sb) &&
- !old_format_only(inode->i_sb) &&
- deh_objectid (deh) == le32_to_cpu (INODE_PKEY(REISERFS_SB(inode->i_sb)->priv_root->d_inode)->k_objectid))
- continue;
+ if (d_reclen > REISERFS_MAX_NAME(inode->i_sb->s_blocksize)) {
+ /* too big to send back to VFS */
+ continue;
+ }
- if (d_reclen <= 32) {
- local_buf = small_buf ;
- } else {
- local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ;
- if (!local_buf) {
- pathrelse (&path_to_entry);
- return -ENOMEM ;
- }
- if (item_moved (&tmp_ih, &path_to_entry)) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
-
- /* sigh, must retry. Do this same offset again */
- next_pos = d_off;
- goto research;
- }
- }
+ /* Ignore the .reiserfs_priv entry */
+ if (reiserfs_xattrs(inode->i_sb) &&
+ !old_format_only(inode->i_sb) &&
+ deh_objectid(deh) ==
+ le32_to_cpu(INODE_PKEY
+ (REISERFS_SB(inode->i_sb)->priv_root->d_inode)->
+ k_objectid))
+ continue;
+
+ if (d_reclen <= 32) {
+ local_buf = small_buf;
+ } else {
+ local_buf =
+ reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb);
+ if (!local_buf) {
+ pathrelse(&path_to_entry);
+ return -ENOMEM;
+ }
+ if (item_moved(&tmp_ih, &path_to_entry)) {
+ reiserfs_kfree(local_buf, d_reclen,
+ inode->i_sb);
+
+ /* sigh, must retry. Do this same offset again */
+ next_pos = d_off;
+ goto research;
+ }
+ }
- // Note, that we copy name to user space via temporary
- // buffer (local_buf) because filldir will block if
- // user space buffer is swapped out. At that time
- // entry can move to somewhere else
- memcpy (local_buf, d_name, d_reclen);
+ // Note, that we copy name to user space via temporary
+ // buffer (local_buf) because filldir will block if
+ // user space buffer is swapped out. At that time
+ // entry can move to somewhere else
+ memcpy(local_buf, d_name, d_reclen);
- /* the filldir function might need to start transactions,
- * or do who knows what. Release the path now that we've
- * copied all the important stuff out of the deh
- */
- pathrelse (&path_to_entry);
-
- if (filldir (dirent, local_buf, d_reclen, d_off, d_ino,
- DT_UNKNOWN) < 0) {
- if (local_buf != small_buf) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
- }
- goto end;
- }
- if (local_buf != small_buf) {
- reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ;
- }
- } /* while */
+ /* the filldir function might need to start transactions,
+ * or do who knows what. Release the path now that we've
+ * copied all the important stuff out of the deh
+ */
+ pathrelse(&path_to_entry);
+
+ if (filldir(dirent, local_buf, d_reclen, d_off, d_ino,
+ DT_UNKNOWN) < 0) {
+ if (local_buf != small_buf) {
+ reiserfs_kfree(local_buf, d_reclen,
+ inode->i_sb);
+ }
+ goto end;
+ }
+ if (local_buf != small_buf) {
+ reiserfs_kfree(local_buf, d_reclen, inode->i_sb);
+ }
+ } /* while */
-end:
- pathrelse (&path_to_entry);
- return 0;
+ end:
+ pathrelse(&path_to_entry);
+ return 0;
}
/*
@@ -417,63 +423,59 @@ end:
static
int xattr_readdir(struct file *file, filldir_t filler, void *buf)
{
- struct inode *inode = file->f_dentry->d_inode;
- int res = -ENOTDIR;
- if (!file->f_op || !file->f_op->readdir)
- goto out;
- down(&inode->i_sem);
+ struct inode *inode = file->f_dentry->d_inode;
+ int res = -ENOTDIR;
+ if (!file->f_op || !file->f_op->readdir)
+ goto out;
+ down(&inode->i_sem);
// down(&inode->i_zombie);
- res = -ENOENT;
- if (!IS_DEADDIR(inode)) {
- lock_kernel();
- res = __xattr_readdir(file, buf, filler);
- unlock_kernel();
- }
+ res = -ENOENT;
+ if (!IS_DEADDIR(inode)) {
+ lock_kernel();
+ res = __xattr_readdir(file, buf, filler);
+ unlock_kernel();
+ }
// up(&inode->i_zombie);
- up(&inode->i_sem);
-out:
- return res;
+ up(&inode->i_sem);
+ out:
+ return res;
}
-
/* Internal operations on file data */
-static inline void
-reiserfs_put_page(struct page *page)
+static inline void reiserfs_put_page(struct page *page)
{
- kunmap(page);
- page_cache_release(page);
+ kunmap(page);
+ page_cache_release(page);
}
-static struct page *
-reiserfs_get_page(struct inode *dir, unsigned long n)
+static struct page *reiserfs_get_page(struct inode *dir, unsigned long n)
{
- struct address_space *mapping = dir->i_mapping;
- struct page *page;
- /* We can deadlock if we try to free dentries,
- and an unlink/rmdir has just occured - GFP_NOFS avoids this */
- mapping->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS;
- page = read_cache_page (mapping, n,
- (filler_t*)mapping->a_ops->readpage, NULL);
- if (!IS_ERR(page)) {
- wait_on_page_locked(page);
- kmap(page);
- if (!PageUptodate(page))
- goto fail;
-
- if (PageError(page))
- goto fail;
- }
- return page;
-
-fail:
- reiserfs_put_page(page);
- return ERR_PTR(-EIO);
+ struct address_space *mapping = dir->i_mapping;
+ struct page *page;
+ /* We can deadlock if we try to free dentries,
+ and an unlink/rmdir has just occured - GFP_NOFS avoids this */
+ mapping->flags = (mapping->flags & ~__GFP_BITS_MASK) | GFP_NOFS;
+ page = read_cache_page(mapping, n,
+ (filler_t *) mapping->a_ops->readpage, NULL);
+ if (!IS_ERR(page)) {
+ wait_on_page_locked(page);
+ kmap(page);
+ if (!PageUptodate(page))
+ goto fail;
+
+ if (PageError(page))
+ goto fail;
+ }
+ return page;
+
+ fail:
+ reiserfs_put_page(page);
+ return ERR_PTR(-EIO);
}
-static inline __u32
-xattr_hash (const char *msg, int len)
+static inline __u32 xattr_hash(const char *msg, int len)
{
- return csum_partial (msg, len, 0);
+ return csum_partial(msg, len, 0);
}
/* Generic extended attribute operations that can be used by xa plugins */
@@ -482,294 +484,300 @@ xattr_hash (const char *msg, int len)
* inode->i_sem: down
*/
int
-reiserfs_xattr_set (struct inode *inode, const char *name, const void *buffer,
- size_t buffer_size, int flags)
+reiserfs_xattr_set(struct inode *inode, const char *name, const void *buffer,
+ size_t buffer_size, int flags)
{
- int err = 0;
- struct file *fp;
- struct page *page;
- char *data;
- struct address_space *mapping;
- size_t file_pos = 0;
- size_t buffer_pos = 0;
- struct inode *xinode;
- struct iattr newattrs;
- __u32 xahash = 0;
-
- if (IS_RDONLY (inode))
- return -EROFS;
-
- if (IS_IMMUTABLE (inode) || IS_APPEND (inode))
- return -EPERM;
-
- if (get_inode_sd_version (inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
-
- /* Empty xattrs are ok, they're just empty files, no hash */
- if (buffer && buffer_size)
- xahash = xattr_hash (buffer, buffer_size);
-
-open_file:
- fp = open_xa_file (inode, name, flags);
- if (IS_ERR (fp)) {
- err = PTR_ERR (fp);
- goto out;
- }
-
- xinode = fp->f_dentry->d_inode;
- REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
-
- /* we need to copy it off.. */
- if (xinode->i_nlink > 1) {
- fput(fp);
- err = reiserfs_xattr_del (inode, name);
- if (err < 0)
- goto out;
- /* We just killed the old one, we're not replacing anymore */
- if (flags & XATTR_REPLACE)
- flags &= ~XATTR_REPLACE;
- goto open_file;
- }
-
- /* Resize it so we're ok to write there */
- newattrs.ia_size = buffer_size;
- newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
- down (&xinode->i_sem);
- err = notify_change(fp->f_dentry, &newattrs);
- if (err)
- goto out_filp;
-
- mapping = xinode->i_mapping;
- while (buffer_pos < buffer_size || buffer_pos == 0) {
- size_t chunk;
- size_t skip = 0;
- size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));
- if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)
- chunk = PAGE_CACHE_SIZE;
- else
- chunk = buffer_size - buffer_pos;
-
- page = reiserfs_get_page (xinode, file_pos >> PAGE_CACHE_SHIFT);
- if (IS_ERR (page)) {
- err = PTR_ERR (page);
- goto out_filp;
- }
-
- lock_page (page);
- data = page_address (page);
-
- if (file_pos == 0) {
- struct reiserfs_xattr_header *rxh;
- skip = file_pos = sizeof (struct reiserfs_xattr_header);
- if (chunk + skip > PAGE_CACHE_SIZE)
- chunk = PAGE_CACHE_SIZE - skip;
- rxh = (struct reiserfs_xattr_header *)data;
- rxh->h_magic = cpu_to_le32 (REISERFS_XATTR_MAGIC);
- rxh->h_hash = cpu_to_le32 (xahash);
- }
-
- err = mapping->a_ops->prepare_write (fp, page, page_offset,
- page_offset + chunk + skip);
- if (!err) {
- if (buffer)
- memcpy (data + skip, buffer + buffer_pos, chunk);
- err = mapping->a_ops->commit_write (fp, page, page_offset,
- page_offset + chunk + skip);
+ int err = 0;
+ struct file *fp;
+ struct page *page;
+ char *data;
+ struct address_space *mapping;
+ size_t file_pos = 0;
+ size_t buffer_pos = 0;
+ struct inode *xinode;
+ struct iattr newattrs;
+ __u32 xahash = 0;
+
+ if (IS_RDONLY(inode))
+ return -EROFS;
+
+ if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+ return -EPERM;
+
+ if (get_inode_sd_version(inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
+
+ /* Empty xattrs are ok, they're just empty files, no hash */
+ if (buffer && buffer_size)
+ xahash = xattr_hash(buffer, buffer_size);
+
+ open_file:
+ fp = open_xa_file(inode, name, flags);
+ if (IS_ERR(fp)) {
+ err = PTR_ERR(fp);
+ goto out;
+ }
+
+ xinode = fp->f_dentry->d_inode;
+ REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+
+ /* we need to copy it off.. */
+ if (xinode->i_nlink > 1) {
+ fput(fp);
+ err = reiserfs_xattr_del(inode, name);
+ if (err < 0)
+ goto out;
+ /* We just killed the old one, we're not replacing anymore */
+ if (flags & XATTR_REPLACE)
+ flags &= ~XATTR_REPLACE;
+ goto open_file;
+ }
+
+ /* Resize it so we're ok to write there */
+ newattrs.ia_size = buffer_size;
+ newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
+ down(&xinode->i_sem);
+ err = notify_change(fp->f_dentry, &newattrs);
+ if (err)
+ goto out_filp;
+
+ mapping = xinode->i_mapping;
+ while (buffer_pos < buffer_size || buffer_pos == 0) {
+ size_t chunk;
+ size_t skip = 0;
+ size_t page_offset = (file_pos & (PAGE_CACHE_SIZE - 1));
+ if (buffer_size - buffer_pos > PAGE_CACHE_SIZE)
+ chunk = PAGE_CACHE_SIZE;
+ else
+ chunk = buffer_size - buffer_pos;
+
+ page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto out_filp;
+ }
+
+ lock_page(page);
+ data = page_address(page);
+
+ if (file_pos == 0) {
+ struct reiserfs_xattr_header *rxh;
+ skip = file_pos = sizeof(struct reiserfs_xattr_header);
+ if (chunk + skip > PAGE_CACHE_SIZE)
+ chunk = PAGE_CACHE_SIZE - skip;
+ rxh = (struct reiserfs_xattr_header *)data;
+ rxh->h_magic = cpu_to_le32(REISERFS_XATTR_MAGIC);
+ rxh->h_hash = cpu_to_le32(xahash);
+ }
+
+ err = mapping->a_ops->prepare_write(fp, page, page_offset,
+ page_offset + chunk + skip);
+ if (!err) {
+ if (buffer)
+ memcpy(data + skip, buffer + buffer_pos, chunk);
+ err =
+ mapping->a_ops->commit_write(fp, page, page_offset,
+ page_offset + chunk +
+ skip);
+ }
+ unlock_page(page);
+ reiserfs_put_page(page);
+ buffer_pos += chunk;
+ file_pos += chunk;
+ skip = 0;
+ if (err || buffer_size == 0 || !buffer)
+ break;
+ }
+
+ /* We can't mark the inode dirty if it's not hashed. This is the case
+ * when we're inheriting the default ACL. If we dirty it, the inode
+ * gets marked dirty, but won't (ever) make it onto the dirty list until
+ * it's synced explicitly to clear I_DIRTY. This is bad. */
+ if (!hlist_unhashed(&inode->i_hash)) {
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
}
- unlock_page (page);
- reiserfs_put_page (page);
- buffer_pos += chunk;
- file_pos += chunk;
- skip = 0;
- if (err || buffer_size == 0 || !buffer)
- break;
- }
-
- /* We can't mark the inode dirty if it's not hashed. This is the case
- * when we're inheriting the default ACL. If we dirty it, the inode
- * gets marked dirty, but won't (ever) make it onto the dirty list until
- * it's synced explicitly to clear I_DIRTY. This is bad. */
- if (!hlist_unhashed(&inode->i_hash)) {
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty (inode);
- }
-
-out_filp:
- up (&xinode->i_sem);
- fput(fp);
-
-out:
- return err;
+
+ out_filp:
+ up(&xinode->i_sem);
+ fput(fp);
+
+ out:
+ return err;
}
/*
* inode->i_sem: down
*/
int
-reiserfs_xattr_get (const struct inode *inode, const char *name, void *buffer,
- size_t buffer_size)
+reiserfs_xattr_get(const struct inode *inode, const char *name, void *buffer,
+ size_t buffer_size)
{
- ssize_t err = 0;
- struct file *fp;
- size_t isize;
- size_t file_pos = 0;
- size_t buffer_pos = 0;
- struct page *page;
- struct inode *xinode;
- __u32 hash = 0;
-
- if (name == NULL)
- return -EINVAL;
-
- /* We can't have xattrs attached to v1 items since they don't have
- * generation numbers */
- if (get_inode_sd_version (inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
-
- fp = open_xa_file (inode, name, FL_READONLY);
- if (IS_ERR (fp)) {
- err = PTR_ERR (fp);
- goto out;
- }
-
- xinode = fp->f_dentry->d_inode;
- isize = xinode->i_size;
- REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
-
- /* Just return the size needed */
- if (buffer == NULL) {
- err = isize - sizeof (struct reiserfs_xattr_header);
- goto out_dput;
- }
-
- if (buffer_size < isize - sizeof (struct reiserfs_xattr_header)) {
- err = -ERANGE;
- goto out_dput;
- }
-
- while (file_pos < isize) {
- size_t chunk;
- char *data;
- size_t skip = 0;
- if (isize - file_pos > PAGE_CACHE_SIZE)
- chunk = PAGE_CACHE_SIZE;
- else
- chunk = isize - file_pos;
-
- page = reiserfs_get_page (xinode, file_pos >> PAGE_CACHE_SHIFT);
- if (IS_ERR (page)) {
- err = PTR_ERR (page);
- goto out_dput;
- }
-
- lock_page (page);
- data = page_address (page);
- if (file_pos == 0) {
- struct reiserfs_xattr_header *rxh =
- (struct reiserfs_xattr_header *)data;
- skip = file_pos = sizeof (struct reiserfs_xattr_header);
- chunk -= skip;
- /* Magic doesn't match up.. */
- if (rxh->h_magic != cpu_to_le32 (REISERFS_XATTR_MAGIC)) {
- unlock_page (page);
- reiserfs_put_page (page);
- reiserfs_warning (inode->i_sb, "Invalid magic for xattr (%s) "
- "associated with %k", name,
- INODE_PKEY (inode));
- err = -EIO;
- goto out_dput;
- }
- hash = le32_to_cpu (rxh->h_hash);
- }
- memcpy (buffer + buffer_pos, data + skip, chunk);
- unlock_page (page);
- reiserfs_put_page (page);
- file_pos += chunk;
- buffer_pos += chunk;
- skip = 0;
- }
- err = isize - sizeof (struct reiserfs_xattr_header);
-
- if (xattr_hash (buffer, isize - sizeof (struct reiserfs_xattr_header)) != hash) {
- reiserfs_warning (inode->i_sb, "Invalid hash for xattr (%s) associated "
- "with %k", name, INODE_PKEY (inode));
- err = -EIO;
- }
-
-out_dput:
- fput(fp);
-
-out:
- return err;
+ ssize_t err = 0;
+ struct file *fp;
+ size_t isize;
+ size_t file_pos = 0;
+ size_t buffer_pos = 0;
+ struct page *page;
+ struct inode *xinode;
+ __u32 hash = 0;
+
+ if (name == NULL)
+ return -EINVAL;
+
+ /* We can't have xattrs attached to v1 items since they don't have
+ * generation numbers */
+ if (get_inode_sd_version(inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
+
+ fp = open_xa_file(inode, name, FL_READONLY);
+ if (IS_ERR(fp)) {
+ err = PTR_ERR(fp);
+ goto out;
+ }
+
+ xinode = fp->f_dentry->d_inode;
+ isize = xinode->i_size;
+ REISERFS_I(inode)->i_flags |= i_has_xattr_dir;
+
+ /* Just return the size needed */
+ if (buffer == NULL) {
+ err = isize - sizeof(struct reiserfs_xattr_header);
+ goto out_dput;
+ }
+
+ if (buffer_size < isize - sizeof(struct reiserfs_xattr_header)) {
+ err = -ERANGE;
+ goto out_dput;
+ }
+
+ while (file_pos < isize) {
+ size_t chunk;
+ char *data;
+ size_t skip = 0;
+ if (isize - file_pos > PAGE_CACHE_SIZE)
+ chunk = PAGE_CACHE_SIZE;
+ else
+ chunk = isize - file_pos;
+
+ page = reiserfs_get_page(xinode, file_pos >> PAGE_CACHE_SHIFT);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto out_dput;
+ }
+
+ lock_page(page);
+ data = page_address(page);
+ if (file_pos == 0) {
+ struct reiserfs_xattr_header *rxh =
+ (struct reiserfs_xattr_header *)data;
+ skip = file_pos = sizeof(struct reiserfs_xattr_header);
+ chunk -= skip;
+ /* Magic doesn't match up.. */
+ if (rxh->h_magic != cpu_to_le32(REISERFS_XATTR_MAGIC)) {
+ unlock_page(page);
+ reiserfs_put_page(page);
+ reiserfs_warning(inode->i_sb,
+ "Invalid magic for xattr (%s) "
+ "associated with %k", name,
+ INODE_PKEY(inode));
+ err = -EIO;
+ goto out_dput;
+ }
+ hash = le32_to_cpu(rxh->h_hash);
+ }
+ memcpy(buffer + buffer_pos, data + skip, chunk);
+ unlock_page(page);
+ reiserfs_put_page(page);
+ file_pos += chunk;
+ buffer_pos += chunk;
+ skip = 0;
+ }
+ err = isize - sizeof(struct reiserfs_xattr_header);
+
+ if (xattr_hash(buffer, isize - sizeof(struct reiserfs_xattr_header)) !=
+ hash) {
+ reiserfs_warning(inode->i_sb,
+ "Invalid hash for xattr (%s) associated "
+ "with %k", name, INODE_PKEY(inode));
+ err = -EIO;
+ }
+
+ out_dput:
+ fput(fp);
+
+ out:
+ return err;
}
static int
-__reiserfs_xattr_del (struct dentry *xadir, const char *name, int namelen)
+__reiserfs_xattr_del(struct dentry *xadir, const char *name, int namelen)
{
- struct dentry *dentry;
- struct inode *dir = xadir->d_inode;
- int err = 0;
-
- dentry = lookup_one_len (name, xadir, namelen);
- if (IS_ERR (dentry)) {
- err = PTR_ERR (dentry);
- goto out;
- } else if (!dentry->d_inode) {
- err = -ENODATA;
- goto out_file;
- }
-
- /* Skip directories.. */
- if (S_ISDIR (dentry->d_inode->i_mode))
- goto out_file;
-
- if (!is_reiserfs_priv_object (dentry->d_inode)) {
- reiserfs_warning (dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have "
- "priv flag set [parent is %sset].",
- le32_to_cpu (INODE_PKEY (dentry->d_inode)->k_objectid),
- xadir->d_name.len, xadir->d_name.name, namelen, name,
- is_reiserfs_priv_object (xadir->d_inode) ? "" : "not ");
- dput (dentry);
- return -EIO;
- }
-
- err = dir->i_op->unlink (dir, dentry);
- if (!err)
- d_delete (dentry);
-
-out_file:
- dput (dentry);
-
-out:
- return err;
-}
+ struct dentry *dentry;
+ struct inode *dir = xadir->d_inode;
+ int err = 0;
+
+ dentry = lookup_one_len(name, xadir, namelen);
+ if (IS_ERR(dentry)) {
+ err = PTR_ERR(dentry);
+ goto out;
+ } else if (!dentry->d_inode) {
+ err = -ENODATA;
+ goto out_file;
+ }
+
+ /* Skip directories.. */
+ if (S_ISDIR(dentry->d_inode->i_mode))
+ goto out_file;
+
+ if (!is_reiserfs_priv_object(dentry->d_inode)) {
+ reiserfs_warning(dir->i_sb, "OID %08x [%.*s/%.*s] doesn't have "
+ "priv flag set [parent is %sset].",
+ le32_to_cpu(INODE_PKEY(dentry->d_inode)->
+ k_objectid), xadir->d_name.len,
+ xadir->d_name.name, namelen, name,
+ is_reiserfs_priv_object(xadir->
+ d_inode) ? "" :
+ "not ");
+ dput(dentry);
+ return -EIO;
+ }
+ err = dir->i_op->unlink(dir, dentry);
+ if (!err)
+ d_delete(dentry);
-int
-reiserfs_xattr_del (struct inode *inode, const char *name)
+ out_file:
+ dput(dentry);
+
+ out:
+ return err;
+}
+
+int reiserfs_xattr_del(struct inode *inode, const char *name)
{
- struct dentry *dir;
- int err;
+ struct dentry *dir;
+ int err;
- if (IS_RDONLY (inode))
- return -EROFS;
+ if (IS_RDONLY(inode))
+ return -EROFS;
- dir = open_xa_dir (inode, FL_READONLY);
- if (IS_ERR (dir)) {
- err = PTR_ERR (dir);
- goto out;
- }
+ dir = open_xa_dir(inode, FL_READONLY);
+ if (IS_ERR(dir)) {
+ err = PTR_ERR(dir);
+ goto out;
+ }
- err = __reiserfs_xattr_del (dir, name, strlen (name));
- dput (dir);
+ err = __reiserfs_xattr_del(dir, name, strlen(name));
+ dput(dir);
- if (!err) {
- inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty (inode);
- }
+ if (!err) {
+ inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(inode);
+ }
-out:
- return err;
+ out:
+ return err;
}
/* The following are side effects of other operations that aren't explicitly
@@ -777,167 +785,163 @@ out:
* or ownership changes, object deletions, etc. */
static int
-reiserfs_delete_xattrs_filler (void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+reiserfs_delete_xattrs_filler(void *buf, const char *name, int namelen,
+ loff_t offset, ino_t ino, unsigned int d_type)
{
- struct dentry *xadir = (struct dentry *)buf;
+ struct dentry *xadir = (struct dentry *)buf;
- return __reiserfs_xattr_del (xadir, name, namelen);
+ return __reiserfs_xattr_del(xadir, name, namelen);
}
/* This is called w/ inode->i_sem downed */
-int
-reiserfs_delete_xattrs (struct inode *inode)
+int reiserfs_delete_xattrs(struct inode *inode)
{
- struct file *fp;
- struct dentry *dir, *root;
- int err = 0;
-
- /* Skip out, an xattr has no xattrs associated with it */
- if (is_reiserfs_priv_object (inode) ||
- get_inode_sd_version (inode) == STAT_DATA_V1 ||
- !reiserfs_xattrs(inode->i_sb))
- {
- return 0;
- }
- reiserfs_read_lock_xattrs (inode->i_sb);
- dir = open_xa_dir (inode, FL_READONLY);
- reiserfs_read_unlock_xattrs (inode->i_sb);
- if (IS_ERR (dir)) {
- err = PTR_ERR (dir);
- goto out;
- } else if (!dir->d_inode) {
- dput (dir);
- return 0;
- }
-
- fp = dentry_open (dir, NULL, O_RDWR);
- if (IS_ERR (fp)) {
- err = PTR_ERR (fp);
- /* dentry_open dputs the dentry if it fails */
- goto out;
- }
-
- lock_kernel ();
- err = xattr_readdir (fp, reiserfs_delete_xattrs_filler, dir);
- if (err) {
- unlock_kernel ();
- goto out_dir;
- }
-
- /* Leftovers besides . and .. -- that's not good. */
- if (dir->d_inode->i_nlink <= 2) {
- root = get_xa_root (inode->i_sb);
- reiserfs_write_lock_xattrs (inode->i_sb);
- err = vfs_rmdir (root->d_inode, dir);
- reiserfs_write_unlock_xattrs (inode->i_sb);
- dput (root);
- } else {
- reiserfs_warning (inode->i_sb,
- "Couldn't remove all entries in directory");
- }
- unlock_kernel ();
-
-out_dir:
- fput(fp);
-
-out:
- if (!err)
- REISERFS_I(inode)->i_flags = REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
- return err;
+ struct file *fp;
+ struct dentry *dir, *root;
+ int err = 0;
+
+ /* Skip out, an xattr has no xattrs associated with it */
+ if (is_reiserfs_priv_object(inode) ||
+ get_inode_sd_version(inode) == STAT_DATA_V1 ||
+ !reiserfs_xattrs(inode->i_sb)) {
+ return 0;
+ }
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ dir = open_xa_dir(inode, FL_READONLY);
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ if (IS_ERR(dir)) {
+ err = PTR_ERR(dir);
+ goto out;
+ } else if (!dir->d_inode) {
+ dput(dir);
+ return 0;
+ }
+
+ fp = dentry_open(dir, NULL, O_RDWR);
+ if (IS_ERR(fp)) {
+ err = PTR_ERR(fp);
+ /* dentry_open dputs the dentry if it fails */
+ goto out;
+ }
+
+ lock_kernel();
+ err = xattr_readdir(fp, reiserfs_delete_xattrs_filler, dir);
+ if (err) {
+ unlock_kernel();
+ goto out_dir;
+ }
+
+ /* Leftovers besides . and .. -- that's not good. */
+ if (dir->d_inode->i_nlink <= 2) {
+ root = get_xa_root(inode->i_sb);
+ reiserfs_write_lock_xattrs(inode->i_sb);
+ err = vfs_rmdir(root->d_inode, dir);
+ reiserfs_write_unlock_xattrs(inode->i_sb);
+ dput(root);
+ } else {
+ reiserfs_warning(inode->i_sb,
+ "Couldn't remove all entries in directory");
+ }
+ unlock_kernel();
+
+ out_dir:
+ fput(fp);
+
+ out:
+ if (!err)
+ REISERFS_I(inode)->i_flags =
+ REISERFS_I(inode)->i_flags & ~i_has_xattr_dir;
+ return err;
}
struct reiserfs_chown_buf {
- struct inode *inode;
- struct dentry *xadir;
- struct iattr *attrs;
+ struct inode *inode;
+ struct dentry *xadir;
+ struct iattr *attrs;
};
/* XXX: If there is a better way to do this, I'd love to hear about it */
static int
-reiserfs_chown_xattrs_filler (void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+reiserfs_chown_xattrs_filler(void *buf, const char *name, int namelen,
+ loff_t offset, ino_t ino, unsigned int d_type)
{
- struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
- struct dentry *xafile, *xadir = chown_buf->xadir;
- struct iattr *attrs = chown_buf->attrs;
- int err = 0;
-
- xafile = lookup_one_len (name, xadir, namelen);
- if (IS_ERR (xafile))
- return PTR_ERR (xafile);
- else if (!xafile->d_inode) {
- dput (xafile);
- return -ENODATA;
- }
-
- if (!S_ISDIR (xafile->d_inode->i_mode))
- err = notify_change (xafile, attrs);
- dput (xafile);
-
- return err;
+ struct reiserfs_chown_buf *chown_buf = (struct reiserfs_chown_buf *)buf;
+ struct dentry *xafile, *xadir = chown_buf->xadir;
+ struct iattr *attrs = chown_buf->attrs;
+ int err = 0;
+
+ xafile = lookup_one_len(name, xadir, namelen);
+ if (IS_ERR(xafile))
+ return PTR_ERR(xafile);
+ else if (!xafile->d_inode) {
+ dput(xafile);
+ return -ENODATA;
+ }
+
+ if (!S_ISDIR(xafile->d_inode->i_mode))
+ err = notify_change(xafile, attrs);
+ dput(xafile);
+
+ return err;
}
-int
-reiserfs_chown_xattrs (struct inode *inode, struct iattr *attrs)
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs)
{
- struct file *fp;
- struct dentry *dir;
- int err = 0;
- struct reiserfs_chown_buf buf;
- unsigned int ia_valid = attrs->ia_valid;
-
- /* Skip out, an xattr has no xattrs associated with it */
- if (is_reiserfs_priv_object (inode) ||
- get_inode_sd_version (inode) == STAT_DATA_V1 ||
- !reiserfs_xattrs(inode->i_sb))
- {
- return 0;
- }
- reiserfs_read_lock_xattrs (inode->i_sb);
- dir = open_xa_dir (inode, FL_READONLY);
- reiserfs_read_unlock_xattrs (inode->i_sb);
- if (IS_ERR (dir)) {
- if (PTR_ERR (dir) != -ENODATA)
- err = PTR_ERR (dir);
- goto out;
- } else if (!dir->d_inode) {
- dput (dir);
- goto out;
- }
-
- fp = dentry_open (dir, NULL, O_RDWR);
- if (IS_ERR (fp)) {
- err = PTR_ERR (fp);
- /* dentry_open dputs the dentry if it fails */
- goto out;
- }
-
- lock_kernel ();
-
- attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
- buf.xadir = dir;
- buf.attrs = attrs;
- buf.inode = inode;
-
- err = xattr_readdir (fp, reiserfs_chown_xattrs_filler, &buf);
- if (err) {
- unlock_kernel ();
- goto out_dir;
- }
-
- err = notify_change (dir, attrs);
- unlock_kernel ();
-
-out_dir:
- fput(fp);
-
-out:
- attrs->ia_valid = ia_valid;
- return err;
-}
+ struct file *fp;
+ struct dentry *dir;
+ int err = 0;
+ struct reiserfs_chown_buf buf;
+ unsigned int ia_valid = attrs->ia_valid;
+
+ /* Skip out, an xattr has no xattrs associated with it */
+ if (is_reiserfs_priv_object(inode) ||
+ get_inode_sd_version(inode) == STAT_DATA_V1 ||
+ !reiserfs_xattrs(inode->i_sb)) {
+ return 0;
+ }
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ dir = open_xa_dir(inode, FL_READONLY);
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ if (IS_ERR(dir)) {
+ if (PTR_ERR(dir) != -ENODATA)
+ err = PTR_ERR(dir);
+ goto out;
+ } else if (!dir->d_inode) {
+ dput(dir);
+ goto out;
+ }
+
+ fp = dentry_open(dir, NULL, O_RDWR);
+ if (IS_ERR(fp)) {
+ err = PTR_ERR(fp);
+ /* dentry_open dputs the dentry if it fails */
+ goto out;
+ }
+ lock_kernel();
+
+ attrs->ia_valid &= (ATTR_UID | ATTR_GID | ATTR_CTIME);
+ buf.xadir = dir;
+ buf.attrs = attrs;
+ buf.inode = inode;
+
+ err = xattr_readdir(fp, reiserfs_chown_xattrs_filler, &buf);
+ if (err) {
+ unlock_kernel();
+ goto out_dir;
+ }
+
+ err = notify_change(dir, attrs);
+ unlock_kernel();
+
+ out_dir:
+ fput(fp);
+
+ out:
+ attrs->ia_valid = ia_valid;
+ return err;
+}
/* Actual operations that are exported to VFS-land */
@@ -946,61 +950,60 @@ out:
* Preliminary locking: we down dentry->d_inode->i_sem
*/
ssize_t
-reiserfs_getxattr (struct dentry *dentry, const char *name, void *buffer,
- size_t size)
+reiserfs_getxattr(struct dentry * dentry, const char *name, void *buffer,
+ size_t size)
{
- struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
- int err;
-
- if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
- get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
-
- reiserfs_read_lock_xattr_i (dentry->d_inode);
- reiserfs_read_lock_xattrs (dentry->d_sb);
- err = xah->get (dentry->d_inode, name, buffer, size);
- reiserfs_read_unlock_xattrs (dentry->d_sb);
- reiserfs_read_unlock_xattr_i (dentry->d_inode);
- return err;
+ struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
+ int err;
+
+ if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
+ get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
+
+ reiserfs_read_lock_xattr_i(dentry->d_inode);
+ reiserfs_read_lock_xattrs(dentry->d_sb);
+ err = xah->get(dentry->d_inode, name, buffer, size);
+ reiserfs_read_unlock_xattrs(dentry->d_sb);
+ reiserfs_read_unlock_xattr_i(dentry->d_inode);
+ return err;
}
-
/*
* Inode operation setxattr()
*
* dentry->d_inode->i_sem down
*/
int
-reiserfs_setxattr (struct dentry *dentry, const char *name, const void *value,
- size_t size, int flags)
+reiserfs_setxattr(struct dentry *dentry, const char *name, const void *value,
+ size_t size, int flags)
{
- struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
- int err;
- int lock;
-
- if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
- get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
-
- if (IS_RDONLY (dentry->d_inode))
- return -EROFS;
-
- if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
- return -EROFS;
-
- reiserfs_write_lock_xattr_i (dentry->d_inode);
- lock = !has_xattr_dir (dentry->d_inode);
- if (lock)
- reiserfs_write_lock_xattrs (dentry->d_sb);
- else
- reiserfs_read_lock_xattrs (dentry->d_sb);
- err = xah->set (dentry->d_inode, name, value, size, flags);
- if (lock)
- reiserfs_write_unlock_xattrs (dentry->d_sb);
- else
- reiserfs_read_unlock_xattrs (dentry->d_sb);
- reiserfs_write_unlock_xattr_i (dentry->d_inode);
- return err;
+ struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
+ int err;
+ int lock;
+
+ if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
+ get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
+
+ if (IS_RDONLY(dentry->d_inode))
+ return -EROFS;
+
+ if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode))
+ return -EROFS;
+
+ reiserfs_write_lock_xattr_i(dentry->d_inode);
+ lock = !has_xattr_dir(dentry->d_inode);
+ if (lock)
+ reiserfs_write_lock_xattrs(dentry->d_sb);
+ else
+ reiserfs_read_lock_xattrs(dentry->d_sb);
+ err = xah->set(dentry->d_inode, name, value, size, flags);
+ if (lock)
+ reiserfs_write_unlock_xattrs(dentry->d_sb);
+ else
+ reiserfs_read_unlock_xattrs(dentry->d_sb);
+ reiserfs_write_unlock_xattr_i(dentry->d_inode);
+ return err;
}
/*
@@ -1008,344 +1011,343 @@ reiserfs_setxattr (struct dentry *dentry, const char *name, const void *value,
*
* dentry->d_inode->i_sem down
*/
-int
-reiserfs_removexattr (struct dentry *dentry, const char *name)
+int reiserfs_removexattr(struct dentry *dentry, const char *name)
{
- int err;
- struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
+ int err;
+ struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix(name);
- if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
- get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
+ if (!xah || !reiserfs_xattrs(dentry->d_sb) ||
+ get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
- if (IS_RDONLY (dentry->d_inode))
- return -EROFS;
+ if (IS_RDONLY(dentry->d_inode))
+ return -EROFS;
- if (IS_IMMUTABLE (dentry->d_inode) || IS_APPEND (dentry->d_inode))
- return -EPERM;
+ if (IS_IMMUTABLE(dentry->d_inode) || IS_APPEND(dentry->d_inode))
+ return -EPERM;
- reiserfs_write_lock_xattr_i (dentry->d_inode);
- reiserfs_read_lock_xattrs (dentry->d_sb);
+ reiserfs_write_lock_xattr_i(dentry->d_inode);
+ reiserfs_read_lock_xattrs(dentry->d_sb);
- /* Deletion pre-operation */
- if (xah->del) {
- err = xah->del (dentry->d_inode, name);
- if (err)
- goto out;
- }
+ /* Deletion pre-operation */
+ if (xah->del) {
+ err = xah->del(dentry->d_inode, name);
+ if (err)
+ goto out;
+ }
- err = reiserfs_xattr_del (dentry->d_inode, name);
+ err = reiserfs_xattr_del(dentry->d_inode, name);
- dentry->d_inode->i_ctime = CURRENT_TIME_SEC;
- mark_inode_dirty (dentry->d_inode);
+ dentry->d_inode->i_ctime = CURRENT_TIME_SEC;
+ mark_inode_dirty(dentry->d_inode);
-out:
- reiserfs_read_unlock_xattrs (dentry->d_sb);
- reiserfs_write_unlock_xattr_i (dentry->d_inode);
- return err;
+ out:
+ reiserfs_read_unlock_xattrs(dentry->d_sb);
+ reiserfs_write_unlock_xattr_i(dentry->d_inode);
+ return err;
}
-
/* This is what filldir will use:
* r_pos will always contain the amount of space required for the entire
* list. If r_pos becomes larger than r_size, we need more space and we
* return an error indicating this. If r_pos is less than r_size, then we've
* filled the buffer successfully and we return success */
struct reiserfs_listxattr_buf {
- int r_pos;
- int r_size;
- char *r_buf;
- struct inode *r_inode;
+ int r_pos;
+ int r_size;
+ char *r_buf;
+ struct inode *r_inode;
};
static int
-reiserfs_listxattr_filler (void *buf, const char *name, int namelen,
- loff_t offset, ino_t ino, unsigned int d_type)
+reiserfs_listxattr_filler(void *buf, const char *name, int namelen,
+ loff_t offset, ino_t ino, unsigned int d_type)
{
- struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
- int len = 0;
- if (name[0] != '.' || (namelen != 1 && (name[1] != '.' || namelen != 2))) {
- struct reiserfs_xattr_handler *xah = find_xattr_handler_prefix (name);
- if (!xah) return 0; /* Unsupported xattr name, skip it */
-
- /* We call ->list() twice because the operation isn't required to just
- * return the name back - we want to make sure we have enough space */
- len += xah->list (b->r_inode, name, namelen, NULL);
-
- if (len) {
- if (b->r_pos + len + 1 <= b->r_size) {
- char *p = b->r_buf + b->r_pos;
- p += xah->list (b->r_inode, name, namelen, p);
- *p++ = '\0';
- }
- b->r_pos += len + 1;
- }
- }
-
- return 0;
+ struct reiserfs_listxattr_buf *b = (struct reiserfs_listxattr_buf *)buf;
+ int len = 0;
+ if (name[0] != '.'
+ || (namelen != 1 && (name[1] != '.' || namelen != 2))) {
+ struct reiserfs_xattr_handler *xah =
+ find_xattr_handler_prefix(name);
+ if (!xah)
+ return 0; /* Unsupported xattr name, skip it */
+
+ /* We call ->list() twice because the operation isn't required to just
+ * return the name back - we want to make sure we have enough space */
+ len += xah->list(b->r_inode, name, namelen, NULL);
+
+ if (len) {
+ if (b->r_pos + len + 1 <= b->r_size) {
+ char *p = b->r_buf + b->r_pos;
+ p += xah->list(b->r_inode, name, namelen, p);
+ *p++ = '\0';
+ }
+ b->r_pos += len + 1;
+ }
+ }
+
+ return 0;
}
+
/*
* Inode operation listxattr()
*
* Preliminary locking: we down dentry->d_inode->i_sem
*/
-ssize_t
-reiserfs_listxattr (struct dentry *dentry, char *buffer, size_t size)
+ssize_t reiserfs_listxattr(struct dentry * dentry, char *buffer, size_t size)
{
- struct file *fp;
- struct dentry *dir;
- int err = 0;
- struct reiserfs_listxattr_buf buf;
-
- if (!dentry->d_inode)
- return -EINVAL;
-
- if (!reiserfs_xattrs(dentry->d_sb) ||
- get_inode_sd_version (dentry->d_inode) == STAT_DATA_V1)
- return -EOPNOTSUPP;
-
- reiserfs_read_lock_xattr_i (dentry->d_inode);
- reiserfs_read_lock_xattrs (dentry->d_sb);
- dir = open_xa_dir (dentry->d_inode, FL_READONLY);
- reiserfs_read_unlock_xattrs (dentry->d_sb);
- if (IS_ERR (dir)) {
- err = PTR_ERR (dir);
- if (err == -ENODATA)
- err = 0; /* Not an error if there aren't any xattrs */
- goto out;
- }
-
- fp = dentry_open (dir, NULL, O_RDWR);
- if (IS_ERR (fp)) {
- err = PTR_ERR (fp);
- /* dentry_open dputs the dentry if it fails */
- goto out;
- }
-
- buf.r_buf = buffer;
- buf.r_size = buffer ? size : 0;
- buf.r_pos = 0;
- buf.r_inode = dentry->d_inode;
-
- REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir;
-
- err = xattr_readdir (fp, reiserfs_listxattr_filler, &buf);
- if (err)
- goto out_dir;
-
- if (buf.r_pos > buf.r_size && buffer != NULL)
- err = -ERANGE;
- else
- err = buf.r_pos;
-
-out_dir:
- fput(fp);
-
-out:
- reiserfs_read_unlock_xattr_i (dentry->d_inode);
- return err;
+ struct file *fp;
+ struct dentry *dir;
+ int err = 0;
+ struct reiserfs_listxattr_buf buf;
+
+ if (!dentry->d_inode)
+ return -EINVAL;
+
+ if (!reiserfs_xattrs(dentry->d_sb) ||
+ get_inode_sd_version(dentry->d_inode) == STAT_DATA_V1)
+ return -EOPNOTSUPP;
+
+ reiserfs_read_lock_xattr_i(dentry->d_inode);
+ reiserfs_read_lock_xattrs(dentry->d_sb);
+ dir = open_xa_dir(dentry->d_inode, FL_READONLY);
+ reiserfs_read_unlock_xattrs(dentry->d_sb);
+ if (IS_ERR(dir)) {
+ err = PTR_ERR(dir);
+ if (err == -ENODATA)
+ err = 0; /* Not an error if there aren't any xattrs */
+ goto out;
+ }
+
+ fp = dentry_open(dir, NULL, O_RDWR);
+ if (IS_ERR(fp)) {
+ err = PTR_ERR(fp);
+ /* dentry_open dputs the dentry if it fails */
+ goto out;
+ }
+
+ buf.r_buf = buffer;
+ buf.r_size = buffer ? size : 0;
+ buf.r_pos = 0;
+ buf.r_inode = dentry->d_inode;
+
+ REISERFS_I(dentry->d_inode)->i_flags |= i_has_xattr_dir;
+
+ err = xattr_readdir(fp, reiserfs_listxattr_filler, &buf);
+ if (err)
+ goto out_dir;
+
+ if (buf.r_pos > buf.r_size && buffer != NULL)
+ err = -ERANGE;
+ else
+ err = buf.r_pos;
+
+ out_dir:
+ fput(fp);
+
+ out:
+ reiserfs_read_unlock_xattr_i(dentry->d_inode);
+ return err;
}
/* This is the implementation for the xattr plugin infrastructure */
-static struct list_head xattr_handlers = LIST_HEAD_INIT (xattr_handlers);
+static struct list_head xattr_handlers = LIST_HEAD_INIT(xattr_handlers);
static DEFINE_RWLOCK(handler_lock);
-static struct reiserfs_xattr_handler *
-find_xattr_handler_prefix (const char *prefix)
+static struct reiserfs_xattr_handler *find_xattr_handler_prefix(const char
+ *prefix)
{
- struct reiserfs_xattr_handler *xah = NULL;
- struct list_head *p;
-
- read_lock (&handler_lock);
- list_for_each (p, &xattr_handlers) {
- xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
- if (strncmp (xah->prefix, prefix, strlen (xah->prefix)) == 0)
- break;
- xah = NULL;
- }
-
- read_unlock (&handler_lock);
- return xah;
+ struct reiserfs_xattr_handler *xah = NULL;
+ struct list_head *p;
+
+ read_lock(&handler_lock);
+ list_for_each(p, &xattr_handlers) {
+ xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
+ if (strncmp(xah->prefix, prefix, strlen(xah->prefix)) == 0)
+ break;
+ xah = NULL;
+ }
+
+ read_unlock(&handler_lock);
+ return xah;
}
-static void
-__unregister_handlers (void)
+static void __unregister_handlers(void)
{
- struct reiserfs_xattr_handler *xah;
- struct list_head *p, *tmp;
+ struct reiserfs_xattr_handler *xah;
+ struct list_head *p, *tmp;
- list_for_each_safe (p, tmp, &xattr_handlers) {
- xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
- if (xah->exit)
- xah->exit();
+ list_for_each_safe(p, tmp, &xattr_handlers) {
+ xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
+ if (xah->exit)
+ xah->exit();
- list_del_init (p);
- }
- INIT_LIST_HEAD (&xattr_handlers);
+ list_del_init(p);
+ }
+ INIT_LIST_HEAD(&xattr_handlers);
}
-int __init
-reiserfs_xattr_register_handlers (void)
+int __init reiserfs_xattr_register_handlers(void)
{
- int err = 0;
- struct reiserfs_xattr_handler *xah;
- struct list_head *p;
+ int err = 0;
+ struct reiserfs_xattr_handler *xah;
+ struct list_head *p;
- write_lock (&handler_lock);
+ write_lock(&handler_lock);
- /* If we're already initialized, nothing to do */
- if (!list_empty (&xattr_handlers)) {
- write_unlock (&handler_lock);
- return 0;
- }
+ /* If we're already initialized, nothing to do */
+ if (!list_empty(&xattr_handlers)) {
+ write_unlock(&handler_lock);
+ return 0;
+ }
- /* Add the handlers */
- list_add_tail (&user_handler.handlers, &xattr_handlers);
- list_add_tail (&trusted_handler.handlers, &xattr_handlers);
+ /* Add the handlers */
+ list_add_tail(&user_handler.handlers, &xattr_handlers);
+ list_add_tail(&trusted_handler.handlers, &xattr_handlers);
#ifdef CONFIG_REISERFS_FS_SECURITY
- list_add_tail (&security_handler.handlers, &xattr_handlers);
+ list_add_tail(&security_handler.handlers, &xattr_handlers);
#endif
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
- list_add_tail (&posix_acl_access_handler.handlers, &xattr_handlers);
- list_add_tail (&posix_acl_default_handler.handlers, &xattr_handlers);
+ list_add_tail(&posix_acl_access_handler.handlers, &xattr_handlers);
+ list_add_tail(&posix_acl_default_handler.handlers, &xattr_handlers);
#endif
- /* Run initializers, if available */
- list_for_each (p, &xattr_handlers) {
- xah = list_entry (p, struct reiserfs_xattr_handler, handlers);
- if (xah->init) {
- err = xah->init ();
- if (err) {
- list_del_init (p);
- break;
- }
- }
- }
-
- /* Clean up other handlers, if any failed */
- if (err)
- __unregister_handlers ();
-
- write_unlock (&handler_lock);
- return err;
+ /* Run initializers, if available */
+ list_for_each(p, &xattr_handlers) {
+ xah = list_entry(p, struct reiserfs_xattr_handler, handlers);
+ if (xah->init) {
+ err = xah->init();
+ if (err) {
+ list_del_init(p);
+ break;
+ }
+ }
+ }
+
+ /* Clean up other handlers, if any failed */
+ if (err)
+ __unregister_handlers();
+
+ write_unlock(&handler_lock);
+ return err;
}
-void
-reiserfs_xattr_unregister_handlers (void)
+void reiserfs_xattr_unregister_handlers(void)
{
- write_lock (&handler_lock);
- __unregister_handlers ();
- write_unlock (&handler_lock);
+ write_lock(&handler_lock);
+ __unregister_handlers();
+ write_unlock(&handler_lock);
}
/* This will catch lookups from the fs root to .reiserfs_priv */
static int
-xattr_lookup_poison (struct dentry *dentry, struct qstr *q1, struct qstr *name)
+xattr_lookup_poison(struct dentry *dentry, struct qstr *q1, struct qstr *name)
{
- struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root;
- if (name->len == priv_root->d_name.len &&
- name->hash == priv_root->d_name.hash &&
- !memcmp (name->name, priv_root->d_name.name, name->len)) {
- return -ENOENT;
- } else if (q1->len == name->len &&
- !memcmp(q1->name, name->name, name->len))
- return 0;
- return 1;
+ struct dentry *priv_root = REISERFS_SB(dentry->d_sb)->priv_root;
+ if (name->len == priv_root->d_name.len &&
+ name->hash == priv_root->d_name.hash &&
+ !memcmp(name->name, priv_root->d_name.name, name->len)) {
+ return -ENOENT;
+ } else if (q1->len == name->len &&
+ !memcmp(q1->name, name->name, name->len))
+ return 0;
+ return 1;
}
static struct dentry_operations xattr_lookup_poison_ops = {
- .d_compare = xattr_lookup_poison,
+ .d_compare = xattr_lookup_poison,
};
-
/* We need to take a copy of the mount flags since things like
* MS_RDONLY don't get set until *after* we're called.
* mount_flags != mount_options */
-int
-reiserfs_xattr_init (struct super_block *s, int mount_flags)
+int reiserfs_xattr_init(struct super_block *s, int mount_flags)
{
- int err = 0;
-
- /* We need generation numbers to ensure that the oid mapping is correct
- * v3.5 filesystems don't have them. */
- if (!old_format_only (s)) {
- set_bit (REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
- } else if (reiserfs_xattrs_optional (s)) {
- /* Old format filesystem, but optional xattrs have been enabled
- * at mount time. Error out. */
- reiserfs_warning (s, "xattrs/ACLs not supported on pre v3.6 "
- "format filesystem. Failing mount.");
- err = -EOPNOTSUPP;
- goto error;
- } else {
- /* Old format filesystem, but no optional xattrs have been enabled. This
- * means we silently disable xattrs on the filesystem. */
- clear_bit (REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
- }
-
- /* If we don't have the privroot located yet - go find it */
- if (reiserfs_xattrs (s) && !REISERFS_SB(s)->priv_root) {
- struct dentry *dentry;
- dentry = lookup_one_len (PRIVROOT_NAME, s->s_root,
- strlen (PRIVROOT_NAME));
- if (!IS_ERR (dentry)) {
- if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
- struct inode *inode = dentry->d_parent->d_inode;
- down (&inode->i_sem);
- err = inode->i_op->mkdir (inode, dentry, 0700);
- up (&inode->i_sem);
- if (err) {
- dput (dentry);
- dentry = NULL;
- }
-
- if (dentry && dentry->d_inode)
- reiserfs_warning (s, "Created %s on %s - reserved for "
- "xattr storage.", PRIVROOT_NAME,
- reiserfs_bdevname (inode->i_sb));
- } else if (!dentry->d_inode) {
- dput (dentry);
- dentry = NULL;
- }
- } else
- err = PTR_ERR (dentry);
-
- if (!err && dentry) {
- s->s_root->d_op = &xattr_lookup_poison_ops;
- reiserfs_mark_inode_private (dentry->d_inode);
- REISERFS_SB(s)->priv_root = dentry;
- } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
- /* If we're read-only it just means that the dir hasn't been
- * created. Not an error -- just no xattrs on the fs. We'll
- * check again if we go read-write */
- reiserfs_warning (s, "xattrs/ACLs enabled and couldn't "
- "find/create .reiserfs_priv. Failing mount.");
- err = -EOPNOTSUPP;
- }
- }
-
-error:
- /* This is only nonzero if there was an error initializing the xattr
- * directory or if there is a condition where we don't support them. */
- if (err) {
- clear_bit (REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
- clear_bit (REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
- clear_bit (REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
- }
-
- /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
- s->s_flags = s->s_flags & ~MS_POSIXACL;
- if (reiserfs_posixacl (s))
- s->s_flags |= MS_POSIXACL;
-
- return err;
+ int err = 0;
+
+ /* We need generation numbers to ensure that the oid mapping is correct
+ * v3.5 filesystems don't have them. */
+ if (!old_format_only(s)) {
+ set_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
+ } else if (reiserfs_xattrs_optional(s)) {
+ /* Old format filesystem, but optional xattrs have been enabled
+ * at mount time. Error out. */
+ reiserfs_warning(s, "xattrs/ACLs not supported on pre v3.6 "
+ "format filesystem. Failing mount.");
+ err = -EOPNOTSUPP;
+ goto error;
+ } else {
+ /* Old format filesystem, but no optional xattrs have been enabled. This
+ * means we silently disable xattrs on the filesystem. */
+ clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
+ }
+
+ /* If we don't have the privroot located yet - go find it */
+ if (reiserfs_xattrs(s) && !REISERFS_SB(s)->priv_root) {
+ struct dentry *dentry;
+ dentry = lookup_one_len(PRIVROOT_NAME, s->s_root,
+ strlen(PRIVROOT_NAME));
+ if (!IS_ERR(dentry)) {
+ if (!(mount_flags & MS_RDONLY) && !dentry->d_inode) {
+ struct inode *inode = dentry->d_parent->d_inode;
+ down(&inode->i_sem);
+ err = inode->i_op->mkdir(inode, dentry, 0700);
+ up(&inode->i_sem);
+ if (err) {
+ dput(dentry);
+ dentry = NULL;
+ }
+
+ if (dentry && dentry->d_inode)
+ reiserfs_warning(s,
+ "Created %s on %s - reserved for "
+ "xattr storage.",
+ PRIVROOT_NAME,
+ reiserfs_bdevname
+ (inode->i_sb));
+ } else if (!dentry->d_inode) {
+ dput(dentry);
+ dentry = NULL;
+ }
+ } else
+ err = PTR_ERR(dentry);
+
+ if (!err && dentry) {
+ s->s_root->d_op = &xattr_lookup_poison_ops;
+ reiserfs_mark_inode_private(dentry->d_inode);
+ REISERFS_SB(s)->priv_root = dentry;
+ } else if (!(mount_flags & MS_RDONLY)) { /* xattrs are unavailable */
+ /* If we're read-only it just means that the dir hasn't been
+ * created. Not an error -- just no xattrs on the fs. We'll
+ * check again if we go read-write */
+ reiserfs_warning(s, "xattrs/ACLs enabled and couldn't "
+ "find/create .reiserfs_priv. Failing mount.");
+ err = -EOPNOTSUPP;
+ }
+ }
+
+ error:
+ /* This is only nonzero if there was an error initializing the xattr
+ * directory or if there is a condition where we don't support them. */
+ if (err) {
+ clear_bit(REISERFS_XATTRS, &(REISERFS_SB(s)->s_mount_opt));
+ clear_bit(REISERFS_XATTRS_USER, &(REISERFS_SB(s)->s_mount_opt));
+ clear_bit(REISERFS_POSIXACL, &(REISERFS_SB(s)->s_mount_opt));
+ }
+
+ /* The super_block MS_POSIXACL must mirror the (no)acl mount option. */
+ s->s_flags = s->s_flags & ~MS_POSIXACL;
+ if (reiserfs_posixacl(s))
+ s->s_flags |= MS_POSIXACL;
+
+ return err;
}
static int
-__reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd,
- int need_lock)
+__reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd,
+ int need_lock)
{
- umode_t mode = inode->i_mode;
+ umode_t mode = inode->i_mode;
if (mask & MAY_WRITE) {
/*
@@ -1363,50 +1365,50 @@ __reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd,
}
/* We don't do permission checks on the internal objects.
- * Permissions are determined by the "owning" object. */
- if (is_reiserfs_priv_object (inode))
+ * Permissions are determined by the "owning" object. */
+ if (is_reiserfs_priv_object(inode))
return 0;
if (current->fsuid == inode->i_uid) {
mode >>= 6;
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
} else if (reiserfs_posixacl(inode->i_sb) &&
- get_inode_sd_version (inode) != STAT_DATA_V1) {
- struct posix_acl *acl;
+ get_inode_sd_version(inode) != STAT_DATA_V1) {
+ struct posix_acl *acl;
/* ACL can't contain additional permissions if
the ACL_MASK entry is 0 */
if (!(mode & S_IRWXG))
goto check_groups;
- if (need_lock) {
- reiserfs_read_lock_xattr_i (inode);
- reiserfs_read_lock_xattrs (inode->i_sb);
+ if (need_lock) {
+ reiserfs_read_lock_xattr_i(inode);
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ }
+ acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
+ if (need_lock) {
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ reiserfs_read_unlock_xattr_i(inode);
}
- acl = reiserfs_get_acl (inode, ACL_TYPE_ACCESS);
- if (need_lock) {
- reiserfs_read_unlock_xattrs (inode->i_sb);
- reiserfs_read_unlock_xattr_i (inode);
+ if (IS_ERR(acl)) {
+ if (PTR_ERR(acl) == -ENODATA)
+ goto check_groups;
+ return PTR_ERR(acl);
}
- if (IS_ERR (acl)) {
- if (PTR_ERR (acl) == -ENODATA)
- goto check_groups;
- return PTR_ERR (acl);
- }
-
- if (acl) {
- int err = posix_acl_permission (inode, acl, mask);
- posix_acl_release (acl);
- if (err == -EACCES) {
- goto check_capabilities;
- }
- return err;
+
+ if (acl) {
+ int err = posix_acl_permission(inode, acl, mask);
+ posix_acl_release(acl);
+ if (err == -EACCES) {
+ goto check_capabilities;
+ }
+ return err;
} else {
goto check_groups;
- }
+ }
#endif
} else {
-check_groups:
+ check_groups:
if (in_group_p(inode->i_gid))
mode >>= 3;
}
@@ -1414,10 +1416,10 @@ check_groups:
/*
* If the DACs are ok we don't need any capability check.
*/
- if (((mode & mask & (MAY_READ|MAY_WRITE|MAY_EXEC)) == mask))
+ if (((mode & mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == mask))
return 0;
-check_capabilities:
+ check_capabilities:
/*
* Read/write DACs are always overridable.
* Executable DACs are overridable if at least one exec bit is set.
@@ -1437,14 +1439,13 @@ check_capabilities:
return -EACCES;
}
-int
-reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd)
+int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
- return __reiserfs_permission (inode, mask, nd, 1);
+ return __reiserfs_permission(inode, mask, nd, 1);
}
int
-reiserfs_permission_locked (struct inode *inode, int mask, struct nameidata *nd)
+reiserfs_permission_locked(struct inode *inode, int mask, struct nameidata *nd)
{
- return __reiserfs_permission (inode, mask, nd, 0);
+ return __reiserfs_permission(inode, mask, nd, 0);
}
diff --git a/fs/reiserfs/xattr_acl.c b/fs/reiserfs/xattr_acl.c
index c312881c5f53..6703efa3c430 100644
--- a/fs/reiserfs/xattr_acl.c
+++ b/fs/reiserfs/xattr_acl.c
@@ -9,7 +9,8 @@
#include <linux/reiserfs_acl.h>
#include <asm/uaccess.h>
-static int reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl);
+static int reiserfs_set_acl(struct inode *inode, int type,
+ struct posix_acl *acl);
static int
xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
@@ -34,14 +35,13 @@ xattr_set_acl(struct inode *inode, int type, const void *value, size_t size)
} else
acl = NULL;
- error = reiserfs_set_acl (inode, type, acl);
+ error = reiserfs_set_acl(inode, type, acl);
-release_and_out:
+ release_and_out:
posix_acl_release(acl);
return error;
}
-
static int
xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
{
@@ -51,7 +51,7 @@ xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
if (!reiserfs_posixacl(inode->i_sb))
return -EOPNOTSUPP;
- acl = reiserfs_get_acl (inode, type);
+ acl = reiserfs_get_acl(inode, type);
if (IS_ERR(acl))
return PTR_ERR(acl);
if (acl == NULL)
@@ -62,12 +62,10 @@ xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
return error;
}
-
/*
* Convert from filesystem to in-memory representation.
*/
-static struct posix_acl *
-posix_acl_from_disk(const void *value, size_t size)
+static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
{
const char *end = (char *)value + size;
int n, count;
@@ -76,8 +74,8 @@ posix_acl_from_disk(const void *value, size_t size)
if (!value)
return NULL;
if (size < sizeof(reiserfs_acl_header))
- return ERR_PTR(-EINVAL);
- if (((reiserfs_acl_header *)value)->a_version !=
+ return ERR_PTR(-EINVAL);
+ if (((reiserfs_acl_header *) value)->a_version !=
cpu_to_le32(REISERFS_ACL_VERSION))
return ERR_PTR(-EINVAL);
value = (char *)value + sizeof(reiserfs_acl_header);
@@ -89,41 +87,39 @@ posix_acl_from_disk(const void *value, size_t size)
acl = posix_acl_alloc(count, GFP_NOFS);
if (!acl)
return ERR_PTR(-ENOMEM);
- for (n=0; n < count; n++) {
- reiserfs_acl_entry *entry =
- (reiserfs_acl_entry *)value;
+ for (n = 0; n < count; n++) {
+ reiserfs_acl_entry *entry = (reiserfs_acl_entry *) value;
if ((char *)value + sizeof(reiserfs_acl_entry_short) > end)
goto fail;
- acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
+ acl->a_entries[n].e_tag = le16_to_cpu(entry->e_tag);
acl->a_entries[n].e_perm = le16_to_cpu(entry->e_perm);
- switch(acl->a_entries[n].e_tag) {
- case ACL_USER_OBJ:
- case ACL_GROUP_OBJ:
- case ACL_MASK:
- case ACL_OTHER:
- value = (char *)value +
- sizeof(reiserfs_acl_entry_short);
- acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
- break;
-
- case ACL_USER:
- case ACL_GROUP:
- value = (char *)value + sizeof(reiserfs_acl_entry);
- if ((char *)value > end)
- goto fail;
- acl->a_entries[n].e_id =
- le32_to_cpu(entry->e_id);
- break;
-
- default:
+ switch (acl->a_entries[n].e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ value = (char *)value +
+ sizeof(reiserfs_acl_entry_short);
+ acl->a_entries[n].e_id = ACL_UNDEFINED_ID;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ value = (char *)value + sizeof(reiserfs_acl_entry);
+ if ((char *)value > end)
goto fail;
+ acl->a_entries[n].e_id = le32_to_cpu(entry->e_id);
+ break;
+
+ default:
+ goto fail;
}
}
if (value != end)
goto fail;
return acl;
-fail:
+ fail:
posix_acl_release(acl);
return ERR_PTR(-EINVAL);
}
@@ -131,46 +127,46 @@ fail:
/*
* Convert from in-memory to filesystem representation.
*/
-static void *
-posix_acl_to_disk(const struct posix_acl *acl, size_t *size)
+static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
{
reiserfs_acl_header *ext_acl;
char *e;
int n;
*size = reiserfs_acl_size(acl->a_count);
- ext_acl = (reiserfs_acl_header *)kmalloc(sizeof(reiserfs_acl_header) +
- acl->a_count * sizeof(reiserfs_acl_entry), GFP_NOFS);
+ ext_acl = (reiserfs_acl_header *) kmalloc(sizeof(reiserfs_acl_header) +
+ acl->a_count *
+ sizeof(reiserfs_acl_entry),
+ GFP_NOFS);
if (!ext_acl)
return ERR_PTR(-ENOMEM);
ext_acl->a_version = cpu_to_le32(REISERFS_ACL_VERSION);
e = (char *)ext_acl + sizeof(reiserfs_acl_header);
- for (n=0; n < acl->a_count; n++) {
- reiserfs_acl_entry *entry = (reiserfs_acl_entry *)e;
- entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
+ for (n = 0; n < acl->a_count; n++) {
+ reiserfs_acl_entry *entry = (reiserfs_acl_entry *) e;
+ entry->e_tag = cpu_to_le16(acl->a_entries[n].e_tag);
entry->e_perm = cpu_to_le16(acl->a_entries[n].e_perm);
- switch(acl->a_entries[n].e_tag) {
- case ACL_USER:
- case ACL_GROUP:
- entry->e_id =
- cpu_to_le32(acl->a_entries[n].e_id);
- e += sizeof(reiserfs_acl_entry);
- break;
-
- case ACL_USER_OBJ:
- case ACL_GROUP_OBJ:
- case ACL_MASK:
- case ACL_OTHER:
- e += sizeof(reiserfs_acl_entry_short);
- break;
-
- default:
- goto fail;
+ switch (acl->a_entries[n].e_tag) {
+ case ACL_USER:
+ case ACL_GROUP:
+ entry->e_id = cpu_to_le32(acl->a_entries[n].e_id);
+ e += sizeof(reiserfs_acl_entry);
+ break;
+
+ case ACL_USER_OBJ:
+ case ACL_GROUP_OBJ:
+ case ACL_MASK:
+ case ACL_OTHER:
+ e += sizeof(reiserfs_acl_entry_short);
+ break;
+
+ default:
+ goto fail;
}
}
return (char *)ext_acl;
-fail:
+ fail:
kfree(ext_acl);
return ERR_PTR(-EINVAL);
}
@@ -181,59 +177,58 @@ fail:
* inode->i_sem: down
* BKL held [before 2.5.x]
*/
-struct posix_acl *
-reiserfs_get_acl(struct inode *inode, int type)
+struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
{
char *name, *value;
struct posix_acl *acl, **p_acl;
size_t size;
int retval;
- struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
-
- switch (type) {
- case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
- p_acl = &reiserfs_i->i_acl_access;
- break;
- case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
- p_acl = &reiserfs_i->i_acl_default;
- break;
- default:
- return ERR_PTR (-EINVAL);
- }
-
- if (IS_ERR (*p_acl)) {
- if (PTR_ERR (*p_acl) == -ENODATA)
- return NULL;
- } else if (*p_acl != NULL)
- return posix_acl_dup (*p_acl);
-
- size = reiserfs_xattr_get (inode, name, NULL, 0);
- if ((int)size < 0) {
- if (size == -ENODATA || size == -ENOSYS) {
- *p_acl = ERR_PTR (-ENODATA);
- return NULL;
- }
- return ERR_PTR (size);
- }
+ struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ p_acl = &reiserfs_i->i_acl_access;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ p_acl = &reiserfs_i->i_acl_default;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (IS_ERR(*p_acl)) {
+ if (PTR_ERR(*p_acl) == -ENODATA)
+ return NULL;
+ } else if (*p_acl != NULL)
+ return posix_acl_dup(*p_acl);
+
+ size = reiserfs_xattr_get(inode, name, NULL, 0);
+ if ((int)size < 0) {
+ if (size == -ENODATA || size == -ENOSYS) {
+ *p_acl = ERR_PTR(-ENODATA);
+ return NULL;
+ }
+ return ERR_PTR(size);
+ }
- value = kmalloc (size, GFP_NOFS);
- if (!value)
- return ERR_PTR (-ENOMEM);
+ value = kmalloc(size, GFP_NOFS);
+ if (!value)
+ return ERR_PTR(-ENOMEM);
retval = reiserfs_xattr_get(inode, name, value, size);
if (retval == -ENODATA || retval == -ENOSYS) {
/* This shouldn't actually happen as it should have
been caught above.. but just in case */
acl = NULL;
- *p_acl = ERR_PTR (-ENODATA);
- } else if (retval < 0) {
+ *p_acl = ERR_PTR(-ENODATA);
+ } else if (retval < 0) {
acl = ERR_PTR(retval);
} else {
acl = posix_acl_from_disk(value, retval);
- *p_acl = posix_acl_dup (acl);
- }
+ *p_acl = posix_acl_dup(acl);
+ }
kfree(value);
return acl;
@@ -248,72 +243,72 @@ reiserfs_get_acl(struct inode *inode, int type)
static int
reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
{
- char *name;
+ char *name;
void *value = NULL;
struct posix_acl **p_acl;
size_t size;
int error;
- struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
+ struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
if (S_ISLNK(inode->i_mode))
return -EOPNOTSUPP;
- switch (type) {
- case ACL_TYPE_ACCESS:
- name = POSIX_ACL_XATTR_ACCESS;
- p_acl = &reiserfs_i->i_acl_access;
- if (acl) {
- mode_t mode = inode->i_mode;
- error = posix_acl_equiv_mode (acl, &mode);
- if (error < 0)
- return error;
- else {
- inode->i_mode = mode;
- if (error == 0)
- acl = NULL;
- }
- }
- break;
- case ACL_TYPE_DEFAULT:
- name = POSIX_ACL_XATTR_DEFAULT;
- p_acl = &reiserfs_i->i_acl_default;
- if (!S_ISDIR (inode->i_mode))
- return acl ? -EACCES : 0;
- break;
- default:
- return -EINVAL;
- }
-
- if (acl) {
- value = posix_acl_to_disk(acl, &size);
- if (IS_ERR(value))
- return (int)PTR_ERR(value);
- error = reiserfs_xattr_set(inode, name, value, size, 0);
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ name = POSIX_ACL_XATTR_ACCESS;
+ p_acl = &reiserfs_i->i_acl_access;
+ if (acl) {
+ mode_t mode = inode->i_mode;
+ error = posix_acl_equiv_mode(acl, &mode);
+ if (error < 0)
+ return error;
+ else {
+ inode->i_mode = mode;
+ if (error == 0)
+ acl = NULL;
+ }
+ }
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = POSIX_ACL_XATTR_DEFAULT;
+ p_acl = &reiserfs_i->i_acl_default;
+ if (!S_ISDIR(inode->i_mode))
+ return acl ? -EACCES : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (acl) {
+ value = posix_acl_to_disk(acl, &size);
+ if (IS_ERR(value))
+ return (int)PTR_ERR(value);
+ error = reiserfs_xattr_set(inode, name, value, size, 0);
} else {
- error = reiserfs_xattr_del (inode, name);
- if (error == -ENODATA) {
- /* This may seem odd here, but it means that the ACL was set
- * with a value representable with mode bits. If there was
- * an ACL before, reiserfs_xattr_del already dirtied the inode.
- */
- mark_inode_dirty (inode);
- error = 0;
- }
- }
+ error = reiserfs_xattr_del(inode, name);
+ if (error == -ENODATA) {
+ /* This may seem odd here, but it means that the ACL was set
+ * with a value representable with mode bits. If there was
+ * an ACL before, reiserfs_xattr_del already dirtied the inode.
+ */
+ mark_inode_dirty(inode);
+ error = 0;
+ }
+ }
if (value)
kfree(value);
- if (!error) {
- /* Release the old one */
- if (!IS_ERR (*p_acl) && *p_acl)
- posix_acl_release (*p_acl);
+ if (!error) {
+ /* Release the old one */
+ if (!IS_ERR(*p_acl) && *p_acl)
+ posix_acl_release(*p_acl);
- if (acl == NULL)
- *p_acl = ERR_PTR (-ENODATA);
- else
- *p_acl = posix_acl_dup (acl);
- }
+ if (acl == NULL)
+ *p_acl = ERR_PTR(-ENODATA);
+ else
+ *p_acl = posix_acl_dup(acl);
+ }
return error;
}
@@ -321,192 +316,190 @@ reiserfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
/* dir->i_sem: down,
* inode is new and not released into the wild yet */
int
-reiserfs_inherit_default_acl (struct inode *dir, struct dentry *dentry, struct inode *inode)
+reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
{
- struct posix_acl *acl;
- int err = 0;
-
- /* ACLs only get applied to files and directories */
- if (S_ISLNK (inode->i_mode))
- return 0;
-
- /* ACLs can only be used on "new" objects, so if it's an old object
- * there is nothing to inherit from */
- if (get_inode_sd_version (dir) == STAT_DATA_V1)
- goto apply_umask;
-
- /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
- * would be useless since permissions are ignored, and a pain because
- * it introduces locking cycles */
- if (is_reiserfs_priv_object (dir)) {
- reiserfs_mark_inode_private (inode);
- goto apply_umask;
- }
-
- acl = reiserfs_get_acl (dir, ACL_TYPE_DEFAULT);
- if (IS_ERR (acl)) {
- if (PTR_ERR (acl) == -ENODATA)
- goto apply_umask;
- return PTR_ERR (acl);
- }
-
- if (acl) {
- struct posix_acl *acl_copy;
- mode_t mode = inode->i_mode;
- int need_acl;
-
- /* Copy the default ACL to the default ACL of a new directory */
- if (S_ISDIR (inode->i_mode)) {
- err = reiserfs_set_acl (inode, ACL_TYPE_DEFAULT, acl);
- if (err)
- goto cleanup;
- }
-
- /* Now we reconcile the new ACL and the mode,
- potentially modifying both */
- acl_copy = posix_acl_clone (acl, GFP_NOFS);
- if (!acl_copy) {
- err = -ENOMEM;
- goto cleanup;
- }
-
-
- need_acl = posix_acl_create_masq (acl_copy, &mode);
- if (need_acl >= 0) {
- if (mode != inode->i_mode) {
- inode->i_mode = mode;
- }
-
- /* If we need an ACL.. */
- if (need_acl > 0) {
- err = reiserfs_set_acl (inode, ACL_TYPE_ACCESS, acl_copy);
- if (err)
- goto cleanup_copy;
- }
- }
-cleanup_copy:
- posix_acl_release (acl_copy);
-cleanup:
- posix_acl_release (acl);
- } else {
-apply_umask:
- /* no ACL, apply umask */
- inode->i_mode &= ~current->fs->umask;
- }
-
- return err;
+ struct posix_acl *acl;
+ int err = 0;
+
+ /* ACLs only get applied to files and directories */
+ if (S_ISLNK(inode->i_mode))
+ return 0;
+
+ /* ACLs can only be used on "new" objects, so if it's an old object
+ * there is nothing to inherit from */
+ if (get_inode_sd_version(dir) == STAT_DATA_V1)
+ goto apply_umask;
+
+ /* Don't apply ACLs to objects in the .reiserfs_priv tree.. This
+ * would be useless since permissions are ignored, and a pain because
+ * it introduces locking cycles */
+ if (is_reiserfs_priv_object(dir)) {
+ reiserfs_mark_inode_private(inode);
+ goto apply_umask;
+ }
+
+ acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl)) {
+ if (PTR_ERR(acl) == -ENODATA)
+ goto apply_umask;
+ return PTR_ERR(acl);
+ }
+
+ if (acl) {
+ struct posix_acl *acl_copy;
+ mode_t mode = inode->i_mode;
+ int need_acl;
+
+ /* Copy the default ACL to the default ACL of a new directory */
+ if (S_ISDIR(inode->i_mode)) {
+ err = reiserfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
+ if (err)
+ goto cleanup;
+ }
+
+ /* Now we reconcile the new ACL and the mode,
+ potentially modifying both */
+ acl_copy = posix_acl_clone(acl, GFP_NOFS);
+ if (!acl_copy) {
+ err = -ENOMEM;
+ goto cleanup;
+ }
+
+ need_acl = posix_acl_create_masq(acl_copy, &mode);
+ if (need_acl >= 0) {
+ if (mode != inode->i_mode) {
+ inode->i_mode = mode;
+ }
+
+ /* If we need an ACL.. */
+ if (need_acl > 0) {
+ err =
+ reiserfs_set_acl(inode, ACL_TYPE_ACCESS,
+ acl_copy);
+ if (err)
+ goto cleanup_copy;
+ }
+ }
+ cleanup_copy:
+ posix_acl_release(acl_copy);
+ cleanup:
+ posix_acl_release(acl);
+ } else {
+ apply_umask:
+ /* no ACL, apply umask */
+ inode->i_mode &= ~current->fs->umask;
+ }
+
+ return err;
}
/* Looks up and caches the result of the default ACL.
* We do this so that we don't need to carry the xattr_sem into
* reiserfs_new_inode if we don't need to */
-int
-reiserfs_cache_default_acl (struct inode *inode)
+int reiserfs_cache_default_acl(struct inode *inode)
{
- int ret = 0;
- if (reiserfs_posixacl (inode->i_sb) &&
- !is_reiserfs_priv_object (inode)) {
- struct posix_acl *acl;
- reiserfs_read_lock_xattr_i (inode);
- reiserfs_read_lock_xattrs (inode->i_sb);
- acl = reiserfs_get_acl (inode, ACL_TYPE_DEFAULT);
- reiserfs_read_unlock_xattrs (inode->i_sb);
- reiserfs_read_unlock_xattr_i (inode);
- ret = acl ? 1 : 0;
- posix_acl_release (acl);
- }
-
- return ret;
+ int ret = 0;
+ if (reiserfs_posixacl(inode->i_sb) && !is_reiserfs_priv_object(inode)) {
+ struct posix_acl *acl;
+ reiserfs_read_lock_xattr_i(inode);
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ acl = reiserfs_get_acl(inode, ACL_TYPE_DEFAULT);
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ reiserfs_read_unlock_xattr_i(inode);
+ ret = acl ? 1 : 0;
+ posix_acl_release(acl);
+ }
+
+ return ret;
}
-int
-reiserfs_acl_chmod (struct inode *inode)
+int reiserfs_acl_chmod(struct inode *inode)
{
- struct posix_acl *acl, *clone;
- int error;
+ struct posix_acl *acl, *clone;
+ int error;
- if (S_ISLNK(inode->i_mode))
- return -EOPNOTSUPP;
+ if (S_ISLNK(inode->i_mode))
+ return -EOPNOTSUPP;
- if (get_inode_sd_version (inode) == STAT_DATA_V1 ||
- !reiserfs_posixacl(inode->i_sb))
- {
- return 0;
+ if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
+ !reiserfs_posixacl(inode->i_sb)) {
+ return 0;
}
- reiserfs_read_lock_xattrs (inode->i_sb);
- acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
- reiserfs_read_unlock_xattrs (inode->i_sb);
- if (!acl)
- return 0;
- if (IS_ERR(acl))
- return PTR_ERR(acl);
- clone = posix_acl_clone(acl, GFP_NOFS);
- posix_acl_release(acl);
- if (!clone)
- return -ENOMEM;
- error = posix_acl_chmod_masq(clone, inode->i_mode);
- if (!error) {
- int lock = !has_xattr_dir (inode);
- reiserfs_write_lock_xattr_i (inode);
- if (lock)
- reiserfs_write_lock_xattrs (inode->i_sb);
- else
- reiserfs_read_lock_xattrs (inode->i_sb);
- error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
- if (lock)
- reiserfs_write_unlock_xattrs (inode->i_sb);
- else
- reiserfs_read_unlock_xattrs (inode->i_sb);
- reiserfs_write_unlock_xattr_i (inode);
- }
- posix_acl_release(clone);
- return error;
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ if (!acl)
+ return 0;
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ clone = posix_acl_clone(acl, GFP_NOFS);
+ posix_acl_release(acl);
+ if (!clone)
+ return -ENOMEM;
+ error = posix_acl_chmod_masq(clone, inode->i_mode);
+ if (!error) {
+ int lock = !has_xattr_dir(inode);
+ reiserfs_write_lock_xattr_i(inode);
+ if (lock)
+ reiserfs_write_lock_xattrs(inode->i_sb);
+ else
+ reiserfs_read_lock_xattrs(inode->i_sb);
+ error = reiserfs_set_acl(inode, ACL_TYPE_ACCESS, clone);
+ if (lock)
+ reiserfs_write_unlock_xattrs(inode->i_sb);
+ else
+ reiserfs_read_unlock_xattrs(inode->i_sb);
+ reiserfs_write_unlock_xattr_i(inode);
+ }
+ posix_acl_release(clone);
+ return error;
}
static int
posix_acl_access_get(struct inode *inode, const char *name,
- void *buffer, size_t size)
+ void *buffer, size_t size)
{
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
return -EINVAL;
return xattr_get_acl(inode, ACL_TYPE_ACCESS, buffer, size);
}
static int
posix_acl_access_set(struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
+ const void *value, size_t size, int flags)
{
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
return -EINVAL;
return xattr_set_acl(inode, ACL_TYPE_ACCESS, value, size);
}
-static int
-posix_acl_access_del (struct inode *inode, const char *name)
+static int posix_acl_access_del(struct inode *inode, const char *name)
{
- struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
- struct posix_acl **acl = &reiserfs_i->i_acl_access;
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS)-1)
- return -EINVAL;
- if (!IS_ERR (*acl) && *acl) {
- posix_acl_release (*acl);
- *acl = ERR_PTR (-ENODATA);
- }
-
- return 0;
+ struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
+ struct posix_acl **acl = &reiserfs_i->i_acl_access;
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_ACCESS) - 1)
+ return -EINVAL;
+ if (!IS_ERR(*acl) && *acl) {
+ posix_acl_release(*acl);
+ *acl = ERR_PTR(-ENODATA);
+ }
+
+ return 0;
}
static int
-posix_acl_access_list (struct inode *inode, const char *name, int namelen, char *out)
+posix_acl_access_list(struct inode *inode, const char *name, int namelen,
+ char *out)
{
- int len = namelen;
- if (!reiserfs_posixacl (inode->i_sb))
- return 0;
- if (out)
- memcpy (out, name, len);
+ int len = namelen;
+ if (!reiserfs_posixacl(inode->i_sb))
+ return 0;
+ if (out)
+ memcpy(out, name, len);
- return len;
+ return len;
}
struct reiserfs_xattr_handler posix_acl_access_handler = {
@@ -518,48 +511,48 @@ struct reiserfs_xattr_handler posix_acl_access_handler = {
};
static int
-posix_acl_default_get (struct inode *inode, const char *name,
- void *buffer, size_t size)
+posix_acl_default_get(struct inode *inode, const char *name,
+ void *buffer, size_t size)
{
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
return -EINVAL;
return xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
}
static int
posix_acl_default_set(struct inode *inode, const char *name,
- const void *value, size_t size, int flags)
+ const void *value, size_t size, int flags)
{
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
return -EINVAL;
return xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
}
-static int
-posix_acl_default_del (struct inode *inode, const char *name)
+static int posix_acl_default_del(struct inode *inode, const char *name)
{
- struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
- struct posix_acl **acl = &reiserfs_i->i_acl_default;
- if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT)-1)
- return -EINVAL;
- if (!IS_ERR (*acl) && *acl) {
- posix_acl_release (*acl);
- *acl = ERR_PTR (-ENODATA);
- }
-
- return 0;
+ struct reiserfs_inode_info *reiserfs_i = REISERFS_I(inode);
+ struct posix_acl **acl = &reiserfs_i->i_acl_default;
+ if (strlen(name) != sizeof(POSIX_ACL_XATTR_DEFAULT) - 1)
+ return -EINVAL;
+ if (!IS_ERR(*acl) && *acl) {
+ posix_acl_release(*acl);
+ *acl = ERR_PTR(-ENODATA);
+ }
+
+ return 0;
}
static int
-posix_acl_default_list (struct inode *inode, const char *name, int namelen, char *out)
+posix_acl_default_list(struct inode *inode, const char *name, int namelen,
+ char *out)
{
- int len = namelen;
- if (!reiserfs_posixacl (inode->i_sb))
- return 0;
- if (out)
- memcpy (out, name, len);
+ int len = namelen;
+ if (!reiserfs_posixacl(inode->i_sb))
+ return 0;
+ if (out)
+ memcpy(out, name, len);
- return len;
+ return len;
}
struct reiserfs_xattr_handler posix_acl_default_handler = {
diff --git a/fs/reiserfs/xattr_security.c b/fs/reiserfs/xattr_security.c
index e044d5117117..5e90a95ad60b 100644
--- a/fs/reiserfs/xattr_security.c
+++ b/fs/reiserfs/xattr_security.c
@@ -9,57 +9,55 @@
#define XATTR_SECURITY_PREFIX "security."
static int
-security_get (struct inode *inode, const char *name, void *buffer, size_t size)
+security_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
- if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
+ return -EINVAL;
- if (is_reiserfs_priv_object(inode))
- return -EPERM;
+ if (is_reiserfs_priv_object(inode))
+ return -EPERM;
- return reiserfs_xattr_get (inode, name, buffer, size);
+ return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
-security_set (struct inode *inode, const char *name, const void *buffer,
- size_t size, int flags)
+security_set(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
{
- if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
+ return -EINVAL;
- if (is_reiserfs_priv_object(inode))
- return -EPERM;
+ if (is_reiserfs_priv_object(inode))
+ return -EPERM;
- return reiserfs_xattr_set (inode, name, buffer, size, flags);
+ return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
-static int
-security_del (struct inode *inode, const char *name)
+static int security_del(struct inode *inode, const char *name)
{
- if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_SECURITY_PREFIX))
+ return -EINVAL;
- if (is_reiserfs_priv_object(inode))
- return -EPERM;
+ if (is_reiserfs_priv_object(inode))
+ return -EPERM;
- return 0;
+ return 0;
}
static int
-security_list (struct inode *inode, const char *name, int namelen, char *out)
+security_list(struct inode *inode, const char *name, int namelen, char *out)
{
- int len = namelen;
+ int len = namelen;
- if (is_reiserfs_priv_object(inode))
- return 0;
+ if (is_reiserfs_priv_object(inode))
+ return 0;
- if (out)
- memcpy (out, name, len);
+ if (out)
+ memcpy(out, name, len);
- return len;
+ return len;
}
-
struct reiserfs_xattr_handler security_handler = {
.prefix = XATTR_SECURITY_PREFIX,
.get = security_get,
diff --git a/fs/reiserfs/xattr_trusted.c b/fs/reiserfs/xattr_trusted.c
index 43762197fb0a..2501f7e66ab9 100644
--- a/fs/reiserfs/xattr_trusted.c
+++ b/fs/reiserfs/xattr_trusted.c
@@ -9,69 +9,67 @@
#define XATTR_TRUSTED_PREFIX "trusted."
static int
-trusted_get (struct inode *inode, const char *name, void *buffer, size_t size)
+trusted_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
- if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs(inode->i_sb))
+ return -EOPNOTSUPP;
- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
- return -EPERM;
+ if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+ return -EPERM;
- return reiserfs_xattr_get (inode, name, buffer, size);
+ return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
-trusted_set (struct inode *inode, const char *name, const void *buffer,
- size_t size, int flags)
+trusted_set(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
{
- if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs(inode->i_sb))
+ return -EOPNOTSUPP;
- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
- return -EPERM;
+ if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+ return -EPERM;
- return reiserfs_xattr_set (inode, name, buffer, size, flags);
+ return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
-static int
-trusted_del (struct inode *inode, const char *name)
+static int trusted_del(struct inode *inode, const char *name)
{
- if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_TRUSTED_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs(inode->i_sb))
+ return -EOPNOTSUPP;
- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
- return -EPERM;
+ if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+ return -EPERM;
- return 0;
+ return 0;
}
static int
-trusted_list (struct inode *inode, const char *name, int namelen, char *out)
+trusted_list(struct inode *inode, const char *name, int namelen, char *out)
{
- int len = namelen;
+ int len = namelen;
- if (!reiserfs_xattrs (inode->i_sb))
- return 0;
+ if (!reiserfs_xattrs(inode->i_sb))
+ return 0;
- if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
- return 0;
+ if (!(capable(CAP_SYS_ADMIN) || is_reiserfs_priv_object(inode)))
+ return 0;
- if (out)
- memcpy (out, name, len);
+ if (out)
+ memcpy(out, name, len);
- return len;
+ return len;
}
-
struct reiserfs_xattr_handler trusted_handler = {
.prefix = XATTR_TRUSTED_PREFIX,
.get = trusted_get,
diff --git a/fs/reiserfs/xattr_user.c b/fs/reiserfs/xattr_user.c
index 0772806466a8..51458048ca66 100644
--- a/fs/reiserfs/xattr_user.c
+++ b/fs/reiserfs/xattr_user.c
@@ -13,81 +13,80 @@
#define XATTR_USER_PREFIX "user."
static int
-user_get (struct inode *inode, const char *name, void *buffer, size_t size)
+user_get(struct inode *inode, const char *name, void *buffer, size_t size)
{
- int error;
+ int error;
- if (strlen(name) < sizeof(XATTR_USER_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_USER_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs_user (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs_user(inode->i_sb))
+ return -EOPNOTSUPP;
- error = reiserfs_permission_locked (inode, MAY_READ, NULL);
- if (error)
- return error;
+ error = reiserfs_permission_locked(inode, MAY_READ, NULL);
+ if (error)
+ return error;
- return reiserfs_xattr_get (inode, name, buffer, size);
+ return reiserfs_xattr_get(inode, name, buffer, size);
}
static int
-user_set (struct inode *inode, const char *name, const void *buffer,
- size_t size, int flags)
+user_set(struct inode *inode, const char *name, const void *buffer,
+ size_t size, int flags)
{
- int error;
+ int error;
- if (strlen(name) < sizeof(XATTR_USER_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_USER_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs_user (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs_user(inode->i_sb))
+ return -EOPNOTSUPP;
- if (!S_ISREG (inode->i_mode) &&
- (!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
- return -EPERM;
+ if (!S_ISREG(inode->i_mode) &&
+ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+ return -EPERM;
- error = reiserfs_permission_locked (inode, MAY_WRITE, NULL);
- if (error)
- return error;
+ error = reiserfs_permission_locked(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
- return reiserfs_xattr_set (inode, name, buffer, size, flags);
+ return reiserfs_xattr_set(inode, name, buffer, size, flags);
}
-static int
-user_del (struct inode *inode, const char *name)
+static int user_del(struct inode *inode, const char *name)
{
- int error;
+ int error;
- if (strlen(name) < sizeof(XATTR_USER_PREFIX))
- return -EINVAL;
+ if (strlen(name) < sizeof(XATTR_USER_PREFIX))
+ return -EINVAL;
- if (!reiserfs_xattrs_user (inode->i_sb))
- return -EOPNOTSUPP;
+ if (!reiserfs_xattrs_user(inode->i_sb))
+ return -EOPNOTSUPP;
- if (!S_ISREG (inode->i_mode) &&
- (!S_ISDIR (inode->i_mode) || inode->i_mode & S_ISVTX))
- return -EPERM;
+ if (!S_ISREG(inode->i_mode) &&
+ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX))
+ return -EPERM;
- error = reiserfs_permission_locked (inode, MAY_WRITE, NULL);
- if (error)
- return error;
+ error = reiserfs_permission_locked(inode, MAY_WRITE, NULL);
+ if (error)
+ return error;
- return 0;
+ return 0;
}
static int
-user_list (struct inode *inode, const char *name, int namelen, char *out)
+user_list(struct inode *inode, const char *name, int namelen, char *out)
{
- int len = namelen;
- if (!reiserfs_xattrs_user (inode->i_sb))
- return 0;
+ int len = namelen;
+ if (!reiserfs_xattrs_user(inode->i_sb))
+ return 0;
- if (out)
- memcpy (out, name, len);
+ if (out)
+ memcpy(out, name, len);
- return len;
+ return len;
}
struct reiserfs_xattr_handler user_handler = {
diff --git a/fs/super.c b/fs/super.c
index 25bc1ec6bc5d..6e57ee252e14 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -840,7 +840,6 @@ do_kern_mount(const char *fstype, int flags, const char *name, void *data)
mnt->mnt_root = dget(sb->s_root);
mnt->mnt_mountpoint = sb->s_root;
mnt->mnt_parent = mnt;
- mnt->mnt_namespace = current->namespace;
up_write(&sb->s_umount);
free_secdata(secdata);
put_filesystem(type);
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index e9cfa39f4099..335288b9be0f 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -3,7 +3,7 @@
*/
#include <linux/module.h>
-#include <linux/dnotify.h>
+#include <linux/fsnotify.h>
#include <linux/kobject.h>
#include <linux/namei.h>
#include <asm/uaccess.h>
@@ -14,7 +14,7 @@
#define to_subsys(k) container_of(k,struct subsystem,kset.kobj)
#define to_sattr(a) container_of(a,struct subsys_attribute,attr)
-/**
+/*
* Subsystem file operations.
* These operations allow subsystems to have files that can be
* read/written.
@@ -192,8 +192,9 @@ fill_write_buffer(struct sysfs_buffer * buffer, const char __user * buf, size_t
/**
* flush_write_buffer - push buffer to kobject.
- * @file: file pointer.
+ * @dentry: dentry to the attribute
* @buffer: data buffer for file.
+ * @count: number of bytes
*
* Get the correct pointers for the kobject and the attribute we're
* dealing with, then call the store() method for the attribute,
@@ -390,9 +391,6 @@ int sysfs_create_file(struct kobject * kobj, const struct attribute * attr)
* sysfs_update_file - update the modified timestamp on an object attribute.
* @kobj: object we're acting for.
* @attr: attribute descriptor.
- *
- * Also call dnotify for the dentry, which lots of userspace programs
- * use.
*/
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
{
@@ -407,7 +405,7 @@ int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
if (victim->d_inode &&
(victim->d_parent->d_inode == dir->d_inode)) {
victim->d_inode->i_mtime = CURRENT_TIME;
- dnotify_parent(victim, DN_MODIFY);
+ fsnotify_modify(victim);
/**
* Drop reference from initial sysfs_get_dentry().
diff --git a/fs/udf/namei.c b/fs/udf/namei.c
index 3f6dc7112bc6..ac191ed7df0a 100644
--- a/fs/udf/namei.c
+++ b/fs/udf/namei.c
@@ -159,14 +159,12 @@ udf_find_entry(struct inode *dir, struct dentry *dentry,
char *nameptr;
uint8_t lfi;
uint16_t liu;
- loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
+ loff_t size;
kernel_lb_addr bloc, eloc;
uint32_t extoffset, elen, offset;
struct buffer_head *bh = NULL;
- if (!dir)
- return NULL;
-
+ size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
f_pos = (udf_ext0_offset(dir) >> 2);
fibh->soffset = fibh->eoffset = (f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
diff --git a/fs/xattr.c b/fs/xattr.c
index 93dee70a1dbe..6acd5c63da91 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -16,6 +16,7 @@
#include <linux/security.h>
#include <linux/syscalls.h>
#include <linux/module.h>
+#include <linux/fsnotify.h>
#include <asm/uaccess.h>
/*
@@ -57,8 +58,10 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
if (error)
goto out;
error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
- if (!error)
+ if (!error) {
+ fsnotify_xattr(d);
security_inode_post_setxattr(d, kname, kvalue, size, flags);
+ }
out:
up(&d->d_inode->i_sem);
}
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c
index 93ce257cd149..a3a4b5aaf5d9 100644
--- a/fs/xfs/linux-2.6/xfs_aops.c
+++ b/fs/xfs/linux-2.6/xfs_aops.c
@@ -149,11 +149,12 @@ linvfs_unwritten_convert(
*/
STATIC void
linvfs_unwritten_convert_direct(
- struct inode *inode,
+ struct kiocb *iocb,
loff_t offset,
ssize_t size,
void *private)
{
+ struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
ASSERT(!private || inode == (struct inode *)private);
/* private indicates an unwritten extent lay beneath this IO */
diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c
index c60e69431e11..df0cba239dd5 100644
--- a/fs/xfs/linux-2.6/xfs_buf.c
+++ b/fs/xfs/linux-2.6/xfs_buf.c
@@ -1771,9 +1771,9 @@ xfsbufd(
INIT_LIST_HEAD(&tmp);
do {
- if (unlikely(current->flags & PF_FREEZE)) {
+ if (unlikely(freezing(current))) {
xfsbufd_force_sleep = 1;
- refrigerator(PF_FREEZE);
+ refrigerator();
} else {
xfsbufd_force_sleep = 0;
}
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c
index 5fe9af38aa20..f6dd7de25927 100644
--- a/fs/xfs/linux-2.6/xfs_super.c
+++ b/fs/xfs/linux-2.6/xfs_super.c
@@ -483,7 +483,7 @@ xfssyncd(
set_current_state(TASK_INTERRUPTIBLE);
timeleft = schedule_timeout(timeleft);
/* swsusp */
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
if (vfsp->vfs_flag & VFS_UMOUNT)
break;
diff --git a/include/acpi/acconfig.h b/include/acpi/acconfig.h
index 2b41e47b7d80..2f6ab189fc6f 100644
--- a/include/acpi/acconfig.h
+++ b/include/acpi/acconfig.h
@@ -64,7 +64,7 @@
/* Version string */
-#define ACPI_CA_VERSION 0x20050309
+#define ACPI_CA_VERSION 0x20050408
/*
* OS name, used for the _OS object. The _OS object is essentially obsolete,
@@ -130,9 +130,8 @@
#define ACPI_MAX_GPE_BLOCKS 2
#define ACPI_GPE_REGISTER_WIDTH 8
-/*
- * Method info (in WALK_STATE), containing local variables and argumetns
- */
+/* Method info (in WALK_STATE), containing local variables and argumetns */
+
#define ACPI_METHOD_NUM_LOCALS 8
#define ACPI_METHOD_MAX_LOCAL 7
diff --git a/include/acpi/acdebug.h b/include/acpi/acdebug.h
index 223b2a506e49..8ba372b0f245 100644
--- a/include/acpi/acdebug.h
+++ b/include/acpi/acdebug.h
@@ -61,9 +61,7 @@ struct argument_info
#define PARAM_LIST(pl) pl
-
#define DBTEST_OUTPUT_LEVEL(lvl) if (acpi_gbl_db_opt_verbose)
-
#define VERBOSE_PRINT(fp) DBTEST_OUTPUT_LEVEL(lvl) {\
acpi_os_printf PARAM_LIST(fp);}
@@ -71,13 +69,9 @@ struct argument_info
#define EX_SINGLE_STEP 2
-/* Prototypes */
-
-
/*
* dbxface - external debugger interfaces
*/
-
acpi_status
acpi_db_initialize (
void);
@@ -92,20 +86,10 @@ acpi_db_single_step (
union acpi_parse_object *op,
u32 op_type);
-acpi_status
-acpi_db_start_command (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op);
-
-void
-acpi_db_method_end (
- struct acpi_walk_state *walk_state);
-
/*
* dbcmds - debug commands and output routines
*/
-
acpi_status
acpi_db_disassemble_method (
char *name);
@@ -177,57 +161,30 @@ acpi_db_find_references (
char *object_arg);
void
-acpi_db_display_locks (void);
-
+acpi_db_display_locks (
+ void);
void
acpi_db_display_resources (
char *object_arg);
void
-acpi_db_display_gpes (void);
+acpi_db_display_gpes (
+ void);
void
acpi_db_check_integrity (
void);
-acpi_status
-acpi_db_integrity_walk (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
-acpi_status
-acpi_db_walk_and_match_name (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
-acpi_status
-acpi_db_walk_for_references (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
-acpi_status
-acpi_db_walk_for_specific_objects (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
void
acpi_db_generate_gpe (
char *gpe_arg,
char *block_arg);
+
/*
* dbdisply - debug display commands
*/
-
void
acpi_db_display_method_info (
union acpi_parse_object *op);
@@ -271,19 +228,10 @@ acpi_db_display_argument_object (
union acpi_operand_object *obj_desc,
struct acpi_walk_state *walk_state);
-void
-acpi_db_dump_parser_descriptor (
- union acpi_parse_object *op);
-
-void *
-acpi_db_get_pointer (
- void *target);
-
/*
* dbexec - debugger control method execution
*/
-
void
acpi_db_execute (
char *name,
@@ -296,44 +244,15 @@ acpi_db_create_execution_threads (
char *num_loops_arg,
char *method_name_arg);
-acpi_status
-acpi_db_execute_method (
- struct acpi_db_method_info *info,
- struct acpi_buffer *return_obj);
-
-void
-acpi_db_execute_setup (
- struct acpi_db_method_info *info);
-
-u32
-acpi_db_get_outstanding_allocations (
- void);
-
-void ACPI_SYSTEM_XFACE
-acpi_db_method_thread (
- void *context);
-
-acpi_status
-acpi_db_execution_walk (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
/*
* dbfileio - Debugger file I/O commands
*/
-
acpi_object_type
acpi_db_match_argument (
char *user_argument,
struct argument_info *arguments);
-acpi_status
-ae_local_load_table (
- struct acpi_table_header *table_ptr);
-
void
acpi_db_close_debug_file (
void);
@@ -356,16 +275,17 @@ acpi_db_read_table_from_file (
char *filename,
struct acpi_table_header **table);
+
/*
* dbhistry - debugger HISTORY command
*/
-
void
acpi_db_add_to_history (
char *command_line);
void
-acpi_db_display_history (void);
+acpi_db_display_history (
+ void);
char *
acpi_db_get_from_history (
@@ -375,7 +295,6 @@ acpi_db_get_from_history (
/*
* dbinput - user front-end to the AML debugger
*/
-
acpi_status
acpi_db_command_dispatch (
char *input_buffer,
@@ -386,71 +305,28 @@ void ACPI_SYSTEM_XFACE
acpi_db_execute_thread (
void *context);
-void
-acpi_db_display_help (
- char *help_type);
-
-char *
-acpi_db_get_next_token (
- char *string,
- char **next);
-
-u32
-acpi_db_get_line (
- char *input_buffer);
-
-u32
-acpi_db_match_command (
- char *user_command);
-
-void
-acpi_db_single_thread (
- void);
-
/*
* dbstats - Generation and display of ACPI table statistics
*/
-
void
acpi_db_generate_statistics (
union acpi_parse_object *root,
u8 is_method);
-
acpi_status
acpi_db_display_statistics (
char *type_arg);
-acpi_status
-acpi_db_classify_one_object (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
-
-void
-acpi_db_count_namespace_objects (
- void);
-
-void
-acpi_db_enumerate_object (
- union acpi_operand_object *obj_desc);
-
/*
* dbutils - AML debugger utilities
*/
-
void
acpi_db_set_output_destination (
u32 where);
void
-acpi_db_dump_buffer (
- u32 address);
-
-void
acpi_db_dump_object (
union acpi_object *obj_desc,
u32 level);
@@ -459,14 +335,8 @@ void
acpi_db_prep_namestring (
char *name);
-
-acpi_status
-acpi_db_second_pass_parse (
- union acpi_parse_object *root);
-
struct acpi_namespace_node *
acpi_db_local_ns_lookup (
char *name);
-
#endif /* __ACDEBUG_H__ */
diff --git a/include/acpi/acdisasm.h b/include/acpi/acdisasm.h
index 26d907eae6fe..dbfa877121ba 100644
--- a/include/acpi/acdisasm.h
+++ b/include/acpi/acdisasm.h
@@ -102,58 +102,16 @@ acpi_status (*asl_walk_callback) (
/*
* dmwalk
*/
-
-void
-acpi_dm_walk_parse_tree (
- union acpi_parse_object *op,
- asl_walk_callback descending_callback,
- asl_walk_callback ascending_callback,
- void *context);
-
-acpi_status
-acpi_dm_descending_op (
- union acpi_parse_object *op,
- u32 level,
- void *context);
-
-acpi_status
-acpi_dm_ascending_op (
- union acpi_parse_object *op,
- u32 level,
- void *context);
-
-
-/*
- * dmopcode
- */
-
-void
-acpi_dm_validate_name (
- char *name,
- union acpi_parse_object *op);
-
-u32
-acpi_dm_dump_name (
- char *name);
-
-void
-acpi_dm_unicode (
- union acpi_parse_object *op);
-
void
acpi_dm_disassemble (
struct acpi_walk_state *walk_state,
union acpi_parse_object *origin,
u32 num_opcodes);
-void
-acpi_dm_namestring (
- char *name);
-
-void
-acpi_dm_display_path (
- union acpi_parse_object *op);
+/*
+ * dmopcode
+ */
void
acpi_dm_disassemble_one_op (
struct acpi_walk_state *walk_state,
@@ -165,18 +123,9 @@ acpi_dm_decode_internal_object (
union acpi_operand_object *obj_desc);
u32
-acpi_dm_block_type (
- union acpi_parse_object *op);
-
-u32
acpi_dm_list_type (
union acpi_parse_object *op);
-acpi_status
-acpi_ps_display_object_pathname (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op);
-
void
acpi_dm_method_flags (
union acpi_parse_object *op);
@@ -197,10 +146,6 @@ void
acpi_dm_match_op (
union acpi_parse_object *op);
-void
-acpi_dm_match_keyword (
- union acpi_parse_object *op);
-
u8
acpi_dm_comma_if_list_member (
union acpi_parse_object *op);
@@ -211,13 +156,25 @@ acpi_dm_comma_if_field_member (
/*
- * dmobject
+ * dmnames
*/
+u32
+acpi_dm_dump_name (
+ char *name);
+
+acpi_status
+acpi_ps_display_object_pathname (
+ struct acpi_walk_state *walk_state,
+ union acpi_parse_object *op);
void
-acpi_dm_decode_node (
- struct acpi_namespace_node *node);
+acpi_dm_namestring (
+ char *name);
+
+/*
+ * dmobject
+ */
void
acpi_dm_display_internal_object (
union acpi_operand_object *obj_desc,
@@ -241,6 +198,16 @@ acpi_dm_dump_method_info (
/*
* dmbuffer
*/
+void
+acpi_dm_disasm_byte_list (
+ u32 level,
+ u8 *byte_data,
+ u32 byte_count);
+
+void
+acpi_dm_byte_list (
+ struct acpi_op_walk_info *info,
+ union acpi_parse_object *op);
void
acpi_is_eisa_id (
@@ -262,18 +229,6 @@ acpi_dm_is_string_buffer (
/*
* dmresrc
*/
-
-void
-acpi_dm_disasm_byte_list (
- u32 level,
- u8 *byte_data,
- u32 byte_count);
-
-void
-acpi_dm_byte_list (
- struct acpi_op_walk_info *info,
- union acpi_parse_object *op);
-
void
acpi_dm_resource_descriptor (
struct acpi_op_walk_info *info,
@@ -296,19 +251,10 @@ void
acpi_dm_decode_attribute (
u8 attribute);
+
/*
* dmresrcl
*/
-
-void
-acpi_dm_io_flags (
- u8 flags);
-
-void
-acpi_dm_memory_flags (
- u8 flags,
- u8 specific_flags);
-
void
acpi_dm_word_descriptor (
struct asl_word_address_desc *resource,
@@ -373,7 +319,6 @@ acpi_dm_vendor_large_descriptor (
/*
* dmresrcs
*/
-
void
acpi_dm_irq_descriptor (
struct asl_irq_format_desc *resource,
@@ -420,7 +365,6 @@ acpi_dm_vendor_small_descriptor (
/*
* dmutils
*/
-
void
acpi_dm_add_to_external_list (
char *path);
diff --git a/include/acpi/acdispat.h b/include/acpi/acdispat.h
index 237d63433581..8f5f2f71b1de 100644
--- a/include/acpi/acdispat.h
+++ b/include/acpi/acdispat.h
@@ -50,40 +50,9 @@
#define NAMEOF_ARG_NTE "__A0"
-/* Common interfaces */
-
-acpi_status
-acpi_ds_obj_stack_push (
- void *object,
- struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ds_obj_stack_pop (
- u32 pop_count,
- struct acpi_walk_state *walk_state);
-
-#ifdef ACPI_FUTURE_USAGE
-void *
-acpi_ds_obj_stack_get_value (
- u32 index,
- struct acpi_walk_state *walk_state);
-#endif
-
-acpi_status
-acpi_ds_obj_stack_pop_object (
- union acpi_operand_object **object,
- struct acpi_walk_state *walk_state);
-
-
-/* dsopcode - support for late evaluation */
-
-acpi_status
-acpi_ds_execute_arguments (
- struct acpi_namespace_node *node,
- struct acpi_namespace_node *scope_node,
- u32 aml_length,
- u8 *aml_start);
-
+/*
+ * dsopcode - support for late evaluation
+ */
acpi_status
acpi_ds_get_buffer_field_arguments (
union acpi_operand_object *obj_desc);
@@ -101,15 +70,6 @@ acpi_ds_get_package_arguments (
union acpi_operand_object *obj_desc);
acpi_status
-acpi_ds_init_buffer_field (
- u16 aml_opcode,
- union acpi_operand_object *obj_desc,
- union acpi_operand_object *buffer_desc,
- union acpi_operand_object *offset_desc,
- union acpi_operand_object *length_desc,
- union acpi_operand_object *result_desc);
-
-acpi_status
acpi_ds_eval_buffer_field_operands (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op);
@@ -130,9 +90,9 @@ acpi_ds_initialize_region (
acpi_handle obj_handle);
-/* dsctrl - Parser/Interpreter interface, control stack routines */
-
-
+/*
+ * dsctrl - Parser/Interpreter interface, control stack routines
+ */
acpi_status
acpi_ds_exec_begin_control_op (
struct acpi_walk_state *walk_state,
@@ -144,9 +104,9 @@ acpi_ds_exec_end_control_op (
union acpi_parse_object *op);
-/* dsexec - Parser/Interpreter interface, method execution callbacks */
-
-
+/*
+ * dsexec - Parser/Interpreter interface, method execution callbacks
+ */
acpi_status
acpi_ds_get_predicate_value (
struct acpi_walk_state *walk_state,
@@ -162,14 +122,9 @@ acpi_ds_exec_end_op (
struct acpi_walk_state *state);
-/* dsfield - Parser/Interpreter interface for AML fields */
-
-acpi_status
-acpi_ds_get_field_names (
- struct acpi_create_field_info *info,
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *arg);
-
+/*
+ * dsfield - Parser/Interpreter interface for AML fields
+ */
acpi_status
acpi_ds_create_field (
union acpi_parse_object *op,
@@ -199,8 +154,9 @@ acpi_ds_init_field_objects (
struct acpi_walk_state *walk_state);
-/* dsload - Parser/Interpreter interface, namespace load callbacks */
-
+/*
+ * dsload - Parser/Interpreter interface, namespace load callbacks
+ */
acpi_status
acpi_ds_load1_begin_op (
struct acpi_walk_state *walk_state,
@@ -225,9 +181,9 @@ acpi_ds_init_callbacks (
u32 pass_number);
-/* dsmthdat - method data (locals/args) */
-
-
+/*
+ * dsmthdat - method data (locals/args)
+ */
acpi_status
acpi_ds_store_object_to_local (
u16 opcode,
@@ -250,14 +206,6 @@ u8
acpi_ds_is_method_value (
union acpi_operand_object *obj_desc);
-#ifdef ACPI_FUTURE_USAGE
-acpi_object_type
-acpi_ds_method_data_get_type (
- u16 opcode,
- u32 index,
- struct acpi_walk_state *walk_state);
-#endif
-
acpi_status
acpi_ds_method_data_get_value (
u16 opcode,
@@ -265,12 +213,6 @@ acpi_ds_method_data_get_value (
struct acpi_walk_state *walk_state,
union acpi_operand_object **dest_desc);
-void
-acpi_ds_method_data_delete_value (
- u16 opcode,
- u32 index,
- struct acpi_walk_state *walk_state);
-
acpi_status
acpi_ds_method_data_init_args (
union acpi_operand_object **params,
@@ -288,16 +230,10 @@ void
acpi_ds_method_data_init (
struct acpi_walk_state *walk_state);
-acpi_status
-acpi_ds_method_data_set_value (
- u16 opcode,
- u32 index,
- union acpi_operand_object *object,
- struct acpi_walk_state *walk_state);
-
-
-/* dsmethod - Parser/Interpreter interface - control method parsing */
+/*
+ * dsmethod - Parser/Interpreter interface - control method parsing
+ */
acpi_status
acpi_ds_parse_method (
acpi_handle obj_handle);
@@ -324,20 +260,18 @@ acpi_ds_begin_method_execution (
struct acpi_namespace_node *calling_method_node);
-/* dsobj - Parser/Interpreter interface - object initialization and conversion */
-
-acpi_status
-acpi_ds_init_one_object (
- acpi_handle obj_handle,
- u32 level,
- void *context,
- void **return_value);
-
+/*
+ * dsinit
+ */
acpi_status
acpi_ds_initialize_objects (
struct acpi_table_desc *table_desc,
struct acpi_namespace_node *start_node);
+
+/*
+ * dsobject - Parser/Interpreter interface - object initialization and conversion
+ */
acpi_status
acpi_ds_build_internal_buffer_obj (
struct acpi_walk_state *walk_state,
@@ -353,12 +287,6 @@ acpi_ds_build_internal_package_obj (
union acpi_operand_object **obj_desc);
acpi_status
-acpi_ds_build_internal_object (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op,
- union acpi_operand_object **obj_desc_ptr);
-
-acpi_status
acpi_ds_init_object_from_op (
struct acpi_walk_state *walk_state,
union acpi_parse_object *op,
@@ -372,8 +300,9 @@ acpi_ds_create_node (
union acpi_parse_object *op);
-/* dsutils - Parser/Interpreter interface utility routines */
-
+/*
+ * dsutils - Parser/Interpreter interface utility routines
+ */
void
acpi_ds_clear_implicit_return (
struct acpi_walk_state *walk_state);
@@ -418,7 +347,6 @@ acpi_ds_clear_operands (
/*
* dswscope - Scope Stack manipulation
*/
-
acpi_status
acpi_ds_scope_stack_push (
struct acpi_namespace_node *node,
@@ -435,7 +363,18 @@ acpi_ds_scope_stack_clear (
struct acpi_walk_state *walk_state);
-/* dswstate - parser WALK_STATE management routines */
+/*
+ * dswstate - parser WALK_STATE management routines
+ */
+acpi_status
+acpi_ds_obj_stack_push (
+ void *object,
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ds_obj_stack_pop (
+ u32 pop_count,
+ struct acpi_walk_state *walk_state);
struct acpi_walk_state *
acpi_ds_create_walk_state (
@@ -454,12 +393,6 @@ acpi_ds_init_aml_walk (
struct acpi_parameter_info *info,
u32 pass_number);
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ds_obj_stack_delete_all (
- struct acpi_walk_state *walk_state);
-#endif
-
acpi_status
acpi_ds_obj_stack_pop_and_delete (
u32 pop_count,
@@ -494,20 +427,8 @@ struct acpi_walk_state *
acpi_ds_get_current_walk_state (
struct acpi_thread_state *thread);
-#ifdef ACPI_ENABLE_OBJECT_CACHE
-void
-acpi_ds_delete_walk_state_cache (
- void);
-#endif
-
#ifdef ACPI_FUTURE_USAGE
acpi_status
-acpi_ds_result_insert (
- void *object,
- u32 index,
- struct acpi_walk_state *walk_state);
-
-acpi_status
acpi_ds_result_remove (
union acpi_operand_object **object,
u32 index,
@@ -529,4 +450,10 @@ acpi_ds_result_pop_from_bottom (
union acpi_operand_object **object,
struct acpi_walk_state *walk_state);
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+void
+acpi_ds_delete_walk_state_cache (
+ void);
+#endif
+
#endif /* _ACDISPAT_H_ */
diff --git a/include/acpi/acevents.h b/include/acpi/acevents.h
index 2dec083ba1cd..61a27c8c5079 100644
--- a/include/acpi/acevents.h
+++ b/include/acpi/acevents.h
@@ -45,6 +45,9 @@
#define __ACEVENTS_H__
+/*
+ * evevent
+ */
acpi_status
acpi_ev_initialize_events (
void);
@@ -53,28 +56,14 @@ acpi_status
acpi_ev_install_xrupt_handlers (
void);
-
-/*
- * Evfixed - Fixed event handling
- */
-
-acpi_status
-acpi_ev_fixed_event_initialize (
- void);
-
u32
acpi_ev_fixed_event_detect (
void);
-u32
-acpi_ev_fixed_event_dispatch (
- u32 event);
-
/*
- * Evmisc
+ * evmisc
*/
-
u8
acpi_ev_is_notify_object (
struct acpi_namespace_node *node);
@@ -100,24 +89,10 @@ acpi_ev_queue_notify_request (
struct acpi_namespace_node *node,
u32 notify_value);
-void ACPI_SYSTEM_XFACE
-acpi_ev_notify_dispatch (
- void *context);
-
/*
- * Evgpe - GPE handling and dispatch
+ * evgpe - GPE handling and dispatch
*/
-
-acpi_status
-acpi_ev_walk_gpe_list (
- ACPI_GPE_CALLBACK gpe_walk_callback,
- u32 flags);
-
-u8
-acpi_ev_valid_gpe_event (
- struct acpi_gpe_event_info *gpe_event_info);
-
acpi_status
acpi_ev_update_gpe_enable_masks (
struct acpi_gpe_event_info *gpe_event_info,
@@ -137,9 +112,23 @@ acpi_ev_get_gpe_event_info (
acpi_handle gpe_device,
u32 gpe_number);
+
+/*
+ * evgpeblk
+ */
+u8
+acpi_ev_valid_gpe_event (
+ struct acpi_gpe_event_info *gpe_event_info);
+
acpi_status
-acpi_ev_gpe_initialize (
- void);
+acpi_ev_walk_gpe_list (
+ ACPI_GPE_CALLBACK gpe_walk_callback,
+ u32 flags);
+
+acpi_status
+acpi_ev_delete_gpe_handlers (
+ struct acpi_gpe_xrupt_info *gpe_xrupt_info,
+ struct acpi_gpe_block_info *gpe_block);
acpi_status
acpi_ev_create_gpe_block (
@@ -154,11 +143,6 @@ acpi_status
acpi_ev_delete_gpe_block (
struct acpi_gpe_block_info *gpe_block);
-acpi_status
-acpi_ev_delete_gpe_handlers (
- struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block);
-
u32
acpi_ev_gpe_dispatch (
struct acpi_gpe_event_info *gpe_event_info,
@@ -177,10 +161,14 @@ acpi_status
acpi_ev_check_for_wake_only_gpe (
struct acpi_gpe_event_info *gpe_event_info);
+acpi_status
+acpi_ev_gpe_initialize (
+ void);
+
+
/*
- * Evregion - Address Space handling
+ * evregion - Address Space handling
*/
-
acpi_status
acpi_ev_install_region_handlers (
void);
@@ -198,13 +186,6 @@ acpi_ev_address_space_dispatch (
void *value);
acpi_status
-acpi_ev_install_handler (
- acpi_handle obj_handle,
- u32 level,
- void *context,
- void **return_value);
-
-acpi_status
acpi_ev_attach_region (
union acpi_operand_object *handler_obj,
union acpi_operand_object *region_obj,
@@ -233,17 +214,10 @@ acpi_ev_execute_reg_method (
union acpi_operand_object *region_obj,
u32 function);
-acpi_status
-acpi_ev_reg_run (
- acpi_handle obj_handle,
- u32 level,
- void *context,
- void **return_value);
/*
- * Evregini - Region initialization and setup
+ * evregini - Region initialization and setup
*/
-
acpi_status
acpi_ev_system_memory_region_setup (
acpi_handle handle,
@@ -293,9 +267,8 @@ acpi_ev_initialize_region (
/*
- * Evsci - SCI (System Control Interrupt) handling/dispatch
+ * evsci - SCI (System Control Interrupt) handling/dispatch
*/
-
u32 ACPI_SYSTEM_XFACE
acpi_ev_gpe_xrupt_handler (
void *context);
diff --git a/include/acpi/acexcep.h b/include/acpi/acexcep.h
index 53f8b50fac1a..60d737b2d70f 100644
--- a/include/acpi/acexcep.h
+++ b/include/acpi/acexcep.h
@@ -48,7 +48,6 @@
/*
* Exceptions returned by external ACPI interfaces
*/
-
#define AE_CODE_ENVIRONMENTAL 0x0000
#define AE_CODE_PROGRAMMER 0x1000
#define AE_CODE_ACPI_TABLES 0x2000
@@ -99,6 +98,7 @@
#define AE_CODE_ENV_MAX 0x001E
+
/*
* Programmer exceptions
*/
@@ -168,6 +168,7 @@
#define AE_CODE_AML_MAX 0x0021
+
/*
* Internal exceptions used for control
*/
@@ -188,6 +189,7 @@
#ifdef DEFINE_ACPI_GLOBALS
+
/*
* String versions of the exception codes above
* These strings must match the corresponding defines exactly
@@ -304,5 +306,4 @@ char const *acpi_gbl_exception_names_ctrl[] =
#endif /* ACPI GLOBALS */
-
#endif /* __ACEXCEP_H__ */
diff --git a/include/acpi/acglobal.h b/include/acpi/acglobal.h
index c7f387a972cb..4946696088c3 100644
--- a/include/acpi/acglobal.h
+++ b/include/acpi/acglobal.h
@@ -146,15 +146,15 @@ ACPI_EXTERN struct acpi_table_header *acpi_gbl_DSDT;
ACPI_EXTERN FACS_DESCRIPTOR *acpi_gbl_FACS;
ACPI_EXTERN struct acpi_common_facs acpi_gbl_common_fACS;
/*
- * Since there may be multiple SSDTs and PSDTS, a single pointer is not
+ * Since there may be multiple SSDTs and PSDTs, a single pointer is not
* sufficient; Therefore, there isn't one!
*/
/*
- * Handle both ACPI 1.0 and ACPI 2.0 Integer widths
- * If we are running a method that exists in a 32-bit ACPI table.
- * Use only 32 bits of the Integer for conversion.
+ * Handle both ACPI 1.0 and ACPI 2.0 Integer widths:
+ * If we are executing a method that exists in a 32-bit ACPI table,
+ * use only the lower 32 bits of the (internal) 64-bit Integer.
*/
ACPI_EXTERN u8 acpi_gbl_integer_bit_width;
ACPI_EXTERN u8 acpi_gbl_integer_byte_width;
@@ -246,6 +246,7 @@ ACPI_EXTERN acpi_size acpi_gbl_lowest_stack_pointer;
ACPI_EXTERN u32 acpi_gbl_deepest_nesting;
#endif
+
/*****************************************************************************
*
* Interpreter globals
@@ -268,6 +269,7 @@ ACPI_EXTERN u8 acpi_gbl_cm_single_step;
ACPI_EXTERN union acpi_parse_object *acpi_gbl_parsed_namespace_root;
+
/*****************************************************************************
*
* Hardware globals
@@ -298,7 +300,6 @@ ACPI_EXTERN acpi_handle acpi_gbl_gpe_lock;
*
****************************************************************************/
-
ACPI_EXTERN u8 acpi_gbl_db_output_flags;
#ifdef ACPI_DISASSEMBLER
@@ -353,5 +354,4 @@ ACPI_EXTERN u32 acpi_gbl_size_of_acpi_objects;
#endif /* ACPI_DEBUGGER */
-
#endif /* __ACGLOBAL_H__ */
diff --git a/include/acpi/achware.h b/include/acpi/achware.h
index 28ad1398c159..9d63641b8e7d 100644
--- a/include/acpi/achware.h
+++ b/include/acpi/achware.h
@@ -46,22 +46,26 @@
/* PM Timer ticks per second (HZ) */
+
#define PM_TIMER_FREQUENCY 3579545
+/* Values for the _SST reserved method */
-/* Prototypes */
+#define ACPI_SST_INDICATOR_OFF 0
+#define ACPI_SST_WORKING 1
+#define ACPI_SST_WAKING 2
+#define ACPI_SST_SLEEPING 3
+#define ACPI_SST_SLEEP_CONTEXT 4
-acpi_status
-acpi_hw_initialize (
- void);
+/* Prototypes */
-acpi_status
-acpi_hw_shutdown (
- void);
+/*
+ * hwacpi - high level functions
+ */
acpi_status
-acpi_hw_initialize_system_info (
+acpi_hw_initialize (
void);
acpi_status
@@ -72,12 +76,10 @@ u32
acpi_hw_get_mode (
void);
-u32
-acpi_hw_get_mode_capabilities (
- void);
-
-/* Register I/O Prototypes */
+/*
+ * hwregs - ACPI Register I/O
+ */
struct acpi_bit_register_info *
acpi_hw_get_bit_register_info (
u32 register_id);
@@ -111,8 +113,9 @@ acpi_hw_clear_acpi_status (
u32 flags);
-/* GPE support */
-
+/*
+ * hwgpe - GPE support
+ */
acpi_status
acpi_hw_write_gpe_enable_reg (
struct acpi_gpe_event_info *gpe_event_info);
@@ -131,12 +134,12 @@ acpi_hw_clear_gpe_block (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_hw_get_gpe_status (
struct acpi_gpe_event_info *gpe_event_info,
acpi_event_status *event_status);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
acpi_status
acpi_hw_disable_all_gpes (
@@ -155,15 +158,11 @@ acpi_hw_enable_runtime_gpe_block (
struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block);
-acpi_status
-acpi_hw_enable_wakeup_gpe_block (
- struct acpi_gpe_xrupt_info *gpe_xrupt_info,
- struct acpi_gpe_block_info *gpe_block);
-
-
-/* ACPI Timer prototypes */
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
+/*
+ * hwtimer - ACPI Timer prototypes
+ */
acpi_status
acpi_get_timer_resolution (
u32 *resolution);
@@ -177,6 +176,7 @@ acpi_get_timer_duration (
u32 start_ticks,
u32 end_ticks,
u32 *time_elapsed);
-#endif /* ACPI_FUTURE_USAGE */
+#endif /* ACPI_FUTURE_USAGE */
+
#endif /* __ACHWARE_H__ */
diff --git a/include/acpi/acinterp.h b/include/acpi/acinterp.h
index c5301f5ffaf4..5c7172477a0f 100644
--- a/include/acpi/acinterp.h
+++ b/include/acpi/acinterp.h
@@ -48,37 +48,9 @@
#define ACPI_WALK_OPERANDS (&(walk_state->operands [walk_state->num_operands -1]))
-acpi_status
-acpi_ex_resolve_operands (
- u16 opcode,
- union acpi_operand_object **stack_ptr,
- struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ex_check_object_type (
- acpi_object_type type_needed,
- acpi_object_type this_type,
- void *object);
-
-/*
- * exxface - External interpreter interfaces
- */
-
-acpi_status
-acpi_ex_load_table (
- acpi_table_type table_id);
-
-acpi_status
-acpi_ex_execute_method (
- struct acpi_namespace_node *method_node,
- union acpi_operand_object **params,
- union acpi_operand_object **return_obj_desc);
-
-
/*
* exconvrt - object conversion
*/
-
acpi_status
acpi_ex_convert_to_integer (
union acpi_operand_object *obj_desc,
@@ -110,17 +82,10 @@ acpi_ex_convert_to_target_type (
union acpi_operand_object **result_desc,
struct acpi_walk_state *walk_state);
-u32
-acpi_ex_convert_to_ascii (
- acpi_integer integer,
- u16 base,
- u8 *string,
- u8 max_length);
/*
* exfield - ACPI AML (p-code) execution - field manipulation
*/
-
acpi_status
acpi_ex_common_buffer_setup (
union acpi_operand_object *obj_desc,
@@ -128,42 +93,6 @@ acpi_ex_common_buffer_setup (
u32 *datum_count);
acpi_status
-acpi_ex_extract_from_field (
- union acpi_operand_object *obj_desc,
- void *buffer,
- u32 buffer_length);
-
-acpi_status
-acpi_ex_insert_into_field (
- union acpi_operand_object *obj_desc,
- void *buffer,
- u32 buffer_length);
-
-acpi_status
-acpi_ex_setup_region (
- union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset);
-
-acpi_status
-acpi_ex_access_region (
- union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset,
- acpi_integer *value,
- u32 read_write);
-
-u8
-acpi_ex_register_overflow (
- union acpi_operand_object *obj_desc,
- acpi_integer value);
-
-acpi_status
-acpi_ex_field_datum_io (
- union acpi_operand_object *obj_desc,
- u32 field_datum_byte_offset,
- acpi_integer *value,
- u32 read_write);
-
-acpi_status
acpi_ex_write_with_update_rule (
union acpi_operand_object *obj_desc,
acpi_integer mask,
@@ -198,28 +127,33 @@ acpi_ex_write_data_to_field (
union acpi_operand_object *obj_desc,
union acpi_operand_object **result_desc);
+
/*
- * exmisc - ACPI AML (p-code) execution - specific opcodes
+ * exfldio - low level field I/O
*/
-
acpi_status
-acpi_ex_opcode_3A_0T_0R (
- struct acpi_walk_state *walk_state);
+acpi_ex_extract_from_field (
+ union acpi_operand_object *obj_desc,
+ void *buffer,
+ u32 buffer_length);
acpi_status
-acpi_ex_opcode_3A_1T_1R (
- struct acpi_walk_state *walk_state);
+acpi_ex_insert_into_field (
+ union acpi_operand_object *obj_desc,
+ void *buffer,
+ u32 buffer_length);
acpi_status
-acpi_ex_opcode_6A_0T_1R (
- struct acpi_walk_state *walk_state);
+acpi_ex_access_region (
+ union acpi_operand_object *obj_desc,
+ u32 field_datum_byte_offset,
+ acpi_integer *value,
+ u32 read_write);
-u8
-acpi_ex_do_match (
- u32 match_op,
- union acpi_operand_object *package_obj,
- union acpi_operand_object *match_obj);
+/*
+ * exmisc - misc support routines
+ */
acpi_status
acpi_ex_get_object_reference (
union acpi_operand_object *obj_desc,
@@ -227,13 +161,6 @@ acpi_ex_get_object_reference (
struct acpi_walk_state *walk_state);
acpi_status
-acpi_ex_resolve_multiple (
- struct acpi_walk_state *walk_state,
- union acpi_operand_object *operand,
- acpi_object_type *return_type,
- union acpi_operand_object **return_desc);
-
-acpi_status
acpi_ex_concat_template (
union acpi_operand_object *obj_desc,
union acpi_operand_object *obj_desc2,
@@ -308,13 +235,6 @@ acpi_ex_create_method (
/*
* exconfig - dynamic table load/unload
*/
-
-acpi_status
-acpi_ex_add_table (
- struct acpi_table_header *table,
- struct acpi_namespace_node *parent_node,
- union acpi_operand_object **ddb_handle);
-
acpi_status
acpi_ex_load_op (
union acpi_operand_object *obj_desc,
@@ -334,7 +254,6 @@ acpi_ex_unload_table (
/*
* exmutex - mutex support
*/
-
acpi_status
acpi_ex_acquire_mutex (
union acpi_operand_object *time_desc,
@@ -354,15 +273,10 @@ void
acpi_ex_unlink_mutex (
union acpi_operand_object *obj_desc);
-void
-acpi_ex_link_mutex (
- union acpi_operand_object *obj_desc,
- struct acpi_thread_state *thread);
/*
- * exprep - ACPI AML (p-code) execution - prep utilities
+ * exprep - ACPI AML execution - prep utilities
*/
-
acpi_status
acpi_ex_prep_common_field_object (
union acpi_operand_object *obj_desc,
@@ -375,10 +289,10 @@ acpi_status
acpi_ex_prep_field_value (
struct acpi_create_field_info *info);
+
/*
* exsystem - Interface to OS services
*/
-
acpi_status
acpi_ex_system_do_notify_op (
union acpi_operand_object *value,
@@ -421,9 +335,8 @@ acpi_ex_system_wait_semaphore (
/*
- * exmonadic - ACPI AML (p-code) execution, monadic operators
+ * exoparg1 - ACPI AML execution, 1 operand
*/
-
acpi_status
acpi_ex_opcode_0A_0T_1R (
struct acpi_walk_state *walk_state);
@@ -445,9 +358,8 @@ acpi_ex_opcode_1A_1T_0R (
struct acpi_walk_state *walk_state);
/*
- * exdyadic - ACPI AML (p-code) execution, dyadic operators
+ * exoparg2 - ACPI AML execution, 2 operands
*/
-
acpi_status
acpi_ex_opcode_2A_0T_0R (
struct acpi_walk_state *walk_state);
@@ -466,21 +378,56 @@ acpi_ex_opcode_2A_2T_1R (
/*
- * exresolv - Object resolution and get value functions
+ * exoparg3 - ACPI AML execution, 3 operands
+ */
+acpi_status
+acpi_ex_opcode_3A_0T_0R (
+ struct acpi_walk_state *walk_state);
+
+acpi_status
+acpi_ex_opcode_3A_1T_1R (
+ struct acpi_walk_state *walk_state);
+
+
+/*
+ * exoparg6 - ACPI AML execution, 6 operands
*/
+acpi_status
+acpi_ex_opcode_6A_0T_1R (
+ struct acpi_walk_state *walk_state);
+
+/*
+ * exresolv - Object resolution and get value functions
+ */
acpi_status
acpi_ex_resolve_to_value (
union acpi_operand_object **stack_ptr,
struct acpi_walk_state *walk_state);
acpi_status
+acpi_ex_resolve_multiple (
+ struct acpi_walk_state *walk_state,
+ union acpi_operand_object *operand,
+ acpi_object_type *return_type,
+ union acpi_operand_object **return_desc);
+
+
+/*
+ * exresnte - resolve namespace node
+ */
+acpi_status
acpi_ex_resolve_node_to_value (
struct acpi_namespace_node **stack_ptr,
struct acpi_walk_state *walk_state);
+
+/*
+ * exresop - resolve operand to value
+ */
acpi_status
-acpi_ex_resolve_object_to_value (
+acpi_ex_resolve_operands (
+ u16 opcode,
union acpi_operand_object **stack_ptr,
struct acpi_walk_state *walk_state);
@@ -488,7 +435,6 @@ acpi_ex_resolve_object_to_value (
/*
* exdump - Interpreter debug output routines
*/
-
void
acpi_ex_dump_operand (
union acpi_operand_object *obj_desc,
@@ -504,7 +450,7 @@ acpi_ex_dump_operands (
char *module_name,
u32 line_number);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
void
acpi_ex_dump_object_descriptor (
union acpi_operand_object *object,
@@ -514,46 +460,12 @@ void
acpi_ex_dump_node (
struct acpi_namespace_node *node,
u32 flags);
+#endif /* ACPI_FUTURE_USAGE */
-void
-acpi_ex_out_string (
- char *title,
- char *value);
-
-void
-acpi_ex_out_pointer (
- char *title,
- void *value);
-
-void
-acpi_ex_out_integer (
- char *title,
- u32 value);
-
-void
-acpi_ex_out_address (
- char *title,
- acpi_physical_address value);
-#endif /* ACPI_FUTURE_USAGE */
/*
- * exnames - interpreter/scanner name load/execute
+ * exnames - AML namestring support
*/
-
-char *
-acpi_ex_allocate_name_string (
- u32 prefix_count,
- u32 num_name_segs);
-
-u32
-acpi_ex_good_char (
- u32 character);
-
-acpi_status
-acpi_ex_name_segment (
- u8 **in_aml_address,
- char *name_string);
-
acpi_status
acpi_ex_get_name_string (
acpi_object_type data_type,
@@ -561,16 +473,10 @@ acpi_ex_get_name_string (
char **out_name_string,
u32 *out_name_length);
-acpi_status
-acpi_ex_do_name (
- acpi_object_type data_type,
- acpi_interpreter_mode load_exec_mode);
-
/*
* exstore - Object store support
*/
-
acpi_status
acpi_ex_store (
union acpi_operand_object *val_desc,
@@ -578,12 +484,6 @@ acpi_ex_store (
struct acpi_walk_state *walk_state);
acpi_status
-acpi_ex_store_object_to_index (
- union acpi_operand_object *val_desc,
- union acpi_operand_object *dest_desc,
- struct acpi_walk_state *walk_state);
-
-acpi_status
acpi_ex_store_object_to_node (
union acpi_operand_object *source_desc,
struct acpi_namespace_node *node,
@@ -593,10 +493,10 @@ acpi_ex_store_object_to_node (
#define ACPI_IMPLICIT_CONVERSION TRUE
#define ACPI_NO_IMPLICIT_CONVERSION FALSE
+
/*
- * exstoren
+ * exstoren - resolve/store object
*/
-
acpi_status
acpi_ex_resolve_object (
union acpi_operand_object **source_desc_ptr,
@@ -612,9 +512,8 @@ acpi_ex_store_object_to_object (
/*
- * excopy - object copy
+ * exstorob - store object - buffer/string
*/
-
acpi_status
acpi_ex_store_buffer_to_buffer (
union acpi_operand_object *source_desc,
@@ -625,6 +524,10 @@ acpi_ex_store_string_to_string (
union acpi_operand_object *source_desc,
union acpi_operand_object *target_desc);
+
+/*
+ * excopy - object copy
+ */
acpi_status
acpi_ex_copy_integer_to_index_field (
union acpi_operand_object *source_desc,
@@ -645,10 +548,10 @@ acpi_ex_copy_integer_to_buffer_field (
union acpi_operand_object *source_desc,
union acpi_operand_object *target_desc);
+
/*
* exutils - interpreter/scanner utilities
*/
-
acpi_status
acpi_ex_enter_interpreter (
void);
@@ -669,11 +572,6 @@ void
acpi_ex_release_global_lock (
u8 locked);
-u32
-acpi_ex_digits_needed (
- acpi_integer value,
- u32 base);
-
void
acpi_ex_eisa_id_to_string (
u32 numeric_id,
@@ -688,7 +586,6 @@ acpi_ex_unsigned_integer_to_string (
/*
* exregion - default op_region handlers
*/
-
acpi_status
acpi_ex_system_memory_space_handler (
u32 function,
diff --git a/include/acpi/aclocal.h b/include/acpi/aclocal.h
index 01d3b4bc0c85..030e641115cb 100644
--- a/include/acpi/aclocal.h
+++ b/include/acpi/aclocal.h
@@ -72,7 +72,6 @@ typedef u32 acpi_mutex_handle;
*
* NOTE: any changes here must be reflected in the acpi_gbl_mutex_names table also!
*/
-
#define ACPI_MTX_EXECUTE 0
#define ACPI_MTX_INTERPRETER 1
#define ACPI_MTX_PARSER 2
@@ -151,13 +150,13 @@ typedef u16 acpi_owner_id;
#define ACPI_FIELD_DWORD_GRANULARITY 4
#define ACPI_FIELD_QWORD_GRANULARITY 8
+
/*****************************************************************************
*
* Namespace typedefs and structs
*
****************************************************************************/
-
/* Operational modes of the AML interpreter/scanner */
typedef enum
@@ -176,7 +175,6 @@ typedef enum
* data_type is used to differentiate between internal descriptors, and MUST
* be the first byte in this structure.
*/
-
union acpi_name_union
{
u32 integer;
@@ -415,7 +413,6 @@ struct acpi_field_info
*
****************************************************************************/
-
#define ACPI_CONTROL_NORMAL 0xC0
#define ACPI_CONTROL_CONDITIONAL_EXECUTING 0xC1
#define ACPI_CONTROL_PREDICATE_EXECUTING 0xC2
@@ -424,6 +421,7 @@ struct acpi_field_info
/* Forward declarations */
+
struct acpi_walk_state ;
struct acpi_obj_mutex;
union acpi_parse_object ;
@@ -601,7 +599,6 @@ struct acpi_opcode_info
u8 type; /* Opcode type */
};
-
union acpi_parse_value
{
acpi_integer integer; /* Integer constant (Up to 64 bits) */
@@ -613,7 +610,6 @@ union acpi_parse_value
union acpi_parse_object *arg; /* arguments and contained ops */
};
-
#define ACPI_PARSE_COMMON \
u8 data_type; /* To differentiate various internal objs */\
u8 flags; /* Type of Op */\
@@ -691,7 +687,6 @@ struct acpi_parse_obj_asl
char parse_op_name[12];
};
-
union acpi_parse_object
{
struct acpi_parse_obj_common common;
@@ -834,7 +829,6 @@ struct acpi_bit_register_info
*
****************************************************************************/
-
/* resource_type values */
#define ACPI_RESOURCE_TYPE_MEMORY_RANGE 0
diff --git a/include/acpi/acmacros.h b/include/acpi/acmacros.h
index fcaced16b16f..09be937d2c39 100644
--- a/include/acpi/acmacros.h
+++ b/include/acpi/acmacros.h
@@ -539,11 +539,6 @@
#define ACPI_DUMP_ENTRY(a,b) acpi_ns_dump_entry (a,b)
-
-#ifdef ACPI_FUTURE_USAGE
-#define ACPI_DUMP_TABLES(a,b) acpi_ns_dump_tables(a,b)
-#endif
-
#define ACPI_DUMP_PATHNAME(a,b,c,d) acpi_ns_dump_pathname(a,b,c,d)
#define ACPI_DUMP_RESOURCE_LIST(a) acpi_rs_dump_resource_list(a)
#define ACPI_DUMP_BUFFER(a,b) acpi_ut_dump_buffer((u8 *)a,b,DB_BYTE_DISPLAY,_COMPONENT)
@@ -596,11 +591,6 @@
#define ACPI_DUMP_STACK_ENTRY(a)
#define ACPI_DUMP_OPERANDS(a,b,c,d,e)
#define ACPI_DUMP_ENTRY(a,b)
-
-#ifdef ACPI_FUTURE_USAGE
-#define ACPI_DUMP_TABLES(a,b)
-#endif
-
#define ACPI_DUMP_PATHNAME(a,b,c,d)
#define ACPI_DUMP_RESOURCE_LIST(a)
#define ACPI_DUMP_BUFFER(a,b)
diff --git a/include/acpi/acnames.h b/include/acpi/acnames.h
new file mode 100644
index 000000000000..deb7cb06f5f0
--- /dev/null
+++ b/include/acpi/acnames.h
@@ -0,0 +1,84 @@
+/******************************************************************************
+ *
+ * Name: acnames.h - Global names and strings
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#ifndef __ACNAMES_H__
+#define __ACNAMES_H__
+
+/* Method names - these methods can appear anywhere in the namespace */
+
+#define METHOD_NAME__HID "_HID"
+#define METHOD_NAME__CID "_CID"
+#define METHOD_NAME__UID "_UID"
+#define METHOD_NAME__ADR "_ADR"
+#define METHOD_NAME__INI "_INI"
+#define METHOD_NAME__STA "_STA"
+#define METHOD_NAME__REG "_REG"
+#define METHOD_NAME__SEG "_SEG"
+#define METHOD_NAME__BBN "_BBN"
+#define METHOD_NAME__PRT "_PRT"
+#define METHOD_NAME__CRS "_CRS"
+#define METHOD_NAME__PRS "_PRS"
+#define METHOD_NAME__PRW "_PRW"
+#define METHOD_NAME__SRS "_SRS"
+
+/* Method names - these methods must appear at the namespace root */
+
+#define METHOD_NAME__BFS "\\_BFS"
+#define METHOD_NAME__GTS "\\_GTS"
+#define METHOD_NAME__PTS "\\_PTS"
+#define METHOD_NAME__SST "\\_SI._SST"
+#define METHOD_NAME__WAK "\\_WAK"
+
+/* Definitions of the predefined namespace names */
+
+#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */
+#define ACPI_ROOT_NAME (u32) 0x5F5F5F5C /* Root name is "\___" */
+#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */
+
+#define ACPI_NS_ROOT_PATH "\\"
+#define ACPI_NS_SYSTEM_BUS "_SB_"
+
+
+#endif /* __ACNAMES_H__ */
+
+
diff --git a/include/acpi/acnamesp.h b/include/acpi/acnamesp.h
index 8b3cdc3566b1..d1b3ce80056f 100644
--- a/include/acpi/acnamesp.h
+++ b/include/acpi/acnamesp.h
@@ -57,17 +57,6 @@
#define ACPI_NS_NEWSCOPE 1 /* a definition of this type opens a name scope */
#define ACPI_NS_LOCAL 2 /* suppress search of enclosing scopes */
-
-/* Definitions of the predefined namespace names */
-
-#define ACPI_UNKNOWN_NAME (u32) 0x3F3F3F3F /* Unknown name is "????" */
-#define ACPI_ROOT_NAME (u32) 0x5F5F5F5C /* Root name is "\___" */
-#define ACPI_SYS_BUS_NAME (u32) 0x5F53425F /* Sys bus name is "_SB_" */
-
-#define ACPI_NS_ROOT_PATH "\\"
-#define ACPI_NS_SYSTEM_BUS "_SB_"
-
-
/* Flags for acpi_ns_lookup, acpi_ns_search_and_enter */
#define ACPI_NS_NO_UPSEARCH 0
@@ -80,10 +69,9 @@
#define ACPI_NS_WALK_NO_UNLOCK FALSE
-acpi_status
-acpi_ns_load_namespace (
- void);
-
+/*
+ * nsinit - Namespace initialization
+ */
acpi_status
acpi_ns_initialize_objects (
void);
@@ -93,23 +81,22 @@ acpi_ns_initialize_devices (
void);
-/* Namespace init - nsxfinit */
-
+/*
+ * nsload - Namespace loading
+ */
acpi_status
-acpi_ns_init_one_device (
- acpi_handle obj_handle,
- u32 nesting_level,
- void *context,
- void **return_value);
+acpi_ns_load_namespace (
+ void);
acpi_status
-acpi_ns_init_one_object (
- acpi_handle obj_handle,
- u32 level,
- void *context,
- void **return_value);
+acpi_ns_load_table (
+ struct acpi_table_desc *table_desc,
+ struct acpi_namespace_node *node);
+/*
+ * nswalk - walk the namespace
+ */
acpi_status
acpi_ns_walk_namespace (
acpi_object_type type,
@@ -126,37 +113,24 @@ acpi_ns_get_next_node (
struct acpi_namespace_node *parent,
struct acpi_namespace_node *child);
-void
-acpi_ns_delete_namespace_by_owner (
- u16 table_id);
-
-
-/* Namespace loading - nsload */
-
-acpi_status
-acpi_ns_one_complete_parse (
- u32 pass_number,
- struct acpi_table_desc *table_desc);
+/*
+ * nsparse - table parsing
+ */
acpi_status
acpi_ns_parse_table (
struct acpi_table_desc *table_desc,
struct acpi_namespace_node *scope);
acpi_status
-acpi_ns_load_table (
- struct acpi_table_desc *table_desc,
- struct acpi_namespace_node *node);
-
-acpi_status
-acpi_ns_load_table_by_type (
- acpi_table_type table_type);
+acpi_ns_one_complete_parse (
+ u32 pass_number,
+ struct acpi_table_desc *table_desc);
/*
- * Top-level namespace access - nsaccess
+ * nsaccess - Top-level namespace access
*/
-
acpi_status
acpi_ns_root_initialize (
void);
@@ -173,9 +147,8 @@ acpi_ns_lookup (
/*
- * Named object allocation/deallocation - nsalloc
+ * nsalloc - Named object allocation/deallocation
*/
-
struct acpi_namespace_node *
acpi_ns_create_node (
u32 name);
@@ -189,6 +162,10 @@ acpi_ns_delete_namespace_subtree (
struct acpi_namespace_node *parent_handle);
void
+acpi_ns_delete_namespace_by_owner (
+ u16 table_id);
+
+void
acpi_ns_detach_object (
struct acpi_namespace_node *node);
@@ -201,36 +178,16 @@ acpi_ns_compare_names (
char *name1,
char *name2);
-void
-acpi_ns_remove_reference (
- struct acpi_namespace_node *node);
-
/*
- * Namespace modification - nsmodify
+ * nsdump - Namespace dump/print utilities
*/
-
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ns_unload_namespace (
- acpi_handle handle);
-
-acpi_status
-acpi_ns_delete_subtree (
- acpi_handle start_handle);
-#endif
-
-
-/*
- * Namespace dump/print utilities - nsdump
- */
-
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
void
acpi_ns_dump_tables (
acpi_handle search_base,
u32 max_depth);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
void
acpi_ns_dump_entry (
@@ -249,19 +206,6 @@ acpi_ns_print_pathname (
u32 num_segments,
char *pathname);
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_ns_dump_one_device (
- acpi_handle obj_handle,
- u32 level,
- void *context,
- void **return_value);
-
-void
-acpi_ns_dump_root_devices (
- void);
-#endif /* ACPI_FUTURE_USAGE */
-
acpi_status
acpi_ns_dump_one_object (
acpi_handle obj_handle,
@@ -269,7 +213,7 @@ acpi_ns_dump_one_object (
void *context,
void **return_value);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
void
acpi_ns_dump_objects (
acpi_object_type type,
@@ -277,13 +221,12 @@ acpi_ns_dump_objects (
u32 max_depth,
u32 ownder_id,
acpi_handle start_handle);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
/*
- * Namespace evaluation functions - nseval
+ * nseval - Namespace evaluation functions
*/
-
acpi_status
acpi_ns_evaluate_by_handle (
struct acpi_parameter_info *info);
@@ -298,40 +241,14 @@ acpi_ns_evaluate_relative (
char *pathname,
struct acpi_parameter_info *info);
-acpi_status
-acpi_ns_execute_control_method (
- struct acpi_parameter_info *info);
-
-acpi_status
-acpi_ns_get_object_value (
- struct acpi_parameter_info *info);
-
-
-/*
- * Parent/Child/Peer utility functions
- */
-
-#ifdef ACPI_FUTURE_USAGE
-acpi_name
-acpi_ns_find_parent_name (
- struct acpi_namespace_node *node_to_search);
-#endif
-
/*
- * Name and Scope manipulation - nsnames
+ * nsnames - Name and Scope manipulation
*/
-
u32
acpi_ns_opens_scope (
acpi_object_type type);
-void
-acpi_ns_build_external_path (
- struct acpi_namespace_node *node,
- acpi_size size,
- char *name_buffer);
-
char *
acpi_ns_get_external_pathname (
struct acpi_namespace_node *node);
@@ -363,9 +280,8 @@ acpi_ns_get_pathname_length (
/*
- * Object management for namespace nodes - nsobject
+ * nsobject - Object management for namespace nodes
*/
-
acpi_status
acpi_ns_attach_object (
struct acpi_namespace_node *node,
@@ -399,9 +315,8 @@ acpi_ns_get_attached_data (
/*
- * Namespace searching and entry - nssearch
+ * nssearch - Namespace searching and entry
*/
-
acpi_status
acpi_ns_search_and_enter (
u32 entry_name,
@@ -428,17 +343,12 @@ acpi_ns_install_node (
/*
- * Utility functions - nsutils
+ * nsutils - Utility functions
*/
-
u8
acpi_ns_valid_root_prefix (
char prefix);
-u8
-acpi_ns_valid_path_separator (
- char sep);
-
acpi_object_type
acpi_ns_get_type (
struct acpi_namespace_node *node);
@@ -511,5 +421,4 @@ struct acpi_namespace_node *
acpi_ns_get_next_valid_node (
struct acpi_namespace_node *node);
-
#endif /* __ACNAMESP_H__ */
diff --git a/include/acpi/acobject.h b/include/acpi/acobject.h
index 036023a940b2..e079b94e4fce 100644
--- a/include/acpi/acobject.h
+++ b/include/acpi/acobject.h
@@ -133,6 +133,7 @@ struct acpi_object_integer
acpi_integer value;
};
+
/*
* Note: The String and Buffer object must be identical through the Pointer
* element. There is code that depends on this.
@@ -468,7 +469,6 @@ union acpi_operand_object
*
*****************************************************************************/
-
/* Object descriptor types */
#define ACPI_DESC_TYPE_CACHED 0x01 /* Used only when object is cached */
diff --git a/include/acpi/acopcode.h b/include/acpi/acopcode.h
new file mode 100644
index 000000000000..118ecba4cf05
--- /dev/null
+++ b/include/acpi/acopcode.h
@@ -0,0 +1,325 @@
+/******************************************************************************
+ *
+ * Name: acopcode.h - AML opcode information for the AML parser and interpreter
+ *
+ *****************************************************************************/
+
+/*
+ * Copyright (C) 2000 - 2005, R. Byron Moore
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ * substantially similar to the "NO WARRANTY" disclaimer below
+ * ("Disclaimer") and any redistribution must be conditioned upon
+ * including a substantially similar Disclaimer requirement for further
+ * binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ * of any contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ */
+
+#ifndef __ACOPCODE_H__
+#define __ACOPCODE_H__
+
+#define MAX_EXTENDED_OPCODE 0x88
+#define NUM_EXTENDED_OPCODE (MAX_EXTENDED_OPCODE + 1)
+#define MAX_INTERNAL_OPCODE
+#define NUM_INTERNAL_OPCODE (MAX_INTERNAL_OPCODE + 1)
+
+/* Used for non-assigned opcodes */
+
+#define _UNK 0x6B
+
+/*
+ * Reserved ASCII characters. Do not use any of these for
+ * internal opcodes, since they are used to differentiate
+ * name strings from AML opcodes
+ */
+#define _ASC 0x6C
+#define _NAM 0x6C
+#define _PFX 0x6D
+
+
+/*
+ * All AML opcodes and the parse-time arguments for each. Used by the AML
+ * parser Each list is compressed into a 32-bit number and stored in the
+ * master opcode table (in psopcode.c).
+ */
+#define ARGP_ACCESSFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_ACQUIRE_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_WORDDATA)
+#define ARGP_ADD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_ALIAS_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_NAME)
+#define ARGP_ARG0 ARG_NONE
+#define ARGP_ARG1 ARG_NONE
+#define ARGP_ARG2 ARG_NONE
+#define ARGP_ARG3 ARG_NONE
+#define ARGP_ARG4 ARG_NONE
+#define ARGP_ARG5 ARG_NONE
+#define ARGP_ARG6 ARG_NONE
+#define ARGP_BANK_FIELD_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_TERMARG, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_BIT_AND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NAND_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_NOT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_OR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BIT_XOR_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_BREAK_OP ARG_NONE
+#define ARGP_BREAK_POINT_OP ARG_NONE
+#define ARGP_BUFFER_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_BYTELIST)
+#define ARGP_BYTE_OP ARGP_LIST1 (ARGP_BYTEDATA)
+#define ARGP_BYTELIST_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_CONCAT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_CONCAT_RES_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_COND_REF_OF_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SUPERNAME)
+#define ARGP_CONTINUE_OP ARG_NONE
+#define ARGP_COPY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_SIMPLENAME)
+#define ARGP_CREATE_BIT_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_BYTE_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_DWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_FIELD_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_QWORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_CREATE_WORD_FIELD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_NAME)
+#define ARGP_DATA_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_DEBUG_OP ARG_NONE
+#define ARGP_DECREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_DEREF_OF_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_DEVICE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_DIVIDE_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET, ARGP_TARGET)
+#define ARGP_DWORD_OP ARGP_LIST1 (ARGP_DWORDDATA)
+#define ARGP_ELSE_OP ARGP_LIST2 (ARGP_PKGLENGTH, ARGP_TERMLIST)
+#define ARGP_EVENT_OP ARGP_LIST1 (ARGP_NAME)
+#define ARGP_FATAL_OP ARGP_LIST3 (ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_TERMARG)
+#define ARGP_FIELD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_FIND_SET_LEFT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FIND_SET_RIGHT_BIT_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_FROM_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_IF_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_INCREMENT_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_INDEX_FIELD_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAMESTRING, ARGP_NAMESTRING,ARGP_BYTEDATA, ARGP_FIELDLIST)
+#define ARGP_INDEX_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_LAND_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LGREATEREQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESS_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LLESSEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LNOT_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_LNOTEQUAL_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOAD_OP ARGP_LIST2 (ARGP_NAMESTRING, ARGP_SUPERNAME)
+#define ARGP_LOAD_TABLE_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_LOCAL0 ARG_NONE
+#define ARGP_LOCAL1 ARG_NONE
+#define ARGP_LOCAL2 ARG_NONE
+#define ARGP_LOCAL3 ARG_NONE
+#define ARGP_LOCAL4 ARG_NONE
+#define ARGP_LOCAL5 ARG_NONE
+#define ARGP_LOCAL6 ARG_NONE
+#define ARGP_LOCAL7 ARG_NONE
+#define ARGP_LOR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_MATCH_OP ARGP_LIST6 (ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_METHOD_OP ARGP_LIST4 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMLIST)
+#define ARGP_METHODCALL_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_MID_OP ARGP_LIST4 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MOD_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MULTIPLY_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_MUTEX_OP ARGP_LIST2 (ARGP_NAME, ARGP_BYTEDATA)
+#define ARGP_NAME_OP ARGP_LIST2 (ARGP_NAME, ARGP_DATAOBJ)
+#define ARGP_NAMEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NAMEPATH_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_NOOP_OP ARG_NONE
+#define ARGP_NOTIFY_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_ONE_OP ARG_NONE
+#define ARGP_ONES_OP ARG_NONE
+#define ARGP_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_BYTEDATA, ARGP_DATAOBJLIST)
+#define ARGP_POWER_RES_OP ARGP_LIST5 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_WORDDATA, ARGP_OBJLIST)
+#define ARGP_PROCESSOR_OP ARGP_LIST6 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_BYTEDATA, ARGP_DWORDDATA, ARGP_BYTEDATA, ARGP_OBJLIST)
+#define ARGP_QWORD_OP ARGP_LIST1 (ARGP_QWORDDATA)
+#define ARGP_REF_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_REGION_OP ARGP_LIST4 (ARGP_NAME, ARGP_BYTEDATA, ARGP_TERMARG, ARGP_TERMARG)
+#define ARGP_RELEASE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RESERVEDFIELD_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_RESET_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_RETURN_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_REVISION_OP ARG_NONE
+#define ARGP_SCOPE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_TERMLIST)
+#define ARGP_SHIFT_LEFT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SHIFT_RIGHT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_SIGNAL_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SIZE_OF_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_SLEEP_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STALL_OP ARGP_LIST1 (ARGP_TERMARG)
+#define ARGP_STATICSTRING_OP ARGP_LIST1 (ARGP_NAMESTRING)
+#define ARGP_STORE_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_SUPERNAME)
+#define ARGP_STRING_OP ARGP_LIST1 (ARGP_CHARLIST)
+#define ARGP_SUBTRACT_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_THERMAL_ZONE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_NAME, ARGP_OBJLIST)
+#define ARGP_TIMER_OP ARG_NONE
+#define ARGP_TO_BCD_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_BUFFER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_DEC_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_HEX_STR_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_INTEGER_OP ARGP_LIST2 (ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TO_STRING_OP ARGP_LIST3 (ARGP_TERMARG, ARGP_TERMARG, ARGP_TARGET)
+#define ARGP_TYPE_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_UNLOAD_OP ARGP_LIST1 (ARGP_SUPERNAME)
+#define ARGP_VAR_PACKAGE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_DATAOBJLIST)
+#define ARGP_WAIT_OP ARGP_LIST2 (ARGP_SUPERNAME, ARGP_TERMARG)
+#define ARGP_WHILE_OP ARGP_LIST3 (ARGP_PKGLENGTH, ARGP_TERMARG, ARGP_TERMLIST)
+#define ARGP_WORD_OP ARGP_LIST1 (ARGP_WORDDATA)
+#define ARGP_ZERO_OP ARG_NONE
+
+
+/*
+ * All AML opcodes and the runtime arguments for each. Used by the AML
+ * interpreter Each list is compressed into a 32-bit number and stored
+ * in the master opcode table (in psopcode.c).
+ *
+ * (Used by prep_operands procedure and the ASL Compiler)
+ */
+#define ARGI_ACCESSFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_ACQUIRE_OP ARGI_LIST2 (ARGI_MUTEX, ARGI_INTEGER)
+#define ARGI_ADD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_ALIAS_OP ARGI_INVALID_OPCODE
+#define ARGI_ARG0 ARG_NONE
+#define ARGI_ARG1 ARG_NONE
+#define ARGI_ARG2 ARG_NONE
+#define ARGI_ARG3 ARG_NONE
+#define ARGI_ARG4 ARG_NONE
+#define ARGI_ARG5 ARG_NONE
+#define ARGI_ARG6 ARG_NONE
+#define ARGI_BANK_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_BIT_AND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NAND_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_NOT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_OR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BIT_XOR_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_BREAK_OP ARG_NONE
+#define ARGI_BREAK_POINT_OP ARG_NONE
+#define ARGI_BUFFER_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_BYTE_OP ARGI_INVALID_OPCODE
+#define ARGI_BYTELIST_OP ARGI_INVALID_OPCODE
+#define ARGI_CONCAT_OP ARGI_LIST3 (ARGI_COMPUTEDATA,ARGI_COMPUTEDATA, ARGI_TARGETREF)
+#define ARGI_CONCAT_RES_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_BUFFER, ARGI_TARGETREF)
+#define ARGI_COND_REF_OF_OP ARGI_LIST2 (ARGI_OBJECT_REF, ARGI_TARGETREF)
+#define ARGI_CONTINUE_OP ARGI_INVALID_OPCODE
+#define ARGI_COPY_OP ARGI_LIST2 (ARGI_ANYTYPE, ARGI_SIMPLE_TARGET)
+#define ARGI_CREATE_BIT_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_BYTE_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#define ARGI_CREATE_DWORD_FIELD_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_REFERENCE)
+#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_DEBUG_OP ARG_NONE
+#define ARGI_DECREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#define ARGI_DEREF_OF_OP ARGI_LIST1 (ARGI_REF_OR_STRING)
+#define ARGI_DEVICE_OP ARGI_INVALID_OPCODE
+#define ARGI_DIVIDE_OP ARGI_LIST4 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF, ARGI_TARGETREF)
+#define ARGI_DWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ELSE_OP ARGI_INVALID_OPCODE
+#define ARGI_EVENT_OP ARGI_INVALID_OPCODE
+#define ARGI_FATAL_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_FIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_FIND_SET_LEFT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FIND_SET_RIGHT_BIT_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_FROM_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_IF_OP ARGI_INVALID_OPCODE
+#define ARGI_INCREMENT_OP ARGI_LIST1 (ARGI_INTEGER_REF)
+#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_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_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
+#define ARGI_LOAD_OP ARGI_LIST2 (ARGI_REGION_OR_FIELD,ARGI_TARGETREF)
+#define ARGI_LOAD_TABLE_OP ARGI_LIST6 (ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_STRING, ARGI_ANYTYPE)
+#define ARGI_LOCAL0 ARG_NONE
+#define ARGI_LOCAL1 ARG_NONE
+#define ARGI_LOCAL2 ARG_NONE
+#define ARGI_LOCAL3 ARG_NONE
+#define ARGI_LOCAL4 ARG_NONE
+#define ARGI_LOCAL5 ARG_NONE
+#define ARGI_LOCAL6 ARG_NONE
+#define ARGI_LOCAL7 ARG_NONE
+#define ARGI_LOR_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_MATCH_OP ARGI_LIST6 (ARGI_PACKAGE, ARGI_INTEGER, ARGI_COMPUTEDATA, ARGI_INTEGER,ARGI_COMPUTEDATA,ARGI_INTEGER)
+#define ARGI_METHOD_OP ARGI_INVALID_OPCODE
+#define ARGI_METHODCALL_OP ARGI_INVALID_OPCODE
+#define ARGI_MID_OP ARGI_LIST4 (ARGI_BUFFER_OR_STRING,ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MOD_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MULTIPLY_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_MUTEX_OP ARGI_INVALID_OPCODE
+#define ARGI_NAME_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_NAMEPATH_OP ARGI_INVALID_OPCODE
+#define ARGI_NOOP_OP ARG_NONE
+#define ARGI_NOTIFY_OP ARGI_LIST2 (ARGI_DEVICE_REF, ARGI_INTEGER)
+#define ARGI_ONE_OP ARG_NONE
+#define ARGI_ONES_OP ARG_NONE
+#define ARGI_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_POWER_RES_OP ARGI_INVALID_OPCODE
+#define ARGI_PROCESSOR_OP ARGI_INVALID_OPCODE
+#define ARGI_QWORD_OP ARGI_INVALID_OPCODE
+#define ARGI_REF_OF_OP ARGI_LIST1 (ARGI_OBJECT_REF)
+#define ARGI_REGION_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_INTEGER)
+#define ARGI_RELEASE_OP ARGI_LIST1 (ARGI_MUTEX)
+#define ARGI_RESERVEDFIELD_OP ARGI_INVALID_OPCODE
+#define ARGI_RESET_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_RETURN_OP ARGI_INVALID_OPCODE
+#define ARGI_REVISION_OP ARG_NONE
+#define ARGI_SCOPE_OP ARGI_INVALID_OPCODE
+#define ARGI_SHIFT_LEFT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SHIFT_RIGHT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_SIGNAL_OP ARGI_LIST1 (ARGI_EVENT)
+#define ARGI_SIZE_OF_OP ARGI_LIST1 (ARGI_DATAOBJECT)
+#define ARGI_SLEEP_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STALL_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_STATICSTRING_OP ARGI_INVALID_OPCODE
+#define ARGI_STORE_OP ARGI_LIST2 (ARGI_DATAREFOBJ, ARGI_TARGETREF)
+#define ARGI_STRING_OP ARGI_INVALID_OPCODE
+#define ARGI_SUBTRACT_OP ARGI_LIST3 (ARGI_INTEGER, ARGI_INTEGER, ARGI_TARGETREF)
+#define ARGI_THERMAL_ZONE_OP ARGI_INVALID_OPCODE
+#define ARGI_TIMER_OP ARG_NONE
+#define ARGI_TO_BCD_OP ARGI_LIST2 (ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TO_BUFFER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_DEC_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_HEX_STR_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_INTEGER_OP ARGI_LIST2 (ARGI_COMPUTEDATA,ARGI_FIXED_TARGET)
+#define ARGI_TO_STRING_OP ARGI_LIST3 (ARGI_BUFFER, ARGI_INTEGER, ARGI_FIXED_TARGET)
+#define ARGI_TYPE_OP ARGI_LIST1 (ARGI_ANYTYPE)
+#define ARGI_UNLOAD_OP ARGI_LIST1 (ARGI_DDBHANDLE)
+#define ARGI_VAR_PACKAGE_OP ARGI_LIST1 (ARGI_INTEGER)
+#define ARGI_WAIT_OP ARGI_LIST2 (ARGI_EVENT, ARGI_INTEGER)
+#define ARGI_WHILE_OP ARGI_INVALID_OPCODE
+#define ARGI_WORD_OP ARGI_INVALID_OPCODE
+#define ARGI_ZERO_OP ARG_NONE
+
+#endif /* __ACOPCODE_H__ */
diff --git a/include/acpi/acparser.h b/include/acpi/acparser.h
index c0395ef2b0d0..698276571818 100644
--- a/include/acpi/acparser.h
+++ b/include/acpi/acparser.h
@@ -64,8 +64,17 @@
#define ACPI_PARSE_DEFERRED_OP 0x0100
-/* Parser external interfaces */
+/******************************************************************************
+ *
+ * Parser interfaces
+ *
+ *****************************************************************************/
+
+
+/*
+ * psxface - Parser external interfaces
+ */
acpi_status
acpi_psx_load_table (
u8 *pcode_addr,
@@ -76,23 +85,13 @@ acpi_psx_execute (
struct acpi_parameter_info *info);
-/******************************************************************************
- *
- * Parser interfaces
- *
- *****************************************************************************/
-
-
-/* psargs - Parse AML opcode arguments */
-
+/*
+ * psargs - Parse AML opcode arguments
+ */
u8 *
acpi_ps_get_next_package_end (
struct acpi_parse_state *parser_state);
-u32
-acpi_ps_get_next_package_length (
- struct acpi_parse_state *parser_state);
-
char *
acpi_ps_get_next_namestring (
struct acpi_parse_state *parser_state);
@@ -110,10 +109,6 @@ acpi_ps_get_next_namepath (
union acpi_parse_object *arg,
u8 method_call);
-union acpi_parse_object *
-acpi_ps_get_next_field (
- struct acpi_parse_state *parser_state);
-
acpi_status
acpi_ps_get_next_arg (
struct acpi_walk_state *walk_state,
@@ -122,8 +117,9 @@ acpi_ps_get_next_arg (
union acpi_parse_object **return_arg);
-/* psfind */
-
+/*
+ * psfind
+ */
union acpi_parse_object *
acpi_ps_find_name (
union acpi_parse_object *scope,
@@ -135,8 +131,9 @@ acpi_ps_get_parent (
union acpi_parse_object *op);
-/* psopcode - AML Opcode information */
-
+/*
+ * psopcode - AML Opcode information
+ */
const struct acpi_opcode_info *
acpi_ps_get_opcode_info (
u16 opcode);
@@ -146,56 +143,25 @@ acpi_ps_get_opcode_name (
u16 opcode);
-/* psparse - top level parsing routines */
-
-u32
-acpi_ps_get_opcode_size (
- u32 opcode);
-
-void
-acpi_ps_complete_this_op (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op);
-
-acpi_status
-acpi_ps_next_parse_state (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object *op,
- acpi_status callback_status);
-
-acpi_status
-acpi_ps_find_object (
- struct acpi_walk_state *walk_state,
- union acpi_parse_object **out_op);
-
-void
-acpi_ps_delete_parse_tree (
- union acpi_parse_object *root);
-
-acpi_status
-acpi_ps_parse_loop (
- struct acpi_walk_state *walk_state);
-
+/*
+ * psparse - top level parsing routines
+ */
acpi_status
acpi_ps_parse_aml (
struct acpi_walk_state *walk_state);
-acpi_status
-acpi_ps_parse_table (
- u8 *aml,
- u32 aml_size,
- acpi_parse_downwards descending_callback,
- acpi_parse_upwards ascending_callback,
- union acpi_parse_object **root_object);
+u32
+acpi_ps_get_opcode_size (
+ u32 opcode);
u16
acpi_ps_peek_opcode (
struct acpi_parse_state *state);
-/* psscope - Scope stack management routines */
-
-
+/*
+ * psscope - Scope stack management routines
+ */
acpi_status
acpi_ps_init_scope (
struct acpi_parse_state *parser_state,
@@ -228,8 +194,9 @@ acpi_ps_cleanup_scope (
struct acpi_parse_state *state);
-/* pstree - parse tree manipulation routines */
-
+/*
+ * pstree - parse tree manipulation routines
+ */
void
acpi_ps_append_arg(
union acpi_parse_object *op,
@@ -247,20 +214,17 @@ acpi_ps_get_arg(
union acpi_parse_object *op,
u32 argn);
-#ifdef ACPI_FUTURE_USAGE
-union acpi_parse_object *
-acpi_ps_get_child (
- union acpi_parse_object *op);
-
+#ifdef ACPI_FUTURE_USAGE
union acpi_parse_object *
acpi_ps_get_depth_next (
union acpi_parse_object *origin,
union acpi_parse_object *op);
-#endif /* ACPI_FUTURE_USAGE */
-
+#endif /* ACPI_FUTURE_USAGE */
-/* pswalk - parse tree walk routines */
+/*
+ * pswalk - parse tree walk routines
+ */
acpi_status
acpi_ps_walk_parsed_aml (
union acpi_parse_object *start_op,
@@ -283,9 +247,14 @@ acpi_status
acpi_ps_delete_completed_op (
struct acpi_walk_state *walk_state);
+void
+acpi_ps_delete_parse_tree (
+ union acpi_parse_object *root);
-/* psutils - parser utilities */
+/*
+ * psutils - parser utilities
+ */
union acpi_parse_object *
acpi_ps_create_scope_op (
void);
@@ -303,12 +272,6 @@ void
acpi_ps_free_op (
union acpi_parse_object *op);
-#ifdef ACPI_ENABLE_OBJECT_CACHE
-void
-acpi_ps_delete_parse_cache (
- void);
-#endif
-
u8
acpi_ps_is_leading_char (
u32 c);
@@ -317,20 +280,27 @@ u8
acpi_ps_is_prefix_char (
u32 c);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
u32
acpi_ps_get_name(
union acpi_parse_object *op);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
void
acpi_ps_set_name(
union acpi_parse_object *op,
u32 name);
+#ifdef ACPI_ENABLE_OBJECT_CACHE
+void
+acpi_ps_delete_parse_cache (
+ void);
+#endif
-/* psdump - display parser tree */
+/*
+ * psdump - display parser tree
+ */
u32
acpi_ps_sprint_path (
char *buffer_start,
diff --git a/include/acpi/acpi.h b/include/acpi/acpi.h
index ad53252dd42d..a69d78942040 100644
--- a/include/acpi/acpi.h
+++ b/include/acpi/acpi.h
@@ -49,6 +49,7 @@
* We put them here because we don't want to duplicate them
* in the rest of the source code again and again.
*/
+#include "acnames.h" /* Global ACPI names and strings */
#include "acconfig.h" /* Configuration constants */
#include "platform/acenv.h" /* Target environment specific items */
#include "actypes.h" /* Fundamental common data types */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index c627bc408a6b..8d0e1290bc76 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -108,6 +108,21 @@ typedef int (*acpi_op_unbind) (struct acpi_device *device);
typedef int (*acpi_op_match) (struct acpi_device *device,
struct acpi_driver *driver);
+struct acpi_bus_ops {
+ u32 acpi_op_add:1;
+ u32 acpi_op_remove:1;
+ u32 acpi_op_lock:1;
+ u32 acpi_op_start:1;
+ u32 acpi_op_stop:1;
+ u32 acpi_op_suspend:1;
+ u32 acpi_op_resume:1;
+ u32 acpi_op_scan:1;
+ u32 acpi_op_bind:1;
+ u32 acpi_op_unbind:1;
+ u32 acpi_op_match:1;
+ u32 reserved:21;
+};
+
struct acpi_device_ops {
acpi_op_add add;
acpi_op_remove remove;
@@ -327,15 +342,36 @@ int acpi_bus_generate_event (struct acpi_device *device, u8 type, int data);
int acpi_bus_receive_event (struct acpi_bus_event *event);
int acpi_bus_register_driver (struct acpi_driver *driver);
int acpi_bus_unregister_driver (struct acpi_driver *driver);
-int acpi_bus_scan (struct acpi_device *start);
int acpi_bus_add (struct acpi_device **child, struct acpi_device *parent,
acpi_handle handle, int type);
+int acpi_bus_start (struct acpi_device *device);
int acpi_match_ids (struct acpi_device *device, char *ids);
int acpi_create_dir(struct acpi_device *);
void acpi_remove_dir(struct acpi_device *);
+
+/*
+ * Bind physical devices with ACPI devices
+ */
+#include <linux/device.h>
+struct acpi_bus_type {
+ struct list_head list;
+ struct bus_type *bus;
+ /* For general devices under the bus*/
+ int (*find_device)(struct device *, acpi_handle*);
+ /* For bridges, such as PCI root bridge, IDE controller */
+ int (*find_bridge)(struct device *, acpi_handle *);
+};
+int register_acpi_bus_type(struct acpi_bus_type *);
+int unregister_acpi_bus_type(struct acpi_bus_type *);
+struct device *acpi_get_physical_device(acpi_handle);
+/* helper */
+acpi_handle acpi_get_child(acpi_handle, acpi_integer);
+acpi_handle acpi_get_pci_rootbridge_handle(unsigned int, unsigned int);
+#define DEVICE_ACPI_HANDLE(dev) ((acpi_handle)((dev)->firmware_data))
+
#endif /*CONFIG_ACPI_BUS*/
#endif /*__ACPI_BUS_H__*/
diff --git a/include/acpi/acpi_drivers.h b/include/acpi/acpi_drivers.h
index c62e92ec43b2..caeaa71a5663 100644
--- a/include/acpi/acpi_drivers.h
+++ b/include/acpi/acpi_drivers.h
@@ -68,6 +68,7 @@ void acpi_pci_irq_del_prt (int segment, int bus);
struct pci_bus;
+acpi_status acpi_get_pci_id (acpi_handle handle, struct acpi_pci_id *id);
int acpi_pci_bind (struct acpi_device *device);
int acpi_pci_unbind (struct acpi_device *device);
int acpi_pci_bind_root (struct acpi_device *device, struct acpi_pci_id *id, struct pci_bus *bus);
@@ -108,5 +109,10 @@ int acpi_ec_ecdt_probe (void);
int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
+/* --------------------------------------------------------------------------
+ Hot Keys
+ -------------------------------------------------------------------------- */
+
+extern int acpi_specific_hotkey_enabled;
#endif /*__ACPI_DRIVERS_H__*/
diff --git a/include/acpi/acpiosxf.h b/include/acpi/acpiosxf.h
index 857c8072eb1e..ea489f235216 100644
--- a/include/acpi/acpiosxf.h
+++ b/include/acpi/acpiosxf.h
@@ -79,7 +79,6 @@ struct acpi_signal_fatal_info
/*
* OSL Initialization and shutdown primitives
*/
-
acpi_status
acpi_os_initialize (
void);
@@ -92,7 +91,6 @@ acpi_os_terminate (
/*
* ACPI Table interfaces
*/
-
acpi_status
acpi_os_get_root_pointer (
u32 flags,
@@ -112,7 +110,6 @@ acpi_os_table_override (
/*
* Synchronization primitives
*/
-
acpi_status
acpi_os_create_semaphore (
u32 max_units,
@@ -156,7 +153,6 @@ acpi_os_release_lock (
/*
* Memory allocation and mapping
*/
-
void *
acpi_os_allocate (
acpi_size size);
@@ -187,7 +183,6 @@ acpi_os_get_physical_address (
/*
* Interrupt handlers
*/
-
acpi_status
acpi_os_install_interrupt_handler (
u32 gsi,
@@ -203,7 +198,6 @@ acpi_os_remove_interrupt_handler (
/*
* Threads and Scheduling
*/
-
u32
acpi_os_get_thread_id (
void);
@@ -234,7 +228,6 @@ acpi_os_stall (
/*
* Platform and hardware-independent I/O interfaces
*/
-
acpi_status
acpi_os_read_port (
acpi_io_address address,
@@ -251,7 +244,6 @@ acpi_os_write_port (
/*
* Platform and hardware-independent physical memory interfaces
*/
-
acpi_status
acpi_os_read_memory (
acpi_physical_address address,
@@ -270,7 +262,6 @@ acpi_os_write_memory (
* Note: Can't use "Register" as a parameter, changed to "Reg" --
* certain compilers complain.
*/
-
acpi_status
acpi_os_read_pci_configuration (
struct acpi_pci_id *pci_id,
@@ -288,7 +279,6 @@ acpi_os_write_pci_configuration (
/*
* Interim function needed for PCI IRQ routing
*/
-
void
acpi_os_derive_pci_id(
acpi_handle rhandle,
@@ -298,7 +288,6 @@ acpi_os_derive_pci_id(
/*
* Miscellaneous
*/
-
u8
acpi_os_readable (
void *pointer,
@@ -323,7 +312,6 @@ acpi_os_signal (
/*
* Debug print routines
*/
-
void ACPI_INTERNAL_VAR_XFACE
acpi_os_printf (
const char *format,
@@ -339,11 +327,10 @@ acpi_os_redirect_output (
void *destination);
+#ifdef ACPI_FUTURE_USAGE
/*
* Debug input
*/
-
-#ifdef ACPI_FUTURE_USAGE
u32
acpi_os_get_line (
char *buffer);
@@ -353,7 +340,6 @@ acpi_os_get_line (
/*
* Directory manipulation
*/
-
void *
acpi_os_open_directory (
char *pathname,
@@ -377,7 +363,6 @@ acpi_os_close_directory (
/*
* Debug
*/
-
void
acpi_os_dbg_assert(
void *failed_assertion,
@@ -385,5 +370,4 @@ acpi_os_dbg_assert(
u32 line_number,
char *message);
-
#endif /* __ACPIOSXF_H__ */
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index 00d78b79652e..f8f619f8e4f8 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -50,10 +50,9 @@
#include "actbl.h"
- /*
+/*
* Global interfaces
*/
-
acpi_status
acpi_initialize_subsystem (
void);
@@ -106,9 +105,8 @@ acpi_install_initialization_handler (
#endif
/*
- * ACPI Memory manager
+ * ACPI Memory managment
*/
-
void *
acpi_allocate (
u32 size);
@@ -125,7 +123,6 @@ acpi_free (
/*
* ACPI table manipulation interfaces
*/
-
acpi_status
acpi_find_root_pointer (
u32 flags,
@@ -168,7 +165,6 @@ acpi_get_firmware_table (
/*
* Namespace and name interfaces
*/
-
acpi_status
acpi_walk_namespace (
acpi_object_type type,
@@ -218,7 +214,6 @@ acpi_get_data (
/*
* Object manipulation and enumeration
*/
-
acpi_status
acpi_evaluate_object (
acpi_handle object,
@@ -262,7 +257,6 @@ acpi_get_parent (
/*
* Event handler interfaces
*/
-
acpi_status
acpi_install_fixed_event_handler (
u32 acpi_event,
@@ -319,7 +313,6 @@ acpi_install_exception_handler (
/*
* Event interfaces
*/
-
acpi_status
acpi_acquire_global_lock (
u16 timeout,
@@ -404,7 +397,6 @@ acpi_remove_gpe_block (
/*
* Resource interfaces
*/
-
typedef
acpi_status (*ACPI_WALK_RESOURCE_CALLBACK) (
struct acpi_resource *resource,
@@ -448,7 +440,6 @@ acpi_resource_to_address64 (
/*
* Hardware (ACPI device) interfaces
*/
-
acpi_status
acpi_get_register (
u32 register_id,
diff --git a/include/acpi/acresrc.h b/include/acpi/acresrc.h
index 93c55ff5c237..ed679264c12c 100644
--- a/include/acpi/acresrc.h
+++ b/include/acpi/acresrc.h
@@ -48,7 +48,6 @@
/*
* Function prototypes called from Acpi* APIs
*/
-
acpi_status
acpi_rs_get_prt_method_data (
acpi_handle handle,
@@ -60,12 +59,12 @@ acpi_rs_get_crs_method_data (
acpi_handle handle,
struct acpi_buffer *ret_buffer);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_rs_get_prs_method_data (
acpi_handle handle,
struct acpi_buffer *ret_buffer);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
acpi_status
acpi_rs_get_method_data (
@@ -95,61 +94,9 @@ acpi_rs_create_pci_routing_table (
/*
- * Function prototypes called from acpi_rs_create*
+ * rsdump
*/
-#ifdef ACPI_FUTURE_USAGE
-void
-acpi_rs_dump_irq (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_address16 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_address32 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_address64 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_dma (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_io (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_extended_irq (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_fixed_io (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_fixed_memory32 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_memory24 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_memory32 (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_start_depend_fns (
- union acpi_resource_data *data);
-
-void
-acpi_rs_dump_vendor_specific (
- union acpi_resource_data *data);
-
+#ifdef ACPI_FUTURE_USAGE
void
acpi_rs_dump_resource_list (
struct acpi_resource *resource);
@@ -157,8 +104,12 @@ acpi_rs_dump_resource_list (
void
acpi_rs_dump_irq_list (
u8 *route_table);
-#endif /* ACPI_FUTURE_USAGE */
+#endif /* ACPI_FUTURE_USAGE */
+
+/*
+ * rscalc
+ */
acpi_status
acpi_rs_get_byte_stream_start (
u8 *byte_stream_buffer,
diff --git a/include/acpi/acstruct.h b/include/acpi/acstruct.h
index c97843f6bcbc..e6b9e36a2eda 100644
--- a/include/acpi/acstruct.h
+++ b/include/acpi/acstruct.h
@@ -56,7 +56,6 @@
* Walk state - current state of a parse tree walk. Used for both a leisurely stroll through
* the tree (for whatever reason), and for control method execution.
*/
-
#define ACPI_NEXT_OP_DOWNWARD 1
#define ACPI_NEXT_OP_UPWARD 2
diff --git a/include/acpi/actables.h b/include/acpi/actables.h
index e8f5d4ffd452..39df92e21a0d 100644
--- a/include/acpi/actables.h
+++ b/include/acpi/actables.h
@@ -50,17 +50,9 @@
#define SIZE_IN_HEADER 0
-#ifdef ACPI_FUTURE_USAGE
-acpi_status
-acpi_tb_handle_to_object (
- u16 table_id,
- struct acpi_table_desc **table_desc);
-#endif
-
/*
* tbconvrt - Table conversion routines
*/
-
acpi_status
acpi_tb_convert_to_xsdt (
struct acpi_table_desc *table_info);
@@ -78,10 +70,10 @@ acpi_tb_get_table_count (
struct rsdp_descriptor *RSDP,
struct acpi_table_header *RSDT);
+
/*
* tbget - Table "get" routines
*/
-
acpi_status
acpi_tb_get_table (
struct acpi_pointer *address,
@@ -99,17 +91,6 @@ acpi_tb_get_table_body (
struct acpi_table_desc *table_info);
acpi_status
-acpi_tb_get_this_table (
- struct acpi_pointer *address,
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_table_override (
- struct acpi_table_header *header,
- struct acpi_table_desc *table_info);
-
-acpi_status
acpi_tb_get_table_ptr (
acpi_table_type table_type,
u32 instance,
@@ -127,36 +108,23 @@ acpi_status
acpi_tb_validate_rsdt (
struct acpi_table_header *table_ptr);
+
+/*
+ * tbgetall - get multiple required tables
+ */
acpi_status
acpi_tb_get_required_tables (
void);
-acpi_status
-acpi_tb_get_primary_table (
- struct acpi_pointer *address,
- struct acpi_table_desc *table_info);
-
-acpi_status
-acpi_tb_get_secondary_table (
- struct acpi_pointer *address,
- acpi_string signature,
- struct acpi_table_desc *table_info);
/*
* tbinstall - Table installation
*/
-
acpi_status
acpi_tb_install_table (
struct acpi_table_desc *table_info);
acpi_status
-acpi_tb_match_signature (
- char *signature,
- struct acpi_table_desc *table_info,
- u8 search_type);
-
-acpi_status
acpi_tb_recognize_table (
struct acpi_table_desc *table_info,
u8 search_type);
@@ -170,7 +138,6 @@ acpi_tb_init_table_descriptor (
/*
* tbremove - Table removal and deletion
*/
-
void
acpi_tb_delete_all_tables (
void);
@@ -189,35 +156,23 @@ acpi_tb_uninstall_table (
/*
- * tbrsd - RSDP, RSDT utilities
+ * tbxfroot - RSDP, RSDT utilities
*/
+acpi_status
+acpi_tb_find_table (
+ char *signature,
+ char *oem_id,
+ char *oem_table_id,
+ struct acpi_table_header **table_ptr);
acpi_status
acpi_tb_get_table_rsdt (
void);
-u8 *
-acpi_tb_scan_memory_for_rsdp (
- u8 *start_address,
- u32 length);
-
-acpi_status
-acpi_tb_find_rsdp (
- struct acpi_table_desc *table_info,
- u32 flags);
-
/*
* tbutils - common table utilities
*/
-
-acpi_status
-acpi_tb_find_table (
- char *signature,
- char *oem_id,
- char *oem_table_id,
- struct acpi_table_header **table_ptr);
-
acpi_status
acpi_tb_verify_table_checksum (
struct acpi_table_header *table_header);
@@ -231,5 +186,4 @@ acpi_status
acpi_tb_validate_table_header (
struct acpi_table_header *table_header);
-
#endif /* __ACTABLES_H__ */
diff --git a/include/acpi/actbl.h b/include/acpi/actbl.h
index 7eee731112b1..b5cdcca444c8 100644
--- a/include/acpi/actbl.h
+++ b/include/acpi/actbl.h
@@ -133,7 +133,6 @@ struct acpi_table_header /* ACPI common table header */
#define DUAL_PIC 0
#define MULTIPLE_APIC 1
-
/* Master MADT */
struct multiple_apic_table
@@ -144,7 +143,6 @@ struct multiple_apic_table
u32 reserved1 : 31;
};
-
/* Values for Type in APIC_HEADER_DEF */
#define APIC_PROCESSOR 0
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 7acb550af3eb..3a451dc48ac8 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -478,7 +478,6 @@ typedef u32 acpi_object_type;
#define ACPI_TYPE_INVALID 0x1E
#define ACPI_TYPE_NOT_FOUND 0xFF
-
/*
* Bitmapped ACPI types. Used internally only
*/
@@ -803,7 +802,6 @@ struct acpi_system_info
/*
* Types specific to the OS service interfaces
*/
-
typedef u32
(ACPI_SYSTEM_XFACE *acpi_osd_handler) (
void *context);
diff --git a/include/acpi/acutils.h b/include/acpi/acutils.h
index 0de26b8f1028..192d0bea3884 100644
--- a/include/acpi/acutils.h
+++ b/include/acpi/acutils.h
@@ -52,13 +52,6 @@ acpi_status (*acpi_pkg_callback) (
union acpi_generic_state *state,
void *context);
-acpi_status
-acpi_ut_walk_package_tree (
- union acpi_operand_object *source_object,
- void *target_object,
- acpi_pkg_callback walk_callback,
- void *context);
-
struct acpi_pkg_info
{
u8 *free_space;
@@ -79,37 +72,13 @@ struct acpi_pkg_info
#define DB_QWORD_DISPLAY 8
-/* Global initialization interfaces */
-
-void
-acpi_ut_init_globals (
- void);
-
-void
-acpi_ut_terminate (
- void);
-
-
/*
- * ut_init - miscellaneous initialization and shutdown
+ * utglobal - Global data structures and procedures
*/
-
-acpi_status
-acpi_ut_hardware_initialize (
- void);
-
void
-acpi_ut_subsystem_shutdown (
- void);
-
-acpi_status
-acpi_ut_validate_fadt (
+acpi_ut_init_globals (
void);
-/*
- * ut_global - Global data structures and procedures
- */
-
#if defined(ACPI_DEBUG_OUTPUT) || defined(ACPI_DEBUGGER)
char *
@@ -157,9 +126,24 @@ acpi_ut_allocate_owner_id (
/*
- * ut_clib - Local implementations of C library functions
+ * utinit - miscellaneous initialization and shutdown
*/
+acpi_status
+acpi_ut_hardware_initialize (
+ void);
+void
+acpi_ut_subsystem_shutdown (
+ void);
+
+acpi_status
+acpi_ut_validate_fadt (
+ void);
+
+
+/*
+ * utclib - Local implementations of C library functions
+ */
#ifndef ACPI_USE_SYSTEM_CLIBRARY
acpi_size
@@ -260,10 +244,10 @@ extern const u8 _acpi_ctype[];
#endif /* ACPI_USE_SYSTEM_CLIBRARY */
+
/*
- * ut_copy - Object construction and conversion interfaces
+ * utcopy - Object construction and conversion interfaces
*/
-
acpi_status
acpi_ut_build_simple_object(
union acpi_operand_object *obj,
@@ -278,30 +262,11 @@ acpi_ut_build_package_object (
u32 *space_used);
acpi_status
-acpi_ut_copy_ielement_to_eelement (
- u8 object_type,
- union acpi_operand_object *source_object,
- union acpi_generic_state *state,
- void *context);
-
-acpi_status
-acpi_ut_copy_ielement_to_ielement (
- u8 object_type,
- union acpi_operand_object *source_object,
- union acpi_generic_state *state,
- void *context);
-
-acpi_status
acpi_ut_copy_iobject_to_eobject (
union acpi_operand_object *obj,
struct acpi_buffer *ret_buffer);
acpi_status
-acpi_ut_copy_esimple_to_isimple(
- union acpi_object *user_obj,
- union acpi_operand_object **return_obj);
-
-acpi_status
acpi_ut_copy_eobject_to_iobject (
union acpi_object *obj,
union acpi_operand_object **internal_obj);
@@ -312,17 +277,6 @@ acpi_ut_copy_isimple_to_isimple (
union acpi_operand_object *dest_obj);
acpi_status
-acpi_ut_copy_ipackage_to_ipackage (
- union acpi_operand_object *source_obj,
- union acpi_operand_object *dest_obj,
- struct acpi_walk_state *walk_state);
-
-acpi_status
-acpi_ut_copy_simple_object (
- union acpi_operand_object *source_desc,
- union acpi_operand_object *dest_desc);
-
-acpi_status
acpi_ut_copy_iobject_to_iobject (
union acpi_operand_object *source_desc,
union acpi_operand_object **dest_desc,
@@ -330,9 +284,8 @@ acpi_ut_copy_iobject_to_iobject (
/*
- * ut_create - Object creation
+ * utcreate - Object creation
*/
-
acpi_status
acpi_ut_update_object_reference (
union acpi_operand_object *object,
@@ -340,9 +293,8 @@ acpi_ut_update_object_reference (
/*
- * ut_debug - Debug interfaces
+ * utdebug - Debug interfaces
*/
-
void
acpi_ut_init_stack_ptr_trace (
void);
@@ -440,11 +392,14 @@ acpi_ut_debug_print_raw (
/*
- * ut_delete - Object deletion
+ * utdelete - Object deletion and reference counts
*/
+void
+acpi_ut_add_reference (
+ union acpi_operand_object *object);
void
-acpi_ut_delete_internal_obj (
+acpi_ut_remove_reference (
union acpi_operand_object *object);
void
@@ -461,25 +416,8 @@ acpi_ut_delete_internal_object_list (
/*
- * ut_eval - object evaluation
+ * uteval - object evaluation
*/
-
-/* Method name strings */
-
-#define METHOD_NAME__HID "_HID"
-#define METHOD_NAME__CID "_CID"
-#define METHOD_NAME__UID "_UID"
-#define METHOD_NAME__ADR "_ADR"
-#define METHOD_NAME__STA "_STA"
-#define METHOD_NAME__REG "_REG"
-#define METHOD_NAME__SEG "_SEG"
-#define METHOD_NAME__BBN "_BBN"
-#define METHOD_NAME__PRT "_PRT"
-#define METHOD_NAME__CRS "_CRS"
-#define METHOD_NAME__PRS "_PRS"
-#define METHOD_NAME__PRW "_PRW"
-
-
acpi_status
acpi_ut_osi_implementation (
struct acpi_walk_state *walk_state);
@@ -522,39 +460,10 @@ acpi_ut_execute_sxds (
struct acpi_namespace_node *device_node,
u8 *highest);
-/*
- * ut_mutex - mutual exclusion interfaces
- */
-
-acpi_status
-acpi_ut_mutex_initialize (
- void);
-
-void
-acpi_ut_mutex_terminate (
- void);
-
-acpi_status
-acpi_ut_create_mutex (
- acpi_mutex_handle mutex_id);
-
-acpi_status
-acpi_ut_delete_mutex (
- acpi_mutex_handle mutex_id);
-
-acpi_status
-acpi_ut_acquire_mutex (
- acpi_mutex_handle mutex_id);
-
-acpi_status
-acpi_ut_release_mutex (
- acpi_mutex_handle mutex_id);
-
/*
- * ut_object - internal object create/delete/cache routines
+ * utobject - internal object create/delete/cache routines
*/
-
union acpi_operand_object *
acpi_ut_create_internal_object_dbg (
char *module_name,
@@ -587,50 +496,15 @@ union acpi_operand_object *
acpi_ut_create_string_object (
acpi_size string_size);
-
-/*
- * ut_ref_cnt - Object reference count management
- */
-
-void
-acpi_ut_add_reference (
- union acpi_operand_object *object);
-
-void
-acpi_ut_remove_reference (
- union acpi_operand_object *object);
-
-/*
- * ut_size - Object size routines
- */
-
-acpi_status
-acpi_ut_get_simple_object_size (
- union acpi_operand_object *obj,
- acpi_size *obj_length);
-
-acpi_status
-acpi_ut_get_package_object_size (
- union acpi_operand_object *obj,
- acpi_size *obj_length);
-
acpi_status
acpi_ut_get_object_size(
union acpi_operand_object *obj,
acpi_size *obj_length);
-acpi_status
-acpi_ut_get_element_length (
- u8 object_type,
- union acpi_operand_object *source_object,
- union acpi_generic_state *state,
- void *context);
-
/*
- * ut_state - Generic state creation/cache routines
+ * utstate - Generic state creation/cache routines
*/
-
void
acpi_ut_push_generic_state (
union acpi_generic_state **list_head,
@@ -666,14 +540,14 @@ acpi_ut_create_update_state_and_push (
u16 action,
union acpi_generic_state **state_list);
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
acpi_status
acpi_ut_create_pkg_state_and_push (
void *internal_object,
void *external_object,
u16 index,
union acpi_generic_state **state_list);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
union acpi_generic_state *
acpi_ut_create_control_state (
@@ -693,15 +567,10 @@ acpi_ut_delete_object_cache (
void);
#endif
+
/*
- * utmisc
+ * utmath
*/
-
-void
-acpi_ut_print_string (
- char *string,
- u8 max_length);
-
acpi_status
acpi_ut_divide (
acpi_integer in_dividend,
@@ -716,6 +585,25 @@ acpi_ut_short_divide (
acpi_integer *out_quotient,
u32 *out_remainder);
+/*
+ * utmisc
+ */
+acpi_status
+acpi_ut_walk_package_tree (
+ union acpi_operand_object *source_object,
+ void *target_object,
+ acpi_pkg_callback walk_callback,
+ void *context);
+
+char *
+acpi_ut_strupr (
+ char *src_string);
+
+void
+acpi_ut_print_string (
+ char *string,
+ u8 max_length);
+
u8
acpi_ut_valid_acpi_name (
u32 name);
@@ -734,11 +622,21 @@ acpi_ut_strtoul64 (
#define ACPI_ANY_BASE 0
-#ifdef ACPI_FUTURE_USAGE
-char *
-acpi_ut_strupr (
- char *src_string);
-#endif
+acpi_status
+acpi_ut_mutex_initialize (
+ void);
+
+void
+acpi_ut_mutex_terminate (
+ void);
+
+acpi_status
+acpi_ut_acquire_mutex (
+ acpi_mutex_handle mutex_id);
+
+acpi_status
+acpi_ut_release_mutex (
+ acpi_mutex_handle mutex_id);
u8 *
acpi_ut_get_resource_end_tag (
@@ -768,9 +666,8 @@ acpi_ut_display_init_pathname (
/*
- * Utalloc - memory allocation and object caching
+ * utalloc - memory allocation and object caching
*/
-
void *
acpi_ut_acquire_from_cache (
u32 list_id);
@@ -795,9 +692,6 @@ acpi_ut_initialize_buffer (
struct acpi_buffer *buffer,
acpi_size required_length);
-
-/* Memory allocation functions */
-
void *
acpi_ut_allocate (
acpi_size size,
@@ -812,9 +706,7 @@ acpi_ut_callocate (
char *module,
u32 line);
-
#ifdef ACPI_DBG_TRACK_ALLOCATIONS
-
void *
acpi_ut_allocate_and_track (
acpi_size size,
@@ -836,34 +728,11 @@ acpi_ut_free_and_track (
char *module,
u32 line);
-struct acpi_debug_mem_block *
-acpi_ut_find_allocation (
- u32 list_id,
- void *allocation);
-
-acpi_status
-acpi_ut_track_allocation (
- u32 list_id,
- struct acpi_debug_mem_block *address,
- acpi_size size,
- u8 alloc_type,
- u32 component,
- char *module,
- u32 line);
-
-acpi_status
-acpi_ut_remove_allocation (
- u32 list_id,
- struct acpi_debug_mem_block *address,
- u32 component,
- char *module,
- u32 line);
-
-#ifdef ACPI_FUTURE_USAGE
+#ifdef ACPI_FUTURE_USAGE
void
acpi_ut_dump_allocation_info (
void);
-#endif
+#endif /* ACPI_FUTURE_USAGE */
void
acpi_ut_dump_allocations (
@@ -871,5 +740,4 @@ acpi_ut_dump_allocations (
char *module);
#endif
-
#endif /* _ACUTILS_H */
diff --git a/include/acpi/amlcode.h b/include/acpi/amlcode.h
index 2ec538eac58e..55e97ed29190 100644
--- a/include/acpi/amlcode.h
+++ b/include/acpi/amlcode.h
@@ -146,8 +146,7 @@
/* prefixed opcodes */
-#define AML_EXTOP (u16) 0x005b
-
+#define AML_EXTOP (u16) 0x005b /* prefix for 2-byte opcodes */
#define AML_MUTEX_OP (u16) 0x5b01
#define AML_EVENT_OP (u16) 0x5b02
@@ -194,7 +193,6 @@
* Use only "Unknown" AML opcodes, don't attempt to use
* any valid ACPI ASCII values (A-Z, 0-9, '-')
*/
-
#define AML_INT_NAMEPATH_OP (u16) 0x002d
#define AML_INT_NAMEDFIELD_OP (u16) 0x0030
#define AML_INT_RESERVEDFIELD_OP (u16) 0x0031
@@ -214,7 +212,6 @@
* There can be up to 31 unique argument types
* Zero is reserved as end-of-list indicator
*/
-
#define ARGP_BYTEDATA 0x01
#define ARGP_BYTELIST 0x02
#define ARGP_CHARLIST 0x03
@@ -295,7 +292,6 @@
/*
* opcode groups and types
*/
-
#define OPGRP_NAMED 0x01
#define OPGRP_FIELD 0x02
#define OPGRP_BYTELIST 0x04
@@ -381,6 +377,12 @@
#define AML_TYPE_UNDEFINED 0x19
#define AML_TYPE_BOGUS 0x1A
+/* AML Package Length encodings */
+
+#define ACPI_AML_PACKAGE_TYPE1 0x40
+#define ACPI_AML_PACKAGE_TYPE2 0x4000
+#define ACPI_AML_PACKAGE_TYPE3 0x400000
+#define ACPI_AML_PACKAGE_TYPE4 0x40000000
/*
* Opcode classes
diff --git a/include/acpi/pdc_intel.h b/include/acpi/pdc_intel.h
new file mode 100644
index 000000000000..fd6730e4e567
--- /dev/null
+++ b/include/acpi/pdc_intel.h
@@ -0,0 +1,29 @@
+
+/* _PDC bit definition for Intel processors */
+
+#ifndef __PDC_INTEL_H__
+#define __PDC_INTEL_H__
+
+#define ACPI_PDC_P_FFH (0x0001)
+#define ACPI_PDC_C_C1_HALT (0x0002)
+#define ACPI_PDC_T_FFH (0x0004)
+#define ACPI_PDC_SMP_C1PT (0x0008)
+#define ACPI_PDC_SMP_C2C3 (0x0010)
+#define ACPI_PDC_SMP_P_SWCOORD (0x0020)
+#define ACPI_PDC_SMP_C_SWCOORD (0x0040)
+#define ACPI_PDC_SMP_T_SWCOORD (0x0080)
+#define ACPI_PDC_C_C1_FFH (0x0100)
+
+
+#define ACPI_PDC_EST_CAPABILITY_SMP (ACPI_PDC_SMP_C1PT | \
+ ACPI_PDC_C_C1_HALT)
+
+#define ACPI_PDC_EST_CAPABILITY_SMP_MSR (ACPI_PDC_EST_CAPABILITY_SMP | \
+ ACPI_PDC_P_FFH)
+
+#define ACPI_PDC_C_CAPABILITY_SMP (ACPI_PDC_SMP_C2C3 | \
+ ACPI_PDC_SMP_C1PT | \
+ ACPI_PDC_C_C1_HALT)
+
+#endif /* __PDC_INTEL_H__ */
+
diff --git a/include/acpi/platform/acenv.h b/include/acpi/platform/acenv.h
index 57bf9362335d..adf969efa510 100644
--- a/include/acpi/platform/acenv.h
+++ b/include/acpi/platform/acenv.h
@@ -198,6 +198,7 @@
#endif
#endif /* !DEBUGGER_THREADING */
+
/******************************************************************************
*
* C library configuration
@@ -209,7 +210,6 @@
* Use the standard C library headers.
* We want to keep these to a minimum.
*/
-
#ifdef ACPI_USE_STANDARD_HEADERS
/*
* Use the standard headers from the standard locations
@@ -224,14 +224,8 @@
/*
* We will be linking to the standard Clib functions
*/
-
#define ACPI_STRSTR(s1,s2) strstr((s1), (s2))
#define ACPI_STRCHR(s1,c) strchr((s1), (c))
-
-#ifdef ACPI_FUTURE_USAGE
-#define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s))
-#endif
-
#define ACPI_STRLEN(s) (acpi_size) strlen((s))
#define ACPI_STRCPY(d,s) (void) strcpy((d), (s))
#define ACPI_STRNCPY(d,s,n) (void) strncpy((d), (s), (acpi_size)(n))
@@ -254,14 +248,15 @@
#define ACPI_IS_ALPHA isalpha
#define ACPI_IS_ASCII isascii
+#else
+
/******************************************************************************
*
* Not using native C library, use local implementations
*
*****************************************************************************/
-#else
-/*
+ /*
* Use local definitions of C library macros and functions
* NOTE: The function implementations may not be as efficient
* as an inline or assembly code implementation provided by a
@@ -278,14 +273,12 @@ typedef char *va_list;
/*
* Storage alignment properties
*/
-
#define _AUPBND (sizeof (acpi_native_int) - 1)
#define _ADNBND (sizeof (acpi_native_int) - 1)
/*
* Variable argument list macro definitions
*/
-
#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
#define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T, _AUPBND))) - (_bnd (T,_ADNBND))))
#define va_end(ap) (void) 0
@@ -296,11 +289,6 @@ typedef char *va_list;
#define ACPI_STRSTR(s1,s2) acpi_ut_strstr ((s1), (s2))
#define ACPI_STRCHR(s1,c) acpi_ut_strchr ((s1), (c))
-
-#ifdef ACPI_FUTURE_USAGE
-#define ACPI_STRUPR(s) (void) acpi_ut_strupr ((s))
-#endif
-
#define ACPI_STRLEN(s) (acpi_size) acpi_ut_strlen ((s))
#define ACPI_STRCPY(d,s) (void) acpi_ut_strcpy ((d), (s))
#define ACPI_STRNCPY(d,s,n) (void) acpi_ut_strncpy ((d), (s), (acpi_size)(n))
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 2f50a5bb0c78..50cfea4ff6ca 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -4,6 +4,8 @@
#include <linux/kernel.h>
#include <linux/config.h>
+#include <asm/acpi.h>
+
#define ACPI_PROCESSOR_BUSY_METRIC 10
#define ACPI_PROCESSOR_MAX_POWER 8
@@ -14,6 +16,8 @@
#define ACPI_PROCESSOR_MAX_THROTTLE 250 /* 25% */
#define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4
+#define ACPI_PDC_REVISION_ID 0x1
+
/* Power Management */
struct acpi_processor_cx;
@@ -59,6 +63,9 @@ struct acpi_processor_power {
u32 bm_activity;
int count;
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
+
+ /* the _PDC objects passed by the driver, if any */
+ struct acpi_object_list *pdc;
};
/* Performance Management */
@@ -82,8 +89,6 @@ struct acpi_processor_px {
acpi_integer status; /* success indicator */
};
-#define ACPI_PDC_REVISION_ID 0x1
-
struct acpi_processor_performance {
unsigned int state;
unsigned int platform_limit;
@@ -179,7 +184,32 @@ int acpi_processor_notify_smm(struct module *calling_module);
extern struct acpi_processor *processors[NR_CPUS];
extern struct acpi_processor_errata errata;
+int acpi_processor_set_pdc(struct acpi_processor *pr,
+ struct acpi_object_list *pdc_in);
+
+#ifdef ARCH_HAS_POWER_PDC_INIT
+void acpi_processor_power_init_pdc(struct acpi_processor_power *pow,
+ unsigned int cpu);
+void acpi_processor_power_init_bm_check(struct acpi_processor_flags *flags,
+ unsigned int cpu);
+#else
+static inline void acpi_processor_power_init_pdc(
+ struct acpi_processor_power *pow, unsigned int cpu)
+{
+ pow->pdc = NULL;
+ return;
+}
+
+static inline void acpi_processor_power_init_bm_check(
+ struct acpi_processor_flags *flags, unsigned int cpu)
+{
+ flags->bm_check = 1;
+ return;
+}
+#endif
+
/* in processor_perflib.c */
+
#ifdef CONFIG_CPU_FREQ
void acpi_processor_ppc_init(void);
void acpi_processor_ppc_exit(void);
diff --git a/include/asm-alpha/pci.h b/include/asm-alpha/pci.h
index 0c7b57bc043a..28957697e59c 100644
--- a/include/asm-alpha/pci.h
+++ b/include/asm-alpha/pci.h
@@ -58,7 +58,7 @@ struct pci_controller {
extern void pcibios_set_master(struct pci_dev *dev);
-extern inline void pcibios_penalize_isa_irq(int irq)
+extern inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -223,6 +223,25 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
/* Nothing to do. */
}
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ unsigned long cacheline_size;
+ u8 byte;
+
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ *strat = PCI_DMA_BURST_BOUNDARY;
+ *strategy_parameter = cacheline_size;
+}
+#endif
+
/* TODO: integrate with include/asm-generic/pci.h ? */
static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
{
diff --git a/include/asm-alpha/pgtable.h b/include/asm-alpha/pgtable.h
index 408aea55e0cc..22b53e369f59 100644
--- a/include/asm-alpha/pgtable.h
+++ b/include/asm-alpha/pgtable.h
@@ -133,6 +133,12 @@
#define __S111 _PAGE_S(0)
/*
+ * pgprot_noncached() is only for infiniband pci support, and a real
+ * implementation for RAM would be more complicated.
+ */
+#define pgprot_noncached(prot) (prot)
+
+/*
* BAD_PAGETABLE is used when we need a bogus page-table, while
* BAD_PAGE is used for a bogus page.
*
diff --git a/include/asm-alpha/serial.h b/include/asm-alpha/serial.h
index 7b2d9ee95a44..7e4b2987d453 100644
--- a/include/asm-alpha/serial.h
+++ b/include/asm-alpha/serial.h
@@ -22,54 +22,9 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS
diff --git a/include/asm-arm/arch-ixp2000/gpio.h b/include/asm-arm/arch-ixp2000/gpio.h
index 84634af5cc64..03cbbe1fd9d8 100644
--- a/include/asm-arm/arch-ixp2000/gpio.h
+++ b/include/asm-arm/arch-ixp2000/gpio.h
@@ -1,5 +1,5 @@
/*
- * include/asm-arm/arch-ixp2000/ixp2000-gpio.h
+ * include/asm-arm/arch-ixp2000/gpio.h
*
* Copyright (C) 2002 Intel Corporation.
*
@@ -16,26 +16,18 @@
* Use this instead of directly setting the GPIO registers.
* GPIOs may also be used as GPIOs (e.g. for emulating i2c/smb)
*/
-#ifndef _ASM_ARCH_IXP2000_GPIO_H_
-#define _ASM_ARCH_IXP2000_GPIO_H_
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
#ifndef __ASSEMBLY__
-#define GPIO_OUT 0x0
-#define GPIO_IN 0x80
+
+#define GPIO_IN 0
+#define GPIO_OUT 1
#define IXP2000_GPIO_LOW 0
#define IXP2000_GPIO_HIGH 1
-#define GPIO_NO_EDGES 0
-#define GPIO_FALLING_EDGE 1
-#define GPIO_RISING_EDGE 2
-#define GPIO_BOTH_EDGES 3
-#define GPIO_LEVEL_LOW 4
-#define GPIO_LEVEL_HIGH 8
-
-extern void set_GPIO_IRQ_edge(int gpio_nr, int edge);
-extern void set_GPIO_IRQ_level(int gpio_nr, int level);
-extern void gpio_line_config(int line, int style);
+extern void gpio_line_config(int line, int direction);
static inline int gpio_line_get(int line)
{
@@ -45,11 +37,12 @@ static inline int gpio_line_get(int line)
static inline void gpio_line_set(int line, int value)
{
if (value == IXP2000_GPIO_HIGH) {
- ixp_reg_write(IXP2000_GPIO_POSR, BIT(line));
- } else if (value == IXP2000_GPIO_LOW)
- ixp_reg_write(IXP2000_GPIO_POCR, BIT(line));
+ ixp2000_reg_write(IXP2000_GPIO_POSR, 1 << line);
+ } else if (value == IXP2000_GPIO_LOW) {
+ ixp2000_reg_write(IXP2000_GPIO_POCR, 1 << line);
+ }
}
#endif /* !__ASSEMBLY__ */
-#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
+#endif /* ASM_ARCH_IXP2000_GPIO_H_ */
diff --git a/include/asm-arm/arch-ixp2000/io.h b/include/asm-arm/arch-ixp2000/io.h
index 083462668e18..3241cd6f0778 100644
--- a/include/asm-arm/arch-ixp2000/io.h
+++ b/include/asm-arm/arch-ixp2000/io.h
@@ -17,18 +17,23 @@
#define IO_SPACE_LIMIT 0xffffffff
#define __mem_pci(a) (a)
-#define ___io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
/*
- * The IXP2400 before revision B0 asserts byte lanes for PCI I/O
+ * The A? revisions of the IXP2000s assert byte lanes for PCI I/O
* transactions the other way round (MEM transactions don't have this
- * issue), so we need to override the standard functions. B0 and later
- * have a bit that can be set to 1 to get the 'proper' behavior, but
- * since that isn't available on the A? revisions we just keep doing
- * things manually.
+ * issue), so if we want to support those models, we need to override
+ * the standard I/O functions.
+ *
+ * B0 and later have a bit that can be set to 1 to get the proper
+ * behavior for I/O transactions, which then allows us to use the
+ * standard I/O functions. This is what we do if the user does not
+ * explicitly ask for support for pre-B0.
*/
-#define alignb(addr) (void __iomem *)((unsigned long)addr ^ 3)
-#define alignw(addr) (void __iomem *)((unsigned long)addr ^ 2)
+#ifdef CONFIG_IXP2000_SUPPORT_BROKEN_PCI_IO
+#define ___io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
+
+#define alignb(addr) (void __iomem *)((unsigned long)(addr) ^ 3)
+#define alignw(addr) (void __iomem *)((unsigned long)(addr) ^ 2)
#define outb(v,p) __raw_writeb((v),alignb(___io(p)))
#define outw(v,p) __raw_writew((v),alignw(___io(p)))
@@ -48,6 +53,81 @@
#define insw(p,d,l) __raw_readsw(alignw(___io(p)),d,l)
#define insl(p,d,l) __raw_readsl(___io(p),d,l)
+#define __is_io_address(p) ((((unsigned long)(p)) & ~(IXP2000_PCI_IO_SIZE - 1)) == IXP2000_PCI_IO_VIRT_BASE)
+
+#define ioread8(p) \
+ ({ \
+ unsigned int __v; \
+ \
+ if (__is_io_address(p)) { \
+ __v = __raw_readb(alignb(p)); \
+ } else { \
+ __v = __raw_readb(p); \
+ } \
+ \
+ __v; \
+ }) \
+
+#define ioread16(p) \
+ ({ \
+ unsigned int __v; \
+ \
+ if (__is_io_address(p)) { \
+ __v = __raw_readw(alignw(p)); \
+ } else { \
+ __v = le16_to_cpu(__raw_readw(p)); \
+ } \
+ \
+ __v; \
+ })
+
+#define ioread32(p) \
+ ({ \
+ unsigned int __v; \
+ \
+ if (__is_io_address(p)) { \
+ __v = __raw_readl(p); \
+ } else { \
+ __v = le32_to_cpu(__raw_readl(p)); \
+ } \
+ \
+ __v; \
+ })
+
+#define iowrite8(v,p) \
+ ({ \
+ if (__is_io_address(p)) { \
+ __raw_writeb((v), alignb(p)); \
+ } else { \
+ __raw_writeb((v), p); \
+ } \
+ })
+
+#define iowrite16(v,p) \
+ ({ \
+ if (__is_io_address(p)) { \
+ __raw_writew((v), alignw(p)); \
+ } else { \
+ __raw_writew(cpu_to_le16(v), p); \
+ } \
+ })
+
+#define iowrite32(v,p) \
+ ({ \
+ if (__is_io_address(p)) { \
+ __raw_writel((v), p); \
+ } else { \
+ __raw_writel(cpu_to_le32(v), p); \
+ } \
+ })
+
+#define ioport_map(port, nr) ___io(port)
+
+#define ioport_unmap(addr)
+#else
+#define __io(p) ((void __iomem *)((p)+IXP2000_PCI_IO_VIRT_BASE))
+#endif
+
#ifdef CONFIG_ARCH_IXDP2X01
/*
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x00.h b/include/asm-arm/arch-ixp2000/ixdp2x00.h
index 3a398dfbf125..229381c64283 100644
--- a/include/asm-arm/arch-ixp2000/ixdp2x00.h
+++ b/include/asm-arm/arch-ixp2000/ixdp2x00.h
@@ -21,8 +21,8 @@
* On board CPLD memory map
*/
#define IXDP2X00_PHYS_CPLD_BASE 0xc7000000
-#define IXDP2X00_VIRT_CPLD_BASE 0xfafff000
-#define IXDP2X00_CPLD_SIZE 0x00001000
+#define IXDP2X00_VIRT_CPLD_BASE 0xfe000000
+#define IXDP2X00_CPLD_SIZE 0x00100000
#define IXDP2X00_CPLD_REG(x) \
diff --git a/include/asm-arm/arch-ixp2000/ixdp2x01.h b/include/asm-arm/arch-ixp2000/ixdp2x01.h
index b3a1bcda8d01..b768009c3a51 100644
--- a/include/asm-arm/arch-ixp2000/ixdp2x01.h
+++ b/include/asm-arm/arch-ixp2000/ixdp2x01.h
@@ -18,8 +18,8 @@
#define __IXDP2X01_H__
#define IXDP2X01_PHYS_CPLD_BASE 0xc6024000
-#define IXDP2X01_VIRT_CPLD_BASE 0xfafff000
-#define IXDP2X01_CPLD_REGION_SIZE 0x00001000
+#define IXDP2X01_VIRT_CPLD_BASE 0xfe000000
+#define IXDP2X01_CPLD_REGION_SIZE 0x00100000
#define IXDP2X01_CPLD_VIRT_REG(reg) (volatile unsigned long*)(IXDP2X01_VIRT_CPLD_BASE | reg)
#define IXDP2X01_CPLD_PHYS_REG(reg) (volatile u32*)(IXDP2X01_PHYS_CPLD_BASE | reg)
diff --git a/include/asm-arm/arch-ixp2000/ixp2000-regs.h b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
index a1d9e181b10f..75623f81ef75 100644
--- a/include/asm-arm/arch-ixp2000/ixp2000-regs.h
+++ b/include/asm-arm/arch-ixp2000/ixp2000-regs.h
@@ -18,6 +18,21 @@
#ifndef _IXP2000_REGS_H_
#define _IXP2000_REGS_H_
+/*
+ * IXP2000 linux memory map:
+ *
+ * virt phys size
+ * fb000000 db000000 16M PCI CFG1
+ * fc000000 da000000 16M PCI CFG0
+ * fd000000 d8000000 16M PCI I/O
+ * fe[0-7]00000 8M per-platform mappings
+ * feb00000 c8000000 1M MSF
+ * fec00000 df000000 1M PCI CSRs
+ * fed00000 de000000 1M PCI CREG
+ * fee00000 d6000000 1M INTCTL
+ * fef00000 c0000000 1M CAP
+ */
+
/*
* Static I/O regions.
*
@@ -71,6 +86,10 @@
#define IXP2000_PCI_CSR_VIRT_BASE 0xfec00000
#define IXP2000_PCI_CSR_SIZE 0x00100000
+#define IXP2000_MSF_PHYS_BASE 0xc8000000
+#define IXP2000_MSF_VIRT_BASE 0xfeb00000
+#define IXP2000_MSF_SIZE 0x00100000
+
#define IXP2000_PCI_IO_PHYS_BASE 0xd8000000
#define IXP2000_PCI_IO_VIRT_BASE 0xfd000000
#define IXP2000_PCI_IO_SIZE 0x01000000
@@ -241,7 +260,7 @@
#define PCI_CONTROL_BE_DEI (1 << 21) /* Big Endian Data Enable In */
#define PCI_CONTROL_BE_BEO (1 << 20) /* Big Endian Byte Enable Out */
#define PCI_CONTROL_BE_BEI (1 << 19) /* Big Endian Byte Enable In */
-#define PCI_CONTROL_PNR (1 << 17) /* PCI Not Reset bit */
+#define PCI_CONTROL_IEE (1 << 17) /* I/O cycle Endian swap Enable */
#define IXP2000_PCI_RST_REL (1 << 2)
#define CFG_RST_DIR (*IXP2000_PCI_CONTROL & IXP2000_PCICNTL_PCF)
diff --git a/include/asm-arm/arch-ixp2000/platform.h b/include/asm-arm/arch-ixp2000/platform.h
index 901bba6d02b4..c0caf3e3e6fd 100644
--- a/include/asm-arm/arch-ixp2000/platform.h
+++ b/include/asm-arm/arch-ixp2000/platform.h
@@ -115,6 +115,7 @@ static inline unsigned int ixp2000_is_pcimaster(void)
}
void ixp2000_map_io(void);
+void ixp2000_uart_init(void);
void ixp2000_init_irq(void);
void ixp2000_init_time(unsigned long);
unsigned long ixp2000_gettimeoffset(void);
@@ -138,30 +139,10 @@ struct ixp2000_flash_data {
unsigned long (*bank_setup)(unsigned long);
};
-/*
- * GPIO helper functions
- */
-#define GPIO_IN 0
-#define GPIO_OUT 1
-
-extern void gpio_line_config(int line, int style);
-
-static inline int gpio_line_get(int line)
-{
- return (((*IXP2000_GPIO_PLR) >> line) & 1);
-}
-
-static inline void gpio_line_set(int line, int value)
-{
- if (value)
- ixp2000_reg_write(IXP2000_GPIO_POSR, (1 << line));
- else
- ixp2000_reg_write(IXP2000_GPIO_POCR, (1 << line));
-}
-
struct ixp2000_i2c_pins {
unsigned long sda_pin;
unsigned long scl_pin;
};
+
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-arm/arch-ixp2000/vmalloc.h b/include/asm-arm/arch-ixp2000/vmalloc.h
index 473dff4ec561..275136963a0c 100644
--- a/include/asm-arm/arch-ixp2000/vmalloc.h
+++ b/include/asm-arm/arch-ixp2000/vmalloc.h
@@ -17,4 +17,4 @@
* The vmalloc() routines leaves a hole of 4kB between each vmalloced
* area for the same reason. ;)
*/
-#define VMALLOC_END 0xfaffefff
+#define VMALLOC_END 0xfb000000
diff --git a/include/asm-arm/arch-ixp4xx/debug-macro.S b/include/asm-arm/arch-ixp4xx/debug-macro.S
index 4499ae8e4b44..2e23651e217f 100644
--- a/include/asm-arm/arch-ixp4xx/debug-macro.S
+++ b/include/asm-arm/arch-ixp4xx/debug-macro.S
@@ -15,6 +15,7 @@
tst \rx, #1 @ MMU enabled?
moveq \rx, #0xc8000000
movne \rx, #0xff000000
+ orrne \rx, \rx, #0x00b00000
add \rx,\rx,#3 @ Uart regs are at off set of 3 if
@ byte writes used - Big Endian.
.endm
diff --git a/include/asm-arm/arch-ixp4xx/io.h b/include/asm-arm/arch-ixp4xx/io.h
index c27b9d3079a7..7495026e2c18 100644
--- a/include/asm-arm/arch-ixp4xx/io.h
+++ b/include/asm-arm/arch-ixp4xx/io.h
@@ -3,7 +3,7 @@
*
* Author: Deepak Saxena <dsaxena@plexity.net>
*
- * Copyright (C) 2002-2004 MontaVista Software, Inc.
+ * Copyright (C) 2002-2005 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 version 2 as
@@ -383,6 +383,180 @@ __ixp4xx_insl(u32 io_addr, u32 *vaddr, u32 count)
*vaddr++ = inl(io_addr);
}
+#define __is_io_address(p) (((unsigned long)p >= 0x0) && \
+ ((unsigned long)p <= 0x0000ffff))
+static inline unsigned int
+__ixp4xx_ioread8(void __iomem *port)
+{
+ if (__is_io_address(port))
+ return (unsigned int)__ixp4xx_inb((unsigned int)port);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ return (unsigned int)__raw_readb((u32)port);
+#else
+ return (unsigned int)__ixp4xx_readb((u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_ioread8_rep(u32 port, u8 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_insb(port, vaddr, count);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_readsb((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_readsb(port, vaddr, count);
+#endif
+}
+
+static inline unsigned int
+__ixp4xx_ioread16(void __iomem *port)
+{
+ if (__is_io_address(port))
+ return (unsigned int)__ixp4xx_inw((unsigned int)port);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ return le16_to_cpu(__raw_readw((u32)port));
+#else
+ return (unsigned int)__ixp4xx_readw((u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_ioread16_rep(u32 port, u16 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_insw(port, vaddr, count);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_readsw((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_readsw(port, vaddr, count);
+#endif
+}
+
+static inline unsigned int
+__ixp4xx_ioread32(void __iomem *port)
+{
+ if (__is_io_address(port))
+ return (unsigned int)__ixp4xx_inl((unsigned int)port);
+ else {
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ return le32_to_cpu(__raw_readl((u32)port));
+#else
+ return (unsigned int)__ixp4xx_readl((u32)port);
+#endif
+ }
+}
+
+static inline void
+__ixp4xx_ioread32_rep(u32 port, u32 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_insl(port, vaddr, count);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_readsl((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_readsl(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite8(u8 value, void __iomem *port)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outb(value, (unsigned int)port);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_writeb(value, (u32)port);
+#else
+ __ixp4xx_writeb(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite8_rep(u32 port, u8 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outsb(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_writesb((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_writesb(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite16(u16 value, void __iomem *port)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outw(value, (unsigned int)port);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_writew(cpu_to_le16(value), (u32)port);
+#else
+ __ixp4xx_writew(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite16_rep(u32 port, u16 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outsw(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_readsw((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_writesw(port, vaddr, count);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite32(u32 value, void __iomem *port)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outl(value, (unsigned int)port);
+ else
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_writel(cpu_to_le32(value), (u32)port);
+#else
+ __ixp4xx_writel(value, (u32)port);
+#endif
+}
+
+static inline void
+__ixp4xx_iowrite32_rep(u32 port, u32 *vaddr, u32 count)
+{
+ if (__is_io_address(port))
+ __ixp4xx_outsl(port, vaddr, count);
+#ifndef CONFIG_IXP4XX_INDIRECT_PCI
+ __raw_readsl((void __iomem *)port, vaddr, count);
+#else
+ __ixp4xx_outsl(port, vaddr, count);
+#endif
+}
+
+#define ioread8(p) __ixp4xx_ioread8(p)
+#define ioread16(p) __ixp4xx_ioread16(p)
+#define ioread32(p) __ixp4xx_ioread32(p)
+
+#define ioread8_rep(p, v, c) __ixp4xx_ioread8_rep(p, v, c)
+#define ioread16_rep(p, v, c) __ixp4xx_ioread16_rep(p, v, c)
+#define ioread32_rep(p, v, c) __ixp4xx_ioread32_rep(p, v, c)
+
+#define iowrite8(v,p) __ixp4xx_iowrite8(v,p)
+#define iowrite16(v,p) __ixp4xx_iowrite16(v,p)
+#define iowrite32(v,p) __ixp4xx_iowrite32(v,p)
+
+#define iowrite8_rep(p, v, c) __ixp4xx_iowrite8_rep(p, v, c)
+#define iowrite16_rep(p, v, c) __ixp4xx_iowrite16_rep(p, v, c)
+#define iowrite32_rep(p, v, c) __ixp4xx_iowrite32_rep(p, v, c)
+
+#define ioport_map(port, nr) ((void __iomem*)port)
+#define ioport_unmap(addr)
#endif // __ASM_ARM_ARCH_IO_H
diff --git a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
index 8eeb1db6309d..004696a95bdb 100644
--- a/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
+++ b/include/asm-arm/arch-ixp4xx/ixp4xx-regs.h
@@ -69,6 +69,16 @@
#define IXP4XX_PERIPHERAL_BASE_VIRT (0xFFBF2000)
#define IXP4XX_PERIPHERAL_REGION_SIZE (0x0000C000)
+/*
+ * Debug UART
+ *
+ * This is basically a remap of UART1 into a region that is section
+ * aligned so that it * can be used with the low-level debug code.
+ */
+#define IXP4XX_DEBUG_UART_BASE_PHYS (0xC8000000)
+#define IXP4XX_DEBUG_UART_BASE_VIRT (0xffb00000)
+#define IXP4XX_DEBUG_UART_REGION_SIZE (0x00001000)
+
#define IXP4XX_EXP_CS0_OFFSET 0x00
#define IXP4XX_EXP_CS1_OFFSET 0x04
#define IXP4XX_EXP_CS2_OFFSET 0x08
diff --git a/include/asm-arm/arch-omap/board-h2.h b/include/asm-arm/arch-omap/board-h2.h
index 60f002b72983..39ca5a31aeea 100644
--- a/include/asm-arm/arch-omap/board-h2.h
+++ b/include/asm-arm/arch-omap/board-h2.h
@@ -34,11 +34,6 @@
/* At OMAP1610 Innovator the Ethernet is directly connected to CS1 */
#define OMAP1610_ETHR_START 0x04000300
-/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
-#define OMAP_NOR_FLASH_SIZE SZ_32M
-#define OMAP_NOR_FLASH_START1 0x0C000000 /* CS3 */
-#define OMAP_NOR_FLASH_START2 0x0A000000 /* CS2B */
-
/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
diff --git a/include/asm-arm/arch-omap/board-h3.h b/include/asm-arm/arch-omap/board-h3.h
index e4d1cd231731..1b12c1dcc2fa 100644
--- a/include/asm-arm/arch-omap/board-h3.h
+++ b/include/asm-arm/arch-omap/board-h3.h
@@ -30,11 +30,6 @@
/* In OMAP1710 H3 the Ethernet is directly connected to CS1 */
#define OMAP1710_ETHR_START 0x04000300
-/* Intel STRATA NOR flash at CS3 or CS2B(NAND Boot) */
-#define OMAP_NOR_FLASH_SIZE SZ_32M
-#define OMAP_NOR_FLASH_START1 0x0C000000 /* CS3 */
-#define OMAP_NOR_FLASH_START2 0x0A000000 /* CS2B */
-
/* Samsung NAND flash at CS2B or CS3(NAND Boot) */
#define OMAP_NAND_FLASH_START1 0x0A000000 /* CS2B */
#define OMAP_NAND_FLASH_START2 0x0C000000 /* CS3 */
diff --git a/include/asm-arm/arch-omap/board-osk.h b/include/asm-arm/arch-omap/board-osk.h
index aaa49a0fbd21..2b1a8a4fe44e 100644
--- a/include/asm-arm/arch-omap/board-osk.h
+++ b/include/asm-arm/arch-omap/board-osk.h
@@ -32,10 +32,5 @@
/* At OMAP5912 OSK the Ethernet is directly connected to CS1 */
#define OMAP_OSK_ETHR_START 0x04800300
-/* Micron NOR flash at CS3 mapped to address 0x0 if BM bit is 1 */
-#define OMAP_OSK_NOR_FLASH_BASE 0xD8000000
-#define OMAP_OSK_NOR_FLASH_SIZE SZ_32M
-#define OMAP_OSK_NOR_FLASH_START 0x00000000
-
#endif /* __ASM_ARCH_OMAP_OSK_H */
diff --git a/include/asm-arm/arch-omap/board.h b/include/asm-arm/arch-omap/board.h
index 1cefd60b6f2a..95bd625480c1 100644
--- a/include/asm-arm/arch-omap/board.h
+++ b/include/asm-arm/arch-omap/board.h
@@ -16,10 +16,11 @@
/* Different peripheral ids */
#define OMAP_TAG_CLOCK 0x4f01
#define OMAP_TAG_MMC 0x4f02
-#define OMAP_TAG_UART 0x4f03
+#define OMAP_TAG_SERIAL_CONSOLE 0x4f03
#define OMAP_TAG_USB 0x4f04
#define OMAP_TAG_LCD 0x4f05
#define OMAP_TAG_GPIO_SWITCH 0x4f06
+#define OMAP_TAG_UART 0x4f07
#define OMAP_TAG_BOOT_REASON 0x4f80
#define OMAP_TAG_FLASH_PART 0x4f81
@@ -35,7 +36,7 @@ struct omap_mmc_config {
s16 mmc1_switch_pin, mmc2_switch_pin;
};
-struct omap_uart_config {
+struct omap_serial_console_config {
u8 console_uart;
u32 console_speed;
};
@@ -82,7 +83,8 @@ struct omap_lcd_config {
*/
#define OMAP_GPIO_SWITCH_TYPE_COVER 0x0000
#define OMAP_GPIO_SWITCH_TYPE_CONNECTION 0x0001
-#define OMAP_GPIO_SWITCH_FLAG_INVERTED 0x0001
+#define OMAP_GPIO_SWITCH_FLAG_INVERTED 0x0001
+#define OMAP_GPIO_SWITCH_FLAG_OUTPUT 0x0002
struct omap_gpio_switch_config {
char name[12];
u16 gpio;
@@ -99,6 +101,10 @@ struct omap_boot_reason_config {
char reason_str[12];
};
+struct omap_uart_config {
+ /* Bit field of UARTs present; bit 0 --> UART1 */
+ unsigned int enabled_uarts;
+};
struct omap_board_config_entry {
u16 tag;
diff --git a/arch/arm/mach-omap/common.h b/include/asm-arm/arch-omap/common.h
index 9f62858c0df4..2a676b4f13b5 100644
--- a/arch/arm/mach-omap/common.h
+++ b/include/asm-arm/arch-omap/common.h
@@ -1,5 +1,5 @@
/*
- * linux/arch/arm/mach-omap/common.h
+ * linux/include/asm-arm/arch-omap/common.h
*
* Header for code common to all OMAP machines.
*
@@ -29,7 +29,7 @@
struct sys_timer;
-extern void omap_map_io(void);
+extern void omap_map_common_io(void);
extern struct sys_timer omap_timer;
extern void omap_serial_init(int ports[]);
diff --git a/include/asm-arm/arch-omap/dma.h b/include/asm-arm/arch-omap/dma.h
index d785248377db..ce114ce5af5d 100644
--- a/include/asm-arm/arch-omap/dma.h
+++ b/include/asm-arm/arch-omap/dma.h
@@ -241,6 +241,7 @@ extern void omap_dma_unlink_lch (int lch_head, int lch_queue);
extern dma_addr_t omap_get_dma_src_pos(int lch);
extern dma_addr_t omap_get_dma_dst_pos(int lch);
extern void omap_clear_dma(int lch);
+extern int omap_dma_running(void);
/* Returns 1 if the DMA module is in OMAP1510-compatible mode, 0 otherwise */
extern int omap_dma_in_1510_mode(void);
diff --git a/include/asm-arm/arch-omap/hardware.h b/include/asm-arm/arch-omap/hardware.h
index 37e06c782bdf..48258c7f6541 100644
--- a/include/asm-arm/arch-omap/hardware.h
+++ b/include/asm-arm/arch-omap/hardware.h
@@ -54,6 +54,19 @@
/*
* ----------------------------------------------------------------------------
+ * Timers
+ * ----------------------------------------------------------------------------
+ */
+#define OMAP_MPU_TIMER1_BASE (0xfffec500)
+#define OMAP_MPU_TIMER2_BASE (0xfffec600)
+#define OMAP_MPU_TIMER3_BASE (0xfffec700)
+#define MPU_TIMER_FREE (1 << 6)
+#define MPU_TIMER_CLOCK_ENABLE (1 << 5)
+#define MPU_TIMER_AR (1 << 1)
+#define MPU_TIMER_ST (1 << 0)
+
+/*
+ * ----------------------------------------------------------------------------
* Clocks
* ----------------------------------------------------------------------------
*/
@@ -78,6 +91,7 @@
/* DSP clock control */
#define DSP_CONFIG_REG_BASE (0xe1008000)
+#define DSP_CKCTL (DSP_CONFIG_REG_BASE + 0x0)
#define DSP_IDLECT1 (DSP_CONFIG_REG_BASE + 0x4)
#define DSP_IDLECT2 (DSP_CONFIG_REG_BASE + 0x8)
@@ -88,6 +102,7 @@
*/
#define ULPD_REG_BASE (0xfffe0800)
#define ULPD_IT_STATUS (ULPD_REG_BASE + 0x14)
+#define ULPD_SETUP_ANALOG_CELL_3 (ULPD_REG_BASE + 0x24)
#define ULPD_CLOCK_CTRL (ULPD_REG_BASE + 0x30)
# define DIS_USB_PVCI_CLK (1 << 5) /* no USB/FAC synch */
# define USB_MCLK_EN (1 << 4) /* enable W4_USB_CLKO */
@@ -268,17 +283,10 @@
* Processor specific defines
* ---------------------------------------------------------------------------
*/
-#ifdef CONFIG_ARCH_OMAP730
-#include "omap730.h"
-#endif
-#ifdef CONFIG_ARCH_OMAP1510
+#include "omap730.h"
#include "omap1510.h"
-#endif
-
-#ifdef CONFIG_ARCH_OMAP16XX
#include "omap16xx.h"
-#endif
/*
* ---------------------------------------------------------------------------
diff --git a/include/asm-arm/arch-omap/irqs.h b/include/asm-arm/arch-omap/irqs.h
index 6701fd9e5f9b..0d05a7c957d1 100644
--- a/include/asm-arm/arch-omap/irqs.h
+++ b/include/asm-arm/arch-omap/irqs.h
@@ -159,6 +159,7 @@
#define INT_1610_GPIO_BANK3 (41 + IH2_BASE)
#define INT_1610_MMC2 (42 + IH2_BASE)
#define INT_1610_CF (43 + IH2_BASE)
+#define INT_1610_WAKE_UP_REQ (46 + IH2_BASE)
#define INT_1610_GPIO_BANK4 (48 + IH2_BASE)
#define INT_1610_SPI (49 + IH2_BASE)
#define INT_1610_DMA_CH6 (53 + IH2_BASE)
@@ -238,6 +239,8 @@
#define IH_MPUIO_BASE (OMAP_MAX_GPIO_LINES + IH_GPIO_BASE)
#define IH_BOARD_BASE (16 + IH_MPUIO_BASE)
+#define OMAP_IRQ_BIT(irq) (1 << ((irq) % 32))
+
#ifndef __ASSEMBLY__
extern void omap_init_irq(void);
#endif
diff --git a/include/asm-arm/arch-omap/mux.h b/include/asm-arm/arch-omap/mux.h
index 39f99decbb7b..5bd3f0097fc6 100644
--- a/include/asm-arm/arch-omap/mux.h
+++ b/include/asm-arm/arch-omap/mux.h
@@ -231,7 +231,7 @@ typedef enum {
J19_1610_ETM_D6,
J18_1610_ETM_D7,
- /* OMAP-1610 GPIO */
+ /* OMAP16XX GPIO */
P20_1610_GPIO4,
V9_1610_GPIO7,
W8_1610_GPIO9,
@@ -241,6 +241,9 @@ typedef enum {
AA20_1610_GPIO_41,
W19_1610_GPIO48,
M7_1610_GPIO62,
+ V14_16XX_GPIO37,
+ R9_16XX_GPIO18,
+ L14_16XX_GPIO49,
/* OMAP-1610 uWire */
V19_1610_UWIRE_SCLK,
@@ -285,12 +288,13 @@ typedef enum {
V6_USB2_TXD,
W5_USB2_SE0,
- /* UART1 1610 */
-
+ /* 16XX UART */
R13_1610_UART1_TX,
- V14_1610_UART1_RX,
+ V14_16XX_UART1_RX,
R14_1610_UART1_CTS,
AA15_1610_UART1_RTS,
+ R9_16XX_UART2_RX,
+ L14_16XX_UART3_RX,
/* I2C OMAP-1610 */
I2C_SCL,
@@ -332,7 +336,7 @@ typedef enum {
* Table of various FUNC_MUX and PULL_DWN combinations for each device.
* See also reg_cfg_t above for the lookup table.
*/
-static reg_cfg_set __initdata_or_module
+static const reg_cfg_set __initdata_or_module
reg_cfg_table[] = {
/*
* description mux mode mux pull pull pull pu_pd pu dbg
@@ -455,7 +459,7 @@ MUX_CFG("L19_1610_ETM_D0", 5, 18, 1, 0, 26, 0, 0, 0, 1)
MUX_CFG("J19_1610_ETM_D6", 5, 0, 1, 0, 20, 0, 0, 0, 1)
MUX_CFG("J18_1610_ETM_D7", 5, 27, 1, 0, 19, 0, 0, 0, 1)
-/* OMAP-1610 GPIO */
+/* OMAP16XX GPIO */
MUX_CFG("P20_1610_GPIO4", 6, 27, 0, 1, 7, 0, 1, 1, 1)
MUX_CFG("V9_1610_GPIO7", B, 12, 1, 2, 20, 0, 2, 1, 1)
MUX_CFG("W8_1610_GPIO9", B, 21, 0, 2, 23, 0, 2, 1, 1)
@@ -465,6 +469,9 @@ MUX_CFG("V5_1610_GPIO24", B, 15, 7, 2, 21, 0, 2, 1, 1)
MUX_CFG("AA20_1610_GPIO_41", 9, 9, 7, 1, 31, 0, 1, 1, 1)
MUX_CFG("W19_1610_GPIO48", 8, 15, 7, 1, 23, 1, 1, 0, 1)
MUX_CFG("M7_1610_GPIO62", 10, 0, 0, 4, 24, 0, 4, 0, 1)
+MUX_CFG("V14_16XX_GPIO37", 9, 18, 7, 2, 2, 0, 2, 2, 0)
+MUX_CFG("R9_16XX_GPIO18", C, 18, 7, 3, 0, 0, 3, 0, 0)
+MUX_CFG("L14_16XX_GPIO49", 6, 3, 7, 0, 31, 0, 0, 31, 0)
/* OMAP-1610 uWire */
MUX_CFG("V19_1610_UWIRE_SCLK", 8, 6, 0, 1, 20, 0, 1, 1, 1)
@@ -503,16 +510,17 @@ MUX_CFG("Y10_USB0_SUSP", B, 3, 5, 2, 17, 0, 2, 0, 1)
MUX_CFG("W9_USB2_TXEN", B, 9, 1, NA, 0, 0, NA, 0, 1)
MUX_CFG("AA9_USB2_VP", B, 6, 1, NA, 0, 0, NA, 0, 1)
MUX_CFG("Y5_USB2_RCV", C, 21, 1, NA, 0, 0, NA, 0, 1)
-MUX_CFG("R8_USB2_VM", C, 18, 1, NA, 0, 0, NA, 0, 1)
+MUX_CFG("R9_USB2_VM", C, 18, 1, NA, 0, 0, NA, 0, 1)
MUX_CFG("V6_USB2_TXD", C, 27, 2, NA, 0, 0, NA, 0, 1)
MUX_CFG("W5_USB2_SE0", C, 24, 2, NA, 0, 0, NA, 0, 1)
-
-/* UART1 */
+/* 16XX UART */
MUX_CFG("R13_1610_UART1_TX", A, 12, 6, 2, 10, 0, 2, 10, 1)
-MUX_CFG("V14_1610_UART1_RX", 9, 18, 0, 2, 2, 0, 2, 2, 1)
+MUX_CFG("V14_16XX_UART1_RX", 9, 18, 0, 2, 2, 0, 2, 2, 1)
MUX_CFG("R14_1610_UART1_CTS", 9, 15, 0, 2, 1, 0, 2, 1, 1)
MUX_CFG("AA15_1610_UART1_RTS", 9, 12, 1, 2, 0, 0, 2, 0, 1)
+MUX_CFG("R9_16XX_UART2_RX", C, 18, 0, 3, 0, 0, 3, 0, 1)
+MUX_CFG("L14_16XX_UART3_RX", 6, 3, 0, 0, 31, 0, 0, 31, 1)
/* I2C interface */
MUX_CFG("I2C_SCL", 7, 24, 0, NA, 0, 0, NA, 0, 0)
diff --git a/include/asm-arm/arch-omap/omap16xx.h b/include/asm-arm/arch-omap/omap16xx.h
index 88b1fe43ae9e..38a9b95e6a33 100644
--- a/include/asm-arm/arch-omap/omap16xx.h
+++ b/include/asm-arm/arch-omap/omap16xx.h
@@ -183,5 +183,37 @@
#define OMAP16XX_PWL_ENABLE (OMAP16XX_PWL_BASE + 0x00)
#define OMAP16XX_PWL_CLK_ENABLE (OMAP16XX_PWL_BASE + 0x04)
+/*
+ * ---------------------------------------------------------------------------
+ * Watchdog timer
+ * ---------------------------------------------------------------------------
+ */
+
+/* 32-bit Watchdog timer in OMAP 16XX */
+#define OMAP_16XX_WATCHDOG_BASE (0xfffeb000)
+#define OMAP_16XX_WIDR (OMAP_16XX_WATCHDOG_BASE + 0x00)
+#define OMAP_16XX_WD_SYSCONFIG (OMAP_16XX_WATCHDOG_BASE + 0x10)
+#define OMAP_16XX_WD_SYSSTATUS (OMAP_16XX_WATCHDOG_BASE + 0x14)
+#define OMAP_16XX_WCLR (OMAP_16XX_WATCHDOG_BASE + 0x24)
+#define OMAP_16XX_WCRR (OMAP_16XX_WATCHDOG_BASE + 0x28)
+#define OMAP_16XX_WLDR (OMAP_16XX_WATCHDOG_BASE + 0x2c)
+#define OMAP_16XX_WTGR (OMAP_16XX_WATCHDOG_BASE + 0x30)
+#define OMAP_16XX_WWPS (OMAP_16XX_WATCHDOG_BASE + 0x34)
+#define OMAP_16XX_WSPR (OMAP_16XX_WATCHDOG_BASE + 0x48)
+
+#define WCLR_PRE_SHIFT 5
+#define WCLR_PTV_SHIFT 2
+
+#define WWPS_W_PEND_WSPR (1 << 4)
+#define WWPS_W_PEND_WTGR (1 << 3)
+#define WWPS_W_PEND_WLDR (1 << 2)
+#define WWPS_W_PEND_WCRR (1 << 1)
+#define WWPS_W_PEND_WCLR (1 << 0)
+
+#define WSPR_ENABLE_0 (0x0000bbbb)
+#define WSPR_ENABLE_1 (0x00004444)
+#define WSPR_DISABLE_0 (0x0000aaaa)
+#define WSPR_DISABLE_1 (0x00005555)
+
#endif /* __ASM_ARCH_OMAP16XX_H */
diff --git a/include/asm-arm/arch-omap/system.h b/include/asm-arm/arch-omap/system.h
index 17a2c4825f07..ff37bc27e603 100644
--- a/include/asm-arm/arch-omap/system.h
+++ b/include/asm-arm/arch-omap/system.h
@@ -5,7 +5,9 @@
#ifndef __ASM_ARCH_SYSTEM_H
#define __ASM_ARCH_SYSTEM_H
#include <linux/config.h>
+#include <asm/mach-types.h>
#include <asm/arch/hardware.h>
+#include <asm/mach-types.h>
static inline void arch_idle(void)
{
@@ -14,7 +16,24 @@ static inline void arch_idle(void)
static inline void arch_reset(char mode)
{
- omap_writew(1, ARM_RSTCT1);
+
+#ifdef CONFIG_ARCH_OMAP16XX
+ /*
+ * Workaround for 5912/1611b bug mentioned in sprz209d.pdf p. 28
+ * "Global Software Reset Affects Traffic Controller Frequency".
+ */
+ if (cpu_is_omap5912()) {
+ omap_writew(omap_readw(DPLL_CTL) & ~(1 << 4),
+ DPLL_CTL);
+ omap_writew(0x8, ARM_RSTCT1);
+ }
+#endif
+#ifdef CONFIG_MACH_VOICEBLUE
+ if (machine_is_voiceblue())
+ voiceblue_reset();
+ else
+#endif
+ omap_writew(1, ARM_RSTCT1);
}
#endif
diff --git a/include/asm-arm/arch-omap/usb.h b/include/asm-arm/arch-omap/usb.h
index 1438c6cef0ca..054fb9a8e0c6 100644
--- a/include/asm-arm/arch-omap/usb.h
+++ b/include/asm-arm/arch-omap/usb.h
@@ -47,6 +47,15 @@
# define HMC_TLLATTACH (1 << 6)
# define OTG_HMC(w) (((w)>>0)&0x3f)
#define OTG_CTRL_REG OTG_REG32(0x0c)
+# define OTG_USB2_EN (1 << 29)
+# define OTG_USB2_DP (1 << 28)
+# define OTG_USB2_DM (1 << 27)
+# define OTG_USB1_EN (1 << 26)
+# define OTG_USB1_DP (1 << 25)
+# define OTG_USB1_DM (1 << 24)
+# define OTG_USB0_EN (1 << 23)
+# define OTG_USB0_DP (1 << 22)
+# define OTG_USB0_DM (1 << 21)
# define OTG_ASESSVLD (1 << 20)
# define OTG_BSESSEND (1 << 19)
# define OTG_BSESSVLD (1 << 18)
diff --git a/include/asm-arm/arch-pxa/debug-macro.S b/include/asm-arm/arch-pxa/debug-macro.S
index f288e74b67c2..b6ec68879176 100644
--- a/include/asm-arm/arch-pxa/debug-macro.S
+++ b/include/asm-arm/arch-pxa/debug-macro.S
@@ -11,6 +11,8 @@
*
*/
+#include "hardware.h"
+
.macro addruart,rx
mrc p15, 0, \rx, c1, c0
tst \rx, #1 @ MMU enabled?
diff --git a/include/asm-arm/arch-pxa/mtd-xip.h b/include/asm-arm/arch-pxa/mtd-xip.h
new file mode 100644
index 000000000000..8704dbceb432
--- /dev/null
+++ b/include/asm-arm/arch-pxa/mtd-xip.h
@@ -0,0 +1,37 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 2, 2004
+ * Copyright: (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $
+ */
+
+#ifndef __ARCH_PXA_MTD_XIP_H__
+#define __ARCH_PXA_MTD_XIP_H__
+
+#include <asm/arch/pxa-regs.h>
+
+#define xip_irqpending() (ICIP & ICMR)
+
+/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
+#define xip_currtime() (OSCR)
+#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4)
+
+/*
+ * xip_cpu_idle() is used when waiting for a delay equal or larger than
+ * the system timer tick period. This should put the CPU into idle mode
+ * to save power and to be woken up only when some interrupts are pending.
+ * As above, this should not rely upon standard kernel code.
+ */
+
+#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1))
+
+#endif /* __ARCH_PXA_MTD_XIP_H__ */
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index b5e54a9e9fa7..51f0fe0ac165 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1505,6 +1505,7 @@
#define PSSR_OTGPH (1 << 6) /* OTG Peripheral control Hold */
#define PSSR_RDH (1 << 5) /* Read Disable Hold */
#define PSSR_PH (1 << 4) /* Peripheral Control Hold */
+#define PSSR_STS (1 << 3) /* Standby Mode Status */
#define PSSR_VFS (1 << 2) /* VDD Fault Status */
#define PSSR_BFS (1 << 1) /* Battery Fault Status */
#define PSSR_SSS (1 << 0) /* Software Sleep Status */
@@ -1965,6 +1966,7 @@
#define MECR_NOS (1 << 0) /* Number Of Sockets: 0 -> 1 sock, 1 -> 2 sock */
#define MECR_CIT (1 << 1) /* Card Is There: 0 -> no card, 1 -> card inserted */
+#define MDREFR_K0DB4 (1 << 29) /* SDCLK0 Divide by 4 Control/Status */
#define MDREFR_K2FREE (1 << 25) /* SDRAM Free-Running Control */
#define MDREFR_K1FREE (1 << 24) /* SDRAM Free-Running Control */
#define MDREFR_K0FREE (1 << 23) /* SDRAM Free-Running Control */
diff --git a/include/asm-arm/arch-s3c2410/audio.h b/include/asm-arm/arch-s3c2410/audio.h
new file mode 100644
index 000000000000..0d276e67f2fb
--- /dev/null
+++ b/include/asm-arm/arch-s3c2410/audio.h
@@ -0,0 +1,49 @@
+/* linux/include/asm-arm/arch-s3c2410/audio.h
+ *
+ * (c) 2004-2005 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * S3C24XX - Audio platfrom_device info
+ *
+ * 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:
+ * 20-Nov-2004 BJD Created file
+ * 07-Mar-2005 BJD Added suspend/resume calls
+*/
+
+#ifndef __ASM_ARCH_AUDIO_H
+#define __ASM_ARCH_AUDIO_H __FILE__
+
+/* struct s3c24xx_iis_ops
+ *
+ * called from the s3c24xx audio core to deal with the architecture
+ * or the codec's setup and control.
+ *
+ * the pointer to itself is passed through in case the caller wants to
+ * embed this in an larger structure for easy reference to it's context.
+*/
+
+struct s3c24xx_iis_ops {
+ struct module *owner;
+
+ int (*startup)(struct s3c24xx_iis_ops *me);
+ void (*shutdown)(struct s3c24xx_iis_ops *me);
+ int (*suspend)(struct s3c24xx_iis_ops *me);
+ int (*resume)(struct s3c24xx_iis_ops *me);
+
+ int (*open)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm);
+ int (*close)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm);
+ int (*prepare)(struct s3c24xx_iis_ops *me, snd_pcm_substream_t *strm, snd_pcm_runtime_t *rt);
+};
+
+struct s3c24xx_platdata_iis {
+ const char *codec_clk;
+ struct s3c24xx_iis_ops *ops;
+ int (*match_dev)(struct device *dev);
+};
+
+#endif /* __ASM_ARCH_AUDIO_H */
diff --git a/include/asm-arm/arch-sa1100/mtd-xip.h b/include/asm-arm/arch-sa1100/mtd-xip.h
new file mode 100644
index 000000000000..80cfdac2b944
--- /dev/null
+++ b/include/asm-arm/arch-sa1100/mtd-xip.h
@@ -0,0 +1,26 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 2, 2004
+ * Copyright: (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $
+ */
+
+#ifndef __ARCH_SA1100_MTD_XIP_H__
+#define __ARCH_SA1100_MTD_XIP_H__
+
+#define xip_irqpending() (ICIP & ICMR)
+
+/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
+#define xip_currtime() (OSCR)
+#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4)
+
+#endif /* __ARCH_SA1100_MTD_XIP_H__ */
diff --git a/include/asm-arm/hardware/arm_timer.h b/include/asm-arm/hardware/arm_timer.h
new file mode 100644
index 000000000000..04be3bdf46b8
--- /dev/null
+++ b/include/asm-arm/hardware/arm_timer.h
@@ -0,0 +1,21 @@
+#ifndef __ASM_ARM_HARDWARE_ARM_TIMER_H
+#define __ASM_ARM_HARDWARE_ARM_TIMER_H
+
+#define TIMER_LOAD 0x00
+#define TIMER_VALUE 0x04
+#define TIMER_CTRL 0x08
+#define TIMER_CTRL_ONESHOT (1 << 0)
+#define TIMER_CTRL_32BIT (1 << 1)
+#define TIMER_CTRL_DIV1 (0 << 2)
+#define TIMER_CTRL_DIV16 (1 << 2)
+#define TIMER_CTRL_DIV256 (2 << 2)
+#define TIMER_CTRL_IE (1 << 5) /* Interrupt Enable (versatile only) */
+#define TIMER_CTRL_PERIODIC (1 << 6)
+#define TIMER_CTRL_ENABLE (1 << 7)
+
+#define TIMER_INTCLR 0x0c
+#define TIMER_RIS 0x10
+#define TIMER_MIS 0x14
+#define TIMER_BGLOAD 0x18
+
+#endif
diff --git a/include/asm-arm/ide.h b/include/asm-arm/ide.h
index 2114acb3d237..4f68c8a5a199 100644
--- a/include/asm-arm/ide.h
+++ b/include/asm-arm/ide.h
@@ -5,7 +5,7 @@
*/
/*
- * This file contains the i386 architecture specific IDE code.
+ * This file contains the ARM architecture specific IDE code.
*/
#ifndef __ASMARM_IDE_H
diff --git a/include/asm-arm/io.h b/include/asm-arm/io.h
index 08a46302d265..cfa71a0dffb6 100644
--- a/include/asm-arm/io.h
+++ b/include/asm-arm/io.h
@@ -82,7 +82,7 @@ extern void __readwrite_bug(const char *fn);
* only. Their primary purpose is to access PCI and ISA peripherals.
*
* Note that for a big endian machine, this implies that the following
- * big endian mode connectivity is in place, as described by numerious
+ * big endian mode connectivity is in place, as described by numerous
* ARM documents:
*
* PCI: D0-D7 D8-D15 D16-D23 D24-D31
@@ -275,6 +275,7 @@ extern void __iounmap(void __iomem *addr);
/*
* io{read,write}{8,16,32} macros
*/
+#ifndef ioread8
#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __v; })
#define ioread16(p) ({ unsigned int __v = le16_to_cpu(__raw_readw(p)); __v; })
#define ioread32(p) ({ unsigned int __v = le32_to_cpu(__raw_readl(p)); __v; })
@@ -293,6 +294,7 @@ extern void __iounmap(void __iomem *addr);
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
extern void ioport_unmap(void __iomem *addr);
+#endif
struct pci_dev;
diff --git a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h
index 3a32e929ec8c..56c6bf4ab0c3 100644
--- a/include/asm-arm/mach/arch.h
+++ b/include/asm-arm/mach/arch.h
@@ -26,7 +26,7 @@ struct machine_desc {
* page tabe entry */
const char *name; /* architecture name */
- unsigned int param_offset; /* parameter page */
+ unsigned long boot_params; /* tagged list */
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
@@ -54,38 +54,6 @@ const struct machine_desc __mach_desc_##_type \
.nr = MACH_TYPE_##_type, \
.name = _name,
-#define MAINTAINER(n)
-
-#define BOOT_MEM(_pram,_pio,_vio) \
- .phys_ram = _pram, \
- .phys_io = _pio, \
- .io_pg_offst = ((_vio)>>18)&0xfffc,
-
-#define BOOT_PARAMS(_params) \
- .param_offset = _params,
-
-#define VIDEO(_start,_end) \
- .video_start = _start, \
- .video_end = _end,
-
-#define DISABLE_PARPORT(_n) \
- .reserve_lp##_n = 1,
-
-#define SOFT_REBOOT \
- .soft_reboot = 1,
-
-#define FIXUP(_func) \
- .fixup = _func,
-
-#define MAPIO(_func) \
- .map_io = _func,
-
-#define INITIRQ(_func) \
- .init_irq = _func,
-
-#define INIT_MACHINE(_func) \
- .init_machine = _func,
-
#define MACHINE_END \
};
diff --git a/include/asm-arm/mach/time.h b/include/asm-arm/mach/time.h
index 5cf4fd659fd5..2cf279a44017 100644
--- a/include/asm-arm/mach/time.h
+++ b/include/asm-arm/mach/time.h
@@ -39,8 +39,31 @@ struct sys_timer {
void (*suspend)(void);
void (*resume)(void);
unsigned long (*offset)(void);
+
+#ifdef CONFIG_NO_IDLE_HZ
+ struct dyn_tick_timer *dyn_tick;
+#endif
+};
+
+#ifdef CONFIG_NO_IDLE_HZ
+
+#define DYN_TICK_SKIPPING (1 << 2)
+#define DYN_TICK_ENABLED (1 << 1)
+#define DYN_TICK_SUITABLE (1 << 0)
+
+struct dyn_tick_timer {
+ unsigned int state; /* Current state */
+ int (*enable)(void); /* Enables dynamic tick */
+ int (*disable)(void); /* Disables dynamic tick */
+ void (*reprogram)(unsigned long); /* Reprograms the timer */
+ int (*handler)(int, void *, struct pt_regs *);
};
+void timer_dyn_reprogram(void);
+#else
+#define timer_dyn_reprogram() do { } while (0)
+#endif
+
extern struct sys_timer *system_timer;
extern void timer_tick(struct pt_regs *);
diff --git a/include/asm-arm/mtd-xip.h b/include/asm-arm/mtd-xip.h
new file mode 100644
index 000000000000..9eb127cc7db2
--- /dev/null
+++ b/include/asm-arm/mtd-xip.h
@@ -0,0 +1,26 @@
+/*
+ * MTD primitives for XIP support. Architecture specific functions
+ *
+ * Do not include this file directly. It's included from linux/mtd/xip.h
+ *
+ * Author: Nicolas Pitre
+ * Created: Nov 2, 2004
+ * Copyright: (C) 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Id: xip.h,v 1.2 2004/12/01 15:49:10 nico Exp $
+ */
+
+#ifndef __ARM_MTD_XIP_H__
+#define __ARM_MTD_XIP_H__
+
+#include <asm/hardware.h>
+#include <asm/arch/mtd-xip.h>
+
+/* fill instruction prefetch */
+#define xip_iprefetch() do { asm volatile (".rep 8; nop; .endr"); } while (0)
+
+#endif /* __ARM_MTD_XIP_H__ */
diff --git a/include/asm-arm/pci.h b/include/asm-arm/pci.h
index 40ffaefbeb1a..b28f1c95dd62 100644
--- a/include/asm-arm/pci.h
+++ b/include/asm-arm/pci.h
@@ -14,7 +14,7 @@ static inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -42,6 +42,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
#define pci_unmap_len(PTR, LEN_NAME) ((PTR)->LEN_NAME)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) (((PTR)->LEN_NAME) = (VAL))
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
diff --git a/include/asm-arm/signal.h b/include/asm-arm/signal.h
index 46e69ae395af..760f6e65af05 100644
--- a/include/asm-arm/signal.h
+++ b/include/asm-arm/signal.h
@@ -114,6 +114,7 @@ typedef unsigned long sigset_t;
#define SIGSTKSZ 8192
#ifdef __KERNEL__
+#define SA_TIMER 0x40000000
#define SA_IRQNOMASK 0x08000000
#endif
diff --git a/include/asm-arm/stat.h b/include/asm-arm/stat.h
index ca8e7a8436da..ec4e2c2e3b47 100644
--- a/include/asm-arm/stat.h
+++ b/include/asm-arm/stat.h
@@ -89,6 +89,6 @@ struct stat64 {
unsigned long st_ctime_nsec;
unsigned long long st_ino;
-};
+} __attribute__((packed));
#endif
diff --git a/include/asm-arm/system.h b/include/asm-arm/system.h
index 39dd7008013c..2f44b2044214 100644
--- a/include/asm-arm/system.h
+++ b/include/asm-arm/system.h
@@ -85,7 +85,9 @@ struct pt_regs;
void die(const char *msg, struct pt_regs *regs, int err)
__attribute__((noreturn));
-void die_if_kernel(const char *str, struct pt_regs *regs, int err);
+struct siginfo;
+void notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
+ unsigned long err, unsigned long trap);
void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int,
struct pt_regs *),
@@ -145,34 +147,12 @@ extern unsigned int user_debug;
#define set_wmb(var, value) do { var = value; wmb(); } while (0)
#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t");
-#ifdef CONFIG_SMP
/*
- * Define our own context switch locking. This allows us to enable
- * interrupts over the context switch, otherwise we end up with high
- * interrupt latency. The real problem area is switch_mm() which may
- * do a full cache flush.
+ * switch_mm() may do a full cache flush over the context switch,
+ * so enable interrupts over the context switch to avoid high
+ * latency.
*/
-#define prepare_arch_switch(rq,next) \
-do { \
- spin_lock(&(next)->switch_lock); \
- spin_unlock_irq(&(rq)->lock); \
-} while (0)
-
-#define finish_arch_switch(rq,prev) \
- spin_unlock(&(prev)->switch_lock)
-
-#define task_running(rq,p) \
- ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
-#else
-/*
- * Our UP-case is more simple, but we assume knowledge of how
- * spin_unlock_irq() and friends are implemented. This avoids
- * us needlessly decrementing and incrementing the preempt count.
- */
-#define prepare_arch_switch(rq,next) local_irq_enable()
-#define finish_arch_switch(rq,prev) spin_unlock(&(rq)->lock)
-#define task_running(rq,p) ((rq)->curr == (p))
-#endif
+#define __ARCH_WANT_INTERRUPTS_ON_CTXSW
/*
* switch_to(prev, next) should switch from task `prev' to `next'
@@ -312,7 +292,6 @@ do { \
})
#ifdef CONFIG_SMP
-#error SMP not supported
#define smp_mb() mb()
#define smp_rmb() rmb()
@@ -326,6 +305,8 @@ do { \
#define smp_wmb() barrier()
#define smp_read_barrier_depends() do { } while(0)
+#endif /* CONFIG_SMP */
+
#if defined(CONFIG_CPU_SA1100) || defined(CONFIG_CPU_SA110)
/*
* On the StrongARM, "swp" is terminally broken since it bypasses the
@@ -338,9 +319,16 @@ do { \
*
* We choose (1) since its the "easiest" to achieve here and is not
* dependent on the processor type.
+ *
+ * NOTE that this solution won't work on an SMP system, so explcitly
+ * forbid it here.
*/
+#ifdef CONFIG_SMP
+#error SMP is not supported on SA1100/SA110
+#else
#define swp_is_buggy
#endif
+#endif
static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size)
{
@@ -383,8 +371,6 @@ static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size
return ret;
}
-#endif /* CONFIG_SMP */
-
#endif /* __ASSEMBLY__ */
#define arch_align_stack(x) (x)
diff --git a/include/asm-arm/tlbflush.h b/include/asm-arm/tlbflush.h
index 8a864b118569..9387a5e1ffe0 100644
--- a/include/asm-arm/tlbflush.h
+++ b/include/asm-arm/tlbflush.h
@@ -235,7 +235,7 @@ extern struct cpu_tlb_fns cpu_tlb;
#define tlb_flag(f) ((always_tlb_flags & (f)) || (__tlb_flag & possible_tlb_flags & (f)))
-static inline void flush_tlb_all(void)
+static inline void local_flush_tlb_all(void)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -253,7 +253,7 @@ static inline void flush_tlb_all(void)
asm("mcr%? p15, 0, %0, c8, c5, 0" : : "r" (zero));
}
-static inline void flush_tlb_mm(struct mm_struct *mm)
+static inline void local_flush_tlb_mm(struct mm_struct *mm)
{
const int zero = 0;
const int asid = ASID(mm);
@@ -282,7 +282,7 @@ static inline void flush_tlb_mm(struct mm_struct *mm)
}
static inline void
-flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
+local_flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -313,7 +313,7 @@ flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr)
asm("mcr%? p15, 0, %0, c8, c5, 1" : : "r" (uaddr));
}
-static inline void flush_tlb_kernel_page(unsigned long kaddr)
+static inline void local_flush_tlb_kernel_page(unsigned long kaddr)
{
const int zero = 0;
const unsigned int __tlb_flag = __cpu_tlb_flags;
@@ -384,8 +384,24 @@ static inline void clean_pmd_entry(pmd_t *pmd)
/*
* Convert calls to our calling convention.
*/
-#define flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
-#define flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
+#define local_flush_tlb_range(vma,start,end) __cpu_flush_user_tlb_range(start,end,vma)
+#define local_flush_tlb_kernel_range(s,e) __cpu_flush_kern_tlb_range(s,e)
+
+#ifndef CONFIG_SMP
+#define flush_tlb_all local_flush_tlb_all
+#define flush_tlb_mm local_flush_tlb_mm
+#define flush_tlb_page local_flush_tlb_page
+#define flush_tlb_kernel_page local_flush_tlb_kernel_page
+#define flush_tlb_range local_flush_tlb_range
+#define flush_tlb_kernel_range local_flush_tlb_kernel_range
+#else
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long uaddr);
+extern void flush_tlb_kernel_page(unsigned long kaddr);
+extern void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
+extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
+#endif
/*
* if PG_dcache_dirty is set for the page, we need to ensure that any
diff --git a/include/asm-arm26/serial.h b/include/asm-arm26/serial.h
index 21e1df31f086..5fc747d1b501 100644
--- a/include/asm-arm26/serial.h
+++ b/include/asm-arm26/serial.h
@@ -30,34 +30,16 @@
#if defined(CONFIG_ARCH_A5K)
/* UART CLK PORT IRQ FLAGS */
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
{ 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */
#else
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
{ 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS1 */
#endif
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS2 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS3 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS13 */
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS
-
#endif
diff --git a/include/asm-frv/pci.h b/include/asm-frv/pci.h
index a6a469231f62..b4efe5e3591a 100644
--- a/include/asm-frv/pci.h
+++ b/include/asm-frv/pci.h
@@ -57,6 +57,16 @@ extern void pci_free_consistent(struct pci_dev *hwdev, size_t size,
*/
#define PCI_DMA_BUS_IS_PHYS (1)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
/*
* These are pretty much arbitary with the CoMEM implementation.
* We have the whole address space to ourselves.
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 99cef06a364a..b3bb326ae5b6 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -73,7 +73,7 @@
}
#define SECURITY_INIT \
- .security_initcall.init : { \
+ .security_initcall.init : AT(ADDR(.security_initcall.init) - LOAD_OFFSET) { \
VMLINUX_SYMBOL(__security_initcall_start) = .; \
*(.security_initcall.init) \
VMLINUX_SYMBOL(__security_initcall_end) = .; \
diff --git a/include/asm-h8300/pci.h b/include/asm-h8300/pci.h
index d032729b19df..5edad5b70fd5 100644
--- a/include/asm-h8300/pci.h
+++ b/include/asm-h8300/pci.h
@@ -15,7 +15,7 @@ extern inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-extern inline void pcibios_penalize_isa_irq(int irq)
+extern inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
diff --git a/include/asm-i386/acpi.h b/include/asm-i386/acpi.h
index c976c1dadece..cf828ace13f9 100644
--- a/include/asm-i386/acpi.h
+++ b/include/asm-i386/acpi.h
@@ -28,6 +28,8 @@
#ifdef __KERNEL__
+#include <acpi/pdc_intel.h>
+
#include <asm/system.h> /* defines cmpxchg */
#define COMPILER_DEPENDENT_INT64 long long
@@ -101,12 +103,6 @@ __acpi_release_global_lock (unsigned int *lock)
:"=r"(n_hi), "=r"(n_lo) \
:"0"(n_hi), "1"(n_lo))
-/*
- * Refer Intel ACPI _PDC support document for bit definitions
- */
-#define ACPI_PDC_EST_CAPABILITY_SMP 0xa
-#define ACPI_PDC_EST_CAPABILITY_MSR 0x1
-
#ifdef CONFIG_ACPI_BOOT
extern int acpi_lapic;
extern int acpi_ioapic;
@@ -185,6 +181,8 @@ extern void acpi_reserve_bootmem(void);
extern u8 x86_acpiid_to_apicid[];
+#define ARCH_HAS_POWER_PDC_INIT 1
+
#endif /*__KERNEL__*/
#endif /*_ASM_ACPI_H*/
diff --git a/include/asm-i386/apic.h b/include/asm-i386/apic.h
index a5810cf7b578..6a1b1882285c 100644
--- a/include/asm-i386/apic.h
+++ b/include/asm-i386/apic.h
@@ -5,6 +5,7 @@
#include <linux/pm.h>
#include <asm/fixmap.h>
#include <asm/apicdef.h>
+#include <asm/processor.h>
#include <asm/system.h>
#define Dprintk(x...)
@@ -16,8 +17,20 @@
#define APIC_VERBOSE 1
#define APIC_DEBUG 2
+extern int enable_local_apic;
extern int apic_verbosity;
+static inline void lapic_disable(void)
+{
+ enable_local_apic = -1;
+ clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
+}
+
+static inline void lapic_enable(void)
+{
+ enable_local_apic = 1;
+}
+
/*
* Define the default level of output to be very little
* This can be turned up by using apic=verbose for more
@@ -87,7 +100,7 @@ extern void (*wait_timer_tick)(void);
extern int get_maxlvt(void);
extern void clear_local_APIC(void);
extern void connect_bsp_APIC (void);
-extern void disconnect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (int virt_wire_setup);
extern void disable_local_APIC (void);
extern void lapic_shutdown (void);
extern int verify_local_APIC (void);
diff --git a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
index c689554ad5b9..a96a8f48fbfc 100644
--- a/include/asm-i386/apicdef.h
+++ b/include/asm-i386/apicdef.h
@@ -86,11 +86,12 @@
#define APIC_LVT_REMOTE_IRR (1<<14)
#define APIC_INPUT_POLARITY (1<<13)
#define APIC_SEND_PENDING (1<<12)
+#define APIC_MODE_MASK 0x700
#define GET_APIC_DELIVERY_MODE(x) (((x)>>8)&0x7)
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
#define APIC_MODE_FIXED 0x0
#define APIC_MODE_NMI 0x4
-#define APIC_MODE_EXINT 0x7
+#define APIC_MODE_EXTINT 0x7
#define APIC_LVT1 0x360
#define APIC_LVTERR 0x370
#define APIC_TMICT 0x380
@@ -108,11 +109,7 @@
#define APIC_BASE (fix_to_virt(FIX_APIC_BASE))
-#ifdef CONFIG_NUMA
- #define MAX_IO_APICS 32
-#else
- #define MAX_IO_APICS 8
-#endif
+#define MAX_IO_APICS 64
/*
* the local APIC register structure, memory mapped. Not terribly well
diff --git a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h
index 002740b21951..e7252c216ca8 100644
--- a/include/asm-i386/cpu.h
+++ b/include/asm-i386/cpu.h
@@ -5,6 +5,7 @@
#include <linux/cpu.h>
#include <linux/topology.h>
#include <linux/nodemask.h>
+#include <linux/percpu.h>
#include <asm/node.h>
@@ -16,4 +17,5 @@ extern int arch_register_cpu(int num);
extern void arch_unregister_cpu(int);
#endif
+DECLARE_PER_CPU(int, cpu_state);
#endif /* _ASM_I386_CPU_H_ */
diff --git a/include/asm-i386/highmem.h b/include/asm-i386/highmem.h
index 1df42bf347df..0fd331306b60 100644
--- a/include/asm-i386/highmem.h
+++ b/include/asm-i386/highmem.h
@@ -70,6 +70,7 @@ void *kmap(struct page *page);
void kunmap(struct page *page);
void *kmap_atomic(struct page *page, enum km_type type);
void kunmap_atomic(void *kvaddr, enum km_type type);
+void *kmap_atomic_pfn(unsigned long pfn, enum km_type type);
struct page *kmap_atomic_to_page(void *ptr);
#define flush_cache_kmaps() do { } while (0)
diff --git a/include/asm-i386/i8253.h b/include/asm-i386/i8253.h
new file mode 100644
index 000000000000..015d8df07690
--- /dev/null
+++ b/include/asm-i386/i8253.h
@@ -0,0 +1,6 @@
+#ifndef __ASM_I8253_H__
+#define __ASM_I8253_H__
+
+extern spinlock_t i8253_lock;
+
+#endif /* __ASM_I8253_H__ */
diff --git a/include/asm-i386/ide.h b/include/asm-i386/ide.h
index 859ebf4da632..79dfab87135d 100644
--- a/include/asm-i386/ide.h
+++ b/include/asm-i386/ide.h
@@ -41,13 +41,17 @@ static __inline__ int ide_default_irq(unsigned long base)
static __inline__ unsigned long ide_default_io_base(int index)
{
+ if (pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) {
+ switch(index) {
+ case 2: return 0x1e8;
+ case 3: return 0x168;
+ case 4: return 0x1e0;
+ case 5: return 0x160;
+ }
+ }
switch (index) {
case 0: return 0x1f0;
case 1: return 0x170;
- case 2: return 0x1e8;
- case 3: return 0x168;
- case 4: return 0x1e0;
- case 5: return 0x160;
default:
return 0;
}
diff --git a/include/asm-i386/irq.h b/include/asm-i386/irq.h
index 05b9e61b0a72..270f1986b19f 100644
--- a/include/asm-i386/irq.h
+++ b/include/asm-i386/irq.h
@@ -29,13 +29,19 @@ extern void release_vm86_irqs(struct task_struct *);
#ifdef CONFIG_4KSTACKS
extern void irq_ctx_init(int cpu);
+ extern void irq_ctx_exit(int cpu);
# define __ARCH_HAS_DO_SOFTIRQ
#else
# define irq_ctx_init(cpu) do { } while (0)
+# define irq_ctx_exit(cpu) do { } while (0)
#endif
#ifdef CONFIG_IRQBALANCE
extern int irqbalance_disable(char *str);
#endif
+#ifdef CONFIG_HOTPLUG_CPU
+extern void fixup_irqs(cpumask_t map);
+#endif
+
#endif /* _ASM_IRQ_H */
diff --git a/include/asm-i386/kdebug.h b/include/asm-i386/kdebug.h
index de6498b0d493..b3f8d5f59d5d 100644
--- a/include/asm-i386/kdebug.h
+++ b/include/asm-i386/kdebug.h
@@ -18,7 +18,7 @@ struct die_args {
};
/* Note - you should never unregister because that can race with NMIs.
- If you really want to do it first unregister - then synchronize_kernel - then free.
+ If you really want to do it first unregister - then synchronize_sched - then free.
*/
int register_die_notifier(struct notifier_block *nb);
extern struct notifier_block *i386die_chain;
diff --git a/include/asm-i386/kexec.h b/include/asm-i386/kexec.h
new file mode 100644
index 000000000000..6ed2a03e37b3
--- /dev/null
+++ b/include/asm-i386/kexec.h
@@ -0,0 +1,33 @@
+#ifndef _I386_KEXEC_H
+#define _I386_KEXEC_H
+
+#include <asm/fixmap.h>
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_386
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /* _I386_KEXEC_H */
diff --git a/include/asm-i386/mach-default/do_timer.h b/include/asm-i386/mach-default/do_timer.h
index 03dd13a48a8c..56211414fc95 100644
--- a/include/asm-i386/mach-default/do_timer.h
+++ b/include/asm-i386/mach-default/do_timer.h
@@ -1,6 +1,7 @@
/* defines for inline arch setup functions */
#include <asm/apic.h>
+#include <asm/i8259.h>
/**
* do_timer_interrupt_hook - hook into timer tick
diff --git a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-i386/mach-default/mach_ipi.h
index 6f2b17a20089..cc756a67cd63 100644
--- a/include/asm-i386/mach-default/mach_ipi.h
+++ b/include/asm-i386/mach-default/mach_ipi.h
@@ -4,11 +4,34 @@
void send_IPI_mask_bitmask(cpumask_t mask, int vector);
void __send_IPI_shortcut(unsigned int shortcut, int vector);
+extern int no_broadcast;
+
static inline void send_IPI_mask(cpumask_t mask, int vector)
{
send_IPI_mask_bitmask(mask, vector);
}
+static inline void __local_send_IPI_allbutself(int vector)
+{
+ if (no_broadcast) {
+ cpumask_t mask = cpu_online_map;
+ int this_cpu = get_cpu();
+
+ cpu_clear(this_cpu, mask);
+ send_IPI_mask(mask, vector);
+ put_cpu();
+ } else
+ __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+}
+
+static inline void __local_send_IPI_all(int vector)
+{
+ if (no_broadcast)
+ send_IPI_mask(cpu_online_map, vector);
+ else
+ __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+}
+
static inline void send_IPI_allbutself(int vector)
{
/*
@@ -18,13 +41,13 @@ static inline void send_IPI_allbutself(int vector)
if (!(num_online_cpus() > 1))
return;
- __send_IPI_shortcut(APIC_DEST_ALLBUT, vector);
+ __local_send_IPI_allbutself(vector);
return;
}
static inline void send_IPI_all(int vector)
{
- __send_IPI_shortcut(APIC_DEST_ALLINC, vector);
+ __local_send_IPI_all(vector);
}
#endif /* __ASM_MACH_IPI_H */
diff --git a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
index 33ce5d37e894..516421300ea2 100644
--- a/include/asm-i386/mmzone.h
+++ b/include/asm-i386/mmzone.h
@@ -8,20 +8,15 @@
#include <asm/smp.h>
-#if CONFIG_NUMA
+#ifdef CONFIG_NUMA
extern struct pglist_data *node_data[];
#define NODE_DATA(nid) (node_data[nid])
-#ifdef CONFIG_NUMA
- #ifdef CONFIG_X86_NUMAQ
- #include <asm/numaq.h>
- #else /* summit or generic arch */
- #include <asm/srat.h>
- #endif
-#else /* !CONFIG_NUMA */
- #define get_memcfg_numa get_memcfg_numa_flat
- #define get_zholes_size(n) (0)
-#endif /* CONFIG_NUMA */
+#ifdef CONFIG_X86_NUMAQ
+ #include <asm/numaq.h>
+#else /* summit or generic arch */
+ #include <asm/srat.h>
+#endif
extern int get_memcfg_numa_flat(void );
/*
@@ -42,6 +37,11 @@ static inline void get_memcfg_numa(void)
get_memcfg_numa_flat();
}
+extern int early_pfn_to_nid(unsigned long pfn);
+
+#else /* !CONFIG_NUMA */
+#define get_memcfg_numa get_memcfg_numa_flat
+#define get_zholes_size(n) (0)
#endif /* CONFIG_NUMA */
#ifdef CONFIG_DISCONTIGMEM
@@ -151,6 +151,4 @@ static inline int pfn_valid(int pfn)
#endif /* CONFIG_NEED_MULTIPLE_NODES */
-extern int early_pfn_to_nid(unsigned long pfn);
-
#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h
index dea8f8e6d86e..8d93f732d72d 100644
--- a/include/asm-i386/page.h
+++ b/include/asm-i386/page.h
@@ -126,9 +126,12 @@ extern int page_is_ram(unsigned long pagenr);
#ifdef __ASSEMBLY__
#define __PAGE_OFFSET (0xC0000000)
+#define __PHYSICAL_START CONFIG_PHYSICAL_START
#else
#define __PAGE_OFFSET (0xC0000000UL)
+#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)
#endif
+#define __KERNEL_START (__PAGE_OFFSET + __PHYSICAL_START)
#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
diff --git a/include/asm-i386/pci.h b/include/asm-i386/pci.h
index fb749b85a739..78c85985aee3 100644
--- a/include/asm-i386/pci.h
+++ b/include/asm-i386/pci.h
@@ -27,7 +27,7 @@ void pcibios_config_init(void);
struct pci_bus * pcibios_scan_root(int bus);
void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq);
+void pcibios_penalize_isa_irq(int irq, int active);
struct irq_routing_table *pcibios_get_irq_routing_table(void);
int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
@@ -99,6 +99,16 @@ static inline void pcibios_add_platform_entries(struct pci_dev *dev)
{
}
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
#endif /* __KERNEL__ */
/* implement the pci_ DMA API in terms of the generic device dma_ one */
diff --git a/include/asm-i386/processor.h b/include/asm-i386/processor.h
index c76c50e96225..5d06e6bd6ba0 100644
--- a/include/asm-i386/processor.h
+++ b/include/asm-i386/processor.h
@@ -691,5 +691,15 @@ extern void select_idle_routine(const struct cpuinfo_x86 *c);
#define cache_line_size() (boot_cpu_data.x86_cache_alignment)
extern unsigned long boot_option_idle_override;
+extern void enable_sep_cpu(void);
+extern int sysenter_setup(void);
+
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
#endif /* __ASM_I386_PROCESSOR_H */
diff --git a/include/asm-i386/serial.h b/include/asm-i386/serial.h
index 21ddecc77c77..e1ecfccb743b 100644
--- a/include/asm-i386/serial.h
+++ b/include/asm-i386/serial.h
@@ -22,109 +22,9 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-#define MCA_COM_FLAGS (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
-#else
-#define MCA_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS \
- MCA_SERIAL_PORT_DFNS
-
diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h
index 55ef31f66bbe..edad9b4712fa 100644
--- a/include/asm-i386/smp.h
+++ b/include/asm-i386/smp.h
@@ -42,10 +42,17 @@ extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
extern void smp_invalidate_rcv(void); /* Process an NMI */
extern void (*mtrr_hook) (void);
extern void zap_low_mappings (void);
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
#define MAX_APICID 256
extern u8 x86_cpu_to_apicid[];
+#ifdef CONFIG_HOTPLUG_CPU
+extern void cpu_exit_clear(void);
+extern void cpu_uninit(void);
+#endif
+
/*
* This function is needed by all SMP systems. It must _always_ be valid
* from the initial startup. We map APIC_BASE very early in page_setup(),
@@ -83,6 +90,9 @@ static __inline int logical_smp_processor_id(void)
}
#endif
+
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
#endif /* !__ASSEMBLY__ */
#define NO_PROC_ID 0xFF /* No processor magic marker */
diff --git a/include/asm-i386/string.h b/include/asm-i386/string.h
index 6a78ac58c194..02c8f5d22065 100644
--- a/include/asm-i386/string.h
+++ b/include/asm-i386/string.h
@@ -116,7 +116,8 @@ __asm__ __volatile__(
"orb $1,%%al\n"
"3:"
:"=a" (__res), "=&S" (d0), "=&D" (d1)
- :"1" (cs),"2" (ct));
+ :"1" (cs),"2" (ct)
+ :"memory");
return __res;
}
@@ -138,8 +139,9 @@ __asm__ __volatile__(
"3:\tsbbl %%eax,%%eax\n\t"
"orb $1,%%al\n"
"4:"
- :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
- :"1" (cs),"2" (ct),"3" (count));
+ :"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
+ :"1" (cs),"2" (ct),"3" (count)
+ :"memory");
return __res;
}
@@ -158,7 +160,9 @@ __asm__ __volatile__(
"movl $1,%1\n"
"2:\tmovl %1,%0\n\t"
"decl %0"
- :"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
+ :"=a" (__res), "=&S" (d0)
+ :"1" (s),"0" (c)
+ :"memory");
return __res;
}
@@ -175,7 +179,9 @@ __asm__ __volatile__(
"leal -1(%%esi),%0\n"
"2:\ttestb %%al,%%al\n\t"
"jne 1b"
- :"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
+ :"=g" (__res), "=&S" (d0), "=&a" (d1)
+ :"0" (0),"1" (s),"2" (c)
+ :"memory");
return __res;
}
@@ -189,7 +195,9 @@ __asm__ __volatile__(
"scasb\n\t"
"notl %0\n\t"
"decl %0"
- :"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffffu));
+ :"=c" (__res), "=&D" (d0)
+ :"1" (s),"a" (0), "0" (0xffffffffu)
+ :"memory");
return __res;
}
@@ -333,7 +341,9 @@ __asm__ __volatile__(
"je 1f\n\t"
"movl $1,%0\n"
"1:\tdecl %0"
- :"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
+ :"=D" (__res), "=&c" (d0)
+ :"a" (c),"0" (cs),"1" (count)
+ :"memory");
return __res;
}
@@ -369,7 +379,7 @@ __asm__ __volatile__(
"je 2f\n\t"
"stosb\n"
"2:"
- : "=&c" (d0), "=&D" (d1)
+ :"=&c" (d0), "=&D" (d1)
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
:"memory");
return (s);
@@ -392,7 +402,8 @@ __asm__ __volatile__(
"jne 1b\n"
"3:\tsubl %2,%0"
:"=a" (__res), "=&d" (d0)
- :"c" (s),"1" (count));
+ :"c" (s),"1" (count)
+ :"memory");
return __res;
}
/* end of additional stuff */
@@ -473,7 +484,8 @@ static inline void * memscan(void * addr, int c, size_t size)
"dec %%edi\n"
"1:"
: "=D" (addr), "=c" (size)
- : "0" (addr), "1" (size), "a" (c));
+ : "0" (addr), "1" (size), "a" (c)
+ : "memory");
return addr;
}
diff --git a/include/asm-i386/tlbflush.h b/include/asm-i386/tlbflush.h
index f22fab0cea26..ab216e1370ef 100644
--- a/include/asm-i386/tlbflush.h
+++ b/include/asm-i386/tlbflush.h
@@ -22,16 +22,18 @@
*/
#define __flush_tlb_global() \
do { \
- unsigned int tmpreg; \
+ unsigned int tmpreg, cr4, cr4_orig; \
\
__asm__ __volatile__( \
- "movl %1, %%cr4; # turn off PGE \n" \
+ "movl %%cr4, %2; # turn off PGE \n" \
+ "movl %2, %1; \n" \
+ "andl %3, %1; \n" \
+ "movl %1, %%cr4; \n" \
"movl %%cr3, %0; \n" \
"movl %0, %%cr3; # flush TLB \n" \
"movl %2, %%cr4; # turn PGE back on \n" \
- : "=&r" (tmpreg) \
- : "r" (mmu_cr4_features & ~X86_CR4_PGE), \
- "r" (mmu_cr4_features) \
+ : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \
+ : "i" (~X86_CR4_PGE) \
: "memory"); \
} while (0)
diff --git a/include/asm-i386/topology.h b/include/asm-i386/topology.h
index 6d0f67507b21..2461b731781e 100644
--- a/include/asm-i386/topology.h
+++ b/include/asm-i386/topology.h
@@ -74,11 +74,14 @@ static inline int node_to_first_cpu(int node)
.imbalance_pct = 125, \
.cache_hot_time = (10*1000000), \
.cache_nice_tries = 1, \
+ .busy_idx = 3, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
.per_cpu_gain = 100, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_WAKE_IDLE \
+ | SD_BALANCE_FORK \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
index 176413fb9ae3..a7cb377745bf 100644
--- a/include/asm-i386/unistd.h
+++ b/include/asm-i386/unistd.h
@@ -294,8 +294,13 @@
#define __NR_add_key 286
#define __NR_request_key 287
#define __NR_keyctl 288
+#define __NR_ioprio_set 289
+#define __NR_ioprio_get 290
+#define __NR_inotify_init 291
+#define __NR_inotify_add_watch 292
+#define __NR_inotify_rm_watch 293
-#define NR_syscalls 289
+#define NR_syscalls 294
/*
* user-visible error numbers are in the range -1 - -128: see
diff --git a/include/asm-ia64/acpi.h b/include/asm-ia64/acpi.h
index 6a26a977f253..4c06d455139c 100644
--- a/include/asm-ia64/acpi.h
+++ b/include/asm-ia64/acpi.h
@@ -98,6 +98,15 @@ const char *acpi_get_sysname (void);
int acpi_request_vector (u32 int_type);
int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
+/*
+ * Record the cpei override flag and current logical cpu. This is
+ * useful for CPU removal.
+ */
+extern unsigned int can_cpei_retarget(void);
+extern unsigned int is_cpu_cpei_target(unsigned int cpu);
+extern void set_cpei_target_cpu(unsigned int cpu);
+extern unsigned int get_cpei_target_cpu(void);
+
#ifdef CONFIG_ACPI_NUMA
/* Proximity bitmap length; _PXM is at most 255 (8 bit)*/
#define MAX_PXM_DOMAINS (256)
diff --git a/include/asm-ia64/hw_irq.h b/include/asm-ia64/hw_irq.h
index cd4e06b74ab6..041ab8c51a64 100644
--- a/include/asm-ia64/hw_irq.h
+++ b/include/asm-ia64/hw_irq.h
@@ -81,7 +81,6 @@ extern __u8 isa_irq_to_vector_map[16];
extern struct hw_interrupt_type irq_type_ia64_lsapic; /* CPU-internal interrupt controller */
-extern int assign_irq_vector_nopanic (int irq); /* allocate a free vector without panic */
extern int assign_irq_vector (int irq); /* allocate a free vector */
extern void free_irq_vector (int vector);
extern void ia64_send_ipi (int cpu, int vector, int delivery_mode, int redirect);
diff --git a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
index 38a7a72791cc..1093f35b3b90 100644
--- a/include/asm-ia64/iosapic.h
+++ b/include/asm-ia64/iosapic.h
@@ -71,8 +71,11 @@ static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
}
extern void __init iosapic_system_init (int pcat_compat);
-extern void __init iosapic_init (unsigned long address,
+extern int __devinit iosapic_init (unsigned long address,
unsigned int gsi_base);
+#ifdef CONFIG_HOTPLUG
+extern int iosapic_remove (unsigned int gsi_base);
+#endif /* CONFIG_HOTPLUG */
extern int gsi_to_vector (unsigned int gsi);
extern int gsi_to_irq (unsigned int gsi);
extern void iosapic_enable_intr (unsigned int vector);
@@ -94,11 +97,14 @@ extern unsigned int iosapic_version (char __iomem *addr);
extern void iosapic_pci_fixup (int);
#ifdef CONFIG_NUMA
-extern void __init map_iosapic_to_node (unsigned int, int);
+extern void __devinit map_iosapic_to_node (unsigned int, int);
#endif
#else
#define iosapic_system_init(pcat_compat) do { } while (0)
-#define iosapic_init(address,gsi_base) do { } while (0)
+#define iosapic_init(address,gsi_base) (-EINVAL)
+#ifdef CONFIG_HOTPLUG
+#define iosapic_remove(gsi_base) (-ENODEV)
+#endif /* CONFIG_HOTPLUG */
#define iosapic_register_intr(gsi,polarity,trigger) (gsi)
#define iosapic_unregister_intr(irq) do { } while (0)
#define iosapic_override_isa_irq(isa_irq,gsi,polarity,trigger) do { } while (0)
diff --git a/include/asm-ia64/kprobes.h b/include/asm-ia64/kprobes.h
index 7b700035e36d..bf36a32e37e4 100644
--- a/include/asm-ia64/kprobes.h
+++ b/include/asm-ia64/kprobes.h
@@ -28,6 +28,7 @@
#include <linux/ptrace.h>
#include <asm/break.h>
+#define MAX_INSN_SIZE 16
#define BREAK_INST (long)(__IA64_BREAK_KPROBE << 6)
typedef union cmp_inst {
@@ -63,6 +64,8 @@ typedef struct _bundle {
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)pentry
+#define ARCH_SUPPORTS_KRETPROBES
+
#define SLOT0_OPCODE_SHIFT (37)
#define SLOT1_p1_OPCODE_SHIFT (37 - (64-46))
#define SLOT2_OPCODE_SHIFT (37)
@@ -94,11 +97,6 @@ struct arch_specific_insn {
};
/* ia64 does not need this */
-static inline void jprobe_return(void)
-{
-}
-
-/* ia64 does not need this */
static inline void arch_copy_kprobe(struct kprobe *p)
{
}
@@ -106,6 +104,12 @@ static inline void arch_copy_kprobe(struct kprobe *p)
#ifdef CONFIG_KPROBES
extern int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data);
+
+/* ia64 does not need this */
+static inline void jprobe_return(void)
+{
+}
+
#else /* !CONFIG_KPROBES */
static inline int kprobe_exceptions_notify(struct notifier_block *self,
unsigned long val, void *data)
diff --git a/include/asm-ia64/mmu_context.h b/include/asm-ia64/mmu_context.h
index 0096e7e05012..e3e5fededb04 100644
--- a/include/asm-ia64/mmu_context.h
+++ b/include/asm-ia64/mmu_context.h
@@ -132,6 +132,9 @@ reload_context (mm_context_t context)
ia64_srlz_i(); /* srlz.i implies srlz.d */
}
+/*
+ * Must be called with preemption off
+ */
static inline void
activate_context (struct mm_struct *mm)
{
diff --git a/include/asm-ia64/mmzone.h b/include/asm-ia64/mmzone.h
index 83ca4043fc11..d32f51e3d6c2 100644
--- a/include/asm-ia64/mmzone.h
+++ b/include/asm-ia64/mmzone.h
@@ -15,6 +15,8 @@
#include <asm/page.h>
#include <asm/meminit.h>
+#ifdef CONFIG_DISCONTIGMEM
+
static inline int pfn_to_nid(unsigned long pfn)
{
#ifdef CONFIG_NUMA
@@ -29,8 +31,6 @@ static inline int pfn_to_nid(unsigned long pfn)
#endif
}
-#ifdef CONFIG_DISCONTIGMEM
-
#ifdef CONFIG_IA64_DIG /* DIG systems are small */
# define MAX_PHYSNODE_ID 8
# define NR_NODE_MEMBLKS (MAX_NUMNODES * 8)
diff --git a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
index a8314ee4e7d2..f11771eadc48 100644
--- a/include/asm-ia64/pci.h
+++ b/include/asm-ia64/pci.h
@@ -47,7 +47,7 @@ pcibios_set_master (struct pci_dev *dev)
}
static inline void
-pcibios_penalize_isa_irq (int irq)
+pcibios_penalize_isa_irq (int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -82,6 +82,25 @@ extern int pcibios_prep_mwi (struct pci_dev *);
#define sg_dma_len(sg) ((sg)->dma_length)
#define sg_dma_address(sg) ((sg)->dma_address)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ unsigned long cacheline_size;
+ u8 byte;
+
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ *strat = PCI_DMA_BURST_MULTIPLE;
+ *strategy_parameter = cacheline_size;
+}
+#endif
+
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
diff --git a/include/asm-ia64/sections.h b/include/asm-ia64/sections.h
index 8e3dbde1b429..e9eb7f62d32b 100644
--- a/include/asm-ia64/sections.h
+++ b/include/asm-ia64/sections.h
@@ -17,6 +17,7 @@ extern char __start_gate_vtop_patchlist[], __end_gate_vtop_patchlist[];
extern char __start_gate_fsyscall_patchlist[], __end_gate_fsyscall_patchlist[];
extern char __start_gate_brl_fsys_bubble_down_patchlist[], __end_gate_brl_fsys_bubble_down_patchlist[];
extern char __start_unwind[], __end_unwind[];
+extern char __start_ivt_text[], __end_ivt_text[];
#endif /* _ASM_IA64_SECTIONS_H */
diff --git a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h
index 1bfdfb4d7b01..103d745dc5f2 100644
--- a/include/asm-ia64/sn/addrs.h
+++ b/include/asm-ia64/sn/addrs.h
@@ -216,6 +216,10 @@
#define TIO_SWIN_WIDGETNUM(x) (((x) >> TIO_SWIN_SIZE_BITS) & TIO_SWIN_WIDGET_MASK)
+#define TIO_IOSPACE_ADDR(n,x) \
+ /* Move in the Chiplet ID for TIO Local Block MMR */ \
+ (REMOTE_ADDR(n,x) | 1UL << (NASID_SHIFT - 2))
+
/*
* The following macros produce the correct base virtual address for
* the hub registers. The REMOTE_HUB_* macro produce
@@ -233,13 +237,16 @@
#define REMOTE_HUB_ADDR(n,x) \
((n & 1) ? \
/* TIO: */ \
- ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x))) \
- : /* SHUB: */ \
- (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x)))\
+ (is_shub2() ? \
+ /* TIO on Shub2 */ \
+ (volatile u64 *)(TIO_IOSPACE_ADDR(n,x)) \
+ : /* TIO on shub1 */ \
+ (volatile u64 *)(GLOBAL_MMR_ADDR(n,x))) \
+ \
+ : /* SHUB1 and SHUB2 MMRs: */ \
+ (((x) & BWIN_TOP) ? ((volatile u64 *)(GLOBAL_MMR_ADDR(n,x))) \
: ((volatile u64 *)(NODE_SWIN_BASE(n,1) + 0x800000 + (x)))))
-
-
#define HUB_L(x) (*((volatile typeof(*x) *)x))
#define HUB_S(x,d) (*((volatile typeof(*x) *)x) = (d))
diff --git a/include/asm-ia64/sn/arch.h b/include/asm-ia64/sn/arch.h
index 635fdce854a8..ab827d298569 100644
--- a/include/asm-ia64/sn/arch.h
+++ b/include/asm-ia64/sn/arch.h
@@ -11,6 +11,7 @@
#ifndef _ASM_IA64_SN_ARCH_H
#define _ASM_IA64_SN_ARCH_H
+#include <linux/numa.h>
#include <asm/types.h>
#include <asm/percpu.h>
#include <asm/sn/types.h>
diff --git a/include/asm-ia64/sn/intr.h b/include/asm-ia64/sn/intr.h
index e51471fb0867..e190dd4213d5 100644
--- a/include/asm-ia64/sn/intr.h
+++ b/include/asm-ia64/sn/intr.h
@@ -9,6 +9,8 @@
#ifndef _ASM_IA64_SN_INTR_H
#define _ASM_IA64_SN_INTR_H
+#include <linux/rcupdate.h>
+
#define SGI_UART_VECTOR (0xe9)
#define SGI_PCIBR_ERROR (0x33)
@@ -33,7 +35,7 @@
// The SN PROM irq struct
struct sn_irq_info {
- struct sn_irq_info *irq_next; /* sharing irq list */
+ struct sn_irq_info *irq_next; /* deprecated DO NOT USE */
short irq_nasid; /* Nasid IRQ is assigned to */
int irq_slice; /* slice IRQ is assigned to */
int irq_cpuid; /* kernel logical cpuid */
@@ -47,6 +49,8 @@ struct sn_irq_info {
int irq_cookie; /* unique cookie */
int irq_flags; /* flags */
int irq_share_cnt; /* num devices sharing IRQ */
+ struct list_head list; /* list of sn_irq_info structs */
+ struct rcu_head rcu; /* rcu callback list */
};
extern void sn_send_IPI_phys(int, long, int, int);
diff --git a/include/asm-ia64/sn/l1.h b/include/asm-ia64/sn/l1.h
index 08050d37b662..2e5f0aa38889 100644
--- a/include/asm-ia64/sn/l1.h
+++ b/include/asm-ia64/sn/l1.h
@@ -33,5 +33,6 @@
#define L1_BRICKTYPE_PA 0x6a /* j */
#define L1_BRICKTYPE_IA 0x6b /* k */
#define L1_BRICKTYPE_ATHENA 0x2b /* + */
+#define L1_BRICKTYPE_DAYTONA 0x7a /* z */
#endif /* _ASM_IA64_SN_L1_H */
diff --git a/arch/ia64/sn/include/pci/pcibr_provider.h b/include/asm-ia64/sn/pcibr_provider.h
index 1cd291d8badd..f9b8d2164007 100644
--- a/arch/ia64/sn/include/pci/pcibr_provider.h
+++ b/include/asm-ia64/sn/pcibr_provider.h
@@ -8,6 +8,9 @@
#ifndef _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
#define _ASM_IA64_SN_PCI_PCIBR_PROVIDER_H
+#include <asm/sn/intr.h>
+#include <asm/sn/pcibus_provider_defs.h>
+
/* Workarounds */
#define PV907516 (1 << 1) /* TIOCP: Don't write the write buffer flush reg */
@@ -20,7 +23,7 @@
#define IS_PIC_SOFT(ps) (ps->pbi_bridge_type == PCIBR_BRIDGETYPE_PIC)
-/*
+/*
* The different PCI Bridge types supported on the SGI Altix platforms
*/
#define PCIBR_BRIDGETYPE_UNKNOWN -1
@@ -100,15 +103,16 @@ struct pcibus_info {
struct ate_resource pbi_int_ate_resource;
uint64_t pbi_int_ate_size;
-
+
uint64_t pbi_dir_xbase;
char pbi_hub_xid;
uint64_t pbi_devreg[8];
- spinlock_t pbi_lock;
uint32_t pbi_valid_devices;
uint32_t pbi_enabled_devices;
+
+ spinlock_t pbi_lock;
};
/*
@@ -148,4 +152,8 @@ extern void pcibr_change_devices_irq(struct sn_irq_info *sn_irq_info);
extern int pcibr_ate_alloc(struct pcibus_info *, int);
extern void pcibr_ate_free(struct pcibus_info *, int);
extern void ate_write(struct pcibus_info *, int, int, uint64_t);
+extern int sal_pcibr_slot_enable(struct pcibus_info *soft, int device,
+ void *resp);
+extern int sal_pcibr_slot_disable(struct pcibus_info *soft, int device,
+ int action, void *resp);
#endif
diff --git a/include/asm-ia64/sn/pcidev.h b/include/asm-ia64/sn/pcidev.h
index ed4031d80811..49711d00ad04 100644
--- a/include/asm-ia64/sn/pcidev.h
+++ b/include/asm-ia64/sn/pcidev.h
@@ -10,11 +10,11 @@
#include <linux/pci.h>
-extern struct sn_irq_info **sn_irq;
-
#define SN_PCIDEV_INFO(pci_dev) \
((struct pcidev_info *)(pci_dev)->sysdata)
+#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
+ (struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
/*
* Given a pci_bus, return the sn pcibus_bussoft struct. Note that
* this only works for root busses, not for busses represented by PPB's.
@@ -23,6 +23,8 @@ extern struct sn_irq_info **sn_irq;
#define SN_PCIBUS_BUSSOFT(pci_bus) \
((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
+#define SN_PCIBUS_BUSSOFT_INFO(pci_bus) \
+ (struct pcibus_info *)((struct pcibus_bussoft *)(PCI_CONTROLLER((pci_bus))->platform_data))
/*
* Given a struct pci_dev, return the sn pcibus_bussoft struct. Note
* that this is not equivalent to SN_PCIBUS_BUSSOFT(pci_dev->bus) due
@@ -50,9 +52,17 @@ struct pcidev_info {
struct sn_irq_info *pdi_sn_irq_info;
struct sn_pcibus_provider *pdi_provider; /* sn pci ops */
+ struct pci_dev *host_pci_dev; /* host bus link */
};
extern void sn_irq_fixup(struct pci_dev *pci_dev,
struct sn_irq_info *sn_irq_info);
-
+extern void sn_irq_unfixup(struct pci_dev *pci_dev);
+extern void sn_pci_controller_fixup(int segment, int busnum,
+ struct pci_bus *bus);
+extern void sn_bus_store_sysdata(struct pci_dev *dev);
+extern void sn_bus_free_sysdata(void);
+extern void sn_pci_fixup_slot(struct pci_dev *dev);
+extern void sn_pci_unfixup_slot(struct pci_dev *dev);
+extern void sn_irq_lh_init(void);
#endif /* _ASM_IA64_SN_PCI_PCIDEV_H */
diff --git a/arch/ia64/sn/include/pci/pic.h b/include/asm-ia64/sn/pic.h
index fd18acecb1e6..0de82e6b0893 100644
--- a/arch/ia64/sn/include/pci/pic.h
+++ b/include/asm-ia64/sn/pic.h
@@ -15,7 +15,7 @@
* PIC handles PCI/X busses. PCI/X requires that the 'bridge' (i.e. PIC)
* be designated as 'device 0'. That is a departure from earlier SGI
* PCI bridges. Because of that we use config space 1 to access the
- * config space of the first actual PCI device on the bus.
+ * config space of the first actual PCI device on the bus.
* Here's what the PIC manual says:
*
* The current PCI-X bus specification now defines that the parent
@@ -29,14 +29,14 @@
* correlated Configs pace and our device space 0 <-> 0, 1 <-> 1, etc.
* PCI-X requires we start a 1, not 0 and currently the PX brick
* does associate our:
- *
+ *
* device 0 with configuration space window 1,
- * device 1 with configuration space window 2,
+ * device 1 with configuration space window 2,
* device 2 with configuration space window 3,
* device 3 with configuration space window 4.
*
- * The net effect is that all config space access are off-by-one with
- * relation to other per-slot accesses on the PIC.
+ * The net effect is that all config space access are off-by-one with
+ * relation to other per-slot accesses on the PIC.
* Here is a table that shows some of that:
*
* Internal Slot#
@@ -65,7 +65,7 @@
*****************************************************************************/
/* NOTE: PIC WAR. PV#854697. PIC does not allow writes just to [31:0]
- * of a 64-bit register. When writing PIC registers, always write the
+ * of a 64-bit register. When writing PIC registers, always write the
* entire 64 bits.
*/
@@ -164,7 +164,7 @@ struct pic {
uint64_t clear_all; /* 0x000{438,,,5F8} */
} p_buf_count[8];
-
+
/* 0x000600-0x0009FF -- PCI/X registers */
uint64_t p_pcix_bus_err_addr; /* 0x000600 */
uint64_t p_pcix_bus_err_attr; /* 0x000608 */
diff --git a/include/asm-ia64/sn/shub_mmr.h b/include/asm-ia64/sn/shub_mmr.h
index 323fa0cd8d83..7de1d1d4b71a 100644
--- a/include/asm-ia64/sn/shub_mmr.h
+++ b/include/asm-ia64/sn/shub_mmr.h
@@ -14,96 +14,98 @@
/* Register "SH_IPI_INT" */
/* SHub Inter-Processor Interrupt Registers */
/* ==================================================================== */
-#define SH1_IPI_INT 0x0000000110000380
-#define SH2_IPI_INT 0x0000000010000380
+#define SH1_IPI_INT __IA64_UL_CONST(0x0000000110000380)
+#define SH2_IPI_INT __IA64_UL_CONST(0x0000000010000380)
/* SH_IPI_INT_TYPE */
/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */
-#define SH_IPI_INT_TYPE_SHFT 0
-#define SH_IPI_INT_TYPE_MASK 0x0000000000000007
+#define SH_IPI_INT_TYPE_SHFT 0
+#define SH_IPI_INT_TYPE_MASK __IA64_UL_CONST(0x0000000000000007)
/* SH_IPI_INT_AGT */
/* Description: Agent, must be 0 for SHub */
-#define SH_IPI_INT_AGT_SHFT 3
-#define SH_IPI_INT_AGT_MASK 0x0000000000000008
+#define SH_IPI_INT_AGT_SHFT 3
+#define SH_IPI_INT_AGT_MASK __IA64_UL_CONST(0x0000000000000008)
/* SH_IPI_INT_PID */
/* Description: Processor ID, same setting as on targeted McKinley */
-#define SH_IPI_INT_PID_SHFT 4
-#define SH_IPI_INT_PID_MASK 0x00000000000ffff0
+#define SH_IPI_INT_PID_SHFT 4
+#define SH_IPI_INT_PID_MASK __IA64_UL_CONST(0x00000000000ffff0)
/* SH_IPI_INT_BASE */
/* Description: Optional interrupt vector area, 2MB aligned */
-#define SH_IPI_INT_BASE_SHFT 21
-#define SH_IPI_INT_BASE_MASK 0x0003ffffffe00000
+#define SH_IPI_INT_BASE_SHFT 21
+#define SH_IPI_INT_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000)
/* SH_IPI_INT_IDX */
/* Description: Targeted McKinley interrupt vector */
-#define SH_IPI_INT_IDX_SHFT 52
-#define SH_IPI_INT_IDX_MASK 0x0ff0000000000000
+#define SH_IPI_INT_IDX_SHFT 52
+#define SH_IPI_INT_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000)
/* SH_IPI_INT_SEND */
/* Description: Send Interrupt Message to PI, This generates a puls */
-#define SH_IPI_INT_SEND_SHFT 63
-#define SH_IPI_INT_SEND_MASK 0x8000000000000000
+#define SH_IPI_INT_SEND_SHFT 63
+#define SH_IPI_INT_SEND_MASK __IA64_UL_CONST(0x8000000000000000)
/* ==================================================================== */
/* Register "SH_EVENT_OCCURRED" */
/* SHub Interrupt Event Occurred */
/* ==================================================================== */
-#define SH1_EVENT_OCCURRED 0x0000000110010000
-#define SH1_EVENT_OCCURRED_ALIAS 0x0000000110010008
-#define SH2_EVENT_OCCURRED 0x0000000010010000
-#define SH2_EVENT_OCCURRED_ALIAS 0x0000000010010008
+#define SH1_EVENT_OCCURRED __IA64_UL_CONST(0x0000000110010000)
+#define SH1_EVENT_OCCURRED_ALIAS __IA64_UL_CONST(0x0000000110010008)
+#define SH2_EVENT_OCCURRED __IA64_UL_CONST(0x0000000010010000)
+#define SH2_EVENT_OCCURRED_ALIAS __IA64_UL_CONST(0x0000000010010008)
/* ==================================================================== */
/* Register "SH_PI_CAM_CONTROL" */
/* CRB CAM MMR Access Control */
/* ==================================================================== */
-#define SH1_PI_CAM_CONTROL 0x0000000120050300
+#define SH1_PI_CAM_CONTROL __IA64_UL_CONST(0x0000000120050300)
/* ==================================================================== */
/* Register "SH_SHUB_ID" */
/* SHub ID Number */
/* ==================================================================== */
-#define SH1_SHUB_ID 0x0000000110060580
-#define SH1_SHUB_ID_REVISION_SHFT 28
-#define SH1_SHUB_ID_REVISION_MASK 0x00000000f0000000
+#define SH1_SHUB_ID __IA64_UL_CONST(0x0000000110060580)
+#define SH1_SHUB_ID_REVISION_SHFT 28
+#define SH1_SHUB_ID_REVISION_MASK __IA64_UL_CONST(0x00000000f0000000)
/* ==================================================================== */
/* Register "SH_RTC" */
/* Real-time Clock */
/* ==================================================================== */
-#define SH1_RTC 0x00000001101c0000
-#define SH2_RTC 0x00000002101c0000
-#define SH_RTC_MASK 0x007fffffffffffff
+#define SH1_RTC __IA64_UL_CONST(0x00000001101c0000)
+#define SH2_RTC __IA64_UL_CONST(0x00000002101c0000)
+#define SH_RTC_MASK __IA64_UL_CONST(0x007fffffffffffff)
/* ==================================================================== */
/* Register "SH_PIO_WRITE_STATUS_0|1" */
/* PIO Write Status for CPU 0 & 1 */
/* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0 0x0000000120070200
-#define SH1_PIO_WRITE_STATUS_1 0x0000000120070280
-#define SH2_PIO_WRITE_STATUS_0 0x0000000020070200
-#define SH2_PIO_WRITE_STATUS_1 0x0000000020070280
-#define SH2_PIO_WRITE_STATUS_2 0x0000000020070300
-#define SH2_PIO_WRITE_STATUS_3 0x0000000020070380
+#define SH1_PIO_WRITE_STATUS_0 __IA64_UL_CONST(0x0000000120070200)
+#define SH1_PIO_WRITE_STATUS_1 __IA64_UL_CONST(0x0000000120070280)
+#define SH2_PIO_WRITE_STATUS_0 __IA64_UL_CONST(0x0000000020070200)
+#define SH2_PIO_WRITE_STATUS_1 __IA64_UL_CONST(0x0000000020070280)
+#define SH2_PIO_WRITE_STATUS_2 __IA64_UL_CONST(0x0000000020070300)
+#define SH2_PIO_WRITE_STATUS_3 __IA64_UL_CONST(0x0000000020070380)
/* SH_PIO_WRITE_STATUS_0_WRITE_DEADLOCK */
/* Description: Deadlock response detected */
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT 1
-#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK 0x0000000000000002
+#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_SHFT 1
+#define SH_PIO_WRITE_STATUS_WRITE_DEADLOCK_MASK \
+ __IA64_UL_CONST(0x0000000000000002)
/* SH_PIO_WRITE_STATUS_0_PENDING_WRITE_COUNT */
/* Description: Count of currently pending PIO writes */
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT 56
-#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK 0x3f00000000000000
+#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_SHFT 56
+#define SH_PIO_WRITE_STATUS_PENDING_WRITE_COUNT_MASK \
+ __IA64_UL_CONST(0x3f00000000000000)
/* ==================================================================== */
/* Register "SH_PIO_WRITE_STATUS_0_ALIAS" */
/* ==================================================================== */
-#define SH1_PIO_WRITE_STATUS_0_ALIAS 0x0000000120070208
-#define SH2_PIO_WRITE_STATUS_0_ALIAS 0x0000000020070208
+#define SH1_PIO_WRITE_STATUS_0_ALIAS __IA64_UL_CONST(0x0000000120070208)
+#define SH2_PIO_WRITE_STATUS_0_ALIAS __IA64_UL_CONST(0x0000000020070208)
/* ==================================================================== */
/* Register "SH_EVENT_OCCURRED" */
@@ -111,33 +113,33 @@
/* ==================================================================== */
/* SH_EVENT_OCCURRED_UART_INT */
/* Description: Pending Junk Bus UART Interrupt */
-#define SH_EVENT_OCCURRED_UART_INT_SHFT 20
-#define SH_EVENT_OCCURRED_UART_INT_MASK 0x0000000000100000
+#define SH_EVENT_OCCURRED_UART_INT_SHFT 20
+#define SH_EVENT_OCCURRED_UART_INT_MASK __IA64_UL_CONST(0x0000000000100000)
/* SH_EVENT_OCCURRED_IPI_INT */
/* Description: Pending IPI Interrupt */
-#define SH_EVENT_OCCURRED_IPI_INT_SHFT 28
-#define SH_EVENT_OCCURRED_IPI_INT_MASK 0x0000000010000000
+#define SH_EVENT_OCCURRED_IPI_INT_SHFT 28
+#define SH_EVENT_OCCURRED_IPI_INT_MASK __IA64_UL_CONST(0x0000000010000000)
/* SH_EVENT_OCCURRED_II_INT0 */
/* Description: Pending II 0 Interrupt */
-#define SH_EVENT_OCCURRED_II_INT0_SHFT 29
-#define SH_EVENT_OCCURRED_II_INT0_MASK 0x0000000020000000
+#define SH_EVENT_OCCURRED_II_INT0_SHFT 29
+#define SH_EVENT_OCCURRED_II_INT0_MASK __IA64_UL_CONST(0x0000000020000000)
/* SH_EVENT_OCCURRED_II_INT1 */
/* Description: Pending II 1 Interrupt */
-#define SH_EVENT_OCCURRED_II_INT1_SHFT 30
-#define SH_EVENT_OCCURRED_II_INT1_MASK 0x0000000040000000
+#define SH_EVENT_OCCURRED_II_INT1_SHFT 30
+#define SH_EVENT_OCCURRED_II_INT1_MASK __IA64_UL_CONST(0x0000000040000000)
/* SH2_EVENT_OCCURRED_EXTIO_INT2 */
/* Description: Pending SHUB 2 EXT IO INT2 */
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT 33
-#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK 0x0000000200000000
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_SHFT 33
+#define SH2_EVENT_OCCURRED_EXTIO_INT2_MASK __IA64_UL_CONST(0x0000000200000000)
/* SH2_EVENT_OCCURRED_EXTIO_INT3 */
/* Description: Pending SHUB 2 EXT IO INT3 */
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT 34
-#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK 0x0000000400000000
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_SHFT 34
+#define SH2_EVENT_OCCURRED_EXTIO_INT3_MASK __IA64_UL_CONST(0x0000000400000000)
#define SH_ALL_INT_MASK \
(SH_EVENT_OCCURRED_UART_INT_MASK | SH_EVENT_OCCURRED_IPI_INT_MASK | \
@@ -149,310 +151,310 @@
/* ==================================================================== */
/* LEDS */
/* ==================================================================== */
-#define SH1_REAL_JUNK_BUS_LED0 0x7fed00000UL
-#define SH1_REAL_JUNK_BUS_LED1 0x7fed10000UL
-#define SH1_REAL_JUNK_BUS_LED2 0x7fed20000UL
-#define SH1_REAL_JUNK_BUS_LED3 0x7fed30000UL
+#define SH1_REAL_JUNK_BUS_LED0 0x7fed00000UL
+#define SH1_REAL_JUNK_BUS_LED1 0x7fed10000UL
+#define SH1_REAL_JUNK_BUS_LED2 0x7fed20000UL
+#define SH1_REAL_JUNK_BUS_LED3 0x7fed30000UL
-#define SH2_REAL_JUNK_BUS_LED0 0xf0000000UL
-#define SH2_REAL_JUNK_BUS_LED1 0xf0010000UL
-#define SH2_REAL_JUNK_BUS_LED2 0xf0020000UL
-#define SH2_REAL_JUNK_BUS_LED3 0xf0030000UL
+#define SH2_REAL_JUNK_BUS_LED0 0xf0000000UL
+#define SH2_REAL_JUNK_BUS_LED1 0xf0010000UL
+#define SH2_REAL_JUNK_BUS_LED2 0xf0020000UL
+#define SH2_REAL_JUNK_BUS_LED3 0xf0030000UL
/* ==================================================================== */
/* Register "SH1_PTC_0" */
/* Puge Translation Cache Message Configuration Information */
/* ==================================================================== */
-#define SH1_PTC_0 0x00000001101a0000
+#define SH1_PTC_0 __IA64_UL_CONST(0x00000001101a0000)
/* SH1_PTC_0_A */
/* Description: Type */
-#define SH1_PTC_0_A_SHFT 0
+#define SH1_PTC_0_A_SHFT 0
/* SH1_PTC_0_PS */
/* Description: Page Size */
-#define SH1_PTC_0_PS_SHFT 2
+#define SH1_PTC_0_PS_SHFT 2
/* SH1_PTC_0_RID */
/* Description: Region ID */
-#define SH1_PTC_0_RID_SHFT 8
+#define SH1_PTC_0_RID_SHFT 8
/* SH1_PTC_0_START */
/* Description: Start */
-#define SH1_PTC_0_START_SHFT 63
+#define SH1_PTC_0_START_SHFT 63
/* ==================================================================== */
/* Register "SH1_PTC_1" */
/* Puge Translation Cache Message Configuration Information */
/* ==================================================================== */
-#define SH1_PTC_1 0x00000001101a0080
+#define SH1_PTC_1 __IA64_UL_CONST(0x00000001101a0080)
/* SH1_PTC_1_START */
/* Description: PTC_1 Start */
-#define SH1_PTC_1_START_SHFT 63
-
+#define SH1_PTC_1_START_SHFT 63
/* ==================================================================== */
/* Register "SH2_PTC" */
/* Puge Translation Cache Message Configuration Information */
/* ==================================================================== */
-#define SH2_PTC 0x0000000170000000
+#define SH2_PTC __IA64_UL_CONST(0x0000000170000000)
/* SH2_PTC_A */
/* Description: Type */
-#define SH2_PTC_A_SHFT 0
+#define SH2_PTC_A_SHFT 0
/* SH2_PTC_PS */
/* Description: Page Size */
-#define SH2_PTC_PS_SHFT 2
+#define SH2_PTC_PS_SHFT 2
/* SH2_PTC_RID */
/* Description: Region ID */
-#define SH2_PTC_RID_SHFT 4
+#define SH2_PTC_RID_SHFT 4
/* SH2_PTC_START */
/* Description: Start */
-#define SH2_PTC_START_SHFT 63
+#define SH2_PTC_START_SHFT 63
/* SH2_PTC_ADDR_RID */
/* Description: Region ID */
-#define SH2_PTC_ADDR_SHFT 4
-#define SH2_PTC_ADDR_MASK 0x1ffffffffffff000
+#define SH2_PTC_ADDR_SHFT 4
+#define SH2_PTC_ADDR_MASK __IA64_UL_CONST(0x1ffffffffffff000)
/* ==================================================================== */
/* Register "SH_RTC1_INT_CONFIG" */
/* SHub RTC 1 Interrupt Config Registers */
/* ==================================================================== */
-#define SH1_RTC1_INT_CONFIG 0x0000000110001480
-#define SH2_RTC1_INT_CONFIG 0x0000000010001480
-#define SH_RTC1_INT_CONFIG_MASK 0x0ff3ffffffefffff
-#define SH_RTC1_INT_CONFIG_INIT 0x0000000000000000
+#define SH1_RTC1_INT_CONFIG __IA64_UL_CONST(0x0000000110001480)
+#define SH2_RTC1_INT_CONFIG __IA64_UL_CONST(0x0000000010001480)
+#define SH_RTC1_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC1_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC1_INT_CONFIG_TYPE */
/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */
-#define SH_RTC1_INT_CONFIG_TYPE_SHFT 0
-#define SH_RTC1_INT_CONFIG_TYPE_MASK 0x0000000000000007
+#define SH_RTC1_INT_CONFIG_TYPE_SHFT 0
+#define SH_RTC1_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007)
/* SH_RTC1_INT_CONFIG_AGT */
/* Description: Agent, must be 0 for SHub */
-#define SH_RTC1_INT_CONFIG_AGT_SHFT 3
-#define SH_RTC1_INT_CONFIG_AGT_MASK 0x0000000000000008
+#define SH_RTC1_INT_CONFIG_AGT_SHFT 3
+#define SH_RTC1_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008)
/* SH_RTC1_INT_CONFIG_PID */
/* Description: Processor ID, same setting as on targeted McKinley */
-#define SH_RTC1_INT_CONFIG_PID_SHFT 4
-#define SH_RTC1_INT_CONFIG_PID_MASK 0x00000000000ffff0
+#define SH_RTC1_INT_CONFIG_PID_SHFT 4
+#define SH_RTC1_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0)
/* SH_RTC1_INT_CONFIG_BASE */
/* Description: Optional interrupt vector area, 2MB aligned */
-#define SH_RTC1_INT_CONFIG_BASE_SHFT 21
-#define SH_RTC1_INT_CONFIG_BASE_MASK 0x0003ffffffe00000
+#define SH_RTC1_INT_CONFIG_BASE_SHFT 21
+#define SH_RTC1_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000)
/* SH_RTC1_INT_CONFIG_IDX */
/* Description: Targeted McKinley interrupt vector */
-#define SH_RTC1_INT_CONFIG_IDX_SHFT 52
-#define SH_RTC1_INT_CONFIG_IDX_MASK 0x0ff0000000000000
+#define SH_RTC1_INT_CONFIG_IDX_SHFT 52
+#define SH_RTC1_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000)
/* ==================================================================== */
/* Register "SH_RTC1_INT_ENABLE" */
/* SHub RTC 1 Interrupt Enable Registers */
/* ==================================================================== */
-#define SH1_RTC1_INT_ENABLE 0x0000000110001500
-#define SH2_RTC1_INT_ENABLE 0x0000000010001500
-#define SH_RTC1_INT_ENABLE_MASK 0x0000000000000001
-#define SH_RTC1_INT_ENABLE_INIT 0x0000000000000000
+#define SH1_RTC1_INT_ENABLE __IA64_UL_CONST(0x0000000110001500)
+#define SH2_RTC1_INT_ENABLE __IA64_UL_CONST(0x0000000010001500)
+#define SH_RTC1_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC1_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC1_INT_ENABLE_RTC1_ENABLE */
/* Description: Enable RTC 1 Interrupt */
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT 0
-#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK 0x0000000000000001
+#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_SHFT 0
+#define SH_RTC1_INT_ENABLE_RTC1_ENABLE_MASK \
+ __IA64_UL_CONST(0x0000000000000001)
/* ==================================================================== */
/* Register "SH_RTC2_INT_CONFIG" */
/* SHub RTC 2 Interrupt Config Registers */
/* ==================================================================== */
-#define SH1_RTC2_INT_CONFIG 0x0000000110001580
-#define SH2_RTC2_INT_CONFIG 0x0000000010001580
-#define SH_RTC2_INT_CONFIG_MASK 0x0ff3ffffffefffff
-#define SH_RTC2_INT_CONFIG_INIT 0x0000000000000000
+#define SH1_RTC2_INT_CONFIG __IA64_UL_CONST(0x0000000110001580)
+#define SH2_RTC2_INT_CONFIG __IA64_UL_CONST(0x0000000010001580)
+#define SH_RTC2_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC2_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC2_INT_CONFIG_TYPE */
/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */
-#define SH_RTC2_INT_CONFIG_TYPE_SHFT 0
-#define SH_RTC2_INT_CONFIG_TYPE_MASK 0x0000000000000007
+#define SH_RTC2_INT_CONFIG_TYPE_SHFT 0
+#define SH_RTC2_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007)
/* SH_RTC2_INT_CONFIG_AGT */
/* Description: Agent, must be 0 for SHub */
-#define SH_RTC2_INT_CONFIG_AGT_SHFT 3
-#define SH_RTC2_INT_CONFIG_AGT_MASK 0x0000000000000008
+#define SH_RTC2_INT_CONFIG_AGT_SHFT 3
+#define SH_RTC2_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008)
/* SH_RTC2_INT_CONFIG_PID */
/* Description: Processor ID, same setting as on targeted McKinley */
-#define SH_RTC2_INT_CONFIG_PID_SHFT 4
-#define SH_RTC2_INT_CONFIG_PID_MASK 0x00000000000ffff0
+#define SH_RTC2_INT_CONFIG_PID_SHFT 4
+#define SH_RTC2_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0)
/* SH_RTC2_INT_CONFIG_BASE */
/* Description: Optional interrupt vector area, 2MB aligned */
-#define SH_RTC2_INT_CONFIG_BASE_SHFT 21
-#define SH_RTC2_INT_CONFIG_BASE_MASK 0x0003ffffffe00000
+#define SH_RTC2_INT_CONFIG_BASE_SHFT 21
+#define SH_RTC2_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000)
/* SH_RTC2_INT_CONFIG_IDX */
/* Description: Targeted McKinley interrupt vector */
-#define SH_RTC2_INT_CONFIG_IDX_SHFT 52
-#define SH_RTC2_INT_CONFIG_IDX_MASK 0x0ff0000000000000
+#define SH_RTC2_INT_CONFIG_IDX_SHFT 52
+#define SH_RTC2_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000)
/* ==================================================================== */
/* Register "SH_RTC2_INT_ENABLE" */
/* SHub RTC 2 Interrupt Enable Registers */
/* ==================================================================== */
-#define SH1_RTC2_INT_ENABLE 0x0000000110001600
-#define SH2_RTC2_INT_ENABLE 0x0000000010001600
-#define SH_RTC2_INT_ENABLE_MASK 0x0000000000000001
-#define SH_RTC2_INT_ENABLE_INIT 0x0000000000000000
+#define SH1_RTC2_INT_ENABLE __IA64_UL_CONST(0x0000000110001600)
+#define SH2_RTC2_INT_ENABLE __IA64_UL_CONST(0x0000000010001600)
+#define SH_RTC2_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC2_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC2_INT_ENABLE_RTC2_ENABLE */
/* Description: Enable RTC 2 Interrupt */
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT 0
-#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK 0x0000000000000001
+#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_SHFT 0
+#define SH_RTC2_INT_ENABLE_RTC2_ENABLE_MASK \
+ __IA64_UL_CONST(0x0000000000000001)
/* ==================================================================== */
/* Register "SH_RTC3_INT_CONFIG" */
/* SHub RTC 3 Interrupt Config Registers */
/* ==================================================================== */
-#define SH1_RTC3_INT_CONFIG 0x0000000110001680
-#define SH2_RTC3_INT_CONFIG 0x0000000010001680
-#define SH_RTC3_INT_CONFIG_MASK 0x0ff3ffffffefffff
-#define SH_RTC3_INT_CONFIG_INIT 0x0000000000000000
+#define SH1_RTC3_INT_CONFIG __IA64_UL_CONST(0x0000000110001680)
+#define SH2_RTC3_INT_CONFIG __IA64_UL_CONST(0x0000000010001680)
+#define SH_RTC3_INT_CONFIG_MASK __IA64_UL_CONST(0x0ff3ffffffefffff)
+#define SH_RTC3_INT_CONFIG_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC3_INT_CONFIG_TYPE */
/* Description: Type of Interrupt: 0=INT, 2=PMI, 4=NMI, 5=INIT */
-#define SH_RTC3_INT_CONFIG_TYPE_SHFT 0
-#define SH_RTC3_INT_CONFIG_TYPE_MASK 0x0000000000000007
+#define SH_RTC3_INT_CONFIG_TYPE_SHFT 0
+#define SH_RTC3_INT_CONFIG_TYPE_MASK __IA64_UL_CONST(0x0000000000000007)
/* SH_RTC3_INT_CONFIG_AGT */
/* Description: Agent, must be 0 for SHub */
-#define SH_RTC3_INT_CONFIG_AGT_SHFT 3
-#define SH_RTC3_INT_CONFIG_AGT_MASK 0x0000000000000008
+#define SH_RTC3_INT_CONFIG_AGT_SHFT 3
+#define SH_RTC3_INT_CONFIG_AGT_MASK __IA64_UL_CONST(0x0000000000000008)
/* SH_RTC3_INT_CONFIG_PID */
/* Description: Processor ID, same setting as on targeted McKinley */
-#define SH_RTC3_INT_CONFIG_PID_SHFT 4
-#define SH_RTC3_INT_CONFIG_PID_MASK 0x00000000000ffff0
+#define SH_RTC3_INT_CONFIG_PID_SHFT 4
+#define SH_RTC3_INT_CONFIG_PID_MASK __IA64_UL_CONST(0x00000000000ffff0)
/* SH_RTC3_INT_CONFIG_BASE */
/* Description: Optional interrupt vector area, 2MB aligned */
-#define SH_RTC3_INT_CONFIG_BASE_SHFT 21
-#define SH_RTC3_INT_CONFIG_BASE_MASK 0x0003ffffffe00000
+#define SH_RTC3_INT_CONFIG_BASE_SHFT 21
+#define SH_RTC3_INT_CONFIG_BASE_MASK __IA64_UL_CONST(0x0003ffffffe00000)
/* SH_RTC3_INT_CONFIG_IDX */
/* Description: Targeted McKinley interrupt vector */
-#define SH_RTC3_INT_CONFIG_IDX_SHFT 52
-#define SH_RTC3_INT_CONFIG_IDX_MASK 0x0ff0000000000000
+#define SH_RTC3_INT_CONFIG_IDX_SHFT 52
+#define SH_RTC3_INT_CONFIG_IDX_MASK __IA64_UL_CONST(0x0ff0000000000000)
/* ==================================================================== */
/* Register "SH_RTC3_INT_ENABLE" */
/* SHub RTC 3 Interrupt Enable Registers */
/* ==================================================================== */
-#define SH1_RTC3_INT_ENABLE 0x0000000110001700
-#define SH2_RTC3_INT_ENABLE 0x0000000010001700
-#define SH_RTC3_INT_ENABLE_MASK 0x0000000000000001
-#define SH_RTC3_INT_ENABLE_INIT 0x0000000000000000
+#define SH1_RTC3_INT_ENABLE __IA64_UL_CONST(0x0000000110001700)
+#define SH2_RTC3_INT_ENABLE __IA64_UL_CONST(0x0000000010001700)
+#define SH_RTC3_INT_ENABLE_MASK __IA64_UL_CONST(0x0000000000000001)
+#define SH_RTC3_INT_ENABLE_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_RTC3_INT_ENABLE_RTC3_ENABLE */
/* Description: Enable RTC 3 Interrupt */
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT 0
-#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK 0x0000000000000001
+#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_SHFT 0
+#define SH_RTC3_INT_ENABLE_RTC3_ENABLE_MASK \
+ __IA64_UL_CONST(0x0000000000000001)
/* SH_EVENT_OCCURRED_RTC1_INT */
/* Description: Pending RTC 1 Interrupt */
-#define SH_EVENT_OCCURRED_RTC1_INT_SHFT 24
-#define SH_EVENT_OCCURRED_RTC1_INT_MASK 0x0000000001000000
+#define SH_EVENT_OCCURRED_RTC1_INT_SHFT 24
+#define SH_EVENT_OCCURRED_RTC1_INT_MASK __IA64_UL_CONST(0x0000000001000000)
/* SH_EVENT_OCCURRED_RTC2_INT */
/* Description: Pending RTC 2 Interrupt */
-#define SH_EVENT_OCCURRED_RTC2_INT_SHFT 25
-#define SH_EVENT_OCCURRED_RTC2_INT_MASK 0x0000000002000000
+#define SH_EVENT_OCCURRED_RTC2_INT_SHFT 25
+#define SH_EVENT_OCCURRED_RTC2_INT_MASK __IA64_UL_CONST(0x0000000002000000)
/* SH_EVENT_OCCURRED_RTC3_INT */
/* Description: Pending RTC 3 Interrupt */
-#define SH_EVENT_OCCURRED_RTC3_INT_SHFT 26
-#define SH_EVENT_OCCURRED_RTC3_INT_MASK 0x0000000004000000
+#define SH_EVENT_OCCURRED_RTC3_INT_SHFT 26
+#define SH_EVENT_OCCURRED_RTC3_INT_MASK __IA64_UL_CONST(0x0000000004000000)
/* ==================================================================== */
/* Register "SH_IPI_ACCESS" */
/* CPU interrupt Access Permission Bits */
/* ==================================================================== */
-#define SH1_IPI_ACCESS 0x0000000110060480
-#define SH2_IPI_ACCESS0 0x0000000010060c00
-#define SH2_IPI_ACCESS1 0x0000000010060c80
-#define SH2_IPI_ACCESS2 0x0000000010060d00
-#define SH2_IPI_ACCESS3 0x0000000010060d80
+#define SH1_IPI_ACCESS __IA64_UL_CONST(0x0000000110060480)
+#define SH2_IPI_ACCESS0 __IA64_UL_CONST(0x0000000010060c00)
+#define SH2_IPI_ACCESS1 __IA64_UL_CONST(0x0000000010060c80)
+#define SH2_IPI_ACCESS2 __IA64_UL_CONST(0x0000000010060d00)
+#define SH2_IPI_ACCESS3 __IA64_UL_CONST(0x0000000010060d80)
/* ==================================================================== */
/* Register "SH_INT_CMPB" */
/* RTC Compare Value for Processor B */
/* ==================================================================== */
-#define SH1_INT_CMPB 0x00000001101b0080
-#define SH2_INT_CMPB 0x00000000101b0080
-#define SH_INT_CMPB_MASK 0x007fffffffffffff
-#define SH_INT_CMPB_INIT 0x0000000000000000
+#define SH1_INT_CMPB __IA64_UL_CONST(0x00000001101b0080)
+#define SH2_INT_CMPB __IA64_UL_CONST(0x00000000101b0080)
+#define SH_INT_CMPB_MASK __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPB_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_INT_CMPB_REAL_TIME_CMPB */
/* Description: Real Time Clock Compare */
-#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT 0
-#define SH_INT_CMPB_REAL_TIME_CMPB_MASK 0x007fffffffffffff
+#define SH_INT_CMPB_REAL_TIME_CMPB_SHFT 0
+#define SH_INT_CMPB_REAL_TIME_CMPB_MASK __IA64_UL_CONST(0x007fffffffffffff)
/* ==================================================================== */
/* Register "SH_INT_CMPC" */
/* RTC Compare Value for Processor C */
/* ==================================================================== */
-#define SH1_INT_CMPC 0x00000001101b0100
-#define SH2_INT_CMPC 0x00000000101b0100
-#define SH_INT_CMPC_MASK 0x007fffffffffffff
-#define SH_INT_CMPC_INIT 0x0000000000000000
+#define SH1_INT_CMPC __IA64_UL_CONST(0x00000001101b0100)
+#define SH2_INT_CMPC __IA64_UL_CONST(0x00000000101b0100)
+#define SH_INT_CMPC_MASK __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPC_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_INT_CMPC_REAL_TIME_CMPC */
/* Description: Real Time Clock Compare */
-#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT 0
-#define SH_INT_CMPC_REAL_TIME_CMPC_MASK 0x007fffffffffffff
+#define SH_INT_CMPC_REAL_TIME_CMPC_SHFT 0
+#define SH_INT_CMPC_REAL_TIME_CMPC_MASK __IA64_UL_CONST(0x007fffffffffffff)
/* ==================================================================== */
/* Register "SH_INT_CMPD" */
/* RTC Compare Value for Processor D */
/* ==================================================================== */
-#define SH1_INT_CMPD 0x00000001101b0180
-#define SH2_INT_CMPD 0x00000000101b0180
-#define SH_INT_CMPD_MASK 0x007fffffffffffff
-#define SH_INT_CMPD_INIT 0x0000000000000000
+#define SH1_INT_CMPD __IA64_UL_CONST(0x00000001101b0180)
+#define SH2_INT_CMPD __IA64_UL_CONST(0x00000000101b0180)
+#define SH_INT_CMPD_MASK __IA64_UL_CONST(0x007fffffffffffff)
+#define SH_INT_CMPD_INIT __IA64_UL_CONST(0x0000000000000000)
/* SH_INT_CMPD_REAL_TIME_CMPD */
/* Description: Real Time Clock Compare */
-#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT 0
-#define SH_INT_CMPD_REAL_TIME_CMPD_MASK 0x007fffffffffffff
+#define SH_INT_CMPD_REAL_TIME_CMPD_SHFT 0
+#define SH_INT_CMPD_REAL_TIME_CMPD_MASK __IA64_UL_CONST(0x007fffffffffffff)
/* ==================================================================== */
/* Register "SH_MD_DQLP_MMR_DIR_PRIVEC0" */
/* privilege vector for acc=0 */
/* ==================================================================== */
-
-#define SH1_MD_DQLP_MMR_DIR_PRIVEC0 0x0000000100030300
+#define SH1_MD_DQLP_MMR_DIR_PRIVEC0 __IA64_UL_CONST(0x0000000100030300)
/* ==================================================================== */
/* Register "SH_MD_DQRP_MMR_DIR_PRIVEC0" */
/* privilege vector for acc=0 */
/* ==================================================================== */
-
-#define SH1_MD_DQRP_MMR_DIR_PRIVEC0 0x0000000100050300
+#define SH1_MD_DQRP_MMR_DIR_PRIVEC0 __IA64_UL_CONST(0x0000000100050300)
/* ==================================================================== */
/* Some MMRs are functionally identical (or close enough) on both SHUB1 */
@@ -484,17 +486,17 @@
/* Engine 0 Control and Status Register */
/* ========================================================================== */
-#define SH2_BT_ENG_CSR_0 0x0000000030040000
-#define SH2_BT_ENG_SRC_ADDR_0 0x0000000030040080
-#define SH2_BT_ENG_DEST_ADDR_0 0x0000000030040100
-#define SH2_BT_ENG_NOTIF_ADDR_0 0x0000000030040180
+#define SH2_BT_ENG_CSR_0 __IA64_UL_CONST(0x0000000030040000)
+#define SH2_BT_ENG_SRC_ADDR_0 __IA64_UL_CONST(0x0000000030040080)
+#define SH2_BT_ENG_DEST_ADDR_0 __IA64_UL_CONST(0x0000000030040100)
+#define SH2_BT_ENG_NOTIF_ADDR_0 __IA64_UL_CONST(0x0000000030040180)
/* ========================================================================== */
/* BTE interfaces 1-3 */
/* ========================================================================== */
-#define SH2_BT_ENG_CSR_1 0x0000000030050000
-#define SH2_BT_ENG_CSR_2 0x0000000030060000
-#define SH2_BT_ENG_CSR_3 0x0000000030070000
+#define SH2_BT_ENG_CSR_1 __IA64_UL_CONST(0x0000000030050000)
+#define SH2_BT_ENG_CSR_2 __IA64_UL_CONST(0x0000000030060000)
+#define SH2_BT_ENG_CSR_3 __IA64_UL_CONST(0x0000000030070000)
#endif /* _ASM_IA64_SN_SHUB_MMR_H */
diff --git a/include/asm-ia64/sn/simulator.h b/include/asm-ia64/sn/simulator.h
index 78eb4f869c8b..cf770e246af5 100644
--- a/include/asm-ia64/sn/simulator.h
+++ b/include/asm-ia64/sn/simulator.h
@@ -10,16 +10,17 @@
#include <linux/config.h>
-#ifdef CONFIG_IA64_SGI_SN_SIM
-
#define SNMAGIC 0xaeeeeeee8badbeefL
-#define IS_RUNNING_ON_SIMULATOR() ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;})
-
-#define SIMULATOR_SLEEP() asm("nop.i 0x8beef")
+#define IS_MEDUSA() ({long sn; asm("mov %0=cpuid[%1]" : "=r"(sn) : "r"(2)); sn == SNMAGIC;})
+#ifdef CONFIG_IA64_SGI_SN_SIM
+#define SIMULATOR_SLEEP() asm("nop.i 0x8beef")
+#define IS_RUNNING_ON_SIMULATOR() (sn_prom_type)
+#define IS_RUNNING_ON_FAKE_PROM() (sn_prom_type == 2)
+extern int sn_prom_type; /* 0=hardware, 1=medusa/realprom, 2=medusa/fakeprom */
#else
-
#define IS_RUNNING_ON_SIMULATOR() (0)
+#define IS_RUNNING_ON_FAKE_PROM() (0)
#define SIMULATOR_SLEEP()
#endif
diff --git a/include/asm-ia64/sn/sn2/sn_hwperf.h b/include/asm-ia64/sn/sn2/sn_hwperf.h
index b0c4d6dd77ba..df75f4c4aec3 100644
--- a/include/asm-ia64/sn/sn2/sn_hwperf.h
+++ b/include/asm-ia64/sn/sn2/sn_hwperf.h
@@ -223,4 +223,6 @@ struct sn_hwperf_ioctl_args {
#define SN_HWPERF_OP_RECONFIGURE 253
#define SN_HWPERF_OP_INVAL 254
+int sn_topology_open(struct inode *inode, struct file *file);
+int sn_topology_release(struct inode *inode, struct file *file);
#endif /* SN_HWPERF_H */
diff --git a/include/asm-ia64/sn/sn_cpuid.h b/include/asm-ia64/sn/sn_cpuid.h
index 20b300187669..d2c1d34dcce4 100644
--- a/include/asm-ia64/sn/sn_cpuid.h
+++ b/include/asm-ia64/sn/sn_cpuid.h
@@ -81,11 +81,6 @@
*
*/
-#ifndef CONFIG_SMP
-#define cpu_physical_id(cpuid) ((ia64_getreg(_IA64_REG_CR_LID) >> 16) & 0xffff)
-#endif
-
-
#define get_node_number(addr) NASID_GET(addr)
/*
diff --git a/include/asm-ia64/sn/sn_sal.h b/include/asm-ia64/sn/sn_sal.h
index eb0395ad0d6a..27976d223186 100644
--- a/include/asm-ia64/sn/sn_sal.h
+++ b/include/asm-ia64/sn/sn_sal.h
@@ -132,43 +132,30 @@
#define SALRET_INVALID_ARG (-2)
#define SALRET_ERROR (-3)
+#define SN_SAL_FAKE_PROM 0x02009999
/**
- * sn_sal_rev_major - get the major SGI SAL revision number
- *
- * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
- * This routine simply extracts the major value from the
- * @ia64_sal_systab structure constructed by ia64_sal_init().
- */
-static inline int
-sn_sal_rev_major(void)
+ * sn_sal_revision - get the SGI SAL revision number
+ *
+ * The SGI PROM stores its version in the sal_[ab]_rev_(major|minor).
+ * This routine simply extracts the major and minor values and
+ * presents them in a u32 format.
+ *
+ * For example, version 4.05 would be represented at 0x0405.
+ */
+static inline u32
+sn_sal_rev(void)
{
struct ia64_sal_systab *systab = efi.sal_systab;
- return (int)systab->sal_b_rev_major;
-}
-
-/**
- * sn_sal_rev_minor - get the minor SGI SAL revision number
- *
- * The SGI PROM stores its version in sal_[ab]_rev_(major|minor).
- * This routine simply extracts the minor value from the
- * @ia64_sal_systab structure constructed by ia64_sal_init().
- */
-static inline int
-sn_sal_rev_minor(void)
-{
- struct ia64_sal_systab *systab = efi.sal_systab;
-
- return (int)systab->sal_b_rev_minor;
+ return (u32)(systab->sal_b_rev_major << 8 | systab->sal_b_rev_minor);
}
/*
* Specify the minimum PROM revsion required for this kernel.
* Note that they're stored in hex format...
*/
-#define SN_SAL_MIN_MAJOR 0x4 /* SN2 kernels need at least PROM 4.0 */
-#define SN_SAL_MIN_MINOR 0x0
+#define SN_SAL_MIN_VERSION 0x0404
/*
* Returns the master console nasid, if the call fails, return an illegal
@@ -1105,4 +1092,12 @@ ia64_sn_bte_recovery(nasid_t nasid)
return (int) rv.status;
}
+static inline int
+ia64_sn_is_fake_prom(void)
+{
+ struct ia64_sal_retval rv;
+ SAL_CALL_NOLOCK(rv, SN_SAL_FAKE_PROM, 0, 0, 0, 0, 0, 0, 0);
+ return (rv.status == 0);
+}
+
#endif /* _ASM_IA64_SN_SN_SAL_H */
diff --git a/include/asm-ia64/sn/tioca_provider.h b/include/asm-ia64/sn/tioca_provider.h
index b6acc22ab239..5ccec608d325 100644
--- a/include/asm-ia64/sn/tioca_provider.h
+++ b/include/asm-ia64/sn/tioca_provider.h
@@ -201,6 +201,7 @@ tioca_tlbflush(struct tioca_kernel *tioca_kernel)
}
extern uint32_t tioca_gart_found;
+extern struct list_head tioca_list;
extern int tioca_init_provider(void);
extern void tioca_fastwrite_enable(struct tioca_kernel *tioca_kern);
#endif /* _ASM_IA64_SN_TIO_CA_AGP_PROVIDER_H */
diff --git a/arch/ia64/sn/include/pci/tiocp.h b/include/asm-ia64/sn/tiocp.h
index f07c83b2bf6e..5f2489c9d2dd 100644
--- a/arch/ia64/sn/include/pci/tiocp.h
+++ b/include/asm-ia64/sn/tiocp.h
@@ -111,7 +111,7 @@ struct tiocp{
uint64_t clear_all; /* 0x000{438,,,5F8} */
} cp_buf_count[8];
-
+
/* 0x000600-0x0009FF -- PCI/X registers */
uint64_t cp_pcix_bus_err_addr; /* 0x000600 */
uint64_t cp_pcix_bus_err_attr; /* 0x000608 */
diff --git a/include/asm-ia64/sn/xp.h b/include/asm-ia64/sn/xp.h
index 9902185c0288..1df1c9f61a65 100644
--- a/include/asm-ia64/sn/xp.h
+++ b/include/asm-ia64/sn/xp.h
@@ -16,7 +16,6 @@
#define _ASM_IA64_SN_XP_H
-#include <linux/version.h>
#include <linux/cache.h>
#include <linux/hardirq.h>
#include <asm/sn/types.h>
diff --git a/include/asm-ia64/system.h b/include/asm-ia64/system.h
index 6f516e76d1f0..cd2cf76b2db1 100644
--- a/include/asm-ia64/system.h
+++ b/include/asm-ia64/system.h
@@ -183,8 +183,6 @@ do { \
#ifdef __KERNEL__
-#define prepare_to_switch() do { } while(0)
-
#ifdef CONFIG_IA32_SUPPORT
# define IS_IA32_PROCESS(regs) (ia64_psr(regs)->is != 0)
#else
@@ -274,13 +272,7 @@ extern void ia64_load_extra (struct task_struct *task);
* of that CPU which will not be released, because there we wait for the
* tasklist_lock to become available.
*/
-#define prepare_arch_switch(rq, next) \
-do { \
- spin_lock(&(next)->switch_lock); \
- spin_unlock(&(rq)->lock); \
-} while (0)
-#define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock)
-#define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
+#define __ARCH_WANT_UNLOCKED_CTXSW
#define ia64_platform_is(x) (strcmp(x, platform_name) == 0)
diff --git a/include/asm-ia64/topology.h b/include/asm-ia64/topology.h
index 21cf351fd05c..4e64c2a6b369 100644
--- a/include/asm-ia64/topology.h
+++ b/include/asm-ia64/topology.h
@@ -42,25 +42,54 @@
void build_cpu_to_node_map(void);
+#define SD_CPU_INIT (struct sched_domain) { \
+ .span = CPU_MASK_NONE, \
+ .parent = NULL, \
+ .groups = NULL, \
+ .min_interval = 1, \
+ .max_interval = 4, \
+ .busy_factor = 64, \
+ .imbalance_pct = 125, \
+ .cache_hot_time = (10*1000000), \
+ .per_cpu_gain = 100, \
+ .cache_nice_tries = 2, \
+ .busy_idx = 2, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
+ .flags = SD_LOAD_BALANCE \
+ | SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_EXEC \
+ | SD_WAKE_AFFINE, \
+ .last_balance = jiffies, \
+ .balance_interval = 1, \
+ .nr_balance_failed = 0, \
+}
+
/* sched_domains SD_NODE_INIT for IA64 NUMA machines */
#define SD_NODE_INIT (struct sched_domain) { \
.span = CPU_MASK_NONE, \
.parent = NULL, \
.groups = NULL, \
- .min_interval = 80, \
- .max_interval = 320, \
- .busy_factor = 320, \
+ .min_interval = 8, \
+ .max_interval = 8*(min(num_online_cpus(), 32)), \
+ .busy_factor = 64, \
.imbalance_pct = 125, \
.cache_hot_time = (10*1000000), \
- .cache_nice_tries = 1, \
+ .cache_nice_tries = 2, \
+ .busy_idx = 3, \
+ .idle_idx = 2, \
+ .newidle_idx = 0, /* unused */ \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
.per_cpu_gain = 100, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_EXEC \
- | SD_BALANCE_NEWIDLE \
- | SD_WAKE_IDLE \
+ | SD_BALANCE_FORK \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
- .balance_interval = 1, \
+ .balance_interval = 64, \
.nr_balance_failed = 0, \
}
@@ -69,17 +98,21 @@ void build_cpu_to_node_map(void);
.span = CPU_MASK_NONE, \
.parent = NULL, \
.groups = NULL, \
- .min_interval = 80, \
- .max_interval = 320, \
- .busy_factor = 320, \
- .imbalance_pct = 125, \
+ .min_interval = 64, \
+ .max_interval = 64*num_online_cpus(), \
+ .busy_factor = 128, \
+ .imbalance_pct = 133, \
.cache_hot_time = (10*1000000), \
.cache_nice_tries = 1, \
+ .busy_idx = 3, \
+ .idle_idx = 3, \
+ .newidle_idx = 0, /* unused */ \
+ .wake_idx = 0, /* unused */ \
+ .forkexec_idx = 0, /* unused */ \
.per_cpu_gain = 100, \
- .flags = SD_LOAD_BALANCE \
- | SD_BALANCE_EXEC, \
+ .flags = SD_LOAD_BALANCE, \
.last_balance = jiffies, \
- .balance_interval = 100*(63+num_online_cpus())/64, \
+ .balance_interval = 64, \
.nr_balance_failed = 0, \
}
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h
index f7f43ec2483a..517f1649ee64 100644
--- a/include/asm-ia64/unistd.h
+++ b/include/asm-ia64/unistd.h
@@ -263,6 +263,8 @@
#define __NR_add_key 1271
#define __NR_request_key 1272
#define __NR_keyctl 1273
+#define __NR_ioprio_set 1274
+#define __NR_ioprio_get 1275
#define __NR_set_zone_reclaim 1276
#ifdef __KERNEL__
diff --git a/include/asm-ia64/vga.h b/include/asm-ia64/vga.h
index 1f446d6841f6..bc3349ffc505 100644
--- a/include/asm-ia64/vga.h
+++ b/include/asm-ia64/vga.h
@@ -14,7 +14,10 @@
* videoram directly without any black magic.
*/
-#define VGA_MAP_MEM(x) ((unsigned long) ioremap((x), 0))
+extern unsigned long vga_console_iobase;
+extern unsigned long vga_console_membase;
+
+#define VGA_MAP_MEM(x) ((unsigned long) ioremap(vga_console_membase + (x), 0))
#define vga_readb(x) (*(x))
#define vga_writeb(x,y) (*(y) = (x))
diff --git a/include/asm-m32r/s1d13806.h b/include/asm-m32r/s1d13806.h
new file mode 100644
index 000000000000..248d36a82d79
--- /dev/null
+++ b/include/asm-m32r/s1d13806.h
@@ -0,0 +1,199 @@
+//----------------------------------------------------------------------------
+//
+// File generated by S1D13806CFG.EXE
+//
+// Copyright (c) 2000,2001 Epson Research and Development, Inc.
+// All rights reserved.
+//
+//----------------------------------------------------------------------------
+
+// Panel: (active) 640x480 77Hz STN Single 8-bit (PCLK=CLKI=25.175MHz)
+// Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=33.333MHz)
+
+#define SWIVEL_VIEW 0 /* 0:none, 1:90 not completed */
+
+static struct s1d13xxxfb_regval s1d13xxxfb_initregs[] = {
+
+ {0x0001,0x00}, // Miscellaneous Register
+ {0x01FC,0x00}, // Display Mode Register
+#if defined(CONFIG_PLAT_MAPPI)
+ {0x0004,0x00}, // General IO Pins Configuration Register 0
+ {0x0005,0x00}, // General IO Pins Configuration Register 1
+ {0x0008,0x00}, // General IO Pins Control Register 0
+ {0x0009,0x00}, // General IO Pins Control Register 1
+ {0x0010,0x00}, // Memory Clock Configuration Register
+ {0x0014,0x00}, // LCD Pixel Clock Configuration Register
+ {0x0018,0x00}, // CRT/TV Pixel Clock Configuration Register
+ {0x001C,0x00}, // MediaPlug Clock Configuration Register
+/*
+ * .. 10MHz: 0x00
+ * .. 30MHz: 0x01
+ * 30MHz ..: 0x02
+ */
+ {0x001E,0x02}, // CPU To Memory Wait State Select Register
+ {0x0021,0x02}, // DRAM Refresh Rate Register
+ {0x002A,0x11}, // DRAM Timings Control Register 0
+ {0x002B,0x13}, // DRAM Timings Control Register 1
+ {0x0020,0x80}, // Memory Configuration Register
+ {0x0030,0x25}, // Panel Type Register
+ {0x0031,0x00}, // MOD Rate Register
+ {0x0032,0x4F}, // LCD Horizontal Display Width Register
+ {0x0034,0x12}, // LCD Horizontal Non-Display Period Register
+ {0x0035,0x01}, // TFT FPLINE Start Position Register
+ {0x0036,0x0B}, // TFT FPLINE Pulse Width Register
+ {0x0038,0xDF}, // LCD Vertical Display Height Register 0
+ {0x0039,0x01}, // LCD Vertical Display Height Register 1
+ {0x003A,0x2C}, // LCD Vertical Non-Display Period Register
+ {0x003B,0x0A}, // TFT FPFRAME Start Position Register
+ {0x003C,0x01}, // TFT FPFRAME Pulse Width Register
+
+ {0x0041,0x00}, // LCD Miscellaneous Register
+ {0x0042,0x00}, // LCD Display Start Address Register 0
+ {0x0043,0x00}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0004,0x07}, // GPIO[0:7] direction
+ {0x0005,0x00}, // GPIO[8:12] direction
+ {0x0008,0x00}, // GPIO[0:7] data
+ {0x0009,0x00}, // GPIO[8:12] data
+ {0x0008,0x04}, // LCD panel Vcc on
+ {0x0008,0x05}, // LCD panel reset
+ {0x0010,0x01}, // Memory Clock Configuration Register
+ {0x0014,0x30}, // LCD Pixel Clock Configuration Register (CLKI 22MHz/4)
+ {0x0018,0x00}, // CRT/TV Pixel Clock Configuration Register
+ {0x001C,0x00}, // MediaPlug Clock Configuration Register(10MHz)
+ {0x001E,0x00}, // CPU To Memory Wait State Select Register
+ {0x0020,0x80}, // Memory Configuration Register
+ {0x0021,0x03}, // DRAM Refresh Rate Register
+ {0x002A,0x00}, // DRAM Timings Control Register 0
+ {0x002B,0x01}, // DRAM Timings Control Register 1
+ {0x0030,0x25}, // Panel Type Register
+ {0x0031,0x00}, // MOD Rate Register
+ {0x0032,0x1d}, // LCD Horizontal Display Width Register
+ {0x0034,0x05}, // LCD Horizontal Non-Display Period Register
+ {0x0035,0x01}, // TFT FPLINE Start Position Register
+ {0x0036,0x01}, // TFT FPLINE Pulse Width Register
+ {0x0038,0x3F}, // LCD Vertical Display Height Register 0
+ {0x0039,0x01}, // LCD Vertical Display Height Register 1
+ {0x003A,0x0b}, // LCD Vertical Non-Display Period Register
+ {0x003B,0x07}, // TFT FPFRAME Start Position Register
+ {0x003C,0x02}, // TFT FPFRAME Pulse Width Register
+
+ {0x0041,0x00}, // LCD Miscellaneous Register
+#if (SWIVEL_VIEW == 0)
+ {0x0042,0x00}, // LCD Display Start Address Register 0
+ {0x0043,0x00}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+
+#elif (SWIVEL_VIEW == 1)
+ // 1024 - W(320) = 0x2C0
+ {0x0042,0xC0}, // LCD Display Start Address Register 0
+ {0x0043,0x02}, // LCD Display Start Address Register 1
+ {0x0044,0x00}, // LCD Display Start Address Register 2
+ // 1024
+ {0x0046,0x00}, // LCD Memory Address Offset Register 0
+ {0x0047,0x02}, // LCD Memory Address Offset Register 1
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif
+#else
+#error no platform configuration
+#endif /* CONFIG_PLAT_XXX */
+
+ {0x0048,0x00}, // LCD Pixel Panning Register
+ {0x004A,0x00}, // LCD Display FIFO High Threshold Control Register
+ {0x004B,0x00}, // LCD Display FIFO Low Threshold Control Register
+ {0x0050,0x4F}, // CRT/TV Horizontal Display Width Register
+ {0x0052,0x13}, // CRT/TV Horizontal Non-Display Period Register
+ {0x0053,0x01}, // CRT/TV HRTC Start Position Register
+ {0x0054,0x0B}, // CRT/TV HRTC Pulse Width Register
+ {0x0056,0xDF}, // CRT/TV Vertical Display Height Register 0
+ {0x0057,0x01}, // CRT/TV Vertical Display Height Register 1
+ {0x0058,0x2B}, // CRT/TV Vertical Non-Display Period Register
+ {0x0059,0x09}, // CRT/TV VRTC Start Position Register
+ {0x005A,0x01}, // CRT/TV VRTC Pulse Width Register
+ {0x005B,0x10}, // TV Output Control Register
+
+ {0x0062,0x00}, // CRT/TV Display Start Address Register 0
+ {0x0063,0x00}, // CRT/TV Display Start Address Register 1
+ {0x0064,0x00}, // CRT/TV Display Start Address Register 2
+
+ {0x0068,0x00}, // CRT/TV Pixel Panning Register
+ {0x006A,0x00}, // CRT/TV Display FIFO High Threshold Control Register
+ {0x006B,0x00}, // CRT/TV Display FIFO Low Threshold Control Register
+ {0x0070,0x00}, // LCD Ink/Cursor Control Register
+ {0x0071,0x01}, // LCD Ink/Cursor Start Address Register
+ {0x0072,0x00}, // LCD Cursor X Position Register 0
+ {0x0073,0x00}, // LCD Cursor X Position Register 1
+ {0x0074,0x00}, // LCD Cursor Y Position Register 0
+ {0x0075,0x00}, // LCD Cursor Y Position Register 1
+ {0x0076,0x00}, // LCD Ink/Cursor Blue Color 0 Register
+ {0x0077,0x00}, // LCD Ink/Cursor Green Color 0 Register
+ {0x0078,0x00}, // LCD Ink/Cursor Red Color 0 Register
+ {0x007A,0x1F}, // LCD Ink/Cursor Blue Color 1 Register
+ {0x007B,0x3F}, // LCD Ink/Cursor Green Color 1 Register
+ {0x007C,0x1F}, // LCD Ink/Cursor Red Color 1 Register
+ {0x007E,0x00}, // LCD Ink/Cursor FIFO Threshold Register
+ {0x0080,0x00}, // CRT/TV Ink/Cursor Control Register
+ {0x0081,0x01}, // CRT/TV Ink/Cursor Start Address Register
+ {0x0082,0x00}, // CRT/TV Cursor X Position Register 0
+ {0x0083,0x00}, // CRT/TV Cursor X Position Register 1
+ {0x0084,0x00}, // CRT/TV Cursor Y Position Register 0
+ {0x0085,0x00}, // CRT/TV Cursor Y Position Register 1
+ {0x0086,0x00}, // CRT/TV Ink/Cursor Blue Color 0 Register
+ {0x0087,0x00}, // CRT/TV Ink/Cursor Green Color 0 Register
+ {0x0088,0x00}, // CRT/TV Ink/Cursor Red Color 0 Register
+ {0x008A,0x1F}, // CRT/TV Ink/Cursor Blue Color 1 Register
+ {0x008B,0x3F}, // CRT/TV Ink/Cursor Green Color 1 Register
+ {0x008C,0x1F}, // CRT/TV Ink/Cursor Red Color 1 Register
+ {0x008E,0x00}, // CRT/TV Ink/Cursor FIFO Threshold Register
+ {0x0100,0x00}, // BitBlt Control Register 0
+ {0x0101,0x00}, // BitBlt Control Register 1
+ {0x0102,0x00}, // BitBlt ROP Code/Color Expansion Register
+ {0x0103,0x00}, // BitBlt Operation Register
+ {0x0104,0x00}, // BitBlt Source Start Address Register 0
+ {0x0105,0x00}, // BitBlt Source Start Address Register 1
+ {0x0106,0x00}, // BitBlt Source Start Address Register 2
+ {0x0108,0x00}, // BitBlt Destination Start Address Register 0
+ {0x0109,0x00}, // BitBlt Destination Start Address Register 1
+ {0x010A,0x00}, // BitBlt Destination Start Address Register 2
+ {0x010C,0x00}, // BitBlt Memory Address Offset Register 0
+ {0x010D,0x00}, // BitBlt Memory Address Offset Register 1
+ {0x0110,0x00}, // BitBlt Width Register 0
+ {0x0111,0x00}, // BitBlt Width Register 1
+ {0x0112,0x00}, // BitBlt Height Register 0
+ {0x0113,0x00}, // BitBlt Height Register 1
+ {0x0114,0x00}, // BitBlt Background Color Register 0
+ {0x0115,0x00}, // BitBlt Background Color Register 1
+ {0x0118,0x00}, // BitBlt Foreground Color Register 0
+ {0x0119,0x00}, // BitBlt Foreground Color Register 1
+ {0x01E0,0x00}, // Look-Up Table Mode Register
+ {0x01E2,0x00}, // Look-Up Table Address Register
+ {0x01F0,0x10}, // Power Save Configuration Register
+ {0x01F1,0x00}, // Power Save Status Register
+ {0x01F4,0x00}, // CPU-to-Memory Access Watchdog Timer Register
+#if (SWIVEL_VIEW == 0)
+ {0x01FC,0x01}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#elif (SWIVEL_VIEW == 1)
+ {0x01FC,0x41}, // Display Mode Register(0x01:LCD, 0x02:CRT, 0x03:LCD&CRT)
+#else
+#error unsupported SWIVEL_VIEW mode
+#endif /* SWIVEL_VIEW */
+
+#if defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0008,0x07}, // LCD panel Vdd & Vg on
+#endif
+
+ {0x0040,0x05}, // LCD Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+#if defined(CONFIG_PLAT_MAPPI)
+ {0x0046,0x80}, // LCD Memory Address Offset Register 0
+ {0x0047,0x02}, // LCD Memory Address Offset Register 1
+#elif defined(CONFIG_PLAT_M32700UT) || defined(CONFIG_PLAT_OPSPUT) || defined(CONFIG_PLAT_MAPPI3)
+ {0x0046,0xf0}, // LCD Memory Address Offset Register 0
+ {0x0047,0x00}, // LCD Memory Address Offset Register 1
+#endif
+ {0x0060,0x05}, // CRT/TV Display Mode Register (2:4bpp,3:8bpp,5:16bpp)
+ {0x0066,0x80}, // CRT/TV Memory Address Offset Register 0 // takeo
+ {0x0067,0x02}, // CRT/TV Memory Address Offset Register 1
+};
diff --git a/include/asm-m68k/pci.h b/include/asm-m68k/pci.h
index 9e7d79ab5d13..9d2c07abe44f 100644
--- a/include/asm-m68k/pci.h
+++ b/include/asm-m68k/pci.h
@@ -43,7 +43,7 @@ static inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
diff --git a/include/asm-m68k/serial.h b/include/asm-m68k/serial.h
index 9f5bcdc105fc..3fe29f8b0194 100644
--- a/include/asm-m68k/serial.h
+++ b/include/asm-m68k/serial.h
@@ -26,54 +26,9 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#endif
-
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS
diff --git a/include/asm-mips/mmzone.h b/include/asm-mips/mmzone.h
index 29ee13be0b2a..d721143dbd47 100644
--- a/include/asm-mips/mmzone.h
+++ b/include/asm-mips/mmzone.h
@@ -8,6 +8,8 @@
#include <asm/page.h>
#include <mmzone.h>
+#ifdef CONFIG_DISCONTIGMEM
+
#define kvaddr_to_nid(kvaddr) pa_to_nid(__pa(kvaddr))
#define pfn_to_nid(pfn) pa_to_nid((pfn) << PAGE_SHIFT)
@@ -36,4 +38,6 @@
/* XXX: FIXME -- wli */
#define kern_addr_valid(addr) (0)
+#endif /* CONFIG_DISCONTIGMEM */
+
#endif /* _ASM_MMZONE_H_ */
diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h
index d1bf8240e73b..5cae35cd9ba9 100644
--- a/include/asm-mips/page.h
+++ b/include/asm-mips/page.h
@@ -127,7 +127,7 @@ static __inline__ int get_order(unsigned long size)
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
#define pfn_to_page(pfn) (mem_map + (pfn))
#define page_to_pfn(page) ((unsigned long)((page) - mem_map))
#define pfn_valid(pfn) ((pfn) < max_mapnr)
diff --git a/include/asm-mips/pci.h b/include/asm-mips/pci.h
index c9c576b48556..d70dc355c1f3 100644
--- a/include/asm-mips/pci.h
+++ b/include/asm-mips/pci.h
@@ -69,7 +69,7 @@ extern unsigned long PCIBIOS_MIN_MEM;
extern void pcibios_set_master(struct pci_dev *dev);
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -130,6 +130,16 @@ extern void pci_dac_dma_sync_single_for_cpu(struct pci_dev *pdev,
extern void pci_dac_dma_sync_single_for_device(struct pci_dev *pdev,
dma64_addr_t dma_addr, size_t len, int direction);
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
extern void pcibios_resource_to_bus(struct pci_dev *dev,
struct pci_bus_region *region, struct resource *res);
diff --git a/include/asm-mips/pgtable.h b/include/asm-mips/pgtable.h
index 878843203d67..e76ccd6e3a5d 100644
--- a/include/asm-mips/pgtable.h
+++ b/include/asm-mips/pgtable.h
@@ -350,7 +350,7 @@ static inline void update_mmu_cache(struct vm_area_struct *vma,
__update_cache(vma, address, pte);
}
-#ifndef CONFIG_DISCONTIGMEM
+#ifndef CONFIG_NEED_MULTIPLE_NODES
#define kern_addr_valid(addr) (1)
#endif
diff --git a/include/asm-mips/serial.h b/include/asm-mips/serial.h
index 8a70ff58f760..4eed8e2acdc3 100644
--- a/include/asm-mips/serial.h
+++ b/include/asm-mips/serial.h
@@ -29,32 +29,6 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#define RS_TABLE_SIZE 64
-#else
-#define RS_TABLE_SIZE
-#endif
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
#ifdef CONFIG_MACH_JAZZ
#include <asm/jazz.h>
@@ -240,66 +214,10 @@
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else /* CONFIG_SERIAL_MANY_PORTS */
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif /* CONFIG_SERIAL_MANY_PORTS */
-
#else /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
#define STD_SERIAL_PORT_DEFNS
-#define EXTRA_SERIAL_PORT_DEFNS
#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
#ifdef CONFIG_MOMENCO_JAGUAR_ATX
/* Ordinary NS16552 duart with a 20MHz crystal. */
#define JAGUAR_ATX_UART_CLK 20000000
@@ -427,8 +345,6 @@
COBALT_SERIAL_PORT_DEFNS \
DDB5477_SERIAL_PORT_DEFNS \
EV96100_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS \
IP32_SERIAL_PORT_DEFNS \
ITE_SERIAL_PORT_DEFNS \
IVR_SERIAL_PORT_DEFNS \
diff --git a/include/asm-mips/system.h b/include/asm-mips/system.h
index 888fd8908467..169f3d4265b1 100644
--- a/include/asm-mips/system.h
+++ b/include/asm-mips/system.h
@@ -422,16 +422,10 @@ extern void __die_if_kernel(const char *, struct pt_regs *, const char *file,
extern int stop_a_enabled;
/*
- * Taken from include/asm-ia64/system.h; prevents deadlock on SMP
+ * See include/asm-ia64/system.h; prevents deadlock on SMP
* systems.
*/
-#define prepare_arch_switch(rq, next) \
-do { \
- spin_lock(&(next)->switch_lock); \
- spin_unlock(&(rq)->lock); \
-} while (0)
-#define finish_arch_switch(rq, prev) spin_unlock_irq(&(prev)->switch_lock)
-#define task_running(rq, p) ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
+#define __ARCH_WANT_UNLOCKED_CTXSW
#define arch_align_stack(x) (x)
diff --git a/include/asm-parisc/pci.h b/include/asm-parisc/pci.h
index 0763c2982fb0..ee741c150176 100644
--- a/include/asm-parisc/pci.h
+++ b/include/asm-parisc/pci.h
@@ -230,6 +230,25 @@ extern inline void pcibios_register_hba(struct pci_hba_data *x)
/* export the pci_ DMA API in terms of the dma_ one */
#include <asm-generic/pci-dma-compat.h>
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ unsigned long cacheline_size;
+ u8 byte;
+
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ *strat = PCI_DMA_BURST_MULTIPLE;
+ *strategy_parameter = cacheline_size;
+}
+#endif
+
extern void
pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region,
struct resource *res);
diff --git a/include/asm-parisc/serial.h b/include/asm-parisc/serial.h
index 239c5dcab7e6..82fd820d684f 100644
--- a/include/asm-parisc/serial.h
+++ b/include/asm-parisc/serial.h
@@ -19,18 +19,4 @@
* A500 w/ PCI serial cards: 5 + 4 * card ~= 17
*/
-#define STD_SERIAL_PORT_DEFNS \
- { 0, }, /* ttyS0 */ \
- { 0, }, /* ttyS1 */ \
- { 0, }, /* ttyS2 */ \
- { 0, }, /* ttyS3 */ \
- { 0, }, /* ttyS4 */ \
- { 0, }, /* ttyS5 */ \
- { 0, }, /* ttyS6 */ \
- { 0, }, /* ttyS7 */ \
- { 0, }, /* ttyS8 */
-
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS
-
+#define SERIAL_PORT_DFNS
diff --git a/include/asm-ppc/fsl_ocp.h b/include/asm-ppc/fsl_ocp.h
deleted file mode 100644
index 050fbba8d049..000000000000
--- a/include/asm-ppc/fsl_ocp.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * include/asm-ppc/fsl_ocp.h
- *
- * Definitions for the on-chip peripherals on Freescale PPC processors
- *
- * Maintainer: Kumar Gala (kumar.gala@freescale.com)
- *
- * Copyright 2004 Freescale Semiconductor, Inc
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifdef __KERNEL__
-#ifndef __ASM_FS_OCP_H__
-#define __ASM_FS_OCP_H__
-
-/* A table of information for supporting the Gianfar Ethernet Controller
- * This helps identify which enet controller we are dealing with,
- * and what type of enet controller it is
- */
-struct ocp_gfar_data {
- uint interruptTransmit;
- uint interruptError;
- uint interruptReceive;
- uint interruptPHY;
- uint flags;
- uint phyid;
- uint phyregidx;
- unsigned char mac_addr[6];
-};
-
-/* Flags in the flags field */
-#define GFAR_HAS_COALESCE 0x20
-#define GFAR_HAS_RMON 0x10
-#define GFAR_HAS_MULTI_INTR 0x08
-#define GFAR_FIRM_SET_MACADDR 0x04
-#define GFAR_HAS_PHY_INTR 0x02 /* if not set use a timer */
-#define GFAR_HAS_GIGABIT 0x01
-
-/* Data structure for I2C support. Just contains a couple flags
- * to distinguish various I2C implementations*/
-struct ocp_fs_i2c_data {
- uint flags;
-};
-
-/* Flags for I2C */
-#define FS_I2C_SEPARATE_DFSRR 0x02
-#define FS_I2C_CLOCK_5200 0x01
-
-#endif /* __ASM_FS_OCP_H__ */
-#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/kexec.h b/include/asm-ppc/kexec.h
new file mode 100644
index 000000000000..6d2aa0aa4642
--- /dev/null
+++ b/include/asm-ppc/kexec.h
@@ -0,0 +1,40 @@
+#ifndef _PPC_KEXEC_H
+#define _PPC_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * Someone correct me if FIXADDR_START - PAGEOFFSET is not the correct
+ * calculation for the amount of memory directly mappable into the
+ * kernel memory space.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+/* Maximum address we can use for the control code buffer */
+#define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_PPC
+
+#ifndef __ASSEMBLY__
+
+extern void *crash_notes;
+
+struct kimage;
+
+extern void machine_kexec_simple(struct kimage *image);
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_KEXEC */
+
+#endif /* _PPC_KEXEC_H */
diff --git a/include/asm-ppc/machdep.h b/include/asm-ppc/machdep.h
index b78d40870c95..1d4ab70a56f3 100644
--- a/include/asm-ppc/machdep.h
+++ b/include/asm-ppc/machdep.h
@@ -4,6 +4,7 @@
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/kexec.h>
#include <asm/setup.h>
#include <asm/page.h>
@@ -114,6 +115,36 @@ struct machdep_calls {
/* functions for dealing with other cpus */
struct smp_ops_t *smp_ops;
#endif /* CONFIG_SMP */
+
+#ifdef CONFIG_KEXEC
+ /* Called to shutdown machine specific hardware not already controlled
+ * by other drivers.
+ * XXX Should we move this one out of kexec scope?
+ */
+ void (*machine_shutdown)(void);
+
+ /* Called to do the minimal shutdown needed to run a kexec'd kernel
+ * to run successfully.
+ * XXX Should we move this one out of kexec scope?
+ */
+ void (*machine_crash_shutdown)(void);
+
+ /* Called to do what every setup is needed on image and the
+ * reboot code buffer. Returns 0 on success.
+ * Provide your own (maybe dummy) implementation if your platform
+ * claims to support kexec.
+ */
+ int (*machine_kexec_prepare)(struct kimage *image);
+
+ /* Called to handle any machine specific cleanup on image */
+ void (*machine_kexec_cleanup)(struct kimage *image);
+
+ /* Called to perform the _real_ kexec.
+ * Do NOT allocate memory or fail here. We are past the point of
+ * no return.
+ */
+ void (*machine_kexec)(struct kimage *image);
+#endif /* CONFIG_KEXEC */
};
extern struct machdep_calls ppc_md;
diff --git a/include/asm-ppc/macio.h b/include/asm-ppc/macio.h
index 2cafc9978607..a481b772d154 100644
--- a/include/asm-ppc/macio.h
+++ b/include/asm-ppc/macio.h
@@ -1,6 +1,7 @@
#ifndef __MACIO_ASIC_H__
#define __MACIO_ASIC_H__
+#include <linux/mod_devicetable.h>
#include <asm/of_device.h>
extern struct bus_type macio_bus_type;
@@ -120,10 +121,10 @@ static inline struct pci_dev *macio_get_pci_dev(struct macio_dev *mdev)
struct macio_driver
{
char *name;
- struct of_match *match_table;
+ struct of_device_id *match_table;
struct module *owner;
- int (*probe)(struct macio_dev* dev, const struct of_match *match);
+ int (*probe)(struct macio_dev* dev, const struct of_device_id *match);
int (*remove)(struct macio_dev* dev);
int (*suspend)(struct macio_dev* dev, pm_message_t state);
diff --git a/include/asm-ppc/mmu.h b/include/asm-ppc/mmu.h
index d465aee1c82e..9205db404c7a 100644
--- a/include/asm-ppc/mmu.h
+++ b/include/asm-ppc/mmu.h
@@ -405,7 +405,7 @@ typedef struct _P601_BAT {
#define MAS0_TLBSEL(x) ((x << 28) & 0x30000000)
#define MAS0_ESEL(x) ((x << 16) & 0x0FFF0000)
-#define MAS0_NV 0x00000FFF
+#define MAS0_NV(x) ((x) & 0x00000FFF)
#define MAS1_VALID 0x80000000
#define MAS1_IPROT 0x40000000
diff --git a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h
index 9222fa6ca172..ccabbce39d85 100644
--- a/include/asm-ppc/mmu_context.h
+++ b/include/asm-ppc/mmu_context.h
@@ -63,7 +63,7 @@ static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
#define LAST_CONTEXT 255
#define FIRST_CONTEXT 1
-#elif defined(CONFIG_E500)
+#elif defined(CONFIG_E200) || defined(CONFIG_E500)
#define NO_CONTEXT 256
#define LAST_CONTEXT 255
#define FIRST_CONTEXT 1
diff --git a/include/asm-ppc/mpc8xx.h b/include/asm-ppc/mpc8xx.h
index 714d69c819d3..7c31f2d564a1 100644
--- a/include/asm-ppc/mpc8xx.h
+++ b/include/asm-ppc/mpc8xx.h
@@ -68,6 +68,10 @@
#include <platforms/lantec.h>
#endif
+#if defined(CONFIG_MPC885ADS)
+#include <platforms/mpc885ads.h>
+#endif
+
/* Currently, all 8xx boards that support a processor to PCI/ISA bridge
* use the same memory map.
*/
diff --git a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h
index c726f1845190..983116f59d90 100644
--- a/include/asm-ppc/ocp.h
+++ b/include/asm-ppc/ocp.h
@@ -202,10 +202,6 @@ static DEVICE_ATTR(name##_##field, S_IRUGO, show_##name##_##field, NULL);
#include <asm/ibm_ocp.h>
#endif
-#ifdef CONFIG_FSL_OCP
-#include <asm/fsl_ocp.h>
-#endif
-
#endif /* CONFIG_PPC_OCP */
#endif /* __OCP_H__ */
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc/of_device.h b/include/asm-ppc/of_device.h
index 7229735a7c18..4b264cfd3998 100644
--- a/include/asm-ppc/of_device.h
+++ b/include/asm-ppc/of_device.h
@@ -24,20 +24,8 @@ struct of_device
};
#define to_of_device(d) container_of(d, struct of_device, dev)
-/*
- * Struct used for matching a device
- */
-struct of_match
-{
- char *name;
- char *type;
- char *compatible;
- void *data;
-};
-#define OF_ANY_MATCH ((char *)-1L)
-
-extern const struct of_match *of_match_device(
- const struct of_match *matches, const struct of_device *dev);
+extern const struct of_device_id *of_match_device(
+ const struct of_device_id *matches, const struct of_device *dev);
extern struct of_device *of_dev_get(struct of_device *dev);
extern void of_dev_put(struct of_device *dev);
@@ -49,10 +37,10 @@ extern void of_dev_put(struct of_device *dev);
struct of_platform_driver
{
char *name;
- struct of_match *match_table;
+ struct of_device_id *match_table;
struct module *owner;
- int (*probe)(struct of_device* dev, const struct of_match *match);
+ int (*probe)(struct of_device* dev, const struct of_device_id *match);
int (*remove)(struct of_device* dev);
int (*suspend)(struct of_device* dev, pm_message_t state);
diff --git a/include/asm-ppc/open_pic.h b/include/asm-ppc/open_pic.h
index dbe853319741..7848aa610c05 100644
--- a/include/asm-ppc/open_pic.h
+++ b/include/asm-ppc/open_pic.h
@@ -25,6 +25,11 @@
#define OPENPIC_VEC_IPI 118 /* and up */
#define OPENPIC_VEC_SPURIOUS 255
+/* Priorities */
+#define OPENPIC_PRIORITY_IPI_BASE 10
+#define OPENPIC_PRIORITY_DEFAULT 4
+#define OPENPIC_PRIORITY_NMI 9
+
/* OpenPIC IRQ controller structure */
extern struct hw_interrupt_type open_pic;
@@ -42,6 +47,7 @@ extern int epic_serial_mode;
extern void openpic_set_sources(int first_irq, int num_irqs, void __iomem *isr);
extern void openpic_init(int linux_irq_offset);
extern void openpic_init_nmi_irq(u_int irq);
+extern void openpic_set_irq_priority(u_int irq, u_int pri);
extern void openpic_hookup_cascade(u_int irq, char *name,
int (*cascade_fn)(struct pt_regs *));
extern u_int openpic_irq(void);
diff --git a/include/asm-ppc/pc_serial.h b/include/asm-ppc/pc_serial.h
index fa9cbb67ce3e..8f994f9f8857 100644
--- a/include/asm-ppc/pc_serial.h
+++ b/include/asm-ppc/pc_serial.h
@@ -35,93 +35,9 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS
diff --git a/include/asm-ppc/pci.h b/include/asm-ppc/pci.h
index ce5ae6d048f5..a13d55870e62 100644
--- a/include/asm-ppc/pci.h
+++ b/include/asm-ppc/pci.h
@@ -37,7 +37,7 @@ extern inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-extern inline void pcibios_penalize_isa_irq(int irq)
+extern inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -69,6 +69,16 @@ extern unsigned long pci_bus_to_phys(unsigned int ba, int busnr);
#define pci_unmap_len(PTR, LEN_NAME) (0)
#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
/*
* At present there are very few 32-bit PPC machines that can have
* memory above the 4GB point, and we don't support that.
@@ -103,6 +113,12 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file,
unsigned long size,
pgprot_t prot);
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ u64 *start, u64 *end);
+
+
#endif /* __KERNEL__ */
#endif /* __PPC_PCI_H */
diff --git a/include/asm-ppc/ppc_asm.h b/include/asm-ppc/ppc_asm.h
index 13fa8e7483c1..f76221def484 100644
--- a/include/asm-ppc/ppc_asm.h
+++ b/include/asm-ppc/ppc_asm.h
@@ -174,6 +174,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_601)
#define CLR_TOP32(r)
#endif /* CONFIG_PPC64BRIDGE */
+#define RFCI .long 0x4c000066 /* rfci instruction */
+#define RFDI .long 0x4c00004e /* rfdi instruction */
#define RFMCI .long 0x4c00004c /* rfmci instruction */
#ifdef CONFIG_IBM405_ERR77
diff --git a/include/asm-ppc/reg.h b/include/asm-ppc/reg.h
index c418aab7cd34..88b4222154d4 100644
--- a/include/asm-ppc/reg.h
+++ b/include/asm-ppc/reg.h
@@ -160,6 +160,7 @@
#define HID0_ICFI (1<<11) /* Instr. Cache Flash Invalidate */
#define HID0_DCI (1<<10) /* Data Cache Invalidate */
#define HID0_SPD (1<<9) /* Speculative disable */
+#define HID0_DAPUEN (1<<8) /* Debug APU enable */
#define HID0_SGE (1<<7) /* Store Gathering Enable */
#define HID0_SIED (1<<7) /* Serial Instr. Execution [Disable] */
#define HID0_DFCA (1<<6) /* Data Cache Flush Assist */
diff --git a/include/asm-ppc/reg_booke.h b/include/asm-ppc/reg_booke.h
index 45c5e6f2b7ab..00ad9c754c78 100644
--- a/include/asm-ppc/reg_booke.h
+++ b/include/asm-ppc/reg_booke.h
@@ -165,6 +165,8 @@ do { \
#define SPRN_MCSRR1 0x23B /* Machine Check Save and Restore Register 1 */
#define SPRN_MCSR 0x23C /* Machine Check Status Register */
#define SPRN_MCAR 0x23D /* Machine Check Address Register */
+#define SPRN_DSRR0 0x23E /* Debug Save and Restore Register 0 */
+#define SPRN_DSRR1 0x23F /* Debug Save and Restore Register 1 */
#define SPRN_MAS0 0x270 /* MMU Assist Register 0 */
#define SPRN_MAS1 0x271 /* MMU Assist Register 1 */
#define SPRN_MAS2 0x272 /* MMU Assist Register 2 */
@@ -264,6 +266,17 @@ do { \
#define MCSR_BUS_IPERR 0x00000002UL /* Instruction parity Error */
#define MCSR_BUS_RPERR 0x00000001UL /* Read parity Error */
#endif
+#ifdef CONFIG_E200
+#define MCSR_MCP 0x80000000UL /* Machine Check Input Pin */
+#define MCSR_CP_PERR 0x20000000UL /* Cache Push Parity Error */
+#define MCSR_CPERR 0x10000000UL /* Cache Parity Error */
+#define MCSR_EXCP_ERR 0x08000000UL /* ISI, ITLB, or Bus Error on 1st insn
+ fetch for an exception handler */
+#define MCSR_BUS_IRERR 0x00000010UL /* Read Bus Error on instruction fetch*/
+#define MCSR_BUS_DRERR 0x00000008UL /* Read Bus Error on data load */
+#define MCSR_BUS_WRERR 0x00000004UL /* Write Bus Error on buffered
+ store or cache line push */
+#endif
/* Bit definitions for the DBSR. */
/*
@@ -311,6 +324,7 @@ do { \
#define ESR_ST 0x00800000 /* Store Operation */
#define ESR_DLK 0x00200000 /* Data Cache Locking */
#define ESR_ILK 0x00100000 /* Instr. Cache Locking */
+#define ESR_PUO 0x00040000 /* Unimplemented Operation exception */
#define ESR_BO 0x00020000 /* Byte Ordering */
/* Bit definitions related to the DBCR0. */
@@ -387,10 +401,12 @@ do { \
#define ICCR_CACHE 1 /* Cacheable */
/* Bit definitions for L1CSR0. */
+#define L1CSR0_CLFC 0x00000100 /* Cache Lock Bits Flash Clear */
#define L1CSR0_DCFI 0x00000002 /* Data Cache Flash Invalidate */
+#define L1CSR0_CFI 0x00000002 /* Cache Flash Invalidate */
#define L1CSR0_DCE 0x00000001 /* Data Cache Enable */
-/* Bit definitions for L1CSR0. */
+/* Bit definitions for L1CSR1. */
#define L1CSR1_ICLFR 0x00000100 /* Instr Cache Lock Bits Flash Reset */
#define L1CSR1_ICFI 0x00000002 /* Instr Cache Flash Invalidate */
#define L1CSR1_ICE 0x00000001 /* Instr Cache Enable */
diff --git a/include/asm-ppc/unistd.h b/include/asm-ppc/unistd.h
index cc51e5c9acc2..a7894e0fbbb1 100644
--- a/include/asm-ppc/unistd.h
+++ b/include/asm-ppc/unistd.h
@@ -262,7 +262,7 @@
#define __NR_rtas 255
#define __NR_sys_debug_setcontext 256
/* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
/* Number 259 is reserved for new sys_mbind */
/* Number 260 is reserved for new sys_get_mempolicy */
/* Number 261 is reserved for new sys_set_mempolicy */
@@ -277,8 +277,10 @@
#define __NR_request_key 270
#define __NR_keyctl 271
#define __NR_waitid 272
+#define __NR_ioprio_set 273
+#define __NR_ioprio_get 274
-#define __NR_syscalls 273
+#define __NR_syscalls 275
#define __NR(n) #n
diff --git a/include/asm-ppc64/byteorder.h b/include/asm-ppc64/byteorder.h
index 80327532de64..8b57da62b674 100644
--- a/include/asm-ppc64/byteorder.h
+++ b/include/asm-ppc64/byteorder.h
@@ -40,7 +40,6 @@ static __inline__ void st_le32(volatile __u32 *addr, const __u32 val)
__asm__ __volatile__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
}
-#if 0
static __inline__ __attribute_const__ __u16 ___arch__swab16(__u16 value)
{
__u16 result;
@@ -63,17 +62,8 @@ static __inline__ __attribute_const__ __u32 ___arch__swab32(__u32 value)
return result;
}
-static __inline__ __attribute_const__ __u64 ___arch__swab64(__u64 value)
-{
- __u64 result;
-#error implement me
-}
-
#define __arch__swab16(x) ___arch__swab16(x)
#define __arch__swab32(x) ___arch__swab32(x)
-#define __arch__swab64(x) ___arch__swab64(x)
-
-#endif
/* The same, but returns converted value from the location pointer by addr. */
#define __arch__swab16p(addr) ld_le16(addr)
diff --git a/include/asm-ppc64/cputable.h b/include/asm-ppc64/cputable.h
index cbbfbec78b6b..d67fa9e26079 100644
--- a/include/asm-ppc64/cputable.h
+++ b/include/asm-ppc64/cputable.h
@@ -138,6 +138,7 @@ extern firmware_feature_t firmware_features_table[];
#define CPU_FTR_COHERENT_ICACHE ASM_CONST(0x0000020000000000)
#define CPU_FTR_LOCKLESS_TLBIE ASM_CONST(0x0000040000000000)
#define CPU_FTR_MMCRA_SIHV ASM_CONST(0x0000080000000000)
+#define CPU_FTR_CTRL ASM_CONST(0x0000100000000000)
/* Platform firmware features */
#define FW_FTR_ ASM_CONST(0x0000000000000001)
@@ -148,7 +149,7 @@ extern firmware_feature_t firmware_features_table[];
#define CPU_FTR_PPCAS_ARCH_V2_BASE (CPU_FTR_SLB | \
CPU_FTR_TLBIEL | CPU_FTR_NOEXECUTE | \
- CPU_FTR_NODSISRALIGN)
+ CPU_FTR_NODSISRALIGN | CPU_FTR_CTRL)
/* iSeries doesn't support large pages */
#ifdef CONFIG_PPC_ISERIES
diff --git a/include/asm-ppc64/hvconsole.h b/include/asm-ppc64/hvconsole.h
index d89d94c91815..6da93ce74dc0 100644
--- a/include/asm-ppc64/hvconsole.h
+++ b/include/asm-ppc64/hvconsole.h
@@ -29,12 +29,21 @@
*/
#define MAX_NR_HVC_CONSOLES 16
+/* implemented by a low level driver */
+struct hv_ops {
+ int (*get_chars)(uint32_t vtermno, char *buf, int count);
+ int (*put_chars)(uint32_t vtermno, const char *buf, int count);
+};
extern int hvc_get_chars(uint32_t vtermno, char *buf, int count);
extern int hvc_put_chars(uint32_t vtermno, const char *buf, int count);
-/* Early discovery of console adapters. */
-extern int hvc_find_vtys(void);
+struct hvc_struct;
-/* Implemented by a console driver */
-extern int hvc_instantiate(uint32_t vtermno, int index);
+/* Register a vterm and a slot index for use as a console (console_init) */
+extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops);
+/* register a vterm for hvc tty operation (module_init or hotplug add) */
+extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int irq,
+ struct hv_ops *ops);
+/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */
+extern int __devexit hvc_remove(struct hvc_struct *hp);
#endif /* _PPC64_HVCONSOLE_H */
diff --git a/include/asm-ppc64/iSeries/ItLpQueue.h b/include/asm-ppc64/iSeries/ItLpQueue.h
index 393299e04d7f..69b26ad74135 100644
--- a/include/asm-ppc64/iSeries/ItLpQueue.h
+++ b/include/asm-ppc64/iSeries/ItLpQueue.h
@@ -41,7 +41,7 @@ struct HvLpEvent;
#define LpEventMaxSize 256
#define LpEventAlign 64
-struct ItLpQueue {
+struct hvlpevent_queue {
/*
* The xSlicCurEventPtr is the pointer to the next event stack entry
* that will become valid. The OS must peek at this entry to determine
@@ -69,16 +69,13 @@ struct ItLpQueue {
char *xSlicEventStackPtr; // 0x20
u8 xIndex; // 0x28 unique sequential index.
u8 xSlicRsvd[3]; // 0x29-2b
- u32 xInUseWord; // 0x2C
- u64 xLpIntCount; // 0x30 Total Lp Int msgs processed
- u64 xLpIntCountByType[9]; // 0x38-0x7F Event counts by type
+ spinlock_t lock;
};
-extern struct ItLpQueue xItLpQueue;
+extern struct hvlpevent_queue hvlpevent_queue;
-extern struct HvLpEvent *ItLpQueue_getNextLpEvent(struct ItLpQueue *);
-extern int ItLpQueue_isLpIntPending(struct ItLpQueue *);
-extern unsigned ItLpQueue_process(struct ItLpQueue *, struct pt_regs *);
-extern void ItLpQueue_clearValid(struct HvLpEvent *);
+extern int hvlpevent_is_pending(void);
+extern void process_hvlpevents(struct pt_regs *);
+extern void setup_hvlpevent_queue(void);
#endif /* _ITLPQUEUE_H */
diff --git a/include/asm-ppc64/kdebug.h b/include/asm-ppc64/kdebug.h
index 488634258a72..d383d161cf8d 100644
--- a/include/asm-ppc64/kdebug.h
+++ b/include/asm-ppc64/kdebug.h
@@ -17,7 +17,7 @@ struct die_args {
/*
Note - you should never unregister because that can race with NMIs.
- If you really want to do it first unregister - then synchronize_kernel -
+ If you really want to do it first unregister - then synchronize_sched -
then free.
*/
int register_die_notifier(struct notifier_block *nb);
diff --git a/include/asm-ppc64/kexec.h b/include/asm-ppc64/kexec.h
new file mode 100644
index 000000000000..511908afaeeb
--- /dev/null
+++ b/include/asm-ppc64/kexec.h
@@ -0,0 +1,41 @@
+#ifndef _PPC64_KEXEC_H
+#define _PPC64_KEXEC_H
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ */
+
+/* Maximum physical address we can use pages from */
+/* XXX: since we copy virt we can use any page we allocate */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can reach in physical address mode */
+/* XXX: I want to allow initrd in highmem. otherwise set to rmo on lpar */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can use for the control code buffer */
+/* XXX: unused today, ppc32 uses TASK_SIZE, probably left over from use_mm */
+#define KEXEC_CONTROL_MEMORY_LIMIT (-1UL)
+
+/* XXX: today we don't use this at all, althogh we have a static stack */
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_PPC64
+
+#define MAX_NOTE_BYTES 1024
+
+#ifndef __ASSEMBLY__
+
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+extern void kexec_smp_wait(void); /* get and clear naca physid, wait for
+ master to copy new code to 0 */
+
+#endif /* __ASSEMBLY__ */
+#endif /* _PPC_KEXEC_H */
+
diff --git a/include/asm-ppc64/kprobes.h b/include/asm-ppc64/kprobes.h
index 19b468bed059..0802919c3235 100644
--- a/include/asm-ppc64/kprobes.h
+++ b/include/asm-ppc64/kprobes.h
@@ -42,10 +42,13 @@ typedef unsigned int kprobe_opcode_t;
#define JPROBE_ENTRY(pentry) (kprobe_opcode_t *)((func_descr_t *)pentry)
+#define ARCH_SUPPORTS_KRETPROBES
+void kretprobe_trampoline(void);
+
/* Architecture specific copy of original instruction */
struct arch_specific_insn {
/* copy of original instruction */
- kprobe_opcode_t insn[MAX_INSN_SIZE];
+ kprobe_opcode_t *insn;
};
#ifdef CONFIG_KPROBES
diff --git a/include/asm-ppc64/machdep.h b/include/asm-ppc64/machdep.h
index 553b2ea23bed..1e6ad4824132 100644
--- a/include/asm-ppc64/machdep.h
+++ b/include/asm-ppc64/machdep.h
@@ -86,6 +86,7 @@ struct machdep_calls {
void (*init_IRQ)(void);
int (*get_irq)(struct pt_regs *);
+ void (*cpu_irq_down)(void);
/* PCI stuff */
void (*pcibios_fixup)(void);
@@ -139,8 +140,13 @@ struct machdep_calls {
unsigned long size,
pgprot_t vma_prot);
+ /* Idle loop for this platform, leave empty for default idle loop */
+ int (*idle_loop)(void);
};
+extern int default_idle(void);
+extern int native_idle(void);
+
extern struct machdep_calls ppc_md;
extern char cmd_line[COMMAND_LINE_SIZE];
diff --git a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
index 9d03a98a4fa3..f373de5e3dd9 100644
--- a/include/asm-ppc64/mmu.h
+++ b/include/asm-ppc64/mmu.h
@@ -181,6 +181,28 @@ static inline void tlbiel(unsigned long va)
asm volatile("ptesync": : :"memory");
}
+static inline unsigned long slot2va(unsigned long avpn, unsigned long large,
+ unsigned long secondary, unsigned long slot)
+{
+ unsigned long va;
+
+ va = avpn << 23;
+
+ if (!large) {
+ unsigned long vpi, pteg;
+
+ pteg = slot / HPTES_PER_GROUP;
+ if (secondary)
+ pteg = ~pteg;
+
+ vpi = ((va >> 28) ^ pteg) & htab_hash_mask;
+
+ va |= vpi << PAGE_SHIFT;
+ }
+
+ return va;
+}
+
/*
* Handle a fault by adding an HPTE. If the address can't be determined
* to be valid via Linux page tables, return 1. If handled return 0
diff --git a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h
index ae76cae1483f..2f0f36f73d38 100644
--- a/include/asm-ppc64/paca.h
+++ b/include/asm-ppc64/paca.h
@@ -20,7 +20,6 @@
#include <asm/types.h>
#include <asm/lppaca.h>
#include <asm/iSeries/ItLpRegSave.h>
-#include <asm/iSeries/ItLpQueue.h>
#include <asm/mmu.h>
register struct paca_struct *local_paca asm("r13");
@@ -62,7 +61,6 @@ struct paca_struct {
u16 paca_index; /* Logical processor number */
u32 default_decr; /* Default decrementer value */
- struct ItLpQueue *lpqueue_ptr; /* LpQueue handled by this CPU */
u64 kernel_toc; /* Kernel TOC address */
u64 stab_real; /* Absolute address of segment table */
u64 stab_addr; /* Virtual address of segment table */
@@ -91,7 +89,6 @@ struct paca_struct {
u64 next_jiffy_update_tb; /* TB value for next jiffy update */
u64 saved_r1; /* r1 save for RTAS calls */
u64 saved_msr; /* MSR saved here by enter_rtas */
- u32 lpevent_count; /* lpevents processed */
u8 proc_enabled; /* irq soft-enable flag */
/* not yet used */
diff --git a/include/asm-ppc64/pci.h b/include/asm-ppc64/pci.h
index 6cd593f660a0..faa772223075 100644
--- a/include/asm-ppc64/pci.h
+++ b/include/asm-ppc64/pci.h
@@ -37,7 +37,7 @@ static inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -78,6 +78,25 @@ static inline int pci_dac_dma_supported(struct pci_dev *hwdev,u64 mask)
return 0;
}
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ unsigned long cacheline_size;
+ u8 byte;
+
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ *strat = PCI_DMA_BURST_MULTIPLE;
+ *strategy_parameter = cacheline_size;
+}
+#endif
+
extern int pci_domain_nr(struct pci_bus *bus);
/* Decide whether to display the domain number in /proc */
@@ -136,6 +155,13 @@ extern pgprot_t pci_phys_mem_access_prot(struct file *file,
unsigned long size,
pgprot_t prot);
+#ifdef CONFIG_PPC_MULTIPLATFORM
+#define HAVE_ARCH_PCI_RESOURCE_TO_USER
+extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc,
+ u64 *start, u64 *end);
+#endif /* CONFIG_PPC_MULTIPLATFORM */
+
#endif /* __KERNEL__ */
diff --git a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
index af28aa55d8c1..352306cfb579 100644
--- a/include/asm-ppc64/processor.h
+++ b/include/asm-ppc64/processor.h
@@ -20,6 +20,7 @@
#include <asm/ptrace.h>
#include <asm/types.h>
#include <asm/systemcfg.h>
+#include <asm/cputable.h>
/* Machine State Register (MSR) Fields */
#define MSR_SF_LG 63 /* Enable 64 bit mode */
@@ -501,24 +502,37 @@ static inline void ppc64_runlatch_on(void)
{
unsigned long ctrl;
- ctrl = mfspr(SPRN_CTRLF);
- ctrl |= CTRL_RUNLATCH;
- mtspr(SPRN_CTRLT, ctrl);
+ if (cpu_has_feature(CPU_FTR_CTRL)) {
+ ctrl = mfspr(SPRN_CTRLF);
+ ctrl |= CTRL_RUNLATCH;
+ mtspr(SPRN_CTRLT, ctrl);
+ }
}
static inline void ppc64_runlatch_off(void)
{
unsigned long ctrl;
- ctrl = mfspr(SPRN_CTRLF);
- ctrl &= ~CTRL_RUNLATCH;
- mtspr(SPRN_CTRLT, ctrl);
+ if (cpu_has_feature(CPU_FTR_CTRL)) {
+ ctrl = mfspr(SPRN_CTRLF);
+ ctrl &= ~CTRL_RUNLATCH;
+ mtspr(SPRN_CTRLT, ctrl);
+ }
}
#endif /* __KERNEL__ */
#endif /* __ASSEMBLY__ */
+#ifdef __KERNEL__
+#define RUNLATCH_ON(REG) \
+BEGIN_FTR_SECTION \
+ mfspr (REG),SPRN_CTRLF; \
+ ori (REG),(REG),CTRL_RUNLATCH; \
+ mtspr SPRN_CTRLT,(REG); \
+END_FTR_SECTION_IFSET(CPU_FTR_CTRL)
+#endif
+
/*
* Number of entries in the SLB. If this ever changes we should handle
* it with a use a cpu feature fixup.
diff --git a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
index 605d91e011ec..4a94acf6bfed 100644
--- a/include/asm-ppc64/unistd.h
+++ b/include/asm-ppc64/unistd.h
@@ -268,7 +268,7 @@
#define __NR_rtas 255
/* Number 256 is reserved for sys_debug_setcontext */
/* Number 257 is reserved for vserver */
-/* Number 258 is reserved for new sys_remap_file_pages */
+/* 258 currently unused */
#define __NR_mbind 259
#define __NR_get_mempolicy 260
#define __NR_set_mempolicy 261
@@ -283,8 +283,10 @@
#define __NR_request_key 270
#define __NR_keyctl 271
#define __NR_waitid 272
+#define __NR_ioprio_set 273
+#define __NR_ioprio_get 274
-#define __NR_syscalls 273
+#define __NR_syscalls 275
#ifdef __KERNEL__
#define NR_syscalls __NR_syscalls
#endif
diff --git a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h
index fdec5e7a7af6..0c45e14e26ca 100644
--- a/include/asm-ppc64/xics.h
+++ b/include/asm-ppc64/xics.h
@@ -17,6 +17,7 @@
void xics_init_IRQ(void);
int xics_get_irq(struct pt_regs *);
void xics_setup_cpu(void);
+void xics_teardown_cpu(void);
void xics_cause_IPI(int cpu);
void xics_request_IPIs(void);
void xics_migrate_irqs_away(void);
diff --git a/include/asm-s390/cpcmd.h b/include/asm-s390/cpcmd.h
index 1d33c5da083e..1fcf65be7a23 100644
--- a/include/asm-s390/cpcmd.h
+++ b/include/asm-s390/cpcmd.h
@@ -11,14 +11,28 @@
#define __CPCMD__
/*
+ * the lowlevel function for cpcmd
* the caller of __cpcmd has to ensure that the response buffer is below 2 GB
*/
-extern void __cpcmd(char *cmd, char *response, int rlen);
+extern int __cpcmd(const char *cmd, char *response, int rlen, int *response_code);
#ifndef __s390x__
#define cpcmd __cpcmd
#else
-extern void cpcmd(char *cmd, char *response, int rlen);
+/*
+ * cpcmd is the in-kernel interface for issuing CP commands
+ *
+ * cmd: null-terminated command string, max 240 characters
+ * response: response buffer for VM's textual response
+ * rlen: size of the response buffer, cpcmd will not exceed this size
+ * but will cap the output, if its too large. Everything that
+ * did not fit into the buffer will be silently dropped
+ * response_code: return pointer for VM's error code
+ * return value: the size of the response. The caller can check if the buffer
+ * was large enough by comparing the return value and rlen
+ * NOTE: If the response buffer is not below 2 GB, cpcmd can sleep
+ */
+extern int cpcmd(const char *cmd, char *response, int rlen, int *response_code);
#endif /*__s390x__*/
#endif
diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h
index 6bbcdea42a86..92360d90144b 100644
--- a/include/asm-s390/debug.h
+++ b/include/asm-s390/debug.h
@@ -9,6 +9,8 @@
#ifndef DEBUG_H
#define DEBUG_H
+#include <linux/config.h>
+#include <linux/fs.h>
#include <linux/string.h>
/* Note:
@@ -31,19 +33,18 @@ struct __debug_entry{
} __attribute__((packed));
-#define __DEBUG_FEATURE_VERSION 1 /* version of debug feature */
+#define __DEBUG_FEATURE_VERSION 2 /* version of debug feature */
#ifdef __KERNEL__
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
-#include <linux/proc_fs.h>
#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */
#define DEBUG_FLUSH_ALL -1 /* parameter to flush all areas */
#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */
-#define DEBUG_MAX_PROCF_LEN 64 /* max length for a proc file name */
+#define DEBUG_MAX_NAME_LEN 64 /* max length for a debugfs file name */
#define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */
#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
@@ -64,16 +65,17 @@ typedef struct debug_info {
spinlock_t lock;
int level;
int nr_areas;
- int page_order;
+ int pages_per_area;
int buf_size;
int entry_size;
- debug_entry_t** areas;
+ debug_entry_t*** areas;
int active_area;
- int *active_entry;
- struct proc_dir_entry* proc_root_entry;
- struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS];
+ int *active_pages;
+ int *active_entries;
+ struct dentry* debugfs_root_entry;
+ struct dentry* debugfs_entries[DEBUG_MAX_VIEWS];
struct debug_view* views[DEBUG_MAX_VIEWS];
- char name[DEBUG_MAX_PROCF_LEN];
+ char name[DEBUG_MAX_NAME_LEN];
} debug_info_t;
typedef int (debug_header_proc_t) (debug_info_t* id,
@@ -98,7 +100,7 @@ int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view,
int area, debug_entry_t* entry, char* out_buf);
struct debug_view {
- char name[DEBUG_MAX_PROCF_LEN];
+ char name[DEBUG_MAX_NAME_LEN];
debug_prolog_proc_t* prolog_proc;
debug_header_proc_t* header_proc;
debug_format_proc_t* format_proc;
@@ -120,7 +122,7 @@ debug_entry_t* debug_exception_common(debug_info_t* id, int level,
/* Debug Feature API: */
-debug_info_t* debug_register(char* name, int pages_index, int nr_areas,
+debug_info_t* debug_register(char* name, int pages, int nr_areas,
int buf_size);
void debug_unregister(debug_info_t* id);
@@ -132,7 +134,8 @@ void debug_stop_all(void);
extern inline debug_entry_t*
debug_event(debug_info_t* id, int level, void* data, int length)
{
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_event_common(id,level,data,length);
}
@@ -140,7 +143,8 @@ extern inline debug_entry_t*
debug_int_event(debug_info_t* id, int level, unsigned int tag)
{
unsigned int t=tag;
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_event_common(id,level,&t,sizeof(unsigned int));
}
@@ -148,14 +152,16 @@ extern inline debug_entry_t *
debug_long_event (debug_info_t* id, int level, unsigned long tag)
{
unsigned long t=tag;
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_event_common(id,level,&t,sizeof(unsigned long));
}
extern inline debug_entry_t*
debug_text_event(debug_info_t* id, int level, const char* txt)
{
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_event_common(id,level,txt,strlen(txt));
}
@@ -167,7 +173,8 @@ debug_sprintf_event(debug_info_t* id,int level,char *string,...)
extern inline debug_entry_t*
debug_exception(debug_info_t* id, int level, void* data, int length)
{
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_exception_common(id,level,data,length);
}
@@ -175,7 +182,8 @@ extern inline debug_entry_t*
debug_int_exception(debug_info_t* id, int level, unsigned int tag)
{
unsigned int t=tag;
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_exception_common(id,level,&t,sizeof(unsigned int));
}
@@ -183,14 +191,16 @@ extern inline debug_entry_t *
debug_long_exception (debug_info_t* id, int level, unsigned long tag)
{
unsigned long t=tag;
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_exception_common(id,level,&t,sizeof(unsigned long));
}
extern inline debug_entry_t*
debug_text_exception(debug_info_t* id, int level, const char* txt)
{
- if ((!id) || (level > id->level)) return NULL;
+ if ((!id) || (level > id->level) || (id->pages_per_area == 0))
+ return NULL;
return debug_exception_common(id,level,txt,strlen(txt));
}
diff --git a/include/asm-s390/kexec.h b/include/asm-s390/kexec.h
new file mode 100644
index 000000000000..54cf7d9f251c
--- /dev/null
+++ b/include/asm-s390/kexec.h
@@ -0,0 +1,42 @@
+/*
+ * include/asm-s390/kexec.h
+ *
+ * (C) Copyright IBM Corp. 2005
+ *
+ * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com>
+ *
+ */
+
+#ifndef _S390_KEXEC_H
+#define _S390_KEXEC_H
+
+#include <asm/page.h>
+#include <asm/processor.h>
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (-1UL)
+
+/* Maximum address we can use for the control pages */
+/* Not more than 2GB */
+#define KEXEC_CONTROL_MEMORY_LIMIT (1<<31)
+
+/* Allocate one page for the pdp and the second for the code */
+#define KEXEC_CONTROL_CODE_SIZE 4096
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_S390
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /*_S390_KEXEC_H */
diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h
index df5172fc589d..76b5b19c0ae2 100644
--- a/include/asm-s390/lowcore.h
+++ b/include/asm-s390/lowcore.h
@@ -109,10 +109,14 @@
#ifndef __s390x__
#define __LC_PFAULT_INTPARM 0x080
+#define __LC_CPU_TIMER_SAVE_AREA 0x0D8
#define __LC_AREGS_SAVE_AREA 0x120
+#define __LC_GPREGS_SAVE_AREA 0x180
#define __LC_CREGS_SAVE_AREA 0x1C0
#else /* __s390x__ */
#define __LC_PFAULT_INTPARM 0x11B8
+#define __LC_GPREGS_SAVE_AREA 0x1280
+#define __LC_CPU_TIMER_SAVE_AREA 0x1328
#define __LC_AREGS_SAVE_AREA 0x1340
#define __LC_CREGS_SAVE_AREA 0x1380
#endif /* __s390x__ */
@@ -167,7 +171,8 @@ struct _lowcore
__u16 subchannel_nr; /* 0x0ba */
__u32 io_int_parm; /* 0x0bc */
__u32 io_int_word; /* 0x0c0 */
- __u8 pad3[0xD8-0xC4]; /* 0x0c4 */
+ __u8 pad3[0xD4-0xC4]; /* 0x0c4 */
+ __u32 extended_save_area_addr; /* 0x0d4 */
__u32 cpu_timer_save_area[2]; /* 0x0d8 */
__u32 clock_comp_save_area[2]; /* 0x0e0 */
__u32 mcck_interruption_code[2]; /* 0x0e8 */
diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h
index fb46e9090b50..8bd14de69e35 100644
--- a/include/asm-s390/processor.h
+++ b/include/asm-s390/processor.h
@@ -207,6 +207,18 @@ unsigned long get_wchan(struct task_struct *p);
#endif /* __s390x__ */
/*
+ * Set PSW to specified value.
+ */
+static inline void __load_psw(psw_t psw)
+{
+#ifndef __s390x__
+ asm volatile ("lpsw 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#else
+ asm volatile ("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
+#endif
+}
+
+/*
* Set PSW mask to specified value, while leaving the
* PSW addr pointing to the next instruction.
*/
@@ -214,8 +226,8 @@ unsigned long get_wchan(struct task_struct *p);
static inline void __load_psw_mask (unsigned long mask)
{
unsigned long addr;
-
psw_t psw;
+
psw.mask = mask;
#ifndef __s390x__
@@ -241,30 +253,8 @@ static inline void __load_psw_mask (unsigned long mask)
*/
static inline void enabled_wait(void)
{
- unsigned long reg;
- psw_t wait_psw;
-
- wait_psw.mask = PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
- PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY;
-#ifndef __s390x__
- asm volatile (
- " basr %0,0\n"
- "0: la %0,1f-0b(%0)\n"
- " st %0,4(%1)\n"
- " oi 4(%1),0x80\n"
- " lpsw 0(%1)\n"
- "1:"
- : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
- : "memory", "cc" );
-#else /* __s390x__ */
- asm volatile (
- " larl %0,0f\n"
- " stg %0,8(%1)\n"
- " lpswe 0(%1)\n"
- "0:"
- : "=&a" (reg) : "a" (&wait_psw), "m" (wait_psw)
- : "memory", "cc" );
-#endif /* __s390x__ */
+ __load_psw_mask(PSW_BASE_BITS | PSW_MASK_IO | PSW_MASK_EXT |
+ PSW_MASK_MCHECK | PSW_MASK_WAIT | PSW_DEFAULT_KEY);
}
/*
@@ -273,13 +263,11 @@ static inline void enabled_wait(void)
static inline void disabled_wait(unsigned long code)
{
- char psw_buffer[2*sizeof(psw_t)];
unsigned long ctl_buf;
- psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1)
- & -sizeof(psw_t));
+ psw_t dw_psw;
- dw_psw->mask = PSW_BASE_BITS | PSW_MASK_WAIT;
- dw_psw->addr = code;
+ dw_psw.mask = PSW_BASE_BITS | PSW_MASK_WAIT;
+ dw_psw.addr = code;
/*
* Store status and then load disabled wait psw,
* the processor is dead afterwards
@@ -301,7 +289,7 @@ static inline void disabled_wait(unsigned long code)
" oi 0x1c0,0x10\n" /* fake protection bit */
" lpsw 0(%1)"
: "=m" (ctl_buf)
- : "a" (dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
+ : "a" (&dw_psw), "a" (&ctl_buf), "m" (dw_psw) : "cc" );
#else /* __s390x__ */
asm volatile (" stctg 0,0,0(%2)\n"
" ni 4(%2),0xef\n" /* switch off protection */
@@ -333,7 +321,7 @@ static inline void disabled_wait(unsigned long code)
" oi 0x384(1),0x10\n" /* fake protection bit */
" lpswe 0(%1)"
: "=m" (ctl_buf)
- : "a" (dw_psw), "a" (&ctl_buf),
+ : "a" (&dw_psw), "a" (&ctl_buf),
"m" (dw_psw) : "cc", "0", "1");
#endif /* __s390x__ */
}
diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h
index 4eff8f2e3bf1..fc7c96edc697 100644
--- a/include/asm-s390/ptrace.h
+++ b/include/asm-s390/ptrace.h
@@ -276,7 +276,7 @@ typedef struct
#endif /* __s390x__ */
#define PSW_KERNEL_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | \
- PSW_DEFAULT_KEY)
+ PSW_MASK_MCHECK | PSW_DEFAULT_KEY)
#define PSW_USER_BITS (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_HOME | \
PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK | \
PSW_MASK_PSTATE | PSW_DEFAULT_KEY)
diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h
index 81514d76edcf..864cae7e1fd6 100644
--- a/include/asm-s390/system.h
+++ b/include/asm-s390/system.h
@@ -16,6 +16,7 @@
#include <asm/types.h>
#include <asm/ptrace.h>
#include <asm/setup.h>
+#include <asm/processor.h>
#ifdef __KERNEL__
@@ -103,29 +104,16 @@ static inline void restore_access_regs(unsigned int *acrs)
prev = __switch_to(prev,next); \
} while (0)
-#define prepare_arch_switch(rq, next) do { } while(0)
-#define task_running(rq, p) ((rq)->curr == (p))
-
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
extern void account_user_vtime(struct task_struct *);
extern void account_system_vtime(struct task_struct *);
+#endif
-#define finish_arch_switch(rq, prev) do { \
+#define finish_arch_switch(prev) do { \
set_fs(current->thread.mm_segment); \
- spin_unlock(&(rq)->lock); \
account_system_vtime(prev); \
- local_irq_enable(); \
} while (0)
-#else
-
-#define finish_arch_switch(rq, prev) do { \
- set_fs(current->thread.mm_segment); \
- spin_unlock_irq(&(rq)->lock); \
-} while (0)
-
-#endif
-
#define nop() __asm__ __volatile__ ("nop")
#define xchg(ptr,x) \
@@ -331,9 +319,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#ifdef __s390x__
-#define __load_psw(psw) \
- __asm__ __volatile__("lpswe 0(%0)" : : "a" (&psw), "m" (psw) : "cc" );
-
#define __ctl_load(array, low, high) ({ \
typedef struct { char _[sizeof(array)]; } addrtype; \
__asm__ __volatile__ ( \
@@ -390,9 +375,6 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
#else /* __s390x__ */
-#define __load_psw(psw) \
- __asm__ __volatile__("lpsw 0(%0)" : : "a" (&psw) : "cc" );
-
#define __ctl_load(array, low, high) ({ \
typedef struct { char _[sizeof(array)]; } addrtype; \
__asm__ __volatile__ ( \
@@ -451,6 +433,20 @@ __cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
/* For spinlocks etc */
#define local_irq_save(x) ((x) = local_irq_disable())
+/*
+ * Use to set psw mask except for the first byte which
+ * won't be changed by this function.
+ */
+static inline void
+__set_psw_mask(unsigned long mask)
+{
+ local_save_flags(mask);
+ __load_psw_mask(mask);
+}
+
+#define local_mcck_enable() __set_psw_mask(PSW_KERNEL_BITS)
+#define local_mcck_disable() __set_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK)
+
#ifdef CONFIG_SMP
extern void smp_ctl_set_bit(int cr, int bit);
diff --git a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h
index fe101d41e849..6c18a3f24316 100644
--- a/include/asm-s390/thread_info.h
+++ b/include/asm-s390/thread_info.h
@@ -96,6 +96,7 @@ static inline struct thread_info *current_thread_info(void)
#define TIF_RESTART_SVC 4 /* restart svc with new svc number */
#define TIF_SYSCALL_AUDIT 5 /* syscall auditing active */
#define TIF_SINGLE_STEP 6 /* deliver sigtrap on return to user */
+#define TIF_MCCK_PENDING 7 /* machine check handling is pending */
#define TIF_USEDFPU 16 /* FPU was used by this task this quantum (SMP) */
#define TIF_POLLING_NRFLAG 17 /* true if poll_idle() is polling
TIF_NEED_RESCHED */
@@ -109,6 +110,7 @@ static inline struct thread_info *current_thread_info(void)
#define _TIF_RESTART_SVC (1<<TIF_RESTART_SVC)
#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SINGLE_STEP (1<<TIF_SINGLE_STEP)
+#define _TIF_MCCK_PENDING (1<<TIF_MCCK_PENDING)
#define _TIF_USEDFPU (1<<TIF_USEDFPU)
#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_31BIT (1<<TIF_31BIT)
diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h
index f1a204f7c0f0..363db45f8d07 100644
--- a/include/asm-s390/unistd.h
+++ b/include/asm-s390/unistd.h
@@ -269,7 +269,7 @@
#define __NR_mq_timedreceive 274
#define __NR_mq_notify 275
#define __NR_mq_getsetattr 276
-/* Number 277 is reserved for new sys_kexec_load */
+#define __NR_kexec_load 277
#define __NR_add_key 278
#define __NR_request_key 279
#define __NR_keyctl 280
diff --git a/include/asm-sh/bigsur/serial.h b/include/asm-sh/bigsur/serial.h
index 540f12205923..7233af42f755 100644
--- a/include/asm-sh/bigsur/serial.h
+++ b/include/asm-sh/bigsur/serial.h
@@ -14,13 +14,10 @@
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */
-
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
/* XXX: This should be moved ino irq.h */
#define irq_cannonicalize(x) (x)
diff --git a/include/asm-sh/ec3104/serial.h b/include/asm-sh/ec3104/serial.h
index f8eb16312ed9..cfe4d78ec1ee 100644
--- a/include/asm-sh/ec3104/serial.h
+++ b/include/asm-sh/ec3104/serial.h
@@ -10,13 +10,11 @@
* it's got the keyboard controller behind it so we can't really use it
* (without moving the keyboard driver to userspace, which doesn't sound
* like a very good idea) */
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x11C00, EC3104_IRQBASE+7, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x12000, EC3104_IRQBASE+8, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x12400, EC3104_IRQBASE+9, STD_COM_FLAGS }, /* ttyS2 */
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
/* XXX: This should be moved ino irq.h */
#define irq_cannonicalize(x) (x)
diff --git a/include/asm-sh/pci.h b/include/asm-sh/pci.h
index 9c3b63d0105e..0a523c85b11c 100644
--- a/include/asm-sh/pci.h
+++ b/include/asm-sh/pci.h
@@ -36,7 +36,7 @@ struct pci_dev;
extern void pcibios_set_master(struct pci_dev *dev);
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -96,6 +96,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
#define sg_dma_address(sg) (virt_to_bus((sg)->dma_address))
#define sg_dma_len(sg) ((sg)->length)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
/* Board-specific fixup routines. */
extern void pcibios_fixup(void);
extern void pcibios_fixup_irqs(void);
diff --git a/include/asm-sh/serial.h b/include/asm-sh/serial.h
index 5474dbdbaa86..f51e232d5cd9 100644
--- a/include/asm-sh/serial.h
+++ b/include/asm-sh/serial.h
@@ -29,20 +29,18 @@
#ifdef CONFIG_HD64465
#include <asm/hd64465.h>
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, HD64465_IRQ_UART, STD_COM_FLAGS } /* ttyS0 */
#else
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */
#endif
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
#endif
#endif /* _ASM_SERIAL_H */
diff --git a/include/asm-sh64/pci.h b/include/asm-sh64/pci.h
index 8cc14e139750..aa8043089bb6 100644
--- a/include/asm-sh64/pci.h
+++ b/include/asm-sh64/pci.h
@@ -26,7 +26,7 @@ extern void pcibios_set_master(struct pci_dev *dev);
/*
* Set penalize isa irq function
*/
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -86,6 +86,16 @@ static inline void pcibios_penalize_isa_irq(int irq)
#define sg_dma_address(sg) ((sg)->dma_address)
#define sg_dma_len(sg) ((sg)->length)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
/* Board-specific fixup routines. */
extern void pcibios_fixup(void);
extern void pcibios_fixup_irqs(void);
diff --git a/include/asm-sh64/serial.h b/include/asm-sh64/serial.h
index 8e39b4e90c76..29c9be15112b 100644
--- a/include/asm-sh64/serial.h
+++ b/include/asm-sh64/serial.h
@@ -20,13 +20,11 @@
#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST)
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS } /* ttyS1 */
-#define SERIAL_PORT_DFNS STD_SERIAL_PORT_DEFNS
-
/* XXX: This should be moved ino irq.h */
#define irq_cannonicalize(x) (x)
diff --git a/include/asm-sparc/pci.h b/include/asm-sparc/pci.h
index d200a25a7373..97052baf90c1 100644
--- a/include/asm-sparc/pci.h
+++ b/include/asm-sparc/pci.h
@@ -20,7 +20,7 @@ extern inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-extern inline void pcibios_penalize_isa_irq(int irq)
+extern inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -144,6 +144,16 @@ extern inline int pci_dma_supported(struct pci_dev *hwdev, u64 mask)
#define pci_dac_dma_supported(dev, mask) (0)
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
static inline void pcibios_add_platform_entries(struct pci_dev *dev)
{
}
diff --git a/include/asm-sparc/system.h b/include/asm-sparc/system.h
index 80cf20cfaee1..898562ebe94c 100644
--- a/include/asm-sparc/system.h
+++ b/include/asm-sparc/system.h
@@ -101,7 +101,7 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
* SWITCH_ENTER and SWITH_DO_LAZY_FPU do not work yet (e.g. SMP does not work)
* XXX WTF is the above comment? Found in late teen 2.4.x.
*/
-#define prepare_arch_switch(rq, next) do { \
+#define prepare_arch_switch(next) do { \
__asm__ __volatile__( \
".globl\tflush_patch_switch\nflush_patch_switch:\n\t" \
"save %sp, -0x40, %sp; save %sp, -0x40, %sp; save %sp, -0x40, %sp\n\t" \
@@ -109,8 +109,6 @@ extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
"save %sp, -0x40, %sp\n\t" \
"restore; restore; restore; restore; restore; restore; restore"); \
} while(0)
-#define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock)
-#define task_running(rq, p) ((rq)->curr == (p))
/* Much care has gone into this code, do not touch it.
*
diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h
index 846708403900..aee17d7e2e44 100644
--- a/include/asm-sparc/unistd.h
+++ b/include/asm-sparc/unistd.h
@@ -212,7 +212,7 @@
#define __NR_epoll_create 193 /* Linux Specific */
#define __NR_epoll_ctl 194 /* Linux Specific */
#define __NR_epoll_wait 195 /* Linux Specific */
-/* #define __NR_ulimit 196 Linux Specific */
+#define __NR_ioprio_set 196 /* Linux Specific */
#define __NR_getppid 197 /* Linux Specific */
#define __NR_sigaction 198 /* Linux Specific */
#define __NR_sgetmask 199 /* Linux Specific */
@@ -234,7 +234,7 @@
#define __NR_ipc 215 /* Linux Specific */
#define __NR_sigreturn 216 /* Linux Specific */
#define __NR_clone 217 /* Linux Specific */
-/* #define __NR_modify_ldt 218 Linux Specific - i386 specific, unused */
+#define __NR_ioprio_get 218 /* Linux Specific */
#define __NR_adjtimex 219 /* Linux Specific */
#define __NR_sigprocmask 220 /* Linux Specific */
#define __NR_create_module 221 /* Linux Specific */
diff --git a/include/asm-sparc64/auxio.h b/include/asm-sparc64/auxio.h
index 5eb01dd47150..81a590a50a1f 100644
--- a/include/asm-sparc64/auxio.h
+++ b/include/asm-sparc64/auxio.h
@@ -75,6 +75,8 @@
#ifndef __ASSEMBLY__
+extern void __iomem *auxio_register;
+
#define AUXIO_LTE_ON 1
#define AUXIO_LTE_OFF 0
diff --git a/include/asm-sparc64/floppy.h b/include/asm-sparc64/floppy.h
index e071b4b4edfd..49d49a285943 100644
--- a/include/asm-sparc64/floppy.h
+++ b/include/asm-sparc64/floppy.h
@@ -159,7 +159,7 @@ static void sun_82077_fd_outb(unsigned char value, unsigned long port)
* underruns. If non-zero, doing_pdma encodes the direction of
* the transfer for debugging. 1=read 2=write
*/
-char *pdma_vaddr;
+unsigned char *pdma_vaddr;
unsigned long pdma_size;
volatile int doing_pdma = 0;
@@ -209,8 +209,7 @@ static void sun_fd_enable_dma(void)
pdma_areasize = pdma_size;
}
-/* Our low-level entry point in arch/sparc/kernel/entry.S */
-extern irqreturn_t floppy_hardint(int irq, void *unused, struct pt_regs *regs);
+extern irqreturn_t sparc_floppy_irq(int, void *, struct pt_regs *);
static int sun_fd_request_irq(void)
{
@@ -220,8 +219,8 @@ static int sun_fd_request_irq(void)
if(!once) {
once = 1;
- error = request_fast_irq(FLOPPY_IRQ, floppy_hardint,
- SA_INTERRUPT, "floppy", NULL);
+ error = request_irq(FLOPPY_IRQ, sparc_floppy_irq,
+ SA_INTERRUPT, "floppy", NULL);
return ((error == 0) ? 0 : -1);
}
@@ -615,7 +614,7 @@ static unsigned long __init sun_floppy_init(void)
struct linux_ebus *ebus;
struct linux_ebus_device *edev = NULL;
unsigned long config = 0;
- unsigned long auxio_reg;
+ void __iomem *auxio_reg;
for_each_ebus(ebus) {
for_each_ebusdev(edev, ebus) {
@@ -642,7 +641,7 @@ static unsigned long __init sun_floppy_init(void)
/* Make sure the high density bit is set, some systems
* (most notably Ultra5/Ultra10) come up with it clear.
*/
- auxio_reg = edev->resource[2].start;
+ auxio_reg = (void __iomem *) edev->resource[2].start;
writel(readl(auxio_reg)|0x2, auxio_reg);
sun_pci_ebus_dev = ebus->self;
@@ -650,7 +649,8 @@ static unsigned long __init sun_floppy_init(void)
spin_lock_init(&sun_pci_fd_ebus_dma.lock);
/* XXX ioremap */
- sun_pci_fd_ebus_dma.regs = edev->resource[1].start;
+ sun_pci_fd_ebus_dma.regs = (void __iomem *)
+ edev->resource[1].start;
if (!sun_pci_fd_ebus_dma.regs)
return 0;
diff --git a/include/asm-sparc64/irq.h b/include/asm-sparc64/irq.h
index 3aef0ca67750..8b70edcb80dc 100644
--- a/include/asm-sparc64/irq.h
+++ b/include/asm-sparc64/irq.h
@@ -16,10 +16,22 @@
#include <asm/pil.h>
#include <asm/ptrace.h>
+struct ino_bucket;
+
+#define MAX_IRQ_DESC_ACTION 4
+
+struct irq_desc {
+ void (*pre_handler)(struct ino_bucket *, void *, void *);
+ void *pre_handler_arg1;
+ void *pre_handler_arg2;
+ u32 action_active_mask;
+ struct irqaction action[MAX_IRQ_DESC_ACTION];
+};
+
/* You should not mess with this directly. That's the job of irq.c.
*
* If you make changes here, please update hand coded assembler of
- * SBUS/floppy interrupt handler in entry.S -DaveM
+ * the vectored interrupt trap handler in entry.S -DaveM
*
* This is currently one DCACHE line, two buckets per L2 cache
* line. Keep this in mind please.
@@ -42,24 +54,11 @@ struct ino_bucket {
/* Miscellaneous flags. */
/*0x06*/unsigned char flags;
- /* This is used to deal with IBF_DMA_SYNC on
- * Sabre systems.
- */
-/*0x07*/unsigned char synctab_ent;
-
- /* Reference to handler for this IRQ. If this is
- * non-NULL this means it is active and should be
- * serviced. Else the pending member is set to one
- * and later registry of the interrupt checks for
- * this condition.
- *
- * Normally this is just an irq_action structure.
- * But, on PCI, if multiple interrupt sources behind
- * a bridge have multiple interrupt sources that share
- * the same INO bucket, this points to an array of
- * pointers to four IRQ action structures.
- */
-/*0x08*/void *irq_info;
+ /* Currently unused. */
+/*0x07*/unsigned char __pad;
+
+ /* Reference to IRQ descriptor for this bucket. */
+/*0x08*/struct irq_desc *irq_info;
/* Sun5 Interrupt Clear Register. */
/*0x10*/unsigned long iclr;
@@ -69,12 +68,6 @@ struct ino_bucket {
};
-#ifdef CONFIG_PCI
-extern unsigned long pci_dma_wsync;
-extern unsigned long dma_sync_reg_table[256];
-extern unsigned char dma_sync_reg_table_entry;
-#endif
-
/* IMAP/ICLR register defines */
#define IMAP_VALID 0x80000000 /* IRQ Enabled */
#define IMAP_TID_UPA 0x7c000000 /* UPA TargetID */
@@ -90,11 +83,9 @@ extern unsigned char dma_sync_reg_table_entry;
#define ICLR_PENDING 0x00000003 /* Pending state */
/* Only 8-bits are available, be careful. -DaveM */
-#define IBF_DMA_SYNC 0x01 /* DMA synchronization behind PCI bridge needed. */
-#define IBF_PCI 0x02 /* Indicates PSYCHO/SABRE/SCHIZO PCI interrupt. */
-#define IBF_ACTIVE 0x04 /* This interrupt is active and has a handler. */
-#define IBF_MULTI 0x08 /* On PCI, indicates shared bucket. */
-#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */
+#define IBF_PCI 0x02 /* PSYCHO/SABRE/SCHIZO PCI interrupt. */
+#define IBF_ACTIVE 0x04 /* Interrupt is active and has a handler.*/
+#define IBF_INPROGRESS 0x10 /* IRQ is being serviced. */
#define NUM_IVECS (IMAP_INR + 1)
extern struct ino_bucket ivector_table[NUM_IVECS];
@@ -122,11 +113,6 @@ extern void enable_irq(unsigned int);
extern unsigned int build_irq(int pil, int inofixup, unsigned long iclr, unsigned long imap);
extern unsigned int sbus_build_irq(void *sbus, unsigned int ino);
-extern int request_fast_irq(unsigned int irq,
- irqreturn_t (*handler)(int, void *, struct pt_regs *),
- unsigned long flags, __const__ char *devname,
- void *dev_id);
-
static __inline__ void set_softint(unsigned long bits)
{
__asm__ __volatile__("wr %0, 0x0, %%set_softint"
diff --git a/include/asm-sparc64/kdebug.h b/include/asm-sparc64/kdebug.h
index f70d3dad01f9..6321f5a0198d 100644
--- a/include/asm-sparc64/kdebug.h
+++ b/include/asm-sparc64/kdebug.h
@@ -16,7 +16,7 @@ struct die_args {
};
/* Note - you should never unregister because that can race with NMIs.
- * If you really want to do it first unregister - then synchronize_kernel
+ * If you really want to do it first unregister - then synchronize_sched
* - then free.
*/
int register_die_notifier(struct notifier_block *nb);
diff --git a/include/asm-sparc64/param.h b/include/asm-sparc64/param.h
index 6a12f3ac0359..a1cd4974630b 100644
--- a/include/asm-sparc64/param.h
+++ b/include/asm-sparc64/param.h
@@ -1,9 +1,10 @@
-/* $Id: param.h,v 1.2 2000/10/30 21:01:41 davem Exp $ */
#ifndef _ASMSPARC64_PARAM_H
#define _ASMSPARC64_PARAM_H
+#include <linux/config.h>
+
#ifdef __KERNEL__
-# define HZ 1000 /* Internal kernel timer frequency */
+# define HZ CONFIG_HZ /* Internal kernel timer frequency */
# define USER_HZ 100 /* .. some user interfaces are in "ticks" */
# define CLOCKS_PER_SEC (USER_HZ)
#endif
diff --git a/include/asm-sparc64/parport.h b/include/asm-sparc64/parport.h
index b7e635544cec..56b5197d7898 100644
--- a/include/asm-sparc64/parport.h
+++ b/include/asm-sparc64/parport.h
@@ -27,12 +27,12 @@ static struct sparc_ebus_info {
static __inline__ void enable_dma(unsigned int dmanr)
{
+ ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
+
if (ebus_dma_request(&sparc_ebus_dmas[dmanr].info,
sparc_ebus_dmas[dmanr].addr,
sparc_ebus_dmas[dmanr].count))
BUG();
-
- ebus_dma_enable(&sparc_ebus_dmas[dmanr].info, 1);
}
static __inline__ void disable_dma(unsigned int dmanr)
diff --git a/include/asm-sparc64/pbm.h b/include/asm-sparc64/pbm.h
index 4c15610a2bac..38bbbccb4068 100644
--- a/include/asm-sparc64/pbm.h
+++ b/include/asm-sparc64/pbm.h
@@ -145,6 +145,9 @@ struct pci_pbm_info {
/* Physical address base of PBM registers. */
unsigned long pbm_regs;
+ /* Physical address of DMA sync register, if any. */
+ unsigned long sync_reg;
+
/* Opaque 32-bit system bus Port ID. */
u32 portid;
diff --git a/include/asm-sparc64/pci.h b/include/asm-sparc64/pci.h
index 2a0c85cd1c11..a4ab0ec7143a 100644
--- a/include/asm-sparc64/pci.h
+++ b/include/asm-sparc64/pci.h
@@ -23,7 +23,7 @@ static inline void pcibios_set_master(struct pci_dev *dev)
/* No special bus mastering setup handling */
}
-static inline void pcibios_penalize_isa_irq(int irq)
+static inline void pcibios_penalize_isa_irq(int irq, int active)
{
/* We don't do dynamic PCI IRQ allocation */
}
@@ -220,6 +220,25 @@ static inline int pci_dma_mapping_error(dma_addr_t dma_addr)
return (dma_addr == PCI_DMA_ERROR_CODE);
}
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ unsigned long cacheline_size;
+ u8 byte;
+
+ pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &byte);
+ if (byte == 0)
+ cacheline_size = 1024;
+ else
+ cacheline_size = (int) byte * 4;
+
+ *strat = PCI_DMA_BURST_BOUNDARY;
+ *strategy_parameter = cacheline_size;
+}
+#endif
+
/* Return the index of the PCI controller for device PDEV. */
extern int pci_domain_nr(struct pci_bus *bus);
diff --git a/include/asm-sparc64/rwsem.h b/include/asm-sparc64/rwsem.h
index bf2ae90ed3df..a1cc94f95984 100644
--- a/include/asm-sparc64/rwsem.h
+++ b/include/asm-sparc64/rwsem.h
@@ -55,8 +55,9 @@ static __inline__ int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
"add %%g1, %1, %%g7\n\t"
"cas [%2], %%g1, %%g7\n\t"
"cmp %%g1, %%g7\n\t"
+ "membar #StoreLoad | #StoreStore\n\t"
"bne,pn %%icc, 1b\n\t"
- " membar #StoreLoad | #StoreStore\n\t"
+ " nop\n\t"
"mov %%g7, %0\n\t"
: "=&r" (tmp)
: "0" (tmp), "r" (sem)
diff --git a/include/asm-sparc64/seccomp.h b/include/asm-sparc64/seccomp.h
new file mode 100644
index 000000000000..7fcd9968192b
--- /dev/null
+++ b/include/asm-sparc64/seccomp.h
@@ -0,0 +1,21 @@
+#ifndef _ASM_SECCOMP_H
+
+#include <linux/thread_info.h> /* already defines TIF_32BIT */
+
+#ifndef TIF_32BIT
+#error "unexpected TIF_32BIT on sparc64"
+#endif
+
+#include <linux/unistd.h>
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+
+#define __NR_seccomp_read_32 __NR_read
+#define __NR_seccomp_write_32 __NR_write
+#define __NR_seccomp_exit_32 __NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_sigreturn
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/include/asm-sparc64/signal.h b/include/asm-sparc64/signal.h
index becdf1bc5924..e3059bb4a465 100644
--- a/include/asm-sparc64/signal.h
+++ b/include/asm-sparc64/signal.h
@@ -162,21 +162,6 @@ struct sigstack {
#define MINSIGSTKSZ 4096
#define SIGSTKSZ 16384
-#ifdef __KERNEL__
-/*
- * DJHR
- * SA_STATIC_ALLOC is used for the SPARC system to indicate that this
- * interrupt handler's irq structure should be statically allocated
- * by the request_irq routine.
- * The alternative is that arch/sparc/kernel/irq.c has carnal knowledge
- * of interrupt usage and that sucks. Also without a flag like this
- * it may be possible for the free_irq routine to attempt to free
- * statically allocated data.. which is NOT GOOD.
- *
- */
-#define SA_STATIC_ALLOC 0x80
-#endif
-
#include <asm-generic/signal.h>
struct __new_sigaction {
diff --git a/include/asm-sparc64/spinlock.h b/include/asm-sparc64/spinlock.h
index db7581bdb531..9cb93a5c2b4f 100644
--- a/include/asm-sparc64/spinlock.h
+++ b/include/asm-sparc64/spinlock.h
@@ -52,12 +52,14 @@ static inline void _raw_spin_lock(spinlock_t *lock)
__asm__ __volatile__(
"1: ldstub [%1], %0\n"
+" membar #StoreLoad | #StoreStore\n"
" brnz,pn %0, 2f\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
" .subsection 2\n"
"2: ldub [%1], %0\n"
+" membar #LoadLoad\n"
" brnz,pt %0, 2b\n"
-" membar #LoadLoad\n"
+" nop\n"
" ba,a,pt %%xcc, 1b\n"
" .previous"
: "=&r" (tmp)
@@ -95,16 +97,18 @@ static inline void _raw_spin_lock_flags(spinlock_t *lock, unsigned long flags)
__asm__ __volatile__(
"1: ldstub [%2], %0\n"
-" brnz,pn %0, 2f\n"
" membar #StoreLoad | #StoreStore\n"
+" brnz,pn %0, 2f\n"
+" nop\n"
" .subsection 2\n"
"2: rdpr %%pil, %1\n"
" wrpr %3, %%pil\n"
"3: ldub [%2], %0\n"
-" brnz,pt %0, 3b\n"
" membar #LoadLoad\n"
+" brnz,pt %0, 3b\n"
+" nop\n"
" ba,pt %%xcc, 1b\n"
-" wrpr %1, %%pil\n"
+" wrpr %1, %%pil\n"
" .previous"
: "=&r" (tmp1), "=&r" (tmp2)
: "r"(lock), "r"(flags)
@@ -162,12 +166,14 @@ static void inline __read_lock(rwlock_t *lock)
"4: add %0, 1, %1\n"
" cas [%2], %0, %1\n"
" cmp %0, %1\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
" .subsection 2\n"
"2: ldsw [%2], %0\n"
+" membar #LoadLoad\n"
" brlz,pt %0, 2b\n"
-" membar #LoadLoad\n"
+" nop\n"
" ba,a,pt %%xcc, 4b\n"
" .previous"
: "=&r" (tmp1), "=&r" (tmp2)
@@ -204,12 +210,14 @@ static void inline __write_lock(rwlock_t *lock)
"4: or %0, %3, %1\n"
" cas [%2], %0, %1\n"
" cmp %0, %1\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
" .subsection 2\n"
"2: lduw [%2], %0\n"
+" membar #LoadLoad\n"
" brnz,pt %0, 2b\n"
-" membar #LoadLoad\n"
+" nop\n"
" ba,a,pt %%xcc, 4b\n"
" .previous"
: "=&r" (tmp1), "=&r" (tmp2)
@@ -240,8 +248,9 @@ static int inline __write_trylock(rwlock_t *lock)
" or %0, %4, %1\n"
" cas [%3], %0, %1\n"
" cmp %0, %1\n"
+" membar #StoreLoad | #StoreStore\n"
" bne,pn %%icc, 1b\n"
-" membar #StoreLoad | #StoreStore\n"
+" nop\n"
" mov 1, %2\n"
"2:"
: "=&r" (tmp1), "=&r" (tmp2), "=&r" (result)
diff --git a/include/asm-sparc64/spitfire.h b/include/asm-sparc64/spitfire.h
index 9d7613eea812..1aa932773af8 100644
--- a/include/asm-sparc64/spitfire.h
+++ b/include/asm-sparc64/spitfire.h
@@ -111,7 +111,6 @@ static __inline__ void spitfire_put_dcache_tag(unsigned long addr, unsigned long
"membar #Sync"
: /* No outputs */
: "r" (tag), "r" (addr), "i" (ASI_DCACHE_TAG));
- __asm__ __volatile__ ("membar #Sync" : : : "memory");
}
/* The instruction cache lines are flushed with this, but note that
diff --git a/include/asm-sparc64/system.h b/include/asm-sparc64/system.h
index fd12ca386f48..f9be2c5b4dc9 100644
--- a/include/asm-sparc64/system.h
+++ b/include/asm-sparc64/system.h
@@ -139,19 +139,13 @@ extern void __flushw_user(void);
#define flush_user_windows flushw_user
#define flush_register_windows flushw_all
-#define prepare_arch_switch(rq, next) \
-do { spin_lock(&(next)->switch_lock); \
- spin_unlock(&(rq)->lock); \
+/* Don't hold the runqueue lock over context switch */
+#define __ARCH_WANT_UNLOCKED_CTXSW
+#define prepare_arch_switch(next) \
+do { \
flushw_all(); \
} while (0)
-#define finish_arch_switch(rq, prev) \
-do { spin_unlock_irq(&(prev)->switch_lock); \
-} while (0)
-
-#define task_running(rq, p) \
- ((rq)->curr == (p) || spin_is_locked(&(p)->switch_lock))
-
/* See what happens when you design the chip correctly?
*
* We tell gcc we clobber all non-fixed-usage registers except
diff --git a/include/asm-sparc64/termios.h b/include/asm-sparc64/termios.h
index 8effce0da087..9777a9cca88a 100644
--- a/include/asm-sparc64/termios.h
+++ b/include/asm-sparc64/termios.h
@@ -100,16 +100,17 @@ struct winsize {
#define user_termio_to_kernel_termios(termios, termio) \
({ \
unsigned short tmp; \
- get_user(tmp, &(termio)->c_iflag); \
+ int err; \
+ err = get_user(tmp, &(termio)->c_iflag); \
(termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \
- get_user(tmp, &(termio)->c_oflag); \
+ err |= get_user(tmp, &(termio)->c_oflag); \
(termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \
- get_user(tmp, &(termio)->c_cflag); \
+ err |= get_user(tmp, &(termio)->c_cflag); \
(termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \
- get_user(tmp, &(termio)->c_lflag); \
+ err |= get_user(tmp, &(termio)->c_lflag); \
(termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \
- copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
- 0; \
+ err |= copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+ err; \
})
/*
@@ -119,53 +120,56 @@ struct winsize {
*/
#define kernel_termios_to_user_termio(termio, termios) \
({ \
- put_user((termios)->c_iflag, &(termio)->c_iflag); \
- put_user((termios)->c_oflag, &(termio)->c_oflag); \
- put_user((termios)->c_cflag, &(termio)->c_cflag); \
- put_user((termios)->c_lflag, &(termio)->c_lflag); \
- put_user((termios)->c_line, &(termio)->c_line); \
- copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+ int err; \
+ err = put_user((termios)->c_iflag, &(termio)->c_iflag); \
+ err |= put_user((termios)->c_oflag, &(termio)->c_oflag); \
+ err |= put_user((termios)->c_cflag, &(termio)->c_cflag); \
+ err |= put_user((termios)->c_lflag, &(termio)->c_lflag); \
+ err |= put_user((termios)->c_line, &(termio)->c_line); \
+ err |= copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
if (!((termios)->c_lflag & ICANON)) { \
- put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
- put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
+ err |= put_user((termios)->c_cc[VMIN], &(termio)->c_cc[_VMIN]); \
+ err |= put_user((termios)->c_cc[VTIME], &(termio)->c_cc[_VTIME]); \
} \
- 0; \
+ err; \
})
#define user_termios_to_kernel_termios(k, u) \
({ \
- get_user((k)->c_iflag, &(u)->c_iflag); \
- get_user((k)->c_oflag, &(u)->c_oflag); \
- get_user((k)->c_cflag, &(u)->c_cflag); \
- get_user((k)->c_lflag, &(u)->c_lflag); \
- get_user((k)->c_line, &(u)->c_line); \
- copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \
+ int err; \
+ err = get_user((k)->c_iflag, &(u)->c_iflag); \
+ err |= get_user((k)->c_oflag, &(u)->c_oflag); \
+ err |= get_user((k)->c_cflag, &(u)->c_cflag); \
+ err |= get_user((k)->c_lflag, &(u)->c_lflag); \
+ err |= get_user((k)->c_line, &(u)->c_line); \
+ err |= copy_from_user((k)->c_cc, (u)->c_cc, NCCS); \
if((k)->c_lflag & ICANON) { \
- get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
- get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
+ err |= get_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
+ err |= get_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
} else { \
- get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \
- get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
+ err |= get_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \
+ err |= get_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
} \
- 0; \
+ err; \
})
#define kernel_termios_to_user_termios(u, k) \
({ \
- put_user((k)->c_iflag, &(u)->c_iflag); \
- put_user((k)->c_oflag, &(u)->c_oflag); \
- put_user((k)->c_cflag, &(u)->c_cflag); \
- put_user((k)->c_lflag, &(u)->c_lflag); \
- put_user((k)->c_line, &(u)->c_line); \
- copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \
+ int err; \
+ err = put_user((k)->c_iflag, &(u)->c_iflag); \
+ err |= put_user((k)->c_oflag, &(u)->c_oflag); \
+ err |= put_user((k)->c_cflag, &(u)->c_cflag); \
+ err |= put_user((k)->c_lflag, &(u)->c_lflag); \
+ err |= put_user((k)->c_line, &(u)->c_line); \
+ err |= copy_to_user((u)->c_cc, (k)->c_cc, NCCS); \
if(!((k)->c_lflag & ICANON)) { \
- put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \
- put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
+ err |= put_user((k)->c_cc[VMIN], &(u)->c_cc[_VMIN]); \
+ err |= put_user((k)->c_cc[VTIME], &(u)->c_cc[_VTIME]); \
} else { \
- put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
- put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
+ err |= put_user((k)->c_cc[VEOF], &(u)->c_cc[VEOF]); \
+ err |= put_user((k)->c_cc[VEOL], &(u)->c_cc[VEOL]); \
} \
- 0; \
+ err; \
})
#endif /* __KERNEL__ */
diff --git a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h
index 0cd652956929..a1d25c06f92a 100644
--- a/include/asm-sparc64/thread_info.h
+++ b/include/asm-sparc64/thread_info.h
@@ -220,8 +220,8 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define TIF_NEWSIGNALS 6 /* wants new-style signals */
#define TIF_32BIT 7 /* 32-bit binary */
#define TIF_NEWCHILD 8 /* just-spawned child process */
-/* TIF_* value 9 is available */
-#define TIF_POLLING_NRFLAG 10
+#define TIF_SECCOMP 9 /* secure computing */
+#define TIF_SYSCALL_AUDIT 10 /* syscall auditing active */
#define TIF_SYSCALL_SUCCESS 11
/* NOTE: Thread flags >= 12 should be ones we have no interest
* in using in assembly, else we can't use the mask as
@@ -229,6 +229,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
*/
#define TIF_ABI_PENDING 12
#define TIF_MEMDIE 13
+#define TIF_POLLING_NRFLAG 14
#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
@@ -239,9 +240,11 @@ register struct thread_info *current_thread_info_reg asm("g6");
#define _TIF_NEWSIGNALS (1<<TIF_NEWSIGNALS)
#define _TIF_32BIT (1<<TIF_32BIT)
#define _TIF_NEWCHILD (1<<TIF_NEWCHILD)
-#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
-#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
+#define _TIF_SECCOMP (1<<TIF_SECCOMP)
+#define _TIF_SYSCALL_AUDIT (1<<TIF_SYSCALL_AUDIT)
#define _TIF_SYSCALL_SUCCESS (1<<TIF_SYSCALL_SUCCESS)
+#define _TIF_ABI_PENDING (1<<TIF_ABI_PENDING)
+#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
#define _TIF_USER_WORK_MASK ((0xff << TI_FLAG_WSAVED_SHIFT) | \
(_TIF_NOTIFY_RESUME | _TIF_SIGPENDING | \
diff --git a/include/asm-sparc64/unistd.h b/include/asm-sparc64/unistd.h
index 5b8dcf5786a5..f59144c6b76a 100644
--- a/include/asm-sparc64/unistd.h
+++ b/include/asm-sparc64/unistd.h
@@ -212,7 +212,7 @@
#define __NR_epoll_create 193 /* Linux Specific */
#define __NR_epoll_ctl 194 /* Linux Specific */
#define __NR_epoll_wait 195 /* Linux Specific */
-/* #define __NR_ulimit 196 Linux Specific */
+#define __NR_ioprio_set 196 /* Linux Specific */
#define __NR_getppid 197 /* Linux Specific */
#define __NR_sigaction 198 /* Linux Specific */
#define __NR_sgetmask 199 /* Linux Specific */
@@ -234,7 +234,7 @@
#define __NR_ipc 215 /* Linux Specific */
#define __NR_sigreturn 216 /* Linux Specific */
#define __NR_clone 217 /* Linux Specific */
-/* #define __NR_modify_ldt 218 Linux Specific - i386 specific, unused */
+#define __NR_ioprio_get 218 /* Linux Specific */
#define __NR_adjtimex 219 /* Linux Specific */
#define __NR_sigprocmask 220 /* Linux Specific */
#define __NR_create_module 221 /* Linux Specific */
diff --git a/include/asm-um/mmu_context.h b/include/asm-um/mmu_context.h
index 89bff310b7a9..095bb627b96a 100644
--- a/include/asm-um/mmu_context.h
+++ b/include/asm-um/mmu_context.h
@@ -7,19 +7,23 @@
#define __UM_MMU_CONTEXT_H
#include "linux/sched.h"
+#include "linux/config.h"
#include "choose-mode.h"
+#include "um_mmu.h"
#define get_mmu_context(task) do ; while(0)
#define activate_context(tsk) do ; while(0)
#define deactivate_mm(tsk,mm) do { } while (0)
+extern void force_flush_all(void);
+
static inline void activate_mm(struct mm_struct *old, struct mm_struct *new)
{
+ if (old != new)
+ force_flush_all();
}
-extern void switch_mm_skas(int mm_fd);
-
static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
struct task_struct *tsk)
{
@@ -30,7 +34,7 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
cpu_set(cpu, next->cpu_vm_mask);
if(next != &init_mm)
CHOOSE_MODE((void) 0,
- switch_mm_skas(next->context.skas.mm_fd));
+ switch_mm_skas(&next->context.skas.id));
}
}
diff --git a/include/asm-um/ptrace-i386.h b/include/asm-um/ptrace-i386.h
index 04222f35c43e..fe882b9d917e 100644
--- a/include/asm-um/ptrace-i386.h
+++ b/include/asm-um/ptrace-i386.h
@@ -32,6 +32,10 @@
#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r)
#define PT_FIX_EXEC_STACK(sp) do ; while(0)
+/* Cope with a conditional i386 definition. */
+#undef profile_pc
+#define profile_pc(regs) PT_REGS_IP(regs)
+
#define user_mode(r) UPT_IS_USER(&(r)->regs)
#endif
diff --git a/include/asm-v850/checksum.h b/include/asm-v850/checksum.h
index d3aedb7bfc5c..4df5e71098f9 100644
--- a/include/asm-v850/checksum.h
+++ b/include/asm-v850/checksum.h
@@ -1,8 +1,8 @@
/*
* include/asm-v850/checksum.h -- Checksum ops
*
- * Copyright (C) 2001 NEC Corporation
- * Copyright (C) 2001 Miles Bader <miles@gnu.org>
+ * Copyright (C) 2001,2005 NEC Corporation
+ * Copyright (C) 2001,2005 Miles Bader <miles@gnu.org>
*
* 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
@@ -36,8 +36,8 @@ extern unsigned int csum_partial (const unsigned char * buff, int len,
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*/
-extern unsigned csum_partial_copy (const char *src, char *dst, int len,
- unsigned sum);
+extern unsigned csum_partial_copy (const unsigned char *src,
+ unsigned char *dst, int len, unsigned sum);
/*
@@ -46,7 +46,8 @@ extern unsigned csum_partial_copy (const char *src, char *dst, int len,
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
*/
-extern unsigned csum_partial_copy_from_user (const char *src, char *dst,
+extern unsigned csum_partial_copy_from_user (const unsigned char *src,
+ unsigned char *dst,
int len, unsigned sum,
int *csum_err);
diff --git a/include/asm-v850/mmu.h b/include/asm-v850/mmu.h
index e30a52becfd6..267768c66ef6 100644
--- a/include/asm-v850/mmu.h
+++ b/include/asm-v850/mmu.h
@@ -1,22 +1,11 @@
-/* Copyright (C) 2002, David McCullough <davidm@snapgear.com> */
+/* Copyright (C) 2002, 2005, David McCullough <davidm@snapgear.com> */
#ifndef __V850_MMU_H__
#define __V850_MMU_H__
-struct mm_rblock_struct {
- int size;
- int refcount;
- void *kblock;
-};
-
-struct mm_tblock_struct {
- struct mm_rblock_struct *rblock;
- struct mm_tblock_struct *next;
-};
-
typedef struct {
- struct mm_tblock_struct tblock;
- unsigned long end_brk;
+ struct vm_list_struct *vmlist;
+ unsigned long end_brk;
} mm_context_t;
#endif /* __V850_MMU_H__ */
diff --git a/include/asm-v850/pci.h b/include/asm-v850/pci.h
index e41941447b49..8e79be0fe99d 100644
--- a/include/asm-v850/pci.h
+++ b/include/asm-v850/pci.h
@@ -81,6 +81,16 @@ extern void
pci_free_consistent (struct pci_dev *pdev, size_t size, void *cpu_addr,
dma_addr_t dma_addr);
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
static inline void pcibios_add_platform_entries(struct pci_dev *dev)
{
}
diff --git a/include/asm-x86_64/acpi.h b/include/asm-x86_64/acpi.h
index a6b41b892062..dc8c981af27f 100644
--- a/include/asm-x86_64/acpi.h
+++ b/include/asm-x86_64/acpi.h
@@ -28,6 +28,8 @@
#ifdef __KERNEL__
+#include <acpi/pdc_intel.h>
+
#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
@@ -99,12 +101,6 @@ __acpi_release_global_lock (unsigned int *lock)
:"=r"(n_hi), "=r"(n_lo) \
:"0"(n_hi), "1"(n_lo))
-/*
- * Refer Intel ACPI _PDC support document for bit definitions
- */
-#define ACPI_PDC_EST_CAPABILITY_SMP 0xa
-#define ACPI_PDC_EST_CAPABILITY_MSR 0x1
-
#ifdef CONFIG_ACPI_BOOT
extern int acpi_lapic;
extern int acpi_ioapic;
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h
index e4b1017b8b2b..16ec82e16b21 100644
--- a/include/asm-x86_64/apic.h
+++ b/include/asm-x86_64/apic.h
@@ -77,7 +77,7 @@ static inline void ack_APIC_irq(void)
extern int get_maxlvt (void);
extern void clear_local_APIC (void);
extern void connect_bsp_APIC (void);
-extern void disconnect_bsp_APIC (void);
+extern void disconnect_bsp_APIC (int virt_wire_setup);
extern void disable_local_APIC (void);
extern int verify_local_APIC (void);
extern void cache_APIC_registers (void);
diff --git a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h
index bfebdb690654..9388062c4f6e 100644
--- a/include/asm-x86_64/apicdef.h
+++ b/include/asm-x86_64/apicdef.h
@@ -94,7 +94,7 @@
#define SET_APIC_DELIVERY_MODE(x,y) (((x)&~0x700)|((y)<<8))
#define APIC_MODE_FIXED 0x0
#define APIC_MODE_NMI 0x4
-#define APIC_MODE_EXINT 0x7
+#define APIC_MODE_EXTINT 0x7
#define APIC_LVT1 0x360
#define APIC_LVTERR 0x370
#define APIC_TMICT 0x380
diff --git a/include/asm-x86_64/io_apic.h b/include/asm-x86_64/io_apic.h
index 32573749004c..a8babd2bbe84 100644
--- a/include/asm-x86_64/io_apic.h
+++ b/include/asm-x86_64/io_apic.h
@@ -217,4 +217,6 @@ extern int assign_irq_vector(int irq);
void enable_NMI_through_LVT0 (void * dummy);
+extern spinlock_t i8259A_lock;
+
#endif
diff --git a/include/asm-x86_64/irq.h b/include/asm-x86_64/irq.h
index 3af50b3c3b05..eb3b7aa9eb9f 100644
--- a/include/asm-x86_64/irq.h
+++ b/include/asm-x86_64/irq.h
@@ -52,4 +52,9 @@ struct irqaction;
struct pt_regs;
int handle_IRQ_event(unsigned int, struct pt_regs *, struct irqaction *);
+#ifdef CONFIG_HOTPLUG_CPU
+#include <linux/cpumask.h>
+extern void fixup_irqs(cpumask_t map);
+#endif
+
#endif /* _ASM_IRQ_H */
diff --git a/include/asm-x86_64/kdebug.h b/include/asm-x86_64/kdebug.h
index 6277f75cbb4b..b90341994d80 100644
--- a/include/asm-x86_64/kdebug.h
+++ b/include/asm-x86_64/kdebug.h
@@ -14,7 +14,7 @@ struct die_args {
};
/* Note - you should never unregister because that can race with NMIs.
- If you really want to do it first unregister - then synchronize_kernel - then free.
+ If you really want to do it first unregister - then synchronize_sched - then free.
*/
int register_die_notifier(struct notifier_block *nb);
extern struct notifier_block *die_chain;
diff --git a/include/asm-x86_64/kexec.h b/include/asm-x86_64/kexec.h
new file mode 100644
index 000000000000..42d2ff15c592
--- /dev/null
+++ b/include/asm-x86_64/kexec.h
@@ -0,0 +1,33 @@
+#ifndef _X86_64_KEXEC_H
+#define _X86_64_KEXEC_H
+
+#include <asm/page.h>
+#include <asm/proto.h>
+
+/*
+ * KEXEC_SOURCE_MEMORY_LIMIT maximum page get_free_page can return.
+ * I.e. Maximum page that is mapped directly into kernel memory,
+ * and kmap is not required.
+ *
+ * So far x86_64 is limited to 40 physical address bits.
+ */
+
+/* Maximum physical address we can use pages from */
+#define KEXEC_SOURCE_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+/* Maximum address we can reach in physical address mode */
+#define KEXEC_DESTINATION_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+/* Maximum address we can use for the control pages */
+#define KEXEC_CONTROL_MEMORY_LIMIT (0xFFFFFFFFFFUL)
+
+/* Allocate one page for the pdp and the second for the code */
+#define KEXEC_CONTROL_CODE_SIZE (4096UL + 4096UL)
+
+/* The native architecture */
+#define KEXEC_ARCH KEXEC_ARCH_X86_64
+
+#define MAX_NOTE_BYTES 1024
+typedef u32 note_buf_t[MAX_NOTE_BYTES/4];
+
+extern note_buf_t crash_notes[];
+
+#endif /* _X86_64_KEXEC_H */
diff --git a/include/asm-x86_64/page.h b/include/asm-x86_64/page.h
index 60130f4ca986..431318764af6 100644
--- a/include/asm-x86_64/page.h
+++ b/include/asm-x86_64/page.h
@@ -64,12 +64,14 @@ typedef struct { unsigned long pgprot; } pgprot_t;
#define __pgd(x) ((pgd_t) { (x) } )
#define __pgprot(x) ((pgprot_t) { (x) } )
-#define __START_KERNEL 0xffffffff80100000UL
+#define __PHYSICAL_START ((unsigned long)CONFIG_PHYSICAL_START)
+#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
#define __START_KERNEL_map 0xffffffff80000000UL
#define __PAGE_OFFSET 0xffff810000000000UL
#else
-#define __START_KERNEL 0xffffffff80100000
+#define __PHYSICAL_START CONFIG_PHYSICAL_START
+#define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START)
#define __START_KERNEL_map 0xffffffff80000000
#define __PAGE_OFFSET 0xffff810000000000
#endif /* !__ASSEMBLY__ */
diff --git a/include/asm-x86_64/pci.h b/include/asm-x86_64/pci.h
index 8712520ca47f..eeb3088a1c9e 100644
--- a/include/asm-x86_64/pci.h
+++ b/include/asm-x86_64/pci.h
@@ -33,7 +33,7 @@ extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int le
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
void pcibios_set_master(struct pci_dev *dev);
-void pcibios_penalize_isa_irq(int irq);
+void pcibios_penalize_isa_irq(int irq, int active);
struct irq_routing_table *pcibios_get_irq_routing_table(void);
int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq);
@@ -123,6 +123,16 @@ pci_dac_dma_sync_single_for_device(struct pci_dev *pdev, dma64_addr_t dma_addr,
flush_write_buffers();
}
+#ifdef CONFIG_PCI
+static inline void pci_dma_burst_advice(struct pci_dev *pdev,
+ enum pci_dma_burst_strategy *strat,
+ unsigned long *strategy_parameter)
+{
+ *strat = PCI_DMA_BURST_INFINITY;
+ *strategy_parameter = ~0UL;
+}
+#endif
+
#define HAVE_PCI_MMAP
extern int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
enum pci_mmap_state mmap_state, int write_combine);
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h
index f2f073642d62..6c813eb521f3 100644
--- a/include/asm-x86_64/proto.h
+++ b/include/asm-x86_64/proto.h
@@ -15,6 +15,13 @@ extern void pda_init(int);
extern void early_idt_handler(void);
extern void mcheck_init(struct cpuinfo_x86 *c);
+#ifdef CONFIG_MTRR
+extern void mtrr_ap_init(void);
+extern void mtrr_bp_init(void);
+#else
+#define mtrr_ap_init() do {} while (0)
+#define mtrr_bp_init() do {} while (0)
+#endif
extern void init_memory_mapping(unsigned long start, unsigned long end);
extern void system_call(void);
diff --git a/include/asm-x86_64/serial.h b/include/asm-x86_64/serial.h
index dbab232044cd..dc752eafa681 100644
--- a/include/asm-x86_64/serial.h
+++ b/include/asm-x86_64/serial.h
@@ -22,109 +22,9 @@
#define STD_COM4_FLAGS ASYNC_BOOT_AUTOCONF
#endif
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define FOURPORT_FLAGS ASYNC_FOURPORT
-#define ACCENT_FLAGS 0
-#define BOCA_FLAGS 0
-#define HUB6_FLAGS 0
-#endif
-
-#define MCA_COM_FLAGS (STD_COM_FLAGS|ASYNC_BOOT_ONLYMCA)
-
-/*
- * The following define the access methods for the HUB6 card. All
- * access is through two ports for all 24 possible chips. The card is
- * selected through the high 2 bits, the port on that card with the
- * "middle" 3 bits, and the register on that port with the bottom
- * 3 bits.
- *
- * While the access port and interrupt is configurable, the default
- * port locations are 0x302 for the port control register, and 0x303
- * for the data read/write register. Normally, the interrupt is at irq3
- * but can be anything from 3 to 7 inclusive. Note that using 3 will
- * require disabling com2.
- */
-
-#define C_P(card,port) (((card)<<6|(port)<<3) + 1)
-
-#define STD_SERIAL_PORT_DEFNS \
+#define SERIAL_PORT_DFNS \
/* UART CLK PORT IRQ FLAGS */ \
{ 0, BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ \
{ 0, BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ \
{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ \
{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */
-
-
-#ifdef CONFIG_SERIAL_MANY_PORTS
-#define EXTRA_SERIAL_PORT_DEFNS \
- { 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ \
- { 0, BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ \
- { 0, BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ \
- { 0, BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ \
- { 0, BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ \
- { 0, BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ \
- { 0, BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ \
- { 0, BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ \
- { 0, BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ \
- { 0, BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare) */ \
- { 0, BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare) */ \
- { 0, BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ \
- { 0, BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ \
- { 0, BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ \
- { 0, BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ \
- { 0, BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ \
- { 0, BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ \
- { 0, BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ \
- { 0, BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ \
- { 0, BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ \
- { 0, BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ \
- { 0, BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ \
- { 0, BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ \
- { 0, BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ \
- { 0, BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ \
- { 0, BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ \
- { 0, BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */
-#else
-#define EXTRA_SERIAL_PORT_DEFNS
-#endif
-
-/* You can have up to four HUB6's in the system, but I've only
- * included two cards here for a total of twelve ports.
- */
-#if (defined(CONFIG_HUB6) && defined(CONFIG_SERIAL_MANY_PORTS))
-#define HUB6_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS38 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS39 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS40 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS41 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS42 */ \
- { 0, BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS43 */
-#else
-#define HUB6_SERIAL_PORT_DFNS
-#endif
-
-#ifdef CONFIG_MCA
-#define MCA_SERIAL_PORT_DFNS \
- { 0, BASE_BAUD, 0x3220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x3228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x4228, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5220, 3, MCA_COM_FLAGS }, \
- { 0, BASE_BAUD, 0x5228, 3, MCA_COM_FLAGS },
-#else
-#define MCA_SERIAL_PORT_DFNS
-#endif
-
-#define SERIAL_PORT_DFNS \
- STD_SERIAL_PORT_DEFNS \
- EXTRA_SERIAL_PORT_DEFNS \
- HUB6_SERIAL_PORT_DFNS \
- MCA_SERIAL_PORT_DFNS
-
diff --git a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h
index a7425aa5a3b7..aeb1b73e21e1 100644
--- a/include/asm-x86_64/smp.h
+++ b/include/asm-x86_64/smp.h
@@ -43,6 +43,8 @@ extern cpumask_t cpu_callout_map;
extern void smp_alloc_memory(void);
extern volatile unsigned long smp_invalidate_needed;
extern int pic_mode;
+extern void lock_ipi_call_lock(void);
+extern void unlock_ipi_call_lock(void);
extern int smp_num_siblings;
extern void smp_flush_tlb(void);
extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs);
@@ -77,6 +79,8 @@ extern __inline int hard_smp_processor_id(void)
}
extern int safe_smp_processor_id(void);
+extern int __cpu_disable(void);
+extern void __cpu_die(unsigned int cpu);
#endif /* !ASSEMBLY */
diff --git a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h
index ec745807feae..bb9f40597d09 100644
--- a/include/asm-x86_64/suspend.h
+++ b/include/asm-x86_64/suspend.h
@@ -16,7 +16,7 @@ arch_prepare_suspend(void)
struct saved_context {
u16 ds, es, fs, gs, ss;
unsigned long gs_base, gs_kernel_base, fs_base;
- unsigned long cr0, cr2, cr3, cr4;
+ unsigned long cr0, cr2, cr3, cr4, cr8;
u16 gdt_pad;
u16 gdt_limit;
unsigned long gdt_base;
diff --git a/include/asm-x86_64/tlbflush.h b/include/asm-x86_64/tlbflush.h
index 2e811ac262af..061742382520 100644
--- a/include/asm-x86_64/tlbflush.h
+++ b/include/asm-x86_64/tlbflush.h
@@ -22,16 +22,18 @@
*/
#define __flush_tlb_global() \
do { \
- unsigned long tmpreg; \
+ unsigned long tmpreg, cr4, cr4_orig; \
\
__asm__ __volatile__( \
- "movq %1, %%cr4; # turn off PGE \n" \
+ "movq %%cr4, %2; # turn off PGE \n" \
+ "movq %2, %1; \n" \
+ "andq %3, %1; \n" \
+ "movq %1, %%cr4; \n" \
"movq %%cr3, %0; # flush TLB \n" \
"movq %0, %%cr3; \n" \
"movq %2, %%cr4; # turn PGE back on \n" \
- : "=&r" (tmpreg) \
- : "r" (mmu_cr4_features & ~X86_CR4_PGE), \
- "r" (mmu_cr4_features) \
+ : "=&r" (tmpreg), "=&r" (cr4), "=&r" (cr4_orig) \
+ : "i" (~X86_CR4_PGE) \
: "memory"); \
} while (0)
diff --git a/include/asm-x86_64/topology.h b/include/asm-x86_64/topology.h
index 8f77e9f6bc23..c1bc3fad482e 100644
--- a/include/asm-x86_64/topology.h
+++ b/include/asm-x86_64/topology.h
@@ -39,12 +39,16 @@ extern int __node_distance(int, int);
.busy_factor = 32, \
.imbalance_pct = 125, \
.cache_hot_time = (10*1000000), \
- .cache_nice_tries = 1, \
+ .cache_nice_tries = 2, \
+ .busy_idx = 3, \
+ .idle_idx = 2, \
+ .newidle_idx = 0, \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
.per_cpu_gain = 100, \
.flags = SD_LOAD_BALANCE \
- | SD_BALANCE_NEWIDLE \
+ | SD_BALANCE_FORK \
| SD_BALANCE_EXEC \
- | SD_WAKE_IDLE \
| SD_WAKE_BALANCE, \
.last_balance = jiffies, \
.balance_interval = 1, \
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h
index 3c9af6fd4332..6560439a83e4 100644
--- a/include/asm-x86_64/unistd.h
+++ b/include/asm-x86_64/unistd.h
@@ -552,7 +552,7 @@ __SYSCALL(__NR_mq_notify, sys_mq_notify)
#define __NR_mq_getsetattr 245
__SYSCALL(__NR_mq_getsetattr, sys_mq_getsetattr)
#define __NR_kexec_load 246
-__SYSCALL(__NR_kexec_load, sys_ni_syscall)
+__SYSCALL(__NR_kexec_load, sys_kexec_load)
#define __NR_waitid 247
__SYSCALL(__NR_waitid, sys_waitid)
#define __NR_add_key 248
@@ -561,8 +561,12 @@ __SYSCALL(__NR_add_key, sys_add_key)
__SYSCALL(__NR_request_key, sys_request_key)
#define __NR_keyctl 250
__SYSCALL(__NR_keyctl, sys_keyctl)
+#define __NR_ioprio_set 251
+__SYSCALL(__NR_ioprio_set, sys_ioprio_set)
+#define __NR_ioprio_get 252
+__SYSCALL(__NR_ioprio_get, sys_ioprio_get)
-#define __NR_syscall_max __NR_keyctl
+#define __NR_syscall_max __NR_ioprio_get
#ifndef __NO_STUBS
/* user-visible error numbers are in the range -1 - -4095 */
diff --git a/include/asm-xtensa/a.out.h b/include/asm-xtensa/a.out.h
new file mode 100644
index 000000000000..3be701dfe098
--- /dev/null
+++ b/include/asm-xtensa/a.out.h
@@ -0,0 +1,33 @@
+/*
+ * include/asm-xtensa/addrspace.h
+ *
+ * Dummy a.out file. Xtensa does not support the a.out format, but the kernel
+ * seems to depend on it.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_A_OUT_H
+#define _XTENSA_A_OUT_H
+
+/* Note: the kernel needs the a.out definitions, even if only ELF is used. */
+
+#define STACK_TOP TASK_SIZE
+
+struct exec
+{
+ unsigned long a_info;
+ unsigned a_text;
+ unsigned a_data;
+ unsigned a_bss;
+ unsigned a_syms;
+ unsigned a_entry;
+ unsigned a_trsize;
+ unsigned a_drsize;
+};
+
+#endif /* _XTENSA_A_OUT_H */
diff --git a/include/asm-xtensa/atomic.h b/include/asm-xtensa/atomic.h
new file mode 100644
index 000000000000..d72bcb32ba4f
--- /dev/null
+++ b/include/asm-xtensa/atomic.h
@@ -0,0 +1,272 @@
+/*
+ * include/asm-xtensa/atomic.h
+ *
+ * Atomic operations that C can't guarantee us. Useful for resource counting..
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ATOMIC_H
+#define _XTENSA_ATOMIC_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+typedef struct { volatile int counter; } atomic_t;
+
+#ifdef __KERNEL__
+#include <asm/processor.h>
+#include <asm/system.h>
+
+#define ATOMIC_INIT(i) ( (atomic_t) { (i) } )
+
+/*
+ * This Xtensa implementation assumes that the right mechanism
+ * for exclusion is for locking interrupts to level 1.
+ *
+ * Locking interrupts looks like this:
+ *
+ * rsil a15, 1
+ * <code>
+ * wsr a15, PS
+ * rsync
+ *
+ * Note that a15 is used here because the register allocation
+ * done by the compiler is not guaranteed and a window overflow
+ * may not occur between the rsil and wsr instructions. By using
+ * a15 in the rsil, the machine is guaranteed to be in a state
+ * where no register reference will cause an overflow.
+ */
+
+/**
+ * atomic_read - read atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically reads the value of @v.
+ */
+#define atomic_read(v) ((v)->counter)
+
+/**
+ * atomic_set - set atomic variable
+ * @v: pointer of type atomic_t
+ * @i: required value
+ *
+ * Atomically sets the value of @v to @i.
+ */
+#define atomic_set(v,i) ((v)->counter = (i))
+
+/**
+ * atomic_add - add integer to atomic variable
+ * @i: integer value to add
+ * @v: pointer of type atomic_t
+ *
+ * Atomically adds @i to @v.
+ */
+extern __inline__ void atomic_add(int i, atomic_t * v)
+{
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15, "__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "add %0, %0, %1 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval)
+ : "a" (i), "a" (v)
+ : "a15", "memory"
+ );
+}
+
+/**
+ * atomic_sub - subtract the atomic variable
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v.
+ */
+extern __inline__ void atomic_sub(int i, atomic_t *v)
+{
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15, "__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "sub %0, %0, %1 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval)
+ : "a" (i), "a" (v)
+ : "a15", "memory"
+ );
+}
+
+/*
+ * We use atomic_{add|sub}_return to define other functions.
+ */
+
+extern __inline__ int atomic_add_return(int i, atomic_t * v)
+{
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15,"__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "add %0, %0, %1 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval)
+ : "a" (i), "a" (v)
+ : "a15", "memory"
+ );
+
+ return vval;
+}
+
+extern __inline__ int atomic_sub_return(int i, atomic_t * v)
+{
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15,"__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "sub %0, %0, %1 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval)
+ : "a" (i), "a" (v)
+ : "a15", "memory"
+ );
+
+ return vval;
+}
+
+/**
+ * atomic_sub_and_test - subtract value from variable and test result
+ * @i: integer value to subtract
+ * @v: pointer of type atomic_t
+ *
+ * Atomically subtracts @i from @v and returns
+ * true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_sub_and_test(i,v) (atomic_sub_return((i),(v)) == 0)
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc(v) atomic_add(1,(v))
+
+/**
+ * atomic_inc - increment atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1.
+ */
+#define atomic_inc_return(v) atomic_add_return(1,(v))
+
+/**
+ * atomic_dec - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec(v) atomic_sub(1,(v))
+
+/**
+ * atomic_dec_return - decrement atomic variable
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1.
+ */
+#define atomic_dec_return(v) atomic_sub_return(1,(v))
+
+/**
+ * atomic_dec_and_test - decrement and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically decrements @v by 1 and
+ * returns true if the result is 0, or false for all other
+ * cases.
+ */
+#define atomic_dec_and_test(v) (atomic_sub_return(1,(v)) == 0)
+
+/**
+ * atomic_inc_and_test - increment and test
+ * @v: pointer of type atomic_t
+ *
+ * Atomically increments @v by 1
+ * and returns true if the result is zero, or false for all
+ * other cases.
+ */
+#define atomic_inc_and_test(v) (atomic_add_return(1,(v)) == 0)
+
+/**
+ * atomic_add_negative - add and test if negative
+ * @v: pointer of type atomic_t
+ * @i: integer value to add
+ *
+ * Atomically adds @i to @v and returns true
+ * if the result is negative, or false when
+ * result is greater than or equal to zero.
+ */
+#define atomic_add_negative(i,v) (atomic_add_return((i),(v)) < 0)
+
+
+extern __inline__ void atomic_clear_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned int all_f = -1;
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15,"__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "xor %1, %4, %3 \n\t"
+ "and %0, %0, %4 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval), "=a" (mask)
+ : "a" (v), "a" (all_f), "1" (mask)
+ : "a15", "memory"
+ );
+}
+
+extern __inline__ void atomic_set_mask(unsigned int mask, atomic_t *v)
+{
+ unsigned int vval;
+
+ __asm__ __volatile__(
+ "rsil a15,"__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %2, 0 \n\t"
+ "or %0, %0, %1 \n\t"
+ "s32i %0, %2, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n"
+ : "=&a" (vval)
+ : "a" (mask), "a" (v)
+ : "a15", "memory"
+ );
+}
+
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_ATOMIC_H */
+
diff --git a/include/asm-xtensa/bitops.h b/include/asm-xtensa/bitops.h
new file mode 100644
index 000000000000..d395ef226c32
--- /dev/null
+++ b/include/asm-xtensa/bitops.h
@@ -0,0 +1,446 @@
+/*
+ * include/asm-xtensa/bitops.h
+ *
+ * Atomic operations that C can't guarantee us.Useful for resource counting etc.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BITOPS_H
+#define _XTENSA_BITOPS_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <asm/byteorder.h>
+#include <asm/system.h>
+
+#ifdef CONFIG_SMP
+# error SMP not supported on this architecture
+#endif
+
+static __inline__ void set_bit(int nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *a |= mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __set_bit(int nr, volatile unsigned long * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+ *a |= mask;
+}
+
+static __inline__ void clear_bit(int nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *a &= ~mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+ *a &= ~mask;
+}
+
+/*
+ * clear_bit() doesn't provide any barrier for the compiler.
+ */
+
+#define smp_mb__before_clear_bit() barrier()
+#define smp_mb__after_clear_bit() barrier()
+
+static __inline__ void change_bit(int nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ *a ^= mask;
+ local_irq_restore(flags);
+}
+
+static __inline__ void __change_bit(int nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+ *a ^= mask;
+}
+
+static __inline__ int test_and_set_bit(int nr, volatile void * addr)
+{
+ unsigned long retval;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = (mask & *a) != 0;
+ *a |= mask;
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+static __inline__ int __test_and_set_bit(int nr, volatile void * addr)
+{
+ unsigned long retval;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+
+ retval = (mask & *a) != 0;
+ *a |= mask;
+
+ return retval;
+}
+
+static __inline__ int test_and_clear_bit(int nr, volatile void * addr)
+{
+ unsigned long retval;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+ retval = (mask & *a) != 0;
+ *a &= ~mask;
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+static __inline__ int __test_and_clear_bit(int nr, volatile void * addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long old = *a;
+
+ *a = old & ~mask;
+ return (old & mask) != 0;
+}
+
+static __inline__ int test_and_change_bit(int nr, volatile void * addr)
+{
+ unsigned long retval;
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ retval = (mask & *a) != 0;
+ *a ^= mask;
+ local_irq_restore(flags);
+
+ return retval;
+}
+
+/*
+ * non-atomic version; can be reordered
+ */
+
+static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
+{
+ unsigned long mask = 1 << (nr & 0x1f);
+ unsigned long *a = ((unsigned long *)addr) + (nr >> 5);
+ unsigned long old = *a;
+
+ *a = old ^ mask;
+ return (old & mask) != 0;
+}
+
+static __inline__ int test_bit(int nr, const volatile void *addr)
+{
+ return 1UL & (((const volatile unsigned int *)addr)[nr>>5] >> (nr&31));
+}
+
+#if XCHAL_HAVE_NSAU
+
+static __inline__ int __cntlz (unsigned long x)
+{
+ int lz;
+ asm ("nsau %0, %1" : "=r" (lz) : "r" (x));
+ return 31 - lz;
+}
+
+#else
+
+static __inline__ int __cntlz (unsigned long x)
+{
+ unsigned long sum, x1, x2, x4, x8, x16;
+ x1 = x & 0xAAAAAAAA;
+ x2 = x & 0xCCCCCCCC;
+ x4 = x & 0xF0F0F0F0;
+ x8 = x & 0xFF00FF00;
+ x16 = x & 0xFFFF0000;
+ sum = x2 ? 2 : 0;
+ sum += (x16 != 0) * 16;
+ sum += (x8 != 0) * 8;
+ sum += (x4 != 0) * 4;
+ sum += (x1 != 0);
+
+ return sum;
+}
+
+#endif
+
+/*
+ * ffz: Find first zero in word. Undefined if no zero exists.
+ * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1).
+ */
+
+static __inline__ int ffz(unsigned long x)
+{
+ if ((x = ~x) == 0)
+ return 32;
+ return __cntlz(x & -x);
+}
+
+/*
+ * __ffs: Find first bit set in word. Return 0 for bit 0
+ */
+
+static __inline__ int __ffs(unsigned long x)
+{
+ return __cntlz(x & -x);
+}
+
+/*
+ * ffs: Find first bit set in word. This is defined the same way as
+ * the libc and compiler builtin ffs routines, therefore
+ * differs in spirit from the above ffz (man ffs).
+ */
+
+static __inline__ int ffs(unsigned long x)
+{
+ return __cntlz(x & -x) + 1;
+}
+
+/*
+ * fls: Find last (most-significant) bit set in word.
+ * Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
+ */
+
+static __inline__ int fls (unsigned int x)
+{
+ return __cntlz(x);
+}
+
+static __inline__ int
+find_next_bit(const unsigned long *addr, int size, int offset)
+{
+ const unsigned long *p = addr + (offset >> 5);
+ unsigned long result = offset & ~31UL;
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *p++;
+ tmp &= ~0UL << offset;
+ if (size < 32)
+ goto found_first;
+ if (tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size >= 32) {
+ if ((tmp = *p++) != 0)
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp &= ~0UL >> (32 - size);
+ if (tmp == 0UL) /* Are any bits set? */
+ return result + size; /* Nope. */
+found_middle:
+ return result + __ffs(tmp);
+}
+
+/**
+ * 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.
+ */
+
+#define find_first_bit(addr, size) \
+ find_next_bit((addr), (size), 0)
+
+static __inline__ int
+find_next_zero_bit(const unsigned long *addr, int size, int offset)
+{
+ const unsigned long *p = addr + (offset >> 5);
+ unsigned long result = offset & ~31UL;
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if (offset) {
+ tmp = *p++;
+ tmp |= ~0UL >> (32-offset);
+ if (size < 32)
+ goto found_first;
+ if (~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while (size & ~31UL) {
+ if (~(tmp = *p++))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if (!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ tmp |= ~0UL << size;
+found_middle:
+ return result + ffz(tmp);
+}
+
+#define find_first_zero_bit(addr, size) \
+ find_next_zero_bit((addr), (size), 0)
+
+#ifdef __XTENSA_EL__
+# define ext2_set_bit(nr,addr) __test_and_set_bit((nr), (addr))
+# define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr),(addr))
+# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr), (addr))
+# define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr),(addr))
+# define ext2_test_bit(nr,addr) test_bit((nr), (addr))
+# define ext2_find_first_zero_bit(addr, size) find_first_zero_bit((addr),(size))
+# define ext2_find_next_zero_bit(addr, size, offset) \
+ find_next_zero_bit((addr), (size), (offset))
+#elif defined(__XTENSA_EB__)
+# define ext2_set_bit(nr,addr) __test_and_set_bit((nr) ^ 0x18, (addr))
+# define ext2_set_bit_atomic(lock,nr,addr) test_and_set_bit((nr) ^ 0x18, (addr))
+# define ext2_clear_bit(nr,addr) __test_and_clear_bit((nr) ^ 18, (addr))
+# define ext2_clear_bit_atomic(lock,nr,addr) test_and_clear_bit((nr)^0x18,(addr))
+# define ext2_test_bit(nr,addr) test_bit((nr) ^ 0x18, (addr))
+# define ext2_find_first_zero_bit(addr, size) \
+ ext2_find_next_zero_bit((addr), (size), 0)
+
+static __inline__ unsigned long ext2_find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+{
+ unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+ unsigned long result = offset & ~31UL;
+ unsigned long tmp;
+
+ if (offset >= size)
+ return size;
+ size -= result;
+ offset &= 31UL;
+ if(offset) {
+ /* We hold the little endian value in tmp, but then the
+ * shift is illegal. So we could keep a big endian value
+ * in tmp, like this:
+ *
+ * tmp = __swab32(*(p++));
+ * tmp |= ~0UL >> (32-offset);
+ *
+ * but this would decrease preformance, so we change the
+ * shift:
+ */
+ tmp = *(p++);
+ tmp |= __swab32(~0UL >> (32-offset));
+ if(size < 32)
+ goto found_first;
+ if(~tmp)
+ goto found_middle;
+ size -= 32;
+ result += 32;
+ }
+ while(size & ~31UL) {
+ if(~(tmp = *(p++)))
+ goto found_middle;
+ result += 32;
+ size -= 32;
+ }
+ if(!size)
+ return result;
+ tmp = *p;
+
+found_first:
+ /* tmp is little endian, so we would have to swab the shift,
+ * see above. But then we have to swab tmp below for ffz, so
+ * we might as well do this here.
+ */
+ return result + ffz(__swab32(tmp) | (~0UL << size));
+found_middle:
+ return result + ffz(__swab32(tmp));
+}
+
+#else
+# error processor byte order undefined!
+#endif
+
+
+#define hweight32(x) generic_hweight32(x)
+#define hweight16(x) generic_hweight16(x)
+#define hweight8(x) generic_hweight8(x)
+
+/*
+ * Find the first bit set in a 140-bit bitmap.
+ * The first 100 bits are unlikely to be set.
+ */
+
+static inline int sched_find_first_bit(const unsigned long *b)
+{
+ if (unlikely(b[0]))
+ return __ffs(b[0]);
+ if (unlikely(b[1]))
+ return __ffs(b[1]) + 32;
+ if (unlikely(b[2]))
+ return __ffs(b[2]) + 64;
+ if (b[3])
+ return __ffs(b[3]) + 96;
+ return __ffs(b[4]) + 128;
+}
+
+
+/* Bitmap functions for the minix filesystem. */
+
+#define minix_test_and_set_bit(nr,addr) test_and_set_bit(nr,addr)
+#define minix_set_bit(nr,addr) set_bit(nr,addr)
+#define minix_test_and_clear_bit(nr,addr) test_and_clear_bit(nr,addr)
+#define minix_test_bit(nr,addr) test_bit(nr,addr)
+#define minix_find_first_zero_bit(addr,size) find_first_zero_bit(addr,size)
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_BITOPS_H */
diff --git a/include/asm-xtensa/bootparam.h b/include/asm-xtensa/bootparam.h
new file mode 100644
index 000000000000..9983f2c1b7ee
--- /dev/null
+++ b/include/asm-xtensa/bootparam.h
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/bootparam.h
+ *
+ * Definition of the Linux/Xtensa boot parameter structure
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * (Concept borrowed from the 68K port)
+ */
+
+#ifndef _XTENSA_BOOTPARAM_H
+#define _XTENSA_BOOTPARAM_H
+
+#define BP_VERSION 0x0001
+
+#define BP_TAG_COMMAND_LINE 0x1001 /* command line (0-terminated string)*/
+#define BP_TAG_INITRD 0x1002 /* ramdisk addr and size (bp_meminfo) */
+#define BP_TAG_MEMORY 0x1003 /* memory addr and size (bp_meminfo) */
+#define BP_TAG_SERIAL_BAUSRATE 0x1004 /* baud rate of current console. */
+#define BP_TAG_SERIAL_PORT 0x1005 /* serial device of current console */
+
+#define BP_TAG_FIRST 0x7B0B /* first tag with a version number */
+#define BP_TAG_LAST 0x7E0B /* last tag */
+
+#ifndef __ASSEMBLY__
+
+/* All records are aligned to 4 bytes */
+
+typedef struct bp_tag {
+ unsigned short id; /* tag id */
+ unsigned short size; /* size of this record excluding the structure*/
+ unsigned long data[0]; /* data */
+} bp_tag_t;
+
+typedef struct meminfo {
+ unsigned long type;
+ unsigned long start;
+ unsigned long end;
+} meminfo_t;
+
+#define SYSMEM_BANKS_MAX 5
+
+#define MEMORY_TYPE_CONVENTIONAL 0x1000
+#define MEMORY_TYPE_NONE 0x2000
+
+typedef struct sysmem_info {
+ int nr_banks;
+ meminfo_t bank[SYSMEM_BANKS_MAX];
+} sysmem_info_t;
+
+extern sysmem_info_t sysmem;
+
+#endif
+#endif
+
+
+
diff --git a/include/asm-xtensa/bug.h b/include/asm-xtensa/bug.h
new file mode 100644
index 000000000000..56703659b204
--- /dev/null
+++ b/include/asm-xtensa/bug.h
@@ -0,0 +1,41 @@
+/*
+ * include/asm-xtensa/bug.h
+ *
+ * Macros to cause a 'bug' message.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BUG_H
+#define _XTENSA_BUG_H
+
+#include <linux/stringify.h>
+
+#define ILL __asm__ __volatile__ (".byte 0,0,0\n")
+
+#ifdef CONFIG_KALLSYMS
+# define BUG() do { \
+ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \
+ ILL; \
+} while (0)
+#else
+# define BUG() do { \
+ printk("kernel BUG!\n"); \
+ ILL; \
+} while (0)
+#endif
+
+#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0)
+#define PAGE_BUG(page) do { BUG(); } while (0)
+#define WARN_ON(condition) do { \
+ if (unlikely((condition)!=0)) { \
+ printk ("Warning in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
+ dump_stack(); \
+ } \
+} while (0)
+
+#endif /* _XTENSA_BUG_H */
diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h
new file mode 100644
index 000000000000..c42285320133
--- /dev/null
+++ b/include/asm-xtensa/bugs.h
@@ -0,0 +1,22 @@
+/*
+ * include/asm-xtensa/bugs.h
+ *
+ * This is included by init/main.c to check for architecture-dependent bugs.
+ *
+ * Xtensa processors don't have any bugs. :)
+ *
+ * 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.
+ */
+
+#ifndef _XTENSA_BUGS_H
+#define _XTENSA_BUGS_H
+
+#include <asm/processor.h>
+
+static void __init check_bugs(void)
+{
+}
+
+#endif /* _XTENSA_BUGS_H */
diff --git a/include/asm-xtensa/byteorder.h b/include/asm-xtensa/byteorder.h
new file mode 100644
index 000000000000..0b1552569aae
--- /dev/null
+++ b/include/asm-xtensa/byteorder.h
@@ -0,0 +1,82 @@
+/*
+ * include/asm-xtensa/byteorder.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_BYTEORDER_H
+#define _XTENSA_BYTEORDER_H
+
+#include <asm/processor.h>
+#include <asm/types.h>
+
+static __inline__ __const__ __u32 ___arch__swab32(__u32 x)
+{
+ __u32 res;
+ /* instruction sequence from Xtensa ISA release 2/2000 */
+ __asm__("ssai 8 \n\t"
+ "srli %0, %1, 16 \n\t"
+ "src %0, %0, %1 \n\t"
+ "src %0, %0, %0 \n\t"
+ "src %0, %1, %0 \n"
+ : "=&a" (res)
+ : "a" (x)
+ );
+ return res;
+}
+
+static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
+{
+ /* Given that 'short' values are signed (i.e., can be negative),
+ * we cannot assume that the upper 16-bits of the register are
+ * zero. We are careful to mask values after shifting.
+ */
+
+ /* There exists an anomaly between xt-gcc and xt-xcc. xt-gcc
+ * inserts an extui instruction after putting this function inline
+ * to ensure that it uses only the least-significant 16 bits of
+ * the result. xt-xcc doesn't use an extui, but assumes the
+ * __asm__ macro follows convention that the upper 16 bits of an
+ * 'unsigned short' result are still zero. This macro doesn't
+ * follow convention; indeed, it leaves garbage in the upport 16
+ * bits of the register.
+
+ * Declaring the temporary variables 'res' and 'tmp' to be 32-bit
+ * types while the return type of the function is a 16-bit type
+ * forces both compilers to insert exactly one extui instruction
+ * (or equivalent) to mask off the upper 16 bits. */
+
+ __u32 res;
+ __u32 tmp;
+
+ __asm__("extui %1, %2, 8, 8\n\t"
+ "slli %0, %2, 8 \n\t"
+ "or %0, %0, %1 \n"
+ : "=&a" (res), "=&a" (tmp)
+ : "a" (x)
+ );
+
+ return res;
+}
+
+#define __arch__swab32(x) ___arch__swab32(x)
+#define __arch__swab16(x) ___arch__swab16(x)
+
+#if !defined(__STRICT_ANSI__) || defined(__KERNEL__)
+# define __BYTEORDER_HAS_U64__
+# define __SWAB_64_THRU_32__
+#endif
+
+#ifdef __XTENSA_EL__
+# include <linux/byteorder/little_endian.h>
+#elif defined(__XTENSA_EB__)
+# include <linux/byteorder/big_endian.h>
+#else
+# error processor byte order undefined!
+#endif
+
+#endif /* __ASM_XTENSA_BYTEORDER_H */
diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h
new file mode 100644
index 000000000000..5aae3f12407c
--- /dev/null
+++ b/include/asm-xtensa/cache.h
@@ -0,0 +1,32 @@
+/*
+ * include/asm-xtensa/cacheflush.h
+ *
+ * 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.
+ * 2 of the License, or (at your option) any later version.
+ *
+ * (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CACHE_H
+#define _XTENSA_CACHE_H
+
+#include <xtensa/config/core.h>
+
+#if XCHAL_ICACHE_SIZE > 0
+# if (XCHAL_ICACHE_SIZE % (XCHAL_ICACHE_LINESIZE*XCHAL_ICACHE_WAYS*4)) != 0
+# error cache configuration outside expected/supported range!
+# endif
+#endif
+
+#if XCHAL_DCACHE_SIZE > 0
+# if (XCHAL_DCACHE_SIZE % (XCHAL_DCACHE_LINESIZE*XCHAL_DCACHE_WAYS*4)) != 0
+# error cache configuration outside expected/supported range!
+# endif
+#endif
+
+#define L1_CACHE_SHIFT XCHAL_CACHE_LINEWIDTH_MAX
+#define L1_CACHE_BYTES XCHAL_CACHE_LINESIZE_MAX
+
+#endif /* _XTENSA_CACHE_H */
diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h
new file mode 100644
index 000000000000..44a36e087844
--- /dev/null
+++ b/include/asm-xtensa/cacheflush.h
@@ -0,0 +1,122 @@
+/*
+ * include/asm-xtensa/cacheflush.h
+ *
+ * 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.
+ *
+ * (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CACHEFLUSH_H
+#define _XTENSA_CACHEFLUSH_H
+
+#ifdef __KERNEL__
+
+#include <linux/mm.h>
+#include <asm/processor.h>
+#include <asm/page.h>
+
+/*
+ * flush and invalidate data cache, invalidate instruction cache:
+ *
+ * __flush_invalidate_cache_all()
+ * __flush_invalidate_cache_range(from,sze)
+ *
+ * invalidate data or instruction cache:
+ *
+ * __invalidate_icache_all()
+ * __invalidate_icache_page(adr)
+ * __invalidate_dcache_page(adr)
+ * __invalidate_icache_range(from,size)
+ * __invalidate_dcache_range(from,size)
+ *
+ * flush data cache:
+ *
+ * __flush_dcache_page(adr)
+ *
+ * flush and invalidate data cache:
+ *
+ * __flush_invalidate_dcache_all()
+ * __flush_invalidate_dcache_page(adr)
+ * __flush_invalidate_dcache_range(from,size)
+ */
+
+extern void __flush_invalidate_cache_all(void);
+extern void __flush_invalidate_cache_range(unsigned long, unsigned long);
+extern void __flush_invalidate_dcache_all(void);
+extern void __invalidate_icache_all(void);
+
+extern void __invalidate_dcache_page(unsigned long);
+extern void __invalidate_icache_page(unsigned long);
+extern void __invalidate_icache_range(unsigned long, unsigned long);
+extern void __invalidate_dcache_range(unsigned long, unsigned long);
+
+#if XCHAL_DCACHE_IS_WRITEBACK
+extern void __flush_dcache_page(unsigned long);
+extern void __flush_invalidate_dcache_page(unsigned long);
+extern void __flush_invalidate_dcache_range(unsigned long, unsigned long);
+#else
+# define __flush_dcache_page(p) do { } while(0)
+# define __flush_invalidate_dcache_page(p) do { } while(0)
+# define __flush_invalidate_dcache_range(p,s) do { } while(0)
+#endif
+
+/*
+ * We have physically tagged caches - nothing to do here -
+ * unless we have cache aliasing.
+ *
+ * Pages can get remapped. Because this might change the 'color' of that page,
+ * we have to flush the cache before the PTE is changed.
+ * (see also Documentation/cachetlb.txt)
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+#define flush_cache_all() __flush_invalidate_cache_all();
+#define flush_cache_mm(mm) __flush_invalidate_cache_all();
+
+#define flush_cache_vmap(start,end) __flush_invalidate_cache_all();
+#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all();
+
+extern void flush_dcache_page(struct page*);
+
+extern void flush_cache_range(struct vm_area_struct*, ulong, ulong);
+extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long);
+
+#else
+
+#define flush_cache_all() do { } while (0)
+#define flush_cache_mm(mm) do { } while (0)
+
+#define flush_cache_vmap(start,end) do { } while (0)
+#define flush_cache_vunmap(start,end) do { } while (0)
+
+#define flush_dcache_page(page) do { } while (0)
+
+#define flush_cache_page(vma,addr,pfn) do { } while (0)
+#define flush_cache_range(vma,start,end) do { } while (0)
+
+#endif
+
+#define flush_icache_range(start,end) \
+ __invalidate_icache_range(start,(end)-(start))
+
+/* This is not required, see Documentation/cachetlb.txt */
+
+#define flush_icache_page(vma,page) do { } while(0)
+
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+
+#define copy_to_user_page(vma, page, vaddr, dst, src, len) \
+ memcpy(dst, src, len)
+
+#define copy_from_user_page(vma, page, vaddr, dst, src, len) \
+ memcpy(dst, src, len)
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_CACHEFLUSH_H */
+
diff --git a/include/asm-xtensa/checksum.h b/include/asm-xtensa/checksum.h
new file mode 100644
index 000000000000..1a00fad19929
--- /dev/null
+++ b/include/asm-xtensa/checksum.h
@@ -0,0 +1,264 @@
+/*
+ * include/asm-xtensa/checksum.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CHECKSUM_H
+#define _XTENSA_CHECKSUM_H
+
+#include <linux/config.h>
+#include <linux/in6.h>
+#include <xtensa/config/core.h>
+
+/*
+ * computes the checksum of a memory block at buff, length len,
+ * and adds in "sum" (32-bit)
+ *
+ * returns a 32-bit number suitable for feeding into itself
+ * or csum_tcpudp_magic
+ *
+ * this function must be called with even lengths, except
+ * for the last fragment, which may be odd
+ *
+ * it's best to have buff aligned on a 32-bit boundary
+ */
+asmlinkage unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum);
+
+/*
+ * the same as csum_partial, but copies from src while it
+ * checksums, and handles user-space pointer exceptions correctly, when needed.
+ *
+ * here even more important to align src and dst on a 32-bit (or even
+ * better 64-bit) boundary
+ */
+
+asmlinkage unsigned int csum_partial_copy_generic( const char *src, char *dst, int len, int sum,
+ int *src_err_ptr, int *dst_err_ptr);
+
+/*
+ * Note: when you get a NULL pointer exception here this means someone
+ * passed in an incorrect kernel address to one of these functions.
+ *
+ * If you use these functions directly please don't forget the
+ * verify_area().
+ */
+extern __inline__
+unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
+ int len, int sum)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
+}
+
+extern __inline__
+unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ return csum_partial_copy_generic ( src, dst, len, sum, err_ptr, NULL);
+}
+
+/*
+ * These are the old (and unsafe) way of doing checksums, a warning message will be
+ * printed if they are used and an exeption occurs.
+ *
+ * these functions should go away after some time.
+ */
+
+#define csum_partial_copy_fromuser csum_partial_copy
+unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum);
+
+/*
+ * Fold a partial checksum
+ */
+
+static __inline__ unsigned int csum_fold(unsigned int sum)
+{
+ unsigned int __dummy;
+ __asm__("extui %1, %0, 16, 16\n\t"
+ "extui %0 ,%0, 0, 16\n\t"
+ "add %0, %0, %1\n\t"
+ "slli %1, %0, 16\n\t"
+ "add %0, %0, %1\n\t"
+ "extui %0, %0, 16, 16\n\t"
+ "neg %0, %0\n\t"
+ "addi %0, %0, -1\n\t"
+ "extui %0, %0, 0, 16\n\t"
+ : "=r" (sum), "=&r" (__dummy)
+ : "0" (sum));
+ return sum;
+}
+
+/*
+ * This is a version of ip_compute_csum() optimized for IP headers,
+ * which always checksum on 4 octet boundaries.
+ */
+static __inline__ unsigned short ip_fast_csum(unsigned char * iph, unsigned int ihl)
+{
+ unsigned int sum, tmp, endaddr;
+
+ __asm__ __volatile__(
+ "sub %0, %0, %0\n\t"
+#if XCHAL_HAVE_LOOPS
+ "loopgtz %2, 2f\n\t"
+#else
+ "beqz %2, 2f\n\t"
+ "slli %4, %2, 2\n\t"
+ "add %4, %4, %1\n\t"
+ "0:\t"
+#endif
+ "l32i %3, %1, 0\n\t"
+ "add %0, %0, %3\n\t"
+ "bgeu %0, %3, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "addi %1, %1, 4\n\t"
+#if !XCHAL_HAVE_LOOPS
+ "blt %1, %4, 0b\n\t"
+#endif
+ "2:\t"
+ /* Since the input registers which are loaded with iph and ihl
+ are modified, we must also specify them as outputs, or gcc
+ will assume they contain their original values. */
+ : "=r" (sum), "=r" (iph), "=r" (ihl), "=&r" (tmp), "=&r" (endaddr)
+ : "1" (iph), "2" (ihl));
+
+ return csum_fold(sum);
+}
+
+static __inline__ unsigned long csum_tcpudp_nofold(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+
+#ifdef __XTENSA_EL__
+ unsigned long len_proto = (ntohs(len)<<16)+proto*256;
+#elif defined(__XTENSA_EB__)
+ unsigned long len_proto = (proto<<16)+len;
+#else
+# error processor byte order undefined!
+#endif
+ __asm__("add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "add %0, %0, %2\n\t"
+ "bgeu %0, %2, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "add %0, %0, %3\n\t"
+ "bgeu %0, %3, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ : "=r" (sum), "=r" (len_proto)
+ : "r" (daddr), "r" (saddr), "1" (len_proto), "0" (sum));
+ return sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+static __inline__ unsigned short int csum_tcpudp_magic(unsigned long saddr,
+ unsigned long daddr,
+ unsigned short len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));
+}
+
+/*
+ * this routine is used for miscellaneous IP-like checksums, mainly
+ * in icmp.c
+ */
+
+static __inline__ unsigned short ip_compute_csum(unsigned char * buff, int len)
+{
+ return csum_fold (csum_partial(buff, len, 0));
+}
+
+#define _HAVE_ARCH_IPV6_CSUM
+static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr,
+ struct in6_addr *daddr,
+ __u32 len,
+ unsigned short proto,
+ unsigned int sum)
+{
+ unsigned int __dummy;
+ __asm__("l32i %1, %2, 0\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %2, 4\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %2, 8\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %2, 12\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %3, 0\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %3, 4\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %3, 8\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "l32i %1, %3, 12\n\t"
+ "add %0, %0, %1\n\t"
+ "bgeu %0, %1, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "add %0, %0, %4\n\t"
+ "bgeu %0, %4, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ "add %0, %0, %5\n\t"
+ "bgeu %0, %5, 1f\n\t"
+ "addi %0, %0, 1\n\t"
+ "1:\t"
+ : "=r" (sum), "=&r" (__dummy)
+ : "r" (saddr), "r" (daddr),
+ "r" (htonl(len)), "r" (htonl(proto)), "0" (sum));
+
+ return csum_fold(sum);
+}
+
+/*
+ * Copy and checksum to user
+ */
+#define HAVE_CSUM_COPY_USER
+static __inline__ unsigned int csum_and_copy_to_user (const char *src, char *dst,
+ int len, int sum, int *err_ptr)
+{
+ if (access_ok(VERIFY_WRITE, dst, len))
+ return csum_partial_copy_generic(src, dst, len, sum, NULL, err_ptr);
+
+ if (len)
+ *err_ptr = -EFAULT;
+
+ return -1; /* invalid checksum */
+}
+#endif
diff --git a/include/asm-xtensa/coprocessor.h b/include/asm-xtensa/coprocessor.h
new file mode 100644
index 000000000000..a91b96dc0efe
--- /dev/null
+++ b/include/asm-xtensa/coprocessor.h
@@ -0,0 +1,70 @@
+/*
+ * include/asm-xtensa/cpextra.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_COPROCESSOR_H
+#define _XTENSA_COPROCESSOR_H
+
+#include <xtensa/config/core.h>
+
+#define XTOFS(last_start,last_size,align) \
+ ((last_start+last_size+align-1) & -align)
+
+#define XTENSA_CP_EXTRA_OFFSET 0
+#define XTENSA_CP_EXTRA_ALIGN XCHAL_EXTRA_SA_ALIGN
+
+#define XTENSA_CPE_CP0_OFFSET \
+ XTOFS(XTENSA_CP_EXTRA_OFFSET, XCHAL_EXTRA_SA_SIZE, XCHAL_CP0_SA_ALIGN)
+#define XTENSA_CPE_CP1_OFFSET \
+ XTOFS(XTENSA_CPE_CP0_OFFSET, XCHAL_CP0_SA_SIZE, XCHAL_CP1_SA_ALIGN)
+#define XTENSA_CPE_CP2_OFFSET \
+ XTOFS(XTENSA_CPE_CP1_OFFSET, XCHAL_CP1_SA_SIZE, XCHAL_CP2_SA_ALIGN)
+#define XTENSA_CPE_CP3_OFFSET \
+ XTOFS(XTENSA_CPE_CP2_OFFSET, XCHAL_CP2_SA_SIZE, XCHAL_CP3_SA_ALIGN)
+#define XTENSA_CPE_CP4_OFFSET \
+ XTOFS(XTENSA_CPE_CP3_OFFSET, XCHAL_CP3_SA_SIZE, XCHAL_CP4_SA_ALIGN)
+#define XTENSA_CPE_CP5_OFFSET \
+ XTOFS(XTENSA_CPE_CP4_OFFSET, XCHAL_CP4_SA_SIZE, XCHAL_CP5_SA_ALIGN)
+#define XTENSA_CPE_CP6_OFFSET \
+ XTOFS(XTENSA_CPE_CP5_OFFSET, XCHAL_CP5_SA_SIZE, XCHAL_CP6_SA_ALIGN)
+#define XTENSA_CPE_CP7_OFFSET \
+ XTOFS(XTENSA_CPE_CP6_OFFSET, XCHAL_CP6_SA_SIZE, XCHAL_CP7_SA_ALIGN)
+#define XTENSA_CP_EXTRA_SIZE \
+ XTOFS(XTENSA_CPE_CP7_OFFSET, XCHAL_CP7_SA_SIZE, 16)
+
+#if XCHAL_CP_NUM > 0
+# ifndef __ASSEMBLY__
+/*
+ * Tasks that own contents of (last user) each coprocessor.
+ * Entries are 0 for not-owned or non-existent coprocessors.
+ * Note: The size of this structure is fixed to 8 bytes in entry.S
+ */
+typedef struct {
+ struct task_struct *owner; /* owner */
+ int offset; /* offset in cpextra space. */
+} coprocessor_info_t;
+# else
+# define COPROCESSOR_INFO_OWNER 0
+# define COPROCESSOR_INFO_OFFSET 4
+# define COPROCESSOR_INFO_SIZE 8
+# endif
+#endif
+
+
+#ifndef __ASSEMBLY__
+# if XCHAL_CP_NUM > 0
+struct task_struct;
+extern void release_coprocessors (struct task_struct*);
+extern void save_coprocessor_registers(void*, int);
+# else
+# define release_coprocessors(task)
+# endif
+#endif
+
+#endif /* _XTENSA_COPROCESSOR_H */
diff --git a/include/asm-xtensa/cpumask.h b/include/asm-xtensa/cpumask.h
new file mode 100644
index 000000000000..ebeede397db3
--- /dev/null
+++ b/include/asm-xtensa/cpumask.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/cpumask.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CPUMASK_H
+#define _XTENSA_CPUMASK_H
+
+#include <asm-generic/cpumask.h>
+
+#endif /* _XTENSA_CPUMASK_H */
diff --git a/include/asm-xtensa/cputime.h b/include/asm-xtensa/cputime.h
new file mode 100644
index 000000000000..a7fb864a50ae
--- /dev/null
+++ b/include/asm-xtensa/cputime.h
@@ -0,0 +1,6 @@
+#ifndef _XTENSA_CPUTIME_H
+#define _XTENSA_CPUTIME_H
+
+#include <asm-generic/cputime.h>
+
+#endif /* _XTENSA_CPUTIME_H */
diff --git a/include/asm-xtensa/current.h b/include/asm-xtensa/current.h
new file mode 100644
index 000000000000..8d1eb5d78649
--- /dev/null
+++ b/include/asm-xtensa/current.h
@@ -0,0 +1,38 @@
+/*
+ * include/asm-xtensa/current.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_CURRENT_H
+#define _XTENSA_CURRENT_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/thread_info.h>
+
+struct task_struct;
+
+static inline struct task_struct *get_current(void)
+{
+ return current_thread_info()->task;
+}
+
+#define current get_current()
+
+#else
+
+#define CURRENT_SHIFT 13
+
+#define GET_CURRENT(reg,sp) \
+ GET_THREAD_INFO(reg,sp); \
+ l32i reg, reg, TI_TASK \
+
+#endif
+
+
+#endif /* XTENSA_CURRENT_H */
diff --git a/include/asm-xtensa/delay.h b/include/asm-xtensa/delay.h
new file mode 100644
index 000000000000..0a123d53a636
--- /dev/null
+++ b/include/asm-xtensa/delay.h
@@ -0,0 +1,50 @@
+/*
+ * include/asm-xtensa/delay.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ */
+
+#ifndef _XTENSA_DELAY_H
+#define _XTENSA_DELAY_H
+
+#include <linux/config.h>
+#include <asm/processor.h>
+#include <asm/param.h>
+
+extern unsigned long loops_per_jiffy;
+
+extern __inline__ void __delay(unsigned long loops)
+{
+ /* 2 cycles per loop. */
+ __asm__ __volatile__ ("1: addi %0, %0, -2; bgeui %0, 2, 1b"
+ : "=r" (loops) : "0" (loops));
+}
+
+static __inline__ u32 xtensa_get_ccount(void)
+{
+ u32 ccount;
+ asm volatile ("rsr %0, 234; # CCOUNT\n" : "=r" (ccount));
+ return ccount;
+}
+
+/* For SMP/NUMA systems, change boot_cpu_data to something like
+ * local_cpu_data->... where local_cpu_data points to the current
+ * cpu. */
+
+static __inline__ void udelay (unsigned long usecs)
+{
+ unsigned long start = xtensa_get_ccount();
+ unsigned long cycles = usecs * (loops_per_jiffy / (1000000UL / HZ));
+
+ /* Note: all variables are unsigned (can wrap around)! */
+ while (((unsigned long)xtensa_get_ccount()) - start < cycles)
+ ;
+}
+
+#endif
+
diff --git a/include/asm-xtensa/div64.h b/include/asm-xtensa/div64.h
new file mode 100644
index 000000000000..c4a105776383
--- /dev/null
+++ b/include/asm-xtensa/div64.h
@@ -0,0 +1,19 @@
+/*
+ * include/asm-xtensa/div64.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DIV64_H
+#define _XTENSA_DIV64_H
+
+#define do_div(n,base) ({ \
+ int __res = n % ((unsigned int) base); \
+ n /= (unsigned int) base; \
+ __res; })
+
+#endif
diff --git a/include/asm-xtensa/dma-mapping.h b/include/asm-xtensa/dma-mapping.h
new file mode 100644
index 000000000000..e86a206f1209
--- /dev/null
+++ b/include/asm-xtensa/dma-mapping.h
@@ -0,0 +1,182 @@
+/*
+ * include/asm-xtensa/dma_mapping.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DMA_MAPPING_H
+#define _XTENSA_DMA_MAPPING_H
+
+#include <asm/scatterlist.h>
+#include <asm/cache.h>
+#include <asm/io.h>
+#include <linux/mm.h>
+
+/*
+ * DMA-consistent mapping functions.
+ */
+
+extern void *consistent_alloc(int, size_t, dma_addr_t, unsigned long);
+extern void consistent_free(void*, size_t, dma_addr_t);
+extern void consistent_sync(void*, size_t, int);
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, int flag);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
+static inline dma_addr_t
+dma_map_single(struct device *dev, void *ptr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+ consistent_sync(ptr, size, direction);
+ return virt_to_phys(ptr);
+}
+
+static inline void
+dma_unmap_single(struct device *dev, dma_addr_t dma_addr, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+}
+
+static inline int
+dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ BUG_ON(direction == DMA_NONE);
+
+ for (i = 0; i < nents; i++, sg++ ) {
+ BUG_ON(!sg->page);
+
+ sg->dma_address = page_to_phys(sg->page) + sg->offset;
+ consistent_sync(page_address(sg->page) + sg->offset,
+ sg->length, direction);
+ }
+
+ return nents;
+}
+
+static inline dma_addr_t
+dma_map_page(struct device *dev, struct page *page, unsigned long offset,
+ size_t size, enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+ return (dma_addr_t)(page_to_pfn(page)) * PAGE_SIZE + offset;
+}
+
+static inline void
+dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+}
+
+
+static inline void
+dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction)
+{
+ BUG_ON(direction == DMA_NONE);
+}
+
+static inline void
+dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void
+dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle, size_t size,
+ enum dma_data_direction direction)
+{
+ consistent_sync((void *)bus_to_virt(dma_handle), size, direction);
+}
+
+static inline void
+dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+
+ consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
+}
+
+static inline void
+dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+
+ consistent_sync((void *)bus_to_virt(dma_handle)+offset,size,direction);
+}
+static inline void
+dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+{
+ int i;
+ for (i = 0; i < nelems; i++, sg++)
+ consistent_sync(page_address(sg->page) + sg->offset,
+ sg->length, dir);
+}
+
+static inline void
+dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction dir)
+{
+ int i;
+ for (i = 0; i < nelems; i++, sg++)
+ consistent_sync(page_address(sg->page) + sg->offset,
+ sg->length, dir);
+}
+static inline int
+dma_mapping_error(dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+static inline int
+dma_supported(struct device *dev, u64 mask)
+{
+ return 1;
+}
+
+static inline int
+dma_set_mask(struct device *dev, u64 mask)
+{
+ if(!dev->dma_mask || !dma_supported(dev, mask))
+ return -EIO;
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
+
+static inline int
+dma_get_cache_alignment(void)
+{
+ return L1_CACHE_BYTES;
+}
+
+#define dma_is_consistent(d) (1)
+
+static inline void
+dma_cache_sync(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+ consistent_sync(vaddr, size, direction);
+}
+
+#endif /* _XTENSA_DMA_MAPPING_H */
diff --git a/include/asm-xtensa/dma.h b/include/asm-xtensa/dma.h
new file mode 100644
index 000000000000..1c22b0234586
--- /dev/null
+++ b/include/asm-xtensa/dma.h
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/dma.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_DMA_H
+#define _XTENSA_DMA_H
+
+#include <linux/config.h>
+#include <asm/io.h> /* need byte IO */
+#include <xtensa/config/core.h>
+
+/*
+ * This is only to be defined if we have PC-like DMA.
+ * By default this is not true on an Xtensa processor,
+ * however on boards with a PCI bus, such functionality
+ * might be emulated externally.
+ *
+ * NOTE: there still exists driver code that assumes
+ * this is defined, eg. drivers/sound/soundcard.c (as of 2.4).
+ */
+#define MAX_DMA_CHANNELS 8
+
+/*
+ * The maximum virtual address to which DMA transfers
+ * can be performed on this platform.
+ *
+ * NOTE: This is board (platform) specific, not processor-specific!
+ *
+ * NOTE: This assumes DMA transfers can only be performed on
+ * the section of physical memory contiguously mapped in virtual
+ * space for the kernel. For the Xtensa architecture, this
+ * means the maximum possible size of this DMA area is
+ * the size of the statically mapped kernel segment
+ * (XCHAL_KSEG_{CACHED,BYPASS}_SIZE), ie. 128 MB.
+ *
+ * NOTE: When the entire KSEG area is DMA capable, we substract
+ * one from the max address so that the virt_to_phys() macro
+ * works correctly on the address (otherwise the address
+ * enters another area, and virt_to_phys() may not return
+ * the value desired).
+ */
+#define MAX_DMA_ADDRESS (PAGE_OFFSET + XCHAL_KSEG_CACHED_SIZE - 1)
+
+/* Reserve and release a DMA channel */
+extern int request_dma(unsigned int dmanr, const char * device_id);
+extern void free_dma(unsigned int dmanr);
+
+#ifdef CONFIG_PCI
+extern int isa_dma_bridge_buggy;
+#else
+#define isa_dma_bridge_buggy (0)
+#endif
+
+
+#endif
diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h
new file mode 100644
index 000000000000..64f1f53874fe
--- /dev/null
+++ b/include/asm-xtensa/elf.h
@@ -0,0 +1,222 @@
+/*
+ * include/asm-xtensa/elf.h
+ *
+ * ELF register definitions
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ELF_H
+#define _XTENSA_ELF_H
+
+#include <asm/ptrace.h>
+#include <asm/coprocessor.h>
+#include <xtensa/config/core.h>
+
+/* Xtensa processor ELF architecture-magic number */
+
+#define EM_XTENSA 94
+#define EM_XTENSA_OLD 0xABC7
+
+/* ELF register definitions. This is needed for core dump support. */
+
+/*
+ * elf_gregset_t contains the application-level state in the following order:
+ * Processor info: config_version, cpuxy
+ * Processor state: pc, ps, exccause, excvaddr, wb, ws,
+ * lbeg, lend, lcount, sar
+ * GP regs: ar0 - arXX
+ */
+
+typedef unsigned long elf_greg_t;
+
+typedef struct {
+ elf_greg_t xchal_config_id0;
+ elf_greg_t xchal_config_id1;
+ elf_greg_t cpux;
+ elf_greg_t cpuy;
+ elf_greg_t pc;
+ elf_greg_t ps;
+ elf_greg_t exccause;
+ elf_greg_t excvaddr;
+ elf_greg_t windowbase;
+ elf_greg_t windowstart;
+ elf_greg_t lbeg;
+ elf_greg_t lend;
+ elf_greg_t lcount;
+ elf_greg_t sar;
+ elf_greg_t syscall;
+ elf_greg_t ar[XCHAL_NUM_AREGS];
+} xtensa_gregset_t;
+
+#define ELF_NGREG (sizeof(xtensa_gregset_t) / sizeof(elf_greg_t))
+
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+/*
+ * Compute the size of the coprocessor and extra state layout (register info)
+ * table (in bytes).
+ * This is actually the maximum size of the table, as opposed to the size,
+ * which is available from the _xtensa_reginfo_table_size global variable.
+ *
+ * (See also arch/xtensa/kernel/coprocessor.S)
+ *
+ */
+
+#ifndef XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM
+# define XTENSA_CPE_LTABLE_SIZE 0
+#else
+# define XTENSA_CPE_SEGMENT(num) (num ? (1+num) : 0)
+# define XTENSA_CPE_LTABLE_ENTRIES \
+ ( XTENSA_CPE_SEGMENT(XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP0_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP1_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP2_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP3_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP4_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP5_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP6_SA_CONTENTS_LIBDB_NUM) \
+ + XTENSA_CPE_SEGMENT(XCHAL_CP7_SA_CONTENTS_LIBDB_NUM) \
+ + 1 /* final entry */ \
+ )
+# define XTENSA_CPE_LTABLE_SIZE (XTENSA_CPE_LTABLE_ENTRIES * 8)
+#endif
+
+
+/*
+ * Instantiations of the elf_fpregset_t type contain, in most
+ * architectures, the floating point (FPU) register set.
+ * For Xtensa, this type is extended to contain all custom state,
+ * ie. coprocessor and "extra" (non-coprocessor) state (including,
+ * for example, TIE-defined states and register files; as well
+ * as other optional processor state).
+ * This includes FPU state if a floating-point coprocessor happens
+ * to have been configured within the Xtensa processor.
+ *
+ * TOTAL_FPREGS_SIZE is the required size (without rounding)
+ * of elf_fpregset_t. It provides space for the following:
+ *
+ * a) 32-bit mask of active coprocessors for this task (similar
+ * to CPENABLE in single-threaded Xtensa processor systems)
+ *
+ * b) table describing the layout of custom states (ie. of
+ * individual registers, etc) within the save areas
+ *
+ * c) save areas for each coprocessor and for non-coprocessor
+ * ("extra") state
+ *
+ * Note that save areas may require up to 16-byte alignment when
+ * accessed by save/restore sequences. We do not need to ensure
+ * such alignment in an elf_fpregset_t structure because custom
+ * state is not directly loaded/stored into it; rather, save area
+ * contents are copied to elf_fpregset_t from the active save areas
+ * (see 'struct task_struct' definition in processor.h for that)
+ * using memcpy(). But we do allow space for such alignment,
+ * to allow optimizations of layout and copying.
+ */
+
+#define TOTAL_FPREGS_SIZE \
+ (4 + XTENSA_CPE_LTABLE_SIZE + XTENSA_CP_EXTRA_SIZE)
+#define ELF_NFPREG \
+ ((TOTAL_FPREGS_SIZE + sizeof(elf_fpreg_t) - 1) / sizeof(elf_fpreg_t))
+
+typedef unsigned int elf_fpreg_t;
+typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
+
+#define ELF_CORE_COPY_REGS(_eregs, _pregs) \
+ xtensa_elf_core_copy_regs (&_eregs, _pregs);
+
+extern void xtensa_elf_core_copy_regs (xtensa_gregset_t *, struct pt_regs *);
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+
+#define elf_check_arch(x) ( ( (x)->e_machine == EM_XTENSA ) || \
+ ( (x)->e_machine == EM_XTENSA_OLD ) )
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+
+#ifdef __XTENSA_EL__
+# define ELF_DATA ELFDATA2LSB
+#elif defined(__XTENSA_EB__)
+# define ELF_DATA ELFDATA2MSB
+#else
+# error processor byte order undefined!
+#endif
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_XTENSA
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE PAGE_SIZE
+
+/*
+ * This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ * use of this is to invoke "./ld.so someprog" to test out a new version of
+ * the loader. We need to make sure that it is out of the way of the program
+ * that it will "exec", and that there is sufficient room for the brk.
+ */
+
+#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3)
+
+/*
+ * This yields a mask that user programs can use to figure out what
+ * instruction set this CPU supports. This could be done in user space,
+ * but it's not easy, and we've already done it here.
+ */
+
+#define ELF_HWCAP (0)
+
+/*
+ * This yields a string that ld.so will use to load implementation
+ * specific libraries for optimization. This is more specific in
+ * intent than poking at uname or /proc/cpuinfo.
+ * For the moment, we have only optimizations for the Intel generations,
+ * but that could change...
+ */
+
+#define ELF_PLATFORM (NULL)
+
+/*
+ * The Xtensa processor ABI says that when the program starts, a2
+ * contains a pointer to a function which might be registered using
+ * `atexit'. This provides a mean for the dynamic linker to call
+ * DT_FINI functions for shared libraries that have been loaded before
+ * the code runs.
+ *
+ * A value of 0 tells we have no such handler.
+ *
+ * We might as well make sure everything else is cleared too (except
+ * for the stack pointer in a1), just to make things more
+ * deterministic. Also, clearing a0 terminates debugger backtraces.
+ */
+
+#define ELF_PLAT_INIT(_r, load_addr) \
+ do { _r->areg[0]=0; /*_r->areg[1]=0;*/ _r->areg[2]=0; _r->areg[3]=0; \
+ _r->areg[4]=0; _r->areg[5]=0; _r->areg[6]=0; _r->areg[7]=0; \
+ _r->areg[8]=0; _r->areg[9]=0; _r->areg[10]=0; _r->areg[11]=0; \
+ _r->areg[12]=0; _r->areg[13]=0; _r->areg[14]=0; _r->areg[15]=0; \
+ } while (0)
+
+#ifdef __KERNEL__
+
+#define SET_PERSONALITY(ex, ibcs2) set_personality(PER_LINUX_32BIT)
+
+extern void do_copy_regs (xtensa_gregset_t*, struct pt_regs*,
+ struct task_struct*);
+extern void do_restore_regs (xtensa_gregset_t*, struct pt_regs*,
+ struct task_struct*);
+extern void do_save_fpregs (elf_fpregset_t*, struct pt_regs*,
+ struct task_struct*);
+extern int do_restore_fpregs (elf_fpregset_t*, struct pt_regs*,
+ struct task_struct*);
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_ELF_H */
diff --git a/include/asm-xtensa/errno.h b/include/asm-xtensa/errno.h
new file mode 100644
index 000000000000..a0f3b96b79b4
--- /dev/null
+++ b/include/asm-xtensa/errno.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/errno.h
+ *
+ * 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) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_ERRNO_H
+#define _XTENSA_ERRNO_H
+
+#include <asm-generic/errno.h>
+
+#endif /* _XTENSA_ERRNO_H */
diff --git a/include/asm-xtensa/fcntl.h b/include/asm-xtensa/fcntl.h
new file mode 100644
index 000000000000..48876bb727d2
--- /dev/null
+++ b/include/asm-xtensa/fcntl.h
@@ -0,0 +1,101 @@
+/*
+ * include/asm-xtensa/fcntl.h
+ *
+ * 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, 1996, 1997, 1998 by Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_FCNTL_H
+#define _XTENSA_FCNTL_H
+
+/* open/fcntl - O_SYNC is only implemented on blocks devices and on files
+ located on an ext2 file system */
+#define O_ACCMODE 0x0003
+#define O_RDONLY 0x0000
+#define O_WRONLY 0x0001
+#define O_RDWR 0x0002
+#define O_APPEND 0x0008
+#define O_SYNC 0x0010
+#define O_NONBLOCK 0x0080
+#define O_CREAT 0x0100 /* not fcntl */
+#define O_TRUNC 0x0200 /* not fcntl */
+#define O_EXCL 0x0400 /* not fcntl */
+#define O_NOCTTY 0x0800 /* not fcntl */
+#define FASYNC 0x1000 /* fcntl, for BSD compatibility */
+#define O_LARGEFILE 0x2000 /* allow large file opens - currently ignored */
+#define O_DIRECT 0x8000 /* direct disk access hint - currently ignored*/
+#define O_DIRECTORY 0x10000 /* must be a directory */
+#define O_NOFOLLOW 0x20000 /* don't follow links */
+#define O_NOATIME 0x100000
+
+#define O_NDELAY O_NONBLOCK
+
+#define F_DUPFD 0 /* dup */
+#define F_GETFD 1 /* get close_on_exec */
+#define F_SETFD 2 /* set/clear close_on_exec */
+#define F_GETFL 3 /* get file->f_flags */
+#define F_SETFL 4 /* set file->f_flags */
+#define F_GETLK 14
+#define F_GETLK64 15
+#define F_SETLK 6
+#define F_SETLKW 7
+#define F_SETLK64 16
+#define F_SETLKW64 17
+
+#define F_SETOWN 24 /* for sockets. */
+#define F_GETOWN 23 /* for sockets. */
+#define F_SETSIG 10 /* for sockets. */
+#define F_GETSIG 11 /* for sockets. */
+
+/* for F_[GET|SET]FL */
+#define FD_CLOEXEC 1 /* actually anything with low bit set goes */
+
+/* for posix fcntl() and lockf() */
+#define F_RDLCK 0
+#define F_WRLCK 1
+#define F_UNLCK 2
+
+/* for old implementation of bsd flock () */
+#define F_EXLCK 4 /* or 3 */
+#define F_SHLCK 8 /* or 4 */
+
+/* for leases */
+#define F_INPROGRESS 16
+
+/* operations for bsd flock(), also used by the kernel implementation */
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* or'd with one of the above to prevent
+ blocking */
+#define LOCK_UN 8 /* remove lock */
+
+#define LOCK_MAND 32 /* This is a mandatory flock ... */
+#define LOCK_READ 64 /* which allows concurrent read operations */
+#define LOCK_WRITE 128 /* which allows concurrent write operations */
+#define LOCK_RW 192 /* which allows concurrent read & write ops */
+
+typedef struct flock {
+ short l_type;
+ short l_whence;
+ __kernel_off_t l_start;
+ __kernel_off_t l_len;
+ long l_sysid;
+ __kernel_pid_t l_pid;
+ long pad[4];
+} flock_t;
+
+struct flock64 {
+ short l_type;
+ short l_whence;
+ __kernel_off_t l_start;
+ __kernel_off_t l_len;
+ pid_t l_pid;
+};
+
+#define F_LINUX_SPECIFIC_BASE 1024
+
+#endif /* _XTENSA_FCNTL_H */
diff --git a/include/asm-xtensa/fixmap.h b/include/asm-xtensa/fixmap.h
new file mode 100644
index 000000000000..4423b8ad4954
--- /dev/null
+++ b/include/asm-xtensa/fixmap.h
@@ -0,0 +1,252 @@
+/*
+ * include/asm-xtensa/fixmap.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_FIXMAP_H
+#define _XTENSA_FIXMAP_H
+
+#include <asm/processor.h>
+
+#ifdef CONFIG_MMU
+
+/*
+ * Here we define all the compile-time virtual addresses.
+ */
+
+#if XCHAL_SEG_MAPPABLE_VADDR != 0
+# error "Current port requires virtual user space starting at 0"
+#endif
+#if XCHAL_SEG_MAPPABLE_SIZE < 0x80000000
+# error "Current port requires at least 0x8000000 bytes for user space"
+#endif
+
+/* Verify instruction/data ram/rom and xlmi don't overlay vmalloc space. */
+
+#define __IN_VMALLOC(addr) \
+ (((addr) >= VMALLOC_START) && ((addr) < VMALLOC_END))
+#define __SPAN_VMALLOC(start,end) \
+ (((start) < VMALLOC_START) && ((end) >= VMALLOC_END))
+#define INSIDE_VMALLOC(start,end) \
+ (__IN_VMALLOC((start)) || __IN_VMALLOC(end) || __SPAN_VMALLOC((start),(end)))
+
+#if XCHAL_NUM_INSTROM
+# if XCHAL_NUM_INSTROM == 1
+# if INSIDE_VMALLOC(XCHAL_INSTROM0_VADDR,XCHAL_INSTROM0_VADDR+XCHAL_INSTROM0_SIZE)
+# error vmalloc range conflicts with instrom0
+# endif
+# endif
+# if XCHAL_NUM_INSTROM == 2
+# if INSIDE_VMALLOC(XCHAL_INSTROM1_VADDR,XCHAL_INSTROM1_VADDR+XCHAL_INSTROM1_SIZE)
+# error vmalloc range conflicts with instrom1
+# endif
+# endif
+#endif
+
+#if XCHAL_NUM_INSTRAM
+# if XCHAL_NUM_INSTRAM == 1
+# if INSIDE_VMALLOC(XCHAL_INSTRAM0_VADDR,XCHAL_INSTRAM0_VADDR+XCHAL_INSTRAM0_SIZE)
+# error vmalloc range conflicts with instram0
+# endif
+# endif
+# if XCHAL_NUM_INSTRAM == 2
+# if INSIDE_VMALLOC(XCHAL_INSTRAM1_VADDR,XCHAL_INSTRAM1_VADDR+XCHAL_INSTRAM1_SIZE)
+# error vmalloc range conflicts with instram1
+# endif
+# endif
+#endif
+
+#if XCHAL_NUM_DATAROM
+# if XCHAL_NUM_DATAROM == 1
+# if INSIDE_VMALLOC(XCHAL_DATAROM0_VADDR,XCHAL_DATAROM0_VADDR+XCHAL_DATAROM0_SIZE)
+# error vmalloc range conflicts with datarom0
+# endif
+# endif
+# if XCHAL_NUM_DATAROM == 2
+# if INSIDE_VMALLOC(XCHAL_DATAROM1_VADDR,XCHAL_DATAROM1_VADDR+XCHAL_DATAROM1_SIZE)
+# error vmalloc range conflicts with datarom1
+# endif
+# endif
+#endif
+
+#if XCHAL_NUM_DATARAM
+# if XCHAL_NUM_DATARAM == 1
+# if INSIDE_VMALLOC(XCHAL_DATARAM0_VADDR,XCHAL_DATARAM0_VADDR+XCHAL_DATARAM0_SIZE)
+# error vmalloc range conflicts with dataram0
+# endif
+# endif
+# if XCHAL_NUM_DATARAM == 2
+# if INSIDE_VMALLOC(XCHAL_DATARAM1_VADDR,XCHAL_DATARAM1_VADDR+XCHAL_DATARAM1_SIZE)
+# error vmalloc range conflicts with dataram1
+# endif
+# endif
+#endif
+
+#if XCHAL_NUM_XLMI
+# if XCHAL_NUM_XLMI == 1
+# if INSIDE_VMALLOC(XCHAL_XLMI0_VADDR,XCHAL_XLMI0_VADDR+XCHAL_XLMI0_SIZE)
+# error vmalloc range conflicts with xlmi0
+# endif
+# endif
+# if XCHAL_NUM_XLMI == 2
+# if INSIDE_VMALLOC(XCHAL_XLMI1_VADDR,XCHAL_XLMI1_VADDR+XCHAL_XLMI1_SIZE)
+# error vmalloc range conflicts with xlmi1
+# endif
+# endif
+#endif
+
+#if (XCHAL_NUM_INSTROM > 2) || \
+ (XCHAL_NUM_INSTRAM > 2) || \
+ (XCHAL_NUM_DATARAM > 2) || \
+ (XCHAL_NUM_DATAROM > 2) || \
+ (XCHAL_NUM_XLMI > 2)
+# error Insufficient checks on vmalloc above for more than 2 devices
+#endif
+
+/*
+ * USER_VM_SIZE does not necessarily equal TASK_SIZE. We bumped
+ * TASK_SIZE down to 0x4000000 to simplify the handling of windowed
+ * call instructions (currently limited to a range of 1 GByte). User
+ * tasks may very well reclaim the VM space from 0x40000000 to
+ * 0x7fffffff in the future, so we do not want the kernel becoming
+ * accustomed to having any of its stuff (e.g., page tables) in this
+ * region. This VM region is no-man's land for now.
+ */
+
+#define USER_VM_START XCHAL_SEG_MAPPABLE_VADDR
+#define USER_VM_SIZE 0x80000000
+
+/* Size of page table: */
+
+#define PGTABLE_SIZE_BITS (32 - XCHAL_MMU_MIN_PTE_PAGE_SIZE + 2)
+#define PGTABLE_SIZE (1L << PGTABLE_SIZE_BITS)
+
+/* All kernel-mappable space: */
+
+#define KERNEL_ALLMAP_START (USER_VM_START + USER_VM_SIZE)
+#define KERNEL_ALLMAP_SIZE (XCHAL_SEG_MAPPABLE_SIZE - KERNEL_ALLMAP_START)
+
+/* Carve out page table at start of kernel-mappable area: */
+
+#if KERNEL_ALLMAP_SIZE < PGTABLE_SIZE
+#error "Gimme some space for page table!"
+#endif
+#define PGTABLE_START KERNEL_ALLMAP_START
+
+/* Remaining kernel-mappable space: */
+
+#define KERNEL_MAPPED_START (KERNEL_ALLMAP_START + PGTABLE_SIZE)
+#define KERNEL_MAPPED_SIZE (KERNEL_ALLMAP_SIZE - PGTABLE_SIZE)
+
+#if KERNEL_MAPPED_SIZE < 0x01000000 /* 16 MB is arbitrary for now */
+# error "Shouldn't the kernel have at least *some* mappable space?"
+#endif
+
+#define MAX_LOW_MEMORY XCHAL_KSEG_CACHED_SIZE
+
+#endif
+
+/*
+ * Some constants used elsewhere, but perhaps only in Xtensa header
+ * files, so maybe we can get rid of some and access compile-time HAL
+ * directly...
+ *
+ * Note: We assume that system RAM is located at the very start of the
+ * kernel segments !!
+ */
+#define KERNEL_VM_LOW XCHAL_KSEG_CACHED_VADDR
+#define KERNEL_VM_HIGH XCHAL_KSEG_BYPASS_VADDR
+#define KERNEL_SPACE XCHAL_KSEG_CACHED_VADDR
+
+/*
+ * Returns the physical/virtual addresses of the kernel space
+ * (works with the cached kernel segment only, which is the
+ * one normally used for kernel operation).
+ */
+
+/* PHYSICAL BYPASS CACHED
+ *
+ * bypass vaddr bypass paddr * cached vaddr
+ * cached vaddr cached paddr bypass vaddr *
+ * bypass paddr * bypass vaddr cached vaddr
+ * cached paddr * bypass vaddr cached vaddr
+ * other * * *
+ */
+
+#define PHYSADDR(a) \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR \
+ && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR + XCHAL_KSEG_BYPASS_PADDR : \
+ ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR \
+ && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR + XCHAL_KSEG_CACHED_PADDR : \
+ (unsigned)(a))
+
+#define BYPASS_ADDR(a) \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR \
+ && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_VADDR : \
+ ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR \
+ && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_BYPASS_VADDR : \
+ ((unsigned)(a) >= XCHAL_KSEG_CACHED_VADDR \
+ && (unsigned)(a) < XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_CACHED_SIZE)? \
+ (unsigned)(a) - XCHAL_KSEG_CACHED_VADDR+XCHAL_KSEG_BYPASS_VADDR: \
+ (unsigned)(a))
+
+#define CACHED_ADDR(a) \
+(((unsigned)(a) >= XCHAL_KSEG_BYPASS_PADDR \
+ && (unsigned)(a) < XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_BYPASS_PADDR + XCHAL_KSEG_CACHED_VADDR : \
+ ((unsigned)(a) >= XCHAL_KSEG_CACHED_PADDR \
+ && (unsigned)(a) < XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_CACHED_PADDR + XCHAL_KSEG_CACHED_VADDR : \
+ ((unsigned)(a) >= XCHAL_KSEG_BYPASS_VADDR \
+ && (unsigned)(a) < XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KSEG_BYPASS_VADDR+XCHAL_KSEG_CACHED_VADDR : \
+ (unsigned)(a))
+
+#define PHYSADDR_IO(a) \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR \
+ && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_PADDR : \
+ ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR \
+ && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_PADDR : \
+ (unsigned)(a))
+
+#define BYPASS_ADDR_IO(a) \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR \
+ && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_VADDR : \
+ ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR \
+ && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_BYPASS_VADDR : \
+ ((unsigned)(a) >= XCHAL_KIO_CACHED_VADDR \
+ && (unsigned)(a) < XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_CACHED_VADDR + XCHAL_KIO_BYPASS_VADDR : \
+ (unsigned)(a))
+
+#define CACHED_ADDR_IO(a) \
+(((unsigned)(a) >= XCHAL_KIO_BYPASS_PADDR \
+ && (unsigned)(a) < XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_BYPASS_PADDR + XCHAL_KIO_CACHED_VADDR : \
+ ((unsigned)(a) >= XCHAL_KIO_CACHED_PADDR \
+ && (unsigned)(a) < XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_CACHED_PADDR + XCHAL_KIO_CACHED_VADDR : \
+ ((unsigned)(a) >= XCHAL_KIO_BYPASS_VADDR \
+ && (unsigned)(a) < XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_BYPASS_SIZE) ? \
+ (unsigned)(a) - XCHAL_KIO_BYPASS_VADDR + XCHAL_KIO_CACHED_VADDR : \
+ (unsigned)(a))
+
+#endif /* _XTENSA_ADDRSPACE_H */
+
+
+
+
+
diff --git a/include/asm-xtensa/hardirq.h b/include/asm-xtensa/hardirq.h
new file mode 100644
index 000000000000..e07c76c36b95
--- /dev/null
+++ b/include/asm-xtensa/hardirq.h
@@ -0,0 +1,28 @@
+/*
+ * include/asm-xtensa/hardirq.h
+ *
+ * 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) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HARDIRQ_H
+#define _XTENSA_HARDIRQ_H
+
+#include <linux/config.h>
+#include <linux/cache.h>
+#include <asm/irq.h>
+
+/* headers.S is sensitive to the offsets of these fields */
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __syscall_count;
+ struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+ unsigned int __nmi_count; /* arch dependent */
+} ____cacheline_aligned irq_cpustat_t;
+
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
+
+#endif /* _XTENSA_HARDIRQ_H */
diff --git a/include/asm-xtensa/hdreg.h b/include/asm-xtensa/hdreg.h
new file mode 100644
index 000000000000..64b80607b80d
--- /dev/null
+++ b/include/asm-xtensa/hdreg.h
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/hdreg.h
+ *
+ * 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) 2002 - 2005 Tensilica Inc.
+ * Copyright (C) 1994-1996 Linus Torvalds & authors
+ */
+
+#ifndef _XTENSA_HDREG_H
+#define _XTENSA_HDREG_H
+
+typedef unsigned int ide_ioreg_t;
+
+#endif
diff --git a/include/asm-xtensa/highmem.h b/include/asm-xtensa/highmem.h
new file mode 100644
index 000000000000..0a046ca5a687
--- /dev/null
+++ b/include/asm-xtensa/highmem.h
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/highmem.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HIGHMEM_H
+#define _XTENSA_HIGHMEM_H
+
+extern void flush_cache_kmaps(void);
+
+#endif
+
diff --git a/include/asm-xtensa/hw_irq.h b/include/asm-xtensa/hw_irq.h
new file mode 100644
index 000000000000..ccf436249eaa
--- /dev/null
+++ b/include/asm-xtensa/hw_irq.h
@@ -0,0 +1,18 @@
+/*
+ * include/asm-xtensa/hw_irq.h
+ *
+ * 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) 2002 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_HW_IRQ_H
+#define _XTENSA_HW_IRQ_H
+
+static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i)
+{
+}
+
+#endif
diff --git a/include/asm-xtensa/ide.h b/include/asm-xtensa/ide.h
new file mode 100644
index 000000000000..b523cd4a486e
--- /dev/null
+++ b/include/asm-xtensa/ide.h
@@ -0,0 +1,36 @@
+/*
+ * include/asm-xtensa/ide.h
+ *
+ * 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) 1994 - 1996 Linus Torvalds & authors
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IDE_H
+#define _XTENSA_IDE_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+
+#ifndef MAX_HWIFS
+# define MAX_HWIFS 1
+#endif
+
+static __inline__ int ide_default_irq(unsigned long base)
+{
+ /* Unsupported! */
+ return 0;
+}
+
+static __inline__ unsigned long ide_default_io_base(int index)
+{
+ /* Unsupported! */
+ return 0;
+}
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_IDE_H */
diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h
new file mode 100644
index 000000000000..2c471c42ecfc
--- /dev/null
+++ b/include/asm-xtensa/io.h
@@ -0,0 +1,197 @@
+/*
+ * linux/include/asm-xtensa/io.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IO_H
+#define _XTENSA_IO_H
+
+#ifdef __KERNEL__
+#include <linux/config.h>
+#include <asm/byteorder.h>
+
+#include <linux/types.h>
+#include <asm/fixmap.h>
+
+#define _IO_BASE 0
+
+
+/*
+ * swap functions to change byte order from little-endian to big-endian and
+ * vice versa.
+ */
+
+static inline unsigned short _swapw (unsigned short v)
+{
+ return (v << 8) | (v >> 8);
+}
+
+static inline unsigned int _swapl (unsigned int v)
+{
+ return (v << 24) | ((v & 0xff00) << 8) | ((v >> 8) & 0xff00) | (v >> 24);
+}
+
+/*
+ * Change virtual addresses to physical addresses and vv.
+ * These are trivial on the 1:1 Linux/Xtensa mapping
+ */
+
+extern inline unsigned long virt_to_phys(volatile void * address)
+{
+ return PHYSADDR((unsigned long)address);
+}
+
+extern inline void * phys_to_virt(unsigned long address)
+{
+ return (void*) CACHED_ADDR(address);
+}
+
+/*
+ * IO bus memory addresses are also 1:1 with the physical address
+ */
+
+extern inline unsigned long virt_to_bus(volatile void * address)
+{
+ return PHYSADDR((unsigned long)address);
+}
+
+extern inline void * bus_to_virt (unsigned long address)
+{
+ return (void *) CACHED_ADDR(address);
+}
+
+/*
+ * Change "struct page" to physical address.
+ */
+
+extern inline void *ioremap(unsigned long offset, unsigned long size)
+{
+ return (void *) CACHED_ADDR_IO(offset);
+}
+
+extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+{
+ return (void *) BYPASS_ADDR_IO(offset);
+}
+
+extern inline void iounmap(void *addr)
+{
+}
+
+/*
+ * Generic I/O
+ */
+
+#define readb(addr) \
+ ({ unsigned char __v = (*(volatile unsigned char *)(addr)); __v; })
+#define readw(addr) \
+ ({ unsigned short __v = (*(volatile unsigned short *)(addr)); __v; })
+#define readl(addr) \
+ ({ unsigned int __v = (*(volatile unsigned int *)(addr)); __v; })
+#define writeb(b, addr) (void)((*(volatile unsigned char *)(addr)) = (b))
+#define writew(b, addr) (void)((*(volatile unsigned short *)(addr)) = (b))
+#define writel(b, addr) (void)((*(volatile unsigned int *)(addr)) = (b))
+
+static inline __u8 __raw_readb(const volatile void __iomem *addr)
+{
+ return *(__force volatile __u8 *)(addr);
+}
+static inline __u16 __raw_readw(const volatile void __iomem *addr)
+{
+ return *(__force volatile __u16 *)(addr);
+}
+static inline __u32 __raw_readl(const volatile void __iomem *addr)
+{
+ return *(__force volatile __u32 *)(addr);
+}
+static inline void __raw_writeb(__u8 b, volatile void __iomem *addr)
+{
+ *(__force volatile __u8 *)(addr) = b;
+}
+static inline void __raw_writew(__u16 b, volatile void __iomem *addr)
+{
+ *(__force volatile __u16 *)(addr) = b;
+}
+static inline void __raw_writel(__u32 b, volatile void __iomem *addr)
+{
+ *(__force volatile __u32 *)(addr) = b;
+}
+
+
+
+
+/* These are the definitions for the x86 IO instructions
+ * inb/inw/inl/outb/outw/outl, the "string" versions
+ * insb/insw/insl/outsb/outsw/outsl, and the "pausing" versions
+ * inb_p/inw_p/...
+ * The macros don't do byte-swapping.
+ */
+
+#define inb(port) readb((u8 *)((port)+_IO_BASE))
+#define outb(val, port) writeb((val),(u8 *)((unsigned long)(port)+_IO_BASE))
+#define inw(port) readw((u16 *)((port)+_IO_BASE))
+#define outw(val, port) writew((val),(u16 *)((unsigned long)(port)+_IO_BASE))
+#define inl(port) readl((u32 *)((port)+_IO_BASE))
+#define outl(val, port) writel((val),(u32 *)((unsigned long)(port)))
+
+#define inb_p(port) inb((port))
+#define outb_p(val, port) outb((val), (port))
+#define inw_p(port) inw((port))
+#define outw_p(val, port) outw((val), (port))
+#define inl_p(port) inl((port))
+#define outl_p(val, port) outl((val), (port))
+
+extern void insb (unsigned long port, void *dst, unsigned long count);
+extern void insw (unsigned long port, void *dst, unsigned long count);
+extern void insl (unsigned long port, void *dst, unsigned long count);
+extern void outsb (unsigned long port, const void *src, unsigned long count);
+extern void outsw (unsigned long port, const void *src, unsigned long count);
+extern void outsl (unsigned long port, const void *src, unsigned long count);
+
+#define IO_SPACE_LIMIT ~0
+
+#define memset_io(a,b,c) memset((void *)(a),(b),(c))
+#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
+#define memcpy_toio(a,b,c) memcpy((void *)(a),(b),(c))
+
+/* At this point the Xtensa doesn't provide byte swap instructions */
+
+#ifdef __XTENSA_EB__
+# define in_8(addr) (*(u8*)(addr))
+# define in_le16(addr) _swapw(*(u16*)(addr))
+# define in_le32(addr) _swapl(*(u32*)(addr))
+# define out_8(b, addr) *(u8*)(addr) = (b)
+# define out_le16(b, addr) *(u16*)(addr) = _swapw(b)
+# define out_le32(b, addr) *(u32*)(addr) = _swapl(b)
+#elif defined(__XTENSA_EL__)
+# define in_8(addr) (*(u8*)(addr))
+# define in_le16(addr) (*(u16*)(addr))
+# define in_le32(addr) (*(u32*)(addr))
+# define out_8(b, addr) *(u8*)(addr) = (b)
+# define out_le16(b, addr) *(u16*)(addr) = (b)
+# define out_le32(b, addr) *(u32*)(addr) = (b)
+#else
+# error processor byte order undefined!
+#endif
+
+
+/*
+ * * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * * access
+ * */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+/*
+ * * Convert a virtual cached pointer to an uncached pointer
+ * */
+#define xlate_dev_kmem_ptr(p) p
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_IO_H */
diff --git a/include/asm-xtensa/ioctl.h b/include/asm-xtensa/ioctl.h
new file mode 100644
index 000000000000..856c605d62b1
--- /dev/null
+++ b/include/asm-xtensa/ioctl.h
@@ -0,0 +1,83 @@
+/*
+ * include/asm-xtensa/ioctl.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ *
+ * Derived from "include/asm-i386/ioctl.h"
+ */
+
+#ifndef _XTENSA_IOCTL_H
+#define _XTENSA_IOCTL_H
+
+
+/* ioctl command encoding: 32 bits total, command in lower 16 bits,
+ * size of the parameter structure in the lower 14 bits of the
+ * upper 16 bits.
+ * Encoding the size of the parameter structure in the ioctl request
+ * is useful for catching programs compiled with old versions
+ * and to avoid overwriting user space outside the user buffer area.
+ * The highest 2 bits are reserved for indicating the ``access mode''.
+ * NOTE: This limits the max parameter size to 16kB -1 !
+ */
+
+/*
+ * The following is for compatibility across the various Linux
+ * platforms. The i386 ioctl numbering scheme doesn't really enforce
+ * a type field. De facto, however, the top 8 bits of the lower 16
+ * bits are indeed used as a type field, so we might just as well make
+ * this explicit here. Please be sure to use the decoding macros
+ * below from now on.
+ */
+#define _IOC_NRBITS 8
+#define _IOC_TYPEBITS 8
+#define _IOC_SIZEBITS 14
+#define _IOC_DIRBITS 2
+
+#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1)
+#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1)
+#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1)
+#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1)
+
+#define _IOC_NRSHIFT 0
+#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS)
+#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS)
+#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS)
+
+/*
+ * Direction bits.
+ */
+#define _IOC_NONE 0U
+#define _IOC_WRITE 1U
+#define _IOC_READ 2U
+
+#define _IOC(dir,type,nr,size) \
+ (((dir) << _IOC_DIRSHIFT) | \
+ ((type) << _IOC_TYPESHIFT) | \
+ ((nr) << _IOC_NRSHIFT) | \
+ ((size) << _IOC_SIZESHIFT))
+
+/* used to create numbers */
+#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0)
+#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size))
+#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size))
+#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size))
+
+/* used to decode ioctl numbers.. */
+#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK)
+#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK)
+#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK)
+#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK)
+
+/* ...and for the drivers/sound files... */
+
+#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT)
+#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT)
+#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT)
+#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT)
+#define IOCSIZE_SHIFT (_IOC_SIZESHIFT)
+
+#endif
diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h
new file mode 100644
index 000000000000..10c443435c11
--- /dev/null
+++ b/include/asm-xtensa/ioctls.h
@@ -0,0 +1,112 @@
+/*
+ * include/asm-xtensa/ioctl.h
+ *
+ * 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) 2003 - 2005 Tensilica Inc.
+ *
+ * Derived from "include/asm-i386/ioctls.h"
+ */
+
+#ifndef _XTENSA_IOCTLS_H
+#define _XTENSA_IOCTLS_H
+
+#include <asm/ioctl.h>
+
+#define FIOCLEX _IO('f', 1)
+#define FIONCLEX _IO('f', 2)
+#define FIOASYNC _IOW('f', 125, int)
+#define FIONBIO _IOW('f', 126, int)
+#define FIONREAD _IOR('f', 127, int)
+#define TIOCINQ FIONREAD
+#define FIOQSIZE _IOR('f', 128, loff_t)
+
+#define TCGETS 0x5401
+#define TCSETS 0x5402
+#define TCSETSW 0x5403
+#define TCSETSF 0x5404
+
+#define TCGETA _IOR('t', 23, struct termio)
+#define TCSETA _IOW('t', 24, struct termio)
+#define TCSETAW _IOW('t', 25, struct termio)
+#define TCSETAF _IOW('t', 28, struct termio)
+
+#define TCSBRK _IO('t', 29)
+#define TCXONC _IO('t', 30)
+#define TCFLSH _IO('t', 31)
+
+#define TIOCSWINSZ _IOW('t', 103, struct winsize)
+#define TIOCGWINSZ _IOR('t', 104, struct winsize)
+#define TIOCSTART _IO('t', 110) /* start output, like ^Q */
+#define TIOCSTOP _IO('t', 111) /* stop output, like ^S */
+#define TIOCOUTQ _IOR('t', 115, int) /* output queue size */
+
+#define TIOCSPGRP _IOW('t', 118, int)
+#define TIOCGPGRP _IOR('t', 119, int)
+
+#define TIOCEXCL _IO('T', 12)
+#define TIOCNXCL _IO('T', 13)
+#define TIOCSCTTY _IO('T', 14)
+
+#define TIOCSTI _IOW('T', 18, char)
+#define TIOCMGET _IOR('T', 21, unsigned int)
+#define TIOCMBIS _IOW('T', 22, unsigned int)
+#define TIOCMBIC _IOW('T', 23, unsigned int)
+#define TIOCMSET _IOW('T', 24, unsigned int)
+# define TIOCM_LE 0x001
+# define TIOCM_DTR 0x002
+# define TIOCM_RTS 0x004
+# define TIOCM_ST 0x008
+# define TIOCM_SR 0x010
+# define TIOCM_CTS 0x020
+# define TIOCM_CAR 0x040
+# define TIOCM_RNG 0x080
+# define TIOCM_DSR 0x100
+# define TIOCM_CD TIOCM_CAR
+# define TIOCM_RI TIOCM_RNG
+
+#define TIOCGSOFTCAR _IOR('T', 25, unsigned int)
+#define TIOCSSOFTCAR _IOW('T', 26, unsigned int)
+#define TIOCLINUX _IOW('T', 28, char)
+#define TIOCCONS _IO('T', 29)
+#define TIOCGSERIAL _IOR('T', 30, struct serial_struct)
+#define TIOCSSERIAL _IOW('T', 31, struct serial_struct)
+#define TIOCPKT _IOW('T', 32, int)
+# define TIOCPKT_DATA 0
+# define TIOCPKT_FLUSHREAD 1
+# define TIOCPKT_FLUSHWRITE 2
+# define TIOCPKT_STOP 4
+# define TIOCPKT_START 8
+# define TIOCPKT_NOSTOP 16
+# define TIOCPKT_DOSTOP 32
+
+
+#define TIOCNOTTY _IO('T', 34)
+#define TIOCSETD _IOW('T', 35, int)
+#define TIOCGETD _IOR('T', 36, int)
+#define TCSBRKP _IOW('T', 37, int) /* Needed for POSIX tcsendbreak()*/
+#define TIOCTTYGSTRUCT _IOR('T', 38, struct tty_struct) /* For debugging only*/
+#define TIOCSBRK _IO('T', 39) /* BSD compatibility */
+#define TIOCCBRK _IO('T', 40) /* BSD compatibility */
+#define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/
+#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define TIOCSERCONFIG _IO('T', 83)
+#define TIOCSERGWILD _IOR('T', 84, int)
+#define TIOCSERSWILD _IOW('T', 85, int)
+#define TIOCGLCKTRMIOS 0x5456
+#define TIOCSLCKTRMIOS 0x5457
+#define TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TIOCSERGETLSR _IOR('T', 89, unsigned int) /* Get line status reg. */
+ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+#define TIOCSERGETMULTI _IOR('T', 90, struct serial_multiport_struct) /* Get multiport config */
+#define TIOCSERSETMULTI _IOW('T', 91, struct serial_multiport_struct) /* Set multiport config */
+
+#define TIOCMIWAIT _IO('T', 92) /* wait for a change on serial input line(s) */
+#define TIOCGICOUNT _IOR('T', 93, struct async_icount) /* read serial port inline interrupt counts */
+
+#endif /* _XTENSA_IOCTLS_H */
diff --git a/include/asm-xtensa/ipcbuf.h b/include/asm-xtensa/ipcbuf.h
new file mode 100644
index 000000000000..c33aa6a42145
--- /dev/null
+++ b/include/asm-xtensa/ipcbuf.h
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/ipcbuf.h
+ *
+ * The ipc64_perm structure for the Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IPCBUF_H
+#define _XTENSA_IPCBUF_H
+
+/*
+ * Pad space is left for:
+ * - 32-bit mode_t and seq
+ * - 2 miscellaneous 32-bit values
+ *
+ * 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.
+ */
+
+struct ipc64_perm
+{
+ __kernel_key_t key;
+ __kernel_uid32_t uid;
+ __kernel_gid32_t gid;
+ __kernel_uid32_t cuid;
+ __kernel_gid32_t cgid;
+ __kernel_mode_t mode;
+ unsigned long seq;
+ unsigned long __unused1;
+ unsigned long __unused2;
+};
+
+#endif /* _XTENSA_IPCBUF_H */
diff --git a/include/asm-xtensa/irq.h b/include/asm-xtensa/irq.h
new file mode 100644
index 000000000000..d984e955938f
--- /dev/null
+++ b/include/asm-xtensa/irq.h
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/irq.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_IRQ_H
+#define _XTENSA_IRQ_H
+
+#include <linux/config.h>
+#include <asm/platform/hardware.h>
+
+#include <xtensa/config/core.h>
+
+#ifndef PLATFORM_NR_IRQS
+# define PLATFORM_NR_IRQS 0
+#endif
+#define XTENSA_NR_IRQS XCHAL_NUM_INTERRUPTS
+#define NR_IRQS (XTENSA_NR_IRQS + PLATFORM_NR_IRQS)
+
+static __inline__ int irq_canonicalize(int irq)
+{
+ return (irq);
+}
+
+struct irqaction;
+#if 0 // FIXME
+extern void disable_irq_nosync(unsigned int);
+extern void disable_irq(unsigned int);
+extern void enable_irq(unsigned int);
+#endif
+
+#endif /* _XTENSA_IRQ_H */
diff --git a/include/asm-xtensa/kmap_types.h b/include/asm-xtensa/kmap_types.h
new file mode 100644
index 000000000000..9e822d2e3bce
--- /dev/null
+++ b/include/asm-xtensa/kmap_types.h
@@ -0,0 +1,31 @@
+/*
+ * include/asm-xtensa/kmap_types.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_KMAP_TYPES_H
+#define _XTENSA_KMAP_TYPES_H
+
+enum km_type {
+ KM_BOUNCE_READ,
+ KM_SKB_SUNRPC_DATA,
+ KM_SKB_DATA_SOFTIRQ,
+ KM_USER0,
+ KM_USER1,
+ KM_BIO_SRC_IRQ,
+ KM_BIO_DST_IRQ,
+ KM_PTE0,
+ KM_PTE1,
+ KM_IRQ0,
+ KM_IRQ1,
+ KM_SOFTIRQ0,
+ KM_SOFTIRQ1,
+ KM_TYPE_NR
+};
+
+#endif /* _XTENSA_KMAP_TYPES_H */
diff --git a/include/asm-xtensa/linkage.h b/include/asm-xtensa/linkage.h
new file mode 100644
index 000000000000..bf2128a99d79
--- /dev/null
+++ b/include/asm-xtensa/linkage.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/linkage.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_LINKAGE_H
+#define _XTENSA_LINKAGE_H
+
+/* Nothing to do here ... */
+
+#endif /* _XTENSA_LINKAGE_H */
diff --git a/include/asm-xtensa/local.h b/include/asm-xtensa/local.h
new file mode 100644
index 000000000000..48723e550d14
--- /dev/null
+++ b/include/asm-xtensa/local.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/local.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_LOCAL_H
+#define _XTENSA_LOCAL_H
+
+#include <asm-generic/local.h>
+
+#endif /* _XTENSA_LOCAL_H */
diff --git a/include/asm-xtensa/mman.h b/include/asm-xtensa/mman.h
new file mode 100644
index 000000000000..9a95a45df996
--- /dev/null
+++ b/include/asm-xtensa/mman.h
@@ -0,0 +1,80 @@
+/*
+ * include/asm-xtensa/mman.h
+ *
+ * Xtensa Processor memory-manager definitions
+ *
+ * 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 Ralf Baechle
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMAN_H
+#define _XTENSA_MMAN_H
+
+/*
+ * Protections are chosen from these bits, OR'd together. The
+ * implementation does not necessarily support PROT_EXEC or PROT_WRITE
+ * without PROT_READ. The only guarantees are that no writing will be
+ * allowed without PROT_WRITE and no access will be allowed for PROT_NONE.
+ */
+
+#define PROT_NONE 0x0 /* page can not be accessed */
+#define PROT_READ 0x1 /* page can be read */
+#define PROT_WRITE 0x2 /* page can be written */
+#define PROT_EXEC 0x4 /* page can be executed */
+
+#define PROT_SEM 0x10 /* page may be used for atomic ops */
+#define PROT_GROWSDOWN 0x01000000 /* mprotect flag: extend change to start of growsdown vma */
+#define PROT_GROWSUP 0x02000000 /* mprotect flag: extend change to end fo growsup vma */
+
+/*
+ * Flags for mmap
+ */
+#define MAP_SHARED 0x001 /* Share changes */
+#define MAP_PRIVATE 0x002 /* Changes are private */
+#define MAP_TYPE 0x00f /* Mask for type of mapping */
+#define MAP_FIXED 0x010 /* Interpret addr exactly */
+
+/* not used by linux, but here to make sure we don't clash with ABI defines */
+#define MAP_RENAME 0x020 /* Assign page to file */
+#define MAP_AUTOGROW 0x040 /* File may grow by writing */
+#define MAP_LOCAL 0x080 /* Copy on fork/sproc */
+#define MAP_AUTORSRV 0x100 /* Logical swap reserved on demand */
+
+/* These are linux-specific */
+#define MAP_NORESERVE 0x0400 /* don't check for reservations */
+#define MAP_ANONYMOUS 0x0800 /* don't use a file */
+#define MAP_GROWSDOWN 0x1000 /* stack-like segment */
+#define MAP_DENYWRITE 0x2000 /* ETXTBSY */
+#define MAP_EXECUTABLE 0x4000 /* mark it as an executable */
+#define MAP_LOCKED 0x8000 /* pages are locked */
+#define MAP_POPULATE 0x10000 /* populate (prefault) pagetables */
+#define MAP_NONBLOCK 0x20000 /* do not block on IO */
+
+/*
+ * Flags for msync
+ */
+#define MS_ASYNC 0x0001 /* sync memory asynchronously */
+#define MS_INVALIDATE 0x0002 /* invalidate mappings & caches */
+#define MS_SYNC 0x0004 /* synchronous memory sync */
+
+/*
+ * Flags for mlockall
+ */
+#define MCL_CURRENT 1 /* lock all current mappings */
+#define MCL_FUTURE 2 /* lock all future mappings */
+
+#define MADV_NORMAL 0x0 /* default page-in behavior */
+#define MADV_RANDOM 0x1 /* page-in minimum required */
+#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */
+#define MADV_WILLNEED 0x3 /* pre-fault pages */
+#define MADV_DONTNEED 0x4 /* discard these pages */
+
+/* compatibility flags */
+#define MAP_ANON MAP_ANONYMOUS
+#define MAP_FILE 0
+
+#endif /* _XTENSA_MMAN_H */
diff --git a/include/asm-xtensa/mmu.h b/include/asm-xtensa/mmu.h
new file mode 100644
index 000000000000..44c5bb04c55c
--- /dev/null
+++ b/include/asm-xtensa/mmu.h
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/mmu.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMU_H
+#define _XTENSA_MMU_H
+
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+#endif /* _XTENSA_MMU_H */
diff --git a/include/asm-xtensa/mmu_context.h b/include/asm-xtensa/mmu_context.h
new file mode 100644
index 000000000000..1b0801548cd9
--- /dev/null
+++ b/include/asm-xtensa/mmu_context.h
@@ -0,0 +1,330 @@
+/*
+ * include/asm-xtensa/mmu_context.h
+ *
+ * Switch an MMU context.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MMU_CONTEXT_H
+#define _XTENSA_MMU_CONTEXT_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+#include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+/*
+ * Linux was ported to Xtensa assuming all auto-refill ways in set 0
+ * had the same properties (a very likely assumption). Multiple sets
+ * of auto-refill ways will still work properly, but not as optimally
+ * as the Xtensa designer may have assumed.
+ *
+ * We make this case a hard #error, killing the kernel build, to alert
+ * the developer to this condition (which is more likely an error).
+ * You super-duper clever developers can change it to a warning or
+ * remove it altogether if you think you know what you're doing. :)
+ */
+
+#if (XCHAL_HAVE_TLBS != 1)
+# error "Linux must have an MMU!"
+#endif
+
+#if ((XCHAL_ITLB_ARF_WAYS == 0) || (XCHAL_DTLB_ARF_WAYS == 0))
+# error "MMU must have auto-refill ways"
+#endif
+
+#if ((XCHAL_ITLB_ARF_SETS != 1) || (XCHAL_DTLB_ARF_SETS != 1))
+# error Linux may not use all auto-refill ways as efficiently as you think
+#endif
+
+#if (XCHAL_MMU_MAX_PTE_PAGE_SIZE != XCHAL_MMU_MIN_PTE_PAGE_SIZE)
+# error Only one page size allowed!
+#endif
+
+extern unsigned long asid_cache;
+extern pgd_t *current_pgd;
+
+/*
+ * Define the number of entries per auto-refill way in set 0 of both I and D
+ * TLBs. We deal only with set 0 here (an assumption further explained in
+ * assertions.h). Also, define the total number of ARF entries in both TLBs.
+ */
+
+#define ITLB_ENTRIES_PER_ARF_WAY (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES))
+#define DTLB_ENTRIES_PER_ARF_WAY (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES))
+
+#define ITLB_ENTRIES \
+ (ITLB_ENTRIES_PER_ARF_WAY * (XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,WAYS)))
+#define DTLB_ENTRIES \
+ (DTLB_ENTRIES_PER_ARF_WAY * (XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,WAYS)))
+
+
+/*
+ * SMALLEST_NTLB_ENTRIES is the smaller of ITLB_ENTRIES and DTLB_ENTRIES.
+ * In practice, they are probably equal. This macro simplifies function
+ * flush_tlb_range().
+ */
+
+#if (DTLB_ENTRIES < ITLB_ENTRIES)
+# define SMALLEST_NTLB_ENTRIES DTLB_ENTRIES
+#else
+# define SMALLEST_NTLB_ENTRIES ITLB_ENTRIES
+#endif
+
+
+/*
+ * asid_cache tracks only the ASID[USER_RING] field of the RASID special
+ * register, which is the current user-task asid allocation value.
+ * mm->context has the same meaning. When it comes time to write the
+ * asid_cache or mm->context values to the RASID special register, we first
+ * shift the value left by 8, then insert the value.
+ * ASID[0] always contains the kernel's asid value, and we reserve three
+ * other asid values that we never assign to user tasks.
+ */
+
+#define ASID_INC 0x1
+#define ASID_MASK ((1 << XCHAL_MMU_ASID_BITS) - 1)
+
+/*
+ * XCHAL_MMU_ASID_INVALID is a configurable Xtensa processor constant
+ * indicating invalid address space. XCHAL_MMU_ASID_KERNEL is a configurable
+ * Xtensa processor constant indicating the kernel address space. They can
+ * be arbitrary values.
+ *
+ * We identify three more unique, reserved ASID values to use in the unused
+ * ring positions. No other user process will be assigned these reserved
+ * ASID values.
+ *
+ * For example, given that
+ *
+ * XCHAL_MMU_ASID_INVALID == 0
+ * XCHAL_MMU_ASID_KERNEL == 1
+ *
+ * the following maze of #if statements would generate
+ *
+ * ASID_RESERVED_1 == 2
+ * ASID_RESERVED_2 == 3
+ * ASID_RESERVED_3 == 4
+ * ASID_FIRST_NONRESERVED == 5
+ */
+
+#if (XCHAL_MMU_ASID_INVALID != XCHAL_MMU_ASID_KERNEL + 1)
+# define ASID_RESERVED_1 ((XCHAL_MMU_ASID_KERNEL + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_1 ((XCHAL_MMU_ASID_KERNEL + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_1 + 1)
+# define ASID_RESERVED_2 ((ASID_RESERVED_1 + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_2 ((ASID_RESERVED_1 + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_2 + 1)
+# define ASID_RESERVED_3 ((ASID_RESERVED_2 + 1) & ASID_MASK)
+#else
+# define ASID_RESERVED_3 ((ASID_RESERVED_2 + 2) & ASID_MASK)
+#endif
+
+#if (XCHAL_MMU_ASID_INVALID != ASID_RESERVED_3 + 1)
+# define ASID_FIRST_NONRESERVED ((ASID_RESERVED_3 + 1) & ASID_MASK)
+#else
+# define ASID_FIRST_NONRESERVED ((ASID_RESERVED_3 + 2) & ASID_MASK)
+#endif
+
+#define ASID_ALL_RESERVED ( ((ASID_RESERVED_1) << 24) + \
+ ((ASID_RESERVED_2) << 16) + \
+ ((ASID_RESERVED_3) << 8) + \
+ ((XCHAL_MMU_ASID_KERNEL)) )
+
+
+/*
+ * NO_CONTEXT is the invalid ASID value that we don't ever assign to
+ * any user or kernel context. NO_CONTEXT is a better mnemonic than
+ * XCHAL_MMU_ASID_INVALID, so we use it in code instead.
+ */
+
+#define NO_CONTEXT XCHAL_MMU_ASID_INVALID
+
+#if (KERNEL_RING != 0)
+# error The KERNEL_RING really should be zero.
+#endif
+
+#if (USER_RING >= XCHAL_MMU_RINGS)
+# error USER_RING cannot be greater than the highest numbered ring.
+#endif
+
+#if (USER_RING == KERNEL_RING)
+# error The user and kernel rings really should not be equal.
+#endif
+
+#if (USER_RING == 1)
+#define ASID_INSERT(x) ( ((ASID_RESERVED_1) << 24) + \
+ ((ASID_RESERVED_2) << 16) + \
+ (((x) & (ASID_MASK)) << 8) + \
+ ((XCHAL_MMU_ASID_KERNEL)) )
+
+#elif (USER_RING == 2)
+#define ASID_INSERT(x) ( ((ASID_RESERVED_1) << 24) + \
+ (((x) & (ASID_MASK)) << 16) + \
+ ((ASID_RESERVED_2) << 8) + \
+ ((XCHAL_MMU_ASID_KERNEL)) )
+
+#elif (USER_RING == 3)
+#define ASID_INSERT(x) ( (((x) & (ASID_MASK)) << 24) + \
+ ((ASID_RESERVED_1) << 16) + \
+ ((ASID_RESERVED_2) << 8) + \
+ ((XCHAL_MMU_ASID_KERNEL)) )
+
+#else
+#error Goofy value for USER_RING
+
+#endif /* USER_RING == 1 */
+
+
+/*
+ * All unused by hardware upper bits will be considered
+ * as a software asid extension.
+ */
+
+#define ASID_VERSION_MASK ((unsigned long)~(ASID_MASK|(ASID_MASK-1)))
+#define ASID_FIRST_VERSION \
+ ((unsigned long)(~ASID_VERSION_MASK) + 1 + ASID_FIRST_NONRESERVED)
+
+extern inline void set_rasid_register (unsigned long val)
+{
+ __asm__ __volatile__ (" wsr %0, "__stringify(RASID)"\n\t"
+ " isync\n" : : "a" (val));
+}
+
+extern inline unsigned long get_rasid_register (void)
+{
+ unsigned long tmp;
+ __asm__ __volatile__ (" rsr %0, "__stringify(RASID)"\n\t" : "=a" (tmp));
+ return tmp;
+}
+
+
+#if ((XCHAL_MMU_ASID_INVALID == 0) && (XCHAL_MMU_ASID_KERNEL == 1))
+
+extern inline void
+get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+{
+ extern void flush_tlb_all(void);
+ if (! ((asid += ASID_INC) & ASID_MASK) ) {
+ flush_tlb_all(); /* start new asid cycle */
+ if (!asid) /* fix version if needed */
+ asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
+ asid += ASID_FIRST_NONRESERVED;
+ }
+ mm->context = asid_cache = asid;
+}
+
+#else
+#warning ASID_{INVALID,KERNEL} values impose non-optimal get_new_mmu_context implementation
+
+/* XCHAL_MMU_ASID_INVALID == 0 and XCHAL_MMU_ASID_KERNEL ==1 are
+ really the best, but if you insist... */
+
+extern inline int validate_asid (unsigned long asid)
+{
+ switch (asid) {
+ case XCHAL_MMU_ASID_INVALID:
+ case XCHAL_MMU_ASID_KERNEL:
+ case ASID_RESERVED_1:
+ case ASID_RESERVED_2:
+ case ASID_RESERVED_3:
+ return 0; /* can't use these values as ASIDs */
+ }
+ return 1; /* valid */
+}
+
+extern inline void
+get_new_mmu_context(struct mm_struct *mm, unsigned long asid)
+{
+ extern void flush_tlb_all(void);
+ while (1) {
+ asid += ASID_INC;
+ if ( ! (asid & ASID_MASK) ) {
+ flush_tlb_all(); /* start new asid cycle */
+ if (!asid) /* fix version if needed */
+ asid = ASID_FIRST_VERSION - ASID_FIRST_NONRESERVED;
+ asid += ASID_FIRST_NONRESERVED;
+ break; /* no need to validate here */
+ }
+ if (validate_asid (asid & ASID_MASK))
+ break;
+ }
+ mm->context = asid_cache = asid;
+}
+
+#endif
+
+
+/*
+ * Initialize the context related info for a new mm_struct
+ * instance.
+ */
+
+extern inline int
+init_new_context(struct task_struct *tsk, struct mm_struct *mm)
+{
+ mm->context = NO_CONTEXT;
+ return 0;
+}
+
+extern inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ unsigned long asid = asid_cache;
+
+ /* Check if our ASID is of an older version and thus invalid */
+
+ if ((next->context ^ asid) & ASID_VERSION_MASK)
+ get_new_mmu_context(next, asid);
+
+ set_rasid_register (ASID_INSERT(next->context));
+ invalidate_page_directory();
+}
+
+#define deactivate_mm(tsk, mm) do { } while(0)
+
+/*
+ * Destroy context related info for an mm_struct that is about
+ * to be put to rest.
+ */
+extern inline void destroy_context(struct mm_struct *mm)
+{
+ /* Nothing to do. */
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+extern inline void
+activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ /* Unconditionally get a new ASID. */
+
+ get_new_mmu_context(next, asid_cache);
+ set_rasid_register (ASID_INSERT(next->context));
+ invalidate_page_directory();
+}
+
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+ /* Nothing to do. */
+
+}
+
+#endif /* _XTENSA_MMU_CONTEXT_H */
diff --git a/include/asm-xtensa/module.h b/include/asm-xtensa/module.h
new file mode 100644
index 000000000000..ffb25bfdf6a1
--- /dev/null
+++ b/include/asm-xtensa/module.h
@@ -0,0 +1,25 @@
+/*
+ * include/asm-xtensa/module.h
+ *
+ * This file contains the module code specific to the Xtensa architecture.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_MODULE_H
+#define _XTENSA_MODULE_H
+
+struct mod_arch_specific
+{
+ /* Module support is not completely implemented. */
+};
+
+#define Elf_Shdr Elf32_Shdr
+#define Elf_Sym Elf32_Sym
+#define Elf_Ehdr Elf32_Ehdr
+
+#endif /* _XTENSA_MODULE_H */
diff --git a/include/asm-xtensa/msgbuf.h b/include/asm-xtensa/msgbuf.h
new file mode 100644
index 000000000000..693c96755280
--- /dev/null
+++ b/include/asm-xtensa/msgbuf.h
@@ -0,0 +1,48 @@
+/*
+ * include/asm-xtensa/msgbuf.h
+ *
+ * The msqid64_ds structure for the Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ * 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.
+ */
+
+#ifndef _XTENSA_MSGBUF_H
+#define _XTENSA_MSGBUF_H
+
+struct msqid64_ds {
+ struct ipc64_perm msg_perm;
+#ifdef __XTENSA_EB__
+ unsigned int __unused1;
+ __kernel_time_t msg_stime; /* last msgsnd time */
+ unsigned int __unused2;
+ __kernel_time_t msg_rtime; /* last msgrcv time */
+ unsigned int __unused3;
+ __kernel_time_t msg_ctime; /* last change time */
+#elif defined(__XTENSA_EL__)
+ __kernel_time_t msg_stime; /* last msgsnd time */
+ unsigned int __unused1;
+ __kernel_time_t msg_rtime; /* last msgrcv time */
+ unsigned int __unused2;
+ __kernel_time_t msg_ctime; /* last change time */
+ unsigned int __unused3;
+#else
+# error processor byte order undefined!
+#endif
+ unsigned long msg_cbytes; /* current number of bytes on queue */
+ unsigned long msg_qnum; /* number of messages in queue */
+ unsigned long msg_qbytes; /* max number of bytes on queue */
+ __kernel_pid_t msg_lspid; /* pid of last msgsnd */
+ __kernel_pid_t msg_lrpid; /* last receive pid */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+#endif /* _XTENSA_MSGBUF_H */
diff --git a/include/asm-xtensa/namei.h b/include/asm-xtensa/namei.h
new file mode 100644
index 000000000000..3fdff039d27d
--- /dev/null
+++ b/include/asm-xtensa/namei.h
@@ -0,0 +1,26 @@
+/*
+ * include/asm-xtensa/namei.h
+ *
+ * Included from linux/fs/namei.c
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_NAMEI_H
+#define _XTENSA_NAMEI_H
+
+#ifdef __KERNEL__
+
+/* This dummy routine maybe changed to something useful
+ * for /usr/gnemul/ emulation stuff.
+ * Look at asm-sparc/namei.h for details.
+ */
+
+#define __emul_prefix() NULL
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_NAMEI_H */
diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h
new file mode 100644
index 000000000000..b495e5b5a942
--- /dev/null
+++ b/include/asm-xtensa/page.h
@@ -0,0 +1,133 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PAGE_H
+#define _XTENSA_PAGE_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/config.h>
+
+/*
+ * PAGE_SHIFT determines the page size
+ * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
+ */
+
+#define PAGE_SHIFT XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
+
+#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
+#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR
+
+#ifdef __ASSEMBLY__
+
+#define __pgprot(x) (x)
+
+#else
+
+/*
+ * These are used to make use of C type-checking..
+ */
+
+typedef struct { unsigned long pte; } pte_t; /* page table entry */
+typedef struct { unsigned long pgd; } pgd_t; /* PGD table entry */
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x) ((x).pte)
+#define pgd_val(x) ((x).pgd)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+/*
+ * Pure 2^n version of get_order
+ */
+
+extern __inline__ int get_order(unsigned long size)
+{
+ int order;
+#ifndef XCHAL_HAVE_NSU
+ unsigned long x1, x2, x4, x8, x16;
+
+ size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ x1 = size & 0xAAAAAAAA;
+ x2 = size & 0xCCCCCCCC;
+ x4 = size & 0xF0F0F0F0;
+ x8 = size & 0xFF00FF00;
+ x16 = size & 0xFFFF0000;
+ order = x2 ? 2 : 0;
+ order += (x16 != 0) * 16;
+ order += (x8 != 0) * 8;
+ order += (x4 != 0) * 4;
+ order += (x1 != 0);
+
+ return order;
+#else
+ size = (size - 1) >> PAGE_SHIFT;
+ asm ("nsau %0, %1" : "=r" (order) : "r" (size));
+ return 32 - order;
+#endif
+}
+
+
+struct page;
+extern void clear_page(void *page);
+extern void copy_page(void *to, void *from);
+
+/*
+ * If we have cache aliasing and writeback caches, we might have to do
+ * some extra work
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
+void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page);
+#else
+# define clear_user_page(page,vaddr,pg) clear_page(page)
+# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+#endif
+
+/*
+ * This handles the memory map. We handle pages at
+ * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
+ * These macros are for conversion of kernel address, not user
+ * addresses.
+ */
+
+#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define pfn_valid(pfn) ((unsigned long)pfn < max_mapnr)
+#ifndef CONFIG_DISCONTIGMEM
+# define pfn_to_page(pfn) (mem_map + (pfn))
+# define page_to_pfn(page) ((unsigned long)((page) - mem_map))
+#else
+# error CONFIG_DISCONTIGMEM not supported
+#endif
+
+#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+
+#define WANT_PAGE_VIRTUAL
+
+
+#endif /* __ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-xtensa/page.h.n b/include/asm-xtensa/page.h.n
new file mode 100644
index 000000000000..546cc6624f24
--- /dev/null
+++ b/include/asm-xtensa/page.h.n
@@ -0,0 +1,135 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PAGE_H
+#define _XTENSA_PAGE_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/config.h>
+
+/*
+ * PAGE_SHIFT determines the page size
+ * PAGE_ALIGN(x) aligns the pointer to the (next) page boundary
+ */
+#define PAGE_SHIFT XCHAL_MMU_MIN_PTE_PAGE_SIZE
+#define PAGE_SIZE (1 << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE-1))
+#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK)
+
+#define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE / XCHAL_DCACHE_WAYS)
+#define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR
+
+#ifdef __ASSEMBLY__
+
+#define __pgprot(x) (x)
+
+#else
+
+
+/*
+ * These are used to make use of C type-checking..
+ */
+typedef struct { unsigned long pte; } pte_t; /* page table entry */
+typedef struct { unsigned long pmd; } pmd_t; /* PMD table entry */
+typedef struct { unsigned long pgd; } pgd_t; /* PGD table entry */
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x) ((x).pte)
+#define pmd_val(x) ((x).pmd)
+#define pgd_val(x) ((x).pgd)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) } )
+#define __pmd(x) ((pmd_t) { (x) } )
+#define __pgd(x) ((pgd_t) { (x) } )
+#define __pgprot(x) ((pgprot_t) { (x) } )
+
+/*
+ * Pure 2^n version of get_order
+ */
+extern __inline__ int get_order(unsigned long size)
+{
+ int order;
+#ifndef XCHAL_HAVE_NSU
+ unsigned long x1, x2, x4, x8, x16;
+
+ size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ x1 = size & 0xAAAAAAAA;
+ x2 = size & 0xCCCCCCCC;
+ x4 = size & 0xF0F0F0F0;
+ x8 = size & 0xFF00FF00;
+ x16 = size & 0xFFFF0000;
+ order = x2 ? 2 : 0;
+ order += (x16 != 0) * 16;
+ order += (x8 != 0) * 8;
+ order += (x4 != 0) * 4;
+ order += (x1 != 0);
+
+ return order;
+#else
+ size = (size - 1) >> PAGE_SHIFT;
+ asm ("nsau %0, %1" : "=r" (order) : "r" (size));
+ return 32 - order;
+#endif
+}
+
+
+struct page;
+extern void clear_page(void *page);
+extern void copy_page(void *to, void *from);
+
+/*
+ * If we have cache aliasing and writeback caches, we might have to do
+ * some extra work
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+void clear_user_page(void *addr, unsigned long vaddr, struct page* page);
+void copy_user_page(void *to, void* from, unsigned long vaddr, struct page* page);
+#else
+# define clear_user_page(page,vaddr,pg) clear_page(page)
+# define copy_user_page(to, from, vaddr, pg) copy_page(to, from)
+#endif
+
+
+/*
+ * This handles the memory map. We handle pages at
+ * XCHAL_KSEG_CACHED_VADDR for kernels with 32 bit address space.
+ * These macros are for conversion of kernel address, not user
+ * addresses.
+ */
+
+#define __pa(x) ((unsigned long) (x) - PAGE_OFFSET)
+#define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET))
+#define pfn_valid(pfn) ((unsigned long)pfn < max_mapnr)
+#ifndef CONFIG_DISCONTIGMEM
+# define pfn_to_page(pfn) (mem_map + (pfn))
+# define page_to_pfn(page) ((unsigned long)((page) - mem_map))
+#else
+# error CONFIG_DISCONTIGMEM not supported
+#endif
+
+#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_virt(page) __va(page_to_pfn(page) << PAGE_SHIFT)
+#define virt_addr_valid(kaddr) pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
+#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
+
+#define WANT_PAGE_VIRTUAL
+
+
+#endif /* __ASSEMBLY__ */
+
+#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PAGE_H */
diff --git a/include/asm-xtensa/param.h b/include/asm-xtensa/param.h
new file mode 100644
index 000000000000..c0eec8260b0e
--- /dev/null
+++ b/include/asm-xtensa/param.h
@@ -0,0 +1,34 @@
+/*
+ * include/asm-xtensa/param.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PARAM_H
+#define _XTENSA_PARAM_H
+
+#include <xtensa/config/core.h>
+
+#ifdef __KERNEL__
+# define HZ 100 /* internal timer frequency */
+# define USER_HZ 100 /* for user interfaces in "ticks" */
+# define CLOCKS_PER_SEC (USER_HZ) /* frequnzy at which times() counts */
+#endif
+
+#define EXEC_PAGESIZE (1 << XCHAL_MMU_MIN_PTE_PAGE_SIZE)
+
+#ifndef NGROUPS
+#define NGROUPS 32
+#endif
+
+#ifndef NOGROUP
+#define NOGROUP (-1)
+#endif
+
+#define MAXHOSTNAMELEN 64 /* max length of hostname */
+
+#endif /* _XTENSA_PARAM_H */
diff --git a/include/asm-xtensa/pci-bridge.h b/include/asm-xtensa/pci-bridge.h
new file mode 100644
index 000000000000..00fcbd7c534a
--- /dev/null
+++ b/include/asm-xtensa/pci-bridge.h
@@ -0,0 +1,88 @@
+/*
+ * include/asm-xtensa/pci-bridge.h
+ *
+ * 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) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PCI_BRIDGE_H
+#define _XTENSA_PCI_BRIDGE_H
+
+#ifdef __KERNEL__
+
+struct device_node;
+struct pci_controller;
+
+/*
+ * pciauto_bus_scan() enumerates the pci space.
+ */
+
+extern int pciauto_bus_scan(struct pci_controller *, int);
+
+struct pci_space {
+ unsigned long start;
+ unsigned long end;
+ unsigned long base;
+};
+
+/*
+ * Structure of a PCI controller (host bridge)
+ */
+
+struct pci_controller {
+ int index; /* used for pci_controller_num */
+ struct pci_controller *next;
+ struct pci_bus *bus;
+ void *arch_data;
+
+ int first_busno;
+ int last_busno;
+
+ struct pci_ops *ops;
+ volatile unsigned int *cfg_addr;
+ volatile unsigned char *cfg_data;
+
+ /* Currently, we limit ourselves to 1 IO range and 3 mem
+ * ranges since the common pci_bus structure can't handle more
+ */
+ struct resource io_resource;
+ struct resource mem_resources[3];
+ int mem_resource_count;
+
+ /* Host bridge I/O and Memory space
+ * Used for BAR placement algorithms
+ */
+ struct pci_space io_space;
+ struct pci_space mem_space;
+
+ /* Return the interrupt number fo a device. */
+ int (*map_irq)(struct pci_dev*, u8, u8);
+
+};
+
+static inline void pcibios_init_resource(struct resource *res,
+ unsigned long start, unsigned long end, int flags, char *name)
+{
+ res->start = start;
+ res->end = end;
+ res->flags = flags;
+ res->name = name;
+ res->parent = NULL;
+ res->sibling = NULL;
+ res->child = NULL;
+}
+
+
+/* These are used for config access before all the PCI probing has been done. */
+int early_read_config_byte(struct pci_controller*, int, int, int, u8*);
+int early_read_config_word(struct pci_controller*, int, int, int, u16*);
+int early_read_config_dword(struct pci_controller*, int, int, int, u32*);
+int early_write_config_byte(struct pci_controller*, int, int, int, u8);
+int early_write_config_word(struct pci_controller*, int, int, int, u16);
+int early_write_config_dword(struct pci_controller*, int, int, int, u32);
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PCI_BRIDGE_H */
diff --git a/include/asm-xtensa/pci.h b/include/asm-xtensa/pci.h
new file mode 100644
index 000000000000..6817742301c2
--- /dev/null
+++ b/include/asm-xtensa/pci.h
@@ -0,0 +1,89 @@
+/*
+ * linux/include/asm-xtensa/pci.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PCI_H
+#define _XTENSA_PCI_H
+
+#ifdef __KERNEL__
+
+/* Can be used to override the logic in pci_scan_bus for skipping
+ * already-configured bus numbers - to be used for buggy BIOSes
+ * or architectures with incomplete PCI setup by the loader
+ */
+
+#define pcibios_assign_all_busses() 0
+
+extern struct pci_controller* pcibios_alloc_controller(void);
+
+extern inline void pcibios_set_master(struct pci_dev *dev)
+{
+ /* No special bus mastering setup handling */
+}
+
+extern inline void pcibios_penalize_isa_irq(int irq)
+{
+ /* We don't do dynamic PCI IRQ allocation */
+}
+
+/* Assume some values. (We should revise them, if necessary) */
+
+#define PCIBIOS_MIN_IO 0x2000
+#define PCIBIOS_MIN_MEM 0x10000000
+
+/* Dynamic DMA mapping stuff.
+ * Xtensa has everything mapped statically like x86.
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <asm/scatterlist.h>
+#include <linux/string.h>
+#include <asm/io.h>
+
+struct pci_dev;
+
+/* The PCI address space does equal the physical memory address space.
+ * The networking and block device layers use this boolean for bounce buffer
+ * decisions.
+ */
+
+#define PCI_DMA_BUS_IS_PHYS (1)
+
+/* pci_unmap_{page,single} is a no-op, so */
+#define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)
+#define DECLARE_PCI_UNMAP_LEN(LEN_NAME)
+#define pci_unmap_addr(PTR, ADDR_NAME) (0)
+#define pci_unmap_addr_set(PTR, ADDR_NAME, VAL) do { } while (0)
+#define pci_ubnmap_len(PTR, LEN_NAME) (0)
+#define pci_unmap_len_set(PTR, LEN_NAME, VAL) do { } while (0)
+
+/* We cannot access memory above 4GB */
+#define pci_dac_dma_supported(pci_dev, mask) (0)
+
+/* Map a range of PCI memory or I/O space for a device into user space */
+int pci_mmap_page_range(struct pci_dev *pdev, struct vm_area_struct *vma,
+ enum pci_mmap_state mmap_state, int write_combine);
+
+/* Tell drivers/pci/proc.c that we have pci_mmap_page_range() */
+#define HAVE_PCI_MMAP 1
+
+static inline void pcibios_add_platform_entries(struct pci_dev *dev)
+{
+}
+
+#endif /* __KERNEL__ */
+
+/* Implement the pci_ DMA API in terms of the generic device dma_ one */
+#include <asm-generic/pci-dma-compat.h>
+
+/* Generic PCI */
+#include <asm-generic/pci.h>
+
+#endif /* _XTENSA_PCI_H */
diff --git a/include/asm-xtensa/percpu.h b/include/asm-xtensa/percpu.h
new file mode 100644
index 000000000000..6d2bc2ada9d1
--- /dev/null
+++ b/include/asm-xtensa/percpu.h
@@ -0,0 +1,16 @@
+/*
+ * linux/include/asm-xtensa/percpu.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PERCPU__
+#define _XTENSA_PERCPU__
+
+#include <asm-generic/percpu.h>
+
+#endif /* _XTENSA_PERCPU__ */
diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h
new file mode 100644
index 000000000000..734a8d060395
--- /dev/null
+++ b/include/asm-xtensa/pgalloc.h
@@ -0,0 +1,116 @@
+/*
+ * linux/include/asm-xtensa/pgalloc.h
+ *
+ * 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.
+ *
+ * Copyright (C) 2001-2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PGALLOC_H
+#define _XTENSA_PGALLOC_H
+
+#ifdef __KERNEL__
+
+#include <linux/config.h>
+#include <linux/threads.h>
+#include <linux/highmem.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+
+
+/* Cache aliasing:
+ *
+ * If the cache size for one way is greater than the page size, we have to
+ * deal with cache aliasing. The cache index is wider than the page size:
+ *
+ * |cache |
+ * |pgnum |page| virtual address
+ * |xxxxxX|zzzz|
+ * | | |
+ * \ / | |
+ * trans.| |
+ * / \ | |
+ * |yyyyyY|zzzz| physical address
+ *
+ * When the page number is translated to the physical page address, the lowest
+ * bit(s) (X) that are also part of the cache index are also translated (Y).
+ * If this translation changes this bit (X), the cache index is also afected,
+ * thus resulting in a different cache line than before.
+ * The kernel does not provide a mechanism to ensure that the page color
+ * (represented by this bit) remains the same when allocated or when pages
+ * are remapped. When user pages are mapped into kernel space, the color of
+ * the page might also change.
+ *
+ * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2
+ * to temporarily map a patch so we can match the color.
+ */
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE)
+# define PAGE_COLOR_MASK (PAGE_MASK & (DCACHE_WAY_SIZE-1))
+# define PAGE_COLOR(a) \
+ (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT)
+# define PAGE_COLOR_EQ(a,b) \
+ ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0)
+# define PAGE_COLOR_MAP0(v) \
+ (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK))
+# define PAGE_COLOR_MAP1(v) \
+ (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE)
+#endif
+
+/*
+ * Allocating and freeing a pmd is trivial: the 1-entry pmd is
+ * inside the pgd, so has no extra memory associated with it.
+ */
+
+#define pgd_free(pgd) free_page((unsigned long)(pgd))
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+
+static inline void
+pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte)
+{
+ pmd_val(*(pmdp)) = (unsigned long)(pte);
+ __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+}
+
+static inline void
+pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page)
+{
+ pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page);
+ __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+}
+
+
+
+#else
+
+# define pmd_populate_kernel(mm, pmdp, pte) \
+ (pmd_val(*(pmdp)) = (unsigned long)(pte))
+# define pmd_populate(mm, pmdp, page) \
+ (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page))
+
+#endif
+
+static inline pgd_t*
+pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *pgd;
+
+ pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER);
+
+ if (likely(pgd != NULL))
+ __flush_dcache_page((unsigned long)pgd);
+
+ return pgd;
+}
+
+extern pte_t* pte_alloc_one_kernel(struct mm_struct* mm, unsigned long addr);
+extern struct page* pte_alloc_one(struct mm_struct* mm, unsigned long addr);
+
+#define pte_free_kernel(pte) free_page((unsigned long)pte)
+#define pte_free(pte) __free_page(pte)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h
new file mode 100644
index 000000000000..0bb6416ae266
--- /dev/null
+++ b/include/asm-xtensa/pgtable.h
@@ -0,0 +1,468 @@
+/*
+ * linux/include/asm-xtensa/page.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version2 as
+ * published by the Free Software Foundation.
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PGTABLE_H
+#define _XTENSA_PGTABLE_H
+
+#include <asm-generic/pgtable-nopmd.h>
+#include <asm/page.h>
+
+/* Assertions. */
+
+#ifdef CONFIG_MMU
+
+
+#if (XCHAL_MMU_RINGS < 2)
+# error Linux build assumes at least 2 ring levels.
+#endif
+
+#if (XCHAL_MMU_CA_BITS != 4)
+# error We assume exactly four bits for CA.
+#endif
+
+#if (XCHAL_MMU_SR_BITS != 0)
+# error We have no room for SR bits.
+#endif
+
+/*
+ * Use the first min-wired way for mapping page-table pages.
+ * Page coloring requires a second min-wired way.
+ */
+
+#if (XCHAL_DTLB_MINWIRED_SETS == 0)
+# error Need a min-wired way for mapping page-table pages
+#endif
+
+#define DTLB_WAY_PGTABLE XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAY)
+
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+# if XCHAL_DTLB_SET(XCHAL_DTLB_MINWIRED_SET0, WAYS) >= 2
+# define DTLB_WAY_DCACHE_ALIAS0 (DTLB_WAY_PGTABLE + 1)
+# define DTLB_WAY_DCACHE_ALIAS1 (DTLB_WAY_PGTABLE + 2)
+# else
+# error Page coloring requires its own wired dtlb way!
+# endif
+#endif
+
+#endif /* CONFIG_MMU */
+
+/*
+ * We only use two ring levels, user and kernel space.
+ */
+
+#define USER_RING 1 /* user ring level */
+#define KERNEL_RING 0 /* kernel ring level */
+
+/*
+ * The Xtensa architecture port of Linux has a two-level page table system,
+ * i.e. the logical three-level Linux page table layout are folded.
+ * Each task has the following memory page tables:
+ *
+ * PGD table (page directory), ie. 3rd-level page table:
+ * One page (4 kB) of 1024 (PTRS_PER_PGD) pointers to PTE tables
+ * (Architectures that don't have the PMD folded point to the PMD tables)
+ *
+ * The pointer to the PGD table for a given task can be retrieved from
+ * the task structure (struct task_struct*) t, e.g. current():
+ * (t->mm ? t->mm : t->active_mm)->pgd
+ *
+ * PMD tables (page middle-directory), ie. 2nd-level page tables:
+ * Absent for the Xtensa architecture (folded, PTRS_PER_PMD == 1).
+ *
+ * PTE tables (page table entry), ie. 1st-level page tables:
+ * One page (4 kB) of 1024 (PTRS_PER_PTE) PTEs with a special PTE
+ * invalid_pte_table for absent mappings.
+ *
+ * The individual pages are 4 kB big with special pages for the empty_zero_page.
+ */
+#define PGDIR_SHIFT 22
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * Entries per page directory level: we use two-level, so
+ * we don't really have any PMD directory physically.
+ */
+#define PTRS_PER_PTE 1024
+#define PTRS_PER_PTE_SHIFT 10
+#define PTRS_PER_PMD 1
+#define PTRS_PER_PGD 1024
+#define PGD_ORDER 0
+#define PMD_ORDER 0
+#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE)
+#define FIRST_USER_ADDRESS XCHAL_SEG_MAPPABLE_VADDR
+#define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT)
+
+/* virtual memory area. We keep a distance to other memory regions to be
+ * on the safe side. We also use this area for cache aliasing.
+ */
+
+// FIXME: virtual memory area must be configuration-dependent
+
+#define VMALLOC_START 0xC0000000
+#define VMALLOC_END 0xC7FF0000
+
+/* Xtensa Linux config PTE layout (when present):
+ * 31-12: PPN
+ * 11-6: Software
+ * 5-4: RING
+ * 3-0: CA
+ *
+ * Similar to the Alpha and MIPS ports, we need to keep track of the ref
+ * and mod bits in software. We have a software "you can read
+ * from this page" bit, and a hardware one which actually lets the
+ * process read from the page. On the same token we have a software
+ * writable bit and the real hardware one which actually lets the
+ * process write to the page.
+ *
+ * See further below for PTE layout for swapped-out pages.
+ */
+
+#define _PAGE_VALID (1<<0) /* hardware: page is accessible */
+#define _PAGE_WRENABLE (1<<1) /* hardware: page is writable */
+
+/* None of these cache modes include MP coherency: */
+#define _PAGE_NO_CACHE (0<<2) /* bypass, non-speculative */
+#if XCHAL_DCACHE_IS_WRITEBACK
+# define _PAGE_WRITEBACK (1<<2) /* write back */
+# define _PAGE_WRITETHRU (2<<2) /* write through */
+#else
+# define _PAGE_WRITEBACK (1<<2) /* assume write through */
+# define _PAGE_WRITETHRU (1<<2)
+#endif
+#define _PAGE_NOALLOC (3<<2) /* don't allocate cache,if not cached */
+#define _CACHE_MASK (3<<2)
+
+#define _PAGE_USER (1<<4) /* user access (ring=1) */
+#define _PAGE_KERNEL (0<<4) /* kernel access (ring=0) */
+
+/* Software */
+#define _PAGE_RW (1<<6) /* software: page writable */
+#define _PAGE_DIRTY (1<<7) /* software: page dirty */
+#define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */
+#define _PAGE_FILE (1<<9) /* nonlinear file mapping*/
+
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _CACHE_MASK | _PAGE_DIRTY)
+#define _PAGE_PRESENT ( _PAGE_VALID | _PAGE_WRITEBACK | _PAGE_ACCESSED)
+
+#ifdef CONFIG_MMU
+
+# define PAGE_NONE __pgprot(_PAGE_PRESENT)
+# define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_RW)
+# define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER)
+# define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER)
+# define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_KERNEL | _PAGE_WRENABLE)
+# define PAGE_INVALID __pgprot(_PAGE_USER)
+
+# if (DCACHE_WAY_SIZE > PAGE_SIZE)
+# define PAGE_DIRECTORY __pgprot(_PAGE_VALID | _PAGE_ACCESSED | _PAGE_KERNEL)
+# else
+# define PAGE_DIRECTORY __pgprot(_PAGE_PRESENT | _PAGE_KERNEL)
+# endif
+
+#else /* no mmu */
+
+# define PAGE_NONE __pgprot(0)
+# define PAGE_SHARED __pgprot(0)
+# define PAGE_COPY __pgprot(0)
+# define PAGE_READONLY __pgprot(0)
+# define PAGE_KERNEL __pgprot(0)
+
+#endif
+
+/*
+ * On certain configurations of Xtensa MMUs (eg. the initial Linux config),
+ * the MMU can't do page protection for execute, and considers that the same as
+ * read. Also, write permissions may imply read permissions.
+ * What follows is the closest we can get by reasonable means..
+ * See linux/mm/mmap.c for protection_map[] array that uses these definitions.
+ */
+#define __P000 PAGE_NONE /* private --- */
+#define __P001 PAGE_READONLY /* private --r */
+#define __P010 PAGE_COPY /* private -w- */
+#define __P011 PAGE_COPY /* private -wr */
+#define __P100 PAGE_READONLY /* private x-- */
+#define __P101 PAGE_READONLY /* private x-r */
+#define __P110 PAGE_COPY /* private xw- */
+#define __P111 PAGE_COPY /* private xwr */
+
+#define __S000 PAGE_NONE /* shared --- */
+#define __S001 PAGE_READONLY /* shared --r */
+#define __S010 PAGE_SHARED /* shared -w- */
+#define __S011 PAGE_SHARED /* shared -wr */
+#define __S100 PAGE_READONLY /* shared x-- */
+#define __S101 PAGE_READONLY /* shared x-r */
+#define __S110 PAGE_SHARED /* shared xw- */
+#define __S111 PAGE_SHARED /* shared xwr */
+
+#ifndef __ASSEMBLY__
+
+#define pte_ERROR(e) \
+ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e))
+#define pgd_ERROR(e) \
+ printk("%s:%d: bad pgd entry %08lx.\n", __FILE__, __LINE__, pgd_val(e))
+
+extern unsigned long empty_zero_page[1024];
+
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)];
+
+/*
+ * The pmd contains the kernel virtual address of the pte page.
+ */
+#define pmd_page_kernel(pmd) ((unsigned long)(pmd_val(pmd) & PAGE_MASK))
+#define pmd_page(pmd) virt_to_page(pmd_val(pmd))
+
+/*
+ * The following only work if pte_present() is true.
+ */
+#define pte_none(pte) (!(pte_val(pte) ^ _PAGE_USER))
+#define pte_present(pte) (pte_val(pte) & _PAGE_VALID)
+#define pte_clear(mm,addr,ptep) \
+ do { update_pte(ptep, __pte(_PAGE_USER)); } while(0)
+
+#define pmd_none(pmd) (!pmd_val(pmd))
+#define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK)
+#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0)
+#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)
+
+/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */
+
+static inline int pte_read(pte_t pte) { return pte_val(pte) & _PAGE_USER; }
+static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; }
+static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; }
+static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; }
+static inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) &= ~_PAGE_USER; return pte; }
+static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkread(pte_t pte) { pte_val(pte) |= _PAGE_USER; return pte; }
+static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; }
+static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; }
+static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; }
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT)
+#define pte_same(a,b) (pte_val(a) == pte_val(b))
+#define pte_page(x) pfn_to_page(pte_pfn(x))
+#define pfn_pte(pfn, prot) __pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
+#define mk_pte(page, prot) pfn_pte(page_to_pfn(page), prot)
+
+extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ return __pte((pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot));
+}
+
+/*
+ * Certain architectures need to do special things when pte's
+ * within a page table are directly modified. Thus, the following
+ * hook is made available.
+ */
+static inline void update_pte(pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+ __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (ptep));
+#endif
+}
+
+extern inline void
+set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep, pte_t pteval)
+{
+ update_pte(ptep, pteval);
+}
+
+
+extern inline void
+set_pmd(pmd_t *pmdp, pmd_t pmdval)
+{
+ *pmdp = pmdval;
+#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK
+ __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp));
+#endif
+}
+
+
+static inline int
+ptep_test_and_clear_young(struct vm_area_struct *vma, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ if (!pte_young(pte))
+ return 0;
+ update_pte(ptep, pte_mkold(pte));
+ return 1;
+}
+
+static inline int
+ptep_test_and_clear_dirty(struct vm_area_struct *vma, unsigned long addr,
+ pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ if (!pte_dirty(pte))
+ return 0;
+ update_pte(ptep, pte_mkclean(pte));
+ return 1;
+}
+
+static inline pte_t
+ptep_get_and_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ pte_clear(mm, addr, ptep);
+ return pte;
+}
+
+static inline void
+ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep)
+{
+ pte_t pte = *ptep;
+ update_pte(ptep, pte_wrprotect(pte));
+}
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(address) pgd_offset(&init_mm, address)
+
+/* to find an entry in a page-table-directory */
+#define pgd_offset(mm,address) ((mm)->pgd + pgd_index(address))
+
+#define pgd_index(address) ((address) >> PGDIR_SHIFT)
+
+/* Find an entry in the second-level page table.. */
+#define pmd_offset(dir,address) ((pmd_t*)(dir))
+
+/* Find an entry in the third-level page table.. */
+#define pte_index(address) (((address) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1))
+#define pte_offset_kernel(dir,addr) \
+ ((pte_t*) pmd_page_kernel(*(dir)) + pte_index(addr))
+#define pte_offset_map(dir,addr) pte_offset_kernel((dir),(addr))
+#define pte_offset_map_nested(dir,addr) pte_offset_kernel((dir),(addr))
+
+#define pte_unmap(pte) do { } while (0)
+#define pte_unmap_nested(pte) do { } while (0)
+
+
+/*
+ * Encode and decode a swap entry.
+ * Each PTE in a process VM's page table is either:
+ * "present" -- valid and not swapped out, protection bits are meaningful;
+ * "not present" -- which further subdivides in these two cases:
+ * "none" -- no mapping at all; identified by pte_none(), set by pte_clear(
+ * "swapped out" -- the page is swapped out, and the SWP macros below
+ * are used to store swap file info in the PTE itself.
+ *
+ * In the Xtensa processor MMU, any PTE entries in user space (or anywhere
+ * in virtual memory that can map differently across address spaces)
+ * must have a correct ring value that represents the RASID field that
+ * is changed when switching address spaces. Eg. such PTE entries cannot
+ * be set to ring zero, because that can cause a (global) kernel ASID
+ * entry to be created in the TLBs (even with invalid cache attribute),
+ * potentially causing a multihit exception when going back to another
+ * address space that mapped the same virtual address at another ring.
+ *
+ * SO: we avoid using ring bits (_PAGE_RING_MASK) in "not present" PTEs.
+ * We also avoid using the _PAGE_VALID bit which must be zero for non-present
+ * pages.
+ *
+ * We end up with the following available bits: 1..3 and 7..31.
+ * We don't bother with 1..3 for now (we can use them later if needed),
+ * and chose to allocate 6 bits for SWP_TYPE and the remaining 19 bits
+ * for SWP_OFFSET. At least 5 bits are needed for SWP_TYPE, because it
+ * is currently implemented as an index into swap_info[MAX_SWAPFILES]
+ * and MAX_SWAPFILES is currently defined as 32 in <linux/swap.h>.
+ * However, for some reason all other architectures in the 2.4 kernel
+ * reserve either 6, 7, or 8 bits so I'll not detract from that for now. :)
+ * SWP_OFFSET is an offset into the swap file in page-size units, so
+ * with 4 kB pages, 19 bits supports a maximum swap file size of 2 GB.
+ *
+ * FIXME: 2 GB isn't very big. Other bits can be used to allow
+ * larger swap sizes. In the meantime, it appears relatively easy to get
+ * around the 2 GB limitation by simply using multiple swap files.
+ */
+
+#define __swp_type(entry) (((entry).val >> 7) & 0x3f)
+#define __swp_offset(entry) ((entry).val >> 13)
+#define __swp_entry(type,offs) ((swp_entry_t) {((type) << 7) | ((offs) << 13)})
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+#define __swp_entry_to_pte(x) ((pte_t) { (x).val })
+
+#define PTE_FILE_MAX_BITS 29
+#define pte_to_pgoff(pte) (pte_val(pte) >> 3)
+#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE })
+
+
+#endif /* !defined (__ASSEMBLY__) */
+
+
+#ifdef __ASSEMBLY__
+
+/* Assembly macro _PGD_INDEX is the same as C pgd_index(unsigned long),
+ * _PGD_OFFSET as C pgd_offset(struct mm_struct*, unsigned long),
+ * _PMD_OFFSET as C pmd_offset(pgd_t*, unsigned long)
+ * _PTE_OFFSET as C pte_offset(pmd_t*, unsigned long)
+ *
+ * Note: We require an additional temporary register which can be the same as
+ * the register that holds the address.
+ *
+ * ((pte_t*) ((unsigned long)(pmd_val(*pmd) & PAGE_MASK)) + pte_index(addr))
+ *
+ */
+#define _PGD_INDEX(rt,rs) extui rt, rs, PGDIR_SHIFT, 32-PGDIR_SHIFT
+#define _PTE_INDEX(rt,rs) extui rt, rs, PAGE_SHIFT, PTRS_PER_PTE_SHIFT
+
+#define _PGD_OFFSET(mm,adr,tmp) l32i mm, mm, MM_PGD; \
+ _PGD_INDEX(tmp, adr); \
+ addx4 mm, tmp, mm
+
+#define _PTE_OFFSET(pmd,adr,tmp) _PTE_INDEX(tmp, adr); \
+ srli pmd, pmd, PAGE_SHIFT; \
+ slli pmd, pmd, PAGE_SHIFT; \
+ addx4 pmd, tmp, pmd
+
+#else
+
+extern void paging_init(void);
+
+#define kern_addr_valid(addr) (1)
+
+extern void update_mmu_cache(struct vm_area_struct * vma,
+ unsigned long address, pte_t pte);
+
+/*
+ * remap a physical address `phys' of size `size' with page protection `prot'
+ * into virtual address `from'
+ */
+#define io_remap_page_range(vma,from,phys,size,prot) \
+ remap_pfn_range(vma, from, (phys) >> PAGE_SHIFT, size, prot)
+
+
+/* No page table caches to init */
+
+#define pgtable_cache_init() do { } while (0)
+
+typedef pte_t *pte_addr_t;
+
+#endif /* !defined (__ASSEMBLY__) */
+
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_YOUNG
+#define __HAVE_ARCH_PTEP_TEST_AND_CLEAR_DIRTY
+#define __HAVE_ARCH_PTEP_GET_AND_CLEAR
+#define __HAVE_ARCH_PTEP_SET_WRPROTECT
+#define __HAVE_ARCH_PTEP_MKDIRTY
+#define __HAVE_ARCH_PTE_SAME
+
+#include <asm-generic/pgtable.h>
+
+#endif /* _XTENSA_PGTABLE_H */
diff --git a/include/asm-xtensa/platform-iss/hardware.h b/include/asm-xtensa/platform-iss/hardware.h
new file mode 100644
index 000000000000..22240f001803
--- /dev/null
+++ b/include/asm-xtensa/platform-iss/hardware.h
@@ -0,0 +1,29 @@
+/*
+ * include/asm-xtensa/platform-iss/hardware.h
+ *
+ * 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 Tensilica Inc.
+ */
+
+/*
+ * This file contains the default configuration of ISS.
+ */
+
+#ifndef __ASM_XTENSA_ISS_HARDWARE
+#define __ASM_XTENSA_ISS_HARDWARE
+
+/*
+ * Memory configuration.
+ */
+
+#define PLATFORM_DEFAULT_MEM_START XSHAL_RAM_PADDR
+#define PLATFORM_DEFAULT_MEM_SIZE XSHAL_RAM_VSIZE
+
+/*
+ * Interrupt configuration.
+ */
+
+#endif /* __ASM_XTENSA_ISS_HARDWARE */
diff --git a/include/asm-xtensa/platform.h b/include/asm-xtensa/platform.h
new file mode 100644
index 000000000000..36163894bc20
--- /dev/null
+++ b/include/asm-xtensa/platform.h
@@ -0,0 +1,92 @@
+/*
+ * include/asm-xtensa/platform.h
+ *
+ * Platform specific functions
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PLATFORM_H
+#define _XTENSA_PLATFORM_H
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+
+#include <asm/bootparam.h>
+
+/*
+ * platform_init is called before the mmu is initialized to give the
+ * platform a early hook-up. bp_tag_t is a list of configuration tags
+ * passed from the boot-loader.
+ */
+extern void platform_init(bp_tag_t*);
+
+/*
+ * platform_setup is called from setup_arch with a pointer to the command-line
+ * string.
+ */
+extern void platform_setup (char **);
+
+/*
+ * platform_init_irq is called from init_IRQ.
+ */
+extern void platform_init_irq (void);
+
+/*
+ * platform_restart is called to restart the system.
+ */
+extern void platform_restart (void);
+
+/*
+ * platform_halt is called to stop the system and halt.
+ */
+extern void platform_halt (void);
+
+/*
+ * platform_power_off is called to stop the system and power it off.
+ */
+extern void platform_power_off (void);
+
+/*
+ * platform_idle is called from the idle function.
+ */
+extern void platform_idle (void);
+
+/*
+ * platform_heartbeat is called every HZ
+ */
+extern void platform_heartbeat (void);
+
+/*
+ * platform_pcibios_init is called to allow the platform to setup the pci bus.
+ */
+extern void platform_pcibios_init (void);
+
+/*
+ * platform_pcibios_fixup allows to modify the PCI configuration.
+ */
+extern int platform_pcibios_fixup (void);
+
+/*
+ * platform_calibrate_ccount calibrates cpu clock freq (CONFIG_XTENSA_CALIBRATE)
+ */
+extern void platform_calibrate_ccount (void);
+
+/*
+ * platform_get_rtc_time returns RTC seconds (returns 0 for no error)
+ */
+extern int platform_get_rtc_time(time_t*);
+
+/*
+ * platform_set_rtc_time set RTC seconds (returns 0 for no error)
+ */
+extern int platform_set_rtc_time(time_t);
+
+
+#endif /* _XTENSA_PLATFORM_H */
+
diff --git a/include/asm-xtensa/poll.h b/include/asm-xtensa/poll.h
new file mode 100644
index 000000000000..dffe447534e0
--- /dev/null
+++ b/include/asm-xtensa/poll.h
@@ -0,0 +1,37 @@
+/*
+ * include/asm-xtensa/poll.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_POLL_H
+#define _XTENSA_POLL_H
+
+
+#define POLLIN 0x0001
+#define POLLPRI 0x0002
+#define POLLOUT 0x0004
+
+#define POLLERR 0x0008
+#define POLLHUP 0x0010
+#define POLLNVAL 0x0020
+
+#define POLLRDNORM 0x0040
+#define POLLRDBAND 0x0080
+#define POLLWRNORM POLLOUT
+#define POLLWRBAND 0x0100
+
+#define POLLMSG 0x0400
+#define POLLREMOVE 0x0800
+
+struct pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+#endif /* _XTENSA_POLL_H */
diff --git a/include/asm-xtensa/posix_types.h b/include/asm-xtensa/posix_types.h
new file mode 100644
index 000000000000..2c816b0e7762
--- /dev/null
+++ b/include/asm-xtensa/posix_types.h
@@ -0,0 +1,123 @@
+/*
+ * include/asm-xtensa/posix_types.h
+ *
+ * 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.
+ *
+ * Largely copied from include/asm-ppc/posix_types.h
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_POSIX_TYPES_H
+#define _XTENSA_POSIX_TYPES_H
+
+/*
+ * This file is generally used by user-level software, so you need to
+ * be a little careful about namespace pollution etc. Also, we cannot
+ * assume GCC is being used.
+ */
+
+typedef unsigned long __kernel_ino_t;
+typedef unsigned int __kernel_mode_t;
+typedef unsigned short __kernel_nlink_t;
+typedef long __kernel_off_t;
+typedef int __kernel_pid_t;
+typedef unsigned short __kernel_ipc_pid_t;
+typedef unsigned int __kernel_uid_t;
+typedef unsigned int __kernel_gid_t;
+typedef unsigned int __kernel_size_t;
+typedef int __kernel_ssize_t;
+typedef long __kernel_ptrdiff_t;
+typedef long __kernel_time_t;
+typedef long __kernel_suseconds_t;
+typedef long __kernel_clock_t;
+typedef int __kernel_timer_t;
+typedef int __kernel_clockid_t;
+typedef int __kernel_daddr_t;
+typedef char * __kernel_caddr_t;
+typedef unsigned short __kernel_uid16_t;
+typedef unsigned short __kernel_gid16_t;
+typedef unsigned int __kernel_uid32_t;
+typedef unsigned int __kernel_gid32_t;
+
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
+typedef unsigned short __kernel_old_dev_t;
+
+#ifdef __GNUC__
+typedef long long __kernel_loff_t;
+#endif
+
+typedef struct {
+ int val[2];
+} __kernel_fsid_t;
+
+#ifndef __GNUC__
+
+#define __FD_SET(d, set) ((set)->fds_bits[__FDELT(d)] |= __FDMASK(d))
+#define __FD_CLR(d, set) ((set)->fds_bits[__FDELT(d)] &= ~__FDMASK(d))
+#define __FD_ISSET(d, set) ((set)->fds_bits[__FDELT(d)] & __FDMASK(d))
+#define __FD_ZERO(set) \
+ ((void) memset ((__ptr_t) (set), 0, sizeof (__kernel_fd_set)))
+
+#else /* __GNUC__ */
+
+#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) \
+ || (__GLIBC__ == 2 && __GLIBC_MINOR__ == 0)
+/* With GNU C, use inline functions instead so args are evaluated only once: */
+
+#undef __FD_SET
+static __inline__ void __FD_SET(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ fdsetp->fds_bits[_tmp] |= (1UL<<_rem);
+}
+
+#undef __FD_CLR
+static __inline__ void __FD_CLR(unsigned long fd, __kernel_fd_set *fdsetp)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ fdsetp->fds_bits[_tmp] &= ~(1UL<<_rem);
+}
+
+#undef __FD_ISSET
+static __inline__ int __FD_ISSET(unsigned long fd, __kernel_fd_set *p)
+{
+ unsigned long _tmp = fd / __NFDBITS;
+ unsigned long _rem = fd % __NFDBITS;
+ return (p->fds_bits[_tmp] & (1UL<<_rem)) != 0;
+}
+
+/*
+ * This will unroll the loop for the normal constant case (8 ints,
+ * for a 256-bit fd_set)
+ */
+#undef __FD_ZERO
+static __inline__ void __FD_ZERO(__kernel_fd_set *p)
+{
+ unsigned int *tmp = (unsigned int *)p->fds_bits;
+ int i;
+
+ if (__builtin_constant_p(__FDSET_LONGS)) {
+ switch (__FDSET_LONGS) {
+ case 8:
+ tmp[0] = 0; tmp[1] = 0; tmp[2] = 0; tmp[3] = 0;
+ tmp[4] = 0; tmp[5] = 0; tmp[6] = 0; tmp[7] = 0;
+ return;
+ }
+ }
+ i = __FDSET_LONGS;
+ while (i) {
+ i--;
+ *tmp = 0;
+ tmp++;
+ }
+}
+
+#endif /* defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) */
+#endif /* __GNUC__ */
+#endif /* _XTENSA_POSIX_TYPES_H */
diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h
new file mode 100644
index 000000000000..9cab5e4298b9
--- /dev/null
+++ b/include/asm-xtensa/processor.h
@@ -0,0 +1,205 @@
+/*
+ * include/asm-xtensa/processor.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PROCESSOR_H
+#define _XTENSA_PROCESSOR_H
+
+#ifdef __ASSEMBLY__
+#define _ASMLANGUAGE
+#endif
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/specreg.h>
+#include <xtensa/config/tie.h>
+#include <xtensa/config/system.h>
+
+#include <asm/ptrace.h>
+#include <asm/types.h>
+#include <asm/coprocessor.h>
+
+/* Assertions. */
+
+#if (XCHAL_HAVE_WINDOWED != 1)
+#error Linux requires the Xtensa Windowed Registers Option.
+#endif
+
+/*
+ * User space process size: 1 GB.
+ * Windowed call ABI requires caller and callee to be located within the same
+ * 1 GB region. The C compiler places trampoline code on the stack for sources
+ * that take the address of a nested C function (a feature used by glibc), so
+ * the 1 GB requirement applies to the stack as well.
+ */
+
+#define TASK_SIZE 0x40000000
+
+/*
+ * General exception cause assigned to debug exceptions. Debug exceptions go
+ * to their own vector, rather than the general exception vectors (user,
+ * kernel, double); and their specific causes are reported via DEBUGCAUSE
+ * rather than EXCCAUSE. However it is sometimes convenient to redirect debug
+ * exceptions to the general exception mechanism. To do this, an otherwise
+ * unused EXCCAUSE value was assigned to debug exceptions for this purpose.
+ */
+
+#define EXCCAUSE_MAPPED_DEBUG 63
+
+/*
+ * We use DEPC also as a flag to distinguish between double and regular
+ * exceptions. For performance reasons, DEPC might contain the value of
+ * EXCCAUSE for regular exceptions, so we use this definition to mark a
+ * valid double exception address.
+ * (Note: We use it in bgeui, so it should be 64, 128, or 256)
+ */
+
+#define VALID_DOUBLE_EXCEPTION_ADDRESS 64
+
+/* LOCKLEVEL defines the interrupt level that masks all
+ * general-purpose interrupts.
+ */
+#define LOCKLEVEL 1
+
+/* WSBITS and WBBITS are the width of the WINDOWSTART and WINDOWBASE
+ * registers
+ */
+#define WSBITS (XCHAL_NUM_AREGS / 4) /* width of WINDOWSTART in bits */
+#define WBBITS (XCHAL_NUM_AREGS_LOG2 - 2) /* width of WINDOWBASE in bits */
+
+#ifndef __ASSEMBLY__
+
+/* Build a valid return address for the specified call winsize.
+ * winsize must be 1 (call4), 2 (call8), or 3 (call12)
+ */
+#define MAKE_RA_FOR_CALL(ra,ws) (((ra) & 0x3fffffff) | (ws) << 30)
+
+/* Convert return address to a valid pc
+ * Note: We assume that the stack pointer is in the same 1GB ranges as the ra
+ */
+#define MAKE_PC_FROM_RA(ra,sp) (((ra) & 0x3fffffff) | ((sp) & 0xc0000000))
+
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+struct thread_struct {
+
+ /* kernel's return address and stack pointer for context switching */
+ unsigned long ra; /* kernel's a0: return address and window call size */
+ unsigned long sp; /* kernel's a1: stack pointer */
+
+ mm_segment_t current_ds; /* see uaccess.h for example uses */
+
+ /* struct xtensa_cpuinfo info; */
+
+ unsigned long bad_vaddr; /* last user fault */
+ unsigned long bad_uaddr; /* last kernel fault accessing user space */
+ unsigned long error_code;
+
+ unsigned long ibreak[XCHAL_NUM_IBREAK];
+ unsigned long dbreaka[XCHAL_NUM_DBREAK];
+ unsigned long dbreakc[XCHAL_NUM_DBREAK];
+
+ /* Allocate storage for extra state and coprocessor state. */
+ unsigned char cp_save[XTENSA_CP_EXTRA_SIZE]
+ __attribute__ ((aligned(XTENSA_CP_EXTRA_ALIGN)));
+
+ /* Make structure 16 bytes aligned. */
+ int align[0] __attribute__ ((aligned(16)));
+};
+
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l;})
+
+
+/* This decides where the kernel will search for a free chunk of vm
+ * space during mmap's.
+ */
+#define TASK_UNMAPPED_BASE (TASK_SIZE / 2)
+
+#define INIT_THREAD \
+{ \
+ ra: 0, \
+ sp: sizeof(init_stack) + (long) &init_stack, \
+ current_ds: {0}, \
+ /*info: {0}, */ \
+ bad_vaddr: 0, \
+ bad_uaddr: 0, \
+ error_code: 0, \
+}
+
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ * Note: We set-up ps as if we did a call4 to the new pc.
+ * set_thread_state in signal.c depends on it.
+ */
+#define USER_PS_VALUE ( (1 << XCHAL_PS_WOE_SHIFT) + \
+ (1 << XCHAL_PS_CALLINC_SHIFT) + \
+ (USER_RING << XCHAL_PS_RING_SHIFT) + \
+ (1 << XCHAL_PS_PROGSTACK_SHIFT) + \
+ (1 << XCHAL_PS_EXCM_SHIFT) )
+
+/* Clearing a0 terminates the backtrace. */
+#define start_thread(regs, new_pc, new_sp) \
+ regs->pc = new_pc; \
+ regs->ps = USER_PS_VALUE; \
+ regs->areg[1] = new_sp; \
+ regs->areg[0] = 0; \
+ regs->wmask = 1; \
+ regs->depc = 0; \
+ regs->windowbase = 0; \
+ regs->windowstart = 1;
+
+/* Forward declaration */
+struct task_struct;
+struct mm_struct;
+
+// FIXME: do we need release_thread for CP??
+/* Free all resources held by a thread. */
+#define release_thread(thread) do { } while(0)
+
+// FIXME: do we need prepare_to_copy (lazy status) for CP??
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk) do { } while (0)
+
+/*
+ * create a kernel thread without removing it from tasklists
+ */
+extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);
+
+/* Copy and release all segment info associated with a VM */
+
+#define copy_segments(p, mm) do { } while(0)
+#define release_segments(mm) do { } while(0)
+#define forget_segments() do { } while (0)
+
+#define thread_saved_pc(tsk) (xtensa_pt_regs(tsk)->pc)
+
+extern unsigned long get_wchan(struct task_struct *p);
+
+#define KSTK_EIP(tsk) (xtensa_pt_regs(tsk)->pc)
+#define KSTK_ESP(tsk) (xtensa_pt_regs(tsk)->areg[1])
+
+#define cpu_relax() do { } while (0)
+
+/* Special register access. */
+
+#define WSR(v,sr) __asm__ __volatile__ ("wsr %0,"__stringify(sr) :: "a"(v));
+#define RSR(v,sr) __asm__ __volatile__ ("rsr %0,"__stringify(sr) : "=a"(v));
+
+#define set_sr(x,sr) ({unsigned int v=(unsigned int)x; WSR(v,sr);})
+#define get_sr(sr) ({unsigned int v; RSR(v,sr); v; })
+
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_PROCESSOR_H */
diff --git a/include/asm-xtensa/ptrace.h b/include/asm-xtensa/ptrace.h
new file mode 100644
index 000000000000..2848a5ff8349
--- /dev/null
+++ b/include/asm-xtensa/ptrace.h
@@ -0,0 +1,135 @@
+/*
+ * include/asm-xtensa/ptrace.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_PTRACE_H
+#define _XTENSA_PTRACE_H
+
+#include <xtensa/config/core.h>
+
+/*
+ * Kernel stack
+ *
+ * +-----------------------+ -------- STACK_SIZE
+ * | register file | |
+ * +-----------------------+ |
+ * | struct pt_regs | |
+ * +-----------------------+ | ------ PT_REGS_OFFSET
+ * double : 16 bytes spill area : | ^
+ * excetion :- - - - - - - - - - - -: | |
+ * frame : struct pt_regs : | |
+ * :- - - - - - - - - - - -: | |
+ * | | | |
+ * | memory stack | | |
+ * | | | |
+ * ~ ~ ~ ~
+ * ~ ~ ~ ~
+ * | | | |
+ * | | | |
+ * +-----------------------+ | | --- STACK_BIAS
+ * | struct task_struct | | | ^
+ * current --> +-----------------------+ | | |
+ * | struct thread_info | | | |
+ * +-----------------------+ --------
+ */
+
+#define KERNEL_STACK_SIZE (2 * PAGE_SIZE)
+
+/* Offsets for exception_handlers[] (3 x 64-entries x 4-byte tables). */
+
+#define EXC_TABLE_KSTK 0x004 /* Kernel Stack */
+#define EXC_TABLE_DOUBLE_SAVE 0x008 /* Double exception save area for a0 */
+#define EXC_TABLE_FIXUP 0x00c /* Fixup handler */
+#define EXC_TABLE_PARAM 0x010 /* For passing a parameter to fixup */
+#define EXC_TABLE_SYSCALL_SAVE 0x014 /* For fast syscall handler */
+#define EXC_TABLE_FAST_USER 0x100 /* Fast user exception handler */
+#define EXC_TABLE_FAST_KERNEL 0x200 /* Fast kernel exception handler */
+#define EXC_TABLE_DEFAULT 0x300 /* Default C-Handler */
+#define EXC_TABLE_SIZE 0x400
+
+/* Registers used by strace */
+
+#define REG_A_BASE 0xfc000000
+#define REG_AR_BASE 0x04000000
+#define REG_PC 0x14000000
+#define REG_PS 0x080000e6
+#define REG_WB 0x08000048
+#define REG_WS 0x08000049
+#define REG_LBEG 0x08000000
+#define REG_LEND 0x08000001
+#define REG_LCOUNT 0x08000002
+#define REG_SAR 0x08000003
+#define REG_DEPC 0x080000c0
+#define REG_EXCCAUSE 0x080000e8
+#define REG_EXCVADDR 0x080000ee
+#define SYSCALL_NR 0x1
+
+#define AR_REGNO_TO_A_REGNO(ar, wb) (ar - wb*4) & ~(XCHAL_NUM_AREGS - 1)
+
+/* Other PTRACE_ values defined in <linux/ptrace.h> using values 0-9,16,17,24 */
+
+#define PTRACE_GETREGS 12
+#define PTRACE_SETREGS 13
+#define PTRACE_GETFPREGS 14
+#define PTRACE_SETFPREGS 15
+#define PTRACE_GETFPREGSIZE 18
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This struct defines the way the registers are stored on the
+ * kernel stack during a system call or other kernel entry.
+ */
+struct pt_regs {
+ unsigned long pc; /* 4 */
+ unsigned long ps; /* 8 */
+ unsigned long depc; /* 12 */
+ unsigned long exccause; /* 16 */
+ unsigned long excvaddr; /* 20 */
+ unsigned long debugcause; /* 24 */
+ unsigned long wmask; /* 28 */
+ unsigned long lbeg; /* 32 */
+ unsigned long lend; /* 36 */
+ unsigned long lcount; /* 40 */
+ unsigned long sar; /* 44 */
+ unsigned long windowbase; /* 48 */
+ unsigned long windowstart; /* 52 */
+ unsigned long syscall; /* 56 */
+ int reserved[2]; /* 64 */
+
+ /* Make sure the areg field is 16 bytes aligned. */
+ int align[0] __attribute__ ((aligned(16)));
+
+ /* current register frame.
+ * Note: The ESF for kernel exceptions ends after 16 registers!
+ */
+ unsigned long areg[16]; /* 128 (64) */
+};
+
+#ifdef __KERNEL__
+# define xtensa_pt_regs(tsk) ((struct pt_regs*) \
+ (((long)(tsk)->thread_info + KERNEL_STACK_SIZE - (XCHAL_NUM_AREGS-16)*4)) - 1)
+# define user_mode(regs) (((regs)->ps & 0x00000020)!=0)
+# define instruction_pointer(regs) ((regs)->pc)
+extern void show_regs(struct pt_regs *);
+
+# ifndef CONFIG_SMP
+# define profile_pc(regs) instruction_pointer(regs)
+# endif
+#endif /* __KERNEL__ */
+
+#else /* __ASSEMBLY__ */
+
+#ifdef __KERNEL__
+# include <asm/offsets.h>
+#define PT_REGS_OFFSET (KERNEL_STACK_SIZE - PT_USER_SIZE)
+#endif
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _XTENSA_PTRACE_H */
diff --git a/include/asm-xtensa/resource.h b/include/asm-xtensa/resource.h
new file mode 100644
index 000000000000..17b5ab311771
--- /dev/null
+++ b/include/asm-xtensa/resource.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/resource.h
+ *
+ * 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) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RESOURCE_H
+#define _XTENSA_RESOURCE_H
+
+#include <asm-generic/resource.h>
+
+#endif /* _XTENSA_RESOURCE_H */
diff --git a/include/asm-xtensa/rmap.h b/include/asm-xtensa/rmap.h
new file mode 100644
index 000000000000..649588b7e9ad
--- /dev/null
+++ b/include/asm-xtensa/rmap.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/rmap.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RMAP_H
+#define _XTENSA_RMAP_H
+
+#include <asm-generic/rmap.h>
+
+#endif
diff --git a/include/asm-xtensa/rwsem.h b/include/asm-xtensa/rwsem.h
new file mode 100644
index 000000000000..3c02b0e033f0
--- /dev/null
+++ b/include/asm-xtensa/rwsem.h
@@ -0,0 +1,175 @@
+/*
+ * include/asm-xtensa/rwsem.h
+ *
+ * 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.
+ *
+ * Largely copied from include/asm-ppc/rwsem.h
+ *
+ * Copyright (C) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_RWSEM_H
+#define _XTENSA_RWSEM_H
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+#include <asm/system.h>
+
+/*
+ * the semaphore definition
+ */
+struct rw_semaphore {
+ signed long count;
+#define RWSEM_UNLOCKED_VALUE 0x00000000
+#define RWSEM_ACTIVE_BIAS 0x00000001
+#define RWSEM_ACTIVE_MASK 0x0000ffff
+#define RWSEM_WAITING_BIAS (-0x00010000)
+#define RWSEM_ACTIVE_READ_BIAS RWSEM_ACTIVE_BIAS
+#define RWSEM_ACTIVE_WRITE_BIAS (RWSEM_WAITING_BIAS + RWSEM_ACTIVE_BIAS)
+ spinlock_t wait_lock;
+ struct list_head wait_list;
+#if RWSEM_DEBUG
+ int debug;
+#endif
+};
+
+/*
+ * initialisation
+ */
+#if RWSEM_DEBUG
+#define __RWSEM_DEBUG_INIT , 0
+#else
+#define __RWSEM_DEBUG_INIT /* */
+#endif
+
+#define __RWSEM_INITIALIZER(name) \
+ { RWSEM_UNLOCKED_VALUE, SPIN_LOCK_UNLOCKED, \
+ LIST_HEAD_INIT((name).wait_list) \
+ __RWSEM_DEBUG_INIT }
+
+#define DECLARE_RWSEM(name) \
+ struct rw_semaphore name = __RWSEM_INITIALIZER(name)
+
+extern struct rw_semaphore *rwsem_down_read_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_down_write_failed(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_wake(struct rw_semaphore *sem);
+extern struct rw_semaphore *rwsem_downgrade_wake(struct rw_semaphore *sem);
+
+static inline void init_rwsem(struct rw_semaphore *sem)
+{
+ sem->count = RWSEM_UNLOCKED_VALUE;
+ spin_lock_init(&sem->wait_lock);
+ INIT_LIST_HEAD(&sem->wait_list);
+#if RWSEM_DEBUG
+ sem->debug = 0;
+#endif
+}
+
+/*
+ * lock for reading
+ */
+static inline void __down_read(struct rw_semaphore *sem)
+{
+ if (atomic_add_return(1,(atomic_t *)(&sem->count)) > 0)
+ smp_wmb();
+ else
+ rwsem_down_read_failed(sem);
+}
+
+static inline int __down_read_trylock(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ while ((tmp = sem->count) >= 0) {
+ if (tmp == cmpxchg(&sem->count, tmp,
+ tmp + RWSEM_ACTIVE_READ_BIAS)) {
+ smp_wmb();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * lock for writing
+ */
+static inline void __down_write(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = atomic_add_return(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_t *)(&sem->count));
+ if (tmp == RWSEM_ACTIVE_WRITE_BIAS)
+ smp_wmb();
+ else
+ rwsem_down_write_failed(sem);
+}
+
+static inline int __down_write_trylock(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ tmp = cmpxchg(&sem->count, RWSEM_UNLOCKED_VALUE,
+ RWSEM_ACTIVE_WRITE_BIAS);
+ smp_wmb();
+ return tmp == RWSEM_UNLOCKED_VALUE;
+}
+
+/*
+ * unlock after reading
+ */
+static inline void __up_read(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ smp_wmb();
+ tmp = atomic_sub_return(1,(atomic_t *)(&sem->count));
+ if (tmp < -1 && (tmp & RWSEM_ACTIVE_MASK) == 0)
+ rwsem_wake(sem);
+}
+
+/*
+ * unlock after writing
+ */
+static inline void __up_write(struct rw_semaphore *sem)
+{
+ smp_wmb();
+ if (atomic_sub_return(RWSEM_ACTIVE_WRITE_BIAS,
+ (atomic_t *)(&sem->count)) < 0)
+ rwsem_wake(sem);
+}
+
+/*
+ * implement atomic add functionality
+ */
+static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem)
+{
+ atomic_add(delta, (atomic_t *)(&sem->count));
+}
+
+/*
+ * downgrade write lock to read lock
+ */
+static inline void __downgrade_write(struct rw_semaphore *sem)
+{
+ int tmp;
+
+ smp_wmb();
+ tmp = atomic_add_return(-RWSEM_WAITING_BIAS, (atomic_t *)(&sem->count));
+ if (tmp < 0)
+ rwsem_downgrade_wake(sem);
+}
+
+/*
+ * implement exchange and add functionality
+ */
+static inline int rwsem_atomic_update(int delta, struct rw_semaphore *sem)
+{
+ smp_mb();
+ return atomic_add_return(delta, (atomic_t *)(&sem->count));
+}
+
+#endif /* _XTENSA_RWSEM_XADD_H */
diff --git a/include/asm-xtensa/scatterlist.h b/include/asm-xtensa/scatterlist.h
new file mode 100644
index 000000000000..38a2b9acd658
--- /dev/null
+++ b/include/asm-xtensa/scatterlist.h
@@ -0,0 +1,34 @@
+/*
+ * include/asm-xtensa/scatterlist.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SCATTERLIST_H
+#define _XTENSA_SCATTERLIST_H
+
+struct scatterlist {
+ struct page *page;
+ unsigned int offset;
+ dma_addr_t dma_address;
+ unsigned int length;
+};
+
+/*
+ * These macros should be used after a pci_map_sg call has been done
+ * to get bus addresses of each of the SG entries and their lengths.
+ * You should only work with the number of sg entries pci_map_sg
+ * returns, or alternatively stop on the first sg_dma_len(sg) which
+ * is 0.
+ */
+#define sg_dma_address(sg) ((sg)->dma_address)
+#define sg_dma_len(sg) ((sg)->length)
+
+
+#define ISA_DMA_THRESHOLD (~0UL)
+
+#endif /* _XTENSA_SCATTERLIST_H */
diff --git a/include/asm-xtensa/sections.h b/include/asm-xtensa/sections.h
new file mode 100644
index 000000000000..40b5191b55a2
--- /dev/null
+++ b/include/asm-xtensa/sections.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/sections.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SECTIONS_H
+#define _XTENSA_SECTIONS_H
+
+#include <asm-generic/sections.h>
+
+#endif /* _XTENSA_SECTIONS_H */
diff --git a/include/asm-xtensa/segment.h b/include/asm-xtensa/segment.h
new file mode 100644
index 000000000000..a2eb547a1a75
--- /dev/null
+++ b/include/asm-xtensa/segment.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/segment.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SEGMENT_H
+#define _XTENSA_SEGMENT_H
+
+#include <asm/uaccess.h>
+
+#endif /* _XTENSA_SEGEMENT_H */
diff --git a/include/asm-xtensa/semaphore.h b/include/asm-xtensa/semaphore.h
new file mode 100644
index 000000000000..c8a7574a9a57
--- /dev/null
+++ b/include/asm-xtensa/semaphore.h
@@ -0,0 +1,129 @@
+/*
+ * linux/include/asm-xtensa/semaphore.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SEMAPHORE_H
+#define _XTENSA_SEMAPHORE_H
+
+#include <asm/atomic.h>
+#include <asm/system.h>
+#include <linux/wait.h>
+#include <linux/rwsem.h>
+
+struct semaphore {
+ atomic_t count;
+ int sleepers;
+ wait_queue_head_t wait;
+#if WAITQUEUE_DEBUG
+ long __magic;
+#endif
+};
+
+#if WAITQUEUE_DEBUG
+# define __SEM_DEBUG_INIT(name) \
+ , (int)&(name).__magic
+#else
+# define __SEM_DEBUG_INIT(name)
+#endif
+
+#define __SEMAPHORE_INITIALIZER(name,count) \
+ { ATOMIC_INIT(count), \
+ 0, \
+ __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \
+ __SEM_DEBUG_INIT(name) }
+
+#define __MUTEX_INITIALIZER(name) \
+ __SEMAPHORE_INITIALIZER(name, 1)
+
+#define __DECLARE_SEMAPHORE_GENERIC(name,count) \
+ struct semaphore name = __SEMAPHORE_INITIALIZER(name,count)
+
+#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1)
+#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0)
+
+extern inline void sema_init (struct semaphore *sem, int val)
+{
+/*
+ * *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val);
+ *
+ * i'd rather use the more flexible initialization above, but sadly
+ * GCC 2.7.2.3 emits a bogus warning. EGCS doesnt. Oh well.
+ */
+ atomic_set(&sem->count, val);
+ init_waitqueue_head(&sem->wait);
+#if WAITQUEUE_DEBUG
+ sem->__magic = (int)&sem->__magic;
+#endif
+}
+
+static inline void init_MUTEX (struct semaphore *sem)
+{
+ sema_init(sem, 1);
+}
+
+static inline void init_MUTEX_LOCKED (struct semaphore *sem)
+{
+ sema_init(sem, 0);
+}
+
+asmlinkage void __down(struct semaphore * sem);
+asmlinkage int __down_interruptible(struct semaphore * sem);
+asmlinkage int __down_trylock(struct semaphore * sem);
+asmlinkage void __up(struct semaphore * sem);
+
+extern spinlock_t semaphore_wake_lock;
+
+extern __inline__ void down(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ __down(sem);
+}
+
+extern __inline__ int down_interruptible(struct semaphore * sem)
+{
+ int ret = 0;
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ ret = __down_interruptible(sem);
+ return ret;
+}
+
+extern __inline__ int down_trylock(struct semaphore * sem)
+{
+ int ret = 0;
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+
+ if (atomic_sub_return(1, &sem->count) < 0)
+ ret = __down_trylock(sem);
+ return ret;
+}
+
+/*
+ * Note! This is subtle. We jump to wake people up only if
+ * the semaphore was negative (== somebody was waiting on it).
+ */
+extern __inline__ void up(struct semaphore * sem)
+{
+#if WAITQUEUE_DEBUG
+ CHECK_MAGIC(sem->__magic);
+#endif
+ if (atomic_add_return(1, &sem->count) <= 0)
+ __up(sem);
+}
+
+#endif /* _XTENSA_SEMAPHORE_H */
diff --git a/include/asm-xtensa/sembuf.h b/include/asm-xtensa/sembuf.h
new file mode 100644
index 000000000000..2d26c47666fe
--- /dev/null
+++ b/include/asm-xtensa/sembuf.h
@@ -0,0 +1,44 @@
+/*
+ * include/asm-xtensa/sembuf.h
+ *
+ * The semid64_ds structure for Xtensa architecture.
+ *
+ * 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 - 2005 Tensilica Inc.
+ *
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ */
+
+#ifndef _XTENSA_SEMBUF_H
+#define _XTENSA_SEMBUF_H
+
+#include <asm/byteorder.h>
+
+struct semid64_ds {
+ struct ipc64_perm sem_perm; /* permissions .. see ipc.h */
+#if XCHAL_HAVE_LE
+ __kernel_time_t sem_otime; /* last semop time */
+ unsigned long __unused1;
+ __kernel_time_t sem_ctime; /* last change time */
+ unsigned long __unused2;
+#else
+ unsigned long __unused1;
+ __kernel_time_t sem_otime; /* last semop time */
+ unsigned long __unused2;
+ __kernel_time_t sem_ctime; /* last change time */
+#endif
+ unsigned long sem_nsems; /* no. of semaphores in array */
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* __ASM_XTENSA_SEMBUF_H */
diff --git a/include/asm-xtensa/serial.h b/include/asm-xtensa/serial.h
new file mode 100644
index 000000000000..ec04114fcf0b
--- /dev/null
+++ b/include/asm-xtensa/serial.h
@@ -0,0 +1,18 @@
+/*
+ * include/asm-xtensa/serial.h
+ *
+ * Configuration details for 8250, 16450, 16550, etc. serial ports
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SERIAL_H
+#define _XTENSA_SERIAL_H
+
+#include <asm/platform/serial.h>
+
+#endif /* _XTENSA_SERIAL_H */
diff --git a/include/asm-xtensa/setup.h b/include/asm-xtensa/setup.h
new file mode 100644
index 000000000000..e3636520d8cc
--- /dev/null
+++ b/include/asm-xtensa/setup.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/setup.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SETUP_H
+#define _XTENSA_SETUP_H
+
+#define COMMAND_LINE_SIZE 256
+
+#endif
diff --git a/include/asm-xtensa/shmbuf.h b/include/asm-xtensa/shmbuf.h
new file mode 100644
index 000000000000..a30b81a4b933
--- /dev/null
+++ b/include/asm-xtensa/shmbuf.h
@@ -0,0 +1,50 @@
+/*
+ * include/asm-xtensa/shmbuf.h
+ *
+ * The shmid64_ds structure for Xtensa architecture.
+ * Note extra padding because this structure is passed back and forth
+ * between kernel and user space.
+ *
+ * Pad space is left for:
+ * - 64-bit time_t to solve y2038 problem
+ * - 2 miscellaneous 32-bit values
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SHMBUF_H
+#define _XTENSA_SHMBUF_H
+
+struct shmid64_ds {
+ struct ipc64_perm shm_perm; /* operation perms */
+ size_t shm_segsz; /* size of segment (bytes) */
+ __kernel_time_t shm_atime; /* last attach time */
+ unsigned long __unused1;
+ __kernel_time_t shm_dtime; /* last detach time */
+ unsigned long __unused2;
+ __kernel_time_t shm_ctime; /* last change time */
+ unsigned long __unused3;
+ __kernel_pid_t shm_cpid; /* pid of creator */
+ __kernel_pid_t shm_lpid; /* pid of last operator */
+ unsigned long shm_nattch; /* no. of current attaches */
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+struct shminfo64 {
+ unsigned long shmmax;
+ unsigned long shmmin;
+ unsigned long shmmni;
+ unsigned long shmseg;
+ unsigned long shmall;
+ unsigned long __unused1;
+ unsigned long __unused2;
+ unsigned long __unused3;
+ unsigned long __unused4;
+};
+
+#endif /* _XTENSA_SHMBUF_H */
diff --git a/include/asm-xtensa/shmparam.h b/include/asm-xtensa/shmparam.h
new file mode 100644
index 000000000000..d3b65bfa71c3
--- /dev/null
+++ b/include/asm-xtensa/shmparam.h
@@ -0,0 +1,23 @@
+/*
+ * include/asm-xtensa/shmparam.h
+ *
+ * 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.
+ */
+
+#ifndef _XTENSA_SHMPARAM_H
+#define _XTENSA_SHMPARAM_H
+
+#include <asm/processor.h>
+
+/*
+ * Xtensa can have variable size caches, and if
+ * the size of single way is larger than the page size,
+ * then we have to start worrying about cache aliasing
+ * problems.
+ */
+
+#define SHMLBA ((PAGE_SIZE > DCACHE_WAY_SIZE)? PAGE_SIZE : DCACHE_WAY_SIZE)
+
+#endif /* _XTENSA_SHMPARAM_H */
diff --git a/include/asm-xtensa/sigcontext.h b/include/asm-xtensa/sigcontext.h
new file mode 100644
index 000000000000..a75177291418
--- /dev/null
+++ b/include/asm-xtensa/sigcontext.h
@@ -0,0 +1,44 @@
+/*
+ * include/asm-xtensa/sigcontext.h
+ *
+ * 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 - 2003 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGCONTEXT_H
+#define _XTENSA_SIGCONTEXT_H
+
+#define _ASMLANGUAGE
+#include <asm/processor.h>
+#include <asm/coprocessor.h>
+
+
+struct _cpstate {
+ unsigned char _cpstate[XTENSA_CP_EXTRA_SIZE];
+} __attribute__ ((aligned (XTENSA_CP_EXTRA_ALIGN)));
+
+
+struct sigcontext {
+ unsigned long oldmask;
+
+ /* CPU registers */
+ unsigned long sc_pc;
+ unsigned long sc_ps;
+ unsigned long sc_wmask;
+ unsigned long sc_windowbase;
+ unsigned long sc_windowstart;
+ unsigned long sc_lbeg;
+ unsigned long sc_lend;
+ unsigned long sc_lcount;
+ unsigned long sc_sar;
+ unsigned long sc_depc;
+ unsigned long sc_dareg0;
+ unsigned long sc_treg[4];
+ unsigned long sc_areg[XCHAL_NUM_AREGS];
+ struct _cpstate *sc_cpstate;
+};
+
+#endif /* __ASM_XTENSA_SIGCONTEXT_H */
diff --git a/include/asm-xtensa/siginfo.h b/include/asm-xtensa/siginfo.h
new file mode 100644
index 000000000000..44f0ae77b539
--- /dev/null
+++ b/include/asm-xtensa/siginfo.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/processor.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGINFO_H
+#define _XTENSA_SIGINFO_H
+
+#include <asm-generic/siginfo.h>
+
+#endif /* _XTENSA_SIGINFO_H */
diff --git a/include/asm-xtensa/signal.h b/include/asm-xtensa/signal.h
new file mode 100644
index 000000000000..5d6fc9cdf58d
--- /dev/null
+++ b/include/asm-xtensa/signal.h
@@ -0,0 +1,187 @@
+/*
+ * include/asm-xtensa/signal.h
+ *
+ * Swiped from 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) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SIGNAL_H
+#define _XTENSA_SIGNAL_H
+
+
+#define _NSIG 64
+#define _NSIG_BPW 32
+#define _NSIG_WORDS (_NSIG / _NSIG_BPW)
+
+#ifndef __ASSEMBLY__
+
+#include <linux/types.h>
+
+/* Avoid too many header ordering problems. */
+struct siginfo;
+typedef unsigned long old_sigset_t; /* at least 32 bits */
+typedef struct {
+ unsigned long sig[_NSIG_WORDS];
+} sigset_t;
+
+#endif
+
+#define SIGHUP 1
+#define SIGINT 2
+#define SIGQUIT 3
+#define SIGILL 4
+#define SIGTRAP 5
+#define SIGABRT 6
+#define SIGIOT 6
+#define SIGBUS 7
+#define SIGFPE 8
+#define SIGKILL 9
+#define SIGUSR1 10
+#define SIGSEGV 11
+#define SIGUSR2 12
+#define SIGPIPE 13
+#define SIGALRM 14
+#define SIGTERM 15
+#define SIGSTKFLT 16
+#define SIGCHLD 17
+#define SIGCONT 18
+#define SIGSTOP 19
+#define SIGTSTP 20
+#define SIGTTIN 21
+#define SIGTTOU 22
+#define SIGURG 23
+#define SIGXCPU 24
+#define SIGXFSZ 25
+#define SIGVTALRM 26
+#define SIGPROF 27
+#define SIGWINCH 28
+#define SIGIO 29
+#define SIGPOLL SIGIO
+/* #define SIGLOST 29 */
+#define SIGPWR 30
+#define SIGSYS 31
+#define SIGUNUSED 31
+
+/* These should not be considered constants from userland. */
+#define SIGRTMIN 32
+#define SIGRTMAX (_NSIG-1)
+
+/*
+ * SA_FLAGS values:
+ *
+ * SA_ONSTACK indicates that a registered stack_t will be used.
+ * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the
+ * SA_RESTART flag to get restarting signals (which were the default long ago)
+ * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop.
+ * SA_RESETHAND clears the handler when the signal is delivered.
+ * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies.
+ * SA_NODEFER prevents the current signal from being masked in the handler.
+ *
+ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single
+ * Unix names RESETHAND and NODEFER respectively.
+ */
+#define SA_NOCLDSTOP 0x00000001
+#define SA_NOCLDWAIT 0x00000002 /* not supported yet */
+#define SA_SIGINFO 0x00000004
+#define SA_ONSTACK 0x08000000
+#define SA_RESTART 0x10000000
+#define SA_NODEFER 0x40000000
+#define SA_RESETHAND 0x80000000
+
+#define SA_NOMASK SA_NODEFER
+#define SA_ONESHOT SA_RESETHAND
+#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */
+
+#define SA_RESTORER 0x04000000
+
+/*
+ * sigaltstack controls
+ */
+#define SS_ONSTACK 1
+#define SS_DISABLE 2
+
+#define MINSIGSTKSZ 2048
+#define SIGSTKSZ 8192
+
+#ifndef __ASSEMBLY__
+#ifdef __KERNEL__
+
+/*
+ * These values of sa_flags are used only by the kernel as part of the
+ * irq handling routines.
+ *
+ * SA_INTERRUPT is also used by the irq handling routines.
+ * SA_SHIRQ is for shared interrupt support on PCI and EISA.
+ */
+#define SA_PROBE SA_ONESHOT
+#define SA_SAMPLE_RANDOM SA_RESTART
+#define SA_SHIRQ 0x04000000
+#endif
+
+#define SIG_BLOCK 0 /* for blocking signals */
+#define SIG_UNBLOCK 1 /* for unblocking signals */
+#define SIG_SETMASK 2 /* for setting the signal mask */
+
+/* Type of a signal handler. */
+typedef void (*__sighandler_t)(int);
+
+#define SIG_DFL ((__sighandler_t)0) /* default signal handling */
+#define SIG_IGN ((__sighandler_t)1) /* ignore signal */
+#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */
+
+#ifdef __KERNEL__
+struct old_sigaction {
+ __sighandler_t sa_handler;
+ old_sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+};
+
+struct sigaction {
+ __sighandler_t sa_handler;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ sigset_t sa_mask; /* mask last for extensibility */
+};
+
+struct k_sigaction {
+ struct sigaction sa;
+};
+
+#else
+
+/* Here we must cater to libcs that poke about in kernel headers. */
+
+struct sigaction {
+ union {
+ __sighandler_t _sa_handler;
+ void (*_sa_sigaction)(int, struct siginfo *, void *);
+ } _u;
+ sigset_t sa_mask;
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+};
+
+#define sa_handler _u._sa_handler
+#define sa_sigaction _u._sa_sigaction
+
+#endif /* __KERNEL__ */
+
+typedef struct sigaltstack {
+ void *ss_sp;
+ int ss_flags;
+ size_t ss_size;
+} stack_t;
+
+#ifdef __KERNEL__
+#include <asm/sigcontext.h>
+#define ptrace_signal_deliver(regs, cookie) do { } while (0)
+
+#endif /* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_SIGNAL_H */
diff --git a/include/asm-xtensa/smp.h b/include/asm-xtensa/smp.h
new file mode 100644
index 000000000000..83c569e3bdbd
--- /dev/null
+++ b/include/asm-xtensa/smp.h
@@ -0,0 +1,27 @@
+/*
+ * include/asm-xtensa/smp.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SMP_H
+#define _XTENSA_SMP_H
+
+extern struct xtensa_cpuinfo boot_cpu_data;
+
+#define cpu_data (&boot_cpu_data)
+#define current_cpu_data boot_cpu_data
+
+struct xtensa_cpuinfo {
+ unsigned long *pgd_cache;
+ unsigned long *pte_cache;
+ unsigned long pgtable_cache_sz;
+};
+
+#define cpu_logical_map(cpu) (cpu)
+
+#endif /* _XTENSA_SMP_H */
diff --git a/include/asm-xtensa/socket.h b/include/asm-xtensa/socket.h
new file mode 100644
index 000000000000..daccd05a14cd
--- /dev/null
+++ b/include/asm-xtensa/socket.h
@@ -0,0 +1,61 @@
+/*
+ * include/asm-xtensa/socket.h
+ *
+ * Copied from i386.
+ *
+ * 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.
+ */
+
+#ifndef _XTENSA_SOCKET_H
+#define _XTENSA_SOCKET_H
+
+#include <asm/sockios.h>
+
+/* For setsockoptions(2) */
+#define SOL_SOCKET 1
+
+#define SO_DEBUG 1
+#define SO_REUSEADDR 2
+#define SO_TYPE 3
+#define SO_ERROR 4
+#define SO_DONTROUTE 5
+#define SO_BROADCAST 6
+#define SO_SNDBUF 7
+#define SO_RCVBUF 8
+#define SO_KEEPALIVE 9
+#define SO_OOBINLINE 10
+#define SO_NO_CHECK 11
+#define SO_PRIORITY 12
+#define SO_LINGER 13
+#define SO_BSDCOMPAT 14
+/* To add :#define SO_REUSEPORT 15 */
+#define SO_PASSCRED 16
+#define SO_PEERCRED 17
+#define SO_RCVLOWAT 18
+#define SO_SNDLOWAT 19
+#define SO_RCVTIMEO 20
+#define SO_SNDTIMEO 21
+
+/* Security levels - as per NRL IPv6 - don't actually do anything */
+
+#define SO_SECURITY_AUTHENTICATION 22
+#define SO_SECURITY_ENCRYPTION_TRANSPORT 23
+#define SO_SECURITY_ENCRYPTION_NETWORK 24
+
+#define SO_BINDTODEVICE 25
+
+/* Socket filtering */
+
+#define SO_ATTACH_FILTER 26
+#define SO_DETACH_FILTER 27
+
+#define SO_PEERNAME 28
+#define SO_TIMESTAMP 29
+#define SCM_TIMESTAMP SO_TIMESTAMP
+
+#define SO_ACCEPTCONN 30
+#define SO_PEERSEC 31
+
+#endif /* _XTENSA_SOCKET_H */
diff --git a/include/asm-xtensa/sockios.h b/include/asm-xtensa/sockios.h
new file mode 100644
index 000000000000..20d2ba10ecd1
--- /dev/null
+++ b/include/asm-xtensa/sockios.h
@@ -0,0 +1,30 @@
+/*
+ * include/asm-xtensa/sockios.h
+ *
+ * Socket-level I/O control calls. Copied from MIPS.
+ *
+ * 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 Ralf Baechle
+ * Copyright (C) 2001 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SOCKIOS_H
+#define _XTENSA_SOCKIOS_H
+
+#include <asm/ioctl.h>
+
+/* Socket-level I/O control calls. */
+
+#define FIOGETOWN _IOR('f', 123, int)
+#define FIOSETOWN _IOW('f', 124, int)
+
+#define SIOCATMARK _IOR('s', 7, int)
+#define SIOCSPGRP _IOW('s', 8, pid_t)
+#define SIOCGPGRP _IOR('s', 9, pid_t)
+
+#define SIOCGSTAMP 0x8906 /* Get stamp - linux-specific */
+
+#endif /* _XTENSA_SOCKIOS_H */
diff --git a/include/asm-xtensa/spinlock.h b/include/asm-xtensa/spinlock.h
new file mode 100644
index 000000000000..8ff23649581b
--- /dev/null
+++ b/include/asm-xtensa/spinlock.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/spinlock.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SPINLOCK_H
+#define _XTENSA_SPINLOCK_H
+
+#include <linux/spinlock.h>
+
+#endif /* _XTENSA_SPINLOCK_H */
diff --git a/include/asm-xtensa/stat.h b/include/asm-xtensa/stat.h
new file mode 100644
index 000000000000..2f4662ff6c3a
--- /dev/null
+++ b/include/asm-xtensa/stat.h
@@ -0,0 +1,105 @@
+/*
+ * include/asm-xtensa/stat.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_STAT_H
+#define _XTENSA_STAT_H
+
+#include <linux/types.h>
+
+struct __old_kernel_stat {
+ unsigned short st_dev;
+ unsigned short st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned long st_size;
+ unsigned long st_atime;
+ unsigned long st_mtime;
+ unsigned long st_ctime;
+};
+
+#define STAT_HAVE_NSEC 1
+
+struct stat {
+ unsigned short st_dev;
+ unsigned short __pad1;
+ unsigned long st_ino;
+ unsigned short st_mode;
+ unsigned short st_nlink;
+ unsigned short st_uid;
+ unsigned short st_gid;
+ unsigned short st_rdev;
+ unsigned short __pad2;
+ unsigned long st_size;
+ unsigned long st_blksize;
+ unsigned long st_blocks;
+ unsigned long st_atime;
+ unsigned long st_atime_nsec;
+ unsigned long st_mtime;
+ unsigned long st_mtime_nsec;
+ unsigned long st_ctime;
+ unsigned long st_ctime_nsec;
+ unsigned long __unused4;
+ unsigned long __unused5;
+};
+
+/* This matches struct stat64 in glibc-2.2.3. */
+
+struct stat64 {
+#ifdef __XTENSA_EL__
+ unsigned short st_dev; /* Device */
+ unsigned char __pad0[10];
+#else
+ unsigned char __pad0[6];
+ unsigned short st_dev;
+ unsigned char __pad1[2];
+#endif
+
+#define STAT64_HAS_BROKEN_ST_INO 1
+ unsigned long __st_ino; /* 32bit file serial number. */
+
+ unsigned int st_mode; /* File mode. */
+ unsigned int st_nlink; /* Link count. */
+ unsigned int st_uid; /* User ID of the file's owner. */
+ unsigned int st_gid; /* Group ID of the file's group. */
+
+#ifdef __XTENSA_EL__
+ unsigned short st_rdev; /* Device number, if device. */
+ unsigned char __pad3[10];
+#else
+ unsigned char __pad2[6];
+ unsigned short st_rdev;
+ unsigned char __pad3[2];
+#endif
+
+ long long int st_size; /* Size of file, in bytes. */
+ long int st_blksize; /* Optimal block size for I/O. */
+
+#ifdef __XTENSA_EL__
+ unsigned long st_blocks; /* Number 512-byte blocks allocated. */
+ unsigned long __pad4;
+#else
+ unsigned long __pad4;
+ unsigned long st_blocks;
+#endif
+
+ unsigned long __pad5;
+ long int st_atime; /* Time of last access. */
+ unsigned long st_atime_nsec;
+ long int st_mtime; /* Time of last modification. */
+ unsigned long st_mtime_nsec;
+ long int st_ctime; /* Time of last status change. */
+ unsigned long st_ctime_nsec;
+ unsigned long long int st_ino; /* File serial number. */
+};
+
+#endif /* _XTENSA_STAT_H */
diff --git a/include/asm-xtensa/statfs.h b/include/asm-xtensa/statfs.h
new file mode 100644
index 000000000000..9c3d1a213136
--- /dev/null
+++ b/include/asm-xtensa/statfs.h
@@ -0,0 +1,17 @@
+/*
+ * include/asm-xtensa/statfs.h
+ *
+ * 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) 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_STATFS_H
+#define _XTENSA_STATFS_H
+
+#include <asm-generic/statfs.h>
+
+#endif /* _XTENSA_STATFS_H */
+
diff --git a/include/asm-xtensa/string.h b/include/asm-xtensa/string.h
new file mode 100644
index 000000000000..3f81b27d9809
--- /dev/null
+++ b/include/asm-xtensa/string.h
@@ -0,0 +1,124 @@
+/*
+ * include/asm-xtensa/string.h
+ *
+ * These trivial string functions are considered part of the public domain.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+/* We should optimize these. See arch/xtensa/lib/strncpy_user.S */
+
+#ifndef _XTENSA_STRING_H
+#define _XTENSA_STRING_H
+
+#define __HAVE_ARCH_STRCPY
+extern __inline__ char *strcpy(char *__dest, const char *__src)
+{
+ register char *__xdest = __dest;
+ unsigned long __dummy;
+
+ __asm__ __volatile__("1:\n\t"
+ "l8ui %2, %1, 0\n\t"
+ "s8i %2, %0, 0\n\t"
+ "addi %1, %1, 1\n\t"
+ "addi %0, %0, 1\n\t"
+ "bnez %2, 1b\n\t"
+ : "=r" (__dest), "=r" (__src), "=&r" (__dummy)
+ : "0" (__dest), "1" (__src)
+ : "memory");
+
+ return __xdest;
+}
+
+#define __HAVE_ARCH_STRNCPY
+extern __inline__ char *strncpy(char *__dest, const char *__src, size_t __n)
+{
+ register char *__xdest = __dest;
+ unsigned long __dummy;
+
+ if (__n == 0)
+ return __xdest;
+
+ __asm__ __volatile__(
+ "1:\n\t"
+ "l8ui %2, %1, 0\n\t"
+ "s8i %2, %0, 0\n\t"
+ "addi %1, %1, 1\n\t"
+ "addi %0, %0, 1\n\t"
+ "beqz %2, 2f\n\t"
+ "bne %1, %5, 1b\n"
+ "2:"
+ : "=r" (__dest), "=r" (__src), "=&r" (__dummy)
+ : "0" (__dest), "1" (__src), "r" (__src+__n)
+ : "memory");
+
+ return __xdest;
+}
+
+#define __HAVE_ARCH_STRCMP
+extern __inline__ int strcmp(const char *__cs, const char *__ct)
+{
+ register int __res;
+ unsigned long __dummy;
+
+ __asm__ __volatile__(
+ "1:\n\t"
+ "l8ui %3, %1, 0\n\t"
+ "addi %1, %1, 1\n\t"
+ "l8ui %2, %0, 0\n\t"
+ "addi %0, %0, 1\n\t"
+ "beqz %2, 2f\n\t"
+ "beq %2, %3, 1b\n"
+ "2:\n\t"
+ "sub %2, %3, %2"
+ : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy)
+ : "0" (__cs), "1" (__ct));
+
+ return __res;
+}
+
+#define __HAVE_ARCH_STRNCMP
+extern __inline__ int strncmp(const char *__cs, const char *__ct, size_t __n)
+{
+ register int __res;
+ unsigned long __dummy;
+
+ __asm__ __volatile__(
+ "mov %2, %3\n"
+ "1:\n\t"
+ "beq %0, %6, 2f\n\t"
+ "l8ui %3, %1, 0\n\t"
+ "addi %1, %1, 1\n\t"
+ "l8ui %2, %0, 0\n\t"
+ "addi %0, %0, 1\n\t"
+ "beqz %2, 2f\n\t"
+ "beqz %3, 2f\n\t"
+ "beq %2, %3, 1b\n"
+ "2:\n\t"
+ "sub %2, %3, %2"
+ : "=r" (__cs), "=r" (__ct), "=&r" (__res), "=&r" (__dummy)
+ : "0" (__cs), "1" (__ct), "r" (__cs+__n));
+
+ return __res;
+}
+
+#define __HAVE_ARCH_MEMSET
+extern void *memset(void *__s, int __c, size_t __count);
+
+#define __HAVE_ARCH_MEMCPY
+extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
+
+#define __HAVE_ARCH_MEMMOVE
+extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
+
+/* Don't build bcopy at all ... */
+#define __HAVE_ARCH_BCOPY
+
+#define __HAVE_ARCH_MEMSCAN
+#define memscan memchr
+
+#endif /* _XTENSA_STRING_H */
diff --git a/include/asm-xtensa/system.h b/include/asm-xtensa/system.h
new file mode 100644
index 000000000000..690fe325e671
--- /dev/null
+++ b/include/asm-xtensa/system.h
@@ -0,0 +1,252 @@
+/*
+ * include/asm-xtensa/system.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_SYSTEM_H
+#define _XTENSA_SYSTEM_H
+
+#include <linux/config.h>
+#include <linux/stringify.h>
+
+#include <asm/processor.h>
+
+/* interrupt control */
+
+#define local_save_flags(x) \
+ __asm__ __volatile__ ("rsr %0,"__stringify(PS) : "=a" (x));
+#define local_irq_restore(x) do { \
+ __asm__ __volatile__ ("wsr %0, "__stringify(PS)" ; rsync" \
+ :: "a" (x) : "memory"); } while(0);
+#define local_irq_save(x) do { \
+ __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL) \
+ : "=a" (x) :: "memory");} while(0);
+
+static inline void local_irq_disable(void)
+{
+ unsigned long flags;
+ __asm__ __volatile__ ("rsil %0, "__stringify(LOCKLEVEL)
+ : "=a" (flags) :: "memory");
+}
+static inline void local_irq_enable(void)
+{
+ unsigned long flags;
+ __asm__ __volatile__ ("rsil %0, 0" : "=a" (flags) :: "memory");
+
+}
+
+static inline int irqs_disabled(void)
+{
+ unsigned long flags;
+ local_save_flags(flags);
+ return flags & 0xf;
+}
+
+#define RSR_CPENABLE(x) do { \
+ __asm__ __volatile__("rsr %0," __stringify(CPENABLE) : "=a" (x)); \
+ } while(0);
+#define WSR_CPENABLE(x) do { \
+ __asm__ __volatile__("wsr %0," __stringify(CPENABLE)";rsync" \
+ :: "a" (x));} while(0);
+
+#define clear_cpenable() __clear_cpenable()
+
+extern __inline__ void __clear_cpenable(void)
+{
+#if XCHAL_HAVE_CP
+ unsigned long i = 0;
+ WSR_CPENABLE(i);
+#endif
+}
+
+extern __inline__ void enable_coprocessor(int i)
+{
+#if XCHAL_HAVE_CP
+ int cp;
+ RSR_CPENABLE(cp);
+ cp |= 1 << i;
+ WSR_CPENABLE(cp);
+#endif
+}
+
+extern __inline__ void disable_coprocessor(int i)
+{
+#if XCHAL_HAVE_CP
+ int cp;
+ RSR_CPENABLE(cp);
+ cp &= ~(1 << i);
+ WSR_CPENABLE(cp);
+#endif
+}
+
+#define smp_read_barrier_depends() do { } while(0)
+#define read_barrier_depends() do { } while(0)
+
+#define mb() barrier()
+#define rmb() mb()
+#define wmb() mb()
+
+#ifdef CONFIG_SMP
+#error smp_* not defined
+#else
+#define smp_mb() barrier()
+#define smp_rmb() barrier()
+#define smp_wmb() barrier()
+#endif
+
+#define set_mb(var, value) do { var = value; mb(); } while (0)
+#define set_wmb(var, value) do { var = value; wmb(); } while (0)
+
+#if !defined (__ASSEMBLY__)
+
+/* * switch_to(n) should switch tasks to task nr n, first
+ * checking that n isn't the current task, in which case it does nothing.
+ */
+extern void *_switch_to(void *last, void *next);
+
+#endif /* __ASSEMBLY__ */
+
+#define prepare_to_switch() do { } while(0)
+
+#define switch_to(prev,next,last) \
+do { \
+ clear_cpenable(); \
+ (last) = _switch_to(prev, next); \
+} while(0)
+
+/*
+ * cmpxchg
+ */
+
+extern __inline__ unsigned long
+__cmpxchg_u32(volatile int *p, int old, int new)
+{
+ __asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %1, 0 \n\t"
+ "bne %0, %2, 1f \n\t"
+ "s32i %3, %1, 0 \n\t"
+ "1: \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n\t"
+ : "=&a" (old)
+ : "a" (p), "a" (old), "r" (new)
+ : "a15", "memory");
+ return old;
+}
+/* This function doesn't exist, so you'll get a linker error
+ * if something tries to do an invalid cmpxchg(). */
+
+extern void __cmpxchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__cmpxchg(volatile void *ptr, unsigned long old, unsigned long new, int size)
+{
+ switch (size) {
+ case 4: return __cmpxchg_u32(ptr, old, new);
+ default: __cmpxchg_called_with_bad_pointer();
+ return old;
+ }
+}
+
+#define cmpxchg(ptr,o,n) \
+ ({ __typeof__(*(ptr)) _o_ = (o); \
+ __typeof__(*(ptr)) _n_ = (n); \
+ (__typeof__(*(ptr))) __cmpxchg((ptr), (unsigned long)_o_, \
+ (unsigned long)_n_, sizeof (*(ptr))); \
+ })
+
+
+
+
+/*
+ * xchg_u32
+ *
+ * Note that a15 is used here because the register allocation
+ * done by the compiler is not guaranteed and a window overflow
+ * may not occur between the rsil and wsr instructions. By using
+ * a15 in the rsil, the machine is guaranteed to be in a state
+ * where no register reference will cause an overflow.
+ */
+
+extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("rsil a15, "__stringify(LOCKLEVEL)"\n\t"
+ "l32i %0, %1, 0 \n\t"
+ "s32i %2, %1, 0 \n\t"
+ "wsr a15, "__stringify(PS)" \n\t"
+ "rsync \n\t"
+ : "=&a" (tmp)
+ : "a" (m), "a" (val)
+ : "a15", "memory");
+ return tmp;
+}
+
+#define tas(ptr) (xchg((ptr),1))
+
+#if ( __XCC__ == 1 )
+
+/* xt-xcc processes __inline__ differently than xt-gcc and decides to
+ * insert an out-of-line copy of function __xchg. This presents the
+ * unresolved symbol at link time of __xchg_called_with_bad_pointer,
+ * even though such a function would never be called at run-time.
+ * xt-gcc always inlines __xchg, and optimizes away the undefined
+ * bad_pointer function.
+ */
+
+#define xchg(ptr,x) xchg_u32(ptr,x)
+
+#else /* assume xt-gcc */
+
+#define xchg(ptr,x) ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr))))
+
+/*
+ * This only works if the compiler isn't horribly bad at optimizing.
+ * gcc-2.5.8 reportedly can't handle this, but I define that one to
+ * be dead anyway.
+ */
+
+extern void __xchg_called_with_bad_pointer(void);
+
+static __inline__ unsigned long
+__xchg(unsigned long x, volatile void * ptr, int size)
+{
+ switch (size) {
+ case 4:
+ return xchg_u32(ptr, x);
+ }
+ __xchg_called_with_bad_pointer();
+ return x;
+}
+
+#endif
+
+extern void set_except_vector(int n, void *addr);
+
+static inline void spill_registers(void)
+{
+ unsigned int a0, ps;
+
+ __asm__ __volatile__ (
+ "movi a14," __stringify (PS_EXCM_MASK) " | 1\n\t"
+ "mov a12, a0\n\t"
+ "rsr a13," __stringify(SAR) "\n\t"
+ "xsr a14," __stringify(PS) "\n\t"
+ "movi a0, _spill_registers\n\t"
+ "rsync\n\t"
+ "callx0 a0\n\t"
+ "mov a0, a12\n\t"
+ "wsr a13," __stringify(SAR) "\n\t"
+ "wsr a14," __stringify(PS) "\n\t"
+ :: "a" (&a0), "a" (&ps)
+ : "a2", "a3", "a12", "a13", "a14", "a15", "memory");
+}
+
+#define arch_align_stack(x) (x)
+
+#endif /* _XTENSA_SYSTEM_H */
diff --git a/include/asm-xtensa/termbits.h b/include/asm-xtensa/termbits.h
new file mode 100644
index 000000000000..c780593ff5f9
--- /dev/null
+++ b/include/asm-xtensa/termbits.h
@@ -0,0 +1,194 @@
+/*
+ * include/asm-xtensa/termbits.h
+ *
+ * Copied from 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) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TERMBITS_H
+#define _XTENSA_TERMBITS_H
+
+
+#include <linux/posix_types.h>
+
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+typedef unsigned int tcflag_t;
+
+#define NCCS 19
+struct termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_line; /* line discipline */
+ cc_t c_cc[NCCS]; /* control characters */
+};
+
+/* c_cc characters */
+
+#define VINTR 0
+#define VQUIT 1
+#define VERASE 2
+#define VKILL 3
+#define VEOF 4
+#define VTIME 5
+#define VMIN 6
+#define VSWTC 7
+#define VSTART 8
+#define VSTOP 9
+#define VSUSP 10
+#define VEOL 11
+#define VREPRINT 12
+#define VDISCARD 13
+#define VWERASE 14
+#define VLNEXT 15
+#define VEOL2 16
+
+/* c_iflag bits */
+
+#define IGNBRK 0000001
+#define BRKINT 0000002
+#define IGNPAR 0000004
+#define PARMRK 0000010
+#define INPCK 0000020
+#define ISTRIP 0000040
+#define INLCR 0000100
+#define IGNCR 0000200
+#define ICRNL 0000400
+#define IUCLC 0001000
+#define IXON 0002000
+#define IXANY 0004000
+#define IXOFF 0010000
+#define IMAXBEL 0020000
+#define IUTF8 0040000
+
+/* c_oflag bits */
+
+#define OPOST 0000001
+#define OLCUC 0000002
+#define ONLCR 0000004
+#define OCRNL 0000010
+#define ONOCR 0000020
+#define ONLRET 0000040
+#define OFILL 0000100
+#define OFDEL 0000200
+#define NLDLY 0000400
+#define NL0 0000000
+#define NL1 0000400
+#define CRDLY 0003000
+#define CR0 0000000
+#define CR1 0001000
+#define CR2 0002000
+#define CR3 0003000
+#define TABDLY 0014000
+#define TAB0 0000000
+#define TAB1 0004000
+#define TAB2 0010000
+#define TAB3 0014000
+#define XTABS 0014000
+#define BSDLY 0020000
+#define BS0 0000000
+#define BS1 0020000
+#define VTDLY 0040000
+#define VT0 0000000
+#define VT1 0040000
+#define FFDLY 0100000
+#define FF0 0000000
+#define FF1 0100000
+
+/* c_cflag bit meaning */
+
+#define CBAUD 0010017
+#define B0 0000000 /* hang up */
+#define B50 0000001
+#define B75 0000002
+#define B110 0000003
+#define B134 0000004
+#define B150 0000005
+#define B200 0000006
+#define B300 0000007
+#define B600 0000010
+#define B1200 0000011
+#define B1800 0000012
+#define B2400 0000013
+#define B4800 0000014
+#define B9600 0000015
+#define B19200 0000016
+#define B38400 0000017
+#define EXTA B19200
+#define EXTB B38400
+#define CSIZE 0000060
+#define CS5 0000000
+#define CS6 0000020
+#define CS7 0000040
+#define CS8 0000060
+#define CSTOPB 0000100
+#define CREAD 0000200
+#define PARENB 0000400
+#define PARODD 0001000
+#define HUPCL 0002000
+#define CLOCAL 0004000
+#define CBAUDEX 0010000
+#define B57600 0010001
+#define B115200 0010002
+#define B230400 0010003
+#define B460800 0010004
+#define B500000 0010005
+#define B576000 0010006
+#define B921600 0010007
+#define B1000000 0010010
+#define B1152000 0010011
+#define B1500000 0010012
+#define B2000000 0010013
+#define B2500000 0010014
+#define B3000000 0010015
+#define B3500000 0010016
+#define B4000000 0010017
+#define CIBAUD 002003600000 /* input baud rate (not used) */
+#define CMSPAR 010000000000 /* mark or space (stick) parity */
+#define CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+
+#define ISIG 0000001
+#define ICANON 0000002
+#define XCASE 0000004
+#define ECHO 0000010
+#define ECHOE 0000020
+#define ECHOK 0000040
+#define ECHONL 0000100
+#define NOFLSH 0000200
+#define TOSTOP 0000400
+#define ECHOCTL 0001000
+#define ECHOPRT 0002000
+#define ECHOKE 0004000
+#define FLUSHO 0010000
+#define PENDIN 0040000
+#define IEXTEN 0100000
+
+/* tcflow() and TCXONC use these */
+
+#define TCOOFF 0
+#define TCOON 1
+#define TCIOFF 2
+#define TCION 3
+
+/* tcflush() and TCFLSH use these */
+
+#define TCIFLUSH 0
+#define TCOFLUSH 1
+#define TCIOFLUSH 2
+
+/* tcsetattr uses these */
+
+#define TCSANOW 0
+#define TCSADRAIN 1
+#define TCSAFLUSH 2
+
+#endif /* _XTENSA_TERMBITS_H */
diff --git a/include/asm-xtensa/termios.h b/include/asm-xtensa/termios.h
new file mode 100644
index 000000000000..83c6aed1d115
--- /dev/null
+++ b/include/asm-xtensa/termios.h
@@ -0,0 +1,122 @@
+/*
+ * include/asm-xtensa/termios.h
+ *
+ * Copied from 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) 2001 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TERMIOS_H
+#define _XTENSA_TERMIOS_H
+
+#include <asm/termbits.h>
+#include <asm/ioctls.h>
+
+struct winsize {
+ unsigned short ws_row;
+ unsigned short ws_col;
+ unsigned short ws_xpixel;
+ unsigned short ws_ypixel;
+};
+
+#define NCC 8
+struct termio {
+ unsigned short c_iflag; /* input mode flags */
+ unsigned short c_oflag; /* output mode flags */
+ unsigned short c_cflag; /* control mode flags */
+ unsigned short c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[NCC]; /* control characters */
+};
+
+/* Modem lines */
+
+#define TIOCM_LE 0x001
+#define TIOCM_DTR 0x002
+#define TIOCM_RTS 0x004
+#define TIOCM_ST 0x008
+#define TIOCM_SR 0x010
+#define TIOCM_CTS 0x020
+#define TIOCM_CAR 0x040
+#define TIOCM_RNG 0x080
+#define TIOCM_DSR 0x100
+#define TIOCM_CD TIOCM_CAR
+#define TIOCM_RI TIOCM_RNG
+#define TIOCM_OUT1 0x2000
+#define TIOCM_OUT2 0x4000
+#define TIOCM_LOOP 0x8000
+
+/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+
+/* Line disciplines */
+
+#define N_TTY 0
+#define N_SLIP 1
+#define N_MOUSE 2
+#define N_PPP 3
+#define N_STRIP 4
+#define N_AX25 5
+#define N_X25 6 /* X.25 async */
+#define N_6PACK 7
+#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */
+#define N_R3964 9 /* Reserved for Simatic R3964 module */
+#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */
+#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */
+#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
+#define N_HDLC 13 /* synchronous HDLC */
+#define N_SYNC_PPP 14
+#define N_HCI 15 /* Bluetooth HCI UART */
+
+#ifdef __KERNEL__
+
+/* intr=^C quit=^\ erase=del kill=^U
+ eof=^D vtime=\0 vmin=\1 sxtc=\0
+ start=^Q stop=^S susp=^Z eol=\0
+ reprint=^R discard=^U werase=^W lnext=^V
+ eol2=\0
+*/
+#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0"
+
+/*
+ * Translate a "termio" structure into a "termios". Ugh.
+ */
+
+#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \
+ unsigned short __tmp; \
+ get_user(__tmp,&(termio)->x); \
+ *(unsigned short *) &(termios)->x = __tmp; \
+}
+
+#define user_termio_to_kernel_termios(termios, termio) \
+({ \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \
+ SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \
+ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \
+})
+
+/*
+ * Translate a "termios" structure into a "termio". Ugh.
+ */
+
+#define kernel_termios_to_user_termio(termio, termios) \
+({ \
+ put_user((termios)->c_iflag, &(termio)->c_iflag); \
+ put_user((termios)->c_oflag, &(termio)->c_oflag); \
+ put_user((termios)->c_cflag, &(termio)->c_cflag); \
+ put_user((termios)->c_lflag, &(termio)->c_lflag); \
+ put_user((termios)->c_line, &(termio)->c_line); \
+ copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \
+})
+
+#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios))
+#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios))
+
+#endif /* __KERNEL__ */
+
+#endif /* _XTENSA_TERMIOS_H */
diff --git a/include/asm-xtensa/thread_info.h b/include/asm-xtensa/thread_info.h
new file mode 100644
index 000000000000..af208d41fd82
--- /dev/null
+++ b/include/asm-xtensa/thread_info.h
@@ -0,0 +1,146 @@
+/*
+ * include/asm-xtensa/thread_info.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_THREAD_INFO_H
+#define _XTENSA_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+#ifndef __ASSEMBLY__
+# include <asm/processor.h>
+#endif
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants
+ * must also be changed
+ */
+
+#ifndef __ASSEMBLY__
+
+struct thread_info {
+ struct task_struct *task; /* main task structure */
+ struct exec_domain *exec_domain; /* execution domain */
+ unsigned long flags; /* low level flags */
+ unsigned long status; /* thread-synchronous flags */
+ __u32 cpu; /* current CPU */
+ __s32 preempt_count; /* 0 => preemptable,< 0 => BUG*/
+
+ mm_segment_t addr_limit; /* thread address space */
+ struct restart_block restart_block;
+
+
+};
+
+#else /* !__ASSEMBLY__ */
+
+/* offsets into the thread_info struct for assembly code access */
+#define TI_TASK 0x00000000
+#define TI_EXEC_DOMAIN 0x00000004
+#define TI_FLAGS 0x00000008
+#define TI_STATUS 0x0000000C
+#define TI_CPU 0x00000010
+#define TI_PRE_COUNT 0x00000014
+#define TI_ADDR_LIMIT 0x00000018
+#define TI_RESTART_BLOCK 0x000001C
+
+#endif
+
+#define PREEMPT_ACTIVE 0x10000000
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+
+#ifndef __ASSEMBLY__
+
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .task = &tsk, \
+ .exec_domain = &default_exec_domain, \
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = 1, \
+ .addr_limit = KERNEL_DS, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+}
+
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+ struct thread_info *ti;
+ __asm__("extui %0,a1,0,13\n\t"
+ "xor %0, a1, %0" : "=&r" (ti) : );
+ return ti;
+}
+
+/* thread information allocation */
+#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1))
+#define free_thread_info(ti) free_pages((unsigned long) (ti), 1)
+#define get_thread_info(ti) get_task_struct((ti)->task)
+#define put_thread_info(ti) put_task_struct((ti)->task)
+
+#else /* !__ASSEMBLY__ */
+
+/* how to get the thread information struct from ASM */
+#define GET_THREAD_INFO(reg,sp) \
+ extui reg, sp, 0, 13; \
+ xor reg, sp, reg
+#endif
+
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files may need to access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
+#define TIF_SIGPENDING 2 /* signal pending */
+#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_SINGLESTEP 4 /* restore singlestep on return to user mode */
+#define TIF_IRET 5 /* return with iret */
+#define TIF_MEMDIE 6
+#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE (1<<TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING (1<<TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1<<TIF_NEED_RESCHED)
+#define _TIF_SINGLESTEP (1<<TIF_SINGLESTEP)
+#define _TIF_IRET (1<<TIF_IRET)
+#define _TIF_POLLING_NRFLAG (1<<TIF_POLLING_NRFLAG)
+
+#define _TIF_WORK_MASK 0x0000FFFE /* work to do on interrupt/exception return */
+#define _TIF_ALLWORK_MASK 0x0000FFFF /* work to do on any return to u-space */
+
+/*
+ * Thread-synchronous status.
+ *
+ * This is different from the flags in that nobody else
+ * ever touches our thread-synchronous status, so we don't
+ * have to worry about atomic accesses.
+ */
+#define TS_USEDFPU 0x0001 /* FPU was used by this task this quantum (SMP) */
+
+#define THREAD_SIZE 8192 //(2*PAGE_SIZE)
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_THREAD_INFO */
diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h
new file mode 100644
index 000000000000..d14a3755a12b
--- /dev/null
+++ b/include/asm-xtensa/timex.h
@@ -0,0 +1,94 @@
+/*
+ * include/asm-xtensa/timex.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TIMEX_H
+#define _XTENSA_TIMEX_H
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/stringify.h>
+
+#if XCHAL_INT_LEVEL(XCHAL_TIMER0_INTERRUPT) == 1
+# define LINUX_TIMER 0
+#elif XCHAL_INT_LEVEL(XCHAL_TIMER1_INTERRUPT) == 1
+# define LINUX_TIMER 1
+#elif XCHAL_INT_LEVEL(XCHAL_TIMER2_INTERRUPT) == 1
+# define LINUX_TIMER 2
+#else
+# error "Bad timer number for Linux configurations!"
+#endif
+
+#define LINUX_TIMER_INT XCHAL_TIMER_INTERRUPT(LINUX_TIMER)
+#define LINUX_TIMER_MASK (1L << LINUX_TIMER_INT)
+
+#define CLOCK_TICK_RATE 1193180 /* (everyone is using this value) */
+#define CLOCK_TICK_FACTOR 20 /* Factor of both 10^6 and CLOCK_TICK_RATE */
+#define FINETUNE ((((((long)LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
+ << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+#ifdef CONFIG_XTENSA_CALIBRATE_CCOUNT
+extern unsigned long ccount_per_jiffy;
+extern unsigned long ccount_nsec;
+#define CCOUNT_PER_JIFFY ccount_per_jiffy
+#define CCOUNT_NSEC ccount_nsec
+#else
+#define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ))
+#define CCOUNT_NSEC (1000000000UL / CONFIG_XTENSA_CPU_CLOCK)
+#endif
+
+
+typedef unsigned long long cycles_t;
+
+/*
+ * Only used for SMP.
+ */
+
+extern cycles_t cacheflush_time;
+
+#define get_cycles() (0)
+
+
+/*
+ * Register access.
+ */
+
+#define WSR_CCOUNT(r) __asm__("wsr %0,"__stringify(CCOUNT) :: "a" (r))
+#define RSR_CCOUNT(r) __asm__("rsr %0,"__stringify(CCOUNT) : "=a" (r))
+#define WSR_CCOMPARE(x,r) __asm__("wsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) :: "a"(r))
+#define RSR_CCOMPARE(x,r) __asm__("rsr %0,"__stringify(CCOMPARE_0)"+"__stringify(x) : "=a"(r))
+
+static inline unsigned long get_ccount (void)
+{
+ unsigned long ccount;
+ RSR_CCOUNT(ccount);
+ return ccount;
+}
+
+static inline void set_ccount (unsigned long ccount)
+{
+ WSR_CCOUNT(ccount);
+}
+
+static inline unsigned long get_linux_timer (void)
+{
+ unsigned ccompare;
+ RSR_CCOMPARE(LINUX_TIMER, ccompare);
+ return ccompare;
+}
+
+static inline void set_linux_timer (unsigned long ccompare)
+{
+ WSR_CCOMPARE(LINUX_TIMER, ccompare);
+}
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_TIMEX_H */
diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h
new file mode 100644
index 000000000000..4562b2dcfbc0
--- /dev/null
+++ b/include/asm-xtensa/tlb.h
@@ -0,0 +1,25 @@
+/*
+ * include/asm-xtensa/tlb.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TLB_H
+#define _XTENSA_TLB_H
+
+#define tlb_start_vma(tlb,vma) do { } while (0)
+#define tlb_end_vma(tlb,vma) do { } while (0)
+#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0)
+
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+#include <asm-generic/tlb.h>
+#include <asm/page.h>
+
+#define __pte_free_tlb(tlb,pte) pte_free(pte)
+
+#endif /* _XTENSA_TLB_H */
diff --git a/include/asm-xtensa/tlbflush.h b/include/asm-xtensa/tlbflush.h
new file mode 100644
index 000000000000..23bfe9db45f5
--- /dev/null
+++ b/include/asm-xtensa/tlbflush.h
@@ -0,0 +1,200 @@
+/*
+ * include/asm-xtensa/tlbflush.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TLBFLUSH_H
+#define _XTENSA_TLBFLUSH_H
+
+#define DEBUG_TLB
+
+#ifdef __KERNEL__
+
+#include <asm/processor.h>
+#include <linux/stringify.h>
+
+/* TLB flushing:
+ *
+ * - flush_tlb_all() flushes all processes TLB entries
+ * - flush_tlb_mm(mm) flushes the specified mm context TLB entries
+ * - flush_tlb_page(mm, vmaddr) flushes a single page
+ * - flush_tlb_range(mm, start, end) flushes a range of pages
+ */
+
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct*);
+extern void flush_tlb_page(struct vm_area_struct*,unsigned long);
+extern void flush_tlb_range(struct vm_area_struct*,unsigned long,unsigned long);
+
+#define flush_tlb_kernel_range(start,end) flush_tlb_all()
+
+
+/* This is calld in munmap when we have freed up some page-table pages.
+ * We don't need to do anything here, there's nothing special about our
+ * page-table pages.
+ */
+
+extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+}
+
+/* TLB operations. */
+
+#define ITLB_WAYS_LOG2 XCHAL_ITLB_WAY_BITS
+#define DTLB_WAYS_LOG2 XCHAL_DTLB_WAY_BITS
+#define ITLB_PROBE_SUCCESS (1 << ITLB_WAYS_LOG2)
+#define DTLB_PROBE_SUCCESS (1 << DTLB_WAYS_LOG2)
+
+extern inline unsigned long itlb_probe(unsigned long addr)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("pitlb %0, %1\n\t" : "=a" (tmp) : "a" (addr));
+ return tmp;
+}
+
+extern inline unsigned long dtlb_probe(unsigned long addr)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("pdtlb %0, %1\n\t" : "=a" (tmp) : "a" (addr));
+ return tmp;
+}
+
+extern inline void invalidate_itlb_entry (unsigned long probe)
+{
+ __asm__ __volatile__("iitlb %0; isync\n\t" : : "a" (probe));
+}
+
+extern inline void invalidate_dtlb_entry (unsigned long probe)
+{
+ __asm__ __volatile__("idtlb %0; dsync\n\t" : : "a" (probe));
+}
+
+/* Use the .._no_isync functions with caution. Generally, these are
+ * handy for bulk invalidates followed by a single 'isync'. The
+ * caller must follow up with an 'isync', which can be relatively
+ * expensive on some Xtensa implementations.
+ */
+extern inline void invalidate_itlb_entry_no_isync (unsigned entry)
+{
+ /* Caller must follow up with 'isync'. */
+ __asm__ __volatile__ ("iitlb %0\n" : : "a" (entry) );
+}
+
+extern inline void invalidate_dtlb_entry_no_isync (unsigned entry)
+{
+ /* Caller must follow up with 'isync'. */
+ __asm__ __volatile__ ("idtlb %0\n" : : "a" (entry) );
+}
+
+extern inline void set_itlbcfg_register (unsigned long val)
+{
+ __asm__ __volatile__("wsr %0, "__stringify(ITLBCFG)"\n\t" "isync\n\t"
+ : : "a" (val));
+}
+
+extern inline void set_dtlbcfg_register (unsigned long val)
+{
+ __asm__ __volatile__("wsr %0, "__stringify(DTLBCFG)"; dsync\n\t"
+ : : "a" (val));
+}
+
+extern inline void set_ptevaddr_register (unsigned long val)
+{
+ __asm__ __volatile__(" wsr %0, "__stringify(PTEVADDR)"; isync\n"
+ : : "a" (val));
+}
+
+extern inline unsigned long read_ptevaddr_register (void)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("rsr %0, "__stringify(PTEVADDR)"\n\t" : "=a" (tmp));
+ return tmp;
+}
+
+extern inline void write_dtlb_entry (pte_t entry, int way)
+{
+ __asm__ __volatile__("wdtlb %1, %0; dsync\n\t"
+ : : "r" (way), "r" (entry) );
+}
+
+extern inline void write_itlb_entry (pte_t entry, int way)
+{
+ __asm__ __volatile__("witlb %1, %0; isync\n\t"
+ : : "r" (way), "r" (entry) );
+}
+
+extern inline void invalidate_page_directory (void)
+{
+ invalidate_dtlb_entry (DTLB_WAY_PGTABLE);
+}
+
+extern inline void invalidate_itlb_mapping (unsigned address)
+{
+ unsigned long tlb_entry;
+ while ((tlb_entry = itlb_probe (address)) & ITLB_PROBE_SUCCESS)
+ invalidate_itlb_entry (tlb_entry);
+}
+
+extern inline void invalidate_dtlb_mapping (unsigned address)
+{
+ unsigned long tlb_entry;
+ while ((tlb_entry = dtlb_probe (address)) & DTLB_PROBE_SUCCESS)
+ invalidate_dtlb_entry (tlb_entry);
+}
+
+#define check_pgt_cache() do { } while (0)
+
+
+#ifdef DEBUG_TLB
+
+/* DO NOT USE THESE FUNCTIONS. These instructions aren't part of the Xtensa
+ * ISA and exist only for test purposes..
+ * You may find it helpful for MMU debugging, however.
+ *
+ * 'at' is the unmodified input register
+ * 'as' is the output register, as follows (specific to the Linux config):
+ *
+ * as[31..12] contain the virtual address
+ * as[11..08] are meaningless
+ * as[07..00] contain the asid
+ */
+
+extern inline unsigned long read_dtlb_virtual (int way)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("rdtlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way));
+ return tmp;
+}
+
+extern inline unsigned long read_dtlb_translation (int way)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("rdtlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way));
+ return tmp;
+}
+
+extern inline unsigned long read_itlb_virtual (int way)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("ritlb0 %0, %1\n\t" : "=a" (tmp), "+a" (way));
+ return tmp;
+}
+
+extern inline unsigned long read_itlb_translation (int way)
+{
+ unsigned long tmp;
+ __asm__ __volatile__("ritlb1 %0, %1\n\t" : "=a" (tmp), "+a" (way));
+ return tmp;
+}
+
+#endif /* DEBUG_TLB */
+
+
+#endif /* __KERNEL__ */
+#endif /* _XTENSA_PGALLOC_H */
diff --git a/include/asm-xtensa/topology.h b/include/asm-xtensa/topology.h
new file mode 100644
index 000000000000..7309e38a0ccb
--- /dev/null
+++ b/include/asm-xtensa/topology.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/topology.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TOPOLOGY_H
+#define _XTENSA_TOPOLOGY_H
+
+#include <asm-generic/topology.h>
+
+#endif /* _XTENSA_TOPOLOGY_H */
diff --git a/include/asm-xtensa/types.h b/include/asm-xtensa/types.h
new file mode 100644
index 000000000000..ebac00469852
--- /dev/null
+++ b/include/asm-xtensa/types.h
@@ -0,0 +1,66 @@
+/*
+ * include/asm-xtensa/types.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_TYPES_H
+#define _XTENSA_TYPES_H
+
+#ifndef __ASSEMBLY__
+
+typedef unsigned short umode_t;
+
+/*
+ * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the
+ * header files exported to user space
+ */
+
+typedef __signed__ char __s8;
+typedef unsigned char __u8;
+
+typedef __signed__ short __s16;
+typedef unsigned short __u16;
+
+typedef __signed__ int __s32;
+typedef unsigned int __u32;
+
+#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
+typedef __signed__ long long __s64;
+typedef unsigned long long __u64;
+#endif
+
+/*
+ * These aren't exported outside the kernel to avoid name space clashes
+ */
+#ifdef __KERNEL__
+
+typedef __signed__ char s8;
+typedef unsigned char u8;
+
+typedef __signed__ short s16;
+typedef unsigned short u16;
+
+typedef __signed__ int s32;
+typedef unsigned int u32;
+
+typedef __signed__ long long s64;
+typedef unsigned long long u64;
+
+
+#define BITS_PER_LONG 32
+
+/* Dma addresses are 32-bits wide. */
+
+typedef u32 dma_addr_t;
+
+typedef unsigned int kmem_bufctl_t;
+
+#endif /* __KERNEL__ */
+#endif
+
+#endif /* _XTENSA_TYPES_H */
diff --git a/include/asm-xtensa/uaccess.h b/include/asm-xtensa/uaccess.h
new file mode 100644
index 000000000000..35576b25c7b2
--- /dev/null
+++ b/include/asm-xtensa/uaccess.h
@@ -0,0 +1,532 @@
+/*
+ * include/asm-xtensa/uaccess.h
+ *
+ * User space memory access functions
+ *
+ * These routines provide basic accessing functions to the user memory
+ * space for the kernel. This header file provides fuctions such as:
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UACCESS_H
+#define _XTENSA_UACCESS_H
+
+#include <linux/errno.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+#ifdef __ASSEMBLY__
+
+#define _ASMLANGUAGE
+#include <asm/current.h>
+#include <asm/offsets.h>
+#include <asm/processor.h>
+
+/*
+ * These assembly macros mirror the C macros that follow below. They
+ * should always have identical functionality. See
+ * arch/xtensa/kernel/sys.S for usage.
+ */
+
+#define KERNEL_DS 0
+#define USER_DS 1
+
+#define get_ds (KERNEL_DS)
+
+/*
+ * get_fs reads current->thread.current_ds into a register.
+ * On Entry:
+ * <ad> anything
+ * <sp> stack
+ * On Exit:
+ * <ad> contains current->thread.current_ds
+ */
+ .macro get_fs ad, sp
+ GET_CURRENT(\ad,\sp)
+ l32i \ad, \ad, THREAD_CURRENT_DS
+ .endm
+
+/*
+ * set_fs sets current->thread.current_ds to some value.
+ * On Entry:
+ * <at> anything (temp register)
+ * <av> value to write
+ * <sp> stack
+ * On Exit:
+ * <at> destroyed (actually, current)
+ * <av> preserved, value to write
+ */
+ .macro set_fs at, av, sp
+ GET_CURRENT(\at,\sp)
+ s32i \av, \at, THREAD_CURRENT_DS
+ .endm
+
+/*
+ * kernel_ok determines whether we should bypass addr/size checking.
+ * See the equivalent C-macro version below for clarity.
+ * On success, kernel_ok branches to a label indicated by parameter
+ * <success>. This implies that the macro falls through to the next
+ * insruction on an error.
+ *
+ * Note that while this macro can be used independently, we designed
+ * in for optimal use in the access_ok macro below (i.e., we fall
+ * through on error).
+ *
+ * On Entry:
+ * <at> anything (temp register)
+ * <success> label to branch to on success; implies
+ * fall-through macro on error
+ * <sp> stack pointer
+ * On Exit:
+ * <at> destroyed (actually, current->thread.current_ds)
+ */
+
+#if ((KERNEL_DS != 0) || (USER_DS == 0))
+# error Assembly macro kernel_ok fails
+#endif
+ .macro kernel_ok at, sp, success
+ get_fs \at, \sp
+ beqz \at, \success
+ .endm
+
+/*
+ * user_ok determines whether the access to user-space memory is allowed.
+ * See the equivalent C-macro version below for clarity.
+ *
+ * On error, user_ok branches to a label indicated by parameter
+ * <error>. This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that while this macro can be used independently, we designed
+ * in for optimal use in the access_ok macro below (i.e., we fall
+ * through on success).
+ *
+ * On Entry:
+ * <aa> register containing memory address
+ * <as> register containing memory size
+ * <at> temp register
+ * <error> label to branch to on error; implies fall-through
+ * macro on success
+ * On Exit:
+ * <aa> preserved
+ * <as> preserved
+ * <at> destroyed (actually, (TASK_SIZE + 1 - size))
+ */
+ .macro user_ok aa, as, at, error
+ movi \at, (TASK_SIZE+1)
+ bgeu \as, \at, \error
+ sub \at, \at, \as
+ bgeu \aa, \at, \error
+ .endm
+
+/*
+ * access_ok determines whether a memory access is allowed. See the
+ * equivalent C-macro version below for clarity.
+ *
+ * On error, access_ok branches to a label indicated by parameter
+ * <error>. This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that we assume success is the common case, and we optimize the
+ * branch fall-through case on success.
+ *
+ * On Entry:
+ * <aa> register containing memory address
+ * <as> register containing memory size
+ * <at> temp register
+ * <sp>
+ * <error> label to branch to on error; implies fall-through
+ * macro on success
+ * On Exit:
+ * <aa> preserved
+ * <as> preserved
+ * <at> destroyed
+ */
+ .macro access_ok aa, as, at, sp, error
+ kernel_ok \at, \sp, .Laccess_ok_\@
+ user_ok \aa, \as, \at, \error
+.Laccess_ok_\@:
+ .endm
+
+/*
+ * verify_area determines whether a memory access is allowed. It's
+ * mostly an unnecessary wrapper for access_ok, but we provide it as a
+ * duplicate of the verify_area() C inline function below. See the
+ * equivalent C version below for clarity.
+ *
+ * On error, verify_area branches to a label indicated by parameter
+ * <error>. This implies that the macro falls through to the next
+ * instruction on success.
+ *
+ * Note that we assume success is the common case, and we optimize the
+ * branch fall-through case on success.
+ *
+ * On Entry:
+ * <aa> register containing memory address
+ * <as> register containing memory size
+ * <at> temp register
+ * <error> label to branch to on error; implies fall-through
+ * macro on success
+ * On Exit:
+ * <aa> preserved
+ * <as> preserved
+ * <at> destroyed
+ */
+ .macro verify_area aa, as, at, sp, error
+ access_ok \at, \aa, \as, \sp, \error
+ .endm
+
+
+#else /* __ASSEMBLY__ not defined */
+
+#include <linux/sched.h>
+#include <asm/types.h>
+
+/*
+ * The fs value determines whether argument validity checking should
+ * be performed or not. If get_fs() == USER_DS, checking is
+ * performed, with get_fs() == KERNEL_DS, checking is bypassed.
+ *
+ * For historical reasons (Data Segment Register?), these macros are
+ * grossly misnamed.
+ */
+
+#define KERNEL_DS ((mm_segment_t) { 0 })
+#define USER_DS ((mm_segment_t) { 1 })
+
+#define get_ds() (KERNEL_DS)
+#define get_fs() (current->thread.current_ds)
+#define set_fs(val) (current->thread.current_ds = (val))
+
+#define segment_eq(a,b) ((a).seg == (b).seg)
+
+#define __kernel_ok (segment_eq(get_fs(), KERNEL_DS))
+#define __user_ok(addr,size) (((size) <= TASK_SIZE)&&((addr) <= TASK_SIZE-(size)))
+#define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size)))
+#define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size))
+
+extern inline int verify_area(int type, const void * addr, unsigned long size)
+{
+ return access_ok(type,addr,size) ? 0 : -EFAULT;
+}
+
+/*
+ * These are the main single-value transfer routines. They
+ * automatically use the right size if we just have the right pointer
+ * type.
+ *
+ * This gets kind of ugly. We want to return _two_ values in
+ * "get_user()" and yet we don't want to do any pointers, because that
+ * is too much of a performance impact. Thus we have a few rather ugly
+ * macros here, and hide all the uglyness from the user.
+ *
+ * Careful to not
+ * (a) re-use the arguments for side effects (sizeof is ok)
+ * (b) require any knowledge of processes at this stage
+ */
+#define put_user(x,ptr) __put_user_check((x),(ptr),sizeof(*(ptr)))
+#define get_user(x,ptr) __get_user_check((x),(ptr),sizeof(*(ptr)))
+
+/*
+ * The "__xxx" versions of the user access functions are versions that
+ * do not verify the address space, that must have been done previously
+ * with a separate "access_ok()" call (this is used when we do multiple
+ * accesses to the same area of user memory).
+ */
+#define __put_user(x,ptr) __put_user_nocheck((x),(ptr),sizeof(*(ptr)))
+#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr)))
+
+
+extern long __put_user_bad(void);
+
+#define __put_user_nocheck(x,ptr,size) \
+({ \
+ long __pu_err; \
+ __put_user_size((x),(ptr),(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_check(x,ptr,size) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) *__pu_addr = (ptr); \
+ if (access_ok(VERIFY_WRITE,__pu_addr,size)) \
+ __put_user_size((x),__pu_addr,(size),__pu_err); \
+ __pu_err; \
+})
+
+#define __put_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __put_user_asm(x,ptr,retval,1,"s8i"); break; \
+ case 2: __put_user_asm(x,ptr,retval,2,"s16i"); break; \
+ case 4: __put_user_asm(x,ptr,retval,4,"s32i"); break; \
+ case 8: { \
+ __typeof__(*ptr) __v64 = x; \
+ retval = __copy_to_user(ptr,&__v64,8); \
+ break; \
+ } \
+ default: __put_user_bad(); \
+ } \
+} while (0)
+
+
+/*
+ * Consider a case of a user single load/store would cause both an
+ * unaligned exception and an MMU-related exception (unaligned
+ * exceptions happen first):
+ *
+ * User code passes a bad variable ptr to a system call.
+ * Kernel tries to access the variable.
+ * Unaligned exception occurs.
+ * Unaligned exception handler tries to make aligned accesses.
+ * Double exception occurs for MMU-related cause (e.g., page not mapped).
+ * do_page_fault() thinks the fault address belongs to the kernel, not the
+ * user, and panics.
+ *
+ * The kernel currently prohibits user unaligned accesses. We use the
+ * __check_align_* macros to check for unaligned addresses before
+ * accessing user space so we don't crash the kernel. Both
+ * __put_user_asm and __get_user_asm use these alignment macros, so
+ * macro-specific labels such as 0f, 1f, %0, %2, and %3 must stay in
+ * sync.
+ */
+
+#define __check_align_1 ""
+
+#define __check_align_2 \
+ " _bbci.l %2, 0, 1f \n" \
+ " movi %0, %3 \n" \
+ " _j 2f \n"
+
+#define __check_align_4 \
+ " _bbsi.l %2, 0, 0f \n" \
+ " _bbci.l %2, 1, 1f \n" \
+ "0: movi %0, %3 \n" \
+ " _j 2f \n"
+
+
+/*
+ * We don't tell gcc that we are accessing memory, but this is OK
+ * because we do not write to any memory gcc knows about, so there
+ * are no aliasing issues.
+ *
+ * WARNING: If you modify this macro at all, verify that the
+ * __check_align_* macros still work.
+ */
+#define __put_user_asm(x, addr, err, align, insn) \
+ __asm__ __volatile__( \
+ __check_align_##align \
+ "1: "insn" %1, %2, 0 \n" \
+ "2: \n" \
+ " .section .fixup,\"ax\" \n" \
+ " .align 4 \n" \
+ "4: \n" \
+ " .long 2b \n" \
+ "5: \n" \
+ " l32r %2, 4b \n" \
+ " movi %0, %3 \n" \
+ " jx %2 \n" \
+ " .previous \n" \
+ " .section __ex_table,\"a\" \n" \
+ " .long 1b, 5b \n" \
+ " .previous" \
+ :"=r" (err) \
+ :"r" ((int)(x)), "r" (addr), "i" (-EFAULT), "0" (err))
+
+#define __get_user_nocheck(x,ptr,size) \
+({ \
+ long __gu_err, __gu_val; \
+ __get_user_size(__gu_val,(ptr),(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+#define __get_user_check(x,ptr,size) \
+({ \
+ long __gu_err = -EFAULT, __gu_val = 0; \
+ const __typeof__(*(ptr)) *__gu_addr = (ptr); \
+ if (access_ok(VERIFY_READ,__gu_addr,size)) \
+ __get_user_size(__gu_val,__gu_addr,(size),__gu_err); \
+ (x) = (__typeof__(*(ptr)))__gu_val; \
+ __gu_err; \
+})
+
+extern long __get_user_bad(void);
+
+#define __get_user_size(x,ptr,size,retval) \
+do { \
+ retval = 0; \
+ switch (size) { \
+ case 1: __get_user_asm(x,ptr,retval,1,"l8ui"); break; \
+ case 2: __get_user_asm(x,ptr,retval,2,"l16ui"); break; \
+ case 4: __get_user_asm(x,ptr,retval,4,"l32i"); break; \
+ case 8: retval = __copy_from_user(&x,ptr,8); break; \
+ default: (x) = __get_user_bad(); \
+ } \
+} while (0)
+
+
+/*
+ * WARNING: If you modify this macro at all, verify that the
+ * __check_align_* macros still work.
+ */
+#define __get_user_asm(x, addr, err, align, insn) \
+ __asm__ __volatile__( \
+ __check_align_##align \
+ "1: "insn" %1, %2, 0 \n" \
+ "2: \n" \
+ " .section .fixup,\"ax\" \n" \
+ " .align 4 \n" \
+ "4: \n" \
+ " .long 2b \n" \
+ "5: \n" \
+ " l32r %2, 4b \n" \
+ " movi %1, 0 \n" \
+ " movi %0, %3 \n" \
+ " jx %2 \n" \
+ " .previous \n" \
+ " .section __ex_table,\"a\" \n" \
+ " .long 1b, 5b \n" \
+ " .previous" \
+ :"=r" (err), "=r" (x) \
+ :"r" (addr), "i" (-EFAULT), "0" (err))
+
+
+/*
+ * Copy to/from user space
+ */
+
+/*
+ * We use a generic, arbitrary-sized copy subroutine. The Xtensa
+ * architecture would cause heavy code bloat if we tried to inline
+ * these functions and provide __constant_copy_* equivalents like the
+ * i386 versions. __xtensa_copy_user is quite efficient. See the
+ * .fixup section of __xtensa_copy_user for a discussion on the
+ * X_zeroing equivalents for Xtensa.
+ */
+
+extern unsigned __xtensa_copy_user(void *to, const void *from, unsigned n);
+#define __copy_user(to,from,size) __xtensa_copy_user(to,from,size)
+
+
+static inline unsigned long
+__generic_copy_from_user_nocheck(void *to, const void *from, unsigned long n)
+{
+ return __copy_user(to,from,n);
+}
+
+static inline unsigned long
+__generic_copy_to_user_nocheck(void *to, const void *from, unsigned long n)
+{
+ return __copy_user(to,from,n);
+}
+
+static inline unsigned long
+__generic_copy_to_user(void *to, const void *from, unsigned long n)
+{
+ prefetch(from);
+ if (access_ok(VERIFY_WRITE, to, n))
+ return __copy_user(to,from,n);
+ return n;
+}
+
+static inline unsigned long
+__generic_copy_from_user(void *to, const void *from, unsigned long n)
+{
+ prefetchw(to);
+ if (access_ok(VERIFY_READ, from, n))
+ return __copy_user(to,from,n);
+ else
+ memset(to, 0, n);
+ return n;
+}
+
+#define copy_to_user(to,from,n) __generic_copy_to_user((to),(from),(n))
+#define copy_from_user(to,from,n) __generic_copy_from_user((to),(from),(n))
+#define __copy_to_user(to,from,n) __generic_copy_to_user_nocheck((to),(from),(n))
+#define __copy_from_user(to,from,n) __generic_copy_from_user_nocheck((to),(from),(n))
+#define __copy_to_user_inatomic __copy_to_user
+#define __copy_from_user_inatomic __copy_from_user
+
+
+/*
+ * We need to return the number of bytes not cleared. Our memset()
+ * returns zero if a problem occurs while accessing user-space memory.
+ * In that event, return no memory cleared. Otherwise, zero for
+ * success.
+ */
+
+extern inline unsigned long
+__xtensa_clear_user(void *addr, unsigned long size)
+{
+ if ( ! memset(addr, 0, size) )
+ return size;
+ return 0;
+}
+
+extern inline unsigned long
+clear_user(void *addr, unsigned long size)
+{
+ if (access_ok(VERIFY_WRITE, addr, size))
+ return __xtensa_clear_user(addr, size);
+ return size ? -EFAULT : 0;
+}
+
+#define __clear_user __xtensa_clear_user
+
+
+extern long __strncpy_user(char *, const char *, long);
+#define __strncpy_from_user __strncpy_user
+
+extern inline long
+strncpy_from_user(char *dst, const char *src, long count)
+{
+ if (access_ok(VERIFY_READ, src, 1))
+ return __strncpy_from_user(dst, src, count);
+ return -EFAULT;
+}
+
+
+#define strlen_user(str) strnlen_user((str), TASK_SIZE - 1)
+
+/*
+ * Return the size of a string (including the ending 0!)
+ */
+extern long __strnlen_user(const char *, long);
+
+extern inline long strnlen_user(const char *str, long len)
+{
+ unsigned long top = __kernel_ok ? ~0UL : TASK_SIZE - 1;
+
+ if ((unsigned long)str > top)
+ return 0;
+ return __strnlen_user(str, len);
+}
+
+
+struct exception_table_entry
+{
+ unsigned long insn, fixup;
+};
+
+/* Returns 0 if exception not found and fixup.unit otherwise. */
+
+extern unsigned long search_exception_table(unsigned long addr);
+extern void sort_exception_table(void);
+
+/* Returns the new pc */
+#define fixup_exception(map_reg, fixup_unit, pc) \
+({ \
+ fixup_unit; \
+})
+
+#endif /* __ASSEMBLY__ */
+#endif /* _XTENSA_UACCESS_H */
diff --git a/include/asm-xtensa/ucontext.h b/include/asm-xtensa/ucontext.h
new file mode 100644
index 000000000000..94c94ed3e00a
--- /dev/null
+++ b/include/asm-xtensa/ucontext.h
@@ -0,0 +1,22 @@
+/*
+ * include/asm-xtensa/ucontext.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UCONTEXT_H
+#define _XTENSA_UCONTEXT_H
+
+struct ucontext {
+ unsigned long uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ struct sigcontext uc_mcontext;
+ sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif /* _XTENSA_UCONTEXT_H */
diff --git a/include/asm-xtensa/unaligned.h b/include/asm-xtensa/unaligned.h
new file mode 100644
index 000000000000..28220890d0a6
--- /dev/null
+++ b/include/asm-xtensa/unaligned.h
@@ -0,0 +1,28 @@
+/*
+ * include/asm-xtensa/unaligned.h
+ *
+ * Xtensa doesn't handle unaligned accesses efficiently.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UNALIGNED_H
+#define _XTENSA_UNALIGNED_H
+
+#include <linux/string.h>
+
+/* Use memmove here, so gcc does not insert a __builtin_memcpy. */
+
+#define get_unaligned(ptr) \
+ ({ __typeof__(*(ptr)) __tmp; memmove(&__tmp, (ptr), sizeof(*(ptr))); __tmp; })
+
+#define put_unaligned(val, ptr) \
+ ({ __typeof__(*(ptr)) __tmp = (val); \
+ memmove((ptr), &__tmp, sizeof(*(ptr))); \
+ (void)0; })
+
+#endif /* _XTENSA_UNALIGNED_H */
diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h
new file mode 100644
index 000000000000..6b39d6609d9c
--- /dev/null
+++ b/include/asm-xtensa/unistd.h
@@ -0,0 +1,439 @@
+/*
+ * include/asm-xtensa/unistd.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_UNISTD_H
+#define _XTENSA_UNISTD_H
+
+#include <linux/linkage.h>
+
+#define __NR_spill 0
+#define __NR_exit 1
+#define __NR_read 3
+#define __NR_write 4
+#define __NR_open 5
+#define __NR_close 6
+#define __NR_creat 8
+#define __NR_link 9
+#define __NR_unlink 10
+#define __NR_execve 11
+#define __NR_chdir 12
+#define __NR_mknod 14
+#define __NR_chmod 15
+#define __NR_lchown 16
+#define __NR_break 17
+#define __NR_lseek 19
+#define __NR_getpid 20
+#define __NR_mount 21
+#define __NR_setuid 23
+#define __NR_getuid 24
+#define __NR_ptrace 26
+#define __NR_utime 30
+#define __NR_stty 31
+#define __NR_gtty 32
+#define __NR_access 33
+#define __NR_ftime 35
+#define __NR_sync 36
+#define __NR_kill 37
+#define __NR_rename 38
+#define __NR_mkdir 39
+#define __NR_rmdir 40
+#define __NR_dup 41
+#define __NR_pipe 42
+#define __NR_times 43
+#define __NR_prof 44
+#define __NR_brk 45
+#define __NR_setgid 46
+#define __NR_getgid 47
+#define __NR_signal 48
+#define __NR_geteuid 49
+#define __NR_getegid 50
+#define __NR_acct 51
+#define __NR_lock 53
+#define __NR_ioctl 54
+#define __NR_fcntl 55
+#define __NR_setpgid 57
+#define __NR_ulimit 58
+#define __NR_umask 60
+#define __NR_chroot 61
+#define __NR_ustat 62
+#define __NR_dup2 63
+#define __NR_getppid 64
+#define __NR_setsid 66
+#define __NR_sigaction 67
+#define __NR_setreuid 70
+#define __NR_setregid 71
+#define __NR_sigsuspend 72
+#define __NR_sigpending 73
+#define __NR_sethostname 74
+#define __NR_setrlimit 75
+#define __NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
+#define __NR_getrusage 77
+#define __NR_gettimeofday 78
+#define __NR_settimeofday 79
+#define __NR_getgroups 80
+#define __NR_setgroups 81
+#define __NR_select 82
+#define __NR_symlink 83
+#define __NR_readlink 85
+#define __NR_uselib 86
+#define __NR_swapon 87
+#define __NR_reboot 88
+#define __NR_munmap 91
+#define __NR_truncate 92
+#define __NR_ftruncate 93
+#define __NR_fchmod 94
+#define __NR_fchown 95
+#define __NR_getpriority 96
+#define __NR_setpriority 97
+#define __NR_profil 98
+#define __NR_statfs 99
+#define __NR_fstatfs 100
+#define __NR_ioperm 101
+#define __NR_syslog 103
+#define __NR_setitimer 104
+#define __NR_getitimer 105
+#define __NR_stat 106
+#define __NR_lstat 107
+#define __NR_fstat 108
+#define __NR_iopl 110
+#define __NR_vhangup 111
+#define __NR_idle 112
+#define __NR_wait4 114
+#define __NR_swapoff 115
+#define __NR_sysinfo 116
+#define __NR_fsync 118
+#define __NR_sigreturn 119
+#define __NR_clone 120
+#define __NR_setdomainname 121
+#define __NR_uname 122
+#define __NR_modify_ldt 123
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
+#define __NR_create_module 127
+#define __NR_init_module 128
+#define __NR_delete_module 129
+#define __NR_quotactl 131
+#define __NR_getpgid 132
+#define __NR_fchdir 133
+#define __NR_bdflush 134
+#define __NR_sysfs 135
+#define __NR_personality 136
+#define __NR_setfsuid 138
+#define __NR_setfsgid 139
+#define __NR__llseek 140
+#define __NR_getdents 141
+#define __NR__newselect 142
+#define __NR_flock 143
+#define __NR_msync 144
+#define __NR_readv 145
+#define __NR_writev 146
+#define __NR_cacheflush 147
+#define __NR_cachectl 148
+#define __NR_sysxtensa 149
+#define __NR_sysdummy 150
+#define __NR_getsid 151
+#define __NR_fdatasync 152
+#define __NR__sysctl 153
+#define __NR_mlock 154
+#define __NR_munlock 155
+#define __NR_mlockall 156
+#define __NR_munlockall 157
+#define __NR_sched_setparam 158
+#define __NR_sched_getparam 159
+#define __NR_sched_setscheduler 160
+#define __NR_sched_getscheduler 161
+#define __NR_sched_yield 162
+#define __NR_sched_get_priority_max 163
+#define __NR_sched_get_priority_min 164
+#define __NR_sched_rr_get_interval 165
+#define __NR_nanosleep 166
+#define __NR_mremap 167
+#define __NR_accept 168
+#define __NR_bind 169
+#define __NR_connect 170
+#define __NR_getpeername 171
+#define __NR_getsockname 172
+#define __NR_getsockopt 173
+#define __NR_listen 174
+#define __NR_recv 175
+#define __NR_recvfrom 176
+#define __NR_recvmsg 177
+#define __NR_send 178
+#define __NR_sendmsg 179
+#define __NR_sendto 180
+#define __NR_setsockopt 181
+#define __NR_shutdown 182
+#define __NR_socket 183
+#define __NR_socketpair 184
+#define __NR_setresuid 185
+#define __NR_getresuid 186
+#define __NR_query_module 187
+#define __NR_poll 188
+#define __NR_nfsservctl 189
+#define __NR_setresgid 190
+#define __NR_getresgid 191
+#define __NR_prctl 192
+#define __NR_rt_sigreturn 193
+#define __NR_rt_sigaction 194
+#define __NR_rt_sigprocmask 195
+#define __NR_rt_sigpending 196
+#define __NR_rt_sigtimedwait 197
+#define __NR_rt_sigqueueinfo 198
+#define __NR_rt_sigsuspend 199
+#define __NR_pread 200
+#define __NR_pwrite 201
+#define __NR_chown 202
+#define __NR_getcwd 203
+#define __NR_capget 204
+#define __NR_capset 205
+#define __NR_sigaltstack 206
+#define __NR_sendfile 207
+#define __NR_mmap2 210
+#define __NR_truncate64 211
+#define __NR_ftruncate64 212
+#define __NR_stat64 213
+#define __NR_lstat64 214
+#define __NR_fstat64 215
+#define __NR_pivot_root 216
+#define __NR_mincore 217
+#define __NR_madvise 218
+#define __NR_getdents64 219
+
+/* Keep this last; should always equal the last valid call number. */
+#define __NR_Linux_syscalls 220
+
+/* user-visible error numbers are in the range -1 - -125: see
+ * <asm-xtensa/errno.h> */
+
+#define SYSXTENSA_RESERVED 0 /* don't use this */
+#define SYSXTENSA_ATOMIC_SET 1 /* set variable */
+#define SYSXTENSA_ATOMIC_EXG_ADD 2 /* exchange memory and add */
+#define SYSXTENSA_ATOMIC_ADD 3 /* add to memory */
+#define SYSXTENSA_ATOMIC_CMP_SWP 4 /* compare and swap */
+
+#define SYSXTENSA_COUNT 5 /* count of syscall0 functions*/
+
+#ifdef __KERNEL__
+#define __syscall_return(type, res) return ((type)(res))
+#else
+#define __syscall_return(type, res) \
+do { \
+ if ((unsigned long)(res) >= (unsigned long)(-125)) { \
+ /* Avoid using "res" which is declared to be in register r2; \
+ * errno might expand to a function call and clobber it. */ \
+ int __err = -(res); \
+ errno = __err; \
+ res = -1; \
+ } \
+ return (type) (res); \
+} while (0)
+#endif
+
+
+/* Tensilica's xt-xcc compiler is much more agressive at code
+ * optimization than gcc. Multiple __asm__ statements are
+ * insufficient for xt-xcc because subsequent optimization passes
+ * (beyond the front-end that knows of __asm__ statements and other
+ * such GNU Extensions to C) can modify the register selection for
+ * containment of C variables.
+ *
+ * xt-xcc cannot modify the contents of a single __asm__ statement, so
+ * we create single-asm versions of the syscall macros that are
+ * suitable and optimal for both xt-xcc and gcc.
+ *
+ * Linux takes system-call arguments in registers. The following
+ * design is optimized for user-land apps (e.g., glibc) which
+ * typically have a function wrapper around the "syscall" assembly
+ * instruction. It satisfies the Xtensa ABI while minizing argument
+ * shifting.
+ *
+ * The Xtensa ABI and software conventions require the system-call
+ * number in a2. If an argument exists in a2, we move it to the next
+ * available register. Note that for improved efficiency, we do NOT
+ * shift all parameters down one register to maintain the original
+ * order.
+ *
+ * At best case (zero arguments), we just write the syscall number to
+ * a2. At worst case (1 to 6 arguments), we move the argument in a2
+ * to the next available register, then write the syscall number to
+ * a2.
+ *
+ * For clarity, the following truth table enumerates all possibilities.
+ *
+ * arguments syscall number arg0, arg1, arg2, arg3, arg4, arg5
+ * --------- -------------- ----------------------------------
+ * 0 a2
+ * 1 a2 a3
+ * 2 a2 a4, a3
+ * 3 a2 a5, a3, a4
+ * 4 a2 a6, a3, a4, a5
+ * 5 a2 a7, a3, a4, a5, a6
+ * 6 a2 a8, a3, a4, a5, a6, a7
+ */
+
+#define _syscall0(type,name) \
+type name(void) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name) \
+ : "a2" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall1(type,name,type0,arg0) \
+type name(type0 arg0) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a3, %2 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0) \
+ : "a2", "a3" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall2(type,name,type0,arg0,type1,arg1) \
+type name(type0 arg0,type1 arg1) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a4, %2 \n" \
+ " mov a3, %3 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0), "a" (arg1) \
+ : "a2", "a3", "a4" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall3(type,name,type0,arg0,type1,arg1,type2,arg2) \
+type name(type0 arg0,type1 arg1,type2 arg2) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a5, %2 \n" \
+ " mov a4, %4 \n" \
+ " mov a3, %3 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2) \
+ : "a2", "a3", "a4", "a5" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+#define _syscall4(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a6, %2 \n" \
+ " mov a5, %5 \n" \
+ " mov a4, %4 \n" \
+ " mov a3, %3 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), "a" (arg3) \
+ : "a2", "a3", "a4", "a5", "a6" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+/* Note that we save and restore the a7 frame pointer.
+ * Including a7 in the clobber list doesn't do what you'd expect.
+ */
+#define _syscall5(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3,type4 arg4) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a9, a7 \n" \
+ " mov a7, %2 \n" \
+ " mov a6, %6 \n" \
+ " mov a5, %5 \n" \
+ " mov a4, %4 \n" \
+ " mov a3, %3 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov a7, a9 \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), \
+ "a" (arg3), "a" (arg4) \
+ : "a2", "a3", "a4", "a5", "a6", "a9" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+/* Note that we save and restore the a7 frame pointer.
+ * Including a7 in the clobber list doesn't do what you'd expect.
+ */
+#define _syscall6(type,name,type0,arg0,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \
+type name(type0 arg0,type1 arg1,type2 arg2,type3 arg3,type4 arg4,type5 arg5) \
+{ \
+long __res; \
+__asm__ __volatile__ ( \
+ " mov a9, a7 \n" \
+ " mov a8, %2 \n" \
+ " mov a7, %7 \n" \
+ " mov a6, %6 \n" \
+ " mov a5, %5 \n" \
+ " mov a4, %4 \n" \
+ " mov a3, %3 \n" \
+ " movi a2, %1 \n" \
+ " syscall \n" \
+ " mov a7, a9 \n" \
+ " mov %0, a2 \n" \
+ : "=a" (__res) \
+ : "i" (__NR_##name), "a" (arg0), "a" (arg1), "a" (arg2), \
+ "a" (arg3), "a" (arg4), "a" (arg5) \
+ : "a2", "a3", "a4", "a5", "a6", "a8", "a9" \
+ ); \
+__syscall_return(type,__res); \
+}
+
+
+#ifdef __KERNEL_SYSCALLS__
+static __inline__ _syscall3(int,execve,const char*,file,char**,argv,char**,envp)
+#endif
+
+/*
+ * "Conditional" syscalls
+ *
+ * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
+ * but it doesn't work on all toolchains, so we just do it by hand
+ */
+#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+
+#ifdef __KERNEL__
+#define __ARCH_WANT_STAT64
+#define __ARCH_WANT_SYS_UTIME
+#define __ARCH_WANT_SYS_LLSEEK
+#define __ARCH_WANT_SYS_RT_SIGACTION
+#endif
+
+#endif /* _XTENSA_UNISTD_H */
diff --git a/include/asm-xtensa/user.h b/include/asm-xtensa/user.h
new file mode 100644
index 000000000000..2c3ed23354a8
--- /dev/null
+++ b/include/asm-xtensa/user.h
@@ -0,0 +1,20 @@
+/*
+ * include/asm-xtensa/user.h
+ *
+ * Xtensa Processor version.
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_USER_H
+#define _XTENSA_USER_H
+
+/* This file usually defines a 'struct user' structure. However, it it only
+ * used for a.out file, which are not supported on Xtensa.
+ */
+
+#endif /* _XTENSA_USER_H */
diff --git a/include/asm-xtensa/vga.h b/include/asm-xtensa/vga.h
new file mode 100644
index 000000000000..23d82f6acb57
--- /dev/null
+++ b/include/asm-xtensa/vga.h
@@ -0,0 +1,19 @@
+/*
+ * include/asm-xtensa/vga.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_VGA_H
+#define _XTENSA_VGA_H
+
+#define VGA_MAP_MEM(x) (unsigned long)phys_to_virt(x)
+
+#define vga_readb(x) (*(x))
+#define vga_writeb(x,y) (*(y) = (x))
+
+#endif
diff --git a/include/asm-xtensa/xor.h b/include/asm-xtensa/xor.h
new file mode 100644
index 000000000000..e7b1f083991d
--- /dev/null
+++ b/include/asm-xtensa/xor.h
@@ -0,0 +1,16 @@
+/*
+ * include/asm-xtensa/xor.h
+ *
+ * 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 - 2005 Tensilica Inc.
+ */
+
+#ifndef _XTENSA_XOR_H
+#define _XTENSA_XOR_H
+
+#include <asm-generic/xor.h>
+
+#endif
diff --git a/include/asm-xtensa/xtensa/cacheasm.h b/include/asm-xtensa/xtensa/cacheasm.h
new file mode 100644
index 000000000000..0cdbb0bf180e
--- /dev/null
+++ b/include/asm-xtensa/xtensa/cacheasm.h
@@ -0,0 +1,708 @@
+#ifndef XTENSA_CACHEASM_H
+#define XTENSA_CACHEASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/cacheasm.h -- assembler-specific cache
+ * related definitions that depend on CORE configuration.
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/coreasm.h>
+
+
+/*
+ * This header file defines assembler macros of the form:
+ * <x>cache_<func>
+ * where <x> is 'i' or 'd' for instruction and data caches,
+ * and <func> indicates the function of the macro.
+ *
+ * The following functions <func> are defined,
+ * and apply only to the specified cache (I or D):
+ *
+ * reset
+ * Resets the cache.
+ *
+ * sync
+ * Makes sure any previous cache instructions have been completed;
+ * ie. makes sure any previous cache control operations
+ * have had full effect and been synchronized to memory.
+ * Eg. any invalidate completed [so as not to generate a hit],
+ * any writebacks or other pipelined writes written to memory, etc.
+ *
+ * invalidate_line (single cache line)
+ * invalidate_region (specified memory range)
+ * invalidate_all (entire cache)
+ * Invalidates all cache entries that cache
+ * data from the specified memory range.
+ * NOTE: locked entries are not invalidated.
+ *
+ * writeback_line (single cache line)
+ * writeback_region (specified memory range)
+ * writeback_all (entire cache)
+ * Writes back to memory all dirty cache entries
+ * that cache data from the specified memory range,
+ * and marks these entries as clean.
+ * NOTE: on some future implementations, this might
+ * also invalidate.
+ * NOTE: locked entries are written back, but never invalidated.
+ * NOTE: instruction caches never implement writeback.
+ *
+ * writeback_inv_line (single cache line)
+ * writeback_inv_region (specified memory range)
+ * writeback_inv_all (entire cache)
+ * Writes back to memory all dirty cache entries
+ * that cache data from the specified memory range,
+ * and invalidates these entries (including all clean
+ * cache entries that cache data from that range).
+ * NOTE: locked entries are written back but not invalidated.
+ * NOTE: instruction caches never implement writeback.
+ *
+ * lock_line (single cache line)
+ * lock_region (specified memory range)
+ * Prefetch and lock the specified memory range into cache.
+ * NOTE: if any part of the specified memory range cannot
+ * be locked, a ??? exception occurs. These macros don't
+ * do anything special (yet anyway) to handle this situation.
+ *
+ * unlock_line (single cache line)
+ * unlock_region (specified memory range)
+ * unlock_all (entire cache)
+ * Unlock cache entries that cache the specified memory range.
+ * Entries not already locked are unaffected.
+ */
+
+
+
+/*************************** GENERIC -- ALL CACHES ***************************/
+
+
+/*
+ * The following macros assume the following cache size/parameter limits
+ * in the current Xtensa core implementation:
+ * cache size: 1024 bytes minimum
+ * line size: 16 - 64 bytes
+ * way count: 1 - 4
+ *
+ * Minimum entries per way (ie. per associativity) = 1024 / 64 / 4 = 4
+ * Hence the assumption that each loop can execute four cache instructions.
+ *
+ * Correspondingly, the offset range of instructions is assumed able to cover
+ * four lines, ie. offsets {0,1,2,3} * line_size are assumed valid for
+ * both hit and indexed cache instructions. Ie. these offsets are all
+ * valid: 0, 16, 32, 48, 64, 96, 128, 192 (for line sizes 16, 32, 64).
+ * This is true of all original cache instructions
+ * (dhi, ihi, dhwb, dhwbi, dii, iii) which have offsets
+ * of 0 to 1020 in multiples of 4 (ie. 8 bits shifted by 2).
+ * This is also true of subsequent cache instructions
+ * (dhu, ihu, diu, iiu, diwb, diwbi, dpfl, ipfl) which have offsets
+ * of 0 to 240 in multiples of 16 (ie. 4 bits shifted by 4).
+ *
+ * (Maximum cache size, currently 32k, doesn't affect the following macros.
+ * Cache ways > MMU min page size cause aliasing but that's another matter.)
+ */
+
+
+
+/*
+ * Macro to apply an 'indexed' cache instruction to the entire cache.
+ *
+ * Parameters:
+ * cainst instruction/ that takes an address register parameter
+ * and an offset parameter (in range 0 .. 3*linesize).
+ * size size of cache in bytes
+ * linesize size of cache line in bytes
+ * assoc_or1 number of associativities (ways/sets) in cache
+ * if all sets affected by cainst,
+ * or 1 if only one set (or not all sets) of the cache
+ * is affected by cainst (eg. DIWB or DIWBI [not yet ISA defined]).
+ * aa, ab unique address registers (temporaries)
+ */
+
+ .macro cache_index_all cainst, size, linesize, assoc_or1, aa, ab
+
+ // Sanity-check on cache parameters:
+ .ifne (\size % (\linesize * \assoc_or1 * 4))
+ .err // cache configuration outside expected/supported range!
+ .endif
+
+ // \size byte cache, \linesize byte lines, \assoc_or1 way(s) affected by each \cainst.
+ movi \aa, (\size / (\linesize * \assoc_or1 * 4))
+ // Possible improvement: need only loop if \aa > 1 ;
+ // however that particular condition is highly unlikely.
+ movi \ab, 0 // to iterate over cache
+ floop \aa, cachex\@
+ \cainst \ab, 0*\linesize
+ \cainst \ab, 1*\linesize
+ \cainst \ab, 2*\linesize
+ \cainst \ab, 3*\linesize
+ addi \ab, \ab, 4*\linesize // move to next line
+ floopend \aa, cachex\@
+
+ .endm
+
+
+/*
+ * Macro to apply a 'hit' cache instruction to a memory region,
+ * ie. to any cache entries that cache a specified portion (region) of memory.
+ * Takes care of the unaligned cases, ie. may apply to one
+ * more cache line than $asize / lineSize if $aaddr is not aligned.
+ *
+ *
+ * Parameters are:
+ * cainst instruction/macro that takes an address register parameter
+ * and an offset parameter (currently always zero)
+ * and generates a cache instruction (eg. "dhi", "dhwb", "ihi", etc.)
+ * linesize_log2 log2(size of cache line in bytes)
+ * addr register containing start address of region (clobbered)
+ * asize register containing size of the region in bytes (clobbered)
+ * askew unique register used as temporary
+ *
+ * !?!?! 2DO: optimization: iterate max(cache_size and \asize) / linesize
+ */
+
+ .macro cache_hit_region cainst, linesize_log2, addr, asize, askew
+
+ // Make \asize the number of iterations:
+ extui \askew, \addr, 0, \linesize_log2 // get unalignment amount of \addr
+ add \asize, \asize, \askew // ... and add it to \asize
+ addi \asize, \asize, (1 << \linesize_log2) - 1 // round up!
+ srli \asize, \asize, \linesize_log2
+
+ // Iterate over region:
+ floopnez \asize, cacheh\@
+ \cainst \addr, 0
+ addi \addr, \addr, (1 << \linesize_log2) // move to next line
+ floopend \asize, cacheh\@
+
+ .endm
+
+
+
+
+
+/*************************** INSTRUCTION CACHE ***************************/
+
+
+/*
+ * Reset/initialize the instruction cache by simply invalidating it:
+ * (need to unlock first also, if cache locking implemented):
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro icache_reset aa, ab
+ icache_unlock_all \aa, \ab
+ icache_invalidate_all \aa, \ab
+ .endm
+
+
+/*
+ * Synchronize after an instruction cache operation,
+ * to be sure everything is in sync with memory as to be
+ * expected following any previous instruction cache control operations.
+ *
+ * Parameters are:
+ * ar an address register (temporary) (currently unused, but may be used in future)
+ */
+ .macro icache_sync ar
+#if XCHAL_ICACHE_SIZE > 0
+ isync
+#endif
+ .endm
+
+
+
+/*
+ * Invalidate a single line of the instruction cache.
+ * Parameters are:
+ * ar address register that contains (virtual) address to invalidate
+ * (may get clobbered in a future implementation, but not currently)
+ * offset (optional) offset to add to \ar to compute effective address to invalidate
+ * (note: some number of lsbits are ignored)
+ */
+ .macro icache_invalidate_line ar, offset
+#if XCHAL_ICACHE_SIZE > 0
+ ihi \ar, \offset // invalidate icache line
+ /*
+ * NOTE: in some version of the silicon [!!!SHOULD HAVE BEEN DOCUMENTED!!!]
+ * 'ihi' doesn't work, so it had been replaced with 'iii'
+ * (which would just invalidate more than it should,
+ * which should be okay other than the performance hit
+ * because cache locking did not exist in that version,
+ * unless user somehow relies on something being cached).
+ * [WHAT VERSION IS IT!!?!?
+ * IS THERE ANY WAY TO TEST FOR THAT HERE, TO OUTPUT 'III' ONLY IF NEEDED!?!?].
+ *
+ * iii \ar, \offset
+ */
+ icache_sync \ar
+#endif
+ .endm
+
+
+
+
+/*
+ * Invalidate instruction cache entries that cache a specified portion of memory.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro icache_invalidate_region astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0
+ // Instruction cache region invalidation:
+ cache_hit_region ihi, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+ icache_sync \ac
+ // End of instruction cache region invalidation
+#endif
+ .endm
+
+
+
+/*
+ * Invalidate entire instruction cache.
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro icache_invalidate_all aa, ab
+#if XCHAL_ICACHE_SIZE > 0
+ // Instruction cache invalidation:
+ cache_index_all iii, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, XCHAL_ICACHE_WAYS, \aa, \ab
+ icache_sync \aa
+ // End of instruction cache invalidation
+#endif
+ .endm
+
+
+
+/*
+ * Lock (prefetch & lock) a single line of the instruction cache.
+ *
+ * Parameters are:
+ * ar address register that contains (virtual) address to lock
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to lock
+ * (note: some number of lsbits are ignored)
+ */
+ .macro icache_lock_line ar, offset
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+ ipfl \ar, \offset /* prefetch and lock icache line */
+ icache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Lock (prefetch & lock) a specified portion of memory into the instruction cache.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro icache_lock_region astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+ // Instruction cache region lock:
+ cache_hit_region ipfl, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+ icache_sync \ac
+ // End of instruction cache region lock
+#endif
+ .endm
+
+
+
+/*
+ * Unlock a single line of the instruction cache.
+ *
+ * Parameters are:
+ * ar address register that contains (virtual) address to unlock
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to unlock
+ * (note: some number of lsbits are ignored)
+ */
+ .macro icache_unlock_line ar, offset
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+ ihu \ar, \offset /* unlock icache line */
+ icache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Unlock a specified portion of memory from the instruction cache.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro icache_unlock_region astart, asize, ac
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+ // Instruction cache region unlock:
+ cache_hit_region ihu, XCHAL_ICACHE_LINEWIDTH, \astart, \asize, \ac
+ icache_sync \ac
+ // End of instruction cache region unlock
+#endif
+ .endm
+
+
+
+/*
+ * Unlock entire instruction cache.
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro icache_unlock_all aa, ab
+#if XCHAL_ICACHE_SIZE > 0 && XCHAL_ICACHE_LINE_LOCKABLE
+ // Instruction cache unlock:
+ cache_index_all iiu, XCHAL_ICACHE_SIZE, XCHAL_ICACHE_LINESIZE, 1, \aa, \ab
+ icache_sync \aa
+ // End of instruction cache unlock
+#endif
+ .endm
+
+
+
+
+
+/*************************** DATA CACHE ***************************/
+
+
+
+/*
+ * Reset/initialize the data cache by simply invalidating it
+ * (need to unlock first also, if cache locking implemented):
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro dcache_reset aa, ab
+ dcache_unlock_all \aa, \ab
+ dcache_invalidate_all \aa, \ab
+ .endm
+
+
+
+
+/*
+ * Synchronize after a data cache operation,
+ * to be sure everything is in sync with memory as to be
+ * expected following any previous data cache control operations.
+ *
+ * Parameters are:
+ * ar an address register (temporary) (currently unused, but may be used in future)
+ */
+ .macro dcache_sync ar
+#if XCHAL_DCACHE_SIZE > 0
+ // This previous sequence errs on the conservative side (too much so); a DSYNC should be sufficient:
+ //memw // synchronize data cache changes relative to subsequent memory accesses
+ //isync // be conservative and ISYNC as well (just to be sure)
+
+ dsync
+#endif
+ .endm
+
+
+
+/*
+ * Synchronize after a data store operation,
+ * to be sure the stored data is completely off the processor
+ * (and assuming there is no buffering outside the processor,
+ * that the data is in memory). This may be required to
+ * ensure that the processor's write buffers are emptied.
+ * A MEMW followed by a read guarantees this, by definition.
+ * We also try to make sure the read itself completes.
+ *
+ * Parameters are:
+ * ar an address register (temporary)
+ */
+ .macro write_sync ar
+ memw // ensure previous memory accesses are complete prior to subsequent memory accesses
+ l32i \ar, sp, 0 // completing this read ensures any previous write has completed, because of MEMW
+ //slot
+ add \ar, \ar, \ar // use the result of the read to help ensure the read completes (in future architectures)
+ .endm
+
+
+/*
+ * Invalidate a single line of the data cache.
+ * Parameters are:
+ * ar address register that contains (virtual) address to invalidate
+ * (may get clobbered in a future implementation, but not currently)
+ * offset (optional) offset to add to \ar to compute effective address to invalidate
+ * (note: some number of lsbits are ignored)
+ */
+ .macro dcache_invalidate_line ar, offset
+#if XCHAL_DCACHE_SIZE > 0
+ dhi \ar, \offset
+ dcache_sync \ar
+#endif
+ .endm
+
+
+
+
+
+/*
+ * Invalidate data cache entries that cache a specified portion of memory.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro dcache_invalidate_region astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0
+ // Data cache region invalidation:
+ cache_hit_region dhi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+ dcache_sync \ac
+ // End of data cache region invalidation
+#endif
+ .endm
+
+
+
+#if 0
+/*
+ * This is a work-around for a bug in SiChip1 (???).
+ * There should be a proper mechanism for not outputting
+ * these instructions when not needed.
+ * To enable work-around, uncomment this and replace 'dii'
+ * with 'dii_s1' everywhere, eg. in dcache_invalidate_all
+ * macro below.
+ */
+ .macro dii_s1 ar, offset
+ dii \ar, \offset
+ or \ar, \ar, \ar
+ or \ar, \ar, \ar
+ or \ar, \ar, \ar
+ or \ar, \ar, \ar
+ .endm
+#endif
+
+
+/*
+ * Invalidate entire data cache.
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro dcache_invalidate_all aa, ab
+#if XCHAL_DCACHE_SIZE > 0
+ // Data cache invalidation:
+ cache_index_all dii, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, XCHAL_DCACHE_WAYS, \aa, \ab
+ dcache_sync \aa
+ // End of data cache invalidation
+#endif
+ .endm
+
+
+
+/*
+ * Writeback a single line of the data cache.
+ * Parameters are:
+ * ar address register that contains (virtual) address to writeback
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to writeback
+ * (note: some number of lsbits are ignored)
+ */
+ .macro dcache_writeback_line ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+ dhwb \ar, \offset
+ dcache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Writeback dirty data cache entries that cache a specified portion of memory.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro dcache_writeback_region astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+ // Data cache region writeback:
+ cache_hit_region dhwb, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+ dcache_sync \ac
+ // End of data cache region writeback
+#endif
+ .endm
+
+
+
+/*
+ * Writeback entire data cache.
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro dcache_writeback_all aa, ab
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_IS_WRITEBACK
+ // Data cache writeback:
+ cache_index_all diwb, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+ dcache_sync \aa
+ // End of data cache writeback
+#endif
+ .endm
+
+
+
+/*
+ * Writeback and invalidate a single line of the data cache.
+ * Parameters are:
+ * ar address register that contains (virtual) address to writeback and invalidate
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to writeback and invalidate
+ * (note: some number of lsbits are ignored)
+ */
+ .macro dcache_writeback_inv_line ar, offset
+#if XCHAL_DCACHE_SIZE > 0
+ dhwbi \ar, \offset /* writeback and invalidate dcache line */
+ dcache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Writeback and invalidate data cache entries that cache a specified portion of memory.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro dcache_writeback_inv_region astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0
+ // Data cache region writeback and invalidate:
+ cache_hit_region dhwbi, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+ dcache_sync \ac
+ // End of data cache region writeback and invalidate
+#endif
+ .endm
+
+
+
+/*
+ * Writeback and invalidate entire data cache.
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro dcache_writeback_inv_all aa, ab
+#if XCHAL_DCACHE_SIZE > 0
+ // Data cache writeback and invalidate:
+#if XCHAL_DCACHE_IS_WRITEBACK
+ cache_index_all diwbi, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+ dcache_sync \aa
+#else /*writeback*/
+ // Data cache does not support writeback, so just invalidate: */
+ dcache_invalidate_all \aa, \ab
+#endif /*writeback*/
+ // End of data cache writeback and invalidate
+#endif
+ .endm
+
+
+
+
+/*
+ * Lock (prefetch & lock) a single line of the data cache.
+ *
+ * Parameters are:
+ * ar address register that contains (virtual) address to lock
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to lock
+ * (note: some number of lsbits are ignored)
+ */
+ .macro dcache_lock_line ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+ dpfl \ar, \offset /* prefetch and lock dcache line */
+ dcache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Lock (prefetch & lock) a specified portion of memory into the data cache.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro dcache_lock_region astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+ // Data cache region lock:
+ cache_hit_region dpfl, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+ dcache_sync \ac
+ // End of data cache region lock
+#endif
+ .endm
+
+
+
+/*
+ * Unlock a single line of the data cache.
+ *
+ * Parameters are:
+ * ar address register that contains (virtual) address to unlock
+ * (may get clobbered in a future implementation, but not currently)
+ * offset offset to add to \ar to compute effective address to unlock
+ * (note: some number of lsbits are ignored)
+ */
+ .macro dcache_unlock_line ar, offset
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+ dhu \ar, \offset /* unlock dcache line */
+ dcache_sync \ar
+#endif
+ .endm
+
+
+
+/*
+ * Unlock a specified portion of memory from the data cache.
+ * Parameters are:
+ * astart start address (register gets clobbered)
+ * asize size of the region in bytes (register gets clobbered)
+ * ac unique register used as temporary
+ */
+ .macro dcache_unlock_region astart, asize, ac
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+ // Data cache region unlock:
+ cache_hit_region dhu, XCHAL_DCACHE_LINEWIDTH, \astart, \asize, \ac
+ dcache_sync \ac
+ // End of data cache region unlock
+#endif
+ .endm
+
+
+
+/*
+ * Unlock entire data cache.
+ *
+ * Parameters:
+ * aa, ab unique address registers (temporaries)
+ */
+ .macro dcache_unlock_all aa, ab
+#if XCHAL_DCACHE_SIZE > 0 && XCHAL_DCACHE_LINE_LOCKABLE
+ // Data cache unlock:
+ cache_index_all diu, XCHAL_DCACHE_SIZE, XCHAL_DCACHE_LINESIZE, 1, \aa, \ab
+ dcache_sync \aa
+ // End of data cache unlock
+#endif
+ .endm
+
+
+#endif /*XTENSA_CACHEASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/cacheattrasm.h b/include/asm-xtensa/xtensa/cacheattrasm.h
new file mode 100644
index 000000000000..1c3e117b3592
--- /dev/null
+++ b/include/asm-xtensa/xtensa/cacheattrasm.h
@@ -0,0 +1,432 @@
+#ifndef XTENSA_CACHEATTRASM_H
+#define XTENSA_CACHEATTRASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/cacheattrasm.h -- assembler-specific
+ * CACHEATTR register related definitions that depend on CORE
+ * configuration.
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/coreasm.h>
+
+
+/*
+ * This header file defines assembler macros of the form:
+ * <x>cacheattr_<func>
+ * where:
+ * <x> is 'i', 'd' or absent for instruction, data
+ * or both caches; and
+ * <func> indicates the function of the macro.
+ *
+ * The following functions are defined:
+ *
+ * icacheattr_get
+ * Reads I-cache CACHEATTR into a2 (clobbers a3-a5).
+ *
+ * dcacheattr_get
+ * Reads D-cache CACHEATTR into a2 (clobbers a3-a5).
+ * (Note: for configs with a real CACHEATTR register, the
+ * above two macros are identical.)
+ *
+ * cacheattr_set
+ * Writes both I-cache and D-cache CACHEATTRs from a2 (a3-a8 clobbered).
+ * Works even when changing one's own code's attributes.
+ *
+ * icacheattr_is_enabled label
+ * Branches to \label if I-cache appears to have been enabled
+ * (eg. if CACHEATTR contains a cache-enabled attribute).
+ * (clobbers a2-a5,SAR)
+ *
+ * dcacheattr_is_enabled label
+ * Branches to \label if D-cache appears to have been enabled
+ * (eg. if CACHEATTR contains a cache-enabled attribute).
+ * (clobbers a2-a5,SAR)
+ *
+ * cacheattr_is_enabled label
+ * Branches to \label if either I-cache or D-cache appears to have been enabled
+ * (eg. if CACHEATTR contains a cache-enabled attribute).
+ * (clobbers a2-a5,SAR)
+ *
+ * The following macros are only defined under certain conditions:
+ *
+ * icacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
+ * Writes I-cache CACHEATTR from a2 (a3-a8 clobbered).
+ *
+ * dcacheattr_set (if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR)
+ * Writes D-cache CACHEATTR from a2 (a3-a8 clobbered).
+ */
+
+
+
+/*************************** GENERIC -- ALL CACHES ***************************/
+
+/*
+ * _cacheattr_get
+ *
+ * (Internal macro.)
+ * Returns value of CACHEATTR register (or closest equivalent) in a2.
+ *
+ * Entry:
+ * (none)
+ * Exit:
+ * a2 value read from CACHEATTR
+ * a3-a5 clobbered (temporaries)
+ */
+ .macro _cacheattr_get tlb
+#if XCHAL_HAVE_CACHEATTR
+ rsr a2, CACHEATTR
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ // We have a config that "mimics" CACHEATTR using a simplified
+ // "MMU" composed of a single statically-mapped way.
+ // DTLB and ITLB are independent, so there's no single
+ // cache attribute that can describe both. So for now
+ // just return the DTLB state.
+ movi a5, 0xE0000000
+ movi a2, 0
+ movi a3, 0
+1: add a3, a3, a5 // next segment
+ r&tlb&1 a4, a3 // get PPN+CA of segment at 0xE0000000, 0xC0000000, ..., 0
+ dsync // interlock???
+ slli a2, a2, 4
+ extui a4, a4, 0, 4 // extract CA
+ or a2, a2, a4
+ bnez a3, 1b
+#else
+ // This macro isn't applicable to arbitrary MMU configurations.
+ // Just return zero.
+ movi a2, 0
+#endif
+ .endm
+
+ .macro icacheattr_get
+ _cacheattr_get itlb
+ .endm
+
+ .macro dcacheattr_get
+ _cacheattr_get dtlb
+ .endm
+
+
+#define XCHAL_CACHEATTR_ALL_BYPASS 0x22222222 /* default (powerup/reset) value of CACHEATTR, all BYPASS
+ mode (ie. disabled/bypassed caches) */
+
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+
+#define XCHAL_FCA_ENAMASK 0x001A /* bitmap of fetch attributes that require enabled icache */
+#define XCHAL_LCA_ENAMASK 0x0003 /* bitmap of load attributes that require enabled dcache */
+#define XCHAL_SCA_ENAMASK 0x0003 /* bitmap of store attributes that require enabled dcache */
+#define XCHAL_LSCA_ENAMASK (XCHAL_LCA_ENAMASK|XCHAL_SCA_ENAMASK) /* l/s attrs requiring enabled dcache */
+#define XCHAL_ALLCA_ENAMASK (XCHAL_FCA_ENAMASK|XCHAL_LSCA_ENAMASK) /* all attrs requiring enabled caches */
+
+/*
+ * _cacheattr_is_enabled
+ *
+ * (Internal macro.)
+ * Branches to \label if CACHEATTR in a2 indicates an enabled
+ * cache, using mask in a3.
+ *
+ * Parameters:
+ * label where to branch to if cache is enabled
+ * Entry:
+ * a2 contains CACHEATTR value used to determine whether
+ * caches are enabled
+ * a3 16-bit constant where each bit correspond to
+ * one of the 16 possible CA values (in a CACHEATTR mask);
+ * CA values that indicate the cache is enabled
+ * have their corresponding bit set in this mask
+ * (eg. use XCHAL_xCA_ENAMASK , above)
+ * Exit:
+ * a2,a4,a5 clobbered
+ * SAR clobbered
+ */
+ .macro _cacheattr_is_enabled label
+ movi a4, 8 // loop 8 times
+.Lcaife\@:
+ extui a5, a2, 0, 4 // get CA nibble
+ ssr a5 // index into mask according to CA...
+ srl a5, a3 // ...and get CA's mask bit in a5 bit 0
+ bbsi.l a5, 0, \label // if CA indicates cache enabled, jump to label
+ srli a2, a2, 4 // next nibble
+ addi a4, a4, -1
+ bnez a4, .Lcaife\@ // loop for each nibble
+ .endm
+
+#else /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+ .macro _cacheattr_is_enabled label
+ j \label // macro not applicable, assume caches always enabled
+ .endm
+#endif /* XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+
+
+
+/*
+ * icacheattr_is_enabled
+ *
+ * Branches to \label if I-cache is enabled.
+ *
+ * Parameters:
+ * label where to branch to if icache is enabled
+ * Entry:
+ * (none)
+ * Exit:
+ * a2-a5, SAR clobbered (temporaries)
+ */
+ .macro icacheattr_is_enabled label
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ icacheattr_get
+ movi a3, XCHAL_FCA_ENAMASK
+#endif
+ _cacheattr_is_enabled \label
+ .endm
+
+/*
+ * dcacheattr_is_enabled
+ *
+ * Branches to \label if D-cache is enabled.
+ *
+ * Parameters:
+ * label where to branch to if dcache is enabled
+ * Entry:
+ * (none)
+ * Exit:
+ * a2-a5, SAR clobbered (temporaries)
+ */
+ .macro dcacheattr_is_enabled label
+#if XCHAL_HAVE_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ dcacheattr_get
+ movi a3, XCHAL_LSCA_ENAMASK
+#endif
+ _cacheattr_is_enabled \label
+ .endm
+
+/*
+ * cacheattr_is_enabled
+ *
+ * Branches to \label if either I-cache or D-cache is enabled.
+ *
+ * Parameters:
+ * label where to branch to if a cache is enabled
+ * Entry:
+ * (none)
+ * Exit:
+ * a2-a5, SAR clobbered (temporaries)
+ */
+ .macro cacheattr_is_enabled label
+#if XCHAL_HAVE_CACHEATTR
+ rsr a2, CACHEATTR
+ movi a3, XCHAL_ALLCA_ENAMASK
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ icacheattr_get
+ movi a3, XCHAL_FCA_ENAMASK
+ _cacheattr_is_enabled \label
+ dcacheattr_get
+ movi a3, XCHAL_LSCA_ENAMASK
+#endif
+ _cacheattr_is_enabled \label
+ .endm
+
+
+
+/*
+ * The ISA does not have a defined way to change the
+ * instruction cache attributes of the running code,
+ * ie. of the memory area that encloses the current PC.
+ * However, each micro-architecture (or class of
+ * configurations within a micro-architecture)
+ * provides a way to deal with this issue.
+ *
+ * Here are a few macros used to implement the relevant
+ * approach taken.
+ */
+
+#if XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ // We have a config that "mimics" CACHEATTR using a simplified
+ // "MMU" composed of a single statically-mapped way.
+
+/*
+ * icacheattr_set
+ *
+ * Entry:
+ * a2 cacheattr value to set
+ * Exit:
+ * a2 unchanged
+ * a3-a8 clobbered (temporaries)
+ */
+ .macro icacheattr_set
+
+ movi a5, 0xE0000000 // mask of upper 3 bits
+ movi a6, 3f // PC where ITLB is set
+ movi a3, 0 // start at region 0 (0 .. 7)
+ and a6, a6, a5 // upper 3 bits of local PC area
+ mov a7, a2 // copy a2 so it doesn't get clobbered
+ j 3f
+
+# if XCHAL_HAVE_XLT_CACHEATTR
+ // Can do translations, use generic method:
+1: sub a6, a3, a5 // address of some other segment
+ ritlb1 a8, a6 // save its PPN+CA
+ dsync // interlock??
+ witlb a4, a6 // make it translate to this code area
+ movi a6, 5f // where to jump into it
+ isync
+ sub a6, a6, a5 // adjust jump address within that other segment
+ jx a6
+
+ // Note that in the following code snippet, which runs at a different virtual
+ // address than it is assembled for, we avoid using literals (eg. via movi/l32r)
+ // just in case literals end up in a different 512 MB segment, and we avoid
+ // instructions that rely on the current PC being what is expected.
+ //
+ .align 4
+ _j 6f // this is at label '5' minus 4 bytes
+ .align 4
+5: witlb a4, a3 // we're in other segment, now can write previous segment's CA
+ isync
+ add a6, a6, a5 // back to previous segment
+ addi a6, a6, -4 // next jump label
+ jx a6
+
+6: sub a6, a3, a5 // address of some other segment
+ witlb a8, a6 // restore PPN+CA of other segment
+ mov a6, a3 // restore a6
+ isync
+# else /* XCHAL_HAVE_XLT_CACHEATTR */
+ // Use micro-architecture specific method.
+ // The following 4-instruction sequence is aligned such that
+ // it all fits within a single I-cache line. Sixteen byte
+ // alignment is sufficient for this (using XCHAL_ICACHE_LINESIZE
+ // actually causes problems because that can be greater than
+ // the alignment of the reset vector, where this macro is often
+ // invoked, which would cause the linker to align the reset
+ // vector code away from the reset vector!!).
+ .align 16 /*XCHAL_ICACHE_LINESIZE*/
+1: _witlb a4, a3 // write wired PTE (CA, no PPN) of 512MB segment to ITLB
+ _isync
+ nop
+ nop
+# endif /* XCHAL_HAVE_XLT_CACHEATTR */
+ beq a3, a5, 4f // done?
+
+ // Note that in the WITLB loop, we don't do any load/stores
+ // (may not be an issue here, but it is important in the DTLB case).
+2: srli a7, a7, 4 // next CA
+ sub a3, a3, a5 // next segment (add 0x20000000)
+3:
+# if XCHAL_HAVE_XLT_CACHEATTR /* if have translation, preserve it */
+ ritlb1 a8, a3 // get current PPN+CA of segment
+ dsync // interlock???
+ extui a4, a7, 0, 4 // extract CA to set
+ srli a8, a8, 4 // clear CA but keep PPN ...
+ slli a8, a8, 4 // ...
+ add a4, a4, a8 // combine new CA with PPN to preserve
+# else
+ extui a4, a7, 0, 4 // extract CA
+# endif
+ beq a3, a6, 1b // current PC's region? if so, do it in a safe way
+ witlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to ITLB
+ bne a3, a5, 2b
+ isync // make sure all ifetch changes take effect
+4:
+ .endm // icacheattr_set
+
+
+/*
+ * dcacheattr_set
+ *
+ * Entry:
+ * a2 cacheattr value to set
+ * Exit:
+ * a2 unchanged
+ * a3-a8 clobbered (temporaries)
+ */
+
+ .macro dcacheattr_set
+
+ movi a5, 0xE0000000 // mask of upper 3 bits
+ movi a3, 0 // start at region 0 (0 .. 7)
+ mov a7, a2 // copy a2 so it doesn't get clobbered
+ j 3f
+ // Note that in the WDTLB loop, we don't do any load/stores
+ // (including implicit l32r via movi) because it isn't safe.
+2: srli a7, a7, 4 // next CA
+ sub a3, a3, a5 // next segment (add 0x20000000)
+3:
+# if XCHAL_HAVE_XLT_CACHEATTR /* if have translation, preserve it */
+ rdtlb1 a8, a3 // get current PPN+CA of segment
+ dsync // interlock???
+ extui a4, a7, 0, 4 // extract CA to set
+ srli a8, a8, 4 // clear CA but keep PPN ...
+ slli a8, a8, 4 // ...
+ add a4, a4, a8 // combine new CA with PPN to preserve
+# else
+ extui a4, a7, 0, 4 // extract CA to set
+# endif
+ wdtlb a4, a3 // write wired PTE (CA [+PPN]) of 512MB segment to DTLB
+ bne a3, a5, 2b
+ dsync // make sure all data path changes take effect
+ .endm // dcacheattr_set
+
+#endif /* XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR */
+
+
+
+/*
+ * cacheattr_set
+ *
+ * Macro that sets the current CACHEATTR safely
+ * (both i and d) according to the current contents of a2.
+ * It works even when changing the cache attributes of
+ * the currently running code.
+ *
+ * Entry:
+ * a2 cacheattr value to set
+ * Exit:
+ * a2 unchanged
+ * a3-a8 clobbered (temporaries)
+ */
+ .macro cacheattr_set
+
+#if XCHAL_HAVE_CACHEATTR
+# if XCHAL_ICACHE_LINESIZE < 4
+ // No i-cache, so can always safely write to CACHEATTR:
+ wsr a2, CACHEATTR
+# else
+ // The Athens micro-architecture, when using the old
+ // exception architecture option (ie. with the CACHEATTR register)
+ // allows changing the cache attributes of the running code
+ // using the following exact sequence aligned to be within
+ // an instruction cache line. (NOTE: using XCHAL_ICACHE_LINESIZE
+ // alignment actually causes problems because that can be greater
+ // than the alignment of the reset vector, where this macro is often
+ // invoked, which would cause the linker to align the reset
+ // vector code away from the reset vector!!).
+ j 1f
+ .align 16 /*XCHAL_ICACHE_LINESIZE*/ // align to within an I-cache line
+1: _wsr a2, CACHEATTR
+ _isync
+ nop
+ nop
+# endif
+#elif XCHAL_HAVE_MIMIC_CACHEATTR || XCHAL_HAVE_XLT_CACHEATTR
+ // DTLB and ITLB are independent, but to keep semantics
+ // of this macro we simply write to both.
+ icacheattr_set
+ dcacheattr_set
+#else
+ // This macro isn't applicable to arbitrary MMU configurations.
+ // Do nothing in this case.
+#endif
+ .endm
+
+
+#endif /*XTENSA_CACHEATTRASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/core.h b/include/asm-xtensa/xtensa/config-linux_be/core.h
new file mode 100644
index 000000000000..d54fe5eb1064
--- /dev/null
+++ b/include/asm-xtensa/xtensa/config-linux_be/core.h
@@ -0,0 +1,1270 @@
+/*
+ * xtensa/config/core.h -- HAL definitions that are dependent on CORE configuration
+ *
+ * This header file is sometimes referred to as the "compile-time HAL" or CHAL.
+ * It was generated for a specific Xtensa processor configuration.
+ *
+ * Source for configuration-independent binaries (which link in a
+ * configuration-specific HAL library) must NEVER include this file.
+ * It is perfectly normal, however, for the HAL source itself to include this file.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_CORE_H
+#define XTENSA_CONFIG_CORE_H
+
+#include <xtensa/hal.h>
+
+
+/*----------------------------------------------------------------------
+ GENERAL
+ ----------------------------------------------------------------------*/
+
+/*
+ * Separators for macros that expand into arrays.
+ * These can be predefined by files that #include this one,
+ * when different separators are required.
+ */
+/* Element separator for macros that expand into 1-dimensional arrays: */
+#ifndef XCHAL_SEP
+#define XCHAL_SEP ,
+#endif
+/* Array separator for macros that expand into 2-dimensional arrays: */
+#ifndef XCHAL_SEP2
+#define XCHAL_SEP2 },{
+#endif
+
+
+/*----------------------------------------------------------------------
+ ENDIANNESS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_BE 1
+#define XCHAL_HAVE_LE 0
+#define XCHAL_MEMORY_ORDER XTHAL_BIGENDIAN
+
+
+/*----------------------------------------------------------------------
+ REGISTER WINDOWS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_WINDOWED 1 /* 1 if windowed registers option configured, 0 otherwise */
+#define XCHAL_NUM_AREGS 64 /* number of physical address regs */
+#define XCHAL_NUM_AREGS_LOG2 6 /* log2(XCHAL_NUM_AREGS) */
+
+
+/*----------------------------------------------------------------------
+ ADDRESS ALIGNMENT
+ ----------------------------------------------------------------------*/
+
+/* These apply to a selected set of core load and store instructions only (see ISA): */
+#define XCHAL_UNALIGNED_LOAD_EXCEPTION 1 /* 1 if unaligned loads cause an exception, 0 otherwise */
+#define XCHAL_UNALIGNED_STORE_EXCEPTION 1 /* 1 if unaligned stores cause an exception, 0 otherwise */
+
+
+/*----------------------------------------------------------------------
+ INTERRUPTS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_INTERRUPTS 1 /* 1 if interrupt option configured, 0 otherwise */
+#define XCHAL_HAVE_HIGHPRI_INTERRUPTS 1 /* 1 if high-priority interrupt option configured, 0 otherwise */
+#define XCHAL_HAVE_HIGHLEVEL_INTERRUPTS XCHAL_HAVE_HIGHPRI_INTERRUPTS
+#define XCHAL_HAVE_NMI 0 /* 1 if NMI option configured, 0 otherwise */
+#define XCHAL_NUM_INTERRUPTS 17 /* number of interrupts */
+#define XCHAL_NUM_INTERRUPTS_LOG2 5 /* number of bits to hold an interrupt number: roundup(log2(number of interrupts)) */
+#define XCHAL_NUM_EXTINTERRUPTS 10 /* number of external interrupts */
+#define XCHAL_NUM_INTLEVELS 4 /* number of interrupt levels (not including level zero!) */
+#define XCHAL_NUM_LOWPRI_LEVELS 1 /* number of low-priority interrupt levels (always 1) */
+#define XCHAL_FIRST_HIGHPRI_LEVEL (XCHAL_NUM_LOWPRI_LEVELS+1) /* level of first high-priority interrupt (always 2) */
+#define XCHAL_EXCM_LEVEL 1 /* level of interrupts masked by PS.EXCM (XEA2 only; always 1 in T10xx);
+ for XEA1, where there is no PS.EXCM, this is always 1;
+ interrupts at levels FIRST_HIGHPRI <= n <= EXCM_LEVEL, if any,
+ are termed "medium priority" interrupts (post T10xx only) */
+/* Note: 1 <= LOWPRI_LEVELS <= EXCM_LEVEL < DEBUGLEVEL <= NUM_INTLEVELS < NMILEVEL <= 15 */
+
+/* Masks of interrupts at each interrupt level: */
+#define XCHAL_INTLEVEL0_MASK 0x00000000
+#define XCHAL_INTLEVEL1_MASK 0x000064F9
+#define XCHAL_INTLEVEL2_MASK 0x00008902
+#define XCHAL_INTLEVEL3_MASK 0x00011204
+#define XCHAL_INTLEVEL4_MASK 0x00000000
+#define XCHAL_INTLEVEL5_MASK 0x00000000
+#define XCHAL_INTLEVEL6_MASK 0x00000000
+#define XCHAL_INTLEVEL7_MASK 0x00000000
+#define XCHAL_INTLEVEL8_MASK 0x00000000
+#define XCHAL_INTLEVEL9_MASK 0x00000000
+#define XCHAL_INTLEVEL10_MASK 0x00000000
+#define XCHAL_INTLEVEL11_MASK 0x00000000
+#define XCHAL_INTLEVEL12_MASK 0x00000000
+#define XCHAL_INTLEVEL13_MASK 0x00000000
+#define XCHAL_INTLEVEL14_MASK 0x00000000
+#define XCHAL_INTLEVEL15_MASK 0x00000000
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_INTLEVEL_MASKS 0x00000000 XCHAL_SEP \
+ 0x000064F9 XCHAL_SEP \
+ 0x00008902 XCHAL_SEP \
+ 0x00011204 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000 XCHAL_SEP \
+ 0x00000000
+
+/* Masks of interrupts at each range 1..n of interrupt levels: */
+#define XCHAL_INTLEVEL0_ANDBELOW_MASK 0x00000000
+#define XCHAL_INTLEVEL1_ANDBELOW_MASK 0x000064F9
+#define XCHAL_INTLEVEL2_ANDBELOW_MASK 0x0000EDFB
+#define XCHAL_INTLEVEL3_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL4_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL5_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL6_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL7_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL8_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL9_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL10_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL11_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL12_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL13_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL14_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_INTLEVEL15_ANDBELOW_MASK 0x0001FFFF
+#define XCHAL_LOWPRI_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK /* mask of all low-priority interrupts */
+#define XCHAL_EXCM_MASK XCHAL_INTLEVEL1_ANDBELOW_MASK /* mask of all interrupts masked by PS.EXCM (or CEXCM) */
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_INTLEVEL_ANDBELOW_MASKS 0x00000000 XCHAL_SEP \
+ 0x000064F9 XCHAL_SEP \
+ 0x0000EDFB XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF XCHAL_SEP \
+ 0x0001FFFF
+
+/* Interrupt numbers for each interrupt level at which only one interrupt was configured: */
+/*#define XCHAL_INTLEVEL1_NUM ...more than one interrupt at this level...*/
+/*#define XCHAL_INTLEVEL2_NUM ...more than one interrupt at this level...*/
+/*#define XCHAL_INTLEVEL3_NUM ...more than one interrupt at this level...*/
+
+/* Level of each interrupt: */
+#define XCHAL_INT0_LEVEL 1
+#define XCHAL_INT1_LEVEL 2
+#define XCHAL_INT2_LEVEL 3
+#define XCHAL_INT3_LEVEL 1
+#define XCHAL_INT4_LEVEL 1
+#define XCHAL_INT5_LEVEL 1
+#define XCHAL_INT6_LEVEL 1
+#define XCHAL_INT7_LEVEL 1
+#define XCHAL_INT8_LEVEL 2
+#define XCHAL_INT9_LEVEL 3
+#define XCHAL_INT10_LEVEL 1
+#define XCHAL_INT11_LEVEL 2
+#define XCHAL_INT12_LEVEL 3
+#define XCHAL_INT13_LEVEL 1
+#define XCHAL_INT14_LEVEL 1
+#define XCHAL_INT15_LEVEL 2
+#define XCHAL_INT16_LEVEL 3
+#define XCHAL_INT17_LEVEL 0
+#define XCHAL_INT18_LEVEL 0
+#define XCHAL_INT19_LEVEL 0
+#define XCHAL_INT20_LEVEL 0
+#define XCHAL_INT21_LEVEL 0
+#define XCHAL_INT22_LEVEL 0
+#define XCHAL_INT23_LEVEL 0
+#define XCHAL_INT24_LEVEL 0
+#define XCHAL_INT25_LEVEL 0
+#define XCHAL_INT26_LEVEL 0
+#define XCHAL_INT27_LEVEL 0
+#define XCHAL_INT28_LEVEL 0
+#define XCHAL_INT29_LEVEL 0
+#define XCHAL_INT30_LEVEL 0
+#define XCHAL_INT31_LEVEL 0
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_INT_LEVELS 1 XCHAL_SEP \
+ 2 XCHAL_SEP \
+ 3 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 2 XCHAL_SEP \
+ 3 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 2 XCHAL_SEP \
+ 3 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 1 XCHAL_SEP \
+ 2 XCHAL_SEP \
+ 3 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0 XCHAL_SEP \
+ 0
+
+/* Type of each interrupt: */
+#define XCHAL_INT0_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT1_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT2_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT3_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT4_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT5_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT6_TYPE XTHAL_INTTYPE_EXTERN_LEVEL
+#define XCHAL_INT7_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT8_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT9_TYPE XTHAL_INTTYPE_EXTERN_EDGE
+#define XCHAL_INT10_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT11_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT12_TYPE XTHAL_INTTYPE_TIMER
+#define XCHAL_INT13_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT14_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT15_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT16_TYPE XTHAL_INTTYPE_SOFTWARE
+#define XCHAL_INT17_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT18_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT19_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT20_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT21_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT22_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT23_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT24_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT25_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT26_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT27_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT28_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT29_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT30_TYPE XTHAL_INTTYPE_UNCONFIGURED
+#define XCHAL_INT31_TYPE XTHAL_INTTYPE_UNCONFIGURED
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_INT_TYPES XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_LEVEL XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
+ XTHAL_INTTYPE_EXTERN_EDGE XCHAL_SEP \
+ XTHAL_INTTYPE_TIMER XCHAL_SEP \
+ XTHAL_INTTYPE_TIMER XCHAL_SEP \
+ XTHAL_INTTYPE_TIMER XCHAL_SEP \
+ XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
+ XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
+ XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
+ XTHAL_INTTYPE_SOFTWARE XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED XCHAL_SEP \
+ XTHAL_INTTYPE_UNCONFIGURED
+
+/* Masks of interrupts for each type of interrupt: */
+#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000
+#define XCHAL_INTTYPE_MASK_SOFTWARE 0x0001E000
+#define XCHAL_INTTYPE_MASK_EXTERN_EDGE 0x00000380
+#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F
+#define XCHAL_INTTYPE_MASK_TIMER 0x00001C00
+#define XCHAL_INTTYPE_MASK_NMI 0x00000000
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_INTTYPE_MASKS 0xFFFE0000 XCHAL_SEP \
+ 0x0001E000 XCHAL_SEP \
+ 0x00000380 XCHAL_SEP \
+ 0x0000007F XCHAL_SEP \
+ 0x00001C00 XCHAL_SEP \
+ 0x00000000
+
+/* Interrupts assigned to each timer (CCOMPARE0 to CCOMPARE3), -1 if unassigned */
+#define XCHAL_TIMER0_INTERRUPT 10
+#define XCHAL_TIMER1_INTERRUPT 11
+#define XCHAL_TIMER2_INTERRUPT 12
+#define XCHAL_TIMER3_INTERRUPT XTHAL_TIMER_UNCONFIGURED
+/* As an array of entries (eg. for C constant arrays): */
+#define XCHAL_TIMER_INTERRUPTS 10 XCHAL_SEP \
+ 11 XCHAL_SEP \
+ 12 XCHAL_SEP \
+ XTHAL_TIMER_UNCONFIGURED
+
+/* Indexing macros: */
+#define _XCHAL_INTLEVEL_MASK(n) XCHAL_INTLEVEL ## n ## _MASK
+#define XCHAL_INTLEVEL_MASK(n) _XCHAL_INTLEVEL_MASK(n) /* n = 0 .. 15 */
+#define _XCHAL_INTLEVEL_ANDBELOWMASK(n) XCHAL_INTLEVEL ## n ## _ANDBELOW_MASK
+#define XCHAL_INTLEVEL_ANDBELOW_MASK(n) _XCHAL_INTLEVEL_ANDBELOWMASK(n) /* n = 0 .. 15 */
+#define _XCHAL_INT_LEVEL(n) XCHAL_INT ## n ## _LEVEL
+#define XCHAL_INT_LEVEL(n) _XCHAL_INT_LEVEL(n) /* n = 0 .. 31 */
+#define _XCHAL_INT_TYPE(n) XCHAL_INT ## n ## _TYPE
+#define XCHAL_INT_TYPE(n) _XCHAL_INT_TYPE(n) /* n = 0 .. 31 */
+#define _XCHAL_TIMER_INTERRUPT(n) XCHAL_TIMER ## n ## _INTERRUPT
+#define XCHAL_TIMER_INTERRUPT(n) _XCHAL_TIMER_INTERRUPT(n) /* n = 0 .. 3 */
+
+
+
+/*
+ * External interrupt vectors/levels.
+ * These macros describe how Xtensa processor interrupt numbers
+ * (as numbered internally, eg. in INTERRUPT and INTENABLE registers)
+ * map to external BInterrupt<n> pins, for those interrupts
+ * configured as external (level-triggered, edge-triggered, or NMI).
+ * See the Xtensa processor databook for more details.
+ */
+
+/* Core interrupt numbers mapped to each EXTERNAL interrupt number: */
+#define XCHAL_EXTINT0_NUM 0 /* (intlevel 1) */
+#define XCHAL_EXTINT1_NUM 1 /* (intlevel 2) */
+#define XCHAL_EXTINT2_NUM 2 /* (intlevel 3) */
+#define XCHAL_EXTINT3_NUM 3 /* (intlevel 1) */
+#define XCHAL_EXTINT4_NUM 4 /* (intlevel 1) */
+#define XCHAL_EXTINT5_NUM 5 /* (intlevel 1) */
+#define XCHAL_EXTINT6_NUM 6 /* (intlevel 1) */
+#define XCHAL_EXTINT7_NUM 7 /* (intlevel 1) */
+#define XCHAL_EXTINT8_NUM 8 /* (intlevel 2) */
+#define XCHAL_EXTINT9_NUM 9 /* (intlevel 3) */
+
+/* Corresponding interrupt masks: */
+#define XCHAL_EXTINT0_MASK 0x00000001
+#define XCHAL_EXTINT1_MASK 0x00000002
+#define XCHAL_EXTINT2_MASK 0x00000004
+#define XCHAL_EXTINT3_MASK 0x00000008
+#define XCHAL_EXTINT4_MASK 0x00000010
+#define XCHAL_EXTINT5_MASK 0x00000020
+#define XCHAL_EXTINT6_MASK 0x00000040
+#define XCHAL_EXTINT7_MASK 0x00000080
+#define XCHAL_EXTINT8_MASK 0x00000100
+#define XCHAL_EXTINT9_MASK 0x00000200
+
+/* Core config interrupt levels mapped to each external interrupt: */
+#define XCHAL_EXTINT0_LEVEL 1 /* (int number 0) */
+#define XCHAL_EXTINT1_LEVEL 2 /* (int number 1) */
+#define XCHAL_EXTINT2_LEVEL 3 /* (int number 2) */
+#define XCHAL_EXTINT3_LEVEL 1 /* (int number 3) */
+#define XCHAL_EXTINT4_LEVEL 1 /* (int number 4) */
+#define XCHAL_EXTINT5_LEVEL 1 /* (int number 5) */
+#define XCHAL_EXTINT6_LEVEL 1 /* (int number 6) */
+#define XCHAL_EXTINT7_LEVEL 1 /* (int number 7) */
+#define XCHAL_EXTINT8_LEVEL 2 /* (int number 8) */
+#define XCHAL_EXTINT9_LEVEL 3 /* (int number 9) */
+
+
+/*----------------------------------------------------------------------
+ EXCEPTIONS and VECTORS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_EXCEPTIONS 1 /* 1 if exception option configured, 0 otherwise */
+
+#define XCHAL_XEA_VERSION 2 /* Xtensa Exception Architecture number: 1 for XEA1 (old), 2 for XEA2 (new) */
+#define XCHAL_HAVE_XEA1 0 /* 1 if XEA1, 0 otherwise */
+#define XCHAL_HAVE_XEA2 1 /* 1 if XEA2, 0 otherwise */
+/* For backward compatibility ONLY -- DO NOT USE (will be removed in future release): */
+#define XCHAL_HAVE_OLD_EXC_ARCH XCHAL_HAVE_XEA1 /* (DEPRECATED) 1 if old exception architecture (XEA1), 0 otherwise (eg. XEA2) */
+#define XCHAL_HAVE_EXCM XCHAL_HAVE_XEA2 /* (DEPRECATED) 1 if PS.EXCM bit exists (currently equals XCHAL_HAVE_TLBS) */
+
+#define XCHAL_RESET_VECTOR_VADDR 0xFE000020
+#define XCHAL_RESET_VECTOR_PADDR 0xFE000020
+#define XCHAL_USER_VECTOR_VADDR 0xD0000220
+#define XCHAL_PROGRAMEXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR /* for backward compatibility */
+#define XCHAL_USEREXC_VECTOR_VADDR XCHAL_USER_VECTOR_VADDR /* for backward compatibility */
+#define XCHAL_USER_VECTOR_PADDR 0x00000220
+#define XCHAL_PROGRAMEXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR /* for backward compatibility */
+#define XCHAL_USEREXC_VECTOR_PADDR XCHAL_USER_VECTOR_PADDR /* for backward compatibility */
+#define XCHAL_KERNEL_VECTOR_VADDR 0xD0000200
+#define XCHAL_STACKEDEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR /* for backward compatibility */
+#define XCHAL_KERNELEXC_VECTOR_VADDR XCHAL_KERNEL_VECTOR_VADDR /* for backward compatibility */
+#define XCHAL_KERNEL_VECTOR_PADDR 0x00000200
+#define XCHAL_STACKEDEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR /* for backward compatibility */
+#define XCHAL_KERNELEXC_VECTOR_PADDR XCHAL_KERNEL_VECTOR_PADDR /* for backward compatibility */
+#define XCHAL_DOUBLEEXC_VECTOR_VADDR 0xD0000290
+#define XCHAL_DOUBLEEXC_VECTOR_PADDR 0x00000290
+#define XCHAL_WINDOW_VECTORS_VADDR 0xD0000000
+#define XCHAL_WINDOW_VECTORS_PADDR 0x00000000
+#define XCHAL_INTLEVEL2_VECTOR_VADDR 0xD0000240
+#define XCHAL_INTLEVEL2_VECTOR_PADDR 0x00000240
+#define XCHAL_INTLEVEL3_VECTOR_VADDR 0xD0000250
+#define XCHAL_INTLEVEL3_VECTOR_PADDR 0x00000250
+#define XCHAL_INTLEVEL4_VECTOR_VADDR 0xFE000520
+#define XCHAL_INTLEVEL4_VECTOR_PADDR 0xFE000520
+#define XCHAL_DEBUG_VECTOR_VADDR XCHAL_INTLEVEL4_VECTOR_VADDR
+#define XCHAL_DEBUG_VECTOR_PADDR XCHAL_INTLEVEL4_VECTOR_PADDR
+
+/* Indexing macros: */
+#define _XCHAL_INTLEVEL_VECTOR_VADDR(n) XCHAL_INTLEVEL ## n ## _VECTOR_VADDR
+#define XCHAL_INTLEVEL_VECTOR_VADDR(n) _XCHAL_INTLEVEL_VECTOR_VADDR(n) /* n = 0 .. 15 */
+
+/*
+ * General Exception Causes
+ * (values of EXCCAUSE special register set by general exceptions,
+ * which vector to the user, kernel, or double-exception vectors):
+ */
+#define XCHAL_EXCCAUSE_ILLEGAL_INSTRUCTION 0 /* Illegal Instruction (IllegalInstruction) */
+#define XCHAL_EXCCAUSE_SYSTEM_CALL 1 /* System Call (SystemCall) */
+#define XCHAL_EXCCAUSE_INSTRUCTION_FETCH_ERROR 2 /* Instruction Fetch Error (InstructionFetchError) */
+#define XCHAL_EXCCAUSE_LOAD_STORE_ERROR 3 /* Load Store Error (LoadStoreError) */
+#define XCHAL_EXCCAUSE_LEVEL1_INTERRUPT 4 /* Level 1 Interrupt (Level1Interrupt) */
+#define XCHAL_EXCCAUSE_ALLOCA 5 /* Stack Extension Assist (Alloca) */
+#define XCHAL_EXCCAUSE_INTEGER_DIVIDE_BY_ZERO 6 /* Integer Divide by Zero (IntegerDivideByZero) */
+#define XCHAL_EXCCAUSE_SPECULATION 7 /* Speculation (Speculation) */
+#define XCHAL_EXCCAUSE_PRIVILEGED 8 /* Privileged Instruction (Privileged) */
+#define XCHAL_EXCCAUSE_UNALIGNED 9 /* Unaligned Load Store (Unaligned) */
+#define XCHAL_EXCCAUSE_ITLB_MISS 16 /* ITlb Miss Exception (ITlbMiss) */
+#define XCHAL_EXCCAUSE_ITLB_MULTIHIT 17 /* ITlb Mutltihit Exception (ITlbMultihit) */
+#define XCHAL_EXCCAUSE_ITLB_PRIVILEGE 18 /* ITlb Privilege Exception (ITlbPrivilege) */
+#define XCHAL_EXCCAUSE_ITLB_SIZE_RESTRICTION 19 /* ITlb Size Restriction Exception (ITlbSizeRestriction) */
+#define XCHAL_EXCCAUSE_FETCH_CACHE_ATTRIBUTE 20 /* Fetch Cache Attribute Exception (FetchCacheAttribute) */
+#define XCHAL_EXCCAUSE_DTLB_MISS 24 /* DTlb Miss Exception (DTlbMiss) */
+#define XCHAL_EXCCAUSE_DTLB_MULTIHIT 25 /* DTlb Multihit Exception (DTlbMultihit) */
+#define XCHAL_EXCCAUSE_DTLB_PRIVILEGE 26 /* DTlb Privilege Exception (DTlbPrivilege) */
+#define XCHAL_EXCCAUSE_DTLB_SIZE_RESTRICTION 27 /* DTlb Size Restriction Exception (DTlbSizeRestriction) */
+#define XCHAL_EXCCAUSE_LOAD_CACHE_ATTRIBUTE 28 /* Load Cache Attribute Exception (LoadCacheAttribute) */
+#define XCHAL_EXCCAUSE_STORE_CACHE_ATTRIBUTE 29 /* Store Cache Attribute Exception (StoreCacheAttribute) */
+#define XCHAL_EXCCAUSE_FLOATING_POINT 40 /* Floating Point Exception (FloatingPoint) */
+
+
+
+/*----------------------------------------------------------------------
+ TIMERS
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_CCOUNT 1 /* 1 if have CCOUNT, 0 otherwise */
+/*#define XCHAL_HAVE_TIMERS XCHAL_HAVE_CCOUNT*/
+#define XCHAL_NUM_TIMERS 3 /* number of CCOMPAREn regs */
+
+
+
+/*----------------------------------------------------------------------
+ DEBUG
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_DEBUG 1 /* 1 if debug option configured, 0 otherwise */
+#define XCHAL_HAVE_OCD 1 /* 1 if OnChipDebug option configured, 0 otherwise */
+#define XCHAL_NUM_IBREAK 2 /* number of IBREAKn regs */
+#define XCHAL_NUM_DBREAK 2 /* number of DBREAKn regs */
+#define XCHAL_DEBUGLEVEL 4 /* debug interrupt level */
+/*DebugExternalInterrupt 0 0|1*/
+/*DebugUseDIRArray 0 0|1*/
+
+
+
+
+/*----------------------------------------------------------------------
+ COPROCESSORS and EXTRA STATE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_CP 0 /* 1 if coprocessor option configured (CPENABLE present) */
+#define XCHAL_CP_MAXCFG 0 /* max allowed cp id plus one (per cfg) */
+
+#include <xtensa/config/tie.h>
+
+
+
+
+/*----------------------------------------------------------------------
+ INTERNAL I/D RAM/ROMs and XLMI
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_INSTROM 0 /* number of core instruction ROMs configured */
+#define XCHAL_NUM_INSTRAM 0 /* number of core instruction RAMs configured */
+#define XCHAL_NUM_DATAROM 0 /* number of core data ROMs configured */
+#define XCHAL_NUM_DATARAM 0 /* number of core data RAMs configured */
+#define XCHAL_NUM_XLMI 0 /* number of core XLMI ports configured */
+#define XCHAL_NUM_IROM XCHAL_NUM_INSTROM /* (DEPRECATED) */
+#define XCHAL_NUM_IRAM XCHAL_NUM_INSTRAM /* (DEPRECATED) */
+#define XCHAL_NUM_DROM XCHAL_NUM_DATAROM /* (DEPRECATED) */
+#define XCHAL_NUM_DRAM XCHAL_NUM_DATARAM /* (DEPRECATED) */
+
+
+
+/*----------------------------------------------------------------------
+ CACHE
+ ----------------------------------------------------------------------*/
+
+/* Size of the cache lines in log2(bytes): */
+#define XCHAL_ICACHE_LINEWIDTH 4
+#define XCHAL_DCACHE_LINEWIDTH 4
+/* Size of the cache lines in bytes: */
+#define XCHAL_ICACHE_LINESIZE 16
+#define XCHAL_DCACHE_LINESIZE 16
+/* Max for both I-cache and D-cache (used for general alignment): */
+#define XCHAL_CACHE_LINEWIDTH_MAX 4
+#define XCHAL_CACHE_LINESIZE_MAX 16
+
+/* Number of cache sets in log2(lines per way): */
+#define XCHAL_ICACHE_SETWIDTH 8
+#define XCHAL_DCACHE_SETWIDTH 8
+/* Max for both I-cache and D-cache (used for general cache-coherency page alignment): */
+#define XCHAL_CACHE_SETWIDTH_MAX 8
+#define XCHAL_CACHE_SETSIZE_MAX 256
+
+/* Cache set associativity (number of ways): */
+#define XCHAL_ICACHE_WAYS 2
+#define XCHAL_DCACHE_WAYS 2
+
+/* Size of the caches in bytes (ways * 2^(linewidth + setwidth)): */
+#define XCHAL_ICACHE_SIZE 8192
+#define XCHAL_DCACHE_SIZE 8192
+
+/* Cache features: */
+#define XCHAL_DCACHE_IS_WRITEBACK 0
+/* Whether cache locking feature is available: */
+#define XCHAL_ICACHE_LINE_LOCKABLE 0
+#define XCHAL_DCACHE_LINE_LOCKABLE 0
+
+/* Number of (encoded) cache attribute bits: */
+#define XCHAL_CA_BITS 4 /* number of bits needed to hold cache attribute encoding */
+/* (The number of access mode bits (decoded cache attribute bits) is defined by the architecture; see xtensa/hal.h?) */
+
+
+/* Cache Attribute encodings -- lists of access modes for each cache attribute: */
+#define XCHAL_FCA_LIST XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_BYPASS XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_BYPASS XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_CACHED XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_CACHED XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_CACHED XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_CACHED XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION XCHAL_SEP \
+ XTHAL_FAM_EXCEPTION
+#define XCHAL_LCA_LIST XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_BYPASSG XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_BYPASSG XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_CACHED XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_CACHED XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_NACACHED XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_NACACHED XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_ISOLATE XCHAL_SEP \
+ XTHAL_LAM_EXCEPTION XCHAL_SEP \
+ XTHAL_LAM_CACHED
+#define XCHAL_SCA_LIST XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_BYPASS XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_WRITETHRU XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_WRITETHRU XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_ISOLATE XCHAL_SEP \
+ XTHAL_SAM_EXCEPTION XCHAL_SEP \
+ XTHAL_SAM_WRITETHRU
+
+/* Test:
+ read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
+ read/only: 0 + 1 + 2 + 4 + 5 + 6 + 8 + 9 + 10 + 12 + 14
+ all: 0 + 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
+ fault: 0 + 2 + 4 + 6 + 8 + 10 + 12 + 14
+ r/w/x cached:
+ r/w/x dcached:
+ I-bypass: 1 + 3
+
+ load guard bit set: 1 + 3
+ load guard bit clr: 0 + 2 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
+ hit-cache r/w/x: 7 + 11
+
+ fams: 5
+ fams: 0 / 6 / 18 / 1 / 2
+ fams: Bypass / Isolate / Cached / Exception / NACached
+
+ MMU okay: yes
+*/
+
+
+/*----------------------------------------------------------------------
+ MMU
+ ----------------------------------------------------------------------*/
+
+/*
+ * General notes on MMU parameters.
+ *
+ * Terminology:
+ * ASID = address-space ID (acts as an "extension" of virtual addresses)
+ * VPN = virtual page number
+ * PPN = physical page number
+ * CA = encoded cache attribute (access modes)
+ * TLB = translation look-aside buffer (term is stretched somewhat here)
+ * I = instruction (fetch accesses)
+ * D = data (load and store accesses)
+ * way = each TLB (ITLB and DTLB) consists of a number of "ways"
+ * that simultaneously match the virtual address of an access;
+ * a TLB successfully translates a virtual address if exactly
+ * one way matches the vaddr; if none match, it is a miss;
+ * if multiple match, one gets a "multihit" exception;
+ * each way can be independently configured in terms of number of
+ * entries, page sizes, which fields are writable or constant, etc.
+ * set = group of contiguous ways with exactly identical parameters
+ * ARF = auto-refill; hardware services a 1st-level miss by loading a PTE
+ * from the page table and storing it in one of the auto-refill ways;
+ * if this PTE load also misses, a miss exception is posted for s/w.
+ * min-wired = a "min-wired" way can be used to map a single (minimum-sized)
+ * page arbitrarily under program control; it has a single entry,
+ * is non-auto-refill (some other way(s) must be auto-refill),
+ * all its fields (VPN, PPN, ASID, CA) are all writable, and it
+ * supports the XCHAL_MMU_MIN_PTE_PAGE_SIZE page size (a current
+ * restriction is that this be the only page size it supports).
+ *
+ * TLB way entries are virtually indexed.
+ * TLB ways that support multiple page sizes:
+ * - must have all writable VPN and PPN fields;
+ * - can only use one page size at any given time (eg. setup at startup),
+ * selected by the respective ITLBCFG or DTLBCFG special register,
+ * whose bits n*4+3 .. n*4 index the list of page sizes for way n
+ * (XCHAL_xTLB_SETm_PAGESZ_LOG2_LIST for set m corresponding to way n);
+ * this list may be sparse for auto-refill ways because auto-refill
+ * ways have independent lists of supported page sizes sharing a
+ * common encoding with PTE entries; the encoding is the index into
+ * this list; unsupported sizes for a given way are zero in the list;
+ * selecting unsupported sizes results in undefined hardware behaviour;
+ * - is only possible for ways 0 thru 7 (due to ITLBCFG/DTLBCFG definition).
+ */
+
+#define XCHAL_HAVE_CACHEATTR 0 /* 1 if CACHEATTR register present, 0 if TLBs present instead */
+#define XCHAL_HAVE_TLBS 1 /* 1 if TLBs present, 0 if CACHEATTR present instead */
+#define XCHAL_HAVE_MMU XCHAL_HAVE_TLBS /* (DEPRECATED; use XCHAL_HAVE_TLBS instead; will be removed in future release) */
+#define XCHAL_HAVE_SPANNING_WAY 0 /* 1 if single way maps entire virtual address space in I+D */
+#define XCHAL_HAVE_IDENTITY_MAP 0 /* 1 if virtual addr == physical addr always, 0 otherwise */
+#define XCHAL_HAVE_MIMIC_CACHEATTR 0 /* 1 if have MMU that mimics a CACHEATTR config (CaMMU) */
+#define XCHAL_HAVE_XLT_CACHEATTR 0 /* 1 if have MMU that mimics a CACHEATTR config, but with translation (CaXltMMU) */
+
+#define XCHAL_MMU_ASID_BITS 8 /* number of bits in ASIDs (address space IDs) */
+#define XCHAL_MMU_ASID_INVALID 0 /* ASID value indicating invalid address space */
+#define XCHAL_MMU_ASID_KERNEL 1 /* ASID value indicating kernel (ring 0) address space */
+#define XCHAL_MMU_RINGS 4 /* number of rings supported (1..4) */
+#define XCHAL_MMU_RING_BITS 2 /* number of bits needed to hold ring number */
+#define XCHAL_MMU_SR_BITS 0 /* number of size-restriction bits supported */
+#define XCHAL_MMU_CA_BITS 4 /* number of bits needed to hold cache attribute encoding */
+#define XCHAL_MMU_MAX_PTE_PAGE_SIZE 12 /* max page size in a PTE structure (log2) */
+#define XCHAL_MMU_MIN_PTE_PAGE_SIZE 12 /* min page size in a PTE structure (log2) */
+
+
+/*** Instruction TLB: ***/
+
+#define XCHAL_ITLB_WAY_BITS 3 /* number of bits holding the ways */
+#define XCHAL_ITLB_WAYS 7 /* number of ways (n-way set-associative TLB) */
+#define XCHAL_ITLB_ARF_WAYS 4 /* number of auto-refill ways */
+#define XCHAL_ITLB_SETS 4 /* number of sets (groups of ways with identical settings) */
+
+/* Way set to which each way belongs: */
+#define XCHAL_ITLB_WAY0_SET 0
+#define XCHAL_ITLB_WAY1_SET 0
+#define XCHAL_ITLB_WAY2_SET 0
+#define XCHAL_ITLB_WAY3_SET 0
+#define XCHAL_ITLB_WAY4_SET 1
+#define XCHAL_ITLB_WAY5_SET 2
+#define XCHAL_ITLB_WAY6_SET 3
+
+/* Ways sets that are used by hardware auto-refill (ARF): */
+#define XCHAL_ITLB_ARF_SETS 1 /* number of auto-refill sets */
+#define XCHAL_ITLB_ARF_SET0 0 /* index of n'th auto-refill set */
+
+/* Way sets that are "min-wired" (see terminology comment above): */
+#define XCHAL_ITLB_MINWIRED_SETS 0 /* number of "min-wired" sets */
+
+
+/* ITLB way set 0 (group of ways 0 thru 3): */
+#define XCHAL_ITLB_SET0_WAY 0 /* index of first way in this way set */
+#define XCHAL_ITLB_SET0_WAYS 4 /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET0_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET0_ENTRIES 4 /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET0_ARF 1 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET0_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET0_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/* ITLB way set 1 (group of ways 4 thru 4): */
+#define XCHAL_ITLB_SET1_WAY 4 /* index of first way in this way set */
+#define XCHAL_ITLB_SET1_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET1_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET1_ENTRIES 4 /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET1_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET1_PAGESIZES 4 /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET1_PAGESZ_BITS 2 /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MIN 20 /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_MAX 26 /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET1_PAGESZ_LOG2_LIST 20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET1_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET1_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET1_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/* ITLB way set 2 (group of ways 5 thru 5): */
+#define XCHAL_ITLB_SET2_WAY 5 /* index of first way in this way set */
+#define XCHAL_ITLB_SET2_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET2_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET2_ENTRIES 2 /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET2_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET2_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET2_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MIN 27 /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_MAX 27 /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET2_PAGESZ_LOG2_LIST 27 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET2_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_VPN_CONSTMASK 0xF0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_PPN_CONSTMASK 0xF8000000 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET2_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET2_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/* Constant ASID values for each entry of ITLB way set 2 (because ASID_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET2_E0_ASID_CONST 0x01
+#define XCHAL_ITLB_SET2_E1_ASID_CONST 0x01
+/* Constant VPN values for each entry of ITLB way set 2 (because VPN_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET2_E0_VPN_CONST 0xD0000000
+#define XCHAL_ITLB_SET2_E1_VPN_CONST 0xD8000000
+/* Constant PPN values for each entry of ITLB way set 2 (because PPN_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET2_E0_PPN_CONST 0x00000000
+#define XCHAL_ITLB_SET2_E1_PPN_CONST 0x00000000
+/* Constant CA values for each entry of ITLB way set 2 (because CA_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET2_E0_CA_CONST 0x07
+#define XCHAL_ITLB_SET2_E1_CA_CONST 0x03
+
+/* ITLB way set 3 (group of ways 6 thru 6): */
+#define XCHAL_ITLB_SET3_WAY 6 /* index of first way in this way set */
+#define XCHAL_ITLB_SET3_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_ITLB_SET3_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
+#define XCHAL_ITLB_SET3_ENTRIES 2 /* number of entries in this way (always a power of 2) */
+#define XCHAL_ITLB_SET3_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_ITLB_SET3_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_ITLB_SET3_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MIN 28 /* log2(minimum supported page size) */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_MAX 28 /* log2(maximum supported page size) */
+#define XCHAL_ITLB_SET3_PAGESZ_LOG2_LIST 28 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_ITLB_SET3_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_VPN_CONSTMASK 0xE0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_PPN_CONSTMASK 0xF0000000 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
+#define XCHAL_ITLB_SET3_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_ITLB_SET3_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/* Constant ASID values for each entry of ITLB way set 3 (because ASID_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET3_E0_ASID_CONST 0x01
+#define XCHAL_ITLB_SET3_E1_ASID_CONST 0x01
+/* Constant VPN values for each entry of ITLB way set 3 (because VPN_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET3_E0_VPN_CONST 0xE0000000
+#define XCHAL_ITLB_SET3_E1_VPN_CONST 0xF0000000
+/* Constant PPN values for each entry of ITLB way set 3 (because PPN_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET3_E0_PPN_CONST 0xF0000000
+#define XCHAL_ITLB_SET3_E1_PPN_CONST 0xF0000000
+/* Constant CA values for each entry of ITLB way set 3 (because CA_CONSTMASK is non-zero): */
+#define XCHAL_ITLB_SET3_E0_CA_CONST 0x07
+#define XCHAL_ITLB_SET3_E1_CA_CONST 0x03
+
+/* Indexing macros: */
+#define _XCHAL_ITLB_SET(n,_what) XCHAL_ITLB_SET ## n ## _what
+#define XCHAL_ITLB_SET(n,what) _XCHAL_ITLB_SET(n, _ ## what )
+#define _XCHAL_ITLB_SET_E(n,i,_what) XCHAL_ITLB_SET ## n ## _E ## i ## _what
+#define XCHAL_ITLB_SET_E(n,i,what) _XCHAL_ITLB_SET_E(n,i, _ ## what )
+/*
+ * Example use: XCHAL_ITLB_SET(XCHAL_ITLB_ARF_SET0,ENTRIES)
+ * to get the value of XCHAL_ITLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
+ */
+
+
+/*** Data TLB: ***/
+
+#define XCHAL_DTLB_WAY_BITS 4 /* number of bits holding the ways */
+#define XCHAL_DTLB_WAYS 10 /* number of ways (n-way set-associative TLB) */
+#define XCHAL_DTLB_ARF_WAYS 4 /* number of auto-refill ways */
+#define XCHAL_DTLB_SETS 5 /* number of sets (groups of ways with identical settings) */
+
+/* Way set to which each way belongs: */
+#define XCHAL_DTLB_WAY0_SET 0
+#define XCHAL_DTLB_WAY1_SET 0
+#define XCHAL_DTLB_WAY2_SET 0
+#define XCHAL_DTLB_WAY3_SET 0
+#define XCHAL_DTLB_WAY4_SET 1
+#define XCHAL_DTLB_WAY5_SET 2
+#define XCHAL_DTLB_WAY6_SET 3
+#define XCHAL_DTLB_WAY7_SET 4
+#define XCHAL_DTLB_WAY8_SET 4
+#define XCHAL_DTLB_WAY9_SET 4
+
+/* Ways sets that are used by hardware auto-refill (ARF): */
+#define XCHAL_DTLB_ARF_SETS 1 /* number of auto-refill sets */
+#define XCHAL_DTLB_ARF_SET0 0 /* index of n'th auto-refill set */
+
+/* Way sets that are "min-wired" (see terminology comment above): */
+#define XCHAL_DTLB_MINWIRED_SETS 1 /* number of "min-wired" sets */
+#define XCHAL_DTLB_MINWIRED_SET0 4 /* index of n'th "min-wired" set */
+
+
+/* DTLB way set 0 (group of ways 0 thru 3): */
+#define XCHAL_DTLB_SET0_WAY 0 /* index of first way in this way set */
+#define XCHAL_DTLB_SET0_WAYS 4 /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET0_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET0_ENTRIES 4 /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET0_ARF 1 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET0_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET0_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET0_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET0_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET0_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET0_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/* DTLB way set 1 (group of ways 4 thru 4): */
+#define XCHAL_DTLB_SET1_WAY 4 /* index of first way in this way set */
+#define XCHAL_DTLB_SET1_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET1_ENTRIES_LOG2 2 /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET1_ENTRIES 4 /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET1_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET1_PAGESIZES 4 /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET1_PAGESZ_BITS 2 /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MIN 20 /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_MAX 26 /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET1_PAGESZ_LOG2_LIST 20 XCHAL_SEP 22 XCHAL_SEP 24 XCHAL_SEP 26 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET1_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET1_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET1_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/* DTLB way set 2 (group of ways 5 thru 5): */
+#define XCHAL_DTLB_SET2_WAY 5 /* index of first way in this way set */
+#define XCHAL_DTLB_SET2_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET2_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET2_ENTRIES 2 /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET2_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET2_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET2_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MIN 27 /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_MAX 27 /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET2_PAGESZ_LOG2_LIST 27 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET2_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_VPN_CONSTMASK 0xF0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_PPN_CONSTMASK 0xF8000000 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET2_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET2_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/* Constant ASID values for each entry of DTLB way set 2 (because ASID_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET2_E0_ASID_CONST 0x01
+#define XCHAL_DTLB_SET2_E1_ASID_CONST 0x01
+/* Constant VPN values for each entry of DTLB way set 2 (because VPN_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET2_E0_VPN_CONST 0xD0000000
+#define XCHAL_DTLB_SET2_E1_VPN_CONST 0xD8000000
+/* Constant PPN values for each entry of DTLB way set 2 (because PPN_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET2_E0_PPN_CONST 0x00000000
+#define XCHAL_DTLB_SET2_E1_PPN_CONST 0x00000000
+/* Constant CA values for each entry of DTLB way set 2 (because CA_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET2_E0_CA_CONST 0x07
+#define XCHAL_DTLB_SET2_E1_CA_CONST 0x03
+
+/* DTLB way set 3 (group of ways 6 thru 6): */
+#define XCHAL_DTLB_SET3_WAY 6 /* index of first way in this way set */
+#define XCHAL_DTLB_SET3_WAYS 1 /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET3_ENTRIES_LOG2 1 /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET3_ENTRIES 2 /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET3_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET3_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET3_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MIN 28 /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_MAX 28 /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET3_PAGESZ_LOG2_LIST 28 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET3_ASID_CONSTMASK 0xFF /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_VPN_CONSTMASK 0xE0000000 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_PPN_CONSTMASK 0xF0000000 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_CA_CONSTMASK 0x0000000F /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET3_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET3_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+/* Constant ASID values for each entry of DTLB way set 3 (because ASID_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET3_E0_ASID_CONST 0x01
+#define XCHAL_DTLB_SET3_E1_ASID_CONST 0x01
+/* Constant VPN values for each entry of DTLB way set 3 (because VPN_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET3_E0_VPN_CONST 0xE0000000
+#define XCHAL_DTLB_SET3_E1_VPN_CONST 0xF0000000
+/* Constant PPN values for each entry of DTLB way set 3 (because PPN_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET3_E0_PPN_CONST 0xF0000000
+#define XCHAL_DTLB_SET3_E1_PPN_CONST 0xF0000000
+/* Constant CA values for each entry of DTLB way set 3 (because CA_CONSTMASK is non-zero): */
+#define XCHAL_DTLB_SET3_E0_CA_CONST 0x07
+#define XCHAL_DTLB_SET3_E1_CA_CONST 0x03
+
+/* DTLB way set 4 (group of ways 7 thru 9): */
+#define XCHAL_DTLB_SET4_WAY 7 /* index of first way in this way set */
+#define XCHAL_DTLB_SET4_WAYS 3 /* number of (contiguous) ways in this way set */
+#define XCHAL_DTLB_SET4_ENTRIES_LOG2 0 /* log2(number of entries in this way) */
+#define XCHAL_DTLB_SET4_ENTRIES 1 /* number of entries in this way (always a power of 2) */
+#define XCHAL_DTLB_SET4_ARF 0 /* 1=autorefill by h/w, 0=non-autorefill (wired/constant/static) */
+#define XCHAL_DTLB_SET4_PAGESIZES 1 /* number of supported page sizes in this way */
+#define XCHAL_DTLB_SET4_PAGESZ_BITS 0 /* number of bits to encode the page size */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MIN 12 /* log2(minimum supported page size) */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_MAX 12 /* log2(maximum supported page size) */
+#define XCHAL_DTLB_SET4_PAGESZ_LOG2_LIST 12 /* list of log2(page size)s, separated by XCHAL_SEP;
+ 2^PAGESZ_BITS entries in list, unsupported entries are zero */
+#define XCHAL_DTLB_SET4_ASID_CONSTMASK 0 /* constant ASID bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_VPN_CONSTMASK 0 /* constant VPN bits, not including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_PPN_CONSTMASK 0 /* constant PPN bits, including entry index bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_CA_CONSTMASK 0 /* constant CA bits; 0 if all writable */
+#define XCHAL_DTLB_SET4_ASID_RESET 0 /* 1 if ASID reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_VPN_RESET 0 /* 1 if VPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_PPN_RESET 0 /* 1 if PPN reset values defined (and all writable); 0 otherwise */
+#define XCHAL_DTLB_SET4_CA_RESET 0 /* 1 if CA reset values defined (and all writable); 0 otherwise */
+
+/* Indexing macros: */
+#define _XCHAL_DTLB_SET(n,_what) XCHAL_DTLB_SET ## n ## _what
+#define XCHAL_DTLB_SET(n,what) _XCHAL_DTLB_SET(n, _ ## what )
+#define _XCHAL_DTLB_SET_E(n,i,_what) XCHAL_DTLB_SET ## n ## _E ## i ## _what
+#define XCHAL_DTLB_SET_E(n,i,what) _XCHAL_DTLB_SET_E(n,i, _ ## what )
+/*
+ * Example use: XCHAL_DTLB_SET(XCHAL_DTLB_ARF_SET0,ENTRIES)
+ * to get the value of XCHAL_DTLB_SET<n>_ENTRIES where <n> is the first auto-refill set.
+ */
+
+
+/*
+ * Determine whether we have a full MMU (with Page Table and Protection)
+ * usable for an MMU-based OS:
+ */
+#if XCHAL_HAVE_TLBS && !XCHAL_HAVE_SPANNING_WAY && XCHAL_ITLB_ARF_WAYS > 0 && XCHAL_DTLB_ARF_WAYS > 0 && XCHAL_MMU_RINGS >= 2
+# define XCHAL_HAVE_PTP_MMU 1 /* have full MMU (with page table [autorefill] and protection) */
+#else
+# define XCHAL_HAVE_PTP_MMU 0 /* don't have full MMU */
+#endif
+
+/*
+ * For full MMUs, report kernel RAM segment and kernel I/O segment static page mappings:
+ */
+#if XCHAL_HAVE_PTP_MMU
+#define XCHAL_KSEG_CACHED_VADDR 0xD0000000 /* virt.addr of kernel RAM cached static map */
+#define XCHAL_KSEG_CACHED_PADDR 0x00000000 /* phys.addr of kseg_cached */
+#define XCHAL_KSEG_CACHED_SIZE 0x08000000 /* size in bytes of kseg_cached (assumed power of 2!!!) */
+#define XCHAL_KSEG_BYPASS_VADDR 0xD8000000 /* virt.addr of kernel RAM bypass (uncached) static map */
+#define XCHAL_KSEG_BYPASS_PADDR 0x00000000 /* phys.addr of kseg_bypass */
+#define XCHAL_KSEG_BYPASS_SIZE 0x08000000 /* size in bytes of kseg_bypass (assumed power of 2!!!) */
+
+#define XCHAL_KIO_CACHED_VADDR 0xE0000000 /* virt.addr of kernel I/O cached static map */
+#define XCHAL_KIO_CACHED_PADDR 0xF0000000 /* phys.addr of kio_cached */
+#define XCHAL_KIO_CACHED_SIZE 0x10000000 /* size in bytes of kio_cached (assumed power of 2!!!) */
+#define XCHAL_KIO_BYPASS_VADDR 0xF0000000 /* virt.addr of kernel I/O bypass (uncached) static map */
+#define XCHAL_KIO_BYPASS_PADDR 0xF0000000 /* phys.addr of kio_bypass */
+#define XCHAL_KIO_BYPASS_SIZE 0x10000000 /* size in bytes of kio_bypass (assumed power of 2!!!) */
+
+#define XCHAL_SEG_MAPPABLE_VADDR 0x00000000 /* start of largest non-static-mapped virtual addr area */
+#define XCHAL_SEG_MAPPABLE_SIZE 0xD0000000 /* size in bytes of " */
+/* define XCHAL_SEG_MAPPABLE2_xxx if more areas present, sorted in order of descending size. */
+#endif
+
+
+/*----------------------------------------------------------------------
+ MISC
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_NUM_WRITEBUFFER_ENTRIES 4 /* number of write buffer entries */
+
+#define XCHAL_CORE_ID "linux_be" /* configuration's alphanumeric core identifier
+ (CoreID) set in the Xtensa Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID 0x00003256 /* software build-unique ID (22-bit) */
+
+/* These definitions describe the hardware targeted by this software: */
+#define XCHAL_HW_CONFIGID0 0xC103D1FF /* config ID reg 0 value (upper 32 of 64 bits) */
+#define XCHAL_HW_CONFIGID1 0x00803256 /* config ID reg 1 value (lower 32 of 64 bits) */
+#define XCHAL_CONFIGID0 XCHAL_HW_CONFIGID0 /* for backward compatibility only -- don't use! */
+#define XCHAL_CONFIGID1 XCHAL_HW_CONFIGID1 /* for backward compatibility only -- don't use! */
+#define XCHAL_HW_RELEASE_MAJOR 1050 /* major release of targeted hardware */
+#define XCHAL_HW_RELEASE_MINOR 1 /* minor release of targeted hardware */
+#define XCHAL_HW_RELEASE_NAME "T1050.1" /* full release name of targeted hardware */
+#define XTHAL_HW_REL_T1050 1
+#define XTHAL_HW_REL_T1050_1 1
+#define XCHAL_HW_CONFIGID_RELIABLE 1
+
+
+/*
+ * Miscellaneous special register fields:
+ */
+
+
+/* DBREAKC (special register number 160): */
+#define XCHAL_DBREAKC_VALIDMASK 0xC000003F /* bits of DBREAKC that are defined */
+/* MASK field: */
+#define XCHAL_DBREAKC_MASK_BITS 6 /* number of bits in MASK field */
+#define XCHAL_DBREAKC_MASK_NUM 64 /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_MASK_SHIFT 0 /* position of MASK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_MASK_MASK 0x0000003F /* mask of bits in MASK field of DBREAKC */
+/* LOADBREAK field: */
+#define XCHAL_DBREAKC_LOADBREAK_BITS 1 /* number of bits in LOADBREAK field */
+#define XCHAL_DBREAKC_LOADBREAK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_LOADBREAK_SHIFT 30 /* position of LOADBREAK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_LOADBREAK_MASK 0x40000000 /* mask of bits in LOADBREAK field of DBREAKC */
+/* STOREBREAK field: */
+#define XCHAL_DBREAKC_STOREBREAK_BITS 1 /* number of bits in STOREBREAK field */
+#define XCHAL_DBREAKC_STOREBREAK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DBREAKC_STOREBREAK_SHIFT 31 /* position of STOREBREAK bits in DBREAKC, starting from lsbit */
+#define XCHAL_DBREAKC_STOREBREAK_MASK 0x80000000 /* mask of bits in STOREBREAK field of DBREAKC */
+
+/* PS (special register number 230): */
+#define XCHAL_PS_VALIDMASK 0x00070FFF /* bits of PS that are defined */
+/* INTLEVEL field: */
+#define XCHAL_PS_INTLEVEL_BITS 4 /* number of bits in INTLEVEL field */
+#define XCHAL_PS_INTLEVEL_NUM 16 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_INTLEVEL_SHIFT 0 /* position of INTLEVEL bits in PS, starting from lsbit */
+#define XCHAL_PS_INTLEVEL_MASK 0x0000000F /* mask of bits in INTLEVEL field of PS */
+/* EXCM field: */
+#define XCHAL_PS_EXCM_BITS 1 /* number of bits in EXCM field */
+#define XCHAL_PS_EXCM_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_EXCM_SHIFT 4 /* position of EXCM bits in PS, starting from lsbit */
+#define XCHAL_PS_EXCM_MASK 0x00000010 /* mask of bits in EXCM field of PS */
+/* PROGSTACK field: */
+#define XCHAL_PS_PROGSTACK_BITS 1 /* number of bits in PROGSTACK field */
+#define XCHAL_PS_PROGSTACK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_PROGSTACK_SHIFT 5 /* position of PROGSTACK bits in PS, starting from lsbit */
+#define XCHAL_PS_PROGSTACK_MASK 0x00000020 /* mask of bits in PROGSTACK field of PS */
+/* RING field: */
+#define XCHAL_PS_RING_BITS 2 /* number of bits in RING field */
+#define XCHAL_PS_RING_NUM 4 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_RING_SHIFT 6 /* position of RING bits in PS, starting from lsbit */
+#define XCHAL_PS_RING_MASK 0x000000C0 /* mask of bits in RING field of PS */
+/* OWB field: */
+#define XCHAL_PS_OWB_BITS 4 /* number of bits in OWB field */
+#define XCHAL_PS_OWB_NUM 16 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_OWB_SHIFT 8 /* position of OWB bits in PS, starting from lsbit */
+#define XCHAL_PS_OWB_MASK 0x00000F00 /* mask of bits in OWB field of PS */
+/* CALLINC field: */
+#define XCHAL_PS_CALLINC_BITS 2 /* number of bits in CALLINC field */
+#define XCHAL_PS_CALLINC_NUM 4 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_CALLINC_SHIFT 16 /* position of CALLINC bits in PS, starting from lsbit */
+#define XCHAL_PS_CALLINC_MASK 0x00030000 /* mask of bits in CALLINC field of PS */
+/* WOE field: */
+#define XCHAL_PS_WOE_BITS 1 /* number of bits in WOE field */
+#define XCHAL_PS_WOE_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_PS_WOE_SHIFT 18 /* position of WOE bits in PS, starting from lsbit */
+#define XCHAL_PS_WOE_MASK 0x00040000 /* mask of bits in WOE field of PS */
+
+/* EXCCAUSE (special register number 232): */
+#define XCHAL_EXCCAUSE_VALIDMASK 0x0000003F /* bits of EXCCAUSE that are defined */
+/* EXCCAUSE field: */
+#define XCHAL_EXCCAUSE_BITS 6 /* number of bits in EXCCAUSE register */
+#define XCHAL_EXCCAUSE_NUM 64 /* max number of possible causes (2^bits) */
+#define XCHAL_EXCCAUSE_SHIFT 0 /* position of EXCCAUSE bits in register, starting from lsbit */
+#define XCHAL_EXCCAUSE_MASK 0x0000003F /* mask of bits in EXCCAUSE register */
+
+/* DEBUGCAUSE (special register number 233): */
+#define XCHAL_DEBUGCAUSE_VALIDMASK 0x0000003F /* bits of DEBUGCAUSE that are defined */
+/* ICOUNT field: */
+#define XCHAL_DEBUGCAUSE_ICOUNT_BITS 1 /* number of bits in ICOUNT field */
+#define XCHAL_DEBUGCAUSE_ICOUNT_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_ICOUNT_SHIFT 0 /* position of ICOUNT bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_ICOUNT_MASK 0x00000001 /* mask of bits in ICOUNT field of DEBUGCAUSE */
+/* IBREAK field: */
+#define XCHAL_DEBUGCAUSE_IBREAK_BITS 1 /* number of bits in IBREAK field */
+#define XCHAL_DEBUGCAUSE_IBREAK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_IBREAK_SHIFT 1 /* position of IBREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_IBREAK_MASK 0x00000002 /* mask of bits in IBREAK field of DEBUGCAUSE */
+/* DBREAK field: */
+#define XCHAL_DEBUGCAUSE_DBREAK_BITS 1 /* number of bits in DBREAK field */
+#define XCHAL_DEBUGCAUSE_DBREAK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_DBREAK_SHIFT 2 /* position of DBREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_DBREAK_MASK 0x00000004 /* mask of bits in DBREAK field of DEBUGCAUSE */
+/* BREAK field: */
+#define XCHAL_DEBUGCAUSE_BREAK_BITS 1 /* number of bits in BREAK field */
+#define XCHAL_DEBUGCAUSE_BREAK_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_BREAK_SHIFT 3 /* position of BREAK bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_BREAK_MASK 0x00000008 /* mask of bits in BREAK field of DEBUGCAUSE */
+/* BREAKN field: */
+#define XCHAL_DEBUGCAUSE_BREAKN_BITS 1 /* number of bits in BREAKN field */
+#define XCHAL_DEBUGCAUSE_BREAKN_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_BREAKN_SHIFT 4 /* position of BREAKN bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_BREAKN_MASK 0x00000010 /* mask of bits in BREAKN field of DEBUGCAUSE */
+/* DEBUGINT field: */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_BITS 1 /* number of bits in DEBUGINT field */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_NUM 2 /* max number of possible causes (2^bits) */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_SHIFT 5 /* position of DEBUGINT bits in DEBUGCAUSE, starting from lsbit */
+#define XCHAL_DEBUGCAUSE_DEBUGINT_MASK 0x00000020 /* mask of bits in DEBUGINT field of DEBUGCAUSE */
+
+
+
+/*----------------------------------------------------------------------
+ ISA
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_HAVE_DENSITY 1 /* 1 if density option configured, 0 otherwise */
+#define XCHAL_HAVE_LOOPS 1 /* 1 if zero-overhead loops option configured, 0 otherwise */
+/* Misc instructions: */
+#define XCHAL_HAVE_NSA 0 /* 1 if NSA/NSAU instructions option configured, 0 otherwise */
+#define XCHAL_HAVE_MINMAX 0 /* 1 if MIN/MAX instructions option configured, 0 otherwise */
+#define XCHAL_HAVE_SEXT 0 /* 1 if sign-extend instruction option configured, 0 otherwise */
+#define XCHAL_HAVE_CLAMPS 0 /* 1 if CLAMPS instruction option configured, 0 otherwise */
+#define XCHAL_HAVE_MAC16 0 /* 1 if MAC16 option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL16 0 /* 1 if 16-bit integer multiply option configured, 0 otherwise */
+/*#define XCHAL_HAVE_POPC 0*/ /* 1 if CRC instruction option configured, 0 otherwise */
+/*#define XCHAL_HAVE_CRC 0*/ /* 1 if POPC instruction option configured, 0 otherwise */
+
+#define XCHAL_HAVE_SPECULATION 0 /* 1 if speculation option configured, 0 otherwise */
+/*#define XCHAL_HAVE_MP_SYNC 0*/ /* 1 if multiprocessor sync. option configured, 0 otherwise */
+#define XCHAL_HAVE_PRID 0 /* 1 if processor ID register configured, 0 otherwise */
+
+#define XCHAL_NUM_MISC_REGS 2 /* number of miscellaneous registers (0..4) */
+
+/* These relate a bit more to TIE: */
+#define XCHAL_HAVE_BOOLEANS 0 /* 1 if booleans option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32 0 /* 1 if 32-bit integer multiply option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32_HIGH 0 /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
+#define XCHAL_HAVE_FP 0 /* 1 if floating point option configured, 0 otherwise */
+
+
+/*----------------------------------------------------------------------
+ DERIVED
+ ----------------------------------------------------------------------*/
+
+#if XCHAL_HAVE_BE
+#define XCHAL_INST_ILLN 0xD60F /* 2-byte illegal instruction, msb-first */
+#define XCHAL_INST_ILLN_BYTE0 0xD6 /* 2-byte illegal instruction, 1st byte */
+#define XCHAL_INST_ILLN_BYTE1 0x0F /* 2-byte illegal instruction, 2nd byte */
+#else
+#define XCHAL_INST_ILLN 0xF06D /* 2-byte illegal instruction, lsb-first */
+#define XCHAL_INST_ILLN_BYTE0 0x6D /* 2-byte illegal instruction, 1st byte */
+#define XCHAL_INST_ILLN_BYTE1 0xF0 /* 2-byte illegal instruction, 2nd byte */
+#endif
+/* Belongs in xtensa/hal.h: */
+#define XTHAL_INST_ILL 0x000000 /* 3-byte illegal instruction */
+
+
+/*
+ * Because information as to exactly which hardware release is targeted
+ * by a given software build is not always available, compile-time HAL
+ * Hardware-Release "_AT" macros are fuzzy (return 0, 1, or XCHAL_MAYBE):
+ */
+#ifndef XCHAL_HW_RELEASE_MAJOR
+# define XCHAL_HW_CONFIGID_RELIABLE 0
+#endif
+#if XCHAL_HW_CONFIGID_RELIABLE
+# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) (XTHAL_REL_LE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) (XTHAL_REL_GE( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_AT(major,minor) (XTHAL_REL_EQ( XCHAL_HW_RELEASE_MAJOR,XCHAL_HW_RELEASE_MINOR, major,minor ) ? 1 : 0)
+# define XCHAL_HW_RELEASE_MAJOR_AT(major) ((XCHAL_HW_RELEASE_MAJOR == (major)) ? 1 : 0)
+#else
+# define XCHAL_HW_RELEASE_AT_OR_BELOW(major,minor) ( ((major) < 1040 && XCHAL_HAVE_XEA2) ? 0 \
+ : ((major) > 1050 && XCHAL_HAVE_XEA1) ? 1 \
+ : XTHAL_MAYBE )
+# define XCHAL_HW_RELEASE_AT_OR_ABOVE(major,minor) ( ((major) >= 2000 && XCHAL_HAVE_XEA1) ? 0 \
+ : (XTHAL_REL_LE(major,minor, 1040,0) && XCHAL_HAVE_XEA2) ? 1 \
+ : XTHAL_MAYBE )
+# define XCHAL_HW_RELEASE_AT(major,minor) ( (((major) < 1040 && XCHAL_HAVE_XEA2) || \
+ ((major) >= 2000 && XCHAL_HAVE_XEA1)) ? 0 : XTHAL_MAYBE)
+# define XCHAL_HW_RELEASE_MAJOR_AT(major) XCHAL_HW_RELEASE_AT(major,0)
+#endif
+
+/*
+ * Specific errata:
+ */
+
+/*
+ * Erratum T1020.H13, T1030.H7, T1040.H10, T1050.H4 (fixed in T1040.3 and T1050.1;
+ * relevant only in XEA1, kernel-vector mode, level-one interrupts and overflows enabled):
+ */
+#define XCHAL_MAYHAVE_ERRATUM_XEA1KWIN (XCHAL_HAVE_XEA1 && \
+ (XCHAL_HW_RELEASE_AT_OR_BELOW(1040,2) != 0 \
+ || XCHAL_HW_RELEASE_AT(1050,0)))
+
+
+
+#endif /*XTENSA_CONFIG_CORE_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/defs.h b/include/asm-xtensa/xtensa/config-linux_be/defs.h
new file mode 100644
index 000000000000..f7c58b273371
--- /dev/null
+++ b/include/asm-xtensa/xtensa/config-linux_be/defs.h
@@ -0,0 +1,270 @@
+/* Definitions for Xtensa instructions, types, and protos. */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+/* Do not modify. This is automatically generated.*/
+
+#ifndef _XTENSA_BASE_HEADER
+#define _XTENSA_BASE_HEADER
+
+#ifdef __XTENSA__
+#if defined(__GNUC__) && !defined(__XCC__)
+
+#define L8UI_ASM(arr, ars, imm) { \
+ __asm__ volatile("l8ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L8UI(ars, imm) \
+({ \
+ unsigned char _arr; \
+ const unsigned char *_ars = ars; \
+ L8UI_ASM(_arr, _ars, imm); \
+ _arr; \
+})
+
+#define L16UI_ASM(arr, ars, imm) { \
+ __asm__ volatile("l16ui %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L16UI(ars, imm) \
+({ \
+ unsigned short _arr; \
+ const unsigned short *_ars = ars; \
+ L16UI_ASM(_arr, _ars, imm); \
+ _arr; \
+})
+
+#define L16SI_ASM(arr, ars, imm) {\
+ __asm__ volatile("l16si %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L16SI(ars, imm) \
+({ \
+ signed short _arr; \
+ const signed short *_ars = ars; \
+ L16SI_ASM(_arr, _ars, imm); \
+ _arr; \
+})
+
+#define L32I_ASM(arr, ars, imm) { \
+ __asm__ volatile("l32i %0, %1, %2" : "=a" (arr) : "a" (ars) , "i" (imm)); \
+}
+
+#define XT_L32I(ars, imm) \
+({ \
+ unsigned _arr; \
+ const unsigned *_ars = ars; \
+ L32I_ASM(_arr, _ars, imm); \
+ _arr; \
+})
+
+#define S8I_ASM(arr, ars, imm) {\
+ __asm__ volatile("s8i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S8I(arr, ars, imm) \
+({ \
+ signed char _arr = arr; \
+ const signed char *_ars = ars; \
+ S8I_ASM(_arr, _ars, imm); \
+})
+
+#define S16I_ASM(arr, ars, imm) {\
+ __asm__ volatile("s16i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S16I(arr, ars, imm) \
+({ \
+ signed short _arr = arr; \
+ const signed short *_ars = ars; \
+ S16I_ASM(_arr, _ars, imm); \
+})
+
+#define S32I_ASM(arr, ars, imm) { \
+ __asm__ volatile("s32i %0, %1, %2" : : "a" (arr), "a" (ars) , "i" (imm) : "memory" ); \
+}
+
+#define XT_S32I(arr, ars, imm) \
+({ \
+ signed int _arr = arr; \
+ const signed int *_ars = ars; \
+ S32I_ASM(_arr, _ars, imm); \
+})
+
+#define ADDI_ASM(art, ars, imm) {\
+ __asm__ ("addi %0, %1, %2" : "=a" (art) : "a" (ars), "i" (imm)); \
+}
+
+#define XT_ADDI(ars, imm) \
+({ \
+ unsigned _art; \
+ unsigned _ars = ars; \
+ ADDI_ASM(_art, _ars, imm); \
+ _art; \
+})
+
+#define ABS_ASM(arr, art) {\
+ __asm__ ("abs %0, %1" : "=a" (arr) : "a" (art)); \
+}
+
+#define XT_ABS(art) \
+({ \
+ unsigned _arr; \
+ signed _art = art; \
+ ABS_ASM(_arr, _art); \
+ _arr; \
+})
+
+/* Note: In the following macros that reference SAR, the magic "state"
+ register is used to capture the dependency on SAR. This is because
+ SAR is a 5-bit register and thus there are no C types that can be
+ used to represent it. It doesn't appear that the SAR register is
+ even relevant to GCC, but it is marked as "clobbered" just in
+ case. */
+
+#define SRC_ASM(arr, ars, art) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("src %0, %1, %2" \
+ : "=a" (arr) : "a" (ars), "a" (art), "t" (_xt_sar)); \
+}
+
+#define XT_SRC(ars, art) \
+({ \
+ unsigned _arr; \
+ unsigned _ars = ars; \
+ unsigned _art = art; \
+ SRC_ASM(_arr, _ars, _art); \
+ _arr; \
+})
+
+#define SSR_ASM(ars) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("ssr %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSR(ars) \
+({ \
+ unsigned _ars = ars; \
+ SSR_ASM(_ars); \
+})
+
+#define SSL_ASM(ars) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("ssl %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSL(ars) \
+({ \
+ unsigned _ars = ars; \
+ SSL_ASM(_ars); \
+})
+
+#define SSA8B_ASM(ars) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("ssa8b %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSA8B(ars) \
+({ \
+ unsigned _ars = ars; \
+ SSA8B_ASM(_ars); \
+})
+
+#define SSA8L_ASM(ars) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("ssa8l %1" : "=t" (_xt_sar) : "a" (ars) : "sar"); \
+}
+
+#define XT_SSA8L(ars) \
+({ \
+ unsigned _ars = ars; \
+ SSA8L_ASM(_ars); \
+})
+
+#define SSAI_ASM(imm) {\
+ register int _xt_sar __asm__ ("state"); \
+ __asm__ ("ssai %1" : "=t" (_xt_sar) : "i" (imm) : "sar"); \
+}
+
+#define XT_SSAI(imm) \
+({ \
+ SSAI_ASM(imm); \
+})
+
+
+
+
+
+
+
+
+#endif /* __GNUC__ && !__XCC__ */
+
+#ifdef __XCC__
+
+/* Core load/store instructions */
+extern unsigned char _TIE_L8UI(const unsigned char * ars, immediate imm);
+extern unsigned short _TIE_L16UI(const unsigned short * ars, immediate imm);
+extern signed short _TIE_L16SI(const signed short * ars, immediate imm);
+extern unsigned _TIE_L32I(const unsigned * ars, immediate imm);
+extern void _TIE_S8I(unsigned char arr, unsigned char * ars, immediate imm);
+extern void _TIE_S16I(unsigned short arr, unsigned short * ars, immediate imm);
+extern void _TIE_S32I(unsigned arr, unsigned * ars, immediate imm);
+
+#define XT_L8UI _TIE_L8UI
+#define XT_L16UI _TIE_L16UI
+#define XT_L16SI _TIE_L16SI
+#define XT_L32I _TIE_L32I
+#define XT_S8I _TIE_S8I
+#define XT_S16I _TIE_S16I
+#define XT_S32I _TIE_S32I
+
+/* Add-immediate instruction */
+extern unsigned _TIE_ADDI(unsigned ars, immediate imm);
+#define XT_ADDI _TIE_ADDI
+
+/* Absolute value instruction */
+extern unsigned _TIE_ABS(int art);
+#define XT_ABS _TIE_ABS
+
+/* funnel shift instructions */
+extern unsigned _TIE_SRC(unsigned ars, unsigned art);
+#define XT_SRC _TIE_SRC
+extern void _TIE_SSR(unsigned ars);
+#define XT_SSR _TIE_SSR
+extern void _TIE_SSL(unsigned ars);
+#define XT_SSL _TIE_SSL
+extern void _TIE_SSA8B(unsigned ars);
+#define XT_SSA8B _TIE_SSA8B
+extern void _TIE_SSA8L(unsigned ars);
+#define XT_SSA8L _TIE_SSA8L
+extern void _TIE_SSAI(immediate imm);
+#define XT_SSAI _TIE_SSAI
+
+
+#endif /* __XCC__ */
+
+#endif /* __XTENSA__ */
+#endif /* !_XTENSA_BASE_HEADER */
diff --git a/include/asm-xtensa/xtensa/config-linux_be/specreg.h b/include/asm-xtensa/xtensa/config-linux_be/specreg.h
new file mode 100644
index 000000000000..fa4106aa9a02
--- /dev/null
+++ b/include/asm-xtensa/xtensa/config-linux_be/specreg.h
@@ -0,0 +1,99 @@
+/*
+ * Xtensa Special Register symbolic names
+ */
+
+/* $Id: specreg.h,v 1.2 2003/03/07 19:15:18 joetaylor Exp $ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+#ifndef XTENSA_SPECREG_H
+#define XTENSA_SPECREG_H
+
+/* Include these special register bitfield definitions, for historical reasons: */
+#include <xtensa/corebits.h>
+
+
+/* Special registers: */
+#define LBEG 0
+#define LEND 1
+#define LCOUNT 2
+#define SAR 3
+#define WINDOWBASE 72
+#define WINDOWSTART 73
+#define PTEVADDR 83
+#define RASID 90
+#define ITLBCFG 91
+#define DTLBCFG 92
+#define IBREAKENABLE 96
+#define DDR 104
+#define IBREAKA_0 128
+#define IBREAKA_1 129
+#define DBREAKA_0 144
+#define DBREAKA_1 145
+#define DBREAKC_0 160
+#define DBREAKC_1 161
+#define EPC_1 177
+#define EPC_2 178
+#define EPC_3 179
+#define EPC_4 180
+#define DEPC 192
+#define EPS_2 194
+#define EPS_3 195
+#define EPS_4 196
+#define EXCSAVE_1 209
+#define EXCSAVE_2 210
+#define EXCSAVE_3 211
+#define EXCSAVE_4 212
+#define INTERRUPT 226
+#define INTENABLE 228
+#define PS 230
+#define EXCCAUSE 232
+#define DEBUGCAUSE 233
+#define CCOUNT 234
+#define ICOUNT 236
+#define ICOUNTLEVEL 237
+#define EXCVADDR 238
+#define CCOMPARE_0 240
+#define CCOMPARE_1 241
+#define CCOMPARE_2 242
+#define MISC_REG_0 244
+#define MISC_REG_1 245
+
+/* Special cases (bases of special register series): */
+#define IBREAKA 128
+#define DBREAKA 144
+#define DBREAKC 160
+#define EPC 176
+#define EPS 192
+#define EXCSAVE 208
+#define CCOMPARE 240
+
+/* Special names for read-only and write-only interrupt registers: */
+#define INTREAD 226
+#define INTSET 226
+#define INTCLEAR 227
+
+#endif /* XTENSA_SPECREG_H */
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/system.h b/include/asm-xtensa/xtensa/config-linux_be/system.h
new file mode 100644
index 000000000000..cf9d4d308e3a
--- /dev/null
+++ b/include/asm-xtensa/xtensa/config-linux_be/system.h
@@ -0,0 +1,198 @@
+/*
+ * xtensa/config/system.h -- HAL definitions that are dependent on SYSTEM configuration
+ *
+ * NOTE: The location and contents of this file are highly subject to change.
+ *
+ * Source for configuration-independent binaries (which link in a
+ * configuration-specific HAL library) must NEVER include this file.
+ * The HAL itself has historically included this file in some instances,
+ * but this is not appropriate either, because the HAL is meant to be
+ * core-specific but system independent.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_SYSTEM_H
+#define XTENSA_CONFIG_SYSTEM_H
+
+/*#include <xtensa/hal.h>*/
+
+
+
+/*----------------------------------------------------------------------
+ DEVICE ADDRESSES
+ ----------------------------------------------------------------------*/
+
+/*
+ * Strange place to find these, but the configuration GUI
+ * allows moving these around to account for various core
+ * configurations. Specific boards (and their BSP software)
+ * will have specific meanings for these components.
+ */
+
+/* I/O Block areas: */
+#define XSHAL_IOBLOCK_CACHED_VADDR 0xE0000000
+#define XSHAL_IOBLOCK_CACHED_PADDR 0xF0000000
+#define XSHAL_IOBLOCK_CACHED_SIZE 0x0E000000
+
+#define XSHAL_IOBLOCK_BYPASS_VADDR 0xF0000000
+#define XSHAL_IOBLOCK_BYPASS_PADDR 0xF0000000
+#define XSHAL_IOBLOCK_BYPASS_SIZE 0x0E000000
+
+/* System ROM: */
+#define XSHAL_ROM_VADDR 0xEE000000
+#define XSHAL_ROM_PADDR 0xFE000000
+#define XSHAL_ROM_SIZE 0x00400000
+/* Largest available area (free of vectors): */
+#define XSHAL_ROM_AVAIL_VADDR 0xEE00052C
+#define XSHAL_ROM_AVAIL_VSIZE 0x003FFAD4
+
+/* System RAM: */
+#define XSHAL_RAM_VADDR 0xD0000000
+#define XSHAL_RAM_PADDR 0x00000000
+#define XSHAL_RAM_VSIZE 0x08000000
+#define XSHAL_RAM_PSIZE 0x10000000
+#define XSHAL_RAM_SIZE XSHAL_RAM_PSIZE
+/* Largest available area (free of vectors): */
+#define XSHAL_RAM_AVAIL_VADDR 0xD0000370
+#define XSHAL_RAM_AVAIL_VSIZE 0x07FFFC90
+
+/*
+ * Shadow system RAM (same device as system RAM, at different address).
+ * (Emulation boards need this for the SONIC Ethernet driver
+ * when data caches are configured for writeback mode.)
+ * NOTE: on full MMU configs, this points to the BYPASS virtual address
+ * of system RAM, ie. is the same as XSHAL_RAM_* except that virtual
+ * addresses are viewed through the BYPASS static map rather than
+ * the CACHED static map.
+ */
+#define XSHAL_RAM_BYPASS_VADDR 0xD8000000
+#define XSHAL_RAM_BYPASS_PADDR 0x00000000
+#define XSHAL_RAM_BYPASS_PSIZE 0x08000000
+
+/* Alternate system RAM (different device than system RAM): */
+#define XSHAL_ALTRAM_VADDR 0xCEE00000
+#define XSHAL_ALTRAM_PADDR 0xC0000000
+#define XSHAL_ALTRAM_SIZE 0x00200000
+
+
+/*----------------------------------------------------------------------
+ * DEVICE-ADDRESS DEPENDENT...
+ *
+ * Values written to CACHEATTR special register (or its equivalent)
+ * to enable and disable caches in various modes.
+ *----------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------
+ BACKWARD COMPATIBILITY ...
+ ----------------------------------------------------------------------*/
+
+/*
+ * NOTE: the following two macros are DEPRECATED. Use the latter
+ * board-specific macros instead, which are specially tuned for the
+ * particular target environments' memory maps.
+ */
+#define XSHAL_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS /* disable caches in bypass mode */
+#define XSHAL_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT /* default setting to enable caches (no writeback!) */
+
+/*----------------------------------------------------------------------
+ ISS (Instruction Set Simulator) SPECIFIC ...
+ ----------------------------------------------------------------------*/
+
+#define XSHAL_ISS_CACHEATTR_WRITEBACK 0x1122222F /* enable caches in write-back mode */
+#define XSHAL_ISS_CACHEATTR_WRITEALLOC 0x1122222F /* enable caches in write-allocate mode */
+#define XSHAL_ISS_CACHEATTR_WRITETHRU 0x1122222F /* enable caches in write-through mode */
+#define XSHAL_ISS_CACHEATTR_BYPASS 0x2222222F /* disable caches in bypass mode */
+#define XSHAL_ISS_CACHEATTR_DEFAULT XSHAL_ISS_CACHEATTR_WRITEBACK /* default setting to enable caches */
+
+/* For Coware only: */
+#define XSHAL_COWARE_CACHEATTR_WRITEBACK 0x11222222 /* enable caches in write-back mode */
+#define XSHAL_COWARE_CACHEATTR_WRITEALLOC 0x11222222 /* enable caches in write-allocate mode */
+#define XSHAL_COWARE_CACHEATTR_WRITETHRU 0x11222222 /* enable caches in write-through mode */
+#define XSHAL_COWARE_CACHEATTR_BYPASS 0x22222222 /* disable caches in bypass mode */
+#define XSHAL_COWARE_CACHEATTR_DEFAULT XSHAL_COWARE_CACHEATTR_WRITEBACK /* default setting to enable caches */
+
+/* For BFM and other purposes: */
+#define XSHAL_ALLVALID_CACHEATTR_WRITEBACK 0x11222222 /* enable caches without any invalid regions */
+#define XSHAL_ALLVALID_CACHEATTR_DEFAULT XSHAL_ALLVALID_CACHEATTR_WRITEBACK /* default setting for caches without any invalid regions */
+
+#define XSHAL_ISS_PIPE_REGIONS 0
+#define XSHAL_ISS_SDRAM_REGIONS 0
+
+
+/*----------------------------------------------------------------------
+ XT2000 BOARD SPECIFIC ...
+ ----------------------------------------------------------------------*/
+
+#define XSHAL_XT2000_CACHEATTR_WRITEBACK 0x22FFFFFF /* enable caches in write-back mode */
+#define XSHAL_XT2000_CACHEATTR_WRITEALLOC 0x22FFFFFF /* enable caches in write-allocate mode */
+#define XSHAL_XT2000_CACHEATTR_WRITETHRU 0x22FFFFFF /* enable caches in write-through mode */
+#define XSHAL_XT2000_CACHEATTR_BYPASS 0x22FFFFFF /* disable caches in bypass mode */
+#define XSHAL_XT2000_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_WRITEBACK /* default setting to enable caches */
+
+#define XSHAL_XT2000_PIPE_REGIONS 0x00001000 /* BusInt pipeline regions */
+#define XSHAL_XT2000_SDRAM_REGIONS 0x00000005 /* BusInt SDRAM regions */
+
+
+/*----------------------------------------------------------------------
+ VECTOR SIZES
+ ----------------------------------------------------------------------*/
+
+/*
+ * Sizes allocated to vectors by the system (memory map) configuration.
+ * These sizes are constrained by core configuration (eg. one vector's
+ * code cannot overflow into another vector) but are dependent on the
+ * system or board (or LSP) memory map configuration.
+ *
+ * Whether or not each vector happens to be in a system ROM is also
+ * a system configuration matter, sometimes useful, included here also:
+ */
+#define XSHAL_RESET_VECTOR_SIZE 0x000004E0
+#define XSHAL_RESET_VECTOR_ISROM 1
+#define XSHAL_USER_VECTOR_SIZE 0x0000001C
+#define XSHAL_USER_VECTOR_ISROM 0
+#define XSHAL_PROGRAMEXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */
+#define XSHAL_USEREXC_VECTOR_SIZE XSHAL_USER_VECTOR_SIZE /* for backward compatibility */
+#define XSHAL_KERNEL_VECTOR_SIZE 0x0000001C
+#define XSHAL_KERNEL_VECTOR_ISROM 0
+#define XSHAL_STACKEDEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */
+#define XSHAL_KERNELEXC_VECTOR_SIZE XSHAL_KERNEL_VECTOR_SIZE /* for backward compatibility */
+#define XSHAL_DOUBLEEXC_VECTOR_SIZE 0x000000E0
+#define XSHAL_DOUBLEEXC_VECTOR_ISROM 0
+#define XSHAL_WINDOW_VECTORS_SIZE 0x00000180
+#define XSHAL_WINDOW_VECTORS_ISROM 0
+#define XSHAL_INTLEVEL2_VECTOR_SIZE 0x0000000C
+#define XSHAL_INTLEVEL2_VECTOR_ISROM 0
+#define XSHAL_INTLEVEL3_VECTOR_SIZE 0x0000000C
+#define XSHAL_INTLEVEL3_VECTOR_ISROM 0
+#define XSHAL_INTLEVEL4_VECTOR_SIZE 0x0000000C
+#define XSHAL_INTLEVEL4_VECTOR_ISROM 1
+#define XSHAL_DEBUG_VECTOR_SIZE XSHAL_INTLEVEL4_VECTOR_SIZE
+#define XSHAL_DEBUG_VECTOR_ISROM XSHAL_INTLEVEL4_VECTOR_ISROM
+
+
+#endif /*XTENSA_CONFIG_SYSTEM_H*/
+
diff --git a/include/asm-xtensa/xtensa/config-linux_be/tie.h b/include/asm-xtensa/xtensa/config-linux_be/tie.h
new file mode 100644
index 000000000000..3c2e514602f4
--- /dev/null
+++ b/include/asm-xtensa/xtensa/config-linux_be/tie.h
@@ -0,0 +1,275 @@
+/*
+ * xtensa/config/tie.h -- HAL definitions that are dependent on CORE and TIE configuration
+ *
+ * This header file is sometimes referred to as the "compile-time HAL" or CHAL.
+ * It was generated for a specific Xtensa processor configuration,
+ * and furthermore for a specific set of TIE source files that extend
+ * basic core functionality.
+ *
+ * Source for configuration-independent binaries (which link in a
+ * configuration-specific HAL library) must NEVER include this file.
+ * It is perfectly normal, however, for the HAL source itself to include this file.
+ */
+
+/*
+ * Copyright (c) 2003 Tensilica, Inc. All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2.1 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like. Any license provided herein, whether implied or
+ * otherwise, applies only to this software file. Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307,
+ * USA.
+ */
+
+
+#ifndef XTENSA_CONFIG_TIE_H
+#define XTENSA_CONFIG_TIE_H
+
+#include <xtensa/hal.h>
+
+
+/*----------------------------------------------------------------------
+ GENERAL
+ ----------------------------------------------------------------------*/
+
+/*
+ * Separators for macros that expand into arrays.
+ * These can be predefined by files that #include this one,
+ * when different separators are required.
+ */
+/* Element separator for macros that expand into 1-dimensional arrays: */
+#ifndef XCHAL_SEP
+#define XCHAL_SEP ,
+#endif
+/* Array separator for macros that expand into 2-dimensional arrays: */
+#ifndef XCHAL_SEP2
+#define XCHAL_SEP2 },{
+#endif
+
+
+
+
+
+
+/*----------------------------------------------------------------------
+ COPROCESSORS and EXTRA STATE
+ ----------------------------------------------------------------------*/
+
+#define XCHAL_CP_NUM 0 /* number of coprocessors */
+#define XCHAL_CP_MAX 0 /* max coprocessor id plus one (0 if none) */
+#define XCHAL_CP_MASK 0x00 /* bitmask of coprocessors by id */
+
+/* Space for coprocessors' state save areas: */
+#define XCHAL_CP0_SA_SIZE 0
+#define XCHAL_CP1_SA_SIZE 0
+#define XCHAL_CP2_SA_SIZE 0
+#define XCHAL_CP3_SA_SIZE 0
+#define XCHAL_CP4_SA_SIZE 0
+#define XCHAL_CP5_SA_SIZE 0
+#define XCHAL_CP6_SA_SIZE 0
+#define XCHAL_CP7_SA_SIZE 0
+/* Minimum required alignments of CP state save areas: */
+#define XCHAL_CP0_SA_ALIGN 1
+#define XCHAL_CP1_SA_ALIGN 1
+#define XCHAL_CP2_SA_ALIGN 1
+#define XCHAL_CP3_SA_ALIGN 1
+#define XCHAL_CP4_SA_ALIGN 1
+#define XCHAL_CP5_SA_ALIGN 1
+#define XCHAL_CP6_SA_ALIGN 1
+#define XCHAL_CP7_SA_ALIGN 1
+
+/* Indexing macros: */
+#define _XCHAL_CP_SA_SIZE(n) XCHAL_CP ## n ## _SA_SIZE
+#define XCHAL_CP_SA_SIZE(n) _XCHAL_CP_SA_SIZE(n) /* n = 0 .. 7 */
+#define _XCHAL_CP_SA_ALIGN(n) XCHAL_CP ## n ## _SA_ALIGN
+#define XCHAL_CP_SA_ALIGN(n) _XCHAL_CP_SA_ALIGN(n) /* n = 0 .. 7 */
+
+
+/* Space for "extra" state (user special registers and non-cp TIE) save area: */
+#define XCHAL_EXTRA_SA_SIZE 0
+#define XCHAL_EXTRA_SA_ALIGN 1
+
+/* Total save area size (extra + all coprocessors) */
+/* (not useful until xthal_{save,restore}_all_extra() is implemented, */
+/* but included for Tor2 beta; doesn't account for alignment!): */
+#define XCHAL_CPEXTRA_SA_SIZE_TOR2 0 /* Tor2Beta temporary definition -- do not use */
+
+/* Combined required alignment for all CP and EXTRA state save areas */
+/* (does not include required alignment for any base config registers): */
+#define XCHAL_CPEXTRA_SA_ALIGN 1
+
+/* ... */
+
+
+#ifdef _ASMLANGUAGE
+/*
+ * Assembly-language specific definitions (assembly macros, etc.).
+ */
+#include <xtensa/config/specreg.h>
+
+/********************
+ * Macros to save and restore the non-coprocessor TIE portion of EXTRA state.
+ */
+
+/* (none) */
+
+
+/********************
+ * Macros to create functions that save and restore all EXTRA (non-coprocessor) state
+ * (does not include zero-overhead loop registers and non-optional registers).
+ */
+
+ /*
+ * Macro that expands to the body of a function that
+ * stores the extra (non-coprocessor) optional/custom state.
+ * Entry: a2 = ptr to save area in which to save extra state
+ * Exit: any register a2-a15 (?) may have been clobbered.
+ */
+ .macro xchal_extra_store_funcbody
+ .endm
+
+
+ /*
+ * Macro that expands to the body of a function that
+ * loads the extra (non-coprocessor) optional/custom state.
+ * Entry: a2 = ptr to save area from which to restore extra state
+ * Exit: any register a2-a15 (?) may have been clobbered.
+ */
+ .macro xchal_extra_load_funcbody
+ .endm
+
+
+/********************
+ * Macros to save and restore the state of each TIE coprocessor.
+ */
+
+
+
+/********************
+ * Macros to create functions that save and restore the state of *any* TIE coprocessor.
+ */
+
+ /*
+ * Macro that expands to the body of a function
+ * that stores the selected coprocessor's state (registers etc).
+ * Entry: a2 = ptr to save area in which to save cp state
+ * a3 = coprocessor number
+ * Exit: any register a2-a15 (?) may have been clobbered.
+ */
+ .macro xchal_cpi_store_funcbody
+ .endm
+
+
+ /*
+ * Macro that expands to the body of a function
+ * that loads the selected coprocessor's state (registers etc).
+ * Entry: a2 = ptr to save area from which to restore cp state
+ * a3 = coprocessor number
+ * Exit: any register a2-a15 (?) may have been clobbered.
+ */
+ .macro xchal_cpi_load_funcbody
+ .endm
+
+#endif /*_ASMLANGUAGE*/
+
+
+/*
+ * Contents of save areas in terms of libdb register numbers.
+ * NOTE: CONTENTS_LIBDB_{UREG,REGF} macros are not defined in this file;
+ * it is up to the user of this header file to define these macros
+ * usefully before each expansion of the CONTENTS_LIBDB macros.
+ * (Fields rsv[123] are reserved for future additions; they are currently
+ * set to zero but may be set to some useful values in the future.)
+ *
+ * CONTENTS_LIBDB_SREG(libdbnum, offset, size, align, rsv1, name, sregnum, bitmask, rsv2, rsv3)
+ * CONTENTS_LIBDB_UREG(libdbnum, offset, size, align, rsv1, name, uregnum, bitmask, rsv2, rsv3)
+ * CONTENTS_LIBDB_REGF(libdbnum, offset, size, align, rsv1, name, index, numentries, contentsize, regname_base, regfile_name, rsv2, rsv3)
+ */
+
+#define XCHAL_EXTRA_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_EXTRA_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP0_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP0_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP1_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP1_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP2_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP2_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP3_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP3_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP4_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP4_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP5_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP5_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP6_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP6_SA_CONTENTS_LIBDB /* empty */
+
+#define XCHAL_CP7_SA_CONTENTS_LIBDB_NUM 0
+#define XCHAL_CP7_SA_CONTENTS_LIBDB /* empty */
+
+
+
+
+
+
+/*----------------------------------------------------------------------
+ MISC
+ ----------------------------------------------------------------------*/
+
+#if 0 /* is there something equivalent for user TIE? */
+#define XCHAL_CORE_ID "linux_be" /* configuration's alphanumeric core identifier
+ (CoreID) set in the Xtensa Processor Generator */
+
+#define XCHAL_BUILD_UNIQUE_ID 0x00003256 /* software build-unique ID (22-bit) */
+
+/* These definitions describe the hardware targeted by this software: */
+#define XCHAL_HW_CONFIGID0 0xC103D1FF /* config ID reg 0 value (upper 32 of 64 bits) */
+#define XCHAL_HW_CONFIGID1 0x00803256 /* config ID reg 1 value (lower 32 of 64 bits) */
+#define XCHAL_CONFIGID0 XCHAL_HW_CONFIGID0 /* for backward compatibility only -- don't use! */
+#define XCHAL_CONFIGID1 XCHAL_HW_CONFIGID1 /* for backward compatibility only -- don't use! */
+#define XCHAL_HW_RELEASE_MAJOR 1050 /* major release of targeted hardware */
+#define XCHAL_HW_RELEASE_MINOR 1 /* minor release of targeted hardware */
+#define XCHAL_HW_RELEASE_NAME "T1050.1" /* full release name of targeted hardware */
+#define XTHAL_HW_REL_T1050 1
+#define XTHAL_HW_REL_T1050_1 1
+#define XCHAL_HW_CONFIGID_RELIABLE 1
+#endif /*0*/
+
+
+
+/*----------------------------------------------------------------------
+ ISA
+ ----------------------------------------------------------------------*/
+
+#if 0 /* these probably don't belong here, but are related to or implemented using TIE */
+#define XCHAL_HAVE_BOOLEANS 0 /* 1 if booleans option configured, 0 otherwise */
+/* Misc instructions: */
+#define XCHAL_HAVE_MUL32 0 /* 1 if 32-bit integer multiply option configured, 0 otherwise */
+#define XCHAL_HAVE_MUL32_HIGH 0 /* 1 if MUL32 option includes MULUH and MULSH, 0 otherwise */
+
+#define XCHAL_HAVE_FP 0 /* 1 if floating point option configured, 0 otherwise */
+#endif /*0*/
+
+
+#endif /*XTENSA_CONFIG_TIE_H*/
+
diff --git a/include/asm-xtensa/xtensa/coreasm.h b/include/asm-xtensa/xtensa/coreasm.h
new file mode 100644
index 000000000000..a8cfb54c20a1
--- /dev/null
+++ b/include/asm-xtensa/xtensa/coreasm.h
@@ -0,0 +1,526 @@
+#ifndef XTENSA_COREASM_H
+#define XTENSA_COREASM_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/coreasm.h -- assembler-specific
+ * definitions that depend on CORE configuration.
+ *
+ * Source for configuration-independent binaries (which link in a
+ * configuration-specific HAL library) must NEVER include this file.
+ * It is perfectly normal, however, for the HAL itself to include this
+ * file.
+ *
+ * This file must NOT include xtensa/config/system.h. Any assembler
+ * header file that depends on system information should likely go in
+ * a new systemasm.h (or sysasm.h) header file.
+ *
+ * NOTE: macro beqi32 is NOT configuration-dependent, and is placed
+ * here til we will have configuration-independent header file.
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/specreg.h>
+
+/*
+ * Assembly-language specific definitions (assembly macros, etc.).
+ */
+
+/*----------------------------------------------------------------------
+ * find_ms_setbit
+ *
+ * This macro finds the most significant bit that is set in <as>
+ * and return its index + <base> in <ad>, or <base> - 1 if <as> is zero.
+ * The index counts starting at zero for the lsbit, so the return
+ * value ranges from <base>-1 (no bit set) to <base>+31 (msbit set).
+ *
+ * Parameters:
+ * <ad> destination address register (any register)
+ * <as> source address register
+ * <at> temporary address register (must be different than <as>)
+ * <base> constant value added to result (usually 0 or 1)
+ * On entry:
+ * <ad> = undefined if different than <as>
+ * <as> = value whose most significant set bit is to be found
+ * <at> = undefined
+ * no other registers are used by this macro.
+ * On exit:
+ * <ad> = <base> + index of msbit set in original <as>,
+ * = <base> - 1 if original <as> was zero.
+ * <as> clobbered (if not <ad>)
+ * <at> clobbered (if not <ad>)
+ * Example:
+ * find_ms_setbit a0, a4, a0, 0 -- return in a0 index of msbit set in a4
+ */
+
+ .macro find_ms_setbit ad, as, at, base
+#if XCHAL_HAVE_NSA
+ movi \at, 31+\base
+ nsau \as, \as // get index of \as, numbered from msbit (32 if absent)
+ sub \ad, \at, \as // get numbering from lsbit (0..31, -1 if absent)
+#else /* XCHAL_HAVE_NSA */
+ movi \at, \base // start with result of 0 (point to lsbit of 32)
+
+ beqz \as, 2f // special case for zero argument: return -1
+ bltui \as, 0x10000, 1f // is it one of the 16 lsbits? (if so, check lower 16 bits)
+ addi \at, \at, 16 // no, increment result to upper 16 bits (of 32)
+ //srli \as, \as, 16 // check upper half (shift right 16 bits)
+ extui \as, \as, 16, 16 // check upper half (shift right 16 bits)
+1: bltui \as, 0x100, 1f // is it one of the 8 lsbits? (if so, check lower 8 bits)
+ addi \at, \at, 8 // no, increment result to upper 8 bits (of 16)
+ srli \as, \as, 8 // shift right to check upper 8 bits
+1: bltui \as, 0x10, 1f // is it one of the 4 lsbits? (if so, check lower 4 bits)
+ addi \at, \at, 4 // no, increment result to upper 4 bits (of 8)
+ srli \as, \as, 4 // shift right 4 bits to check upper half
+1: bltui \as, 0x4, 1f // is it one of the 2 lsbits? (if so, check lower 2 bits)
+ addi \at, \at, 2 // no, increment result to upper 2 bits (of 4)
+ srli \as, \as, 2 // shift right 2 bits to check upper half
+1: bltui \as, 0x2, 1f // is it the lsbit?
+ addi \at, \at, 2 // no, increment result to upper bit (of 2)
+2: addi \at, \at, -1 // (from just above: add 1; from beqz: return -1)
+ //srli \as, \as, 1
+1: // done! \at contains index of msbit set (or -1 if none set)
+ .if 0x\ad - 0x\at // destination different than \at ? (works because regs are a0-a15)
+ mov \ad, \at // then move result to \ad
+ .endif
+#endif /* XCHAL_HAVE_NSA */
+ .endm // find_ms_setbit
+
+/*----------------------------------------------------------------------
+ * find_ls_setbit
+ *
+ * This macro finds the least significant bit that is set in <as>,
+ * and return its index in <ad>.
+ * Usage is the same as for the find_ms_setbit macro.
+ * Example:
+ * find_ls_setbit a0, a4, a0, 0 -- return in a0 index of lsbit set in a4
+ */
+
+ .macro find_ls_setbit ad, as, at, base
+ neg \at, \as // keep only the least-significant bit that is set...
+ and \as, \at, \as // ... in \as
+ find_ms_setbit \ad, \as, \at, \base
+ .endm // find_ls_setbit
+
+/*----------------------------------------------------------------------
+ * find_ls_one
+ *
+ * Same as find_ls_setbit with base zero.
+ * Source (as) and destination (ad) registers must be different.
+ * Provided for backward compatibility.
+ */
+
+ .macro find_ls_one ad, as
+ find_ls_setbit \ad, \as, \ad, 0
+ .endm // find_ls_one
+
+/*----------------------------------------------------------------------
+ * floop, floopnez, floopgtz, floopend
+ *
+ * These macros are used for fast inner loops that
+ * work whether or not the Loops options is configured.
+ * If the Loops option is configured, they simply use
+ * the zero-overhead LOOP instructions; otherwise
+ * they use explicit decrement and branch instructions.
+ *
+ * They are used in pairs, with floop, floopnez or floopgtz
+ * at the beginning of the loop, and floopend at the end.
+ *
+ * Each pair of loop macro calls must be given the loop count
+ * address register and a unique label for that loop.
+ *
+ * Example:
+ *
+ * movi a3, 16 // loop 16 times
+ * floop a3, myloop1
+ * :
+ * bnez a7, end1 // exit loop if a7 != 0
+ * :
+ * floopend a3, myloop1
+ * end1:
+ *
+ * Like the LOOP instructions, these macros cannot be
+ * nested, must include at least one instruction,
+ * cannot call functions inside the loop, etc.
+ * The loop can be exited by jumping to the instruction
+ * following floopend (or elsewhere outside the loop),
+ * or continued by jumping to a NOP instruction placed
+ * immediately before floopend.
+ *
+ * Unlike LOOP instructions, the register passed to floop*
+ * cannot be used inside the loop, because it is used as
+ * the loop counter if the Loops option is not configured.
+ * And its value is undefined after exiting the loop.
+ * And because the loop counter register is active inside
+ * the loop, you can't easily use this construct to loop
+ * across a register file using ROTW as you might with LOOP
+ * instructions, unless you copy the loop register along.
+ */
+
+ /* Named label version of the macros: */
+
+ .macro floop ar, endlabel
+ floop_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+ .endm
+
+ .macro floopnez ar, endlabel
+ floopnez_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+ .endm
+
+ .macro floopgtz ar, endlabel
+ floopgtz_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+ .endm
+
+ .macro floopend ar, endlabel
+ floopend_ \ar, .Lfloopstart_\endlabel, .Lfloopend_\endlabel
+ .endm
+
+ /* Numbered local label version of the macros: */
+#if 0 /*UNTESTED*/
+ .macro floop89 ar
+ floop_ \ar, 8, 9f
+ .endm
+
+ .macro floopnez89 ar
+ floopnez_ \ar, 8, 9f
+ .endm
+
+ .macro floopgtz89 ar
+ floopgtz_ \ar, 8, 9f
+ .endm
+
+ .macro floopend89 ar
+ floopend_ \ar, 8b, 9
+ .endm
+#endif /*0*/
+
+ /* Underlying version of the macros: */
+
+ .macro floop_ ar, startlabel, endlabelref
+ .ifdef _infloop_
+ .if _infloop_
+ .err // Error: floop cannot be nested
+ .endif
+ .endif
+ .set _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+ loop \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+\startlabel:
+ addi \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+ .endm // floop_
+
+ .macro floopnez_ ar, startlabel, endlabelref
+ .ifdef _infloop_
+ .if _infloop_
+ .err // Error: floopnez cannot be nested
+ .endif
+ .endif
+ .set _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+ loopnez \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+ beqz \ar, \endlabelref
+\startlabel:
+ addi \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+ .endm // floopnez_
+
+ .macro floopgtz_ ar, startlabel, endlabelref
+ .ifdef _infloop_
+ .if _infloop_
+ .err // Error: floopgtz cannot be nested
+ .endif
+ .endif
+ .set _infloop_, 1
+#if XCHAL_HAVE_LOOPS
+ loopgtz \ar, \endlabelref
+#else /* XCHAL_HAVE_LOOPS */
+ bltz \ar, \endlabelref
+ beqz \ar, \endlabelref
+\startlabel:
+ addi \ar, \ar, -1
+#endif /* XCHAL_HAVE_LOOPS */
+ .endm // floopgtz_
+
+
+ .macro floopend_ ar, startlabelref, endlabel
+ .ifndef _infloop_
+ .err // Error: floopend without matching floopXXX
+ .endif
+ .ifeq _infloop_
+ .err // Error: floopend without matching floopXXX
+ .endif
+ .set _infloop_, 0
+#if ! XCHAL_HAVE_LOOPS
+ bnez \ar, \startlabelref
+#endif /* XCHAL_HAVE_LOOPS */
+\endlabel:
+ .endm // floopend_
+
+/*----------------------------------------------------------------------
+ * crsil -- conditional RSIL (read/set interrupt level)
+ *
+ * Executes the RSIL instruction if it exists, else just reads PS.
+ * The RSIL instruction does not exist in the new exception architecture
+ * if the interrupt option is not selected.
+ */
+
+ .macro crsil ar, newlevel
+#if XCHAL_HAVE_OLD_EXC_ARCH || XCHAL_HAVE_INTERRUPTS
+ rsil \ar, \newlevel
+#else
+ rsr \ar, PS
+#endif
+ .endm // crsil
+
+/*----------------------------------------------------------------------
+ * window_spill{4,8,12}
+ *
+ * These macros spill callers' register windows to the stack.
+ * They work for both privileged and non-privileged tasks.
+ * Must be called from a windowed ABI context, eg. within
+ * a windowed ABI function (ie. valid stack frame, window
+ * exceptions enabled, not in exception mode, etc).
+ *
+ * This macro requires a single invocation of the window_spill_common
+ * macro in the same assembly unit and section.
+ *
+ * Note that using window_spill{4,8,12} macros is more efficient
+ * than calling a function implemented using window_spill_function,
+ * because the latter needs extra code to figure out the size of
+ * the call to the spilling function.
+ *
+ * Example usage:
+ *
+ * .text
+ * .align 4
+ * .global some_function
+ * .type some_function,@function
+ * some_function:
+ * entry a1, 16
+ * :
+ * :
+ *
+ * window_spill4 // spill windows of some_function's callers; preserves a0..a3 only;
+ * // to use window_spill{8,12} in this example function we'd have
+ * // to increase space allocated by the entry instruction, because
+ * // 16 bytes only allows call4; 32 or 48 bytes (+locals) are needed
+ * // for call8/window_spill8 or call12/window_spill12 respectively.
+ * :
+ *
+ * retw
+ *
+ * window_spill_common // instantiates code used by window_spill4
+ *
+ *
+ * On entry:
+ * none (if window_spill4)
+ * stack frame has enough space allocated for call8 (if window_spill8)
+ * stack frame has enough space allocated for call12 (if window_spill12)
+ * On exit:
+ * a4..a15 clobbered (if window_spill4)
+ * a8..a15 clobbered (if window_spill8)
+ * a12..a15 clobbered (if window_spill12)
+ * no caller windows are in live registers
+ */
+
+ .macro window_spill4
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+ movi a15, 0 // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+ call4 .L__wdwspill_assist28 // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+ call4 .L__wdwspill_assist60 // call deep enough to clear out any live callers
+# endif
+#endif
+ .endm // window_spill4
+
+ .macro window_spill8
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+ movi a15, 0 // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+ call8 .L__wdwspill_assist24 // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+ call8 .L__wdwspill_assist56 // call deep enough to clear out any live callers
+# endif
+#endif
+ .endm // window_spill8
+
+ .macro window_spill12
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 16
+ movi a15, 0 // for 16-register files, no need to call to reach the end
+# elif XCHAL_NUM_AREGS == 32
+ call12 .L__wdwspill_assist20 // call deep enough to clear out any live callers
+# elif XCHAL_NUM_AREGS == 64
+ call12 .L__wdwspill_assist52 // call deep enough to clear out any live callers
+# endif
+#endif
+ .endm // window_spill12
+
+/*----------------------------------------------------------------------
+ * window_spill_function
+ *
+ * This macro outputs a function that will spill its caller's callers'
+ * register windows to the stack. Eg. it could be used to implement
+ * a version of xthal_window_spill() that works in non-privileged tasks.
+ * This works for both privileged and non-privileged tasks.
+ *
+ * Typical usage:
+ *
+ * .text
+ * .align 4
+ * .global my_spill_function
+ * .type my_spill_function,@function
+ * my_spill_function:
+ * window_spill_function
+ *
+ * On entry to resulting function:
+ * none
+ * On exit from resulting function:
+ * none (no caller windows are in live registers)
+ */
+
+ .macro window_spill_function
+#if XCHAL_HAVE_WINDOWED
+# if XCHAL_NUM_AREGS == 32
+ entry sp, 48
+ bbci.l a0, 31, 1f // branch if called with call4
+ bbsi.l a0, 30, 2f // branch if called with call12
+ call8 .L__wdwspill_assist16 // called with call8, only need another 8
+ retw
+1: call12 .L__wdwspill_assist16 // called with call4, only need another 12
+ retw
+2: call4 .L__wdwspill_assist16 // called with call12, only need another 4
+ retw
+# elif XCHAL_NUM_AREGS == 64
+ entry sp, 48
+ bbci.l a0, 31, 1f // branch if called with call4
+ bbsi.l a0, 30, 2f // branch if called with call12
+ call4 .L__wdwspill_assist52 // called with call8, only need a call4
+ retw
+1: call8 .L__wdwspill_assist52 // called with call4, only need a call8
+ retw
+2: call12 .L__wdwspill_assist40 // called with call12, can skip a call12
+ retw
+# elif XCHAL_NUM_AREGS == 16
+ entry sp, 16
+ bbci.l a0, 31, 1f // branch if called with call4
+ bbsi.l a0, 30, 2f // branch if called with call12
+ movi a7, 0 // called with call8
+ retw
+1: movi a11, 0 // called with call4
+2: retw // if called with call12, everything already spilled
+
+// movi a15, 0 // trick to spill all but the direct caller
+// j 1f
+// // The entry instruction is magical in the assembler (gets auto-aligned)
+// // so we have to jump to it to avoid falling through the padding.
+// // We need entry/retw to know where to return.
+//1: entry sp, 16
+// retw
+# else
+# error "unrecognized address register file size"
+# endif
+#endif /* XCHAL_HAVE_WINDOWED */
+ window_spill_common
+ .endm // window_spill_function
+
+/*----------------------------------------------------------------------
+ * window_spill_common
+ *
+ * Common code used by any number of invocations of the window_spill##
+ * and window_spill_function macros.
+ *
+ * Must be instantiated exactly once within a given assembly unit,
+ * within call/j range of and same section as window_spill##
+ * macro invocations for that assembly unit.
+ * (Is automatically instantiated by the window_spill_function macro.)
+ */
+
+ .macro window_spill_common
+#if XCHAL_HAVE_WINDOWED && (XCHAL_NUM_AREGS == 32 || XCHAL_NUM_AREGS == 64)
+ .ifndef .L__wdwspill_defined
+# if XCHAL_NUM_AREGS >= 64
+.L__wdwspill_assist60:
+ entry sp, 32
+ call8 .L__wdwspill_assist52
+ retw
+.L__wdwspill_assist56:
+ entry sp, 16
+ call4 .L__wdwspill_assist52
+ retw
+.L__wdwspill_assist52:
+ entry sp, 48
+ call12 .L__wdwspill_assist40
+ retw
+.L__wdwspill_assist40:
+ entry sp, 48
+ call12 .L__wdwspill_assist28
+ retw
+# endif
+.L__wdwspill_assist28:
+ entry sp, 48
+ call12 .L__wdwspill_assist16
+ retw
+.L__wdwspill_assist24:
+ entry sp, 32
+ call8 .L__wdwspill_assist16
+ retw
+.L__wdwspill_assist20:
+ entry sp, 16
+ call4 .L__wdwspill_assist16
+ retw
+.L__wdwspill_assist16:
+ entry sp, 16
+ movi a15, 0
+ retw
+ .set .L__wdwspill_defined, 1
+ .endif
+#endif /* XCHAL_HAVE_WINDOWED with 32 or 64 aregs */
+ .endm // window_spill_common
+
+/*----------------------------------------------------------------------
+ * beqi32
+ *
+ * macro implements version of beqi for arbitrary 32-bit immidiate value
+ *
+ * beqi32 ax, ay, imm32, label
+ *
+ * Compares value in register ax with imm32 value and jumps to label if
+ * equal. Clobberes register ay if needed
+ *
+ */
+ .macro beqi32 ax, ay, imm, label
+ .ifeq ((\imm-1) & ~7) // 1..8 ?
+ beqi \ax, \imm, \label
+ .else
+ .ifeq (\imm+1) // -1 ?
+ beqi \ax, \imm, \label
+ .else
+ .ifeq (\imm) // 0 ?
+ beqz \ax, \label
+ .else
+ // We could also handle immediates 10,12,16,32,64,128,256
+ // but it would be a long macro...
+ movi \ay, \imm
+ beq \ax, \ay, \label
+ .endif
+ .endif
+ .endif
+ .endm // beqi32
+
+#endif /*XTENSA_COREASM_H*/
+
diff --git a/include/asm-xtensa/xtensa/corebits.h b/include/asm-xtensa/xtensa/corebits.h
new file mode 100644
index 000000000000..e578ade41632
--- /dev/null
+++ b/include/asm-xtensa/xtensa/corebits.h
@@ -0,0 +1,77 @@
+#ifndef XTENSA_COREBITS_H
+#define XTENSA_COREBITS_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * xtensa/corebits.h - Xtensa Special Register field positions and masks.
+ *
+ * (In previous releases, these were defined in specreg.h, a generated file.
+ * This file is not generated, i.e. it is processor configuration independent.)
+ */
+
+
+/* EXCCAUSE register fields: */
+#define EXCCAUSE_EXCCAUSE_SHIFT 0
+#define EXCCAUSE_EXCCAUSE_MASK 0x3F
+/* Exception causes (mostly incomplete!): */
+#define EXCCAUSE_ILLEGAL 0
+#define EXCCAUSE_SYSCALL 1
+#define EXCCAUSE_IFETCHERROR 2
+#define EXCCAUSE_LOADSTOREERROR 3
+#define EXCCAUSE_LEVEL1INTERRUPT 4
+#define EXCCAUSE_ALLOCA 5
+
+/* PS register fields: */
+#define PS_WOE_SHIFT 18
+#define PS_WOE_MASK 0x00040000
+#define PS_WOE PS_WOE_MASK
+#define PS_CALLINC_SHIFT 16
+#define PS_CALLINC_MASK 0x00030000
+#define PS_CALLINC(n) (((n)&3)<<PS_CALLINC_SHIFT) /* n = 0..3 */
+#define PS_OWB_SHIFT 8
+#define PS_OWB_MASK 0x00000F00
+#define PS_OWB(n) (((n)&15)<<PS_OWB_SHIFT) /* n = 0..15 (or 0..7) */
+#define PS_RING_SHIFT 6
+#define PS_RING_MASK 0x000000C0
+#define PS_RING(n) (((n)&3)<<PS_RING_SHIFT) /* n = 0..3 */
+#define PS_UM_SHIFT 5
+#define PS_UM_MASK 0x00000020
+#define PS_UM PS_UM_MASK
+#define PS_EXCM_SHIFT 4
+#define PS_EXCM_MASK 0x00000010
+#define PS_EXCM PS_EXCM_MASK
+#define PS_INTLEVEL_SHIFT 0
+#define PS_INTLEVEL_MASK 0x0000000F
+#define PS_INTLEVEL(n) ((n)&PS_INTLEVEL_MASK) /* n = 0..15 */
+/* Backward compatibility (deprecated): */
+#define PS_PROGSTACK_SHIFT PS_UM_SHIFT
+#define PS_PROGSTACK_MASK PS_UM_MASK
+#define PS_PROG_SHIFT PS_UM_SHIFT
+#define PS_PROG_MASK PS_UM_MASK
+#define PS_PROG PS_UM
+
+/* DBREAKCn register fields: */
+#define DBREAKC_MASK_SHIFT 0
+#define DBREAKC_MASK_MASK 0x0000003F
+#define DBREAKC_LOADBREAK_SHIFT 30
+#define DBREAKC_LOADBREAK_MASK 0x40000000
+#define DBREAKC_STOREBREAK_SHIFT 31
+#define DBREAKC_STOREBREAK_MASK 0x80000000
+
+/* DEBUGCAUSE register fields: */
+#define DEBUGCAUSE_DEBUGINT_SHIFT 5
+#define DEBUGCAUSE_DEBUGINT_MASK 0x20 /* debug interrupt */
+#define DEBUGCAUSE_BREAKN_SHIFT 4
+#define DEBUGCAUSE_BREAKN_MASK 0x10 /* BREAK.N instruction */
+#define DEBUGCAUSE_BREAK_SHIFT 3
+#define DEBUGCAUSE_BREAK_MASK 0x08 /* BREAK instruction */
+#define DEBUGCAUSE_DBREAK_SHIFT 2
+#define DEBUGCAUSE_DBREAK_MASK 0x04 /* DBREAK match */
+#define DEBUGCAUSE_IBREAK_SHIFT 1
+#define DEBUGCAUSE_IBREAK_MASK 0x02 /* IBREAK match */
+#define DEBUGCAUSE_ICOUNT_SHIFT 0
+#define DEBUGCAUSE_ICOUNT_MASK 0x01 /* ICOUNT would increment to zero */
+
+#endif /*XTENSA_COREBITS_H*/
+
diff --git a/include/asm-xtensa/xtensa/hal.h b/include/asm-xtensa/xtensa/hal.h
new file mode 100644
index 000000000000..d10472505454
--- /dev/null
+++ b/include/asm-xtensa/xtensa/hal.h
@@ -0,0 +1,822 @@
+#ifndef XTENSA_HAL_H
+#define XTENSA_HAL_H
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/hal.h -- contains a definition of the
+ * Core HAL interface.
+ *
+ * All definitions in this header file are independent of any specific
+ * Xtensa processor configuration. Thus an OS or other software can
+ * include this header file and be compiled into configuration-
+ * independent objects that can be distributed and eventually linked
+ * to the HAL library (libhal.a) to create a configuration-specific
+ * final executable.
+ *
+ * Certain definitions, however, are release-specific -- such as the
+ * XTHAL_RELEASE_xxx macros (or additions made in later releases).
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+/*----------------------------------------------------------------------
+ Constant Definitions
+ (shared with assembly)
+ ----------------------------------------------------------------------*/
+
+/* Software release information (not configuration-specific!): */
+#define XTHAL_RELEASE_MAJOR 1050
+#define XTHAL_RELEASE_MINOR 0
+#define XTHAL_RELEASE_NAME "T1050.0-2002-08-06-eng0"
+#define XTHAL_RELEASE_INTERNAL "2002-08-06-eng0"
+#define XTHAL_REL_T1050 1
+#define XTHAL_REL_T1050_0 1
+#define XTHAL_REL_T1050_0_2002 1
+#define XTHAL_REL_T1050_0_2002_08 1
+#define XTHAL_REL_T1050_0_2002_08_06 1
+#define XTHAL_REL_T1050_0_2002_08_06_ENG0 1
+
+/* HAL version numbers (these names are for backward compatibility): */
+#define XTHAL_MAJOR_REV XTHAL_RELEASE_MAJOR
+#define XTHAL_MINOR_REV XTHAL_RELEASE_MINOR
+/*
+ * A bit of software release history on values of XTHAL_{MAJOR,MINOR}_REV:
+ *
+ * Release MAJOR MINOR Comment
+ * ======= ===== ===== =======
+ * T1015.n n/a n/a (HAL not yet available)
+ * T1020.{0,1,2} 0 1 (HAL beta)
+ * T1020.{3,4} 0 2 First release.
+ * T1020.n (n>4) 0 2 or >3 (TBD)
+ * T1030.0 0 1 (HAL beta)
+ * T1030.{1,2} 0 3 Equivalent to first release.
+ * T1030.n (n>=3) 0 >= 3 (TBD)
+ * T1040.n 1040 n Full CHAL available from T1040.2
+ * T1050.n 1050 n Current release.
+ *
+ *
+ * Note: there is a distinction between the software release with
+ * which something is compiled (accessible using XTHAL_RELEASE_* macros)
+ * and the software release with which the HAL library was compiled
+ * (accessible using Xthal_release_* global variables). This
+ * distinction is particularly relevant for vendors that distribute
+ * configuration-independent binaries (eg. an OS), where their customer
+ * might link it with a HAL of a different Xtensa software release.
+ * In this case, it may be appropriate for the OS to verify at run-time
+ * whether XTHAL_RELEASE_* and Xthal_release_* are compatible.
+ * [Guidelines as to which release is compatible with which are not
+ * currently provided explicitly, but might be inferred from reading
+ * OSKit documentation for all releases -- compatibility is also highly
+ * dependent on which HAL features are used. Each release is usually
+ * backward compatible, with very few exceptions if any.]
+ *
+ * Notes:
+ * Tornado 2.0 supported in T1020.3+, T1030.1+, and T1040.{0,1} only.
+ * Tornado 2.0.2 supported in T1040.2+, and T1050.
+ * Compile-time HAL port of NucleusPlus supported by T1040.2+ and T1050.
+ */
+
+
+/*
+ * Architectural limits, independent of configuration.
+ * Note that these are ISA-defined limits, not micro-architecture implementation
+ * limits enforced by the Xtensa Processor Generator (which may be stricter than
+ * these below).
+ */
+#define XTHAL_MAX_CPS 8 /* max number of coprocessors (0..7) */
+#define XTHAL_MAX_INTERRUPTS 32 /* max number of interrupts (0..31) */
+#define XTHAL_MAX_INTLEVELS 16 /* max number of interrupt levels (0..15) */
+ /* (as of T1040, implementation limit is 7: 0..6) */
+#define XTHAL_MAX_TIMERS 4 /* max number of timers (CCOMPARE0..CCOMPARE3) */
+ /* (as of T1040, implementation limit is 3: 0..2) */
+
+/* Misc: */
+#define XTHAL_LITTLEENDIAN 0
+#define XTHAL_BIGENDIAN 1
+
+
+/* Interrupt types: */
+#define XTHAL_INTTYPE_UNCONFIGURED 0
+#define XTHAL_INTTYPE_SOFTWARE 1
+#define XTHAL_INTTYPE_EXTERN_EDGE 2
+#define XTHAL_INTTYPE_EXTERN_LEVEL 3
+#define XTHAL_INTTYPE_TIMER 4
+#define XTHAL_INTTYPE_NMI 5
+#define XTHAL_MAX_INTTYPES 6 /* number of interrupt types */
+
+/* Timer related: */
+#define XTHAL_TIMER_UNCONFIGURED -1 /* Xthal_timer_interrupt[] value for non-existent timers */
+#define XTHAL_TIMER_UNASSIGNED XTHAL_TIMER_UNCONFIGURED /* (for backwards compatibility only) */
+
+
+/* Access Mode bits (tentative): */ /* bit abbr unit short_name PPC equ - Description */
+#define XTHAL_AMB_EXCEPTION 0 /* 001 E EX fls: EXception none - generate exception on any access (aka "illegal") */
+#define XTHAL_AMB_HITCACHE 1 /* 002 C CH fls: use Cache on Hit ~(I CI) - use cache on hit -- way from tag match [or H HC, or U UC] (ISA: same, except for Isolate case) */
+#define XTHAL_AMB_ALLOCATE 2 /* 004 A AL fl?: ALlocate none - refill cache on miss -- way from LRU [or F FI fill] (ISA: Read/Write Miss Refill) */
+#define XTHAL_AMB_WRITETHRU 3 /* 008 W WT --s: WriteThrough W WT - store immediately to memory (ISA: same) */
+#define XTHAL_AMB_ISOLATE 4 /* 010 I IS fls: ISolate none - use cache regardless of hit-vs-miss -- way from vaddr (ISA: use-cache-on-miss+hit) */
+#define XTHAL_AMB_GUARD 5 /* 020 G GU ?l?: GUard G * - non-speculative; spec/replay refs not permitted */
+#if 0
+#define XTHAL_AMB_ORDERED x /* 000 O OR fls: ORdered G * - mem accesses cannot be out of order */
+#define XTHAL_AMB_FUSEWRITES x /* 000 F FW --s: FuseWrites none - allow combining/merging multiple writes (to same datapath data unit) into one (implied by writeback) */
+#define XTHAL_AMB_COHERENT x /* 000 M MC fl?: Mem/MP Coherent M - on reads, other CPUs/bus-masters may need to supply data */
+#define XTHAL_AMB_TRUSTED x /* 000 T TR ?l?: TRusted none - memory will not bus error (if it does, handle as fatal imprecise interrupt) */
+#define XTHAL_AMB_PREFETCH x /* 000 P PR fl?: PRefetch none - on refill, read line+1 into prefetch buffers */
+#define XTHAL_AMB_STREAM x /* 000 S ST ???: STreaming none - access one of N stream buffers */
+#endif /*0*/
+
+#define XTHAL_AM_EXCEPTION (1<<XTHAL_AMB_EXCEPTION)
+#define XTHAL_AM_HITCACHE (1<<XTHAL_AMB_HITCACHE)
+#define XTHAL_AM_ALLOCATE (1<<XTHAL_AMB_ALLOCATE)
+#define XTHAL_AM_WRITETHRU (1<<XTHAL_AMB_WRITETHRU)
+#define XTHAL_AM_ISOLATE (1<<XTHAL_AMB_ISOLATE)
+#define XTHAL_AM_GUARD (1<<XTHAL_AMB_GUARD)
+#if 0
+#define XTHAL_AM_ORDERED (1<<XTHAL_AMB_ORDERED)
+#define XTHAL_AM_FUSEWRITES (1<<XTHAL_AMB_FUSEWRITES)
+#define XTHAL_AM_COHERENT (1<<XTHAL_AMB_COHERENT)
+#define XTHAL_AM_TRUSTED (1<<XTHAL_AMB_TRUSTED)
+#define XTHAL_AM_PREFETCH (1<<XTHAL_AMB_PREFETCH)
+#define XTHAL_AM_STREAM (1<<XTHAL_AMB_STREAM)
+#endif /*0*/
+
+/*
+ * Allowed Access Modes (bit combinations).
+ *
+ * Columns are:
+ * "FOGIWACE"
+ * Access mode bits (see XTHAL_AMB_xxx above).
+ * <letter> = bit is set
+ * '-' = bit is clear
+ * '.' = bit is irrelevant / don't care, as follows:
+ * E=1 makes all others irrelevant
+ * W,F relevant only for stores
+ * "2345"
+ * Indicates which Xtensa releases support the corresponding
+ * access mode. Releases for each character column are:
+ * 2 = prior to T1020.2: T1015 (V1.5), T1020.0, T1020.1
+ * 3 = T1020.2 and later: T1020.2+, T1030
+ * 4 = T1040
+ * 5 = T1050 (maybe)
+ * And the character column contents are:
+ * <number> = support by release(s)
+ * "." = unsupported by release(s)
+ * "?" = support unknown
+ */
+ /* FOGIWACE 2345 */
+/* For instruction fetch: */
+#define XTHAL_FAM_EXCEPTION 0x001 /* .......E 2345 exception */
+#define XTHAL_FAM_ISOLATE 0x012 /* .--I.-C- .... isolate */
+#define XTHAL_FAM_BYPASS 0x000 /* .---.--- 2345 bypass */
+#define XTHAL_FAM_NACACHED 0x002 /* .---.-C- .... cached no-allocate (frozen) */
+#define XTHAL_FAM_CACHED 0x006 /* .---.AC- 2345 cached */
+/* For data load: */
+#define XTHAL_LAM_EXCEPTION 0x001 /* .......E 2345 exception */
+#define XTHAL_LAM_ISOLATE 0x012 /* .--I.-C- 2345 isolate */
+#define XTHAL_LAM_BYPASS 0x000 /* .O--.--- 2... bypass speculative */
+#define XTHAL_LAM_BYPASSG 0x020 /* .OG-.--- .345 bypass guarded */
+#define XTHAL_LAM_NACACHED 0x002 /* .O--.-C- 2... cached no-allocate speculative */
+#define XTHAL_LAM_NACACHEDG 0x022 /* .OG-.-C- .345 cached no-allocate guarded */
+#define XTHAL_LAM_CACHED 0x006 /* .---.AC- 2345 cached speculative */
+#define XTHAL_LAM_CACHEDG 0x026 /* .?G-.AC- .... cached guarded */
+/* For data store: */
+#define XTHAL_SAM_EXCEPTION 0x001 /* .......E 2345 exception */
+#define XTHAL_SAM_ISOLATE 0x032 /* .-GI--C- 2345 isolate */
+#define XTHAL_SAM_BYPASS 0x028 /* -OG-W--- 2345 bypass */
+/*efine XTHAL_SAM_BYPASSF 0x028*/ /* F-G-W--- ...? bypass write-combined */
+#define XTHAL_SAM_WRITETHRU 0x02A /* -OG-W-C- 234? writethrough */
+/*efine XTHAL_SAM_WRITETHRUF 0x02A*/ /* F-G-W-C- ...5 writethrough write-combined */
+#define XTHAL_SAM_WRITEALLOC 0x02E /* -OG-WAC- ...? writethrough-allocate */
+/*efine XTHAL_SAM_WRITEALLOCF 0x02E*/ /* F-G-WAC- ...? writethrough-allocate write-combined */
+#define XTHAL_SAM_WRITEBACK 0x026 /* F-G--AC- ...5 writeback */
+
+#if 0
+/*
+ Cache attribute encoding for CACHEATTR (per ISA):
+ (Note: if this differs from ISA Ref Manual, ISA has precedence)
+
+ Inst-fetches Loads Stores
+ ------------- ------------ -------------
+0x0 FCA_EXCEPTION ?LCA_NACACHED_G* SCA_WRITETHRU "uncached"
+0x1 FCA_CACHED LCA_CACHED SCA_WRITETHRU cached
+0x2 FCA_BYPASS LCA_BYPASS_G* SCA_BYPASS bypass
+0x3 FCA_CACHED LCA_CACHED SCA_WRITEALLOCF write-allocate
+ or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented)
+0x4 FCA_CACHED LCA_CACHED SCA_WRITEBACK write-back
+ or LCA_EXCEPTION SCA_EXCEPTION (if unimplemented)
+0x5..D FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION (reserved)
+0xE FCA_EXCEPTION LCA_ISOLATE SCA_ISOLATE isolate
+0xF FCA_EXCEPTION LCA_EXCEPTION SCA_EXCEPTION illegal
+ * Prior to T1020.2?, guard feature not supported, this defaulted to speculative (no _G)
+*/
+#endif /*0*/
+
+
+#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*----------------------------------------------------------------------
+ HAL
+ ----------------------------------------------------------------------*/
+
+/* Constant to be checked in build = (XTHAL_MAJOR_REV<<16)|XTHAL_MINOR_REV */
+extern const unsigned int Xthal_rev_no;
+
+
+/*----------------------------------------------------------------------
+ Processor State
+ ----------------------------------------------------------------------*/
+/* save & restore the extra processor state */
+extern void xthal_save_extra(void *base);
+extern void xthal_restore_extra(void *base);
+
+extern void xthal_save_cpregs(void *base, int);
+extern void xthal_restore_cpregs(void *base, int);
+
+/*extern void xthal_save_all_extra(void *base);*/
+/*extern void xthal_restore_all_extra(void *base);*/
+
+/* space for processor state */
+extern const unsigned int Xthal_extra_size;
+extern const unsigned int Xthal_extra_align;
+/* space for TIE register files */
+extern const unsigned int Xthal_cpregs_size[XTHAL_MAX_CPS];
+extern const unsigned int Xthal_cpregs_align[XTHAL_MAX_CPS];
+
+/* total of space for the processor state (for Tor2) */
+extern const unsigned int Xthal_all_extra_size;
+extern const unsigned int Xthal_all_extra_align;
+
+/* initialize the extra processor */
+/*extern void xthal_init_extra(void);*/
+/* initialize the TIE coprocessor */
+/*extern void xthal_init_cp(int);*/
+
+/* initialize the extra processor */
+extern void xthal_init_mem_extra(void *);
+/* initialize the TIE coprocessor */
+extern void xthal_init_mem_cp(void *, int);
+
+/* validate & invalidate the TIE register file */
+extern void xthal_validate_cp(int);
+extern void xthal_invalidate_cp(int);
+
+/* the number of TIE coprocessors contiguous from zero (for Tor2) */
+extern const unsigned int Xthal_num_coprocessors;
+
+/* actual number of coprocessors */
+extern const unsigned char Xthal_cp_num;
+/* index of highest numbered coprocessor, plus one */
+extern const unsigned char Xthal_cp_max;
+/* index of highest allowed coprocessor number, per cfg, plus one */
+/*extern const unsigned char Xthal_cp_maxcfg;*/
+/* bitmask of which coprocessors are present */
+extern const unsigned int Xthal_cp_mask;
+
+/* read and write cpenable register */
+extern void xthal_set_cpenable(unsigned);
+extern unsigned xthal_get_cpenable(void);
+
+/* read & write extra state register */
+/*extern int xthal_read_extra(void *base, unsigned reg, unsigned *value);*/
+/*extern int xthal_write_extra(void *base, unsigned reg, unsigned value);*/
+
+/* read & write a TIE coprocessor register */
+/*extern int xthal_read_cpreg(void *base, int cp, unsigned reg, unsigned *value);*/
+/*extern int xthal_write_cpreg(void *base, int cp, unsigned reg, unsigned value);*/
+
+/* return coprocessor number based on register */
+/*extern int xthal_which_cp(unsigned reg);*/
+
+/*----------------------------------------------------------------------
+ Interrupts
+ ----------------------------------------------------------------------*/
+
+/* the number of interrupt levels */
+extern const unsigned char Xthal_num_intlevels;
+/* the number of interrupts */
+extern const unsigned char Xthal_num_interrupts;
+
+/* mask for level of interrupts */
+extern const unsigned int Xthal_intlevel_mask[XTHAL_MAX_INTLEVELS];
+/* mask for level 0 to N interrupts */
+extern const unsigned int Xthal_intlevel_andbelow_mask[XTHAL_MAX_INTLEVELS];
+
+/* level of each interrupt */
+extern const unsigned char Xthal_intlevel[XTHAL_MAX_INTERRUPTS];
+
+/* type per interrupt */
+extern const unsigned char Xthal_inttype[XTHAL_MAX_INTERRUPTS];
+
+/* masks of each type of interrupt */
+extern const unsigned int Xthal_inttype_mask[XTHAL_MAX_INTTYPES];
+
+/* interrupt numbers assigned to each timer interrupt */
+extern const int Xthal_timer_interrupt[XTHAL_MAX_TIMERS];
+
+/*** Virtual interrupt prioritization: ***/
+
+/* Convert between interrupt levels (as per PS.INTLEVEL) and virtual interrupt priorities: */
+extern unsigned xthal_vpri_to_intlevel(unsigned vpri);
+extern unsigned xthal_intlevel_to_vpri(unsigned intlevel);
+
+/* Enables/disables given set (mask) of interrupts; returns previous enabled-mask of all ints: */
+extern unsigned xthal_int_enable(unsigned);
+extern unsigned xthal_int_disable(unsigned);
+
+/* Set/get virtual priority of an interrupt: */
+extern int xthal_set_int_vpri(int intnum, int vpri);
+extern int xthal_get_int_vpri(int intnum);
+
+/* Set/get interrupt lockout level for exclusive access to virtual priority data structures: */
+extern void xthal_set_vpri_locklevel(unsigned intlevel);
+extern unsigned xthal_get_vpri_locklevel(void);
+
+/* Set/get current virtual interrupt priority: */
+extern unsigned xthal_set_vpri(unsigned vpri);
+extern unsigned xthal_get_vpri(unsigned vpri);
+extern unsigned xthal_set_vpri_intlevel(unsigned intlevel);
+extern unsigned xthal_set_vpri_lock(void);
+
+
+
+/*----------------------------------------------------------------------
+ Generic Interrupt Trampolining Support
+ ----------------------------------------------------------------------*/
+
+typedef void (XtHalVoidFunc)(void);
+
+/*
+ * Bitmask of interrupts currently trampolining down:
+ */
+extern unsigned Xthal_tram_pending;
+
+/*
+ * Bitmask of which interrupts currently trampolining down
+ * synchronously are actually enabled; this bitmask is necessary
+ * because INTENABLE cannot hold that state (sync-trampolining
+ * interrupts must be kept disabled while trampolining);
+ * in the current implementation, any bit set here is not set
+ * in INTENABLE, and vice-versa; once a sync-trampoline is
+ * handled (at level one), its enable bit must be moved from
+ * here to INTENABLE:
+ */
+extern unsigned Xthal_tram_enabled;
+
+/*
+ * Bitmask of interrupts configured for sync trampolining:
+ */
+extern unsigned Xthal_tram_sync;
+
+
+/* Trampoline support functions: */
+extern unsigned xthal_tram_pending_to_service( void );
+extern void xthal_tram_done( unsigned serviced_mask );
+extern int xthal_tram_set_sync( int intnum, int sync );
+extern XtHalVoidFunc* xthal_set_tram_trigger_func( XtHalVoidFunc *trigger_fn );
+
+/* INTENABLE,INTREAD,INTSET,INTCLEAR register access functions: */
+extern unsigned xthal_get_intenable( void );
+extern void xthal_set_intenable( unsigned );
+extern unsigned xthal_get_intread( void );
+extern void xthal_set_intset( unsigned );
+extern void xthal_set_intclear( unsigned );
+
+
+/*----------------------------------------------------------------------
+ Register Windows
+ ----------------------------------------------------------------------*/
+
+/* number of registers in register window */
+extern const unsigned int Xthal_num_aregs;
+extern const unsigned char Xthal_num_aregs_log2;
+
+/* This spill any live register windows (other than the caller's): */
+extern void xthal_window_spill( void );
+
+
+/*----------------------------------------------------------------------
+ Cache
+ ----------------------------------------------------------------------*/
+
+/* size of the cache lines in log2(bytes) */
+extern const unsigned char Xthal_icache_linewidth;
+extern const unsigned char Xthal_dcache_linewidth;
+/* size of the cache lines in bytes */
+extern const unsigned short Xthal_icache_linesize;
+extern const unsigned short Xthal_dcache_linesize;
+/* number of cache sets in log2(lines per way) */
+extern const unsigned char Xthal_icache_setwidth;
+extern const unsigned char Xthal_dcache_setwidth;
+/* cache set associativity (number of ways) */
+extern const unsigned int Xthal_icache_ways;
+extern const unsigned int Xthal_dcache_ways;
+/* size of the caches in bytes (ways * 2^(linewidth + setwidth)) */
+extern const unsigned int Xthal_icache_size;
+extern const unsigned int Xthal_dcache_size;
+/* cache features */
+extern const unsigned char Xthal_dcache_is_writeback;
+extern const unsigned char Xthal_icache_line_lockable;
+extern const unsigned char Xthal_dcache_line_lockable;
+
+/* cache attribute register control (used by other HAL routines) */
+extern unsigned xthal_get_cacheattr( void );
+extern unsigned xthal_get_icacheattr( void );
+extern unsigned xthal_get_dcacheattr( void );
+extern void xthal_set_cacheattr( unsigned );
+extern void xthal_set_icacheattr( unsigned );
+extern void xthal_set_dcacheattr( unsigned );
+
+/* initialize cache support (must be called once at startup, before all other cache calls) */
+/*extern void xthal_cache_startinit( void );*/
+/* reset caches */
+/*extern void xthal_icache_reset( void );*/
+/*extern void xthal_dcache_reset( void );*/
+/* enable caches */
+extern void xthal_icache_enable( void ); /* DEPRECATED */
+extern void xthal_dcache_enable( void ); /* DEPRECATED */
+/* disable caches */
+extern void xthal_icache_disable( void ); /* DEPRECATED */
+extern void xthal_dcache_disable( void ); /* DEPRECATED */
+
+/* invalidate the caches */
+extern void xthal_icache_all_invalidate( void );
+extern void xthal_dcache_all_invalidate( void );
+extern void xthal_icache_region_invalidate( void *addr, unsigned size );
+extern void xthal_dcache_region_invalidate( void *addr, unsigned size );
+extern void xthal_icache_line_invalidate(void *addr);
+extern void xthal_dcache_line_invalidate(void *addr);
+/* write dirty data back */
+extern void xthal_dcache_all_writeback( void );
+extern void xthal_dcache_region_writeback( void *addr, unsigned size );
+extern void xthal_dcache_line_writeback(void *addr);
+/* write dirty data back and invalidate */
+extern void xthal_dcache_all_writeback_inv( void );
+extern void xthal_dcache_region_writeback_inv( void *addr, unsigned size );
+extern void xthal_dcache_line_writeback_inv(void *addr);
+/* prefetch and lock specified memory range into cache */
+extern void xthal_icache_region_lock( void *addr, unsigned size );
+extern void xthal_dcache_region_lock( void *addr, unsigned size );
+extern void xthal_icache_line_lock(void *addr);
+extern void xthal_dcache_line_lock(void *addr);
+/* unlock from cache */
+extern void xthal_icache_all_unlock( void );
+extern void xthal_dcache_all_unlock( void );
+extern void xthal_icache_region_unlock( void *addr, unsigned size );
+extern void xthal_dcache_region_unlock( void *addr, unsigned size );
+extern void xthal_icache_line_unlock(void *addr);
+extern void xthal_dcache_line_unlock(void *addr);
+
+
+/* sync icache and memory */
+extern void xthal_icache_sync( void );
+/* sync dcache and memory */
+extern void xthal_dcache_sync( void );
+
+/*----------------------------------------------------------------------
+ Debug
+ ----------------------------------------------------------------------*/
+
+/* 1 if debug option configured, 0 if not: */
+extern const int Xthal_debug_configured;
+
+/* Number of instruction and data break registers: */
+extern const int Xthal_num_ibreak;
+extern const int Xthal_num_dbreak;
+
+/* Set (plant) and remove software breakpoint, both synchronizing cache: */
+extern unsigned int xthal_set_soft_break(void *addr);
+extern void xthal_remove_soft_break(void *addr, unsigned int);
+
+
+/*----------------------------------------------------------------------
+ Disassembler
+ ----------------------------------------------------------------------*/
+
+/* Max expected size of the return buffer for a disassembled instruction (hint only): */
+#define XTHAL_DISASM_BUFSIZE 80
+
+/* Disassembly option bits for selecting what to return: */
+#define XTHAL_DISASM_OPT_ADDR 0x0001 /* display address */
+#define XTHAL_DISASM_OPT_OPHEX 0x0002 /* display opcode bytes in hex */
+#define XTHAL_DISASM_OPT_OPCODE 0x0004 /* display opcode name (mnemonic) */
+#define XTHAL_DISASM_OPT_PARMS 0x0008 /* display parameters */
+#define XTHAL_DISASM_OPT_ALL 0x0FFF /* display everything */
+
+/* routine to get a string for the disassembled instruction */
+extern int xthal_disassemble( unsigned char *instr_buf, void *tgt_addr,
+ char *buffer, unsigned buflen, unsigned options );
+
+/* routine to get the size of the next instruction. Returns 0 for
+ illegal instruction */
+extern int xthal_disassemble_size( unsigned char *instr_buf );
+
+
+/*----------------------------------------------------------------------
+ Core Counter
+ ----------------------------------------------------------------------*/
+
+/* counter info */
+extern const unsigned char Xthal_have_ccount; /* set if CCOUNT register present */
+extern const unsigned char Xthal_num_ccompare; /* number of CCOMPAREn registers */
+
+/* get CCOUNT register (if not present return 0) */
+extern unsigned xthal_get_ccount(void);
+
+/* set and get CCOMPAREn registers (if not present, get returns 0) */
+extern void xthal_set_ccompare(int, unsigned);
+extern unsigned xthal_get_ccompare(int);
+
+
+/*----------------------------------------------------------------------
+ Instruction/Data RAM/ROM Access
+ ----------------------------------------------------------------------*/
+
+extern void* xthal_memcpy(void *dst, const void *src, unsigned len);
+extern void* xthal_bcopy(const void *src, void *dst, unsigned len);
+
+/*----------------------------------------------------------------------
+ MP Synchronization
+ ----------------------------------------------------------------------*/
+extern int xthal_compare_and_set( int *addr, int test_val, int compare_val );
+extern unsigned xthal_get_prid( void );
+
+/*extern const char Xthal_have_s32c1i;*/
+extern const unsigned char Xthal_have_prid;
+
+
+/*----------------------------------------------------------------------
+ Miscellaneous
+ ----------------------------------------------------------------------*/
+
+extern const unsigned int Xthal_release_major;
+extern const unsigned int Xthal_release_minor;
+extern const char * const Xthal_release_name;
+extern const char * const Xthal_release_internal;
+
+extern const unsigned char Xthal_memory_order;
+extern const unsigned char Xthal_have_windowed;
+extern const unsigned char Xthal_have_density;
+extern const unsigned char Xthal_have_booleans;
+extern const unsigned char Xthal_have_loops;
+extern const unsigned char Xthal_have_nsa;
+extern const unsigned char Xthal_have_minmax;
+extern const unsigned char Xthal_have_sext;
+extern const unsigned char Xthal_have_clamps;
+extern const unsigned char Xthal_have_mac16;
+extern const unsigned char Xthal_have_mul16;
+extern const unsigned char Xthal_have_fp;
+extern const unsigned char Xthal_have_speculation;
+extern const unsigned char Xthal_have_exceptions;
+extern const unsigned char Xthal_xea_version;
+extern const unsigned char Xthal_have_interrupts;
+extern const unsigned char Xthal_have_highlevel_interrupts;
+extern const unsigned char Xthal_have_nmi;
+
+extern const unsigned short Xthal_num_writebuffer_entries;
+
+extern const unsigned int Xthal_build_unique_id;
+/* Release info for hardware targeted by software upgrades: */
+extern const unsigned int Xthal_hw_configid0;
+extern const unsigned int Xthal_hw_configid1;
+extern const unsigned int Xthal_hw_release_major;
+extern const unsigned int Xthal_hw_release_minor;
+extern const char * const Xthal_hw_release_name;
+extern const char * const Xthal_hw_release_internal;
+
+
+/* Internal memories... */
+
+extern const unsigned char Xthal_num_instrom;
+extern const unsigned char Xthal_num_instram;
+extern const unsigned char Xthal_num_datarom;
+extern const unsigned char Xthal_num_dataram;
+extern const unsigned char Xthal_num_xlmi;
+extern const unsigned int Xthal_instrom_vaddr[1];
+extern const unsigned int Xthal_instrom_paddr[1];
+extern const unsigned int Xthal_instrom_size [1];
+extern const unsigned int Xthal_instram_vaddr[1];
+extern const unsigned int Xthal_instram_paddr[1];
+extern const unsigned int Xthal_instram_size [1];
+extern const unsigned int Xthal_datarom_vaddr[1];
+extern const unsigned int Xthal_datarom_paddr[1];
+extern const unsigned int Xthal_datarom_size [1];
+extern const unsigned int Xthal_dataram_vaddr[1];
+extern const unsigned int Xthal_dataram_paddr[1];
+extern const unsigned int Xthal_dataram_size [1];
+extern const unsigned int Xthal_xlmi_vaddr[1];
+extern const unsigned int Xthal_xlmi_paddr[1];
+extern const unsigned int Xthal_xlmi_size [1];
+
+
+
+/*----------------------------------------------------------------------
+ Memory Management Unit
+ ----------------------------------------------------------------------*/
+
+extern const unsigned char Xthal_have_spanning_way;
+extern const unsigned char Xthal_have_identity_map;
+extern const unsigned char Xthal_have_mimic_cacheattr;
+extern const unsigned char Xthal_have_xlt_cacheattr;
+extern const unsigned char Xthal_have_cacheattr;
+extern const unsigned char Xthal_have_tlbs;
+
+extern const unsigned char Xthal_mmu_asid_bits; /* 0 .. 8 */
+extern const unsigned char Xthal_mmu_asid_kernel;
+extern const unsigned char Xthal_mmu_rings; /* 1 .. 4 (perhaps 0 if no MMU and/or no protection?) */
+extern const unsigned char Xthal_mmu_ring_bits;
+extern const unsigned char Xthal_mmu_sr_bits;
+extern const unsigned char Xthal_mmu_ca_bits;
+extern const unsigned int Xthal_mmu_max_pte_page_size;
+extern const unsigned int Xthal_mmu_min_pte_page_size;
+
+extern const unsigned char Xthal_itlb_way_bits;
+extern const unsigned char Xthal_itlb_ways;
+extern const unsigned char Xthal_itlb_arf_ways;
+extern const unsigned char Xthal_dtlb_way_bits;
+extern const unsigned char Xthal_dtlb_ways;
+extern const unsigned char Xthal_dtlb_arf_ways;
+
+/* Convert between virtual and physical addresses (through static maps only): */
+/*** WARNING: these two functions may go away in a future release; don't depend on them! ***/
+extern int xthal_static_v2p( unsigned vaddr, unsigned *paddrp );
+extern int xthal_static_p2v( unsigned paddr, unsigned *vaddrp, unsigned cached );
+
+#if 0
+/******************* EXPERIMENTAL AND TENTATIVE ONLY ********************/
+
+#define XTHAL_MMU_PAGESZ_COUNT_MAX 8 /* maximum number of different page sizes */
+extern const char Xthal_mmu_pagesz_count; /* 0 .. 8 number of different page sizes configured */
+
+/* Note: the following table doesn't necessarily have page sizes in increasing order: */
+extern const char Xthal_mmu_pagesz_log2[XTHAL_MMU_PAGESZ_COUNT_MAX]; /* 10 .. 28 (0 past count) */
+
+/* Sorted (increasing) table of page sizes, that indexes into the above table: */
+extern const char Xthal_mmu_pagesz_sorted[XTHAL_MMU_PAGESZ_COUNT_MAX]; /* 0 .. 7 (0 past count) */
+
+/*u32 Xthal_virtual_exceptions;*/ /* bitmask of which exceptions execute in virtual mode... */
+
+extern const char Xthal_mmu_pte_pagesz_log2_min; /* ?? minimum page size in PTEs */
+extern const char Xthal_mmu_pte_pagesz_log2_max; /* ?? maximum page size in PTEs */
+
+/* Cache Attribute Bits Implemented by the Cache (part of the cache abstraction) */
+extern const char Xthal_icache_fca_bits_implemented; /* ITLB/UTLB only! */
+extern const char Xthal_dcache_lca_bits_implemented; /* DTLB/UTLB only! */
+extern const char Xthal_dcache_sca_bits_implemented; /* DTLB/UTLB only! */
+
+/* Per TLB Parameters (Instruction, Data, Unified) */
+struct XtHalMmuTlb Xthal_itlb; /* description of MMU I-TLB generic features */
+struct XtHalMmuTlb Xthal_dtlb; /* description of MMU D-TLB generic features */
+struct XtHalMmuTlb Xthal_utlb; /* description of MMU U-TLB generic features */
+
+#define XTHAL_MMU_WAYS_MAX 8 /* maximum number of ways (associativities) for each TLB */
+
+/* Structure for common information described for each possible TLB (instruction, data and unified): */
+typedef struct XtHalMmuTlb {
+ u8 va_bits; /* 32 (number of virtual address bits) */
+ u8 pa_bits; /* 32 (number of physical address bits) */
+ bool tlb_va_indexed; /* 1 (set if TLB is indexed by virtual address) */
+ bool tlb_va_tagged; /* 0 (set if TLB is tagged by virtual address) */
+ bool cache_va_indexed; /* 1 (set if cache is indexed by virtual address) */
+ bool cache_va_tagged; /* 0 (set if cache is tagged by virtual address) */
+ /*bool (whether page tables are traversed in vaddr sorted order, paddr sorted order, ...) */
+ /*u8 (set of available page attribute bits, other than cache attribute bits defined above) */
+ /*u32 (various masks for pages, MMU table/TLB entries, etc.) */
+ u8 way_count; /* 0 .. 8 (number of ways, a.k.a. associativities, for this TLB) */
+ XtHalMmuTlbWay * ways[XTHAL_MMU_WAYS_MAX]; /* pointers to per-way parms for each way */
+} XtHalMmuTlb;
+
+/* Per TLB Way (Per Associativity) Parameters */
+typedef struct XtHalMmuTlbWay {
+ u32 index_count_log2; /* 0 .. 4 */
+ u32 pagesz_mask; /* 0 .. 2^pagesz_count - 1 (each bit corresponds to a size */
+ /* defined in the Xthal_mmu_pagesz_log2[] table) */
+ u32 vpn_const_mask;
+ u32 vpn_const_value;
+ u64 ppn_const_mask; /* future may support pa_bits > 32 */
+ u64 ppn_const_value;
+ u32 ppn_id_mask; /* paddr bits taken directly from vaddr */
+ bool backgnd_match; /* 0 or 1 */
+ /* These are defined in terms of the XTHAL_CACHE_xxx bits: */
+ u8 fca_const_mask; /* ITLB/UTLB only! */
+ u8 fca_const_value; /* ITLB/UTLB only! */
+ u8 lca_const_mask; /* DTLB/UTLB only! */
+ u8 lca_const_value; /* DTLB/UTLB only! */
+ u8 sca_const_mask; /* DTLB/UTLB only! */
+ u8 sca_const_value; /* DTLB/UTLB only! */
+ /* These define an encoding that map 5 bits in TLB and PTE entries to */
+ /* 8 bits (FCA, ITLB), 16 bits (LCA+SCA, DTLB) or 24 bits (FCA+LCA+SCA, UTLB): */
+ /* (they may be moved to struct XtHalMmuTlb) */
+ u8 ca_bits; /* number of bits in TLB/PTE entries for cache attributes */
+ u32 * ca_map; /* pointer to array of 2^ca_bits entries of FCA+LCA+SCA bits */
+} XtHalMmuTlbWay;
+
+/*
+ * The way to determine whether protection support is present in core
+ * is to [look at Xthal_mmu_rings ???].
+ * Give info on memory requirements for MMU tables and other in-memory
+ * data structures (globally, per task, base and per page, etc.) - whatever bounds can be calculated.
+ */
+
+
+/* Default vectors: */
+xthal_immu_fetch_miss_vector
+xthal_dmmu_load_miss_vector
+xthal_dmmu_store_miss_vector
+
+/* Functions called when a fault is detected: */
+typedef void (XtHalMmuFaultFunc)( unsigned vaddr, ...context... );
+/* Or, */
+/* a? = vaddr */
+/* a? = context... */
+/* PS.xxx = xxx */
+XtHalMMuFaultFunc *Xthal_immu_fetch_fault_func;
+XtHalMMuFaultFunc *Xthal_dmmu_load_fault_func;
+XtHalMMuFaultFunc *Xthal_dmmu_store_fault_func;
+
+/* Default Handlers: */
+/* The user and/or kernel exception handlers may jump to these handlers to handle the relevant exceptions,
+ * according to the value of EXCCAUSE. The exact register state on entry to these handlers is TBD. */
+/* When multiple TLB entries match (hit) on the same access: */
+xthal_immu_fetch_multihit_handler
+xthal_dmmu_load_multihit_handler
+xthal_dmmu_store_multihit_handler
+/* Protection violations according to cache attributes, and other cache attribute mismatches: */
+xthal_immu_fetch_attr_handler
+xthal_dmmu_load_attr_handler
+xthal_dmmu_store_attr_handler
+/* Protection violations due to insufficient ring level: */
+xthal_immu_fetch_priv_handler
+xthal_dmmu_load_priv_handler
+xthal_dmmu_store_priv_handler
+/* Alignment exception handlers (if supported by the particular Xtensa MMU configuration): */
+xthal_dmmu_load_align_handler
+xthal_dmmu_store_align_handler
+
+/* Or, alternatively, the OS user and/or kernel exception handlers may simply jump to the
+ * following entry points which will handle any values of EXCCAUSE not handled by the OS: */
+xthal_user_exc_default_handler
+xthal_kernel_exc_default_handler
+
+#endif /*0*/
+
+#ifdef INCLUDE_DEPRECATED_HAL_CODE
+extern const unsigned char Xthal_have_old_exc_arch;
+extern const unsigned char Xthal_have_mmu;
+extern const unsigned int Xthal_num_regs;
+extern const unsigned char Xthal_num_iroms;
+extern const unsigned char Xthal_num_irams;
+extern const unsigned char Xthal_num_droms;
+extern const unsigned char Xthal_num_drams;
+extern const unsigned int Xthal_configid0;
+extern const unsigned int Xthal_configid1;
+#endif
+
+#ifdef INCLUDE_DEPRECATED_HAL_DEBUG_CODE
+#define XTHAL_24_BIT_BREAK 0x80000000
+#define XTHAL_16_BIT_BREAK 0x40000000
+extern const unsigned short Xthal_ill_inst_16[16];
+#define XTHAL_DEST_REG 0xf0000000 /* Mask for destination register */
+#define XTHAL_DEST_REG_INST 0x08000000 /* Branch address is in register */
+#define XTHAL_DEST_REL_INST 0x04000000 /* Branch address is relative */
+#define XTHAL_RFW_INST 0x00000800
+#define XTHAL_RFUE_INST 0x00000400
+#define XTHAL_RFI_INST 0x00000200
+#define XTHAL_RFE_INST 0x00000100
+#define XTHAL_RET_INST 0x00000080
+#define XTHAL_BREAK_INST 0x00000040
+#define XTHAL_SYSCALL_INST 0x00000020
+#define XTHAL_LOOP_END 0x00000010 /* Not set by xthal_inst_type */
+#define XTHAL_JUMP_INST 0x00000008 /* Call or jump instruction */
+#define XTHAL_BRANCH_INST 0x00000004 /* Branch instruction */
+#define XTHAL_24_BIT_INST 0x00000002
+#define XTHAL_16_BIT_INST 0x00000001
+typedef struct xthal_state {
+ unsigned pc;
+ unsigned ar[16];
+ unsigned lbeg;
+ unsigned lend;
+ unsigned lcount;
+ unsigned extra_ptr;
+ unsigned cpregs_ptr[XTHAL_MAX_CPS];
+} XTHAL_STATE;
+extern unsigned int xthal_inst_type(void *addr);
+extern unsigned int xthal_branch_addr(void *addr);
+extern unsigned int xthal_get_npc(XTHAL_STATE *user_state);
+#endif /* INCLUDE_DEPRECATED_HAL_DEBUG_CODE */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*!__ASSEMBLY__ */
+
+#endif /*XTENSA_HAL_H*/
+
diff --git a/include/asm-xtensa/xtensa/simcall.h b/include/asm-xtensa/xtensa/simcall.h
new file mode 100644
index 000000000000..a2b868929a49
--- /dev/null
+++ b/include/asm-xtensa/xtensa/simcall.h
@@ -0,0 +1,130 @@
+#ifndef SIMCALL_INCLUDED
+#define SIMCALL_INCLUDED
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/simcall.h - Simulator call numbers
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+/*
+ * System call like services offered by the simulator host.
+ * These are modeled after the Linux 2.4 kernel system calls
+ * for Xtensa processors. However not all system calls and
+ * not all functionality of a given system call are implemented,
+ * or necessarily have well defined or equivalent semantics in
+ * the context of a simulation (as opposed to a Unix kernel).
+ *
+ * These services behave largely as if they had been invoked
+ * as a task in the simulator host's operating system
+ * (eg. files accessed are those of the simulator host).
+ * However, these SIMCALLs model a virtual operating system
+ * so that various definitions, bit assignments etc
+ * (eg. open mode bits, errno values, etc) are independent
+ * of the host operating system used to run the simulation.
+ * Rather these definitions are specific to the Xtensa ISS.
+ * This way Xtensa ISA code written to use these SIMCALLs
+ * can (in principle) be simulated on any host.
+ *
+ * Up to 6 parameters are passed in registers a3 to a8
+ * (note the 6th parameter isn't passed on the stack,
+ * unlike windowed function calling conventions).
+ * The return value is in a2. A negative value in the
+ * range -4096 to -1 indicates a negated error code to be
+ * reported in errno with a return value of -1, otherwise
+ * the value in a2 is returned as is.
+ */
+
+/* These #defines need to match what's in Xtensa/OS/vxworks/xtiss/simcalls.c */
+
+#define SYS_nop 0 /* n/a - setup; used to flush register windows */
+#define SYS_exit 1 /*x*/
+#define SYS_fork 2
+#define SYS_read 3 /*x*/
+#define SYS_write 4 /*x*/
+#define SYS_open 5 /*x*/
+#define SYS_close 6 /*x*/
+#define SYS_rename 7 /*x 38 - waitpid */
+#define SYS_creat 8 /*x*/
+#define SYS_link 9 /*x (not implemented on WIN32) */
+#define SYS_unlink 10 /*x*/
+#define SYS_execv 11 /* n/a - execve */
+#define SYS_execve 12 /* 11 - chdir */
+#define SYS_pipe 13 /* 42 - time */
+#define SYS_stat 14 /* 106 - mknod */
+#define SYS_chmod 15
+#define SYS_chown 16 /* 202 - lchown */
+#define SYS_utime 17 /* 30 - break */
+#define SYS_wait 18 /* n/a - oldstat */
+#define SYS_lseek 19 /*x*/
+#define SYS_getpid 20
+#define SYS_isatty 21 /* n/a - mount */
+#define SYS_fstat 22 /* 108 - oldumount */
+#define SYS_time 23 /* 13 - setuid */
+#define SYS_gettimeofday 24 /*x 78 - getuid (not implemented on WIN32) */
+#define SYS_times 25 /*X 43 - stime (Xtensa-specific implementation) */
+#define SYS_socket 26
+#define SYS_sendto 27
+#define SYS_recvfrom 28
+#define SYS_select_one 29 /* not compitible select, one file descriptor at the time */
+#define SYS_bind 30
+#define SYS_ioctl 31
+
+/*
+ * Other...
+ */
+#define SYS_iss_argc 1000 /* returns value of argc */
+#define SYS_iss_argv_size 1001 /* bytes needed for argv & arg strings */
+#define SYS_iss_set_argv 1002 /* saves argv & arg strings at given addr */
+
+/*
+ * SIMCALLs for the ferret memory debugger. All are invoked by
+ * libferret.a ... ( Xtensa/Target-Libs/ferret )
+ */
+#define SYS_ferret 1010
+#define SYS_malloc 1011
+#define SYS_free 1012
+#define SYS_more_heap 1013
+#define SYS_no_heap 1014
+
+
+/*
+ * Extra SIMCALLs for GDB:
+ */
+#define SYS_gdb_break -1 /* invoked by XTOS on user exceptions if EPC points
+ to a break.n/break, regardless of cause! */
+#define SYS_xmon_out -2 /* invoked by XMON: ... */
+#define SYS_xmon_in -3 /* invoked by XMON: ... */
+#define SYS_xmon_flush -4 /* invoked by XMON: ... */
+#define SYS_gdb_abort -5 /* invoked by XTOS in _xtos_panic() */
+#define SYS_gdb_illegal_inst -6 /* invoked by XTOS for illegal instructions (too deeply) */
+#define SYS_xmon_init -7 /* invoked by XMON: ... */
+#define SYS_gdb_enter_sktloop -8 /* invoked by XTOS on debug exceptions */
+
+/*
+ * SIMCALLs for vxWorks xtiss BSP:
+ */
+#define SYS_setup_ppp_pipes -83
+#define SYS_log_msg -84
+
+/*
+ * Test SIMCALLs:
+ */
+#define SYS_test_write_state -100
+#define SYS_test_read_state -101
+
+/*
+ * SYS_select_one specifiers
+ */
+#define XTISS_SELECT_ONE_READ 1
+#define XTISS_SELECT_ONE_WRITE 2
+#define XTISS_SELECT_ONE_EXCEPT 3
+
+#endif /* !SIMCALL_INCLUDED */
diff --git a/include/asm-xtensa/xtensa/xt2000-uart.h b/include/asm-xtensa/xtensa/xt2000-uart.h
new file mode 100644
index 000000000000..0154460f0ed8
--- /dev/null
+++ b/include/asm-xtensa/xtensa/xt2000-uart.h
@@ -0,0 +1,155 @@
+#ifndef _uart_h_included_
+#define _uart_h_included_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/xt2000-uart.h -- NatSemi PC16552D DUART
+ * definitions
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/xt2000.h>
+
+
+/* 16550 UART DEVICE REGISTERS
+ The XT2000 board aligns each register to a 32-bit word but the UART device only uses
+ one byte of the word, which is the least-significant byte regardless of the
+ endianness of the core (ie. byte offset 0 for little-endian and 3 for big-endian).
+ So if using word accesses then endianness doesn't matter.
+ The macros provided here do that.
+*/
+struct uart_dev_s {
+ union {
+ unsigned int rxb; /* DLAB=0: receive buffer, read-only */
+ unsigned int txb; /* DLAB=0: transmit buffer, write-only */
+ unsigned int dll; /* DLAB=1: divisor, least-significant byte latch (was write-only?) */
+ } w0;
+ union {
+ unsigned int ier; /* DLAB=0: interrupt-enable register (was write-only?) */
+ unsigned int dlm; /* DLAB=1: divisor, most-significant byte latch (was write-only?) */
+ } w1;
+
+ union {
+ unsigned int isr; /* DLAB=0: interrupt status register, read-only */
+ unsigned int fcr; /* DLAB=0: FIFO control register, write-only */
+ unsigned int afr; /* DLAB=1: alternate function register */
+ } w2;
+
+ unsigned int lcr; /* line control-register, write-only */
+ unsigned int mcr; /* modem control-regsiter, write-only */
+ unsigned int lsr; /* line status register, read-only */
+ unsigned int msr; /* modem status register, read-only */
+ unsigned int scr; /* scratch regsiter, read/write */
+};
+
+#define _RXB(u) ((u)->w0.rxb)
+#define _TXB(u) ((u)->w0.txb)
+#define _DLL(u) ((u)->w0.dll)
+#define _IER(u) ((u)->w1.ier)
+#define _DLM(u) ((u)->w1.dlm)
+#define _ISR(u) ((u)->w2.isr)
+#define _FCR(u) ((u)->w2.fcr)
+#define _AFR(u) ((u)->w2.afr)
+#define _LCR(u) ((u)->lcr)
+#define _MCR(u) ((u)->mcr)
+#define _LSR(u) ((u)->lsr)
+#define _MSR(u) ((u)->msr)
+#define _SCR(u) ((u)->scr)
+
+typedef volatile struct uart_dev_s uart_dev_t;
+
+/* IER bits */
+#define RCVR_DATA_REG_INTENABLE 0x01
+#define XMIT_HOLD_REG_INTENABLE 0x02
+#define RCVR_STATUS_INTENABLE 0x04
+#define MODEM_STATUS_INTENABLE 0x08
+
+/* FCR bits */
+#define _FIFO_ENABLE 0x01
+#define RCVR_FIFO_RESET 0x02
+#define XMIT_FIFO_RESET 0x04
+#define DMA_MODE_SELECT 0x08
+#define RCVR_TRIGGER_LSB 0x40
+#define RCVR_TRIGGER_MSB 0x80
+
+/* AFR bits */
+#define AFR_CONC_WRITE 0x01
+#define AFR_BAUDOUT_SEL 0x02
+#define AFR_RXRDY_SEL 0x04
+
+/* ISR bits */
+#define INT_STATUS(r) ((r)&1)
+#define INT_PRIORITY(r) (((r)>>1)&0x7)
+
+/* LCR bits */
+#define WORD_LENGTH(n) (((n)-5)&0x3)
+#define STOP_BIT_ENABLE 0x04
+#define PARITY_ENABLE 0x08
+#define EVEN_PARITY 0x10
+#define FORCE_PARITY 0x20
+#define XMIT_BREAK 0x40
+#define DLAB_ENABLE 0x80
+
+/* MCR bits */
+#define _DTR 0x01
+#define _RTS 0x02
+#define _OP1 0x04
+#define _OP2 0x08
+#define LOOP_BACK 0x10
+
+/* LSR Bits */
+#define RCVR_DATA_READY 0x01
+#define OVERRUN_ERROR 0x02
+#define PARITY_ERROR 0x04
+#define FRAMING_ERROR 0x08
+#define BREAK_INTERRUPT 0x10
+#define XMIT_HOLD_EMPTY 0x20
+#define XMIT_EMPTY 0x40
+#define FIFO_ERROR 0x80
+#define RCVR_READY(u) (_LSR(u)&RCVR_DATA_READY)
+#define XMIT_READY(u) (_LSR(u)&XMIT_HOLD_EMPTY)
+
+/* MSR bits */
+#define _RDR 0x01
+#define DELTA_DSR 0x02
+#define DELTA_RI 0x04
+#define DELTA_CD 0x08
+#define _CTS 0x10
+#define _DSR 0x20
+#define _RI 0x40
+#define _CD 0x80
+
+/* prototypes */
+void uart_init( uart_dev_t *u, int bitrate );
+void uart_out( uart_dev_t *u, char c );
+void uart_puts( uart_dev_t *u, char *s );
+char uart_in( uart_dev_t *u );
+void uart_enable_rcvr_int( uart_dev_t *u );
+void uart_disable_rcvr_int( uart_dev_t *u );
+
+#ifdef DUART16552_1_VADDR
+/* DUART present. */
+#define DUART_1_BASE (*(uart_dev_t*)DUART16552_1_VADDR)
+#define DUART_2_BASE (*(uart_dev_t*)DUART16552_2_VADDR)
+#define UART1_PUTS(s) uart_puts( &DUART_1_BASE, s )
+#define UART2_PUTS(s) uart_puts( &DUART_2_BASE, s )
+#else
+/* DUART not configured, use dummy placeholders to allow compiles to work. */
+#define DUART_1_BASE (*(uart_dev_t*)0)
+#define DUART_2_BASE (*(uart_dev_t*)0)
+#define UART1_PUTS(s)
+#define UART2_PUTS(s)
+#endif
+
+/* Compute 16-bit divisor for baudrate generator, with rounding: */
+#define DUART_DIVISOR(crystal,speed) (((crystal)/16 + (speed)/2)/(speed))
+
+#endif /*_uart_h_included_*/
+
diff --git a/include/asm-xtensa/xtensa/xt2000.h b/include/asm-xtensa/xtensa/xt2000.h
new file mode 100644
index 000000000000..703a45002f8f
--- /dev/null
+++ b/include/asm-xtensa/xtensa/xt2000.h
@@ -0,0 +1,408 @@
+#ifndef _INC_XT2000_H_
+#define _INC_XT2000_H_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * include/asm-xtensa/xtensa/xt2000.h - Definitions specific to the
+ * Tensilica XT2000 Emulation Board
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/config/core.h>
+#include <xtensa/config/system.h>
+
+
+/*
+ * Default assignment of XT2000 devices to external interrupts.
+ */
+
+/* Ethernet interrupt: */
+#ifdef XCHAL_EXTINT3_NUM
+#define SONIC83934_INTNUM XCHAL_EXTINT3_NUM
+#define SONIC83934_INTLEVEL XCHAL_EXTINT3_LEVEL
+#define SONIC83934_INTMASK XCHAL_EXTINT3_MASK
+#else
+#define SONIC83934_INTMASK 0
+#endif
+
+/* DUART channel 1 interrupt (P1 - console): */
+#ifdef XCHAL_EXTINT4_NUM
+#define DUART16552_1_INTNUM XCHAL_EXTINT4_NUM
+#define DUART16552_1_INTLEVEL XCHAL_EXTINT4_LEVEL
+#define DUART16552_1_INTMASK XCHAL_EXTINT4_MASK
+#else
+#define DUART16552_1_INTMASK 0
+#endif
+
+/* DUART channel 2 interrupt (P2 - 2nd serial port): */
+#ifdef XCHAL_EXTINT5_NUM
+#define DUART16552_2_INTNUM XCHAL_EXTINT5_NUM
+#define DUART16552_2_INTLEVEL XCHAL_EXTINT5_LEVEL
+#define DUART16552_2_INTMASK XCHAL_EXTINT5_MASK
+#else
+#define DUART16552_2_INTMASK 0
+#endif
+
+/* FPGA-combined PCI/etc interrupts: */
+#ifdef XCHAL_EXTINT6_NUM
+#define XT2000_FPGAPCI_INTNUM XCHAL_EXTINT6_NUM
+#define XT2000_FPGAPCI_INTLEVEL XCHAL_EXTINT6_LEVEL
+#define XT2000_FPGAPCI_INTMASK XCHAL_EXTINT6_MASK
+#else
+#define XT2000_FPGAPCI_INTMASK 0
+#endif
+
+
+
+/*
+ * Device addresses.
+ *
+ * Note: for endianness-independence, use 32-bit loads and stores for all
+ * register accesses to Ethernet, DUART and LED devices. Undefined bits
+ * may need to be masked out if needed when reading if the actual register
+ * size is smaller than 32 bits.
+ *
+ * Note: XT2000 bus byte lanes are defined in terms of msbyte and lsbyte
+ * relative to the processor. So 32-bit registers are accessed consistently
+ * from both big and little endian processors. However, this means byte
+ * sequences are not consistent between big and little endian processors.
+ * This is fine for RAM, and for ROM if ROM is created for a specific
+ * processor (and thus has correct byte sequences). However this may be
+ * unexpected for Flash, which might contain a file-system that one wants
+ * to use for multiple processor configurations (eg. the Flash might contain
+ * the Ethernet card's address, endianness-independent application data, etc).
+ * That is, byte sequences written in Flash by a core of a given endianness
+ * will be byte-swapped when seen by a core of the other endianness.
+ * Someone implementing an endianness-independent Flash file system will
+ * likely handle this byte-swapping issue in the Flash driver software.
+ */
+
+#define DUART16552_XTAL_FREQ 18432000 /* crystal frequency in Hz */
+#define XTBOARD_FLASH_MAXSIZE 0x4000000 /* 64 MB (max; depends on what is socketed!) */
+#define XTBOARD_EPROM_MAXSIZE 0x0400000 /* 4 MB (max; depends on what is socketed!) */
+#define XTBOARD_EEPROM_MAXSIZE 0x0080000 /* 512 kB (max; depends on what is socketed!) */
+#define XTBOARD_ASRAM_SIZE 0x0100000 /* 1 MB */
+#define XTBOARD_PCI_MEM_SIZE 0x8000000 /* 128 MB (allocated) */
+#define XTBOARD_PCI_IO_SIZE 0x1000000 /* 16 MB (allocated) */
+
+#ifdef XSHAL_IOBLOCK_BYPASS_PADDR
+/* PCI memory space: */
+# define XTBOARD_PCI_MEM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x0000000)
+/* Socketed Flash (eg. 2 x 16-bit devices): */
+# define XTBOARD_FLASH_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0x8000000)
+/* PCI I/O space: */
+# define XTBOARD_PCI_IO_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xC000000)
+/* V3 PCI interface chip register/config space: */
+# define XTBOARD_V3PCI_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD000000)
+/* Bus Interface registers: */
+# define XTBOARD_BUSINT_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD010000)
+/* FPGA registers: */
+# define XT2000_FPGAREGS_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD020000)
+/* SONIC SN83934 Ethernet controller/transceiver: */
+# define SONIC83934_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD030000)
+/* 8-character bitmapped LED display: */
+# define XTBOARD_LED_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD040000)
+/* National-Semi PC16552D DUART: */
+# define DUART16552_1_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050020) /* channel 1 (P1 - console) */
+# define DUART16552_2_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD050000) /* channel 2 (P2) */
+/* Asynchronous Static RAM: */
+# define XTBOARD_ASRAM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD400000)
+/* 8-bit EEPROM: */
+# define XTBOARD_EEPROM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD600000)
+/* 2 x 16-bit EPROMs: */
+# define XTBOARD_EPROM_PADDR (XSHAL_IOBLOCK_BYPASS_PADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_BYPASS_PADDR */
+
+/* These devices might be accessed cached: */
+#ifdef XSHAL_IOBLOCK_CACHED_PADDR
+# define XTBOARD_PCI_MEM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0x0000000)
+# define XTBOARD_FLASH_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0x8000000)
+# define XTBOARD_ASRAM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD400000)
+# define XTBOARD_EEPROM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD600000)
+# define XTBOARD_EPROM_CACHED_PADDR (XSHAL_IOBLOCK_CACHED_PADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_CACHED_PADDR */
+
+
+/*** Same thing over again, this time with virtual addresses: ***/
+
+#ifdef XSHAL_IOBLOCK_BYPASS_VADDR
+/* PCI memory space: */
+# define XTBOARD_PCI_MEM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x0000000)
+/* Socketed Flash (eg. 2 x 16-bit devices): */
+# define XTBOARD_FLASH_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0x8000000)
+/* PCI I/O space: */
+# define XTBOARD_PCI_IO_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xC000000)
+/* V3 PCI interface chip register/config space: */
+# define XTBOARD_V3PCI_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD000000)
+/* Bus Interface registers: */
+# define XTBOARD_BUSINT_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD010000)
+/* FPGA registers: */
+# define XT2000_FPGAREGS_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD020000)
+/* SONIC SN83934 Ethernet controller/transceiver: */
+# define SONIC83934_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD030000)
+/* 8-character bitmapped LED display: */
+# define XTBOARD_LED_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD040000)
+/* National-Semi PC16552D DUART: */
+# define DUART16552_1_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050020) /* channel 1 (P1 - console) */
+# define DUART16552_2_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD050000) /* channel 2 (P2) */
+/* Asynchronous Static RAM: */
+# define XTBOARD_ASRAM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD400000)
+/* 8-bit EEPROM: */
+# define XTBOARD_EEPROM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD600000)
+/* 2 x 16-bit EPROMs: */
+# define XTBOARD_EPROM_VADDR (XSHAL_IOBLOCK_BYPASS_VADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_BYPASS_VADDR */
+
+/* These devices might be accessed cached: */
+#ifdef XSHAL_IOBLOCK_CACHED_VADDR
+# define XTBOARD_PCI_MEM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0x0000000)
+# define XTBOARD_FLASH_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0x8000000)
+# define XTBOARD_ASRAM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD400000)
+# define XTBOARD_EEPROM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD600000)
+# define XTBOARD_EPROM_CACHED_VADDR (XSHAL_IOBLOCK_CACHED_VADDR+0xD800000)
+#endif /* XSHAL_IOBLOCK_CACHED_VADDR */
+
+
+/* System ROM: */
+#define XTBOARD_ROM_SIZE XSHAL_ROM_SIZE
+#ifdef XSHAL_ROM_VADDR
+#define XTBOARD_ROM_VADDR XSHAL_ROM_VADDR
+#endif
+#ifdef XSHAL_ROM_PADDR
+#define XTBOARD_ROM_PADDR XSHAL_ROM_PADDR
+#endif
+
+/* System RAM: */
+#define XTBOARD_RAM_SIZE XSHAL_RAM_SIZE
+#ifdef XSHAL_RAM_VADDR
+#define XTBOARD_RAM_VADDR XSHAL_RAM_VADDR
+#endif
+#ifdef XSHAL_RAM_PADDR
+#define XTBOARD_RAM_PADDR XSHAL_RAM_PADDR
+#endif
+#define XTBOARD_RAM_BYPASS_VADDR XSHAL_RAM_BYPASS_VADDR
+#define XTBOARD_RAM_BYPASS_PADDR XSHAL_RAM_BYPASS_PADDR
+
+
+
+/*
+ * Things that depend on device addresses.
+ */
+
+
+#define XTBOARD_CACHEATTR_WRITEBACK XSHAL_XT2000_CACHEATTR_WRITEBACK
+#define XTBOARD_CACHEATTR_WRITEALLOC XSHAL_XT2000_CACHEATTR_WRITEALLOC
+#define XTBOARD_CACHEATTR_WRITETHRU XSHAL_XT2000_CACHEATTR_WRITETHRU
+#define XTBOARD_CACHEATTR_BYPASS XSHAL_XT2000_CACHEATTR_BYPASS
+#define XTBOARD_CACHEATTR_DEFAULT XSHAL_XT2000_CACHEATTR_DEFAULT
+
+#define XTBOARD_BUSINT_PIPE_REGIONS XSHAL_XT2000_PIPE_REGIONS
+#define XTBOARD_BUSINT_SDRAM_REGIONS XSHAL_XT2000_SDRAM_REGIONS
+
+
+
+/*
+ * BusLogic (FPGA) registers.
+ * All these registers are normally accessed using 32-bit loads/stores.
+ */
+
+/* Register offsets: */
+#define XT2000_DATECD_OFS 0x00 /* date code (read-only) */
+#define XT2000_STSREG_OFS 0x04 /* status (read-only) */
+#define XT2000_SYSLED_OFS 0x08 /* system LED */
+#define XT2000_WRPROT_OFS 0x0C /* write protect */
+#define XT2000_SWRST_OFS 0x10 /* software reset */
+#define XT2000_SYSRST_OFS 0x14 /* system (peripherals) reset */
+#define XT2000_IMASK_OFS 0x18 /* interrupt mask */
+#define XT2000_ISTAT_OFS 0x1C /* interrupt status */
+#define XT2000_V3CFG_OFS 0x20 /* V3 config (V320 PCI) */
+
+/* Physical register addresses: */
+#ifdef XT2000_FPGAREGS_PADDR
+#define XT2000_DATECD_PADDR (XT2000_FPGAREGS_PADDR+XT2000_DATECD_OFS)
+#define XT2000_STSREG_PADDR (XT2000_FPGAREGS_PADDR+XT2000_STSREG_OFS)
+#define XT2000_SYSLED_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SYSLED_OFS)
+#define XT2000_WRPROT_PADDR (XT2000_FPGAREGS_PADDR+XT2000_WRPROT_OFS)
+#define XT2000_SWRST_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SWRST_OFS)
+#define XT2000_SYSRST_PADDR (XT2000_FPGAREGS_PADDR+XT2000_SYSRST_OFS)
+#define XT2000_IMASK_PADDR (XT2000_FPGAREGS_PADDR+XT2000_IMASK_OFS)
+#define XT2000_ISTAT_PADDR (XT2000_FPGAREGS_PADDR+XT2000_ISTAT_OFS)
+#define XT2000_V3CFG_PADDR (XT2000_FPGAREGS_PADDR+XT2000_V3CFG_OFS)
+#endif
+
+/* Virtual register addresses: */
+#ifdef XT2000_FPGAREGS_VADDR
+#define XT2000_DATECD_VADDR (XT2000_FPGAREGS_VADDR+XT2000_DATECD_OFS)
+#define XT2000_STSREG_VADDR (XT2000_FPGAREGS_VADDR+XT2000_STSREG_OFS)
+#define XT2000_SYSLED_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SYSLED_OFS)
+#define XT2000_WRPROT_VADDR (XT2000_FPGAREGS_VADDR+XT2000_WRPROT_OFS)
+#define XT2000_SWRST_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SWRST_OFS)
+#define XT2000_SYSRST_VADDR (XT2000_FPGAREGS_VADDR+XT2000_SYSRST_OFS)
+#define XT2000_IMASK_VADDR (XT2000_FPGAREGS_VADDR+XT2000_IMASK_OFS)
+#define XT2000_ISTAT_VADDR (XT2000_FPGAREGS_VADDR+XT2000_ISTAT_OFS)
+#define XT2000_V3CFG_VADDR (XT2000_FPGAREGS_VADDR+XT2000_V3CFG_OFS)
+/* Register access (for C code): */
+#define XT2000_DATECD_REG (*(volatile unsigned*) XT2000_DATECD_VADDR)
+#define XT2000_STSREG_REG (*(volatile unsigned*) XT2000_STSREG_VADDR)
+#define XT2000_SYSLED_REG (*(volatile unsigned*) XT2000_SYSLED_VADDR)
+#define XT2000_WRPROT_REG (*(volatile unsigned*) XT2000_WRPROT_VADDR)
+#define XT2000_SWRST_REG (*(volatile unsigned*) XT2000_SWRST_VADDR)
+#define XT2000_SYSRST_REG (*(volatile unsigned*) XT2000_SYSRST_VADDR)
+#define XT2000_IMASK_REG (*(volatile unsigned*) XT2000_IMASK_VADDR)
+#define XT2000_ISTAT_REG (*(volatile unsigned*) XT2000_ISTAT_VADDR)
+#define XT2000_V3CFG_REG (*(volatile unsigned*) XT2000_V3CFG_VADDR)
+#endif
+
+/* DATECD (date code) bit fields: */
+
+/* BCD-coded month (01..12): */
+#define XT2000_DATECD_MONTH_SHIFT 24
+#define XT2000_DATECD_MONTH_BITS 8
+#define XT2000_DATECD_MONTH_MASK 0xFF000000
+/* BCD-coded day (01..31): */
+#define XT2000_DATECD_DAY_SHIFT 16
+#define XT2000_DATECD_DAY_BITS 8
+#define XT2000_DATECD_DAY_MASK 0x00FF0000
+/* BCD-coded year (2001..9999): */
+#define XT2000_DATECD_YEAR_SHIFT 0
+#define XT2000_DATECD_YEAR_BITS 16
+#define XT2000_DATECD_YEAR_MASK 0x0000FFFF
+
+/* STSREG (status) bit fields: */
+
+/* Switch SW3 setting bit fields (0=off/up, 1=on/down): */
+#define XT2000_STSREG_SW3_SHIFT 0
+#define XT2000_STSREG_SW3_BITS 4
+#define XT2000_STSREG_SW3_MASK 0x0000000F
+/* Boot-select bits of switch SW3: */
+#define XT2000_STSREG_BOOTSEL_SHIFT 0
+#define XT2000_STSREG_BOOTSEL_BITS 2
+#define XT2000_STSREG_BOOTSEL_MASK 0x00000003
+/* Boot-select values: */
+#define XT2000_STSREG_BOOTSEL_FLASH 0
+#define XT2000_STSREG_BOOTSEL_EPROM16 1
+#define XT2000_STSREG_BOOTSEL_PROM8 2
+#define XT2000_STSREG_BOOTSEL_ASRAM 3
+/* User-defined bits of switch SW3: */
+#define XT2000_STSREG_SW3_2_SHIFT 2
+#define XT2000_STSREG_SW3_2_MASK 0x00000004
+#define XT2000_STSREG_SW3_3_SHIFT 3
+#define XT2000_STSREG_SW3_3_MASK 0x00000008
+
+/* SYSLED (system LED) bit fields: */
+
+/* LED control bit (0=off, 1=on): */
+#define XT2000_SYSLED_LEDON_SHIFT 0
+#define XT2000_SYSLED_LEDON_MASK 0x00000001
+
+/* WRPROT (write protect) bit fields (0=writable, 1=write-protected [default]): */
+
+/* Flash write protect: */
+#define XT2000_WRPROT_FLWP_SHIFT 0
+#define XT2000_WRPROT_FLWP_MASK 0x00000001
+/* Reserved but present write protect bits: */
+#define XT2000_WRPROT_WRP_SHIFT 1
+#define XT2000_WRPROT_WRP_BITS 7
+#define XT2000_WRPROT_WRP_MASK 0x000000FE
+
+/* SWRST (software reset; allows s/w to generate power-on equivalent reset): */
+
+/* Software reset bits: */
+#define XT2000_SWRST_SWR_SHIFT 0
+#define XT2000_SWRST_SWR_BITS 16
+#define XT2000_SWRST_SWR_MASK 0x0000FFFF
+/* Software reset value -- writing this value resets the board: */
+#define XT2000_SWRST_RESETVALUE 0x0000DEAD
+
+/* SYSRST (system reset; controls reset of individual peripherals): */
+
+/* All-device reset: */
+#define XT2000_SYSRST_ALL_SHIFT 0
+#define XT2000_SYSRST_ALL_BITS 4
+#define XT2000_SYSRST_ALL_MASK 0x0000000F
+/* HDSP-2534 LED display reset (1=reset, 0=nothing): */
+#define XT2000_SYSRST_LED_SHIFT 0
+#define XT2000_SYSRST_LED_MASK 0x00000001
+/* Sonic DP83934 Ethernet controller reset (1=reset, 0=nothing): */
+#define XT2000_SYSRST_SONIC_SHIFT 1
+#define XT2000_SYSRST_SONIC_MASK 0x00000002
+/* DP16552 DUART reset (1=reset, 0=nothing): */
+#define XT2000_SYSRST_DUART_SHIFT 2
+#define XT2000_SYSRST_DUART_MASK 0x00000004
+/* V3 V320 PCI bridge controller reset (1=reset, 0=nothing): */
+#define XT2000_SYSRST_V3_SHIFT 3
+#define XT2000_SYSRST_V3_MASK 0x00000008
+
+/* IMASK (interrupt mask; 0=disable, 1=enable): */
+/* ISTAT (interrupt status; 0=inactive, 1=pending): */
+
+/* PCI INTP interrupt: */
+#define XT2000_INTMUX_PCI_INTP_SHIFT 2
+#define XT2000_INTMUX_PCI_INTP_MASK 0x00000004
+/* PCI INTS interrupt: */
+#define XT2000_INTMUX_PCI_INTS_SHIFT 3
+#define XT2000_INTMUX_PCI_INTS_MASK 0x00000008
+/* PCI INTD interrupt: */
+#define XT2000_INTMUX_PCI_INTD_SHIFT 4
+#define XT2000_INTMUX_PCI_INTD_MASK 0x00000010
+/* V320 PCI controller interrupt: */
+#define XT2000_INTMUX_V3_SHIFT 5
+#define XT2000_INTMUX_V3_MASK 0x00000020
+/* PCI ENUM interrupt: */
+#define XT2000_INTMUX_PCI_ENUM_SHIFT 6
+#define XT2000_INTMUX_PCI_ENUM_MASK 0x00000040
+/* PCI DEG interrupt: */
+#define XT2000_INTMUX_PCI_DEG_SHIFT 7
+#define XT2000_INTMUX_PCI_DEG_MASK 0x00000080
+
+/* V3CFG (V3 config, V320 PCI controller): */
+
+/* V3 address control (0=pass-thru, 1=V3 address bits 31:28 set to 4'b0001 [default]): */
+#define XT2000_V3CFG_V3ADC_SHIFT 0
+#define XT2000_V3CFG_V3ADC_MASK 0x00000001
+
+/* I2C Devices */
+
+#define XT2000_I2C_RTC_ID 0x68
+#define XT2000_I2C_NVRAM0_ID 0x56 /* 1st 256 byte block */
+#define XT2000_I2C_NVRAM1_ID 0x57 /* 2nd 256 byte block */
+
+/* NVRAM Board Info structure: */
+
+#define XT2000_NVRAM_SIZE 512
+
+#define XT2000_NVRAM_BINFO_START 0x100
+#define XT2000_NVRAM_BINFO_SIZE 0x20
+#define XT2000_NVRAM_BINFO_VERSION 0x10 /* version 1.0 */
+#if 0
+#define XT2000_NVRAM_BINFO_VERSION_OFFSET 0x00
+#define XT2000_NVRAM_BINFO_VERSION_SIZE 0x1
+#define XT2000_NVRAM_BINFO_ETH_ADDR_OFFSET 0x02
+#define XT2000_NVRAM_BINFO_ETH_ADDR_SIZE 0x6
+#define XT2000_NVRAM_BINFO_SN_OFFSET 0x10
+#define XT2000_NVRAM_BINFO_SN_SIZE 0xE
+#define XT2000_NVRAM_BINFO_CRC_OFFSET 0x1E
+#define XT2000_NVRAM_BINFO_CRC_SIZE 0x2
+#endif /*0*/
+
+#if !defined(__ASSEMBLY__) && !defined(_NOCLANGUAGE)
+typedef struct xt2000_nvram_binfo {
+ unsigned char version;
+ unsigned char reserved1;
+ unsigned char eth_addr[6];
+ unsigned char reserved8[8];
+ unsigned char serialno[14];
+ unsigned char crc[2]; /* 16-bit CRC */
+} xt2000_nvram_binfo;
+#endif /*!__ASSEMBLY__ && !_NOCLANGUAGE*/
+
+
+#endif /*_INC_XT2000_H_*/
+
diff --git a/include/asm-xtensa/xtensa/xtboard.h b/include/asm-xtensa/xtensa/xtboard.h
new file mode 100644
index 000000000000..22469c175307
--- /dev/null
+++ b/include/asm-xtensa/xtensa/xtboard.h
@@ -0,0 +1,120 @@
+#ifndef _xtboard_h_included_
+#define _xtboard_h_included_
+
+/*
+ * THIS FILE IS GENERATED -- DO NOT MODIFY BY HAND
+ *
+ * xtboard.h -- Routines for getting useful information from the board.
+ *
+ * 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) 2002 Tensilica Inc.
+ */
+
+
+#include <xtensa/xt2000.h>
+
+#define XTBOARD_RTC_ERROR -1
+#define XTBOARD_RTC_STOPPED -2
+
+
+/* xt2000-i2cdev.c: */
+typedef void XtboardDelayFunc( unsigned );
+extern XtboardDelayFunc* xtboard_set_nsdelay_func( XtboardDelayFunc *delay_fn );
+extern int xtboard_i2c_read (unsigned id, unsigned char *buf, unsigned addr, unsigned size);
+extern int xtboard_i2c_write(unsigned id, unsigned char *buf, unsigned addr, unsigned size);
+extern int xtboard_i2c_wait_nvram_ack(unsigned id, unsigned swtimer);
+
+/* xtboard.c: */
+extern int xtboard_nvram_read (unsigned addr, unsigned len, unsigned char *buf);
+extern int xtboard_nvram_write(unsigned addr, unsigned len, unsigned char *buf);
+extern int xtboard_nvram_binfo_read (xt2000_nvram_binfo *buf);
+extern int xtboard_nvram_binfo_write(xt2000_nvram_binfo *buf);
+extern int xtboard_nvram_binfo_valid(xt2000_nvram_binfo *buf);
+extern int xtboard_ethermac_get(unsigned char *buf);
+extern int xtboard_ethermac_set(unsigned char *buf);
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_rtc_time
+/
+/ Description: Get time stored in real-time clock.
+/
+/ Returns: time in seconds stored in real-time clock.
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_get_rtc_time(void);
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_set_rtc_time
+/
+/ Description: Set time stored in real-time clock.
+/
+/ Parameters: time -- time in seconds to store to real-time clock
+/
+/ Returns: 0 on success, xtboard_i2c_write() error code otherwise.
+/-**----------------------------------------------------------------------------*/
+
+extern int xtboard_set_rtc_time(unsigned time);
+
+
+/* xtfreq.c: */
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_measure_sys_clk
+/
+/ Description: Get frequency of system clock.
+/
+/ Parameters: none
+/
+/ Returns: frequency of system clock.
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_measure_sys_clk(void);
+
+
+#if 0 /* old stuff from xtboard.c: */
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_nvram valid
+/
+/ Description: Determines if data in NVRAM is valid.
+/
+/ Parameters: delay -- 10us delay function
+/
+/ Returns: 1 if NVRAM is valid, 0 otherwise
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_nvram_valid(void (*delay)( void ));
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_nvram_contents
+/
+/ Description: Returns contents of NVRAM.
+/
+/ Parameters: buf -- buffer to NVRAM contents.
+/ delay -- 10us delay function
+/
+/ Returns: 1 if NVRAM is valid, 0 otherwise
+/-**----------------------------------------------------------------------------*/
+
+extern unsigned xtboard_get_nvram_contents(unsigned char *buf, void (*delay)( void ));
+
+/*+*----------------------------------------------------------------------------
+/ Function: xtboard_get_ether_addr
+/
+/ Description: Returns ethernet address of board.
+/
+/ Parameters: buf -- buffer to store ethernet address
+/ delay -- 10us delay function
+/
+/ Returns: nothing.
+/-**----------------------------------------------------------------------------*/
+
+extern void xtboard_get_ether_addr(unsigned char *buf, void (*delay)( void ));
+
+#endif /*0*/
+
+
+#endif /*_xtboard_h_included_*/
+
diff --git a/include/linux/a.out.h b/include/linux/a.out.h
index af8a1dfa5c32..f913cc3e1b0d 100644
--- a/include/linux/a.out.h
+++ b/include/linux/a.out.h
@@ -138,7 +138,7 @@ enum machine_type {
#endif
#endif
-#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1))
+#define _N_SEGMENT_ROUND(x) ALIGN(x, SEGMENT_SIZE)
#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index b123cc08773d..f85cbe919e13 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -206,7 +206,10 @@ struct acpi_table_plat_int_src {
u8 eid;
u8 iosapic_vector;
u32 global_irq;
- u32 reserved;
+ struct {
+ u32 cpei_override_flag:1;
+ u32 reserved:31;
+ } plint_flags;
} __attribute__ ((packed));
enum acpi_interrupt_id {
@@ -342,11 +345,19 @@ struct acpi_table_ecdt {
/* PCI MMCONFIG */
+/* Defined in PCI Firmware Specification 3.0 */
+struct acpi_table_mcfg_config {
+ u32 base_address;
+ u32 base_reserved;
+ u16 pci_segment_group_number;
+ u8 start_bus_number;
+ u8 end_bus_number;
+ u8 reserved[4];
+} __attribute__ ((packed));
struct acpi_table_mcfg {
struct acpi_table_header header;
u8 reserved[8];
- u32 base_address;
- u32 base_reserved;
+ struct acpi_table_mcfg_config config[0];
} __attribute__ ((packed));
/* Table Handlers */
@@ -391,6 +402,7 @@ int acpi_table_parse (enum acpi_table_id id, acpi_table_handler handler);
int acpi_get_table_header_early (enum acpi_table_id id, struct acpi_table_header **header);
int acpi_table_parse_madt (enum acpi_madt_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
int acpi_table_parse_srat (enum acpi_srat_entry_id id, acpi_madt_entry_handler handler, unsigned int max_entries);
+int acpi_parse_mcfg (unsigned long phys_addr, unsigned long size);
void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
@@ -407,9 +419,13 @@ int acpi_map_lsapic(acpi_handle handle, int *pcpu);
int acpi_unmap_lsapic(int cpu);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */
+int acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base);
+int acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base);
+
extern int acpi_mp_config;
-extern u32 pci_mmcfg_base_addr;
+extern struct acpi_table_mcfg_config *pci_mmcfg_config;
+extern int pci_mmcfg_config_num;
extern int sbf_port ;
@@ -462,7 +478,7 @@ struct acpi_prt_list {
struct pci_dev;
int acpi_pci_irq_enable (struct pci_dev *dev);
-void acpi_penalize_isa_irq(int irq);
+void acpi_penalize_isa_irq(int irq, int active);
#ifdef CONFIG_ACPI_DEALLOCATE_IRQ
void acpi_pci_irq_disable (struct pci_dev *dev);
diff --git a/include/linux/atalk.h b/include/linux/atalk.h
index 09a1451c1159..911c09cb9bf9 100644
--- a/include/linux/atalk.h
+++ b/include/linux/atalk.h
@@ -1,6 +1,8 @@
#ifndef __LINUX_ATALK_H__
#define __LINUX_ATALK_H__
+#include <asm/byteorder.h>
+
/*
* AppleTalk networking structures
*
diff --git a/include/linux/audit.h b/include/linux/audit.h
index bf2ad3ba72eb..68aba0c02e49 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -165,7 +165,7 @@
#define AUDIT_ARCH_SH64 (EM_SH|__AUDIT_ARCH_64BIT)
#define AUDIT_ARCH_SHEL64 (EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_SPARC (EM_SPARC)
-#define AUDIT_ARCH_SPARC64 (EM_SPARC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SPARC64 (EM_SPARCV9|__AUDIT_ARCH_64BIT)
#define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE)
#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
diff --git a/include/linux/bio.h b/include/linux/bio.h
index 038022763f09..36ef29fa0d8b 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -22,6 +22,7 @@
#include <linux/highmem.h>
#include <linux/mempool.h>
+#include <linux/ioprio.h>
/* Platforms may set this to teach the BIO layer about IOMMU hardware. */
#include <asm/io.h>
@@ -150,6 +151,19 @@ struct bio {
#define BIO_RW_SYNC 4
/*
+ * upper 16 bits of bi_rw define the io priority of this bio
+ */
+#define BIO_PRIO_SHIFT (8 * sizeof(unsigned long) - IOPRIO_BITS)
+#define bio_prio(bio) ((bio)->bi_rw >> BIO_PRIO_SHIFT)
+#define bio_prio_valid(bio) ioprio_valid(bio_prio(bio))
+
+#define bio_set_prio(bio, prio) do { \
+ WARN_ON(prio >= (1 << IOPRIO_BITS)); \
+ (bio)->bi_rw &= ((1UL << BIO_PRIO_SHIFT) - 1); \
+ (bio)->bi_rw |= ((unsigned long) (prio) << BIO_PRIO_SHIFT); \
+} while (0)
+
+/*
* various member access, note that bio_data should of course not be used
* on highmem page vectors
*/
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 60272141ff19..0881b5cdee3d 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -54,16 +54,23 @@ struct as_io_context {
struct cfq_queue;
struct cfq_io_context {
- void (*dtor)(struct cfq_io_context *);
- void (*exit)(struct cfq_io_context *);
-
- struct io_context *ioc;
-
/*
* circular list of cfq_io_contexts belonging to a process io context
*/
struct list_head list;
struct cfq_queue *cfqq;
+ void *key;
+
+ struct io_context *ioc;
+
+ unsigned long last_end_request;
+ unsigned long last_queue;
+ unsigned long ttime_total;
+ unsigned long ttime_samples;
+ unsigned long ttime_mean;
+
+ void (*dtor)(struct cfq_io_context *);
+ void (*exit)(struct cfq_io_context *);
};
/*
@@ -73,7 +80,9 @@ struct cfq_io_context {
*/
struct io_context {
atomic_t refcount;
- pid_t pid;
+ struct task_struct *task;
+
+ int (*set_ioprio)(struct io_context *, unsigned int);
/*
* For request batching
@@ -81,14 +90,13 @@ struct io_context {
unsigned long last_waited; /* Time last woken after wait for request */
int nr_batch_requests; /* Number of requests left in the batch */
- spinlock_t lock;
-
struct as_io_context *aic;
struct cfq_io_context *cic;
};
void put_io_context(struct io_context *ioc);
void exit_io_context(void);
+struct io_context *current_io_context(int gfp_flags);
struct io_context *get_io_context(int gfp_flags);
void copy_io_context(struct io_context **pdst, struct io_context **psrc);
void swap_io_context(struct io_context **ioc1, struct io_context **ioc2);
@@ -134,6 +142,8 @@ struct request {
void *elevator_private;
+ unsigned short ioprio;
+
int rq_status; /* should split this into a few status bits */
struct gendisk *rq_disk;
int errors;
@@ -539,15 +549,12 @@ extern void generic_make_request(struct bio *bio);
extern void blk_put_request(struct request *);
extern void blk_end_sync_rq(struct request *rq);
extern void blk_attempt_remerge(request_queue_t *, struct request *);
-extern void __blk_attempt_remerge(request_queue_t *, struct request *);
extern struct request *blk_get_request(request_queue_t *, int, int);
extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
extern void blk_requeue_request(request_queue_t *, struct request *);
extern void blk_plug_device(request_queue_t *);
extern int blk_remove_plug(request_queue_t *);
extern void blk_recount_segments(request_queue_t *, struct bio *);
-extern int blk_phys_contig_segment(request_queue_t *q, struct bio *, struct bio *);
-extern int blk_hw_contig_segment(request_queue_t *q, struct bio *, struct bio *);
extern int scsi_cmd_ioctl(struct file *, struct gendisk *, unsigned int, void __user *);
extern void blk_start_queue(request_queue_t *q);
extern void blk_stop_queue(request_queue_t *q);
@@ -631,7 +638,6 @@ extern void blk_queue_dma_alignment(request_queue_t *, int);
extern struct backing_dev_info *blk_get_backing_dev_info(struct block_device *bdev);
extern void blk_queue_ordered(request_queue_t *, int);
extern void blk_queue_issue_flush_fn(request_queue_t *, issue_flush_fn *);
-extern int blkdev_scsi_issue_flush_fn(request_queue_t *, struct gendisk *, sector_t *);
extern struct request *blk_start_pre_flush(request_queue_t *,struct request *);
extern int blk_complete_barrier_rq(request_queue_t *, struct request *, int);
extern int blk_complete_barrier_rq_locked(request_queue_t *, struct request *, int);
@@ -675,8 +681,6 @@ extern int blkdev_issue_flush(struct block_device *, sector_t *);
#define blkdev_entry_to_request(entry) list_entry((entry), struct request, queuelist)
-extern void drive_stat_acct(struct request *, int, int);
-
static inline int queue_hardsect_size(request_queue_t *q)
{
int retval = 512;
diff --git a/include/linux/bootmem.h b/include/linux/bootmem.h
index 500f451ce0c0..82bd8842d11c 100644
--- a/include/linux/bootmem.h
+++ b/include/linux/bootmem.h
@@ -22,6 +22,10 @@ extern unsigned long min_low_pfn;
*/
extern unsigned long max_pfn;
+#ifdef CONFIG_CRASH_DUMP
+extern unsigned long saved_max_pfn;
+#endif
+
/*
* node_bootmem_map is a map pointer - the bits represent all physical
* memory pages (including holes) on the node.
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index 802c91e9b3da..90828493791f 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -19,6 +19,9 @@ enum bh_state_bits {
BH_Dirty, /* Is dirty */
BH_Lock, /* Is locked */
BH_Req, /* Has been submitted for I/O */
+ BH_Uptodate_Lock,/* Used by the first bh in a page, to serialise
+ * IO completion of other buffers in the page
+ */
BH_Mapped, /* Has a disk mapping */
BH_New, /* Disk mapping was newly created by get_block */
diff --git a/include/linux/byteorder/swabb.h b/include/linux/byteorder/swabb.h
index d28d9a804d3b..d5f2a3205109 100644
--- a/include/linux/byteorder/swabb.h
+++ b/include/linux/byteorder/swabb.h
@@ -92,29 +92,32 @@
#endif /* OPTIMIZE */
-static __inline__ __const__ __u32 __fswahw32(__u32 x)
+static inline __u32 __fswahw32(__u32 x)
{
return __arch__swahw32(x);
}
-static __inline__ __u32 __swahw32p(__u32 *x)
+
+static inline __u32 __swahw32p(__u32 *x)
{
return __arch__swahw32p(x);
}
-static __inline__ void __swahw32s(__u32 *addr)
+
+static inline void __swahw32s(__u32 *addr)
{
__arch__swahw32s(addr);
}
-
-static __inline__ __const__ __u32 __fswahb32(__u32 x)
+static inline __u32 __fswahb32(__u32 x)
{
return __arch__swahb32(x);
}
-static __inline__ __u32 __swahb32p(__u32 *x)
+
+static inline __u32 __swahb32p(__u32 *x)
{
return __arch__swahb32p(x);
}
-static __inline__ void __swahb32s(__u32 *addr)
+
+static inline void __swahb32s(__u32 *addr)
{
__arch__swahb32s(addr);
}
diff --git a/include/linux/cache.h b/include/linux/cache.h
index 4d767b93738a..f6b5a46c5f82 100644
--- a/include/linux/cache.h
+++ b/include/linux/cache.h
@@ -13,6 +13,12 @@
#define SMP_CACHE_BYTES L1_CACHE_BYTES
#endif
+#if defined(CONFIG_X86) || defined(CONFIG_SPARC64)
+#define __read_mostly __attribute__((__section__(".data.read_mostly")))
+#else
+#define __read_mostly
+#endif
+
#ifndef ____cacheline_aligned
#define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES)))
#endif
diff --git a/include/linux/cciss_ioctl.h b/include/linux/cciss_ioctl.h
index ee0c6e8995da..424d5e622b43 100644
--- a/include/linux/cciss_ioctl.h
+++ b/include/linux/cciss_ioctl.h
@@ -10,6 +10,7 @@
typedef struct _cciss_pci_info_struct
{
unsigned char bus;
+ unsigned short domain;
unsigned char dev_fn;
__u32 board_id;
} cciss_pci_info_struct;
diff --git a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h
index 70a4ebb5d964..ecb0d39c0798 100644
--- a/include/linux/compat_ioctl.h
+++ b/include/linux/compat_ioctl.h
@@ -346,10 +346,27 @@ COMPATIBLE_IOCTL(PPPOEIOCDFWD)
/* LP */
COMPATIBLE_IOCTL(LPGETSTATUS)
/* ppdev */
+COMPATIBLE_IOCTL(PPSETMODE)
+COMPATIBLE_IOCTL(PPRSTATUS)
+COMPATIBLE_IOCTL(PPRCONTROL)
+COMPATIBLE_IOCTL(PPWCONTROL)
+COMPATIBLE_IOCTL(PPFCONTROL)
+COMPATIBLE_IOCTL(PPRDATA)
+COMPATIBLE_IOCTL(PPWDATA)
COMPATIBLE_IOCTL(PPCLAIM)
COMPATIBLE_IOCTL(PPRELEASE)
-COMPATIBLE_IOCTL(PPEXCL)
COMPATIBLE_IOCTL(PPYIELD)
+COMPATIBLE_IOCTL(PPEXCL)
+COMPATIBLE_IOCTL(PPDATADIR)
+COMPATIBLE_IOCTL(PPNEGOT)
+COMPATIBLE_IOCTL(PPWCTLONIRQ)
+COMPATIBLE_IOCTL(PPCLRIRQ)
+COMPATIBLE_IOCTL(PPSETPHASE)
+COMPATIBLE_IOCTL(PPGETMODES)
+COMPATIBLE_IOCTL(PPGETMODE)
+COMPATIBLE_IOCTL(PPGETPHASE)
+COMPATIBLE_IOCTL(PPGETFLAGS)
+COMPATIBLE_IOCTL(PPSETFLAGS)
/* CDROM stuff */
COMPATIBLE_IOCTL(CDROMPAUSE)
COMPATIBLE_IOCTL(CDROMRESUME)
diff --git a/include/linux/cpu.h b/include/linux/cpu.h
index fe0298e5dae1..e8904c0da686 100644
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -69,6 +69,7 @@ extern struct semaphore cpucontrol;
register_cpu_notifier(&fn##_nb); \
}
int cpu_down(unsigned int cpu);
+extern int __attribute__((weak)) smp_prepare_cpu(int cpu);
#define cpu_is_offline(cpu) unlikely(!cpu_online(cpu))
#else
#define lock_cpu_hotplug() do { } while (0)
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 927daa86c9b3..ff7f80f48df1 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -201,7 +201,7 @@ struct cpufreq_driver {
/* optional */
int (*exit) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy, u32 state);
+ int (*suspend) (struct cpufreq_policy *policy, pm_message_t pmsg);
int (*resume) (struct cpufreq_policy *policy);
struct freq_attr **attr;
};
diff --git a/include/linux/crash_dump.h b/include/linux/crash_dump.h
new file mode 100644
index 000000000000..534d750d922d
--- /dev/null
+++ b/include/linux/crash_dump.h
@@ -0,0 +1,18 @@
+#ifndef LINUX_CRASH_DUMP_H
+#define LINUX_CRASH_DUMP_H
+
+#ifdef CONFIG_CRASH_DUMP
+#include <linux/kexec.h>
+#include <linux/smp_lock.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+
+#define ELFCORE_ADDR_MAX (-1ULL)
+extern unsigned long long elfcorehdr_addr;
+extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
+ unsigned long, int);
+extern struct file_operations proc_vmcore_operations;
+extern struct proc_dir_entry *proc_vmcore;
+
+#endif /* CONFIG_CRASH_DUMP */
+#endif /* LINUX_CRASHDUMP_H */
diff --git a/include/linux/crypto.h b/include/linux/crypto.h
index 387da6a3e58c..5e2bcc636a02 100644
--- a/include/linux/crypto.h
+++ b/include/linux/crypto.h
@@ -61,6 +61,15 @@
#define CRYPTO_DIR_DECRYPT 0
struct scatterlist;
+struct crypto_tfm;
+
+struct cipher_desc {
+ struct crypto_tfm *tfm;
+ void (*crfn)(void *ctx, u8 *dst, const u8 *src);
+ unsigned int (*prfn)(const struct cipher_desc *desc, u8 *dst,
+ const u8 *src, unsigned int nbytes);
+ void *info;
+};
/*
* Algorithms: modular crypto algorithm implementations, managed
@@ -73,6 +82,19 @@ struct cipher_alg {
unsigned int keylen, u32 *flags);
void (*cia_encrypt)(void *ctx, u8 *dst, const u8 *src);
void (*cia_decrypt)(void *ctx, u8 *dst, const u8 *src);
+
+ unsigned int (*cia_encrypt_ecb)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes);
+ unsigned int (*cia_decrypt_ecb)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes);
+ unsigned int (*cia_encrypt_cbc)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes);
+ unsigned int (*cia_decrypt_cbc)(const struct cipher_desc *desc,
+ u8 *dst, const u8 *src,
+ unsigned int nbytes);
};
struct digest_alg {
@@ -102,6 +124,7 @@ struct crypto_alg {
u32 cra_flags;
unsigned int cra_blocksize;
unsigned int cra_ctxsize;
+ unsigned int cra_alignmask;
const char cra_name[CRYPTO_MAX_ALG_NAME];
union {
@@ -136,7 +159,6 @@ static inline int crypto_alg_available(const char *name, u32 flags)
* and core processing logic. Managed via crypto_alloc_tfm() and
* crypto_free_tfm(), as well as the various helpers below.
*/
-struct crypto_tfm;
struct cipher_tfm {
void *cit_iv;
@@ -266,6 +288,16 @@ static inline unsigned int crypto_tfm_alg_digestsize(struct crypto_tfm *tfm)
return tfm->__crt_alg->cra_digest.dia_digestsize;
}
+static inline unsigned int crypto_tfm_alg_alignmask(struct crypto_tfm *tfm)
+{
+ return tfm->__crt_alg->cra_alignmask;
+}
+
+static inline void *crypto_tfm_ctx(struct crypto_tfm *tfm)
+{
+ return (void *)&tfm[1];
+}
+
/*
* API wrappers.
*/
diff --git a/include/linux/device.h b/include/linux/device.h
index 7b781a72b293..06e5d42f2c7b 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -69,7 +69,7 @@ struct bus_type {
extern int bus_register(struct bus_type * bus);
extern void bus_unregister(struct bus_type * bus);
-extern int bus_rescan_devices(struct bus_type * bus);
+extern void bus_rescan_devices(struct bus_type * bus);
extern struct bus_type * get_bus(struct bus_type * bus);
extern void put_bus(struct bus_type * bus);
@@ -80,6 +80,8 @@ extern struct bus_type * find_bus(char * name);
int bus_for_each_dev(struct bus_type * bus, struct device * start, void * data,
int (*fn)(struct device *, void *));
+struct device * bus_find_device(struct bus_type *bus, struct device *start,
+ void *data, int (*match)(struct device *, void *));
int bus_for_each_drv(struct bus_type * bus, struct device_driver * start,
void * data, int (*fn)(struct device_driver *, void *));
@@ -142,6 +144,9 @@ extern void driver_remove_file(struct device_driver *, struct driver_attribute *
extern int driver_for_each_device(struct device_driver * drv, struct device * start,
void * data, int (*fn)(struct device *, void *));
+struct device * driver_find_device(struct device_driver *drv,
+ struct device *start, void *data,
+ int (*match)(struct device *, void *));
/*
@@ -279,8 +284,10 @@ struct device {
struct device_driver *driver; /* which driver has allocated this
device */
void *driver_data; /* data private to the driver */
- void *platform_data; /* Platform specific data (e.g. ACPI,
- BIOS data relevant to device) */
+ void *platform_data; /* Platform specific data, device
+ core doesn't touch it */
+ void *firmware_data; /* Firmware specific data (e.g. ACPI,
+ BIOS data),reserved for device core*/
struct dev_pm_info power;
u64 *dma_mask; /* dma mask (if dma'able device) */
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index d2bcf556088b..5e93e6dce9a4 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -9,6 +9,7 @@ enum dmi_field {
DMI_SYS_VENDOR,
DMI_PRODUCT_NAME,
DMI_PRODUCT_VERSION,
+ DMI_PRODUCT_SERIAL,
DMI_BOARD_VENDOR,
DMI_BOARD_NAME,
DMI_BOARD_VERSION,
diff --git a/include/linux/dqblk_v1.h b/include/linux/dqblk_v1.h
index 42fbf4797156..57f1250d5a52 100644
--- a/include/linux/dqblk_v1.h
+++ b/include/linux/dqblk_v1.h
@@ -11,6 +11,12 @@
/* Root squash turned on */
#define V1_DQF_RSQUASH 1
+/* Numbers of blocks needed for updates */
+#define V1_INIT_ALLOC 1
+#define V1_INIT_REWRITE 1
+#define V1_DEL_ALLOC 0
+#define V1_DEL_REWRITE 2
+
/* Special information about quotafile */
struct v1_mem_dqinfo {
};
diff --git a/include/linux/dqblk_v2.h b/include/linux/dqblk_v2.h
index 4a6c5f6867bb..4f853322cb7f 100644
--- a/include/linux/dqblk_v2.h
+++ b/include/linux/dqblk_v2.h
@@ -10,6 +10,12 @@
/* id numbers of quota format */
#define QFMT_VFS_V0 2
+/* Numbers of blocks needed for updates */
+#define V2_INIT_ALLOC 4
+#define V2_INIT_REWRITE 2
+#define V2_DEL_ALLOC 0
+#define V2_DEL_REWRITE 6
+
/* Inmemory copy of version specific information */
struct v2_mem_dqinfo {
unsigned int dqi_blocks;
diff --git a/include/linux/elevator.h b/include/linux/elevator.h
index ee54f81faad5..ea6bbc2d7407 100644
--- a/include/linux/elevator.h
+++ b/include/linux/elevator.h
@@ -16,9 +16,9 @@ typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
typedef void (elevator_requeue_req_fn) (request_queue_t *, struct request *);
typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
typedef void (elevator_completed_req_fn) (request_queue_t *, struct request *);
-typedef int (elevator_may_queue_fn) (request_queue_t *, int);
+typedef int (elevator_may_queue_fn) (request_queue_t *, int, struct bio *);
-typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
+typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, struct bio *, int);
typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
typedef void (elevator_deactivate_req_fn) (request_queue_t *, struct request *);
@@ -96,9 +96,9 @@ extern struct request *elv_former_request(request_queue_t *, struct request *);
extern struct request *elv_latter_request(request_queue_t *, struct request *);
extern int elv_register_queue(request_queue_t *q);
extern void elv_unregister_queue(request_queue_t *q);
-extern int elv_may_queue(request_queue_t *, int);
+extern int elv_may_queue(request_queue_t *, int, struct bio *);
extern void elv_completed_request(request_queue_t *, struct request *);
-extern int elv_set_request(request_queue_t *, struct request *, int);
+extern int elv_set_request(request_queue_t *, struct request *, struct bio *, int);
extern void elv_put_request(request_queue_t *, struct request *);
/*
diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h
index a1478258d002..ce8518e658b6 100644
--- a/include/linux/etherdevice.h
+++ b/include/linux/etherdevice.h
@@ -25,6 +25,7 @@
#define _LINUX_ETHERDEVICE_H
#include <linux/if_ether.h>
+#include <linux/netdevice.h>
#include <linux/random.h>
#ifdef __KERNEL__
@@ -32,7 +33,7 @@ extern int eth_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr,
void *saddr, unsigned len);
extern int eth_rebuild_header(struct sk_buff *skb);
-extern unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev);
+extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev);
extern void eth_header_cache_update(struct hh_cache *hh, struct net_device *dev,
unsigned char * haddr);
extern int eth_header_cache(struct neighbour *neigh,
@@ -65,7 +66,7 @@ static inline int is_zero_ether_addr(const u8 *addr)
*/
static inline int is_multicast_ether_addr(const u8 *addr)
{
- return addr[0] & 0x01;
+ return ((addr[0] != 0xff) && (0x01 & addr[0]));
}
/**
diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h
index fab43527e597..a657130ba03a 100644
--- a/include/linux/ext2_fs.h
+++ b/include/linux/ext2_fs.h
@@ -300,18 +300,19 @@ struct ext2_inode {
/*
* Mount flags
*/
-#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
-#define EXT2_MOUNT_OLDALLOC 0x0002 /* Don't use the new Orlov allocator */
-#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
-#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
-#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
-#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
-#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
-#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
-#define EXT2_MOUNT_NOBH 0x0100 /* No buffer_heads */
-#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
-#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */
-#define EXT2_MOUNT_POSIX_ACL 0x8000 /* POSIX Access Control Lists */
+#define EXT2_MOUNT_CHECK 0x000001 /* Do mount-time checks */
+#define EXT2_MOUNT_OLDALLOC 0x000002 /* Don't use the new Orlov allocator */
+#define EXT2_MOUNT_GRPID 0x000004 /* Create files with directory's group */
+#define EXT2_MOUNT_DEBUG 0x000008 /* Some debugging messages */
+#define EXT2_MOUNT_ERRORS_CONT 0x000010 /* Continue on errors */
+#define EXT2_MOUNT_ERRORS_RO 0x000020 /* Remount fs ro on errors */
+#define EXT2_MOUNT_ERRORS_PANIC 0x000040 /* Panic on errors */
+#define EXT2_MOUNT_MINIX_DF 0x000080 /* Mimics the Minix statfs */
+#define EXT2_MOUNT_NOBH 0x000100 /* No buffer_heads */
+#define EXT2_MOUNT_NO_UID32 0x000200 /* Disable 32-bit UIDs */
+#define EXT2_MOUNT_XATTR_USER 0x004000 /* Extended user attributes */
+#define EXT2_MOUNT_POSIX_ACL 0x008000 /* POSIX Access Control Lists */
+#define EXT2_MOUNT_XIP 0x010000 /* Execute in place */
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
diff --git a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
index 74ad31781e3e..c16662836c58 100644
--- a/include/linux/ext3_fs.h
+++ b/include/linux/ext3_fs.h
@@ -239,6 +239,20 @@ struct ext3_new_group_data {
#define EXT3_IOC_SETRSVSZ _IOW('f', 6, long)
/*
+ * Mount options
+ */
+struct ext3_mount_options {
+ unsigned long s_mount_opt;
+ uid_t s_resuid;
+ gid_t s_resgid;
+ unsigned long s_commit_interval;
+#ifdef CONFIG_QUOTA
+ int s_jquota_fmt;
+ char *s_qf_names[MAXQUOTAS];
+#endif
+};
+
+/*
* Structure of an inode on the disk
*/
struct ext3_inode {
@@ -358,6 +372,7 @@ struct ext3_inode {
#define EXT3_MOUNT_RESERVATION 0x10000 /* Preallocation */
#define EXT3_MOUNT_BARRIER 0x20000 /* Use block barriers */
#define EXT3_MOUNT_NOBH 0x40000 /* No bufferheads */
+#define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
#ifndef _LINUX_EXT2_FS_H
diff --git a/include/linux/ext3_jbd.h b/include/linux/ext3_jbd.h
index e8292af9033b..c8307c02dd07 100644
--- a/include/linux/ext3_jbd.h
+++ b/include/linux/ext3_jbd.h
@@ -42,15 +42,15 @@
* superblock only gets updated once, of course, so don't bother
* counting that again for the quota updates. */
-#define EXT3_DATA_TRANS_BLOCKS (EXT3_SINGLEDATA_TRANS_BLOCKS + \
+#define EXT3_DATA_TRANS_BLOCKS(sb) (EXT3_SINGLEDATA_TRANS_BLOCKS + \
EXT3_XATTR_TRANS_BLOCKS - 2 + \
- 2*EXT3_QUOTA_TRANS_BLOCKS)
+ 2*EXT3_QUOTA_TRANS_BLOCKS(sb))
/* Delete operations potentially hit one directory's namespace plus an
* entire inode, plus arbitrary amounts of bitmap/indirection data. Be
* generous. We can grow the delete transaction later if necessary. */
-#define EXT3_DELETE_TRANS_BLOCKS (2 * EXT3_DATA_TRANS_BLOCKS + 64)
+#define EXT3_DELETE_TRANS_BLOCKS(sb) (2 * EXT3_DATA_TRANS_BLOCKS(sb) + 64)
/* Define an arbitrary limit for the amount of data we will anticipate
* writing to any given transaction. For unbounded transactions such as
@@ -74,14 +74,17 @@
#ifdef CONFIG_QUOTA
/* Amount of blocks needed for quota update - we know that the structure was
* allocated so we need to update only inode+data */
-#define EXT3_QUOTA_TRANS_BLOCKS 2
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) (test_opt(sb, QUOTA) ? 2 : 0)
/* Amount of blocks needed for quota insert/delete - we do some block writes
* but inode, sb and group updates are done only once */
-#define EXT3_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*\
- (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3)
+#define EXT3_QUOTA_INIT_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_INIT_ALLOC*\
+ (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_INIT_REWRITE) : 0)
+#define EXT3_QUOTA_DEL_BLOCKS(sb) (test_opt(sb, QUOTA) ? (DQUOT_DEL_ALLOC*\
+ (EXT3_SINGLEDATA_TRANS_BLOCKS-3)+3+DQUOT_DEL_REWRITE) : 0)
#else
-#define EXT3_QUOTA_TRANS_BLOCKS 0
-#define EXT3_QUOTA_INIT_BLOCKS 0
+#define EXT3_QUOTA_TRANS_BLOCKS(sb) 0
+#define EXT3_QUOTA_INIT_BLOCKS(sb) 0
+#define EXT3_QUOTA_DEL_BLOCKS(sb) 0
#endif
int
diff --git a/include/linux/fddidevice.h b/include/linux/fddidevice.h
index 002f6367697d..e61e42dfd317 100644
--- a/include/linux/fddidevice.h
+++ b/include/linux/fddidevice.h
@@ -25,7 +25,7 @@
#include <linux/if_fddi.h>
#ifdef __KERNEL__
-extern unsigned short fddi_type_trans(struct sk_buff *skb,
+extern __be16 fddi_type_trans(struct sk_buff *skb,
struct net_device *dev);
extern struct net_device *alloc_fddidev(int sizeof_priv);
#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 517bf4966bf5..c9bf3746a9fb 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -213,6 +213,7 @@ extern int dir_notify_enable;
#include <linux/radix-tree.h>
#include <linux/prio_tree.h>
#include <linux/init.h>
+#include <linux/sched.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>
@@ -220,6 +221,7 @@ extern int dir_notify_enable;
struct iovec;
struct nameidata;
+struct kiocb;
struct pipe_inode_info;
struct poll_table_struct;
struct kstatfs;
@@ -240,7 +242,7 @@ typedef int (get_block_t)(struct inode *inode, sector_t iblock,
typedef int (get_blocks_t)(struct inode *inode, sector_t iblock,
unsigned long max_blocks,
struct buffer_head *bh_result, int create);
-typedef void (dio_iodone_t)(struct inode *inode, loff_t offset,
+typedef void (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
ssize_t bytes, void *private);
/*
@@ -302,7 +304,6 @@ struct iattr {
struct page;
struct address_space;
struct writeback_control;
-struct kiocb;
struct address_space_operations {
int (*writepage)(struct page *page, struct writeback_control *wbc);
@@ -330,6 +331,8 @@ struct address_space_operations {
int (*releasepage) (struct page *, int);
ssize_t (*direct_IO)(int, struct kiocb *, const struct iovec *iov,
loff_t offset, unsigned long nr_segs);
+ struct page* (*get_xip_page)(struct address_space *, sector_t,
+ int);
};
struct backing_dev_info;
@@ -471,6 +474,11 @@ struct inode {
struct dnotify_struct *i_dnotify; /* for directory notifications */
#endif
+#ifdef CONFIG_INOTIFY
+ struct list_head inotify_watches; /* watches on this inode */
+ struct semaphore inotify_sem; /* protects the watches list */
+#endif
+
unsigned long i_state;
unsigned long dirtied_when; /* jiffies of first dirtying */
@@ -820,16 +828,34 @@ enum {
#define vfs_check_frozen(sb, level) \
wait_event((sb)->s_wait_unfrozen, ((sb)->s_frozen < (level)))
+static inline void get_fs_excl(void)
+{
+ atomic_inc(&current->fs_excl);
+}
+
+static inline void put_fs_excl(void)
+{
+ atomic_dec(&current->fs_excl);
+}
+
+static inline int has_fs_excl(void)
+{
+ return atomic_read(&current->fs_excl);
+}
+
+
/*
* Superblock locking.
*/
static inline void lock_super(struct super_block * sb)
{
+ get_fs_excl();
down(&sb->s_lock);
}
static inline void unlock_super(struct super_block * sb)
{
+ put_fs_excl();
up(&sb->s_lock);
}
@@ -885,6 +911,7 @@ struct block_device_operations {
int (*ioctl) (struct inode *, struct file *, unsigned, unsigned long);
long (*unlocked_ioctl) (struct file *, unsigned, unsigned long);
long (*compat_ioctl) (struct file *, unsigned, unsigned long);
+ int (*direct_access) (struct block_device *, sector_t, unsigned long *);
int (*media_changed) (struct gendisk *);
int (*revalidate_disk) (struct gendisk *);
struct module *owner;
@@ -1371,7 +1398,6 @@ extern void emergency_remount(void);
extern int do_remount_sb(struct super_block *sb, int flags,
void *data, int force);
extern sector_t bmap(struct inode *, sector_t);
-extern int setattr_mask(unsigned int);
extern int notify_change(struct dentry *, struct iattr *);
extern int permission(struct inode *, int, struct nameidata *);
extern int generic_permission(struct inode *, int,
@@ -1413,6 +1439,7 @@ extern struct inode * igrab(struct inode *);
extern ino_t iunique(struct super_block *, ino_t);
extern int inode_needs_sync(struct inode *inode);
extern void generic_delete_inode(struct inode *inode);
+extern void generic_drop_inode(struct inode *inode);
extern struct inode *ilookup5(struct super_block *sb, unsigned long hashval,
int (*test)(struct inode *, void *), void *data);
@@ -1496,6 +1523,23 @@ extern loff_t remote_llseek(struct file *file, loff_t offset, int origin);
extern int generic_file_open(struct inode * inode, struct file * filp);
extern int nonseekable_open(struct inode * inode, struct file * filp);
+#ifdef CONFIG_FS_XIP
+extern ssize_t xip_file_read(struct file *filp, char __user *buf, size_t len,
+ loff_t *ppos);
+extern ssize_t xip_file_sendfile(struct file *in_file, loff_t *ppos,
+ size_t count, read_actor_t actor,
+ void *target);
+extern int xip_file_mmap(struct file * file, struct vm_area_struct * vma);
+extern ssize_t xip_file_write(struct file *filp, const char __user *buf,
+ size_t len, loff_t *ppos);
+extern int xip_truncate_page(struct address_space *mapping, loff_t from);
+#else
+static inline int xip_truncate_page(struct address_space *mapping, loff_t from)
+{
+ return 0;
+}
+#endif
+
static inline void do_generic_file_read(struct file * filp, loff_t *ppos,
read_descriptor_t * desc,
read_actor_t actor)
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
new file mode 100644
index 000000000000..eb581b6cfca9
--- /dev/null
+++ b/include/linux/fsnotify.h
@@ -0,0 +1,248 @@
+#ifndef _LINUX_FS_NOTIFY_H
+#define _LINUX_FS_NOTIFY_H
+
+/*
+ * include/linux/fsnotify.h - generic hooks for filesystem notification, to
+ * reduce in-source duplication from both dnotify and inotify.
+ *
+ * We don't compile any of this away in some complicated menagerie of ifdefs.
+ * Instead, we rely on the code inside to optimize away as needed.
+ *
+ * (C) Copyright 2005 Robert Love
+ */
+
+#ifdef __KERNEL__
+
+#include <linux/dnotify.h>
+#include <linux/inotify.h>
+
+/*
+ * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
+ */
+static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
+ const char *old_name, const char *new_name,
+ int isdir)
+{
+ u32 cookie = inotify_get_cookie();
+
+ if (old_dir == new_dir)
+ inode_dir_notify(old_dir, DN_RENAME);
+ else {
+ inode_dir_notify(old_dir, DN_DELETE);
+ inode_dir_notify(new_dir, DN_CREATE);
+ }
+
+ if (isdir)
+ isdir = IN_ISDIR;
+ inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name);
+ inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name);
+}
+
+/*
+ * fsnotify_unlink - file was unlinked
+ */
+static inline void fsnotify_unlink(struct dentry *dentry, struct inode *dir)
+{
+ struct inode *inode = dentry->d_inode;
+
+ inode_dir_notify(dir, DN_DELETE);
+ inotify_inode_queue_event(dir, IN_DELETE, 0, dentry->d_name.name);
+ inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL);
+
+ inotify_inode_is_dead(inode);
+}
+
+/*
+ * fsnotify_rmdir - directory was removed
+ */
+static inline void fsnotify_rmdir(struct dentry *dentry, struct inode *inode,
+ struct inode *dir)
+{
+ inode_dir_notify(dir, DN_DELETE);
+ inotify_inode_queue_event(dir,IN_DELETE|IN_ISDIR,0,dentry->d_name.name);
+ inotify_inode_queue_event(inode, IN_DELETE_SELF | IN_ISDIR, 0, NULL);
+ inotify_inode_is_dead(inode);
+}
+
+/*
+ * fsnotify_create - 'name' was linked in
+ */
+static inline void fsnotify_create(struct inode *inode, const char *name)
+{
+ inode_dir_notify(inode, DN_CREATE);
+ inotify_inode_queue_event(inode, IN_CREATE, 0, name);
+}
+
+/*
+ * fsnotify_mkdir - directory 'name' was created
+ */
+static inline void fsnotify_mkdir(struct inode *inode, const char *name)
+{
+ inode_dir_notify(inode, DN_CREATE);
+ inotify_inode_queue_event(inode, IN_CREATE | IN_ISDIR, 0, name);
+}
+
+/*
+ * fsnotify_access - file was read
+ */
+static inline void fsnotify_access(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ u32 mask = IN_ACCESS;
+
+ if (S_ISDIR(inode->i_mode))
+ mask |= IN_ISDIR;
+
+ dnotify_parent(dentry, DN_ACCESS);
+ inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
+ inotify_inode_queue_event(inode, mask, 0, NULL);
+}
+
+/*
+ * fsnotify_modify - file was modified
+ */
+static inline void fsnotify_modify(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ u32 mask = IN_MODIFY;
+
+ if (S_ISDIR(inode->i_mode))
+ mask |= IN_ISDIR;
+
+ dnotify_parent(dentry, DN_MODIFY);
+ inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
+ inotify_inode_queue_event(inode, mask, 0, NULL);
+}
+
+/*
+ * fsnotify_open - file was opened
+ */
+static inline void fsnotify_open(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ u32 mask = IN_OPEN;
+
+ if (S_ISDIR(inode->i_mode))
+ mask |= IN_ISDIR;
+
+ inotify_inode_queue_event(inode, mask, 0, NULL);
+ inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
+}
+
+/*
+ * fsnotify_close - file was closed
+ */
+static inline void fsnotify_close(struct file *file)
+{
+ struct dentry *dentry = file->f_dentry;
+ struct inode *inode = dentry->d_inode;
+ const char *name = dentry->d_name.name;
+ mode_t mode = file->f_mode;
+ u32 mask = (mode & FMODE_WRITE) ? IN_CLOSE_WRITE : IN_CLOSE_NOWRITE;
+
+ if (S_ISDIR(inode->i_mode))
+ mask |= IN_ISDIR;
+
+ inotify_dentry_parent_queue_event(dentry, mask, 0, name);
+ inotify_inode_queue_event(inode, mask, 0, NULL);
+}
+
+/*
+ * fsnotify_xattr - extended attributes were changed
+ */
+static inline void fsnotify_xattr(struct dentry *dentry)
+{
+ struct inode *inode = dentry->d_inode;
+ u32 mask = IN_ATTRIB;
+
+ if (S_ISDIR(inode->i_mode))
+ mask |= IN_ISDIR;
+
+ inotify_dentry_parent_queue_event(dentry, mask, 0, dentry->d_name.name);
+ inotify_inode_queue_event(inode, mask, 0, NULL);
+}
+
+/*
+ * fsnotify_change - notify_change event. file was modified and/or metadata
+ * was changed.
+ */
+static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
+{
+ struct inode *inode = dentry->d_inode;
+ int dn_mask = 0;
+ u32 in_mask = 0;
+
+ if (ia_valid & ATTR_UID) {
+ in_mask |= IN_ATTRIB;
+ dn_mask |= DN_ATTRIB;
+ }
+ if (ia_valid & ATTR_GID) {
+ in_mask |= IN_ATTRIB;
+ dn_mask |= DN_ATTRIB;
+ }
+ if (ia_valid & ATTR_SIZE) {
+ in_mask |= IN_MODIFY;
+ dn_mask |= DN_MODIFY;
+ }
+ /* both times implies a utime(s) call */
+ if ((ia_valid & (ATTR_ATIME | ATTR_MTIME)) == (ATTR_ATIME | ATTR_MTIME))
+ {
+ in_mask |= IN_ATTRIB;
+ dn_mask |= DN_ATTRIB;
+ } else if (ia_valid & ATTR_ATIME) {
+ in_mask |= IN_ACCESS;
+ dn_mask |= DN_ACCESS;
+ } else if (ia_valid & ATTR_MTIME) {
+ in_mask |= IN_MODIFY;
+ dn_mask |= DN_MODIFY;
+ }
+ if (ia_valid & ATTR_MODE) {
+ in_mask |= IN_ATTRIB;
+ dn_mask |= DN_ATTRIB;
+ }
+
+ if (dn_mask)
+ dnotify_parent(dentry, dn_mask);
+ if (in_mask) {
+ if (S_ISDIR(inode->i_mode))
+ in_mask |= IN_ISDIR;
+ inotify_inode_queue_event(inode, in_mask, 0, NULL);
+ inotify_dentry_parent_queue_event(dentry, in_mask, 0,
+ dentry->d_name.name);
+ }
+}
+
+#ifdef CONFIG_INOTIFY /* inotify helpers */
+
+/*
+ * fsnotify_oldname_init - save off the old filename before we change it
+ */
+static inline const char *fsnotify_oldname_init(const char *name)
+{
+ return kstrdup(name, GFP_KERNEL);
+}
+
+/*
+ * fsnotify_oldname_free - free the name we got from fsnotify_oldname_init
+ */
+static inline void fsnotify_oldname_free(const char *old_name)
+{
+ kfree(old_name);
+}
+
+#else /* CONFIG_INOTIFY */
+
+static inline const char *fsnotify_oldname_init(const char *name)
+{
+ return NULL;
+}
+
+static inline void fsnotify_oldname_free(const char *old_name)
+{
+}
+
+#endif /* ! CONFIG_INOTIFY */
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_FS_NOTIFY_H */
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 8d6bf608b199..7c7400137e97 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -12,8 +12,8 @@ struct vm_area_struct;
* GFP bitmasks..
*/
/* Zone modifiers in GFP_ZONEMASK (see linux/mmzone.h - low two bits) */
-#define __GFP_DMA 0x01
-#define __GFP_HIGHMEM 0x02
+#define __GFP_DMA 0x01u
+#define __GFP_HIGHMEM 0x02u
/*
* Action modifiers - doesn't change the zoning
diff --git a/include/linux/hardirq.h b/include/linux/hardirq.h
index 8336dba18971..5912874ca83c 100644
--- a/include/linux/hardirq.h
+++ b/include/linux/hardirq.h
@@ -2,6 +2,7 @@
#define LINUX_HARDIRQ_H
#include <linux/config.h>
+#include <linux/preempt.h>
#include <linux/smp_lock.h>
#include <asm/hardirq.h>
#include <asm/system.h>
diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h
index ed2927ef1ff7..df695e9ae327 100644
--- a/include/linux/hdlc.h
+++ b/include/linux/hdlc.h
@@ -242,8 +242,8 @@ static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
}
-static __inline__ unsigned short hdlc_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb,
+ struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 2a7e6c65c882..6bece9280eb7 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -28,6 +28,7 @@ static inline void *kmap(struct page *page)
#define kmap_atomic(page, idx) page_address(page)
#define kunmap_atomic(addr, idx) do { } while (0)
+#define kmap_atomic_pfn(pfn, idx) page_address(pfn_to_page(pfn))
#define kmap_atomic_to_page(ptr) virt_to_page(ptr)
#endif /* CONFIG_HIGHMEM */
diff --git a/include/linux/i2c-dev.h b/include/linux/i2c-dev.h
index d228230ffe5d..541695679762 100644
--- a/include/linux/i2c-dev.h
+++ b/include/linux/i2c-dev.h
@@ -25,6 +25,7 @@
#define _LINUX_I2C_DEV_H
#include <linux/types.h>
+#include <linux/compiler.h>
/* Some IOCTL commands are defined in <linux/i2c.h> */
/* Note: 10-bit addresses are NOT supported! */
diff --git a/include/linux/i2o-dev.h b/include/linux/i2o-dev.h
index ef7f644dd873..36fd18cdad28 100644
--- a/include/linux/i2o-dev.h
+++ b/include/linux/i2o-dev.h
@@ -24,6 +24,13 @@
#define MAX_I2O_CONTROLLERS 32
//#include <linux/ioctl.h>
+#ifndef __KERNEL__
+
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+#endif /* __KERNEL__ */
/*
* I2O Control IOCTLs and structures
@@ -113,6 +120,10 @@ struct i2o_evt_get {
int lost;
};
+typedef struct i2o_sg_io_hdr {
+ unsigned int flags; /* see I2O_DPT_SG_IO_FLAGS */
+} i2o_sg_io_hdr_t;
+
/**************************************************************************
* HRT related constants and structures
**************************************************************************/
@@ -126,14 +137,6 @@ struct i2o_evt_get {
#define I2O_BUS_CARDBUS 7
#define I2O_BUS_UNKNOWN 0x80
-#ifndef __KERNEL__
-
-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
-
-#endif /* __KERNEL__ */
-
typedef struct _i2o_pci_bus {
u8 PciFunctionNumber;
u8 PciDeviceNumber;
@@ -333,7 +336,7 @@ typedef struct _i2o_status_block {
#define I2O_CLASS_ATE_PERIPHERAL 0x061
#define I2O_CLASS_FLOPPY_CONTROLLER 0x070
#define I2O_CLASS_FLOPPY_DEVICE 0x071
-#define I2O_CLASS_BUS_ADAPTER_PORT 0x080
+#define I2O_CLASS_BUS_ADAPTER 0x080
#define I2O_CLASS_PEER_TRANSPORT_AGENT 0x090
#define I2O_CLASS_PEER_TRANSPORT 0x091
#define I2O_CLASS_END 0xfff
@@ -399,4 +402,26 @@ typedef struct _i2o_status_block {
#define ADAPTER_STATE_FAILED 0x10
#define ADAPTER_STATE_FAULTED 0x11
+/*
+ * Software module types
+ */
+#define I2O_SOFTWARE_MODULE_IRTOS 0x11
+#define I2O_SOFTWARE_MODULE_IOP_PRIVATE 0x22
+#define I2O_SOFTWARE_MODULE_IOP_CONFIG 0x23
+
+/*
+ * Vendors
+ */
+#define I2O_VENDOR_DPT 0x001b
+
+/*
+ * DPT / Adaptec specific values for i2o_sg_io_hdr flags.
+ */
+#define I2O_DPT_SG_FLAG_INTERPRET 0x00010000
+#define I2O_DPT_SG_FLAG_PHYSICAL 0x00020000
+
+#define I2O_DPT_FLASH_FRAG_SIZE 0x10000
+#define I2O_DPT_FLASH_READ 0x0101
+#define I2O_DPT_FLASH_WRITE 0x0102
+
#endif /* _I2O_DEV_H */
diff --git a/include/linux/i2o.h b/include/linux/i2o.h
index ea9a3ad4b67f..bdc286ec947c 100644
--- a/include/linux/i2o.h
+++ b/include/linux/i2o.h
@@ -119,12 +119,21 @@ struct i2o_driver {
};
/*
- * Contains all information which are necessary for DMA operations
+ * Contains DMA mapped address information
*/
struct i2o_dma {
void *virt;
dma_addr_t phys;
- u32 len;
+ size_t len;
+};
+
+/*
+ * Contains IO mapped address information
+ */
+struct i2o_io {
+ void __iomem *virt;
+ unsigned long phys;
+ unsigned long len;
};
/*
@@ -147,28 +156,25 @@ struct i2o_controller {
struct pci_dev *pdev; /* PCI device */
- unsigned int short_req:1; /* use small block sizes */
+ unsigned int promise:1; /* Promise controller */
+ unsigned int adaptec:1; /* DPT / Adaptec controller */
+ unsigned int raptor:1; /* split bar */
unsigned int no_quiesce:1; /* dont quiesce before reset */
- unsigned int raptor:1; /* split bar */
- unsigned int promise:1; /* Promise controller */
-
-#ifdef CONFIG_MTRR
- int mtrr_reg0;
- int mtrr_reg1;
-#endif
+ unsigned int short_req:1; /* use small block sizes */
+ unsigned int limit_sectors:1; /* limit number of sectors / request */
+ unsigned int pae_support:1; /* controller has 64-bit SGL support */
struct list_head devices; /* list of I2O devices */
-
- struct notifier_block *event_notifer; /* Events */
- atomic_t users;
struct list_head list; /* Controller list */
- void __iomem *post_port; /* Inbout port address */
- void __iomem *reply_port; /* Outbound port address */
- void __iomem *irq_mask; /* Interrupt register address */
+
+ void __iomem *in_port; /* Inbout port address */
+ void __iomem *out_port; /* Outbound port address */
+ void __iomem *irq_status; /* Interrupt status register address */
+ void __iomem *irq_mask; /* Interrupt mask register address */
/* Dynamic LCT related data */
- struct i2o_dma status; /* status of IOP */
+ struct i2o_dma status; /* IOP status block */
struct i2o_dma hrt; /* HW Resource Table */
i2o_lct *lct; /* Logical Config Table */
@@ -176,21 +182,19 @@ struct i2o_controller {
struct semaphore lct_lock; /* Lock for LCT updates */
struct i2o_dma status_block; /* IOP status block */
- struct i2o_dma base; /* controller messaging unit */
- struct i2o_dma in_queue; /* inbound message queue Host->IOP */
+ struct i2o_io base; /* controller messaging unit */
+ struct i2o_io in_queue; /* inbound message queue Host->IOP */
struct i2o_dma out_queue; /* outbound message queue IOP->Host */
- unsigned int battery:1; /* Has a battery backup */
+ unsigned int battery:1; /* Has a battery backup */
unsigned int io_alloc:1; /* An I/O resource was allocated */
unsigned int mem_alloc:1; /* A memory resource was allocated */
struct resource io_resource; /* I/O resource allocated to the IOP */
struct resource mem_resource; /* Mem resource allocated to the IOP */
- struct proc_dir_entry *proc_entry; /* /proc dir */
-
- struct list_head bus_list; /* list of busses on IOP */
struct device device;
+ struct class_device classdev; /* I2O controller class */
struct i2o_device *exec; /* Executive */
#if BITS_PER_LONG == 64
spinlock_t context_list_lock; /* lock for context_list */
@@ -241,9 +245,10 @@ struct i2o_sys_tbl {
extern struct list_head i2o_controllers;
/* Message functions */
-static inline u32 i2o_msg_get(struct i2o_controller *, struct i2o_message __iomem **);
-extern u32 i2o_msg_get_wait(struct i2o_controller *, struct i2o_message __iomem **,
- int);
+static inline u32 i2o_msg_get(struct i2o_controller *,
+ struct i2o_message __iomem **);
+extern u32 i2o_msg_get_wait(struct i2o_controller *,
+ struct i2o_message __iomem **, int);
static inline void i2o_msg_post(struct i2o_controller *, u32);
static inline int i2o_msg_post_wait(struct i2o_controller *, u32,
unsigned long);
@@ -252,15 +257,6 @@ extern int i2o_msg_post_wait_mem(struct i2o_controller *, u32, unsigned long,
extern void i2o_msg_nop(struct i2o_controller *, u32);
static inline void i2o_flush_reply(struct i2o_controller *, u32);
-/* DMA handling functions */
-static inline int i2o_dma_alloc(struct device *, struct i2o_dma *, size_t,
- unsigned int);
-static inline void i2o_dma_free(struct device *, struct i2o_dma *);
-int i2o_dma_realloc(struct device *, struct i2o_dma *, size_t, unsigned int);
-
-static inline int i2o_dma_map(struct device *, struct i2o_dma *);
-static inline void i2o_dma_unmap(struct device *, struct i2o_dma *);
-
/* IOP functions */
extern int i2o_status_get(struct i2o_controller *);
@@ -285,6 +281,16 @@ static inline u32 i2o_ptr_high(void *ptr)
{
return (u32) ((u64) ptr >> 32);
};
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+ return (u32) (u64) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+ return (u32) ((u64) dma_addr >> 32);
+};
#else
static inline u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
{
@@ -315,8 +321,246 @@ static inline u32 i2o_ptr_high(void *ptr)
{
return 0;
};
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+ return (u32) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+ return 0;
+};
#endif
+/**
+ * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ * @c: I2O controller for which the calculation should be done
+ * @body_size: maximum body size used for message in 32-bit words.
+ *
+ * Return the maximum number of SG elements in a SG list.
+ */
+static inline u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ u16 sg_count =
+ (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+ body_size;
+
+ if (c->pae_support) {
+ /*
+ * for 64-bit a SG attribute element must be added and each
+ * SG element needs 12 bytes instead of 8.
+ */
+ sg_count -= 2;
+ sg_count /= 3;
+ } else
+ sg_count /= 2;
+
+ if (c->short_req && (sg_count > 8))
+ sg_count = 8;
+
+ return sg_count;
+};
+
+/**
+ * i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ * @c: I2O controller
+ * @ptr: pointer to the data which should be mapped
+ * @size: size of data in bytes
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ * SG list if the allocation was successful.
+ *
+ * Returns DMA address which must be checked for failures using
+ * dma_mapping_error().
+ */
+static inline dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+ size_t size,
+ enum dma_data_direction direction,
+ u32 __iomem ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 __iomem *mptr = *sg_ptr;
+ dma_addr_t dma_addr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0xd4000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0xd0000000;
+ break;
+ default:
+ return 0;
+ }
+
+ dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+ if (!dma_mapping_error(dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ writel(0x7C020002, mptr++);
+ writel(PAGE_SIZE, mptr++);
+ }
+#endif
+
+ writel(sg_flags | size, mptr++);
+ writel(i2o_dma_low(dma_addr), mptr++);
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ writel(i2o_dma_high(dma_addr), mptr++);
+#endif
+ *sg_ptr = mptr;
+ }
+ return dma_addr;
+};
+
+/**
+ * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ * @c: I2O controller
+ * @sg: SG list to be mapped
+ * @sg_count: number of elements in the SG list
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ * list if the allocation was successful.
+ *
+ * Returns 0 on failure or 1 on success.
+ */
+static inline int i2o_dma_map_sg(struct i2o_controller *c,
+ struct scatterlist *sg, int sg_count,
+ enum dma_data_direction direction,
+ u32 __iomem ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 __iomem *mptr = *sg_ptr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0x14000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0x10000000;
+ break;
+ default:
+ return 0;
+ }
+
+ sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+ if (!sg_count)
+ return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ writel(0x7C020002, mptr++);
+ writel(PAGE_SIZE, mptr++);
+ }
+#endif
+
+ while (sg_count-- > 0) {
+ if (!sg_count)
+ sg_flags |= 0xC0000000;
+ writel(sg_flags | sg_dma_len(sg), mptr++);
+ writel(i2o_dma_low(sg_dma_address(sg)), mptr++);
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ writel(i2o_dma_high(sg_dma_address(sg)), mptr++);
+#endif
+ sg++;
+ }
+ *sg_ptr = mptr;
+
+ return 1;
+};
+
+/**
+ * i2o_dma_alloc - Allocate DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which should get the DMA buffer
+ * @len: length of the new DMA memory
+ * @gfp_mask: GFP mask
+ *
+ * Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ * Returns 0 on success or -ENOMEM on failure.
+ */
+static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
+ size_t len, unsigned int gfp_mask)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int dma_64 = 0;
+
+ if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_64BIT_MASK)) {
+ dma_64 = 1;
+ if (pci_set_dma_mask(pdev, DMA_32BIT_MASK))
+ return -ENOMEM;
+ }
+
+ addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
+
+ if ((sizeof(dma_addr_t) > 4) && dma_64)
+ if (pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+ printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+
+ if (!addr->virt)
+ return -ENOMEM;
+
+ memset(addr->virt, 0, len);
+ addr->len = len;
+
+ return 0;
+};
+
+/**
+ * i2o_dma_free - Free DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which contains the DMA buffer
+ *
+ * Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+ if (addr->virt) {
+ if (addr->phys)
+ dma_free_coherent(dev, addr->len, addr->virt,
+ addr->phys);
+ else
+ kfree(addr->virt);
+ addr->virt = NULL;
+ }
+};
+
+/**
+ * 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.
+ */
+static inline 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 driver (OSM) functions */
extern int i2o_driver_register(struct i2o_driver *);
extern void i2o_driver_unregister(struct i2o_driver *);
@@ -385,49 +629,11 @@ extern int i2o_device_claim_release(struct i2o_device *);
/* Exec OSM functions */
extern int i2o_exec_lct_get(struct i2o_controller *);
-/* device to i2o_device and driver to i2o_driver convertion functions */
+/* device / driver / kobject conversion functions */
#define to_i2o_driver(drv) container_of(drv,struct i2o_driver, driver)
#define to_i2o_device(dev) container_of(dev, struct i2o_device, device)
-
-/*
- * Messenger inlines
- */
-static inline u32 I2O_POST_READ32(struct i2o_controller *c)
-{
- rmb();
- return readl(c->post_port);
-};
-
-static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 val)
-{
- wmb();
- writel(val, c->post_port);
-};
-
-static inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
-{
- rmb();
- return readl(c->reply_port);
-};
-
-static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 val)
-{
- wmb();
- writel(val, c->reply_port);
-};
-
-static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
-{
- rmb();
- return readl(c->irq_mask);
-};
-
-static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 val)
-{
- wmb();
- writel(val, c->irq_mask);
- wmb();
-};
+#define to_i2o_controller(dev) container_of(dev, struct i2o_controller, device)
+#define kobj_to_i2o_device(kobj) to_i2o_device(container_of(kobj, struct device, kobj))
/**
* i2o_msg_get - obtain an I2O message from the IOP
@@ -443,11 +649,11 @@ static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 val)
* available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
*/
static inline u32 i2o_msg_get(struct i2o_controller *c,
- struct i2o_message __iomem **msg)
+ struct i2o_message __iomem ** msg)
{
- u32 m;
+ u32 m = readl(c->in_port);
- if ((m = I2O_POST_READ32(c)) != I2O_QUEUE_EMPTY)
+ if (m != I2O_QUEUE_EMPTY)
*msg = c->in_queue.virt + m;
return m;
@@ -462,7 +668,7 @@ static inline u32 i2o_msg_get(struct i2o_controller *c,
*/
static inline void i2o_msg_post(struct i2o_controller *c, u32 m)
{
- I2O_POST_WRITE32(c, m);
+ writel(m, c->in_port);
};
/**
@@ -491,12 +697,10 @@ static inline int i2o_msg_post_wait(struct i2o_controller *c, u32 m,
* The I2O controller must be informed that the reply message is not needed
* anymore. If you forget to flush the reply, the message frame can't be
* used by the controller anymore and is therefore lost.
- *
- * FIXME: is there a timeout after which the controller reuse the message?
*/
static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
{
- I2O_REPLY_WRITE32(c, m);
+ writel(m, c->out_port);
};
/**
@@ -530,97 +734,13 @@ static inline struct i2o_message *i2o_msg_out_to_virt(struct i2o_controller *c,
* work for receive side messages as they are kmalloc objects
* in a different pool.
*/
-static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct i2o_controller *c,
- u32 m)
+static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct
+ i2o_controller *c,
+ u32 m)
{
return c->in_queue.virt + m;
};
-/**
- * i2o_dma_alloc - Allocate DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should get the DMA buffer
- * @len: length of the new DMA memory
- * @gfp_mask: GFP mask
- *
- * Allocate a coherent DMA memory and write the pointers into addr.
- *
- * Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr,
- size_t len, unsigned int gfp_mask)
-{
- addr->virt = dma_alloc_coherent(dev, len, &addr->phys, gfp_mask);
- if (!addr->virt)
- return -ENOMEM;
-
- memset(addr->virt, 0, len);
- addr->len = len;
-
- return 0;
-};
-
-/**
- * i2o_dma_free - Free DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which contains the DMA buffer
- *
- * Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-static inline void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
- if (addr->virt) {
- if (addr->phys)
- dma_free_coherent(dev, addr->len, addr->virt,
- addr->phys);
- else
- kfree(addr->virt);
- addr->virt = NULL;
- }
-};
-
-/**
- * i2o_dma_map - Map the memory to DMA
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should be mapped
- *
- * Map the memory in addr->virt to coherent DMA memory and write the
- * physical address into addr->phys.
- *
- * Returns 0 on success or -ENOMEM on failure.
- */
-static inline int i2o_dma_map(struct device *dev, struct i2o_dma *addr)
-{
- if (!addr->virt)
- return -EFAULT;
-
- if (!addr->phys)
- addr->phys = dma_map_single(dev, addr->virt, addr->len,
- DMA_BIDIRECTIONAL);
- if (!addr->phys)
- return -ENOMEM;
-
- return 0;
-};
-
-/**
- * i2o_dma_unmap - Unmap the DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should be unmapped
- *
- * Unmap the memory in addr->virt from DMA memory.
- */
-static inline void i2o_dma_unmap(struct device *dev, struct i2o_dma *addr)
-{
- if (!addr->virt)
- return;
-
- if (addr->phys) {
- dma_unmap_single(dev, addr->phys, addr->len, DMA_BIDIRECTIONAL);
- addr->phys = 0;
- }
-};
-
/*
* Endian handling wrapped into the macro - keeps the core code
* cleaner.
@@ -773,6 +893,14 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define I2O_CMD_SCSI_BUSRESET 0x27
/*
+ * Bus Adapter Class
+ */
+#define I2O_CMD_BUS_ADAPTER_RESET 0x85
+#define I2O_CMD_BUS_RESET 0x87
+#define I2O_CMD_BUS_SCAN 0x89
+#define I2O_CMD_BUS_QUIESCE 0x8b
+
+/*
* Random Block Storage Class
*/
#define I2O_CMD_BLOCK_READ 0x30
@@ -784,7 +912,7 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define I2O_CMD_BLOCK_MEJECT 0x43
#define I2O_CMD_BLOCK_POWER 0x70
-#define I2O_PRIVATE_MSG 0xFF
+#define I2O_CMD_PRIVATE 0xFF
/* Command status values */
@@ -922,7 +1050,7 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define I2OVER15 0x0001
#define I2OVER20 0x0002
-/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
+/* Default is 1.5 */
#define I2OVERSION I2OVER15
#define SGL_OFFSET_0 I2OVERSION
@@ -933,9 +1061,9 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define SGL_OFFSET_8 (0x0080 | I2OVERSION)
#define SGL_OFFSET_9 (0x0090 | I2OVERSION)
#define SGL_OFFSET_10 (0x00A0 | I2OVERSION)
-
-#define TRL_OFFSET_5 (0x0050 | I2OVERSION)
-#define TRL_OFFSET_6 (0x0060 | I2OVERSION)
+#define SGL_OFFSET_11 (0x00B0 | I2OVERSION)
+#define SGL_OFFSET_12 (0x00C0 | I2OVERSION)
+#define SGL_OFFSET(x) (((x)<<4) | I2OVERSION)
/* Transaction Reply Lists (TRL) Control Word structure */
#define TRL_SINGLE_FIXED_LENGTH 0x00
@@ -962,17 +1090,13 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define ELEVEN_WORD_MSG_SIZE 0x000B0000
#define I2O_MESSAGE_SIZE(x) ((x)<<16)
-/* Special TID Assignments */
-
+/* special TID assignments */
#define ADAPTER_TID 0
#define HOST_TID 1
-#define MSG_FRAME_SIZE 128 /* i2o_scsi assumes >= 32 */
-#define REPLY_FRAME_SIZE 17
-#define SG_TABLESIZE 30
-#define NMBR_MSG_FRAMES 128
-
-#define MSG_POOL_SIZE (MSG_FRAME_SIZE*NMBR_MSG_FRAMES*sizeof(u32))
+/* outbound queue defines */
+#define I2O_MAX_OUTBOUND_MSG_FRAMES 128
+#define I2O_OUTBOUND_MSG_FRAME_SIZE 128 /* in 32-bit words */
#define I2O_POST_WAIT_OK 0
#define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT
@@ -993,11 +1117,10 @@ extern void i2o_debug_state(struct i2o_controller *c);
#define I2O_HRT_GET_TRIES 3
#define I2O_LCT_GET_TRIES 3
-/* request queue sizes */
+/* defines for max_sectors and max_phys_segments */
#define I2O_MAX_SECTORS 1024
-#define I2O_MAX_SEGMENTS 128
-
-#define I2O_REQ_MEMPOOL_SIZE 32
+#define I2O_MAX_SECTORS_LIMITED 256
+#define I2O_MAX_PHYS_SEGMENTS MAX_PHYS_SEGMENTS
#endif /* __KERNEL__ */
#endif /* _I2O_H */
diff --git a/include/linux/if_bonding.h b/include/linux/if_bonding.h
index 57024ce2c74f..84598fa2e9de 100644
--- a/include/linux/if_bonding.h
+++ b/include/linux/if_bonding.h
@@ -35,6 +35,9 @@
*
* 2003/12/01 - Shmulik Hen <shmulik.hen at intel dot com>
* - Code cleanup and style changes
+ *
+ * 2005/05/05 - Jason Gabler <jygabler at lbl dot gov>
+ * - added definitions for various XOR hashing policies
*/
#ifndef _LINUX_IF_BONDING_H
@@ -80,6 +83,10 @@
#define BOND_DEFAULT_MAX_BONDS 1 /* Default maximum number of devices to support */
+/* hashing types */
+#define BOND_XMIT_POLICY_LAYER2 0 /* layer 2 (MAC only), default */
+#define BOND_XMIT_POLICY_LAYER34 1 /* layer 3+4 (IP ^ MAC) */
+
typedef struct ifbond {
__s32 bond_mode;
__s32 num_slaves;
diff --git a/include/linux/if_shaper.h b/include/linux/if_shaper.h
index 004e6f09a6e2..68c896a36a34 100644
--- a/include/linux/if_shaper.h
+++ b/include/linux/if_shaper.h
@@ -23,7 +23,7 @@ struct shaper
__u32 shapeclock;
unsigned long recovery; /* Time we can next clock a packet out on
an empty queue */
- struct semaphore sem;
+ spinlock_t lock;
struct net_device_stats stats;
struct net_device *dev;
int (*hard_start_xmit) (struct sk_buff *skb,
diff --git a/include/linux/igmp.h b/include/linux/igmp.h
index 390e760a96d3..0c31ef0b5bad 100644
--- a/include/linux/igmp.h
+++ b/include/linux/igmp.h
@@ -148,7 +148,6 @@ struct ip_sf_socklist
struct ip_mc_socklist
{
struct ip_mc_socklist *next;
- int count;
struct ip_mreqn multi;
unsigned int sfmode; /* MCAST_{INCLUDE,EXCLUDE} */
struct ip_sf_socklist *sflist;
diff --git a/include/linux/in6.h b/include/linux/in6.h
index f8256c582845..dcf5720ffcbb 100644
--- a/include/linux/in6.h
+++ b/include/linux/in6.h
@@ -156,7 +156,7 @@ struct in6_flowlabel_req
#define IPV6_CHECKSUM 7
#define IPV6_HOPLIMIT 8
#define IPV6_NEXTHOP 9
-#define IPV6_AUTHHDR 10
+#define IPV6_AUTHHDR 10 /* obsolete */
#define IPV6_FLOWINFO 11
#define IPV6_UNICAST_HOPS 16
diff --git a/include/linux/init.h b/include/linux/init.h
index 05c83e0521ca..59008c3826cf 100644
--- a/include/linux/init.h
+++ b/include/linux/init.h
@@ -229,6 +229,18 @@ void __init parse_early_param(void);
#define __devexitdata __exitdata
#endif
+#ifdef CONFIG_HOTPLUG_CPU
+#define __cpuinit
+#define __cpuinitdata
+#define __cpuexit
+#define __cpuexitdata
+#else
+#define __cpuinit __init
+#define __cpuinitdata __initdata
+#define __cpuexit __exit
+#define __cpuexitdata __exitdata
+#endif
+
/* Functions marked as __devexit may be discarded at kernel link time, depending
on config options. Newer versions of binutils detect references from
retained sections to discarded sections and flag an error. Pointers to
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index a6a8c1a38d5e..c727c195a91a 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -81,6 +81,7 @@ extern struct group_info init_groups;
.mm = NULL, \
.active_mm = &init_mm, \
.run_list = LIST_HEAD_INIT(tsk.run_list), \
+ .ioprio = 0, \
.time_slice = HZ, \
.tasks = LIST_HEAD_INIT(tsk.tasks), \
.ptrace_children= LIST_HEAD_INIT(tsk.ptrace_children), \
@@ -108,9 +109,9 @@ extern struct group_info init_groups;
.blocked = {{0}}, \
.alloc_lock = SPIN_LOCK_UNLOCKED, \
.proc_lock = SPIN_LOCK_UNLOCKED, \
- .switch_lock = SPIN_LOCK_UNLOCKED, \
.journal_info = NULL, \
.cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \
+ .fs_excl = ATOMIC_INIT(0), \
}
diff --git a/include/linux/inotify.h b/include/linux/inotify.h
new file mode 100644
index 000000000000..a40c2bf0408e
--- /dev/null
+++ b/include/linux/inotify.h
@@ -0,0 +1,108 @@
+/*
+ * Inode based directory notification for Linux
+ *
+ * Copyright (C) 2005 John McCutchan
+ */
+
+#ifndef _LINUX_INOTIFY_H
+#define _LINUX_INOTIFY_H
+
+#include <linux/types.h>
+
+/*
+ * struct inotify_event - structure read from the inotify device for each event
+ *
+ * When you are watching a directory, you will receive the filename for events
+ * such as IN_CREATE, IN_DELETE, IN_OPEN, IN_CLOSE, ..., relative to the wd.
+ */
+struct inotify_event {
+ __s32 wd; /* watch descriptor */
+ __u32 mask; /* watch mask */
+ __u32 cookie; /* cookie to synchronize two events */
+ __u32 len; /* length (including nulls) of name */
+ char name[0]; /* stub for possible name */
+};
+
+/* the following are legal, implemented events that user-space can watch for */
+#define IN_ACCESS 0x00000001 /* File was accessed */
+#define IN_MODIFY 0x00000002 /* File was modified */
+#define IN_ATTRIB 0x00000004 /* Metadata changed */
+#define IN_CLOSE_WRITE 0x00000008 /* Writtable file was closed */
+#define IN_CLOSE_NOWRITE 0x00000010 /* Unwrittable file closed */
+#define IN_OPEN 0x00000020 /* File was opened */
+#define IN_MOVED_FROM 0x00000040 /* File was moved from X */
+#define IN_MOVED_TO 0x00000080 /* File was moved to Y */
+#define IN_CREATE 0x00000100 /* Subfile was created */
+#define IN_DELETE 0x00000200 /* Subfile was deleted */
+#define IN_DELETE_SELF 0x00000400 /* Self was deleted */
+
+/* the following are legal events. they are sent as needed to any watch */
+#define IN_UNMOUNT 0x00002000 /* Backing fs was unmounted */
+#define IN_Q_OVERFLOW 0x00004000 /* Event queued overflowed */
+#define IN_IGNORED 0x00008000 /* File was ignored */
+
+/* helper events */
+#define IN_CLOSE (IN_CLOSE_WRITE | IN_CLOSE_NOWRITE) /* close */
+#define IN_MOVE (IN_MOVED_FROM | IN_MOVED_TO) /* moves */
+
+/* special flags */
+#define IN_ISDIR 0x40000000 /* event occurred against dir */
+#define IN_ONESHOT 0x80000000 /* only send event once */
+
+/*
+ * All of the events - we build the list by hand so that we can add flags in
+ * the future and not break backward compatibility. Apps will get only the
+ * events that they originally wanted. Be sure to add new events here!
+ */
+#define IN_ALL_EVENTS (IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE | \
+ IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM | \
+ IN_MOVED_TO | IN_DELETE | IN_CREATE | IN_DELETE_SELF)
+
+#ifdef __KERNEL__
+
+#include <linux/dcache.h>
+#include <linux/fs.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_INOTIFY
+
+extern void inotify_inode_queue_event(struct inode *, __u32, __u32,
+ const char *);
+extern void inotify_dentry_parent_queue_event(struct dentry *, __u32, __u32,
+ const char *);
+extern void inotify_unmount_inodes(struct list_head *);
+extern void inotify_inode_is_dead(struct inode *);
+extern u32 inotify_get_cookie(void);
+
+#else
+
+static inline void inotify_inode_queue_event(struct inode *inode,
+ __u32 mask, __u32 cookie,
+ const char *filename)
+{
+}
+
+static inline void inotify_dentry_parent_queue_event(struct dentry *dentry,
+ __u32 mask, __u32 cookie,
+ const char *filename)
+{
+}
+
+static inline void inotify_unmount_inodes(struct list_head *list)
+{
+}
+
+static inline void inotify_inode_is_dead(struct inode *inode)
+{
+}
+
+static inline u32 inotify_get_cookie(void)
+{
+ return 0;
+}
+
+#endif /* CONFIG_INOTIFY */
+
+#endif /* __KERNEL __ */
+
+#endif /* _LINUX_INOTIFY_H */
diff --git a/include/linux/input.h b/include/linux/input.h
index 9d9598ed760d..b9cc0ac71f44 100644
--- a/include/linux/input.h
+++ b/include/linux/input.h
@@ -859,6 +859,10 @@ struct input_dev {
int (*erase_effect)(struct input_dev *dev, int effect_id);
struct input_handle *grab;
+
+ struct semaphore sem; /* serializes open and close operations */
+ unsigned int users;
+
struct device *dev;
struct list_head h_list;
diff --git a/include/linux/ioprio.h b/include/linux/ioprio.h
new file mode 100644
index 000000000000..88d5961f7a3f
--- /dev/null
+++ b/include/linux/ioprio.h
@@ -0,0 +1,85 @@
+#ifndef IOPRIO_H
+#define IOPRIO_H
+
+#include <linux/sched.h>
+
+/*
+ * Gives us 8 prio classes with 13-bits of data for each class
+ */
+#define IOPRIO_BITS (16)
+#define IOPRIO_CLASS_SHIFT (13)
+#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1)
+
+#define IOPRIO_PRIO_CLASS(mask) ((mask) >> IOPRIO_CLASS_SHIFT)
+#define IOPRIO_PRIO_DATA(mask) ((mask) & IOPRIO_PRIO_MASK)
+#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data)
+
+#define ioprio_valid(mask) (IOPRIO_PRIO_CLASS((mask)) != IOPRIO_CLASS_NONE)
+
+/*
+ * These are the io priority groups as implemented by CFQ. RT is the realtime
+ * class, it always gets premium service. BE is the best-effort scheduling
+ * class, the default for any process. IDLE is the idle scheduling class, it
+ * is only served when no one else is using the disk.
+ */
+enum {
+ IOPRIO_CLASS_NONE,
+ IOPRIO_CLASS_RT,
+ IOPRIO_CLASS_BE,
+ IOPRIO_CLASS_IDLE,
+};
+
+/*
+ * 8 best effort priority levels are supported
+ */
+#define IOPRIO_BE_NR (8)
+
+enum {
+ IOPRIO_WHO_PROCESS = 1,
+ IOPRIO_WHO_PGRP,
+ IOPRIO_WHO_USER,
+};
+
+/*
+ * if process has set io priority explicitly, use that. if not, convert
+ * the cpu scheduler nice value to an io priority
+ */
+#define IOPRIO_NORM (4)
+static inline int task_ioprio(struct task_struct *task)
+{
+ WARN_ON(!ioprio_valid(task->ioprio));
+ return IOPRIO_PRIO_DATA(task->ioprio);
+}
+
+static inline int task_nice_ioprio(struct task_struct *task)
+{
+ return (task_nice(task) + 20) / 5;
+}
+
+/*
+ * For inheritance, return the highest of the two given priorities
+ */
+static inline int ioprio_best(unsigned short aprio, unsigned short bprio)
+{
+ unsigned short aclass = IOPRIO_PRIO_CLASS(aprio);
+ unsigned short bclass = IOPRIO_PRIO_CLASS(bprio);
+
+ if (!ioprio_valid(aprio))
+ return bprio;
+ if (!ioprio_valid(bprio))
+ return aprio;
+
+ if (aclass == IOPRIO_CLASS_NONE)
+ aclass = IOPRIO_CLASS_BE;
+ if (bclass == IOPRIO_CLASS_NONE)
+ bclass = IOPRIO_CLASS_BE;
+
+ if (aclass == bclass)
+ return min(aprio, bprio);
+ if (aclass > bclass)
+ return bprio;
+ else
+ return aprio;
+}
+
+#endif
diff --git a/include/linux/ipmi.h b/include/linux/ipmi.h
index 2ec265e1045f..596ca6130159 100644
--- a/include/linux/ipmi.h
+++ b/include/linux/ipmi.h
@@ -209,6 +209,11 @@ struct kernel_ipmi_msg
#include <linux/list.h>
#include <linux/module.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+extern struct proc_dir_entry *proc_ipmi_root;
+#endif /* CONFIG_PROC_FS */
+
/* Opaque type for a IPMI message user. One of these is needed to
send and receive messages. */
typedef struct ipmi_user *ipmi_user_t;
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 7fc1022be9ee..069d3b84d311 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -85,10 +85,10 @@ extern int no_irq_affinity;
extern int noirqdebug_setup(char *str);
extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs,
- struct irqaction *action);
+ struct irqaction *action);
extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs);
-extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret);
-extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret);
+extern void note_interrupt(unsigned int irq, irq_desc_t *desc,
+ int action_ret, struct pt_regs *regs);
extern int can_request_irq(unsigned int irq, unsigned long irqflags);
extern void init_irq_proc(void);
diff --git a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h
index 4afc8d8c2e9e..1e21546622de 100644
--- a/include/linux/jffs2_fs_sb.h
+++ b/include/linux/jffs2_fs_sb.h
@@ -1,4 +1,4 @@
-/* $Id: jffs2_fs_sb.h,v 1.48 2004/11/20 10:41:12 dwmw2 Exp $ */
+/* $Id: jffs2_fs_sb.h,v 1.52 2005/05/19 16:12:17 gleixner Exp $ */
#ifndef _JFFS2_FS_SB
#define _JFFS2_FS_SB
@@ -14,7 +14,8 @@
#include <linux/rwsem.h>
#define JFFS2_SB_FLAG_RO 1
-#define JFFS2_SB_FLAG_MOUNTING 2
+#define JFFS2_SB_FLAG_SCANNING 2 /* Flash scanning is in progress */
+#define JFFS2_SB_FLAG_BUILDING 4 /* File system building is in progress */
struct jffs2_inodirty;
@@ -31,7 +32,7 @@ struct jffs2_sb_info {
unsigned int flags;
struct task_struct *gc_task; /* GC task struct */
- struct semaphore gc_thread_start; /* GC thread start mutex */
+ struct completion gc_thread_start; /* GC thread start completion */
struct completion gc_thread_exit; /* GC thread exit completion port */
struct semaphore alloc_sem; /* Used to protect all the following
@@ -94,7 +95,7 @@ struct jffs2_sb_info {
to an obsoleted node. I don't like this. Alternatives welcomed. */
struct semaphore erase_free_sem;
-#if defined CONFIG_JFFS2_FS_NAND || defined CONFIG_JFFS2_FS_NOR_ECC
+#ifdef CONFIG_JFFS2_FS_WRITEBUFFER
/* Write-behind buffer for NAND flash */
unsigned char *wbuf;
uint32_t wbuf_ofs;
diff --git a/include/linux/joystick.h b/include/linux/joystick.h
index b7e0ab622cd7..06b9af77eb7f 100644
--- a/include/linux/joystick.h
+++ b/include/linux/joystick.h
@@ -111,18 +111,35 @@ struct js_corr {
#define JS_SET_ALL 8
struct JS_DATA_TYPE {
- int buttons;
- int x;
- int y;
+ __s32 buttons;
+ __s32 x;
+ __s32 y;
};
-struct JS_DATA_SAVE_TYPE {
- int JS_TIMEOUT;
- int BUSY;
- long JS_EXPIRETIME;
- long JS_TIMELIMIT;
+struct JS_DATA_SAVE_TYPE_32 {
+ __s32 JS_TIMEOUT;
+ __s32 BUSY;
+ __s32 JS_EXPIRETIME;
+ __s32 JS_TIMELIMIT;
struct JS_DATA_TYPE JS_SAVE;
struct JS_DATA_TYPE JS_CORR;
};
+struct JS_DATA_SAVE_TYPE_64 {
+ __s32 JS_TIMEOUT;
+ __s32 BUSY;
+ __s64 JS_EXPIRETIME;
+ __s64 JS_TIMELIMIT;
+ struct JS_DATA_TYPE JS_SAVE;
+ struct JS_DATA_TYPE JS_CORR;
+};
+
+#if BITS_PER_LONG == 64
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_64
+#elif BITS_PER_LONG == 32
+#define JS_DATA_SAVE_TYPE JS_DATA_SAVE_TYPE_32
+#else
+#error Unexpected BITS_PER_LONG
+#endif
+
#endif /* _LINUX_JOYSTICK_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index e25b97062ce1..687ba8c9973d 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -58,15 +58,23 @@ struct completion;
* be biten later when the calling function happens to sleep when it is not
* supposed to.
*/
+#ifdef CONFIG_PREEMPT_VOLUNTARY
+extern int cond_resched(void);
+# define might_resched() cond_resched()
+#else
+# define might_resched() do { } while (0)
+#endif
+
#ifdef CONFIG_DEBUG_SPINLOCK_SLEEP
-#define might_sleep() __might_sleep(__FILE__, __LINE__)
-#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
-void __might_sleep(char *file, int line);
+ void __might_sleep(char *file, int line);
+# define might_sleep() \
+ do { __might_sleep(__FILE__, __LINE__); might_resched(); } while (0)
#else
-#define might_sleep() do {} while(0)
-#define might_sleep_if(cond) do {} while (0)
+# define might_sleep() do { might_resched(); } while (0)
#endif
+#define might_sleep_if(cond) do { if (unlikely(cond)) might_sleep(); } while (0)
+
#define abs(x) ({ \
int __x = (x); \
(__x < 0) ? -__x : __x; \
diff --git a/include/linux/kexec.h b/include/linux/kexec.h
new file mode 100644
index 000000000000..c8468472aec0
--- /dev/null
+++ b/include/linux/kexec.h
@@ -0,0 +1,135 @@
+#ifndef LINUX_KEXEC_H
+#define LINUX_KEXEC_H
+
+#ifdef CONFIG_KEXEC
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/linkage.h>
+#include <linux/compat.h>
+#include <asm/kexec.h>
+
+/* Verify architecture specific macros are defined */
+
+#ifndef KEXEC_SOURCE_MEMORY_LIMIT
+#error KEXEC_SOURCE_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_DESTINATION_MEMORY_LIMIT
+#error KEXEC_DESTINATION_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_CONTROL_MEMORY_LIMIT
+#error KEXEC_CONTROL_MEMORY_LIMIT not defined
+#endif
+
+#ifndef KEXEC_CONTROL_CODE_SIZE
+#error KEXEC_CONTROL_CODE_SIZE not defined
+#endif
+
+#ifndef KEXEC_ARCH
+#error KEXEC_ARCH not defined
+#endif
+
+/*
+ * This structure is used to hold the arguments that are used when loading
+ * kernel binaries.
+ */
+
+typedef unsigned long kimage_entry_t;
+#define IND_DESTINATION 0x1
+#define IND_INDIRECTION 0x2
+#define IND_DONE 0x4
+#define IND_SOURCE 0x8
+
+#define KEXEC_SEGMENT_MAX 8
+struct kexec_segment {
+ void __user *buf;
+ size_t bufsz;
+ unsigned long mem; /* User space sees this as a (void *) ... */
+ size_t memsz;
+};
+
+#ifdef CONFIG_COMPAT
+struct compat_kexec_segment {
+ compat_uptr_t buf;
+ compat_size_t bufsz;
+ compat_ulong_t mem; /* User space sees this as a (void *) ... */
+ compat_size_t memsz;
+};
+#endif
+
+struct kimage {
+ kimage_entry_t head;
+ kimage_entry_t *entry;
+ kimage_entry_t *last_entry;
+
+ unsigned long destination;
+
+ unsigned long start;
+ struct page *control_code_page;
+
+ unsigned long nr_segments;
+ struct kexec_segment segment[KEXEC_SEGMENT_MAX];
+
+ struct list_head control_pages;
+ struct list_head dest_pages;
+ struct list_head unuseable_pages;
+
+ /* Address of next control page to allocate for crash kernels. */
+ unsigned long control_page;
+
+ /* Flags to indicate special processing */
+ unsigned int type : 1;
+#define KEXEC_TYPE_DEFAULT 0
+#define KEXEC_TYPE_CRASH 1
+};
+
+
+
+/* kexec interface functions */
+extern NORET_TYPE void machine_kexec(struct kimage *image) ATTRIB_NORET;
+extern int machine_kexec_prepare(struct kimage *image);
+extern void machine_kexec_cleanup(struct kimage *image);
+extern asmlinkage long sys_kexec_load(unsigned long entry,
+ unsigned long nr_segments,
+ struct kexec_segment __user *segments,
+ unsigned long flags);
+#ifdef CONFIG_COMPAT
+extern asmlinkage long compat_sys_kexec_load(unsigned long entry,
+ unsigned long nr_segments,
+ struct compat_kexec_segment __user *segments,
+ unsigned long flags);
+#endif
+extern struct page *kimage_alloc_control_pages(struct kimage *image,
+ unsigned int order);
+extern void crash_kexec(struct pt_regs *);
+int kexec_should_crash(struct task_struct *);
+extern struct kimage *kexec_image;
+
+#define KEXEC_ON_CRASH 0x00000001
+#define KEXEC_ARCH_MASK 0xffff0000
+
+/* These values match the ELF architecture values.
+ * Unless there is a good reason that should continue to be the case.
+ */
+#define KEXEC_ARCH_DEFAULT ( 0 << 16)
+#define KEXEC_ARCH_386 ( 3 << 16)
+#define KEXEC_ARCH_X86_64 (62 << 16)
+#define KEXEC_ARCH_PPC (20 << 16)
+#define KEXEC_ARCH_PPC64 (21 << 16)
+#define KEXEC_ARCH_IA_64 (50 << 16)
+#define KEXEC_ARCH_S390 (22 << 16)
+
+#define KEXEC_FLAGS (KEXEC_ON_CRASH) /* List of defined/legal kexec flags */
+
+/* Location of a reserved region to hold the crash kernel.
+ */
+extern struct resource crashk_res;
+
+#else /* !CONFIG_KEXEC */
+struct pt_regs;
+struct task_struct;
+static inline void crash_kexec(struct pt_regs *regs) { }
+static inline int kexec_should_crash(struct task_struct *p) { return 0; }
+#endif /* CONFIG_KEXEC */
+#endif /* LINUX_KEXEC_H */
diff --git a/include/linux/key-ui.h b/include/linux/key-ui.h
index 60cc7b762e78..cc326174a808 100644
--- a/include/linux/key-ui.h
+++ b/include/linux/key-ui.h
@@ -1,4 +1,4 @@
-/* key-ui.h: key userspace interface stuff for use by keyfs
+/* key-ui.h: key userspace interface stuff
*
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
@@ -31,8 +31,10 @@ extern spinlock_t key_serial_lock;
* subscribed
*/
struct keyring_list {
- unsigned maxkeys; /* max keys this list can hold */
- unsigned nkeys; /* number of keys currently held */
+ struct rcu_head rcu; /* RCU deletion hook */
+ unsigned short maxkeys; /* max keys this list can hold */
+ unsigned short nkeys; /* number of keys currently held */
+ unsigned short delkey; /* key to be unlinked by RCU */
struct key *keys[0];
};
@@ -82,8 +84,45 @@ static inline int key_any_permission(const struct key *key, key_perm_t perm)
return kperm != 0;
}
+static inline int key_task_groups_search(struct task_struct *tsk, gid_t gid)
+{
+ int ret;
+
+ task_lock(tsk);
+ ret = groups_search(tsk->group_info, gid);
+ task_unlock(tsk);
+ return ret;
+}
+
+static inline int key_task_permission(const struct key *key,
+ struct task_struct *context,
+ key_perm_t perm)
+{
+ key_perm_t kperm;
+
+ if (key->uid == context->fsuid) {
+ kperm = key->perm >> 16;
+ }
+ else if (key->gid != -1 &&
+ key->perm & KEY_GRP_ALL && (
+ key->gid == context->fsgid ||
+ key_task_groups_search(context, key->gid)
+ )
+ ) {
+ kperm = key->perm >> 8;
+ }
+ else {
+ kperm = key->perm;
+ }
+
+ kperm = kperm & perm & KEY_ALL;
+
+ return kperm == perm;
+
+}
-extern struct key *lookup_user_key(key_serial_t id, int create, int part,
+extern struct key *lookup_user_key(struct task_struct *context,
+ key_serial_t id, int create, int partial,
key_perm_t perm);
extern long join_session_keyring(const char *name);
diff --git a/include/linux/key.h b/include/linux/key.h
index 6aa46d0e812f..970bbd916cf4 100644
--- a/include/linux/key.h
+++ b/include/linux/key.h
@@ -18,7 +18,7 @@
#include <linux/types.h>
#include <linux/list.h>
#include <linux/rbtree.h>
-#include <linux/spinlock.h>
+#include <linux/rcupdate.h>
#include <asm/atomic.h>
#ifdef __KERNEL__
@@ -78,7 +78,6 @@ struct key {
key_serial_t serial; /* key serial number */
struct rb_node serial_node;
struct key_type *type; /* type of key */
- rwlock_t lock; /* examination vs change lock */
struct rw_semaphore sem; /* change vs change sem */
struct key_user *user; /* owner of this key */
time_t expiry; /* time at which key expires (or 0) */
@@ -86,14 +85,10 @@ struct key {
gid_t gid;
key_perm_t perm; /* access permissions */
unsigned short quotalen; /* length added to quota */
- unsigned short datalen; /* payload data length */
- unsigned short flags; /* status flags (change with lock writelocked) */
-#define KEY_FLAG_INSTANTIATED 0x00000001 /* set if key has been instantiated */
-#define KEY_FLAG_DEAD 0x00000002 /* set if key type has been deleted */
-#define KEY_FLAG_REVOKED 0x00000004 /* set if key had been revoked */
-#define KEY_FLAG_IN_QUOTA 0x00000008 /* set if key consumes quota */
-#define KEY_FLAG_USER_CONSTRUCT 0x00000010 /* set if key is being constructed in userspace */
-#define KEY_FLAG_NEGATIVE 0x00000020 /* set if key is negative */
+ unsigned short datalen; /* payload data length
+ * - may not match RCU dereferenced payload
+ * - payload should contain own length
+ */
#ifdef KEY_DEBUGGING
unsigned magic;
@@ -101,6 +96,14 @@ struct key {
#define KEY_DEBUG_MAGIC_X 0xf8e9dacbu
#endif
+ unsigned long flags; /* status flags (change with bitops) */
+#define KEY_FLAG_INSTANTIATED 0 /* set if key has been instantiated */
+#define KEY_FLAG_DEAD 1 /* set if key type has been deleted */
+#define KEY_FLAG_REVOKED 2 /* set if key had been revoked */
+#define KEY_FLAG_IN_QUOTA 3 /* set if key consumes quota */
+#define KEY_FLAG_USER_CONSTRUCT 4 /* set if key is being constructed in userspace */
+#define KEY_FLAG_NEGATIVE 5 /* set if key is negative */
+
/* the description string
* - this is used to match a key against search criteria
* - this should be a printable string
@@ -196,10 +199,12 @@ extern int key_payload_reserve(struct key *key, size_t datalen);
extern int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
- struct key *keyring);
+ struct key *keyring,
+ struct key *instkey);
extern int key_negate_and_link(struct key *key,
unsigned timeout,
- struct key *keyring);
+ struct key *keyring,
+ struct key *instkey);
extern void key_revoke(struct key *key);
extern void key_put(struct key *key);
@@ -242,14 +247,13 @@ extern struct key *keyring_search(struct key *keyring,
struct key_type *type,
const char *description);
-extern struct key *search_process_keyrings(struct key_type *type,
- const char *description);
-
extern int keyring_add_key(struct key *keyring,
struct key *key);
extern struct key *key_lookup(key_serial_t id);
+extern void keyring_replace_payload(struct key *key, void *replacement);
+
#define key_serial(key) ((key) ? (key)->serial : 0)
/*
@@ -268,14 +272,22 @@ extern void key_fsuid_changed(struct task_struct *tsk);
extern void key_fsgid_changed(struct task_struct *tsk);
extern void key_init(void);
+#define __install_session_keyring(tsk, keyring) \
+({ \
+ struct key *old_session = tsk->signal->session_keyring; \
+ tsk->signal->session_keyring = keyring; \
+ old_session; \
+})
+
#else /* CONFIG_KEYS */
#define key_validate(k) 0
#define key_serial(k) 0
-#define key_get(k) NULL
+#define key_get(k) ({ NULL; })
#define key_put(k) do { } while(0)
#define alloc_uid_keyring(u) 0
#define switch_uid_keyring(u) do { } while(0)
+#define __install_session_keyring(t, k) ({ NULL; })
#define copy_keys(f,t) 0
#define copy_thread_group_keys(t) 0
#define exit_keys(t) do { } while(0)
diff --git a/include/linux/keyctl.h b/include/linux/keyctl.h
index 381dedc370a3..8d7c59a29e09 100644
--- a/include/linux/keyctl.h
+++ b/include/linux/keyctl.h
@@ -20,6 +20,16 @@
#define KEY_SPEC_USER_SESSION_KEYRING -5 /* - key ID for UID-session keyring */
#define KEY_SPEC_GROUP_KEYRING -6 /* - key ID for GID-specific keyring */
+/* request-key default keyrings */
+#define KEY_REQKEY_DEFL_NO_CHANGE -1
+#define KEY_REQKEY_DEFL_DEFAULT 0
+#define KEY_REQKEY_DEFL_THREAD_KEYRING 1
+#define KEY_REQKEY_DEFL_PROCESS_KEYRING 2
+#define KEY_REQKEY_DEFL_SESSION_KEYRING 3
+#define KEY_REQKEY_DEFL_USER_KEYRING 4
+#define KEY_REQKEY_DEFL_USER_SESSION_KEYRING 5
+#define KEY_REQKEY_DEFL_GROUP_KEYRING 6
+
/* keyctl commands */
#define KEYCTL_GET_KEYRING_ID 0 /* ask for a keyring's ID */
#define KEYCTL_JOIN_SESSION_KEYRING 1 /* join or start named session keyring */
@@ -35,5 +45,6 @@
#define KEYCTL_READ 11 /* read a key or keyring's contents */
#define KEYCTL_INSTANTIATE 12 /* instantiate a partially constructed key */
#define KEYCTL_NEGATE 13 /* negate a partially constructed key */
+#define KEYCTL_SET_REQKEY_KEYRING 14 /* set default request-key keyring */
#endif /* _LINUX_KEYCTL_H */
diff --git a/include/linux/kmod.h b/include/linux/kmod.h
index 95d0e4b0814d..e4a231549407 100644
--- a/include/linux/kmod.h
+++ b/include/linux/kmod.h
@@ -19,6 +19,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/stddef.h>
#include <linux/config.h>
#include <linux/errno.h>
#include <linux/compiler.h>
@@ -34,7 +35,17 @@ static inline int request_module(const char * name, ...) { return -ENOSYS; }
#endif
#define try_then_request_module(x, mod...) ((x) ?: (request_module(mod), (x)))
-extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
+
+struct key;
+extern int call_usermodehelper_keys(char *path, char *argv[], char *envp[],
+ struct key *session_keyring, int wait);
+
+static inline int
+call_usermodehelper(char *path, char **argv, char **envp, int wait)
+{
+ return call_usermodehelper_keys(path, argv, envp, NULL, wait);
+}
+
extern void usermodehelper_init(void);
#endif /* __LINUX_KMOD_H__ */
diff --git a/include/linux/kprobes.h b/include/linux/kprobes.h
index 5e1a7b0d7b3f..e050fc2d4c26 100644
--- a/include/linux/kprobes.h
+++ b/include/linux/kprobes.h
@@ -104,33 +104,12 @@ struct jprobe {
};
#ifdef ARCH_SUPPORTS_KRETPROBES
-extern int trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs);
-extern void trampoline_post_handler(struct kprobe *p, struct pt_regs *regs,
- unsigned long flags);
-extern struct task_struct *arch_get_kprobe_task(void *ptr);
extern void arch_prepare_kretprobe(struct kretprobe *rp, struct pt_regs *regs);
-extern void arch_kprobe_flush_task(struct task_struct *tk);
#else /* ARCH_SUPPORTS_KRETPROBES */
-static inline void kretprobe_trampoline(void)
-{
-}
-static inline int trampoline_probe_handler(struct kprobe *p,
- struct pt_regs *regs)
-{
- return 0;
-}
-static inline void trampoline_post_handler(struct kprobe *p,
- struct pt_regs *regs, unsigned long flags)
-{
-}
static inline void arch_prepare_kretprobe(struct kretprobe *rp,
struct pt_regs *regs)
{
}
-static inline void arch_kprobe_flush_task(struct task_struct *tk)
-{
-}
-#define arch_get_kprobe_task(ptr) ((struct task_struct *)NULL)
#endif /* ARCH_SUPPORTS_KRETPROBES */
/*
* Function-return probe -
@@ -155,8 +134,8 @@ struct kretprobe_instance {
struct hlist_node uflist; /* either on free list or used list */
struct hlist_node hlist;
struct kretprobe *rp;
- void *ret_addr;
- void *stack_addr;
+ kprobe_opcode_t *ret_addr;
+ struct task_struct *task;
};
#ifdef CONFIG_KPROBES
@@ -176,7 +155,10 @@ extern void arch_copy_kprobe(struct kprobe *p);
extern void arch_arm_kprobe(struct kprobe *p);
extern void arch_disarm_kprobe(struct kprobe *p);
extern void arch_remove_kprobe(struct kprobe *p);
+extern int arch_init_kprobes(void);
extern void show_registers(struct pt_regs *regs);
+extern kprobe_opcode_t *get_insn_slot(void);
+extern void free_insn_slot(kprobe_opcode_t *slot);
/* Get the kprobe at this addr (if any). Must have called lock_kprobes */
struct kprobe *get_kprobe(void *addr);
@@ -194,8 +176,6 @@ int register_kretprobe(struct kretprobe *rp);
void unregister_kretprobe(struct kretprobe *rp);
struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp);
-struct kretprobe_instance *get_rp_inst(void *sara);
-struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk);
void add_rp_inst(struct kretprobe_instance *ri);
void kprobe_flush_task(struct task_struct *tk);
void recycle_rp_inst(struct kretprobe_instance *ri);
diff --git a/include/linux/libps2.h b/include/linux/libps2.h
index 923bdbc6d9e4..a710bddda4eb 100644
--- a/include/linux/libps2.h
+++ b/include/linux/libps2.h
@@ -41,6 +41,7 @@ struct ps2dev {
void ps2_init(struct ps2dev *ps2dev, struct serio *serio);
int ps2_sendbyte(struct ps2dev *ps2dev, unsigned char byte, int timeout);
+void ps2_drain(struct ps2dev *ps2dev, int maxbytes, int timeout);
int ps2_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_schedule_command(struct ps2dev *ps2dev, unsigned char *param, int command);
int ps2_handle_ack(struct ps2dev *ps2dev, unsigned char data);
diff --git a/include/linux/list.h b/include/linux/list.h
index 399b51d17218..aab2db21b013 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -185,7 +185,7 @@ static inline void list_del(struct list_head *entry)
* list_for_each_entry_rcu().
*
* Note that the caller is not permitted to immediately free
- * the newly deleted entry. Instead, either synchronize_kernel()
+ * the newly deleted entry. Instead, either synchronize_rcu()
* or call_rcu() must be used to defer freeing until an RCU
* grace period has elapsed.
*/
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index d6eb7b2efc04..dce53ac1625d 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -174,5 +174,62 @@ struct serio_device_id {
__u8 proto;
};
+/*
+ * Struct used for matching a device
+ */
+struct of_device_id
+{
+ char name[32];
+ char type[32];
+ char compatible[128];
+ void *data;
+};
+
+
+/* PCMCIA */
+
+struct pcmcia_device_id {
+ __u16 match_flags;
+
+ __u16 manf_id;
+ __u16 card_id;
+
+ __u8 func_id;
+
+ /* for real multi-function devices */
+ __u8 function;
+
+ /* for pseude multi-function devices */
+ __u8 device_no;
+
+ __u32 prod_id_hash[4];
+
+ /* not matched against in kernelspace*/
+#ifdef __KERNEL__
+ const char * prod_id[4];
+#else
+ kernel_ulong_t prod_id[4];
+#endif
+
+ /* not matched against */
+ kernel_ulong_t driver_info;
+#ifdef __KERNEL__
+ char * cisfile;
+#else
+ kernel_ulong_t cisfile;
+#endif
+};
+
+#define PCMCIA_DEV_ID_MATCH_MANF_ID 0x0001
+#define PCMCIA_DEV_ID_MATCH_CARD_ID 0x0002
+#define PCMCIA_DEV_ID_MATCH_FUNC_ID 0x0004
+#define PCMCIA_DEV_ID_MATCH_FUNCTION 0x0008
+#define PCMCIA_DEV_ID_MATCH_PROD_ID1 0x0010
+#define PCMCIA_DEV_ID_MATCH_PROD_ID2 0x0020
+#define PCMCIA_DEV_ID_MATCH_PROD_ID3 0x0040
+#define PCMCIA_DEV_ID_MATCH_PROD_ID4 0x0080
+#define PCMCIA_DEV_ID_MATCH_DEVICE_NO 0x0100
+#define PCMCIA_DEV_ID_MATCH_FAKE_CIS 0x0200
+#define PCMCIA_DEV_ID_MATCH_ANONYMOUS 0x0400
#endif /* LINUX_MOD_DEVICETABLE_H */
diff --git a/include/linux/module.h b/include/linux/module.h
index 0e432a0f4aee..f05372b7fe77 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -51,6 +51,9 @@ struct module_attribute {
ssize_t (*show)(struct module_attribute *, struct module *, char *);
ssize_t (*store)(struct module_attribute *, struct module *,
const char *, size_t count);
+ void (*setup)(struct module *, const char *);
+ int (*test)(struct module *);
+ void (*free)(struct module *);
};
struct module_kobject
@@ -239,6 +242,8 @@ struct module
/* Sysfs stuff. */
struct module_kobject mkobj;
struct module_param_attrs *param_attrs;
+ const char *version;
+ const char *srcversion;
/* Exported symbols */
const struct kernel_symbol *syms;
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 8b8d3b9beefd..f8f39937e301 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -12,6 +12,7 @@
#define _LINUX_MOUNT_H
#ifdef __KERNEL__
+#include <linux/types.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/atomic.h>
@@ -34,7 +35,7 @@ struct vfsmount
int mnt_expiry_mark; /* true if marked for expiry */
char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
struct list_head mnt_list;
- struct list_head mnt_fslink; /* link in fs-specific expiry list */
+ struct list_head mnt_expire; /* link in fs-specific expiry list */
struct namespace *mnt_namespace; /* containing namespace */
};
@@ -47,7 +48,7 @@ static inline struct vfsmount *mntget(struct vfsmount *mnt)
extern void __mntput(struct vfsmount *mnt);
-static inline void _mntput(struct vfsmount *mnt)
+static inline void mntput_no_expire(struct vfsmount *mnt)
{
if (mnt) {
if (atomic_dec_and_test(&mnt->mnt_count))
@@ -59,7 +60,7 @@ static inline void mntput(struct vfsmount *mnt)
{
if (mnt) {
mnt->mnt_expiry_mark = 0;
- _mntput(mnt);
+ mntput_no_expire(mnt);
}
}
@@ -76,6 +77,7 @@ extern int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
extern void mark_mounts_for_expiry(struct list_head *mounts);
extern spinlock_t vfsmount_lock;
+extern dev_t name_to_dev_t(char *name);
#endif
#endif /* _LINUX_MOUNT_H */
diff --git a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h
index 2ed8c585021e..e6b6a1c66bd5 100644
--- a/include/linux/mtd/cfi.h
+++ b/include/linux/mtd/cfi.h
@@ -1,7 +1,7 @@
/* Common Flash Interface structures
* See http://support.intel.com/design/flash/technote/index.htm
- * $Id: cfi.h,v 1.50 2004/11/20 12:46:51 dwmw2 Exp $
+ * $Id: cfi.h,v 1.54 2005/06/06 23:04:36 tpoynor Exp $
*/
#ifndef __MTD_CFI_H__
@@ -148,6 +148,14 @@ struct cfi_pri_intelext {
uint8_t extra[0];
} __attribute__((packed));
+struct cfi_intelext_otpinfo {
+ uint32_t ProtRegAddr;
+ uint16_t FactGroups;
+ uint8_t FactProtRegSize;
+ uint16_t UserGroups;
+ uint8_t UserProtRegSize;
+} __attribute__((packed));
+
struct cfi_intelext_blockinfo {
uint16_t NumIdentBlocks;
uint16_t BlockSize;
@@ -244,7 +252,7 @@ static inline uint32_t cfi_build_cmd_addr(uint32_t cmd_ofs, int interleave, int
* It looks too long to be inline, but in the common case it should almost all
* get optimised away.
*/
-static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi)
+static inline map_word cfi_build_cmd(u_long cmd, struct map_info *map, struct cfi_private *cfi)
{
map_word val = { {0} };
int wordwidth, words_per_bus, chip_mode, chips_per_word;
@@ -307,6 +315,69 @@ static inline map_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cf
}
#define CMD(x) cfi_build_cmd((x), map, cfi)
+
+static inline unsigned char cfi_merge_status(map_word val, struct map_info *map,
+ struct cfi_private *cfi)
+{
+ int wordwidth, words_per_bus, chip_mode, chips_per_word;
+ unsigned long onestat, res = 0;
+ int i;
+
+ /* We do it this way to give the compiler a fighting chance
+ of optimising away all the crap for 'bankwidth' larger than
+ an unsigned long, in the common case where that support is
+ disabled */
+ if (map_bankwidth_is_large(map)) {
+ wordwidth = sizeof(unsigned long);
+ words_per_bus = (map_bankwidth(map)) / wordwidth; // i.e. normally 1
+ } else {
+ wordwidth = map_bankwidth(map);
+ words_per_bus = 1;
+ }
+
+ chip_mode = map_bankwidth(map) / cfi_interleave(cfi);
+ chips_per_word = wordwidth * cfi_interleave(cfi) / map_bankwidth(map);
+
+ onestat = val.x[0];
+ /* Or all status words together */
+ for (i=1; i < words_per_bus; i++) {
+ onestat |= val.x[i];
+ }
+
+ res = onestat;
+ switch(chips_per_word) {
+ default: BUG();
+#if BITS_PER_LONG >= 64
+ case 8:
+ res |= (onestat >> (chip_mode * 32));
+#endif
+ case 4:
+ res |= (onestat >> (chip_mode * 16));
+ case 2:
+ res |= (onestat >> (chip_mode * 8));
+ case 1:
+ ;
+ }
+
+ /* Last, determine what the bit-pattern should be for a single
+ device, according to chip mode and endianness... */
+ switch (chip_mode) {
+ case 1:
+ break;
+ case 2:
+ res = cfi16_to_cpu(res);
+ break;
+ case 4:
+ res = cfi32_to_cpu(res);
+ break;
+ default: BUG();
+ }
+ return res;
+}
+
+#define MERGESTATUS(x) cfi_merge_status((x), map, cfi)
+
+
/*
* Sends a CFI command to a bank of flash for the given geometry.
*
@@ -357,16 +428,6 @@ static inline void cfi_udelay(int us)
}
}
-static inline void cfi_spin_lock(spinlock_t *mutex)
-{
- spin_lock_bh(mutex);
-}
-
-static inline void cfi_spin_unlock(spinlock_t *mutex)
-{
- spin_unlock_bh(mutex);
-}
-
struct cfi_extquery *cfi_read_pri(struct map_info *map, uint16_t adr, uint16_t size,
const char* name);
struct cfi_fixup {
diff --git a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h
index c66ba812bf90..675776fa3e27 100644
--- a/include/linux/mtd/flashchip.h
+++ b/include/linux/mtd/flashchip.h
@@ -6,7 +6,7 @@
*
* (C) 2000 Red Hat. GPLd.
*
- * $Id: flashchip.h,v 1.15 2004/11/05 22:41:06 nico Exp $
+ * $Id: flashchip.h,v 1.17 2005/03/14 18:27:15 bjd Exp $
*
*/
@@ -29,6 +29,7 @@ typedef enum {
FL_ERASE_SUSPENDED,
FL_WRITING,
FL_WRITING_TO_BUFFER,
+ FL_OTP_WRITE,
FL_WRITE_SUSPENDING,
FL_WRITE_SUSPENDED,
FL_PM_SUSPENDED,
@@ -62,8 +63,8 @@ struct flchip {
flstate_t state;
flstate_t oldstate;
- int write_suspended:1;
- int erase_suspended:1;
+ unsigned int write_suspended:1;
+ unsigned int erase_suspended:1;
unsigned long in_progress_block_addr;
spinlock_t *mutex;
diff --git a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h
index b52c8cbd235c..0268125a6271 100644
--- a/include/linux/mtd/inftl.h
+++ b/include/linux/mtd/inftl.h
@@ -3,7 +3,7 @@
*
* (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com)
*
- * $Id: inftl.h,v 1.6 2004/06/30 14:49:00 dbrown Exp $
+ * $Id: inftl.h,v 1.7 2005/06/13 13:08:45 sean Exp $
*/
#ifndef __MTD_INFTL_H__
@@ -20,7 +20,7 @@
#include <mtd/inftl-user.h>
#ifndef INFTL_MAJOR
-#define INFTL_MAJOR 94
+#define INFTL_MAJOR 96
#endif
#define INFTL_PARTN_BITS 4
diff --git a/include/linux/mtd/map.h b/include/linux/mtd/map.h
index f0268b99c900..142963f01d29 100644
--- a/include/linux/mtd/map.h
+++ b/include/linux/mtd/map.h
@@ -1,6 +1,6 @@
/* Overhauled routines for dealing with different mmap regions of flash */
-/* $Id: map.h,v 1.46 2005/01/05 17:09:44 dwmw2 Exp $ */
+/* $Id: map.h,v 1.52 2005/05/25 10:29:41 gleixner Exp $ */
#ifndef __LINUX_MTD_MAP_H__
#define __LINUX_MTD_MAP_H__
@@ -263,6 +263,17 @@ static inline map_word map_word_and(struct map_info *map, map_word val1, map_wor
return r;
}
+static inline map_word map_word_clr(struct map_info *map, map_word val1, map_word val2)
+{
+ map_word r;
+ int i;
+
+ for (i=0; i<map_words(map); i++) {
+ r.x[i] = val1.x[i] & ~val2.x[i];
+ }
+ return r;
+}
+
static inline map_word map_word_or(struct map_info *map, map_word val1, map_word val2)
{
map_word r;
@@ -273,6 +284,7 @@ static inline map_word map_word_or(struct map_info *map, map_word val1, map_word
}
return r;
}
+
#define map_word_andequal(m, a, b, z) map_word_equal(m, z, map_word_and(m, a, b))
static inline int map_word_bitsset(struct map_info *map, map_word val1, map_word val2)
@@ -328,16 +340,27 @@ static inline map_word map_word_load_partial(struct map_info *map, map_word orig
return orig;
}
+#if BITS_PER_LONG < 64
+#define MAP_FF_LIMIT 4
+#else
+#define MAP_FF_LIMIT 8
+#endif
+
static inline map_word map_word_ff(struct map_info *map)
{
map_word r;
int i;
-
- for (i=0; i<map_words(map); i++) {
- r.x[i] = ~0UL;
+
+ if (map_bankwidth(map) < MAP_FF_LIMIT) {
+ int bw = 8 * map_bankwidth(map);
+ r.x[0] = (1 << bw) - 1;
+ } else {
+ for (i=0; i<map_words(map); i++)
+ r.x[i] = ~0UL;
}
return r;
}
+
static inline map_word inline_map_read(struct map_info *map, unsigned long ofs)
{
map_word r;
@@ -405,7 +428,7 @@ extern void simple_map_init(struct map_info *);
#define simple_map_init(map) BUG_ON(!map_bankwidth_supported((map)->bankwidth))
-#define map_is_linear(map) (1)
+#define map_is_linear(map) ({ (void)(map); 1; })
#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
index b3d134392b31..c50c3f3927d9 100644
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -1,5 +1,5 @@
/*
- * $Id: mtd.h,v 1.56 2004/08/09 18:46:04 dmarlin Exp $
+ * $Id: mtd.h,v 1.59 2005/04/11 10:19:02 gleixner Exp $
*
* Copyright (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> et al.
*
@@ -18,6 +18,7 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/uio.h>
+#include <linux/notifier.h>
#include <linux/mtd/compatmac.h>
#include <mtd/mtd-abi.h>
@@ -69,7 +70,6 @@ struct mtd_info {
u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
- u_int32_t oobavail; // Number of bytes in OOB area available for fs
u_int32_t ecctype;
u_int32_t eccsize;
@@ -80,6 +80,7 @@ struct mtd_info {
// oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO)
struct nand_oobinfo oobinfo;
+ u_int32_t oobavail; // Number of bytes in OOB area available for fs
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
@@ -113,12 +114,12 @@ struct mtd_info {
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
- int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
+ int (*get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
-
- /* This function is not yet implemented */
+ int (*get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf, size_t len);
+ int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
+ int (*lock_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len);
/* kvec-based read/write methods. We need these especially for NAND flash,
with its limited number of write cycles per erase.
@@ -147,6 +148,8 @@ struct mtd_info {
int (*block_isbad) (struct mtd_info *mtd, loff_t ofs);
int (*block_markbad) (struct mtd_info *mtd, loff_t ofs);
+ struct notifier_block reboot_notifier; /* default mode before reboot */
+
void *priv;
struct module *owner;
diff --git a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h
index 9a19c65abd74..9b5b76217584 100644
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -5,7 +5,7 @@
* Steven J. Hill <sjhill@realitydiluted.com>
* Thomas Gleixner <tglx@linutronix.de>
*
- * $Id: nand.h,v 1.68 2004/11/12 10:40:37 gleixner Exp $
+ * $Id: nand.h,v 1.73 2005/05/31 19:39:17 gleixner Exp $
*
* 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
@@ -48,6 +48,10 @@
* 02-08-2004 tglx added option field to nand structure for chip anomalities
* 05-25-2004 tglx added bad block table support, ST-MICRO manufacturer id
* update of nand_chip structure description
+ * 01-17-2005 dmarlin added extended commands for AG-AND device and added option
+ * for BBT_AUTO_REFRESH.
+ * 01-20-2005 dmarlin added optional pointer to hardware specific callback for
+ * extra error status checks.
*/
#ifndef __LINUX_MTD_NAND_H
#define __LINUX_MTD_NAND_H
@@ -115,6 +119,25 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
#define NAND_CMD_READSTART 0x30
#define NAND_CMD_CACHEDPROG 0x15
+/* Extended commands for AG-AND device */
+/*
+ * Note: the command for NAND_CMD_DEPLETE1 is really 0x00 but
+ * there is no way to distinguish that from NAND_CMD_READ0
+ * until the remaining sequence of commands has been completed
+ * so add a high order bit and mask it off in the command.
+ */
+#define NAND_CMD_DEPLETE1 0x100
+#define NAND_CMD_DEPLETE2 0x38
+#define NAND_CMD_STATUS_MULTI 0x71
+#define NAND_CMD_STATUS_ERROR 0x72
+/* multi-bank error status (banks 0-3) */
+#define NAND_CMD_STATUS_ERROR0 0x73
+#define NAND_CMD_STATUS_ERROR1 0x74
+#define NAND_CMD_STATUS_ERROR2 0x75
+#define NAND_CMD_STATUS_ERROR3 0x76
+#define NAND_CMD_STATUS_RESET 0x7f
+#define NAND_CMD_STATUS_CLEAR 0xff
+
/* Status bits */
#define NAND_STATUS_FAIL 0x01
#define NAND_STATUS_FAIL_N1 0x02
@@ -143,7 +166,7 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/*
* Constants for Hardware ECC
-*/
+ */
/* Reset Hardware ECC for read */
#define NAND_ECC_READ 0
/* Reset Hardware ECC for write */
@@ -151,6 +174,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Enable Hardware ECC before syndrom is read back from flash */
#define NAND_ECC_READSYN 2
+/* Bit mask for flags passed to do_nand_read_ecc */
+#define NAND_GET_DEVICE 0x80
+
+
/* Option constants for bizarre disfunctionality and real
* features
*/
@@ -170,6 +197,10 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
/* Chip has a array of 4 pages which can be read without
* additional ready /busy waits */
#define NAND_4PAGE_ARRAY 0x00000040
+/* Chip requires that BBT is periodically rewritten to prevent
+ * bits from adjacent blocks from 'leaking' in altering data.
+ * This happens with the Renesas AG-AND chips, possibly others. */
+#define BBT_AUTO_REFRESH 0x00000080
/* Options valid for Samsung large page devices */
#define NAND_SAMSUNG_LP_OPTIONS \
@@ -192,7 +223,8 @@ extern int nand_read_raw (struct mtd_info *mtd, uint8_t *buf, loff_t from, size_
* This can only work if we have the ecc bytes directly behind the
* data bytes. Applies for DOC and AG-AND Renesas HW Reed Solomon generators */
#define NAND_HWECC_SYNDROME 0x00020000
-
+/* This option skips the bbt scan during initialization. */
+#define NAND_SKIP_BBTSCAN 0x00040000
/* Options set by nand scan */
/* Nand scan has allocated oob_buf */
@@ -221,10 +253,13 @@ struct nand_chip;
* struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independend devices
* @lock: protection lock
* @active: the mtd device which holds the controller currently
+ * @wq: wait queue to sleep on if a NAND operation is in progress
+ * used instead of the per chip wait queue when a hw controller is available
*/
struct nand_hw_control {
spinlock_t lock;
struct nand_chip *active;
+ wait_queue_head_t wq;
};
/**
@@ -283,6 +318,8 @@ struct nand_hw_control {
* @badblock_pattern: [REPLACEABLE] bad block scan pattern used for initial bad block scan
* @controller: [OPTIONAL] a pointer to a hardware controller structure which is shared among multiple independend devices
* @priv: [OPTIONAL] pointer to private chip date
+ * @errstat: [OPTIONAL] hardware specific function to perform additional error status checks
+ * (determine if errors are correctable)
*/
struct nand_chip {
@@ -338,6 +375,7 @@ struct nand_chip {
struct nand_bbt_descr *badblock_pattern;
struct nand_hw_control *controller;
void *priv;
+ int (*errstat)(struct mtd_info *mtd, struct nand_chip *this, int state, int status, int page);
};
/*
@@ -349,6 +387,7 @@ struct nand_chip {
#define NAND_MFR_NATIONAL 0x8f
#define NAND_MFR_RENESAS 0x07
#define NAND_MFR_STMICRO 0x20
+#define NAND_MFR_HYNIX 0xad
/**
* struct nand_flash_dev - NAND Flash Device ID Structure
@@ -459,6 +498,9 @@ extern int nand_update_bbt (struct mtd_info *mtd, loff_t offs);
extern int nand_default_bbt (struct mtd_info *mtd);
extern int nand_isbad_bbt (struct mtd_info *mtd, loff_t offs, int allowbbt);
extern int nand_erase_nand (struct mtd_info *mtd, struct erase_info *instr, int allowbbt);
+extern int nand_do_read_ecc (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t * retlen, u_char * buf, u_char * oob_buf,
+ struct nand_oobinfo *oobsel, int flags);
/*
* Constants for oob configuration
diff --git a/include/linux/mtd/plat-ram.h b/include/linux/mtd/plat-ram.h
new file mode 100644
index 000000000000..2332eda07e0e
--- /dev/null
+++ b/include/linux/mtd/plat-ram.h
@@ -0,0 +1,35 @@
+/* linux/include/mtd/plat-ram.h
+ *
+ * (c) 2004 Simtec Electronics
+ * http://www.simtec.co.uk/products/SWLINUX/
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * Generic platform device based RAM map
+ *
+ * $Id: plat-ram.h,v 1.2 2005/01/24 00:37:40 bjd Exp $
+ *
+ * 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 __LINUX_MTD_PLATRAM_H
+#define __LINUX_MTD_PLATRAM_H __FILE__
+
+#define PLATRAM_RO (0)
+#define PLATRAM_RW (1)
+
+struct platdata_mtd_ram {
+ char *mapname;
+ char **probes;
+ struct mtd_partition *partitions;
+ int nr_partitions;
+ int bankwidth;
+
+ /* control callbacks */
+
+ void (*set_rw)(struct device *dev, int to);
+};
+
+#endif /* __LINUX_MTD_PLATRAM_H */
diff --git a/include/linux/mtd/xip.h b/include/linux/mtd/xip.h
index fc071125cbcc..7b7deef6b180 100644
--- a/include/linux/mtd/xip.h
+++ b/include/linux/mtd/xip.h
@@ -58,22 +58,16 @@
* returned value is <= the real elapsed time.
* note 2: this should be able to cope with a few seconds without
* overflowing.
+ *
+ * xip_iprefetch()
+ *
+ * Macro to fill instruction prefetch
+ * e.g. a series of nops: asm volatile (".rep 8; nop; .endr");
*/
-#if defined(CONFIG_ARCH_SA1100) || defined(CONFIG_ARCH_PXA)
-
-#include <asm/hardware.h>
-#ifdef CONFIG_ARCH_PXA
-#include <asm/arch/pxa-regs.h>
-#endif
-
-#define xip_irqpending() (ICIP & ICMR)
-
-/* we sample OSCR and convert desired delta to usec (1/4 ~= 1000000/3686400) */
-#define xip_currtime() (OSCR)
-#define xip_elapsed_since(x) (signed)((OSCR - (x)) / 4)
+#include <asm/mtd-xip.h>
-#else
+#ifndef xip_irqpending
#warning "missing IRQ and timer primitives for XIP MTD support"
#warning "some of the XIP MTD support code will be disabled"
@@ -85,16 +79,17 @@
#endif
+#ifndef xip_iprefetch
+#define xip_iprefetch() do { } while (0)
+#endif
+
/*
* xip_cpu_idle() is used when waiting for a delay equal or larger than
* the system timer tick period. This should put the CPU into idle mode
* to save power and to be woken up only when some interrupts are pending.
- * As above, this should not rely upon standard kernel code.
+ * This should not rely upon standard kernel code.
*/
-
-#if defined(CONFIG_CPU_XSCALE)
-#define xip_cpu_idle() asm volatile ("mcr p14, 0, %0, c7, c0, 0" :: "r" (1))
-#else
+#ifndef xip_cpu_idle
#define xip_cpu_idle() do { } while (0)
#endif
diff --git a/include/linux/namespace.h b/include/linux/namespace.h
index 9eca1558d72f..0e5a86f13b2f 100644
--- a/include/linux/namespace.h
+++ b/include/linux/namespace.h
@@ -12,13 +12,13 @@ struct namespace {
struct rw_semaphore sem;
};
-extern void umount_tree(struct vfsmount *);
extern int copy_namespace(int, struct task_struct *);
extern void __put_namespace(struct namespace *namespace);
static inline void put_namespace(struct namespace *namespace)
{
- if (atomic_dec_and_test(&namespace->count))
+ if (atomic_dec_and_lock(&namespace->count, &vfsmount_lock))
+ /* releases vfsmount_lock */
__put_namespace(namespace);
}
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index d89816ad642f..3a0ed7f9e801 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -164,12 +164,6 @@ struct netif_rx_stats
unsigned total;
unsigned dropped;
unsigned time_squeeze;
- unsigned throttled;
- unsigned fastroute_hit;
- unsigned fastroute_success;
- unsigned fastroute_defer;
- unsigned fastroute_deferred_out;
- unsigned fastroute_latency_reduction;
unsigned cpu_collision;
};
@@ -562,12 +556,9 @@ static inline int unregister_gifconf(unsigned int family)
struct softnet_data
{
- int throttle;
- int cng_level;
- int avg_blog;
+ struct net_device *output_queue;
struct sk_buff_head input_pkt_queue;
struct list_head poll_list;
- struct net_device *output_queue;
struct sk_buff *completion_queue;
struct net_device backlog_dev; /* Sorry. 8) */
diff --git a/include/linux/netlink.h b/include/linux/netlink.h
index 3029cad63a01..2f0c085f2c7d 100644
--- a/include/linux/netlink.h
+++ b/include/linux/netlink.h
@@ -16,6 +16,7 @@
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
+#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
@@ -168,6 +169,7 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags)
nlh->nlmsg_flags = flags;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
+ memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size);
return nlh;
}
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 5bb5b2fd7ba2..0c1c306cdaec 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -28,7 +28,7 @@
#define NFS4_ACCESS_DELETE 0x0010
#define NFS4_ACCESS_EXECUTE 0x0020
-#define NFS4_FH_PERISTENT 0x0000
+#define NFS4_FH_PERSISTENT 0x0000
#define NFS4_FH_NOEXPIRE_WITH_OPEN 0x0001
#define NFS4_FH_VOLATILE_ANY 0x0002
#define NFS4_FH_VOL_MIGRATION 0x0004
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 4bf931d5ff56..6d5a24f3fc6d 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -124,6 +124,7 @@ int nfsd_statfs(struct svc_rqst *, struct svc_fh *,
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
+void nfsd_sync_dir(struct dentry *dp);
#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
#ifdef CONFIG_NFSD_V2_ACL
@@ -145,15 +146,19 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
* NFSv4 State
*/
#ifdef CONFIG_NFSD_V4
-int nfs4_state_init(void);
+void nfs4_state_init(void);
+int nfs4_state_start(void);
void nfs4_state_shutdown(void);
time_t nfs4_lease_time(void);
void nfs4_reset_lease(time_t leasetime);
+int nfs4_reset_recoverydir(char *recdir);
#else
-static inline int nfs4_state_init(void){return 0;}
+static inline void nfs4_state_init(void){};
+static inline int nfs4_state_start(void){return 0;}
static inline void nfs4_state_shutdown(void){}
static inline time_t nfs4_lease_time(void){return 0;}
static inline void nfs4_reset_lease(time_t leasetime){}
+static inline int nfs4_reset_recoverydir(char *recdir) {return 0;}
#endif
/*
@@ -226,6 +231,7 @@ void nfsd_lockd_shutdown(void);
#define nfserr_reclaim_bad __constant_htonl(NFSERR_RECLAIM_BAD)
#define nfserr_badname __constant_htonl(NFSERR_BADNAME)
#define nfserr_cb_path_down __constant_htonl(NFSERR_CB_PATH_DOWN)
+#define nfserr_locked __constant_htonl(NFSERR_LOCKED)
/* error codes for internal use */
/* if a request fails due to kmalloc failure, it gets dropped.
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
index b6b2fe1e7c63..8bf23cf8b603 100644
--- a/include/linux/nfsd/state.h
+++ b/include/linux/nfsd/state.h
@@ -61,11 +61,6 @@ typedef struct {
#define si_stateownerid si_opaque.so_stateownerid
#define si_fileid si_opaque.so_fileid
-extern stateid_t zerostateid;
-extern stateid_t onestateid;
-
-#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
-#define ONE_STATEID(stateid) (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
struct nfs4_cb_recall {
u32 cbr_ident;
@@ -77,8 +72,8 @@ struct nfs4_cb_recall {
};
struct nfs4_delegation {
- struct list_head dl_del_perfile; /* nfs4_file->fi_del_perfile */
- struct list_head dl_del_perclnt; /* nfs4_client->cl_del_perclnt*/
+ struct list_head dl_perfile;
+ struct list_head dl_perclnt;
struct list_head dl_recall_lru; /* delegation recalled */
atomic_t dl_count; /* ref count */
struct nfs4_client *dl_client;
@@ -97,7 +92,6 @@ struct nfs4_delegation {
/* client delegation callback info */
struct nfs4_callback {
/* SETCLIENTID info */
- u32 cb_parsed; /* addr parsed */
u32 cb_addr;
unsigned short cb_port;
u32 cb_prog;
@@ -109,6 +103,8 @@ struct nfs4_callback {
struct rpc_clnt * cb_client;
};
+#define HEXDIR_LEN 33 /* hex version of 16 byte md5 of cl_name plus '\0' */
+
/*
* struct nfs4_client - one per client. Clientids live here.
* o Each nfs4_client is hashed by clientid.
@@ -122,10 +118,11 @@ struct nfs4_callback {
struct nfs4_client {
struct list_head cl_idhash; /* hash by cl_clientid.id */
struct list_head cl_strhash; /* hash by cl_name */
- struct list_head cl_perclient; /* list: stateowners */
- struct list_head cl_del_perclnt; /* list: delegations */
+ struct list_head cl_openowners;
+ struct list_head cl_delegations;
struct list_head cl_lru; /* tail queue */
struct xdr_netobj cl_name; /* id generated by client */
+ char cl_recdir[HEXDIR_LEN]; /* recovery dir */
nfs4_verifier cl_verifier; /* generated by client */
time_t cl_time; /* time of last lease renewal */
u32 cl_addr; /* client ipaddress */
@@ -134,6 +131,7 @@ struct nfs4_client {
nfs4_verifier cl_confirm; /* generated by server */
struct nfs4_callback cl_callback; /* callback info */
atomic_t cl_count; /* ref count */
+ u32 cl_firststate; /* recovery dir creation */
};
/* struct nfs4_client_reset
@@ -143,7 +141,7 @@ struct nfs4_client {
*/
struct nfs4_client_reclaim {
struct list_head cr_strhash; /* hash by cr_name */
- struct xdr_netobj cr_name; /* id generated by client */
+ char cr_recdir[HEXDIR_LEN]; /* recover dir */
};
static inline void
@@ -197,15 +195,17 @@ struct nfs4_stateowner {
struct kref so_ref;
struct list_head so_idhash; /* hash by so_id */
struct list_head so_strhash; /* hash by op_name */
- struct list_head so_perclient; /* nfs4_client->cl_perclient */
- struct list_head so_perfilestate; /* list: nfs4_stateid */
- struct list_head so_perlockowner; /* nfs4_stateid->st_perlockowner */
+ struct list_head so_perclient;
+ struct list_head so_stateids;
+ struct list_head so_perstateid; /* for lockowners only */
struct list_head so_close_lru; /* tail queue */
time_t so_time; /* time of placement on so_close_lru */
int so_is_open_owner; /* 1=openowner,0=lockowner */
u32 so_id;
struct nfs4_client * so_client;
- u32 so_seqid;
+ /* after increment in ENCODE_SEQID_OP_TAIL, represents the next
+ * sequence id expected from the client: */
+ u32 so_seqid;
struct xdr_netobj so_owner; /* open owner name */
int so_confirmed; /* successful OPEN_CONFIRM? */
struct nfs4_replay so_replay;
@@ -217,9 +217,10 @@ struct nfs4_stateowner {
* share_acces, share_deny on the file.
*/
struct nfs4_file {
+ struct kref fi_ref;
struct list_head fi_hash; /* hash by "struct inode *" */
- struct list_head fi_perfile; /* list: nfs4_stateid */
- struct list_head fi_del_perfile; /* list: nfs4_delegation */
+ struct list_head fi_stateids;
+ struct list_head fi_delegations;
struct inode *fi_inode;
u32 fi_id; /* used with stateowner->so_id
* for stateid_hashtbl hash */
@@ -236,19 +237,24 @@ struct nfs4_file {
* st_perlockowner: (open stateid) list of lock nfs4_stateowners
* st_access_bmap: used only for open stateid
* st_deny_bmap: used only for open stateid
+* st_openstp: open stateid lock stateid was derived from
+*
+* XXX: open stateids and lock stateids have diverged sufficiently that
+* we should consider defining separate structs for the two cases.
*/
struct nfs4_stateid {
struct list_head st_hash;
struct list_head st_perfile;
- struct list_head st_perfilestate;
- struct list_head st_perlockowner;
+ struct list_head st_perstateowner;
+ struct list_head st_lockowners;
struct nfs4_stateowner * st_stateowner;
struct nfs4_file * st_file;
stateid_t st_stateid;
struct file * st_vfs_file;
unsigned long st_access_bmap;
unsigned long st_deny_bmap;
+ struct nfs4_stateid * st_openstp;
};
/* flags for preprocess_seqid_op() */
@@ -267,12 +273,9 @@ struct nfs4_stateid {
((err) != nfserr_stale_stateid) && \
((err) != nfserr_bad_stateid))
-extern time_t nfs4_laundromat(void);
extern int nfsd4_renew(clientid_t *clid);
extern int nfs4_preprocess_stateid_op(struct svc_fh *current_fh,
stateid_t *stateid, int flags, struct file **filp);
-extern int nfs4_share_conflict(struct svc_fh *current_fh,
- unsigned int deny_type);
extern void nfs4_lock_state(void);
extern void nfs4_unlock_state(void);
extern int nfs4_in_grace(void);
@@ -282,6 +285,15 @@ extern void nfs4_free_stateowner(struct kref *kref);
extern void nfsd4_probe_callback(struct nfs4_client *clp);
extern void nfsd4_cb_recall(struct nfs4_delegation *dp);
extern void nfs4_put_delegation(struct nfs4_delegation *dp);
+extern int nfs4_make_rec_clidname(char *clidname, struct xdr_netobj *clname);
+extern void nfsd4_init_recdir(char *recdir_name);
+extern int nfsd4_recdir_load(void);
+extern void nfsd4_shutdown_recdir(void);
+extern int nfs4_client_to_reclaim(const char *name);
+extern int nfs4_has_reclaimed_state(const char *name);
+extern void nfsd4_recdir_purge_old(void);
+extern int nfsd4_create_clid_dir(struct nfs4_client *clp);
+extern void nfsd4_remove_clid_dir(struct nfs4_client *clp);
static inline void
nfs4_put_stateowner(struct nfs4_stateowner *so)
diff --git a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
index a1f5ad0be1bf..4d24d65c0e88 100644
--- a/include/linux/nfsd/xdr4.h
+++ b/include/linux/nfsd/xdr4.h
@@ -210,6 +210,7 @@ struct nfsd4_open {
u32 op_share_access; /* request */
u32 op_share_deny; /* request */
stateid_t op_stateid; /* response */
+ u32 op_recall; /* recall */
struct nfsd4_change_info op_cinfo; /* response */
u32 op_rflags; /* response */
int op_truncate; /* used during processing */
diff --git a/include/linux/nfsd_idmap.h b/include/linux/nfsd_idmap.h
index 9bb7f30e923b..e82746fcad14 100644
--- a/include/linux/nfsd_idmap.h
+++ b/include/linux/nfsd_idmap.h
@@ -43,8 +43,13 @@
/* XXX from linux/nfs_idmap.h */
#define IDMAP_NAMESZ 128
+#ifdef CONFIG_NFSD_V4
void nfsd_idmap_init(void);
void nfsd_idmap_shutdown(void);
+#else
+static inline void nfsd_idmap_init(void) {};
+static inline void nfsd_idmap_shutdown(void) {};
+#endif
int nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, __u32 *);
int nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, __u32 *);
diff --git a/include/linux/nvram.h b/include/linux/nvram.h
index b031e41b5e0d..9189829c131c 100644
--- a/include/linux/nvram.h
+++ b/include/linux/nvram.h
@@ -20,8 +20,6 @@ extern void __nvram_write_byte(unsigned char c, int i);
extern void nvram_write_byte(unsigned char c, int i);
extern int __nvram_check_checksum(void);
extern int nvram_check_checksum(void);
-extern void __nvram_set_checksum(void);
-extern void nvram_set_checksum(void);
#endif
#endif /* _LINUX_NVRAM_H */
diff --git a/include/linux/pci-dynids.h b/include/linux/pci-dynids.h
deleted file mode 100644
index 183b6b0de81c..000000000000
--- a/include/linux/pci-dynids.h
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * PCI defines and function prototypes
- * Copyright 2003 Dell Inc.
- * by Matt Domsch <Matt_Domsch@dell.com>
- */
-
-#ifndef LINUX_PCI_DYNIDS_H
-#define LINUX_PCI_DYNIDS_H
-
-#include <linux/list.h>
-#include <linux/mod_devicetable.h>
-
-struct dynid {
- struct list_head node;
- struct pci_device_id id;
-};
-
-#endif
diff --git a/include/linux/pci.h b/include/linux/pci.h
index b5238bd18830..7ac14961ba22 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -586,7 +586,7 @@ struct pci_dev {
#define PCI_NUM_RESOURCES 11
#ifndef PCI_BUS_NUM_RESOURCES
-#define PCI_BUS_NUM_RESOURCES 4
+#define PCI_BUS_NUM_RESOURCES 8
#endif
#define PCI_REGION_FLAG_MASK 0x0fU /* These bits of resource flags tell us the PCI region flags */
@@ -734,16 +734,20 @@ void pcibios_update_irq(struct pci_dev *, int irq);
/* Generic PCI functions used internally */
extern struct pci_bus *pci_find_bus(int domain, int busnr);
+void pci_bus_add_devices(struct pci_bus *bus);
struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
{
- return pci_scan_bus_parented(NULL, bus, ops, sysdata);
+ struct pci_bus *root_bus;
+ root_bus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
+ if (root_bus)
+ pci_bus_add_devices(root_bus);
+ return root_bus;
}
int pci_scan_slot(struct pci_bus *bus, int devfn);
struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn);
unsigned int pci_scan_child_bus(struct pci_bus *bus);
void pci_bus_add_device(struct pci_dev *dev);
-void pci_bus_add_devices(struct pci_bus *bus);
void pci_name_device(struct pci_dev *dev);
char *pci_class_name(u32 class);
void pci_read_bridge_bases(struct pci_bus *child);
@@ -856,7 +860,8 @@ int pci_register_driver(struct pci_driver *);
void pci_unregister_driver(struct pci_driver *);
void pci_remove_behind_bridge(struct pci_dev *);
struct pci_driver *pci_dev_driver(const struct pci_dev *);
-const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev);
+const struct pci_device_id *pci_match_device(struct pci_driver *drv, struct pci_dev *dev);
+const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, struct pci_dev *dev);
int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass);
/* kmem_cache style wrapper around pci_alloc_consistent() */
@@ -870,6 +875,15 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass
#define pci_pool_alloc(pool, flags, handle) dma_pool_alloc(pool, flags, handle)
#define pci_pool_free(pool, vaddr, addr) dma_pool_free(pool, vaddr, addr)
+enum pci_dma_burst_strategy {
+ PCI_DMA_BURST_INFINITY, /* make bursts as large as possible,
+ strategy_parameter is N/A */
+ PCI_DMA_BURST_BOUNDARY, /* disconnect at every strategy_parameter
+ byte boundaries */
+ PCI_DMA_BURST_MULTIPLE, /* disconnect at some multiple of
+ strategy_parameter byte boundaries */
+};
+
#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
extern struct pci_dev *isa_bridge;
#endif
@@ -972,6 +986,8 @@ static inline int pci_proc_domain(struct pci_bus *bus)
}
#endif
+#define pci_dma_burst_advice(pdev, strat, strategy_parameter) do { } while (0)
+
#endif /* !CONFIG_PCI */
/* these helpers provide future and backwards compatibility
@@ -1016,6 +1032,20 @@ static inline char *pci_name(struct pci_dev *pdev)
#define pci_pretty_name(dev) ""
#endif
+
+/* Some archs don't want to expose struct resource to userland as-is
+ * in sysfs and /proc
+ */
+#ifndef HAVE_ARCH_PCI_RESOURCE_TO_USER
+static inline void pci_resource_to_user(const struct pci_dev *dev, int bar,
+ const struct resource *rsrc, u64 *start, u64 *end)
+{
+ *start = rsrc->start;
+ *end = rsrc->end;
+}
+#endif /* HAVE_ARCH_PCI_RESOURCE_TO_USER */
+
+
/*
* The world is not perfect and supplies us with broken PCI devices.
* For at least a part of these bugs we need a work-around, so both
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 63e89e47b8e9..27348c22dacb 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -62,6 +62,8 @@
#define PCI_BASE_CLASS_SYSTEM 0x08
#define PCI_CLASS_SYSTEM_PIC 0x0800
+#define PCI_CLASS_SYSTEM_PIC_IOAPIC 0x080010
+#define PCI_CLASS_SYSTEM_PIC_IOXAPIC 0x080020
#define PCI_CLASS_SYSTEM_DMA 0x0801
#define PCI_CLASS_SYSTEM_TIMER 0x0802
#define PCI_CLASS_SYSTEM_RTC 0x0803
@@ -712,8 +714,9 @@
#define PCI_DEVICE_ID_HP_DIVA_AUX 0x1290
#define PCI_DEVICE_ID_HP_DIVA_RMP3 0x1301
#define PCI_DEVICE_ID_HP_CISSA 0x3220
-#define PCI_DEVICE_ID_HP_CISSB 0x3230
+#define PCI_DEVICE_ID_HP_CISSB 0x3222
#define PCI_DEVICE_ID_HP_ZX2_IOC 0x4031
+#define PCI_DEVICE_ID_HP_CISSC 0x3230
#define PCI_VENDOR_ID_PCTECH 0x1042
#define PCI_DEVICE_ID_PCTECH_RZ1000 0x1000
@@ -1235,6 +1238,7 @@
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266
#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267
+#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E
#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268
#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269
#define PCI_DEVICE_ID_NVIDIA_MCP51_AUDIO 0x026B
@@ -1284,6 +1288,8 @@
#define PCI_DEVICE_ID_NVIDIA_GEFORCE_FX_GO5700_2 0x0348
#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_GO1000 0x034C
#define PCI_DEVICE_ID_NVIDIA_QUADRO_FX_1100 0x034E
+#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372
+#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373
#define PCI_VENDOR_ID_IMS 0x10e0
#define PCI_DEVICE_ID_IMS_8849 0x8849
@@ -1568,6 +1574,7 @@
#define PCI_DEVICE_ID_SERVERWORKS_OSB4USB 0x0220
#define PCI_DEVICE_ID_SERVERWORKS_CSB5USB PCI_DEVICE_ID_SERVERWORKS_OSB4USB
#define PCI_DEVICE_ID_SERVERWORKS_CSB6USB 0x0221
+#define PCI_DEVICE_ID_SERVERWORKS_CSB6LPC 0x0227
#define PCI_DEVICE_ID_SERVERWORKS_GCLE 0x0225
#define PCI_DEVICE_ID_SERVERWORKS_GCLE2 0x0227
#define PCI_DEVICE_ID_SERVERWORKS_CSB5ISA 0x0230
@@ -1811,6 +1818,8 @@
#define PCI_VENDOR_ID_ITE 0x1283
#define PCI_DEVICE_ID_ITE_IT8172G 0x8172
#define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801
+#define PCI_DEVICE_ID_ITE_8211 0x8211
+#define PCI_DEVICE_ID_ITE_8212 0x8212
#define PCI_DEVICE_ID_ITE_8872 0x8872
#define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886
diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h
index d2aa214d6803..bd2c5a2bbbf5 100644
--- a/include/linux/pkt_cls.h
+++ b/include/linux/pkt_cls.h
@@ -276,6 +276,7 @@ struct tc_rsvp_pinfo
__u8 protocol;
__u8 tunnelid;
__u8 tunnelhdr;
+ __u8 pad;
};
/* ROUTE filter */
@@ -408,6 +409,7 @@ enum
TCF_EM_NBYTE,
TCF_EM_U32,
TCF_EM_META,
+ TCF_EM_TEXT,
__TCF_EM_MAX
};
diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h
index 1d9da36eb9db..60ffcb9c5791 100644
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -221,9 +221,11 @@ struct tc_gred_qopt
/* gred setup */
struct tc_gred_sopt
{
- __u32 DPs;
- __u32 def_DP;
- __u8 grio;
+ __u32 DPs;
+ __u32 def_DP;
+ __u8 grio;
+ __u8 pad1;
+ __u16 pad2;
};
/* HTB section */
@@ -351,6 +353,7 @@ struct tc_cbq_ovl
#define TC_CBQ_OVL_DROP 3
#define TC_CBQ_OVL_RCLASSIC 4
unsigned char priority2;
+ __u16 pad;
__u32 penalty;
};
diff --git a/include/linux/pm.h b/include/linux/pm.h
index ed2b76e75199..7aeb208ed713 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -103,7 +103,8 @@ extern int pm_active;
/*
* Register a device with power management
*/
-struct pm_dev __deprecated *pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
+struct pm_dev __deprecated *
+pm_register(pm_dev_t type, unsigned long id, pm_callback callback);
/*
* Unregister a device with power management
@@ -175,7 +176,7 @@ struct pm_ops {
};
extern void pm_set_ops(struct pm_ops *);
-
+extern struct pm_ops *pm_ops;
extern int pm_suspend(suspend_state_t state);
@@ -190,17 +191,18 @@ typedef u32 __bitwise pm_message_t;
/*
* There are 4 important states driver can be in:
* ON -- driver is working
- * FREEZE -- stop operations and apply whatever policy is applicable to a suspended driver
- * of that class, freeze queues for block like IDE does, drop packets for
- * ethernet, etc... stop DMA engine too etc... so a consistent image can be
- * saved; but do not power any hardware down.
- * SUSPEND - like FREEZE, but hardware is doing as much powersaving as possible. Roughly
- * pci D3.
+ * FREEZE -- stop operations and apply whatever policy is applicable to a
+ * suspended driver of that class, freeze queues for block like IDE
+ * does, drop packets for ethernet, etc... stop DMA engine too etc...
+ * so a consistent image can be saved; but do not power any hardware
+ * down.
+ * SUSPEND - like FREEZE, but hardware is doing as much powersaving as
+ * possible. Roughly pci D3.
*
- * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3 (SUSPEND).
- * We'll need to fix the drivers. So yes, putting 3 to all diferent defines is intentional,
- * and will go away as soon as drivers are fixed. Also note that typedef is neccessary,
- * we'll probably want to switch to
+ * Unfortunately, current drivers only recognize numeric values 0 (ON) and 3
+ * (SUSPEND). We'll need to fix the drivers. So yes, putting 3 to all different
+ * defines is intentional, and will go away as soon as drivers are fixed. Also
+ * note that typedef is neccessary, we'll probably want to switch to
* typedef struct pm_message_t { int event; int flags; } pm_message_t
* or something similar soon.
*/
@@ -222,11 +224,18 @@ struct dev_pm_info {
extern void device_pm_set_parent(struct device * dev, struct device * parent);
-extern int device_suspend(pm_message_t state);
extern int device_power_down(pm_message_t state);
extern void device_power_up(void);
extern void device_resume(void);
+#ifdef CONFIG_PM
+extern int device_suspend(pm_message_t state);
+#else
+static inline int device_suspend(pm_message_t state)
+{
+ return 0;
+}
+#endif
#endif /* __KERNEL__ */
diff --git a/include/linux/pmu.h b/include/linux/pmu.h
index 6d73eada277e..373bd3b9b330 100644
--- a/include/linux/pmu.h
+++ b/include/linux/pmu.h
@@ -166,7 +166,7 @@ extern int pmu_i2c_simple_read(int bus, int addr, u8* data, int len);
extern int pmu_i2c_simple_write(int bus, int addr, u8* data, int len);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* Stuff for putting the powerbook to sleep and waking it again.
*
@@ -208,6 +208,8 @@ struct pmu_sleep_notifier
int pmu_register_sleep_notifier(struct pmu_sleep_notifier* notifier);
int pmu_unregister_sleep_notifier(struct pmu_sleep_notifier* notifier);
+#endif /* CONFIG_PM */
+
#define PMU_MAX_BATTERIES 2
/* values for pmu_power_flags */
@@ -235,6 +237,4 @@ extern int pmu_battery_count;
extern struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
extern unsigned int pmu_power_flags;
-#endif /* CONFIG_PMAC_PBOOK */
-
#endif /* __KERNEL__ */
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index 59e505261fd6..0563581e3a02 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -74,6 +74,13 @@ struct kcore_list {
size_t size;
};
+struct vmcore {
+ struct list_head list;
+ unsigned long long paddr;
+ unsigned long size;
+ loff_t offset;
+};
+
#ifdef CONFIG_PROC_FS
extern struct proc_dir_entry proc_root;
diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h
index 22ba580b0ae8..fc610bb0f733 100644
--- a/include/linux/qnx4_fs.h
+++ b/include/linux/qnx4_fs.h
@@ -46,11 +46,11 @@ struct qnx4_inode_entry {
char di_fname[QNX4_SHORT_NAME_MAX];
qnx4_off_t di_size;
qnx4_xtnt_t di_first_xtnt;
- __u32 di_xblk;
- __s32 di_ftime;
- __s32 di_mtime;
- __s32 di_atime;
- __s32 di_ctime;
+ __le32 di_xblk;
+ __le32 di_ftime;
+ __le32 di_mtime;
+ __le32 di_atime;
+ __le32 di_ctime;
qnx4_nxtnt_t di_num_xtnts;
qnx4_mode_t di_mode;
qnx4_muid_t di_uid;
@@ -63,18 +63,18 @@ struct qnx4_inode_entry {
struct qnx4_link_info {
char dl_fname[QNX4_NAME_MAX];
- __u32 dl_inode_blk;
+ __le32 dl_inode_blk;
__u8 dl_inode_ndx;
__u8 dl_spare[10];
__u8 dl_status;
};
struct qnx4_xblk {
- __u32 xblk_next_xblk;
- __u32 xblk_prev_xblk;
+ __le32 xblk_next_xblk;
+ __le32 xblk_prev_xblk;
__u8 xblk_num_xtnts;
__u8 xblk_spare[3];
- __s32 xblk_num_blocks;
+ __le32 xblk_num_blocks;
qnx4_xtnt_t xblk_xtnts[QNX4_MAX_XTNTS_PER_XBLK];
char xblk_signature[8];
qnx4_xtnt_t xblk_first_xtnt;
diff --git a/include/linux/qnxtypes.h b/include/linux/qnxtypes.h
index fb518e318c7c..a3eb1137857b 100644
--- a/include/linux/qnxtypes.h
+++ b/include/linux/qnxtypes.h
@@ -12,18 +12,18 @@
#ifndef _QNX4TYPES_H
#define _QNX4TYPES_H
-typedef __u16 qnx4_nxtnt_t;
+typedef __le16 qnx4_nxtnt_t;
typedef __u8 qnx4_ftype_t;
typedef struct {
- __u32 xtnt_blk;
- __u32 xtnt_size;
+ __le32 xtnt_blk;
+ __le32 xtnt_size;
} qnx4_xtnt_t;
-typedef __u16 qnx4_mode_t;
-typedef __u16 qnx4_muid_t;
-typedef __u16 qnx4_mgid_t;
-typedef __u32 qnx4_off_t;
-typedef __u16 qnx4_nlink_t;
+typedef __le16 qnx4_mode_t;
+typedef __le16 qnx4_muid_t;
+typedef __le16 qnx4_mgid_t;
+typedef __le32 qnx4_off_t;
+typedef __le16 qnx4_nlink_t;
#endif
diff --git a/include/linux/quota.h b/include/linux/quota.h
index ac5b90f4f256..700ead45084f 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -138,8 +138,11 @@ struct if_dqinfo {
#include <linux/dqblk_v2.h>
/* Maximal numbers of writes for quota operation (insert/delete/update)
- * (over all formats) - info block, 4 pointer blocks, data block */
-#define DQUOT_MAX_WRITES 6
+ * (over VFS all formats) */
+#define DQUOT_INIT_ALLOC max(V1_INIT_ALLOC, V2_INIT_ALLOC)
+#define DQUOT_INIT_REWRITE max(V1_INIT_REWRITE, V2_INIT_REWRITE)
+#define DQUOT_DEL_ALLOC max(V1_DEL_ALLOC, V2_DEL_ALLOC)
+#define DQUOT_DEL_REWRITE max(V1_DEL_REWRITE, V2_DEL_REWRITE)
/*
* Data for one user/group kept in memory
diff --git a/include/linux/reboot.h b/include/linux/reboot.h
index d60fafc8bdc5..2d4dd23168dd 100644
--- a/include/linux/reboot.h
+++ b/include/linux/reboot.h
@@ -51,6 +51,10 @@ extern void machine_restart(char *cmd);
extern void machine_halt(void);
extern void machine_power_off(void);
+extern void machine_shutdown(void);
+struct pt_regs;
+extern void machine_crash_shutdown(struct pt_regs *);
+
#endif
#endif /* _LINUX_REBOOT_H */
diff --git a/include/linux/reiserfs_acl.h b/include/linux/reiserfs_acl.h
index 0760507a545b..0a3605099c44 100644
--- a/include/linux/reiserfs_acl.h
+++ b/include/linux/reiserfs_acl.h
@@ -4,29 +4,29 @@
#define REISERFS_ACL_VERSION 0x0001
typedef struct {
- __le16 e_tag;
- __le16 e_perm;
- __le32 e_id;
+ __le16 e_tag;
+ __le16 e_perm;
+ __le32 e_id;
} reiserfs_acl_entry;
typedef struct {
- __le16 e_tag;
- __le16 e_perm;
+ __le16 e_tag;
+ __le16 e_perm;
} reiserfs_acl_entry_short;
typedef struct {
- __le32 a_version;
+ __le32 a_version;
} reiserfs_acl_header;
static inline size_t reiserfs_acl_size(int count)
{
if (count <= 4) {
return sizeof(reiserfs_acl_header) +
- count * sizeof(reiserfs_acl_entry_short);
+ count * sizeof(reiserfs_acl_entry_short);
} else {
return sizeof(reiserfs_acl_header) +
- 4 * sizeof(reiserfs_acl_entry_short) +
- (count - 4) * sizeof(reiserfs_acl_entry);
+ 4 * sizeof(reiserfs_acl_entry_short) +
+ (count - 4) * sizeof(reiserfs_acl_entry);
}
}
@@ -46,14 +46,14 @@ static inline int reiserfs_acl_count(size_t size)
}
}
-
#ifdef CONFIG_REISERFS_FS_POSIX_ACL
-struct posix_acl * reiserfs_get_acl(struct inode *inode, int type);
-int reiserfs_acl_chmod (struct inode *inode);
-int reiserfs_inherit_default_acl (struct inode *dir, struct dentry *dentry, struct inode *inode);
-int reiserfs_cache_default_acl (struct inode *dir);
-extern int reiserfs_xattr_posix_acl_init (void) __init;
-extern int reiserfs_xattr_posix_acl_exit (void);
+struct posix_acl *reiserfs_get_acl(struct inode *inode, int type);
+int reiserfs_acl_chmod(struct inode *inode);
+int reiserfs_inherit_default_acl(struct inode *dir, struct dentry *dentry,
+ struct inode *inode);
+int reiserfs_cache_default_acl(struct inode *dir);
+extern int reiserfs_xattr_posix_acl_init(void) __init;
+extern int reiserfs_xattr_posix_acl_exit(void);
extern struct reiserfs_xattr_handler posix_acl_default_handler;
extern struct reiserfs_xattr_handler posix_acl_access_handler;
#else
@@ -61,28 +61,26 @@ extern struct reiserfs_xattr_handler posix_acl_access_handler;
#define reiserfs_get_acl NULL
#define reiserfs_cache_default_acl(inode) 0
-static inline int
-reiserfs_xattr_posix_acl_init (void)
+static inline int reiserfs_xattr_posix_acl_init(void)
{
- return 0;
+ return 0;
}
-static inline int
-reiserfs_xattr_posix_acl_exit (void)
+static inline int reiserfs_xattr_posix_acl_exit(void)
{
- return 0;
+ return 0;
}
-static inline int
-reiserfs_acl_chmod (struct inode *inode)
+static inline int reiserfs_acl_chmod(struct inode *inode)
{
- return 0;
+ return 0;
}
static inline int
-reiserfs_inherit_default_acl (const struct inode *dir, struct dentry *dentry, struct inode *inode)
+reiserfs_inherit_default_acl(const struct inode *dir, struct dentry *dentry,
+ struct inode *inode)
{
- return 0;
+ return 0;
}
#endif
diff --git a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
index 32148625fc2f..17e458e17e2b 100644
--- a/include/linux/reiserfs_fs.h
+++ b/include/linux/reiserfs_fs.h
@@ -3,11 +3,10 @@
*/
/* this file has an amazingly stupid
- name, yura please fix it to be
- reiserfs.h, and merge all the rest
- of our .h files that are in this
- directory into it. */
-
+ name, yura please fix it to be
+ reiserfs.h, and merge all the rest
+ of our .h files that are in this
+ directory into it. */
#ifndef _LINUX_REISER_FS_H
#define _LINUX_REISER_FS_H
@@ -74,9 +73,9 @@
/* debug levels. Right now, CONFIG_REISERFS_CHECK means print all debug
** messages.
*/
-#define REISERFS_DEBUG_CODE 5 /* extra messages to help find/debug errors */
+#define REISERFS_DEBUG_CODE 5 /* extra messages to help find/debug errors */
-void reiserfs_warning (struct super_block *s, const char * fmt, ...);
+void reiserfs_warning(struct super_block *s, const char *fmt, ...);
/* assertions handling */
/** always check a condition and panic if it's false. */
@@ -105,82 +104,78 @@ if( !( cond ) ) \
* Structure of super block on disk, a version of which in RAM is often accessed as REISERFS_SB(s)->s_rs
* the version in RAM is part of a larger structure containing fields never written to disk.
*/
-#define UNSET_HASH 0 // read_super will guess about, what hash names
- // in directories were sorted with
+#define UNSET_HASH 0 // read_super will guess about, what hash names
+ // in directories were sorted with
#define TEA_HASH 1
#define YURA_HASH 2
#define R5_HASH 3
#define DEFAULT_HASH R5_HASH
-
struct journal_params {
- __le32 jp_journal_1st_block; /* where does journal start from on its
- * device */
- __le32 jp_journal_dev; /* journal device st_rdev */
- __le32 jp_journal_size; /* size of the journal */
- __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */
- __le32 jp_journal_magic; /* random value made on fs creation (this
- * was sb_journal_block_count) */
- __le32 jp_journal_max_batch; /* max number of blocks to batch into a
- * trans */
- __le32 jp_journal_max_commit_age; /* in seconds, how old can an async
- * commit be */
- __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction
- * be */
+ __le32 jp_journal_1st_block; /* where does journal start from on its
+ * device */
+ __le32 jp_journal_dev; /* journal device st_rdev */
+ __le32 jp_journal_size; /* size of the journal */
+ __le32 jp_journal_trans_max; /* max number of blocks in a transaction. */
+ __le32 jp_journal_magic; /* random value made on fs creation (this
+ * was sb_journal_block_count) */
+ __le32 jp_journal_max_batch; /* max number of blocks to batch into a
+ * trans */
+ __le32 jp_journal_max_commit_age; /* in seconds, how old can an async
+ * commit be */
+ __le32 jp_journal_max_trans_age; /* in seconds, how old can a transaction
+ * be */
};
/* this is the super from 3.5.X, where X >= 10 */
-struct reiserfs_super_block_v1
-{
- __le32 s_block_count; /* blocks count */
- __le32 s_free_blocks; /* free blocks count */
- __le32 s_root_block; /* root block number */
- struct journal_params s_journal;
- __le16 s_blocksize; /* block size */
- __le16 s_oid_maxsize; /* max size of object id array, see
- * get_objectid() commentary */
- __le16 s_oid_cursize; /* current size of object id array */
- __le16 s_umount_state; /* this is set to 1 when filesystem was
- * umounted, to 2 - when not */
- char s_magic[10]; /* reiserfs magic string indicates that
- * file system is reiserfs:
- * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
- __le16 s_fs_state; /* it is set to used by fsck to mark which
- * phase of rebuilding is done */
- __le32 s_hash_function_code; /* indicate, what hash function is being use
- * to sort names in a directory*/
- __le16 s_tree_height; /* height of disk tree */
- __le16 s_bmap_nr; /* amount of bitmap blocks needed to address
- * each block of file system */
- __le16 s_version; /* this field is only reliable on filesystem
- * with non-standard journal */
- __le16 s_reserved_for_journal; /* size in blocks of journal area on main
- * device, we need to keep after
- * making fs with non-standard journal */
+struct reiserfs_super_block_v1 {
+ __le32 s_block_count; /* blocks count */
+ __le32 s_free_blocks; /* free blocks count */
+ __le32 s_root_block; /* root block number */
+ struct journal_params s_journal;
+ __le16 s_blocksize; /* block size */
+ __le16 s_oid_maxsize; /* max size of object id array, see
+ * get_objectid() commentary */
+ __le16 s_oid_cursize; /* current size of object id array */
+ __le16 s_umount_state; /* this is set to 1 when filesystem was
+ * umounted, to 2 - when not */
+ char s_magic[10]; /* reiserfs magic string indicates that
+ * file system is reiserfs:
+ * "ReIsErFs" or "ReIsEr2Fs" or "ReIsEr3Fs" */
+ __le16 s_fs_state; /* it is set to used by fsck to mark which
+ * phase of rebuilding is done */
+ __le32 s_hash_function_code; /* indicate, what hash function is being use
+ * to sort names in a directory*/
+ __le16 s_tree_height; /* height of disk tree */
+ __le16 s_bmap_nr; /* amount of bitmap blocks needed to address
+ * each block of file system */
+ __le16 s_version; /* this field is only reliable on filesystem
+ * with non-standard journal */
+ __le16 s_reserved_for_journal; /* size in blocks of journal area on main
+ * device, we need to keep after
+ * making fs with non-standard journal */
} __attribute__ ((__packed__));
#define SB_SIZE_V1 (sizeof(struct reiserfs_super_block_v1))
/* this is the on disk super block */
-struct reiserfs_super_block
-{
- struct reiserfs_super_block_v1 s_v1;
- __le32 s_inode_generation;
- __le32 s_flags; /* Right now used only by inode-attributes, if enabled */
- unsigned char s_uuid[16]; /* filesystem unique identifier */
- unsigned char s_label[16]; /* filesystem volume label */
- char s_unused[88] ; /* zero filled by mkreiserfs and
- * reiserfs_convert_objectid_map_v1()
- * so any additions must be updated
- * there as well. */
-} __attribute__ ((__packed__));
+struct reiserfs_super_block {
+ struct reiserfs_super_block_v1 s_v1;
+ __le32 s_inode_generation;
+ __le32 s_flags; /* Right now used only by inode-attributes, if enabled */
+ unsigned char s_uuid[16]; /* filesystem unique identifier */
+ unsigned char s_label[16]; /* filesystem volume label */
+ char s_unused[88]; /* zero filled by mkreiserfs and
+ * reiserfs_convert_objectid_map_v1()
+ * so any additions must be updated
+ * there as well. */
+} __attribute__ ((__packed__));
#define SB_SIZE (sizeof(struct reiserfs_super_block))
#define REISERFS_VERSION_1 0
#define REISERFS_VERSION_2 2
-
// on-disk super block fields converted to cpu form
#define SB_DISK_SUPER_BLOCK(s) (REISERFS_SB(s)->s_rs)
#define SB_V1_DISK_SUPER_BLOCK(s) (&(SB_DISK_SUPER_BLOCK(s)->s_v1))
@@ -210,13 +205,12 @@ struct reiserfs_super_block
#define PUT_SB_TREE_HEIGHT(s, val) \
do { SB_V1_DISK_SUPER_BLOCK(s)->s_tree_height = cpu_to_le16(val); } while (0)
#define PUT_SB_REISERFS_STATE(s, val) \
- do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
+ do { SB_V1_DISK_SUPER_BLOCK(s)->s_umount_state = cpu_to_le16(val); } while (0)
#define PUT_SB_VERSION(s, val) \
do { SB_V1_DISK_SUPER_BLOCK(s)->s_version = cpu_to_le16(val); } while (0)
#define PUT_SB_BMAP_NR(s, val) \
do { SB_V1_DISK_SUPER_BLOCK(s)->s_bmap_nr = cpu_to_le16 (val); } while (0)
-
#define SB_ONDISK_JP(s) (&SB_V1_DISK_SUPER_BLOCK(s)->s_journal)
#define SB_ONDISK_JOURNAL_SIZE(s) \
le32_to_cpu ((SB_ONDISK_JP(s)->jp_journal_size))
@@ -231,21 +225,19 @@ struct reiserfs_super_block
block >= SB_JOURNAL_1st_RESERVED_BLOCK(s) \
&& block < SB_JOURNAL_1st_RESERVED_BLOCK(s) + \
((!is_reiserfs_jr(SB_DISK_SUPER_BLOCK(s)) ? \
- SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
-
-
+ SB_ONDISK_JOURNAL_SIZE(s) + 1 : SB_ONDISK_RESERVED_FOR_JOURNAL(s)))
/* used by gcc */
#define REISERFS_SUPER_MAGIC 0x52654973
/* used by file system utilities that
- look at the superblock, etc. */
+ look at the superblock, etc. */
#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
#define REISER2FS_JR_SUPER_MAGIC_STRING "ReIsEr3Fs"
-int is_reiserfs_3_5 (struct reiserfs_super_block * rs);
-int is_reiserfs_3_6 (struct reiserfs_super_block * rs);
-int is_reiserfs_jr (struct reiserfs_super_block * rs);
+int is_reiserfs_3_5(struct reiserfs_super_block *rs);
+int is_reiserfs_3_6(struct reiserfs_super_block *rs);
+int is_reiserfs_jr(struct reiserfs_super_block *rs);
/* ReiserFS leaves the first 64k unused, so that partition labels have
enough space. If someone wants to write a fancy bootloader that
@@ -272,8 +264,8 @@ typedef __u32 b_blocknr_t;
typedef __le32 unp_t;
struct unfm_nodeinfo {
- unp_t unfm_nodenum;
- unsigned short unfm_freespace;
+ unp_t unfm_nodenum;
+ unsigned short unfm_freespace;
};
/* there are two formats of keys: 3.5 and 3.6
@@ -285,7 +277,6 @@ struct unfm_nodeinfo {
#define STAT_DATA_V1 0
#define STAT_DATA_V2 1
-
static inline struct reiserfs_inode_info *REISERFS_I(const struct inode *inode)
{
return container_of(inode, struct reiserfs_inode_info, vfs_inode);
@@ -343,15 +334,13 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
file would fit into one DIRECT item.
Primary intention for this one is to increase performance by decreasing
seeking.
-*/
+*/
#define STORE_TAIL_IN_UNFM_S2(n_file_size,n_tail_size,n_block_size) \
(\
(!(n_tail_size)) || \
(((n_file_size) > MAX_DIRECT_ITEM_LEN(n_block_size)) ) \
)
-
-
/*
* values for s_umount_state field
*/
@@ -364,9 +353,9 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
#define TYPE_STAT_DATA 0
#define TYPE_INDIRECT 1
#define TYPE_DIRECT 2
-#define TYPE_DIRENTRY 3
-#define TYPE_MAXTYPE 3
-#define TYPE_ANY 15 // FIXME: comment is required
+#define TYPE_DIRENTRY 3
+#define TYPE_MAXTYPE 3
+#define TYPE_ANY 15 // FIXME: comment is required
/***************************************************************************/
/* KEY & ITEM HEAD */
@@ -376,60 +365,62 @@ static inline struct reiserfs_sb_info *REISERFS_SB(const struct super_block *sb)
// directories use this key as well as old files
//
struct offset_v1 {
- __le32 k_offset;
- __le32 k_uniqueness;
+ __le32 k_offset;
+ __le32 k_uniqueness;
} __attribute__ ((__packed__));
struct offset_v2 {
__le64 v;
} __attribute__ ((__packed__));
-static inline __u16 offset_v2_k_type( const struct offset_v2 *v2 )
+static inline __u16 offset_v2_k_type(const struct offset_v2 *v2)
{
__u8 type = le64_to_cpu(v2->v) >> 60;
- return (type <= TYPE_MAXTYPE)?type:TYPE_ANY;
+ return (type <= TYPE_MAXTYPE) ? type : TYPE_ANY;
}
-
-static inline void set_offset_v2_k_type( struct offset_v2 *v2, int type )
+
+static inline void set_offset_v2_k_type(struct offset_v2 *v2, int type)
{
- v2->v = (v2->v & cpu_to_le64(~0ULL>>4)) | cpu_to_le64((__u64)type<<60);
+ v2->v =
+ (v2->v & cpu_to_le64(~0ULL >> 4)) | cpu_to_le64((__u64) type << 60);
}
-
-static inline loff_t offset_v2_k_offset( const struct offset_v2 *v2 )
+
+static inline loff_t offset_v2_k_offset(const struct offset_v2 *v2)
{
- return le64_to_cpu(v2->v) & (~0ULL>>4);
+ return le64_to_cpu(v2->v) & (~0ULL >> 4);
}
-static inline void set_offset_v2_k_offset( struct offset_v2 *v2, loff_t offset ){
- offset &= (~0ULL>>4);
- v2->v = (v2->v & cpu_to_le64(15ULL<<60)) | cpu_to_le64(offset);
+static inline void set_offset_v2_k_offset(struct offset_v2 *v2, loff_t offset)
+{
+ offset &= (~0ULL >> 4);
+ v2->v = (v2->v & cpu_to_le64(15ULL << 60)) | cpu_to_le64(offset);
}
/* Key of an item determines its location in the S+tree, and
is composed of 4 components */
struct reiserfs_key {
- __le32 k_dir_id; /* packing locality: by default parent
- directory object id */
- __le32 k_objectid; /* object identifier */
- union {
- struct offset_v1 k_offset_v1;
- struct offset_v2 k_offset_v2;
- } __attribute__ ((__packed__)) u;
+ __le32 k_dir_id; /* packing locality: by default parent
+ directory object id */
+ __le32 k_objectid; /* object identifier */
+ union {
+ struct offset_v1 k_offset_v1;
+ struct offset_v2 k_offset_v2;
+ } __attribute__ ((__packed__)) u;
} __attribute__ ((__packed__));
struct in_core_key {
- __u32 k_dir_id; /* packing locality: by default parent
- directory object id */
- __u32 k_objectid; /* object identifier */
- __u64 k_offset;
- __u8 k_type;
+ __u32 k_dir_id; /* packing locality: by default parent
+ directory object id */
+ __u32 k_objectid; /* object identifier */
+ __u64 k_offset;
+ __u8 k_type;
};
struct cpu_key {
- struct in_core_key on_disk_key;
- int version;
- int key_length; /* 3 in all cases but direct2indirect and
- indirect2direct conversion */
+ struct in_core_key on_disk_key;
+ int version;
+ int key_length; /* 3 in all cases but direct2indirect and
+ indirect2direct conversion */
};
/* Our function for comparing keys can compare keys of different
@@ -475,8 +466,7 @@ struct cpu_key {
indirect items) and specifies the location of the item itself
within the block. */
-struct item_head
-{
+struct item_head {
/* Everything in the tree is found by searching for it based on
* its key.*/
struct reiserfs_key ih_key;
@@ -492,13 +482,13 @@ struct item_head
number of directory entries in the directory item. */
__le16 ih_entry_count;
} __attribute__ ((__packed__)) u;
- __le16 ih_item_len; /* total size of the item body */
- __le16 ih_item_location; /* an offset to the item body
- * within the block */
- __le16 ih_version; /* 0 for all old items, 2 for new
- ones. Highest bit is set by fsck
- temporary, cleaned after all
- done */
+ __le16 ih_item_len; /* total size of the item body */
+ __le16 ih_item_location; /* an offset to the item body
+ * within the block */
+ __le16 ih_version; /* 0 for all old items, 2 for new
+ ones. Highest bit is set by fsck
+ temporary, cleaned after all
+ done */
} __attribute__ ((__packed__));
/* size of item header */
#define IH_SIZE (sizeof(struct item_head))
@@ -515,7 +505,6 @@ struct item_head
#define put_ih_location(ih, val) do { (ih)->ih_item_location = cpu_to_le16(val); } while (0)
#define put_ih_item_len(ih, val) do { (ih)->ih_item_len = cpu_to_le16(val); } while (0)
-
#define unreachable_item(ih) (ih_version(ih) & (1 << 15))
#define get_ih_free_space(ih) (ih_version (ih) == KEY_FORMAT_3_6 ? 0 : ih_free_space (ih))
@@ -537,40 +526,48 @@ struct item_head
#define V1_INDIRECT_UNIQUENESS 0xfffffffe
#define V1_DIRECT_UNIQUENESS 0xffffffff
#define V1_DIRENTRY_UNIQUENESS 500
-#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required
+#define V1_ANY_UNIQUENESS 555 // FIXME: comment is required
//
// here are conversion routines
//
-static inline int uniqueness2type (__u32 uniqueness) CONSTF;
-static inline int uniqueness2type (__u32 uniqueness)
+static inline int uniqueness2type(__u32 uniqueness) CONSTF;
+static inline int uniqueness2type(__u32 uniqueness)
{
- switch ((int)uniqueness) {
- case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
- case V1_INDIRECT_UNIQUENESS: return TYPE_INDIRECT;
- case V1_DIRECT_UNIQUENESS: return TYPE_DIRECT;
- case V1_DIRENTRY_UNIQUENESS: return TYPE_DIRENTRY;
- default:
- reiserfs_warning (NULL, "vs-500: unknown uniqueness %d",
- uniqueness);
+ switch ((int)uniqueness) {
+ case V1_SD_UNIQUENESS:
+ return TYPE_STAT_DATA;
+ case V1_INDIRECT_UNIQUENESS:
+ return TYPE_INDIRECT;
+ case V1_DIRECT_UNIQUENESS:
+ return TYPE_DIRECT;
+ case V1_DIRENTRY_UNIQUENESS:
+ return TYPE_DIRENTRY;
+ default:
+ reiserfs_warning(NULL, "vs-500: unknown uniqueness %d",
+ uniqueness);
case V1_ANY_UNIQUENESS:
- return TYPE_ANY;
- }
+ return TYPE_ANY;
+ }
}
-static inline __u32 type2uniqueness (int type) CONSTF;
-static inline __u32 type2uniqueness (int type)
+static inline __u32 type2uniqueness(int type) CONSTF;
+static inline __u32 type2uniqueness(int type)
{
- switch (type) {
- case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
- case TYPE_INDIRECT: return V1_INDIRECT_UNIQUENESS;
- case TYPE_DIRECT: return V1_DIRECT_UNIQUENESS;
- case TYPE_DIRENTRY: return V1_DIRENTRY_UNIQUENESS;
- default:
- reiserfs_warning (NULL, "vs-501: unknown type %d", type);
+ switch (type) {
+ case TYPE_STAT_DATA:
+ return V1_SD_UNIQUENESS;
+ case TYPE_INDIRECT:
+ return V1_INDIRECT_UNIQUENESS;
+ case TYPE_DIRECT:
+ return V1_DIRECT_UNIQUENESS;
+ case TYPE_DIRENTRY:
+ return V1_DIRENTRY_UNIQUENESS;
+ default:
+ reiserfs_warning(NULL, "vs-501: unknown type %d", type);
case TYPE_ANY:
- return V1_ANY_UNIQUENESS;
- }
+ return V1_ANY_UNIQUENESS;
+ }
}
//
@@ -578,57 +575,56 @@ static inline __u32 type2uniqueness (int type)
// there is no way to get version of object from key, so, provide
// version to these defines
//
-static inline loff_t le_key_k_offset (int version, const struct reiserfs_key * key)
+static inline loff_t le_key_k_offset(int version,
+ const struct reiserfs_key *key)
{
- return (version == KEY_FORMAT_3_5) ?
- le32_to_cpu( key->u.k_offset_v1.k_offset ) :
- offset_v2_k_offset( &(key->u.k_offset_v2) );
+ return (version == KEY_FORMAT_3_5) ?
+ le32_to_cpu(key->u.k_offset_v1.k_offset) :
+ offset_v2_k_offset(&(key->u.k_offset_v2));
}
-static inline loff_t le_ih_k_offset (const struct item_head * ih)
+static inline loff_t le_ih_k_offset(const struct item_head *ih)
{
- return le_key_k_offset (ih_version (ih), &(ih->ih_key));
+ return le_key_k_offset(ih_version(ih), &(ih->ih_key));
}
-static inline loff_t le_key_k_type (int version, const struct reiserfs_key * key)
+static inline loff_t le_key_k_type(int version, const struct reiserfs_key *key)
{
- return (version == KEY_FORMAT_3_5) ?
- uniqueness2type( le32_to_cpu( key->u.k_offset_v1.k_uniqueness)) :
- offset_v2_k_type( &(key->u.k_offset_v2) );
+ return (version == KEY_FORMAT_3_5) ?
+ uniqueness2type(le32_to_cpu(key->u.k_offset_v1.k_uniqueness)) :
+ offset_v2_k_type(&(key->u.k_offset_v2));
}
-static inline loff_t le_ih_k_type (const struct item_head * ih)
+static inline loff_t le_ih_k_type(const struct item_head *ih)
{
- return le_key_k_type (ih_version (ih), &(ih->ih_key));
+ return le_key_k_type(ih_version(ih), &(ih->ih_key));
}
-
-static inline void set_le_key_k_offset (int version, struct reiserfs_key * key, loff_t offset)
+static inline void set_le_key_k_offset(int version, struct reiserfs_key *key,
+ loff_t offset)
{
- (version == KEY_FORMAT_3_5) ?
- (void)(key->u.k_offset_v1.k_offset = cpu_to_le32 (offset)) : /* jdm check */
- (void)(set_offset_v2_k_offset( &(key->u.k_offset_v2), offset ));
+ (version == KEY_FORMAT_3_5) ? (void)(key->u.k_offset_v1.k_offset = cpu_to_le32(offset)) : /* jdm check */
+ (void)(set_offset_v2_k_offset(&(key->u.k_offset_v2), offset));
}
-
-static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
+static inline void set_le_ih_k_offset(struct item_head *ih, loff_t offset)
{
- set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
+ set_le_key_k_offset(ih_version(ih), &(ih->ih_key), offset);
}
-
-static inline void set_le_key_k_type (int version, struct reiserfs_key * key, int type)
+static inline void set_le_key_k_type(int version, struct reiserfs_key *key,
+ int type)
{
- (version == KEY_FORMAT_3_5) ?
- (void)(key->u.k_offset_v1.k_uniqueness = cpu_to_le32(type2uniqueness(type))):
- (void)(set_offset_v2_k_type( &(key->u.k_offset_v2), type ));
+ (version == KEY_FORMAT_3_5) ?
+ (void)(key->u.k_offset_v1.k_uniqueness =
+ cpu_to_le32(type2uniqueness(type)))
+ : (void)(set_offset_v2_k_type(&(key->u.k_offset_v2), type));
}
-static inline void set_le_ih_k_type (struct item_head * ih, int type)
+static inline void set_le_ih_k_type(struct item_head *ih, int type)
{
- set_le_key_k_type (ih_version (ih), &(ih->ih_key), type);
+ set_le_key_k_type(ih_version(ih), &(ih->ih_key), type);
}
-
#define is_direntry_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRENTRY)
#define is_direct_le_key(version,key) (le_key_k_type (version, key) == TYPE_DIRECT)
#define is_indirect_le_key(version,key) (le_key_k_type (version, key) == TYPE_INDIRECT)
@@ -642,34 +638,32 @@ static inline void set_le_ih_k_type (struct item_head * ih, int type)
#define is_indirect_le_ih(ih) is_indirect_le_key (ih_version(ih), &((ih)->ih_key))
#define is_statdata_le_ih(ih) is_statdata_le_key (ih_version (ih), &((ih)->ih_key))
-
-
//
// key is pointer to cpu key, result is cpu
//
-static inline loff_t cpu_key_k_offset (const struct cpu_key * key)
+static inline loff_t cpu_key_k_offset(const struct cpu_key *key)
{
- return key->on_disk_key.k_offset;
+ return key->on_disk_key.k_offset;
}
-static inline loff_t cpu_key_k_type (const struct cpu_key * key)
+static inline loff_t cpu_key_k_type(const struct cpu_key *key)
{
- return key->on_disk_key.k_type;
+ return key->on_disk_key.k_type;
}
-static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
+static inline void set_cpu_key_k_offset(struct cpu_key *key, loff_t offset)
{
key->on_disk_key.k_offset = offset;
}
-static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
+static inline void set_cpu_key_k_type(struct cpu_key *key, int type)
{
key->on_disk_key.k_type = type;
}
-static inline void cpu_key_k_offset_dec (struct cpu_key * key)
+static inline void cpu_key_k_offset_dec(struct cpu_key *key)
{
- key->on_disk_key.k_offset --;
+ key->on_disk_key.k_offset--;
}
#define is_direntry_cpu_key(key) (cpu_key_k_type (key) == TYPE_DIRENTRY)
@@ -677,34 +671,25 @@ static inline void cpu_key_k_offset_dec (struct cpu_key * key)
#define is_indirect_cpu_key(key) (cpu_key_k_type (key) == TYPE_INDIRECT)
#define is_statdata_cpu_key(key) (cpu_key_k_type (key) == TYPE_STAT_DATA)
-
/* are these used ? */
#define is_direntry_cpu_ih(ih) (is_direntry_cpu_key (&((ih)->ih_key)))
#define is_direct_cpu_ih(ih) (is_direct_cpu_key (&((ih)->ih_key)))
#define is_indirect_cpu_ih(ih) (is_indirect_cpu_key (&((ih)->ih_key)))
#define is_statdata_cpu_ih(ih) (is_statdata_cpu_key (&((ih)->ih_key)))
-
-
-
-
#define I_K_KEY_IN_ITEM(p_s_ih, p_s_key, n_blocksize) \
( ! COMP_SHORT_KEYS(p_s_ih, p_s_key) && \
I_OFF_BYTE_IN_ITEM(p_s_ih, k_offset (p_s_key), n_blocksize) )
-/* maximal length of item */
+/* maximal length of item */
#define MAX_ITEM_LEN(block_size) (block_size - BLKH_SIZE - IH_SIZE)
#define MIN_ITEM_LEN 1
-
/* object identifier for root dir */
#define REISERFS_ROOT_OBJECTID 2
#define REISERFS_ROOT_PARENT_OBJECTID 1
extern struct reiserfs_key root_key;
-
-
-
/*
* Picture represents a leaf of the S+tree
* ______________________________________________________
@@ -716,13 +701,13 @@ extern struct reiserfs_key root_key;
/* Header of a disk block. More precisely, header of a formatted leaf
or internal node, and not the header of an unformatted node. */
-struct block_head {
- __le16 blk_level; /* Level of a block in the tree. */
- __le16 blk_nr_item; /* Number of keys/items in a block. */
- __le16 blk_free_space; /* Block free space in bytes. */
- __le16 blk_reserved;
- /* dump this in v4/planA */
- struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */
+struct block_head {
+ __le16 blk_level; /* Level of a block in the tree. */
+ __le16 blk_nr_item; /* Number of keys/items in a block. */
+ __le16 blk_free_space; /* Block free space in bytes. */
+ __le16 blk_reserved;
+ /* dump this in v4/planA */
+ struct reiserfs_key blk_right_delim_key; /* kept only for compatibility */
};
#define BLKH_SIZE (sizeof(struct block_head))
@@ -741,12 +726,12 @@ struct block_head {
* values for blk_level field of the struct block_head
*/
-#define FREE_LEVEL 0 /* when node gets removed from the tree its
- blk_level is set to FREE_LEVEL. It is then
- used to see whether the node is still in the
- tree */
+#define FREE_LEVEL 0 /* when node gets removed from the tree its
+ blk_level is set to FREE_LEVEL. It is then
+ used to see whether the node is still in the
+ tree */
-#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level.*/
+#define DISK_LEAF_NODE_LEVEL 1 /* Leaf node level. */
/* Given the buffer head of a formatted node, resolve to the block head of that node. */
#define B_BLK_HEAD(p_s_bh) ((struct block_head *)((p_s_bh)->b_data))
@@ -759,7 +744,6 @@ struct block_head {
#define PUT_B_LEVEL(p_s_bh,val) do { set_blkh_level(B_BLK_HEAD(p_s_bh),val); } while (0)
#define PUT_B_FREE_SPACE(p_s_bh,val) do { set_blkh_free_space(B_BLK_HEAD(p_s_bh),val); } while (0)
-
/* Get right delimiting key. -- little endian */
#define B_PRIGHT_DELIM_KEY(p_s_bh) (&(blk_right_delim_key(B_BLK_HEAD(p_s_bh))
@@ -770,41 +754,36 @@ struct block_head {
#define B_IS_KEYS_LEVEL(p_s_bh) (B_LEVEL(p_s_bh) > DISK_LEAF_NODE_LEVEL \
&& B_LEVEL(p_s_bh) <= MAX_HEIGHT)
-
-
-
/***************************************************************************/
/* STAT DATA */
/***************************************************************************/
-
//
// old stat data is 32 bytes long. We are going to distinguish new one by
// different size
//
-struct stat_data_v1
-{
- __le16 sd_mode; /* file type, permissions */
- __le16 sd_nlink; /* number of hard links */
- __le16 sd_uid; /* owner */
- __le16 sd_gid; /* group */
- __le32 sd_size; /* file size */
- __le32 sd_atime; /* time of last access */
- __le32 sd_mtime; /* time file was last modified */
- __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
- union {
- __le32 sd_rdev;
- __le32 sd_blocks; /* number of blocks file uses */
- } __attribute__ ((__packed__)) u;
- __le32 sd_first_direct_byte; /* first byte of file which is stored
- in a direct item: except that if it
- equals 1 it is a symlink and if it
- equals ~(__u32)0 there is no
- direct item. The existence of this
- field really grates on me. Let's
- replace it with a macro based on
- sd_size and our tail suppression
- policy. Someday. -Hans */
+struct stat_data_v1 {
+ __le16 sd_mode; /* file type, permissions */
+ __le16 sd_nlink; /* number of hard links */
+ __le16 sd_uid; /* owner */
+ __le16 sd_gid; /* group */
+ __le32 sd_size; /* file size */
+ __le32 sd_atime; /* time of last access */
+ __le32 sd_mtime; /* time file was last modified */
+ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+ union {
+ __le32 sd_rdev;
+ __le32 sd_blocks; /* number of blocks file uses */
+ } __attribute__ ((__packed__)) u;
+ __le32 sd_first_direct_byte; /* first byte of file which is stored
+ in a direct item: except that if it
+ equals 1 it is a symlink and if it
+ equals ~(__u32)0 there is no
+ direct item. The existence of this
+ field really grates on me. Let's
+ replace it with a macro based on
+ sd_size and our tail suppression
+ policy. Someday. -Hans */
} __attribute__ ((__packed__));
#define SD_V1_SIZE (sizeof(struct stat_data_v1))
@@ -862,29 +841,29 @@ struct stat_data_v1
/* Stat Data on disk (reiserfs version of UFS disk inode minus the
address blocks) */
struct stat_data {
- __le16 sd_mode; /* file type, permissions */
- __le16 sd_attrs; /* persistent inode flags */
- __le32 sd_nlink; /* number of hard links */
- __le64 sd_size; /* file size */
- __le32 sd_uid; /* owner */
- __le32 sd_gid; /* group */
- __le32 sd_atime; /* time of last access */
- __le32 sd_mtime; /* time file was last modified */
- __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
- __le32 sd_blocks;
- union {
- __le32 sd_rdev;
- __le32 sd_generation;
- //__le32 sd_first_direct_byte;
- /* first byte of file which is stored in a
- direct item: except that if it equals 1
- it is a symlink and if it equals
- ~(__u32)0 there is no direct item. The
- existence of this field really grates
- on me. Let's replace it with a macro
- based on sd_size and our tail
- suppression policy? */
- } __attribute__ ((__packed__)) u;
+ __le16 sd_mode; /* file type, permissions */
+ __le16 sd_attrs; /* persistent inode flags */
+ __le32 sd_nlink; /* number of hard links */
+ __le64 sd_size; /* file size */
+ __le32 sd_uid; /* owner */
+ __le32 sd_gid; /* group */
+ __le32 sd_atime; /* time of last access */
+ __le32 sd_mtime; /* time file was last modified */
+ __le32 sd_ctime; /* time inode (stat data) was last changed (except changes to sd_atime and sd_mtime) */
+ __le32 sd_blocks;
+ union {
+ __le32 sd_rdev;
+ __le32 sd_generation;
+ //__le32 sd_first_direct_byte;
+ /* first byte of file which is stored in a
+ direct item: except that if it equals 1
+ it is a symlink and if it equals
+ ~(__u32)0 there is no direct item. The
+ existence of this field really grates
+ on me. Let's replace it with a macro
+ based on sd_size and our tail
+ suppression policy? */
+ } __attribute__ ((__packed__)) u;
} __attribute__ ((__packed__));
//
// this is 44 bytes long
@@ -919,7 +898,6 @@ struct stat_data {
#define sd_v2_attrs(sdp) (le16_to_cpu((sdp)->sd_attrs))
#define set_sd_v2_attrs(sdp,v) ((sdp)->sd_attrs = cpu_to_le16(v))
-
/***************************************************************************/
/* DIRECTORY STRUCTURE */
/***************************************************************************/
@@ -954,17 +932,14 @@ struct stat_data {
/* NOT IMPLEMENTED:
Directory will someday contain stat data of object */
-
-
-struct reiserfs_de_head
-{
- __le32 deh_offset; /* third component of the directory entry key */
- __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced
- by directory entry */
- __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */
- __le16 deh_location; /* offset of name in the whole item */
- __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether
- entry is hidden (unlinked) */
+struct reiserfs_de_head {
+ __le32 deh_offset; /* third component of the directory entry key */
+ __le32 deh_dir_id; /* objectid of the parent directory of the object, that is referenced
+ by directory entry */
+ __le32 deh_objectid; /* objectid of the object, that is referenced by directory entry */
+ __le16 deh_location; /* offset of name in the whole item */
+ __le16 deh_state; /* whether 1) entry contains stat data (for future), and 2) whether
+ entry is hidden (unlinked) */
} __attribute__ ((__packed__));
#define DEH_SIZE sizeof(struct reiserfs_de_head)
#define deh_offset(p_deh) (le32_to_cpu((p_deh)->deh_offset))
@@ -986,7 +961,7 @@ struct reiserfs_de_head
/* old format directories have this size when empty */
#define EMPTY_DIR_SIZE_V1 (DEH_SIZE * 2 + 3)
-#define DEH_Statdata 0 /* not used now */
+#define DEH_Statdata 0 /* not used now */
#define DEH_Visible 2
/* 64 bit systems (and the S/390) need to be aligned explicitly -jdm */
@@ -1023,10 +998,10 @@ struct reiserfs_de_head
#define de_visible(deh) test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
#define de_hidden(deh) !test_bit_unaligned (DEH_Visible, &((deh)->deh_state))
-extern void make_empty_dir_item_v1 (char * body, __le32 dirid, __le32 objid,
- __le32 par_dirid, __le32 par_objid);
-extern void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
- __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item_v1(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid);
+extern void make_empty_dir_item(char *body, __le32 dirid, __le32 objid,
+ __le32 par_dirid, __le32 par_objid);
/* array of the entry headers */
/* get item body */
@@ -1043,53 +1018,48 @@ extern void make_empty_dir_item (char * body, __le32 dirid, __le32 objid,
#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
((i) ? (deh_location((deh)-1) - deh_location((deh))) : (ih_item_len((ih)) - deh_location((deh))))
*/
-static inline int entry_length (const struct buffer_head * bh,
- const struct item_head * ih, int pos_in_item)
+static inline int entry_length(const struct buffer_head *bh,
+ const struct item_head *ih, int pos_in_item)
{
- struct reiserfs_de_head * deh;
+ struct reiserfs_de_head *deh;
- deh = B_I_DEH (bh, ih) + pos_in_item;
- if (pos_in_item)
- return deh_location(deh-1) - deh_location(deh);
+ deh = B_I_DEH(bh, ih) + pos_in_item;
+ if (pos_in_item)
+ return deh_location(deh - 1) - deh_location(deh);
- return ih_item_len(ih) - deh_location(deh);
+ return ih_item_len(ih) - deh_location(deh);
}
-
-
/* number of entries in the directory item, depends on ENTRY_COUNT being at the start of directory dynamic data. */
#define I_ENTRY_COUNT(ih) (ih_entry_count((ih)))
-
/* name by bh, ih and entry_num */
#define B_I_E_NAME(bh,ih,entry_num) ((char *)(bh->b_data + ih_location(ih) + deh_location(B_I_DEH(bh,ih)+(entry_num))))
// two entries per block (at least)
#define REISERFS_MAX_NAME(block_size) 255
-
/* this structure is used for operations on directory entries. It is
not a disk structure. */
/* When reiserfs_find_entry or search_by_entry_key find directory
entry, they return filled reiserfs_dir_entry structure */
-struct reiserfs_dir_entry
-{
- struct buffer_head * de_bh;
- int de_item_num;
- struct item_head * de_ih;
- int de_entry_num;
- struct reiserfs_de_head * de_deh;
- int de_entrylen;
- int de_namelen;
- char * de_name;
- char * de_gen_number_bit_string;
-
- __u32 de_dir_id;
- __u32 de_objectid;
-
- struct cpu_key de_entry_key;
+struct reiserfs_dir_entry {
+ struct buffer_head *de_bh;
+ int de_item_num;
+ struct item_head *de_ih;
+ int de_entry_num;
+ struct reiserfs_de_head *de_deh;
+ int de_entrylen;
+ int de_namelen;
+ char *de_name;
+ char *de_gen_number_bit_string;
+
+ __u32 de_dir_id;
+ __u32 de_objectid;
+
+ struct cpu_key de_entry_key;
};
-
+
/* these defines are useful when a particular member of a reiserfs_dir_entry is needed */
/* pointer to file name, stored in entry */
@@ -1099,8 +1069,6 @@ struct reiserfs_dir_entry
#define I_DEH_N_ENTRY_FILE_NAME_LENGTH(ih,deh,entry_num) \
(I_DEH_N_ENTRY_LENGTH (ih, deh, entry_num) - (de_with_sd (deh) ? SD_SIZE : 0))
-
-
/* hash value occupies bits from 7 up to 30 */
#define GET_HASH_VALUE(offset) ((offset) & 0x7fffff80LL)
/* generation number occupies 7 bits starting from 0 up to 6 */
@@ -1109,7 +1077,6 @@ struct reiserfs_dir_entry
#define SET_GENERATION_NUMBER(offset,gen_number) (GET_HASH_VALUE(offset)|(gen_number))
-
/*
* Picture represents an internal node of the reiserfs tree
* ______________________________________________________
@@ -1125,9 +1092,9 @@ struct reiserfs_dir_entry
/* Disk child pointer: The pointer from an internal node of the tree
to a node that is on disk. */
struct disk_child {
- __le32 dc_block_number; /* Disk child's block number. */
- __le16 dc_size; /* Disk child's used space. */
- __le16 dc_reserved;
+ __le32 dc_block_number; /* Disk child's block number. */
+ __le16 dc_size; /* Disk child's used space. */
+ __le16 dc_reserved;
};
#define DC_SIZE (sizeof(struct disk_child))
@@ -1144,7 +1111,7 @@ struct disk_child {
#define B_N_CHILD_NUM(p_s_bh,n_pos) (dc_block_number(B_N_CHILD(p_s_bh,n_pos)))
#define PUT_B_N_CHILD_NUM(p_s_bh,n_pos, val) (put_dc_block_number(B_N_CHILD(p_s_bh,n_pos), val ))
- /* maximal value of field child_size in structure disk_child */
+ /* maximal value of field child_size in structure disk_child */
/* child size is the combined size of all items and their headers */
#define MAX_CHILD_SIZE(bh) ((int)( (bh)->b_size - BLKH_SIZE ))
@@ -1159,7 +1126,6 @@ struct disk_child {
/* PATH STRUCTURES AND DEFINES */
/***************************************************************************/
-
/* Search_by_key fills up the path from the root to the leaf as it descends the tree looking for the
key. It uses reiserfs_bread to try to find buffers in the cache given their block number. If it
does not find them in the cache it reads them from disk. For each node search_by_key finds using
@@ -1168,20 +1134,18 @@ struct disk_child {
is looking through a leaf node bin_search will find the position of the item which has key either
equal to given key, or which is the maximal key less than the given key. */
-struct path_element {
- struct buffer_head * pe_buffer; /* Pointer to the buffer at the path in the tree. */
- int pe_position; /* Position in the tree node which is placed in the */
- /* buffer above. */
+struct path_element {
+ struct buffer_head *pe_buffer; /* Pointer to the buffer at the path in the tree. */
+ int pe_position; /* Position in the tree node which is placed in the */
+ /* buffer above. */
};
-#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
-#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
-#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */
-
-#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
-#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */
-
+#define MAX_HEIGHT 5 /* maximal height of a tree. don't change this without changing JOURNAL_PER_BALANCE_CNT */
+#define EXTENDED_MAX_HEIGHT 7 /* Must be equals MAX_HEIGHT + FIRST_PATH_ELEMENT_OFFSET */
+#define FIRST_PATH_ELEMENT_OFFSET 2 /* Must be equal to at least 2. */
+#define ILLEGAL_PATH_ELEMENT_OFFSET 1 /* Must be equal to FIRST_PATH_ELEMENT_OFFSET - 1 */
+#define MAX_FEB_SIZE 6 /* this MUST be MAX_HEIGHT + 1. See about FEB below */
/* We need to keep track of who the ancestors of nodes are. When we
perform a search we record which nodes were visited while
@@ -1200,14 +1164,14 @@ excessive effort to avoid disturbing the precious VFS code.:-( The
gods only know how we are going to SMP the code that uses them.
znodes are the way! */
-#define PATH_READA 0x1 /* do read ahead */
-#define PATH_READA_BACK 0x2 /* read backwards */
+#define PATH_READA 0x1 /* do read ahead */
+#define PATH_READA_BACK 0x2 /* read backwards */
-struct path {
- int path_length; /* Length of the array above. */
- int reada;
- struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
- int pos_in_item;
+struct path {
+ int path_length; /* Length of the array above. */
+ int reada;
+ struct path_element path_elements[EXTENDED_MAX_HEIGHT]; /* Array of the path elements. */
+ int pos_in_item;
};
#define pos_in_item(path) ((path)->pos_in_item)
@@ -1224,25 +1188,23 @@ struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
/* Get position in the element at the path by path and path position. */
#define PATH_OFFSET_POSITION(p_s_path,n_offset) (PATH_OFFSET_PELEMENT(p_s_path,n_offset)->pe_position)
-
#define PATH_PLAST_BUFFER(p_s_path) (PATH_OFFSET_PBUFFER((p_s_path), (p_s_path)->path_length))
/* you know, to the person who didn't
- write this the macro name does not
- at first suggest what it does.
- Maybe POSITION_FROM_PATH_END? Or
- maybe we should just focus on
- dumping paths... -Hans */
+ write this the macro name does not
+ at first suggest what it does.
+ Maybe POSITION_FROM_PATH_END? Or
+ maybe we should just focus on
+ dumping paths... -Hans */
#define PATH_LAST_POSITION(p_s_path) (PATH_OFFSET_POSITION((p_s_path), (p_s_path)->path_length))
-
#define PATH_PITEM_HEAD(p_s_path) B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_path),PATH_LAST_POSITION(p_s_path))
/* in do_balance leaf has h == 0 in contrast with path structure,
where root has level == 0. That is why we need these defines */
#define PATH_H_PBUFFER(p_s_path, h) PATH_OFFSET_PBUFFER (p_s_path, p_s_path->path_length - (h)) /* tb->S[h] */
-#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
-#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
-#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */
+#define PATH_H_PPARENT(path, h) PATH_H_PBUFFER (path, (h) + 1) /* tb->F[h] or tb->S[0]->b_parent */
+#define PATH_H_POSITION(path, h) PATH_OFFSET_POSITION (path, path->path_length - (h))
+#define PATH_H_B_ITEM_ORDER(path, h) PATH_H_POSITION(path, h + 1) /* tb->S[h]->b_item_order */
#define PATH_H_PATH_OFFSET(p_s_path, n_h) ((p_s_path)->path_length - (n_h))
@@ -1253,7 +1215,6 @@ struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
#define item_moved(ih,path) comp_items(ih, path)
#define path_changed(ih,path) comp_items (ih, path)
-
/***************************************************************************/
/* MISC */
/***************************************************************************/
@@ -1272,30 +1233,26 @@ struct path var = {.path_length = ILLEGAL_PATH_ELEMENT_OFFSET, .reada = 0,}
// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
#define U32_MAX (~(__u32)0)
-static inline loff_t max_reiserfs_offset (struct inode * inode)
+static inline loff_t max_reiserfs_offset(struct inode *inode)
{
- if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
- return (loff_t)U32_MAX;
+ if (get_inode_item_key_version(inode) == KEY_FORMAT_3_5)
+ return (loff_t) U32_MAX;
- return (loff_t)((~(__u64)0) >> 4);
+ return (loff_t) ((~(__u64) 0) >> 4);
}
-
/*#define MAX_KEY_UNIQUENESS MAX_UL_INT*/
#define MAX_KEY_OBJECTID MAX_UL_INT
-
#define MAX_B_NUM MAX_UL_INT
#define MAX_FC_NUM MAX_US_INT
-
/* the purpose is to detect overflow of an unsigned short */
#define REISERFS_LINK_MAX (MAX_US_INT - 1000)
-
/* The following defines are used in reiserfs_insert_item and reiserfs_append_item */
-#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */
-#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */
+#define REISERFS_KERNEL_MEM 0 /* reiserfs kernel memory mode */
+#define REISERFS_USER_MEM 1 /* reiserfs user memory mode */
#define fs_generation(s) (REISERFS_SB(s)->s_generation_counter)
#define get_generation(s) atomic_read (&fs_generation(s))
@@ -1303,7 +1260,6 @@ static inline loff_t max_reiserfs_offset (struct inode * inode)
#define __fs_changed(gen,s) (gen != get_generation (s))
#define fs_changed(gen,s) ({cond_resched(); __fs_changed(gen, s);})
-
/***************************************************************************/
/* FIXATE NODES */
/***************************************************************************/
@@ -1324,38 +1280,34 @@ static inline loff_t max_reiserfs_offset (struct inode * inode)
calculating what we can shift to neighbors and how many nodes we
have to have if we do not any shiftings, if we shift to left/right
neighbor or to both. */
-struct virtual_item
-{
- int vi_index; // index in the array of item operations
- unsigned short vi_type; // left/right mergeability
- unsigned short vi_item_len; /* length of item that it will have after balancing */
- struct item_head * vi_ih;
- const char * vi_item; // body of item (old or new)
- const void * vi_new_data; // 0 always but paste mode
- void * vi_uarea; // item specific area
+struct virtual_item {
+ int vi_index; // index in the array of item operations
+ unsigned short vi_type; // left/right mergeability
+ unsigned short vi_item_len; /* length of item that it will have after balancing */
+ struct item_head *vi_ih;
+ const char *vi_item; // body of item (old or new)
+ const void *vi_new_data; // 0 always but paste mode
+ void *vi_uarea; // item specific area
};
-
-struct virtual_node
-{
- char * vn_free_ptr; /* this is a pointer to the free space in the buffer */
- unsigned short vn_nr_item; /* number of items in virtual node */
- short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */
- short vn_mode; /* mode of balancing (paste, insert, delete, cut) */
- short vn_affected_item_num;
- short vn_pos_in_item;
- struct item_head * vn_ins_ih; /* item header of inserted item, 0 for other modes */
- const void * vn_data;
- struct virtual_item * vn_vi; /* array of items (including a new one, excluding item to be deleted) */
+struct virtual_node {
+ char *vn_free_ptr; /* this is a pointer to the free space in the buffer */
+ unsigned short vn_nr_item; /* number of items in virtual node */
+ short vn_size; /* size of node , that node would have if it has unlimited size and no balancing is performed */
+ short vn_mode; /* mode of balancing (paste, insert, delete, cut) */
+ short vn_affected_item_num;
+ short vn_pos_in_item;
+ struct item_head *vn_ins_ih; /* item header of inserted item, 0 for other modes */
+ const void *vn_data;
+ struct virtual_item *vn_vi; /* array of items (including a new one, excluding item to be deleted) */
};
/* used by directory items when creating virtual nodes */
struct direntry_uarea {
- int flags;
- __u16 entry_count;
- __u16 entry_sizes[1];
-} __attribute__ ((__packed__)) ;
-
+ int flags;
+ __u16 entry_count;
+ __u16 entry_sizes[1];
+} __attribute__ ((__packed__));
/***************************************************************************/
/* TREE BALANCE */
@@ -1378,73 +1330,72 @@ struct direntry_uarea {
#define MAX_AMOUNT_NEEDED 2
/* someday somebody will prefix every field in this struct with tb_ */
-struct tree_balance
-{
- int tb_mode;
- int need_balance_dirty;
- struct super_block * tb_sb;
- struct reiserfs_transaction_handle *transaction_handle ;
- struct path * tb_path;
- struct buffer_head * L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */
- struct buffer_head * R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path*/
- struct buffer_head * FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */
- struct buffer_head * FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */
- struct buffer_head * CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */
- struct buffer_head * CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */
-
- struct buffer_head * FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals
- cur_blknum. */
- struct buffer_head * used[MAX_FEB_SIZE];
- struct buffer_head * thrown[MAX_FEB_SIZE];
- int lnum[MAX_HEIGHT]; /* array of number of items which must be
- shifted to the left in order to balance the
- current node; for leaves includes item that
- will be partially shifted; for internal
- nodes, it is the number of child pointers
- rather than items. It includes the new item
- being created. The code sometimes subtracts
- one to get the number of wholly shifted
- items for other purposes. */
- int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */
- int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and
- S[h] to its item number within the node CFL[h] */
- int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */
- int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from
- S[h]. A negative value means removing. */
- int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
- balancing on the level h of the tree. If 0 then S is
- being deleted, if 1 then S is remaining and no new nodes
- are being created, if 2 or 3 then 1 or 2 new nodes is
- being created */
-
- /* fields that are used only for balancing leaves of the tree */
- int cur_blknum; /* number of empty blocks having been already allocated */
- int s0num; /* number of items that fall into left most node when S[0] splits */
- int s1num; /* number of items that fall into first new node when S[0] splits */
- int s2num; /* number of items that fall into second new node when S[0] splits */
- int lbytes; /* number of bytes which can flow to the left neighbor from the left */
- /* most liquid item that cannot be shifted from S[0] entirely */
- /* if -1 then nothing will be partially shifted */
- int rbytes; /* number of bytes which will flow to the right neighbor from the right */
- /* most liquid item that cannot be shifted from S[0] entirely */
- /* if -1 then nothing will be partially shifted */
- int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */
- /* note: if S[0] splits into 3 nodes, then items do not need to be cut */
- int s2bytes;
- struct buffer_head * buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */
- char * vn_buf; /* kmalloced memory. Used to create
+struct tree_balance {
+ int tb_mode;
+ int need_balance_dirty;
+ struct super_block *tb_sb;
+ struct reiserfs_transaction_handle *transaction_handle;
+ struct path *tb_path;
+ struct buffer_head *L[MAX_HEIGHT]; /* array of left neighbors of nodes in the path */
+ struct buffer_head *R[MAX_HEIGHT]; /* array of right neighbors of nodes in the path */
+ struct buffer_head *FL[MAX_HEIGHT]; /* array of fathers of the left neighbors */
+ struct buffer_head *FR[MAX_HEIGHT]; /* array of fathers of the right neighbors */
+ struct buffer_head *CFL[MAX_HEIGHT]; /* array of common parents of center node and its left neighbor */
+ struct buffer_head *CFR[MAX_HEIGHT]; /* array of common parents of center node and its right neighbor */
+
+ struct buffer_head *FEB[MAX_FEB_SIZE]; /* array of empty buffers. Number of buffers in array equals
+ cur_blknum. */
+ struct buffer_head *used[MAX_FEB_SIZE];
+ struct buffer_head *thrown[MAX_FEB_SIZE];
+ int lnum[MAX_HEIGHT]; /* array of number of items which must be
+ shifted to the left in order to balance the
+ current node; for leaves includes item that
+ will be partially shifted; for internal
+ nodes, it is the number of child pointers
+ rather than items. It includes the new item
+ being created. The code sometimes subtracts
+ one to get the number of wholly shifted
+ items for other purposes. */
+ int rnum[MAX_HEIGHT]; /* substitute right for left in comment above */
+ int lkey[MAX_HEIGHT]; /* array indexed by height h mapping the key delimiting L[h] and
+ S[h] to its item number within the node CFL[h] */
+ int rkey[MAX_HEIGHT]; /* substitute r for l in comment above */
+ int insert_size[MAX_HEIGHT]; /* the number of bytes by we are trying to add or remove from
+ S[h]. A negative value means removing. */
+ int blknum[MAX_HEIGHT]; /* number of nodes that will replace node S[h] after
+ balancing on the level h of the tree. If 0 then S is
+ being deleted, if 1 then S is remaining and no new nodes
+ are being created, if 2 or 3 then 1 or 2 new nodes is
+ being created */
+
+ /* fields that are used only for balancing leaves of the tree */
+ int cur_blknum; /* number of empty blocks having been already allocated */
+ int s0num; /* number of items that fall into left most node when S[0] splits */
+ int s1num; /* number of items that fall into first new node when S[0] splits */
+ int s2num; /* number of items that fall into second new node when S[0] splits */
+ int lbytes; /* number of bytes which can flow to the left neighbor from the left */
+ /* most liquid item that cannot be shifted from S[0] entirely */
+ /* if -1 then nothing will be partially shifted */
+ int rbytes; /* number of bytes which will flow to the right neighbor from the right */
+ /* most liquid item that cannot be shifted from S[0] entirely */
+ /* if -1 then nothing will be partially shifted */
+ int s1bytes; /* number of bytes which flow to the first new node when S[0] splits */
+ /* note: if S[0] splits into 3 nodes, then items do not need to be cut */
+ int s2bytes;
+ struct buffer_head *buf_to_free[MAX_FREE_BLOCK]; /* buffers which are to be freed after do_balance finishes by unfix_nodes */
+ char *vn_buf; /* kmalloced memory. Used to create
virtual node and keep map of
dirtied bitmap blocks */
- int vn_buf_size; /* size of the vn_buf */
- struct virtual_node * tb_vn; /* VN starts after bitmap of bitmap blocks */
+ int vn_buf_size; /* size of the vn_buf */
+ struct virtual_node *tb_vn; /* VN starts after bitmap of bitmap blocks */
- int fs_gen; /* saved value of `reiserfs_generation' counter
- see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
+ int fs_gen; /* saved value of `reiserfs_generation' counter
+ see FILESYSTEM_CHANGED() macro in reiserfs_fs.h */
#ifdef DISPLACE_NEW_PACKING_LOCALITIES
- struct in_core_key key; /* key pointer, to pass to block allocator or
- another low-level subsystem */
+ struct in_core_key key; /* key pointer, to pass to block allocator or
+ another low-level subsystem */
#endif
-} ;
+};
/* These are modes of balancing */
@@ -1479,13 +1430,12 @@ struct tree_balance
/* used in do_balance for passing parent of node information that has
been gotten from tb struct */
struct buffer_info {
- struct tree_balance * tb;
- struct buffer_head * bi_bh;
- struct buffer_head * bi_parent;
- int bi_position;
+ struct tree_balance *tb;
+ struct buffer_head *bi_bh;
+ struct buffer_head *bi_parent;
+ int bi_position;
};
-
/* there are 4 types of items: stat data, directory item, indirect, direct.
+-------------------+------------+--------------+------------+
| | k_offset | k_uniqueness | mergeable? |
@@ -1503,24 +1453,24 @@ struct buffer_info {
*/
struct item_operations {
- int (*bytes_number) (struct item_head * ih, int block_size);
- void (*decrement_key) (struct cpu_key *);
- int (*is_left_mergeable) (struct reiserfs_key * ih, unsigned long bsize);
- void (*print_item) (struct item_head *, char * item);
- void (*check_item) (struct item_head *, char * item);
-
- int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
- int is_affected, int insert_size);
- int (*check_left) (struct virtual_item * vi, int free,
- int start_skip, int end_skip);
- int (*check_right) (struct virtual_item * vi, int free);
- int (*part_size) (struct virtual_item * vi, int from, int to);
- int (*unit_num) (struct virtual_item * vi);
- void (*print_vi) (struct virtual_item * vi);
+ int (*bytes_number) (struct item_head * ih, int block_size);
+ void (*decrement_key) (struct cpu_key *);
+ int (*is_left_mergeable) (struct reiserfs_key * ih,
+ unsigned long bsize);
+ void (*print_item) (struct item_head *, char *item);
+ void (*check_item) (struct item_head *, char *item);
+
+ int (*create_vi) (struct virtual_node * vn, struct virtual_item * vi,
+ int is_affected, int insert_size);
+ int (*check_left) (struct virtual_item * vi, int free,
+ int start_skip, int end_skip);
+ int (*check_right) (struct virtual_item * vi, int free);
+ int (*part_size) (struct virtual_item * vi, int from, int to);
+ int (*unit_num) (struct virtual_item * vi);
+ void (*print_vi) (struct virtual_item * vi);
};
-
-extern struct item_operations * item_ops [TYPE_ANY + 1];
+extern struct item_operations *item_ops[TYPE_ANY + 1];
#define op_bytes_number(ih,bsize) item_ops[le_ih_k_type (ih)]->bytes_number (ih, bsize)
#define op_is_left_mergeable(key,bsize) item_ops[le_key_k_type (le_key_version (key), key)]->is_left_mergeable (key, bsize)
@@ -1533,8 +1483,6 @@ extern struct item_operations * item_ops [TYPE_ANY + 1];
#define op_unit_num(vi) item_ops[(vi)->vi_index]->unit_num (vi)
#define op_print_vi(vi) item_ops[(vi)->vi_index]->print_vi (vi)
-
-
#define COMP_SHORT_KEYS comp_short_keys
/* number of blocks pointed to by the indirect item */
@@ -1545,8 +1493,7 @@ extern struct item_operations * item_ops [TYPE_ANY + 1];
/* number of bytes contained by the direct item or the unformatted nodes the indirect item points to */
-
-/* get the item header */
+/* get the item header */
#define B_N_PITEM_HEAD(bh,item_num) ( (struct item_head * )((bh)->b_data + BLKH_SIZE) + (item_num) )
/* get key */
@@ -1577,9 +1524,9 @@ extern struct item_operations * item_ops [TYPE_ANY + 1];
#define PUT_B_I_POS_UNFM_POINTER(bh,ih,pos, val) do {*(((unp_t *)B_I_PITEM(bh,ih)) + (pos)) = cpu_to_le32(val); } while (0)
struct reiserfs_iget_args {
- __u32 objectid ;
- __u32 dirid ;
-} ;
+ __u32 objectid;
+ __u32 dirid;
+};
/***************************************************************************/
/* FUNCTION DECLARATIONS */
@@ -1595,11 +1542,11 @@ struct reiserfs_iget_args {
/* first block written in a commit. */
struct reiserfs_journal_desc {
- __le32 j_trans_id ; /* id of commit */
- __le32 j_len ; /* length of commit. len +1 is the commit block */
- __le32 j_mount_id ; /* mount id of this trans*/
- __le32 j_realblock[1] ; /* real locations for each block */
-} ;
+ __le32 j_trans_id; /* id of commit */
+ __le32 j_len; /* length of commit. len +1 is the commit block */
+ __le32 j_mount_id; /* mount id of this trans */
+ __le32 j_realblock[1]; /* real locations for each block */
+};
#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id)
#define get_desc_trans_len(d) le32_to_cpu((d)->j_len)
@@ -1611,10 +1558,10 @@ struct reiserfs_journal_desc {
/* last block written in a commit */
struct reiserfs_journal_commit {
- __le32 j_trans_id ; /* must match j_trans_id from the desc block */
- __le32 j_len ; /* ditto */
- __le32 j_realblock[1] ; /* real locations for each block */
-} ;
+ __le32 j_trans_id; /* must match j_trans_id from the desc block */
+ __le32 j_len; /* ditto */
+ __le32 j_realblock[1]; /* real locations for each block */
+};
#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id)
#define get_commit_trans_len(c) le32_to_cpu((c)->j_len)
@@ -1628,27 +1575,34 @@ struct reiserfs_journal_commit {
** and this transaction does not need to be replayed.
*/
struct reiserfs_journal_header {
- __le32 j_last_flush_trans_id ; /* id of last fully flushed transaction */
- __le32 j_first_unflushed_offset ; /* offset in the log of where to start replay after a crash */
- __le32 j_mount_id ;
- /* 12 */ struct journal_params jh_journal;
-} ;
+ __le32 j_last_flush_trans_id; /* id of last fully flushed transaction */
+ __le32 j_first_unflushed_offset; /* offset in the log of where to start replay after a crash */
+ __le32 j_mount_id;
+ /* 12 */ struct journal_params jh_journal;
+};
/* biggest tunable defines are right here */
-#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
-#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
+#define JOURNAL_BLOCK_COUNT 8192 /* number of blocks in the journal */
+#define JOURNAL_TRANS_MAX_DEFAULT 1024 /* biggest possible single transaction, don't change for now (8/3/99) */
#define JOURNAL_TRANS_MIN_DEFAULT 256
-#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */
+#define JOURNAL_MAX_BATCH_DEFAULT 900 /* max blocks to batch into one transaction, don't make this any bigger than 900 */
#define JOURNAL_MIN_RATIO 2
-#define JOURNAL_MAX_COMMIT_AGE 30
+#define JOURNAL_MAX_COMMIT_AGE 30
#define JOURNAL_MAX_TRANS_AGE 30
#define JOURNAL_PER_BALANCE_CNT (3 * (MAX_HEIGHT-2) + 9)
#ifdef CONFIG_QUOTA
-#define REISERFS_QUOTA_TRANS_BLOCKS 2 /* We need to update data and inode (atime) */
-#define REISERFS_QUOTA_INIT_BLOCKS (DQUOT_MAX_WRITES*(JOURNAL_PER_BALANCE_CNT+2)+1) /* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+/* We need to update data and inode (atime) */
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? 2 : 0)
+/* 1 balancing, 1 bitmap, 1 data per write + stat data update */
+#define REISERFS_QUOTA_INIT_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_INIT_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_INIT_REWRITE+1) : 0)
+/* same as with INIT */
+#define REISERFS_QUOTA_DEL_BLOCKS(s) (REISERFS_SB(s)->s_mount_opt & (1<<REISERFS_QUOTA) ? \
+(DQUOT_DEL_ALLOC*(JOURNAL_PER_BALANCE_CNT+2)+DQUOT_DEL_REWRITE+1) : 0)
#else
-#define REISERFS_QUOTA_TRANS_BLOCKS 0
-#define REISERFS_QUOTA_INIT_BLOCKS 0
+#define REISERFS_QUOTA_TRANS_BLOCKS(s) 0
+#define REISERFS_QUOTA_INIT_BLOCKS(s) 0
+#define REISERFS_QUOTA_DEL_BLOCKS(s) 0
#endif
/* both of these can be as low as 1, or as high as you want. The min is the
@@ -1657,10 +1611,10 @@ struct reiserfs_journal_header {
** the current number of nodes is > max, the node is freed, otherwise,
** it is put on a free list for faster use later.
*/
-#define REISERFS_MIN_BITMAP_NODES 10
-#define REISERFS_MAX_BITMAP_NODES 100
+#define REISERFS_MIN_BITMAP_NODES 10
+#define REISERFS_MAX_BITMAP_NODES 100
-#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */
+#define JBH_HASH_SHIFT 13 /* these are based on journal hash size of 8192 */
#define JBH_HASH_MASK 8191
#define _jhashfn(sb,block) \
@@ -1674,14 +1628,14 @@ struct reiserfs_journal_header {
#define journal_bread(s, block) __bread(SB_JOURNAL(s)->j_dev_bd, block, s->s_blocksize)
enum reiserfs_bh_state_bits {
- BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */
- BH_JDirty_wait,
- BH_JNew, /* disk block was taken off free list before
- * being in a finished transaction, or
- * written to disk. Can be reused immed. */
- BH_JPrepared,
- BH_JRestore_dirty,
- BH_JTest, // debugging only will go away
+ BH_JDirty = BH_PrivateStart, /* buffer is in current transaction */
+ BH_JDirty_wait,
+ BH_JNew, /* disk block was taken off free list before
+ * being in a finished transaction, or
+ * written to disk. Can be reused immed. */
+ BH_JPrepared,
+ BH_JRestore_dirty,
+ BH_JTest, // debugging only will go away
};
BUFFER_FNS(JDirty, journaled);
@@ -1701,175 +1655,192 @@ TAS_BUFFER_FNS(JTest, journal_test);
** transaction handle which is passed around for all journal calls
*/
struct reiserfs_transaction_handle {
- struct super_block *t_super ; /* super for this FS when journal_begin was
- called. saves calls to reiserfs_get_super
- also used by nested transactions to make
- sure they are nesting on the right FS
- _must_ be first in the handle
- */
- int t_refcount;
- int t_blocks_logged ; /* number of blocks this writer has logged */
- int t_blocks_allocated ; /* number of blocks this writer allocated */
- unsigned long t_trans_id ; /* sanity check, equals the current trans id */
- void *t_handle_save ; /* save existing current->journal_info */
- unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
- should be displaced from others */
- struct list_head t_list;
-} ;
+ struct super_block *t_super; /* super for this FS when journal_begin was
+ called. saves calls to reiserfs_get_super
+ also used by nested transactions to make
+ sure they are nesting on the right FS
+ _must_ be first in the handle
+ */
+ int t_refcount;
+ int t_blocks_logged; /* number of blocks this writer has logged */
+ int t_blocks_allocated; /* number of blocks this writer allocated */
+ unsigned long t_trans_id; /* sanity check, equals the current trans id */
+ void *t_handle_save; /* save existing current->journal_info */
+ unsigned displace_new_blocks:1; /* if new block allocation occurres, that block
+ should be displaced from others */
+ struct list_head t_list;
+};
/* used to keep track of ordered and tail writes, attached to the buffer
* head through b_journal_head.
*/
struct reiserfs_jh {
- struct reiserfs_journal_list *jl;
- struct buffer_head *bh;
- struct list_head list;
+ struct reiserfs_journal_list *jl;
+ struct buffer_head *bh;
+ struct list_head list;
};
void reiserfs_free_jh(struct buffer_head *bh);
int reiserfs_add_tail_list(struct inode *inode, struct buffer_head *bh);
int reiserfs_add_ordered_list(struct inode *inode, struct buffer_head *bh);
-int journal_mark_dirty(struct reiserfs_transaction_handle *, struct super_block *, struct buffer_head *bh) ;
-
-static inline int
-reiserfs_file_data_log(struct inode *inode) {
- if (reiserfs_data_log(inode->i_sb) ||
- (REISERFS_I(inode)->i_flags & i_data_log))
- return 1 ;
- return 0 ;
+int journal_mark_dirty(struct reiserfs_transaction_handle *,
+ struct super_block *, struct buffer_head *bh);
+
+static inline int reiserfs_file_data_log(struct inode *inode)
+{
+ if (reiserfs_data_log(inode->i_sb) ||
+ (REISERFS_I(inode)->i_flags & i_data_log))
+ return 1;
+ return 0;
}
-static inline int reiserfs_transaction_running(struct super_block *s) {
- struct reiserfs_transaction_handle *th = current->journal_info ;
- if (th && th->t_super == s)
- return 1 ;
- if (th && th->t_super == NULL)
- BUG();
- return 0 ;
+static inline int reiserfs_transaction_running(struct super_block *s)
+{
+ struct reiserfs_transaction_handle *th = current->journal_info;
+ if (th && th->t_super == s)
+ return 1;
+ if (th && th->t_super == NULL)
+ BUG();
+ return 0;
}
int reiserfs_async_progress_wait(struct super_block *s);
-struct reiserfs_transaction_handle *
-reiserfs_persistent_transaction(struct super_block *, int count);
+struct reiserfs_transaction_handle *reiserfs_persistent_transaction(struct
+ super_block
+ *,
+ int count);
int reiserfs_end_persistent_transaction(struct reiserfs_transaction_handle *);
int reiserfs_commit_page(struct inode *inode, struct page *page,
- unsigned from, unsigned to);
+ unsigned from, unsigned to);
int reiserfs_flush_old_commits(struct super_block *);
-int reiserfs_commit_for_inode(struct inode *) ;
-int reiserfs_inode_needs_commit(struct inode *) ;
-void reiserfs_update_inode_transaction(struct inode *) ;
-void reiserfs_wait_on_write_block(struct super_block *s) ;
-void reiserfs_block_writes(struct reiserfs_transaction_handle *th) ;
-void reiserfs_allow_writes(struct super_block *s) ;
-void reiserfs_check_lock_depth(struct super_block *s, char *caller) ;
-int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh, int wait) ;
-void reiserfs_restore_prepared_buffer(struct super_block *, struct buffer_head *bh) ;
-int journal_init(struct super_block *, const char * j_dev_name, int old_format, unsigned int) ;
-int journal_release(struct reiserfs_transaction_handle*, struct super_block *) ;
-int journal_release_error(struct reiserfs_transaction_handle*, struct super_block *) ;
-int journal_end(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ;
-int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *, unsigned long) ;
-int journal_mark_freed(struct reiserfs_transaction_handle *, struct super_block *, b_blocknr_t blocknr) ;
-int journal_transaction_should_end(struct reiserfs_transaction_handle *, int) ;
-int reiserfs_in_journal(struct super_block *p_s_sb, int bmap_nr, int bit_nr, int searchall, b_blocknr_t *next) ;
-int journal_begin(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-int journal_join_abort(struct reiserfs_transaction_handle *, struct super_block *p_s_sb, unsigned long) ;
-void reiserfs_journal_abort (struct super_block *sb, int errno);
-void reiserfs_abort (struct super_block *sb, int errno, const char *fmt, ...);
-int reiserfs_allocate_list_bitmaps(struct super_block *s, struct reiserfs_list_bitmap *, int) ;
-
-void add_save_link (struct reiserfs_transaction_handle * th,
- struct inode * inode, int truncate);
-int remove_save_link (struct inode * inode, int truncate);
+int reiserfs_commit_for_inode(struct inode *);
+int reiserfs_inode_needs_commit(struct inode *);
+void reiserfs_update_inode_transaction(struct inode *);
+void reiserfs_wait_on_write_block(struct super_block *s);
+void reiserfs_block_writes(struct reiserfs_transaction_handle *th);
+void reiserfs_allow_writes(struct super_block *s);
+void reiserfs_check_lock_depth(struct super_block *s, char *caller);
+int reiserfs_prepare_for_journal(struct super_block *, struct buffer_head *bh,
+ int wait);
+void reiserfs_restore_prepared_buffer(struct super_block *,
+ struct buffer_head *bh);
+int journal_init(struct super_block *, const char *j_dev_name, int old_format,
+ unsigned int);
+int journal_release(struct reiserfs_transaction_handle *, struct super_block *);
+int journal_release_error(struct reiserfs_transaction_handle *,
+ struct super_block *);
+int journal_end(struct reiserfs_transaction_handle *, struct super_block *,
+ unsigned long);
+int journal_end_sync(struct reiserfs_transaction_handle *, struct super_block *,
+ unsigned long);
+int journal_mark_freed(struct reiserfs_transaction_handle *,
+ struct super_block *, b_blocknr_t blocknr);
+int journal_transaction_should_end(struct reiserfs_transaction_handle *, int);
+int reiserfs_in_journal(struct super_block *p_s_sb, int bmap_nr, int bit_nr,
+ int searchall, b_blocknr_t * next);
+int journal_begin(struct reiserfs_transaction_handle *,
+ struct super_block *p_s_sb, unsigned long);
+int journal_join_abort(struct reiserfs_transaction_handle *,
+ struct super_block *p_s_sb, unsigned long);
+void reiserfs_journal_abort(struct super_block *sb, int errno);
+void reiserfs_abort(struct super_block *sb, int errno, const char *fmt, ...);
+int reiserfs_allocate_list_bitmaps(struct super_block *s,
+ struct reiserfs_list_bitmap *, int);
+
+void add_save_link(struct reiserfs_transaction_handle *th,
+ struct inode *inode, int truncate);
+int remove_save_link(struct inode *inode, int truncate);
/* objectid.c */
-__u32 reiserfs_get_unused_objectid (struct reiserfs_transaction_handle *th);
-void reiserfs_release_objectid (struct reiserfs_transaction_handle *th, __u32 objectid_to_release);
-int reiserfs_convert_objectid_map_v1(struct super_block *) ;
+__u32 reiserfs_get_unused_objectid(struct reiserfs_transaction_handle *th);
+void reiserfs_release_objectid(struct reiserfs_transaction_handle *th,
+ __u32 objectid_to_release);
+int reiserfs_convert_objectid_map_v1(struct super_block *);
/* stree.c */
int B_IS_IN_TREE(const struct buffer_head *);
-extern void copy_item_head(struct item_head * p_v_to,
- const struct item_head * p_v_from);
+extern void copy_item_head(struct item_head *p_v_to,
+ const struct item_head *p_v_from);
// first key is in cpu form, second - le
-extern int comp_short_keys (const struct reiserfs_key * le_key,
- const struct cpu_key * cpu_key);
-extern void le_key2cpu_key (struct cpu_key * to, const struct reiserfs_key * from);
+extern int comp_short_keys(const struct reiserfs_key *le_key,
+ const struct cpu_key *cpu_key);
+extern void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from);
// both are in le form
-extern int comp_le_keys (const struct reiserfs_key *, const struct reiserfs_key *);
-extern int comp_short_le_keys (const struct reiserfs_key *, const struct reiserfs_key *);
+extern int comp_le_keys(const struct reiserfs_key *,
+ const struct reiserfs_key *);
+extern int comp_short_le_keys(const struct reiserfs_key *,
+ const struct reiserfs_key *);
//
// get key version from on disk key - kludge
//
-static inline int le_key_version (const struct reiserfs_key * key)
+static inline int le_key_version(const struct reiserfs_key *key)
{
- int type;
-
- type = offset_v2_k_type( &(key->u.k_offset_v2));
- if (type != TYPE_DIRECT && type != TYPE_INDIRECT && type != TYPE_DIRENTRY)
- return KEY_FORMAT_3_5;
-
- return KEY_FORMAT_3_6;
-
-}
+ int type;
+ type = offset_v2_k_type(&(key->u.k_offset_v2));
+ if (type != TYPE_DIRECT && type != TYPE_INDIRECT
+ && type != TYPE_DIRENTRY)
+ return KEY_FORMAT_3_5;
+
+ return KEY_FORMAT_3_6;
-static inline void copy_key (struct reiserfs_key *to, const struct reiserfs_key *from)
-{
- memcpy (to, from, KEY_SIZE);
}
+static inline void copy_key(struct reiserfs_key *to,
+ const struct reiserfs_key *from)
+{
+ memcpy(to, from, KEY_SIZE);
+}
-int comp_items (const struct item_head * stored_ih, const struct path * p_s_path);
-const struct reiserfs_key * get_rkey (const struct path * p_s_chk_path,
- const struct super_block * p_s_sb);
-int search_by_key (struct super_block *, const struct cpu_key *,
- struct path *, int);
+int comp_items(const struct item_head *stored_ih, const struct path *p_s_path);
+const struct reiserfs_key *get_rkey(const struct path *p_s_chk_path,
+ const struct super_block *p_s_sb);
+int search_by_key(struct super_block *, const struct cpu_key *,
+ struct path *, int);
#define search_item(s,key,path) search_by_key (s, key, path, DISK_LEAF_NODE_LEVEL)
-int search_for_position_by_key (struct super_block * p_s_sb,
- const struct cpu_key * p_s_cpu_key,
- struct path * p_s_search_path);
-extern void decrement_bcount (struct buffer_head * p_s_bh);
-void decrement_counters_in_path (struct path * p_s_search_path);
-void pathrelse (struct path * p_s_search_path);
-int reiserfs_check_path(struct path *p) ;
-void pathrelse_and_restore (struct super_block *s, struct path * p_s_search_path);
-
-int reiserfs_insert_item (struct reiserfs_transaction_handle *th,
- struct path * path,
- const struct cpu_key * key,
- struct item_head * ih,
- struct inode *inode, const char * body);
-
-int reiserfs_paste_into_item (struct reiserfs_transaction_handle *th,
- struct path * path,
- const struct cpu_key * key,
- struct inode *inode,
- const char * body, int paste_size);
-
-int reiserfs_cut_from_item (struct reiserfs_transaction_handle *th,
- struct path * path,
- struct cpu_key * key,
- struct inode * inode,
- struct page *page,
- loff_t new_file_size);
-
-int reiserfs_delete_item (struct reiserfs_transaction_handle *th,
- struct path * path,
- const struct cpu_key * key,
- struct inode * inode,
- struct buffer_head * p_s_un_bh);
-
-void reiserfs_delete_solid_item (struct reiserfs_transaction_handle *th,
- struct inode *inode, struct reiserfs_key * key);
-int reiserfs_delete_object (struct reiserfs_transaction_handle *th, struct inode * p_s_inode);
-int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
- struct inode * p_s_inode, struct page *,
- int update_timestamps);
+int search_for_position_by_key(struct super_block *p_s_sb,
+ const struct cpu_key *p_s_cpu_key,
+ struct path *p_s_search_path);
+extern void decrement_bcount(struct buffer_head *p_s_bh);
+void decrement_counters_in_path(struct path *p_s_search_path);
+void pathrelse(struct path *p_s_search_path);
+int reiserfs_check_path(struct path *p);
+void pathrelse_and_restore(struct super_block *s, struct path *p_s_search_path);
+
+int reiserfs_insert_item(struct reiserfs_transaction_handle *th,
+ struct path *path,
+ const struct cpu_key *key,
+ struct item_head *ih,
+ struct inode *inode, const char *body);
+
+int reiserfs_paste_into_item(struct reiserfs_transaction_handle *th,
+ struct path *path,
+ const struct cpu_key *key,
+ struct inode *inode,
+ const char *body, int paste_size);
+
+int reiserfs_cut_from_item(struct reiserfs_transaction_handle *th,
+ struct path *path,
+ struct cpu_key *key,
+ struct inode *inode,
+ struct page *page, loff_t new_file_size);
+
+int reiserfs_delete_item(struct reiserfs_transaction_handle *th,
+ struct path *path,
+ const struct cpu_key *key,
+ struct inode *inode, struct buffer_head *p_s_un_bh);
+
+void reiserfs_delete_solid_item(struct reiserfs_transaction_handle *th,
+ struct inode *inode, struct reiserfs_key *key);
+int reiserfs_delete_object(struct reiserfs_transaction_handle *th,
+ struct inode *p_s_inode);
+int reiserfs_do_truncate(struct reiserfs_transaction_handle *th,
+ struct inode *p_s_inode, struct page *,
+ int update_timestamps);
#define i_block_size(inode) ((inode)->i_sb->s_blocksize)
#define file_size(inode) ((inode)->i_size)
@@ -1878,66 +1849,67 @@ int reiserfs_do_truncate (struct reiserfs_transaction_handle *th,
#define tail_has_to_be_packed(inode) (have_large_tails ((inode)->i_sb)?\
!STORE_TAIL_IN_UNFM_S1(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):have_small_tails ((inode)->i_sb)?!STORE_TAIL_IN_UNFM_S2(file_size (inode), tail_size(inode), inode->i_sb->s_blocksize):0 )
-void padd_item (char * item, int total_length, int length);
+void padd_item(char *item, int total_length, int length);
/* inode.c */
/* args for the create parameter of reiserfs_get_block */
-#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
-#define GET_BLOCK_CREATE 1 /* add anything you need to find block */
-#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */
-#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */
-#define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */
-#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
-
-int restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
-void reiserfs_read_locked_inode(struct inode * inode, struct reiserfs_iget_args *args) ;
-int reiserfs_find_actor(struct inode * inode, void *p) ;
-int reiserfs_init_locked_inode(struct inode * inode, void *p) ;
-void reiserfs_delete_inode (struct inode * inode);
-int reiserfs_write_inode (struct inode * inode, int) ;
-int reiserfs_get_block (struct inode * inode, sector_t block, struct buffer_head * bh_result, int create);
-struct dentry *reiserfs_get_dentry(struct super_block *, void *) ;
-struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 *data,
- int len, int fhtype,
- int (*acceptable)(void *contect, struct dentry *de),
- void *context) ;
-int reiserfs_encode_fh( struct dentry *dentry, __u32 *data, int *lenp,
- int connectable );
-
-int reiserfs_truncate_file(struct inode *, int update_timestamps) ;
-void make_cpu_key (struct cpu_key * cpu_key, struct inode * inode, loff_t offset,
- int type, int key_length);
-void make_le_item_head (struct item_head * ih, const struct cpu_key * key,
- int version,
- loff_t offset, int type, int length, int entry_count);
-struct inode * reiserfs_iget (struct super_block * s,
- const struct cpu_key * key);
-
-
-int reiserfs_new_inode (struct reiserfs_transaction_handle *th,
- struct inode * dir, int mode,
- const char * symname, loff_t i_size,
- struct dentry *dentry, struct inode *inode);
-
-void reiserfs_update_sd_size (struct reiserfs_transaction_handle *th,
- struct inode * inode, loff_t size);
+#define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
+#define GET_BLOCK_CREATE 1 /* add anything you need to find block */
+#define GET_BLOCK_NO_HOLE 2 /* return -ENOENT for file holes */
+#define GET_BLOCK_READ_DIRECT 4 /* read the tail if indirect item not found */
+#define GET_BLOCK_NO_ISEM 8 /* i_sem is not held, don't preallocate */
+#define GET_BLOCK_NO_DANGLE 16 /* don't leave any transactions running */
+
+int restart_transaction(struct reiserfs_transaction_handle *th,
+ struct inode *inode, struct path *path);
+void reiserfs_read_locked_inode(struct inode *inode,
+ struct reiserfs_iget_args *args);
+int reiserfs_find_actor(struct inode *inode, void *p);
+int reiserfs_init_locked_inode(struct inode *inode, void *p);
+void reiserfs_delete_inode(struct inode *inode);
+int reiserfs_write_inode(struct inode *inode, int);
+int reiserfs_get_block(struct inode *inode, sector_t block,
+ struct buffer_head *bh_result, int create);
+struct dentry *reiserfs_get_dentry(struct super_block *, void *);
+struct dentry *reiserfs_decode_fh(struct super_block *sb, __u32 * data,
+ int len, int fhtype,
+ int (*acceptable) (void *contect,
+ struct dentry * de),
+ void *context);
+int reiserfs_encode_fh(struct dentry *dentry, __u32 * data, int *lenp,
+ int connectable);
+
+int reiserfs_truncate_file(struct inode *, int update_timestamps);
+void make_cpu_key(struct cpu_key *cpu_key, struct inode *inode, loff_t offset,
+ int type, int key_length);
+void make_le_item_head(struct item_head *ih, const struct cpu_key *key,
+ int version,
+ loff_t offset, int type, int length, int entry_count);
+struct inode *reiserfs_iget(struct super_block *s, const struct cpu_key *key);
+
+int reiserfs_new_inode(struct reiserfs_transaction_handle *th,
+ struct inode *dir, int mode,
+ const char *symname, loff_t i_size,
+ struct dentry *dentry, struct inode *inode);
+
+void reiserfs_update_sd_size(struct reiserfs_transaction_handle *th,
+ struct inode *inode, loff_t size);
static inline void reiserfs_update_sd(struct reiserfs_transaction_handle *th,
- struct inode *inode)
+ struct inode *inode)
{
- reiserfs_update_sd_size(th, inode, inode->i_size) ;
+ reiserfs_update_sd_size(th, inode, inode->i_size);
}
-void sd_attrs_to_i_attrs( __u16 sd_attrs, struct inode *inode );
-void i_attrs_to_sd_attrs( struct inode *inode, __u16 *sd_attrs );
+void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode);
+void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs);
int reiserfs_setattr(struct dentry *dentry, struct iattr *attr);
/* namei.c */
-void set_de_name_and_namelen (struct reiserfs_dir_entry * de);
-int search_by_entry_key (struct super_block * sb, const struct cpu_key * key,
- struct path * path,
- struct reiserfs_dir_entry * de);
-struct dentry *reiserfs_get_parent(struct dentry *) ;
+void set_de_name_and_namelen(struct reiserfs_dir_entry *de);
+int search_by_entry_key(struct super_block *sb, const struct cpu_key *key,
+ struct path *path, struct reiserfs_dir_entry *de);
+struct dentry *reiserfs_get_parent(struct dentry *);
/* procfs.c */
#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
@@ -1946,15 +1918,15 @@ struct dentry *reiserfs_get_parent(struct dentry *) ;
#undef REISERFS_PROC_INFO
#endif
-int reiserfs_proc_info_init( struct super_block *sb );
-int reiserfs_proc_info_done( struct super_block *sb );
-struct proc_dir_entry *reiserfs_proc_register_global( char *name,
- read_proc_t *func );
-void reiserfs_proc_unregister_global( const char *name );
-int reiserfs_proc_info_global_init( void );
-int reiserfs_proc_info_global_done( void );
-int reiserfs_global_version_in_proc( char *buffer, char **start, off_t offset,
- int count, int *eof, void *data );
+int reiserfs_proc_info_init(struct super_block *sb);
+int reiserfs_proc_info_done(struct super_block *sb);
+struct proc_dir_entry *reiserfs_proc_register_global(char *name,
+ read_proc_t * func);
+void reiserfs_proc_unregister_global(const char *name);
+int reiserfs_proc_info_global_init(void);
+int reiserfs_proc_info_global_done(void);
+int reiserfs_global_version_in_proc(char *buffer, char **start, off_t offset,
+ int count, int *eof, void *data);
#if defined( REISERFS_PROC_INFO )
@@ -1986,123 +1958,132 @@ extern struct inode_operations reiserfs_special_inode_operations;
extern struct file_operations reiserfs_dir_operations;
/* tail_conversion.c */
-int direct2indirect (struct reiserfs_transaction_handle *, struct inode *, struct path *, struct buffer_head *, loff_t);
-int indirect2direct (struct reiserfs_transaction_handle *, struct inode *, struct page *, struct path *, const struct cpu_key *, loff_t, char *);
-void reiserfs_unmap_buffer(struct buffer_head *) ;
-
+int direct2indirect(struct reiserfs_transaction_handle *, struct inode *,
+ struct path *, struct buffer_head *, loff_t);
+int indirect2direct(struct reiserfs_transaction_handle *, struct inode *,
+ struct page *, struct path *, const struct cpu_key *,
+ loff_t, char *);
+void reiserfs_unmap_buffer(struct buffer_head *);
/* file.c */
extern struct inode_operations reiserfs_file_inode_operations;
extern struct file_operations reiserfs_file_operations;
-extern struct address_space_operations reiserfs_address_space_operations ;
+extern struct address_space_operations reiserfs_address_space_operations;
/* fix_nodes.c */
#ifdef CONFIG_REISERFS_CHECK
-void * reiserfs_kmalloc (size_t size, int flags, struct super_block * s);
-void reiserfs_kfree (const void * vp, size_t size, struct super_block * s);
+void *reiserfs_kmalloc(size_t size, int flags, struct super_block *s);
+void reiserfs_kfree(const void *vp, size_t size, struct super_block *s);
#else
static inline void *reiserfs_kmalloc(size_t size, int flags,
- struct super_block *s)
+ struct super_block *s)
{
return kmalloc(size, flags);
}
static inline void reiserfs_kfree(const void *vp, size_t size,
- struct super_block *s)
+ struct super_block *s)
{
kfree(vp);
}
#endif
-int fix_nodes (int n_op_mode, struct tree_balance * p_s_tb,
- struct item_head * p_s_ins_ih, const void *);
-void unfix_nodes (struct tree_balance *);
-
+int fix_nodes(int n_op_mode, struct tree_balance *p_s_tb,
+ struct item_head *p_s_ins_ih, const void *);
+void unfix_nodes(struct tree_balance *);
/* prints.c */
-void reiserfs_panic (struct super_block * s, const char * fmt, ...) __attribute__ ( ( noreturn ) );
-void reiserfs_info (struct super_block *s, const char * fmt, ...);
-void reiserfs_debug (struct super_block *s, int level, const char * fmt, ...);
-void print_indirect_item (struct buffer_head * bh, int item_num);
-void store_print_tb (struct tree_balance * tb);
-void print_cur_tb (char * mes);
-void print_de (struct reiserfs_dir_entry * de);
-void print_bi (struct buffer_info * bi, char * mes);
-#define PRINT_LEAF_ITEMS 1 /* print all items */
-#define PRINT_DIRECTORY_ITEMS 2 /* print directory items */
-#define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */
-void print_block (struct buffer_head * bh, ...);
-void print_bmap (struct super_block * s, int silent);
-void print_bmap_block (int i, char * data, int size, int silent);
+void reiserfs_panic(struct super_block *s, const char *fmt, ...)
+ __attribute__ ((noreturn));
+void reiserfs_info(struct super_block *s, const char *fmt, ...);
+void reiserfs_debug(struct super_block *s, int level, const char *fmt, ...);
+void print_indirect_item(struct buffer_head *bh, int item_num);
+void store_print_tb(struct tree_balance *tb);
+void print_cur_tb(char *mes);
+void print_de(struct reiserfs_dir_entry *de);
+void print_bi(struct buffer_info *bi, char *mes);
+#define PRINT_LEAF_ITEMS 1 /* print all items */
+#define PRINT_DIRECTORY_ITEMS 2 /* print directory items */
+#define PRINT_DIRECT_ITEMS 4 /* print contents of direct items */
+void print_block(struct buffer_head *bh, ...);
+void print_bmap(struct super_block *s, int silent);
+void print_bmap_block(int i, char *data, int size, int silent);
/*void print_super_block (struct super_block * s, char * mes);*/
-void print_objectid_map (struct super_block * s);
-void print_block_head (struct buffer_head * bh, char * mes);
-void check_leaf (struct buffer_head * bh);
-void check_internal (struct buffer_head * bh);
-void print_statistics (struct super_block * s);
-char * reiserfs_hashname(int code);
+void print_objectid_map(struct super_block *s);
+void print_block_head(struct buffer_head *bh, char *mes);
+void check_leaf(struct buffer_head *bh);
+void check_internal(struct buffer_head *bh);
+void print_statistics(struct super_block *s);
+char *reiserfs_hashname(int code);
/* lbalance.c */
-int leaf_move_items (int shift_mode, struct tree_balance * tb, int mov_num, int mov_bytes, struct buffer_head * Snew);
-int leaf_shift_left (struct tree_balance * tb, int shift_num, int shift_bytes);
-int leaf_shift_right (struct tree_balance * tb, int shift_num, int shift_bytes);
-void leaf_delete_items (struct buffer_info * cur_bi, int last_first, int first, int del_num, int del_bytes);
-void leaf_insert_into_buf (struct buffer_info * bi, int before,
- struct item_head * inserted_item_ih, const char * inserted_item_body, int zeros_number);
-void leaf_paste_in_buffer (struct buffer_info * bi, int pasted_item_num,
- int pos_in_item, int paste_size, const char * body, int zeros_number);
-void leaf_cut_from_buffer (struct buffer_info * bi, int cut_item_num, int pos_in_item,
- int cut_size);
-void leaf_paste_entries (struct buffer_head * bh, int item_num, int before,
- int new_entry_count, struct reiserfs_de_head * new_dehs, const char * records, int paste_size);
+int leaf_move_items(int shift_mode, struct tree_balance *tb, int mov_num,
+ int mov_bytes, struct buffer_head *Snew);
+int leaf_shift_left(struct tree_balance *tb, int shift_num, int shift_bytes);
+int leaf_shift_right(struct tree_balance *tb, int shift_num, int shift_bytes);
+void leaf_delete_items(struct buffer_info *cur_bi, int last_first, int first,
+ int del_num, int del_bytes);
+void leaf_insert_into_buf(struct buffer_info *bi, int before,
+ struct item_head *inserted_item_ih,
+ const char *inserted_item_body, int zeros_number);
+void leaf_paste_in_buffer(struct buffer_info *bi, int pasted_item_num,
+ int pos_in_item, int paste_size, const char *body,
+ int zeros_number);
+void leaf_cut_from_buffer(struct buffer_info *bi, int cut_item_num,
+ int pos_in_item, int cut_size);
+void leaf_paste_entries(struct buffer_head *bh, int item_num, int before,
+ int new_entry_count, struct reiserfs_de_head *new_dehs,
+ const char *records, int paste_size);
/* ibalance.c */
-int balance_internal (struct tree_balance * , int, int, struct item_head * ,
- struct buffer_head **);
+int balance_internal(struct tree_balance *, int, int, struct item_head *,
+ struct buffer_head **);
/* do_balance.c */
-void do_balance_mark_leaf_dirty (struct tree_balance * tb,
- struct buffer_head * bh, int flag);
+void do_balance_mark_leaf_dirty(struct tree_balance *tb,
+ struct buffer_head *bh, int flag);
#define do_balance_mark_internal_dirty do_balance_mark_leaf_dirty
#define do_balance_mark_sb_dirty do_balance_mark_leaf_dirty
-void do_balance (struct tree_balance * tb, struct item_head * ih,
- const char * body, int flag);
-void reiserfs_invalidate_buffer (struct tree_balance * tb, struct buffer_head * bh);
+void do_balance(struct tree_balance *tb, struct item_head *ih,
+ const char *body, int flag);
+void reiserfs_invalidate_buffer(struct tree_balance *tb,
+ struct buffer_head *bh);
-int get_left_neighbor_position (struct tree_balance * tb, int h);
-int get_right_neighbor_position (struct tree_balance * tb, int h);
-void replace_key (struct tree_balance * tb, struct buffer_head *, int, struct buffer_head *, int);
-void make_empty_node (struct buffer_info *);
-struct buffer_head * get_FEB (struct tree_balance *);
+int get_left_neighbor_position(struct tree_balance *tb, int h);
+int get_right_neighbor_position(struct tree_balance *tb, int h);
+void replace_key(struct tree_balance *tb, struct buffer_head *, int,
+ struct buffer_head *, int);
+void make_empty_node(struct buffer_info *);
+struct buffer_head *get_FEB(struct tree_balance *);
/* bitmap.c */
/* structure contains hints for block allocator, and it is a container for
* arguments, such as node, search path, transaction_handle, etc. */
- struct __reiserfs_blocknr_hint {
- struct inode * inode; /* inode passed to allocator, if we allocate unf. nodes */
- long block; /* file offset, in blocks */
- struct in_core_key key;
- struct path * path; /* search path, used by allocator to deternine search_start by
- * various ways */
- struct reiserfs_transaction_handle * th; /* transaction handle is needed to log super blocks and
- * bitmap blocks changes */
- b_blocknr_t beg, end;
- b_blocknr_t search_start; /* a field used to transfer search start value (block number)
+struct __reiserfs_blocknr_hint {
+ struct inode *inode; /* inode passed to allocator, if we allocate unf. nodes */
+ long block; /* file offset, in blocks */
+ struct in_core_key key;
+ struct path *path; /* search path, used by allocator to deternine search_start by
+ * various ways */
+ struct reiserfs_transaction_handle *th; /* transaction handle is needed to log super blocks and
+ * bitmap blocks changes */
+ b_blocknr_t beg, end;
+ b_blocknr_t search_start; /* a field used to transfer search start value (block number)
* between different block allocator procedures
* (determine_search_start() and others) */
- int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed
- * function that do actual allocation */
+ int prealloc_size; /* is set in determine_prealloc_size() function, used by underlayed
+ * function that do actual allocation */
- unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for
+ unsigned formatted_node:1; /* the allocator uses different polices for getting disk space for
* formatted/unformatted blocks with/without preallocation */
- unsigned preallocate:1;
+ unsigned preallocate:1;
};
typedef struct __reiserfs_blocknr_hint reiserfs_blocknr_hint_t;
-int reiserfs_parse_alloc_options (struct super_block *, char *);
-void reiserfs_init_alloc_options (struct super_block *s);
+int reiserfs_parse_alloc_options(struct super_block *, char *);
+void reiserfs_init_alloc_options(struct super_block *s);
/*
* given a directory, this will tell you what packing locality
@@ -2111,68 +2092,72 @@ void reiserfs_init_alloc_options (struct super_block *s);
*/
__le32 reiserfs_choose_packing(struct inode *dir);
-int is_reusable (struct super_block * s, b_blocknr_t block, int bit_value);
-void reiserfs_free_block (struct reiserfs_transaction_handle *th, struct inode *, b_blocknr_t, int for_unformatted);
-int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t * , int, int);
-extern inline int reiserfs_new_form_blocknrs (struct tree_balance * tb,
- b_blocknr_t *new_blocknrs, int amount_needed)
+int is_reusable(struct super_block *s, b_blocknr_t block, int bit_value);
+void reiserfs_free_block(struct reiserfs_transaction_handle *th, struct inode *,
+ b_blocknr_t, int for_unformatted);
+int reiserfs_allocate_blocknrs(reiserfs_blocknr_hint_t *, b_blocknr_t *, int,
+ int);
+extern inline int reiserfs_new_form_blocknrs(struct tree_balance *tb,
+ b_blocknr_t * new_blocknrs,
+ int amount_needed)
{
- reiserfs_blocknr_hint_t hint = {
- .th = tb->transaction_handle,
- .path = tb->tb_path,
- .inode = NULL,
- .key = tb->key,
- .block = 0,
- .formatted_node = 1
- };
- return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed, 0);
+ reiserfs_blocknr_hint_t hint = {
+ .th = tb->transaction_handle,
+ .path = tb->tb_path,
+ .inode = NULL,
+ .key = tb->key,
+ .block = 0,
+ .formatted_node = 1
+ };
+ return reiserfs_allocate_blocknrs(&hint, new_blocknrs, amount_needed,
+ 0);
}
-extern inline int reiserfs_new_unf_blocknrs (struct reiserfs_transaction_handle *th,
- struct inode *inode,
- b_blocknr_t *new_blocknrs,
- struct path * path, long block)
+extern inline int reiserfs_new_unf_blocknrs(struct reiserfs_transaction_handle
+ *th, struct inode *inode,
+ b_blocknr_t * new_blocknrs,
+ struct path *path, long block)
{
- reiserfs_blocknr_hint_t hint = {
- .th = th,
- .path = path,
- .inode = inode,
- .block = block,
- .formatted_node = 0,
- .preallocate = 0
- };
- return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+ reiserfs_blocknr_hint_t hint = {
+ .th = th,
+ .path = path,
+ .inode = inode,
+ .block = block,
+ .formatted_node = 0,
+ .preallocate = 0
+ };
+ return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
}
#ifdef REISERFS_PREALLOCATE
-extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle *th,
- struct inode * inode,
- b_blocknr_t *new_blocknrs,
- struct path * path, long block)
+extern inline int reiserfs_new_unf_blocknrs2(struct reiserfs_transaction_handle
+ *th, struct inode *inode,
+ b_blocknr_t * new_blocknrs,
+ struct path *path, long block)
{
- reiserfs_blocknr_hint_t hint = {
- .th = th,
- .path = path,
- .inode = inode,
- .block = block,
- .formatted_node = 0,
- .preallocate = 1
- };
- return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
+ reiserfs_blocknr_hint_t hint = {
+ .th = th,
+ .path = path,
+ .inode = inode,
+ .block = block,
+ .formatted_node = 0,
+ .preallocate = 1
+ };
+ return reiserfs_allocate_blocknrs(&hint, new_blocknrs, 1, 0);
}
-void reiserfs_discard_prealloc (struct reiserfs_transaction_handle *th,
- struct inode * inode);
-void reiserfs_discard_all_prealloc (struct reiserfs_transaction_handle *th);
+void reiserfs_discard_prealloc(struct reiserfs_transaction_handle *th,
+ struct inode *inode);
+void reiserfs_discard_all_prealloc(struct reiserfs_transaction_handle *th);
#endif
-void reiserfs_claim_blocks_to_be_allocated( struct super_block *sb, int blocks);
-void reiserfs_release_claimed_blocks( struct super_block *sb, int blocks);
+void reiserfs_claim_blocks_to_be_allocated(struct super_block *sb, int blocks);
+void reiserfs_release_claimed_blocks(struct super_block *sb, int blocks);
int reiserfs_can_fit_pages(struct super_block *sb);
/* hashes.c */
-__u32 keyed_hash (const signed char *msg, int len);
-__u32 yura_hash (const signed char *msg, int len);
-__u32 r5_hash (const signed char *msg, int len);
+__u32 keyed_hash(const signed char *msg, int len);
+__u32 yura_hash(const signed char *msg, int len);
+__u32 r5_hash(const signed char *msg, int len);
/* the ext2 bit routines adjust for big or little endian as
** appropriate for the arch, so in our laziness we use them rather
@@ -2192,11 +2177,10 @@ __u32 r5_hash (const signed char *msg, int len);
absolutely safe */
#define SPARE_SPACE 500
-
/* prototypes from ioctl.c */
-int reiserfs_ioctl (struct inode * inode, struct file * filp,
- unsigned int cmd, unsigned long arg);
-
+int reiserfs_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg);
+
/* ioctl's command */
#define REISERFS_IOC_UNPACK _IOW(0xCD,1,long)
/* define following flags to be the same as in ext2, so that chattr(1),
@@ -2211,10 +2195,8 @@ int reiserfs_ioctl (struct inode * inode, struct file * filp,
would evolve into real per-fs locks */
#define reiserfs_write_lock( sb ) lock_kernel()
#define reiserfs_write_unlock( sb ) unlock_kernel()
-
+
/* xattr stuff */
#define REISERFS_XATTR_DIR_SEM(s) (REISERFS_SB(s)->xattr_dir_sem)
-#endif /* _LINUX_REISER_FS_H */
-
-
+#endif /* _LINUX_REISER_FS_H */
diff --git a/include/linux/reiserfs_fs_i.h b/include/linux/reiserfs_fs_i.h
index e321eb050d65..149be8d9a0c9 100644
--- a/include/linux/reiserfs_fs_i.h
+++ b/include/linux/reiserfs_fs_i.h
@@ -10,54 +10,53 @@ typedef enum {
/** this says what format of key do all items (but stat data) of
an object have. If this is set, that format is 3.6 otherwise
- 3.5 */
- i_item_key_version_mask = 0x0001,
+ i_item_key_version_mask = 0x0001,
/** If this is unset, object has 3.5 stat data, otherwise, it has
3.6 stat data with 64bit size, 32bit nlink etc. */
- i_stat_data_version_mask = 0x0002,
+ i_stat_data_version_mask = 0x0002,
/** file might need tail packing on close */
- i_pack_on_close_mask = 0x0004,
+ i_pack_on_close_mask = 0x0004,
/** don't pack tail of file */
- i_nopack_mask = 0x0008,
+ i_nopack_mask = 0x0008,
/** If those is set, "safe link" was created for this file during
truncate or unlink. Safe link is used to avoid leakage of disk
space on crash with some files open, but unlinked. */
- i_link_saved_unlink_mask = 0x0010,
- i_link_saved_truncate_mask = 0x0020,
- i_has_xattr_dir = 0x0040,
- i_data_log = 0x0080,
+ i_link_saved_unlink_mask = 0x0010,
+ i_link_saved_truncate_mask = 0x0020,
+ i_has_xattr_dir = 0x0040,
+ i_data_log = 0x0080,
} reiserfs_inode_flags;
-
struct reiserfs_inode_info {
- __u32 i_key [4];/* key is still 4 32 bit integers */
+ __u32 i_key[4]; /* key is still 4 32 bit integers */
/** transient inode flags that are never stored on disk. Bitmasks
for this field are defined above. */
- __u32 i_flags;
+ __u32 i_flags;
- __u32 i_first_direct_byte; // offset of first byte stored in direct item.
+ __u32 i_first_direct_byte; // offset of first byte stored in direct item.
- /* copy of persistent inode flags read from sd_attrs. */
- __u32 i_attrs;
+ /* copy of persistent inode flags read from sd_attrs. */
+ __u32 i_attrs;
- int i_prealloc_block; /* first unused block of a sequence of unused blocks */
- int i_prealloc_count; /* length of that sequence */
- struct list_head i_prealloc_list; /* per-transaction list of inodes which
- * have preallocated blocks */
+ int i_prealloc_block; /* first unused block of a sequence of unused blocks */
+ int i_prealloc_count; /* length of that sequence */
+ struct list_head i_prealloc_list; /* per-transaction list of inodes which
+ * have preallocated blocks */
- unsigned new_packing_locality:1; /* new_packig_locality is created; new blocks
- * for the contents of this directory should be
- * displaced */
+ unsigned new_packing_locality:1; /* new_packig_locality is created; new blocks
+ * for the contents of this directory should be
+ * displaced */
- /* we use these for fsync or O_SYNC to decide which transaction
- ** needs to be committed in order for this inode to be properly
- ** flushed */
- unsigned long i_trans_id ;
- struct reiserfs_journal_list *i_jl;
+ /* we use these for fsync or O_SYNC to decide which transaction
+ ** needs to be committed in order for this inode to be properly
+ ** flushed */
+ unsigned long i_trans_id;
+ struct reiserfs_journal_list *i_jl;
- struct posix_acl *i_acl_access;
- struct posix_acl *i_acl_default;
- struct rw_semaphore xattr_sem;
- struct inode vfs_inode;
+ struct posix_acl *i_acl_access;
+ struct posix_acl *i_acl_default;
+ struct rw_semaphore xattr_sem;
+ struct inode vfs_inode;
};
#endif
diff --git a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
index 37a3a7afbec7..3e68592e52e9 100644
--- a/include/linux/reiserfs_fs_sb.h
+++ b/include/linux/reiserfs_fs_sb.h
@@ -10,7 +10,7 @@
#endif
typedef enum {
- reiserfs_attrs_cleared = 0x00000001,
+ reiserfs_attrs_cleared = 0x00000001,
} reiserfs_super_block_flags;
/* struct reiserfs_super_block accessors/mutators
@@ -61,7 +61,7 @@ typedef enum {
#define sb_umount_state(sbp) (le16_to_cpu((sbp)->s_v1.s_umount_state))
#define set_sb_umount_state(sbp,v) ((sbp)->s_v1.s_umount_state = cpu_to_le16(v))
#define sb_fs_state(sbp) (le16_to_cpu((sbp)->s_v1.s_fs_state))
-#define set_sb_fs_state(sbp,v) ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
+#define set_sb_fs_state(sbp,v) ((sbp)->s_v1.s_fs_state = cpu_to_le16(v))
#define sb_hash_function_code(sbp) \
(le32_to_cpu((sbp)->s_v1.s_hash_function_code))
#define set_sb_hash_function_code(sbp,v) \
@@ -103,10 +103,10 @@ typedef enum {
/* don't mess with these for a while */
/* we have a node size define somewhere in reiserfs_fs.h. -Hans */
-#define JOURNAL_BLOCK_SIZE 4096 /* BUG gotta get rid of this */
-#define JOURNAL_MAX_CNODE 1500 /* max cnodes to allocate. */
-#define JOURNAL_HASH_SIZE 8192
-#define JOURNAL_NUM_BITMAPS 5 /* number of copies of the bitmaps to have floating. Must be >= 2 */
+#define JOURNAL_BLOCK_SIZE 4096 /* BUG gotta get rid of this */
+#define JOURNAL_MAX_CNODE 1500 /* max cnodes to allocate. */
+#define JOURNAL_HASH_SIZE 8192
+#define JOURNAL_NUM_BITMAPS 5 /* number of copies of the bitmaps to have floating. Must be >= 2 */
/* One of these for every block in every transaction
** Each one is in two hash tables. First, a hash of the current transaction, and after journal_end, a
@@ -117,27 +117,27 @@ typedef enum {
** to a given transaction.
*/
struct reiserfs_journal_cnode {
- struct buffer_head *bh ; /* real buffer head */
- struct super_block *sb ; /* dev of real buffer head */
- __u32 blocknr ; /* block number of real buffer head, == 0 when buffer on disk */
- long state ;
- struct reiserfs_journal_list *jlist ; /* journal list this cnode lives in */
- struct reiserfs_journal_cnode *next ; /* next in transaction list */
- struct reiserfs_journal_cnode *prev ; /* prev in transaction list */
- struct reiserfs_journal_cnode *hprev ; /* prev in hash list */
- struct reiserfs_journal_cnode *hnext ; /* next in hash list */
+ struct buffer_head *bh; /* real buffer head */
+ struct super_block *sb; /* dev of real buffer head */
+ __u32 blocknr; /* block number of real buffer head, == 0 when buffer on disk */
+ long state;
+ struct reiserfs_journal_list *jlist; /* journal list this cnode lives in */
+ struct reiserfs_journal_cnode *next; /* next in transaction list */
+ struct reiserfs_journal_cnode *prev; /* prev in transaction list */
+ struct reiserfs_journal_cnode *hprev; /* prev in hash list */
+ struct reiserfs_journal_cnode *hnext; /* next in hash list */
};
struct reiserfs_bitmap_node {
- int id ;
- char *data ;
- struct list_head list ;
-} ;
+ int id;
+ char *data;
+ struct list_head list;
+};
struct reiserfs_list_bitmap {
- struct reiserfs_journal_list *journal_list ;
- struct reiserfs_bitmap_node **bitmaps ;
-} ;
+ struct reiserfs_journal_list *journal_list;
+ struct reiserfs_bitmap_node **bitmaps;
+};
/*
** one of these for each transaction. The most important part here is the j_realblock.
@@ -146,273 +146,269 @@ struct reiserfs_list_bitmap {
** and to make sure every real block in a transaction is on disk before allowing the log area
** to be overwritten */
struct reiserfs_journal_list {
- unsigned long j_start ;
- unsigned long j_state;
- unsigned long j_len ;
- atomic_t j_nonzerolen ;
- atomic_t j_commit_left ;
- atomic_t j_older_commits_done ; /* all commits older than this on disk*/
- struct semaphore j_commit_lock;
- unsigned long j_trans_id ;
- time_t j_timestamp ;
- struct reiserfs_list_bitmap *j_list_bitmap ;
- struct buffer_head *j_commit_bh ; /* commit buffer head */
- struct reiserfs_journal_cnode *j_realblock ;
- struct reiserfs_journal_cnode *j_freedlist ; /* list of buffers that were freed during this trans. free each of these on flush */
- /* time ordered list of all active transactions */
- struct list_head j_list;
-
- /* time ordered list of all transactions we haven't tried to flush yet */
- struct list_head j_working_list;
-
- /* list of tail conversion targets in need of flush before commit */
- struct list_head j_tail_bh_list;
- /* list of data=ordered buffers in need of flush before commit */
- struct list_head j_bh_list;
- int j_refcount;
-} ;
+ unsigned long j_start;
+ unsigned long j_state;
+ unsigned long j_len;
+ atomic_t j_nonzerolen;
+ atomic_t j_commit_left;
+ atomic_t j_older_commits_done; /* all commits older than this on disk */
+ struct semaphore j_commit_lock;
+ unsigned long j_trans_id;
+ time_t j_timestamp;
+ struct reiserfs_list_bitmap *j_list_bitmap;
+ struct buffer_head *j_commit_bh; /* commit buffer head */
+ struct reiserfs_journal_cnode *j_realblock;
+ struct reiserfs_journal_cnode *j_freedlist; /* list of buffers that were freed during this trans. free each of these on flush */
+ /* time ordered list of all active transactions */
+ struct list_head j_list;
+
+ /* time ordered list of all transactions we haven't tried to flush yet */
+ struct list_head j_working_list;
+
+ /* list of tail conversion targets in need of flush before commit */
+ struct list_head j_tail_bh_list;
+ /* list of data=ordered buffers in need of flush before commit */
+ struct list_head j_bh_list;
+ int j_refcount;
+};
struct reiserfs_journal {
- struct buffer_head ** j_ap_blocks ; /* journal blocks on disk */
- struct reiserfs_journal_cnode *j_last ; /* newest journal block */
- struct reiserfs_journal_cnode *j_first ; /* oldest journal block. start here for traverse */
-
- struct file *j_dev_file;
- struct block_device *j_dev_bd;
- int j_1st_reserved_block; /* first block on s_dev of reserved area journal */
-
- long j_state ;
- unsigned long j_trans_id ;
- unsigned long j_mount_id ;
- unsigned long j_start ; /* start of current waiting commit (index into j_ap_blocks) */
- unsigned long j_len ; /* lenght of current waiting commit */
- unsigned long j_len_alloc ; /* number of buffers requested by journal_begin() */
- atomic_t j_wcount ; /* count of writers for current commit */
- unsigned long j_bcount ; /* batch count. allows turning X transactions into 1 */
- unsigned long j_first_unflushed_offset ; /* first unflushed transactions offset */
- unsigned long j_last_flush_trans_id ; /* last fully flushed journal timestamp */
- struct buffer_head *j_header_bh ;
-
- time_t j_trans_start_time ; /* time this transaction started */
- struct semaphore j_lock;
- struct semaphore j_flush_sem;
- wait_queue_head_t j_join_wait ; /* wait for current transaction to finish before starting new one */
- atomic_t j_jlock ; /* lock for j_join_wait */
- int j_list_bitmap_index ; /* number of next list bitmap to use */
- int j_must_wait ; /* no more journal begins allowed. MUST sleep on j_join_wait */
- int j_next_full_flush ; /* next journal_end will flush all journal list */
- int j_next_async_flush ; /* next journal_end will flush all async commits */
-
- int j_cnode_used ; /* number of cnodes on the used list */
- int j_cnode_free ; /* number of cnodes on the free list */
-
- unsigned int j_trans_max ; /* max number of blocks in a transaction. */
- unsigned int j_max_batch ; /* max number of blocks to batch into a trans */
- unsigned int j_max_commit_age ; /* in seconds, how old can an async commit be */
- unsigned int j_max_trans_age ; /* in seconds, how old can a transaction be */
- unsigned int j_default_max_commit_age ; /* the default for the max commit age */
-
- struct reiserfs_journal_cnode *j_cnode_free_list ;
- struct reiserfs_journal_cnode *j_cnode_free_orig ; /* orig pointer returned from vmalloc */
-
- struct reiserfs_journal_list *j_current_jl;
- int j_free_bitmap_nodes ;
- int j_used_bitmap_nodes ;
-
- int j_num_lists; /* total number of active transactions */
- int j_num_work_lists; /* number that need attention from kreiserfsd */
-
- /* debugging to make sure things are flushed in order */
- int j_last_flush_id;
-
- /* debugging to make sure things are committed in order */
- int j_last_commit_id;
-
- struct list_head j_bitmap_nodes ;
- struct list_head j_dirty_buffers ;
- spinlock_t j_dirty_buffers_lock ; /* protects j_dirty_buffers */
-
- /* list of all active transactions */
- struct list_head j_journal_list;
- /* lists that haven't been touched by writeback attempts */
- struct list_head j_working_list;
-
- struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS] ; /* array of bitmaps to record the deleted blocks */
- struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for real buffer heads in current trans */
- struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for all the real buffer heads in all
- the transactions */
- struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */
- int j_persistent_trans;
- unsigned long j_max_trans_size ;
- unsigned long j_max_batch_size ;
-
- int j_errno;
-
- /* when flushing ordered buffers, throttle new ordered writers */
- struct work_struct j_work;
- atomic_t j_async_throttle;
+ struct buffer_head **j_ap_blocks; /* journal blocks on disk */
+ struct reiserfs_journal_cnode *j_last; /* newest journal block */
+ struct reiserfs_journal_cnode *j_first; /* oldest journal block. start here for traverse */
+
+ struct file *j_dev_file;
+ struct block_device *j_dev_bd;
+ int j_1st_reserved_block; /* first block on s_dev of reserved area journal */
+
+ long j_state;
+ unsigned long j_trans_id;
+ unsigned long j_mount_id;
+ unsigned long j_start; /* start of current waiting commit (index into j_ap_blocks) */
+ unsigned long j_len; /* lenght of current waiting commit */
+ unsigned long j_len_alloc; /* number of buffers requested by journal_begin() */
+ atomic_t j_wcount; /* count of writers for current commit */
+ unsigned long j_bcount; /* batch count. allows turning X transactions into 1 */
+ unsigned long j_first_unflushed_offset; /* first unflushed transactions offset */
+ unsigned long j_last_flush_trans_id; /* last fully flushed journal timestamp */
+ struct buffer_head *j_header_bh;
+
+ time_t j_trans_start_time; /* time this transaction started */
+ struct semaphore j_lock;
+ struct semaphore j_flush_sem;
+ wait_queue_head_t j_join_wait; /* wait for current transaction to finish before starting new one */
+ atomic_t j_jlock; /* lock for j_join_wait */
+ int j_list_bitmap_index; /* number of next list bitmap to use */
+ int j_must_wait; /* no more journal begins allowed. MUST sleep on j_join_wait */
+ int j_next_full_flush; /* next journal_end will flush all journal list */
+ int j_next_async_flush; /* next journal_end will flush all async commits */
+
+ int j_cnode_used; /* number of cnodes on the used list */
+ int j_cnode_free; /* number of cnodes on the free list */
+
+ unsigned int j_trans_max; /* max number of blocks in a transaction. */
+ unsigned int j_max_batch; /* max number of blocks to batch into a trans */
+ unsigned int j_max_commit_age; /* in seconds, how old can an async commit be */
+ unsigned int j_max_trans_age; /* in seconds, how old can a transaction be */
+ unsigned int j_default_max_commit_age; /* the default for the max commit age */
+
+ struct reiserfs_journal_cnode *j_cnode_free_list;
+ struct reiserfs_journal_cnode *j_cnode_free_orig; /* orig pointer returned from vmalloc */
+
+ struct reiserfs_journal_list *j_current_jl;
+ int j_free_bitmap_nodes;
+ int j_used_bitmap_nodes;
+
+ int j_num_lists; /* total number of active transactions */
+ int j_num_work_lists; /* number that need attention from kreiserfsd */
+
+ /* debugging to make sure things are flushed in order */
+ int j_last_flush_id;
+
+ /* debugging to make sure things are committed in order */
+ int j_last_commit_id;
+
+ struct list_head j_bitmap_nodes;
+ struct list_head j_dirty_buffers;
+ spinlock_t j_dirty_buffers_lock; /* protects j_dirty_buffers */
+
+ /* list of all active transactions */
+ struct list_head j_journal_list;
+ /* lists that haven't been touched by writeback attempts */
+ struct list_head j_working_list;
+
+ struct reiserfs_list_bitmap j_list_bitmap[JOURNAL_NUM_BITMAPS]; /* array of bitmaps to record the deleted blocks */
+ struct reiserfs_journal_cnode *j_hash_table[JOURNAL_HASH_SIZE]; /* hash table for real buffer heads in current trans */
+ struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE]; /* hash table for all the real buffer heads in all
+ the transactions */
+ struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */
+ int j_persistent_trans;
+ unsigned long j_max_trans_size;
+ unsigned long j_max_batch_size;
+
+ int j_errno;
+
+ /* when flushing ordered buffers, throttle new ordered writers */
+ struct work_struct j_work;
+ atomic_t j_async_throttle;
};
enum journal_state_bits {
- J_WRITERS_BLOCKED = 1, /* set when new writers not allowed */
- J_WRITERS_QUEUED, /* set when log is full due to too many writers */
- J_ABORTED, /* set when log is aborted */
+ J_WRITERS_BLOCKED = 1, /* set when new writers not allowed */
+ J_WRITERS_QUEUED, /* set when log is full due to too many writers */
+ J_ABORTED, /* set when log is aborted */
};
+#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */
-#define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */
+typedef __u32(*hashf_t) (const signed char *, int);
-typedef __u32 (*hashf_t) (const signed char *, int);
-
-struct reiserfs_bitmap_info
-{
- // FIXME: Won't work with block sizes > 8K
- __u16 first_zero_hint;
- __u16 free_count;
- struct buffer_head *bh; /* the actual bitmap */
+struct reiserfs_bitmap_info {
+ // FIXME: Won't work with block sizes > 8K
+ __u16 first_zero_hint;
+ __u16 free_count;
+ struct buffer_head *bh; /* the actual bitmap */
};
struct proc_dir_entry;
#if defined( CONFIG_PROC_FS ) && defined( CONFIG_REISERFS_PROC_INFO )
typedef unsigned long int stat_cnt_t;
-typedef struct reiserfs_proc_info_data
-{
- spinlock_t lock;
- int exiting;
- int max_hash_collisions;
-
- stat_cnt_t breads;
- stat_cnt_t bread_miss;
- stat_cnt_t search_by_key;
- stat_cnt_t search_by_key_fs_changed;
- stat_cnt_t search_by_key_restarted;
-
- stat_cnt_t insert_item_restarted;
- stat_cnt_t paste_into_item_restarted;
- stat_cnt_t cut_from_item_restarted;
- stat_cnt_t delete_solid_item_restarted;
- stat_cnt_t delete_item_restarted;
-
- stat_cnt_t leaked_oid;
- stat_cnt_t leaves_removable;
-
- /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
- stat_cnt_t balance_at[ 5 ]; /* XXX */
- /* sbk == search_by_key */
- stat_cnt_t sbk_read_at[ 5 ]; /* XXX */
- stat_cnt_t sbk_fs_changed[ 5 ];
- stat_cnt_t sbk_restarted[ 5 ];
- stat_cnt_t items_at[ 5 ]; /* XXX */
- stat_cnt_t free_at[ 5 ]; /* XXX */
- stat_cnt_t can_node_be_removed[ 5 ]; /* XXX */
- long int lnum[ 5 ]; /* XXX */
- long int rnum[ 5 ]; /* XXX */
- long int lbytes[ 5 ]; /* XXX */
- long int rbytes[ 5 ]; /* XXX */
- stat_cnt_t get_neighbors[ 5 ];
- stat_cnt_t get_neighbors_restart[ 5 ];
- stat_cnt_t need_l_neighbor[ 5 ];
- stat_cnt_t need_r_neighbor[ 5 ];
-
- stat_cnt_t free_block;
- struct __scan_bitmap_stats {
- stat_cnt_t call;
- stat_cnt_t wait;
- stat_cnt_t bmap;
- stat_cnt_t retry;
- stat_cnt_t in_journal_hint;
- stat_cnt_t in_journal_nohint;
- stat_cnt_t stolen;
- } scan_bitmap;
- struct __journal_stats {
- stat_cnt_t in_journal;
- stat_cnt_t in_journal_bitmap;
- stat_cnt_t in_journal_reusable;
- stat_cnt_t lock_journal;
- stat_cnt_t lock_journal_wait;
- stat_cnt_t journal_being;
- stat_cnt_t journal_relock_writers;
- stat_cnt_t journal_relock_wcount;
- stat_cnt_t mark_dirty;
- stat_cnt_t mark_dirty_already;
- stat_cnt_t mark_dirty_notjournal;
- stat_cnt_t restore_prepared;
- stat_cnt_t prepare;
- stat_cnt_t prepare_retry;
- } journal;
+typedef struct reiserfs_proc_info_data {
+ spinlock_t lock;
+ int exiting;
+ int max_hash_collisions;
+
+ stat_cnt_t breads;
+ stat_cnt_t bread_miss;
+ stat_cnt_t search_by_key;
+ stat_cnt_t search_by_key_fs_changed;
+ stat_cnt_t search_by_key_restarted;
+
+ stat_cnt_t insert_item_restarted;
+ stat_cnt_t paste_into_item_restarted;
+ stat_cnt_t cut_from_item_restarted;
+ stat_cnt_t delete_solid_item_restarted;
+ stat_cnt_t delete_item_restarted;
+
+ stat_cnt_t leaked_oid;
+ stat_cnt_t leaves_removable;
+
+ /* balances per level. Use explicit 5 as MAX_HEIGHT is not visible yet. */
+ stat_cnt_t balance_at[5]; /* XXX */
+ /* sbk == search_by_key */
+ stat_cnt_t sbk_read_at[5]; /* XXX */
+ stat_cnt_t sbk_fs_changed[5];
+ stat_cnt_t sbk_restarted[5];
+ stat_cnt_t items_at[5]; /* XXX */
+ stat_cnt_t free_at[5]; /* XXX */
+ stat_cnt_t can_node_be_removed[5]; /* XXX */
+ long int lnum[5]; /* XXX */
+ long int rnum[5]; /* XXX */
+ long int lbytes[5]; /* XXX */
+ long int rbytes[5]; /* XXX */
+ stat_cnt_t get_neighbors[5];
+ stat_cnt_t get_neighbors_restart[5];
+ stat_cnt_t need_l_neighbor[5];
+ stat_cnt_t need_r_neighbor[5];
+
+ stat_cnt_t free_block;
+ struct __scan_bitmap_stats {
+ stat_cnt_t call;
+ stat_cnt_t wait;
+ stat_cnt_t bmap;
+ stat_cnt_t retry;
+ stat_cnt_t in_journal_hint;
+ stat_cnt_t in_journal_nohint;
+ stat_cnt_t stolen;
+ } scan_bitmap;
+ struct __journal_stats {
+ stat_cnt_t in_journal;
+ stat_cnt_t in_journal_bitmap;
+ stat_cnt_t in_journal_reusable;
+ stat_cnt_t lock_journal;
+ stat_cnt_t lock_journal_wait;
+ stat_cnt_t journal_being;
+ stat_cnt_t journal_relock_writers;
+ stat_cnt_t journal_relock_wcount;
+ stat_cnt_t mark_dirty;
+ stat_cnt_t mark_dirty_already;
+ stat_cnt_t mark_dirty_notjournal;
+ stat_cnt_t restore_prepared;
+ stat_cnt_t prepare;
+ stat_cnt_t prepare_retry;
+ } journal;
} reiserfs_proc_info_data_t;
#else
-typedef struct reiserfs_proc_info_data
-{} reiserfs_proc_info_data_t;
+typedef struct reiserfs_proc_info_data {
+} reiserfs_proc_info_data_t;
#endif
/* reiserfs union of in-core super block data */
-struct reiserfs_sb_info
-{
- struct buffer_head * s_sbh; /* Buffer containing the super block */
- /* both the comment and the choice of
- name are unclear for s_rs -Hans */
- struct reiserfs_super_block * s_rs; /* Pointer to the super block in the buffer */
- struct reiserfs_bitmap_info * s_ap_bitmap;
- struct reiserfs_journal *s_journal ; /* pointer to journal information */
- unsigned short s_mount_state; /* reiserfs state (valid, invalid) */
-
- /* Comment? -Hans */
- void (*end_io_handler)(struct buffer_head *, int);
- hashf_t s_hash_function; /* pointer to function which is used
- to sort names in directory. Set on
- mount */
- unsigned long s_mount_opt; /* reiserfs's mount options are set
- here (currently - NOTAIL, NOLOG,
- REPLAYONLY) */
-
- struct { /* This is a structure that describes block allocator options */
- unsigned long bits; /* Bitfield for enable/disable kind of options */
- unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */
- int border; /* percentage of disk, border takes */
- int preallocmin; /* Minimal file size (in blocks) starting from which we do preallocations */
- int preallocsize; /* Number of blocks we try to prealloc when file
- reaches preallocmin size (in blocks) or
- prealloc_list is empty. */
- } s_alloc_options;
-
- /* Comment? -Hans */
- wait_queue_head_t s_wait;
- /* To be obsoleted soon by per buffer seals.. -Hans */
- atomic_t s_generation_counter; // increased by one every time the
- // tree gets re-balanced
- unsigned long s_properties; /* File system properties. Currently holds
- on-disk FS format */
-
- /* session statistics */
- int s_kmallocs;
- int s_disk_reads;
- int s_disk_writes;
- int s_fix_nodes;
- int s_do_balance;
- int s_unneeded_left_neighbor;
- int s_good_search_by_key_reada;
- int s_bmaps;
- int s_bmaps_without_search;
- int s_direct2indirect;
- int s_indirect2direct;
+struct reiserfs_sb_info {
+ struct buffer_head *s_sbh; /* Buffer containing the super block */
+ /* both the comment and the choice of
+ name are unclear for s_rs -Hans */
+ struct reiserfs_super_block *s_rs; /* Pointer to the super block in the buffer */
+ struct reiserfs_bitmap_info *s_ap_bitmap;
+ struct reiserfs_journal *s_journal; /* pointer to journal information */
+ unsigned short s_mount_state; /* reiserfs state (valid, invalid) */
+
+ /* Comment? -Hans */
+ void (*end_io_handler) (struct buffer_head *, int);
+ hashf_t s_hash_function; /* pointer to function which is used
+ to sort names in directory. Set on
+ mount */
+ unsigned long s_mount_opt; /* reiserfs's mount options are set
+ here (currently - NOTAIL, NOLOG,
+ REPLAYONLY) */
+
+ struct { /* This is a structure that describes block allocator options */
+ unsigned long bits; /* Bitfield for enable/disable kind of options */
+ unsigned long large_file_size; /* size started from which we consider file to be a large one(in blocks) */
+ int border; /* percentage of disk, border takes */
+ int preallocmin; /* Minimal file size (in blocks) starting from which we do preallocations */
+ int preallocsize; /* Number of blocks we try to prealloc when file
+ reaches preallocmin size (in blocks) or
+ prealloc_list is empty. */
+ } s_alloc_options;
+
+ /* Comment? -Hans */
+ wait_queue_head_t s_wait;
+ /* To be obsoleted soon by per buffer seals.. -Hans */
+ atomic_t s_generation_counter; // increased by one every time the
+ // tree gets re-balanced
+ unsigned long s_properties; /* File system properties. Currently holds
+ on-disk FS format */
+
+ /* session statistics */
+ int s_kmallocs;
+ int s_disk_reads;
+ int s_disk_writes;
+ int s_fix_nodes;
+ int s_do_balance;
+ int s_unneeded_left_neighbor;
+ int s_good_search_by_key_reada;
+ int s_bmaps;
+ int s_bmaps_without_search;
+ int s_direct2indirect;
+ int s_indirect2direct;
/* set up when it's ok for reiserfs_read_inode2() to read from
disk inode with nlink==0. Currently this is only used during
finish_unfinished() processing at mount time */
- int s_is_unlinked_ok;
- reiserfs_proc_info_data_t s_proc_info_data;
- struct proc_dir_entry *procdir;
- int reserved_blocks; /* amount of blocks reserved for further allocations */
- spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
- struct dentry *priv_root; /* root of /.reiserfs_priv */
- struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
- struct rw_semaphore xattr_dir_sem;
-
- int j_errno;
+ int s_is_unlinked_ok;
+ reiserfs_proc_info_data_t s_proc_info_data;
+ struct proc_dir_entry *procdir;
+ int reserved_blocks; /* amount of blocks reserved for further allocations */
+ spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
+ struct dentry *priv_root; /* root of /.reiserfs_priv */
+ struct dentry *xattr_root; /* root of /.reiserfs_priv/.xa */
+ struct rw_semaphore xattr_dir_sem;
+
+ int j_errno;
#ifdef CONFIG_QUOTA
- char *s_qf_names[MAXQUOTAS];
- int s_jquota_fmt;
+ char *s_qf_names[MAXQUOTAS];
+ int s_jquota_fmt;
#endif
};
@@ -422,14 +418,14 @@ struct reiserfs_sb_info
enum reiserfs_mount_options {
/* Mount options */
- REISERFS_LARGETAIL, /* large tails will be created in a session */
- REISERFS_SMALLTAIL, /* small (for files less than block size) tails will be created in a session */
- REPLAYONLY, /* replay journal and return 0. Use by fsck */
- REISERFS_CONVERT, /* -o conv: causes conversion of old
- format super block to the new
- format. If not specified - old
- partition will be dealt with in a
- manner of 3.5.x */
+ REISERFS_LARGETAIL, /* large tails will be created in a session */
+ REISERFS_SMALLTAIL, /* small (for files less than block size) tails will be created in a session */
+ REPLAYONLY, /* replay journal and return 0. Use by fsck */
+ REISERFS_CONVERT, /* -o conv: causes conversion of old
+ format super block to the new
+ format. If not specified - old
+ partition will be dealt with in a
+ manner of 3.5.x */
/* -o hash={tea, rupasov, r5, detect} is meant for properly mounting
** reiserfs disks from 3.5.19 or earlier. 99% of the time, this option
@@ -439,39 +435,41 @@ enum reiserfs_mount_options {
** the existing hash on the FS, so if you have a tea hash disk, and mount
** with -o hash=rupasov, the mount will fail.
*/
- FORCE_TEA_HASH, /* try to force tea hash on mount */
- FORCE_RUPASOV_HASH, /* try to force rupasov hash on mount */
- FORCE_R5_HASH, /* try to force rupasov hash on mount */
- FORCE_HASH_DETECT, /* try to detect hash function on mount */
+ FORCE_TEA_HASH, /* try to force tea hash on mount */
+ FORCE_RUPASOV_HASH, /* try to force rupasov hash on mount */
+ FORCE_R5_HASH, /* try to force rupasov hash on mount */
+ FORCE_HASH_DETECT, /* try to detect hash function on mount */
- REISERFS_DATA_LOG,
- REISERFS_DATA_ORDERED,
- REISERFS_DATA_WRITEBACK,
+ REISERFS_DATA_LOG,
+ REISERFS_DATA_ORDERED,
+ REISERFS_DATA_WRITEBACK,
/* used for testing experimental features, makes benchmarking new
features with and without more convenient, should never be used by
users in any code shipped to users (ideally) */
- REISERFS_NO_BORDER,
- REISERFS_NO_UNHASHED_RELOCATION,
- REISERFS_HASHED_RELOCATION,
- REISERFS_ATTRS,
- REISERFS_XATTRS,
- REISERFS_XATTRS_USER,
- REISERFS_POSIXACL,
- REISERFS_BARRIER_NONE,
- REISERFS_BARRIER_FLUSH,
-
- /* Actions on error */
- REISERFS_ERROR_PANIC,
- REISERFS_ERROR_RO,
- REISERFS_ERROR_CONTINUE,
-
- REISERFS_TEST1,
- REISERFS_TEST2,
- REISERFS_TEST3,
- REISERFS_TEST4,
- REISERFS_UNSUPPORTED_OPT,
+ REISERFS_NO_BORDER,
+ REISERFS_NO_UNHASHED_RELOCATION,
+ REISERFS_HASHED_RELOCATION,
+ REISERFS_ATTRS,
+ REISERFS_XATTRS,
+ REISERFS_XATTRS_USER,
+ REISERFS_POSIXACL,
+ REISERFS_BARRIER_NONE,
+ REISERFS_BARRIER_FLUSH,
+
+ /* Actions on error */
+ REISERFS_ERROR_PANIC,
+ REISERFS_ERROR_RO,
+ REISERFS_ERROR_CONTINUE,
+
+ REISERFS_QUOTA, /* Some quota option specified */
+
+ REISERFS_TEST1,
+ REISERFS_TEST2,
+ REISERFS_TEST3,
+ REISERFS_TEST4,
+ REISERFS_UNSUPPORTED_OPT,
};
#define reiserfs_r5_hash(s) (REISERFS_SB(s)->s_mount_opt & (1 << FORCE_R5_HASH))
@@ -502,18 +500,17 @@ enum reiserfs_mount_options {
#define reiserfs_error_panic(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_PANIC))
#define reiserfs_error_ro(s) (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_ERROR_RO))
-void reiserfs_file_buffer (struct buffer_head * bh, int list);
+void reiserfs_file_buffer(struct buffer_head *bh, int list);
extern struct file_system_type reiserfs_fs_type;
-int reiserfs_resize(struct super_block *, unsigned long) ;
+int reiserfs_resize(struct super_block *, unsigned long);
#define CARRY_ON 0
#define SCHEDULE_OCCURRED 1
-
#define SB_BUFFER_WITH_SB(s) (REISERFS_SB(s)->s_sbh)
#define SB_JOURNAL(s) (REISERFS_SB(s)->s_journal)
#define SB_JOURNAL_1st_RESERVED_BLOCK(s) (SB_JOURNAL(s)->j_1st_reserved_block)
-#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
+#define SB_JOURNAL_LEN_FREE(s) (SB_JOURNAL(s)->j_journal_len_free)
#define SB_AP_BITMAP(s) (REISERFS_SB(s)->s_ap_bitmap)
#define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
@@ -523,13 +520,14 @@ int reiserfs_resize(struct super_block *, unsigned long) ;
*/
static inline char *reiserfs_bdevname(struct super_block *s)
{
- return (s == NULL) ? "Null superblock" : s -> s_id;
+ return (s == NULL) ? "Null superblock" : s->s_id;
}
#define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
-static inline int __reiserfs_is_journal_aborted (struct reiserfs_journal *journal)
+static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
+ *journal)
{
- return test_bit (J_ABORTED, &journal->j_state);
+ return test_bit(J_ABORTED, &journal->j_state);
}
-#endif /* _LINUX_REISER_FS_SB */
+#endif /* _LINUX_REISER_FS_SB */
diff --git a/include/linux/reiserfs_xattr.h b/include/linux/reiserfs_xattr.h
index 9244c5748820..c84354e8374c 100644
--- a/include/linux/reiserfs_xattr.h
+++ b/include/linux/reiserfs_xattr.h
@@ -7,48 +7,48 @@
#include <linux/xattr.h>
/* Magic value in header */
-#define REISERFS_XATTR_MAGIC 0x52465841 /* "RFXA" */
+#define REISERFS_XATTR_MAGIC 0x52465841 /* "RFXA" */
struct reiserfs_xattr_header {
- __le32 h_magic; /* magic number for identification */
- __le32 h_hash; /* hash of the value */
+ __le32 h_magic; /* magic number for identification */
+ __le32 h_hash; /* hash of the value */
};
#ifdef __KERNEL__
struct reiserfs_xattr_handler {
char *prefix;
- int (*init)(void);
- void (*exit)(void);
- int (*get)(struct inode *inode, const char *name, void *buffer,
- size_t size);
- int (*set)(struct inode *inode, const char *name, const void *buffer,
- size_t size, int flags);
- int (*del)(struct inode *inode, const char *name);
- int (*list)(struct inode *inode, const char *name, int namelen, char *out);
- struct list_head handlers;
+ int (*init) (void);
+ void (*exit) (void);
+ int (*get) (struct inode * inode, const char *name, void *buffer,
+ size_t size);
+ int (*set) (struct inode * inode, const char *name, const void *buffer,
+ size_t size, int flags);
+ int (*del) (struct inode * inode, const char *name);
+ int (*list) (struct inode * inode, const char *name, int namelen,
+ char *out);
+ struct list_head handlers;
};
-
#ifdef CONFIG_REISERFS_FS_XATTR
#define is_reiserfs_priv_object(inode) IS_PRIVATE(inode)
#define has_xattr_dir(inode) (REISERFS_I(inode)->i_flags & i_has_xattr_dir)
-ssize_t reiserfs_getxattr (struct dentry *dentry, const char *name,
- void *buffer, size_t size);
-int reiserfs_setxattr (struct dentry *dentry, const char *name,
- const void *value, size_t size, int flags);
-ssize_t reiserfs_listxattr (struct dentry *dentry, char *buffer, size_t size);
-int reiserfs_removexattr (struct dentry *dentry, const char *name);
-int reiserfs_delete_xattrs (struct inode *inode);
-int reiserfs_chown_xattrs (struct inode *inode, struct iattr *attrs);
-int reiserfs_xattr_init (struct super_block *sb, int mount_flags);
-int reiserfs_permission (struct inode *inode, int mask, struct nameidata *nd);
-int reiserfs_permission_locked (struct inode *inode, int mask, struct nameidata *nd);
-
-int reiserfs_xattr_del (struct inode *, const char *);
-int reiserfs_xattr_get (const struct inode *, const char *, void *, size_t);
-int reiserfs_xattr_set (struct inode *, const char *, const void *,
- size_t, int);
+ssize_t reiserfs_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size);
+int reiserfs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags);
+ssize_t reiserfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
+int reiserfs_removexattr(struct dentry *dentry, const char *name);
+int reiserfs_delete_xattrs(struct inode *inode);
+int reiserfs_chown_xattrs(struct inode *inode, struct iattr *attrs);
+int reiserfs_xattr_init(struct super_block *sb, int mount_flags);
+int reiserfs_permission(struct inode *inode, int mask, struct nameidata *nd);
+int reiserfs_permission_locked(struct inode *inode, int mask,
+ struct nameidata *nd);
+
+int reiserfs_xattr_del(struct inode *, const char *);
+int reiserfs_xattr_get(const struct inode *, const char *, void *, size_t);
+int reiserfs_xattr_set(struct inode *, const char *, const void *, size_t, int);
extern struct reiserfs_xattr_handler user_handler;
extern struct reiserfs_xattr_handler trusted_handler;
@@ -56,57 +56,48 @@ extern struct reiserfs_xattr_handler trusted_handler;
extern struct reiserfs_xattr_handler security_handler;
#endif
-int reiserfs_xattr_register_handlers (void) __init;
-void reiserfs_xattr_unregister_handlers (void);
+int reiserfs_xattr_register_handlers(void) __init;
+void reiserfs_xattr_unregister_handlers(void);
-static inline void
-reiserfs_write_lock_xattrs(struct super_block *sb)
+static inline void reiserfs_write_lock_xattrs(struct super_block *sb)
{
- down_write (&REISERFS_XATTR_DIR_SEM(sb));
+ down_write(&REISERFS_XATTR_DIR_SEM(sb));
}
-static inline void
-reiserfs_write_unlock_xattrs(struct super_block *sb)
+static inline void reiserfs_write_unlock_xattrs(struct super_block *sb)
{
- up_write (&REISERFS_XATTR_DIR_SEM(sb));
+ up_write(&REISERFS_XATTR_DIR_SEM(sb));
}
-static inline void
-reiserfs_read_lock_xattrs(struct super_block *sb)
+static inline void reiserfs_read_lock_xattrs(struct super_block *sb)
{
- down_read (&REISERFS_XATTR_DIR_SEM(sb));
+ down_read(&REISERFS_XATTR_DIR_SEM(sb));
}
-static inline void
-reiserfs_read_unlock_xattrs(struct super_block *sb)
+static inline void reiserfs_read_unlock_xattrs(struct super_block *sb)
{
- up_read (&REISERFS_XATTR_DIR_SEM(sb));
+ up_read(&REISERFS_XATTR_DIR_SEM(sb));
}
-static inline void
-reiserfs_write_lock_xattr_i(struct inode *inode)
+static inline void reiserfs_write_lock_xattr_i(struct inode *inode)
{
- down_write (&REISERFS_I(inode)->xattr_sem);
+ down_write(&REISERFS_I(inode)->xattr_sem);
}
-static inline void
-reiserfs_write_unlock_xattr_i(struct inode *inode)
+static inline void reiserfs_write_unlock_xattr_i(struct inode *inode)
{
- up_write (&REISERFS_I(inode)->xattr_sem);
+ up_write(&REISERFS_I(inode)->xattr_sem);
}
-static inline void
-reiserfs_read_lock_xattr_i(struct inode *inode)
+static inline void reiserfs_read_lock_xattr_i(struct inode *inode)
{
- down_read (&REISERFS_I(inode)->xattr_sem);
+ down_read(&REISERFS_I(inode)->xattr_sem);
}
-static inline void
-reiserfs_read_unlock_xattr_i(struct inode *inode)
+static inline void reiserfs_read_unlock_xattr_i(struct inode *inode)
{
- up_read (&REISERFS_I(inode)->xattr_sem);
+ up_read(&REISERFS_I(inode)->xattr_sem);
}
-static inline void
-reiserfs_mark_inode_private(struct inode *inode)
+static inline void reiserfs_mark_inode_private(struct inode *inode)
{
- inode->i_flags |= S_PRIVATE;
+ inode->i_flags |= S_PRIVATE;
}
#else
@@ -127,13 +118,20 @@ reiserfs_mark_inode_private(struct inode *inode)
#define reiserfs_xattr_register_handlers() 0
#define reiserfs_xattr_unregister_handlers()
-static inline int reiserfs_delete_xattrs (struct inode *inode) { return 0; };
-static inline int reiserfs_chown_xattrs (struct inode *inode, struct iattr *attrs) { return 0; };
-static inline int reiserfs_xattr_init (struct super_block *sb, int mount_flags)
+static inline int reiserfs_delete_xattrs(struct inode *inode)
+{
+ return 0;
+};
+static inline int reiserfs_chown_xattrs(struct inode *inode,
+ struct iattr *attrs)
+{
+ return 0;
+};
+static inline int reiserfs_xattr_init(struct super_block *sb, int mount_flags)
{
- sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
- return 0;
+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL); /* to be sure */
+ return 0;
};
#endif
-#endif /* __KERNEL__ */
+#endif /* __KERNEL__ */
diff --git a/include/linux/rmap.h b/include/linux/rmap.h
index 11b484e37ac9..e80fb7ee6efd 100644
--- a/include/linux/rmap.h
+++ b/include/linux/rmap.h
@@ -93,6 +93,12 @@ int page_referenced(struct page *, int is_locked, int ignore_token);
int try_to_unmap(struct page *);
/*
+ * Called from mm/filemap_xip.c to unmap empty zero page
+ */
+pte_t *page_check_address(struct page *, struct mm_struct *, unsigned long);
+
+
+/*
* Used by swapoff to help locate where page is expected in vma.
*/
unsigned long page_address_in_vma(struct page *, struct vm_area_struct *);
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index e68dbf0bf579..657c05ab8f9e 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -363,6 +363,8 @@ enum
struct rta_session
{
__u8 proto;
+ __u8 pad1;
+ __u16 pad2;
union {
struct {
@@ -635,10 +637,13 @@ struct ifinfomsg
struct prefixmsg
{
unsigned char prefix_family;
+ unsigned char prefix_pad1;
+ unsigned short prefix_pad2;
int prefix_ifindex;
unsigned char prefix_type;
unsigned char prefix_len;
unsigned char prefix_flags;
+ unsigned char prefix_pad3;
};
enum
@@ -892,10 +897,15 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi
goto rtattr_failure; \
__rta_fill(skb, attrtype, attrlen, data); })
-#define RTA_PUT_NOHDR(skb, attrlen, data) \
+#define RTA_APPEND(skb, attrlen, data) \
({ if (unlikely(skb_tailroom(skb) < (int)(attrlen))) \
goto rtattr_failure; \
- memcpy(skb_put(skb, RTA_ALIGN(attrlen)), data, attrlen); })
+ memcpy(skb_put(skb, attrlen), data, attrlen); })
+
+#define RTA_PUT_NOHDR(skb, attrlen, data) \
+({ RTA_APPEND(skb, RTA_ALIGN(attrlen), data); \
+ memset(skb->tail - (RTA_ALIGN(attrlen) - attrlen), 0, \
+ RTA_ALIGN(attrlen) - attrlen); })
#define RTA_PUT_U8(skb, attrtype, value) \
({ u8 _tmp = (value); \
@@ -975,6 +985,7 @@ __rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
rta->rta_type = attrtype;
rta->rta_len = size;
+ memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
return rta;
}
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 901742f92389..dec5827c7742 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -368,6 +368,11 @@ struct signal_struct {
#endif
};
+/* Context switch must be unlocked if interrupts are to be enabled */
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+# define __ARCH_WANT_UNLOCKED_CTXSW
+#endif
+
/*
* Bits in flags field of signal_struct.
*/
@@ -405,6 +410,10 @@ struct user_struct {
atomic_t processes; /* How many processes does this user have? */
atomic_t files; /* How many open files does this user have? */
atomic_t sigpending; /* How many pending signals does this user have? */
+#ifdef CONFIG_INOTIFY
+ atomic_t inotify_watches; /* How many inotify watches does this user have? */
+ atomic_t inotify_devs; /* How many inotify devs does this user have opened? */
+#endif
/* protected by mq_lock */
unsigned long mq_bytes; /* How many bytes can be allocated to mqueue? */
unsigned long locked_shm; /* How many pages of mlocked shm ? */
@@ -460,10 +469,11 @@ enum idle_type
#define SD_LOAD_BALANCE 1 /* Do load balancing on this domain. */
#define SD_BALANCE_NEWIDLE 2 /* Balance when about to become idle */
#define SD_BALANCE_EXEC 4 /* Balance on exec */
-#define SD_WAKE_IDLE 8 /* Wake to idle CPU on task wakeup */
-#define SD_WAKE_AFFINE 16 /* Wake task to waking CPU */
-#define SD_WAKE_BALANCE 32 /* Perform balancing at task wakeup */
-#define SD_SHARE_CPUPOWER 64 /* Domain members share cpu power */
+#define SD_BALANCE_FORK 8 /* Balance on fork, clone */
+#define SD_WAKE_IDLE 16 /* Wake to idle CPU on task wakeup */
+#define SD_WAKE_AFFINE 32 /* Wake task to waking CPU */
+#define SD_WAKE_BALANCE 64 /* Perform balancing at task wakeup */
+#define SD_SHARE_CPUPOWER 128 /* Domain members share cpu power */
struct sched_group {
struct sched_group *next; /* Must be a circular list */
@@ -488,6 +498,11 @@ struct sched_domain {
unsigned long long cache_hot_time; /* Task considered cache hot (ns) */
unsigned int cache_nice_tries; /* Leave cache hot tasks for # tries */
unsigned int per_cpu_gain; /* CPU % gained by adding domain cpus */
+ unsigned int busy_idx;
+ unsigned int idle_idx;
+ unsigned int newidle_idx;
+ unsigned int wake_idx;
+ unsigned int forkexec_idx;
int flags; /* See SD_* */
/* Runtime fields. */
@@ -511,10 +526,16 @@ struct sched_domain {
unsigned long alb_failed;
unsigned long alb_pushed;
- /* sched_balance_exec() stats */
- unsigned long sbe_attempts;
+ /* SD_BALANCE_EXEC stats */
+ unsigned long sbe_cnt;
+ unsigned long sbe_balanced;
unsigned long sbe_pushed;
+ /* SD_BALANCE_FORK stats */
+ unsigned long sbf_cnt;
+ unsigned long sbf_balanced;
+ unsigned long sbf_pushed;
+
/* try_to_wake_up() stats */
unsigned long ttwu_wake_remote;
unsigned long ttwu_move_affine;
@@ -522,6 +543,8 @@ struct sched_domain {
#endif
};
+extern void partition_sched_domains(cpumask_t *partition1,
+ cpumask_t *partition2);
#ifdef ARCH_HAS_SCHED_DOMAIN
/* Useful helpers that arch setup code may use. Defined in kernel/sched.c */
extern cpumask_t cpu_isolated_map;
@@ -561,9 +584,10 @@ struct group_info {
groups_free(group_info); \
} while (0)
-struct group_info *groups_alloc(int gidsetsize);
-void groups_free(struct group_info *group_info);
-int set_current_groups(struct group_info *group_info);
+extern struct group_info *groups_alloc(int gidsetsize);
+extern void groups_free(struct group_info *group_info);
+extern int set_current_groups(struct group_info *group_info);
+extern int groups_search(struct group_info *group_info, gid_t grp);
/* access the groups "array" with this macro */
#define GROUP_AT(gi, i) \
((gi)->blocks[(i)/NGROUPS_PER_BLOCK][(i)%NGROUPS_PER_BLOCK])
@@ -581,10 +605,15 @@ struct task_struct {
int lock_depth; /* BKL lock depth */
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+ int oncpu;
+#endif
int prio, static_prio;
struct list_head run_list;
prio_array_t *array;
+ unsigned short ioprio;
+
unsigned long sleep_avg;
unsigned long long timestamp, last_ran;
unsigned long long sched_time; /* sched_clock time spent running */
@@ -660,6 +689,7 @@ struct task_struct {
struct user_struct *user;
#ifdef CONFIG_KEYS
struct key *thread_keyring; /* keyring private to this thread */
+ unsigned char jit_keyring; /* default keyring to attach requested keys to */
#endif
int oomkilladj; /* OOM kill score adjustment (bit shift). */
char comm[TASK_COMM_LEN]; /* executable name excluding path
@@ -702,8 +732,6 @@ struct task_struct {
spinlock_t alloc_lock;
/* Protection of proc_dentry: nesting proc_lock, dcache_lock, write_lock_irq(&tasklist_lock); */
spinlock_t proc_lock;
-/* context-switch lock */
- spinlock_t switch_lock;
/* journalling filesystem info */
void *journal_info;
@@ -741,6 +769,7 @@ struct task_struct {
nodemask_t mems_allowed;
int cpuset_mems_generation;
#endif
+ atomic_t fs_excl; /* holding fs exclusive resources */
};
static inline pid_t process_group(struct task_struct *tsk)
@@ -910,7 +939,7 @@ extern void FASTCALL(wake_up_new_task(struct task_struct * tsk,
#else
static inline void kick_process(struct task_struct *tsk) { }
#endif
-extern void FASTCALL(sched_fork(task_t * p));
+extern void FASTCALL(sched_fork(task_t * p, int clone_flags));
extern void FASTCALL(sched_exit(task_t * p));
extern int in_group_p(gid_t);
@@ -1090,7 +1119,8 @@ extern void unhash_process(struct task_struct *p);
/*
* Protects ->fs, ->files, ->mm, ->ptrace, ->group_info, ->comm, keyring
- * subscriptions and synchronises with wait4(). Also used in procfs.
+ * subscriptions and synchronises with wait4(). Also used in procfs. Also
+ * pins the final release of task.io_context.
*
* Nests both inside and outside of read_lock(&tasklist_lock).
* It must not be nested with write_lock_irq(&tasklist_lock),
@@ -1243,33 +1273,78 @@ extern void normalize_rt_tasks(void);
#endif
-/* try_to_freeze
- *
- * Checks whether we need to enter the refrigerator
- * and returns 1 if we did so.
- */
#ifdef CONFIG_PM
-extern void refrigerator(unsigned long);
+/*
+ * Check if a process has been frozen
+ */
+static inline int frozen(struct task_struct *p)
+{
+ return p->flags & PF_FROZEN;
+}
+
+/*
+ * Check if there is a request to freeze a process
+ */
+static inline int freezing(struct task_struct *p)
+{
+ return p->flags & PF_FREEZE;
+}
+
+/*
+ * Request that a process be frozen
+ * FIXME: SMP problem. We may not modify other process' flags!
+ */
+static inline void freeze(struct task_struct *p)
+{
+ p->flags |= PF_FREEZE;
+}
+
+/*
+ * Wake up a frozen process
+ */
+static inline int thaw_process(struct task_struct *p)
+{
+ if (frozen(p)) {
+ p->flags &= ~PF_FROZEN;
+ wake_up_process(p);
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * freezing is complete, mark process as frozen
+ */
+static inline void frozen_process(struct task_struct *p)
+{
+ p->flags = (p->flags & ~PF_FREEZE) | PF_FROZEN;
+}
+
+extern void refrigerator(void);
extern int freeze_processes(void);
extern void thaw_processes(void);
-static inline int try_to_freeze(unsigned long refrigerator_flags)
+static inline int try_to_freeze(void)
{
- if (unlikely(current->flags & PF_FREEZE)) {
- refrigerator(refrigerator_flags);
+ if (freezing(current)) {
+ refrigerator();
return 1;
} else
return 0;
}
#else
-static inline void refrigerator(unsigned long flag) {}
+static inline int frozen(struct task_struct *p) { return 0; }
+static inline int freezing(struct task_struct *p) { return 0; }
+static inline void freeze(struct task_struct *p) { BUG(); }
+static inline int thaw_process(struct task_struct *p) { return 1; }
+static inline void frozen_process(struct task_struct *p) { BUG(); }
+
+static inline void refrigerator(void) {}
static inline int freeze_processes(void) { BUG(); return 0; }
static inline void thaw_processes(void) {}
-static inline int try_to_freeze(unsigned long refrigerator_flags)
-{
- return 0;
-}
+static inline int try_to_freeze(void) { return 0; }
+
#endif /* CONFIG_PM */
#endif /* __KERNEL__ */
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index 3a2702bbb1d6..dc89116bb1ca 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -19,6 +19,11 @@ static inline void secure_computing(int this_syscall)
__secure_computing(this_syscall);
}
+static inline int has_secure_computing(struct thread_info *ti)
+{
+ return unlikely(test_ti_thread_flag(ti, TIF_SECCOMP));
+}
+
#else /* CONFIG_SECCOMP */
#if (__GNUC__ > 2)
@@ -28,6 +33,11 @@ static inline void secure_computing(int this_syscall)
#endif
#define secure_computing(x) do { } while (0)
+/* static inline to preserve typechecking */
+static inline int has_secure_computing(struct thread_info *ti)
+{
+ return 0;
+}
#endif /* CONFIG_SECCOMP */
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index 823181af6ddf..3e3c1fa35b06 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -22,6 +22,7 @@ struct plat_serial8250_port {
unsigned int uartclk; /* UART clock rate */
unsigned char regshift; /* register shift */
unsigned char iotype; /* UPIO_* */
+ unsigned char hub6;
unsigned int flags; /* UPF_* flags */
};
diff --git a/include/linux/serio.h b/include/linux/serio.h
index a2d3b9ae06f4..aa4d6493a034 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -83,6 +83,7 @@ static inline void serio_register_port(struct serio *serio)
}
void serio_unregister_port(struct serio *serio);
+void serio_unregister_child_port(struct serio *serio);
void __serio_unregister_port_delayed(struct serio *serio, struct module *owner);
static inline void serio_unregister_port_delayed(struct serio *serio)
{
@@ -153,6 +154,11 @@ static inline int serio_pin_driver(struct serio *serio)
return down_interruptible(&serio->drv_sem);
}
+static inline void serio_pin_driver_uninterruptible(struct serio *serio)
+{
+ down(&serio->drv_sem);
+}
+
static inline void serio_unpin_driver(struct serio *serio)
{
up(&serio->drv_sem);
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index d7c839a21842..5d4a990d5577 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -27,6 +27,7 @@
#include <linux/highmem.h>
#include <linux/poll.h>
#include <linux/net.h>
+#include <linux/textsearch.h>
#include <net/checksum.h>
#define HAVE_ALLOC_SKB /* For the drivers to know */
@@ -182,7 +183,6 @@ struct skb_shared_info {
* @priority: Packet queueing priority
* @users: User count - see {datagram,tcp}.c
* @protocol: Packet protocol from driver
- * @security: Security level of packet
* @truesize: Buffer size
* @head: Head of buffer
* @data: Data head pointer
@@ -248,18 +248,18 @@ struct sk_buff {
data_len,
mac_len,
csum;
- unsigned char local_df,
- cloned:1,
- nohdr:1,
- pkt_type,
- ip_summed;
__u32 priority;
- unsigned short protocol,
- security;
+ __u8 local_df:1,
+ cloned:1,
+ ip_summed:2,
+ nohdr:1;
+ /* 3 bits spare */
+ __u8 pkt_type;
+ __u16 protocol;
void (*destructor)(struct sk_buff *skb);
#ifdef CONFIG_NETFILTER
- unsigned long nfmark;
+ unsigned long nfmark;
__u32 nfcache;
__u32 nfctinfo;
struct nf_conntrack *nfct;
@@ -300,20 +300,26 @@ struct sk_buff {
#include <asm/system.h>
extern void __kfree_skb(struct sk_buff *skb);
-extern struct sk_buff *alloc_skb(unsigned int size, int priority);
+extern struct sk_buff *alloc_skb(unsigned int size,
+ unsigned int __nocast priority);
extern struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
- unsigned int size, int priority);
+ unsigned int size,
+ unsigned int __nocast priority);
extern void kfree_skbmem(struct sk_buff *skb);
-extern struct sk_buff *skb_clone(struct sk_buff *skb, int priority);
-extern struct sk_buff *skb_copy(const struct sk_buff *skb, int priority);
-extern struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask);
+extern struct sk_buff *skb_clone(struct sk_buff *skb,
+ unsigned int __nocast priority);
+extern struct sk_buff *skb_copy(const struct sk_buff *skb,
+ unsigned int __nocast priority);
+extern struct sk_buff *pskb_copy(struct sk_buff *skb,
+ unsigned int __nocast gfp_mask);
extern int pskb_expand_head(struct sk_buff *skb,
- int nhead, int ntail, int gfp_mask);
+ int nhead, int ntail,
+ unsigned int __nocast gfp_mask);
extern struct sk_buff *skb_realloc_headroom(struct sk_buff *skb,
unsigned int headroom);
extern struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
int newheadroom, int newtailroom,
- int priority);
+ unsigned int __nocast priority);
extern struct sk_buff * skb_pad(struct sk_buff *skb, int pad);
#define dev_kfree_skb(a) kfree_skb(a)
extern void skb_over_panic(struct sk_buff *skb, int len,
@@ -321,6 +327,28 @@ extern void skb_over_panic(struct sk_buff *skb, int len,
extern void skb_under_panic(struct sk_buff *skb, int len,
void *here);
+struct skb_seq_state
+{
+ __u32 lower_offset;
+ __u32 upper_offset;
+ __u32 frag_idx;
+ __u32 stepped_offset;
+ struct sk_buff *root_skb;
+ struct sk_buff *cur_skb;
+ __u8 *frag_data;
+};
+
+extern void skb_prepare_seq_read(struct sk_buff *skb,
+ unsigned int from, unsigned int to,
+ struct skb_seq_state *st);
+extern unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
+ struct skb_seq_state *st);
+extern void skb_abort_seq_read(struct skb_seq_state *st);
+
+extern unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
+ unsigned int to, struct ts_config *config,
+ struct ts_state *state);
+
/* Internal */
#define skb_shinfo(SKB) ((struct skb_shared_info *)((SKB)->end))
@@ -442,7 +470,8 @@ static inline int skb_shared(const struct sk_buff *skb)
*
* NULL is returned on a memory allocation failure.
*/
-static inline struct sk_buff *skb_share_check(struct sk_buff *skb, int pri)
+static inline struct sk_buff *skb_share_check(struct sk_buff *skb,
+ unsigned int __nocast pri)
{
might_sleep_if(pri & __GFP_WAIT);
if (skb_shared(skb)) {
@@ -979,7 +1008,7 @@ static inline void __skb_queue_purge(struct sk_buff_head *list)
* %NULL is returned in there is no free memory.
*/
static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
- int gfp_mask)
+ unsigned int __nocast gfp_mask)
{
struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
if (likely(skb))
@@ -1092,8 +1121,8 @@ static inline int skb_can_coalesce(struct sk_buff *skb, int i,
* If there is no free memory -ENOMEM is returned, otherwise zero
* is returned and the old skb data released.
*/
-extern int __skb_linearize(struct sk_buff *skb, int gfp);
-static inline int skb_linearize(struct sk_buff *skb, int gfp)
+extern int __skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp);
+static inline int skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp)
{
return __skb_linearize(skb, gfp);
}
@@ -1188,7 +1217,7 @@ static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
{
int hlen = skb_headlen(skb);
- if (offset + len <= hlen)
+ if (hlen - offset >= len)
return skb->data + offset;
if (skb_copy_bits(skb, offset, buffer, len) < 0)
diff --git a/include/linux/slab.h b/include/linux/slab.h
index 76cf7e60216c..4c8e552471b0 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -65,7 +65,7 @@ extern void *kmem_cache_alloc(kmem_cache_t *, unsigned int __nocast);
extern void kmem_cache_free(kmem_cache_t *, void *);
extern unsigned int kmem_cache_size(kmem_cache_t *);
extern const char *kmem_cache_name(kmem_cache_t *);
-extern kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags);
+extern kmem_cache_t *kmem_find_general_cachep(size_t size, unsigned int __nocast gfpflags);
/* Size description struct for general caches. */
struct cache_sizes {
@@ -105,7 +105,7 @@ extern unsigned int ksize(const void *);
#ifdef CONFIG_NUMA
extern void *kmem_cache_alloc_node(kmem_cache_t *, int flags, int node);
-extern void *kmalloc_node(size_t size, int flags, int node);
+extern void *kmalloc_node(size_t size, unsigned int __nocast flags, int node);
#else
static inline void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int node)
{
diff --git a/include/linux/string.h b/include/linux/string.h
index 93994c613095..dab2652acbd8 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -88,7 +88,7 @@ extern int memcmp(const void *,const void *,__kernel_size_t);
extern void * memchr(const void *,int,__kernel_size_t);
#endif
-extern char *kstrdup(const char *s, int gfp);
+extern char *kstrdup(const char *s, unsigned int __nocast gfp);
#ifdef __cplusplus
}
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 2bf0d5fabcdb..f2e96fdfaae0 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -58,7 +58,7 @@ static inline int software_suspend(void)
}
#endif
-#ifdef CONFIG_SMP
+#ifdef CONFIG_SUSPEND_SMP
extern void disable_nonboot_cpus(void);
extern void enable_nonboot_cpus(void);
#else
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 2343f999e6e1..239f520cc49e 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -7,6 +7,8 @@
#include <linux/mmzone.h>
#include <linux/list.h>
#include <linux/sched.h>
+#include <linux/pagemap.h>
+
#include <asm/atomic.h>
#include <asm/page.h>
@@ -148,7 +150,7 @@ struct swap_list_t {
#define vm_swap_full() (nr_swap_pages*2 < total_swap_pages)
/* linux/mm/oom_kill.c */
-extern void out_of_memory(unsigned int __nocast gfp_mask);
+extern void out_of_memory(unsigned int __nocast gfp_mask, int order);
/* linux/mm/memory.c */
extern void swapin_readahead(swp_entry_t, unsigned long, struct vm_area_struct *);
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index c39f6f72cbbc..425f58c8ea4a 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -159,8 +159,9 @@ asmlinkage long sys_shutdown(int, int);
asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd,
void __user *arg);
asmlinkage long sys_restart_syscall(void);
-asmlinkage long sys_kexec_load(void *entry, unsigned long nr_segments,
- struct kexec_segment *segments, unsigned long flags);
+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
+ struct kexec_segment __user *segments,
+ unsigned long flags);
asmlinkage long sys_exit(int error_code);
asmlinkage void sys_exit_group(int error_code);
@@ -505,4 +506,7 @@ asmlinkage long sys_request_key(const char __user *_type,
asmlinkage long sys_keyctl(int cmd, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5);
+asmlinkage long sys_ioprio_set(int which, int who, int ioprio);
+asmlinkage long sys_ioprio_get(int which, int who);
+
#endif
diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
index 614e939c78a4..ce19a2aa0b21 100644
--- a/include/linux/sysctl.h
+++ b/include/linux/sysctl.h
@@ -61,7 +61,8 @@ enum
CTL_DEV=7, /* Devices */
CTL_BUS=8, /* Busses */
CTL_ABI=9, /* Binary emulation */
- CTL_CPU=10 /* CPU stuff (speed scaling, etc) */
+ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */
+ CTL_INOTIFY=11 /* Inotify */
};
/* CTL_BUS names: */
@@ -70,6 +71,14 @@ enum
CTL_BUS_ISA=1 /* ISA */
};
+/* CTL_INOTIFY names: */
+enum
+{
+ INOTIFY_MAX_USER_DEVICES=1, /* max number of inotify device instances per user */
+ INOTIFY_MAX_USER_WATCHES=2, /* max number of inotify watches per user */
+ INOTIFY_MAX_QUEUED_EVENTS=3 /* Max number of queued events per inotify device instance */
+};
+
/* CTL_KERN names: */
enum
{
@@ -243,6 +252,7 @@ enum
NET_CORE_MOD_CONG=16,
NET_CORE_DEV_WEIGHT=17,
NET_CORE_SOMAXCONN=18,
+ NET_CORE_BUDGET=19,
};
/* /proc/sys/net/ethernet */
@@ -333,21 +343,14 @@ enum
NET_TCP_FRTO=92,
NET_TCP_LOW_LATENCY=93,
NET_IPV4_IPFRAG_SECRET_INTERVAL=94,
- NET_TCP_WESTWOOD=95,
NET_IPV4_IGMP_MAX_MSF=96,
NET_TCP_NO_METRICS_SAVE=97,
- NET_TCP_VEGAS=98,
- NET_TCP_VEGAS_ALPHA=99,
- NET_TCP_VEGAS_BETA=100,
- NET_TCP_VEGAS_GAMMA=101,
- NET_TCP_BIC=102,
- NET_TCP_BIC_FAST_CONVERGENCE=103,
- NET_TCP_BIC_LOW_WINDOW=104,
NET_TCP_DEFAULT_WIN_SCALE=105,
NET_TCP_MODERATE_RCVBUF=106,
NET_TCP_TSO_WIN_DIVISOR=107,
NET_TCP_BIC_BETA=108,
NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR=109,
+ NET_TCP_CONG_CONTROL=110,
};
enum {
@@ -647,6 +650,7 @@ enum {
NET_SCTP_ADDIP_ENABLE = 13,
NET_SCTP_PRSCTP_ENABLE = 14,
NET_SCTP_SNDBUF_POLICY = 15,
+ NET_SCTP_SACK_TIMEOUT = 16,
};
/* /proc/sys/net/bridge */
diff --git a/include/linux/tc_ematch/tc_em_meta.h b/include/linux/tc_ematch/tc_em_meta.h
index a6b2cc530af5..bcb762d93123 100644
--- a/include/linux/tc_ematch/tc_em_meta.h
+++ b/include/linux/tc_ematch/tc_em_meta.h
@@ -45,7 +45,7 @@ enum
TCF_META_ID_REALDEV,
TCF_META_ID_PRIORITY,
TCF_META_ID_PROTOCOL,
- TCF_META_ID_SECURITY,
+ TCF_META_ID_SECURITY, /* obsolete */
TCF_META_ID_PKTTYPE,
TCF_META_ID_PKTLEN,
TCF_META_ID_DATALEN,
diff --git a/include/linux/tc_ematch/tc_em_text.h b/include/linux/tc_ematch/tc_em_text.h
new file mode 100644
index 000000000000..7cd43e99c7f5
--- /dev/null
+++ b/include/linux/tc_ematch/tc_em_text.h
@@ -0,0 +1,19 @@
+#ifndef __LINUX_TC_EM_TEXT_H
+#define __LINUX_TC_EM_TEXT_H
+
+#include <linux/pkt_cls.h>
+
+#define TC_EM_TEXT_ALGOSIZ 16
+
+struct tcf_em_text
+{
+ char algo[TC_EM_TEXT_ALGOSIZ];
+ __u16 from_offset;
+ __u16 to_offset;
+ __u16 pattern_len;
+ __u8 from_layer:4;
+ __u8 to_layer:4;
+ __u8 pad;
+};
+
+#endif
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 97a7c9e03df5..e4fd82e42104 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -127,6 +127,7 @@ enum {
#define TCP_WINDOW_CLAMP 10 /* Bound advertised window */
#define TCP_INFO 11 /* Information about this connection. */
#define TCP_QUICKACK 12 /* Block/reenable quick acks */
+#define TCP_CONGESTION 13 /* Congestion control algorithm */
#define TCPI_OPT_TIMESTAMPS 1
#define TCPI_OPT_SACK 2
@@ -203,13 +204,6 @@ struct tcp_sack_block {
__u32 end_seq;
};
-enum tcp_congestion_algo {
- TCP_RENO=0,
- TCP_VEGAS,
- TCP_WESTWOOD,
- TCP_BIC,
-};
-
struct tcp_options_received {
/* PAWS/RTTM data */
long ts_recent_stamp;/* Time we stored ts_recent (for aging) */
@@ -292,7 +286,7 @@ struct tcp_sock {
__u32 max_window; /* Maximal window ever seen from peer */
__u32 pmtu_cookie; /* Last pmtu seen by socket */
__u32 mss_cache; /* Cached effective mss, not including SACKS */
- __u16 mss_cache_std; /* Like mss_cache, but without TSO */
+ __u16 xmit_size_goal; /* Goal for segmenting output packets */
__u16 ext_header_len; /* Network protocol overhead (IP/IPv6 options) */
__u8 ca_state; /* State of fast-retransmit machine */
__u8 retransmits; /* Number of unrecovered RTO timeouts. */
@@ -305,7 +299,7 @@ struct tcp_sock {
__u8 reordering; /* Packet reordering metric. */
__u8 frto_counter; /* Number of new acks after RTO */
- __u8 adv_cong; /* Using Vegas, Westwood, or BIC */
+ __u8 unused;
__u8 defer_accept; /* User waits for some data after accept() */
/* RTT measurement */
@@ -401,37 +395,10 @@ struct tcp_sock {
__u32 time;
} rcvq_space;
-/* TCP Westwood structure */
- struct {
- __u32 bw_ns_est; /* first bandwidth estimation..not too smoothed 8) */
- __u32 bw_est; /* bandwidth estimate */
- __u32 rtt_win_sx; /* here starts a new evaluation... */
- __u32 bk;
- __u32 snd_una; /* used for evaluating the number of acked bytes */
- __u32 cumul_ack;
- __u32 accounted;
- __u32 rtt;
- __u32 rtt_min; /* minimum observed RTT */
- } westwood;
-
-/* Vegas variables */
- struct {
- __u32 beg_snd_nxt; /* right edge during last RTT */
- __u32 beg_snd_una; /* left edge during last RTT */
- __u32 beg_snd_cwnd; /* saves the size of the cwnd */
- __u8 doing_vegas_now;/* if true, do vegas for this RTT */
- __u16 cntRTT; /* # of RTTs measured within last RTT */
- __u32 minRTT; /* min of RTTs measured within last RTT (in usec) */
- __u32 baseRTT; /* the min of all Vegas RTT measurements seen (in usec) */
- } vegas;
-
- /* BI TCP Parameters */
- struct {
- __u32 cnt; /* increase cwnd by 1 after this number of ACKs */
- __u32 last_max_cwnd; /* last maximium snd_cwnd */
- __u32 last_cwnd; /* the last snd_cwnd */
- __u32 last_stamp; /* time when updated last_cwnd */
- } bictcp;
+ /* Pluggable TCP congestion control hook */
+ struct tcp_congestion_ops *ca_ops;
+ u32 ca_priv[16];
+#define TCP_CA_PRIV_SIZE (16*sizeof(u32))
};
static inline struct tcp_sock *tcp_sk(const struct sock *sk)
@@ -439,6 +406,11 @@ static inline struct tcp_sock *tcp_sk(const struct sock *sk)
return (struct tcp_sock *)sk;
}
+static inline void *tcp_ca(const struct tcp_sock *tp)
+{
+ return (void *) tp->ca_priv;
+}
+
#endif
#endif /* _LINUX_TCP_H */
diff --git a/include/linux/tcp_diag.h b/include/linux/tcp_diag.h
index ceee962e1d15..7a5996743946 100644
--- a/include/linux/tcp_diag.h
+++ b/include/linux/tcp_diag.h
@@ -99,9 +99,10 @@ enum
TCPDIAG_MEMINFO,
TCPDIAG_INFO,
TCPDIAG_VEGASINFO,
+ TCPDIAG_CONG,
};
-#define TCPDIAG_MAX TCPDIAG_VEGASINFO
+#define TCPDIAG_MAX TCPDIAG_CONG
/* TCPDIAG_MEM */
@@ -123,5 +124,4 @@ struct tcpvegas_info {
__u32 tcpv_minrtt;
};
-
#endif /* _TCP_DIAG_H_ */
diff --git a/include/linux/textsearch.h b/include/linux/textsearch.h
new file mode 100644
index 000000000000..941f45ac117a
--- /dev/null
+++ b/include/linux/textsearch.h
@@ -0,0 +1,180 @@
+#ifndef __LINUX_TEXTSEARCH_H
+#define __LINUX_TEXTSEARCH_H
+
+#ifdef __KERNEL__
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+
+struct ts_config;
+
+/**
+ * TS_AUTOLOAD - Automatically load textsearch modules when needed
+ */
+#define TS_AUTOLOAD 1
+
+/**
+ * struct ts_state - search state
+ * @offset: offset for next match
+ * @cb: control buffer, for persistant variables of get_next_block()
+ */
+struct ts_state
+{
+ unsigned int offset;
+ char cb[40];
+};
+
+/**
+ * struct ts_ops - search module operations
+ * @name: name of search algorithm
+ * @init: initialization function to prepare a search
+ * @find: find the next occurrence of the pattern
+ * @destroy: destroy algorithm specific parts of a search configuration
+ * @get_pattern: return head of pattern
+ * @get_pattern_len: return length of pattern
+ * @owner: module reference to algorithm
+ */
+struct ts_ops
+{
+ const char *name;
+ struct ts_config * (*init)(const void *, unsigned int, int);
+ unsigned int (*find)(struct ts_config *,
+ struct ts_state *);
+ void (*destroy)(struct ts_config *);
+ void * (*get_pattern)(struct ts_config *);
+ unsigned int (*get_pattern_len)(struct ts_config *);
+ struct module *owner;
+ struct list_head list;
+};
+
+/**
+ * struct ts_config - search configuration
+ * @ops: operations of chosen algorithm
+ * @get_next_block: callback to fetch the next block to search in
+ * @finish: callback to finalize a search
+ */
+struct ts_config
+{
+ struct ts_ops *ops;
+
+ /**
+ * get_next_block - fetch next block of data
+ * @consumed: number of bytes consumed by the caller
+ * @dst: destination buffer
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Called repeatedly until 0 is returned. Must assign the
+ * head of the next block of data to &*dst and return the length
+ * of the block or 0 if at the end. consumed == 0 indicates
+ * a new search. May store/read persistant values in state->cb.
+ */
+ unsigned int (*get_next_block)(unsigned int consumed,
+ const u8 **dst,
+ struct ts_config *conf,
+ struct ts_state *state);
+
+ /**
+ * finish - finalize/clean a series of get_next_block() calls
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Called after the last use of get_next_block(), may be used
+ * to cleanup any leftovers.
+ */
+ void (*finish)(struct ts_config *conf,
+ struct ts_state *state);
+};
+
+/**
+ * textsearch_next - continue searching for a pattern
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Continues a search looking for more occurrences of the pattern.
+ * textsearch_find() must be called to find the first occurrence
+ * in order to reset the state.
+ *
+ * Returns the position of the next occurrence of the pattern or
+ * UINT_MAX if not match was found.
+ */
+static inline unsigned int textsearch_next(struct ts_config *conf,
+ struct ts_state *state)
+{
+ unsigned int ret = conf->ops->find(conf, state);
+
+ if (conf->finish)
+ conf->finish(conf, state);
+
+ return ret;
+}
+
+/**
+ * textsearch_find - start searching for a pattern
+ * @conf: search configuration
+ * @state: search state
+ *
+ * Returns the position of first occurrence of the pattern or
+ * UINT_MAX if no match was found.
+ */
+static inline unsigned int textsearch_find(struct ts_config *conf,
+ struct ts_state *state)
+{
+ state->offset = 0;
+ return textsearch_next(conf, state);
+}
+
+/**
+ * textsearch_get_pattern - return head of the pattern
+ * @conf: search configuration
+ */
+static inline void *textsearch_get_pattern(struct ts_config *conf)
+{
+ return conf->ops->get_pattern(conf);
+}
+
+/**
+ * textsearch_get_pattern_len - return length of the pattern
+ * @conf: search configuration
+ */
+static inline unsigned int textsearch_get_pattern_len(struct ts_config *conf)
+{
+ return conf->ops->get_pattern_len(conf);
+}
+
+extern int textsearch_register(struct ts_ops *);
+extern int textsearch_unregister(struct ts_ops *);
+extern struct ts_config *textsearch_prepare(const char *, const void *,
+ unsigned int, int, int);
+extern void textsearch_destroy(struct ts_config *conf);
+extern unsigned int textsearch_find_continuous(struct ts_config *,
+ struct ts_state *,
+ const void *, unsigned int);
+
+
+#define TS_PRIV_ALIGNTO 8
+#define TS_PRIV_ALIGN(len) (((len) + TS_PRIV_ALIGNTO-1) & ~(TS_PRIV_ALIGNTO-1))
+
+static inline struct ts_config *alloc_ts_config(size_t payload, int gfp_mask)
+{
+ struct ts_config *conf;
+
+ conf = kmalloc(TS_PRIV_ALIGN(sizeof(*conf)) + payload, gfp_mask);
+ if (conf == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ memset(conf, 0, TS_PRIV_ALIGN(sizeof(*conf)) + payload);
+ return conf;
+}
+
+static inline void *ts_config_priv(struct ts_config *conf)
+{
+ return ((u8 *) conf + TS_PRIV_ALIGN(sizeof(struct ts_config)));
+}
+
+#endif /* __KERNEL__ */
+
+#endif
diff --git a/include/linux/textsearch_fsm.h b/include/linux/textsearch_fsm.h
new file mode 100644
index 000000000000..fdfa078c66e5
--- /dev/null
+++ b/include/linux/textsearch_fsm.h
@@ -0,0 +1,48 @@
+#ifndef __LINUX_TEXTSEARCH_FSM_H
+#define __LINUX_TEXTSEARCH_FSM_H
+
+#include <linux/types.h>
+
+enum {
+ TS_FSM_SPECIFIC, /* specific character */
+ TS_FSM_WILDCARD, /* any character */
+ TS_FSM_DIGIT, /* isdigit() */
+ TS_FSM_XDIGIT, /* isxdigit() */
+ TS_FSM_PRINT, /* isprint() */
+ TS_FSM_ALPHA, /* isalpha() */
+ TS_FSM_ALNUM, /* isalnum() */
+ TS_FSM_ASCII, /* isascii() */
+ TS_FSM_CNTRL, /* iscntrl() */
+ TS_FSM_GRAPH, /* isgraph() */
+ TS_FSM_LOWER, /* islower() */
+ TS_FSM_UPPER, /* isupper() */
+ TS_FSM_PUNCT, /* ispunct() */
+ TS_FSM_SPACE, /* isspace() */
+ __TS_FSM_TYPE_MAX,
+};
+#define TS_FSM_TYPE_MAX (__TS_FSM_TYPE_MAX - 1)
+
+enum {
+ TS_FSM_SINGLE, /* 1 occurrence */
+ TS_FSM_PERHAPS, /* 1 or 0 occurrence */
+ TS_FSM_ANY, /* 0..n occurrences */
+ TS_FSM_MULTI, /* 1..n occurrences */
+ TS_FSM_HEAD_IGNORE, /* 0..n ignored occurrences at head */
+ __TS_FSM_RECUR_MAX,
+};
+#define TS_FSM_RECUR_MAX (__TS_FSM_RECUR_MAX - 1)
+
+/**
+ * struct ts_fsm_token - state machine token (state)
+ * @type: type of token
+ * @recur: number of recurrences
+ * @value: character value for TS_FSM_SPECIFIC
+ */
+struct ts_fsm_token
+{
+ __u16 type;
+ __u8 recur;
+ __u8 value;
+};
+
+#endif
diff --git a/include/linux/topology.h b/include/linux/topology.h
index d70e8972c67f..0320225e96da 100644
--- a/include/linux/topology.h
+++ b/include/linux/topology.h
@@ -89,6 +89,11 @@
.cache_hot_time = 0, \
.cache_nice_tries = 0, \
.per_cpu_gain = 25, \
+ .busy_idx = 0, \
+ .idle_idx = 0, \
+ .newidle_idx = 1, \
+ .wake_idx = 0, \
+ .forkexec_idx = 0, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_NEWIDLE \
| SD_BALANCE_EXEC \
@@ -115,12 +120,15 @@
.cache_hot_time = (5*1000000/2), \
.cache_nice_tries = 1, \
.per_cpu_gain = 100, \
+ .busy_idx = 2, \
+ .idle_idx = 1, \
+ .newidle_idx = 2, \
+ .wake_idx = 1, \
+ .forkexec_idx = 1, \
.flags = SD_LOAD_BALANCE \
| SD_BALANCE_NEWIDLE \
| SD_BALANCE_EXEC \
- | SD_WAKE_AFFINE \
- | SD_WAKE_IDLE \
- | SD_WAKE_BALANCE, \
+ | SD_WAKE_AFFINE, \
.last_balance = jiffies, \
.balance_interval = 1, \
.nr_balance_failed = 0, \
diff --git a/include/linux/usb.h b/include/linux/usb.h
index eb282b581546..724637792996 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -938,17 +938,17 @@ static inline void usb_fill_int_urb (struct urb *urb,
}
extern void usb_init_urb(struct urb *urb);
-extern struct urb *usb_alloc_urb(int iso_packets, int mem_flags);
+extern struct urb *usb_alloc_urb(int iso_packets, unsigned mem_flags);
extern void usb_free_urb(struct urb *urb);
#define usb_put_urb usb_free_urb
extern struct urb *usb_get_urb(struct urb *urb);
-extern int usb_submit_urb(struct urb *urb, int mem_flags);
+extern int usb_submit_urb(struct urb *urb, unsigned mem_flags);
extern int usb_unlink_urb(struct urb *urb);
extern void usb_kill_urb(struct urb *urb);
#define HAVE_USB_BUFFERS
void *usb_buffer_alloc (struct usb_device *dev, size_t size,
- int mem_flags, dma_addr_t *dma);
+ unsigned mem_flags, dma_addr_t *dma);
void usb_buffer_free (struct usb_device *dev, size_t size,
void *addr, dma_addr_t dma);
@@ -1055,7 +1055,7 @@ int usb_sg_init (
struct scatterlist *sg,
int nents,
size_t length,
- int mem_flags
+ unsigned mem_flags
);
void usb_sg_cancel (struct usb_sg_request *io);
void usb_sg_wait (struct usb_sg_request *io);
diff --git a/include/linux/usb_cdc.h b/include/linux/usb_cdc.h
index f22d6beecc73..ba617c372455 100644
--- a/include/linux/usb_cdc.h
+++ b/include/linux/usb_cdc.h
@@ -34,6 +34,7 @@
#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
#define USB_CDC_COUNTRY_TYPE 0x07
+#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
#define USB_CDC_WHCM_TYPE 0x11
#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
@@ -83,6 +84,18 @@ struct usb_cdc_union_desc {
/* ... and there could be other slave interfaces */
} __attribute__ ((packed));
+/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
+struct usb_cdc_network_terminal_desc {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDescriptorSubType;
+
+ __u8 bEntityId;
+ __u8 iName;
+ __u8 bChannelIndex;
+ __u8 bPhysicalInterface;
+} __attribute__ ((packed));
+
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
struct usb_cdc_ether_desc {
__u8 bLength;
diff --git a/include/linux/usb_ch9.h b/include/linux/usb_ch9.h
index f5fe94e09a03..ee21e6bf3867 100644
--- a/include/linux/usb_ch9.h
+++ b/include/linux/usb_ch9.h
@@ -6,17 +6,20 @@
*
* - the master/host side Linux-USB kernel driver API;
* - the "usbfs" user space API; and
- * - (eventually) a Linux "gadget" slave/device side driver API.
+ * - the Linux "gadget" slave/device/peripheral side driver API.
*
* USB 2.0 adds an additional "On The Go" (OTG) mode, which lets systems
* act either as a USB master/host or as a USB slave/device. That means
- * the master and slave side APIs will benefit from working well together.
+ * the master and slave side APIs benefit from working well together.
+ *
+ * There's also "Wireless USB", using low power short range radios for
+ * peripheral interconnection but otherwise building on the USB framework.
*/
#ifndef __LINUX_USB_CH9_H
#define __LINUX_USB_CH9_H
-#include <asm/types.h> /* __u8 etc */
+#include <linux/types.h> /* __u8 etc */
/*-------------------------------------------------------------------------*/
@@ -68,6 +71,18 @@
#define USB_REQ_SET_INTERFACE 0x0B
#define USB_REQ_SYNCH_FRAME 0x0C
+#define USB_REQ_SET_ENCRYPTION 0x0D /* Wireless USB */
+#define USB_REQ_GET_ENCRYPTION 0x0E
+#define USB_REQ_SET_HANDSHAKE 0x0F
+#define USB_REQ_GET_HANDSHAKE 0x10
+#define USB_REQ_SET_CONNECTION 0x11
+#define USB_REQ_SET_SECURITY_DATA 0x12
+#define USB_REQ_GET_SECURITY_DATA 0x13
+#define USB_REQ_SET_WUSB_DATA 0x14
+#define USB_REQ_LOOPBACK_DATA_WRITE 0x15
+#define USB_REQ_LOOPBACK_DATA_READ 0x16
+#define USB_REQ_SET_INTERFACE_DS 0x17
+
/*
* USB feature flags are written using USB_REQ_{CLEAR,SET}_FEATURE, and
* are read as a bit array returned by USB_REQ_GET_STATUS. (So there
@@ -75,10 +90,12 @@
*/
#define USB_DEVICE_SELF_POWERED 0 /* (read only) */
#define USB_DEVICE_REMOTE_WAKEUP 1 /* dev may initiate wakeup */
-#define USB_DEVICE_TEST_MODE 2 /* (high speed only) */
-#define USB_DEVICE_B_HNP_ENABLE 3 /* dev may initiate HNP */
-#define USB_DEVICE_A_HNP_SUPPORT 4 /* RH port supports HNP */
-#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* other RH port does */
+#define USB_DEVICE_TEST_MODE 2 /* (wired high speed only) */
+#define USB_DEVICE_BATTERY 2 /* (wireless) */
+#define USB_DEVICE_B_HNP_ENABLE 3 /* (otg) dev may initiate HNP */
+#define USB_DEVICE_WUSB_DEVICE 3 /* (wireless)*/
+#define USB_DEVICE_A_HNP_SUPPORT 4 /* (otg) RH port supports HNP */
+#define USB_DEVICE_A_ALT_HNP_SUPPORT 5 /* (otg) other RH port does */
#define USB_DEVICE_DEBUG_MODE 6 /* (special devices only) */
#define USB_ENDPOINT_HALT 0 /* IN/OUT will STALL */
@@ -135,6 +152,13 @@ struct usb_ctrlrequest {
#define USB_DT_OTG 0x09
#define USB_DT_DEBUG 0x0a
#define USB_DT_INTERFACE_ASSOCIATION 0x0b
+/* these are from the Wireless USB spec */
+#define USB_DT_SECURITY 0x0c
+#define USB_DT_KEY 0x0d
+#define USB_DT_ENCRYPTION_TYPE 0x0e
+#define USB_DT_BOS 0x0f
+#define USB_DT_DEVICE_CAPABILITY 0x10
+#define USB_DT_WIRELESS_ENDPOINT_COMP 0x11
/* conventional codes for class-specific descriptors */
#define USB_DT_CS_DEVICE 0x21
@@ -192,6 +216,7 @@ struct usb_device_descriptor {
#define USB_CLASS_CSCID 0x0b /* chip+ smart card */
#define USB_CLASS_CONTENT_SEC 0x0d /* content security */
#define USB_CLASS_VIDEO 0x0e
+#define USB_CLASS_WIRELESS_CONTROLLER 0xe0
#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
@@ -223,6 +248,7 @@ struct usb_config_descriptor {
#define USB_CONFIG_ATT_ONE (1 << 7) /* must be set */
#define USB_CONFIG_ATT_SELFPOWER (1 << 6) /* self powered */
#define USB_CONFIG_ATT_WAKEUP (1 << 5) /* can wakeup */
+#define USB_CONFIG_ATT_BATTERY (1 << 4) /* battery powered */
/*-------------------------------------------------------------------------*/
@@ -268,8 +294,8 @@ struct usb_endpoint_descriptor {
__le16 wMaxPacketSize;
__u8 bInterval;
- // NOTE: these two are _only_ in audio endpoints.
- // use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof.
+ /* NOTE: these two are _only_ in audio endpoints. */
+ /* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
@@ -289,6 +315,7 @@ struct usb_endpoint_descriptor {
#define USB_ENDPOINT_XFER_ISOC 1
#define USB_ENDPOINT_XFER_BULK 2
#define USB_ENDPOINT_XFER_INT 3
+#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
/*-------------------------------------------------------------------------*/
@@ -352,12 +379,154 @@ struct usb_interface_assoc_descriptor {
/*-------------------------------------------------------------------------*/
+/* USB_DT_SECURITY: group of wireless security descriptors, including
+ * encryption types available for setting up a CC/association.
+ */
+struct usb_security_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+
+ __le16 wTotalLength;
+ __u8 bNumEncryptionTypes;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_KEY: used with {GET,SET}_SECURITY_DATA; only public keys
+ * may be retrieved.
+ */
+struct usb_key_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+
+ __u8 tTKID[3];
+ __u8 bReserved;
+ __u8 bKeyData[0];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_ENCRYPTION_TYPE: bundled in DT_SECURITY groups */
+struct usb_encryption_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+
+ __u8 bEncryptionType;
+#define USB_ENC_TYPE_UNSECURE 0
+#define USB_ENC_TYPE_WIRED 1 /* non-wireless mode */
+#define USB_ENC_TYPE_CCM_1 2 /* aes128/cbc session */
+#define USB_ENC_TYPE_RSA_1 3 /* rsa3072/sha1 auth */
+ __u8 bEncryptionValue; /* use in SET_ENCRYPTION */
+ __u8 bAuthKeyIndex;
+};
+
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_BOS: group of wireless capabilities */
+struct usb_bos_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+
+ __le16 wTotalLength;
+ __u8 bNumDeviceCaps;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_DEVICE_CAPABILITY: grouped with BOS */
+struct usb_dev_cap_header {
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+};
+
+#define USB_CAP_TYPE_WIRELESS_USB 1
+
+struct usb_wireless_cap_descriptor { /* Ultra Wide Band */
+ __u8 bLength;
+ __u8 bDescriptorType;
+ __u8 bDevCapabilityType;
+
+ __u8 bmAttributes;
+#define USB_WIRELESS_P2P_DRD (1 << 1)
+#define USB_WIRELESS_BEACON_MASK (3 << 2)
+#define USB_WIRELESS_BEACON_SELF (1 << 2)
+#define USB_WIRELESS_BEACON_DIRECTED (2 << 2)
+#define USB_WIRELESS_BEACON_NONE (3 << 2)
+ __le16 wPHYRates; /* bit rates, Mbps */
+#define USB_WIRELESS_PHY_53 (1 << 0) /* always set */
+#define USB_WIRELESS_PHY_80 (1 << 1)
+#define USB_WIRELESS_PHY_107 (1 << 2) /* always set */
+#define USB_WIRELESS_PHY_160 (1 << 3)
+#define USB_WIRELESS_PHY_200 (1 << 4) /* always set */
+#define USB_WIRELESS_PHY_320 (1 << 5)
+#define USB_WIRELESS_PHY_400 (1 << 6)
+#define USB_WIRELESS_PHY_480 (1 << 7)
+ __u8 bmTFITXPowerInfo; /* TFI power levels */
+ __u8 bmFFITXPowerInfo; /* FFI power levels */
+ __le16 bmBandGroup;
+ __u8 bReserved;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_DT_WIRELESS_ENDPOINT_COMP: companion descriptor associated with
+ * each endpoint descriptor for a wireless device
+ */
+struct usb_wireless_ep_comp_descriptor {
+ __u8 bLength;
+ __u8 bDescriptorType;
+
+ __u8 bMaxBurst;
+ __u8 bMaxSequence;
+ __le16 wMaxStreamDelay;
+ __le16 wOverTheAirPacketSize;
+ __u8 bOverTheAirInterval;
+ __u8 bmCompAttributes;
+#define USB_ENDPOINT_SWITCH_MASK 0x03 /* in bmCompAttributes */
+#define USB_ENDPOINT_SWITCH_NO 0
+#define USB_ENDPOINT_SWITCH_SWITCH 1
+#define USB_ENDPOINT_SWITCH_SCALE 2
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_HANDSHAKE is a four-way handshake used between a wireless
+ * host and a device for connection set up, mutual authentication, and
+ * exchanging short lived session keys. The handshake depends on a CC.
+ */
+struct usb_handshake {
+ __u8 bMessageNumber;
+ __u8 bStatus;
+ __u8 tTKID[3];
+ __u8 bReserved;
+ __u8 CDID[16];
+ __u8 nonce[16];
+ __u8 MIC[8];
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* USB_REQ_SET_CONNECTION modifies or revokes a connection context (CC).
+ * A CC may also be set up using non-wireless secure channels (including
+ * wired USB!), and some devices may support CCs with multiple hosts.
+ */
+struct usb_connection_context {
+ __u8 CHID[16]; /* persistent host id */
+ __u8 CDID[16]; /* device id (unique w/in host context) */
+ __u8 CK[16]; /* connection key */
+};
+
+/*-------------------------------------------------------------------------*/
+
/* USB 2.0 defines three speeds, here's how Linux identifies them */
enum usb_device_speed {
USB_SPEED_UNKNOWN = 0, /* enumerating */
USB_SPEED_LOW, USB_SPEED_FULL, /* usb 1.1 */
- USB_SPEED_HIGH /* usb 2.0 */
+ USB_SPEED_HIGH, /* usb 2.0 */
+ USB_SPEED_VARIABLE, /* wireless (usb 2.5) */
};
enum usb_device_state {
diff --git a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
index 9bba9997947b..71e608607324 100644
--- a/include/linux/usb_gadget.h
+++ b/include/linux/usb_gadget.h
@@ -107,18 +107,18 @@ struct usb_ep_ops {
int (*disable) (struct usb_ep *ep);
struct usb_request *(*alloc_request) (struct usb_ep *ep,
- int gfp_flags);
+ unsigned gfp_flags);
void (*free_request) (struct usb_ep *ep, struct usb_request *req);
void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,
- dma_addr_t *dma, int gfp_flags);
+ dma_addr_t *dma, unsigned gfp_flags);
void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
unsigned bytes);
// NOTE: on 2.6, drivers may also use dma_map() and
// dma_sync_single_*() to directly manage dma overhead.
int (*queue) (struct usb_ep *ep, struct usb_request *req,
- int gfp_flags);
+ unsigned gfp_flags);
int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
int (*set_halt) (struct usb_ep *ep, int value);
@@ -214,7 +214,7 @@ usb_ep_disable (struct usb_ep *ep)
* Returns the request, or null if one could not be allocated.
*/
static inline struct usb_request *
-usb_ep_alloc_request (struct usb_ep *ep, int gfp_flags)
+usb_ep_alloc_request (struct usb_ep *ep, unsigned gfp_flags)
{
return ep->ops->alloc_request (ep, gfp_flags);
}
@@ -254,7 +254,7 @@ usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
*/
static inline void *
usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma,
- int gfp_flags)
+ unsigned gfp_flags)
{
return ep->ops->alloc_buffer (ep, len, dma, gfp_flags);
}
@@ -330,7 +330,7 @@ usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len)
* reported when the usb peripheral is disconnected.
*/
static inline int
-usb_ep_queue (struct usb_ep *ep, struct usb_request *req, int gfp_flags)
+usb_ep_queue (struct usb_ep *ep, struct usb_request *req, unsigned gfp_flags)
{
return ep->ops->queue (ep, req, gfp_flags);
}
@@ -711,7 +711,7 @@ usb_gadget_disconnect (struct usb_gadget *gadget)
* the hardware level driver. Most calls must be handled by
* the gadget driver, including descriptor and configuration
* management. The 16 bit members of the setup data are in
- * cpu order. Called in_interrupt; this may not sleep. Driver
+ * USB byte order. Called in_interrupt; this may not sleep. Driver
* queues a response to ep0, or returns negative to stall.
* @disconnect: Invoked after all transfers have been stopped,
* when the host is disconnected. May be called in_interrupt; this
diff --git a/include/linux/usb_isp116x.h b/include/linux/usb_isp116x.h
new file mode 100644
index 000000000000..5f5a9d9bd6c2
--- /dev/null
+++ b/include/linux/usb_isp116x.h
@@ -0,0 +1,47 @@
+
+/*
+ * Board initialization code should put one of these into dev->platform_data
+ * and place the isp116x onto platform_bus.
+ */
+
+struct isp116x_platform_data {
+ /* Enable internal resistors on downstream ports */
+ unsigned sel15Kres:1;
+ /* Chip's internal clock won't be stopped in suspended state.
+ Setting/unsetting this bit takes effect only if
+ 'remote_wakeup_enable' below is not set. */
+ unsigned clknotstop:1;
+ /* On-chip overcurrent protection */
+ unsigned oc_enable:1;
+ /* INT output polarity */
+ unsigned int_act_high:1;
+ /* INT edge or level triggered */
+ unsigned int_edge_triggered:1;
+ /* WAKEUP pin connected - NOT SUPPORTED */
+ /* unsigned remote_wakeup_connected:1; */
+ /* Wakeup by devices on usb bus enabled */
+ unsigned remote_wakeup_enable:1;
+ /* Switch or not to switch (keep always powered) */
+ unsigned no_power_switching:1;
+ /* Ganged port power switching (0) or individual port
+ power switching (1) */
+ unsigned power_switching_mode:1;
+ /* Given port_power, msec/2 after power on till power good */
+ u8 potpg;
+ /* Hardware reset set/clear. If implemented, this function must:
+ if set == 0, deassert chip's HW reset pin
+ otherwise, assert chip's HW reset pin */
+ void (*reset) (struct device * dev, int set);
+ /* Hardware clock start/stop. If implemented, this function must:
+ if start == 0, stop the external clock
+ otherwise, start the external clock
+ */
+ void (*clock) (struct device * dev, int start);
+ /* Inter-io delay (ns). The chip is picky about access timings; it
+ expects at least:
+ 150ns delay between consecutive accesses to DATA_REG,
+ 300ns delay between access to ADDR_REG and DATA_REG
+ OE, WE MUST NOT be changed during these intervals
+ */
+ void (*delay) (struct device * dev, int delay);
+};
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 4e0edce53760..acbfc525576d 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -221,6 +221,8 @@ struct v4l2_pix_format
/* Vendor-specific formats */
#define V4L2_PIX_FMT_WNVA v4l2_fourcc('W','N','V','A') /* Winnov hw compress */
#define V4L2_PIX_FMT_SN9C10X v4l2_fourcc('S','9','1','0') /* SN9C10x compression */
+#define V4L2_PIX_FMT_PWC1 v4l2_fourcc('P','W','C','1') /* pwc older webcam */
+#define V4L2_PIX_FMT_PWC2 v4l2_fourcc('P','W','C','2') /* pwc newer webcam */
/*
* F O R M A T E N U M E R A T I O N
diff --git a/include/linux/wanrouter.h b/include/linux/wanrouter.h
index 3e89f0f15f49..1b6b76a4eb54 100644
--- a/include/linux/wanrouter.h
+++ b/include/linux/wanrouter.h
@@ -516,8 +516,7 @@ struct wan_device {
/* Public functions available for device drivers */
extern int register_wan_device(struct wan_device *wandev);
extern int unregister_wan_device(char *name);
-unsigned short wanrouter_type_trans(struct sk_buff *skb,
- struct net_device *dev);
+__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev);
int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
unsigned short type);
diff --git a/include/linux/writeback.h b/include/linux/writeback.h
index 1262cb43c3ab..542dbaee6512 100644
--- a/include/linux/writeback.h
+++ b/include/linux/writeback.h
@@ -14,11 +14,13 @@ extern struct list_head inode_unused;
* Yes, writeback.h requires sched.h
* No, sched.h is not included from here.
*/
-static inline int current_is_pdflush(void)
+static inline int task_is_pdflush(struct task_struct *task)
{
- return current->flags & PF_FLUSHER;
+ return task->flags & PF_FLUSHER;
}
+#define current_is_pdflush() task_is_pdflush(current)
+
/*
* fs/fs-writeback.c
*/
@@ -83,7 +85,7 @@ static inline void wait_on_inode(struct inode *inode)
/*
* mm/page-writeback.c
*/
-int wakeup_bdflush(long nr_pages);
+int wakeup_pdflush(long nr_pages);
void laptop_io_completion(void);
void laptop_sync_completion(void);
void throttle_vm_writeout(void);
diff --git a/include/linux/xattr_acl.h b/include/linux/xattr_acl.h
deleted file mode 100644
index 7a1f9b93a45f..000000000000
--- a/include/linux/xattr_acl.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- File: linux/xattr_acl.h
-
- (extended attribute representation of access control lists)
-
- (C) 2000 Andreas Gruenbacher, <a.gruenbacher@computer.org>
-*/
-
-#ifndef _LINUX_XATTR_ACL_H
-#define _LINUX_XATTR_ACL_H
-
-#include <linux/posix_acl.h>
-
-#define XATTR_NAME_ACL_ACCESS "system.posix_acl_access"
-#define XATTR_NAME_ACL_DEFAULT "system.posix_acl_default"
-
-#define XATTR_ACL_VERSION 0x0002
-
-typedef struct {
- __u16 e_tag;
- __u16 e_perm;
- __u32 e_id;
-} xattr_acl_entry;
-
-typedef struct {
- __u32 a_version;
- xattr_acl_entry a_entries[0];
-} xattr_acl_header;
-
-static inline size_t xattr_acl_size(int count)
-{
- return sizeof(xattr_acl_header) + count * sizeof(xattr_acl_entry);
-}
-
-static inline int xattr_acl_count(size_t size)
-{
- if (size < sizeof(xattr_acl_header))
- return -1;
- size -= sizeof(xattr_acl_header);
- if (size % sizeof(xattr_acl_entry))
- return -1;
- return size / sizeof(xattr_acl_entry);
-}
-
-struct posix_acl * posix_acl_from_xattr(const void *value, size_t size);
-int posix_acl_to_xattr(const struct posix_acl *acl, void *buffer, size_t size);
-
-
-
-#endif /* _LINUX_XATTR_ACL_H */
diff --git a/include/media/audiochip.h b/include/media/audiochip.h
index d3e9e30608dc..cd831168fdc1 100644
--- a/include/media/audiochip.h
+++ b/include/media/audiochip.h
@@ -1,3 +1,7 @@
+/*
+ * $Id: audiochip.h,v 1.5 2005/06/16 22:59:16 hhackmann Exp $
+ */
+
#ifndef AUDIOCHIP_H
#define AUDIOCHIP_H
@@ -31,5 +35,4 @@
/* misc stuff to pass around config info to i2c chips */
#define AUDC_CONFIG_PINNACLE _IOW('m',32,int)
-
#endif /* AUDIOCHIP_H */
diff --git a/include/media/id.h b/include/media/id.h
index 1b0320dc8f73..a39a6423914b 100644
--- a/include/media/id.h
+++ b/include/media/id.h
@@ -1,3 +1,7 @@
+/*
+ * $Id: id.h,v 1.4 2005/06/12 04:19:19 mchehab Exp $
+ */
+
/* FIXME: this temporarely, until these are included in linux/i2c-id.h */
/* drivers */
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index 62c963a52d86..698670547f16 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -1,5 +1,5 @@
/*
- * $Id: ir-common.h,v 1.8 2005/02/22 12:28:40 kraxel Exp $
+ * $Id: ir-common.h,v 1.9 2005/05/15 19:01:26 mchehab Exp $
*
* some common structs and functions to handle infrared remotes via
* input layer ...
@@ -50,6 +50,7 @@ extern IR_KEYTAB_TYPE ir_codes_rc5_tv[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_winfast[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_empty[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_hauppauge_new[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
void ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
int ir_type, IR_KEYTAB_TYPE *ir_codes);
diff --git a/include/media/saa6752hs.h b/include/media/saa6752hs.h
index 791bad2b86e9..3b8686ead80d 100644
--- a/include/media/saa6752hs.h
+++ b/include/media/saa6752hs.h
@@ -18,55 +18,6 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#if 0 /* ndef _SAA6752HS_H */
-#define _SAA6752HS_H
-
-enum mpeg_video_bitrate_mode {
- MPEG_VIDEO_BITRATE_MODE_VBR = 0, /* Variable bitrate */
- MPEG_VIDEO_BITRATE_MODE_CBR = 1, /* Constant bitrate */
-
- MPEG_VIDEO_BITRATE_MODE_MAX
-};
-
-enum mpeg_audio_bitrate {
- MPEG_AUDIO_BITRATE_256 = 0, /* 256 kBit/sec */
- MPEG_AUDIO_BITRATE_384 = 1, /* 384 kBit/sec */
-
- MPEG_AUDIO_BITRATE_MAX
-};
-
-enum mpeg_video_format {
- MPEG_VIDEO_FORMAT_D1 = 0,
- MPEG_VIDEO_FORMAT_2_3_D1 = 1,
- MPEG_VIDEO_FORMAT_1_2_D1 = 2,
- MPEG_VIDEO_FORMAT_SIF = 3,
-
- MPEG_VIDEO_FORMAT_MAX
-};
-
-#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000
-#define MPEG_VIDEO_MAX_BITRATE_MAX 27000
-#define MPEG_TOTAL_BITRATE_MAX 27000
-#define MPEG_PID_MAX ((1 << 14) - 1)
-
-struct mpeg_params {
- enum mpeg_video_bitrate_mode video_bitrate_mode;
- unsigned int video_target_bitrate;
- unsigned int video_max_bitrate; // only used for VBR
- enum mpeg_audio_bitrate audio_bitrate;
- unsigned int total_bitrate;
-
- unsigned int pmt_pid;
- unsigned int video_pid;
- unsigned int audio_pid;
- unsigned int pcr_pid;
-
- enum mpeg_video_format video_format;
-};
-
-#define MPEG_SETPARAMS _IOW('6',100,struct mpeg_params)
-
-#endif // _SAA6752HS_H
/*
* Local variables:
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 156a9c51ffec..d8c0a5563289 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -1,5 +1,6 @@
-/*
+/* $Id: tuner.h,v 1.42 2005/07/06 09:42:19 mchehab Exp $
+ *
tuner.h - definition for different tuners
Copyright (C) 1997 Markus Schroeder (schroedm@uni-duesseldorf.de)
@@ -23,7 +24,9 @@
#ifndef _TUNER_H
#define _TUNER_H
-#include "id.h"
+#include <linux/videodev2.h>
+
+#define ADDR_UNSET (255)
#define TUNER_TEMIC_PAL 0 /* 4002 FH5 (3X 7756, 9483) */
#define TUNER_PHILIPS_PAL_I 1
@@ -86,7 +89,7 @@
#define TUNER_LG_NTSC_TAPE 47
#define TUNER_TNF_8831BGFF 48
-#define TUNER_MICROTUNE_4042FI5 49 /* FusionHDTV 3 Gold - 4042 FI5 (3X 8147) */
+#define TUNER_MICROTUNE_4042FI5 49 /* DViCO FusionHDTV 3 Gold-Q - 4042 FI5 (3X 8147) */
#define TUNER_TCL_2002N 50
#define TUNER_PHILIPS_FM1256_IH3 51
@@ -96,7 +99,15 @@
#define TUNER_LG_PAL_TAPE 55 /* Hauppauge PVR-150 PAL */
#define TUNER_PHILIPS_FQ1216AME_MK4 56 /* Hauppauge PVR-150 PAL */
-#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */
+#define TUNER_PHILIPS_FQ1236A_MK4 57 /* Hauppauge PVR-500MCE NTSC */
+
+#define TUNER_YMEC_TVF_8531MF 58
+#define TUNER_YMEC_TVF_5533MF 59 /* Pixelview Pro Ultra NTSC */
+#define TUNER_THOMSON_DTT7611 60 /* DViCO FusionHDTV 3 Gold-T */
+#define TUNER_TENA_9533_DI 61
+
+#define TUNER_TEA5767 62 /* Only FM Radio Tuner */
+#define TUNER_PHILIPS_FMD1216ME_MK3 63
#define NOTUNER 0
#define PAL 1 /* PAL_BG */
@@ -104,6 +115,7 @@
#define NTSC 3
#define SECAM 4
#define ATSC 5
+#define RADIO 6
#define NoTuner 0
#define Philips 1
@@ -119,10 +131,9 @@
#define TCL 11
#define THOMSON 12
-#define TUNER_SET_TYPE _IOW('t',1,int) /* set tuner type */
-#define TUNER_SET_TVFREQ _IOW('t',2,int) /* set tv freq */
+#define TUNER_SET_TYPE_ADDR _IOW('T',3,int)
+#define TDA9887_SET_CONFIG _IOW('t',5,int)
-#define TDA9887_SET_CONFIG _IOW('t',5,int)
/* tv card specific */
# define TDA9887_PRESENT (1<<0)
# define TDA9887_PORT1_INACTIVE (1<<1)
@@ -143,19 +154,34 @@
#define I2C_ADDR_TDA8290 0x4b
#define I2C_ADDR_TDA8275 0x61
+enum tuner_mode {
+ T_UNINITIALIZED = 0,
+ T_RADIO = 1 << V4L2_TUNER_RADIO,
+ T_ANALOG_TV = 1 << V4L2_TUNER_ANALOG_TV,
+ T_DIGITAL_TV = 1 << V4L2_TUNER_DIGITAL_TV,
+ T_STANDBY = 1 << 31
+};
+
+struct tuner_setup {
+ unsigned short addr;
+ unsigned int type;
+ unsigned int mode_mask;
+};
+
struct tuner {
/* device */
struct i2c_client i2c;
- /* state + config */
- unsigned int initialized;
unsigned int type; /* chip type */
+
+ unsigned int mode;
+ unsigned int mode_mask; /* Combination of allowable modes */
+
unsigned int freq; /* keep track of the current settings */
+ unsigned int audmode;
v4l2_std_id std;
- int using_v4l2;
- enum v4l2_tuner_type mode;
- unsigned int input;
+ int using_v4l2;
/* used by MT2032 */
unsigned int xogc;
@@ -177,7 +203,9 @@ extern unsigned const int tuner_count;
extern int microtune_init(struct i2c_client *c);
extern int tda8290_init(struct i2c_client *c);
+extern int tea5767_tuner_init(struct i2c_client *c);
extern int default_tuner_init(struct i2c_client *c);
+extern int tea5767_autodetection(struct i2c_client *c);
#define tuner_warn(fmt, arg...) \
dev_printk(KERN_WARNING , &t->i2c.dev , fmt , ## arg)
diff --git a/include/media/tveeprom.h b/include/media/tveeprom.h
index 627603e561a6..5c4fe30e8d1d 100644
--- a/include/media/tveeprom.h
+++ b/include/media/tveeprom.h
@@ -1,3 +1,7 @@
+/*
+ * $Id: tveeprom.h,v 1.2 2005/06/12 04:19:19 mchehab Exp $
+ */
+
struct tveeprom {
u32 has_radio;
diff --git a/include/mtd/mtd-abi.h b/include/mtd/mtd-abi.h
index a76ab898f445..428d9122940b 100644
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -1,5 +1,5 @@
/*
- * $Id: mtd-abi.h,v 1.7 2004/11/23 15:37:32 gleixner Exp $
+ * $Id: mtd-abi.h,v 1.11 2005/05/19 16:08:58 gleixner Exp $
*
* Portions of MTD ABI definition which are shared by kernel and user space
*/
@@ -29,6 +29,7 @@ struct mtd_oob_buf {
#define MTD_NORFLASH 3
#define MTD_NANDFLASH 4
#define MTD_PEROM 5
+#define MTD_DATAFLASH 6
#define MTD_OTHER 14
#define MTD_UNKNOWN 15
@@ -60,6 +61,12 @@ struct mtd_oob_buf {
#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
+#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
+
+/* OTP mode selection */
+#define MTD_OTP_OFF 0
+#define MTD_OTP_FACTORY 1
+#define MTD_OTP_USER 2
struct mtd_info_user {
uint8_t type;
@@ -80,6 +87,12 @@ struct region_info_user {
uint32_t regionindex;
};
+struct otp_info {
+ uint32_t start;
+ uint32_t length;
+ uint32_t locked;
+};
+
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
#define MEMERASE _IOW('M', 2, struct erase_info_user)
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
@@ -92,6 +105,10 @@ struct region_info_user {
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
#define MEMGETBADBLOCK _IOW('M', 11, loff_t)
#define MEMSETBADBLOCK _IOW('M', 12, loff_t)
+#define OTPSELECT _IOR('M', 13, int)
+#define OTPGETREGIONCOUNT _IOW('M', 14, int)
+#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
+#define OTPLOCK _IOR('M', 16, struct otp_info)
struct nand_oobinfo {
uint32_t useecc;
diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h
new file mode 100644
index 000000000000..db09580ad14b
--- /dev/null
+++ b/include/net/ieee80211.h
@@ -0,0 +1,856 @@
+/*
+ * Merged with mainline ieee80211.h in Aug 2004. Original ieee802_11
+ * remains copyright by the original authors
+ *
+ * Portions of the merged code are based on Host AP (software wireless
+ * LAN access point) driver for Intersil Prism2/2.5/3.
+ *
+ * Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
+ * <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * Adaption to a generic IEEE 802.11 stack by James Ketrenos
+ * <jketreno@linux.intel.com>
+ * Copyright (c) 2004, Intel Corporation
+ *
+ * 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. See README and COPYING for
+ * more details.
+ */
+#ifndef IEEE80211_H
+#define IEEE80211_H
+
+#include <linux/if_ether.h> /* ETH_ALEN */
+#include <linux/kernel.h> /* ARRAY_SIZE */
+
+#if WIRELESS_EXT < 17
+#define IW_QUAL_QUAL_INVALID 0x10
+#define IW_QUAL_LEVEL_INVALID 0x20
+#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_QUAL_UPDATED 0x1
+#define IW_QUAL_LEVEL_UPDATED 0x2
+#define IW_QUAL_NOISE_UPDATED 0x4
+#endif
+
+#define IEEE80211_DATA_LEN 2304
+/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
+ 6.2.1.1.2.
+
+ The figure in section 7.1.2 suggests a body size of up to 2312
+ bytes is allowed, which is a bit confusing, I suspect this
+ represents the 2304 bytes of real data, plus a possible 8 bytes of
+ WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
+
+
+#define IEEE80211_HLEN 30
+#define IEEE80211_FRAME_LEN (IEEE80211_DATA_LEN + IEEE80211_HLEN)
+
+struct ieee80211_hdr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+ u8 addr4[ETH_ALEN];
+} __attribute__ ((packed));
+
+struct ieee80211_hdr_3addr {
+ u16 frame_ctl;
+ u16 duration_id;
+ u8 addr1[ETH_ALEN];
+ u8 addr2[ETH_ALEN];
+ u8 addr3[ETH_ALEN];
+ u16 seq_ctl;
+} __attribute__ ((packed));
+
+enum eap_type {
+ EAP_PACKET = 0,
+ EAPOL_START,
+ EAPOL_LOGOFF,
+ EAPOL_KEY,
+ EAPOL_ENCAP_ASF_ALERT
+};
+
+static const char *eap_types[] = {
+ [EAP_PACKET] = "EAP-Packet",
+ [EAPOL_START] = "EAPOL-Start",
+ [EAPOL_LOGOFF] = "EAPOL-Logoff",
+ [EAPOL_KEY] = "EAPOL-Key",
+ [EAPOL_ENCAP_ASF_ALERT] = "EAPOL-Encap-ASF-Alert"
+};
+
+static inline const char *eap_get_type(int type)
+{
+ return (type >= ARRAY_SIZE(eap_types)) ? "Unknown" : eap_types[type];
+}
+
+struct eapol {
+ u8 snap[6];
+ u16 ethertype;
+ u8 version;
+ u8 type;
+ u16 length;
+} __attribute__ ((packed));
+
+#define IEEE80211_1ADDR_LEN 10
+#define IEEE80211_2ADDR_LEN 16
+#define IEEE80211_3ADDR_LEN 24
+#define IEEE80211_4ADDR_LEN 30
+#define IEEE80211_FCS_LEN 4
+
+#define MIN_FRAG_THRESHOLD 256U
+#define MAX_FRAG_THRESHOLD 2346U
+
+/* Frame control field constants */
+#define IEEE80211_FCTL_VERS 0x0002
+#define IEEE80211_FCTL_FTYPE 0x000c
+#define IEEE80211_FCTL_STYPE 0x00f0
+#define IEEE80211_FCTL_TODS 0x0100
+#define IEEE80211_FCTL_FROMDS 0x0200
+#define IEEE80211_FCTL_MOREFRAGS 0x0400
+#define IEEE80211_FCTL_RETRY 0x0800
+#define IEEE80211_FCTL_PM 0x1000
+#define IEEE80211_FCTL_MOREDATA 0x2000
+#define IEEE80211_FCTL_WEP 0x4000
+#define IEEE80211_FCTL_ORDER 0x8000
+
+#define IEEE80211_FTYPE_MGMT 0x0000
+#define IEEE80211_FTYPE_CTL 0x0004
+#define IEEE80211_FTYPE_DATA 0x0008
+
+/* management */
+#define IEEE80211_STYPE_ASSOC_REQ 0x0000
+#define IEEE80211_STYPE_ASSOC_RESP 0x0010
+#define IEEE80211_STYPE_REASSOC_REQ 0x0020
+#define IEEE80211_STYPE_REASSOC_RESP 0x0030
+#define IEEE80211_STYPE_PROBE_REQ 0x0040
+#define IEEE80211_STYPE_PROBE_RESP 0x0050
+#define IEEE80211_STYPE_BEACON 0x0080
+#define IEEE80211_STYPE_ATIM 0x0090
+#define IEEE80211_STYPE_DISASSOC 0x00A0
+#define IEEE80211_STYPE_AUTH 0x00B0
+#define IEEE80211_STYPE_DEAUTH 0x00C0
+
+/* control */
+#define IEEE80211_STYPE_PSPOLL 0x00A0
+#define IEEE80211_STYPE_RTS 0x00B0
+#define IEEE80211_STYPE_CTS 0x00C0
+#define IEEE80211_STYPE_ACK 0x00D0
+#define IEEE80211_STYPE_CFEND 0x00E0
+#define IEEE80211_STYPE_CFENDACK 0x00F0
+
+/* data */
+#define IEEE80211_STYPE_DATA 0x0000
+#define IEEE80211_STYPE_DATA_CFACK 0x0010
+#define IEEE80211_STYPE_DATA_CFPOLL 0x0020
+#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
+#define IEEE80211_STYPE_NULLFUNC 0x0040
+#define IEEE80211_STYPE_CFACK 0x0050
+#define IEEE80211_STYPE_CFPOLL 0x0060
+#define IEEE80211_STYPE_CFACKPOLL 0x0070
+
+#define IEEE80211_SCTL_FRAG 0x000F
+#define IEEE80211_SCTL_SEQ 0xFFF0
+
+
+/* debug macros */
+
+#ifdef CONFIG_IEEE80211_DEBUG
+extern u32 ieee80211_debug_level;
+#define IEEE80211_DEBUG(level, fmt, args...) \
+do { if (ieee80211_debug_level & (level)) \
+ printk(KERN_DEBUG "ieee80211: %c %s " fmt, \
+ in_interrupt() ? 'I' : 'U', __FUNCTION__ , ## args); } while (0)
+#else
+#define IEEE80211_DEBUG(level, fmt, args...) do {} while (0)
+#endif /* CONFIG_IEEE80211_DEBUG */
+
+/*
+ * To use the debug system;
+ *
+ * If you are defining a new debug classification, simply add it to the #define
+ * list here in the form of:
+ *
+ * #define IEEE80211_DL_xxxx VALUE
+ *
+ * shifting value to the left one bit from the previous entry. xxxx should be
+ * the name of the classification (for example, WEP)
+ *
+ * You then need to either add a IEEE80211_xxxx_DEBUG() macro definition for your
+ * classification, or use IEEE80211_DEBUG(IEEE80211_DL_xxxx, ...) whenever you want
+ * to send output to that classification.
+ *
+ * To add your debug level to the list of levels seen when you perform
+ *
+ * % cat /proc/net/ipw/debug_level
+ *
+ * you simply need to add your entry to the ipw_debug_levels array.
+ *
+ * If you do not see debug_level in /proc/net/ipw then you do not have
+ * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ *
+ */
+
+#define IEEE80211_DL_INFO (1<<0)
+#define IEEE80211_DL_WX (1<<1)
+#define IEEE80211_DL_SCAN (1<<2)
+#define IEEE80211_DL_STATE (1<<3)
+#define IEEE80211_DL_MGMT (1<<4)
+#define IEEE80211_DL_FRAG (1<<5)
+#define IEEE80211_DL_EAP (1<<6)
+#define IEEE80211_DL_DROP (1<<7)
+
+#define IEEE80211_DL_TX (1<<8)
+#define IEEE80211_DL_RX (1<<9)
+
+#define IEEE80211_ERROR(f, a...) printk(KERN_ERR "ieee80211: " f, ## a)
+#define IEEE80211_WARNING(f, a...) printk(KERN_WARNING "ieee80211: " f, ## a)
+#define IEEE80211_DEBUG_INFO(f, a...) IEEE80211_DEBUG(IEEE80211_DL_INFO, f, ## a)
+
+#define IEEE80211_DEBUG_WX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_WX, f, ## a)
+#define IEEE80211_DEBUG_SCAN(f, a...) IEEE80211_DEBUG(IEEE80211_DL_SCAN, f, ## a)
+#define IEEE80211_DEBUG_STATE(f, a...) IEEE80211_DEBUG(IEEE80211_DL_STATE, f, ## a)
+#define IEEE80211_DEBUG_MGMT(f, a...) IEEE80211_DEBUG(IEEE80211_DL_MGMT, f, ## a)
+#define IEEE80211_DEBUG_FRAG(f, a...) IEEE80211_DEBUG(IEEE80211_DL_FRAG, f, ## a)
+#define IEEE80211_DEBUG_EAP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_EAP, f, ## a)
+#define IEEE80211_DEBUG_DROP(f, a...) IEEE80211_DEBUG(IEEE80211_DL_DROP, f, ## a)
+#define IEEE80211_DEBUG_TX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_TX, f, ## a)
+#define IEEE80211_DEBUG_RX(f, a...) IEEE80211_DEBUG(IEEE80211_DL_RX, f, ## a)
+#include <linux/netdevice.h>
+#include <linux/wireless.h>
+#include <linux/if_arp.h> /* ARPHRD_ETHER */
+
+#ifndef WIRELESS_SPY
+#define WIRELESS_SPY // enable iwspy support
+#endif
+#include <net/iw_handler.h> // new driver API
+
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW (ETH_P_ECONET + 1)
+#endif
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+ u8 dsap; /* always 0xAA */
+ u8 ssap; /* always 0xAA */
+ u8 ctrl; /* always 0x03 */
+ u8 oui[P80211_OUI_LEN]; /* organizational universal id */
+
+} __attribute__ ((packed));
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq) ((seq) & IEEE80211_SCTL_SEQ)
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_BSS (1<<0)
+#define WLAN_CAPABILITY_IBSS (1<<1)
+#define WLAN_CAPABILITY_CF_POLLABLE (1<<2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3)
+#define WLAN_CAPABILITY_PRIVACY (1<<4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5)
+#define WLAN_CAPABILITY_PBCC (1<<6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION (1<<0)
+#define IEEE80211_OFDM_MODULATION (1<<1)
+
+#define IEEE80211_24GHZ_BAND (1<<0)
+#define IEEE80211_52GHZ_BAND (1<<1)
+
+#define IEEE80211_CCK_RATE_1MB 0x02
+#define IEEE80211_CCK_RATE_2MB 0x04
+#define IEEE80211_CCK_RATE_5MB 0x0B
+#define IEEE80211_CCK_RATE_11MB 0x16
+#define IEEE80211_OFDM_RATE_6MB 0x0C
+#define IEEE80211_OFDM_RATE_9MB 0x12
+#define IEEE80211_OFDM_RATE_12MB 0x18
+#define IEEE80211_OFDM_RATE_18MB 0x24
+#define IEEE80211_OFDM_RATE_24MB 0x30
+#define IEEE80211_OFDM_RATE_36MB 0x48
+#define IEEE80211_OFDM_RATE_48MB 0x60
+#define IEEE80211_OFDM_RATE_54MB 0x6C
+#define IEEE80211_BASIC_RATE_MASK 0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK 0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+ IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK (IEEE80211_CCK_BASIC_RATES_MASK | \
+ IEEE80211_CCK_RATE_5MB_MASK | \
+ IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK 0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK (IEEE80211_OFDM_RATE_6MB_MASK | \
+ IEEE80211_OFDM_RATE_12MB_MASK | \
+ IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK (IEEE80211_OFDM_BASIC_RATES_MASK | \
+ IEEE80211_OFDM_RATE_9MB_MASK | \
+ IEEE80211_OFDM_RATE_18MB_MASK | \
+ IEEE80211_OFDM_RATE_36MB_MASK | \
+ IEEE80211_OFDM_RATE_48MB_MASK | \
+ IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+ IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES 8
+#define IEEE80211_NUM_CCK_RATES 4
+#define IEEE80211_OFDM_SHIFT_MASK_A 4
+
+
+
+
+/* NOTE: This data is for statistical purposes; not all hardware provides this
+ * information for frames received. Not setting these will not cause
+ * any adverse affects. */
+struct ieee80211_rx_stats {
+ u32 mac_time;
+ s8 rssi;
+ u8 signal;
+ u8 noise;
+ u16 rate; /* in 100 kbps */
+ u8 received_channel;
+ u8 control;
+ u8 mask;
+ u8 freq;
+ u16 len;
+};
+
+/* IEEE 802.11 requires that STA supports concurrent reception of at least
+ * three fragmented frames. This define can be increased to support more
+ * concurrent frames, but it should be noted that each entry can consume about
+ * 2 kB of RAM and increasing cache size will slow down frame reassembly. */
+#define IEEE80211_FRAG_CACHE_LEN 4
+
+struct ieee80211_frag_entry {
+ unsigned long first_frag_time;
+ unsigned int seq;
+ unsigned int last_frag;
+ struct sk_buff *skb;
+ u8 src_addr[ETH_ALEN];
+ u8 dst_addr[ETH_ALEN];
+};
+
+struct ieee80211_stats {
+ unsigned int tx_unicast_frames;
+ unsigned int tx_multicast_frames;
+ unsigned int tx_fragments;
+ unsigned int tx_unicast_octets;
+ unsigned int tx_multicast_octets;
+ unsigned int tx_deferred_transmissions;
+ unsigned int tx_single_retry_frames;
+ unsigned int tx_multiple_retry_frames;
+ unsigned int tx_retry_limit_exceeded;
+ unsigned int tx_discards;
+ unsigned int rx_unicast_frames;
+ unsigned int rx_multicast_frames;
+ unsigned int rx_fragments;
+ unsigned int rx_unicast_octets;
+ unsigned int rx_multicast_octets;
+ unsigned int rx_fcs_errors;
+ unsigned int rx_discards_no_buffer;
+ unsigned int tx_discards_wrong_sa;
+ unsigned int rx_discards_undecryptable;
+ unsigned int rx_message_in_msg_fragments;
+ unsigned int rx_message_in_bad_msg_fragments;
+};
+
+struct ieee80211_device;
+
+#if 0 /* for later */
+#include "ieee80211_crypt.h"
+#endif
+
+#define SEC_KEY_1 (1<<0)
+#define SEC_KEY_2 (1<<1)
+#define SEC_KEY_3 (1<<2)
+#define SEC_KEY_4 (1<<3)
+#define SEC_ACTIVE_KEY (1<<4)
+#define SEC_AUTH_MODE (1<<5)
+#define SEC_UNICAST_GROUP (1<<6)
+#define SEC_LEVEL (1<<7)
+#define SEC_ENABLED (1<<8)
+
+#define SEC_LEVEL_0 0 /* None */
+#define SEC_LEVEL_1 1 /* WEP 40 and 104 bit */
+#define SEC_LEVEL_2 2 /* Level 1 + TKIP */
+#define SEC_LEVEL_2_CKIP 3 /* Level 1 + CKIP */
+#define SEC_LEVEL_3 4 /* Level 2 + CCMP */
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+struct ieee80211_security {
+ u16 active_key:2,
+ enabled:1,
+ auth_mode:2,
+ auth_algo:4,
+ unicast_uses_group:1;
+ u8 key_sizes[WEP_KEYS];
+ u8 keys[WEP_KEYS][WEP_KEY_LEN];
+ u8 level;
+ u16 flags;
+} __attribute__ ((packed));
+
+
+/*
+
+ 802.11 data frame from AP
+
+ ,-------------------------------------------------------------------.
+Bytes | 2 | 2 | 6 | 6 | 6 | 2 | 0..2312 | 4 |
+ |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura | DA/RA | TA | SA | Sequ | frame | fcs |
+ | | tion | (BSSID) | | | ence | data | |
+ `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+#define BEACON_PROBE_SSID_ID_POSITION 12
+
+/* Management Frame Information Element Types */
+#define MFIE_TYPE_SSID 0
+#define MFIE_TYPE_RATES 1
+#define MFIE_TYPE_FH_SET 2
+#define MFIE_TYPE_DS_SET 3
+#define MFIE_TYPE_CF_SET 4
+#define MFIE_TYPE_TIM 5
+#define MFIE_TYPE_IBSS_SET 6
+#define MFIE_TYPE_CHALLENGE 16
+#define MFIE_TYPE_RSN 48
+#define MFIE_TYPE_RATES_EX 50
+#define MFIE_TYPE_GENERIC 221
+
+struct ieee80211_info_element_hdr {
+ u8 id;
+ u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+ u8 id;
+ u8 len;
+ u8 data[0];
+} __attribute__ ((packed));
+
+/*
+ * These are the data types that can make up management packets
+ *
+ u16 auth_algorithm;
+ u16 auth_sequence;
+ u16 beacon_interval;
+ u16 capability;
+ u8 current_ap[ETH_ALEN];
+ u16 listen_interval;
+ struct {
+ u16 association_id:14, reserved:2;
+ } __attribute__ ((packed));
+ u32 time_stamp[2];
+ u16 reason;
+ u16 status;
+*/
+
+struct ieee80211_authentication {
+ struct ieee80211_hdr_3addr header;
+ u16 algorithm;
+ u16 transaction;
+ u16 status;
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+
+struct ieee80211_probe_response {
+ struct ieee80211_hdr_3addr header;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 capability;
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_request_frame {
+ u16 capability;
+ u16 listen_interval;
+ u8 current_ap[ETH_ALEN];
+ struct ieee80211_info_element info_element;
+} __attribute__ ((packed));
+
+struct ieee80211_assoc_response_frame {
+ struct ieee80211_hdr_3addr header;
+ u16 capability;
+ u16 status;
+ u16 aid;
+ struct ieee80211_info_element info_element; /* supported rates */
+} __attribute__ ((packed));
+
+
+struct ieee80211_txb {
+ u8 nr_frags;
+ u8 encrypted;
+ u16 reserved;
+ u16 frag_size;
+ u16 payload_size;
+ struct sk_buff *fragments[0];
+};
+
+
+/* SWEEP TABLE ENTRIES NUMBER*/
+#define MAX_SWEEP_TAB_ENTRIES 42
+#define MAX_SWEEP_TAB_ENTRIES_PER_PACKET 7
+/* MAX_RATES_LENGTH needs to be 12. The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates. Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH ((u8)12)
+#define MAX_RATES_EX_LENGTH ((u8)16)
+#define MAX_NETWORK_COUNT 128
+
+#define CRC_LENGTH 4U
+
+#define MAX_WPA_IE_LEN 64
+
+#define NETWORK_EMPTY_ESSID (1<<0)
+#define NETWORK_HAS_OFDM (1<<1)
+#define NETWORK_HAS_CCK (1<<2)
+
+struct ieee80211_network {
+ /* These entries are used to identify a unique network */
+ u8 bssid[ETH_ALEN];
+ u8 channel;
+ /* Ensure null-terminated for any debug msgs */
+ u8 ssid[IW_ESSID_MAX_SIZE + 1];
+ u8 ssid_len;
+
+ /* These are network statistics */
+ struct ieee80211_rx_stats stats;
+ u16 capability;
+ u8 rates[MAX_RATES_LENGTH];
+ u8 rates_len;
+ u8 rates_ex[MAX_RATES_EX_LENGTH];
+ u8 rates_ex_len;
+ unsigned long last_scanned;
+ u8 mode;
+ u8 flags;
+ u32 last_associate;
+ u32 time_stamp[2];
+ u16 beacon_interval;
+ u16 listen_interval;
+ u16 atim_window;
+ u8 wpa_ie[MAX_WPA_IE_LEN];
+ size_t wpa_ie_len;
+ u8 rsn_ie[MAX_WPA_IE_LEN];
+ size_t rsn_ie_len;
+ struct list_head list;
+};
+
+enum ieee80211_state {
+ IEEE80211_UNINITIALIZED = 0,
+ IEEE80211_INITIALIZED,
+ IEEE80211_ASSOCIATING,
+ IEEE80211_ASSOCIATED,
+ IEEE80211_AUTHENTICATING,
+ IEEE80211_AUTHENTICATED,
+ IEEE80211_SHUTDOWN
+};
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+struct ieee80211_device {
+ struct net_device *dev;
+
+ /* Bookkeeping structures */
+ struct net_device_stats stats;
+ struct ieee80211_stats ieee_stats;
+
+ /* Probe / Beacon management */
+ struct list_head network_free_list;
+ struct list_head network_list;
+ struct ieee80211_network *networks;
+ int scans;
+ int scan_age;
+
+ int iw_mode; /* operating mode (IW_MODE_*) */
+
+ spinlock_t lock;
+
+ int tx_headroom; /* Set to size of any additional room needed at front
+ * of allocated Tx SKBs */
+ u32 config;
+
+ /* WEP and other encryption related settings at the device level */
+ int open_wep; /* Set to 1 to allow unencrypted frames */
+
+ int reset_on_keychange; /* Set to 1 if the HW needs to be reset on
+ * WEP key changes */
+
+ /* If the host performs {en,de}cryption, then set to 1 */
+ int host_encrypt;
+ int host_decrypt;
+ int ieee802_1x; /* is IEEE 802.1X used */
+
+ /* WPA data */
+ int wpa_enabled;
+ int drop_unencrypted;
+ int tkip_countermeasures;
+ int privacy_invoked;
+ size_t wpa_ie_len;
+ u8 *wpa_ie;
+
+ struct list_head crypt_deinit_list;
+ struct ieee80211_crypt_data *crypt[WEP_KEYS];
+ int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */
+ struct timer_list crypt_deinit_timer;
+
+ int bcrx_sta_key; /* use individual keys to override default keys even
+ * with RX of broad/multicast frames */
+
+ /* Fragmentation structures */
+ struct ieee80211_frag_entry frag_cache[IEEE80211_FRAG_CACHE_LEN];
+ unsigned int frag_next_idx;
+ u16 fts; /* Fragmentation Threshold */
+
+ /* Association info */
+ u8 bssid[ETH_ALEN];
+
+ enum ieee80211_state state;
+
+ int mode; /* A, B, G */
+ int modulation; /* CCK, OFDM */
+ int freq_band; /* 2.4Ghz, 5.2Ghz, Mixed */
+ int abg_ture; /* ABG flag */
+
+ /* Callback functions */
+ void (*set_security)(struct net_device *dev,
+ struct ieee80211_security *sec);
+ int (*hard_start_xmit)(struct ieee80211_txb *txb,
+ struct net_device *dev);
+ int (*reset_port)(struct net_device *dev);
+
+ /* This must be the last item so that it points to the data
+ * allocated beyond this structure by alloc_ieee80211 */
+ u8 priv[0];
+};
+
+#define IEEE_A (1<<0)
+#define IEEE_B (1<<1)
+#define IEEE_G (1<<2)
+#define IEEE_MODE_MASK (IEEE_A|IEEE_B|IEEE_G)
+
+extern inline void *ieee80211_priv(struct net_device *dev)
+{
+ return ((struct ieee80211_device *)netdev_priv(dev))->priv;
+}
+
+extern inline int ieee80211_is_empty_essid(const char *essid, int essid_len)
+{
+ /* Single white space is for Linksys APs */
+ if (essid_len == 1 && essid[0] == ' ')
+ return 1;
+
+ /* Otherwise, if the entire essid is 0, we assume it is hidden */
+ while (essid_len) {
+ essid_len--;
+ if (essid[essid_len] != '\0')
+ return 0;
+ }
+
+ return 1;
+}
+
+extern inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode)
+{
+ /*
+ * It is possible for both access points and our device to support
+ * combinations of modes, so as long as there is one valid combination
+ * of ap/device supported modes, then return success
+ *
+ */
+ if ((mode & IEEE_A) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_52GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_G) &&
+ (ieee->modulation & IEEE80211_OFDM_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ if ((mode & IEEE_B) &&
+ (ieee->modulation & IEEE80211_CCK_MODULATION) &&
+ (ieee->freq_band & IEEE80211_24GHZ_BAND))
+ return 1;
+
+ return 0;
+}
+
+extern inline int ieee80211_get_hdrlen(u16 fc)
+{
+ int hdrlen = IEEE80211_3ADDR_LEN;
+
+ switch (WLAN_FC_GET_TYPE(fc)) {
+ case IEEE80211_FTYPE_DATA:
+ if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
+ hdrlen = IEEE80211_4ADDR_LEN;
+ break;
+ case IEEE80211_FTYPE_CTL:
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case IEEE80211_STYPE_CTS:
+ case IEEE80211_STYPE_ACK:
+ hdrlen = IEEE80211_1ADDR_LEN;
+ break;
+ default:
+ hdrlen = IEEE80211_2ADDR_LEN;
+ break;
+ }
+ break;
+ }
+
+ return hdrlen;
+}
+
+
+
+/* ieee80211.c */
+extern void free_ieee80211(struct net_device *dev);
+extern struct net_device *alloc_ieee80211(int sizeof_priv);
+
+extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
+
+/* ieee80211_tx.c */
+
+
+extern int ieee80211_xmit(struct sk_buff *skb,
+ struct net_device *dev);
+extern void ieee80211_txb_free(struct ieee80211_txb *);
+
+
+/* ieee80211_rx.c */
+extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
+ struct ieee80211_rx_stats *rx_stats);
+extern void ieee80211_rx_mgt(struct ieee80211_device *ieee,
+ struct ieee80211_hdr *header,
+ struct ieee80211_rx_stats *stats);
+
+/* iee80211_wx.c */
+extern int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+extern int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
+ struct iw_request_info *info,
+ union iwreq_data *wrqu, char *key);
+
+
+extern inline void ieee80211_increment_scans(struct ieee80211_device *ieee)
+{
+ ieee->scans++;
+}
+
+extern inline int ieee80211_get_scans(struct ieee80211_device *ieee)
+{
+ return ieee->scans;
+}
+
+static inline const char *escape_essid(const char *essid, u8 essid_len) {
+ static char escaped[IW_ESSID_MAX_SIZE * 2 + 1];
+ const char *s = essid;
+ char *d = escaped;
+
+ if (ieee80211_is_empty_essid(essid, essid_len)) {
+ memcpy(escaped, "<hidden>", sizeof("<hidden>"));
+ return escaped;
+ }
+
+ essid_len = min(essid_len, (u8)IW_ESSID_MAX_SIZE);
+ while (essid_len--) {
+ if (*s == '\0') {
+ *d++ = '\\';
+ *d++ = '0';
+ s++;
+ } else {
+ *d++ = *s++;
+ }
+ }
+ *d = '\0';
+ return escaped;
+}
+
+#endif /* IEEE80211_H */
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 771b47e30f86..69324465e8b3 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -183,7 +183,6 @@ struct ipv6_txoptions
struct ipv6_opt_hdr *hopopt;
struct ipv6_opt_hdr *dst0opt;
struct ipv6_rt_hdr *srcrt; /* Routing Header */
- struct ipv6_opt_hdr *auth;
struct ipv6_opt_hdr *dst1opt;
/* Option buffer, as read by IPV6_PKTOPTIONS, starts here. */
diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h
index 71d6af83b631..92c828029cd8 100644
--- a/include/net/irda/irda_device.h
+++ b/include/net/irda/irda_device.h
@@ -224,7 +224,7 @@ int irda_device_is_receiving(struct net_device *dev);
/* Interface for internal use */
static inline int irda_device_txqueue_empty(const struct net_device *dev)
{
- return (skb_queue_len(&dev->qdisc->q) == 0);
+ return skb_queue_empty(&dev->qdisc->q);
}
int irda_device_set_raw_mode(struct net_device* self, int status);
struct net_device *alloc_irdadev(int sizeof_priv);
diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h
index fcb05a387dbe..6492e7363d84 100644
--- a/include/net/pkt_sched.h
+++ b/include/net/pkt_sched.h
@@ -13,13 +13,12 @@ struct qdisc_walker
extern rwlock_t qdisc_tree_lock;
-#define QDISC_ALIGN 32
-#define QDISC_ALIGN_CONST (QDISC_ALIGN - 1)
+#define QDISC_ALIGNTO 32
+#define QDISC_ALIGN(len) (((len) + QDISC_ALIGNTO-1) & ~(QDISC_ALIGNTO-1))
static inline void *qdisc_priv(struct Qdisc *q)
{
- return (char *)q + ((sizeof(struct Qdisc) + QDISC_ALIGN_CONST)
- & ~QDISC_ALIGN_CONST);
+ return (char *) q + QDISC_ALIGN(sizeof(struct Qdisc));
}
/*
@@ -207,8 +206,6 @@ psched_tod_diff(int delta_sec, int bound)
#endif /* !CONFIG_NET_SCH_CLK_GETTIMEOFDAY */
-extern struct Qdisc noop_qdisc;
-extern struct Qdisc_ops noop_qdisc_ops;
extern struct Qdisc_ops pfifo_qdisc_ops;
extern struct Qdisc_ops bfifo_qdisc_ops;
@@ -216,14 +213,6 @@ extern int register_qdisc(struct Qdisc_ops *qops);
extern int unregister_qdisc(struct Qdisc_ops *qops);
extern struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle);
extern struct Qdisc *qdisc_lookup_class(struct net_device *dev, u32 handle);
-extern void dev_init_scheduler(struct net_device *dev);
-extern void dev_shutdown(struct net_device *dev);
-extern void dev_activate(struct net_device *dev);
-extern void dev_deactivate(struct net_device *dev);
-extern void qdisc_reset(struct Qdisc *qdisc);
-extern void qdisc_destroy(struct Qdisc *qdisc);
-extern struct Qdisc * qdisc_create_dflt(struct net_device *dev,
- struct Qdisc_ops *ops);
extern struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
struct rtattr *tab);
extern void qdisc_put_rtab(struct qdisc_rate_table *tab);
diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h
index 7b97405e2dbf..7b6ec9986715 100644
--- a/include/net/sch_generic.h
+++ b/include/net/sch_generic.h
@@ -164,6 +164,19 @@ extern void qdisc_unlock_tree(struct net_device *dev);
#define tcf_tree_lock(tp) qdisc_lock_tree((tp)->q->dev)
#define tcf_tree_unlock(tp) qdisc_unlock_tree((tp)->q->dev)
+extern struct Qdisc noop_qdisc;
+extern struct Qdisc_ops noop_qdisc_ops;
+
+extern void dev_init_scheduler(struct net_device *dev);
+extern void dev_shutdown(struct net_device *dev);
+extern void dev_activate(struct net_device *dev);
+extern void dev_deactivate(struct net_device *dev);
+extern void qdisc_reset(struct Qdisc *qdisc);
+extern void qdisc_destroy(struct Qdisc *qdisc);
+extern struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops);
+extern struct Qdisc *qdisc_create_dflt(struct net_device *dev,
+ struct Qdisc_ops *ops);
+
static inline void
tcf_destroy(struct tcf_proto *tp)
{
diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h
index 4868c7f7749d..5999e5684bbf 100644
--- a/include/net/sctp/constants.h
+++ b/include/net/sctp/constants.h
@@ -263,23 +263,11 @@ enum { SCTP_MIN_PMTU = 576 };
enum { SCTP_MAX_DUP_TSNS = 16 };
enum { SCTP_MAX_GABS = 16 };
-/* Here we define the default timers. */
+/* Heartbeat interval - 30 secs */
+#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (30 * HZ)
-/* cookie timer def = ? seconds */
-#define SCTP_DEFAULT_TIMEOUT_T1_COOKIE (3 * HZ)
-
-/* init timer def = 3 seconds */
-#define SCTP_DEFAULT_TIMEOUT_T1_INIT (3 * HZ)
-
-/* shutdown timer def = 300 ms */
-#define SCTP_DEFAULT_TIMEOUT_T2_SHUTDOWN ((300 * HZ) / 1000)
-
-/* 0 seconds + RTO */
-#define SCTP_DEFAULT_TIMEOUT_HEARTBEAT (10 * HZ)
-
-/* recv timer def = 200ms (in usec) */
+/* Delayed sack timer - 200ms */
#define SCTP_DEFAULT_TIMEOUT_SACK ((200 * HZ) / 1000)
-#define SCTP_DEFAULT_TIMEOUT_SACK_MAX ((500 * HZ) / 1000) /* 500 ms */
/* RTO.Initial - 3 seconds
* RTO.Min - 1 second
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
index ef2738159ab3..4a26adfaed71 100644
--- a/include/net/sctp/sctp.h
+++ b/include/net/sctp/sctp.h
@@ -125,7 +125,8 @@
*/
extern struct sock *sctp_get_ctl_sock(void);
extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
- sctp_scope_t, int gfp, int flags);
+ sctp_scope_t, unsigned int __nocast gfp,
+ int flags);
extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index a53e08a45e32..58462164d960 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -131,7 +131,6 @@ sctp_state_fn_t sctp_sf_do_ecne;
sctp_state_fn_t sctp_sf_ootb;
sctp_state_fn_t sctp_sf_pdiscard;
sctp_state_fn_t sctp_sf_violation;
-sctp_state_fn_t sctp_sf_violation_chunklen;
sctp_state_fn_t sctp_sf_discard_chunk;
sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
@@ -182,17 +181,17 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t,
int sctp_chunk_iif(const struct sctp_chunk *);
struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *,
struct sctp_chunk *,
- int gfp);
+ unsigned int __nocast gfp);
__u32 sctp_generate_verification_tag(void);
void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
/* Prototypes for chunk-building functions. */
struct sctp_chunk *sctp_make_init(const struct sctp_association *,
const struct sctp_bind_addr *,
- int gfp, int vparam_len);
+ unsigned int __nocast gfp, int vparam_len);
struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *,
const struct sctp_chunk *,
- const int gfp,
+ const unsigned int __nocast gfp,
const int unkparam_len);
struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *,
const struct sctp_chunk *);
@@ -259,11 +258,6 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *);
-sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
- __u16 error,
- const struct sctp_association *asoc,
- struct sctp_transport *transport);
-
/* Prototypes for statetable processing. */
int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
@@ -271,7 +265,7 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
struct sctp_endpoint *,
struct sctp_association *asoc,
void *event_arg,
- int gfp);
+ unsigned int __nocast gfp);
/* 2nd level prototypes */
void sctp_generate_t3_rtx_event(unsigned long peer);
@@ -281,7 +275,8 @@ void sctp_ootb_pkt_free(struct sctp_packet *);
struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
const struct sctp_association *,
- struct sctp_chunk *, int gfp, int *err,
+ struct sctp_chunk *,
+ unsigned int __nocast gfp, int *err,
struct sctp_chunk **err_chk_p);
int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
struct sockaddr_storage*, int);
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index dfad4d3c581c..994009bbe3b4 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -161,6 +161,9 @@ extern struct sctp_globals {
*/
int sndbuf_policy;
+ /* Delayed SACK timeout 200ms default*/
+ int sack_timeout;
+
/* HB.interval - 30 seconds */
int hb_interval;
@@ -217,6 +220,7 @@ extern struct sctp_globals {
#define sctp_sndbuf_policy (sctp_globals.sndbuf_policy)
#define sctp_max_retrans_path (sctp_globals.max_retrans_path)
#define sctp_max_retrans_init (sctp_globals.max_retrans_init)
+#define sctp_sack_timeout (sctp_globals.sack_timeout)
#define sctp_hb_interval (sctp_globals.hb_interval)
#define sctp_max_instreams (sctp_globals.max_instreams)
#define sctp_max_outstreams (sctp_globals.max_outstreams)
@@ -441,7 +445,8 @@ struct sctp_ssnmap {
int malloced;
};
-struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp);
+struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
+ unsigned int __nocast gfp);
void sctp_ssnmap_free(struct sctp_ssnmap *map);
void sctp_ssnmap_clear(struct sctp_ssnmap *map);
@@ -578,7 +583,6 @@ void sctp_datamsg_track(struct sctp_chunk *);
void sctp_chunk_fail(struct sctp_chunk *, int error);
int sctp_chunk_abandoned(struct sctp_chunk *);
-
/* RFC2960 1.4 Key Terms
*
* o Chunk: A unit of information within an SCTP packet, consisting of
@@ -588,13 +592,8 @@ int sctp_chunk_abandoned(struct sctp_chunk *);
* each chunk as well as a few other header pointers...
*/
struct sctp_chunk {
- /* These first three elements MUST PRECISELY match the first
- * three elements of struct sk_buff. This allows us to reuse
- * all the skb_* queue management functions.
- */
- struct sctp_chunk *next;
- struct sctp_chunk *prev;
- struct sk_buff_head *list;
+ struct list_head list;
+
atomic_t refcnt;
/* This is our link to the per-transport transmitted list. */
@@ -713,7 +712,7 @@ struct sctp_packet {
__u32 vtag;
/* This contains the payload chunks. */
- struct sk_buff_head chunks;
+ struct list_head chunk_list;
/* This is the overhead of the sctp and ip headers. */
size_t overhead;
@@ -947,7 +946,8 @@ struct sctp_transport {
} cacc;
};
-struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
+struct sctp_transport *sctp_transport_new(const union sctp_addr *,
+ unsigned int __nocast);
void sctp_transport_set_owner(struct sctp_transport *,
struct sctp_association *);
void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
@@ -970,7 +970,7 @@ struct sctp_inq {
/* This is actually a queue of sctp_chunk each
* containing a partially decoded packet.
*/
- struct sk_buff_head in;
+ struct list_head in_chunk_list;
/* This is the packet which is currently off the in queue and is
* being worked on through the inbound chunk processing.
*/
@@ -1013,7 +1013,7 @@ struct sctp_outq {
struct sctp_association *asoc;
/* Data pending that has never been transmitted. */
- struct sk_buff_head out;
+ struct list_head out_chunk_list;
unsigned out_qlen; /* Total length of queued data chunks. */
@@ -1021,7 +1021,7 @@ struct sctp_outq {
unsigned error;
/* These are control chunks we want to send. */
- struct sk_buff_head control;
+ struct list_head control_chunk_list;
/* These are chunks that have been sacked but are above the
* CTSN, or cumulative tsn ack point.
@@ -1095,9 +1095,10 @@ void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
void sctp_bind_addr_free(struct sctp_bind_addr *);
int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src,
- sctp_scope_t scope, int gfp,int flags);
+ sctp_scope_t scope, unsigned int __nocast gfp,
+ int flags);
int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
- int gfp);
+ unsigned int __nocast gfp);
int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
struct sctp_sock *);
@@ -1106,9 +1107,10 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
int addrcnt,
struct sctp_sock *opt);
union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
- int *addrs_len, int gfp);
+ int *addrs_len,
+ unsigned int __nocast gfp);
int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw, int len,
- __u16 port, int gfp);
+ __u16 port, unsigned int __nocast gfp);
sctp_scope_t sctp_scope(const union sctp_addr *);
int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
@@ -1237,7 +1239,7 @@ static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
}
/* These are function signatures for manipulating endpoints. */
-struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
+struct sctp_endpoint *sctp_endpoint_new(struct sock *, unsigned int __nocast);
void sctp_endpoint_free(struct sctp_endpoint *);
void sctp_endpoint_put(struct sctp_endpoint *);
void sctp_endpoint_hold(struct sctp_endpoint *);
@@ -1258,7 +1260,7 @@ int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t,
struct sctp_chunk **err_chunk);
int sctp_process_init(struct sctp_association *, sctp_cid_t cid,
const union sctp_addr *peer,
- sctp_init_chunk_t *init, int gfp);
+ sctp_init_chunk_t *init, unsigned int __nocast gfp);
__u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const struct sctp_endpoint *);
@@ -1668,7 +1670,7 @@ struct sctp_association {
* which already resides in sctp_outq. Please move this
* queue and its supporting logic down there. --piggy]
*/
- struct sk_buff_head addip_chunks;
+ struct list_head addip_chunk_list;
/* ADDIP Section 4.1 ASCONF Chunk Procedures
*
@@ -1721,7 +1723,7 @@ static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base)
struct sctp_association *
sctp_association_new(const struct sctp_endpoint *, const struct sock *,
- sctp_scope_t scope, int gfp);
+ sctp_scope_t scope, unsigned int __nocast gfp);
void sctp_association_free(struct sctp_association *);
void sctp_association_put(struct sctp_association *);
void sctp_association_hold(struct sctp_association *);
@@ -1737,7 +1739,7 @@ int sctp_assoc_lookup_laddr(struct sctp_association *asoc,
const union sctp_addr *laddr);
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *,
const union sctp_addr *address,
- const int gfp,
+ const unsigned int __nocast gfp,
const int peer_state);
void sctp_assoc_del_peer(struct sctp_association *asoc,
const union sctp_addr *addr);
@@ -1761,9 +1763,11 @@ void sctp_assoc_rwnd_increase(struct sctp_association *, unsigned);
void sctp_assoc_rwnd_decrease(struct sctp_association *, unsigned);
void sctp_assoc_set_primary(struct sctp_association *,
struct sctp_transport *);
-int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *, int);
+int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *,
+ unsigned int __nocast);
int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
- struct sctp_cookie*, int gfp);
+ struct sctp_cookie*,
+ unsigned int __nocast gfp);
int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2);
diff --git a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
index 1019d83a580a..90fe4bf6754f 100644
--- a/include/net/sctp/ulpevent.h
+++ b/include/net/sctp/ulpevent.h
@@ -88,7 +88,7 @@ struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
__u16 error,
__u16 outbound,
__u16 inbound,
- int gfp);
+ unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const struct sctp_association *asoc,
@@ -96,35 +96,35 @@ struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
int flags,
int state,
int error,
- int gfp);
+ unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
__u16 flags,
- int gfp);
+ unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
__u16 flags,
__u32 error,
- int gfp);
+ unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const struct sctp_association *asoc,
__u16 flags,
- int gfp);
+ unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
const struct sctp_association *asoc,
- __u32 indication, int gfp);
+ __u32 indication, unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication(
- const struct sctp_association *asoc, int gfp);
+ const struct sctp_association *asoc, unsigned int __nocast gfp);
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
struct sctp_chunk *chunk,
- int gfp);
+ unsigned int __nocast gfp);
void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
struct msghdr *);
diff --git a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h
index 961736d29d21..1a60c6d943c1 100644
--- a/include/net/sctp/ulpqueue.h
+++ b/include/net/sctp/ulpqueue.h
@@ -62,19 +62,22 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
void sctp_ulpq_free(struct sctp_ulpq *);
/* Add a new DATA chunk for processing. */
-int sctp_ulpq_tail_data(struct sctp_ulpq *, struct sctp_chunk *, int);
+int sctp_ulpq_tail_data(struct sctp_ulpq *, struct sctp_chunk *,
+ unsigned int __nocast);
/* Add a new event for propagation to the ULP. */
int sctp_ulpq_tail_event(struct sctp_ulpq *, struct sctp_ulpevent *ev);
/* Renege previously received chunks. */
-void sctp_ulpq_renege(struct sctp_ulpq *, struct sctp_chunk *, int);
+void sctp_ulpq_renege(struct sctp_ulpq *, struct sctp_chunk *,
+ unsigned int __nocast);
/* Perform partial delivery. */
-void sctp_ulpq_partial_delivery(struct sctp_ulpq *, struct sctp_chunk *, int);
+void sctp_ulpq_partial_delivery(struct sctp_ulpq *, struct sctp_chunk *,
+ unsigned int __nocast);
/* Abort the partial delivery. */
-void sctp_ulpq_abort_pd(struct sctp_ulpq *, int);
+void sctp_ulpq_abort_pd(struct sctp_ulpq *, unsigned int __nocast);
/* Clear the partial data delivery condition on this socket. */
int sctp_clear_pd(struct sock *sk);
diff --git a/include/net/slhc_vj.h b/include/net/slhc_vj.h
index 0b2c2784f333..8716d5942b65 100644
--- a/include/net/slhc_vj.h
+++ b/include/net/slhc_vj.h
@@ -170,19 +170,14 @@ struct slcompress {
};
#define NULLSLCOMPR (struct slcompress *)0
-#define __ARGS(x) x
-
/* In slhc.c: */
-struct slcompress *slhc_init __ARGS((int rslots, int tslots));
-void slhc_free __ARGS((struct slcompress *comp));
-
-int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp,
- int isize, unsigned char *ocp, unsigned char **cpp,
- int compress_cid));
-int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp,
- int isize));
-int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp,
- int isize));
-int slhc_toss __ARGS((struct slcompress *comp));
+struct slcompress *slhc_init(int rslots, int tslots);
+void slhc_free(struct slcompress *comp);
+
+int slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
+ unsigned char *ocp, unsigned char **cpp, int compress_cid);
+int slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize);
+int slhc_remember(struct slcompress *comp, unsigned char *icp, int isize);
+int slhc_toss(struct slcompress *comp);
#endif /* _SLHC_H */
diff --git a/include/net/sock.h b/include/net/sock.h
index e593af5b1ecc..a1042d08becd 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -684,16 +684,17 @@ extern void FASTCALL(release_sock(struct sock *sk));
#define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock))
#define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock))
-extern struct sock *sk_alloc(int family, int priority,
+extern struct sock *sk_alloc(int family,
+ unsigned int __nocast priority,
struct proto *prot, int zero_it);
extern void sk_free(struct sock *sk);
extern struct sk_buff *sock_wmalloc(struct sock *sk,
unsigned long size, int force,
- int priority);
+ unsigned int __nocast priority);
extern struct sk_buff *sock_rmalloc(struct sock *sk,
unsigned long size, int force,
- int priority);
+ unsigned int __nocast priority);
extern void sock_wfree(struct sk_buff *skb);
extern void sock_rfree(struct sk_buff *skb);
@@ -708,7 +709,8 @@ extern struct sk_buff *sock_alloc_send_skb(struct sock *sk,
unsigned long size,
int noblock,
int *errcode);
-extern void *sock_kmalloc(struct sock *sk, int size, int priority);
+extern void *sock_kmalloc(struct sock *sk, int size,
+ unsigned int __nocast priority);
extern void sock_kfree_s(struct sock *sk, void *mem, int size);
extern void sk_send_sigurg(struct sock *sk);
@@ -1132,15 +1134,19 @@ static inline void sk_stream_moderate_sndbuf(struct sock *sk)
}
static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
- int size, int mem, int gfp)
+ int size, int mem,
+ unsigned int __nocast gfp)
{
- struct sk_buff *skb = alloc_skb(size + sk->sk_prot->max_header, gfp);
+ struct sk_buff *skb;
+ int hdr_len;
+ hdr_len = SKB_DATA_ALIGN(sk->sk_prot->max_header);
+ skb = alloc_skb(size + hdr_len, gfp);
if (skb) {
skb->truesize += mem;
if (sk->sk_forward_alloc >= (int)skb->truesize ||
sk_stream_mem_schedule(sk, skb->truesize, 0)) {
- skb_reserve(skb, sk->sk_prot->max_header);
+ skb_reserve(skb, hdr_len);
return skb;
}
__kfree_skb(skb);
@@ -1152,7 +1158,8 @@ static inline struct sk_buff *sk_stream_alloc_pskb(struct sock *sk,
}
static inline struct sk_buff *sk_stream_alloc_skb(struct sock *sk,
- int size, int gfp)
+ int size,
+ unsigned int __nocast gfp)
{
return sk_stream_alloc_pskb(sk, size, 0, gfp);
}
@@ -1185,7 +1192,7 @@ static inline int sock_writeable(const struct sock *sk)
return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf / 2);
}
-static inline int gfp_any(void)
+static inline unsigned int __nocast gfp_any(void)
{
return in_softirq() ? GFP_ATOMIC : GFP_KERNEL;
}
diff --git a/include/net/tcp.h b/include/net/tcp.h
index f730935b824a..f4f9aba07ac2 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -505,25 +505,6 @@ static __inline__ int tcp_sk_listen_hashfn(struct sock *sk)
#else
# define TCP_TW_RECYCLE_TICK (12+2-TCP_TW_RECYCLE_SLOTS_LOG)
#endif
-
-#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
- * max_cwnd = snd_cwnd * beta
- */
-#define BICTCP_MAX_INCREMENT 32 /*
- * Limit on the amount of
- * increment allowed during
- * binary search.
- */
-#define BICTCP_FUNC_OF_MIN_INCR 11 /*
- * log(B/Smin)/log(B/(B-1))+1,
- * Smin:min increment
- * B:log factor
- */
-#define BICTCP_B 4 /*
- * In binary search,
- * go to point (max+min)/N
- */
-
/*
* TCP option
*/
@@ -596,16 +577,7 @@ extern int sysctl_tcp_adv_win_scale;
extern int sysctl_tcp_tw_reuse;
extern int sysctl_tcp_frto;
extern int sysctl_tcp_low_latency;
-extern int sysctl_tcp_westwood;
-extern int sysctl_tcp_vegas_cong_avoid;
-extern int sysctl_tcp_vegas_alpha;
-extern int sysctl_tcp_vegas_beta;
-extern int sysctl_tcp_vegas_gamma;
extern int sysctl_tcp_nometrics_save;
-extern int sysctl_tcp_bic;
-extern int sysctl_tcp_bic_fast_convergence;
-extern int sysctl_tcp_bic_low_window;
-extern int sysctl_tcp_bic_beta;
extern int sysctl_tcp_moderate_rcvbuf;
extern int sysctl_tcp_tso_win_divisor;
@@ -749,11 +721,16 @@ static inline int tcp_ack_scheduled(struct tcp_sock *tp)
return tp->ack.pending&TCP_ACK_SCHED;
}
-static __inline__ void tcp_dec_quickack_mode(struct tcp_sock *tp)
+static __inline__ void tcp_dec_quickack_mode(struct tcp_sock *tp, unsigned int pkts)
{
- if (tp->ack.quick && --tp->ack.quick == 0) {
- /* Leaving quickack mode we deflate ATO. */
- tp->ack.ato = TCP_ATO_MIN;
+ if (tp->ack.quick) {
+ if (pkts >= tp->ack.quick) {
+ tp->ack.quick = 0;
+
+ /* Leaving quickack mode we deflate ATO. */
+ tp->ack.ato = TCP_ATO_MIN;
+ } else
+ tp->ack.quick -= pkts;
}
}
@@ -871,7 +848,9 @@ extern __u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb,
/* tcp_output.c */
-extern int tcp_write_xmit(struct sock *, int nonagle);
+extern void __tcp_push_pending_frames(struct sock *sk, struct tcp_sock *tp,
+ unsigned int cur_mss, int nonagle);
+extern int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp);
extern int tcp_retransmit_skb(struct sock *, struct sk_buff *);
extern void tcp_xmit_retransmit_queue(struct sock *);
extern void tcp_simple_retransmit(struct sock *);
@@ -881,12 +860,16 @@ extern void tcp_send_probe0(struct sock *);
extern void tcp_send_partial(struct sock *);
extern int tcp_write_wakeup(struct sock *);
extern void tcp_send_fin(struct sock *sk);
-extern void tcp_send_active_reset(struct sock *sk, int priority);
+extern void tcp_send_active_reset(struct sock *sk,
+ unsigned int __nocast priority);
extern int tcp_send_synack(struct sock *);
-extern void tcp_push_one(struct sock *, unsigned mss_now);
+extern void tcp_push_one(struct sock *, unsigned int mss_now);
extern void tcp_send_ack(struct sock *sk);
extern void tcp_send_delayed_ack(struct sock *sk);
+/* tcp_input.c */
+extern void tcp_cwnd_application_limited(struct sock *sk);
+
/* tcp_timer.c */
extern void tcp_init_xmit_timers(struct sock *);
extern void tcp_clear_xmit_timers(struct sock *);
@@ -986,7 +969,7 @@ static inline void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long
static inline void tcp_initialize_rcv_mss(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
- unsigned int hint = min(tp->advmss, tp->mss_cache_std);
+ unsigned int hint = min_t(unsigned int, tp->advmss, tp->mss_cache);
hint = min(hint, tp->rcv_wnd/2);
hint = min(hint, TCP_MIN_RCVMSS);
@@ -1009,7 +992,7 @@ static __inline__ void tcp_fast_path_on(struct tcp_sock *tp)
static inline void tcp_fast_path_check(struct sock *sk, struct tcp_sock *tp)
{
- if (skb_queue_len(&tp->out_of_order_queue) == 0 &&
+ if (skb_queue_empty(&tp->out_of_order_queue) &&
tp->rcv_wnd &&
atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf &&
!tp->urg_data)
@@ -1136,6 +1119,82 @@ static inline void tcp_packets_out_dec(struct tcp_sock *tp,
tp->packets_out -= tcp_skb_pcount(skb);
}
+/* Events passed to congestion control interface */
+enum tcp_ca_event {
+ CA_EVENT_TX_START, /* first transmit when no packets in flight */
+ CA_EVENT_CWND_RESTART, /* congestion window restart */
+ CA_EVENT_COMPLETE_CWR, /* end of congestion recovery */
+ CA_EVENT_FRTO, /* fast recovery timeout */
+ CA_EVENT_LOSS, /* loss timeout */
+ CA_EVENT_FAST_ACK, /* in sequence ack */
+ CA_EVENT_SLOW_ACK, /* other ack */
+};
+
+/*
+ * Interface for adding new TCP congestion control handlers
+ */
+#define TCP_CA_NAME_MAX 16
+struct tcp_congestion_ops {
+ struct list_head list;
+
+ /* initialize private data (optional) */
+ void (*init)(struct tcp_sock *tp);
+ /* cleanup private data (optional) */
+ void (*release)(struct tcp_sock *tp);
+
+ /* return slow start threshold (required) */
+ u32 (*ssthresh)(struct tcp_sock *tp);
+ /* lower bound for congestion window (optional) */
+ u32 (*min_cwnd)(struct tcp_sock *tp);
+ /* do new cwnd calculation (required) */
+ void (*cong_avoid)(struct tcp_sock *tp, u32 ack,
+ u32 rtt, u32 in_flight, int good_ack);
+ /* round trip time sample per acked packet (optional) */
+ void (*rtt_sample)(struct tcp_sock *tp, u32 usrtt);
+ /* call before changing ca_state (optional) */
+ void (*set_state)(struct tcp_sock *tp, u8 new_state);
+ /* call when cwnd event occurs (optional) */
+ void (*cwnd_event)(struct tcp_sock *tp, enum tcp_ca_event ev);
+ /* new value of cwnd after loss (optional) */
+ u32 (*undo_cwnd)(struct tcp_sock *tp);
+ /* hook for packet ack accounting (optional) */
+ void (*pkts_acked)(struct tcp_sock *tp, u32 num_acked);
+ /* get info for tcp_diag (optional) */
+ void (*get_info)(struct tcp_sock *tp, u32 ext, struct sk_buff *skb);
+
+ char name[TCP_CA_NAME_MAX];
+ struct module *owner;
+};
+
+extern int tcp_register_congestion_control(struct tcp_congestion_ops *type);
+extern void tcp_unregister_congestion_control(struct tcp_congestion_ops *type);
+
+extern void tcp_init_congestion_control(struct tcp_sock *tp);
+extern void tcp_cleanup_congestion_control(struct tcp_sock *tp);
+extern int tcp_set_default_congestion_control(const char *name);
+extern void tcp_get_default_congestion_control(char *name);
+extern int tcp_set_congestion_control(struct tcp_sock *tp, const char *name);
+
+extern struct tcp_congestion_ops tcp_init_congestion_ops;
+extern u32 tcp_reno_ssthresh(struct tcp_sock *tp);
+extern void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack,
+ u32 rtt, u32 in_flight, int flag);
+extern u32 tcp_reno_min_cwnd(struct tcp_sock *tp);
+extern struct tcp_congestion_ops tcp_reno;
+
+static inline void tcp_set_ca_state(struct tcp_sock *tp, u8 ca_state)
+{
+ if (tp->ca_ops->set_state)
+ tp->ca_ops->set_state(tp, ca_state);
+ tp->ca_state = ca_state;
+}
+
+static inline void tcp_ca_event(struct tcp_sock *tp, enum tcp_ca_event event)
+{
+ if (tp->ca_ops->cwnd_event)
+ tp->ca_ops->cwnd_event(tp, event);
+}
+
/* This determines how many packets are "in the network" to the best
* of our knowledge. In many cases it is conservative, but where
* detailed information is available from the receiver (via SACK
@@ -1155,91 +1214,6 @@ static __inline__ unsigned int tcp_packets_in_flight(const struct tcp_sock *tp)
return (tp->packets_out - tp->left_out + tp->retrans_out);
}
-/*
- * Which congestion algorithim is in use on the connection.
- */
-#define tcp_is_vegas(__tp) ((__tp)->adv_cong == TCP_VEGAS)
-#define tcp_is_westwood(__tp) ((__tp)->adv_cong == TCP_WESTWOOD)
-#define tcp_is_bic(__tp) ((__tp)->adv_cong == TCP_BIC)
-
-/* Recalculate snd_ssthresh, we want to set it to:
- *
- * Reno:
- * one half the current congestion window, but no
- * less than two segments
- *
- * BIC:
- * behave like Reno until low_window is reached,
- * then increase congestion window slowly
- */
-static inline __u32 tcp_recalc_ssthresh(struct tcp_sock *tp)
-{
- if (tcp_is_bic(tp)) {
- if (sysctl_tcp_bic_fast_convergence &&
- tp->snd_cwnd < tp->bictcp.last_max_cwnd)
- tp->bictcp.last_max_cwnd = (tp->snd_cwnd *
- (BICTCP_BETA_SCALE
- + sysctl_tcp_bic_beta))
- / (2 * BICTCP_BETA_SCALE);
- else
- tp->bictcp.last_max_cwnd = tp->snd_cwnd;
-
- if (tp->snd_cwnd > sysctl_tcp_bic_low_window)
- return max((tp->snd_cwnd * sysctl_tcp_bic_beta)
- / BICTCP_BETA_SCALE, 2U);
- }
-
- return max(tp->snd_cwnd >> 1U, 2U);
-}
-
-/* Stop taking Vegas samples for now. */
-#define tcp_vegas_disable(__tp) ((__tp)->vegas.doing_vegas_now = 0)
-
-static inline void tcp_vegas_enable(struct tcp_sock *tp)
-{
- /* There are several situations when we must "re-start" Vegas:
- *
- * o when a connection is established
- * o after an RTO
- * o after fast recovery
- * o when we send a packet and there is no outstanding
- * unacknowledged data (restarting an idle connection)
- *
- * In these circumstances we cannot do a Vegas calculation at the
- * end of the first RTT, because any calculation we do is using
- * stale info -- both the saved cwnd and congestion feedback are
- * stale.
- *
- * Instead we must wait until the completion of an RTT during
- * which we actually receive ACKs.
- */
-
- /* Begin taking Vegas samples next time we send something. */
- tp->vegas.doing_vegas_now = 1;
-
- /* Set the beginning of the next send window. */
- tp->vegas.beg_snd_nxt = tp->snd_nxt;
-
- tp->vegas.cntRTT = 0;
- tp->vegas.minRTT = 0x7fffffff;
-}
-
-/* Should we be taking Vegas samples right now? */
-#define tcp_vegas_enabled(__tp) ((__tp)->vegas.doing_vegas_now)
-
-extern void tcp_ca_init(struct tcp_sock *tp);
-
-static inline void tcp_set_ca_state(struct tcp_sock *tp, u8 ca_state)
-{
- if (tcp_is_vegas(tp)) {
- if (ca_state == TCP_CA_Open)
- tcp_vegas_enable(tp);
- else
- tcp_vegas_disable(tp);
- }
- tp->ca_state = ca_state;
-}
-
/* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd.
* The exception is rate halving phase, when cwnd is decreasing towards
* ssthresh.
@@ -1262,33 +1236,11 @@ static inline void tcp_sync_left_out(struct tcp_sock *tp)
tp->left_out = tp->sacked_out + tp->lost_out;
}
-extern void tcp_cwnd_application_limited(struct sock *sk);
-
-/* Congestion window validation. (RFC2861) */
-
-static inline void tcp_cwnd_validate(struct sock *sk, struct tcp_sock *tp)
-{
- __u32 packets_out = tp->packets_out;
-
- if (packets_out >= tp->snd_cwnd) {
- /* Network is feed fully. */
- tp->snd_cwnd_used = 0;
- tp->snd_cwnd_stamp = tcp_time_stamp;
- } else {
- /* Network starves. */
- if (tp->packets_out > tp->snd_cwnd_used)
- tp->snd_cwnd_used = tp->packets_out;
-
- if ((s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= tp->rto)
- tcp_cwnd_application_limited(sk);
- }
-}
-
/* Set slow start threshould and cwnd not falling to slow start */
static inline void __tcp_enter_cwr(struct tcp_sock *tp)
{
tp->undo_marker = 0;
- tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
tp->snd_cwnd = min(tp->snd_cwnd,
tcp_packets_in_flight(tp) + 1U);
tp->snd_cwnd_cnt = 0;
@@ -1316,12 +1268,6 @@ static __inline__ __u32 tcp_max_burst(const struct tcp_sock *tp)
return 3;
}
-static __inline__ int tcp_minshall_check(const struct tcp_sock *tp)
-{
- return after(tp->snd_sml,tp->snd_una) &&
- !after(tp->snd_sml, tp->snd_nxt);
-}
-
static __inline__ void tcp_minshall_update(struct tcp_sock *tp, int mss,
const struct sk_buff *skb)
{
@@ -1329,122 +1275,18 @@ static __inline__ void tcp_minshall_update(struct tcp_sock *tp, int mss,
tp->snd_sml = TCP_SKB_CB(skb)->end_seq;
}
-/* Return 0, if packet can be sent now without violation Nagle's rules:
- 1. It is full sized.
- 2. Or it contains FIN.
- 3. Or TCP_NODELAY was set.
- 4. Or TCP_CORK is not set, and all sent packets are ACKed.
- With Minshall's modification: all sent small packets are ACKed.
- */
-
-static __inline__ int
-tcp_nagle_check(const struct tcp_sock *tp, const struct sk_buff *skb,
- unsigned mss_now, int nonagle)
-{
- return (skb->len < mss_now &&
- !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) &&
- ((nonagle&TCP_NAGLE_CORK) ||
- (!nonagle &&
- tp->packets_out &&
- tcp_minshall_check(tp))));
-}
-
-extern void tcp_set_skb_tso_segs(struct sock *, struct sk_buff *);
-
-/* This checks if the data bearing packet SKB (usually sk->sk_send_head)
- * should be put on the wire right now.
- */
-static __inline__ int tcp_snd_test(struct sock *sk,
- struct sk_buff *skb,
- unsigned cur_mss, int nonagle)
-{
- struct tcp_sock *tp = tcp_sk(sk);
- int pkts = tcp_skb_pcount(skb);
-
- if (!pkts) {
- tcp_set_skb_tso_segs(sk, skb);
- pkts = tcp_skb_pcount(skb);
- }
-
- /* RFC 1122 - section 4.2.3.4
- *
- * We must queue if
- *
- * a) The right edge of this frame exceeds the window
- * b) There are packets in flight and we have a small segment
- * [SWS avoidance and Nagle algorithm]
- * (part of SWS is done on packetization)
- * Minshall version sounds: there are no _small_
- * segments in flight. (tcp_nagle_check)
- * c) We have too many packets 'in flight'
- *
- * Don't use the nagle rule for urgent data (or
- * for the final FIN -DaveM).
- *
- * Also, Nagle rule does not apply to frames, which
- * sit in the middle of queue (they have no chances
- * to get new data) and if room at tail of skb is
- * not enough to save something seriously (<32 for now).
- */
-
- /* Don't be strict about the congestion window for the
- * final FIN frame. -DaveM
- */
- return (((nonagle&TCP_NAGLE_PUSH) || tp->urg_mode
- || !tcp_nagle_check(tp, skb, cur_mss, nonagle)) &&
- (((tcp_packets_in_flight(tp) + (pkts-1)) < tp->snd_cwnd) ||
- (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) &&
- !after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd));
-}
-
static __inline__ void tcp_check_probe_timer(struct sock *sk, struct tcp_sock *tp)
{
if (!tp->packets_out && !tp->pending)
tcp_reset_xmit_timer(sk, TCP_TIME_PROBE0, tp->rto);
}
-static __inline__ int tcp_skb_is_last(const struct sock *sk,
- const struct sk_buff *skb)
-{
- return skb->next == (struct sk_buff *)&sk->sk_write_queue;
-}
-
-/* Push out any pending frames which were held back due to
- * TCP_CORK or attempt at coalescing tiny packets.
- * The socket must be locked by the caller.
- */
-static __inline__ void __tcp_push_pending_frames(struct sock *sk,
- struct tcp_sock *tp,
- unsigned cur_mss,
- int nonagle)
-{
- struct sk_buff *skb = sk->sk_send_head;
-
- if (skb) {
- if (!tcp_skb_is_last(sk, skb))
- nonagle = TCP_NAGLE_PUSH;
- if (!tcp_snd_test(sk, skb, cur_mss, nonagle) ||
- tcp_write_xmit(sk, nonagle))
- tcp_check_probe_timer(sk, tp);
- }
- tcp_cwnd_validate(sk, tp);
-}
-
static __inline__ void tcp_push_pending_frames(struct sock *sk,
struct tcp_sock *tp)
{
__tcp_push_pending_frames(sk, tp, tcp_current_mss(sk, 1), tp->nonagle);
}
-static __inline__ int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
-{
- struct sk_buff *skb = sk->sk_send_head;
-
- return (skb &&
- tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
- tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle));
-}
-
static __inline__ void tcp_init_wl(struct tcp_sock *tp, u32 ack, u32 seq)
{
tp->snd_wl1 = seq;
@@ -1876,52 +1718,4 @@ struct tcp_iter_state {
extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
-/* TCP Westwood functions and constants */
-
-#define TCP_WESTWOOD_INIT_RTT (20*HZ) /* maybe too conservative?! */
-#define TCP_WESTWOOD_RTT_MIN (HZ/20) /* 50ms */
-
-static inline void tcp_westwood_update_rtt(struct tcp_sock *tp, __u32 rtt_seq)
-{
- if (tcp_is_westwood(tp))
- tp->westwood.rtt = rtt_seq;
-}
-
-static inline __u32 __tcp_westwood_bw_rttmin(const struct tcp_sock *tp)
-{
- return max((tp->westwood.bw_est) * (tp->westwood.rtt_min) /
- (__u32) (tp->mss_cache_std),
- 2U);
-}
-
-static inline __u32 tcp_westwood_bw_rttmin(const struct tcp_sock *tp)
-{
- return tcp_is_westwood(tp) ? __tcp_westwood_bw_rttmin(tp) : 0;
-}
-
-static inline int tcp_westwood_ssthresh(struct tcp_sock *tp)
-{
- __u32 ssthresh = 0;
-
- if (tcp_is_westwood(tp)) {
- ssthresh = __tcp_westwood_bw_rttmin(tp);
- if (ssthresh)
- tp->snd_ssthresh = ssthresh;
- }
-
- return (ssthresh != 0);
-}
-
-static inline int tcp_westwood_cwnd(struct tcp_sock *tp)
-{
- __u32 cwnd = 0;
-
- if (tcp_is_westwood(tp)) {
- cwnd = __tcp_westwood_bw_rttmin(tp);
- if (cwnd)
- tp->snd_cwnd = cwnd;
- }
-
- return (cwnd != 0);
-}
#endif /* _TCP_H */
diff --git a/include/net/x25device.h b/include/net/x25device.h
index cf36a20ea3c5..d45ae883bd1d 100644
--- a/include/net/x25device.h
+++ b/include/net/x25device.h
@@ -5,8 +5,7 @@
#include <linux/if_packet.h>
#include <linux/skbuff.h>
-static inline unsigned short x25_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static inline __be16 x25_type_trans(struct sk_buff *skb, struct net_device *dev)
{
skb->mac.raw = skb->data;
skb->input_dev = skb->dev = dev;
diff --git a/include/pcmcia/ciscode.h b/include/pcmcia/ciscode.h
index 2000b43ece91..da19c297dd65 100644
--- a/include/pcmcia/ciscode.h
+++ b/include/pcmcia/ciscode.h
@@ -112,6 +112,8 @@
#define MANFID_TDK 0x0105
#define PRODID_TDK_CF010 0x0900
+#define PRODID_TDK_NP9610 0x0d0a
+#define PRODID_TDK_MN3200 0x0e0a
#define PRODID_TDK_GN3410 0x4815
#define MANFID_TOSHIBA 0x0098
diff --git a/include/pcmcia/cs.h b/include/pcmcia/cs.h
index 8d8643adc786..2cab39f49eb2 100644
--- a/include/pcmcia/cs.h
+++ b/include/pcmcia/cs.h
@@ -68,21 +68,9 @@ typedef struct adjust_t {
#define RES_ALLOCATED 0x20
#define RES_REMOVED 0x40
-typedef struct servinfo_t {
- char Signature[2];
- u_int Count;
- u_int Revision;
- u_int CSLevel;
- char *VendorString;
-} servinfo_t;
-
typedef struct event_callback_args_t {
- client_handle_t client_handle;
- void *info;
- void *mtdrequest;
- void *buffer;
- void *misc;
- void *client_data;
+ struct pcmcia_device *client_handle;
+ void *client_data;
} event_callback_args_t;
/* for GetConfigurationInfo */
@@ -393,31 +381,29 @@ enum service {
struct pcmcia_socket;
-int pcmcia_access_configuration_register(client_handle_t handle, conf_reg_t *reg);
-int pcmcia_deregister_client(client_handle_t handle);
-int pcmcia_get_configuration_info(client_handle_t handle, config_info_t *config);
-int pcmcia_get_card_services_info(servinfo_t *info);
+int pcmcia_access_configuration_register(struct pcmcia_device *p_dev, conf_reg_t *reg);
+int pcmcia_deregister_client(struct pcmcia_device *p_dev);
+int pcmcia_get_configuration_info(struct pcmcia_device *p_dev, config_info_t *config);
int pcmcia_get_first_window(window_handle_t *win, win_req_t *req);
int pcmcia_get_next_window(window_handle_t *win, win_req_t *req);
-int pcmcia_get_status(client_handle_t handle, cs_status_t *status);
+int pcmcia_get_status(struct pcmcia_device *p_dev, cs_status_t *status);
int pcmcia_get_mem_page(window_handle_t win, memreq_t *req);
int pcmcia_map_mem_page(window_handle_t win, memreq_t *req);
-int pcmcia_modify_configuration(client_handle_t handle, modconf_t *mod);
+int pcmcia_modify_configuration(struct pcmcia_device *p_dev, modconf_t *mod);
int pcmcia_register_client(client_handle_t *handle, client_reg_t *req);
-int pcmcia_release_configuration(client_handle_t handle);
-int pcmcia_release_io(client_handle_t handle, io_req_t *req);
-int pcmcia_release_irq(client_handle_t handle, irq_req_t *req);
+int pcmcia_release_configuration(struct pcmcia_device *p_dev);
+int pcmcia_release_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_release_irq(struct pcmcia_device *p_dev, irq_req_t *req);
int pcmcia_release_window(window_handle_t win);
-int pcmcia_request_configuration(client_handle_t handle, config_req_t *req);
-int pcmcia_request_io(client_handle_t handle, io_req_t *req);
-int pcmcia_request_irq(client_handle_t handle, irq_req_t *req);
-int pcmcia_request_window(client_handle_t *handle, win_req_t *req, window_handle_t *wh);
-int pcmcia_reset_card(client_handle_t handle, client_req_t *req);
+int pcmcia_request_configuration(struct pcmcia_device *p_dev, config_req_t *req);
+int pcmcia_request_io(struct pcmcia_device *p_dev, io_req_t *req);
+int pcmcia_request_irq(struct pcmcia_device *p_dev, irq_req_t *req);
+int pcmcia_request_window(struct pcmcia_device **p_dev, win_req_t *req, window_handle_t *wh);
+int pcmcia_reset_card(struct pcmcia_device *p_dev, client_req_t *req);
int pcmcia_suspend_card(struct pcmcia_socket *skt);
int pcmcia_resume_card(struct pcmcia_socket *skt);
int pcmcia_eject_card(struct pcmcia_socket *skt);
int pcmcia_insert_card(struct pcmcia_socket *skt);
-int pcmcia_report_error(client_handle_t handle, error_info_t *err);
struct pcmcia_socket * pcmcia_get_socket(struct pcmcia_socket *skt);
void pcmcia_put_socket(struct pcmcia_socket *skt);
diff --git a/include/pcmcia/cs_types.h b/include/pcmcia/cs_types.h
index 7881d40aac8d..c1d1629fcd27 100644
--- a/include/pcmcia/cs_types.h
+++ b/include/pcmcia/cs_types.h
@@ -34,8 +34,8 @@ typedef u_int event_t;
typedef u_char cisdata_t;
typedef u_short page_t;
-struct client_t;
-typedef struct client_t *client_handle_t;
+struct pcmcia_device;
+typedef struct pcmcia_device *client_handle_t;
struct window_t;
typedef struct window_t *window_handle_t;
diff --git a/include/pcmcia/device_id.h b/include/pcmcia/device_id.h
new file mode 100644
index 000000000000..346d81ece287
--- /dev/null
+++ b/include/pcmcia/device_id.h
@@ -0,0 +1,249 @@
+/*
+ * Copyright (2003-2004) Dominik Brodowski <linux@brodo.de>
+ * David Woodhouse
+ *
+ * License: GPL v2
+ */
+
+#define PCMCIA_DEVICE_MANF_CARD(manf, card) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+ PCMCIA_DEV_ID_MATCH_CARD_ID, \
+ .manf_id = (manf), \
+ .card_id = (card), }
+
+#define PCMCIA_DEVICE_FUNC_ID(func) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FUNC_ID, \
+ .func_id = (func), }
+
+#define PCMCIA_DEVICE_PROD_ID1(v1, vh1) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1, \
+ .prod_id = { (v1), NULL, NULL, NULL }, \
+ .prod_id_hash = { (vh1), 0, 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID2(v2, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+ .prod_id = { NULL, (v2), NULL, NULL }, \
+ .prod_id_hash = { 0, (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID12(v1, v2, vh1, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID13(v1, v3, vh1, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+ .prod_id = { (v1), NULL, (v3), NULL }, \
+ .prod_id_hash = { (vh1), 0, (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID14(v1, v4, vh1, vh4) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+ .prod_id = { (v1), NULL, NULL, (v4) }, \
+ .prod_id_hash = { (vh1), 0, 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID123(v1, v2, v3, vh1, vh2, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+ .prod_id = { (v1), (v2), (v3), NULL },\
+ .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, }
+
+#define PCMCIA_DEVICE_PROD_ID124(v1, v2, v4, vh1, vh2, vh4) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+ .prod_id = { (v1), (v2), NULL, (v4) }, \
+ .prod_id_hash = { (vh1), (vh2), 0, (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID134(v1, v3, v4, vh1, vh3, vh4) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+ .prod_id = { (v1), NULL, (v3), (v4) }, \
+ .prod_id_hash = { (vh1), 0, (vh3), (vh4) }, }
+
+#define PCMCIA_DEVICE_PROD_ID1234(v1, v2, v3, v4, vh1, vh2, vh3, vh4) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID4, \
+ .prod_id = { (v1), (v2), (v3), (v4) }, \
+ .prod_id_hash = { (vh1), (vh2), (vh3), (vh4) }, }
+
+
+/* multi-function devices */
+
+#define PCMCIA_MFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+ PCMCIA_DEV_ID_MATCH_CARD_ID| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .manf_id = (manf), \
+ .card_id = (card), \
+ .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { (v1), NULL, NULL, NULL }, \
+ .prod_id_hash = { (vh1), 0, 0, 0 }, \
+ .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { NULL, (v2), NULL, NULL }, \
+ .prod_id_hash = { 0, (vh2), 0, 0 }, \
+ .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+ .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { (v1), NULL, (v3), NULL }, \
+ .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+ .function = (mfc), }
+
+#define PCMCIA_MFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { (v1), (v2), (v3), NULL },\
+ .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+ .function = (mfc), }
+
+/* pseudo multi-function devices */
+
+#define PCMCIA_PFC_DEVICE_MANF_CARD(mfc, manf, card) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_MANF_ID| \
+ PCMCIA_DEV_ID_MATCH_CARD_ID| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .manf_id = (manf), \
+ .card_id = (card), \
+ .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID1(mfc, v1, vh1) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { (v1), NULL, NULL, NULL }, \
+ .prod_id_hash = { (vh1), 0, 0, 0 }, \
+ .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID2(mfc, v2, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { NULL, (v2), NULL, NULL }, \
+ .prod_id_hash = { 0, (vh2), 0, 0 }, \
+ .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID12(mfc, v1, v2, vh1, vh2) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+ .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID13(mfc, v1, v3, vh1, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { (v1), NULL, (v3), NULL }, \
+ .prod_id_hash = { (vh1), 0, (vh3), 0 }, \
+ .device_no = (mfc), }
+
+#define PCMCIA_PFC_DEVICE_PROD_ID123(mfc, v1, v2, v3, vh1, vh2, vh3) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { (v1), (v2), (v3), NULL },\
+ .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+ .device_no = (mfc), }
+
+/* cards needing a CIS override */
+
+#define PCMCIA_DEVICE_CIS_MANF_CARD(manf, card, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_MANF_ID| \
+ PCMCIA_DEV_ID_MATCH_CARD_ID, \
+ .manf_id = (manf), \
+ .card_id = (card), \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID12(v1, v2, vh1, vh2, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_DEVICE_CIS_PROD_ID123(v1, v2, v3, vh1, vh2, vh3, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID3, \
+ .prod_id = { (v1), (v2), (v3), NULL },\
+ .prod_id_hash = { (vh1), (vh2), (vh3), 0 }, \
+ .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_CIS_PROD_ID2(v2, vh2, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2, \
+ .prod_id = { NULL, (v2), NULL, NULL }, \
+ .prod_id_hash = { 0, (vh2), 0, 0 }, \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_PFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_DEVICE_NO, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 },\
+ .device_no = (mfc), \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_MANF_CARD(mfc, manf, card, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_MANF_ID| \
+ PCMCIA_DEV_ID_MATCH_CARD_ID| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .manf_id = (manf), \
+ .card_id = (card), \
+ .function = (mfc), \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID12(mfc, v1, v2, vh1, vh2, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID1| \
+ PCMCIA_DEV_ID_MATCH_PROD_ID2| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { (v1), (v2), NULL, NULL }, \
+ .prod_id_hash = { (vh1), (vh2), 0, 0 }, \
+ .function = (mfc), \
+ .cisfile = (_cisfile)}
+
+#define PCMCIA_MFC_DEVICE_CIS_PROD_ID4(mfc, v4, vh4, _cisfile) { \
+ .match_flags = PCMCIA_DEV_ID_MATCH_FAKE_CIS | \
+ PCMCIA_DEV_ID_MATCH_PROD_ID4| \
+ PCMCIA_DEV_ID_MATCH_FUNCTION, \
+ .prod_id = { NULL, NULL, NULL, (v4) }, \
+ .prod_id_hash = { 0, 0, 0, (vh4) }, \
+ .function = (mfc), \
+ .cisfile = (_cisfile)}
+
+
+#define PCMCIA_DEVICE_NULL { .match_flags = 0, }
diff --git a/include/pcmcia/ds.h b/include/pcmcia/ds.h
index 312fd958c901..b707a603351b 100644
--- a/include/pcmcia/ds.h
+++ b/include/pcmcia/ds.h
@@ -16,8 +16,13 @@
#ifndef _LINUX_DS_H
#define _LINUX_DS_H
+#ifdef __KERNEL__
+#include <linux/mod_devicetable.h>
+#endif
+
#include <pcmcia/bulkmem.h>
#include <pcmcia/cs_types.h>
+#include <pcmcia/device_id.h>
typedef struct tuple_parse_t {
tuple_t tuple;
@@ -47,7 +52,6 @@ typedef struct mtd_info_t {
} mtd_info_t;
typedef union ds_ioctl_arg_t {
- servinfo_t servinfo;
adjust_t adjust;
config_info_t config;
tuple_t tuple;
@@ -63,7 +67,6 @@ typedef union ds_ioctl_arg_t {
cisdump_t cisdump;
} ds_ioctl_arg_t;
-#define DS_GET_CARD_SERVICES_INFO _IOR ('d', 1, servinfo_t)
#define DS_ADJUST_RESOURCE_INFO _IOWR('d', 2, adjust_t)
#define DS_GET_CONFIGURATION_INFO _IOWR('d', 3, config_info_t)
#define DS_GET_FIRST_TUPLE _IOWR('d', 4, tuple_t)
@@ -129,12 +132,13 @@ typedef struct dev_link_t {
struct pcmcia_socket;
-extern struct bus_type pcmcia_bus_type;
-
struct pcmcia_driver {
dev_link_t *(*attach)(void);
+ int (*event) (event_t event, int priority,
+ event_callback_args_t *);
void (*detach)(dev_link_t *);
struct module *owner;
+ struct pcmcia_device_id *id_table;
struct device_driver drv;
};
@@ -158,22 +162,16 @@ struct pcmcia_device {
/* deprecated, a cleaned up version will be moved into this
struct soon */
dev_link_t *instance;
- struct client_t {
- u_short client_magic;
- struct pcmcia_socket *Socket;
- u_char Function;
- u_int state;
- event_t EventMask;
- int (*event_handler) (event_t event, int priority,
- event_callback_args_t *);
- event_callback_args_t event_callback_args;
- } client;
+ event_callback_args_t event_callback_args;
+ u_int state;
/* information about this device */
u8 has_manf_id:1;
u8 has_card_id:1;
u8 has_func_id:1;
- u8 reserved:5;
+
+ u8 allow_func_id_match:1;
+ u8 reserved:4;
u8 func_id;
u16 manf_id;
@@ -190,8 +188,8 @@ struct pcmcia_device {
#define to_pcmcia_dev(n) container_of(n, struct pcmcia_device, dev)
#define to_pcmcia_drv(n) container_of(n, struct pcmcia_driver, drv)
-#define handle_to_pdev(handle) container_of(handle, struct pcmcia_device, client);
-#define handle_to_dev(handle) ((container_of(handle, struct pcmcia_device, client))->dev)
+#define handle_to_pdev(handle) (handle)
+#define handle_to_dev(handle) (handle->dev)
/* error reporting */
void cs_error(client_handle_t handle, int func, int ret);
diff --git a/include/pcmcia/ss.h b/include/pcmcia/ss.h
index 67b867f31fe4..0f7aacc33fe9 100644
--- a/include/pcmcia/ss.h
+++ b/include/pcmcia/ss.h
@@ -15,10 +15,12 @@
#ifndef _LINUX_SS_H
#define _LINUX_SS_H
+#include <linux/config.h>
+#include <linux/device.h>
+
#include <pcmcia/cs_types.h>
#include <pcmcia/cs.h>
#include <pcmcia/bulkmem.h>
-#include <linux/device.h>
/* Definitions for card status flags for GetStatus */
#define SS_WRPROT 0x0001
@@ -171,7 +173,7 @@ typedef struct window_t {
struct config_t;
struct pcmcia_callback;
-
+struct user_info_t;
struct pcmcia_socket {
struct module *owner;
@@ -216,8 +218,9 @@ struct pcmcia_socket {
/* is set to one if resource setup is done using adjust_resource_info() */
u8 resource_setup_old:1;
+ u8 resource_setup_new:1;
- u8 reserved:6;
+ u8 reserved:5;
/* socket operations */
struct pccard_operations * ops;
@@ -241,9 +244,32 @@ struct pcmcia_socket {
unsigned int thread_events;
/* pcmcia (16-bit) */
- struct pcmcia_bus_socket *pcmcia;
struct pcmcia_callback *callback;
+#if defined(CONFIG_PCMCIA) || defined(CONFIG_PCMCIA_MODULE)
+ struct list_head devices_list; /* PCMCIA devices */
+ u8 device_count; /* the number of devices, used
+ * only internally and subject
+ * to incorrectness and change */
+
+ struct {
+ u8 present:1, /* PCMCIA card is present in socket */
+ busy:1, /* "master" ioctl is used */
+ dead:1, /* pcmcia module is being unloaded */
+ device_add_pending:1, /* a pseudo-multifunction-device
+ * add event is pending */
+ reserved:4;
+ } pcmcia_state;
+
+ struct work_struct device_add; /* for adding further pseudo-multifunction
+ * devices */
+
+#ifdef CONFIG_PCMCIA_IOCTL
+ struct user_info_t *user;
+ wait_queue_head_t queue;
+#endif
+#endif
+
/* cardbus (32-bit) */
#ifdef CONFIG_CARDBUS
struct resource * cb_cis_res;
diff --git a/include/pcmcia/version.h b/include/pcmcia/version.h
index eb88263fc8d5..5ad9c5e198b6 100644
--- a/include/pcmcia/version.h
+++ b/include/pcmcia/version.h
@@ -1,4 +1,3 @@
/* version.h 1.94 2000/10/03 17:55:48 (David Hinds) */
-#define CS_RELEASE "3.1.22"
-#define CS_RELEASE_CODE 0x3116
+/* This file will be removed, please don't include it */
diff --git a/include/scsi/sg_request.h b/include/scsi/sg_request.h
new file mode 100644
index 000000000000..57ff525bdd3b
--- /dev/null
+++ b/include/scsi/sg_request.h
@@ -0,0 +1,26 @@
+typedef struct scsi_request Scsi_Request;
+
+static Scsi_Request *dummy_cmdp; /* only used for sizeof */
+
+typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
+ unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
+ unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+ unsigned bufflen; /* Size of (aggregate) data buffer */
+ unsigned b_malloc_len; /* actual len malloc'ed in buffer */
+ void *buffer; /* Data buffer or scatter list (k_use_sg>0) */
+ char dio_in_use; /* 0->indirect IO (or mmap), 1->dio */
+ unsigned char cmd_opcode; /* first byte of command */
+} Sg_scatter_hold;
+
+typedef struct sg_request { /* SG_MAX_QUEUE requests outstanding per file */
+ Scsi_Request *my_cmdp; /* != 0 when request with lower levels */
+ struct sg_request *nextrp; /* NULL -> tail request (slist) */
+ struct sg_fd *parentfp; /* NULL -> not in use */
+ Sg_scatter_hold data; /* hold buffer, perhaps scatter list */
+ sg_io_hdr_t header; /* scsi command+info, see <scsi/sg.h> */
+ unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)];
+ char res_used; /* 1 -> using reserve buffer, 0 -> not ... */
+ char orphan; /* 1 -> drop on sight, 0 -> normal */
+ char sg_io_owned; /* 1 -> packet belongs to SG_IO */
+ volatile char done; /* 0->before bh, 1->before read, 2->read */
+} Sg_request;
diff --git a/init/Kconfig b/init/Kconfig
index b1091d7542ce..75755ef50c89 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -174,7 +174,7 @@ config AUDIT
config AUDITSYSCALL
bool "Enable system-call auditing support"
- depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML)
+ depends on AUDIT && (X86 || PPC || PPC64 || ARCH_S390 || IA64 || UML || SPARC64)
default y if SECURITY_SELINUX
help
Enable low-overhead system-call auditing infrastructure that
diff --git a/init/do_mounts.c b/init/do_mounts.c
index b7570c074d0f..1b02be734ccc 100644
--- a/init/do_mounts.c
+++ b/init/do_mounts.c
@@ -7,6 +7,7 @@
#include <linux/root_dev.h>
#include <linux/security.h>
#include <linux/delay.h>
+#include <linux/mount.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
diff --git a/init/do_mounts.h b/init/do_mounts.h
index de92bee4f35e..e0a7ac9649e1 100644
--- a/init/do_mounts.h
+++ b/init/do_mounts.h
@@ -9,7 +9,6 @@
#include <linux/major.h>
#include <linux/root_dev.h>
-dev_t name_to_dev_t(char *name);
void change_floppy(char *fmt, ...);
void mount_block_root(char *name, int flags);
void mount_root(void);
diff --git a/init/do_mounts_initrd.c b/init/do_mounts_initrd.c
index 07e7d31f2d0b..a05cabd0fd10 100644
--- a/init/do_mounts_initrd.c
+++ b/init/do_mounts_initrd.c
@@ -41,7 +41,7 @@ static int __init do_linuxrc(void * shell)
static void __init handle_initrd(void)
{
int error;
- int i, pid;
+ int pid;
real_root_dev = new_encode_dev(ROOT_DEV);
create_dev("/dev/root.old", Root_RAM0, NULL);
@@ -58,7 +58,7 @@ static void __init handle_initrd(void)
pid = kernel_thread(do_linuxrc, "/linuxrc", SIGCHLD);
if (pid > 0) {
- while (pid != sys_wait4(-1, &i, 0, NULL))
+ while (pid != sys_wait4(-1, NULL, 0, NULL))
yield();
}
@@ -86,7 +86,10 @@ static void __init handle_initrd(void)
printk("okay\n");
else {
int fd = sys_open("/dev/root.old", O_RDWR, 0);
- printk("failed\n");
+ if (error == -ENOENT)
+ printk("/initrd does not exist. Ignored.\n");
+ else
+ printk("failed\n");
printk(KERN_NOTICE "Unmounting old root\n");
sys_umount("/old", MNT_DETACH);
printk(KERN_NOTICE "Trying to free ramdisk memory ... ");
diff --git a/init/main.c b/init/main.c
index d324801729ba..b5e421e39ede 100644
--- a/init/main.c
+++ b/init/main.c
@@ -383,6 +383,13 @@ static void noinline rest_init(void)
numa_default_policy();
unlock_kernel();
preempt_enable_no_resched();
+
+ /*
+ * The boot idle thread must execute schedule()
+ * at least one to get things moving:
+ */
+ schedule();
+
cpu_idle();
}
diff --git a/ipc/compat.c b/ipc/compat.c
index 70e4e4e10fd1..3881d564c668 100644
--- a/ipc/compat.c
+++ b/ipc/compat.c
@@ -572,6 +572,7 @@ static inline int put_compat_shminfo(struct shminfo64 *smi,
err |= __put_user(smi->shmmni, &up->shmmni);
err |= __put_user(smi->shmseg, &up->shmseg);
err |= __put_user(smi->shmall, &up->shmall);
+ return err;
}
static inline int put_compat_shm_info(struct shm_info __user *ip,
diff --git a/ipc/util.h b/ipc/util.h
index 07d689452363..44348ca5a707 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -67,7 +67,7 @@ int ipc_checkid(struct ipc_ids* ids, struct kern_ipc_perm* ipcp, int uid);
void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out);
void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out);
-#if defined(__ia64__) || defined(__x86_64__) || defined(__hppa__)
+#if defined(__ia64__) || defined(__x86_64__) || defined(__hppa__) || defined(__XTENSA__)
/* On IA-64, we always use the "64-bit version" of the IPC structures. */
# define ipc_parse_version(cmd) IPC_64
#else
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
new file mode 100644
index 000000000000..0b46a5dff4c0
--- /dev/null
+++ b/kernel/Kconfig.preempt
@@ -0,0 +1,65 @@
+
+choice
+ prompt "Preemption Model"
+ default PREEMPT_NONE
+
+config PREEMPT_NONE
+ bool "No Forced Preemption (Server)"
+ help
+ This is the traditional Linux preemption model, geared towards
+ throughput. It will still provide good latencies most of the
+ time, but there are no guarantees and occasional longer delays
+ are possible.
+
+ Select this option if you are building a kernel for a server or
+ scientific/computation system, or if you want to maximize the
+ raw processing power of the kernel, irrespective of scheduling
+ latencies.
+
+config PREEMPT_VOLUNTARY
+ bool "Voluntary Kernel Preemption (Desktop)"
+ help
+ This option reduces the latency of the kernel by adding more
+ "explicit preemption points" to the kernel code. These new
+ preemption points have been selected to reduce the maximum
+ latency of rescheduling, providing faster application reactions,
+ at the cost of slighly lower throughput.
+
+ This allows reaction to interactive events by allowing a
+ low priority process to voluntarily preempt itself even if it
+ is in kernel mode executing a system call. This allows
+ applications to run more 'smoothly' even when the system is
+ under load.
+
+ Select this if you are building a kernel for a desktop system.
+
+config PREEMPT
+ bool "Preemptible Kernel (Low-Latency Desktop)"
+ help
+ This option reduces the latency of the kernel by making
+ all kernel code (that is not executing in a critical section)
+ preemptible. This allows reaction to interactive events by
+ permitting a low priority process to be preempted involuntarily
+ even if it is in kernel mode executing a system call and would
+ otherwise not be about to reach a natural preemption point.
+ This allows applications to run more 'smoothly' even when the
+ system is under load, at the cost of slighly lower throughput
+ and a slight runtime overhead to kernel code.
+
+ Select this if you are building a kernel for a desktop or
+ embedded system with latency requirements in the milliseconds
+ range.
+
+endchoice
+
+config PREEMPT_BKL
+ bool "Preempt The Big Kernel Lock"
+ depends on SMP || PREEMPT
+ default y
+ help
+ This option reduces the latency of the kernel by making the
+ big kernel lock preemptible.
+
+ Say Y here if you are building a kernel for a desktop system.
+ Say N if you are unsure.
+
diff --git a/kernel/Makefile b/kernel/Makefile
index b01d26fe8db7..cb05cd05d237 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -17,6 +17,7 @@ obj-$(CONFIG_MODULES) += module.o
obj-$(CONFIG_KALLSYMS) += kallsyms.o
obj-$(CONFIG_PM) += power/
obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
+obj-$(CONFIG_KEXEC) += kexec.o
obj-$(CONFIG_COMPAT) += compat.o
obj-$(CONFIG_CPUSETS) += cpuset.o
obj-$(CONFIG_IKCONFIG) += configs.o
@@ -27,6 +28,7 @@ obj-$(CONFIG_AUDITSYSCALL) += auditsc.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
+obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
obj-$(CONFIG_SECCOMP) += seccomp.o
ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 628f4ccda127..53d8263ae12e 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -63,19 +63,15 @@ static int take_cpu_down(void *unused)
{
int err;
- /* Take offline: makes arch_cpu_down somewhat easier. */
- cpu_clear(smp_processor_id(), cpu_online_map);
-
/* Ensure this CPU doesn't handle any more interrupts. */
err = __cpu_disable();
if (err < 0)
- cpu_set(smp_processor_id(), cpu_online_map);
- else
- /* Force idle task to run as soon as we yield: it should
- immediately notice cpu is offline and die quickly. */
- sched_idle_next();
+ return err;
- return err;
+ /* Force idle task to run as soon as we yield: it should
+ immediately notice cpu is offline and die quickly. */
+ sched_idle_next();
+ return 0;
}
int cpu_down(unsigned int cpu)
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 79dd929f4084..984c0bf3807f 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -595,10 +595,62 @@ static int validate_change(const struct cpuset *cur, const struct cpuset *trial)
return 0;
}
+/*
+ * For a given cpuset cur, partition the system as follows
+ * a. All cpus in the parent cpuset's cpus_allowed that are not part of any
+ * exclusive child cpusets
+ * b. All cpus in the current cpuset's cpus_allowed that are not part of any
+ * exclusive child cpusets
+ * Build these two partitions by calling partition_sched_domains
+ *
+ * Call with cpuset_sem held. May nest a call to the
+ * lock_cpu_hotplug()/unlock_cpu_hotplug() pair.
+ */
+static void update_cpu_domains(struct cpuset *cur)
+{
+ struct cpuset *c, *par = cur->parent;
+ cpumask_t pspan, cspan;
+
+ if (par == NULL || cpus_empty(cur->cpus_allowed))
+ return;
+
+ /*
+ * Get all cpus from parent's cpus_allowed not part of exclusive
+ * children
+ */
+ pspan = par->cpus_allowed;
+ list_for_each_entry(c, &par->children, sibling) {
+ if (is_cpu_exclusive(c))
+ cpus_andnot(pspan, pspan, c->cpus_allowed);
+ }
+ if (is_removed(cur) || !is_cpu_exclusive(cur)) {
+ cpus_or(pspan, pspan, cur->cpus_allowed);
+ if (cpus_equal(pspan, cur->cpus_allowed))
+ return;
+ cspan = CPU_MASK_NONE;
+ } else {
+ if (cpus_empty(pspan))
+ return;
+ cspan = cur->cpus_allowed;
+ /*
+ * Get all cpus from current cpuset's cpus_allowed not part
+ * of exclusive children
+ */
+ list_for_each_entry(c, &cur->children, sibling) {
+ if (is_cpu_exclusive(c))
+ cpus_andnot(cspan, cspan, c->cpus_allowed);
+ }
+ }
+
+ lock_cpu_hotplug();
+ partition_sched_domains(&pspan, &cspan);
+ unlock_cpu_hotplug();
+}
+
static int update_cpumask(struct cpuset *cs, char *buf)
{
struct cpuset trialcs;
- int retval;
+ int retval, cpus_unchanged;
trialcs = *cs;
retval = cpulist_parse(buf, trialcs.cpus_allowed);
@@ -608,9 +660,13 @@ static int update_cpumask(struct cpuset *cs, char *buf)
if (cpus_empty(trialcs.cpus_allowed))
return -ENOSPC;
retval = validate_change(cs, &trialcs);
- if (retval == 0)
- cs->cpus_allowed = trialcs.cpus_allowed;
- return retval;
+ if (retval < 0)
+ return retval;
+ cpus_unchanged = cpus_equal(cs->cpus_allowed, trialcs.cpus_allowed);
+ cs->cpus_allowed = trialcs.cpus_allowed;
+ if (is_cpu_exclusive(cs) && !cpus_unchanged)
+ update_cpu_domains(cs);
+ return 0;
}
static int update_nodemask(struct cpuset *cs, char *buf)
@@ -646,7 +702,7 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
{
int turning_on;
struct cpuset trialcs;
- int err;
+ int err, cpu_exclusive_changed;
turning_on = (simple_strtoul(buf, NULL, 10) != 0);
@@ -657,13 +713,18 @@ static int update_flag(cpuset_flagbits_t bit, struct cpuset *cs, char *buf)
clear_bit(bit, &trialcs.flags);
err = validate_change(cs, &trialcs);
- if (err == 0) {
- if (turning_on)
- set_bit(bit, &cs->flags);
- else
- clear_bit(bit, &cs->flags);
- }
- return err;
+ if (err < 0)
+ return err;
+ cpu_exclusive_changed =
+ (is_cpu_exclusive(cs) != is_cpu_exclusive(&trialcs));
+ if (turning_on)
+ set_bit(bit, &cs->flags);
+ else
+ clear_bit(bit, &cs->flags);
+
+ if (cpu_exclusive_changed)
+ update_cpu_domains(cs);
+ return 0;
}
static int attach_task(struct cpuset *cs, char *buf)
@@ -1309,12 +1370,14 @@ static int cpuset_rmdir(struct inode *unused_dir, struct dentry *dentry)
up(&cpuset_sem);
return -EBUSY;
}
- spin_lock(&cs->dentry->d_lock);
parent = cs->parent;
set_bit(CS_REMOVED, &cs->flags);
+ if (is_cpu_exclusive(cs))
+ update_cpu_domains(cs);
list_del(&cs->sibling); /* delete my sibling from parent->children */
if (list_empty(&parent->children))
check_for_release(parent);
+ spin_lock(&cs->dentry->d_lock);
d = dget(cs->dentry);
cs->dentry = NULL;
spin_unlock(&d->d_lock);
diff --git a/kernel/crash_dump.c b/kernel/crash_dump.c
new file mode 100644
index 000000000000..459ba49e376a
--- /dev/null
+++ b/kernel/crash_dump.c
@@ -0,0 +1,52 @@
+/*
+ * kernel/crash_dump.c - Memory preserving reboot related code.
+ *
+ * Created by: Hariprasad Nellitheertha (hari@in.ibm.com)
+ * Copyright (C) IBM Corporation, 2004. All rights reserved
+ */
+
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/bootmem.h>
+#include <linux/highmem.h>
+#include <linux/crash_dump.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+/* Stores the physical address of elf header of crash image. */
+unsigned long long elfcorehdr_addr = ELFCORE_ADDR_MAX;
+
+/*
+ * Copy a page from "oldmem". For this page, there is no pte mapped
+ * in the current kernel. We stitch up a pte, similar to kmap_atomic.
+ */
+ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
+ size_t csize, unsigned long offset, int userbuf)
+{
+ void *page, *vaddr;
+
+ if (!csize)
+ return 0;
+
+ page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+
+ vaddr = kmap_atomic_pfn(pfn, KM_PTE0);
+ copy_page(page, vaddr);
+ kunmap_atomic(vaddr, KM_PTE0);
+
+ if (userbuf) {
+ if (copy_to_user(buf, (page + offset), csize)) {
+ kfree(page);
+ return -EFAULT;
+ }
+ } else {
+ memcpy(buf, (page + offset), csize);
+ }
+
+ kfree(page);
+ return csize;
+}
diff --git a/kernel/exit.c b/kernel/exit.c
index 3ebcd60a19c6..9d1b10ed0135 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -784,6 +784,8 @@ fastcall NORET_TYPE void do_exit(long code)
profile_task_exit(tsk);
+ WARN_ON(atomic_read(&tsk->fs_excl));
+
if (unlikely(in_interrupt()))
panic("Aiee, killing interrupt handler!");
if (unlikely(!tsk->pid))
diff --git a/kernel/fork.c b/kernel/fork.c
index a28d11e10877..b65187f0c74e 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -208,8 +208,10 @@ static inline int dup_mmap(struct mm_struct * mm, struct mm_struct * oldmm)
struct file *file;
if (mpnt->vm_flags & VM_DONTCOPY) {
+ long pages = vma_pages(mpnt);
+ mm->total_vm -= pages;
__vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file,
- -vma_pages(mpnt));
+ -pages);
continue;
}
charge = 0;
@@ -1003,9 +1005,6 @@ static task_t *copy_process(unsigned long clone_flags,
p->pdeath_signal = 0;
p->exit_state = 0;
- /* Perform scheduler related setup */
- sched_fork(p);
-
/*
* Ok, make it visible to the rest of the system.
* We dont wake it up yet.
@@ -1014,18 +1013,24 @@ static task_t *copy_process(unsigned long clone_flags,
INIT_LIST_HEAD(&p->ptrace_children);
INIT_LIST_HEAD(&p->ptrace_list);
+ /* Perform scheduler related setup. Assign this task to a CPU. */
+ sched_fork(p, clone_flags);
+
/* Need tasklist lock for parent etc handling! */
write_lock_irq(&tasklist_lock);
/*
- * The task hasn't been attached yet, so cpus_allowed mask cannot
- * have changed. The cpus_allowed mask of the parent may have
- * changed after it was copied first time, and it may then move to
- * another CPU - so we re-copy it here and set the child's CPU to
- * the parent's CPU. This avoids alot of nasty races.
+ * The task hasn't been attached yet, so its cpus_allowed mask will
+ * not be changed, nor will its assigned CPU.
+ *
+ * The cpus_allowed mask of the parent may have changed after it was
+ * copied first time - so re-copy it here, then check the child's CPU
+ * to ensure it is on a valid CPU (and if not, just force it back to
+ * parent's CPU). This avoids alot of nasty races.
*/
p->cpus_allowed = current->cpus_allowed;
- set_task_cpu(p, smp_processor_id());
+ if (unlikely(!cpu_isset(task_cpu(p), p->cpus_allowed)))
+ set_task_cpu(p, smp_processor_id());
/*
* Check for pending SIGKILL! The new thread should not be allowed
@@ -1087,6 +1092,11 @@ static task_t *copy_process(unsigned long clone_flags,
spin_unlock(&current->sighand->siglock);
}
+ /*
+ * inherit ioprio
+ */
+ p->ioprio = current->ioprio;
+
SET_LINKS(p);
if (unlikely(p->ptrace & PT_PTRACED))
__ptrace_link(p, current->parent);
diff --git a/kernel/irq/autoprobe.c b/kernel/irq/autoprobe.c
index 98d62d8efeaf..3467097ca61a 100644
--- a/kernel/irq/autoprobe.c
+++ b/kernel/irq/autoprobe.c
@@ -9,6 +9,7 @@
#include <linux/irq.h>
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/delay.h>
/*
* Autodetection depends on the fact that any interrupt that
@@ -26,7 +27,7 @@ static DECLARE_MUTEX(probe_sem);
*/
unsigned long probe_irq_on(void)
{
- unsigned long val, delay;
+ unsigned long val;
irq_desc_t *desc;
unsigned int i;
@@ -45,8 +46,7 @@ unsigned long probe_irq_on(void)
}
/* Wait for longstanding interrupts to trigger. */
- for (delay = jiffies + HZ/50; time_after(delay, jiffies); )
- /* about 20ms delay */ barrier();
+ msleep(20);
/*
* enable any unassigned irqs
@@ -68,8 +68,7 @@ unsigned long probe_irq_on(void)
/*
* Wait for spurious interrupts to trigger
*/
- for (delay = jiffies + HZ/10; time_after(delay, jiffies); )
- /* about 100ms delay */ barrier();
+ msleep(100);
/*
* Now filter out any obviously spurious interrupts
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index 436c7d93c00a..c29f83c16497 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -172,7 +172,7 @@ fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs)
spin_lock(&desc->lock);
if (!noirqdebug)
- note_interrupt(irq, desc, action_ret);
+ note_interrupt(irq, desc, action_ret, regs);
if (likely(!(desc->status & IRQ_PENDING)))
break;
desc->status &= ~IRQ_PENDING;
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index f6297c306905..7df9abd5ec86 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -11,6 +11,83 @@
#include <linux/kallsyms.h>
#include <linux/interrupt.h>
+static int irqfixup;
+
+/*
+ * Recovery handler for misrouted interrupts.
+ */
+
+static int misrouted_irq(int irq, struct pt_regs *regs)
+{
+ int i;
+ irq_desc_t *desc;
+ int ok = 0;
+ int work = 0; /* Did we do work for a real IRQ */
+
+ for(i = 1; i < NR_IRQS; i++) {
+ struct irqaction *action;
+
+ if (i == irq) /* Already tried */
+ continue;
+ desc = &irq_desc[i];
+ spin_lock(&desc->lock);
+ action = desc->action;
+ /* Already running on another processor */
+ if (desc->status & IRQ_INPROGRESS) {
+ /*
+ * Already running: If it is shared get the other
+ * CPU to go looking for our mystery interrupt too
+ */
+ if (desc->action && (desc->action->flags & SA_SHIRQ))
+ desc->status |= IRQ_PENDING;
+ spin_unlock(&desc->lock);
+ continue;
+ }
+ /* Honour the normal IRQ locking */
+ desc->status |= IRQ_INPROGRESS;
+ spin_unlock(&desc->lock);
+ while (action) {
+ /* Only shared IRQ handlers are safe to call */
+ if (action->flags & SA_SHIRQ) {
+ if (action->handler(i, action->dev_id, regs) ==
+ IRQ_HANDLED)
+ ok = 1;
+ }
+ action = action->next;
+ }
+ local_irq_disable();
+ /* Now clean up the flags */
+ spin_lock(&desc->lock);
+ action = desc->action;
+
+ /*
+ * While we were looking for a fixup someone queued a real
+ * IRQ clashing with our walk
+ */
+
+ while ((desc->status & IRQ_PENDING) && action) {
+ /*
+ * Perform real IRQ processing for the IRQ we deferred
+ */
+ work = 1;
+ spin_unlock(&desc->lock);
+ handle_IRQ_event(i, regs, action);
+ spin_lock(&desc->lock);
+ desc->status &= ~IRQ_PENDING;
+ }
+ desc->status &= ~IRQ_INPROGRESS;
+ /*
+ * If we did actual work for the real IRQ line we must let the
+ * IRQ controller clean up too
+ */
+ if(work)
+ desc->handler->end(i);
+ spin_unlock(&desc->lock);
+ }
+ /* So the caller can adjust the irq error counts */
+ return ok;
+}
+
/*
* 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
@@ -31,7 +108,8 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
printk(KERN_ERR "irq event %d: bogus return value %x\n",
irq, action_ret);
} else {
- printk(KERN_ERR "irq %d: nobody cared!\n", irq);
+ printk(KERN_ERR "irq %d: nobody cared (try booting with "
+ "the \"irqpoll\" option)\n", irq);
}
dump_stack();
printk(KERN_ERR "handlers:\n");
@@ -45,7 +123,7 @@ __report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
}
}
-void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+static void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
{
static int count = 100;
@@ -55,7 +133,8 @@ void report_bad_irq(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
}
}
-void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
+void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret,
+ struct pt_regs *regs)
{
if (action_ret != IRQ_HANDLED) {
desc->irqs_unhandled++;
@@ -63,6 +142,15 @@ void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret)
report_bad_irq(irq, desc, action_ret);
}
+ if (unlikely(irqfixup)) {
+ /* Don't punish working computers */
+ if ((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) {
+ int ok = misrouted_irq(irq, regs);
+ if (action_ret == IRQ_NONE)
+ desc->irqs_unhandled -= ok;
+ }
+ }
+
desc->irq_count++;
if (desc->irq_count < 100000)
return;
@@ -94,3 +182,24 @@ int __init noirqdebug_setup(char *str)
__setup("noirqdebug", noirqdebug_setup);
+static int __init irqfixup_setup(char *str)
+{
+ irqfixup = 1;
+ printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n");
+ printk(KERN_WARNING "This may impact system performance.\n");
+ return 1;
+}
+
+__setup("irqfixup", irqfixup_setup);
+
+static int __init irqpoll_setup(char *str)
+{
+ irqfixup = 2;
+ printk(KERN_WARNING "Misrouted IRQ fixup and polling support "
+ "enabled\n");
+ printk(KERN_WARNING "This may significantly impact system "
+ "performance\n");
+ return 1;
+}
+
+__setup("irqpoll", irqpoll_setup);
diff --git a/kernel/itimer.c b/kernel/itimer.c
index 1dc988e0d2c7..a72cb0e5aa4b 100644
--- a/kernel/itimer.c
+++ b/kernel/itimer.c
@@ -153,11 +153,15 @@ int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
switch (which) {
case ITIMER_REAL:
+again:
spin_lock_irq(&tsk->sighand->siglock);
interval = tsk->signal->it_real_incr;
val = it_real_value(tsk->signal);
- if (val)
- del_timer_sync(&tsk->signal->real_timer);
+ /* We are sharing ->siglock with it_real_fn() */
+ if (try_to_del_timer_sync(&tsk->signal->real_timer) < 0) {
+ spin_unlock_irq(&tsk->sighand->siglock);
+ goto again;
+ }
tsk->signal->it_real_incr =
timeval_to_jiffies(&value->it_interval);
it_real_arm(tsk, timeval_to_jiffies(&value->it_value));
diff --git a/kernel/kexec.c b/kernel/kexec.c
new file mode 100644
index 000000000000..cdd4dcd8fb63
--- /dev/null
+++ b/kernel/kexec.c
@@ -0,0 +1,1063 @@
+/*
+ * kexec.c - kexec system call
+ * Copyright (C) 2002-2004 Eric Biederman <ebiederm@xmission.com>
+ *
+ * This source code is licensed under the GNU General Public License,
+ * Version 2. See the file COPYING for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/file.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/kexec.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/highmem.h>
+#include <linux/syscalls.h>
+#include <linux/reboot.h>
+#include <linux/syscalls.h>
+#include <linux/ioport.h>
+#include <linux/hardirq.h>
+
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/semaphore.h>
+
+/* Location of the reserved area for the crash kernel */
+struct resource crashk_res = {
+ .name = "Crash kernel",
+ .start = 0,
+ .end = 0,
+ .flags = IORESOURCE_BUSY | IORESOURCE_MEM
+};
+
+int kexec_should_crash(struct task_struct *p)
+{
+ if (in_interrupt() || !p->pid || p->pid == 1 || panic_on_oops)
+ return 1;
+ return 0;
+}
+
+/*
+ * When kexec transitions to the new kernel there is a one-to-one
+ * mapping between physical and virtual addresses. On processors
+ * where you can disable the MMU this is trivial, and easy. For
+ * others it is still a simple predictable page table to setup.
+ *
+ * In that environment kexec copies the new kernel to its final
+ * resting place. This means I can only support memory whose
+ * physical address can fit in an unsigned long. In particular
+ * addresses where (pfn << PAGE_SHIFT) > ULONG_MAX cannot be handled.
+ * If the assembly stub has more restrictive requirements
+ * KEXEC_SOURCE_MEMORY_LIMIT and KEXEC_DEST_MEMORY_LIMIT can be
+ * defined more restrictively in <asm/kexec.h>.
+ *
+ * The code for the transition from the current kernel to the
+ * the new kernel is placed in the control_code_buffer, whose size
+ * is given by KEXEC_CONTROL_CODE_SIZE. In the best case only a single
+ * page of memory is necessary, but some architectures require more.
+ * Because this memory must be identity mapped in the transition from
+ * virtual to physical addresses it must live in the range
+ * 0 - TASK_SIZE, as only the user space mappings are arbitrarily
+ * modifiable.
+ *
+ * The assembly stub in the control code buffer is passed a linked list
+ * of descriptor pages detailing the source pages of the new kernel,
+ * and the destination addresses of those source pages. As this data
+ * structure is not used in the context of the current OS, it must
+ * be self-contained.
+ *
+ * The code has been made to work with highmem pages and will use a
+ * destination page in its final resting place (if it happens
+ * to allocate it). The end product of this is that most of the
+ * physical address space, and most of RAM can be used.
+ *
+ * Future directions include:
+ * - allocating a page table with the control code buffer identity
+ * mapped, to simplify machine_kexec and make kexec_on_panic more
+ * reliable.
+ */
+
+/*
+ * KIMAGE_NO_DEST is an impossible destination address..., for
+ * allocating pages whose destination address we do not care about.
+ */
+#define KIMAGE_NO_DEST (-1UL)
+
+static int kimage_is_destination_range(struct kimage *image,
+ unsigned long start, unsigned long end);
+static struct page *kimage_alloc_page(struct kimage *image,
+ unsigned int gfp_mask,
+ unsigned long dest);
+
+static int do_kimage_alloc(struct kimage **rimage, unsigned long entry,
+ unsigned long nr_segments,
+ struct kexec_segment __user *segments)
+{
+ size_t segment_bytes;
+ struct kimage *image;
+ unsigned long i;
+ int result;
+
+ /* Allocate a controlling structure */
+ result = -ENOMEM;
+ image = kmalloc(sizeof(*image), GFP_KERNEL);
+ if (!image)
+ goto out;
+
+ memset(image, 0, sizeof(*image));
+ image->head = 0;
+ image->entry = &image->head;
+ image->last_entry = &image->head;
+ image->control_page = ~0; /* By default this does not apply */
+ image->start = entry;
+ image->type = KEXEC_TYPE_DEFAULT;
+
+ /* Initialize the list of control pages */
+ INIT_LIST_HEAD(&image->control_pages);
+
+ /* Initialize the list of destination pages */
+ INIT_LIST_HEAD(&image->dest_pages);
+
+ /* Initialize the list of unuseable pages */
+ INIT_LIST_HEAD(&image->unuseable_pages);
+
+ /* Read in the segments */
+ image->nr_segments = nr_segments;
+ segment_bytes = nr_segments * sizeof(*segments);
+ result = copy_from_user(image->segment, segments, segment_bytes);
+ if (result)
+ goto out;
+
+ /*
+ * Verify we have good destination addresses. The caller is
+ * responsible for making certain we don't attempt to load
+ * the new image into invalid or reserved areas of RAM. This
+ * just verifies it is an address we can use.
+ *
+ * Since the kernel does everything in page size chunks ensure
+ * the destination addreses are page aligned. Too many
+ * special cases crop of when we don't do this. The most
+ * insidious is getting overlapping destination addresses
+ * simply because addresses are changed to page size
+ * granularity.
+ */
+ result = -EADDRNOTAVAIL;
+ for (i = 0; i < nr_segments; i++) {
+ unsigned long mstart, mend;
+
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz;
+ if ((mstart & ~PAGE_MASK) || (mend & ~PAGE_MASK))
+ goto out;
+ if (mend >= KEXEC_DESTINATION_MEMORY_LIMIT)
+ goto out;
+ }
+
+ /* Verify our destination addresses do not overlap.
+ * If we alloed overlapping destination addresses
+ * through very weird things can happen with no
+ * easy explanation as one segment stops on another.
+ */
+ result = -EINVAL;
+ for (i = 0; i < nr_segments; i++) {
+ unsigned long mstart, mend;
+ unsigned long j;
+
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz;
+ for (j = 0; j < i; j++) {
+ unsigned long pstart, pend;
+ pstart = image->segment[j].mem;
+ pend = pstart + image->segment[j].memsz;
+ /* Do the segments overlap ? */
+ if ((mend > pstart) && (mstart < pend))
+ goto out;
+ }
+ }
+
+ /* Ensure our buffer sizes are strictly less than
+ * our memory sizes. This should always be the case,
+ * and it is easier to check up front than to be surprised
+ * later on.
+ */
+ result = -EINVAL;
+ for (i = 0; i < nr_segments; i++) {
+ if (image->segment[i].bufsz > image->segment[i].memsz)
+ goto out;
+ }
+
+ result = 0;
+out:
+ if (result == 0)
+ *rimage = image;
+ else
+ kfree(image);
+
+ return result;
+
+}
+
+static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry,
+ unsigned long nr_segments,
+ struct kexec_segment __user *segments)
+{
+ int result;
+ struct kimage *image;
+
+ /* Allocate and initialize a controlling structure */
+ image = NULL;
+ result = do_kimage_alloc(&image, entry, nr_segments, segments);
+ if (result)
+ goto out;
+
+ *rimage = image;
+
+ /*
+ * Find a location for the control code buffer, and add it
+ * the vector of segments so that it's pages will also be
+ * counted as destination pages.
+ */
+ result = -ENOMEM;
+ image->control_code_page = kimage_alloc_control_pages(image,
+ get_order(KEXEC_CONTROL_CODE_SIZE));
+ if (!image->control_code_page) {
+ printk(KERN_ERR "Could not allocate control_code_buffer\n");
+ goto out;
+ }
+
+ result = 0;
+ out:
+ if (result == 0)
+ *rimage = image;
+ else
+ kfree(image);
+
+ return result;
+}
+
+static int kimage_crash_alloc(struct kimage **rimage, unsigned long entry,
+ unsigned long nr_segments,
+ struct kexec_segment __user *segments)
+{
+ int result;
+ struct kimage *image;
+ unsigned long i;
+
+ image = NULL;
+ /* Verify we have a valid entry point */
+ if ((entry < crashk_res.start) || (entry > crashk_res.end)) {
+ result = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ /* Allocate and initialize a controlling structure */
+ result = do_kimage_alloc(&image, entry, nr_segments, segments);
+ if (result)
+ goto out;
+
+ /* Enable the special crash kernel control page
+ * allocation policy.
+ */
+ image->control_page = crashk_res.start;
+ image->type = KEXEC_TYPE_CRASH;
+
+ /*
+ * Verify we have good destination addresses. Normally
+ * the caller is responsible for making certain we don't
+ * attempt to load the new image into invalid or reserved
+ * areas of RAM. But crash kernels are preloaded into a
+ * reserved area of ram. We must ensure the addresses
+ * are in the reserved area otherwise preloading the
+ * kernel could corrupt things.
+ */
+ result = -EADDRNOTAVAIL;
+ for (i = 0; i < nr_segments; i++) {
+ unsigned long mstart, mend;
+
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz - 1;
+ /* Ensure we are within the crash kernel limits */
+ if ((mstart < crashk_res.start) || (mend > crashk_res.end))
+ goto out;
+ }
+
+ /*
+ * Find a location for the control code buffer, and add
+ * the vector of segments so that it's pages will also be
+ * counted as destination pages.
+ */
+ result = -ENOMEM;
+ image->control_code_page = kimage_alloc_control_pages(image,
+ get_order(KEXEC_CONTROL_CODE_SIZE));
+ if (!image->control_code_page) {
+ printk(KERN_ERR "Could not allocate control_code_buffer\n");
+ goto out;
+ }
+
+ result = 0;
+out:
+ if (result == 0)
+ *rimage = image;
+ else
+ kfree(image);
+
+ return result;
+}
+
+static int kimage_is_destination_range(struct kimage *image,
+ unsigned long start,
+ unsigned long end)
+{
+ unsigned long i;
+
+ for (i = 0; i < image->nr_segments; i++) {
+ unsigned long mstart, mend;
+
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz;
+ if ((end > mstart) && (start < mend))
+ return 1;
+ }
+
+ return 0;
+}
+
+static struct page *kimage_alloc_pages(unsigned int gfp_mask,
+ unsigned int order)
+{
+ struct page *pages;
+
+ pages = alloc_pages(gfp_mask, order);
+ if (pages) {
+ unsigned int count, i;
+ pages->mapping = NULL;
+ pages->private = order;
+ count = 1 << order;
+ for (i = 0; i < count; i++)
+ SetPageReserved(pages + i);
+ }
+
+ return pages;
+}
+
+static void kimage_free_pages(struct page *page)
+{
+ unsigned int order, count, i;
+
+ order = page->private;
+ count = 1 << order;
+ for (i = 0; i < count; i++)
+ ClearPageReserved(page + i);
+ __free_pages(page, order);
+}
+
+static void kimage_free_page_list(struct list_head *list)
+{
+ struct list_head *pos, *next;
+
+ list_for_each_safe(pos, next, list) {
+ struct page *page;
+
+ page = list_entry(pos, struct page, lru);
+ list_del(&page->lru);
+ kimage_free_pages(page);
+ }
+}
+
+static struct page *kimage_alloc_normal_control_pages(struct kimage *image,
+ unsigned int order)
+{
+ /* Control pages are special, they are the intermediaries
+ * that are needed while we copy the rest of the pages
+ * to their final resting place. As such they must
+ * not conflict with either the destination addresses
+ * or memory the kernel is already using.
+ *
+ * The only case where we really need more than one of
+ * these are for architectures where we cannot disable
+ * the MMU and must instead generate an identity mapped
+ * page table for all of the memory.
+ *
+ * At worst this runs in O(N) of the image size.
+ */
+ struct list_head extra_pages;
+ struct page *pages;
+ unsigned int count;
+
+ count = 1 << order;
+ INIT_LIST_HEAD(&extra_pages);
+
+ /* Loop while I can allocate a page and the page allocated
+ * is a destination page.
+ */
+ do {
+ unsigned long pfn, epfn, addr, eaddr;
+
+ pages = kimage_alloc_pages(GFP_KERNEL, order);
+ if (!pages)
+ break;
+ pfn = page_to_pfn(pages);
+ epfn = pfn + count;
+ addr = pfn << PAGE_SHIFT;
+ eaddr = epfn << PAGE_SHIFT;
+ if ((epfn >= (KEXEC_CONTROL_MEMORY_LIMIT >> PAGE_SHIFT)) ||
+ kimage_is_destination_range(image, addr, eaddr)) {
+ list_add(&pages->lru, &extra_pages);
+ pages = NULL;
+ }
+ } while (!pages);
+
+ if (pages) {
+ /* Remember the allocated page... */
+ list_add(&pages->lru, &image->control_pages);
+
+ /* Because the page is already in it's destination
+ * location we will never allocate another page at
+ * that address. Therefore kimage_alloc_pages
+ * will not return it (again) and we don't need
+ * to give it an entry in image->segment[].
+ */
+ }
+ /* Deal with the destination pages I have inadvertently allocated.
+ *
+ * Ideally I would convert multi-page allocations into single
+ * page allocations, and add everyting to image->dest_pages.
+ *
+ * For now it is simpler to just free the pages.
+ */
+ kimage_free_page_list(&extra_pages);
+
+ return pages;
+}
+
+static struct page *kimage_alloc_crash_control_pages(struct kimage *image,
+ unsigned int order)
+{
+ /* Control pages are special, they are the intermediaries
+ * that are needed while we copy the rest of the pages
+ * to their final resting place. As such they must
+ * not conflict with either the destination addresses
+ * or memory the kernel is already using.
+ *
+ * Control pages are also the only pags we must allocate
+ * when loading a crash kernel. All of the other pages
+ * are specified by the segments and we just memcpy
+ * into them directly.
+ *
+ * The only case where we really need more than one of
+ * these are for architectures where we cannot disable
+ * the MMU and must instead generate an identity mapped
+ * page table for all of the memory.
+ *
+ * Given the low demand this implements a very simple
+ * allocator that finds the first hole of the appropriate
+ * size in the reserved memory region, and allocates all
+ * of the memory up to and including the hole.
+ */
+ unsigned long hole_start, hole_end, size;
+ struct page *pages;
+
+ pages = NULL;
+ size = (1 << order) << PAGE_SHIFT;
+ hole_start = (image->control_page + (size - 1)) & ~(size - 1);
+ hole_end = hole_start + size - 1;
+ while (hole_end <= crashk_res.end) {
+ unsigned long i;
+
+ if (hole_end > KEXEC_CONTROL_MEMORY_LIMIT)
+ break;
+ if (hole_end > crashk_res.end)
+ break;
+ /* See if I overlap any of the segments */
+ for (i = 0; i < image->nr_segments; i++) {
+ unsigned long mstart, mend;
+
+ mstart = image->segment[i].mem;
+ mend = mstart + image->segment[i].memsz - 1;
+ if ((hole_end >= mstart) && (hole_start <= mend)) {
+ /* Advance the hole to the end of the segment */
+ hole_start = (mend + (size - 1)) & ~(size - 1);
+ hole_end = hole_start + size - 1;
+ break;
+ }
+ }
+ /* If I don't overlap any segments I have found my hole! */
+ if (i == image->nr_segments) {
+ pages = pfn_to_page(hole_start >> PAGE_SHIFT);
+ break;
+ }
+ }
+ if (pages)
+ image->control_page = hole_end;
+
+ return pages;
+}
+
+
+struct page *kimage_alloc_control_pages(struct kimage *image,
+ unsigned int order)
+{
+ struct page *pages = NULL;
+
+ switch (image->type) {
+ case KEXEC_TYPE_DEFAULT:
+ pages = kimage_alloc_normal_control_pages(image, order);
+ break;
+ case KEXEC_TYPE_CRASH:
+ pages = kimage_alloc_crash_control_pages(image, order);
+ break;
+ }
+
+ return pages;
+}
+
+static int kimage_add_entry(struct kimage *image, kimage_entry_t entry)
+{
+ if (*image->entry != 0)
+ image->entry++;
+
+ if (image->entry == image->last_entry) {
+ kimage_entry_t *ind_page;
+ struct page *page;
+
+ page = kimage_alloc_page(image, GFP_KERNEL, KIMAGE_NO_DEST);
+ if (!page)
+ return -ENOMEM;
+
+ ind_page = page_address(page);
+ *image->entry = virt_to_phys(ind_page) | IND_INDIRECTION;
+ image->entry = ind_page;
+ image->last_entry = ind_page +
+ ((PAGE_SIZE/sizeof(kimage_entry_t)) - 1);
+ }
+ *image->entry = entry;
+ image->entry++;
+ *image->entry = 0;
+
+ return 0;
+}
+
+static int kimage_set_destination(struct kimage *image,
+ unsigned long destination)
+{
+ int result;
+
+ destination &= PAGE_MASK;
+ result = kimage_add_entry(image, destination | IND_DESTINATION);
+ if (result == 0)
+ image->destination = destination;
+
+ return result;
+}
+
+
+static int kimage_add_page(struct kimage *image, unsigned long page)
+{
+ int result;
+
+ page &= PAGE_MASK;
+ result = kimage_add_entry(image, page | IND_SOURCE);
+ if (result == 0)
+ image->destination += PAGE_SIZE;
+
+ return result;
+}
+
+
+static void kimage_free_extra_pages(struct kimage *image)
+{
+ /* Walk through and free any extra destination pages I may have */
+ kimage_free_page_list(&image->dest_pages);
+
+ /* Walk through and free any unuseable pages I have cached */
+ kimage_free_page_list(&image->unuseable_pages);
+
+}
+static int kimage_terminate(struct kimage *image)
+{
+ if (*image->entry != 0)
+ image->entry++;
+
+ *image->entry = IND_DONE;
+
+ return 0;
+}
+
+#define for_each_kimage_entry(image, ptr, entry) \
+ for (ptr = &image->head; (entry = *ptr) && !(entry & IND_DONE); \
+ ptr = (entry & IND_INDIRECTION)? \
+ phys_to_virt((entry & PAGE_MASK)): ptr +1)
+
+static void kimage_free_entry(kimage_entry_t entry)
+{
+ struct page *page;
+
+ page = pfn_to_page(entry >> PAGE_SHIFT);
+ kimage_free_pages(page);
+}
+
+static void kimage_free(struct kimage *image)
+{
+ kimage_entry_t *ptr, entry;
+ kimage_entry_t ind = 0;
+
+ if (!image)
+ return;
+
+ kimage_free_extra_pages(image);
+ for_each_kimage_entry(image, ptr, entry) {
+ if (entry & IND_INDIRECTION) {
+ /* Free the previous indirection page */
+ if (ind & IND_INDIRECTION)
+ kimage_free_entry(ind);
+ /* Save this indirection page until we are
+ * done with it.
+ */
+ ind = entry;
+ }
+ else if (entry & IND_SOURCE)
+ kimage_free_entry(entry);
+ }
+ /* Free the final indirection page */
+ if (ind & IND_INDIRECTION)
+ kimage_free_entry(ind);
+
+ /* Handle any machine specific cleanup */
+ machine_kexec_cleanup(image);
+
+ /* Free the kexec control pages... */
+ kimage_free_page_list(&image->control_pages);
+ kfree(image);
+}
+
+static kimage_entry_t *kimage_dst_used(struct kimage *image,
+ unsigned long page)
+{
+ kimage_entry_t *ptr, entry;
+ unsigned long destination = 0;
+
+ for_each_kimage_entry(image, ptr, entry) {
+ if (entry & IND_DESTINATION)
+ destination = entry & PAGE_MASK;
+ else if (entry & IND_SOURCE) {
+ if (page == destination)
+ return ptr;
+ destination += PAGE_SIZE;
+ }
+ }
+
+ return NULL;
+}
+
+static struct page *kimage_alloc_page(struct kimage *image,
+ unsigned int gfp_mask,
+ unsigned long destination)
+{
+ /*
+ * Here we implement safeguards to ensure that a source page
+ * is not copied to its destination page before the data on
+ * the destination page is no longer useful.
+ *
+ * To do this we maintain the invariant that a source page is
+ * either its own destination page, or it is not a
+ * destination page at all.
+ *
+ * That is slightly stronger than required, but the proof
+ * that no problems will not occur is trivial, and the
+ * implementation is simply to verify.
+ *
+ * When allocating all pages normally this algorithm will run
+ * in O(N) time, but in the worst case it will run in O(N^2)
+ * time. If the runtime is a problem the data structures can
+ * be fixed.
+ */
+ struct page *page;
+ unsigned long addr;
+
+ /*
+ * Walk through the list of destination pages, and see if I
+ * have a match.
+ */
+ list_for_each_entry(page, &image->dest_pages, lru) {
+ addr = page_to_pfn(page) << PAGE_SHIFT;
+ if (addr == destination) {
+ list_del(&page->lru);
+ return page;
+ }
+ }
+ page = NULL;
+ while (1) {
+ kimage_entry_t *old;
+
+ /* Allocate a page, if we run out of memory give up */
+ page = kimage_alloc_pages(gfp_mask, 0);
+ if (!page)
+ return NULL;
+ /* If the page cannot be used file it away */
+ if (page_to_pfn(page) >
+ (KEXEC_SOURCE_MEMORY_LIMIT >> PAGE_SHIFT)) {
+ list_add(&page->lru, &image->unuseable_pages);
+ continue;
+ }
+ addr = page_to_pfn(page) << PAGE_SHIFT;
+
+ /* If it is the destination page we want use it */
+ if (addr == destination)
+ break;
+
+ /* If the page is not a destination page use it */
+ if (!kimage_is_destination_range(image, addr,
+ addr + PAGE_SIZE))
+ break;
+
+ /*
+ * I know that the page is someones destination page.
+ * See if there is already a source page for this
+ * destination page. And if so swap the source pages.
+ */
+ old = kimage_dst_used(image, addr);
+ if (old) {
+ /* If so move it */
+ unsigned long old_addr;
+ struct page *old_page;
+
+ old_addr = *old & PAGE_MASK;
+ old_page = pfn_to_page(old_addr >> PAGE_SHIFT);
+ copy_highpage(page, old_page);
+ *old = addr | (*old & ~PAGE_MASK);
+
+ /* The old page I have found cannot be a
+ * destination page, so return it.
+ */
+ addr = old_addr;
+ page = old_page;
+ break;
+ }
+ else {
+ /* Place the page on the destination list I
+ * will use it later.
+ */
+ list_add(&page->lru, &image->dest_pages);
+ }
+ }
+
+ return page;
+}
+
+static int kimage_load_normal_segment(struct kimage *image,
+ struct kexec_segment *segment)
+{
+ unsigned long maddr;
+ unsigned long ubytes, mbytes;
+ int result;
+ unsigned char __user *buf;
+
+ result = 0;
+ buf = segment->buf;
+ ubytes = segment->bufsz;
+ mbytes = segment->memsz;
+ maddr = segment->mem;
+
+ result = kimage_set_destination(image, maddr);
+ if (result < 0)
+ goto out;
+
+ while (mbytes) {
+ struct page *page;
+ char *ptr;
+ size_t uchunk, mchunk;
+
+ page = kimage_alloc_page(image, GFP_HIGHUSER, maddr);
+ if (page == 0) {
+ result = -ENOMEM;
+ goto out;
+ }
+ result = kimage_add_page(image, page_to_pfn(page)
+ << PAGE_SHIFT);
+ if (result < 0)
+ goto out;
+
+ ptr = kmap(page);
+ /* Start with a clear page */
+ memset(ptr, 0, PAGE_SIZE);
+ ptr += maddr & ~PAGE_MASK;
+ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
+ if (mchunk > mbytes)
+ mchunk = mbytes;
+
+ uchunk = mchunk;
+ if (uchunk > ubytes)
+ uchunk = ubytes;
+
+ result = copy_from_user(ptr, buf, uchunk);
+ kunmap(page);
+ if (result) {
+ result = (result < 0) ? result : -EIO;
+ goto out;
+ }
+ ubytes -= uchunk;
+ maddr += mchunk;
+ buf += mchunk;
+ mbytes -= mchunk;
+ }
+out:
+ return result;
+}
+
+static int kimage_load_crash_segment(struct kimage *image,
+ struct kexec_segment *segment)
+{
+ /* For crash dumps kernels we simply copy the data from
+ * user space to it's destination.
+ * We do things a page at a time for the sake of kmap.
+ */
+ unsigned long maddr;
+ unsigned long ubytes, mbytes;
+ int result;
+ unsigned char __user *buf;
+
+ result = 0;
+ buf = segment->buf;
+ ubytes = segment->bufsz;
+ mbytes = segment->memsz;
+ maddr = segment->mem;
+ while (mbytes) {
+ struct page *page;
+ char *ptr;
+ size_t uchunk, mchunk;
+
+ page = pfn_to_page(maddr >> PAGE_SHIFT);
+ if (page == 0) {
+ result = -ENOMEM;
+ goto out;
+ }
+ ptr = kmap(page);
+ ptr += maddr & ~PAGE_MASK;
+ mchunk = PAGE_SIZE - (maddr & ~PAGE_MASK);
+ if (mchunk > mbytes)
+ mchunk = mbytes;
+
+ uchunk = mchunk;
+ if (uchunk > ubytes) {
+ uchunk = ubytes;
+ /* Zero the trailing part of the page */
+ memset(ptr + uchunk, 0, mchunk - uchunk);
+ }
+ result = copy_from_user(ptr, buf, uchunk);
+ kunmap(page);
+ if (result) {
+ result = (result < 0) ? result : -EIO;
+ goto out;
+ }
+ ubytes -= uchunk;
+ maddr += mchunk;
+ buf += mchunk;
+ mbytes -= mchunk;
+ }
+out:
+ return result;
+}
+
+static int kimage_load_segment(struct kimage *image,
+ struct kexec_segment *segment)
+{
+ int result = -ENOMEM;
+
+ switch (image->type) {
+ case KEXEC_TYPE_DEFAULT:
+ result = kimage_load_normal_segment(image, segment);
+ break;
+ case KEXEC_TYPE_CRASH:
+ result = kimage_load_crash_segment(image, segment);
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Exec Kernel system call: for obvious reasons only root may call it.
+ *
+ * This call breaks up into three pieces.
+ * - A generic part which loads the new kernel from the current
+ * address space, and very carefully places the data in the
+ * allocated pages.
+ *
+ * - A generic part that interacts with the kernel and tells all of
+ * the devices to shut down. Preventing on-going dmas, and placing
+ * the devices in a consistent state so a later kernel can
+ * reinitialize them.
+ *
+ * - A machine specific part that includes the syscall number
+ * and the copies the image to it's final destination. And
+ * jumps into the image at entry.
+ *
+ * kexec does not sync, or unmount filesystems so if you need
+ * that to happen you need to do that yourself.
+ */
+struct kimage *kexec_image = NULL;
+static struct kimage *kexec_crash_image = NULL;
+/*
+ * A home grown binary mutex.
+ * Nothing can wait so this mutex is safe to use
+ * in interrupt context :)
+ */
+static int kexec_lock = 0;
+
+asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments,
+ struct kexec_segment __user *segments,
+ unsigned long flags)
+{
+ struct kimage **dest_image, *image;
+ int locked;
+ int result;
+
+ /* We only trust the superuser with rebooting the system. */
+ if (!capable(CAP_SYS_BOOT))
+ return -EPERM;
+
+ /*
+ * Verify we have a legal set of flags
+ * This leaves us room for future extensions.
+ */
+ if ((flags & KEXEC_FLAGS) != (flags & ~KEXEC_ARCH_MASK))
+ return -EINVAL;
+
+ /* Verify we are on the appropriate architecture */
+ if (((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH) &&
+ ((flags & KEXEC_ARCH_MASK) != KEXEC_ARCH_DEFAULT))
+ return -EINVAL;
+
+ /* Put an artificial cap on the number
+ * of segments passed to kexec_load.
+ */
+ if (nr_segments > KEXEC_SEGMENT_MAX)
+ return -EINVAL;
+
+ image = NULL;
+ result = 0;
+
+ /* Because we write directly to the reserved memory
+ * region when loading crash kernels we need a mutex here to
+ * prevent multiple crash kernels from attempting to load
+ * simultaneously, and to prevent a crash kernel from loading
+ * over the top of a in use crash kernel.
+ *
+ * KISS: always take the mutex.
+ */
+ locked = xchg(&kexec_lock, 1);
+ if (locked)
+ return -EBUSY;
+
+ dest_image = &kexec_image;
+ if (flags & KEXEC_ON_CRASH)
+ dest_image = &kexec_crash_image;
+ if (nr_segments > 0) {
+ unsigned long i;
+
+ /* Loading another kernel to reboot into */
+ if ((flags & KEXEC_ON_CRASH) == 0)
+ result = kimage_normal_alloc(&image, entry,
+ nr_segments, segments);
+ /* Loading another kernel to switch to if this one crashes */
+ else if (flags & KEXEC_ON_CRASH) {
+ /* Free any current crash dump kernel before
+ * we corrupt it.
+ */
+ kimage_free(xchg(&kexec_crash_image, NULL));
+ result = kimage_crash_alloc(&image, entry,
+ nr_segments, segments);
+ }
+ if (result)
+ goto out;
+
+ result = machine_kexec_prepare(image);
+ if (result)
+ goto out;
+
+ for (i = 0; i < nr_segments; i++) {
+ result = kimage_load_segment(image, &image->segment[i]);
+ if (result)
+ goto out;
+ }
+ result = kimage_terminate(image);
+ if (result)
+ goto out;
+ }
+ /* Install the new kernel, and Uninstall the old */
+ image = xchg(dest_image, image);
+
+out:
+ xchg(&kexec_lock, 0); /* Release the mutex */
+ kimage_free(image);
+
+ return result;
+}
+
+#ifdef CONFIG_COMPAT
+asmlinkage long compat_sys_kexec_load(unsigned long entry,
+ unsigned long nr_segments,
+ struct compat_kexec_segment __user *segments,
+ unsigned long flags)
+{
+ struct compat_kexec_segment in;
+ struct kexec_segment out, __user *ksegments;
+ unsigned long i, result;
+
+ /* Don't allow clients that don't understand the native
+ * architecture to do anything.
+ */
+ if ((flags & KEXEC_ARCH_MASK) == KEXEC_ARCH_DEFAULT)
+ return -EINVAL;
+
+ if (nr_segments > KEXEC_SEGMENT_MAX)
+ return -EINVAL;
+
+ ksegments = compat_alloc_user_space(nr_segments * sizeof(out));
+ for (i=0; i < nr_segments; i++) {
+ result = copy_from_user(&in, &segments[i], sizeof(in));
+ if (result)
+ return -EFAULT;
+
+ out.buf = compat_ptr(in.buf);
+ out.bufsz = in.bufsz;
+ out.mem = in.mem;
+ out.memsz = in.memsz;
+
+ result = copy_to_user(&ksegments[i], &out, sizeof(out));
+ if (result)
+ return -EFAULT;
+ }
+
+ return sys_kexec_load(entry, nr_segments, ksegments, flags);
+}
+#endif
+
+void crash_kexec(struct pt_regs *regs)
+{
+ struct kimage *image;
+ int locked;
+
+
+ /* Take the kexec_lock here to prevent sys_kexec_load
+ * running on one cpu from replacing the crash kernel
+ * we are using after a panic on a different cpu.
+ *
+ * If the crash kernel was not located in a fixed area
+ * of memory the xchg(&kexec_crash_image) would be
+ * sufficient. But since I reuse the memory...
+ */
+ locked = xchg(&kexec_lock, 1);
+ if (!locked) {
+ image = xchg(&kexec_crash_image, NULL);
+ if (image) {
+ machine_crash_shutdown(regs);
+ machine_kexec(image);
+ }
+ xchg(&kexec_lock, 0);
+ }
+}
diff --git a/kernel/kmod.c b/kernel/kmod.c
index eed53d4f5230..44166e3bb8af 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -120,6 +120,7 @@ struct subprocess_info {
char *path;
char **argv;
char **envp;
+ struct key *ring;
int wait;
int retval;
};
@@ -130,16 +131,21 @@ struct subprocess_info {
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
+ struct key *old_session;
int retval;
- /* Unblock all signals. */
+ /* Unblock all signals and set the session keyring. */
+ key_get(sub_info->ring);
flush_signals(current);
spin_lock_irq(&current->sighand->siglock);
+ old_session = __install_session_keyring(current, sub_info->ring);
flush_signal_handlers(current, 1);
sigemptyset(&current->blocked);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
+ key_put(old_session);
+
/* We can run anywhere, unlike our parent keventd(). */
set_cpus_allowed(current, CPU_MASK_ALL);
@@ -211,10 +217,11 @@ static void __call_usermodehelper(void *data)
}
/**
- * call_usermodehelper - start a usermode application
+ * call_usermodehelper_keys - start a usermode application
* @path: pathname for the application
* @argv: null-terminated argument list
* @envp: null-terminated environment list
+ * @session_keyring: session keyring for process (NULL for an empty keyring)
* @wait: wait for the application to finish and return status.
*
* Runs a user-space application. The application is started
@@ -224,7 +231,8 @@ static void __call_usermodehelper(void *data)
* Must be called from process context. Returns a negative error code
* if program was not execed successfully, or 0.
*/
-int call_usermodehelper(char *path, char **argv, char **envp, int wait)
+int call_usermodehelper_keys(char *path, char **argv, char **envp,
+ struct key *session_keyring, int wait)
{
DECLARE_COMPLETION(done);
struct subprocess_info sub_info = {
@@ -232,6 +240,7 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
.path = path,
.argv = argv,
.envp = envp,
+ .ring = session_keyring,
.wait = wait,
.retval = 0,
};
@@ -247,7 +256,7 @@ int call_usermodehelper(char *path, char **argv, char **envp, int wait)
wait_for_completion(&done);
return sub_info.retval;
}
-EXPORT_SYMBOL(call_usermodehelper);
+EXPORT_SYMBOL(call_usermodehelper_keys);
void __init usermodehelper_init(void)
{
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 334f37472c56..b0237122b24e 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -36,6 +36,7 @@
#include <linux/hash.h>
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/moduleloader.h>
#include <asm/cacheflush.h>
#include <asm/errno.h>
#include <asm/kdebug.h>
@@ -50,6 +51,106 @@ unsigned int kprobe_cpu = NR_CPUS;
static DEFINE_SPINLOCK(kprobe_lock);
static struct kprobe *curr_kprobe;
+/*
+ * kprobe->ainsn.insn points to the copy of the instruction to be
+ * single-stepped. x86_64, POWER4 and above have no-exec support and
+ * stepping on the instruction on a vmalloced/kmalloced/data page
+ * is a recipe for disaster
+ */
+#define INSNS_PER_PAGE (PAGE_SIZE/(MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
+
+struct kprobe_insn_page {
+ struct hlist_node hlist;
+ kprobe_opcode_t *insns; /* Page of instruction slots */
+ char slot_used[INSNS_PER_PAGE];
+ int nused;
+};
+
+static struct hlist_head kprobe_insn_pages;
+
+/**
+ * get_insn_slot() - Find a slot on an executable page for an instruction.
+ * We allocate an executable page if there's no room on existing ones.
+ */
+kprobe_opcode_t *get_insn_slot(void)
+{
+ struct kprobe_insn_page *kip;
+ struct hlist_node *pos;
+
+ hlist_for_each(pos, &kprobe_insn_pages) {
+ kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ if (kip->nused < INSNS_PER_PAGE) {
+ int i;
+ for (i = 0; i < INSNS_PER_PAGE; i++) {
+ if (!kip->slot_used[i]) {
+ kip->slot_used[i] = 1;
+ kip->nused++;
+ return kip->insns + (i * MAX_INSN_SIZE);
+ }
+ }
+ /* Surprise! No unused slots. Fix kip->nused. */
+ kip->nused = INSNS_PER_PAGE;
+ }
+ }
+
+ /* All out of space. Need to allocate a new page. Use slot 0.*/
+ kip = kmalloc(sizeof(struct kprobe_insn_page), GFP_KERNEL);
+ if (!kip) {
+ return NULL;
+ }
+
+ /*
+ * Use module_alloc so this page is within +/- 2GB of where the
+ * kernel image and loaded module images reside. This is required
+ * so x86_64 can correctly handle the %rip-relative fixups.
+ */
+ kip->insns = module_alloc(PAGE_SIZE);
+ if (!kip->insns) {
+ kfree(kip);
+ return NULL;
+ }
+ INIT_HLIST_NODE(&kip->hlist);
+ hlist_add_head(&kip->hlist, &kprobe_insn_pages);
+ memset(kip->slot_used, 0, INSNS_PER_PAGE);
+ kip->slot_used[0] = 1;
+ kip->nused = 1;
+ return kip->insns;
+}
+
+void free_insn_slot(kprobe_opcode_t *slot)
+{
+ struct kprobe_insn_page *kip;
+ struct hlist_node *pos;
+
+ hlist_for_each(pos, &kprobe_insn_pages) {
+ kip = hlist_entry(pos, struct kprobe_insn_page, hlist);
+ if (kip->insns <= slot &&
+ slot < kip->insns + (INSNS_PER_PAGE * MAX_INSN_SIZE)) {
+ int i = (slot - kip->insns) / MAX_INSN_SIZE;
+ kip->slot_used[i] = 0;
+ kip->nused--;
+ if (kip->nused == 0) {
+ /*
+ * Page is no longer in use. Free it unless
+ * it's the last one. We keep the last one
+ * so as not to have to set it up again the
+ * next time somebody inserts a probe.
+ */
+ hlist_del(&kip->hlist);
+ if (hlist_empty(&kprobe_insn_pages)) {
+ INIT_HLIST_NODE(&kip->hlist);
+ hlist_add_head(&kip->hlist,
+ &kprobe_insn_pages);
+ } else {
+ module_free(NULL, kip->insns);
+ kfree(kip);
+ }
+ }
+ return;
+ }
+ }
+}
+
/* Locks kprobe: irqs must be disabled */
void lock_kprobes(void)
{
@@ -139,12 +240,6 @@ static int aggr_break_handler(struct kprobe *p, struct pt_regs *regs)
return 0;
}
-struct kprobe trampoline_p = {
- .addr = (kprobe_opcode_t *) &kretprobe_trampoline,
- .pre_handler = trampoline_probe_handler,
- .post_handler = trampoline_post_handler
-};
-
struct kretprobe_instance *get_free_rp_inst(struct kretprobe *rp)
{
struct hlist_node *node;
@@ -163,35 +258,18 @@ static struct kretprobe_instance *get_used_rp_inst(struct kretprobe *rp)
return NULL;
}
-struct kretprobe_instance *get_rp_inst(void *sara)
-{
- struct hlist_head *head;
- struct hlist_node *node;
- struct task_struct *tsk;
- struct kretprobe_instance *ri;
-
- tsk = arch_get_kprobe_task(sara);
- head = &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
- hlist_for_each_entry(ri, node, head, hlist) {
- if (ri->stack_addr == sara)
- return ri;
- }
- return NULL;
-}
-
void add_rp_inst(struct kretprobe_instance *ri)
{
- struct task_struct *tsk;
/*
* Remove rp inst off the free list -
* Add it back when probed function returns
*/
hlist_del(&ri->uflist);
- tsk = arch_get_kprobe_task(ri->stack_addr);
+
/* Add rp inst onto table */
INIT_HLIST_NODE(&ri->hlist);
hlist_add_head(&ri->hlist,
- &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)]);
+ &kretprobe_inst_table[hash_ptr(ri->task, KPROBE_HASH_BITS)]);
/* Also add this rp inst to the used list. */
INIT_HLIST_NODE(&ri->uflist);
@@ -218,34 +296,25 @@ struct hlist_head * kretprobe_inst_table_head(struct task_struct *tsk)
return &kretprobe_inst_table[hash_ptr(tsk, KPROBE_HASH_BITS)];
}
-struct kretprobe_instance *get_rp_inst_tsk(struct task_struct *tk)
-{
- struct task_struct *tsk;
- struct hlist_head *head;
- struct hlist_node *node;
- struct kretprobe_instance *ri;
-
- head = &kretprobe_inst_table[hash_ptr(tk, KPROBE_HASH_BITS)];
-
- hlist_for_each_entry(ri, node, head, hlist) {
- tsk = arch_get_kprobe_task(ri->stack_addr);
- if (tsk == tk)
- return ri;
- }
- return NULL;
-}
-
/*
- * This function is called from do_exit or do_execv when task tk's stack is
- * about to be recycled. Recycle any function-return probe instances
- * associated with this task. These represent probed functions that have
- * been called but may never return.
+ * This function is called from exit_thread or flush_thread when task tk's
+ * stack is being recycled so that we can recycle any function-return probe
+ * instances associated with this task. These left over instances represent
+ * probed functions that have been called but will never return.
*/
void kprobe_flush_task(struct task_struct *tk)
{
+ struct kretprobe_instance *ri;
+ struct hlist_head *head;
+ struct hlist_node *node, *tmp;
unsigned long flags = 0;
+
spin_lock_irqsave(&kprobe_lock, flags);
- arch_kprobe_flush_task(tk);
+ head = kretprobe_inst_table_head(current);
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->task == tk)
+ recycle_rp_inst(ri);
+ }
spin_unlock_irqrestore(&kprobe_lock, flags);
}
@@ -505,9 +574,10 @@ static int __init init_kprobes(void)
INIT_HLIST_HEAD(&kretprobe_inst_table[i]);
}
- err = register_die_notifier(&kprobe_exceptions_nb);
- /* Register the trampoline probe for return probe */
- register_kprobe(&trampoline_p);
+ err = arch_init_kprobes();
+ if (!err)
+ err = register_die_notifier(&kprobe_exceptions_nb);
+
return err;
}
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c
index 1f064a63f8cf..015fb69ad94d 100644
--- a/kernel/ksysfs.c
+++ b/kernel/ksysfs.c
@@ -30,6 +30,16 @@ static ssize_t hotplug_seqnum_show(struct subsystem *subsys, char *page)
KERNEL_ATTR_RO(hotplug_seqnum);
#endif
+#ifdef CONFIG_KEXEC
+#include <asm/kexec.h>
+
+static ssize_t crash_notes_show(struct subsystem *subsys, char *page)
+{
+ return sprintf(page, "%p\n", (void *)crash_notes);
+}
+KERNEL_ATTR_RO(crash_notes);
+#endif
+
decl_subsys(kernel, NULL, NULL);
EXPORT_SYMBOL_GPL(kernel_subsys);
@@ -37,6 +47,9 @@ static struct attribute * kernel_attrs[] = {
#ifdef CONFIG_HOTPLUG
&hotplug_seqnum_attr.attr,
#endif
+#ifdef CONFIG_KEXEC
+ &crash_notes_attr.attr,
+#endif
NULL
};
diff --git a/kernel/module.c b/kernel/module.c
index a566745dde62..068e271ab3a5 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -35,6 +35,7 @@
#include <linux/notifier.h>
#include <linux/stop_machine.h>
#include <linux/device.h>
+#include <linux/string.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/cacheflush.h>
@@ -370,6 +371,43 @@ static inline void percpu_modcopy(void *pcpudst, const void *src,
#endif /* CONFIG_SMP */
#ifdef CONFIG_MODULE_UNLOAD
+#define MODINFO_ATTR(field) \
+static void setup_modinfo_##field(struct module *mod, const char *s) \
+{ \
+ mod->field = kstrdup(s, GFP_KERNEL); \
+} \
+static ssize_t show_modinfo_##field(struct module_attribute *mattr, \
+ struct module *mod, char *buffer) \
+{ \
+ return sprintf(buffer, "%s\n", mod->field); \
+} \
+static int modinfo_##field##_exists(struct module *mod) \
+{ \
+ return mod->field != NULL; \
+} \
+static void free_modinfo_##field(struct module *mod) \
+{ \
+ kfree(mod->field); \
+ mod->field = NULL; \
+} \
+static struct module_attribute modinfo_##field = { \
+ .attr = { .name = __stringify(field), .mode = 0444, \
+ .owner = THIS_MODULE }, \
+ .show = show_modinfo_##field, \
+ .setup = setup_modinfo_##field, \
+ .test = modinfo_##field##_exists, \
+ .free = free_modinfo_##field, \
+};
+
+MODINFO_ATTR(version);
+MODINFO_ATTR(srcversion);
+
+static struct module_attribute *modinfo_attrs[] = {
+ &modinfo_version,
+ &modinfo_srcversion,
+ NULL,
+};
+
/* Init the unload section of the module. */
static void module_unload_init(struct module *mod)
{
@@ -692,7 +730,7 @@ static int obsparm_copy_string(const char *val, struct kernel_param *kp)
return 0;
}
-int set_obsolete(const char *val, struct kernel_param *kp)
+static int set_obsolete(const char *val, struct kernel_param *kp)
{
unsigned int min, max;
unsigned int size, maxsize;
@@ -1031,6 +1069,32 @@ static void module_remove_refcnt_attr(struct module *mod)
}
#endif
+#ifdef CONFIG_MODULE_UNLOAD
+static int module_add_modinfo_attrs(struct module *mod)
+{
+ struct module_attribute *attr;
+ int error = 0;
+ int i;
+
+ for (i = 0; (attr = modinfo_attrs[i]) && !error; i++) {
+ if (!attr->test ||
+ (attr->test && attr->test(mod)))
+ error = sysfs_create_file(&mod->mkobj.kobj,&attr->attr);
+ }
+ return error;
+}
+
+static void module_remove_modinfo_attrs(struct module *mod)
+{
+ struct module_attribute *attr;
+ int i;
+
+ for (i = 0; (attr = modinfo_attrs[i]); i++) {
+ sysfs_remove_file(&mod->mkobj.kobj,&attr->attr);
+ attr->free(mod);
+ }
+}
+#endif
static int mod_sysfs_setup(struct module *mod,
struct kernel_param *kparam,
@@ -1056,6 +1120,12 @@ static int mod_sysfs_setup(struct module *mod,
if (err)
goto out_unreg;
+#ifdef CONFIG_MODULE_UNLOAD
+ err = module_add_modinfo_attrs(mod);
+ if (err)
+ goto out_unreg;
+#endif
+
return 0;
out_unreg:
@@ -1066,6 +1136,9 @@ out:
static void mod_kobject_remove(struct module *mod)
{
+#ifdef CONFIG_MODULE_UNLOAD
+ module_remove_modinfo_attrs(mod);
+#endif
module_remove_refcnt_attr(mod);
module_param_sysfs_remove(mod);
@@ -1311,6 +1384,23 @@ static char *get_modinfo(Elf_Shdr *sechdrs,
return NULL;
}
+#ifdef CONFIG_MODULE_UNLOAD
+static void setup_modinfo(struct module *mod, Elf_Shdr *sechdrs,
+ unsigned int infoindex)
+{
+ struct module_attribute *attr;
+ int i;
+
+ for (i = 0; (attr = modinfo_attrs[i]); i++) {
+ if (attr->setup)
+ attr->setup(mod,
+ get_modinfo(sechdrs,
+ infoindex,
+ attr->attr.name));
+ }
+}
+#endif
+
#ifdef CONFIG_KALLSYMS
int is_exported(const char *name, const struct module *mod)
{
@@ -1615,6 +1705,11 @@ static struct module *load_module(void __user *umod,
/* Set up license info based on the info section */
set_license(mod, get_modinfo(sechdrs, infoindex, "license"));
+#ifdef CONFIG_MODULE_UNLOAD
+ /* Set up MODINFO_ATTR fields */
+ setup_modinfo(mod, sechdrs, infoindex);
+#endif
+
/* Fix up syms, so that st_value is a pointer to location. */
err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex,
mod);
diff --git a/kernel/panic.c b/kernel/panic.c
index 081f7465fc8d..74ba5f3e46c7 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -18,6 +18,7 @@
#include <linux/sysrq.h>
#include <linux/interrupt.h>
#include <linux/nmi.h>
+#include <linux/kexec.h>
int panic_timeout;
int panic_on_oops;
@@ -63,6 +64,13 @@ NORET_TYPE void panic(const char * fmt, ...)
unsigned long caller = (unsigned long) __builtin_return_address(0);
#endif
+ /*
+ * It's possible to come here directly from a panic-assertion and not
+ * have preempt disabled. Some functions called from here want
+ * preempt to be disabled. No point enabling it later though...
+ */
+ preempt_disable();
+
bust_spinlocks(1);
va_start(args, fmt);
vsnprintf(buf, sizeof(buf), fmt, args);
@@ -70,7 +78,19 @@ NORET_TYPE void panic(const char * fmt, ...)
printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
bust_spinlocks(0);
+ /*
+ * If we have crashed and we have a crash kernel loaded let it handle
+ * everything else.
+ * Do we want to call this before we try to display a message?
+ */
+ crash_kexec(NULL);
+
#ifdef CONFIG_SMP
+ /*
+ * Note smp_send_stop is the usual smp shutdown function, which
+ * unfortunately means it may not be hardened to work in a panic
+ * situation.
+ */
smp_send_stop();
#endif
@@ -79,8 +99,7 @@ NORET_TYPE void panic(const char * fmt, ...)
if (!panic_blink)
panic_blink = no_blink;
- if (panic_timeout > 0)
- {
+ if (panic_timeout > 0) {
/*
* Delay timeout seconds before rebooting the machine.
* We can't use the "normal" timers since we just panicked..
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index 696387ffe49c..2c7121d9bff1 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -27,8 +27,8 @@ config PM_DEBUG
like suspend support.
config SOFTWARE_SUSPEND
- bool "Software Suspend (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PM && SWAP
+ bool "Software Suspend"
+ depends on EXPERIMENTAL && PM && SWAP && ((X86 && SMP) || ((FVR || PPC32 || X86) && !SMP))
---help---
Enable the possibility of suspending the machine.
It doesn't need APM.
@@ -72,3 +72,7 @@ config PM_STD_PARTITION
suspended image to. It will simply pick the first available swap
device.
+config SUSPEND_SMP
+ bool
+ depends on HOTPLUG_CPU && X86 && PM
+ default y
diff --git a/kernel/power/Makefile b/kernel/power/Makefile
index fbdc634135a7..2f438d0eaa13 100644
--- a/kernel/power/Makefile
+++ b/kernel/power/Makefile
@@ -3,9 +3,9 @@ ifeq ($(CONFIG_PM_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
endif
-swsusp-smp-$(CONFIG_SMP) += smp.o
-
obj-y := main.o process.o console.o pm.o
-obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o $(swsusp-smp-y) disk.o
+obj-$(CONFIG_SOFTWARE_SUSPEND) += swsusp.o disk.o
+
+obj-$(CONFIG_SUSPEND_SMP) += smp.o
obj-$(CONFIG_MAGIC_SYSRQ) += poweroff.o
diff --git a/kernel/power/disk.c b/kernel/power/disk.c
index 02b6764034dc..3ec789c6b537 100644
--- a/kernel/power/disk.c
+++ b/kernel/power/disk.c
@@ -16,6 +16,8 @@
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/fs.h>
+#include <linux/mount.h>
+
#include "power.h"
@@ -117,8 +119,8 @@ static void finish(void)
{
device_resume();
platform_finish();
- enable_nonboot_cpus();
thaw_processes();
+ enable_nonboot_cpus();
pm_restore_console();
}
@@ -131,28 +133,35 @@ static int prepare_processes(void)
sys_sync();
+ disable_nonboot_cpus();
+
if (freeze_processes()) {
error = -EBUSY;
- return error;
+ goto thaw;
}
if (pm_disk_mode == PM_DISK_PLATFORM) {
if (pm_ops && pm_ops->prepare) {
if ((error = pm_ops->prepare(PM_SUSPEND_DISK)))
- return error;
+ goto thaw;
}
}
/* Free memory before shutting down devices. */
free_some_memory();
-
return 0;
+thaw:
+ thaw_processes();
+ enable_nonboot_cpus();
+ pm_restore_console();
+ return error;
}
static void unprepare_processes(void)
{
- enable_nonboot_cpus();
+ platform_finish();
thaw_processes();
+ enable_nonboot_cpus();
pm_restore_console();
}
@@ -160,15 +169,9 @@ static int prepare_devices(void)
{
int error;
- disable_nonboot_cpus();
- if ((error = device_suspend(PMSG_FREEZE))) {
+ if ((error = device_suspend(PMSG_FREEZE)))
printk("Some devices failed to suspend\n");
- platform_finish();
- enable_nonboot_cpus();
- return error;
- }
-
- return 0;
+ return error;
}
/**
@@ -185,9 +188,9 @@ int pm_suspend_disk(void)
int error;
error = prepare_processes();
- if (!error) {
- error = prepare_devices();
- }
+ if (error)
+ return error;
+ error = prepare_devices();
if (error) {
unprepare_processes();
@@ -233,6 +236,16 @@ static int software_resume(void)
{
int error;
+ if (!swsusp_resume_device) {
+ if (!strlen(resume_file))
+ return -ENOENT;
+ swsusp_resume_device = name_to_dev_t(resume_file);
+ pr_debug("swsusp: Resume From Partition %s\n", resume_file);
+ } else {
+ pr_debug("swsusp: Resume From Partition %d:%d\n",
+ MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
+ }
+
if (noresume) {
/**
* FIXME: If noresume is specified, we need to find the partition
@@ -250,7 +263,7 @@ static int software_resume(void)
if ((error = prepare_processes())) {
swsusp_close();
- goto Cleanup;
+ goto Done;
}
pr_debug("PM: Reading swsusp image.\n");
diff --git a/kernel/power/main.c b/kernel/power/main.c
index 4cdebc972ff2..71aa0fd22007 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -19,6 +19,9 @@
#include "power.h"
+/*This is just an arbitrary number */
+#define FREE_PAGE_NUMBER (100)
+
DECLARE_MUTEX(pm_sem);
struct pm_ops * pm_ops = NULL;
@@ -49,17 +52,35 @@ void pm_set_ops(struct pm_ops * ops)
static int suspend_prepare(suspend_state_t state)
{
int error = 0;
+ unsigned int free_pages;
if (!pm_ops || !pm_ops->enter)
return -EPERM;
pm_prepare_console();
+ disable_nonboot_cpus();
+
+ if (num_online_cpus() != 1) {
+ error = -EPERM;
+ goto Enable_cpu;
+ }
+
if (freeze_processes()) {
error = -EAGAIN;
goto Thaw;
}
+ if ((free_pages = nr_free_pages()) < FREE_PAGE_NUMBER) {
+ pr_debug("PM: free some memory\n");
+ shrink_all_memory(FREE_PAGE_NUMBER - free_pages);
+ if (nr_free_pages() < FREE_PAGE_NUMBER) {
+ error = -ENOMEM;
+ printk(KERN_ERR "PM: No enough memory\n");
+ goto Thaw;
+ }
+ }
+
if (pm_ops->prepare) {
if ((error = pm_ops->prepare(state)))
goto Thaw;
@@ -75,6 +96,8 @@ static int suspend_prepare(suspend_state_t state)
pm_ops->finish(state);
Thaw:
thaw_processes();
+ Enable_cpu:
+ enable_nonboot_cpus();
pm_restore_console();
return error;
}
@@ -113,6 +136,7 @@ static void suspend_finish(suspend_state_t state)
if (pm_ops && pm_ops->finish)
pm_ops->finish(state);
thaw_processes();
+ enable_nonboot_cpus();
pm_restore_console();
}
@@ -150,12 +174,6 @@ static int enter_state(suspend_state_t state)
goto Unlock;
}
- /* Suspend is hard to get right on SMP. */
- if (num_online_cpus() != 1) {
- error = -EPERM;
- goto Unlock;
- }
-
pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
if ((error = suspend_prepare(state)))
goto Unlock;
@@ -190,7 +208,7 @@ int software_suspend(void)
int pm_suspend(suspend_state_t state)
{
- if (state > PM_SUSPEND_ON && state < PM_SUSPEND_MAX)
+ if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX)
return enter_state(state);
return -EINVAL;
}
diff --git a/kernel/power/process.c b/kernel/power/process.c
index 78d92dc6a1ed..3bd0d261818f 100644
--- a/kernel/power/process.c
+++ b/kernel/power/process.c
@@ -32,7 +32,7 @@ static inline int freezeable(struct task_struct * p)
}
/* Refrigerator is place where frozen processes are stored :-). */
-void refrigerator(unsigned long flag)
+void refrigerator(void)
{
/* Hmm, should we be allowed to suspend when there are realtime
processes around? */
@@ -41,14 +41,13 @@ void refrigerator(unsigned long flag)
current->state = TASK_UNINTERRUPTIBLE;
pr_debug("%s entered refrigerator\n", current->comm);
printk("=");
- current->flags &= ~PF_FREEZE;
+ frozen_process(current);
spin_lock_irq(&current->sighand->siglock);
recalc_sigpending(); /* We sent fake signal, clean it up */
spin_unlock_irq(&current->sighand->siglock);
- current->flags |= PF_FROZEN;
- while (current->flags & PF_FROZEN)
+ while (frozen(current))
schedule();
pr_debug("%s left refrigerator\n", current->comm);
current->state = save;
@@ -57,27 +56,23 @@ void refrigerator(unsigned long flag)
/* 0 = success, else # of processes that we failed to stop */
int freeze_processes(void)
{
- int todo;
- unsigned long start_time;
+ int todo;
+ unsigned long start_time;
struct task_struct *g, *p;
-
+ unsigned long flags;
+
printk( "Stopping tasks: " );
start_time = jiffies;
do {
todo = 0;
read_lock(&tasklist_lock);
do_each_thread(g, p) {
- unsigned long flags;
if (!freezeable(p))
continue;
- if ((p->flags & PF_FROZEN) ||
- (p->state == TASK_TRACED) ||
- (p->state == TASK_STOPPED))
+ if (frozen(p))
continue;
- /* FIXME: smp problem here: we may not access other process' flags
- without locking */
- p->flags |= PF_FREEZE;
+ freeze(p);
spin_lock_irqsave(&p->sighand->siglock, flags);
signal_wake_up(p, 0);
spin_unlock_irqrestore(&p->sighand->siglock, flags);
@@ -91,7 +86,7 @@ int freeze_processes(void)
return todo;
}
} while(todo);
-
+
printk( "|\n" );
BUG_ON(in_atomic());
return 0;
@@ -106,10 +101,7 @@ void thaw_processes(void)
do_each_thread(g, p) {
if (!freezeable(p))
continue;
- if (p->flags & PF_FROZEN) {
- p->flags &= ~PF_FROZEN;
- wake_up_process(p);
- } else
+ if (!thaw_process(p))
printk(KERN_INFO " Strange, %s not stopped\n", p->comm );
} while_each_thread(g, p);
diff --git a/kernel/power/smp.c b/kernel/power/smp.c
index 457c2302ed42..bbe23079c62c 100644
--- a/kernel/power/smp.c
+++ b/kernel/power/smp.c
@@ -13,73 +13,52 @@
#include <linux/interrupt.h>
#include <linux/suspend.h>
#include <linux/module.h>
+#include <linux/cpu.h>
#include <asm/atomic.h>
#include <asm/tlbflush.h>
-static atomic_t cpu_counter, freeze;
-
-
-static void smp_pause(void * data)
-{
- struct saved_context ctxt;
- __save_processor_state(&ctxt);
- printk("Sleeping in:\n");
- dump_stack();
- atomic_inc(&cpu_counter);
- while (atomic_read(&freeze)) {
- /* FIXME: restore takes place at random piece inside this.
- This should probably be written in assembly, and
- preserve general-purpose registers, too
-
- What about stack? We may need to move to new stack here.
-
- This should better be ran with interrupts disabled.
- */
- cpu_relax();
- barrier();
- }
- atomic_dec(&cpu_counter);
- __restore_processor_state(&ctxt);
-}
-
-static cpumask_t oldmask;
+/* This is protected by pm_sem semaphore */
+static cpumask_t frozen_cpus;
void disable_nonboot_cpus(void)
{
- oldmask = current->cpus_allowed;
- set_cpus_allowed(current, cpumask_of_cpu(0));
- printk("Freezing CPUs (at %d)", raw_smp_processor_id());
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(HZ);
- printk("...");
- BUG_ON(raw_smp_processor_id() != 0);
-
- /* FIXME: for this to work, all the CPUs must be running
- * "idle" thread (or we deadlock). Is that guaranteed? */
+ int cpu, error;
- atomic_set(&cpu_counter, 0);
- atomic_set(&freeze, 1);
- smp_call_function(smp_pause, NULL, 0, 0);
- while (atomic_read(&cpu_counter) < (num_online_cpus() - 1)) {
- cpu_relax();
- barrier();
+ error = 0;
+ cpus_clear(frozen_cpus);
+ printk("Freezing cpus ...\n");
+ for_each_online_cpu(cpu) {
+ if (cpu == 0)
+ continue;
+ error = cpu_down(cpu);
+ if (!error) {
+ cpu_set(cpu, frozen_cpus);
+ printk("CPU%d is down\n", cpu);
+ continue;
+ }
+ printk("Error taking cpu %d down: %d\n", cpu, error);
}
- printk("ok\n");
+ BUG_ON(smp_processor_id() != 0);
+ if (error)
+ panic("cpus not sleeping");
}
void enable_nonboot_cpus(void)
{
- printk("Restarting CPUs");
- atomic_set(&freeze, 0);
- while (atomic_read(&cpu_counter)) {
- cpu_relax();
- barrier();
- }
- printk("...");
- set_cpus_allowed(current, oldmask);
- schedule();
- printk("ok\n");
+ int cpu, error;
+ printk("Thawing cpus ...\n");
+ for_each_cpu_mask(cpu, frozen_cpus) {
+ error = smp_prepare_cpu(cpu);
+ if (!error)
+ error = cpu_up(cpu);
+ if (!error) {
+ printk("CPU%d is up\n", cpu);
+ continue;
+ }
+ printk("Error taking cpu %d up: %d\n", cpu, error);
+ panic("Not enough cpus");
+ }
+ cpus_clear(frozen_cpus);
}
-
diff --git a/kernel/power/swsusp.c b/kernel/power/swsusp.c
index 90b3b68dee3f..f2bc71b9fe8b 100644
--- a/kernel/power/swsusp.c
+++ b/kernel/power/swsusp.c
@@ -10,12 +10,12 @@
* This file is released under the GPLv2.
*
* I'd like to thank the following people for their work:
- *
+ *
* Pavel Machek <pavel@ucw.cz>:
* Modifications, defectiveness pointing, being with me at the very beginning,
* suspend to swap space, stop all tasks. Port to 2.4.18-ac and 2.5.17.
*
- * Steve Doddi <dirk@loth.demon.co.uk>:
+ * Steve Doddi <dirk@loth.demon.co.uk>:
* Support the possibility of hardware state restoring.
*
* Raph <grey.havens@earthling.net>:
@@ -63,6 +63,7 @@
#include <linux/console.h>
#include <linux/highmem.h>
#include <linux/bio.h>
+#include <linux/mount.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -81,14 +82,14 @@ static int nr_copy_pages_check;
extern char resume_file[];
/* Local variables that should not be affected by save */
-unsigned int nr_copy_pages __nosavedata = 0;
+static unsigned int nr_copy_pages __nosavedata = 0;
/* Suspend pagedir is allocated before final copy, therefore it
- must be freed after resume
+ must be freed after resume
Warning: this is evil. There are actually two pagedirs at time of
resume. One is "pagedir_save", which is empty frame allocated at
- time of suspend, that must be freed. Second is "pagedir_nosave",
+ time of suspend, that must be freed. Second is "pagedir_nosave",
allocated at time of resume, that travels through memory not to
collide with anything.
@@ -132,7 +133,7 @@ static int mark_swapfiles(swp_entry_t prev)
{
int error;
- rw_swap_page_sync(READ,
+ rw_swap_page_sync(READ,
swp_entry(root_swap, 0),
virt_to_page((unsigned long)&swsusp_header));
if (!memcmp("SWAP-SPACE",swsusp_header.sig, 10) ||
@@ -140,7 +141,7 @@ static int mark_swapfiles(swp_entry_t prev)
memcpy(swsusp_header.orig_sig,swsusp_header.sig, 10);
memcpy(swsusp_header.sig,SWSUSP_SIG, 10);
swsusp_header.swsusp_info = prev;
- error = rw_swap_page_sync(WRITE,
+ error = rw_swap_page_sync(WRITE,
swp_entry(root_swap, 0),
virt_to_page((unsigned long)
&swsusp_header));
@@ -174,22 +175,22 @@ static int is_resume_device(const struct swap_info_struct *swap_info)
static int swsusp_swap_check(void) /* This is called before saving image */
{
int i, len;
-
+
len=strlen(resume_file);
root_swap = 0xFFFF;
-
+
swap_list_lock();
- for(i=0; i<MAX_SWAPFILES; i++) {
+ for (i=0; i<MAX_SWAPFILES; i++) {
if (swap_info[i].flags == 0) {
swapfile_used[i]=SWAPFILE_UNUSED;
} else {
- if(!len) {
+ if (!len) {
printk(KERN_WARNING "resume= option should be used to set suspend device" );
- if(root_swap == 0xFFFF) {
+ if (root_swap == 0xFFFF) {
swapfile_used[i] = SWAPFILE_SUSPEND;
root_swap = i;
} else
- swapfile_used[i] = SWAPFILE_IGNORED;
+ swapfile_used[i] = SWAPFILE_IGNORED;
} else {
/* we ignore all swap devices that are not the resume_file */
if (is_resume_device(&swap_info[i])) {
@@ -209,15 +210,15 @@ static int swsusp_swap_check(void) /* This is called before saving image */
* This is called after saving image so modification
* will be lost after resume... and that's what we want.
* we make the device unusable. A new call to
- * lock_swapdevices can unlock the devices.
+ * lock_swapdevices can unlock the devices.
*/
static void lock_swapdevices(void)
{
int i;
swap_list_lock();
- for(i = 0; i< MAX_SWAPFILES; i++)
- if(swapfile_used[i] == SWAPFILE_IGNORED) {
+ for (i = 0; i< MAX_SWAPFILES; i++)
+ if (swapfile_used[i] == SWAPFILE_IGNORED) {
swap_info[i].flags ^= 0xFF;
}
swap_list_unlock();
@@ -229,7 +230,7 @@ static void lock_swapdevices(void)
* @loc: Place to store the entry we used.
*
* Allocate a new swap entry and 'sync' it. Note we discard -EIO
- * errors. That is an artifact left over from swsusp. It did not
+ * errors. That is an artifact left over from swsusp. It did not
* check the return of rw_swap_page_sync() at all, since most pages
* written back to swap would return -EIO.
* This is a partial improvement, since we will at least return other
@@ -241,7 +242,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
int error = 0;
entry = get_swap_page();
- if (swp_offset(entry) &&
+ if (swp_offset(entry) &&
swapfile_used[swp_type(entry)] == SWAPFILE_SUSPEND) {
error = rw_swap_page_sync(WRITE, entry,
virt_to_page(addr));
@@ -257,7 +258,7 @@ static int write_page(unsigned long addr, swp_entry_t * loc)
/**
* data_free - Free the swap entries used by the saved image.
*
- * Walk the list of used swap entries and free each one.
+ * Walk the list of used swap entries and free each one.
* This is only used for cleanup when suspend fails.
*/
static void data_free(void)
@@ -290,7 +291,7 @@ static int data_write(void)
mod = 1;
printk( "Writing data to swap (%d pages)... ", nr_copy_pages );
- for_each_pbe(p, pagedir_nosave) {
+ for_each_pbe (p, pagedir_nosave) {
if (!(i%mod))
printk( "\b\b\b\b%3d%%", i / mod );
if ((error = write_page(p->address, &(p->swap_address))))
@@ -335,7 +336,7 @@ static int close_swap(void)
dump_info();
error = write_page((unsigned long)&swsusp_info, &entry);
- if (!error) {
+ if (!error) {
printk( "S" );
error = mark_swapfiles(entry);
printk( "|\n" );
@@ -370,7 +371,7 @@ static int write_pagedir(void)
struct pbe * pbe;
printk( "Writing pagedir...");
- for_each_pb_page(pbe, pagedir_nosave) {
+ for_each_pb_page (pbe, pagedir_nosave) {
if ((error = write_page((unsigned long)pbe, &swsusp_info.pagedir[n++])))
return error;
}
@@ -472,7 +473,7 @@ static int save_highmem(void)
int res = 0;
pr_debug("swsusp: Saving Highmem\n");
- for_each_zone(zone) {
+ for_each_zone (zone) {
if (is_highmem(zone))
res = save_highmem_zone(zone);
if (res)
@@ -547,7 +548,7 @@ static void count_data_pages(void)
nr_copy_pages = 0;
- for_each_zone(zone) {
+ for_each_zone (zone) {
if (is_highmem(zone))
continue;
mark_free_pages(zone);
@@ -562,9 +563,9 @@ static void copy_data_pages(void)
struct zone *zone;
unsigned long zone_pfn;
struct pbe * pbe = pagedir_nosave;
-
+
pr_debug("copy_data_pages(): pages to copy: %d\n", nr_copy_pages);
- for_each_zone(zone) {
+ for_each_zone (zone) {
if (is_highmem(zone))
continue;
mark_free_pages(zone);
@@ -702,7 +703,7 @@ static void free_image_pages(void)
{
struct pbe * p;
- for_each_pbe(p, pagedir_save) {
+ for_each_pbe (p, pagedir_save) {
if (p->address) {
ClearPageNosave(virt_to_page(p->address));
free_page(p->address);
@@ -719,7 +720,7 @@ static int alloc_image_pages(void)
{
struct pbe * p;
- for_each_pbe(p, pagedir_save) {
+ for_each_pbe (p, pagedir_save) {
p->address = get_zeroed_page(GFP_ATOMIC | __GFP_COLD);
if (!p->address)
return -ENOMEM;
@@ -740,7 +741,7 @@ void swsusp_free(void)
/**
* enough_free_mem - Make sure we enough free memory to snapshot.
*
- * Returns TRUE or FALSE after checking the number of available
+ * Returns TRUE or FALSE after checking the number of available
* free pages.
*/
@@ -758,11 +759,11 @@ static int enough_free_mem(void)
/**
* enough_swap - Make sure we have enough swap to save the image.
*
- * Returns TRUE or FALSE after checking the total amount of swap
+ * Returns TRUE or FALSE after checking the total amount of swap
* space avaiable.
*
* FIXME: si_swapinfo(&i) returns all swap devices information.
- * We should only consider resume_device.
+ * We should only consider resume_device.
*/
static int enough_swap(void)
@@ -781,18 +782,18 @@ static int swsusp_alloc(void)
{
int error;
+ pagedir_nosave = NULL;
+ nr_copy_pages = calc_nr(nr_copy_pages);
+
pr_debug("suspend: (pages needed: %d + %d free: %d)\n",
nr_copy_pages, PAGES_FOR_IO, nr_free_pages());
- pagedir_nosave = NULL;
if (!enough_free_mem())
return -ENOMEM;
if (!enough_swap())
return -ENOSPC;
- nr_copy_pages = calc_nr(nr_copy_pages);
-
if (!(pagedir_save = alloc_pagedir(nr_copy_pages))) {
printk(KERN_ERR "suspend: Allocating pagedir failed.\n");
return -ENOMEM;
@@ -827,8 +828,8 @@ static int suspend_prepare_image(void)
error = swsusp_alloc();
if (error)
return error;
-
- /* During allocating of suspend pagedir, new cold pages may appear.
+
+ /* During allocating of suspend pagedir, new cold pages may appear.
* Kill them.
*/
drain_local_pages();
@@ -869,13 +870,6 @@ extern asmlinkage int swsusp_arch_resume(void);
asmlinkage int swsusp_save(void)
{
- int error = 0;
-
- if ((error = swsusp_swap_check())) {
- printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
- "swapon -a!\n");
- return error;
- }
return suspend_prepare_image();
}
@@ -892,14 +886,20 @@ int swsusp_suspend(void)
* at resume time, and evil weirdness ensues.
*/
if ((error = device_power_down(PMSG_FREEZE))) {
- printk(KERN_ERR "Some devices failed to power down, aborting suspend\n");
local_irq_enable();
- swsusp_free();
return error;
}
+
+ if ((error = swsusp_swap_check())) {
+ printk(KERN_ERR "swsusp: FATAL: cannot find swap device, try "
+ "swapon -a!\n");
+ local_irq_enable();
+ return error;
+ }
+
save_processor_state();
if ((error = swsusp_arch_suspend()))
- swsusp_free();
+ printk("Error %d suspending\n", error);
/* Restore control flow magically appears here */
restore_processor_state();
BUG_ON (nr_copy_pages_check != nr_copy_pages);
@@ -929,21 +929,6 @@ int swsusp_resume(void)
return error;
}
-/* More restore stuff */
-
-/*
- * Returns true if given address/order collides with any orig_address
- */
-static int does_collide_order(unsigned long addr, int order)
-{
- int i;
-
- for (i=0; i < (1<<order); i++)
- if (!PageNosaveFree(virt_to_page(addr + i * PAGE_SIZE)))
- return 1;
- return 0;
-}
-
/**
* On resume, for storing the PBE list and the image,
* we can only use memory pages that do not conflict with the pages
@@ -973,7 +958,7 @@ static unsigned long get_usable_page(unsigned gfp_mask)
unsigned long m;
m = get_zeroed_page(gfp_mask);
- while (does_collide_order(m, 0)) {
+ while (!PageNosaveFree(virt_to_page(m))) {
eat_page((void *)m);
m = get_zeroed_page(gfp_mask);
if (!m)
@@ -1045,7 +1030,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
/* Set page flags */
- for_each_zone(zone) {
+ for_each_zone (zone) {
for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn)
SetPageNosaveFree(pfn_to_page(zone_pfn +
zone->zone_start_pfn));
@@ -1061,7 +1046,7 @@ static struct pbe * swsusp_pagedir_relocate(struct pbe *pblist)
/* Relocate colliding pages */
for_each_pb_page (pbpage, pblist) {
- if (does_collide_order((unsigned long)pbpage, 0)) {
+ if (!PageNosaveFree(virt_to_page((unsigned long)pbpage))) {
m = (void *)get_usable_page(GFP_ATOMIC | __GFP_COLD);
if (!m) {
error = -ENOMEM;
@@ -1181,9 +1166,9 @@ static int bio_write_page(pgoff_t page_off, void * page)
static const char * sanity_check(void)
{
dump_info();
- if(swsusp_info.version_code != LINUX_VERSION_CODE)
+ if (swsusp_info.version_code != LINUX_VERSION_CODE)
return "kernel version";
- if(swsusp_info.num_physpages != num_physpages)
+ if (swsusp_info.num_physpages != num_physpages)
return "memory size";
if (strcmp(swsusp_info.uts.sysname,system_utsname.sysname))
return "system type";
@@ -1193,8 +1178,10 @@ static const char * sanity_check(void)
return "version";
if (strcmp(swsusp_info.uts.machine,system_utsname.machine))
return "machine";
+#if 0
if(swsusp_info.cpus != num_online_cpus())
return "number of cpus";
+#endif
return NULL;
}
@@ -1274,8 +1261,6 @@ static int data_read(struct pbe *pblist)
return error;
}
-extern dev_t name_to_dev_t(const char *line);
-
/**
* read_pagedir - Read page backup list pages from swap
*/
@@ -1369,16 +1354,6 @@ int swsusp_check(void)
{
int error;
- if (!swsusp_resume_device) {
- if (!strlen(resume_file))
- return -ENOENT;
- swsusp_resume_device = name_to_dev_t(resume_file);
- pr_debug("swsusp: Resume From Partition %s\n", resume_file);
- } else {
- pr_debug("swsusp: Resume From Partition %d:%d\n",
- MAJOR(swsusp_resume_device), MINOR(swsusp_resume_device));
- }
-
resume_bdev = open_by_devnum(swsusp_resume_device, FMODE_READ);
if (!IS_ERR(resume_bdev)) {
set_blocksize(resume_bdev, PAGE_SIZE);
diff --git a/kernel/printk.c b/kernel/printk.c
index 3a442bfb8bee..5092397fac29 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -588,8 +588,7 @@ asmlinkage int vprintk(const char *fmt, va_list args)
log_level_unknown = 1;
}
- if (!cpu_online(smp_processor_id()) &&
- system_state != SYSTEM_RUNNING) {
+ if (!cpu_online(smp_processor_id())) {
/*
* Some console drivers may assume that per-cpu resources have
* been allocated. So don't allow them to be called by this
diff --git a/kernel/profile.c b/kernel/profile.c
index ad8cbb75ffa2..f89248e6d704 100644
--- a/kernel/profile.c
+++ b/kernel/profile.c
@@ -35,11 +35,11 @@ struct profile_hit {
#define NR_PROFILE_GRP (NR_PROFILE_HIT/PROFILE_GRPSZ)
/* Oprofile timer tick hook */
-int (*timer_hook)(struct pt_regs *);
+int (*timer_hook)(struct pt_regs *) __read_mostly;
static atomic_t *prof_buffer;
static unsigned long prof_len, prof_shift;
-static int prof_on;
+static int prof_on __read_mostly;
static cpumask_t prof_cpu_mask = CPU_MASK_ALL;
#ifdef CONFIG_SMP
static DEFINE_PER_CPU(struct profile_hit *[2], cpu_profile_hits);
diff --git a/kernel/resource.c b/kernel/resource.c
index 52f696f11adf..26967e042201 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -263,7 +263,7 @@ static int find_resource(struct resource *root, struct resource *new,
new->start = min;
if (new->end > max)
new->end = max;
- new->start = (new->start + align - 1) & ~(align - 1);
+ new->start = ALIGN(new->start, align);
if (alignf)
alignf(alignf_data, new, size, align);
if (new->start < new->end && new->end - new->start >= size - 1) {
diff --git a/kernel/sched.c b/kernel/sched.c
index 76080d142e3d..4107db0dc091 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -166,7 +166,7 @@
#define SCALE_PRIO(x, prio) \
max(x * (MAX_PRIO - prio) / (MAX_USER_PRIO/2), MIN_TIMESLICE)
-static inline unsigned int task_timeslice(task_t *p)
+static unsigned int task_timeslice(task_t *p)
{
if (p->static_prio < NICE_TO_PRIO(0))
return SCALE_PRIO(DEF_TIMESLICE*4, p->static_prio);
@@ -206,7 +206,7 @@ struct runqueue {
*/
unsigned long nr_running;
#ifdef CONFIG_SMP
- unsigned long cpu_load;
+ unsigned long cpu_load[3];
#endif
unsigned long long nr_switches;
@@ -260,22 +260,86 @@ struct runqueue {
static DEFINE_PER_CPU(struct runqueue, runqueues);
+/*
+ * The domain tree (rq->sd) is protected by RCU's quiescent state transition.
+ * See detach_destroy_domains: synchronize_sched for details.
+ *
+ * The domain tree of any CPU may only be accessed from within
+ * preempt-disabled sections.
+ */
#define for_each_domain(cpu, domain) \
- for (domain = cpu_rq(cpu)->sd; domain; domain = domain->parent)
+for (domain = rcu_dereference(cpu_rq(cpu)->sd); domain; domain = domain->parent)
#define cpu_rq(cpu) (&per_cpu(runqueues, (cpu)))
#define this_rq() (&__get_cpu_var(runqueues))
#define task_rq(p) cpu_rq(task_cpu(p))
#define cpu_curr(cpu) (cpu_rq(cpu)->curr)
-/*
- * Default context-switch locking:
- */
#ifndef prepare_arch_switch
-# define prepare_arch_switch(rq, next) do { } while (0)
-# define finish_arch_switch(rq, next) spin_unlock_irq(&(rq)->lock)
-# define task_running(rq, p) ((rq)->curr == (p))
+# define prepare_arch_switch(next) do { } while (0)
+#endif
+#ifndef finish_arch_switch
+# define finish_arch_switch(prev) do { } while (0)
+#endif
+
+#ifndef __ARCH_WANT_UNLOCKED_CTXSW
+static inline int task_running(runqueue_t *rq, task_t *p)
+{
+ return rq->curr == p;
+}
+
+static inline void prepare_lock_switch(runqueue_t *rq, task_t *next)
+{
+}
+
+static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
+{
+ spin_unlock_irq(&rq->lock);
+}
+
+#else /* __ARCH_WANT_UNLOCKED_CTXSW */
+static inline int task_running(runqueue_t *rq, task_t *p)
+{
+#ifdef CONFIG_SMP
+ return p->oncpu;
+#else
+ return rq->curr == p;
+#endif
+}
+
+static inline void prepare_lock_switch(runqueue_t *rq, task_t *next)
+{
+#ifdef CONFIG_SMP
+ /*
+ * We can optimise this out completely for !SMP, because the
+ * SMP rebalancing from interrupt is the only thing that cares
+ * here.
+ */
+ next->oncpu = 1;
#endif
+#ifdef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+ spin_unlock_irq(&rq->lock);
+#else
+ spin_unlock(&rq->lock);
+#endif
+}
+
+static inline void finish_lock_switch(runqueue_t *rq, task_t *prev)
+{
+#ifdef CONFIG_SMP
+ /*
+ * After ->oncpu is cleared, the task can be moved to a different CPU.
+ * We must ensure this doesn't happen until the switch is completely
+ * finished.
+ */
+ smp_wmb();
+ prev->oncpu = 0;
+#endif
+#ifndef __ARCH_WANT_INTERRUPTS_ON_CTXSW
+ local_irq_enable();
+#endif
+}
+#endif /* __ARCH_WANT_UNLOCKED_CTXSW */
/*
* task_rq_lock - lock the runqueue a given task resides on and disable
@@ -309,7 +373,7 @@ static inline void task_rq_unlock(runqueue_t *rq, unsigned long *flags)
* bump this up when changing the output format or the meaning of an existing
* format, so that tools can adapt (or abort)
*/
-#define SCHEDSTAT_VERSION 11
+#define SCHEDSTAT_VERSION 12
static int show_schedstat(struct seq_file *seq, void *v)
{
@@ -338,6 +402,7 @@ static int show_schedstat(struct seq_file *seq, void *v)
#ifdef CONFIG_SMP
/* domain-specific stats */
+ preempt_disable();
for_each_domain(cpu, sd) {
enum idle_type itype;
char mask_str[NR_CPUS];
@@ -356,11 +421,13 @@ static int show_schedstat(struct seq_file *seq, void *v)
sd->lb_nobusyq[itype],
sd->lb_nobusyg[itype]);
}
- seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu\n",
+ seq_printf(seq, " %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu\n",
sd->alb_cnt, sd->alb_failed, sd->alb_pushed,
- sd->sbe_pushed, sd->sbe_attempts,
+ sd->sbe_cnt, sd->sbe_balanced, sd->sbe_pushed,
+ sd->sbf_cnt, sd->sbf_balanced, sd->sbf_pushed,
sd->ttwu_wake_remote, sd->ttwu_move_affine, sd->ttwu_move_balance);
}
+ preempt_enable();
#endif
}
return 0;
@@ -414,22 +481,6 @@ static inline runqueue_t *this_rq_lock(void)
return rq;
}
-#ifdef CONFIG_SCHED_SMT
-static int cpu_and_siblings_are_idle(int cpu)
-{
- int sib;
- for_each_cpu_mask(sib, cpu_sibling_map[cpu]) {
- if (idle_cpu(sib))
- continue;
- return 0;
- }
-
- return 1;
-}
-#else
-#define cpu_and_siblings_are_idle(A) idle_cpu(A)
-#endif
-
#ifdef CONFIG_SCHEDSTATS
/*
* Called when a process is dequeued from the active array and given
@@ -622,7 +673,7 @@ static inline void __activate_idle_task(task_t *p, runqueue_t *rq)
rq->nr_running++;
}
-static void recalc_task_prio(task_t *p, unsigned long long now)
+static int recalc_task_prio(task_t *p, unsigned long long now)
{
/* Caller must always ensure 'now >= p->timestamp' */
unsigned long long __sleep_time = now - p->timestamp;
@@ -681,7 +732,7 @@ static void recalc_task_prio(task_t *p, unsigned long long now)
}
}
- p->prio = effective_prio(p);
+ return effective_prio(p);
}
/*
@@ -704,7 +755,7 @@ static void activate_task(task_t *p, runqueue_t *rq, int local)
}
#endif
- recalc_task_prio(p, now);
+ p->prio = recalc_task_prio(p, now);
/*
* This checks to make sure it's not an uninterruptible task
@@ -782,22 +833,12 @@ inline int task_curr(const task_t *p)
}
#ifdef CONFIG_SMP
-enum request_type {
- REQ_MOVE_TASK,
- REQ_SET_DOMAIN,
-};
-
typedef struct {
struct list_head list;
- enum request_type type;
- /* For REQ_MOVE_TASK */
task_t *task;
int dest_cpu;
- /* For REQ_SET_DOMAIN */
- struct sched_domain *sd;
-
struct completion done;
} migration_req_t;
@@ -819,7 +860,6 @@ static int migrate_task(task_t *p, int dest_cpu, migration_req_t *req)
}
init_completion(&req->done);
- req->type = REQ_MOVE_TASK;
req->task = p;
req->dest_cpu = dest_cpu;
list_add(&req->list, &rq->migration_queue);
@@ -886,26 +926,154 @@ void kick_process(task_t *p)
* We want to under-estimate the load of migration sources, to
* balance conservatively.
*/
-static inline unsigned long source_load(int cpu)
+static inline unsigned long source_load(int cpu, int type)
{
runqueue_t *rq = cpu_rq(cpu);
unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+ if (type == 0)
+ return load_now;
- return min(rq->cpu_load, load_now);
+ return min(rq->cpu_load[type-1], load_now);
}
/*
* Return a high guess at the load of a migration-target cpu
*/
-static inline unsigned long target_load(int cpu)
+static inline unsigned long target_load(int cpu, int type)
{
runqueue_t *rq = cpu_rq(cpu);
unsigned long load_now = rq->nr_running * SCHED_LOAD_SCALE;
+ if (type == 0)
+ return load_now;
- return max(rq->cpu_load, load_now);
+ return max(rq->cpu_load[type-1], load_now);
}
-#endif
+/*
+ * find_idlest_group finds and returns the least busy CPU group within the
+ * domain.
+ */
+static struct sched_group *
+find_idlest_group(struct sched_domain *sd, struct task_struct *p, int this_cpu)
+{
+ struct sched_group *idlest = NULL, *this = NULL, *group = sd->groups;
+ unsigned long min_load = ULONG_MAX, this_load = 0;
+ int load_idx = sd->forkexec_idx;
+ int imbalance = 100 + (sd->imbalance_pct-100)/2;
+
+ do {
+ unsigned long load, avg_load;
+ int local_group;
+ int i;
+
+ local_group = cpu_isset(this_cpu, group->cpumask);
+ /* XXX: put a cpus allowed check */
+
+ /* Tally up the load of all CPUs in the group */
+ avg_load = 0;
+
+ for_each_cpu_mask(i, group->cpumask) {
+ /* Bias balancing toward cpus of our domain */
+ if (local_group)
+ load = source_load(i, load_idx);
+ else
+ load = target_load(i, load_idx);
+
+ avg_load += load;
+ }
+
+ /* Adjust by relative CPU power of the group */
+ avg_load = (avg_load * SCHED_LOAD_SCALE) / group->cpu_power;
+
+ if (local_group) {
+ this_load = avg_load;
+ this = group;
+ } else if (avg_load < min_load) {
+ min_load = avg_load;
+ idlest = group;
+ }
+ group = group->next;
+ } while (group != sd->groups);
+
+ if (!idlest || 100*this_load < imbalance*min_load)
+ return NULL;
+ return idlest;
+}
+
+/*
+ * find_idlest_queue - find the idlest runqueue among the cpus in group.
+ */
+static int find_idlest_cpu(struct sched_group *group, int this_cpu)
+{
+ unsigned long load, min_load = ULONG_MAX;
+ int idlest = -1;
+ int i;
+
+ for_each_cpu_mask(i, group->cpumask) {
+ load = source_load(i, 0);
+
+ if (load < min_load || (load == min_load && i == this_cpu)) {
+ min_load = load;
+ idlest = i;
+ }
+ }
+
+ return idlest;
+}
+
+/*
+ * sched_balance_self: balance the current task (running on cpu) in domains
+ * that have the 'flag' flag set. In practice, this is SD_BALANCE_FORK and
+ * SD_BALANCE_EXEC.
+ *
+ * Balance, ie. select the least loaded group.
+ *
+ * Returns the target CPU number, or the same CPU if no balancing is needed.
+ *
+ * preempt must be disabled.
+ */
+static int sched_balance_self(int cpu, int flag)
+{
+ struct task_struct *t = current;
+ struct sched_domain *tmp, *sd = NULL;
+
+ for_each_domain(cpu, tmp)
+ if (tmp->flags & flag)
+ sd = tmp;
+
+ while (sd) {
+ cpumask_t span;
+ struct sched_group *group;
+ int new_cpu;
+ int weight;
+
+ span = sd->span;
+ group = find_idlest_group(sd, t, cpu);
+ if (!group)
+ goto nextlevel;
+
+ new_cpu = find_idlest_cpu(group, cpu);
+ if (new_cpu == -1 || new_cpu == cpu)
+ goto nextlevel;
+
+ /* Now try balancing at a lower domain level */
+ cpu = new_cpu;
+nextlevel:
+ sd = NULL;
+ weight = cpus_weight(span);
+ for_each_domain(cpu, tmp) {
+ if (weight <= cpus_weight(tmp->span))
+ break;
+ if (tmp->flags & flag)
+ sd = tmp;
+ }
+ /* while loop will break here if sd == NULL */
+ }
+
+ return cpu;
+}
+
+#endif /* CONFIG_SMP */
/*
* wake_idle() will wake a task on an idle cpu if task->cpu is
@@ -927,14 +1095,14 @@ static int wake_idle(int cpu, task_t *p)
for_each_domain(cpu, sd) {
if (sd->flags & SD_WAKE_IDLE) {
- cpus_and(tmp, sd->span, cpu_online_map);
- cpus_and(tmp, tmp, p->cpus_allowed);
+ cpus_and(tmp, sd->span, p->cpus_allowed);
for_each_cpu_mask(i, tmp) {
if (idle_cpu(i))
return i;
}
}
- else break;
+ else
+ break;
}
return cpu;
}
@@ -967,7 +1135,7 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
runqueue_t *rq;
#ifdef CONFIG_SMP
unsigned long load, this_load;
- struct sched_domain *sd;
+ struct sched_domain *sd, *this_sd = NULL;
int new_cpu;
#endif
@@ -986,70 +1154,69 @@ static int try_to_wake_up(task_t * p, unsigned int state, int sync)
if (unlikely(task_running(rq, p)))
goto out_activate;
-#ifdef CONFIG_SCHEDSTATS
+ new_cpu = cpu;
+
schedstat_inc(rq, ttwu_cnt);
if (cpu == this_cpu) {
schedstat_inc(rq, ttwu_local);
- } else {
- for_each_domain(this_cpu, sd) {
- if (cpu_isset(cpu, sd->span)) {
- schedstat_inc(sd, ttwu_wake_remote);
- break;
- }
+ goto out_set_cpu;
+ }
+
+ for_each_domain(this_cpu, sd) {
+ if (cpu_isset(cpu, sd->span)) {
+ schedstat_inc(sd, ttwu_wake_remote);
+ this_sd = sd;
+ break;
}
}
-#endif
- new_cpu = cpu;
- if (cpu == this_cpu || unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
+ if (unlikely(!cpu_isset(this_cpu, p->cpus_allowed)))
goto out_set_cpu;
- load = source_load(cpu);
- this_load = target_load(this_cpu);
-
/*
- * If sync wakeup then subtract the (maximum possible) effect of
- * the currently running task from the load of the current CPU:
+ * Check for affine wakeup and passive balancing possibilities.
*/
- if (sync)
- this_load -= SCHED_LOAD_SCALE;
+ if (this_sd) {
+ int idx = this_sd->wake_idx;
+ unsigned int imbalance;
- /* Don't pull the task off an idle CPU to a busy one */
- if (load < SCHED_LOAD_SCALE/2 && this_load > SCHED_LOAD_SCALE/2)
- goto out_set_cpu;
+ imbalance = 100 + (this_sd->imbalance_pct - 100) / 2;
- new_cpu = this_cpu; /* Wake to this CPU if we can */
+ load = source_load(cpu, idx);
+ this_load = target_load(this_cpu, idx);
- /*
- * Scan domains for affine wakeup and passive balancing
- * possibilities.
- */
- for_each_domain(this_cpu, sd) {
- unsigned int imbalance;
- /*
- * Start passive balancing when half the imbalance_pct
- * limit is reached.
- */
- imbalance = sd->imbalance_pct + (sd->imbalance_pct - 100) / 2;
+ new_cpu = this_cpu; /* Wake to this CPU if we can */
- if ((sd->flags & SD_WAKE_AFFINE) &&
- !task_hot(p, rq->timestamp_last_tick, sd)) {
+ if (this_sd->flags & SD_WAKE_AFFINE) {
+ unsigned long tl = this_load;
/*
- * This domain has SD_WAKE_AFFINE and p is cache cold
- * in this domain.
+ * If sync wakeup then subtract the (maximum possible)
+ * effect of the currently running task from the load
+ * of the current CPU:
*/
- if (cpu_isset(cpu, sd->span)) {
- schedstat_inc(sd, ttwu_move_affine);
+ if (sync)
+ tl -= SCHED_LOAD_SCALE;
+
+ if ((tl <= load &&
+ tl + target_load(cpu, idx) <= SCHED_LOAD_SCALE) ||
+ 100*(tl + SCHED_LOAD_SCALE) <= imbalance*load) {
+ /*
+ * This domain has SD_WAKE_AFFINE and
+ * p is cache cold in this domain, and
+ * there is no bad imbalance.
+ */
+ schedstat_inc(this_sd, ttwu_move_affine);
goto out_set_cpu;
}
- } else if ((sd->flags & SD_WAKE_BALANCE) &&
- imbalance*this_load <= 100*load) {
- /*
- * This domain has SD_WAKE_BALANCE and there is
- * an imbalance.
- */
- if (cpu_isset(cpu, sd->span)) {
- schedstat_inc(sd, ttwu_move_balance);
+ }
+
+ /*
+ * Start passive balancing when half the imbalance_pct
+ * limit is reached.
+ */
+ if (this_sd->flags & SD_WAKE_BALANCE) {
+ if (imbalance*this_load <= 100*load) {
+ schedstat_inc(this_sd, ttwu_move_balance);
goto out_set_cpu;
}
}
@@ -1120,17 +1287,19 @@ int fastcall wake_up_state(task_t *p, unsigned int state)
return try_to_wake_up(p, state, 0);
}
-#ifdef CONFIG_SMP
-static int find_idlest_cpu(struct task_struct *p, int this_cpu,
- struct sched_domain *sd);
-#endif
-
/*
* Perform scheduler related setup for a newly forked process p.
* p is forked by current.
*/
-void fastcall sched_fork(task_t *p)
+void fastcall sched_fork(task_t *p, int clone_flags)
{
+ int cpu = get_cpu();
+
+#ifdef CONFIG_SMP
+ cpu = sched_balance_self(cpu, SD_BALANCE_FORK);
+#endif
+ set_task_cpu(p, cpu);
+
/*
* We mark the process as running here, but have not actually
* inserted it onto the runqueue yet. This guarantees that
@@ -1140,17 +1309,14 @@ void fastcall sched_fork(task_t *p)
p->state = TASK_RUNNING;
INIT_LIST_HEAD(&p->run_list);
p->array = NULL;
- spin_lock_init(&p->switch_lock);
#ifdef CONFIG_SCHEDSTATS
memset(&p->sched_info, 0, sizeof(p->sched_info));
#endif
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+ p->oncpu = 0;
+#endif
#ifdef CONFIG_PREEMPT
- /*
- * During context-switch we hold precisely one spinlock, which
- * schedule_tail drops. (in the common case it's this_rq()->lock,
- * but it also can be p->switch_lock.) So we compensate with a count
- * of 1. Also, we want to start with kernel preemption disabled.
- */
+ /* Want to start with kernel preemption disabled. */
p->thread_info->preempt_count = 1;
#endif
/*
@@ -1174,12 +1340,10 @@ void fastcall sched_fork(task_t *p)
* runqueue lock is not a problem.
*/
current->time_slice = 1;
- preempt_disable();
scheduler_tick();
- local_irq_enable();
- preempt_enable();
- } else
- local_irq_enable();
+ }
+ local_irq_enable();
+ put_cpu();
}
/*
@@ -1196,10 +1360,9 @@ void fastcall wake_up_new_task(task_t * p, unsigned long clone_flags)
runqueue_t *rq, *this_rq;
rq = task_rq_lock(p, &flags);
- cpu = task_cpu(p);
- this_cpu = smp_processor_id();
-
BUG_ON(p->state != TASK_RUNNING);
+ this_cpu = smp_processor_id();
+ cpu = task_cpu(p);
/*
* We decrease the sleep average of forking parents
@@ -1296,22 +1459,40 @@ void fastcall sched_exit(task_t * p)
}
/**
+ * prepare_task_switch - prepare to switch tasks
+ * @rq: the runqueue preparing to switch
+ * @next: the task we are going to switch to.
+ *
+ * This is called with the rq lock held and interrupts off. It must
+ * be paired with a subsequent finish_task_switch after the context
+ * switch.
+ *
+ * prepare_task_switch sets up locking and calls architecture specific
+ * hooks.
+ */
+static inline void prepare_task_switch(runqueue_t *rq, task_t *next)
+{
+ prepare_lock_switch(rq, next);
+ prepare_arch_switch(next);
+}
+
+/**
* finish_task_switch - clean up after a task-switch
* @prev: the thread we just switched away from.
*
- * We enter this with the runqueue still locked, and finish_arch_switch()
- * will unlock it along with doing any other architecture-specific cleanup
- * actions.
+ * finish_task_switch must be called after the context switch, paired
+ * with a prepare_task_switch call before the context switch.
+ * finish_task_switch will reconcile locking set up by prepare_task_switch,
+ * and do any other architecture-specific cleanup actions.
*
* Note that we may have delayed dropping an mm in context_switch(). If
* so, we finish that here outside of the runqueue lock. (Doing it
* with the lock held can cause deadlocks; see schedule() for
* details.)
*/
-static inline void finish_task_switch(task_t *prev)
+static inline void finish_task_switch(runqueue_t *rq, task_t *prev)
__releases(rq->lock)
{
- runqueue_t *rq = this_rq();
struct mm_struct *mm = rq->prev_mm;
unsigned long prev_task_flags;
@@ -1329,7 +1510,8 @@ static inline void finish_task_switch(task_t *prev)
* Manfred Spraul <manfred@colorfullife.com>
*/
prev_task_flags = prev->flags;
- finish_arch_switch(rq, prev);
+ finish_arch_switch(prev);
+ finish_lock_switch(rq, prev);
if (mm)
mmdrop(mm);
if (unlikely(prev_task_flags & PF_DEAD))
@@ -1343,8 +1525,12 @@ static inline void finish_task_switch(task_t *prev)
asmlinkage void schedule_tail(task_t *prev)
__releases(rq->lock)
{
- finish_task_switch(prev);
-
+ runqueue_t *rq = this_rq();
+ finish_task_switch(rq, prev);
+#ifdef __ARCH_WANT_UNLOCKED_CTXSW
+ /* In this case, finish_task_switch does not reenable preemption */
+ preempt_enable();
+#endif
if (current->set_child_tid)
put_user(current->pid, current->set_child_tid);
}
@@ -1494,51 +1680,6 @@ static void double_lock_balance(runqueue_t *this_rq, runqueue_t *busiest)
}
/*
- * find_idlest_cpu - find the least busy runqueue.
- */
-static int find_idlest_cpu(struct task_struct *p, int this_cpu,
- struct sched_domain *sd)
-{
- unsigned long load, min_load, this_load;
- int i, min_cpu;
- cpumask_t mask;
-
- min_cpu = UINT_MAX;
- min_load = ULONG_MAX;
-
- cpus_and(mask, sd->span, p->cpus_allowed);
-
- for_each_cpu_mask(i, mask) {
- load = target_load(i);
-
- if (load < min_load) {
- min_cpu = i;
- min_load = load;
-
- /* break out early on an idle CPU: */
- if (!min_load)
- break;
- }
- }
-
- /* add +1 to account for the new task */
- this_load = source_load(this_cpu) + SCHED_LOAD_SCALE;
-
- /*
- * Would with the addition of the new task to the
- * current CPU there be an imbalance between this
- * CPU and the idlest CPU?
- *
- * Use half of the balancing threshold - new-context is
- * a good opportunity to balance.
- */
- if (min_load*(100 + (sd->imbalance_pct-100)/2) < this_load*100)
- return min_cpu;
-
- return this_cpu;
-}
-
-/*
* If dest_cpu is allowed for this process, migrate the task to it.
* This is accomplished by forcing the cpu_allowed mask to only
* allow dest_cpu, which will force the cpu onto dest_cpu. Then
@@ -1571,37 +1712,16 @@ out:
}
/*
- * sched_exec(): find the highest-level, exec-balance-capable
- * domain and try to migrate the task to the least loaded CPU.
- *
- * execve() is a valuable balancing opportunity, because at this point
- * the task has the smallest effective memory and cache footprint.
+ * sched_exec - execve() is a valuable balancing opportunity, because at
+ * this point the task has the smallest effective memory and cache footprint.
*/
void sched_exec(void)
{
- struct sched_domain *tmp, *sd = NULL;
int new_cpu, this_cpu = get_cpu();
-
- /* Prefer the current CPU if there's only this task running */
- if (this_rq()->nr_running <= 1)
- goto out;
-
- for_each_domain(this_cpu, tmp)
- if (tmp->flags & SD_BALANCE_EXEC)
- sd = tmp;
-
- if (sd) {
- schedstat_inc(sd, sbe_attempts);
- new_cpu = find_idlest_cpu(current, this_cpu, sd);
- if (new_cpu != this_cpu) {
- schedstat_inc(sd, sbe_pushed);
- put_cpu();
- sched_migrate_task(current, new_cpu);
- return;
- }
- }
-out:
+ new_cpu = sched_balance_self(this_cpu, SD_BALANCE_EXEC);
put_cpu();
+ if (new_cpu != this_cpu)
+ sched_migrate_task(current, new_cpu);
}
/*
@@ -1632,7 +1752,7 @@ void pull_task(runqueue_t *src_rq, prio_array_t *src_array, task_t *p,
*/
static inline
int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
- struct sched_domain *sd, enum idle_type idle)
+ struct sched_domain *sd, enum idle_type idle, int *all_pinned)
{
/*
* We do not migrate tasks that are:
@@ -1640,23 +1760,24 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
* 2) cannot be migrated to this CPU due to cpus_allowed, or
* 3) are cache-hot on their current CPU.
*/
- if (task_running(rq, p))
- return 0;
if (!cpu_isset(this_cpu, p->cpus_allowed))
return 0;
+ *all_pinned = 0;
+
+ if (task_running(rq, p))
+ return 0;
/*
* Aggressive migration if:
- * 1) the [whole] cpu is idle, or
+ * 1) task is cache cold, or
* 2) too many balance attempts have failed.
*/
- if (cpu_and_siblings_are_idle(this_cpu) || \
- sd->nr_balance_failed > sd->cache_nice_tries)
+ if (sd->nr_balance_failed > sd->cache_nice_tries)
return 1;
if (task_hot(p, rq->timestamp_last_tick, sd))
- return 0;
+ return 0;
return 1;
}
@@ -1669,16 +1790,18 @@ int can_migrate_task(task_t *p, runqueue_t *rq, int this_cpu,
*/
static int move_tasks(runqueue_t *this_rq, int this_cpu, runqueue_t *busiest,
unsigned long max_nr_move, struct sched_domain *sd,
- enum idle_type idle)
+ enum idle_type idle, int *all_pinned)
{
prio_array_t *array, *dst_array;
struct list_head *head, *curr;
- int idx, pulled = 0;
+ int idx, pulled = 0, pinned = 0;
task_t *tmp;
- if (max_nr_move <= 0 || busiest->nr_running <= 1)
+ if (max_nr_move == 0)
goto out;
+ pinned = 1;
+
/*
* We first consider expired tasks. Those will likely not be
* executed in the near future, and they are most likely to
@@ -1717,7 +1840,7 @@ skip_queue:
curr = curr->prev;
- if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle)) {
+ if (!can_migrate_task(tmp, busiest, this_cpu, sd, idle, &pinned)) {
if (curr != head)
goto skip_queue;
idx++;
@@ -1746,6 +1869,9 @@ out:
* inside pull_task().
*/
schedstat_add(sd, lb_gained[idle], pulled);
+
+ if (all_pinned)
+ *all_pinned = pinned;
return pulled;
}
@@ -1760,8 +1886,15 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
{
struct sched_group *busiest = NULL, *this = NULL, *group = sd->groups;
unsigned long max_load, avg_load, total_load, this_load, total_pwr;
+ int load_idx;
max_load = this_load = total_load = total_pwr = 0;
+ if (idle == NOT_IDLE)
+ load_idx = sd->busy_idx;
+ else if (idle == NEWLY_IDLE)
+ load_idx = sd->newidle_idx;
+ else
+ load_idx = sd->idle_idx;
do {
unsigned long load;
@@ -1776,9 +1909,9 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
for_each_cpu_mask(i, group->cpumask) {
/* Bias balancing toward cpus of our domain */
if (local_group)
- load = target_load(i);
+ load = target_load(i, load_idx);
else
- load = source_load(i);
+ load = source_load(i, load_idx);
avg_load += load;
}
@@ -1792,12 +1925,10 @@ find_busiest_group(struct sched_domain *sd, int this_cpu,
if (local_group) {
this_load = avg_load;
this = group;
- goto nextgroup;
} else if (avg_load > max_load) {
max_load = avg_load;
busiest = group;
}
-nextgroup:
group = group->next;
} while (group != sd->groups);
@@ -1870,15 +2001,9 @@ nextgroup:
/* Get rid of the scaling factor, rounding down as we divide */
*imbalance = *imbalance / SCHED_LOAD_SCALE;
-
return busiest;
out_balanced:
- if (busiest && (idle == NEWLY_IDLE ||
- (idle == SCHED_IDLE && max_load > SCHED_LOAD_SCALE)) ) {
- *imbalance = 1;
- return busiest;
- }
*imbalance = 0;
return NULL;
@@ -1894,7 +2019,7 @@ static runqueue_t *find_busiest_queue(struct sched_group *group)
int i;
for_each_cpu_mask(i, group->cpumask) {
- load = source_load(i);
+ load = source_load(i, 0);
if (load > max_load) {
max_load = load;
@@ -1906,6 +2031,12 @@ static runqueue_t *find_busiest_queue(struct sched_group *group)
}
/*
+ * Max backoff if we encounter pinned tasks. Pretty arbitrary value, but
+ * so long as it is large enough.
+ */
+#define MAX_PINNED_INTERVAL 512
+
+/*
* Check this_cpu to ensure it is balanced within domain. Attempt to move
* tasks if there is an imbalance.
*
@@ -1917,7 +2048,8 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
struct sched_group *group;
runqueue_t *busiest;
unsigned long imbalance;
- int nr_moved;
+ int nr_moved, all_pinned = 0;
+ int active_balance = 0;
spin_lock(&this_rq->lock);
schedstat_inc(sd, lb_cnt[idle]);
@@ -1934,15 +2066,7 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
goto out_balanced;
}
- /*
- * This should be "impossible", but since load
- * balancing is inherently racy and statistical,
- * it could happen in theory.
- */
- if (unlikely(busiest == this_rq)) {
- WARN_ON(1);
- goto out_balanced;
- }
+ BUG_ON(busiest == this_rq);
schedstat_add(sd, lb_imbalance[idle], imbalance);
@@ -1956,9 +2080,15 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
*/
double_lock_balance(this_rq, busiest);
nr_moved = move_tasks(this_rq, this_cpu, busiest,
- imbalance, sd, idle);
+ imbalance, sd, idle,
+ &all_pinned);
spin_unlock(&busiest->lock);
+
+ /* All tasks on this runqueue were pinned by CPU affinity */
+ if (unlikely(all_pinned))
+ goto out_balanced;
}
+
spin_unlock(&this_rq->lock);
if (!nr_moved) {
@@ -1966,36 +2096,38 @@ static int load_balance(int this_cpu, runqueue_t *this_rq,
sd->nr_balance_failed++;
if (unlikely(sd->nr_balance_failed > sd->cache_nice_tries+2)) {
- int wake = 0;
spin_lock(&busiest->lock);
if (!busiest->active_balance) {
busiest->active_balance = 1;
busiest->push_cpu = this_cpu;
- wake = 1;
+ active_balance = 1;
}
spin_unlock(&busiest->lock);
- if (wake)
+ if (active_balance)
wake_up_process(busiest->migration_thread);
/*
* We've kicked active balancing, reset the failure
* counter.
*/
- sd->nr_balance_failed = sd->cache_nice_tries;
+ sd->nr_balance_failed = sd->cache_nice_tries+1;
}
-
- /*
- * We were unbalanced, but unsuccessful in move_tasks(),
- * so bump the balance_interval to lessen the lock contention.
- */
- if (sd->balance_interval < sd->max_interval)
- sd->balance_interval++;
- } else {
+ } else
sd->nr_balance_failed = 0;
+ if (likely(!active_balance)) {
/* We were unbalanced, so reset the balancing interval */
sd->balance_interval = sd->min_interval;
+ } else {
+ /*
+ * If we've begun active balancing, start to back off. This
+ * case may not be covered by the all_pinned logic if there
+ * is only 1 task on the busy runqueue (because we don't call
+ * move_tasks).
+ */
+ if (sd->balance_interval < sd->max_interval)
+ sd->balance_interval *= 2;
}
return nr_moved;
@@ -2005,8 +2137,10 @@ out_balanced:
schedstat_inc(sd, lb_balanced[idle]);
+ sd->nr_balance_failed = 0;
/* tune up the balancing interval */
- if (sd->balance_interval < sd->max_interval)
+ if ((all_pinned && sd->balance_interval < MAX_PINNED_INTERVAL) ||
+ (sd->balance_interval < sd->max_interval))
sd->balance_interval *= 2;
return 0;
@@ -2030,31 +2164,36 @@ static int load_balance_newidle(int this_cpu, runqueue_t *this_rq,
schedstat_inc(sd, lb_cnt[NEWLY_IDLE]);
group = find_busiest_group(sd, this_cpu, &imbalance, NEWLY_IDLE);
if (!group) {
- schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
schedstat_inc(sd, lb_nobusyg[NEWLY_IDLE]);
- goto out;
+ goto out_balanced;
}
busiest = find_busiest_queue(group);
- if (!busiest || busiest == this_rq) {
- schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+ if (!busiest) {
schedstat_inc(sd, lb_nobusyq[NEWLY_IDLE]);
- goto out;
+ goto out_balanced;
}
+ BUG_ON(busiest == this_rq);
+
/* Attempt to move tasks */
double_lock_balance(this_rq, busiest);
schedstat_add(sd, lb_imbalance[NEWLY_IDLE], imbalance);
nr_moved = move_tasks(this_rq, this_cpu, busiest,
- imbalance, sd, NEWLY_IDLE);
+ imbalance, sd, NEWLY_IDLE, NULL);
if (!nr_moved)
schedstat_inc(sd, lb_failed[NEWLY_IDLE]);
+ else
+ sd->nr_balance_failed = 0;
spin_unlock(&busiest->lock);
-
-out:
return nr_moved;
+
+out_balanced:
+ schedstat_inc(sd, lb_balanced[NEWLY_IDLE]);
+ sd->nr_balance_failed = 0;
+ return 0;
}
/*
@@ -2086,56 +2225,42 @@ static inline void idle_balance(int this_cpu, runqueue_t *this_rq)
static void active_load_balance(runqueue_t *busiest_rq, int busiest_cpu)
{
struct sched_domain *sd;
- struct sched_group *cpu_group;
runqueue_t *target_rq;
- cpumask_t visited_cpus;
- int cpu;
+ int target_cpu = busiest_rq->push_cpu;
+
+ if (busiest_rq->nr_running <= 1)
+ /* no task to move */
+ return;
+
+ target_rq = cpu_rq(target_cpu);
/*
- * Search for suitable CPUs to push tasks to in successively higher
- * domains with SD_LOAD_BALANCE set.
+ * This condition is "impossible", if it occurs
+ * we need to fix it. Originally reported by
+ * Bjorn Helgaas on a 128-cpu setup.
*/
- visited_cpus = CPU_MASK_NONE;
- for_each_domain(busiest_cpu, sd) {
- if (!(sd->flags & SD_LOAD_BALANCE))
- /* no more domains to search */
- break;
+ BUG_ON(busiest_rq == target_rq);
- schedstat_inc(sd, alb_cnt);
+ /* move a task from busiest_rq to target_rq */
+ double_lock_balance(busiest_rq, target_rq);
- cpu_group = sd->groups;
- do {
- for_each_cpu_mask(cpu, cpu_group->cpumask) {
- if (busiest_rq->nr_running <= 1)
- /* no more tasks left to move */
- return;
- if (cpu_isset(cpu, visited_cpus))
- continue;
- cpu_set(cpu, visited_cpus);
- if (!cpu_and_siblings_are_idle(cpu) || cpu == busiest_cpu)
- continue;
-
- target_rq = cpu_rq(cpu);
- /*
- * This condition is "impossible", if it occurs
- * we need to fix it. Originally reported by
- * Bjorn Helgaas on a 128-cpu setup.
- */
- BUG_ON(busiest_rq == target_rq);
-
- /* move a task from busiest_rq to target_rq */
- double_lock_balance(busiest_rq, target_rq);
- if (move_tasks(target_rq, cpu, busiest_rq,
- 1, sd, SCHED_IDLE)) {
- schedstat_inc(sd, alb_pushed);
- } else {
- schedstat_inc(sd, alb_failed);
- }
- spin_unlock(&target_rq->lock);
- }
- cpu_group = cpu_group->next;
- } while (cpu_group != sd->groups);
- }
+ /* Search for an sd spanning us and the target CPU. */
+ for_each_domain(target_cpu, sd)
+ if ((sd->flags & SD_LOAD_BALANCE) &&
+ cpu_isset(busiest_cpu, sd->span))
+ break;
+
+ if (unlikely(sd == NULL))
+ goto out;
+
+ schedstat_inc(sd, alb_cnt);
+
+ if (move_tasks(target_rq, target_cpu, busiest_rq, 1, sd, SCHED_IDLE, NULL))
+ schedstat_inc(sd, alb_pushed);
+ else
+ schedstat_inc(sd, alb_failed);
+out:
+ spin_unlock(&target_rq->lock);
}
/*
@@ -2156,18 +2281,23 @@ static void rebalance_tick(int this_cpu, runqueue_t *this_rq,
unsigned long old_load, this_load;
unsigned long j = jiffies + CPU_OFFSET(this_cpu);
struct sched_domain *sd;
+ int i;
- /* Update our load */
- old_load = this_rq->cpu_load;
this_load = this_rq->nr_running * SCHED_LOAD_SCALE;
- /*
- * Round up the averaging division if load is increasing. This
- * prevents us from getting stuck on 9 if the load is 10, for
- * example.
- */
- if (this_load > old_load)
- old_load++;
- this_rq->cpu_load = (old_load + this_load) / 2;
+ /* Update our load */
+ for (i = 0; i < 3; i++) {
+ unsigned long new_load = this_load;
+ int scale = 1 << i;
+ old_load = this_rq->cpu_load[i];
+ /*
+ * Round up the averaging division if load is increasing. This
+ * prevents us from getting stuck on 9 if the load is 10, for
+ * example.
+ */
+ if (new_load > old_load)
+ new_load += scale-1;
+ this_rq->cpu_load[i] = (old_load*(scale-1) + new_load) / scale;
+ }
for_each_domain(this_cpu, sd) {
unsigned long interval;
@@ -2447,11 +2577,15 @@ out:
#ifdef CONFIG_SCHED_SMT
static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
{
- struct sched_domain *sd = this_rq->sd;
+ struct sched_domain *tmp, *sd = NULL;
cpumask_t sibling_map;
int i;
- if (!(sd->flags & SD_SHARE_CPUPOWER))
+ for_each_domain(this_cpu, tmp)
+ if (tmp->flags & SD_SHARE_CPUPOWER)
+ sd = tmp;
+
+ if (!sd)
return;
/*
@@ -2492,13 +2626,17 @@ static inline void wake_sleeping_dependent(int this_cpu, runqueue_t *this_rq)
static inline int dependent_sleeper(int this_cpu, runqueue_t *this_rq)
{
- struct sched_domain *sd = this_rq->sd;
+ struct sched_domain *tmp, *sd = NULL;
cpumask_t sibling_map;
prio_array_t *array;
int ret = 0, i;
task_t *p;
- if (!(sd->flags & SD_SHARE_CPUPOWER))
+ for_each_domain(this_cpu, tmp)
+ if (tmp->flags & SD_SHARE_CPUPOWER)
+ sd = tmp;
+
+ if (!sd)
return 0;
/*
@@ -2613,7 +2751,7 @@ asmlinkage void __sched schedule(void)
struct list_head *queue;
unsigned long long now;
unsigned long run_time;
- int cpu, idx;
+ int cpu, idx, new_prio;
/*
* Test if we are atomic. Since do_exit() needs to call into
@@ -2735,9 +2873,14 @@ go_idle:
delta = delta * (ON_RUNQUEUE_WEIGHT * 128 / 100) / 128;
array = next->array;
- dequeue_task(next, array);
- recalc_task_prio(next, next->timestamp + delta);
- enqueue_task(next, array);
+ new_prio = recalc_task_prio(next, next->timestamp + delta);
+
+ if (unlikely(next->prio != new_prio)) {
+ dequeue_task(next, array);
+ next->prio = new_prio;
+ enqueue_task(next, array);
+ } else
+ requeue_task(next, array);
}
next->activated = 0;
switch_tasks:
@@ -2761,11 +2904,15 @@ switch_tasks:
rq->curr = next;
++*switch_count;
- prepare_arch_switch(rq, next);
+ prepare_task_switch(rq, next);
prev = context_switch(rq, prev, next);
barrier();
-
- finish_task_switch(prev);
+ /*
+ * this_rq must be evaluated again because prev may have moved
+ * CPUs since it called schedule(), thus the 'rq' on its stack
+ * frame will be invalid.
+ */
+ finish_task_switch(this_rq(), prev);
} else
spin_unlock_irq(&rq->lock);
@@ -3301,15 +3448,7 @@ int task_nice(const task_t *p)
{
return TASK_NICE(p);
}
-
-/*
- * The only users of task_nice are binfmt_elf and binfmt_elf32.
- * binfmt_elf is no longer modular, but binfmt_elf32 still is.
- * Therefore, task_nice is needed if there is a compat_mode.
- */
-#ifdef CONFIG_COMPAT
EXPORT_SYMBOL_GPL(task_nice);
-#endif
/**
* idle_cpu - is a given cpu idle currently?
@@ -3384,13 +3523,24 @@ recheck:
if ((policy == SCHED_NORMAL) != (param->sched_priority == 0))
return -EINVAL;
- if ((policy == SCHED_FIFO || policy == SCHED_RR) &&
- param->sched_priority > p->signal->rlim[RLIMIT_RTPRIO].rlim_cur &&
- !capable(CAP_SYS_NICE))
- return -EPERM;
- if ((current->euid != p->euid) && (current->euid != p->uid) &&
- !capable(CAP_SYS_NICE))
- return -EPERM;
+ /*
+ * Allow unprivileged RT tasks to decrease priority:
+ */
+ if (!capable(CAP_SYS_NICE)) {
+ /* can't change policy */
+ if (policy != p->policy)
+ return -EPERM;
+ /* can't increase priority */
+ if (policy != SCHED_NORMAL &&
+ param->sched_priority > p->rt_priority &&
+ param->sched_priority >
+ p->signal->rlim[RLIMIT_RTPRIO].rlim_cur)
+ return -EPERM;
+ /* can't change other user's priorities */
+ if ((current->euid != p->euid) &&
+ (current->euid != p->uid))
+ return -EPERM;
+ }
retval = security_task_setscheduler(p, policy, param);
if (retval)
@@ -3727,6 +3877,13 @@ asmlinkage long sys_sched_yield(void)
static inline void __cond_resched(void)
{
+ /*
+ * The BKS might be reacquired before we have dropped
+ * PREEMPT_ACTIVE, which could trigger a second
+ * cond_resched() call.
+ */
+ if (unlikely(preempt_count()))
+ return;
do {
add_preempt_count(PREEMPT_ACTIVE);
schedule();
@@ -4016,6 +4173,14 @@ void show_state(void)
read_unlock(&tasklist_lock);
}
+/**
+ * init_idle - set up an idle thread for a given CPU
+ * @idle: task in question
+ * @cpu: cpu the idle task belongs to
+ *
+ * NOTE: this function does not set the idle thread's NEED_RESCHED
+ * flag, to make booting more robust.
+ */
void __devinit init_idle(task_t *idle, int cpu)
{
runqueue_t *rq = cpu_rq(cpu);
@@ -4030,7 +4195,9 @@ void __devinit init_idle(task_t *idle, int cpu)
spin_lock_irqsave(&rq->lock, flags);
rq->curr = rq->idle = idle;
- set_tsk_need_resched(idle);
+#if defined(CONFIG_SMP) && defined(__ARCH_WANT_UNLOCKED_CTXSW)
+ idle->oncpu = 1;
+#endif
spin_unlock_irqrestore(&rq->lock, flags);
/* Set the preempt count _outside_ the spinlocks! */
@@ -4174,8 +4341,7 @@ static int migration_thread(void * data)
struct list_head *head;
migration_req_t *req;
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
spin_lock_irq(&rq->lock);
@@ -4200,17 +4366,9 @@ static int migration_thread(void * data)
req = list_entry(head->next, migration_req_t, list);
list_del_init(head->next);
- if (req->type == REQ_MOVE_TASK) {
- spin_unlock(&rq->lock);
- __migrate_task(req->task, cpu, req->dest_cpu);
- local_irq_enable();
- } else if (req->type == REQ_SET_DOMAIN) {
- rq->sd = req->sd;
- spin_unlock_irq(&rq->lock);
- } else {
- spin_unlock_irq(&rq->lock);
- WARN_ON(1);
- }
+ spin_unlock(&rq->lock);
+ __migrate_task(req->task, cpu, req->dest_cpu);
+ local_irq_enable();
complete(&req->done);
}
@@ -4441,7 +4599,6 @@ static int migration_call(struct notifier_block *nfb, unsigned long action,
migration_req_t *req;
req = list_entry(rq->migration_queue.next,
migration_req_t, list);
- BUG_ON(req->type != REQ_MOVE_TASK);
list_del_init(&req->list);
complete(&req->done);
}
@@ -4472,12 +4629,17 @@ int __init migration_init(void)
#endif
#ifdef CONFIG_SMP
-#define SCHED_DOMAIN_DEBUG
+#undef SCHED_DOMAIN_DEBUG
#ifdef SCHED_DOMAIN_DEBUG
static void sched_domain_debug(struct sched_domain *sd, int cpu)
{
int level = 0;
+ if (!sd) {
+ printk(KERN_DEBUG "CPU%d attaching NULL sched-domain.\n", cpu);
+ return;
+ }
+
printk(KERN_DEBUG "CPU%d attaching sched-domain:\n", cpu);
do {
@@ -4560,37 +4722,81 @@ static void sched_domain_debug(struct sched_domain *sd, int cpu)
#define sched_domain_debug(sd, cpu) {}
#endif
+static int sd_degenerate(struct sched_domain *sd)
+{
+ if (cpus_weight(sd->span) == 1)
+ return 1;
+
+ /* Following flags need at least 2 groups */
+ if (sd->flags & (SD_LOAD_BALANCE |
+ SD_BALANCE_NEWIDLE |
+ SD_BALANCE_FORK |
+ SD_BALANCE_EXEC)) {
+ if (sd->groups != sd->groups->next)
+ return 0;
+ }
+
+ /* Following flags don't use groups */
+ if (sd->flags & (SD_WAKE_IDLE |
+ SD_WAKE_AFFINE |
+ SD_WAKE_BALANCE))
+ return 0;
+
+ return 1;
+}
+
+static int sd_parent_degenerate(struct sched_domain *sd,
+ struct sched_domain *parent)
+{
+ unsigned long cflags = sd->flags, pflags = parent->flags;
+
+ if (sd_degenerate(parent))
+ return 1;
+
+ if (!cpus_equal(sd->span, parent->span))
+ return 0;
+
+ /* Does parent contain flags not in child? */
+ /* WAKE_BALANCE is a subset of WAKE_AFFINE */
+ if (cflags & SD_WAKE_AFFINE)
+ pflags &= ~SD_WAKE_BALANCE;
+ /* Flags needing groups don't count if only 1 group in parent */
+ if (parent->groups == parent->groups->next) {
+ pflags &= ~(SD_LOAD_BALANCE |
+ SD_BALANCE_NEWIDLE |
+ SD_BALANCE_FORK |
+ SD_BALANCE_EXEC);
+ }
+ if (~cflags & pflags)
+ return 0;
+
+ return 1;
+}
+
/*
* Attach the domain 'sd' to 'cpu' as its base domain. Callers must
* hold the hotplug lock.
*/
-void __devinit cpu_attach_domain(struct sched_domain *sd, int cpu)
+void cpu_attach_domain(struct sched_domain *sd, int cpu)
{
- migration_req_t req;
- unsigned long flags;
runqueue_t *rq = cpu_rq(cpu);
- int local = 1;
-
- sched_domain_debug(sd, cpu);
-
- spin_lock_irqsave(&rq->lock, flags);
+ struct sched_domain *tmp;
- if (cpu == smp_processor_id() || !cpu_online(cpu)) {
- rq->sd = sd;
- } else {
- init_completion(&req.done);
- req.type = REQ_SET_DOMAIN;
- req.sd = sd;
- list_add(&req.list, &rq->migration_queue);
- local = 0;
+ /* Remove the sched domains which do not contribute to scheduling. */
+ for (tmp = sd; tmp; tmp = tmp->parent) {
+ struct sched_domain *parent = tmp->parent;
+ if (!parent)
+ break;
+ if (sd_parent_degenerate(tmp, parent))
+ tmp->parent = parent->parent;
}
- spin_unlock_irqrestore(&rq->lock, flags);
+ if (sd && sd_degenerate(sd))
+ sd = sd->parent;
- if (!local) {
- wake_up_process(rq->migration_thread);
- wait_for_completion(&req.done);
- }
+ sched_domain_debug(sd, cpu);
+
+ rcu_assign_pointer(rq->sd, sd);
}
/* cpus with isolated domains */
@@ -4622,7 +4828,7 @@ __setup ("isolcpus=", isolated_cpu_setup);
* covered by the given span, and will set each group's ->cpumask correctly,
* and ->cpu_power to 0.
*/
-void __devinit init_sched_build_groups(struct sched_group groups[],
+void init_sched_build_groups(struct sched_group groups[],
cpumask_t span, int (*group_fn)(int cpu))
{
struct sched_group *first = NULL, *last = NULL;
@@ -4658,13 +4864,14 @@ void __devinit init_sched_build_groups(struct sched_group groups[],
#ifdef ARCH_HAS_SCHED_DOMAIN
-extern void __devinit arch_init_sched_domains(void);
-extern void __devinit arch_destroy_sched_domains(void);
+extern void build_sched_domains(const cpumask_t *cpu_map);
+extern void arch_init_sched_domains(const cpumask_t *cpu_map);
+extern void arch_destroy_sched_domains(const cpumask_t *cpu_map);
#else
#ifdef CONFIG_SCHED_SMT
static DEFINE_PER_CPU(struct sched_domain, cpu_domains);
static struct sched_group sched_group_cpus[NR_CPUS];
-static int __devinit cpu_to_cpu_group(int cpu)
+static int cpu_to_cpu_group(int cpu)
{
return cpu;
}
@@ -4672,7 +4879,7 @@ static int __devinit cpu_to_cpu_group(int cpu)
static DEFINE_PER_CPU(struct sched_domain, phys_domains);
static struct sched_group sched_group_phys[NR_CPUS];
-static int __devinit cpu_to_phys_group(int cpu)
+static int cpu_to_phys_group(int cpu)
{
#ifdef CONFIG_SCHED_SMT
return first_cpu(cpu_sibling_map[cpu]);
@@ -4685,7 +4892,7 @@ static int __devinit cpu_to_phys_group(int cpu)
static DEFINE_PER_CPU(struct sched_domain, node_domains);
static struct sched_group sched_group_nodes[MAX_NUMNODES];
-static int __devinit cpu_to_node_group(int cpu)
+static int cpu_to_node_group(int cpu)
{
return cpu_to_node(cpu);
}
@@ -4716,39 +4923,28 @@ static void check_sibling_maps(void)
#endif
/*
- * Set up scheduler domains and groups. Callers must hold the hotplug lock.
+ * Build sched domains for a given set of cpus and attach the sched domains
+ * to the individual cpus
*/
-static void __devinit arch_init_sched_domains(void)
+static void build_sched_domains(const cpumask_t *cpu_map)
{
int i;
- cpumask_t cpu_default_map;
-
-#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
- check_sibling_maps();
-#endif
- /*
- * Setup mask for cpus without special case scheduling requirements.
- * For now this just excludes isolated cpus, but could be used to
- * exclude other special cases in the future.
- */
- cpus_complement(cpu_default_map, cpu_isolated_map);
- cpus_and(cpu_default_map, cpu_default_map, cpu_online_map);
/*
- * Set up domains. Isolated domains just stay on the dummy domain.
+ * Set up domains for cpus specified by the cpu_map.
*/
- for_each_cpu_mask(i, cpu_default_map) {
+ for_each_cpu_mask(i, *cpu_map) {
int group;
struct sched_domain *sd = NULL, *p;
cpumask_t nodemask = node_to_cpumask(cpu_to_node(i));
- cpus_and(nodemask, nodemask, cpu_default_map);
+ cpus_and(nodemask, nodemask, *cpu_map);
#ifdef CONFIG_NUMA
sd = &per_cpu(node_domains, i);
group = cpu_to_node_group(i);
*sd = SD_NODE_INIT;
- sd->span = cpu_default_map;
+ sd->span = *cpu_map;
sd->groups = &sched_group_nodes[group];
#endif
@@ -4766,7 +4962,7 @@ static void __devinit arch_init_sched_domains(void)
group = cpu_to_cpu_group(i);
*sd = SD_SIBLING_INIT;
sd->span = cpu_sibling_map[i];
- cpus_and(sd->span, sd->span, cpu_default_map);
+ cpus_and(sd->span, sd->span, *cpu_map);
sd->parent = p;
sd->groups = &sched_group_cpus[group];
#endif
@@ -4776,7 +4972,7 @@ static void __devinit arch_init_sched_domains(void)
/* Set up CPU (sibling) groups */
for_each_online_cpu(i) {
cpumask_t this_sibling_map = cpu_sibling_map[i];
- cpus_and(this_sibling_map, this_sibling_map, cpu_default_map);
+ cpus_and(this_sibling_map, this_sibling_map, *cpu_map);
if (i != first_cpu(this_sibling_map))
continue;
@@ -4789,7 +4985,7 @@ static void __devinit arch_init_sched_domains(void)
for (i = 0; i < MAX_NUMNODES; i++) {
cpumask_t nodemask = node_to_cpumask(i);
- cpus_and(nodemask, nodemask, cpu_default_map);
+ cpus_and(nodemask, nodemask, *cpu_map);
if (cpus_empty(nodemask))
continue;
@@ -4799,12 +4995,12 @@ static void __devinit arch_init_sched_domains(void)
#ifdef CONFIG_NUMA
/* Set up node groups */
- init_sched_build_groups(sched_group_nodes, cpu_default_map,
+ init_sched_build_groups(sched_group_nodes, *cpu_map,
&cpu_to_node_group);
#endif
/* Calculate CPU power for physical packages and nodes */
- for_each_cpu_mask(i, cpu_default_map) {
+ for_each_cpu_mask(i, *cpu_map) {
int power;
struct sched_domain *sd;
#ifdef CONFIG_SCHED_SMT
@@ -4828,7 +5024,7 @@ static void __devinit arch_init_sched_domains(void)
}
/* Attach the domains */
- for_each_online_cpu(i) {
+ for_each_cpu_mask(i, *cpu_map) {
struct sched_domain *sd;
#ifdef CONFIG_SCHED_SMT
sd = &per_cpu(cpu_domains, i);
@@ -4838,41 +5034,85 @@ static void __devinit arch_init_sched_domains(void)
cpu_attach_domain(sd, i);
}
}
+/*
+ * Set up scheduler domains and groups. Callers must hold the hotplug lock.
+ */
+static void arch_init_sched_domains(cpumask_t *cpu_map)
+{
+ cpumask_t cpu_default_map;
-#ifdef CONFIG_HOTPLUG_CPU
-static void __devinit arch_destroy_sched_domains(void)
+#if defined(CONFIG_SCHED_SMT) && defined(CONFIG_NUMA)
+ check_sibling_maps();
+#endif
+ /*
+ * Setup mask for cpus without special case scheduling requirements.
+ * For now this just excludes isolated cpus, but could be used to
+ * exclude other special cases in the future.
+ */
+ cpus_andnot(cpu_default_map, *cpu_map, cpu_isolated_map);
+
+ build_sched_domains(&cpu_default_map);
+}
+
+static void arch_destroy_sched_domains(const cpumask_t *cpu_map)
{
/* Do nothing: everything is statically allocated. */
}
-#endif
#endif /* ARCH_HAS_SCHED_DOMAIN */
/*
- * Initial dummy domain for early boot and for hotplug cpu. Being static,
- * it is initialized to zero, so all balancing flags are cleared which is
- * what we want.
+ * Detach sched domains from a group of cpus specified in cpu_map
+ * These cpus will now be attached to the NULL domain
*/
-static struct sched_domain sched_domain_dummy;
+static inline void detach_destroy_domains(const cpumask_t *cpu_map)
+{
+ int i;
+
+ for_each_cpu_mask(i, *cpu_map)
+ cpu_attach_domain(NULL, i);
+ synchronize_sched();
+ arch_destroy_sched_domains(cpu_map);
+}
+
+/*
+ * Partition sched domains as specified by the cpumasks below.
+ * This attaches all cpus from the cpumasks to the NULL domain,
+ * waits for a RCU quiescent period, recalculates sched
+ * domain information and then attaches them back to the
+ * correct sched domains
+ * Call with hotplug lock held
+ */
+void partition_sched_domains(cpumask_t *partition1, cpumask_t *partition2)
+{
+ cpumask_t change_map;
+
+ cpus_and(*partition1, *partition1, cpu_online_map);
+ cpus_and(*partition2, *partition2, cpu_online_map);
+ cpus_or(change_map, *partition1, *partition2);
+
+ /* Detach sched domains from all of the affected cpus */
+ detach_destroy_domains(&change_map);
+ if (!cpus_empty(*partition1))
+ build_sched_domains(partition1);
+ if (!cpus_empty(*partition2))
+ build_sched_domains(partition2);
+}
#ifdef CONFIG_HOTPLUG_CPU
/*
* Force a reinitialization of the sched domains hierarchy. The domains
* and groups cannot be updated in place without racing with the balancing
- * code, so we temporarily attach all running cpus to a "dummy" domain
+ * code, so we temporarily attach all running cpus to the NULL domain
* which will prevent rebalancing while the sched domains are recalculated.
*/
static int update_sched_domains(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
- int i;
-
switch (action) {
case CPU_UP_PREPARE:
case CPU_DOWN_PREPARE:
- for_each_online_cpu(i)
- cpu_attach_domain(&sched_domain_dummy, i);
- arch_destroy_sched_domains();
+ detach_destroy_domains(&cpu_online_map);
return NOTIFY_OK;
case CPU_UP_CANCELED:
@@ -4888,7 +5128,7 @@ static int update_sched_domains(struct notifier_block *nfb,
}
/* The hotplug lock is already held by cpu_up/cpu_down */
- arch_init_sched_domains();
+ arch_init_sched_domains(&cpu_online_map);
return NOTIFY_OK;
}
@@ -4897,7 +5137,7 @@ static int update_sched_domains(struct notifier_block *nfb,
void __init sched_init_smp(void)
{
lock_cpu_hotplug();
- arch_init_sched_domains();
+ arch_init_sched_domains(&cpu_online_map);
unlock_cpu_hotplug();
/* XXX: Theoretical race here - CPU may be hotplugged now */
hotcpu_notifier(update_sched_domains, 0);
@@ -4927,13 +5167,15 @@ void __init sched_init(void)
rq = cpu_rq(i);
spin_lock_init(&rq->lock);
+ rq->nr_running = 0;
rq->active = rq->arrays;
rq->expired = rq->arrays + 1;
rq->best_expired_prio = MAX_PRIO;
#ifdef CONFIG_SMP
- rq->sd = &sched_domain_dummy;
- rq->cpu_load = 0;
+ rq->sd = NULL;
+ for (j = 1; j < 3; j++)
+ rq->cpu_load[j] = 0;
rq->active_balance = 0;
rq->push_cpu = 0;
rq->migration_thread = NULL;
diff --git a/kernel/signal.c b/kernel/signal.c
index d1258729a5f9..ca1186eef938 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -213,7 +213,7 @@ static inline int has_pending_signals(sigset_t *signal, sigset_t *blocked)
fastcall void recalc_sigpending_tsk(struct task_struct *t)
{
if (t->signal->group_stop_count > 0 ||
- (t->flags & PF_FREEZE) ||
+ (freezing(t)) ||
PENDING(&t->pending, &t->blocked) ||
PENDING(&t->signal->shared_pending, &t->blocked))
set_tsk_thread_flag(t, TIF_SIGPENDING);
@@ -2231,8 +2231,7 @@ sys_rt_sigtimedwait(const sigset_t __user *uthese,
current->state = TASK_INTERRUPTIBLE;
timeout = schedule_timeout(timeout);
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+ try_to_freeze();
spin_lock_irq(&current->sighand->siglock);
sig = dequeue_signal(current, &these, &info);
current->blocked = current->real_blocked;
diff --git a/kernel/sys.c b/kernel/sys.c
index 5a9d6b075016..9a24374c23bc 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -16,6 +16,8 @@
#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/key.h>
@@ -405,6 +407,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
case LINUX_REBOOT_CMD_HALT:
notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
system_state = SYSTEM_HALT;
+ device_suspend(PMSG_SUSPEND);
device_shutdown();
printk(KERN_EMERG "System halted.\n");
machine_halt();
@@ -415,6 +418,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
case LINUX_REBOOT_CMD_POWER_OFF:
notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
system_state = SYSTEM_POWER_OFF;
+ device_suspend(PMSG_SUSPEND);
device_shutdown();
printk(KERN_EMERG "Power down.\n");
machine_power_off();
@@ -431,11 +435,30 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
system_state = SYSTEM_RESTART;
+ device_suspend(PMSG_FREEZE);
device_shutdown();
printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
machine_restart(buffer);
break;
+#ifdef CONFIG_KEXEC
+ case LINUX_REBOOT_CMD_KEXEC:
+ {
+ struct kimage *image;
+ image = xchg(&kexec_image, 0);
+ if (!image) {
+ unlock_kernel();
+ return -EINVAL;
+ }
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+ system_state = SYSTEM_RESTART;
+ device_shutdown();
+ printk(KERN_EMERG "Starting new kernel\n");
+ machine_shutdown();
+ machine_kexec(image);
+ break;
+ }
+#endif
#ifdef CONFIG_SOFTWARE_SUSPEND
case LINUX_REBOOT_CMD_SW_SUSPEND:
{
@@ -1259,7 +1282,7 @@ static void groups_sort(struct group_info *group_info)
}
/* a simple bsearch */
-static int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(struct group_info *group_info, gid_t grp)
{
int left, right;
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 6f15bea7d1a8..42b40ae5eada 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -18,6 +18,8 @@ cond_syscall(sys_acct);
cond_syscall(sys_lookup_dcookie);
cond_syscall(sys_swapon);
cond_syscall(sys_swapoff);
+cond_syscall(sys_kexec_load);
+cond_syscall(compat_sys_kexec_load);
cond_syscall(sys_init_module);
cond_syscall(sys_delete_module);
cond_syscall(sys_socketpair);
@@ -78,6 +80,9 @@ cond_syscall(sys_keyctl);
cond_syscall(compat_sys_keyctl);
cond_syscall(compat_sys_socketcall);
cond_syscall(sys_set_zone_reclaim);
+cond_syscall(sys_inotify_init);
+cond_syscall(sys_inotify_add_watch);
+cond_syscall(sys_inotify_rm_watch);
/* arch-specific weak syscall entries */
cond_syscall(sys_pciconfig_read);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 24a4d12d5aa9..b240e2cb86fc 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -67,6 +67,12 @@ extern int printk_ratelimit_jiffies;
extern int printk_ratelimit_burst;
extern int pid_max_min, pid_max_max;
+#ifdef CONFIG_INOTIFY
+extern int inotify_max_user_devices;
+extern int inotify_max_user_watches;
+extern int inotify_max_queued_events;
+#endif
+
#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_X86)
int unknown_nmi_panic;
extern int proc_unknown_nmi_panic(ctl_table *, int, struct file *,
@@ -218,6 +224,7 @@ static ctl_table root_table[] = {
.mode = 0555,
.child = dev_table,
},
+
{ .ctl_name = 0 }
};
@@ -959,6 +966,40 @@ static ctl_table fs_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
+#ifdef CONFIG_INOTIFY
+ {
+ .ctl_name = INOTIFY_MAX_USER_DEVICES,
+ .procname = "max_user_devices",
+ .data = &inotify_max_user_devices,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ },
+
+ {
+ .ctl_name = INOTIFY_MAX_USER_WATCHES,
+ .procname = "max_user_watches",
+ .data = &inotify_max_user_watches,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero,
+ },
+
+ {
+ .ctl_name = INOTIFY_MAX_QUEUED_EVENTS,
+ .procname = "max_queued_events",
+ .data = &inotify_max_queued_events,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec_minmax,
+ .strategy = &sysctl_intvec,
+ .extra1 = &zero
+ },
+#endif
{ .ctl_name = 0 }
};
@@ -968,7 +1009,7 @@ static ctl_table debug_table[] = {
static ctl_table dev_table[] = {
{ .ctl_name = 0 }
-};
+};
extern void init_irq_proc (void);
@@ -1000,8 +1041,7 @@ int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *ol
int error = parse_table(name, nlen, oldval, oldlenp,
newval, newlen, head->ctl_table,
&context);
- if (context)
- kfree(context);
+ kfree(context);
if (error != -ENOTDIR)
return error;
tmp = tmp->next;
diff --git a/kernel/timer.c b/kernel/timer.c
index 51ff917c9590..f2a11887a726 100644
--- a/kernel/timer.c
+++ b/kernel/timer.c
@@ -1597,7 +1597,7 @@ void msleep(unsigned int msecs)
EXPORT_SYMBOL(msleep);
/**
- * msleep_interruptible - sleep waiting for waitqueue interruptions
+ * msleep_interruptible - sleep waiting for signals
* @msecs: Time in milliseconds to sleep for
*/
unsigned long msleep_interruptible(unsigned int msecs)
diff --git a/kernel/user.c b/kernel/user.c
index 734575d55769..89e562feb1b1 100644
--- a/kernel/user.c
+++ b/kernel/user.c
@@ -120,6 +120,10 @@ struct user_struct * alloc_uid(uid_t uid)
atomic_set(&new->processes, 0);
atomic_set(&new->files, 0);
atomic_set(&new->sigpending, 0);
+#ifdef CONFIG_INOTIFY
+ atomic_set(&new->inotify_watches, 0);
+ atomic_set(&new->inotify_devs, 0);
+#endif
new->mq_bytes = 0;
new->locked_shm = 0;
diff --git a/lib/Kconfig b/lib/Kconfig
index 2d4d4e3bc4aa..eeb429a52152 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -63,5 +63,16 @@ config REED_SOLOMON_ENC16
config REED_SOLOMON_DEC16
boolean
-endmenu
+#
+# Textsearch support is select'ed if needed
+#
+config TEXTSEARCH
+ boolean
+config TEXTSEARCH_KMP
+ tristate
+
+config TEXTSEARCH_FSM
+ tristate
+
+endmenu
diff --git a/lib/Makefile b/lib/Makefile
index dcb4231916e2..beed1585294c 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -36,6 +36,10 @@ obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
obj-$(CONFIG_REED_SOLOMON) += reed_solomon/
+obj-$(CONFIG_TEXTSEARCH) += textsearch.o
+obj-$(CONFIG_TEXTSEARCH_KMP) += ts_kmp.o
+obj-$(CONFIG_TEXTSEARCH_FSM) += ts_fsm.o
+
hostprogs-y := gen_crc32table
clean-files := crc32table.h
diff --git a/lib/bitmap.c b/lib/bitmap.c
index d1388a5ce89c..fb9371fdd44a 100644
--- a/lib/bitmap.c
+++ b/lib/bitmap.c
@@ -289,7 +289,6 @@ EXPORT_SYMBOL(__bitmap_weight);
#define CHUNKSZ 32
#define nbits_to_hold_value(val) fls(val)
-#define roundup_power2(val,modulus) (((val) + (modulus) - 1) & ~((modulus) - 1))
#define unhex(c) (isdigit(c) ? (c - '0') : (toupper(c) - 'A' + 10))
#define BASEDEC 10 /* fancier cpuset lists input in decimal */
@@ -316,7 +315,7 @@ int bitmap_scnprintf(char *buf, unsigned int buflen,
if (chunksz == 0)
chunksz = CHUNKSZ;
- i = roundup_power2(nmaskbits, CHUNKSZ) - CHUNKSZ;
+ i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
for (; i >= 0; i -= CHUNKSZ) {
chunkmask = ((1ULL << chunksz) - 1);
word = i / BITS_PER_LONG;
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 04d664377f2c..10bed1c8c3c3 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -58,7 +58,7 @@ struct radix_tree_path {
#define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long))
#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
-static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
+static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH] __read_mostly;
/*
* Radix tree node cache.
diff --git a/lib/sha1.c b/lib/sha1.c
index 2f7f1148dfde..1cdabe3065f9 100644
--- a/lib/sha1.c
+++ b/lib/sha1.c
@@ -41,7 +41,7 @@ void sha_transform(__u32 *digest, const char *in, __u32 *W)
__u32 a, b, c, d, e, t, i;
for (i = 0; i < 16; i++)
- W[i] = be32_to_cpu(((const __u32 *)in)[i]);
+ W[i] = be32_to_cpu(((const __be32 *)in)[i]);
for (i = 0; i < 64; i++)
W[i+16] = rol32(W[i+13] ^ W[i+8] ^ W[i+2] ^ W[i], 1);
diff --git a/lib/textsearch.c b/lib/textsearch.c
new file mode 100644
index 000000000000..1e934c196f0f
--- /dev/null
+++ b/lib/textsearch.c
@@ -0,0 +1,317 @@
+/*
+ * lib/textsearch.c Generic text search interface
+ *
+ * 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.
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ * Pablo Neira Ayuso <pablo@eurodev.net>
+ *
+ * ==========================================================================
+ *
+ * INTRODUCTION
+ *
+ * The textsearch infrastructure provides text searching facitilies for
+ * both linear and non-linear data. Individual search algorithms are
+ * implemented in modules and chosen by the user.
+ *
+ * ARCHITECTURE
+ *
+ * User
+ * +----------------+
+ * | finish()|<--------------(6)-----------------+
+ * |get_next_block()|<--------------(5)---------------+ |
+ * | | Algorithm | |
+ * | | +------------------------------+
+ * | | | init() find() destroy() |
+ * | | +------------------------------+
+ * | | Core API ^ ^ ^
+ * | | +---------------+ (2) (4) (8)
+ * | (1)|----->| prepare() |---+ | |
+ * | (3)|----->| find()/next() |-----------+ |
+ * | (7)|----->| destroy() |----------------------+
+ * +----------------+ +---------------+
+ *
+ * (1) User configures a search by calling _prepare() specifying the
+ * search parameters such as the pattern and algorithm name.
+ * (2) Core requests the algorithm to allocate and initialize a search
+ * configuration according to the specified parameters.
+ * (3) User starts the search(es) by calling _find() or _next() to
+ * fetch subsequent occurrences. A state variable is provided
+ * to the algorihtm to store persistant variables.
+ * (4) Core eventually resets the search offset and forwards the find()
+ * request to the algorithm.
+ * (5) Algorithm calls get_next_block() provided by the user continously
+ * to fetch the data to be searched in block by block.
+ * (6) Algorithm invokes finish() after the last call to get_next_block
+ * to clean up any leftovers from get_next_block. (Optional)
+ * (7) User destroys the configuration by calling _destroy().
+ * (8) Core notifies the algorithm to destroy algorithm specific
+ * allocations. (Optional)
+ *
+ * USAGE
+ *
+ * Before a search can be performed, a configuration must be created
+ * by calling textsearch_prepare() specyfing the searching algorithm and
+ * the pattern to look for. The returned configuration may then be used
+ * for an arbitary amount of times and even in parallel as long as a
+ * separate struct ts_state variable is provided to every instance.
+ *
+ * The actual search is performed by either calling textsearch_find_-
+ * continuous() for linear data or by providing an own get_next_block()
+ * implementation and calling textsearch_find(). Both functions return
+ * the position of the first occurrence of the patern or UINT_MAX if
+ * no match was found. Subsequent occurences can be found by calling
+ * textsearch_next() regardless of the linearity of the data.
+ *
+ * Once you're done using a configuration it must be given back via
+ * textsearch_destroy.
+ *
+ * EXAMPLE
+ *
+ * int pos;
+ * struct ts_config *conf;
+ * struct ts_state state;
+ * const char *pattern = "chicken";
+ * const char *example = "We dance the funky chicken";
+ *
+ * conf = textsearch_prepare("kmp", pattern, strlen(pattern),
+ * GFP_KERNEL, TS_AUTOLOAD);
+ * if (IS_ERR(conf)) {
+ * err = PTR_ERR(conf);
+ * goto errout;
+ * }
+ *
+ * pos = textsearch_find_continuous(conf, &state, example, strlen(example));
+ * if (pos != UINT_MAX)
+ * panic("Oh my god, dancing chickens at %d\n", pos);
+ *
+ * textsearch_destroy(conf);
+ *
+ * ==========================================================================
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/rcupdate.h>
+#include <linux/err.h>
+#include <linux/textsearch.h>
+
+static LIST_HEAD(ts_ops);
+static DEFINE_SPINLOCK(ts_mod_lock);
+
+static inline struct ts_ops *lookup_ts_algo(const char *name)
+{
+ struct ts_ops *o;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(o, &ts_ops, list) {
+ if (!strcmp(name, o->name)) {
+ if (!try_module_get(o->owner))
+ o = NULL;
+ rcu_read_unlock();
+ return o;
+ }
+ }
+ rcu_read_unlock();
+
+ return NULL;
+}
+
+/**
+ * textsearch_register - register a textsearch module
+ * @ops: operations lookup table
+ *
+ * This function must be called by textsearch modules to announce
+ * their presence. The specified &@ops must have %name set to a
+ * unique identifier and the callbacks find(), init(), get_pattern(),
+ * and get_pattern_len() must be implemented.
+ *
+ * Returns 0 or -EEXISTS if another module has already registered
+ * with same name.
+ */
+int textsearch_register(struct ts_ops *ops)
+{
+ int err = -EEXIST;
+ struct ts_ops *o;
+
+ if (ops->name == NULL || ops->find == NULL || ops->init == NULL ||
+ ops->get_pattern == NULL || ops->get_pattern_len == NULL)
+ return -EINVAL;
+
+ spin_lock(&ts_mod_lock);
+ list_for_each_entry(o, &ts_ops, list) {
+ if (!strcmp(ops->name, o->name))
+ goto errout;
+ }
+
+ list_add_tail_rcu(&ops->list, &ts_ops);
+ err = 0;
+errout:
+ spin_unlock(&ts_mod_lock);
+ return err;
+}
+
+/**
+ * textsearch_unregister - unregister a textsearch module
+ * @ops: operations lookup table
+ *
+ * This function must be called by textsearch modules to announce
+ * their disappearance for examples when the module gets unloaded.
+ * The &ops parameter must be the same as the one during the
+ * registration.
+ *
+ * Returns 0 on success or -ENOENT if no matching textsearch
+ * registration was found.
+ */
+int textsearch_unregister(struct ts_ops *ops)
+{
+ int err = 0;
+ struct ts_ops *o;
+
+ spin_lock(&ts_mod_lock);
+ list_for_each_entry(o, &ts_ops, list) {
+ if (o == ops) {
+ list_del_rcu(&o->list);
+ goto out;
+ }
+ }
+
+ err = -ENOENT;
+out:
+ spin_unlock(&ts_mod_lock);
+ return err;
+}
+
+struct ts_linear_state
+{
+ unsigned int len;
+ const void *data;
+};
+
+static unsigned int get_linear_data(unsigned int consumed, const u8 **dst,
+ struct ts_config *conf,
+ struct ts_state *state)
+{
+ struct ts_linear_state *st = (struct ts_linear_state *) state->cb;
+
+ if (likely(consumed < st->len)) {
+ *dst = st->data + consumed;
+ return st->len - consumed;
+ }
+
+ return 0;
+}
+
+/**
+ * textsearch_find_continuous - search a pattern in continuous/linear data
+ * @conf: search configuration
+ * @state: search state
+ * @data: data to search in
+ * @len: length of data
+ *
+ * A simplified version of textsearch_find() for continuous/linear data.
+ * Call textsearch_next() to retrieve subsequent matches.
+ *
+ * Returns the position of first occurrence of the pattern or
+ * UINT_MAX if no occurrence was found.
+ */
+unsigned int textsearch_find_continuous(struct ts_config *conf,
+ struct ts_state *state,
+ const void *data, unsigned int len)
+{
+ struct ts_linear_state *st = (struct ts_linear_state *) state->cb;
+
+ conf->get_next_block = get_linear_data;
+ st->data = data;
+ st->len = len;
+
+ return textsearch_find(conf, state);
+}
+
+/**
+ * textsearch_prepare - Prepare a search
+ * @algo: name of search algorithm
+ * @pattern: pattern data
+ * @len: length of pattern
+ * @gfp_mask: allocation mask
+ * @flags: search flags
+ *
+ * Looks up the search algorithm module and creates a new textsearch
+ * configuration for the specified pattern. Upon completion all
+ * necessary refcnts are held and the configuration must be put back
+ * using textsearch_put() after usage.
+ *
+ * Note: The format of the pattern may not be compatible between
+ * the various search algorithms.
+ *
+ * Returns a new textsearch configuration according to the specified
+ * parameters or a ERR_PTR().
+ */
+struct ts_config *textsearch_prepare(const char *algo, const void *pattern,
+ unsigned int len, int gfp_mask, int flags)
+{
+ int err = -ENOENT;
+ struct ts_config *conf;
+ struct ts_ops *ops;
+
+ ops = lookup_ts_algo(algo);
+#ifdef CONFIG_KMOD
+ /*
+ * Why not always autoload you may ask. Some users are
+ * in a situation where requesting a module may deadlock,
+ * especially when the module is located on a NFS mount.
+ */
+ if (ops == NULL && flags & TS_AUTOLOAD) {
+ request_module("ts_%s", algo);
+ ops = lookup_ts_algo(algo);
+ }
+#endif
+
+ if (ops == NULL)
+ goto errout;
+
+ conf = ops->init(pattern, len, gfp_mask);
+ if (IS_ERR(conf)) {
+ err = PTR_ERR(conf);
+ goto errout;
+ }
+
+ conf->ops = ops;
+ return conf;
+
+errout:
+ if (ops)
+ module_put(ops->owner);
+
+ return ERR_PTR(err);
+}
+
+/**
+ * textsearch_destroy - destroy a search configuration
+ * @conf: search configuration
+ *
+ * Releases all references of the configuration and frees
+ * up the memory.
+ */
+void textsearch_destroy(struct ts_config *conf)
+{
+ if (conf->ops) {
+ if (conf->ops->destroy)
+ conf->ops->destroy(conf);
+ module_put(conf->ops->owner);
+ }
+
+ kfree(conf);
+}
+
+EXPORT_SYMBOL(textsearch_register);
+EXPORT_SYMBOL(textsearch_unregister);
+EXPORT_SYMBOL(textsearch_prepare);
+EXPORT_SYMBOL(textsearch_find_continuous);
+EXPORT_SYMBOL(textsearch_destroy);
diff --git a/lib/ts_fsm.c b/lib/ts_fsm.c
new file mode 100644
index 000000000000..d27c0a072940
--- /dev/null
+++ b/lib/ts_fsm.c
@@ -0,0 +1,338 @@
+/*
+ * lib/ts_fsm.c A naive finite state machine text search approach
+ *
+ * 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.
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ *
+ * A finite state machine consists of n states (struct ts_fsm_token)
+ * representing the pattern as a finite automation. The data is read
+ * sequentially on a octet basis. Every state token specifies the number
+ * of recurrences and the type of value accepted which can be either a
+ * specific character or ctype based set of characters. The available
+ * type of recurrences include 1, (0|1), [0 n], and [1 n].
+ *
+ * The algorithm differs between strict/non-strict mode specyfing
+ * whether the pattern has to start at the first octect. Strict mode
+ * is enabled by default and can be disabled by inserting
+ * TS_FSM_HEAD_IGNORE as the first token in the chain.
+ *
+ * The runtime performance of the algorithm should be around O(n),
+ * however while in strict mode the average runtime can be better.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/textsearch.h>
+#include <linux/textsearch_fsm.h>
+
+struct ts_fsm
+{
+ unsigned int ntokens;
+ struct ts_fsm_token tokens[0];
+};
+
+/* other values derived from ctype.h */
+#define _A 0x100 /* ascii */
+#define _W 0x200 /* wildcard */
+
+/* Map to _ctype flags and some magic numbers */
+static u16 token_map[TS_FSM_TYPE_MAX+1] = {
+ [TS_FSM_SPECIFIC] = 0,
+ [TS_FSM_WILDCARD] = _W,
+ [TS_FSM_CNTRL] = _C,
+ [TS_FSM_LOWER] = _L,
+ [TS_FSM_UPPER] = _U,
+ [TS_FSM_PUNCT] = _P,
+ [TS_FSM_SPACE] = _S,
+ [TS_FSM_DIGIT] = _D,
+ [TS_FSM_XDIGIT] = _D | _X,
+ [TS_FSM_ALPHA] = _U | _L,
+ [TS_FSM_ALNUM] = _U | _L | _D,
+ [TS_FSM_PRINT] = _P | _U | _L | _D | _SP,
+ [TS_FSM_GRAPH] = _P | _U | _L | _D,
+ [TS_FSM_ASCII] = _A,
+};
+
+static u16 token_lookup_tbl[256] = {
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 0- 3 */
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 4- 7 */
+_W|_A|_C, _W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C|_S, /* 8- 11 */
+_W|_A|_C|_S, _W|_A|_C|_S, _W|_A|_C, _W|_A|_C, /* 12- 15 */
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 16- 19 */
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 20- 23 */
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 24- 27 */
+_W|_A|_C, _W|_A|_C, _W|_A|_C, _W|_A|_C, /* 28- 31 */
+_W|_A|_S|_SP, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 32- 35 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 36- 39 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 40- 43 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 44- 47 */
+_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 48- 51 */
+_W|_A|_D, _W|_A|_D, _W|_A|_D, _W|_A|_D, /* 52- 55 */
+_W|_A|_D, _W|_A|_D, _W|_A|_P, _W|_A|_P, /* 56- 59 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 60- 63 */
+_W|_A|_P, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, /* 64- 67 */
+_W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U|_X, _W|_A|_U, /* 68- 71 */
+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 72- 75 */
+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 76- 79 */
+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 80- 83 */
+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_U, /* 84- 87 */
+_W|_A|_U, _W|_A|_U, _W|_A|_U, _W|_A|_P, /* 88- 91 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_P, /* 92- 95 */
+_W|_A|_P, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, /* 96- 99 */
+_W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L|_X, _W|_A|_L, /* 100-103 */
+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 104-107 */
+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 108-111 */
+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 112-115 */
+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_L, /* 116-119 */
+_W|_A|_L, _W|_A|_L, _W|_A|_L, _W|_A|_P, /* 120-123 */
+_W|_A|_P, _W|_A|_P, _W|_A|_P, _W|_A|_C, /* 124-127 */
+_W, _W, _W, _W, /* 128-131 */
+_W, _W, _W, _W, /* 132-135 */
+_W, _W, _W, _W, /* 136-139 */
+_W, _W, _W, _W, /* 140-143 */
+_W, _W, _W, _W, /* 144-147 */
+_W, _W, _W, _W, /* 148-151 */
+_W, _W, _W, _W, /* 152-155 */
+_W, _W, _W, _W, /* 156-159 */
+_W|_S|_SP, _W|_P, _W|_P, _W|_P, /* 160-163 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 164-167 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 168-171 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 172-175 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 176-179 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 180-183 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 184-187 */
+_W|_P, _W|_P, _W|_P, _W|_P, /* 188-191 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 192-195 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 196-199 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 200-203 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 204-207 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 208-211 */
+_W|_U, _W|_U, _W|_U, _W|_P, /* 212-215 */
+_W|_U, _W|_U, _W|_U, _W|_U, /* 216-219 */
+_W|_U, _W|_U, _W|_U, _W|_L, /* 220-223 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 224-227 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 228-231 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 232-235 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 236-239 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 240-243 */
+_W|_L, _W|_L, _W|_L, _W|_P, /* 244-247 */
+_W|_L, _W|_L, _W|_L, _W|_L, /* 248-251 */
+_W|_L, _W|_L, _W|_L, _W|_L}; /* 252-255 */
+
+static inline int match_token(struct ts_fsm_token *t, u8 d)
+{
+ if (t->type)
+ return (token_lookup_tbl[d] & t->type) != 0;
+ else
+ return t->value == d;
+}
+
+static unsigned int fsm_find(struct ts_config *conf, struct ts_state *state)
+{
+ struct ts_fsm *fsm = ts_config_priv(conf);
+ struct ts_fsm_token *cur = NULL, *next;
+ unsigned int match_start, block_idx = 0, tok_idx;
+ unsigned block_len = 0, strict, consumed = state->offset;
+ const u8 *data;
+
+#define GET_NEXT_BLOCK() \
+({ consumed += block_idx; \
+ block_idx = 0; \
+ block_len = conf->get_next_block(consumed, &data, conf, state); })
+
+#define TOKEN_MISMATCH() \
+ do { \
+ if (strict) \
+ goto no_match; \
+ block_idx++; \
+ goto startover; \
+ } while(0)
+
+#define end_of_data() unlikely(block_idx >= block_len && !GET_NEXT_BLOCK())
+
+ if (end_of_data())
+ goto no_match;
+
+ strict = fsm->tokens[0].recur != TS_FSM_HEAD_IGNORE;
+
+startover:
+ match_start = consumed + block_idx;
+
+ for (tok_idx = 0; tok_idx < fsm->ntokens; tok_idx++) {
+ cur = &fsm->tokens[tok_idx];
+
+ if (likely(tok_idx < (fsm->ntokens - 1)))
+ next = &fsm->tokens[tok_idx + 1];
+ else
+ next = NULL;
+
+ switch (cur->recur) {
+ case TS_FSM_SINGLE:
+ if (end_of_data())
+ goto no_match;
+
+ if (!match_token(cur, data[block_idx]))
+ TOKEN_MISMATCH();
+ break;
+
+ case TS_FSM_PERHAPS:
+ if (end_of_data() ||
+ !match_token(cur, data[block_idx]))
+ continue;
+ break;
+
+ case TS_FSM_MULTI:
+ if (end_of_data())
+ goto no_match;
+
+ if (!match_token(cur, data[block_idx]))
+ TOKEN_MISMATCH();
+
+ block_idx++;
+ /* fall through */
+
+ case TS_FSM_ANY:
+ if (next == NULL)
+ goto found_match;
+
+ if (end_of_data())
+ continue;
+
+ while (!match_token(next, data[block_idx])) {
+ if (!match_token(cur, data[block_idx]))
+ TOKEN_MISMATCH();
+ block_idx++;
+ if (end_of_data())
+ goto no_match;
+ }
+ continue;
+
+ /*
+ * Optimization: Prefer small local loop over jumping
+ * back and forth until garbage at head is munched.
+ */
+ case TS_FSM_HEAD_IGNORE:
+ if (end_of_data())
+ continue;
+
+ while (!match_token(next, data[block_idx])) {
+ /*
+ * Special case, don't start over upon
+ * a mismatch, give the user the
+ * chance to specify the type of data
+ * allowed to be ignored.
+ */
+ if (!match_token(cur, data[block_idx]))
+ goto no_match;
+
+ block_idx++;
+ if (end_of_data())
+ goto no_match;
+ }
+
+ match_start = consumed + block_idx;
+ continue;
+ }
+
+ block_idx++;
+ }
+
+ if (end_of_data())
+ goto found_match;
+
+no_match:
+ return UINT_MAX;
+
+found_match:
+ state->offset = consumed + block_idx;
+ return match_start;
+}
+
+static struct ts_config *fsm_init(const void *pattern, unsigned int len,
+ int gfp_mask)
+{
+ int i, err = -EINVAL;
+ struct ts_config *conf;
+ struct ts_fsm *fsm;
+ struct ts_fsm_token *tokens = (struct ts_fsm_token *) pattern;
+ unsigned int ntokens = len / sizeof(*tokens);
+ size_t priv_size = sizeof(*fsm) + len;
+
+ if (len % sizeof(struct ts_fsm_token) || ntokens < 1)
+ goto errout;
+
+ for (i = 0; i < ntokens; i++) {
+ struct ts_fsm_token *t = &tokens[i];
+
+ if (t->type > TS_FSM_TYPE_MAX || t->recur > TS_FSM_RECUR_MAX)
+ goto errout;
+
+ if (t->recur == TS_FSM_HEAD_IGNORE &&
+ (i != 0 || i == (ntokens - 1)))
+ goto errout;
+ }
+
+ conf = alloc_ts_config(priv_size, gfp_mask);
+ if (IS_ERR(conf))
+ return conf;
+
+ fsm = ts_config_priv(conf);
+ fsm->ntokens = ntokens;
+ memcpy(fsm->tokens, pattern, len);
+
+ for (i = 0; i < fsm->ntokens; i++) {
+ struct ts_fsm_token *t = &fsm->tokens[i];
+ t->type = token_map[t->type];
+ }
+
+ return conf;
+
+errout:
+ return ERR_PTR(err);
+}
+
+static void *fsm_get_pattern(struct ts_config *conf)
+{
+ struct ts_fsm *fsm = ts_config_priv(conf);
+ return fsm->tokens;
+}
+
+static unsigned int fsm_get_pattern_len(struct ts_config *conf)
+{
+ struct ts_fsm *fsm = ts_config_priv(conf);
+ return fsm->ntokens * sizeof(struct ts_fsm_token);
+}
+
+static struct ts_ops fsm_ops = {
+ .name = "fsm",
+ .find = fsm_find,
+ .init = fsm_init,
+ .get_pattern = fsm_get_pattern,
+ .get_pattern_len = fsm_get_pattern_len,
+ .owner = THIS_MODULE,
+ .list = LIST_HEAD_INIT(fsm_ops.list)
+};
+
+static int __init init_fsm(void)
+{
+ return textsearch_register(&fsm_ops);
+}
+
+static void __exit exit_fsm(void)
+{
+ textsearch_unregister(&fsm_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_fsm);
+module_exit(exit_fsm);
diff --git a/lib/ts_kmp.c b/lib/ts_kmp.c
new file mode 100644
index 000000000000..73266b975585
--- /dev/null
+++ b/lib/ts_kmp.c
@@ -0,0 +1,145 @@
+/*
+ * lib/ts_kmp.c Knuth-Morris-Pratt text search implementation
+ *
+ * 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.
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ *
+ * ==========================================================================
+ *
+ * Implements a linear-time string-matching algorithm due to Knuth,
+ * Morris, and Pratt [1]. Their algorithm avoids the explicit
+ * computation of the transition function DELTA altogether. Its
+ * matching time is O(n), for n being length(text), using just an
+ * auxiliary function PI[1..m], for m being length(pattern),
+ * precomputed from the pattern in time O(m). The array PI allows
+ * the transition function DELTA to be computed efficiently
+ * "on the fly" as needed. Roughly speaking, for any state
+ * "q" = 0,1,...,m and any character "a" in SIGMA, the value
+ * PI["q"] contains the information that is independent of "a" and
+ * is needed to compute DELTA("q", "a") [2]. Since the array PI
+ * has only m entries, whereas DELTA has O(m|SIGMA|) entries, we
+ * save a factor of |SIGMA| in the preprocessing time by computing
+ * PI rather than DELTA.
+ *
+ * [1] Cormen, Leiserson, Rivest, Stein
+ * Introdcution to Algorithms, 2nd Edition, MIT Press
+ * [2] See finite automation theory
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/textsearch.h>
+
+struct ts_kmp
+{
+ u8 * pattern;
+ unsigned int pattern_len;
+ unsigned int prefix_tbl[0];
+};
+
+static unsigned int kmp_find(struct ts_config *conf, struct ts_state *state)
+{
+ struct ts_kmp *kmp = ts_config_priv(conf);
+ unsigned int i, q = 0, text_len, consumed = state->offset;
+ const u8 *text;
+
+ for (;;) {
+ text_len = conf->get_next_block(consumed, &text, conf, state);
+
+ if (unlikely(text_len == 0))
+ break;
+
+ for (i = 0; i < text_len; i++) {
+ while (q > 0 && kmp->pattern[q] != text[i])
+ q = kmp->prefix_tbl[q - 1];
+ if (kmp->pattern[q] == text[i])
+ q++;
+ if (unlikely(q == kmp->pattern_len)) {
+ state->offset = consumed + i + 1;
+ return state->offset - kmp->pattern_len;
+ }
+ }
+
+ consumed += text_len;
+ }
+
+ return UINT_MAX;
+}
+
+static inline void compute_prefix_tbl(const u8 *pattern, unsigned int len,
+ unsigned int *prefix_tbl)
+{
+ unsigned int k, q;
+
+ for (k = 0, q = 1; q < len; q++) {
+ while (k > 0 && pattern[k] != pattern[q])
+ k = prefix_tbl[k-1];
+ if (pattern[k] == pattern[q])
+ k++;
+ prefix_tbl[q] = k;
+ }
+}
+
+static struct ts_config *kmp_init(const void *pattern, unsigned int len,
+ int gfp_mask)
+{
+ struct ts_config *conf;
+ struct ts_kmp *kmp;
+ unsigned int prefix_tbl_len = len * sizeof(unsigned int);
+ size_t priv_size = sizeof(*kmp) + len + prefix_tbl_len;
+
+ conf = alloc_ts_config(priv_size, gfp_mask);
+ if (IS_ERR(conf))
+ return conf;
+
+ kmp = ts_config_priv(conf);
+ kmp->pattern_len = len;
+ compute_prefix_tbl(pattern, len, kmp->prefix_tbl);
+ kmp->pattern = (u8 *) kmp->prefix_tbl + prefix_tbl_len;
+ memcpy(kmp->pattern, pattern, len);
+
+ return conf;
+}
+
+static void *kmp_get_pattern(struct ts_config *conf)
+{
+ struct ts_kmp *kmp = ts_config_priv(conf);
+ return kmp->pattern;
+}
+
+static unsigned int kmp_get_pattern_len(struct ts_config *conf)
+{
+ struct ts_kmp *kmp = ts_config_priv(conf);
+ return kmp->pattern_len;
+}
+
+static struct ts_ops kmp_ops = {
+ .name = "kmp",
+ .find = kmp_find,
+ .init = kmp_init,
+ .get_pattern = kmp_get_pattern,
+ .get_pattern_len = kmp_get_pattern_len,
+ .owner = THIS_MODULE,
+ .list = LIST_HEAD_INIT(kmp_ops.list)
+};
+
+static int __init init_kmp(void)
+{
+ return textsearch_register(&kmp_ops);
+}
+
+static void __exit exit_kmp(void)
+{
+ textsearch_unregister(&kmp_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_kmp);
+module_exit(exit_kmp);
diff --git a/mm/Makefile b/mm/Makefile
index 8f70ffd763c8..4cd69e3ce421 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_SPARSEMEM) += sparse.o
obj-$(CONFIG_SHMEM) += shmem.o
obj-$(CONFIG_TINY_SHMEM) += tiny-shmem.o
+obj-$(CONFIG_FS_XIP) += filemap_xip.o
diff --git a/mm/bootmem.c b/mm/bootmem.c
index f82f7aebbee3..c1330cc19783 100644
--- a/mm/bootmem.c
+++ b/mm/bootmem.c
@@ -33,6 +33,14 @@ EXPORT_SYMBOL(max_pfn); /* This is exported so
* dma_get_required_mask(), which uses
* it, can be an inline function */
+#ifdef CONFIG_CRASH_DUMP
+/*
+ * If we have booted due to a crash, max_pfn will be a very low value. We need
+ * to know the amount of memory that the previous kernel used.
+ */
+unsigned long saved_max_pfn;
+#endif
+
/* return the number of _pages_ that will be allocated for the boot bitmap */
unsigned long __init bootmem_bootmap_pages (unsigned long pages)
{
@@ -57,7 +65,7 @@ static unsigned long __init init_bootmem_core (pg_data_t *pgdat,
pgdat->pgdat_next = pgdat_list;
pgdat_list = pgdat;
- mapsize = (mapsize + (sizeof(long) - 1UL)) & ~(sizeof(long) - 1UL);
+ mapsize = ALIGN(mapsize, sizeof(long));
bdata->node_bootmem_map = phys_to_virt(mapstart << PAGE_SHIFT);
bdata->node_boot_start = (start << PAGE_SHIFT);
bdata->node_low_pfn = end;
@@ -178,7 +186,7 @@ __alloc_bootmem_core(struct bootmem_data *bdata, unsigned long size,
} else
preferred = 0;
- preferred = ((preferred + align - 1) & ~(align - 1)) >> PAGE_SHIFT;
+ preferred = ALIGN(preferred, align) >> PAGE_SHIFT;
preferred += offset;
areasize = (size+PAGE_SIZE-1)/PAGE_SIZE;
incr = align >> PAGE_SHIFT ? : 1;
@@ -219,7 +227,7 @@ found:
*/
if (align < PAGE_SIZE &&
bdata->last_offset && bdata->last_pos+1 == start) {
- offset = (bdata->last_offset+align-1) & ~(align-1);
+ offset = ALIGN(bdata->last_offset, align);
BUG_ON(offset > PAGE_SIZE);
remaining_size = PAGE_SIZE-offset;
if (size < remaining_size) {
diff --git a/mm/fadvise.c b/mm/fadvise.c
index 57264d74b8bf..5f19e87bc5af 100644
--- a/mm/fadvise.c
+++ b/mm/fadvise.c
@@ -43,6 +43,10 @@ asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice)
goto out;
}
+ if (mapping->a_ops->get_xip_page)
+ /* no bad return value, but ignore advice */
+ goto out;
+
/* Careful about overflows. Len == 0 means "as much as possible" */
endbyte = offset + len;
if (!len || endbyte < len)
diff --git a/mm/filemap.c b/mm/filemap.c
index a3598b542a31..c11418dd94e8 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -28,6 +28,7 @@
#include <linux/blkdev.h>
#include <linux/security.h>
#include <linux/syscalls.h>
+#include "filemap.h"
/*
* FIXME: remove all knowledge of the buffer layer from the core VM
*/
@@ -1714,32 +1715,7 @@ int remove_suid(struct dentry *dentry)
}
EXPORT_SYMBOL(remove_suid);
-/*
- * Copy as much as we can into the page and return the number of bytes which
- * were sucessfully copied. If a fault is encountered then clear the page
- * out to (offset+bytes) and return the number of bytes which were copied.
- */
-static inline size_t
-filemap_copy_from_user(struct page *page, unsigned long offset,
- const char __user *buf, unsigned bytes)
-{
- char *kaddr;
- int left;
-
- kaddr = kmap_atomic(page, KM_USER0);
- left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
- kunmap_atomic(kaddr, KM_USER0);
-
- if (left != 0) {
- /* Do it the slow way */
- kaddr = kmap(page);
- left = __copy_from_user(kaddr + offset, buf, bytes);
- kunmap(page);
- }
- return bytes - left;
-}
-
-static size_t
+size_t
__filemap_copy_from_user_iovec(char *vaddr,
const struct iovec *iov, size_t base, size_t bytes)
{
@@ -1767,52 +1743,6 @@ __filemap_copy_from_user_iovec(char *vaddr,
}
/*
- * This has the same sideeffects and return value as filemap_copy_from_user().
- * The difference is that on a fault we need to memset the remainder of the
- * page (out to offset+bytes), to emulate filemap_copy_from_user()'s
- * single-segment behaviour.
- */
-static inline size_t
-filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
- const struct iovec *iov, size_t base, size_t bytes)
-{
- char *kaddr;
- size_t copied;
-
- kaddr = kmap_atomic(page, KM_USER0);
- copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
- base, bytes);
- kunmap_atomic(kaddr, KM_USER0);
- if (copied != bytes) {
- kaddr = kmap(page);
- copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
- base, bytes);
- kunmap(page);
- }
- return copied;
-}
-
-static inline void
-filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
-{
- const struct iovec *iov = *iovp;
- size_t base = *basep;
-
- while (bytes) {
- int copy = min(bytes, iov->iov_len - base);
-
- bytes -= copy;
- base += copy;
- if (iov->iov_len == base) {
- iov++;
- base = 0;
- }
- }
- *iovp = iov;
- *basep = base;
-}
-
-/*
* Performs necessary checks before doing a write
*
* Can adjust writing position aor amount of bytes to write.
@@ -1921,8 +1851,11 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
* i_sem is held, which protects generic_osync_inode() from
* livelocking.
*/
- if (written >= 0 && file->f_flags & O_SYNC)
- generic_osync_inode(inode, mapping, OSYNC_METADATA);
+ if (written >= 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
+ int err = generic_osync_inode(inode, mapping, OSYNC_METADATA);
+ if (err < 0)
+ written = err;
+ }
if (written == count && !is_sync_kiocb(iocb))
written = -EIOCBQUEUED;
return written;
@@ -2021,7 +1954,9 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov,
if (unlikely(nr_segs > 1)) {
filemap_set_next_iovec(&cur_iov,
&iov_base, status);
- buf = cur_iov->iov_base + iov_base;
+ if (count)
+ buf = cur_iov->iov_base +
+ iov_base;
} else {
iov_base += status;
}
diff --git a/mm/filemap.h b/mm/filemap.h
new file mode 100644
index 000000000000..13793ba0ce17
--- /dev/null
+++ b/mm/filemap.h
@@ -0,0 +1,94 @@
+/*
+ * linux/mm/filemap.h
+ *
+ * Copyright (C) 1994-1999 Linus Torvalds
+ */
+
+#ifndef __FILEMAP_H
+#define __FILEMAP_H
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/uio.h>
+#include <linux/config.h>
+#include <asm/uaccess.h>
+
+size_t
+__filemap_copy_from_user_iovec(char *vaddr,
+ const struct iovec *iov,
+ size_t base,
+ size_t bytes);
+
+/*
+ * Copy as much as we can into the page and return the number of bytes which
+ * were sucessfully copied. If a fault is encountered then clear the page
+ * out to (offset+bytes) and return the number of bytes which were copied.
+ */
+static inline size_t
+filemap_copy_from_user(struct page *page, unsigned long offset,
+ const char __user *buf, unsigned bytes)
+{
+ char *kaddr;
+ int left;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ left = __copy_from_user_inatomic(kaddr + offset, buf, bytes);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ if (left != 0) {
+ /* Do it the slow way */
+ kaddr = kmap(page);
+ left = __copy_from_user(kaddr + offset, buf, bytes);
+ kunmap(page);
+ }
+ return bytes - left;
+}
+
+/*
+ * This has the same sideeffects and return value as filemap_copy_from_user().
+ * The difference is that on a fault we need to memset the remainder of the
+ * page (out to offset+bytes), to emulate filemap_copy_from_user()'s
+ * single-segment behaviour.
+ */
+static inline size_t
+filemap_copy_from_user_iovec(struct page *page, unsigned long offset,
+ const struct iovec *iov, size_t base, size_t bytes)
+{
+ char *kaddr;
+ size_t copied;
+
+ kaddr = kmap_atomic(page, KM_USER0);
+ copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+ base, bytes);
+ kunmap_atomic(kaddr, KM_USER0);
+ if (copied != bytes) {
+ kaddr = kmap(page);
+ copied = __filemap_copy_from_user_iovec(kaddr + offset, iov,
+ base, bytes);
+ kunmap(page);
+ }
+ return copied;
+}
+
+static inline void
+filemap_set_next_iovec(const struct iovec **iovp, size_t *basep, size_t bytes)
+{
+ const struct iovec *iov = *iovp;
+ size_t base = *basep;
+
+ while (bytes) {
+ int copy = min(bytes, iov->iov_len - base);
+
+ bytes -= copy;
+ base += copy;
+ if (iov->iov_len == base) {
+ iov++;
+ base = 0;
+ }
+ }
+ *iovp = iov;
+ *basep = base;
+}
+#endif
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c
new file mode 100644
index 000000000000..4553b2c5aab4
--- /dev/null
+++ b/mm/filemap_xip.c
@@ -0,0 +1,447 @@
+/*
+ * linux/mm/filemap_xip.c
+ *
+ * Copyright (C) 2005 IBM Corporation
+ * Author: Carsten Otte <cotte@de.ibm.com>
+ *
+ * derived from linux/mm/filemap.c - Copyright (C) Linus Torvalds
+ *
+ */
+
+#include <linux/fs.h>
+#include <linux/pagemap.h>
+#include <linux/module.h>
+#include <linux/uio.h>
+#include <linux/rmap.h>
+#include <asm/tlbflush.h>
+#include "filemap.h"
+
+/*
+ * This is a file read routine for execute in place files, and uses
+ * the mapping->a_ops->get_xip_page() function for the actual low-level
+ * stuff.
+ *
+ * Note the struct file* is not used at all. It may be NULL.
+ */
+static void
+do_xip_mapping_read(struct address_space *mapping,
+ struct file_ra_state *_ra,
+ struct file *filp,
+ loff_t *ppos,
+ read_descriptor_t *desc,
+ read_actor_t actor)
+{
+ struct inode *inode = mapping->host;
+ unsigned long index, end_index, offset;
+ loff_t isize;
+
+ BUG_ON(!mapping->a_ops->get_xip_page);
+
+ index = *ppos >> PAGE_CACHE_SHIFT;
+ offset = *ppos & ~PAGE_CACHE_MASK;
+
+ isize = i_size_read(inode);
+ if (!isize)
+ goto out;
+
+ end_index = (isize - 1) >> PAGE_CACHE_SHIFT;
+ for (;;) {
+ struct page *page;
+ unsigned long nr, ret;
+
+ /* nr is the maximum number of bytes to copy from this page */
+ nr = PAGE_CACHE_SIZE;
+ if (index >= end_index) {
+ if (index > end_index)
+ goto out;
+ nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1;
+ if (nr <= offset) {
+ goto out;
+ }
+ }
+ nr = nr - offset;
+
+ page = mapping->a_ops->get_xip_page(mapping,
+ index*(PAGE_SIZE/512), 0);
+ if (!page)
+ goto no_xip_page;
+ if (unlikely(IS_ERR(page))) {
+ if (PTR_ERR(page) == -ENODATA) {
+ /* sparse */
+ page = virt_to_page(empty_zero_page);
+ } else {
+ desc->error = PTR_ERR(page);
+ goto out;
+ }
+ } else
+ BUG_ON(!PageUptodate(page));
+
+ /* If users can be writing to this page using arbitrary
+ * virtual addresses, take care about potential aliasing
+ * before reading the page on the kernel side.
+ */
+ if (mapping_writably_mapped(mapping))
+ flush_dcache_page(page);
+
+ /*
+ * Ok, we have the page, and it's up-to-date, so
+ * now we can copy it to user space...
+ *
+ * The actor routine returns how many bytes were actually used..
+ * NOTE! This may not be the same as how much of a user buffer
+ * we filled up (we may be padding etc), so we can only update
+ * "pos" here (the actor routine has to update the user buffer
+ * pointers and the remaining count).
+ */
+ ret = actor(desc, page, offset, nr);
+ offset += ret;
+ index += offset >> PAGE_CACHE_SHIFT;
+ offset &= ~PAGE_CACHE_MASK;
+
+ if (ret == nr && desc->count)
+ continue;
+ goto out;
+
+no_xip_page:
+ /* Did not get the page. Report it */
+ desc->error = -EIO;
+ goto out;
+ }
+
+out:
+ *ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
+ if (filp)
+ file_accessed(filp);
+}
+
+ssize_t
+xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos)
+{
+ read_descriptor_t desc;
+
+ if (!access_ok(VERIFY_WRITE, buf, len))
+ return -EFAULT;
+
+ desc.written = 0;
+ desc.arg.buf = buf;
+ desc.count = len;
+ desc.error = 0;
+
+ do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp,
+ ppos, &desc, file_read_actor);
+
+ if (desc.written)
+ return desc.written;
+ else
+ return desc.error;
+}
+EXPORT_SYMBOL_GPL(xip_file_read);
+
+ssize_t
+xip_file_sendfile(struct file *in_file, loff_t *ppos,
+ size_t count, read_actor_t actor, void *target)
+{
+ read_descriptor_t desc;
+
+ if (!count)
+ return 0;
+
+ desc.written = 0;
+ desc.count = count;
+ desc.arg.data = target;
+ desc.error = 0;
+
+ do_xip_mapping_read(in_file->f_mapping, &in_file->f_ra, in_file,
+ ppos, &desc, actor);
+ if (desc.written)
+ return desc.written;
+ return desc.error;
+}
+EXPORT_SYMBOL_GPL(xip_file_sendfile);
+
+/*
+ * __xip_unmap is invoked from xip_unmap and
+ * xip_write
+ *
+ * This function walks all vmas of the address_space and unmaps the
+ * empty_zero_page when found at pgoff. Should it go in rmap.c?
+ */
+static void
+__xip_unmap (struct address_space * mapping,
+ unsigned long pgoff)
+{
+ struct vm_area_struct *vma;
+ struct mm_struct *mm;
+ struct prio_tree_iter iter;
+ unsigned long address;
+ pte_t *pte;
+ pte_t pteval;
+
+ spin_lock(&mapping->i_mmap_lock);
+ vma_prio_tree_foreach(vma, &iter, &mapping->i_mmap, pgoff, pgoff) {
+ mm = vma->vm_mm;
+ address = vma->vm_start +
+ ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
+ BUG_ON(address < vma->vm_start || address >= vma->vm_end);
+ /*
+ * We need the page_table_lock to protect us from page faults,
+ * munmap, fork, etc...
+ */
+ pte = page_check_address(virt_to_page(empty_zero_page), mm,
+ address);
+ if (!IS_ERR(pte)) {
+ /* Nuke the page table entry. */
+ flush_cache_page(vma, address, pte_pfn(*pte));
+ pteval = ptep_clear_flush(vma, address, pte);
+ BUG_ON(pte_dirty(pteval));
+ pte_unmap(pte);
+ spin_unlock(&mm->page_table_lock);
+ }
+ }
+ spin_unlock(&mapping->i_mmap_lock);
+}
+
+/*
+ * xip_nopage() is invoked via the vma operations vector for a
+ * mapped memory region to read in file data during a page fault.
+ *
+ * This function is derived from filemap_nopage, but used for execute in place
+ */
+static struct page *
+xip_file_nopage(struct vm_area_struct * area,
+ unsigned long address,
+ int *type)
+{
+ struct file *file = area->vm_file;
+ struct address_space *mapping = file->f_mapping;
+ struct inode *inode = mapping->host;
+ struct page *page;
+ unsigned long size, pgoff, endoff;
+
+ pgoff = ((address - area->vm_start) >> PAGE_CACHE_SHIFT)
+ + area->vm_pgoff;
+ endoff = ((area->vm_end - area->vm_start) >> PAGE_CACHE_SHIFT)
+ + area->vm_pgoff;
+
+ size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ if (pgoff >= size) {
+ return NULL;
+ }
+
+ page = mapping->a_ops->get_xip_page(mapping, pgoff*(PAGE_SIZE/512), 0);
+ if (!IS_ERR(page)) {
+ BUG_ON(!PageUptodate(page));
+ return page;
+ }
+ if (PTR_ERR(page) != -ENODATA)
+ return NULL;
+
+ /* sparse block */
+ if ((area->vm_flags & (VM_WRITE | VM_MAYWRITE)) &&
+ (area->vm_flags & (VM_SHARED| VM_MAYSHARE)) &&
+ (!(mapping->host->i_sb->s_flags & MS_RDONLY))) {
+ /* maybe shared writable, allocate new block */
+ page = mapping->a_ops->get_xip_page (mapping,
+ pgoff*(PAGE_SIZE/512), 1);
+ if (IS_ERR(page))
+ return NULL;
+ BUG_ON(!PageUptodate(page));
+ /* unmap page at pgoff from all other vmas */
+ __xip_unmap(mapping, pgoff);
+ } else {
+ /* not shared and writable, use empty_zero_page */
+ page = virt_to_page(empty_zero_page);
+ }
+
+ return page;
+}
+
+static struct vm_operations_struct xip_file_vm_ops = {
+ .nopage = xip_file_nopage,
+};
+
+int xip_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+ BUG_ON(!file->f_mapping->a_ops->get_xip_page);
+
+ file_accessed(file);
+ vma->vm_ops = &xip_file_vm_ops;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xip_file_mmap);
+
+static ssize_t
+__xip_file_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t pos, loff_t *ppos)
+{
+ struct address_space * mapping = filp->f_mapping;
+ struct address_space_operations *a_ops = mapping->a_ops;
+ struct inode *inode = mapping->host;
+ long status = 0;
+ struct page *page;
+ size_t bytes;
+ ssize_t written = 0;
+
+ BUG_ON(!mapping->a_ops->get_xip_page);
+
+ do {
+ unsigned long index;
+ unsigned long offset;
+ size_t copied;
+
+ offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
+ index = pos >> PAGE_CACHE_SHIFT;
+ bytes = PAGE_CACHE_SIZE - offset;
+ if (bytes > count)
+ bytes = count;
+
+ /*
+ * Bring in the user page that we will copy from _first_.
+ * Otherwise there's a nasty deadlock on copying from the
+ * same page as we're writing to, without it being marked
+ * up-to-date.
+ */
+ fault_in_pages_readable(buf, bytes);
+
+ page = a_ops->get_xip_page(mapping,
+ index*(PAGE_SIZE/512), 0);
+ if (IS_ERR(page) && (PTR_ERR(page) == -ENODATA)) {
+ /* we allocate a new page unmap it */
+ page = a_ops->get_xip_page(mapping,
+ index*(PAGE_SIZE/512), 1);
+ if (!IS_ERR(page))
+ /* unmap page at pgoff from all other vmas */
+ __xip_unmap(mapping, index);
+ }
+
+ if (IS_ERR(page)) {
+ status = PTR_ERR(page);
+ break;
+ }
+
+ BUG_ON(!PageUptodate(page));
+
+ copied = filemap_copy_from_user(page, offset, buf, bytes);
+ flush_dcache_page(page);
+ if (likely(copied > 0)) {
+ status = copied;
+
+ if (status >= 0) {
+ written += status;
+ count -= status;
+ pos += status;
+ buf += status;
+ }
+ }
+ if (unlikely(copied != bytes))
+ if (status >= 0)
+ status = -EFAULT;
+ if (status < 0)
+ break;
+ } while (count);
+ *ppos = pos;
+ /*
+ * No need to use i_size_read() here, the i_size
+ * cannot change under us because we hold i_sem.
+ */
+ if (pos > inode->i_size) {
+ i_size_write(inode, pos);
+ mark_inode_dirty(inode);
+ }
+
+ return written ? written : status;
+}
+
+ssize_t
+xip_file_write(struct file *filp, const char __user *buf, size_t len,
+ loff_t *ppos)
+{
+ struct address_space *mapping = filp->f_mapping;
+ struct inode *inode = mapping->host;
+ size_t count;
+ loff_t pos;
+ ssize_t ret;
+
+ down(&inode->i_sem);
+
+ if (!access_ok(VERIFY_READ, buf, len)) {
+ ret=-EFAULT;
+ goto out_up;
+ }
+
+ pos = *ppos;
+ count = len;
+
+ vfs_check_frozen(inode->i_sb, SB_FREEZE_WRITE);
+
+ /* We can write back this queue in page reclaim */
+ current->backing_dev_info = mapping->backing_dev_info;
+
+ ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode));
+ if (ret)
+ goto out_backing;
+ if (count == 0)
+ goto out_backing;
+
+ ret = remove_suid(filp->f_dentry);
+ if (ret)
+ goto out_backing;
+
+ inode_update_time(inode, 1);
+
+ ret = __xip_file_write (filp, buf, count, pos, ppos);
+
+ out_backing:
+ current->backing_dev_info = NULL;
+ out_up:
+ up(&inode->i_sem);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(xip_file_write);
+
+/*
+ * truncate a page used for execute in place
+ * functionality is analog to block_truncate_page but does use get_xip_page
+ * to get the page instead of page cache
+ */
+int
+xip_truncate_page(struct address_space *mapping, loff_t from)
+{
+ pgoff_t index = from >> PAGE_CACHE_SHIFT;
+ unsigned offset = from & (PAGE_CACHE_SIZE-1);
+ unsigned blocksize;
+ unsigned length;
+ struct page *page;
+ void *kaddr;
+
+ BUG_ON(!mapping->a_ops->get_xip_page);
+
+ blocksize = 1 << mapping->host->i_blkbits;
+ length = offset & (blocksize - 1);
+
+ /* Block boundary? Nothing to do */
+ if (!length)
+ return 0;
+
+ length = blocksize - length;
+
+ page = mapping->a_ops->get_xip_page(mapping,
+ index*(PAGE_SIZE/512), 0);
+ if (!page)
+ return -ENOMEM;
+ if (unlikely(IS_ERR(page))) {
+ if (PTR_ERR(page) == -ENODATA)
+ /* Hole? No need to truncate */
+ return 0;
+ else
+ return PTR_ERR(page);
+ } else
+ BUG_ON(!PageUptodate(page));
+ kaddr = kmap_atomic(page, KM_USER0);
+ memset(kaddr + offset, 0, length);
+ kunmap_atomic(kaddr, KM_USER0);
+
+ flush_dcache_page(page);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(xip_truncate_page);
diff --git a/mm/madvise.c b/mm/madvise.c
index 54a5d3bc55d5..73180a22877e 100644
--- a/mm/madvise.c
+++ b/mm/madvise.c
@@ -86,6 +86,11 @@ static long madvise_willneed(struct vm_area_struct * vma,
if (!file)
return -EBADF;
+ if (file->f_mapping->a_ops->get_xip_page) {
+ /* no bad return value, but ignore advice */
+ return 0;
+ }
+
*prev = vma;
start = ((start - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff;
if (end > vma->vm_end)
diff --git a/mm/memory.c b/mm/memory.c
index 30975ef48722..beabdefa6254 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -1139,7 +1139,7 @@ int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr,
{
pgd_t *pgd;
unsigned long next;
- unsigned long end = addr + size;
+ unsigned long end = addr + PAGE_ALIGN(size);
struct mm_struct *mm = vma->vm_mm;
int err;
@@ -1458,7 +1458,7 @@ restart:
* unmap_mapping_range - unmap the portion of all mmaps
* in the specified address_space corresponding to the specified
* page range in the underlying file.
- * @address_space: the address space containing mmaps to be unmapped.
+ * @mapping: the address space containing mmaps to be unmapped.
* @holebegin: byte in first page to unmap, relative to the start of
* the underlying file. This will be rounded down to a PAGE_SIZE
* boundary. Note that this is different from vmtruncate(), which
diff --git a/mm/mempool.c b/mm/mempool.c
index 9a72f7d918fa..65f2957b8d51 100644
--- a/mm/mempool.c
+++ b/mm/mempool.c
@@ -205,7 +205,7 @@ void * mempool_alloc(mempool_t *pool, unsigned int __nocast gfp_mask)
void *element;
unsigned long flags;
wait_queue_t wait;
- int gfp_temp;
+ unsigned int gfp_temp;
might_sleep_if(gfp_mask & __GFP_WAIT);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 59666d905f19..1e56076672f5 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -253,14 +253,16 @@ static struct mm_struct *oom_kill_process(struct task_struct *p)
* OR try to be smart about which process to kill. Note that we
* don't have to be perfect here, we just have to be good.
*/
-void out_of_memory(unsigned int __nocast gfp_mask)
+void out_of_memory(unsigned int __nocast gfp_mask, int order)
{
struct mm_struct *mm = NULL;
task_t * p;
- printk("oom-killer: gfp_mask=0x%x\n", gfp_mask);
- /* print memory stats */
- show_mem();
+ if (printk_ratelimit()) {
+ printk("oom-killer: gfp_mask=0x%x, order=%d\n",
+ gfp_mask, order);
+ show_mem();
+ }
read_lock(&tasklist_lock);
retry:
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 613b99a55917..a6329fa8f862 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -354,7 +354,7 @@ static void background_writeout(unsigned long _min_pages)
* the whole world. Returns 0 if a pdflush thread was dispatched. Returns
* -1 if all pdflush threads were busy.
*/
-int wakeup_bdflush(long nr_pages)
+int wakeup_pdflush(long nr_pages)
{
if (nr_pages == 0) {
struct writeback_state wbs;
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 7ee675ad101e..1d6ba6a4b594 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -897,12 +897,6 @@ rebalance:
cond_resched();
if (likely(did_some_progress)) {
- /*
- * Go through the zonelist yet one more time, keep
- * very high watermark here, this is only to catch
- * a parallel oom killing, we must fail if we're still
- * under heavy pressure.
- */
for (i = 0; (z = zones[i]) != NULL; i++) {
if (!zone_watermark_ok(z, order, z->pages_min,
classzone_idx, can_try_harder,
@@ -936,7 +930,7 @@ rebalance:
goto got_pg;
}
- out_of_memory(gfp_mask);
+ out_of_memory(gfp_mask, order);
goto restart;
}
@@ -1667,9 +1661,8 @@ void __init memmap_init_zone(unsigned long size, int nid, unsigned long zone,
#ifdef WANT_PAGE_VIRTUAL
/* The shift won't overflow because ZONE_NORMAL is below 4G. */
if (!is_highmem_idx(zone))
- set_page_address(page, __va(start_pfn << PAGE_SHIFT));
+ set_page_address(page, __va(pfn << PAGE_SHIFT));
#endif
- start_pfn++;
}
}
diff --git a/mm/page_io.c b/mm/page_io.c
index 667c76df1ec2..2e605a19ce57 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -127,7 +127,7 @@ out:
return ret;
}
-#if defined(CONFIG_SOFTWARE_SUSPEND) || defined(CONFIG_PM_DISK)
+#ifdef CONFIG_SOFTWARE_SUSPEND
/*
* A scruffy utility function to read or write an arbitrary swap page
* and wait on the I/O. The caller must have a ref on the page.
diff --git a/mm/pdflush.c b/mm/pdflush.c
index 38ce279cc8cd..d6781951267e 100644
--- a/mm/pdflush.c
+++ b/mm/pdflush.c
@@ -105,7 +105,7 @@ static int __pdflush(struct pdflush_work *my_work)
spin_unlock_irq(&pdflush_lock);
schedule();
- if (try_to_freeze(PF_FREEZE)) {
+ if (try_to_freeze()) {
spin_lock_irq(&pdflush_lock);
continue;
}
diff --git a/mm/rmap.c b/mm/rmap.c
index 89770bd25f31..08ac5c7fa91f 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -247,8 +247,8 @@ unsigned long page_address_in_vma(struct page *page, struct vm_area_struct *vma)
*
* On success returns with mapped pte and locked mm->page_table_lock.
*/
-static pte_t *page_check_address(struct page *page, struct mm_struct *mm,
- unsigned long address)
+pte_t *page_check_address(struct page *page, struct mm_struct *mm,
+ unsigned long address)
{
pgd_t *pgd;
pud_t *pud;
diff --git a/mm/slab.c b/mm/slab.c
index 122d031baab2..c9e706db4634 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -584,7 +584,8 @@ static inline struct array_cache *ac_data(kmem_cache_t *cachep)
return cachep->array[smp_processor_id()];
}
-static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
+static inline kmem_cache_t *__find_general_cachep(size_t size,
+ unsigned int __nocast gfpflags)
{
struct cache_sizes *csizep = malloc_sizes;
@@ -608,7 +609,8 @@ static inline kmem_cache_t *__find_general_cachep(size_t size, int gfpflags)
return csizep->cs_cachep;
}
-kmem_cache_t *kmem_find_general_cachep(size_t size, int gfpflags)
+kmem_cache_t *kmem_find_general_cachep(size_t size,
+ unsigned int __nocast gfpflags)
{
return __find_general_cachep(size, gfpflags);
}
@@ -2100,7 +2102,7 @@ cache_alloc_debugcheck_before(kmem_cache_t *cachep, unsigned int __nocast flags)
#if DEBUG
static void *
cache_alloc_debugcheck_after(kmem_cache_t *cachep,
- unsigned long flags, void *objp, void *caller)
+ unsigned int __nocast flags, void *objp, void *caller)
{
if (!objp)
return objp;
@@ -2372,6 +2374,9 @@ void *kmem_cache_alloc_node(kmem_cache_t *cachep, int flags, int nodeid)
struct slab *slabp;
kmem_bufctl_t next;
+ if (nodeid == -1)
+ return kmem_cache_alloc(cachep, flags);
+
for (loop = 0;;loop++) {
struct list_head *q;
@@ -2439,7 +2444,7 @@ got_slabp:
}
EXPORT_SYMBOL(kmem_cache_alloc_node);
-void *kmalloc_node(size_t size, int flags, int node)
+void *kmalloc_node(size_t size, unsigned int __nocast flags, int node)
{
kmem_cache_t *cachep;
@@ -3091,7 +3096,7 @@ unsigned int ksize(const void *objp)
* @s: the string to duplicate
* @gfp: the GFP mask used in the kmalloc() call when allocating memory
*/
-char *kstrdup(const char *s, int gfp)
+char *kstrdup(const char *s, unsigned int __nocast gfp)
{
size_t len;
char *buf;
diff --git a/mm/vmscan.c b/mm/vmscan.c
index 4b8e62a19370..cfffe5098d53 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -972,7 +972,7 @@ int try_to_free_pages(struct zone **zones, unsigned int gfp_mask)
* writeout. So in laptop mode, write out the whole world.
*/
if (total_scanned > sc.swap_cluster_max + sc.swap_cluster_max/2) {
- wakeup_bdflush(laptop_mode ? 0 : total_scanned);
+ wakeup_pdflush(laptop_mode ? 0 : total_scanned);
sc.may_writepage = 1;
}
@@ -1216,8 +1216,8 @@ static int kswapd(void *p)
order = 0;
for ( ; ; ) {
unsigned long new_order;
- if (current->flags & PF_FREEZE)
- refrigerator(PF_FREEZE);
+
+ try_to_freeze();
prepare_to_wait(&pgdat->kswapd_wait, &wait, TASK_INTERRUPTIBLE);
new_order = pgdat->kswapd_max_order;
diff --git a/net/802/fddi.c b/net/802/fddi.c
index ebcf4830d6f1..5ce24c4bb840 100644
--- a/net/802/fddi.c
+++ b/net/802/fddi.c
@@ -122,10 +122,10 @@ static int fddi_rebuild_header(struct sk_buff *skb)
* the proper pointer to the start of packet data (skb->data).
*/
-unsigned short fddi_type_trans(struct sk_buff *skb, struct net_device *dev)
+__be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct fddihdr *fddi = (struct fddihdr *)skb->data;
- unsigned short type;
+ __be16 type;
/*
* Set mac.raw field to point to FC byte, set data field to point
diff --git a/net/8021q/Kconfig b/net/8021q/Kconfig
new file mode 100644
index 000000000000..c4a382e450e2
--- /dev/null
+++ b/net/8021q/Kconfig
@@ -0,0 +1,19 @@
+#
+# Configuration for 802.1Q VLAN support
+#
+
+config VLAN_8021Q
+ tristate "802.1Q VLAN Support"
+ ---help---
+ Select this and you will be able to create 802.1Q VLAN interfaces
+ on your ethernet interfaces. 802.1Q VLAN supports almost
+ everything a regular ethernet interface does, including
+ firewalling, bridging, and of course IP traffic. You will need
+ the 'vconfig' tool from the VLAN project in order to effectively
+ use VLANs. See the VLAN web page for more information:
+ <http://www.candelatech.com/~greear/vlan.html>
+
+ To compile this code as a module, choose M here: the module
+ will be called 8021q.
+
+ If unsure, say N.
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 1f6d31670bc7..91e412b0ab00 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -578,6 +578,14 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
if (!vlandev)
continue;
+ if (netif_carrier_ok(dev)) {
+ if (!netif_carrier_ok(vlandev))
+ netif_carrier_on(vlandev);
+ } else {
+ if (netif_carrier_ok(vlandev))
+ netif_carrier_off(vlandev);
+ }
+
if ((vlandev->state & VLAN_LINK_STATE_MASK) != flgs) {
vlandev->state = (vlandev->state &~ VLAN_LINK_STATE_MASK)
| flgs;
diff --git a/net/Kconfig b/net/Kconfig
index 9251b28e8d5d..2684e809a649 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -2,7 +2,7 @@
# Network configuration
#
-menu "Networking support"
+menu "Networking"
config NET
bool "Networking support"
@@ -10,7 +10,9 @@ config NET
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
+ 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
@@ -20,57 +22,14 @@ config NET
recommended to read the NET-HOWTO, available from
<http://www.tldp.org/docs.html#howto>.
-menu "Networking options"
- depends on NET
-
-config PACKET
- tristate "Packet socket"
- ---help---
- The Packet protocol is used by applications which communicate
- directly with network devices without an intermediate network
- protocol implemented in the kernel, e.g. tcpdump. If you want them
- to work, choose Y.
+# Make sure that all config symbols are dependent on NET
+if NET
- To compile this driver as a module, choose M here: the module will
- be called af_packet.
-
- If unsure, say Y.
-
-config PACKET_MMAP
- bool "Packet socket: mmapped IO"
- depends on PACKET
- help
- If you say Y here, the Packet protocol driver will use an IO
- mechanism that results in faster communication.
-
- If unsure, say N.
-
-config UNIX
- tristate "Unix domain sockets"
- ---help---
- If you say Y here, you will include support for Unix domain sockets;
- sockets are the standard Unix mechanism for establishing and
- accessing network connections. Many commonly used programs such as
- the X Window system and syslog use these sockets even if your
- machine is not connected to any network. Unless you are working on
- an embedded system or something similar, you therefore definitely
- want to say Y here.
-
- To compile this driver as a module, choose M here: the module will be
- called unix. Note that several important services won't work
- correctly if you say M here and then neglect to load the module.
-
- Say Y unless you know what you are doing.
-
-config NET_KEY
- tristate "PF_KEY sockets"
- select XFRM
- ---help---
- PF_KEYv2 socket family, compatible to KAME ones.
- They are required if you are going to use IPsec tools ported
- from KAME.
+menu "Networking options"
- Say Y unless you know what you are doing.
+source "net/packet/Kconfig"
+source "net/unix/Kconfig"
+source "net/xfrm/Kconfig"
config INET
bool "TCP/IP networking"
@@ -94,30 +53,12 @@ config INET
Short answer: say Y.
+if INET
source "net/ipv4/Kconfig"
-
-# IPv6 as module will cause a CRASH if you try to unload it
-config IPV6
- tristate "The IPv6 protocol"
- depends on INET
- default m
- select CRYPTO if IPV6_PRIVACY
- select CRYPTO_MD5 if IPV6_PRIVACY
- ---help---
- This is complemental support for the IP version 6.
- You will still be able to do traditional IPv4 networking as well.
-
- For general information about IPv6, see
- <http://playground.sun.com/pub/ipng/html/ipng-main.html>.
- For Linux IPv6 development information, see <http://www.linux-ipv6.org>.
- For specific information about IPv6 under Linux, read the HOWTO at
- <http://www.bieringer.de/linux/IPv6/>.
-
- To compile this protocol support as a module, choose M here: the
- module will be called ipv6.
-
source "net/ipv6/Kconfig"
+endif # if INET
+
menuconfig NETFILTER
bool "Network packet filtering (replaces ipchains)"
---help---
@@ -206,269 +147,16 @@ source "net/bridge/netfilter/Kconfig"
endif
-config XFRM
- bool
- depends on NET
-
-source "net/xfrm/Kconfig"
-
source "net/sctp/Kconfig"
-
-config ATM
- tristate "Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- ---help---
- ATM is a high-speed networking technology for Local Area Networks
- and Wide Area Networks. It uses a fixed packet size and is
- connection oriented, allowing for the negotiation of minimum
- bandwidth requirements.
-
- In order to participate in an ATM network, your Linux box needs an
- ATM networking card. If you have that, say Y here and to the driver
- of your ATM card below.
-
- Note that you need a set of user-space programs to actually make use
- of ATM. See the file <file:Documentation/networking/atm.txt> for
- further details.
-
-config ATM_CLIP
- tristate "Classical IP over ATM (EXPERIMENTAL)"
- depends on ATM && INET
- help
- Classical IP over ATM for PVCs and SVCs, supporting InARP and
- ATMARP. If you want to communication with other IP hosts on your ATM
- network, you will typically either say Y here or to "LAN Emulation
- (LANE)" below.
-
-config ATM_CLIP_NO_ICMP
- bool "Do NOT send ICMP if no neighbour (EXPERIMENTAL)"
- depends on ATM_CLIP
- help
- Normally, an "ICMP host unreachable" message is sent if a neighbour
- cannot be reached because there is no VC to it in the kernel's
- ATMARP table. This may cause problems when ATMARP table entries are
- briefly removed during revalidation. If you say Y here, packets to
- such neighbours are silently discarded instead.
-
-config ATM_LANE
- tristate "LAN Emulation (LANE) support (EXPERIMENTAL)"
- depends on ATM
- help
- LAN Emulation emulates services of existing LANs across an ATM
- network. Besides operating as a normal ATM end station client, Linux
- LANE client can also act as an proxy client bridging packets between
- ELAN and Ethernet segments. You need LANE if you want to try MPOA.
-
-config ATM_MPOA
- tristate "Multi-Protocol Over ATM (MPOA) support (EXPERIMENTAL)"
- depends on ATM && INET && ATM_LANE!=n
- help
- Multi-Protocol Over ATM allows ATM edge devices such as routers,
- bridges and ATM attached hosts establish direct ATM VCs across
- subnetwork boundaries. These shortcut connections bypass routers
- enhancing overall network performance.
-
-config ATM_BR2684
- tristate "RFC1483/2684 Bridged protocols"
- depends on ATM && INET
- help
- ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483)
- This device will act like an ethernet from the kernels point of view,
- with the traffic being carried by ATM PVCs (currently 1 PVC/device).
- This is sometimes used over DSL lines. If in doubt, say N.
-
-config ATM_BR2684_IPFILTER
- bool "Per-VC IP filter kludge"
- depends on ATM_BR2684
- help
- This is an experimental mechanism for users who need to terminating a
- large number of IP-only vcc's. Do not enable this unless you are sure
- you know what you are doing.
-
-config BRIDGE
- tristate "802.1d Ethernet Bridging"
- ---help---
- If you say Y here, then your Linux box will be able to act as an
- Ethernet bridge, which means that the different Ethernet segments it
- is connected to will appear as one Ethernet to the participants.
- Several such bridges can work together to create even larger
- networks of Ethernets using the IEEE 802.1 spanning tree algorithm.
- As this is a standard, Linux bridges will cooperate properly with
- other third party bridge products.
-
- In order to use the Ethernet bridge, you'll need the bridge
- configuration tools; see <file:Documentation/networking/bridge.txt>
- for location. Please read the Bridge mini-HOWTO for more
- information.
-
- If you enable iptables support along with the bridge support then you
- turn your bridge into a bridging IP firewall.
- iptables will then see the IP packets being bridged, so you need to
- take this into account when setting up your firewall rules.
- Enabling arptables support when bridging will let arptables see
- bridged ARP traffic in the arptables FORWARD chain.
-
- To compile this code as a module, choose M here: the module
- will be called bridge.
-
- If unsure, say N.
-
-config VLAN_8021Q
- tristate "802.1Q VLAN Support"
- ---help---
- Select this and you will be able to create 802.1Q VLAN interfaces
- on your ethernet interfaces. 802.1Q VLAN supports almost
- everything a regular ethernet interface does, including
- firewalling, bridging, and of course IP traffic. You will need
- the 'vconfig' tool from the VLAN project in order to effectively
- use VLANs. See the VLAN web page for more information:
- <http://www.candelatech.com/~greear/vlan.html>
-
- To compile this code as a module, choose M here: the module
- will be called 8021q.
-
- If unsure, say N.
-
-config DECNET
- tristate "DECnet Support"
- ---help---
- The DECnet networking protocol was used in many products made by
- Digital (now Compaq). It provides reliable stream and sequenced
- packet communications over which run a variety of services similar
- to those which run over TCP/IP.
-
- To find some tools to use with the kernel layer support, please
- look at Patrick Caulfield's web site:
- <http://linux-decnet.sourceforge.net/>.
-
- More detailed documentation is available in
- <file:Documentation/networking/decnet.txt>.
-
- Be sure to say Y to "/proc file system support" and "Sysctl support"
- below when using DECnet, since you will need sysctl support to aid
- in configuration at run time.
-
- The DECnet code is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module is called decnet.
-
+source "net/atm/Kconfig"
+source "net/bridge/Kconfig"
+source "net/8021q/Kconfig"
source "net/decnet/Kconfig"
-
source "net/llc/Kconfig"
-
-config IPX
- tristate "The IPX protocol"
- select LLC
- ---help---
- This is support for the Novell networking protocol, IPX, commonly
- used for local networks of Windows machines. You need it if you
- want to access Novell NetWare file or print servers using the Linux
- Novell client ncpfs (available from
- <ftp://platan.vc.cvut.cz/pub/linux/ncpfs/>) or from
- within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO,
- available from <http://www.tldp.org/docs.html#howto>). In order
- to do the former, you'll also have to say Y to "NCP file system
- support", below.
-
- IPX is similar in scope to IP, while SPX, which runs on top of IPX,
- is similar to TCP. There is also experimental support for SPX in
- Linux (see "SPX networking", below).
-
- To turn your Linux box into a fully featured NetWare file server and
- IPX router, say Y here and fetch either lwared from
- <ftp://ibiblio.org/pub/Linux/system/network/daemons/> or
- mars_nwe from <ftp://www.compu-art.de/mars_nwe/>. For more
- information, read the IPX-HOWTO available from
- <http://www.tldp.org/docs.html#howto>.
-
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
-
- The IPX driver would enlarge your kernel by about 16 KB. To compile
- this driver as a module, choose M here: the module will be called ipx.
- Unless you want to integrate your Linux box with a local Novell
- network, say N.
-
source "net/ipx/Kconfig"
-
-config ATALK
- tristate "Appletalk protocol support"
- select LLC
- ---help---
- AppleTalk is the protocol that Apple computers can use to communicate
- on a network. If your Linux box is connected to such a network and you
- wish to connect to it, say Y. You will need to use the netatalk package
- so that your Linux box can act as a print and file server for Macs as
- well as access AppleTalk printers. Check out
- <http://www.zettabyte.net/netatalk/> on the WWW for details.
- EtherTalk is the name used for AppleTalk over Ethernet and the
- cheaper and slower LocalTalk is AppleTalk over a proprietary Apple
- network using serial links. EtherTalk and LocalTalk are fully
- supported by Linux.
-
- General information about how to connect Linux, Windows machines and
- Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>. The
- NET-3-HOWTO, available from
- <http://www.tldp.org/docs.html#howto>, contains valuable
- information as well.
-
- To compile this driver as a module, choose M here: the module will be
- called appletalk. You almost certainly want to compile it as a
- module so you can restart your AppleTalk stack without rebooting
- your machine. I hear that the GNU boycott of Apple is over, so
- even politically correct people are allowed to say Y here.
-
source "drivers/net/appletalk/Kconfig"
-
-config X25
- tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- ---help---
- X.25 is a set of standardized network protocols, similar in scope to
- frame relay; the one physical line from your box to the X.25 network
- entry point can carry several logical point-to-point connections
- (called "virtual circuits") to other computers connected to the X.25
- network. Governments, banks, and other organizations tend to use it
- to connect to each other or to form Wide Area Networks (WANs). Many
- countries have public X.25 networks. X.25 consists of two
- protocols: the higher level Packet Layer Protocol (PLP) (say Y here
- if you want that) and the lower level data link layer protocol LAPB
- (say Y to "LAPB Data Link Driver" below if you want that).
-
- You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
- <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>.
- Information about X.25 for Linux is contained in the files
- <file:Documentation/networking/x25.txt> and
- <file:Documentation/networking/x25-iface.txt>.
-
- One connects to an X.25 network either with a dedicated network card
- using the X.21 protocol (not yet supported by Linux) or one can do
- X.25 over a standard telephone line using an ordinary modem (say Y
- to "X.25 async driver" below) or over Ethernet using an ordinary
- Ethernet card and the LAPB over Ethernet (say Y to "LAPB Data Link
- Driver" and "LAPB over Ethernet driver" below).
-
- To compile this driver as a module, choose M here: the module
- will be called x25. If unsure, say N.
-
-config LAPB
- tristate "LAPB Data Link Driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL
- ---help---
- Link Access Procedure, Balanced (LAPB) is the data link layer (i.e.
- the lower) part of the X.25 protocol. It offers a reliable
- connection service to exchange data frames with one other host, and
- it is used to transport higher level protocols (mostly X.25 Packet
- Layer, the higher part of X.25, but others are possible as well).
- Usually, LAPB is used with specialized X.21 network cards, but Linux
- currently supports LAPB only over Ethernet connections. If you want
- to use LAPB connections over Ethernet, say Y here and to "LAPB over
- Ethernet driver" below. Read
- <file:Documentation/networking/lapb-module.txt> for technical
- details.
-
- To compile this driver as a module, choose M here: the
- module will be called lapb. If unsure, say N.
+source "net/x25/Kconfig"
+source "net/lapb/Kconfig"
config NET_DIVERT
bool "Frame Diverter (EXPERIMENTAL)"
@@ -496,107 +184,10 @@ config NET_DIVERT
If unsure, say N.
-config ECONET
- tristate "Acorn Econet/AUN protocols (EXPERIMENTAL)"
- depends on EXPERIMENTAL && INET
- ---help---
- Econet is a fairly old and slow networking protocol mainly used by
- Acorn computers to access file and print servers. It uses native
- Econet network cards. AUN is an implementation of the higher level
- parts of Econet that runs over ordinary Ethernet connections, on
- top of the UDP packet protocol, which in turn runs on top of the
- Internet protocol IP.
-
- If you say Y here, you can choose with the next two options whether
- to send Econet/AUN traffic over a UDP Ethernet connection or over
- a native Econet network card.
-
- To compile this driver as a module, choose M here: the module
- will be called econet.
-
-config ECONET_AUNUDP
- bool "AUN over UDP"
- depends on ECONET
- help
- Say Y here if you want to send Econet/AUN traffic over a UDP
- connection (UDP is a packet based protocol that runs on top of the
- Internet protocol IP) using an ordinary Ethernet network card.
-
-config ECONET_NATIVE
- bool "Native Econet"
- depends on ECONET
- help
- Say Y here if you have a native Econet network card installed in
- your computer.
-
-config WAN_ROUTER
- tristate "WAN router"
- depends on EXPERIMENTAL
- ---help---
- Wide Area Networks (WANs), such as X.25, frame relay and leased
- lines, are used to interconnect Local Area Networks (LANs) over vast
- distances with data transfer rates significantly higher than those
- achievable with commonly used asynchronous modem connections.
- Usually, a quite expensive external device called a `WAN router' is
- needed to connect to a WAN.
-
- As an alternative, WAN routing can be built into the Linux kernel.
- With relatively inexpensive WAN interface cards available on the
- market, a perfectly usable router can be built for less than half
- the price of an external router. If you have one of those cards and
- wish to use your Linux box as a WAN router, say Y here and also to
- the WAN driver for your card, below. You will then need the
- wan-tools package which is available from <ftp://ftp.sangoma.com/>.
- Read <file:Documentation/networking/wan-router.txt> for more
- information.
-
- To compile WAN routing support as a module, choose M here: the
- module will be called wanrouter.
-
- If unsure, say N.
-
-menu "QoS and/or fair queueing"
-
-config NET_SCHED
- bool "QoS and/or fair queueing"
- ---help---
- When the kernel has several packets to send out over a network
- device, it has to decide which ones to send first, which ones to
- delay, and which ones to drop. This is the job of the packet
- scheduler, and several different algorithms for how to do this
- "fairly" have been proposed.
-
- If you say N here, you will get the standard packet scheduler, which
- is a FIFO (first come, first served). If you say Y here, you will be
- able to choose from among several alternative algorithms which can
- then be attached to different network devices. This is useful for
- example if some of your network devices are real time devices that
- need a certain minimum data flow rate, or if you need to limit the
- maximum data flow rate for traffic which matches specified criteria.
- This code is considered to be experimental.
-
- To administer these schedulers, you'll need the user-level utilities
- from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>.
- That package also contains some documentation; for more, check out
- <http://snafu.freedom.org/linux2.2/iproute-notes.html>.
-
- This Quality of Service (QoS) support will enable you to use
- Differentiated Services (diffserv) and Resource Reservation Protocol
- (RSVP) on your Linux router if you also say Y to "QoS support",
- "Packet classifier API" and to some classifiers below. Documentation
- and software is at <http://diffserv.sourceforge.net/>.
-
- If you say Y here and to "/proc file system" below, you will be able
- to read status information about packet schedulers from the file
- /proc/net/psched.
-
- The available schedulers are listed in the following questions; you
- can say Y to as many as you like. If unsure, say N now.
-
+source "net/econet/Kconfig"
+source "net/wanrouter/Kconfig"
source "net/sched/Kconfig"
-endmenu
-
menu "Network testing"
config NET_PKTGEN
@@ -635,12 +226,9 @@ config NET_POLL_CONTROLLER
def_bool NETPOLL
source "net/ax25/Kconfig"
-
source "net/irda/Kconfig"
-
source "net/bluetooth/Kconfig"
-source "drivers/net/Kconfig"
-
-endmenu
+endif # if NET
+endmenu # Networking
diff --git a/net/atm/Kconfig b/net/atm/Kconfig
new file mode 100644
index 000000000000..bea2426229b1
--- /dev/null
+++ b/net/atm/Kconfig
@@ -0,0 +1,74 @@
+#
+# Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)
+#
+
+config ATM
+ tristate "Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ ATM is a high-speed networking technology for Local Area Networks
+ and Wide Area Networks. It uses a fixed packet size and is
+ connection oriented, allowing for the negotiation of minimum
+ bandwidth requirements.
+
+ In order to participate in an ATM network, your Linux box needs an
+ ATM networking card. If you have that, say Y here and to the driver
+ of your ATM card below.
+
+ Note that you need a set of user-space programs to actually make use
+ of ATM. See the file <file:Documentation/networking/atm.txt> for
+ further details.
+
+config ATM_CLIP
+ tristate "Classical IP over ATM (EXPERIMENTAL)"
+ depends on ATM && INET
+ help
+ Classical IP over ATM for PVCs and SVCs, supporting InARP and
+ ATMARP. If you want to communication with other IP hosts on your ATM
+ network, you will typically either say Y here or to "LAN Emulation
+ (LANE)" below.
+
+config ATM_CLIP_NO_ICMP
+ bool "Do NOT send ICMP if no neighbour (EXPERIMENTAL)"
+ depends on ATM_CLIP
+ help
+ Normally, an "ICMP host unreachable" message is sent if a neighbour
+ cannot be reached because there is no VC to it in the kernel's
+ ATMARP table. This may cause problems when ATMARP table entries are
+ briefly removed during revalidation. If you say Y here, packets to
+ such neighbours are silently discarded instead.
+
+config ATM_LANE
+ tristate "LAN Emulation (LANE) support (EXPERIMENTAL)"
+ depends on ATM
+ help
+ LAN Emulation emulates services of existing LANs across an ATM
+ network. Besides operating as a normal ATM end station client, Linux
+ LANE client can also act as an proxy client bridging packets between
+ ELAN and Ethernet segments. You need LANE if you want to try MPOA.
+
+config ATM_MPOA
+ tristate "Multi-Protocol Over ATM (MPOA) support (EXPERIMENTAL)"
+ depends on ATM && INET && ATM_LANE!=n
+ help
+ Multi-Protocol Over ATM allows ATM edge devices such as routers,
+ bridges and ATM attached hosts establish direct ATM VCs across
+ subnetwork boundaries. These shortcut connections bypass routers
+ enhancing overall network performance.
+
+config ATM_BR2684
+ tristate "RFC1483/2684 Bridged protocols"
+ depends on ATM && INET
+ help
+ ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483)
+ This device will act like an ethernet from the kernels point of view,
+ with the traffic being carried by ATM PVCs (currently 1 PVC/device).
+ This is sometimes used over DSL lines. If in doubt, say N.
+
+config ATM_BR2684_IPFILTER
+ bool "Per-VC IP filter kludge"
+ depends on ATM_BR2684
+ help
+ This is an experimental mechanism for users who need to terminating a
+ large number of IP-only vcc's. Do not enable this unless you are sure
+ you know what you are doing.
diff --git a/net/atm/br2684.c b/net/atm/br2684.c
index e6954cf1459d..289956c4dd3e 100644
--- a/net/atm/br2684.c
+++ b/net/atm/br2684.c
@@ -289,8 +289,7 @@ xmit will add the additional header part in that case */
* This is similar to eth_type_trans, which cannot be used because of
* our dev->hard_header_len
*/
-static inline unsigned short br_type_trans(struct sk_buff *skb,
- struct net_device *dev)
+static inline __be16 br_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index 2e341de3e763..901eff7ebe74 100644
--- a/net/bluetooth/cmtp/core.c
+++ b/net/bluetooth/cmtp/core.c
@@ -213,7 +213,7 @@ static int cmtp_send_frame(struct cmtp_session *session, unsigned char *data, in
return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
-static int cmtp_process_transmit(struct cmtp_session *session)
+static void cmtp_process_transmit(struct cmtp_session *session)
{
struct sk_buff *skb, *nskb;
unsigned char *hdr;
@@ -223,7 +223,7 @@ static int cmtp_process_transmit(struct cmtp_session *session)
if (!(nskb = alloc_skb(session->mtu, GFP_ATOMIC))) {
BT_ERR("Can't allocate memory for new frame");
- return -ENOMEM;
+ return;
}
while ((skb = skb_dequeue(&session->transmit))) {
@@ -275,8 +275,6 @@ static int cmtp_process_transmit(struct cmtp_session *session)
cmtp_send_frame(session, nskb->data, nskb->len);
kfree_skb(nskb);
-
- return skb_queue_len(&session->transmit);
}
static int cmtp_session(void *arg)
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index affbc55462e8..de8af5f42394 100644
--- a/net/bluetooth/hidp/core.c
+++ b/net/bluetooth/hidp/core.c
@@ -428,7 +428,7 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
-static int hidp_process_transmit(struct hidp_session *session)
+static void hidp_process_transmit(struct hidp_session *session)
{
struct sk_buff *skb;
@@ -453,9 +453,6 @@ static int hidp_process_transmit(struct hidp_session *session)
hidp_set_timer(session);
kfree_skb(skb);
}
-
- return skb_queue_len(&session->ctrl_transmit) +
- skb_queue_len(&session->intr_transmit);
}
static int hidp_session(void *arg)
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index f3f6355a2786..63a123c5c41b 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -590,8 +590,11 @@ static long rfcomm_sock_data_wait(struct sock *sk, long timeo)
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
- if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) ||
- signal_pending(current) || !timeo)
+ if (!skb_queue_empty(&sk->sk_receive_queue) ||
+ sk->sk_err ||
+ (sk->sk_shutdown & RCV_SHUTDOWN) ||
+ signal_pending(current) ||
+ !timeo)
break;
set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
index 6d689200bcf3..6304590fd36a 100644
--- a/net/bluetooth/rfcomm/tty.c
+++ b/net/bluetooth/rfcomm/tty.c
@@ -781,7 +781,7 @@ static int rfcomm_tty_chars_in_buffer(struct tty_struct *tty)
BT_DBG("tty %p dev %p", tty, dev);
- if (skb_queue_len(&dlc->tx_queue))
+ if (!skb_queue_empty(&dlc->tx_queue))
return dlc->mtu;
return 0;
diff --git a/net/bridge/Kconfig b/net/bridge/Kconfig
new file mode 100644
index 000000000000..db23d59746cf
--- /dev/null
+++ b/net/bridge/Kconfig
@@ -0,0 +1,31 @@
+#
+# 802.1d Ethernet Bridging
+#
+
+config BRIDGE
+ tristate "802.1d Ethernet Bridging"
+ ---help---
+ If you say Y here, then your Linux box will be able to act as an
+ Ethernet bridge, which means that the different Ethernet segments it
+ is connected to will appear as one Ethernet to the participants.
+ Several such bridges can work together to create even larger
+ networks of Ethernets using the IEEE 802.1 spanning tree algorithm.
+ As this is a standard, Linux bridges will cooperate properly with
+ other third party bridge products.
+
+ In order to use the Ethernet bridge, you'll need the bridge
+ configuration tools; see <file:Documentation/networking/bridge.txt>
+ for location. Please read the Bridge mini-HOWTO for more
+ information.
+
+ If you enable iptables support along with the bridge support then you
+ turn your bridge into a bridging IP firewall.
+ iptables will then see the IP packets being bridged, so you need to
+ take this into account when setting up your firewall rules.
+ Enabling arptables support when bridging will let arptables see
+ bridged ARP traffic in the arptables FORWARD chain.
+
+ To compile this code as a module, choose M here: the module
+ will be called bridge.
+
+ If unsure, say N.
diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
index 03ae4edddac3..2d52fee63a8c 100644
--- a/net/bridge/br_netfilter.c
+++ b/net/bridge/br_netfilter.c
@@ -844,7 +844,7 @@ static unsigned int ip_sabotage_out(unsigned int hook, struct sk_buff **pskb,
* doesn't use the bridge parent of the indev by using
* the BRNF_DONT_TAKE_PARENT mask. */
if (hook == NF_IP_FORWARD && nf_bridge->physindev == NULL) {
- nf_bridge->mask &= BRNF_DONT_TAKE_PARENT;
+ nf_bridge->mask |= BRNF_DONT_TAKE_PARENT;
nf_bridge->physindev = (struct net_device *)in;
}
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index e4ae34b88925..662975be3d1d 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -61,8 +61,6 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
{
struct ebt_log_info *info = (struct ebt_log_info *)data;
char level_string[4] = "< >";
- union {struct iphdr iph; struct tcpudphdr ports;
- struct arphdr arph; struct arppayload arpp;} u;
level_string[1] = '0' + info->loglevel;
spin_lock_bh(&ebt_log_lock);
@@ -88,7 +86,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
}
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
- printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos,
+ printk(" IP tos=0x%02X, IP proto=%d", ih->tos,
ih->protocol);
if (ih->protocol == IPPROTO_TCP ||
ih->protocol == IPPROTO_UDP) {
@@ -127,7 +125,7 @@ static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
ah->ar_pln == sizeof(uint32_t)) {
struct arppayload _arpp, *ap;
- ap = skb_header_pointer(skb, sizeof(u.arph),
+ ap = skb_header_pointer(skb, sizeof(_arph),
sizeof(_arpp), &_arpp);
if (ap == NULL) {
printk(" INCOMPLETE ARP payload");
diff --git a/net/core/dev.c b/net/core/dev.c
index ab935778ce81..ff9dc029233a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -115,18 +115,6 @@
#endif /* CONFIG_NET_RADIO */
#include <asm/current.h>
-/* This define, if set, will randomly drop a packet when congestion
- * is more than moderate. It helps fairness in the multi-interface
- * case when one of them is a hog, but it kills performance for the
- * single interface case so it is off now by default.
- */
-#undef RAND_LIE
-
-/* Setting this will sample the queue lengths and thus congestion
- * via a timer instead of as each packet is received.
- */
-#undef OFFLINE_SAMPLE
-
/*
* The list of packet types we will receive (as opposed to discard)
* and the routines to invoke.
@@ -159,11 +147,6 @@ static DEFINE_SPINLOCK(ptype_lock);
static struct list_head ptype_base[16]; /* 16 way hashed list */
static struct list_head ptype_all; /* Taps */
-#ifdef OFFLINE_SAMPLE
-static void sample_queue(unsigned long dummy);
-static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
-#endif
-
/*
* The @dev_base list is protected by @dev_base_lock and the rtln
* semaphore.
@@ -215,7 +198,7 @@ static struct notifier_block *netdev_chain;
* Device drivers call our routines to queue packets here. We empty the
* queue in the local softnet handler.
*/
-DEFINE_PER_CPU(struct softnet_data, softnet_data) = { 0, };
+DEFINE_PER_CPU(struct softnet_data, softnet_data) = { NULL };
#ifdef CONFIG_SYSFS
extern int netdev_sysfs_init(void);
@@ -1144,7 +1127,7 @@ static inline int illegal_highdma(struct net_device *dev, struct sk_buff *skb)
extern void skb_release_data(struct sk_buff *);
/* Keep head the same: replace data */
-int __skb_linearize(struct sk_buff *skb, int gfp_mask)
+int __skb_linearize(struct sk_buff *skb, unsigned int __nocast gfp_mask)
{
unsigned int size;
u8 *data;
@@ -1363,71 +1346,13 @@ out:
Receiver routines
=======================================================================*/
-int netdev_max_backlog = 300;
+int netdev_max_backlog = 1000;
+int netdev_budget = 300;
int weight_p = 64; /* old backlog weight */
-/* These numbers are selected based on intuition and some
- * experimentatiom, if you have more scientific way of doing this
- * please go ahead and fix things.
- */
-int no_cong_thresh = 10;
-int no_cong = 20;
-int lo_cong = 100;
-int mod_cong = 290;
DEFINE_PER_CPU(struct netif_rx_stats, netdev_rx_stat) = { 0, };
-static void get_sample_stats(int cpu)
-{
-#ifdef RAND_LIE
- unsigned long rd;
- int rq;
-#endif
- struct softnet_data *sd = &per_cpu(softnet_data, cpu);
- int blog = sd->input_pkt_queue.qlen;
- int avg_blog = sd->avg_blog;
-
- avg_blog = (avg_blog >> 1) + (blog >> 1);
-
- if (avg_blog > mod_cong) {
- /* Above moderate congestion levels. */
- sd->cng_level = NET_RX_CN_HIGH;
-#ifdef RAND_LIE
- rd = net_random();
- rq = rd % netdev_max_backlog;
- if (rq < avg_blog) /* unlucky bastard */
- sd->cng_level = NET_RX_DROP;
-#endif
- } else if (avg_blog > lo_cong) {
- sd->cng_level = NET_RX_CN_MOD;
-#ifdef RAND_LIE
- rd = net_random();
- rq = rd % netdev_max_backlog;
- if (rq < avg_blog) /* unlucky bastard */
- sd->cng_level = NET_RX_CN_HIGH;
-#endif
- } else if (avg_blog > no_cong)
- sd->cng_level = NET_RX_CN_LOW;
- else /* no congestion */
- sd->cng_level = NET_RX_SUCCESS;
-
- sd->avg_blog = avg_blog;
-}
-
-#ifdef OFFLINE_SAMPLE
-static void sample_queue(unsigned long dummy)
-{
-/* 10 ms 0r 1ms -- i don't care -- JHS */
- int next_tick = 1;
- int cpu = smp_processor_id();
-
- get_sample_stats(cpu);
- next_tick += jiffies;
- mod_timer(&samp_timer, next_tick);
-}
-#endif
-
-
/**
* netif_rx - post buffer to the network code
* @skb: buffer to post
@@ -1448,7 +1373,6 @@ static void sample_queue(unsigned long dummy)
int netif_rx(struct sk_buff *skb)
{
- int this_cpu;
struct softnet_data *queue;
unsigned long flags;
@@ -1464,38 +1388,22 @@ int netif_rx(struct sk_buff *skb)
* short when CPU is congested, but is still operating.
*/
local_irq_save(flags);
- this_cpu = smp_processor_id();
queue = &__get_cpu_var(softnet_data);
__get_cpu_var(netdev_rx_stat).total++;
if (queue->input_pkt_queue.qlen <= netdev_max_backlog) {
if (queue->input_pkt_queue.qlen) {
- if (queue->throttle)
- goto drop;
-
enqueue:
dev_hold(skb->dev);
__skb_queue_tail(&queue->input_pkt_queue, skb);
-#ifndef OFFLINE_SAMPLE
- get_sample_stats(this_cpu);
-#endif
local_irq_restore(flags);
- return queue->cng_level;
+ return NET_RX_SUCCESS;
}
- if (queue->throttle)
- queue->throttle = 0;
-
netif_rx_schedule(&queue->backlog_dev);
goto enqueue;
}
- if (!queue->throttle) {
- queue->throttle = 1;
- __get_cpu_var(netdev_rx_stat).throttled++;
- }
-
-drop:
__get_cpu_var(netdev_rx_stat).dropped++;
local_irq_restore(flags);
@@ -1780,8 +1688,6 @@ job_done:
smp_mb__before_clear_bit();
netif_poll_enable(backlog_dev);
- if (queue->throttle)
- queue->throttle = 0;
local_irq_enable();
return 0;
}
@@ -1790,8 +1696,7 @@ static void net_rx_action(struct softirq_action *h)
{
struct softnet_data *queue = &__get_cpu_var(softnet_data);
unsigned long start_time = jiffies;
- int budget = netdev_max_backlog;
-
+ int budget = netdev_budget;
local_irq_disable();
@@ -2055,15 +1960,9 @@ static int softnet_seq_show(struct seq_file *seq, void *v)
struct netif_rx_stats *s = v;
seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
- s->total, s->dropped, s->time_squeeze, s->throttled,
- s->fastroute_hit, s->fastroute_success, s->fastroute_defer,
- s->fastroute_deferred_out,
-#if 0
- s->fastroute_latency_reduction
-#else
- s->cpu_collision
-#endif
- );
+ s->total, s->dropped, s->time_squeeze, 0,
+ 0, 0, 0, 0, /* was fastroute */
+ s->cpu_collision );
return 0;
}
@@ -2190,10 +2089,11 @@ void dev_set_promiscuity(struct net_device *dev, int inc)
{
unsigned short old_flags = dev->flags;
- dev->flags |= IFF_PROMISC;
if ((dev->promiscuity += inc) == 0)
dev->flags &= ~IFF_PROMISC;
- if (dev->flags ^ old_flags) {
+ else
+ dev->flags |= IFF_PROMISC;
+ if (dev->flags != old_flags) {
dev_mc_upload(dev);
printk(KERN_INFO "device %s %s promiscuous mode\n",
dev->name, (dev->flags & IFF_PROMISC) ? "entered" :
@@ -3305,9 +3205,6 @@ static int __init net_dev_init(void)
queue = &per_cpu(softnet_data, i);
skb_queue_head_init(&queue->input_pkt_queue);
- queue->throttle = 0;
- queue->cng_level = 0;
- queue->avg_blog = 10; /* arbitrary non-zero */
queue->completion_queue = NULL;
INIT_LIST_HEAD(&queue->poll_list);
set_bit(__LINK_STATE_START, &queue->backlog_dev.state);
@@ -3316,11 +3213,6 @@ static int __init net_dev_init(void)
atomic_set(&queue->backlog_dev.refcnt, 1);
}
-#ifdef OFFLINE_SAMPLE
- samp_timer.expires = jiffies + (10 * HZ);
- add_timer(&samp_timer);
-#endif
-
dev_boot_phase = 0;
open_softirq(NET_TX_SOFTIRQ, net_tx_action, NULL);
diff --git a/net/core/filter.c b/net/core/filter.c
index f3b88205ace2..cd91a24f9720 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -36,7 +36,7 @@
#include <linux/filter.h>
/* No hurry in this branch */
-static u8 *load_pointer(struct sk_buff *skb, int k)
+static void *__load_pointer(struct sk_buff *skb, int k)
{
u8 *ptr = NULL;
@@ -50,6 +50,18 @@ static u8 *load_pointer(struct sk_buff *skb, int k)
return NULL;
}
+static inline void *load_pointer(struct sk_buff *skb, int k,
+ unsigned int size, void *buffer)
+{
+ if (k >= 0)
+ return skb_header_pointer(skb, k, size, buffer);
+ else {
+ if (k >= SKF_AD_OFF)
+ return NULL;
+ return __load_pointer(skb, k);
+ }
+}
+
/**
* sk_run_filter - run a filter on a socket
* @skb: buffer to run the filter on
@@ -64,15 +76,12 @@ static u8 *load_pointer(struct sk_buff *skb, int k)
int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
{
- unsigned char *data = skb->data;
- /* len is UNSIGNED. Byte wide insns relies only on implicit
- type casts to prevent reading arbitrary memory locations.
- */
- unsigned int len = skb->len-skb->data_len;
struct sock_filter *fentry; /* We walk down these */
+ void *ptr;
u32 A = 0; /* Accumulator */
u32 X = 0; /* Index Register */
u32 mem[BPF_MEMWORDS]; /* Scratch Memory Store */
+ u32 tmp;
int k;
int pc;
@@ -168,86 +177,35 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
case BPF_LD|BPF_W|BPF_ABS:
k = fentry->k;
load_w:
- if (k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) {
- A = ntohl(*(u32*)&data[k]);
+ ptr = load_pointer(skb, k, 4, &tmp);
+ if (ptr != NULL) {
+ A = ntohl(*(u32 *)ptr);
continue;
}
- if (k < 0) {
- u8 *ptr;
-
- if (k >= SKF_AD_OFF)
- break;
- ptr = load_pointer(skb, k);
- if (ptr) {
- A = ntohl(*(u32*)ptr);
- continue;
- }
- } else {
- u32 _tmp, *p;
- p = skb_header_pointer(skb, k, 4, &_tmp);
- if (p != NULL) {
- A = ntohl(*p);
- continue;
- }
- }
return 0;
case BPF_LD|BPF_H|BPF_ABS:
k = fentry->k;
load_h:
- if (k >= 0 && (unsigned int)(k + sizeof(u16)) <= len) {
- A = ntohs(*(u16*)&data[k]);
+ ptr = load_pointer(skb, k, 2, &tmp);
+ if (ptr != NULL) {
+ A = ntohs(*(u16 *)ptr);
continue;
}
- if (k < 0) {
- u8 *ptr;
-
- if (k >= SKF_AD_OFF)
- break;
- ptr = load_pointer(skb, k);
- if (ptr) {
- A = ntohs(*(u16*)ptr);
- continue;
- }
- } else {
- u16 _tmp, *p;
- p = skb_header_pointer(skb, k, 2, &_tmp);
- if (p != NULL) {
- A = ntohs(*p);
- continue;
- }
- }
return 0;
case BPF_LD|BPF_B|BPF_ABS:
k = fentry->k;
load_b:
- if (k >= 0 && (unsigned int)k < len) {
- A = data[k];
+ ptr = load_pointer(skb, k, 1, &tmp);
+ if (ptr != NULL) {
+ A = *(u8 *)ptr;
continue;
}
- if (k < 0) {
- u8 *ptr;
-
- if (k >= SKF_AD_OFF)
- break;
- ptr = load_pointer(skb, k);
- if (ptr) {
- A = *ptr;
- continue;
- }
- } else {
- u8 _tmp, *p;
- p = skb_header_pointer(skb, k, 1, &_tmp);
- if (p != NULL) {
- A = *p;
- continue;
- }
- }
return 0;
case BPF_LD|BPF_W|BPF_LEN:
- A = len;
+ A = skb->len;
continue;
case BPF_LDX|BPF_W|BPF_LEN:
- X = len;
+ X = skb->len;
continue;
case BPF_LD|BPF_W|BPF_IND:
k = X + fentry->k;
@@ -259,10 +217,12 @@ load_b:
k = X + fentry->k;
goto load_b;
case BPF_LDX|BPF_B|BPF_MSH:
- if (fentry->k >= len)
- return 0;
- X = (data[fentry->k] & 0xf) << 2;
- continue;
+ ptr = load_pointer(skb, fentry->k, 1, &tmp);
+ if (ptr != NULL) {
+ X = (*(u8 *)ptr & 0xf) << 2;
+ continue;
+ }
+ return 0;
case BPF_LD|BPF_IMM:
A = fentry->k;
continue;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 851eb927ed97..1beb782ac41b 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -1598,6 +1598,8 @@ static int neightbl_fill_info(struct neigh_table *tbl, struct sk_buff *skb,
read_lock_bh(&tbl->lock);
ndtmsg->ndtm_family = tbl->family;
+ ndtmsg->ndtm_pad1 = 0;
+ ndtmsg->ndtm_pad2 = 0;
RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
RTA_PUT_MSECS(skb, NDTA_GC_INTERVAL, tbl->gc_interval);
@@ -1683,6 +1685,8 @@ static int neightbl_fill_param_info(struct neigh_table *tbl,
read_lock_bh(&tbl->lock);
ndtmsg->ndtm_family = tbl->family;
+ ndtmsg->ndtm_pad1 = 0;
+ ndtmsg->ndtm_pad2 = 0;
RTA_PUT_STRING(skb, NDTA_NAME, tbl->id);
if (neightbl_fill_parms(skb, parms) < 0)
@@ -1872,6 +1876,8 @@ static int neigh_fill_info(struct sk_buff *skb, struct neighbour *n,
struct ndmsg *ndm = NLMSG_DATA(nlh);
ndm->ndm_family = n->ops->family;
+ ndm->ndm_pad1 = 0;
+ ndm->ndm_pad2 = 0;
ndm->ndm_flags = n->flags;
ndm->ndm_type = n->type;
ndm->ndm_ifindex = n->dev->ifindex;
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index c57b06bc79f3..975d651312dc 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -151,7 +151,7 @@
#include <asm/timex.h>
-#define VERSION "pktgen v2.61: Packet Generator for packet performance testing.\n"
+#define VERSION "pktgen v2.62: Packet Generator for packet performance testing.\n"
/* #define PG_DEBUG(a) a */
#define PG_DEBUG(a)
@@ -1921,6 +1921,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
struct iphdr *iph;
struct pktgen_hdr *pgh = NULL;
+ /* Update any of the values, used when we're incrementing various
+ * fields.
+ */
+ mod_cur_headers(pkt_dev);
+
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
@@ -1934,11 +1939,6 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
- /* Update any of the values, used when we're incrementing various
- * fields.
- */
- mod_cur_headers(pkt_dev);
-
memcpy(eth, pkt_dev->hh, 12);
*(u16*)&eth[12] = __constant_htons(ETH_P_IP);
@@ -2192,7 +2192,12 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
int datalen;
struct ipv6hdr *iph;
struct pktgen_hdr *pgh = NULL;
-
+
+ /* Update any of the values, used when we're incrementing various
+ * fields.
+ */
+ mod_cur_headers(pkt_dev);
+
skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16, GFP_ATOMIC);
if (!skb) {
sprintf(pkt_dev->result, "No memory");
@@ -2206,17 +2211,9 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
-
- /* Update any of the values, used when we're incrementing various
- * fields.
- */
- mod_cur_headers(pkt_dev);
-
-
memcpy(eth, pkt_dev->hh, 12);
*(u16*)&eth[12] = __constant_htons(ETH_P_IPV6);
-
-
+
datalen = pkt_dev->cur_pkt_size-14-
sizeof(struct ipv6hdr)-sizeof(struct udphdr); /* Eth + IPh + UDPh */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index e013d836a7ab..4b1bb30e6381 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -126,6 +126,7 @@ void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const void *data
rta->rta_type = attrtype;
rta->rta_len = size;
memcpy(RTA_DATA(rta), data, attrlen);
+ memset(RTA_DATA(rta) + attrlen, 0, RTA_ALIGN(size) - size);
}
size_t rtattr_strlcpy(char *dest, const struct rtattr *rta, size_t size)
@@ -188,6 +189,7 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
nlh = NLMSG_NEW(skb, pid, seq, type, sizeof(*r), flags);
r = NLMSG_DATA(nlh);
r->ifi_family = AF_UNSPEC;
+ r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev_get_flags(dev);
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 6d68c03bc051..d9f7b06fe886 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -129,7 +129,7 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
* Buffers may only be allocated from interrupts using a @gfp_mask of
* %GFP_ATOMIC.
*/
-struct sk_buff *alloc_skb(unsigned int size, int gfp_mask)
+struct sk_buff *alloc_skb(unsigned int size, unsigned int __nocast gfp_mask)
{
struct sk_buff *skb;
u8 *data;
@@ -182,7 +182,8 @@ nodata:
* %GFP_ATOMIC.
*/
struct sk_buff *alloc_skb_from_cache(kmem_cache_t *cp,
- unsigned int size, int gfp_mask)
+ unsigned int size,
+ unsigned int __nocast gfp_mask)
{
struct sk_buff *skb;
u8 *data;
@@ -322,7 +323,7 @@ void __kfree_skb(struct sk_buff *skb)
* %GFP_ATOMIC.
*/
-struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_clone(struct sk_buff *skb, unsigned int __nocast gfp_mask)
{
struct sk_buff *n = kmem_cache_alloc(skbuff_head_cache, gfp_mask);
@@ -357,7 +358,6 @@ struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask)
C(ip_summed);
C(priority);
C(protocol);
- C(security);
n->destructor = NULL;
#ifdef CONFIG_NETFILTER
C(nfmark);
@@ -422,7 +422,6 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
new->pkt_type = old->pkt_type;
new->stamp = old->stamp;
new->destructor = NULL;
- new->security = old->security;
#ifdef CONFIG_NETFILTER
new->nfmark = old->nfmark;
new->nfcache = old->nfcache;
@@ -462,7 +461,7 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
* header is going to be modified. Use pskb_copy() instead.
*/
-struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
+struct sk_buff *skb_copy(const struct sk_buff *skb, unsigned int __nocast gfp_mask)
{
int headerlen = skb->data - skb->head;
/*
@@ -501,7 +500,7 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, int gfp_mask)
* The returned buffer has a reference count of 1.
*/
-struct sk_buff *pskb_copy(struct sk_buff *skb, int gfp_mask)
+struct sk_buff *pskb_copy(struct sk_buff *skb, unsigned int __nocast gfp_mask)
{
/*
* Allocate the copy buffer
@@ -559,7 +558,8 @@ out:
* reloaded after call to this function.
*/
-int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int gfp_mask)
+int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
+ unsigned int __nocast gfp_mask)
{
int i;
u8 *data;
@@ -649,7 +649,8 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
* only by netfilter in the cases when checksum is recalculated? --ANK
*/
struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
- int newheadroom, int newtailroom, int gfp_mask)
+ int newheadroom, int newtailroom,
+ unsigned int __nocast gfp_mask)
{
/*
* Allocate the copy buffer
@@ -1500,6 +1501,159 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
skb_split_no_header(skb, skb1, len, pos);
}
+/**
+ * skb_prepare_seq_read - Prepare a sequential read of skb data
+ * @skb: the buffer to read
+ * @from: lower offset of data to be read
+ * @to: upper offset of data to be read
+ * @st: state variable
+ *
+ * Initializes the specified state variable. Must be called before
+ * invoking skb_seq_read() for the first time.
+ */
+void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
+ unsigned int to, struct skb_seq_state *st)
+{
+ st->lower_offset = from;
+ st->upper_offset = to;
+ st->root_skb = st->cur_skb = skb;
+ st->frag_idx = st->stepped_offset = 0;
+ st->frag_data = NULL;
+}
+
+/**
+ * skb_seq_read - Sequentially read skb data
+ * @consumed: number of bytes consumed by the caller so far
+ * @data: destination pointer for data to be returned
+ * @st: state variable
+ *
+ * Reads a block of skb data at &consumed relative to the
+ * lower offset specified to skb_prepare_seq_read(). Assigns
+ * the head of the data block to &data and returns the length
+ * of the block or 0 if the end of the skb data or the upper
+ * offset has been reached.
+ *
+ * The caller is not required to consume all of the data
+ * returned, i.e. &consumed is typically set to the number
+ * of bytes already consumed and the next call to
+ * skb_seq_read() will return the remaining part of the block.
+ *
+ * Note: The size of each block of data returned can be arbitary,
+ * this limitation is the cost for zerocopy seqeuental
+ * reads of potentially non linear data.
+ *
+ * Note: Fragment lists within fragments are not implemented
+ * at the moment, state->root_skb could be replaced with
+ * a stack for this purpose.
+ */
+unsigned int skb_seq_read(unsigned int consumed, const u8 **data,
+ struct skb_seq_state *st)
+{
+ unsigned int block_limit, abs_offset = consumed + st->lower_offset;
+ skb_frag_t *frag;
+
+ if (unlikely(abs_offset >= st->upper_offset))
+ return 0;
+
+next_skb:
+ block_limit = skb_headlen(st->cur_skb);
+
+ if (abs_offset < block_limit) {
+ *data = st->cur_skb->data + abs_offset;
+ return block_limit - abs_offset;
+ }
+
+ if (st->frag_idx == 0 && !st->frag_data)
+ st->stepped_offset += skb_headlen(st->cur_skb);
+
+ while (st->frag_idx < skb_shinfo(st->cur_skb)->nr_frags) {
+ frag = &skb_shinfo(st->cur_skb)->frags[st->frag_idx];
+ block_limit = frag->size + st->stepped_offset;
+
+ if (abs_offset < block_limit) {
+ if (!st->frag_data)
+ st->frag_data = kmap_skb_frag(frag);
+
+ *data = (u8 *) st->frag_data + frag->page_offset +
+ (abs_offset - st->stepped_offset);
+
+ return block_limit - abs_offset;
+ }
+
+ if (st->frag_data) {
+ kunmap_skb_frag(st->frag_data);
+ st->frag_data = NULL;
+ }
+
+ st->frag_idx++;
+ st->stepped_offset += frag->size;
+ }
+
+ if (st->cur_skb->next) {
+ st->cur_skb = st->cur_skb->next;
+ st->frag_idx = 0;
+ goto next_skb;
+ } else if (st->root_skb == st->cur_skb &&
+ skb_shinfo(st->root_skb)->frag_list) {
+ st->cur_skb = skb_shinfo(st->root_skb)->frag_list;
+ goto next_skb;
+ }
+
+ return 0;
+}
+
+/**
+ * skb_abort_seq_read - Abort a sequential read of skb data
+ * @st: state variable
+ *
+ * Must be called if skb_seq_read() was not called until it
+ * returned 0.
+ */
+void skb_abort_seq_read(struct skb_seq_state *st)
+{
+ if (st->frag_data)
+ kunmap_skb_frag(st->frag_data);
+}
+
+#define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb))
+
+static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,
+ struct ts_config *conf,
+ struct ts_state *state)
+{
+ return skb_seq_read(offset, text, TS_SKB_CB(state));
+}
+
+static void skb_ts_finish(struct ts_config *conf, struct ts_state *state)
+{
+ skb_abort_seq_read(TS_SKB_CB(state));
+}
+
+/**
+ * skb_find_text - Find a text pattern in skb data
+ * @skb: the buffer to look in
+ * @from: search offset
+ * @to: search limit
+ * @config: textsearch configuration
+ * @state: uninitialized textsearch state variable
+ *
+ * Finds a pattern in the skb data according to the specified
+ * textsearch configuration. Use textsearch_next() to retrieve
+ * subsequent occurrences of the pattern. Returns the offset
+ * to the first occurrence or UINT_MAX if no match was found.
+ */
+unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
+ unsigned int to, struct ts_config *config,
+ struct ts_state *state)
+{
+ config->get_next_block = skb_ts_get_next_block;
+ config->finish = skb_ts_finish;
+
+ skb_prepare_seq_read(skb, from, to, TS_SKB_CB(state));
+
+ return textsearch_find(config, state);
+}
+
void __init skb_init(void)
{
skbuff_head_cache = kmem_cache_create("skbuff_head_cache",
@@ -1538,3 +1692,7 @@ EXPORT_SYMBOL(skb_queue_tail);
EXPORT_SYMBOL(skb_unlink);
EXPORT_SYMBOL(skb_append);
EXPORT_SYMBOL(skb_split);
+EXPORT_SYMBOL(skb_prepare_seq_read);
+EXPORT_SYMBOL(skb_seq_read);
+EXPORT_SYMBOL(skb_abort_seq_read);
+EXPORT_SYMBOL(skb_find_text);
diff --git a/net/core/sock.c b/net/core/sock.c
index a6ec3ada7f9e..8b35ccdc2b3b 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -622,7 +622,8 @@ lenout:
* @prot: struct proto associated with this new sock instance
* @zero_it: if we should zero the newly allocated sock
*/
-struct sock *sk_alloc(int family, int priority, struct proto *prot, int zero_it)
+struct sock *sk_alloc(int family, unsigned int __nocast priority,
+ struct proto *prot, int zero_it)
{
struct sock *sk = NULL;
kmem_cache_t *slab = prot->slab;
@@ -750,7 +751,8 @@ unsigned long sock_i_ino(struct sock *sk)
/*
* Allocate a skb from the socket's send buffer.
*/
-struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority)
+struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
+ unsigned int __nocast priority)
{
if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) {
struct sk_buff * skb = alloc_skb(size, priority);
@@ -765,7 +767,8 @@ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int
/*
* Allocate a skb from the socket's receive buffer.
*/
-struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
+struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force,
+ unsigned int __nocast priority)
{
if (force || atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) {
struct sk_buff *skb = alloc_skb(size, priority);
@@ -780,7 +783,7 @@ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int
/*
* Allocate a memory block from the socket's option memory buffer.
*/
-void *sock_kmalloc(struct sock *sk, int size, int priority)
+void *sock_kmalloc(struct sock *sk, int size, unsigned int __nocast priority)
{
if ((unsigned)size <= sysctl_optmem_max &&
atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) {
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 880a88815211..8f817ad9f546 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -13,12 +13,8 @@
#ifdef CONFIG_SYSCTL
extern int netdev_max_backlog;
+extern int netdev_budget;
extern int weight_p;
-extern int no_cong_thresh;
-extern int no_cong;
-extern int lo_cong;
-extern int mod_cong;
-extern int netdev_fastroute;
extern int net_msg_cost;
extern int net_msg_burst;
@@ -86,38 +82,6 @@ ctl_table core_table[] = {
.proc_handler = &proc_dointvec
},
{
- .ctl_name = NET_CORE_NO_CONG_THRESH,
- .procname = "no_cong_thresh",
- .data = &no_cong_thresh,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
- .ctl_name = NET_CORE_NO_CONG,
- .procname = "no_cong",
- .data = &no_cong,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
- .ctl_name = NET_CORE_LO_CONG,
- .procname = "lo_cong",
- .data = &lo_cong,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
- .ctl_name = NET_CORE_MOD_CONG,
- .procname = "mod_cong",
- .data = &mod_cong,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec
- },
- {
.ctl_name = NET_CORE_MSG_COST,
.procname = "message_cost",
.data = &net_msg_cost,
@@ -161,6 +125,14 @@ ctl_table core_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec
},
+ {
+ .ctl_name = NET_CORE_BUDGET,
+ .procname = "netdev_budget",
+ .data = &netdev_budget,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = &proc_dointvec
+ },
{ .ctl_name = 0 }
};
diff --git a/net/core/wireless.c b/net/core/wireless.c
index b2fe378dfbf8..3ff5639c0b78 100644
--- a/net/core/wireless.c
+++ b/net/core/wireless.c
@@ -1102,6 +1102,7 @@ static inline int rtnetlink_fill_iwinfo(struct sk_buff * skb,
nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(*r));
r = NLMSG_DATA(nlh);
r->ifi_family = AF_UNSPEC;
+ r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev->flags;
diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig
index 2101da542ba8..92f2ec46fd22 100644
--- a/net/decnet/Kconfig
+++ b/net/decnet/Kconfig
@@ -1,6 +1,29 @@
#
# DECnet configuration
#
+config DECNET
+ tristate "DECnet Support"
+ ---help---
+ The DECnet networking protocol was used in many products made by
+ Digital (now Compaq). It provides reliable stream and sequenced
+ packet communications over which run a variety of services similar
+ to those which run over TCP/IP.
+
+ To find some tools to use with the kernel layer support, please
+ look at Patrick Caulfield's web site:
+ <http://linux-decnet.sourceforge.net/>.
+
+ More detailed documentation is available in
+ <file:Documentation/networking/decnet.txt>.
+
+ Be sure to say Y to "/proc file system support" and "Sysctl support"
+ below when using DECnet, since you will need sysctl support to aid
+ in configuration at run time.
+
+ The DECnet code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module is called decnet.
+
config DECNET_ROUTER
bool "DECnet: router support (EXPERIMENTAL)"
depends on DECNET && EXPERIMENTAL
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 29bb3cd21965..96a02800cd28 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -536,7 +536,7 @@ static void dn_keepalive(struct sock *sk)
* we are double checking that we are not sending too
* many of these keepalive frames.
*/
- if (skb_queue_len(&scp->other_xmit_queue) == 0)
+ if (skb_queue_empty(&scp->other_xmit_queue))
dn_nsp_send_link(sk, DN_NOCHANGE, 0);
}
@@ -1191,7 +1191,7 @@ static unsigned int dn_poll(struct file *file, struct socket *sock, poll_table
struct dn_scp *scp = DN_SK(sk);
int mask = datagram_poll(file, sock, wait);
- if (skb_queue_len(&scp->other_receive_queue))
+ if (!skb_queue_empty(&scp->other_receive_queue))
mask |= POLLRDBAND;
return mask;
@@ -1214,7 +1214,7 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCATMARK:
lock_sock(sk);
- val = (skb_queue_len(&scp->other_receive_queue) != 0);
+ val = !skb_queue_empty(&scp->other_receive_queue);
if (scp->state != DN_RUN)
val = -ENOTCONN;
release_sock(sk);
@@ -1630,7 +1630,7 @@ static int dn_data_ready(struct sock *sk, struct sk_buff_head *q, int flags, int
int len = 0;
if (flags & MSG_OOB)
- return skb_queue_len(q) ? 1 : 0;
+ return !skb_queue_empty(q) ? 1 : 0;
while(skb != (struct sk_buff *)q) {
struct dn_skb_cb *cb = DN_SKB_CB(skb);
@@ -1707,7 +1707,7 @@ static int dn_recvmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_err)
goto out;
- if (skb_queue_len(&scp->other_receive_queue)) {
+ if (!skb_queue_empty(&scp->other_receive_queue)) {
if (!(flags & MSG_OOB)) {
msg->msg_flags |= MSG_OOB;
if (!scp->other_report) {
diff --git a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
index 9934b25720e4..99bc061759c3 100644
--- a/net/decnet/dn_fib.c
+++ b/net/decnet/dn_fib.c
@@ -551,7 +551,8 @@ int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
if (t < s_t)
continue;
if (t > s_t)
- memset(&cb->args[1], 0, sizeof(cb->args)-sizeof(int));
+ memset(&cb->args[1], 0,
+ sizeof(cb->args) - sizeof(cb->args[0]));
tb = dn_fib_get_table(t, 0);
if (tb == NULL)
continue;
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 42abbf3f524f..8cce1fdbda90 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -342,7 +342,8 @@ int dn_nsp_xmit_timeout(struct sock *sk)
dn_nsp_output(sk);
- if (skb_queue_len(&scp->data_xmit_queue) || skb_queue_len(&scp->other_xmit_queue))
+ if (!skb_queue_empty(&scp->data_xmit_queue) ||
+ !skb_queue_empty(&scp->other_xmit_queue))
scp->persist = dn_nsp_persist(sk);
return 0;
diff --git a/net/econet/Kconfig b/net/econet/Kconfig
new file mode 100644
index 000000000000..39a2d2975e0e
--- /dev/null
+++ b/net/econet/Kconfig
@@ -0,0 +1,36 @@
+#
+# Acorn Econet/AUN protocols
+#
+
+config ECONET
+ tristate "Acorn Econet/AUN protocols (EXPERIMENTAL)"
+ depends on EXPERIMENTAL && INET
+ ---help---
+ Econet is a fairly old and slow networking protocol mainly used by
+ Acorn computers to access file and print servers. It uses native
+ Econet network cards. AUN is an implementation of the higher level
+ parts of Econet that runs over ordinary Ethernet connections, on
+ top of the UDP packet protocol, which in turn runs on top of the
+ Internet protocol IP.
+
+ If you say Y here, you can choose with the next two options whether
+ to send Econet/AUN traffic over a UDP Ethernet connection or over
+ a native Econet network card.
+
+ To compile this driver as a module, choose M here: the module
+ will be called econet.
+
+config ECONET_AUNUDP
+ bool "AUN over UDP"
+ depends on ECONET
+ help
+ Say Y here if you want to send Econet/AUN traffic over a UDP
+ connection (UDP is a packet based protocol that runs on top of the
+ Internet protocol IP) using an ordinary Ethernet network card.
+
+config ECONET_NATIVE
+ bool "Native Econet"
+ depends on ECONET
+ help
+ Say Y here if you have a native Econet network card installed in
+ your computer.
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
index 6617ea47d365..f6dbfb99b14d 100644
--- a/net/ethernet/eth.c
+++ b/net/ethernet/eth.c
@@ -92,10 +92,9 @@ int eth_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
* Set the source hardware address.
*/
- if(saddr)
- memcpy(eth->h_source,saddr,dev->addr_len);
- else
- memcpy(eth->h_source,dev->dev_addr,dev->addr_len);
+ if(!saddr)
+ saddr = dev->dev_addr;
+ memcpy(eth->h_source,saddr,dev->addr_len);
/*
* Anyway, the loopback-device should never use this function...
@@ -156,7 +155,7 @@ int eth_rebuild_header(struct sk_buff *skb)
* This is normal practice and works for any 'now in use' protocol.
*/
-unsigned short eth_type_trans(struct sk_buff *skb, struct net_device *dev)
+__be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
{
struct ethhdr *eth;
unsigned char *rawp;
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 567b03b1c349..df5386885a90 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -1,35 +1,8 @@
#
# IP configuration
#
-choice
- prompt "Choose IP: FIB lookup"
- depends on INET
- default IP_FIB_HASH
-
-config IP_FIB_HASH
- bool "FIB_HASH"
- ---help---
- Current FIB is very proven and good enough for most users.
-
-config IP_FIB_TRIE
- bool "FIB_TRIE"
- ---help---
- Use new experimental LC-trie as FIB lookup algoritm.
- This improves lookup performance
-
- LC-trie is described in:
-
- IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
- IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
- An experimental study of compression methods for dynamic tries
- Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
- http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
-
-endchoice
-
config IP_MULTICAST
bool "IP: multicasting"
- depends on INET
help
This is code for addressing several networked computers at once,
enlarging your kernel by about 2 KB. You need multicasting if you
@@ -43,7 +16,6 @@ config IP_MULTICAST
config IP_ADVANCED_ROUTER
bool "IP: advanced router"
- depends on INET
---help---
If you intend to run your Linux box mostly as a router, i.e. as a
computer that forwards and redistributes network packets, say Y; you
@@ -79,6 +51,44 @@ config IP_ADVANCED_ROUTER
If unsure, say N here.
+choice
+ prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)"
+ depends on IP_ADVANCED_ROUTER
+ default IP_FIB_HASH
+
+config IP_FIB_HASH
+ bool "FIB_HASH"
+ ---help---
+ Current FIB is very proven and good enough for most users.
+
+config IP_FIB_TRIE
+ bool "FIB_TRIE"
+ ---help---
+ Use new experimental LC-trie as FIB lookup algoritm.
+ This improves lookup performance if you have a large
+ number of routes.
+
+ LC-trie is a longest matching prefix lookup algorithm which
+ performs better than FIB_HASH for large routing tables.
+ But, it consumes more memory and is more complex.
+
+ LC-trie is described in:
+
+ IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
+ IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
+ An experimental study of compression methods for dynamic tries
+ Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
+ http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+
+endchoice
+
+# If the user does not enable advanced routing, he gets the safe
+# default of the fib-hash algorithm.
+config IP_FIB_HASH
+ bool
+ depends on !IP_ADVANCED_ROUTER
+ default y
+
config IP_MULTIPLE_TABLES
bool "IP: policy routing"
depends on IP_ADVANCED_ROUTER
@@ -171,7 +181,6 @@ config IP_ROUTE_VERBOSE
config IP_PNP
bool "IP: kernel level autoconfiguration"
- depends on INET
help
This enables automatic configuration of IP addresses of devices and
of the routing table during kernel boot, based on either information
@@ -230,7 +239,6 @@ config IP_PNP_RARP
# bool ' IP: ARP support' CONFIG_IP_PNP_ARP
config NET_IPIP
tristate "IP: tunneling"
- depends on INET
select INET_TUNNEL
---help---
Tunneling means encapsulating data of one protocol type within
@@ -248,7 +256,6 @@ config NET_IPIP
config NET_IPGRE
tristate "IP: GRE tunnels over IP"
- depends on INET
select XFRM
help
Tunneling means encapsulating data of one protocol type within
@@ -307,7 +314,7 @@ config IP_PIMSM_V2
config ARPD
bool "IP: ARP daemon support (EXPERIMENTAL)"
- depends on INET && EXPERIMENTAL
+ depends on EXPERIMENTAL
---help---
Normally, the kernel maintains an internal cache which maps IP
addresses to hardware addresses on the local network, so that
@@ -332,7 +339,6 @@ config ARPD
config SYN_COOKIES
bool "IP: TCP syncookie support (disabled per default)"
- depends on INET
---help---
Normal TCP/IP networking is open to an attack known as "SYN
flooding". This denial-of-service attack prevents legitimate remote
@@ -369,7 +375,6 @@ config SYN_COOKIES
config INET_AH
tristate "IP: AH transformation"
- depends on INET
select XFRM
select CRYPTO
select CRYPTO_HMAC
@@ -382,7 +387,6 @@ config INET_AH
config INET_ESP
tristate "IP: ESP transformation"
- depends on INET
select XFRM
select CRYPTO
select CRYPTO_HMAC
@@ -396,7 +400,6 @@ config INET_ESP
config INET_IPCOMP
tristate "IP: IPComp transformation"
- depends on INET
select XFRM
select INET_TUNNEL
select CRYPTO
@@ -409,7 +412,6 @@ config INET_IPCOMP
config INET_TUNNEL
tristate "IP: tunnel transformation"
- depends on INET
select XFRM
---help---
Support for generic IP tunnel transformation, which is required by
@@ -419,7 +421,6 @@ config INET_TUNNEL
config IP_TCPDIAG
tristate "IP: TCP socket monitoring interface"
- depends on INET
default y
---help---
Support for TCP socket monitoring interface used by native Linux
@@ -433,5 +434,108 @@ config IP_TCPDIAG
config IP_TCPDIAG_IPV6
def_bool (IP_TCPDIAG=y && IPV6=y) || (IP_TCPDIAG=m && IPV6)
+config TCP_CONG_ADVANCED
+ bool "TCP: advanced congestion control"
+ ---help---
+ Support for selection of various TCP congestion control
+ modules.
+
+ Nearly all users can safely say no here, and a safe default
+ selection will be made (BIC-TCP with new Reno as a fallback).
+
+ If unsure, say N.
+
+# TCP Reno is builtin (required as fallback)
+menu "TCP congestion control"
+ depends on TCP_CONG_ADVANCED
+
+config TCP_CONG_BIC
+ tristate "Binary Increase Congestion (BIC) control"
+ default y
+ ---help---
+ BIC-TCP is a sender-side only change that ensures a linear RTT
+ fairness under large windows while offering both scalability and
+ bounded TCP-friendliness. The protocol combines two schemes
+ called additive increase and binary search increase. When the
+ congestion window is large, additive increase with a large
+ increment ensures linear RTT fairness as well as good
+ scalability. Under small congestion windows, binary search
+ increase provides TCP friendliness.
+ See http://www.csc.ncsu.edu/faculty/rhee/export/bitcp/
+
+config TCP_CONG_WESTWOOD
+ tristate "TCP Westwood+"
+ default m
+ ---help---
+ TCP Westwood+ is a sender-side only modification of the TCP Reno
+ protocol stack that optimizes the performance of TCP congestion
+ control. It is based on end-to-end bandwidth estimation to set
+ congestion window and slow start threshold after a congestion
+ episode. Using this estimation, TCP Westwood+ adaptively sets a
+ slow start threshold and a congestion window which takes into
+ account the bandwidth used at the time congestion is experienced.
+ TCP Westwood+ significantly increases fairness wrt TCP Reno in
+ wired networks and throughput over wireless links.
+
+config TCP_CONG_HTCP
+ tristate "H-TCP"
+ default m
+ ---help---
+ H-TCP is a send-side only modifications of the TCP Reno
+ protocol stack that optimizes the performance of TCP
+ congestion control for high speed network links. It uses a
+ modeswitch to change the alpha and beta parameters of TCP Reno
+ based on network conditions and in a way so as to be fair with
+ other Reno and H-TCP flows.
+
+config TCP_CONG_HSTCP
+ tristate "High Speed TCP"
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ Sally Floyd's High Speed TCP (RFC 3649) congestion control.
+ A modification to TCP's congestion control mechanism for use
+ with large congestion windows. A table indicates how much to
+ increase the congestion window by when an ACK is received.
+ For more detail see http://www.icir.org/floyd/hstcp.html
+
+config TCP_CONG_HYBLA
+ tristate "TCP-Hybla congestion control algorithm"
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ TCP-Hybla is a sender-side only change that eliminates penalization of
+ long-RTT, large-bandwidth connections, like when satellite legs are
+ involved, expecially when sharing a common bottleneck with normal
+ terrestrial connections.
+
+config TCP_CONG_VEGAS
+ tristate "TCP Vegas"
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ TCP Vegas is a sender-side only change to TCP that anticipates
+ the onset of congestion by estimating the bandwidth. TCP Vegas
+ adjusts the sending rate by modifying the congestion
+ window. TCP Vegas should provide less packet loss, but it is
+ not as aggressive as TCP Reno.
+
+config TCP_CONG_SCALABLE
+ tristate "Scalable TCP"
+ depends on EXPERIMENTAL
+ default n
+ ---help---
+ Scalable TCP is a sender-side only change to TCP which uses a
+ MIMD congestion control algorithm which has some nice scaling
+ properties, though is known to have fairness issues.
+ See http://www-lce.eng.cam.ac.uk/~ctk21/scalable/
+
+endmenu
+
+config TCP_CONG_BIC
+ tristate
+ depends on !TCP_CONG_ADVANCED
+ default y
+
source "net/ipv4/ipvs/Kconfig"
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile
index 65d57d8e1add..5718cdb3a61e 100644
--- a/net/ipv4/Makefile
+++ b/net/ipv4/Makefile
@@ -5,7 +5,8 @@
obj-y := utils.o route.o inetpeer.o protocol.o \
ip_input.o ip_fragment.o ip_forward.o ip_options.o \
ip_output.o ip_sockglue.o \
- tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o tcp_minisocks.o \
+ tcp.o tcp_input.o tcp_output.o tcp_timer.o tcp_ipv4.o \
+ tcp_minisocks.o tcp_cong.o \
datagram.o raw.o udp.o arp.o icmp.o devinet.o af_inet.o igmp.o \
sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
@@ -30,6 +31,13 @@ obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_IP_VS) += ipvs/
obj-$(CONFIG_IP_TCPDIAG) += tcp_diag.o
obj-$(CONFIG_IP_ROUTE_MULTIPATH_CACHED) += multipath.o
+obj-$(CONFIG_TCP_CONG_BIC) += tcp_bic.o
+obj-$(CONFIG_TCP_CONG_WESTWOOD) += tcp_westwood.o
+obj-$(CONFIG_TCP_CONG_HSTCP) += tcp_highspeed.o
+obj-$(CONFIG_TCP_CONG_HYBLA) += tcp_hybla.o
+obj-$(CONFIG_TCP_CONG_HTCP) += tcp_htcp.o
+obj-$(CONFIG_TCP_CONG_VEGAS) += tcp_vegas.o
+obj-$(CONFIG_TCP_CONG_SCALABLE) += tcp_scalable.o
obj-$(CONFIG_XFRM) += xfrm4_policy.o xfrm4_state.o xfrm4_input.o \
xfrm4_output.o
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 658e7977924d..ef7468376ae6 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1009,6 +1009,15 @@ static int __init init_ipv4_mibs(void)
static int ipv4_proc_init(void);
extern void ipfrag_init(void);
+/*
+ * IP protocol layer initialiser
+ */
+
+static struct packet_type ip_packet_type = {
+ .type = __constant_htons(ETH_P_IP),
+ .func = ip_rcv,
+};
+
static int __init inet_init(void)
{
struct sk_buff *dummy_skb;
@@ -1102,6 +1111,8 @@ static int __init inet_init(void)
ipfrag_init();
+ dev_add_pack(&ip_packet_type);
+
rc = 0;
out:
return rc;
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c
index 0671569ee6f0..4be234c7d8c3 100644
--- a/net/ipv4/fib_trie.c
+++ b/net/ipv4/fib_trie.c
@@ -43,7 +43,7 @@
* 2 of the License, or (at your option) any later version.
*/
-#define VERSION "0.323"
+#define VERSION "0.325"
#include <linux/config.h>
#include <asm/uaccess.h>
@@ -136,6 +136,7 @@ struct trie_use_stats {
unsigned int semantic_match_passed;
unsigned int semantic_match_miss;
unsigned int null_node_hit;
+ unsigned int resize_node_skipped;
};
#endif
@@ -164,8 +165,8 @@ static void put_child(struct trie *t, struct tnode *tn, int i, struct node *n);
static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int wasfull);
static int tnode_child_length(struct tnode *tn);
static struct node *resize(struct trie *t, struct tnode *tn);
-static struct tnode *inflate(struct trie *t, struct tnode *tn);
-static struct tnode *halve(struct trie *t, struct tnode *tn);
+static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err);
+static struct tnode *halve(struct trie *t, struct tnode *tn, int *err);
static void tnode_free(struct tnode *tn);
static void trie_dump_seq(struct seq_file *seq, struct trie *t);
extern struct fib_alias *fib_find_alias(struct list_head *fah, u8 tos, u32 prio);
@@ -341,8 +342,10 @@ static struct leaf *leaf_new(void)
static struct leaf_info *leaf_info_new(int plen)
{
struct leaf_info *li = kmalloc(sizeof(struct leaf_info), GFP_KERNEL);
- li->plen = plen;
- INIT_LIST_HEAD(&li->falh);
+ if(li) {
+ li->plen = plen;
+ INIT_LIST_HEAD(&li->falh);
+ }
return li;
}
@@ -356,11 +359,32 @@ static inline void free_leaf_info(struct leaf_info *li)
kfree(li);
}
+static struct tnode *tnode_alloc(unsigned int size)
+{
+ if (size <= PAGE_SIZE) {
+ return kmalloc(size, GFP_KERNEL);
+ } else {
+ return (struct tnode *)
+ __get_free_pages(GFP_KERNEL, get_order(size));
+ }
+}
+
+static void __tnode_free(struct tnode *tn)
+{
+ unsigned int size = sizeof(struct tnode) +
+ (1<<tn->bits) * sizeof(struct node *);
+
+ if (size <= PAGE_SIZE)
+ kfree(tn);
+ else
+ free_pages((unsigned long)tn, get_order(size));
+}
+
static struct tnode* tnode_new(t_key key, int pos, int bits)
{
int nchildren = 1<<bits;
int sz = sizeof(struct tnode) + nchildren * sizeof(struct node *);
- struct tnode *tn = kmalloc(sz, GFP_KERNEL);
+ struct tnode *tn = tnode_alloc(sz);
if(tn) {
memset(tn, 0, sz);
@@ -388,7 +412,7 @@ static void tnode_free(struct tnode *tn)
printk("FL %p \n", tn);
}
else if(IS_TNODE(tn)) {
- kfree(tn);
+ __tnode_free(tn);
if(trie_debug > 0 )
printk("FT %p \n", tn);
}
@@ -458,6 +482,7 @@ static void tnode_put_child_reorg(struct tnode *tn, int i, struct node *n, int w
static struct node *resize(struct trie *t, struct tnode *tn)
{
int i;
+ int err = 0;
if (!tn)
return NULL;
@@ -554,12 +579,20 @@ static struct node *resize(struct trie *t, struct tnode *tn)
*/
check_tnode(tn);
-
+
+ err = 0;
while ((tn->full_children > 0 &&
50 * (tn->full_children + tnode_child_length(tn) - tn->empty_children) >=
inflate_threshold * tnode_child_length(tn))) {
- tn = inflate(t, tn);
+ tn = inflate(t, tn, &err);
+
+ if(err) {
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+ t->stats.resize_node_skipped++;
+#endif
+ break;
+ }
}
check_tnode(tn);
@@ -568,11 +601,22 @@ static struct node *resize(struct trie *t, struct tnode *tn)
* Halve as long as the number of empty children in this
* node is above threshold.
*/
+
+ err = 0;
while (tn->bits > 1 &&
100 * (tnode_child_length(tn) - tn->empty_children) <
- halve_threshold * tnode_child_length(tn))
+ halve_threshold * tnode_child_length(tn)) {
+
+ tn = halve(t, tn, &err);
+
+ if(err) {
+#ifdef CONFIG_IP_FIB_TRIE_STATS
+ t->stats.resize_node_skipped++;
+#endif
+ break;
+ }
+ }
- tn = halve(t, tn);
/* Only one child remains */
@@ -597,7 +641,7 @@ static struct node *resize(struct trie *t, struct tnode *tn)
return (struct node *) tn;
}
-static struct tnode *inflate(struct trie *t, struct tnode *tn)
+static struct tnode *inflate(struct trie *t, struct tnode *tn, int *err)
{
struct tnode *inode;
struct tnode *oldtnode = tn;
@@ -609,8 +653,63 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
tn = tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits + 1);
- if (!tn)
- trie_bug("tnode_new failed");
+ if (!tn) {
+ *err = -ENOMEM;
+ return oldtnode;
+ }
+
+ /*
+ * Preallocate and store tnodes before the actual work so we
+ * don't get into an inconsistent state if memory allocation
+ * fails. In case of failure we return the oldnode and inflate
+ * of tnode is ignored.
+ */
+
+ for(i = 0; i < olen; i++) {
+ struct tnode *inode = (struct tnode *) tnode_get_child(oldtnode, i);
+
+ if (inode &&
+ IS_TNODE(inode) &&
+ inode->pos == oldtnode->pos + oldtnode->bits &&
+ inode->bits > 1) {
+ struct tnode *left, *right;
+
+ t_key m = TKEY_GET_MASK(inode->pos, 1);
+
+ left = tnode_new(inode->key&(~m), inode->pos + 1,
+ inode->bits - 1);
+
+ if(!left) {
+ *err = -ENOMEM;
+ break;
+ }
+
+ right = tnode_new(inode->key|m, inode->pos + 1,
+ inode->bits - 1);
+
+ if(!right) {
+ *err = -ENOMEM;
+ break;
+ }
+
+ put_child(t, tn, 2*i, (struct node *) left);
+ put_child(t, tn, 2*i+1, (struct node *) right);
+ }
+ }
+
+ if(*err) {
+ int size = tnode_child_length(tn);
+ int j;
+
+ for(j = 0; j < size; j++)
+ if( tn->child[j])
+ tnode_free((struct tnode *)tn->child[j]);
+
+ tnode_free(tn);
+
+ *err = -ENOMEM;
+ return oldtnode;
+ }
for(i = 0; i < olen; i++) {
struct node *node = tnode_get_child(oldtnode, i);
@@ -623,7 +722,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
if(IS_LEAF(node) || ((struct tnode *) node)->pos >
tn->pos + tn->bits - 1) {
- if(tkey_extract_bits(node->key, tn->pos + tn->bits - 1,
+ if(tkey_extract_bits(node->key, oldtnode->pos + oldtnode->bits,
1) == 0)
put_child(t, tn, 2*i, node);
else
@@ -663,27 +762,22 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
* the position (inode->pos)
*/
- t_key m = TKEY_GET_MASK(inode->pos, 1);
-
/* Use the old key, but set the new significant
* bit to zero.
*/
- left = tnode_new(inode->key&(~m), inode->pos + 1,
- inode->bits - 1);
- if(!left)
- trie_bug("tnode_new failed");
-
-
- /* Use the old key, but set the new significant
- * bit to one.
- */
- right = tnode_new(inode->key|m, inode->pos + 1,
- inode->bits - 1);
+ left = (struct tnode *) tnode_get_child(tn, 2*i);
+ put_child(t, tn, 2*i, NULL);
+
+ if(!left)
+ BUG();
+
+ right = (struct tnode *) tnode_get_child(tn, 2*i+1);
+ put_child(t, tn, 2*i+1, NULL);
+
+ if(!right)
+ BUG();
- if(!right)
- trie_bug("tnode_new failed");
-
size = tnode_child_length(left);
for(j = 0; j < size; j++) {
put_child(t, left, j, inode->child[j]);
@@ -699,7 +793,7 @@ static struct tnode *inflate(struct trie *t, struct tnode *tn)
return tn;
}
-static struct tnode *halve(struct trie *t, struct tnode *tn)
+static struct tnode *halve(struct trie *t, struct tnode *tn, int *err)
{
struct tnode *oldtnode = tn;
struct node *left, *right;
@@ -710,8 +804,48 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
tn=tnode_new(oldtnode->key, oldtnode->pos, oldtnode->bits - 1);
- if(!tn)
- trie_bug("tnode_new failed");
+ if (!tn) {
+ *err = -ENOMEM;
+ return oldtnode;
+ }
+
+ /*
+ * Preallocate and store tnodes before the actual work so we
+ * don't get into an inconsistent state if memory allocation
+ * fails. In case of failure we return the oldnode and halve
+ * of tnode is ignored.
+ */
+
+ for(i = 0; i < olen; i += 2) {
+ left = tnode_get_child(oldtnode, i);
+ right = tnode_get_child(oldtnode, i+1);
+
+ /* Two nonempty children */
+ if( left && right) {
+ struct tnode *newBinNode =
+ tnode_new(left->key, tn->pos + tn->bits, 1);
+
+ if(!newBinNode) {
+ *err = -ENOMEM;
+ break;
+ }
+ put_child(t, tn, i/2, (struct node *)newBinNode);
+ }
+ }
+
+ if(*err) {
+ int size = tnode_child_length(tn);
+ int j;
+
+ for(j = 0; j < size; j++)
+ if( tn->child[j])
+ tnode_free((struct tnode *)tn->child[j]);
+
+ tnode_free(tn);
+
+ *err = -ENOMEM;
+ return oldtnode;
+ }
for(i = 0; i < olen; i += 2) {
left = tnode_get_child(oldtnode, i);
@@ -728,10 +862,11 @@ static struct tnode *halve(struct trie *t, struct tnode *tn)
/* Two nonempty children */
else {
struct tnode *newBinNode =
- tnode_new(left->key, tn->pos + tn->bits, 1);
+ (struct tnode *) tnode_get_child(tn, i/2);
+ put_child(t, tn, i/2, NULL);
if(!newBinNode)
- trie_bug("tnode_new failed");
+ BUG();
put_child(t, newBinNode, 0, left);
put_child(t, newBinNode, 1, right);
@@ -879,8 +1014,8 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn)
return (struct node*) tn;
}
-static struct list_head *
-fib_insert_node(struct trie *t, u32 key, int plen)
+static struct list_head *
+fib_insert_node(struct trie *t, int *err, u32 key, int plen)
{
int pos, newpos;
struct tnode *tp = NULL, *tn = NULL;
@@ -940,7 +1075,6 @@ fib_insert_node(struct trie *t, u32 key, int plen)
if(tp && IS_LEAF(tp))
BUG();
- t->revision++;
/* Case 1: n is a leaf. Compare prefixes */
@@ -949,8 +1083,10 @@ fib_insert_node(struct trie *t, u32 key, int plen)
li = leaf_info_new(plen);
- if(! li)
- BUG();
+ if(! li) {
+ *err = -ENOMEM;
+ goto err;
+ }
fa_head = &li->falh;
insert_leaf_info(&l->list, li);
@@ -959,14 +1095,19 @@ fib_insert_node(struct trie *t, u32 key, int plen)
t->size++;
l = leaf_new();
- if(! l)
- BUG();
+ if(! l) {
+ *err = -ENOMEM;
+ goto err;
+ }
l->key = key;
li = leaf_info_new(plen);
- if(! li)
- BUG();
+ if(! li) {
+ tnode_free((struct tnode *) l);
+ *err = -ENOMEM;
+ goto err;
+ }
fa_head = &li->falh;
insert_leaf_info(&l->list, li);
@@ -1003,9 +1144,14 @@ fib_insert_node(struct trie *t, u32 key, int plen)
newpos = 0;
tn = tnode_new(key, newpos, 1); /* First tnode */
}
- if(!tn)
- trie_bug("tnode_pfx_new failed");
+ if(!tn) {
+ free_leaf_info(li);
+ tnode_free((struct tnode *) l);
+ *err = -ENOMEM;
+ goto err;
+ }
+
NODE_SET_PARENT(tn, tp);
missbit=tkey_extract_bits(key, newpos, 1);
@@ -1027,7 +1173,9 @@ fib_insert_node(struct trie *t, u32 key, int plen)
}
/* Rebalance the trie */
t->trie = trie_rebalance(t, tp);
-done:;
+done:
+ t->revision++;
+err:;
return fa_head;
}
@@ -1156,8 +1304,12 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
* Insert new entry to the list.
*/
- if(!fa_head)
- fa_head = fib_insert_node(t, key, plen);
+ if(!fa_head) {
+ fa_head = fib_insert_node(t, &err, key, plen);
+ err = 0;
+ if(err)
+ goto out_free_new_fa;
+ }
write_lock_bh(&fib_lock);
@@ -1170,6 +1322,9 @@ fn_trie_insert(struct fib_table *tb, struct rtmsg *r, struct kern_rta *rta,
rtmsg_fib(RTM_NEWROUTE, htonl(key), new_fa, plen, tb->tb_id, nlhdr, req);
succeeded:
return 0;
+
+out_free_new_fa:
+ kmem_cache_free(fn_alias_kmem, new_fa);
out:
fib_release_info(fi);
err:;
@@ -2279,6 +2434,7 @@ static void collect_and_show(struct trie *t, struct seq_file *seq)
seq_printf(seq,"semantic match passed = %d\n", t->stats.semantic_match_passed);
seq_printf(seq,"semantic match miss = %d\n", t->stats.semantic_match_miss);
seq_printf(seq,"null node hit= %d\n", t->stats.null_node_hit);
+ seq_printf(seq,"skipped node resize = %d\n", t->stats.resize_node_skipped);
#ifdef CLEAR_STATS
memset(&(t->stats), 0, sizeof(t->stats));
#endif
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index cb759484979d..279f57abfecb 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -970,7 +970,8 @@ int icmp_rcv(struct sk_buff *skb)
* RFC 1122: 3.2.2.8 An ICMP_TIMESTAMP MAY be silently
* discarded if to broadcast/multicast.
*/
- if (icmph->type == ICMP_ECHO &&
+ if ((icmph->type == ICMP_ECHO ||
+ icmph->type == ICMP_TIMESTAMP) &&
sysctl_icmp_echo_ignore_broadcasts) {
goto error;
}
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 1f3183168a90..5088f90835ae 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1615,9 +1615,10 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
{
int err;
u32 addr = imr->imr_multiaddr.s_addr;
- struct ip_mc_socklist *iml, *i;
+ struct ip_mc_socklist *iml=NULL, *i;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
+ int ifindex;
int count = 0;
if (!MULTICAST(addr))
@@ -1633,37 +1634,30 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr)
goto done;
}
- iml = (struct ip_mc_socklist *)sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL);
-
err = -EADDRINUSE;
+ ifindex = imr->imr_ifindex;
for (i = inet->mc_list; i; i = i->next) {
- if (memcmp(&i->multi, imr, sizeof(*imr)) == 0) {
- /* New style additions are reference counted */
- if (imr->imr_address.s_addr == 0) {
- i->count++;
- err = 0;
- }
+ if (i->multi.imr_multiaddr.s_addr == addr &&
+ i->multi.imr_ifindex == ifindex)
goto done;
- }
count++;
}
err = -ENOBUFS;
- if (iml == NULL || count >= sysctl_igmp_max_memberships)
+ if (count >= sysctl_igmp_max_memberships)
+ goto done;
+ iml = (struct ip_mc_socklist *)sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL);
+ if (iml == NULL)
goto done;
+
memcpy(&iml->multi, imr, sizeof(*imr));
iml->next = inet->mc_list;
- iml->count = 1;
iml->sflist = NULL;
iml->sfmode = MCAST_EXCLUDE;
inet->mc_list = iml;
ip_mc_inc_group(in_dev, addr);
- iml = NULL;
err = 0;
-
done:
rtnl_shunlock();
- if (iml)
- sock_kfree_s(sk, iml, sizeof(*iml));
return err;
}
@@ -1693,30 +1687,25 @@ int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr)
{
struct inet_sock *inet = inet_sk(sk);
struct ip_mc_socklist *iml, **imlp;
+ struct in_device *in_dev;
+ u32 group = imr->imr_multiaddr.s_addr;
+ u32 ifindex;
rtnl_lock();
+ in_dev = ip_mc_find_dev(imr);
+ if (!in_dev) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+ ifindex = imr->imr_ifindex;
for (imlp = &inet->mc_list; (iml = *imlp) != NULL; imlp = &iml->next) {
- if (iml->multi.imr_multiaddr.s_addr==imr->imr_multiaddr.s_addr &&
- iml->multi.imr_address.s_addr==imr->imr_address.s_addr &&
- (!imr->imr_ifindex || iml->multi.imr_ifindex==imr->imr_ifindex)) {
- struct in_device *in_dev;
-
- in_dev = inetdev_by_index(iml->multi.imr_ifindex);
- if (in_dev)
- (void) ip_mc_leave_src(sk, iml, in_dev);
- if (--iml->count) {
- rtnl_unlock();
- if (in_dev)
- in_dev_put(in_dev);
- return 0;
- }
+ if (iml->multi.imr_multiaddr.s_addr == group &&
+ iml->multi.imr_ifindex == ifindex) {
+ (void) ip_mc_leave_src(sk, iml, in_dev);
*imlp = iml->next;
- if (in_dev) {
- ip_mc_dec_group(in_dev, imr->imr_multiaddr.s_addr);
- in_dev_put(in_dev);
- }
+ ip_mc_dec_group(in_dev, group);
rtnl_unlock();
sock_kfree_s(sk, iml, sizeof(*iml));
return 0;
@@ -1736,6 +1725,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
struct in_device *in_dev = NULL;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *psl;
+ int leavegroup = 0;
int i, j, rv;
if (!MULTICAST(addr))
@@ -1755,15 +1745,20 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
err = -EADDRNOTAVAIL;
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
- if (memcmp(&pmc->multi, mreqs, 2*sizeof(__u32)) == 0)
+ if (pmc->multi.imr_multiaddr.s_addr == imr.imr_multiaddr.s_addr
+ && pmc->multi.imr_ifindex == imr.imr_ifindex)
break;
}
- if (!pmc) /* must have a prior join */
+ if (!pmc) { /* must have a prior join */
+ err = -EINVAL;
goto done;
+ }
/* if a source filter was set, must be the same mode as before */
if (pmc->sflist) {
- if (pmc->sfmode != omode)
+ if (pmc->sfmode != omode) {
+ err = -EINVAL;
goto done;
+ }
} else if (pmc->sfmode != omode) {
/* allow mode switches for empty-set filters */
ip_mc_add_src(in_dev, &mreqs->imr_multiaddr, omode, 0, NULL, 0);
@@ -1775,7 +1770,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
psl = pmc->sflist;
if (!add) {
if (!psl)
- goto done;
+ goto done; /* err = -EADDRNOTAVAIL */
rv = !0;
for (i=0; i<psl->sl_count; i++) {
rv = memcmp(&psl->sl_addr[i], &mreqs->imr_sourceaddr,
@@ -1784,7 +1779,13 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
break;
}
if (rv) /* source not found */
+ goto done; /* err = -EADDRNOTAVAIL */
+
+ /* special case - (INCLUDE, empty) == LEAVE_GROUP */
+ if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
+ leavegroup = 1;
goto done;
+ }
/* update the interface filter */
ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1,
@@ -1842,18 +1843,21 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
&mreqs->imr_sourceaddr, 1);
done:
rtnl_shunlock();
+ if (leavegroup)
+ return ip_mc_leave_group(sk, &imr);
return err;
}
int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
{
- int err;
+ int err = 0;
struct ip_mreqn imr;
u32 addr = msf->imsf_multiaddr;
struct ip_mc_socklist *pmc;
struct in_device *in_dev;
struct inet_sock *inet = inet_sk(sk);
struct ip_sf_socklist *newpsl, *psl;
+ int leavegroup = 0;
if (!MULTICAST(addr))
return -EINVAL;
@@ -1872,15 +1876,22 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
err = -ENODEV;
goto done;
}
- err = -EADDRNOTAVAIL;
+
+ /* special case - (INCLUDE, empty) == LEAVE_GROUP */
+ if (msf->imsf_fmode == MCAST_INCLUDE && msf->imsf_numsrc == 0) {
+ leavegroup = 1;
+ goto done;
+ }
for (pmc=inet->mc_list; pmc; pmc=pmc->next) {
if (pmc->multi.imr_multiaddr.s_addr == msf->imsf_multiaddr &&
pmc->multi.imr_ifindex == imr.imr_ifindex)
break;
}
- if (!pmc) /* must have a prior join */
+ if (!pmc) { /* must have a prior join */
+ err = -EINVAL;
goto done;
+ }
if (msf->imsf_numsrc) {
newpsl = (struct ip_sf_socklist *)sock_kmalloc(sk,
IP_SFLSIZE(msf->imsf_numsrc), GFP_KERNEL);
@@ -1909,8 +1920,11 @@ int ip_mc_msfilter(struct sock *sk, struct ip_msfilter *msf, int ifindex)
0, NULL, 0);
pmc->sflist = newpsl;
pmc->sfmode = msf->imsf_fmode;
+ err = 0;
done:
rtnl_shunlock();
+ if (leavegroup)
+ err = ip_mc_leave_group(sk, &imr);
return err;
}
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index af2ec88bbb2f..c703528e0bcd 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -283,14 +283,18 @@ static inline int ip_rcv_finish(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
struct iphdr *iph = skb->nh.iph;
+ int err;
/*
* Initialise the virtual path cache for the packet. It describes
* how the packet travels inside Linux networking.
*/
if (skb->dst == NULL) {
- if (ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))
+ if ((err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos, dev))) {
+ if (err == -EHOSTUNREACH)
+ IP_INC_STATS_BH(IPSTATS_MIB_INADDRERRORS);
goto drop;
+ }
}
#ifdef CONFIG_NET_CLS_ROUTE
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index ee07aec215a0..80d13103b2b0 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -107,7 +107,6 @@ static int ip_dev_loopback_xmit(struct sk_buff *newskb)
newskb->pkt_type = PACKET_LOOPBACK;
newskb->ip_summed = CHECKSUM_UNNECESSARY;
BUG_TRAP(newskb->dst);
- nf_reset(newskb);
netif_rx(newskb);
return 0;
}
@@ -188,8 +187,6 @@ static inline int ip_finish_output2(struct sk_buff *skb)
skb = skb2;
}
- nf_reset(skb);
-
if (hh) {
int hh_alen;
@@ -383,7 +380,6 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->pkt_type = from->pkt_type;
to->priority = from->priority;
to->protocol = from->protocol;
- to->security = from->security;
dst_release(to->dst);
to->dst = dst_clone(from->dst);
to->dev = from->dev;
@@ -1323,23 +1319,8 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
ip_rt_put(rt);
}
-/*
- * IP protocol layer initialiser
- */
-
-static struct packet_type ip_packet_type = {
- .type = __constant_htons(ETH_P_IP),
- .func = ip_rcv,
-};
-
-/*
- * IP registers the packet type and then calls the subprotocol initialisers
- */
-
void __init ip_init(void)
{
- dev_add_pack(&ip_packet_type);
-
ip_rt_init();
inet_initpeers();
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index f8b172f89811..fc7c481d0d79 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -677,11 +677,11 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
mreq.imr_address.s_addr = mreqs.imr_interface;
mreq.imr_ifindex = 0;
err = ip_mc_join_group(sk, &mreq);
- if (err)
+ if (err && err != -EADDRINUSE)
break;
omode = MCAST_INCLUDE;
add = 1;
- } else /*IP_DROP_SOURCE_MEMBERSHIP */ {
+ } else /* IP_DROP_SOURCE_MEMBERSHIP */ {
omode = MCAST_INCLUDE;
add = 0;
}
@@ -754,7 +754,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
mreq.imr_address.s_addr = 0;
mreq.imr_ifindex = greqs.gsr_interface;
err = ip_mc_join_group(sk, &mreq);
- if (err)
+ if (err && err != -EADDRINUSE)
break;
greqs.gsr_interface = mreq.imr_ifindex;
omode = MCAST_INCLUDE;
diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c
index f2509034ce72..d2bf8e1930a3 100644
--- a/net/ipv4/ipconfig.c
+++ b/net/ipv4/ipconfig.c
@@ -1149,8 +1149,10 @@ static int __init ic_dynamic(void)
ic_rarp_cleanup();
#endif
- if (!ic_got_reply)
+ if (!ic_got_reply) {
+ ic_myaddr = INADDR_NONE;
return -1;
+ }
printk("IP-Config: Got %s answer from %u.%u.%u.%u, ",
((ic_got_reply & IC_RARP) ? "RARP"
diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c
index e4f809a93f47..7833d920bdba 100644
--- a/net/ipv4/ipmr.c
+++ b/net/ipv4/ipmr.c
@@ -297,6 +297,7 @@ static int vif_delete(int vifi)
static void ipmr_destroy_unres(struct mfc_cache *c)
{
struct sk_buff *skb;
+ struct nlmsgerr *e;
atomic_dec(&cache_resolve_queue_len);
@@ -306,7 +307,9 @@ static void ipmr_destroy_unres(struct mfc_cache *c)
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -ETIMEDOUT;
+ e = NLMSG_DATA(nlh);
+ e->error = -ETIMEDOUT;
+ memset(&e->msg, 0, sizeof(e->msg));
netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
} else
kfree_skb(skb);
@@ -499,6 +502,7 @@ static struct mfc_cache *ipmr_cache_alloc_unres(void)
static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
{
struct sk_buff *skb;
+ struct nlmsgerr *e;
/*
* Play the pending entries through our router
@@ -515,7 +519,9 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c)
nlh->nlmsg_type = NLMSG_ERROR;
nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr));
skb_trim(skb, nlh->nlmsg_len);
- ((struct nlmsgerr*)NLMSG_DATA(nlh))->error = -EMSGSIZE;
+ e = NLMSG_DATA(nlh);
+ e->error = -EMSGSIZE;
+ memset(&e->msg, 0, sizeof(e->msg));
}
err = netlink_unicast(rtnl, skb, NETLINK_CB(skb).dst_pid, MSG_DONTWAIT);
} else
diff --git a/net/ipv4/ipvs/Kconfig b/net/ipv4/ipvs/Kconfig
index 63a82b4b64bb..c9820bfc493a 100644
--- a/net/ipv4/ipvs/Kconfig
+++ b/net/ipv4/ipvs/Kconfig
@@ -2,11 +2,11 @@
# IP Virtual Server configuration
#
menu "IP: Virtual Server Configuration"
- depends on INET && NETFILTER
+ depends on NETFILTER
config IP_VS
tristate "IP virtual server support (EXPERIMENTAL)"
- depends on INET && NETFILTER
+ depends on NETFILTER
---help---
IP Virtual Server support will let you build a high-performance
virtual server based on cluster of two or more real servers. This
diff --git a/net/ipv4/ipvs/ip_vs_conn.c b/net/ipv4/ipvs/ip_vs_conn.c
index fd6feb5499fe..d0145a8b1551 100644
--- a/net/ipv4/ipvs/ip_vs_conn.c
+++ b/net/ipv4/ipvs/ip_vs_conn.c
@@ -548,7 +548,6 @@ void ip_vs_conn_expire_now(struct ip_vs_conn *cp)
{
if (del_timer(&cp->timer))
mod_timer(&cp->timer, jiffies);
- __ip_vs_conn_put(cp);
}
@@ -759,12 +758,11 @@ static inline int todrop_entry(struct ip_vs_conn *cp)
return 1;
}
-
+/* Called from keventd and must protect itself from softirqs */
void ip_vs_random_dropentry(void)
{
int idx;
struct ip_vs_conn *cp;
- struct ip_vs_conn *ct;
/*
* Randomly scan 1/32 of the whole table every second
@@ -775,7 +773,7 @@ void ip_vs_random_dropentry(void)
/*
* Lock is actually needed in this loop.
*/
- ct_write_lock(hash);
+ ct_write_lock_bh(hash);
list_for_each_entry(cp, &ip_vs_conn_tab[hash], c_list) {
if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT))
@@ -801,23 +799,14 @@ void ip_vs_random_dropentry(void)
continue;
}
- /*
- * Drop the entry, and drop its ct if not referenced
- */
- atomic_inc(&cp->refcnt);
- ct_write_unlock(hash);
-
- if ((ct = cp->control))
- atomic_inc(&ct->refcnt);
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (ct) {
+ if (cp->control) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(ct);
+ ip_vs_conn_expire_now(cp->control);
}
- ct_write_lock(hash);
}
- ct_write_unlock(hash);
+ ct_write_unlock_bh(hash);
}
}
@@ -829,7 +818,6 @@ static void ip_vs_conn_flush(void)
{
int idx;
struct ip_vs_conn *cp;
- struct ip_vs_conn *ct;
flush_again:
for (idx=0; idx<IP_VS_CONN_TAB_SIZE; idx++) {
@@ -839,18 +827,13 @@ static void ip_vs_conn_flush(void)
ct_write_lock_bh(idx);
list_for_each_entry(cp, &ip_vs_conn_tab[idx], c_list) {
- atomic_inc(&cp->refcnt);
- ct_write_unlock(idx);
- if ((ct = cp->control))
- atomic_inc(&ct->refcnt);
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
- if (ct) {
+ if (cp->control) {
IP_VS_DBG(4, "del conn template\n");
- ip_vs_conn_expire_now(ct);
+ ip_vs_conn_expire_now(cp->control);
}
- ct_write_lock(idx);
}
ct_write_unlock_bh(idx);
}
diff --git a/net/ipv4/ipvs/ip_vs_ctl.c b/net/ipv4/ipvs/ip_vs_ctl.c
index 218d9701036e..7d99ede2ef79 100644
--- a/net/ipv4/ipvs/ip_vs_ctl.c
+++ b/net/ipv4/ipvs/ip_vs_ctl.c
@@ -90,7 +90,8 @@ int ip_vs_get_debug_level(void)
#endif
/*
- * update_defense_level is called from keventd and from sysctl.
+ * update_defense_level is called from keventd and from sysctl,
+ * so it needs to protect itself from softirqs
*/
static void update_defense_level(void)
{
@@ -110,6 +111,8 @@ static void update_defense_level(void)
nomem = (availmem < sysctl_ip_vs_amemthresh);
+ local_bh_disable();
+
/* drop_entry */
spin_lock(&__ip_vs_dropentry_lock);
switch (sysctl_ip_vs_drop_entry) {
@@ -206,6 +209,8 @@ static void update_defense_level(void)
if (to_change >= 0)
ip_vs_protocol_timeout_change(sysctl_ip_vs_secure_tcp>1);
write_unlock(&__ip_vs_securetcp_lock);
+
+ local_bh_enable();
}
@@ -1360,9 +1365,7 @@ proc_do_defense_mode(ctl_table *table, int write, struct file * filp,
/* Restore the correct value */
*valp = val;
} else {
- local_bh_disable();
update_defense_level();
- local_bh_enable();
}
}
return rc;
@@ -2059,7 +2062,7 @@ ip_vs_copy_service(struct ip_vs_service_entry *dst, struct ip_vs_service *src)
dst->addr = src->addr;
dst->port = src->port;
dst->fwmark = src->fwmark;
- strcpy(dst->sched_name, src->scheduler->name);
+ strlcpy(dst->sched_name, src->scheduler->name, sizeof(dst->sched_name));
dst->flags = src->flags;
dst->timeout = src->timeout / HZ;
dst->netmask = src->netmask;
@@ -2080,6 +2083,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
list_for_each_entry(svc, &ip_vs_svc_table[idx], s_list) {
if (count >= get->num_services)
goto out;
+ memset(&entry, 0, sizeof(entry));
ip_vs_copy_service(&entry, svc);
if (copy_to_user(&uptr->entrytable[count],
&entry, sizeof(entry))) {
@@ -2094,6 +2098,7 @@ __ip_vs_get_service_entries(const struct ip_vs_get_services *get,
list_for_each_entry(svc, &ip_vs_svc_fwm_table[idx], f_list) {
if (count >= get->num_services)
goto out;
+ memset(&entry, 0, sizeof(entry));
ip_vs_copy_service(&entry, svc);
if (copy_to_user(&uptr->entrytable[count],
&entry, sizeof(entry))) {
@@ -2304,12 +2309,12 @@ do_ip_vs_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
memset(&d, 0, sizeof(d));
if (ip_vs_sync_state & IP_VS_STATE_MASTER) {
d[0].state = IP_VS_STATE_MASTER;
- strcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn);
+ strlcpy(d[0].mcast_ifn, ip_vs_master_mcast_ifn, sizeof(d[0].mcast_ifn));
d[0].syncid = ip_vs_master_syncid;
}
if (ip_vs_sync_state & IP_VS_STATE_BACKUP) {
d[1].state = IP_VS_STATE_BACKUP;
- strcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn);
+ strlcpy(d[1].mcast_ifn, ip_vs_backup_mcast_ifn, sizeof(d[1].mcast_ifn));
d[1].syncid = ip_vs_backup_syncid;
}
if (copy_to_user(user, &d, sizeof(d)) != 0)
diff --git a/net/ipv4/ipvs/ip_vs_sync.c b/net/ipv4/ipvs/ip_vs_sync.c
index 25c479550a32..574d1f509b46 100644
--- a/net/ipv4/ipvs/ip_vs_sync.c
+++ b/net/ipv4/ipvs/ip_vs_sync.c
@@ -839,10 +839,10 @@ int start_sync_thread(int state, char *mcast_ifn, __u8 syncid)
ip_vs_sync_state |= state;
if (state == IP_VS_STATE_MASTER) {
- strcpy(ip_vs_master_mcast_ifn, mcast_ifn);
+ strlcpy(ip_vs_master_mcast_ifn, mcast_ifn, sizeof(ip_vs_master_mcast_ifn));
ip_vs_master_syncid = syncid;
} else {
- strcpy(ip_vs_backup_mcast_ifn, mcast_ifn);
+ strlcpy(ip_vs_backup_mcast_ifn, mcast_ifn, sizeof(ip_vs_backup_mcast_ifn));
ip_vs_backup_syncid = syncid;
}
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
index 42dc95102873..1dd824f3cf0a 100644
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -432,6 +432,13 @@ static unsigned int ip_conntrack_defrag(unsigned int hooknum,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
+#if !defined(CONFIG_IP_NF_NAT) && !defined(CONFIG_IP_NF_NAT_MODULE)
+ /* Previously seen (loopback)? Ignore. Do this before
+ fragment check. */
+ if ((*pskb)->nfct)
+ return NF_ACCEPT;
+#endif
+
/* Gather fragments. */
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb,
diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c
index 9cde8c61f525..6706d3a1bc4f 100644
--- a/net/ipv4/netfilter/ipt_CLUSTERIP.c
+++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c
@@ -30,7 +30,7 @@
#include <linux/netfilter_ipv4/ipt_CLUSTERIP.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
-#define CLUSTERIP_VERSION "0.6"
+#define CLUSTERIP_VERSION "0.7"
#define DEBUG_CLUSTERIP
@@ -524,8 +524,9 @@ arp_mangle(unsigned int hook,
|| arp->ar_pln != 4 || arp->ar_hln != ETH_ALEN)
return NF_ACCEPT;
- /* we only want to mangle arp replies */
- if (arp->ar_op != htons(ARPOP_REPLY))
+ /* we only want to mangle arp requests and replies */
+ if (arp->ar_op != htons(ARPOP_REPLY)
+ && arp->ar_op != htons(ARPOP_REQUEST))
return NF_ACCEPT;
payload = (void *)(arp+1);
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 80cf633d9f4a..d675ff80b04d 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -54,6 +54,7 @@
* Marc Boucher : routing by fwmark
* Robert Olsson : Added rt_cache statistics
* Arnaldo C. Melo : Convert proc stuff to seq_file
+ * Eric Dumazet : hashed spinlocks and rt_check_expire() fixes.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -70,6 +71,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
+#include <linux/bootmem.h>
#include <linux/string.h>
#include <linux/socket.h>
#include <linux/sockios.h>
@@ -201,8 +203,37 @@ __u8 ip_tos2prio[16] = {
struct rt_hash_bucket {
struct rtable *chain;
- spinlock_t lock;
-} __attribute__((__aligned__(8)));
+};
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
+/*
+ * Instead of using one spinlock for each rt_hash_bucket, we use a table of spinlocks
+ * The size of this table is a power of two and depends on the number of CPUS.
+ */
+#if NR_CPUS >= 32
+#define RT_HASH_LOCK_SZ 4096
+#elif NR_CPUS >= 16
+#define RT_HASH_LOCK_SZ 2048
+#elif NR_CPUS >= 8
+#define RT_HASH_LOCK_SZ 1024
+#elif NR_CPUS >= 4
+#define RT_HASH_LOCK_SZ 512
+#else
+#define RT_HASH_LOCK_SZ 256
+#endif
+
+static spinlock_t *rt_hash_locks;
+# define rt_hash_lock_addr(slot) &rt_hash_locks[(slot) & (RT_HASH_LOCK_SZ - 1)]
+# define rt_hash_lock_init() { \
+ int i; \
+ rt_hash_locks = kmalloc(sizeof(spinlock_t) * RT_HASH_LOCK_SZ, GFP_KERNEL); \
+ if (!rt_hash_locks) panic("IP: failed to allocate rt_hash_locks\n"); \
+ for (i = 0; i < RT_HASH_LOCK_SZ; i++) \
+ spin_lock_init(&rt_hash_locks[i]); \
+ }
+#else
+# define rt_hash_lock_addr(slot) NULL
+# define rt_hash_lock_init()
+#endif
static struct rt_hash_bucket *rt_hash_table;
static unsigned rt_hash_mask;
@@ -575,19 +606,26 @@ static struct rtable **rt_remove_balanced_route(struct rtable **chain_head,
/* This runs via a timer and thus is always in BH context. */
static void rt_check_expire(unsigned long dummy)
{
- static int rover;
- int i = rover, t;
+ static unsigned int rover;
+ unsigned int i = rover, goal;
struct rtable *rth, **rthp;
unsigned long now = jiffies;
-
- for (t = ip_rt_gc_interval << rt_hash_log; t >= 0;
- t -= ip_rt_gc_timeout) {
+ u64 mult;
+
+ mult = ((u64)ip_rt_gc_interval) << rt_hash_log;
+ if (ip_rt_gc_timeout > 1)
+ do_div(mult, ip_rt_gc_timeout);
+ goal = (unsigned int)mult;
+ if (goal > rt_hash_mask) goal = rt_hash_mask + 1;
+ for (; goal > 0; goal--) {
unsigned long tmo = ip_rt_gc_timeout;
i = (i + 1) & rt_hash_mask;
rthp = &rt_hash_table[i].chain;
- spin_lock(&rt_hash_table[i].lock);
+ if (*rthp == 0)
+ continue;
+ spin_lock(rt_hash_lock_addr(i));
while ((rth = *rthp) != NULL) {
if (rth->u.dst.expires) {
/* Entry is expired even if it is in use */
@@ -620,14 +658,14 @@ static void rt_check_expire(unsigned long dummy)
rt_free(rth);
#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
}
- spin_unlock(&rt_hash_table[i].lock);
+ spin_unlock(rt_hash_lock_addr(i));
/* Fallback loop breaker. */
if (time_after(jiffies, now))
break;
}
rover = i;
- mod_timer(&rt_periodic_timer, now + ip_rt_gc_interval);
+ mod_timer(&rt_periodic_timer, jiffies + ip_rt_gc_interval);
}
/* This can run from both BH and non-BH contexts, the latter
@@ -643,11 +681,11 @@ static void rt_run_flush(unsigned long dummy)
get_random_bytes(&rt_hash_rnd, 4);
for (i = rt_hash_mask; i >= 0; i--) {
- spin_lock_bh(&rt_hash_table[i].lock);
+ spin_lock_bh(rt_hash_lock_addr(i));
rth = rt_hash_table[i].chain;
if (rth)
rt_hash_table[i].chain = NULL;
- spin_unlock_bh(&rt_hash_table[i].lock);
+ spin_unlock_bh(rt_hash_lock_addr(i));
for (; rth; rth = next) {
next = rth->u.rt_next;
@@ -780,7 +818,7 @@ static int rt_garbage_collect(void)
k = (k + 1) & rt_hash_mask;
rthp = &rt_hash_table[k].chain;
- spin_lock_bh(&rt_hash_table[k].lock);
+ spin_lock_bh(rt_hash_lock_addr(k));
while ((rth = *rthp) != NULL) {
if (!rt_may_expire(rth, tmo, expire)) {
tmo >>= 1;
@@ -812,7 +850,7 @@ static int rt_garbage_collect(void)
goal--;
#endif /* CONFIG_IP_ROUTE_MULTIPATH_CACHED */
}
- spin_unlock_bh(&rt_hash_table[k].lock);
+ spin_unlock_bh(rt_hash_lock_addr(k));
if (goal <= 0)
break;
}
@@ -882,7 +920,7 @@ restart:
rthp = &rt_hash_table[hash].chain;
- spin_lock_bh(&rt_hash_table[hash].lock);
+ spin_lock_bh(rt_hash_lock_addr(hash));
while ((rth = *rthp) != NULL) {
#ifdef CONFIG_IP_ROUTE_MULTIPATH_CACHED
if (!(rth->u.dst.flags & DST_BALANCED) &&
@@ -908,7 +946,7 @@ restart:
rth->u.dst.__use++;
dst_hold(&rth->u.dst);
rth->u.dst.lastuse = now;
- spin_unlock_bh(&rt_hash_table[hash].lock);
+ spin_unlock_bh(rt_hash_lock_addr(hash));
rt_drop(rt);
*rp = rth;
@@ -949,7 +987,7 @@ restart:
if (rt->rt_type == RTN_UNICAST || rt->fl.iif == 0) {
int err = arp_bind_neighbour(&rt->u.dst);
if (err) {
- spin_unlock_bh(&rt_hash_table[hash].lock);
+ spin_unlock_bh(rt_hash_lock_addr(hash));
if (err != -ENOBUFS) {
rt_drop(rt);
@@ -990,7 +1028,7 @@ restart:
}
#endif
rt_hash_table[hash].chain = rt;
- spin_unlock_bh(&rt_hash_table[hash].lock);
+ spin_unlock_bh(rt_hash_lock_addr(hash));
*rp = rt;
return 0;
}
@@ -1058,7 +1096,7 @@ static void rt_del(unsigned hash, struct rtable *rt)
{
struct rtable **rthp;
- spin_lock_bh(&rt_hash_table[hash].lock);
+ spin_lock_bh(rt_hash_lock_addr(hash));
ip_rt_put(rt);
for (rthp = &rt_hash_table[hash].chain; *rthp;
rthp = &(*rthp)->u.rt_next)
@@ -1067,7 +1105,7 @@ static void rt_del(unsigned hash, struct rtable *rt)
rt_free(rt);
break;
}
- spin_unlock_bh(&rt_hash_table[hash].lock);
+ spin_unlock_bh(rt_hash_lock_addr(hash));
}
void ip_rt_redirect(u32 old_gw, u32 daddr, u32 new_gw,
@@ -1647,7 +1685,7 @@ static void ip_handle_martian_source(struct net_device *dev,
printk(KERN_WARNING "martian source %u.%u.%u.%u from "
"%u.%u.%u.%u, on dev %s\n",
NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
- if (dev->hard_header_len) {
+ if (dev->hard_header_len && skb->mac.raw) {
int i;
unsigned char *p = skb->mac.raw;
printk(KERN_WARNING "ll header: ");
@@ -1909,7 +1947,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
*/
if ((err = fib_lookup(&fl, &res)) != 0) {
if (!IN_DEV_FORWARD(in_dev))
- goto e_inval;
+ goto e_hostunreach;
goto no_route;
}
free_res = 1;
@@ -1933,7 +1971,7 @@ static int ip_route_input_slow(struct sk_buff *skb, u32 daddr, u32 saddr,
}
if (!IN_DEV_FORWARD(in_dev))
- goto e_inval;
+ goto e_hostunreach;
if (res.type != RTN_UNICAST)
goto martian_destination;
@@ -2025,6 +2063,11 @@ martian_destination:
"%u.%u.%u.%u, dev %s\n",
NIPQUAD(daddr), NIPQUAD(saddr), dev->name);
#endif
+
+e_hostunreach:
+ err = -EHOSTUNREACH;
+ goto done;
+
e_inval:
err = -EINVAL;
goto done;
@@ -3068,12 +3111,14 @@ __setup("rhash_entries=", set_rhash_entries);
int __init ip_rt_init(void)
{
- int i, order, goal, rc = 0;
+ int rc = 0;
rt_hash_rnd = (int) ((num_physpages ^ (num_physpages>>8)) ^
(jiffies ^ (jiffies >> 7)));
#ifdef CONFIG_NET_CLS_ROUTE
+ {
+ int order;
for (order = 0;
(PAGE_SIZE << order) < 256 * sizeof(struct ip_rt_acct) * NR_CPUS; order++)
/* NOTHING */;
@@ -3081,6 +3126,7 @@ int __init ip_rt_init(void)
if (!ip_rt_acct)
panic("IP: failed to allocate ip_rt_acct\n");
memset(ip_rt_acct, 0, PAGE_SIZE << order);
+ }
#endif
ipv4_dst_ops.kmem_cachep = kmem_cache_create("ip_dst_cache",
@@ -3091,36 +3137,19 @@ int __init ip_rt_init(void)
if (!ipv4_dst_ops.kmem_cachep)
panic("IP: failed to allocate ip_dst_cache\n");
- goal = num_physpages >> (26 - PAGE_SHIFT);
- if (rhash_entries)
- goal = (rhash_entries * sizeof(struct rt_hash_bucket)) >> PAGE_SHIFT;
- for (order = 0; (1UL << order) < goal; order++)
- /* NOTHING */;
-
- do {
- rt_hash_mask = (1UL << order) * PAGE_SIZE /
- sizeof(struct rt_hash_bucket);
- while (rt_hash_mask & (rt_hash_mask - 1))
- rt_hash_mask--;
- rt_hash_table = (struct rt_hash_bucket *)
- __get_free_pages(GFP_ATOMIC, order);
- } while (rt_hash_table == NULL && --order > 0);
-
- if (!rt_hash_table)
- panic("Failed to allocate IP route cache hash table\n");
-
- printk(KERN_INFO "IP: routing cache hash table of %u buckets, %ldKbytes\n",
- rt_hash_mask,
- (long) (rt_hash_mask * sizeof(struct rt_hash_bucket)) / 1024);
-
- for (rt_hash_log = 0; (1 << rt_hash_log) != rt_hash_mask; rt_hash_log++)
- /* NOTHING */;
-
- rt_hash_mask--;
- for (i = 0; i <= rt_hash_mask; i++) {
- spin_lock_init(&rt_hash_table[i].lock);
- rt_hash_table[i].chain = NULL;
- }
+ rt_hash_table = (struct rt_hash_bucket *)
+ alloc_large_system_hash("IP route cache",
+ sizeof(struct rt_hash_bucket),
+ rhash_entries,
+ (num_physpages >= 128 * 1024) ?
+ (27 - PAGE_SHIFT) :
+ (29 - PAGE_SHIFT),
+ HASH_HIGHMEM,
+ &rt_hash_log,
+ &rt_hash_mask,
+ 0);
+ memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
+ rt_hash_lock_init();
ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1);
ip_rt_max_size = (rt_hash_mask + 1) * 16;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 23068bddbf0b..e32894532416 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -118,6 +118,45 @@ static int ipv4_sysctl_forward_strategy(ctl_table *table,
return 1;
}
+static int proc_tcp_congestion_control(ctl_table *ctl, int write, struct file * filp,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
+{
+ char val[TCP_CA_NAME_MAX];
+ ctl_table tbl = {
+ .data = val,
+ .maxlen = TCP_CA_NAME_MAX,
+ };
+ int ret;
+
+ tcp_get_default_congestion_control(val);
+
+ ret = proc_dostring(&tbl, write, filp, buffer, lenp, ppos);
+ if (write && ret == 0)
+ ret = tcp_set_default_congestion_control(val);
+ return ret;
+}
+
+int sysctl_tcp_congestion_control(ctl_table *table, int __user *name, int nlen,
+ void __user *oldval, size_t __user *oldlenp,
+ void __user *newval, size_t newlen,
+ void **context)
+{
+ char val[TCP_CA_NAME_MAX];
+ ctl_table tbl = {
+ .data = val,
+ .maxlen = TCP_CA_NAME_MAX,
+ };
+ int ret;
+
+ tcp_get_default_congestion_control(val);
+ ret = sysctl_string(&tbl, name, nlen, oldval, oldlenp, newval, newlen,
+ context);
+ if (ret == 0 && newval && newlen)
+ ret = tcp_set_default_congestion_control(val);
+ return ret;
+}
+
+
ctl_table ipv4_table[] = {
{
.ctl_name = NET_IPV4_TCP_TIMESTAMPS,
@@ -612,70 +651,6 @@ ctl_table ipv4_table[] = {
.proc_handler = &proc_dointvec,
},
{
- .ctl_name = NET_TCP_WESTWOOD,
- .procname = "tcp_westwood",
- .data = &sysctl_tcp_westwood,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_VEGAS,
- .procname = "tcp_vegas_cong_avoid",
- .data = &sysctl_tcp_vegas_cong_avoid,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_VEGAS_ALPHA,
- .procname = "tcp_vegas_alpha",
- .data = &sysctl_tcp_vegas_alpha,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_VEGAS_BETA,
- .procname = "tcp_vegas_beta",
- .data = &sysctl_tcp_vegas_beta,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_VEGAS_GAMMA,
- .procname = "tcp_vegas_gamma",
- .data = &sysctl_tcp_vegas_gamma,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_BIC,
- .procname = "tcp_bic",
- .data = &sysctl_tcp_bic,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_BIC_FAST_CONVERGENCE,
- .procname = "tcp_bic_fast_convergence",
- .data = &sysctl_tcp_bic_fast_convergence,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
- .ctl_name = NET_TCP_BIC_LOW_WINDOW,
- .procname = "tcp_bic_low_window",
- .data = &sysctl_tcp_bic_low_window,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
- {
.ctl_name = NET_TCP_MODERATE_RCVBUF,
.procname = "tcp_moderate_rcvbuf",
.data = &sysctl_tcp_moderate_rcvbuf,
@@ -692,13 +667,14 @@ ctl_table ipv4_table[] = {
.proc_handler = &proc_dointvec,
},
{
- .ctl_name = NET_TCP_BIC_BETA,
- .procname = "tcp_bic_beta",
- .data = &sysctl_tcp_bic_beta,
- .maxlen = sizeof(int),
+ .ctl_name = NET_TCP_CONG_CONTROL,
+ .procname = "tcp_congestion_control",
.mode = 0644,
- .proc_handler = &proc_dointvec,
+ .maxlen = TCP_CA_NAME_MAX,
+ .proc_handler = &proc_tcp_congestion_control,
+ .strategy = &sysctl_tcp_congestion_control,
},
+
{ .ctl_name = 0 }
};
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 674bbd8cfd36..ddb6ce4ecff2 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -615,7 +615,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
size_t psize, int flags)
{
struct tcp_sock *tp = tcp_sk(sk);
- int mss_now;
+ int mss_now, size_goal;
int err;
ssize_t copied;
long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
@@ -628,6 +628,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+ size_goal = tp->xmit_size_goal;
copied = 0;
err = -EPIPE;
@@ -641,7 +642,7 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
int offset = poffset % PAGE_SIZE;
int size = min_t(size_t, psize, PAGE_SIZE - offset);
- if (!sk->sk_send_head || (copy = mss_now - skb->len) <= 0) {
+ if (!sk->sk_send_head || (copy = size_goal - skb->len) <= 0) {
new_segment:
if (!sk_stream_memory_free(sk))
goto wait_for_sndbuf;
@@ -652,7 +653,7 @@ new_segment:
goto wait_for_memory;
skb_entail(sk, tp, skb);
- copy = mss_now;
+ copy = size_goal;
}
if (copy > size)
@@ -693,7 +694,7 @@ new_segment:
if (!(psize -= copy))
goto out;
- if (skb->len != mss_now || (flags & MSG_OOB))
+ if (skb->len < mss_now || (flags & MSG_OOB))
continue;
if (forced_push(tp)) {
@@ -713,6 +714,7 @@ wait_for_memory:
goto do_error;
mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+ size_goal = tp->xmit_size_goal;
}
out:
@@ -754,15 +756,20 @@ ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset,
static inline int select_size(struct sock *sk, struct tcp_sock *tp)
{
- int tmp = tp->mss_cache_std;
+ int tmp = tp->mss_cache;
if (sk->sk_route_caps & NETIF_F_SG) {
- int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
+ if (sk->sk_route_caps & NETIF_F_TSO)
+ tmp = 0;
+ else {
+ int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER);
- if (tmp >= pgbreak &&
- tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE)
- tmp = pgbreak;
+ if (tmp >= pgbreak &&
+ tmp <= pgbreak + (MAX_SKB_FRAGS - 1) * PAGE_SIZE)
+ tmp = pgbreak;
+ }
}
+
return tmp;
}
@@ -773,7 +780,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
int iovlen, flags;
- int mss_now;
+ int mss_now, size_goal;
int err, copied;
long timeo;
@@ -792,6 +799,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+ size_goal = tp->xmit_size_goal;
/* Ok commence sending. */
iovlen = msg->msg_iovlen;
@@ -814,7 +822,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
skb = sk->sk_write_queue.prev;
if (!sk->sk_send_head ||
- (copy = mss_now - skb->len) <= 0) {
+ (copy = size_goal - skb->len) <= 0) {
new_segment:
/* Allocate new segment. If the interface is SG,
@@ -837,7 +845,7 @@ new_segment:
skb->ip_summed = CHECKSUM_HW;
skb_entail(sk, tp, skb);
- copy = mss_now;
+ copy = size_goal;
}
/* Try to append data to the end of skb. */
@@ -872,11 +880,6 @@ new_segment:
tcp_mark_push(tp, skb);
goto new_segment;
} else if (page) {
- /* If page is cached, align
- * offset to L1 cache boundary
- */
- off = (off + L1_CACHE_BYTES - 1) &
- ~(L1_CACHE_BYTES - 1);
if (off == PAGE_SIZE) {
put_page(page);
TCP_PAGE(sk) = page = NULL;
@@ -937,7 +940,7 @@ new_segment:
if ((seglen -= copy) == 0 && iovlen == 0)
goto out;
- if (skb->len != mss_now || (flags & MSG_OOB))
+ if (skb->len < mss_now || (flags & MSG_OOB))
continue;
if (forced_push(tp)) {
@@ -957,6 +960,7 @@ wait_for_memory:
goto do_error;
mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
+ size_goal = tp->xmit_size_goal;
}
}
@@ -1101,7 +1105,7 @@ static void tcp_prequeue_process(struct sock *sk)
struct sk_buff *skb;
struct tcp_sock *tp = tcp_sk(sk);
- NET_ADD_STATS_USER(LINUX_MIB_TCPPREQUEUED, skb_queue_len(&tp->ucopy.prequeue));
+ NET_INC_STATS_USER(LINUX_MIB_TCPPREQUEUED);
/* RX process wants to run with disabled BHs, though it is not
* necessary */
@@ -1365,7 +1369,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
* is not empty. It is more elegant, but eats cycles,
* unfortunately.
*/
- if (skb_queue_len(&tp->ucopy.prequeue))
+ if (!skb_queue_empty(&tp->ucopy.prequeue))
goto do_prequeue;
/* __ Set realtime policy in scheduler __ */
@@ -1390,7 +1394,7 @@ int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
}
if (tp->rcv_nxt == tp->copied_seq &&
- skb_queue_len(&tp->ucopy.prequeue)) {
+ !skb_queue_empty(&tp->ucopy.prequeue)) {
do_prequeue:
tcp_prequeue_process(sk);
@@ -1472,7 +1476,7 @@ skip_copy:
} while (len > 0);
if (user_recv) {
- if (skb_queue_len(&tp->ucopy.prequeue)) {
+ if (!skb_queue_empty(&tp->ucopy.prequeue)) {
int chunk;
tp->ucopy.len = copied > 0 ? len : 0;
@@ -1927,6 +1931,25 @@ int tcp_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
return tp->af_specific->setsockopt(sk, level, optname,
optval, optlen);
+ /* This is a string value all the others are int's */
+ if (optname == TCP_CONGESTION) {
+ char name[TCP_CA_NAME_MAX];
+
+ if (optlen < 1)
+ return -EINVAL;
+
+ val = strncpy_from_user(name, optval,
+ min(TCP_CA_NAME_MAX-1, optlen));
+ if (val < 0)
+ return -EFAULT;
+ name[val] = 0;
+
+ lock_sock(sk);
+ err = tcp_set_congestion_control(tp, name);
+ release_sock(sk);
+ return err;
+ }
+
if (optlen < sizeof(int))
return -EINVAL;
@@ -2109,7 +2132,7 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info)
info->tcpi_rto = jiffies_to_usecs(tp->rto);
info->tcpi_ato = jiffies_to_usecs(tp->ack.ato);
- info->tcpi_snd_mss = tp->mss_cache_std;
+ info->tcpi_snd_mss = tp->mss_cache;
info->tcpi_rcv_mss = tp->ack.rcv_mss;
info->tcpi_unacked = tp->packets_out;
@@ -2159,7 +2182,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
switch (optname) {
case TCP_MAXSEG:
- val = tp->mss_cache_std;
+ val = tp->mss_cache;
if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)))
val = tp->rx_opt.user_mss;
break;
@@ -2211,6 +2234,16 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
case TCP_QUICKACK:
val = !tp->ack.pingpong;
break;
+
+ case TCP_CONGESTION:
+ if (get_user(len, optlen))
+ return -EFAULT;
+ len = min_t(unsigned int, len, TCP_CA_NAME_MAX);
+ if (put_user(len, optlen))
+ return -EFAULT;
+ if (copy_to_user(optval, tp->ca_ops->name, len))
+ return -EFAULT;
+ return 0;
default:
return -ENOPROTOOPT;
};
@@ -2224,7 +2257,7 @@ int tcp_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
extern void __skb_cb_too_small_for_tcp(int, int);
-extern void tcpdiag_init(void);
+extern struct tcp_congestion_ops tcp_reno;
static __initdata unsigned long thash_entries;
static int __init set_thash_entries(char *str)
@@ -2333,6 +2366,8 @@ void __init tcp_init(void)
printk(KERN_INFO "TCP: Hash tables configured "
"(established %d bind %d)\n",
tcp_ehash_size << 1, tcp_bhash_size);
+
+ tcp_register_congestion_control(&tcp_reno);
}
EXPORT_SYMBOL(tcp_accept);
diff --git a/net/ipv4/tcp_bic.c b/net/ipv4/tcp_bic.c
new file mode 100644
index 000000000000..ec38d45d6649
--- /dev/null
+++ b/net/ipv4/tcp_bic.c
@@ -0,0 +1,331 @@
+/*
+ * Binary Increase Congestion control for TCP
+ *
+ * This is from the implementation of BICTCP in
+ * Lison-Xu, Kahaled Harfoush, and Injong Rhee.
+ * "Binary Increase Congestion Control for Fast, Long Distance
+ * Networks" in InfoComm 2004
+ * Available from:
+ * http://www.csc.ncsu.edu/faculty/rhee/export/bitcp.pdf
+ *
+ * Unless BIC is enabled and congestion window is large
+ * this behaves the same as the original Reno.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <net/tcp.h>
+
+
+#define BICTCP_BETA_SCALE 1024 /* Scale factor beta calculation
+ * max_cwnd = snd_cwnd * beta
+ */
+#define BICTCP_B 4 /*
+ * In binary search,
+ * go to point (max+min)/N
+ */
+
+static int fast_convergence = 1;
+static int max_increment = 32;
+static int low_window = 14;
+static int beta = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */
+static int low_utilization_threshold = 153;
+static int low_utilization_period = 2;
+static int initial_ssthresh = 100;
+static int smooth_part = 20;
+
+module_param(fast_convergence, int, 0644);
+MODULE_PARM_DESC(fast_convergence, "turn on/off fast convergence");
+module_param(max_increment, int, 0644);
+MODULE_PARM_DESC(max_increment, "Limit on increment allowed during binary search");
+module_param(low_window, int, 0644);
+MODULE_PARM_DESC(low_window, "lower bound on congestion window (for TCP friendliness)");
+module_param(beta, int, 0644);
+MODULE_PARM_DESC(beta, "beta for multiplicative increase");
+module_param(low_utilization_threshold, int, 0644);
+MODULE_PARM_DESC(low_utilization_threshold, "percent (scaled by 1024) for low utilization mode");
+module_param(low_utilization_period, int, 0644);
+MODULE_PARM_DESC(low_utilization_period, "if average delay exceeds then goto to low utilization mode (seconds)");
+module_param(initial_ssthresh, int, 0644);
+MODULE_PARM_DESC(initial_ssthresh, "initial value of slow start threshold");
+module_param(smooth_part, int, 0644);
+MODULE_PARM_DESC(smooth_part, "log(B/(B*Smin))/log(B/(B-1))+B, # of RTT from Wmax-B to Wmax");
+
+
+/* BIC TCP Parameters */
+struct bictcp {
+ u32 cnt; /* increase cwnd by 1 after ACKs */
+ u32 last_max_cwnd; /* last maximum snd_cwnd */
+ u32 loss_cwnd; /* congestion window at last loss */
+ u32 last_cwnd; /* the last snd_cwnd */
+ u32 last_time; /* time when updated last_cwnd */
+ u32 delay_min; /* min delay */
+ u32 delay_max; /* max delay */
+ u32 last_delay;
+ u8 low_utilization;/* 0: high; 1: low */
+ u32 low_utilization_start; /* starting time of low utilization detection*/
+ u32 epoch_start; /* beginning of an epoch */
+#define ACK_RATIO_SHIFT 4
+ u32 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */
+};
+
+static inline void bictcp_reset(struct bictcp *ca)
+{
+ ca->cnt = 0;
+ ca->last_max_cwnd = 0;
+ ca->loss_cwnd = 0;
+ ca->last_cwnd = 0;
+ ca->last_time = 0;
+ ca->delay_min = 0;
+ ca->delay_max = 0;
+ ca->last_delay = 0;
+ ca->low_utilization = 0;
+ ca->low_utilization_start = 0;
+ ca->epoch_start = 0;
+ ca->delayed_ack = 2 << ACK_RATIO_SHIFT;
+}
+
+static void bictcp_init(struct tcp_sock *tp)
+{
+ bictcp_reset(tcp_ca(tp));
+ if (initial_ssthresh)
+ tp->snd_ssthresh = initial_ssthresh;
+}
+
+/*
+ * Compute congestion window to use.
+ */
+static inline void bictcp_update(struct bictcp *ca, u32 cwnd)
+{
+ if (ca->last_cwnd == cwnd &&
+ (s32)(tcp_time_stamp - ca->last_time) <= HZ / 32)
+ return;
+
+ ca->last_cwnd = cwnd;
+ ca->last_time = tcp_time_stamp;
+
+ if (ca->epoch_start == 0) /* record the beginning of an epoch */
+ ca->epoch_start = tcp_time_stamp;
+
+ /* start off normal */
+ if (cwnd <= low_window) {
+ ca->cnt = cwnd;
+ return;
+ }
+
+ /* binary increase */
+ if (cwnd < ca->last_max_cwnd) {
+ __u32 dist = (ca->last_max_cwnd - cwnd)
+ / BICTCP_B;
+
+ if (dist > max_increment)
+ /* linear increase */
+ ca->cnt = cwnd / max_increment;
+ else if (dist <= 1U)
+ /* binary search increase */
+ ca->cnt = (cwnd * smooth_part) / BICTCP_B;
+ else
+ /* binary search increase */
+ ca->cnt = cwnd / dist;
+ } else {
+ /* slow start AMD linear increase */
+ if (cwnd < ca->last_max_cwnd + BICTCP_B)
+ /* slow start */
+ ca->cnt = (cwnd * smooth_part) / BICTCP_B;
+ else if (cwnd < ca->last_max_cwnd + max_increment*(BICTCP_B-1))
+ /* slow start */
+ ca->cnt = (cwnd * (BICTCP_B-1))
+ / cwnd-ca->last_max_cwnd;
+ else
+ /* linear increase */
+ ca->cnt = cwnd / max_increment;
+ }
+
+ /* if in slow start or link utilization is very low */
+ if ( ca->loss_cwnd == 0 ||
+ (cwnd > ca->loss_cwnd && ca->low_utilization)) {
+ if (ca->cnt > 20) /* increase cwnd 5% per RTT */
+ ca->cnt = 20;
+ }
+
+ ca->cnt = (ca->cnt << ACK_RATIO_SHIFT) / ca->delayed_ack;
+ if (ca->cnt == 0) /* cannot be zero */
+ ca->cnt = 1;
+}
+
+
+/* Detect low utilization in congestion avoidance */
+static inline void bictcp_low_utilization(struct tcp_sock *tp, int flag)
+{
+ struct bictcp *ca = tcp_ca(tp);
+ u32 dist, delay;
+
+ /* No time stamp */
+ if (!(tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr) ||
+ /* Discard delay samples right after fast recovery */
+ tcp_time_stamp < ca->epoch_start + HZ ||
+ /* this delay samples may not be accurate */
+ flag == 0) {
+ ca->last_delay = 0;
+ goto notlow;
+ }
+
+ delay = ca->last_delay<<3; /* use the same scale as tp->srtt*/
+ ca->last_delay = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
+ if (delay == 0) /* no previous delay sample */
+ goto notlow;
+
+ /* first time call or link delay decreases */
+ if (ca->delay_min == 0 || ca->delay_min > delay) {
+ ca->delay_min = ca->delay_max = delay;
+ goto notlow;
+ }
+
+ if (ca->delay_max < delay)
+ ca->delay_max = delay;
+
+ /* utilization is low, if avg delay < dist*threshold
+ for checking_period time */
+ dist = ca->delay_max - ca->delay_min;
+ if (dist <= ca->delay_min>>6 ||
+ tp->srtt - ca->delay_min >= (dist*low_utilization_threshold)>>10)
+ goto notlow;
+
+ if (ca->low_utilization_start == 0) {
+ ca->low_utilization = 0;
+ ca->low_utilization_start = tcp_time_stamp;
+ } else if ((s32)(tcp_time_stamp - ca->low_utilization_start)
+ > low_utilization_period*HZ) {
+ ca->low_utilization = 1;
+ }
+
+ return;
+
+ notlow:
+ ca->low_utilization = 0;
+ ca->low_utilization_start = 0;
+
+}
+
+static void bictcp_cong_avoid(struct tcp_sock *tp, u32 ack,
+ u32 seq_rtt, u32 in_flight, int data_acked)
+{
+ struct bictcp *ca = tcp_ca(tp);
+
+ bictcp_low_utilization(tp, data_acked);
+
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ /* In "safe" area, increase. */
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ } else {
+ bictcp_update(ca, tp->snd_cwnd);
+
+ /* In dangerous area, increase slowly.
+ * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
+ */
+ if (tp->snd_cwnd_cnt >= ca->cnt) {
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt = 0;
+ } else
+ tp->snd_cwnd_cnt++;
+ }
+
+}
+
+/*
+ * behave like Reno until low_window is reached,
+ * then increase congestion window slowly
+ */
+static u32 bictcp_recalc_ssthresh(struct tcp_sock *tp)
+{
+ struct bictcp *ca = tcp_ca(tp);
+
+ ca->epoch_start = 0; /* end of epoch */
+
+ /* in case of wrong delay_max*/
+ if (ca->delay_min > 0 && ca->delay_max > ca->delay_min)
+ ca->delay_max = ca->delay_min
+ + ((ca->delay_max - ca->delay_min)* 90) / 100;
+
+ /* Wmax and fast convergence */
+ if (tp->snd_cwnd < ca->last_max_cwnd && fast_convergence)
+ ca->last_max_cwnd = (tp->snd_cwnd * (BICTCP_BETA_SCALE + beta))
+ / (2 * BICTCP_BETA_SCALE);
+ else
+ ca->last_max_cwnd = tp->snd_cwnd;
+
+ ca->loss_cwnd = tp->snd_cwnd;
+
+
+ if (tp->snd_cwnd <= low_window)
+ return max(tp->snd_cwnd >> 1U, 2U);
+ else
+ return max((tp->snd_cwnd * beta) / BICTCP_BETA_SCALE, 2U);
+}
+
+static u32 bictcp_undo_cwnd(struct tcp_sock *tp)
+{
+ struct bictcp *ca = tcp_ca(tp);
+
+ return max(tp->snd_cwnd, ca->last_max_cwnd);
+}
+
+static u32 bictcp_min_cwnd(struct tcp_sock *tp)
+{
+ return tp->snd_ssthresh;
+}
+
+static void bictcp_state(struct tcp_sock *tp, u8 new_state)
+{
+ if (new_state == TCP_CA_Loss)
+ bictcp_reset(tcp_ca(tp));
+}
+
+/* Track delayed acknowledgement ratio using sliding window
+ * ratio = (15*ratio + sample) / 16
+ */
+static void bictcp_acked(struct tcp_sock *tp, u32 cnt)
+{
+ if (cnt > 0 && tp->ca_state == TCP_CA_Open) {
+ struct bictcp *ca = tcp_ca(tp);
+ cnt -= ca->delayed_ack >> ACK_RATIO_SHIFT;
+ ca->delayed_ack += cnt;
+ }
+}
+
+
+static struct tcp_congestion_ops bictcp = {
+ .init = bictcp_init,
+ .ssthresh = bictcp_recalc_ssthresh,
+ .cong_avoid = bictcp_cong_avoid,
+ .set_state = bictcp_state,
+ .undo_cwnd = bictcp_undo_cwnd,
+ .min_cwnd = bictcp_min_cwnd,
+ .pkts_acked = bictcp_acked,
+ .owner = THIS_MODULE,
+ .name = "bic",
+};
+
+static int __init bictcp_register(void)
+{
+ BUG_ON(sizeof(struct bictcp) > TCP_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&bictcp);
+}
+
+static void __exit bictcp_unregister(void)
+{
+ tcp_unregister_congestion_control(&bictcp);
+}
+
+module_init(bictcp_register);
+module_exit(bictcp_unregister);
+
+MODULE_AUTHOR("Stephen Hemminger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("BIC TCP");
diff --git a/net/ipv4/tcp_cong.c b/net/ipv4/tcp_cong.c
new file mode 100644
index 000000000000..4970d10a7785
--- /dev/null
+++ b/net/ipv4/tcp_cong.c
@@ -0,0 +1,237 @@
+/*
+ * Plugable TCP congestion control support and newReno
+ * congestion control.
+ * Based on ideas from I/O scheduler suport and Web100.
+ *
+ * Copyright (C) 2005 Stephen Hemminger <shemminger@osdl.org>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <net/tcp.h>
+
+static DEFINE_SPINLOCK(tcp_cong_list_lock);
+static LIST_HEAD(tcp_cong_list);
+
+/* Simple linear search, don't expect many entries! */
+static struct tcp_congestion_ops *tcp_ca_find(const char *name)
+{
+ struct tcp_congestion_ops *e;
+
+ list_for_each_entry_rcu(e, &tcp_cong_list, list) {
+ if (strcmp(e->name, name) == 0)
+ return e;
+ }
+
+ return NULL;
+}
+
+/*
+ * Attach new congestion control algorthim to the list
+ * of available options.
+ */
+int tcp_register_congestion_control(struct tcp_congestion_ops *ca)
+{
+ int ret = 0;
+
+ /* all algorithms must implement ssthresh and cong_avoid ops */
+ if (!ca->ssthresh || !ca->cong_avoid || !ca->min_cwnd) {
+ printk(KERN_ERR "TCP %s does not implement required ops\n",
+ ca->name);
+ return -EINVAL;
+ }
+
+ spin_lock(&tcp_cong_list_lock);
+ if (tcp_ca_find(ca->name)) {
+ printk(KERN_NOTICE "TCP %s already registered\n", ca->name);
+ ret = -EEXIST;
+ } else {
+ list_add_rcu(&ca->list, &tcp_cong_list);
+ printk(KERN_INFO "TCP %s registered\n", ca->name);
+ }
+ spin_unlock(&tcp_cong_list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(tcp_register_congestion_control);
+
+/*
+ * Remove congestion control algorithm, called from
+ * the module's remove function. Module ref counts are used
+ * to ensure that this can't be done till all sockets using
+ * that method are closed.
+ */
+void tcp_unregister_congestion_control(struct tcp_congestion_ops *ca)
+{
+ spin_lock(&tcp_cong_list_lock);
+ list_del_rcu(&ca->list);
+ spin_unlock(&tcp_cong_list_lock);
+}
+EXPORT_SYMBOL_GPL(tcp_unregister_congestion_control);
+
+/* Assign choice of congestion control. */
+void tcp_init_congestion_control(struct tcp_sock *tp)
+{
+ struct tcp_congestion_ops *ca;
+
+ if (tp->ca_ops != &tcp_init_congestion_ops)
+ return;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(ca, &tcp_cong_list, list) {
+ if (try_module_get(ca->owner)) {
+ tp->ca_ops = ca;
+ break;
+ }
+
+ }
+ rcu_read_unlock();
+
+ if (tp->ca_ops->init)
+ tp->ca_ops->init(tp);
+}
+
+/* Manage refcounts on socket close. */
+void tcp_cleanup_congestion_control(struct tcp_sock *tp)
+{
+ if (tp->ca_ops->release)
+ tp->ca_ops->release(tp);
+ module_put(tp->ca_ops->owner);
+}
+
+/* Used by sysctl to change default congestion control */
+int tcp_set_default_congestion_control(const char *name)
+{
+ struct tcp_congestion_ops *ca;
+ int ret = -ENOENT;
+
+ spin_lock(&tcp_cong_list_lock);
+ ca = tcp_ca_find(name);
+#ifdef CONFIG_KMOD
+ if (!ca) {
+ spin_unlock(&tcp_cong_list_lock);
+
+ request_module("tcp_%s", name);
+ spin_lock(&tcp_cong_list_lock);
+ ca = tcp_ca_find(name);
+ }
+#endif
+
+ if (ca) {
+ list_move(&ca->list, &tcp_cong_list);
+ ret = 0;
+ }
+ spin_unlock(&tcp_cong_list_lock);
+
+ return ret;
+}
+
+/* Get current default congestion control */
+void tcp_get_default_congestion_control(char *name)
+{
+ struct tcp_congestion_ops *ca;
+ /* We will always have reno... */
+ BUG_ON(list_empty(&tcp_cong_list));
+
+ rcu_read_lock();
+ ca = list_entry(tcp_cong_list.next, struct tcp_congestion_ops, list);
+ strncpy(name, ca->name, TCP_CA_NAME_MAX);
+ rcu_read_unlock();
+}
+
+/* Change congestion control for socket */
+int tcp_set_congestion_control(struct tcp_sock *tp, const char *name)
+{
+ struct tcp_congestion_ops *ca;
+ int err = 0;
+
+ rcu_read_lock();
+ ca = tcp_ca_find(name);
+ if (ca == tp->ca_ops)
+ goto out;
+
+ if (!ca)
+ err = -ENOENT;
+
+ else if (!try_module_get(ca->owner))
+ err = -EBUSY;
+
+ else {
+ tcp_cleanup_congestion_control(tp);
+ tp->ca_ops = ca;
+ if (tp->ca_ops->init)
+ tp->ca_ops->init(tp);
+ }
+ out:
+ rcu_read_unlock();
+ return err;
+}
+
+/*
+ * TCP Reno congestion control
+ * This is special case used for fallback as well.
+ */
+/* This is Jacobson's slow start and congestion avoidance.
+ * SIGCOMM '88, p. 328.
+ */
+void tcp_reno_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt, u32 in_flight,
+ int flag)
+{
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ /* In "safe" area, increase. */
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ } else {
+ /* In dangerous area, increase slowly.
+ * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
+ */
+ if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt = 0;
+ } else
+ tp->snd_cwnd_cnt++;
+ }
+}
+EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
+
+/* Slow start threshold is half the congestion window (min 2) */
+u32 tcp_reno_ssthresh(struct tcp_sock *tp)
+{
+ return max(tp->snd_cwnd >> 1U, 2U);
+}
+EXPORT_SYMBOL_GPL(tcp_reno_ssthresh);
+
+/* Lower bound on congestion window. */
+u32 tcp_reno_min_cwnd(struct tcp_sock *tp)
+{
+ return tp->snd_ssthresh/2;
+}
+EXPORT_SYMBOL_GPL(tcp_reno_min_cwnd);
+
+struct tcp_congestion_ops tcp_reno = {
+ .name = "reno",
+ .owner = THIS_MODULE,
+ .ssthresh = tcp_reno_ssthresh,
+ .cong_avoid = tcp_reno_cong_avoid,
+ .min_cwnd = tcp_reno_min_cwnd,
+};
+
+/* Initial congestion control used (until SYN)
+ * really reno under another name so we can tell difference
+ * during tcp_set_default_congestion_control
+ */
+struct tcp_congestion_ops tcp_init_congestion_ops = {
+ .name = "",
+ .owner = THIS_MODULE,
+ .ssthresh = tcp_reno_ssthresh,
+ .cong_avoid = tcp_reno_cong_avoid,
+ .min_cwnd = tcp_reno_min_cwnd,
+};
+EXPORT_SYMBOL_GPL(tcp_init_congestion_ops);
diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
index 634befc07921..f66945cb158f 100644
--- a/net/ipv4/tcp_diag.c
+++ b/net/ipv4/tcp_diag.c
@@ -42,15 +42,8 @@ struct tcpdiag_entry
static struct sock *tcpnl;
-
#define TCPDIAG_PUT(skb, attrtype, attrlen) \
-({ int rtalen = RTA_LENGTH(attrlen); \
- struct rtattr *rta; \
- if (skb_tailroom(skb) < RTA_ALIGN(rtalen)) goto nlmsg_failure; \
- rta = (void*)__skb_put(skb, RTA_ALIGN(rtalen)); \
- rta->rta_type = attrtype; \
- rta->rta_len = rtalen; \
- RTA_DATA(rta); })
+ RTA_DATA(__RTA_PUT(skb, attrtype, attrlen))
static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
int ext, u32 pid, u32 seq, u16 nlmsg_flags)
@@ -61,7 +54,6 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
struct nlmsghdr *nlh;
struct tcp_info *info = NULL;
struct tcpdiag_meminfo *minfo = NULL;
- struct tcpvegas_info *vinfo = NULL;
unsigned char *b = skb->tail;
nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r));
@@ -73,9 +65,11 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
if (ext & (1<<(TCPDIAG_INFO-1)))
info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info));
- if ((tcp_is_westwood(tp) || tcp_is_vegas(tp))
- && (ext & (1<<(TCPDIAG_VEGASINFO-1))))
- vinfo = TCPDIAG_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*vinfo));
+ if (ext & (1<<(TCPDIAG_CONG-1))) {
+ size_t len = strlen(tp->ca_ops->name);
+ strcpy(TCPDIAG_PUT(skb, TCPDIAG_CONG, len+1),
+ tp->ca_ops->name);
+ }
}
r->tcpdiag_family = sk->sk_family;
r->tcpdiag_state = sk->sk_state;
@@ -166,23 +160,13 @@ static int tcpdiag_fill(struct sk_buff *skb, struct sock *sk,
if (info)
tcp_get_info(sk, info);
- if (vinfo) {
- if (tcp_is_vegas(tp)) {
- vinfo->tcpv_enabled = tp->vegas.doing_vegas_now;
- vinfo->tcpv_rttcnt = tp->vegas.cntRTT;
- vinfo->tcpv_rtt = jiffies_to_usecs(tp->vegas.baseRTT);
- vinfo->tcpv_minrtt = jiffies_to_usecs(tp->vegas.minRTT);
- } else {
- vinfo->tcpv_enabled = 0;
- vinfo->tcpv_rttcnt = 0;
- vinfo->tcpv_rtt = jiffies_to_usecs(tp->westwood.rtt);
- vinfo->tcpv_minrtt = jiffies_to_usecs(tp->westwood.rtt_min);
- }
- }
+ if (sk->sk_state < TCP_TIME_WAIT && tp->ca_ops->get_info)
+ tp->ca_ops->get_info(tp, ext, skb);
nlh->nlmsg_len = skb->tail - b;
return skb->len;
+rtattr_failure:
nlmsg_failure:
skb_trim(skb, b - skb->data);
return -1;
diff --git a/net/ipv4/tcp_highspeed.c b/net/ipv4/tcp_highspeed.c
new file mode 100644
index 000000000000..36c51f8136bf
--- /dev/null
+++ b/net/ipv4/tcp_highspeed.c
@@ -0,0 +1,181 @@
+/*
+ * Sally Floyd's High Speed TCP (RFC 3649) congestion control
+ *
+ * See http://www.icir.org/floyd/hstcp.html
+ *
+ * John Heffner <jheffner@psc.edu>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/tcp.h>
+
+
+/* From AIMD tables from RFC 3649 appendix B,
+ * with fixed-point MD scaled <<8.
+ */
+static const struct hstcp_aimd_val {
+ unsigned int cwnd;
+ unsigned int md;
+} hstcp_aimd_vals[] = {
+ { 38, 128, /* 0.50 */ },
+ { 118, 112, /* 0.44 */ },
+ { 221, 104, /* 0.41 */ },
+ { 347, 98, /* 0.38 */ },
+ { 495, 93, /* 0.37 */ },
+ { 663, 89, /* 0.35 */ },
+ { 851, 86, /* 0.34 */ },
+ { 1058, 83, /* 0.33 */ },
+ { 1284, 81, /* 0.32 */ },
+ { 1529, 78, /* 0.31 */ },
+ { 1793, 76, /* 0.30 */ },
+ { 2076, 74, /* 0.29 */ },
+ { 2378, 72, /* 0.28 */ },
+ { 2699, 71, /* 0.28 */ },
+ { 3039, 69, /* 0.27 */ },
+ { 3399, 68, /* 0.27 */ },
+ { 3778, 66, /* 0.26 */ },
+ { 4177, 65, /* 0.26 */ },
+ { 4596, 64, /* 0.25 */ },
+ { 5036, 62, /* 0.25 */ },
+ { 5497, 61, /* 0.24 */ },
+ { 5979, 60, /* 0.24 */ },
+ { 6483, 59, /* 0.23 */ },
+ { 7009, 58, /* 0.23 */ },
+ { 7558, 57, /* 0.22 */ },
+ { 8130, 56, /* 0.22 */ },
+ { 8726, 55, /* 0.22 */ },
+ { 9346, 54, /* 0.21 */ },
+ { 9991, 53, /* 0.21 */ },
+ { 10661, 52, /* 0.21 */ },
+ { 11358, 52, /* 0.20 */ },
+ { 12082, 51, /* 0.20 */ },
+ { 12834, 50, /* 0.20 */ },
+ { 13614, 49, /* 0.19 */ },
+ { 14424, 48, /* 0.19 */ },
+ { 15265, 48, /* 0.19 */ },
+ { 16137, 47, /* 0.19 */ },
+ { 17042, 46, /* 0.18 */ },
+ { 17981, 45, /* 0.18 */ },
+ { 18955, 45, /* 0.18 */ },
+ { 19965, 44, /* 0.17 */ },
+ { 21013, 43, /* 0.17 */ },
+ { 22101, 43, /* 0.17 */ },
+ { 23230, 42, /* 0.17 */ },
+ { 24402, 41, /* 0.16 */ },
+ { 25618, 41, /* 0.16 */ },
+ { 26881, 40, /* 0.16 */ },
+ { 28193, 39, /* 0.16 */ },
+ { 29557, 39, /* 0.15 */ },
+ { 30975, 38, /* 0.15 */ },
+ { 32450, 38, /* 0.15 */ },
+ { 33986, 37, /* 0.15 */ },
+ { 35586, 36, /* 0.14 */ },
+ { 37253, 36, /* 0.14 */ },
+ { 38992, 35, /* 0.14 */ },
+ { 40808, 35, /* 0.14 */ },
+ { 42707, 34, /* 0.13 */ },
+ { 44694, 33, /* 0.13 */ },
+ { 46776, 33, /* 0.13 */ },
+ { 48961, 32, /* 0.13 */ },
+ { 51258, 32, /* 0.13 */ },
+ { 53677, 31, /* 0.12 */ },
+ { 56230, 30, /* 0.12 */ },
+ { 58932, 30, /* 0.12 */ },
+ { 61799, 29, /* 0.12 */ },
+ { 64851, 28, /* 0.11 */ },
+ { 68113, 28, /* 0.11 */ },
+ { 71617, 27, /* 0.11 */ },
+ { 75401, 26, /* 0.10 */ },
+ { 79517, 26, /* 0.10 */ },
+ { 84035, 25, /* 0.10 */ },
+ { 89053, 24, /* 0.10 */ },
+};
+
+#define HSTCP_AIMD_MAX ARRAY_SIZE(hstcp_aimd_vals)
+
+struct hstcp {
+ u32 ai;
+};
+
+static void hstcp_init(struct tcp_sock *tp)
+{
+ struct hstcp *ca = tcp_ca(tp);
+
+ ca->ai = 0;
+
+ /* Ensure the MD arithmetic works. This is somewhat pedantic,
+ * since I don't think we will see a cwnd this large. :) */
+ tp->snd_cwnd_clamp = min_t(u32, tp->snd_cwnd_clamp, 0xffffffff/128);
+}
+
+static void hstcp_cong_avoid(struct tcp_sock *tp, u32 adk, u32 rtt,
+ u32 in_flight, int good)
+{
+ struct hstcp *ca = tcp_ca(tp);
+
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ } else {
+ /* Update AIMD parameters */
+ if (tp->snd_cwnd > hstcp_aimd_vals[ca->ai].cwnd) {
+ while (tp->snd_cwnd > hstcp_aimd_vals[ca->ai].cwnd &&
+ ca->ai < HSTCP_AIMD_MAX)
+ ca->ai++;
+ } else if (tp->snd_cwnd < hstcp_aimd_vals[ca->ai].cwnd) {
+ while (tp->snd_cwnd > hstcp_aimd_vals[ca->ai].cwnd &&
+ ca->ai > 0)
+ ca->ai--;
+ }
+
+ /* Do additive increase */
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp) {
+ tp->snd_cwnd_cnt += ca->ai;
+ if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt -= tp->snd_cwnd;
+ }
+ }
+ }
+}
+
+static u32 hstcp_ssthresh(struct tcp_sock *tp)
+{
+ struct hstcp *ca = tcp_ca(tp);
+
+ /* Do multiplicative decrease */
+ return max(tp->snd_cwnd - ((tp->snd_cwnd * hstcp_aimd_vals[ca->ai].md) >> 8), 2U);
+}
+
+
+static struct tcp_congestion_ops tcp_highspeed = {
+ .init = hstcp_init,
+ .ssthresh = hstcp_ssthresh,
+ .cong_avoid = hstcp_cong_avoid,
+ .min_cwnd = tcp_reno_min_cwnd,
+
+ .owner = THIS_MODULE,
+ .name = "highspeed"
+};
+
+static int __init hstcp_register(void)
+{
+ BUG_ON(sizeof(struct hstcp) > TCP_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_highspeed);
+}
+
+static void __exit hstcp_unregister(void)
+{
+ tcp_unregister_congestion_control(&tcp_highspeed);
+}
+
+module_init(hstcp_register);
+module_exit(hstcp_unregister);
+
+MODULE_AUTHOR("John Heffner");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("High Speed TCP");
diff --git a/net/ipv4/tcp_htcp.c b/net/ipv4/tcp_htcp.c
new file mode 100644
index 000000000000..40168275acf9
--- /dev/null
+++ b/net/ipv4/tcp_htcp.c
@@ -0,0 +1,289 @@
+/*
+ * H-TCP congestion control. The algorithm is detailed in:
+ * R.N.Shorten, D.J.Leith:
+ * "H-TCP: TCP for high-speed and long-distance networks"
+ * Proc. PFLDnet, Argonne, 2004.
+ * http://www.hamilton.ie/net/htcp3.pdf
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <net/tcp.h>
+
+#define ALPHA_BASE (1<<7) /* 1.0 with shift << 7 */
+#define BETA_MIN (1<<6) /* 0.5 with shift << 7 */
+#define BETA_MAX 102 /* 0.8 with shift << 7 */
+
+static int use_rtt_scaling = 1;
+module_param(use_rtt_scaling, int, 0644);
+MODULE_PARM_DESC(use_rtt_scaling, "turn on/off RTT scaling");
+
+static int use_bandwidth_switch = 1;
+module_param(use_bandwidth_switch, int, 0644);
+MODULE_PARM_DESC(use_bandwidth_switch, "turn on/off bandwidth switcher");
+
+struct htcp {
+ u16 alpha; /* Fixed point arith, << 7 */
+ u8 beta; /* Fixed point arith, << 7 */
+ u8 modeswitch; /* Delay modeswitch until we had at least one congestion event */
+ u8 ccount; /* Number of RTTs since last congestion event */
+ u8 undo_ccount;
+ u16 packetcount;
+ u32 minRTT;
+ u32 maxRTT;
+ u32 snd_cwnd_cnt2;
+
+ u32 undo_maxRTT;
+ u32 undo_old_maxB;
+
+ /* Bandwidth estimation */
+ u32 minB;
+ u32 maxB;
+ u32 old_maxB;
+ u32 Bi;
+ u32 lasttime;
+};
+
+static inline void htcp_reset(struct htcp *ca)
+{
+ ca->undo_ccount = ca->ccount;
+ ca->undo_maxRTT = ca->maxRTT;
+ ca->undo_old_maxB = ca->old_maxB;
+
+ ca->ccount = 0;
+ ca->snd_cwnd_cnt2 = 0;
+}
+
+static u32 htcp_cwnd_undo(struct tcp_sock *tp)
+{
+ struct htcp *ca = tcp_ca(tp);
+ ca->ccount = ca->undo_ccount;
+ ca->maxRTT = ca->undo_maxRTT;
+ ca->old_maxB = ca->undo_old_maxB;
+ return max(tp->snd_cwnd, (tp->snd_ssthresh<<7)/ca->beta);
+}
+
+static inline void measure_rtt(struct tcp_sock *tp)
+{
+ struct htcp *ca = tcp_ca(tp);
+ u32 srtt = tp->srtt>>3;
+
+ /* keep track of minimum RTT seen so far, minRTT is zero at first */
+ if (ca->minRTT > srtt || !ca->minRTT)
+ ca->minRTT = srtt;
+
+ /* max RTT */
+ if (tp->ca_state == TCP_CA_Open && tp->snd_ssthresh < 0xFFFF && ca->ccount > 3) {
+ if (ca->maxRTT < ca->minRTT)
+ ca->maxRTT = ca->minRTT;
+ if (ca->maxRTT < srtt && srtt <= ca->maxRTT+HZ/50)
+ ca->maxRTT = srtt;
+ }
+}
+
+static void measure_achieved_throughput(struct tcp_sock *tp, u32 pkts_acked)
+{
+ struct htcp *ca = tcp_ca(tp);
+ u32 now = tcp_time_stamp;
+
+ /* achieved throughput calculations */
+ if (tp->ca_state != TCP_CA_Open && tp->ca_state != TCP_CA_Disorder) {
+ ca->packetcount = 0;
+ ca->lasttime = now;
+ return;
+ }
+
+ ca->packetcount += pkts_acked;
+
+ if (ca->packetcount >= tp->snd_cwnd - (ca->alpha>>7? : 1)
+ && now - ca->lasttime >= ca->minRTT
+ && ca->minRTT > 0) {
+ __u32 cur_Bi = ca->packetcount*HZ/(now - ca->lasttime);
+ if (ca->ccount <= 3) {
+ /* just after backoff */
+ ca->minB = ca->maxB = ca->Bi = cur_Bi;
+ } else {
+ ca->Bi = (3*ca->Bi + cur_Bi)/4;
+ if (ca->Bi > ca->maxB)
+ ca->maxB = ca->Bi;
+ if (ca->minB > ca->maxB)
+ ca->minB = ca->maxB;
+ }
+ ca->packetcount = 0;
+ ca->lasttime = now;
+ }
+}
+
+static inline void htcp_beta_update(struct htcp *ca, u32 minRTT, u32 maxRTT)
+{
+ if (use_bandwidth_switch) {
+ u32 maxB = ca->maxB;
+ u32 old_maxB = ca->old_maxB;
+ ca->old_maxB = ca->maxB;
+
+ if (!between(5*maxB, 4*old_maxB, 6*old_maxB)) {
+ ca->beta = BETA_MIN;
+ ca->modeswitch = 0;
+ return;
+ }
+ }
+
+ if (ca->modeswitch && minRTT > max(HZ/100, 1) && maxRTT) {
+ ca->beta = (minRTT<<7)/maxRTT;
+ if (ca->beta < BETA_MIN)
+ ca->beta = BETA_MIN;
+ else if (ca->beta > BETA_MAX)
+ ca->beta = BETA_MAX;
+ } else {
+ ca->beta = BETA_MIN;
+ ca->modeswitch = 1;
+ }
+}
+
+static inline void htcp_alpha_update(struct htcp *ca)
+{
+ u32 minRTT = ca->minRTT;
+ u32 factor = 1;
+ u32 diff = ca->ccount * minRTT; /* time since last backoff */
+
+ if (diff > HZ) {
+ diff -= HZ;
+ factor = 1+ ( 10*diff + ((diff/2)*(diff/2)/HZ) )/HZ;
+ }
+
+ if (use_rtt_scaling && minRTT) {
+ u32 scale = (HZ<<3)/(10*minRTT);
+ scale = min(max(scale, 1U<<2), 10U<<3); /* clamping ratio to interval [0.5,10]<<3 */
+ factor = (factor<<3)/scale;
+ if (!factor)
+ factor = 1;
+ }
+
+ ca->alpha = 2*factor*((1<<7)-ca->beta);
+ if (!ca->alpha)
+ ca->alpha = ALPHA_BASE;
+}
+
+/* After we have the rtt data to calculate beta, we'd still prefer to wait one
+ * rtt before we adjust our beta to ensure we are working from a consistent
+ * data.
+ *
+ * This function should be called when we hit a congestion event since only at
+ * that point do we really have a real sense of maxRTT (the queues en route
+ * were getting just too full now).
+ */
+static void htcp_param_update(struct tcp_sock *tp)
+{
+ struct htcp *ca = tcp_ca(tp);
+ u32 minRTT = ca->minRTT;
+ u32 maxRTT = ca->maxRTT;
+
+ htcp_beta_update(ca, minRTT, maxRTT);
+ htcp_alpha_update(ca);
+
+ /* add slowly fading memory for maxRTT to accommodate routing changes etc */
+ if (minRTT > 0 && maxRTT > minRTT)
+ ca->maxRTT = minRTT + ((maxRTT-minRTT)*95)/100;
+}
+
+static u32 htcp_recalc_ssthresh(struct tcp_sock *tp)
+{
+ struct htcp *ca = tcp_ca(tp);
+ htcp_param_update(tp);
+ return max((tp->snd_cwnd * ca->beta) >> 7, 2U);
+}
+
+static void htcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+ u32 in_flight, int data_acked)
+{
+ struct htcp *ca = tcp_ca(tp);
+
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ /* In "safe" area, increase. */
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ } else {
+ measure_rtt(tp);
+
+ /* keep track of number of round-trip times since last backoff event */
+ if (ca->snd_cwnd_cnt2++ > tp->snd_cwnd) {
+ ca->ccount++;
+ ca->snd_cwnd_cnt2 = 0;
+ htcp_alpha_update(ca);
+ }
+
+ /* In dangerous area, increase slowly.
+ * In theory this is tp->snd_cwnd += alpha / tp->snd_cwnd
+ */
+ if ((tp->snd_cwnd_cnt++ * ca->alpha)>>7 >= tp->snd_cwnd) {
+ if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt = 0;
+ ca->ccount++;
+ }
+ }
+}
+
+/* Lower bound on congestion window. */
+static u32 htcp_min_cwnd(struct tcp_sock *tp)
+{
+ return tp->snd_ssthresh;
+}
+
+
+static void htcp_init(struct tcp_sock *tp)
+{
+ struct htcp *ca = tcp_ca(tp);
+
+ memset(ca, 0, sizeof(struct htcp));
+ ca->alpha = ALPHA_BASE;
+ ca->beta = BETA_MIN;
+}
+
+static void htcp_state(struct tcp_sock *tp, u8 new_state)
+{
+ switch (new_state) {
+ case TCP_CA_CWR:
+ case TCP_CA_Recovery:
+ case TCP_CA_Loss:
+ htcp_reset(tcp_ca(tp));
+ break;
+ }
+}
+
+static struct tcp_congestion_ops htcp = {
+ .init = htcp_init,
+ .ssthresh = htcp_recalc_ssthresh,
+ .min_cwnd = htcp_min_cwnd,
+ .cong_avoid = htcp_cong_avoid,
+ .set_state = htcp_state,
+ .undo_cwnd = htcp_cwnd_undo,
+ .pkts_acked = measure_achieved_throughput,
+ .owner = THIS_MODULE,
+ .name = "htcp",
+};
+
+static int __init htcp_register(void)
+{
+ BUG_ON(sizeof(struct htcp) > TCP_CA_PRIV_SIZE);
+ BUILD_BUG_ON(BETA_MIN >= BETA_MAX);
+ if (!use_bandwidth_switch)
+ htcp.pkts_acked = NULL;
+ return tcp_register_congestion_control(&htcp);
+}
+
+static void __exit htcp_unregister(void)
+{
+ tcp_unregister_congestion_control(&htcp);
+}
+
+module_init(htcp_register);
+module_exit(htcp_unregister);
+
+MODULE_AUTHOR("Baruch Even");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("H-TCP");
diff --git a/net/ipv4/tcp_hybla.c b/net/ipv4/tcp_hybla.c
new file mode 100644
index 000000000000..13a66342c304
--- /dev/null
+++ b/net/ipv4/tcp_hybla.c
@@ -0,0 +1,187 @@
+/*
+ * TCP HYBLA
+ *
+ * TCP-HYBLA Congestion control algorithm, based on:
+ * C.Caini, R.Firrincieli, "TCP-Hybla: A TCP Enhancement
+ * for Heterogeneous Networks",
+ * International Journal on satellite Communications,
+ * September 2004
+ * Daniele Lacamera
+ * root at danielinux.net
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/tcp.h>
+
+/* Tcp Hybla structure. */
+struct hybla {
+ u8 hybla_en;
+ u32 snd_cwnd_cents; /* Keeps increment values when it is <1, <<7 */
+ u32 rho; /* Rho parameter, integer part */
+ u32 rho2; /* Rho * Rho, integer part */
+ u32 rho_3ls; /* Rho parameter, <<3 */
+ u32 rho2_7ls; /* Rho^2, <<7 */
+ u32 minrtt; /* Minimum smoothed round trip time value seen */
+};
+
+/* Hybla reference round trip time (default= 1/40 sec = 25 ms),
+ expressed in jiffies */
+static int rtt0 = 25;
+module_param(rtt0, int, 0644);
+MODULE_PARM_DESC(rtt0, "reference rout trip time (ms)");
+
+
+/* This is called to refresh values for hybla parameters */
+static inline void hybla_recalc_param (struct tcp_sock *tp)
+{
+ struct hybla *ca = tcp_ca(tp);
+
+ ca->rho_3ls = max_t(u32, tp->srtt / msecs_to_jiffies(rtt0), 8);
+ ca->rho = ca->rho_3ls >> 3;
+ ca->rho2_7ls = (ca->rho_3ls * ca->rho_3ls) << 1;
+ ca->rho2 = ca->rho2_7ls >>7;
+}
+
+static void hybla_init(struct tcp_sock *tp)
+{
+ struct hybla *ca = tcp_ca(tp);
+
+ ca->rho = 0;
+ ca->rho2 = 0;
+ ca->rho_3ls = 0;
+ ca->rho2_7ls = 0;
+ ca->snd_cwnd_cents = 0;
+ ca->hybla_en = 1;
+ tp->snd_cwnd = 2;
+ tp->snd_cwnd_clamp = 65535;
+
+ /* 1st Rho measurement based on initial srtt */
+ hybla_recalc_param(tp);
+
+ /* set minimum rtt as this is the 1st ever seen */
+ ca->minrtt = tp->srtt;
+ tp->snd_cwnd = ca->rho;
+}
+
+static void hybla_state(struct tcp_sock *tp, u8 ca_state)
+{
+ struct hybla *ca = tcp_ca(tp);
+
+ ca->hybla_en = (ca_state == TCP_CA_Open);
+}
+
+static inline u32 hybla_fraction(u32 odds)
+{
+ static const u32 fractions[] = {
+ 128, 139, 152, 165, 181, 197, 215, 234,
+ };
+
+ return (odds < ARRAY_SIZE(fractions)) ? fractions[odds] : 128;
+}
+
+/* TCP Hybla main routine.
+ * This is the algorithm behavior:
+ * o Recalc Hybla parameters if min_rtt has changed
+ * o Give cwnd a new value based on the model proposed
+ * o remember increments <1
+ */
+static void hybla_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+ u32 in_flight, int flag)
+{
+ struct hybla *ca = tcp_ca(tp);
+ u32 increment, odd, rho_fractions;
+ int is_slowstart = 0;
+
+ /* Recalculate rho only if this srtt is the lowest */
+ if (tp->srtt < ca->minrtt){
+ hybla_recalc_param(tp);
+ ca->minrtt = tp->srtt;
+ }
+
+ if (!ca->hybla_en)
+ return tcp_reno_cong_avoid(tp, ack, rtt, in_flight, flag);
+
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (ca->rho == 0)
+ hybla_recalc_param(tp);
+
+ rho_fractions = ca->rho_3ls - (ca->rho << 3);
+
+ if (tp->snd_cwnd < tp->snd_ssthresh) {
+ /*
+ * slow start
+ * INC = 2^RHO - 1
+ * This is done by splitting the rho parameter
+ * into 2 parts: an integer part and a fraction part.
+ * Inrement<<7 is estimated by doing:
+ * [2^(int+fract)]<<7
+ * that is equal to:
+ * (2^int) * [(2^fract) <<7]
+ * 2^int is straightly computed as 1<<int,
+ * while we will use hybla_slowstart_fraction_increment() to
+ * calculate 2^fract in a <<7 value.
+ */
+ is_slowstart = 1;
+ increment = ((1 << ca->rho) * hybla_fraction(rho_fractions))
+ - 128;
+ } else {
+ /*
+ * congestion avoidance
+ * INC = RHO^2 / W
+ * as long as increment is estimated as (rho<<7)/window
+ * it already is <<7 and we can easily count its fractions.
+ */
+ increment = ca->rho2_7ls / tp->snd_cwnd;
+ if (increment < 128)
+ tp->snd_cwnd_cnt++;
+ }
+
+ odd = increment % 128;
+ tp->snd_cwnd += increment >> 7;
+ ca->snd_cwnd_cents += odd;
+
+ /* check when fractions goes >=128 and increase cwnd by 1. */
+ while(ca->snd_cwnd_cents >= 128) {
+ tp->snd_cwnd++;
+ ca->snd_cwnd_cents -= 128;
+ tp->snd_cwnd_cnt = 0;
+ }
+
+ /* clamp down slowstart cwnd to ssthresh value. */
+ if (is_slowstart)
+ tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+
+ tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
+}
+
+static struct tcp_congestion_ops tcp_hybla = {
+ .init = hybla_init,
+ .ssthresh = tcp_reno_ssthresh,
+ .min_cwnd = tcp_reno_min_cwnd,
+ .cong_avoid = hybla_cong_avoid,
+ .set_state = hybla_state,
+
+ .owner = THIS_MODULE,
+ .name = "hybla"
+};
+
+static int __init hybla_register(void)
+{
+ BUG_ON(sizeof(struct hybla) > TCP_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_hybla);
+}
+
+static void __exit hybla_unregister(void)
+{
+ tcp_unregister_congestion_control(&tcp_hybla);
+}
+
+module_init(hybla_register);
+module_exit(hybla_unregister);
+
+MODULE_AUTHOR("Daniele Lacamera");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TCP Hybla");
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 5bad504630a3..53a8a5399f1e 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -61,7 +61,6 @@
* Panu Kuhlberg: Experimental audit of TCP (re)transmission
* engine. Lots of bugs are found.
* Pasi Sarolahti: F-RTO for dealing with spurious RTOs
- * Angelo Dell'Aera: TCP Westwood+ support
*/
#include <linux/config.h>
@@ -88,23 +87,9 @@ int sysctl_tcp_rfc1337;
int sysctl_tcp_max_orphans = NR_FILE;
int sysctl_tcp_frto;
int sysctl_tcp_nometrics_save;
-int sysctl_tcp_westwood;
-int sysctl_tcp_vegas_cong_avoid;
int sysctl_tcp_moderate_rcvbuf = 1;
-/* Default values of the Vegas variables, in fixed-point representation
- * with V_PARAM_SHIFT bits to the right of the binary point.
- */
-#define V_PARAM_SHIFT 1
-int sysctl_tcp_vegas_alpha = 1<<V_PARAM_SHIFT;
-int sysctl_tcp_vegas_beta = 3<<V_PARAM_SHIFT;
-int sysctl_tcp_vegas_gamma = 1<<V_PARAM_SHIFT;
-int sysctl_tcp_bic = 1;
-int sysctl_tcp_bic_fast_convergence = 1;
-int sysctl_tcp_bic_low_window = 14;
-int sysctl_tcp_bic_beta = 819; /* = 819/1024 (BICTCP_BETA_SCALE) */
-
#define FLAG_DATA 0x01 /* Incoming frame contained data. */
#define FLAG_WIN_UPDATE 0x02 /* Incoming ACK was a window update. */
#define FLAG_DATA_ACKED 0x04 /* This ACK acknowledged new data. */
@@ -333,15 +318,6 @@ static void tcp_init_buffer_space(struct sock *sk)
tp->snd_cwnd_stamp = tcp_time_stamp;
}
-static void init_bictcp(struct tcp_sock *tp)
-{
- tp->bictcp.cnt = 0;
-
- tp->bictcp.last_max_cwnd = 0;
- tp->bictcp.last_cwnd = 0;
- tp->bictcp.last_stamp = 0;
-}
-
/* 5. Recalculate window clamp after socket hit its memory bounds. */
static void tcp_clamp_window(struct sock *sk, struct tcp_sock *tp)
{
@@ -558,45 +534,6 @@ static void tcp_event_data_recv(struct sock *sk, struct tcp_sock *tp, struct sk_
tcp_grow_window(sk, tp, skb);
}
-/* When starting a new connection, pin down the current choice of
- * congestion algorithm.
- */
-void tcp_ca_init(struct tcp_sock *tp)
-{
- if (sysctl_tcp_westwood)
- tp->adv_cong = TCP_WESTWOOD;
- else if (sysctl_tcp_bic)
- tp->adv_cong = TCP_BIC;
- else if (sysctl_tcp_vegas_cong_avoid) {
- tp->adv_cong = TCP_VEGAS;
- tp->vegas.baseRTT = 0x7fffffff;
- tcp_vegas_enable(tp);
- }
-}
-
-/* Do RTT sampling needed for Vegas.
- * Basically we:
- * o min-filter RTT samples from within an RTT to get the current
- * propagation delay + queuing delay (we are min-filtering to try to
- * avoid the effects of delayed ACKs)
- * o min-filter RTT samples from a much longer window (forever for now)
- * to find the propagation delay (baseRTT)
- */
-static inline void vegas_rtt_calc(struct tcp_sock *tp, __u32 rtt)
-{
- __u32 vrtt = rtt + 1; /* Never allow zero rtt or baseRTT */
-
- /* Filter to find propagation delay: */
- if (vrtt < tp->vegas.baseRTT)
- tp->vegas.baseRTT = vrtt;
-
- /* Find the min RTT during the last RTT to find
- * the current prop. delay + queuing delay:
- */
- tp->vegas.minRTT = min(tp->vegas.minRTT, vrtt);
- tp->vegas.cntRTT++;
-}
-
/* Called to compute a smoothed rtt estimate. The data fed to this
* routine either comes from timestamps, or from segments that were
* known _not_ to have been retransmitted [see Karn/Partridge
@@ -606,13 +543,10 @@ static inline void vegas_rtt_calc(struct tcp_sock *tp, __u32 rtt)
* To save cycles in the RFC 1323 implementation it was better to break
* it up into three procedures. -- erics
*/
-static void tcp_rtt_estimator(struct tcp_sock *tp, __u32 mrtt)
+static void tcp_rtt_estimator(struct tcp_sock *tp, __u32 mrtt, u32 *usrtt)
{
long m = mrtt; /* RTT */
- if (tcp_vegas_enabled(tp))
- vegas_rtt_calc(tp, mrtt);
-
/* The following amusing code comes from Jacobson's
* article in SIGCOMM '88. Note that rtt and mdev
* are scaled versions of rtt and mean deviation.
@@ -670,7 +604,8 @@ static void tcp_rtt_estimator(struct tcp_sock *tp, __u32 mrtt)
tp->rtt_seq = tp->snd_nxt;
}
- tcp_westwood_update_rtt(tp, tp->srtt >> 3);
+ if (tp->ca_ops->rtt_sample)
+ tp->ca_ops->rtt_sample(tp, *usrtt);
}
/* Calculate rto without backoff. This is the second half of Van Jacobson's
@@ -805,10 +740,10 @@ __u32 tcp_init_cwnd(struct tcp_sock *tp, struct dst_entry *dst)
__u32 cwnd = (dst ? dst_metric(dst, RTAX_INITCWND) : 0);
if (!cwnd) {
- if (tp->mss_cache_std > 1460)
+ if (tp->mss_cache > 1460)
cwnd = 2;
else
- cwnd = (tp->mss_cache_std > 1095) ? 3 : 4;
+ cwnd = (tp->mss_cache > 1095) ? 3 : 4;
}
return min_t(__u32, cwnd, tp->snd_cwnd_clamp);
}
@@ -979,7 +914,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
if (sk->sk_route_caps & NETIF_F_TSO) {
sk->sk_route_caps &= ~NETIF_F_TSO;
sock_set_flag(sk, SOCK_NO_LARGESEND);
- tp->mss_cache = tp->mss_cache_std;
+ tp->mss_cache = tp->mss_cache;
}
if (!tp->sacked_out)
@@ -1142,7 +1077,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
(IsFack(tp) ||
!before(lost_retrans,
TCP_SKB_CB(skb)->ack_seq + tp->reordering *
- tp->mss_cache_std))) {
+ tp->mss_cache))) {
TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
tp->retrans_out -= tcp_skb_pcount(skb);
@@ -1185,8 +1120,8 @@ void tcp_enter_frto(struct sock *sk)
tp->snd_una == tp->high_seq ||
(tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
tp->prior_ssthresh = tcp_current_ssthresh(tp);
- if (!tcp_westwood_ssthresh(tp))
- tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
+ tcp_ca_event(tp, CA_EVENT_FRTO);
}
/* Have to clear retransmission markers here to keep the bookkeeping
@@ -1252,8 +1187,6 @@ static void tcp_enter_frto_loss(struct sock *sk)
tcp_set_ca_state(tp, TCP_CA_Loss);
tp->high_seq = tp->frto_highmark;
TCP_ECN_queue_cwr(tp);
-
- init_bictcp(tp);
}
void tcp_clear_retrans(struct tcp_sock *tp)
@@ -1283,7 +1216,8 @@ void tcp_enter_loss(struct sock *sk, int how)
if (tp->ca_state <= TCP_CA_Disorder || tp->snd_una == tp->high_seq ||
(tp->ca_state == TCP_CA_Loss && !tp->retransmits)) {
tp->prior_ssthresh = tcp_current_ssthresh(tp);
- tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
+ tcp_ca_event(tp, CA_EVENT_LOSS);
}
tp->snd_cwnd = 1;
tp->snd_cwnd_cnt = 0;
@@ -1596,28 +1530,14 @@ static inline void tcp_moderate_cwnd(struct tcp_sock *tp)
}
/* Decrease cwnd each second ack. */
-
static void tcp_cwnd_down(struct tcp_sock *tp)
{
int decr = tp->snd_cwnd_cnt + 1;
- __u32 limit;
-
- /*
- * TCP Westwood
- * Here limit is evaluated as BWestimation*RTTmin (for obtaining it
- * in packets we use mss_cache). If sysctl_tcp_westwood is off
- * tcp_westwood_bw_rttmin() returns 0. In such case snd_ssthresh is
- * still used as usual. It prevents other strange cases in which
- * BWE*RTTmin could assume value 0. It should not happen but...
- */
-
- if (!(limit = tcp_westwood_bw_rttmin(tp)))
- limit = tp->snd_ssthresh/2;
tp->snd_cwnd_cnt = decr&1;
decr >>= 1;
- if (decr && tp->snd_cwnd > limit)
+ if (decr && tp->snd_cwnd > tp->ca_ops->min_cwnd(tp))
tp->snd_cwnd -= decr;
tp->snd_cwnd = min(tp->snd_cwnd, tcp_packets_in_flight(tp)+1);
@@ -1654,8 +1574,8 @@ static void DBGUNDO(struct sock *sk, struct tcp_sock *tp, const char *msg)
static void tcp_undo_cwr(struct tcp_sock *tp, int undo)
{
if (tp->prior_ssthresh) {
- if (tcp_is_bic(tp))
- tp->snd_cwnd = max(tp->snd_cwnd, tp->bictcp.last_max_cwnd);
+ if (tp->ca_ops->undo_cwnd)
+ tp->snd_cwnd = tp->ca_ops->undo_cwnd(tp);
else
tp->snd_cwnd = max(tp->snd_cwnd, tp->snd_ssthresh<<1);
@@ -1767,11 +1687,9 @@ static int tcp_try_undo_loss(struct sock *sk, struct tcp_sock *tp)
static inline void tcp_complete_cwr(struct tcp_sock *tp)
{
- if (tcp_westwood_cwnd(tp))
- tp->snd_ssthresh = tp->snd_cwnd;
- else
- tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
+ tp->snd_cwnd = min(tp->snd_cwnd, tp->snd_ssthresh);
tp->snd_cwnd_stamp = tcp_time_stamp;
+ tcp_ca_event(tp, CA_EVENT_COMPLETE_CWR);
}
static void tcp_try_to_open(struct sock *sk, struct tcp_sock *tp, int flag)
@@ -1946,7 +1864,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
if (tp->ca_state < TCP_CA_CWR) {
if (!(flag&FLAG_ECE))
tp->prior_ssthresh = tcp_current_ssthresh(tp);
- tp->snd_ssthresh = tcp_recalc_ssthresh(tp);
+ tp->snd_ssthresh = tp->ca_ops->ssthresh(tp);
TCP_ECN_queue_cwr(tp);
}
@@ -1963,7 +1881,7 @@ tcp_fastretrans_alert(struct sock *sk, u32 prior_snd_una,
/* Read draft-ietf-tcplw-high-performance before mucking
* with this code. (Superceeds RFC1323)
*/
-static void tcp_ack_saw_tstamp(struct tcp_sock *tp, int flag)
+static void tcp_ack_saw_tstamp(struct tcp_sock *tp, u32 *usrtt, int flag)
{
__u32 seq_rtt;
@@ -1983,13 +1901,13 @@ static void tcp_ack_saw_tstamp(struct tcp_sock *tp, int flag)
* in window is lost... Voila. --ANK (010210)
*/
seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr;
- tcp_rtt_estimator(tp, seq_rtt);
+ tcp_rtt_estimator(tp, seq_rtt, usrtt);
tcp_set_rto(tp);
tp->backoff = 0;
tcp_bound_rto(tp);
}
-static void tcp_ack_no_tstamp(struct tcp_sock *tp, u32 seq_rtt, int flag)
+static void tcp_ack_no_tstamp(struct tcp_sock *tp, u32 seq_rtt, u32 *usrtt, int flag)
{
/* We don't have a timestamp. Can only use
* packets that are not retransmitted to determine
@@ -2003,338 +1921,29 @@ static void tcp_ack_no_tstamp(struct tcp_sock *tp, u32 seq_rtt, int flag)
if (flag & FLAG_RETRANS_DATA_ACKED)
return;
- tcp_rtt_estimator(tp, seq_rtt);
+ tcp_rtt_estimator(tp, seq_rtt, usrtt);
tcp_set_rto(tp);
tp->backoff = 0;
tcp_bound_rto(tp);
}
static inline void tcp_ack_update_rtt(struct tcp_sock *tp,
- int flag, s32 seq_rtt)
+ int flag, s32 seq_rtt, u32 *usrtt)
{
/* Note that peer MAY send zero echo. In this case it is ignored. (rfc1323) */
if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr)
- tcp_ack_saw_tstamp(tp, flag);
+ tcp_ack_saw_tstamp(tp, usrtt, flag);
else if (seq_rtt >= 0)
- tcp_ack_no_tstamp(tp, seq_rtt, flag);
-}
-
-/*
- * Compute congestion window to use.
- *
- * This is from the implementation of BICTCP in
- * Lison-Xu, Kahaled Harfoush, and Injog Rhee.
- * "Binary Increase Congestion Control for Fast, Long Distance
- * Networks" in InfoComm 2004
- * Available from:
- * http://www.csc.ncsu.edu/faculty/rhee/export/bitcp.pdf
- *
- * Unless BIC is enabled and congestion window is large
- * this behaves the same as the original Reno.
- */
-static inline __u32 bictcp_cwnd(struct tcp_sock *tp)
-{
- /* orignal Reno behaviour */
- if (!tcp_is_bic(tp))
- return tp->snd_cwnd;
-
- if (tp->bictcp.last_cwnd == tp->snd_cwnd &&
- (s32)(tcp_time_stamp - tp->bictcp.last_stamp) <= (HZ>>5))
- return tp->bictcp.cnt;
-
- tp->bictcp.last_cwnd = tp->snd_cwnd;
- tp->bictcp.last_stamp = tcp_time_stamp;
-
- /* start off normal */
- if (tp->snd_cwnd <= sysctl_tcp_bic_low_window)
- tp->bictcp.cnt = tp->snd_cwnd;
-
- /* binary increase */
- else if (tp->snd_cwnd < tp->bictcp.last_max_cwnd) {
- __u32 dist = (tp->bictcp.last_max_cwnd - tp->snd_cwnd)
- / BICTCP_B;
-
- if (dist > BICTCP_MAX_INCREMENT)
- /* linear increase */
- tp->bictcp.cnt = tp->snd_cwnd / BICTCP_MAX_INCREMENT;
- else if (dist <= 1U)
- /* binary search increase */
- tp->bictcp.cnt = tp->snd_cwnd * BICTCP_FUNC_OF_MIN_INCR
- / BICTCP_B;
- else
- /* binary search increase */
- tp->bictcp.cnt = tp->snd_cwnd / dist;
- } else {
- /* slow start amd linear increase */
- if (tp->snd_cwnd < tp->bictcp.last_max_cwnd + BICTCP_B)
- /* slow start */
- tp->bictcp.cnt = tp->snd_cwnd * BICTCP_FUNC_OF_MIN_INCR
- / BICTCP_B;
- else if (tp->snd_cwnd < tp->bictcp.last_max_cwnd
- + BICTCP_MAX_INCREMENT*(BICTCP_B-1))
- /* slow start */
- tp->bictcp.cnt = tp->snd_cwnd * (BICTCP_B-1)
- / (tp->snd_cwnd-tp->bictcp.last_max_cwnd);
- else
- /* linear increase */
- tp->bictcp.cnt = tp->snd_cwnd / BICTCP_MAX_INCREMENT;
- }
- return tp->bictcp.cnt;
+ tcp_ack_no_tstamp(tp, seq_rtt, usrtt, flag);
}
-/* This is Jacobson's slow start and congestion avoidance.
- * SIGCOMM '88, p. 328.
- */
-static inline void reno_cong_avoid(struct tcp_sock *tp)
+static inline void tcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+ u32 in_flight, int good)
{
- if (tp->snd_cwnd <= tp->snd_ssthresh) {
- /* In "safe" area, increase. */
- if (tp->snd_cwnd < tp->snd_cwnd_clamp)
- tp->snd_cwnd++;
- } else {
- /* In dangerous area, increase slowly.
- * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
- */
- if (tp->snd_cwnd_cnt >= bictcp_cwnd(tp)) {
- if (tp->snd_cwnd < tp->snd_cwnd_clamp)
- tp->snd_cwnd++;
- tp->snd_cwnd_cnt=0;
- } else
- tp->snd_cwnd_cnt++;
- }
+ tp->ca_ops->cong_avoid(tp, ack, rtt, in_flight, good);
tp->snd_cwnd_stamp = tcp_time_stamp;
}
-/* This is based on the congestion detection/avoidance scheme described in
- * Lawrence S. Brakmo and Larry L. Peterson.
- * "TCP Vegas: End to end congestion avoidance on a global internet."
- * IEEE Journal on Selected Areas in Communication, 13(8):1465--1480,
- * October 1995. Available from:
- * ftp://ftp.cs.arizona.edu/xkernel/Papers/jsac.ps
- *
- * See http://www.cs.arizona.edu/xkernel/ for their implementation.
- * The main aspects that distinguish this implementation from the
- * Arizona Vegas implementation are:
- * o We do not change the loss detection or recovery mechanisms of
- * Linux in any way. Linux already recovers from losses quite well,
- * using fine-grained timers, NewReno, and FACK.
- * o To avoid the performance penalty imposed by increasing cwnd
- * only every-other RTT during slow start, we increase during
- * every RTT during slow start, just like Reno.
- * o Largely to allow continuous cwnd growth during slow start,
- * we use the rate at which ACKs come back as the "actual"
- * rate, rather than the rate at which data is sent.
- * o To speed convergence to the right rate, we set the cwnd
- * to achieve the right ("actual") rate when we exit slow start.
- * o To filter out the noise caused by delayed ACKs, we use the
- * minimum RTT sample observed during the last RTT to calculate
- * the actual rate.
- * o When the sender re-starts from idle, it waits until it has
- * received ACKs for an entire flight of new data before making
- * a cwnd adjustment decision. The original Vegas implementation
- * assumed senders never went idle.
- */
-static void vegas_cong_avoid(struct tcp_sock *tp, u32 ack, u32 seq_rtt)
-{
- /* The key players are v_beg_snd_una and v_beg_snd_nxt.
- *
- * These are so named because they represent the approximate values
- * of snd_una and snd_nxt at the beginning of the current RTT. More
- * precisely, they represent the amount of data sent during the RTT.
- * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt,
- * we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding
- * bytes of data have been ACKed during the course of the RTT, giving
- * an "actual" rate of:
- *
- * (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration)
- *
- * Unfortunately, v_beg_snd_una is not exactly equal to snd_una,
- * because delayed ACKs can cover more than one segment, so they
- * don't line up nicely with the boundaries of RTTs.
- *
- * Another unfortunate fact of life is that delayed ACKs delay the
- * advance of the left edge of our send window, so that the number
- * of bytes we send in an RTT is often less than our cwnd will allow.
- * So we keep track of our cwnd separately, in v_beg_snd_cwnd.
- */
-
- if (after(ack, tp->vegas.beg_snd_nxt)) {
- /* Do the Vegas once-per-RTT cwnd adjustment. */
- u32 old_wnd, old_snd_cwnd;
-
-
- /* Here old_wnd is essentially the window of data that was
- * sent during the previous RTT, and has all
- * been acknowledged in the course of the RTT that ended
- * with the ACK we just received. Likewise, old_snd_cwnd
- * is the cwnd during the previous RTT.
- */
- old_wnd = (tp->vegas.beg_snd_nxt - tp->vegas.beg_snd_una) /
- tp->mss_cache_std;
- old_snd_cwnd = tp->vegas.beg_snd_cwnd;
-
- /* Save the extent of the current window so we can use this
- * at the end of the next RTT.
- */
- tp->vegas.beg_snd_una = tp->vegas.beg_snd_nxt;
- tp->vegas.beg_snd_nxt = tp->snd_nxt;
- tp->vegas.beg_snd_cwnd = tp->snd_cwnd;
-
- /* Take into account the current RTT sample too, to
- * decrease the impact of delayed acks. This double counts
- * this sample since we count it for the next window as well,
- * but that's not too awful, since we're taking the min,
- * rather than averaging.
- */
- vegas_rtt_calc(tp, seq_rtt);
-
- /* We do the Vegas calculations only if we got enough RTT
- * samples that we can be reasonably sure that we got
- * at least one RTT sample that wasn't from a delayed ACK.
- * If we only had 2 samples total,
- * then that means we're getting only 1 ACK per RTT, which
- * means they're almost certainly delayed ACKs.
- * If we have 3 samples, we should be OK.
- */
-
- if (tp->vegas.cntRTT <= 2) {
- /* We don't have enough RTT samples to do the Vegas
- * calculation, so we'll behave like Reno.
- */
- if (tp->snd_cwnd > tp->snd_ssthresh)
- tp->snd_cwnd++;
- } else {
- u32 rtt, target_cwnd, diff;
-
- /* We have enough RTT samples, so, using the Vegas
- * algorithm, we determine if we should increase or
- * decrease cwnd, and by how much.
- */
-
- /* Pluck out the RTT we are using for the Vegas
- * calculations. This is the min RTT seen during the
- * last RTT. Taking the min filters out the effects
- * of delayed ACKs, at the cost of noticing congestion
- * a bit later.
- */
- rtt = tp->vegas.minRTT;
-
- /* Calculate the cwnd we should have, if we weren't
- * going too fast.
- *
- * This is:
- * (actual rate in segments) * baseRTT
- * We keep it as a fixed point number with
- * V_PARAM_SHIFT bits to the right of the binary point.
- */
- target_cwnd = ((old_wnd * tp->vegas.baseRTT)
- << V_PARAM_SHIFT) / rtt;
-
- /* Calculate the difference between the window we had,
- * and the window we would like to have. This quantity
- * is the "Diff" from the Arizona Vegas papers.
- *
- * Again, this is a fixed point number with
- * V_PARAM_SHIFT bits to the right of the binary
- * point.
- */
- diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd;
-
- if (tp->snd_cwnd < tp->snd_ssthresh) {
- /* Slow start. */
- if (diff > sysctl_tcp_vegas_gamma) {
- /* Going too fast. Time to slow down
- * and switch to congestion avoidance.
- */
- tp->snd_ssthresh = 2;
-
- /* Set cwnd to match the actual rate
- * exactly:
- * cwnd = (actual rate) * baseRTT
- * Then we add 1 because the integer
- * truncation robs us of full link
- * utilization.
- */
- tp->snd_cwnd = min(tp->snd_cwnd,
- (target_cwnd >>
- V_PARAM_SHIFT)+1);
-
- }
- } else {
- /* Congestion avoidance. */
- u32 next_snd_cwnd;
-
- /* Figure out where we would like cwnd
- * to be.
- */
- if (diff > sysctl_tcp_vegas_beta) {
- /* The old window was too fast, so
- * we slow down.
- */
- next_snd_cwnd = old_snd_cwnd - 1;
- } else if (diff < sysctl_tcp_vegas_alpha) {
- /* We don't have enough extra packets
- * in the network, so speed up.
- */
- next_snd_cwnd = old_snd_cwnd + 1;
- } else {
- /* Sending just as fast as we
- * should be.
- */
- next_snd_cwnd = old_snd_cwnd;
- }
-
- /* Adjust cwnd upward or downward, toward the
- * desired value.
- */
- if (next_snd_cwnd > tp->snd_cwnd)
- tp->snd_cwnd++;
- else if (next_snd_cwnd < tp->snd_cwnd)
- tp->snd_cwnd--;
- }
- }
-
- /* Wipe the slate clean for the next RTT. */
- tp->vegas.cntRTT = 0;
- tp->vegas.minRTT = 0x7fffffff;
- }
-
- /* The following code is executed for every ack we receive,
- * except for conditions checked in should_advance_cwnd()
- * before the call to tcp_cong_avoid(). Mainly this means that
- * we only execute this code if the ack actually acked some
- * data.
- */
-
- /* If we are in slow start, increase our cwnd in response to this ACK.
- * (If we are not in slow start then we are in congestion avoidance,
- * and adjust our congestion window only once per RTT. See the code
- * above.)
- */
- if (tp->snd_cwnd <= tp->snd_ssthresh)
- tp->snd_cwnd++;
-
- /* to keep cwnd from growing without bound */
- tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
-
- /* Make sure that we are never so timid as to reduce our cwnd below
- * 2 MSS.
- *
- * Going below 2 MSS would risk huge delayed ACKs from our receiver.
- */
- tp->snd_cwnd = max(tp->snd_cwnd, 2U);
-
- tp->snd_cwnd_stamp = tcp_time_stamp;
-}
-
-static inline void tcp_cong_avoid(struct tcp_sock *tp, u32 ack, u32 seq_rtt)
-{
- if (tcp_vegas_enabled(tp))
- vegas_cong_avoid(tp, ack, seq_rtt);
- else
- reno_cong_avoid(tp);
-}
-
/* Restart timer after forward progress on connection.
* RFC2988 recommends to restart timer to now+rto.
*/
@@ -2348,15 +1957,6 @@ static inline void tcp_ack_packets_out(struct sock *sk, struct tcp_sock *tp)
}
}
-/* There is one downside to this scheme. Although we keep the
- * ACK clock ticking, adjusting packet counters and advancing
- * congestion window, we do not liberate socket send buffer
- * space.
- *
- * Mucking with skb->truesize and sk->sk_wmem_alloc et al.
- * then making a write space wakeup callback is a possible
- * future enhancement. WARNING: it is not trivial to make.
- */
static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb,
__u32 now, __s32 *seq_rtt)
{
@@ -2415,13 +2015,18 @@ static int tcp_tso_acked(struct sock *sk, struct sk_buff *skb,
/* Remove acknowledged frames from the retransmission queue. */
-static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
+static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p, s32 *seq_usrtt)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
__u32 now = tcp_time_stamp;
int acked = 0;
__s32 seq_rtt = -1;
+ struct timeval usnow;
+ u32 pkts_acked = 0;
+
+ if (seq_usrtt)
+ do_gettimeofday(&usnow);
while ((skb = skb_peek(&sk->sk_write_queue)) &&
skb != sk->sk_send_head) {
@@ -2433,7 +2038,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
* the other end.
*/
if (after(scb->end_seq, tp->snd_una)) {
- if (tcp_skb_pcount(skb) > 1)
+ if (tcp_skb_pcount(skb) > 1 &&
+ after(tp->snd_una, scb->seq))
acked |= tcp_tso_acked(sk, skb,
now, &seq_rtt);
break;
@@ -2448,6 +2054,7 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
*/
if (!(scb->flags & TCPCB_FLAG_SYN)) {
acked |= FLAG_DATA_ACKED;
+ ++pkts_acked;
} else {
acked |= FLAG_SYN_ACKED;
tp->retrans_stamp = 0;
@@ -2461,6 +2068,10 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
seq_rtt = -1;
} else if (seq_rtt < 0)
seq_rtt = now - scb->when;
+ if (seq_usrtt)
+ *seq_usrtt = (usnow.tv_sec - skb->stamp.tv_sec) * 1000000
+ + (usnow.tv_usec - skb->stamp.tv_usec);
+
if (sacked & TCPCB_SACKED_ACKED)
tp->sacked_out -= tcp_skb_pcount(skb);
if (sacked & TCPCB_LOST)
@@ -2479,8 +2090,11 @@ static int tcp_clean_rtx_queue(struct sock *sk, __s32 *seq_rtt_p)
}
if (acked&FLAG_ACKED) {
- tcp_ack_update_rtt(tp, acked, seq_rtt);
+ tcp_ack_update_rtt(tp, acked, seq_rtt, seq_usrtt);
tcp_ack_packets_out(sk, tp);
+
+ if (tp->ca_ops->pkts_acked)
+ tp->ca_ops->pkts_acked(tp, pkts_acked);
}
#if FASTRETRANS_DEBUG > 0
@@ -2624,257 +2238,6 @@ static void tcp_process_frto(struct sock *sk, u32 prior_snd_una)
tp->frto_counter = (tp->frto_counter + 1) % 3;
}
-/*
- * TCP Westwood+
- */
-
-/*
- * @init_westwood
- * This function initializes fields used in TCP Westwood+. We can't
- * get no information about RTTmin at this time so we simply set it to
- * TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative
- * since in this way we're sure it will be updated in a consistent
- * way as soon as possible. It will reasonably happen within the first
- * RTT period of the connection lifetime.
- */
-
-static void init_westwood(struct sock *sk)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- tp->westwood.bw_ns_est = 0;
- tp->westwood.bw_est = 0;
- tp->westwood.accounted = 0;
- tp->westwood.cumul_ack = 0;
- tp->westwood.rtt_win_sx = tcp_time_stamp;
- tp->westwood.rtt = TCP_WESTWOOD_INIT_RTT;
- tp->westwood.rtt_min = TCP_WESTWOOD_INIT_RTT;
- tp->westwood.snd_una = tp->snd_una;
-}
-
-/*
- * @westwood_do_filter
- * Low-pass filter. Implemented using constant coeffients.
- */
-
-static inline __u32 westwood_do_filter(__u32 a, __u32 b)
-{
- return (((7 * a) + b) >> 3);
-}
-
-static void westwood_filter(struct sock *sk, __u32 delta)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- tp->westwood.bw_ns_est =
- westwood_do_filter(tp->westwood.bw_ns_est,
- tp->westwood.bk / delta);
- tp->westwood.bw_est =
- westwood_do_filter(tp->westwood.bw_est,
- tp->westwood.bw_ns_est);
-}
-
-/*
- * @westwood_update_rttmin
- * It is used to update RTTmin. In this case we MUST NOT use
- * WESTWOOD_RTT_MIN minimum bound since we could be on a LAN!
- */
-
-static inline __u32 westwood_update_rttmin(const struct sock *sk)
-{
- const struct tcp_sock *tp = tcp_sk(sk);
- __u32 rttmin = tp->westwood.rtt_min;
-
- if (tp->westwood.rtt != 0 &&
- (tp->westwood.rtt < tp->westwood.rtt_min || !rttmin))
- rttmin = tp->westwood.rtt;
-
- return rttmin;
-}
-
-/*
- * @westwood_acked
- * Evaluate increases for dk.
- */
-
-static inline __u32 westwood_acked(const struct sock *sk)
-{
- const struct tcp_sock *tp = tcp_sk(sk);
-
- return tp->snd_una - tp->westwood.snd_una;
-}
-
-/*
- * @westwood_new_window
- * It evaluates if we are receiving data inside the same RTT window as
- * when we started.
- * Return value:
- * It returns 0 if we are still evaluating samples in the same RTT
- * window, 1 if the sample has to be considered in the next window.
- */
-
-static int westwood_new_window(const struct sock *sk)
-{
- const struct tcp_sock *tp = tcp_sk(sk);
- __u32 left_bound;
- __u32 rtt;
- int ret = 0;
-
- left_bound = tp->westwood.rtt_win_sx;
- rtt = max(tp->westwood.rtt, (u32) TCP_WESTWOOD_RTT_MIN);
-
- /*
- * A RTT-window has passed. Be careful since if RTT is less than
- * 50ms we don't filter but we continue 'building the sample'.
- * This minimum limit was choosen since an estimation on small
- * time intervals is better to avoid...
- * Obvioulsy on a LAN we reasonably will always have
- * right_bound = left_bound + WESTWOOD_RTT_MIN
- */
-
- if ((left_bound + rtt) < tcp_time_stamp)
- ret = 1;
-
- return ret;
-}
-
-/*
- * @westwood_update_window
- * It updates RTT evaluation window if it is the right moment to do
- * it. If so it calls filter for evaluating bandwidth.
- */
-
-static void __westwood_update_window(struct sock *sk, __u32 now)
-{
- struct tcp_sock *tp = tcp_sk(sk);
- __u32 delta = now - tp->westwood.rtt_win_sx;
-
- if (delta) {
- if (tp->westwood.rtt)
- westwood_filter(sk, delta);
-
- tp->westwood.bk = 0;
- tp->westwood.rtt_win_sx = tcp_time_stamp;
- }
-}
-
-
-static void westwood_update_window(struct sock *sk, __u32 now)
-{
- if (westwood_new_window(sk))
- __westwood_update_window(sk, now);
-}
-
-/*
- * @__tcp_westwood_fast_bw
- * It is called when we are in fast path. In particular it is called when
- * header prediction is successfull. In such case infact update is
- * straight forward and doesn't need any particular care.
- */
-
-static void __tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- westwood_update_window(sk, tcp_time_stamp);
-
- tp->westwood.bk += westwood_acked(sk);
- tp->westwood.snd_una = tp->snd_una;
- tp->westwood.rtt_min = westwood_update_rttmin(sk);
-}
-
-static inline void tcp_westwood_fast_bw(struct sock *sk, struct sk_buff *skb)
-{
- if (tcp_is_westwood(tcp_sk(sk)))
- __tcp_westwood_fast_bw(sk, skb);
-}
-
-
-/*
- * @westwood_dupack_update
- * It updates accounted and cumul_ack when receiving a dupack.
- */
-
-static void westwood_dupack_update(struct sock *sk)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- tp->westwood.accounted += tp->mss_cache_std;
- tp->westwood.cumul_ack = tp->mss_cache_std;
-}
-
-static inline int westwood_may_change_cumul(struct tcp_sock *tp)
-{
- return (tp->westwood.cumul_ack > tp->mss_cache_std);
-}
-
-static inline void westwood_partial_update(struct tcp_sock *tp)
-{
- tp->westwood.accounted -= tp->westwood.cumul_ack;
- tp->westwood.cumul_ack = tp->mss_cache_std;
-}
-
-static inline void westwood_complete_update(struct tcp_sock *tp)
-{
- tp->westwood.cumul_ack -= tp->westwood.accounted;
- tp->westwood.accounted = 0;
-}
-
-/*
- * @westwood_acked_count
- * This function evaluates cumul_ack for evaluating dk in case of
- * delayed or partial acks.
- */
-
-static inline __u32 westwood_acked_count(struct sock *sk)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- tp->westwood.cumul_ack = westwood_acked(sk);
-
- /* If cumul_ack is 0 this is a dupack since it's not moving
- * tp->snd_una.
- */
- if (!(tp->westwood.cumul_ack))
- westwood_dupack_update(sk);
-
- if (westwood_may_change_cumul(tp)) {
- /* Partial or delayed ack */
- if (tp->westwood.accounted >= tp->westwood.cumul_ack)
- westwood_partial_update(tp);
- else
- westwood_complete_update(tp);
- }
-
- tp->westwood.snd_una = tp->snd_una;
-
- return tp->westwood.cumul_ack;
-}
-
-
-/*
- * @__tcp_westwood_slow_bw
- * It is called when something is going wrong..even if there could
- * be no problems! Infact a simple delayed packet may trigger a
- * dupack. But we need to be careful in such case.
- */
-
-static void __tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- westwood_update_window(sk, tcp_time_stamp);
-
- tp->westwood.bk += westwood_acked_count(sk);
- tp->westwood.rtt_min = westwood_update_rttmin(sk);
-}
-
-static inline void tcp_westwood_slow_bw(struct sock *sk, struct sk_buff *skb)
-{
- if (tcp_is_westwood(tcp_sk(sk)))
- __tcp_westwood_slow_bw(sk, skb);
-}
-
/* This routine deals with incoming acks, but not outgoing ones. */
static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
{
@@ -2884,6 +2247,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
u32 ack = TCP_SKB_CB(skb)->ack_seq;
u32 prior_in_flight;
s32 seq_rtt;
+ s32 seq_usrtt = 0;
int prior_packets;
/* If the ack is newer than sent or older than previous acks
@@ -2902,9 +2266,10 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
*/
tcp_update_wl(tp, ack, ack_seq);
tp->snd_una = ack;
- tcp_westwood_fast_bw(sk, skb);
flag |= FLAG_WIN_UPDATE;
+ tcp_ca_event(tp, CA_EVENT_FAST_ACK);
+
NET_INC_STATS_BH(LINUX_MIB_TCPHPACKS);
} else {
if (ack_seq != TCP_SKB_CB(skb)->end_seq)
@@ -2920,7 +2285,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
if (TCP_ECN_rcv_ecn_echo(tp, skb->h.th))
flag |= FLAG_ECE;
- tcp_westwood_slow_bw(sk,skb);
+ tcp_ca_event(tp, CA_EVENT_SLOW_ACK);
}
/* We passed data and got it acked, remove any soft error
@@ -2935,22 +2300,20 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
prior_in_flight = tcp_packets_in_flight(tp);
/* See if we can take anything off of the retransmit queue. */
- flag |= tcp_clean_rtx_queue(sk, &seq_rtt);
+ flag |= tcp_clean_rtx_queue(sk, &seq_rtt,
+ tp->ca_ops->rtt_sample ? &seq_usrtt : NULL);
if (tp->frto_counter)
tcp_process_frto(sk, prior_snd_una);
if (tcp_ack_is_dubious(tp, flag)) {
/* Advanve CWND, if state allows this. */
- if ((flag & FLAG_DATA_ACKED) &&
- (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd) &&
- tcp_may_raise_cwnd(tp, flag))
- tcp_cong_avoid(tp, ack, seq_rtt);
+ if ((flag & FLAG_DATA_ACKED) && tcp_may_raise_cwnd(tp, flag))
+ tcp_cong_avoid(tp, ack, seq_rtt, prior_in_flight, 0);
tcp_fastretrans_alert(sk, prior_snd_una, prior_packets, flag);
} else {
- if ((flag & FLAG_DATA_ACKED) &&
- (tcp_vegas_enabled(tp) || prior_in_flight >= tp->snd_cwnd))
- tcp_cong_avoid(tp, ack, seq_rtt);
+ if ((flag & FLAG_DATA_ACKED))
+ tcp_cong_avoid(tp, ack, seq_rtt, prior_in_flight, 1);
}
if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP))
@@ -3439,7 +2802,7 @@ static void tcp_sack_remove(struct tcp_sock *tp)
int this_sack;
/* Empty ofo queue, hence, all the SACKs are eaten. Clear. */
- if (skb_queue_len(&tp->out_of_order_queue) == 0) {
+ if (skb_queue_empty(&tp->out_of_order_queue)) {
tp->rx_opt.num_sacks = 0;
tp->rx_opt.eff_sacks = tp->rx_opt.dsack;
return;
@@ -3572,13 +2935,13 @@ queue_and_out:
if(th->fin)
tcp_fin(skb, sk, th);
- if (skb_queue_len(&tp->out_of_order_queue)) {
+ if (!skb_queue_empty(&tp->out_of_order_queue)) {
tcp_ofo_queue(sk);
/* RFC2581. 4.2. SHOULD send immediate ACK, when
* gap in queue is filled.
*/
- if (!skb_queue_len(&tp->out_of_order_queue))
+ if (skb_queue_empty(&tp->out_of_order_queue))
tp->ack.pingpong = 0;
}
@@ -3886,9 +3249,8 @@ static int tcp_prune_queue(struct sock *sk)
* This must not ever occur. */
/* First, purge the out_of_order queue. */
- if (skb_queue_len(&tp->out_of_order_queue)) {
- NET_ADD_STATS_BH(LINUX_MIB_OFOPRUNED,
- skb_queue_len(&tp->out_of_order_queue));
+ if (!skb_queue_empty(&tp->out_of_order_queue)) {
+ NET_INC_STATS_BH(LINUX_MIB_OFOPRUNED);
__skb_queue_purge(&tp->out_of_order_queue);
/* Reset SACK state. A conforming SACK implementation will
@@ -3937,6 +3299,28 @@ void tcp_cwnd_application_limited(struct sock *sk)
tp->snd_cwnd_stamp = tcp_time_stamp;
}
+static inline int tcp_should_expand_sndbuf(struct sock *sk, struct tcp_sock *tp)
+{
+ /* If the user specified a specific send buffer setting, do
+ * not modify it.
+ */
+ if (sk->sk_userlocks & SOCK_SNDBUF_LOCK)
+ return 0;
+
+ /* If we are under global TCP memory pressure, do not expand. */
+ if (tcp_memory_pressure)
+ return 0;
+
+ /* If we are under soft global TCP memory pressure, do not expand. */
+ if (atomic_read(&tcp_memory_allocated) >= sysctl_tcp_mem[0])
+ return 0;
+
+ /* If we filled the congestion window, do not expand. */
+ if (tp->packets_out >= tp->snd_cwnd)
+ return 0;
+
+ return 1;
+}
/* When incoming ACK allowed to free some skb from write_queue,
* we remember this event in flag SOCK_QUEUE_SHRUNK and wake up socket
@@ -3948,11 +3332,8 @@ static void tcp_new_space(struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
- if (tp->packets_out < tp->snd_cwnd &&
- !(sk->sk_userlocks & SOCK_SNDBUF_LOCK) &&
- !tcp_memory_pressure &&
- atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) {
- int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache_std) +
+ if (tcp_should_expand_sndbuf(sk, tp)) {
+ int sndmem = max_t(u32, tp->rx_opt.mss_clamp, tp->mss_cache) +
MAX_TCP_HEADER + 16 + sizeof(struct sk_buff),
demanded = max_t(unsigned int, tp->snd_cwnd,
tp->reordering + 1);
@@ -3975,22 +3356,9 @@ static inline void tcp_check_space(struct sock *sk)
}
}
-static void __tcp_data_snd_check(struct sock *sk, struct sk_buff *skb)
+static __inline__ void tcp_data_snd_check(struct sock *sk, struct tcp_sock *tp)
{
- struct tcp_sock *tp = tcp_sk(sk);
-
- if (after(TCP_SKB_CB(skb)->end_seq, tp->snd_una + tp->snd_wnd) ||
- tcp_packets_in_flight(tp) >= tp->snd_cwnd ||
- tcp_write_xmit(sk, tp->nonagle))
- tcp_check_probe_timer(sk, tp);
-}
-
-static __inline__ void tcp_data_snd_check(struct sock *sk)
-{
- struct sk_buff *skb = sk->sk_send_head;
-
- if (skb != NULL)
- __tcp_data_snd_check(sk, skb);
+ tcp_push_pending_frames(sk, tp);
tcp_check_space(sk);
}
@@ -4284,7 +3652,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
*/
tcp_ack(sk, skb, 0);
__kfree_skb(skb);
- tcp_data_snd_check(sk);
+ tcp_data_snd_check(sk, tp);
return 0;
} else { /* Header too small */
TCP_INC_STATS_BH(TCP_MIB_INERRS);
@@ -4350,7 +3718,7 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
if (TCP_SKB_CB(skb)->ack_seq != tp->snd_una) {
/* Well, only one small jumplet in fast path... */
tcp_ack(sk, skb, FLAG_DATA);
- tcp_data_snd_check(sk);
+ tcp_data_snd_check(sk, tp);
if (!tcp_ack_scheduled(tp))
goto no_ack;
}
@@ -4428,7 +3796,7 @@ step5:
/* step 7: process the segment text */
tcp_data_queue(sk, skb);
- tcp_data_snd_check(sk);
+ tcp_data_snd_check(sk, tp);
tcp_ack_snd_check(sk);
return 0;
@@ -4552,6 +3920,8 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
tcp_init_metrics(sk);
+ tcp_init_congestion_control(tp);
+
/* Prevent spurious tcp_cwnd_restart() on first data
* packet.
*/
@@ -4708,9 +4078,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if(tp->af_specific->conn_request(sk, skb) < 0)
return 1;
- init_westwood(sk);
- init_bictcp(tp);
-
/* Now we have several options: In theory there is
* nothing else in the frame. KA9Q has an option to
* send data with the syn, BSD accepts data with the
@@ -4732,9 +4099,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
goto discard;
case TCP_SYN_SENT:
- init_westwood(sk);
- init_bictcp(tp);
-
queued = tcp_rcv_synsent_state_process(sk, skb, th, len);
if (queued >= 0)
return queued;
@@ -4742,7 +4106,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* Do step6 onward by hand. */
tcp_urg(sk, skb, th);
__kfree_skb(skb);
- tcp_data_snd_check(sk);
+ tcp_data_snd_check(sk, tp);
return 0;
}
@@ -4816,7 +4180,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
*/
if (tp->rx_opt.saw_tstamp && tp->rx_opt.rcv_tsecr &&
!tp->srtt)
- tcp_ack_saw_tstamp(tp, 0);
+ tcp_ack_saw_tstamp(tp, 0, 0);
if (tp->rx_opt.tstamp_ok)
tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
@@ -4828,6 +4192,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
tcp_init_metrics(sk);
+ tcp_init_congestion_control(tp);
+
/* Prevent spurious tcp_cwnd_restart() on
* first data packet.
*/
@@ -4931,7 +4297,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
/* tcp_data could move socket to TIME-WAIT */
if (sk->sk_state != TCP_CLOSE) {
- tcp_data_snd_check(sk);
+ tcp_data_snd_check(sk, tp);
tcp_ack_snd_check(sk);
}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 2d41d5d6ad19..62f62bb05c2a 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2045,9 +2045,10 @@ static int tcp_v4_init_sock(struct sock *sk)
*/
tp->snd_ssthresh = 0x7fffffff; /* Infinity */
tp->snd_cwnd_clamp = ~0;
- tp->mss_cache_std = tp->mss_cache = 536;
+ tp->mss_cache = 536;
tp->reordering = sysctl_tcp_reordering;
+ tp->ca_ops = &tcp_init_congestion_ops;
sk->sk_state = TCP_CLOSE;
@@ -2070,6 +2071,8 @@ int tcp_v4_destroy_sock(struct sock *sk)
tcp_clear_xmit_timers(sk);
+ tcp_cleanup_congestion_control(tp);
+
/* Cleanup up the write buffer. */
sk_stream_writequeue_purge(sk);
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index b3943e7562f3..f42a284164b7 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -774,6 +774,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
newtp->frto_counter = 0;
newtp->frto_highmark = 0;
+ newtp->ca_ops = &tcp_reno;
+
tcp_set_ca_state(newtp, TCP_CA_Open);
tcp_init_xmit_timers(newsk);
skb_queue_head_init(&newtp->out_of_order_queue);
@@ -842,8 +844,6 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
if (newtp->ecn_flags&TCP_ECN_OK)
sock_set_flag(newsk, SOCK_NO_LARGESEND);
- tcp_ca_init(newtp);
-
TCP_INC_STATS_BH(TCP_MIB_PASSIVEOPENS);
}
return newsk;
diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c
index f17c6577e337..e3f8ea1bfa9c 100644
--- a/net/ipv4/tcp_output.c
+++ b/net/ipv4/tcp_output.c
@@ -49,7 +49,7 @@ int sysctl_tcp_retrans_collapse = 1;
* will allow a single TSO frame to consume. Building TSO frames
* which are too large can cause TCP streams to be bursty.
*/
-int sysctl_tcp_tso_win_divisor = 8;
+int sysctl_tcp_tso_win_divisor = 3;
static inline void update_send_head(struct sock *sk, struct tcp_sock *tp,
struct sk_buff *skb)
@@ -111,8 +111,7 @@ static void tcp_cwnd_restart(struct tcp_sock *tp, struct dst_entry *dst)
u32 restart_cwnd = tcp_init_cwnd(tp, dst);
u32 cwnd = tp->snd_cwnd;
- if (tcp_is_vegas(tp))
- tcp_vegas_enable(tp);
+ tcp_ca_event(tp, CA_EVENT_CWND_RESTART);
tp->snd_ssthresh = tcp_current_ssthresh(tp);
restart_cwnd = min(restart_cwnd, cwnd);
@@ -141,11 +140,11 @@ static inline void tcp_event_data_sent(struct tcp_sock *tp,
tp->ack.pingpong = 1;
}
-static __inline__ void tcp_event_ack_sent(struct sock *sk)
+static __inline__ void tcp_event_ack_sent(struct sock *sk, unsigned int pkts)
{
struct tcp_sock *tp = tcp_sk(sk);
- tcp_dec_quickack_mode(tp);
+ tcp_dec_quickack_mode(tp, pkts);
tcp_clear_xmit_timer(sk, TCP_TIME_DACK);
}
@@ -280,6 +279,10 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
#define SYSCTL_FLAG_WSCALE 0x2
#define SYSCTL_FLAG_SACK 0x4
+ /* If congestion control is doing timestamping */
+ if (tp->ca_ops->rtt_sample)
+ do_gettimeofday(&skb->stamp);
+
sysctl_flags = 0;
if (tcb->flags & TCPCB_FLAG_SYN) {
tcp_header_size = sizeof(struct tcphdr) + TCPOLEN_MSS;
@@ -304,17 +307,8 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
(tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK));
}
- /*
- * If the connection is idle and we are restarting,
- * then we don't want to do any Vegas calculations
- * until we get fresh RTT samples. So when we
- * restart, we reset our Vegas state to a clean
- * slate. After we get acks for this flight of
- * packets, _then_ we can make Vegas calculations
- * again.
- */
- if (tcp_is_vegas(tp) && tcp_packets_in_flight(tp) == 0)
- tcp_vegas_enable(tp);
+ if (tcp_packets_in_flight(tp) == 0)
+ tcp_ca_event(tp, CA_EVENT_TX_START);
th = (struct tcphdr *) skb_push(skb, tcp_header_size);
skb->h.th = th;
@@ -361,7 +355,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb)
tp->af_specific->send_check(sk, th, skb->len, skb);
if (tcb->flags & TCPCB_FLAG_ACK)
- tcp_event_ack_sent(sk);
+ tcp_event_ack_sent(sk, tcp_skb_pcount(skb));
if (skb->len != tcp_header_size)
tcp_event_data_sent(tp, skb, sk);
@@ -409,42 +403,11 @@ static void tcp_queue_skb(struct sock *sk, struct sk_buff *skb)
sk->sk_send_head = skb;
}
-static inline void tcp_tso_set_push(struct sk_buff *skb)
-{
- /* Force push to be on for any TSO frames to workaround
- * problems with busted implementations like Mac OS-X that
- * hold off socket receive wakeups until push is seen.
- */
- if (tcp_skb_pcount(skb) > 1)
- TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
-}
-
-/* Send _single_ skb sitting at the send head. This function requires
- * true push pending frames to setup probe timer etc.
- */
-void tcp_push_one(struct sock *sk, unsigned cur_mss)
+static void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
{
struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb = sk->sk_send_head;
- if (tcp_snd_test(sk, skb, cur_mss, TCP_NAGLE_PUSH)) {
- /* Send it out now. */
- TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_tso_set_push(skb);
- if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) {
- sk->sk_send_head = NULL;
- tp->snd_nxt = TCP_SKB_CB(skb)->end_seq;
- tcp_packets_out_inc(sk, tp, skb);
- return;
- }
- }
-}
-
-void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
-{
- struct tcp_sock *tp = tcp_sk(sk);
-
- if (skb->len <= tp->mss_cache_std ||
+ if (skb->len <= tp->mss_cache ||
!(sk->sk_route_caps & NETIF_F_TSO)) {
/* Avoid the costly divide in the normal
* non-TSO case.
@@ -454,10 +417,10 @@ void tcp_set_skb_tso_segs(struct sock *sk, struct sk_buff *skb)
} else {
unsigned int factor;
- factor = skb->len + (tp->mss_cache_std - 1);
- factor /= tp->mss_cache_std;
+ factor = skb->len + (tp->mss_cache - 1);
+ factor /= tp->mss_cache;
skb_shinfo(skb)->tso_segs = factor;
- skb_shinfo(skb)->tso_size = tp->mss_cache_std;
+ skb_shinfo(skb)->tso_size = tp->mss_cache;
}
}
@@ -521,6 +484,7 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
* skbs, which it never sent before. --ANK
*/
TCP_SKB_CB(buff)->when = TCP_SKB_CB(skb)->when;
+ buff->stamp = skb->stamp;
if (TCP_SKB_CB(skb)->sacked & TCPCB_LOST) {
tp->lost_out -= tcp_skb_pcount(skb);
@@ -542,6 +506,7 @@ static int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len)
}
/* Link BUFF into the send queue. */
+ skb_header_release(buff);
__skb_append(skb, buff);
return 0;
@@ -662,7 +627,7 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
/* And store cached results */
tp->pmtu_cookie = pmtu;
- tp->mss_cache = tp->mss_cache_std = mss_now;
+ tp->mss_cache = mss_now;
return mss_now;
}
@@ -674,57 +639,316 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
* cannot be large. However, taking into account rare use of URG, this
* is not a big flaw.
*/
-
-unsigned int tcp_current_mss(struct sock *sk, int large)
+unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
{
struct tcp_sock *tp = tcp_sk(sk);
struct dst_entry *dst = __sk_dst_get(sk);
- unsigned int do_large, mss_now;
+ u32 mss_now;
+ u16 xmit_size_goal;
+ int doing_tso = 0;
+
+ mss_now = tp->mss_cache;
+
+ if (large_allowed &&
+ (sk->sk_route_caps & NETIF_F_TSO) &&
+ !tp->urg_mode)
+ doing_tso = 1;
- mss_now = tp->mss_cache_std;
if (dst) {
u32 mtu = dst_mtu(dst);
if (mtu != tp->pmtu_cookie)
mss_now = tcp_sync_mss(sk, mtu);
}
- do_large = (large &&
- (sk->sk_route_caps & NETIF_F_TSO) &&
- !tp->urg_mode);
+ if (tp->rx_opt.eff_sacks)
+ mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
+ (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK));
- if (do_large) {
- unsigned int large_mss, factor, limit;
+ xmit_size_goal = mss_now;
- large_mss = 65535 - tp->af_specific->net_header_len -
+ if (doing_tso) {
+ xmit_size_goal = 65535 -
+ tp->af_specific->net_header_len -
tp->ext_header_len - tp->tcp_header_len;
- if (tp->max_window && large_mss > (tp->max_window>>1))
- large_mss = max((tp->max_window>>1),
- 68U - tp->tcp_header_len);
+ if (tp->max_window &&
+ (xmit_size_goal > (tp->max_window >> 1)))
+ xmit_size_goal = max((tp->max_window >> 1),
+ 68U - tp->tcp_header_len);
- factor = large_mss / mss_now;
+ xmit_size_goal -= (xmit_size_goal % mss_now);
+ }
+ tp->xmit_size_goal = xmit_size_goal;
- /* Always keep large mss multiple of real mss, but
- * do not exceed 1/tso_win_divisor of the congestion window
- * so we can keep the ACK clock ticking and minimize
- * bursting.
- */
- limit = tp->snd_cwnd;
- if (sysctl_tcp_tso_win_divisor)
- limit /= sysctl_tcp_tso_win_divisor;
- limit = max(1U, limit);
- if (factor > limit)
- factor = limit;
+ return mss_now;
+}
+
+/* Congestion window validation. (RFC2861) */
+
+static inline void tcp_cwnd_validate(struct sock *sk, struct tcp_sock *tp)
+{
+ __u32 packets_out = tp->packets_out;
- tp->mss_cache = mss_now * factor;
+ if (packets_out >= tp->snd_cwnd) {
+ /* Network is feed fully. */
+ tp->snd_cwnd_used = 0;
+ tp->snd_cwnd_stamp = tcp_time_stamp;
+ } else {
+ /* Network starves. */
+ if (tp->packets_out > tp->snd_cwnd_used)
+ tp->snd_cwnd_used = tp->packets_out;
- mss_now = tp->mss_cache;
+ if ((s32)(tcp_time_stamp - tp->snd_cwnd_stamp) >= tp->rto)
+ tcp_cwnd_application_limited(sk);
}
+}
- if (tp->rx_opt.eff_sacks)
- mss_now -= (TCPOLEN_SACK_BASE_ALIGNED +
- (tp->rx_opt.eff_sacks * TCPOLEN_SACK_PERBLOCK));
- return mss_now;
+static unsigned int tcp_window_allows(struct tcp_sock *tp, struct sk_buff *skb, unsigned int mss_now, unsigned int cwnd)
+{
+ u32 window, cwnd_len;
+
+ window = (tp->snd_una + tp->snd_wnd - TCP_SKB_CB(skb)->seq);
+ cwnd_len = mss_now * cwnd;
+ return min(window, cwnd_len);
+}
+
+/* Can at least one segment of SKB be sent right now, according to the
+ * congestion window rules? If so, return how many segments are allowed.
+ */
+static inline unsigned int tcp_cwnd_test(struct tcp_sock *tp, struct sk_buff *skb)
+{
+ u32 in_flight, cwnd;
+
+ /* Don't be strict about the congestion window for the final FIN. */
+ if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+ return 1;
+
+ in_flight = tcp_packets_in_flight(tp);
+ cwnd = tp->snd_cwnd;
+ if (in_flight < cwnd)
+ return (cwnd - in_flight);
+
+ return 0;
+}
+
+/* This must be invoked the first time we consider transmitting
+ * SKB onto the wire.
+ */
+static inline int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb)
+{
+ int tso_segs = tcp_skb_pcount(skb);
+
+ if (!tso_segs) {
+ tcp_set_skb_tso_segs(sk, skb);
+ tso_segs = tcp_skb_pcount(skb);
+ }
+ return tso_segs;
+}
+
+static inline int tcp_minshall_check(const struct tcp_sock *tp)
+{
+ return after(tp->snd_sml,tp->snd_una) &&
+ !after(tp->snd_sml, tp->snd_nxt);
+}
+
+/* Return 0, if packet can be sent now without violation Nagle's rules:
+ * 1. It is full sized.
+ * 2. Or it contains FIN. (already checked by caller)
+ * 3. Or TCP_NODELAY was set.
+ * 4. Or TCP_CORK is not set, and all sent packets are ACKed.
+ * With Minshall's modification: all sent small packets are ACKed.
+ */
+
+static inline int tcp_nagle_check(const struct tcp_sock *tp,
+ const struct sk_buff *skb,
+ unsigned mss_now, int nonagle)
+{
+ return (skb->len < mss_now &&
+ ((nonagle&TCP_NAGLE_CORK) ||
+ (!nonagle &&
+ tp->packets_out &&
+ tcp_minshall_check(tp))));
+}
+
+/* Return non-zero if the Nagle test allows this packet to be
+ * sent now.
+ */
+static inline int tcp_nagle_test(struct tcp_sock *tp, struct sk_buff *skb,
+ unsigned int cur_mss, int nonagle)
+{
+ /* Nagle rule does not apply to frames, which sit in the middle of the
+ * write_queue (they have no chances to get new data).
+ *
+ * This is implemented in the callers, where they modify the 'nonagle'
+ * argument based upon the location of SKB in the send queue.
+ */
+ if (nonagle & TCP_NAGLE_PUSH)
+ return 1;
+
+ /* Don't use the nagle rule for urgent data (or for the final FIN). */
+ if (tp->urg_mode ||
+ (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN))
+ return 1;
+
+ if (!tcp_nagle_check(tp, skb, cur_mss, nonagle))
+ return 1;
+
+ return 0;
+}
+
+/* Does at least the first segment of SKB fit into the send window? */
+static inline int tcp_snd_wnd_test(struct tcp_sock *tp, struct sk_buff *skb, unsigned int cur_mss)
+{
+ u32 end_seq = TCP_SKB_CB(skb)->end_seq;
+
+ if (skb->len > cur_mss)
+ end_seq = TCP_SKB_CB(skb)->seq + cur_mss;
+
+ return !after(end_seq, tp->snd_una + tp->snd_wnd);
+}
+
+/* This checks if the data bearing packet SKB (usually sk->sk_send_head)
+ * should be put on the wire right now. If so, it returns the number of
+ * packets allowed by the congestion window.
+ */
+static unsigned int tcp_snd_test(struct sock *sk, struct sk_buff *skb,
+ unsigned int cur_mss, int nonagle)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ unsigned int cwnd_quota;
+
+ tcp_init_tso_segs(sk, skb);
+
+ if (!tcp_nagle_test(tp, skb, cur_mss, nonagle))
+ return 0;
+
+ cwnd_quota = tcp_cwnd_test(tp, skb);
+ if (cwnd_quota &&
+ !tcp_snd_wnd_test(tp, skb, cur_mss))
+ cwnd_quota = 0;
+
+ return cwnd_quota;
+}
+
+static inline int tcp_skb_is_last(const struct sock *sk,
+ const struct sk_buff *skb)
+{
+ return skb->next == (struct sk_buff *)&sk->sk_write_queue;
+}
+
+int tcp_may_send_now(struct sock *sk, struct tcp_sock *tp)
+{
+ struct sk_buff *skb = sk->sk_send_head;
+
+ return (skb &&
+ tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
+ (tcp_skb_is_last(sk, skb) ?
+ TCP_NAGLE_PUSH :
+ tp->nonagle)));
+}
+
+/* Trim TSO SKB to LEN bytes, put the remaining data into a new packet
+ * which is put after SKB on the list. It is very much like
+ * tcp_fragment() except that it may make several kinds of assumptions
+ * in order to speed up the splitting operation. In particular, we
+ * know that all the data is in scatter-gather pages, and that the
+ * packet has never been sent out before (and thus is not cloned).
+ */
+static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len)
+{
+ struct sk_buff *buff;
+ int nlen = skb->len - len;
+ u16 flags;
+
+ /* All of a TSO frame must be composed of paged data. */
+ BUG_ON(skb->len != skb->data_len);
+
+ buff = sk_stream_alloc_pskb(sk, 0, 0, GFP_ATOMIC);
+ if (unlikely(buff == NULL))
+ return -ENOMEM;
+
+ buff->truesize = nlen;
+ skb->truesize -= nlen;
+
+ /* Correct the sequence numbers. */
+ TCP_SKB_CB(buff)->seq = TCP_SKB_CB(skb)->seq + len;
+ TCP_SKB_CB(buff)->end_seq = TCP_SKB_CB(skb)->end_seq;
+ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(buff)->seq;
+
+ /* PSH and FIN should only be set in the second packet. */
+ flags = TCP_SKB_CB(skb)->flags;
+ TCP_SKB_CB(skb)->flags = flags & ~(TCPCB_FLAG_FIN|TCPCB_FLAG_PSH);
+ TCP_SKB_CB(buff)->flags = flags;
+
+ /* This packet was never sent out yet, so no SACK bits. */
+ TCP_SKB_CB(buff)->sacked = 0;
+
+ buff->ip_summed = skb->ip_summed = CHECKSUM_HW;
+ skb_split(skb, buff, len);
+
+ /* Fix up tso_factor for both original and new SKB. */
+ tcp_set_skb_tso_segs(sk, skb);
+ tcp_set_skb_tso_segs(sk, buff);
+
+ /* Link BUFF into the send queue. */
+ skb_header_release(buff);
+ __skb_append(skb, buff);
+
+ return 0;
+}
+
+/* Try to defer sending, if possible, in order to minimize the amount
+ * of TSO splitting we do. View it as a kind of TSO Nagle test.
+ *
+ * This algorithm is from John Heffner.
+ */
+static int tcp_tso_should_defer(struct sock *sk, struct tcp_sock *tp, struct sk_buff *skb)
+{
+ u32 send_win, cong_win, limit, in_flight;
+
+ if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)
+ return 0;
+
+ if (tp->ca_state != TCP_CA_Open)
+ return 0;
+
+ in_flight = tcp_packets_in_flight(tp);
+
+ BUG_ON(tcp_skb_pcount(skb) <= 1 ||
+ (tp->snd_cwnd <= in_flight));
+
+ send_win = (tp->snd_una + tp->snd_wnd) - TCP_SKB_CB(skb)->seq;
+
+ /* From in_flight test above, we know that cwnd > in_flight. */
+ cong_win = (tp->snd_cwnd - in_flight) * tp->mss_cache;
+
+ limit = min(send_win, cong_win);
+
+ /* If sk_send_head can be sent fully now, just do it. */
+ if (skb->len <= limit)
+ return 0;
+
+ if (sysctl_tcp_tso_win_divisor) {
+ u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
+
+ /* If at least some fraction of a window is available,
+ * just use it.
+ */
+ chunk /= sysctl_tcp_tso_win_divisor;
+ if (limit >= chunk)
+ return 0;
+ } else {
+ /* Different approach, try not to defer past a single
+ * ACK. Receiver should ACK every other full sized
+ * frame, so if we have space for more than 3 frames
+ * then send now.
+ */
+ if (limit > tcp_max_burst(tp) * tp->mss_cache)
+ return 0;
+ }
+
+ /* Ok, it looks like it is advisable to defer. */
+ return 1;
}
/* This routine writes packets to the network. It advances the
@@ -734,57 +958,158 @@ unsigned int tcp_current_mss(struct sock *sk, int large)
* Returns 1, if no segments are in flight and we have queued segments, but
* cannot send anything now because of SWS or another problem.
*/
-int tcp_write_xmit(struct sock *sk, int nonagle)
+static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle)
{
struct tcp_sock *tp = tcp_sk(sk);
- unsigned int mss_now;
+ struct sk_buff *skb;
+ unsigned int tso_segs, sent_pkts;
+ int cwnd_quota;
/* If we are closed, the bytes will have to remain here.
* In time closedown will finish, we empty the write queue and all
* will be happy.
*/
- if (sk->sk_state != TCP_CLOSE) {
- struct sk_buff *skb;
- int sent_pkts = 0;
+ if (unlikely(sk->sk_state == TCP_CLOSE))
+ return 0;
+
+ skb = sk->sk_send_head;
+ if (unlikely(!skb))
+ return 0;
+
+ tso_segs = tcp_init_tso_segs(sk, skb);
+ cwnd_quota = tcp_cwnd_test(tp, skb);
+ if (unlikely(!cwnd_quota))
+ goto out;
+
+ sent_pkts = 0;
+ while (likely(tcp_snd_wnd_test(tp, skb, mss_now))) {
+ BUG_ON(!tso_segs);
+
+ if (tso_segs == 1) {
+ if (unlikely(!tcp_nagle_test(tp, skb, mss_now,
+ (tcp_skb_is_last(sk, skb) ?
+ nonagle : TCP_NAGLE_PUSH))))
+ break;
+ } else {
+ if (tcp_tso_should_defer(sk, tp, skb))
+ break;
+ }
- /* Account for SACKS, we may need to fragment due to this.
- * It is just like the real MSS changing on us midstream.
- * We also handle things correctly when the user adds some
- * IP options mid-stream. Silly to do, but cover it.
- */
- mss_now = tcp_current_mss(sk, 1);
-
- while ((skb = sk->sk_send_head) &&
- tcp_snd_test(sk, skb, mss_now,
- tcp_skb_is_last(sk, skb) ? nonagle :
- TCP_NAGLE_PUSH)) {
- if (skb->len > mss_now) {
- if (tcp_fragment(sk, skb, mss_now))
+ if (tso_segs > 1) {
+ u32 limit = tcp_window_allows(tp, skb,
+ mss_now, cwnd_quota);
+
+ if (skb->len < limit) {
+ unsigned int trim = skb->len % mss_now;
+
+ if (trim)
+ limit = skb->len - trim;
+ }
+ if (skb->len > limit) {
+ if (tso_fragment(sk, skb, limit))
break;
}
-
- TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_tso_set_push(skb);
- if (tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC)))
+ } else if (unlikely(skb->len > mss_now)) {
+ if (unlikely(tcp_fragment(sk, skb, mss_now)))
break;
+ }
- /* Advance the send_head. This one is sent out.
- * This call will increment packets_out.
- */
- update_send_head(sk, tp, skb);
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+
+ if (unlikely(tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC))))
+ break;
+
+ /* Advance the send_head. This one is sent out.
+ * This call will increment packets_out.
+ */
+ update_send_head(sk, tp, skb);
+
+ tcp_minshall_update(tp, mss_now, skb);
+ sent_pkts++;
+
+ /* Do not optimize this to use tso_segs. If we chopped up
+ * the packet above, tso_segs will no longer be valid.
+ */
+ cwnd_quota -= tcp_skb_pcount(skb);
+
+ BUG_ON(cwnd_quota < 0);
+ if (!cwnd_quota)
+ break;
+
+ skb = sk->sk_send_head;
+ if (!skb)
+ break;
+ tso_segs = tcp_init_tso_segs(sk, skb);
+ }
+
+ if (likely(sent_pkts)) {
+ tcp_cwnd_validate(sk, tp);
+ return 0;
+ }
+out:
+ return !tp->packets_out && sk->sk_send_head;
+}
+
+/* Push out any pending frames which were held back due to
+ * TCP_CORK or attempt at coalescing tiny packets.
+ * The socket must be locked by the caller.
+ */
+void __tcp_push_pending_frames(struct sock *sk, struct tcp_sock *tp,
+ unsigned int cur_mss, int nonagle)
+{
+ struct sk_buff *skb = sk->sk_send_head;
+
+ if (skb) {
+ if (tcp_write_xmit(sk, cur_mss, nonagle))
+ tcp_check_probe_timer(sk, tp);
+ }
+}
+
+/* Send _single_ skb sitting at the send head. This function requires
+ * true push pending frames to setup probe timer etc.
+ */
+void tcp_push_one(struct sock *sk, unsigned int mss_now)
+{
+ struct tcp_sock *tp = tcp_sk(sk);
+ struct sk_buff *skb = sk->sk_send_head;
+ unsigned int tso_segs, cwnd_quota;
+
+ BUG_ON(!skb || skb->len < mss_now);
+
+ tso_segs = tcp_init_tso_segs(sk, skb);
+ cwnd_quota = tcp_snd_test(sk, skb, mss_now, TCP_NAGLE_PUSH);
+
+ if (likely(cwnd_quota)) {
+ BUG_ON(!tso_segs);
- tcp_minshall_update(tp, mss_now, skb);
- sent_pkts = 1;
+ if (tso_segs > 1) {
+ u32 limit = tcp_window_allows(tp, skb,
+ mss_now, cwnd_quota);
+
+ if (skb->len < limit) {
+ unsigned int trim = skb->len % mss_now;
+
+ if (trim)
+ limit = skb->len - trim;
+ }
+ if (skb->len > limit) {
+ if (unlikely(tso_fragment(sk, skb, limit)))
+ return;
+ }
+ } else if (unlikely(skb->len > mss_now)) {
+ if (unlikely(tcp_fragment(sk, skb, mss_now)))
+ return;
}
- if (sent_pkts) {
+ /* Send it out now. */
+ TCP_SKB_CB(skb)->when = tcp_time_stamp;
+
+ if (likely(!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation)))) {
+ update_send_head(sk, tp, skb);
tcp_cwnd_validate(sk, tp);
- return 0;
+ return;
}
-
- return !tp->packets_out && sk->sk_send_head;
}
- return 0;
}
/* This function returns the amount that we can raise the
@@ -1044,7 +1369,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
if (sk->sk_route_caps & NETIF_F_TSO) {
sk->sk_route_caps &= ~NETIF_F_TSO;
sock_set_flag(sk, SOCK_NO_LARGESEND);
- tp->mss_cache = tp->mss_cache_std;
}
if (tcp_trim_head(sk, skb, tp->snd_una - TCP_SKB_CB(skb)->seq))
@@ -1106,7 +1430,6 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
* is still in somebody's hands, else make a clone.
*/
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_tso_set_push(skb);
err = tcp_transmit_skb(sk, (skb_cloned(skb) ?
pskb_copy(skb, GFP_ATOMIC):
@@ -1290,7 +1613,7 @@ void tcp_send_fin(struct sock *sk)
* was unread data in the receive queue. This behavior is recommended
* by draft-ietf-tcpimpl-prob-03.txt section 3.10. -DaveM
*/
-void tcp_send_active_reset(struct sock *sk, int priority)
+void tcp_send_active_reset(struct sock *sk, unsigned int __nocast priority)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
@@ -1449,7 +1772,6 @@ static inline void tcp_connect_init(struct sock *sk)
tp->window_clamp = dst_metric(dst, RTAX_WINDOW);
tp->advmss = dst_metric(dst, RTAX_ADVMSS);
tcp_initialize_rcv_mss(sk);
- tcp_ca_init(tp);
tcp_select_initial_window(tcp_full_space(sk),
tp->advmss - (tp->rx_opt.ts_recent_stamp ? tp->tcp_header_len - sizeof(struct tcphdr) : 0),
@@ -1503,7 +1825,6 @@ int tcp_connect(struct sock *sk)
TCP_SKB_CB(buff)->end_seq = tp->write_seq;
tp->snd_nxt = tp->write_seq;
tp->pushed_seq = tp->write_seq;
- tcp_ca_init(tp);
/* Send it off. */
TCP_SKB_CB(buff)->when = tcp_time_stamp;
@@ -1677,14 +1998,12 @@ int tcp_write_wakeup(struct sock *sk)
if (sk->sk_route_caps & NETIF_F_TSO) {
sock_set_flag(sk, SOCK_NO_LARGESEND);
sk->sk_route_caps &= ~NETIF_F_TSO;
- tp->mss_cache = tp->mss_cache_std;
}
} else if (!tcp_skb_pcount(skb))
tcp_set_skb_tso_segs(sk, skb);
TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH;
TCP_SKB_CB(skb)->when = tcp_time_stamp;
- tcp_tso_set_push(skb);
err = tcp_transmit_skb(sk, skb_clone(skb, GFP_ATOMIC));
if (!err) {
update_send_head(sk, tp, skb);
diff --git a/net/ipv4/tcp_scalable.c b/net/ipv4/tcp_scalable.c
new file mode 100644
index 000000000000..70e108e15c71
--- /dev/null
+++ b/net/ipv4/tcp_scalable.c
@@ -0,0 +1,68 @@
+/* Tom Kelly's Scalable TCP
+ *
+ * See htt://www-lce.eng.cam.ac.uk/~ctk21/scalable/
+ *
+ * John Heffner <jheffner@sc.edu>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/tcp.h>
+
+/* These factors derived from the recommended values in the aer:
+ * .01 and and 7/8. We use 50 instead of 100 to account for
+ * delayed ack.
+ */
+#define TCP_SCALABLE_AI_CNT 50U
+#define TCP_SCALABLE_MD_SCALE 3
+
+static void tcp_scalable_cong_avoid(struct tcp_sock *tp, u32 ack, u32 rtt,
+ u32 in_flight, int flag)
+{
+ if (in_flight < tp->snd_cwnd)
+ return;
+
+ if (tp->snd_cwnd <= tp->snd_ssthresh) {
+ tp->snd_cwnd++;
+ } else {
+ tp->snd_cwnd_cnt++;
+ if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
+ tp->snd_cwnd++;
+ tp->snd_cwnd_cnt = 0;
+ }
+ }
+ tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
+ tp->snd_cwnd_stamp = tcp_time_stamp;
+}
+
+static u32 tcp_scalable_ssthresh(struct tcp_sock *tp)
+{
+ return max(tp->snd_cwnd - (tp->snd_cwnd>>TCP_SCALABLE_MD_SCALE), 2U);
+}
+
+
+static struct tcp_congestion_ops tcp_scalable = {
+ .ssthresh = tcp_scalable_ssthresh,
+ .cong_avoid = tcp_scalable_cong_avoid,
+ .min_cwnd = tcp_reno_min_cwnd,
+
+ .owner = THIS_MODULE,
+ .name = "scalable",
+};
+
+static int __init tcp_scalable_register(void)
+{
+ return tcp_register_congestion_control(&tcp_scalable);
+}
+
+static void __exit tcp_scalable_unregister(void)
+{
+ tcp_unregister_congestion_control(&tcp_scalable);
+}
+
+module_init(tcp_scalable_register);
+module_exit(tcp_scalable_unregister);
+
+MODULE_AUTHOR("John Heffner");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Scalable TCP");
diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index b127b4498565..0084227438c2 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -231,11 +231,10 @@ static void tcp_delack_timer(unsigned long data)
}
tp->ack.pending &= ~TCP_ACK_TIMER;
- if (skb_queue_len(&tp->ucopy.prequeue)) {
+ if (!skb_queue_empty(&tp->ucopy.prequeue)) {
struct sk_buff *skb;
- NET_ADD_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED,
- skb_queue_len(&tp->ucopy.prequeue));
+ NET_INC_STATS_BH(LINUX_MIB_TCPSCHEDULERFAILED);
while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL)
sk->sk_backlog_rcv(sk, skb);
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c
new file mode 100644
index 000000000000..9bd443db5193
--- /dev/null
+++ b/net/ipv4/tcp_vegas.c
@@ -0,0 +1,411 @@
+/*
+ * TCP Vegas congestion control
+ *
+ * This is based on the congestion detection/avoidance scheme described in
+ * Lawrence S. Brakmo and Larry L. Peterson.
+ * "TCP Vegas: End to end congestion avoidance on a global internet."
+ * IEEE Journal on Selected Areas in Communication, 13(8):1465--1480,
+ * October 1995. Available from:
+ * ftp://ftp.cs.arizona.edu/xkernel/Papers/jsac.ps
+ *
+ * See http://www.cs.arizona.edu/xkernel/ for their implementation.
+ * The main aspects that distinguish this implementation from the
+ * Arizona Vegas implementation are:
+ * o We do not change the loss detection or recovery mechanisms of
+ * Linux in any way. Linux already recovers from losses quite well,
+ * using fine-grained timers, NewReno, and FACK.
+ * o To avoid the performance penalty imposed by increasing cwnd
+ * only every-other RTT during slow start, we increase during
+ * every RTT during slow start, just like Reno.
+ * o Largely to allow continuous cwnd growth during slow start,
+ * we use the rate at which ACKs come back as the "actual"
+ * rate, rather than the rate at which data is sent.
+ * o To speed convergence to the right rate, we set the cwnd
+ * to achieve the right ("actual") rate when we exit slow start.
+ * o To filter out the noise caused by delayed ACKs, we use the
+ * minimum RTT sample observed during the last RTT to calculate
+ * the actual rate.
+ * o When the sender re-starts from idle, it waits until it has
+ * received ACKs for an entire flight of new data before making
+ * a cwnd adjustment decision. The original Vegas implementation
+ * assumed senders never went idle.
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/tcp_diag.h>
+
+#include <net/tcp.h>
+
+/* Default values of the Vegas variables, in fixed-point representation
+ * with V_PARAM_SHIFT bits to the right of the binary point.
+ */
+#define V_PARAM_SHIFT 1
+static int alpha = 1<<V_PARAM_SHIFT;
+static int beta = 3<<V_PARAM_SHIFT;
+static int gamma = 1<<V_PARAM_SHIFT;
+
+module_param(alpha, int, 0644);
+MODULE_PARM_DESC(alpha, "lower bound of packets in network (scale by 2)");
+module_param(beta, int, 0644);
+MODULE_PARM_DESC(beta, "upper bound of packets in network (scale by 2)");
+module_param(gamma, int, 0644);
+MODULE_PARM_DESC(gamma, "limit on increase (scale by 2)");
+
+
+/* Vegas variables */
+struct vegas {
+ u32 beg_snd_nxt; /* right edge during last RTT */
+ u32 beg_snd_una; /* left edge during last RTT */
+ u32 beg_snd_cwnd; /* saves the size of the cwnd */
+ u8 doing_vegas_now;/* if true, do vegas for this RTT */
+ u16 cntRTT; /* # of RTTs measured within last RTT */
+ u32 minRTT; /* min of RTTs measured within last RTT (in usec) */
+ u32 baseRTT; /* the min of all Vegas RTT measurements seen (in usec) */
+};
+
+/* There are several situations when we must "re-start" Vegas:
+ *
+ * o when a connection is established
+ * o after an RTO
+ * o after fast recovery
+ * o when we send a packet and there is no outstanding
+ * unacknowledged data (restarting an idle connection)
+ *
+ * In these circumstances we cannot do a Vegas calculation at the
+ * end of the first RTT, because any calculation we do is using
+ * stale info -- both the saved cwnd and congestion feedback are
+ * stale.
+ *
+ * Instead we must wait until the completion of an RTT during
+ * which we actually receive ACKs.
+ */
+static inline void vegas_enable(struct tcp_sock *tp)
+{
+ struct vegas *vegas = tcp_ca(tp);
+
+ /* Begin taking Vegas samples next time we send something. */
+ vegas->doing_vegas_now = 1;
+
+ /* Set the beginning of the next send window. */
+ vegas->beg_snd_nxt = tp->snd_nxt;
+
+ vegas->cntRTT = 0;
+ vegas->minRTT = 0x7fffffff;
+}
+
+/* Stop taking Vegas samples for now. */
+static inline void vegas_disable(struct tcp_sock *tp)
+{
+ struct vegas *vegas = tcp_ca(tp);
+
+ vegas->doing_vegas_now = 0;
+}
+
+static void tcp_vegas_init(struct tcp_sock *tp)
+{
+ struct vegas *vegas = tcp_ca(tp);
+
+ vegas->baseRTT = 0x7fffffff;
+ vegas_enable(tp);
+}
+
+/* Do RTT sampling needed for Vegas.
+ * Basically we:
+ * o min-filter RTT samples from within an RTT to get the current
+ * propagation delay + queuing delay (we are min-filtering to try to
+ * avoid the effects of delayed ACKs)
+ * o min-filter RTT samples from a much longer window (forever for now)
+ * to find the propagation delay (baseRTT)
+ */
+static void tcp_vegas_rtt_calc(struct tcp_sock *tp, u32 usrtt)
+{
+ struct vegas *vegas = tcp_ca(tp);
+ u32 vrtt = usrtt + 1; /* Never allow zero rtt or baseRTT */
+
+ /* Filter to find propagation delay: */
+ if (vrtt < vegas->baseRTT)
+ vegas->baseRTT = vrtt;
+
+ /* Find the min RTT during the last RTT to find
+ * the current prop. delay + queuing delay:
+ */
+ vegas->minRTT = min(vegas->minRTT, vrtt);
+ vegas->cntRTT++;
+}
+
+static void tcp_vegas_state(struct tcp_sock *tp, u8 ca_state)
+{
+
+ if (ca_state == TCP_CA_Open)
+ vegas_enable(tp);
+ else
+ vegas_disable(tp);
+}
+
+/*
+ * If the connection is idle and we are restarting,
+ * then we don't want to do any Vegas calculations
+ * until we get fresh RTT samples. So when we
+ * restart, we reset our Vegas state to a clean
+ * slate. After we get acks for this flight of
+ * packets, _then_ we can make Vegas calculations
+ * again.
+ */
+static void tcp_vegas_cwnd_event(struct tcp_sock *tp, enum tcp_ca_event event)
+{
+ if (event == CA_EVENT_CWND_RESTART ||
+ event == CA_EVENT_TX_START)
+ tcp_vegas_init(tp);
+}
+
+static void tcp_vegas_cong_avoid(struct tcp_sock *tp, u32 ack,
+ u32 seq_rtt, u32 in_flight, int flag)
+{
+ struct vegas *vegas = tcp_ca(tp);
+
+ if (!vegas->doing_vegas_now)
+ return tcp_reno_cong_avoid(tp, ack, seq_rtt, in_flight, flag);
+
+ /* The key players are v_beg_snd_una and v_beg_snd_nxt.
+ *
+ * These are so named because they represent the approximate values
+ * of snd_una and snd_nxt at the beginning of the current RTT. More
+ * precisely, they represent the amount of data sent during the RTT.
+ * At the end of the RTT, when we receive an ACK for v_beg_snd_nxt,
+ * we will calculate that (v_beg_snd_nxt - v_beg_snd_una) outstanding
+ * bytes of data have been ACKed during the course of the RTT, giving
+ * an "actual" rate of:
+ *
+ * (v_beg_snd_nxt - v_beg_snd_una) / (rtt duration)
+ *
+ * Unfortunately, v_beg_snd_una is not exactly equal to snd_una,
+ * because delayed ACKs can cover more than one segment, so they
+ * don't line up nicely with the boundaries of RTTs.
+ *
+ * Another unfortunate fact of life is that delayed ACKs delay the
+ * advance of the left edge of our send window, so that the number
+ * of bytes we send in an RTT is often less than our cwnd will allow.
+ * So we keep track of our cwnd separately, in v_beg_snd_cwnd.
+ */
+
+ if (after(ack, vegas->beg_snd_nxt)) {
+ /* Do the Vegas once-per-RTT cwnd adjustment. */
+ u32 old_wnd, old_snd_cwnd;
+
+
+ /* Here old_wnd is essentially the window of data that was
+ * sent during the previous RTT, and has all
+ * been acknowledged in the course of the RTT that ended
+ * with the ACK we just received. Likewise, old_snd_cwnd
+ * is the cwnd during the previous RTT.
+ */
+ old_wnd = (vegas->beg_snd_nxt - vegas->beg_snd_una) /
+ tp->mss_cache;
+ old_snd_cwnd = vegas->beg_snd_cwnd;
+
+ /* Save the extent of the current window so we can use this
+ * at the end of the next RTT.
+ */
+ vegas->beg_snd_una = vegas->beg_snd_nxt;
+ vegas->beg_snd_nxt = tp->snd_nxt;
+ vegas->beg_snd_cwnd = tp->snd_cwnd;
+
+ /* Take into account the current RTT sample too, to
+ * decrease the impact of delayed acks. This double counts
+ * this sample since we count it for the next window as well,
+ * but that's not too awful, since we're taking the min,
+ * rather than averaging.
+ */
+ tcp_vegas_rtt_calc(tp, seq_rtt*1000);
+
+ /* We do the Vegas calculations only if we got enough RTT
+ * samples that we can be reasonably sure that we got
+ * at least one RTT sample that wasn't from a delayed ACK.
+ * If we only had 2 samples total,
+ * then that means we're getting only 1 ACK per RTT, which
+ * means they're almost certainly delayed ACKs.
+ * If we have 3 samples, we should be OK.
+ */
+
+ if (vegas->cntRTT <= 2) {
+ /* We don't have enough RTT samples to do the Vegas
+ * calculation, so we'll behave like Reno.
+ */
+ if (tp->snd_cwnd > tp->snd_ssthresh)
+ tp->snd_cwnd++;
+ } else {
+ u32 rtt, target_cwnd, diff;
+
+ /* We have enough RTT samples, so, using the Vegas
+ * algorithm, we determine if we should increase or
+ * decrease cwnd, and by how much.
+ */
+
+ /* Pluck out the RTT we are using for the Vegas
+ * calculations. This is the min RTT seen during the
+ * last RTT. Taking the min filters out the effects
+ * of delayed ACKs, at the cost of noticing congestion
+ * a bit later.
+ */
+ rtt = vegas->minRTT;
+
+ /* Calculate the cwnd we should have, if we weren't
+ * going too fast.
+ *
+ * This is:
+ * (actual rate in segments) * baseRTT
+ * We keep it as a fixed point number with
+ * V_PARAM_SHIFT bits to the right of the binary point.
+ */
+ target_cwnd = ((old_wnd * vegas->baseRTT)
+ << V_PARAM_SHIFT) / rtt;
+
+ /* Calculate the difference between the window we had,
+ * and the window we would like to have. This quantity
+ * is the "Diff" from the Arizona Vegas papers.
+ *
+ * Again, this is a fixed point number with
+ * V_PARAM_SHIFT bits to the right of the binary
+ * point.
+ */
+ diff = (old_wnd << V_PARAM_SHIFT) - target_cwnd;
+
+ if (tp->snd_cwnd < tp->snd_ssthresh) {
+ /* Slow start. */
+ if (diff > gamma) {
+ /* Going too fast. Time to slow down
+ * and switch to congestion avoidance.
+ */
+ tp->snd_ssthresh = 2;
+
+ /* Set cwnd to match the actual rate
+ * exactly:
+ * cwnd = (actual rate) * baseRTT
+ * Then we add 1 because the integer
+ * truncation robs us of full link
+ * utilization.
+ */
+ tp->snd_cwnd = min(tp->snd_cwnd,
+ (target_cwnd >>
+ V_PARAM_SHIFT)+1);
+
+ }
+ } else {
+ /* Congestion avoidance. */
+ u32 next_snd_cwnd;
+
+ /* Figure out where we would like cwnd
+ * to be.
+ */
+ if (diff > beta) {
+ /* The old window was too fast, so
+ * we slow down.
+ */
+ next_snd_cwnd = old_snd_cwnd - 1;
+ } else if (diff < alpha) {
+ /* We don't have enough extra packets
+ * in the network, so speed up.
+ */
+ next_snd_cwnd = old_snd_cwnd + 1;
+ } else {
+ /* Sending just as fast as we
+ * should be.
+ */
+ next_snd_cwnd = old_snd_cwnd;
+ }
+
+ /* Adjust cwnd upward or downward, toward the
+ * desired value.
+ */
+ if (next_snd_cwnd > tp->snd_cwnd)
+ tp->snd_cwnd++;
+ else if (next_snd_cwnd < tp->snd_cwnd)
+ tp->snd_cwnd--;
+ }
+ }
+
+ /* Wipe the slate clean for the next RTT. */
+ vegas->cntRTT = 0;
+ vegas->minRTT = 0x7fffffff;
+ }
+
+ /* The following code is executed for every ack we receive,
+ * except for conditions checked in should_advance_cwnd()
+ * before the call to tcp_cong_avoid(). Mainly this means that
+ * we only execute this code if the ack actually acked some
+ * data.
+ */
+
+ /* If we are in slow start, increase our cwnd in response to this ACK.
+ * (If we are not in slow start then we are in congestion avoidance,
+ * and adjust our congestion window only once per RTT. See the code
+ * above.)
+ */
+ if (tp->snd_cwnd <= tp->snd_ssthresh)
+ tp->snd_cwnd++;
+
+ /* to keep cwnd from growing without bound */
+ tp->snd_cwnd = min_t(u32, tp->snd_cwnd, tp->snd_cwnd_clamp);
+
+ /* Make sure that we are never so timid as to reduce our cwnd below
+ * 2 MSS.
+ *
+ * Going below 2 MSS would risk huge delayed ACKs from our receiver.
+ */
+ tp->snd_cwnd = max(tp->snd_cwnd, 2U);
+}
+
+/* Extract info for Tcp socket info provided via netlink. */
+static void tcp_vegas_get_info(struct tcp_sock *tp, u32 ext,
+ struct sk_buff *skb)
+{
+ const struct vegas *ca = tcp_ca(tp);
+ if (ext & (1<<(TCPDIAG_VEGASINFO-1))) {
+ struct tcpvegas_info *info;
+
+ info = RTA_DATA(__RTA_PUT(skb, TCPDIAG_VEGASINFO,
+ sizeof(*info)));
+
+ info->tcpv_enabled = ca->doing_vegas_now;
+ info->tcpv_rttcnt = ca->cntRTT;
+ info->tcpv_rtt = ca->baseRTT;
+ info->tcpv_minrtt = ca->minRTT;
+ rtattr_failure: ;
+ }
+}
+
+static struct tcp_congestion_ops tcp_vegas = {
+ .init = tcp_vegas_init,
+ .ssthresh = tcp_reno_ssthresh,
+ .cong_avoid = tcp_vegas_cong_avoid,
+ .min_cwnd = tcp_reno_min_cwnd,
+ .rtt_sample = tcp_vegas_rtt_calc,
+ .set_state = tcp_vegas_state,
+ .cwnd_event = tcp_vegas_cwnd_event,
+ .get_info = tcp_vegas_get_info,
+
+ .owner = THIS_MODULE,
+ .name = "vegas",
+};
+
+static int __init tcp_vegas_register(void)
+{
+ BUG_ON(sizeof(struct vegas) > TCP_CA_PRIV_SIZE);
+ tcp_register_congestion_control(&tcp_vegas);
+ return 0;
+}
+
+static void __exit tcp_vegas_unregister(void)
+{
+ tcp_unregister_congestion_control(&tcp_vegas);
+}
+
+module_init(tcp_vegas_register);
+module_exit(tcp_vegas_unregister);
+
+MODULE_AUTHOR("Stephen Hemminger");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TCP Vegas");
diff --git a/net/ipv4/tcp_westwood.c b/net/ipv4/tcp_westwood.c
new file mode 100644
index 000000000000..ef827242c940
--- /dev/null
+++ b/net/ipv4/tcp_westwood.c
@@ -0,0 +1,259 @@
+/*
+ * TCP Westwood+
+ *
+ * Angelo Dell'Aera: TCP Westwood+ support
+ */
+
+#include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/tcp_diag.h>
+#include <net/tcp.h>
+
+/* TCP Westwood structure */
+struct westwood {
+ u32 bw_ns_est; /* first bandwidth estimation..not too smoothed 8) */
+ u32 bw_est; /* bandwidth estimate */
+ u32 rtt_win_sx; /* here starts a new evaluation... */
+ u32 bk;
+ u32 snd_una; /* used for evaluating the number of acked bytes */
+ u32 cumul_ack;
+ u32 accounted;
+ u32 rtt;
+ u32 rtt_min; /* minimum observed RTT */
+};
+
+
+/* TCP Westwood functions and constants */
+#define TCP_WESTWOOD_RTT_MIN (HZ/20) /* 50ms */
+#define TCP_WESTWOOD_INIT_RTT (20*HZ) /* maybe too conservative?! */
+
+/*
+ * @tcp_westwood_create
+ * This function initializes fields used in TCP Westwood+,
+ * it is called after the initial SYN, so the sequence numbers
+ * are correct but new passive connections we have no
+ * information about RTTmin at this time so we simply set it to
+ * TCP_WESTWOOD_INIT_RTT. This value was chosen to be too conservative
+ * since in this way we're sure it will be updated in a consistent
+ * way as soon as possible. It will reasonably happen within the first
+ * RTT period of the connection lifetime.
+ */
+static void tcp_westwood_init(struct tcp_sock *tp)
+{
+ struct westwood *w = tcp_ca(tp);
+
+ w->bk = 0;
+ w->bw_ns_est = 0;
+ w->bw_est = 0;
+ w->accounted = 0;
+ w->cumul_ack = 0;
+ w->rtt_min = w->rtt = TCP_WESTWOOD_INIT_RTT;
+ w->rtt_win_sx = tcp_time_stamp;
+ w->snd_una = tp->snd_una;
+}
+
+/*
+ * @westwood_do_filter
+ * Low-pass filter. Implemented using constant coefficients.
+ */
+static inline u32 westwood_do_filter(u32 a, u32 b)
+{
+ return (((7 * a) + b) >> 3);
+}
+
+static inline void westwood_filter(struct westwood *w, u32 delta)
+{
+ w->bw_ns_est = westwood_do_filter(w->bw_ns_est, w->bk / delta);
+ w->bw_est = westwood_do_filter(w->bw_est, w->bw_ns_est);
+}
+
+/*
+ * @westwood_pkts_acked
+ * Called after processing group of packets.
+ * but all westwood needs is the last sample of srtt.
+ */
+static void tcp_westwood_pkts_acked(struct tcp_sock *tp, u32 cnt)
+{
+ struct westwood *w = tcp_ca(tp);
+ if (cnt > 0)
+ w->rtt = tp->srtt >> 3;
+}
+
+/*
+ * @westwood_update_window
+ * It updates RTT evaluation window if it is the right moment to do
+ * it. If so it calls filter for evaluating bandwidth.
+ */
+static void westwood_update_window(struct tcp_sock *tp)
+{
+ struct westwood *w = tcp_ca(tp);
+ s32 delta = tcp_time_stamp - w->rtt_win_sx;
+
+ /*
+ * See if a RTT-window has passed.
+ * Be careful since if RTT is less than
+ * 50ms we don't filter but we continue 'building the sample'.
+ * This minimum limit was chosen since an estimation on small
+ * time intervals is better to avoid...
+ * Obviously on a LAN we reasonably will always have
+ * right_bound = left_bound + WESTWOOD_RTT_MIN
+ */
+ if (w->rtt && delta > max_t(u32, w->rtt, TCP_WESTWOOD_RTT_MIN)) {
+ westwood_filter(w, delta);
+
+ w->bk = 0;
+ w->rtt_win_sx = tcp_time_stamp;
+ }
+}
+
+/*
+ * @westwood_fast_bw
+ * It is called when we are in fast path. In particular it is called when
+ * header prediction is successful. In such case in fact update is
+ * straight forward and doesn't need any particular care.
+ */
+static inline void westwood_fast_bw(struct tcp_sock *tp)
+{
+ struct westwood *w = tcp_ca(tp);
+
+ westwood_update_window(tp);
+
+ w->bk += tp->snd_una - w->snd_una;
+ w->snd_una = tp->snd_una;
+ w->rtt_min = min(w->rtt, w->rtt_min);
+}
+
+/*
+ * @westwood_acked_count
+ * This function evaluates cumul_ack for evaluating bk in case of
+ * delayed or partial acks.
+ */
+static inline u32 westwood_acked_count(struct tcp_sock *tp)
+{
+ struct westwood *w = tcp_ca(tp);
+
+ w->cumul_ack = tp->snd_una - w->snd_una;
+
+ /* If cumul_ack is 0 this is a dupack since it's not moving
+ * tp->snd_una.
+ */
+ if (!w->cumul_ack) {
+ w->accounted += tp->mss_cache;
+ w->cumul_ack = tp->mss_cache;
+ }
+
+ if (w->cumul_ack > tp->mss_cache) {
+ /* Partial or delayed ack */
+ if (w->accounted >= w->cumul_ack) {
+ w->accounted -= w->cumul_ack;
+ w->cumul_ack = tp->mss_cache;
+ } else {
+ w->cumul_ack -= w->accounted;
+ w->accounted = 0;
+ }
+ }
+
+ w->snd_una = tp->snd_una;
+
+ return w->cumul_ack;
+}
+
+static inline u32 westwood_bw_rttmin(const struct tcp_sock *tp)
+{
+ struct westwood *w = tcp_ca(tp);
+ return max_t(u32, (w->bw_est * w->rtt_min) / tp->mss_cache, 2);
+}
+
+/*
+ * TCP Westwood
+ * Here limit is evaluated as Bw estimation*RTTmin (for obtaining it
+ * in packets we use mss_cache). Rttmin is guaranteed to be >= 2
+ * so avoids ever returning 0.
+ */
+static u32 tcp_westwood_cwnd_min(struct tcp_sock *tp)
+{
+ return westwood_bw_rttmin(tp);
+}
+
+static void tcp_westwood_event(struct tcp_sock *tp, enum tcp_ca_event event)
+{
+ struct westwood *w = tcp_ca(tp);
+
+ switch(event) {
+ case CA_EVENT_FAST_ACK:
+ westwood_fast_bw(tp);
+ break;
+
+ case CA_EVENT_COMPLETE_CWR:
+ tp->snd_cwnd = tp->snd_ssthresh = westwood_bw_rttmin(tp);
+ break;
+
+ case CA_EVENT_FRTO:
+ tp->snd_ssthresh = westwood_bw_rttmin(tp);
+ break;
+
+ case CA_EVENT_SLOW_ACK:
+ westwood_update_window(tp);
+ w->bk += westwood_acked_count(tp);
+ w->rtt_min = min(w->rtt, w->rtt_min);
+ break;
+
+ default:
+ /* don't care */
+ break;
+ }
+}
+
+
+/* Extract info for Tcp socket info provided via netlink. */
+static void tcp_westwood_info(struct tcp_sock *tp, u32 ext,
+ struct sk_buff *skb)
+{
+ const struct westwood *ca = tcp_ca(tp);
+ if (ext & (1<<(TCPDIAG_VEGASINFO-1))) {
+ struct rtattr *rta;
+ struct tcpvegas_info *info;
+
+ rta = __RTA_PUT(skb, TCPDIAG_VEGASINFO, sizeof(*info));
+ info = RTA_DATA(rta);
+ info->tcpv_enabled = 1;
+ info->tcpv_rttcnt = 0;
+ info->tcpv_rtt = jiffies_to_usecs(ca->rtt);
+ info->tcpv_minrtt = jiffies_to_usecs(ca->rtt_min);
+ rtattr_failure: ;
+ }
+}
+
+
+static struct tcp_congestion_ops tcp_westwood = {
+ .init = tcp_westwood_init,
+ .ssthresh = tcp_reno_ssthresh,
+ .cong_avoid = tcp_reno_cong_avoid,
+ .min_cwnd = tcp_westwood_cwnd_min,
+ .cwnd_event = tcp_westwood_event,
+ .get_info = tcp_westwood_info,
+ .pkts_acked = tcp_westwood_pkts_acked,
+
+ .owner = THIS_MODULE,
+ .name = "westwood"
+};
+
+static int __init tcp_westwood_register(void)
+{
+ BUG_ON(sizeof(struct westwood) > TCP_CA_PRIV_SIZE);
+ return tcp_register_congestion_control(&tcp_westwood);
+}
+
+static void __exit tcp_westwood_unregister(void)
+{
+ tcp_unregister_congestion_control(&tcp_westwood);
+}
+
+module_init(tcp_westwood_register);
+module_exit(tcp_westwood_unregister);
+
+MODULE_AUTHOR("Stephen Hemminger, Angelo Dell'Aera");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("TCP Westwood+");
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig
index e66ca9381cfd..95163cd52ae0 100644
--- a/net/ipv6/Kconfig
+++ b/net/ipv6/Kconfig
@@ -1,6 +1,26 @@
#
# IPv6 configuration
-#
+#
+
+# IPv6 as module will cause a CRASH if you try to unload it
+config IPV6
+ tristate "The IPv6 protocol"
+ default m
+ select CRYPTO if IPV6_PRIVACY
+ select CRYPTO_MD5 if IPV6_PRIVACY
+ ---help---
+ This is complemental support for the IP version 6.
+ You will still be able to do traditional IPv4 networking as well.
+
+ For general information about IPv6, see
+ <http://playground.sun.com/pub/ipng/html/ipng-main.html>.
+ For Linux IPv6 development information, see <http://www.linux-ipv6.org>.
+ For specific information about IPv6 under Linux, read the HOWTO at
+ <http://www.bieringer.de/linux/IPv6/>.
+
+ To compile this protocol support as a module, choose M here: the
+ module will be called ipv6.
+
config IPV6_PRIVACY
bool "IPv6: Privacy Extensions (RFC 3041) support"
depends on IPV6
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index a54d4ef3fd35..77004b9456c0 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2777,7 +2777,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
read_lock_bh(&idev->lock);
switch (type) {
case UNICAST_ADDR:
- /* unicast address */
+ /* unicast address incl. temp addr */
for (ifa = idev->addr_list; ifa;
ifa = ifa->if_next, ip_idx++) {
if (ip_idx < s_ip_idx)
@@ -2788,19 +2788,6 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
NLM_F_MULTI)) <= 0)
goto done;
}
- /* temp addr */
-#ifdef CONFIG_IPV6_PRIVACY
- for (ifa = idev->tempaddr_list; ifa;
- ifa = ifa->tmp_next, ip_idx++) {
- if (ip_idx < s_ip_idx)
- continue;
- if ((err = inet6_fill_ifaddr(skb, ifa,
- NETLINK_CB(cb->skb).pid,
- cb->nlh->nlmsg_seq, RTM_NEWADDR,
- NLM_F_MULTI)) <= 0)
- goto done;
- }
-#endif
break;
case MULTICAST_ADDR:
/* multicast address */
@@ -2923,6 +2910,7 @@ static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*r), flags);
r = NLMSG_DATA(nlh);
r->ifi_family = AF_INET6;
+ r->__ifi_pad = 0;
r->ifi_type = dev->type;
r->ifi_index = dev->ifindex;
r->ifi_flags = dev_get_flags(dev);
@@ -3030,9 +3018,12 @@ static int inet6_fill_prefix(struct sk_buff *skb, struct inet6_dev *idev,
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*pmsg), flags);
pmsg = NLMSG_DATA(nlh);
pmsg->prefix_family = AF_INET6;
+ pmsg->prefix_pad1 = 0;
+ pmsg->prefix_pad2 = 0;
pmsg->prefix_ifindex = idev->dev->ifindex;
pmsg->prefix_len = pinfo->prefix_len;
pmsg->prefix_type = pinfo->type;
+ pmsg->prefix_pad3 = 0;
pmsg->prefix_flags = 0;
if (pinfo->onlink)
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 2b193e3df49a..28d9bcab0970 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -774,7 +774,6 @@ static int __init inet6_init(void)
if (if6_proc_init())
goto proc_if6_fail;
#endif
- ipv6_packet_init();
ip6_route_init();
ip6_flowlabel_init();
err = addrconf_init();
@@ -791,6 +790,8 @@ static int __init inet6_init(void)
/* Init v6 transport protocols. */
udpv6_init();
tcpv6_init();
+
+ ipv6_packet_init();
err = 0;
out:
return err;
@@ -798,7 +799,6 @@ out:
addrconf_fail:
ip6_flowlabel_cleanup();
ip6_route_cleanup();
- ipv6_packet_cleanup();
#ifdef CONFIG_PROC_FS
if6_proc_exit();
proc_if6_fail:
diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c
index 0e5f7499debb..b6c73da5ff35 100644
--- a/net/ipv6/ip6_flowlabel.c
+++ b/net/ipv6/ip6_flowlabel.c
@@ -244,7 +244,6 @@ struct ipv6_txoptions *fl6_merge_options(struct ipv6_txoptions * opt_space,
opt_space->opt_nflen = 0;
}
opt_space->dst1opt = fopt->dst1opt;
- opt_space->auth = fopt->auth;
opt_space->opt_flen = fopt->opt_flen;
return opt_space;
}
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index 06e7cdaeedc5..1f2c2f9e353f 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -465,7 +465,6 @@ static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
to->pkt_type = from->pkt_type;
to->priority = from->priority;
to->protocol = from->protocol;
- to->security = from->security;
dst_release(to->dst);
to->dst = dst_clone(from->dst);
to->dev = from->dev;
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index 562fcd14fdea..29fed6e58d0a 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -281,7 +281,7 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, struct in6_addr *addr)
}
write_unlock_bh(&ipv6_sk_mc_lock);
- return -ENOENT;
+ return -EADDRNOTAVAIL;
}
static struct inet6_dev *ip6_mc_find_dev(struct in6_addr *group, int ifindex)
@@ -386,12 +386,16 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
if (ipv6_addr_equal(&pmc->addr, group))
break;
}
- if (!pmc) /* must have a prior join */
+ if (!pmc) { /* must have a prior join */
+ err = -EINVAL;
goto done;
+ }
/* if a source filter was set, must be the same mode as before */
if (pmc->sflist) {
- if (pmc->sfmode != omode)
+ if (pmc->sfmode != omode) {
+ err = -EINVAL;
goto done;
+ }
} else if (pmc->sfmode != omode) {
/* allow mode switches for empty-set filters */
ip6_mc_add_src(idev, group, omode, 0, NULL, 0);
@@ -402,7 +406,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
psl = pmc->sflist;
if (!add) {
if (!psl)
- goto done;
+ goto done; /* err = -EADDRNOTAVAIL */
rv = !0;
for (i=0; i<psl->sl_count; i++) {
rv = memcmp(&psl->sl_addr[i], source,
@@ -411,7 +415,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
break;
}
if (rv) /* source not found */
- goto done;
+ goto done; /* err = -EADDRNOTAVAIL */
/* special case - (INCLUDE, empty) == LEAVE_GROUP */
if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
@@ -488,6 +492,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
struct inet6_dev *idev;
struct ipv6_pinfo *inet6 = inet6_sk(sk);
struct ip6_sf_socklist *newpsl, *psl;
+ int leavegroup = 0;
int i, err;
group = &((struct sockaddr_in6 *)&gsf->gf_group)->sin6_addr;
@@ -503,7 +508,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
if (!idev)
return -ENODEV;
dev = idev->dev;
- err = -EADDRNOTAVAIL;
+
+ err = 0;
+ if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
+ leavegroup = 1;
+ goto done;
+ }
for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
if (pmc->ifindex != gsf->gf_interface)
@@ -511,8 +521,10 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
if (ipv6_addr_equal(&pmc->addr, group))
break;
}
- if (!pmc) /* must have a prior join */
+ if (!pmc) { /* must have a prior join */
+ err = -EINVAL;
goto done;
+ }
if (gsf->gf_numsrc) {
newpsl = (struct ip6_sf_socklist *)sock_kmalloc(sk,
IP6_SFLSIZE(gsf->gf_numsrc), GFP_ATOMIC);
@@ -544,10 +556,13 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
pmc->sflist = newpsl;
pmc->sfmode = gsf->gf_fmode;
+ err = 0;
done:
read_unlock_bh(&idev->lock);
in6_dev_put(idev);
dev_put(dev);
+ if (leavegroup)
+ err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
return err;
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 2414937f2a83..f6e288dc116e 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -2018,14 +2018,14 @@ static int tcp_v6_init_sock(struct sock *sk)
*/
tp->snd_ssthresh = 0x7fffffff;
tp->snd_cwnd_clamp = ~0;
- tp->mss_cache_std = tp->mss_cache = 536;
+ tp->mss_cache = 536;
tp->reordering = sysctl_tcp_reordering;
sk->sk_state = TCP_CLOSE;
tp->af_specific = &ipv6_specific;
-
+ tp->ca_ops = &tcp_init_congestion_ops;
sk->sk_write_space = sk_stream_write_space;
sock_set_flag(sk, SOCK_USE_WRITE_QUEUE);
diff --git a/net/ipx/Kconfig b/net/ipx/Kconfig
index a16237c0e783..980a826f5d02 100644
--- a/net/ipx/Kconfig
+++ b/net/ipx/Kconfig
@@ -1,6 +1,39 @@
#
# IPX configuration
#
+config IPX
+ tristate "The IPX protocol"
+ select LLC
+ ---help---
+ This is support for the Novell networking protocol, IPX, commonly
+ used for local networks of Windows machines. You need it if you
+ want to access Novell NetWare file or print servers using the Linux
+ Novell client ncpfs (available from
+ <ftp://platan.vc.cvut.cz/pub/linux/ncpfs/>) or from
+ within the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO,
+ available from <http://www.tldp.org/docs.html#howto>). In order
+ to do the former, you'll also have to say Y to "NCP file system
+ support", below.
+
+ IPX is similar in scope to IP, while SPX, which runs on top of IPX,
+ is similar to TCP. There is also experimental support for SPX in
+ Linux (see "SPX networking", below).
+
+ To turn your Linux box into a fully featured NetWare file server and
+ IPX router, say Y here and fetch either lwared from
+ <ftp://ibiblio.org/pub/Linux/system/network/daemons/> or
+ mars_nwe from <ftp://www.compu-art.de/mars_nwe/>. For more
+ information, read the IPX-HOWTO available from
+ <http://www.tldp.org/docs.html#howto>.
+
+ General information about how to connect Linux, Windows machines and
+ Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
+
+ The IPX driver would enlarge your kernel by about 16 KB. To compile
+ this driver as a module, choose M here: the module will be called ipx.
+ Unless you want to integrate your Linux box with a local Novell
+ network, say N.
+
config IPX_INTERN
bool "IPX: Full internal IPX network"
depends on IPX
diff --git a/net/irda/irlap.c b/net/irda/irlap.c
index 046ad0750e48..7029618f5719 100644
--- a/net/irda/irlap.c
+++ b/net/irda/irlap.c
@@ -445,9 +445,8 @@ void irlap_disconnect_request(struct irlap_cb *self)
IRDA_ASSERT(self->magic == LAP_MAGIC, return;);
/* Don't disconnect until all data frames are successfully sent */
- if (skb_queue_len(&self->txq) > 0) {
+ if (!skb_queue_empty(&self->txq)) {
self->disconnect_pending = TRUE;
-
return;
}
diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c
index 1cd89f5f3b75..a505b5457608 100644
--- a/net/irda/irlap_event.c
+++ b/net/irda/irlap_event.c
@@ -191,7 +191,7 @@ static void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
* Send out the RR frames faster if our own transmit queue is empty, or
* if the peer is busy. The effect is a much faster conversation
*/
- if ((skb_queue_len(&self->txq) == 0) || (self->remote_busy)) {
+ if (skb_queue_empty(&self->txq) || self->remote_busy) {
if (self->fast_RR == TRUE) {
/*
* Assert that the fast poll timer has not reached the
@@ -263,7 +263,7 @@ void irlap_do_event(struct irlap_cb *self, IRLAP_EVENT event,
IRDA_DEBUG(2, "%s() : queue len = %d\n", __FUNCTION__,
skb_queue_len(&self->txq));
- if (skb_queue_len(&self->txq)) {
+ if (!skb_queue_empty(&self->txq)) {
/* Prevent race conditions with irlap_data_request() */
self->local_busy = TRUE;
@@ -1074,7 +1074,7 @@ static int irlap_state_xmit_p(struct irlap_cb *self, IRLAP_EVENT event,
#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
/* Window has been adjusted for the max packet
* size, so much simpler... - Jean II */
- nextfit = (skb_queue_len(&self->txq) > 0);
+ nextfit = !skb_queue_empty(&self->txq);
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
/*
* Send data with poll bit cleared only if window > 1
@@ -1814,7 +1814,7 @@ static int irlap_state_xmit_s(struct irlap_cb *self, IRLAP_EVENT event,
#else /* CONFIG_IRDA_DYNAMIC_WINDOW */
/* Window has been adjusted for the max packet
* size, so much simpler... - Jean II */
- nextfit = (skb_queue_len(&self->txq) > 0);
+ nextfit = !skb_queue_empty(&self->txq);
#endif /* CONFIG_IRDA_DYNAMIC_WINDOW */
/*
* Send data with final bit cleared only if window > 1
@@ -1937,7 +1937,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
irlap_data_indication(self, skb, FALSE);
/* Any pending data requests? */
- if ((skb_queue_len(&self->txq) > 0) &&
+ if (!skb_queue_empty(&self->txq) &&
(self->window > 0))
{
self->ack_required = TRUE;
@@ -2038,7 +2038,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
/*
* Any pending data requests?
*/
- if ((skb_queue_len(&self->txq) > 0) &&
+ if (!skb_queue_empty(&self->txq) &&
(self->window > 0) && !self->remote_busy)
{
irlap_data_indication(self, skb, TRUE);
@@ -2069,7 +2069,7 @@ static int irlap_state_nrm_s(struct irlap_cb *self, IRLAP_EVENT event,
*/
nr_status = irlap_validate_nr_received(self, info->nr);
if (nr_status == NR_EXPECTED) {
- if ((skb_queue_len( &self->txq) > 0) &&
+ if (!skb_queue_empty(&self->txq) &&
(self->window > 0)) {
self->remote_busy = FALSE;
diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c
index 040abe714aa3..6dafbb43b529 100644
--- a/net/irda/irlap_frame.c
+++ b/net/irda/irlap_frame.c
@@ -1018,11 +1018,10 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
/*
* We can now fill the window with additional data frames
*/
- while (skb_queue_len( &self->txq) > 0) {
+ while (!skb_queue_empty(&self->txq)) {
IRDA_DEBUG(0, "%s(), sending additional frames!\n", __FUNCTION__);
- if ((skb_queue_len( &self->txq) > 0) &&
- (self->window > 0)) {
+ if (self->window > 0) {
skb = skb_dequeue( &self->txq);
IRDA_ASSERT(skb != NULL, return;);
@@ -1031,8 +1030,7 @@ void irlap_resend_rejected_frames(struct irlap_cb *self, int command)
* bit cleared
*/
if ((self->window > 1) &&
- skb_queue_len(&self->txq) > 0)
- {
+ !skb_queue_empty(&self->txq)) {
irlap_send_data_primary(self, skb);
} else {
irlap_send_data_primary_poll(self, skb);
diff --git a/net/irda/irttp.c b/net/irda/irttp.c
index d091ccf773b3..6602d901f8b1 100644
--- a/net/irda/irttp.c
+++ b/net/irda/irttp.c
@@ -1513,7 +1513,7 @@ int irttp_disconnect_request(struct tsap_cb *self, struct sk_buff *userdata,
/*
* Check if there is still data segments in the transmit queue
*/
- if (skb_queue_len(&self->tx_queue) > 0) {
+ if (!skb_queue_empty(&self->tx_queue)) {
if (priority == P_HIGH) {
/*
* No need to send the queued data, if we are
diff --git a/net/lapb/Kconfig b/net/lapb/Kconfig
new file mode 100644
index 000000000000..f0b5efb31a00
--- /dev/null
+++ b/net/lapb/Kconfig
@@ -0,0 +1,22 @@
+#
+# LAPB Data Link Drive
+#
+
+config LAPB
+ tristate "LAPB Data Link Driver (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ Link Access Procedure, Balanced (LAPB) is the data link layer (i.e.
+ the lower) part of the X.25 protocol. It offers a reliable
+ connection service to exchange data frames with one other host, and
+ it is used to transport higher level protocols (mostly X.25 Packet
+ Layer, the higher part of X.25, but others are possible as well).
+ Usually, LAPB is used with specialized X.21 network cards, but Linux
+ currently supports LAPB only over Ethernet connections. If you want
+ to use LAPB connections over Ethernet, say Y here and to "LAPB over
+ Ethernet driver" below. Read
+ <file:Documentation/networking/lapb-module.txt> for technical
+ details.
+
+ To compile this driver as a module, choose M here: the
+ module will be called lapb. If unsure, say N.
diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
index cd130c3b72bc..d5bdb53a348f 100644
--- a/net/llc/llc_c_ev.c
+++ b/net/llc/llc_c_ev.c
@@ -84,7 +84,7 @@ static u16 llc_util_nr_inside_tx_window(struct sock *sk, u8 nr)
if (llc->dev->flags & IFF_LOOPBACK)
goto out;
rc = 1;
- if (!skb_queue_len(&llc->pdu_unack_q))
+ if (skb_queue_empty(&llc->pdu_unack_q))
goto out;
skb = skb_peek(&llc->pdu_unack_q);
pdu = llc_pdu_sn_hdr(skb);
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index 70bcd4744d93..3405fdf41b93 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -315,8 +315,8 @@ err:
static void netlink_remove(struct sock *sk)
{
netlink_table_grab();
- nl_table[sk->sk_protocol].hash.entries--;
- sk_del_node_init(sk);
+ if (sk_del_node_init(sk))
+ nl_table[sk->sk_protocol].hash.entries--;
if (nlk_sk(sk)->groups)
__sk_del_bind_node(sk);
netlink_table_ungrab();
@@ -429,7 +429,12 @@ retry:
err = netlink_insert(sk, pid);
if (err == -EADDRINUSE)
goto retry;
- return 0;
+
+ /* If 2 threads race to autobind, that is fine. */
+ if (err == -EBUSY)
+ err = 0;
+
+ return err;
}
static inline int netlink_capable(struct socket *sock, unsigned int flag)
@@ -853,7 +858,7 @@ static inline void netlink_rcv_wake(struct sock *sk)
{
struct netlink_sock *nlk = nlk_sk(sk);
- if (!skb_queue_len(&sk->sk_receive_queue))
+ if (skb_queue_empty(&sk->sk_receive_queue))
clear_bit(0, &nlk->state);
if (!test_bit(0, &nlk->state))
wake_up_interruptible(&nlk->wait);
diff --git a/net/packet/Kconfig b/net/packet/Kconfig
new file mode 100644
index 000000000000..34ff93ff894d
--- /dev/null
+++ b/net/packet/Kconfig
@@ -0,0 +1,26 @@
+#
+# Packet configuration
+#
+
+config PACKET
+ tristate "Packet socket"
+ ---help---
+ The Packet protocol is used by applications which communicate
+ directly with network devices without an intermediate network
+ protocol implemented in the kernel, e.g. tcpdump. If you want them
+ to work, choose Y.
+
+ To compile this driver as a module, choose M here: the module will
+ be called af_packet.
+
+ If unsure, say Y.
+
+config PACKET_MMAP
+ bool "Packet socket: mmapped IO"
+ depends on PACKET
+ help
+ If you say Y here, the Packet protocol driver will use an IO
+ mechanism that results in faster communication.
+
+ If unsure, say N.
+
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 0269616e75a1..c9d5980aa4de 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -274,6 +274,9 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev, struct
dst_release(skb->dst);
skb->dst = NULL;
+ /* drop conntrack reference */
+ nf_reset(skb);
+
spkt = (struct sockaddr_pkt*)skb->cb;
skb_push(skb, skb->data-skb->mac.raw);
@@ -517,6 +520,9 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
dst_release(skb->dst);
skb->dst = NULL;
+ /* drop conntrack reference */
+ nf_reset(skb);
+
spin_lock(&sk->sk_receive_queue.lock);
po->stats.tp_packets++;
__skb_queue_tail(&sk->sk_receive_queue, skb);
diff --git a/net/rxrpc/krxiod.c b/net/rxrpc/krxiod.c
index 2b537f425a17..dada34a77b21 100644
--- a/net/rxrpc/krxiod.c
+++ b/net/rxrpc/krxiod.c
@@ -138,7 +138,7 @@ static int rxrpc_krxiod(void *arg)
_debug("### End Work");
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/rxrpc/krxsecd.c b/net/rxrpc/krxsecd.c
index 6020c89d9228..1aadd026d354 100644
--- a/net/rxrpc/krxsecd.c
+++ b/net/rxrpc/krxsecd.c
@@ -107,7 +107,7 @@ static int rxrpc_krxsecd(void *arg)
_debug("### End Inbound Calls");
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/rxrpc/krxtimod.c b/net/rxrpc/krxtimod.c
index 249c2b0290bb..3ac81cdd1211 100644
--- a/net/rxrpc/krxtimod.c
+++ b/net/rxrpc/krxtimod.c
@@ -90,7 +90,7 @@ static int krxtimod(void *arg)
complete_and_exit(&krxtimod_dead, 0);
}
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
/* discard pending signals */
rxrpc_discard_my_signals();
diff --git a/net/sched/Kconfig b/net/sched/Kconfig
index b22c9beb604d..59d3e71f8b85 100644
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -1,6 +1,43 @@
#
# Traffic control configuration.
#
+
+menuconfig NET_SCHED
+ bool "QoS and/or fair queueing"
+ ---help---
+ When the kernel has several packets to send out over a network
+ device, it has to decide which ones to send first, which ones to
+ delay, and which ones to drop. This is the job of the packet
+ scheduler, and several different algorithms for how to do this
+ "fairly" have been proposed.
+
+ If you say N here, you will get the standard packet scheduler, which
+ is a FIFO (first come, first served). If you say Y here, you will be
+ able to choose from among several alternative algorithms which can
+ then be attached to different network devices. This is useful for
+ example if some of your network devices are real time devices that
+ need a certain minimum data flow rate, or if you need to limit the
+ maximum data flow rate for traffic which matches specified criteria.
+ This code is considered to be experimental.
+
+ To administer these schedulers, you'll need the user-level utilities
+ from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>.
+ That package also contains some documentation; for more, check out
+ <http://snafu.freedom.org/linux2.2/iproute-notes.html>.
+
+ This Quality of Service (QoS) support will enable you to use
+ Differentiated Services (diffserv) and Resource Reservation Protocol
+ (RSVP) on your Linux router if you also say Y to "QoS support",
+ "Packet classifier API" and to some classifiers below. Documentation
+ and software is at <http://diffserv.sourceforge.net/>.
+
+ If you say Y here and to "/proc file system" below, you will be able
+ to read status information about packet schedulers from the file
+ /proc/net/psched.
+
+ The available schedulers are listed in the following questions; you
+ can say Y to as many as you like. If unsure, say N now.
+
choice
prompt "Packet scheduler clock source"
depends on NET_SCHED
@@ -449,6 +486,19 @@ config NET_EMATCH_META
To compile this code as a module, choose M here: the
module will be called em_meta.
+config NET_EMATCH_TEXT
+ tristate "Textsearch"
+ depends on NET_EMATCH
+ select TEXTSEARCH
+ select TEXTSEARCH_KMP
+ select TEXTSEARCH_FSM
+ ---help---
+ Say Y here if you want to be ablt to classify packets based on
+ textsearch comparisons.
+
+ To compile this code as a module, choose M here: the
+ module will be called em_text.
+
config NET_CLS_ACT
bool "Packet ACTION"
depends on EXPERIMENTAL && NET_CLS && NET_QOS
diff --git a/net/sched/Makefile b/net/sched/Makefile
index eb3fe583eba8..e48d0d456b3e 100644
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -4,7 +4,7 @@
obj-y := sch_generic.o
-obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o
+obj-$(CONFIG_NET_SCHED) += sch_api.o sch_fifo.o sch_blackhole.o
obj-$(CONFIG_NET_CLS) += cls_api.o
obj-$(CONFIG_NET_CLS_ACT) += act_api.o
obj-$(CONFIG_NET_ACT_POLICE) += police.o
@@ -40,3 +40,4 @@ obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o
obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o
obj-$(CONFIG_NET_EMATCH_U32) += em_u32.o
obj-$(CONFIG_NET_EMATCH_META) += em_meta.o
+obj-$(CONFIG_NET_EMATCH_TEXT) += em_text.o
diff --git a/net/sched/act_api.c b/net/sched/act_api.c
index 9594206e6035..249c61936ea0 100644
--- a/net/sched/act_api.c
+++ b/net/sched/act_api.c
@@ -439,6 +439,8 @@ tca_get_fill(struct sk_buff *skb, struct tc_action *a, u32 pid, u32 seq,
t = NLMSG_DATA(nlh);
t->tca_family = AF_UNSPEC;
+ t->tca__pad1 = 0;
+ t->tca__pad2 = 0;
x = (struct rtattr*) skb->tail;
RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
@@ -580,6 +582,8 @@ static int tca_action_flush(struct rtattr *rta, struct nlmsghdr *n, u32 pid)
nlh = NLMSG_PUT(skb, pid, n->nlmsg_seq, RTM_DELACTION, sizeof(*t));
t = NLMSG_DATA(nlh);
t->tca_family = AF_UNSPEC;
+ t->tca__pad1 = 0;
+ t->tca__pad2 = 0;
x = (struct rtattr *) skb->tail;
RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
@@ -687,7 +691,9 @@ static int tcf_add_notify(struct tc_action *a, u32 pid, u32 seq, int event,
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*t), flags);
t = NLMSG_DATA(nlh);
t->tca_family = AF_UNSPEC;
-
+ t->tca__pad1 = 0;
+ t->tca__pad2 = 0;
+
x = (struct rtattr*) skb->tail;
RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
@@ -842,6 +848,8 @@ tc_dump_action(struct sk_buff *skb, struct netlink_callback *cb)
cb->nlh->nlmsg_type, sizeof(*t));
t = NLMSG_DATA(nlh);
t->tca_family = AF_UNSPEC;
+ t->tca__pad1 = 0;
+ t->tca__pad2 = 0;
x = (struct rtattr *) skb->tail;
RTA_PUT(skb, TCA_ACT_TAB, 0, NULL);
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c
index 1616bf5c9627..3b5714ef4d1a 100644
--- a/net/sched/cls_api.c
+++ b/net/sched/cls_api.c
@@ -331,6 +331,8 @@ tcf_fill_node(struct sk_buff *skb, struct tcf_proto *tp, unsigned long fh,
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
tcm = NLMSG_DATA(nlh);
tcm->tcm_family = AF_UNSPEC;
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad1 = 0;
tcm->tcm_ifindex = tp->q->dev->ifindex;
tcm->tcm_parent = tp->classid;
tcm->tcm_info = TC_H_MAKE(tp->prio, tp->protocol);
diff --git a/net/sched/cls_rsvp.h b/net/sched/cls_rsvp.h
index 232fb9196810..006168d69376 100644
--- a/net/sched/cls_rsvp.h
+++ b/net/sched/cls_rsvp.h
@@ -618,6 +618,7 @@ static int rsvp_dump(struct tcf_proto *tp, unsigned long fh,
pinfo.protocol = s->protocol;
pinfo.tunnelid = s->tunnelid;
pinfo.tunnelhdr = f->tunnelhdr;
+ pinfo.pad = 0;
RTA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo);
if (f->res.classid)
RTA_PUT(skb, TCA_RSVP_CLASSID, 4, &f->res.classid);
diff --git a/net/sched/em_meta.c b/net/sched/em_meta.c
index 48bb23c2a35a..53d98f8d3d80 100644
--- a/net/sched/em_meta.c
+++ b/net/sched/em_meta.c
@@ -205,11 +205,6 @@ META_COLLECTOR(int_protocol)
dst->value = skb->protocol;
}
-META_COLLECTOR(int_security)
-{
- dst->value = skb->security;
-}
-
META_COLLECTOR(int_pkttype)
{
dst->value = skb->pkt_type;
@@ -524,7 +519,6 @@ static struct meta_ops __meta_ops[TCF_META_TYPE_MAX+1][TCF_META_ID_MAX+1] = {
[META_ID(REALDEV)] = META_FUNC(int_realdev),
[META_ID(PRIORITY)] = META_FUNC(int_priority),
[META_ID(PROTOCOL)] = META_FUNC(int_protocol),
- [META_ID(SECURITY)] = META_FUNC(int_security),
[META_ID(PKTTYPE)] = META_FUNC(int_pkttype),
[META_ID(PKTLEN)] = META_FUNC(int_pktlen),
[META_ID(DATALEN)] = META_FUNC(int_datalen),
diff --git a/net/sched/em_text.c b/net/sched/em_text.c
new file mode 100644
index 000000000000..873840d8d072
--- /dev/null
+++ b/net/sched/em_text.c
@@ -0,0 +1,157 @@
+/*
+ * net/sched/em_text.c Textsearch ematch
+ *
+ * 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.
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+#include <linux/textsearch.h>
+#include <linux/tc_ematch/tc_em_text.h>
+#include <net/pkt_cls.h>
+
+struct text_match
+{
+ u16 from_offset;
+ u16 to_offset;
+ u8 from_layer;
+ u8 to_layer;
+ struct ts_config *config;
+};
+
+#define EM_TEXT_PRIV(m) ((struct text_match *) (m)->data)
+
+static int em_text_match(struct sk_buff *skb, struct tcf_ematch *m,
+ struct tcf_pkt_info *info)
+{
+ struct text_match *tm = EM_TEXT_PRIV(m);
+ int from, to;
+ struct ts_state state;
+
+ from = tcf_get_base_ptr(skb, tm->from_layer) - skb->data;
+ from += tm->from_offset;
+
+ to = tcf_get_base_ptr(skb, tm->to_layer) - skb->data;
+ to += tm->to_offset;
+
+ return skb_find_text(skb, from, to, tm->config, &state) != UINT_MAX;
+}
+
+static int em_text_change(struct tcf_proto *tp, void *data, int len,
+ struct tcf_ematch *m)
+{
+ struct text_match *tm;
+ struct tcf_em_text *conf = data;
+ struct ts_config *ts_conf;
+ int flags = 0;
+
+ printk("Configuring text: %s from %d:%d to %d:%d len %d\n", conf->algo, conf->from_offset,
+ conf->from_layer, conf->to_offset, conf->to_layer, conf->pattern_len);
+
+ if (len < sizeof(*conf) || len < (sizeof(*conf) + conf->pattern_len))
+ return -EINVAL;
+
+ if (conf->from_layer > conf->to_layer)
+ return -EINVAL;
+
+ if (conf->from_layer == conf->to_layer &&
+ conf->from_offset > conf->to_offset)
+ return -EINVAL;
+
+retry:
+ ts_conf = textsearch_prepare(conf->algo, (u8 *) conf + sizeof(*conf),
+ conf->pattern_len, GFP_KERNEL, flags);
+
+ if (flags & TS_AUTOLOAD)
+ rtnl_lock();
+
+ if (IS_ERR(ts_conf)) {
+ if (PTR_ERR(ts_conf) == -ENOENT && !(flags & TS_AUTOLOAD)) {
+ rtnl_unlock();
+ flags |= TS_AUTOLOAD;
+ goto retry;
+ } else
+ return PTR_ERR(ts_conf);
+ } else if (flags & TS_AUTOLOAD) {
+ textsearch_destroy(ts_conf);
+ return -EAGAIN;
+ }
+
+ tm = kmalloc(sizeof(*tm), GFP_KERNEL);
+ if (tm == NULL) {
+ textsearch_destroy(ts_conf);
+ return -ENOBUFS;
+ }
+
+ tm->from_offset = conf->from_offset;
+ tm->to_offset = conf->to_offset;
+ tm->from_layer = conf->from_layer;
+ tm->to_layer = conf->to_layer;
+ tm->config = ts_conf;
+
+ m->datalen = sizeof(*tm);
+ m->data = (unsigned long) tm;
+
+ return 0;
+}
+
+static void em_text_destroy(struct tcf_proto *tp, struct tcf_ematch *m)
+{
+ textsearch_destroy(EM_TEXT_PRIV(m)->config);
+}
+
+static int em_text_dump(struct sk_buff *skb, struct tcf_ematch *m)
+{
+ struct text_match *tm = EM_TEXT_PRIV(m);
+ struct tcf_em_text conf;
+
+ strncpy(conf.algo, tm->config->ops->name, sizeof(conf.algo) - 1);
+ conf.from_offset = tm->from_offset;
+ conf.to_offset = tm->to_offset;
+ conf.from_layer = tm->from_layer;
+ conf.to_layer = tm->to_layer;
+ conf.pattern_len = textsearch_get_pattern_len(tm->config);
+ conf.pad = 0;
+
+ RTA_PUT_NOHDR(skb, sizeof(conf), &conf);
+ RTA_APPEND(skb, conf.pattern_len, textsearch_get_pattern(tm->config));
+ return 0;
+
+rtattr_failure:
+ return -1;
+}
+
+static struct tcf_ematch_ops em_text_ops = {
+ .kind = TCF_EM_TEXT,
+ .change = em_text_change,
+ .match = em_text_match,
+ .destroy = em_text_destroy,
+ .dump = em_text_dump,
+ .owner = THIS_MODULE,
+ .link = LIST_HEAD_INIT(em_text_ops.link)
+};
+
+static int __init init_em_text(void)
+{
+ return tcf_em_register(&em_text_ops);
+}
+
+static void __exit exit_em_text(void)
+{
+ tcf_em_unregister(&em_text_ops);
+}
+
+MODULE_LICENSE("GPL");
+
+module_init(init_em_text);
+module_exit(exit_em_text);
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c
index 97c1c75d5c78..b9a069af4a02 100644
--- a/net/sched/sch_api.c
+++ b/net/sched/sch_api.c
@@ -399,10 +399,8 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
{
int err;
struct rtattr *kind = tca[TCA_KIND-1];
- void *p = NULL;
struct Qdisc *sch;
struct Qdisc_ops *ops;
- int size;
ops = qdisc_lookup_ops(kind);
#ifdef CONFIG_KMOD
@@ -437,64 +435,55 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp)
if (ops == NULL)
goto err_out;
- /* ensure that the Qdisc and the private data are 32-byte aligned */
- size = ((sizeof(*sch) + QDISC_ALIGN_CONST) & ~QDISC_ALIGN_CONST);
- size += ops->priv_size + QDISC_ALIGN_CONST;
-
- p = kmalloc(size, GFP_KERNEL);
- err = -ENOBUFS;
- if (!p)
+ sch = qdisc_alloc(dev, ops);
+ if (IS_ERR(sch)) {
+ err = PTR_ERR(sch);
goto err_out2;
- memset(p, 0, size);
- sch = (struct Qdisc *)(((unsigned long)p + QDISC_ALIGN_CONST)
- & ~QDISC_ALIGN_CONST);
- sch->padded = (char *)sch - (char *)p;
-
- INIT_LIST_HEAD(&sch->list);
- skb_queue_head_init(&sch->q);
+ }
- if (handle == TC_H_INGRESS)
+ if (handle == TC_H_INGRESS) {
sch->flags |= TCQ_F_INGRESS;
-
- sch->ops = ops;
- sch->enqueue = ops->enqueue;
- sch->dequeue = ops->dequeue;
- sch->dev = dev;
- dev_hold(dev);
- atomic_set(&sch->refcnt, 1);
- sch->stats_lock = &dev->queue_lock;
- if (handle == 0) {
+ handle = TC_H_MAKE(TC_H_INGRESS, 0);
+ } else if (handle == 0) {
handle = qdisc_alloc_handle(dev);
err = -ENOMEM;
if (handle == 0)
goto err_out3;
}
- if (handle == TC_H_INGRESS)
- sch->handle =TC_H_MAKE(TC_H_INGRESS, 0);
- else
- sch->handle = handle;
+ sch->handle = handle;
if (!ops->init || (err = ops->init(sch, tca[TCA_OPTIONS-1])) == 0) {
+#ifdef CONFIG_NET_ESTIMATOR
+ if (tca[TCA_RATE-1]) {
+ err = gen_new_estimator(&sch->bstats, &sch->rate_est,
+ sch->stats_lock,
+ tca[TCA_RATE-1]);
+ if (err) {
+ /*
+ * Any broken qdiscs that would require
+ * a ops->reset() here? The qdisc was never
+ * in action so it shouldn't be necessary.
+ */
+ if (ops->destroy)
+ ops->destroy(sch);
+ goto err_out3;
+ }
+ }
+#endif
qdisc_lock_tree(dev);
list_add_tail(&sch->list, &dev->qdisc_list);
qdisc_unlock_tree(dev);
-#ifdef CONFIG_NET_ESTIMATOR
- if (tca[TCA_RATE-1])
- gen_new_estimator(&sch->bstats, &sch->rate_est,
- sch->stats_lock, tca[TCA_RATE-1]);
-#endif
return sch;
}
err_out3:
dev_put(dev);
+ kfree((char *) sch - sch->padded);
err_out2:
module_put(ops->owner);
err_out:
*errp = err;
- if (p)
- kfree(p);
return NULL;
}
@@ -770,6 +759,8 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid,
nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags);
tcm = NLMSG_DATA(nlh);
tcm->tcm_family = AF_UNSPEC;
+ tcm->tcm__pad1 = 0;
+ tcm->tcm__pad2 = 0;
tcm->tcm_ifindex = q->dev->ifindex;
tcm->tcm_parent = clid;
tcm->tcm_handle = q->handle;
diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c
new file mode 100644
index 000000000000..81f0b8346d17
--- /dev/null
+++ b/net/sched/sch_blackhole.c
@@ -0,0 +1,54 @@
+/*
+ * net/sched/sch_blackhole.c Black hole queue
+ *
+ * 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.
+ *
+ * Authors: Thomas Graf <tgraf@suug.ch>
+ *
+ * Note: Quantum tunneling is not supported.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <net/pkt_sched.h>
+
+static int blackhole_enqueue(struct sk_buff *skb, struct Qdisc *sch)
+{
+ qdisc_drop(skb, sch);
+ return NET_XMIT_SUCCESS;
+}
+
+static struct sk_buff *blackhole_dequeue(struct Qdisc *sch)
+{
+ return NULL;
+}
+
+static struct Qdisc_ops blackhole_qdisc_ops = {
+ .id = "blackhole",
+ .priv_size = 0,
+ .enqueue = blackhole_enqueue,
+ .dequeue = blackhole_dequeue,
+ .owner = THIS_MODULE,
+};
+
+static int __init blackhole_module_init(void)
+{
+ return register_qdisc(&blackhole_qdisc_ops);
+}
+
+static void __exit blackhole_module_exit(void)
+{
+ unregister_qdisc(&blackhole_qdisc_ops);
+}
+
+module_init(blackhole_module_init)
+module_exit(blackhole_module_exit)
+
+MODULE_LICENSE("GPL");
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index d43e3b8cbf6a..09453f997d8c 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1528,6 +1528,7 @@ static __inline__ int cbq_dump_ovl(struct sk_buff *skb, struct cbq_class *cl)
opt.strategy = cl->ovl_strategy;
opt.priority2 = cl->priority2+1;
+ opt.pad = 0;
opt.penalty = (cl->penalty*1000)/HZ;
RTA_PUT(skb, TCA_CBQ_OVL_STRATEGY, sizeof(opt), &opt);
return skb->len;
@@ -1563,6 +1564,8 @@ static __inline__ int cbq_dump_police(struct sk_buff *skb, struct cbq_class *cl)
if (cl->police) {
opt.police = cl->police;
+ opt.__res1 = 0;
+ opt.__res2 = 0;
RTA_PUT(skb, TCA_CBQ_POLICE, sizeof(opt), &opt);
}
return skb->len;
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 7683b34dc6a9..73e218e646ac 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -395,24 +395,23 @@ static struct Qdisc_ops pfifo_fast_ops = {
.owner = THIS_MODULE,
};
-struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
+struct Qdisc *qdisc_alloc(struct net_device *dev, struct Qdisc_ops *ops)
{
void *p;
struct Qdisc *sch;
- int size;
+ unsigned int size;
+ int err = -ENOBUFS;
/* ensure that the Qdisc and the private data are 32-byte aligned */
- size = ((sizeof(*sch) + QDISC_ALIGN_CONST) & ~QDISC_ALIGN_CONST);
- size += ops->priv_size + QDISC_ALIGN_CONST;
+ size = QDISC_ALIGN(sizeof(*sch));
+ size += ops->priv_size + (QDISC_ALIGNTO - 1);
p = kmalloc(size, GFP_KERNEL);
if (!p)
- return NULL;
+ goto errout;
memset(p, 0, size);
-
- sch = (struct Qdisc *)(((unsigned long)p + QDISC_ALIGN_CONST)
- & ~QDISC_ALIGN_CONST);
- sch->padded = (char *)sch - (char *)p;
+ sch = (struct Qdisc *) QDISC_ALIGN((unsigned long) p);
+ sch->padded = (char *) sch - (char *) p;
INIT_LIST_HEAD(&sch->list);
skb_queue_head_init(&sch->q);
@@ -423,11 +422,24 @@ struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
dev_hold(dev);
sch->stats_lock = &dev->queue_lock;
atomic_set(&sch->refcnt, 1);
+
+ return sch;
+errout:
+ return ERR_PTR(-err);
+}
+
+struct Qdisc * qdisc_create_dflt(struct net_device *dev, struct Qdisc_ops *ops)
+{
+ struct Qdisc *sch;
+
+ sch = qdisc_alloc(dev, ops);
+ if (IS_ERR(sch))
+ goto errout;
+
if (!ops->init || ops->init(sch, NULL) == 0)
return sch;
- dev_put(dev);
- kfree(p);
+errout:
return NULL;
}
@@ -591,6 +603,7 @@ EXPORT_SYMBOL(__netdev_watchdog_up);
EXPORT_SYMBOL(noop_qdisc);
EXPORT_SYMBOL(noop_qdisc_ops);
EXPORT_SYMBOL(qdisc_create_dflt);
+EXPORT_SYMBOL(qdisc_alloc);
EXPORT_SYMBOL(qdisc_destroy);
EXPORT_SYMBOL(qdisc_reset);
EXPORT_SYMBOL(qdisc_restart);
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 664d0e47374f..7845d045eec4 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -385,7 +385,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
memcpy(q->Stab, RTA_DATA(tb[TCA_RED_STAB-1]), 256);
q->qcount = -1;
- if (skb_queue_len(&sch->q) == 0)
+ if (skb_queue_empty(&sch->q))
PSCHED_SET_PASTPERFECT(q->qidlestart);
sch_tree_unlock(sch);
return 0;
diff --git a/net/sctp/associola.c b/net/sctp/associola.c
index 7ae6aa772dab..5b24ae0650d3 100644
--- a/net/sctp/associola.c
+++ b/net/sctp/associola.c
@@ -71,7 +71,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
const struct sctp_endpoint *ep,
const struct sock *sk,
sctp_scope_t scope,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sctp_sock *sp;
int i;
@@ -203,7 +203,7 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
*/
asoc->addip_serial = asoc->c.initial_tsn;
- skb_queue_head_init(&asoc->addip_chunks);
+ INIT_LIST_HEAD(&asoc->addip_chunk_list);
/* Make an empty list of remote transport addresses. */
INIT_LIST_HEAD(&asoc->peer.transport_addr_list);
@@ -272,7 +272,8 @@ fail_init:
/* Allocate and initialize a new association */
struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
const struct sock *sk,
- sctp_scope_t scope, int gfp)
+ sctp_scope_t scope,
+ unsigned int __nocast gfp)
{
struct sctp_association *asoc;
@@ -478,7 +479,7 @@ void sctp_assoc_rm_peer(struct sctp_association *asoc,
/* Add a transport address to an association. */
struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
const union sctp_addr *addr,
- const int gfp,
+ const unsigned int __nocast gfp,
const int peer_state)
{
struct sctp_transport *peer;
@@ -1229,7 +1230,8 @@ void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, unsigned len)
/* Build the bind address list for the association based on info from the
* local endpoint and the remote peer.
*/
-int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp)
+int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc,
+ unsigned int __nocast gfp)
{
sctp_scope_t scope;
int flags;
@@ -1251,7 +1253,8 @@ int sctp_assoc_set_bind_addr_from_ep(struct sctp_association *asoc, int gfp)
/* Build the association's bind address list from the cookie. */
int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
- struct sctp_cookie *cookie, int gfp)
+ struct sctp_cookie *cookie,
+ unsigned int __nocast gfp)
{
int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);
int var_size3 = cookie->raw_addr_list_len;
diff --git a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
index f90eadfb60a2..f71549710f2e 100644
--- a/net/sctp/bind_addr.c
+++ b/net/sctp/bind_addr.c
@@ -53,7 +53,8 @@
/* Forward declarations for internal helpers. */
static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *,
- sctp_scope_t scope, int gfp, int flags);
+ sctp_scope_t scope, unsigned int __nocast gfp,
+ int flags);
static void sctp_bind_addr_clean(struct sctp_bind_addr *);
/* First Level Abstractions. */
@@ -63,7 +64,8 @@ static void sctp_bind_addr_clean(struct sctp_bind_addr *);
*/
int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
const struct sctp_bind_addr *src,
- sctp_scope_t scope, int gfp, int flags)
+ sctp_scope_t scope, unsigned int __nocast gfp,
+ int flags)
{
struct sctp_sockaddr_entry *addr;
struct list_head *pos;
@@ -144,7 +146,7 @@ void sctp_bind_addr_free(struct sctp_bind_addr *bp)
/* Add an address to the bind address list in the SCTP_bind_addr structure. */
int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sctp_sockaddr_entry *addr;
@@ -197,7 +199,8 @@ int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
* The second argument is the return value for the length.
*/
union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
- int *addrs_len, int gfp)
+ int *addrs_len,
+ unsigned int __nocast gfp)
{
union sctp_params addrparms;
union sctp_params retval;
@@ -249,7 +252,7 @@ end_raw:
* address parameters).
*/
int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
- int addrs_len, __u16 port, int gfp)
+ int addrs_len, __u16 port, unsigned int __nocast gfp)
{
union sctp_addr_param *rawaddr;
struct sctp_paramhdr *param;
@@ -347,7 +350,8 @@ union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp,
/* Copy out addresses from the global local address list. */
static int sctp_copy_one_addr(struct sctp_bind_addr *dest,
union sctp_addr *addr,
- sctp_scope_t scope, int gfp, int flags)
+ sctp_scope_t scope, unsigned int __nocast gfp,
+ int flags)
{
int error = 0;
diff --git a/net/sctp/chunk.c b/net/sctp/chunk.c
index 0c2ab7885058..61da2937e641 100644
--- a/net/sctp/chunk.c
+++ b/net/sctp/chunk.c
@@ -62,7 +62,7 @@ static void sctp_datamsg_init(struct sctp_datamsg *msg)
}
/* Allocate and initialize datamsg. */
-SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(int gfp)
+SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(unsigned int __nocast gfp)
{
struct sctp_datamsg *msg;
msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c
index 2ec0320fac3b..e47ac0d1a6d6 100644
--- a/net/sctp/endpointola.c
+++ b/net/sctp/endpointola.c
@@ -67,7 +67,8 @@ static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
* Initialize the base fields of the endpoint structure.
*/
static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
- struct sock *sk, int gfp)
+ struct sock *sk,
+ unsigned int __nocast gfp)
{
struct sctp_sock *sp = sctp_sk(sk);
memset(ep, 0, sizeof(struct sctp_endpoint));
@@ -102,9 +103,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Set up the base timeout information. */
ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
- SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
+ msecs_to_jiffies(sp->rtoinfo.srto_initial);
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
- SCTP_DEFAULT_TIMEOUT_T1_INIT;
+ msecs_to_jiffies(sp->rtoinfo.srto_initial);
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
msecs_to_jiffies(sp->rtoinfo.srto_initial);
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
@@ -117,12 +118,9 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
= 5 * msecs_to_jiffies(sp->rtoinfo.srto_max);
- ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
- SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
- ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
- SCTP_DEFAULT_TIMEOUT_SACK;
- ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
- sp->autoclose * HZ;
+ ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
+ ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = sctp_sack_timeout;
+ ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = sp->autoclose * HZ;
/* Use SCTP specific send buffer space queues. */
ep->sndbuf_policy = sctp_sndbuf_policy;
@@ -140,7 +138,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
/* Create a sctp_endpoint with all that boring stuff initialized.
* Returns NULL if there isn't enough memory.
*/
-struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
+struct sctp_endpoint *sctp_endpoint_new(struct sock *sk,
+ unsigned int __nocast gfp)
{
struct sctp_endpoint *ep;
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 339f7acfdb64..5e085e041a6e 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -115,6 +115,17 @@ static void sctp_rcv_set_owner_r(struct sk_buff *skb, struct sock *sk)
atomic_add(sizeof(struct sctp_chunk),&sk->sk_rmem_alloc);
}
+struct sctp_input_cb {
+ union {
+ struct inet_skb_parm h4;
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+ struct inet6_skb_parm h6;
+#endif
+ } header;
+ struct sctp_chunk *chunk;
+};
+#define SCTP_INPUT_CB(__skb) ((struct sctp_input_cb *)&((__skb)->cb[0]))
+
/*
* This is the routine which IP calls when receiving an SCTP packet.
*/
@@ -243,6 +254,7 @@ int sctp_rcv(struct sk_buff *skb)
ret = -ENOMEM;
goto discard_release;
}
+ SCTP_INPUT_CB(skb)->chunk = chunk;
sctp_rcv_set_owner_r(skb,sk);
@@ -265,9 +277,9 @@ int sctp_rcv(struct sk_buff *skb)
sctp_bh_lock_sock(sk);
if (sock_owned_by_user(sk))
- sk_add_backlog(sk, (struct sk_buff *) chunk);
+ sk_add_backlog(sk, skb);
else
- sctp_backlog_rcv(sk, (struct sk_buff *) chunk);
+ sctp_backlog_rcv(sk, skb);
/* Release the sock and any reference counts we took in the
* lookup calls.
@@ -302,14 +314,8 @@ discard_release:
*/
int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
{
- struct sctp_chunk *chunk;
- struct sctp_inq *inqueue;
-
- /* One day chunk will live inside the skb, but for
- * now this works.
- */
- chunk = (struct sctp_chunk *) skb;
- inqueue = &chunk->rcvr->inqueue;
+ struct sctp_chunk *chunk = SCTP_INPUT_CB(skb)->chunk;
+ struct sctp_inq *inqueue = &chunk->rcvr->inqueue;
sctp_inq_push(inqueue, chunk);
return 0;
diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
index cedf4351556c..2d33922c044b 100644
--- a/net/sctp/inqueue.c
+++ b/net/sctp/inqueue.c
@@ -50,7 +50,7 @@
/* Initialize an SCTP inqueue. */
void sctp_inq_init(struct sctp_inq *queue)
{
- skb_queue_head_init(&queue->in);
+ INIT_LIST_HEAD(&queue->in_chunk_list);
queue->in_progress = NULL;
/* Create a task for delivering data. */
@@ -62,11 +62,13 @@ void sctp_inq_init(struct sctp_inq *queue)
/* Release the memory associated with an SCTP inqueue. */
void sctp_inq_free(struct sctp_inq *queue)
{
- struct sctp_chunk *chunk;
+ struct sctp_chunk *chunk, *tmp;
/* Empty the queue. */
- while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)) != NULL)
+ list_for_each_entry_safe(chunk, tmp, &queue->in_chunk_list, list) {
+ list_del_init(&chunk->list);
sctp_chunk_free(chunk);
+ }
/* If there is a packet which is currently being worked on,
* free it as well.
@@ -92,7 +94,7 @@ void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet)
* Eventually, we should clean up inqueue to not rely
* on the BH related data structures.
*/
- skb_queue_tail(&(q->in), (struct sk_buff *) packet);
+ list_add_tail(&packet->list, &q->in_chunk_list);
q->immediate.func(q->immediate.data);
}
@@ -131,12 +133,16 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
/* Do we need to take the next packet out of the queue to process? */
if (!chunk) {
+ struct list_head *entry;
+
/* Is the queue empty? */
- if (skb_queue_empty(&queue->in))
+ if (list_empty(&queue->in_chunk_list))
return NULL;
+ entry = queue->in_chunk_list.next;
chunk = queue->in_progress =
- (struct sctp_chunk *) skb_dequeue(&queue->in);
+ list_entry(entry, struct sctp_chunk, list);
+ list_del_init(entry);
/* This is the first chunk in the packet. */
chunk->singleton = 1;
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 84b5b370b09d..931371633464 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -108,7 +108,7 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
packet->transport = transport;
packet->source_port = sport;
packet->destination_port = dport;
- skb_queue_head_init(&packet->chunks);
+ INIT_LIST_HEAD(&packet->chunk_list);
if (asoc) {
struct sctp_sock *sp = sctp_sk(asoc->base.sk);
overhead = sp->pf->af->net_header_len;
@@ -129,12 +129,14 @@ struct sctp_packet *sctp_packet_init(struct sctp_packet *packet,
/* Free a packet. */
void sctp_packet_free(struct sctp_packet *packet)
{
- struct sctp_chunk *chunk;
+ struct sctp_chunk *chunk, *tmp;
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
- while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL)
+ list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+ list_del_init(&chunk->list);
sctp_chunk_free(chunk);
+ }
if (packet->malloced)
kfree(packet);
@@ -276,7 +278,7 @@ append:
packet->has_sack = 1;
/* It is OK to send this chunk. */
- __skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
+ list_add_tail(&chunk->list, &packet->chunk_list);
packet->size += chunk_len;
chunk->transport = packet->transport;
finish:
@@ -295,7 +297,7 @@ int sctp_packet_transmit(struct sctp_packet *packet)
struct sctphdr *sh;
__u32 crc32;
struct sk_buff *nskb;
- struct sctp_chunk *chunk;
+ struct sctp_chunk *chunk, *tmp;
struct sock *sk;
int err = 0;
int padding; /* How much padding do we need? */
@@ -305,11 +307,11 @@ int sctp_packet_transmit(struct sctp_packet *packet)
SCTP_DEBUG_PRINTK("%s: packet:%p\n", __FUNCTION__, packet);
/* Do NOT generate a chunkless packet. */
- chunk = (struct sctp_chunk *)skb_peek(&packet->chunks);
- if (unlikely(!chunk))
+ if (list_empty(&packet->chunk_list))
return err;
/* Set up convenience variables... */
+ chunk = list_entry(packet->chunk_list.next, struct sctp_chunk, list);
sk = chunk->skb->sk;
/* Allocate the new skb. */
@@ -370,7 +372,8 @@ int sctp_packet_transmit(struct sctp_packet *packet)
* [This whole comment explains WORD_ROUND() below.]
*/
SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
- while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
+ list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+ list_del_init(&chunk->list);
if (sctp_chunk_is_data(chunk)) {
if (!chunk->has_tsn) {
@@ -511,7 +514,8 @@ err:
* will get resent or dropped later.
*/
- while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)) != NULL) {
+ list_for_each_entry_safe(chunk, tmp, &packet->chunk_list, list) {
+ list_del_init(&chunk->list);
if (!sctp_chunk_is_data(chunk))
sctp_chunk_free(chunk);
}
diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c
index 4eb81a1407b7..efb72faba20c 100644
--- a/net/sctp/outqueue.c
+++ b/net/sctp/outqueue.c
@@ -75,7 +75,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 sack_ctsn);
static inline void sctp_outq_head_data(struct sctp_outq *q,
struct sctp_chunk *ch)
{
- __skb_queue_head(&q->out, (struct sk_buff *)ch);
+ list_add(&ch->list, &q->out_chunk_list);
q->out_qlen += ch->skb->len;
return;
}
@@ -83,17 +83,22 @@ static inline void sctp_outq_head_data(struct sctp_outq *q,
/* Take data from the front of the queue. */
static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q)
{
- struct sctp_chunk *ch;
- ch = (struct sctp_chunk *)__skb_dequeue(&q->out);
- if (ch)
+ struct sctp_chunk *ch = NULL;
+
+ if (!list_empty(&q->out_chunk_list)) {
+ struct list_head *entry = q->out_chunk_list.next;
+
+ ch = list_entry(entry, struct sctp_chunk, list);
+ list_del_init(entry);
q->out_qlen -= ch->skb->len;
+ }
return ch;
}
/* Add data chunk to the end of the queue. */
static inline void sctp_outq_tail_data(struct sctp_outq *q,
struct sctp_chunk *ch)
{
- __skb_queue_tail(&q->out, (struct sk_buff *)ch);
+ list_add_tail(&ch->list, &q->out_chunk_list);
q->out_qlen += ch->skb->len;
return;
}
@@ -197,8 +202,8 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary,
void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
{
q->asoc = asoc;
- skb_queue_head_init(&q->out);
- skb_queue_head_init(&q->control);
+ INIT_LIST_HEAD(&q->out_chunk_list);
+ INIT_LIST_HEAD(&q->control_chunk_list);
INIT_LIST_HEAD(&q->retransmit);
INIT_LIST_HEAD(&q->sacked);
INIT_LIST_HEAD(&q->abandoned);
@@ -217,7 +222,7 @@ void sctp_outq_teardown(struct sctp_outq *q)
{
struct sctp_transport *transport;
struct list_head *lchunk, *pos, *temp;
- struct sctp_chunk *chunk;
+ struct sctp_chunk *chunk, *tmp;
/* Throw away unacknowledged chunks. */
list_for_each(pos, &q->asoc->peer.transport_addr_list) {
@@ -269,8 +274,10 @@ void sctp_outq_teardown(struct sctp_outq *q)
q->error = 0;
/* Throw away any leftover control chunks. */
- while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)) != NULL)
+ list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+ list_del_init(&chunk->list);
sctp_chunk_free(chunk);
+ }
}
/* Free the outqueue structure and any related pending chunks. */
@@ -333,7 +340,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
break;
};
} else {
- __skb_queue_tail(&q->control, (struct sk_buff *) chunk);
+ list_add_tail(&chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
}
@@ -650,10 +657,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
__u16 sport = asoc->base.bind_addr.port;
__u16 dport = asoc->peer.port;
__u32 vtag = asoc->peer.i.init_tag;
- struct sk_buff_head *queue;
struct sctp_transport *transport = NULL;
struct sctp_transport *new_transport;
- struct sctp_chunk *chunk;
+ struct sctp_chunk *chunk, *tmp;
sctp_xmit_t status;
int error = 0;
int start_timer = 0;
@@ -675,8 +681,9 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
* ...
*/
- queue = &q->control;
- while ((chunk = (struct sctp_chunk *)skb_dequeue(queue)) != NULL) {
+ list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+ list_del_init(&chunk->list);
+
/* Pick the right transport to use. */
new_transport = chunk->transport;
@@ -814,8 +821,6 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
/* Finally, transmit new packets. */
start_timer = 0;
- queue = &q->out;
-
while ((chunk = sctp_outq_dequeue_data(q)) != NULL) {
/* RFC 2960 6.5 Every DATA chunk MUST carry a valid
* stream identifier.
@@ -1149,8 +1154,9 @@ int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
/* See if all chunks are acked.
* Make sure the empty queue handler will get run later.
*/
- q->empty = skb_queue_empty(&q->out) && skb_queue_empty(&q->control) &&
- list_empty(&q->retransmit);
+ q->empty = (list_empty(&q->out_chunk_list) &&
+ list_empty(&q->control_chunk_list) &&
+ list_empty(&q->retransmit));
if (!q->empty)
goto finish;
@@ -1679,9 +1685,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
if (TSN_lte(tsn, ctsn)) {
list_del_init(lchunk);
if (!chunk->tsn_gap_acked) {
- chunk->transport->flight_size -=
- sctp_data_size(chunk);
- q->outstanding_bytes -= sctp_data_size(chunk);
+ chunk->transport->flight_size -=
+ sctp_data_size(chunk);
+ q->outstanding_bytes -= sctp_data_size(chunk);
}
sctp_chunk_free(chunk);
} else {
@@ -1729,7 +1735,7 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
nskips, &ftsn_skip_arr[0]);
if (ftsn_chunk) {
- __skb_queue_tail(&q->control, (struct sk_buff *)ftsn_chunk);
+ list_add_tail(&ftsn_chunk->list, &q->control_chunk_list);
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
}
}
diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c
index 5135e1a25d25..ce9245e71fca 100644
--- a/net/sctp/protocol.c
+++ b/net/sctp/protocol.c
@@ -219,7 +219,7 @@ static void sctp_free_local_addr_list(void)
/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct sctp_bind_addr *bp, sctp_scope_t scope,
- int gfp, int copy_flags)
+ unsigned int __nocast gfp, int copy_flags)
{
struct sctp_sockaddr_entry *addr;
int error = 0;
@@ -1050,7 +1050,10 @@ SCTP_STATIC __init int sctp_init(void)
sctp_sndbuf_policy = 0;
/* HB.interval - 30 seconds */
- sctp_hb_interval = 30 * HZ;
+ sctp_hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
+
+ /* delayed SACK timeout */
+ sctp_sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK;
/* Implementation specific variables. */
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 5baed9bb7de5..00d32b7c8266 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -78,7 +78,7 @@ static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
static int sctp_process_param(struct sctp_association *asoc,
union sctp_params param,
const union sctp_addr *peer_addr,
- int gfp);
+ unsigned int __nocast gfp);
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
@@ -174,7 +174,7 @@ void sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
*/
struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
const struct sctp_bind_addr *bp,
- int gfp, int vparam_len)
+ unsigned int __nocast gfp, int vparam_len)
{
sctp_inithdr_t init;
union sctp_params addrs;
@@ -261,7 +261,7 @@ nodata:
struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
- int gfp, int unkparam_len)
+ unsigned int __nocast gfp, int unkparam_len)
{
sctp_inithdr_t initack;
struct sctp_chunk *retval;
@@ -1003,6 +1003,7 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
}
+ INIT_LIST_HEAD(&retval->list);
retval->skb = skb;
retval->asoc = (struct sctp_association *)asoc;
retval->resent = 0;
@@ -1116,8 +1117,7 @@ static void sctp_chunk_destroy(struct sctp_chunk *chunk)
/* Possibly, free the chunk. */
void sctp_chunk_free(struct sctp_chunk *chunk)
{
- /* Make sure that we are not on any list. */
- skb_unlink((struct sk_buff *) chunk);
+ BUG_ON(!list_empty(&chunk->list));
list_del_init(&chunk->transmitted_list);
/* Release our reference on the message tracker. */
@@ -1233,7 +1233,8 @@ void sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
/* Create a CLOSED association to use with an incoming packet. */
struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
- struct sctp_chunk *chunk, int gfp)
+ struct sctp_chunk *chunk,
+ unsigned int __nocast gfp)
{
struct sctp_association *asoc;
struct sk_buff *skb;
@@ -1348,7 +1349,7 @@ nodata:
struct sctp_association *sctp_unpack_cookie(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
- struct sctp_chunk *chunk, int gfp,
+ struct sctp_chunk *chunk, unsigned int __nocast gfp,
int *error, struct sctp_chunk **errp)
{
struct sctp_association *retval = NULL;
@@ -1812,7 +1813,7 @@ int sctp_verify_init(const struct sctp_association *asoc,
*/
int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
const union sctp_addr *peer_addr,
- sctp_init_chunk_t *peer_init, int gfp)
+ sctp_init_chunk_t *peer_init, unsigned int __nocast gfp)
{
union sctp_params param;
struct sctp_transport *transport;
@@ -1983,7 +1984,7 @@ nomem:
static int sctp_process_param(struct sctp_association *asoc,
union sctp_params param,
const union sctp_addr *peer_addr,
- int gfp)
+ unsigned int __nocast gfp)
{
union sctp_addr addr;
int i;
@@ -2739,8 +2740,12 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
asoc->addip_last_asconf = NULL;
/* Send the next asconf chunk from the addip chunk queue. */
- asconf = (struct sctp_chunk *)__skb_dequeue(&asoc->addip_chunks);
- if (asconf) {
+ if (!list_empty(&asoc->addip_chunk_list)) {
+ struct list_head *entry = asoc->addip_chunk_list.next;
+ asconf = list_entry(entry, struct sctp_chunk, list);
+
+ list_del_init(entry);
+
/* Hold the chunk until an ASCONF_ACK is received. */
sctp_chunk_hold(asconf);
if (sctp_primitive_ASCONF(asoc, asconf))
diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
index 778639db125a..39c970b5b198 100644
--- a/net/sctp/sm_sideeffect.c
+++ b/net/sctp/sm_sideeffect.c
@@ -63,7 +63,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
- int gfp);
+ unsigned int __nocast gfp);
static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
@@ -71,7 +71,7 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
- int gfp);
+ unsigned int __nocast gfp);
/********************************************************************
* Helper functions
@@ -497,7 +497,8 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
static int sctp_cmd_process_init(sctp_cmd_seq_t *commands,
struct sctp_association *asoc,
struct sctp_chunk *chunk,
- sctp_init_chunk_t *peer_init, int gfp)
+ sctp_init_chunk_t *peer_init,
+ unsigned int __nocast gfp)
{
int error;
@@ -852,7 +853,7 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
- int gfp)
+ unsigned int __nocast gfp)
{
sctp_cmd_seq_t commands;
const sctp_sm_table_entry_t *state_fn;
@@ -897,7 +898,7 @@ static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
- int gfp)
+ unsigned int __nocast gfp)
{
int error;
@@ -985,7 +986,7 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
- int gfp)
+ unsigned int __nocast gfp)
{
int error = 0;
int force;
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 058189684c7c..86073df418f5 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -92,6 +92,17 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
sctp_cmd_seq_t *commands);
static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+ __u16 error,
+ const struct sctp_association *asoc,
+ struct sctp_transport *transport);
+
+static sctp_disposition_t sctp_sf_violation_chunklen(
+ const struct sctp_endpoint *ep,
+ const struct sctp_association *asoc,
+ const sctp_subtype_t type,
+ void *arg,
+ sctp_cmd_seq_t *commands);
/* Small helper function that checks if the chunk length
* is of the appropriate length. The 'required_length' argument
@@ -2328,7 +2339,7 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
*
* This is common code called by several sctp_sf_*_abort() functions above.
*/
-sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
+static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
__u16 error,
const struct sctp_association *asoc,
struct sctp_transport *transport)
@@ -3687,7 +3698,8 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
*
* Generate an ABORT chunk and terminate the association.
*/
-sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
+static sctp_disposition_t sctp_sf_violation_chunklen(
+ const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index aad55dc3792b..091a66f06a35 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -406,7 +406,7 @@ static int sctp_send_asconf(struct sctp_association *asoc,
* transmission.
*/
if (asoc->addip_last_asconf) {
- __skb_queue_tail(&asoc->addip_chunks, (struct sk_buff *)chunk);
+ list_add_tail(&chunk->list, &asoc->addip_chunk_list);
goto out;
}
diff --git a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c
index e627d2b451b6..25037daf3fa0 100644
--- a/net/sctp/ssnmap.c
+++ b/net/sctp/ssnmap.c
@@ -57,7 +57,8 @@ static inline size_t sctp_ssnmap_size(__u16 in, __u16 out)
/* Create a new sctp_ssnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
-struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
+struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out,
+ unsigned int __nocast gfp)
{
struct sctp_ssnmap *retval;
int size;
diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c
index 7fc31849312b..dc4893474f18 100644
--- a/net/sctp/sysctl.c
+++ b/net/sctp/sysctl.c
@@ -47,6 +47,8 @@
static ctl_handler sctp_sysctl_jiffies_ms;
static long rto_timer_min = 1;
static long rto_timer_max = 86400000; /* One day */
+static long sack_timer_min = 1;
+static long sack_timer_max = 500;
static ctl_table sctp_table[] = {
{
@@ -187,6 +189,17 @@ static ctl_table sctp_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec
},
+ {
+ .ctl_name = NET_SCTP_SACK_TIMEOUT,
+ .procname = "sack_timeout",
+ .data = &sctp_sack_timeout,
+ .maxlen = sizeof(long),
+ .mode = 0644,
+ .proc_handler = &proc_doulongvec_ms_jiffies_minmax,
+ .strategy = &sctp_sysctl_jiffies_ms,
+ .extra1 = &sack_timer_min,
+ .extra2 = &sack_timer_max,
+ },
{ .ctl_name = 0 }
};
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 0ec0fde6e6c5..d2f04ebe5081 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -57,7 +57,7 @@
/* Initialize a new transport from provided memory. */
static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr,
- int gfp)
+ unsigned int __nocast gfp)
{
/* Copy in the address. */
peer->ipaddr = *addr;
@@ -103,7 +103,6 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
/* Set up the heartbeat timer. */
init_timer(&peer->hb_timer);
- peer->hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
peer->hb_timer.function = sctp_generate_heartbeat_event;
peer->hb_timer.data = (unsigned long)peer;
@@ -122,7 +121,8 @@ static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
}
/* Allocate and initialize a new transport. */
-struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
+struct sctp_transport *sctp_transport_new(const union sctp_addr *addr,
+ unsigned int __nocast gfp)
{
struct sctp_transport *transport;
diff --git a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
index 17d0ff534735..0abd5101107c 100644
--- a/net/sctp/ulpevent.c
+++ b/net/sctp/ulpevent.c
@@ -74,7 +74,7 @@ SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
/* Create a new sctp_ulpevent. */
SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sk_buff *skb;
@@ -136,7 +136,7 @@ static inline void sctp_ulpevent_release_owner(struct sctp_ulpevent *event)
struct sctp_ulpevent *sctp_ulpevent_make_assoc_change(
const struct sctp_association *asoc,
__u16 flags, __u16 state, __u16 error, __u16 outbound,
- __u16 inbound, int gfp)
+ __u16 inbound, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_assoc_change *sac;
@@ -237,7 +237,7 @@ fail:
struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
const struct sctp_association *asoc,
const struct sockaddr_storage *aaddr,
- int flags, int state, int error, int gfp)
+ int flags, int state, int error, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_paddr_change *spc;
@@ -350,7 +350,7 @@ fail:
*/
struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
const struct sctp_association *asoc, struct sctp_chunk *chunk,
- __u16 flags, int gfp)
+ __u16 flags, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_remote_error *sre;
@@ -448,7 +448,7 @@ fail:
*/
struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
const struct sctp_association *asoc, struct sctp_chunk *chunk,
- __u16 flags, __u32 error, int gfp)
+ __u16 flags, __u32 error, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_send_failed *ssf;
@@ -557,7 +557,7 @@ fail:
*/
struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
const struct sctp_association *asoc,
- __u16 flags, int gfp)
+ __u16 flags, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_shutdown_event *sse;
@@ -620,7 +620,7 @@ fail:
* 5.3.1.6 SCTP_ADAPTION_INDICATION
*/
struct sctp_ulpevent *sctp_ulpevent_make_adaption_indication(
- const struct sctp_association *asoc, int gfp)
+ const struct sctp_association *asoc, unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_adaption_event *sai;
@@ -657,7 +657,7 @@ fail:
*/
struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
struct sctp_chunk *chunk,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sctp_ulpevent *event = NULL;
struct sk_buff *skb;
@@ -718,7 +718,8 @@ fail:
* various events.
*/
struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
- const struct sctp_association *asoc, __u32 indication, int gfp)
+ const struct sctp_association *asoc, __u32 indication,
+ unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_pdapi_event *pd;
diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
index d5dd2cf7ac4a..8bbc279d6c99 100644
--- a/net/sctp/ulpqueue.c
+++ b/net/sctp/ulpqueue.c
@@ -100,7 +100,7 @@ void sctp_ulpq_free(struct sctp_ulpq *ulpq)
/* Process an incoming DATA chunk. */
int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sk_buff_head temp;
sctp_data_chunk_t *hdr;
@@ -778,7 +778,8 @@ static __u16 sctp_ulpq_renege_frags(struct sctp_ulpq *ulpq, __u16 needed)
/* Partial deliver the first message as there is pressure on rwnd. */
void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
- struct sctp_chunk *chunk, int gfp)
+ struct sctp_chunk *chunk,
+ unsigned int __nocast gfp)
{
struct sctp_ulpevent *event;
struct sctp_association *asoc;
@@ -802,7 +803,7 @@ void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
/* Renege some packets to make room for an incoming chunk. */
void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
- int gfp)
+ unsigned int __nocast gfp)
{
struct sctp_association *asoc;
__u16 needed, freed;
@@ -841,7 +842,7 @@ void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
/* Notify the application if an association is aborted and in
* partial delivery mode. Send up any pending received messages.
*/
-void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int gfp)
+void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, unsigned int __nocast gfp)
{
struct sctp_ulpevent *ev = NULL;
struct sock *sk;
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 32e8acbc60fe..62a073495276 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -41,6 +41,7 @@ EXPORT_SYMBOL(rpc_release_task);
/* RPC client functions */
EXPORT_SYMBOL(rpc_create_client);
+EXPORT_SYMBOL(rpc_new_client);
EXPORT_SYMBOL(rpc_clone_client);
EXPORT_SYMBOL(rpc_bind_new_program);
EXPORT_SYMBOL(rpc_destroy_client);
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 05907035bc96..56db8f13e6cb 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1185,8 +1185,8 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
arg->page_len = (pages-2)*PAGE_SIZE;
arg->len = (pages-1)*PAGE_SIZE;
arg->tail[0].iov_len = 0;
-
- try_to_freeze(PF_FREEZE);
+
+ try_to_freeze();
if (signalled())
return -EINTR;
@@ -1227,7 +1227,7 @@ svc_recv(struct svc_serv *serv, struct svc_rqst *rqstp, long timeout)
schedule_timeout(timeout);
- try_to_freeze(PF_FREEZE);
+ try_to_freeze();
spin_lock_bh(&serv->sv_lock);
remove_wait_queue(&rqstp->rq_wait, &wait);
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index eca92405948f..3c654e06b084 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -145,8 +145,6 @@ __xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task)
if (test_and_set_bit(XPRT_LOCKED, &xprt->sockstate)) {
if (task == xprt->snd_task)
return 1;
- if (task == NULL)
- return 0;
goto out_sleep;
}
if (xprt->nocong || __xprt_get_cong(xprt, task)) {
@@ -970,7 +968,7 @@ tcp_read_request(struct rpc_xprt *xprt, skb_reader_t *desc)
goto out;
}
- dprintk("RPC: XID %08x read %u bytes\n",
+ dprintk("RPC: XID %08x read %Zd bytes\n",
ntohl(xprt->tcp_xid), r);
dprintk("RPC: xprt = %p, tcp_copied = %lu, tcp_offset = %u, tcp_reclen = %u\n",
xprt, xprt->tcp_copied, xprt->tcp_offset, xprt->tcp_reclen);
@@ -1006,7 +1004,7 @@ tcp_read_discard(struct rpc_xprt *xprt, skb_reader_t *desc)
desc->count -= len;
desc->offset += len;
xprt->tcp_offset += len;
- dprintk("RPC: discarded %u bytes\n", len);
+ dprintk("RPC: discarded %Zu bytes\n", len);
tcp_check_recm(xprt);
}
diff --git a/net/unix/Kconfig b/net/unix/Kconfig
new file mode 100644
index 000000000000..5a69733bcdad
--- /dev/null
+++ b/net/unix/Kconfig
@@ -0,0 +1,21 @@
+#
+# Unix Domain Sockets
+#
+
+config UNIX
+ tristate "Unix domain sockets"
+ ---help---
+ If you say Y here, you will include support for Unix domain sockets;
+ sockets are the standard Unix mechanism for establishing and
+ accessing network connections. Many commonly used programs such as
+ the X Window system and syslog use these sockets even if your
+ machine is not connected to any network. Unless you are working on
+ an embedded system or something similar, you therefore definitely
+ want to say Y here.
+
+ To compile this driver as a module, choose M here: the module will be
+ called unix. Note that several important services won't work
+ correctly if you say M here and then neglect to load the module.
+
+ Say Y unless you know what you are doing.
+
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index c420eba4876b..d403e34088ad 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -302,7 +302,7 @@ static void unix_write_space(struct sock *sk)
* may receive messages only from that peer. */
static void unix_dgram_disconnected(struct sock *sk, struct sock *other)
{
- if (skb_queue_len(&sk->sk_receive_queue)) {
+ if (!skb_queue_empty(&sk->sk_receive_queue)) {
skb_queue_purge(&sk->sk_receive_queue);
wake_up_interruptible_all(&unix_sk(sk)->peer_wait);
@@ -1619,7 +1619,7 @@ static long unix_stream_data_wait(struct sock * sk, long timeo)
for (;;) {
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
- if (skb_queue_len(&sk->sk_receive_queue) ||
+ if (!skb_queue_empty(&sk->sk_receive_queue) ||
sk->sk_err ||
(sk->sk_shutdown & RCV_SHUTDOWN) ||
signal_pending(current) ||
diff --git a/net/wanrouter/Kconfig b/net/wanrouter/Kconfig
new file mode 100644
index 000000000000..1debe1cb054e
--- /dev/null
+++ b/net/wanrouter/Kconfig
@@ -0,0 +1,29 @@
+#
+# Configuration for WAN router
+#
+
+config WAN_ROUTER
+ tristate "WAN router"
+ depends on EXPERIMENTAL
+ ---help---
+ Wide Area Networks (WANs), such as X.25, frame relay and leased
+ lines, are used to interconnect Local Area Networks (LANs) over vast
+ distances with data transfer rates significantly higher than those
+ achievable with commonly used asynchronous modem connections.
+ Usually, a quite expensive external device called a `WAN router' is
+ needed to connect to a WAN.
+
+ As an alternative, WAN routing can be built into the Linux kernel.
+ With relatively inexpensive WAN interface cards available on the
+ market, a perfectly usable router can be built for less than half
+ the price of an external router. If you have one of those cards and
+ wish to use your Linux box as a WAN router, say Y here and also to
+ the WAN driver for your card, below. You will then need the
+ wan-tools package which is available from <ftp://ftp.sangoma.com/>.
+ Read <file:Documentation/networking/wan-router.txt> for more
+ information.
+
+ To compile WAN routing support as a module, choose M here: the
+ module will be called wanrouter.
+
+ If unsure, say N.
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index d6844ac226f5..13b650ad22e2 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -358,10 +358,10 @@ int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
*/
-unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
+__be16 wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
{
int cnt = skb->data[0] ? 0 : 1; /* there may be a pad present */
- unsigned short ethertype;
+ __be16 ethertype;
switch (skb->data[cnt]) {
case NLPID_IP: /* IP datagramm */
@@ -379,7 +379,7 @@ unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
skb->data[cnt+3], dev->name);
return 0;
}
- ethertype = *((unsigned short*)&skb->data[cnt+4]);
+ ethertype = *((__be16*)&skb->data[cnt+4]);
cnt += 6;
break;
diff --git a/net/x25/Kconfig b/net/x25/Kconfig
new file mode 100644
index 000000000000..e6759c9660bb
--- /dev/null
+++ b/net/x25/Kconfig
@@ -0,0 +1,36 @@
+#
+# CCITT X.25 Packet Layer
+#
+
+config X25
+ tristate "CCITT X.25 Packet Layer (EXPERIMENTAL)"
+ depends on EXPERIMENTAL
+ ---help---
+ X.25 is a set of standardized network protocols, similar in scope to
+ frame relay; the one physical line from your box to the X.25 network
+ entry point can carry several logical point-to-point connections
+ (called "virtual circuits") to other computers connected to the X.25
+ network. Governments, banks, and other organizations tend to use it
+ to connect to each other or to form Wide Area Networks (WANs). Many
+ countries have public X.25 networks. X.25 consists of two
+ protocols: the higher level Packet Layer Protocol (PLP) (say Y here
+ if you want that) and the lower level data link layer protocol LAPB
+ (say Y to "LAPB Data Link Driver" below if you want that).
+
+ You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
+ <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>.
+ Information about X.25 for Linux is contained in the files
+ <file:Documentation/networking/x25.txt> and
+ <file:Documentation/networking/x25-iface.txt>.
+
+ One connects to an X.25 network either with a dedicated network card
+ using the X.21 protocol (not yet supported by Linux) or one can do
+ X.25 over a standard telephone line using an ordinary modem (say Y
+ to "X.25 async driver" below) or over Ethernet using an ordinary
+ Ethernet card and the LAPB over Ethernet (say Y to "LAPB Data Link
+ Driver" and "LAPB over Ethernet driver" below).
+
+ To compile this driver as a module, choose M here: the module
+ will be called x25. If unsure, say N.
+
+
diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig
index 58ca6a972c48..0c1c04322baf 100644
--- a/net/xfrm/Kconfig
+++ b/net/xfrm/Kconfig
@@ -1,6 +1,10 @@
#
# XFRM configuration
#
+config XFRM
+ bool
+ depends on NET
+
config XFRM_USER
tristate "IPsec user configuration interface"
depends on INET && XFRM
@@ -10,3 +14,14 @@ config XFRM_USER
If unsure, say Y.
+config NET_KEY
+ tristate "PF_KEY sockets"
+ select XFRM
+ ---help---
+ PF_KEYv2 socket family, compatible to KAME ones.
+ They are required if you are going to use IPsec tools ported
+ from KAME.
+
+ Say Y unless you know what you are doing.
+
+
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c
index 8ca7ecdb68fb..cb02baa63256 100644
--- a/scripts/basic/docproc.c
+++ b/scripts/basic/docproc.c
@@ -52,7 +52,7 @@ FILEONLY *internalfunctions;
FILEONLY *externalfunctions;
FILEONLY *symbolsonly;
-typedef void FILELINE(char * file, signed char * line);
+typedef void FILELINE(char * file, char * line);
FILELINE * singlefunctions;
FILELINE * entity_system;
@@ -148,9 +148,9 @@ struct symfile * filename_exist(char * filename)
* Files are separated by tabs.
*/
void adddep(char * file) { printf("\t%s", file); }
-void adddep2(char * file, signed char * line) { line = line; adddep(file); }
+void adddep2(char * file, char * line) { line = line; adddep(file); }
void noaction(char * line) { line = line; }
-void noaction2(char * file, signed char * line) { file = file; line = line; }
+void noaction2(char * file, char * line) { file = file; line = line; }
/* Echo the line without further action */
void printline(char * line) { printf("%s", line); }
@@ -179,8 +179,8 @@ void find_export_symbols(char * filename)
perror(real_filename);
}
while(fgets(line, MAXLINESZ, fp)) {
- signed char *p;
- signed char *e;
+ char *p;
+ char *e;
if (((p = strstr(line, "EXPORT_SYMBOL_GPL")) != 0) ||
((p = strstr(line, "EXPORT_SYMBOL")) != 0)) {
/* Skip EXPORT_SYMBOL{_GPL} */
@@ -253,7 +253,7 @@ void extfunc(char * filename) { docfunctions(filename, FUNCTION); }
* Call kernel-doc with the following parameters:
* kernel-doc -docbook -function function1 [-function function2]
*/
-void singfunc(char * filename, signed char * line)
+void singfunc(char * filename, char * line)
{
char *vec[200]; /* Enough for specific functions */
int i, idx = 0;
@@ -290,7 +290,7 @@ void singfunc(char * filename, signed char * line)
void parse_file(FILE *infile)
{
char line[MAXLINESZ];
- signed char * s;
+ char * s;
while(fgets(line, MAXLINESZ, infile)) {
if (line[0] == '!') {
s = line + 2;
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index 7f42c5d8a5a2..0b61bea869f7 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -212,23 +212,23 @@ void use_config(char *m, int slen)
if (*p == '_')
*p = '/';
else
- *p = tolower((unsigned char)*p);
+ *p = tolower((int)*p);
}
printf(" $(wildcard include/config/%s.h) \\\n", s);
}
-void parse_config_file(signed char *map, size_t len)
+void parse_config_file(char *map, size_t len)
{
int *end = (int *) (map + len);
/* start at +1, so that p can never be < map */
int *m = (int *) map + 1;
- signed char *p, *q;
+ char *p, *q;
for (; m < end; m++) {
- if (*m == INT_CONF) { p = (signed char *) m ; goto conf; }
- if (*m == INT_ONFI) { p = (signed char *) m-1; goto conf; }
- if (*m == INT_NFIG) { p = (signed char *) m-2; goto conf; }
- if (*m == INT_FIG_) { p = (signed char *) m-3; goto conf; }
+ if (*m == INT_CONF) { p = (char *) m ; goto conf; }
+ if (*m == INT_ONFI) { p = (char *) m-1; goto conf; }
+ if (*m == INT_NFIG) { p = (char *) m-2; goto conf; }
+ if (*m == INT_FIG_) { p = (char *) m-3; goto conf; }
continue;
conf:
if (p > map + len - 7)
@@ -291,9 +291,9 @@ void do_config_file(char *filename)
void parse_dep_file(void *map, size_t len)
{
- signed char *m = map;
- signed char *end = m + len;
- signed char *p;
+ char *m = map;
+ char *end = m + len;
+ char *p;
char s[PATH_MAX];
p = strchr(m, ':');
diff --git a/scripts/basic/split-include.c b/scripts/basic/split-include.c
index 60fc4d8ebaa9..459c45276cb1 100644
--- a/scripts/basic/split-include.c
+++ b/scripts/basic/split-include.c
@@ -104,7 +104,7 @@ int main(int argc, const char * argv [])
/* Read config lines. */
while (fgets(line, buffer_size, fp_config))
{
- const signed char * str_config;
+ const char * str_config;
int is_same;
int itarget;
diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c
index 70e7264c6942..bc20cab9d0d6 100644
--- a/scripts/kconfig/conf.c
+++ b/scripts/kconfig/conf.c
@@ -31,14 +31,14 @@ char *defconfig_file;
static int indent = 1;
static int valid_stdin = 1;
static int conf_cnt;
-static signed char line[128];
+static char line[128];
static struct menu *rootEntry;
static char nohelp_text[] = N_("Sorry, no help available for this option yet.\n");
-static void strip(signed char *str)
+static void strip(char *str)
{
- signed char *p = str;
+ char *p = str;
int l;
while ((isspace(*p)))
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c
index 2755c459d780..02f670cc6bb9 100644
--- a/scripts/kconfig/confdata.c
+++ b/scripts/kconfig/confdata.c
@@ -27,10 +27,10 @@ const char *conf_confnames[] = {
NULL,
};
-static char *conf_expand_value(const signed char *in)
+static char *conf_expand_value(const char *in)
{
struct symbol *sym;
- const signed char *src;
+ const char *src;
static char res_value[SYMBOL_MAXLENGTH];
char *dst, name[SYMBOL_MAXLENGTH];
diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c
index e5db10ca9564..457bec29511d 100644
--- a/scripts/kconfig/mconf.c
+++ b/scripts/kconfig/mconf.c
@@ -20,6 +20,7 @@
#include <string.h>
#include <termios.h>
#include <unistd.h>
+#include <locale.h>
#define LKC_DIRECT_LINK
#include "lkc.h"
@@ -254,8 +255,8 @@ search_help[] = N_(
" USB$ => find all CONFIG_ symbols ending with USB\n"
"\n");
-static signed char buf[4096], *bufptr = buf;
-static signed char input_buf[4096];
+static char buf[4096], *bufptr = buf;
+static char input_buf[4096];
static char filename[PATH_MAX+1] = ".config";
static char *args[1024], **argptr = args;
static int indent;
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 32197efe67ed..5180405c1a84 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -25,6 +25,8 @@ typedef Elf64_Addr kernel_ulong_t;
#include <stdint.h>
#endif
+#include <ctype.h>
+
typedef uint32_t __u32;
typedef uint16_t __u16;
typedef unsigned char __u8;
@@ -287,6 +289,58 @@ static int do_pnp_card_entry(const char *filename,
return 1;
}
+/* Looks like: pcmcia:mNcNfNfnNpfnNvaNvbNvcNvdN. */
+static int do_pcmcia_entry(const char *filename,
+ struct pcmcia_device_id *id, char *alias)
+{
+ unsigned int i;
+
+ id->manf_id = TO_NATIVE(id->manf_id);
+ id->card_id = TO_NATIVE(id->card_id);
+ id->func_id = TO_NATIVE(id->func_id);
+ id->function = TO_NATIVE(id->function);
+ id->device_no = TO_NATIVE(id->device_no);
+ for (i=0; i<4; i++) {
+ id->prod_id_hash[i] = TO_NATIVE(id->prod_id_hash[i]);
+ }
+
+ strcpy(alias, "pcmcia:");
+ ADD(alias, "m", id->match_flags & PCMCIA_DEV_ID_MATCH_MANF_ID,
+ id->manf_id);
+ ADD(alias, "c", id->match_flags & PCMCIA_DEV_ID_MATCH_CARD_ID,
+ id->card_id);
+ ADD(alias, "f", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNC_ID,
+ id->func_id);
+ ADD(alias, "fn", id->match_flags & PCMCIA_DEV_ID_MATCH_FUNCTION,
+ id->function);
+ ADD(alias, "pfn", id->match_flags & PCMCIA_DEV_ID_MATCH_DEVICE_NO,
+ id->device_no);
+ ADD(alias, "pa", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID1, id->prod_id_hash[0]);
+ ADD(alias, "pb", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID2, id->prod_id_hash[1]);
+ ADD(alias, "pc", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID3, id->prod_id_hash[2]);
+ ADD(alias, "pd", id->match_flags & PCMCIA_DEV_ID_MATCH_PROD_ID4, id->prod_id_hash[3]);
+
+ return 1;
+}
+
+
+
+static int do_of_entry (const char *filename, struct of_device_id *of, char *alias)
+{
+ char *tmp;
+ sprintf (alias, "of:N%sT%sC%s",
+ of->name[0] ? of->name : "*",
+ of->type[0] ? of->type : "*",
+ of->compatible[0] ? of->compatible : "*");
+
+ /* Replace all whitespace with underscores */
+ for (tmp = alias; tmp && *tmp; tmp++)
+ if (isspace (*tmp))
+ *tmp = '_';
+
+ return 1;
+}
+
/* Ignore any prefix, eg. v850 prepends _ */
static inline int sym_is(const char *symbol, const char *name)
{
@@ -362,6 +416,13 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
else if (sym_is(symname, "__mod_pnp_card_device_table"))
do_table(symval, sym->st_size, sizeof(struct pnp_card_device_id),
do_pnp_card_entry, mod);
+ else if (sym_is(symname, "__mod_pcmcia_device_table"))
+ do_table(symval, sym->st_size, sizeof(struct pcmcia_device_id),
+ do_pcmcia_entry, mod);
+ else if (sym_is(symname, "__mod_of_device_table"))
+ do_table(symval, sym->st_size, sizeof(struct of_device_id),
+ do_of_entry, mod);
+
}
/* Now add out buffered information to the generated C source */
diff --git a/security/keys/Makefile b/security/keys/Makefile
index ddb495d65062..c392d750b208 100644
--- a/security/keys/Makefile
+++ b/security/keys/Makefile
@@ -7,8 +7,9 @@ obj-y := \
keyring.o \
keyctl.o \
process_keys.o \
- user_defined.o \
- request_key.o
+ request_key.o \
+ request_key_auth.o \
+ user_defined.o
obj-$(CONFIG_KEYS_COMPAT) += compat.o
obj-$(CONFIG_PROC_FS) += proc.o
diff --git a/security/keys/compat.c b/security/keys/compat.c
index aff8b22dcb5c..3303673c636e 100644
--- a/security/keys/compat.c
+++ b/security/keys/compat.c
@@ -1,6 +1,6 @@
/* compat.c: 32-bit compatibility syscall for 64-bit systems
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -24,7 +24,7 @@
* - if you can, you should call sys_keyctl directly
*/
asmlinkage long compat_sys_keyctl(u32 option,
- u32 arg2, u32 arg3, u32 arg4, u32 arg5)
+ u32 arg2, u32 arg3, u32 arg4, u32 arg5)
{
switch (option) {
case KEYCTL_GET_KEYRING_ID:
@@ -71,6 +71,9 @@ asmlinkage long compat_sys_keyctl(u32 option,
case KEYCTL_NEGATE:
return keyctl_negate_key(arg2, arg3, arg4);
+ case KEYCTL_SET_REQKEY_KEYRING:
+ return keyctl_set_reqkey_keyring(arg2);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/internal.h b/security/keys/internal.h
index 67b2b93a7489..46c8602661c9 100644
--- a/security/keys/internal.h
+++ b/security/keys/internal.h
@@ -1,6 +1,6 @@
/* internal.h: authentication token and access key management internal defs
*
- * Copyright (C) 2003 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2003-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -15,6 +15,16 @@
#include <linux/key.h>
#include <linux/key-ui.h>
+#if 0
+#define kenter(FMT, a...) printk("==> %s("FMT")\n",__FUNCTION__ , ## a)
+#define kleave(FMT, a...) printk("<== %s()"FMT"\n",__FUNCTION__ , ## a)
+#define kdebug(FMT, a...) printk(FMT"\n" , ## a)
+#else
+#define kenter(FMT, a...) do {} while(0)
+#define kleave(FMT, a...) do {} while(0)
+#define kdebug(FMT, a...) do {} while(0)
+#endif
+
extern struct key_type key_type_dead;
extern struct key_type key_type_user;
@@ -66,20 +76,46 @@ extern struct key *__keyring_search_one(struct key *keyring,
const char *description,
key_perm_t perm);
+extern struct key *keyring_search_instkey(struct key *keyring,
+ key_serial_t target_id);
+
typedef int (*key_match_func_t)(const struct key *, const void *);
extern struct key *keyring_search_aux(struct key *keyring,
+ struct task_struct *tsk,
struct key_type *type,
const void *description,
key_match_func_t match);
-extern struct key *search_process_keyrings_aux(struct key_type *type,
- const void *description,
- key_match_func_t match);
+extern struct key *search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *tsk);
extern struct key *find_keyring_by_name(const char *name, key_serial_t bound);
extern int install_thread_keyring(struct task_struct *tsk);
+extern int install_process_keyring(struct task_struct *tsk);
+
+extern struct key *request_key_and_link(struct key_type *type,
+ const char *description,
+ const char *callout_info,
+ struct key *dest_keyring);
+
+/*
+ * request_key authorisation
+ */
+struct request_key_auth {
+ struct key *target_key;
+ struct task_struct *context;
+ pid_t pid;
+};
+
+extern struct key_type key_type_request_key_auth;
+extern struct key *request_key_auth_new(struct key *target,
+ struct key **_rkakey);
+
+extern struct key *key_get_instantiation_authkey(key_serial_t target_id);
/*
* keyctl functions
@@ -100,6 +136,7 @@ extern long keyctl_setperm_key(key_serial_t, key_perm_t);
extern long keyctl_instantiate_key(key_serial_t, const void __user *,
size_t, key_serial_t);
extern long keyctl_negate_key(key_serial_t, unsigned, key_serial_t);
+extern long keyctl_set_reqkey_keyring(int);
/*
diff --git a/security/keys/key.c b/security/keys/key.c
index 59402c843203..fb89f9844465 100644
--- a/security/keys/key.c
+++ b/security/keys/key.c
@@ -1,6 +1,6 @@
/* key.c: basic authentication token and access key management
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -294,7 +294,6 @@ struct key *key_alloc(struct key_type *type, const char *desc,
}
atomic_set(&key->usage, 1);
- rwlock_init(&key->lock);
init_rwsem(&key->sem);
key->type = type;
key->user = user;
@@ -308,7 +307,7 @@ struct key *key_alloc(struct key_type *type, const char *desc,
key->payload.data = NULL;
if (!not_in_quota)
- key->flags |= KEY_FLAG_IN_QUOTA;
+ key->flags |= 1 << KEY_FLAG_IN_QUOTA;
memset(&key->type_data, 0, sizeof(key->type_data));
@@ -359,7 +358,7 @@ int key_payload_reserve(struct key *key, size_t datalen)
key_check(key);
/* contemplate the quota adjustment */
- if (delta != 0 && key->flags & KEY_FLAG_IN_QUOTA) {
+ if (delta != 0 && test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
spin_lock(&key->user->lock);
if (delta > 0 &&
@@ -392,7 +391,8 @@ EXPORT_SYMBOL(key_payload_reserve);
static int __key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
int ret, awaken;
@@ -405,27 +405,25 @@ static int __key_instantiate_and_link(struct key *key,
down_write(&key_construction_sem);
/* can't instantiate twice */
- if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* instantiate the key */
ret = key->type->instantiate(key, data, datalen);
if (ret == 0) {
/* mark the key as being instantiated */
- write_lock(&key->lock);
-
atomic_inc(&key->user->nikeys);
- key->flags |= KEY_FLAG_INSTANTIATED;
+ set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
- if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
- key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+ if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
awaken = 1;
- }
-
- write_unlock(&key->lock);
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
+
+ /* disable the authorisation key */
+ if (instkey)
+ key_revoke(instkey);
}
}
@@ -446,19 +444,21 @@ static int __key_instantiate_and_link(struct key *key,
int key_instantiate_and_link(struct key *key,
const void *data,
size_t datalen,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
int ret;
if (keyring)
down_write(&keyring->sem);
- ret = __key_instantiate_and_link(key, data, datalen, keyring);
+ ret = __key_instantiate_and_link(key, data, datalen, keyring, instkey);
if (keyring)
up_write(&keyring->sem);
return ret;
+
} /* end key_instantiate_and_link() */
EXPORT_SYMBOL(key_instantiate_and_link);
@@ -469,7 +469,8 @@ EXPORT_SYMBOL(key_instantiate_and_link);
*/
int key_negate_and_link(struct key *key,
unsigned timeout,
- struct key *keyring)
+ struct key *keyring,
+ struct key *instkey)
{
struct timespec now;
int ret, awaken;
@@ -486,26 +487,26 @@ int key_negate_and_link(struct key *key,
down_write(&key_construction_sem);
/* can't instantiate twice */
- if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
+ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
/* mark the key as being negatively instantiated */
- write_lock(&key->lock);
-
atomic_inc(&key->user->nikeys);
- key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
+ set_bit(KEY_FLAG_NEGATIVE, &key->flags);
+ set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
now = current_kernel_time();
key->expiry = now.tv_sec + timeout;
- if (key->flags & KEY_FLAG_USER_CONSTRUCT) {
- key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
+ if (test_and_clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags))
awaken = 1;
- }
- write_unlock(&key->lock);
ret = 0;
/* and link it into the destination keyring */
if (keyring)
ret = __key_link(keyring, key);
+
+ /* disable the authorisation key */
+ if (instkey)
+ key_revoke(instkey);
}
up_write(&key_construction_sem);
@@ -553,8 +554,10 @@ static void key_cleanup(void *data)
rb_erase(&key->serial_node, &key_serial_tree);
spin_unlock(&key_serial_lock);
+ key_check(key);
+
/* deal with the user's key tracking and quota */
- if (key->flags & KEY_FLAG_IN_QUOTA) {
+ if (test_bit(KEY_FLAG_IN_QUOTA, &key->flags)) {
spin_lock(&key->user->lock);
key->user->qnkeys--;
key->user->qnbytes -= key->quotalen;
@@ -562,7 +565,7 @@ static void key_cleanup(void *data)
}
atomic_dec(&key->user->nkeys);
- if (key->flags & KEY_FLAG_INSTANTIATED)
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
atomic_dec(&key->user->nikeys);
key_user_put(key->user);
@@ -631,9 +634,9 @@ struct key *key_lookup(key_serial_t id)
goto error;
found:
- /* pretent doesn't exist if it's dead */
+ /* pretend it doesn't exist if it's dead */
if (atomic_read(&key->usage) == 0 ||
- (key->flags & KEY_FLAG_DEAD) ||
+ test_bit(KEY_FLAG_DEAD, &key->flags) ||
key->type == &key_type_dead)
goto not_found;
@@ -708,12 +711,9 @@ static inline struct key *__key_update(struct key *key, const void *payload,
ret = key->type->update(key, payload, plen);
- if (ret == 0) {
+ if (ret == 0)
/* updating a negative key instantiates it */
- write_lock(&key->lock);
- key->flags &= ~KEY_FLAG_NEGATIVE;
- write_unlock(&key->lock);
- }
+ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
up_write(&key->sem);
@@ -793,7 +793,7 @@ struct key *key_create_or_update(struct key *keyring,
}
/* instantiate it and link it into the target keyring */
- ret = __key_instantiate_and_link(key, payload, plen, keyring);
+ ret = __key_instantiate_and_link(key, payload, plen, keyring, NULL);
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
@@ -841,12 +841,9 @@ int key_update(struct key *key, const void *payload, size_t plen)
down_write(&key->sem);
ret = key->type->update(key, payload, plen);
- if (ret == 0) {
+ if (ret == 0)
/* updating a negative key instantiates it */
- write_lock(&key->lock);
- key->flags &= ~KEY_FLAG_NEGATIVE;
- write_unlock(&key->lock);
- }
+ clear_bit(KEY_FLAG_NEGATIVE, &key->flags);
up_write(&key->sem);
}
@@ -892,10 +889,7 @@ struct key *key_duplicate(struct key *source, const char *desc)
goto error2;
atomic_inc(&key->user->nikeys);
-
- write_lock(&key->lock);
- key->flags |= KEY_FLAG_INSTANTIATED;
- write_unlock(&key->lock);
+ set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
error_k:
up_read(&key_types_sem);
@@ -922,9 +916,7 @@ void key_revoke(struct key *key)
/* make sure no one's trying to change or use the key when we mark
* it */
down_write(&key->sem);
- write_lock(&key->lock);
- key->flags |= KEY_FLAG_REVOKED;
- write_unlock(&key->lock);
+ set_bit(KEY_FLAG_REVOKED, &key->flags);
up_write(&key->sem);
} /* end key_revoke() */
@@ -975,24 +967,33 @@ void unregister_key_type(struct key_type *ktype)
/* withdraw the key type */
list_del_init(&ktype->link);
- /* need to withdraw all keys of this type */
+ /* mark all the keys of this type dead */
spin_lock(&key_serial_lock);
for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
key = rb_entry(_n, struct key, serial_node);
- if (key->type != ktype)
- continue;
+ if (key->type == ktype)
+ key->type = &key_type_dead;
+ }
+
+ spin_unlock(&key_serial_lock);
+
+ /* make sure everyone revalidates their keys */
+ synchronize_rcu();
- write_lock(&key->lock);
- key->type = &key_type_dead;
- write_unlock(&key->lock);
+ /* we should now be able to destroy the payloads of all the keys of
+ * this type with impunity */
+ spin_lock(&key_serial_lock);
+
+ for (_n = rb_first(&key_serial_tree); _n; _n = rb_next(_n)) {
+ key = rb_entry(_n, struct key, serial_node);
- /* there shouldn't be anyone looking at the description or
- * payload now */
- if (ktype->destroy)
- ktype->destroy(key);
- memset(&key->payload, 0xbd, sizeof(key->payload));
+ if (key->type == ktype) {
+ if (ktype->destroy)
+ ktype->destroy(key);
+ memset(&key->payload, 0xbd, sizeof(key->payload));
+ }
}
spin_unlock(&key_serial_lock);
@@ -1037,4 +1038,5 @@ void __init key_init(void)
/* link the two root keyrings together */
key_link(&root_session_keyring, &root_user_keyring);
+
} /* end key_init() */
diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c
index dc0011b3fac9..fea262860ea0 100644
--- a/security/keys/keyctl.c
+++ b/security/keys/keyctl.c
@@ -1,6 +1,6 @@
/* keyctl.c: userspace keyctl operations
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -49,6 +49,13 @@ asmlinkage long sys_add_key(const char __user *_type,
goto error;
type[31] = '\0';
+ if (!type[0])
+ goto error;
+
+ ret = -EPERM;
+ if (type[0] == '.')
+ goto error;
+
ret = -EFAULT;
dlen = strnlen_user(_description, PAGE_SIZE - 1);
if (dlen <= 0)
@@ -82,7 +89,7 @@ asmlinkage long sys_add_key(const char __user *_type,
}
/* find the target keyring (which must be writable) */
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
@@ -181,7 +188,7 @@ asmlinkage long sys_request_key(const char __user *_type,
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
- dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+ dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
@@ -196,23 +203,15 @@ asmlinkage long sys_request_key(const char __user *_type,
}
/* do the search */
- key = request_key(ktype, description, callout_info);
+ key = request_key_and_link(ktype, description, callout_info, dest);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error5;
}
- /* link the resulting key to the destination keyring */
- if (dest) {
- ret = key_link(dest, key);
- if (ret < 0)
- goto error6;
- }
-
ret = key->serial;
- error6:
- key_put(key);
+ key_put(key);
error5:
key_type_put(ktype);
error4:
@@ -237,7 +236,7 @@ long keyctl_get_keyring_ID(key_serial_t id, int create)
struct key *key;
long ret;
- key = lookup_user_key(id, create, 0, KEY_SEARCH);
+ key = lookup_user_key(NULL, id, create, 0, KEY_SEARCH);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -324,7 +323,7 @@ long keyctl_update_key(key_serial_t id,
}
/* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 0, KEY_WRITE);
+ key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -352,7 +351,7 @@ long keyctl_revoke_key(key_serial_t id)
struct key *key;
long ret;
- key = lookup_user_key(id, 0, 0, KEY_WRITE);
+ key = lookup_user_key(NULL, id, 0, 0, KEY_WRITE);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -378,7 +377,7 @@ long keyctl_keyring_clear(key_serial_t ringid)
struct key *keyring;
long ret;
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
@@ -404,13 +403,13 @@ long keyctl_keyring_link(key_serial_t id, key_serial_t ringid)
struct key *keyring, *key;
long ret;
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
- key = lookup_user_key(id, 1, 0, KEY_LINK);
+ key = lookup_user_key(NULL, id, 1, 0, KEY_LINK);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -438,13 +437,13 @@ long keyctl_keyring_unlink(key_serial_t id, key_serial_t ringid)
struct key *keyring, *key;
long ret;
- keyring = lookup_user_key(ringid, 0, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error;
}
- key = lookup_user_key(id, 0, 0, 0);
+ key = lookup_user_key(NULL, id, 0, 0, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error2;
@@ -475,16 +474,29 @@ long keyctl_describe_key(key_serial_t keyid,
char __user *buffer,
size_t buflen)
{
- struct key *key;
+ struct key *key, *instkey;
char *tmpbuf;
long ret;
- key = lookup_user_key(keyid, 0, 1, KEY_VIEW);
+ key = lookup_user_key(NULL, keyid, 0, 1, KEY_VIEW);
if (IS_ERR(key)) {
+ /* viewing a key under construction is permitted if we have the
+ * authorisation token handy */
+ if (PTR_ERR(key) == -EACCES) {
+ instkey = key_get_instantiation_authkey(keyid);
+ if (!IS_ERR(instkey)) {
+ key_put(instkey);
+ key = lookup_user_key(NULL, keyid, 0, 1, 0);
+ if (!IS_ERR(key))
+ goto okay;
+ }
+ }
+
ret = PTR_ERR(key);
goto error;
}
+okay:
/* calculate how much description we're going to return */
ret = -ENOMEM;
tmpbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
@@ -568,7 +580,7 @@ long keyctl_keyring_search(key_serial_t ringid,
goto error2;
/* get the keyring at which to begin the search */
- keyring = lookup_user_key(ringid, 0, 0, KEY_SEARCH);
+ keyring = lookup_user_key(NULL, ringid, 0, 0, KEY_SEARCH);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
@@ -577,7 +589,7 @@ long keyctl_keyring_search(key_serial_t ringid,
/* get the destination keyring if specified */
dest = NULL;
if (destringid) {
- dest = lookup_user_key(destringid, 1, 0, KEY_WRITE);
+ dest = lookup_user_key(NULL, destringid, 1, 0, KEY_WRITE);
if (IS_ERR(dest)) {
ret = PTR_ERR(dest);
goto error3;
@@ -656,24 +668,23 @@ long keyctl_read_key(key_serial_t keyid, char __user *buffer, size_t buflen)
long ret;
/* find the key first */
- key = lookup_user_key(keyid, 0, 0, 0);
+ key = lookup_user_key(NULL, keyid, 0, 0, 0);
if (!IS_ERR(key)) {
/* see if we can read it directly */
if (key_permission(key, KEY_READ))
goto can_read_key;
- /* can't; see if it's searchable from this process's
- * keyrings */
- ret = -ENOKEY;
- if (key_permission(key, KEY_SEARCH)) {
- /* okay - we do have search permission on the key
- * itself, but do we have the key? */
- skey = search_process_keyrings_aux(key->type, key,
- keyctl_read_key_same);
- if (!IS_ERR(skey))
- goto can_read_key2;
- }
-
+ /* we can't; see if it's searchable from this process's
+ * keyrings
+ * - we automatically take account of the fact that it may be
+ * dangling off an instantiation key
+ */
+ skey = search_process_keyrings(key->type, key,
+ keyctl_read_key_same, current);
+ if (!IS_ERR(skey))
+ goto can_read_key2;
+
+ ret = PTR_ERR(skey);
goto error2;
}
@@ -719,7 +730,7 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
if (uid == (uid_t) -1 && gid == (gid_t) -1)
goto error;
- key = lookup_user_key(id, 1, 1, 0);
+ key = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
@@ -728,7 +739,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
/* make the changes with the locks held to prevent chown/chown races */
ret = -EACCES;
down_write(&key->sem);
- write_lock(&key->lock);
if (!capable(CAP_SYS_ADMIN)) {
/* only the sysadmin can chown a key to some other UID */
@@ -755,7 +765,6 @@ long keyctl_chown_key(key_serial_t id, uid_t uid, gid_t gid)
ret = 0;
no_access:
- write_unlock(&key->lock);
up_write(&key->sem);
key_put(key);
error:
@@ -778,32 +787,25 @@ long keyctl_setperm_key(key_serial_t id, key_perm_t perm)
if (perm & ~(KEY_USR_ALL | KEY_GRP_ALL | KEY_OTH_ALL))
goto error;
- key = lookup_user_key(id, 1, 1, 0);
+ key = lookup_user_key(NULL, id, 1, 1, 0);
if (IS_ERR(key)) {
ret = PTR_ERR(key);
goto error;
}
- /* make the changes with the locks held to prevent chown/chmod
- * races */
+ /* make the changes with the locks held to prevent chown/chmod races */
ret = -EACCES;
down_write(&key->sem);
- write_lock(&key->lock);
- /* if we're not the sysadmin, we can only chmod a key that we
- * own */
- if (!capable(CAP_SYS_ADMIN) && key->uid != current->fsuid)
- goto no_access;
-
- /* changing the permissions mask */
- key->perm = perm;
- ret = 0;
+ /* if we're not the sysadmin, we can only change a key that we own */
+ if (capable(CAP_SYS_ADMIN) || key->uid == current->fsuid) {
+ key->perm = perm;
+ ret = 0;
+ }
- no_access:
- write_unlock(&key->lock);
up_write(&key->sem);
key_put(key);
- error:
+error:
return ret;
} /* end keyctl_setperm_key() */
@@ -818,7 +820,8 @@ long keyctl_instantiate_key(key_serial_t id,
size_t plen,
key_serial_t ringid)
{
- struct key *key, *keyring;
+ struct request_key_auth *rka;
+ struct key *instkey, *keyring;
void *payload;
long ret;
@@ -840,18 +843,21 @@ long keyctl_instantiate_key(key_serial_t id,
goto error2;
}
- /* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 1, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ /* find the instantiation authorisation key */
+ instkey = key_get_instantiation_authkey(id);
+ if (IS_ERR(instkey)) {
+ ret = PTR_ERR(instkey);
goto error2;
}
- /* find the destination keyring if present (which must also be
- * writable) */
+ rka = instkey->payload.data;
+
+ /* find the destination keyring amongst those belonging to the
+ * requesting task */
keyring = NULL;
if (ringid) {
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(rka->context, ringid, 1, 0,
+ KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error3;
@@ -859,11 +865,12 @@ long keyctl_instantiate_key(key_serial_t id,
}
/* instantiate the key and link it into a keyring */
- ret = key_instantiate_and_link(key, payload, plen, keyring);
+ ret = key_instantiate_and_link(rka->target_key, payload, plen,
+ keyring, instkey);
key_put(keyring);
error3:
- key_put(key);
+ key_put(instkey);
error2:
kfree(payload);
error:
@@ -878,21 +885,24 @@ long keyctl_instantiate_key(key_serial_t id,
*/
long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
{
- struct key *key, *keyring;
+ struct request_key_auth *rka;
+ struct key *instkey, *keyring;
long ret;
- /* find the target key (which must be writable) */
- key = lookup_user_key(id, 0, 1, KEY_WRITE);
- if (IS_ERR(key)) {
- ret = PTR_ERR(key);
+ /* find the instantiation authorisation key */
+ instkey = key_get_instantiation_authkey(id);
+ if (IS_ERR(instkey)) {
+ ret = PTR_ERR(instkey);
goto error;
}
+ rka = instkey->payload.data;
+
/* find the destination keyring if present (which must also be
* writable) */
keyring = NULL;
if (ringid) {
- keyring = lookup_user_key(ringid, 1, 0, KEY_WRITE);
+ keyring = lookup_user_key(NULL, ringid, 1, 0, KEY_WRITE);
if (IS_ERR(keyring)) {
ret = PTR_ERR(keyring);
goto error2;
@@ -900,11 +910,11 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
}
/* instantiate the key and link it into a keyring */
- ret = key_negate_and_link(key, timeout, keyring);
+ ret = key_negate_and_link(rka->target_key, timeout, keyring, instkey);
key_put(keyring);
error2:
- key_put(key);
+ key_put(instkey);
error:
return ret;
@@ -912,6 +922,44 @@ long keyctl_negate_key(key_serial_t id, unsigned timeout, key_serial_t ringid)
/*****************************************************************************/
/*
+ * set the default keyring in which request_key() will cache keys
+ * - return the old setting
+ */
+long keyctl_set_reqkey_keyring(int reqkey_defl)
+{
+ int ret;
+
+ switch (reqkey_defl) {
+ case KEY_REQKEY_DEFL_THREAD_KEYRING:
+ ret = install_thread_keyring(current);
+ if (ret < 0)
+ return ret;
+ goto set;
+
+ case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+ ret = install_process_keyring(current);
+ if (ret < 0)
+ return ret;
+
+ case KEY_REQKEY_DEFL_DEFAULT:
+ case KEY_REQKEY_DEFL_SESSION_KEYRING:
+ case KEY_REQKEY_DEFL_USER_KEYRING:
+ case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+ set:
+ current->jit_keyring = reqkey_defl;
+
+ case KEY_REQKEY_DEFL_NO_CHANGE:
+ return current->jit_keyring;
+
+ case KEY_REQKEY_DEFL_GROUP_KEYRING:
+ default:
+ return -EINVAL;
+ }
+
+} /* end keyctl_set_reqkey_keyring() */
+
+/*****************************************************************************/
+/*
* the key control system call
*/
asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
@@ -980,6 +1028,9 @@ asmlinkage long sys_keyctl(int option, unsigned long arg2, unsigned long arg3,
(unsigned) arg3,
(key_serial_t) arg4);
+ case KEYCTL_SET_REQKEY_KEYRING:
+ return keyctl_set_reqkey_keyring(arg2);
+
default:
return -EOPNOTSUPP;
}
diff --git a/security/keys/keyring.c b/security/keys/keyring.c
index e2ab4f8e7481..a1f6bac647a1 100644
--- a/security/keys/keyring.c
+++ b/security/keys/keyring.c
@@ -1,6 +1,6 @@
/* keyring.c: keyring handling
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -129,13 +129,20 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
int loop, ret;
const unsigned limit =
- (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key);
+ (PAGE_SIZE - sizeof(*klist)) / sizeof(struct key *);
ret = 0;
- sklist = source->payload.subscriptions;
- if (sklist && sklist->nkeys > 0) {
+ /* find out how many keys are currently linked */
+ rcu_read_lock();
+ sklist = rcu_dereference(source->payload.subscriptions);
+ max = 0;
+ if (sklist)
max = sklist->nkeys;
+ rcu_read_unlock();
+
+ /* allocate a new payload and stuff load with key links */
+ if (max > 0) {
BUG_ON(max > limit);
max = (max + 3) & ~3;
@@ -143,21 +150,27 @@ static int keyring_duplicate(struct key *keyring, const struct key *source)
max = limit;
ret = -ENOMEM;
- size = sizeof(*klist) + sizeof(struct key) * max;
+ size = sizeof(*klist) + sizeof(struct key *) * max;
klist = kmalloc(size, GFP_KERNEL);
if (!klist)
goto error;
+ /* set links */
+ rcu_read_lock();
+ sklist = rcu_dereference(source->payload.subscriptions);
+
klist->maxkeys = max;
klist->nkeys = sklist->nkeys;
memcpy(klist->keys,
sklist->keys,
- sklist->nkeys * sizeof(struct key));
+ sklist->nkeys * sizeof(struct key *));
for (loop = klist->nkeys - 1; loop >= 0; loop--)
atomic_inc(&klist->keys[loop]->usage);
- keyring->payload.subscriptions = klist;
+ rcu_read_unlock();
+
+ rcu_assign_pointer(keyring->payload.subscriptions, klist);
ret = 0;
}
@@ -192,7 +205,7 @@ static void keyring_destroy(struct key *keyring)
write_unlock(&keyring_name_lock);
}
- klist = keyring->payload.subscriptions;
+ klist = rcu_dereference(keyring->payload.subscriptions);
if (klist) {
for (loop = klist->nkeys - 1; loop >= 0; loop--)
key_put(klist->keys[loop]);
@@ -216,17 +229,20 @@ static void keyring_describe(const struct key *keyring, struct seq_file *m)
seq_puts(m, "[anon]");
}
- klist = keyring->payload.subscriptions;
+ rcu_read_lock();
+ klist = rcu_dereference(keyring->payload.subscriptions);
if (klist)
seq_printf(m, ": %u/%u", klist->nkeys, klist->maxkeys);
else
seq_puts(m, ": empty");
+ rcu_read_unlock();
} /* end keyring_describe() */
/*****************************************************************************/
/*
* read a list of key IDs from the keyring's contents
+ * - the keyring's semaphore is read-locked
*/
static long keyring_read(const struct key *keyring,
char __user *buffer, size_t buflen)
@@ -237,7 +253,7 @@ static long keyring_read(const struct key *keyring,
int loop, ret;
ret = 0;
- klist = keyring->payload.subscriptions;
+ klist = rcu_dereference(keyring->payload.subscriptions);
if (klist) {
/* calculate how much data we could return */
@@ -292,7 +308,7 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
uid, gid, KEY_USR_ALL, not_in_quota);
if (!IS_ERR(keyring)) {
- ret = key_instantiate_and_link(keyring, NULL, 0, dest);
+ ret = key_instantiate_and_link(keyring, NULL, 0, dest, NULL);
if (ret < 0) {
key_put(keyring);
keyring = ERR_PTR(ret);
@@ -310,17 +326,18 @@ struct key *keyring_alloc(const char *description, uid_t uid, gid_t gid,
* - we only find keys on which we have search permission
* - we use the supplied match function to see if the description (or other
* feature of interest) matches
- * - we readlock the keyrings as we search down the tree
+ * - we rely on RCU to prevent the keyring lists from disappearing on us
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we only found negative matching keys
*/
struct key *keyring_search_aux(struct key *keyring,
+ struct task_struct *context,
struct key_type *type,
const void *description,
key_match_func_t match)
{
struct {
- struct key *keyring;
+ struct keyring_list *keylist;
int kix;
} stack[KEYRING_SEARCH_MAX_DEPTH];
@@ -328,13 +345,15 @@ struct key *keyring_search_aux(struct key *keyring,
struct timespec now;
struct key *key;
long err;
- int sp, psp, kix;
+ int sp, kix;
key_check(keyring);
+ rcu_read_lock();
+
/* top keyring must have search permission to begin the search */
key = ERR_PTR(-EACCES);
- if (!key_permission(keyring, KEY_SEARCH))
+ if (!key_task_permission(keyring, context, KEY_SEARCH))
goto error;
key = ERR_PTR(-ENOTDIR);
@@ -347,11 +366,10 @@ struct key *keyring_search_aux(struct key *keyring,
/* start processing a new keyring */
descend:
- read_lock(&keyring->lock);
- if (keyring->flags & KEY_FLAG_REVOKED)
+ if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
goto not_this_keyring;
- keylist = keyring->payload.subscriptions;
+ keylist = rcu_dereference(keyring->payload.subscriptions);
if (!keylist)
goto not_this_keyring;
@@ -364,7 +382,7 @@ struct key *keyring_search_aux(struct key *keyring,
continue;
/* skip revoked keys and expired keys */
- if (key->flags & KEY_FLAG_REVOKED)
+ if (test_bit(KEY_FLAG_REVOKED, &key->flags))
continue;
if (key->expiry && now.tv_sec >= key->expiry)
@@ -375,11 +393,11 @@ struct key *keyring_search_aux(struct key *keyring,
continue;
/* key must have search permissions */
- if (!key_permission(key, KEY_SEARCH))
+ if (!key_task_permission(key, context, KEY_SEARCH))
continue;
/* we set a different error code if we find a negative key */
- if (key->flags & KEY_FLAG_NEGATIVE) {
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
err = -ENOKEY;
continue;
}
@@ -390,48 +408,37 @@ struct key *keyring_search_aux(struct key *keyring,
/* search through the keyrings nested in this one */
kix = 0;
ascend:
- while (kix < keylist->nkeys) {
+ for (; kix < keylist->nkeys; kix++) {
key = keylist->keys[kix];
if (key->type != &key_type_keyring)
- goto next;
+ continue;
/* recursively search nested keyrings
* - only search keyrings for which we have search permission
*/
if (sp >= KEYRING_SEARCH_MAX_DEPTH)
- goto next;
-
- if (!key_permission(key, KEY_SEARCH))
- goto next;
+ continue;
- /* evade loops in the keyring tree */
- for (psp = 0; psp < sp; psp++)
- if (stack[psp].keyring == keyring)
- goto next;
+ if (!key_task_permission(key, context, KEY_SEARCH))
+ continue;
/* stack the current position */
- stack[sp].keyring = keyring;
+ stack[sp].keylist = keylist;
stack[sp].kix = kix;
sp++;
/* begin again with the new keyring */
keyring = key;
goto descend;
-
- next:
- kix++;
}
/* the keyring we're looking at was disqualified or didn't contain a
* matching key */
not_this_keyring:
- read_unlock(&keyring->lock);
-
if (sp > 0) {
/* resume the processing of a keyring higher up in the tree */
sp--;
- keyring = stack[sp].keyring;
- keylist = keyring->payload.subscriptions;
+ keylist = stack[sp].keylist;
kix = stack[sp].kix + 1;
goto ascend;
}
@@ -442,16 +449,9 @@ struct key *keyring_search_aux(struct key *keyring,
/* we found a viable match */
found:
atomic_inc(&key->usage);
- read_unlock(&keyring->lock);
-
- /* unwind the keyring stack */
- while (sp > 0) {
- sp--;
- read_unlock(&stack[sp].keyring->lock);
- }
-
key_check(key);
error:
+ rcu_read_unlock();
return key;
} /* end keyring_search_aux() */
@@ -469,7 +469,11 @@ struct key *keyring_search(struct key *keyring,
struct key_type *type,
const char *description)
{
- return keyring_search_aux(keyring, type, description, type->match);
+ if (!type->match)
+ return ERR_PTR(-ENOKEY);
+
+ return keyring_search_aux(keyring, current,
+ type, description, type->match);
} /* end keyring_search() */
@@ -489,15 +493,18 @@ struct key *__keyring_search_one(struct key *keyring,
struct key *key;
int loop;
- klist = keyring->payload.subscriptions;
+ rcu_read_lock();
+
+ klist = rcu_dereference(keyring->payload.subscriptions);
if (klist) {
for (loop = 0; loop < klist->nkeys; loop++) {
key = klist->keys[loop];
if (key->type == ktype &&
- key->type->match(key, description) &&
+ (!key->type->match ||
+ key->type->match(key, description)) &&
key_permission(key, perm) &&
- !(key->flags & KEY_FLAG_REVOKED)
+ !test_bit(KEY_FLAG_REVOKED, &key->flags)
)
goto found;
}
@@ -509,12 +516,58 @@ struct key *__keyring_search_one(struct key *keyring,
found:
atomic_inc(&key->usage);
error:
+ rcu_read_unlock();
return key;
} /* end __keyring_search_one() */
/*****************************************************************************/
/*
+ * search for an instantiation authorisation key matching a target key
+ * - the RCU read lock must be held by the caller
+ * - a target_id of zero specifies any valid token
+ */
+struct key *keyring_search_instkey(struct key *keyring,
+ key_serial_t target_id)
+{
+ struct request_key_auth *rka;
+ struct keyring_list *klist;
+ struct key *instkey;
+ int loop;
+
+ klist = rcu_dereference(keyring->payload.subscriptions);
+ if (klist) {
+ for (loop = 0; loop < klist->nkeys; loop++) {
+ instkey = klist->keys[loop];
+
+ if (instkey->type != &key_type_request_key_auth)
+ continue;
+
+ rka = instkey->payload.data;
+ if (target_id && rka->target_key->serial != target_id)
+ continue;
+
+ /* the auth key is revoked during instantiation */
+ if (!test_bit(KEY_FLAG_REVOKED, &instkey->flags))
+ goto found;
+
+ instkey = ERR_PTR(-EKEYREVOKED);
+ goto error;
+ }
+ }
+
+ instkey = ERR_PTR(-EACCES);
+ goto error;
+
+found:
+ atomic_inc(&instkey->usage);
+error:
+ return instkey;
+
+} /* end keyring_search_instkey() */
+
+/*****************************************************************************/
+/*
* find a keyring with the specified name
* - all named keyrings are searched
* - only find keyrings with search permission for the process
@@ -540,7 +593,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
&keyring_name_hash[bucket],
type_data.link
) {
- if (keyring->flags & KEY_FLAG_REVOKED)
+ if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
continue;
if (strcmp(keyring->description, name) != 0)
@@ -579,7 +632,7 @@ struct key *find_keyring_by_name(const char *name, key_serial_t bound)
static int keyring_detect_cycle(struct key *A, struct key *B)
{
struct {
- struct key *subtree;
+ struct keyring_list *keylist;
int kix;
} stack[KEYRING_SEARCH_MAX_DEPTH];
@@ -587,20 +640,21 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
struct key *subtree, *key;
int sp, kix, ret;
+ rcu_read_lock();
+
ret = -EDEADLK;
if (A == B)
- goto error;
+ goto cycle_detected;
subtree = B;
sp = 0;
/* start processing a new keyring */
descend:
- read_lock(&subtree->lock);
- if (subtree->flags & KEY_FLAG_REVOKED)
+ if (test_bit(KEY_FLAG_REVOKED, &subtree->flags))
goto not_this_keyring;
- keylist = subtree->payload.subscriptions;
+ keylist = rcu_dereference(subtree->payload.subscriptions);
if (!keylist)
goto not_this_keyring;
kix = 0;
@@ -619,7 +673,7 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
goto too_deep;
/* stack the current position */
- stack[sp].subtree = subtree;
+ stack[sp].keylist = keylist;
stack[sp].kix = kix;
sp++;
@@ -632,13 +686,10 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
/* the keyring we're looking at was disqualified or didn't contain a
* matching key */
not_this_keyring:
- read_unlock(&subtree->lock);
-
if (sp > 0) {
/* resume the checking of a keyring higher up in the tree */
sp--;
- subtree = stack[sp].subtree;
- keylist = subtree->payload.subscriptions;
+ keylist = stack[sp].keylist;
kix = stack[sp].kix + 1;
goto ascend;
}
@@ -646,30 +697,36 @@ static int keyring_detect_cycle(struct key *A, struct key *B)
ret = 0; /* no cycles detected */
error:
+ rcu_read_unlock();
return ret;
too_deep:
ret = -ELOOP;
- goto error_unwind;
+ goto error;
+
cycle_detected:
ret = -EDEADLK;
- error_unwind:
- read_unlock(&subtree->lock);
-
- /* unwind the keyring stack */
- while (sp > 0) {
- sp--;
- read_unlock(&stack[sp].subtree->lock);
- }
-
goto error;
} /* end keyring_detect_cycle() */
/*****************************************************************************/
/*
+ * dispose of a keyring list after the RCU grace period
+ */
+static void keyring_link_rcu_disposal(struct rcu_head *rcu)
+{
+ struct keyring_list *klist =
+ container_of(rcu, struct keyring_list, rcu);
+
+ kfree(klist);
+
+} /* end keyring_link_rcu_disposal() */
+
+/*****************************************************************************/
+/*
* link a key into to a keyring
- * - must be called with the keyring's semaphore held
+ * - must be called with the keyring's semaphore write-locked
*/
int __key_link(struct key *keyring, struct key *key)
{
@@ -679,7 +736,7 @@ int __key_link(struct key *keyring, struct key *key)
int ret;
ret = -EKEYREVOKED;
- if (keyring->flags & KEY_FLAG_REVOKED)
+ if (test_bit(KEY_FLAG_REVOKED, &keyring->flags))
goto error;
ret = -ENOTDIR;
@@ -710,9 +767,10 @@ int __key_link(struct key *keyring, struct key *key)
/* there's sufficient slack space to add directly */
atomic_inc(&key->usage);
- write_lock(&keyring->lock);
- klist->keys[klist->nkeys++] = key;
- write_unlock(&keyring->lock);
+ klist->keys[klist->nkeys] = key;
+ smp_wmb();
+ klist->nkeys++;
+ smp_wmb();
ret = 0;
}
@@ -723,7 +781,9 @@ int __key_link(struct key *keyring, struct key *key)
max += klist->maxkeys;
ret = -ENFILE;
- size = sizeof(*klist) + sizeof(*key) * max;
+ if (max > 65535)
+ goto error3;
+ size = sizeof(*klist) + sizeof(struct key *) * max;
if (size > PAGE_SIZE)
goto error3;
@@ -743,14 +803,13 @@ int __key_link(struct key *keyring, struct key *key)
/* add the key into the new space */
atomic_inc(&key->usage);
-
- write_lock(&keyring->lock);
- keyring->payload.subscriptions = nklist;
nklist->keys[nklist->nkeys++] = key;
- write_unlock(&keyring->lock);
+
+ rcu_assign_pointer(keyring->payload.subscriptions, nklist);
/* dispose of the old keyring list */
- kfree(klist);
+ if (klist)
+ call_rcu(&klist->rcu, keyring_link_rcu_disposal);
ret = 0;
}
@@ -791,11 +850,26 @@ EXPORT_SYMBOL(key_link);
/*****************************************************************************/
/*
+ * dispose of a keyring list after the RCU grace period, freeing the unlinked
+ * key
+ */
+static void keyring_unlink_rcu_disposal(struct rcu_head *rcu)
+{
+ struct keyring_list *klist =
+ container_of(rcu, struct keyring_list, rcu);
+
+ key_put(klist->keys[klist->delkey]);
+ kfree(klist);
+
+} /* end keyring_unlink_rcu_disposal() */
+
+/*****************************************************************************/
+/*
* unlink the first link to a key from a keyring
*/
int key_unlink(struct key *keyring, struct key *key)
{
- struct keyring_list *klist;
+ struct keyring_list *klist, *nklist;
int loop, ret;
key_check(keyring);
@@ -819,31 +893,46 @@ int key_unlink(struct key *keyring, struct key *key)
ret = -ENOENT;
goto error;
- key_is_present:
+key_is_present:
+ /* we need to copy the key list for RCU purposes */
+ nklist = kmalloc(sizeof(*klist) +
+ sizeof(struct key *) * klist->maxkeys,
+ GFP_KERNEL);
+ if (!nklist)
+ goto nomem;
+ nklist->maxkeys = klist->maxkeys;
+ nklist->nkeys = klist->nkeys - 1;
+
+ if (loop > 0)
+ memcpy(&nklist->keys[0],
+ &klist->keys[0],
+ loop * sizeof(struct key *));
+
+ if (loop < nklist->nkeys)
+ memcpy(&nklist->keys[loop],
+ &klist->keys[loop + 1],
+ (nklist->nkeys - loop) * sizeof(struct key *));
+
/* adjust the user's quota */
key_payload_reserve(keyring,
keyring->datalen - KEYQUOTA_LINK_BYTES);
- /* shuffle down the key pointers
- * - it might be worth shrinking the allocated memory, but that runs
- * the risk of ENOMEM as we would have to copy
- */
- write_lock(&keyring->lock);
+ rcu_assign_pointer(keyring->payload.subscriptions, nklist);
- klist->nkeys--;
- if (loop < klist->nkeys)
- memcpy(&klist->keys[loop],
- &klist->keys[loop + 1],
- (klist->nkeys - loop) * sizeof(struct key *));
+ up_write(&keyring->sem);
- write_unlock(&keyring->lock);
+ /* schedule for later cleanup */
+ klist->delkey = loop;
+ call_rcu(&klist->rcu, keyring_unlink_rcu_disposal);
- up_write(&keyring->sem);
- key_put(key);
ret = 0;
- error:
+error:
return ret;
+nomem:
+ ret = -ENOMEM;
+ up_write(&keyring->sem);
+ goto error;
} /* end key_unlink() */
@@ -851,13 +940,32 @@ EXPORT_SYMBOL(key_unlink);
/*****************************************************************************/
/*
+ * dispose of a keyring list after the RCU grace period, releasing the keys it
+ * links to
+ */
+static void keyring_clear_rcu_disposal(struct rcu_head *rcu)
+{
+ struct keyring_list *klist;
+ int loop;
+
+ klist = container_of(rcu, struct keyring_list, rcu);
+
+ for (loop = klist->nkeys - 1; loop >= 0; loop--)
+ key_put(klist->keys[loop]);
+
+ kfree(klist);
+
+} /* end keyring_clear_rcu_disposal() */
+
+/*****************************************************************************/
+/*
* clear the specified process keyring
* - implements keyctl(KEYCTL_CLEAR)
*/
int keyring_clear(struct key *keyring)
{
struct keyring_list *klist;
- int loop, ret;
+ int ret;
ret = -ENOTDIR;
if (keyring->type == &key_type_keyring) {
@@ -870,20 +978,15 @@ int keyring_clear(struct key *keyring)
key_payload_reserve(keyring,
sizeof(struct keyring_list));
- write_lock(&keyring->lock);
- keyring->payload.subscriptions = NULL;
- write_unlock(&keyring->lock);
+ rcu_assign_pointer(keyring->payload.subscriptions,
+ NULL);
}
up_write(&keyring->sem);
/* free the keys after the locks have been dropped */
- if (klist) {
- for (loop = klist->nkeys - 1; loop >= 0; loop--)
- key_put(klist->keys[loop]);
-
- kfree(klist);
- }
+ if (klist)
+ call_rcu(&klist->rcu, keyring_clear_rcu_disposal);
ret = 0;
}
diff --git a/security/keys/proc.c b/security/keys/proc.c
index 91343b85c39c..c55cf1fd0826 100644
--- a/security/keys/proc.c
+++ b/security/keys/proc.c
@@ -140,7 +140,7 @@ static int proc_keys_show(struct seq_file *m, void *v)
now = current_kernel_time();
- read_lock(&key->lock);
+ rcu_read_lock();
/* come up with a suitable timeout value */
if (key->expiry == 0) {
@@ -164,14 +164,17 @@ static int proc_keys_show(struct seq_file *m, void *v)
sprintf(xbuf, "%luw", timo / (60*60*24*7));
}
+#define showflag(KEY, LETTER, FLAG) \
+ (test_bit(FLAG, &(KEY)->flags) ? LETTER : '-')
+
seq_printf(m, "%08x %c%c%c%c%c%c %5d %4s %06x %5d %5d %-9.9s ",
key->serial,
- key->flags & KEY_FLAG_INSTANTIATED ? 'I' : '-',
- key->flags & KEY_FLAG_REVOKED ? 'R' : '-',
- key->flags & KEY_FLAG_DEAD ? 'D' : '-',
- key->flags & KEY_FLAG_IN_QUOTA ? 'Q' : '-',
- key->flags & KEY_FLAG_USER_CONSTRUCT ? 'U' : '-',
- key->flags & KEY_FLAG_NEGATIVE ? 'N' : '-',
+ showflag(key, 'I', KEY_FLAG_INSTANTIATED),
+ showflag(key, 'R', KEY_FLAG_REVOKED),
+ showflag(key, 'D', KEY_FLAG_DEAD),
+ showflag(key, 'Q', KEY_FLAG_IN_QUOTA),
+ showflag(key, 'U', KEY_FLAG_USER_CONSTRUCT),
+ showflag(key, 'N', KEY_FLAG_NEGATIVE),
atomic_read(&key->usage),
xbuf,
key->perm,
@@ -179,11 +182,13 @@ static int proc_keys_show(struct seq_file *m, void *v)
key->gid,
key->type->name);
+#undef showflag
+
if (key->type->describe)
key->type->describe(key, m);
seq_putc(m, '\n');
- read_unlock(&key->lock);
+ rcu_read_unlock();
return 0;
diff --git a/security/keys/process_keys.c b/security/keys/process_keys.c
index 2eb0e471cd40..9b0369c5a223 100644
--- a/security/keys/process_keys.c
+++ b/security/keys/process_keys.c
@@ -1,6 +1,6 @@
/* process_keys.c: management of a process's keyrings
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -38,10 +38,9 @@ struct key root_user_keyring = {
.serial = 2,
.type = &key_type_keyring,
.user = &root_key_user,
- .lock = RW_LOCK_UNLOCKED,
.sem = __RWSEM_INITIALIZER(root_user_keyring.sem),
.perm = KEY_USR_ALL,
- .flags = KEY_FLAG_INSTANTIATED,
+ .flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid.0",
#ifdef KEY_DEBUGGING
.magic = KEY_DEBUG_MAGIC,
@@ -54,10 +53,9 @@ struct key root_session_keyring = {
.serial = 1,
.type = &key_type_keyring,
.user = &root_key_user,
- .lock = RW_LOCK_UNLOCKED,
.sem = __RWSEM_INITIALIZER(root_session_keyring.sem),
.perm = KEY_USR_ALL,
- .flags = KEY_FLAG_INSTANTIATED,
+ .flags = 1 << KEY_FLAG_INSTANTIATED,
.description = "_uid_ses.0",
#ifdef KEY_DEBUGGING
.magic = KEY_DEBUG_MAGIC,
@@ -167,7 +165,7 @@ int install_thread_keyring(struct task_struct *tsk)
/*
* make sure a process keyring is installed
*/
-static int install_process_keyring(struct task_struct *tsk)
+int install_process_keyring(struct task_struct *tsk)
{
unsigned long flags;
struct key *keyring;
@@ -183,7 +181,7 @@ static int install_process_keyring(struct task_struct *tsk)
goto error;
}
- /* attach or swap keyrings */
+ /* attach keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags);
if (!tsk->signal->process_keyring) {
tsk->signal->process_keyring = keyring;
@@ -229,12 +227,14 @@ static int install_session_keyring(struct task_struct *tsk,
/* install the keyring */
spin_lock_irqsave(&tsk->sighand->siglock, flags);
- old = tsk->signal->session_keyring;
- tsk->signal->session_keyring = keyring;
+ old = rcu_dereference(tsk->signal->session_keyring);
+ rcu_assign_pointer(tsk->signal->session_keyring, keyring);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
ret = 0;
+ /* we're using RCU on the pointer */
+ synchronize_rcu();
key_put(old);
error:
return ret;
@@ -247,8 +247,6 @@ static int install_session_keyring(struct task_struct *tsk,
*/
int copy_thread_group_keys(struct task_struct *tsk)
{
- unsigned long flags;
-
key_check(current->thread_group->session_keyring);
key_check(current->thread_group->process_keyring);
@@ -256,10 +254,10 @@ int copy_thread_group_keys(struct task_struct *tsk)
tsk->signal->process_keyring = NULL;
/* same session keyring */
- spin_lock_irqsave(&current->sighand->siglock, flags);
+ rcu_read_lock();
tsk->signal->session_keyring =
- key_get(current->signal->session_keyring);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ key_get(rcu_dereference(current->signal->session_keyring));
+ rcu_read_unlock();
return 0;
@@ -349,9 +347,7 @@ void key_fsuid_changed(struct task_struct *tsk)
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
- write_lock(&tsk->thread_keyring->lock);
tsk->thread_keyring->uid = tsk->fsuid;
- write_unlock(&tsk->thread_keyring->lock);
up_write(&tsk->thread_keyring->sem);
}
@@ -366,9 +362,7 @@ void key_fsgid_changed(struct task_struct *tsk)
/* update the ownership of the thread keyring */
if (tsk->thread_keyring) {
down_write(&tsk->thread_keyring->sem);
- write_lock(&tsk->thread_keyring->lock);
tsk->thread_keyring->gid = tsk->fsgid;
- write_unlock(&tsk->thread_keyring->lock);
up_write(&tsk->thread_keyring->sem);
}
@@ -382,13 +376,13 @@ void key_fsgid_changed(struct task_struct *tsk)
* - we return -EAGAIN if we didn't find any matching key
* - we return -ENOKEY if we found only negative matching keys
*/
-struct key *search_process_keyrings_aux(struct key_type *type,
- const void *description,
- key_match_func_t match)
+struct key *search_process_keyrings(struct key_type *type,
+ const void *description,
+ key_match_func_t match,
+ struct task_struct *context)
{
- struct task_struct *tsk = current;
- unsigned long flags;
- struct key *key, *ret, *err, *tmp;
+ struct request_key_auth *rka;
+ struct key *key, *ret, *err, *instkey;
/* we want to return -EAGAIN or -ENOKEY if any of the keyrings were
* searchable, but we failed to find a key or we found a negative key;
@@ -402,9 +396,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
err = ERR_PTR(-EAGAIN);
/* search the thread keyring first */
- if (tsk->thread_keyring) {
- key = keyring_search_aux(tsk->thread_keyring, type,
- description, match);
+ if (context->thread_keyring) {
+ key = keyring_search_aux(context->thread_keyring,
+ context, type, description, match);
if (!IS_ERR(key))
goto found;
@@ -422,9 +416,9 @@ struct key *search_process_keyrings_aux(struct key_type *type,
}
/* search the process keyring second */
- if (tsk->signal->process_keyring) {
- key = keyring_search_aux(tsk->signal->process_keyring,
- type, description, match);
+ if (context->signal->process_keyring) {
+ key = keyring_search_aux(context->signal->process_keyring,
+ context, type, description, match);
if (!IS_ERR(key))
goto found;
@@ -441,52 +435,93 @@ struct key *search_process_keyrings_aux(struct key_type *type,
}
}
- /* search the session keyring last */
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
+ /* search the session keyring */
+ if (context->signal->session_keyring) {
+ rcu_read_lock();
+ key = keyring_search_aux(
+ rcu_dereference(context->signal->session_keyring),
+ context, type, description, match);
+ rcu_read_unlock();
- tmp = tsk->signal->session_keyring;
- if (!tmp)
- tmp = tsk->user->session_keyring;
- atomic_inc(&tmp->usage);
+ if (!IS_ERR(key))
+ goto found;
- spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
+ break;
+ default:
+ err = key;
+ break;
+ }
+
+ /* if this process has a session keyring and that has an
+ * instantiation authorisation key in the bottom level, then we
+ * also search the keyrings of the process mentioned there */
+ if (context != current)
+ goto no_key;
+
+ rcu_read_lock();
+ instkey = __keyring_search_one(
+ rcu_dereference(context->signal->session_keyring),
+ &key_type_request_key_auth, NULL, 0);
+ rcu_read_unlock();
+
+ if (IS_ERR(instkey))
+ goto no_key;
+
+ rka = instkey->payload.data;
- key = keyring_search_aux(tmp, type, description, match);
- key_put(tmp);
- if (!IS_ERR(key))
- goto found;
+ key = search_process_keyrings(type, description, match,
+ rka->context);
+ key_put(instkey);
- switch (PTR_ERR(key)) {
- case -EAGAIN: /* no key */
- if (ret)
+ if (!IS_ERR(key))
+ goto found;
+
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
break;
- case -ENOKEY: /* negative key */
- ret = key;
- break;
- default:
- err = key;
- break;
+ default:
+ err = key;
+ break;
+ }
+ }
+ /* or search the user-session keyring */
+ else {
+ key = keyring_search_aux(context->user->session_keyring,
+ context, type, description, match);
+ if (!IS_ERR(key))
+ goto found;
+
+ switch (PTR_ERR(key)) {
+ case -EAGAIN: /* no key */
+ if (ret)
+ break;
+ case -ENOKEY: /* negative key */
+ ret = key;
+ break;
+ default:
+ err = key;
+ break;
+ }
}
+
+no_key:
/* no key - decide on the error we're going to go for */
key = ret ? ret : err;
- found:
+found:
return key;
-} /* end search_process_keyrings_aux() */
-
-/*****************************************************************************/
-/*
- * search the process keyrings for the first matching key
- * - we return -EAGAIN if we didn't find any matching key
- * - we return -ENOKEY if we found only negative matching keys
- */
-struct key *search_process_keyrings(struct key_type *type,
- const char *description)
-{
- return search_process_keyrings_aux(type, description, type->match);
-
} /* end search_process_keyrings() */
/*****************************************************************************/
@@ -495,72 +530,73 @@ struct key *search_process_keyrings(struct key_type *type,
* - don't create special keyrings unless so requested
* - partially constructed keys aren't found unless requested
*/
-struct key *lookup_user_key(key_serial_t id, int create, int partial,
- key_perm_t perm)
+struct key *lookup_user_key(struct task_struct *context, key_serial_t id,
+ int create, int partial, key_perm_t perm)
{
- struct task_struct *tsk = current;
- unsigned long flags;
struct key *key;
int ret;
+ if (!context)
+ context = current;
+
key = ERR_PTR(-ENOKEY);
switch (id) {
case KEY_SPEC_THREAD_KEYRING:
- if (!tsk->thread_keyring) {
+ if (!context->thread_keyring) {
if (!create)
goto error;
- ret = install_thread_keyring(tsk);
+ ret = install_thread_keyring(context);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
- key = tsk->thread_keyring;
+ key = context->thread_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_PROCESS_KEYRING:
- if (!tsk->signal->process_keyring) {
+ if (!context->signal->process_keyring) {
if (!create)
goto error;
- ret = install_process_keyring(tsk);
+ ret = install_process_keyring(context);
if (ret < 0) {
key = ERR_PTR(ret);
goto error;
}
}
- key = tsk->signal->process_keyring;
+ key = context->signal->process_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_SESSION_KEYRING:
- if (!tsk->signal->session_keyring) {
+ if (!context->signal->session_keyring) {
/* always install a session keyring upon access if one
* doesn't exist yet */
ret = install_session_keyring(
- tsk, tsk->user->session_keyring);
+ context, context->user->session_keyring);
if (ret < 0)
goto error;
}
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
- key = tsk->signal->session_keyring;
+ rcu_read_lock();
+ key = rcu_dereference(context->signal->session_keyring);
atomic_inc(&key->usage);
- spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ rcu_read_unlock();
break;
case KEY_SPEC_USER_KEYRING:
- key = tsk->user->uid_keyring;
+ key = context->user->uid_keyring;
atomic_inc(&key->usage);
break;
case KEY_SPEC_USER_SESSION_KEYRING:
- key = tsk->user->session_keyring;
+ key = context->user->session_keyring;
atomic_inc(&key->usage);
break;
@@ -580,7 +616,7 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
break;
}
- /* check the status and permissions */
+ /* check the status */
if (perm) {
ret = key_validate(key);
if (ret < 0)
@@ -588,11 +624,13 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
}
ret = -EIO;
- if (!partial && !(key->flags & KEY_FLAG_INSTANTIATED))
+ if (!partial && !test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
goto invalid_key;
+ /* check the permissions */
ret = -EACCES;
- if (!key_permission(key, perm))
+
+ if (!key_task_permission(key, context, perm))
goto invalid_key;
error:
@@ -615,7 +653,6 @@ struct key *lookup_user_key(key_serial_t id, int create, int partial,
long join_session_keyring(const char *name)
{
struct task_struct *tsk = current;
- unsigned long flags;
struct key *keyring;
long ret;
@@ -625,9 +662,9 @@ long join_session_keyring(const char *name)
if (ret < 0)
goto error;
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
- ret = tsk->signal->session_keyring->serial;
- spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
+ rcu_read_lock();
+ ret = rcu_dereference(tsk->signal->session_keyring)->serial;
+ rcu_read_unlock();
goto error;
}
diff --git a/security/keys/request_key.c b/security/keys/request_key.c
index 9705b1aeba5d..dfcd983af1fd 100644
--- a/security/keys/request_key.c
+++ b/security/keys/request_key.c
@@ -1,6 +1,6 @@
/* request_key.c: request a key from userspace
*
- * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
+ * Copyright (C) 2004-5 Red Hat, Inc. All Rights Reserved.
* Written by David Howells (dhowells@redhat.com)
*
* This program is free software; you can redistribute it and/or
@@ -13,6 +13,7 @@
#include <linux/sched.h>
#include <linux/kmod.h>
#include <linux/err.h>
+#include <linux/keyctl.h>
#include "internal.h"
struct key_construction {
@@ -27,18 +28,26 @@ DECLARE_WAIT_QUEUE_HEAD(request_key_conswq);
/*
* request userspace finish the construction of a key
* - execute "/sbin/request-key <op> <key> <uid> <gid> <keyring> <keyring> <keyring> <info>"
- * - if callout_info is an empty string, it'll be rendered as a "-" instead
*/
static int call_request_key(struct key *key,
const char *op,
const char *callout_info)
{
struct task_struct *tsk = current;
- unsigned long flags;
key_serial_t prkey, sskey;
+ struct key *session_keyring, *rkakey;
char *argv[10], *envp[3], uid_str[12], gid_str[12];
char key_str[12], keyring_str[3][12];
- int i;
+ int ret, i;
+
+ kenter("{%d},%s,%s", key->serial, op, callout_info);
+
+ /* generate a new session keyring with an auth key in it */
+ session_keyring = request_key_auth_new(key, &rkakey);
+ if (IS_ERR(session_keyring)) {
+ ret = PTR_ERR(session_keyring);
+ goto error;
+ }
/* record the UID and GID */
sprintf(uid_str, "%d", current->fsuid);
@@ -55,17 +64,17 @@ static int call_request_key(struct key *key,
if (tsk->signal->process_keyring)
prkey = tsk->signal->process_keyring->serial;
- sskey = 0;
- spin_lock_irqsave(&tsk->sighand->siglock, flags);
- if (tsk->signal->session_keyring)
- sskey = tsk->signal->session_keyring->serial;
- spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
-
+ sprintf(keyring_str[1], "%d", prkey);
- if (!sskey)
+ if (tsk->signal->session_keyring) {
+ rcu_read_lock();
+ sskey = rcu_dereference(tsk->signal->session_keyring)->serial;
+ rcu_read_unlock();
+ }
+ else {
sskey = tsk->user->session_keyring->serial;
+ }
- sprintf(keyring_str[1], "%d", prkey);
sprintf(keyring_str[2], "%d", sskey);
/* set up a minimal environment */
@@ -84,11 +93,20 @@ static int call_request_key(struct key *key,
argv[i++] = keyring_str[0];
argv[i++] = keyring_str[1];
argv[i++] = keyring_str[2];
- argv[i++] = callout_info[0] ? (char *) callout_info : "-";
+ argv[i++] = (char *) callout_info;
argv[i] = NULL;
/* do it */
- return call_usermodehelper(argv[0], argv, envp, 1);
+ ret = call_usermodehelper_keys(argv[0], argv, envp, session_keyring, 1);
+
+ /* dispose of the special keys */
+ key_revoke(rkakey);
+ key_put(rkakey);
+ key_put(session_keyring);
+
+ error:
+ kleave(" = %d", ret);
+ return ret;
} /* end call_request_key() */
@@ -105,7 +123,9 @@ static struct key *__request_key_construction(struct key_type *type,
struct key_construction cons;
struct timespec now;
struct key *key;
- int ret, negative;
+ int ret, negated;
+
+ kenter("%s,%s,%s", type->name, description, callout_info);
/* create a key and add it to the queue */
key = key_alloc(type, description,
@@ -113,9 +133,7 @@ static struct key *__request_key_construction(struct key_type *type,
if (IS_ERR(key))
goto alloc_failed;
- write_lock(&key->lock);
- key->flags |= KEY_FLAG_USER_CONSTRUCT;
- write_unlock(&key->lock);
+ set_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
cons.key = key;
list_add_tail(&cons.link, &key->user->consq);
@@ -130,7 +148,7 @@ static struct key *__request_key_construction(struct key_type *type,
/* if the key wasn't instantiated, then we want to give an error */
ret = -ENOKEY;
- if (!(key->flags & KEY_FLAG_INSTANTIATED))
+ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
goto request_failed;
down_write(&key_construction_sem);
@@ -139,12 +157,13 @@ static struct key *__request_key_construction(struct key_type *type,
/* also give an error if the key was negatively instantiated */
check_not_negative:
- if (key->flags & KEY_FLAG_NEGATIVE) {
+ if (test_bit(KEY_FLAG_NEGATIVE, &key->flags)) {
key_put(key);
key = ERR_PTR(-ENOKEY);
}
out:
+ kleave(" = %p", key);
return key;
request_failed:
@@ -152,24 +171,23 @@ static struct key *__request_key_construction(struct key_type *type,
* - remove from construction queue
* - mark the key as dead
*/
- negative = 0;
+ negated = 0;
down_write(&key_construction_sem);
list_del(&cons.link);
- write_lock(&key->lock);
- key->flags &= ~KEY_FLAG_USER_CONSTRUCT;
-
/* check it didn't get instantiated between the check and the down */
- if (!(key->flags & KEY_FLAG_INSTANTIATED)) {
- key->flags |= KEY_FLAG_INSTANTIATED | KEY_FLAG_NEGATIVE;
- negative = 1;
+ if (!test_bit(KEY_FLAG_INSTANTIATED, &key->flags)) {
+ set_bit(KEY_FLAG_NEGATIVE, &key->flags);
+ set_bit(KEY_FLAG_INSTANTIATED, &key->flags);
+ negated = 1;
}
- write_unlock(&key->lock);
+ clear_bit(KEY_FLAG_USER_CONSTRUCT, &key->flags);
+
up_write(&key_construction_sem);
- if (!negative)
+ if (!negated)
goto check_not_negative; /* surprisingly, the key got
* instantiated */
@@ -178,13 +196,12 @@ static struct key *__request_key_construction(struct key_type *type,
key->expiry = now.tv_sec + key_negative_timeout;
if (current->signal->session_keyring) {
- unsigned long flags;
struct key *keyring;
- spin_lock_irqsave(&current->sighand->siglock, flags);
- keyring = current->signal->session_keyring;
+ rcu_read_lock();
+ keyring = rcu_dereference(current->signal->session_keyring);
atomic_inc(&keyring->usage);
- spin_unlock_irqrestore(&current->sighand->siglock, flags);
+ rcu_read_unlock();
key_link(keyring, key);
key_put(keyring);
@@ -220,6 +237,9 @@ static struct key *request_key_construction(struct key_type *type,
DECLARE_WAITQUEUE(myself, current);
+ kenter("%s,%s,{%d},%s",
+ type->name, description, user->uid, callout_info);
+
/* see if there's such a key under construction already */
down_write(&key_construction_sem);
@@ -236,6 +256,7 @@ static struct key *request_key_construction(struct key_type *type,
/* see about getting userspace to construct the key */
key = __request_key_construction(type, description, callout_info);
error:
+ kleave(" = %p", key);
return key;
/* someone else has the same key under construction
@@ -249,8 +270,10 @@ static struct key *request_key_construction(struct key_type *type,
add_wait_queue(&request_key_conswq, &myself);
for (;;) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (!(ckey->flags & KEY_FLAG_USER_CONSTRUCT))
+ set_current_state(TASK_INTERRUPTIBLE);
+ if (!test_bit(KEY_FLAG_USER_CONSTRUCT, &ckey->flags))
+ break;
+ if (signal_pending(current))
break;
schedule();
}
@@ -271,21 +294,83 @@ static struct key *request_key_construction(struct key_type *type,
/*****************************************************************************/
/*
+ * link a freshly minted key to an appropriate destination keyring
+ */
+static void request_key_link(struct key *key, struct key *dest_keyring)
+{
+ struct task_struct *tsk = current;
+ struct key *drop = NULL;
+
+ kenter("{%d},%p", key->serial, dest_keyring);
+
+ /* find the appropriate keyring */
+ if (!dest_keyring) {
+ switch (tsk->jit_keyring) {
+ case KEY_REQKEY_DEFL_DEFAULT:
+ case KEY_REQKEY_DEFL_THREAD_KEYRING:
+ dest_keyring = tsk->thread_keyring;
+ if (dest_keyring)
+ break;
+
+ case KEY_REQKEY_DEFL_PROCESS_KEYRING:
+ dest_keyring = tsk->signal->process_keyring;
+ if (dest_keyring)
+ break;
+
+ case KEY_REQKEY_DEFL_SESSION_KEYRING:
+ rcu_read_lock();
+ dest_keyring = key_get(
+ rcu_dereference(tsk->signal->session_keyring));
+ rcu_read_unlock();
+ drop = dest_keyring;
+
+ if (dest_keyring)
+ break;
+
+ case KEY_REQKEY_DEFL_USER_SESSION_KEYRING:
+ dest_keyring = current->user->session_keyring;
+ break;
+
+ case KEY_REQKEY_DEFL_USER_KEYRING:
+ dest_keyring = current->user->uid_keyring;
+ break;
+
+ case KEY_REQKEY_DEFL_GROUP_KEYRING:
+ default:
+ BUG();
+ }
+ }
+
+ /* and attach the key to it */
+ key_link(dest_keyring, key);
+
+ key_put(drop);
+
+ kleave("");
+
+} /* end request_key_link() */
+
+/*****************************************************************************/
+/*
* request a key
* - search the process's keyrings
* - check the list of keys being created or updated
- * - call out to userspace for a key if requested (supplementary info can be
- * passed)
+ * - call out to userspace for a key if supplementary info was provided
+ * - cache the key in an appropriate keyring
*/
-struct key *request_key(struct key_type *type,
- const char *description,
- const char *callout_info)
+struct key *request_key_and_link(struct key_type *type,
+ const char *description,
+ const char *callout_info,
+ struct key *dest_keyring)
{
struct key_user *user;
struct key *key;
+ kenter("%s,%s,%s,%p",
+ type->name, description, callout_info, dest_keyring);
+
/* search all the process keyrings for a key */
- key = search_process_keyrings_aux(type, description, type->match);
+ key = search_process_keyrings(type, description, type->match, current);
if (PTR_ERR(key) == -EAGAIN) {
/* the search failed, but the keyrings were searchable, so we
@@ -296,12 +381,13 @@ struct key *request_key(struct key_type *type,
/* - get hold of the user's construction queue */
user = key_user_lookup(current->fsuid);
- if (!user) {
- key = ERR_PTR(-ENOMEM);
- goto error;
- }
+ if (!user)
+ goto nomem;
+
+ do {
+ if (signal_pending(current))
+ goto interrupted;
- for (;;) {
/* ask userspace (returns NULL if it waited on a key
* being constructed) */
key = request_key_construction(type, description,
@@ -311,18 +397,46 @@ struct key *request_key(struct key_type *type,
/* someone else made the key we want, so we need to
* search again as it might now be available to us */
- key = search_process_keyrings_aux(type, description,
- type->match);
- if (PTR_ERR(key) != -EAGAIN)
- break;
- }
+ key = search_process_keyrings(type, description,
+ type->match, current);
+
+ } while (PTR_ERR(key) == -EAGAIN);
key_user_put(user);
+
+ /* link the new key into the appropriate keyring */
+ if (!PTR_ERR(key))
+ request_key_link(key, dest_keyring);
}
- error:
+error:
+ kleave(" = %p", key);
return key;
+nomem:
+ key = ERR_PTR(-ENOMEM);
+ goto error;
+
+interrupted:
+ key_user_put(user);
+ key = ERR_PTR(-EINTR);
+ goto error;
+
+} /* end request_key_and_link() */
+
+/*****************************************************************************/
+/*
+ * request a key
+ * - search the process's keyrings
+ * - check the list of keys being created or updated
+ * - call out to userspace for a key if supplementary info was provided
+ */
+struct key *request_key(struct key_type *type,
+ const char *description,
+ const char *callout_info)
+{
+ return request_key_and_link(type, description, callout_info, NULL);
+
} /* end request_key() */
EXPORT_SYMBOL(request_key);
@@ -339,7 +453,8 @@ int key_validate(struct key *key)
if (key) {
/* check it's still accessible */
ret = -EKEYREVOKED;
- if (key->flags & (KEY_FLAG_REVOKED | KEY_FLAG_DEAD))
+ if (test_bit(KEY_FLAG_REVOKED, &key->flags) ||
+ test_bit(KEY_FLAG_DEAD, &key->flags))
goto error;
/* check it hasn't expired */
diff --git a/security/keys/request_key_auth.c b/security/keys/request_key_auth.c
new file mode 100644
index 000000000000..f22264632229
--- /dev/null
+++ b/security/keys/request_key_auth.c
@@ -0,0 +1,180 @@
+/* request_key_auth.c: request key authorisation controlling key def
+ *
+ * Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.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.
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/seq_file.h>
+#include "internal.h"
+
+static int request_key_auth_instantiate(struct key *, const void *, size_t);
+static void request_key_auth_describe(const struct key *, struct seq_file *);
+static void request_key_auth_destroy(struct key *);
+
+/*
+ * the request-key authorisation key type definition
+ */
+struct key_type key_type_request_key_auth = {
+ .name = ".request_key_auth",
+ .def_datalen = sizeof(struct request_key_auth),
+ .instantiate = request_key_auth_instantiate,
+ .describe = request_key_auth_describe,
+ .destroy = request_key_auth_destroy,
+};
+
+/*****************************************************************************/
+/*
+ * instantiate a request-key authorisation record
+ */
+static int request_key_auth_instantiate(struct key *key,
+ const void *data,
+ size_t datalen)
+{
+ struct request_key_auth *rka, *irka;
+ struct key *instkey;
+ int ret;
+
+ ret = -ENOMEM;
+ rka = kmalloc(sizeof(*rka), GFP_KERNEL);
+ if (rka) {
+ /* see if the calling process is already servicing the key
+ * request of another process */
+ instkey = key_get_instantiation_authkey(0);
+ if (!IS_ERR(instkey)) {
+ /* it is - use that instantiation context here too */
+ irka = instkey->payload.data;
+ rka->context = irka->context;
+ rka->pid = irka->pid;
+ key_put(instkey);
+ }
+ else {
+ /* it isn't - use this process as the context */
+ rka->context = current;
+ rka->pid = current->pid;
+ }
+
+ rka->target_key = key_get((struct key *) data);
+ key->payload.data = rka;
+ ret = 0;
+ }
+
+ return ret;
+
+} /* end request_key_auth_instantiate() */
+
+/*****************************************************************************/
+/*
+ *
+ */
+static void request_key_auth_describe(const struct key *key,
+ struct seq_file *m)
+{
+ struct request_key_auth *rka = key->payload.data;
+
+ seq_puts(m, "key:");
+ seq_puts(m, key->description);
+ seq_printf(m, " pid:%d", rka->pid);
+
+} /* end request_key_auth_describe() */
+
+/*****************************************************************************/
+/*
+ * destroy an instantiation authorisation token key
+ */
+static void request_key_auth_destroy(struct key *key)
+{
+ struct request_key_auth *rka = key->payload.data;
+
+ kenter("{%d}", key->serial);
+
+ key_put(rka->target_key);
+
+} /* end request_key_auth_destroy() */
+
+/*****************************************************************************/
+/*
+ * create a session keyring to be for the invokation of /sbin/request-key and
+ * stick an authorisation token in it
+ */
+struct key *request_key_auth_new(struct key *target, struct key **_rkakey)
+{
+ struct key *keyring, *rkakey = NULL;
+ char desc[20];
+ int ret;
+
+ kenter("%d,", target->serial);
+
+ /* allocate a new session keyring */
+ sprintf(desc, "_req.%u", target->serial);
+
+ keyring = keyring_alloc(desc, current->fsuid, current->fsgid, 1, NULL);
+ if (IS_ERR(keyring)) {
+ kleave("= %ld", PTR_ERR(keyring));
+ return keyring;
+ }
+
+ /* allocate the auth key */
+ sprintf(desc, "%x", target->serial);
+
+ rkakey = key_alloc(&key_type_request_key_auth, desc,
+ current->fsuid, current->fsgid,
+ KEY_USR_VIEW, 1);
+ if (IS_ERR(rkakey)) {
+ key_put(keyring);
+ kleave("= %ld", PTR_ERR(rkakey));
+ return rkakey;
+ }
+
+ /* construct and attach to the keyring */
+ ret = key_instantiate_and_link(rkakey, target, 0, keyring, NULL);
+ if (ret < 0) {
+ key_revoke(rkakey);
+ key_put(rkakey);
+ key_put(keyring);
+ kleave("= %d", ret);
+ return ERR_PTR(ret);
+ }
+
+ *_rkakey = rkakey;
+ kleave(" = {%d} ({%d})", keyring->serial, rkakey->serial);
+ return keyring;
+
+} /* end request_key_auth_new() */
+
+/*****************************************************************************/
+/*
+ * get the authorisation key for instantiation of a specific key if attached to
+ * the current process's keyrings
+ * - this key is inserted into a keyring and that is set as /sbin/request-key's
+ * session keyring
+ * - a target_id of zero specifies any valid token
+ */
+struct key *key_get_instantiation_authkey(key_serial_t target_id)
+{
+ struct task_struct *tsk = current;
+ struct key *instkey;
+
+ /* we must have our own personal session keyring */
+ if (!tsk->signal->session_keyring)
+ return ERR_PTR(-EACCES);
+
+ /* and it must contain a suitable request authorisation key
+ * - lock RCU against session keyring changing
+ */
+ rcu_read_lock();
+
+ instkey = keyring_search_instkey(
+ rcu_dereference(tsk->signal->session_keyring), target_id);
+
+ rcu_read_unlock();
+ return instkey;
+
+} /* end key_get_instantiation_authkey() */
diff --git a/security/keys/user_defined.c b/security/keys/user_defined.c
index 8d65b3a28129..e446acba73d3 100644
--- a/security/keys/user_defined.c
+++ b/security/keys/user_defined.c
@@ -42,12 +42,21 @@ struct key_type key_type_user = {
.read = user_read,
};
+struct user_key_payload {
+ struct rcu_head rcu; /* RCU destructor */
+ unsigned short datalen; /* length of this data */
+ char data[0]; /* actual data */
+};
+
+EXPORT_SYMBOL_GPL(key_type_user);
+
/*****************************************************************************/
/*
* instantiate a user defined key
*/
static int user_instantiate(struct key *key, const void *data, size_t datalen)
{
+ struct user_key_payload *upayload;
int ret;
ret = -EINVAL;
@@ -58,13 +67,15 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen)
if (ret < 0)
goto error;
- /* attach the data */
ret = -ENOMEM;
- key->payload.data = kmalloc(datalen, GFP_KERNEL);
- if (!key->payload.data)
+ upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
+ if (!upayload)
goto error;
- memcpy(key->payload.data, data, datalen);
+ /* attach the data */
+ upayload->datalen = datalen;
+ memcpy(upayload->data, data, datalen);
+ rcu_assign_pointer(key->payload.data, upayload);
ret = 0;
error:
@@ -75,18 +86,25 @@ static int user_instantiate(struct key *key, const void *data, size_t datalen)
/*****************************************************************************/
/*
* duplicate a user defined key
+ * - both keys' semaphores are locked against further modification
+ * - the new key cannot yet be accessed
*/
static int user_duplicate(struct key *key, const struct key *source)
{
+ struct user_key_payload *upayload, *spayload;
int ret;
/* just copy the payload */
ret = -ENOMEM;
- key->payload.data = kmalloc(source->datalen, GFP_KERNEL);
+ upayload = kmalloc(sizeof(*upayload) + source->datalen, GFP_KERNEL);
+ if (upayload) {
+ spayload = rcu_dereference(source->payload.data);
+ BUG_ON(source->datalen != spayload->datalen);
+
+ upayload->datalen = key->datalen = spayload->datalen;
+ memcpy(upayload->data, spayload->data, key->datalen);
- if (key->payload.data) {
- key->datalen = source->datalen;
- memcpy(key->payload.data, source->payload.data, source->datalen);
+ key->payload.data = upayload;
ret = 0;
}
@@ -96,40 +114,54 @@ static int user_duplicate(struct key *key, const struct key *source)
/*****************************************************************************/
/*
+ * dispose of the old data from an updated user defined key
+ */
+static void user_update_rcu_disposal(struct rcu_head *rcu)
+{
+ struct user_key_payload *upayload;
+
+ upayload = container_of(rcu, struct user_key_payload, rcu);
+
+ kfree(upayload);
+
+} /* end user_update_rcu_disposal() */
+
+/*****************************************************************************/
+/*
* update a user defined key
+ * - the key's semaphore is write-locked
*/
static int user_update(struct key *key, const void *data, size_t datalen)
{
- void *new, *zap;
+ struct user_key_payload *upayload, *zap;
int ret;
ret = -EINVAL;
if (datalen <= 0 || datalen > 32767 || !data)
goto error;
- /* copy the data */
+ /* construct a replacement payload */
ret = -ENOMEM;
- new = kmalloc(datalen, GFP_KERNEL);
- if (!new)
+ upayload = kmalloc(sizeof(*upayload) + datalen, GFP_KERNEL);
+ if (!upayload)
goto error;
- memcpy(new, data, datalen);
+ upayload->datalen = datalen;
+ memcpy(upayload->data, data, datalen);
/* check the quota and attach the new data */
- zap = new;
- write_lock(&key->lock);
+ zap = upayload;
ret = key_payload_reserve(key, datalen);
if (ret == 0) {
/* attach the new data, displacing the old */
zap = key->payload.data;
- key->payload.data = new;
+ rcu_assign_pointer(key->payload.data, upayload);
key->expiry = 0;
}
- write_unlock(&key->lock);
- kfree(zap);
+ call_rcu(&zap->rcu, user_update_rcu_disposal);
error:
return ret;
@@ -152,13 +184,15 @@ static int user_match(const struct key *key, const void *description)
*/
static void user_destroy(struct key *key)
{
- kfree(key->payload.data);
+ struct user_key_payload *upayload = key->payload.data;
+
+ kfree(upayload);
} /* end user_destroy() */
/*****************************************************************************/
/*
- * describe the user
+ * describe the user key
*/
static void user_describe(const struct key *key, struct seq_file *m)
{
@@ -171,18 +205,23 @@ static void user_describe(const struct key *key, struct seq_file *m)
/*****************************************************************************/
/*
* read the key data
+ * - the key's semaphore is read-locked
*/
static long user_read(const struct key *key,
char __user *buffer, size_t buflen)
{
- long ret = key->datalen;
+ struct user_key_payload *upayload;
+ long ret;
+
+ upayload = rcu_dereference(key->payload.data);
+ ret = upayload->datalen;
/* we can return the data as is */
if (buffer && buflen > 0) {
- if (buflen > key->datalen)
- buflen = key->datalen;
+ if (buflen > upayload->datalen)
+ buflen = upayload->datalen;
- if (copy_to_user(buffer, key->payload.data, buflen) != 0)
+ if (copy_to_user(buffer, upayload->data, buflen) != 0)
ret = -EFAULT;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 87302a49067b..6be273851144 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -68,6 +68,7 @@
#include <linux/personality.h>
#include <linux/sysctl.h>
#include <linux/audit.h>
+#include <linux/string.h>
#include "avc.h"
#include "objsec.h"
@@ -1658,9 +1659,8 @@ static int selinux_bprm_secureexec (struct linux_binprm *bprm)
static void selinux_bprm_free_security(struct linux_binprm *bprm)
{
- struct bprm_security_struct *bsec = bprm->security;
+ kfree(bprm->security);
bprm->security = NULL;
- kfree(bsec);
}
extern struct vfsmount *selinuxfs_mount;
@@ -1944,7 +1944,7 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
}
} while (*in_end++);
- copy_page(in_save, nosec_save);
+ strcpy(in_save, nosec_save);
free_page((unsigned long)nosec_save);
out:
return rc;
@@ -2477,6 +2477,17 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
prot = reqprot;
#ifndef CONFIG_PPC32
+ if ((prot & PROT_EXEC) && !(vma->vm_flags & VM_EXECUTABLE) &&
+ (vma->vm_start >= vma->vm_mm->start_brk &&
+ vma->vm_end <= vma->vm_mm->brk)) {
+ /*
+ * We are making an executable mapping in the brk region.
+ * This has an additional execheap check.
+ */
+ rc = task_has_perm(current, current, PROCESS__EXECHEAP);
+ if (rc)
+ return rc;
+ }
if (vma->vm_file != NULL && vma->anon_vma != NULL && (prot & PROT_EXEC)) {
/*
* We are making executable a file mapping that has
@@ -2488,6 +2499,16 @@ static int selinux_file_mprotect(struct vm_area_struct *vma,
if (rc)
return rc;
}
+ if (!vma->vm_file && (prot & PROT_EXEC) &&
+ vma->vm_start <= vma->vm_mm->start_stack &&
+ vma->vm_end >= vma->vm_mm->start_stack) {
+ /* Attempt to make the process stack executable.
+ * This has an additional execstack check.
+ */
+ rc = task_has_perm(current, current, PROCESS__EXECSTACK);
+ if (rc)
+ return rc;
+ }
#endif
return file_map_prot_check(vma->vm_file, prot, vma->vm_flags&VM_SHARED);
diff --git a/security/selinux/include/av_perm_to_string.h b/security/selinux/include/av_perm_to_string.h
index 8928bb4d3c53..1deb59e1b762 100644
--- a/security/selinux/include/av_perm_to_string.h
+++ b/security/selinux/include/av_perm_to_string.h
@@ -70,6 +70,8 @@
S_(SECCLASS_PROCESS, PROCESS__DYNTRANSITION, "dyntransition")
S_(SECCLASS_PROCESS, PROCESS__SETCURRENT, "setcurrent")
S_(SECCLASS_PROCESS, PROCESS__EXECMEM, "execmem")
+ S_(SECCLASS_PROCESS, PROCESS__EXECSTACK, "execstack")
+ S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
S_(SECCLASS_MSG, MSG__SEND, "send")
S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index bdfce4ca8f8e..a78b5d59c9fc 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -465,6 +465,8 @@
#define PROCESS__DYNTRANSITION 0x00800000UL
#define PROCESS__SETCURRENT 0x01000000UL
#define PROCESS__EXECMEM 0x02000000UL
+#define PROCESS__EXECSTACK 0x04000000UL
+#define PROCESS__EXECHEAP 0x08000000UL
#define IPC__CREATE 0x00000001UL
#define IPC__DESTROY 0x00000002UL
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 07221568b505..8eb140dd2e4b 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -951,8 +951,7 @@ static int sel_make_bools(void)
u32 sid;
/* remove any existing files */
- if (bool_pending_values)
- kfree(bool_pending_values);
+ kfree(bool_pending_values);
sel_remove_bools(dir);
@@ -997,10 +996,8 @@ static int sel_make_bools(void)
out:
free_page((unsigned long)page);
if (names) {
- for (i = 0; i < num; i++) {
- if (names[i])
- kfree(names[i]);
- }
+ for (i = 0; i < num; i++)
+ kfree(names[i]);
kfree(names);
}
return ret;
diff --git a/security/selinux/ss/conditional.c b/security/selinux/ss/conditional.c
index b53441184aca..e2057f5a411a 100644
--- a/security/selinux/ss/conditional.c
+++ b/security/selinux/ss/conditional.c
@@ -166,16 +166,14 @@ static void cond_list_destroy(struct cond_node *list)
void cond_policydb_destroy(struct policydb *p)
{
- if (p->bool_val_to_struct != NULL)
- kfree(p->bool_val_to_struct);
+ kfree(p->bool_val_to_struct);
avtab_destroy(&p->te_cond_avtab);
cond_list_destroy(p->cond_list);
}
int cond_init_bool_indexes(struct policydb *p)
{
- if (p->bool_val_to_struct)
- kfree(p->bool_val_to_struct);
+ kfree(p->bool_val_to_struct);
p->bool_val_to_struct = (struct cond_bool_datum**)
kmalloc(p->p_bools.nprim * sizeof(struct cond_bool_datum*), GFP_KERNEL);
if (!p->bool_val_to_struct)
@@ -185,8 +183,7 @@ int cond_init_bool_indexes(struct policydb *p)
int cond_destroy_bool(void *key, void *datum, void *p)
{
- if (key)
- kfree(key);
+ kfree(key);
kfree(datum);
return 0;
}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 14190efbf333..785c33cf4864 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -590,17 +590,12 @@ void policydb_destroy(struct policydb *p)
hashtab_destroy(p->symtab[i].table);
}
- for (i = 0; i < SYM_NUM; i++) {
- if (p->sym_val_to_name[i])
- kfree(p->sym_val_to_name[i]);
- }
+ for (i = 0; i < SYM_NUM; i++)
+ kfree(p->sym_val_to_name[i]);
- if (p->class_val_to_struct)
- kfree(p->class_val_to_struct);
- if (p->role_val_to_struct)
- kfree(p->role_val_to_struct);
- if (p->user_val_to_struct)
- kfree(p->user_val_to_struct);
+ kfree(p->class_val_to_struct);
+ kfree(p->role_val_to_struct);
+ kfree(p->user_val_to_struct);
avtab_destroy(&p->te_avtab);
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index b6149147d5cb..922bb45054aa 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1705,11 +1705,9 @@ out:
err:
if (*names) {
for (i = 0; i < *len; i++)
- if ((*names)[i])
- kfree((*names)[i]);
+ kfree((*names)[i]);
}
- if (*values)
- kfree(*values);
+ kfree(*values);
goto out;
}
diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig
index e537bd66a707..7bd95ceab7cc 100644
--- a/sound/oss/Kconfig
+++ b/sound/oss/Kconfig
@@ -6,7 +6,7 @@
# Prompt user for primary drivers.
config SOUND_BT878
tristate "BT878 audio dma"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
---help---
Audio DMA support for bt878 based grabber boards. As you might have
already noticed, bt878 is listed with two functions in /proc/pci.
@@ -22,7 +22,7 @@ config SOUND_BT878
config SOUND_CMPCI
tristate "C-Media PCI (CMI8338/8738)"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a PCI sound card using the CMI8338
or the CMI8738 chipset. Data on these chips are available at
@@ -52,7 +52,7 @@ config SOUND_CMPCI_MIDI
config SOUND_CMPCI_JOYSTICK
bool "Enable joystick"
- depends on SOUND_CMPCI && X86
+ depends on SOUND_CMPCI && X86 && (GAMEPORT=y || SOUND_CMPCI=GAMEPORT)
help
Say Y here in order to enable the joystick port on a sound card using
the CMI8338 or the CMI8738 chipset. You need to config the
@@ -61,7 +61,7 @@ config SOUND_CMPCI_JOYSTICK
config SOUND_EMU10K1
tristate "Creative SBLive! (EMU10K1)"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
---help---
Say Y or M if you have a PCI sound card using the EMU10K1 chipset,
such as the Creative SBLive!, SB PCI512 or Emu-APS.
@@ -87,7 +87,7 @@ config MIDI_EMU10K1
config SOUND_FUSION
tristate "Crystal SoundFusion (CS4280/461x)"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
help
This module drives the Crystal SoundFusion devices (CS4280/46xx
series) when wired as native sound drivers with AC97 codecs. If
@@ -95,14 +95,14 @@ config SOUND_FUSION
config SOUND_CS4281
tristate "Crystal Sound CS4281"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
help
Picture and feature list at
<http://www.pcbroker.com/crystal4281.html>.
config SOUND_BCM_CS4297A
tristate "Crystal Sound CS4297a (for Swarm)"
- depends on SOUND_PRIME!=n && SIBYTE_SWARM && SOUND
+ depends on SOUND_PRIME && SIBYTE_SWARM
help
The BCM91250A has a Crystal CS4297a on synchronous serial
port B (in addition to the DB-9 serial port). Say Y or M
@@ -112,7 +112,7 @@ config SOUND_BCM_CS4297A
config SOUND_ES1370
tristate "Ensoniq AudioPCI (ES1370)"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a PCI sound card utilizing the Ensoniq
ES1370 chipset, such as Ensoniq's AudioPCI (non-97). To find
@@ -125,7 +125,7 @@ config SOUND_ES1370
config SOUND_ES1371
tristate "Creative Ensoniq AudioPCI 97 (ES1371)"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a PCI sound card utilizing the Ensoniq
ES1371 chipset, such as Ensoniq's AudioPCI97. To find out if
@@ -138,7 +138,7 @@ config SOUND_ES1371
config SOUND_ESSSOLO1
tristate "ESS Technology Solo1"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a PCI sound card utilizing the ESS Technology
Solo1 chip. To find out if your sound card uses a
@@ -149,7 +149,7 @@ config SOUND_ESSSOLO1
config SOUND_MAESTRO
tristate "ESS Maestro, Maestro2, Maestro2E driver"
- depends on SOUND_PRIME!=n && SOUND && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a sound system driven by ESS's Maestro line
of PCI sound chips. These include the Maestro 1, Maestro 2, and
@@ -158,28 +158,28 @@ config SOUND_MAESTRO
config SOUND_MAESTRO3
tristate "ESS Maestro3/Allegro driver (EXPERIMENTAL)"
- depends on SOUND_PRIME!=n && SOUND && PCI && EXPERIMENTAL
+ depends on SOUND_PRIME && PCI && EXPERIMENTAL
help
Say Y or M if you have a sound system driven by ESS's Maestro 3
PCI sound chip.
config SOUND_ICH
tristate "Intel ICH (i8xx) audio support"
- depends on SOUND_PRIME!=n && PCI
+ depends on SOUND_PRIME && PCI
help
Support for integral audio in Intel's I/O Controller Hub (ICH)
chipset, as used on the 810/820/840 motherboards.
config SOUND_HARMONY
tristate "PA Harmony audio driver"
- depends on GSC_LASI && SOUND_PRIME!=n
+ depends on GSC_LASI && SOUND_PRIME
help
Say 'Y' or 'M' to include support for Harmony soundchip
on HP 712, 715/new and many other GSC based machines.
config SOUND_SONICVIBES
tristate "S3 SonicVibes"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
help
Say Y or M if you have a PCI sound card utilizing the S3
SonicVibes chipset. To find out if your sound card uses a
@@ -190,7 +190,7 @@ config SOUND_SONICVIBES
config SOUND_VWSND
tristate "SGI Visual Workstation Sound"
- depends on SOUND_PRIME!=n && X86_VISWS && SOUND
+ depends on SOUND_PRIME && X86_VISWS
help
Say Y or M if you have an SGI Visual Workstation and you want to be
able to use its on-board audio. Read
@@ -199,18 +199,18 @@ config SOUND_VWSND
config SOUND_HAL2
tristate "SGI HAL2 sound (EXPERIMENTAL)"
- depends on SOUND_PRIME!=n && SOUND && SGI_IP22 && EXPERIMENTAL
+ depends on SOUND_PRIME && SGI_IP22 && EXPERIMENTAL
help
Say Y or M if you have an SGI Indy system and want to be able to
use it's on-board A2 audio system.
config SOUND_IT8172
tristate "IT8172G Sound"
- depends on SOUND_PRIME!=n && (MIPS_ITE8172 || MIPS_IVR) && SOUND
+ depends on SOUND_PRIME && (MIPS_ITE8172 || MIPS_IVR)
config SOUND_VRC5477
tristate "NEC Vrc5477 AC97 sound"
- depends on SOUND_PRIME!=n && DDB5477 && SOUND
+ depends on SOUND_PRIME && DDB5477
help
Say Y here to enable sound support for the NEC Vrc5477 chip, an
integrated, multi-function controller chip for MIPS CPUs. Works
@@ -218,15 +218,15 @@ config SOUND_VRC5477
config SOUND_AU1000
tristate "Au1000 Sound"
- depends on SOUND_PRIME!=n && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500) && SOUND
+ depends on SOUND_PRIME && (SOC_AU1000 || SOC_AU1100 || SOC_AU1500)
config SOUND_AU1550_AC97
tristate "Au1550 AC97 Sound"
- depends on SOUND_PRIME!=n && SOC_AU1550 && SOUND
+ depends on SOUND_PRIME && SOC_AU1550
config SOUND_TRIDENT
tristate "Trident 4DWave DX/NX, SiS 7018 or ALi 5451 PCI Audio Core"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
---help---
Say Y or M if you have a PCI sound card utilizing the Trident
4DWave-DX/NX chipset or your mother board chipset has SiS 7018
@@ -267,7 +267,7 @@ config SOUND_TRIDENT
config SOUND_MSNDCLAS
tristate "Support for Turtle Beach MultiSound Classic, Tahiti, Monterey"
- depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE)
+ depends on SOUND_PRIME && (m || !STANDALONE)
help
Say M here if you have a Turtle Beach MultiSound Classic, Tahiti or
Monterey (not for the Pinnacle or Fiji).
@@ -331,7 +331,7 @@ config MSNDCLAS_IO
config SOUND_MSNDPIN
tristate "Support for Turtle Beach MultiSound Pinnacle, Fiji"
- depends on SOUND_PRIME!=n && SOUND && (m || !STANDALONE)
+ depends on SOUND_PRIME && (m || !STANDALONE)
help
Say M here if you have a Turtle Beach MultiSound Pinnacle or Fiji.
See <file:Documentation/sound/oss/MultiSound> for important information
@@ -492,7 +492,7 @@ config MSND_FIFOSIZE
config SOUND_VIA82CXXX
tristate "VIA 82C686 Audio Codec"
- depends on SOUND_PRIME!=n && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y here to include support for the audio codec found on VIA
82Cxxx-based chips. Typically these are built into a motherboard.
@@ -512,7 +512,7 @@ config MIDI_VIA82CXXX
config SOUND_OSS
tristate "OSS sound modules"
- depends on SOUND_PRIME!=n && SOUND
+ depends on SOUND_PRIME
help
OSS is the Open Sound System suite of sound card drivers. They make
sound programming easier since they provide a common API. Say Y or
@@ -1077,7 +1077,7 @@ config SOUND_WAVEARTIST
config SOUND_TVMIXER
tristate "TV card (bt848) mixer support"
- depends on SOUND_PRIME!=n && SOUND && I2C
+ depends on SOUND_PRIME && I2C
help
Support for audio mixer facilities on the BT848 TV frame-grabber
card.
@@ -1088,11 +1088,11 @@ config SOUND_KAHLUA
config SOUND_ALI5455
tristate "ALi5455 audio support"
- depends on SOUND_PRIME!=n && PCI
+ depends on SOUND_PRIME && PCI
config SOUND_FORTE
tristate "ForteMedia FM801 driver"
- depends on SOUND_PRIME!=n && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you want driver support for the ForteMedia FM801 PCI
audio controller (Abit AU10, Genius Sound Maker, HP Workstation
@@ -1100,7 +1100,7 @@ config SOUND_FORTE
config SOUND_RME96XX
tristate "RME Hammerfall (RME96XX) support"
- depends on SOUND_PRIME!=n && PCI
+ depends on SOUND_PRIME && PCI
help
Say Y or M if you have a Hammerfall or Hammerfall light
multichannel card from RME. If you want to access advanced
@@ -1108,11 +1108,11 @@ config SOUND_RME96XX
config SOUND_AD1980
tristate "AD1980 front/back switch plugin"
- depends on SOUND_PRIME!=n
+ depends on SOUND_PRIME
config SOUND_SH_DAC_AUDIO
tristate "SuperH DAC audio support"
- depends on SOUND_PRIME!=n && SOUND && CPU_SH3
+ depends on SOUND_PRIME && CPU_SH3
config SOUND_SH_DAC_AUDIO_CHANNEL
int " DAC channel"
diff --git a/sound/oss/ad1816.c b/sound/oss/ad1816.c
index 22dae5d0fda3..95586de02028 100644
--- a/sound/oss/ad1816.c
+++ b/sound/oss/ad1816.c
@@ -592,7 +592,7 @@ typedef struct mixer_def mixer_ent;
{{reg_l, pola_l, pos_l, len_l}, {reg_r, pola_r, pos_r, len_r}}
-mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {
+static mixer_ent mix_devices[SOUND_MIXER_NRDEVICES][2] = {
MIX_ENT(SOUND_MIXER_VOLUME, 14, 1, 8, 5, 14, 1, 0, 5),
MIX_ENT(SOUND_MIXER_BASS, 0, 0, 0, 0, 0, 0, 0, 0),
MIX_ENT(SOUND_MIXER_TREBLE, 0, 0, 0, 0, 0, 0, 0, 0),
diff --git a/sound/oss/ad1848.c b/sound/oss/ad1848.c
index 4384dac3f794..7c835abd99bc 100644
--- a/sound/oss/ad1848.c
+++ b/sound/oss/ad1848.c
@@ -2178,8 +2178,7 @@ void ad1848_unload(int io_base, int irq, int dma_playback, int dma_capture, int
if (devc != NULL)
{
- if(audio_devs[dev]->portc!=NULL)
- kfree(audio_devs[dev]->portc);
+ kfree(audio_devs[dev]->portc);
release_region(devc->base, 4);
if (!share_dma)
diff --git a/sound/oss/ad1889.c b/sound/oss/ad1889.c
index b767c621fd09..2cfd214e4c2a 100644
--- a/sound/oss/ad1889.c
+++ b/sound/oss/ad1889.c
@@ -277,8 +277,7 @@ static void ad1889_free_dev(ad1889_dev_t *dev)
for (j = 0; j < AD_MAX_STATES; j++) {
dmabuf = &dev->state[j].dmabuf;
- if (dmabuf->rawbuf != NULL)
- kfree(dmabuf->rawbuf);
+ kfree(dmabuf->rawbuf);
}
kfree(dev);
diff --git a/sound/oss/cmpci.c b/sound/oss/cmpci.c
index 34720e66dae1..74dcca78c6c0 100644
--- a/sound/oss/cmpci.c
+++ b/sound/oss/cmpci.c
@@ -123,6 +123,7 @@
#include <linux/smp_lock.h>
#include <linux/bitops.h>
#include <linux/wait.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -3058,7 +3059,7 @@ static int __devinit cm_probe(struct pci_dev *pcidev, const struct pci_device_id
return -ENODEV;
if (pcidev->irq == 0)
return -ENODEV;
- i = pci_set_dma_mask(pcidev, 0xffffffff);
+ i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
if (i) {
printk(KERN_WARNING "cmpci: architecture does not support 32bit PCI busmaster DMA\n");
return i;
diff --git a/sound/oss/cs46xx.c b/sound/oss/cs46xx.c
index 9e42a1a67ca4..cb998e8c0fdd 100644
--- a/sound/oss/cs46xx.c
+++ b/sound/oss/cs46xx.c
@@ -4174,7 +4174,7 @@ static int cs_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int
list_for_each(entry, &cs46xx_devs)
{
card = list_entry(entry, struct cs_card, list);
- cs46xx_suspend(card, 0);
+ cs46xx_suspend(card, PMSG_ON);
}
}
@@ -5749,7 +5749,7 @@ static int cs46xx_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
case PM_SUSPEND:
CS_DBGOUT(CS_PM, 2, printk(KERN_INFO
"cs46xx: PM suspend request\n"));
- if(cs46xx_suspend(card, 0))
+ if(cs46xx_suspend(card, PMSG_SUSPEND))
{
CS_DBGOUT(CS_ERROR, 2, printk(KERN_INFO
"cs46xx: PM suspend request refused\n"));
@@ -5779,7 +5779,7 @@ static int cs46xx_suspend_tbl(struct pci_dev *pcidev, pm_message_t state)
struct cs_card *s = PCI_GET_DRIVER_DATA(pcidev);
CS_DBGOUT(CS_PM | CS_FUNCTION, 2,
printk(KERN_INFO "cs46xx: cs46xx_suspend_tbl request\n"));
- cs46xx_suspend(s, 0);
+ cs46xx_suspend(s, state);
return 0;
}
diff --git a/sound/oss/dmasound/dmasound_awacs.c b/sound/oss/dmasound/dmasound_awacs.c
index 5281b88987f3..2704e1598add 100644
--- a/sound/oss/dmasound/dmasound_awacs.c
+++ b/sound/oss/dmasound/dmasound_awacs.c
@@ -255,7 +255,7 @@ static int awacs_burgundy_read_mvolume(unsigned address);
static volatile struct dbdma_cmd *emergency_dbdma_cmd;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* Stuff for restoring after a sleep.
*/
@@ -263,7 +263,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when);
struct pmu_sleep_notifier awacs_sleep_notifier = {
awacs_sleep_notify, SLEEP_LEVEL_SOUND,
};
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
/* for (soft) sample rate translations */
int expand_bal; /* Balance factor for expanding (not volume!) */
@@ -671,15 +671,11 @@ static void PMacIrqCleanup(void)
release_OF_resource(awacs_node, 1);
release_OF_resource(awacs_node, 2);
- if (awacs_tx_cmd_space)
- kfree(awacs_tx_cmd_space);
- if (awacs_rx_cmd_space)
- kfree(awacs_rx_cmd_space);
- if (beep_dbdma_cmd_space)
- kfree(beep_dbdma_cmd_space);
- if (beep_buf)
- kfree(beep_buf);
-#ifdef CONFIG_PMAC_PBOOK
+ kfree(awacs_tx_cmd_space);
+ kfree(awacs_rx_cmd_space);
+ kfree(beep_dbdma_cmd_space);
+ kfree(beep_buf);
+#ifdef CONFIG_PM
pmu_unregister_sleep_notifier(&awacs_sleep_notifier);
#endif
}
@@ -1419,7 +1415,7 @@ load_awacs(void)
}
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/*
* Save state when going to sleep, restore it afterwards.
*/
@@ -1555,7 +1551,7 @@ static int awacs_sleep_notify(struct pmu_sleep_notifier *self, int when)
}
return PBOOK_SLEEP_OK;
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
/* All the burgundy functions: */
@@ -2301,8 +2297,7 @@ if (count <= 0)
#endif
if ((write_sq.max_count + 1) > number_of_tx_cmd_buffers) {
- if (awacs_tx_cmd_space)
- kfree(awacs_tx_cmd_space);
+ kfree(awacs_tx_cmd_space);
number_of_tx_cmd_buffers = 0;
/* we need nbufs + 1 (for the loop) and we should request + 1
@@ -2360,8 +2355,7 @@ if (count <= 0)
#endif
if ((read_sq.max_count+1) > number_of_rx_cmd_buffers ) {
- if (awacs_rx_cmd_space)
- kfree(awacs_rx_cmd_space);
+ kfree(awacs_rx_cmd_space);
number_of_rx_cmd_buffers = 0;
/* we need nbufs + 1 (for the loop) and we should request + 1 again
@@ -2805,7 +2799,7 @@ __init setup_beep(void)
beep_buf = (short *) kmalloc(BEEP_BUFLEN * 4, GFP_KERNEL);
if (beep_buf == NULL) {
printk(KERN_ERR "dmasound_pmac: no memory for beep buffer\n");
- if( beep_dbdma_cmd_space ) kfree(beep_dbdma_cmd_space) ;
+ kfree(beep_dbdma_cmd_space) ;
return -ENOMEM ;
}
return 0 ;
@@ -3059,9 +3053,9 @@ printk("dmasound_pmac: Awacs/Screamer Codec Mfct: %d Rev %d\n", mfg, rev);
if ((res=setup_beep()))
return res ;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
pmu_register_sleep_notifier(&awacs_sleep_notifier);
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
/* Powerbooks have odd ways of enabling inputs such as
an expansion-bay CD or sound from an internal modem
diff --git a/sound/oss/emu10k1/midi.c b/sound/oss/emu10k1/midi.c
index 33dea3d56c1e..b40b5f97aace 100644
--- a/sound/oss/emu10k1/midi.c
+++ b/sound/oss/emu10k1/midi.c
@@ -523,10 +523,8 @@ void emu10k1_seq_midi_close(int dev)
card = midi_devs[dev]->devc;
emu10k1_mpuout_close(card);
- if (card->seq_mididev) {
- kfree(card->seq_mididev);
- card->seq_mididev = NULL;
- }
+ kfree(card->seq_mididev);
+ card->seq_mididev = NULL;
}
int emu10k1_seq_midi_out(int dev, unsigned char midi_byte)
diff --git a/sound/oss/emu10k1/passthrough.c b/sound/oss/emu10k1/passthrough.c
index 4094be55f3be..4e3baca7d41f 100644
--- a/sound/oss/emu10k1/passthrough.c
+++ b/sound/oss/emu10k1/passthrough.c
@@ -213,8 +213,7 @@ void emu10k1_pt_stop(struct emu10k1_card *card)
sblive_writeptr(card, SPCS0 + i, 0, pt->old_spcs[i]);
}
pt->state = PT_STATE_INACTIVE;
- if(pt->buf)
- kfree(pt->buf);
+ kfree(pt->buf);
}
}
diff --git a/sound/oss/es1370.c b/sound/oss/es1370.c
index 056091cff266..8538085086e7 100644
--- a/sound/oss/es1370.c
+++ b/sound/oss/es1370.c
@@ -156,11 +156,16 @@
#include <linux/spinlock.h>
#include <linux/gameport.h>
#include <linux/wait.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/uaccess.h>
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
/* --------------------------------------------------------------------- */
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -384,7 +389,10 @@ struct es1370_state {
unsigned char obuf[MIDIOUTBUF];
} midi;
+#ifdef SUPPORT_JOYSTICK
struct gameport *gameport;
+#endif
+
struct semaphore sem;
};
@@ -2553,10 +2561,55 @@ static struct initvol {
{ SOUND_MIXER_WRITE_OGAIN, 0x4040 }
};
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1370_register_gameport(struct es1370_state *s)
+{
+ struct gameport *gp;
+
+ if (!request_region(0x200, JOY_EXTENT, "es1370")) {
+ printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
+ return -EBUSY;
+ }
+
+ s->gameport = gp = gameport_allocate_port();
+ if (!gp) {
+ printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
+ release_region(0x200, JOY_EXTENT);
+ return -ENOMEM;
+ }
+
+ gameport_set_name(gp, "ESS1370");
+ gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
+ gp->dev.parent = &s->dev->dev;
+ gp->io = 0x200;
+
+ s->ctrl |= CTRL_JYSTK_EN;
+ outl(s->ctrl, s->io + ES1370_REG_CONTROL);
+
+ gameport_register_port(gp);
+
+ return 0;
+}
+
+static inline void es1370_unregister_gameport(struct es1370_state *s)
+{
+ if (s->gameport) {
+ int gpio = s->gameport->io;
+ gameport_unregister_port(s->gameport);
+ release_region(gpio, JOY_EXTENT);
+
+ }
+}
+
+#else
+static inline int es1370_register_gameport(struct es1370_state *s) { return -ENOSYS; }
+static inline void es1370_unregister_gameport(struct es1370_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct es1370_state *s;
- struct gameport *gp = NULL;
mm_segment_t fs;
int i, val, ret;
@@ -2569,7 +2622,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
return -ENODEV;
if (pcidev->irq == 0)
return -ENODEV;
- i = pci_set_dma_mask(pcidev, 0xffffffff);
+ i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
if (i) {
printk(KERN_WARNING "es1370: architecture does not support 32bit PCI busmaster DMA\n");
return i;
@@ -2605,28 +2658,14 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
/* note: setting CTRL_SERR_DIS is reported to break
* mic bias setting (by Kim.Berts@fisub.mail.abb.com) */
s->ctrl = CTRL_CDC_EN | (DAC2_SRTODIV(8000) << CTRL_SH_PCLKDIV) | (1 << CTRL_SH_WTSRSEL);
- if (!request_region(0x200, JOY_EXTENT, "es1370")) {
- printk(KERN_ERR "es1370: joystick io port 0x200 in use\n");
- } else if (!(s->gameport = gp = gameport_allocate_port())) {
- printk(KERN_ERR "es1370: can not allocate memory for gameport\n");
- release_region(0x200, JOY_EXTENT);
- } else {
- gameport_set_name(gp, "ESS1370");
- gameport_set_phys(gp, "pci%s/gameport0", pci_name(s->dev));
- gp->dev.parent = &s->dev->dev;
- gp->io = 0x200;
- s->ctrl |= CTRL_JYSTK_EN;
- }
if (lineout[devindex])
s->ctrl |= CTRL_XCTL0;
if (micbias[devindex])
s->ctrl |= CTRL_XCTL1;
s->sctrl = 0;
- printk(KERN_INFO "es1370: found adapter at io %#lx irq %u\n"
- KERN_INFO "es1370: features: joystick %s, line %s, mic impedance %s\n",
- s->io, s->irq, (s->ctrl & CTRL_JYSTK_EN) ? "on" : "off",
- (s->ctrl & CTRL_XCTL0) ? "out" : "in",
- (s->ctrl & CTRL_XCTL1) ? "1" : "0");
+ printk(KERN_INFO "es1370: adapter at io %#lx irq %u, line %s, mic impedance %s\n",
+ s->io, s->irq, (s->ctrl & CTRL_XCTL0) ? "out" : "in",
+ (s->ctrl & CTRL_XCTL1) ? "1" : "0");
/* register devices */
if ((s->dev_audio = register_sound_dsp(&es1370_audio_fops, -1)) < 0) {
ret = s->dev_audio;
@@ -2672,9 +2711,7 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
}
set_fs(fs);
- /* register gameport */
- if (gp)
- gameport_register_port(gp);
+ es1370_register_gameport(s);
/* store it in the driver field */
pci_set_drvdata(pcidev, s);
@@ -2696,10 +2733,6 @@ static int __devinit es1370_probe(struct pci_dev *pcidev, const struct pci_devic
err_dev1:
printk(KERN_ERR "es1370: cannot register misc device\n");
free_irq(s->irq, s);
- if (s->gameport) {
- release_region(s->gameport->io, JOY_EXTENT);
- gameport_free_port(s->gameport);
- }
err_irq:
release_region(s->io, ES1370_EXTENT);
err_region:
@@ -2718,11 +2751,7 @@ static void __devexit es1370_remove(struct pci_dev *dev)
outl(0, s->io+ES1370_REG_SERIAL_CONTROL); /* clear serial interrupts */
synchronize_irq(s->irq);
free_irq(s->irq, s);
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, JOY_EXTENT);
- }
+ es1370_unregister_gameport(s);
release_region(s->io, ES1370_EXTENT);
unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->dev_mixer);
diff --git a/sound/oss/es1371.c b/sound/oss/es1371.c
index a50fddaeea21..12a56d5ab498 100644
--- a/sound/oss/es1371.c
+++ b/sound/oss/es1371.c
@@ -128,11 +128,16 @@
#include <linux/ac97_codec.h>
#include <linux/gameport.h>
#include <linux/wait.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/page.h>
#include <asm/uaccess.h>
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK
+#endif
+
/* --------------------------------------------------------------------- */
#undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -453,7 +458,10 @@ struct es1371_state {
unsigned char obuf[MIDIOUTBUF];
} midi;
+#ifdef SUPPORT_JOYSTICK
struct gameport *gameport;
+#endif
+
struct semaphore sem;
};
@@ -2786,12 +2794,63 @@ static struct
{ PCI_ANY_ID, PCI_ANY_ID }
};
+#ifdef SUPPORT_JOYSTICK
+
+static int __devinit es1371_register_gameport(struct es1371_state *s)
+{
+ struct gameport *gp;
+ int gpio;
+
+ for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
+ if (request_region(gpio, JOY_EXTENT, "es1371"))
+ break;
+
+ if (gpio < 0x200) {
+ printk(KERN_ERR PFX "no free joystick address found\n");
+ return -EBUSY;
+ }
+
+ s->gameport = gp = gameport_allocate_port();
+ if (!gp) {
+ printk(KERN_ERR PFX "can not allocate memory for gameport\n");
+ release_region(gpio, JOY_EXTENT);
+ return -ENOMEM;
+ }
+
+ gameport_set_name(gp, "ESS1371 Gameport");
+ gameport_set_phys(gp, "isa%04x/gameport0", gpio);
+ gp->dev.parent = &s->dev->dev;
+ gp->io = gpio;
+
+ s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
+ outl(s->ctrl, s->io + ES1371_REG_CONTROL);
+
+ gameport_register_port(gp);
+
+ return 0;
+}
+
+static inline void es1371_unregister_gameport(struct es1371_state *s)
+{
+ if (s->gameport) {
+ int gpio = s->gameport->io;
+ gameport_unregister_port(s->gameport);
+ release_region(gpio, JOY_EXTENT);
+
+ }
+}
+
+#else
+static inline int es1371_register_gameport(struct es1371_state *s) { return -ENOSYS; }
+static inline void es1371_unregister_gameport(struct es1371_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
+
static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct es1371_state *s;
- struct gameport *gp;
mm_segment_t fs;
- int i, gpio, val, res = -1;
+ int i, val, res = -1;
int idx;
unsigned long tmo;
signed long tmo2;
@@ -2804,7 +2863,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
return -ENODEV;
if (pcidev->irq == 0)
return -ENODEV;
- i = pci_set_dma_mask(pcidev, 0xffffffff);
+ i = pci_set_dma_mask(pcidev, DMA_32BIT_MASK);
if (i) {
printk(KERN_WARNING "es1371: architecture does not support 32bit PCI busmaster DMA\n");
return i;
@@ -2882,23 +2941,6 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
}
}
- for (gpio = 0x218; gpio >= 0x200; gpio -= 0x08)
- if (request_region(gpio, JOY_EXTENT, "es1371"))
- break;
-
- if (gpio < 0x200) {
- printk(KERN_ERR PFX "no free joystick address found\n");
- } else if (!(s->gameport = gp = gameport_allocate_port())) {
- printk(KERN_ERR PFX "can not allocate memory for gameport\n");
- release_region(gpio, JOY_EXTENT);
- } else {
- gameport_set_name(gp, "ESS1371 Gameport");
- gameport_set_phys(gp, "isa%04x/gameport0", gpio);
- gp->dev.parent = &s->dev->dev;
- gp->io = gpio;
- s->ctrl |= CTRL_JYSTK_EN | (((gpio >> 3) & CTRL_JOY_MASK) << CTRL_JOY_SHIFT);
- }
-
s->sctrl = 0;
cssr = 0;
s->spdif_volume = -1;
@@ -2968,9 +3010,7 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* turn on S/PDIF output driver if requested */
outl(cssr, s->io+ES1371_REG_STATUS);
- /* register gameport */
- if (s->gameport)
- gameport_register_port(s->gameport);
+ es1371_register_gameport(s);
/* store it in the driver field */
pci_set_drvdata(pcidev, s);
@@ -2979,13 +3019,9 @@ static int __devinit es1371_probe(struct pci_dev *pcidev, const struct pci_devic
/* increment devindex */
if (devindex < NR_DEVICE-1)
devindex++;
- return 0;
+ return 0;
err_gp:
- if (s->gameport) {
- release_region(s->gameport->io, JOY_EXTENT);
- gameport_free_port(s->gameport);
- }
#ifdef ES1371_DEBUG
if (s->ps)
remove_proc_entry("es1371", NULL);
@@ -3024,11 +3060,7 @@ static void __devexit es1371_remove(struct pci_dev *dev)
outl(0, s->io+ES1371_REG_SERIAL_CONTROL); /* clear serial interrupts */
synchronize_irq(s->irq);
free_irq(s->irq, s);
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, JOY_EXTENT);
- }
+ es1371_unregister_gameport(s);
release_region(s->io, ES1371_EXTENT);
unregister_sound_dsp(s->dev_audio);
unregister_sound_mixer(s->codec->dev_mixer);
diff --git a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c
index 6b3b9a99579d..a4ecab2f0522 100644
--- a/sound/oss/esssolo1.c
+++ b/sound/oss/esssolo1.c
@@ -104,6 +104,7 @@
#include <linux/smp_lock.h>
#include <linux/gameport.h>
#include <linux/wait.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/page.h>
@@ -149,6 +150,10 @@
#define FMODE_DMFM 0x10
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
static struct pci_driver solo1_driver;
/* --------------------------------------------------------------------- */
@@ -226,7 +231,9 @@ struct solo1_state {
unsigned char obuf[MIDIOUTBUF];
} midi;
+#if SUPPORT_JOYSTICK
struct gameport *gameport;
+#endif
};
/* --------------------------------------------------------------------- */
@@ -2280,6 +2287,7 @@ solo1_resume(struct pci_dev *pci_dev) {
return 0;
}
+#ifdef SUPPORT_JOYSTICK
static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
{
struct gameport *gp;
@@ -2306,6 +2314,19 @@ static int __devinit solo1_register_gameport(struct solo1_state *s, int io_port)
return 0;
}
+static inline void solo1_unregister_gameport(struct solo1_state *s)
+{
+ if (s->gameport) {
+ int gpio = s->gameport->io;
+ gameport_unregister_port(s->gameport);
+ release_region(gpio, GAMEPORT_EXTENT);
+ }
+}
+#else
+static inline int solo1_register_gameport(struct solo1_state *s, int io_port) { return -ENOSYS; }
+static inline void solo1_unregister_gameport(struct solo1_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
struct solo1_state *s;
@@ -2326,7 +2347,7 @@ static int __devinit solo1_probe(struct pci_dev *pcidev, const struct pci_device
* to 24 bits first, then 32 bits (playback only) if that fails.
*/
if (pci_set_dma_mask(pcidev, 0x00ffffff) &&
- pci_set_dma_mask(pcidev, 0xffffffff)) {
+ pci_set_dma_mask(pcidev, DMA_32BIT_MASK)) {
printk(KERN_WARNING "solo1: architecture does not support 24bit or 32bit PCI busmaster DMA\n");
return -ENODEV;
}
@@ -2437,11 +2458,7 @@ static void __devexit solo1_remove(struct pci_dev *dev)
synchronize_irq(s->irq);
pci_write_config_word(s->dev, 0x60, 0); /* turn off DDMA controller address space */
free_irq(s->irq, s);
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, GAMEPORT_EXTENT);
- }
+ solo1_unregister_gameport(s);
release_region(s->iobase, IOBASE_EXTENT);
release_region(s->sbbase+FMSYNTH_EXTENT, SBBASE_EXTENT-FMSYNTH_EXTENT);
release_region(s->ddmabase, DDMABASE_EXTENT);
diff --git a/sound/oss/mad16.c b/sound/oss/mad16.c
index a7067f169919..aa3c50db66c4 100644
--- a/sound/oss/mad16.c
+++ b/sound/oss/mad16.c
@@ -50,9 +50,12 @@
#include "sb.h"
#include "mpu401.h"
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
static int mad16_conf;
static int mad16_cdsel;
-static struct gameport *gameport;
static DEFINE_SPINLOCK(lock);
#define C928 1
@@ -902,6 +905,10 @@ static int __initdata irq_map[16] =
-1, -1, -1, -1
};
+#ifdef SUPPORT_JOYSTICK
+
+static struct gameport *gameport;
+
static int __devinit mad16_register_gameport(int io_port)
{
if (!request_region(io_port, 1, "mad16 gameport")) {
@@ -925,6 +932,20 @@ static int __devinit mad16_register_gameport(int io_port)
return 0;
}
+static inline void mad16_unregister_gameport(void)
+{
+ if (gameport) {
+ /* the gameport was initialized so we must free it up */
+ gameport_unregister_port(gameport);
+ gameport = NULL;
+ release_region(0x201, 1);
+ }
+}
+#else
+static inline int mad16_register_gameport(int io_port) { return -ENOSYS; }
+static inline void mad16_unregister_gameport(void) { }
+#endif
+
static int __devinit init_mad16(void)
{
int dmatype = 0;
@@ -1060,12 +1081,7 @@ static void __exit cleanup_mad16(void)
{
if (found_mpu)
unload_mad16_mpu(&cfg_mpu);
- if (gameport) {
- /* the gameport was initialized so we must free it up */
- gameport_unregister_port(gameport);
- gameport = NULL;
- release_region(0x201, 1);
- }
+ mad16_unregister_gameport();
unload_mad16(&cfg);
release_region(MC0_PORT, 12);
}
diff --git a/sound/oss/maestro.c b/sound/oss/maestro.c
index 52d2db4bc312..3dce504e6d6d 100644
--- a/sound/oss/maestro.c
+++ b/sound/oss/maestro.c
@@ -2356,7 +2356,7 @@ ess_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
}
rec_return_free:
- if(combbuf) kfree(combbuf);
+ kfree(combbuf);
return ret;
}
diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c
index b66f53fa8db0..0aac54c68f01 100644
--- a/sound/oss/mpu401.c
+++ b/sound/oss/mpu401.c
@@ -1240,8 +1240,7 @@ void unload_mpu401(struct address_info *hw_config)
p=mpu401_synth_operations[n];
sound_unload_mididev(n);
sound_unload_timerdev(hw_config->slots[2]);
- if(p)
- kfree(p);
+ kfree(p);
}
}
diff --git a/sound/oss/nm256.h b/sound/oss/nm256.h
index eae7d99d6826..21e07b5081f2 100644
--- a/sound/oss/nm256.h
+++ b/sound/oss/nm256.h
@@ -128,9 +128,6 @@ struct nm256_info
struct nm256_info *next_card;
};
-/* Debug flag--bigger numbers mean more output. */
-extern int nm256_debug;
-
/* The BIOS signature. */
#define NM_SIGNATURE 0x4e4d0000
/* Signature mask. */
@@ -284,7 +281,7 @@ nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
}
/* Returns a non-zero value if we should use the coefficient cache. */
-extern int nm256_cachedCoefficients (struct nm256_info *card);
+static int nm256_cachedCoefficients (struct nm256_info *card);
#endif
diff --git a/sound/oss/nm256_audio.c b/sound/oss/nm256_audio.c
index f9166e135192..66970062eb36 100644
--- a/sound/oss/nm256_audio.c
+++ b/sound/oss/nm256_audio.c
@@ -28,12 +28,13 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include "sound_config.h"
-#include "nm256.h"
-#include "nm256_coeff.h"
-int nm256_debug;
+static int nm256_debug;
static int force_load;
+#include "nm256.h"
+#include "nm256_coeff.h"
+
/*
* The size of the playback reserve. When the playback buffer has less
* than NM256_PLAY_WMARK_SIZE bytes to output, we request a new
@@ -138,7 +139,7 @@ static int usecache;
static int buffertop;
/* Check to see if we're using the bank of cached coefficients. */
-int
+static int
nm256_cachedCoefficients (struct nm256_info *card)
{
return usecache;
diff --git a/sound/oss/nm256_coeff.h b/sound/oss/nm256_coeff.h
index 0ceecc20077b..6fc07f3cb33b 100644
--- a/sound/oss/nm256_coeff.h
+++ b/sound/oss/nm256_coeff.h
@@ -4650,7 +4650,7 @@ nm256_loadAllCoefficients (struct nm256_info *card)
card->coeffsCurrent = 1;
}
-void
+static void
nm256_loadCoefficient (struct nm256_info *card, int which, int number)
{
static u16 addrs[3] = { 0x1c, 0x21c, 0x408 };
diff --git a/sound/oss/rme96xx.c b/sound/oss/rme96xx.c
index b4278eecc917..7609c68a89f4 100644
--- a/sound/oss/rme96xx.c
+++ b/sound/oss/rme96xx.c
@@ -1750,9 +1750,7 @@ static unsigned int rme96xx_poll(struct file *file, struct poll_table_struct *wa
static struct file_operations rme96xx_audio_fops = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
.owner = THIS_MODULE,
-#endif
.read = rme96xx_read,
.write = rme96xx_write,
.poll = rme96xx_poll,
@@ -1852,9 +1850,7 @@ static int rme96xx_mixer_release(struct inode *inode, struct file *file)
}
static /*const*/ struct file_operations rme96xx_mixer_fops = {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
.owner = THIS_MODULE,
-#endif
.ioctl = rme96xx_mixer_ioctl,
.open = rme96xx_mixer_open,
.release = rme96xx_mixer_release,
diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c
index ce359e6c933a..5f955e3d2e26 100644
--- a/sound/oss/sb_common.c
+++ b/sound/oss/sb_common.c
@@ -915,8 +915,8 @@ void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
}
else
release_region(hw_config->io_base, 16);
- if(detected_devc)
- kfree(detected_devc);
+
+ kfree(detected_devc);
}
/*
diff --git a/sound/oss/sonicvibes.c b/sound/oss/sonicvibes.c
index 06047e7979af..17d0e461f8d8 100644
--- a/sound/oss/sonicvibes.c
+++ b/sound/oss/sonicvibes.c
@@ -122,6 +122,9 @@
#include "dm.h"
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
/* --------------------------------------------------------------------- */
@@ -365,7 +368,9 @@ struct sv_state {
unsigned char obuf[MIDIOUTBUF];
} midi;
+#if SUPPORT_JOYSTICK
struct gameport *gameport;
+#endif
};
/* --------------------------------------------------------------------- */
@@ -2485,6 +2490,7 @@ static struct initvol {
#define RSRCISIOREGION(dev,num) (pci_resource_start((dev), (num)) != 0 && \
(pci_resource_flags((dev), (num)) & IORESOURCE_IO))
+#ifdef SUPPORT_JOYSTICK
static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
{
struct gameport *gp;
@@ -2511,6 +2517,19 @@ static int __devinit sv_register_gameport(struct sv_state *s, int io_port)
return 0;
}
+static inline void sv_unregister_gameport(struct sv_state *s)
+{
+ if (s->gameport) {
+ int gpio = s->gameport->io;
+ gameport_unregister_port(s->gameport);
+ release_region(gpio, SV_EXTENT_GAME);
+ }
+}
+#else
+static inline int sv_register_gameport(struct sv_state *s, int io_port) { return -ENOSYS; }
+static inline void sv_unregister_gameport(struct sv_state *s) { }
+#endif /* SUPPORT_JOYSTICK */
+
static int __devinit sv_probe(struct pci_dev *pcidev, const struct pci_device_id *pciid)
{
static char __devinitdata sv_ddma_name[] = "S3 Inc. SonicVibes DDMA Controller";
@@ -2711,11 +2730,7 @@ static void __devexit sv_remove(struct pci_dev *dev)
/*outb(0, s->iodmaa + SV_DMA_RESET);*/
/*outb(0, s->iodmac + SV_DMA_RESET);*/
free_irq(s->irq, s);
- if (s->gameport) {
- int gpio = s->gameport->io;
- gameport_unregister_port(s->gameport);
- release_region(gpio, SV_EXTENT_GAME);
- }
+ sv_unregister_gameport(s);
release_region(s->iodmac, SV_EXTENT_DMA);
release_region(s->iodmaa, SV_EXTENT_DMA);
release_region(s->ioenh, SV_EXTENT_ENH);
diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c
index 50ca64629450..9ed5211c3168 100644
--- a/sound/oss/sscape.c
+++ b/sound/oss/sscape.c
@@ -991,7 +991,6 @@ static void __init sscape_pnp_init_hw(sscape_info* devc)
unsigned i;
static char code_file_name[23] = "/sndscape/sndscape.cox";
- int sscape_sb_enable = 0;
int sscape_joystic_enable = 0x7f;
int sscape_mic_enable = 0;
int sscape_ext_midi = 0;
@@ -1015,14 +1014,9 @@ static void __init sscape_pnp_init_hw(sscape_info* devc)
sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40);
sscape_write( devc, 3, ( devc -> dma << 4) | 0x80);
- if ( sscape_sb_enable )
- sscape_write (devc, 4, 0xF0 | (sb_irq << 2) | midi_irq);
- else
- sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
+ sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq);
i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0);
- if ( sscape_sb_enable )
- i |= devc->ic_type == IC_ODIE ? 0x05 : 0x07;
if (sscape_joystic_enable) i |= 8;
sscape_write (devc, 9, i);
diff --git a/sound/oss/trident.c b/sound/oss/trident.c
index 47537f0a5b05..5f0ad6bb43b9 100644
--- a/sound/oss/trident.c
+++ b/sound/oss/trident.c
@@ -228,6 +228,10 @@
#define DRIVER_VERSION "0.14.10j-2.6"
+#if defined(CONFIG_GAMEPORT) || (defined(MODULE) && defined(CONFIG_GAMEPORT_MODULE))
+#define SUPPORT_JOYSTICK 1
+#endif
+
/* magic numbers to protect our data structures */
#define TRIDENT_CARD_MAGIC 0x5072696E /* "Prin" */
#define TRIDENT_STATE_MAGIC 0x63657373 /* "cess" */
@@ -4252,24 +4256,25 @@ trident_ac97_init(struct trident_card *card)
return num_ac97 + 1;
}
+#ifdef SUPPORT_JOYSTICK
/* Gameport functions for the cards ADC gameport */
-static unsigned char
-trident_game_read(struct gameport *gameport)
+static unsigned char trident_game_read(struct gameport *gameport)
{
struct trident_card *card = gameport->port_data;
+
return inb(TRID_REG(card, T4D_GAME_LEG));
}
-static void
-trident_game_trigger(struct gameport *gameport)
+static void trident_game_trigger(struct gameport *gameport)
{
struct trident_card *card = gameport->port_data;
+
outb(0xff, TRID_REG(card, T4D_GAME_LEG));
}
-static int
-trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+static int trident_game_cooked_read(struct gameport *gameport,
+ int *axes, int *buttons)
{
struct trident_card *card = gameport->port_data;
int i;
@@ -4285,8 +4290,7 @@ trident_game_cooked_read(struct gameport *gameport, int *axes, int *buttons)
return 0;
}
-static int
-trident_game_open(struct gameport *gameport, int mode)
+static int trident_game_open(struct gameport *gameport, int mode)
{
struct trident_card *card = gameport->port_data;
@@ -4305,8 +4309,7 @@ trident_game_open(struct gameport *gameport, int mode)
return 0;
}
-static int __devinit
-trident_register_gameport(struct trident_card *card)
+static int __devinit trident_register_gameport(struct trident_card *card)
{
struct gameport *gp;
@@ -4330,6 +4333,17 @@ trident_register_gameport(struct trident_card *card)
return 0;
}
+static inline void trident_unregister_gameport(struct trident_card *card)
+{
+ if (card->gameport)
+ gameport_unregister_port(card->gameport);
+}
+
+#else
+static inline int trident_register_gameport(struct trident_card *card) { return -ENOSYS; }
+static inline void trident_unregister_gameport(struct trident_card *card) { }
+#endif /* SUPPORT_JOYSTICK */
+
/* install the driver, we do not allocate hardware channel nor DMA buffer */
/* now, they are defered until "ACCESS" time (in prog_dmabuf called by */
/* open/read/write/ioctl/mmap) */
@@ -4569,8 +4583,7 @@ trident_remove(struct pci_dev *pci_dev)
}
/* Unregister gameport */
- if (card->gameport)
- gameport_unregister_port(card->gameport);
+ trident_unregister_gameport(card);
/* Kill interrupts, and SP/DIF */
trident_disable_loop_interrupts(card);
diff --git a/sound/oss/v_midi.c b/sound/oss/v_midi.c
index 077b76797665..a7ef04fab075 100644
--- a/sound/oss/v_midi.c
+++ b/sound/oss/v_midi.c
@@ -39,8 +39,6 @@ static void *midi_mem = NULL;
*/
-void (*midi_input_intr) (int dev, unsigned char data);
-
static int v_midi_open (int dev, int mode,
void (*input) (int dev, unsigned char data),
void (*output) (int dev)
diff --git a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c
index b387e1e52485..83edda93f0b4 100644
--- a/sound/oss/via82cxxx_audio.c
+++ b/sound/oss/via82cxxx_audio.c
@@ -35,6 +35,7 @@
#include <linux/smp_lock.h>
#include <linux/ioport.h>
#include <linux/delay.h>
+#include <linux/dma-mapping.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
@@ -3391,10 +3392,10 @@ static int __devinit via_init_one (struct pci_dev *pdev, const struct pci_device
if (rc)
goto err_out_disable;
- rc = pci_set_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
goto err_out_res;
- rc = pci_set_consistent_dma_mask(pdev, 0xffffffffULL);
+ rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
if (rc)
goto err_out_res;
diff --git a/sound/oss/wavfront.c b/sound/oss/wavfront.c
index cce1278dc487..b92ba8921638 100644
--- a/sound/oss/wavfront.c
+++ b/sound/oss/wavfront.c
@@ -151,11 +151,11 @@ static int (*midi_load_patch) (int devno, int format, const char __user *addr,
/*** Module-accessible parameters ***************************************/
-int wf_raw; /* we normally check for "raw state" to firmware
- loading. if set, then during driver loading, the
- state of the board is ignored, and we reset the
- board and load the firmware anyway.
- */
+static int wf_raw; /* we normally check for "raw state" to firmware
+ loading. if set, then during driver loading, the
+ state of the board is ignored, and we reset the
+ board and load the firmware anyway.
+ */
static int fx_raw = 1; /* if this is zero, we'll leave the FX processor in
whatever state it is when the driver is loaded.
@@ -2911,7 +2911,7 @@ int __init detect_wffx (void)
return 0;
}
-void
+static void
wffx_mute (int onoff)
{
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c
index defdc5a459f0..c5557eaf3e2e 100644
--- a/sound/pci/bt87x.c
+++ b/sound/pci/bt87x.c
@@ -798,13 +798,15 @@ static struct {
{0x270f, 0xfc00}, /* Chaintech Digitop DST-1000 DVB-S */
};
+static struct pci_driver driver;
+
/* return the rate of the card, or a negative value if it's blacklisted */
static int __devinit snd_bt87x_detect_card(struct pci_dev *pci)
{
int i;
const struct pci_device_id *supported;
- supported = pci_match_device(snd_bt87x_ids, pci);
+ supported = pci_match_device(&driver, pci);
if (supported)
return supported->driver_data;
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c
index b6e1854e9389..eb3c52b03af3 100644
--- a/sound/pci/cs4281.c
+++ b/sound/pci/cs4281.c
@@ -1338,11 +1338,6 @@ static inline int snd_cs4281_create_gameport(cs4281_t *chip) { return -ENOSYS; }
static inline void snd_cs4281_free_gameport(cs4281_t *chip) { }
#endif /* CONFIG_GAMEPORT || (MODULE && CONFIG_GAMEPORT_MODULE) */
-
-/*
-
- */
-
static int snd_cs4281_free(cs4281_t *chip)
{
snd_cs4281_free_gameport(chip);
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c
index f72c81cc9952..d6918b453f28 100644
--- a/sound/pcmcia/pdaudiocf/pdaudiocf.c
+++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c
@@ -22,7 +22,6 @@
#include <sound/core.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
-#include <pcmcia/version.h>
#include <pcmcia/ciscode.h>
#include <pcmcia/cisreg.h>
#include "pdaudiocf.h"
@@ -171,14 +170,6 @@ static dev_link_t *snd_pdacf_attach(void)
/* Register with Card Services */
client_reg.dev_info = &dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
- | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
- | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
- ;
- client_reg.event_handler = &pdacf_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -380,13 +371,21 @@ static int pdacf_event(event_t event, int priority, event_callback_args_t *args)
/*
* Module entry points
*/
+static struct pcmcia_device_id snd_pdacf_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x015d, 0x4c45),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, snd_pdacf_ids);
+
static struct pcmcia_driver pdacf_cs_driver = {
- .owner = THIS_MODULE,
- .drv = {
- .name = "snd-pdaudiocf",
+ .owner = THIS_MODULE,
+ .drv = {
+ .name = "snd-pdaudiocf",
},
- .attach = snd_pdacf_attach,
- .detach = snd_pdacf_detach
+ .attach = snd_pdacf_attach,
+ .event = pdacf_event,
+ .detach = snd_pdacf_detach,
+ .id_table = snd_pdacf_ids,
};
static int __init init_pdacf(void)
diff --git a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c
index 332bbca3dfc4..df7a39ba9680 100644
--- a/sound/pcmcia/vx/vx_entry.c
+++ b/sound/pcmcia/vx/vx_entry.c
@@ -35,7 +35,6 @@ MODULE_LICENSE("GPL");
* prototypes
*/
static void vxpocket_config(dev_link_t *link);
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args);
static void vxpocket_release(dev_link_t *link)
@@ -169,14 +168,6 @@ dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw)
/* Register with Card Services */
memset(&client_reg, 0, sizeof(client_reg));
client_reg.dev_info = hw->dev_info;
- client_reg.EventMask =
- CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL
-#ifdef CONFIG_PM
- | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET
- | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME
-#endif
- ;
- client_reg.event_handler = &vxpocket_event;
client_reg.Version = 0x0210;
client_reg.event_callback_args.client_data = link;
@@ -321,7 +312,7 @@ failed:
/*
* event callback
*/
-static int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
+int vxpocket_event(event_t event, int priority, event_callback_args_t *args)
{
dev_link_t *link = args->client_data;
vx_core_t *chip = link->priv;
@@ -380,4 +371,5 @@ static int vxpocket_event(event_t event, int priority, event_callback_args_t *ar
*/
EXPORT_SYMBOL(snd_vxpocket_ops);
EXPORT_SYMBOL(snd_vxpocket_attach);
+EXPORT_SYMBOL(vxpocket_event);
EXPORT_SYMBOL(snd_vxpocket_detach);
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index fce2ad04fd8b..62d6fa128148 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -18,23 +18,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-/*
- please add the following as /etc/pcmcia/vxpocket.conf:
-
- device "snd-vxpocket"
- class "audio" module "snd-vxpocket"
-
- card "Digigram VX-POCKET"
- manfid 0x01f1, 0x0100
- bind "snd-vxpocket"
-
- */
#include <sound/driver.h>
#include <linux/init.h>
#include <linux/moduleparam.h>
#include <sound/core.h>
-#include <pcmcia/version.h>
#include "vxpocket.h"
#include <sound/initval.h>
@@ -140,13 +128,20 @@ static void vxp_detach(dev_link_t *link)
* Module entry points
*/
+static struct pcmcia_device_id vxp_ids[] = {
+ PCMCIA_DEVICE_MANF_CARD(0x01f1, 0x0100),
+ PCMCIA_DEVICE_NULL
+};
+MODULE_DEVICE_TABLE(pcmcia, vxp_ids);
+
static struct pcmcia_driver vxp_cs_driver = {
.owner = THIS_MODULE,
.drv = {
.name = DEV_INFO,
},
.attach = vxp_attach,
- .detach = vxp_detach
+ .detach = vxp_detach,
+ .id_table = vxp_ids,
};
static int __init init_vxpocket(void)
diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c
index e052bd071e5b..061e52d3d771 100644
--- a/sound/ppc/awacs.c
+++ b/sound/ppc/awacs.c
@@ -90,7 +90,7 @@ snd_pmac_awacs_write_noreg(pmac_t *chip, int reg, int val)
snd_pmac_awacs_write(chip, val | (reg << 12));
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/* Recalibrate chip */
static void screamer_recalibrate(pmac_t *chip)
{
@@ -642,7 +642,7 @@ static void awacs_restore_all_regs(pmac_t *chip)
}
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static void snd_pmac_awacs_suspend(pmac_t *chip)
{
snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1]
@@ -676,7 +676,7 @@ static void snd_pmac_awacs_resume(pmac_t *chip)
}
#endif
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
#ifdef PMAC_SUPPORT_AUTOMUTE
/*
@@ -883,7 +883,7 @@ snd_pmac_awacs_init(pmac_t *chip)
* set lowlevel callbacks
*/
chip->set_format = snd_pmac_awacs_set_format;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
chip->suspend = snd_pmac_awacs_suspend;
chip->resume = snd_pmac_awacs_resume;
#endif
diff --git a/sound/ppc/daca.c b/sound/ppc/daca.c
index f24a91693616..a737f298e77d 100644
--- a/sound/ppc/daca.c
+++ b/sound/ppc/daca.c
@@ -218,7 +218,7 @@ static snd_kcontrol_new_t daca_mixers[] = {
};
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
static void daca_resume(pmac_t *chip)
{
pmac_daca_t *mix = chip->mixer_data;
@@ -227,7 +227,7 @@ static void daca_resume(pmac_t *chip)
mix->amp_on ? 0x05 : 0x04);
daca_set_volume(mix);
}
-#endif /* CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
static void daca_cleanup(pmac_t *chip)
@@ -275,7 +275,7 @@ int __init snd_pmac_daca_init(pmac_t *chip)
return err;
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
chip->resume = daca_resume;
#endif
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 080ef3928465..75b8b7423036 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -36,7 +36,7 @@
#include <asm/pci-bridge.h>
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
static int snd_pmac_register_sleep_notifier(pmac_t *chip);
static int snd_pmac_unregister_sleep_notifier(pmac_t *chip);
static int snd_pmac_suspend(snd_card_t *card, pm_message_t state);
@@ -782,7 +782,7 @@ static int snd_pmac_free(pmac_t *chip)
}
snd_pmac_sound_feature(chip, 0);
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
snd_pmac_unregister_sleep_notifier(chip);
#endif
@@ -1292,7 +1292,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return)
/* Reset dbdma channels */
snd_pmac_dbdma_reset(chip);
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
/* add sleep notifier */
if (! snd_pmac_register_sleep_notifier(chip))
snd_card_set_pm_callback(chip->card, snd_pmac_suspend, snd_pmac_resume, chip);
@@ -1316,7 +1316,7 @@ int __init snd_pmac_new(snd_card_t *card, pmac_t **chip_return)
* sleep notify for powerbook
*/
-#if defined(CONFIG_PM) && defined(CONFIG_PMAC_PBOOK)
+#ifdef CONFIG_PM
/*
* Save state when going to sleep, restore it afterwards.
@@ -1414,4 +1414,5 @@ static int snd_pmac_unregister_sleep_notifier(pmac_t *chip)
return 0;
}
-#endif /* CONFIG_PM && CONFIG_PMAC_PBOOK */
+#endif /* CONFIG_PM */
+
diff --git a/sound/ppc/pmac.h b/sound/ppc/pmac.h
index 0a84c05f714b..582db5220119 100644
--- a/sound/ppc/pmac.h
+++ b/sound/ppc/pmac.h
@@ -167,7 +167,7 @@ struct snd_pmac {
void (*set_format)(pmac_t *chip);
void (*update_automute)(pmac_t *chip, int do_notify);
int (*detect_headphone)(pmac_t *chip);
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
void (*suspend)(pmac_t *chip);
void (*resume)(pmac_t *chip);
#endif
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index 9332237cb6a4..36c5d5d45bb1 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -1128,7 +1128,7 @@ static void tumbler_reset_audio(pmac_t *chip)
}
}
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
/* suspend mixer */
static void tumbler_suspend(pmac_t *chip)
{
@@ -1370,7 +1370,7 @@ int __init snd_pmac_tumbler_init(pmac_t *chip)
if ((err = snd_ctl_add(chip->card, chip->drc_sw_ctl)) < 0)
return err;
-#ifdef CONFIG_PMAC_PBOOK
+#ifdef CONFIG_PM
chip->suspend = tumbler_suspend;
chip->resume = tumbler_resume;
#endif